From 92f43c452c5313a7914eab2b08d966a6c5007baa Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sun, 19 Apr 2015 00:05:14 +0200 Subject: [PATCH 0001/7006] kbuild/mkspec: Simplify vmlinux.bz2 creation No need for the intermediary vmlinux.orig - bzip2 can keep the original files used for compression with --keep. Signed-off-by: Borislav Petkov Signed-off-by: Michal Marek --- scripts/package/mkspec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index d9ab94b17de0b..89f9669d4f007 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -111,10 +111,8 @@ echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE" echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE" echo "%ifnarch ppc64" -echo 'cp vmlinux vmlinux.orig' -echo 'bzip2 -9 vmlinux' +echo 'bzip2 -9 --keep vmlinux' echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2" -echo 'mv vmlinux.orig vmlinux' echo "%endif" if ! $PREBUILT; then -- GitLab From dca0c0246fb739bccdd19ff2bfd0f02ccffdb07c Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Thu, 16 Apr 2015 16:42:46 +0300 Subject: [PATCH 0002/7006] deb-pkg: move setting debarch for a separate function create_package() function tries to resolve used architecture for everry package. Split the setting the architecture to a new function, set_debarch(), called once on startup. This allows using debarch from other parts of script as needed. v2: Follow Michals suggestion on setting variables at top scope and also setting the fallback $debarch in the new function Signed-off-by: Riku Voipio Signed-off-by: Michal Marek --- scripts/package/builddeb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 88dbf23b69708..fccabe5fb72bd 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -25,8 +25,13 @@ create_package() { chown -R root:root "$pdir" chmod -R go-w "$pdir" + # Create the package + dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch}" -p$pname -P"$pdir" + dpkg --build "$pdir" .. +} + +set_debarch() { # Attempt to find the correct Debian architecture - local forcearch="" debarch="" case "$UTS_MACHINE" in i386|ia64|alpha) debarch="$UTS_MACHINE" ;; @@ -47,6 +52,7 @@ create_package() { arm*) debarch=arm$(grep -q CONFIG_AEABI=y $KCONFIG_CONFIG && echo el || true) ;; *) + debarch=$(dpkg --print-architecture) echo "" >&2 echo "** ** ** WARNING ** ** **" >&2 echo "" >&2 @@ -59,13 +65,8 @@ create_package() { if [ -n "$KBUILD_DEBARCH" ] ; then debarch="$KBUILD_DEBARCH" fi - if [ -n "$debarch" ] ; then - forcearch="-DArchitecture=$debarch" - fi + forcearch="-DArchitecture=$debarch" - # Create the package - dpkg-gencontrol $forcearch -Vkernel:debarch="${debarch:-$(dpkg --print-architecture)}" -p$pname -P"$pdir" - dpkg --build "$pdir" .. } # Some variables and settings used throughout the script @@ -86,6 +87,9 @@ fwpackagename=linux-firmware-image-$version kernel_headers_packagename=linux-headers-$version libc_headers_packagename=linux-libc-dev dbg_packagename=$packagename-dbg +debarch= +forcearch= +set_debarch if [ "$ARCH" = "um" ] ; then packagename=user-mode-linux-$version -- GitLab From 64178cb62c329350fe06622cd215264d849b27b1 Mon Sep 17 00:00:00 2001 From: Andrey Skvortsov Date: Mon, 16 Mar 2015 11:20:54 +0300 Subject: [PATCH 0003/7006] builddeb: fix stripped module signatures if CONFIG_DEBUG_INFO and CONFIG_MODULE_SIG_ALL are set If CONFIG_MODULE_SIG_ALL is set, then user expects that all modules are automatically signed in the result package, as it's for rpm-pkg, binrpm-pkg, tar, tar-*. For deb-pkg this is correct only if CONFIG_DEBUG_INFO is NOT set. In that case deb-package contains signed modules. But if CONFIG_DEBUG_INFO is set, builddeb creates separate package with debug information. To do that, debug information from all modules is copied into separate files by objcopy. And loadable kernel modules are stripped afterwards. Stripping removes previously (during modules_install) added signatures from loadable kernel modules. Therefore final deb-package contains unsigned modules despite of set option CONFIG_MODULE_SIG_ALL. This patch resigns all stripped modules if CONFIG_MODULE_SIG_ALL is set to solve this problem. Signed-off-by: Andrey Skvortsov Acked-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index fccabe5fb72bd..222770c1b7751 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -166,6 +166,12 @@ if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then # then add a link to those $OBJCOPY --add-gnu-debuglink=$dbg_dir/usr/lib/debug/$module $tmpdir/$module done + + # resign stripped modules + MODULE_SIG_ALL="$(grep -s '^CONFIG_MODULE_SIG_ALL=y' $KCONFIG_CONFIG || true)" + if [ -n "$MODULE_SIG_ALL" ]; then + INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_sign + fi fi fi -- GitLab From ca2a9d2cf6cf3dd852c3926ac7e30ee774da4638 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard (Rtp)" Date: Tue, 3 Feb 2015 13:16:33 +0100 Subject: [PATCH 0004/7006] deb-pkg: Add device tree blobs to the package When building a package with make deb-pkg (say, for arm), the dtb files are not added to the package. Given that things are still evolving on arm, it make sense to have them along with the kernel and modules. Signed-off-by: Arnaud Patard Reviewed-by: Ben Hutchings Acked-by: maximilian attems Signed-off-by: Michal Marek --- scripts/package/builddeb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 222770c1b7751..d30116b57e7e4 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -147,6 +147,13 @@ else cp arch/$ARCH/boot/$KBUILD_IMAGE "$tmpdir/$installed_image_path" fi +if grep -q "^CONFIG_OF=y" $KCONFIG_CONFIG ; then + # Only some architectures with OF support have this target + if grep -q dtbs_install "${srctree}/arch/$SRCARCH/Makefile"; then + $MAKE KBUILD_SRC= INSTALL_DTBS_PATH="$tmpdir/usr/lib/$packagename" dtbs_install + fi +fi + if grep -q '^CONFIG_MODULES=y' $KCONFIG_CONFIG ; then INSTALL_MOD_PATH="$tmpdir" $MAKE KBUILD_SRC= modules_install rm -f "$tmpdir/lib/modules/$version/build" -- GitLab From f9beafc9d8bf7febf673df9b41e13596ca669f75 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 9 May 2015 17:09:27 -0300 Subject: [PATCH 0005/7006] coccinelle: pm_runtime: Insert blank line Insert a blank line in order to improve the readability of the generated patch and also make it consistent with the other .cocci files. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/api/pm_runtime.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccinelle/api/pm_runtime.cocci b/scripts/coccinelle/api/pm_runtime.cocci index f01789e967ec4..b7042d074078c 100644 --- a/scripts/coccinelle/api/pm_runtime.cocci +++ b/scripts/coccinelle/api/pm_runtime.cocci @@ -1,5 +1,5 @@ /// Make sure pm_runtime_* calls does not use unnecessary IS_ERR_VALUE -// +/// // Keywords: pm_runtime // Confidence: Medium // Copyright (C) 2013 Texas Instruments Incorporated - GPLv2. -- GitLab From fe8c46b632505a880c527bc9ae246e868aa3ece5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 9 May 2015 17:09:28 -0300 Subject: [PATCH 0006/7006] coccinelle: returnvar: Use imperative mood According to Documentation/SubmittingPatches: "Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behaviour." So do as recommended. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/returnvar.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccinelle/misc/returnvar.cocci b/scripts/coccinelle/misc/returnvar.cocci index 605955a91c449..d8286ef5307fc 100644 --- a/scripts/coccinelle/misc/returnvar.cocci +++ b/scripts/coccinelle/misc/returnvar.cocci @@ -1,5 +1,5 @@ /// -/// Removes unneeded variable used to store return value. +/// Remove unneeded variable used to store return value. /// // Confidence: Moderate // Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2. -- GitLab From dd494ac0de48ded6a7ec0525f253116fde5c7be5 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 9 May 2015 17:09:29 -0300 Subject: [PATCH 0007/7006] coccinelle: ifaddr: Fix the sentence Make the sentence sensible. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/ifaddr.cocci | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scripts/coccinelle/misc/ifaddr.cocci b/scripts/coccinelle/misc/ifaddr.cocci index 8aebd1875e752..c2663c677ac1c 100644 --- a/scripts/coccinelle/misc/ifaddr.cocci +++ b/scripts/coccinelle/misc/ifaddr.cocci @@ -1,5 +1,4 @@ -/// the address of a variable or field is non-zero is likely always to bo -/// non-zero +/// The address of a variable or field is likely always to be non-zero. /// // Confidence: High // Copyright: (C) 2012 Julia Lawall, INRIA/LIP6. GPLv2. -- GitLab From ca34cba43168830dd96f8f6407282131733e6fb4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 9 May 2015 17:09:30 -0300 Subject: [PATCH 0008/7006] coccinelle: simple_open: Use imperative mood According to Documentation/SubmittingPatches: "Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behaviour." So do as recommended. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/api/simple_open.cocci | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/coccinelle/api/simple_open.cocci b/scripts/coccinelle/api/simple_open.cocci index b67e174f3d95e..bd1a2a4ee106d 100644 --- a/scripts/coccinelle/api/simple_open.cocci +++ b/scripts/coccinelle/api/simple_open.cocci @@ -1,5 +1,5 @@ -/// This removes an open coded simple_open() function -/// and replaces file operations references to the function +/// Remove an open coded simple_open() function +/// and replace file operations references to the function /// with simple_open() instead. /// // Confidence: High -- GitLab From 4341f6e5ce448dd79c3e663513213b936ba34c83 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 May 2015 08:02:34 -0300 Subject: [PATCH 0009/7006] scripts/coccinelle/misc/semicolon.cocci: Use imperative mood According to Documentation/SubmittingPatches: "Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behaviour. So do as recommended. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/semicolon.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccinelle/misc/semicolon.cocci b/scripts/coccinelle/misc/semicolon.cocci index a47eba2edc9e1..6740c659a2b38 100644 --- a/scripts/coccinelle/misc/semicolon.cocci +++ b/scripts/coccinelle/misc/semicolon.cocci @@ -1,5 +1,5 @@ /// -/// Removes unneeded semicolon. +/// Remove unneeded semicolon. /// // Confidence: Moderate // Copyright: (C) 2012 Peter Senna Tschudin, INRIA/LIP6. GPLv2. -- GitLab From 74de120d8096f72bdf95aba7234428c798d931cd Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 20 May 2015 08:02:35 -0300 Subject: [PATCH 0010/7006] scripts/coccinelle/misc/irqf_oneshot.cocci: Fix grammar Correct form is 'always requested'. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/irqf_oneshot.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccinelle/misc/irqf_oneshot.cocci b/scripts/coccinelle/misc/irqf_oneshot.cocci index a24a754ae1d72..b17ac8b998947 100644 --- a/scripts/coccinelle/misc/irqf_oneshot.cocci +++ b/scripts/coccinelle/misc/irqf_oneshot.cocci @@ -1,4 +1,4 @@ -/// Make sure threaded IRQs without a primary handler are always request with +/// Make sure threaded IRQs without a primary handler are always requested with /// IRQF_ONESHOT /// // -- GitLab From 4c8f20bb8e0ba6eecf62958bbf0502a2dc445ce6 Mon Sep 17 00:00:00 2001 From: Dmitry Kalinkin Date: Thu, 21 May 2015 19:19:13 +0800 Subject: [PATCH 0011/7006] coccinelle: api: add vma_pages.cocci This semantic patch replaces explicit computations of vma page count with explicit function call. Signed-off-by: Dmitry Kalinkin Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/api/vma_pages.cocci | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 scripts/coccinelle/api/vma_pages.cocci diff --git a/scripts/coccinelle/api/vma_pages.cocci b/scripts/coccinelle/api/vma_pages.cocci new file mode 100644 index 0000000000000..3e52e11ea1dc8 --- /dev/null +++ b/scripts/coccinelle/api/vma_pages.cocci @@ -0,0 +1,60 @@ +/// +/// Use vma_pages function on vma object instead of explicit computation. +/// +// Confidence: High +// Keywords: vma_pages vma +// Comment: Based on resource_size.cocci + +virtual context +virtual patch +virtual org +virtual report + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@r_context depends on context && !patch && !org && !report@ +struct vm_area_struct *vma; +@@ + +* (vma->vm_end - vma->vm_start) >> PAGE_SHIFT + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@r_patch depends on !context && patch && !org && !report@ +struct vm_area_struct *vma; +@@ + +- ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) ++ vma_pages(vma) + +//---------------------------------------------------------- +// For org mode +//---------------------------------------------------------- + +@r_org depends on !context && !patch && (org || report)@ +struct vm_area_struct *vma; +position p; +@@ + + (vma->vm_end@p - vma->vm_start) >> PAGE_SHIFT + +@script:python depends on report@ +p << r_org.p; +x << r_org.vma; +@@ + +msg="WARNING: Consider using vma_pages helper on %s" % (x) +coccilib.report.print_report(p[0], msg) + +@script:python depends on org@ +p << r_org.p; +x << r_org.vma; +@@ + +msg="WARNING: Consider using vma_pages helper on %s" % (x) +msg_safe=msg.replace("[","@(").replace("]",")") +coccilib.org.print_todo(p[0], msg_safe) -- GitLab From 9473a62f779d78bae646e7ef1a792d53ad4ac29e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 24 May 2015 17:45:54 -0300 Subject: [PATCH 0012/7006] coccinelle: irqf_oneshot.cocci: Improve the generated commit log Improve the commit log of the generated patch by mentioning the commit log that makes threaded IRQs without a primary handler to be requested with the IRQF_ONESHOT flag. Signed-off-by: Fabio Estevam Acked- by: Valentin Rothberg Signed-off-by: Michal Marek --- scripts/coccinelle/misc/irqf_oneshot.cocci | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/scripts/coccinelle/misc/irqf_oneshot.cocci b/scripts/coccinelle/misc/irqf_oneshot.cocci index b17ac8b998947..b421150a2effc 100644 --- a/scripts/coccinelle/misc/irqf_oneshot.cocci +++ b/scripts/coccinelle/misc/irqf_oneshot.cocci @@ -1,5 +1,8 @@ -/// Make sure threaded IRQs without a primary handler are always requested with -/// IRQF_ONESHOT +/// Since commit 1c6c69525b40 ("genirq: Reject bogus threaded irq requests") +/// threaded IRQs without a primary handler need to be requested with +/// IRQF_ONESHOT, otherwise the request will fail. +/// +/// So pass the IRQF_ONESHOT flag in this case. /// // // Confidence: Good -- GitLab From b1b38278e12b04cf9a227f6af2c24651cf6e8a85 Mon Sep 17 00:00:00 2001 From: David Weinehall Date: Wed, 20 May 2015 17:00:13 +0300 Subject: [PATCH 0013/7006] drm/i915: add a context parameter to {en, dis}able zero address mapping Export a new context parameter that can be set/queried through the context_{get,set}param ioctls. This parameter is passed as a context flag and decides whether or not a GPU address mapping is allowed to be made at address zero. The default is to allow such mappings. Signed-off-by: David Weinehall Acked-by: "Zou, Nanhai" Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/i915_gem_context.c | 11 +++++++++++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 13 +++++++++---- include/uapi/drm/i915_drm.h | 1 + 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 72f5a3f9dbf24..d35b592c7378a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -805,11 +805,15 @@ struct i915_ctx_hang_stats { /* This must match up with the value previously used for execbuf2.rsvd1. */ #define DEFAULT_CONTEXT_HANDLE 0 + +#define CONTEXT_NO_ZEROMAP (1<<0) /** * struct intel_context - as the name implies, represents a context. * @ref: reference count. * @user_handle: userspace tracking identity for this context. * @remap_slice: l3 row remapping information. + * @flags: context specific flags: + * CONTEXT_NO_ZEROMAP: do not allow mapping things to page 0. * @file_priv: filp associated with this context (NULL for global default * context). * @hang_stats: information about the role of this context in possible GPU @@ -826,6 +830,7 @@ struct intel_context { struct kref ref; int user_handle; uint8_t remap_slice; + int flags; struct drm_i915_file_private *file_priv; struct i915_ctx_hang_stats hang_stats; struct i915_hw_ppgtt *ppgtt; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8867818b14017..133afcf4d79e4 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -900,6 +900,9 @@ int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data, case I915_CONTEXT_PARAM_BAN_PERIOD: args->value = ctx->hang_stats.ban_period_seconds; break; + case I915_CONTEXT_PARAM_NO_ZEROMAP: + args->value = ctx->flags & CONTEXT_NO_ZEROMAP; + break; default: ret = -EINVAL; break; @@ -937,6 +940,14 @@ int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data, else ctx->hang_stats.ban_period_seconds = args->value; break; + case I915_CONTEXT_PARAM_NO_ZEROMAP: + if (args->size) { + ret = -EINVAL; + } else { + ctx->flags &= ~CONTEXT_NO_ZEROMAP; + ctx->flags |= args->value ? CONTEXT_NO_ZEROMAP : 0; + } + break; default: ret = -EINVAL; break; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index bd0e4bda2c649..3336e1c2c0a5e 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -676,6 +676,7 @@ eb_vma_misplaced(struct i915_vma *vma) static int i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, struct list_head *vmas, + struct intel_context *ctx, bool *need_relocs) { struct drm_i915_gem_object *obj; @@ -698,6 +699,9 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring, obj = vma->obj; entry = vma->exec_entry; + if (ctx->flags & CONTEXT_NO_ZEROMAP) + entry->flags |= __EXEC_OBJECT_NEEDS_BIAS; + if (!has_fenced_gpu_access) entry->flags &= ~EXEC_OBJECT_NEEDS_FENCE; need_fence = @@ -775,7 +779,8 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, struct eb_vmas *eb, - struct drm_i915_gem_exec_object2 *exec) + struct drm_i915_gem_exec_object2 *exec, + struct intel_context *ctx) { struct drm_i915_gem_relocation_entry *reloc; struct i915_address_space *vm; @@ -861,7 +866,7 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev, goto err; need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, ctx, &need_relocs); if (ret) goto err; @@ -1519,7 +1524,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, /* Move the objects en-masse into the GTT, evicting if necessary. */ need_relocs = (args->flags & I915_EXEC_NO_RELOC) == 0; - ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, &need_relocs); + ret = i915_gem_execbuffer_reserve(ring, &eb->vmas, ctx, &need_relocs); if (ret) goto err; @@ -1529,7 +1534,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) { if (ret == -EFAULT) { ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring, - eb, exec); + eb, exec, ctx); BUG_ON(!mutex_is_locked(&dev->struct_mutex)); } if (ret) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 6e1a2ed116cb1..92d61a7c942a9 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -1106,6 +1106,7 @@ struct drm_i915_gem_context_param { __u32 size; __u64 param; #define I915_CONTEXT_PARAM_BAN_PERIOD 0x1 +#define I915_CONTEXT_PARAM_NO_ZEROMAP 0x2 __u64 value; }; -- GitLab From 0d2e42970cfa8814ce5f73e329f61c94b7ec2dab Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:39 +0300 Subject: [PATCH 0014/7006] drm/i915: reduce indent in i9xx_hpd_irq_handler Bail out early if nothing to do. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 35 +++++++++++++++++---------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e6bb72dca3ffb..f0206f63617ec 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1756,28 +1756,29 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); - if (hotplug_status) { - I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); - /* - * Make sure hotplug status is cleared before we clear IIR, or else we - * may miss hotplug events. - */ - POSTING_READ(PORT_HOTPLUG_STAT); + if (!hotplug_status) + return; - if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { - u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; + I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status); + /* + * Make sure hotplug status is cleared before we clear IIR, or else we + * may miss hotplug events. + */ + POSTING_READ(PORT_HOTPLUG_STAT); - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); - } else { - u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; + if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); - } + intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); + } else { + u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && - hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) - dp_aux_irq_handler(dev); + intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); } + + if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && + hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); } static irqreturn_t valleyview_irq_handler(int irq, void *arg) -- GitLab From 369712e89404089fa559235bb1ee8fc40d976e6b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:40 +0300 Subject: [PATCH 0015/7006] drm/i915: reduce duplicate conditions in i9xx_hpd_irq_handler Move dp aux irq handling within the same branch instead of duplicating the conditions. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f0206f63617ec..333b3d9dd5fcb 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1770,15 +1770,14 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); + + if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) + dp_aux_irq_handler(dev); } else { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); } - - if ((IS_G4X(dev) || IS_VALLEYVIEW(dev)) && - hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) - dp_aux_irq_handler(dev); } static irqreturn_t valleyview_irq_handler(int irq, void *arg) -- GitLab From b0c29a33fc80bec3ae0f5862d7733e3782878d6d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:41 +0300 Subject: [PATCH 0016/7006] drm/i915: reduce indent in intel_hpd_irq_handler Continue to loop early if there's nothing to do. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 49 +++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 333b3d9dd5fcb..48e5b79a79296 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1442,36 +1442,39 @@ static void intel_hpd_irq_handler(struct drm_device *dev, spin_lock(&dev_priv->irq_lock); for (i = 1; i < HPD_NUM_PINS; i++) { + bool long_hpd; + if (!(hpd[i] & hotplug_trigger)) continue; port = get_port_from_pin(i); - if (port && dev_priv->hpd_irq_port[port]) { - bool long_hpd; + if (!port || !dev_priv->hpd_irq_port[port]) + continue; - if (!HAS_GMCH_DISPLAY(dev_priv)) { - dig_shift = pch_port_to_hotplug_shift(port); - long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } else { - dig_shift = i915_port_to_hotplug_shift(port); - long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } + if (!HAS_GMCH_DISPLAY(dev_priv)) { + dig_shift = pch_port_to_hotplug_shift(port); + long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } else { + dig_shift = i915_port_to_hotplug_shift(port); + long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } - DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", - port_name(port), - long_hpd ? "long" : "short"); - /* for long HPD pulses we want to have the digital queue happen, - but we still want HPD storm detection to function. */ - if (long_hpd) { - dev_priv->long_hpd_port_mask |= (1 << port); - dig_port_mask |= hpd[i]; - } else { - /* for short HPD just trigger the digital queue */ - dev_priv->short_hpd_port_mask |= (1 << port); - hotplug_trigger &= ~hpd[i]; - } - queue_dig = true; + DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), + long_hpd ? "long" : "short"); + /* + * For long HPD pulses we want to have the digital queue happen, + * but we still want HPD storm detection to function. + */ + if (long_hpd) { + dev_priv->long_hpd_port_mask |= (1 << port); + dig_port_mask |= hpd[i]; + } else { + /* for short HPD just trigger the digital queue */ + dev_priv->short_hpd_port_mask |= (1 << port); + hotplug_trigger &= ~hpd[i]; } + + queue_dig = true; } for (i = 1; i < HPD_NUM_PINS; i++) { -- GitLab From 5fcece80ecdac932a0acb71e3a239c39dd4af20f Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:42 +0300 Subject: [PATCH 0017/7006] drm/i915: group all hotplug related fields into a new struct in dev_priv There are plenty of hotplug related fields in struct drm_i915_private scattered all around. Group them under one hotplug struct. Clean up naming while at it. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 8 +-- drivers/gpu/drm/i915/i915_drv.c | 12 ++--- drivers/gpu/drm/i915/i915_drv.h | 58 +++++++++++---------- drivers/gpu/drm/i915/i915_irq.c | 86 ++++++++++++++++---------------- drivers/gpu/drm/i915/intel_ddi.c | 2 +- drivers/gpu/drm/i915/intel_dp.c | 6 +-- 6 files changed, 88 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index d2df321ba6349..34248635c36c0 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -933,8 +933,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags) goto out_mtrrfree; } - dev_priv->dp_wq = alloc_ordered_workqueue("i915-dp", 0); - if (dev_priv->dp_wq == NULL) { + dev_priv->hotplug.dp_wq = alloc_ordered_workqueue("i915-dp", 0); + if (dev_priv->hotplug.dp_wq == NULL) { DRM_ERROR("Failed to create our dp workqueue.\n"); ret = -ENOMEM; goto out_freewq; @@ -1029,7 +1029,7 @@ out_gem_unload: pm_qos_remove_request(&dev_priv->pm_qos); destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); out_freedpwq: - destroy_workqueue(dev_priv->dp_wq); + destroy_workqueue(dev_priv->hotplug.dp_wq); out_freewq: destroy_workqueue(dev_priv->wq); out_mtrrfree: @@ -1123,7 +1123,7 @@ int i915_driver_unload(struct drm_device *dev) intel_teardown_gmbus(dev); intel_teardown_mchbar(dev); - destroy_workqueue(dev_priv->dp_wq); + destroy_workqueue(dev_priv->hotplug.dp_wq); destroy_workqueue(dev_priv->wq); destroy_workqueue(dev_priv->gpu_error.hangcheck_wq); pm_qos_remove_request(&dev_priv->pm_qos); diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 884b4f9b81c4a..a051a0241883c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -545,15 +545,15 @@ void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) { spin_lock_irq(&dev_priv->irq_lock); - dev_priv->long_hpd_port_mask = 0; - dev_priv->short_hpd_port_mask = 0; - dev_priv->hpd_event_bits = 0; + dev_priv->hotplug.long_port_mask = 0; + dev_priv->hotplug.short_port_mask = 0; + dev_priv->hotplug.event_bits = 0; spin_unlock_irq(&dev_priv->irq_lock); - cancel_work_sync(&dev_priv->dig_port_work); - cancel_work_sync(&dev_priv->hotplug_work); - cancel_delayed_work_sync(&dev_priv->hotplug_reenable_work); + cancel_work_sync(&dev_priv->hotplug.dig_port_work); + cancel_work_sync(&dev_priv->hotplug.hotplug_work); + cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); } void i915_firmware_load_error_print(const char *fw_path, int err) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d35b592c7378a..173c9051bf86e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -217,6 +217,36 @@ enum hpd_pin { HPD_NUM_PINS }; +struct i915_hotplug { + struct work_struct hotplug_work; + + struct { + unsigned long last_jiffies; + int count; + enum { + HPD_ENABLED = 0, + HPD_DISABLED = 1, + HPD_MARK_DISABLED = 2 + } state; + } stats[HPD_NUM_PINS]; + u32 event_bits; + struct delayed_work reenable_work; + + struct intel_digital_port *irq_port[I915_MAX_PORTS]; + u32 long_port_mask; + u32 short_port_mask; + struct work_struct dig_port_work; + + /* + * if we get a HPD irq from DP and a HPD irq from non-DP + * the non-DP HPD could block the workqueue on a mode config + * mutex getting, that userspace may have taken. However + * userspace is waiting on the DP workqueue to run which is + * blocked behind the non-DP one. + */ + struct workqueue_struct *dp_wq; +}; + #define I915_GEM_GPU_DOMAINS \ (I915_GEM_DOMAIN_RENDER | \ I915_GEM_DOMAIN_SAMPLER | \ @@ -1684,19 +1714,7 @@ struct drm_i915_private { u32 pm_rps_events; u32 pipestat_irq_mask[I915_MAX_PIPES]; - struct work_struct hotplug_work; - struct { - unsigned long hpd_last_jiffies; - int hpd_cnt; - enum { - HPD_ENABLED = 0, - HPD_DISABLED = 1, - HPD_MARK_DISABLED = 2 - } hpd_mark; - } hpd_stats[HPD_NUM_PINS]; - u32 hpd_event_bits; - struct delayed_work hotplug_reenable_work; - + struct i915_hotplug hotplug; struct i915_fbc fbc; struct i915_drrs drrs; struct intel_opregion opregion; @@ -1862,20 +1880,6 @@ struct drm_i915_private { struct i915_runtime_pm pm; - struct intel_digital_port *hpd_irq_port[I915_MAX_PORTS]; - u32 long_hpd_port_mask; - u32 short_hpd_port_mask; - struct work_struct dig_port_work; - - /* - * if we get a HPD irq from DP and a HPD irq from non-DP - * the non-DP HPD could block the workqueue on a mode config - * mutex getting, that userspace may have taken. However - * userspace is waiting on the DP workqueue to run which is - * blocked behind the non-DP one. - */ - struct workqueue_struct *dp_wq; - /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ struct { int (*execbuf_submit)(struct drm_device *dev, struct drm_file *file, diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 48e5b79a79296..91cb0b6ec47b2 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -832,23 +832,23 @@ static bool intel_hpd_irq_event(struct drm_device *dev, static void i915_digport_work_func(struct work_struct *work) { struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, dig_port_work); + container_of(work, struct drm_i915_private, hotplug.dig_port_work); u32 long_port_mask, short_port_mask; struct intel_digital_port *intel_dig_port; int i; u32 old_bits = 0; spin_lock_irq(&dev_priv->irq_lock); - long_port_mask = dev_priv->long_hpd_port_mask; - dev_priv->long_hpd_port_mask = 0; - short_port_mask = dev_priv->short_hpd_port_mask; - dev_priv->short_hpd_port_mask = 0; + long_port_mask = dev_priv->hotplug.long_port_mask; + dev_priv->hotplug.long_port_mask = 0; + short_port_mask = dev_priv->hotplug.short_port_mask; + dev_priv->hotplug.short_port_mask = 0; spin_unlock_irq(&dev_priv->irq_lock); for (i = 0; i < I915_MAX_PORTS; i++) { bool valid = false; bool long_hpd = false; - intel_dig_port = dev_priv->hpd_irq_port[i]; + intel_dig_port = dev_priv->hotplug.irq_port[i]; if (!intel_dig_port || !intel_dig_port->hpd_pulse) continue; @@ -871,9 +871,9 @@ static void i915_digport_work_func(struct work_struct *work) if (old_bits) { spin_lock_irq(&dev_priv->irq_lock); - dev_priv->hpd_event_bits |= old_bits; + dev_priv->hotplug.event_bits |= old_bits; spin_unlock_irq(&dev_priv->irq_lock); - schedule_work(&dev_priv->hotplug_work); + schedule_work(&dev_priv->hotplug.hotplug_work); } } @@ -885,7 +885,7 @@ static void i915_digport_work_func(struct work_struct *work) static void i915_hotplug_work_func(struct work_struct *work) { struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, hotplug_work); + container_of(work, struct drm_i915_private, hotplug.hotplug_work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; struct intel_connector *intel_connector; @@ -900,20 +900,20 @@ static void i915_hotplug_work_func(struct work_struct *work) spin_lock_irq(&dev_priv->irq_lock); - hpd_event_bits = dev_priv->hpd_event_bits; - dev_priv->hpd_event_bits = 0; + hpd_event_bits = dev_priv->hotplug.event_bits; + dev_priv->hotplug.event_bits = 0; list_for_each_entry(connector, &mode_config->connector_list, head) { intel_connector = to_intel_connector(connector); if (!intel_connector->encoder) continue; intel_encoder = intel_connector->encoder; if (intel_encoder->hpd_pin > HPD_NONE && - dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_MARK_DISABLED && + dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_MARK_DISABLED && connector->polled == DRM_CONNECTOR_POLL_HPD) { DRM_INFO("HPD interrupt storm detected on connector %s: " "switching from hotplug detection to polling\n", connector->name); - dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark = HPD_DISABLED; + dev_priv->hotplug.stats[intel_encoder->hpd_pin].state = HPD_DISABLED; connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT; hpd_disabled = true; @@ -928,7 +928,7 @@ static void i915_hotplug_work_func(struct work_struct *work) * some connectors */ if (hpd_disabled) { drm_kms_helper_poll_enable(dev); - mod_delayed_work(system_wq, &dev_priv->hotplug_reenable_work, + mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); } @@ -1448,7 +1448,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; port = get_port_from_pin(i); - if (!port || !dev_priv->hpd_irq_port[port]) + if (!port || !dev_priv->hotplug.irq_port[port]) continue; if (!HAS_GMCH_DISPLAY(dev_priv)) { @@ -1466,11 +1466,11 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * but we still want HPD storm detection to function. */ if (long_hpd) { - dev_priv->long_hpd_port_mask |= (1 << port); + dev_priv->hotplug.long_port_mask |= (1 << port); dig_port_mask |= hpd[i]; } else { /* for short HPD just trigger the digital queue */ - dev_priv->short_hpd_port_mask |= (1 << port); + dev_priv->hotplug.short_port_mask |= (1 << port); hotplug_trigger &= ~hpd[i]; } @@ -1479,7 +1479,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, for (i = 1; i < HPD_NUM_PINS; i++) { if (hpd[i] & hotplug_trigger && - dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED) { + dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* * On GMCH platforms the interrupt mask bits only * prevent irq generation, not the setting of the @@ -1494,29 +1494,29 @@ static void intel_hpd_irq_handler(struct drm_device *dev, } if (!(hpd[i] & hotplug_trigger) || - dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED) + dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; if (!(dig_port_mask & hpd[i])) { - dev_priv->hpd_event_bits |= (1 << i); + dev_priv->hotplug.event_bits |= (1 << i); queue_hp = true; } - if (!time_in_range(jiffies, dev_priv->hpd_stats[i].hpd_last_jiffies, - dev_priv->hpd_stats[i].hpd_last_jiffies + if (!time_in_range(jiffies, dev_priv->hotplug.stats[i].last_jiffies, + dev_priv->hotplug.stats[i].last_jiffies + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { - dev_priv->hpd_stats[i].hpd_last_jiffies = jiffies; - dev_priv->hpd_stats[i].hpd_cnt = 0; + dev_priv->hotplug.stats[i].last_jiffies = jiffies; + dev_priv->hotplug.stats[i].count = 0; DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); - } else if (dev_priv->hpd_stats[i].hpd_cnt > HPD_STORM_THRESHOLD) { - dev_priv->hpd_stats[i].hpd_mark = HPD_MARK_DISABLED; - dev_priv->hpd_event_bits &= ~(1 << i); + } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) { + dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED; + dev_priv->hotplug.event_bits &= ~(1 << i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); storm_detected = true; } else { - dev_priv->hpd_stats[i].hpd_cnt++; + dev_priv->hotplug.stats[i].count++; DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", i, - dev_priv->hpd_stats[i].hpd_cnt); + dev_priv->hotplug.stats[i].count); } } @@ -1531,9 +1531,9 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * deadlock. */ if (queue_dig) - queue_work(dev_priv->dp_wq, &dev_priv->dig_port_work); + queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); if (queue_hp) - schedule_work(&dev_priv->hotplug_work); + schedule_work(&dev_priv->hotplug.hotplug_work); } static void gmbus_irq_handler(struct drm_device *dev) @@ -3213,12 +3213,12 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) if (HAS_PCH_IBX(dev)) { hotplug_irqs = SDE_HOTPLUG_MASK; for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin]; } else { hotplug_irqs = SDE_HOTPLUG_MASK_CPT; for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) enabled_irqs |= hpd_cpt[intel_encoder->hpd_pin]; } @@ -3247,7 +3247,7 @@ static void bxt_hpd_irq_setup(struct drm_device *dev) /* Now, enable HPD */ for_each_intel_encoder(dev, intel_encoder) { - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) hotplug_port |= hpd_bxt[intel_encoder->hpd_pin]; } @@ -4140,7 +4140,7 @@ static void i915_hpd_irq_setup(struct drm_device *dev) /* Note HDMI and DP share hotplug bits */ /* enable bits are the same for all generations */ for_each_intel_encoder(dev, intel_encoder) - if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin]; /* Programming the CRT detection parameters tends to generate a spurious hotplug event about three @@ -4284,7 +4284,7 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), - hotplug_reenable_work.work); + hotplug.reenable_work.work); struct drm_device *dev = dev_priv->dev; struct drm_mode_config *mode_config = &dev->mode_config; int i; @@ -4295,10 +4295,10 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { struct drm_connector *connector; - if (dev_priv->hpd_stats[i].hpd_mark != HPD_DISABLED) + if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) continue; - dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + dev_priv->hotplug.stats[i].state = HPD_ENABLED; list_for_each_entry(connector, &mode_config->connector_list, head) { struct intel_connector *intel_connector = to_intel_connector(connector); @@ -4331,8 +4331,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func); + INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); + INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); @@ -4345,7 +4345,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); - INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work, + INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, intel_hpd_irq_reenable_work); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); @@ -4451,8 +4451,8 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) int i; for (i = 1; i < HPD_NUM_PINS; i++) { - dev_priv->hpd_stats[i].hpd_cnt = 0; - dev_priv->hpd_stats[i].hpd_mark = HPD_ENABLED; + dev_priv->hotplug.stats[i].count = 0; + dev_priv->hotplug.stats[i].state = HPD_ENABLED; } list_for_each_entry(connector, &mode_config->connector_list, head) { struct intel_connector *intel_connector = to_intel_connector(connector); diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cacb07b7a8f10..62a7c7f2b5d4a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2832,7 +2832,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port) goto err; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; - dev_priv->hpd_irq_port[port] = intel_dig_port; + dev_priv->hotplug.irq_port[port] = intel_dig_port; } /* In theory we don't need the encoder->type check, but leave it just in diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 280c282da9bd6..61c8d28deabe4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5940,7 +5940,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->hot_plug = intel_dp_hot_plug; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; - dev_priv->hpd_irq_port[port] = intel_dig_port; + dev_priv->hotplug.irq_port[port] = intel_dig_port; if (!intel_dp_init_connector(intel_dig_port, intel_connector)) { drm_encoder_cleanup(encoder); @@ -5956,7 +5956,7 @@ void intel_dp_mst_suspend(struct drm_device *dev) /* disable MST */ for (i = 0; i < I915_MAX_PORTS; i++) { - struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i]; + struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i]; if (!intel_dig_port) continue; @@ -5975,7 +5975,7 @@ void intel_dp_mst_resume(struct drm_device *dev) int i; for (i = 0; i < I915_MAX_PORTS; i++) { - struct intel_digital_port *intel_dig_port = dev_priv->hpd_irq_port[i]; + struct intel_digital_port *intel_dig_port = dev_priv->hotplug.irq_port[i]; if (!intel_dig_port) continue; if (intel_dig_port->base.type == INTEL_OUTPUT_DISPLAYPORT) { -- GitLab From d66716200a8e8362599ce939df40821bb960e866 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:44 +0300 Subject: [PATCH 0018/7006] drm/i915: remove useless DP and DDI encoder ->hot_plug hooks The hotplug callbacks for DP and DDI effectively did nothing. Remove them. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 15 --------------- drivers/gpu/drm/i915/intel_dp.c | 7 ------- 2 files changed, 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 62a7c7f2b5d4a..54b60a97ef2de 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2618,20 +2618,6 @@ void intel_ddi_fdi_disable(struct drm_crtc *crtc) I915_WRITE(_FDI_RXA_CTL, val); } -static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder) -{ - struct intel_digital_port *intel_dig_port = enc_to_dig_port(&intel_encoder->base); - int type = intel_dig_port->base.type; - - if (type != INTEL_OUTPUT_DISPLAYPORT && - type != INTEL_OUTPUT_EDP && - type != INTEL_OUTPUT_UNKNOWN) { - return; - } - - intel_dp_hot_plug(intel_encoder); -} - void intel_ddi_get_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { @@ -2825,7 +2811,6 @@ void intel_ddi_init(struct drm_device *dev, enum port port) intel_encoder->type = INTEL_OUTPUT_UNKNOWN; intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); intel_encoder->cloneable = 0; - intel_encoder->hot_plug = intel_ddi_hot_plug; if (init_dp) { if (!intel_ddi_init_dp_connector(intel_dig_port)) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 61c8d28deabe4..823a1b31177cb 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4920,12 +4920,6 @@ static const struct drm_encoder_funcs intel_dp_enc_funcs = { .destroy = intel_dp_encoder_destroy, }; -void -intel_dp_hot_plug(struct intel_encoder *intel_encoder) -{ - return; -} - enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) { @@ -5937,7 +5931,6 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port) intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2); } intel_encoder->cloneable = 0; - intel_encoder->hot_plug = intel_dp_hot_plug; intel_dig_port->hpd_pulse = intel_dp_hpd_pulse; dev_priv->hotplug.irq_port[port] = intel_dig_port; -- GitLab From ea875496360cf8f89ea009239bf7ef12cdd4febc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 27 May 2015 15:03:45 +0300 Subject: [PATCH 0019/7006] drm/i915/dsi: remove non-op hot plug callback Not needed or used. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b5a5558ecd631..98998e976dbba 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -261,11 +261,6 @@ static inline bool is_cmd_mode(struct intel_dsi *intel_dsi) return intel_dsi->operation_mode == INTEL_DSI_COMMAND_MODE; } -static void intel_dsi_hot_plug(struct intel_encoder *encoder) -{ - DRM_DEBUG_KMS("\n"); -} - static bool intel_dsi_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *config) { @@ -1022,7 +1017,6 @@ void intel_dsi_init(struct drm_device *dev) drm_encoder_init(dev, encoder, &intel_dsi_funcs, DRM_MODE_ENCODER_DSI); /* XXX: very likely not all of these are needed */ - intel_encoder->hot_plug = intel_dsi_hot_plug; intel_encoder->compute_config = intel_dsi_compute_config; intel_encoder->pre_pll_enable = intel_dsi_pre_pll_enable; intel_encoder->pre_enable = intel_dsi_pre_enable; -- GitLab From 6cf75178deacd87af12a657d914e6bbca806b5ba Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:38 +0100 Subject: [PATCH 0020/7006] drm/i915/skl: Make sure to break when not finding suitable PLL dividers Right now, when finishing the cycle with odd dividers without finding a suitable candidate, we end up in an infinite loop. Make sure to break in that case. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 54b60a97ef2de..233467f40a4a9 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1184,6 +1184,10 @@ found: } if (min_dco_index > 2 && dco_count == 2) { + /* oh well, we tried... */ + if (retry_with_odd) + break; + retry_with_odd = true; dco_count = 0; } -- GitLab From 19cdc0e6cdfc29e3ddee1fe56c3bcdfe25f6a916 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:39 +0100 Subject: [PATCH 0021/7006] drm/i915/skl: Display the WRPLL frequency we couldn't accomodate when failing This helps debugging. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 233467f40a4a9..c1abe6efff9d9 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1194,7 +1194,8 @@ found: } if (min_dco_index > 2) { - WARN(1, "No valid values found for the given pixel clock\n"); + WARN(1, "No valid parameters found for pixel clock: %dHz\n", + clock); } else { wrpll_params->central_freq = dco_central_freq[min_dco_index]; -- GitLab From 318bd821d65d37fb12c5673607e2b013f7a86a01 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:40 +0100 Subject: [PATCH 0022/7006] drm/i915/skl: Propagate the error if we fail to find a suitable DPLL divider At the moment, even if we fail to find a suitable divider, we'll still try to set the mode with bogus parameters. Just fail the modeset if we can't generate the frequency. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c1abe6efff9d9..f10f55690749c 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1115,7 +1115,7 @@ struct skl_wrpll_params { uint32_t central_freq; }; -static void +static bool skl_ddi_calculate_wrpll(int clock /* in Hz */, struct skl_wrpll_params *wrpll_params) { @@ -1196,6 +1196,7 @@ found: if (min_dco_index > 2) { WARN(1, "No valid parameters found for pixel clock: %dHz\n", clock); + return false; } else { wrpll_params->central_freq = dco_central_freq[min_dco_index]; @@ -1262,6 +1263,8 @@ found: wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); } + + return true; } @@ -1286,7 +1289,8 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, ctrl1 |= DPLL_CTRL1_HDMI_MODE(0); - skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params); + if (!skl_ddi_calculate_wrpll(clock * 1000, &wrpll_params)) + return false; cfgcr1 = DPLL_CFGCR1_FREQ_ENABLE | DPLL_CFGCR1_DCO_FRACTION(wrpll_params.dco_fraction) | -- GitLab From 9c2367538de381435503425c22c4f192c72e282e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:41 +0100 Subject: [PATCH 0023/7006] drm/i915/skl: Use a more idomatic early return We can coalesce the WARN() condition with the WARN() itself and, as we are returning early, we can de-intent the rest of the function. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 121 +++++++++++++++---------------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f10f55690749c..c547f03904bca 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1193,76 +1193,73 @@ found: } } - if (min_dco_index > 2) { - WARN(1, "No valid parameters found for pixel clock: %dHz\n", - clock); + if (WARN(min_dco_index > 2, + "No valid parameters found for pixel clock: %dHz\n", clock)) return false; - } else { - wrpll_params->central_freq = dco_central_freq[min_dco_index]; - switch (dco_central_freq[min_dco_index]) { - case 9600000000ULL: - wrpll_params->central_freq = 0; - break; - case 9000000000ULL: - wrpll_params->central_freq = 1; - break; - case 8400000000ULL: - wrpll_params->central_freq = 3; - } + wrpll_params->central_freq = dco_central_freq[min_dco_index]; - switch (candidate_p0[min_dco_index]) { - case 1: - wrpll_params->pdiv = 0; - break; - case 2: - wrpll_params->pdiv = 1; - break; - case 3: - wrpll_params->pdiv = 2; - break; - case 7: - wrpll_params->pdiv = 4; - break; - default: - WARN(1, "Incorrect PDiv\n"); - } + switch (dco_central_freq[min_dco_index]) { + case 9600000000ULL: + wrpll_params->central_freq = 0; + break; + case 9000000000ULL: + wrpll_params->central_freq = 1; + break; + case 8400000000ULL: + wrpll_params->central_freq = 3; + } - switch (candidate_p2[min_dco_index]) { - case 5: - wrpll_params->kdiv = 0; - break; - case 2: - wrpll_params->kdiv = 1; - break; - case 3: - wrpll_params->kdiv = 2; - break; - case 1: - wrpll_params->kdiv = 3; - break; - default: - WARN(1, "Incorrect KDiv\n"); - } + switch (candidate_p0[min_dco_index]) { + case 1: + wrpll_params->pdiv = 0; + break; + case 2: + wrpll_params->pdiv = 1; + break; + case 3: + wrpll_params->pdiv = 2; + break; + case 7: + wrpll_params->pdiv = 4; + break; + default: + WARN(1, "Incorrect PDiv\n"); + } - wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; - wrpll_params->qdiv_mode = - (wrpll_params->qdiv_ratio == 1) ? 0 : 1; + switch (candidate_p2[min_dco_index]) { + case 5: + wrpll_params->kdiv = 0; + break; + case 2: + wrpll_params->kdiv = 1; + break; + case 3: + wrpll_params->kdiv = 2; + break; + case 1: + wrpll_params->kdiv = 3; + break; + default: + WARN(1, "Incorrect KDiv\n"); + } - dco_freq = candidate_p0[min_dco_index] * - candidate_p1[min_dco_index] * - candidate_p2[min_dco_index] * afe_clock; + wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; + wrpll_params->qdiv_mode = + (wrpll_params->qdiv_ratio == 1) ? 0 : 1; - /* - * Intermediate values are in Hz. - * Divide by MHz to match bsepc - */ - wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); - wrpll_params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + dco_freq = candidate_p0[min_dco_index] * + candidate_p1[min_dco_index] * + candidate_p2[min_dco_index] * afe_clock; - } + /* + * Intermediate values are in Hz. + * Divide by MHz to match bsepc + */ + wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + wrpll_params->dco_fraction = + div_u64(((div_u64(dco_freq, 24) - + wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); return true; } -- GitLab From 76516fbc294d60481f2427d6a42125364a629386 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:42 +0100 Subject: [PATCH 0024/7006] drm/i915/skl: Factor out computing the DPLL paramaters from the dividers This part doesn't depend on how we compute the DPLL dividers (p and p0/p1/p2) and can be reused even if we change the algorithm to do so. (something that is planned for a followup patch) Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 139 +++++++++++++++++-------------- 1 file changed, 75 insertions(+), 64 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index c547f03904bca..a8d3976f7c5fa 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1115,6 +1115,75 @@ struct skl_wrpll_params { uint32_t central_freq; }; +static void skl_wrpll_params_populate(struct skl_wrpll_params *params, + uint64_t afe_clock, + uint64_t central_freq, + uint32_t p0, uint32_t p1, uint32_t p2) +{ + uint64_t dco_freq; + + params->central_freq = central_freq; + + switch (central_freq) { + case 9600000000ULL: + params->central_freq = 0; + break; + case 9000000000ULL: + params->central_freq = 1; + break; + case 8400000000ULL: + params->central_freq = 3; + } + + switch (p0) { + case 1: + params->pdiv = 0; + break; + case 2: + params->pdiv = 1; + break; + case 3: + params->pdiv = 2; + break; + case 7: + params->pdiv = 4; + break; + default: + WARN(1, "Incorrect PDiv\n"); + } + + switch (p2) { + case 5: + params->kdiv = 0; + break; + case 2: + params->kdiv = 1; + break; + case 3: + params->kdiv = 2; + break; + case 1: + params->kdiv = 3; + break; + default: + WARN(1, "Incorrect KDiv\n"); + } + + params->qdiv_ratio = p1; + params->qdiv_mode = (params->qdiv_ratio == 1) ? 0 : 1; + + dco_freq = p0 * p1 * p2 * afe_clock; + + /* + * Intermediate values are in Hz. + * Divide by MHz to match bsepc + */ + params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + params->dco_fraction = + div_u64(((div_u64(dco_freq, 24) - + params->dco_integer * MHz(1)) * 0x8000), MHz(1)); +} + static bool skl_ddi_calculate_wrpll(int clock /* in Hz */, struct skl_wrpll_params *wrpll_params) @@ -1134,7 +1203,6 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, uint32_t dco_central_freq_deviation[3]; uint32_t i, P1, k, dco_count; bool retry_with_odd = false; - uint64_t dco_freq; /* Determine P0, P1 or P2 */ for (dco_count = 0; dco_count < 3; dco_count++) { @@ -1197,69 +1265,12 @@ found: "No valid parameters found for pixel clock: %dHz\n", clock)) return false; - wrpll_params->central_freq = dco_central_freq[min_dco_index]; - - switch (dco_central_freq[min_dco_index]) { - case 9600000000ULL: - wrpll_params->central_freq = 0; - break; - case 9000000000ULL: - wrpll_params->central_freq = 1; - break; - case 8400000000ULL: - wrpll_params->central_freq = 3; - } - - switch (candidate_p0[min_dco_index]) { - case 1: - wrpll_params->pdiv = 0; - break; - case 2: - wrpll_params->pdiv = 1; - break; - case 3: - wrpll_params->pdiv = 2; - break; - case 7: - wrpll_params->pdiv = 4; - break; - default: - WARN(1, "Incorrect PDiv\n"); - } - - switch (candidate_p2[min_dco_index]) { - case 5: - wrpll_params->kdiv = 0; - break; - case 2: - wrpll_params->kdiv = 1; - break; - case 3: - wrpll_params->kdiv = 2; - break; - case 1: - wrpll_params->kdiv = 3; - break; - default: - WARN(1, "Incorrect KDiv\n"); - } - - wrpll_params->qdiv_ratio = candidate_p1[min_dco_index]; - wrpll_params->qdiv_mode = - (wrpll_params->qdiv_ratio == 1) ? 0 : 1; - - dco_freq = candidate_p0[min_dco_index] * - candidate_p1[min_dco_index] * - candidate_p2[min_dco_index] * afe_clock; - - /* - * Intermediate values are in Hz. - * Divide by MHz to match bsepc - */ - wrpll_params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); - wrpll_params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - wrpll_params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + skl_wrpll_params_populate(wrpll_params, + afe_clock, + dco_central_freq[min_dco_index], + candidate_p0[min_dco_index], + candidate_p1[min_dco_index], + candidate_p2[min_dco_index]); return true; } -- GitLab From 30a7862de84e69abc3018c57184f485048eed9d8 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:43 +0100 Subject: [PATCH 0025/7006] drm/i915/skl: Remove unnecessary () used with div_u64() div_u64() can be either a inline function or a define, but in either case it's safe to provide expressions as parameters without outer () around them. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index a8d3976f7c5fa..416f8fbea34ea 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1178,10 +1178,10 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, * Intermediate values are in Hz. * Divide by MHz to match bsepc */ - params->dco_integer = div_u64(dco_freq, (24 * MHz(1))); + params->dco_integer = div_u64(dco_freq, 24 * MHz(1)); params->dco_fraction = - div_u64(((div_u64(dco_freq, 24) - - params->dco_integer * MHz(1)) * 0x8000), MHz(1)); + div_u64((div_u64(dco_freq, 24) - + params->dco_integer * MHz(1)) * 0x8000, MHz(1)); } static bool -- GitLab From 64311571a91fdd6d2ddc9055e9ba477f118067ad Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:44 +0100 Subject: [PATCH 0026/7006] drm/i915/skl: Remove unnecessary () used with abs_diff() abs_diff() properly protects its parameters, so no need for the outer () here. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 416f8fbea34ea..0f931740149b9 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1239,7 +1239,7 @@ found: if (found) { dco_central_freq_deviation[dco_count] = div64_u64(10000 * - abs_diff((candidate_p * afe_clock), + abs_diff(candidate_p * afe_clock, dco_central_freq[dco_count]), dco_central_freq[dco_count]); -- GitLab From 6358298337abfabcf1e2b211c433f2093e5e9b28 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:46 +0100 Subject: [PATCH 0027/7006] drm/i915: Correctly prefix HSW/BDW HDMI clock functions Those functions were the only one in existence when they were introduced. We now know they are only valid for HSW/BDW. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 0f931740149b9..8bb5291ca4da3 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -625,11 +625,11 @@ intel_ddi_get_crtc_new_encoder(struct intel_crtc_state *crtc_state) (void) (&__a == &__b); \ __a > __b ? (__a - __b) : (__b - __a); }) -struct wrpll_rnp { +struct hsw_wrpll_rnp { unsigned p, n2, r2; }; -static unsigned wrpll_get_budget_for_freq(int clock) +static unsigned hsw_wrpll_get_budget_for_freq(int clock) { unsigned budget; @@ -703,9 +703,9 @@ static unsigned wrpll_get_budget_for_freq(int clock) return budget; } -static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, - unsigned r2, unsigned n2, unsigned p, - struct wrpll_rnp *best) +static void hsw_wrpll_update_rnp(uint64_t freq2k, unsigned budget, + unsigned r2, unsigned n2, unsigned p, + struct hsw_wrpll_rnp *best) { uint64_t a, b, c, d, diff, diff_best; @@ -762,8 +762,7 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget, /* Otherwise a < c && b >= d, do nothing */ } -static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, - int reg) +static int hsw_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv, int reg) { int refclk = LC_FREQ; int n, p, r; @@ -929,10 +928,10 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, link_clock = 270000; break; case PORT_CLK_SEL_WRPLL1: - link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1); + link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1); break; case PORT_CLK_SEL_WRPLL2: - link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2); + link_clock = hsw_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2); break; case PORT_CLK_SEL_SPLL: pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK; @@ -1011,12 +1010,12 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, { uint64_t freq2k; unsigned p, n2, r2; - struct wrpll_rnp best = { 0, 0, 0 }; + struct hsw_wrpll_rnp best = { 0, 0, 0 }; unsigned budget; freq2k = clock / 100; - budget = wrpll_get_budget_for_freq(clock); + budget = hsw_wrpll_get_budget_for_freq(clock); /* Special case handling for 540 pixel clock: bypass WR PLL entirely * and directly pass the LC PLL to it. */ @@ -1060,8 +1059,8 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */, n2++) { for (p = P_MIN; p <= P_MAX; p += P_INC) - wrpll_update_rnp(freq2k, budget, - r2, n2, p, &best); + hsw_wrpll_update_rnp(freq2k, budget, + r2, n2, p, &best); } } -- GitLab From 877f61d947b6666205fee4ea7a04faf187a4ede5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 7 May 2015 18:38:47 +0100 Subject: [PATCH 0028/7006] drm/i915/skl: Don't try to store the wrong central frequency The orignal code started by storing the actual central frequency (in Hz, using a uint64_t) in a uint32_t which codes for the register value. That can't be right. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 8bb5291ca4da3..832e4e141b3d6 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1121,8 +1121,6 @@ static void skl_wrpll_params_populate(struct skl_wrpll_params *params, { uint64_t dco_freq; - params->central_freq = central_freq; - switch (central_freq) { case 9600000000ULL: params->central_freq = 0; -- GitLab From 8d2fdc3f26d150633004a04b53a4398cc2eed343 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 27 May 2015 10:52:32 +0100 Subject: [PATCH 0029/7006] drm/i915: Only show view type for GGTT VMAs Printing it for PPGTT VMAs only adds noise since we have defined view types are only applicable for GGTT. Signed-off-by: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 88cc793c46d36..3e17210c3277e 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -156,13 +156,13 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) if (obj->fence_reg != I915_FENCE_REG_NONE) seq_printf(m, " (fence: %d)", obj->fence_reg); list_for_each_entry(vma, &obj->vma_list, vma_link) { - if (!i915_is_ggtt(vma->vm)) - seq_puts(m, " (pp"); + seq_printf(m, " (%sgtt offset: %08llx, size: %08llx", + i915_is_ggtt(vma->vm) ? "g" : "pp", + vma->node.start, vma->node.size); + if (i915_is_ggtt(vma->vm)) + seq_printf(m, ", type: %u)", vma->ggtt_view.type); else - seq_puts(m, " (g"); - seq_printf(m, "gtt offset: %08llx, size: %08llx, type: %u)", - vma->node.start, vma->node.size, - vma->ggtt_view.type); + seq_puts(m, ")"); } if (obj->stolen) seq_printf(m, " (stolen: %08llx)", obj->stolen->start); -- GitLab From 1b1d27160dad5478f614f95ae5a87bd8382c5612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 May 2015 11:22:31 +0300 Subject: [PATCH 0030/7006] drm/i915: Fix i855 get_display_clock_speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Actually read the HPLLCC register insted of assuming it's 0. Fix the HPLLCC bit definitions and all the missing ones from the 852GME spec. 852GME, 854 and 855 all seem to match the same HPLLC encoding even though only some of the values are valid is some of the platforms. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä (v1) Signed-off-by: Mika Kahola Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 11 ++++++++--- drivers/gpu/drm/i915/intel_display.c | 15 ++++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 6d3fead3a3586..a2daf599c97dc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -50,12 +50,17 @@ /* PCI config space */ -#define HPLLCC 0xc0 /* 855 only */ -#define GC_CLOCK_CONTROL_MASK (0xf << 0) +#define HPLLCC 0xc0 /* 85x only */ +#define GC_CLOCK_CONTROL_MASK (0x7 << 0) #define GC_CLOCK_133_200 (0 << 0) #define GC_CLOCK_100_200 (1 << 0) #define GC_CLOCK_100_133 (2 << 0) -#define GC_CLOCK_166_250 (3 << 0) +#define GC_CLOCK_133_266 (3 << 0) +#define GC_CLOCK_133_200_2 (4 << 0) +#define GC_CLOCK_133_266_2 (5 << 0) +#define GC_CLOCK_166_266 (6 << 0) +#define GC_CLOCK_166_250 (7 << 0) + #define GCFGC2 0xda #define GCFGC 0xf0 /* 915+ only */ #define GC_LOW_FREQUENCY_ENABLE (1 << 7) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 067b1dee1b906..0b1d8d68ad2bb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6822,20 +6822,29 @@ static int i865_get_display_clock_speed(struct drm_device *dev) return 266667; } -static int i855_get_display_clock_speed(struct drm_device *dev) +static int i85x_get_display_clock_speed(struct drm_device *dev) { u16 hpllcc = 0; + + pci_bus_read_config_word(dev->pdev->bus, + PCI_DEVFN(0, 3), HPLLCC, &hpllcc); + /* Assume that the hardware is in the high speed state. This * should be the default. */ switch (hpllcc & GC_CLOCK_CONTROL_MASK) { case GC_CLOCK_133_200: + case GC_CLOCK_133_200_2: case GC_CLOCK_100_200: return 200000; case GC_CLOCK_166_250: return 250000; case GC_CLOCK_100_133: return 133333; + case GC_CLOCK_133_266: + case GC_CLOCK_133_266_2: + case GC_CLOCK_166_266: + return 266667; } /* Shouldn't happen */ @@ -14399,8 +14408,8 @@ static void intel_init_display(struct drm_device *dev) i865_get_display_clock_speed; else if (IS_I85X(dev)) dev_priv->display.get_display_clock_speed = - i855_get_display_clock_speed; - else /* 852, 830 */ + i85x_get_display_clock_speed; + else /* 830 */ dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; -- GitLab From 65cd2b3fa521d1abec13dd36bf1bfc8f2469d8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 May 2015 11:22:32 +0300 Subject: [PATCH 0031/7006] drm/i915: Fix 852GM/GMV cdclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It seems 852GM/GMV uses a different HPLLCC encoding than the other 85x platforms. For 852GM/GMV cdclk is always 133MHz. Try to detect that using the PCI revision (sinc the device ID seems useless for that). I'm not at all sure this is a good idea, but according to the specs it should work. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä (v1) Signed-off-by: Mika Kahola Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0b1d8d68ad2bb..73a46149564ab 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6826,6 +6826,14 @@ static int i85x_get_display_clock_speed(struct drm_device *dev) { u16 hpllcc = 0; + /* + * 852GM/852GMV only supports 133 MHz and the HPLLCC + * encoding is different :( + * FIXME is this the right way to detect 852GM/852GMV? + */ + if (dev->pdev->revision == 0x1) + return 133333; + pci_bus_read_config_word(dev->pdev->bus, PCI_DEVFN(0, 3), HPLLCC, &hpllcc); -- GitLab From 34edce2fea6960ce5855d6e09902f82822c374c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 May 2015 11:22:33 +0300 Subject: [PATCH 0032/7006] drm/i915: Add cdclk extraction for g33, g965gm and g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement cdclk extraction for g33, 965gm and g4x platforms. The details came from configdb. Sadly there isn't anything there for other gen3/gen4 chipsets. So far I've tested this on one ELK where it gave me a HPLL VCO of 5333 MHz and cdclk of 444 MHz which seems perfectly sane for this machine. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 + drivers/gpu/drm/i915/intel_display.c | 183 ++++++++++++++++++++++++++- 2 files changed, 185 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a2daf599c97dc..00cec1f70b649 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2493,6 +2493,9 @@ enum skl_disp_power_wells { #define CLKCFG_MEM_800 (3 << 4) #define CLKCFG_MEM_MASK (7 << 4) +#define HPLLVCO (MCHBAR_MIRROR_BASE + 0xc38) +#define HPLLVCO_MOBILE (MCHBAR_MIRROR_BASE + 0xc0f) + #define TSC1 0x11001 #define TSE (1<<0) #define TR1 0x11006 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 73a46149564ab..9aa3c597e5cb1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6864,6 +6864,175 @@ static int i830_get_display_clock_speed(struct drm_device *dev) return 133333; } +static unsigned int intel_hpll_vco(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + static const unsigned int blb_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + [4] = 6400000, + }; + static const unsigned int pnv_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + [4] = 2666667, + }; + static const unsigned int cl_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 6400000, + [4] = 3333333, + [5] = 3566667, + [6] = 4266667, + }; + static const unsigned int elk_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 4800000, + }; + static const unsigned int ctg_vco[8] = { + [0] = 3200000, + [1] = 4000000, + [2] = 5333333, + [3] = 6400000, + [4] = 2666667, + [5] = 4266667, + }; + const unsigned int *vco_table; + unsigned int vco; + uint8_t tmp = 0; + + /* FIXME other chipsets? */ + if (IS_GM45(dev)) + vco_table = ctg_vco; + else if (IS_G4X(dev)) + vco_table = elk_vco; + else if (IS_CRESTLINE(dev)) + vco_table = cl_vco; + else if (IS_PINEVIEW(dev)) + vco_table = pnv_vco; + else if (IS_G33(dev)) + vco_table = blb_vco; + else + return 0; + + tmp = I915_READ(IS_MOBILE(dev) ? HPLLVCO_MOBILE : HPLLVCO); + + vco = vco_table[tmp & 0x7]; + if (vco == 0) + DRM_ERROR("Bad HPLL VCO (HPLLVCO=0x%02x)\n", tmp); + else + DRM_DEBUG_KMS("HPLL VCO %u kHz\n", vco); + + return vco; +} + +static int gm45_get_display_clock_speed(struct drm_device *dev) +{ + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = (tmp >> 12) & 0x1; + + switch (vco) { + case 2666667: + case 4000000: + case 5333333: + return cdclk_sel ? 333333 : 222222; + case 3200000: + return cdclk_sel ? 320000 : 228571; + default: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u, CFGC=0x%04x\n", vco, tmp); + return 222222; + } +} + +static int i965gm_get_display_clock_speed(struct drm_device *dev) +{ + static const uint8_t div_3200[] = { 16, 10, 8 }; + static const uint8_t div_4000[] = { 20, 12, 10 }; + static const uint8_t div_5333[] = { 24, 16, 14 }; + const uint8_t *div_table; + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = ((tmp >> 8) & 0x1f) - 1; + + if (cdclk_sel >= ARRAY_SIZE(div_3200)) + goto fail; + + switch (vco) { + case 3200000: + div_table = div_3200; + break; + case 4000000: + div_table = div_4000; + break; + case 5333333: + div_table = div_5333; + break; + default: + goto fail; + } + + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); + + fail: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp); + return 200000; +} + +static int g33_get_display_clock_speed(struct drm_device *dev) +{ + static const uint8_t div_3200[] = { 12, 10, 8, 7, 5, 16 }; + static const uint8_t div_4000[] = { 14, 12, 10, 8, 6, 20 }; + static const uint8_t div_4800[] = { 20, 14, 12, 10, 8, 24 }; + static const uint8_t div_5333[] = { 20, 16, 12, 12, 8, 28 }; + const uint8_t *div_table; + unsigned int cdclk_sel, vco = intel_hpll_vco(dev); + uint16_t tmp = 0; + + pci_read_config_word(dev->pdev, GCFGC, &tmp); + + cdclk_sel = (tmp >> 4) & 0x7; + + if (cdclk_sel >= ARRAY_SIZE(div_3200)) + goto fail; + + switch (vco) { + case 3200000: + div_table = div_3200; + break; + case 4000000: + div_table = div_4000; + break; + case 4800000: + div_table = div_4800; + break; + case 5333333: + div_table = div_5333; + break; + default: + goto fail; + } + + return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); + + fail: + DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp); + return 190476; +} + static void intel_reduce_m_n_ratio(uint32_t *num, uint32_t *den) { @@ -14396,9 +14565,21 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.get_display_clock_speed = ilk_get_display_clock_speed; else if (IS_I945G(dev) || IS_BROADWATER(dev) || - IS_GEN6(dev) || IS_IVYBRIDGE(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev))) + IS_GEN6(dev) || IS_IVYBRIDGE(dev)) dev_priv->display.get_display_clock_speed = i945_get_display_clock_speed; + else if (IS_GM45(dev)) + dev_priv->display.get_display_clock_speed = + gm45_get_display_clock_speed; + else if (IS_CRESTLINE(dev)) + dev_priv->display.get_display_clock_speed = + i965gm_get_display_clock_speed; + else if (IS_PINEVIEW(dev)) + dev_priv->display.get_display_clock_speed = + pnv_get_display_clock_speed; + else if (IS_G33(dev) || IS_G4X(dev)) + dev_priv->display.get_display_clock_speed = + g33_get_display_clock_speed; else if (IS_I915G(dev)) dev_priv->display.get_display_clock_speed = i915_get_display_clock_speed; -- GitLab From 623e01e53927b05e96781532bdb40536e833e276 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 22 May 2015 11:22:34 +0300 Subject: [PATCH 0033/7006] drm/i915: Warn when cdclk for the platforms is not known MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Print a warning if we fall through the .get_display_clock_speed() function pointer setup. We end up assuming a 133MHz cdclk which should mean that at least we avoid any 0 deivisions and whatnot. But this could at least help remind people that they have to provide this function for new platforms. v2: Rebased to the latest v3: Rebased to the latest Signed-off-by: Ville Syrjälä (v1) Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9aa3c597e5cb1..92f6ed3d3c165 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14598,9 +14598,11 @@ static void intel_init_display(struct drm_device *dev) else if (IS_I85X(dev)) dev_priv->display.get_display_clock_speed = i85x_get_display_clock_speed; - else /* 830 */ + else { /* 830 */ + WARN(!IS_I830(dev), "Unknown platform. Assuming 133 MHz CDCLK\n"); dev_priv->display.get_display_clock_speed = i830_get_display_clock_speed; + } if (IS_GEN5(dev)) { dev_priv->display.fdi_link_train = ironlake_fdi_link_train; -- GitLab From c91711f93f7102c4c71896b6e9273f222bf31989 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:48 +0300 Subject: [PATCH 0034/7006] drm/i915: add for_each_hpd_pin to iterate over hotplug pins No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_irq.c | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 173c9051bf86e..60aa9626f91fa 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -217,6 +217,9 @@ enum hpd_pin { HPD_NUM_PINS }; +#define for_each_hpd_pin(__pin) \ + for ((__pin) = (HPD_NONE + 1); (__pin) < HPD_NUM_PINS; (__pin)++) + struct i915_hotplug { struct work_struct hotplug_work; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 91cb0b6ec47b2..ad8897828b0cf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1441,7 +1441,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, hotplug_trigger, dig_hotplug_reg); spin_lock(&dev_priv->irq_lock); - for (i = 1; i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { bool long_hpd; if (!(hpd[i] & hotplug_trigger)) @@ -1477,7 +1477,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_dig = true; } - for (i = 1; i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { if (hpd[i] & hotplug_trigger && dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* @@ -4292,7 +4292,7 @@ static void intel_hpd_irq_reenable_work(struct work_struct *work) intel_runtime_pm_get(dev_priv); spin_lock_irq(&dev_priv->irq_lock); - for (i = (HPD_NONE + 1); i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { struct drm_connector *connector; if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) @@ -4450,7 +4450,7 @@ void intel_hpd_init(struct drm_i915_private *dev_priv) struct drm_connector *connector; int i; - for (i = 1; i < HPD_NUM_PINS; i++) { + for_each_hpd_pin(i) { dev_priv->hotplug.stats[i].count = 0; dev_priv->hotplug.stats[i].state = HPD_ENABLED; } -- GitLab From 641a969eff3ffb01088736ef9531caffe38a6fd9 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:49 +0300 Subject: [PATCH 0035/7006] drm/i915: simplify conditions for skipping the 2nd hpd loop iterations Multiple positive and negative checks for hpd[i] & hotplug_trigger gets hard to read. Simplify. This should make follow-up patches merging the two loops easier. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ad8897828b0cf..536e97381cefe 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1478,8 +1478,10 @@ static void intel_hpd_irq_handler(struct drm_device *dev, } for_each_hpd_pin(i) { - if (hpd[i] & hotplug_trigger && - dev_priv->hotplug.stats[i].state == HPD_DISABLED) { + if (!(hpd[i] & hotplug_trigger)) + continue; + + if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* * On GMCH platforms the interrupt mask bits only * prevent irq generation, not the setting of the @@ -1493,8 +1495,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; } - if (!(hpd[i] & hotplug_trigger) || - dev_priv->hotplug.stats[i].state != HPD_ENABLED) + if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; if (!(dig_port_mask & hpd[i])) { -- GitLab From ab68d5bb0b49727e4049b018185f82764cf44736 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:50 +0300 Subject: [PATCH 0036/7006] drm/i915: put back the indent in intel_hpd_irq_handler In an unfortunate back and forth stepping, retract the earlier change to reduce indent. This is to make merging the two loops easier. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 51 ++++++++++++++++----------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 536e97381cefe..4840b21c18694 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1442,39 +1442,38 @@ static void intel_hpd_irq_handler(struct drm_device *dev, spin_lock(&dev_priv->irq_lock); for_each_hpd_pin(i) { - bool long_hpd; - if (!(hpd[i] & hotplug_trigger)) continue; port = get_port_from_pin(i); - if (!port || !dev_priv->hotplug.irq_port[port]) - continue; + if (port && dev_priv->hotplug.irq_port[port]) { + bool long_hpd; - if (!HAS_GMCH_DISPLAY(dev_priv)) { - dig_shift = pch_port_to_hotplug_shift(port); - long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } else { - dig_shift = i915_port_to_hotplug_shift(port); - long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } + if (!HAS_GMCH_DISPLAY(dev_priv)) { + dig_shift = pch_port_to_hotplug_shift(port); + long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } else { + dig_shift = i915_port_to_hotplug_shift(port); + long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; + } - DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), - long_hpd ? "long" : "short"); - /* - * For long HPD pulses we want to have the digital queue happen, - * but we still want HPD storm detection to function. - */ - if (long_hpd) { - dev_priv->hotplug.long_port_mask |= (1 << port); - dig_port_mask |= hpd[i]; - } else { - /* for short HPD just trigger the digital queue */ - dev_priv->hotplug.short_port_mask |= (1 << port); - hotplug_trigger &= ~hpd[i]; - } + DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), + long_hpd ? "long" : "short"); + /* + * For long HPD pulses we want to have the digital queue happen, + * but we still want HPD storm detection to function. + */ + if (long_hpd) { + dev_priv->hotplug.long_port_mask |= (1 << port); + dig_port_mask |= hpd[i]; + } else { + /* for short HPD just trigger the digital queue */ + dev_priv->hotplug.short_port_mask |= (1 << port); + hotplug_trigger &= ~hpd[i]; + } - queue_dig = true; + queue_dig = true; + } } for_each_hpd_pin(i) { -- GitLab From 9ace043310ba4875e08863b9f31f429d853685f2 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:51 +0300 Subject: [PATCH 0037/7006] drm/i915: merge the two hpd loops in intel_hpd_irq_handler to one Nothing in the two consecutive loops over hpd pins depends on state in a larger context than the single hpd pin. If we skip the rest of the loop on short hpd pulses, we can merge the two loops into one. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 4840b21c18694..b53b91744a17b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1463,22 +1463,17 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * For long HPD pulses we want to have the digital queue happen, * but we still want HPD storm detection to function. */ + queue_dig = true; if (long_hpd) { dev_priv->hotplug.long_port_mask |= (1 << port); + /* FIXME: this can be simplified. */ dig_port_mask |= hpd[i]; } else { /* for short HPD just trigger the digital queue */ dev_priv->hotplug.short_port_mask |= (1 << port); - hotplug_trigger &= ~hpd[i]; + continue; } - - queue_dig = true; } - } - - for_each_hpd_pin(i) { - if (!(hpd[i] & hotplug_trigger)) - continue; if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { /* -- GitLab From c8727233aa80cdf54e3460ac5ebc93c05b09ff5d Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:52 +0300 Subject: [PATCH 0038/7006] drm/i915: simplify condition for digital port As the hpd loops have been merged together, we don't have to maintain state for all hpd triggers. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index b53b91744a17b..6fffbfd3121a7 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1432,7 +1432,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, bool storm_detected = false; bool queue_dig = false, queue_hp = false; u32 dig_shift; - u32 dig_port_mask = 0; + bool is_dig_port; if (!hotplug_trigger) return; @@ -1446,7 +1446,9 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; port = get_port_from_pin(i); - if (port && dev_priv->hotplug.irq_port[port]) { + is_dig_port = port && dev_priv->hotplug.irq_port[port]; + + if (is_dig_port) { bool long_hpd; if (!HAS_GMCH_DISPLAY(dev_priv)) { @@ -1466,8 +1468,6 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_dig = true; if (long_hpd) { dev_priv->hotplug.long_port_mask |= (1 << port); - /* FIXME: this can be simplified. */ - dig_port_mask |= hpd[i]; } else { /* for short HPD just trigger the digital queue */ dev_priv->hotplug.short_port_mask |= (1 << port); @@ -1492,7 +1492,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) continue; - if (!(dig_port_mask & hpd[i])) { + if (!is_dig_port) { dev_priv->hotplug.event_bits |= (1 << i); queue_hp = true; } -- GitLab From 676574dffa4d67ff4e8b2ec796eb9f41aad925d8 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:53 +0300 Subject: [PATCH 0039/7006] drm/i915: abstract away platform specific parts from hpd handling Split intel_hpd_irq_handler into platforms specific and platform agnostic parts. The platform specific parts decode the registers into information about which hpd pins triggered, and if they were long pulses. The platform agnostic parts do further processing, such as interrupt storm mitigation and scheduling bottom halves. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 147 ++++++++++++++++++++++---------- 1 file changed, 101 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 6fffbfd3121a7..d401c863aeee0 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1375,35 +1375,31 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 -static int pch_port_to_hotplug_shift(enum port port) +static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { - case PORT_A: - case PORT_E: - default: - return -1; case PORT_B: - return 0; + return val & PORTB_HOTPLUG_LONG_DETECT; case PORT_C: - return 8; + return val & PORTC_HOTPLUG_LONG_DETECT; case PORT_D: - return 16; + return val & PORTD_HOTPLUG_LONG_DETECT; + default: + return false; } } -static int i915_port_to_hotplug_shift(enum port port) +static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { - case PORT_A: - case PORT_E: - default: - return -1; case PORT_B: - return 17; + return val & PORTB_HOTPLUG_INT_LONG_PULSE; case PORT_C: - return 19; + return val & PORTC_HOTPLUG_INT_LONG_PULSE; case PORT_D: - return 21; + return val & PORTD_HOTPLUG_INT_LONG_PULSE; + default: + return false; } } @@ -1421,43 +1417,96 @@ static enum port get_port_from_pin(enum hpd_pin pin) } } +/* Get a bit mask of pins that have triggered, and which ones may be long. */ +static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, + u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS]) +{ + int i; + + *pin_mask = 0; + *long_mask = 0; + + if (!hotplug_trigger) + return; + + for_each_hpd_pin(i) { + if (hpd[i] & hotplug_trigger) { + *pin_mask |= BIT(i); + + if (pch_port_hotplug_long_detect(get_port_from_pin(i), dig_hotplug_reg)) + *long_mask |= BIT(i); + } + } + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", + hotplug_trigger, dig_hotplug_reg, *pin_mask); + +} + +/* Get a bit mask of pins that have triggered, and which ones may be long. */ +static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, + u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS]) +{ + int i; + + *pin_mask = 0; + *long_mask = 0; + + if (!hotplug_trigger) + return; + + for_each_hpd_pin(i) { + if (hpd[i] & hotplug_trigger) { + *pin_mask |= BIT(i); + + if (i9xx_port_hotplug_long_detect(get_port_from_pin(i), hotplug_trigger)) + *long_mask |= BIT(i); + } + } + + DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n", + hotplug_trigger, *pin_mask); +} + +/** + * intel_hpd_irq_handler - main hotplug irq handler + * @dev: drm device + * @pin_mask: a mask of hpd pins that have triggered the irq + * @long_mask: a mask of hpd pins that may be long hpd pulses + * + * This is the main hotplug irq handler for all platforms. The platform specific + * irq handlers call the platform specific hotplug irq handlers, which read and + * decode the appropriate registers into bitmasks about hpd pins that have + * triggered (@pin_mask), and which of those pins may be long pulses + * (@long_mask). The @long_mask is ignored if the port corresponding to the pin + * is not a digital port. + * + * Here, we do hotplug irq storm detection and mitigation, and pass further + * processing to appropriate bottom halves. + */ static void intel_hpd_irq_handler(struct drm_device *dev, - u32 hotplug_trigger, - u32 dig_hotplug_reg, - const u32 hpd[HPD_NUM_PINS]) + u32 pin_mask, u32 long_mask) { struct drm_i915_private *dev_priv = dev->dev_private; int i; enum port port; bool storm_detected = false; bool queue_dig = false, queue_hp = false; - u32 dig_shift; bool is_dig_port; - if (!hotplug_trigger) + if (!pin_mask) return; - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x\n", - hotplug_trigger, dig_hotplug_reg); - spin_lock(&dev_priv->irq_lock); for_each_hpd_pin(i) { - if (!(hpd[i] & hotplug_trigger)) + if (!(BIT(i) & pin_mask)) continue; port = get_port_from_pin(i); is_dig_port = port && dev_priv->hotplug.irq_port[port]; if (is_dig_port) { - bool long_hpd; - - if (!HAS_GMCH_DISPLAY(dev_priv)) { - dig_shift = pch_port_to_hotplug_shift(port); - long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } else { - dig_shift = i915_port_to_hotplug_shift(port); - long_hpd = (hotplug_trigger >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT; - } + bool long_hpd = long_mask & BIT(i); DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), long_hpd ? "long" : "short"); @@ -1483,9 +1532,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, * interrupts on saner platforms. */ WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), - "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n", - hotplug_trigger, i, hpd[i]); - + "Received HPD interrupt on pin %d although disabled\n", i); continue; } @@ -1493,7 +1540,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, continue; if (!is_dig_port) { - dev_priv->hotplug.event_bits |= (1 << i); + dev_priv->hotplug.event_bits |= BIT(i); queue_hp = true; } @@ -1505,7 +1552,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) { dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED; - dev_priv->hotplug.event_bits &= ~(1 << i); + dev_priv->hotplug.event_bits &= ~BIT(i); DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); storm_detected = true; } else { @@ -1753,6 +1800,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT); + u32 pin_mask, long_mask; if (!hotplug_status) return; @@ -1767,14 +1815,16 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_g4x); + i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_g4x); + intel_hpd_irq_handler(dev, pin_mask, long_mask); if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) dp_aux_irq_handler(dev); } else { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - intel_hpd_irq_handler(dev, hotplug_trigger, 0, hpd_status_i915); + i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_i915); + intel_hpd_irq_handler(dev, pin_mask, long_mask); } } @@ -1874,11 +1924,13 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; u32 dig_hotplug_reg; + u32 pin_mask, long_mask; dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_ibx); + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_ibx); + intel_hpd_irq_handler(dev, pin_mask, long_mask); if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -1971,11 +2023,13 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; u32 dig_hotplug_reg; + u32 pin_mask, long_mask; dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_hpd_irq_handler(dev, hotplug_trigger, dig_hotplug_reg, hpd_cpt); + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_cpt); + intel_hpd_irq_handler(dev, pin_mask, long_mask); if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> @@ -2174,8 +2228,8 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg) static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) { struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t hp_control; - uint32_t hp_trigger; + u32 hp_control, hp_trigger; + u32 pin_mask, long_mask; /* Get the status */ hp_trigger = iir_status & BXT_DE_PORT_HOTPLUG_MASK; @@ -2191,7 +2245,8 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) hp_control & BXT_HOTPLUG_CTL_MASK); /* Check for HPD storm and schedule bottom half */ - intel_hpd_irq_handler(dev, hp_trigger, hp_control, hpd_bxt); + pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt); + intel_hpd_irq_handler(dev, pin_mask, long_mask); /* * FIXME: Save the hot plug status for bottom half before -- GitLab From 475c2e3b3cfba9283793d56742dc2cae2712574b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 28 May 2015 15:43:54 +0300 Subject: [PATCH 0040/7006] drm/i915/bxt: clear hpd status sticky bits earlier The hotplug status is cached in hp_control, and will be passed on to bottom halves through intel_hpd_irq_handler(), so we can clear the sticky bits earlier. While at it, drop the redundant logging of the hotplug status, which will also be logged by pch_get_hpd_pins(). Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d401c863aeee0..e4260b0924f1f 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2241,21 +2241,11 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) return; } - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n", - hp_control & BXT_HOTPLUG_CTL_MASK); + /* Clear sticky bits in hpd status */ + I915_WRITE(BXT_HOTPLUG_CTL, hp_control); - /* Check for HPD storm and schedule bottom half */ pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt); intel_hpd_irq_handler(dev, pin_mask, long_mask); - - /* - * FIXME: Save the hot plug status for bottom half before - * clearing the sticky status bits, else the status will be - * lost. - */ - - /* Clear sticky bits in hpd status */ - I915_WRITE(BXT_HOTPLUG_CTL, hp_control); } static irqreturn_t gen8_irq_handler(int irq, void *arg) -- GitLab From bd4b4827acdc00bf9e71f939d160102021d10d4f Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Fri, 29 May 2015 14:28:09 +0300 Subject: [PATCH 0041/7006] drm/i915: Silence compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Silence the following -Wmaybe-uninitialized warnings and make the code more clear. drivers/gpu/drm/i915/intel_display.c: In function ‘__intel_set_mode’: drivers/gpu/drm/i915/intel_display.c:11844:14: warning: ‘crtc_state’ may be used uninitialized in this function [-Wmaybe-uninitialized] return state->mode_changed || state->active_changed; ^ drivers/gpu/drm/i915/intel_display.c:11854:25: note: ‘crtc_state’ was declared here struct drm_crtc_state *crtc_state; ^ drivers/gpu/drm/i915/intel_display.c:11868:6: warning: ‘crtc’ may be used uninitialized in this function [-Wmaybe-uninitialized] if (crtc != intel_encoder->base.crtc) ^ drivers/gpu/drm/i915/intel_display.c:11853:19: note: ‘crtc’ was declared here struct drm_crtc *crtc; Reported-by: Chris Wilson Suggested-by: Chris Wilson Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 42 ++++++++++++++-------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 92f6ed3d3c165..475779ae4bec6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12045,15 +12045,15 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!intel_encoder->base.crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc == intel_encoder->base.crtc) - break; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc != intel_encoder->base.crtc) + continue; - if (crtc != intel_encoder->base.crtc) - continue; + if (crtc_state->enable && needs_modeset(crtc_state)) + intel_encoder->connectors_active = false; - if (crtc_state->enable && needs_modeset(crtc_state)) - intel_encoder->connectors_active = false; + break; + } } drm_atomic_helper_swap_state(state->dev, state); @@ -12068,24 +12068,24 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!connector->encoder || !connector->encoder->crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc == connector->encoder->crtc) - break; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (crtc != connector->encoder->crtc) + continue; - if (crtc != connector->encoder->crtc) - continue; + if (crtc->state->enable && needs_modeset(crtc->state)) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; - if (crtc->state->enable && needs_modeset(crtc->state)) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; + connector->dpms = DRM_MODE_DPMS_ON; + drm_object_property_set_value(&connector->base, + dpms_property, + DRM_MODE_DPMS_ON); - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, - dpms_property, - DRM_MODE_DPMS_ON); + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } - intel_encoder = to_intel_encoder(connector->encoder); - intel_encoder->connectors_active = true; + break; } } -- GitLab From a2ee48d60eed9cfb6447a4233370aee4ea88108b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Fri, 29 May 2015 16:14:37 +0300 Subject: [PATCH 0042/7006] drm/i915: abstract hpd irq storm detection Simplify intel_hpd_irq_handler() by extracting HPD irq storm detection to a separate function. Signed-off-by: Jani Nikula Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 53 +++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index e4260b0924f1f..eb52a039d6287 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1375,6 +1375,45 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, #define HPD_STORM_DETECT_PERIOD 1000 #define HPD_STORM_THRESHOLD 5 +/** + * intel_hpd_irq_storm - gather stats and detect HPD irq storm on a pin + * @dev_priv: private driver data pointer + * @pin: the pin to gather stats on + * + * Gather stats about HPD irqs from the specified @pin, and detect irq + * storms. Only the pin specific stats and state are changed, the caller is + * responsible for further action. + * + * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, + * otherwise it's considered an irq storm, and the irq state is set to + * @HPD_MARK_DISABLED. + * + * Return true if an irq storm was detected on @pin. + */ +static bool intel_hpd_irq_storm(struct drm_i915_private *dev_priv, + enum hpd_pin pin) +{ + unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; + unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); + bool storm = false; + + if (!time_in_range(jiffies, start, end)) { + dev_priv->hotplug.stats[pin].last_jiffies = jiffies; + dev_priv->hotplug.stats[pin].count = 0; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); + } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { + dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); + storm = true; + } else { + dev_priv->hotplug.stats[pin].count++; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, + dev_priv->hotplug.stats[pin].count); + } + + return storm; +} + static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -1544,21 +1583,9 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_hp = true; } - if (!time_in_range(jiffies, dev_priv->hotplug.stats[i].last_jiffies, - dev_priv->hotplug.stats[i].last_jiffies - + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD))) { - dev_priv->hotplug.stats[i].last_jiffies = jiffies; - dev_priv->hotplug.stats[i].count = 0; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", i); - } else if (dev_priv->hotplug.stats[i].count > HPD_STORM_THRESHOLD) { - dev_priv->hotplug.stats[i].state = HPD_MARK_DISABLED; + if (intel_hpd_irq_storm(dev_priv, i)) { dev_priv->hotplug.event_bits &= ~BIT(i); - DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", i); storm_detected = true; - } else { - dev_priv->hotplug.stats[i].count++; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", i, - dev_priv->hotplug.stats[i].count); } } -- GitLab From 5b6fd12a88a7233b58c669dc87979da9a69728b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 2 Jun 2015 15:37:35 +0300 Subject: [PATCH 0043/7006] drm/i915: Move WaBarrierPerformanceFixDisable:skl to skl code from chv code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 65ca7514e21adbee25b8175fc909759c735d00ff Author: Damien Lespiau Date: Mon Feb 9 19:33:22 2015 +0000 drm/i915/skl: Implement WaBarrierPerformanceFixDisable got misapplied and the code landed in chv_init_workarounds() instead of the intended skl_init_workarounds(). Move it over to the right place. Cc: Damien Lespiau Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Reviewed-by: Ben Widawsky Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ringbuffer.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index d934f857394dd..edd47baa119c5 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -901,13 +901,6 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4); - if (INTEL_REVID(dev) == SKL_REVID_C0 || - INTEL_REVID(dev) == SKL_REVID_D0) - /* WaBarrierPerformanceFixDisable:skl */ - WA_SET_BIT_MASKED(HDC_CHICKEN0, - HDC_FENCE_DEST_SLM_DISABLE | - HDC_BARRIER_PERFORMANCE_DISABLE); - return 0; } @@ -1041,6 +1034,13 @@ static int skl_init_workarounds(struct intel_engine_cs *ring) HDC_FORCE_NON_COHERENT); } + if (INTEL_REVID(dev) == SKL_REVID_C0 || + INTEL_REVID(dev) == SKL_REVID_D0) + /* WaBarrierPerformanceFixDisable:skl */ + WA_SET_BIT_MASKED(HDC_CHICKEN0, + HDC_FENCE_DEST_SLM_DISABLE | + HDC_BARRIER_PERFORMANCE_DISABLE); + return skl_tune_iz_hashing(ring); } -- GitLab From 64987fc59d90738715703362292f743b7dbbe76b Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Tue, 26 May 2015 17:50:13 +0530 Subject: [PATCH 0044/7006] drm/i915/bxt: edp1.4 Intermediate Freq support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BXT supports following intermediate link rates for edp: 2.16GHz, 2.43GHz, 3.24GHz, 4.32GHz. Adding support for programming the intermediate rates. v2: Adding clock in bxt_clk_div struct and then look for the entry with required rate (Ville) v3: 'clock' has the selected value, no need to use link_bw or rate_select for selecting pll(Ville) v4: Make bxt_dp_clk_val const and remove size (Ville) v5: Rebased v6: Removed setting of vco while rebasing in v5, adding it back Signed-off-by: Sonika Jindal Reviewed-by: Ville Syrjälä (v4) Reviewed-by: Vandana Kannan Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 39 +++++++++++++------------------- drivers/gpu/drm/i915/intel_dp.c | 7 +++++- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 832e4e141b3d6..3eaf5c0505737 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1348,6 +1348,7 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, /* bxt clock parameters */ struct bxt_clk_div { + int clock; uint32_t p1; uint32_t p2; uint32_t m2_int; @@ -1357,14 +1358,14 @@ struct bxt_clk_div { }; /* pre-calculated values for DP linkrates */ -static struct bxt_clk_div bxt_dp_clk_val[7] = { - /* 162 */ {4, 2, 32, 1677722, 1, 1}, - /* 270 */ {4, 1, 27, 0, 0, 1}, - /* 540 */ {2, 1, 27, 0, 0, 1}, - /* 216 */ {3, 2, 32, 1677722, 1, 1}, - /* 243 */ {4, 1, 24, 1258291, 1, 1}, - /* 324 */ {4, 1, 32, 1677722, 1, 1}, - /* 432 */ {3, 1, 32, 1677722, 1, 1} +static const struct bxt_clk_div bxt_dp_clk_val[] = { + {162000, 4, 2, 32, 1677722, 1, 1}, + {270000, 4, 1, 27, 0, 0, 1}, + {540000, 2, 1, 27, 0, 0, 1}, + {216000, 3, 2, 32, 1677722, 1, 1}, + {243000, 4, 1, 24, 1258291, 1, 1}, + {324000, 4, 1, 32, 1677722, 1, 1}, + {432000, 3, 1, 32, 1677722, 1, 1} }; static bool @@ -1404,22 +1405,14 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, vco = best_clock.vco; } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT || intel_encoder->type == INTEL_OUTPUT_EDP) { - struct drm_encoder *encoder = &intel_encoder->base; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); + int i; - switch (intel_dp->link_bw) { - case DP_LINK_BW_1_62: - clk_div = bxt_dp_clk_val[0]; - break; - case DP_LINK_BW_2_7: - clk_div = bxt_dp_clk_val[1]; - break; - case DP_LINK_BW_5_4: - clk_div = bxt_dp_clk_val[2]; - break; - default: - clk_div = bxt_dp_clk_val[0]; - DRM_ERROR("Unknown link rate\n"); + clk_div = bxt_dp_clk_val[0]; + for (i = 0; i < ARRAY_SIZE(bxt_dp_clk_val); ++i) { + if (bxt_dp_clk_val[i].clock == clock) { + clk_div = bxt_dp_clk_val[i]; + break; + } } vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 823a1b31177cb..fb5c01e46f4b8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -91,6 +91,8 @@ static const struct dp_link_dpll chv_dpll[] = { { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; +static const int bxt_rates[] = { 162000, 216000, 243000, 270000, + 324000, 432000, 540000 }; static const int skl_rates[] = { 162000, 216000, 270000, 324000, 432000, 540000 }; static const int chv_rates[] = { 162000, 202500, 210000, 216000, @@ -1170,7 +1172,10 @@ intel_dp_sink_rates(struct intel_dp *intel_dp, const int **sink_rates) static int intel_dp_source_rates(struct drm_device *dev, const int **source_rates) { - if (IS_SKYLAKE(dev)) { + if (IS_BROXTON(dev)) { + *source_rates = bxt_rates; + return ARRAY_SIZE(bxt_rates); + } else if (IS_SKYLAKE(dev)) { *source_rates = skl_rates; return ARRAY_SIZE(skl_rates); } else if (IS_CHERRYVIEW(dev)) { -- GitLab From f94c56f4f33dd34551af6bcc1afde5082fdf6e86 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 1 Jun 2015 22:52:20 -0300 Subject: [PATCH 0045/7006] coccinelle: simple_return: Add a blank line Insert a blank line in order to improve the readability of the generated patch and also make it consistent with the other .cocci files. Signed-off-by: Fabio Estevam Acked-by: Julia Lawall Signed-off-by: Michal Marek --- scripts/coccinelle/misc/simple_return.cocci | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/coccinelle/misc/simple_return.cocci b/scripts/coccinelle/misc/simple_return.cocci index 47f7084b6360a..e8b6313b116f5 100644 --- a/scripts/coccinelle/misc/simple_return.cocci +++ b/scripts/coccinelle/misc/simple_return.cocci @@ -1,6 +1,6 @@ /// Simplify a trivial if-return sequence. Possibly combine with a /// preceding function call. -// +/// // Confidence: High // Copyright: (C) 2014 Julia Lawall, INRIA/LIP6. GPLv2. // Copyright: (C) 2014 Gilles Muller, INRIA/LiP6. GPLv2. -- GitLab From 9cc83020616d38339e6c29dc44536e9806abfdb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 2 Jun 2015 15:37:36 +0300 Subject: [PATCH 0046/7006] drm/i915: Set INSTPM_FORCE_ORDERING via LRI on gen8, drop it on gen9+ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit INSTPM is saved in the logical context so we should initialize it using LRIs on gen8. It actually defaults to 1 starting from HSW, but let's keep the write around anyway. Also drop the INSTPM_FORCE_ORDERING setup entirely on gen9+ since it's now a reserved bit. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index edd47baa119c5..06f4b22c6327b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -800,6 +800,8 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisablePartialInstShootdown:bdw */ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -861,6 +863,8 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisablePartialInstShootdown:chv */ /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -1132,7 +1136,7 @@ static int init_render_ring(struct intel_engine_cs *ring) _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB)); } - if (INTEL_INFO(dev)->gen >= 6) + if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING)); if (HAS_L3_DPF(dev)) -- GitLab From 2441f8779e886d74389bf78aad149dc99876a900 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 2 Jun 2015 15:37:37 +0300 Subject: [PATCH 0047/7006] drm/i915: Apply WaDisableAsyncFlipPerfMode via LRIs on gen8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MI_MODE is saved in the logical context so WaDisableAsyncFlipPerfMode must be applied using LRIs on gen8. Signed-off-by: Ville Syrjälä Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ringbuffer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 06f4b22c6327b..b70d25bffb608 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -802,6 +802,9 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisableAsyncFlipPerfMode:bdw */ + WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + /* WaDisablePartialInstShootdown:bdw */ /* WaDisableThreadStallDopClockGating:bdw (pre-production) */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -865,6 +868,9 @@ static int chv_init_workarounds(struct intel_engine_cs *ring) WA_SET_BIT_MASKED(INSTPM, INSTPM_FORCE_ORDERING); + /* WaDisableAsyncFlipPerfMode:chv */ + WA_SET_BIT_MASKED(MI_MODE, ASYNC_FLIP_PERF_DISABLE); + /* WaDisablePartialInstShootdown:chv */ /* WaDisableThreadStallDopClockGating:chv */ WA_SET_BIT_MASKED(GEN8_ROW_CHICKEN, @@ -1109,9 +1115,9 @@ static int init_render_ring(struct intel_engine_cs *ring) * to use MI_WAIT_FOR_EVENT within the CS. It should already be * programmed to '1' on all products. * - * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw,chv + * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv */ - if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 9) + if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE)); /* Required for the hardware to program scanline values for waiting */ -- GitLab From 75fd7ffa7fab91c2c3234bd3e465ba4f366733f4 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 3 Jun 2015 07:37:24 -0400 Subject: [PATCH 0048/7006] tools/power turbostat: update turbostat(8) Remove reference to the original Nehalem Turbo white paper, since it has moved, and these mechanisms have now long since been documented in the Software Developer's Manual. Reported-by: Jeremie Lagraviere Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index 05b8fc38dc8bc..622db685b4f99 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -251,11 +251,6 @@ Although it is not guaranteed by the architecture, turbostat assumes that they count at TSC rate, which is true on all processors tested to date. .SH REFERENCES -"Intel® Turbo Boost Technology -in Intel® Core™ Microarchitecture (Nehalem) Based Processors" -http://download.intel.com/design/processor/applnots/320354.pdf - -"Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide" http://www.intel.com/products/processor/manuals/ -- GitLab From b6283055b408fd9bee5386bd71fdf5f3b5553ae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Jun 2015 15:45:07 +0300 Subject: [PATCH 0049/7006] drm/i915: Cache current cdclk frequency in dev_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather that extracting the current cdclk freuqncy every time someone wants to know it, cache the current value and use that. VLV/CHV already stored a cached value there so just expand that to cover all platforms. v2: Rebased to the latest v3: Rebased to the latest v4: Rebased to the latest v5: Removed spurious call to 'intel_update_cdclk(dev)' based on Damien Lespiau's comment Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 16e159db5025c..9cf155382a4fb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5747,7 +5747,7 @@ static int valleyview_get_vco(struct drm_i915_private *dev_priv) return vco_freq[hpll_freq] * 1000; } -static void vlv_update_cdclk(struct drm_device *dev) +static void intel_update_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5760,7 +5760,14 @@ static void vlv_update_cdclk(struct drm_device *dev) * BSpec erroneously claims we should aim for 4MHz, but * in fact 1MHz is the correct frequency. */ - I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); + if (IS_VALLEYVIEW(dev)) { + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); + } } /* Adjust CDclk dividers to allow high res or save power if possible */ @@ -5826,7 +5833,7 @@ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) mutex_unlock(&dev_priv->sb_lock); - vlv_update_cdclk(dev); + intel_update_cdclk(dev); } static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) @@ -5867,7 +5874,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk) } mutex_unlock(&dev_priv->rps.hw_lock); - vlv_update_cdclk(dev); + intel_update_cdclk(dev); } static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv, @@ -9479,6 +9486,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv) } intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); + intel_update_cdclk(dev_priv->dev); } /* @@ -13273,6 +13281,8 @@ static void intel_shared_dpll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + intel_update_cdclk(dev); + if (HAS_DDI(dev)) intel_ddi_pll_init(dev); else if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) @@ -14848,13 +14858,9 @@ static void i915_disable_vga(struct drm_device *dev) void intel_modeset_init_hw(struct drm_device *dev) { + intel_update_cdclk(dev); intel_prepare_ddi(dev); - - if (IS_VALLEYVIEW(dev)) - vlv_update_cdclk(dev); - intel_init_clock_gating(dev); - intel_enable_gt_powersave(dev); } -- GitLab From 05024da3c2482e26e94fb3a8324a355c066d2faf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Jun 2015 15:45:08 +0300 Subject: [PATCH 0050/7006] drm/i915: Use cached cdclk value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rather than reading out the current cdclk value use the cached value we have tucked away in dev_priv. v2: Rebased to the latest v3: Rebased to the latest v4: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 +-- drivers/gpu/drm/i915/intel_dp.c | 5 +++-- drivers/gpu/drm/i915/intel_pm.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9cf155382a4fb..d1dd8abaf1f14 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6610,8 +6610,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - int clock_limit = - dev_priv->display.get_display_clock_speed(dev); + int clock_limit = dev_priv->cdclk_freq; /* * Enable pixel doubling when the dot clock diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fb5c01e46f4b8..f73da99e66b8b 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -710,7 +710,8 @@ static uint32_t ilk_get_aux_clock_divider(struct intel_dp *intel_dp, int index) return 0; if (intel_dig_port->port == PORT_A) { - return DIV_ROUND_UP(dev_priv->display.get_display_clock_speed(dev), 2000); + return DIV_ROUND_UP(dev_priv->cdclk_freq, 2000); + } else { return DIV_ROUND_UP(intel_pch_rawclk(dev), 2); } @@ -725,7 +726,7 @@ static uint32_t hsw_get_aux_clock_divider(struct intel_dp *intel_dp, int index) if (intel_dig_port->port == PORT_A) { if (index) return 0; - return DIV_ROUND_CLOSEST(dev_priv->display.get_display_clock_speed(dev), 2000); + return DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 2000); } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) { /* Workaround for non-ULT HSW */ switch (index) { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index eadc15cddbeb4..5db429e92be5f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1815,7 +1815,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc) linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8, mode->crtc_clock); ips_linetime = DIV_ROUND_CLOSEST(mode->crtc_htotal * 1000 * 8, - dev_priv->display.get_display_clock_speed(dev_priv->dev)); + dev_priv->cdclk_freq); return PIPE_WM_LINETIME_IPS_LINETIME(ips_linetime) | PIPE_WM_LINETIME_TIME(linetime); -- GitLab From 44913155f036ae966f09a7bc0d299c31876b4383 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Jun 2015 15:45:10 +0300 Subject: [PATCH 0051/7006] drm/i915: Store max cdclk value in dev_priv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep the cdclk maximum supported frequency around in dev_priv so that we can verify certain things against it before actually changing the cdclk frequency. For now only VLV/CHV have support changing cdclk frequency, so other plarforms get to assume cdclk is fixed. v2: Rebased to the latest v3: Rebased to the latest v4: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 20 +++++++++++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 60aa9626f91fa..db9e268629b24 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1743,7 +1743,7 @@ struct drm_i915_private { unsigned int fsb_freq, mem_freq, is_ddr3; unsigned int skl_boot_cdclk; - unsigned int cdclk_freq; + unsigned int cdclk_freq, max_cdclk_freq; unsigned int hpll_freq; /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d1dd8abaf1f14..445385dd062a0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5747,6 +5747,21 @@ static int valleyview_get_vco(struct drm_i915_private *dev_priv) return vco_freq[hpll_freq] * 1000; } +static void intel_update_max_cdclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_VALLEYVIEW(dev)) { + dev_priv->max_cdclk_freq = 400000; + } else { + /* otherwise assume cdclk is fixed */ + dev_priv->max_cdclk_freq = dev_priv->cdclk_freq; + } + + DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n", + dev_priv->max_cdclk_freq); +} + static void intel_update_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5768,6 +5783,9 @@ static void intel_update_cdclk(struct drm_device *dev) */ I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); } + + if (dev_priv->max_cdclk_freq == 0) + intel_update_max_cdclk(dev); } /* Adjust CDclk dividers to allow high res or save power if possible */ @@ -6610,7 +6628,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { - int clock_limit = dev_priv->cdclk_freq; + int clock_limit = dev_priv->max_cdclk_freq; /* * Enable pixel doubling when the dot clock -- GitLab From 8cfb340774744438dea08a32072bea4a162dd132 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Jun 2015 15:45:11 +0300 Subject: [PATCH 0052/7006] drm/i915: Don't enable IPS when pixel rate exceeds 95% MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bspec says we shouldn't enable IPS on BDW when the pipe pixel rate exceeds 95% of the core display clock. Apparently this can cause underruns. There's no similar restriction listed for HSW, so leave that one alone for now. v2: Add pipe_config_supports_ips() (Chris) v3: Compare against the max cdclk insted of the current cdclk v4: Rebased to the latest v5: Rebased to the latest v6: Fix for patch style problems Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=83497 Tested-by: Timo Aaltonen Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 30 ++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_pm.c | 17 ++++++++-------- 3 files changed, 37 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 445385dd062a0..c3f01aa9b5102 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6610,12 +6610,38 @@ retry: return ret; } +static bool pipe_config_supports_ips(struct drm_i915_private *dev_priv, + struct intel_crtc_state *pipe_config) +{ + if (pipe_config->pipe_bpp > 24) + return false; + + /* HSW can handle pixel rate up to cdclk? */ + if (IS_HASWELL(dev_priv->dev)) + return true; + + /* + * FIXME if we compare against max we should then + * increase the cdclk frequency when the current + * value is too low. The other option is to compare + * against the cdclk frequency we're going have post + * modeset (ie. one we computed using other constraints). + * Need to measure whether using a lower cdclk w/o IPS + * is better or worse than a higher cdclk w/ IPS. + */ + return ilk_pipe_pixel_rate(pipe_config) <= + dev_priv->max_cdclk_freq * 95 / 100; +} + static void hsw_compute_ips_config(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + pipe_config->ips_enabled = i915.enable_ips && - hsw_crtc_supports_ips(crtc) && - pipe_config->pipe_bpp <= 24; + hsw_crtc_supports_ips(crtc) && + pipe_config_supports_ips(dev_priv, pipe_config); } static int intel_crtc_compute_config(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2afb31a462757..5cb30044acf48 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1375,7 +1375,7 @@ void ilk_wm_get_hw_state(struct drm_device *dev); void skl_wm_get_hw_state(struct drm_device *dev); void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, struct skl_ddb_allocation *ddb /* out */); - +uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config); /* intel_sdvo.c */ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5db429e92be5f..d091fec1e1018 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1434,23 +1434,22 @@ static void i845_update_wm(struct drm_crtc *unused_crtc) I915_WRITE(FW_BLC, fwater_lo); } -static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev, - struct drm_crtc *crtc) +uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pixel_rate; - pixel_rate = intel_crtc->config->base.adjusted_mode.crtc_clock; + pixel_rate = pipe_config->base.adjusted_mode.crtc_clock; /* We only use IF-ID interlacing. If we ever use PF-ID we'll need to * adjust the pixel_rate here. */ - if (intel_crtc->config->pch_pfit.enabled) { + if (pipe_config->pch_pfit.enabled) { uint64_t pipe_w, pipe_h, pfit_w, pfit_h; - uint32_t pfit_size = intel_crtc->config->pch_pfit.size; + uint32_t pfit_size = pipe_config->pch_pfit.size; + + pipe_w = pipe_config->pipe_src_w; + pipe_h = pipe_config->pipe_src_h; - pipe_w = intel_crtc->config->pipe_src_w; - pipe_h = intel_crtc->config->pipe_src_h; pfit_w = (pfit_size >> 16) & 0xFFFF; pfit_h = pfit_size & 0xFFFF; if (pipe_w < pfit_w) @@ -2066,7 +2065,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, p->active = true; p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal; - p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc); + p->pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); if (crtc->primary->state->fb) p->pri.bytes_per_pixel = -- GitLab From ebb72aad41e231fe5c586785dbbf5910867e7978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Jun 2015 15:45:12 +0300 Subject: [PATCH 0053/7006] drm/i915: Add IS_BDW_ULX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We need to tell BDW ULT and ULX apart. v2: Rebased to the latest v3: Rebased to the latest v4: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index db9e268629b24..46722f85ef761 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2399,6 +2399,9 @@ struct drm_i915_cmd_table { ((INTEL_DEVID(dev) & 0xf) == 0x6 || \ (INTEL_DEVID(dev) & 0xf) == 0xb || \ (INTEL_DEVID(dev) & 0xf) == 0xe)) +/* ULX machines are also considered ULT. */ +#define IS_BDW_ULX(dev) (IS_BROADWELL(dev) && \ + (INTEL_DEVID(dev) & 0xf) == 0xe) #define IS_BDW_GT3(dev) (IS_BROADWELL(dev) && \ (INTEL_DEVID(dev) & 0x00F0) == 0x0020) #define IS_HSW_ULT(dev) (IS_HASWELL(dev) && \ -- GitLab From b432e5cfd5e92127ad2dd83bfc3083f1dbce43fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 3 Jun 2015 15:45:13 +0300 Subject: [PATCH 0054/7006] drm/i915: BDW clock change support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for changing cdclk frequency during runtime on BDW. Also with IPS enabled the actual pixel rate mustn't exceed 95% of cdclk, so take that into account when computing the max pixel rate. v2: Grab rps.hw_lock around sandybridge_pcode_write() v3: Rebase due to power well vs. .global_resources() reordering v4: Rebased to the latest v5: Rebased to the latest v6: Patch order shuffle so that Broadwell CD clock change is applied before the patch for Haswell CD clock change v7: Fix for patch style problems Signed-off-by: Ville Syrjälä Signed-off-by: Mika Kahola Reviewed-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_reg.h | 2 + drivers/gpu/drm/i915/intel_display.c | 216 +++++++++++++++++++++++++-- 2 files changed, 208 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 00cec1f70b649..89fd7c8a15257 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6705,6 +6705,7 @@ enum skl_disp_power_wells { #define GEN6_PCODE_READ_RC6VIDS 0x5 #define GEN6_ENCODE_RC6_VID(mv) (((mv) - 245) / 5) #define GEN6_DECODE_RC6_VID(vids) (((vids) * 5) + 245) +#define BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ 0x18 #define GEN9_PCODE_READ_MEM_LATENCY 0x6 #define GEN9_MEM_LATENCY_LEVEL_MASK 0xFF #define GEN9_MEM_LATENCY_LEVEL_1_5_SHIFT 8 @@ -7167,6 +7168,7 @@ enum skl_disp_power_wells { #define LCPLL_CLK_FREQ_337_5_BDW (2<<26) #define LCPLL_CLK_FREQ_675_BDW (3<<26) #define LCPLL_CD_CLOCK_DISABLE (1<<25) +#define LCPLL_ROOT_CD_CLOCK_DISABLE (1<<24) #define LCPLL_CD2X_CLOCK_DISABLE (1<<23) #define LCPLL_POWER_DOWN_ALLOW (1<<22) #define LCPLL_CD_SOURCE_FCLK (1<<21) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c3f01aa9b5102..b1e206933b953 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5751,7 +5751,22 @@ static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_VALLEYVIEW(dev)) { + if (IS_BROADWELL(dev)) { + /* + * FIXME with extra cooling we can allow + * 540 MHz for ULX and 675 Mhz for ULT. + * How can we know if extra cooling is + * available? PCI ID, VTB, something else? + */ + if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULX(dev)) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULT(dev)) + dev_priv->max_cdclk_freq = 540000; + else + dev_priv->max_cdclk_freq = 675000; + } else if (IS_VALLEYVIEW(dev)) { dev_priv->max_cdclk_freq = 400000; } else { /* otherwise assume cdclk is fixed */ @@ -6621,13 +6636,11 @@ static bool pipe_config_supports_ips(struct drm_i915_private *dev_priv, return true; /* - * FIXME if we compare against max we should then - * increase the cdclk frequency when the current - * value is too low. The other option is to compare - * against the cdclk frequency we're going have post - * modeset (ie. one we computed using other constraints). - * Need to measure whether using a lower cdclk w/o IPS - * is better or worse than a higher cdclk w/ IPS. + * We compare against max which means we must take + * the increased cdclk requirement into account when + * calculating the new cdclk. + * + * Should measure whether using a lower cdclk w/o IPS */ return ilk_pipe_pixel_rate(pipe_config) <= dev_priv->max_cdclk_freq * 95 / 100; @@ -9608,6 +9621,182 @@ static void broxton_modeset_global_resources(struct drm_atomic_state *old_state) broxton_set_cdclk(dev, req_cdclk); } +/* compute the max rate for new configuration */ +static int ilk_max_pixel_rate(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + int max_pixel_rate = 0; + int pixel_rate; + + for_each_crtc(dev, crtc) { + if (!crtc->state->enable) + continue; + + intel_crtc = to_intel_crtc(crtc); + pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); + + /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ + if (IS_BROADWELL(dev) && intel_crtc->config->ips_enabled) + pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95); + + max_pixel_rate = max(max_pixel_rate, pixel_rate); + } + + return max_pixel_rate; +} + +static void broadwell_set_cdclk(struct drm_device *dev, int cdclk) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val, data; + int ret; + + if (WARN((I915_READ(LCPLL_CTL) & + (LCPLL_PLL_DISABLE | LCPLL_PLL_LOCK | + LCPLL_CD_CLOCK_DISABLE | LCPLL_ROOT_CD_CLOCK_DISABLE | + LCPLL_CD2X_CLOCK_DISABLE | LCPLL_POWER_DOWN_ALLOW | + LCPLL_CD_SOURCE_FCLK)) != LCPLL_PLL_LOCK, + "trying to change cdclk frequency with cdclk not enabled\n")) + return; + + mutex_lock(&dev_priv->rps.hw_lock); + ret = sandybridge_pcode_write(dev_priv, + BDW_PCODE_DISPLAY_FREQ_CHANGE_REQ, 0x0); + mutex_unlock(&dev_priv->rps.hw_lock); + if (ret) { + DRM_ERROR("failed to inform pcode about cdclk change\n"); + return; + } + + val = I915_READ(LCPLL_CTL); + val |= LCPLL_CD_SOURCE_FCLK; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for_atomic_us(I915_READ(LCPLL_CTL) & + LCPLL_CD_SOURCE_FCLK_DONE, 1)) + DRM_ERROR("Switching to FCLK failed\n"); + + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_CLK_FREQ_MASK; + + switch (cdclk) { + case 450000: + val |= LCPLL_CLK_FREQ_450; + data = 0; + break; + case 540000: + val |= LCPLL_CLK_FREQ_54O_BDW; + data = 1; + break; + case 337500: + val |= LCPLL_CLK_FREQ_337_5_BDW; + data = 2; + break; + case 675000: + val |= LCPLL_CLK_FREQ_675_BDW; + data = 3; + break; + default: + WARN(1, "invalid cdclk frequency\n"); + return; + } + + I915_WRITE(LCPLL_CTL, val); + + val = I915_READ(LCPLL_CTL); + val &= ~LCPLL_CD_SOURCE_FCLK; + I915_WRITE(LCPLL_CTL, val); + + if (wait_for_atomic_us((I915_READ(LCPLL_CTL) & + LCPLL_CD_SOURCE_FCLK_DONE) == 0, 1)) + DRM_ERROR("Switching back to LCPLL failed\n"); + + mutex_lock(&dev_priv->rps.hw_lock); + sandybridge_pcode_write(dev_priv, HSW_PCODE_DE_WRITE_FREQ_REQ, data); + mutex_unlock(&dev_priv->rps.hw_lock); + + intel_update_cdclk(dev); + + WARN(cdclk != dev_priv->cdclk_freq, + "cdclk requested %d kHz but got %d kHz\n", + cdclk, dev_priv->cdclk_freq); +} + +static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, + int max_pixel_rate) +{ + int cdclk; + + /* + * FIXME should also account for plane ratio + * once 64bpp pixel formats are supported. + */ + if (max_pixel_rate > 540000) + cdclk = 675000; + else if (max_pixel_rate > 450000) + cdclk = 540000; + else if (max_pixel_rate > 337500) + cdclk = 450000; + else + cdclk = 337500; + + /* + * FIXME move the cdclk caclulation to + * compute_config() so we can fail gracegully. + */ + if (cdclk > dev_priv->max_cdclk_freq) { + DRM_ERROR("requested cdclk (%d kHz) exceeds max (%d kHz)\n", + cdclk, dev_priv->max_cdclk_freq); + cdclk = dev_priv->max_cdclk_freq; + } + + return cdclk; +} + +static int broadwell_modeset_global_pipes(struct drm_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int max_pixclk = ilk_max_pixel_rate(dev_priv); + int cdclk, i; + + cdclk = broadwell_calc_cdclk(dev_priv, max_pixclk); + + if (cdclk == dev_priv->cdclk_freq) + return 0; + + /* add all active pipes to the state */ + for_each_crtc(state->dev, crtc) { + if (!crtc->state->enable) + continue; + + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + } + + /* disable/enable all currently active pipes while we change cdclk */ + for_each_crtc_in_state(state, crtc, crtc_state, i) + if (crtc_state->enable) + crtc_state->mode_changed = true; + + return 0; +} + +static void broadwell_modeset_global_resources(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixel_rate = ilk_max_pixel_rate(dev_priv); + int req_cdclk = broadwell_calc_cdclk(dev_priv, max_pixel_rate); + + if (req_cdclk != dev_priv->cdclk_freq) + broadwell_set_cdclk(dev, req_cdclk); +} + static int haswell_crtc_compute_clock(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { @@ -12788,8 +12977,12 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) { - ret = valleyview_modeset_global_pipes(state); + if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev) || IS_BROADWELL(dev)) { + if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) + ret = valleyview_modeset_global_pipes(state); + else + ret = broadwell_modeset_global_pipes(state); + if (ret) return ret; } @@ -14677,6 +14870,9 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; + if (IS_BROADWELL(dev)) + dev_priv->display.modeset_global_resources = + broadwell_modeset_global_resources; } else if (IS_VALLEYVIEW(dev)) { dev_priv->display.modeset_global_resources = valleyview_modeset_global_resources; -- GitLab From 70d0c5742013b888a9254f54ee527e9941171297 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:29 +0100 Subject: [PATCH 0055/7006] drm/i915: Make broxton_set_cdclk() static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b1e206933b953..7e8b583527e9b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5346,7 +5346,7 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_set_init_power(dev_priv, false); } -void broxton_set_cdclk(struct drm_device *dev, int frequency) +static void broxton_set_cdclk(struct drm_device *dev, int frequency) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t divider; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5cb30044acf48..5c9d6217f371b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1113,7 +1113,6 @@ void hsw_enable_pc8(struct drm_i915_private *dev_priv); void hsw_disable_pc8(struct drm_i915_private *dev_priv); void broxton_init_cdclk(struct drm_device *dev); void broxton_uninit_cdclk(struct drm_device *dev); -void broxton_set_cdclk(struct drm_device *dev, int frequency); void broxton_ddi_phy_init(struct drm_device *dev); void broxton_ddi_phy_uninit(struct drm_device *dev); void bxt_enable_dc9(struct drm_i915_private *dev_priv); -- GitLab From a9419e846bd8c8e00c1d28282de936523229eff7 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:30 +0100 Subject: [PATCH 0056/7006] drm/i915/skl: Derive the max CDCLK from DFSM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_reg.h | 7 +++++++ drivers/gpu/drm/i915/intel_display.c | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 89fd7c8a15257..760dbebc1aefc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5761,6 +5761,13 @@ enum skl_disp_power_wells { #define HSW_NDE_RSTWRN_OPT 0x46408 #define RESET_PCH_HANDSHAKE_ENABLE (1<<4) +#define SKL_DFSM 0x51000 +#define SKL_DFSM_CDCLK_LIMIT_MASK (3 << 23) +#define SKL_DFSM_CDCLK_LIMIT_675 (0 << 23) +#define SKL_DFSM_CDCLK_LIMIT_540 (1 << 23) +#define SKL_DFSM_CDCLK_LIMIT_450 (2 << 23) +#define SKL_DFSM_CDCLK_LIMIT_337_5 (3 << 23) + #define FF_SLICE_CS_CHICKEN2 0x20e4 #define GEN9_TSG_BARRIER_ACK_DISABLE (1<<8) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e8b583527e9b..9280e76505fce 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5751,7 +5751,18 @@ static void intel_update_max_cdclk(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (IS_BROADWELL(dev)) { + if (IS_SKYLAKE(dev)) { + u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; + + if (limit == SKL_DFSM_CDCLK_LIMIT_675) + dev_priv->max_cdclk_freq = 675000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_540) + dev_priv->max_cdclk_freq = 540000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_450) + dev_priv->max_cdclk_freq = 450000; + else + dev_priv->max_cdclk_freq = 337500; + } else if (IS_BROADWELL(dev)) { /* * FIXME with extra cooling we can allow * 540 MHz for ULX and 675 Mhz for ULT. -- GitLab From 414355a7c3f029b762518d73a6ea7e4d07d48e34 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:31 +0100 Subject: [PATCH 0057/7006] drm/i915/skl: Don't warn if reading back DPLL0 is disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We can operate with DPLL0 off with CDCLK backed by the 24Mhz reference clock, and that's a supported configuration. Don't warn when notice DPLL0 is off then. We still have a separate warn at boot if cdclk is disabled (because we don't currently try to handle the case (that shouldn't happen on SKL as far as I know) where we boot with display not initialized. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9280e76505fce..0a3456988c127 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6737,10 +6737,8 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) uint32_t cdctl = I915_READ(CDCLK_CTL); uint32_t linkrate; - if (!(lcpll1 & LCPLL_PLL_ENABLE)) { - WARN(1, "LCPLL1 not enabled\n"); + if (!(lcpll1 & LCPLL_PLL_ENABLE)) return 24000; /* 24MHz is the cd freq with NSSC ref */ - } if ((cdctl & CDCLK_FREQ_SEL_MASK) == CDCLK_FREQ_540) return 540000; -- GitLab From d9062ae59de1025bdd15988a4030d6e667c389d0 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:32 +0100 Subject: [PATCH 0058/7006] drm/i915: Don't display the boot CDCLK twice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit intel_update_cdclk() will already display the boot CDCLK for DDI platforms, no need to repeat there. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 3eaf5c0505737..fff494412fe6b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2517,7 +2517,6 @@ void intel_ddi_pll_init(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; uint32_t val = I915_READ(LCPLL_CTL); - int cdclk_freq; if (IS_SKYLAKE(dev)) skl_shared_dplls_init(dev_priv); @@ -2526,10 +2525,10 @@ void intel_ddi_pll_init(struct drm_device *dev) else hsw_shared_dplls_init(dev_priv); - cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - DRM_DEBUG_KMS("CDCLK running at %dKHz\n", cdclk_freq); - if (IS_SKYLAKE(dev)) { + int cdclk_freq; + + cdclk_freq = dev_priv->display.get_display_clock_speed(dev); dev_priv->skl_boot_cdclk = cdclk_freq; if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) DRM_ERROR("LCPLL1 is disabled\n"); -- GitLab From 560a7ae4b6f679927876b0dfcc1fcdfabdd20684 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:33 +0100 Subject: [PATCH 0059/7006] drm/i915/skl: Update the cached CDCLK at the end of set_cdclk() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ville's and Mika's cdclk series was in flight at the same time as the SKL S3 patches so we were missing that update. intel_update_max_cdclk() and intel_update_cdclk() had to be moved up a bit to avoid forward declarations. Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 137 ++++++++++++++------------- 1 file changed, 70 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0a3456988c127..17070deaf798f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5346,6 +5346,73 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_set_init_power(dev_priv, false); } +static void intel_update_max_cdclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (IS_SKYLAKE(dev)) { + u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; + + if (limit == SKL_DFSM_CDCLK_LIMIT_675) + dev_priv->max_cdclk_freq = 675000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_540) + dev_priv->max_cdclk_freq = 540000; + else if (limit == SKL_DFSM_CDCLK_LIMIT_450) + dev_priv->max_cdclk_freq = 450000; + else + dev_priv->max_cdclk_freq = 337500; + } else if (IS_BROADWELL(dev)) { + /* + * FIXME with extra cooling we can allow + * 540 MHz for ULX and 675 Mhz for ULT. + * How can we know if extra cooling is + * available? PCI ID, VTB, something else? + */ + if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULX(dev)) + dev_priv->max_cdclk_freq = 450000; + else if (IS_BDW_ULT(dev)) + dev_priv->max_cdclk_freq = 540000; + else + dev_priv->max_cdclk_freq = 675000; + } else if (IS_VALLEYVIEW(dev)) { + dev_priv->max_cdclk_freq = 400000; + } else { + /* otherwise assume cdclk is fixed */ + dev_priv->max_cdclk_freq = dev_priv->cdclk_freq; + } + + DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n", + dev_priv->max_cdclk_freq); +} + +static void intel_update_cdclk(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); + DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", + dev_priv->cdclk_freq); + + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + if (IS_VALLEYVIEW(dev)) { + /* + * Program the gmbus_freq based on the cdclk frequency. + * BSpec erroneously claims we should aim for 4MHz, but + * in fact 1MHz is the correct frequency. + */ + I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); + } + + if (dev_priv->max_cdclk_freq == 0) + intel_update_max_cdclk(dev); +} + static void broxton_set_cdclk(struct drm_device *dev, int frequency) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -5637,6 +5704,7 @@ static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv) static void skl_set_cdclk(struct drm_i915_private *dev_priv, unsigned int freq) { + struct drm_device *dev = dev_priv->dev; u32 freq_select, pcu_ack; DRM_DEBUG_DRIVER("Changing CDCLK to %dKHz\n", freq); @@ -5677,6 +5745,8 @@ static void skl_set_cdclk(struct drm_i915_private *dev_priv, unsigned int freq) mutex_lock(&dev_priv->rps.hw_lock); sandybridge_pcode_write(dev_priv, SKL_PCODE_CDCLK_CONTROL, pcu_ack); mutex_unlock(&dev_priv->rps.hw_lock); + + intel_update_cdclk(dev); } void skl_uninit_cdclk(struct drm_i915_private *dev_priv) @@ -5747,73 +5817,6 @@ static int valleyview_get_vco(struct drm_i915_private *dev_priv) return vco_freq[hpll_freq] * 1000; } -static void intel_update_max_cdclk(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (IS_SKYLAKE(dev)) { - u32 limit = I915_READ(SKL_DFSM) & SKL_DFSM_CDCLK_LIMIT_MASK; - - if (limit == SKL_DFSM_CDCLK_LIMIT_675) - dev_priv->max_cdclk_freq = 675000; - else if (limit == SKL_DFSM_CDCLK_LIMIT_540) - dev_priv->max_cdclk_freq = 540000; - else if (limit == SKL_DFSM_CDCLK_LIMIT_450) - dev_priv->max_cdclk_freq = 450000; - else - dev_priv->max_cdclk_freq = 337500; - } else if (IS_BROADWELL(dev)) { - /* - * FIXME with extra cooling we can allow - * 540 MHz for ULX and 675 Mhz for ULT. - * How can we know if extra cooling is - * available? PCI ID, VTB, something else? - */ - if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) - dev_priv->max_cdclk_freq = 450000; - else if (IS_BDW_ULX(dev)) - dev_priv->max_cdclk_freq = 450000; - else if (IS_BDW_ULT(dev)) - dev_priv->max_cdclk_freq = 540000; - else - dev_priv->max_cdclk_freq = 675000; - } else if (IS_VALLEYVIEW(dev)) { - dev_priv->max_cdclk_freq = 400000; - } else { - /* otherwise assume cdclk is fixed */ - dev_priv->max_cdclk_freq = dev_priv->cdclk_freq; - } - - DRM_DEBUG_DRIVER("Max CD clock rate: %d kHz\n", - dev_priv->max_cdclk_freq); -} - -static void intel_update_cdclk(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - dev_priv->cdclk_freq = dev_priv->display.get_display_clock_speed(dev); - DRM_DEBUG_DRIVER("Current CD clock rate: %d kHz\n", - dev_priv->cdclk_freq); - - /* - * Program the gmbus_freq based on the cdclk frequency. - * BSpec erroneously claims we should aim for 4MHz, but - * in fact 1MHz is the correct frequency. - */ - if (IS_VALLEYVIEW(dev)) { - /* - * Program the gmbus_freq based on the cdclk frequency. - * BSpec erroneously claims we should aim for 4MHz, but - * in fact 1MHz is the correct frequency. - */ - I915_WRITE(GMBUSFREQ_VLV, DIV_ROUND_UP(dev_priv->cdclk_freq, 1000)); - } - - if (dev_priv->max_cdclk_freq == 0) - intel_update_max_cdclk(dev); -} - /* Adjust CDclk dividers to allow high res or save power if possible */ static void valleyview_set_cdclk(struct drm_device *dev, int cdclk) { -- GitLab From a47871bd8ac2954b486272faa2a92831a69b1b8e Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:21:34 +0100 Subject: [PATCH 0060/7006] drm/i915/bxt: Use intel_update_cdclk() to update dev_priv->cdclk_freq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Damien Lespiau Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 17070deaf798f..58846b58b676f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5529,7 +5529,7 @@ static void broxton_set_cdclk(struct drm_device *dev, int frequency) return; } - dev_priv->cdclk_freq = frequency; + intel_update_cdclk(dev); } void broxton_init_cdclk(struct drm_device *dev) -- GitLab From 6455c870e97b7e8a6cf7aacba8ea19087b7db973 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:23:57 +0100 Subject: [PATCH 0061/7006] drm/i915: Make pc8_status report status for all runtime PM platforms Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 3e17210c3277e..8d25ce4a40db1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2476,13 +2476,13 @@ static int i915_energy_uJ(struct seq_file *m, void *data) return 0; } -static int i915_pc8_status(struct seq_file *m, void *unused) +static int i915_runtime_pm_status(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) { + if (!HAS_RUNTIME_PM(dev)) { seq_puts(m, "not supported\n"); return 0; } @@ -5039,7 +5039,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_edp_psr_status", i915_edp_psr_status, 0}, {"i915_sink_crc_eDP1", i915_sink_crc, 0}, {"i915_energy_uJ", i915_energy_uJ, 0}, - {"i915_pc8_status", i915_pc8_status, 0}, + {"i915_runtime_pm_status", i915_runtime_pm_status, 0}, {"i915_power_domain_info", i915_power_domain_info, 0}, {"i915_display_info", i915_display_info, 0}, {"i915_semaphore_status", i915_semaphore_status, 0}, -- GitLab From a6aaec8be22652a808d6e316d4a92e58cb75e986 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 18:23:58 +0100 Subject: [PATCH 0062/7006] drm/i915: Add runtime PM's usage_count in i915_runtime_pm_status Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 8d25ce4a40db1..47d9854434c59 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2490,6 +2490,8 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy)); seq_printf(m, "IRQs disabled: %s\n", yesno(!intel_irqs_enabled(dev_priv))); + seq_printf(m, "Usage count: %d\n", + atomic_read(&dev->dev->power.usage_count)); return 0; } -- GitLab From fe4c63c8cbd22251f8ce8bcb7853e46385f7af82 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 4 Jun 2015 18:01:35 +0300 Subject: [PATCH 0063/7006] drm/i915/bxt: fix DDI PHY vswing scale value setting According to bspec the DDI PHY vswing scale value is "don't care" in case the scale enable bit [27] is clear. But this doesn't seem to be correct. The scale value seems to also matter if the scale mode bit [26] is set. So both bit 26 and 27 depend on the value. Setting the scale value to 0 while either bit is set results in a failed modeset on HDMI (sink reports no signal). After reset the scale value is 0x98, but according to the spec we have to program it to 0x9a. So for consistency program it always to 0x9a regardless of the scale enable bit. Signed-off-by: Imre Deak Tested-by: Matt Roper Acked-by: Damien Lespiau Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 36 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index fff494412fe6b..31b29e8781ace 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -181,15 +181,15 @@ struct bxt_ddi_buf_trans { */ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { /* Idx NT mV diff db */ - { 52, 0, 0, 128, true }, /* 0: 400 0 */ - { 78, 0, 0, 85, false }, /* 1: 400 3.5 */ - { 104, 0, 0, 64, false }, /* 2: 400 6 */ - { 154, 0, 0, 43, false }, /* 3: 400 9.5 */ - { 77, 0, 0, 128, false }, /* 4: 600 0 */ - { 116, 0, 0, 85, false }, /* 5: 600 3.5 */ - { 154, 0, 0, 64, false }, /* 6: 600 6 */ - { 102, 0, 0, 128, false }, /* 7: 800 0 */ - { 154, 0, 0, 85, false }, /* 8: 800 3.5 */ + { 52, 0x9A, 0, 128, true }, /* 0: 400 0 */ + { 78, 0x9A, 0, 85, false }, /* 1: 400 3.5 */ + { 104, 0x9A, 0, 64, false }, /* 2: 400 6 */ + { 154, 0x9A, 0, 43, false }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, false }, /* 4: 600 0 */ + { 116, 0x9A, 0, 85, false }, /* 5: 600 3.5 */ + { 154, 0x9A, 0, 64, false }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ + { 154, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ }; @@ -198,15 +198,15 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { */ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { /* Idx NT mV diff db */ - { 52, 0, 0, 128, false }, /* 0: 400 0 */ - { 52, 0, 0, 85, false }, /* 1: 400 3.5 */ - { 52, 0, 0, 64, false }, /* 2: 400 6 */ - { 42, 0, 0, 43, false }, /* 3: 400 9.5 */ - { 77, 0, 0, 128, false }, /* 4: 600 0 */ - { 77, 0, 0, 85, false }, /* 5: 600 3.5 */ - { 77, 0, 0, 64, false }, /* 6: 600 6 */ - { 102, 0, 0, 128, false }, /* 7: 800 0 */ - { 102, 0, 0, 85, false }, /* 8: 800 3.5 */ + { 52, 0x9A, 0, 128, false }, /* 0: 400 0 */ + { 52, 0x9A, 0, 85, false }, /* 1: 400 3.5 */ + { 52, 0x9A, 0, 64, false }, /* 2: 400 6 */ + { 42, 0x9A, 0, 43, false }, /* 3: 400 9.5 */ + { 77, 0x9A, 0, 128, false }, /* 4: 600 0 */ + { 77, 0x9A, 0, 85, false }, /* 5: 600 3.5 */ + { 77, 0x9A, 0, 64, false }, /* 6: 600 6 */ + { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ + { 102, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ { 154, 0x9A, 1, 128, true }, /* 9: 1200 0 */ }; -- GitLab From 41da1f5d492b4bfef04419feb12ee9b0ea0517cb Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:45 +0200 Subject: [PATCH 0064/7006] drm/i915: get rid of put_shared_dpll Now that the pll updates are staged the put_shared_dpll function consists only of checks that are done in check_shared_dpll_state after a modeset too. The changes to pll->config are overwritten by intel_shared_dpll_commit, so this entire function is a noop. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 34 +++------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 3 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58846b58b676f..9d271172dddd9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4199,27 +4199,6 @@ static void lpt_pch_enable(struct drm_crtc *crtc) lpt_enable_pch_transcoder(dev_priv, cpu_transcoder); } -void intel_put_shared_dpll(struct intel_crtc *crtc) -{ - struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc); - - if (pll == NULL) - return; - - if (!(pll->config.crtc_mask & (1 << crtc->pipe))) { - WARN(1, "bad %s crtc mask\n", pll->name); - return; - } - - pll->config.crtc_mask &= ~(1 << crtc->pipe); - if (pll->config.crtc_mask == 0) { - WARN_ON(pll->on); - WARN_ON(pll->active); - } - - crtc->config->shared_dpll = DPLL_ID_PRIVATE; -} - struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { @@ -5206,13 +5185,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_disable_shared_dpll(intel_crtc); } -static void ironlake_crtc_off(struct drm_crtc *crtc) -{ - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_put_shared_dpll(intel_crtc); -} - - static void i9xx_pfit_enable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -14770,7 +14742,7 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = skylake_update_primary_plane; } else if (HAS_DDI(dev)) { @@ -14781,7 +14753,7 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (HAS_PCH_SPLIT(dev)) { @@ -14792,7 +14764,7 @@ static void intel_init_display(struct drm_device *dev) ironlake_crtc_compute_clock; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; - dev_priv->display.off = ironlake_crtc_off; + dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (IS_VALLEYVIEW(dev)) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5c9d6217f371b..4635c83e6dc2a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1083,7 +1083,6 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv, #define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false) struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, struct intel_crtc_state *state); -void intel_put_shared_dpll(struct intel_crtc *crtc); void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe, const struct dpll *dpll); -- GitLab From 69024de8ba9ee28bbb2c0ba2f813d37a7d0be80a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:46 +0200 Subject: [PATCH 0065/7006] drm/i915: get rid of intel_crtc_disable and related code, v3 Now that the dpll updates are (mostly) atomic, the .off() code is a noop, and intel_crtc_disable does mostly the same as intel_modeset_update_state. Move all logic for connectors_active and setting dpms to that function. Changes since v1: - Move drm_atomic_helper_swap_state up. Changes since v2: - Split out intel_put_shared_dpll removal. Changes since v3: - Rebase on top of latest drm-intel. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 93 +++++++--------------------- 2 files changed, 23 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 46722f85ef761..03ae50ee47372 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -631,7 +631,6 @@ struct drm_i915_display_funcs { struct intel_crtc_state *crtc_state); void (*crtc_enable)(struct drm_crtc *crtc); void (*crtc_disable)(struct drm_crtc *crtc); - void (*off)(struct drm_crtc *crtc); void (*audio_codec_enable)(struct drm_connector *connector, struct intel_encoder *encoder, struct drm_display_mode *mode); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9d271172dddd9..490581081df74 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6278,10 +6278,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } -static void i9xx_crtc_off(struct drm_crtc *crtc) -{ -} - /* Master function to enable/disable CRTC and corresponding power wells */ void intel_crtc_control(struct drm_crtc *crtc, bool enable) { @@ -6331,34 +6327,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) crtc->state->active = enable; } -static void intel_crtc_disable(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_connector *connector; - struct drm_i915_private *dev_priv = dev->dev_private; - - /* crtc should still be enabled when we disable it. */ - WARN_ON(!crtc->state->enable); - - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); - dev_priv->display.off(crtc); - - drm_plane_helper_disable(crtc->primary); - - /* Update computed state. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { - if (!connector->encoder || !connector->encoder->crtc) - continue; - - if (connector->encoder->crtc != crtc) - continue; - - connector->dpms = DRM_MODE_DPMS_OFF; - to_intel_encoder(connector->encoder)->connectors_active = false; - } -} - void intel_encoder_destroy(struct drm_encoder *encoder) { struct intel_encoder *intel_encoder = to_intel_encoder(encoder); @@ -12272,26 +12240,22 @@ intel_modeset_update_state(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_connector *connector; - int i; intel_shared_dpll_commit(dev_priv); + drm_atomic_helper_swap_state(state->dev, state); for_each_intel_encoder(dev, intel_encoder) { if (!intel_encoder->base.crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc != intel_encoder->base.crtc) - continue; - - if (crtc_state->enable && needs_modeset(crtc_state)) - intel_encoder->connectors_active = false; + crtc = intel_encoder->base.crtc; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (!crtc_state || !needs_modeset(crtc->state)) + continue; - break; - } + intel_encoder->connectors_active = false; } - drm_atomic_helper_swap_state(state->dev, state); intel_modeset_fixup_state(state); /* Double check state. */ @@ -12303,27 +12267,23 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!connector->encoder || !connector->encoder->crtc) continue; - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (crtc != connector->encoder->crtc) - continue; - - if (crtc->state->enable && needs_modeset(crtc->state)) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; + crtc = connector->encoder->crtc; + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (!crtc_state || !needs_modeset(crtc->state)) + continue; - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, - dpms_property, - DRM_MODE_DPMS_ON); + if (crtc->state->enable) { + struct drm_property *dpms_property = + dev->mode_config.dpms_property; - intel_encoder = to_intel_encoder(connector->encoder); - intel_encoder->connectors_active = true; - } + connector->dpms = DRM_MODE_DPMS_ON; + drm_object_property_set_value(&connector->base, dpms_property, DRM_MODE_DPMS_ON); - break; - } + intel_encoder = to_intel_encoder(connector->encoder); + intel_encoder->connectors_active = true; + } else + connector->dpms = DRM_MODE_DPMS_OFF; } - } static bool intel_fuzzy_clock_check(int clock1, int clock2) @@ -13001,12 +12961,10 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, if (!needs_modeset(crtc_state)) continue; - if (!crtc_state->enable) { - intel_crtc_disable(crtc); - } else if (crtc->state->enable) { - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); - } + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); + if (!crtc_state->enable) + drm_plane_helper_disable(crtc->primary); } /* crtc->mode is already used by the ->mode_set callbacks, hence we need @@ -14742,7 +14700,6 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = skylake_update_primary_plane; } else if (HAS_DDI(dev)) { @@ -14753,7 +14710,6 @@ static void intel_init_display(struct drm_device *dev) haswell_crtc_compute_clock; dev_priv->display.crtc_enable = haswell_crtc_enable; dev_priv->display.crtc_disable = haswell_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (HAS_PCH_SPLIT(dev)) { @@ -14764,7 +14720,6 @@ static void intel_init_display(struct drm_device *dev) ironlake_crtc_compute_clock; dev_priv->display.crtc_enable = ironlake_crtc_enable; dev_priv->display.crtc_disable = ironlake_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = ironlake_update_primary_plane; } else if (IS_VALLEYVIEW(dev)) { @@ -14774,7 +14729,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; dev_priv->display.crtc_enable = valleyview_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = i9xx_update_primary_plane; } else { @@ -14784,7 +14738,6 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock; dev_priv->display.crtc_enable = i9xx_crtc_enable; dev_priv->display.crtc_disable = i9xx_crtc_disable; - dev_priv->display.off = i9xx_crtc_off; dev_priv->display.update_primary_plane = i9xx_update_primary_plane; } -- GitLab From 6b72d486245265676df9866734bca1b39252e480 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:47 +0200 Subject: [PATCH 0066/7006] drm/i915: add intel_display_suspend, v2 This is a function used to disable all crtc's. This makes it clearer to distinguish between when mode needs to be preserved and when it can be trashed. Changes since v1: - Copy power changes from intel_crtc_control. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 4 +-- drivers/gpu/drm/i915/intel_display.c | 38 ++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index a051a0241883c..78ef0bb53c36a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -601,7 +601,6 @@ static int bxt_resume_prepare(struct drm_i915_private *dev_priv); static int i915_drm_suspend(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; pci_power_t opregion_target_state; int error; @@ -632,8 +631,7 @@ static int i915_drm_suspend(struct drm_device *dev) * for _thaw. Also, power gate the CRTC power wells. */ drm_modeset_lock_all(dev); - for_each_crtc(dev, crtc) - intel_crtc_control(crtc, false); + intel_display_suspend(dev); drm_modeset_unlock_all(dev); intel_dp_mst_suspend(dev); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 490581081df74..da7c886026da0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3190,9 +3190,6 @@ void intel_crtc_reset(struct intel_crtc *crtc) void intel_prepare_reset(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(dev); - struct intel_crtc *crtc; - /* no reset support for gen2 */ if (IS_GEN2(dev)) return; @@ -3207,13 +3204,7 @@ void intel_prepare_reset(struct drm_device *dev) * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. */ - for_each_intel_crtc(dev, crtc) { - if (!crtc->active) - continue; - - intel_crtc_disable_planes(&crtc->base); - dev_priv->display.crtc_disable(&crtc->base); - } + intel_display_suspend(dev); } void intel_finish_reset(struct drm_device *dev) @@ -6278,6 +6269,33 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } +/* + * turn all crtc's off, but do not adjust state + * This has to be paired with a call to intel_modeset_setup_hw_state. + */ +void intel_display_suspend(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_crtc *crtc; + + for_each_crtc(dev, crtc) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum intel_display_power_domain domain; + unsigned long domains; + + if (!intel_crtc->active) + continue; + + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); + + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; + } +} + /* Master function to enable/disable CRTC and corresponding power wells */ void intel_crtc_control(struct drm_crtc *crtc, bool enable) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4635c83e6dc2a..31afeb05ea90a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -993,6 +993,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); +void intel_display_suspend(struct drm_device *dev); void intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_reset(struct intel_crtc *crtc); void intel_crtc_update_dpms(struct drm_crtc *crtc); -- GitLab From 1b5092592824d1c91d6e48d820b6047f6ba323ce Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:48 +0200 Subject: [PATCH 0067/7006] drm/i915: use intel_crtc_control everywhere, v3. Having a single path for everything makes it a lot easier to keep crtc_state->active in sync with intel_crtc->active. A crtc cannot be changed to active when not enabled, because it means no mode is set and no connectors are connected. This should also make intel_crtc->active match crtc_state->active. Changes since v1: - Reworded commit message, there's no intel_crtc_toggle. Changes since v2: - Change some callers of intel_crtc_control to intel_display_suspend. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 18 ++++++++-- drivers/gpu/drm/i915/intel_display.c | 54 +++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 35 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 47d9854434c59..aac252ca0bda3 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -3630,12 +3630,18 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev) */ if (crtc->config->cpu_transcoder == TRANSCODER_EDP && !crtc->config->pch_pfit.enabled) { + bool active = crtc->active; + + if (active) + intel_crtc_control(&crtc->base, false); + crtc->config->pch_pfit.force_thru = true; intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); - intel_crtc_reset(crtc); + if (active) + intel_crtc_control(&crtc->base, true); } drm_modeset_unlock_all(dev); } @@ -3654,12 +3660,18 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) * routing. */ if (crtc->config->pch_pfit.force_thru) { - crtc->config->pch_pfit.force_thru = false; + bool active = crtc->active; - intel_crtc_reset(crtc); + if (active) + intel_crtc_control(&crtc->base, false); + + crtc->config->pch_pfit.force_thru = false; intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); + + if (active) + intel_crtc_control(&crtc->base, true); } drm_modeset_unlock_all(dev); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index da7c886026da0..aab75d3b7d20e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3175,19 +3175,6 @@ static void intel_update_primary_planes(struct drm_device *dev) } } -void intel_crtc_reset(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = to_i915(crtc->base.dev); - - if (!crtc->active) - return; - - intel_crtc_disable_planes(&crtc->base); - dev_priv->display.crtc_disable(&crtc->base); - dev_priv->display.crtc_enable(&crtc->base); - intel_crtc_enable_planes(&crtc->base); -} - void intel_prepare_reset(struct drm_device *dev) { /* no reset support for gen2 */ @@ -3199,7 +3186,6 @@ void intel_prepare_reset(struct drm_device *dev) return; drm_modeset_lock_all(dev); - /* * Disabling the crtcs gracefully seems nicer. Also the * g33 docs say we should at least disable all the planes. @@ -6305,26 +6291,29 @@ void intel_crtc_control(struct drm_crtc *crtc, bool enable) enum intel_display_power_domain domain; unsigned long domains; + if (enable == intel_crtc->active) + return; + + if (enable && !crtc->state->enable) + return; + + crtc->state->active = enable; if (enable) { - if (!intel_crtc->active) { - domains = get_crtc_power_domains(crtc); - for_each_power_domain(domain, domains) - intel_display_power_get(dev_priv, domain); - intel_crtc->enabled_power_domains = domains; + domains = get_crtc_power_domains(crtc); + for_each_power_domain(domain, domains) + intel_display_power_get(dev_priv, domain); + intel_crtc->enabled_power_domains = domains; - dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); - } + dev_priv->display.crtc_enable(crtc); + intel_crtc_enable_planes(crtc); } else { - if (intel_crtc->active) { - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; - } + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; } } @@ -6341,8 +6330,6 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc) enable |= intel_encoder->connectors_active; intel_crtc_control(crtc, enable); - - crtc->state->active = enable; } void intel_encoder_destroy(struct drm_encoder *encoder) @@ -15240,8 +15227,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; crtc->plane = !plane; - intel_crtc_disable_planes(&crtc->base); - dev_priv->display.crtc_disable(&crtc->base); + intel_crtc_control(&crtc->base, false); crtc->plane = plane; /* ... and break all links. */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 31afeb05ea90a..ea1351f87f0a9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -995,7 +995,6 @@ void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); void intel_display_suspend(struct drm_device *dev); void intel_crtc_control(struct drm_crtc *crtc, bool enable); -void intel_crtc_reset(struct intel_crtc *crtc); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); -- GitLab From 3cb480bcb3397a1cfdc04115adcdb33393fde4f9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:49 +0200 Subject: [PATCH 0068/7006] drm/i915: Use drm_atomic_helper_update_legacy_modeset_state, v2. Now that the helper is exported there's no need to duplicate this code any more. Changes since v1: - move intel_modeset_update_staged_output_state call to the right place. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 61 ++-------------------------- 1 file changed, 4 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aab75d3b7d20e..c1042ea501361 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11737,43 +11737,6 @@ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) } } -/* Fixup legacy state after an atomic state swap. - */ -static void intel_modeset_fixup_state(struct drm_atomic_state *state) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - - for_each_intel_connector(state->dev, connector) { - connector->base.encoder = connector->base.state->best_encoder; - if (connector->base.encoder) - connector->base.encoder->crtc = - connector->base.state->crtc; - } - - /* Update crtc of disabled encoders */ - for_each_intel_encoder(state->dev, encoder) { - int num_connectors = 0; - - for_each_intel_connector(state->dev, connector) - if (connector->base.encoder == &encoder->base) - num_connectors++; - - if (num_connectors == 0) - encoder->base.crtc = NULL; - } - - for_each_intel_crtc(state->dev, crtc) { - crtc->base.enabled = crtc->base.state->enable; - crtc->config = to_intel_crtc_state(crtc->base.state); - } - - /* Copy the new configuration to the staged state, to keep the few - * pieces of code that haven't been converted yet happy */ - intel_modeset_update_staged_output_state(state->dev); -} - static void connected_sink_compute_bpp(struct intel_connector *connector, struct intel_crtc_state *pipe_config) @@ -12261,11 +12224,14 @@ intel_modeset_update_state(struct drm_atomic_state *state) intel_encoder->connectors_active = false; } - intel_modeset_fixup_state(state); + drm_atomic_helper_update_legacy_modeset_state(state->dev, state); + intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc(dev, crtc) { WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); + + to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { @@ -12972,25 +12938,6 @@ static int __intel_set_mode(struct drm_crtc *modeset_crtc, drm_plane_helper_disable(crtc->primary); } - /* crtc->mode is already used by the ->mode_set callbacks, hence we need - * to set it here already despite that we pass it down the callchain. - * - * Note we'll need to fix this up when we start tracking multiple - * pipes; here we assume a single modeset_pipe and only track the - * single crtc and mode. - */ - if (pipe_config->base.enable && needs_modeset(&pipe_config->base)) { - modeset_crtc->mode = pipe_config->base.mode; - - /* - * Calculate and store various constants which - * are later needed by vblank and swap-completion - * timestamping. They are derived from true hwmode. - */ - drm_calc_timestamping_constants(modeset_crtc, - &pipe_config->base.adjusted_mode); - } - /* Only after disabling all output pipelines that will be changed can we * update the the output configuration. */ intel_modeset_update_state(state); -- GitLab From c72d969b23253ee8196e4190ec2c15e7cf607372 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:49:50 +0200 Subject: [PATCH 0069/7006] drm/i915: Make __intel_set_mode() take only atomic state as argument With the use of drm_atomic_helper_update_legacy_modeset_state the last user of modeset_crtc is removed from this function. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c1042ea501361..7116217ca25ba 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12909,12 +12909,10 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) return 0; } -static int __intel_set_mode(struct drm_crtc *modeset_crtc, - struct intel_crtc_state *pipe_config) +static int __intel_set_mode(struct drm_atomic_state *state) { - struct drm_device *dev = modeset_crtc->dev; + struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_atomic_state *state = pipe_config->base.state; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret = 0; @@ -12974,7 +12972,7 @@ static int intel_set_mode_with_config(struct drm_crtc *crtc, { int ret; - ret = __intel_set_mode(crtc, pipe_config); + ret = __intel_set_mode(pipe_config->base.state); if (ret == 0) intel_modeset_check_state(crtc->dev); -- GitLab From cdba954e426761cdfe08ce4c9909cd97ce254b9c Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:49:51 +0200 Subject: [PATCH 0070/7006] drm/i915: Set mode_changed for audio in intel_modeset_pipe_config() A follow up patch will make intel_modeset_compute_config() deal with multiple crtcs, so move crtc specific stuff into the lower level crtc specific function. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 51 +++++++++++++++------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7116217ca25ba..eb40f9fc9b446 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -431,6 +431,12 @@ static void vlv_clock(int refclk, intel_clock_t *clock) clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } +static bool +needs_modeset(struct drm_crtc_state *state) +{ + return state->mode_changed || state->active_changed; +} + /** * Returns whether any output on the specified pipe is of the specified type */ @@ -12085,6 +12091,15 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return -EINVAL; } + /* + * XXX: Add all connectors to make the crtc state match the encoders. + */ + if (!needs_modeset(&pipe_config->base)) { + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; + } + clear_intel_crtc_state(pipe_config); pipe_config->cpu_transcoder = @@ -12176,6 +12191,18 @@ encoder_retry: DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", base_bpp, pipe_config->pipe_bpp, pipe_config->dither); + /* Check if we need to force a modeset */ + if (pipe_config->has_audio != + to_intel_crtc_state(crtc->state)->has_audio) + pipe_config->base.mode_changed = true; + + /* + * Note we have an issue here with infoframes: current code + * only updates them on the full mode set path per hw + * requirements. So here we should be checking for any + * required changes and forcing a mode set. + */ + return 0; fail: return ret; @@ -12193,12 +12220,6 @@ static bool intel_crtc_in_use(struct drm_crtc *crtc) return false; } -static bool -needs_modeset(struct drm_crtc_state *state) -{ - return state->mode_changed || state->active_changed; -} - static void intel_modeset_update_state(struct drm_atomic_state *state) { @@ -12785,10 +12806,6 @@ intel_modeset_compute_config(struct drm_crtc *crtc, struct intel_crtc_state *pipe_config; int ret = 0; - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ERR_PTR(ret); - ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) return ERR_PTR(ret); @@ -12810,19 +12827,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (ret) return ERR_PTR(ret); - /* Check things that can only be changed through modeset */ - if (pipe_config->has_audio != - to_intel_crtc(crtc)->config->has_audio) - pipe_config->base.mode_changed = true; - - /* - * Note we have an issue here with infoframes: current code - * only updates them on the full mode set path per hw - * requirements. So here we should be checking for any - * required changes and forcing a mode set. - */ - - intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,"[modeset]"); + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, "[modeset]"); ret = drm_atomic_helper_check_planes(state->dev, state); if (ret) -- GitLab From 53d9f4e99de001374eb06195609cc0451f31a318 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:52 +0200 Subject: [PATCH 0071/7006] drm/i915: Use crtc_state->active instead of crtc_state->enable crtc_state->enable means a crtc is configured, but it may be turned off for dpms. Until the commit "use intel_crtc_control everywhere" crtc_state->active was not updated on crtc off, but now crtc_state->active should be used for tracking whether a crtc is scanning out or not. A few commits from now dpms will be handled by calling intel_set_mode with a different value for crtc_state->active, which causes a crtc to turn on or off. At this point crtc->active should mirror crtc_state->active, so some paranoia from the crtc_disable functions can be removed. intel_set_mode_setup_plls still checks for ->enable, because all resources that are needed have to be calculated, else dpms changes may not succeed. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 44 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index eb52a039d6287..dadd586f05277 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -796,7 +796,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, return -EINVAL; } - if (!crtc->state->enable) { + if (!crtc->state->active) { DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); return -EBUSY; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb40f9fc9b446..4648fa5ab55af 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4629,7 +4629,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc) bool reenable_ips = false; /* The clocks have to be on to load the palette. */ - if (!crtc->state->enable || !intel_crtc->active) + if (!crtc->state->active) return; if (HAS_GMCH_DISPLAY(dev_priv->dev)) { @@ -4845,9 +4845,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; if (intel_crtc->config->has_pch_encoder) @@ -4951,9 +4949,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; if (intel_crtc_to_shared_dpll(intel_crtc)) @@ -5055,7 +5051,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp; - if (!intel_crtc->active) + if (WARN_ON(!intel_crtc->active)) return; for_each_encoder_on_crtc(dev, crtc, encoder) @@ -5118,7 +5114,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - if (!intel_crtc->active) + if (WARN_ON(!intel_crtc->active)) return; for_each_encoder_on_crtc(dev, crtc, encoder) { @@ -5978,7 +5974,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) /* add all active pipes to the state */ for_each_crtc(state->dev, crtc) { - if (!crtc->state->enable) + if (!crtc->state->active) continue; crtc_state = drm_atomic_get_crtc_state(state, crtc); @@ -5988,7 +5984,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) /* disable/enable all currently active pipes while we change cdclk */ for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->enable) + if (crtc_state->active) crtc_state->mode_changed = true; return 0; @@ -6076,9 +6072,7 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; bool is_dsi; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; is_dsi = intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_DSI); @@ -6154,9 +6148,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - WARN_ON(!crtc->state->enable); - - if (intel_crtc->active) + if (WARN_ON(intel_crtc->active)) return; i9xx_set_pll_dividers(intel_crtc); @@ -6216,7 +6208,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - if (!intel_crtc->active) + if (WARN_ON(!intel_crtc->active)) return; /* @@ -12264,7 +12256,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) if (!crtc_state || !needs_modeset(crtc->state)) continue; - if (crtc->state->enable) { + if (crtc->state->active) { struct drm_property *dpms_property = dev->mode_config.dpms_property; @@ -12679,6 +12671,10 @@ check_crtc_state(struct drm_device *dev) "crtc active state doesn't match with hw state " "(expected %i, found %i)\n", crtc->active, active); + I915_STATE_WARN(crtc->active != crtc->base.state->active, + "transitional active state does not match atomic hw state " + "(expected %i, found %i)\n", crtc->base.state->active, crtc->active); + if (active && !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) { I915_STATE_WARN(1, "pipe state doesn't match!\n"); @@ -12820,6 +12816,10 @@ intel_modeset_compute_config(struct drm_crtc *crtc, if (IS_ERR(pipe_config)) return pipe_config; + if (!pipe_config->base.enable && + WARN_ON(pipe_config->base.active)) + pipe_config->base.active = false; + if (!pipe_config->base.enable) return pipe_config; @@ -12932,7 +12932,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) return ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state)) + if (!needs_modeset(crtc_state) || !crtc->state->active) continue; intel_crtc_disable_planes(crtc); @@ -12954,7 +12954,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc->state) || !crtc->state->enable) + if (!needs_modeset(crtc->state) || !crtc->state->active) continue; update_scanline_offset(to_intel_crtc(crtc)); @@ -15215,7 +15215,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * have active connectors/encoders. */ intel_crtc_update_dpms(&crtc->base); - if (crtc->active != crtc->base.state->enable) { + if (crtc->active != crtc->base.state->active) { struct intel_encoder *encoder; /* This can happen either due to bugs in the get_hw_state -- GitLab From 85a96e7a4213de094acc63fd433dcf766e91c782 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:53 +0200 Subject: [PATCH 0072/7006] drm/i915: Make sure all planes and connectors are added on modeset. Add missing calls to drm_atomic_add_affected_*. This is needed to convert to atomic planes. When converting to atomic all planes are needed on modeset. For good measure make sure all connectors are added too. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4648fa5ab55af..2b5b829a98adf 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5959,7 +5959,7 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int max_pixclk = intel_mode_max_pixclk(state->dev, state); - int cdclk, i; + int cdclk, ret = 0; if (max_pixclk < 0) return max_pixclk; @@ -5974,20 +5974,25 @@ static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) /* add all active pipes to the state */ for_each_crtc(state->dev, crtc) { - if (!crtc->state->active) - continue; - crtc_state = drm_atomic_get_crtc_state(state, crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - } - /* disable/enable all currently active pipes while we change cdclk */ - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->active) - crtc_state->mode_changed = true; + if (!crtc_state->active || needs_modeset(crtc_state)) + continue; - return 0; + crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + break; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + break; + } + + return ret; } static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) @@ -12185,8 +12190,10 @@ encoder_retry: /* Check if we need to force a modeset */ if (pipe_config->has_audio != - to_intel_crtc_state(crtc->state)->has_audio) + to_intel_crtc_state(crtc->state)->has_audio) { pipe_config->base.mode_changed = true; + ret = drm_atomic_add_affected_planes(state, crtc); + } /* * Note we have an issue here with infoframes: current code @@ -12194,8 +12201,6 @@ encoder_retry: * requirements. So here we should be checking for any * required changes and forcing a mode set. */ - - return 0; fail: return ret; } -- GitLab From 36750f284b3a4f19b304fda1bb7d6e9e1275ea8d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:54 +0200 Subject: [PATCH 0073/7006] drm/i915: update plane state during init Atomic planes updates rely on having a accurate plane_mask. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2b5b829a98adf..91a0f7ca7ed27 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2632,9 +2632,9 @@ valid_fb: dev_priv->preserve_bios_swizzle = true; primary->fb = fb; - primary->state->crtc = &intel_crtc->base; - primary->crtc = &intel_crtc->base; + primary->crtc = primary->state->crtc = &intel_crtc->base; update_state_fb(primary); + intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); } @@ -15563,7 +15563,9 @@ void intel_modeset_gem_init(struct drm_device *dev) to_intel_crtc(c)->pipe); drm_framebuffer_unreference(c->primary->fb); c->primary->fb = NULL; + c->primary->crtc = c->primary->state->crtc = NULL; update_state_fb(c->primary); + c->state->plane_mask &= ~(1 << drm_plane_index(c->primary)); } } -- GitLab From 8a8f7f44a1b704c482f77a0d31cbcdf1af062263 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:55 +0200 Subject: [PATCH 0074/7006] drm/i915: do not wait for vblank when crtc is off This can happen when turning off a sprite plane. Because the crtc state is not yet always swapped correctly and transitional helpers are used the crtc state cannot be relied on. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 91a0f7ca7ed27..e0edff9d034db 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13768,7 +13768,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_put(dev_priv); - if (intel_crtc->atomic.wait_vblank) + if (intel_crtc->atomic.wait_vblank && intel_crtc->active) intel_wait_for_vblank(dev, intel_crtc->pipe); intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits); -- GitLab From fb9d6cf8c29bfcb0b3c602f7ded87f128d730382 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:56 +0200 Subject: [PATCH 0075/7006] drm/i915: calculate primary visibility changes instead of calling from set_config This should be much cleaner, with the same effects. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 46 +++++----------------------- 1 file changed, 7 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e0edff9d034db..52759c03c9e85 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13225,20 +13225,11 @@ intel_modeset_stage_output_state(struct drm_device *dev, return 0; } -static bool primary_plane_visible(struct drm_crtc *crtc) -{ - struct intel_plane_state *plane_state = - to_intel_plane_state(crtc->primary->state); - - return plane_state->visible; -} - static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; struct intel_crtc_state *pipe_config; - bool primary_plane_was_visible; int ret; BUG_ON(!set); @@ -13277,38 +13268,8 @@ static int intel_crtc_set_config(struct drm_mode_set *set) intel_update_pipe_size(to_intel_crtc(set->crtc)); - primary_plane_was_visible = primary_plane_visible(set->crtc); - ret = intel_set_mode_with_config(set->crtc, pipe_config); - if (ret == 0 && - pipe_config->base.enable && - pipe_config->base.planes_changed && - !needs_modeset(&pipe_config->base)) { - struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc); - - /* - * We need to make sure the primary plane is re-enabled if it - * has previously been turned off. - */ - if (ret == 0 && !primary_plane_was_visible && - primary_plane_visible(set->crtc)) { - WARN_ON(!intel_crtc->active); - intel_post_enable_primary(set->crtc); - } - - /* - * In the fastboot case this may be our only check of the - * state after boot. It would be better to only do it on - * the first update, but we don't have a nice way of doing that - * (and really, set_config isn't used much for high freq page - * flipping, so increasing its cost here shouldn't be a big - * deal). - */ - if (i915.fastboot && ret == 0) - intel_modeset_check_state(set->crtc->dev); - } - if (ret) { DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", set->crtc->base.id, ret); @@ -13641,8 +13602,15 @@ intel_check_primary_plane(struct drm_plane *plane, */ if (IS_BROADWELL(dev)) intel_crtc->atomic.wait_vblank = true; + + if (crtc_state && !needs_modeset(&crtc_state->base)) + intel_crtc->atomic.post_enable_primary = true; } + if (!state->visible && old_state->visible && + crtc_state && !needs_modeset(&crtc_state->base)) + intel_crtc->atomic.pre_disable_primary = true; + intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); -- GitLab From 568c634a2af62e07ed248a6e7fe9770173f9d9b2 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:49:57 +0200 Subject: [PATCH 0076/7006] drm/i915: Support modeset across multiple pipes Compute new pipe_configs for all crtcs in the atomic state. The commit part of the mode set (__intel_set_mode()) is already enabled to support multiple pipes, the only thing missing was calculating a new pipe_config for every crtc. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 108 +++++++++++---------------- 1 file changed, 45 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 52759c03c9e85..e566515e27ca1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -86,8 +86,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); -static int intel_set_mode(struct drm_crtc *crtc, - struct drm_atomic_state *state); +static int intel_set_mode(struct drm_atomic_state *state); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, @@ -10482,7 +10481,7 @@ retry: drm_mode_copy(&crtc_state->base.mode, mode); - if (intel_set_mode(crtc, state)) { + if (intel_set_mode(state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -10556,7 +10555,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - ret = intel_set_mode(crtc, state); + ret = intel_set_mode(state); if (ret) goto fail; @@ -12068,9 +12067,10 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) static int intel_modeset_pipe_config(struct drm_crtc *crtc, - struct drm_atomic_state *state, - struct intel_crtc_state *pipe_config) + struct drm_atomic_state *state) { + struct drm_crtc_state *crtc_state; + struct intel_crtc_state *pipe_config; struct intel_encoder *encoder; struct drm_connector *connector; struct drm_connector_state *connector_state; @@ -12088,6 +12088,12 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return -EINVAL; } + crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); + if (WARN_ON(!crtc_state)) + return -EINVAL; + + pipe_config = to_intel_crtc_state(crtc_state); + /* * XXX: Add all connectors to make the crtc state match the encoders. */ @@ -12800,45 +12806,35 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static struct intel_crtc_state * -intel_modeset_compute_config(struct drm_crtc *crtc, - struct drm_atomic_state *state) +static int +intel_modeset_compute_config(struct drm_atomic_state *state) { - struct intel_crtc_state *pipe_config; - int ret = 0; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret, i; ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) - return ERR_PTR(ret); - - /* - * Note this needs changes when we start tracking multiple modes - * and crtcs. At that point we'll need to compute the whole config - * (i.e. one pipe_config for each crtc) rather than just the one - * for this crtc. - */ - pipe_config = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); - if (IS_ERR(pipe_config)) - return pipe_config; - - if (!pipe_config->base.enable && - WARN_ON(pipe_config->base.active)) - pipe_config->base.active = false; + return ret; - if (!pipe_config->base.enable) - return pipe_config; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->enable && + WARN_ON(crtc_state->active)) + crtc_state->active = false; - ret = intel_modeset_pipe_config(crtc, state, pipe_config); - if (ret) - return ERR_PTR(ret); + if (!crtc_state->enable) + continue; - intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, "[modeset]"); + ret = intel_modeset_pipe_config(crtc, state); + if (ret) + return ret; - ret = drm_atomic_helper_check_planes(state->dev, state); - if (ret) - return ERR_PTR(ret); + intel_dump_pipe_config(to_intel_crtc(crtc), + to_intel_crtc_state(crtc_state), + "[modeset]"); + } - return pipe_config; + return drm_atomic_helper_check_planes(state->dev, state); } static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) @@ -12977,37 +12973,27 @@ static int __intel_set_mode(struct drm_atomic_state *state) return 0; } -static int intel_set_mode_with_config(struct drm_crtc *crtc, - struct intel_crtc_state *pipe_config) +static int intel_set_mode_checked(struct drm_atomic_state *state) { + struct drm_device *dev = state->dev; int ret; - ret = __intel_set_mode(pipe_config->base.state); - + ret = __intel_set_mode(state); if (ret == 0) - intel_modeset_check_state(crtc->dev); + intel_modeset_check_state(dev); return ret; } -static int intel_set_mode(struct drm_crtc *crtc, - struct drm_atomic_state *state) +static int intel_set_mode(struct drm_atomic_state *state) { - struct intel_crtc_state *pipe_config; - int ret = 0; - - pipe_config = intel_modeset_compute_config(crtc, state); - if (IS_ERR(pipe_config)) { - ret = PTR_ERR(pipe_config); - goto out; - } + int ret; - ret = intel_set_mode_with_config(crtc, pipe_config); + ret = intel_modeset_compute_config(state); if (ret) - goto out; + return ret; -out: - return ret; + return intel_set_mode_checked(state); } void intel_crtc_restore_mode(struct drm_crtc *crtc) @@ -13079,7 +13065,7 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) intel_modeset_setup_plane_state(state, crtc, &crtc->mode, crtc->primary->fb, crtc->x, crtc->y); - ret = intel_set_mode(crtc, state); + ret = intel_set_mode(state); if (ret) drm_atomic_state_free(state); } @@ -13229,7 +13215,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set) { struct drm_device *dev; struct drm_atomic_state *state = NULL; - struct intel_crtc_state *pipe_config; int ret; BUG_ON(!set); @@ -13260,16 +13245,13 @@ static int intel_crtc_set_config(struct drm_mode_set *set) if (ret) goto out; - pipe_config = intel_modeset_compute_config(set->crtc, state); - if (IS_ERR(pipe_config)) { - ret = PTR_ERR(pipe_config); + ret = intel_modeset_compute_config(state); + if (ret) goto out; - } intel_update_pipe_size(to_intel_crtc(set->crtc)); - ret = intel_set_mode_with_config(set->crtc, pipe_config); - + ret = intel_set_mode_checked(state); if (ret) { DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", set->crtc->base.id, ret); -- GitLab From 880fa62648bf193eb17193a9eae00a52c7844ea7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:49:58 +0200 Subject: [PATCH 0077/7006] drm/i915: Zap call to drm_plane_helper_disable, v2. The primary plane can still be configured when crtc is off, furthermore this is also a noop now that affected planes are added on modesets. Changes since v1: - Move commit so no frontbuffer_bits warnings are generated. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e566515e27ca1..dcd256f47fe50 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12938,8 +12938,6 @@ static int __intel_set_mode(struct drm_atomic_state *state) intel_crtc_disable_planes(crtc); dev_priv->display.crtc_disable(crtc); - if (!crtc_state->enable) - drm_plane_helper_disable(crtc->primary); } /* Only after disabling all output pipelines that will be changed can we -- GitLab From de419ab6b774facc14b2fa71e3d8642027924c86 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 4 Jun 2015 10:21:28 +0200 Subject: [PATCH 0078/7006] drm/i915: Use global atomic state for staged pll, config, v3. Now that we can subclass drm_atomic_state we can also use it to keep track of all the pll settings. atomic_state is a better place to hold all shared state than keeping pll->new_config everywhere. Changes since v1: - Assert connection_mutex is held. Changes since v2: - Fix swapped arguments to kzalloc for intel_atomic_state_alloc. (Jani Nikula) Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_atomic.c | 51 ++++++++++++ drivers/gpu/drm/i915/intel_display.c | 111 ++++++++------------------- drivers/gpu/drm/i915/intel_drv.h | 13 ++++ 4 files changed, 97 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 03ae50ee47372..611fbd86c1cc2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -376,7 +376,6 @@ struct intel_shared_dpll_config { struct intel_shared_dpll { struct intel_shared_dpll_config config; - struct intel_shared_dpll_config *new_config; int active; /* count of number of active CRTCs (i.e. DPMS on) */ bool on; /* is the PLL actually active? Disabled during modeset */ diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 7ed8033aae609..45af3cc9d04c8 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -421,3 +421,54 @@ int intel_atomic_setup_scalers(struct drm_device *dev, return 0; } + +static void +intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, + struct intel_shared_dpll_config *shared_dpll) +{ + enum intel_dpll_id i; + + /* Copy shared dpll state */ + for (i = 0; i < dev_priv->num_shared_dpll; i++) { + struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; + + shared_dpll[i] = pll->config; + } +} + +struct intel_shared_dpll_config * +intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s) +{ + struct intel_atomic_state *state = to_intel_atomic_state(s); + + WARN_ON(!drm_modeset_is_locked(&s->dev->mode_config.connection_mutex)); + + if (!state->dpll_set) { + state->dpll_set = true; + + intel_atomic_duplicate_dpll_state(to_i915(s->dev), + state->shared_dpll); + } + + return state->shared_dpll; +} + +struct drm_atomic_state * +intel_atomic_state_alloc(struct drm_device *dev) +{ + struct intel_atomic_state *state = kzalloc(sizeof(*state), GFP_KERNEL); + + if (!state || drm_atomic_state_init(dev, &state->base) < 0) { + kfree(state); + return NULL; + } + + return &state->base; +} + +void intel_atomic_state_clear(struct drm_atomic_state *s) +{ + struct intel_atomic_state *state = to_intel_atomic_state(s); + drm_atomic_state_default_clear(&state->base); + state->dpll_set = false; +} diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dcd256f47fe50..aec398cd2289f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4186,8 +4186,11 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; struct intel_shared_dpll *pll; + struct intel_shared_dpll_config *shared_dpll; enum intel_dpll_id i; + shared_dpll = intel_atomic_get_shared_dpll_state(crtc_state->base.state); + if (HAS_PCH_IBX(dev_priv->dev)) { /* Ironlake PCH has a fixed PLL->PCH pipe mapping. */ i = (enum intel_dpll_id) crtc->pipe; @@ -4196,7 +4199,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->new_config->crtc_mask); + WARN_ON(shared_dpll[i].crtc_mask); goto found; } @@ -4216,7 +4219,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, pll = &dev_priv->shared_dplls[i]; DRM_DEBUG_KMS("CRTC:%d using pre-allocated %s\n", crtc->base.base.id, pll->name); - WARN_ON(pll->new_config->crtc_mask); + WARN_ON(shared_dpll[i].crtc_mask); goto found; } @@ -4225,15 +4228,15 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, pll = &dev_priv->shared_dplls[i]; /* Only want to check enabled timings first */ - if (pll->new_config->crtc_mask == 0) + if (shared_dpll[i].crtc_mask == 0) continue; if (memcmp(&crtc_state->dpll_hw_state, - &pll->new_config->hw_state, - sizeof(pll->new_config->hw_state)) == 0) { + &shared_dpll[i].hw_state, + sizeof(crtc_state->dpll_hw_state)) == 0) { DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n", crtc->base.base.id, pll->name, - pll->new_config->crtc_mask, + shared_dpll[i].crtc_mask, pll->active); goto found; } @@ -4242,7 +4245,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, /* Ok no matching timings, maybe there's a free one? */ for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - if (pll->new_config->crtc_mask == 0) { + if (shared_dpll[i].crtc_mask == 0) { DRM_DEBUG_KMS("CRTC:%d allocated %s\n", crtc->base.base.id, pll->name); goto found; @@ -4252,83 +4255,33 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc, return NULL; found: - if (pll->new_config->crtc_mask == 0) - pll->new_config->hw_state = crtc_state->dpll_hw_state; + if (shared_dpll[i].crtc_mask == 0) + shared_dpll[i].hw_state = + crtc_state->dpll_hw_state; crtc_state->shared_dpll = i; DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name, pipe_name(crtc->pipe)); - pll->new_config->crtc_mask |= 1 << crtc->pipe; + shared_dpll[i].crtc_mask |= 1 << crtc->pipe; return pll; } -/** - * intel_shared_dpll_start_config - start a new PLL staged config - * @dev_priv: DRM device - * @clear_pipes: mask of pipes that will have their PLLs freed - * - * Starts a new PLL staged config, copying the current config but - * releasing the references of pipes specified in clear_pipes. - */ -static int intel_shared_dpll_start_config(struct drm_i915_private *dev_priv, - unsigned clear_pipes) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id i; - - for (i = 0; i < dev_priv->num_shared_dpll; i++) { - pll = &dev_priv->shared_dplls[i]; - - pll->new_config = kmemdup(&pll->config, sizeof pll->config, - GFP_KERNEL); - if (!pll->new_config) - goto cleanup; - - pll->new_config->crtc_mask &= ~clear_pipes; - } - - return 0; - -cleanup: - while (--i >= 0) { - pll = &dev_priv->shared_dplls[i]; - kfree(pll->new_config); - pll->new_config = NULL; - } - - return -ENOMEM; -} - -static void intel_shared_dpll_commit(struct drm_i915_private *dev_priv) +static void intel_shared_dpll_commit(struct drm_atomic_state *state) { + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_shared_dpll_config *shared_dpll; struct intel_shared_dpll *pll; enum intel_dpll_id i; - for (i = 0; i < dev_priv->num_shared_dpll; i++) { - pll = &dev_priv->shared_dplls[i]; - - WARN_ON(pll->new_config == &pll->config); - - pll->config = *pll->new_config; - kfree(pll->new_config); - pll->new_config = NULL; - } -} - -static void intel_shared_dpll_abort_config(struct drm_i915_private *dev_priv) -{ - struct intel_shared_dpll *pll; - enum intel_dpll_id i; + if (!to_intel_atomic_state(state)->dpll_set) + return; + shared_dpll = to_intel_atomic_state(state)->shared_dpll; for (i = 0; i < dev_priv->num_shared_dpll; i++) { pll = &dev_priv->shared_dplls[i]; - - WARN_ON(pll->new_config == &pll->config); - - kfree(pll->new_config); - pll->new_config = NULL; + pll->config = shared_dpll[i]; } } @@ -12227,13 +12180,12 @@ static void intel_modeset_update_state(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_encoder *intel_encoder; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_connector *connector; - intel_shared_dpll_commit(dev_priv); + intel_shared_dpll_commit(state); drm_atomic_helper_swap_state(state->dev, state); for_each_intel_encoder(dev, intel_encoder) { @@ -12862,9 +12814,13 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) } } - ret = intel_shared_dpll_start_config(dev_priv, clear_pipes); - if (ret) - goto done; + if (clear_pipes) { + struct intel_shared_dpll_config *shared_dpll = + intel_atomic_get_shared_dpll_state(state); + + for (i = 0; i < dev_priv->num_shared_dpll; i++) + shared_dpll[i].crtc_mask &= ~clear_pipes; + } for_each_crtc_in_state(state, crtc, crtc_state, i) { if (!needs_modeset(crtc_state) || !crtc_state->enable) @@ -12875,13 +12831,10 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) ret = dev_priv->display.crtc_compute_clock(intel_crtc, intel_crtc_state); - if (ret) { - intel_shared_dpll_abort_config(dev_priv); - goto done; - } + if (ret) + return ret; } -done: return ret; } @@ -14582,6 +14535,8 @@ static const struct drm_mode_config_funcs intel_mode_funcs = { .output_poll_changed = intel_fbdev_output_poll_changed, .atomic_check = intel_atomic_check, .atomic_commit = intel_atomic_commit, + .atomic_state_alloc = intel_atomic_state_alloc, + .atomic_state_clear = intel_atomic_state_clear, }; /* Set up chip specific display functions */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index ea1351f87f0a9..e15039800cf0e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -241,6 +241,13 @@ typedef struct dpll { int p; } intel_clock_t; +struct intel_atomic_state { + struct drm_atomic_state base; + + bool dpll_set; + struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; +}; + struct intel_plane_state { struct drm_plane_state base; struct drm_rect src; @@ -628,6 +635,7 @@ struct cxsr_latency { unsigned long cursor_hpll_disable; }; +#define to_intel_atomic_state(x) container_of(x, struct intel_atomic_state, base) #define to_intel_crtc(x) container_of(x, struct intel_crtc, base) #define to_intel_crtc_state(x) container_of(x, struct intel_crtc_state, base) #define to_intel_connector(x) container_of(x, struct intel_connector, base) @@ -1404,6 +1412,11 @@ int intel_connector_atomic_get_property(struct drm_connector *connector, struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc); void intel_crtc_destroy_state(struct drm_crtc *crtc, struct drm_crtc_state *state); +struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); +void intel_atomic_state_clear(struct drm_atomic_state *); +struct intel_shared_dpll_config * +intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s); + static inline struct intel_crtc_state * intel_atomic_get_crtc_state(struct drm_atomic_state *state, struct intel_crtc *crtc) -- GitLab From 61c054983271426f8d31ef9e52eda249b123a7df Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:00 +0200 Subject: [PATCH 0079/7006] drm/i915: Use drm_atomic_helper_swap_state in intel_atomic_commit. And update crtc->config to point to the new state. There is no point in swapping only part of the state when the rest of the state should be untouched. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 44 ++++++++--------------------- 1 file changed, 12 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 45af3cc9d04c8..d0b901ddb3570 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -129,6 +129,8 @@ int intel_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, bool async) { + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; int ret; int i; @@ -142,48 +144,26 @@ int intel_atomic_commit(struct drm_device *dev, return ret; /* Point of no return */ + drm_atomic_helper_swap_state(dev, state); + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); + + if (INTEL_INFO(dev)->gen >= 9) + skl_detach_scalers(to_intel_crtc(crtc)); + } /* * FIXME: The proper sequence here will eventually be: * - * drm_atomic_helper_swap_state(dev, state) * drm_atomic_helper_commit_modeset_disables(dev, state); * drm_atomic_helper_commit_planes(dev, state); * 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); * - * once we have full atomic modeset. For now, just manually update - * plane states to avoid clobbering good states with dummy states - * while nuclear pageflipping. + * once we have full atomic modeset. */ - for (i = 0; i < dev->mode_config.num_total_plane; i++) { - struct drm_plane *plane = state->planes[i]; - - if (!plane) - continue; - - plane->state->state = state; - swap(state->plane_states[i], plane->state); - plane->state->state = NULL; - } - - /* swap crtc_scaler_state */ - for (i = 0; i < dev->mode_config.num_crtc; i++) { - struct drm_crtc *crtc = state->crtcs[i]; - if (!crtc) { - continue; - } - - to_intel_crtc(crtc)->config->scaler_state = - to_intel_crtc_state(state->crtc_states[i])->scaler_state; - - if (INTEL_INFO(dev)->gen >= 9) - skl_detach_scalers(to_intel_crtc(crtc)); - } - drm_atomic_helper_commit_planes(dev, state); + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); drm_atomic_state_free(state); -- GitLab From 5ac1c4bcf073ad897c4510931518275d9e393dc7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:01 +0200 Subject: [PATCH 0080/7006] drm/i915: Swap planes on each crtc separately, v2. Repeated calls to begin_crtc_commit can cause warnings like this: [ 169.127746] BUG: sleeping function called from invalid context at kernel/locking/mutex.c:616 [ 169.127835] in_atomic(): 0, irqs_disabled(): 1, pid: 1947, name: kms_flip [ 169.127840] 3 locks held by kms_flip/1947: [ 169.127843] #0: (&dev->mode_config.mutex){+.+.+.}, at: [] __drm_modeset_lock_all+0x9c/0x130 [ 169.127860] #1: (crtc_ww_class_acquire){+.+.+.}, at: [] __drm_modeset_lock_all+0xad/0x130 [ 169.127870] #2: (crtc_ww_class_mutex){+.+.+.}, at: [] drm_modeset_lock+0x38/0x110 [ 169.127879] irq event stamp: 665690 [ 169.127882] hardirqs last enabled at (665689): [] _raw_spin_unlock_irqrestore+0x55/0x70 [ 169.127889] hardirqs last disabled at (665690): [] intel_pipe_update_start+0x113/0x5c0 [i915] [ 169.127936] softirqs last enabled at (665470): [] __do_softirq+0x236/0x650 [ 169.127942] softirqs last disabled at (665465): [] irq_exit+0xc5/0xd0 [ 169.127951] CPU: 1 PID: 1947 Comm: kms_flip Not tainted 4.1.0-rc4-patser+ #4039 [ 169.127954] Hardware name: LENOVO 2349AV8/2349AV8, BIOS G1ETA5WW (2.65 ) 04/15/2014 [ 169.127957] ffff8800c49036f0 ffff8800cde5fa28 ffffffff817f6907 0000000080000001 [ 169.127964] 0000000000000000 ffff8800cde5fa58 ffffffff810aebed 0000000000000046 [ 169.127970] ffffffff81c5d518 0000000000000268 0000000000000000 ffff8800cde5fa88 [ 169.127981] Call Trace: [ 169.127992] [] dump_stack+0x4f/0x7b [ 169.128001] [] ___might_sleep+0x16d/0x270 [ 169.128008] [] __might_sleep+0x48/0x90 [ 169.128017] [] mutex_lock_nested+0x29/0x410 [ 169.128073] [] ? vgpu_write64+0x220/0x220 [i915] [ 169.128138] [] ? ironlake_update_primary_plane+0x2ff/0x410 [i915] [ 169.128198] [] intel_frontbuffer_flush+0x25/0x70 [i915] [ 169.128253] [] intel_finish_crtc_commit+0x4c/0x180 [i915] [ 169.128279] [] drm_atomic_helper_commit_planes+0x12c/0x240 [drm_kms_helper] [ 169.128338] [] __intel_set_mode+0x684/0x830 [i915] [ 169.128378] [] intel_crtc_set_config+0x49a/0x620 [i915] [ 169.128385] [] ? mutex_unlock+0x9/0x10 [ 169.128391] [] drm_mode_set_config_internal+0x69/0x120 [ 169.128398] [] ? might_fault+0x57/0xb0 [ 169.128403] [] drm_mode_setcrtc+0x253/0x620 [ 169.128409] [] drm_ioctl+0x1a0/0x6a0 [ 169.128415] [] ? get_parent_ip+0x11/0x50 [ 169.128424] [] do_vfs_ioctl+0x2f8/0x530 [ 169.128429] [] ? trace_hardirqs_on+0xd/0x10 [ 169.128435] [] ? selinux_file_ioctl+0x56/0x100 [ 169.128439] [] SyS_ioctl+0x81/0xa0 [ 169.128445] [] system_call_fastpath+0x12/0x6f Solve it by using the newly introduced drm_atomic_helper_commit_planes_on_crtc. The problem here was that the drm_atomic_helper_commit_planes() helper we were using was basically designed to do begin_crtc_commit(crtc #1) begin_crtc_commit(crtc #2) ... commit all planes finish_crtc_commit(crtc #1) finish_crtc_commit(crtc #2) The problem here is that since our hardware relies on vblank evasion, our CRTC 'begin' function waits until we're out of the danger zone in which register writes might wind up straddling the vblank, then disables interrupts; our 'finish' function re-enables interrupts after the registers have been written. The expectation is that the operations between 'begin' and 'end' must be performed without sleeping (since interrupts are disabled) and should happen as quickly as possible. By clumping all of the 'begin' calls together, we introducing a couple problems: * Subsequent 'begin' invocations might sleep (which is illegal) * The first 'begin' ensured that we were far enough from the vblank that we could write our registers safely and ensure they all fell within the same frame. Adding extra delay waiting for subsequent CRTC's wasn't accounted for and could put us back into the 'danger zone' for CRTC #1. This commit solves the problem by using a new helper that allows an order of operations like: for each crtc { begin_crtc_commit(crtc) // sleep (maybe), then disable interrupts commit planes for this specific CRTC end_crtc_commit(crtc) // reenable interrupts } so that sleeps will only be performed while interrupts are enabled and we can be sure that registers for a CRTC will be written immediately once we know we're in the safe zone. The crtc->config->base.crtc update may seem unrelated, but the helper will use it to obtain the crtc for the state. Without the update it will dereference NULL and crash. Changes since v1: - Use Matt Roper's commit message. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 13 +++---------- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index d0b901ddb3570..4df6d2d7a9c8e 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -151,18 +151,11 @@ int intel_atomic_commit(struct drm_device *dev, if (INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(to_intel_crtc(crtc)); + + drm_atomic_helper_commit_planes_on_crtc(crtc_state); } - /* - * FIXME: The proper sequence here will eventually be: - * - * drm_atomic_helper_commit_modeset_disables(dev, state); - * drm_atomic_helper_commit_planes(dev, state); - * drm_atomic_helper_commit_modeset_enables(dev, state); - * - * once we have full atomic modeset. - */ - drm_atomic_helper_commit_planes(dev, state); + /* FIXME: This function should eventually call __intel_set_mode when needed */ drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aec398cd2289f..b56641b6de707 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12902,10 +12902,10 @@ static int __intel_set_mode(struct drm_atomic_state *state) modeset_update_crtc_power_domains(state); - drm_atomic_helper_commit_planes(dev, state); - /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { + drm_atomic_helper_commit_planes_on_crtc(crtc_state); + if (!needs_modeset(crtc->state) || !crtc->state->active) continue; @@ -15267,6 +15267,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) struct intel_plane_state *plane_state; memset(crtc->config, 0, sizeof(*crtc->config)); + crtc->config->base.crtc = &crtc->base; crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; -- GitLab From c347a6768df15c7145ac16bf4b4f7c5fc2be1179 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:50:02 +0200 Subject: [PATCH 0081/7006] drm/i915: Move cdclk and pll setup to intel_modeset_compute_config(), v2. It makes more sense there, since these are computation steps that can fail. Changes since v1: - Rename __intel_set_mode_checks to intel_modeset_checks (Matt Roper) - Move intel_modeset_checks to before check_planes, so it won't have to be moved later. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 74 +++++++++++++--------------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b56641b6de707..12d6da8f0465a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12758,38 +12758,7 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static int -intel_modeset_compute_config(struct drm_atomic_state *state) -{ - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int ret, i; - - ret = drm_atomic_helper_check_modeset(state->dev, state); - if (ret) - return ret; - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->enable && - WARN_ON(crtc_state->active)) - crtc_state->active = false; - - if (!crtc_state->enable) - continue; - - ret = intel_modeset_pipe_config(crtc, state); - if (ret) - return ret; - - intel_dump_pipe_config(to_intel_crtc(crtc), - to_intel_crtc_state(crtc_state), - "[modeset]"); - } - - return drm_atomic_helper_check_planes(state->dev, state); -} - -static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) +static int intel_modeset_setup_plls(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = to_i915(dev); @@ -12839,7 +12808,7 @@ static int __intel_set_mode_setup_plls(struct drm_atomic_state *state) } /* Code that should eventually be part of atomic_check() */ -static int __intel_set_mode_checks(struct drm_atomic_state *state) +static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; int ret; @@ -12861,11 +12830,42 @@ static int __intel_set_mode_checks(struct drm_atomic_state *state) return ret; } - ret = __intel_set_mode_setup_plls(state); + return intel_modeset_setup_plls(state); +} + +static int +intel_modeset_compute_config(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret, i; + + ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) return ret; - return 0; + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->enable && + WARN_ON(crtc_state->active)) + crtc_state->active = false; + + if (!crtc_state->enable) + continue; + + ret = intel_modeset_pipe_config(crtc, state); + if (ret) + return ret; + + intel_dump_pipe_config(to_intel_crtc(crtc), + to_intel_crtc_state(crtc_state), + "[modeset]"); + } + + ret = intel_modeset_checks(state); + if (ret) + return ret; + + return drm_atomic_helper_check_planes(state->dev, state); } static int __intel_set_mode(struct drm_atomic_state *state) @@ -12877,10 +12877,6 @@ static int __intel_set_mode(struct drm_atomic_state *state) int ret = 0; int i; - ret = __intel_set_mode_checks(state); - if (ret < 0) - return ret; - ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; -- GitLab From 37ade41794e914103b8db417e480afd20dcea971 Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 1 Jun 2015 12:50:03 +0200 Subject: [PATCH 0082/7006] drm/i915: Read hw state into an atomic state struct, v2. To make this work we load the new hardware state into the atomic_state, then swap it with the sw state. This lets us change the force restore path in setup_hw_state() to use a single call to intel_mode_set() to restore all the previous state. As a nice bonus this kills off encoder->new_encoder, connector->new_enabled and crtc->new_enabled. They were used only to restore the state after a modeset. Changes since v1: - Make sure all possible planes are added with their crtc set, so they will be turned off on first modeset. Signed-off-by: Ander Conselvan de Oliveira Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 379 +++++++++++++++++---------- drivers/gpu/drm/i915/intel_drv.h | 14 +- 3 files changed, 243 insertions(+), 152 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 4df6d2d7a9c8e..e47e00e5b130a 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -395,7 +395,7 @@ int intel_atomic_setup_scalers(struct drm_device *dev, return 0; } -static void +void intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll_config *shared_dpll) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 12d6da8f0465a..c04bc80d1a651 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10312,7 +10312,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) - goto fail_unlock; + goto fail; /* * Algorithm gets a little messy: @@ -10330,10 +10330,10 @@ retry: ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -10352,9 +10352,6 @@ retry: continue; if (possible_crtc->state->enable) continue; - /* This can occur when applying the pipe A quirk on resume. */ - if (to_intel_crtc(possible_crtc)->new_enabled) - continue; crtc = possible_crtc; break; @@ -10365,20 +10362,17 @@ retry: */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - goto fail_unlock; + goto fail; } ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; - intel_encoder->new_crtc = to_intel_crtc(crtc); - to_intel_connector(connector)->new_encoder = intel_encoder; + goto fail; intel_crtc = to_intel_crtc(crtc); - intel_crtc->new_enabled = true; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -10446,9 +10440,7 @@ retry: intel_wait_for_vblank(dev, intel_crtc->pipe); return true; - fail: - intel_crtc->new_enabled = crtc->state->enable; -fail_unlock: +fail: drm_atomic_state_free(state); state = NULL; @@ -10494,10 +10486,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(crtc_state)) goto fail; - to_intel_connector(connector)->new_encoder = NULL; - intel_encoder->new_crtc = NULL; - intel_crtc->new_enabled = false; - connector_state->best_encoder = NULL; connector_state->crtc = NULL; @@ -11644,33 +11632,6 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .atomic_flush = intel_finish_crtc_commit, }; -/** - * intel_modeset_update_staged_output_state - * - * Updates the staged output configuration state, e.g. after we've read out the - * current hw state. - */ -static void intel_modeset_update_staged_output_state(struct drm_device *dev) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - - for_each_intel_connector(dev, connector) { - connector->new_encoder = - to_intel_encoder(connector->base.encoder); - } - - for_each_intel_encoder(dev, encoder) { - encoder->new_crtc = - to_intel_crtc(encoder->base.crtc); - } - - for_each_intel_crtc(dev, crtc) { - crtc->new_enabled = crtc->base.state->enable; - } -} - /* Transitional helper to copy current connector/encoder state to * connector->state. This is needed so that code that is partially * converted to atomic does the right thing. @@ -12201,7 +12162,6 @@ intel_modeset_update_state(struct drm_atomic_state *state) } drm_atomic_helper_update_legacy_modeset_state(state->dev, state); - intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc(dev, crtc) { @@ -12505,11 +12465,14 @@ check_connector_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { + struct drm_encoder *encoder = connector->base.encoder; + struct drm_connector_state *state = connector->base.state; + /* This also checks the encoder/connector hw state with the * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, + I915_STATE_WARN(state->best_encoder != encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -12529,8 +12492,6 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); - I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, - "encoder's stage crtc doesn't match current crtc\n"); I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); @@ -12540,6 +12501,9 @@ check_encoder_state(struct drm_device *dev) enabled = true; if (connector->base.dpms != DRM_MODE_DPMS_OFF) active = true; + + I915_STATE_WARN(connector->base.state->crtc != encoder->base.crtc, + "encoder's stage crtc doesn't match current crtc\n"); } /* * for MST connectors if we unplug the connector is gone @@ -12969,11 +12933,11 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) * need to copy the staged config to the atomic state, otherwise the * mode set will just reapply the state the HW is already in. */ for_each_intel_encoder(dev, encoder) { - if (&encoder->new_crtc->base != crtc) + if (encoder->base.crtc != crtc) continue; for_each_intel_connector(dev, connector) { - if (connector->new_encoder != encoder) + if (connector->base.state->best_encoder != &encoder->base) continue; connector_state = drm_atomic_get_connector_state(state, &connector->base); @@ -12986,14 +12950,10 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } connector_state->crtc = crtc; - connector_state->best_encoder = &encoder->base; } } for_each_intel_crtc(dev, intel_crtc) { - if (intel_crtc->new_enabled == intel_crtc->base.enabled) - continue; - crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) { DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", @@ -13002,9 +12962,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) continue; } - crtc_state->base.active = crtc_state->base.enable = - intel_crtc->new_enabled; - if (&intel_crtc->base == crtc) drm_mode_copy(&crtc_state->base.mode, &crtc->mode); } @@ -15080,6 +15037,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * ... */ plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; + crtc->base.primary->crtc = &crtc->base; crtc->plane = !plane; intel_crtc_control(&crtc->base, false); crtc->plane = plane; @@ -15243,99 +15201,225 @@ static bool primary_get_hw_state(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!crtc->active) + if (!crtc->base.enabled) return false; return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; } -static void intel_modeset_readout_hw_state(struct drm_device *dev) +static int readout_hw_crtc_state(struct drm_atomic_state *state, + struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - int i; + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_crtc_state *crtc_state; + struct drm_plane *primary = crtc->base.primary; + struct drm_plane_state *drm_plane_state; + struct intel_plane_state *plane_state; + int ret; - for_each_intel_crtc(dev, crtc) { - struct drm_plane *primary = crtc->base.primary; - struct intel_plane_state *plane_state; + crtc_state = intel_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); - memset(crtc->config, 0, sizeof(*crtc->config)); - crtc->config->base.crtc = &crtc->base; + ret = drm_atomic_add_affected_planes(state, &crtc->base); + if (ret) + return ret; - crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; + memset(crtc_state, 0, sizeof(*crtc_state)); + crtc_state->base.crtc = &crtc->base; + crtc_state->base.state = state; - crtc->active = dev_priv->display.get_pipe_config(crtc, - crtc->config); + crtc_state->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - crtc->base.state->enable = crtc->active; - crtc->base.state->active = crtc->active; - crtc->base.enabled = crtc->active; + crtc_state->base.enable = crtc_state->base.active = + crtc->base.enabled = dev_priv->display.get_pipe_config(crtc, crtc_state); - plane_state = to_intel_plane_state(primary->state); - plane_state->visible = primary_get_hw_state(crtc); + /* update transitional state */ + crtc->active = crtc_state->base.active; + crtc->config = crtc_state; - DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", - crtc->base.base.id, - crtc->active ? "enabled" : "disabled"); - } + drm_plane_state = drm_atomic_get_plane_state(state, primary); + if (IS_ERR(drm_plane_state)) + return PTR_ERR(drm_plane_state); + + plane_state = to_intel_plane_state(drm_plane_state); + plane_state->visible = primary_get_hw_state(crtc); + if (plane_state->visible) { + primary->crtc = &crtc->base; + crtc_state->base.plane_mask |= 1 << drm_plane_index(primary); + } else + crtc_state->base.plane_mask &= ~(1 << drm_plane_index(primary)); + + DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", + crtc->base.base.id, + crtc_state->base.active ? "enabled" : "disabled"); + + return 0; +} + +static int readout_hw_pll_state(struct drm_atomic_state *state) +{ + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_shared_dpll_config *shared_dpll; + struct intel_crtc *crtc; + struct intel_crtc_state *crtc_state; + int i; + + shared_dpll = intel_atomic_get_shared_dpll_state(state); for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; pll->on = pll->get_hw_state(dev_priv, pll, - &pll->config.hw_state); + &shared_dpll[i].hw_state); + pll->active = 0; - pll->config.crtc_mask = 0; - for_each_intel_crtc(dev, crtc) { - if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) { + shared_dpll[i].crtc_mask = 0; + + for_each_intel_crtc(state->dev, crtc) { + crtc_state = intel_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (crtc_state->base.active && + crtc_state->shared_dpll == i) { pll->active++; - pll->config.crtc_mask |= 1 << crtc->pipe; + shared_dpll[i].crtc_mask |= + 1 << crtc->pipe; } } DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->name, pll->config.crtc_mask, pll->on); + pll->name, shared_dpll[i].crtc_mask, + pll->on); - if (pll->config.crtc_mask) + if (shared_dpll[i].crtc_mask) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } - for_each_intel_encoder(dev, encoder) { - pipe = 0; + return 0; +} - if (encoder->get_hw_state(encoder, &pipe)) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - encoder->base.crtc = &crtc->base; - encoder->get_config(encoder, crtc->config); - } else { - encoder->base.crtc = NULL; - } +static struct drm_connector_state * +get_connector_state_for_encoder(struct drm_atomic_state *state, + struct intel_encoder *encoder) +{ + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; - encoder->connectors_active = false; - DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", - encoder->base.base.id, - encoder->base.name, - encoder->base.crtc ? "enabled" : "disabled", - pipe_name(pipe)); - } + for_each_connector_in_state(state, connector, connector_state, i) + if (connector_state->best_encoder == &encoder->base) + return connector_state; + + return NULL; +} + +static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = to_i915(state->dev); + struct intel_crtc *crtc; + struct drm_crtc_state *drm_crtc_state; + struct intel_crtc_state *crtc_state; + struct intel_encoder *encoder; + struct intel_connector *connector; + struct drm_connector_state *connector_state; + enum pipe pipe; for_each_intel_connector(dev, connector) { + connector_state = + drm_atomic_get_connector_state(state, &connector->base); + if (IS_ERR(connector_state)) + return PTR_ERR(connector_state); + if (connector->get_hw_state(connector)) { connector->base.dpms = DRM_MODE_DPMS_ON; - connector->encoder->connectors_active = true; connector->base.encoder = &connector->encoder->base; } else { connector->base.dpms = DRM_MODE_DPMS_OFF; connector->base.encoder = NULL; } + + /* We'll update the crtc field when reading encoder state */ + connector_state->crtc = NULL; + + connector_state->best_encoder = connector->base.encoder; + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", connector->base.base.id, connector->base.name, connector->base.encoder ? "enabled" : "disabled"); } + + for_each_intel_encoder(dev, encoder) { + pipe = 0; + + connector_state = + get_connector_state_for_encoder(state, encoder); + + encoder->connectors_active = !!connector_state; + + if (encoder->get_hw_state(encoder, &pipe)) { + encoder->base.crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + crtc = to_intel_crtc(encoder->base.crtc); + + drm_crtc_state = + state->crtc_states[drm_crtc_index(&crtc->base)]; + crtc_state = to_intel_crtc_state(drm_crtc_state); + + encoder->get_config(encoder, crtc_state); + + if (connector_state) + connector_state->crtc = &crtc->base; + } else { + encoder->base.crtc = NULL; + } + + DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", + encoder->base.base.id, + encoder->base.name, + encoder->base.crtc ? "enabled" : "disabled", + pipe_name(pipe)); + } + + return 0; +} + +static struct drm_atomic_state * +intel_modeset_readout_hw_state(struct drm_device *dev) +{ + struct intel_crtc *crtc; + int ret = 0; + + struct drm_atomic_state *state; + + state = drm_atomic_state_alloc(dev); + if (!state) + return ERR_PTR(-ENOMEM); + + state->acquire_ctx = dev->mode_config.acquire_ctx; + + for_each_intel_crtc(dev, crtc) { + ret = readout_hw_crtc_state(state, crtc); + if (ret) + goto err_free; + } + + ret = readout_hw_pll_state(state); + if (ret) + goto err_free; + + ret = readout_hw_connector_encoder_state(state); + if (ret) + goto err_free; + + return state; + +err_free: + drm_atomic_state_free(state); + return ERR_PTR(ret); } /* Scan out the current hw modeset state, sanitizes it and maps it into the drm @@ -15344,37 +15428,57 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore) { struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - struct intel_crtc *crtc; + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; struct intel_encoder *encoder; + struct drm_atomic_state *state; + struct intel_shared_dpll_config shared_dplls[I915_NUM_PLLS]; int i; - intel_modeset_readout_hw_state(dev); - - /* - * Now that we have the config, copy it to each CRTC struct - * Note that this could go away if we move to using crtc_config - * checking everywhere. - */ - for_each_intel_crtc(dev, crtc) { - if (crtc->active && i915.fastboot) { - intel_mode_from_pipe_config(&crtc->base.mode, - crtc->config); - DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", - crtc->base.base.id); - drm_mode_debug_printmodeline(&crtc->base.mode); - } + state = intel_modeset_readout_hw_state(dev); + if (IS_ERR(state)) { + DRM_ERROR("Failed to read out hw state\n"); + return; } + drm_atomic_helper_swap_state(dev, state); + + /* swap sw/hw dpll state */ + intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls); + intel_shared_dpll_commit(state); + memcpy(to_intel_atomic_state(state)->shared_dpll, + shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll); + /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); } - for_each_pipe(dev_priv, pipe) { - crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - intel_sanitize_crtc(crtc); - intel_dump_pipe_config(crtc, crtc->config, + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + + /* prevent unnneeded restores with force_restore */ + crtc_state->active_changed = + crtc_state->mode_changed = + crtc_state->planes_changed = false; + + if (crtc->enabled) { + intel_mode_from_pipe_config(&crtc->state->mode, + to_intel_crtc_state(crtc->state)); + + drm_mode_copy(&crtc->mode, &crtc->state->mode); + drm_mode_copy(&crtc->hwmode, + &crtc->state->adjusted_mode); + } + + intel_sanitize_crtc(intel_crtc); + + /* + * sanitize_crtc may have forced an update of crtc->state, + * so reload in intel_dump_pipe_config + */ + intel_dump_pipe_config(intel_crtc, + to_intel_crtc_state(crtc->state), "[setup_hw_state]"); } @@ -15398,20 +15502,17 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, ilk_wm_get_hw_state(dev); if (force_restore) { - i915_redisable_vga(dev); + int ret; - /* - * We need to use raw interfaces for restoring state to avoid - * checking (bogus) intermediate states. - */ - for_each_pipe(dev_priv, pipe) { - struct drm_crtc *crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; + i915_redisable_vga(dev); - intel_crtc_restore_mode(crtc); + ret = intel_set_mode(state); + if (ret) { + DRM_ERROR("Failed to restore previous mode\n"); + drm_atomic_state_free(state); } } else { - intel_modeset_update_staged_output_state(dev); + drm_atomic_state_free(state); } intel_modeset_check_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e15039800cf0e..4aa10a5198f6b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -130,11 +130,6 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; - /* - * The new crtc this encoder will be driven from. Only differs from - * base->crtc while a modeset is in progress. - */ - struct intel_crtc *new_crtc; enum intel_output_type type; unsigned int cloneable; @@ -195,12 +190,6 @@ struct intel_connector { */ struct intel_encoder *encoder; - /* - * The new encoder this connector will be driven. Only differs from - * encoder while a modeset is in progress. - */ - struct intel_encoder *new_encoder; - /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); @@ -535,7 +524,6 @@ struct intel_crtc { struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; - bool new_enabled; /* reset counter value when the last flip was submitted */ unsigned int reset_counter; @@ -1416,6 +1404,8 @@ struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); void intel_atomic_state_clear(struct drm_atomic_state *); struct intel_shared_dpll_config * intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s); +void intel_atomic_duplicate_dpll_state(struct drm_i915_private *, + struct intel_shared_dpll_config *); static inline struct intel_crtc_state * intel_atomic_get_crtc_state(struct drm_atomic_state *state, -- GitLab From 5da76e94c4b8d40465a907fc3a151051e8021cdc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:04 +0200 Subject: [PATCH 0083/7006] drm/i915: Implement intel_crtc_control using atomic state, v4 Assume the callers lock everything with drm_modeset_lock_all. This change had to be done after converting suspend/resume to use atomic_state so the atomic state is preserved, otherwise all transitional state is erased. Now all callers of .crtc_enable and .crtc_disable go through atomic modeset! :-D Changes since v1: - Only check for crtc_state->active in valleyview_modeset_global_pipes. - Only check for crtc_state->active in modeset_update_crtc_power_domains. Changes since v2: - Rework on top of the changed patch order. Changes since v3: - Rename intel_crtc_toggle in description to *_control - Change return value to int. - Do not add plane state, should be done implicitly already. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 53 +++++++++++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c04bc80d1a651..048a86857d0d1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6238,38 +6238,49 @@ void intel_display_suspend(struct drm_device *dev) } /* Master function to enable/disable CRTC and corresponding power wells */ -void intel_crtc_control(struct drm_crtc *crtc, bool enable) +int intel_crtc_control(struct drm_crtc *crtc, bool enable) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum intel_display_power_domain domain; - unsigned long domains; + struct intel_crtc_state *pipe_config; + struct drm_atomic_state *state; + int ret; if (enable == intel_crtc->active) - return; + return 0; if (enable && !crtc->state->enable) - return; + return 0; - crtc->state->active = enable; - if (enable) { - domains = get_crtc_power_domains(crtc); - for_each_power_domain(domain, domains) - intel_display_power_get(dev_priv, domain); - intel_crtc->enabled_power_domains = domains; + /* this function should be called with drm_modeset_lock_all for now */ + if (WARN_ON(!ctx)) + return -EIO; + lockdep_assert_held(&ctx->ww_ctx); - dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); - } else { - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); + state = drm_atomic_state_alloc(dev); + if (WARN_ON(!state)) + return -ENOMEM; - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; + state->acquire_ctx = ctx; + state->allow_modeset = true; + + pipe_config = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(pipe_config)) { + ret = PTR_ERR(pipe_config); + goto err; } + pipe_config->base.active = enable; + + ret = intel_set_mode(state); + if (!ret) + return ret; + +err: + DRM_ERROR("Updating crtc active failed with %i\n", ret); + drm_atomic_state_free(state); + return ret; } /** diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 4aa10a5198f6b..7f8fa7f026aa3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -990,7 +990,7 @@ void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); void intel_display_suspend(struct drm_device *dev); -void intel_crtc_control(struct drm_crtc *crtc, bool enable); +int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); -- GitLab From 06ea0b0897db906c5616f660a34b54d92f7d09cf Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:05 +0200 Subject: [PATCH 0084/7006] drm/i915: Make intel_display_suspend atomic, v2. Calculate all state using a normal transition, but afterwards fudge crtc->state->active back to its old value. This should still allow state restore in setup_hw_state to work properly. Calling intel_set_mode will cause intel_display_set_init_power to be called, make sure init_power gets set again afterwards. Changes since v1: - Fix to compile with v2 of the patch that adds intel_display_suspend. - Add intel_display_set_init_power. - Set return value to int to allow error checking. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 3 ++ drivers/gpu/drm/i915/intel_display.c | 55 ++++++++++++++++++++++------ drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 47 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 78ef0bb53c36a..d3632c56fdf74 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -634,6 +634,9 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_suspend(dev); drm_modeset_unlock_all(dev); + /* suspending displays will unsets init power */ + intel_display_set_init_power(dev_priv, true); + intel_dp_mst_suspend(dev); intel_runtime_pm_disable_interrupts(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 048a86857d0d1..547d6db2a6ee0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6214,27 +6214,58 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -void intel_display_suspend(struct drm_device *dev) +int intel_display_suspend(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(dev); + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; + struct drm_atomic_state *state; struct drm_crtc *crtc; + unsigned crtc_mask = 0; + int ret = 0; + + if (WARN_ON(!ctx)) + return 0; + + lockdep_assert_held(&ctx->ww_ctx); + state = drm_atomic_state_alloc(dev); + if (WARN_ON(!state)) + return -ENOMEM; + + state->acquire_ctx = ctx; + state->allow_modeset = true; for_each_crtc(dev, crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum intel_display_power_domain domain; - unsigned long domains; + struct drm_crtc_state *crtc_state = + drm_atomic_get_crtc_state(state, crtc); - if (!intel_crtc->active) + ret = PTR_ERR_OR_ZERO(crtc_state); + if (ret) + goto free; + + if (!crtc_state->active) continue; - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); + crtc_state->active = false; + crtc_mask |= 1 << drm_crtc_index(crtc); + } - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; + if (crtc_mask) { + ret = intel_set_mode(state); + + if (!ret) { + for_each_crtc(dev, crtc) + if (crtc_mask & (1 << drm_crtc_index(crtc))) + crtc->state->active = true; + + return ret; + } } + +free: + if (ret) + DRM_ERROR("Suspending crtc's failed with %i\n", ret); + drm_atomic_state_free(state); + return ret; } /* Master function to enable/disable CRTC and corresponding power wells */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7f8fa7f026aa3..6d9c771747f9e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -989,7 +989,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); -void intel_display_suspend(struct drm_device *dev); +int intel_display_suspend(struct drm_device *dev); int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); -- GitLab From 1c5e19f8f124b2ff442756e79d9a05c2b9494a28 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:06 +0200 Subject: [PATCH 0085/7006] drm/i915: move swap state to the right place This is a preparation for passing crtc state to the helpers. When converting all users of crtc->config to use the old or new state it's easier to find regressions when swap_state is done first. If crtc->config is swapped at the same place as swap_state bugs will never be found. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 547d6db2a6ee0..d4d7708b58a43 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12189,7 +12189,6 @@ intel_modeset_update_state(struct drm_atomic_state *state) struct drm_connector *connector; intel_shared_dpll_commit(state); - drm_atomic_helper_swap_state(state->dev, state); for_each_intel_encoder(dev, intel_encoder) { if (!intel_encoder->base.crtc) @@ -12887,8 +12886,10 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (ret) return ret; + drm_atomic_helper_swap_state(dev, state); + for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state) || !crtc->state->active) + if (!needs_modeset(crtc->state) || !crtc_state->active) continue; intel_crtc_disable_planes(crtc); -- GitLab From fc467a221a01c5ec369a3969fcafea077c3677b4 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:07 +0200 Subject: [PATCH 0086/7006] drm/i915: Use crtc->hwmode for vblanks, v2. intel_crtc->config will be removed eventually, so use crtc->hwmode. drm_atomic_helper_update_legacy_modeset_state updates hwmode, but crtc->active will eventually be gone too. Set dotclock to zero to indicate the crtc is inactive. Changes since v1: - With the hwmode update in drm*update_legacy_modeset_state removed, intel_modeset_update_state has to assign it instead. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 13 ++++++------- drivers/gpu/drm/i915/intel_display.c | 6 ++++++ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index dadd586f05277..56db9e7474646 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -564,8 +564,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe) u32 high1, high2, low, pixel, vbl_start, hsync_start, htotal; struct intel_crtc *intel_crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); - const struct drm_display_mode *mode = - &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *mode = &intel_crtc->base.hwmode; htotal = mode->crtc_htotal; hsync_start = mode->crtc_hsync_start; @@ -620,7 +619,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; + const struct drm_display_mode *mode = &crtc->base.hwmode; enum pipe pipe = crtc->pipe; int position, vtotal; @@ -647,14 +646,14 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe, struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe]; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - const struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode; + const struct drm_display_mode *mode = &intel_crtc->base.hwmode; int position; int vbl_start, vbl_end, hsync_start, htotal, vtotal; bool in_vbl = true; int ret = 0; unsigned long irqflags; - if (!intel_crtc->active) { + if (WARN_ON(!mode->crtc_clock)) { DRM_DEBUG_DRIVER("trying to get scanoutpos for disabled " "pipe %c\n", pipe_name(pipe)); return 0; @@ -796,7 +795,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, return -EINVAL; } - if (!crtc->state->active) { + if (!crtc->hwmode.crtc_clock) { DRM_DEBUG_KMS("crtc %d is disabled\n", pipe); return -EBUSY; } @@ -805,7 +804,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error, vblank_time, flags, crtc, - &to_intel_crtc(crtc)->config->base.adjusted_mode); + &crtc->hwmode); } static bool intel_hpd_irq_event(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d4d7708b58a43..7e2bbd7e62109 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12209,6 +12209,12 @@ intel_modeset_update_state(struct drm_atomic_state *state) WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); + + /* Update hwmode for vblank functions */ + if (crtc->state->active) + crtc->hwmode = crtc->state->adjusted_mode; + else + crtc->hwmode.crtc_clock = 0; } list_for_each_entry(connector, &dev->mode_config.connector_list, head) { -- GitLab From f77076c91d563a07c6519b80e234b4e962306b67 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:08 +0200 Subject: [PATCH 0087/7006] drm/i915: Remove use of crtc->config from i915_debugfs.c crtc->config is updated to always contain to the active crtc_state and only differs from crtc_state during crtc_disable. It will eventually be removed, so start with some low hanging fruit. For crtc->active the situation is the same; it will be removed eventually. Instead use crtc->state->active. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 42 ++++++++++++++++++----------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index aac252ca0bda3..0029c25bf72a8 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2779,13 +2779,16 @@ static int i915_display_info(struct seq_file *m, void *unused) seq_printf(m, "---------\n"); for_each_intel_crtc(dev, crtc) { bool active; + struct intel_crtc_state *pipe_config; int x, y; + pipe_config = to_intel_crtc_state(crtc->base.state); + seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n", crtc->base.base.id, pipe_name(crtc->pipe), - yesno(crtc->active), crtc->config->pipe_src_w, - crtc->config->pipe_src_h); - if (crtc->active) { + yesno(pipe_config->base.active), + pipe_config->pipe_src_w, pipe_config->pipe_src_h); + if (pipe_config->base.active) { intel_crtc_info(m, crtc); active = cursor_position(dev, crtc->pipe, &x, &y); @@ -3026,7 +3029,7 @@ static void drrs_status_per_crtc(struct seq_file *m, seq_puts(m, "\n\n"); - if (intel_crtc->config->has_drrs) { + if (to_intel_crtc_state(intel_crtc->base.state)->has_drrs) { struct intel_panel *panel; mutex_lock(&drrs->mutex); @@ -3078,7 +3081,7 @@ static int i915_drrs_status(struct seq_file *m, void *unused) for_each_intel_crtc(dev, intel_crtc) { drm_modeset_lock(&intel_crtc->base.mutex, NULL); - if (intel_crtc->active) { + if (intel_crtc->base.state->active) { active_crtc_cnt++; seq_printf(m, "\nCRTC %d: ", active_crtc_cnt); @@ -3620,22 +3623,27 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]); + struct intel_crtc_state *pipe_config; drm_modeset_lock_all(dev); + pipe_config = to_intel_crtc_state(crtc->base.state); + /* * If we use the eDP transcoder we need to make sure that we don't * bypass the pfit, since otherwise the pipe CRC source won't work. Only * relevant on hsw with pipe A when using the always-on power well * routing. */ - if (crtc->config->cpu_transcoder == TRANSCODER_EDP && - !crtc->config->pch_pfit.enabled) { - bool active = crtc->active; + if (pipe_config->cpu_transcoder == TRANSCODER_EDP && + !pipe_config->pch_pfit.enabled) { + bool active = pipe_config->base.active; - if (active) + if (active) { intel_crtc_control(&crtc->base, false); + pipe_config = to_intel_crtc_state(crtc->base.state); + } - crtc->config->pch_pfit.force_thru = true; + pipe_config->pch_pfit.force_thru = true; intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); @@ -3651,6 +3659,7 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_A]); + struct intel_crtc_state *pipe_config; drm_modeset_lock_all(dev); /* @@ -3659,13 +3668,16 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev) * relevant on hsw with pipe A when using the always-on power well * routing. */ - if (crtc->config->pch_pfit.force_thru) { - bool active = crtc->active; + pipe_config = to_intel_crtc_state(crtc->base.state); + if (pipe_config->pch_pfit.force_thru) { + bool active = pipe_config->base.active; - if (active) + if (active) { intel_crtc_control(&crtc->base, false); + pipe_config = to_intel_crtc_state(crtc->base.state); + } - crtc->config->pch_pfit.force_thru = false; + pipe_config->pch_pfit.force_thru = false; intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A)); @@ -3787,7 +3799,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe, pipe_name(pipe)); drm_modeset_lock(&crtc->base.mutex, NULL); - if (crtc->active) + if (crtc->base.state->active) intel_wait_for_vblank(dev, pipe); drm_modeset_unlock(&crtc->base.mutex); -- GitLab From 99d736a2ce431dbbcf96ee9d26bd41ca2c2284a1 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:09 +0200 Subject: [PATCH 0088/7006] drm/i915: Calculate haswell plane workaround, v5. This needs to be done last after all modesets have been calculated. A modeset first disables all crtc's, so any crtc that undergoes a modeset counts as inactive. If no modeset's done, or > 1 crtc's stay w/a doesn't apply. Apply workaround on the first crtc if 1 crtc stays active. Apply workaround on the second crtc if no crtc was active. Changes since v1: - Use intel_crtc->atomic as a place to put hsw_workaround_pipe. - Make sure quirk only applies to haswell. - Use first loop to iterate over newly enabled crtc's only. This increases readability. Changes since v2: - Move hsw_workaround_pipe back to crtc_state. Changes since v3: - Return errors from haswell_mode_set_planes_workaround. Changes since v4: - Clean up commit message. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 113 +++++++++++++++++++-------- drivers/gpu/drm/i915/intel_drv.h | 3 + 2 files changed, 84 insertions(+), 32 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7e2bbd7e62109..cd9a7545b0d3b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4864,42 +4864,15 @@ static bool hsw_crtc_supports_ips(struct intel_crtc *crtc) return HAS_IPS(crtc->base.dev) && crtc->pipe == PIPE_A; } -/* - * This implements the workaround described in the "notes" section of the mode - * set sequence documentation. When going from no pipes or single pipe to - * multiple pipes, and planes are enabled after the pipe, we need to wait at - * least 2 vblanks on the first pipe before enabling planes on the second pipe. - */ -static void haswell_mode_set_planes_workaround(struct intel_crtc *crtc) -{ - struct drm_device *dev = crtc->base.dev; - struct intel_crtc *crtc_it, *other_active_crtc = NULL; - - /* We want to get the other_active_crtc only if there's only 1 other - * active crtc. */ - for_each_intel_crtc(dev, crtc_it) { - if (!crtc_it->active || crtc_it == crtc) - continue; - - if (other_active_crtc) - return; - - other_active_crtc = crtc_it; - } - if (!other_active_crtc) - return; - - intel_wait_for_vblank(dev, other_active_crtc->pipe); - intel_wait_for_vblank(dev, other_active_crtc->pipe); -} - static void haswell_crtc_enable(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_encoder *encoder; - int pipe = intel_crtc->pipe; + int pipe = intel_crtc->pipe, hsw_workaround_pipe; + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc->state); if (WARN_ON(intel_crtc->active)) return; @@ -4976,7 +4949,11 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) /* If we change the relative order between pipe/planes enabling, we need * to change the workaround. */ - haswell_mode_set_planes_workaround(intel_crtc); + hsw_workaround_pipe = pipe_config->hsw_workaround_pipe; + if (IS_HASWELL(dev) && hsw_workaround_pipe != INVALID_PIPE) { + intel_wait_for_vblank(dev, hsw_workaround_pipe); + intel_wait_for_vblank(dev, hsw_workaround_pipe); + } } static void ironlake_pfit_disable(struct intel_crtc *crtc) @@ -12818,6 +12795,71 @@ static int intel_modeset_setup_plls(struct drm_atomic_state *state) return ret; } +/* + * This implements the workaround described in the "notes" section of the mode + * set sequence documentation. When going from no pipes or single pipe to + * multiple pipes, and planes are enabled after the pipe, we need to wait at + * least 2 vblanks on the first pipe before enabling planes on the second pipe. + */ +static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state; + struct intel_crtc *intel_crtc; + struct drm_crtc *crtc; + struct intel_crtc_state *first_crtc_state = NULL; + struct intel_crtc_state *other_crtc_state = NULL; + enum pipe first_pipe = INVALID_PIPE, enabled_pipe = INVALID_PIPE; + int i; + + /* look at all crtc's that are going to be enabled in during modeset */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + intel_crtc = to_intel_crtc(crtc); + + if (!crtc_state->active || !needs_modeset(crtc_state)) + continue; + + if (first_crtc_state) { + other_crtc_state = to_intel_crtc_state(crtc_state); + break; + } else { + first_crtc_state = to_intel_crtc_state(crtc_state); + first_pipe = intel_crtc->pipe; + } + } + + /* No workaround needed? */ + if (!first_crtc_state) + return 0; + + /* w/a possibly needed, check how many crtc's are already enabled. */ + for_each_intel_crtc(state->dev, intel_crtc) { + struct intel_crtc_state *pipe_config; + + pipe_config = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(pipe_config)) + return PTR_ERR(pipe_config); + + pipe_config->hsw_workaround_pipe = INVALID_PIPE; + + if (!pipe_config->base.active || + needs_modeset(&pipe_config->base)) + continue; + + /* 2 or more enabled crtcs means no need for w/a */ + if (enabled_pipe != INVALID_PIPE) + return 0; + + enabled_pipe = intel_crtc->pipe; + } + + if (enabled_pipe != INVALID_PIPE) + first_crtc_state->hsw_workaround_pipe = enabled_pipe; + else if (other_crtc_state) + other_crtc_state->hsw_workaround_pipe = first_pipe; + + return 0; +} + /* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { @@ -12841,7 +12883,14 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return ret; } - return intel_modeset_setup_plls(state); + ret = intel_modeset_setup_plls(state); + if (ret) + return ret; + + if (IS_HASWELL(dev)) + ret = haswell_mode_set_planes_workaround(state); + + return ret; } static int diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 6d9c771747f9e..5312160e7c951 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -443,6 +443,9 @@ struct intel_crtc_state { int pbn; struct intel_crtc_scaler_state scaler_state; + + /* w/a for waiting 2 vblanks during crtc enable */ + enum pipe hsw_workaround_pipe; }; struct intel_pipe_wm { -- GitLab From 3538b9dffd8344cd40413018bcd7dc7b2bc1e21d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:10 +0200 Subject: [PATCH 0089/7006] drm/i915: Use atomic state for calculating DVO_2X_MODE on i830. This is a small behavioral change because it leaves DVO_2X_MODE set between crtc_disable and crtc_enable. This is probably harmless though and if not should be fixed by calculating 2x mode before enable/disable pll. This is needed because intel_crtc->active will be removed eventually. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cd9a7545b0d3b..28fc3efa95eda 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1698,7 +1698,7 @@ static int intel_num_dvo_pipes(struct drm_device *dev) int count = 0; for_each_intel_crtc(dev, crtc) - count += crtc->active && + count += crtc->base.state->active && intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO); return count; @@ -1779,7 +1779,7 @@ static void i9xx_disable_pll(struct intel_crtc *crtc) /* Disable DVO 2x clock on both PLLs if necessary */ if (IS_I830(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_DVO) && - intel_num_dvo_pipes(dev) == 1) { + !intel_num_dvo_pipes(dev)) { I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) & ~DPLL_DVO_2X_MODE); I915_WRITE(DPLL(PIPE_A), -- GitLab From 5c2db1882ab32546c46318d9feb017673c072717 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 1 Jun 2015 12:50:11 +0200 Subject: [PATCH 0090/7006] drm/i915: use calculated state for vblank evasion crtc->active will be gone eventually, and this check should be just as good. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 28fc3efa95eda..a232dc9f51f62 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13658,6 +13658,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_crtc_state *crtc_state = intel_crtc->base.state; struct intel_plane *intel_plane; struct drm_plane *p; unsigned fb_bits = 0; @@ -13701,7 +13702,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_get(dev_priv); /* Perform vblank evasion around commit operation */ - if (intel_crtc->active) + if (crtc_state->active && !needs_modeset(crtc_state)) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); -- GitLab From 9716c691ce06b043d3e75c8ff93704cb40c52265 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 10 Jun 2015 10:24:19 +0200 Subject: [PATCH 0091/7006] Revert "drm/i915: Make intel_display_suspend atomic, v2." This reverts commit 490f400db5d886fc28566af69b02f6497f31be4b. We're not ready yet to make it atomic, we calculate some state in advance, but without atomic plane support atomic the hw readout will fail. It's required to revert this commit to revert the atomic hw state readout patch. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90868 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90861 Signed-off-by: Maarten Lankhorst Acked-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 3 -- drivers/gpu/drm/i915/intel_display.c | 55 ++++++---------------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 3 files changed, 13 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index d3632c56fdf74..78ef0bb53c36a 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -634,9 +634,6 @@ static int i915_drm_suspend(struct drm_device *dev) intel_display_suspend(dev); drm_modeset_unlock_all(dev); - /* suspending displays will unsets init power */ - intel_display_set_init_power(dev_priv, true); - intel_dp_mst_suspend(dev); intel_runtime_pm_disable_interrupts(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a232dc9f51f62..cc7fad9905b9a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6191,58 +6191,27 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -int intel_display_suspend(struct drm_device *dev) +void intel_display_suspend(struct drm_device *dev) { - struct drm_mode_config *config = &dev->mode_config; - struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; - struct drm_atomic_state *state; + struct drm_i915_private *dev_priv = to_i915(dev); struct drm_crtc *crtc; - unsigned crtc_mask = 0; - int ret = 0; - - if (WARN_ON(!ctx)) - return 0; - - lockdep_assert_held(&ctx->ww_ctx); - state = drm_atomic_state_alloc(dev); - if (WARN_ON(!state)) - return -ENOMEM; - - state->acquire_ctx = ctx; - state->allow_modeset = true; for_each_crtc(dev, crtc) { - struct drm_crtc_state *crtc_state = - drm_atomic_get_crtc_state(state, crtc); - - ret = PTR_ERR_OR_ZERO(crtc_state); - if (ret) - goto free; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum intel_display_power_domain domain; + unsigned long domains; - if (!crtc_state->active) + if (!intel_crtc->active) continue; - crtc_state->active = false; - crtc_mask |= 1 << drm_crtc_index(crtc); - } - - if (crtc_mask) { - ret = intel_set_mode(state); - - if (!ret) { - for_each_crtc(dev, crtc) - if (crtc_mask & (1 << drm_crtc_index(crtc))) - crtc->state->active = true; + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); - return ret; - } + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; } - -free: - if (ret) - DRM_ERROR("Suspending crtc's failed with %i\n", ret); - drm_atomic_state_free(state); - return ret; } /* Master function to enable/disable CRTC and corresponding power wells */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 5312160e7c951..9ca683ae2dec9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -992,7 +992,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); -int intel_display_suspend(struct drm_device *dev); +void intel_display_suspend(struct drm_device *dev); int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); -- GitLab From f721790560be9551c9e7f1644e04960b3ac44d06 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 10 Jun 2015 10:24:20 +0200 Subject: [PATCH 0092/7006] Revert "drm/i915: Read hw state into an atomic state struct, v2." This reverts commit 3bae26eb2991c00670df377cf6c3bc2b0577e82a. Seems it introduces regressions for 3 different reasons, oh boy.. In bug #90868 as I can see the atomic state will be restored on resume without the planes being set up properly. Because plane setup here requires the atomic state, we'll have to settle for committing atomic planes first. In bug #90861 the failure appears to affect mostly DP devices, and happens because reading out the atomic state prevents a modeset on boot, which would require better hw state readout. In bug #90874 it's shown that cdclk should be part of the atomic state, so only performing a single modeset during resume excarbated the issue. It's better to fix those issues first, and then commit this patch, so do that temporarily. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90868 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90861 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90874 Signed-off-by: Maarten Lankhorst Acked-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_atomic.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 379 ++++++++++----------------- drivers/gpu/drm/i915/intel_drv.h | 14 +- 3 files changed, 152 insertions(+), 243 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index e47e00e5b130a..4df6d2d7a9c8e 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -395,7 +395,7 @@ int intel_atomic_setup_scalers(struct drm_device *dev, return 0; } -void +static void intel_atomic_duplicate_dpll_state(struct drm_i915_private *dev_priv, struct intel_shared_dpll_config *shared_dpll) { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cc7fad9905b9a..5cc2263db199d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10300,7 +10300,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) - goto fail; + goto fail_unlock; /* * Algorithm gets a little messy: @@ -10318,10 +10318,10 @@ retry: ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -10340,6 +10340,9 @@ retry: continue; if (possible_crtc->state->enable) continue; + /* This can occur when applying the pipe A quirk on resume. */ + if (to_intel_crtc(possible_crtc)->new_enabled) + continue; crtc = possible_crtc; break; @@ -10350,17 +10353,20 @@ retry: */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - goto fail; + goto fail_unlock; } ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail; + goto fail_unlock; + intel_encoder->new_crtc = to_intel_crtc(crtc); + to_intel_connector(connector)->new_encoder = intel_encoder; intel_crtc = to_intel_crtc(crtc); + intel_crtc->new_enabled = true; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -10428,7 +10434,9 @@ retry: intel_wait_for_vblank(dev, intel_crtc->pipe); return true; -fail: + fail: + intel_crtc->new_enabled = crtc->state->enable; +fail_unlock: drm_atomic_state_free(state); state = NULL; @@ -10474,6 +10482,10 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(crtc_state)) goto fail; + to_intel_connector(connector)->new_encoder = NULL; + intel_encoder->new_crtc = NULL; + intel_crtc->new_enabled = false; + connector_state->best_encoder = NULL; connector_state->crtc = NULL; @@ -11620,6 +11632,33 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .atomic_flush = intel_finish_crtc_commit, }; +/** + * intel_modeset_update_staged_output_state + * + * Updates the staged output configuration state, e.g. after we've read out the + * current hw state. + */ +static void intel_modeset_update_staged_output_state(struct drm_device *dev) +{ + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + + for_each_intel_connector(dev, connector) { + connector->new_encoder = + to_intel_encoder(connector->base.encoder); + } + + for_each_intel_encoder(dev, encoder) { + encoder->new_crtc = + to_intel_crtc(encoder->base.crtc); + } + + for_each_intel_crtc(dev, crtc) { + crtc->new_enabled = crtc->base.state->enable; + } +} + /* Transitional helper to copy current connector/encoder state to * connector->state. This is needed so that code that is partially * converted to atomic does the right thing. @@ -12149,6 +12188,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) } drm_atomic_helper_update_legacy_modeset_state(state->dev, state); + intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc(dev, crtc) { @@ -12458,14 +12498,11 @@ check_connector_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { - struct drm_encoder *encoder = connector->base.encoder; - struct drm_connector_state *state = connector->base.state; - /* This also checks the encoder/connector hw state with the * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - I915_STATE_WARN(state->best_encoder != encoder, + I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -12485,6 +12522,8 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); + I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, + "encoder's stage crtc doesn't match current crtc\n"); I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); @@ -12494,9 +12533,6 @@ check_encoder_state(struct drm_device *dev) enabled = true; if (connector->base.dpms != DRM_MODE_DPMS_OFF) active = true; - - I915_STATE_WARN(connector->base.state->crtc != encoder->base.crtc, - "encoder's stage crtc doesn't match current crtc\n"); } /* * for MST connectors if we unplug the connector is gone @@ -13000,11 +13036,11 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) * need to copy the staged config to the atomic state, otherwise the * mode set will just reapply the state the HW is already in. */ for_each_intel_encoder(dev, encoder) { - if (encoder->base.crtc != crtc) + if (&encoder->new_crtc->base != crtc) continue; for_each_intel_connector(dev, connector) { - if (connector->base.state->best_encoder != &encoder->base) + if (connector->new_encoder != encoder) continue; connector_state = drm_atomic_get_connector_state(state, &connector->base); @@ -13017,10 +13053,14 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } connector_state->crtc = crtc; + connector_state->best_encoder = &encoder->base; } } for_each_intel_crtc(dev, intel_crtc) { + if (intel_crtc->new_enabled == intel_crtc->base.enabled) + continue; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) { DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", @@ -13029,6 +13069,9 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) continue; } + crtc_state->base.active = crtc_state->base.enable = + intel_crtc->new_enabled; + if (&intel_crtc->base == crtc) drm_mode_copy(&crtc_state->base.mode, &crtc->mode); } @@ -15105,7 +15148,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * ... */ plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; - crtc->base.primary->crtc = &crtc->base; crtc->plane = !plane; intel_crtc_control(&crtc->base, false); crtc->plane = plane; @@ -15269,182 +15311,78 @@ static bool primary_get_hw_state(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!crtc->base.enabled) + if (!crtc->active) return false; return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; } -static int readout_hw_crtc_state(struct drm_atomic_state *state, - struct intel_crtc *crtc) +static void intel_modeset_readout_hw_state(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_crtc_state *crtc_state; - struct drm_plane *primary = crtc->base.primary; - struct drm_plane_state *drm_plane_state; - struct intel_plane_state *plane_state; - int ret; - - crtc_state = intel_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - ret = drm_atomic_add_affected_planes(state, &crtc->base); - if (ret) - return ret; - - memset(crtc_state, 0, sizeof(*crtc_state)); - crtc_state->base.crtc = &crtc->base; - crtc_state->base.state = state; - - crtc_state->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - - crtc_state->base.enable = crtc_state->base.active = - crtc->base.enabled = dev_priv->display.get_pipe_config(crtc, crtc_state); + struct drm_i915_private *dev_priv = dev->dev_private; + enum pipe pipe; + struct intel_crtc *crtc; + struct intel_encoder *encoder; + struct intel_connector *connector; + int i; - /* update transitional state */ - crtc->active = crtc_state->base.active; - crtc->config = crtc_state; + for_each_intel_crtc(dev, crtc) { + struct drm_plane *primary = crtc->base.primary; + struct intel_plane_state *plane_state; - drm_plane_state = drm_atomic_get_plane_state(state, primary); - if (IS_ERR(drm_plane_state)) - return PTR_ERR(drm_plane_state); + memset(crtc->config, 0, sizeof(*crtc->config)); + crtc->config->base.crtc = &crtc->base; - plane_state = to_intel_plane_state(drm_plane_state); - plane_state->visible = primary_get_hw_state(crtc); + crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - if (plane_state->visible) { - primary->crtc = &crtc->base; - crtc_state->base.plane_mask |= 1 << drm_plane_index(primary); - } else - crtc_state->base.plane_mask &= ~(1 << drm_plane_index(primary)); + crtc->active = dev_priv->display.get_pipe_config(crtc, + crtc->config); - DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", - crtc->base.base.id, - crtc_state->base.active ? "enabled" : "disabled"); + crtc->base.state->enable = crtc->active; + crtc->base.state->active = crtc->active; + crtc->base.enabled = crtc->active; - return 0; -} + plane_state = to_intel_plane_state(primary->state); + plane_state->visible = primary_get_hw_state(crtc); -static int readout_hw_pll_state(struct drm_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_shared_dpll_config *shared_dpll; - struct intel_crtc *crtc; - struct intel_crtc_state *crtc_state; - int i; + DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", + crtc->base.base.id, + crtc->active ? "enabled" : "disabled"); + } - shared_dpll = intel_atomic_get_shared_dpll_state(state); for (i = 0; i < dev_priv->num_shared_dpll; i++) { struct intel_shared_dpll *pll = &dev_priv->shared_dplls[i]; pll->on = pll->get_hw_state(dev_priv, pll, - &shared_dpll[i].hw_state); - + &pll->config.hw_state); pll->active = 0; - shared_dpll[i].crtc_mask = 0; - - for_each_intel_crtc(state->dev, crtc) { - crtc_state = intel_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - if (crtc_state->base.active && - crtc_state->shared_dpll == i) { + pll->config.crtc_mask = 0; + for_each_intel_crtc(dev, crtc) { + if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll) { pll->active++; - shared_dpll[i].crtc_mask |= - 1 << crtc->pipe; + pll->config.crtc_mask |= 1 << crtc->pipe; } } DRM_DEBUG_KMS("%s hw state readout: crtc_mask 0x%08x, on %i\n", - pll->name, shared_dpll[i].crtc_mask, - pll->on); + pll->name, pll->config.crtc_mask, pll->on); - if (shared_dpll[i].crtc_mask) + if (pll->config.crtc_mask) intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); } - return 0; -} - -static struct drm_connector_state * -get_connector_state_for_encoder(struct drm_atomic_state *state, - struct intel_encoder *encoder) -{ - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) - if (connector_state->best_encoder == &encoder->base) - return connector_state; - - return NULL; -} - -static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct intel_crtc *crtc; - struct drm_crtc_state *drm_crtc_state; - struct intel_crtc_state *crtc_state; - struct intel_encoder *encoder; - struct intel_connector *connector; - struct drm_connector_state *connector_state; - enum pipe pipe; - - for_each_intel_connector(dev, connector) { - connector_state = - drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) - return PTR_ERR(connector_state); - - if (connector->get_hw_state(connector)) { - connector->base.dpms = DRM_MODE_DPMS_ON; - connector->base.encoder = &connector->encoder->base; - } else { - connector->base.dpms = DRM_MODE_DPMS_OFF; - connector->base.encoder = NULL; - } - - /* We'll update the crtc field when reading encoder state */ - connector_state->crtc = NULL; - - connector_state->best_encoder = connector->base.encoder; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", - connector->base.base.id, - connector->base.name, - connector->base.encoder ? "enabled" : "disabled"); - } - for_each_intel_encoder(dev, encoder) { pipe = 0; - connector_state = - get_connector_state_for_encoder(state, encoder); - - encoder->connectors_active = !!connector_state; - if (encoder->get_hw_state(encoder, &pipe)) { - encoder->base.crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; - crtc = to_intel_crtc(encoder->base.crtc); - - drm_crtc_state = - state->crtc_states[drm_crtc_index(&crtc->base)]; - crtc_state = to_intel_crtc_state(drm_crtc_state); - - encoder->get_config(encoder, crtc_state); - - if (connector_state) - connector_state->crtc = &crtc->base; + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + encoder->base.crtc = &crtc->base; + encoder->get_config(encoder, crtc->config); } else { encoder->base.crtc = NULL; } + encoder->connectors_active = false; DRM_DEBUG_KMS("[ENCODER:%d:%s] hw state readout: %s, pipe %c\n", encoder->base.base.id, encoder->base.name, @@ -15452,42 +15390,20 @@ static int readout_hw_connector_encoder_state(struct drm_atomic_state *state) pipe_name(pipe)); } - return 0; -} - -static struct drm_atomic_state * -intel_modeset_readout_hw_state(struct drm_device *dev) -{ - struct intel_crtc *crtc; - int ret = 0; - - struct drm_atomic_state *state; - - state = drm_atomic_state_alloc(dev); - if (!state) - return ERR_PTR(-ENOMEM); - - state->acquire_ctx = dev->mode_config.acquire_ctx; - - for_each_intel_crtc(dev, crtc) { - ret = readout_hw_crtc_state(state, crtc); - if (ret) - goto err_free; + for_each_intel_connector(dev, connector) { + if (connector->get_hw_state(connector)) { + connector->base.dpms = DRM_MODE_DPMS_ON; + connector->encoder->connectors_active = true; + connector->base.encoder = &connector->encoder->base; + } else { + connector->base.dpms = DRM_MODE_DPMS_OFF; + connector->base.encoder = NULL; + } + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] hw state readout: %s\n", + connector->base.base.id, + connector->base.name, + connector->base.encoder ? "enabled" : "disabled"); } - - ret = readout_hw_pll_state(state); - if (ret) - goto err_free; - - ret = readout_hw_connector_encoder_state(state); - if (ret) - goto err_free; - - return state; - -err_free: - drm_atomic_state_free(state); - return ERR_PTR(ret); } /* Scan out the current hw modeset state, sanitizes it and maps it into the drm @@ -15496,57 +15412,37 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, bool force_restore) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; + enum pipe pipe; + struct intel_crtc *crtc; struct intel_encoder *encoder; - struct drm_atomic_state *state; - struct intel_shared_dpll_config shared_dplls[I915_NUM_PLLS]; int i; - state = intel_modeset_readout_hw_state(dev); - if (IS_ERR(state)) { - DRM_ERROR("Failed to read out hw state\n"); - return; - } - - drm_atomic_helper_swap_state(dev, state); + intel_modeset_readout_hw_state(dev); - /* swap sw/hw dpll state */ - intel_atomic_duplicate_dpll_state(dev_priv, shared_dplls); - intel_shared_dpll_commit(state); - memcpy(to_intel_atomic_state(state)->shared_dpll, - shared_dplls, sizeof(*shared_dplls) * dev_priv->num_shared_dpll); + /* + * Now that we have the config, copy it to each CRTC struct + * Note that this could go away if we move to using crtc_config + * checking everywhere. + */ + for_each_intel_crtc(dev, crtc) { + if (crtc->active && i915.fastboot) { + intel_mode_from_pipe_config(&crtc->base.mode, + crtc->config); + DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", + crtc->base.base.id); + drm_mode_debug_printmodeline(&crtc->base.mode); + } + } /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); } - for_each_crtc_in_state(state, crtc, crtc_state, i) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* prevent unnneeded restores with force_restore */ - crtc_state->active_changed = - crtc_state->mode_changed = - crtc_state->planes_changed = false; - - if (crtc->enabled) { - intel_mode_from_pipe_config(&crtc->state->mode, - to_intel_crtc_state(crtc->state)); - - drm_mode_copy(&crtc->mode, &crtc->state->mode); - drm_mode_copy(&crtc->hwmode, - &crtc->state->adjusted_mode); - } - - intel_sanitize_crtc(intel_crtc); - - /* - * sanitize_crtc may have forced an update of crtc->state, - * so reload in intel_dump_pipe_config - */ - intel_dump_pipe_config(intel_crtc, - to_intel_crtc_state(crtc->state), + for_each_pipe(dev_priv, pipe) { + crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]); + intel_sanitize_crtc(crtc); + intel_dump_pipe_config(crtc, crtc->config, "[setup_hw_state]"); } @@ -15570,17 +15466,20 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, ilk_wm_get_hw_state(dev); if (force_restore) { - int ret; - i915_redisable_vga(dev); - ret = intel_set_mode(state); - if (ret) { - DRM_ERROR("Failed to restore previous mode\n"); - drm_atomic_state_free(state); + /* + * We need to use raw interfaces for restoring state to avoid + * checking (bogus) intermediate states. + */ + for_each_pipe(dev_priv, pipe) { + struct drm_crtc *crtc = + dev_priv->pipe_to_crtc_mapping[pipe]; + + intel_crtc_restore_mode(crtc); } } else { - drm_atomic_state_free(state); + intel_modeset_update_staged_output_state(dev); } intel_modeset_check_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 9ca683ae2dec9..b28029a1c8f29 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -130,6 +130,11 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; + /* + * The new crtc this encoder will be driven from. Only differs from + * base->crtc while a modeset is in progress. + */ + struct intel_crtc *new_crtc; enum intel_output_type type; unsigned int cloneable; @@ -190,6 +195,12 @@ struct intel_connector { */ struct intel_encoder *encoder; + /* + * The new encoder this connector will be driven. Only differs from + * encoder while a modeset is in progress. + */ + struct intel_encoder *new_encoder; + /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); @@ -527,6 +538,7 @@ struct intel_crtc { struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; + bool new_enabled; /* reset counter value when the last flip was submitted */ unsigned int reset_counter; @@ -1407,8 +1419,6 @@ struct drm_atomic_state *intel_atomic_state_alloc(struct drm_device *dev); void intel_atomic_state_clear(struct drm_atomic_state *); struct intel_shared_dpll_config * intel_atomic_get_shared_dpll_state(struct drm_atomic_state *s); -void intel_atomic_duplicate_dpll_state(struct drm_i915_private *, - struct intel_shared_dpll_config *); static inline struct intel_crtc_state * intel_atomic_get_crtc_state(struct drm_atomic_state *state, -- GitLab From b17d48e27d35bc890ff205c9663b58803798b63b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:39 +0200 Subject: [PATCH 0093/7006] drm/i915: Do not use atomic modesets in hw readout. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should fix fallout caused by making intel_crtc_control and update_dpms atomic, which became a problem after reverting the atomic hw readout patch. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90929 Reported-by: Ville Syrjälä Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 75 ++++++++++++---------------- 1 file changed, 32 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5cc2263db199d..7abaffeda7ce0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6187,31 +6187,35 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) mutex_unlock(&dev->struct_mutex); } +static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_i915_private *dev_priv = to_i915(crtc->dev); + enum intel_display_power_domain domain; + unsigned long domains; + + if (!intel_crtc->active) + return; + + intel_crtc_disable_planes(crtc); + dev_priv->display.crtc_disable(crtc); + + domains = intel_crtc->enabled_power_domains; + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); + intel_crtc->enabled_power_domains = 0; +} + /* * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ void intel_display_suspend(struct drm_device *dev) { - struct drm_i915_private *dev_priv = to_i915(dev); struct drm_crtc *crtc; - for_each_crtc(dev, crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum intel_display_power_domain domain; - unsigned long domains; - - if (!intel_crtc->active) - continue; - - intel_crtc_disable_planes(crtc); - dev_priv->display.crtc_disable(crtc); - - domains = intel_crtc->enabled_power_domains; - for_each_power_domain(domain, domains) - intel_display_power_put(dev_priv, domain); - intel_crtc->enabled_power_domains = 0; - } + for_each_crtc(dev, crtc) + intel_crtc_disable_noatomic(crtc); } /* Master function to enable/disable CRTC and corresponding power wells */ @@ -15120,7 +15124,9 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_encoder *encoder; u32 reg; + bool enable; /* Clear any frame start delays used for debugging left by the BIOS */ reg = PIPECONF(crtc->config->cpu_transcoder); @@ -15137,7 +15143,6 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) * disable the crtc (and hence change the state) if it is wrong. Note * that gen4+ has a fixed plane -> pipe mapping. */ if (INTEL_INFO(dev)->gen < 4 && !intel_check_plane_mapping(crtc)) { - struct intel_connector *connector; bool plane; DRM_DEBUG_KMS("[CRTC:%d] wrong plane connection detected!\n", @@ -15149,29 +15154,8 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) plane = crtc->plane; to_intel_plane_state(crtc->base.primary->state)->visible = true; crtc->plane = !plane; - intel_crtc_control(&crtc->base, false); + intel_crtc_disable_noatomic(&crtc->base); crtc->plane = plane; - - /* ... and break all links. */ - for_each_intel_connector(dev, connector) { - if (connector->encoder->base.crtc != &crtc->base) - continue; - - connector->base.dpms = DRM_MODE_DPMS_OFF; - connector->base.encoder = NULL; - } - /* multiple connectors may have the same encoder: - * handle them and break crtc link separately */ - for_each_intel_connector(dev, connector) - if (connector->encoder->base.crtc == &crtc->base) { - connector->encoder->base.crtc = NULL; - connector->encoder->connectors_active = false; - } - - WARN_ON(crtc->active); - crtc->base.state->enable = false; - crtc->base.state->active = false; - crtc->base.enabled = false; } if (dev_priv->quirks & QUIRK_PIPEA_FORCE && @@ -15185,13 +15169,18 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) /* Adjust the state of the output pipe according to whether we * have active connectors/encoders. */ - intel_crtc_update_dpms(&crtc->base); + enable = false; + for_each_encoder_on_crtc(dev, &crtc->base, encoder) + enable |= encoder->connectors_active; + + if (!enable) + intel_crtc_disable_noatomic(&crtc->base); if (crtc->active != crtc->base.state->active) { - struct intel_encoder *encoder; /* This can happen either due to bugs in the get_hw_state - * functions or because the pipe is force-enabled due to the + * functions or because of calls to intel_crtc_disable_noatomic, + * or because the pipe is force-enabled due to the * pipe A quirk. */ DRM_DEBUG_KMS("[CRTC:%d] hw state adjusted, was %s, now %s\n", crtc->base.base.id, -- GitLab From 02e0efb5b40b42f06668ba38f39654c57feaacdb Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:40 +0200 Subject: [PATCH 0094/7006] drm/i915: get rid of intel_plane_restore in intel_crtc_page_flip Use a full atomic call instead. intel_crtc_page_flip will still have to live until async updates are allowed. This doesn't seem to be a regression from the convert to atomic, part 3 patch. During GPU reset it fixes the following warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 752 at drivers/gpu/drm/drm_crtc.c:5337 drm_mode_page_flip_ioctl+0x27b/0x360() Modules linked in: i915 CPU: 0 PID: 752 Comm: Xorg Not tainted 4.1.0-rc7-patser+ #4090 Hardware name: NUC5i7RYB, BIOS RYBDWi35.86A.0246.2015.0309.1355 03/09/2015 ffffffff81c90866 ffff8800d87c3ca8 ffffffff817f7d87 0000000080000001 0000000000000000 ffff8800d87c3ce8 ffffffff81084955 ffff880000000000 ffff8800d87c3dc0 ffff8800d93d1208 0000000000000000 ffff8800b7d1f3e0 Call Trace: [] dump_stack+0x4f/0x7b [] warn_slowpath_common+0x85/0xc0 [] warn_slowpath_null+0x15/0x20 [] drm_mode_page_flip_ioctl+0x27b/0x360 [] drm_ioctl+0x1a0/0x6a0 [] ? get_parent_ip+0x11/0x50 [] ? avc_has_perm+0x20/0x280 [] ? get_parent_ip+0x11/0x50 [] do_vfs_ioctl+0x2f8/0x530 [] ? expand_files+0x261/0x270 [] ? selinux_file_ioctl+0x56/0x100 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x12/0x6f ---[ end trace 9ce834560085bd64 ]--- Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 29 +++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7abaffeda7ce0..cdf6549c8e748 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11618,8 +11618,35 @@ free_work: kfree(work); if (ret == -EIO) { + struct drm_atomic_state *state; + struct drm_plane_state *plane_state; + out_hang: - ret = intel_plane_restore(primary); + state = drm_atomic_state_alloc(dev); + if (!state) + return -ENOMEM; + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); + +retry: + plane_state = drm_atomic_get_plane_state(state, primary); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) { + drm_atomic_set_fb_for_plane(plane_state, fb); + + ret = drm_atomic_set_crtc_for_plane(plane_state, crtc); + if (!ret) + ret = drm_atomic_commit(state); + } + + if (ret == -EDEADLK) { + drm_modeset_backoff(state->acquire_ctx); + drm_atomic_state_clear(state); + goto retry; + } + + if (ret) + drm_atomic_state_free(state); + if (ret == 0 && event) { spin_lock_irq(&dev->event_lock); drm_send_vblank_event(dev, pipe, event); -- GitLab From b8b7fadec3c797d7babb3c7fec484971e1604978 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:41 +0200 Subject: [PATCH 0095/7006] drm/i915: Set hwmode during readout. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This was introduced after converting hw readout to atomic, so it should have been part of the revert too. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90929 Reported-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cdf6549c8e748..14ccf49b9067b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15357,6 +15357,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.state->enable = crtc->active; crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; + crtc->base.hwmode = crtc->config->base.adjusted_mode; plane_state = to_intel_plane_state(primary->state); plane_state->visible = primary_get_hw_state(crtc); -- GitLab From c0165304e10f317672e20f2b40770d74c51e287f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 12 Jun 2015 11:15:42 +0200 Subject: [PATCH 0096/7006] drm/i915: Only enable cursor if it can be enabled. The cursor should only be enabled if it's visible. This fixes igt/kms_cursor_crc, which may otherwise produce the following warning: ------------[ cut here ]------------ WARNING: CPU: 0 PID: 3425 at drivers/gpu/drm/i915/intel_display.c:9995 intel_crtc_update_cursor+0x14c/0x4d0 [i915]() Missing switch case (0) in i9xx_update_cursor Modules linked in: i915 CPU: 0 PID: 3425 Comm: kms_cursor_crc Tainted: G W 4.1.0-rc7-patser+ #4079 Hardware name: LENOVO 2349AV8/2349AV8, BIOS G1ETA5WW (2.65 ) 04/15/2014 ffffffffc01aad10 ffff8800b083faa8 ffffffff817f7827 0000000080000001 ffff8800b083faf8 ffff8800b083fae8 ffffffff81084955 ffff8800b083fad8 ffff8800c4931148 0000000001200000 ffff8800c48b0000 0000000000000000 Call Trace: [] dump_stack+0x4f/0x7b [] warn_slowpath_common+0x85/0xc0 [] warn_slowpath_fmt+0x41/0x50 [] intel_crtc_update_cursor+0x14c/0x4d0 [i915] [] __intel_set_mode+0x6c4/0x750 [i915] [] intel_crtc_set_config+0x473/0x5c0 [i915] [] drm_mode_set_config_internal+0x69/0x120 [] drm_mode_setcrtc+0x189/0x540 [] drm_ioctl+0x1a0/0x6a0 [] ? get_parent_ip+0x11/0x50 [] do_vfs_ioctl+0x2f8/0x530 [] ? trace_hardirqs_on+0xd/0x10 [] ? selinux_file_ioctl+0x56/0x100 [] SyS_ioctl+0x81/0xa0 [] system_call_fastpath+0x12/0x6f ---[ end trace abf0f71163290a96 ]--- Signed-off-by: Maarten Lankhorst Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 14ccf49b9067b..afe91a8f7e369 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4748,7 +4748,8 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) intel_enable_primary_hw_plane(crtc->primary, crtc); intel_enable_sprite_planes(crtc); - intel_crtc_update_cursor(crtc, true); + if (to_intel_plane_state(crtc->cursor->state)->visible) + intel_crtc_update_cursor(crtc, true); intel_post_enable_primary(crtc); -- GitLab From d0fe116b4554d79125f384f7ba23722b41c3cb93 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Fri, 24 Apr 2015 10:27:40 -0700 Subject: [PATCH 0097/7006] gitignore: Add MIPS vmlinux.32 to the list MIPS64 kernels builds will produce a vmlinux.32 kernel image for compatibility, ignore them. Signed-off-by: Florian Fainelli Signed-off-by: Michal Marek --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4ad4a98b884b9..34d6bad9317b3 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ Module.symvers /TAGS /linux /vmlinux +/vmlinux.32 /vmlinux-gdb.py /vmlinuz /System.map -- GitLab From d1b1589c4800678a8a2beba83845366b2dff5d70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:19 +0300 Subject: [PATCH 0098/7006] drm/i915: Implement WaEnableHDMI8bpcBefore12bpc:snb, ivb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CPT/PPT require a specific procedure for enabling 12bpc HDMI. Implement it, and to keep things neat pull the code into a function. v2: Rebased due to crtc->config changes s/HDMI_GC/HDMIUNIT_GC/ to match spec better Factor out intel_enable_hdmi_audio() Signed-off-by: Ville Syrjälä Reviewed-by: Ander Conselvan de Oliveira Reviewed-By: Chandra Konduru Testecase: igt/kms_render/* Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_hdmi.c | 74 ++++++++++++++++++++++++++++--- 2 files changed, 69 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 760dbebc1aefc..1db6b4bf68fd7 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6200,6 +6200,7 @@ enum skl_disp_power_wells { #define _TRANSA_CHICKEN1 0xf0060 #define _TRANSB_CHICKEN1 0xf1060 #define TRANS_CHICKEN1(pipe) _PIPE(pipe, _TRANSA_CHICKEN1, _TRANSB_CHICKEN1) +#define TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE (1<<10) #define TRANS_CHICKEN1_DP0UNIT_GC_DISABLE (1<<4) #define _TRANSA_CHICKEN2 0xf0064 #define _TRANSB_CHICKEN2 0xf1064 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index e97731aab6dcf..9ee6176a5f27f 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -814,6 +814,16 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, pipe_config->base.adjusted_mode.crtc_clock = dotclock; } +static void intel_enable_hdmi_audio(struct intel_encoder *encoder) +{ + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + + WARN_ON(!crtc->config->has_hdmi_sink); + DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", + pipe_name(crtc->pipe)); + intel_audio_codec_enable(encoder); +} + static void intel_enable_hdmi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; @@ -854,12 +864,61 @@ static void intel_enable_hdmi(struct intel_encoder *encoder) POSTING_READ(intel_hdmi->hdmi_reg); } - if (intel_crtc->config->has_audio) { - WARN_ON(!intel_crtc->config->has_hdmi_sink); - DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n", - pipe_name(intel_crtc->pipe)); - intel_audio_codec_enable(encoder); + if (intel_crtc->config->has_audio) + intel_enable_hdmi_audio(encoder); +} + +static void cpt_enable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + enum pipe pipe = crtc->pipe; + u32 temp; + + temp = I915_READ(intel_hdmi->hdmi_reg); + + temp |= SDVO_ENABLE; + if (crtc->config->has_audio) + temp |= SDVO_AUDIO_ENABLE; + + /* + * WaEnableHDMI8bpcBefore12bpc:snb,ivb + * + * The procedure for 12bpc is as follows: + * 1. disable HDMI clock gating + * 2. enable HDMI with 8bpc + * 3. enable HDMI with 12bpc + * 4. enable HDMI clock gating + */ + + if (crtc->config->pipe_bpp > 24) { + I915_WRITE(TRANS_CHICKEN1(pipe), + I915_READ(TRANS_CHICKEN1(pipe)) | + TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); + + temp &= ~SDVO_COLOR_FORMAT_MASK; + temp |= SDVO_COLOR_FORMAT_8bpc; } + + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); + + if (crtc->config->pipe_bpp > 24) { + temp &= ~SDVO_COLOR_FORMAT_MASK; + temp |= HDMI_COLOR_FORMAT_12bpc; + + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); + + I915_WRITE(TRANS_CHICKEN1(pipe), + I915_READ(TRANS_CHICKEN1(pipe)) & + ~TRANS_CHICKEN1_HDMIUNIT_GC_DISABLE); + } + + if (crtc->config->has_audio) + intel_enable_hdmi_audio(encoder); } static void vlv_enable_hdmi(struct intel_encoder *encoder) @@ -1827,7 +1886,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->post_disable = vlv_hdmi_post_disable; } else { intel_encoder->pre_enable = intel_hdmi_pre_enable; - intel_encoder->enable = intel_enable_hdmi; + if (HAS_PCH_CPT(dev)) + intel_encoder->enable = cpt_enable_hdmi; + else + intel_encoder->enable = intel_enable_hdmi; } intel_encoder->type = INTEL_OUTPUT_HDMI; -- GitLab From 6d67415f40b1f166212f37ecc9c23b9f380dfebc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:20 +0300 Subject: [PATCH 0099/7006] drm/i915: Send GCP infoframes for deep color HDMI sinks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCP infoframes are required to inform the HDMI sink about the color depth. Send the GCP infoframe whenever the sink supports any deep color modes since such sinks must anyway be capable of receiving them. For sinks that don't support deep color let's skip the GCP in case it might confuse the sink, although HDMI 1.4 spec does say all sinks must be capable of reciving them. In theory we could skip the GCP infoframe for deep color sinks in 8bpc mode as well since sinks must fall back to 8bpc whenever GCP isn't received for some time. BSpec says we should disable GCP after disabling the port, so do that as well. v2: s/intel_set_gcp_infoframe/intel_hdmi_set_gcp_infoframe/ Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä [danvet: Resolve conflict with lack of chv phy patches and fixup typo Chandra spotted.] Reviewed-by: Chandra Konduru Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++ drivers/gpu/drm/i915/intel_hdmi.c | 74 +++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1db6b4bf68fd7..c9f9d3d3adbad 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6061,6 +6061,9 @@ enum skl_disp_power_wells { #define _VIDEO_DIP_CTL_A 0xe0200 #define _VIDEO_DIP_DATA_A 0xe0208 #define _VIDEO_DIP_GCP_A 0xe0210 +#define GCP_COLOR_INDICATION (1 << 2) +#define GCP_DEFAULT_PHASE_ENABLE (1 << 1) +#define GCP_AV_MUTE (1 << 0) #define _VIDEO_DIP_CTL_B 0xe1200 #define _VIDEO_DIP_DATA_B 0xe1208 diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 9ee6176a5f27f..a422d83b6efb8 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -541,6 +541,66 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, intel_hdmi_set_hdmi_infoframe(encoder, adjusted_mode); } +static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder) +{ + struct drm_device *dev = encoder->dev; + struct drm_connector *connector; + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + + /* + * HDMI cloning is only supported on g4x which doesn't + * support deep color or GCP infoframes anyway so no + * need to worry about multiple HDMI sinks here. + */ + list_for_each_entry(connector, &dev->mode_config.connector_list, head) + if (connector->encoder == encoder) + return connector->display_info.bpc > 8; + + return false; +} + +static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) +{ + struct drm_i915_private *dev_priv = encoder->dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->crtc); + u32 reg, val = 0; + + if (HAS_DDI(dev_priv)) + reg = HSW_TVIDEO_DIP_GCP(crtc->config->cpu_transcoder); + else if (IS_VALLEYVIEW(dev_priv)) + reg = VLV_TVIDEO_DIP_GCP(crtc->pipe); + else if (HAS_PCH_SPLIT(dev_priv->dev)) + reg = TVIDEO_DIP_GCP(crtc->pipe); + else + return false; + + /* Indicate color depth whenever the sink supports deep color */ + if (hdmi_sink_is_deep_color(encoder)) + val |= GCP_COLOR_INDICATION; + + I915_WRITE(reg, val); + + return val != 0; +} + +static void intel_disable_gcp_infoframe(struct intel_crtc *crtc) +{ + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + u32 reg; + + if (HAS_DDI(dev_priv)) + reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder); + else if (IS_VALLEYVIEW(dev_priv)) + reg = VLV_TVIDEO_DIP_CTL(crtc->pipe); + else if (HAS_PCH_SPLIT(dev_priv->dev)) + reg = TVIDEO_DIP_CTL(crtc->pipe); + else + return; + + I915_WRITE(reg, I915_READ(reg) & ~VIDEO_DIP_ENABLE_GCP); +} + static void ibx_set_infoframes(struct drm_encoder *encoder, bool enable, struct drm_display_mode *adjusted_mode) @@ -581,6 +641,9 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -618,6 +681,9 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -666,6 +732,9 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -695,6 +764,9 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); + if (intel_hdmi_set_gcp_infoframe(encoder)) + val |= VIDEO_DIP_ENABLE_GCP_HSW; + I915_WRITE(reg, val); POSTING_READ(reg); @@ -960,6 +1032,8 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); } + + intel_disable_gcp_infoframe(to_intel_crtc(encoder->base.crtc)); } static void g4x_disable_hdmi(struct intel_encoder *encoder) -- GitLab From 12aa32905df59a32a6fb770830799058bf591eed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:21 +0300 Subject: [PATCH 0100/7006] drm/i915: Enable default_phase in GCP when possible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the video timings are suitably aligned so that all different periods start at phase 0 (ie. none of the periods start mid-pixel) we can inform the sink about this. Supposedly the sink can then optimize certain things. Obviously this is only relevant when outputting >8bpc data since otherwise there are no mid-pixel phases. v2: Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index a422d83b6efb8..b1e1c3d8b8cd3 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -560,6 +560,49 @@ static bool hdmi_sink_is_deep_color(struct drm_encoder *encoder) return false; } +/* + * Determine if default_phase=1 can be indicated in the GCP infoframe. + * + * From HDMI specification 1.4a: + * - The first pixel of each Video Data Period shall always have a pixel packing phase of 0 + * - The first pixel following each Video Data Period shall have a pixel packing phase of 0 + * - The PP bits shall be constant for all GCPs and will be equal to the last packing phase + * - The first pixel following every transition of HSYNC or VSYNC shall have a pixel packing + * phase of 0 + */ +static bool gcp_default_phase_possible(int pipe_bpp, + const struct drm_display_mode *mode) +{ + unsigned int pixels_per_group; + + switch (pipe_bpp) { + case 30: + /* 4 pixels in 5 clocks */ + pixels_per_group = 4; + break; + case 36: + /* 2 pixels in 3 clocks */ + pixels_per_group = 2; + break; + case 48: + /* 1 pixel in 2 clocks */ + pixels_per_group = 1; + break; + default: + /* phase information not relevant for 8bpc */ + return false; + } + + return mode->crtc_hdisplay % pixels_per_group == 0 && + mode->crtc_htotal % pixels_per_group == 0 && + mode->crtc_hblank_start % pixels_per_group == 0 && + mode->crtc_hblank_end % pixels_per_group == 0 && + mode->crtc_hsync_start % pixels_per_group == 0 && + mode->crtc_hsync_end % pixels_per_group == 0 && + ((mode->flags & DRM_MODE_FLAG_INTERLACE) == 0 || + mode->crtc_htotal/2 % pixels_per_group == 0); +} + static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) { struct drm_i915_private *dev_priv = encoder->dev->dev_private; @@ -579,6 +622,11 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) if (hdmi_sink_is_deep_color(encoder)) val |= GCP_COLOR_INDICATION; + /* Enable default_phase whenever the display mode is suitably aligned */ + if (gcp_default_phase_possible(crtc->config->pipe_bpp, + &crtc->config->base.adjusted_mode)) + val |= GCP_DEFAULT_PHASE_ENABLE; + I915_WRITE(reg, val); return val != 0; -- GitLab From c5de7c6f3b3185ebbb9cf81abb94580c7f2ebd5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:22 +0300 Subject: [PATCH 0101/7006] drm/i915: Fix HDMI 12bpc TRANSCONF bpc value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit IBX BSpec says we must specify 8bpc in TRANSCONF for both 8bpc and 12bpc HDMI output. Do so. v2: Pass intel_crtc to intel_pipe_has_type() Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 58846b58b676f..c4ccc376ae44e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2003,11 +2003,15 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv, if (HAS_PCH_IBX(dev_priv->dev)) { /* - * make the BPC in transcoder be consistent with - * that in pipeconf reg. + * Make the BPC in transcoder be consistent with + * that in pipeconf reg. For HDMI we must use 8bpc + * here for both 8bpc and 12bpc. */ val &= ~PIPECONF_BPC_MASK; - val |= pipeconf_val & PIPECONF_BPC_MASK; + if (intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_HDMI)) + val |= PIPECONF_8BPC; + else + val |= pipeconf_val & PIPECONF_BPC_MASK; } val &= ~TRANS_INTERLACE_MASK; -- GitLab From bf868c7ddaa7fd5645fbc01cf2c4ad6ddd64c142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:23 +0300 Subject: [PATCH 0102/7006] drm/i915: Fix 12bpc HDMI enable for IBX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the procedure listed in Bspec to toggle the port enable bit off and on when enabling HDMI with 12bpc and pixel repeat on IBX. The old code didn't actually enable the port before "toggling" the bit back off, so the whole workaround was essentially a nop. Also take the opportunity to clarify the code by splitting the gmch platforms to a separate (much more straightforward) function. v2: Rebased due to crtc->config changes Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 78 +++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index b1e1c3d8b8cd3..14a916437b243 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -944,47 +944,73 @@ static void intel_enable_hdmi_audio(struct intel_encoder *encoder) intel_audio_codec_enable(encoder); } -static void intel_enable_hdmi(struct intel_encoder *encoder) +static void g4x_enable_hdmi(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc); + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); u32 temp; - u32 enable_bits = SDVO_ENABLE; - - if (intel_crtc->config->has_audio) - enable_bits |= SDVO_AUDIO_ENABLE; temp = I915_READ(intel_hdmi->hdmi_reg); - /* HW workaround for IBX, we need to move the port to transcoder A - * before disabling it, so restore the transcoder select bit here. */ - if (HAS_PCH_IBX(dev)) - enable_bits |= SDVO_PIPE_SEL(intel_crtc->pipe); + temp |= SDVO_ENABLE; + if (crtc->config->has_audio) + temp |= SDVO_AUDIO_ENABLE; - /* HW workaround, need to toggle enable bit off and on for 12bpc, but - * we do this anyway which shows more stable in testing. - */ - if (HAS_PCH_SPLIT(dev)) { - I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); - POSTING_READ(intel_hdmi->hdmi_reg); - } + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); + + if (crtc->config->has_audio) + intel_enable_hdmi_audio(encoder); +} + +static void ibx_enable_hdmi(struct intel_encoder *encoder) +{ + struct drm_device *dev = encoder->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); + struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); + u32 temp; + + temp = I915_READ(intel_hdmi->hdmi_reg); - temp |= enable_bits; + temp |= SDVO_ENABLE; + if (crtc->config->has_audio) + temp |= SDVO_AUDIO_ENABLE; + /* + * HW workaround, need to write this twice for issue + * that may result in first write getting masked. + */ + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); - /* HW workaround, need to write this twice for issue that may result - * in first write getting masked. + /* + * HW workaround, need to toggle enable bit off and on + * for 12bpc with pixel repeat. + * + * FIXME: BSpec says this should be done at the end of + * of the modeset sequence, so not sure if this isn't too soon. */ - if (HAS_PCH_SPLIT(dev)) { + if (crtc->config->pipe_bpp > 24 && + crtc->config->pixel_multiplier > 1) { + I915_WRITE(intel_hdmi->hdmi_reg, temp & ~SDVO_ENABLE); + POSTING_READ(intel_hdmi->hdmi_reg); + + /* + * HW workaround, need to write this twice for issue + * that may result in first write getting masked. + */ + I915_WRITE(intel_hdmi->hdmi_reg, temp); + POSTING_READ(intel_hdmi->hdmi_reg); I915_WRITE(intel_hdmi->hdmi_reg, temp); POSTING_READ(intel_hdmi->hdmi_reg); } - if (intel_crtc->config->has_audio) + if (crtc->config->has_audio) intel_enable_hdmi_audio(encoder); } @@ -1504,7 +1530,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder) intel_crtc->config->has_hdmi_sink, adjusted_mode); - intel_enable_hdmi(encoder); + g4x_enable_hdmi(encoder); vlv_wait_port_ready(dev_priv, dport, 0x0); } @@ -1821,7 +1847,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder) intel_crtc->config->has_hdmi_sink, adjusted_mode); - intel_enable_hdmi(encoder); + g4x_enable_hdmi(encoder); vlv_wait_port_ready(dev_priv, dport, 0x0); } @@ -2010,8 +2036,10 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port) intel_encoder->pre_enable = intel_hdmi_pre_enable; if (HAS_PCH_CPT(dev)) intel_encoder->enable = cpt_enable_hdmi; + else if (HAS_PCH_IBX(dev)) + intel_encoder->enable = ibx_enable_hdmi; else - intel_encoder->enable = intel_enable_hdmi; + intel_encoder->enable = g4x_enable_hdmi; } intel_encoder->type = INTEL_OUTPUT_HDMI; -- GitLab From 0be6f0c835077bb4dc7346e8eb75329d131a445b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:24 +0300 Subject: [PATCH 0103/7006] drm/i915: Disable all infoframes when turning off the HDMI port MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we just disable the GCP infoframe when turning off the port. That means if the same transcoder is used on a DP port next, we might end up pushing infoframes over DP, which isn't intended. Just disable all the infoframes when turning off the port. Also protect against two ports stomping on each other on g4x due to the single video DIP instance. Now only the first port to enable gets to send infoframes. v2: Rebase Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 85 +++++++++++++++---------------- 1 file changed, 40 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 14a916437b243..ed0fce1e59532 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -514,7 +514,13 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~VIDEO_DIP_ENABLE; + if (port != (val & VIDEO_DIP_PORT_MASK)) { + DRM_DEBUG_KMS("video DIP still enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); + return; + } + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); I915_WRITE(reg, val); POSTING_READ(reg); return; @@ -522,16 +528,17 @@ static void g4x_set_infoframes(struct drm_encoder *encoder, if (port != (val & VIDEO_DIP_PORT_MASK)) { if (val & VIDEO_DIP_ENABLE) { - val &= ~VIDEO_DIP_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); + DRM_DEBUG_KMS("video DIP already enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); + return; } val &= ~VIDEO_DIP_PORT_MASK; val |= port; } val |= VIDEO_DIP_ENABLE; - val &= ~VIDEO_DIP_ENABLE_VENDOR; + val &= ~(VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); I915_WRITE(reg, val); POSTING_READ(reg); @@ -632,23 +639,6 @@ static bool intel_hdmi_set_gcp_infoframe(struct drm_encoder *encoder) return val != 0; } -static void intel_disable_gcp_infoframe(struct intel_crtc *crtc) -{ - struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - u32 reg; - - if (HAS_DDI(dev_priv)) - reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder); - else if (IS_VALLEYVIEW(dev_priv)) - reg = VLV_TVIDEO_DIP_CTL(crtc->pipe); - else if (HAS_PCH_SPLIT(dev_priv->dev)) - reg = TVIDEO_DIP_CTL(crtc->pipe); - else - return; - - I915_WRITE(reg, I915_READ(reg) & ~VIDEO_DIP_ENABLE_GCP); -} - static void ibx_set_infoframes(struct drm_encoder *encoder, bool enable, struct drm_display_mode *adjusted_mode) @@ -669,25 +659,26 @@ static void ibx_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~VIDEO_DIP_ENABLE; + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); return; } if (port != (val & VIDEO_DIP_PORT_MASK)) { - if (val & VIDEO_DIP_ENABLE) { - val &= ~VIDEO_DIP_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); - } + WARN(val & VIDEO_DIP_ENABLE, + "DIP already enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); val &= ~VIDEO_DIP_PORT_MASK; val |= port; } val |= VIDEO_DIP_ENABLE; - val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | - VIDEO_DIP_ENABLE_GCP); + val &= ~(VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP; @@ -718,7 +709,9 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI); + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); return; @@ -727,7 +720,7 @@ static void cpt_set_infoframes(struct drm_encoder *encoder, /* Set both together, unset both together: see the spec. */ val |= VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI; val &= ~(VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | - VIDEO_DIP_ENABLE_GCP); + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP; @@ -760,25 +753,26 @@ static void vlv_set_infoframes(struct drm_encoder *encoder, if (!enable) { if (!(val & VIDEO_DIP_ENABLE)) return; - val &= ~VIDEO_DIP_ENABLE; + val &= ~(VIDEO_DIP_ENABLE | VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); I915_WRITE(reg, val); POSTING_READ(reg); return; } if (port != (val & VIDEO_DIP_PORT_MASK)) { - if (val & VIDEO_DIP_ENABLE) { - val &= ~VIDEO_DIP_ENABLE; - I915_WRITE(reg, val); - POSTING_READ(reg); - } + WARN(val & VIDEO_DIP_ENABLE, + "DIP already enabled on port %c\n", + (val & VIDEO_DIP_PORT_MASK) >> 29); val &= ~VIDEO_DIP_PORT_MASK; val |= port; } val |= VIDEO_DIP_ENABLE; - val &= ~(VIDEO_DIP_ENABLE_AVI | VIDEO_DIP_ENABLE_VENDOR | - VIDEO_DIP_ENABLE_GAMUT | VIDEO_DIP_ENABLE_GCP); + val &= ~(VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP; @@ -803,15 +797,16 @@ static void hsw_set_infoframes(struct drm_encoder *encoder, assert_hdmi_port_disabled(intel_hdmi); + val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | + VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | + VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); + if (!enable) { - I915_WRITE(reg, 0); + I915_WRITE(reg, val); POSTING_READ(reg); return; } - val &= ~(VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_GCP_HSW | - VIDEO_DIP_ENABLE_VS_HSW | VIDEO_DIP_ENABLE_GMP_HSW); - if (intel_hdmi_set_gcp_infoframe(encoder)) val |= VIDEO_DIP_ENABLE_GCP_HSW; @@ -1107,7 +1102,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder) POSTING_READ(intel_hdmi->hdmi_reg); } - intel_disable_gcp_infoframe(to_intel_crtc(encoder->base.crtc)); + intel_hdmi->set_infoframes(&encoder->base, false, NULL); } static void g4x_disable_hdmi(struct intel_encoder *encoder) -- GitLab From ec1dc603c664364c9d6c9c8e774f2822edf7397b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:25 +0300 Subject: [PATCH 0104/7006] drm/i915: Check infoframe state more diligently. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check that the DIP is enabled on the right port on IBX and VLV/CHV as we're doing on g4x, and also check for all the infoframe enable bits on all platforms. Eventually we should track each infoframe type independently, and also their contents. This is a small step in that direction as .infoframe_enabled() return value could be easily turned into a bitmask. Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 44 ++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index ed0fce1e59532..1cde6c045da25 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -174,10 +174,14 @@ static bool g4x_infoframe_enabled(struct drm_encoder *encoder) struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); u32 val = I915_READ(VIDEO_DIP_CTL); - if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; - return false; + if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_SPD); } static void ibx_write_infoframe(struct drm_encoder *encoder, @@ -227,10 +231,15 @@ static bool ibx_infoframe_enabled(struct drm_encoder *encoder) int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); - if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; - return false; + if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); } static void cpt_write_infoframe(struct drm_encoder *encoder, @@ -282,7 +291,12 @@ static bool cpt_infoframe_enabled(struct drm_encoder *encoder) int reg = TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); } static void vlv_write_infoframe(struct drm_encoder *encoder, @@ -332,10 +346,15 @@ static bool vlv_infoframe_enabled(struct drm_encoder *encoder) int reg = VLV_TVIDEO_DIP_CTL(intel_crtc->pipe); u32 val = I915_READ(reg); - if (VIDEO_DIP_PORT(intel_dig_port->port) == (val & VIDEO_DIP_PORT_MASK)) - return val & VIDEO_DIP_ENABLE; + if ((val & VIDEO_DIP_ENABLE) == 0) + return false; - return false; + if ((val & VIDEO_DIP_PORT_MASK) != VIDEO_DIP_PORT(intel_dig_port->port)) + return false; + + return val & (VIDEO_DIP_ENABLE_AVI | + VIDEO_DIP_ENABLE_VENDOR | VIDEO_DIP_ENABLE_GAMUT | + VIDEO_DIP_ENABLE_SPD | VIDEO_DIP_ENABLE_GCP); } static void hsw_write_infoframe(struct drm_encoder *encoder, @@ -383,8 +402,9 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder) u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder); u32 val = I915_READ(ctl_reg); - return val & (VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_SPD_HSW | - VIDEO_DIP_ENABLE_VS_HSW); + return val & (VIDEO_DIP_ENABLE_VSC_HSW | VIDEO_DIP_ENABLE_AVI_HSW | + VIDEO_DIP_ENABLE_GCP_HSW | VIDEO_DIP_ENABLE_VS_HSW | + VIDEO_DIP_ENABLE_GMP_HSW | VIDEO_DIP_ENABLE_SPD_HSW); } /* -- GitLab From be69a1335fceb706e19f7eaf8d34c9a721c5baf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:26 +0300 Subject: [PATCH 0105/7006] drm/i915: Fix hdmi clock readout with pixel repeat MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Account for the pixel multiplier when reading out the HDMI mode dotclock. Makes the state checked happier on my ILK when using double clocked modes. Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 1cde6c045da25..42fc505281904 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -943,6 +943,9 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder, else dotclock = pipe_config->port_clock; + if (pipe_config->pixel_multiplier) + dotclock /= pipe_config->pixel_multiplier; + if (HAS_PCH_SPLIT(dev_priv->dev)) ironlake_check_encoder_dotclock(pipe_config, dotclock); -- GitLab From 3320e37f7ac1f4df90268f204fef490dacee7ca0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 5 May 2015 17:06:27 +0300 Subject: [PATCH 0106/7006] drm/i915: Double the port clock when using double clocked modes with 12bpc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we're forgetting to double the port clock when using double clocked modes with 12bpc on HDMI. We're only accounting for the 1.5x factor due to the 12bpc. So further double the 1.5x port clock when we have a double clocked mode. Unfortunately I don't have any displays that support both 12bpc and double clocked modes, so I was unable to test this. Signed-off-by: Ville Syrjälä Reviewed-by: Chandra Konduru Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 42fc505281904..00c4b40e0158b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1242,6 +1242,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { pipe_config->pixel_multiplier = 2; + clock_12bpc *= 2; } if (intel_hdmi->color_range) -- GitLab From 66c826a1754c07012e29fbe9be7013e92a5acbac Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 1 Jun 2015 10:32:01 +0300 Subject: [PATCH 0107/7006] drm/i915/vlv: fix RC6 residency time calculation The divider value to convert from CZ clock rate to ms needs a +1 adjustment on VLV just like on CHV. This matches both the spec and the accuracy test by pm_rc6_residency. v2: - simplify logic checking for the CHV 320MHz special case (Rodrigo) Testcase: igt/pm_rc6_residency Signed-off-by: Imre Deak Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=76877 Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_sysfs.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 247626885f49d..55bd04c6b9390 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -64,24 +64,16 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg) goto out; } - units = 0; - div = 1000000ULL; - - if (IS_CHERRYVIEW(dev)) { + if (IS_CHERRYVIEW(dev) && czcount_30ns == 1) { /* Special case for 320Mhz */ - if (czcount_30ns == 1) { - div = 10000000ULL; - units = 3125ULL; - } else { - /* chv counts are one less */ - czcount_30ns += 1; - } + div = 10000000ULL; + units = 3125ULL; + } else { + czcount_30ns += 1; + div = 1000000ULL; + units = DIV_ROUND_UP_ULL(30ULL * bias, czcount_30ns); } - if (units == 0) - units = DIV_ROUND_UP_ULL(30ULL * bias, - (u64)czcount_30ns); - if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH) units <<= 8; -- GitLab From ea3f5d261fb0b757f95c1657f71ac86eb1778fd1 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 22 May 2015 20:04:58 +0300 Subject: [PATCH 0108/7006] drm/i915/gtt: Don't leak scratch page on mapping error Free the scratch page if dma mapping fails. Signed-off-by: Mika Kuoppala Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 619dad1b23863..5e3bfa94221ba 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2143,8 +2143,10 @@ static int setup_scratch_page(struct drm_device *dev) #ifdef CONFIG_INTEL_IOMMU dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, dma_addr)) + if (pci_dma_mapping_error(dev->pdev, dma_addr)) { + __free_page(page); return -EINVAL; + } #else dma_addr = page_to_phys(page); #endif -- GitLab From 8a1ebd7480fe8e80119d12bef2906f9480c2916f Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 22 May 2015 20:04:59 +0300 Subject: [PATCH 0109/7006] drm/i915/gtt: Remove _single from page table allocator We are always allocating a single page. No need to be verbose so remove the suffix. Signed-off-by: Mika Kuoppala Reviewed-by: Joonas Lahtinen Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5e3bfa94221ba..d7ea81aa5cebf 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -369,7 +369,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, kunmap_atomic(pt_vaddr); } -static struct i915_page_table *alloc_pt_single(struct drm_device *dev) +static struct i915_page_table *alloc_pt(struct drm_device *dev) { struct i915_page_table *pt; const size_t count = INTEL_INFO(dev)->gen >= 8 ? @@ -417,7 +417,7 @@ static void unmap_and_free_pd(struct i915_page_directory *pd, } } -static struct i915_page_directory *alloc_pd_single(struct drm_device *dev) +static struct i915_page_directory *alloc_pd(struct drm_device *dev) { struct i915_page_directory *pd; int ret = -ENOMEM; @@ -702,7 +702,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, continue; } - pt = alloc_pt_single(dev); + pt = alloc_pt(dev); if (IS_ERR(pt)) goto unwind_out; @@ -763,7 +763,7 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, if (pd) continue; - pd = alloc_pd_single(dev); + pd = alloc_pd(dev); if (IS_ERR(pd)) goto unwind_out; @@ -939,11 +939,11 @@ err_out: */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - ppgtt->scratch_pt = alloc_pt_single(ppgtt->base.dev); + ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); if (IS_ERR(ppgtt->scratch_pt)) return PTR_ERR(ppgtt->scratch_pt); - ppgtt->scratch_pd = alloc_pd_single(ppgtt->base.dev); + ppgtt->scratch_pd = alloc_pd(ppgtt->base.dev); if (IS_ERR(ppgtt->scratch_pd)) return PTR_ERR(ppgtt->scratch_pd); @@ -1327,7 +1327,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, /* We've already allocated a page table */ WARN_ON(!bitmap_empty(pt->used_ptes, GEN6_PTES)); - pt = alloc_pt_single(dev); + pt = alloc_pt(dev); if (IS_ERR(pt)) { ret = PTR_ERR(pt); goto unwind_out; @@ -1413,7 +1413,7 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) * size. We allocate at the top of the GTT to avoid fragmentation. */ BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm)); - ppgtt->scratch_pt = alloc_pt_single(ppgtt->base.dev); + ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); if (IS_ERR(ppgtt->scratch_pt)) return PTR_ERR(ppgtt->scratch_pt); -- GitLab From ac3f918d5a069f1c34c6e0d39cccb0e9c8ac9334 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Sat, 30 May 2015 20:25:53 +0200 Subject: [PATCH 0110/7006] Fix resume from suspend on IBM X30 This patch fixes the resume from suspend-to-ram on the IBM X30 laptop. The problem is caused by the Bios missing to re-initialize the iVCH registers, especially the PLL registers. This patch records the iVCH registers during initialization, and re-installs this register set when resuming. Signed-off-by: Thomas Richter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/dvo_ivch.c | 63 +++++++++++++++++++++++++++++---- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/dvo_ivch.c b/drivers/gpu/drm/i915/dvo_ivch.c index 89b08a896d20c..732ce8785945d 100644 --- a/drivers/gpu/drm/i915/dvo_ivch.c +++ b/drivers/gpu/drm/i915/dvo_ivch.c @@ -22,6 +22,7 @@ * * Authors: * Eric Anholt + * Thomas Richter * * Minor modifications (Dithering enable): * Thomas Richter @@ -90,7 +91,7 @@ /* * LCD Vertical Display Size */ -#define VR21 0x20 +#define VR21 0x21 /* * Panel power down status @@ -155,16 +156,33 @@ # define VR8F_POWER_MASK (0x3c) # define VR8F_POWER_POS (2) +/* Some Bios implementations do not restore the DVO state upon + * resume from standby. Thus, this driver has to handle it + * instead. The following list contains all registers that + * require saving. + */ +static const uint16_t backup_addresses[] = { + 0x11, 0x12, + 0x18, 0x19, 0x1a, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x8e, 0x8f, + 0x10 /* this must come last */ +}; + struct ivch_priv { bool quiet; uint16_t width, height; + + /* Register backup */ + + uint16_t reg_backup[ARRAY_SIZE(backup_addresses)]; }; static void ivch_dump_regs(struct intel_dvo_device *dvo); - /** * Reads a register on the ivch. * @@ -246,6 +264,7 @@ static bool ivch_init(struct intel_dvo_device *dvo, { struct ivch_priv *priv; uint16_t temp; + int i; priv = kzalloc(sizeof(struct ivch_priv), GFP_KERNEL); if (priv == NULL) @@ -273,6 +292,14 @@ static bool ivch_init(struct intel_dvo_device *dvo, ivch_read(dvo, VR20, &priv->width); ivch_read(dvo, VR21, &priv->height); + /* Make a backup of the registers to be able to restore them + * upon suspend. + */ + for (i = 0; i < ARRAY_SIZE(backup_addresses); i++) + ivch_read(dvo, backup_addresses[i], priv->reg_backup + i); + + ivch_dump_regs(dvo); + return true; out: @@ -294,12 +321,31 @@ static enum drm_mode_status ivch_mode_valid(struct intel_dvo_device *dvo, return MODE_OK; } +/* Restore the DVO registers after a resume + * from RAM. Registers have been saved during + * the initialization. + */ +static void ivch_reset(struct intel_dvo_device *dvo) +{ + struct ivch_priv *priv = dvo->dev_priv; + int i; + + DRM_DEBUG_KMS("Resetting the IVCH registers\n"); + + ivch_write(dvo, VR10, 0x0000); + + for (i = 0; i < ARRAY_SIZE(backup_addresses); i++) + ivch_write(dvo, backup_addresses[i], priv->reg_backup[i]); +} + /** Sets the power state of the panel connected to the ivch */ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) { int i; uint16_t vr01, vr30, backlight; + ivch_reset(dvo); + /* Set the new power state of the panel. */ if (!ivch_read(dvo, VR01, &vr01)) return; @@ -308,6 +354,7 @@ static void ivch_dpms(struct intel_dvo_device *dvo, bool enable) backlight = 1; else backlight = 0; + ivch_write(dvo, VR80, backlight); if (enable) @@ -334,6 +381,8 @@ static bool ivch_get_hw_state(struct intel_dvo_device *dvo) { uint16_t vr01; + ivch_reset(dvo); + /* Set the new power state of the panel. */ if (!ivch_read(dvo, VR01, &vr01)) return false; @@ -348,11 +397,15 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { + struct ivch_priv *priv = dvo->dev_priv; uint16_t vr40 = 0; uint16_t vr01 = 0; uint16_t vr10; - ivch_read(dvo, VR10, &vr10); + ivch_reset(dvo); + + vr10 = priv->reg_backup[ARRAY_SIZE(backup_addresses) - 1]; + /* Enable dithering for 18 bpp pipelines */ vr10 &= VR10_INTERFACE_DEPTH_MASK; if (vr10 == VR10_INTERFACE_2X18 || vr10 == VR10_INTERFACE_1X18) @@ -366,7 +419,7 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, uint16_t x_ratio, y_ratio; vr01 |= VR01_PANEL_FIT_ENABLE; - vr40 |= VR40_CLOCK_GATING_ENABLE | VR40_ENHANCED_PANEL_FITTING; + vr40 |= VR40_CLOCK_GATING_ENABLE; x_ratio = (((mode->hdisplay - 1) << 16) / (adjusted_mode->hdisplay - 1)) >> 2; y_ratio = (((mode->vdisplay - 1) << 16) / @@ -381,8 +434,6 @@ static void ivch_mode_set(struct intel_dvo_device *dvo, ivch_write(dvo, VR01, vr01); ivch_write(dvo, VR40, vr40); - - ivch_dump_regs(dvo); } static void ivch_dump_regs(struct intel_dvo_device *dvo) -- GitLab From fcc0008fd02330f1c539a8dd831b00ca9b998cd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 26 May 2015 20:22:40 +0300 Subject: [PATCH 0111/7006] drm/i915: Bump CHV PFI credits to 63 when cdclk>=czclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Switch from using 31 PFI credits to 63 PFI credits when cdclk>=czclk on CHV. The spec lists both 31 and 63 as "suggested" values, but based on feedback from hardware folks we should actually be using 63. Originally I picked the 31 basically by flipping a coin. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c4ccc376ae44e..193ba79e5a41f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6055,7 +6055,7 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) if (DIV_ROUND_CLOSEST(dev_priv->cdclk_freq, 1000) >= dev_priv->rps.cz_freq) { /* CHV suggested value is 31 or 63 */ if (IS_CHERRYVIEW(dev_priv)) - credits = PFI_CREDIT_31; + credits = PFI_CREDIT_63; else credits = PFI_CREDIT(15); } else { -- GitLab From 6a65c5b9326c9dd391afb1b3df75cbedffbaccdb Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 29 May 2015 16:44:13 +0300 Subject: [PATCH 0112/7006] drm/i915: Fix command parser to validate multiple register access with the same command. Until now the software command checker assumed that commands could read or write at most a single register per packet. This is not necessarily the case, MI_LOAD_REGISTER_IMM expects a variable-length list of offset/value pairs and writes them in sequence. The previous code would only check whether the first entry was valid, effectively allowing userspace to write unrestricted registers of the MMIO space by sending a multi-register write with a legal first register, with potential security implications on Gen6 and 7 hardware. Fix it by extending the drm_i915_cmd_descriptor table to represent multi-register access and making validate_cmd() iterate for all register offsets present in the command packet. Signed-off-by: Francisco Jerez Reviewed-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 74 +++++++++++++++----------- drivers/gpu/drm/i915/i915_drv.h | 5 ++ 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 9605ff8f2fcdf..5fc49bbcdb9de 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -123,7 +123,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { CMD( MI_SEMAPHORE_MBOX, SMI, !F, 0xFF, R ), CMD( MI_STORE_DWORD_INDEX, SMI, !F, 0xFF, R ), CMD( MI_LOAD_REGISTER_IMM(1), SMI, !F, 0xFF, W, - .reg = { .offset = 1, .mask = 0x007FFFFC } ), + .reg = { .offset = 1, .mask = 0x007FFFFC, .step = 2 } ), CMD( MI_STORE_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, .reg = { .offset = 1, .mask = 0x007FFFFC }, .bits = {{ @@ -934,7 +934,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring) static bool check_cmd(const struct intel_engine_cs *ring, const struct drm_i915_cmd_descriptor *desc, - const u32 *cmd, + const u32 *cmd, u32 length, const bool is_master, bool *oacontrol_set) { @@ -950,38 +950,49 @@ static bool check_cmd(const struct intel_engine_cs *ring, } if (desc->flags & CMD_DESC_REGISTER) { - u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask; - /* - * OACONTROL requires some special handling for writes. We - * want to make sure that any batch which enables OA also - * disables it before the end of the batch. The goal is to - * prevent one process from snooping on the perf data from - * another process. To do that, we need to check the value - * that will be written to the register. Hence, limit - * OACONTROL writes to only MI_LOAD_REGISTER_IMM commands. + * Get the distance between individual register offset + * fields if the command can perform more than one + * access at a time. */ - if (reg_addr == OACONTROL) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { - DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); - return false; + const u32 step = desc->reg.step ? desc->reg.step : length; + u32 offset; + + for (offset = desc->reg.offset; offset < length; + offset += step) { + const u32 reg_addr = cmd[offset] & desc->reg.mask; + + /* + * OACONTROL requires some special handling for + * writes. We want to make sure that any batch which + * enables OA also disables it before the end of the + * batch. The goal is to prevent one process from + * snooping on the perf data from another process. To do + * that, we need to check the value that will be written + * to the register. Hence, limit OACONTROL writes to + * only MI_LOAD_REGISTER_IMM commands. + */ + if (reg_addr == OACONTROL) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); + return false; + } + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) + *oacontrol_set = (cmd[offset + 1] != 0); } - if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1)) - *oacontrol_set = (cmd[2] != 0); - } - - if (!valid_reg(ring->reg_table, - ring->reg_count, reg_addr)) { - if (!is_master || - !valid_reg(ring->master_reg_table, - ring->master_reg_count, - reg_addr)) { - DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", - reg_addr, - *cmd, - ring->id); - return false; + if (!valid_reg(ring->reg_table, + ring->reg_count, reg_addr)) { + if (!is_master || + !valid_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr)) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, *cmd, + ring->id); + return false; + } } } } @@ -1105,7 +1116,8 @@ int i915_parse_cmds(struct intel_engine_cs *ring, break; } - if (!check_cmd(ring, desc, cmd, is_master, &oacontrol_set)) { + if (!check_cmd(ring, desc, cmd, length, is_master, + &oacontrol_set)) { ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 46722f85ef761..971fc330cc35a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2312,10 +2312,15 @@ struct drm_i915_cmd_descriptor { * Describes where to find a register address in the command to check * against the ring's register whitelist. Only valid if flags has the * CMD_DESC_REGISTER bit set. + * + * A non-zero step value implies that the command may access multiple + * registers in sequence (e.g. LRI), in that case step gives the + * distance in dwords between individual offset fields. */ struct { u32 offset; u32 mask; + u32 step; } reg; #define MAX_CMD_DESC_BITMASKS 3 -- GitLab From 4e86f725cebc8164e5f6601707379dd51440269d Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 29 May 2015 16:44:14 +0300 Subject: [PATCH 0113/7006] drm/i915: Extend the parser to check register writes against a mask/value pair. In some cases it might be unnecessary or dangerous to give userspace the right to write arbitrary values to some register, even though it might be desirable to give it control of some of its bits. This patch extends the register whitelist entries to contain a mask/value pair in addition to the register offset. For registers with non-zero mask, any LRM writes and LRI writes where the bits of the immediate given by the mask don't match the specified value will be rejected. This will be used in my next patch to grant userspace partial write access to some sensitive registers. Signed-off-by: Francisco Jerez Reviewed-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 138 ++++++++++++++++-------- drivers/gpu/drm/i915/intel_ringbuffer.h | 5 +- 2 files changed, 96 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 5fc49bbcdb9de..cafa3e2f16fc7 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -395,16 +395,38 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = { /* * Register whitelists, sorted by increasing register offset. + */ + +/* + * An individual whitelist entry granting access to register addr. If + * mask is non-zero the argument of immediate register writes will be + * AND-ed with mask, and the command will be rejected if the result + * doesn't match value. + * + * Registers with non-zero mask are only allowed to be written using + * LRI. + */ +struct drm_i915_reg_descriptor { + u32 addr; + u32 mask; + u32 value; +}; + +/* Convenience macro for adding 32-bit registers. */ +#define REG32(address, ...) \ + { .addr = address, __VA_ARGS__ } + +/* + * Convenience macro for adding 64-bit registers. * * Some registers that userspace accesses are 64 bits. The register * access commands only allow 32-bit accesses. Hence, we have to include * entries for both halves of the 64-bit registers. */ +#define REG64(addr) \ + REG32(addr), REG32(addr + sizeof(u32)) -/* Convenience macro for adding 64-bit registers */ -#define REG64(addr) (addr), (addr + sizeof(u32)) - -static const u32 gen7_render_regs[] = { +static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG64(GPGPU_THREADS_DISPATCHED), REG64(HS_INVOCATION_COUNT), REG64(DS_INVOCATION_COUNT), @@ -417,15 +439,15 @@ static const u32 gen7_render_regs[] = { REG64(CL_PRIMITIVES_COUNT), REG64(PS_INVOCATION_COUNT), REG64(PS_DEPTH_COUNT), - OACONTROL, /* Only allowed for LRI and SRM. See below. */ + REG32(OACONTROL), /* Only allowed for LRI and SRM. See below. */ REG64(MI_PREDICATE_SRC0), REG64(MI_PREDICATE_SRC1), - GEN7_3DPRIM_END_OFFSET, - GEN7_3DPRIM_START_VERTEX, - GEN7_3DPRIM_VERTEX_COUNT, - GEN7_3DPRIM_INSTANCE_COUNT, - GEN7_3DPRIM_START_INSTANCE, - GEN7_3DPRIM_BASE_VERTEX, + REG32(GEN7_3DPRIM_END_OFFSET), + REG32(GEN7_3DPRIM_START_VERTEX), + REG32(GEN7_3DPRIM_VERTEX_COUNT), + REG32(GEN7_3DPRIM_INSTANCE_COUNT), + REG32(GEN7_3DPRIM_START_INSTANCE), + REG32(GEN7_3DPRIM_BASE_VERTEX), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(0)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(1)), REG64(GEN7_SO_NUM_PRIMS_WRITTEN(2)), @@ -434,33 +456,34 @@ static const u32 gen7_render_regs[] = { REG64(GEN7_SO_PRIM_STORAGE_NEEDED(1)), REG64(GEN7_SO_PRIM_STORAGE_NEEDED(2)), REG64(GEN7_SO_PRIM_STORAGE_NEEDED(3)), - GEN7_SO_WRITE_OFFSET(0), - GEN7_SO_WRITE_OFFSET(1), - GEN7_SO_WRITE_OFFSET(2), - GEN7_SO_WRITE_OFFSET(3), - GEN7_L3SQCREG1, - GEN7_L3CNTLREG2, - GEN7_L3CNTLREG3, + REG32(GEN7_SO_WRITE_OFFSET(0)), + REG32(GEN7_SO_WRITE_OFFSET(1)), + REG32(GEN7_SO_WRITE_OFFSET(2)), + REG32(GEN7_SO_WRITE_OFFSET(3)), + REG32(GEN7_L3SQCREG1), + REG32(GEN7_L3CNTLREG2), + REG32(GEN7_L3CNTLREG3), }; -static const u32 gen7_blt_regs[] = { - BCS_SWCTRL, +static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { + REG32(BCS_SWCTRL), }; -static const u32 ivb_master_regs[] = { - FORCEWAKE_MT, - DERRMR, - GEN7_PIPE_DE_LOAD_SL(PIPE_A), - GEN7_PIPE_DE_LOAD_SL(PIPE_B), - GEN7_PIPE_DE_LOAD_SL(PIPE_C), +static const struct drm_i915_reg_descriptor ivb_master_regs[] = { + REG32(FORCEWAKE_MT), + REG32(DERRMR), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_A)), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_B)), + REG32(GEN7_PIPE_DE_LOAD_SL(PIPE_C)), }; -static const u32 hsw_master_regs[] = { - FORCEWAKE_MT, - DERRMR, +static const struct drm_i915_reg_descriptor hsw_master_regs[] = { + REG32(FORCEWAKE_MT), + REG32(DERRMR), }; #undef REG64 +#undef REG32 static u32 gen7_render_get_cmd_length_mask(u32 cmd_header) { @@ -550,14 +573,16 @@ static bool validate_cmds_sorted(struct intel_engine_cs *ring, return ret; } -static bool check_sorted(int ring_id, const u32 *reg_table, int reg_count) +static bool check_sorted(int ring_id, + const struct drm_i915_reg_descriptor *reg_table, + int reg_count) { int i; u32 previous = 0; bool ret = true; for (i = 0; i < reg_count; i++) { - u32 curr = reg_table[i]; + u32 curr = reg_table[i].addr; if (curr < previous) { DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n", @@ -804,18 +829,20 @@ find_cmd(struct intel_engine_cs *ring, return default_desc; } -static bool valid_reg(const u32 *table, int count, u32 addr) +static const struct drm_i915_reg_descriptor * +find_reg(const struct drm_i915_reg_descriptor *table, + int count, u32 addr) { - if (table && count != 0) { + if (table) { int i; for (i = 0; i < count; i++) { - if (table[i] == addr) - return true; + if (table[i].addr == addr) + return &table[i]; } } - return false; + return NULL; } static u32 *vmap_batch(struct drm_i915_gem_object *obj, @@ -961,6 +988,20 @@ static bool check_cmd(const struct intel_engine_cs *ring, for (offset = desc->reg.offset; offset < length; offset += step) { const u32 reg_addr = cmd[offset] & desc->reg.mask; + const struct drm_i915_reg_descriptor *reg = + find_reg(ring->reg_table, ring->reg_count, + reg_addr); + + if (!reg && is_master) + reg = find_reg(ring->master_reg_table, + ring->master_reg_count, + reg_addr); + + if (!reg) { + DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", + reg_addr, *cmd, ring->id); + return false; + } /* * OACONTROL requires some special handling for @@ -982,15 +1023,22 @@ static bool check_cmd(const struct intel_engine_cs *ring, *oacontrol_set = (cmd[offset + 1] != 0); } - if (!valid_reg(ring->reg_table, - ring->reg_count, reg_addr)) { - if (!is_master || - !valid_reg(ring->master_reg_table, - ring->master_reg_count, - reg_addr)) { - DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n", - reg_addr, *cmd, - ring->id); + /* + * Check the value written to the register against the + * allowed mask/value pair given in the whitelist entry. + */ + if (reg->mask) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n", + reg_addr); + return false; + } + + if (desc->cmd.value == MI_LOAD_REGISTER_IMM(1) && + (offset + 2 > length || + (cmd[offset + 1] & reg->mask) != reg->value)) { + DRM_DEBUG_DRIVER("CMD: Rejected LRI to masked register 0x%08X\n", + reg_addr); return false; } } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 39f6dfc0ee549..e539314ae87e0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -118,6 +118,7 @@ struct intel_ringbuffer { }; struct intel_context; +struct drm_i915_reg_descriptor; struct intel_engine_cs { const char *name; @@ -300,14 +301,14 @@ struct intel_engine_cs { /* * Table of registers allowed in commands that read/write registers. */ - const u32 *reg_table; + const struct drm_i915_reg_descriptor *reg_table; int reg_count; /* * Table of registers allowed in commands that read/write registers, but * only from the DRM master. */ - const u32 *master_reg_table; + const struct drm_i915_reg_descriptor *master_reg_table; int master_reg_count; /* -- GitLab From d351f6d94893f3ba98b1b20c5ef44c35fc1da124 Mon Sep 17 00:00:00 2001 From: Francisco Jerez Date: Fri, 29 May 2015 16:44:15 +0300 Subject: [PATCH 0114/7006] drm/i915: Add SCRATCH1 and ROW_CHICKEN3 to the register whitelist. Only bit 27 of SCRATCH1 and bit 6 of ROW_CHICKEN3 are allowed to be set because of security-sensitive bits we don't want userspace to mess with. On HSW hardware the whitelisted bits control whether atomic read-modify-write operations are performed on L3 or on GTI, and when set to L3 (which can be 10x-30x better performing than on GTI, depending on the application) require great care to avoid a system hang, so we currently program them to be handled on GTI by default. Beignet can immediately start taking advantage of this change to enable L3 atomics. Mesa should eventually switch to L3 atomics too, but a number of non-trivial changes are still required so it will continue using GTI atomics for now. Signed-off-by: Francisco Jerez Reviewed-by: Zhigang Gong Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index cafa3e2f16fc7..306d9e4e5cf37 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -463,6 +463,13 @@ static const struct drm_i915_reg_descriptor gen7_render_regs[] = { REG32(GEN7_L3SQCREG1), REG32(GEN7_L3CNTLREG2), REG32(GEN7_L3CNTLREG3), + REG32(HSW_SCRATCH1, + .mask = ~HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE, + .value = 0), + REG32(HSW_ROW_CHICKEN3, + .mask = ~(HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE << 16 | + HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE), + .value = 0), }; static const struct drm_i915_reg_descriptor gen7_blt_regs[] = { -- GitLab From 78ace48cfe6ca226793e46b8c465507efd053bba Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 16:42:15 +0100 Subject: [PATCH 0115/7006] drm/i915: Remove unnecessary () used with WARN() In Linux, macros are usually well done and protect their arguments properly, even avoiding multiple evaluations of the parameters. Extra () are really not needed. Cc: Suketu Shah Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index 5cb8cc18994a3..aae065280d1b4 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -459,7 +459,8 @@ void intel_csr_ucode_fini(struct drm_device *dev) void assert_csr_loaded(struct drm_i915_private *dev_priv) { - WARN((intel_csr_load_status_get(dev_priv) != FW_LOADED), "CSR is not loaded.\n"); + WARN(intel_csr_load_status_get(dev_priv) != FW_LOADED, + "CSR is not loaded.\n"); WARN(!I915_READ(CSR_PROGRAM_BASE), "CSR program storage start is NULL\n"); WARN(!I915_READ(CSR_SSP_BASE), "CSR SSP Base Not fine\n"); -- GitLab From abd41dc93c37abc89fb0470a8195c58f37aa52ac Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 16:42:16 +0100 Subject: [PATCH 0116/7006] drm/i915/skl: Add debug messages at the start/end of DMC firmware loading It's handy to have debug message for the "big" events and this one qualifies IMHO. Also helpful to see what's happening while we're loading the firwmare and how much time it takes. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_csr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index aae065280d1b4..2cf25ee8a2685 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -389,6 +389,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) intel_csr_load_program(dev); fw_loaded = true; + DRM_DEBUG_KMS("Finished loading %s\n", dev_priv->csr.fw_path); out: if (fw_loaded) intel_runtime_pm_put(dev_priv); @@ -422,6 +423,8 @@ void intel_csr_ucode_init(struct drm_device *dev) return; } + DRM_DEBUG_KMS("Loading %s\n", csr->fw_path); + /* * Obtain a runtime pm reference, until CSR is loaded, * to avoid entering runtime-suspend. -- GitLab From caf4e2527599a86f1b7d6c7e13546d80e7e50a7c Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 4 Jun 2015 16:56:18 +0100 Subject: [PATCH 0117/7006] drm/i915: Make sure our labels start at column 0 I noticed one of those and it turned out we have a few lingering around. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++-- drivers/gpu/drm/i915/intel_sprite.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 193ba79e5a41f..9c07098d2e131 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7077,7 +7077,7 @@ static int i965gm_get_display_clock_speed(struct drm_device *dev) return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); - fail: +fail: DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%04x\n", vco, tmp); return 200000; } @@ -7118,7 +7118,7 @@ static int g33_get_display_clock_speed(struct drm_device *dev) return DIV_ROUND_CLOSEST(vco, div_table[cdclk_sel]); - fail: +fail: DRM_ERROR("Unable to determine CDCLK. HPLL VCO=%u kHz, CFGC=0x%08x\n", vco, tmp); return 190476; } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 8193a35388d7a..f5965fb490083 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1189,6 +1189,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs); - out: +out: return ret; } -- GitLab From a37161c0588c0d3ff4afb08ef83106a80bde604e Mon Sep 17 00:00:00 2001 From: Andi Kleen Date: Thu, 16 Apr 2015 14:02:41 -0700 Subject: [PATCH 0118/7006] Kbuild: Add ID files to .gitignore I use GNU id-utils to find code (essentially a database backed grep), which generates an ID file to maintain its data. Add ID to the .gitignore file. Signed-off-by: Andi Kleen Signed-off-by: Michal Marek --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 34d6bad9317b3..98b91fccff45f 100644 --- a/.gitignore +++ b/.gitignore @@ -90,6 +90,9 @@ GRTAGS GSYMS GTAGS +# id-utils files +ID + *.orig *~ \#*# -- GitLab From 0d8041842644cff1183f3d0df429792764aecd3f Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jun 2015 12:52:28 +0100 Subject: [PATCH 0119/7006] drm/i915: Fix build without CONFIG_PM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/i915_debugfs.c: In function ‘i915_runtime_pm_status’: drivers/gpu/drm/i915/i915_debugfs.c:2528:34: error: ‘struct dev_pm_info’ has no member named ‘usage_count’ atomic_read(&dev->dev->power.usage_count)); Regression from commit a6aaec8be22652a808d6e316d4a92e58cb75e986 Author: Damien Lespiau Date: Thu Jun 4 18:23:58 2015 +0100 drm/i915: Add runtime PM's usage_count in i915_runtime_pm_status Signed-off-by: Chris Wilson Cc: Damien Lespiau Cc: Paulo Zanoni Cc: Jani Nikula Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 47d9854434c59..2ad71ef867706 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2490,8 +2490,12 @@ static int i915_runtime_pm_status(struct seq_file *m, void *unused) seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy)); seq_printf(m, "IRQs disabled: %s\n", yesno(!intel_irqs_enabled(dev_priv))); +#ifdef CONFIG_PM seq_printf(m, "Usage count: %d\n", atomic_read(&dev->dev->power.usage_count)); +#else + seq_printf(m, "Device Power Management (CONFIG_PM) disabled\n"); +#endif return 0; } -- GitLab From 21a59991ce0cd9a0b54b135305e3fcf880f2aaf1 Mon Sep 17 00:00:00 2001 From: Jim Davis Date: Mon, 8 Jun 2015 13:19:08 -0700 Subject: [PATCH 0120/7006] scripts/package/Makefile: rpmbuild is needed for rpm targets Before rpm release 4.1, in 2002, either the rpm command or the rpmbuild command could be used in the rpm-pkg or binrpm-pkg targets, and the Makefile chose the rpm command if the rpmbuild command wasn't found. After release 4.1, however, the rpm command could no longer be used in place of the rpmbuild command. As the rpmbuild command is not installed by default, this can lead to failures with the rpm-pkg and binrpm-pkg targets: rpm --define "_builddir ." --target \ x86_64 -bb ./binkernel.spec rpm --target: unknown option scripts/package/Makefile:60: recipe for target 'binrpm-pkg' failed Change the Makefile to use rpmbuild unconditionally to avoid this. Signed-off-by: Jim Davis Signed-off-by: Michal Marek --- scripts/package/Makefile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/scripts/package/Makefile b/scripts/package/Makefile index 99ca6e76eb0a5..8b11d5adec7f5 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -21,10 +21,6 @@ # Note that the rpm-pkg target cannot be used with KBUILD_OUTPUT, # but the binrpm-pkg target can; for some reason O= gets ignored. -# Do we have rpmbuild, otherwise fall back to the older rpm -RPM := $(shell if [ -x "/usr/bin/rpmbuild" ]; then echo rpmbuild; \ - else echo rpm; fi) - # Remove hyphens since they have special meaning in RPM filenames KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE)) # Include only those top-level files that are needed by make, plus the GPL copy @@ -51,7 +47,7 @@ rpm-pkg rpm: FORCE rm -f $(objtree)/.scmversion $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version mv -f $(objtree)/.tmp_version $(objtree)/.version - $(RPM) $(RPMOPTS) --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz + rpmbuild --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz rm $(KERNELPATH).tar.gz kernel.spec # binrpm-pkg @@ -62,7 +58,7 @@ binrpm-pkg: FORCE $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version mv -f $(objtree)/.tmp_version $(objtree)/.version - $(RPM) $(RPMOPTS) --define "_builddir $(objtree)" --target \ + rpmbuild --define "_builddir $(objtree)" --target \ $(UTS_MACHINE) -bb $(objtree)/binkernel.spec rm binkernel.spec -- GitLab From 49e4d842f0d0892c3d26c93a81b9f22c1467030e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 15 Jun 2015 12:23:48 +0100 Subject: [PATCH 0121/7006] drm/i915: Report to userspace if we have a (presumed) working GPU reset In igt, we want to test handling of GPU hangs, both for recovery purposes and for reporting. However, we don't want to inject a genuine GPU hang onto a machine that cannot recover and so be permenantly wedged. Rather than embed heuristics into igt, have the kernel report exactly when it expects the GPU reset to work. This can also be usefully extended in future to indicate different levels of fine-grained resets. Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Tim Gore Cc: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 5 +++++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_uncore.c | 28 ++++++++++++++++++++++------ include/uapi/drm/i915_drm.h | 1 + 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 34248635c36c0..88795d2f1819e 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -163,6 +163,11 @@ static int i915_getparam(struct drm_device *dev, void *data, if (!value) return -ENODEV; break; + case I915_PARAM_HAS_GPU_RESET: + value = i915.enable_hangcheck && + i915.reset && + intel_has_gpu_reset(dev); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 971fc330cc35a..44efb4deccb5d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2594,6 +2594,7 @@ extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); #endif extern int intel_gpu_reset(struct drm_device *dev); +extern bool intel_has_gpu_reset(struct drm_device *dev); extern int i915_reset(struct drm_device *dev); extern unsigned long i915_chipset_val(struct drm_i915_private *dev_priv); extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index a6d8a3ee7750a..4a86cf007aa0b 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1455,20 +1455,36 @@ static int gen6_do_reset(struct drm_device *dev) return ret; } -int intel_gpu_reset(struct drm_device *dev) +static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) { if (INTEL_INFO(dev)->gen >= 6) - return gen6_do_reset(dev); + return gen6_do_reset; else if (IS_GEN5(dev)) - return ironlake_do_reset(dev); + return ironlake_do_reset; else if (IS_G4X(dev)) - return g4x_do_reset(dev); + return g4x_do_reset; else if (IS_G33(dev)) - return g33_do_reset(dev); + return g33_do_reset; else if (INTEL_INFO(dev)->gen >= 3) - return i915_do_reset(dev); + return i915_do_reset; else + return NULL; +} + +int intel_gpu_reset(struct drm_device *dev) +{ + int (*reset)(struct drm_device *); + + reset = intel_get_gpu_reset(dev); + if (reset == NULL) return -ENODEV; + + return reset(dev); +} + +bool intel_has_gpu_reset(struct drm_device *dev) +{ + return intel_get_gpu_reset(dev) != NULL; } void intel_uncore_check_errors(struct drm_device *dev) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index 92d61a7c942a9..f88cc1cac5d98 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -354,6 +354,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_REVISION 32 #define I915_PARAM_SUBSLICE_TOTAL 33 #define I915_PARAM_EU_TOTAL 34 +#define I915_PARAM_HAS_GPU_RESET 35 typedef struct drm_i915_getparam { int param; -- GitLab From 0ddfd20385f2e0b22cb19e7da4a235121755f192 Mon Sep 17 00:00:00 2001 From: Ramalingam C Date: Mon, 15 Jun 2015 20:50:05 +0530 Subject: [PATCH 0122/7006] drm/i915: Restarting the Idleness DRRS in drrs_flush Corrected the documentation on the intel_edp_drrs_flush and intel_edp_drrs_invalidate. And accordingly edp_drrs_flush function is modified to restart the idleness detection after upclocking. v2: Update kerneldoc Signed-off-by: Daniel Vetter (v1) Signed-off-by: Ramalingam C Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f73da99e66b8b..f9e4fa8424503 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5456,13 +5456,12 @@ unlock: } /** - * intel_edp_drrs_invalidate - Invalidate DRRS + * intel_edp_drrs_invalidate - Disable Idleness DRRS * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits * - * When there is a disturbance on screen (due to cursor movement/time - * update etc), DRRS needs to be invalidated, i.e. need to switch to - * high RR. + * This function gets called everytime rendering on the given planes start. + * Hence DRRS needs to be Upclocked, i.e. (LOW_RR -> HIGH_RR). * * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. */ @@ -5487,6 +5486,7 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + /* invalidate means busy screen hence upclock */ if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. @@ -5500,13 +5500,14 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, } /** - * intel_edp_drrs_flush - Flush DRRS + * intel_edp_drrs_flush - Restart Idleness DRRS * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits * - * When there is no movement on screen, DRRS work can be scheduled. - * This DRRS work is responsible for setting relevant registers after a - * timeout of 1 second. + * This function gets called every time rendering on the given planes has + * completed or flip on a crtc is completed. So DRRS should be upclocked + * (LOW_RR -> HIGH_RR). And also Idleness detection should be started again, + * if no other planes are dirty. * * Dirty frontbuffers relevant to DRRS are tracked in busy_frontbuffer_bits. */ @@ -5532,8 +5533,17 @@ void intel_edp_drrs_flush(struct drm_device *dev, pipe = to_intel_crtc(crtc)->pipe; dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; - if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR && - !dev_priv->drrs.busy_frontbuffer_bits) + /* flush means busy screen hence upclock */ + if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) + intel_dp_set_drrs_state(dev_priv->dev, + dev_priv->drrs.dp->attached_connector->panel. + fixed_mode->vrefresh); + + /* + * flush also means no more activity hence schedule downclock, if all + * other fbs are quiescent too + */ + if (!dev_priv->drrs.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->drrs.work, msecs_to_jiffies(1000)); mutex_unlock(&dev_priv->drrs.mutex); -- GitLab From 7cd35277b4b7af2121dbc5534fc112e2b3896ef4 Mon Sep 17 00:00:00 2001 From: Chandra Konduru Date: Wed, 10 Jun 2015 16:16:12 -0700 Subject: [PATCH 0123/7006] drm/i915: Delete duplicate #defines added for DCx Delete the duplicate #defines introduced by: commit 6b457d31ea0465fcadcf6d5044f5f71398954727 Author: A.Sunil Kamath Date: Thu Apr 16 14:22:09 2015 +0530 drm/i915/skl: Implement enable/disable for Display C5 state. Signed-off-by: Chandra Konduru Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c9f9d3d3adbad..a66967fd01977 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7282,12 +7282,6 @@ enum skl_disp_power_wells { #define DC_STATE_EN 0x45504 #define DC_STATE_EN_UPTO_DC5 (1<<0) #define DC_STATE_EN_DC9 (1<<3) - -/* -* SKL DC -*/ -#define DC_STATE_EN 0x45504 -#define DC_STATE_EN_UPTO_DC5 (1<<0) #define DC_STATE_EN_UPTO_DC6 (2<<0) #define DC_STATE_EN_UPTO_DC5_DC6_MASK 0x3 -- GitLab From 4e9a86b6bd335925077dde1006da6838774537d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 11 Jun 2015 16:31:14 +0300 Subject: [PATCH 0124/7006] drm/i915: Actually respect DSPSURF alignment restrictions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently intel_gen4_compute_page_offset() simply picks the closest page boundary below the linear offset. That however may not be suitably aligned to satisfy any hardware specific restrictions. So let's make sure the page boundary we choose is properly aligned. Also to play it a bit safer lets split the remaining linear offset into x and y values instead of just x. This should make no difference for most platforms since we convert the x and y offsets back into a linear offset before feeding them to the hardware. HSW+ are different however and use x and y offsets even with linear buffers, so they might have trouble if either the x or y get too big. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 37 +++++++++++++++++----------- drivers/gpu/drm/i915/intel_drv.h | 3 ++- drivers/gpu/drm/i915/intel_sprite.c | 9 ++++--- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df2383849fc38..1d440e7e0344f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2329,6 +2329,18 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, return 0; } +static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) +{ + if (INTEL_INFO(dev_priv)->gen >= 9) + return 256 * 1024; + else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv)) + return 128 * 1024; + else if (INTEL_INFO(dev_priv)->gen >= 4) + return 4 * 1024; + else + return 64 * 1024; +} + int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, @@ -2346,14 +2358,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, switch (fb->modifier[0]) { case DRM_FORMAT_MOD_NONE: - if (INTEL_INFO(dev)->gen >= 9) - alignment = 256 * 1024; - else if (IS_BROADWATER(dev) || IS_CRESTLINE(dev)) - alignment = 128 * 1024; - else if (INTEL_INFO(dev)->gen >= 4) - alignment = 4 * 1024; - else - alignment = 64 * 1024; + alignment = intel_linear_alignment(dev_priv); break; case I915_FORMAT_MOD_X_TILED: if (INTEL_INFO(dev)->gen >= 9) @@ -2443,7 +2448,8 @@ static void intel_unpin_fb_obj(struct drm_framebuffer *fb, /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel * is assumed to be a power-of-two. */ -unsigned long intel_gen4_compute_page_offset(int *x, int *y, +unsigned long intel_gen4_compute_page_offset(struct drm_i915_private *dev_priv, + int *x, int *y, unsigned int tiling_mode, unsigned int cpp, unsigned int pitch) @@ -2459,12 +2465,13 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y, return tile_rows * pitch * 8 + tiles * 4096; } else { + unsigned int alignment = intel_linear_alignment(dev_priv) - 1; unsigned int offset; offset = *y * pitch + *x * cpp; - *y = 0; - *x = (offset & 4095) / cpp; - return offset & -4096; + *y = (offset & alignment) / pitch; + *x = ((offset & alignment) - *y * pitch) / cpp; + return offset & ~alignment; } } @@ -2733,7 +2740,8 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc, if (INTEL_INFO(dev)->gen >= 4) { intel_crtc->dspaddr_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; @@ -2834,7 +2842,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * pixel_size; intel_crtc->dspaddr_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= intel_crtc->dspaddr_offset; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b28029a1c8f29..c28d1171ea808 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1113,7 +1113,8 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv, void assert_pipe(struct drm_i915_private *dev_priv, enum pipe pipe, bool state); #define assert_pipe_enabled(d, p) assert_pipe(d, p, true) #define assert_pipe_disabled(d, p) assert_pipe(d, p, false) -unsigned long intel_gen4_compute_page_offset(int *x, int *y, +unsigned long intel_gen4_compute_page_offset(struct drm_i915_private *dev_priv, + int *x, int *y, unsigned int tiling_mode, unsigned int bpp, unsigned int pitch); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f5965fb490083..0434cbe1634b5 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -411,7 +411,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, crtc_h--; linear_offset = y * fb->pitches[0] + x * pixel_size; - sprsurf_offset = intel_gen4_compute_page_offset(&x, &y, + sprsurf_offset = intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); @@ -546,7 +547,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * pixel_size; sprsurf_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= sprsurf_offset; @@ -682,7 +684,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, linear_offset = y * fb->pitches[0] + x * pixel_size; dvssurf_offset = - intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode, + intel_gen4_compute_page_offset(dev_priv, + &x, &y, obj->tiling_mode, pixel_size, fb->pitches[0]); linear_offset -= dvssurf_offset; -- GitLab From 985b8bb486e7dd924925898f86fffca546d698db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 11 Jun 2015 16:31:15 +0300 Subject: [PATCH 0125/7006] drm/i915: Align DSPSURF to 128k on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VLV/CHV have problems with 4k aligned linear scanout buffers. The VLV docs got updated at some point to say that we need to align them to 128k, just like we do on gen4. So far I've seen the problem manifest when the stride is an odd multiple of 512 bytes, and the surface address meets the following pattern '(addr & 0xf000) == 0x1000' (also == 0x2000 is problematic on VLV). The result is a starcase effect (so some pages get dropped maybe?), with a few pages here and there clearly getting scannout out at the wrong position. I've not actually been able to reproduce this problem on gen4, so it's not clear of the issue is any way related to the 128k restrictions supposedly inherited from gen4. But let's hope the 128k alignment is sufficient to hide it all. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Reviewed-by: Arun R Murthy Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1d440e7e0344f..e94a9a0a6d91e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2333,7 +2333,8 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) { if (INTEL_INFO(dev_priv)->gen >= 9) return 256 * 1024; - else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv)) + else if (IS_BROADWATER(dev_priv) || IS_CRESTLINE(dev_priv) || + IS_VALLEYVIEW(dev_priv)) return 128 * 1024; else if (INTEL_INFO(dev_priv)->gen >= 4) return 4 * 1024; -- GitLab From 44c5905e8e977b1dd9bb99bcd5686464fa0aa247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 11 Jun 2015 16:31:16 +0300 Subject: [PATCH 0126/7006] drm/i915: Drop the 64k linear scanout alignment on gen2/3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docs don't support the 64k linear scanout alignment we impose on gen2/3. And it really makes no sense since we have no DSPSURF register, so the only thing that the hardware will see is the linear offset which will be just pixel aligned anyway. There is one case where 64k comes into the picture, and that's FBC. The start of the line length buffer corresponds to a 64k aligned address of the uncompressed framebuffer. So if the uncompressed fb is not 64k aligned, the first actually used entry in the line length buffer will not be byte 0. There are 32 extra entries in the line length buffer to account for this extra alignment so we shouldn't have to worry about it when mapping the uncompressed fb to the GTT. Signed-off-by: Ville Syrjälä Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e94a9a0a6d91e..a806f1598a463 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2339,7 +2339,7 @@ static unsigned int intel_linear_alignment(struct drm_i915_private *dev_priv) else if (INTEL_INFO(dev_priv)->gen >= 4) return 4 * 1024; else - return 64 * 1024; + return 0; } int -- GitLab From 31b9df1040a9ac1d4b88e382f16a50b9f0aff9be Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:18 -0300 Subject: [PATCH 0127/7006] drm/i915: print FBC compression status on debugfs We already had a few bugs in the past where FBC was compressing nothing when it was enabled, which makes the feature quite useless. Add this information to debugfs so the test suites can check for regressions in this piece of the code. Our igt/tests/kms_frontbuffer_tracking already has support for this message. v2: - Remove pointless VLV check (Ville). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 5 +++++ drivers/gpu/drm/i915/i915_reg.h | 3 +++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 698c0a2db0674..6c788e434255b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1638,6 +1638,11 @@ static int i915_fbc_status(struct seq_file *m, void *unused) seq_putc(m, '\n'); } + if (INTEL_INFO(dev_priv)->gen >= 7) + seq_printf(m, "Compressing: %s\n", + yesno(I915_READ(FBC_STATUS2) & + FBC_COMPRESSION_MASK)); + intel_runtime_pm_put(dev_priv); return 0; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index a66967fd01977..2261609d1d755 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1951,6 +1951,9 @@ enum skl_disp_power_wells { #define FBC_FENCE_OFF 0x03218 /* BSpec typo has 321Bh */ #define FBC_TAG 0x03300 +#define FBC_STATUS2 0x43214 +#define FBC_COMPRESSION_MASK 0x7ff + #define FBC_LL_SIZE (1536) /* Framebuffer compression for GM45+ */ -- GitLab From 87f5ff0115eed248377f3474834caceca072b9ba Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:19 -0300 Subject: [PATCH 0128/7006] drm/i915: add FBC_ROTATION to enum no_fbc_reason Because we're currently using FBC_UNSUPPORTED_MODE for two different cases. This commit will also allow us to write the next one without hiding information from the user. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6c788e434255b..985e860691b4c 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1632,6 +1632,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused) case FBC_CHIP_DEFAULT: seq_puts(m, "disabled per chip default"); break; + case FBC_ROTATION: + seq_puts(m, "rotation not supported"); + break; default: seq_puts(m, "unknown reason"); } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 617b01f560623..491ef0cfcb0b2 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -926,6 +926,7 @@ struct i915_fbc { FBC_MULTIPLE_PIPES, /* more than one pipe active */ FBC_MODULE_PARAM, FBC_CHIP_DEFAULT, /* disabled by default on this chip */ + FBC_ROTATION, /* rotation is not supported */ } no_fbc_reason; }; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 6abb83432d4d7..43704a48f20ce 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -587,7 +587,7 @@ void intel_fbc_update(struct drm_device *dev) } if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { - if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) + if (set_no_fbc_reason(dev_priv, FBC_ROTATION)) DRM_DEBUG_KMS("Rotation unsupported, disabling\n"); goto out_disable; } -- GitLab From 2e8144a53db50cf3d5b32641346d116f778a9680 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:20 -0300 Subject: [PATCH 0129/7006] drm/i915: unify no_fbc_reason message printing This commit has two main advantages: simplify intel_fbc_update() and deduplicate the strings. v2: - Rebase due to changes on P1. - set_no_fbc_reason() can now return void (Chris). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 49 ++------------------ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 70 +++++++++++++++++++---------- 3 files changed, 51 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 985e860691b4c..35a5defe7e29f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1594,52 +1594,11 @@ static int i915_fbc_status(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); - if (intel_fbc_enabled(dev)) { + if (intel_fbc_enabled(dev)) seq_puts(m, "FBC enabled\n"); - } else { - seq_puts(m, "FBC disabled: "); - switch (dev_priv->fbc.no_fbc_reason) { - case FBC_OK: - seq_puts(m, "FBC actived, but currently disabled in hardware"); - break; - case FBC_UNSUPPORTED: - seq_puts(m, "unsupported by this chipset"); - break; - case FBC_NO_OUTPUT: - seq_puts(m, "no outputs"); - break; - case FBC_STOLEN_TOO_SMALL: - seq_puts(m, "not enough stolen memory"); - break; - case FBC_UNSUPPORTED_MODE: - seq_puts(m, "mode not supported"); - break; - case FBC_MODE_TOO_LARGE: - seq_puts(m, "mode too large"); - break; - case FBC_BAD_PLANE: - seq_puts(m, "FBC unsupported on plane"); - break; - case FBC_NOT_TILED: - seq_puts(m, "scanout buffer not tiled"); - break; - case FBC_MULTIPLE_PIPES: - seq_puts(m, "multiple pipes are enabled"); - break; - case FBC_MODULE_PARAM: - seq_puts(m, "disabled per module param (default off)"); - break; - case FBC_CHIP_DEFAULT: - seq_puts(m, "disabled per chip default"); - break; - case FBC_ROTATION: - seq_puts(m, "rotation not supported"); - break; - default: - seq_puts(m, "unknown reason"); - } - seq_putc(m, '\n'); - } + else + seq_printf(m, "FBC disabled: %s\n", + intel_no_fbc_reason_str(dev_priv->fbc.no_fbc_reason)); if (INTEL_INFO(dev_priv)->gen >= 7) seq_printf(m, "Compressing: %s\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c28d1171ea808..bcafefcf048b0 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1256,6 +1256,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, enum fb_op_origin origin); void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); +const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 43704a48f20ce..1ff288ce84d88 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -432,14 +432,47 @@ void intel_fbc_disable(struct drm_device *dev) dev_priv->fbc.crtc = NULL; } -static bool set_no_fbc_reason(struct drm_i915_private *dev_priv, +const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) +{ + switch (reason) { + case FBC_OK: + return "FBC enabled but currently disabled in hardware"; + case FBC_UNSUPPORTED: + return "unsupported by this chipset"; + case FBC_NO_OUTPUT: + return "no output"; + case FBC_STOLEN_TOO_SMALL: + return "not enough stolen memory"; + case FBC_UNSUPPORTED_MODE: + return "mode incompatible with compression"; + case FBC_MODE_TOO_LARGE: + return "mode too large for compression"; + case FBC_BAD_PLANE: + return "FBC unsupported on plane"; + case FBC_NOT_TILED: + return "framebuffer not tiled or fenced"; + case FBC_MULTIPLE_PIPES: + return "more than one pipe active"; + case FBC_MODULE_PARAM: + return "disabled per module param"; + case FBC_CHIP_DEFAULT: + return "disabled per chip default"; + case FBC_ROTATION: + return "rotation unsupported"; + default: + MISSING_CASE(reason); + return "unknown reason"; + } +} + +static void set_no_fbc_reason(struct drm_i915_private *dev_priv, enum no_fbc_reason reason) { if (dev_priv->fbc.no_fbc_reason == reason) - return false; + return; dev_priv->fbc.no_fbc_reason = reason; - return true; + DRM_DEBUG_KMS("Disabling FBC: %s\n", intel_no_fbc_reason_str(reason)); } static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) @@ -459,8 +492,7 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) if (intel_crtc_active(tmp_crtc) && to_intel_plane_state(tmp_crtc->primary->state)->visible) { if (one_pipe_only && crtc) { - if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES)) - DRM_DEBUG_KMS("more than one pipe active, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); return NULL; } crtc = tmp_crtc; @@ -471,8 +503,7 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) } if (!crtc || crtc->primary->fb == NULL) { - if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT)) - DRM_DEBUG_KMS("no output, disabling\n"); + set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); return NULL; } @@ -516,14 +547,12 @@ void intel_fbc_update(struct drm_device *dev) i915.enable_fbc = 0; if (i915.enable_fbc < 0) { - if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT)) - DRM_DEBUG_KMS("disabled per chip default\n"); + set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT); goto out_disable; } if (!i915.enable_fbc) { - if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM)) - DRM_DEBUG_KMS("fbc disabled per module param\n"); + set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM); goto out_disable; } @@ -547,9 +576,7 @@ void intel_fbc_update(struct drm_device *dev) if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) || (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) { - if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE)) - DRM_DEBUG_KMS("mode incompatible with compression, " - "disabling\n"); + set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE); goto out_disable; } @@ -565,14 +592,12 @@ void intel_fbc_update(struct drm_device *dev) } if (intel_crtc->config->pipe_src_w > max_width || intel_crtc->config->pipe_src_h > max_height) { - if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE)) - DRM_DEBUG_KMS("mode too large for compression, disabling\n"); + set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); goto out_disable; } if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) && intel_crtc->plane != PLANE_A) { - if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE)) - DRM_DEBUG_KMS("plane not A, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); goto out_disable; } @@ -581,14 +606,12 @@ void intel_fbc_update(struct drm_device *dev) */ if (obj->tiling_mode != I915_TILING_X || obj->fence_reg == I915_FENCE_REG_NONE) { - if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED)) - DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_NOT_TILED); goto out_disable; } if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { - if (set_no_fbc_reason(dev_priv, FBC_ROTATION)) - DRM_DEBUG_KMS("Rotation unsupported, disabling\n"); + set_no_fbc_reason(dev_priv, FBC_ROTATION); goto out_disable; } @@ -598,8 +621,7 @@ void intel_fbc_update(struct drm_device *dev) if (i915_gem_stolen_setup_compression(dev, obj->base.size, drm_format_plane_cpp(fb->pixel_format, 0))) { - if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL)) - DRM_DEBUG_KMS("framebuffer too large, disabling compression\n"); + set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; } -- GitLab From d8514d6306ea023f144ac922c4e6e6b283d5b78d Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 12 Jun 2015 14:36:21 -0300 Subject: [PATCH 0130/7006] drm/i915: don't set the FBC plane select bits on HSW+ This commit is just to make the intentions explicit: on HSW+ these bits are MBZ, but since we only support plane A and the macro evaluates to zero when plane A is the parameter, we're not fixing any bug. v2: - Remove useless extra blank like (Chris). - Init dpfc_ctl in another place (Chris). Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 1ff288ce84d88..50ed3332def1e 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -262,7 +262,10 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dev_priv->fbc.enabled = true; - dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl = 0; + if (IS_IVYBRIDGE(dev)) + dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); + if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) dev_priv->fbc.threshold++; -- GitLab From 0904deaf4e6bc1d854ed48255bdb170c7906c8fb Mon Sep 17 00:00:00 2001 From: Mika Kahola Date: Fri, 12 Jun 2015 10:11:32 +0300 Subject: [PATCH 0131/7006] drm/i915: Limit CHV max cdclk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Limit CHV maximum cdclk to 320MHz. v2: Rebase to the latest v3: Clean up of if-else tree Signed-off-by: Mika Kahola Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a806f1598a463..3f4891782cf68 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5271,6 +5271,8 @@ static void intel_update_max_cdclk(struct drm_device *dev) dev_priv->max_cdclk_freq = 540000; else dev_priv->max_cdclk_freq = 675000; + } else if (IS_CHERRYVIEW(dev)) { + dev_priv->max_cdclk_freq = 320000; } else if (IS_VALLEYVIEW(dev)) { dev_priv->max_cdclk_freq = 400000; } else { -- GitLab From e7d66d89bc8bb44f9aab2f4749246214d15a159f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 15 Jun 2015 23:23:54 +0200 Subject: [PATCH 0132/7006] drm/i915: Remove more ilk rc6 remnants Leftover from the big purge commit a561165493e5fec2f74bd3ae0577ed659e44ab7f Author: John Harrison Date: Thu Mar 5 14:03:03 2015 +0000 drm/i915: Remove ironlake rc6 support Cc: John Harrison Cc: Rob Clark Reported-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index d091fec1e1018..32ff034a0875d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4249,12 +4249,8 @@ static void intel_print_rc6_info(struct drm_device *dev, u32 mode) static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) { - /* No RC6 before Ironlake */ - if (INTEL_INFO(dev)->gen < 5) - return 0; - - /* RC6 is only on Ironlake mobile not on desktop */ - if (INTEL_INFO(dev)->gen == 5 && !IS_IRONLAKE_M(dev)) + /* No RC6 before Ironlake and code is gone for ilk. */ + if (INTEL_INFO(dev)->gen < 6) return 0; /* Respect the kernel parameter if it is set */ @@ -4274,10 +4270,6 @@ static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6) return enable_rc6 & mask; } - /* Disable RC6 on Ironlake */ - if (INTEL_INFO(dev)->gen == 5) - return 0; - if (IS_IVYBRIDGE(dev)) return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE); -- GitLab From b27bc5a40f915671eda3ac255734a64153fc91f5 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:40 +0300 Subject: [PATCH 0133/7006] ath10k: dump fw features during probing This should help when analysing problems from users and spot fw api blob problems easier. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 44 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/core.h | 3 ++ drivers/net/wireless/ath/ath10k/debug.c | 9 +++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 59496a90ad5e2..f5db43284b97c 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -103,6 +103,50 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { }, }; +static const char *const ath10k_core_fw_feature_str[] = { + [ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX] = "wmi-mgmt-rx", + [ATH10K_FW_FEATURE_WMI_10X] = "wmi-10.x", + [ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX] = "has-wmi-mgmt-tx", + [ATH10K_FW_FEATURE_NO_P2P] = "no-p2p", + [ATH10K_FW_FEATURE_WMI_10_2] = "wmi-10.2", + [ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT] = "multi-vif-ps", + [ATH10K_FW_FEATURE_WOWLAN_SUPPORT] = "wowlan", + [ATH10K_FW_FEATURE_IGNORE_OTP_RESULT] = "ignore-otp", + [ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING] = "no-4addr-pad", + [ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT] = "skip-clock-init", +}; + +static unsigned int ath10k_core_get_fw_feature_str(char *buf, + size_t buf_len, + enum ath10k_fw_features feat) +{ + if (feat >= ARRAY_SIZE(ath10k_core_fw_feature_str) || + WARN_ON(!ath10k_core_fw_feature_str[feat])) { + return scnprintf(buf, buf_len, "bit%d", feat); + } + + return scnprintf(buf, buf_len, "%s", ath10k_core_fw_feature_str[feat]); +} + +void ath10k_core_get_fw_features_str(struct ath10k *ar, + char *buf, + size_t buf_len) +{ + unsigned int len = 0; + int i; + + for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) { + if (test_bit(i, ar->fw_features)) { + if (len > 0) + len += scnprintf(buf + len, buf_len - len, ","); + + len += ath10k_core_get_fw_feature_str(buf + len, + buf_len - len, + i); + } + } +} + static void ath10k_send_suspend_complete(struct ath10k *ar) { ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot suspend complete\n"); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 78094f23c9dd5..e9f93045fbd86 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -749,6 +749,9 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, enum ath10k_hw_rev hw_rev, const struct ath10k_hif_ops *hif_ops); void ath10k_core_destroy(struct ath10k *ar); +void ath10k_core_get_fw_features_str(struct ath10k *ar, + char *buf, + size_t max_len); int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode); int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt); diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8fa606a9c4dda..8a4edfd36e47a 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -124,7 +124,11 @@ EXPORT_SYMBOL(ath10k_info); void ath10k_print_driver_info(struct ath10k *ar) { - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n", + char fw_features[128]; + + ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); + + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -138,7 +142,8 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.target_version_minor, ar->wmi.op_version, ath10k_cal_mode_str(ar->cal_mode), - ar->max_num_stations); + ar->max_num_stations, + fw_features); ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n", config_enabled(CONFIG_ATH10K_DEBUG), config_enabled(CONFIG_ATH10K_DEBUGFS), -- GitLab From 67c81f5a06ed1474c4f16ad93f4502c760999515 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:41 +0300 Subject: [PATCH 0134/7006] ath10k: print htt op_version upon driver boot HTT version itself isn't sufficient to know what HTT version given firmware blob uses. Hence print the recently introduced HTT op version code. While at it make the info string a bit more consistent and clear. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c index 8a4edfd36e47a..edf6047997a7b 100644 --- a/drivers/net/wireless/ath/ath10k/debug.c +++ b/drivers/net/wireless/ath/ath10k/debug.c @@ -128,7 +128,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ath10k_core_get_fw_features_str(ar, fw_features, sizeof(fw_features)); - ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d features %s\n", + ath10k_info(ar, "%s (0x%08x, 0x%08x%s%s%s) fw %s api %d htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d features %s\n", ar->hw_params.name, ar->target_version, ar->chip_id, @@ -141,6 +141,7 @@ void ath10k_print_driver_info(struct ath10k *ar) ar->htt.target_version_major, ar->htt.target_version_minor, ar->wmi.op_version, + ar->htt.op_version, ath10k_cal_mode_str(ar->cal_mode), ar->max_num_stations, fw_features); -- GitLab From c702534a23d61deaa0565ef0495ab866c06c4325 Mon Sep 17 00:00:00 2001 From: Janusz Dziedzic Date: Mon, 15 Jun 2015 14:46:41 +0300 Subject: [PATCH 0135/7006] ath10k: enable VHT for IBSS Enable VHT support for IBSS, while mac80211/cfg80211 and wpa_supplicant already support this. In my test env, qca988x 2x2 I get: (udp) ath10k-1 >>>> ath10k-2 (server) - speed: 419 Mbits/sec (tcp) ath10k-1 >>>> ath10k-2 (server) - speed: 404 Mbits/sec During tests I used wpa_supplicant (latest git version), which already support IBSS VHT, and choose highest available BW. Also tested with qca6174. Signed-off-by: Janusz Dziedzic Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c48c744acbccc..c6255069e6e06 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6902,6 +6902,8 @@ int ath10k_mac_register(struct ath10k *ar) goto err_free; } + wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); + /* * on LL hardware queues are managed entirely by the FW * so we only advertise to mac we can do the queues thing -- GitLab From aeae5b4cd9185b0dc72f6d6102cf45073bfbc974 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Mon, 15 Jun 2015 14:46:42 +0300 Subject: [PATCH 0136/7006] ath10k: prevent debugfs mmio access crash kernel It was possible to force an out of bounds MMIO read/write via debugfs. E.g. on QCA988X this could be triggered with: echo 0x2080e0 | tee /sys/kernel/debug/ieee80211/*/ath10k/reg_addr cat /sys/kernel/debug/ieee80211/*/ath10k/reg_value BUG: unable to handle kernel paging request at ffffc90001e080e0 IP: [] ioread32+0x40/0x50 ... Call Trace: [] ? ath10k_pci_read32+0x4f/0x70 [ath10k_pci] [] ath10k_reg_value_read+0x90/0xf0 [ath10k_core] [] ? handle_mm_fault+0xa91/0x1050 [] __vfs_read+0x28/0xe0 [] ? security_file_permission+0x84/0xa0 [] ? rw_verify_area+0x53/0x100 [] vfs_read+0x8a/0x140 [] SyS_read+0x49/0xb0 [] ? trace_do_page_fault+0x3c/0xc0 [] system_call_fastpath+0x12/0x71 Reported-by: Ben Greear Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 13 +++++++++++++ drivers/net/wireless/ath/ath10k/pci.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index ea656e011a96e..41765172297ce 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -479,6 +479,12 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value) struct ath10k_pci *ar_pci = ath10k_pci_priv(ar); int ret; + if (unlikely(offset + sizeof(value) > ar_pci->mem_len)) { + ath10k_warn(ar, "refusing to write mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", + offset, offset + sizeof(value), ar_pci->mem_len); + return; + } + ret = ath10k_pci_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake target for write32 of 0x%08x at 0x%08x: %d\n", @@ -496,6 +502,12 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset) u32 val; int ret; + if (unlikely(offset + sizeof(val) > ar_pci->mem_len)) { + ath10k_warn(ar, "refusing to read mmio out of bounds at 0x%08x - 0x%08zx (max 0x%08zx)\n", + offset, offset + sizeof(val), ar_pci->mem_len); + return 0; + } + ret = ath10k_pci_wake(ar); if (ret) { ath10k_warn(ar, "failed to wake target for read32 at 0x%08x: %d\n", @@ -2679,6 +2691,7 @@ static int ath10k_pci_claim(struct ath10k *ar) pci_set_master(pdev); /* Arrange for access to Target SoC registers. */ + ar_pci->mem_len = pci_resource_len(pdev, BAR_NUM); ar_pci->mem = pci_iomap(pdev, BAR_NUM, 0); if (!ar_pci->mem) { ath10k_err(ar, "failed to iomap BAR%d\n", BAR_NUM); diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index d7696ddc03c42..eea0a0170b00f 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -162,6 +162,7 @@ struct ath10k_pci { struct device *dev; struct ath10k *ar; void __iomem *mem; + size_t mem_len; /* * Number of MSI interrupts granted, 0 --> using legacy PCI line -- GitLab From 404d67ef2935c5e41d3d7a403c5fb1c278eff60e Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 15 Jun 2015 14:46:42 +0300 Subject: [PATCH 0137/7006] ath10k: remove unused variable hdr in ath10k_htt_rx_h_undecap() Just found this during code review. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 89eb16b30fc42..7399e45a016ef 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -1201,7 +1201,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, { struct htt_rx_desc *rxd; enum rx_msdu_decap_format decap; - struct ieee80211_hdr *hdr; /* First msdu's decapped header: * [802.11 header] <-- padded to 4 bytes long @@ -1215,7 +1214,6 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, */ rxd = (void *)msdu->data - sizeof(*rxd); - hdr = (void *)rxd->rx_hdr_status; decap = MS(__le32_to_cpu(rxd->msdu_start.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); -- GitLab From d4298a3a8c92a18d375e55feecc60e4eefeb45e3 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 14:46:43 +0300 Subject: [PATCH 0138/7006] ath10k: mac: remove unreachable negative return check wait_event_timeout(), introduced in 'commit 5e3dd157d7e7 ("ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices")' never returns < 0 so the only failure condition to be checked is ==0 (timeout). Further the return type is long not int - an appropriately named variable is added and the assignments fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c6255069e6e06..e17eb75c508ef 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -5566,7 +5566,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, { struct ath10k *ar = hw->priv; bool skip; - int ret; + long time_left; /* mac80211 doesn't care if we really xmit queued frames or not * we'll collect those frames either way if we stop/delete vdevs */ @@ -5578,7 +5578,7 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (ar->state == ATH10K_STATE_WEDGED) goto skip; - ret = wait_event_timeout(ar->htt.empty_tx_wq, ({ + time_left = wait_event_timeout(ar->htt.empty_tx_wq, ({ bool empty; spin_lock_bh(&ar->htt.tx_lock); @@ -5592,9 +5592,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, (empty || skip); }), ATH10K_FLUSH_TIMEOUT_HZ); - if (ret <= 0 || skip) - ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n", - skip, ar->state, ret); + if (time_left == 0 || skip) + ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %ld\n", + skip, ar->state, time_left); skip: mutex_unlock(&ar->conf_mutex); -- GitLab From 71c47df4aa54ee3bfb113a5ae468c8bfb3a6fb7b Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 14:46:43 +0300 Subject: [PATCH 0139/7006] ath10k: txrx: remove unreachable negative return check and fixup type wait_event_timeout(), introduced in 'commit 5e3dd157d7e7 ("ath10k: mac80211 driver for Qualcomm Atheros 802.11ac CQA98xx devices")' never returns < 0 so the only failure condition to be checked is == 0 (timeout). Further the return type is long not int - an appropriately named variable is added and the assignments fixed up. Signed-off-by: Nicholas Mc Guire Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/txrx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c index 826500bb2b1b2..6cf289158840a 100644 --- a/drivers/net/wireless/ath/ath10k/txrx.c +++ b/drivers/net/wireless/ath/ath10k/txrx.c @@ -147,9 +147,9 @@ struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id) static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, const u8 *addr, bool expect_mapped) { - int ret; + long time_left; - ret = wait_event_timeout(ar->peer_mapping_wq, ({ + time_left = wait_event_timeout(ar->peer_mapping_wq, ({ bool mapped; spin_lock_bh(&ar->data_lock); @@ -160,7 +160,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id, test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)); }), 3*HZ); - if (ret <= 0) + if (time_left == 0) return -ETIMEDOUT; return 0; -- GitLab From ce52299ca6ac23222e040284913d1271edc96459 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Fri, 5 Jun 2015 15:08:24 -0700 Subject: [PATCH 0140/7006] drm/i915: Use helper to set CRTC state's mode We need to call drm_atomic_set_mode_for_crtc() rather than copying the mode in manually. As of commit commit 99cf4a29fa24461bbfe22125967188a18383eb5c Author: Daniel Stone Date: Mon May 25 19:11:51 2015 +0100 drm/atomic: Add current-mode blob to CRTC state the helper now also takes care of setting up the mode property blob for us; if we don't use the helper and never setup the mode blob, this will also trigger a failure in drm_atomic_crtc_check() when we have the DRIVER_ATOMIC flag set (i.e., when using the nuclear pageflip support via i915.nuclear_pageflip kernel command line parameter). Cc: Maarten Lankhorst Signed-off-by: Matt Roper Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3f4891782cf68..98bb15ac4c663 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13264,8 +13264,9 @@ intel_modeset_stage_output_state(struct drm_device *dev, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - if (set->mode) - drm_mode_copy(&crtc_state->mode, set->mode); + ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); + if (ret) + return ret; if (set->num_connectors) crtc_state->active = true; -- GitLab From bfae2052265cde825afaba35eb3a4d3889432734 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 17 Jun 2015 12:27:21 -0400 Subject: [PATCH 0141/7006] tools/power turbostat: cpu0 is no longer hard-coded, so update output The --debug option reads a number of per-package MSRs. Previously we explicitly read them on cpu0, but recently turbostat changed to read them on the current "base_cpu". Update the print-out to reflect base_cpu, rather than the hard-coded cpu0. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 323b65edfc970..67162ec6e87b7 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -1157,7 +1157,7 @@ dump_nhm_platform_info(void) get_msr(base_cpu, MSR_NHM_PLATFORM_INFO, &msr); - fprintf(stderr, "cpu0: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", msr); + fprintf(stderr, "cpu%d: MSR_NHM_PLATFORM_INFO: 0x%08llx\n", base_cpu, msr); ratio = (msr >> 40) & 0xFF; fprintf(stderr, "%d * %.0f = %.0f MHz max efficiency frequency\n", @@ -1168,8 +1168,8 @@ dump_nhm_platform_info(void) ratio, bclk, ratio * bclk); get_msr(base_cpu, MSR_IA32_POWER_CTL, &msr); - fprintf(stderr, "cpu0: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n", - msr, msr & 0x2 ? "EN" : "DIS"); + fprintf(stderr, "cpu%d: MSR_IA32_POWER_CTL: 0x%08llx (C1E auto-promotion: %sabled)\n", + base_cpu, msr, msr & 0x2 ? "EN" : "DIS"); return; } @@ -1182,7 +1182,7 @@ dump_hsw_turbo_ratio_limits(void) get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT2, &msr); - fprintf(stderr, "cpu0: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", msr); + fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT2: 0x%08llx\n", base_cpu, msr); ratio = (msr >> 8) & 0xFF; if (ratio) @@ -1204,7 +1204,7 @@ dump_ivt_turbo_ratio_limits(void) get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT1, &msr); - fprintf(stderr, "cpu0: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", msr); + fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT1: 0x%08llx\n", base_cpu, msr); ratio = (msr >> 56) & 0xFF; if (ratio) @@ -1256,7 +1256,7 @@ dump_nhm_turbo_ratio_limits(void) get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr); - fprintf(stderr, "cpu0: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", msr); + fprintf(stderr, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n", base_cpu, msr); ratio = (msr >> 56) & 0xFF; if (ratio) @@ -1312,8 +1312,8 @@ dump_knl_turbo_ratio_limits(void) get_msr(base_cpu, MSR_NHM_TURBO_RATIO_LIMIT, &msr); - fprintf(stderr, "cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", - msr); + fprintf(stderr, "cpu%d: MSR_NHM_TURBO_RATIO_LIMIT: 0x%08llx\n", + base_cpu, msr); /** * Turbo encoding in KNL is as follows: @@ -1371,7 +1371,7 @@ dump_nhm_cst_cfg(void) #define SNB_C1_AUTO_UNDEMOTE (1UL << 27) #define SNB_C3_AUTO_UNDEMOTE (1UL << 28) - fprintf(stderr, "cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", msr); + fprintf(stderr, "cpu%d: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x%08llx", base_cpu, msr); fprintf(stderr, " (%s%s%s%s%slocked: pkg-cstate-limit=%d: %s)\n", (msr & SNB_C3_AUTO_UNDEMOTE) ? "UNdemote-C3, " : "", -- GitLab From 6fb3143b561c4a7865e5513eeb02d42ef38e8173 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 17 Jun 2015 16:23:45 -0400 Subject: [PATCH 0142/7006] tools/power turbostat: dump CONFIG_TDP Config TDP is a feature that allows parts to be configured for different thermal limits after they have left the factory. This can have an effect on the operation of the part, particularly in determiniing... Max Non-turbo Ratio Turbo Activation Ratio Signed-off-by: Len Brown --- arch/x86/include/uapi/asm/msr-index.h | 6 +++ tools/power/x86/turbostat/turbostat.c | 78 ++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h index 3c6bb342a48f1..872b592d86b17 100644 --- a/arch/x86/include/uapi/asm/msr-index.h +++ b/arch/x86/include/uapi/asm/msr-index.h @@ -169,6 +169,12 @@ #define MSR_PP1_ENERGY_STATUS 0x00000641 #define MSR_PP1_POLICY 0x00000642 +#define MSR_CONFIG_TDP_NOMINAL 0x00000648 +#define MSR_CONFIG_TDP_LEVEL_1 0x00000649 +#define MSR_CONFIG_TDP_LEVEL_2 0x0000064A +#define MSR_CONFIG_TDP_CONTROL 0x0000064B +#define MSR_TURBO_ACTIVATION_RATIO 0x0000064C + #define MSR_PKG_WEIGHTED_CORE_C0_RES 0x00000658 #define MSR_PKG_ANY_CORE_C0_RES 0x00000659 #define MSR_PKG_ANY_GFXE_C0_RES 0x0000065A diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 67162ec6e87b7..5a793bed453a3 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -1384,6 +1384,49 @@ dump_nhm_cst_cfg(void) return; } +static void +dump_config_tdp(void) +{ + unsigned long long msr; + + get_msr(base_cpu, MSR_CONFIG_TDP_NOMINAL, &msr); + fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_NOMINAL: 0x%08llx", base_cpu, msr); + fprintf(stderr, " (base_ratio=%d)\n", (unsigned int)msr & 0xEF); + + get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_1, &msr); + fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_LEVEL_1: 0x%08llx (", base_cpu, msr); + if (msr) { + fprintf(stderr, "PKG_MIN_PWR_LVL1=%d ", (unsigned int)(msr >> 48) & 0xEFFF); + fprintf(stderr, "PKG_MAX_PWR_LVL1=%d ", (unsigned int)(msr >> 32) & 0xEFFF); + fprintf(stderr, "LVL1_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF); + fprintf(stderr, "PKG_TDP_LVL1=%d", (unsigned int)(msr) & 0xEFFF); + } + fprintf(stderr, ")\n"); + + get_msr(base_cpu, MSR_CONFIG_TDP_LEVEL_2, &msr); + fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_LEVEL_2: 0x%08llx (", base_cpu, msr); + if (msr) { + fprintf(stderr, "PKG_MIN_PWR_LVL2=%d ", (unsigned int)(msr >> 48) & 0xEFFF); + fprintf(stderr, "PKG_MAX_PWR_LVL2=%d ", (unsigned int)(msr >> 32) & 0xEFFF); + fprintf(stderr, "LVL2_RATIO=%d ", (unsigned int)(msr >> 16) & 0xEF); + fprintf(stderr, "PKG_TDP_LVL2=%d", (unsigned int)(msr) & 0xEFFF); + } + fprintf(stderr, ")\n"); + + get_msr(base_cpu, MSR_CONFIG_TDP_CONTROL, &msr); + fprintf(stderr, "cpu%d: MSR_CONFIG_TDP_CONTROL: 0x%08llx (", base_cpu, msr); + if ((msr) & 0x3) + fprintf(stderr, "TDP_LEVEL=%d ", (unsigned int)(msr) & 0x3); + fprintf(stderr, " lock=%d", (unsigned int)(msr >> 31) & 1); + fprintf(stderr, ")\n"); + + get_msr(base_cpu, MSR_TURBO_ACTIVATION_RATIO, &msr); + fprintf(stderr, "cpu%d: MSR_TURBO_ACTIVATION_RATIO: 0x%08llx (", base_cpu, msr); + fprintf(stderr, "MAX_NON_TURBO_RATIO=%d", (unsigned int)(msr) & 0xEF); + fprintf(stderr, " lock=%d", (unsigned int)(msr >> 31) & 1); + fprintf(stderr, ")\n"); +} + void free_all_buffers(void) { CPU_FREE(cpu_present_set); @@ -1873,6 +1916,36 @@ int has_knl_turbo_ratio_limit(unsigned int family, unsigned int model) return 0; } } +int has_config_tdp(unsigned int family, unsigned int model) +{ + if (!genuine_intel) + return 0; + + if (family != 6) + return 0; + + switch (model) { + case 0x3A: /* IVB */ + case 0x3E: /* IVB Xeon */ + + case 0x3C: /* HSW */ + case 0x3F: /* HSX */ + case 0x45: /* HSW */ + case 0x46: /* HSW */ + case 0x3D: /* BDW */ + case 0x47: /* BDW */ + case 0x4F: /* BDX */ + case 0x56: /* BDX-DE */ + case 0x4E: /* SKL */ + case 0x5E: /* SKL */ + + case 0x57: /* Knights Landing */ + return 1; + default: + return 0; + } +} + static void dump_cstate_pstate_config_info(family, model) { @@ -1893,6 +1966,9 @@ dump_cstate_pstate_config_info(family, model) if (has_knl_turbo_ratio_limit(family, model)) dump_knl_turbo_ratio_limits(); + if (has_config_tdp(family, model)) + dump_config_tdp(); + dump_nhm_cst_cfg(); } @@ -3014,7 +3090,7 @@ int get_and_dump_counters(void) } void print_version() { - fprintf(stderr, "turbostat version 4.7 27-May, 2015" + fprintf(stderr, "turbostat version 4.7 17-June, 2015" " - Len Brown \n"); } -- GitLab From b0a08bec96318be54db97c3f0b9e37b52561f9ea Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Thu, 18 Jun 2015 11:00:55 +0530 Subject: [PATCH 0143/7006] drm/i915/bxt: eDP Panel Power sequencing Changes for BXT - added a IS_BROXTON check to use the macro related to PPS registers for BXT. BXT does not have PP_DIV register. Making changes to handle this. Second set of PPS registers have been defined but will be used when VBT provides a selection between the 2 sets of registers. v2: [Jani] Added 2nd set of PPS registers and the macro Jani's review comments - remove reference in i915_suspend.c - Use BXT PP macro Squashing all PPS related patches into one. v3: Jani's review comments addressed - Use pp_ctl instead of pp - ironlake_get_pp_control() is not required for BXT - correct the use of && in the print statement - drop the shift in the print statement v4: Jani's comments - modify ironlake_get_pp_control() - dont set unlock key for bxt v5: Sonika's comments addressed - check alignment - move pp_ctrl_reg write (after ironlake_get_pp_control()) to !IS_BROXTON case. - check before subtracting 1 for t11_t12 Signed-off-by: Vandana Kannan Signed-off-by: A.Sunil Kamath Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 13 ++++++ drivers/gpu/drm/i915/intel_dp.c | 82 ++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 2261609d1d755..c154a7b732cdc 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -6391,6 +6391,8 @@ enum skl_disp_power_wells { #define PCH_PP_CONTROL 0xc7204 #define PANEL_UNLOCK_REGS (0xabcd << 16) #define PANEL_UNLOCK_MASK (0xffff << 16) +#define BXT_POWER_CYCLE_DELAY_MASK (0x1f0) +#define BXT_POWER_CYCLE_DELAY_SHIFT 4 #define EDP_FORCE_VDD (1 << 3) #define EDP_BLC_ENABLE (1 << 2) #define PANEL_POWER_RESET (1 << 1) @@ -6419,6 +6421,17 @@ enum skl_disp_power_wells { #define PANEL_POWER_CYCLE_DELAY_MASK (0x1f) #define PANEL_POWER_CYCLE_DELAY_SHIFT 0 +/* BXT PPS changes - 2nd set of PPS registers */ +#define _BXT_PP_STATUS2 0xc7300 +#define _BXT_PP_CONTROL2 0xc7304 +#define _BXT_PP_ON_DELAYS2 0xc7308 +#define _BXT_PP_OFF_DELAYS2 0xc730c + +#define BXT_PP_STATUS(n) ((!n) ? PCH_PP_STATUS : _BXT_PP_STATUS2) +#define BXT_PP_CONTROL(n) ((!n) ? PCH_PP_CONTROL : _BXT_PP_CONTROL2) +#define BXT_PP_ON_DELAYS(n) ((!n) ? PCH_PP_ON_DELAYS : _BXT_PP_ON_DELAYS2) +#define BXT_PP_OFF_DELAYS(n) ((!n) ? PCH_PP_OFF_DELAYS : _BXT_PP_OFF_DELAYS2) + #define PCH_DP_B 0xe4100 #define PCH_DPB_AUX_CH_CTL 0xe4110 #define PCH_DPB_AUX_CH_DATA1 0xe4114 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index f9e4fa8424503..2e6f23890dbfc 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -567,7 +567,9 @@ static u32 _pp_ctrl_reg(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (HAS_PCH_SPLIT(dev)) + if (IS_BROXTON(dev)) + return BXT_PP_CONTROL(0); + else if (HAS_PCH_SPLIT(dev)) return PCH_PP_CONTROL; else return VLV_PIPE_PP_CONTROL(vlv_power_sequencer_pipe(intel_dp)); @@ -577,7 +579,9 @@ static u32 _pp_stat_reg(struct intel_dp *intel_dp) { struct drm_device *dev = intel_dp_to_dev(intel_dp); - if (HAS_PCH_SPLIT(dev)) + if (IS_BROXTON(dev)) + return BXT_PP_STATUS(0); + else if (HAS_PCH_SPLIT(dev)) return PCH_PP_STATUS; else return VLV_PIPE_PP_STATUS(vlv_power_sequencer_pipe(intel_dp)); @@ -1703,8 +1707,10 @@ static u32 ironlake_get_pp_control(struct intel_dp *intel_dp) lockdep_assert_held(&dev_priv->pps_mutex); control = I915_READ(_pp_ctrl_reg(intel_dp)); - control &= ~PANEL_UNLOCK_MASK; - control |= PANEL_UNLOCK_REGS; + if (!IS_BROXTON(dev)) { + control &= ~PANEL_UNLOCK_MASK; + control |= PANEL_UNLOCK_REGS; + } return control; } @@ -5093,8 +5099,8 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; struct edp_power_seq cur, vbt, spec, *final = &intel_dp->pps_delays; - u32 pp_on, pp_off, pp_div, pp; - int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg; + u32 pp_on, pp_off, pp_div = 0, pp_ctl = 0; + int pp_ctrl_reg, pp_on_reg, pp_off_reg, pp_div_reg = 0; lockdep_assert_held(&dev_priv->pps_mutex); @@ -5102,7 +5108,16 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, if (final->t11_t12 != 0) return; - if (HAS_PCH_SPLIT(dev)) { + if (IS_BROXTON(dev)) { + /* + * TODO: BXT has 2 sets of PPS registers. + * Correct Register for Broxton need to be identified + * using VBT. hardcoding for now + */ + pp_ctrl_reg = BXT_PP_CONTROL(0); + pp_on_reg = BXT_PP_ON_DELAYS(0); + pp_off_reg = BXT_PP_OFF_DELAYS(0); + } else if (HAS_PCH_SPLIT(dev)) { pp_ctrl_reg = PCH_PP_CONTROL; pp_on_reg = PCH_PP_ON_DELAYS; pp_off_reg = PCH_PP_OFF_DELAYS; @@ -5118,12 +5133,14 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, /* Workaround: Need to write PP_CONTROL with the unlock key as * the very first thing. */ - pp = ironlake_get_pp_control(intel_dp); - I915_WRITE(pp_ctrl_reg, pp); + pp_ctl = ironlake_get_pp_control(intel_dp); pp_on = I915_READ(pp_on_reg); pp_off = I915_READ(pp_off_reg); - pp_div = I915_READ(pp_div_reg); + if (!IS_BROXTON(dev)) { + I915_WRITE(pp_ctrl_reg, pp_ctl); + pp_div = I915_READ(pp_div_reg); + } /* Pull timing values out of registers */ cur.t1_t3 = (pp_on & PANEL_POWER_UP_DELAY_MASK) >> @@ -5138,8 +5155,17 @@ intel_dp_init_panel_power_sequencer(struct drm_device *dev, cur.t10 = (pp_off & PANEL_POWER_DOWN_DELAY_MASK) >> PANEL_POWER_DOWN_DELAY_SHIFT; - cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> + if (IS_BROXTON(dev)) { + u16 tmp = (pp_ctl & BXT_POWER_CYCLE_DELAY_MASK) >> + BXT_POWER_CYCLE_DELAY_SHIFT; + if (tmp > 0) + cur.t11_t12 = (tmp - 1) * 1000; + else + cur.t11_t12 = 0; + } else { + cur.t11_t12 = ((pp_div & PANEL_POWER_CYCLE_DELAY_MASK) >> PANEL_POWER_CYCLE_DELAY_SHIFT) * 1000; + } DRM_DEBUG_KMS("cur t1_t3 %d t8 %d t9 %d t10 %d t11_t12 %d\n", cur.t1_t3, cur.t8, cur.t9, cur.t10, cur.t11_t12); @@ -5196,13 +5222,23 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, struct drm_i915_private *dev_priv = dev->dev_private; u32 pp_on, pp_off, pp_div, port_sel = 0; int div = HAS_PCH_SPLIT(dev) ? intel_pch_rawclk(dev) : intel_hrawclk(dev); - int pp_on_reg, pp_off_reg, pp_div_reg; + int pp_on_reg, pp_off_reg, pp_div_reg = 0, pp_ctrl_reg; enum port port = dp_to_dig_port(intel_dp)->port; const struct edp_power_seq *seq = &intel_dp->pps_delays; lockdep_assert_held(&dev_priv->pps_mutex); - if (HAS_PCH_SPLIT(dev)) { + if (IS_BROXTON(dev)) { + /* + * TODO: BXT has 2 sets of PPS registers. + * Correct Register for Broxton need to be identified + * using VBT. hardcoding for now + */ + pp_ctrl_reg = BXT_PP_CONTROL(0); + pp_on_reg = BXT_PP_ON_DELAYS(0); + pp_off_reg = BXT_PP_OFF_DELAYS(0); + + } else if (HAS_PCH_SPLIT(dev)) { pp_on_reg = PCH_PP_ON_DELAYS; pp_off_reg = PCH_PP_OFF_DELAYS; pp_div_reg = PCH_PP_DIVISOR; @@ -5228,9 +5264,16 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT); /* Compute the divisor for the pp clock, simply match the Bspec * formula. */ - pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; - pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) - << PANEL_POWER_CYCLE_DELAY_SHIFT); + if (IS_BROXTON(dev)) { + pp_div = I915_READ(pp_ctrl_reg); + pp_div &= ~BXT_POWER_CYCLE_DELAY_MASK; + pp_div |= (DIV_ROUND_UP((seq->t11_t12 + 1), 1000) + << BXT_POWER_CYCLE_DELAY_SHIFT); + } else { + pp_div = ((100 * div)/2 - 1) << PP_REFERENCE_DIVIDER_SHIFT; + pp_div |= (DIV_ROUND_UP(seq->t11_t12, 1000) + << PANEL_POWER_CYCLE_DELAY_SHIFT); + } /* Haswell doesn't have any port selection bits for the panel * power sequencer any more. */ @@ -5247,11 +5290,16 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev, I915_WRITE(pp_on_reg, pp_on); I915_WRITE(pp_off_reg, pp_off); - I915_WRITE(pp_div_reg, pp_div); + if (IS_BROXTON(dev)) + I915_WRITE(pp_ctrl_reg, pp_div); + else + I915_WRITE(pp_div_reg, pp_div); DRM_DEBUG_KMS("panel power sequencer register settings: PP_ON %#x, PP_OFF %#x, PP_DIV %#x\n", I915_READ(pp_on_reg), I915_READ(pp_off_reg), + IS_BROXTON(dev) ? + (I915_READ(pp_ctrl_reg) & BXT_POWER_CYCLE_DELAY_MASK) : I915_READ(pp_div_reg)); } -- GitLab From 7fd2d26921d1dd70732d8765d714ec3a023a3ca9 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 18 Jun 2015 12:51:40 +0300 Subject: [PATCH 0144/7006] drm/i915: Reset request handling for gen8+ In order for gen8+ hardware to guarantee that no context switch takes place during engine reset and that current context is properly saved, the driver needs to notify and query hw before commencing with reset. There are gpu hangs where the engine gets so stuck that it never will report to be ready for reset. We could proceed with reset anyway, but with some hangs with skl, the forced gpu reset will result in a system hang. By inspecting the unreadiness for reset seems to correlate with the probable system hang. We will only proceed with reset if all engines report that they are ready for reset. If root cause for system hang is found and can be worked around with another means, we can reconsider if we can reinstate full reset for unreadiness case. v2: -EIO, Recovery, gen8 (Chris, Tomas, Daniel) v3: updated commit msg v4: timeout_ms, simpler error path (Chris) References: https://bugs.freedesktop.org/show_bug.cgi?id=89959 References: https://bugs.freedesktop.org/show_bug.cgi?id=90854 Testcase: igt/gem_concurrent_blit/prw-blt-overwrite-source-read-rcs-forked Testcase: igt/gem_concurrent_blit/gtt-blt-overwrite-source-read-rcs-forked Cc: Chris Wilson Cc: Daniel Vetter Cc: Tomas Elf Reviewed-by: Chris Wilson Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 3 ++ drivers/gpu/drm/i915/intel_uncore.c | 43 ++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c154a7b732cdc..64caa470f2c6c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1461,6 +1461,9 @@ enum skl_disp_power_wells { #define RING_MAX_IDLE(base) ((base)+0x54) #define RING_HWS_PGA(base) ((base)+0x80) #define RING_HWS_PGA_GEN6(base) ((base)+0x2080) +#define RING_RESET_CTL(base) ((base)+0xd0) +#define RESET_CTL_REQUEST_RESET (1 << 0) +#define RESET_CTL_READY_TO_RESET (1 << 1) #define HSW_GTT_CACHE_EN 0x4024 #define GTT_CACHE_EN_ALL 0xF0007FFF diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 4a86cf007aa0b..160a47a9bdd97 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1455,9 +1455,50 @@ static int gen6_do_reset(struct drm_device *dev) return ret; } +static int wait_for_register(struct drm_i915_private *dev_priv, + const u32 reg, + const u32 mask, + const u32 value, + const unsigned long timeout_ms) +{ + return wait_for((I915_READ(reg) & mask) == value, timeout_ms); +} + +static int gen8_do_reset(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_engine_cs *engine; + int i; + + for_each_ring(engine, dev_priv, i) { + I915_WRITE(RING_RESET_CTL(engine->mmio_base), + _MASKED_BIT_ENABLE(RESET_CTL_REQUEST_RESET)); + + if (wait_for_register(dev_priv, + RING_RESET_CTL(engine->mmio_base), + RESET_CTL_READY_TO_RESET, + RESET_CTL_READY_TO_RESET, + 700)) { + DRM_ERROR("%s: reset request timeout\n", engine->name); + goto not_ready; + } + } + + return gen6_do_reset(dev); + +not_ready: + for_each_ring(engine, dev_priv, i) + I915_WRITE(RING_RESET_CTL(engine->mmio_base), + _MASKED_BIT_DISABLE(RESET_CTL_REQUEST_RESET)); + + return -EIO; +} + static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) { - if (INTEL_INFO(dev)->gen >= 6) + if (INTEL_INFO(dev)->gen >= 8) + return gen8_do_reset; + else if (INTEL_INFO(dev)->gen >= 6) return gen6_do_reset; else if (IS_GEN5(dev)) return ironlake_do_reset; -- GitLab From fbb35c1981012c72adff8f09f09005a8900a6dfd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 19 Jun 2015 21:17:42 +0200 Subject: [PATCH 0145/7006] drm/i915: Update DRIVER_DATE to 20150619 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 491ef0cfcb0b2..290017857c6da 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150522" +#define DRIVER_DATE "20150619" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- GitLab From b359283a035e44a6c760244e14af86cf1f62ef67 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:38 +0200 Subject: [PATCH 0146/7006] drm/i915: Use crtc state in intel_modeset_pipe_config Grabbing crtc state from atomic state is a lot more involved, and make sure connectors are added before calling this function. Move check_digital_port_conflicts to intel_modeset_checks, it's only useful to check it on a modeset. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 39 +++++++++++----------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 98bb15ac4c663..a483a65f07575 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12056,10 +12056,9 @@ clear_intel_crtc_state(struct intel_crtc_state *crtc_state) static int intel_modeset_pipe_config(struct drm_crtc *crtc, - struct drm_atomic_state *state) + struct intel_crtc_state *pipe_config) { - struct drm_crtc_state *crtc_state; - struct intel_crtc_state *pipe_config; + struct drm_atomic_state *state = pipe_config->base.state; struct intel_encoder *encoder; struct drm_connector *connector; struct drm_connector_state *connector_state; @@ -12072,26 +12071,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, return -EINVAL; } - if (!check_digital_port_conflicts(state)) { - DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); - return -EINVAL; - } - - crtc_state = drm_atomic_get_existing_crtc_state(state, crtc); - if (WARN_ON(!crtc_state)) - return -EINVAL; - - pipe_config = to_intel_crtc_state(crtc_state); - - /* - * XXX: Add all connectors to make the crtc state match the encoders. - */ - if (!needs_modeset(&pipe_config->base)) { - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ret; - } - clear_intel_crtc_state(pipe_config); pipe_config->cpu_transcoder = @@ -12919,6 +12898,11 @@ static int intel_modeset_checks(struct drm_atomic_state *state) struct drm_device *dev = state->dev; int ret; + if (!check_digital_port_conflicts(state)) { + DRM_DEBUG_KMS("rejecting conflicting digital port configuration\n"); + return -EINVAL; + } + /* * See if the config requires any additional preparation, e.g. * to adjust global state with pipes off. We need to do this @@ -12965,7 +12949,14 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (!crtc_state->enable) continue; - ret = intel_modeset_pipe_config(crtc, state); + if (!needs_modeset(crtc_state)) { + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; + } + + ret = intel_modeset_pipe_config(crtc, + to_intel_crtc_state(crtc_state)); if (ret) return ret; -- GitLab From 133b0d128be39e308ccd3b3d765c31ebdbf5380e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:39 +0200 Subject: [PATCH 0147/7006] drm/i915: Clean up intel_atomic_setup_scalers slightly. Get rid of a whole lot of ternary operators and assign the index in scaler_id, instead of the id. They're the same thing. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 21 +++++++++++---------- drivers/gpu/drm/i915/intel_display.c | 2 -- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 4df6d2d7a9c8e..041bff5046291 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -309,15 +309,23 @@ int intel_atomic_setup_scalers(struct drm_device *dev, /* walkthrough scaler_users bits and start assigning scalers */ for (i = 0; i < sizeof(scaler_state->scaler_users) * 8; i++) { int *scaler_id; + const char *name; + int idx; /* skip if scaler not required */ if (!(scaler_state->scaler_users & (1 << i))) continue; if (i == SKL_CRTC_INDEX) { + name = "CRTC"; + idx = intel_crtc->base.base.id; + /* panel fitter case: assign as a crtc scaler */ scaler_id = &scaler_state->scaler_id; } else { + name = "PLANE"; + idx = plane->base.id; + if (!drm_state) continue; @@ -356,23 +364,16 @@ int intel_atomic_setup_scalers(struct drm_device *dev, for (j = 0; j < intel_crtc->num_scalers; j++) { if (!scaler_state->scalers[j].in_use) { scaler_state->scalers[j].in_use = 1; - *scaler_id = scaler_state->scalers[j].id; + *scaler_id = j; DRM_DEBUG_KMS("Attached scaler id %u.%u to %s:%d\n", - intel_crtc->pipe, - i == SKL_CRTC_INDEX ? scaler_state->scaler_id : - plane_state->scaler_id, - i == SKL_CRTC_INDEX ? "CRTC" : "PLANE", - i == SKL_CRTC_INDEX ? intel_crtc->base.base.id : - plane->base.id); + intel_crtc->pipe, *scaler_id, name, idx); break; } } } if (WARN_ON(*scaler_id < 0)) { - DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", - i == SKL_CRTC_INDEX ? "CRTC" : "PLANE", - i == SKL_CRTC_INDEX ? intel_crtc->base.base.id:plane->base.id); + DRM_DEBUG_KMS("Cannot find scaler for %s:%d\n", name, idx); continue; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a483a65f07575..df301cdb6a95e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14070,8 +14070,6 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr for (i = 0; i < intel_crtc->num_scalers; i++) { intel_scaler = &scaler_state->scalers[i]; intel_scaler->in_use = 0; - intel_scaler->id = i; - intel_scaler->mode = PS_SCALER_MODE_DYN; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bcafefcf048b0..02b18a173472b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -293,7 +293,6 @@ struct intel_initial_plane_config { #define SKL_MAX_DST_H 4096 struct intel_scaler { - int id; int in_use; uint32_t mode; }; -- GitLab From 6d3a1ce7dc1a125a40d496e924e8e478560eb42f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:40 +0200 Subject: [PATCH 0148/7006] drm/i915: Add a simple atomic crtc check function, v2. Move the check for encoder cloning here. Changes since v1: - Remove was/is crtc_disabled. (mattrope) - Rename function to intel_crtc_atomic_check. (mattrope) Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 5 +- drivers/gpu/drm/i915/intel_display.c | 126 +++++++++++++++------------ 2 files changed, 75 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 041bff5046291..6ab71ea928192 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -100,7 +100,10 @@ int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - /* FIXME: move to crtc atomic check function once it is ready */ + /* + * FIXME: move to crtc atomic check function once this is + * more atomic friendly. + */ ret = intel_atomic_setup_scalers(dev, nuclear_crtc, crtc_state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df301cdb6a95e..df13769cf0484 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11673,11 +11673,82 @@ retry: return ret; } +static bool encoders_cloneable(const struct intel_encoder *a, + const struct intel_encoder *b) +{ + /* masks could be asymmetric, so check both ways */ + return a == b || (a->cloneable & (1 << b->type) && + b->cloneable & (1 << a->type)); +} + +static bool check_single_encoder_cloning(struct drm_atomic_state *state, + struct intel_crtc *crtc, + struct intel_encoder *encoder) +{ + struct intel_encoder *source_encoder; + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; + + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != &crtc->base) + continue; + + source_encoder = + to_intel_encoder(connector_state->best_encoder); + if (!encoders_cloneable(encoder, source_encoder)) + return false; + } + + return true; +} + +static bool check_encoder_cloning(struct drm_atomic_state *state, + struct intel_crtc *crtc) +{ + struct intel_encoder *encoder; + struct drm_connector *connector; + struct drm_connector_state *connector_state; + int i; + + for_each_connector_in_state(state, connector, connector_state, i) { + if (connector_state->crtc != &crtc->base) + continue; + + encoder = to_intel_encoder(connector_state->best_encoder); + if (!check_single_encoder_cloning(state, crtc, encoder)) + return false; + } + + return true; +} + +static int intel_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_atomic_state *state = crtc_state->state; + int idx = crtc->base.id; + bool mode_changed = needs_modeset(crtc_state); + + if (mode_changed && !check_encoder_cloning(state, intel_crtc)) { + DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); + return -EINVAL; + } + + I915_STATE_WARN(crtc->state->active != intel_crtc->active, + "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", + idx, crtc->state->active, intel_crtc->active); + + return 0; +} + static const struct drm_crtc_helper_funcs intel_helper_funcs = { .mode_set_base_atomic = intel_pipe_set_base_atomic, .load_lut = intel_crtc_load_lut, .atomic_begin = intel_begin_crtc_commit, .atomic_flush = intel_finish_crtc_commit, + .atomic_check = intel_crtc_atomic_check, }; /** @@ -11930,56 +12001,6 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, } } -static bool encoders_cloneable(const struct intel_encoder *a, - const struct intel_encoder *b) -{ - /* masks could be asymmetric, so check both ways */ - return a == b || (a->cloneable & (1 << b->type) && - b->cloneable & (1 << a->type)); -} - -static bool check_single_encoder_cloning(struct drm_atomic_state *state, - struct intel_crtc *crtc, - struct intel_encoder *encoder) -{ - struct intel_encoder *source_encoder; - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) { - if (connector_state->crtc != &crtc->base) - continue; - - source_encoder = - to_intel_encoder(connector_state->best_encoder); - if (!encoders_cloneable(encoder, source_encoder)) - return false; - } - - return true; -} - -static bool check_encoder_cloning(struct drm_atomic_state *state, - struct intel_crtc *crtc) -{ - struct intel_encoder *encoder; - struct drm_connector *connector; - struct drm_connector_state *connector_state; - int i; - - for_each_connector_in_state(state, connector, connector_state, i) { - if (connector_state->crtc != &crtc->base) - continue; - - encoder = to_intel_encoder(connector_state->best_encoder); - if (!check_single_encoder_cloning(state, crtc, encoder)) - return false; - } - - return true; -} - static bool check_digital_port_conflicts(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -12066,11 +12087,6 @@ intel_modeset_pipe_config(struct drm_crtc *crtc, int i; bool retry = true; - if (!check_encoder_cloning(state, to_intel_crtc(crtc))) { - DRM_DEBUG_KMS("rejecting invalid cloning configuration\n"); - return -EINVAL; - } - clear_intel_crtc_state(pipe_config); pipe_config->cpu_transcoder = -- GitLab From cf5a15befd90742128ca2bdc4409789e782fcc9d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:41 +0200 Subject: [PATCH 0149/7006] drm/i915: Move scaler setup to check crtc function, v2. The scaler setup may add planes, but since they're unchanged we only have to wait for primary flips. Also set planes_changed to indicate at least 1 plane is modified. Changes since v1: - Instead of removing planes, do minimal validation needed. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 17 +++++++++-------- drivers/gpu/drm/i915/intel_display.c | 15 +++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 6ab71ea928192..d5afc2aa4ac7e 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -100,14 +100,6 @@ int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - /* - * FIXME: move to crtc atomic check function once this is - * more atomic friendly. - */ - ret = intel_atomic_setup_scalers(dev, nuclear_crtc, crtc_state); - if (ret) - return ret; - return ret; } @@ -349,6 +341,15 @@ int intel_atomic_setup_scalers(struct drm_device *dev, plane->base.id); return PTR_ERR(state); } + + /* + * the plane is added after plane checks are run, + * but since this plane is unchanged just do the + * minimum required validation. + */ + if (plane->type == DRM_PLANE_TYPE_PRIMARY) + intel_crtc->atomic.wait_for_flips = true; + crtc_state->base.planes_changed = true; } intel_plane = to_intel_plane(plane); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index df13769cf0484..4b307ec173ef5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6586,7 +6586,6 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - int ret; /* FIXME should check pixel clock limits on all platforms */ if (INTEL_INFO(dev)->gen < 4) { @@ -6632,14 +6631,7 @@ static int intel_crtc_compute_config(struct intel_crtc *crtc, if (pipe_config->has_pch_encoder) return ironlake_fdi_compute_config(crtc, pipe_config); - /* FIXME: remove below call once atomic mode set is place and all crtc - * related checks called from atomic_crtc_check function */ - ret = 0; - DRM_DEBUG_KMS("intel_crtc = %p drm_state (pipe_config->base.state) = %p\n", - crtc, pipe_config->base.state); - ret = intel_atomic_setup_scalers(dev, crtc, pipe_config); - - return ret; + return 0; } static int skylake_get_display_clock_speed(struct drm_device *dev) @@ -11726,7 +11718,10 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { + struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc_state); struct drm_atomic_state *state = crtc_state->state; int idx = crtc->base.id; bool mode_changed = needs_modeset(crtc_state); @@ -11740,7 +11735,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); - return 0; + return intel_atomic_setup_scalers(dev, intel_crtc, pipe_config); } static const struct drm_crtc_helper_funcs intel_helper_funcs = { -- GitLab From ad421372a61a6104f21520845e85ba89d691e783 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:42 +0200 Subject: [PATCH 0150/7006] drm/i915: Assign a new pll from the crtc check function, v2. It saves another loop over all crtc's in the state, and computing clock is more of a per crtc thing. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 60 ++++++++++++---------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4b307ec173ef5..0576be36cd689 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11719,11 +11719,12 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); struct drm_atomic_state *state = crtc_state->state; - int idx = crtc->base.id; + int ret, idx = crtc->base.id; bool mode_changed = needs_modeset(crtc_state); if (mode_changed && !check_encoder_cloning(state, intel_crtc)) { @@ -11735,6 +11736,15 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); + if (mode_changed && crtc_state->enable && + dev_priv->display.crtc_compute_clock && + !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) { + ret = dev_priv->display.crtc_compute_clock(intel_crtc, + pipe_config); + if (ret) + return ret; + } + return intel_atomic_setup_scalers(dev, intel_crtc, pipe_config); } @@ -12789,53 +12799,37 @@ static void update_scanline_offset(struct intel_crtc *crtc) crtc->scanline_offset = 1; } -static int intel_modeset_setup_plls(struct drm_atomic_state *state) +static void intel_modeset_clear_plls(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = to_i915(dev); - unsigned clear_pipes = 0; + struct intel_shared_dpll_config *shared_dpll = NULL; struct intel_crtc *intel_crtc; struct intel_crtc_state *intel_crtc_state; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; - int ret = 0; int i; if (!dev_priv->display.crtc_compute_clock) - return 0; + return; for_each_crtc_in_state(state, crtc, crtc_state, i) { + int dpll; + intel_crtc = to_intel_crtc(crtc); intel_crtc_state = to_intel_crtc_state(crtc_state); + dpll = intel_crtc_state->shared_dpll; - if (needs_modeset(crtc_state)) { - clear_pipes |= 1 << intel_crtc->pipe; - intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE; - } - } - - if (clear_pipes) { - struct intel_shared_dpll_config *shared_dpll = - intel_atomic_get_shared_dpll_state(state); - - for (i = 0; i < dev_priv->num_shared_dpll; i++) - shared_dpll[i].crtc_mask &= ~clear_pipes; - } - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc_state) || !crtc_state->enable) + if (!needs_modeset(crtc_state) || dpll == DPLL_ID_PRIVATE) continue; - intel_crtc = to_intel_crtc(crtc); - intel_crtc_state = to_intel_crtc_state(crtc_state); + intel_crtc_state->shared_dpll = DPLL_ID_PRIVATE; - ret = dev_priv->display.crtc_compute_clock(intel_crtc, - intel_crtc_state); - if (ret) - return ret; - } + if (!shared_dpll) + shared_dpll = intel_atomic_get_shared_dpll_state(state); - return ret; + shared_dpll[dpll].crtc_mask &= ~(1 << intel_crtc->pipe); + } } /* @@ -12931,14 +12925,12 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return ret; } - ret = intel_modeset_setup_plls(state); - if (ret) - return ret; + intel_modeset_clear_plls(state); if (IS_HASWELL(dev)) - ret = haswell_mode_set_planes_workaround(state); + return haswell_mode_set_planes_workaround(state); - return ret; + return 0; } static int -- GitLab From 86adf9d7024a699d5195d44c30b7dcd866441f33 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 22 Jun 2015 09:50:32 +0200 Subject: [PATCH 0151/7006] drm/i915: Split skl_update_scaler, v4. commit 2c310b9d2859863826c3688c88218d607d5dd19a Author: Maarten Lankhorst Date: Mon May 18 12:28:52 2015 +0200 drm/i915: Split skl_update_scaler, v4. It's easier to read separate functions for crtc and plane scaler state. Changes since v1: - Update documentation. Changes since v2: - Get rid of parameters to skl_update_scaler only used for traces. This avoids needing to document the other parameters. Changes since v3: - Rename scaler_idx to scaler_user. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 211 ++++++++++++++------------- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 12 +- drivers/gpu/drm/i915/intel_sprite.c | 3 +- 4 files changed, 121 insertions(+), 107 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 0576be36cd689..29e1258fed065 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4313,62 +4313,16 @@ static void cpt_verify_modeset(struct drm_device *dev, int pipe) } } -/** - * skl_update_scaler_users - Stages update to crtc's scaler state - * @intel_crtc: crtc - * @crtc_state: crtc_state - * @plane: plane (NULL indicates crtc is requesting update) - * @plane_state: plane's state - * @force_detach: request unconditional detachment of scaler - * - * This function updates scaler state for requested plane or crtc. - * To request scaler usage update for a plane, caller shall pass plane pointer. - * To request scaler usage update for crtc, caller shall pass plane pointer - * as NULL. - * - * Return - * 0 - scaler_usage updated successfully - * error - requested scaling cannot be supported or other error condition - */ -int -skl_update_scaler_users( - struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state, - struct intel_plane *intel_plane, struct intel_plane_state *plane_state, - int force_detach) +static int +skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, + unsigned scaler_user, int *scaler_id, unsigned int rotation, + int src_w, int src_h, int dst_w, int dst_h) { + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct intel_crtc *intel_crtc = + to_intel_crtc(crtc_state->base.crtc); int need_scaling; - int idx; - int src_w, src_h, dst_w, dst_h; - int *scaler_id; - struct drm_framebuffer *fb; - struct intel_crtc_scaler_state *scaler_state; - unsigned int rotation; - - if (!intel_crtc || !crtc_state) - return 0; - - scaler_state = &crtc_state->scaler_state; - - idx = intel_plane ? drm_plane_index(&intel_plane->base) : SKL_CRTC_INDEX; - fb = intel_plane ? plane_state->base.fb : NULL; - - if (intel_plane) { - src_w = drm_rect_width(&plane_state->src) >> 16; - src_h = drm_rect_height(&plane_state->src) >> 16; - dst_w = drm_rect_width(&plane_state->dst); - dst_h = drm_rect_height(&plane_state->dst); - scaler_id = &plane_state->scaler_id; - rotation = plane_state->base.rotation; - } else { - struct drm_display_mode *adjusted_mode = - &crtc_state->base.adjusted_mode; - src_w = crtc_state->pipe_src_w; - src_h = crtc_state->pipe_src_h; - dst_w = adjusted_mode->hdisplay; - dst_h = adjusted_mode->vdisplay; - scaler_id = &scaler_state->scaler_id; - rotation = DRM_ROTATE_0; - } need_scaling = intel_rotation_90_or_270(rotation) ? (src_h != dst_w || src_w != dst_h): @@ -4384,17 +4338,14 @@ skl_update_scaler_users( * update to free the scaler is done in plane/panel-fit programming. * For this purpose crtc/plane_state->scaler_id isn't reset here. */ - if (force_detach || !need_scaling || (intel_plane && - (!fb || !plane_state->visible))) { + if (force_detach || !need_scaling) { if (*scaler_id >= 0) { - scaler_state->scaler_users &= ~(1 << idx); + scaler_state->scaler_users &= ~(1 << scaler_user); scaler_state->scalers[*scaler_id].in_use = 0; - DRM_DEBUG_KMS("Staged freeing scaler id %d.%d from %s:%d " - "crtc_state = %p scaler_users = 0x%x\n", - intel_crtc->pipe, *scaler_id, intel_plane ? "PLANE" : "CRTC", - intel_plane ? intel_plane->base.base.id : - intel_crtc->base.base.id, crtc_state, + DRM_DEBUG_KMS("scaler_user index %u.%u: " + "Staged freeing scaler id %d scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, *scaler_id, scaler_state->scaler_users); *scaler_id = -1; } @@ -4407,51 +4358,112 @@ skl_update_scaler_users( src_w > SKL_MAX_SRC_W || src_h > SKL_MAX_SRC_H || dst_w > SKL_MAX_DST_W || dst_h > SKL_MAX_DST_H) { - DRM_DEBUG_KMS("%s:%d scaler_user index %u.%u: src %ux%u dst %ux%u " + DRM_DEBUG_KMS("scaler_user index %u.%u: src %ux%u dst %ux%u " "size is out of scaler range\n", - intel_plane ? "PLANE" : "CRTC", - intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id, - intel_crtc->pipe, idx, src_w, src_h, dst_w, dst_h); + intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h); return -EINVAL; } + /* mark this plane as a scaler user in crtc_state */ + scaler_state->scaler_users |= (1 << scaler_user); + DRM_DEBUG_KMS("scaler_user index %u.%u: " + "staged scaling request for %ux%u->%ux%u scaler_users = 0x%x\n", + intel_crtc->pipe, scaler_user, src_w, src_h, dst_w, dst_h, + scaler_state->scaler_users); + + return 0; +} + +/** + * skl_update_scaler_crtc - Stages update to scaler state for a given crtc. + * + * @state: crtc's scaler state + * @force_detach: whether to forcibly disable scaler + * + * Return + * 0 - scaler_usage updated successfully + * error - requested scaling cannot be supported or other error condition + */ +int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) +{ + struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); + struct drm_display_mode *adjusted_mode = + &state->base.adjusted_mode; + + DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", + intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); + + return skl_update_scaler(state, force_detach, SKL_CRTC_INDEX, + &state->scaler_state.scaler_id, DRM_ROTATE_0, + state->pipe_src_w, state->pipe_src_h, + adjusted_mode->hdisplay, adjusted_mode->hdisplay); +} + +/** + * skl_update_scaler_plane - Stages update to scaler state for a given plane. + * + * @state: crtc's scaler state + * @intel_plane: affected plane + * @plane_state: atomic plane state to update + * + * Return + * 0 - scaler_usage updated successfully + * error - requested scaling cannot be supported or other error condition + */ +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane *intel_plane, + struct intel_plane_state *plane_state) +{ + + struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); + struct drm_framebuffer *fb = plane_state->base.fb; + int ret; + + bool force_detach = !fb || !plane_state->visible; + + DRM_DEBUG_KMS("Updating scaler for [PLANE:%d] scaler_user index %u.%u\n", + intel_plane->base.base.id, intel_crtc->pipe, + drm_plane_index(&intel_plane->base)); + + ret = skl_update_scaler(crtc_state, force_detach, + drm_plane_index(&intel_plane->base), + &plane_state->scaler_id, + plane_state->base.rotation, + drm_rect_width(&plane_state->src) >> 16, + drm_rect_height(&plane_state->src) >> 16, + drm_rect_width(&plane_state->dst), + drm_rect_height(&plane_state->dst)); + + if (ret || plane_state->scaler_id < 0) + return ret; + /* check colorkey */ - if (WARN_ON(intel_plane && - intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) { - DRM_DEBUG_KMS("PLANE:%d scaling %ux%u->%ux%u not allowed with colorkey", - intel_plane->base.base.id, src_w, src_h, dst_w, dst_h); + if (WARN_ON(intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) { + DRM_DEBUG_KMS("[PLANE:%d] scaling with color key not allowed", + intel_plane->base.base.id); return -EINVAL; } /* Check src format */ - if (intel_plane) { - switch (fb->pixel_format) { - case DRM_FORMAT_RGB565: - case DRM_FORMAT_XBGR8888: - case DRM_FORMAT_XRGB8888: - case DRM_FORMAT_ABGR8888: - case DRM_FORMAT_ARGB8888: - case DRM_FORMAT_XRGB2101010: - case DRM_FORMAT_XBGR2101010: - case DRM_FORMAT_YUYV: - case DRM_FORMAT_YVYU: - case DRM_FORMAT_UYVY: - case DRM_FORMAT_VYUY: - break; - default: - DRM_DEBUG_KMS("PLANE:%d FB:%d unsupported scaling format 0x%x\n", - intel_plane->base.base.id, fb->base.id, fb->pixel_format); - return -EINVAL; - } + switch (fb->pixel_format) { + case DRM_FORMAT_RGB565: + case DRM_FORMAT_XBGR8888: + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_ARGB8888: + case DRM_FORMAT_XRGB2101010: + case DRM_FORMAT_XBGR2101010: + case DRM_FORMAT_YUYV: + case DRM_FORMAT_YVYU: + case DRM_FORMAT_UYVY: + case DRM_FORMAT_VYUY: + break; + default: + DRM_DEBUG_KMS("[PLANE:%d] FB:%d unsupported scaling format 0x%x\n", + intel_plane->base.base.id, fb->base.id, fb->pixel_format); + return -EINVAL; } - /* mark this plane as a scaler user in crtc_state */ - scaler_state->scaler_users |= (1 << idx); - DRM_DEBUG_KMS("%s:%d staged scaling request for %ux%u->%ux%u " - "crtc_state = %p scaler_users = 0x%x\n", - intel_plane ? "PLANE" : "CRTC", - intel_plane ? intel_plane->base.base.id : intel_crtc->base.base.id, - src_w, src_h, dst_w, dst_h, crtc_state, scaler_state->scaler_users); return 0; } @@ -4466,7 +4478,7 @@ static void skylake_pfit_update(struct intel_crtc *crtc, int enable) DRM_DEBUG_KMS("for crtc_state = %p\n", crtc->config); /* To update pfit, first update scaler state */ - skl_update_scaler_users(crtc, crtc->config, NULL, NULL, !enable); + skl_update_scaler_crtc(crtc->config, !enable); intel_atomic_setup_scalers(crtc->base.dev, crtc, crtc->config); skl_detach_scalers(crtc); if (!enable) @@ -13660,8 +13672,9 @@ intel_check_primary_plane(struct drm_plane *plane, } if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_users(intel_crtc, crtc_state, - to_intel_plane(plane), state, 0); + ret = skl_update_scaler_plane(crtc_state, + to_intel_plane(plane), + state); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 2e6f23890dbfc..a1873b1498c9e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1382,7 +1382,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (INTEL_INFO(dev)->gen >= 9) { int ret; - ret = skl_update_scaler_users(intel_crtc, pipe_config, NULL, NULL, 0); + ret = skl_update_scaler_crtc(pipe_config, 0); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 02b18a173472b..2436af9d2678a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -263,7 +263,7 @@ struct intel_plane_state { * plane requiring a scaler: * - During check_plane, its bit is set in * crtc_state->scaler_state.scaler_users by calling helper function - * update_scaler_users. + * update_scaler_plane. * - scaler_id indicates the scaler it got assigned. * * plane doesn't require a scaler: @@ -271,7 +271,7 @@ struct intel_plane_state { * got disabled. * - During check_plane, corresponding bit is reset in * crtc_state->scaler_state.scaler_users by calling helper function - * update_scaler_users. + * update_scaler_plane. */ int scaler_id; }; @@ -1148,9 +1148,11 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); void skl_detach_scalers(struct intel_crtc *intel_crtc); -int skl_update_scaler_users(struct intel_crtc *intel_crtc, - struct intel_crtc_state *crtc_state, struct intel_plane *intel_plane, - struct intel_plane_state *plane_state, int force_detach); +int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane *intel_plane, + struct intel_plane_state *plane_state); + +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 0434cbe1634b5..f57268bde9aa8 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -944,8 +944,7 @@ finish: } if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_users(intel_crtc, crtc_state, intel_plane, - state, 0); + ret = skl_update_scaler_plane(crtc_state, intel_plane, state); if (ret) return ret; } -- GitLab From da20eabd2c69761f9dfd849985eb299e3335531f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:44 +0200 Subject: [PATCH 0152/7006] drm/i915: Split plane updates of crtc->atomic into a helper, v2. This makes it easier to verify that no changes are done when calling this from crtc instead. Changes since v1: - Make intel_wm_need_update static and always check it. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 21 +- drivers/gpu/drm/i915/intel_display.c | 275 +++++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_sprite.c | 32 +-- 4 files changed, 176 insertions(+), 160 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 86ba4b2c3a651..aa2128369a0ac 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -114,6 +114,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, struct intel_crtc_state *crtc_state; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane_state *intel_state = to_intel_plane_state(state); + int ret; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); @@ -160,20 +161,6 @@ static int intel_plane_atomic_check(struct drm_plane *plane, intel_state->clip.y2 = crtc_state->base.active ? crtc_state->pipe_src_h : 0; - /* - * Disabling a plane is always okay; we just need to update - * fb tracking in a special way since cleanup_fb() won't - * get called by the plane helpers. - */ - if (state->fb == NULL && plane->state->fb != NULL) { - /* - * 'prepare' is never called when plane is being disabled, so - * we need to handle frontbuffer tracking as a special case - */ - intel_crtc->atomic.disabled_planes |= - (1 << drm_plane_index(plane)); - } - if (state->fb && intel_rotation_90_or_270(state->rotation)) { if (!(state->fb->modifier[0] == I915_FORMAT_MOD_Y_TILED || state->fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)) { @@ -198,7 +185,11 @@ static int intel_plane_atomic_check(struct drm_plane *plane, } } - return intel_plane->check_plane(plane, intel_state); + ret = intel_plane->check_plane(plane, intel_state); + if (ret || !state->state) + return ret; + + return intel_plane_atomic_calc_changes(&crtc_state->base, state); } static void intel_plane_atomic_update(struct drm_plane *plane, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 29e1258fed065..39f6b80f990f9 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4403,19 +4403,19 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) * skl_update_scaler_plane - Stages update to scaler state for a given plane. * * @state: crtc's scaler state - * @intel_plane: affected plane * @plane_state: atomic plane state to update * * Return * 0 - scaler_usage updated successfully * error - requested scaling cannot be supported or other error condition */ -int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, - struct intel_plane *intel_plane, - struct intel_plane_state *plane_state) +static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, + struct intel_plane_state *plane_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc_state->base.crtc); + struct intel_plane *intel_plane = + to_intel_plane(plane_state->base.plane); struct drm_framebuffer *fb = plane_state->base.fb; int ret; @@ -11677,6 +11677,161 @@ retry: return ret; } + +/** + * intel_wm_need_update - Check whether watermarks need updating + * @plane: drm plane + * @state: new plane state + * + * Check current plane state versus the new one to determine whether + * watermarks need to be recalculated. + * + * Returns true or false. + */ +static bool intel_wm_need_update(struct drm_plane *plane, + struct drm_plane_state *state) +{ + /* Update watermarks on tiling changes. */ + if (!plane->state->fb || !state->fb || + plane->state->fb->modifier[0] != state->fb->modifier[0] || + plane->state->rotation != state->rotation) + return true; + + if (plane->state->crtc_w != state->crtc_w) + return true; + + return false; +} + +int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state) +{ + struct drm_crtc *crtc = crtc_state->crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + struct drm_plane *plane = plane_state->plane; + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_plane_state *old_plane_state = + to_intel_plane_state(plane->state); + int idx = intel_crtc->base.base.id, ret; + int i = drm_plane_index(plane); + bool mode_changed = needs_modeset(crtc_state); + bool was_crtc_enabled = crtc->state->active; + bool is_crtc_enabled = crtc_state->active; + + bool turn_off, turn_on, visible, was_visible; + struct drm_framebuffer *fb = plane_state->fb; + + if (crtc_state && INTEL_INFO(dev)->gen >= 9 && + plane->type != DRM_PLANE_TYPE_CURSOR) { + ret = skl_update_scaler_plane( + to_intel_crtc_state(crtc_state), + to_intel_plane_state(plane_state)); + if (ret) + return ret; + } + + /* + * Disabling a plane is always okay; we just need to update + * fb tracking in a special way since cleanup_fb() won't + * get called by the plane helpers. + */ + if (old_plane_state->base.fb && !fb) + intel_crtc->atomic.disabled_planes |= 1 << i; + + /* don't run rest during modeset yet */ + if (!intel_crtc->active || mode_changed) + return 0; + + was_visible = old_plane_state->visible; + visible = to_intel_plane_state(plane_state)->visible; + + if (!was_crtc_enabled && WARN_ON(was_visible)) + was_visible = false; + + if (!is_crtc_enabled && WARN_ON(visible)) + visible = false; + + if (!was_visible && !visible) + return 0; + + turn_off = was_visible && (!visible || mode_changed); + turn_on = visible && (!was_visible || mode_changed); + + DRM_DEBUG_ATOMIC("[CRTC:%i] has [PLANE:%i] with fb %i\n", idx, + plane->base.id, fb ? fb->base.id : -1); + + DRM_DEBUG_ATOMIC("[PLANE:%i] visible %i -> %i, off %i, on %i, ms %i\n", + plane->base.id, was_visible, visible, + turn_off, turn_on, mode_changed); + + if (intel_wm_need_update(plane, plane_state)) + intel_crtc->atomic.update_wm = true; + + switch (plane->type) { + case DRM_PLANE_TYPE_PRIMARY: + if (visible) + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); + + intel_crtc->atomic.wait_for_flips = true; + intel_crtc->atomic.pre_disable_primary = turn_off; + intel_crtc->atomic.post_enable_primary = turn_on; + + if (turn_off) + intel_crtc->atomic.disable_fbc = true; + + /* + * FBC does not work on some platforms for rotated + * planes, so disable it when rotation is not 0 and + * update it when rotation is set back to 0. + * + * FIXME: This is redundant with the fbc update done in + * the primary plane enable function except that that + * one is done too late. We eventually need to unify + * this. + */ + + if (visible && + INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + dev_priv->fbc.crtc == intel_crtc && + plane_state->rotation != BIT(DRM_ROTATE_0)) + intel_crtc->atomic.disable_fbc = true; + + /* + * BDW signals flip done immediately if the plane + * is disabled, even if the plane enable is already + * armed to occur at the next vblank :( + */ + if (turn_on && IS_BROADWELL(dev)) + intel_crtc->atomic.wait_vblank = true; + + intel_crtc->atomic.update_fbc |= visible || mode_changed; + break; + case DRM_PLANE_TYPE_CURSOR: + if (visible) + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + /* + * 'prepare' is never called when plane is being disabled, so + * we need to handle frontbuffer tracking as a special case + */ + if (visible) + intel_crtc->atomic.fb_bits |= + INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); + + if (turn_off && is_crtc_enabled) { + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_sprite_watermarks |= + 1 << i; + } + break; + } + return 0; +} + static bool encoders_cloneable(const struct intel_encoder *a, const struct intel_encoder *b) { @@ -13443,28 +13598,6 @@ static void intel_shared_dpll_init(struct drm_device *dev) BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS); } -/** - * intel_wm_need_update - Check whether watermarks need updating - * @plane: drm plane - * @state: new plane state - * - * Check current plane state versus the new one to determine whether - * watermarks need to be recalculated. - * - * Returns true or false. - */ -bool intel_wm_need_update(struct drm_plane *plane, - struct drm_plane_state *state) -{ - /* Update watermarks on tiling changes. */ - if (!plane->state->fb || !state->fb || - plane->state->fb->modifier[0] != state->fb->modifier[0] || - plane->state->rotation != state->rotation) - return true; - - return false; -} - /** * intel_prepare_plane_fb - Prepare fb for usage on plane * @plane: drm plane to prepare for @@ -13586,7 +13719,6 @@ intel_check_primary_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = state->base.crtc; struct intel_crtc *intel_crtc; struct intel_crtc_state *crtc_state; @@ -13597,7 +13729,6 @@ intel_check_primary_plane(struct drm_plane *plane, bool can_position = false; int max_scale = DRM_PLANE_HELPER_NO_SCALING; int min_scale = DRM_PLANE_HELPER_NO_SCALING; - int ret; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); @@ -13613,73 +13744,11 @@ intel_check_primary_plane(struct drm_plane *plane, can_position = true; } - ret = drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, - min_scale, - max_scale, - can_position, true, - &state->visible); - if (ret) - return ret; - - if (intel_crtc->active) { - struct intel_plane_state *old_state = - to_intel_plane_state(plane->state); - - intel_crtc->atomic.wait_for_flips = true; - - /* - * FBC does not work on some platforms for rotated - * planes, so disable it when rotation is not 0 and - * update it when rotation is set back to 0. - * - * FIXME: This is redundant with the fbc update done in - * the primary plane enable function except that that - * one is done too late. We eventually need to unify - * this. - */ - if (state->visible && - INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && - dev_priv->fbc.crtc == intel_crtc && - state->base.rotation != BIT(DRM_ROTATE_0)) { - intel_crtc->atomic.disable_fbc = true; - } - - if (state->visible && !old_state->visible) { - /* - * BDW signals flip done immediately if the plane - * is disabled, even if the plane enable is already - * armed to occur at the next vblank :( - */ - if (IS_BROADWELL(dev)) - intel_crtc->atomic.wait_vblank = true; - - if (crtc_state && !needs_modeset(&crtc_state->base)) - intel_crtc->atomic.post_enable_primary = true; - } - - if (!state->visible && old_state->visible && - crtc_state && !needs_modeset(&crtc_state->base)) - intel_crtc->atomic.pre_disable_primary = true; - - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); - - intel_crtc->atomic.update_fbc = true; - - if (intel_wm_need_update(plane, &state->base)) - intel_crtc->atomic.update_wm = true; - } - - if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_plane(crtc_state, - to_intel_plane(plane), - state); - if (ret) - return ret; - } - - return 0; + return drm_plane_helper_check_update(plane, crtc, fb, + src, dest, clip, + min_scale, max_scale, + can_position, true, + &state->visible); } static void @@ -13939,10 +14008,9 @@ intel_check_cursor_plane(struct drm_plane *plane, if (ret) return ret; - /* if we want to turn off the cursor ignore width and height */ if (!obj) - goto finish; + return 0; /* Check for which cursor types we support */ if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) { @@ -13959,19 +14027,10 @@ intel_check_cursor_plane(struct drm_plane *plane, if (fb->modifier[0] != DRM_FORMAT_MOD_NONE) { DRM_DEBUG_KMS("cursor cannot be tiled\n"); - ret = -EINVAL; - } - -finish: - if (intel_crtc->active) { - if (plane->state->crtc_w != state->base.crtc_w) - intel_crtc->atomic.update_wm = true; - - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); + return -EINVAL; } - return ret; + return 0; } static void diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2436af9d2678a..198cb20d9193b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1067,6 +1067,8 @@ int intel_plane_atomic_set_property(struct drm_plane *plane, struct drm_plane_state *state, struct drm_property *property, uint64_t val); +int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, + struct drm_plane_state *plane_state); unsigned int intel_tile_height(struct drm_device *dev, uint32_t pixel_format, @@ -1081,9 +1083,6 @@ intel_rotation_90_or_270(unsigned int rotation) void intel_create_rotation_property(struct drm_device *dev, struct intel_plane *plane); -bool intel_wm_need_update(struct drm_plane *plane, - struct drm_plane_state *state); - /* shared dpll functions */ struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc); void assert_shared_dpll(struct drm_i915_private *dev_priv, @@ -1148,9 +1147,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); void skl_detach_scalers(struct intel_crtc *intel_crtc); -int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, - struct intel_plane *intel_plane, - struct intel_plane_state *plane_state); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index f57268bde9aa8..e36bef805576f 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -759,7 +759,6 @@ intel_check_sprite_plane(struct drm_plane *plane, int max_scale, min_scale; bool can_scale; int pixel_size; - int ret; intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); crtc_state = state->base.state ? @@ -767,7 +766,7 @@ intel_check_sprite_plane(struct drm_plane *plane, if (!fb) { state->visible = false; - goto finish; + return 0; } /* Don't modify another pipe's plane */ @@ -920,35 +919,6 @@ intel_check_sprite_plane(struct drm_plane *plane, dst->y1 = crtc_y; dst->y2 = crtc_y + crtc_h; -finish: - /* - * If the sprite is completely covering the primary plane, - * we can disable the primary and save power. - */ - if (intel_crtc->active) { - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - - if (intel_wm_need_update(plane, &state->base)) - intel_crtc->atomic.update_wm = true; - - if (!state->visible) { - /* - * Avoid underruns when disabling the sprite. - * FIXME remove once watermark updates are done properly. - */ - intel_crtc->atomic.wait_vblank = true; - intel_crtc->atomic.update_sprite_watermarks |= - (1 << drm_plane_index(plane)); - } - } - - if (INTEL_INFO(dev)->gen >= 9) { - ret = skl_update_scaler_plane(crtc_state, intel_plane, state); - if (ret) - return ret; - } - return 0; } -- GitLab From 302d19ac76ae5abacfcffcc76fb384d0b8d54c80 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:45 +0200 Subject: [PATCH 0153/7006] drm/i915: clean up plane commit functions No point in hiding behind big ifs. This will be true most of the time. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++++++------- drivers/gpu/drm/i915/intel_sprite.c | 33 ++++++++++++---------------- 2 files changed, 22 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 39f6b80f990f9..2f50c73653d95 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13769,14 +13769,14 @@ intel_commit_primary_plane(struct drm_plane *plane, crtc->x = src->x1 >> 16; crtc->y = src->y1 >> 16; - if (intel_crtc->active) { - if (state->visible) - /* FIXME: kill this fastboot hack */ - intel_update_pipe_size(intel_crtc); + if (!intel_crtc->active) + return; - dev_priv->display.update_primary_plane(crtc, plane->fb, - crtc->x, crtc->y); - } + if (state->visible) + /* FIXME: kill this fastboot hack */ + intel_update_pipe_size(intel_crtc); + + dev_priv->display.update_primary_plane(crtc, fb, crtc->x, crtc->y); } static void @@ -14078,8 +14078,8 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_crtc->cursor_addr = addr; intel_crtc->cursor_bo = obj; -update: +update: if (intel_crtc->active) intel_crtc_update_cursor(crtc, state->visible); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e36bef805576f..48353b34d0f52 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -930,31 +930,26 @@ intel_commit_sprite_plane(struct drm_plane *plane, struct intel_crtc *intel_crtc; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; - int crtc_x, crtc_y; - unsigned int crtc_w, crtc_h; - uint32_t src_x, src_y, src_w, src_h; crtc = crtc ? crtc : plane->crtc; intel_crtc = to_intel_crtc(crtc); plane->fb = fb; - if (intel_crtc->active) { - if (state->visible) { - crtc_x = state->dst.x1; - crtc_y = state->dst.y1; - crtc_w = drm_rect_width(&state->dst); - crtc_h = drm_rect_height(&state->dst); - src_x = state->src.x1 >> 16; - src_y = state->src.y1 >> 16; - src_w = drm_rect_width(&state->src) >> 16; - src_h = drm_rect_height(&state->src) >> 16; - intel_plane->update_plane(plane, crtc, fb, - crtc_x, crtc_y, crtc_w, crtc_h, - src_x, src_y, src_w, src_h); - } else { - intel_plane->disable_plane(plane, crtc, false); - } + if (!intel_crtc->active) + return; + + if (state->visible) { + intel_plane->update_plane(plane, crtc, fb, + state->dst.x1, state->dst.y1, + drm_rect_width(&state->dst), + drm_rect_height(&state->dst), + state->src.x1 >> 16, + state->src.y1 >> 16, + drm_rect_width(&state->src) >> 16, + drm_rect_height(&state->src) >> 16); + } else { + intel_plane->disable_plane(plane, crtc, false); } } -- GitLab From 061e4b8d650afd16ebe447d454431c717265b89f Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:46 +0200 Subject: [PATCH 0154/7006] drm/i915: clean up atomic plane check functions, v2. By passing crtc_state to the check_plane functions a lot of duplicated code can be removed. There are still some transitional helper calls, they will be removed later. Changes since v1: - Revert state->visible changes. - Use plane->state->crtc instead of plane->crtc. - Use drm_atomic_get_existing_crtc_state. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 16 +++++--- drivers/gpu/drm/i915/intel_display.c | 48 +++++++---------------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 9 ++--- 4 files changed, 29 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index aa2128369a0ac..91d53768df9d5 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -116,7 +116,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, struct intel_plane_state *intel_state = to_intel_plane_state(state); int ret; - crtc = crtc ? crtc : plane->crtc; + crtc = crtc ? crtc : plane->state->crtc; intel_crtc = to_intel_crtc(crtc); /* @@ -131,10 +131,13 @@ static int intel_plane_atomic_check(struct drm_plane *plane, /* FIXME: temporary hack necessary while we still use the plane update * helper. */ if (state->state) { - crtc_state = - intel_atomic_get_crtc_state(state->state, intel_crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); + struct drm_crtc_state *drm_crtc_state = + drm_atomic_get_existing_crtc_state(state->state, crtc); + + if (WARN_ON(!drm_crtc_state)) + return -EINVAL; + + crtc_state = to_intel_crtc_state(drm_crtc_state); } else { crtc_state = intel_crtc->config; } @@ -185,7 +188,8 @@ static int intel_plane_atomic_check(struct drm_plane *plane, } } - ret = intel_plane->check_plane(plane, intel_state); + intel_state->visible = false; + ret = intel_plane->check_plane(plane, crtc_state, intel_state); if (ret || !state->state) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2f50c73653d95..d7ad8449a9e14 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13716,36 +13716,25 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state static int intel_check_primary_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state) { - struct drm_device *dev = plane->dev; struct drm_crtc *crtc = state->base.crtc; - struct intel_crtc *intel_crtc; - struct intel_crtc_state *crtc_state; struct drm_framebuffer *fb = state->base.fb; - struct drm_rect *dest = &state->dst; - struct drm_rect *src = &state->src; - const struct drm_rect *clip = &state->clip; - bool can_position = false; - int max_scale = DRM_PLANE_HELPER_NO_SCALING; int min_scale = DRM_PLANE_HELPER_NO_SCALING; + int max_scale = DRM_PLANE_HELPER_NO_SCALING; + bool can_position = false; - crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); - crtc_state = state->base.state ? - intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; - - if (INTEL_INFO(dev)->gen >= 9) { - /* use scaler when colorkey is not required */ - if (to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) { - min_scale = 1; - max_scale = skl_max_scale(intel_crtc, crtc_state); - } + /* use scaler when colorkey is not required */ + if (INTEL_INFO(plane->dev)->gen >= 9 && + to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) { + min_scale = 1; + max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); can_position = true; } - return drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, + return drm_plane_helper_check_update(plane, crtc, fb, &state->src, + &state->dst, &state->clip, min_scale, max_scale, can_position, true, &state->visible); @@ -13984,24 +13973,17 @@ void intel_create_rotation_property(struct drm_device *dev, struct intel_plane * static int intel_check_cursor_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state) { - struct drm_crtc *crtc = state->base.crtc; - struct drm_device *dev = plane->dev; + struct drm_crtc *crtc = crtc_state->base.crtc; struct drm_framebuffer *fb = state->base.fb; - struct drm_rect *dest = &state->dst; - struct drm_rect *src = &state->src; - const struct drm_rect *clip = &state->clip; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc; unsigned stride; int ret; - crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); - - ret = drm_plane_helper_check_update(plane, crtc, fb, - src, dest, clip, + ret = drm_plane_helper_check_update(plane, crtc, fb, &state->src, + &state->dst, &state->clip, DRM_PLANE_HELPER_NO_SCALING, DRM_PLANE_HELPER_NO_SCALING, true, true, &state->visible); @@ -14013,7 +13995,7 @@ intel_check_cursor_plane(struct drm_plane *plane, return 0; /* Check for which cursor types we support */ - if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) { + if (!cursor_size_ok(plane->dev, state->base.crtc_w, state->base.crtc_h)) { DRM_DEBUG("Cursor dimension %dx%d not supported\n", state->base.crtc_w, state->base.crtc_h); return -EINVAL; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 198cb20d9193b..0145e0878be54 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -613,6 +613,7 @@ struct intel_plane { void (*disable_plane)(struct drm_plane *plane, struct drm_crtc *crtc, bool force); int (*check_plane)(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state); void (*commit_plane)(struct drm_plane *plane, struct intel_plane_state *state); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 48353b34d0f52..cc18605ab7a8f 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -742,11 +742,12 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) static int intel_check_sprite_plane(struct drm_plane *plane, + struct intel_crtc_state *crtc_state, struct intel_plane_state *state) { struct drm_device *dev = plane->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); - struct intel_crtc_state *crtc_state; + struct drm_crtc *crtc = state->base.crtc; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; int crtc_x, crtc_y; @@ -760,10 +761,6 @@ intel_check_sprite_plane(struct drm_plane *plane, bool can_scale; int pixel_size; - intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc); - crtc_state = state->base.state ? - intel_atomic_get_crtc_state(state->base.state, intel_crtc) : NULL; - if (!fb) { state->visible = false; return 0; -- GitLab From 7fabf5ef18ea76714ff04baaeeddb949faf486dd Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:47 +0200 Subject: [PATCH 0155/7006] drm/i915: remove force argument from disable_plane The idea was good, but planes can have a fb even though they're disabled. This makes the force argument useless and always true, because only the commit function updates state. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_sprite.c | 10 +++++----- 3 files changed, 9 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d7ad8449a9e14..bc55221ffe659 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4804,7 +4804,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) struct drm_crtc *from = intel_plane->base.crtc; intel_plane->disable_plane(&intel_plane->base, - from ?: crtc, true); + from ?: crtc); } } @@ -13770,8 +13770,7 @@ intel_commit_primary_plane(struct drm_plane *plane, static void intel_disable_primary_plane(struct drm_plane *plane, - struct drm_crtc *crtc, - bool force) + struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -14017,17 +14016,8 @@ intel_check_cursor_plane(struct drm_plane *plane, static void intel_disable_cursor_plane(struct drm_plane *plane, - struct drm_crtc *crtc, - bool force) + struct drm_crtc *crtc) { - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - if (!force) { - plane->fb = NULL; - intel_crtc->cursor_bo = NULL; - intel_crtc->cursor_addr = 0; - } - intel_crtc_update_cursor(crtc, false); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0145e0878be54..eaf7eaf2ffacb 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -611,7 +611,7 @@ struct intel_plane { uint32_t x, uint32_t y, uint32_t src_w, uint32_t src_h); void (*disable_plane)(struct drm_plane *plane, - struct drm_crtc *crtc, bool force); + struct drm_crtc *crtc); int (*check_plane)(struct drm_plane *plane, struct intel_crtc_state *crtc_state, struct intel_plane_state *state); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cc18605ab7a8f..699311a9bdfe0 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -272,7 +272,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, } static void -skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc, bool force) +skl_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) { struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -456,7 +456,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, } static void -vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc, bool force) +vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) { struct drm_device *dev = dplane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -597,7 +597,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static void -ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) +ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -725,7 +725,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, } static void -ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc, bool force) +ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc) { struct drm_device *dev = plane->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -946,7 +946,7 @@ intel_commit_sprite_plane(struct drm_plane *plane, drm_rect_width(&state->src) >> 16, drm_rect_height(&state->src) >> 16); } else { - intel_plane->disable_plane(plane, crtc, false); + intel_plane->disable_plane(plane, crtc); } } -- GitLab From 0583236eaa8f8596c2adf5116020dba9bcf77806 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:48 +0200 Subject: [PATCH 0156/7006] drm/i915: move detaching scalers to begin_crtc_commit, v2. This is probably intended to be be done during vblank evasion. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 3 --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index d5afc2aa4ac7e..c1263be8c98b1 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -144,9 +144,6 @@ int intel_atomic_commit(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); - if (INTEL_INFO(dev)->gen >= 9) - skl_detach_scalers(to_intel_crtc(crtc)); - drm_atomic_helper_commit_planes_on_crtc(crtc_state); } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bc55221ffe659..449e07d29b3e7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2925,16 +2925,13 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, /* * This function detaches (aka. unbinds) unused scalers in hardware */ -void skl_detach_scalers(struct intel_crtc *intel_crtc) +static void skl_detach_scalers(struct intel_crtc *intel_crtc) { struct drm_device *dev; struct drm_i915_private *dev_priv; struct intel_crtc_scaler_state *scaler_state; int i; - if (!intel_crtc || !intel_crtc->config) - return; - dev = intel_crtc->base.dev; dev_priv = dev->dev_private; scaler_state = &intel_crtc->config->scaler_state; @@ -13831,6 +13828,9 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); + + if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9) + skl_detach_scalers(intel_crtc); } static void intel_finish_crtc_commit(struct drm_crtc *crtc) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eaf7eaf2ffacb..49ec7142b9cc9 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1147,7 +1147,6 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, struct intel_crtc_state *pipe_config); void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); -void skl_detach_scalers(struct intel_crtc *intel_crtc); int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); -- GitLab From ac21b225638a035449107dbbcc0c9f5bd4a24102 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:49 +0200 Subject: [PATCH 0157/7006] drm/i915: Move crtc commit updates to separate functions. To allow them to be used in intel_set_mode. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 127 +++++++++++++++------------ 1 file changed, 69 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 449e07d29b3e7..118c8acc26037 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4763,6 +4763,72 @@ intel_pre_disable_primary(struct drm_crtc *crtc) hsw_disable_ips(intel_crtc); } +static void intel_post_plane_update(struct intel_crtc *crtc) +{ + struct intel_crtc_atomic_commit *atomic = &crtc->atomic; + struct drm_device *dev = crtc->base.dev; + struct drm_plane *plane; + + if (atomic->wait_vblank) + intel_wait_for_vblank(dev, crtc->pipe); + + intel_frontbuffer_flip(dev, atomic->fb_bits); + + if (atomic->update_fbc) { + mutex_lock(&dev->struct_mutex); + intel_fbc_update(dev); + mutex_unlock(&dev->struct_mutex); + } + + if (atomic->post_enable_primary) + intel_post_enable_primary(&crtc->base); + + drm_for_each_plane_mask(plane, dev, atomic->update_sprite_watermarks) + intel_update_sprite_watermarks(plane, &crtc->base, + 0, 0, 0, false, false); + + memset(atomic, 0, sizeof(*atomic)); +} + +static void intel_pre_plane_update(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct intel_crtc_atomic_commit *atomic = &crtc->atomic; + struct drm_plane *p; + + /* Track fb's for any planes being disabled */ + + drm_for_each_plane_mask(p, dev, atomic->disabled_planes) { + struct intel_plane *plane = to_intel_plane(p); + unsigned fb_bits = 0; + + switch (p->type) { + case DRM_PLANE_TYPE_PRIMARY: + fb_bits = INTEL_FRONTBUFFER_PRIMARY(plane->pipe); + break; + case DRM_PLANE_TYPE_CURSOR: + fb_bits = INTEL_FRONTBUFFER_CURSOR(plane->pipe); + break; + case DRM_PLANE_TYPE_OVERLAY: + fb_bits = INTEL_FRONTBUFFER_SPRITE(plane->pipe); + break; + } + + mutex_lock(&dev->struct_mutex); + i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, fb_bits); + mutex_unlock(&dev->struct_mutex); + } + + if (atomic->wait_for_flips) + intel_crtc_wait_for_pending_flips(&crtc->base); + + if (atomic->disable_fbc) + intel_fbc_disable(dev); + + if (atomic->pre_disable_primary) + intel_pre_disable_primary(&crtc->base); +} + static void intel_crtc_enable_planes(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; @@ -13780,43 +13846,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_crtc_state *crtc_state = intel_crtc->base.state; - struct intel_plane *intel_plane; - struct drm_plane *p; - unsigned fb_bits = 0; - - /* Track fb's for any planes being disabled */ - list_for_each_entry(p, &dev->mode_config.plane_list, head) { - intel_plane = to_intel_plane(p); - - if (intel_crtc->atomic.disabled_planes & - (1 << drm_plane_index(p))) { - switch (p->type) { - case DRM_PLANE_TYPE_PRIMARY: - fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe); - break; - case DRM_PLANE_TYPE_CURSOR: - fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe); - break; - case DRM_PLANE_TYPE_OVERLAY: - fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe); - break; - } - - mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(p->fb), NULL, fb_bits); - mutex_unlock(&dev->struct_mutex); - } - } - - if (intel_crtc->atomic.wait_for_flips) - intel_crtc_wait_for_pending_flips(crtc); - - if (intel_crtc->atomic.disable_fbc) - intel_fbc_disable(dev); - if (intel_crtc->atomic.pre_disable_primary) - intel_pre_disable_primary(crtc); + intel_pre_plane_update(intel_crtc); if (intel_crtc->atomic.update_wm) intel_update_watermarks(crtc); @@ -13824,7 +13855,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_get(dev_priv); /* Perform vblank evasion around commit operation */ - if (crtc_state->active && !needs_modeset(crtc_state)) + if (crtc->state->active && !needs_modeset(crtc->state)) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); @@ -13838,7 +13869,6 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct drm_plane *p; if (intel_crtc->atomic.evade) intel_pipe_update_end(intel_crtc, @@ -13846,26 +13876,7 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_put(dev_priv); - if (intel_crtc->atomic.wait_vblank && intel_crtc->active) - intel_wait_for_vblank(dev, intel_crtc->pipe); - - intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits); - - if (intel_crtc->atomic.update_fbc) { - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - } - - if (intel_crtc->atomic.post_enable_primary) - intel_post_enable_primary(crtc); - - drm_for_each_legacy_plane(p, &dev->mode_config.plane_list) - if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p)) - intel_update_sprite_watermarks(p, crtc, 0, 0, 0, - false, false); - - memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic)); + intel_post_plane_update(intel_crtc); } /** -- GitLab From 61333b6075bf3b48a31fb5623a4101ed6bf393bc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:50 +0200 Subject: [PATCH 0158/7006] drm/i915: Do not run most checks when there's no modeset. All the checks in intel_modeset_checks are only useful when a modeset occurs, because there is nothing to update otherwise. Same for power/cdclk changes, if there is no modeset they are noops. Unfortunately intel_modeset_pipe_config still gets called without modeset, because atomic hw readout isn't done yet. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 33 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 118c8acc26037..57bc49039991b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13169,18 +13169,18 @@ intel_modeset_compute_config(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; + bool any_ms = false; ret = drm_atomic_helper_check_modeset(state->dev, state); if (ret) return ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->enable && - WARN_ON(crtc_state->active)) - crtc_state->active = false; - - if (!crtc_state->enable) + if (!crtc_state->enable) { + if (needs_modeset(crtc_state)) + any_ms = true; continue; + } if (!needs_modeset(crtc_state)) { ret = drm_atomic_add_affected_connectors(state, crtc); @@ -13193,14 +13193,20 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; + if (needs_modeset(crtc_state)) + any_ms = true; + intel_dump_pipe_config(to_intel_crtc(crtc), to_intel_crtc_state(crtc_state), "[modeset]"); } - ret = intel_modeset_checks(state); - if (ret) - return ret; + if (any_ms) { + ret = intel_modeset_checks(state); + + if (ret) + return ret; + } return drm_atomic_helper_check_planes(state->dev, state); } @@ -13213,6 +13219,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) struct drm_crtc_state *crtc_state; int ret = 0; int i; + bool any_ms = false; ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) @@ -13221,7 +13228,11 @@ static int __intel_set_mode(struct drm_atomic_state *state) drm_atomic_helper_swap_state(dev, state); for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!needs_modeset(crtc->state) || !crtc_state->active) + if (!needs_modeset(crtc->state)) + continue; + + any_ms = true; + if (!crtc_state->active) continue; intel_crtc_disable_planes(crtc); @@ -13234,8 +13245,8 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* The state has been swaped above, so state actually contains the * old state now. */ - - modeset_update_crtc_power_domains(state); + if (any_ms) + modeset_update_crtc_power_domains(state); /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { -- GitLab From d032ffa04cf7c6f7187e53125e860597bf64b11c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:51 +0200 Subject: [PATCH 0159/7006] drm/i915: Handle disabling planes better, v2. Read out the initial state, and add a quirk to force add all planes to crtc_state->plane_mask during initial commit. This will disable all planes during the initial modeset. The initial plane quirk is temporary, and will go away when hardware readout is fully atomic, and the watermark updates in intel_sprite.c are removed. Changes since v1: - Unset state->visible on !primary planes. - Do not rely on the plane->crtc pointer in intel_atomic_plane, instead assume planes are invisible until modeset. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 7 ++ drivers/gpu/drm/i915/intel_display.c | 120 ++++++++++++++++++++++----- drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 106 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index c1263be8c98b1..060d98b10f83f 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -96,6 +96,13 @@ int intel_atomic_check(struct drm_device *dev, return -EINVAL; } + if (crtc_state && + crtc_state->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { + ret = drm_atomic_add_affected_planes(state, &nuclear_crtc->base); + if (ret) + return ret; + } + ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 57bc49039991b..827c5a513f86b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -109,8 +109,6 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); -static void intel_crtc_enable_planes(struct drm_crtc *crtc); -static void intel_crtc_disable_planes(struct drm_crtc *crtc); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -4850,11 +4848,11 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc) intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); } -static void intel_crtc_disable_planes(struct drm_crtc *crtc) +static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask) { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - struct intel_plane *intel_plane; + struct drm_plane *p; int pipe = intel_crtc->pipe; intel_crtc_wait_for_pending_flips(crtc); @@ -4862,14 +4860,9 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc) intel_pre_disable_primary(crtc); intel_crtc_dpms_overlay_disable(intel_crtc); - for_each_intel_plane(dev, intel_plane) { - if (intel_plane->pipe == pipe) { - struct drm_crtc *from = intel_plane->base.crtc; - intel_plane->disable_plane(&intel_plane->base, - from ?: crtc); - } - } + drm_for_each_plane_mask(p, dev, plane_mask) + to_intel_plane(p)->disable_plane(p, crtc); /* * FIXME: Once we grow proper nuclear flip support out of this we need @@ -6289,7 +6282,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) if (!intel_crtc->active) return; - intel_crtc_disable_planes(crtc); + intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); domains = intel_crtc->enabled_power_domains; @@ -11885,7 +11878,7 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.fb_bits |= INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - if (turn_off && is_crtc_enabled) { + if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; @@ -11945,6 +11938,34 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, return true; } +static void intel_crtc_check_initial_planes(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc_state); + struct drm_plane *p; + unsigned visible_mask = 0; + + drm_for_each_plane_mask(p, crtc->dev, crtc_state->plane_mask) { + struct drm_plane_state *plane_state = + drm_atomic_get_existing_plane_state(crtc_state->state, p); + + if (WARN_ON(!plane_state)) + continue; + + if (!plane_state->fb) + crtc_state->plane_mask &= + ~(1 << drm_plane_index(p)); + else if (to_intel_plane_state(plane_state)->visible) + visible_mask |= 1 << drm_plane_index(p); + } + + if (!visible_mask) + return; + + pipe_config->quirks &= ~PIPE_CONFIG_QUIRK_INITIAL_PLANES; +} + static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { @@ -11966,6 +11987,10 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); + /* plane mask is fixed up after all initial planes are calculated */ + if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) + intel_crtc_check_initial_planes(crtc, crtc_state); + if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) { @@ -13182,6 +13207,20 @@ intel_modeset_compute_config(struct drm_atomic_state *state) continue; } + if (to_intel_crtc_state(crtc_state)->quirks & + PIPE_CONFIG_QUIRK_INITIAL_PLANES) { + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + + /* + * We ought to handle i915.fastboot here. + * If no modeset is required and the primary plane has + * a fb, update the members of crtc_state as needed, + * and run the necessary updates during vblank evasion. + */ + } + if (!needs_modeset(crtc_state)) { ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) @@ -13235,7 +13274,7 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (!crtc_state->active) continue; - intel_crtc_disable_planes(crtc); + intel_crtc_disable_planes(crtc, crtc_state->plane_mask); dev_priv->display.crtc_disable(crtc); } @@ -15403,10 +15442,51 @@ static bool primary_get_hw_state(struct intel_crtc *crtc) { struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; - if (!crtc->active) - return false; + return !!(I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE); +} + +static void readout_plane_state(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state) +{ + struct intel_plane *p; + struct drm_plane_state *drm_plane_state; + bool active = crtc_state->base.active; + + if (active) { + crtc_state->quirks |= PIPE_CONFIG_QUIRK_INITIAL_PLANES; + + /* apply to previous sw state too */ + to_intel_crtc_state(crtc->base.state)->quirks |= + PIPE_CONFIG_QUIRK_INITIAL_PLANES; + } - return I915_READ(DSPCNTR(crtc->plane)) & DISPLAY_PLANE_ENABLE; + for_each_intel_plane(crtc->base.dev, p) { + bool visible = active; + + if (crtc->pipe != p->pipe) + continue; + + drm_plane_state = p->base.state; + if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { + visible = primary_get_hw_state(crtc); + to_intel_plane_state(drm_plane_state)->visible = visible; + } else { + /* + * unknown state, assume it's off to force a transition + * to on when calculating state changes. + */ + to_intel_plane_state(drm_plane_state)->visible = false; + } + + if (visible) { + crtc_state->base.plane_mask |= + 1 << drm_plane_index(&p->base); + } else if (crtc_state->base.state) { + /* Make this unconditional for atomic hw readout. */ + crtc_state->base.plane_mask &= + ~(1 << drm_plane_index(&p->base)); + } + } } static void intel_modeset_readout_hw_state(struct drm_device *dev) @@ -15419,9 +15499,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) int i; for_each_intel_crtc(dev, crtc) { - struct drm_plane *primary = crtc->base.primary; - struct intel_plane_state *plane_state; - memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->base.crtc = &crtc->base; @@ -15435,8 +15512,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->base.enabled = crtc->active; crtc->base.hwmode = crtc->config->base.adjusted_mode; - plane_state = to_intel_plane_state(primary->state); - plane_state->visible = primary_get_hw_state(crtc); + readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state)); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", crtc->base.base.id, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 49ec7142b9cc9..3127c9ae4b42f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -338,6 +338,7 @@ struct intel_crtc_state { */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ #define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ +#define PIPE_CONFIG_QUIRK_INITIAL_PLANES (1<<2) /* planes are in unknown state */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) -- GitLab From a539205a1628e76cbaae35c8ba64d503c6aa619b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:52 +0200 Subject: [PATCH 0160/7006] drm/i915: atomic plane updates in a nutshell Now that all planes are added during a modeset we can use the calculated changes before disabling a plane, and then either commit or force disable a plane before disabling the crtc. The code is shared with atomic_begin/flush, except watermark updating and vblank evasion are not used. This is needed for proper atomic suspend/resume support. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90868 Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 103 ++++++--------------------- drivers/gpu/drm/i915/intel_sprite.c | 4 +- 2 files changed, 23 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 827c5a513f86b..32fac724a2f8e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2217,28 +2217,6 @@ static void intel_disable_pipe(struct intel_crtc *crtc) intel_wait_for_pipe_off(crtc); } -/** - * intel_enable_primary_hw_plane - enable the primary plane on a given pipe - * @plane: plane to be enabled - * @crtc: crtc for the plane - * - * Enable @plane on @crtc, making sure that the pipe is running first. - */ -static void intel_enable_primary_hw_plane(struct drm_plane *plane, - struct drm_crtc *crtc) -{ - struct drm_device *dev = plane->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - /* If the pipe isn't enabled, we can't pump pixels and may hang */ - assert_pipe_enabled(dev_priv, intel_crtc->pipe); - to_intel_plane_state(plane->state)->visible = true; - - dev_priv->display.update_primary_plane(crtc, plane->fb, - crtc->x, crtc->y); -} - static bool need_vtd_wa(struct drm_device *dev) { #ifdef CONFIG_INTEL_IOMMU @@ -4518,20 +4496,6 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc) } } -static void intel_enable_sprite_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - enum pipe pipe = to_intel_crtc(crtc)->pipe; - struct drm_plane *plane; - struct intel_plane *intel_plane; - - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { - intel_plane = to_intel_plane(plane); - if (intel_plane->pipe == pipe) - intel_plane_restore(&intel_plane->base); - } -} - void hsw_enable_ips(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -4827,27 +4791,6 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) intel_pre_disable_primary(&crtc->base); } -static void intel_crtc_enable_planes(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int pipe = intel_crtc->pipe; - - intel_enable_primary_hw_plane(crtc->primary, crtc); - intel_enable_sprite_planes(crtc); - if (to_intel_plane_state(crtc->cursor->state)->visible) - intel_crtc_update_cursor(crtc, true); - - intel_post_enable_primary(crtc); - - /* - * FIXME: Once we grow proper nuclear flip support out of this we need - * to compute the mask of flip planes precisely. For the time being - * consider this a flip to a NULL plane. - */ - intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_ALL_MASK(pipe)); -} - static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask) { struct drm_device *dev = crtc->dev; @@ -4855,10 +4798,6 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask struct drm_plane *p; int pipe = intel_crtc->pipe; - intel_crtc_wait_for_pending_flips(crtc); - - intel_pre_disable_primary(crtc); - intel_crtc_dpms_overlay_disable(intel_crtc); drm_for_each_plane_mask(p, dev, plane_mask) @@ -6282,6 +6221,11 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) if (!intel_crtc->active) return; + if (to_intel_plane_state(crtc->primary->state)->visible) { + intel_crtc_wait_for_pending_flips(crtc); + intel_pre_disable_primary(crtc); + } + intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); @@ -11795,10 +11739,6 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, if (old_plane_state->base.fb && !fb) intel_crtc->atomic.disabled_planes |= 1 << i; - /* don't run rest during modeset yet */ - if (!intel_crtc->active || mode_changed) - return 0; - was_visible = old_plane_state->visible; visible = to_intel_plane_state(plane_state)->visible; @@ -13267,15 +13207,18 @@ static int __intel_set_mode(struct drm_atomic_state *state) drm_atomic_helper_swap_state(dev, state); for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + if (!needs_modeset(crtc->state)) continue; any_ms = true; - if (!crtc_state->active) - continue; + intel_pre_plane_update(intel_crtc); - intel_crtc_disable_planes(crtc, crtc_state->plane_mask); - dev_priv->display.crtc_disable(crtc); + if (crtc_state->active) { + intel_crtc_disable_planes(crtc, crtc_state->plane_mask); + dev_priv->display.crtc_disable(crtc); + } } /* Only after disabling all output pipelines that will be changed can we @@ -13289,15 +13232,12 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - drm_atomic_helper_commit_planes_on_crtc(crtc_state); - - if (!needs_modeset(crtc->state) || !crtc->state->active) - continue; - - update_scanline_offset(to_intel_crtc(crtc)); + if (needs_modeset(crtc->state) && crtc->state->active) { + update_scanline_offset(to_intel_crtc(crtc)); + dev_priv->display.crtc_enable(crtc); + } - dev_priv->display.crtc_enable(crtc); - intel_crtc_enable_planes(crtc); + drm_atomic_helper_commit_planes_on_crtc(crtc_state); } /* FIXME: add subpixel order */ @@ -13871,7 +13811,7 @@ intel_commit_primary_plane(struct drm_plane *plane, crtc->x = src->x1 >> 16; crtc->y = src->y1 >> 16; - if (!intel_crtc->active) + if (!crtc->state->active) return; if (state->visible) @@ -13897,7 +13837,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - intel_pre_plane_update(intel_crtc); + if (!needs_modeset(crtc->state)) + intel_pre_plane_update(intel_crtc); if (intel_crtc->atomic.update_wm) intel_update_watermarks(crtc); @@ -13905,7 +13846,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) intel_runtime_pm_get(dev_priv); /* Perform vblank evasion around commit operation */ - if (crtc->state->active && !needs_modeset(crtc->state)) + if (crtc->state->active) intel_crtc->atomic.evade = intel_pipe_update_start(intel_crtc, &intel_crtc->atomic.start_vbl_count); @@ -14113,7 +14054,7 @@ intel_commit_cursor_plane(struct drm_plane *plane, intel_crtc->cursor_bo = obj; update: - if (intel_crtc->active) + if (crtc->state->active) intel_crtc_update_cursor(crtc, state->visible); } diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 699311a9bdfe0..b605ad848b10c 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -924,16 +924,14 @@ intel_commit_sprite_plane(struct drm_plane *plane, struct intel_plane_state *state) { struct drm_crtc *crtc = state->base.crtc; - struct intel_crtc *intel_crtc; struct intel_plane *intel_plane = to_intel_plane(plane); struct drm_framebuffer *fb = state->base.fb; crtc = crtc ? crtc : plane->crtc; - intel_crtc = to_intel_crtc(crtc); plane->fb = fb; - if (!intel_crtc->active) + if (!crtc->state->active) return; if (state->visible) { -- GitLab From eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:53 +0200 Subject: [PATCH 0161/7006] drm/i915: Update less state during modeset. No need to repeatedly call update_watermarks, or update_fbc. Down to a single call to update_watermarks in .crtc_enable Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 66 +++++++--------------------- 1 file changed, 16 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 32fac724a2f8e..b77ecaebeea71 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1945,10 +1945,10 @@ static void intel_disable_shared_dpll(struct intel_crtc *crtc) /* PCH only available on ILK+ */ BUG_ON(INTEL_INFO(dev)->gen < 5); - if (WARN_ON(pll == NULL)) - return; + if (pll == NULL) + return; - if (WARN_ON(pll->config.crtc_mask == 0)) + if (WARN_ON(!(pll->config.crtc_mask & (1 << drm_crtc_index(&crtc->base))))) return; DRM_DEBUG_KMS("disable %s (active %d, on? %d) for crtc %d\n", @@ -4653,10 +4653,6 @@ intel_post_enable_primary(struct drm_crtc *crtc) */ hsw_enable_ips(intel_crtc); - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - /* * Gen2 reports pipe underruns whenever all planes are disabled. * So don't enable underrun reporting before at least some planes @@ -4711,11 +4707,6 @@ intel_pre_disable_primary(struct drm_crtc *crtc) if (HAS_GMCH_DISPLAY(dev)) intel_set_memory_cxsr(dev_priv, false); - mutex_lock(&dev->struct_mutex); - if (dev_priv->fbc.crtc == intel_crtc) - intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); - /* * FIXME IPS should be fine as long as one plane is * enabled, but in practice it seems to have problems @@ -4755,6 +4746,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) static void intel_pre_plane_update(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_plane *p; @@ -4784,8 +4776,13 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->wait_for_flips) intel_crtc_wait_for_pending_flips(&crtc->base); - if (atomic->disable_fbc) - intel_fbc_disable(dev); + if (atomic->disable_fbc && + dev_priv->fbc.crtc == crtc) { + mutex_lock(&dev->struct_mutex); + if (dev_priv->fbc.crtc == crtc) + intel_fbc_disable(dev); + mutex_unlock(&dev->struct_mutex); + } if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); @@ -5002,9 +4999,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) int pipe = intel_crtc->pipe; u32 reg, temp; - if (WARN_ON(!intel_crtc->active)) - return; - for_each_encoder_on_crtc(dev, crtc, encoder) encoder->disable(encoder); @@ -5043,18 +5037,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) I915_WRITE(PCH_DPLL_SEL, temp); } - /* disable PCH DPLL */ - intel_disable_shared_dpll(intel_crtc); - ironlake_fdi_pll_disable(intel_crtc); } - - intel_crtc->active = false; - intel_update_watermarks(crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5065,9 +5049,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder; - if (WARN_ON(!intel_crtc->active)) - return; - for_each_encoder_on_crtc(dev, crtc, encoder) { intel_opregion_notify_encoder(encoder, false); encoder->disable(encoder); @@ -5103,16 +5084,6 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); - - intel_crtc->active = false; - intel_update_watermarks(crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - - if (intel_crtc_to_shared_dpll(intel_crtc)) - intel_disable_shared_dpll(intel_crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6166,9 +6137,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) struct intel_encoder *encoder; int pipe = intel_crtc->pipe; - if (WARN_ON(!intel_crtc->active)) - return; - /* * On gen2 planes are double buffered but the pipe isn't, so we must * wait for planes to fully turn off before disabling the pipe. @@ -6202,13 +6170,6 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); - - intel_crtc->active = false; - intel_update_watermarks(crtc); - - mutex_lock(&dev->struct_mutex); - intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) @@ -11931,6 +11892,9 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) intel_crtc_check_initial_planes(crtc, crtc_state); + if (mode_changed) + intel_crtc->atomic.update_wm = !crtc_state->active; + if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && !WARN_ON(pipe_config->shared_dpll != DPLL_ID_PRIVATE)) { @@ -13218,6 +13182,8 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (crtc_state->active) { intel_crtc_disable_planes(crtc, crtc_state->plane_mask); dev_priv->display.crtc_disable(crtc); + intel_crtc->active = false; + intel_disable_shared_dpll(intel_crtc); } } -- GitLab From 818ed961e6ee7988829918b5dc41da14a05f5bc5 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:54 +0200 Subject: [PATCH 0162/7006] drm/i915: Make setting color key atomic. By making color key atomic there are no more transitional helpers. The plane check function will reject the color key when a scaler is active. Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 1 + drivers/gpu/drm/i915/intel_display.c | 7 +- drivers/gpu/drm/i915/intel_drv.h | 6 +- drivers/gpu/drm/i915/intel_sprite.c | 85 +++++++++++------------ 4 files changed, 46 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 91d53768df9d5..10a8ecedc942f 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -56,6 +56,7 @@ intel_create_plane_state(struct drm_plane *plane) state->base.plane = plane; state->base.rotation = BIT(DRM_ROTATE_0); + state->ckey.flags = I915_SET_COLORKEY_NONE; return state; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b77ecaebeea71..30ffca865e1d7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4411,9 +4411,9 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, return ret; /* check colorkey */ - if (WARN_ON(intel_plane->ckey.flags != I915_SET_COLORKEY_NONE)) { + if (plane_state->ckey.flags != I915_SET_COLORKEY_NONE) { DRM_DEBUG_KMS("[PLANE:%d] scaling with color key not allowed", - intel_plane->base.base.id); + intel_plane->base.base.id); return -EINVAL; } @@ -13746,7 +13746,7 @@ intel_check_primary_plane(struct drm_plane *plane, /* use scaler when colorkey is not required */ if (INTEL_INFO(plane->dev)->gen >= 9 && - to_intel_plane(plane)->ckey.flags == I915_SET_COLORKEY_NONE) { + state->ckey.flags == I915_SET_COLORKEY_NONE) { min_scale = 1; max_scale = skl_max_scale(to_intel_crtc(crtc), crtc_state); can_position = true; @@ -13892,7 +13892,6 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, primary->check_plane = intel_check_primary_plane; primary->commit_plane = intel_commit_primary_plane; primary->disable_plane = intel_disable_primary_plane; - primary->ckey.flags = I915_SET_COLORKEY_NONE; if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) primary->plane = !pipe; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3127c9ae4b42f..d48b98014080d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -274,6 +274,8 @@ struct intel_plane_state { * update_scaler_plane. */ int scaler_id; + + struct drm_intel_sprite_colorkey ckey; }; struct intel_initial_plane_config { @@ -588,9 +590,6 @@ struct intel_plane { bool can_scale; int max_downscale; - /* FIXME convert to properties */ - struct drm_intel_sprite_colorkey ckey; - /* Since we need to change the watermarks before/after * enabling/disabling the planes, we need to store the parameters here * as the other pieces of the struct may not reflect the values we want @@ -1392,7 +1391,6 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); /* intel_sprite.c */ int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); -int intel_plane_restore(struct drm_plane *plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); bool intel_pipe_update_start(struct intel_crtc *crtc, diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index b605ad848b10c..e0045aa97bd22 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -182,7 +182,8 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc, const int plane = intel_plane->plane + 1; u32 plane_ctl, stride_div, stride; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(drm_plane->state)->ckey; unsigned long surf_addr; u32 tile_height, plane_offset, plane_size; unsigned int rotation; @@ -344,7 +345,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, u32 sprctl; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(dplane->state)->ckey; sprctl = SP_ENABLE; @@ -488,7 +490,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, u32 sprctl, sprscale = 0; unsigned long sprsurf_offset, linear_offset; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(plane->state)->ckey; sprctl = SPRITE_ENABLE; @@ -629,7 +632,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, unsigned long dvssurf_offset, linear_offset; u32 dvscntr, dvsscale; int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0); - const struct drm_intel_sprite_colorkey *key = &intel_plane->ckey; + const struct drm_intel_sprite_colorkey *key = + &to_intel_plane_state(plane->state)->ckey; dvscntr = DVS_ENABLE; @@ -781,7 +785,7 @@ intel_check_sprite_plane(struct drm_plane *plane, /* setup can_scale, min_scale, max_scale */ if (INTEL_INFO(dev)->gen >= 9) { /* use scaler when colorkey is not required */ - if (intel_plane->ckey.flags == I915_SET_COLORKEY_NONE) { + if (state->ckey.flags == I915_SET_COLORKEY_NONE) { can_scale = 1; min_scale = 1; max_scale = skl_max_scale(intel_crtc, crtc_state); @@ -801,7 +805,6 @@ intel_check_sprite_plane(struct drm_plane *plane, * coordinates and sizes. We probably need some way to decide whether * more strict checking should be done instead. */ - drm_rect_rotate(src, fb->width << 16, fb->height << 16, state->base.rotation); @@ -811,7 +814,7 @@ intel_check_sprite_plane(struct drm_plane *plane, vscale = drm_rect_calc_vscale_relaxed(src, dst, min_scale, max_scale); BUG_ON(vscale < 0); - state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); + state->visible = drm_rect_clip_scaled(src, dst, clip, hscale, vscale); crtc_x = dst->x1; crtc_y = dst->y1; @@ -953,7 +956,9 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, { struct drm_intel_sprite_colorkey *set = data; struct drm_plane *plane; - struct intel_plane *intel_plane; + struct drm_plane_state *plane_state; + struct drm_atomic_state *state; + struct drm_modeset_acquire_ctx ctx; int ret = 0; /* Make sure we don't try to enable both src & dest simultaneously */ @@ -964,50 +969,41 @@ int intel_sprite_set_colorkey(struct drm_device *dev, void *data, set->flags & I915_SET_COLORKEY_DESTINATION) return -EINVAL; - drm_modeset_lock_all(dev); - plane = drm_plane_find(dev, set->plane_id); - if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) { - ret = -ENOENT; - goto out_unlock; - } + if (!plane || plane->type != DRM_PLANE_TYPE_OVERLAY) + return -ENOENT; - intel_plane = to_intel_plane(plane); + drm_modeset_acquire_init(&ctx, 0); - if (INTEL_INFO(dev)->gen >= 9) { - /* plane scaling and colorkey are mutually exclusive */ - if (to_intel_plane_state(plane->state)->scaler_id >= 0) { - DRM_ERROR("colorkey not allowed with scaler\n"); - ret = -EINVAL; - goto out_unlock; - } + state = drm_atomic_state_alloc(plane->dev); + if (!state) { + ret = -ENOMEM; + goto out; } + state->acquire_ctx = &ctx; + + while (1) { + plane_state = drm_atomic_get_plane_state(state, plane); + ret = PTR_ERR_OR_ZERO(plane_state); + if (!ret) { + to_intel_plane_state(plane_state)->ckey = *set; + ret = drm_atomic_commit(state); + } - intel_plane->ckey = *set; - - /* - * The only way this could fail would be due to - * the current plane state being unsupportable already, - * and we dont't consider that an error for the - * colorkey ioctl. So just ignore any error. - */ - intel_plane_restore(plane); + if (ret != -EDEADLK) + break; -out_unlock: - drm_modeset_unlock_all(dev); - return ret; -} + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + } -int intel_plane_restore(struct drm_plane *plane) -{ - if (!plane->crtc || !plane->state->fb) - return 0; + if (ret) + drm_atomic_state_free(state); - return drm_plane_helper_update(plane, plane->crtc, plane->state->fb, - plane->state->crtc_x, plane->state->crtc_y, - plane->state->crtc_w, plane->state->crtc_h, - plane->state->src_x, plane->state->src_y, - plane->state->src_w, plane->state->src_h); +out: + drm_modeset_drop_locks(&ctx); + drm_modeset_acquire_fini(&ctx); + return ret; } static const uint32_t ilk_plane_formats[] = { @@ -1136,7 +1132,6 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->plane = plane; intel_plane->check_plane = intel_check_sprite_plane; intel_plane->commit_plane = intel_commit_sprite_plane; - intel_plane->ckey.flags = I915_SET_COLORKEY_NONE; possible_crtcs = (1 << pipe); ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs, &intel_plane_funcs, -- GitLab From c389c9c4d981e49185b1c89354c85608effefe50 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:55 +0200 Subject: [PATCH 0163/7006] drm/i915: Remove transitional references from intel_plane_atomic_check. All transitional plane helpers are gone, party! Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic_plane.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c index 10a8ecedc942f..f1ab8e4b9c11c 100644 --- a/drivers/gpu/drm/i915/intel_atomic_plane.c +++ b/drivers/gpu/drm/i915/intel_atomic_plane.c @@ -115,6 +115,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, struct intel_crtc_state *crtc_state; struct intel_plane *intel_plane = to_intel_plane(plane); struct intel_plane_state *intel_state = to_intel_plane_state(state); + struct drm_crtc_state *drm_crtc_state; int ret; crtc = crtc ? crtc : plane->state->crtc; @@ -129,19 +130,11 @@ static int intel_plane_atomic_check(struct drm_plane *plane, if (!crtc) return 0; - /* FIXME: temporary hack necessary while we still use the plane update - * helper. */ - if (state->state) { - struct drm_crtc_state *drm_crtc_state = - drm_atomic_get_existing_crtc_state(state->state, crtc); + drm_crtc_state = drm_atomic_get_existing_crtc_state(state->state, crtc); + if (WARN_ON(!drm_crtc_state)) + return -EINVAL; - if (WARN_ON(!drm_crtc_state)) - return -EINVAL; - - crtc_state = to_intel_crtc_state(drm_crtc_state); - } else { - crtc_state = intel_crtc->config; - } + crtc_state = to_intel_crtc_state(drm_crtc_state); /* * The original src/dest coordinates are stored in state->base, but @@ -191,7 +184,7 @@ static int intel_plane_atomic_check(struct drm_plane *plane, intel_state->visible = false; ret = intel_plane->check_plane(plane, crtc_state, intel_state); - if (ret || !state->state) + if (ret) return ret; return intel_plane_atomic_calc_changes(&crtc_state->base, state); -- GitLab From 27c329ed16ddf5540151dfa9d22c584b819e0718 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 15 Jun 2015 12:33:56 +0200 Subject: [PATCH 0164/7006] drm/i915: Make cdclk part of the atomic state. The skylake scalers depend on the cdclk freq, but that frequency can change during a modeset. So when a modeset happens calculate the new cdclk in the atomic state. With the transitional helpers gone the cached value can be used in the scaler, and committed after all crtc's are disabled. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90874 Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_atomic.c | 2 + drivers/gpu/drm/i915/intel_display.c | 274 +++++++++++++-------------- drivers/gpu/drm/i915/intel_drv.h | 1 + 4 files changed, 135 insertions(+), 145 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 290017857c6da..3e36af90f9430 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -619,7 +619,8 @@ struct drm_i915_display_funcs { struct drm_crtc *crtc, uint32_t sprite_width, uint32_t sprite_height, int pixel_size, bool enable, bool scaled); - void (*modeset_global_resources)(struct drm_atomic_state *state); + int (*modeset_calc_cdclk)(struct drm_atomic_state *state); + void (*modeset_commit_cdclk)(struct drm_atomic_state *state); /* Returns the active state of the crtc, and if the crtc is active, * fills out the pipe-config with the hw state. */ bool (*get_pipe_config)(struct intel_crtc *, diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 060d98b10f83f..0aeced82201e4 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -54,6 +54,8 @@ int intel_atomic_check(struct drm_device *dev, int i; bool not_nuclear = false; + to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq; + /* * FIXME: At the moment, we only support "nuclear pageflip" on a * single CRTC. Cross-crtc updates will be added later. diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 30ffca865e1d7..64c6c38ec8af2 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5204,8 +5204,13 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) intel_display_power_get(dev_priv, domain); } - if (dev_priv->display.modeset_global_resources) - dev_priv->display.modeset_global_resources(state); + if (dev_priv->display.modeset_commit_cdclk) { + unsigned int cdclk = to_intel_atomic_state(state)->cdclk; + + if (cdclk != dev_priv->cdclk_freq && + !WARN_ON(!state->allow_modeset)) + dev_priv->display.modeset_commit_cdclk(state); + } for_each_intel_crtc(dev, crtc) { enum intel_display_power_domain domain; @@ -5859,11 +5864,7 @@ static int intel_mode_max_pixclk(struct drm_device *dev, int max_pixclk = 0; for_each_intel_crtc(dev, intel_crtc) { - if (state) - crtc_state = - intel_atomic_get_crtc_state(state, intel_crtc); - else - crtc_state = intel_crtc->config; + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); @@ -5877,46 +5878,34 @@ static int intel_mode_max_pixclk(struct drm_device *dev, return max_pixclk; } -static int valleyview_modeset_global_pipes(struct drm_atomic_state *state) +static int valleyview_modeset_calc_cdclk(struct drm_atomic_state *state) { - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int max_pixclk = intel_mode_max_pixclk(state->dev, state); - int cdclk, ret = 0; + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev, state); if (max_pixclk < 0) return max_pixclk; - if (IS_VALLEYVIEW(dev_priv)) - cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - else - cdclk = broxton_calc_cdclk(dev_priv, max_pixclk); - - if (cdclk == dev_priv->cdclk_freq) - return 0; - - /* add all active pipes to the state */ - for_each_crtc(state->dev, crtc) { - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); + to_intel_atomic_state(state)->cdclk = + valleyview_calc_cdclk(dev_priv, max_pixclk); - if (!crtc_state->active || needs_modeset(crtc_state)) - continue; + return 0; +} - crtc_state->mode_changed = true; +static int broxton_modeset_calc_cdclk(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + int max_pixclk = intel_mode_max_pixclk(dev, state); - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - break; + if (max_pixclk < 0) + return max_pixclk; - ret = drm_atomic_add_affected_planes(state, crtc); - if (ret) - break; - } + to_intel_atomic_state(state)->cdclk = + broxton_calc_cdclk(dev_priv, max_pixclk); - return ret; + return 0; } static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) @@ -5955,41 +5944,31 @@ static void vlv_program_pfi_credits(struct drm_i915_private *dev_priv) WARN_ON(I915_READ(GCI_CONTROL) & PFI_CREDIT_RESEND); } -static void valleyview_modeset_global_resources(struct drm_atomic_state *old_state) +static void valleyview_modeset_commit_cdclk(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev, NULL); - int req_cdclk; - - /* The path in intel_mode_max_pixclk() with a NULL atomic state should - * never fail. */ - if (WARN_ON(max_pixclk < 0)) - return; - - req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk); - if (req_cdclk != dev_priv->cdclk_freq) { - /* - * FIXME: We can end up here with all power domains off, yet - * with a CDCLK frequency other than the minimum. To account - * for this take the PIPE-A power domain, which covers the HW - * blocks needed for the following programming. This can be - * removed once it's guaranteed that we get here either with - * the minimum CDCLK set, or the required power domains - * enabled. - */ - intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A); + /* + * FIXME: We can end up here with all power domains off, yet + * with a CDCLK frequency other than the minimum. To account + * for this take the PIPE-A power domain, which covers the HW + * blocks needed for the following programming. This can be + * removed once it's guaranteed that we get here either with + * the minimum CDCLK set, or the required power domains + * enabled. + */ + intel_display_power_get(dev_priv, POWER_DOMAIN_PIPE_A); - if (IS_CHERRYVIEW(dev)) - cherryview_set_cdclk(dev, req_cdclk); - else - valleyview_set_cdclk(dev, req_cdclk); + if (IS_CHERRYVIEW(dev)) + cherryview_set_cdclk(dev, req_cdclk); + else + valleyview_set_cdclk(dev, req_cdclk); - vlv_program_pfi_credits(dev_priv); + vlv_program_pfi_credits(dev_priv); - intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A); - } + intel_display_power_put(dev_priv, POWER_DOMAIN_PIPE_A); } static void valleyview_crtc_enable(struct drm_crtc *crtc) @@ -9490,41 +9469,35 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv) intel_prepare_ddi(dev); } -static void broxton_modeset_global_resources(struct drm_atomic_state *old_state) +static void broxton_modeset_commit_cdclk(struct drm_atomic_state *old_state) { struct drm_device *dev = old_state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixclk = intel_mode_max_pixclk(dev, NULL); - int req_cdclk; - - /* see the comment in valleyview_modeset_global_resources */ - if (WARN_ON(max_pixclk < 0)) - return; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; - req_cdclk = broxton_calc_cdclk(dev_priv, max_pixclk); - - if (req_cdclk != dev_priv->cdclk_freq) - broxton_set_cdclk(dev, req_cdclk); + broxton_set_cdclk(dev, req_cdclk); } /* compute the max rate for new configuration */ -static int ilk_max_pixel_rate(struct drm_i915_private *dev_priv) +static int ilk_max_pixel_rate(struct drm_atomic_state *state) { - struct drm_device *dev = dev_priv->dev; struct intel_crtc *intel_crtc; - struct drm_crtc *crtc; + struct intel_crtc_state *crtc_state; int max_pixel_rate = 0; - int pixel_rate; - for_each_crtc(dev, crtc) { - if (!crtc->state->enable) + for_each_intel_crtc(state->dev, intel_crtc) { + int pixel_rate; + + crtc_state = intel_atomic_get_crtc_state(state, intel_crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->base.enable) continue; - intel_crtc = to_intel_crtc(crtc); - pixel_rate = ilk_pipe_pixel_rate(intel_crtc->config); + pixel_rate = ilk_pipe_pixel_rate(crtc_state); /* pixel rate mustn't exceed 95% of cdclk with IPS on BDW */ - if (IS_BROADWELL(dev) && intel_crtc->config->ips_enabled) + if (IS_BROADWELL(state->dev) && crtc_state->ips_enabled) pixel_rate = DIV_ROUND_UP(pixel_rate * 100, 95); max_pixel_rate = max(max_pixel_rate, pixel_rate); @@ -9610,20 +9583,21 @@ static void broadwell_set_cdclk(struct drm_device *dev, int cdclk) cdclk, dev_priv->cdclk_freq); } -static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, - int max_pixel_rate) +static int broadwell_modeset_calc_cdclk(struct drm_atomic_state *state) { + struct drm_i915_private *dev_priv = to_i915(state->dev); + int max_pixclk = ilk_max_pixel_rate(state); int cdclk; /* * FIXME should also account for plane ratio * once 64bpp pixel formats are supported. */ - if (max_pixel_rate > 540000) + if (max_pixclk > 540000) cdclk = 675000; - else if (max_pixel_rate > 450000) + else if (max_pixclk > 450000) cdclk = 540000; - else if (max_pixel_rate > 337500) + else if (max_pixclk > 337500) cdclk = 450000; else cdclk = 337500; @@ -9638,49 +9612,17 @@ static int broadwell_calc_cdclk(struct drm_i915_private *dev_priv, cdclk = dev_priv->max_cdclk_freq; } - return cdclk; -} - -static int broadwell_modeset_global_pipes(struct drm_atomic_state *state) -{ - struct drm_i915_private *dev_priv = to_i915(state->dev); - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int max_pixclk = ilk_max_pixel_rate(dev_priv); - int cdclk, i; - - cdclk = broadwell_calc_cdclk(dev_priv, max_pixclk); - - if (cdclk == dev_priv->cdclk_freq) - return 0; - - /* add all active pipes to the state */ - for_each_crtc(state->dev, crtc) { - if (!crtc->state->enable) - continue; - - crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } - - /* disable/enable all currently active pipes while we change cdclk */ - for_each_crtc_in_state(state, crtc, crtc_state, i) - if (crtc_state->enable) - crtc_state->mode_changed = true; + to_intel_atomic_state(state)->cdclk = cdclk; return 0; } -static void broadwell_modeset_global_resources(struct drm_atomic_state *state) +static void broadwell_modeset_commit_cdclk(struct drm_atomic_state *old_state) { - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - int max_pixel_rate = ilk_max_pixel_rate(dev_priv); - int req_cdclk = broadwell_calc_cdclk(dev_priv, max_pixel_rate); + struct drm_device *dev = old_state->dev; + unsigned int req_cdclk = to_intel_atomic_state(old_state)->cdclk; - if (req_cdclk != dev_priv->cdclk_freq) - broadwell_set_cdclk(dev, req_cdclk); + broadwell_set_cdclk(dev, req_cdclk); } static int haswell_crtc_compute_clock(struct intel_crtc *crtc, @@ -13056,10 +12998,41 @@ static int haswell_mode_set_planes_workaround(struct drm_atomic_state *state) return 0; } +static int intel_modeset_all_pipes(struct drm_atomic_state *state) +{ + struct drm_crtc *crtc; + struct drm_crtc_state *crtc_state; + int ret = 0; + + /* add all active pipes to the state */ + for_each_crtc(state->dev, crtc) { + crtc_state = drm_atomic_get_crtc_state(state, crtc); + if (IS_ERR(crtc_state)) + return PTR_ERR(crtc_state); + + if (!crtc_state->active || needs_modeset(crtc_state)) + continue; + + crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + break; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + break; + } + + return ret; +} + + /* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; int ret; if (!check_digital_port_conflicts(state)) { @@ -13074,15 +13047,19 @@ static int intel_modeset_checks(struct drm_atomic_state *state) * mode set on this crtc. For other crtcs we need to use the * adjusted_mode bits in the crtc directly. */ - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev) || IS_BROADWELL(dev)) { - if (IS_VALLEYVIEW(dev) || IS_BROXTON(dev)) - ret = valleyview_modeset_global_pipes(state); - else - ret = broadwell_modeset_global_pipes(state); + if (dev_priv->display.modeset_calc_cdclk) { + unsigned int cdclk; - if (ret) + ret = dev_priv->display.modeset_calc_cdclk(state); + + cdclk = to_intel_atomic_state(state)->cdclk; + if (!ret && cdclk != dev_priv->cdclk_freq) + ret = intel_modeset_all_pipes(state); + + if (ret < 0) return ret; - } + } else + to_intel_atomic_state(state)->cdclk = dev_priv->cdclk_freq; intel_modeset_clear_plls(state); @@ -13149,7 +13126,9 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; - } + } else + to_intel_atomic_state(state)->cdclk = + to_i915(state->dev)->cdclk_freq; return drm_atomic_helper_check_planes(state->dev, state); } @@ -13717,7 +13696,7 @@ skl_max_scale(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state dev = intel_crtc->base.dev; dev_priv = dev->dev_private; crtc_clock = crtc_state->base.adjusted_mode.crtc_clock; - cdclk = dev_priv->display.get_display_clock_speed(dev); + cdclk = to_intel_atomic_state(crtc_state->base.state)->cdclk; if (!crtc_clock || !cdclk) return DRM_PLANE_HELPER_NO_SCALING; @@ -14786,15 +14765,22 @@ static void intel_init_display(struct drm_device *dev) dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train; } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { dev_priv->display.fdi_link_train = hsw_fdi_link_train; - if (IS_BROADWELL(dev)) - dev_priv->display.modeset_global_resources = - broadwell_modeset_global_resources; + if (IS_BROADWELL(dev)) { + dev_priv->display.modeset_commit_cdclk = + broadwell_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + broadwell_modeset_calc_cdclk; + } } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.modeset_global_resources = - valleyview_modeset_global_resources; + dev_priv->display.modeset_commit_cdclk = + valleyview_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + valleyview_modeset_calc_cdclk; } else if (IS_BROXTON(dev)) { - dev_priv->display.modeset_global_resources = - broxton_modeset_global_resources; + dev_priv->display.modeset_commit_cdclk = + broxton_modeset_commit_cdclk; + dev_priv->display.modeset_calc_cdclk = + broxton_modeset_calc_cdclk; } switch (INTEL_INFO(dev)->gen) { diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index d48b98014080d..853bfd98ef725 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -244,6 +244,7 @@ typedef struct dpll { struct intel_atomic_state { struct drm_atomic_state base; + unsigned int cdclk; bool dpll_set; struct intel_shared_dpll_config shared_dpll[I915_NUM_PLLS]; }; -- GitLab From a0049865ea53df19a3f14128fa080719e8f4bdba Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:13 +0300 Subject: [PATCH 0165/7006] drm/i915/irq: move hotplug even debug print to second connector loop The hotplug work function has two loops iterating over connectors, the first for handling hotplug disabling due to irq storms and the second for actually handling the hotplug events. Move the debug printing into the second one, so we can abstract the storm handling better. This may change the output ordering slightly when there are multiple simultaneous hotplug events. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 56db9e7474646..d64d6895a2e52 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -917,10 +917,6 @@ static void i915_hotplug_work_func(struct work_struct *work) | DRM_CONNECTOR_POLL_DISCONNECT; hpd_disabled = true; } - if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { - DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", - connector->name, intel_encoder->hpd_pin); - } } /* if there were no outputs to poll, poll was disabled, * therefore make sure it's enabled when disabling HPD on @@ -939,6 +935,8 @@ static void i915_hotplug_work_func(struct work_struct *work) continue; intel_encoder = intel_connector->encoder; if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { + DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", + connector->name, intel_encoder->hpd_pin); if (intel_encoder->hot_plug) intel_encoder->hot_plug(intel_encoder); if (intel_hpd_irq_event(dev, connector)) -- GitLab From 70f71d5ff465965e2cfdb6f3f195a7b3fe2ab5cc Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:14 +0300 Subject: [PATCH 0166/7006] drm/i915/irq: abstract irq storm hotplug disabling Continue abstracting hotplug storm related functions to clarify the code. This time, abstract hotplug irq storm related hotplug disabling. While at it, clean up the loop iterating over connectors for readability. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 77 +++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d64d6895a2e52..bf4c15d0ea2bf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -879,7 +879,7 @@ static void i915_digport_work_func(struct work_struct *work) /* * Handle hotplug events outside the interrupt handler proper. */ -#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) +static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv); static void i915_hotplug_work_func(struct work_struct *work) { @@ -890,7 +890,6 @@ static void i915_hotplug_work_func(struct work_struct *work) struct intel_connector *intel_connector; struct intel_encoder *intel_encoder; struct drm_connector *connector; - bool hpd_disabled = false; bool changed = false; u32 hpd_event_bits; @@ -901,31 +900,9 @@ static void i915_hotplug_work_func(struct work_struct *work) hpd_event_bits = dev_priv->hotplug.event_bits; dev_priv->hotplug.event_bits = 0; - list_for_each_entry(connector, &mode_config->connector_list, head) { - intel_connector = to_intel_connector(connector); - if (!intel_connector->encoder) - continue; - intel_encoder = intel_connector->encoder; - if (intel_encoder->hpd_pin > HPD_NONE && - dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_MARK_DISABLED && - connector->polled == DRM_CONNECTOR_POLL_HPD) { - DRM_INFO("HPD interrupt storm detected on connector %s: " - "switching from hotplug detection to polling\n", - connector->name); - dev_priv->hotplug.stats[intel_encoder->hpd_pin].state = HPD_DISABLED; - connector->polled = DRM_CONNECTOR_POLL_CONNECT - | DRM_CONNECTOR_POLL_DISCONNECT; - hpd_disabled = true; - } - } - /* if there were no outputs to poll, poll was disabled, - * therefore make sure it's enabled when disabling HPD on - * some connectors */ - if (hpd_disabled) { - drm_kms_helper_poll_enable(dev); - mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, - msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); - } + + /* Disable hotplug on connectors that hit an irq storm. */ + intel_hpd_irq_storm_disable(dev_priv); spin_unlock_irq(&dev_priv->irq_lock); @@ -1411,6 +1388,52 @@ static bool intel_hpd_irq_storm(struct drm_i915_private *dev_priv, return storm; } +#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) + +static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + enum hpd_pin pin; + bool hpd_disabled = false; + + assert_spin_locked(&dev_priv->irq_lock); + + list_for_each_entry(connector, &mode_config->connector_list, head) { + if (connector->polled != DRM_CONNECTOR_POLL_HPD) + continue; + + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (!intel_encoder) + continue; + + pin = intel_encoder->hpd_pin; + if (pin == HPD_NONE || + dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) + continue; + + DRM_INFO("HPD interrupt storm detected on connector %s: " + "switching from hotplug detection to polling\n", + connector->name); + + dev_priv->hotplug.stats[pin].state = HPD_DISABLED; + connector->polled = DRM_CONNECTOR_POLL_CONNECT + | DRM_CONNECTOR_POLL_DISCONNECT; + hpd_disabled = true; + } + + /* Enable polling and queue hotplug re-enabling. */ + if (hpd_disabled) { + drm_kms_helper_poll_enable(dev); + mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, + msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); + } +} + static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { -- GitLab From 10b0e9e904c409be8e2476058d9b19a6b37d619e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:15 +0300 Subject: [PATCH 0167/7006] drm/i915/irq: clarify irq storm related function naming We'll have three functions: intel_hpd_irq_storm_detect for detecting irq storms, intel_hpd_irq_storm_disable for disabling hotplugs after detected storms, intel_hpd_irq_storm_reenable_work for re-enabling hotplug. No functional changes. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index bf4c15d0ea2bf..ce9eef5f722ca 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1350,7 +1350,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, #define HPD_STORM_THRESHOLD 5 /** - * intel_hpd_irq_storm - gather stats and detect HPD irq storm on a pin + * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin * @dev_priv: private driver data pointer * @pin: the pin to gather stats on * @@ -1364,8 +1364,8 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, * * Return true if an irq storm was detected on @pin. */ -static bool intel_hpd_irq_storm(struct drm_i915_private *dev_priv, - enum hpd_pin pin) +static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, + enum hpd_pin pin) { unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); @@ -1603,7 +1603,7 @@ static void intel_hpd_irq_handler(struct drm_device *dev, queue_hp = true; } - if (intel_hpd_irq_storm(dev_priv, i)) { + if (intel_hpd_irq_storm_detect(dev_priv, i)) { dev_priv->hotplug.event_bits &= ~BIT(i); storm_detected = true; } @@ -4367,7 +4367,7 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } -static void intel_hpd_irq_reenable_work(struct work_struct *work) +static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), @@ -4433,7 +4433,7 @@ void intel_irq_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, - intel_hpd_irq_reenable_work); + intel_hpd_irq_storm_reenable_work); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); -- GitLab From 77913b39addfaa836929815515ff55cea1142b66 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:16 +0300 Subject: [PATCH 0168/7006] drm/i915: move generic hotplug code into new intel_hotplug.c file We have enough generic hotplug functions sprinkled all over i915_irq.c to warrant moving them to a file of their own. This should further underline the distinction between generic code in the new file and platform specific hotplug and irq code that remains in i915_irq.c. Add new intel_hpd_init_work to keep work functions static, and rename get_port_from_pin to intel_hpd_pin_to_port while increasing its visibility, but keep everything else the same. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.c | 15 - drivers/gpu/drm/i915/i915_drv.h | 9 +- drivers/gpu/drm/i915/i915_irq.c | 409 +----------------------- drivers/gpu/drm/i915/intel_hotplug.c | 452 +++++++++++++++++++++++++++ 5 files changed, 464 insertions(+), 422 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_hotplug.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index b7ddf48e1d758..de21965433676 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -34,6 +34,7 @@ i915-y += i915_cmd_parser.o \ i915_gpu_error.o \ i915_irq.o \ i915_trace_points.o \ + intel_hotplug.o \ intel_lrc.o \ intel_ringbuffer.o \ intel_uncore.o diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 78ef0bb53c36a..0ec57bad454fb 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -541,21 +541,6 @@ bool i915_semaphore_is_enabled(struct drm_device *dev) return true; } -void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) -{ - spin_lock_irq(&dev_priv->irq_lock); - - dev_priv->hotplug.long_port_mask = 0; - dev_priv->hotplug.short_port_mask = 0; - dev_priv->hotplug.event_bits = 0; - - spin_unlock_irq(&dev_priv->irq_lock); - - cancel_work_sync(&dev_priv->hotplug.dig_port_work); - cancel_work_sync(&dev_priv->hotplug.hotplug_work); - cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); -} - void i915_firmware_load_error_print(const char *fw_path, int err) { DRM_ERROR("failed to load firmware %s (%d)\n", fw_path, err); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3e36af90f9430..c3b9fcf301a07 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2601,9 +2601,15 @@ extern unsigned long i915_mch_val(struct drm_i915_private *dev_priv); extern unsigned long i915_gfx_val(struct drm_i915_private *dev_priv); extern void i915_update_gfx_val(struct drm_i915_private *dev_priv); int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on); -void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); void i915_firmware_load_error_print(const char *fw_path, int err); +/* intel_hotplug.c */ +void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask); +void intel_hpd_init(struct drm_i915_private *dev_priv); +void intel_hpd_init_work(struct drm_i915_private *dev_priv); +void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); +enum port intel_hpd_pin_to_port(enum hpd_pin pin); + /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); __printf(3, 4) @@ -2611,7 +2617,6 @@ void i915_handle_error(struct drm_device *dev, bool wedged, const char *fmt, ...); extern void intel_irq_init(struct drm_i915_private *dev_priv); -extern void intel_hpd_init(struct drm_i915_private *dev_priv); int intel_irq_install(struct drm_i915_private *dev_priv); void intel_irq_uninstall(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index ce9eef5f722ca..2d3b2ccf9ce4c 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -807,125 +807,6 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe, &crtc->hwmode); } -static bool intel_hpd_irq_event(struct drm_device *dev, - struct drm_connector *connector) -{ - enum drm_connector_status old_status; - - WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); - old_status = connector->status; - - connector->status = connector->funcs->detect(connector, false); - if (old_status == connector->status) - return false; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", - connector->base.id, - connector->name, - drm_get_connector_status_name(old_status), - drm_get_connector_status_name(connector->status)); - - return true; -} - -static void i915_digport_work_func(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, hotplug.dig_port_work); - u32 long_port_mask, short_port_mask; - struct intel_digital_port *intel_dig_port; - int i; - u32 old_bits = 0; - - spin_lock_irq(&dev_priv->irq_lock); - long_port_mask = dev_priv->hotplug.long_port_mask; - dev_priv->hotplug.long_port_mask = 0; - short_port_mask = dev_priv->hotplug.short_port_mask; - dev_priv->hotplug.short_port_mask = 0; - spin_unlock_irq(&dev_priv->irq_lock); - - for (i = 0; i < I915_MAX_PORTS; i++) { - bool valid = false; - bool long_hpd = false; - intel_dig_port = dev_priv->hotplug.irq_port[i]; - if (!intel_dig_port || !intel_dig_port->hpd_pulse) - continue; - - if (long_port_mask & (1 << i)) { - valid = true; - long_hpd = true; - } else if (short_port_mask & (1 << i)) - valid = true; - - if (valid) { - enum irqreturn ret; - - ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd); - if (ret == IRQ_NONE) { - /* fall back to old school hpd */ - old_bits |= (1 << intel_dig_port->base.hpd_pin); - } - } - } - - if (old_bits) { - spin_lock_irq(&dev_priv->irq_lock); - dev_priv->hotplug.event_bits |= old_bits; - spin_unlock_irq(&dev_priv->irq_lock); - schedule_work(&dev_priv->hotplug.hotplug_work); - } -} - -/* - * Handle hotplug events outside the interrupt handler proper. - */ -static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv); - -static void i915_hotplug_work_func(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, struct drm_i915_private, hotplug.hotplug_work); - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_connector *intel_connector; - struct intel_encoder *intel_encoder; - struct drm_connector *connector; - bool changed = false; - u32 hpd_event_bits; - - mutex_lock(&mode_config->mutex); - DRM_DEBUG_KMS("running encoder hotplug functions\n"); - - spin_lock_irq(&dev_priv->irq_lock); - - hpd_event_bits = dev_priv->hotplug.event_bits; - dev_priv->hotplug.event_bits = 0; - - /* Disable hotplug on connectors that hit an irq storm. */ - intel_hpd_irq_storm_disable(dev_priv); - - spin_unlock_irq(&dev_priv->irq_lock); - - list_for_each_entry(connector, &mode_config->connector_list, head) { - intel_connector = to_intel_connector(connector); - if (!intel_connector->encoder) - continue; - intel_encoder = intel_connector->encoder; - if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { - DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", - connector->name, intel_encoder->hpd_pin); - if (intel_encoder->hot_plug) - intel_encoder->hot_plug(intel_encoder); - if (intel_hpd_irq_event(dev, connector)) - changed = true; - } - } - mutex_unlock(&mode_config->mutex); - - if (changed) - drm_kms_helper_hotplug_event(dev); -} - static void ironlake_rps_change_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1346,94 +1227,6 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, return ret; } -#define HPD_STORM_DETECT_PERIOD 1000 -#define HPD_STORM_THRESHOLD 5 - -/** - * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin - * @dev_priv: private driver data pointer - * @pin: the pin to gather stats on - * - * Gather stats about HPD irqs from the specified @pin, and detect irq - * storms. Only the pin specific stats and state are changed, the caller is - * responsible for further action. - * - * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, - * otherwise it's considered an irq storm, and the irq state is set to - * @HPD_MARK_DISABLED. - * - * Return true if an irq storm was detected on @pin. - */ -static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, - enum hpd_pin pin) -{ - unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; - unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); - bool storm = false; - - if (!time_in_range(jiffies, start, end)) { - dev_priv->hotplug.stats[pin].last_jiffies = jiffies; - dev_priv->hotplug.stats[pin].count = 0; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); - } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { - dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; - DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); - storm = true; - } else { - dev_priv->hotplug.stats[pin].count++; - DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, - dev_priv->hotplug.stats[pin].count); - } - - return storm; -} - -#define I915_REENABLE_HOTPLUG_DELAY (2*60*1000) - -static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct intel_connector *intel_connector; - struct intel_encoder *intel_encoder; - struct drm_connector *connector; - enum hpd_pin pin; - bool hpd_disabled = false; - - assert_spin_locked(&dev_priv->irq_lock); - - list_for_each_entry(connector, &mode_config->connector_list, head) { - if (connector->polled != DRM_CONNECTOR_POLL_HPD) - continue; - - intel_connector = to_intel_connector(connector); - intel_encoder = intel_connector->encoder; - if (!intel_encoder) - continue; - - pin = intel_encoder->hpd_pin; - if (pin == HPD_NONE || - dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) - continue; - - DRM_INFO("HPD interrupt storm detected on connector %s: " - "switching from hotplug detection to polling\n", - connector->name); - - dev_priv->hotplug.stats[pin].state = HPD_DISABLED; - connector->polled = DRM_CONNECTOR_POLL_CONNECT - | DRM_CONNECTOR_POLL_DISCONNECT; - hpd_disabled = true; - } - - /* Enable polling and queue hotplug re-enabling. */ - if (hpd_disabled) { - drm_kms_helper_poll_enable(dev); - mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, - msecs_to_jiffies(I915_REENABLE_HOTPLUG_DELAY)); - } -} - static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -1462,20 +1255,6 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) } } -static enum port get_port_from_pin(enum hpd_pin pin) -{ - switch (pin) { - case HPD_PORT_B: - return PORT_B; - case HPD_PORT_C: - return PORT_C; - case HPD_PORT_D: - return PORT_D; - default: - return PORT_A; /* no hpd */ - } -} - /* Get a bit mask of pins that have triggered, and which ones may be long. */ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS]) @@ -1492,7 +1271,7 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, if (hpd[i] & hotplug_trigger) { *pin_mask |= BIT(i); - if (pch_port_hotplug_long_detect(get_port_from_pin(i), dig_hotplug_reg)) + if (pch_port_hotplug_long_detect(intel_hpd_pin_to_port(i), dig_hotplug_reg)) *long_mask |= BIT(i); } } @@ -1518,7 +1297,7 @@ static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, if (hpd[i] & hotplug_trigger) { *pin_mask |= BIT(i); - if (i9xx_port_hotplug_long_detect(get_port_from_pin(i), hotplug_trigger)) + if (i9xx_port_hotplug_long_detect(intel_hpd_pin_to_port(i), hotplug_trigger)) *long_mask |= BIT(i); } } @@ -1527,104 +1306,6 @@ static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, hotplug_trigger, *pin_mask); } -/** - * intel_hpd_irq_handler - main hotplug irq handler - * @dev: drm device - * @pin_mask: a mask of hpd pins that have triggered the irq - * @long_mask: a mask of hpd pins that may be long hpd pulses - * - * This is the main hotplug irq handler for all platforms. The platform specific - * irq handlers call the platform specific hotplug irq handlers, which read and - * decode the appropriate registers into bitmasks about hpd pins that have - * triggered (@pin_mask), and which of those pins may be long pulses - * (@long_mask). The @long_mask is ignored if the port corresponding to the pin - * is not a digital port. - * - * Here, we do hotplug irq storm detection and mitigation, and pass further - * processing to appropriate bottom halves. - */ -static void intel_hpd_irq_handler(struct drm_device *dev, - u32 pin_mask, u32 long_mask) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - enum port port; - bool storm_detected = false; - bool queue_dig = false, queue_hp = false; - bool is_dig_port; - - if (!pin_mask) - return; - - spin_lock(&dev_priv->irq_lock); - for_each_hpd_pin(i) { - if (!(BIT(i) & pin_mask)) - continue; - - port = get_port_from_pin(i); - is_dig_port = port && dev_priv->hotplug.irq_port[port]; - - if (is_dig_port) { - bool long_hpd = long_mask & BIT(i); - - DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), - long_hpd ? "long" : "short"); - /* - * For long HPD pulses we want to have the digital queue happen, - * but we still want HPD storm detection to function. - */ - queue_dig = true; - if (long_hpd) { - dev_priv->hotplug.long_port_mask |= (1 << port); - } else { - /* for short HPD just trigger the digital queue */ - dev_priv->hotplug.short_port_mask |= (1 << port); - continue; - } - } - - if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { - /* - * On GMCH platforms the interrupt mask bits only - * prevent irq generation, not the setting of the - * hotplug bits itself. So only WARN about unexpected - * interrupts on saner platforms. - */ - WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), - "Received HPD interrupt on pin %d although disabled\n", i); - continue; - } - - if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) - continue; - - if (!is_dig_port) { - dev_priv->hotplug.event_bits |= BIT(i); - queue_hp = true; - } - - if (intel_hpd_irq_storm_detect(dev_priv, i)) { - dev_priv->hotplug.event_bits &= ~BIT(i); - storm_detected = true; - } - } - - if (storm_detected) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock(&dev_priv->irq_lock); - - /* - * Our hotplug handler can grab modeset locks (by calling down into the - * fb helpers). Hence it must not be run on our own dev-priv->wq work - * queue for otherwise the flush_work in the pageflip code will - * deadlock. - */ - if (queue_dig) - queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); - if (queue_hp) - schedule_work(&dev_priv->hotplug.hotplug_work); -} - static void gmbus_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -4367,46 +4048,6 @@ static void i965_irq_uninstall(struct drm_device * dev) I915_WRITE(IIR, I915_READ(IIR)); } -static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) -{ - struct drm_i915_private *dev_priv = - container_of(work, typeof(*dev_priv), - hotplug.reenable_work.work); - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - int i; - - intel_runtime_pm_get(dev_priv); - - spin_lock_irq(&dev_priv->irq_lock); - for_each_hpd_pin(i) { - struct drm_connector *connector; - - if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) - continue; - - dev_priv->hotplug.stats[i].state = HPD_ENABLED; - - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct intel_connector *intel_connector = to_intel_connector(connector); - - if (intel_connector->encoder->hpd_pin == i) { - if (connector->polled != intel_connector->polled) - DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", - connector->name); - connector->polled = intel_connector->polled; - if (!connector->polled) - connector->polled = DRM_CONNECTOR_POLL_HPD; - } - } - } - if (dev_priv->display.hpd_irq_setup) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock_irq(&dev_priv->irq_lock); - - intel_runtime_pm_put(dev_priv); -} - /** * intel_irq_init - initializes irq support * @dev_priv: i915 device instance @@ -4418,8 +4059,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv) { struct drm_device *dev = dev_priv->dev; - INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); - INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); + intel_hpd_init_work(dev_priv); + INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work); INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work); @@ -4432,8 +4073,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work, i915_hangcheck_elapsed); - INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, - intel_hpd_irq_storm_reenable_work); pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE); @@ -4518,46 +4157,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv) } } -/** - * intel_hpd_init - initializes and enables hpd support - * @dev_priv: i915 device instance - * - * This function enables the hotplug support. It requires that interrupts have - * already been enabled with intel_irq_init_hw(). From this point on hotplug and - * poll request can run concurrently to other code, so locking rules must be - * obeyed. - * - * This is a separate step from interrupt enabling to simplify the locking rules - * in the driver load and resume code. - */ -void intel_hpd_init(struct drm_i915_private *dev_priv) -{ - struct drm_device *dev = dev_priv->dev; - struct drm_mode_config *mode_config = &dev->mode_config; - struct drm_connector *connector; - int i; - - for_each_hpd_pin(i) { - dev_priv->hotplug.stats[i].count = 0; - dev_priv->hotplug.stats[i].state = HPD_ENABLED; - } - list_for_each_entry(connector, &mode_config->connector_list, head) { - struct intel_connector *intel_connector = to_intel_connector(connector); - connector->polled = intel_connector->polled; - if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) - connector->polled = DRM_CONNECTOR_POLL_HPD; - if (intel_connector->mst_port) - connector->polled = DRM_CONNECTOR_POLL_HPD; - } - - /* Interrupt setup is already guaranteed to be single-threaded, this is - * just to make the assert_spin_locked checks happy. */ - spin_lock_irq(&dev_priv->irq_lock); - if (dev_priv->display.hpd_irq_setup) - dev_priv->display.hpd_irq_setup(dev); - spin_unlock_irq(&dev_priv->irq_lock); -} - /** * intel_irq_install - enables the hardware interrupt * @dev_priv: i915 device instance diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c new file mode 100644 index 0000000000000..3c53aac71d983 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -0,0 +1,452 @@ +/* + * Copyright © 2015 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. + */ + +#include + +#include +#include + +#include "i915_drv.h" +#include "intel_drv.h" + +enum port intel_hpd_pin_to_port(enum hpd_pin pin) +{ + switch (pin) { + case HPD_PORT_B: + return PORT_B; + case HPD_PORT_C: + return PORT_C; + case HPD_PORT_D: + return PORT_D; + default: + return PORT_A; /* no hpd */ + } +} + +#define HPD_STORM_DETECT_PERIOD 1000 +#define HPD_STORM_THRESHOLD 5 +#define HPD_STORM_REENABLE_DELAY (2 * 60 * 1000) + +/** + * intel_hpd_irq_storm_detect - gather stats and detect HPD irq storm on a pin + * @dev_priv: private driver data pointer + * @pin: the pin to gather stats on + * + * Gather stats about HPD irqs from the specified @pin, and detect irq + * storms. Only the pin specific stats and state are changed, the caller is + * responsible for further action. + * + * @HPD_STORM_THRESHOLD irqs are allowed within @HPD_STORM_DETECT_PERIOD ms, + * otherwise it's considered an irq storm, and the irq state is set to + * @HPD_MARK_DISABLED. + * + * Return true if an irq storm was detected on @pin. + */ +static bool intel_hpd_irq_storm_detect(struct drm_i915_private *dev_priv, + enum hpd_pin pin) +{ + unsigned long start = dev_priv->hotplug.stats[pin].last_jiffies; + unsigned long end = start + msecs_to_jiffies(HPD_STORM_DETECT_PERIOD); + bool storm = false; + + if (!time_in_range(jiffies, start, end)) { + dev_priv->hotplug.stats[pin].last_jiffies = jiffies; + dev_priv->hotplug.stats[pin].count = 0; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: 0\n", pin); + } else if (dev_priv->hotplug.stats[pin].count > HPD_STORM_THRESHOLD) { + dev_priv->hotplug.stats[pin].state = HPD_MARK_DISABLED; + DRM_DEBUG_KMS("HPD interrupt storm detected on PIN %d\n", pin); + storm = true; + } else { + dev_priv->hotplug.stats[pin].count++; + DRM_DEBUG_KMS("Received HPD interrupt on PIN %d - cnt: %d\n", pin, + dev_priv->hotplug.stats[pin].count); + } + + return storm; +} + +static void intel_hpd_irq_storm_disable(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + enum hpd_pin pin; + bool hpd_disabled = false; + + assert_spin_locked(&dev_priv->irq_lock); + + list_for_each_entry(connector, &mode_config->connector_list, head) { + if (connector->polled != DRM_CONNECTOR_POLL_HPD) + continue; + + intel_connector = to_intel_connector(connector); + intel_encoder = intel_connector->encoder; + if (!intel_encoder) + continue; + + pin = intel_encoder->hpd_pin; + if (pin == HPD_NONE || + dev_priv->hotplug.stats[pin].state != HPD_MARK_DISABLED) + continue; + + DRM_INFO("HPD interrupt storm detected on connector %s: " + "switching from hotplug detection to polling\n", + connector->name); + + dev_priv->hotplug.stats[pin].state = HPD_DISABLED; + connector->polled = DRM_CONNECTOR_POLL_CONNECT + | DRM_CONNECTOR_POLL_DISCONNECT; + hpd_disabled = true; + } + + /* Enable polling and queue hotplug re-enabling. */ + if (hpd_disabled) { + drm_kms_helper_poll_enable(dev); + mod_delayed_work(system_wq, &dev_priv->hotplug.reenable_work, + msecs_to_jiffies(HPD_STORM_REENABLE_DELAY)); + } +} + +static void intel_hpd_irq_storm_reenable_work(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, typeof(*dev_priv), + hotplug.reenable_work.work); + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + int i; + + intel_runtime_pm_get(dev_priv); + + spin_lock_irq(&dev_priv->irq_lock); + for_each_hpd_pin(i) { + struct drm_connector *connector; + + if (dev_priv->hotplug.stats[i].state != HPD_DISABLED) + continue; + + dev_priv->hotplug.stats[i].state = HPD_ENABLED; + + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + + if (intel_connector->encoder->hpd_pin == i) { + if (connector->polled != intel_connector->polled) + DRM_DEBUG_DRIVER("Reenabling HPD on connector %s\n", + connector->name); + connector->polled = intel_connector->polled; + if (!connector->polled) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + } + } + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irq(&dev_priv->irq_lock); + + intel_runtime_pm_put(dev_priv); +} + +static bool intel_hpd_irq_event(struct drm_device *dev, + struct drm_connector *connector) +{ + enum drm_connector_status old_status; + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + old_status = connector->status; + + connector->status = connector->funcs->detect(connector, false); + if (old_status == connector->status) + return false; + + DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n", + connector->base.id, + connector->name, + drm_get_connector_status_name(old_status), + drm_get_connector_status_name(connector->status)); + + return true; +} + +static void i915_digport_work_func(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, hotplug.dig_port_work); + u32 long_port_mask, short_port_mask; + struct intel_digital_port *intel_dig_port; + int i; + u32 old_bits = 0; + + spin_lock_irq(&dev_priv->irq_lock); + long_port_mask = dev_priv->hotplug.long_port_mask; + dev_priv->hotplug.long_port_mask = 0; + short_port_mask = dev_priv->hotplug.short_port_mask; + dev_priv->hotplug.short_port_mask = 0; + spin_unlock_irq(&dev_priv->irq_lock); + + for (i = 0; i < I915_MAX_PORTS; i++) { + bool valid = false; + bool long_hpd = false; + intel_dig_port = dev_priv->hotplug.irq_port[i]; + if (!intel_dig_port || !intel_dig_port->hpd_pulse) + continue; + + if (long_port_mask & (1 << i)) { + valid = true; + long_hpd = true; + } else if (short_port_mask & (1 << i)) + valid = true; + + if (valid) { + enum irqreturn ret; + + ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd); + if (ret == IRQ_NONE) { + /* fall back to old school hpd */ + old_bits |= (1 << intel_dig_port->base.hpd_pin); + } + } + } + + if (old_bits) { + spin_lock_irq(&dev_priv->irq_lock); + dev_priv->hotplug.event_bits |= old_bits; + spin_unlock_irq(&dev_priv->irq_lock); + schedule_work(&dev_priv->hotplug.hotplug_work); + } +} + +/* + * Handle hotplug events outside the interrupt handler proper. + */ +static void i915_hotplug_work_func(struct work_struct *work) +{ + struct drm_i915_private *dev_priv = + container_of(work, struct drm_i915_private, hotplug.hotplug_work); + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct intel_connector *intel_connector; + struct intel_encoder *intel_encoder; + struct drm_connector *connector; + bool changed = false; + u32 hpd_event_bits; + + mutex_lock(&mode_config->mutex); + DRM_DEBUG_KMS("running encoder hotplug functions\n"); + + spin_lock_irq(&dev_priv->irq_lock); + + hpd_event_bits = dev_priv->hotplug.event_bits; + dev_priv->hotplug.event_bits = 0; + + /* Disable hotplug on connectors that hit an irq storm. */ + intel_hpd_irq_storm_disable(dev_priv); + + spin_unlock_irq(&dev_priv->irq_lock); + + list_for_each_entry(connector, &mode_config->connector_list, head) { + intel_connector = to_intel_connector(connector); + if (!intel_connector->encoder) + continue; + intel_encoder = intel_connector->encoder; + if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) { + DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n", + connector->name, intel_encoder->hpd_pin); + if (intel_encoder->hot_plug) + intel_encoder->hot_plug(intel_encoder); + if (intel_hpd_irq_event(dev, connector)) + changed = true; + } + } + mutex_unlock(&mode_config->mutex); + + if (changed) + drm_kms_helper_hotplug_event(dev); +} + + +/** + * intel_hpd_irq_handler - main hotplug irq handler + * @dev: drm device + * @pin_mask: a mask of hpd pins that have triggered the irq + * @long_mask: a mask of hpd pins that may be long hpd pulses + * + * This is the main hotplug irq handler for all platforms. The platform specific + * irq handlers call the platform specific hotplug irq handlers, which read and + * decode the appropriate registers into bitmasks about hpd pins that have + * triggered (@pin_mask), and which of those pins may be long pulses + * (@long_mask). The @long_mask is ignored if the port corresponding to the pin + * is not a digital port. + * + * Here, we do hotplug irq storm detection and mitigation, and pass further + * processing to appropriate bottom halves. + */ +void intel_hpd_irq_handler(struct drm_device *dev, + u32 pin_mask, u32 long_mask) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + enum port port; + bool storm_detected = false; + bool queue_dig = false, queue_hp = false; + bool is_dig_port; + + if (!pin_mask) + return; + + spin_lock(&dev_priv->irq_lock); + for_each_hpd_pin(i) { + if (!(BIT(i) & pin_mask)) + continue; + + port = intel_hpd_pin_to_port(i); + is_dig_port = port && dev_priv->hotplug.irq_port[port]; + + if (is_dig_port) { + bool long_hpd = long_mask & BIT(i); + + DRM_DEBUG_DRIVER("digital hpd port %c - %s\n", port_name(port), + long_hpd ? "long" : "short"); + /* + * For long HPD pulses we want to have the digital queue happen, + * but we still want HPD storm detection to function. + */ + queue_dig = true; + if (long_hpd) { + dev_priv->hotplug.long_port_mask |= (1 << port); + } else { + /* for short HPD just trigger the digital queue */ + dev_priv->hotplug.short_port_mask |= (1 << port); + continue; + } + } + + if (dev_priv->hotplug.stats[i].state == HPD_DISABLED) { + /* + * On GMCH platforms the interrupt mask bits only + * prevent irq generation, not the setting of the + * hotplug bits itself. So only WARN about unexpected + * interrupts on saner platforms. + */ + WARN_ONCE(INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev), + "Received HPD interrupt on pin %d although disabled\n", i); + continue; + } + + if (dev_priv->hotplug.stats[i].state != HPD_ENABLED) + continue; + + if (!is_dig_port) { + dev_priv->hotplug.event_bits |= BIT(i); + queue_hp = true; + } + + if (intel_hpd_irq_storm_detect(dev_priv, i)) { + dev_priv->hotplug.event_bits &= ~BIT(i); + storm_detected = true; + } + } + + if (storm_detected) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock(&dev_priv->irq_lock); + + /* + * Our hotplug handler can grab modeset locks (by calling down into the + * fb helpers). Hence it must not be run on our own dev-priv->wq work + * queue for otherwise the flush_work in the pageflip code will + * deadlock. + */ + if (queue_dig) + queue_work(dev_priv->hotplug.dp_wq, &dev_priv->hotplug.dig_port_work); + if (queue_hp) + schedule_work(&dev_priv->hotplug.hotplug_work); +} + +/** + * intel_hpd_init - initializes and enables hpd support + * @dev_priv: i915 device instance + * + * This function enables the hotplug support. It requires that interrupts have + * already been enabled with intel_irq_init_hw(). From this point on hotplug and + * poll request can run concurrently to other code, so locking rules must be + * obeyed. + * + * This is a separate step from interrupt enabling to simplify the locking rules + * in the driver load and resume code. + */ +void intel_hpd_init(struct drm_i915_private *dev_priv) +{ + struct drm_device *dev = dev_priv->dev; + struct drm_mode_config *mode_config = &dev->mode_config; + struct drm_connector *connector; + int i; + + for_each_hpd_pin(i) { + dev_priv->hotplug.stats[i].count = 0; + dev_priv->hotplug.stats[i].state = HPD_ENABLED; + } + list_for_each_entry(connector, &mode_config->connector_list, head) { + struct intel_connector *intel_connector = to_intel_connector(connector); + connector->polled = intel_connector->polled; + if (connector->encoder && !connector->polled && I915_HAS_HOTPLUG(dev) && intel_connector->encoder->hpd_pin > HPD_NONE) + connector->polled = DRM_CONNECTOR_POLL_HPD; + if (intel_connector->mst_port) + connector->polled = DRM_CONNECTOR_POLL_HPD; + } + + /* + * Interrupt setup is already guaranteed to be single-threaded, this is + * just to make the assert_spin_locked checks happy. + */ + spin_lock_irq(&dev_priv->irq_lock); + if (dev_priv->display.hpd_irq_setup) + dev_priv->display.hpd_irq_setup(dev); + spin_unlock_irq(&dev_priv->irq_lock); +} + +void intel_hpd_init_work(struct drm_i915_private *dev_priv) +{ + INIT_WORK(&dev_priv->hotplug.hotplug_work, i915_hotplug_work_func); + INIT_WORK(&dev_priv->hotplug.dig_port_work, i915_digport_work_func); + INIT_DELAYED_WORK(&dev_priv->hotplug.reenable_work, + intel_hpd_irq_storm_reenable_work); +} + +void intel_hpd_cancel_work(struct drm_i915_private *dev_priv) +{ + spin_lock_irq(&dev_priv->irq_lock); + + dev_priv->hotplug.long_port_mask = 0; + dev_priv->hotplug.short_port_mask = 0; + dev_priv->hotplug.event_bits = 0; + + spin_unlock_irq(&dev_priv->irq_lock); + + cancel_work_sync(&dev_priv->hotplug.dig_port_work); + cancel_work_sync(&dev_priv->hotplug.hotplug_work); + cancel_delayed_work_sync(&dev_priv->hotplug.reenable_work); +} -- GitLab From 8c841e57cadee2d0de7a1ea81c987088fb6a17fd Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 18 Jun 2015 13:06:17 +0300 Subject: [PATCH 0169/7006] drm/i915: reduce line width in {pch, i9xx}_get_hpd_pins() Make Paulo happier. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 2d3b2ccf9ce4c..a6fbe6443d63b 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1257,8 +1257,10 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) /* Get a bit mask of pins that have triggered, and which ones may be long. */ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, - u32 hotplug_trigger, u32 dig_hotplug_reg, const u32 hpd[HPD_NUM_PINS]) + u32 hotplug_trigger, u32 dig_hotplug_reg, + const u32 hpd[HPD_NUM_PINS]) { + enum port port; int i; *pin_mask = 0; @@ -1268,12 +1270,14 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, return; for_each_hpd_pin(i) { - if (hpd[i] & hotplug_trigger) { - *pin_mask |= BIT(i); + if ((hpd[i] & hotplug_trigger) == 0) + continue; - if (pch_port_hotplug_long_detect(intel_hpd_pin_to_port(i), dig_hotplug_reg)) - *long_mask |= BIT(i); - } + *pin_mask |= BIT(i); + + port = intel_hpd_pin_to_port(i); + if (pch_port_hotplug_long_detect(port, dig_hotplug_reg)) + *long_mask |= BIT(i); } DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, dig 0x%08x, pins 0x%08x\n", @@ -1285,6 +1289,7 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS]) { + enum port port; int i; *pin_mask = 0; @@ -1294,12 +1299,14 @@ static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, return; for_each_hpd_pin(i) { - if (hpd[i] & hotplug_trigger) { - *pin_mask |= BIT(i); + if ((hpd[i] & hotplug_trigger) == 0) + continue; - if (i9xx_port_hotplug_long_detect(intel_hpd_pin_to_port(i), hotplug_trigger)) - *long_mask |= BIT(i); - } + *pin_mask |= BIT(i); + + port = intel_hpd_pin_to_port(i); + if (i9xx_port_hotplug_long_detect(port, hotplug_trigger)) + *long_mask |= BIT(i); } DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n", -- GitLab From 3b1429d9458f5fc1abe57fb47b429290acb5d4d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 18 Jun 2015 13:47:22 +0300 Subject: [PATCH 0170/7006] drm/i915: Factor out p2 divider selection for pre-ilk platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The same dpll p2 divider selection is repeated three times in the gen2-4 .find_dpll() functions. Factor it out. Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 78 +++++++++++----------------- 1 file changed, 30 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 64c6c38ec8af2..df6f6adc7881d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -641,16 +641,12 @@ static bool intel_PLL_is_valid(struct drm_device *dev, return true; } -static bool -i9xx_find_best_dpll(const intel_limit_t *limit, - struct intel_crtc_state *crtc_state, - int target, int refclk, intel_clock_t *match_clock, - intel_clock_t *best_clock) +static int +i9xx_select_p2_div(const intel_limit_t *limit, + const struct intel_crtc_state *crtc_state, + int target) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_device *dev = crtc->base.dev; - intel_clock_t clock; - int err = target; + struct drm_device *dev = crtc_state->base.crtc->dev; if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) { /* @@ -659,18 +655,31 @@ i9xx_find_best_dpll(const intel_limit_t *limit, * single/dual channel state, if we even can. */ if (intel_is_dual_link_lvds(dev)) - clock.p2 = limit->p2.p2_fast; + return limit->p2.p2_fast; else - clock.p2 = limit->p2.p2_slow; + return limit->p2.p2_slow; } else { if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; + return limit->p2.p2_slow; else - clock.p2 = limit->p2.p2_fast; + return limit->p2.p2_fast; } +} + +static bool +i9xx_find_best_dpll(const intel_limit_t *limit, + struct intel_crtc_state *crtc_state, + int target, int refclk, intel_clock_t *match_clock, + intel_clock_t *best_clock) +{ + struct drm_device *dev = crtc_state->base.crtc->dev; + intel_clock_t clock; + int err = target; memset(best_clock, 0, sizeof(*best_clock)); + clock.p2 = i9xx_select_p2_div(limit, crtc_state, target); + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { for (clock.m2 = limit->m2.min; @@ -710,30 +719,14 @@ pnv_find_best_dpll(const intel_limit_t *limit, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_device *dev = crtc->base.dev; + struct drm_device *dev = crtc_state->base.crtc->dev; intel_clock_t clock; int err = target; - if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) { - /* - * For LVDS just rely on its current settings for dual-channel. - * We haven't figured out how to reliably set up different - * single/dual channel state, if we even can. - */ - if (intel_is_dual_link_lvds(dev)) - clock.p2 = limit->p2.p2_fast; - else - clock.p2 = limit->p2.p2_slow; - } else { - if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; - else - clock.p2 = limit->p2.p2_fast; - } - memset(best_clock, 0, sizeof(*best_clock)); + clock.p2 = i9xx_select_p2_div(limit, crtc_state, target); + for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max; clock.m1++) { for (clock.m2 = limit->m2.min; @@ -771,28 +764,17 @@ g4x_find_best_dpll(const intel_limit_t *limit, int target, int refclk, intel_clock_t *match_clock, intel_clock_t *best_clock) { - struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc); - struct drm_device *dev = crtc->base.dev; + struct drm_device *dev = crtc_state->base.crtc->dev; intel_clock_t clock; int max_n; - bool found; + bool found = false; /* approximately equals target * 0.00585 */ int err_most = (target >> 8) + (target >> 9); - found = false; - - if (intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS)) { - if (intel_is_dual_link_lvds(dev)) - clock.p2 = limit->p2.p2_fast; - else - clock.p2 = limit->p2.p2_slow; - } else { - if (target < limit->p2.dot_limit) - clock.p2 = limit->p2.p2_slow; - else - clock.p2 = limit->p2.p2_fast; - } memset(best_clock, 0, sizeof(*best_clock)); + + clock.p2 = i9xx_select_p2_div(limit, crtc_state, target); + max_n = limit->n.max; /* based on hardware requirement, prefer smaller n to precision */ for (clock.n = limit->n.min; clock.n <= max_n; clock.n++) { -- GitLab From 77a0d1cab489eb2b6ebd54234df4262f4840d498 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 18 Jun 2015 11:43:24 -0700 Subject: [PATCH 0171/7006] drm/i915: Remove unused ring argument from frontbuffer invalidate and busy functions. This patch doesn't have any functional change, but organize fruntbuffer invalidate and busy by removing unecesarry signature argument for ring. It was unsed on mark_fb_busy and only used on fb_obj_invalidate for the same ORIGIN_CS usage. So let's clean it a bit Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 10 +++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 - drivers/gpu/drm/i915/intel_fbdev.c | 4 ++-- drivers/gpu/drm/i915/intel_frontbuffer.c | 14 +++++--------- 5 files changed, 13 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index be35f0486202d..620e1b74cb03b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -350,7 +350,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, if (ret) return ret; - intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU); + intel_fb_obj_invalidate(obj, ORIGIN_CPU); if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { unsigned long unwritten; @@ -804,7 +804,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, offset = i915_gem_obj_ggtt_offset(obj) + args->offset; - intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(obj, ORIGIN_GTT); while (remain > 0) { /* Operation in this page @@ -948,7 +948,7 @@ i915_gem_shmem_pwrite(struct drm_device *dev, if (ret) return ret; - intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU); + intel_fb_obj_invalidate(obj, ORIGIN_CPU); i915_gem_object_pin_pages(obj); @@ -3942,7 +3942,7 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) } if (write) - intel_fb_obj_invalidate(obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(obj, ORIGIN_GTT); trace_i915_gem_object_change_domain(obj, old_read_domains, @@ -4215,7 +4215,7 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) } if (write) - intel_fb_obj_invalidate(obj, NULL, ORIGIN_CPU); + intel_fb_obj_invalidate(obj, ORIGIN_CPU); trace_i915_gem_object_change_domain(obj, old_read_domains, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3336e1c2c0a5e..edb8c458cbe15 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1038,7 +1038,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, obj->dirty = 1; i915_gem_request_assign(&obj->last_write_req, req); - intel_fb_obj_invalidate(obj, ring, ORIGIN_CS); + intel_fb_obj_invalidate(obj, ORIGIN_CS); /* update for the implicit flush after a batch */ obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 853bfd98ef725..e2174fd3030bc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -956,7 +956,6 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, /* intel_frontbuffer.c */ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, enum fb_op_origin origin); void intel_frontbuffer_flip_prepare(struct drm_device *dev, unsigned frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 6372cfc7d0532..838214666cc37 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -89,7 +89,7 @@ static int intel_fbdev_blank(int blank, struct fb_info *info) * now until we solve this for real. */ mutex_lock(&fb_helper->dev->struct_mutex); - intel_fb_obj_invalidate(ifbdev->fb->obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); } @@ -115,7 +115,7 @@ static int intel_fbdev_pan_display(struct fb_var_screeninfo *var, * now until we solve this for real. */ mutex_lock(&fb_helper->dev->struct_mutex); - intel_fb_obj_invalidate(ifbdev->fb->obj, NULL, ORIGIN_GTT); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 57095f54c1f2e..bdf0d57cad0fc 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -98,14 +98,12 @@ static void intel_increase_pllclock(struct drm_device *dev, * intel_mark_fb_busy - mark given planes as busy * @dev: DRM device * @frontbuffer_bits: bits for the affected planes - * @ring: optional ring for asynchronous commands * * This function gets called every time the screen contents change. It can be * used to keep e.g. the update rate at the nominal refresh rate with DRRS. */ static void intel_mark_fb_busy(struct drm_device *dev, - unsigned frontbuffer_bits, - struct intel_engine_cs *ring) + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; @@ -121,17 +119,15 @@ static void intel_mark_fb_busy(struct drm_device *dev, /** * intel_fb_obj_invalidate - invalidate frontbuffer object * @obj: GEM object to invalidate - * @ring: set for asynchronous rendering * @origin: which operation caused the invalidation * * This function gets called every time rendering on the given object starts and * frontbuffer caching (fbc, low refresh rate for DRRS, panel self refresh) must - * be invalidated. If @ring is non-NULL any subsequent invalidation will be delayed + * be invalidated. For ORIGIN_CS any subsequent invalidation will be delayed * until the rendering completes or a flip on this frontbuffer plane is * scheduled. */ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, enum fb_op_origin origin) { struct drm_device *dev = obj->base.dev; @@ -142,7 +138,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, if (!obj->frontbuffer_bits) return; - if (ring) { + if (origin == ORIGIN_CS) { mutex_lock(&dev_priv->fb_tracking.lock); dev_priv->fb_tracking.busy_bits |= obj->frontbuffer_bits; @@ -151,7 +147,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, mutex_unlock(&dev_priv->fb_tracking.lock); } - intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring); + intel_mark_fb_busy(dev, obj->frontbuffer_bits); intel_psr_invalidate(dev, obj->frontbuffer_bits); intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits); @@ -179,7 +175,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_mark_fb_busy(dev, frontbuffer_bits, NULL); + intel_mark_fb_busy(dev, frontbuffer_bits); intel_edp_drrs_flush(dev, frontbuffer_bits); intel_psr_flush(dev, frontbuffer_bits); -- GitLab From 55a9785d125a4dd33678795ccba0ed61a6e8540c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jun 2015 13:59:46 +0100 Subject: [PATCH 0172/7006] drm/i915: Enforce execobject.alignment to be a power-of-two Internal requirement for the alignment is that it must be a power-of-two, so enforce rejection at the user interface to execbuffer (which allows the caller to specify a stricter-than-expected alignment criterion). Signed-off-by: Chris Wilson Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index edb8c458cbe15..21f8eb6592516 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -957,6 +957,9 @@ validate_exec_list(struct drm_device *dev, if (exec[i].flags & invalid_flags) return -EINVAL; + if (exec[i].alignment && !is_power_of_2(exec[i].alignment)) + return -EINVAL; + /* First check for malicious input causing overflow in * the worst case where we need to allocate the entire * relocation tree as a single array. -- GitLab From eebaed646ab263cabcd19485e606e51c0bb11c5c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jun 2015 13:57:43 +0100 Subject: [PATCH 0173/7006] drm/i915: Ignore LVDS presence in VBT flag if the LVDS is enabled by BIOS On older gen, pre-Ironlake, parts there is no hardwired pin to report the presence of an LVDS panel. Instead, we have to rely on the VBT to declare whether the machine has a panel or not. Though notoriously unreliable, so far we have erred on the side of false-positives and have required a list of machines which end up falsely reporting a panel as present. However, we now have reports of false-negatives, machines with an LVDS that are being ignored due to the VBT not declaring the panel. This patch ignores the VBT setting if the BIOS has already enabled the LVDS panel (and on Ironlake+ we also have the hardware presence pin). It fixes the Samsung NP680Z5E-X01FR in the bug report, but is likely to result in more false-positives, and since we rely on the BIOS to enable the panel, there are likely different circumstances where the BIOS will not enable that panel (and so we may see the same machine with and without a panel all on the whim of the BIOS). Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90979 Reported-and-tested-by: lysxia@gmail.com Signed-off-by: Chris Wilson Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 161ab26f81fb8..bf1702a6e33d0 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -942,12 +942,6 @@ void intel_lvds_init(struct drm_device *dev) if (dmi_check_system(intel_no_lvds)) return; - pin = GMBUS_PIN_PANEL; - if (!lvds_is_present_in_vbt(dev, &pin)) { - DRM_DEBUG_KMS("LVDS is not present in VBT\n"); - return; - } - if (HAS_PCH_SPLIT(dev)) { if ((I915_READ(PCH_LVDS) & LVDS_DETECTED) == 0) return; @@ -957,6 +951,16 @@ void intel_lvds_init(struct drm_device *dev) } } + pin = GMBUS_PIN_PANEL; + if (!lvds_is_present_in_vbt(dev, &pin)) { + u32 reg = HAS_PCH_SPLIT(dev) ? PCH_LVDS : LVDS; + if ((I915_READ(reg) & LVDS_PORT_EN) == 0) { + DRM_DEBUG_KMS("LVDS is not present in VBT\n"); + return; + } + DRM_DEBUG_KMS("LVDS is not present in VBT, but enabled anyway\n"); + } + lvds_encoder = kzalloc(sizeof(*lvds_encoder), GFP_KERNEL); if (!lvds_encoder) return; -- GitLab From fd930478fb797e4cbaa799d9ddd970e9a1fa1b4a Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Fri, 19 Jun 2015 20:27:27 +0100 Subject: [PATCH 0174/7006] drm/i915: Remove KMS Kconfig option Since we only support modesetting by default (disabling modesetting on the command line prevents i915.ko from loading), having a parameter to disable modesstting by default is superfluous, i.e. saying CONFIG_DRM_I915_KMS=n is equivalent to CONFIG_DRM_I915=n. Signed-off-by: Chris Wilson Cc: Daniel Veter Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- arch/x86/configs/x86_64_defconfig | 1 - drivers/gpu/drm/i915/Kconfig | 9 --------- drivers/gpu/drm/i915/i915_drv.c | 20 +++++++------------- 3 files changed, 7 insertions(+), 23 deletions(-) diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig index 315b861065725..05630dfcb9f44 100644 --- a/arch/x86/configs/x86_64_defconfig +++ b/arch/x86/configs/x86_64_defconfig @@ -207,7 +207,6 @@ CONFIG_AGP_AMD64=y CONFIG_AGP_INTEL=y CONFIG_DRM=y CONFIG_DRM_I915=y -CONFIG_DRM_I915_KMS=y CONFIG_FB_MODE_HELPERS=y CONFIG_FB_TILEBLITTING=y CONFIG_FB_EFI=y diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 74acca9bcd9dc..eb87e25388615 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -36,15 +36,6 @@ config DRM_I915 i810 driver instead, and the Atom z5xx series has an entirely different implementation. -config DRM_I915_KMS - bool "Enable modesetting on intel by default" - depends on DRM_I915 - default y - help - Choose this option if you want kernel modesetting enabled by default. - - If in doubt, say "Y". - config DRM_I915_FBDEV bool "Enable legacy fbdev support for the modesetting intel driver" depends on DRM_I915 diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0ec57bad454fb..c69f19271e27d 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1710,20 +1710,14 @@ static int __init i915_init(void) driver.num_ioctls = i915_max_ioctl; /* - * If CONFIG_DRM_I915_KMS is set, default to KMS unless - * explicitly disabled with the module pararmeter. - * - * Otherwise, just follow the parameter (defaulting to off). - * - * Allow optional vga_text_mode_force boot option to override - * the default behavior. + * Enable KMS by default, unless explicitly overriden by + * either the i915.modeset prarameter or by the + * vga_text_mode_force boot option. */ -#if defined(CONFIG_DRM_I915_KMS) - if (i915.modeset != 0) - driver.driver_features |= DRIVER_MODESET; -#endif - if (i915.modeset == 1) - driver.driver_features |= DRIVER_MODESET; + driver.driver_features |= DRIVER_MODESET; + + if (i915.modeset == 0) + driver.driver_features &= ~DRIVER_MODESET; #ifdef CONFIG_VGA_CONSOLE if (vgacon_text_force() && i915.modeset == -1) -- GitLab From bf13af56252b2b4f50eb6fc8638e8cb9e84ff475 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Jun 2015 13:57:47 +0200 Subject: [PATCH 0175/7006] drm/i915: Fix up KMS Kconfig removal patch The module pciid list got lost, but somehow most distros seem to force-load drm drivers early and no one noticed for a while. Bug introduced in commit fd930478fb797e4cbaa799d9ddd970e9a1fa1b4a Author: Chris Wilson Date: Fri Jun 19 20:27:27 2015 +0100 drm/i915: Remove KMS Kconfig option Reported-by: Tvrtko Ursulin Cc: Tvrtko Ursulin Cc: Damien Lespiau Cc: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 -- drivers/gpu/drm/i915/i915_params.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index c69f19271e27d..b12a8218e35ea 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -440,9 +440,7 @@ static const struct pci_device_id pciidlist[] = { /* aka */ {0, 0, 0} }; -#if defined(CONFIG_DRM_I915_KMS) MODULE_DEVICE_TABLE(pci, pciidlist); -#endif void intel_detect_pch(struct drm_device *dev) { diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 8ac5a1b29ac07..3f67e69185c8c 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -58,7 +58,7 @@ struct i915_params i915 __read_mostly = { module_param_named(modeset, i915.modeset, int, 0400); MODULE_PARM_DESC(modeset, - "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, " + "Use kernel modesetting [KMS] (0=disable, " "1=on, -1=force vga console preference [default])"); module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600); -- GitLab From b1330fbb870467bbb90adb2e8868672af4ca88c7 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Jun 2015 11:42:08 +0100 Subject: [PATCH 0176/7006] drm/i915: Report an error when i915.reset prevents a reset If the user disables the GPU reset using the i915.reset parameter and one occurs, report that we failed to reset the GPU. If we return early, as we currently do, then we leave all state intact (with a hung GPU) and clients block forever waiting for their requests to complete. Testcase: igt/gem_eio Signed-off-by: Chris Wilson [danvet: Mark i915.reset as an unsafe modoption, as discussed with Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 - drivers/gpu/drm/i915/i915_drv.c | 3 --- drivers/gpu/drm/i915/i915_params.c | 2 +- drivers/gpu/drm/i915/intel_uncore.c | 3 +++ 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 88795d2f1819e..c5349fa3fccef 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -165,7 +165,6 @@ static int i915_getparam(struct drm_device *dev, void *data, break; case I915_PARAM_HAS_GPU_RESET: value = i915.enable_hangcheck && - i915.reset && intel_has_gpu_reset(dev); break; default: diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index b12a8218e35ea..e44dc0d6656fa 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -846,9 +846,6 @@ int i915_reset(struct drm_device *dev) bool simulated; int ret; - if (!i915.reset) - return 0; - intel_reset_gt_powersave(dev); mutex_lock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 3f67e69185c8c..18f65595d60ee 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -104,7 +104,7 @@ MODULE_PARM_DESC(vbt_sdvo_panel_type, "Override/Ignore selection of SDVO panel mode in the VBT " "(-2=ignore, -1=auto [default], index in VBT BIOS table)"); -module_param_named(reset, i915.reset, bool, 0600); +module_param_named_unsafe(reset, i915.reset, bool, 0600); MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)"); module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644); diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c index 160a47a9bdd97..45285a9178fe1 100644 --- a/drivers/gpu/drm/i915/intel_uncore.c +++ b/drivers/gpu/drm/i915/intel_uncore.c @@ -1496,6 +1496,9 @@ not_ready: static int (*intel_get_gpu_reset(struct drm_device *dev))(struct drm_device *) { + if (!i915.reset) + return NULL; + if (INTEL_INFO(dev)->gen >= 8) return gen8_do_reset; else if (INTEL_INFO(dev)->gen >= 6) -- GitLab From 17ee950df38b649d8431e2f6f7f85282d89f5398 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 19:07:01 +0100 Subject: [PATCH 0177/7006] drm/i915/gen8: Add infrastructure to initialize WA batch buffers Some of the WA are to be applied during context save but before restore and some at the end of context save/restore but before executing the instructions in the ring, WA batch buffers are created for this purpose and these WA cannot be applied using normal means. Each context has two registers to load the offsets of these batch buffers. If they are non-zero, HW understands that it need to execute these batches. v1: In this version two separate ring_buffer objects were used to load WA instructions for indirect and per context batch buffers and they were part of every context. v2: Chris suggested to include additional page in context and use it to load these WA instead of creating separate objects. This will simplify lot of things as we need not explicity pin/unpin them. Thomas Daniel further pointed that GuC is planning to use a similar setup to share data between GuC and driver and WA batch buffers can probably share that page. However after discussions with Dave who is implementing GuC changes, he suggested to use an independent page for the reasons - GuC area might grow and these WA are initialized only once and are not changed afterwards so we can share them share across all contexts. The page is updated with WA during render ring init. This has an advantage of not adding more special cases to default_context. We don't know upfront the number of WA we will applying using these batch buffers. For this reason the size was fixed earlier but it is not a good idea. To fix this, the functions that load instructions are modified to report the no of commands inserted and the size is now calculated after the batch is updated. A macro is introduced to add commands to these batch buffers which also checks for overflow and returns error. We have a full page dedicated for these WA so that should be sufficient for good number of WA, anything more means we have major issues. The list for Gen8 is small, same for Gen9 also, maybe few more gets added going forward but not close to filling entire page. Chris suggested a two-pass approach but we agreed to go with single page setup as it is a one-off routine and simpler code wins. One additional option is offset field which is helpful if we would like to have multiple batches at different offsets within the page and select them based on some criteria. This is not a requirement at this point but could help in future (Dave). Chris provided some helpful macros and suggestions which further simplified the code, they will also help in reducing code duplication when WA for other Gen are added. Add detailed comments explaining restrictions. Use do {} while(0) for wa_ctx_emit() macro. (Many thanks to Chris, Dave and Thomas for their reviews and inputs) Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 223 +++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 21 +++ 2 files changed, 240 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9f5485ddcbe6e..9b791a3d47dde 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -211,6 +211,7 @@ enum { FAULT_AND_CONTINUE /* Unsupported */ }; #define GEN8_CTX_ID_SHIFT 32 +#define CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 static int intel_lr_context_pin(struct intel_engine_cs *ring, struct intel_context *ctx); @@ -1077,6 +1078,191 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; } +#define wa_ctx_emit(batch, cmd) \ + do { \ + if (WARN_ON(index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ + return -ENOSPC; \ + } \ + batch[index++] = (cmd); \ + } while (0) + +static inline uint32_t wa_ctx_start(struct i915_wa_ctx_bb *wa_ctx, + uint32_t offset, + uint32_t start_alignment) +{ + return wa_ctx->offset = ALIGN(offset, start_alignment); +} + +static inline int wa_ctx_end(struct i915_wa_ctx_bb *wa_ctx, + uint32_t offset, + uint32_t size_alignment) +{ + wa_ctx->size = offset - wa_ctx->offset; + + WARN(wa_ctx->size % size_alignment, + "wa_ctx_bb failed sanity checks: size %d is not aligned to %d\n", + wa_ctx->size, size_alignment); + return 0; +} + +/** + * gen8_init_indirectctx_bb() - initialize indirect ctx batch with WA + * + * @ring: only applicable for RCS + * @wa_ctx: structure representing wa_ctx + * offset: specifies start of the batch, should be cache-aligned. This is updated + * with the offset value received as input. + * size: size of the batch in DWORDS but HW expects in terms of cachelines + * @batch: page in which WA are loaded + * @offset: This field specifies the start of the batch, it should be + * cache-aligned otherwise it is adjusted accordingly. + * Typically we only have one indirect_ctx and per_ctx batch buffer which are + * initialized at the beginning and shared across all contexts but this field + * helps us to have multiple batches at different offsets and select them based + * on a criteria. At the moment this batch always start at the beginning of the page + * and at this point we don't have multiple wa_ctx batch buffers. + * + * The number of WA applied are not known at the beginning; we use this field + * to return the no of DWORDS written. + + * It is to be noted that this batch does not contain MI_BATCH_BUFFER_END + * so it adds NOOPs as padding to make it cacheline aligned. + * MI_BATCH_BUFFER_END will be added to perctx batch and both of them together + * makes a complete batch buffer. + * + * Return: non-zero if we exceed the PAGE_SIZE limit. + */ + +static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + /* FIXME: Replace me with WA */ + wa_ctx_emit(batch, MI_NOOP); + + /* Pad to end of cacheline */ + while (index % CACHELINE_DWORDS) + wa_ctx_emit(batch, MI_NOOP); + + /* + * MI_BATCH_BUFFER_END is not required in Indirect ctx BB because + * execution depends on the length specified in terms of cache lines + * in the register CTX_RCS_INDIRECT_CTX + */ + + return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS); +} + +/** + * gen8_init_perctx_bb() - initialize per ctx batch with WA + * + * @ring: only applicable for RCS + * @wa_ctx: structure representing wa_ctx + * offset: specifies start of the batch, should be cache-aligned. + * size: size of the batch in DWORDS but HW expects in terms of cachelines + * @offset: This field specifies the start of this batch. + * This batch is started immediately after indirect_ctx batch. Since we ensure + * that indirect_ctx ends on a cacheline this batch is aligned automatically. + * + * The number of DWORDS written are returned using this field. + * + * This batch is terminated with MI_BATCH_BUFFER_END and so we need not add padding + * to align it with cacheline as padding after MI_BATCH_BUFFER_END is redundant. + */ +static int gen8_init_perctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + wa_ctx_emit(batch, MI_BATCH_BUFFER_END); + + return wa_ctx_end(wa_ctx, *offset = index, 1); +} + +static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *ring, u32 size) +{ + int ret; + + ring->wa_ctx.obj = i915_gem_alloc_object(ring->dev, PAGE_ALIGN(size)); + if (!ring->wa_ctx.obj) { + DRM_DEBUG_DRIVER("alloc LRC WA ctx backing obj failed.\n"); + return -ENOMEM; + } + + ret = i915_gem_obj_ggtt_pin(ring->wa_ctx.obj, PAGE_SIZE, 0); + if (ret) { + DRM_DEBUG_DRIVER("pin LRC WA ctx backing obj failed: %d\n", + ret); + drm_gem_object_unreference(&ring->wa_ctx.obj->base); + return ret; + } + + return 0; +} + +static void lrc_destroy_wa_ctx_obj(struct intel_engine_cs *ring) +{ + if (ring->wa_ctx.obj) { + i915_gem_object_ggtt_unpin(ring->wa_ctx.obj); + drm_gem_object_unreference(&ring->wa_ctx.obj->base); + ring->wa_ctx.obj = NULL; + } +} + +static int intel_init_workaround_bb(struct intel_engine_cs *ring) +{ + int ret; + uint32_t *batch; + uint32_t offset; + struct page *page; + struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx; + + WARN_ON(ring->id != RCS); + + ret = lrc_setup_wa_ctx_obj(ring, PAGE_SIZE); + if (ret) { + DRM_DEBUG_DRIVER("Failed to setup context WA page: %d\n", ret); + return ret; + } + + page = i915_gem_object_get_page(wa_ctx->obj, 0); + batch = kmap_atomic(page); + offset = 0; + + if (INTEL_INFO(ring->dev)->gen == 8) { + ret = gen8_init_indirectctx_bb(ring, + &wa_ctx->indirect_ctx, + batch, + &offset); + if (ret) + goto out; + + ret = gen8_init_perctx_bb(ring, + &wa_ctx->per_ctx, + batch, + &offset); + if (ret) + goto out; + } else { + WARN(INTEL_INFO(ring->dev)->gen >= 8, + "WA batch buffer is not initialized for Gen%d\n", + INTEL_INFO(ring->dev)->gen); + lrc_destroy_wa_ctx_obj(ring); + } + +out: + kunmap_atomic(batch); + if (ret) + lrc_destroy_wa_ctx_obj(ring); + + return ret; +} + static int gen8_init_common_ring(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; @@ -1411,6 +1597,8 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) kunmap(sg_page(ring->status_page.obj->pages->sgl)); ring->status_page.obj = NULL; } + + lrc_destroy_wa_ctx_obj(ring); } static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring) @@ -1474,7 +1662,22 @@ static int logical_render_ring_init(struct drm_device *dev) if (ret) return ret; - return intel_init_pipe_control(ring); + ret = intel_init_workaround_bb(ring); + if (ret) { + /* + * We continue even if we fail to initialize WA batch + * because we only expect rare glitches but nothing + * critical to prevent us from using GPU + */ + DRM_ERROR("WA batch buffer initialization failed: %d\n", + ret); + } + + ret = intel_init_pipe_control(ring); + if (ret) + lrc_destroy_wa_ctx_obj(ring); + + return ret; } static int logical_bsd_ring_init(struct drm_device *dev) @@ -1754,15 +1957,27 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118; reg_state[CTX_SECOND_BB_STATE+1] = 0; if (ring->id == RCS) { - /* TODO: according to BSpec, the register state context - * for CHV does not have these. OTOH, these registers do - * exist in CHV. I'm waiting for a clarification */ reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0; reg_state[CTX_BB_PER_CTX_PTR+1] = 0; reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4; reg_state[CTX_RCS_INDIRECT_CTX+1] = 0; reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8; reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0; + if (ring->wa_ctx.obj) { + struct i915_ctx_workarounds *wa_ctx = &ring->wa_ctx; + uint32_t ggtt_offset = i915_gem_obj_ggtt_offset(wa_ctx->obj); + + reg_state[CTX_RCS_INDIRECT_CTX+1] = + (ggtt_offset + wa_ctx->indirect_ctx.offset * sizeof(uint32_t)) | + (wa_ctx->indirect_ctx.size / CACHELINE_DWORDS); + + reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = + CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT << 6; + + reg_state[CTX_BB_PER_CTX_PTR+1] = + (ggtt_offset + wa_ctx->per_ctx.offset * sizeof(uint32_t)) | + 0x01; + } } reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9); reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index e539314ae87e0..64850293559c4 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -12,6 +12,7 @@ * workarounds! */ #define CACHELINE_BYTES 64 +#define CACHELINE_DWORDS (CACHELINE_BYTES / sizeof(uint32_t)) /* * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use" @@ -120,6 +121,25 @@ struct intel_ringbuffer { struct intel_context; struct drm_i915_reg_descriptor; +/* + * we use a single page to load ctx workarounds so all of these + * values are referred in terms of dwords + * + * struct i915_wa_ctx_bb: + * offset: specifies batch starting position, also helpful in case + * if we want to have multiple batches at different offsets based on + * some criteria. It is not a requirement at the moment but provides + * an option for future use. + * size: size of the batch in DWORDS + */ +struct i915_ctx_workarounds { + struct i915_wa_ctx_bb { + u32 offset; + u32 size; + } indirect_ctx, per_ctx; + struct drm_i915_gem_object *obj; +}; + struct intel_engine_cs { const char *name; enum intel_ring_id { @@ -143,6 +163,7 @@ struct intel_engine_cs { struct i915_gem_batch_pool batch_pool; struct intel_hw_status_page status_page; + struct i915_ctx_workarounds wa_ctx; unsigned irq_refcount; /* protected by dev_priv->irq_lock */ u32 irq_enable_mask; /* bitmask to enable ring interrupt */ -- GitLab From c4db7599194248214b343d1ef1a1bc53d6cff187 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 18:37:11 +0100 Subject: [PATCH 0178/7006] drm/i915/gen8: Re-order init pipe_control in lrc mode Some of the WA applied using WA batch buffers perform writes to scratch page. In the current flow WA are initialized before scratch obj is allocated. This patch reorders intel_init_pipe_control() to have a valid scratch obj before we initialize WA. v2: Check for valid scratch page before initializing WA as some of them perform writes to it. Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Michel Thierry Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9b791a3d47dde..f83d97ea40289 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1224,6 +1224,12 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); + /* some WA perform writes to scratch page, ensure it is valid */ + if (ring->scratch.obj == NULL) { + DRM_ERROR("scratch page not allocated for %s\n", ring->name); + return -EINVAL; + } + ret = lrc_setup_wa_ctx_obj(ring, PAGE_SIZE); if (ret) { DRM_DEBUG_DRIVER("Failed to setup context WA page: %d\n", ret); @@ -1658,7 +1664,8 @@ static int logical_render_ring_init(struct drm_device *dev) ring->emit_bb_start = gen8_emit_bb_start; ring->dev = dev; - ret = logical_ring_init(dev, ring); + + ret = intel_init_pipe_control(ring); if (ret) return ret; @@ -1673,9 +1680,10 @@ static int logical_render_ring_init(struct drm_device *dev) ret); } - ret = intel_init_pipe_control(ring); - if (ret) + ret = logical_ring_init(dev, ring); + if (ret) { lrc_destroy_wa_ctx_obj(ring); + } return ret; } -- GitLab From 7ad00d1ac12bf461d0f0b69bf4e0e883b9e23c53 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 18:37:12 +0100 Subject: [PATCH 0179/7006] drm/i915/gen8: Add WaDisableCtxRestoreArbitration workaround In Indirect and Per context w/a batch buffer, +WaDisableCtxRestoreArbitration Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f83d97ea40289..a1198baf34aad 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1140,8 +1140,8 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, { uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - /* FIXME: Replace me with WA */ - wa_ctx_emit(batch, MI_NOOP); + /* WaDisableCtxRestoreArbitration:bdw,chv */ + wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) @@ -1179,6 +1179,9 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *ring, { uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + /* WaDisableCtxRestoreArbitration:bdw,chv */ + wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_ENABLE); + wa_ctx_emit(batch, MI_BATCH_BUFFER_END); return wa_ctx_end(wa_ctx, *offset = index, 1); -- GitLab From c82435bbe5aca62fc54615ff8ba78134bfa33866 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 19 Jun 2015 18:37:13 +0100 Subject: [PATCH 0180/7006] drm/i915/gen8: Add WaFlushCoherentL3CacheLinesAtContextSwitch workaround In Indirect context w/a batch buffer, +WaFlushCoherentL3CacheLinesAtContextSwitch:bdw v2: Add LRI commands to set/reset bit that invalidates coherent lines, update WA to include programming restrictions and exclude CHV as it is not required (Ville) v3: Avoid unnecessary read when it can be done by reading register once (Chris). Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_lrc.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 64caa470f2c6c..b8e2259fe9ee5 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -431,6 +431,7 @@ #define PIPE_CONTROL_INDIRECT_STATE_DISABLE (1<<9) #define PIPE_CONTROL_NOTIFY (1<<8) #define PIPE_CONTROL_FLUSH_ENABLE (1<<7) /* gen7+ */ +#define PIPE_CONTROL_DC_FLUSH_ENABLE (1<<5) #define PIPE_CONTROL_VF_CACHE_INVALIDATE (1<<4) #define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1<<3) #define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1<<2) @@ -5811,6 +5812,7 @@ enum skl_disp_power_wells { #define GEN8_L3SQCREG4 0xb118 #define GEN8_LQSC_RO_PERF_DIS (1<<27) +#define GEN8_LQSC_FLUSH_COHERENT_LINES (1<<21) /* GEN8 chicken */ #define HDC_CHICKEN0 0x7300 diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a1198baf34aad..2b65d29c48018 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1143,6 +1143,29 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, /* WaDisableCtxRestoreArbitration:bdw,chv */ wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_DISABLE); + /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ + if (IS_BROADWELL(ring->dev)) { + struct drm_i915_private *dev_priv = to_i915(ring->dev); + uint32_t l3sqc4_flush = (I915_READ(GEN8_L3SQCREG4) | + GEN8_LQSC_FLUSH_COHERENT_LINES); + + wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, l3sqc4_flush); + + wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_DC_FLUSH_ENABLE)); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + + wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, l3sqc4_flush & ~GEN8_LQSC_FLUSH_COHERENT_LINES); + } + /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, MI_NOOP); -- GitLab From 29b1b415fcd95a2266ab58fc7825bccbffa5c142 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 18 Jun 2015 13:10:09 +0100 Subject: [PATCH 0181/7006] drm/i915: Reserve ring buffer space for i915_add_request() commands It is a bad idea for i915_add_request() to fail. The work will already have been send to the ring and will be processed, but there will not be any tracking or management of that work. The only way the add request call can fail is if it can't write its epilogue commands to the ring (cache flushing, seqno updates, interrupt signalling). The reasons for that are mostly down to running out of ring buffer space and the problems associated with trying to get some more. This patch prevents that situation from happening in the first place. When a request is created, it marks sufficient space as reserved for the epilogue commands. Thus guaranteeing that by the time the epilogue is written, there will be plenty of space for it. Note that a ring_begin() call is required to actually reserve the space (and do any potential waiting). However, that is not currently done at request creation time. This is because the ring_begin() code can allocate a request. Hence calling begin() from the request allocation code would lead to infinite recursion! Later patches in this series remove the need for begin() to do the allocate. At that point, it becomes safe for the allocate to call begin() and really reserve the space. Until then, there is a potential for insufficient space to be available at the point of calling i915_add_request(). However, that would only be in the case where the request was created and immediately submitted without ever calling ring_begin() and adding any work to that request. Which should never happen. And even if it does, and if that request happens to fall down the tiny window of opportunity for failing due to being out of ring space then does it really matter because the request wasn't doing anything in the first place? v2: Updated the 'reserved space too small' warning to include the offending sizes. Added a 'cancel' operation to clean up when a request is abandoned. Added re-initialisation of tracking state after a buffer wrap to keep the sanity checks accurate. v3: Incremented the reserved size to accommodate Ironlake (after finally managing to run on an ILK system). Also fixed missing wrap code in LRC mode. v4: Added extra comment and removed duplicate WARN (feedback from Tomas). For: VIZ-5115 CC: Tomas Elf Signed-off-by: John Harrison Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem.c | 37 +++++++++++++ drivers/gpu/drm/i915/intel_lrc.c | 21 ++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 71 ++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_ringbuffer.h | 25 +++++++++ 5 files changed, 153 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c3b9fcf301a07..6446911077d00 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2200,6 +2200,7 @@ struct drm_i915_gem_request { int i915_gem_request_alloc(struct intel_engine_cs *ring, struct intel_context *ctx); +void i915_gem_request_cancel(struct drm_i915_gem_request *req); void i915_gem_request_free(struct kref *req_ref); static inline uint32_t diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 80b509bed6e09..b9e0989063b45 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2485,6 +2485,13 @@ int __i915_add_request(struct intel_engine_cs *ring, } else ringbuf = ring->buffer; + /* + * To ensure that this call will not fail, space for its emissions + * should already have been reserved in the ring buffer. Let the ring + * know that it is time to use that space up. + */ + intel_ring_reserved_space_use(ringbuf); + request_start = intel_ring_get_tail(ringbuf); /* * Emit any outstanding flushes - execbuf can fail to emit the flush @@ -2567,6 +2574,9 @@ int __i915_add_request(struct intel_engine_cs *ring, round_jiffies_up_relative(HZ)); intel_mark_busy(dev_priv->dev); + /* Sanity check that the reserved size was large enough. */ + intel_ring_reserved_space_end(ringbuf); + return 0; } @@ -2665,6 +2675,26 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, if (ret) goto err; + /* + * Reserve space in the ring buffer for all the commands required to + * eventually emit this request. This is to guarantee that the + * i915_add_request() call can't fail. Note that the reserve may need + * to be redone if the request is not actually submitted straight + * away, e.g. because a GPU scheduler has deferred it. + * + * Note further that this call merely notes the reserve request. A + * subsequent call to *_ring_begin() is required to actually ensure + * that the reservation is available. Without the begin, if the + * request creator immediately submitted the request without adding + * any commands to it then there might not actually be sufficient + * room for the submission commands. Unfortunately, the current + * *_ring_begin() implementations potentially call back here to + * i915_gem_request_alloc(). Thus calling _begin() here would lead to + * infinite recursion! Until that back call path is removed, it is + * necessary to do a manual _begin() outside. + */ + intel_ring_reserved_space_reserve(req->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + ring->outstanding_lazy_request = req; return 0; @@ -2673,6 +2703,13 @@ err: return ret; } +void i915_gem_request_cancel(struct drm_i915_gem_request *req) +{ + intel_ring_reserved_space_cancel(req->ringbuf); + + i915_gem_request_unreference(req); +} + struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_engine_cs *ring) { diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2b65d29c48018..7451f38b2ef8b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -686,6 +686,9 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, unsigned space; int ret; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + if (intel_ring_space(ringbuf) >= bytes) return 0; @@ -746,6 +749,9 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, uint32_t __iomem *virt; int rem = ringbuf->size - ringbuf->tail; + /* Can't wrap if space has already been reserved! */ + WARN_ON(ringbuf->reserved_in_use); + if (ringbuf->space < rem) { int ret = logical_ring_wait_for_space(ringbuf, ctx, rem); @@ -769,10 +775,25 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, { int ret; + /* + * Add on the reserved size to the request to make sure that after + * the intended commands have been emitted, there is guaranteed to + * still be enough free space to send them to the hardware. + */ + if (!ringbuf->reserved_in_use) + bytes += ringbuf->reserved_size; + if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { ret = logical_ring_wrap_buffer(ringbuf, ctx); if (unlikely(ret)) return ret; + + if(ringbuf->reserved_size) { + uint32_t size = ringbuf->reserved_size; + + intel_ring_reserved_space_cancel(ringbuf); + intel_ring_reserved_space_reserve(ringbuf, size); + } } if (unlikely(ringbuf->space < bytes)) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b70d25bffb608..0c2bf0ed633d1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2113,6 +2113,9 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) unsigned space; int ret; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + if (intel_ring_space(ringbuf) >= n) return 0; @@ -2140,6 +2143,9 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) struct intel_ringbuffer *ringbuf = ring->buffer; int rem = ringbuf->size - ringbuf->tail; + /* Can't wrap if space has already been reserved! */ + WARN_ON(ringbuf->reserved_in_use); + if (ringbuf->space < rem) { int ret = ring_wait_for_space(ring, rem); if (ret) @@ -2190,16 +2196,77 @@ int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request) return 0; } -static int __intel_ring_prepare(struct intel_engine_cs *ring, - int bytes) +void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size) +{ + /* NB: Until request management is fully tidied up and the OLR is + * removed, there are too many ways for get false hits on this + * anti-recursion check! */ + /*WARN_ON(ringbuf->reserved_size);*/ + WARN_ON(ringbuf->reserved_in_use); + + ringbuf->reserved_size = size; + + /* + * Really need to call _begin() here but that currently leads to + * recursion problems! This will be fixed later but for now just + * return and hope for the best. Note that there is only a real + * problem if the create of the request never actually calls _begin() + * but if they are not submitting any work then why did they create + * the request in the first place? + */ +} + +void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf) +{ + WARN_ON(ringbuf->reserved_in_use); + + ringbuf->reserved_size = 0; + ringbuf->reserved_in_use = false; +} + +void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf) +{ + WARN_ON(ringbuf->reserved_in_use); + + ringbuf->reserved_in_use = true; + ringbuf->reserved_tail = ringbuf->tail; +} + +void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf) +{ + WARN_ON(!ringbuf->reserved_in_use); + WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size, + "request reserved size too small: %d vs %d!\n", + ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size); + + ringbuf->reserved_size = 0; + ringbuf->reserved_in_use = false; +} + +static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) { struct intel_ringbuffer *ringbuf = ring->buffer; int ret; + /* + * Add on the reserved size to the request to make sure that after + * the intended commands have been emitted, there is guaranteed to + * still be enough free space to send them to the hardware. + */ + if (!ringbuf->reserved_in_use) + bytes += ringbuf->reserved_size; + if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { ret = intel_wrap_ring_buffer(ring); if (unlikely(ret)) return ret; + + if(ringbuf->reserved_size) { + uint32_t size = ringbuf->reserved_size; + + intel_ring_reserved_space_cancel(ringbuf); + intel_ring_reserved_space_reserve(ringbuf, size); + } } if (unlikely(ringbuf->space < bytes)) { diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 64850293559c4..73db3ae8f237a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -106,6 +106,9 @@ struct intel_ringbuffer { int space; int size; int effective_size; + int reserved_size; + int reserved_tail; + bool reserved_in_use; /** We track the position of the requests in the ring buffer, and * when each is retired we increment last_retired_head as the GPU @@ -472,4 +475,26 @@ intel_ring_get_request(struct intel_engine_cs *ring) return ring->outstanding_lazy_request; } +/* + * Arbitrary size for largest possible 'add request' sequence. The code paths + * are complex and variable. Empirical measurement shows that the worst case + * is ILK at 136 words. Reserving too much is better than reserving too little + * as that allows for corner cases that might have been missed. So the figure + * has been rounded up to 160 words. + */ +#define MIN_SPACE_FOR_ADD_REQUEST 160 + +/* + * Reserve space in the ring to guarantee that the i915_add_request() call + * will always have sufficient room to do its stuff. The request creation + * code calls this automatically. + */ +void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size); +/* Cancel the reservation, e.g. because the request is being discarded. */ +void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf); +/* Use the reserved space - for use by i915_add_request() only. */ +void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf); +/* Finish with the reserved space - for use by i915_add_request() only. */ +void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf); + #endif /* _INTEL_RINGBUFFER_H_ */ -- GitLab From bf7dc5b70952eb58c4fd57c9b964488650303a32 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:24 +0100 Subject: [PATCH 0182/7006] drm/i915: i915_add_request must not fail The i915_add_request() function is called to keep track of work that has been written to the ring buffer. It adds epilogue commands to track progress (seqno updates and such), moves the request structure onto the right list and other such house keeping tasks. However, the work itself has already been written to the ring and will get executed whether or not the add request call succeeds. So no matter what goes wrong, there isn't a whole lot of point in failing the call. At the moment, this is fine(ish). If the add request does bail early on and not do the housekeeping, the request will still float around in the ring->outstanding_lazy_request field and be picked up next time. It means multiple pieces of work will be tagged as the same request and driver can't actually wait for the first piece of work until something else has been submitted. But it all sort of hangs together. This patch series is all about removing the OLR and guaranteeing that each piece of work gets its own personal request. That means that there is no more 'hoovering up of forgotten requests'. If the request does not get tracked then it will be leaked. Thus the add request call _must_ not fail. The previous patch should have already ensured that it _will_ not fail by removing the potential for running out of ring space. This patch enforces the rule by actually removing the early exit paths and the return code. Note that if something does manage to fail and the epilogue commands don't get written to the ring, the driver will still hang together. The request will be added to the tracking lists. And as in the old case, any subsequent work will generate a new seqno which will suffice for marking the old one as complete. v2: Improved WARNings (Tomas Elf review request). For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 6 +-- drivers/gpu/drm/i915/i915_gem.c | 43 +++++++++----------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 8 ++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 8 +--- 7 files changed, 31 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6446911077d00..b687e9f4dcf96 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2887,9 +2887,9 @@ void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); -int __i915_add_request(struct intel_engine_cs *ring, - struct drm_file *file, - struct drm_i915_gem_object *batch_obj); +void __i915_add_request(struct intel_engine_cs *ring, + struct drm_file *file, + struct drm_i915_gem_object *batch_obj); #define i915_add_request(ring) \ __i915_add_request(ring, NULL, NULL) int __i915_wait_request(struct drm_i915_gem_request *req, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b9e0989063b45..23ee54dbc9c5d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1155,15 +1155,12 @@ i915_gem_check_wedge(struct i915_gpu_error *error, int i915_gem_check_olr(struct drm_i915_gem_request *req) { - int ret; - WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); - ret = 0; if (req == req->ring->outstanding_lazy_request) - ret = i915_add_request(req->ring); + i915_add_request(req->ring); - return ret; + return 0; } static void fake_irq(unsigned long data) @@ -2466,9 +2463,14 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) return 0; } -int __i915_add_request(struct intel_engine_cs *ring, - struct drm_file *file, - struct drm_i915_gem_object *obj) +/* + * NB: This function is not allowed to fail. Doing so would mean the the + * request is not being tracked for completion but the work itself is + * going to happen on the hardware. This would be a Bad Thing(tm). + */ +void __i915_add_request(struct intel_engine_cs *ring, + struct drm_file *file, + struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; @@ -2478,7 +2480,7 @@ int __i915_add_request(struct intel_engine_cs *ring, request = ring->outstanding_lazy_request; if (WARN_ON(request == NULL)) - return -ENOMEM; + return; if (i915.enable_execlists) { ringbuf = request->ctx->engine[ring->id].ringbuf; @@ -2500,15 +2502,12 @@ int __i915_add_request(struct intel_engine_cs *ring, * is that the flush _must_ happen before the next request, no matter * what. */ - if (i915.enable_execlists) { + if (i915.enable_execlists) ret = logical_ring_flush_all_caches(ringbuf, request->ctx); - if (ret) - return ret; - } else { + else ret = intel_ring_flush_all_caches(ring); - if (ret) - return ret; - } + /* Not allowed to fail! */ + WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); /* Record the position of the start of the request so that * should we detect the updated seqno part-way through the @@ -2517,17 +2516,15 @@ int __i915_add_request(struct intel_engine_cs *ring, */ request->postfix = intel_ring_get_tail(ringbuf); - if (i915.enable_execlists) { + if (i915.enable_execlists) ret = ring->emit_request(ringbuf, request); - if (ret) - return ret; - } else { + else { ret = ring->add_request(ring); - if (ret) - return ret; request->tail = intel_ring_get_tail(ringbuf); } + /* Not allowed to fail! */ + WARN(ret, "emit|add_request failed: %d!\n", ret); request->head = request_start; @@ -2576,8 +2573,6 @@ int __i915_add_request(struct intel_engine_cs *ring, /* Sanity check that the reserved size was large enough. */ intel_ring_reserved_space_end(ringbuf); - - return 0; } static bool i915_context_is_banned(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 21f8eb6592516..8ebc10d0527df 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1069,7 +1069,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev, ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - (void)__i915_add_request(ring, file, obj); + __i915_add_request(ring, file, obj); } static int diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 521548a085782..ce4788ff3df56 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - ret = __i915_add_request(ring, NULL, so.obj); + __i915_add_request(ring, NULL, so.obj); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7451f38b2ef8b..5373b0d1068a5 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1601,7 +1601,7 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - ret = __i915_add_request(ring, file, so.obj); + __i915_add_request(ring, file, so.obj); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 25c8ec697da1f..e7534b9466957 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -220,9 +220,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, ring->outstanding_lazy_request); - ret = i915_add_request(ring); - if (ret) - return ret; + i915_add_request(ring); overlay->flip_tail = tail; ret = i915_wait_request(overlay->last_flip_req); @@ -291,7 +289,9 @@ static int intel_overlay_continue(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, ring->outstanding_lazy_request); - return i915_add_request(ring); + i915_add_request(ring); + + return 0; } static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 0c2bf0ed633d1..b48aea12acc4f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2166,14 +2166,10 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) int intel_ring_idle(struct intel_engine_cs *ring) { struct drm_i915_gem_request *req; - int ret; /* We need to add any requests required to flush the objects and ring */ - if (ring->outstanding_lazy_request) { - ret = i915_add_request(ring); - if (ret) - return ret; - } + if (ring->outstanding_lazy_request) + i915_add_request(ring); /* Wait upon the last request to be completed */ if (list_empty(&ring->request_list)) -- GitLab From 0c8dac889539ab26382ba1636ec1159cae73f2b3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:25 +0100 Subject: [PATCH 0183/7006] drm/i915: Early alloc request in execbuff Start of explicit request management in the execbuffer code path. This patch adds a call to allocate a request structure before all the actual hardware work is done. Thus guaranteeing that all that work is tagged by a known request. At present, nothing further is done with the request, the rest comes later in the series. The only noticable change is that failure to get a request (e.g. due to lack of memory) will be caught earlier in the sequence. It now occurs right at the start before any un-undoable work has been done. v2: Simplified the error handling path. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 8ebc10d0527df..2e41f7281c84f 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1611,10 +1611,16 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, } else exec_start += i915_gem_obj_offset(batch_obj, vm); + /* Allocate a request for this batch buffer nice and early. */ + ret = i915_gem_request_alloc(ring, ctx); + if (ret) + goto err_batch_unpin; + ret = dev_priv->gt.execbuf_submit(dev, file, ring, ctx, args, &eb->vmas, batch_obj, exec_start, dispatch_flags); +err_batch_unpin: /* * FIXME: We crucially rely upon the active tracking for the (ppgtt) * batch vma for correctness. For less ugly and less fragility this @@ -1623,6 +1629,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, */ if (dispatch_flags & I915_DISPATCH_SECURE) i915_gem_object_ggtt_unpin(batch_obj); + err: /* the request owns the ref now */ i915_gem_context_unreference(ctx); -- GitLab From 40e895ceca40b9c3104b2abd0ed5c72650fb20a4 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:26 +0100 Subject: [PATCH 0184/7006] drm/i915: Set context in request from creation even in legacy mode In execlist mode, the context object pointer is written in to the request structure (and reference counted) at the point of request creation. In legacy mode, this only happens inside i915_add_request(). This patch updates the legacy code path to match the execlist version. This allows all the intermediate code between request creation and request submission to get at the context object given only a request structure. Thus negating the need to pass context pointers here, there and everywhere. v2: Moved the context reference so it does not need to be undone if the get_seqno() fails. v3: Fixed execlist mode always hitting a warning about invalid last_contexts (which don't exist in execlist mode). v4: Updated for new i915_gem_request_alloc() scheme. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 22 +++++++++------------- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++------- drivers/gpu/drm/i915/intel_lrc.h | 3 +-- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 23ee54dbc9c5d..80705dee92d6c 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2536,14 +2536,7 @@ void __i915_add_request(struct intel_engine_cs *ring, */ request->batch_obj = obj; - if (!i915.enable_execlists) { - /* Hold a reference to the current context so that we can inspect - * it later in case a hangcheck error event fires. - */ - request->ctx = ring->last_context; - if (request->ctx) - i915_gem_context_reference(request->ctx); - } + WARN_ON(!i915.enable_execlists && (request->ctx != ring->last_context)); request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); @@ -2654,21 +2647,24 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, if (req == NULL) return -ENOMEM; - kref_init(&req->ref); - req->i915 = dev_priv; - ret = i915_gem_get_seqno(ring->dev, &req->seqno); if (ret) goto err; + kref_init(&req->ref); + req->i915 = dev_priv; req->ring = ring; + req->ctx = ctx; + i915_gem_context_reference(req->ctx); if (i915.enable_execlists) - ret = intel_logical_ring_alloc_request_extras(req, ctx); + ret = intel_logical_ring_alloc_request_extras(req); else ret = intel_ring_alloc_request_extras(req); - if (ret) + if (ret) { + i915_gem_context_unreference(req->ctx); goto err; + } /* * Reserve space in the ring buffer for all the commands required to diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5373b0d1068a5..6f3ec7197d896 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -659,20 +659,17 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, return logical_ring_invalidate_all_caches(ringbuf, ctx); } -int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request, - struct intel_context *ctx) +int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) { int ret; - if (ctx != request->ring->default_context) { - ret = intel_lr_context_pin(request->ring, ctx); + if (request->ctx != request->ring->default_context) { + ret = intel_lr_context_pin(request->ring, request->ctx); if (ret) return ret; } - request->ringbuf = ctx->engine[request->ring->id].ringbuf; - request->ctx = ctx; - i915_gem_context_reference(request->ctx); + request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; return 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 04d3a6d8b207e..4148de0169316 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -36,8 +36,7 @@ #define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) /* Logical Rings */ -int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request, - struct intel_context *ctx); +int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request); void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); -- GitLab From 5f19e2bffa63a91cd4ac1adcec648e14a44277ce Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:27 +0100 Subject: [PATCH 0185/7006] drm/i915: Merged the many do_execbuf() parameters into a structure The do_execbuf() function takes quite a few parameters. The actual set of parameters is going to change with the conversion to passing requests around. Further, it is due to grow massively with the arrival of the GPU scheduler. This patch simplifies the prototype by passing a parameter structure instead. Changing the parameter set in the future is then simply a matter of adding/removing items to the structure. Note that the structure does not contain absolutely everything that is passed in. This is because the intention is to use this structure more extensively later in this patch series and more especially in the GPU scheduler that is coming soon. The latter requires hanging on to the structure as the final hardware submission can be delayed until long after the execbuf IOCTL has returned to user land. Thus it is unsafe to put anything in the structure that is local to the IOCTL call itself - such as the 'args' parameter. All entries must be copies of data or pointers to structures that are reference counted in some way and guaranteed to exist for the duration of the batch buffer's life. v2: Rebased to newer tree and updated for changes to the command parser. Specifically, a code shuffle has required saving the batch start address in the params structure. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 28 +++++----- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 59 ++++++++++++++-------- drivers/gpu/drm/i915/intel_lrc.c | 26 +++++----- drivers/gpu/drm/i915/intel_lrc.h | 9 ++-- 4 files changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b687e9f4dcf96..e2d0ed05c1e54 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1648,6 +1648,17 @@ struct i915_virtual_gpu { bool active; }; +struct i915_execbuffer_params { + struct drm_device *dev; + struct drm_file *file; + uint32_t dispatch_flags; + uint32_t args_batch_start_offset; + uint32_t batch_obj_vm_offset; + struct intel_engine_cs *ring; + struct drm_i915_gem_object *batch_obj; + struct intel_context *ctx; +}; + struct drm_i915_private { struct drm_device *dev; struct kmem_cache *objects; @@ -1885,13 +1896,9 @@ struct drm_i915_private { /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */ struct { - int (*execbuf_submit)(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, + int (*execbuf_submit)(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 flags); + struct list_head *vmas); int (*init_rings)(struct drm_device *dev); void (*cleanup_ring)(struct intel_engine_cs *ring); void (*stop_ring)(struct intel_engine_cs *ring); @@ -2689,14 +2696,9 @@ void i915_gem_execbuffer_retire_commands(struct drm_device *dev, struct drm_file *file, struct intel_engine_cs *ring, struct drm_i915_gem_object *obj); -int i915_gem_ringbuffer_submission(struct drm_device *dev, - struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 flags); + struct list_head *vmas); int i915_gem_execbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv); int i915_gem_execbuffer2(struct drm_device *dev, void *data, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 2e41f7281c84f..c5f879e594c4c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1193,17 +1193,15 @@ err: } int -i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 dispatch_flags) + struct list_head *vmas) { struct drm_clip_rect *cliprects = NULL; + struct drm_device *dev = params->dev; + struct intel_engine_cs *ring = params->ring; struct drm_i915_private *dev_priv = dev->dev_private; - u64 exec_len; + u64 exec_start, exec_len; int instp_mode; u32 instp_mask; int i, ret = 0; @@ -1255,11 +1253,11 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, if (ret) goto error; - ret = i915_switch_context(ring, ctx); + ret = i915_switch_context(ring, params->ctx); if (ret) goto error; - WARN(ctx->ppgtt && ctx->ppgtt->pd_dirty_rings & (1<id), + WARN(params->ctx->ppgtt && params->ctx->ppgtt->pd_dirty_rings & (1<id), "%s didn't clear reload\n", ring->name); instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK; @@ -1320,7 +1318,10 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, goto error; } - exec_len = args->batch_len; + exec_len = args->batch_len; + exec_start = params->batch_obj_vm_offset + + params->args_batch_start_offset; + if (cliprects) { for (i = 0; i < args->num_cliprects; i++) { ret = i915_emit_box(ring, &cliprects[i], @@ -1330,22 +1331,23 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file, ret = ring->dispatch_execbuffer(ring, exec_start, exec_len, - dispatch_flags); + params->dispatch_flags); if (ret) goto error; } } else { ret = ring->dispatch_execbuffer(ring, exec_start, exec_len, - dispatch_flags); + params->dispatch_flags); if (ret) return ret; } - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags); + trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); + i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, + params->batch_obj); error: kfree(cliprects); @@ -1415,8 +1417,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct intel_engine_cs *ring; struct intel_context *ctx; struct i915_address_space *vm; + struct i915_execbuffer_params params_master; /* XXX: will be removed later */ + struct i915_execbuffer_params *params = ¶ms_master; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); - u64 exec_start = args->batch_start_offset; u32 dispatch_flags; int ret; bool need_relocs; @@ -1509,6 +1512,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, else vm = &dev_priv->gtt.base; + memset(¶ms_master, 0x00, sizeof(params_master)); + eb = eb_create(args); if (eb == NULL) { i915_gem_context_unreference(ctx); @@ -1551,6 +1556,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, goto err; } + params->args_batch_start_offset = args->batch_start_offset; if (i915_needs_cmd_parser(ring) && args->batch_len) { struct drm_i915_gem_object *parsed_batch_obj; @@ -1582,7 +1588,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, * command parser has accepted. */ dispatch_flags |= I915_DISPATCH_SECURE; - exec_start = 0; + params->args_batch_start_offset = 0; batch_obj = parsed_batch_obj; } } @@ -1607,18 +1613,29 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err; - exec_start += i915_gem_obj_ggtt_offset(batch_obj); + params->batch_obj_vm_offset = i915_gem_obj_ggtt_offset(batch_obj); } else - exec_start += i915_gem_obj_offset(batch_obj, vm); + params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm); /* Allocate a request for this batch buffer nice and early. */ ret = i915_gem_request_alloc(ring, ctx); if (ret) goto err_batch_unpin; - ret = dev_priv->gt.execbuf_submit(dev, file, ring, ctx, args, - &eb->vmas, batch_obj, exec_start, - dispatch_flags); + /* + * Save assorted stuff away to pass through to *_submission(). + * NB: This data should be 'persistent' and not local as it will + * kept around beyond the duration of the IOCTL once the GPU + * scheduler arrives. + */ + params->dev = dev; + params->file = file; + params->ring = ring; + params->dispatch_flags = dispatch_flags; + params->batch_obj = batch_obj; + params->ctx = ctx; + + ret = dev_priv->gt.execbuf_submit(params, args, &eb->vmas); err_batch_unpin: /* diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 6f3ec7197d896..eda3096a5b754 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -858,16 +858,15 @@ static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, * * Return: non-zero if the submission fails. */ -int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +int intel_execlists_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 dispatch_flags) + struct list_head *vmas) { + struct drm_device *dev = params->dev; + struct intel_engine_cs *ring = params->ring; struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_ringbuffer *ringbuf = params->ctx->engine[ring->id].ringbuf; + u64 exec_start; int instp_mode; u32 instp_mask; int ret; @@ -918,13 +917,13 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, return -EINVAL; } - ret = execlists_move_to_gpu(ringbuf, ctx, vmas); + ret = execlists_move_to_gpu(ringbuf, params->ctx, vmas); if (ret) return ret; if (ring == &dev_priv->ring[RCS] && instp_mode != dev_priv->relative_constants_mode) { - ret = intel_logical_ring_begin(ringbuf, ctx, 4); + ret = intel_logical_ring_begin(ringbuf, params->ctx, 4); if (ret) return ret; @@ -937,14 +936,17 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, dev_priv->relative_constants_mode = instp_mode; } - ret = ring->emit_bb_start(ringbuf, ctx, exec_start, dispatch_flags); + exec_start = params->batch_obj_vm_offset + + args->batch_start_offset; + + ret = ring->emit_bb_start(ringbuf, params->ctx, exec_start, params->dispatch_flags); if (ret) return ret; - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), dispatch_flags); + trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj); + i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, params->batch_obj); return 0; } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 4148de0169316..bf137c43e0a90 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -76,13 +76,10 @@ void intel_lr_context_reset(struct drm_device *dev, /* Execlists */ int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists); -int intel_execlists_submission(struct drm_device *dev, struct drm_file *file, - struct intel_engine_cs *ring, - struct intel_context *ctx, +struct i915_execbuffer_params; +int intel_execlists_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, - struct list_head *vmas, - struct drm_i915_gem_object *batch_obj, - u64 exec_start, u32 dispatch_flags); + struct list_head *vmas); u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj); void intel_lrc_irq_handler(struct intel_engine_cs *ring); -- GitLab From adeca76d8e2b34b5c739a36f4191aed63080da40 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:28 +0100 Subject: [PATCH 0186/7006] drm/i915: Simplify i915_gem_execbuffer_retire_commands() parameters Shrunk the parameter list of i915_gem_execbuffer_retire_commands() to a single structure as everything it requires is available in the execbuff_params object. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +---- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 ++++-------- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e2d0ed05c1e54..fdb185da2eef8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2692,10 +2692,7 @@ int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_execbuffer_move_to_active(struct list_head *vmas, struct intel_engine_cs *ring); -void i915_gem_execbuffer_retire_commands(struct drm_device *dev, - struct drm_file *file, - struct intel_engine_cs *ring, - struct drm_i915_gem_object *obj); +void i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params); int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, struct list_head *vmas); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index c5f879e594c4c..4bd10df1911ce 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1060,16 +1060,13 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, } void -i915_gem_execbuffer_retire_commands(struct drm_device *dev, - struct drm_file *file, - struct intel_engine_cs *ring, - struct drm_i915_gem_object *obj) +i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) { /* Unconditionally force add_request to emit a full flush. */ - ring->gpu_caches_dirty = true; + params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(ring, file, obj); + __i915_add_request(params->ring, params->file, params->batch_obj); } static int @@ -1346,8 +1343,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, - params->batch_obj); + i915_gem_execbuffer_retire_commands(params); error: kfree(cliprects); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index eda3096a5b754..54654d25608a6 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -946,7 +946,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); - i915_gem_execbuffer_retire_commands(params->dev, params->file, ring, params->batch_obj); + i915_gem_execbuffer_retire_commands(params); return 0; } -- GitLab From 217e46b576ef0d5eed10ddfeb2b29bd3de289e95 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:29 +0100 Subject: [PATCH 0187/7006] drm/i915: Update alloc_request to return the allocated request The alloc_request() function does not actually return the newly allocated request. Instead, it must be pulled from ring->outstanding_lazy_request. This patch fixes this so that code can create a request and start using it knowing exactly which request it actually owns. v2: Updated for new i915_gem_request_alloc() scheme. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_gem.c | 10 +++++++--- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 3 ++- drivers/gpu/drm/i915/intel_lrc.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- 5 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fdb185da2eef8..c439461db9af7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2206,7 +2206,8 @@ struct drm_i915_gem_request { }; int i915_gem_request_alloc(struct intel_engine_cs *ring, - struct intel_context *ctx); + struct intel_context *ctx, + struct drm_i915_gem_request **req_out); void i915_gem_request_cancel(struct drm_i915_gem_request *req); void i915_gem_request_free(struct kref *req_ref); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 80705dee92d6c..a0f51478581f0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2634,13 +2634,17 @@ void i915_gem_request_free(struct kref *req_ref) } int i915_gem_request_alloc(struct intel_engine_cs *ring, - struct intel_context *ctx) + struct intel_context *ctx, + struct drm_i915_gem_request **req_out) { struct drm_i915_private *dev_priv = to_i915(ring->dev); struct drm_i915_gem_request *req; int ret; - if (ring->outstanding_lazy_request) + if (!req_out) + return -EINVAL; + + if ((*req_out = ring->outstanding_lazy_request) != NULL) return 0; req = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL); @@ -2686,7 +2690,7 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, */ intel_ring_reserved_space_reserve(req->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); - ring->outstanding_lazy_request = req; + *req_out = ring->outstanding_lazy_request = req; return 0; err: diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 4bd10df1911ce..9c9e20ace5e33 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1415,6 +1415,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct i915_address_space *vm; struct i915_execbuffer_params params_master; /* XXX: will be removed later */ struct i915_execbuffer_params *params = ¶ms_master; + struct drm_i915_gem_request *request; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 dispatch_flags; int ret; @@ -1614,7 +1615,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm); /* Allocate a request for this batch buffer nice and early. */ - ret = i915_gem_request_alloc(ring, ctx); + ret = i915_gem_request_alloc(ring, ctx, &request); if (ret) goto err_batch_unpin; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 54654d25608a6..8af35889740b3 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -818,6 +818,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, struct intel_context *ctx, int num_dwords) { + struct drm_i915_gem_request *req; struct intel_engine_cs *ring = ringbuf->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -833,7 +834,7 @@ static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, return ret; /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ctx); + ret = i915_gem_request_alloc(ring, ctx, &req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index b48aea12acc4f..13eab17579728 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2277,6 +2277,7 @@ static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) int intel_ring_begin(struct intel_engine_cs *ring, int num_dwords) { + struct drm_i915_gem_request *req; struct drm_i915_private *dev_priv = ring->dev->dev_private; int ret; @@ -2290,7 +2291,7 @@ int intel_ring_begin(struct intel_engine_cs *ring, return ret; /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ring->default_context); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; -- GitLab From 6a6ae79a761ddc95b67254e256f82f6d7c9c44d3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:30 +0100 Subject: [PATCH 0188/7006] drm/i915: Add request to execbuf params and add explicit cleanup Rather than just having a local request variable in the execbuff code, the request pointer is now stored in the execbuff params structure. Also added explicit cleanup of the request (plus wiping the OLR to match) in the error case. This means that the execbuff code is no longer dependent upon the OLR keeping track of the request so as to not leak it when things do go wrong. Note that in the success case, the i915_add_request() at the end of the submission function will tidy up the request and clear the OLR. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_gem_execbuffer.c | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index c439461db9af7..4364a209c6a5f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1657,6 +1657,7 @@ struct i915_execbuffer_params { struct intel_engine_cs *ring; struct drm_i915_gem_object *batch_obj; struct intel_context *ctx; + struct drm_i915_gem_request *request; }; struct drm_i915_private { diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9c9e20ace5e33..9d53d787fcf6e 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1415,7 +1415,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, struct i915_address_space *vm; struct i915_execbuffer_params params_master; /* XXX: will be removed later */ struct i915_execbuffer_params *params = ¶ms_master; - struct drm_i915_gem_request *request; const u32 ctx_id = i915_execbuffer2_get_context_id(*args); u32 dispatch_flags; int ret; @@ -1615,7 +1614,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, params->batch_obj_vm_offset = i915_gem_obj_offset(batch_obj, vm); /* Allocate a request for this batch buffer nice and early. */ - ret = i915_gem_request_alloc(ring, ctx, &request); + ret = i915_gem_request_alloc(ring, ctx, ¶ms->request); if (ret) goto err_batch_unpin; @@ -1649,6 +1648,16 @@ err: i915_gem_context_unreference(ctx); eb_destroy(eb); + /* + * If the request was created but not successfully submitted then it + * must be freed again. If it was submitted then it is being tracked + * on the active request list and no clean up is required here. + */ + if (ret && params->request) { + i915_gem_request_cancel(params->request); + ring->outstanding_lazy_request = NULL; + } + mutex_unlock(&dev->struct_mutex); pre_mutex_err: -- GitLab From 95c24161cd8561bd2f866a802a44b28fd0a867b7 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:31 +0100 Subject: [PATCH 0189/7006] drm/i915: Update the dispatch tracepoint to use params->request Updated a couple of trace points to use the now cached request pointer rather than extracting it from the ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9d53d787fcf6e..610c3307a02a2 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1340,7 +1340,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, return ret; } - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); + trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_retire_commands(params); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8af35889740b3..d94c015473044 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -944,7 +944,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, if (ret) return ret; - trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), params->dispatch_flags); + trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); i915_gem_execbuffer_move_to_active(vmas, ring); i915_gem_execbuffer_retire_commands(params); -- GitLab From 535fbe8233d164e76bac515dd7efee699093cea9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:32 +0100 Subject: [PATCH 0190/7006] drm/i915: Update move_to_gpu() to take a request structure The plan is to pass requests around as the basic submission tracking structure rather than rings and contexts. This patch updates the move_to_gpu() code paths. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 ++++++------ drivers/gpu/drm/i915/intel_lrc.c | 12 +++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 610c3307a02a2..f6ce811a024a1 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -891,10 +891,10 @@ err: } static int -i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, +i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req, struct list_head *vmas) { - const unsigned other_rings = ~intel_ring_flag(ring); + const unsigned other_rings = ~intel_ring_flag(req->ring); struct i915_vma *vma; uint32_t flush_domains = 0; bool flush_chipset = false; @@ -904,7 +904,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, ring); + ret = i915_gem_object_sync(obj, req->ring); if (ret) return ret; } @@ -916,7 +916,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, } if (flush_chipset) - i915_gem_chipset_flush(ring->dev); + i915_gem_chipset_flush(req->ring->dev); if (flush_domains & I915_GEM_DOMAIN_GTT) wmb(); @@ -924,7 +924,7 @@ i915_gem_execbuffer_move_to_gpu(struct intel_engine_cs *ring, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return intel_ring_invalidate_all_caches(ring); + return intel_ring_invalidate_all_caches(req->ring); } static bool @@ -1246,7 +1246,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, } } - ret = i915_gem_execbuffer_move_to_gpu(ring, vmas); + ret = i915_gem_execbuffer_move_to_gpu(params->request, vmas); if (ret) goto error; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d94c015473044..aa12a595a309e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -624,12 +624,10 @@ static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf, return 0; } -static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int execlists_move_to_gpu(struct drm_i915_gem_request *req, struct list_head *vmas) { - struct intel_engine_cs *ring = ringbuf->ring; - const unsigned other_rings = ~intel_ring_flag(ring); + const unsigned other_rings = ~intel_ring_flag(req->ring); struct i915_vma *vma; uint32_t flush_domains = 0; bool flush_chipset = false; @@ -639,7 +637,7 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, ring); + ret = i915_gem_object_sync(obj, req->ring); if (ret) return ret; } @@ -656,7 +654,7 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return logical_ring_invalidate_all_caches(ringbuf, ctx); + return logical_ring_invalidate_all_caches(req->ringbuf, req->ctx); } int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) @@ -918,7 +916,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, return -EINVAL; } - ret = execlists_move_to_gpu(ringbuf, params->ctx, vmas); + ret = execlists_move_to_gpu(params->request, vmas); if (ret) return ret; -- GitLab From 8a8edb59172983a7c4aa46ab35b5a23a49c729c5 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:33 +0100 Subject: [PATCH 0191/7006] drm/i915: Update execbuffer_move_to_active() to take a request structure The plan is to pass requests around as the basic submission tracking structure rather than rings and contexts. This patch updates the execbuffer_move_to_active() code path. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 +++--- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4364a209c6a5f..14154c4607623 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2693,7 +2693,7 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); void i915_gem_execbuffer_move_to_active(struct list_head *vmas, - struct intel_engine_cs *ring); + struct drm_i915_gem_request *req); void i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params); int i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, struct drm_i915_gem_execbuffer2 *args, diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index f6ce811a024a1..76bfc68d1a881 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1020,9 +1020,9 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file, void i915_gem_execbuffer_move_to_active(struct list_head *vmas, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { - struct drm_i915_gem_request *req = intel_ring_get_request(ring); + struct intel_engine_cs *ring = i915_gem_request_get_ring(req); struct i915_vma *vma; list_for_each_entry(vma, vmas, exec_list) { @@ -1342,7 +1342,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); - i915_gem_execbuffer_move_to_active(vmas, ring); + i915_gem_execbuffer_move_to_active(vmas, params->request); i915_gem_execbuffer_retire_commands(params); error: diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index aa12a595a309e..754aa39eb12b6 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -944,7 +944,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, trace_i915_gem_ring_dispatch(params->request, params->dispatch_flags); - i915_gem_execbuffer_move_to_active(vmas, ring); + i915_gem_execbuffer_move_to_active(vmas, params->request); i915_gem_execbuffer_retire_commands(params); return 0; -- GitLab From 5b4a60c2768434a8c6d5f803a2410245334b8bf7 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:34 +0100 Subject: [PATCH 0192/7006] drm/i915: Add flag to i915_add_request() to skip the cache flush In order to explcitly track all GPU work (and completely remove the outstanding lazy request), it is necessary to add extra i915_add_request() calls to various places. Some of these do not need the implicit cache flush done as part of the standard batch buffer submission process. This patch adds a flag to _add_request() to specify whether the flush is required or not. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +++++-- drivers/gpu/drm/i915/i915_gem.c | 17 ++++++++++------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 14154c4607623..104893bea2f1f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2890,9 +2890,12 @@ int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct intel_engine_cs *ring, struct drm_file *file, - struct drm_i915_gem_object *batch_obj); + struct drm_i915_gem_object *batch_obj, + bool flush_caches); #define i915_add_request(ring) \ - __i915_add_request(ring, NULL, NULL) + __i915_add_request(ring, NULL, NULL, true) +#define i915_add_request_no_flush(ring) \ + __i915_add_request(ring, NULL, NULL, false) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a0f51478581f0..74c319350876f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2470,7 +2470,8 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) */ void __i915_add_request(struct intel_engine_cs *ring, struct drm_file *file, - struct drm_i915_gem_object *obj) + struct drm_i915_gem_object *obj, + bool flush_caches) { struct drm_i915_private *dev_priv = ring->dev->dev_private; struct drm_i915_gem_request *request; @@ -2502,12 +2503,14 @@ void __i915_add_request(struct intel_engine_cs *ring, * is that the flush _must_ happen before the next request, no matter * what. */ - if (i915.enable_execlists) - ret = logical_ring_flush_all_caches(ringbuf, request->ctx); - else - ret = intel_ring_flush_all_caches(ring); - /* Not allowed to fail! */ - WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); + if (flush_caches) { + if (i915.enable_execlists) + ret = logical_ring_flush_all_caches(ringbuf, request->ctx); + else + ret = intel_ring_flush_all_caches(ring); + /* Not allowed to fail! */ + WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); + } /* Record the position of the start of the request so that * should we detect the updated seqno part-way through the diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 76bfc68d1a881..a15517249bb99 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1066,7 +1066,7 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(params->ring, params->file, params->batch_obj); + __i915_add_request(params->ring, params->file, params->batch_obj, true); } static int diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index ce4788ff3df56..4418616301e75 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, NULL, so.obj); + __i915_add_request(ring, NULL, so.obj, true); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 754aa39eb12b6..47443b9aa1721 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1599,7 +1599,7 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, file, so.obj); + __i915_add_request(ring, file, so.obj, true); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: -- GitLab From 73cfa86512813807f39a51a21d14774a29714e15 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:35 +0100 Subject: [PATCH 0193/7006] drm/i915: Update i915_gpu_idle() to manage its own request Added explicit request creation and submission to the GPU idle code path. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 74c319350876f..1a3a65d022389 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3305,11 +3305,23 @@ int i915_gpu_idle(struct drm_device *dev) /* Flush everything onto the inactive list. */ for_each_ring(ring, dev_priv, i) { if (!i915.enable_execlists) { - ret = i915_switch_context(ring, ring->default_context); + struct drm_i915_gem_request *req; + + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + + ret = i915_switch_context(req->ring, ring->default_context); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + + i915_add_request_no_flush(req->ring); } + WARN_ON(ring->outstanding_lazy_request); + ret = intel_ring_idle(ring); if (ret) return ret; -- GitLab From 4ad2fd888bd3fa53e4bd36e5552bd784fb7ba241 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 18 Jun 2015 13:11:20 +0100 Subject: [PATCH 0194/7006] drm/i915: Split i915_ppgtt_init_hw() in half - generic and per ring The i915_gem_init_hw() function calls a bunch of smaller initialisation functions. Multiple of which have generic sections and per ring sections. This means multiple passes are done over the rings. Each pass writes data to the ring which floats around in that ring's OLR until some random point in the future when an add_request() is done by some random other piece of code. This patch breaks i915_ppgtt_init_hw() in two with the per ring initialisation now being done in i915_ppgtt_init_ring(). The ring looping is now done at the top level in i915_gem_init_hw(). v2: Fix dumb loop variable re-use. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 27 ++++++++++++++++++++------- drivers/gpu/drm/i915/i915_gem_gtt.c | 28 +++++++++++++++------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 1 + 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1a3a65d022389..9522e861a733d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5015,7 +5015,7 @@ i915_gem_init_hw(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring; - int ret, i; + int ret, i, j; if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt()) return -EIO; @@ -5052,19 +5052,32 @@ i915_gem_init_hw(struct drm_device *dev) */ init_unused_rings(dev); + ret = i915_ppgtt_init_hw(dev); + if (ret) { + DRM_ERROR("PPGTT enable HW failed %d\n", ret); + goto out; + } + + /* Need to do basic initialisation of all rings first: */ for_each_ring(ring, dev_priv, i) { ret = ring->init_hw(ring); if (ret) goto out; } - for (i = 0; i < NUM_L3_SLICES(dev); i++) - i915_gem_l3_remap(&dev_priv->ring[RCS], i); + /* Now it is safe to go back round and do everything else: */ + for_each_ring(ring, dev_priv, i) { + if (ring->id == RCS) { + for (j = 0; j < NUM_L3_SLICES(dev); j++) + i915_gem_l3_remap(ring, j); + } - ret = i915_ppgtt_init_hw(dev); - if (ret && ret != -EIO) { - DRM_ERROR("PPGTT enable failed %d\n", ret); - i915_gem_cleanup_ringbuffer(dev); + ret = i915_ppgtt_init_ring(ring); + if (ret && ret != -EIO) { + DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); + i915_gem_cleanup_ringbuffer(dev); + goto out; + } } ret = i915_gem_context_enable(dev_priv); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index d7ea81aa5cebf..f8ecea22748a9 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1550,11 +1550,6 @@ int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) int i915_ppgtt_init_hw(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring; - struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; - int i, ret = 0; - /* In the case of execlists, PPGTT is enabled by the context descriptor * and the PDPs are contained within the context itself. We don't * need to do anything here. */ @@ -1573,16 +1568,23 @@ int i915_ppgtt_init_hw(struct drm_device *dev) else MISSING_CASE(INTEL_INFO(dev)->gen); - if (ppgtt) { - for_each_ring(ring, dev_priv, i) { - ret = ppgtt->switch_mm(ppgtt, ring); - if (ret != 0) - return ret; - } - } + return 0; +} - return ret; +int i915_ppgtt_init_ring(struct intel_engine_cs *ring) +{ + struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; + + if (i915.enable_execlists) + return 0; + + if (!ppgtt) + return 0; + + return ppgtt->switch_mm(ppgtt, ring); } + struct i915_hw_ppgtt * i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 0d46dd20bf717..0caa9ebb615b0 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -475,6 +475,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev); int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); int i915_ppgtt_init_hw(struct drm_device *dev); +int i915_ppgtt_init_ring(struct intel_engine_cs *ring); void i915_ppgtt_release(struct kref *kref); struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv); -- GitLab From 90638cc1a4299acf19ed6fe253517a86d52a02ab Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:37 +0100 Subject: [PATCH 0195/7006] drm/i915: Moved the for_each_ring loop outside of i915_gem_context_enable() The start of day context initialisation code in i915_gem_context_enable() loops over each ring and calls the legacy switch context or the execlist init context code as appropriate. This patch moves the ring looping out of that function in to the top level caller i915_gem_init_hw(). This means the a single pass can be made over all rings doing the PPGTT, L3 remap and context initialisation of each ring altogether. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 17 +++++++------ drivers/gpu/drm/i915/i915_gem_context.c | 32 +++++++++---------------- 3 files changed, 22 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 104893bea2f1f..198e681639b71 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3039,7 +3039,7 @@ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); -int i915_gem_context_enable(struct drm_i915_private *dev_priv); +int i915_gem_context_enable(struct intel_engine_cs *ring); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_engine_cs *ring, struct intel_context *to); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 9522e861a733d..a580593f586e6 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5052,6 +5052,8 @@ i915_gem_init_hw(struct drm_device *dev) */ init_unused_rings(dev); + BUG_ON(!dev_priv->ring[RCS].default_context); + ret = i915_ppgtt_init_hw(dev); if (ret) { DRM_ERROR("PPGTT enable HW failed %d\n", ret); @@ -5067,6 +5069,8 @@ i915_gem_init_hw(struct drm_device *dev) /* Now it is safe to go back round and do everything else: */ for_each_ring(ring, dev_priv, i) { + WARN_ON(!ring->default_context); + if (ring->id == RCS) { for (j = 0; j < NUM_L3_SLICES(dev); j++) i915_gem_l3_remap(ring, j); @@ -5078,14 +5082,13 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); goto out; } - } - ret = i915_gem_context_enable(dev_priv); - if (ret && ret != -EIO) { - DRM_ERROR("Context enable failed %d\n", ret); - i915_gem_cleanup_ringbuffer(dev); - - goto out; + ret = i915_gem_context_enable(ring); + if (ret && ret != -EIO) { + DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); + i915_gem_cleanup_ringbuffer(dev); + goto out; + } } out: diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 133afcf4d79e4..9687d00c4b920 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -409,32 +409,22 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_context_unreference(dctx); } -int i915_gem_context_enable(struct drm_i915_private *dev_priv) +int i915_gem_context_enable(struct intel_engine_cs *ring) { - struct intel_engine_cs *ring; - int ret, i; - - BUG_ON(!dev_priv->ring[RCS].default_context); + int ret; if (i915.enable_execlists) { - for_each_ring(ring, dev_priv, i) { - if (ring->init_context) { - ret = ring->init_context(ring, - ring->default_context); - if (ret) { - DRM_ERROR("ring init context: %d\n", - ret); - return ret; - } - } - } + if (ring->init_context == NULL) + return 0; + ret = ring->init_context(ring, ring->default_context); } else - for_each_ring(ring, dev_priv, i) { - ret = i915_switch_context(ring, ring->default_context); - if (ret) - return ret; - } + ret = i915_switch_context(ring, ring->default_context); + + if (ret) { + DRM_ERROR("ring init context: %d\n", ret); + return ret; + } return 0; } -- GitLab From a3fbe05a611811ad8413130f63aaa79428b00377 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:38 +0100 Subject: [PATCH 0196/7006] drm/i915: Don't tag kernel batches as user batches The render state initialisation code does an explicit i915_add_request() call to commit the init commands. It was passing in the initialisation batch buffer to add_request() as the batch object parameter. However, the batch object entry in the request structure (which is all that parameter is used for) is meant for keeping track of user generated batch buffers for blame tagging during GPU hangs. This patch clears the batch object parameter so that kernel generated batch buffers are not tagged as being user generated. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 4418616301e75..a32a4b9492b65 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, NULL, so.obj, true); + __i915_add_request(ring, NULL, NULL, true); /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 47443b9aa1721..550e854a35091 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1599,7 +1599,7 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, file, so.obj, true); + __i915_add_request(ring, file, NULL, true); /* intel_logical_ring_add_request moves object to inactive if it * fails */ out: -- GitLab From dc4be6071a24f0d2da6af8ce16c19f276ac4d7a2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:39 +0100 Subject: [PATCH 0197/7006] drm/i915: Add explicit request management to i915_gem_init_hw() Now that a single per ring loop is being done for all the different intialisation steps in i915_gem_init_hw(), it is possible to add proper request management as well. The last remaining issue is that the context enable call eventually ends up within *_render_state_init() and this does its own private _i915_add_request() call. This patch adds explicit request creation and submission to the top level loop and removes the add_request() from deep within the sub-functions. v2: Updated for removal of batch_obj from add_request call in previous patch. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++++++++ drivers/gpu/drm/i915/i915_gem_render_state.c | 2 -- drivers/gpu/drm/i915/intel_lrc.c | 5 ----- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 198e681639b71..75255392e1f45 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2169,7 +2169,8 @@ struct drm_i915_gem_request { struct intel_context *ctx; struct intel_ringbuffer *ringbuf; - /** Batch buffer related to this request if any */ + /** Batch buffer related to this request if any (used for + error state dump only) */ struct drm_i915_gem_object *batch_obj; /** Time at which this request was emitted, in jiffies. */ diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index a580593f586e6..1872c985f8e54 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5069,8 +5069,16 @@ i915_gem_init_hw(struct drm_device *dev) /* Now it is safe to go back round and do everything else: */ for_each_ring(ring, dev_priv, i) { + struct drm_i915_gem_request *req; + WARN_ON(!ring->default_context); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); + if (ret) { + i915_gem_cleanup_ringbuffer(dev); + goto out; + } + if (ring->id == RCS) { for (j = 0; j < NUM_L3_SLICES(dev); j++) i915_gem_l3_remap(ring, j); @@ -5079,6 +5087,7 @@ i915_gem_init_hw(struct drm_device *dev) ret = i915_ppgtt_init_ring(ring); if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); + i915_gem_request_cancel(req); i915_gem_cleanup_ringbuffer(dev); goto out; } @@ -5086,9 +5095,12 @@ i915_gem_init_hw(struct drm_device *dev) ret = i915_gem_context_enable(ring); if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); + i915_gem_request_cancel(req); i915_gem_cleanup_ringbuffer(dev); goto out; } + + i915_add_request_no_flush(ring); } out: diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a32a4b9492b65..a07b4ee89fc27 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -173,8 +173,6 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring) i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, NULL, NULL, true); - /* __i915_add_request moves object to inactive if it fails */ out: i915_gem_render_state_fini(&so); return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 550e854a35091..3549ba608e6e8 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1579,8 +1579,6 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, { struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; struct render_state so; - struct drm_i915_file_private *file_priv = ctx->file_priv; - struct drm_file *file = file_priv ? file_priv->file : NULL; int ret; ret = i915_gem_render_state_prepare(ring, &so); @@ -1599,9 +1597,6 @@ static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); - __i915_add_request(ring, file, NULL, true); - /* intel_logical_ring_add_request moves object to inactive if it - * fails */ out: i915_gem_render_state_fini(&so); return ret; -- GitLab From b3dd6b9681e4116bce4dd1145cb162a5a48bac8e Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:40 +0100 Subject: [PATCH 0198/7006] drm/i915: Update ppgtt_init_ring() & context_enable() to take requests The final step in removing the OLR from i915_gem_init_hw() is to pass the newly allocated request structure in to each step rather than passing a ring structure. This patch updates both i915_ppgtt_init_ring() and i915_gem_context_enable() to take request pointers. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_context.c | 3 ++- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +++--- drivers/gpu/drm/i915/i915_gem_gtt.h | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 75255392e1f45..714caed86cdc3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3040,7 +3040,7 @@ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); -int i915_gem_context_enable(struct intel_engine_cs *ring); +int i915_gem_context_enable(struct drm_i915_gem_request *req); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); int i915_switch_context(struct intel_engine_cs *ring, struct intel_context *to); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 1872c985f8e54..8fbdfc3e971c3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5084,7 +5084,7 @@ i915_gem_init_hw(struct drm_device *dev) i915_gem_l3_remap(ring, j); } - ret = i915_ppgtt_init_ring(ring); + ret = i915_ppgtt_init_ring(req); if (ret && ret != -EIO) { DRM_ERROR("PPGTT enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); @@ -5092,7 +5092,7 @@ i915_gem_init_hw(struct drm_device *dev) goto out; } - ret = i915_gem_context_enable(ring); + ret = i915_gem_context_enable(req); if (ret && ret != -EIO) { DRM_ERROR("Context enable ring #%d failed %d\n", i, ret); i915_gem_request_cancel(req); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 9687d00c4b920..4514d5aa5a933 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -409,8 +409,9 @@ void i915_gem_context_fini(struct drm_device *dev) i915_gem_context_unreference(dctx); } -int i915_gem_context_enable(struct intel_engine_cs *ring) +int i915_gem_context_enable(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; if (i915.enable_execlists) { diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index f8ecea22748a9..81ffd70c335e7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1571,9 +1571,9 @@ int i915_ppgtt_init_hw(struct drm_device *dev) return 0; } -int i915_ppgtt_init_ring(struct intel_engine_cs *ring) +int i915_ppgtt_init_ring(struct drm_i915_gem_request *req) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct drm_i915_private *dev_priv = req->ring->dev->dev_private; struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; if (i915.enable_execlists) @@ -1582,7 +1582,7 @@ int i915_ppgtt_init_ring(struct intel_engine_cs *ring) if (!ppgtt) return 0; - return ppgtt->switch_mm(ppgtt, ring); + return ppgtt->switch_mm(ppgtt, req->ring); } struct i915_hw_ppgtt * diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 0caa9ebb615b0..75dfa05d610dc 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -475,7 +475,7 @@ void i915_global_gtt_cleanup(struct drm_device *dev); int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt); int i915_ppgtt_init_hw(struct drm_device *dev); -int i915_ppgtt_init_ring(struct intel_engine_cs *ring); +int i915_ppgtt_init_ring(struct drm_i915_gem_request *req); void i915_ppgtt_release(struct kref *kref); struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv); -- GitLab From ba01cc9346bce45a8861f36bce2c4c5d44b800b2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:41 +0100 Subject: [PATCH 0199/7006] drm/i915: Update i915_switch_context() to take a request structure Now that the request is guaranteed to specify the context, it is possible to update the context switch code to use requests rather than ring and context pairs. This patch updates i915_switch_context() accordingly. Also removed the warning that the request's context must match the last context switch's context. As the context switch now gets the context object from the request structure, there is no longer any scope for the two to become out of step. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 +-- drivers/gpu/drm/i915/i915_gem.c | 4 +--- drivers/gpu/drm/i915/i915_gem_context.c | 19 +++++++++---------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 4 files changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 714caed86cdc3..b96d4b1a09780 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3042,8 +3042,7 @@ void i915_gem_context_reset(struct drm_device *dev); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); int i915_gem_context_enable(struct drm_i915_gem_request *req); void i915_gem_context_close(struct drm_device *dev, struct drm_file *file); -int i915_switch_context(struct intel_engine_cs *ring, - struct intel_context *to); +int i915_switch_context(struct drm_i915_gem_request *req); struct intel_context * i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id); void i915_gem_context_free(struct kref *ctx_ref); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 8fbdfc3e971c3..4625a2fdc180f 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2539,8 +2539,6 @@ void __i915_add_request(struct intel_engine_cs *ring, */ request->batch_obj = obj; - WARN_ON(!i915.enable_execlists && (request->ctx != ring->last_context)); - request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); request->file_priv = NULL; @@ -3311,7 +3309,7 @@ int i915_gpu_idle(struct drm_device *dev) if (ret) return ret; - ret = i915_switch_context(req->ring, ring->default_context); + ret = i915_switch_context(req); if (ret) { i915_gem_request_cancel(req); return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 4514d5aa5a933..f8902bcc39397 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -420,7 +420,7 @@ int i915_gem_context_enable(struct drm_i915_gem_request *req) ret = ring->init_context(ring, ring->default_context); } else - ret = i915_switch_context(ring, ring->default_context); + ret = i915_switch_context(req); if (ret) { DRM_ERROR("ring init context: %d\n", ret); @@ -775,8 +775,7 @@ unpin_out: /** * i915_switch_context() - perform a GPU context switch. - * @ring: ring for which we'll execute the context switch - * @to: the context to switch to + * @req: request for which we'll execute the context switch * * The context life cycle is simple. The context refcount is incremented and * decremented by 1 and create and destroy. If the context is in use by the GPU, @@ -787,25 +786,25 @@ unpin_out: * switched by writing to the ELSP and requests keep a reference to their * context. */ -int i915_switch_context(struct intel_engine_cs *ring, - struct intel_context *to) +int i915_switch_context(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = ring->dev->dev_private; WARN_ON(i915.enable_execlists); WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex)); - if (to->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */ - if (to != ring->last_context) { - i915_gem_context_reference(to); + if (req->ctx->legacy_hw_ctx.rcs_state == NULL) { /* We have the fake context */ + if (req->ctx != ring->last_context) { + i915_gem_context_reference(req->ctx); if (ring->last_context) i915_gem_context_unreference(ring->last_context); - ring->last_context = to; + ring->last_context = req->ctx; } return 0; } - return do_switch(ring, to); + return do_switch(req->ring, req->ctx); } static bool contexts_enabled(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index a15517249bb99..d0ced5b04f4d3 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1250,7 +1250,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (ret) goto error; - ret = i915_switch_context(ring, params->ctx); + ret = i915_switch_context(params->request); if (ret) goto error; -- GitLab From abd68d9ed3fbd3280e8780150bd0e01099b02627 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:42 +0100 Subject: [PATCH 0200/7006] drm/i915: Update do_switch() to take a request structure Updated do_switch() to take a request pointer instead of a ring/context pair. v2: Removed some overzealous req-> dereferencing. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index f8902bcc39397..116c98394507b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -614,9 +614,10 @@ needs_pd_load_post(struct intel_engine_cs *ring, struct intel_context *to, return false; } -static int do_switch(struct intel_engine_cs *ring, - struct intel_context *to) +static int do_switch(struct drm_i915_gem_request *req) { + struct intel_context *to = req->ctx; + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = ring->dev->dev_private; struct intel_context *from = ring->last_context; u32 hw_flags = 0; @@ -804,7 +805,7 @@ int i915_switch_context(struct drm_i915_gem_request *req) return 0; } - return do_switch(req->ring, req->ctx); + return do_switch(req); } static bool contexts_enabled(struct drm_device *dev) -- GitLab From 76c3916887f1225db4b4960c59820db1a995f3cb Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:43 +0100 Subject: [PATCH 0201/7006] drm/i915: Update deferred context creation to do explicit request management In execlist mode, context initialisation is deferred until first use of the given context. This is because execlist mode has per ring context state and thus many more context storage objects than legacy mode and many are never actually used. Previously, the initialisation commands were written to the ring and tagged with some random request structure via the OLR. This seemed to be causing a null pointer deference bug under certain circumstances (BZ:88865). This patch adds explicit request creation and submission to the deferred initialisation code path. Thus removing any reliance on or randomness caused by the OLR. Note that it should be possible to move the deferred context creation until even later - when the context is actually switched to rather than when it is merely validated. This would allow the initialisation to be done within the request of the work that is wanting to use the context. Hence, the extra request that is created, used and retired just for the context init could be removed completely. However, this is left for a follow up patch. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3549ba608e6e8..3d60823e2c203 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2230,13 +2230,22 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, lrc_setup_hardware_status_page(ring, ctx_obj); else if (ring->id == RCS && !ctx->rcs_initialized) { if (ring->init_context) { - ret = ring->init_context(ring, ctx); + struct drm_i915_gem_request *req; + + ret = i915_gem_request_alloc(ring, ctx, &req); + if (ret) + return ret; + + ret = ring->init_context(req->ring, ctx); if (ret) { DRM_ERROR("ring init context: %d\n", ret); + i915_gem_request_cancel(req); ctx->engine[ring->id].ringbuf = NULL; ctx->engine[ring->id].state = NULL; goto error; } + + i915_add_request_no_flush(req->ring); } ctx->rcs_initialized = true; -- GitLab From 8753181e1006dcebc84127ce29b8f8166bb1ada3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:44 +0100 Subject: [PATCH 0202/7006] drm/i915: Update init_context() to take a request structure Now that everything above has been converted to use requests, it is possible to update init_context() to take a request pointer instead of a ring/context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/intel_lrc.c | 9 ++++----- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 116c98394507b..4969fc467ac03 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -418,7 +418,7 @@ int i915_gem_context_enable(struct drm_i915_gem_request *req) if (ring->init_context == NULL) return 0; - ret = ring->init_context(ring, ring->default_context); + ret = ring->init_context(req); } else ret = i915_switch_context(req); @@ -760,7 +760,7 @@ done: if (uninitialized) { if (ring->init_context) { - ret = ring->init_context(ring, to); + ret = ring->init_context(req); if (ret) DRM_ERROR("ring init context: %d\n", ret); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 3d60823e2c203..a8704f3571ffc 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1602,16 +1602,15 @@ out: return ret; } -static int gen8_init_rcs_context(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int gen8_init_rcs_context(struct drm_i915_gem_request *req) { int ret; - ret = intel_logical_ring_workarounds_emit(ring, ctx); + ret = intel_logical_ring_workarounds_emit(req->ring, req->ctx); if (ret) return ret; - return intel_lr_context_render_state_init(ring, ctx); + return intel_lr_context_render_state_init(req->ring, req->ctx); } /** @@ -2236,7 +2235,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, if (ret) return ret; - ret = ring->init_context(req->ring, ctx); + ret = ring->init_context(req); if (ret) { DRM_ERROR("ring init context: %d\n", ret); i915_gem_request_cancel(req); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 13eab17579728..1b9b2c0605334 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -742,16 +742,15 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; } -static int intel_rcs_ctx_init(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) { int ret; - ret = intel_ring_workarounds_emit(ring, ctx); + ret = intel_ring_workarounds_emit(req->ring, req->ctx); if (ret != 0) return ret; - ret = i915_gem_render_state_init(ring); + ret = i915_gem_render_state_init(req->ring); if (ret) DRM_ERROR("init render state: %d\n", ret); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 73db3ae8f237a..2bf58fa024eff 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -176,8 +176,7 @@ struct intel_engine_cs { int (*init_hw)(struct intel_engine_cs *ring); - int (*init_context)(struct intel_engine_cs *ring, - struct intel_context *ctx); + int (*init_context)(struct drm_i915_gem_request *req); void (*write_tail)(struct intel_engine_cs *ring, u32 value); -- GitLab From be01363f0a38c30828aca620e30f8c158910fca6 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:45 +0100 Subject: [PATCH 0203/7006] drm/i915: Update render_state_init() to take a request structure Updated the two render_state_init() functions to take a request pointer instead of a ring. This removes their reliance on the OLR. v2: Rebased to newer tree. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 14 +++++++------- drivers/gpu/drm/i915/i915_gem_render_state.h | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 18 ++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a07b4ee89fc27..6598f9bc67e55 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -152,26 +152,26 @@ int i915_gem_render_state_prepare(struct intel_engine_cs *ring, return 0; } -int i915_gem_render_state_init(struct intel_engine_cs *ring) +int i915_gem_render_state_init(struct drm_i915_gem_request *req) { struct render_state so; int ret; - ret = i915_gem_render_state_prepare(ring, &so); + ret = i915_gem_render_state_prepare(req->ring, &so); if (ret) return ret; if (so.rodata == NULL) return 0; - ret = ring->dispatch_execbuffer(ring, - so.ggtt_offset, - so.rodata->batch_items * 4, - I915_DISPATCH_SECURE); + ret = req->ring->dispatch_execbuffer(req->ring, + so.ggtt_offset, + so.rodata->batch_items * 4, + I915_DISPATCH_SECURE); if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.h b/drivers/gpu/drm/i915/i915_gem_render_state.h index c44961ed3fad4..7aa73728178ac 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.h +++ b/drivers/gpu/drm/i915/i915_gem_render_state.h @@ -39,7 +39,7 @@ struct render_state { int gen; }; -int i915_gem_render_state_init(struct intel_engine_cs *ring); +int i915_gem_render_state_init(struct drm_i915_gem_request *req); void i915_gem_render_state_fini(struct render_state *so); int i915_gem_render_state_prepare(struct intel_engine_cs *ring, struct render_state *so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a8704f3571ffc..78f3bac9403bb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1574,28 +1574,26 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf, return 0; } -static int intel_lr_context_render_state_init(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) { - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; struct render_state so; int ret; - ret = i915_gem_render_state_prepare(ring, &so); + ret = i915_gem_render_state_prepare(req->ring, &so); if (ret) return ret; if (so.rodata == NULL) return 0; - ret = ring->emit_bb_start(ringbuf, - ctx, - so.ggtt_offset, - I915_DISPATCH_SECURE); + ret = req->ring->emit_bb_start(req->ringbuf, + req->ctx, + so.ggtt_offset, + I915_DISPATCH_SECURE); if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); out: i915_gem_render_state_fini(&so); @@ -1610,7 +1608,7 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req) if (ret) return ret; - return intel_lr_context_render_state_init(req->ring, req->ctx); + return intel_lr_context_render_state_init(req); } /** diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1b9b2c0605334..c5e42fcdecb37 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -750,7 +750,7 @@ static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) if (ret != 0) return ret; - ret = i915_gem_render_state_init(req->ring); + ret = i915_gem_render_state_init(req); if (ret) DRM_ERROR("init render state: %d\n", ret); -- GitLab From 91af127fd7a2f069046b0b6740473e70e0051492 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Thu, 18 Jun 2015 13:14:56 +0100 Subject: [PATCH 0204/7006] drm/i915: Update i915_gem_object_sync() to take a request structure The plan is to pass requests around as the basic submission tracking structure rather than rings and contexts. This patch updates the i915_gem_object_sync() code path. v2: Much more complex patch to share a single request between the sync and the page flip. The _sync() function now supports lazy allocation of the request structure. That is, if one is passed in then that will be used. If one is not, then a request will be allocated and passed back out. Note that the _sync() code does not necessarily require a request. Thus one will only be created until certain situations. The reason the lazy allocation must be done within the _sync() code itself is because the decision to need one or not is not really something that code above can second guess (except in the case where one is definitely not required because no ring is passed in). The call chains above _sync() now support passing a request through which most callers passing in NULL and assuming that no request will be required (because they also pass in NULL for the ring and therefore can't be generating any ring code). The exeception is intel_crtc_page_flip() which now supports having a request returned from _sync(). If one is, then that request is shared by the page flip (if the page flip is of a type to need a request). If _sync() does not generate a request but the page flip does need one, then the page flip path will create its own request. v3: Updated comment description to be clearer about 'to_req' parameter (Tomas Elf review request). Rebased onto newer tree that significantly changed the synchronisation code. v4: Updated comments from review feedback (Tomas Elf) For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/i915_gem.c | 48 ++++++++++++++++------ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 17 +++++--- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_fbdev.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 2 +- 8 files changed, 57 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b96d4b1a09780..6f2fd3de88e4d 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2805,7 +2805,8 @@ static inline void i915_gem_object_unpin_pages(struct drm_i915_gem_object *obj) int __must_check i915_mutex_lock_interruptible(struct drm_device *dev); int i915_gem_object_sync(struct drm_i915_gem_object *obj, - struct intel_engine_cs *to); + struct intel_engine_cs *to, + struct drm_i915_gem_request **to_req); void i915_vma_move_to_active(struct i915_vma *vma, struct intel_engine_cs *ring); int i915_gem_dumb_create(struct drm_file *file_priv, @@ -2916,6 +2917,7 @@ int __must_check i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request, const struct i915_ggtt_view *view); void i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj, const struct i915_ggtt_view *view); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 4625a2fdc180f..e80b08b864e77 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3094,25 +3094,26 @@ out: static int __i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_engine_cs *to, - struct drm_i915_gem_request *req) + struct drm_i915_gem_request *from_req, + struct drm_i915_gem_request **to_req) { struct intel_engine_cs *from; int ret; - from = i915_gem_request_get_ring(req); + from = i915_gem_request_get_ring(from_req); if (to == from) return 0; - if (i915_gem_request_completed(req, true)) + if (i915_gem_request_completed(from_req, true)) return 0; - ret = i915_gem_check_olr(req); + ret = i915_gem_check_olr(from_req); if (ret) return ret; if (!i915_semaphore_is_enabled(obj->base.dev)) { struct drm_i915_private *i915 = to_i915(obj->base.dev); - ret = __i915_wait_request(req, + ret = __i915_wait_request(from_req, atomic_read(&i915->gpu_error.reset_counter), i915->mm.interruptible, NULL, @@ -3120,15 +3121,23 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, if (ret) return ret; - i915_gem_object_retire_request(obj, req); + i915_gem_object_retire_request(obj, from_req); } else { int idx = intel_ring_sync_index(from, to); - u32 seqno = i915_gem_request_get_seqno(req); + u32 seqno = i915_gem_request_get_seqno(from_req); + + WARN_ON(!to_req); if (seqno <= from->semaphore.sync_seqno[idx]) return 0; - trace_i915_gem_ring_sync_to(from, to, req); + if (*to_req == NULL) { + ret = i915_gem_request_alloc(to, to->default_context, to_req); + if (ret) + return ret; + } + + trace_i915_gem_ring_sync_to(from, to, from_req); ret = to->semaphore.sync_to(to, from, seqno); if (ret) return ret; @@ -3149,11 +3158,14 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, * * @obj: object which may be in use on another ring. * @to: ring we wish to use the object on. May be NULL. + * @to_req: request we wish to use the object for. See below. + * This will be allocated and returned if a request is + * required but not passed in. * * This code is meant to abstract object synchronization with the GPU. * Calling with NULL implies synchronizing the object with the CPU * rather than a particular GPU ring. Conceptually we serialise writes - * between engines inside the GPU. We only allow on engine to write + * between engines inside the GPU. We only allow one engine to write * into a buffer at any time, but multiple readers. To ensure each has * a coherent view of memory, we must: * @@ -3164,11 +3176,22 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, * - If we are a write request (pending_write_domain is set), the new * request must wait for outstanding read requests to complete. * + * For CPU synchronisation (NULL to) no request is required. For syncing with + * rings to_req must be non-NULL. However, a request does not have to be + * pre-allocated. If *to_req is NULL and sync commands will be emitted then a + * request will be allocated automatically and returned through *to_req. Note + * that it is not guaranteed that commands will be emitted (because the system + * might already be idle). Hence there is no need to create a request that + * might never have any work submitted. Note further that if a request is + * returned in *to_req, it is the responsibility of the caller to submit + * that request (after potentially adding more work to it). + * * Returns 0 if successful, else propagates up the lower layer error. */ int i915_gem_object_sync(struct drm_i915_gem_object *obj, - struct intel_engine_cs *to) + struct intel_engine_cs *to, + struct drm_i915_gem_request **to_req) { const bool readonly = obj->base.pending_write_domain == 0; struct drm_i915_gem_request *req[I915_NUM_RINGS]; @@ -3190,7 +3213,7 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj, req[n++] = obj->last_read_req[i]; } for (i = 0; i < n; i++) { - ret = __i915_gem_object_sync(obj, to, req[i]); + ret = __i915_gem_object_sync(obj, to, req[i], to_req); if (ret) return ret; } @@ -4140,12 +4163,13 @@ int i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj, u32 alignment, struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request, const struct i915_ggtt_view *view) { u32 old_read_domains, old_write_domain; int ret; - ret = i915_gem_object_sync(obj, pipelined); + ret = i915_gem_object_sync(obj, pipelined, pipelined_request); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index d0ced5b04f4d3..9968c02f76f33 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -904,7 +904,7 @@ i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, req->ring); + ret = i915_gem_object_sync(obj, req->ring, &req); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index de6f8cc3c6d00..733308697094d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2304,7 +2304,8 @@ int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state, - struct intel_engine_cs *pipelined) + struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request) { struct drm_device *dev = fb->dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -2362,7 +2363,7 @@ intel_pin_and_fence_fb_obj(struct drm_plane *plane, dev_priv->mm.interruptible = false; ret = i915_gem_object_pin_to_display_plane(obj, alignment, pipelined, - &view); + pipelined_request, &view); if (ret) goto err_interruptible; @@ -11352,6 +11353,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, struct intel_unpin_work *work; struct intel_engine_cs *ring; bool mmio_flip; + struct drm_i915_gem_request *request = NULL; int ret; /* @@ -11458,7 +11460,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, */ ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, crtc->primary->state, - mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring); + mmio_flip ? i915_gem_request_get_ring(obj->last_write_req) : ring, &request); if (ret) goto cleanup_pending; @@ -11489,6 +11491,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_ring_get_request(ring)); } + if (request) + i915_add_request_no_flush(request->ring); + work->flip_queued_vblank = drm_crtc_vblank_count(crtc); work->enable_stall_check = true; @@ -11506,6 +11511,8 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, cleanup_unpin: intel_unpin_fb_obj(fb, crtc->primary->state); cleanup_pending: + if (request) + i915_gem_request_cancel(request); atomic_dec(&intel_crtc->unpin_work_count); mutex_unlock(&dev->struct_mutex); cleanup: @@ -13620,7 +13627,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, if (ret) DRM_DEBUG_KMS("failed to attach phys object\n"); } else { - ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL); + ret = intel_pin_and_fence_fb_obj(plane, fb, new_state, NULL, NULL); } if (ret == 0) @@ -15560,7 +15567,7 @@ void intel_modeset_gem_init(struct drm_device *dev) ret = intel_pin_and_fence_fb_obj(c->primary, c->primary->fb, c->primary->state, - NULL); + NULL, NULL); mutex_unlock(&dev->struct_mutex); if (ret) { DRM_ERROR("failed to pin boot fb on pipe %d\n", diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e2174fd3030bc..3529c9c9c4209 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1045,7 +1045,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, int intel_pin_and_fence_fb_obj(struct drm_plane *plane, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state, - struct intel_engine_cs *pipelined); + struct intel_engine_cs *pipelined, + struct drm_i915_gem_request **pipelined_request); struct drm_framebuffer * __intel_framebuffer_create(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 838214666cc37..2a1724e34a36a 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -177,7 +177,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper, } /* Flush everything out, we'll be doing GTT only from now on */ - ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL); + ret = intel_pin_and_fence_fb_obj(NULL, fb, NULL, NULL, NULL); if (ret) { DRM_ERROR("failed to pin obj: %d\n", ret); goto out_fb; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 78f3bac9403bb..7bcf1ec4d6aa0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -637,7 +637,7 @@ static int execlists_move_to_gpu(struct drm_i915_gem_request *req, struct drm_i915_gem_object *obj = vma->obj; if (obj->active & other_rings) { - ret = i915_gem_object_sync(obj, req->ring); + ret = i915_gem_object_sync(obj, req->ring, &req); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index e7534b9466957..0f8187a121829 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -724,7 +724,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay, if (ret != 0) return ret; - ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, + ret = i915_gem_object_pin_to_display_plane(new_bo, 0, NULL, NULL, &i915_ggtt_view_normal); if (ret != 0) return ret; -- GitLab From dad540ce02c5bc82569061c9562982e6f052ee42 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:47 +0100 Subject: [PATCH 0205/7006] drm/i915: Update overlay code to do explicit request management The overlay update code path to do explicit request creation and submission rather than relying on the OLR to do the right thing. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_overlay.c | 57 ++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 0f8187a121829..3adb63eb0b99d 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -210,17 +210,14 @@ static void intel_overlay_unmap_regs(struct intel_overlay *overlay, } static int intel_overlay_do_wait_request(struct intel_overlay *overlay, + struct drm_i915_gem_request *req, void (*tail)(struct intel_overlay *)) { - struct drm_device *dev = overlay->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_engine_cs *ring = &dev_priv->ring[RCS]; int ret; WARN_ON(overlay->last_flip_req); - i915_gem_request_assign(&overlay->last_flip_req, - ring->outstanding_lazy_request); - i915_add_request(ring); + i915_gem_request_assign(&overlay->last_flip_req, req); + i915_add_request(req->ring); overlay->flip_tail = tail; ret = i915_wait_request(overlay->last_flip_req); @@ -237,15 +234,22 @@ static int intel_overlay_on(struct intel_overlay *overlay) struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + struct drm_i915_gem_request *req; int ret; WARN_ON(overlay->active); WARN_ON(IS_I830(dev) && !(dev_priv->quirks & QUIRK_PIPEA_FORCE)); - ret = intel_ring_begin(ring, 4); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 4); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + overlay->active = true; intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_ON); @@ -254,7 +258,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); - return intel_overlay_do_wait_request(overlay, NULL); + return intel_overlay_do_wait_request(overlay, req, NULL); } /* overlay needs to be enabled in OCMD reg */ @@ -264,6 +268,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + struct drm_i915_gem_request *req; u32 flip_addr = overlay->flip_addr; u32 tmp; int ret; @@ -278,18 +283,23 @@ static int intel_overlay_continue(struct intel_overlay *overlay, if (tmp & (1 << 17)) DRM_DEBUG("overlay underrun, DOVSTA: %x\n", tmp); - ret = intel_ring_begin(ring, 2); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 2); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); intel_ring_emit(ring, flip_addr); intel_ring_advance(ring); WARN_ON(overlay->last_flip_req); - i915_gem_request_assign(&overlay->last_flip_req, - ring->outstanding_lazy_request); - i915_add_request(ring); + i915_gem_request_assign(&overlay->last_flip_req, req); + i915_add_request(req->ring); return 0; } @@ -327,6 +337,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) struct drm_device *dev = overlay->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *ring = &dev_priv->ring[RCS]; + struct drm_i915_gem_request *req; u32 flip_addr = overlay->flip_addr; int ret; @@ -338,10 +349,16 @@ static int intel_overlay_off(struct intel_overlay *overlay) * of the hw. Do it in both cases */ flip_addr |= OFC_UPDATE; - ret = intel_ring_begin(ring, 6); + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 6); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + /* wait for overlay to go idle */ intel_ring_emit(ring, MI_OVERLAY_FLIP | MI_OVERLAY_CONTINUE); intel_ring_emit(ring, flip_addr); @@ -360,7 +377,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) } intel_ring_advance(ring); - return intel_overlay_do_wait_request(overlay, intel_overlay_off_tail); + return intel_overlay_do_wait_request(overlay, req, intel_overlay_off_tail); } /* recover from an interruption due to a signal @@ -404,15 +421,23 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) if (I915_READ(ISR) & I915_OVERLAY_PLANE_FLIP_PENDING_INTERRUPT) { /* synchronous slowpath */ - ret = intel_ring_begin(ring, 2); + struct drm_i915_gem_request *req; + + ret = i915_gem_request_alloc(ring, ring->default_context, &req); if (ret) return ret; + ret = intel_ring_begin(ring, 2); + if (ret) { + i915_gem_request_cancel(req); + return ret; + } + intel_ring_emit(ring, MI_WAIT_FOR_EVENT | MI_WAIT_FOR_OVERLAY_FLIP); intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); - ret = intel_overlay_do_wait_request(overlay, + ret = intel_overlay_do_wait_request(overlay, req, intel_overlay_release_old_vid_tail); if (ret) return ret; -- GitLab From 6258fbe23fe04da544261f48112a292bdb068c12 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:48 +0100 Subject: [PATCH 0206/7006] drm/i915: Update queue_flip() to take a request structure Updated the display page flip code to do explicit request creation and submission rather than relying on the OLR and just hoping that the request actually gets submitted at some random point. The sequence is now to create a request, queue the work to the ring, assign the known request to the flip queue work item then actually submit the work and post the request. Note that every single flip function used to finish with '__intel_ring_advance(ring);'. However, immediately after they return there is now an add request call which will do the advance anyway. Thus the many duplicate advance calls have been removed. v2: Updated commit message with comment about advance removal. v3: The request can now be allocated by the _sync() code earlier on. Thus the page flip path does not necessarily need to allocate a new request, it may be able to re-use one. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/intel_display.c | 33 ++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 - 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6f2fd3de88e4d..0bb6a340d1c96 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -640,7 +640,7 @@ struct drm_i915_display_funcs { int (*queue_flip)(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags); void (*update_primary_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 733308697094d..36d8cdeaed035 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10868,9 +10868,10 @@ static int intel_gen2_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 flip_mask; int ret; @@ -10895,7 +10896,6 @@ static int intel_gen2_queue_flip(struct drm_device *dev, intel_ring_emit(ring, 0); /* aux display base address, unused */ intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -10903,9 +10903,10 @@ static int intel_gen3_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 flip_mask; int ret; @@ -10927,7 +10928,6 @@ static int intel_gen3_queue_flip(struct drm_device *dev, intel_ring_emit(ring, MI_NOOP); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -10935,9 +10935,10 @@ static int intel_gen4_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pf, pipesrc; @@ -10966,7 +10967,6 @@ static int intel_gen4_queue_flip(struct drm_device *dev, intel_ring_emit(ring, pf | pipesrc); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -10974,9 +10974,10 @@ static int intel_gen6_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t pf, pipesrc; @@ -11002,7 +11003,6 @@ static int intel_gen6_queue_flip(struct drm_device *dev, intel_ring_emit(ring, pf | pipesrc); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -11010,9 +11010,10 @@ static int intel_gen7_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { + struct intel_engine_cs *ring = req->ring; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); uint32_t plane_bit = 0; int len, ret; @@ -11097,7 +11098,6 @@ static int intel_gen7_queue_flip(struct drm_device *dev, intel_ring_emit(ring, (MI_NOOP)); intel_mark_page_flip_active(intel_crtc); - __intel_ring_advance(ring); return 0; } @@ -11267,7 +11267,7 @@ static int intel_default_queue_flip(struct drm_device *dev, struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_gem_object *obj, - struct intel_engine_cs *ring, + struct drm_i915_gem_request *req, uint32_t flags) { return -ENODEV; @@ -11482,13 +11482,18 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, goto cleanup_unpin; } - ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring, + if (!request) { + ret = i915_gem_request_alloc(ring, ring->default_context, &request); + if (ret) + goto cleanup_unpin; + } + + ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, request, page_flip_flags); if (ret) goto cleanup_unpin; - i915_gem_request_assign(&work->flip_queued_req, - intel_ring_get_request(ring)); + i915_gem_request_assign(&work->flip_queued_req, request); } if (request) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index c5e42fcdecb37..38fa1fad594f8 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -81,7 +81,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring) return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring); } -void __intel_ring_advance(struct intel_engine_cs *ring) +static void __intel_ring_advance(struct intel_engine_cs *ring) { struct intel_ringbuffer *ringbuf = ring->buffer; ringbuf->tail &= ringbuf->size - 1; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2bf58fa024eff..8713b0589859a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -442,7 +442,6 @@ int __intel_ring_space(int head, int tail, int size); void intel_ring_update_space(struct intel_ringbuffer *ringbuf); int intel_ring_space(struct intel_ringbuffer *ringbuf); bool intel_ring_stopped(struct intel_engine_cs *ring); -void __intel_ring_advance(struct intel_engine_cs *ring); int __must_check intel_ring_idle(struct intel_engine_cs *ring); void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno); -- GitLab From 75289874e4484cd4702b3341b654b45b4a09b9d3 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:49 +0100 Subject: [PATCH 0207/7006] drm/i915: Update add_request() to take a request structure Now that all callers of i915_add_request() have a request pointer to hand, it is possible to update the add request function to take a request pointer rather than pulling it out of the OLR. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 10 +++++----- drivers/gpu/drm/i915/i915_gem.c | 22 +++++++++++----------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- drivers/gpu/drm/i915/intel_overlay.c | 4 ++-- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0bb6a340d1c96..da7cb141a4d50 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2890,14 +2890,14 @@ void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); -void __i915_add_request(struct intel_engine_cs *ring, +void __i915_add_request(struct drm_i915_gem_request *req, struct drm_file *file, struct drm_i915_gem_object *batch_obj, bool flush_caches); -#define i915_add_request(ring) \ - __i915_add_request(ring, NULL, NULL, true) -#define i915_add_request_no_flush(ring) \ - __i915_add_request(ring, NULL, NULL, false) +#define i915_add_request(req) \ + __i915_add_request(req, NULL, NULL, true) +#define i915_add_request_no_flush(req) \ + __i915_add_request(req, NULL, NULL, false) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e80b08b864e77..c12bdd855be7b 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1158,7 +1158,7 @@ i915_gem_check_olr(struct drm_i915_gem_request *req) WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); if (req == req->ring->outstanding_lazy_request) - i915_add_request(req->ring); + i915_add_request(req); return 0; } @@ -2468,25 +2468,25 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) * request is not being tracked for completion but the work itself is * going to happen on the hardware. This would be a Bad Thing(tm). */ -void __i915_add_request(struct intel_engine_cs *ring, +void __i915_add_request(struct drm_i915_gem_request *request, struct drm_file *file, struct drm_i915_gem_object *obj, bool flush_caches) { - struct drm_i915_private *dev_priv = ring->dev->dev_private; - struct drm_i915_gem_request *request; + struct intel_engine_cs *ring; + struct drm_i915_private *dev_priv; struct intel_ringbuffer *ringbuf; u32 request_start; int ret; - request = ring->outstanding_lazy_request; if (WARN_ON(request == NULL)) return; - if (i915.enable_execlists) { - ringbuf = request->ctx->engine[ring->id].ringbuf; - } else - ringbuf = ring->buffer; + ring = request->ring; + dev_priv = ring->dev->dev_private; + ringbuf = request->ringbuf; + + WARN_ON(request != ring->outstanding_lazy_request); /* * To ensure that this call will not fail, space for its emissions @@ -3338,7 +3338,7 @@ int i915_gpu_idle(struct drm_device *dev) return ret; } - i915_add_request_no_flush(req->ring); + i915_add_request_no_flush(req); } WARN_ON(ring->outstanding_lazy_request); @@ -5122,7 +5122,7 @@ i915_gem_init_hw(struct drm_device *dev) goto out; } - i915_add_request_no_flush(ring); + i915_add_request_no_flush(req); } out: diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9968c02f76f33..896f7a117b995 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1066,7 +1066,7 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(params->ring, params->file, params->batch_obj, true); + __i915_add_request(params->request, params->file, params->batch_obj, true); } static int diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 36d8cdeaed035..7ec2421f0a970 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11497,7 +11497,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, } if (request) - i915_add_request_no_flush(request->ring); + i915_add_request_no_flush(request); work->flip_queued_vblank = drm_crtc_vblank_count(crtc); work->enable_stall_check = true; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7bcf1ec4d6aa0..d142d284afd71 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -2242,7 +2242,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx, goto error; } - i915_add_request_no_flush(req->ring); + i915_add_request_no_flush(req); } ctx->rcs_initialized = true; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3adb63eb0b99d..3f709042b86cf 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -217,7 +217,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, req); - i915_add_request(req->ring); + i915_add_request(req); overlay->flip_tail = tail; ret = i915_wait_request(overlay->last_flip_req); @@ -299,7 +299,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, WARN_ON(overlay->last_flip_req); i915_gem_request_assign(&overlay->last_flip_req, req); - i915_add_request(req->ring); + i915_add_request(req); return 0; } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 38fa1fad594f8..049bc7fa3c426 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2167,8 +2167,9 @@ int intel_ring_idle(struct intel_engine_cs *ring) struct drm_i915_gem_request *req; /* We need to add any requests required to flush the objects and ring */ + WARN_ON(ring->outstanding_lazy_request); if (ring->outstanding_lazy_request) - i915_add_request(ring); + i915_add_request(ring->outstanding_lazy_request); /* Wait upon the last request to be completed */ if (list_empty(&ring->request_list)) -- GitLab From b2af03769301e986740c50bf72a47b9abd528290 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:50 +0100 Subject: [PATCH 0208/7006] drm/i915: Update [vma|object]_move_to_active() to take request structures Now that everything above has been converted to use request structures, it is possible to update the lower level move_to_active() functions to be request based as well. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 8 +++++--- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- drivers/gpu/drm/i915/i915_gem_render_state.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 2 +- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index da7cb141a4d50..74a437f0ae685 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2808,7 +2808,7 @@ int i915_gem_object_sync(struct drm_i915_gem_object *obj, struct intel_engine_cs *to, struct drm_i915_gem_request **to_req); void i915_vma_move_to_active(struct i915_vma *vma, - struct intel_engine_cs *ring); + struct drm_i915_gem_request *req); int i915_gem_dumb_create(struct drm_file *file_priv, struct drm_device *dev, struct drm_mode_create_dumb *args); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c12bdd855be7b..19a2441519130 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2340,9 +2340,12 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj) } void i915_vma_move_to_active(struct i915_vma *vma, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { struct drm_i915_gem_object *obj = vma->obj; + struct intel_engine_cs *ring; + + ring = i915_gem_request_get_ring(req); /* Add a reference if we're newly entering the active list. */ if (obj->active == 0) @@ -2350,8 +2353,7 @@ void i915_vma_move_to_active(struct i915_vma *vma, obj->active |= intel_ring_flag(ring); list_move_tail(&obj->ring_list[ring->id], &ring->active_list); - i915_gem_request_assign(&obj->last_read_req[ring->id], - intel_ring_get_request(ring)); + i915_gem_request_assign(&obj->last_read_req[ring->id], req); list_move_tail(&vma->mm_list, &vma->vm->active_list); } diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 4969fc467ac03..ea959abb8e2ce 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -736,7 +736,7 @@ static int do_switch(struct drm_i915_gem_request *req) */ if (from != NULL) { from->legacy_hw_ctx.rcs_state->base.read_domains = I915_GEM_DOMAIN_INSTRUCTION; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->legacy_hw_ctx.rcs_state), ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(from->legacy_hw_ctx.rcs_state), req); /* As long as MI_SET_CONTEXT is serializing, ie. it flushes the * whole damn pipeline, we don't need to explicitly mark the * object dirty. The only exception is that the context must be diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 896f7a117b995..6bc86b8916e9d 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1036,7 +1036,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, obj->base.pending_read_domains |= obj->base.read_domains; obj->base.read_domains = obj->base.pending_read_domains; - i915_vma_move_to_active(vma, ring); + i915_vma_move_to_active(vma, req); if (obj->base.write_domain) { obj->dirty = 1; i915_gem_request_assign(&obj->last_write_req, req); diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index 6598f9bc67e55..e04cda40df5ef 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -171,7 +171,7 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: i915_gem_render_state_fini(&so); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d142d284afd71..18e2f5f06117d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1593,7 +1593,7 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; - i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req->ring); + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: i915_gem_render_state_fini(&so); -- GitLab From 6909a666466e4a83159df94c4e29cb9cd52fce9e Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:51 +0100 Subject: [PATCH 0209/7006] drm/i915: Update l3_remap to take a request structure Converted i915_gem_l3_remap() to take a request structure instead of a ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem.c | 5 +++-- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 74a437f0ae685..5aea6ddd50915 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2885,7 +2885,7 @@ bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force); int __must_check i915_gem_init(struct drm_device *dev); int i915_gem_init_rings(struct drm_device *dev); int __must_check i915_gem_init_hw(struct drm_device *dev); -int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice); +int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice); void i915_gem_init_swizzling(struct drm_device *dev); void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 19a2441519130..79c4c328984db 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4882,8 +4882,9 @@ err: return ret; } -int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice) +int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200); @@ -5105,7 +5106,7 @@ i915_gem_init_hw(struct drm_device *dev) if (ring->id == RCS) { for (j = 0; j < NUM_L3_SLICES(dev); j++) - i915_gem_l3_remap(ring, j); + i915_gem_l3_remap(req, j); } ret = i915_ppgtt_init_ring(req); diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index ea959abb8e2ce..8e52f3c58f61b 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -720,7 +720,7 @@ static int do_switch(struct drm_i915_gem_request *req) if (!(to->remap_slice & (1< Date: Fri, 29 May 2015 17:43:52 +0100 Subject: [PATCH 0210/7006] drm/i915: Update mi_set_context() to take a request structure Updated mi_set_context() to take a request structure instead of a ring and context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index 8e52f3c58f61b..a9dd7e96306e0 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -478,10 +478,9 @@ i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id) } static inline int -mi_set_context(struct intel_engine_cs *ring, - struct intel_context *new_context, - u32 hw_flags) +mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) { + struct intel_engine_cs *ring = req->ring; u32 flags = hw_flags | MI_MM_SPACE_GTT; const int num_rings = /* Use an extended w/a on ivb+ if signalling from other rings */ @@ -533,7 +532,7 @@ mi_set_context(struct intel_engine_cs *ring, intel_ring_emit(ring, MI_NOOP); intel_ring_emit(ring, MI_SET_CONTEXT); - intel_ring_emit(ring, i915_gem_obj_ggtt_offset(new_context->legacy_hw_ctx.rcs_state) | + intel_ring_emit(ring, i915_gem_obj_ggtt_offset(req->ctx->legacy_hw_ctx.rcs_state) | flags); /* * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP @@ -695,7 +694,7 @@ static int do_switch(struct drm_i915_gem_request *req) WARN_ON(needs_pd_load_pre(ring, to) && needs_pd_load_post(ring, to, hw_flags)); - ret = mi_set_context(ring, to, hw_flags); + ret = mi_set_context(req, hw_flags); if (ret) goto unpin_out; -- GitLab From 2f20055d360a2bb6863163d8b8b005ded1f6ba08 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:53 +0100 Subject: [PATCH 0211/7006] drm/i915: Update a bunch of execbuffer helpers to take request structures Updated *_ring_invalidate_all_caches(), i915_reset_gen7_sol_offsets() and i915_emit_box() to take request structures instead of ring or ringbuf/context pairs. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 12 +++++++----- drivers/gpu/drm/i915/intel_lrc.c | 9 ++++----- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6bc86b8916e9d..1cbd6d65dae56 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -924,7 +924,7 @@ i915_gem_execbuffer_move_to_gpu(struct drm_i915_gem_request *req, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return intel_ring_invalidate_all_caches(req->ring); + return intel_ring_invalidate_all_caches(req); } static bool @@ -1071,8 +1071,9 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) static int i915_reset_gen7_sol_offsets(struct drm_device *dev, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = dev->dev_private; int ret, i; @@ -1097,10 +1098,11 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, } static int -i915_emit_box(struct intel_engine_cs *ring, +i915_emit_box(struct drm_i915_gem_request *req, struct drm_clip_rect *box, int DR1, int DR4) { + struct intel_engine_cs *ring = req->ring; int ret; if (box->y2 <= box->y1 || box->x2 <= box->x1 || @@ -1310,7 +1312,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, } if (args->flags & I915_EXEC_GEN7_SOL_RESET) { - ret = i915_reset_gen7_sol_offsets(dev, ring); + ret = i915_reset_gen7_sol_offsets(dev, params->request); if (ret) goto error; } @@ -1321,7 +1323,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (cliprects) { for (i = 0; i < args->num_cliprects; i++) { - ret = i915_emit_box(ring, &cliprects[i], + ret = i915_emit_box(params->request, &cliprects[i], args->DR1, args->DR4); if (ret) goto error; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 18e2f5f06117d..284b48bdffb92 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -604,10 +604,9 @@ static int execlists_context_queue(struct intel_engine_cs *ring, return 0; } -static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx) +static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req) { - struct intel_engine_cs *ring = ringbuf->ring; + struct intel_engine_cs *ring = req->ring; uint32_t flush_domains; int ret; @@ -615,7 +614,7 @@ static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf, if (ring->gpu_caches_dirty) flush_domains = I915_GEM_GPU_DOMAINS; - ret = ring->emit_flush(ringbuf, ctx, + ret = ring->emit_flush(req->ringbuf, req->ctx, I915_GEM_GPU_DOMAINS, flush_domains); if (ret) return ret; @@ -654,7 +653,7 @@ static int execlists_move_to_gpu(struct drm_i915_gem_request *req, /* Unconditionally invalidate gpu caches and ensure that we do flush * any residual writes from the previous batch. */ - return logical_ring_invalidate_all_caches(req->ringbuf, req->ctx); + return logical_ring_invalidate_all_caches(req); } int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 049bc7fa3c426..6bdb0ac1edf32 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2910,8 +2910,9 @@ intel_ring_flush_all_caches(struct intel_engine_cs *ring) } int -intel_ring_invalidate_all_caches(struct intel_engine_cs *ring) +intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; uint32_t flush_domains; int ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8713b0589859a..2eba35847946d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -446,7 +446,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring); int __must_check intel_ring_idle(struct intel_engine_cs *ring); void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno); int intel_ring_flush_all_caches(struct intel_engine_cs *ring); -int intel_ring_invalidate_all_caches(struct intel_engine_cs *ring); +int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req); void intel_fini_pipe_control(struct intel_engine_cs *ring); int intel_init_pipe_control(struct intel_engine_cs *ring); -- GitLab From e2be4faf30d6cb0af77c0105837df25f925903c9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:54 +0100 Subject: [PATCH 0212/7006] drm/i915: Update workarounds_emit() to take request structures Updated the *_ring_workarounds_emit() functions to take requests instead of ring/context pairs. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 +++++++------- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 +++--- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 284b48bdffb92..11f0c25c10208 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1058,11 +1058,11 @@ void intel_lr_context_unpin(struct intel_engine_cs *ring, } } -static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) { int ret, i; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = req->ring; + struct intel_ringbuffer *ringbuf = req->ringbuf; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; @@ -1071,11 +1071,11 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, return 0; ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, ctx); + ret = logical_ring_flush_all_caches(ringbuf, req->ctx); if (ret) return ret; - ret = intel_logical_ring_begin(ringbuf, ctx, w->count * 2 + 2); + ret = intel_logical_ring_begin(ringbuf, req->ctx, w->count * 2 + 2); if (ret) return ret; @@ -1089,7 +1089,7 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring, intel_logical_ring_advance(ringbuf); ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, ctx); + ret = logical_ring_flush_all_caches(ringbuf, req->ctx); if (ret) return ret; @@ -1603,7 +1603,7 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req) { int ret; - ret = intel_logical_ring_workarounds_emit(req->ring, req->ctx); + ret = intel_logical_ring_workarounds_emit(req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6bdb0ac1edf32..49869feb9e23f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -703,10 +703,10 @@ err: return ret; } -static int intel_ring_workarounds_emit(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) { int ret, i; + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct i915_workarounds *w = &dev_priv->workarounds; @@ -746,7 +746,7 @@ static int intel_rcs_ctx_init(struct drm_i915_gem_request *req) { int ret; - ret = intel_ring_workarounds_emit(req->ring, req->ctx); + ret = intel_ring_workarounds_emit(req); if (ret != 0) return ret; -- GitLab From 4866d729ab3833b811b8972d773477d3e4a6f9c0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:55 +0100 Subject: [PATCH 0213/7006] drm/i915: Update flush_all_caches() to take request structures Updated the *_ring_flush_all_caches() functions to take requests instead of rings or ringbuf/context pairs. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/intel_lrc.c | 11 +++++------ drivers/gpu/drm/i915/intel_lrc.h | 3 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 7 ++++--- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 5 files changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 79c4c328984db..25fe1ef32eaac 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2507,9 +2507,9 @@ void __i915_add_request(struct drm_i915_gem_request *request, */ if (flush_caches) { if (i915.enable_execlists) - ret = logical_ring_flush_all_caches(ringbuf, request->ctx); + ret = logical_ring_flush_all_caches(request); else - ret = intel_ring_flush_all_caches(ring); + ret = intel_ring_flush_all_caches(request); /* Not allowed to fail! */ WARN(ret, "*_ring_flush_all_caches failed: %d!\n", ret); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 11f0c25c10208..7a18e83623b29 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -997,16 +997,15 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring) I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING)); } -int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx) +int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) { - struct intel_engine_cs *ring = ringbuf->ring; + struct intel_engine_cs *ring = req->ring; int ret; if (!ring->gpu_caches_dirty) return 0; - ret = ring->emit_flush(ringbuf, ctx, 0, I915_GEM_GPU_DOMAINS); + ret = ring->emit_flush(req->ringbuf, req->ctx, 0, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1071,7 +1070,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) return 0; ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, req->ctx); + ret = logical_ring_flush_all_caches(req); if (ret) return ret; @@ -1089,7 +1088,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) intel_logical_ring_advance(ringbuf); ring->gpu_caches_dirty = true; - ret = logical_ring_flush_all_caches(ringbuf, req->ctx); + ret = logical_ring_flush_all_caches(req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index bf137c43e0a90..044c0e5c72e5f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -41,8 +41,7 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); -int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx); +int logical_ring_flush_all_caches(struct drm_i915_gem_request *req); /** * intel_logical_ring_advance() - advance the ringbuffer tail * @ringbuf: Ringbuffer to advance. diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 49869feb9e23f..48ca73e7aaa6b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -715,7 +715,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) return 0; ring->gpu_caches_dirty = true; - ret = intel_ring_flush_all_caches(ring); + ret = intel_ring_flush_all_caches(req); if (ret) return ret; @@ -733,7 +733,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) intel_ring_advance(ring); ring->gpu_caches_dirty = true; - ret = intel_ring_flush_all_caches(ring); + ret = intel_ring_flush_all_caches(req); if (ret) return ret; @@ -2892,8 +2892,9 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev) } int -intel_ring_flush_all_caches(struct intel_engine_cs *ring) +intel_ring_flush_all_caches(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; if (!ring->gpu_caches_dirty) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 2eba35847946d..3f70687a2dc68 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -445,7 +445,7 @@ bool intel_ring_stopped(struct intel_engine_cs *ring); int __must_check intel_ring_idle(struct intel_engine_cs *ring); void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno); -int intel_ring_flush_all_caches(struct intel_engine_cs *ring); +int intel_ring_flush_all_caches(struct drm_i915_gem_request *req); int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req); void intel_fini_pipe_control(struct intel_engine_cs *ring); -- GitLab From e85b26dc1ca5ecbf6456c61a131a986a755cbc69 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:56 +0100 Subject: [PATCH 0214/7006] drm/i915: Update switch_mm() to take a request structure Updated the switch_mm() code paths to take a request instead of a ring. This includes the myriad *_mm_switch functions themselves and a bunch of PDP related helper functions. v2: Rebased to newer tree. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_gtt.c | 21 +++++++++++++-------- drivers/gpu/drm/i915/i915_gem_gtt.h | 2 +- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a9dd7e96306e0..a223c9dd16fda 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -652,7 +652,7 @@ static int do_switch(struct drm_i915_gem_request *req) * Register Immediate commands in Ring Buffer before submitting * a context."*/ trace_switch_mm(ring, to); - ret = to->ppgtt->switch_mm(to->ppgtt, ring); + ret = to->ppgtt->switch_mm(to->ppgtt, req); if (ret) goto unpin_out; @@ -703,7 +703,7 @@ static int do_switch(struct drm_i915_gem_request *req) */ if (needs_pd_load_post(ring, to, hw_flags)) { trace_switch_mm(ring, to); - ret = to->ppgtt->switch_mm(to->ppgtt, ring); + ret = to->ppgtt->switch_mm(to->ppgtt, req); /* The hardware context switch is emitted, but we haven't * actually changed the state - so it's probably safe to bail * here. Still, let the user know something dangerous has diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 81ffd70c335e7..5b0f512b1a409 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -452,10 +452,11 @@ free_pd: } /* Broadwell Page Directory Pointer Descriptors */ -static int gen8_write_pdp(struct intel_engine_cs *ring, +static int gen8_write_pdp(struct drm_i915_gem_request *req, unsigned entry, dma_addr_t addr) { + struct intel_engine_cs *ring = req->ring; int ret; BUG_ON(entry >= 4); @@ -476,7 +477,7 @@ static int gen8_write_pdp(struct intel_engine_cs *ring, } static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { int i, ret; @@ -485,7 +486,7 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, dma_addr_t pd_daddr = pd ? pd->daddr : ppgtt->scratch_pd->daddr; /* The page directory might be NULL, but we need to clear out * whatever the previous context might have used. */ - ret = gen8_write_pdp(ring, i, pd_daddr); + ret = gen8_write_pdp(req, i, pd_daddr); if (ret) return ret; } @@ -1062,8 +1063,9 @@ static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) } static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; /* NB: TLBs must be flushed and invalidated before a switch */ @@ -1087,8 +1089,9 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, } static int vgpu_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_i915_private *dev_priv = to_i915(ppgtt->base.dev); I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G); @@ -1097,8 +1100,9 @@ static int vgpu_mm_switch(struct i915_hw_ppgtt *ppgtt, } static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; /* NB: TLBs must be flushed and invalidated before a switch */ @@ -1129,8 +1133,9 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, } static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring) + struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -1582,7 +1587,7 @@ int i915_ppgtt_init_ring(struct drm_i915_gem_request *req) if (!ppgtt) return 0; - return ppgtt->switch_mm(ppgtt, req->ring); + return ppgtt->switch_mm(ppgtt, req); } struct i915_hw_ppgtt * diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 75dfa05d610dc..735f11986ea66 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -338,7 +338,7 @@ struct i915_hw_ppgtt { int (*enable)(struct i915_hw_ppgtt *ppgtt); int (*switch_mm)(struct i915_hw_ppgtt *ppgtt, - struct intel_engine_cs *ring); + struct drm_i915_gem_request *req); void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m); }; -- GitLab From a84c3ae168837dbedd0bde76a536360e84ae863a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:57 +0100 Subject: [PATCH 0215/7006] drm/i915: Update ring->flush() to take a requests structure Updated the various ring->flush() functions to take a request instead of a ring. Also updated the tracer to include the request id. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf [danvet: Rebase since I didn't merge the addition of req->uniq.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++--- drivers/gpu/drm/i915/i915_trace.h | 8 +++--- drivers/gpu/drm/i915/intel_ringbuffer.c | 34 +++++++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 5 files changed, 30 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a223c9dd16fda..c80b59db3c921 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -495,7 +495,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) * itlb_before_ctx_switch. */ if (IS_GEN6(ring->dev)) { - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, 0); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, 0); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 5b0f512b1a409..037f86ed6a8a7 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1069,7 +1069,7 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, int ret; /* NB: TLBs must be flushed and invalidated before a switch */ - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1106,7 +1106,7 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, int ret; /* NB: TLBs must be flushed and invalidated before a switch */ - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1124,7 +1124,7 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, /* XXX: RCS is the only one to auto invalidate the TLBs? */ if (ring->id != RCS) { - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index 497cba5deb1e9..cf58eeb1c2c0c 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -475,8 +475,8 @@ TRACE_EVENT(i915_gem_ring_dispatch, ); TRACE_EVENT(i915_gem_ring_flush, - TP_PROTO(struct intel_engine_cs *ring, u32 invalidate, u32 flush), - TP_ARGS(ring, invalidate, flush), + TP_PROTO(struct drm_i915_gem_request *req, u32 invalidate, u32 flush), + TP_ARGS(req, invalidate, flush), TP_STRUCT__entry( __field(u32, dev) @@ -486,8 +486,8 @@ TRACE_EVENT(i915_gem_ring_flush, ), TP_fast_assign( - __entry->dev = ring->dev->primary->index; - __entry->ring = ring->id; + __entry->dev = req->ring->dev->primary->index; + __entry->ring = req->ring->id; __entry->invalidate = invalidate; __entry->flush = flush; ), diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 48ca73e7aaa6b..2425dc2db42c0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -91,10 +91,11 @@ static void __intel_ring_advance(struct intel_engine_cs *ring) } static int -gen2_render_ring_flush(struct intel_engine_cs *ring, +gen2_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 cmd; int ret; @@ -117,10 +118,11 @@ gen2_render_ring_flush(struct intel_engine_cs *ring, } static int -gen4_render_ring_flush(struct intel_engine_cs *ring, +gen4_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; u32 cmd; int ret; @@ -247,9 +249,10 @@ intel_emit_post_sync_nonzero_flush(struct intel_engine_cs *ring) } static int -gen6_render_ring_flush(struct intel_engine_cs *ring, - u32 invalidate_domains, u32 flush_domains) +gen6_render_ring_flush(struct drm_i915_gem_request *req, + u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 flags = 0; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -318,9 +321,10 @@ gen7_render_ring_cs_stall_wa(struct intel_engine_cs *ring) } static int -gen7_render_ring_flush(struct intel_engine_cs *ring, +gen7_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 flags = 0; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -400,9 +404,10 @@ gen8_emit_pipe_control(struct intel_engine_cs *ring, } static int -gen8_render_ring_flush(struct intel_engine_cs *ring, +gen8_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; u32 flags = 0; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -1594,10 +1599,11 @@ i8xx_ring_put_irq(struct intel_engine_cs *ring) } static int -bsd_ring_flush(struct intel_engine_cs *ring, +bsd_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -2372,9 +2378,10 @@ static void gen6_bsd_ring_write_tail(struct intel_engine_cs *ring, _MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE)); } -static int gen6_bsd_ring_flush(struct intel_engine_cs *ring, +static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, u32 invalidate, u32 flush) { + struct intel_engine_cs *ring = req->ring; uint32_t cmd; int ret; @@ -2484,9 +2491,10 @@ gen6_ring_dispatch_execbuffer(struct intel_engine_cs *ring, /* Blitter support (SandyBridge+) */ -static int gen6_ring_flush(struct intel_engine_cs *ring, +static int gen6_ring_flush(struct drm_i915_gem_request *req, u32 invalidate, u32 flush) { + struct intel_engine_cs *ring = req->ring; struct drm_device *dev = ring->dev; uint32_t cmd; int ret; @@ -2900,11 +2908,11 @@ intel_ring_flush_all_caches(struct drm_i915_gem_request *req) if (!ring->gpu_caches_dirty) return 0; - ret = ring->flush(ring, 0, I915_GEM_GPU_DOMAINS); + ret = ring->flush(req, 0, I915_GEM_GPU_DOMAINS); if (ret) return ret; - trace_i915_gem_ring_flush(ring, 0, I915_GEM_GPU_DOMAINS); + trace_i915_gem_ring_flush(req, 0, I915_GEM_GPU_DOMAINS); ring->gpu_caches_dirty = false; return 0; @@ -2921,11 +2929,11 @@ intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req) if (ring->gpu_caches_dirty) flush_domains = I915_GEM_GPU_DOMAINS; - ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + ret = ring->flush(req, I915_GEM_GPU_DOMAINS, flush_domains); if (ret) return ret; - trace_i915_gem_ring_flush(ring, I915_GEM_GPU_DOMAINS, flush_domains); + trace_i915_gem_ring_flush(req, I915_GEM_GPU_DOMAINS, flush_domains); ring->gpu_caches_dirty = false; return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 3f70687a2dc68..4c0d3296b78f6 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -180,7 +180,7 @@ struct intel_engine_cs { void (*write_tail)(struct intel_engine_cs *ring, u32 value); - int __must_check (*flush)(struct intel_engine_cs *ring, + int __must_check (*flush)(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains); int (*add_request)(struct intel_engine_cs *ring); -- GitLab From f2cf1fcc70d6577dce73f269609e0753e1a99802 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:58 +0100 Subject: [PATCH 0216/7006] drm/i915: Update some flush helpers to take request structures Updated intel_emit_post_sync_nonzero_flush(), gen7_render_ring_cs_stall_wa() and gen8_emit_pipe_control() to take requests instead of rings. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 2425dc2db42c0..e0aa008f05550 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -214,8 +214,9 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, * really our business. That leaves only stall at scoreboard. */ static int -intel_emit_post_sync_nonzero_flush(struct intel_engine_cs *ring) +intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -258,7 +259,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, int ret; /* Force SNB workarounds for PIPE_CONTROL flushes */ - ret = intel_emit_post_sync_nonzero_flush(ring); + ret = intel_emit_post_sync_nonzero_flush(req); if (ret) return ret; @@ -302,8 +303,9 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, } static int -gen7_render_ring_cs_stall_wa(struct intel_engine_cs *ring) +gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 4); @@ -366,7 +368,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, /* Workaround: we must issue a pipe_control with CS-stall bit * set before a pipe_control command that has the state cache * invalidate bit set. */ - gen7_render_ring_cs_stall_wa(ring); + gen7_render_ring_cs_stall_wa(req); } ret = intel_ring_begin(ring, 4); @@ -383,9 +385,10 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, } static int -gen8_emit_pipe_control(struct intel_engine_cs *ring, +gen8_emit_pipe_control(struct drm_i915_gem_request *req, u32 flags, u32 scratch_addr) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 6); @@ -407,9 +410,8 @@ static int gen8_render_ring_flush(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains) { - struct intel_engine_cs *ring = req->ring; u32 flags = 0; - u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; + u32 scratch_addr = req->ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; flags |= PIPE_CONTROL_CS_STALL; @@ -429,7 +431,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req, flags |= PIPE_CONTROL_GLOBAL_GTT_IVB; /* WaCsStallBeforeStateCacheInvalidate:bdw,chv */ - ret = gen8_emit_pipe_control(ring, + ret = gen8_emit_pipe_control(req, PIPE_CONTROL_CS_STALL | PIPE_CONTROL_STALL_AT_SCOREBOARD, 0); @@ -437,7 +439,7 @@ gen8_render_ring_flush(struct drm_i915_gem_request *req, return ret; } - return gen8_emit_pipe_control(ring, flags, scratch_addr); + return gen8_emit_pipe_control(req, flags, scratch_addr); } static void ring_write_tail(struct intel_engine_cs *ring, -- GitLab From 7deb4d3980ea44ebb4097426f85d5f6c89b873a4 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:43:59 +0100 Subject: [PATCH 0217/7006] drm/i915: Update ring->emit_flush() to take a request structure Updated the various ring->emit_flush() implementations to take a request instead of a ringbuf/context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 17 ++++++++--------- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7a18e83623b29..97390fa0684d1 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -614,8 +614,7 @@ static int logical_ring_invalidate_all_caches(struct drm_i915_gem_request *req) if (ring->gpu_caches_dirty) flush_domains = I915_GEM_GPU_DOMAINS; - ret = ring->emit_flush(req->ringbuf, req->ctx, - I915_GEM_GPU_DOMAINS, flush_domains); + ret = ring->emit_flush(req, I915_GEM_GPU_DOMAINS, flush_domains); if (ret) return ret; @@ -1005,7 +1004,7 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) if (!ring->gpu_caches_dirty) return 0; - ret = ring->emit_flush(req->ringbuf, req->ctx, 0, I915_GEM_GPU_DOMAINS); + ret = ring->emit_flush(req, 0, I915_GEM_GPU_DOMAINS); if (ret) return ret; @@ -1420,18 +1419,18 @@ static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring) spin_unlock_irqrestore(&dev_priv->irq_lock, flags); } -static int gen8_emit_flush(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int gen8_emit_flush(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 unused) { + struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *ring = ringbuf->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; uint32_t cmd; int ret; - ret = intel_logical_ring_begin(ringbuf, ctx, 4); + ret = intel_logical_ring_begin(ringbuf, request->ctx, 4); if (ret) return ret; @@ -1461,11 +1460,11 @@ static int gen8_emit_flush(struct intel_ringbuffer *ringbuf, return 0; } -static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int gen8_emit_flush_render(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains) { + struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *ring = ringbuf->ring; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; bool vf_flush_wa; @@ -1497,7 +1496,7 @@ static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf, vf_flush_wa = INTEL_INFO(ring->dev)->gen >= 9 && flags & PIPE_CONTROL_VF_CACHE_INVALIDATE; - ret = intel_logical_ring_begin(ringbuf, ctx, vf_flush_wa ? 12 : 6); + ret = intel_logical_ring_begin(ringbuf, request->ctx, vf_flush_wa ? 12 : 6); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 4c0d3296b78f6..8c713f625755b 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -268,8 +268,7 @@ struct intel_engine_cs { u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ int (*emit_request)(struct intel_ringbuffer *ringbuf, struct drm_i915_gem_request *request); - int (*emit_flush)(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, + int (*emit_flush)(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains); int (*emit_bb_start)(struct intel_ringbuffer *ringbuf, -- GitLab From ee044a8863de58044cb370c23f97b9b68b33e47b Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:00 +0100 Subject: [PATCH 0218/7006] drm/i915: Update ring->add_request() to take a request structure Updated the various ring->add_request() implementations to take a request instead of a ring. This removes their reliance on the OLR to obtain the seqno value that the request should be tagged with. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 26 ++++++++++++------------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 25fe1ef32eaac..6d511d32f72aa 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2524,7 +2524,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, if (i915.enable_execlists) ret = ring->emit_request(ringbuf, request); else { - ret = ring->add_request(ring); + ret = ring->add_request(request); request->tail = intel_ring_get_tail(ringbuf); } diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e0aa008f05550..28d7801a8fa5c 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1288,16 +1288,16 @@ static int gen6_signal(struct intel_engine_cs *signaller, /** * gen6_add_request - Update the semaphore mailbox registers - * - * @ring - ring that is adding a request - * @seqno - return seqno stuck into the ring + * + * @request - request to write to the ring * * Update the mailbox registers in the *other* rings with the current seqno. * This acts like a signal in the canonical semaphore. */ static int -gen6_add_request(struct intel_engine_cs *ring) +gen6_add_request(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; if (ring->semaphore.signal) @@ -1310,8 +1310,7 @@ gen6_add_request(struct intel_engine_cs *ring) intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, MI_USER_INTERRUPT); __intel_ring_advance(ring); @@ -1408,8 +1407,9 @@ do { \ } while (0) static int -pc_render_add_request(struct intel_engine_cs *ring) +pc_render_add_request(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; @@ -1429,8 +1429,7 @@ pc_render_add_request(struct intel_engine_cs *ring) PIPE_CONTROL_WRITE_FLUSH | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, 0); PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */ @@ -1449,8 +1448,7 @@ pc_render_add_request(struct intel_engine_cs *ring) PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | PIPE_CONTROL_NOTIFY); intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, 0); __intel_ring_advance(ring); @@ -1619,8 +1617,9 @@ bsd_ring_flush(struct drm_i915_gem_request *req, } static int -i9xx_add_request(struct intel_engine_cs *ring) +i9xx_add_request(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 4); @@ -1629,8 +1628,7 @@ i9xx_add_request(struct intel_engine_cs *ring) intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); - intel_ring_emit(ring, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_ring_emit(ring, i915_gem_request_get_seqno(req)); intel_ring_emit(ring, MI_USER_INTERRUPT); __intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8c713f625755b..cb6d3d0b25307 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -183,7 +183,7 @@ struct intel_engine_cs { int __must_check (*flush)(struct drm_i915_gem_request *req, u32 invalidate_domains, u32 flush_domains); - int (*add_request)(struct intel_engine_cs *ring); + int (*add_request)(struct drm_i915_gem_request *req); /* Some chipsets are not quite as coherent as advertised and need * an expensive kick to force a true read of the up-to-date seqno. * However, the up-to-date seqno is not always required and the last -- GitLab From c4e766389e8b7ce3ceb7f2785d4bb94b82448ff0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:01 +0100 Subject: [PATCH 0219/7006] drm/i915: Update ring->emit_request() to take a request structure Updated the ring->emit_request() implementation to take a request instead of a ringbuf/request pair. Also removed its use of the OLR for obtaining the request's seqno. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/intel_lrc.c | 7 +++---- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 6d511d32f72aa..339799c5aceb2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2522,7 +2522,7 @@ void __i915_add_request(struct drm_i915_gem_request *request, request->postfix = intel_ring_get_tail(ringbuf); if (i915.enable_execlists) - ret = ring->emit_request(ringbuf, request); + ret = ring->emit_request(request); else { ret = ring->add_request(request); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 97390fa0684d1..9be732b401212 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1530,9 +1530,9 @@ static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno) intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno); } -static int gen8_emit_request(struct intel_ringbuffer *ringbuf, - struct drm_i915_gem_request *request) +static int gen8_emit_request(struct drm_i915_gem_request *request) { + struct intel_ringbuffer *ringbuf = request->ringbuf; struct intel_engine_cs *ring = ringbuf->ring; u32 cmd; int ret; @@ -1554,8 +1554,7 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf, (ring->status_page.gfx_addr + (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT))); intel_logical_ring_emit(ringbuf, 0); - intel_logical_ring_emit(ringbuf, - i915_gem_request_get_seqno(ring->outstanding_lazy_request)); + intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request)); intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); intel_logical_ring_emit(ringbuf, MI_NOOP); intel_logical_ring_advance_and_submit(ringbuf, request->ctx, request); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index cb6d3d0b25307..96b8e353a1f07 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -266,8 +266,7 @@ struct intel_engine_cs { struct list_head execlist_retired_req_list; u8 next_context_status_buffer; u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ - int (*emit_request)(struct intel_ringbuffer *ringbuf, - struct drm_i915_gem_request *request); + int (*emit_request)(struct drm_i915_gem_request *request); int (*emit_flush)(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains); -- GitLab From 53fddaf70d08aa6ff59a94ae0578ddc8743e920f Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:02 +0100 Subject: [PATCH 0220/7006] drm/i915: Update ring->dispatch_execbuffer() to take a request structure Updated the various ring->dispatch_execbuffer() implementations to take a request instead of a ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 ++-- drivers/gpu/drm/i915/i915_gem_render_state.c | 3 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 18 ++++++++++++------ drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 4 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 1cbd6d65dae56..9977c23ab47d9 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1328,14 +1328,14 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (ret) goto error; - ret = ring->dispatch_execbuffer(ring, + ret = ring->dispatch_execbuffer(params->request, exec_start, exec_len, params->dispatch_flags); if (ret) goto error; } } else { - ret = ring->dispatch_execbuffer(ring, + ret = ring->dispatch_execbuffer(params->request, exec_start, exec_len, params->dispatch_flags); if (ret) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index e04cda40df5ef..a0201fc94d256 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -164,8 +164,7 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req) if (so.rodata == NULL) return 0; - ret = req->ring->dispatch_execbuffer(req->ring, - so.ggtt_offset, + ret = req->ring->dispatch_execbuffer(req, so.ggtt_offset, so.rodata->batch_items * 4, I915_DISPATCH_SECURE); if (ret) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 28d7801a8fa5c..44fdfd07d912a 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1760,10 +1760,11 @@ gen8_ring_put_irq(struct intel_engine_cs *ring) } static int -i965_dispatch_execbuffer(struct intel_engine_cs *ring, +i965_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 length, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -1786,10 +1787,11 @@ i965_dispatch_execbuffer(struct intel_engine_cs *ring, #define I830_TLB_ENTRIES (2) #define I830_WA_SIZE max(I830_TLB_ENTRIES*4096, I830_BATCH_LIMIT) static int -i830_dispatch_execbuffer(struct intel_engine_cs *ring, +i830_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; u32 cs_offset = ring->scratch.gtt_offset; int ret; @@ -1848,10 +1850,11 @@ i830_dispatch_execbuffer(struct intel_engine_cs *ring, } static int -i915_dispatch_execbuffer(struct intel_engine_cs *ring, +i915_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -2423,10 +2426,11 @@ static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, } static int -gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring, +gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; bool ppgtt = USES_PPGTT(ring->dev) && !(dispatch_flags & I915_DISPATCH_SECURE); int ret; @@ -2446,10 +2450,11 @@ gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring, } static int -hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring, +hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); @@ -2468,10 +2473,11 @@ hsw_ring_dispatch_execbuffer(struct intel_engine_cs *ring, } static int -gen6_ring_dispatch_execbuffer(struct intel_engine_cs *ring, +gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, u64 offset, u32 len, unsigned dispatch_flags) { + struct intel_engine_cs *ring = req->ring; int ret; ret = intel_ring_begin(ring, 2); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 96b8e353a1f07..bf679ae03aa15 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -194,7 +194,7 @@ struct intel_engine_cs { bool lazy_coherency); void (*set_seqno)(struct intel_engine_cs *ring, u32 seqno); - int (*dispatch_execbuffer)(struct intel_engine_cs *ring, + int (*dispatch_execbuffer)(struct drm_i915_gem_request *req, u64 offset, u32 length, unsigned dispatch_flags); #define I915_DISPATCH_SECURE 0x1 -- GitLab From be795fc17bc9d42b0e5ec3e4442b59848137eb64 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:03 +0100 Subject: [PATCH 0221/7006] drm/i915: Update ring->emit_bb_start() to take a request structure Updated the ring->emit_bb_start() implementation to take a request instead of a ringbuf/context pair. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 12 +++++------- drivers/gpu/drm/i915/intel_ringbuffer.h | 3 +-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9be732b401212..9e99c6226b57e 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -936,7 +936,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, exec_start = params->batch_obj_vm_offset + args->batch_start_offset; - ret = ring->emit_bb_start(ringbuf, params->ctx, exec_start, params->dispatch_flags); + ret = ring->emit_bb_start(params->request, exec_start, params->dispatch_flags); if (ret) return ret; @@ -1365,14 +1365,14 @@ static int gen9_init_render_ring(struct intel_engine_cs *ring) return init_workarounds_ring(ring); } -static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int gen8_emit_bb_start(struct drm_i915_gem_request *req, u64 offset, unsigned dispatch_flags) { + struct intel_ringbuffer *ringbuf = req->ringbuf; bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); int ret; - ret = intel_logical_ring_begin(ringbuf, ctx, 4); + ret = intel_logical_ring_begin(ringbuf, req->ctx, 4); if (ret) return ret; @@ -1582,9 +1582,7 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) if (so.rodata == NULL) return 0; - ret = req->ring->emit_bb_start(req->ringbuf, - req->ctx, - so.ggtt_offset, + ret = req->ring->emit_bb_start(req, so.ggtt_offset, I915_DISPATCH_SECURE); if (ret) goto out; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index bf679ae03aa15..1f11c3236768f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -270,8 +270,7 @@ struct intel_engine_cs { int (*emit_flush)(struct drm_i915_gem_request *request, u32 invalidate_domains, u32 flush_domains); - int (*emit_bb_start)(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, + int (*emit_bb_start)(struct drm_i915_gem_request *req, u64 offset, unsigned dispatch_flags); /** -- GitLab From 599d924c6b01e89b53c7879e7d7d89baa8d677d2 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:04 +0100 Subject: [PATCH 0222/7006] drm/i915: Update ring->sync_to() to take a request structure Updated the ring->sync_to() implementations to take a request instead of a ring. Also updated the tracer to include the request id. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf [danvet: Rebase since I didn't merge the patch which added ->uniq.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 4 ++-- drivers/gpu/drm/i915/i915_trace.h | 8 ++++---- drivers/gpu/drm/i915/intel_ringbuffer.c | 6 ++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ++-- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 339799c5aceb2..ae9e5ecfe34c0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3139,8 +3139,8 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, return ret; } - trace_i915_gem_ring_sync_to(from, to, from_req); - ret = to->semaphore.sync_to(to, from, seqno); + trace_i915_gem_ring_sync_to(*to_req, from, from_req); + ret = to->semaphore.sync_to(*to_req, from, seqno); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h index cf58eeb1c2c0c..63328b6e8ea51 100644 --- a/drivers/gpu/drm/i915/i915_trace.h +++ b/drivers/gpu/drm/i915/i915_trace.h @@ -424,10 +424,10 @@ TRACE_EVENT(i915_gem_evict_vm, ); TRACE_EVENT(i915_gem_ring_sync_to, - TP_PROTO(struct intel_engine_cs *from, - struct intel_engine_cs *to, + TP_PROTO(struct drm_i915_gem_request *to_req, + struct intel_engine_cs *from, struct drm_i915_gem_request *req), - TP_ARGS(from, to, req), + TP_ARGS(to_req, from, req), TP_STRUCT__entry( __field(u32, dev) @@ -439,7 +439,7 @@ TRACE_EVENT(i915_gem_ring_sync_to, TP_fast_assign( __entry->dev = from->dev->primary->index; __entry->sync_from = from->id; - __entry->sync_to = to->id; + __entry->sync_to = to_req->ring->id; __entry->seqno = i915_gem_request_get_seqno(req); ), diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 44fdfd07d912a..eb436a03fae95 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1333,10 +1333,11 @@ static inline bool i915_gem_has_seqno_wrapped(struct drm_device *dev, */ static int -gen8_ring_sync(struct intel_engine_cs *waiter, +gen8_ring_sync(struct drm_i915_gem_request *waiter_req, struct intel_engine_cs *signaller, u32 seqno) { + struct intel_engine_cs *waiter = waiter_req->ring; struct drm_i915_private *dev_priv = waiter->dev->dev_private; int ret; @@ -1358,10 +1359,11 @@ gen8_ring_sync(struct intel_engine_cs *waiter, } static int -gen6_ring_sync(struct intel_engine_cs *waiter, +gen6_ring_sync(struct drm_i915_gem_request *waiter_req, struct intel_engine_cs *signaller, u32 seqno) { + struct intel_engine_cs *waiter = waiter_req->ring; u32 dw1 = MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 1f11c3236768f..6853f8f0ee299 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -252,8 +252,8 @@ struct intel_engine_cs { }; /* AKA wait() */ - int (*sync_to)(struct intel_engine_cs *ring, - struct intel_engine_cs *to, + int (*sync_to)(struct drm_i915_gem_request *to_req, + struct intel_engine_cs *from, u32 seqno); int (*signal)(struct intel_engine_cs *signaller, /* num_dwords needed by caller */ -- GitLab From f71696876a16c3d68d27db71d93f389ae440171c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:05 +0100 Subject: [PATCH 0223/7006] drm/i915: Update ring->signal() to take a request structure Updated the various ring->signal() implementations to take a request instead of a ring. This removes their reliance on the OLR to obtain the seqno value that should be used for the signal. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.c | 20 ++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index eb436a03fae95..e6ef8d7963111 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -1171,10 +1171,11 @@ static void render_ring_cleanup(struct intel_engine_cs *ring) intel_fini_pipe_control(ring); } -static int gen8_rcs_signal(struct intel_engine_cs *signaller, +static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req, unsigned int num_dwords) { #define MBOX_UPDATE_DWORDS 8 + struct intel_engine_cs *signaller = signaller_req->ring; struct drm_device *dev = signaller->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *waiter; @@ -1194,8 +1195,7 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller, if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) continue; - seqno = i915_gem_request_get_seqno( - signaller->outstanding_lazy_request); + seqno = i915_gem_request_get_seqno(signaller_req); intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6)); intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB | PIPE_CONTROL_QW_WRITE | @@ -1212,10 +1212,11 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller, return 0; } -static int gen8_xcs_signal(struct intel_engine_cs *signaller, +static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req, unsigned int num_dwords) { #define MBOX_UPDATE_DWORDS 6 + struct intel_engine_cs *signaller = signaller_req->ring; struct drm_device *dev = signaller->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *waiter; @@ -1235,8 +1236,7 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller, if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID) continue; - seqno = i915_gem_request_get_seqno( - signaller->outstanding_lazy_request); + seqno = i915_gem_request_get_seqno(signaller_req); intel_ring_emit(signaller, (MI_FLUSH_DW + 1) | MI_FLUSH_DW_OP_STOREDW); intel_ring_emit(signaller, lower_32_bits(gtt_offset) | @@ -1251,9 +1251,10 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller, return 0; } -static int gen6_signal(struct intel_engine_cs *signaller, +static int gen6_signal(struct drm_i915_gem_request *signaller_req, unsigned int num_dwords) { + struct intel_engine_cs *signaller = signaller_req->ring; struct drm_device *dev = signaller->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct intel_engine_cs *useless; @@ -1271,8 +1272,7 @@ static int gen6_signal(struct intel_engine_cs *signaller, for_each_ring(useless, dev_priv, i) { u32 mbox_reg = signaller->semaphore.mbox.signal[i]; if (mbox_reg != GEN6_NOSYNC) { - u32 seqno = i915_gem_request_get_seqno( - signaller->outstanding_lazy_request); + u32 seqno = i915_gem_request_get_seqno(signaller_req); intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1)); intel_ring_emit(signaller, mbox_reg); intel_ring_emit(signaller, seqno); @@ -1301,7 +1301,7 @@ gen6_add_request(struct drm_i915_gem_request *req) int ret; if (ring->semaphore.signal) - ret = ring->semaphore.signal(ring, 4); + ret = ring->semaphore.signal(req, 4); else ret = intel_ring_begin(ring, 4); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 6853f8f0ee299..ca04f3f587571 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -255,7 +255,7 @@ struct intel_engine_cs { int (*sync_to)(struct drm_i915_gem_request *to_req, struct intel_engine_cs *from, u32 seqno); - int (*signal)(struct intel_engine_cs *signaller, + int (*signal)(struct drm_i915_gem_request *signaller_req, /* num_dwords needed by caller */ unsigned int num_dwords); } semaphore; -- GitLab From bba09b12b47b31b147206f5784691d2fb8888bf1 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:06 +0100 Subject: [PATCH 0224/7006] drm/i915: Update cacheline_align() to take a request structure Updated intel_ring_cacheline_align() to take a request instead of a ring. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_ringbuffer.c | 3 ++- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7ec2421f0a970..7882820b741a1 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11055,7 +11055,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, * then do the cacheline alignment, and finally emit the * MI_DISPLAY_FLIP. */ - ret = intel_ring_cacheline_align(ring); + ret = intel_ring_cacheline_align(req); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e6ef8d7963111..6a77014e1d667 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2311,8 +2311,9 @@ int intel_ring_begin(struct intel_engine_cs *ring, } /* Align the ring tail to a cacheline boundary */ -int intel_ring_cacheline_align(struct intel_engine_cs *ring) +int intel_ring_cacheline_align(struct drm_i915_gem_request *req) { + struct intel_engine_cs *ring = req->ring; int num_dwords = (ring->buffer->tail & (CACHELINE_BYTES - 1)) / sizeof(uint32_t); int ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index ca04f3f587571..8a5317bba1123 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -422,7 +422,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring); int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request); int __must_check intel_ring_begin(struct intel_engine_cs *ring, int n); -int __must_check intel_ring_cacheline_align(struct intel_engine_cs *ring); +int __must_check intel_ring_cacheline_align(struct drm_i915_gem_request *req); static inline void intel_ring_emit(struct intel_engine_cs *ring, u32 data) { -- GitLab From 5fb9de1a2ea1968b57c906c6770794f1e7744828 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:07 +0100 Subject: [PATCH 0225/7006] drm/i915: Update intel_ring_begin() to take a request structure Now that everything above has been converted to use requests, intel_ring_begin() can be updated to take a request instead of a ring. This also means that it no longer needs to lazily allocate a request if no-one happens to have done it earlier. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 2 +- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 8 +-- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 +- drivers/gpu/drm/i915/intel_display.c | 10 +-- drivers/gpu/drm/i915/intel_overlay.c | 8 +-- drivers/gpu/drm/i915/intel_ringbuffer.c | 74 +++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 2 +- 8 files changed, 55 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index ae9e5ecfe34c0..e7a40f8712bc5 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4894,7 +4894,7 @@ int i915_gem_l3_remap(struct drm_i915_gem_request *req, int slice) if (!HAS_L3_DPF(dev) || !remap_info) return 0; - ret = intel_ring_begin(ring, GEN7_L3LOG_SIZE / 4 * 3); + ret = intel_ring_begin(req, GEN7_L3LOG_SIZE / 4 * 3); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index c80b59db3c921..a7e58a8ae7704 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -509,7 +509,7 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) if (INTEL_INFO(ring->dev)->gen >= 7) len += 2 + (num_rings ? 4*num_rings + 2 : 0); - ret = intel_ring_begin(ring, len); + ret = intel_ring_begin(req, len); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 9977c23ab47d9..6657bb9b2690c 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1082,7 +1082,7 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev, return -EINVAL; } - ret = intel_ring_begin(ring, 4 * 3); + ret = intel_ring_begin(req, 4 * 3); if (ret) return ret; @@ -1113,7 +1113,7 @@ i915_emit_box(struct drm_i915_gem_request *req, } if (INTEL_INFO(ring->dev)->gen >= 4) { - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1122,7 +1122,7 @@ i915_emit_box(struct drm_i915_gem_request *req, intel_ring_emit(ring, ((box->x2 - 1) & 0xffff) | (box->y2 - 1) << 16); intel_ring_emit(ring, DR4); } else { - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1298,7 +1298,7 @@ i915_gem_ringbuffer_submission(struct i915_execbuffer_params *params, if (ring == &dev_priv->ring[RCS] && instp_mode != dev_priv->relative_constants_mode) { - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(params->request, 4); if (ret) goto error; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 037f86ed6a8a7..a8c33f7f922f6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -461,7 +461,7 @@ static int gen8_write_pdp(struct drm_i915_gem_request *req, BUG_ON(entry >= 4); - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1073,7 +1073,7 @@ static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, if (ret) return ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1110,7 +1110,7 @@ static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt, if (ret) return ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7882820b741a1..bd121cd7ca1d6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10876,7 +10876,7 @@ static int intel_gen2_queue_flip(struct drm_device *dev, u32 flip_mask; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -10911,7 +10911,7 @@ static int intel_gen3_queue_flip(struct drm_device *dev, u32 flip_mask; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -10944,7 +10944,7 @@ static int intel_gen4_queue_flip(struct drm_device *dev, uint32_t pf, pipesrc; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -10983,7 +10983,7 @@ static int intel_gen6_queue_flip(struct drm_device *dev, uint32_t pf, pipesrc; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -11059,7 +11059,7 @@ static int intel_gen7_queue_flip(struct drm_device *dev, if (ret) return ret; - ret = intel_ring_begin(ring, len); + ret = intel_ring_begin(req, len); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c index 3f709042b86cf..444542696a2c1 100644 --- a/drivers/gpu/drm/i915/intel_overlay.c +++ b/drivers/gpu/drm/i915/intel_overlay.c @@ -244,7 +244,7 @@ static int intel_overlay_on(struct intel_overlay *overlay) if (ret) return ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) { i915_gem_request_cancel(req); return ret; @@ -287,7 +287,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay, if (ret) return ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) { i915_gem_request_cancel(req); return ret; @@ -353,7 +353,7 @@ static int intel_overlay_off(struct intel_overlay *overlay) if (ret) return ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) { i915_gem_request_cancel(req); return ret; @@ -427,7 +427,7 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay) if (ret) return ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) { i915_gem_request_cancel(req); return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 6a77014e1d667..dfba3ee573827 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -106,7 +106,7 @@ gen2_render_ring_flush(struct drm_i915_gem_request *req, if (invalidate_domains & I915_GEM_DOMAIN_SAMPLER) cmd |= MI_READ_FLUSH; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -165,7 +165,7 @@ gen4_render_ring_flush(struct drm_i915_gem_request *req, (IS_G4X(dev) || IS_GEN5(dev))) cmd |= MI_INVALIDATE_ISP; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -220,8 +220,7 @@ intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req) u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES; int ret; - - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -234,7 +233,7 @@ intel_emit_post_sync_nonzero_flush(struct drm_i915_gem_request *req) intel_ring_emit(ring, MI_NOOP); intel_ring_advance(ring); - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -289,7 +288,7 @@ gen6_render_ring_flush(struct drm_i915_gem_request *req, flags |= PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_CS_STALL; } - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -308,7 +307,7 @@ gen7_render_ring_cs_stall_wa(struct drm_i915_gem_request *req) struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -371,7 +370,7 @@ gen7_render_ring_flush(struct drm_i915_gem_request *req, gen7_render_ring_cs_stall_wa(req); } - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -391,7 +390,7 @@ gen8_emit_pipe_control(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -726,7 +725,7 @@ static int intel_ring_workarounds_emit(struct drm_i915_gem_request *req) if (ret) return ret; - ret = intel_ring_begin(ring, (w->count * 2 + 2)); + ret = intel_ring_begin(req, (w->count * 2 + 2)); if (ret) return ret; @@ -1185,7 +1184,7 @@ static int gen8_rcs_signal(struct drm_i915_gem_request *signaller_req, num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS; #undef MBOX_UPDATE_DWORDS - ret = intel_ring_begin(signaller, num_dwords); + ret = intel_ring_begin(signaller_req, num_dwords); if (ret) return ret; @@ -1226,7 +1225,7 @@ static int gen8_xcs_signal(struct drm_i915_gem_request *signaller_req, num_dwords += (num_rings-1) * MBOX_UPDATE_DWORDS; #undef MBOX_UPDATE_DWORDS - ret = intel_ring_begin(signaller, num_dwords); + ret = intel_ring_begin(signaller_req, num_dwords); if (ret) return ret; @@ -1265,7 +1264,7 @@ static int gen6_signal(struct drm_i915_gem_request *signaller_req, num_dwords += round_up((num_rings-1) * MBOX_UPDATE_DWORDS, 2); #undef MBOX_UPDATE_DWORDS - ret = intel_ring_begin(signaller, num_dwords); + ret = intel_ring_begin(signaller_req, num_dwords); if (ret) return ret; @@ -1303,7 +1302,7 @@ gen6_add_request(struct drm_i915_gem_request *req) if (ring->semaphore.signal) ret = ring->semaphore.signal(req, 4); else - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1341,7 +1340,7 @@ gen8_ring_sync(struct drm_i915_gem_request *waiter_req, struct drm_i915_private *dev_priv = waiter->dev->dev_private; int ret; - ret = intel_ring_begin(waiter, 4); + ret = intel_ring_begin(waiter_req, 4); if (ret) return ret; @@ -1378,7 +1377,7 @@ gen6_ring_sync(struct drm_i915_gem_request *waiter_req, WARN_ON(wait_mbox == MI_SEMAPHORE_SYNC_INVALID); - ret = intel_ring_begin(waiter, 4); + ret = intel_ring_begin(waiter_req, 4); if (ret) return ret; @@ -1423,7 +1422,7 @@ pc_render_add_request(struct drm_i915_gem_request *req) * incoherence by flushing the 6 PIPE_NOTIFY buffers out to * memory before requesting an interrupt. */ - ret = intel_ring_begin(ring, 32); + ret = intel_ring_begin(req, 32); if (ret) return ret; @@ -1608,7 +1607,7 @@ bsd_ring_flush(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -1624,7 +1623,7 @@ i9xx_add_request(struct drm_i915_gem_request *req) struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1769,7 +1768,7 @@ i965_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -1797,7 +1796,7 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req, u32 cs_offset = ring->scratch.gtt_offset; int ret; - ret = intel_ring_begin(ring, 6); + ret = intel_ring_begin(req, 6); if (ret) return ret; @@ -1814,7 +1813,7 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req, if (len > I830_BATCH_LIMIT) return -ENOSPC; - ret = intel_ring_begin(ring, 6 + 2); + ret = intel_ring_begin(req, 6 + 2); if (ret) return ret; @@ -1837,7 +1836,7 @@ i830_dispatch_execbuffer(struct drm_i915_gem_request *req, offset = cs_offset; } - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -1859,7 +1858,7 @@ i915_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -2285,13 +2284,17 @@ static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) return 0; } -int intel_ring_begin(struct intel_engine_cs *ring, +int intel_ring_begin(struct drm_i915_gem_request *req, int num_dwords) { - struct drm_i915_gem_request *req; - struct drm_i915_private *dev_priv = ring->dev->dev_private; + struct intel_engine_cs *ring; + struct drm_i915_private *dev_priv; int ret; + WARN_ON(req == NULL); + ring = req->ring; + dev_priv = ring->dev->dev_private; + ret = i915_gem_check_wedge(&dev_priv->gpu_error, dev_priv->mm.interruptible); if (ret) @@ -2301,11 +2304,6 @@ int intel_ring_begin(struct intel_engine_cs *ring, if (ret) return ret; - /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ring->default_context, &req); - if (ret) - return ret; - ring->buffer->space -= num_dwords * sizeof(uint32_t); return 0; } @@ -2321,7 +2319,7 @@ int intel_ring_cacheline_align(struct drm_i915_gem_request *req) return 0; num_dwords = CACHELINE_BYTES / sizeof(uint32_t) - num_dwords; - ret = intel_ring_begin(ring, num_dwords); + ret = intel_ring_begin(req, num_dwords); if (ret) return ret; @@ -2391,7 +2389,7 @@ static int gen6_bsd_ring_flush(struct drm_i915_gem_request *req, uint32_t cmd; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -2438,7 +2436,7 @@ gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, !(dispatch_flags & I915_DISPATCH_SECURE); int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; @@ -2460,7 +2458,7 @@ hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -2483,7 +2481,7 @@ gen6_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, struct intel_engine_cs *ring = req->ring; int ret; - ret = intel_ring_begin(ring, 2); + ret = intel_ring_begin(req, 2); if (ret) return ret; @@ -2508,7 +2506,7 @@ static int gen6_ring_flush(struct drm_i915_gem_request *req, uint32_t cmd; int ret; - ret = intel_ring_begin(ring, 4); + ret = intel_ring_begin(req, 4); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 8a5317bba1123..00a4ff7593ce7 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -421,7 +421,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring); int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request); -int __must_check intel_ring_begin(struct intel_engine_cs *ring, int n); +int __must_check intel_ring_begin(struct drm_i915_gem_request *req, int n); int __must_check intel_ring_cacheline_align(struct drm_i915_gem_request *req); static inline void intel_ring_emit(struct intel_engine_cs *ring, u32 data) -- GitLab From 4d616a293a1071d19066808abccb40930f0ae5a0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:08 +0100 Subject: [PATCH 0226/7006] drm/i915: Update intel_logical_ring_begin() to take a request structure Now that everything above has been converted to use requests, intel_logical_ring_begin() can be updated to take a request instead of a ringbuf/context pair. This also means that it no longer needs to lazily allocate a request if no-one happens to have done it earlier. Note that this change makes the execlist signature the same as the legacy version. Thus the two functions could be merged into a ring->begin() wrapper if required. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 36 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9e99c6226b57e..ad9db8a79d080 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -801,7 +801,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, /** * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands * - * @ringbuf: Logical ringbuffer. + * @request: The request to start some new work for * @num_dwords: number of DWORDs that we plan to write to the ringbuffer. * * The ringbuffer might not be ready to accept the commands right away (maybe it needs to @@ -811,30 +811,26 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, * * Return: non-zero if the ringbuffer is not ready to be written to. */ -static int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, int num_dwords) +static int intel_logical_ring_begin(struct drm_i915_gem_request *req, + int num_dwords) { - struct drm_i915_gem_request *req; - struct intel_engine_cs *ring = ringbuf->ring; - struct drm_device *dev = ring->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv; int ret; + WARN_ON(req == NULL); + dev_priv = req->ring->dev->dev_private; + ret = i915_gem_check_wedge(&dev_priv->gpu_error, dev_priv->mm.interruptible); if (ret) return ret; - ret = logical_ring_prepare(ringbuf, ctx, num_dwords * sizeof(uint32_t)); - if (ret) - return ret; - - /* Preallocate the olr before touching the ring */ - ret = i915_gem_request_alloc(ring, ctx, &req); + ret = logical_ring_prepare(req->ringbuf, req->ctx, + num_dwords * sizeof(uint32_t)); if (ret) return ret; - ringbuf->space -= num_dwords * sizeof(uint32_t); + req->ringbuf->space -= num_dwords * sizeof(uint32_t); return 0; } @@ -920,7 +916,7 @@ int intel_execlists_submission(struct i915_execbuffer_params *params, if (ring == &dev_priv->ring[RCS] && instp_mode != dev_priv->relative_constants_mode) { - ret = intel_logical_ring_begin(ringbuf, params->ctx, 4); + ret = intel_logical_ring_begin(params->request, 4); if (ret) return ret; @@ -1073,7 +1069,7 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) if (ret) return ret; - ret = intel_logical_ring_begin(ringbuf, req->ctx, w->count * 2 + 2); + ret = intel_logical_ring_begin(req, w->count * 2 + 2); if (ret) return ret; @@ -1372,7 +1368,7 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req, bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); int ret; - ret = intel_logical_ring_begin(ringbuf, req->ctx, 4); + ret = intel_logical_ring_begin(req, 4); if (ret) return ret; @@ -1430,7 +1426,7 @@ static int gen8_emit_flush(struct drm_i915_gem_request *request, uint32_t cmd; int ret; - ret = intel_logical_ring_begin(ringbuf, request->ctx, 4); + ret = intel_logical_ring_begin(request, 4); if (ret) return ret; @@ -1496,7 +1492,7 @@ static int gen8_emit_flush_render(struct drm_i915_gem_request *request, vf_flush_wa = INTEL_INFO(ring->dev)->gen >= 9 && flags & PIPE_CONTROL_VF_CACHE_INVALIDATE; - ret = intel_logical_ring_begin(ringbuf, request->ctx, vf_flush_wa ? 12 : 6); + ret = intel_logical_ring_begin(request, vf_flush_wa ? 12 : 6); if (ret) return ret; @@ -1542,7 +1538,7 @@ static int gen8_emit_request(struct drm_i915_gem_request *request) * used as a workaround for not being allowed to do lite * restore with HEAD==TAIL (WaIdleLiteRestore). */ - ret = intel_logical_ring_begin(ringbuf, request->ctx, 8); + ret = intel_logical_ring_begin(request, 8); if (ret) return ret; -- GitLab From ccd98fe4996cd22094cde7b6a1f7c569f261b3e9 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:09 +0100 Subject: [PATCH 0227/7006] drm/i915: Add *_ring_begin() to request allocation Now that the *_ring_begin() functions no longer call the request allocation code, it is finally safe for the request allocation code to call *_ring_begin(). This is important to guarantee that the space reserved for the subsequent i915_add_request() call does actually get reserved. v2: Renamed functions according to review feedback (Tomas Elf). For: VIZ-5115 Signed-off-by: John Harrison Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 25 +++++++++++---------- drivers/gpu/drm/i915/intel_lrc.c | 15 +++++++++++++ drivers/gpu/drm/i915/intel_lrc.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 29 ++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 5 files changed, 46 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index e7a40f8712bc5..0af4960d141c2 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2679,19 +2679,20 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, * i915_add_request() call can't fail. Note that the reserve may need * to be redone if the request is not actually submitted straight * away, e.g. because a GPU scheduler has deferred it. - * - * Note further that this call merely notes the reserve request. A - * subsequent call to *_ring_begin() is required to actually ensure - * that the reservation is available. Without the begin, if the - * request creator immediately submitted the request without adding - * any commands to it then there might not actually be sufficient - * room for the submission commands. Unfortunately, the current - * *_ring_begin() implementations potentially call back here to - * i915_gem_request_alloc(). Thus calling _begin() here would lead to - * infinite recursion! Until that back call path is removed, it is - * necessary to do a manual _begin() outside. */ - intel_ring_reserved_space_reserve(req->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + if (i915.enable_execlists) + ret = intel_logical_ring_reserve_space(req); + else + ret = intel_ring_reserve_space(req); + if (ret) { + /* + * At this point, the request is fully allocated even if not + * fully prepared. Thus it can be cleaned up using the proper + * free code. + */ + i915_gem_request_cancel(req); + return ret; + } *req_out = ring->outstanding_lazy_request = req; return 0; diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index ad9db8a79d080..75c3b9dfec9eb 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -834,6 +834,21 @@ static int intel_logical_ring_begin(struct drm_i915_gem_request *req, return 0; } +int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request) +{ + /* + * The first call merely notes the reserve request and is common for + * all back ends. The subsequent localised _begin() call actually + * ensures that the reservation is available. Without the begin, if + * the request creator immediately submitted the request without + * adding any commands to it then there might not actually be + * sufficient room for the submission commands. + */ + intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + + return intel_logical_ring_begin(request, 0); +} + /** * execlists_submission() - submit a batchbuffer for execution, Execlists style * @dev: DRM device. diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 044c0e5c72e5f..f59940ac1cfc7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -37,6 +37,7 @@ /* Logical Rings */ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request); +int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request); void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index dfba3ee573827..a378360d0461e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2202,24 +2202,27 @@ int intel_ring_alloc_request_extras(struct drm_i915_gem_request *request) return 0; } +int intel_ring_reserve_space(struct drm_i915_gem_request *request) +{ + /* + * The first call merely notes the reserve request and is common for + * all back ends. The subsequent localised _begin() call actually + * ensures that the reservation is available. Without the begin, if + * the request creator immediately submitted the request without + * adding any commands to it then there might not actually be + * sufficient room for the submission commands. + */ + intel_ring_reserved_space_reserve(request->ringbuf, MIN_SPACE_FOR_ADD_REQUEST); + + return intel_ring_begin(request, 0); +} + void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size) { - /* NB: Until request management is fully tidied up and the OLR is - * removed, there are too many ways for get false hits on this - * anti-recursion check! */ - /*WARN_ON(ringbuf->reserved_size);*/ + WARN_ON(ringbuf->reserved_size); WARN_ON(ringbuf->reserved_in_use); ringbuf->reserved_size = size; - - /* - * Really need to call _begin() here but that currently leads to - * recursion problems! This will be fixed later but for now just - * return and hope for the best. Note that there is only a real - * problem if the create of the request never actually calls _begin() - * but if they are not submitting any work then why did they create - * the request in the first place? - */ } void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 00a4ff7593ce7..0f12020b54e9e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -484,6 +484,7 @@ intel_ring_get_request(struct intel_engine_cs *ring) * will always have sufficient room to do its stuff. The request creation * code calls this automatically. */ +int intel_ring_reserve_space(struct drm_i915_gem_request *request); void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size); /* Cancel the reservation, e.g. because the request is being discarded. */ void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf); -- GitLab From 59c35a4d120ef5e34e91f2bccdfcf9e27a3b9397 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:10 +0100 Subject: [PATCH 0228/7006] drm/i915: Remove the now obsolete intel_ring_get_request() Much of the driver has now been converted to passing requests around instead of rings/ringbufs/contexts. Thus the function for retreiving the request from a ring (i.e. the OLR) is no longer used and can be removed. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ringbuffer.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 0f12020b54e9e..d2cf4d92efc93 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -463,13 +463,6 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf) return ringbuf->tail; } -static inline struct drm_i915_gem_request * -intel_ring_get_request(struct intel_engine_cs *ring) -{ - BUG_ON(ring->outstanding_lazy_request == NULL); - return ring->outstanding_lazy_request; -} - /* * Arbitrary size for largest possible 'add request' sequence. The code paths * are complex and variable. Empirical measurement shows that the worst case -- GitLab From bccca494f75cbad4ea2d09e8205cab09ee610f6a Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:11 +0100 Subject: [PATCH 0229/7006] drm/i915: Remove the now obsolete 'outstanding_lazy_request' The outstanding_lazy_request is no longer used anywhere in the driver. Everything that was looking at it now has a request explicitly passed in from on high. Everything that was relying upon it behind the scenes is now explicitly creating/passing/submitting its own private request. Thus the OLR can be removed. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 16 ++-------------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 4 +--- drivers/gpu/drm/i915/intel_lrc.c | 1 - drivers/gpu/drm/i915/intel_ringbuffer.c | 8 -------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 ---- 5 files changed, 3 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 0af4960d141c2..d1193dcb87291 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1157,9 +1157,6 @@ i915_gem_check_olr(struct drm_i915_gem_request *req) { WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); - if (req == req->ring->outstanding_lazy_request) - i915_add_request(req); - return 0; } @@ -2488,8 +2485,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, dev_priv = ring->dev->dev_private; ringbuf = request->ringbuf; - WARN_ON(request != ring->outstanding_lazy_request); - /* * To ensure that this call will not fail, space for its emissions * should already have been reserved in the ring buffer. Let the ring @@ -2558,7 +2553,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, } trace_i915_gem_request_add(request); - ring->outstanding_lazy_request = NULL; i915_queue_hangcheck(ring->dev); @@ -2647,8 +2641,7 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, if (!req_out) return -EINVAL; - if ((*req_out = ring->outstanding_lazy_request) != NULL) - return 0; + *req_out = NULL; req = kmem_cache_zalloc(dev_priv->requests, GFP_KERNEL); if (req == NULL) @@ -2694,7 +2687,7 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, return ret; } - *req_out = ring->outstanding_lazy_request = req; + *req_out = req; return 0; err: @@ -2791,9 +2784,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, i915_gem_request_retire(request); } - - /* This may not have been flushed before the reset, so clean it now */ - i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); } void i915_gem_restore_fences(struct drm_device *dev) @@ -3344,8 +3334,6 @@ int i915_gpu_idle(struct drm_device *dev) i915_add_request_no_flush(req); } - WARN_ON(ring->outstanding_lazy_request); - ret = intel_ring_idle(ring); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 6657bb9b2690c..3aa2358c2b935 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1655,10 +1655,8 @@ err: * must be freed again. If it was submitted then it is being tracked * on the active request list and no clean up is required here. */ - if (ret && params->request) { + if (ret && params->request) i915_gem_request_cancel(params->request); - ring->outstanding_lazy_request = NULL; - } mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 75c3b9dfec9eb..44568839103ab 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1633,7 +1633,6 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring) intel_logical_ring_stop(ring); WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0); - i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); if (ring->cleanup) ring->cleanup(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index a378360d0461e..af7c12ed0ba7d 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2101,7 +2101,6 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring) intel_unpin_ringbuffer_obj(ringbuf); intel_destroy_ringbuffer_obj(ringbuf); - i915_gem_request_assign(&ring->outstanding_lazy_request, NULL); if (ring->cleanup) ring->cleanup(ring); @@ -2176,11 +2175,6 @@ int intel_ring_idle(struct intel_engine_cs *ring) { struct drm_i915_gem_request *req; - /* We need to add any requests required to flush the objects and ring */ - WARN_ON(ring->outstanding_lazy_request); - if (ring->outstanding_lazy_request) - i915_add_request(ring->outstanding_lazy_request); - /* Wait upon the last request to be completed */ if (list_empty(&ring->request_list)) return 0; @@ -2339,8 +2333,6 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno) struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - BUG_ON(ring->outstanding_lazy_request); - if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) { I915_WRITE(RING_SYNC_0(ring->mmio_base), 0); I915_WRITE(RING_SYNC_1(ring->mmio_base), 0); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index d2cf4d92efc93..0e2bbc6a3f8b0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -291,10 +291,6 @@ struct intel_engine_cs { */ struct list_head request_list; - /** - * Do we have some not yet emitted requests outstanding? - */ - struct drm_i915_gem_request *outstanding_lazy_request; bool gpu_caches_dirty; wait_queue_head_t irq_queue; -- GitLab From fcfa423cbba268b1473e2d8c38fe6dbe65da88ea Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:12 +0100 Subject: [PATCH 0230/7006] drm/i915: Move the request/file and request/pid association to creation time In _i915_add_request(), the request is associated with a userland client. Specifically it is linked to the 'file' structure and the current user process is recorded. One problem here is that the current user process is not necessarily the same as when the request was submitted to the driver. This is especially true when the GPU scheduler arrives and decouples driver submission from hardware submission. Note also that it is only in the case where the add request comes from an execbuff call that there is a client to associate. Any other add request call is kernel only so does not need to do it. This patch moves the client association into a separate function. This is then called from the execbuffer code path itself at a sensible time. It also removes the now redundant 'file' pointer from the add request parameter list. An extra cleanup of the client association is also added to the request clean up code for the eventuality where the request is killed after association but before being submitted (e.g. due to out of memory error somewhere). Once the submission has happened, the request is on the request list and the regular request list removal will clear the association. Note that this still needs to happen at this point in time because the request might be kept floating around much longer (due to someone holding a reference count) and the client should not be worrying about this request after it has been retired. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +-- drivers/gpu/drm/i915/i915_gem.c | 56 +++++++++++++++------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 6 ++- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 5aea6ddd50915..7d7339c8ec963 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2212,6 +2212,8 @@ int i915_gem_request_alloc(struct intel_engine_cs *ring, struct drm_i915_gem_request **req_out); void i915_gem_request_cancel(struct drm_i915_gem_request *req); void i915_gem_request_free(struct kref *req_ref); +int i915_gem_request_add_to_client(struct drm_i915_gem_request *req, + struct drm_file *file); static inline uint32_t i915_gem_request_get_seqno(struct drm_i915_gem_request *req) @@ -2891,13 +2893,12 @@ void i915_gem_cleanup_ringbuffer(struct drm_device *dev); int __must_check i915_gpu_idle(struct drm_device *dev); int __must_check i915_gem_suspend(struct drm_device *dev); void __i915_add_request(struct drm_i915_gem_request *req, - struct drm_file *file, struct drm_i915_gem_object *batch_obj, bool flush_caches); #define i915_add_request(req) \ - __i915_add_request(req, NULL, NULL, true) + __i915_add_request(req, NULL, true) #define i915_add_request_no_flush(req) \ - __i915_add_request(req, NULL, NULL, false) + __i915_add_request(req, NULL, false) int __i915_wait_request(struct drm_i915_gem_request *req, unsigned reset_counter, bool interruptible, diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d1193dcb87291..10832c05e96d8 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1331,6 +1331,33 @@ out: return ret; } +int i915_gem_request_add_to_client(struct drm_i915_gem_request *req, + struct drm_file *file) +{ + struct drm_i915_private *dev_private; + struct drm_i915_file_private *file_priv; + + WARN_ON(!req || !file || req->file_priv); + + if (!req || !file) + return -EINVAL; + + if (req->file_priv) + return -EINVAL; + + dev_private = req->ring->dev->dev_private; + file_priv = file->driver_priv; + + spin_lock(&file_priv->mm.lock); + req->file_priv = file_priv; + list_add_tail(&req->client_list, &file_priv->mm.request_list); + spin_unlock(&file_priv->mm.lock); + + req->pid = get_pid(task_pid(current)); + + return 0; +} + static inline void i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) { @@ -1343,6 +1370,9 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request) list_del(&request->client_list); request->file_priv = NULL; spin_unlock(&file_priv->mm.lock); + + put_pid(request->pid); + request->pid = NULL; } static void i915_gem_request_retire(struct drm_i915_gem_request *request) @@ -1362,8 +1392,6 @@ static void i915_gem_request_retire(struct drm_i915_gem_request *request) list_del_init(&request->list); i915_gem_request_remove_from_client(request); - put_pid(request->pid); - i915_gem_request_unreference(request); } @@ -2468,7 +2496,6 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno) * going to happen on the hardware. This would be a Bad Thing(tm). */ void __i915_add_request(struct drm_i915_gem_request *request, - struct drm_file *file, struct drm_i915_gem_object *obj, bool flush_caches) { @@ -2538,19 +2565,6 @@ void __i915_add_request(struct drm_i915_gem_request *request, request->emitted_jiffies = jiffies; list_add_tail(&request->list, &ring->request_list); - request->file_priv = NULL; - - if (file) { - struct drm_i915_file_private *file_priv = file->driver_priv; - - spin_lock(&file_priv->mm.lock); - request->file_priv = file_priv; - list_add_tail(&request->client_list, - &file_priv->mm.request_list); - spin_unlock(&file_priv->mm.lock); - - request->pid = get_pid(task_pid(current)); - } trace_i915_gem_request_add(request); @@ -2616,6 +2630,9 @@ void i915_gem_request_free(struct kref *req_ref) typeof(*req), ref); struct intel_context *ctx = req->ctx; + if (req->file_priv) + i915_gem_request_remove_from_client(req); + if (ctx) { if (i915.enable_execlists) { struct intel_engine_cs *ring = req->ring; @@ -4314,6 +4331,13 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file) if (time_after_eq(request->emitted_jiffies, recent_enough)) break; + /* + * Note that the request might not have been submitted yet. + * In which case emitted_jiffies will be zero. + */ + if (!request->emitted_jiffies) + continue; + target = request; } reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter); diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 3aa2358c2b935..600db7441847b 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1066,7 +1066,7 @@ i915_gem_execbuffer_retire_commands(struct i915_execbuffer_params *params) params->ring->gpu_caches_dirty = true; /* Add a breadcrumb for the completion of the batch buffer */ - __i915_add_request(params->request, params->file, params->batch_obj, true); + __i915_add_request(params->request, params->batch_obj, true); } static int @@ -1620,6 +1620,10 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, if (ret) goto err_batch_unpin; + ret = i915_gem_request_add_to_client(params->request, file); + if (ret) + goto err_batch_unpin; + /* * Save assorted stuff away to pass through to *_submission(). * NB: This data should be 'persistent' and not local as it will -- GitLab From 9bb1af4406f475e6b68aa53c6227b98aed56d11d Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:13 +0100 Subject: [PATCH 0231/7006] drm/i915: Remove 'faked' request from LRC submission The LRC submission code requires a request for tracking purposes. It does not actually require that request to 'complete' it simply uses it for keeping hold of reference counts on contexts and such like. Previously, the fall back path of polling for space in the ring would start by submitting any outstanding work that was sat in the buffer. This submission was not done as part of the request that that work was owned by because that would lead to complications with the request being submitted twice. Instead, a null request structure was passed in to the submit call and a fake one was created. That fall back path has long since been obsoleted and has now been removed. Thus there is never any need to fake up a request structure. This patch removes that code. A couple of sanity check warnings are added as well, just in case. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Thomas Daniel Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 44568839103ab..a40ca1f5965be 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -555,22 +555,11 @@ static int execlists_context_queue(struct intel_engine_cs *ring, if (to != ring->default_context) intel_lr_context_pin(ring, to); - if (!request) { - /* - * If there isn't a request associated with this submission, - * create one as a temporary holder. - */ - request = kzalloc(sizeof(*request), GFP_KERNEL); - if (request == NULL) - return -ENOMEM; - request->ring = ring; - request->ctx = to; - kref_init(&request->ref); - i915_gem_context_reference(request->ctx); - } else { - i915_gem_request_reference(request); - WARN_ON(to != request->ctx); - } + WARN_ON(!request); + WARN_ON(to != request->ctx); + + i915_gem_request_reference(request); + request->tail = tail; spin_lock_irq(&ring->execlist_lock); -- GitLab From ae70797d8d28d01e6354961e76f56112dae09052 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:14 +0100 Subject: [PATCH 0232/7006] drm/i915: Update a bunch of LRC functions to take requests A bunch of the low level LRC functions were passing around ringbuf and ctx pairs. In a few cases, they took the r/c pair and a request as well. This is all quite messy and unnecesary. The context_queue() call is especially bad since the fake request code got removed - it takes a request and three extra things that must be extracted from the request and then it checks them against what it finds in the request. Removing all the derivable data makes the code much simpler all round. This patch updates those functions to just take the request structure. Note that logical_ring_wait_for_space now takes a request structure but already had a local request pointer that it uses to scan for something to wait on. To avoid confusion the local variable has been renamed 'target' (it is searching for a target request to do something with) and the parameter has been called req (to guarantee anything accidentally missed gets a compiler error). v2: Updated commit message re wait_for_space (Tomas Elf review comment). For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 66 ++++++++++++++------------------ 1 file changed, 29 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a40ca1f5965be..045c99220184a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -544,23 +544,18 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) ((u32)ring->next_context_status_buffer & 0x07) << 8); } -static int execlists_context_queue(struct intel_engine_cs *ring, - struct intel_context *to, - u32 tail, - struct drm_i915_gem_request *request) +static int execlists_context_queue(struct drm_i915_gem_request *request) { + struct intel_engine_cs *ring = request->ring; struct drm_i915_gem_request *cursor; int num_elements = 0; - if (to != ring->default_context) - intel_lr_context_pin(ring, to); - - WARN_ON(!request); - WARN_ON(to != request->ctx); + if (request->ctx != ring->default_context) + intel_lr_context_pin(ring, request->ctx); i915_gem_request_reference(request); - request->tail = tail; + request->tail = request->ringbuf->tail; spin_lock_irq(&ring->execlist_lock); @@ -575,7 +570,7 @@ static int execlists_context_queue(struct intel_engine_cs *ring, struct drm_i915_gem_request, execlist_link); - if (to == tail_req->ctx) { + if (request->ctx == tail_req->ctx) { WARN(tail_req->elsp_submitted != 0, "More than 2 already-submitted reqs queued\n"); list_del(&tail_req->execlist_link); @@ -659,12 +654,12 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request return 0; } -static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, +static int logical_ring_wait_for_space(struct drm_i915_gem_request *req, int bytes) { - struct intel_engine_cs *ring = ringbuf->ring; - struct drm_i915_gem_request *request; + struct intel_ringbuffer *ringbuf = req->ringbuf; + struct intel_engine_cs *ring = req->ring; + struct drm_i915_gem_request *target; unsigned space; int ret; @@ -674,26 +669,26 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, if (intel_ring_space(ringbuf) >= bytes) return 0; - list_for_each_entry(request, &ring->request_list, list) { + list_for_each_entry(target, &ring->request_list, list) { /* * The request queue is per-engine, so can contain requests * from multiple ringbuffers. Here, we must ignore any that * aren't from the ringbuffer we're considering. */ - if (request->ringbuf != ringbuf) + if (target->ringbuf != ringbuf) continue; /* Would completion of this request free enough space? */ - space = __intel_ring_space(request->postfix, ringbuf->tail, + space = __intel_ring_space(target->postfix, ringbuf->tail, ringbuf->size); if (space >= bytes) break; } - if (WARN_ON(&request->list == &ring->request_list)) + if (WARN_ON(&target->list == &ring->request_list)) return -ENOSPC; - ret = i915_wait_request(request); + ret = i915_wait_request(target); if (ret) return ret; @@ -703,7 +698,7 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, /* * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload - * @ringbuf: Logical Ringbuffer to advance. + * @request: Request to advance the logical ringbuffer of. * * The tail is updated in our logical ringbuffer struct, not in the actual context. What * really happens during submission is that the context and current tail will be placed @@ -711,23 +706,21 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf, * point, the tail *inside* the context is updated and the ELSP written to. */ static void -intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, - struct drm_i915_gem_request *request) +intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) { - struct intel_engine_cs *ring = ringbuf->ring; + struct intel_engine_cs *ring = request->ring; - intel_logical_ring_advance(ringbuf); + intel_logical_ring_advance(request->ringbuf); if (intel_ring_stopped(ring)) return; - execlists_context_queue(ring, ctx, ringbuf->tail, request); + execlists_context_queue(request); } -static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx) +static int logical_ring_wrap_buffer(struct drm_i915_gem_request *req) { + struct intel_ringbuffer *ringbuf = req->ringbuf; uint32_t __iomem *virt; int rem = ringbuf->size - ringbuf->tail; @@ -735,7 +728,7 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, WARN_ON(ringbuf->reserved_in_use); if (ringbuf->space < rem) { - int ret = logical_ring_wait_for_space(ringbuf, ctx, rem); + int ret = logical_ring_wait_for_space(req, rem); if (ret) return ret; @@ -752,9 +745,9 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf, return 0; } -static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, - struct intel_context *ctx, int bytes) +static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) { + struct intel_ringbuffer *ringbuf = req->ringbuf; int ret; /* @@ -766,7 +759,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, bytes += ringbuf->reserved_size; if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { - ret = logical_ring_wrap_buffer(ringbuf, ctx); + ret = logical_ring_wrap_buffer(req); if (unlikely(ret)) return ret; @@ -779,7 +772,7 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, } if (unlikely(ringbuf->space < bytes)) { - ret = logical_ring_wait_for_space(ringbuf, ctx, bytes); + ret = logical_ring_wait_for_space(req, bytes); if (unlikely(ret)) return ret; } @@ -814,8 +807,7 @@ static int intel_logical_ring_begin(struct drm_i915_gem_request *req, if (ret) return ret; - ret = logical_ring_prepare(req->ringbuf, req->ctx, - num_dwords * sizeof(uint32_t)); + ret = logical_ring_prepare(req, num_dwords * sizeof(uint32_t)); if (ret) return ret; @@ -1557,7 +1549,7 @@ static int gen8_emit_request(struct drm_i915_gem_request *request) intel_logical_ring_emit(ringbuf, i915_gem_request_get_seqno(request)); intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT); intel_logical_ring_emit(ringbuf, MI_NOOP); - intel_logical_ring_advance_and_submit(ringbuf, request->ctx, request); + intel_logical_ring_advance_and_submit(request); /* * Here we add two extra NOOPs as padding to avoid -- GitLab From a5ac0f907d5b713a89c960605f36c0ccb436022c Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 29 May 2015 17:44:15 +0100 Subject: [PATCH 0233/7006] drm/i915: Remove the now obsolete 'i915_gem_check_olr()' As there is no OLR to check, the check_olr() function is now a no-op and can be removed. For: VIZ-5115 Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_gem.c | 34 +--------------------------- drivers/gpu/drm/i915/intel_display.c | 6 ----- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7d7339c8ec963..92a38ff365e05 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2852,7 +2852,6 @@ bool i915_gem_retire_requests(struct drm_device *dev); void i915_gem_retire_requests_ring(struct intel_engine_cs *ring); int __must_check i915_gem_check_wedge(struct i915_gpu_error *error, bool interruptible); -int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req); static inline bool i915_reset_in_progress(struct i915_gpu_error *error) { diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 10832c05e96d8..f79ce9f223120 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1149,17 +1149,6 @@ i915_gem_check_wedge(struct i915_gpu_error *error, return 0; } -/* - * Compare arbitrary request against outstanding lazy request. Emit on match. - */ -int -i915_gem_check_olr(struct drm_i915_gem_request *req) -{ - WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex)); - - return 0; -} - static void fake_irq(unsigned long data) { wake_up_process((struct task_struct *)data); @@ -1440,10 +1429,6 @@ i915_wait_request(struct drm_i915_gem_request *req) if (ret) return ret; - ret = i915_gem_check_olr(req); - if (ret) - return ret; - ret = __i915_wait_request(req, atomic_read(&dev_priv->gpu_error.reset_counter), interruptible, NULL, NULL); @@ -1543,10 +1528,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (req == NULL) return 0; - ret = i915_gem_check_olr(req); - if (ret) - goto err; - requests[n++] = i915_gem_request_reference(req); } else { for (i = 0; i < I915_NUM_RINGS; i++) { @@ -1556,10 +1537,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, if (req == NULL) continue; - ret = i915_gem_check_olr(req); - if (ret) - goto err; - requests[n++] = i915_gem_request_reference(req); } } @@ -1570,7 +1547,6 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj, NULL, rps); mutex_lock(&dev->struct_mutex); -err: for (i = 0; i < n; i++) { if (ret == 0) i915_gem_object_retire_request(obj, requests[i]); @@ -2983,7 +2959,7 @@ i915_gem_idle_work_handler(struct work_struct *work) static int i915_gem_object_flush_active(struct drm_i915_gem_object *obj) { - int ret, i; + int i; if (!obj->active) return 0; @@ -2998,10 +2974,6 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj) if (list_empty(&req->list)) goto retire; - ret = i915_gem_check_olr(req); - if (ret) - return ret; - if (i915_gem_request_completed(req, true)) { __i915_gem_request_retire__upto(req); retire: @@ -3117,10 +3089,6 @@ __i915_gem_object_sync(struct drm_i915_gem_object *obj, if (i915_gem_request_completed(from_req, true)) return 0; - ret = i915_gem_check_olr(from_req); - if (ret) - return ret; - if (!i915_semaphore_is_enabled(obj->base.dev)) { struct drm_i915_private *i915 = to_i915(obj->base.dev); ret = __i915_wait_request(from_req, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bd121cd7ca1d6..1bc217ab3592a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11476,12 +11476,6 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_request_assign(&work->flip_queued_req, obj->last_write_req); } else { - if (obj->last_write_req) { - ret = i915_gem_check_olr(obj->last_write_req); - if (ret) - goto cleanup_unpin; - } - if (!request) { ret = i915_gem_request_alloc(ring, ring->default_context, &request); if (ret) -- GitLab From 4d78c8dcf9f856587fb7bf664021d9fb699012d9 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 23 Jun 2015 15:50:43 +0100 Subject: [PATCH 0234/7006] drm/i915: Fix warnings reported by 0-day Kernel 0-day framework reported warnings with WA batch patches, this patch fixes those warnings and an additional warning reported in intel_lrc.c file. Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 045c99220184a..8d1c66debb2b0 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -784,6 +784,7 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands * * @request: The request to start some new work for + * @ctx: Logical ring context whose ringbuffer is being prepared. * @num_dwords: number of DWORDs that we plan to write to the ringbuffer. * * The ringbuffer might not be ready to accept the commands right away (maybe it needs to @@ -1132,7 +1133,7 @@ static inline int wa_ctx_end(struct i915_wa_ctx_bb *wa_ctx, * * The number of WA applied are not known at the beginning; we use this field * to return the no of DWORDS written. - + * * It is to be noted that this batch does not contain MI_BATCH_BUFFER_END * so it adds NOOPs as padding to make it cacheline aligned. * MI_BATCH_BUFFER_END will be added to perctx batch and both of them together @@ -1194,6 +1195,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, * @wa_ctx: structure representing wa_ctx * offset: specifies start of the batch, should be cache-aligned. * size: size of the batch in DWORDS but HW expects in terms of cachelines + * @batch: page in which WA are loaded * @offset: This field specifies the start of this batch. * This batch is started immediately after indirect_ctx batch. Since we ensure * that indirect_ctx ends on a cacheline this batch is aligned automatically. -- GitLab From 5e60d790714bbda0402ddd715aee5e61b48682f4 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 23 Jun 2015 15:50:44 +0100 Subject: [PATCH 0235/7006] drm/i915: Bail out early if WA batch is not available for given Gen To initialize WA batch, at the moment we first allocate batch and then check whether we have any WA to be initialized for the given Gen; if we don't have any WA then we WARN the user, destroy the batch and return but this is causing another WARN in cleanup code complaining about sleeping in atomic context. Till we understand this better and to keep things simpler, bail out early if we don't have WA. Cc: Tvrtko Ursulin Cc: Chris Wilson Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8d1c66debb2b0..500ae5139f517 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1260,6 +1260,12 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); + /* update this when WA for higher Gen are added */ + if (WARN(INTEL_INFO(ring->dev)->gen > 8, + "WA batch buffer is not initialized for Gen%d\n", + INTEL_INFO(ring->dev)->gen)) + return 0; + /* some WA perform writes to scratch page, ensure it is valid */ if (ring->scratch.obj == NULL) { DRM_ERROR("scratch page not allocated for %s\n", ring->name); @@ -1290,11 +1296,6 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) &offset); if (ret) goto out; - } else { - WARN(INTEL_INFO(ring->dev)->gen >= 8, - "WA batch buffer is not initialized for Gen%d\n", - INTEL_INFO(ring->dev)->gen); - lrc_destroy_wa_ctx_obj(ring); } out: -- GitLab From 392d39cfcaa9bcfa202fb0fd3bc65f3c20de318f Mon Sep 17 00:00:00 2001 From: Han Xu Date: Wed, 13 May 2015 14:40:57 -0500 Subject: [PATCH 0236/7006] mtd: fsl-quadspi: Access multiple chips simultaneously Add supports for simultaneous access to multiple chips. Need to lock the mutex before any quad spi operations and unlock the mutex after operations complete. Signed-off-by: Han Xu [Brian: reworked err path in fsl_qspi_prep()] Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 32 ++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 52a872fa1b6e4..4fe13dd535f8b 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -26,6 +26,7 @@ #include #include #include +#include /* The registers */ #define QUADSPI_MCR 0x00 @@ -233,6 +234,7 @@ struct fsl_qspi { u32 clk_rate; unsigned int chip_base_addr; /* We may support two chips. */ bool has_second_chip; + struct mutex lock; }; static inline int is_vybrid_qspi(struct fsl_qspi *q) @@ -761,18 +763,24 @@ static int fsl_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops) struct fsl_qspi *q = nor->priv; int ret; + mutex_lock(&q->lock); ret = clk_enable(q->clk_en); if (ret) - return ret; + goto err_mutex; ret = clk_enable(q->clk); - if (ret) { - clk_disable(q->clk_en); - return ret; - } + if (ret) + goto err_clk; fsl_qspi_set_base_addr(q, nor); return 0; + +err_clk: + clk_disable(q->clk_en); +err_mutex: + mutex_unlock(&q->lock); + + return ret; } static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) @@ -781,6 +789,7 @@ static void fsl_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops) clk_disable(q->clk); clk_disable(q->clk_en); + mutex_unlock(&q->lock); } static int fsl_qspi_probe(struct platform_device *pdev) @@ -864,6 +873,8 @@ static int fsl_qspi_probe(struct platform_device *pdev) if (of_get_property(np, "fsl,qspi-has-second-chip", NULL)) q->has_second_chip = true; + mutex_init(&q->lock); + /* iterate the subnodes. */ for_each_available_child_of_node(dev->of_node, np) { char modalias[40]; @@ -892,24 +903,24 @@ static int fsl_qspi_probe(struct platform_device *pdev) ret = of_modalias_node(np, modalias, sizeof(modalias)); if (ret < 0) - goto irq_failed; + goto mutex_failed; ret = of_property_read_u32(np, "spi-max-frequency", &q->clk_rate); if (ret < 0) - goto irq_failed; + goto mutex_failed; /* set the chip address for READID */ fsl_qspi_set_base_addr(q, nor); ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD); if (ret) - goto irq_failed; + goto mutex_failed; ppdata.of_node = np; ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); if (ret) - goto irq_failed; + goto mutex_failed; /* Set the correct NOR size now. */ if (q->nor_size == 0) { @@ -950,6 +961,8 @@ last_init_failed: i *= 2; mtd_device_unregister(&q->mtd[i]); } +mutex_failed: + mutex_destroy(&q->lock); irq_failed: clk_disable_unprepare(q->clk); clk_failed: @@ -973,6 +986,7 @@ static int fsl_qspi_remove(struct platform_device *pdev) writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR); writel(0x0, q->iobase + QUADSPI_RSER); + mutex_destroy(&q->lock); clk_unprepare(q->clk); clk_unprepare(q->clk_en); return 0; -- GitLab From fdbff9282c0f5f61ffc87d57461b04d943250910 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 11:23:24 +0200 Subject: [PATCH 0237/7006] drm/i915: Clear fb_tracking.busy_bits also for synchronous flips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current/old frontbuffer might still have gpu frontbuffer rendering pending. But once flipped it won't have the corresponding frontbuffer bits any more and hence the request retire function won't ever clear the corresponding busy bits. The async flip tracking (with the flip_prepare and flip_complete functions) already does this, but somehow I've forgotten to do this for synchronous flips. Note that we don't track outstanding rendering of the new framebuffer with busy_bits since all our plane update code waits for previous rendering to complete before displaying a new buffer. Hence a new buffer will never be busy. v2: Drop the spurious inline Ville spotted. v3: Don't touch flip_bits in the synchronsou frontbuffer_flip function, noticed by Paulo. v4: Remove one more inline that slipped through (Paulo). Reported-by: Paulo Zanoni Cc: Paulo Zanoni Cc: Ville Syrjälä Testcase: igt/kms_frontbuffer_tracking/fbc-modesetfrombusy Tested-by: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 17 +--------------- drivers/gpu/drm/i915/intel_frontbuffer.c | 25 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3529c9c9c4209..e66ff7a3cb8ac 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -963,23 +963,8 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits); void intel_frontbuffer_flush(struct drm_device *dev, unsigned frontbuffer_bits); -/** - * intel_frontbuffer_flip - synchronous frontbuffer flip - * @dev: DRM device - * @frontbuffer_bits: frontbuffer plane tracking bits - * - * This function gets called after scheduling a flip on @obj. This is for - * synchronous plane updates which will happen on the next vblank and which will - * not get delayed by pending gpu rendering. - * - * Can be called without any locks held. - */ -static inline void intel_frontbuffer_flip(struct drm_device *dev, - unsigned frontbuffer_bits) -{ - intel_frontbuffer_flush(dev, frontbuffer_bits); -} + unsigned frontbuffer_bits); unsigned int intel_fb_align_height(struct drm_device *dev, unsigned int height, diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index bdf0d57cad0fc..3b0ac73ede8f0 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -266,3 +266,28 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, intel_frontbuffer_flush(dev, frontbuffer_bits); } + +/** + * intel_frontbuffer_flip - synchronous frontbuffer flip + * @dev: DRM device + * @frontbuffer_bits: frontbuffer plane tracking bits + * + * This function gets called after scheduling a flip on @obj. This is for + * synchronous plane updates which will happen on the next vblank and which will + * not get delayed by pending gpu rendering. + * + * Can be called without any locks held. + */ + +void intel_frontbuffer_flip(struct drm_device *dev, + unsigned frontbuffer_bits) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->fb_tracking.lock); + /* Remove stale busy bits due to the old buffer. */ + dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; + mutex_unlock(&dev_priv->fb_tracking.lock); + + intel_frontbuffer_flush(dev, frontbuffer_bits); +} -- GitLab From 27e78a2a1f92e79707b4fb18cff1276088ef9178 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:21 +0200 Subject: [PATCH 0238/7006] drm/i915: Filter out no-op frontbuffer tracking flushes Paulo noticed that the fbc frontbuffer tracking flush callback occasionally gets a call without any bit set. This can happen when we have to filter flush calls due to e.g. gpu rendering. Filter these out. Reported-by: Paulo Zanoni Cc: Paulo Zanoni Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_frontbuffer.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 3b0ac73ede8f0..6a70a51332e93 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -175,6 +175,9 @@ void intel_frontbuffer_flush(struct drm_device *dev, frontbuffer_bits &= ~dev_priv->fb_tracking.busy_bits; mutex_unlock(&dev_priv->fb_tracking.lock); + if (!frontbuffer_bits) + return; + intel_mark_fb_busy(dev, frontbuffer_bits); intel_edp_drrs_flush(dev, frontbuffer_bits); -- GitLab From 9a851789e8a0cf38f9c04705a8e01b572e61f05f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:22 +0200 Subject: [PATCH 0239/7006] drm/i915: debugfs for frontbuffer tracking Useful to figure out whether stuck bits are due to the frontbuffer tracking code as opposed to individual consumers (who have their own bitmask tracking). Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 35a5defe7e29f..495a6376cf39a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1581,6 +1581,21 @@ static int i915_drpc_info(struct seq_file *m, void *unused) return ironlake_drpc_info(m); } +static int i915_frontbuffer_tracking(struct seq_file *m, void *unused) +{ + struct drm_info_node *node = m->private; + struct drm_device *dev = node->minor->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + seq_printf(m, "FB tracking busy bits: 0x%08x\n", + dev_priv->fb_tracking.busy_bits); + + seq_printf(m, "FB tracking flip bits: 0x%08x\n", + dev_priv->fb_tracking.flip_bits); + + return 0; +} + static int i915_fbc_status(struct seq_file *m, void *unused) { struct drm_info_node *node = m->private; @@ -5021,6 +5036,7 @@ static const struct drm_info_list i915_debugfs_list[] = { {"i915_drpc_info", i915_drpc_info, 0}, {"i915_emon_status", i915_emon_status, 0}, {"i915_ring_freq_table", i915_ring_freq_table, 0}, + {"i915_frontbuffer_tracking", i915_frontbuffer_tracking, 0}, {"i915_fbc_status", i915_fbc_status, 0}, {"i915_ips_status", i915_ips_status, 0}, {"i915_sr_status", i915_sr_status, 0}, -- GitLab From 251ac8621921d3936ea2eff6790fe35b25cf28a4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:24 +0200 Subject: [PATCH 0240/7006] drm/i915: s/update/compute/ for gmch dpll register functions I was momentarily confused until I've double-checked that these functions really only compute state and don't update the hardware state. They once did that, but since Ander's rework of the dpll computation flow that's no longer the case. Rename them to avoid further confusion. Note that the ilk code already follows the compute_dpll naming scheme for computing the actual register value. DDI code goes with _calc_, but that is close enough. Cc: Ander Conselvan de Oliveira Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 40 ++++++++++++++-------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1bc217ab3592a..060e30be3e394 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7160,8 +7160,8 @@ void intel_dp_set_m_n(struct intel_crtc *crtc, enum link_m_n_set m_n) intel_cpu_transcoder_set_m_n(crtc, dp_m_n, dp_m2_n2); } -static void vlv_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) +static void vlv_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) { u32 dpll, dpll_md; @@ -7274,8 +7274,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, mutex_unlock(&dev_priv->sb_lock); } -static void chv_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *pipe_config) +static void chv_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *pipe_config) { pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | @@ -7414,11 +7414,11 @@ void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe, }; if (IS_CHERRYVIEW(dev)) { - chv_update_pll(crtc, &pipe_config); + chv_compute_dpll(crtc, &pipe_config); chv_prepare_pll(crtc, &pipe_config); chv_enable_pll(crtc, &pipe_config); } else { - vlv_update_pll(crtc, &pipe_config); + vlv_compute_dpll(crtc, &pipe_config); vlv_prepare_pll(crtc, &pipe_config); vlv_enable_pll(crtc, &pipe_config); } @@ -7440,10 +7440,10 @@ void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe) vlv_disable_pll(to_i915(dev), pipe); } -static void i9xx_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - intel_clock_t *reduced_clock, - int num_connectors) +static void i9xx_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state, + intel_clock_t *reduced_clock, + int num_connectors) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -7517,10 +7517,10 @@ static void i9xx_update_pll(struct intel_crtc *crtc, } } -static void i8xx_update_pll(struct intel_crtc *crtc, - struct intel_crtc_state *crtc_state, - intel_clock_t *reduced_clock, - int num_connectors) +static void i8xx_compute_dpll(struct intel_crtc *crtc, + struct intel_crtc_state *crtc_state, + intel_clock_t *reduced_clock, + int num_connectors) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -7830,17 +7830,17 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, } if (IS_GEN2(dev)) { - i8xx_update_pll(crtc, crtc_state, + i8xx_compute_dpll(crtc, crtc_state, has_reduced_clock ? &reduced_clock : NULL, - num_connectors); + num_connectors); } else if (IS_CHERRYVIEW(dev)) { - chv_update_pll(crtc, crtc_state); + chv_compute_dpll(crtc, crtc_state); } else if (IS_VALLEYVIEW(dev)) { - vlv_update_pll(crtc, crtc_state); + vlv_compute_dpll(crtc, crtc_state); } else { - i9xx_update_pll(crtc, crtc_state, + i9xx_compute_dpll(crtc, crtc_state, has_reduced_clock ? &reduced_clock : NULL, - num_connectors); + num_connectors); } return 0; -- GitLab From c1d038c6e2fe1a07b23d8908bb2edfc95ca571cd Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:25 +0200 Subject: [PATCH 0241/7006] drm/i915/drrs: Restrict buffer tracking to the DRRS pipe The current code tracks business across all pipes, but we're only really interested in the one pipe DRRS is enabled on. Fairly tiny optimization, but something I noticed while reading the code. But it might matter a bit when e.g. showing a video or something only on the external screen, while the panel is kept static. Also regroup the code slightly: First compute new bitmasks, then take appropriate actions. Cc: Ramalingam C Cc: Sivakumar Thulasimani Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a1873b1498c9e..c43bff90c47a2 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5534,16 +5534,15 @@ void intel_edp_drrs_invalidate(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); + dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; + /* invalidate means busy screen hence upclock */ - if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) { + if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. fixed_mode->vrefresh); - } - - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); - dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits; mutex_unlock(&dev_priv->drrs.mutex); } @@ -5579,10 +5578,12 @@ void intel_edp_drrs_flush(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + + frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits; /* flush means busy screen hence upclock */ - if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) + if (frontbuffer_bits && dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) intel_dp_set_drrs_state(dev_priv->dev, dev_priv->drrs.dp->attached_connector->panel. fixed_mode->vrefresh); -- GitLab From ec76d62999b73f818f7d777ce037157bd2d4af02 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:26 +0200 Subject: [PATCH 0242/7006] drm/i915/psr: Restrict buffer tracking to the PSR pipe The current code tracks business across all pipes, but we're only really interested in the one pipe DRRS is enabled on. Fairly tiny optimization, but something I noticed while reading the code. But it might matter a bit when e.g. showing a video or something only on the external screen, while the panel is kept static. Also regroup the code slightly: First compute new bitmasks, then take appropriate actions. Cc: Rodrigo Vivi Cc: Durgadoss R Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 5ee0fa57ed199..e354ceacb628d 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -663,11 +663,12 @@ void intel_psr_invalidate(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; - intel_psr_exit(dev); - frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); - dev_priv->psr.busy_frontbuffer_bits |= frontbuffer_bits; + + if (frontbuffer_bits) + intel_psr_exit(dev); + mutex_unlock(&dev_priv->psr.lock); } @@ -698,6 +699,8 @@ void intel_psr_flush(struct drm_device *dev, crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; + + frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits; /* @@ -716,7 +719,7 @@ void intel_psr_flush(struct drm_device *dev, * invalidating. Which means we need to manually fake this in * software for all flushes, not just when we've seen a preceding * invalidation through frontbuffer rendering. */ - if (!HAS_DDI(dev)) + if (frontbuffer_bits && !HAS_DDI(dev)) intel_psr_exit(dev); if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) -- GitLab From 20c8838b0e3ba408a0ffe185b6124cdd0fcc3283 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:27 +0200 Subject: [PATCH 0243/7006] drm/i915/psr: Restrict single-shot updates to the PSR pipe The frontbuffer code gives us accurate information about activity, let's use it. Again this should avoid unecessary updates when multiple screens are on. Also realign function paramaters, I couldn't resist that bit of OCD. Cc: Rodrigo Vivi Cc: Durgadoss R Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 7 ++++--- drivers/gpu/drm/i915/intel_frontbuffer.c | 2 +- drivers/gpu/drm/i915/intel_psr.c | 22 +++++++++++++--------- 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e66ff7a3cb8ac..e90c7432bf4b8 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1307,11 +1307,12 @@ void intel_backlight_unregister(struct drm_device *dev); void intel_psr_enable(struct intel_dp *intel_dp); void intel_psr_disable(struct intel_dp *intel_dp); void intel_psr_invalidate(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits); void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits); void intel_psr_init(struct drm_device *dev); -void intel_psr_single_frame_update(struct drm_device *dev); +void intel_psr_single_frame_update(struct drm_device *dev, + unsigned frontbuffer_bits); /* intel_runtime_pm.c */ int intel_power_domains_init(struct drm_i915_private *); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 6a70a51332e93..89139c2ddd9e3 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -243,7 +243,7 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_psr_single_frame_update(dev); + intel_psr_single_frame_update(dev, frontbuffer_bits); } /** diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index e354ceacb628d..d79ba58637d72 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -596,13 +596,15 @@ static void intel_psr_exit(struct drm_device *dev) /** * intel_psr_single_frame_update - Single Frame Update * @dev: DRM device + * @frontbuffer_bits: frontbuffer plane tracking bits * * Some platforms support a single frame update feature that is used to * send and update only one frame on Remote Frame Buffer. * So far it is only implemented for Valleyview and Cherryview because * hardware requires this to be done before a page flip. */ -void intel_psr_single_frame_update(struct drm_device *dev) +void intel_psr_single_frame_update(struct drm_device *dev, + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -624,14 +626,16 @@ void intel_psr_single_frame_update(struct drm_device *dev) crtc = dp_to_dig_port(dev_priv->psr.enabled)->base.base.crtc; pipe = to_intel_crtc(crtc)->pipe; - val = I915_READ(VLV_PSRCTL(pipe)); - /* - * We need to set this bit before writing registers for a flip. - * This bit will be self-clear when it gets to the PSR active state. - */ - I915_WRITE(VLV_PSRCTL(pipe), val | VLV_EDP_PSR_SINGLE_FRAME_UPDATE); + if (frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe)) { + val = I915_READ(VLV_PSRCTL(pipe)); + /* + * We need to set this bit before writing registers for a flip. + * This bit will be self-clear when it gets to the PSR active state. + */ + I915_WRITE(VLV_PSRCTL(pipe), val | VLV_EDP_PSR_SINGLE_FRAME_UPDATE); + } mutex_unlock(&dev_priv->psr.lock); } @@ -648,7 +652,7 @@ void intel_psr_single_frame_update(struct drm_device *dev) * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits." */ void intel_psr_invalidate(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -685,7 +689,7 @@ void intel_psr_invalidate(struct drm_device *dev, * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits. */ void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; -- GitLab From 9fb73863cc3eda7476e88a03e8b125b3d309b7b3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:28 +0200 Subject: [PATCH 0244/7006] drm/i915: Use to_i915 in intel_frontbuffer.c Must have missed the transition. Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_frontbuffer.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 89139c2ddd9e3..16e699dac295f 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -131,7 +131,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, enum fb_op_origin origin) { struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -168,7 +168,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, void intel_frontbuffer_flush(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); /* Delay flushing when rings are still busy.*/ mutex_lock(&dev_priv->fb_tracking.lock); @@ -198,7 +198,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire) { struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); unsigned frontbuffer_bits; WARN_ON(!mutex_is_locked(&dev->struct_mutex)); @@ -235,7 +235,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, void intel_frontbuffer_flip_prepare(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev_priv->fb_tracking.lock); dev_priv->fb_tracking.flip_bits |= frontbuffer_bits; @@ -259,7 +259,7 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev_priv->fb_tracking.lock); /* Mask any cancelled flips. */ @@ -285,7 +285,7 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits) { - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = to_i915(dev); mutex_lock(&dev_priv->fb_tracking.lock); /* Remove stale busy bits due to the old buffer. */ -- GitLab From 0160f055393f457f8f218377bc088207eb502c38 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 23 Jun 2015 15:46:57 +0100 Subject: [PATCH 0245/7006] drm/i915/gen8: Add WaClearSlmSpaceAtContextSwitch workaround In Indirect context w/a batch buffer, WaClearSlmSpaceAtContextSwitch This WA performs writes to scratch page so it must be valid, this check is performed before initializing the batch with this WA. v2: s/PIPE_CONTROL_FLUSH_RO_CACHES/PIPE_CONTROL_FLUSH_L3 (Ville) v3: GTT bit in scratch address should be mbz (Chris) Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Rafael Barbalho Signed-off-by: Arun Siluvery Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_lrc.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b8e2259fe9ee5..c19067c843e87 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -415,6 +415,7 @@ #define DISPLAY_PLANE_A (0<<20) #define DISPLAY_PLANE_B (1<<20) #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|(len-2)) +#define PIPE_CONTROL_FLUSH_L3 (1<<27) #define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24) /* gen7+ */ #define PIPE_CONTROL_MMIO_WRITE (1<<23) #define PIPE_CONTROL_STORE_DATA_INDEX (1<<21) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 500ae5139f517..90a02dc5245ef 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1147,6 +1147,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + uint32_t scratch_addr; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:bdw,chv */ @@ -1175,6 +1176,20 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, wa_ctx_emit(batch, l3sqc4_flush & ~GEN8_LQSC_FLUSH_COHERENT_LINES); } + /* WaClearSlmSpaceAtContextSwitch:bdw,chv */ + /* Actual scratch location is at 128 bytes offset */ + scratch_addr = ring->scratch.gtt_offset + 2*CACHELINE_BYTES; + + wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, (PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE)); + wa_ctx_emit(batch, scratch_addr); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, MI_NOOP); -- GitLab From 8c6cda29194c5891d52cbd9d7aac496b61bf9310 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 23 Jun 2015 20:40:27 +0300 Subject: [PATCH 0246/7006] drm/i915/gen9: fix typo when setting up the crtc scaler This typo lead to the crtc scaler getting enabled incorrectly and an evantual state checker mismatch about the scaler_id. Signed-off-by: Imre Deak Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 060e30be3e394..47c0501f052c8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4352,7 +4352,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) return skl_update_scaler(state, force_detach, SKL_CRTC_INDEX, &state->scaler_state.scaler_id, DRM_ROTATE_0, state->pipe_src_w, state->pipe_src_h, - adjusted_mode->hdisplay, adjusted_mode->hdisplay); + adjusted_mode->hdisplay, adjusted_mode->vdisplay); } /** -- GitLab From c329a4ec595e886300710271db24bc29b74a4205 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 18 Jun 2015 10:30:23 +0200 Subject: [PATCH 0247/7006] drm/i915: Nuke lvds downclock support With the new DRRS code it kinda sticks out, and we never managed to get this to work well enough without causing issues. Time to wave goodbye. I've decided to keep the logic for programming the reduced clocks intact, but everything else is gone. If anyone ever wants to resurrect this we need to redo it all anyway on top of the frontbuffer tracking. Signed-off-by: Daniel Vetter Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 -- drivers/gpu/drm/i915/i915_params.c | 6 -- drivers/gpu/drm/i915/intel_bios.c | 62 +--------------- drivers/gpu/drm/i915/intel_display.c | 90 ++---------------------- drivers/gpu/drm/i915/intel_frontbuffer.c | 55 --------------- drivers/gpu/drm/i915/intel_lvds.c | 18 +---- 6 files changed, 8 insertions(+), 227 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 92a38ff365e05..ea9caf22283f6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1806,9 +1806,6 @@ struct drm_i915_private { /* Reclocking support */ bool render_reclock_avail; - bool lvds_downclock_avail; - /* indicates the reduced downclock for LVDS*/ - int lvds_downclock; struct i915_frontbuffer_tracking fb_tracking; @@ -2562,7 +2559,6 @@ struct i915_params { int modeset; int panel_ignore_lid; int semaphores; - unsigned int lvds_downclock; int lvds_channel_mode; int panel_use_ssc; int vbt_sdvo_panel_type; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 18f65595d60ee..7983fe48a6549 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -28,7 +28,6 @@ struct i915_params i915 __read_mostly = { .modeset = -1, .panel_ignore_lid = 1, .semaphores = -1, - .lvds_downclock = 0, .lvds_channel_mode = 0, .panel_use_ssc = -1, .vbt_sdvo_panel_type = -1, @@ -84,11 +83,6 @@ MODULE_PARM_DESC(enable_fbc, "Enable frame buffer compression for power savings " "(default: -1 (use per-chip default))"); -module_param_named(lvds_downclock, i915.lvds_downclock, int, 0400); -MODULE_PARM_DESC(lvds_downclock, - "Use panel (LVDS/eDP) downclocking for power savings " - "(default: false)"); - module_param_named(lvds_channel_mode, i915.lvds_channel_mode, int, 0600); MODULE_PARM_DESC(lvds_channel_mode, "Specify LVDS channel mode " diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 198fc3c3291b2..2ff9eb00fdec6 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -122,42 +122,6 @@ fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, drm_mode_set_name(panel_fixed_mode); } -static bool -lvds_dvo_timing_equal_size(const struct lvds_dvo_timing *a, - const struct lvds_dvo_timing *b) -{ - if (a->hactive_hi != b->hactive_hi || - a->hactive_lo != b->hactive_lo) - return false; - - if (a->hsync_off_hi != b->hsync_off_hi || - a->hsync_off_lo != b->hsync_off_lo) - return false; - - if (a->hsync_pulse_width != b->hsync_pulse_width) - return false; - - if (a->hblank_hi != b->hblank_hi || - a->hblank_lo != b->hblank_lo) - return false; - - if (a->vactive_hi != b->vactive_hi || - a->vactive_lo != b->vactive_lo) - return false; - - if (a->vsync_off != b->vsync_off) - return false; - - if (a->vsync_pulse_width != b->vsync_pulse_width) - return false; - - if (a->vblank_hi != b->vblank_hi || - a->vblank_lo != b->vblank_lo) - return false; - - return true; -} - static const struct lvds_dvo_timing * get_lvds_dvo_timing(const struct bdb_lvds_lfp_data *lvds_lfp_data, const struct bdb_lvds_lfp_data_ptrs *lvds_lfp_data_ptrs, @@ -213,7 +177,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, const struct lvds_dvo_timing *panel_dvo_timing; const struct lvds_fp_timing *fp_timing; struct drm_display_mode *panel_fixed_mode; - int i, downclock, drrs_mode; + int drrs_mode; lvds_options = find_section(bdb, BDB_LVDS_OPTIONS); if (!lvds_options) @@ -272,30 +236,6 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Found panel mode in BIOS VBT tables:\n"); drm_mode_debug_printmodeline(panel_fixed_mode); - /* - * Iterate over the LVDS panel timing info to find the lowest clock - * for the native resolution. - */ - downclock = panel_dvo_timing->clock; - for (i = 0; i < 16; i++) { - const struct lvds_dvo_timing *dvo_timing; - - dvo_timing = get_lvds_dvo_timing(lvds_lfp_data, - lvds_lfp_data_ptrs, - i); - if (lvds_dvo_timing_equal_size(dvo_timing, panel_dvo_timing) && - dvo_timing->clock < downclock) - downclock = dvo_timing->clock; - } - - if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) { - dev_priv->lvds_downclock_avail = 1; - dev_priv->lvds_downclock = downclock * 10; - DRM_DEBUG_KMS("LVDS downclock is found in VBT. " - "Normal Clock %dKHz, downclock %dKHz\n", - panel_fixed_mode->clock, 10*downclock); - } - fp_timing = get_lvds_fp_timing(bdb, lvds_lfp_data, lvds_lfp_data_ptrs, lvds_options->panel_type); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 47c0501f052c8..6851943e50a84 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7754,9 +7754,9 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; int refclk, num_connectors = 0; - intel_clock_t clock, reduced_clock; - bool ok, has_reduced_clock = false; - bool is_lvds = false, is_dsi = false; + intel_clock_t clock; + bool ok; + bool is_dsi = false; struct intel_encoder *encoder; const intel_limit_t *limit; struct drm_atomic_state *state = crtc_state->base.state; @@ -7774,9 +7774,6 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, encoder = to_intel_encoder(connector_state->best_encoder); switch (encoder->type) { - case INTEL_OUTPUT_LVDS: - is_lvds = true; - break; case INTEL_OUTPUT_DSI: is_dsi = true; break; @@ -7808,19 +7805,6 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, return -EINVAL; } - if (is_lvds && dev_priv->lvds_downclock_avail) { - /* - * Ensure we match the reduced clock's P to the target - * clock. If the clocks don't match, we can't switch - * the display clock by using the FP0/FP1. In such case - * we will disable the LVDS downclock feature. - */ - has_reduced_clock = - dev_priv->display.find_dpll(limit, crtc_state, - dev_priv->lvds_downclock, - refclk, &clock, - &reduced_clock); - } /* Compat-code for transition, will disappear. */ crtc_state->dpll.n = clock.n; crtc_state->dpll.m1 = clock.m1; @@ -7830,16 +7814,14 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc, } if (IS_GEN2(dev)) { - i8xx_compute_dpll(crtc, crtc_state, - has_reduced_clock ? &reduced_clock : NULL, + i8xx_compute_dpll(crtc, crtc_state, NULL, num_connectors); } else if (IS_CHERRYVIEW(dev)) { chv_compute_dpll(crtc, crtc_state); } else if (IS_VALLEYVIEW(dev)) { vlv_compute_dpll(crtc, crtc_state); } else { - i9xx_compute_dpll(crtc, crtc_state, - has_reduced_clock ? &reduced_clock : NULL, + i9xx_compute_dpll(crtc, crtc_state, NULL, num_connectors); } @@ -8651,9 +8633,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, struct drm_i915_private *dev_priv = dev->dev_private; int refclk; const intel_limit_t *limit; - bool ret, is_lvds = false; - - is_lvds = intel_pipe_will_have_type(crtc_state, INTEL_OUTPUT_LVDS); + bool ret; refclk = ironlake_get_refclk(crtc_state); @@ -8669,20 +8649,6 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc, if (!ret) return false; - if (is_lvds && dev_priv->lvds_downclock_avail) { - /* - * Ensure we match the reduced clock's P to the target clock. - * If the clocks don't match, we can't switch the display clock - * by using the FP0/FP1. In such case we will disable the LVDS - * downclock feature. - */ - *has_reduced_clock = - dev_priv->display.find_dpll(limit, crtc_state, - dev_priv->lvds_downclock, - refclk, clock, - reduced_clock); - } - return true; } @@ -10620,42 +10586,6 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev, return mode; } -static void intel_decrease_pllclock(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - - if (!HAS_GMCH_DISPLAY(dev)) - return; - - if (!dev_priv->lvds_downclock_avail) - return; - - /* - * Since this is called by a timer, we should never get here in - * the manual case. - */ - if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) { - int pipe = intel_crtc->pipe; - int dpll_reg = DPLL(pipe); - int dpll; - - DRM_DEBUG_DRIVER("downclocking LVDS\n"); - - assert_panel_unlocked(dev_priv, pipe); - - dpll = I915_READ(dpll_reg); - dpll |= DISPLAY_RATE_SELECT_FPA1; - I915_WRITE(dpll_reg, dpll); - intel_wait_for_vblank(dev, pipe); - dpll = I915_READ(dpll_reg); - if (!(dpll & DISPLAY_RATE_SELECT_FPA1)) - DRM_DEBUG_DRIVER("failed to downclock LVDS!\n"); - } - -} - void intel_mark_busy(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -10673,20 +10603,12 @@ void intel_mark_busy(struct drm_device *dev) void intel_mark_idle(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_crtc *crtc; if (!dev_priv->mm.busy) return; dev_priv->mm.busy = false; - for_each_crtc(dev, crtc) { - if (!crtc->primary->fb) - continue; - - intel_decrease_pllclock(crtc); - } - if (INTEL_INFO(dev)->gen >= 6) gen6_rps_idle(dev->dev_private); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 16e699dac295f..6e90e2b0293d5 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -65,57 +65,6 @@ #include "intel_drv.h" #include "i915_drv.h" -static void intel_increase_pllclock(struct drm_device *dev, - enum pipe pipe) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int dpll_reg = DPLL(pipe); - int dpll; - - if (!HAS_GMCH_DISPLAY(dev)) - return; - - if (!dev_priv->lvds_downclock_avail) - return; - - dpll = I915_READ(dpll_reg); - if (!HAS_PIPE_CXSR(dev) && (dpll & DISPLAY_RATE_SELECT_FPA1)) { - DRM_DEBUG_DRIVER("upclocking LVDS\n"); - - assert_panel_unlocked(dev_priv, pipe); - - dpll &= ~DISPLAY_RATE_SELECT_FPA1; - I915_WRITE(dpll_reg, dpll); - intel_wait_for_vblank(dev, pipe); - - dpll = I915_READ(dpll_reg); - if (dpll & DISPLAY_RATE_SELECT_FPA1) - DRM_DEBUG_DRIVER("failed to upclock LVDS!\n"); - } -} - -/** - * intel_mark_fb_busy - mark given planes as busy - * @dev: DRM device - * @frontbuffer_bits: bits for the affected planes - * - * This function gets called every time the screen contents change. It can be - * used to keep e.g. the update rate at the nominal refresh rate with DRRS. - */ -static void intel_mark_fb_busy(struct drm_device *dev, - unsigned frontbuffer_bits) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - enum pipe pipe; - - for_each_pipe(dev_priv, pipe) { - if (!(frontbuffer_bits & INTEL_FRONTBUFFER_ALL_MASK(pipe))) - continue; - - intel_increase_pllclock(dev, pipe); - } -} - /** * intel_fb_obj_invalidate - invalidate frontbuffer object * @obj: GEM object to invalidate @@ -147,8 +96,6 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, mutex_unlock(&dev_priv->fb_tracking.lock); } - intel_mark_fb_busy(dev, obj->frontbuffer_bits); - intel_psr_invalidate(dev, obj->frontbuffer_bits); intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits); intel_fbc_invalidate(dev_priv, obj->frontbuffer_bits, origin); @@ -178,8 +125,6 @@ void intel_frontbuffer_flush(struct drm_device *dev, if (!frontbuffer_bits) return; - intel_mark_fb_busy(dev, frontbuffer_bits); - intel_edp_drrs_flush(dev, frontbuffer_bits); intel_psr_flush(dev, frontbuffer_bits); intel_fbc_flush(dev_priv, frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index bf1702a6e33d0..ea85547611a56 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -1072,24 +1072,8 @@ void intel_lvds_init(struct drm_device *dev) drm_mode_debug_printmodeline(scan); fixed_mode = drm_mode_duplicate(dev, scan); - if (fixed_mode) { - downclock_mode = - intel_find_panel_downclock(dev, - fixed_mode, connector); - if (downclock_mode != NULL && - i915.lvds_downclock) { - /* We found the downclock for LVDS. */ - dev_priv->lvds_downclock_avail = true; - dev_priv->lvds_downclock = - downclock_mode->clock; - DRM_DEBUG_KMS("LVDS downclock is found" - " in EDID. Normal clock %dKhz, " - "downclock %dKhz\n", - fixed_mode->clock, - dev_priv->lvds_downclock); - } + if (fixed_mode) goto out; - } } } -- GitLab From c9f8fd2d87eebb97b0ffdb3ff6cd90eb1c8e00bd Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 24 Jun 2015 09:55:20 +0100 Subject: [PATCH 0248/7006] drm/i915: Remove mostly unused variable in intel_rotate_fb_obj_pages It is only used in logging and it doesn't need to exist on its own. Also it was misleading to log view size as object size. v2: Improve commit message. (Joonas Lahtinen) Signed-off-by: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen [danvet: s/%lu/%zu/ where needed, reported by 0-day.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a8c33f7f922f6..005b78b59affd 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2702,7 +2702,7 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, { struct drm_device *dev = obj->base.dev; struct intel_rotation_info *rot_info = &ggtt_view->rotation_info; - unsigned long size, pages, rot_pages; + unsigned long pages, rot_pages; struct sg_page_iter sg_iter; unsigned long i; dma_addr_t *page_addr_list; @@ -2720,7 +2720,6 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch); height_pages = DIV_ROUND_UP(rot_info->height, tile_height); rot_pages = width_pages * height_pages; - size = rot_pages * PAGE_SIZE; /* Allocate a temporary list of source pages for random access. */ page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t)); @@ -2747,8 +2746,8 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, rotate_pages(page_addr_list, width_pages, height_pages, st); DRM_DEBUG_KMS( - "Created rotated page mapping for object size %lu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n", - size, rot_info->pitch, rot_info->height, + "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n", + obj->base.size, rot_info->pitch, rot_info->height, rot_info->pixel_format, width_pages, height_pages, rot_pages); @@ -2762,8 +2761,8 @@ err_st_alloc: drm_free_large(page_addr_list); DRM_DEBUG_KMS( - "Failed to create rotated mapping for object size %lu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n", - size, ret, rot_info->pitch, rot_info->height, + "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n", + obj->base.size, ret, rot_info->pitch, rot_info->height, rot_info->pixel_format, width_pages, height_pages, rot_pages); return ERR_PTR(ret); -- GitLab From 84fe03f7b2481b3a1cf4fb9db6e5df8d3698a4fe Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 23 Jun 2015 14:26:46 +0100 Subject: [PATCH 0249/7006] drm/i915: Move rotated geometry calculations into the fill helper This way data is available as soon as the view is passed into the call chain. v2: Store size in bytes instead of pages under the appropriate name. (Chris Wilson) v3: Use uint64_t instead of size_t. (Daniel Vetter) Signed-off-by: Tvrtko Ursulin Cc: Daniel Vetter Cc: Chris Wilson Reviewed-by: Joonas Lahtinen (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 36 ++++++++++------------------ drivers/gpu/drm/i915/i915_gem_gtt.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 8 +++++++ 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 005b78b59affd..53a59b89462f1 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2700,29 +2700,17 @@ static struct sg_table * intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, struct drm_i915_gem_object *obj) { - struct drm_device *dev = obj->base.dev; struct intel_rotation_info *rot_info = &ggtt_view->rotation_info; - unsigned long pages, rot_pages; + unsigned int size_pages = rot_info->size >> PAGE_SHIFT; struct sg_page_iter sg_iter; unsigned long i; dma_addr_t *page_addr_list; struct sg_table *st; - unsigned int tile_pitch, tile_height; - unsigned int width_pages, height_pages; int ret = -ENOMEM; - pages = obj->base.size / PAGE_SIZE; - - /* Calculate tiling geometry. */ - tile_height = intel_tile_height(dev, rot_info->pixel_format, - rot_info->fb_modifier); - tile_pitch = PAGE_SIZE / tile_height; - width_pages = DIV_ROUND_UP(rot_info->pitch, tile_pitch); - height_pages = DIV_ROUND_UP(rot_info->height, tile_height); - rot_pages = width_pages * height_pages; - /* Allocate a temporary list of source pages for random access. */ - page_addr_list = drm_malloc_ab(pages, sizeof(dma_addr_t)); + page_addr_list = drm_malloc_ab(obj->base.size / PAGE_SIZE, + sizeof(dma_addr_t)); if (!page_addr_list) return ERR_PTR(ret); @@ -2731,7 +2719,7 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, if (!st) goto err_st_alloc; - ret = sg_alloc_table(st, rot_pages, GFP_KERNEL); + ret = sg_alloc_table(st, size_pages, GFP_KERNEL); if (ret) goto err_sg_alloc; @@ -2743,13 +2731,15 @@ intel_rotate_fb_obj_pages(struct i915_ggtt_view *ggtt_view, } /* Rotate the pages. */ - rotate_pages(page_addr_list, width_pages, height_pages, st); + rotate_pages(page_addr_list, + rot_info->width_pages, rot_info->height_pages, + st); DRM_DEBUG_KMS( - "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages).\n", + "Created rotated page mapping for object size %zu (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages).\n", obj->base.size, rot_info->pitch, rot_info->height, - rot_info->pixel_format, width_pages, height_pages, - rot_pages); + rot_info->pixel_format, rot_info->width_pages, + rot_info->height_pages, size_pages); drm_free_large(page_addr_list); @@ -2761,10 +2751,10 @@ err_st_alloc: drm_free_large(page_addr_list); DRM_DEBUG_KMS( - "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %lu pages)\n", + "Failed to create rotated mapping for object size %zu! (%d) (pitch=%u, height=%u, pixel_format=0x%x, %ux%u tiles, %u pages)\n", obj->base.size, ret, rot_info->pitch, rot_info->height, - rot_info->pixel_format, width_pages, height_pages, - rot_pages); + rot_info->pixel_format, rot_info->width_pages, + rot_info->height_pages, size_pages); return ERR_PTR(ret); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 735f11986ea66..017ea308f8b41 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -126,6 +126,8 @@ struct intel_rotation_info { unsigned int pitch; uint32_t pixel_format; uint64_t fb_modifier; + unsigned int width_pages, height_pages; + uint64_t size; }; struct i915_ggtt_view { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6851943e50a84..292d69e52cc56 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2268,6 +2268,7 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, const struct drm_plane_state *plane_state) { struct intel_rotation_info *info = &view->rotation_info; + unsigned int tile_height, tile_pitch; *view = i915_ggtt_view_normal; @@ -2284,6 +2285,13 @@ intel_fill_fb_ggtt_view(struct i915_ggtt_view *view, struct drm_framebuffer *fb, info->pitch = fb->pitches[0]; info->fb_modifier = fb->modifier[0]; + tile_height = intel_tile_height(fb->dev, fb->pixel_format, + fb->modifier[0]); + tile_pitch = PAGE_SIZE / tile_height; + info->width_pages = DIV_ROUND_UP(fb->pitches[0], tile_pitch); + info->height_pages = DIV_ROUND_UP(fb->height, tile_height); + info->size = info->width_pages * info->height_pages * PAGE_SIZE; + return 0; } -- GitLab From 9e759ff1f4a047c405034dfff1ee5c87abba41db Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Tue, 23 Jun 2015 12:57:43 +0100 Subject: [PATCH 0250/7006] drm/i915: Return correct size for rotated views Currently object size is returned for the rotated VMA size which can be bigger than the rotated view itself. Since the binding code pads all excess size with scratch pages the only minor issue with this is wasting some GGTT space, but still feels nicer to fix and report the real size. v2: Rebase for tracking size in bytes instead of pages. Signed-off-by: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 53a59b89462f1..2279e030570cd 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2899,9 +2899,10 @@ size_t i915_ggtt_view_size(struct drm_i915_gem_object *obj, const struct i915_ggtt_view *view) { - if (view->type == I915_GGTT_VIEW_NORMAL || - view->type == I915_GGTT_VIEW_ROTATED) { + if (view->type == I915_GGTT_VIEW_NORMAL) { return obj->base.size; + } else if (view->type == I915_GGTT_VIEW_ROTATED) { + return view->rotation_info.size; } else if (view->type == I915_GGTT_VIEW_PARTIAL) { return view->params.partial.size << PAGE_SHIFT; } else { -- GitLab From acd3f3d3516838ebe001b7048fe59ab5b93bb645 Mon Sep 17 00:00:00 2001 From: Bob Paauwe Date: Tue, 23 Jun 2015 14:14:26 -0700 Subject: [PATCH 0251/7006] drm/i915: Add the ddi get cdclk code for BXT (v3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The registers and process differ from other platforms. If the hardware was programmed incorrectly, this will return invalid cdclk values, which should then cause reprogramming of the hardware. v2(Matt): Return 19.2 MHz when DE PLL is disabled (Ville) v3: Make less assumptions about the hardware state (Ville) Cc: Ville Syrjälä Cc: Imre Deak Cc: Matt Roper Signed-off-by: Bob Paauwe Signed-off-by: Matt Roper Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 31 ++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 292d69e52cc56..cc68e4179a5a0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6624,6 +6624,34 @@ static int skylake_get_display_clock_speed(struct drm_device *dev) return 24000; } +static int broxton_get_display_clock_speed(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + uint32_t cdctl = I915_READ(CDCLK_CTL); + uint32_t pll_ratio = I915_READ(BXT_DE_PLL_CTL) & BXT_DE_PLL_RATIO_MASK; + uint32_t pll_enab = I915_READ(BXT_DE_PLL_ENABLE); + int cdclk; + + if (!(pll_enab & BXT_DE_PLL_PLL_ENABLE)) + return 19200; + + cdclk = 19200 * pll_ratio / 2; + + switch (cdctl & BXT_CDCLK_CD2X_DIV_SEL_MASK) { + case BXT_CDCLK_CD2X_DIV_SEL_1: + return cdclk; /* 576MHz or 624MHz */ + case BXT_CDCLK_CD2X_DIV_SEL_1_5: + return cdclk * 2 / 3; /* 384MHz */ + case BXT_CDCLK_CD2X_DIV_SEL_2: + return cdclk / 2; /* 288MHz */ + case BXT_CDCLK_CD2X_DIV_SEL_4: + return cdclk / 4; /* 144MHz */ + } + + /* error case, do as if DE PLL isn't enabled */ + return 19200; +} + static int broadwell_get_display_clock_speed(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -14615,6 +14643,9 @@ static void intel_init_display(struct drm_device *dev) if (IS_SKYLAKE(dev)) dev_priv->display.get_display_clock_speed = skylake_get_display_clock_speed; + else if (IS_BROXTON(dev)) + dev_priv->display.get_display_clock_speed = + broxton_get_display_clock_speed; else if (IS_BROADWELL(dev)) dev_priv->display.get_display_clock_speed = broadwell_get_display_clock_speed; -- GitLab From a9ff8714d911b1f9417af75525eb29ac31e014fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 21:59:34 +0300 Subject: [PATCH 0252/7006] drm/i915: Store frontbuffer_bits in the plane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Avoid some 'switch (plane->type)' by storing the fronbuffer_bits in intel_plane. Signed-off-by: Ville Syrjälä [danvet: use singular frontbuffer_bits in intel_plane since a plan can only ever have one bit. Discussed with Ville on irc.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 75 ++++++++-------------------- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_sprite.c | 1 + 3 files changed, 22 insertions(+), 55 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cc68e4179a5a0..4882e43fd8a28 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2613,7 +2613,7 @@ valid_fb: primary->crtc = primary->state->crtc = &intel_crtc->base; update_state_fb(primary); intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); - obj->frontbuffer_bits |= INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); + obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit; } static void i9xx_update_primary_plane(struct drm_crtc *crtc, @@ -4742,25 +4742,12 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) struct drm_plane *p; /* Track fb's for any planes being disabled */ - drm_for_each_plane_mask(p, dev, atomic->disabled_planes) { struct intel_plane *plane = to_intel_plane(p); - unsigned fb_bits = 0; - - switch (p->type) { - case DRM_PLANE_TYPE_PRIMARY: - fb_bits = INTEL_FRONTBUFFER_PRIMARY(plane->pipe); - break; - case DRM_PLANE_TYPE_CURSOR: - fb_bits = INTEL_FRONTBUFFER_CURSOR(plane->pipe); - break; - case DRM_PLANE_TYPE_OVERLAY: - fb_bits = INTEL_FRONTBUFFER_SPRITE(plane->pipe); - break; - } mutex_lock(&dev->struct_mutex); - i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, fb_bits); + i915_gem_track_fb(intel_fb_obj(plane->base.fb), NULL, + plane->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); } @@ -10676,11 +10663,12 @@ static void intel_unpin_work_fn(struct work_struct *__work) { struct intel_unpin_work *work = container_of(__work, struct intel_unpin_work, work); - struct drm_device *dev = work->crtc->dev; - enum pipe pipe = to_intel_crtc(work->crtc)->pipe; + struct intel_crtc *crtc = to_intel_crtc(work->crtc); + struct drm_device *dev = crtc->base.dev; + struct drm_plane *primary = crtc->base.primary; mutex_lock(&dev->struct_mutex); - intel_unpin_fb_obj(work->old_fb, work->crtc->primary->state); + intel_unpin_fb_obj(work->old_fb, primary->state); drm_gem_object_unreference(&work->pending_flip_obj->base); intel_fbc_update(dev); @@ -10689,11 +10677,11 @@ static void intel_unpin_work_fn(struct work_struct *__work) i915_gem_request_assign(&work->flip_queued_req, NULL); mutex_unlock(&dev->struct_mutex); - intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); + intel_frontbuffer_flip_complete(dev, to_intel_plane(primary)->frontbuffer_bit); drm_framebuffer_unreference(work->old_fb); - BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0); - atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count); + BUG_ON(atomic_read(&crtc->unpin_work_count) == 0); + atomic_dec(&crtc->unpin_work_count); kfree(work); } @@ -11455,10 +11443,11 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, work->enable_stall_check = true; i915_gem_track_fb(intel_fb_obj(work->old_fb), obj, - INTEL_FRONTBUFFER_PRIMARY(pipe)); + to_intel_plane(primary)->frontbuffer_bit); intel_fbc_disable(dev); - intel_frontbuffer_flip_prepare(dev, INTEL_FRONTBUFFER_PRIMARY(pipe)); + intel_frontbuffer_flip_prepare(dev, + to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); @@ -11613,12 +11602,12 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, if (intel_wm_need_update(plane, plane_state)) intel_crtc->atomic.update_wm = true; + if (visible) + intel_crtc->atomic.fb_bits |= + to_intel_plane(plane)->frontbuffer_bit; + switch (plane->type) { case DRM_PLANE_TYPE_PRIMARY: - if (visible) - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe); - intel_crtc->atomic.wait_for_flips = true; intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; @@ -11654,25 +11643,13 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.update_fbc |= visible || mode_changed; break; case DRM_PLANE_TYPE_CURSOR: - if (visible) - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe); break; case DRM_PLANE_TYPE_OVERLAY: - /* - * 'prepare' is never called when plane is being disabled, so - * we need to handle frontbuffer tracking as a special case - */ - if (visible) - intel_crtc->atomic.fb_bits |= - INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe); - if (turn_off && !mode_changed) { intel_crtc->atomic.wait_vblank = true; intel_crtc->atomic.update_sprite_watermarks |= 1 << i; } - break; } return 0; } @@ -13554,27 +13531,13 @@ intel_prepare_plane_fb(struct drm_plane *plane, { struct drm_device *dev = plane->dev; struct intel_plane *intel_plane = to_intel_plane(plane); - enum pipe pipe = intel_plane->pipe; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb); - unsigned frontbuffer_bits = 0; int ret = 0; if (!obj) return 0; - switch (plane->type) { - case DRM_PLANE_TYPE_PRIMARY: - frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(pipe); - break; - case DRM_PLANE_TYPE_CURSOR: - frontbuffer_bits = INTEL_FRONTBUFFER_CURSOR(pipe); - break; - case DRM_PLANE_TYPE_OVERLAY: - frontbuffer_bits = INTEL_FRONTBUFFER_SPRITE(pipe); - break; - } - mutex_lock(&dev->struct_mutex); if (plane->type == DRM_PLANE_TYPE_CURSOR && @@ -13588,7 +13551,7 @@ intel_prepare_plane_fb(struct drm_plane *plane, } if (ret == 0) - i915_gem_track_fb(old_obj, obj, frontbuffer_bits); + i915_gem_track_fb(old_obj, obj, intel_plane->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); @@ -13807,6 +13770,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev, } primary->pipe = pipe; primary->plane = pipe; + primary->frontbuffer_bit = INTEL_FRONTBUFFER_PRIMARY(pipe); primary->check_plane = intel_check_primary_plane; primary->commit_plane = intel_commit_primary_plane; primary->disable_plane = intel_disable_primary_plane; @@ -13962,6 +13926,7 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev, cursor->max_downscale = 1; cursor->pipe = pipe; cursor->plane = pipe; + cursor->frontbuffer_bit = INTEL_FRONTBUFFER_CURSOR(pipe); cursor->check_plane = intel_check_cursor_plane; cursor->commit_plane = intel_commit_cursor_plane; cursor->disable_plane = intel_disable_cursor_plane; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e90c7432bf4b8..e016d722cacb4 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -590,6 +590,7 @@ struct intel_plane { enum pipe pipe; bool can_scale; int max_downscale; + uint32_t frontbuffer_bit; /* Since we need to change the watermarks before/after * enabling/disabling the planes, we need to store the parameters here diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index e0045aa97bd22..16be667cc5eb4 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -1130,6 +1130,7 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane) intel_plane->pipe = pipe; intel_plane->plane = plane; + intel_plane->frontbuffer_bit = INTEL_FRONTBUFFER_SPRITE(pipe); intel_plane->check_plane = intel_check_sprite_plane; intel_plane->commit_plane = intel_commit_sprite_plane; possible_crtcs = (1 << pipe); -- GitLab From 9e2ee2dd044e01e06e4a6389583f95bfa1058bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 21:59:35 +0300 Subject: [PATCH 0253/7006] drm/i915: Add debug messages for pipe enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we don't have any real indication when a pipe gets enabled/disabled. Add some. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4882e43fd8a28..01eaab8b6d40a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2110,6 +2110,8 @@ static void intel_enable_pipe(struct intel_crtc *crtc) int reg; u32 val; + DRM_DEBUG_KMS("enabling pipe %c\n", pipe_name(pipe)); + assert_planes_disabled(dev_priv, pipe); assert_cursor_disabled(dev_priv, pipe); assert_sprites_disabled(dev_priv, pipe); @@ -2169,6 +2171,8 @@ static void intel_disable_pipe(struct intel_crtc *crtc) int reg; u32 val; + DRM_DEBUG_KMS("disabling pipe %c\n", pipe_name(pipe)); + /* * Make sure planes won't keep trying to pump pixels to us, * or we might hang the display. -- GitLab From b503ed603ec9acc25dd31808fe87575bdaeab4e7 Mon Sep 17 00:00:00 2001 From: Eyal Shapira Date: Wed, 27 May 2015 22:20:46 +0300 Subject: [PATCH 0254/7006] iwlwifi: mvm: rs: report last tx rate based on RSSI and caps In scenarios where we haven't converged yet to a specific modulation and rate it could be better to report to userspace the last tx rate based on the STA capabilities and RSSI. This is important as sometimes userspace displays the last tx rate as the link speed. This avoids being presented with low legacy rates when rs just begins its search or after an idle period in which it resets itself. Signed-off-by: Eyal Shapira Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/rs.c | 157 ++++++++++++++++++++++++-- drivers/net/wireless/iwlwifi/mvm/rs.h | 10 ++ 2 files changed, 160 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c index daff1d0a8e4ad..19a79262e0a0e 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.c +++ b/drivers/net/wireless/iwlwifi/mvm/rs.c @@ -2403,7 +2403,7 @@ struct rs_init_rate_info { u8 rate_idx; }; -static const struct rs_init_rate_info rs_init_rates_24ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_24ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -68, IWL_RATE_36M_INDEX }, @@ -2416,7 +2416,7 @@ static const struct rs_init_rate_info rs_init_rates_24ghz[] = { { S8_MIN, IWL_RATE_1M_INDEX }, }; -static const struct rs_init_rate_info rs_init_rates_5ghz[] = { +static const struct rs_init_rate_info rs_optimal_rates_5ghz_legacy[] = { { -60, IWL_RATE_54M_INDEX }, { -64, IWL_RATE_48M_INDEX }, { -72, IWL_RATE_36M_INDEX }, @@ -2427,6 +2427,124 @@ static const struct rs_init_rate_info rs_init_rates_5ghz[] = { { S8_MIN, IWL_RATE_6M_INDEX }, }; +static const struct rs_init_rate_info rs_optimal_rates_ht[] = { + { -60, IWL_RATE_MCS_7_INDEX }, + { -64, IWL_RATE_MCS_6_INDEX }, + { -68, IWL_RATE_MCS_5_INDEX }, + { -72, IWL_RATE_MCS_4_INDEX }, + { -80, IWL_RATE_MCS_3_INDEX }, + { -84, IWL_RATE_MCS_2_INDEX }, + { -85, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_20mhz[] = { + { -60, IWL_RATE_MCS_8_INDEX }, + { -64, IWL_RATE_MCS_7_INDEX }, + { -68, IWL_RATE_MCS_6_INDEX }, + { -72, IWL_RATE_MCS_5_INDEX }, + { -80, IWL_RATE_MCS_4_INDEX }, + { -84, IWL_RATE_MCS_3_INDEX }, + { -85, IWL_RATE_MCS_2_INDEX }, + { -87, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX}, +}; + +static const struct rs_init_rate_info rs_optimal_rates_vht_40_80mhz[] = { + { -60, IWL_RATE_MCS_9_INDEX }, + { -64, IWL_RATE_MCS_8_INDEX }, + { -68, IWL_RATE_MCS_7_INDEX }, + { -72, IWL_RATE_MCS_6_INDEX }, + { -80, IWL_RATE_MCS_5_INDEX }, + { -84, IWL_RATE_MCS_4_INDEX }, + { -85, IWL_RATE_MCS_3_INDEX }, + { -87, IWL_RATE_MCS_2_INDEX }, + { -88, IWL_RATE_MCS_1_INDEX }, + { S8_MIN, IWL_RATE_MCS_0_INDEX }, +}; + +/* Init the optimal rate based on STA caps + * This combined with rssi is used to report the last tx rate + * to userspace when we haven't transmitted enough frames. + */ +static void rs_init_optimal_rate(struct iwl_mvm *mvm, + struct ieee80211_sta *sta, + struct iwl_lq_sta *lq_sta) +{ + struct rs_rate *rate = &lq_sta->optimal_rate; + + if (lq_sta->max_mimo2_rate_idx != IWL_RATE_INVALID) + rate->type = lq_sta->is_vht ? LQ_VHT_MIMO2 : LQ_HT_MIMO2; + else if (lq_sta->max_siso_rate_idx != IWL_RATE_INVALID) + rate->type = lq_sta->is_vht ? LQ_VHT_SISO : LQ_HT_SISO; + else if (lq_sta->band == IEEE80211_BAND_5GHZ) + rate->type = LQ_LEGACY_A; + else + rate->type = LQ_LEGACY_G; + + rate->bw = rs_bw_from_sta_bw(sta); + rate->sgi = rs_sgi_allow(mvm, sta, rate, NULL); + + /* ANT/LDPC/STBC aren't relevant for the rate reported to userspace */ + + if (is_mimo(rate)) { + lq_sta->optimal_rate_mask = lq_sta->active_mimo2_rate; + } else if (is_siso(rate)) { + lq_sta->optimal_rate_mask = lq_sta->active_siso_rate; + } else { + lq_sta->optimal_rate_mask = lq_sta->active_legacy_rate; + + if (lq_sta->band == IEEE80211_BAND_5GHZ) { + lq_sta->optimal_rates = rs_optimal_rates_5ghz_legacy; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); + } else { + lq_sta->optimal_rates = rs_optimal_rates_24ghz_legacy; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); + } + } + + if (is_vht(rate)) { + if (rate->bw == RATE_MCS_CHAN_WIDTH_20) { + lq_sta->optimal_rates = rs_optimal_rates_vht_20mhz; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_vht_20mhz); + } else { + lq_sta->optimal_rates = rs_optimal_rates_vht_40_80mhz; + lq_sta->optimal_nentries = + ARRAY_SIZE(rs_optimal_rates_vht_40_80mhz); + } + } else if (is_ht(rate)) { + lq_sta->optimal_rates = rs_optimal_rates_ht; + lq_sta->optimal_nentries = ARRAY_SIZE(rs_optimal_rates_ht); + } +} + +/* Compute the optimal rate index based on RSSI */ +static struct rs_rate *rs_get_optimal_rate(struct iwl_mvm *mvm, + struct iwl_lq_sta *lq_sta) +{ + struct rs_rate *rate = &lq_sta->optimal_rate; + int i; + + rate->index = find_first_bit(&lq_sta->optimal_rate_mask, + BITS_PER_LONG); + + for (i = 0; i < lq_sta->optimal_nentries; i++) { + int rate_idx = lq_sta->optimal_rates[i].rate_idx; + + if ((lq_sta->pers.last_rssi >= lq_sta->optimal_rates[i].rssi) && + (BIT(rate_idx) & lq_sta->optimal_rate_mask)) { + rate->index = rate_idx; + break; + } + } + + rs_dump_rate(mvm, rate, "OPTIMAL RATE"); + return rate; +} + /* Choose an initial legacy rate and antenna to use based on the RSSI * of last Rx */ @@ -2468,12 +2586,12 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm, if (band == IEEE80211_BAND_5GHZ) { rate->type = LQ_LEGACY_A; - initial_rates = rs_init_rates_5ghz; - nentries = ARRAY_SIZE(rs_init_rates_5ghz); + initial_rates = rs_optimal_rates_5ghz_legacy; + nentries = ARRAY_SIZE(rs_optimal_rates_5ghz_legacy); } else { rate->type = LQ_LEGACY_G; - initial_rates = rs_init_rates_24ghz; - nentries = ARRAY_SIZE(rs_init_rates_24ghz); + initial_rates = rs_optimal_rates_24ghz_legacy; + nentries = ARRAY_SIZE(rs_optimal_rates_24ghz_legacy); } if (IWL_MVM_RS_RSSI_BASED_INIT_RATE) { @@ -2496,10 +2614,21 @@ void rs_update_last_rssi(struct iwl_mvm *mvm, struct iwl_lq_sta *lq_sta, struct ieee80211_rx_status *rx_status) { + int i; + lq_sta->pers.chains = rx_status->chains; lq_sta->pers.chain_signal[0] = rx_status->chain_signal[0]; lq_sta->pers.chain_signal[1] = rx_status->chain_signal[1]; lq_sta->pers.chain_signal[2] = rx_status->chain_signal[2]; + lq_sta->pers.last_rssi = S8_MIN; + + for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) { + if (!(lq_sta->pers.chains & BIT(i))) + continue; + + if (lq_sta->pers.chain_signal[i] > lq_sta->pers.last_rssi) + lq_sta->pers.last_rssi = lq_sta->pers.chain_signal[i]; + } } /** @@ -2538,6 +2667,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm, rate = &tbl->rate; rs_get_initial_rate(mvm, lq_sta, band, rate); + rs_init_optimal_rate(mvm, sta, lq_sta); WARN_ON_ONCE(rate->ant != ANT_A && rate->ant != ANT_B); if (rate->ant == ANT_A) @@ -2560,6 +2690,8 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, struct iwl_mvm *mvm __maybe_unused = IWL_OP_MODE_GET_MVM(op_mode); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct iwl_lq_sta *lq_sta = mvm_sta; + struct rs_rate *optimal_rate; + u32 last_ucode_rate; if (sta && !iwl_mvm_sta_from_mac80211(sta)->vif) { /* if vif isn't initialized mvm doesn't know about @@ -2583,8 +2715,18 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta, iwl_mvm_hwrate_to_tx_rate(lq_sta->last_rate_n_flags, info->band, &info->control.rates[0]); - info->control.rates[0].count = 1; + + /* Report the optimal rate based on rssi and STA caps if we haven't + * converged yet (too little traffic) or exploring other modulations + */ + if (lq_sta->rs_state != RS_STATE_STAY_IN_COLUMN) { + optimal_rate = rs_get_optimal_rate(mvm, lq_sta); + last_ucode_rate = ucode_rate_from_rs_rate(mvm, + optimal_rate); + iwl_mvm_hwrate_to_tx_rate(last_ucode_rate, info->band, + &txrc->reported_rate); + } } static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, @@ -2605,6 +2747,7 @@ static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta, #endif lq_sta->pers.chains = 0; memset(lq_sta->pers.chain_signal, 0, sizeof(lq_sta->pers.chain_signal)); + lq_sta->pers.last_rssi = S8_MIN; return &sta_priv->lq_sta; } diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h index 2a3da314305ab..81314ad9ebe09 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rs.h +++ b/drivers/net/wireless/iwlwifi/mvm/rs.h @@ -1,6 +1,7 @@ /****************************************************************************** * * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved. + * Copyright(c) 2015 Intel Mobile Communications GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License as @@ -316,6 +317,14 @@ struct iwl_lq_sta { u8 max_siso_rate_idx; u8 max_mimo2_rate_idx; + /* Optimal rate based on RSSI and STA caps. + * Used only to reflect link speed to userspace. + */ + struct rs_rate optimal_rate; + unsigned long optimal_rate_mask; + const struct rs_init_rate_info *optimal_rates; + int optimal_nentries; + u8 missed_rate_counter; struct iwl_lq_cmd lq; @@ -341,6 +350,7 @@ struct iwl_lq_sta { #endif u8 chains; s8 chain_signal[IEEE80211_MAX_CHAINS]; + s8 last_rssi; struct rs_rate_stats tx_stats[RS_COLUMN_COUNT][IWL_RATE_COUNT]; struct iwl_mvm *drv; } pers; -- GitLab From 1738d60b31d7792516426d62521ec65bff8281f5 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 22 May 2015 12:09:44 +0200 Subject: [PATCH 0255/7006] iwlwifi: mvm: handle RX MPDUs separately There's no need to forward RX MPDUs to notification wait tests, nor do we need to check them for firmware dump triggers, nor could they be asynchronous. It's thus more efficient to handle them separately, before going into the regular RX handlers. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/ops.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffdc..8f896cd1c9cd1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -221,7 +221,6 @@ struct iwl_rx_handlers { * called from a worker with mvm->mutex held. */ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { - RX_HANDLER(REPLY_RX_MPDU_CMD, iwl_mvm_rx_rx_mpdu, false), RX_HANDLER(REPLY_RX_PHY_CMD, iwl_mvm_rx_rx_phy_cmd, false), RX_HANDLER(TX_CMD, iwl_mvm_rx_tx_cmd, false), RX_HANDLER(BA_NOTIF, iwl_mvm_rx_ba_notif, false), @@ -716,6 +715,9 @@ static int iwl_mvm_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); u8 i; + if (likely(pkt->hdr.cmd == REPLY_RX_MPDU_CMD)) + return iwl_mvm_rx_rx_mpdu(mvm, rxb, cmd); + iwl_mvm_rx_check_trigger(mvm, pkt); /* -- GitLab From 6c7d32cfdc622ef4b9f157592fc167513507270d Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Sun, 7 Jun 2015 09:34:57 +0300 Subject: [PATCH 0256/7006] iwlwifi: deprecate -10.ucode for 3160 / 7260 / 7265 This firmware is not supported anymore - stop loading this firmware. Remove code handling older versions. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- drivers/net/wireless/iwlwifi/mvm/fw.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index cc35f796d4061..fa35da4edda26 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -76,7 +76,7 @@ #define IWL3165_UCODE_API_OK 13 /* Lowest firmware API version supported */ -#define IWL7260_UCODE_API_MIN 10 +#define IWL7260_UCODE_API_MIN 12 #define IWL3165_UCODE_API_MIN 13 /* NVM versions */ diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 72040cd0b9794..0de575124fa2a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -75,7 +75,7 @@ #define IWL8000_UCODE_API_OK 12 /* Lowest firmware API version supported */ -#define IWL8000_UCODE_API_MIN 10 +#define IWL8000_UCODE_API_MIN 12 /* NVM versions */ #define IWL8000_NVM_VERSION 0x0a1d diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c index eb10c5ee4a140..a482ce692f5f8 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw.c +++ b/drivers/net/wireless/iwlwifi/mvm/fw.c @@ -676,8 +676,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm) goto error; } - if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10) - iwl_mvm_get_shared_mem_conf(mvm); + iwl_mvm_get_shared_mem_conf(mvm); ret = iwl_mvm_sf_update(mvm, NULL, false); if (ret) -- GitLab From 012c02c15ac63b0b26c7f058c744e85cb563a737 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Tue, 16 Jun 2015 22:37:40 +0300 Subject: [PATCH 0257/7006] iwlwifi: dvm: start HW before running FW The new locking in PCIe transport requires to start_hw before start_fw. This uncovered a bug in dvm which failed to do so. Fix that. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/mac80211.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index 7acaa266b7046..f603fb3122f74 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -250,12 +250,24 @@ static int __iwl_up(struct iwl_priv *priv) } } + ret = iwl_trans_start_hw(priv->trans); + if (ret) { + IWL_ERR(priv, "Failed to start HW: %d\n", ret); + goto error; + } + ret = iwl_run_init_ucode(priv); if (ret) { IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret); goto error; } + ret = iwl_trans_start_hw(priv->trans); + if (ret) { + IWL_ERR(priv, "Failed to start HW: %d\n", ret); + goto error; + } + ret = iwl_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR); if (ret) { IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret); -- GitLab From fa9f3281cbb1075545d4528c84059a3f4e117b44 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Thu, 11 Jun 2015 20:45:49 +0300 Subject: [PATCH 0258/7006] iwlwifi: pcie: lock start_hw / start_fw / stop_device This allows to ensure that we don't have races between them. A user reported that stop_device was called twice upon rfkill interrupt after suspend. When the interrupts are enabled, and right after when we directly check the rfkill state. Reviewed-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/pcie/drv.c | 4 + drivers/net/wireless/iwlwifi/pcie/internal.h | 3 + drivers/net/wireless/iwlwifi/pcie/rx.c | 2 + drivers/net/wireless/iwlwifi/pcie/trans.c | 82 +++++++++++++++++--- 4 files changed, 81 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c index 2ed1e4d2774da..dbd2a03a0f6d4 100644 --- a/drivers/net/wireless/iwlwifi/pcie/drv.c +++ b/drivers/net/wireless/iwlwifi/pcie/drv.c @@ -613,6 +613,7 @@ static int iwl_pci_resume(struct device *device) { struct pci_dev *pdev = to_pci_dev(device); struct iwl_trans *trans = pci_get_drvdata(pdev); + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; /* Before you put code here, think about WoWLAN. You cannot check here @@ -643,7 +644,10 @@ static int iwl_pci_resume(struct device *device) } hw_rfkill = iwl_is_rfkill_set(trans); + + mutex_lock(&trans_pcie->mutex); iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); return 0; } diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 31f72a61cc3fe..4f0640767d307 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -301,6 +301,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx) * @scd_set_active: should the transport configure the SCD for HCMD queue * @rx_page_order: page order for receive buffer size * @reg_lock: protect hw register access + * @mutex: to protect stop_device / start_fw / start_hw * @cmd_in_flight: true when we have a host command in flight * @fw_mon_phys: physical address of the buffer for the firmware monitor * @fw_mon_page: points to the first page of the buffer for the firmware monitor @@ -320,9 +321,11 @@ struct iwl_trans_pcie { dma_addr_t ict_tbl_dma; int ict_index; bool use_ict; + bool is_down; struct isr_statistics isr_stats; spinlock_t irq_lock; + struct mutex mutex; u32 inta_mask; u32 scd_base_addr; struct iwl_dma_ptr scd_bc_tbls; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index a3fbaa0ef5e04..93062f2e8f563 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -1251,7 +1251,9 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id) isr_stats->rfkill++; + mutex_lock(&trans_pcie->mutex); iwl_trans_pcie_rf_kill(trans, hw_rfkill); + mutex_unlock(&trans_pcie->mutex); if (hw_rfkill) { set_bit(STATUS_RFKILL, &trans->status); if (test_and_clear_bit(STATUS_SYNC_HCMD_ACTIVE, diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 43ae658af6ec5..23f2824e8d562 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -982,13 +982,25 @@ static int iwl_pcie_load_given_ucode_8000(struct iwl_trans *trans, static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, const struct fw_img *fw, bool run_in_rfkill) { - int ret; + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; + int ret; + + mutex_lock(&trans_pcie->mutex); + + /* Someone called stop_device, don't try to start_fw */ + if (trans_pcie->is_down) { + IWL_WARN(trans, + "Can't start_fw since the HW hasn't been started\n"); + ret = EIO; + goto out; + } /* This may fail if AMT took ownership of the device */ if (iwl_pcie_prepare_card_hw(trans)) { IWL_WARN(trans, "Exit HW not ready\n"); - return -EIO; + ret = -EIO; + goto out; } iwl_enable_rfkill_int(trans); @@ -1000,15 +1012,17 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, else clear_bit(STATUS_RFKILL, &trans->status); iwl_trans_pcie_rf_kill(trans, hw_rfkill); - if (hw_rfkill && !run_in_rfkill) - return -ERFKILL; + if (hw_rfkill && !run_in_rfkill) { + ret = -ERFKILL; + goto out; + } iwl_write32(trans, CSR_INT, 0xFFFFFFFF); ret = iwl_pcie_nic_init(trans); if (ret) { IWL_ERR(trans, "Unable to init nic\n"); - return ret; + goto out; } /* make sure rfkill handshake bits are cleared */ @@ -1026,9 +1040,13 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans, /* Load the given image to the HW */ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) - return iwl_pcie_load_given_ucode_8000(trans, fw); + ret = iwl_pcie_load_given_ucode_8000(trans, fw); else - return iwl_pcie_load_given_ucode(trans, fw); + ret = iwl_pcie_load_given_ucode(trans, fw); + +out: + mutex_unlock(&trans_pcie->mutex); + return ret; } static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) @@ -1037,11 +1055,18 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr) iwl_pcie_tx_start(trans, scd_addr); } -static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +static void _iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill, was_hw_rfkill; + lockdep_assert_held(&trans_pcie->mutex); + + if (trans_pcie->is_down) + return; + + trans_pcie->is_down = true; + was_hw_rfkill = iwl_is_rfkill_set(trans); /* tell the device to stop sending interrupts */ @@ -1131,10 +1156,24 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) iwl_pcie_prepare_card_hw(trans); } +static void iwl_trans_pcie_stop_device(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + + mutex_lock(&trans_pcie->mutex); + _iwl_trans_pcie_stop_device(trans, low_power); + mutex_unlock(&trans_pcie->mutex); +} + void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state) { + struct iwl_trans_pcie __maybe_unused *trans_pcie = + IWL_TRANS_GET_PCIE_TRANS(trans); + + lockdep_assert_held(&trans_pcie->mutex); + if (iwl_op_mode_hw_rf_kill(trans->op_mode, state)) - iwl_trans_pcie_stop_device(trans, true); + _iwl_trans_pcie_stop_device(trans, true); } static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test) @@ -1219,11 +1258,14 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans, return 0; } -static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) { + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); bool hw_rfkill; int err; + lockdep_assert_held(&trans_pcie->mutex); + err = iwl_pcie_prepare_card_hw(trans); if (err) { IWL_ERR(trans, "Error while preparing HW: %d\n", err); @@ -1240,20 +1282,38 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) /* From now on, the op_mode will be kept updated about RF kill state */ iwl_enable_rfkill_int(trans); + /* Set is_down to false here so that...*/ + trans_pcie->is_down = false; + hw_rfkill = iwl_is_rfkill_set(trans); if (hw_rfkill) set_bit(STATUS_RFKILL, &trans->status); else clear_bit(STATUS_RFKILL, &trans->status); + /* ... rfkill can call stop_device and set it false if needed */ iwl_trans_pcie_rf_kill(trans, hw_rfkill); return 0; } +static int iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power) +{ + struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + int ret; + + mutex_lock(&trans_pcie->mutex); + ret = _iwl_trans_pcie_start_hw(trans, low_power); + mutex_unlock(&trans_pcie->mutex); + + return ret; +} + static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); + mutex_lock(&trans_pcie->mutex); + /* disable interrupts - don't enable HW RF kill interrupt */ spin_lock(&trans_pcie->irq_lock); iwl_disable_interrupts(trans); @@ -1266,6 +1326,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans) spin_unlock(&trans_pcie->irq_lock); iwl_pcie_disable_ict(trans); + mutex_unlock(&trans_pcie->mutex); } static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val) @@ -2472,6 +2533,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, spin_lock_init(&trans_pcie->irq_lock); spin_lock_init(&trans_pcie->reg_lock); spin_lock_init(&trans_pcie->ref_lock); + mutex_init(&trans_pcie->mutex); init_waitqueue_head(&trans_pcie->ucode_write_waitq); err = pci_enable_device(pdev); -- GitLab From 5b7e4c9ce19038f88828309a0a61f5d5c6686d37 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:03 +0300 Subject: [PATCH 0259/7006] drm/i915/gtt: Mark TLBS dirty for gen8+ When we touch gen8+ page maps, mark them dirty like we do with previous gens. v2: Update comment (Joonas) Signed-off-by: Mika Kuoppala Reviewed-by: Joonas Lahtinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2279e030570cd..bc41063756501 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -831,6 +831,16 @@ err_out: return -ENOMEM; } +/* PDE TLBs are a pain to invalidate on GEN8+. When we modify + * the page table structures, we mark them dirty so that + * context switching/execlist queuing code takes extra steps + * to ensure that tlbs are flushed. + */ +static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt) +{ + ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask; +} + static int gen8_alloc_va_range(struct i915_address_space *vm, uint64_t start, uint64_t length) @@ -916,6 +926,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, } free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); + mark_tlbs_dirty(ppgtt); return 0; err_out: @@ -928,6 +939,7 @@ err_out: unmap_and_free_pd(ppgtt->pdp.page_directory[pdpe], vm->dev); free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); + mark_tlbs_dirty(ppgtt); return ret; } @@ -1272,16 +1284,6 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_atomic(pt_vaddr); } -/* PDE TLBs are a pain invalidate pre GEN8. It requires a context reload. If we - * are switching between contexts with the same LRCA, we also must do a force - * restore. - */ -static void mark_tlbs_dirty(struct i915_hw_ppgtt *ppgtt) -{ - /* If current vm != vm, */ - ppgtt->pd_dirty_rings = INTEL_INFO(ppgtt->base.dev)->ring_mask; -} - static void gen6_initialize_pt(struct i915_address_space *vm, struct i915_page_table *pt) { -- GitLab From a05d80eec27460a2dca06676d489637e25f93caf Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:04 +0300 Subject: [PATCH 0260/7006] drm/i915/gtt: Check va range against vm size Check the allocation area against the known end of address space instead of against fixed value. v2: Return ENODEV on internal bugs (Chris) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index bc41063756501..68705e381adae 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -757,9 +757,6 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, WARN_ON(!bitmap_empty(new_pds, GEN8_LEGACY_PDPES)); - /* FIXME: upper bound must not overflow 32 bits */ - WARN_ON((start + length) > (1ULL << 32)); - gen8_for_each_pdpe(pd, pdp, start, length, temp, pdpe) { if (pd) continue; @@ -859,7 +856,10 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, * actually use the other side of the canonical address space. */ if (WARN_ON(start + length < start)) - return -ERANGE; + return -ENODEV; + + if (WARN_ON(start + length > ppgtt->base.total)) + return -ENODEV; ret = alloc_gen8_temp_bitmaps(&new_page_dirs, &new_page_tables); if (ret) @@ -1304,7 +1304,7 @@ static void gen6_initialize_pt(struct i915_address_space *vm, } static int gen6_alloc_va_range(struct i915_address_space *vm, - uint64_t start, uint64_t length) + uint64_t start_in, uint64_t length_in) { DECLARE_BITMAP(new_page_tables, I915_PDES); struct drm_device *dev = vm->dev; @@ -1312,11 +1312,15 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, struct i915_hw_ppgtt *ppgtt = container_of(vm, struct i915_hw_ppgtt, base); struct i915_page_table *pt; - const uint32_t start_save = start, length_save = length; + uint32_t start, length, start_save, length_save; uint32_t pde, temp; int ret; - WARN_ON(upper_32_bits(start)); + if (WARN_ON(start_in + length_in > ppgtt->base.total)) + return -ENODEV; + + start = start_save = start_in; + length = length_save = length_in; bitmap_zero(new_page_tables, I915_PDES); -- GitLab From c44ef60e437019b8ca1dab8b4d2e8761fd4ce1e9 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:05 +0300 Subject: [PATCH 0261/7006] drm/i915/gtt: Allow >= 4GB sizes for vm. We can have exactly 4GB sized ppgtt with 32bit system. size_t is inadequate for this. v2: Convert a lot more places (Daniel) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/char/agp/intel-gtt.c | 4 +-- drivers/gpu/drm/i915/i915_debugfs.c | 42 ++++++++++++++--------------- drivers/gpu/drm/i915/i915_gem.c | 6 ++--- drivers/gpu/drm/i915/i915_gem_gtt.c | 22 +++++++-------- drivers/gpu/drm/i915/i915_gem_gtt.h | 12 ++++----- include/drm/intel-gtt.h | 4 +-- 6 files changed, 45 insertions(+), 45 deletions(-) diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c index 0b4188b9af7cd..4734d02ca8991 100644 --- a/drivers/char/agp/intel-gtt.c +++ b/drivers/char/agp/intel-gtt.c @@ -1408,8 +1408,8 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, } EXPORT_SYMBOL(intel_gmch_probe); -void intel_gtt_get(size_t *gtt_total, size_t *stolen_size, - phys_addr_t *mappable_base, unsigned long *mappable_end) +void intel_gtt_get(u64 *gtt_total, size_t *stolen_size, + phys_addr_t *mappable_base, u64 *mappable_end) { *gtt_total = intel_private.gtt_total_entries << PAGE_SHIFT; *stolen_size = intel_private.stolen_size; diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 495a6376cf39a..bd0fbd6caac28 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -198,7 +198,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) struct drm_i915_private *dev_priv = dev->dev_private; struct i915_address_space *vm = &dev_priv->gtt.base; struct i915_vma *vma; - size_t total_obj_size, total_gtt_size; + u64 total_obj_size, total_gtt_size; int count, ret; ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -231,7 +231,7 @@ static int i915_gem_object_list_info(struct seq_file *m, void *data) } mutex_unlock(&dev->struct_mutex); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", count, total_obj_size, total_gtt_size); return 0; } @@ -253,7 +253,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; - size_t total_obj_size, total_gtt_size; + u64 total_obj_size, total_gtt_size; LIST_HEAD(stolen); int count, ret; @@ -292,7 +292,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) } mutex_unlock(&dev->struct_mutex); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", count, total_obj_size, total_gtt_size); return 0; } @@ -310,10 +310,10 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) struct file_stats { struct drm_i915_file_private *file_priv; - int count; - size_t total, unbound; - size_t global, shared; - size_t active, inactive; + unsigned long count; + u64 total, unbound; + u64 global, shared; + u64 active, inactive; }; static int per_file_stats(int id, void *ptr, void *data) @@ -370,7 +370,7 @@ static int per_file_stats(int id, void *ptr, void *data) #define print_file_stats(m, name, stats) do { \ if (stats.count) \ - seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \ + seq_printf(m, "%s: %lu objects, %llu bytes (%llu active, %llu inactive, %llu global, %llu shared, %llu unbound)\n", \ name, \ stats.count, \ stats.total, \ @@ -420,7 +420,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) struct drm_device *dev = node->minor->dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 count, mappable_count, purgeable_count; - size_t size, mappable_size, purgeable_size; + u64 size, mappable_size, purgeable_size; struct drm_i915_gem_object *obj; struct i915_address_space *vm = &dev_priv->gtt.base; struct drm_file *file; @@ -437,17 +437,17 @@ static int i915_gem_object_info(struct seq_file *m, void* data) size = count = mappable_size = mappable_count = 0; count_objects(&dev_priv->mm.bound_list, global_list); - seq_printf(m, "%u [%u] objects, %zu [%zu] bytes in gtt\n", + seq_printf(m, "%u [%u] objects, %llu [%llu] bytes in gtt\n", count, mappable_count, size, mappable_size); size = count = mappable_size = mappable_count = 0; count_vmas(&vm->active_list, mm_list); - seq_printf(m, " %u [%u] active objects, %zu [%zu] bytes\n", + seq_printf(m, " %u [%u] active objects, %llu [%llu] bytes\n", count, mappable_count, size, mappable_size); size = count = mappable_size = mappable_count = 0; count_vmas(&vm->inactive_list, mm_list); - seq_printf(m, " %u [%u] inactive objects, %zu [%zu] bytes\n", + seq_printf(m, " %u [%u] inactive objects, %llu [%llu] bytes\n", count, mappable_count, size, mappable_size); size = count = purgeable_size = purgeable_count = 0; @@ -456,7 +456,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data) if (obj->madv == I915_MADV_DONTNEED) purgeable_size += obj->base.size, ++purgeable_count; } - seq_printf(m, "%u unbound objects, %zu bytes\n", count, size); + seq_printf(m, "%u unbound objects, %llu bytes\n", count, size); size = count = mappable_size = mappable_count = 0; list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) { @@ -473,16 +473,16 @@ static int i915_gem_object_info(struct seq_file *m, void* data) ++purgeable_count; } } - seq_printf(m, "%u purgeable objects, %zu bytes\n", + seq_printf(m, "%u purgeable objects, %llu bytes\n", purgeable_count, purgeable_size); - seq_printf(m, "%u pinned mappable objects, %zu bytes\n", + seq_printf(m, "%u pinned mappable objects, %llu bytes\n", mappable_count, mappable_size); - seq_printf(m, "%u fault mappable objects, %zu bytes\n", + seq_printf(m, "%u fault mappable objects, %llu bytes\n", count, size); - seq_printf(m, "%zu [%lu] gtt total\n", + seq_printf(m, "%llu [%llu] gtt total\n", dev_priv->gtt.base.total, - dev_priv->gtt.mappable_end - dev_priv->gtt.base.start); + (u64)dev_priv->gtt.mappable_end - dev_priv->gtt.base.start); seq_putc(m, '\n'); print_batch_pool_stats(m, dev_priv); @@ -519,7 +519,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) uintptr_t list = (uintptr_t) node->info_ent->data; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_object *obj; - size_t total_obj_size, total_gtt_size; + u64 total_obj_size, total_gtt_size; int count, ret; ret = mutex_lock_interruptible(&dev->struct_mutex); @@ -541,7 +541,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) mutex_unlock(&dev->struct_mutex); - seq_printf(m, "Total %d objects, %zu bytes, %zu GTT size\n", + seq_printf(m, "Total %d objects, %llu bytes, %llu GTT size\n", count, total_obj_size, total_gtt_size); return 0; diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index f79ce9f223120..db1955fad0059 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -3712,9 +3712,9 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; u32 size, fence_size, fence_alignment, unfenced_alignment; - unsigned long start = + u64 start = flags & PIN_OFFSET_BIAS ? flags & PIN_OFFSET_MASK : 0; - unsigned long end = + u64 end = flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total; struct i915_vma *vma; int ret; @@ -3770,7 +3770,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj, * attempt to find space. */ if (size > end) { - DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%lu\n", + DRM_DEBUG("Attempting to bind an object (view type=%u) larger than the aperture: size=%u > %s aperture=%llu\n", ggtt_view ? ggtt_view->type : 0, size, flags & PIN_MAPPABLE ? "mappable" : "total", diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 68705e381adae..7a7789e18f388 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2112,7 +2112,7 @@ static int i915_gem_setup_global_gtt(struct drm_device *dev, void i915_gem_init_global_gtt(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long gtt_size, mappable_size; + u64 gtt_size, mappable_size; gtt_size = dev_priv->gtt.base.total; mappable_size = dev_priv->gtt.mappable_end; @@ -2369,13 +2369,13 @@ static void chv_setup_private_ppat(struct drm_i915_private *dev_priv) } static int gen8_gmch_probe(struct drm_device *dev, - size_t *gtt_total, + u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end) + u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; - unsigned int gtt_size; + u64 gtt_size; u16 snb_gmch_ctl; int ret; @@ -2417,10 +2417,10 @@ static int gen8_gmch_probe(struct drm_device *dev, } static int gen6_gmch_probe(struct drm_device *dev, - size_t *gtt_total, + u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end) + u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; unsigned int gtt_size; @@ -2434,7 +2434,7 @@ static int gen6_gmch_probe(struct drm_device *dev, * a coarse sanity check. */ if ((*mappable_end < (64<<20) || (*mappable_end > (512<<20)))) { - DRM_ERROR("Unknown GMADR size (%lx)\n", + DRM_ERROR("Unknown GMADR size (%llx)\n", dev_priv->gtt.mappable_end); return -ENXIO; } @@ -2468,10 +2468,10 @@ static void gen6_gmch_remove(struct i915_address_space *vm) } static int i915_gmch_probe(struct drm_device *dev, - size_t *gtt_total, + u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end) + u64 *mappable_end) { struct drm_i915_private *dev_priv = dev->dev_private; int ret; @@ -2536,9 +2536,9 @@ int i915_gem_gtt_init(struct drm_device *dev) gtt->base.dev = dev; /* GMADR is the PCI mmio aperture into the global GTT. */ - DRM_INFO("Memory usable by graphics device = %zdM\n", + DRM_INFO("Memory usable by graphics device = %lluM\n", gtt->base.total >> 20); - DRM_DEBUG_DRIVER("GMADR size = %ldM\n", gtt->mappable_end >> 20); + DRM_DEBUG_DRIVER("GMADR size = %lldM\n", gtt->mappable_end >> 20); DRM_DEBUG_DRIVER("GTT stolen size = %zdM\n", gtt->stolen_size >> 20); #ifdef CONFIG_INTEL_IOMMU if (intel_iommu_gfx_mapped) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 017ea308f8b41..600eec00a1f43 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -235,8 +235,8 @@ struct i915_address_space { struct drm_mm mm; struct drm_device *dev; struct list_head global_link; - unsigned long start; /* Start offset always 0 for dri2 */ - size_t total; /* size addr space maps (ex. 2GB for ggtt) */ + u64 start; /* Start offset always 0 for dri2 */ + u64 total; /* size addr space maps (ex. 2GB for ggtt) */ struct { dma_addr_t addr; @@ -302,9 +302,9 @@ struct i915_address_space { */ struct i915_gtt { struct i915_address_space base; - size_t stolen_size; /* Total size of stolen memory */ - unsigned long mappable_end; /* End offset that we can CPU map */ + size_t stolen_size; /* Total size of stolen memory */ + u64 mappable_end; /* End offset that we can CPU map */ struct io_mapping *mappable; /* Mapping to our CPU mappable region */ phys_addr_t mappable_base; /* PA of our GMADR */ @@ -316,9 +316,9 @@ struct i915_gtt { int mtrr; /* global gtt ops */ - int (*gtt_probe)(struct drm_device *dev, size_t *gtt_total, + int (*gtt_probe)(struct drm_device *dev, u64 *gtt_total, size_t *stolen, phys_addr_t *mappable_base, - unsigned long *mappable_end); + u64 *mappable_end); }; struct i915_hw_ppgtt { diff --git a/include/drm/intel-gtt.h b/include/drm/intel-gtt.h index b08bdade60025..9e9bddaa58a50 100644 --- a/include/drm/intel-gtt.h +++ b/include/drm/intel-gtt.h @@ -3,8 +3,8 @@ #ifndef _DRM_INTEL_GTT_H #define _DRM_INTEL_GTT_H -void intel_gtt_get(size_t *gtt_total, size_t *stolen_size, - phys_addr_t *mappable_base, unsigned long *mappable_end); +void intel_gtt_get(u64 *gtt_total, size_t *stolen_size, + phys_addr_t *mappable_base, u64 *mappable_end); int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev, struct agp_bridge_data *bridge); -- GitLab From d852c7bf902aa36f37b6fd0bb1147c922e7bd0fb Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:06 +0300 Subject: [PATCH 0262/7006] drm/i915/gtt: Introduce i915_page_dir_dma_addr The legacy mode mm switch and the execlist context assignment needs dma address for the page directories. Introduce a function that encapsulates the scratch_pd dma fallback if no pd is found. v2: Rebase, s/ring/req Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry (v1) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++---- drivers/gpu/drm/i915/i915_gem_gtt.h | 8 ++++++++ drivers/gpu/drm/i915/intel_lrc.c | 4 +--- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 7a7789e18f388..47e8e2eec26d0 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -482,10 +482,8 @@ static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt, int i, ret; for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) { - struct i915_page_directory *pd = ppgtt->pdp.page_directory[i]; - dma_addr_t pd_daddr = pd ? pd->daddr : ppgtt->scratch_pd->daddr; - /* The page directory might be NULL, but we need to clear out - * whatever the previous context might have used. */ + const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); + ret = gen8_write_pdp(req, i, pd_daddr); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 600eec00a1f43..f368c71552232 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -470,6 +470,14 @@ static inline size_t gen8_pte_count(uint64_t address, uint64_t length) return i915_pte_count(address, length, GEN8_PDE_SHIFT); } +static inline dma_addr_t +i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) +{ + return test_bit(n, ppgtt->pdp.used_pdpes) ? + ppgtt->pdp.page_directory[n]->daddr : + ppgtt->scratch_pd->daddr; +} + int i915_gem_gtt_init(struct drm_device *dev); void i915_gem_init_global_gtt(struct drm_device *dev); void i915_global_gtt_cleanup(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 90a02dc5245ef..fd25314fc913b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -190,9 +190,7 @@ #define GEN8_CTX_PRIVILEGE (1<<8) #define ASSIGN_CTX_PDP(ppgtt, reg_state, n) { \ - const u64 _addr = test_bit(n, ppgtt->pdp.used_pdpes) ? \ - ppgtt->pdp.page_directory[n]->daddr : \ - ppgtt->scratch_pd->daddr; \ + const u64 _addr = i915_page_dir_dma_addr((ppgtt), (n)); \ reg_state[CTX_PDP ## n ## _UDW+1] = upper_32_bits(_addr); \ reg_state[CTX_PDP ## n ## _LDW+1] = lower_32_bits(_addr); \ } -- GitLab From 44159ddbeac3d34e5ca9037e151a242b7388df8e Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:07 +0300 Subject: [PATCH 0263/7006] drm/i915/gtt: Introduce struct i915_page_dma All our paging structures have struct page and dma address for that page. Add struct for page/dma address pairs and use it to make the setup and teardown for different paging structures identical. Include the page directory offset also in the struct for legacy gens. Rename it to clearly point out that it is offset into the ggtt. v2: Add comment about ggtt_offset (Michel) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_gem_gtt.c | 120 +++++++++++----------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 25 +++--- 3 files changed, 64 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bd0fbd6caac28..b509844df0dd1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2227,7 +2227,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev) struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt; seq_puts(m, "aliasing PPGTT:\n"); - seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd.pd_offset); + seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd.base.ggtt_offset); ppgtt->debug_dump(ppgtt, m); } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 47e8e2eec26d0..a7bdbeb469041 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -301,52 +301,39 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr, return pte; } -#define i915_dma_unmap_single(px, dev) \ - __i915_dma_unmap_single((px)->daddr, dev) - -static void __i915_dma_unmap_single(dma_addr_t daddr, - struct drm_device *dev) +static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) { struct device *device = &dev->pdev->dev; - dma_unmap_page(device, daddr, 4096, PCI_DMA_BIDIRECTIONAL); -} - -/** - * i915_dma_map_single() - Create a dma mapping for a page table/dir/etc. - * @px: Page table/dir/etc to get a DMA map for - * @dev: drm device - * - * Page table allocations are unified across all gens. They always require a - * single 4k allocation, as well as a DMA mapping. If we keep the structs - * symmetric here, the simple macro covers us for every page table type. - * - * Return: 0 if success. - */ -#define i915_dma_map_single(px, dev) \ - i915_dma_map_page_single((px)->page, (dev), &(px)->daddr) + p->page = alloc_page(GFP_KERNEL); + if (!p->page) + return -ENOMEM; -static int i915_dma_map_page_single(struct page *page, - struct drm_device *dev, - dma_addr_t *daddr) -{ - struct device *device = &dev->pdev->dev; + p->daddr = dma_map_page(device, + p->page, 0, 4096, PCI_DMA_BIDIRECTIONAL); - *daddr = dma_map_page(device, page, 0, 4096, PCI_DMA_BIDIRECTIONAL); - if (dma_mapping_error(device, *daddr)) - return -ENOMEM; + if (dma_mapping_error(device, p->daddr)) { + __free_page(p->page); + return -EINVAL; + } return 0; } -static void unmap_and_free_pt(struct i915_page_table *pt, - struct drm_device *dev) +static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) { - if (WARN_ON(!pt->page)) + if (WARN_ON(!p->page)) return; - i915_dma_unmap_single(pt, dev); - __free_page(pt->page); + dma_unmap_page(&dev->pdev->dev, p->daddr, 4096, PCI_DMA_BIDIRECTIONAL); + __free_page(p->page); + memset(p, 0, sizeof(*p)); +} + +static void unmap_and_free_pt(struct i915_page_table *pt, + struct drm_device *dev) +{ + cleanup_page_dma(dev, &pt->base); kfree(pt->used_ptes); kfree(pt); } @@ -357,7 +344,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, gen8_pte_t *pt_vaddr, scratch_pte; int i; - pt_vaddr = kmap_atomic(pt->page); + pt_vaddr = kmap_atomic(pt->base.page); scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); @@ -386,19 +373,13 @@ static struct i915_page_table *alloc_pt(struct drm_device *dev) if (!pt->used_ptes) goto fail_bitmap; - pt->page = alloc_page(GFP_KERNEL); - if (!pt->page) - goto fail_page; - - ret = i915_dma_map_single(pt, dev); + ret = setup_page_dma(dev, &pt->base); if (ret) - goto fail_dma; + goto fail_page_m; return pt; -fail_dma: - __free_page(pt->page); -fail_page: +fail_page_m: kfree(pt->used_ptes); fail_bitmap: kfree(pt); @@ -409,9 +390,8 @@ fail_bitmap: static void unmap_and_free_pd(struct i915_page_directory *pd, struct drm_device *dev) { - if (pd->page) { - i915_dma_unmap_single(pd, dev); - __free_page(pd->page); + if (pd->base.page) { + cleanup_page_dma(dev, &pd->base); kfree(pd->used_pdes); kfree(pd); } @@ -431,18 +411,12 @@ static struct i915_page_directory *alloc_pd(struct drm_device *dev) if (!pd->used_pdes) goto free_pd; - pd->page = alloc_page(GFP_KERNEL); - if (!pd->page) - goto free_bitmap; - - ret = i915_dma_map_single(pd, dev); + ret = setup_page_dma(dev, &pd->base); if (ret) - goto free_page; + goto free_bitmap; return pd; -free_page: - __free_page(pd->page); free_bitmap: kfree(pd->used_pdes); free_pd: @@ -524,10 +498,10 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, pt = pd->page_table[pde]; - if (WARN_ON(!pt->page)) + if (WARN_ON(!pt->base.page)) continue; - page_table = pt->page; + page_table = pt->base.page; last_pte = pte + num_entries; if (last_pte > GEN8_PTES) @@ -574,7 +548,7 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, if (pt_vaddr == NULL) { struct i915_page_directory *pd = ppgtt->pdp.page_directory[pdpe]; struct i915_page_table *pt = pd->page_table[pde]; - struct page *page_table = pt->page; + struct page *page_table = pt->base.page; pt_vaddr = kmap_atomic(page_table); } @@ -606,7 +580,7 @@ static void __gen8_do_map_pt(gen8_pde_t * const pde, struct drm_device *dev) { gen8_pde_t entry = - gen8_pde_encode(dev, pt->daddr, I915_CACHE_LLC); + gen8_pde_encode(dev, pt->base.daddr, I915_CACHE_LLC); *pde = entry; } @@ -619,7 +593,7 @@ static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_table *pt; int i; - page_directory = kmap_atomic(pd->page); + page_directory = kmap_atomic(pd->base.page); pt = ppgtt->scratch_pt; for (i = 0; i < I915_PDES; i++) /* Map the PDE to the page table */ @@ -634,7 +608,7 @@ static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_dev { int i; - if (!pd->page) + if (!pd->base.page) return; for_each_set_bit(i, pd->used_pdes, I915_PDES) { @@ -885,7 +859,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, /* Allocations have completed successfully, so set the bitmaps, and do * the mappings. */ gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) { - gen8_pde_t *const page_directory = kmap_atomic(pd->page); + gen8_pde_t *const page_directory = kmap_atomic(pd->base.page); struct i915_page_table *pt; uint64_t pd_len = gen8_clamp_pd(start, length); uint64_t pd_start = start; @@ -996,7 +970,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; gen6_pte_t *pt_vaddr; - dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->daddr; + dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->base.daddr; pd_entry = readl(ppgtt->pd_addr + pde); expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); @@ -1007,7 +981,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) expected); seq_printf(m, "\tPDE: %x\n", pd_entry); - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->page); + pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->base.page); for (pte = 0; pte < GEN6_PTES; pte+=4) { unsigned long va = (pde * PAGE_SIZE * GEN6_PTES) + @@ -1042,7 +1016,7 @@ static void gen6_write_pde(struct i915_page_directory *pd, container_of(pd, struct i915_hw_ppgtt, pd); u32 pd_entry; - pd_entry = GEN6_PDE_ADDR_ENCODE(pt->daddr); + pd_entry = GEN6_PDE_ADDR_ENCODE(pt->base.daddr); pd_entry |= GEN6_PDE_VALID; writel(pd_entry, ppgtt->pd_addr + pde); @@ -1067,9 +1041,9 @@ static void gen6_write_page_range(struct drm_i915_private *dev_priv, static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt) { - BUG_ON(ppgtt->pd.pd_offset & 0x3f); + BUG_ON(ppgtt->pd.base.ggtt_offset & 0x3f); - return (ppgtt->pd.pd_offset / 64) << 16; + return (ppgtt->pd.base.ggtt_offset / 64) << 16; } static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt, @@ -1236,7 +1210,7 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, if (last_pte > GEN6_PTES) last_pte = GEN6_PTES; - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page); + pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); for (i = first_pte; i < last_pte; i++) pt_vaddr[i] = scratch_pte; @@ -1265,7 +1239,7 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, pt_vaddr = NULL; for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { if (pt_vaddr == NULL) - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->page); + pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); pt_vaddr[act_pte] = vm->pte_encode(sg_page_iter_dma_address(&sg_iter), @@ -1293,7 +1267,7 @@ static void gen6_initialize_pt(struct i915_address_space *vm, scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); - pt_vaddr = kmap_atomic(pt->page); + pt_vaddr = kmap_atomic(pt->base.page); for (i = 0; i < GEN6_PTES; i++) pt_vaddr[i] = scratch_pte; @@ -1509,11 +1483,11 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->base.total = I915_PDES * GEN6_PTES * PAGE_SIZE; ppgtt->debug_dump = gen6_dump_ppgtt; - ppgtt->pd.pd_offset = + ppgtt->pd.base.ggtt_offset = ppgtt->node.start / PAGE_SIZE * sizeof(gen6_pte_t); ppgtt->pd_addr = (gen6_pte_t __iomem *)dev_priv->gtt.gsm + - ppgtt->pd.pd_offset / sizeof(gen6_pte_t); + ppgtt->pd.base.ggtt_offset / sizeof(gen6_pte_t); gen6_scratch_va_range(ppgtt, 0, ppgtt->base.total); @@ -1524,7 +1498,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) ppgtt->node.start / PAGE_SIZE); DRM_DEBUG("Adding PPGTT at offset %x\n", - ppgtt->pd.pd_offset << 10); + ppgtt->pd.base.ggtt_offset << 10); return 0; } diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index f368c71552232..c681573b4005c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -207,19 +207,26 @@ struct i915_vma { #define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf }; -struct i915_page_table { +struct i915_page_dma { struct page *page; - dma_addr_t daddr; + union { + dma_addr_t daddr; + + /* For gen6/gen7 only. This is the offset in the GGTT + * where the page directory entries for PPGTT begin + */ + uint32_t ggtt_offset; + }; +}; + +struct i915_page_table { + struct i915_page_dma base; unsigned long *used_ptes; }; struct i915_page_directory { - struct page *page; /* NULL for GEN6-GEN7 */ - union { - uint32_t pd_offset; - dma_addr_t daddr; - }; + struct i915_page_dma base; unsigned long *used_pdes; struct i915_page_table *page_table[I915_PDES]; /* PDEs */ @@ -474,8 +481,8 @@ static inline dma_addr_t i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) { return test_bit(n, ppgtt->pdp.used_pdpes) ? - ppgtt->pdp.page_directory[n]->daddr : - ppgtt->scratch_pd->daddr; + ppgtt->pdp.page_directory[n]->base.daddr : + ppgtt->scratch_pd->base.daddr; } int i915_gem_gtt_init(struct drm_device *dev); -- GitLab From a08e111a6cc88514155b087e0c307581064352b5 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:08 +0300 Subject: [PATCH 0264/7006] drm/i915/gtt: Rename unmap_and_free_px to free_px All the paging structures are now similar and mapped for dma. The unmapping is taken care of by common accessors, so don't overload the reader with such details. v2: Be consistent with goto labels (Michel) Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 40 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a7bdbeb469041..82ccc69a4a23a 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -330,8 +330,7 @@ static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) memset(p, 0, sizeof(*p)); } -static void unmap_and_free_pt(struct i915_page_table *pt, - struct drm_device *dev) +static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { cleanup_page_dma(dev, &pt->base); kfree(pt->used_ptes); @@ -387,8 +386,7 @@ fail_bitmap: return ERR_PTR(ret); } -static void unmap_and_free_pd(struct i915_page_directory *pd, - struct drm_device *dev) +static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) { if (pd->base.page) { cleanup_page_dma(dev, &pd->base); @@ -409,17 +407,17 @@ static struct i915_page_directory *alloc_pd(struct drm_device *dev) pd->used_pdes = kcalloc(BITS_TO_LONGS(I915_PDES), sizeof(*pd->used_pdes), GFP_KERNEL); if (!pd->used_pdes) - goto free_pd; + goto fail_bitmap; ret = setup_page_dma(dev, &pd->base); if (ret) - goto free_bitmap; + goto fail_page_m; return pd; -free_bitmap: +fail_page_m: kfree(pd->used_pdes); -free_pd: +fail_bitmap: kfree(pd); return ERR_PTR(ret); @@ -615,7 +613,7 @@ static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_dev if (WARN_ON(!pd->page_table[i])) continue; - unmap_and_free_pt(pd->page_table[i], dev); + free_pt(dev, pd->page_table[i]); pd->page_table[i] = NULL; } } @@ -631,11 +629,11 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) continue; gen8_free_page_tables(ppgtt->pdp.page_directory[i], ppgtt->base.dev); - unmap_and_free_pd(ppgtt->pdp.page_directory[i], ppgtt->base.dev); + free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } - unmap_and_free_pd(ppgtt->scratch_pd, ppgtt->base.dev); - unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev); + free_pd(ppgtt->base.dev, ppgtt->scratch_pd); + free_pt(ppgtt->base.dev, ppgtt->scratch_pt); } /** @@ -688,7 +686,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, unwind_out: for_each_set_bit(pde, new_pts, I915_PDES) - unmap_and_free_pt(pd->page_table[pde], dev); + free_pt(dev, pd->page_table[pde]); return -ENOMEM; } @@ -746,7 +744,7 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, unwind_out: for_each_set_bit(pdpe, new_pds, GEN8_LEGACY_PDPES) - unmap_and_free_pd(pdp->page_directory[pdpe], dev); + free_pd(dev, pdp->page_directory[pdpe]); return -ENOMEM; } @@ -904,11 +902,11 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, err_out: while (pdpe--) { for_each_set_bit(temp, new_page_tables[pdpe], I915_PDES) - unmap_and_free_pt(ppgtt->pdp.page_directory[pdpe]->page_table[temp], vm->dev); + free_pt(vm->dev, ppgtt->pdp.page_directory[pdpe]->page_table[temp]); } for_each_set_bit(pdpe, new_page_dirs, GEN8_LEGACY_PDPES) - unmap_and_free_pd(ppgtt->pdp.page_directory[pdpe], vm->dev); + free_pd(vm->dev, ppgtt->pdp.page_directory[pdpe]); free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); mark_tlbs_dirty(ppgtt); @@ -1358,7 +1356,7 @@ unwind_out: struct i915_page_table *pt = ppgtt->pd.page_table[pde]; ppgtt->pd.page_table[pde] = ppgtt->scratch_pt; - unmap_and_free_pt(pt, vm->dev); + free_pt(vm->dev, pt); } mark_tlbs_dirty(ppgtt); @@ -1377,11 +1375,11 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) gen6_for_all_pdes(pt, ppgtt, pde) { if (pt != ppgtt->scratch_pt) - unmap_and_free_pt(pt, ppgtt->base.dev); + free_pt(ppgtt->base.dev, pt); } - unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev); - unmap_and_free_pd(&ppgtt->pd, ppgtt->base.dev); + free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pd(ppgtt->base.dev, &ppgtt->pd); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) @@ -1431,7 +1429,7 @@ alloc: return 0; err_out: - unmap_and_free_pt(ppgtt->scratch_pt, ppgtt->base.dev); + free_pt(ppgtt->base.dev, ppgtt->scratch_pt); return ret; } -- GitLab From cee30c5439f5c9569ac9260b6e6968faf19cc575 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:09 +0300 Subject: [PATCH 0265/7006] drm/i915/gtt: Remove superfluous free_pd with gen6/7 This has slipped in somewhere but it was harmless as we check the page pointer before teardown. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 82ccc69a4a23a..21fba03dcd623 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -1379,7 +1379,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) } free_pt(ppgtt->base.dev, ppgtt->scratch_pt); - free_pd(ppgtt->base.dev, &ppgtt->pd); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) -- GitLab From 73eeea537b1bb9c53c9e406a16354f6bc9b2be62 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:10 +0300 Subject: [PATCH 0266/7006] drm/i915/gtt: Introduce fill_page_dma() When we setup page directories and tables, we point the entries to a to the next level scratch structure. Make this generic by introducing a fill_page_dma which maps and flushes. We also need 32 bit variant for legacy gens. v2: Fix flushes and handle valleyview (Ville) v3: Now really fix flushes (Michel, Ville) Reviewed-by: Michel Thierry Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 74 ++++++++++++++++------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 21fba03dcd623..734ffd240cd6d 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -330,6 +330,34 @@ static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) memset(p, 0, sizeof(*p)); } +static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, + const uint64_t val) +{ + int i; + uint64_t * const vaddr = kmap_atomic(p->page); + + for (i = 0; i < 512; i++) + vaddr[i] = val; + + /* There are only few exceptions for gen >=6. chv and bxt. + * And we are not sure about the latter so play safe for now. + */ + if (IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) + drm_clflush_virt_range(vaddr, PAGE_SIZE); + + kunmap_atomic(vaddr); +} + +static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, + const uint32_t val32) +{ + uint64_t v = val32; + + v = v << 32 | val32; + + fill_page_dma(dev, p, v); +} + static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { cleanup_page_dma(dev, &pt->base); @@ -340,19 +368,11 @@ static void free_pt(struct drm_device *dev, struct i915_page_table *pt) static void gen8_initialize_pt(struct i915_address_space *vm, struct i915_page_table *pt) { - gen8_pte_t *pt_vaddr, scratch_pte; - int i; - - pt_vaddr = kmap_atomic(pt->base.page); - scratch_pte = gen8_pte_encode(vm->scratch.addr, - I915_CACHE_LLC, true); + gen8_pte_t scratch_pte; - for (i = 0; i < GEN8_PTES; i++) - pt_vaddr[i] = scratch_pte; + scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); - if (!HAS_LLC(vm->dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); + fill_page_dma(vm->dev, &pt->base, scratch_pte); } static struct i915_page_table *alloc_pt(struct drm_device *dev) @@ -586,20 +606,13 @@ static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_directory *pd) { struct i915_hw_ppgtt *ppgtt = - container_of(vm, struct i915_hw_ppgtt, base); - gen8_pde_t *page_directory; - struct i915_page_table *pt; - int i; + container_of(vm, struct i915_hw_ppgtt, base); + gen8_pde_t scratch_pde; - page_directory = kmap_atomic(pd->base.page); - pt = ppgtt->scratch_pt; - for (i = 0; i < I915_PDES; i++) - /* Map the PDE to the page table */ - __gen8_do_map_pt(page_directory + i, pt, vm->dev); + scratch_pde = gen8_pde_encode(vm->dev, ppgtt->scratch_pt->base.daddr, + I915_CACHE_LLC); - if (!HAS_LLC(vm->dev)) - drm_clflush_virt_range(page_directory, PAGE_SIZE); - kunmap_atomic(page_directory); + fill_page_dma(vm->dev, &pd->base, scratch_pde); } static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_device *dev) @@ -1255,22 +1268,15 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, } static void gen6_initialize_pt(struct i915_address_space *vm, - struct i915_page_table *pt) + struct i915_page_table *pt) { - gen6_pte_t *pt_vaddr, scratch_pte; - int i; + gen6_pte_t scratch_pte; WARN_ON(vm->scratch.addr == 0); - scratch_pte = vm->pte_encode(vm->scratch.addr, - I915_CACHE_LLC, true, 0); - - pt_vaddr = kmap_atomic(pt->base.page); - - for (i = 0; i < GEN6_PTES; i++) - pt_vaddr[i] = scratch_pte; + scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); - kunmap_atomic(pt_vaddr); + fill_page_dma_32(vm->dev, &pt->base, scratch_pte); } static int gen6_alloc_va_range(struct i915_address_space *vm, -- GitLab From d1c54acd67dc6518629224b68cac17cd5cff1dc3 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:11 +0300 Subject: [PATCH 0267/7006] drm/i915/gtt: Introduce kmap|kunmap for dma page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As there is flushing involved when we have done the cpu write, make functions for mapping for cpu space. Make macros to map any type of paging structure. v2: Make it clear tha flushing kunmap is only for ppgtt (Ville) v3: Flushing fixed (Ville, Michel). Removed superfluous semicolon Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 77 +++++++++++++++-------------- 1 file changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 734ffd240cd6d..6abcf326b6492 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -330,15 +330,16 @@ static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) memset(p, 0, sizeof(*p)); } -static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, - const uint64_t val) +static void *kmap_page_dma(struct i915_page_dma *p) { - int i; - uint64_t * const vaddr = kmap_atomic(p->page); - - for (i = 0; i < 512; i++) - vaddr[i] = val; + return kmap_atomic(p->page); +} +/* We use the flushing unmap only with ppgtt structures: + * page directories, page tables and scratch pages. + */ +static void kunmap_page_dma(struct drm_device *dev, void *vaddr) +{ /* There are only few exceptions for gen >=6. chv and bxt. * And we are not sure about the latter so play safe for now. */ @@ -348,6 +349,21 @@ static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, kunmap_atomic(vaddr); } +#define kmap_px(px) kmap_page_dma(&(px)->base) +#define kunmap_px(ppgtt, vaddr) kunmap_page_dma((ppgtt)->base.dev, (vaddr)) + +static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, + const uint64_t val) +{ + int i; + uint64_t * const vaddr = kmap_page_dma(p); + + for (i = 0; i < 512; i++) + vaddr[i] = val; + + kunmap_page_dma(dev, vaddr); +} + static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, const uint32_t val32) { @@ -504,7 +520,6 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, while (num_entries) { struct i915_page_directory *pd; struct i915_page_table *pt; - struct page *page_table; if (WARN_ON(!ppgtt->pdp.page_directory[pdpe])) continue; @@ -519,22 +534,18 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, if (WARN_ON(!pt->base.page)) continue; - page_table = pt->base.page; - last_pte = pte + num_entries; if (last_pte > GEN8_PTES) last_pte = GEN8_PTES; - pt_vaddr = kmap_atomic(page_table); + pt_vaddr = kmap_px(pt); for (i = pte; i < last_pte; i++) { pt_vaddr[i] = scratch_pte; num_entries--; } - if (!HAS_LLC(ppgtt->base.dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt); pte = 0; if (++pde == I915_PDES) { @@ -566,18 +577,14 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, if (pt_vaddr == NULL) { struct i915_page_directory *pd = ppgtt->pdp.page_directory[pdpe]; struct i915_page_table *pt = pd->page_table[pde]; - struct page *page_table = pt->base.page; - - pt_vaddr = kmap_atomic(page_table); + pt_vaddr = kmap_px(pt); } pt_vaddr[pte] = gen8_pte_encode(sg_page_iter_dma_address(&sg_iter), cache_level, true); if (++pte == GEN8_PTES) { - if (!HAS_LLC(ppgtt->base.dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); pt_vaddr = NULL; if (++pde == I915_PDES) { pdpe++; @@ -586,11 +593,9 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, pte = 0; } } - if (pt_vaddr) { - if (!HAS_LLC(ppgtt->base.dev)) - drm_clflush_virt_range(pt_vaddr, PAGE_SIZE); - kunmap_atomic(pt_vaddr); - } + + if (pt_vaddr) + kunmap_px(ppgtt, pt_vaddr); } static void __gen8_do_map_pt(gen8_pde_t * const pde, @@ -870,7 +875,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, /* Allocations have completed successfully, so set the bitmaps, and do * the mappings. */ gen8_for_each_pdpe(pd, &ppgtt->pdp, start, length, temp, pdpe) { - gen8_pde_t *const page_directory = kmap_atomic(pd->base.page); + gen8_pde_t *const page_directory = kmap_px(pd); struct i915_page_table *pt; uint64_t pd_len = gen8_clamp_pd(start, length); uint64_t pd_start = start; @@ -900,10 +905,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, * point we're still relying on insert_entries() */ } - if (!HAS_LLC(vm->dev)) - drm_clflush_virt_range(page_directory, PAGE_SIZE); - - kunmap_atomic(page_directory); + kunmap_px(ppgtt, page_directory); set_bit(pdpe, ppgtt->pdp.used_pdpes); } @@ -992,7 +994,8 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) expected); seq_printf(m, "\tPDE: %x\n", pd_entry); - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[pde]->base.page); + pt_vaddr = kmap_px(ppgtt->pd.page_table[pde]); + for (pte = 0; pte < GEN6_PTES; pte+=4) { unsigned long va = (pde * PAGE_SIZE * GEN6_PTES) + @@ -1014,7 +1017,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) } seq_puts(m, "\n"); } - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); } } @@ -1221,12 +1224,12 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, if (last_pte > GEN6_PTES) last_pte = GEN6_PTES; - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); + pt_vaddr = kmap_px(ppgtt->pd.page_table[act_pt]); for (i = first_pte; i < last_pte; i++) pt_vaddr[i] = scratch_pte; - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); num_entries -= last_pte - first_pte; first_pte = 0; @@ -1250,21 +1253,21 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, pt_vaddr = NULL; for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) { if (pt_vaddr == NULL) - pt_vaddr = kmap_atomic(ppgtt->pd.page_table[act_pt]->base.page); + pt_vaddr = kmap_px(ppgtt->pd.page_table[act_pt]); pt_vaddr[act_pte] = vm->pte_encode(sg_page_iter_dma_address(&sg_iter), cache_level, true, flags); if (++act_pte == GEN6_PTES) { - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); pt_vaddr = NULL; act_pt++; act_pte = 0; } } if (pt_vaddr) - kunmap_atomic(pt_vaddr); + kunmap_px(ppgtt, pt_vaddr); } static void gen6_initialize_pt(struct i915_address_space *vm, -- GitLab From 567047be2a7ede082d29f45524c287b87bd75e53 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:12 +0300 Subject: [PATCH 0268/7006] drm/i915/gtt: Use macros to access dma mapped pages Make paging structure type agnostic *_px macros to access page dma struct, the backing page and the dma address. This makes the code less cluttered on internals of i915_page_dma. v2: Superfluous const -> nonconst removed v3: Rebased Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry (v2) Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 35 ++++++++++++++++------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 8 +++++-- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6abcf326b6492..e85676e2352a9 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -349,9 +349,14 @@ static void kunmap_page_dma(struct drm_device *dev, void *vaddr) kunmap_atomic(vaddr); } -#define kmap_px(px) kmap_page_dma(&(px)->base) +#define kmap_px(px) kmap_page_dma(px_base(px)) #define kunmap_px(ppgtt, vaddr) kunmap_page_dma((ppgtt)->base.dev, (vaddr)) +#define setup_px(dev, px) setup_page_dma((dev), px_base(px)) +#define cleanup_px(dev, px) cleanup_page_dma((dev), px_base(px)) +#define fill_px(dev, px, v) fill_page_dma((dev), px_base(px), (v)) +#define fill32_px(dev, px, v) fill_page_dma_32((dev), px_base(px), (v)) + static void fill_page_dma(struct drm_device *dev, struct i915_page_dma *p, const uint64_t val) { @@ -376,7 +381,7 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { - cleanup_page_dma(dev, &pt->base); + cleanup_px(dev, pt); kfree(pt->used_ptes); kfree(pt); } @@ -388,7 +393,7 @@ static void gen8_initialize_pt(struct i915_address_space *vm, scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); - fill_page_dma(vm->dev, &pt->base, scratch_pte); + fill_px(vm->dev, pt, scratch_pte); } static struct i915_page_table *alloc_pt(struct drm_device *dev) @@ -408,7 +413,7 @@ static struct i915_page_table *alloc_pt(struct drm_device *dev) if (!pt->used_ptes) goto fail_bitmap; - ret = setup_page_dma(dev, &pt->base); + ret = setup_px(dev, pt); if (ret) goto fail_page_m; @@ -424,8 +429,8 @@ fail_bitmap: static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) { - if (pd->base.page) { - cleanup_page_dma(dev, &pd->base); + if (px_page(pd)) { + cleanup_px(dev, pd); kfree(pd->used_pdes); kfree(pd); } @@ -445,7 +450,7 @@ static struct i915_page_directory *alloc_pd(struct drm_device *dev) if (!pd->used_pdes) goto fail_bitmap; - ret = setup_page_dma(dev, &pd->base); + ret = setup_px(dev, pd); if (ret) goto fail_page_m; @@ -531,7 +536,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, pt = pd->page_table[pde]; - if (WARN_ON(!pt->base.page)) + if (WARN_ON(!px_page(pt))) continue; last_pte = pte + num_entries; @@ -603,7 +608,7 @@ static void __gen8_do_map_pt(gen8_pde_t * const pde, struct drm_device *dev) { gen8_pde_t entry = - gen8_pde_encode(dev, pt->base.daddr, I915_CACHE_LLC); + gen8_pde_encode(dev, px_dma(pt), I915_CACHE_LLC); *pde = entry; } @@ -614,17 +619,17 @@ static void gen8_initialize_pd(struct i915_address_space *vm, container_of(vm, struct i915_hw_ppgtt, base); gen8_pde_t scratch_pde; - scratch_pde = gen8_pde_encode(vm->dev, ppgtt->scratch_pt->base.daddr, + scratch_pde = gen8_pde_encode(vm->dev, px_dma(ppgtt->scratch_pt), I915_CACHE_LLC); - fill_page_dma(vm->dev, &pd->base, scratch_pde); + fill_px(vm->dev, pd, scratch_pde); } static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_device *dev) { int i; - if (!pd->base.page) + if (!px_page(pd)) return; for_each_set_bit(i, pd->used_pdes, I915_PDES) { @@ -983,7 +988,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; gen6_pte_t *pt_vaddr; - dma_addr_t pt_addr = ppgtt->pd.page_table[pde]->base.daddr; + const dma_addr_t pt_addr = px_dma(ppgtt->pd.page_table[pde]); pd_entry = readl(ppgtt->pd_addr + pde); expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID); @@ -1030,7 +1035,7 @@ static void gen6_write_pde(struct i915_page_directory *pd, container_of(pd, struct i915_hw_ppgtt, pd); u32 pd_entry; - pd_entry = GEN6_PDE_ADDR_ENCODE(pt->base.daddr); + pd_entry = GEN6_PDE_ADDR_ENCODE(px_dma(pt)); pd_entry |= GEN6_PDE_VALID; writel(pd_entry, ppgtt->pd_addr + pde); @@ -1279,7 +1284,7 @@ static void gen6_initialize_pt(struct i915_address_space *vm, scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); - fill_page_dma_32(vm->dev, &pt->base, scratch_pte); + fill32_px(vm->dev, pt, scratch_pte); } static int gen6_alloc_va_range(struct i915_address_space *vm, diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index c681573b4005c..f4bcec2b389a4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -219,6 +219,10 @@ struct i915_page_dma { }; }; +#define px_base(px) (&(px)->base) +#define px_page(px) (px_base(px)->page) +#define px_dma(px) (px_base(px)->daddr) + struct i915_page_table { struct i915_page_dma base; @@ -481,8 +485,8 @@ static inline dma_addr_t i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) { return test_bit(n, ppgtt->pdp.used_pdpes) ? - ppgtt->pdp.page_directory[n]->base.daddr : - ppgtt->scratch_pd->base.daddr; + px_dma(ppgtt->pdp.page_directory[n]) : + px_dma(ppgtt->scratch_pd); } int i915_gem_gtt_init(struct drm_device *dev); -- GitLab From c114f76a0a76eeffa1c1be392d98182c2cc30291 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:13 +0300 Subject: [PATCH 0269/7006] drm/i915/gtt: Make scratch page i915_page_dma compatible Lay out scratch page structure in similar manner than other paging structures. This allows us to use the same tools for setup and teardown. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 89 ++++++++++++++++------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 9 +-- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index e85676e2352a9..0cc0cf4362eae 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -301,11 +301,12 @@ static gen6_pte_t iris_pte_encode(dma_addr_t addr, return pte; } -static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) +static int __setup_page_dma(struct drm_device *dev, + struct i915_page_dma *p, gfp_t flags) { struct device *device = &dev->pdev->dev; - p->page = alloc_page(GFP_KERNEL); + p->page = alloc_page(flags); if (!p->page) return -ENOMEM; @@ -320,6 +321,11 @@ static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) return 0; } +static int setup_page_dma(struct drm_device *dev, struct i915_page_dma *p) +{ + return __setup_page_dma(dev, p, GFP_KERNEL); +} + static void cleanup_page_dma(struct drm_device *dev, struct i915_page_dma *p) { if (WARN_ON(!p->page)) @@ -391,7 +397,8 @@ static void gen8_initialize_pt(struct i915_address_space *vm, { gen8_pte_t scratch_pte; - scratch_pte = gen8_pte_encode(vm->scratch.addr, I915_CACHE_LLC, true); + scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true); fill_px(vm->dev, pt, scratch_pte); } @@ -519,7 +526,7 @@ static void gen8_ppgtt_clear_range(struct i915_address_space *vm, unsigned num_entries = length >> PAGE_SHIFT; unsigned last_pte, i; - scratch_pte = gen8_pte_encode(ppgtt->base.scratch.addr, + scratch_pte = gen8_pte_encode(px_dma(ppgtt->base.scratch_page), I915_CACHE_LLC, use_scratch); while (num_entries) { @@ -983,7 +990,7 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) uint32_t pte, pde, temp; uint32_t start = ppgtt->base.start, length = ppgtt->base.total; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, true, 0); gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; @@ -1222,7 +1229,8 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm, unsigned first_pte = first_entry % GEN6_PTES; unsigned last_pte, i; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); while (num_entries) { last_pte = first_pte + num_entries; @@ -1280,9 +1288,10 @@ static void gen6_initialize_pt(struct i915_address_space *vm, { gen6_pte_t scratch_pte; - WARN_ON(vm->scratch.addr == 0); + WARN_ON(px_dma(vm->scratch_page) == 0); - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); fill32_px(vm->dev, pt, scratch_pte); } @@ -1519,13 +1528,14 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) struct drm_i915_private *dev_priv = dev->dev_private; ppgtt->base.dev = dev; - ppgtt->base.scratch = dev_priv->gtt.base.scratch; + ppgtt->base.scratch_page = dev_priv->gtt.base.scratch_page; if (INTEL_INFO(dev)->gen < 8) return gen6_ppgtt_init(ppgtt); else return gen8_ppgtt_init(ppgtt); } + int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1842,7 +1852,7 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = gen8_pte_encode(vm->scratch.addr, + scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, use_scratch); for (i = 0; i < num_entries; i++) @@ -1868,7 +1878,8 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm, first_entry, num_entries, max_entries)) num_entries = max_entries; - scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, use_scratch, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, use_scratch, 0); for (i = 0; i < num_entries; i++) iowrite32(scratch_pte, >t_base[i]); @@ -2125,42 +2136,40 @@ void i915_global_gtt_cleanup(struct drm_device *dev) vm->cleanup(vm); } -static int setup_scratch_page(struct drm_device *dev) +static int alloc_scratch_page(struct i915_address_space *vm) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct page *page; - dma_addr_t dma_addr; + struct i915_page_scratch *sp; + int ret; + + WARN_ON(vm->scratch_page); - page = alloc_page(GFP_KERNEL | GFP_DMA32 | __GFP_ZERO); - if (page == NULL) + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (sp == NULL) return -ENOMEM; - set_pages_uc(page, 1); -#ifdef CONFIG_INTEL_IOMMU - dma_addr = pci_map_page(dev->pdev, page, 0, PAGE_SIZE, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(dev->pdev, dma_addr)) { - __free_page(page); - return -EINVAL; + ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); + if (ret) { + kfree(sp); + return ret; } -#else - dma_addr = page_to_phys(page); -#endif - dev_priv->gtt.base.scratch.page = page; - dev_priv->gtt.base.scratch.addr = dma_addr; + + set_pages_uc(px_page(sp), 1); + + vm->scratch_page = sp; return 0; } -static void teardown_scratch_page(struct drm_device *dev) +static void free_scratch_page(struct i915_address_space *vm) { - struct drm_i915_private *dev_priv = dev->dev_private; - struct page *page = dev_priv->gtt.base.scratch.page; + struct i915_page_scratch *sp = vm->scratch_page; - set_pages_wb(page, 1); - pci_unmap_page(dev->pdev, dev_priv->gtt.base.scratch.addr, - PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); - __free_page(page); + set_pages_wb(px_page(sp), 1); + + cleanup_px(vm->dev, sp); + kfree(sp); + + vm->scratch_page = NULL; } static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) @@ -2268,7 +2277,7 @@ static int ggtt_probe_common(struct drm_device *dev, return -ENOMEM; } - ret = setup_scratch_page(dev); + ret = alloc_scratch_page(&dev_priv->gtt.base); if (ret) { DRM_ERROR("Scratch setup failed\n"); /* iounmap will also get called at remove, but meh */ @@ -2447,7 +2456,7 @@ static void gen6_gmch_remove(struct i915_address_space *vm) struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); iounmap(gtt->gsm); - teardown_scratch_page(vm->dev); + free_scratch_page(vm); } static int i915_gmch_probe(struct drm_device *dev, @@ -2511,13 +2520,13 @@ int i915_gem_gtt_init(struct drm_device *dev) dev_priv->gtt.base.cleanup = gen6_gmch_remove; } + gtt->base.dev = dev; + ret = gtt->gtt_probe(dev, >t->base.total, >t->stolen_size, >t->mappable_base, >t->mappable_end); if (ret) return ret; - gtt->base.dev = dev; - /* GMADR is the PCI mmio aperture into the global GTT. */ DRM_INFO("Memory usable by graphics device = %lluM\n", gtt->base.total >> 20); diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index f4bcec2b389a4..216d949507afe 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -223,6 +223,10 @@ struct i915_page_dma { #define px_page(px) (px_base(px)->page) #define px_dma(px) (px_base(px)->daddr) +struct i915_page_scratch { + struct i915_page_dma base; +}; + struct i915_page_table { struct i915_page_dma base; @@ -249,10 +253,7 @@ struct i915_address_space { u64 start; /* Start offset always 0 for dri2 */ u64 total; /* size addr space maps (ex. 2GB for ggtt) */ - struct { - dma_addr_t addr; - struct page *page; - } scratch; + struct i915_page_scratch *scratch_page; /** * List of objects currently involved in rendering. -- GitLab From b2dd45111e0fb4b36dcc972c7ae4e69ff1df4f88 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:15 +0300 Subject: [PATCH 0270/7006] drm/i915/gtt: Pin vma during virtual address allocation Dynamic page table allocation might wake the shrinker when memory is requested for page table structures. As this happens when we try to allocate the virtual address during binding, our vma might be among the targets for eviction. We should do i915_vma_pin() and do pin early in there like Chris suggests but this is interim solution. Shield our vma from shrinker by incrementing pin count before the virtual address is allocated. The proper place to fix this would be in gem, inside of i915_vma_pin(). But we don't have that yet so take the short cut as a intermediate solution. Testcase: igt/gem_ctx_thrash Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 0cc0cf4362eae..29d76b06e7de6 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -2870,9 +2870,12 @@ int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level, vma->node.size, VM_TO_TRACE_NAME(vma->vm)); + /* XXX: i915_vma_pin() will fix this +- hack */ + vma->pin_count++; ret = vma->vm->allocate_va_range(vma->vm, vma->node.start, vma->node.size); + vma->pin_count--; if (ret) return ret; } -- GitLab From fe36f55d4d4447679923fc74564786ae423ca4bd Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:16 +0300 Subject: [PATCH 0271/7006] drm/i915/gtt: Cleanup page directory encoding Write page directory entry without using superfluous indirect function. Also remove unused device parameter from the encode function. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 29d76b06e7de6..6817b072fac4c 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -192,9 +192,8 @@ static gen8_pte_t gen8_pte_encode(dma_addr_t addr, return pte; } -static gen8_pde_t gen8_pde_encode(struct drm_device *dev, - dma_addr_t addr, - enum i915_cache_level level) +static gen8_pde_t gen8_pde_encode(const dma_addr_t addr, + const enum i915_cache_level level) { gen8_pde_t pde = _PAGE_PRESENT | _PAGE_RW; pde |= addr; @@ -610,15 +609,6 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_px(ppgtt, pt_vaddr); } -static void __gen8_do_map_pt(gen8_pde_t * const pde, - struct i915_page_table *pt, - struct drm_device *dev) -{ - gen8_pde_t entry = - gen8_pde_encode(dev, px_dma(pt), I915_CACHE_LLC); - *pde = entry; -} - static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_directory *pd) { @@ -626,7 +616,7 @@ static void gen8_initialize_pd(struct i915_address_space *vm, container_of(vm, struct i915_hw_ppgtt, base); gen8_pde_t scratch_pde; - scratch_pde = gen8_pde_encode(vm->dev, px_dma(ppgtt->scratch_pt), + scratch_pde = gen8_pde_encode(px_dma(ppgtt->scratch_pt), I915_CACHE_LLC); fill_px(vm->dev, pd, scratch_pde); @@ -911,7 +901,8 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, set_bit(pde, pd->used_pdes); /* Map the PDE to the page table */ - __gen8_do_map_pt(page_directory + pde, pt, vm->dev); + page_directory[pde] = gen8_pde_encode(px_dma(pt), + I915_CACHE_LLC); /* NB: We haven't yet mapped ptes to pages. At this * point we're still relying on insert_entries() */ -- GitLab From 79ab93705464982b9f7e9b5dfabfacde634338aa Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:17 +0300 Subject: [PATCH 0272/7006] drm/i915/gtt: Move scratch_pd and scratch_pt into vm struct Scratch page is part of struct i915_address_space. Move other scratch entities into the same struct. This is a preparatory patch for having only one instance of each scratch_pt/pd. v2: make commit msg more readable Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry (v1) [danvet: Bikeshed summary to avoid confusion with vmas.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 51 ++++++++++++++--------------- drivers/gpu/drm/i915/i915_gem_gtt.h | 7 ++-- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 6817b072fac4c..2c8201e06e27e 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -612,12 +612,9 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, static void gen8_initialize_pd(struct i915_address_space *vm, struct i915_page_directory *pd) { - struct i915_hw_ppgtt *ppgtt = - container_of(vm, struct i915_hw_ppgtt, base); gen8_pde_t scratch_pde; - scratch_pde = gen8_pde_encode(px_dma(ppgtt->scratch_pt), - I915_CACHE_LLC); + scratch_pde = gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC); fill_px(vm->dev, pd, scratch_pde); } @@ -652,8 +649,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } - free_pd(ppgtt->base.dev, ppgtt->scratch_pd); - free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pd(vm->dev, vm->scratch_pd); + free_pt(vm->dev, vm->scratch_pt); } /** @@ -689,7 +686,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, /* Don't reallocate page tables */ if (pt) { /* Scratch is never allocated this way */ - WARN_ON(pt == ppgtt->scratch_pt); + WARN_ON(pt == ppgtt->base.scratch_pt); continue; } @@ -940,16 +937,16 @@ err_out: */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->scratch_pt)) - return PTR_ERR(ppgtt->scratch_pt); + ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); + if (IS_ERR(ppgtt->base.scratch_pt)) + return PTR_ERR(ppgtt->base.scratch_pt); - ppgtt->scratch_pd = alloc_pd(ppgtt->base.dev); - if (IS_ERR(ppgtt->scratch_pd)) - return PTR_ERR(ppgtt->scratch_pd); + ppgtt->base.scratch_pd = alloc_pd(ppgtt->base.dev); + if (IS_ERR(ppgtt->base.scratch_pd)) + return PTR_ERR(ppgtt->base.scratch_pd); - gen8_initialize_pt(&ppgtt->base, ppgtt->scratch_pt); - gen8_initialize_pd(&ppgtt->base, ppgtt->scratch_pd); + gen8_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); + gen8_initialize_pd(&ppgtt->base, ppgtt->base.scratch_pd); ppgtt->base.start = 0; ppgtt->base.total = 1ULL << 32; @@ -981,7 +978,8 @@ static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m) uint32_t pte, pde, temp; uint32_t start = ppgtt->base.start, length = ppgtt->base.total; - scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), I915_CACHE_LLC, true, 0); + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) { u32 expected; @@ -1314,7 +1312,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, * tables. */ gen6_for_each_pde(pt, &ppgtt->pd, start, length, temp, pde) { - if (pt != ppgtt->scratch_pt) { + if (pt != vm->scratch_pt) { WARN_ON(bitmap_empty(pt->used_ptes, GEN6_PTES)); continue; } @@ -1369,7 +1367,7 @@ unwind_out: for_each_set_bit(pde, new_page_tables, I915_PDES) { struct i915_page_table *pt = ppgtt->pd.page_table[pde]; - ppgtt->pd.page_table[pde] = ppgtt->scratch_pt; + ppgtt->pd.page_table[pde] = vm->scratch_pt; free_pt(vm->dev, pt); } @@ -1384,15 +1382,14 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) struct i915_page_table *pt; uint32_t pde; - drm_mm_remove_node(&ppgtt->node); gen6_for_all_pdes(pt, ppgtt, pde) { - if (pt != ppgtt->scratch_pt) + if (pt != vm->scratch_pt) free_pt(ppgtt->base.dev, pt); } - free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pt(vm->dev, vm->scratch_pt); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) @@ -1407,11 +1404,11 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) * size. We allocate at the top of the GTT to avoid fragmentation. */ BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm)); - ppgtt->scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->scratch_pt)) - return PTR_ERR(ppgtt->scratch_pt); + ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); + if (IS_ERR(ppgtt->base.scratch_pt)) + return PTR_ERR(ppgtt->base.scratch_pt); - gen6_initialize_pt(&ppgtt->base, ppgtt->scratch_pt); + gen6_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); alloc: ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm, @@ -1442,7 +1439,7 @@ alloc: return 0; err_out: - free_pt(ppgtt->base.dev, ppgtt->scratch_pt); + free_pt(ppgtt->base.dev, ppgtt->base.scratch_pt); return ret; } @@ -1458,7 +1455,7 @@ static void gen6_scratch_va_range(struct i915_hw_ppgtt *ppgtt, uint32_t pde, temp; gen6_for_each_pde(unused, &ppgtt->pd, start, length, temp, pde) - ppgtt->pd.page_table[pde] = ppgtt->scratch_pt; + ppgtt->pd.page_table[pde] = ppgtt->base.scratch_pt; } static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h index 216d949507afe..e1cfa292f9adf 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.h +++ b/drivers/gpu/drm/i915/i915_gem_gtt.h @@ -254,6 +254,8 @@ struct i915_address_space { u64 total; /* size addr space maps (ex. 2GB for ggtt) */ struct i915_page_scratch *scratch_page; + struct i915_page_table *scratch_pt; + struct i915_page_directory *scratch_pd; /** * List of objects currently involved in rendering. @@ -343,9 +345,6 @@ struct i915_hw_ppgtt { struct i915_page_directory pd; }; - struct i915_page_table *scratch_pt; - struct i915_page_directory *scratch_pd; - struct drm_i915_file_private *file_priv; gen6_pte_t __iomem *pd_addr; @@ -487,7 +486,7 @@ i915_page_dir_dma_addr(const struct i915_hw_ppgtt *ppgtt, const unsigned n) { return test_bit(n, ppgtt->pdp.used_pdpes) ? px_dma(ppgtt->pdp.page_directory[n]) : - px_dma(ppgtt->scratch_pd); + px_dma(ppgtt->base.scratch_pd); } int i915_gem_gtt_init(struct drm_device *dev); -- GitLab From 966082c93273f4fd52f4a068b4b55c47e3ba72cc Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 25 Jun 2015 18:35:19 +0300 Subject: [PATCH 0273/7006] drm/i915/gtt: Use nonatomic bitmap ops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is no need for atomicity here. Convert all bitmap operations to nonatomic variants. Cc: Ville Syrjälä Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index 2c8201e06e27e..e7e0a049995f4 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -696,7 +696,7 @@ static int gen8_ppgtt_alloc_pagetabs(struct i915_hw_ppgtt *ppgtt, gen8_initialize_pt(&ppgtt->base, pt); pd->page_table[pde] = pt; - set_bit(pde, new_pts); + __set_bit(pde, new_pts); } return 0; @@ -754,7 +754,7 @@ static int gen8_ppgtt_alloc_page_directories(struct i915_hw_ppgtt *ppgtt, gen8_initialize_pd(&ppgtt->base, pd); pdp->page_directory[pdpe] = pd; - set_bit(pdpe, new_pds); + __set_bit(pdpe, new_pds); } return 0; @@ -895,7 +895,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, gen8_pte_count(pd_start, pd_len)); /* Our pde is now pointing to the pagetable, pt */ - set_bit(pde, pd->used_pdes); + __set_bit(pde, pd->used_pdes); /* Map the PDE to the page table */ page_directory[pde] = gen8_pde_encode(px_dma(pt), @@ -907,7 +907,7 @@ static int gen8_alloc_va_range(struct i915_address_space *vm, kunmap_px(ppgtt, page_directory); - set_bit(pdpe, ppgtt->pdp.used_pdpes); + __set_bit(pdpe, ppgtt->pdp.used_pdpes); } free_gen8_temp_bitmaps(new_page_dirs, new_page_tables); @@ -1329,7 +1329,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, gen6_initialize_pt(vm, pt); ppgtt->pd.page_table[pde] = pt; - set_bit(pde, new_page_tables); + __set_bit(pde, new_page_tables); trace_i915_page_table_entry_alloc(vm, pde, start, GEN6_PDE_SHIFT); } @@ -1343,7 +1343,7 @@ static int gen6_alloc_va_range(struct i915_address_space *vm, bitmap_set(tmp_bitmap, gen6_pte_index(start), gen6_pte_count(start, length)); - if (test_and_clear_bit(pde, new_page_tables)) + if (__test_and_clear_bit(pde, new_page_tables)) gen6_write_pde(&ppgtt->pd, pde, pt); trace_i915_page_table_entry_map(vm, pde, pt, -- GitLab From 7a01a0a292c25a85cd36efcd5920d2f1caccbb2b Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Fri, 26 Jun 2015 13:46:14 +0100 Subject: [PATCH 0274/7006] drm/i915/lrc: Update PDPx registers with lri commands A safer way to update the PDPx registers is sending lri commands, added in the ring before the batchbuffer start. Otherwise, the ctx must be idle before trying to change anything (but the ring-tail) in the ctx image. An example where the ctx won't be idle is lite-restore. This patch depends on 5b7e4c9ce ("drm/i915/gtt: Mark TLBS dirty for gen8+"). v2: Combine lri writes (and save 8 commands). (Mika) v3: Rebase after ring/req changes, and removed references to deprecated patches. Cc: Dave Gordon Cc: Mika Kuoppala Signed-off-by: Michel Thierry Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 42 ++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index fd25314fc913b..8cac4cab1666f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1373,6 +1373,34 @@ static int gen9_init_render_ring(struct intel_engine_cs *ring) return init_workarounds_ring(ring); } +static int intel_logical_ring_emit_pdps(struct drm_i915_gem_request *req) +{ + struct i915_hw_ppgtt *ppgtt = req->ctx->ppgtt; + struct intel_engine_cs *ring = req->ring; + struct intel_ringbuffer *ringbuf = req->ringbuf; + const int num_lri_cmds = GEN8_LEGACY_PDPES * 2; + int i, ret; + + ret = intel_logical_ring_begin(req, num_lri_cmds * 2 + 2); + if (ret) + return ret; + + intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(num_lri_cmds)); + for (i = GEN8_LEGACY_PDPES - 1; i >= 0; i--) { + const dma_addr_t pd_daddr = i915_page_dir_dma_addr(ppgtt, i); + + intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_UDW(ring, i)); + intel_logical_ring_emit(ringbuf, upper_32_bits(pd_daddr)); + intel_logical_ring_emit(ringbuf, GEN8_RING_PDP_LDW(ring, i)); + intel_logical_ring_emit(ringbuf, lower_32_bits(pd_daddr)); + } + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + static int gen8_emit_bb_start(struct drm_i915_gem_request *req, u64 offset, unsigned dispatch_flags) { @@ -1380,6 +1408,20 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req, bool ppgtt = !(dispatch_flags & I915_DISPATCH_SECURE); int ret; + /* Don't rely in hw updating PDPs, specially in lite-restore. + * Ideally, we should set Force PD Restore in ctx descriptor, + * but we can't. Force Restore would be a second option, but + * it is unsafe in case of lite-restore (because the ctx is + * not idle). */ + if (req->ctx->ppgtt && + (intel_ring_flag(req->ring) & req->ctx->ppgtt->pd_dirty_rings)) { + ret = intel_logical_ring_emit_pdps(req); + if (ret) + return ret; + + req->ctx->ppgtt->pd_dirty_rings &= ~intel_ring_flag(req->ring); + } + ret = intel_logical_ring_begin(req, 4); if (ret) return ret; -- GitLab From f37c05052ff6430767f3bff60efc0e92f690495b Mon Sep 17 00:00:00 2001 From: Michel Thierry Date: Wed, 10 Jun 2015 17:46:39 +0100 Subject: [PATCH 0275/7006] drm/i915/gtt: Switch gen8_free_page_tables params After Mika's ppgtt cleanup series, all the other free functions have drm_device as the first parameter, except this one. No functional changes. Signed-off-by: Michel Thierry Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index e7e0a049995f4..b94eebe81fd83 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -619,7 +619,8 @@ static void gen8_initialize_pd(struct i915_address_space *vm, fill_px(vm->dev, pd, scratch_pde); } -static void gen8_free_page_tables(struct i915_page_directory *pd, struct drm_device *dev) +static void gen8_free_page_tables(struct drm_device *dev, + struct i915_page_directory *pd) { int i; @@ -645,7 +646,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) if (WARN_ON(!ppgtt->pdp.page_directory[i])) continue; - gen8_free_page_tables(ppgtt->pdp.page_directory[i], ppgtt->base.dev); + gen8_free_page_tables(ppgtt->base.dev, + ppgtt->pdp.page_directory[i]); free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } -- GitLab From dc2538139277089e218b1b1d0d01454ecf39e944 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 25 Jun 2015 16:15:06 +0100 Subject: [PATCH 0276/7006] drm/i915/skl: Replace the HDMI DPLL divider computation algorithm The HW validation team came back from further testing with a slightly changed constraint on the deviation between the DCO frequency and the central frequency. Instead of +-4%, it's now +1%/-6%. Unfortunately, the previous algorithm didn't quite cope with these new constraints, the reason being that it wasn't thorough enough looking at the possible divider candidates. The new algorithm looks at all dividers, which is definitely a hammer approach (we could reduce further the set of dividers to good ones as a follow up, at the cost of a bit more complicated code). But, at least, we can now satisfy the +1%/+6% rule for all the "Well known" HDMI frequencies of my test set (373 entries). On that subject, the new code is quite extensively tested in intel-gpu-tools (tools/skl_compute_wrpll). v2: Fix cycling between central frequencies and dividers (Paulo) Properly choose the minimal deviation between postive and negative candidates (Paulo). On the 373 test frequencies, v2 computes better dividers than v1 (ie more even dividers and lower deviation on average): v1: average deviation: 206.52 v2: average deviation: 194.47 Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 211 ++++++++++++++++++++----------- 1 file changed, 137 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 31b29e8781ace..6e964ef7dfdad 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1104,6 +1104,103 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc, return true; } +struct skl_wrpll_context { + uint64_t min_deviation; /* current minimal deviation */ + uint64_t central_freq; /* chosen central freq */ + uint64_t dco_freq; /* chosen dco freq */ + unsigned int p; /* chosen divider */ +}; + +static void skl_wrpll_context_init(struct skl_wrpll_context *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + + ctx->min_deviation = U64_MAX; +} + +/* DCO freq must be within +1%/-6% of the DCO central freq */ +#define SKL_DCO_MAX_PDEVIATION 100 +#define SKL_DCO_MAX_NDEVIATION 600 + +static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, + uint64_t central_freq, + uint64_t dco_freq, + unsigned int divider) +{ + uint64_t deviation; + + deviation = div64_u64(10000 * abs_diff(dco_freq, central_freq), + central_freq); + + /* positive deviation */ + if (dco_freq >= central_freq) { + if (deviation < SKL_DCO_MAX_PDEVIATION && + deviation < ctx->min_deviation) { + ctx->min_deviation = deviation; + ctx->central_freq = central_freq; + ctx->dco_freq = dco_freq; + ctx->p = divider; + } + /* negative deviation */ + } else if (deviation < SKL_DCO_MAX_NDEVIATION && + deviation < ctx->min_deviation) { + ctx->min_deviation = deviation; + ctx->central_freq = central_freq; + ctx->dco_freq = dco_freq; + ctx->p = divider; + } + +} + +static void skl_wrpll_get_multipliers(unsigned int p, + unsigned int *p0 /* out */, + unsigned int *p1 /* out */, + unsigned int *p2 /* out */) +{ + /* even dividers */ + if (p % 2 == 0) { + unsigned int half = p / 2; + + if (half == 1 || half == 2 || half == 3 || half == 5) { + *p0 = 2; + *p1 = 1; + *p2 = half; + } else if (half % 2 == 0) { + *p0 = 2; + *p1 = half / 2; + *p2 = 2; + } else if (half % 3 == 0) { + *p0 = 3; + *p1 = half / 3; + *p2 = 2; + } else if (half % 7 == 0) { + *p0 = 7; + *p1 = half / 7; + *p2 = 2; + } + } else if (p == 3 || p == 9) { /* 3, 5, 7, 9, 15, 21, 35 */ + *p0 = 3; + *p1 = 1; + *p2 = p / 3; + } else if (p == 5 || p == 7) { + *p0 = p; + *p1 = 1; + *p2 = 1; + } else if (p == 15) { + *p0 = 3; + *p1 = 1; + *p2 = 5; + } else if (p == 21) { + *p0 = 7; + *p1 = 1; + *p2 = 3; + } else if (p == 35) { + *p0 = 7; + *p1 = 1; + *p2 = 5; + } +} + struct skl_wrpll_params { uint32_t dco_fraction; uint32_t dco_integer; @@ -1189,90 +1286,56 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, uint64_t dco_central_freq[3] = {8400000000ULL, 9000000000ULL, 9600000000ULL}; - uint32_t min_dco_deviation = 400; - uint32_t min_dco_index = 3; - uint32_t P0[4] = {1, 2, 3, 7}; - uint32_t P2[4] = {1, 2, 3, 5}; - bool found = false; - uint32_t candidate_p = 0; - uint32_t candidate_p0[3] = {0}, candidate_p1[3] = {0}; - uint32_t candidate_p2[3] = {0}; - uint32_t dco_central_freq_deviation[3]; - uint32_t i, P1, k, dco_count; - bool retry_with_odd = false; - - /* Determine P0, P1 or P2 */ - for (dco_count = 0; dco_count < 3; dco_count++) { - found = false; - candidate_p = - div64_u64(dco_central_freq[dco_count], afe_clock); - if (retry_with_odd == false) - candidate_p = (candidate_p % 2 == 0 ? - candidate_p : candidate_p + 1); - - for (P1 = 1; P1 < candidate_p; P1++) { - for (i = 0; i < 4; i++) { - if (!(P0[i] != 1 || P1 == 1)) - continue; - - for (k = 0; k < 4; k++) { - if (P1 != 1 && P2[k] != 2) - continue; - - if (candidate_p == P0[i] * P1 * P2[k]) { - /* Found possible P0, P1, P2 */ - found = true; - candidate_p0[dco_count] = P0[i]; - candidate_p1[dco_count] = P1; - candidate_p2[dco_count] = P2[k]; - goto found; - } - - } - } - } - -found: - if (found) { - dco_central_freq_deviation[dco_count] = - div64_u64(10000 * - abs_diff(candidate_p * afe_clock, - dco_central_freq[dco_count]), - dco_central_freq[dco_count]); - - if (dco_central_freq_deviation[dco_count] < - min_dco_deviation) { - min_dco_deviation = - dco_central_freq_deviation[dco_count]; - min_dco_index = dco_count; + static const int even_dividers[] = { 4, 6, 8, 10, 12, 14, 16, 18, 20, + 24, 28, 30, 32, 36, 40, 42, 44, + 48, 52, 54, 56, 60, 64, 66, 68, + 70, 72, 76, 78, 80, 84, 88, 90, + 92, 96, 98 }; + static const int odd_dividers[] = { 3, 5, 7, 9, 15, 21, 35 }; + static const struct { + const int *list; + int n_dividers; + } dividers[] = { + { even_dividers, ARRAY_SIZE(even_dividers) }, + { odd_dividers, ARRAY_SIZE(odd_dividers) }, + }; + struct skl_wrpll_context ctx; + unsigned int dco, d, i; + unsigned int p0, p1, p2; + + skl_wrpll_context_init(&ctx); + + for (d = 0; d < ARRAY_SIZE(dividers); d++) { + for (dco = 0; dco < ARRAY_SIZE(dco_central_freq); dco++) { + for (i = 0; i < dividers[d].n_dividers; i++) { + unsigned int p = dividers[d].list[i]; + uint64_t dco_freq = p * afe_clock; + + skl_wrpll_try_divider(&ctx, + dco_central_freq[dco], + dco_freq, + p); } } - - if (min_dco_index > 2 && dco_count == 2) { - /* oh well, we tried... */ - if (retry_with_odd) - break; - - retry_with_odd = true; - dco_count = 0; - } } - if (WARN(min_dco_index > 2, - "No valid parameters found for pixel clock: %dHz\n", clock)) + if (!ctx.p) { + DRM_DEBUG_DRIVER("No valid divider found for %dHz\n", clock); return false; + } - skl_wrpll_params_populate(wrpll_params, - afe_clock, - dco_central_freq[min_dco_index], - candidate_p0[min_dco_index], - candidate_p1[min_dco_index], - candidate_p2[min_dco_index]); + /* + * gcc incorrectly analyses that these can be used without being + * initialized. To be fair, it's hard to guess. + */ + p0 = p1 = p2 = 0; + skl_wrpll_get_multipliers(ctx.p, &p0, &p1, &p2); + skl_wrpll_params_populate(wrpll_params, afe_clock, ctx.central_freq, + p0, p1, p2); return true; } - static bool skl_ddi_pll_select(struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state, -- GitLab From 267db663458a8077a087674fb85ea95f540d8671 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 25 Jun 2015 16:19:24 +0100 Subject: [PATCH 0277/7006] drm/i915/skl: Prefer even dividers for SKL DPLLs Currently, if an odd divider improves the deviation (minimizes it), we take that divider. The recommendation is to prefer even dividers. v2: Move the check at the right place after having inverted the two for loops in the previous patch. Signed-off-by: Damien Lespiau Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 6e964ef7dfdad..f6b3ccc4ab669 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1317,6 +1317,13 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, p); } } + + /* + * If a solution is found with an even divider, prefer + * this one. + */ + if (d == 0 && ctx.p) + break; } if (!ctx.p) { -- GitLab From 350405623ff3f447813eaef2035272bf05281671 Mon Sep 17 00:00:00 2001 From: Bob Paauwe Date: Thu, 25 Jun 2015 14:54:07 -0700 Subject: [PATCH 0278/7006] drm/i915: Update rps frequencies for BXT Broxton is using a different register and different bit ordering for rps status capabilities. Also GT perf freqency register is different for Broxton so update that. Signed-off-by: Bob Paauwe Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 21 ++++++++++++++++----- drivers/gpu/drm/i915/i915_reg.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 16 ++++++++++++---- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index b509844df0dd1..7d303e721a77a 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1132,9 +1132,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused) (rgvstat & MEMSTAT_PSTATE_MASK) >> MEMSTAT_PSTATE_SHIFT); } else if (IS_GEN6(dev) || (IS_GEN7(dev) && !IS_VALLEYVIEW(dev)) || IS_BROADWELL(dev) || IS_GEN9(dev)) { - u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); - u32 rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); - u32 rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + u32 rp_state_limits; + u32 gt_perf_status; + u32 rp_state_cap; u32 rpmodectl, rpinclimit, rpdeclimit; u32 rpstat, cagf, reqf; u32 rpupei, rpcurup, rpprevup; @@ -1142,6 +1142,15 @@ static int i915_frequency_info(struct seq_file *m, void *unused) u32 pm_ier, pm_imr, pm_isr, pm_iir, pm_mask; int max_freq; + rp_state_limits = I915_READ(GEN6_RP_STATE_LIMITS); + if (IS_BROXTON(dev)) { + rp_state_cap = I915_READ(BXT_RP_STATE_CAP); + gt_perf_status = I915_READ(BXT_GT_PERF_STATUS); + } else { + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS); + } + /* RPSTAT1 is in the GT power well */ ret = mutex_lock_interruptible(&dev->struct_mutex); if (ret) @@ -1229,7 +1238,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "Down threshold: %d%%\n", dev_priv->rps.down_threshold); - max_freq = (rp_state_cap & 0xff0000) >> 16; + max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 0 : + rp_state_cap >> 16) & 0xff; max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Lowest (RPN) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); @@ -1239,7 +1249,8 @@ static int i915_frequency_info(struct seq_file *m, void *unused) seq_printf(m, "Nominal (RP1) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); - max_freq = rp_state_cap & 0xff; + max_freq = (IS_BROXTON(dev) ? rp_state_cap >> 16 : + rp_state_cap >> 0) & 0xff; max_freq *= (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1); seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n", intel_gpu_freq(dev_priv, max_freq)); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index c19067c843e87..b6c8037a9e541 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2734,8 +2734,10 @@ enum skl_disp_power_wells { #define GEN6_GT_THREAD_STATUS_CORE_MASK 0x7 #define GEN6_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x5948) +#define BXT_GT_PERF_STATUS (MCHBAR_MIRROR_BASE_SNB + 0x7070) #define GEN6_RP_STATE_LIMITS (MCHBAR_MIRROR_BASE_SNB + 0x5994) #define GEN6_RP_STATE_CAP (MCHBAR_MIRROR_BASE_SNB + 0x5998) +#define BXT_RP_STATE_CAP 0x138170 #define INTERVAL_1_28_US(us) (((us) * 100) >> 7) #define INTERVAL_1_33_US(us) (((us) * 3) >> 2) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 32ff034a0875d..213da42d6c24b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4288,13 +4288,21 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) u32 ddcc_status = 0; int ret; - rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); /* All of these values are in units of 50MHz */ dev_priv->rps.cur_freq = 0; /* static values from HW: RP0 > RP1 > RPn (min_freq) */ - dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff; - dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; - dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; + if (IS_BROXTON(dev)) { + rp_state_cap = I915_READ(BXT_RP_STATE_CAP); + dev_priv->rps.rp0_freq = (rp_state_cap >> 16) & 0xff; + dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; + dev_priv->rps.min_freq = (rp_state_cap >> 0) & 0xff; + } else { + rp_state_cap = I915_READ(GEN6_RP_STATE_CAP); + dev_priv->rps.rp0_freq = (rp_state_cap >> 0) & 0xff; + dev_priv->rps.rp1_freq = (rp_state_cap >> 8) & 0xff; + dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; + } + if (IS_SKYLAKE(dev)) { /* Store the frequency values in 16.66 MHZ units, which is the natural hardware unit for SKL */ -- GitLab From e7ad987832637701fc723ac2c1580c30c191bca6 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Fri, 26 Jun 2015 18:34:29 +0100 Subject: [PATCH 0279/7006] drm/i915/skl: Skip remaining dividers when deviation is 0 We can't improve a 0 deviation, so when we find such a divider, skip the remaining ones they won't be better. This short-circuit the search for 34 of the 373 test frequencies in the corresponding i-g-t test (tools/skl_compute_wrpll) v2: Place the short-circuiting code in skl_compute_wrpll() (Paulo) (I'm sure nobody will notice the spurious removal of a blank line) Reviewed-by: Paulo Zanoni Suggested-by: Paulo Zanoni Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index f6b3ccc4ab669..42c14870ef439 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1149,7 +1149,6 @@ static void skl_wrpll_try_divider(struct skl_wrpll_context *ctx, ctx->dco_freq = dco_freq; ctx->p = divider; } - } static void skl_wrpll_get_multipliers(unsigned int p, @@ -1315,9 +1314,17 @@ skl_ddi_calculate_wrpll(int clock /* in Hz */, dco_central_freq[dco], dco_freq, p); + /* + * Skip the remaining dividers if we're sure to + * have found the definitive divider, we can't + * improve a 0 deviation. + */ + if (ctx.min_deviation == 0) + goto skip_remaining_dividers; } } +skip_remaining_dividers: /* * If a solution is found with an even divider, prefer * this one. -- GitLab From 066cf55b9ce35f1f90dde9fcec01431a9243a949 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 26 Jun 2015 13:55:54 -0700 Subject: [PATCH 0280/7006] drm/i915: Fix IPS related flicker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We cannot let IPS enabled with no plane on the pipe: BSpec: "IPS cannot be enabled until after at least one plane has been enabled for at least one vertical blank." and "IPS must be disabled while there is still at least one plane enabled on the same pipe as IPS." This restriction apply to HSW and BDW. However a shortcut path on update primary plane function to make primary plane invisible by setting DSPCTRL to 0 was leting IPS enabled while there was no other plane enabled on the pipe causing flickerings that we were believing that it was caused by that other restriction where ips cannot be used when pixel rate is greater than 95% of cdclok. v2: Don't mess with Atomic path as pointed out by Ville. v3: Rebase after a long time and atomic path changes. Accept Ville suggestion of not check !fb v4: Re-factore on dinq Reference: https://bugs.freedesktop.org/show_bug.cgi?id=85583 Cc: Paulo Zanoni Cc: Jani Nikula Cc: Daniel Vetter Reviewed-by: Ville Syrjälä Tested-by: Kenneth Graunke [danvet: Make it compile] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 16 +++++++++++++++- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 01eaab8b6d40a..eb665d7ffda70 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4766,6 +4766,9 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) mutex_unlock(&dev->struct_mutex); } + if (crtc->atomic.disable_ips) + hsw_disable_ips(crtc); + if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); } @@ -11616,8 +11619,19 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, intel_crtc->atomic.pre_disable_primary = turn_off; intel_crtc->atomic.post_enable_primary = turn_on; - if (turn_off) + if (turn_off) { + /* + * FIXME: Actually if we will still have any other + * plane enabled on the pipe we could let IPS enabled + * still, but for now lets consider that when we make + * primary invisible by setting DSPCNTR to 0 on + * update_primary_plane function IPS needs to be + * disable. + */ + intel_crtc->atomic.disable_ips = true; + intel_crtc->atomic.disable_fbc = true; + } /* * FBC does not work on some platforms for rotated diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e016d722cacb4..33cff9d9a7a14 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -498,6 +498,7 @@ struct intel_crtc_atomic_commit { /* Sleepable operations to perform before commit */ bool wait_for_flips; bool disable_fbc; + bool disable_ips; bool pre_disable_primary; bool update_wm; unsigned disabled_planes; -- GitLab From 031b698a77a70a6c394568034437b5486a44e868 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 26 Jun 2015 19:35:16 +0200 Subject: [PATCH 0281/7006] drm/i915: Unconditionally do fb tracking invalidate in set_domain We can't elide the fb tracking invalidate if the buffer is already in the right domain since that would lead to missed screen updates. I'm pretty sure I've written this already before but must have gotten lost unfortunately :( v2: Chris observed that all internal set_domain users already correctly do the fb invalidate on their own, hence we can move this just into the set_domain ioctl instead. v3: I screwed up setting the invalidate ORIGIN_* correctly (Chris). Cc: Chris Wilson Reported-by: Paulo Zanoni Cc: Paulo Zanoni Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Tested-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index db1955fad0059..37cd901c9d750 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1614,6 +1614,11 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data, else ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0); + if (write_domain != 0) + intel_fb_obj_invalidate(obj, + write_domain == I915_GEM_DOMAIN_GTT ? + ORIGIN_GTT : ORIGIN_CPU); + unref: drm_gem_object_unreference(&obj->base); unlock: @@ -3982,9 +3987,6 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write) obj->dirty = 1; } - if (write) - intel_fb_obj_invalidate(obj, ORIGIN_GTT); - trace_i915_gem_object_change_domain(obj, old_read_domains, old_write_domain); @@ -4256,9 +4258,6 @@ i915_gem_object_set_to_cpu_domain(struct drm_i915_gem_object *obj, bool write) obj->base.write_domain = I915_GEM_DOMAIN_CPU; } - if (write) - intel_fb_obj_invalidate(obj, ORIGIN_CPU); - trace_i915_gem_object_change_domain(obj, old_read_domains, old_write_domain); -- GitLab From a7a6c498927ea42c9a3b26e0caa5c854a980d58c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:01 +0300 Subject: [PATCH 0282/7006] drm/i915: POSTING_READ() in intel_set_memory_cxsr() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want cxsr exit to happen ASAP, so toss in some POSTING_READ()s to make sure things are really kicked off. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 213da42d6c24b..66a70966ed43f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -334,22 +334,27 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable) if (IS_VALLEYVIEW(dev)) { I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0); + POSTING_READ(FW_BLC_SELF_VLV); if (IS_CHERRYVIEW(dev)) chv_set_memory_pm5(dev_priv, enable); } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) { I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0); + POSTING_READ(FW_BLC_SELF); } else if (IS_PINEVIEW(dev)) { val = I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN; val |= enable ? PINEVIEW_SELF_REFRESH_EN : 0; I915_WRITE(DSPFW3, val); + POSTING_READ(DSPFW3); } else if (IS_I945G(dev) || IS_I945GM(dev)) { val = enable ? _MASKED_BIT_ENABLE(FW_BLC_SELF_EN) : _MASKED_BIT_DISABLE(FW_BLC_SELF_EN); I915_WRITE(FW_BLC_SELF, val); + POSTING_READ(FW_BLC_SELF); } else if (IS_I915GM(dev)) { val = enable ? _MASKED_BIT_ENABLE(INSTPM_SELF_EN) : _MASKED_BIT_DISABLE(INSTPM_SELF_EN); I915_WRITE(INSTPM, val); + POSTING_READ(INSTPM); } else { return; } -- GitLab From f015c5518879fb3e578caaa63806617468a24045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:02 +0300 Subject: [PATCH 0283/7006] drm/i915: Split atomic wm update to pre and post variants MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Try to update the watermarks on the right side of the plane update. This is just a temporary hack until we get the proper two part update into place. However in the meantime this might have some chance of at least working. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb665d7ffda70..8024e7a30eed7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4722,6 +4722,9 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_frontbuffer_flip(dev, atomic->fb_bits); + if (crtc->atomic.update_wm_post) + intel_update_watermarks(&crtc->base); + if (atomic->update_fbc) { mutex_lock(&dev->struct_mutex); intel_fbc_update(dev); @@ -11606,8 +11609,12 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, plane->base.id, was_visible, visible, turn_off, turn_on, mode_changed); - if (intel_wm_need_update(plane, plane_state)) - intel_crtc->atomic.update_wm = true; + if (turn_on) + intel_crtc->atomic.update_wm_pre = true; + else if (turn_off) + intel_crtc->atomic.update_wm_post = true; + else if (intel_wm_need_update(plane, plane_state)) + intel_crtc->atomic.update_wm_pre = true; if (visible) intel_crtc->atomic.fb_bits |= @@ -11776,7 +11783,7 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, intel_crtc_check_initial_planes(crtc, crtc_state); if (mode_changed) - intel_crtc->atomic.update_wm = !crtc_state->active; + intel_crtc->atomic.update_wm_post = !crtc_state->active; if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && @@ -13705,7 +13712,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) if (!needs_modeset(crtc->state)) intel_pre_plane_update(intel_crtc); - if (intel_crtc->atomic.update_wm) + if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); intel_runtime_pm_get(dev_priv); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 33cff9d9a7a14..a02bdfbc6accc 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -500,7 +500,7 @@ struct intel_crtc_atomic_commit { bool disable_fbc; bool disable_ips; bool pre_disable_primary; - bool update_wm; + bool update_wm_pre, update_wm_post; unsigned disabled_planes; /* Sleepable operations to perform after commit */ -- GitLab From 6eb1a6817246f1a67de4d6959a84d09efead5329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:03 +0300 Subject: [PATCH 0284/7006] drm/i915: Read wm values from hardware at init on CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Read out the current watermark settings from the hardware at driver init time. This will allow us to compare the newly calculated values against the currrent ones and potentially avoid needless WM updates. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 4 +- drivers/gpu/drm/i915/intel_drv.h | 2 + drivers/gpu/drm/i915/intel_pm.c | 141 +++++++++++++++++++++++++++ 4 files changed, 148 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index ea9caf22283f6..2009ba5163346 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1515,6 +1515,8 @@ struct vlv_wm_values { uint8_t sprite[2]; uint8_t primary; } ddl[3]; + uint8_t level; + bool cxsr; }; struct skl_ddb_entry { diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8024e7a30eed7..2295f08ac0b6b 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15453,7 +15453,9 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (IS_GEN9(dev)) + if (IS_CHERRYVIEW(dev)) + vlv_wm_get_hw_state(dev); + else if (IS_GEN9(dev)) skl_wm_get_hw_state(dev); else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index a02bdfbc6accc..e7a82dcfda245 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -583,6 +583,7 @@ struct intel_plane_wm_parameters { bool scaled; u64 tiling; unsigned int rotation; + uint16_t fifo_size; }; struct intel_plane { @@ -1368,6 +1369,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv, unsigned long submitted); void intel_queue_rps_boost_for_request(struct drm_device *dev, struct drm_i915_gem_request *req); +void vlv_wm_get_hw_state(struct drm_device *dev); void ilk_wm_get_hw_state(struct drm_device *dev); void skl_wm_get_hw_state(struct drm_device *dev); void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 66a70966ed43f..8ea4768dcf10c 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1006,6 +1006,14 @@ static int vlv_compute_wm(struct intel_crtc *crtc, return fifo_size - clamp(DIV_ROUND_UP(256 * entries, 64), 0, fifo_size - 8); } +enum vlv_wm_level { + VLV_WM_LEVEL_PM2, + VLV_WM_LEVEL_PM5, + VLV_WM_LEVEL_DDR_DVFS, + CHV_WM_NUM_LEVELS, + VLV_WM_NUM_LEVELS = 1, +}; + static bool vlv_compute_sr_wm(struct drm_device *dev, struct vlv_wm_values *wm) { @@ -3689,6 +3697,139 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc) } } +#define _FW_WM(value, plane) \ + (((value) & DSPFW_ ## plane ## _MASK) >> DSPFW_ ## plane ## _SHIFT) +#define _FW_WM_VLV(value, plane) \ + (((value) & DSPFW_ ## plane ## _MASK_VLV) >> DSPFW_ ## plane ## _SHIFT) + +static void vlv_read_wm_values(struct drm_i915_private *dev_priv, + struct vlv_wm_values *wm) +{ + enum pipe pipe; + uint32_t tmp; + + for_each_pipe(dev_priv, pipe) { + tmp = I915_READ(VLV_DDL(pipe)); + + wm->ddl[pipe].primary = + (tmp >> DDL_PLANE_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + wm->ddl[pipe].cursor = + (tmp >> DDL_CURSOR_SHIFT) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + wm->ddl[pipe].sprite[0] = + (tmp >> DDL_SPRITE_SHIFT(0)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + wm->ddl[pipe].sprite[1] = + (tmp >> DDL_SPRITE_SHIFT(1)) & (DDL_PRECISION_HIGH | DRAIN_LATENCY_MASK); + } + + tmp = I915_READ(DSPFW1); + wm->sr.plane = _FW_WM(tmp, SR); + wm->pipe[PIPE_B].cursor = _FW_WM(tmp, CURSORB); + wm->pipe[PIPE_B].primary = _FW_WM_VLV(tmp, PLANEB); + wm->pipe[PIPE_A].primary = _FW_WM_VLV(tmp, PLANEA); + + tmp = I915_READ(DSPFW2); + wm->pipe[PIPE_A].sprite[1] = _FW_WM_VLV(tmp, SPRITEB); + wm->pipe[PIPE_A].cursor = _FW_WM(tmp, CURSORA); + wm->pipe[PIPE_A].sprite[0] = _FW_WM_VLV(tmp, SPRITEA); + + tmp = I915_READ(DSPFW3); + wm->sr.cursor = _FW_WM(tmp, CURSOR_SR); + + if (IS_CHERRYVIEW(dev_priv)) { + tmp = I915_READ(DSPFW7_CHV); + wm->pipe[PIPE_B].sprite[1] = _FW_WM_VLV(tmp, SPRITED); + wm->pipe[PIPE_B].sprite[0] = _FW_WM_VLV(tmp, SPRITEC); + + tmp = I915_READ(DSPFW8_CHV); + wm->pipe[PIPE_C].sprite[1] = _FW_WM_VLV(tmp, SPRITEF); + wm->pipe[PIPE_C].sprite[0] = _FW_WM_VLV(tmp, SPRITEE); + + tmp = I915_READ(DSPFW9_CHV); + wm->pipe[PIPE_C].primary = _FW_WM_VLV(tmp, PLANEC); + wm->pipe[PIPE_C].cursor = _FW_WM(tmp, CURSORC); + + tmp = I915_READ(DSPHOWM); + wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9; + wm->pipe[PIPE_C].sprite[1] |= _FW_WM(tmp, SPRITEF_HI) << 8; + wm->pipe[PIPE_C].sprite[0] |= _FW_WM(tmp, SPRITEE_HI) << 8; + wm->pipe[PIPE_C].primary |= _FW_WM(tmp, PLANEC_HI) << 8; + wm->pipe[PIPE_B].sprite[1] |= _FW_WM(tmp, SPRITED_HI) << 8; + wm->pipe[PIPE_B].sprite[0] |= _FW_WM(tmp, SPRITEC_HI) << 8; + wm->pipe[PIPE_B].primary |= _FW_WM(tmp, PLANEB_HI) << 8; + wm->pipe[PIPE_A].sprite[1] |= _FW_WM(tmp, SPRITEB_HI) << 8; + wm->pipe[PIPE_A].sprite[0] |= _FW_WM(tmp, SPRITEA_HI) << 8; + wm->pipe[PIPE_A].primary |= _FW_WM(tmp, PLANEA_HI) << 8; + } else { + tmp = I915_READ(DSPFW7); + wm->pipe[PIPE_B].sprite[1] = _FW_WM_VLV(tmp, SPRITED); + wm->pipe[PIPE_B].sprite[0] = _FW_WM_VLV(tmp, SPRITEC); + + tmp = I915_READ(DSPHOWM); + wm->sr.plane |= _FW_WM(tmp, SR_HI) << 9; + wm->pipe[PIPE_B].sprite[1] |= _FW_WM(tmp, SPRITED_HI) << 8; + wm->pipe[PIPE_B].sprite[0] |= _FW_WM(tmp, SPRITEC_HI) << 8; + wm->pipe[PIPE_B].primary |= _FW_WM(tmp, PLANEB_HI) << 8; + wm->pipe[PIPE_A].sprite[1] |= _FW_WM(tmp, SPRITEB_HI) << 8; + wm->pipe[PIPE_A].sprite[0] |= _FW_WM(tmp, SPRITEA_HI) << 8; + wm->pipe[PIPE_A].primary |= _FW_WM(tmp, PLANEA_HI) << 8; + } +} + +#undef _FW_WM +#undef _FW_WM_VLV + +void vlv_wm_get_hw_state(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = to_i915(dev); + struct vlv_wm_values *wm = &dev_priv->wm.vlv; + struct intel_plane *plane; + enum pipe pipe; + u32 val; + + vlv_read_wm_values(dev_priv, wm); + + for_each_intel_plane(dev, plane) { + switch (plane->base.type) { + int sprite; + case DRM_PLANE_TYPE_CURSOR: + plane->wm.fifo_size = 63; + break; + case DRM_PLANE_TYPE_PRIMARY: + plane->wm.fifo_size = vlv_get_fifo_size(dev, plane->pipe, 0); + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + plane->wm.fifo_size = vlv_get_fifo_size(dev, plane->pipe, sprite + 1); + break; + } + } + + wm->cxsr = I915_READ(FW_BLC_SELF_VLV) & FW_CSPWRDWNEN; + wm->level = VLV_WM_LEVEL_PM2; + + if (IS_CHERRYVIEW(dev_priv)) { + mutex_lock(&dev_priv->rps.hw_lock); + + val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ); + if (val & DSP_MAXFIFO_PM5_ENABLE) + wm->level = VLV_WM_LEVEL_PM5; + + val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2); + if ((val & FORCE_DDR_HIGH_FREQ) == 0) + wm->level = VLV_WM_LEVEL_DDR_DVFS; + + mutex_unlock(&dev_priv->rps.hw_lock); + } + + for_each_pipe(dev_priv, pipe) + DRM_DEBUG_KMS("Initial watermarks: pipe %c, plane=%d, cursor=%d, sprite0=%d, sprite1=%d\n", + pipe_name(pipe), wm->pipe[pipe].primary, wm->pipe[pipe].cursor, + wm->pipe[pipe].sprite[0], wm->pipe[pipe].sprite[1]); + + DRM_DEBUG_KMS("Initial watermarks: SR plane=%d, SR cursor=%d level=%d cxsr=%d\n", + wm->sr.plane, wm->sr.cursor, wm->level, wm->cxsr); +} + void ilk_wm_get_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- GitLab From 262cd2e154c29dc3a235f68cc91e13d8f48e8002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:04 +0300 Subject: [PATCH 0285/7006] drm/i915: CHV DDR DVFS support and another watermark rewrite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Turns out the VLV/CHV system agent doesn't understand memory latencies, so trying to rely on the PND deadline mechanism is not going to fly especially when DDR DVFS is enabled. Currently we try to avoid the problems by lying to the system agent about the deadlines and setting the FIFO watermarks to 8 cachelines. This however leads to bad memory self refresh residency. So in order to satosfy everyone we'll just give up on the deadline scheme and program the watermarks old school based on the worst case memory latency. I've modelled this a bit on the ILK+ approach where we compute multiple sets of watermarks for each pipe (PM2,PM5,DDR DVFS) and when merge thet appropriate one later with the watermarks from other pipes. There isn't too much to merge actually since each pipe has a totally independent FIFO (well apart from the mess with the partially shared DSPARB registers), but still decopuling the pipes from each other seems like a good idea. Eventually we'll want to perform the watermark update in two phases around the plane update to avoid underruns due to the single buffered watermark registers. But that's still in limbo for ILK+ too, so I've not gone that far yet for VLV/CHV either. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 28 ++- drivers/gpu/drm/i915/intel_display.c | 6 +- drivers/gpu/drm/i915/intel_drv.h | 11 + drivers/gpu/drm/i915/intel_pm.c | 318 ++++++++++++++++++++++++++- 4 files changed, 345 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2009ba5163346..6acc6504863b6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -276,6 +276,12 @@ struct i915_hotplug { &dev->mode_config.plane_list, \ base.head) +#define for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) \ + list_for_each_entry(intel_plane, \ + &(dev)->mode_config.plane_list, \ + base.head) \ + if ((intel_plane)->pipe == (intel_crtc)->pipe) + #define for_each_intel_crtc(dev, intel_crtc) \ list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list, base.head) @@ -1498,18 +1504,20 @@ struct ilk_wm_values { enum intel_ddb_partitioning partitioning; }; -struct vlv_wm_values { - struct { - uint16_t primary; - uint16_t sprite[2]; - uint8_t cursor; - } pipe[3]; +struct vlv_pipe_wm { + uint16_t primary; + uint16_t sprite[2]; + uint8_t cursor; +}; - struct { - uint16_t plane; - uint8_t cursor; - } sr; +struct vlv_sr_wm { + uint16_t plane; + uint8_t cursor; +}; +struct vlv_wm_values { + struct vlv_pipe_wm pipe[3]; + struct vlv_sr_wm sr; struct { uint8_t cursor; uint8_t sprite[2]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 2295f08ac0b6b..7baa45db97563 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4699,8 +4699,11 @@ intel_pre_disable_primary(struct drm_crtc *crtc) * event which is after the vblank start event, so we need to have a * wait-for-vblank between disabling the plane and the pipe. */ - if (HAS_GMCH_DISPLAY(dev)) + if (HAS_GMCH_DISPLAY(dev)) { intel_set_memory_cxsr(dev_priv, false); + dev_priv->wm.vlv.cxsr = false; + intel_wait_for_vblank(dev, pipe); + } /* * FIXME IPS should be fine as long as one plane is @@ -6017,7 +6020,6 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc) intel_crtc_load_lut(crtc); - intel_update_watermarks(crtc); intel_enable_pipe(intel_crtc); assert_vblank_disabled(crtc); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index e7a82dcfda245..8397d1c9005bf 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -462,6 +462,15 @@ struct intel_crtc_state { enum pipe hsw_workaround_pipe; }; +struct vlv_wm_state { + struct vlv_pipe_wm wm[3]; + struct vlv_sr_wm sr[3]; + uint8_t num_active_planes; + uint8_t num_levels; + uint8_t level; + bool cxsr; +}; + struct intel_pipe_wm { struct intel_wm_level wm[5]; uint32_t linetime; @@ -565,6 +574,8 @@ struct intel_crtc { /* scalers available on this crtc */ int num_scalers; + + struct vlv_wm_state wm_state; }; struct intel_plane_wm_parameters { diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 8ea4768dcf10c..23e5be9887a37 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -335,8 +335,6 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable) if (IS_VALLEYVIEW(dev)) { I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0); POSTING_READ(FW_BLC_SELF_VLV); - if (IS_CHERRYVIEW(dev)) - chv_set_memory_pm5(dev_priv, enable); } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) { I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0); POSTING_READ(FW_BLC_SELF); @@ -929,8 +927,6 @@ static void vlv_write_wm_values(struct intel_crtc *crtc, } POSTING_READ(DSPFW1); - - dev_priv->wm.vlv = *wm; } #undef FW_WM_VLV @@ -1014,6 +1010,72 @@ enum vlv_wm_level { VLV_WM_NUM_LEVELS = 1, }; +/* latency must be in 0.1us units. */ +static unsigned int vlv_wm_method2(unsigned int pixel_rate, + unsigned int pipe_htotal, + unsigned int horiz_pixels, + unsigned int bytes_per_pixel, + unsigned int latency) +{ + unsigned int ret; + + ret = (latency * pixel_rate) / (pipe_htotal * 10000); + ret = (ret + 1) * horiz_pixels * bytes_per_pixel; + ret = DIV_ROUND_UP(ret, 64); + + return ret; +} + +static void vlv_setup_wm_latency(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* all latencies in usec */ + dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM2] = 3; + + if (IS_CHERRYVIEW(dev_priv)) { + dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM5] = 12; + dev_priv->wm.pri_latency[VLV_WM_LEVEL_DDR_DVFS] = 33; + } +} + +static uint16_t vlv_compute_wm_level(struct intel_plane *plane, + struct intel_crtc *crtc, + const struct intel_plane_state *state, + int level) +{ + struct drm_i915_private *dev_priv = to_i915(plane->base.dev); + int clock, htotal, pixel_size, width, wm; + + if (dev_priv->wm.pri_latency[level] == 0) + return USHRT_MAX; + + if (!state->visible) + return 0; + + pixel_size = drm_format_plane_cpp(state->base.fb->pixel_format, 0); + clock = crtc->config->base.adjusted_mode.crtc_clock; + htotal = crtc->config->base.adjusted_mode.crtc_htotal; + width = crtc->config->pipe_src_w; + if (WARN_ON(htotal == 0)) + htotal = 1; + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + /* + * FIXME the formula gives values that are + * too big for the cursor FIFO, and hence we + * would never be able to use cursors. For + * now just hardcode the watermark. + */ + wm = 63; + } else { + wm = vlv_wm_method2(clock, htotal, width, pixel_size, + dev_priv->wm.pri_latency[level] * 10); + } + + return min_t(int, wm, USHRT_MAX); +} + static bool vlv_compute_sr_wm(struct drm_device *dev, struct vlv_wm_values *wm) { @@ -1105,6 +1167,249 @@ static void valleyview_update_wm(struct drm_crtc *crtc) if (cxsr_enabled) intel_set_memory_cxsr(dev_priv, true); + + dev_priv->wm.vlv = wm; +} + +static void vlv_invert_wms(struct intel_crtc *crtc) +{ + struct vlv_wm_state *wm_state = &crtc->wm_state; + int level; + + for (level = 0; level < wm_state->num_levels; level++) { + struct drm_device *dev = crtc->base.dev; + const int sr_fifo_size = INTEL_INFO(dev)->num_pipes * 512 - 1; + struct intel_plane *plane; + + wm_state->sr[level].plane = sr_fifo_size - wm_state->sr[level].plane; + wm_state->sr[level].cursor = 63 - wm_state->sr[level].cursor; + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + switch (plane->base.type) { + int sprite; + case DRM_PLANE_TYPE_CURSOR: + wm_state->wm[level].cursor = plane->wm.fifo_size - + wm_state->wm[level].cursor; + break; + case DRM_PLANE_TYPE_PRIMARY: + wm_state->wm[level].primary = plane->wm.fifo_size - + wm_state->wm[level].primary; + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + wm_state->wm[level].sprite[sprite] = plane->wm.fifo_size - + wm_state->wm[level].sprite[sprite]; + break; + } + } + } +} + +static void _vlv_compute_wm(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct vlv_wm_state *wm_state = &crtc->wm_state; + struct intel_plane *plane; + int sr_fifo_size = INTEL_INFO(dev)->num_pipes * 512 - 1; + int level; + + memset(wm_state, 0, sizeof(*wm_state)); + + wm_state->cxsr = crtc->pipe != PIPE_C; + if (IS_CHERRYVIEW(dev)) + wm_state->num_levels = CHV_WM_NUM_LEVELS; + else + wm_state->num_levels = VLV_WM_NUM_LEVELS; + + wm_state->num_active_planes = 0; + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + if (state->visible) + wm_state->num_active_planes++; + } + + if (wm_state->num_active_planes != 1) + wm_state->cxsr = false; + + if (wm_state->cxsr) { + for (level = 0; level < wm_state->num_levels; level++) { + wm_state->sr[level].plane = sr_fifo_size; + wm_state->sr[level].cursor = 63; + } + } + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + + if (!state->visible) + continue; + + /* normal watermarks */ + for (level = 0; level < wm_state->num_levels; level++) { + int wm = vlv_compute_wm_level(plane, crtc, state, level); + int max_wm = plane->base.type == DRM_PLANE_TYPE_CURSOR ? 63 : 511; + + /* hack */ + if (WARN_ON(level == 0 && wm > max_wm)) + wm = max_wm; + + if (wm > plane->wm.fifo_size) + break; + + switch (plane->base.type) { + int sprite; + case DRM_PLANE_TYPE_CURSOR: + wm_state->wm[level].cursor = wm; + break; + case DRM_PLANE_TYPE_PRIMARY: + wm_state->wm[level].primary = wm; + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + wm_state->wm[level].sprite[sprite] = wm; + break; + } + } + + wm_state->num_levels = level; + + if (!wm_state->cxsr) + continue; + + /* maxfifo watermarks */ + switch (plane->base.type) { + int sprite, level; + case DRM_PLANE_TYPE_CURSOR: + for (level = 0; level < wm_state->num_levels; level++) + wm_state->sr[level].cursor = + wm_state->sr[level].cursor; + break; + case DRM_PLANE_TYPE_PRIMARY: + for (level = 0; level < wm_state->num_levels; level++) + wm_state->sr[level].plane = + min(wm_state->sr[level].plane, + wm_state->wm[level].primary); + break; + case DRM_PLANE_TYPE_OVERLAY: + sprite = plane->plane; + for (level = 0; level < wm_state->num_levels; level++) + wm_state->sr[level].plane = + min(wm_state->sr[level].plane, + wm_state->wm[level].sprite[sprite]); + break; + } + } + + /* clear any (partially) filled invalid levels */ + for (level = wm_state->num_levels; level < CHV_WM_NUM_LEVELS; level++) { + memset(&wm_state->wm[level], 0, sizeof(wm_state->wm[level])); + memset(&wm_state->sr[level], 0, sizeof(wm_state->sr[level])); + } + + vlv_invert_wms(crtc); +} + +static void vlv_merge_wm(struct drm_device *dev, + struct vlv_wm_values *wm) +{ + struct intel_crtc *crtc; + int num_active_crtcs = 0; + + if (IS_CHERRYVIEW(dev)) + wm->level = VLV_WM_LEVEL_DDR_DVFS; + else + wm->level = VLV_WM_LEVEL_PM2; + wm->cxsr = true; + + for_each_intel_crtc(dev, crtc) { + const struct vlv_wm_state *wm_state = &crtc->wm_state; + + if (!crtc->active) + continue; + + if (!wm_state->cxsr) + wm->cxsr = false; + + num_active_crtcs++; + wm->level = min_t(int, wm->level, wm_state->num_levels - 1); + } + + if (num_active_crtcs != 1) + wm->cxsr = false; + + for_each_intel_crtc(dev, crtc) { + struct vlv_wm_state *wm_state = &crtc->wm_state; + enum pipe pipe = crtc->pipe; + + if (!crtc->active) + continue; + + wm->pipe[pipe] = wm_state->wm[wm->level]; + if (wm->cxsr) + wm->sr = wm_state->sr[wm->level]; + + wm->ddl[pipe].primary = DDL_PRECISION_HIGH | 2; + wm->ddl[pipe].sprite[0] = DDL_PRECISION_HIGH | 2; + wm->ddl[pipe].sprite[1] = DDL_PRECISION_HIGH | 2; + wm->ddl[pipe].cursor = DDL_PRECISION_HIGH | 2; + } +} + +static void vlv_update_wm(struct drm_crtc *crtc) +{ + struct drm_device *dev = crtc->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum pipe pipe = intel_crtc->pipe; + struct vlv_wm_values wm = {}; + + _vlv_compute_wm(intel_crtc); + vlv_merge_wm(dev, &wm); + + if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) + return; + + if (wm.level < VLV_WM_LEVEL_DDR_DVFS && + dev_priv->wm.vlv.level >= VLV_WM_LEVEL_DDR_DVFS) + chv_set_memory_dvfs(dev_priv, false); + + if (wm.level < VLV_WM_LEVEL_PM5 && + dev_priv->wm.vlv.level >= VLV_WM_LEVEL_PM5) + chv_set_memory_pm5(dev_priv, false); + + if (!wm.cxsr && dev_priv->wm.vlv.cxsr) { + intel_set_memory_cxsr(dev_priv, false); + intel_wait_for_vblank(dev, pipe); + } + + vlv_write_wm_values(intel_crtc, &wm); + + DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, " + "sprite0=%d, sprite1=%d, SR: plane=%d, cursor=%d level=%d cxsr=%d\n", + pipe_name(pipe), wm.pipe[pipe].primary, wm.pipe[pipe].cursor, + wm.pipe[pipe].sprite[0], wm.pipe[pipe].sprite[1], + wm.sr.plane, wm.sr.cursor, wm.level, wm.cxsr); + + if (wm.cxsr && !dev_priv->wm.vlv.cxsr) { + intel_wait_for_vblank(dev, pipe); + intel_set_memory_cxsr(dev_priv, true); + } + + if (wm.level >= VLV_WM_LEVEL_PM5 && + dev_priv->wm.vlv.level < VLV_WM_LEVEL_PM5) + chv_set_memory_pm5(dev_priv, true); + + if (wm.level >= VLV_WM_LEVEL_DDR_DVFS && + dev_priv->wm.vlv.level < VLV_WM_LEVEL_DDR_DVFS) + chv_set_memory_dvfs(dev_priv, true); + + dev_priv->wm.vlv = wm; } static void valleyview_update_sprite_wm(struct drm_plane *plane, @@ -6831,8 +7136,9 @@ void intel_init_pm(struct drm_device *dev) else if (INTEL_INFO(dev)->gen == 8) dev_priv->display.init_clock_gating = broadwell_init_clock_gating; } else if (IS_CHERRYVIEW(dev)) { - dev_priv->display.update_wm = valleyview_update_wm; - dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm; + vlv_setup_wm_latency(dev); + + dev_priv->display.update_wm = vlv_update_wm; dev_priv->display.init_clock_gating = cherryview_init_clock_gating; } else if (IS_VALLEYVIEW(dev)) { -- GitLab From 54f1b6e15db87722aa21035169ce811af9d971fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:05 +0300 Subject: [PATCH 0286/7006] drm/i915: Compute display FIFO split dynamically for CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consider which planes are active and compute the FIFO split based on the relative data rates. Since we only consider the pipe src width rather than the plane width when computing watermarks it seems best to do the same when computing the FIFO split as well. This means the only thing we actually have to consider for the FIFO splut is the bpp, and we can ignore the rest. I've just stuffed the logic into the watermark code for now. Eventually it'll need to move into the atomic update for the crtc. There's also one extra complication I've not yet considered; Some of the DSPARB registers contain bits related to multiple pipes. The registers are double buffered but apparently they update on the vblank of any active pipe. So doing the FIFO reconfiguration properly when multiple pipes are active is not going to be fun. But let's ignore that mess for now. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 25 ++++- drivers/gpu/drm/i915/intel_pm.c | 175 ++++++++++++++++++++++++++++++-- 2 files changed, 189 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b6c8037a9e541..50e6279d7d562 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -4415,9 +4415,32 @@ enum skl_disp_power_wells { #define DSPARB_BSTART_SHIFT 0 #define DSPARB_BEND_SHIFT 9 /* on 855 */ #define DSPARB_AEND_SHIFT 0 - +#define DSPARB_SPRITEA_SHIFT_VLV 0 +#define DSPARB_SPRITEA_MASK_VLV (0xff << 0) +#define DSPARB_SPRITEB_SHIFT_VLV 8 +#define DSPARB_SPRITEB_MASK_VLV (0xff << 8) +#define DSPARB_SPRITEC_SHIFT_VLV 16 +#define DSPARB_SPRITEC_MASK_VLV (0xff << 16) +#define DSPARB_SPRITED_SHIFT_VLV 24 +#define DSPARB_SPRITED_MASK_VLV (0xff << 24) #define DSPARB2 (VLV_DISPLAY_BASE + 0x70060) /* vlv/chv */ +#define DSPARB_SPRITEA_HI_SHIFT_VLV 0 +#define DSPARB_SPRITEA_HI_MASK_VLV (0x1 << 0) +#define DSPARB_SPRITEB_HI_SHIFT_VLV 4 +#define DSPARB_SPRITEB_HI_MASK_VLV (0x1 << 4) +#define DSPARB_SPRITEC_HI_SHIFT_VLV 8 +#define DSPARB_SPRITEC_HI_MASK_VLV (0x1 << 8) +#define DSPARB_SPRITED_HI_SHIFT_VLV 12 +#define DSPARB_SPRITED_HI_MASK_VLV (0x1 << 12) +#define DSPARB_SPRITEE_HI_SHIFT_VLV 16 +#define DSPARB_SPRITEE_HI_MASK_VLV (0x1 << 16) +#define DSPARB_SPRITEF_HI_SHIFT_VLV 20 +#define DSPARB_SPRITEF_HI_MASK_VLV (0x1 << 20) #define DSPARB3 (VLV_DISPLAY_BASE + 0x7006c) /* chv */ +#define DSPARB_SPRITEE_SHIFT_VLV 0 +#define DSPARB_SPRITEE_MASK_VLV (0xff << 0) +#define DSPARB_SPRITEF_SHIFT_VLV 8 +#define DSPARB_SPRITEF_MASK_VLV (0xff << 8) /* pnv/gen4/g4x/vlv/chv */ #define DSPFW1 (dev_priv->info.display_mmio_offset + 0x70034) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 23e5be9887a37..49cca0b16cc66 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1171,6 +1171,73 @@ static void valleyview_update_wm(struct drm_crtc *crtc) dev_priv->wm.vlv = wm; } +static void vlv_compute_fifo(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct vlv_wm_state *wm_state = &crtc->wm_state; + struct intel_plane *plane; + unsigned int total_rate = 0; + const int fifo_size = 512 - 1; + int fifo_extra, fifo_left = fifo_size; + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + if (state->visible) { + wm_state->num_active_planes++; + total_rate += drm_format_plane_cpp(state->base.fb->pixel_format, 0); + } + } + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + struct intel_plane_state *state = + to_intel_plane_state(plane->base.state); + unsigned int rate; + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + plane->wm.fifo_size = 63; + continue; + } + + if (!state->visible) { + plane->wm.fifo_size = 0; + continue; + } + + rate = drm_format_plane_cpp(state->base.fb->pixel_format, 0); + plane->wm.fifo_size = fifo_size * rate / total_rate; + fifo_left -= plane->wm.fifo_size; + } + + fifo_extra = DIV_ROUND_UP(fifo_left, wm_state->num_active_planes ?: 1); + + /* spread the remainder evenly */ + for_each_intel_plane_on_crtc(dev, crtc, plane) { + int plane_extra; + + if (fifo_left == 0) + break; + + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) + continue; + + /* give it all to the first plane if none are active */ + if (plane->wm.fifo_size == 0 && + wm_state->num_active_planes) + continue; + + plane_extra = min(fifo_extra, fifo_left); + plane->wm.fifo_size += plane_extra; + fifo_left -= plane_extra; + } + + WARN_ON(fifo_left != 0); +} + static void vlv_invert_wms(struct intel_crtc *crtc) { struct vlv_wm_state *wm_state = &crtc->wm_state; @@ -1222,16 +1289,8 @@ static void _vlv_compute_wm(struct intel_crtc *crtc) wm_state->num_levels = VLV_WM_NUM_LEVELS; wm_state->num_active_planes = 0; - for_each_intel_plane_on_crtc(dev, crtc, plane) { - struct intel_plane_state *state = - to_intel_plane_state(plane->base.state); - - if (plane->base.type == DRM_PLANE_TYPE_CURSOR) - continue; - if (state->visible) - wm_state->num_active_planes++; - } + vlv_compute_fifo(crtc); if (wm_state->num_active_planes != 1) wm_state->cxsr = false; @@ -1315,6 +1374,96 @@ static void _vlv_compute_wm(struct intel_crtc *crtc) vlv_invert_wms(crtc); } +#define VLV_FIFO(plane, value) \ + (((value) << DSPARB_ ## plane ## _SHIFT_VLV) & DSPARB_ ## plane ## _MASK_VLV) + +static void vlv_pipe_set_fifo_size(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = to_i915(dev); + struct intel_plane *plane; + int sprite0_start = 0, sprite1_start = 0, fifo_size = 0; + + for_each_intel_plane_on_crtc(dev, crtc, plane) { + if (plane->base.type == DRM_PLANE_TYPE_CURSOR) { + WARN_ON(plane->wm.fifo_size != 63); + continue; + } + + if (plane->base.type == DRM_PLANE_TYPE_PRIMARY) + sprite0_start = plane->wm.fifo_size; + else if (plane->plane == 0) + sprite1_start = sprite0_start + plane->wm.fifo_size; + else + fifo_size = sprite1_start + plane->wm.fifo_size; + } + + WARN_ON(fifo_size != 512 - 1); + + DRM_DEBUG_KMS("Pipe %c FIFO split %d / %d / %d\n", + pipe_name(crtc->pipe), sprite0_start, + sprite1_start, fifo_size); + + switch (crtc->pipe) { + uint32_t dsparb, dsparb2, dsparb3; + case PIPE_A: + dsparb = I915_READ(DSPARB); + dsparb2 = I915_READ(DSPARB2); + + dsparb &= ~(VLV_FIFO(SPRITEA, 0xff) | + VLV_FIFO(SPRITEB, 0xff)); + dsparb |= (VLV_FIFO(SPRITEA, sprite0_start) | + VLV_FIFO(SPRITEB, sprite1_start)); + + dsparb2 &= ~(VLV_FIFO(SPRITEA_HI, 0x1) | + VLV_FIFO(SPRITEB_HI, 0x1)); + dsparb2 |= (VLV_FIFO(SPRITEA_HI, sprite0_start >> 8) | + VLV_FIFO(SPRITEB_HI, sprite1_start >> 8)); + + I915_WRITE(DSPARB, dsparb); + I915_WRITE(DSPARB2, dsparb2); + break; + case PIPE_B: + dsparb = I915_READ(DSPARB); + dsparb2 = I915_READ(DSPARB2); + + dsparb &= ~(VLV_FIFO(SPRITEC, 0xff) | + VLV_FIFO(SPRITED, 0xff)); + dsparb |= (VLV_FIFO(SPRITEC, sprite0_start) | + VLV_FIFO(SPRITED, sprite1_start)); + + dsparb2 &= ~(VLV_FIFO(SPRITEC_HI, 0xff) | + VLV_FIFO(SPRITED_HI, 0xff)); + dsparb2 |= (VLV_FIFO(SPRITEC_HI, sprite0_start >> 8) | + VLV_FIFO(SPRITED_HI, sprite1_start >> 8)); + + I915_WRITE(DSPARB, dsparb); + I915_WRITE(DSPARB2, dsparb2); + break; + case PIPE_C: + dsparb3 = I915_READ(DSPARB3); + dsparb2 = I915_READ(DSPARB2); + + dsparb3 &= ~(VLV_FIFO(SPRITEE, 0xff) | + VLV_FIFO(SPRITEF, 0xff)); + dsparb3 |= (VLV_FIFO(SPRITEE, sprite0_start) | + VLV_FIFO(SPRITEF, sprite1_start)); + + dsparb2 &= ~(VLV_FIFO(SPRITEE_HI, 0xff) | + VLV_FIFO(SPRITEF_HI, 0xff)); + dsparb2 |= (VLV_FIFO(SPRITEE_HI, sprite0_start >> 8) | + VLV_FIFO(SPRITEF_HI, sprite1_start >> 8)); + + I915_WRITE(DSPARB3, dsparb3); + I915_WRITE(DSPARB2, dsparb2); + break; + default: + break; + } +} + +#undef VLV_FIFO + static void vlv_merge_wm(struct drm_device *dev, struct vlv_wm_values *wm) { @@ -1372,8 +1521,11 @@ static void vlv_update_wm(struct drm_crtc *crtc) _vlv_compute_wm(intel_crtc); vlv_merge_wm(dev, &wm); - if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) + if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) { + /* FIXME should be part of crtc atomic commit */ + vlv_pipe_set_fifo_size(intel_crtc); return; + } if (wm.level < VLV_WM_LEVEL_DDR_DVFS && dev_priv->wm.vlv.level >= VLV_WM_LEVEL_DDR_DVFS) @@ -1388,6 +1540,9 @@ static void vlv_update_wm(struct drm_crtc *crtc) intel_wait_for_vblank(dev, pipe); } + /* FIXME should be part of crtc atomic commit */ + vlv_pipe_set_fifo_size(intel_crtc); + vlv_write_wm_values(intel_crtc, &wm); DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, " -- GitLab From 26e1fe4fbd4c15919f8cfa9440d70eca5a457ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:06 +0300 Subject: [PATCH 0287/7006] drm/i915: Use the memory latency based WM computation on VLV too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to get decnet memory self refresh residency on VLV, flip it over to the new CHV way of doing things. VLV doesn't do PM5 or DDR DVFS so it's a bit simpler. I'm not sure the currently memory latency used for CHV is really appropriate for VLV. Some further testing will probably be needed to figure that out. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 223 +-------------------------- drivers/gpu/drm/i915/intel_sprite.c | 6 - 3 files changed, 6 insertions(+), 225 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 7baa45db97563..649c5dba5463e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15455,7 +15455,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, pll->on = false; } - if (IS_CHERRYVIEW(dev)) + if (IS_VALLEYVIEW(dev)) vlv_wm_get_hw_state(dev); else if (IS_GEN9(dev)) skl_wm_get_hw_state(dev); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 49cca0b16cc66..0cccc44e1828e 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -931,77 +931,6 @@ static void vlv_write_wm_values(struct intel_crtc *crtc, #undef FW_WM_VLV -static uint8_t vlv_compute_drain_latency(struct drm_crtc *crtc, - struct drm_plane *plane) -{ - struct drm_device *dev = crtc->dev; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - int entries, prec_mult, drain_latency, pixel_size; - int clock = intel_crtc->config->base.adjusted_mode.crtc_clock; - const int high_precision = IS_CHERRYVIEW(dev) ? 16 : 64; - - /* - * FIXME the plane might have an fb - * but be invisible (eg. due to clipping) - */ - if (!intel_crtc->active || !plane->state->fb) - return 0; - - if (WARN(clock == 0, "Pixel clock is zero!\n")) - return 0; - - pixel_size = drm_format_plane_cpp(plane->state->fb->pixel_format, 0); - - if (WARN(pixel_size == 0, "Pixel size is zero!\n")) - return 0; - - entries = DIV_ROUND_UP(clock, 1000) * pixel_size; - - prec_mult = high_precision; - drain_latency = 64 * prec_mult * 4 / entries; - - if (drain_latency > DRAIN_LATENCY_MASK) { - prec_mult /= 2; - drain_latency = 64 * prec_mult * 4 / entries; - } - - if (drain_latency > DRAIN_LATENCY_MASK) - drain_latency = DRAIN_LATENCY_MASK; - - return drain_latency | (prec_mult == high_precision ? - DDL_PRECISION_HIGH : DDL_PRECISION_LOW); -} - -static int vlv_compute_wm(struct intel_crtc *crtc, - struct intel_plane *plane, - int fifo_size) -{ - int clock, entries, pixel_size; - - /* - * FIXME the plane might have an fb - * but be invisible (eg. due to clipping) - */ - if (!crtc->active || !plane->base.state->fb) - return 0; - - pixel_size = drm_format_plane_cpp(plane->base.state->fb->pixel_format, 0); - clock = crtc->config->base.adjusted_mode.crtc_clock; - - entries = DIV_ROUND_UP(clock, 1000) * pixel_size; - - /* - * Set up the watermark such that we don't start issuing memory - * requests until we are within PND's max deadline value (256us). - * Idea being to be idle as long as possible while still taking - * advatange of PND's deadline scheduling. The limit of 8 - * cachelines (used when the FIFO will anyway drain in less time - * than 256us) should match what we would be done if trickle - * feed were enabled. - */ - return fifo_size - clamp(DIV_ROUND_UP(256 * entries, 64), 0, fifo_size - 8); -} - enum vlv_wm_level { VLV_WM_LEVEL_PM2, VLV_WM_LEVEL_PM5, @@ -1076,101 +1005,6 @@ static uint16_t vlv_compute_wm_level(struct intel_plane *plane, return min_t(int, wm, USHRT_MAX); } -static bool vlv_compute_sr_wm(struct drm_device *dev, - struct vlv_wm_values *wm) -{ - struct drm_i915_private *dev_priv = to_i915(dev); - struct drm_crtc *crtc; - enum pipe pipe = INVALID_PIPE; - int num_planes = 0; - int fifo_size = 0; - struct intel_plane *plane; - - wm->sr.cursor = wm->sr.plane = 0; - - crtc = single_enabled_crtc(dev); - /* maxfifo not supported on pipe C */ - if (crtc && to_intel_crtc(crtc)->pipe != PIPE_C) { - pipe = to_intel_crtc(crtc)->pipe; - num_planes = !!wm->pipe[pipe].primary + - !!wm->pipe[pipe].sprite[0] + - !!wm->pipe[pipe].sprite[1]; - fifo_size = INTEL_INFO(dev_priv)->num_pipes * 512 - 1; - } - - if (fifo_size == 0 || num_planes > 1) - return false; - - wm->sr.cursor = vlv_compute_wm(to_intel_crtc(crtc), - to_intel_plane(crtc->cursor), 0x3f); - - list_for_each_entry(plane, &dev->mode_config.plane_list, base.head) { - if (plane->base.type == DRM_PLANE_TYPE_CURSOR) - continue; - - if (plane->pipe != pipe) - continue; - - wm->sr.plane = vlv_compute_wm(to_intel_crtc(crtc), - plane, fifo_size); - if (wm->sr.plane != 0) - break; - } - - return true; -} - -static void valleyview_update_wm(struct drm_crtc *crtc) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - bool cxsr_enabled; - struct vlv_wm_values wm = dev_priv->wm.vlv; - - wm.ddl[pipe].primary = vlv_compute_drain_latency(crtc, crtc->primary); - wm.pipe[pipe].primary = vlv_compute_wm(intel_crtc, - to_intel_plane(crtc->primary), - vlv_get_fifo_size(dev, pipe, 0)); - - wm.ddl[pipe].cursor = vlv_compute_drain_latency(crtc, crtc->cursor); - wm.pipe[pipe].cursor = vlv_compute_wm(intel_crtc, - to_intel_plane(crtc->cursor), - 0x3f); - - cxsr_enabled = vlv_compute_sr_wm(dev, &wm); - - if (memcmp(&wm, &dev_priv->wm.vlv, sizeof(wm)) == 0) - return; - - DRM_DEBUG_KMS("Setting FIFO watermarks - %c: plane=%d, cursor=%d, " - "SR: plane=%d, cursor=%d\n", pipe_name(pipe), - wm.pipe[pipe].primary, wm.pipe[pipe].cursor, - wm.sr.plane, wm.sr.cursor); - - /* - * FIXME DDR DVFS introduces massive memory latencies which - * are not known to system agent so any deadline specified - * by the display may not be respected. To support DDR DVFS - * the watermark code needs to be rewritten to essentially - * bypass deadline mechanism and rely solely on the - * watermarks. For now disable DDR DVFS. - */ - if (IS_CHERRYVIEW(dev_priv)) - chv_set_memory_dvfs(dev_priv, false); - - if (!cxsr_enabled) - intel_set_memory_cxsr(dev_priv, false); - - vlv_write_wm_values(intel_crtc, &wm); - - if (cxsr_enabled) - intel_set_memory_cxsr(dev_priv, true); - - dev_priv->wm.vlv = wm; -} - static void vlv_compute_fifo(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; @@ -1272,7 +1106,7 @@ static void vlv_invert_wms(struct intel_crtc *crtc) } } -static void _vlv_compute_wm(struct intel_crtc *crtc) +static void vlv_compute_wm(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct vlv_wm_state *wm_state = &crtc->wm_state; @@ -1518,7 +1352,7 @@ static void vlv_update_wm(struct drm_crtc *crtc) enum pipe pipe = intel_crtc->pipe; struct vlv_wm_values wm = {}; - _vlv_compute_wm(intel_crtc); + vlv_compute_wm(intel_crtc); vlv_merge_wm(dev, &wm); if (memcmp(&dev_priv->wm.vlv, &wm, sizeof(wm)) == 0) { @@ -1567,54 +1401,6 @@ static void vlv_update_wm(struct drm_crtc *crtc) dev_priv->wm.vlv = wm; } -static void valleyview_update_sprite_wm(struct drm_plane *plane, - struct drm_crtc *crtc, - uint32_t sprite_width, - uint32_t sprite_height, - int pixel_size, - bool enabled, bool scaled) -{ - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - enum pipe pipe = intel_crtc->pipe; - int sprite = to_intel_plane(plane)->plane; - bool cxsr_enabled; - struct vlv_wm_values wm = dev_priv->wm.vlv; - - if (enabled) { - wm.ddl[pipe].sprite[sprite] = - vlv_compute_drain_latency(crtc, plane); - - wm.pipe[pipe].sprite[sprite] = - vlv_compute_wm(intel_crtc, - to_intel_plane(plane), - vlv_get_fifo_size(dev, pipe, sprite+1)); - } else { - wm.ddl[pipe].sprite[sprite] = 0; - wm.pipe[pipe].sprite[sprite] = 0; - } - - cxsr_enabled = vlv_compute_sr_wm(dev, &wm); - - if (memcmp(&wm, &dev_priv->wm.vlv, sizeof(wm)) == 0) - return; - - DRM_DEBUG_KMS("Setting FIFO watermarks - %c: sprite %c=%d, " - "SR: plane=%d, cursor=%d\n", pipe_name(pipe), - sprite_name(pipe, sprite), - wm.pipe[pipe].sprite[sprite], - wm.sr.plane, wm.sr.cursor); - - if (!cxsr_enabled) - intel_set_memory_cxsr(dev_priv, false); - - vlv_write_wm_values(intel_crtc, &wm); - - if (cxsr_enabled) - intel_set_memory_cxsr(dev_priv, true); -} - #define single_plane_enabled(mask) is_power_of_2(mask) static void g4x_update_wm(struct drm_crtc *crtc) @@ -7297,8 +7083,9 @@ void intel_init_pm(struct drm_device *dev) dev_priv->display.init_clock_gating = cherryview_init_clock_gating; } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.update_wm = valleyview_update_wm; - dev_priv->display.update_sprite_wm = valleyview_update_sprite_wm; + vlv_setup_wm_latency(dev); + + dev_priv->display.update_wm = vlv_update_wm; dev_priv->display.init_clock_gating = valleyview_init_clock_gating; } else if (IS_PINEVIEW(dev)) { diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index 16be667cc5eb4..cd21525df3526 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -402,10 +402,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc, if (obj->tiling_mode != I915_TILING_NONE) sprctl |= SP_TILED; - intel_update_sprite_watermarks(dplane, crtc, src_w, src_h, - pixel_size, true, - src_w != crtc_w || src_h != crtc_h); - /* Sizes are 0 based */ src_w--; src_h--; @@ -470,8 +466,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc) I915_WRITE(SPSURF(pipe, plane), 0); POSTING_READ(SPSURF(pipe, plane)); - - intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false); } static void -- GitLab From 852eb00dc44ea2b8896e2fa27c6a36a1f697ba5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:07 +0300 Subject: [PATCH 0288/7006] drm/i915: Try to make sure cxsr is disabled around plane enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CxSR (or maxfifo on VLV/CHV) blocks somne changes to the plane control register (enable bit at least, not quite sure about the rest). So in order to have the plane enable/disable when we want we need to first kick the hardware out of cxsr. Unfortunateloy this requires some extra vblank waits. For the CxSR enable after the plane update we should eventually use an async vblank worker, but since we don't have that just do sync vblank waits. For the disable case we have no choice but to do it synchronously. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 36 ++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_drv.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 11 ++++----- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 649c5dba5463e..b7d42e6aac109 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4725,6 +4725,9 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_frontbuffer_flip(dev, atomic->fb_bits); + if (atomic->disable_cxsr) + crtc->wm.cxsr_allowed = true; + if (crtc->atomic.update_wm_post) intel_update_watermarks(&crtc->base); @@ -4777,6 +4780,11 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->pre_disable_primary) intel_pre_disable_primary(&crtc->base); + + if (atomic->disable_cxsr) { + crtc->wm.cxsr_allowed = false; + intel_set_memory_cxsr(dev_priv, false); + } } static void intel_crtc_disable_planes(struct drm_crtc *crtc, unsigned plane_mask) @@ -11611,12 +11619,26 @@ int intel_plane_atomic_calc_changes(struct drm_crtc_state *crtc_state, plane->base.id, was_visible, visible, turn_off, turn_on, mode_changed); - if (turn_on) + if (turn_on) { intel_crtc->atomic.update_wm_pre = true; - else if (turn_off) + /* must disable cxsr around plane enable/disable */ + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + intel_crtc->atomic.disable_cxsr = true; + /* to potentially re-enable cxsr */ + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.update_wm_post = true; + } + } else if (turn_off) { intel_crtc->atomic.update_wm_post = true; - else if (intel_wm_need_update(plane, plane_state)) + /* must disable cxsr around plane enable/disable */ + if (plane->type != DRM_PLANE_TYPE_CURSOR) { + if (is_crtc_enabled) + intel_crtc->atomic.wait_vblank = true; + intel_crtc->atomic.disable_cxsr = true; + } + } else if (intel_wm_need_update(plane, plane_state)) { intel_crtc->atomic.update_wm_pre = true; + } if (visible) intel_crtc->atomic.fb_bits |= @@ -11784,8 +11806,8 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) intel_crtc_check_initial_planes(crtc, crtc_state); - if (mode_changed) - intel_crtc->atomic.update_wm_post = !crtc_state->active; + if (mode_changed && !crtc_state->active) + intel_crtc->atomic.update_wm_post = true; if (mode_changed && crtc_state->enable && dev_priv->display.crtc_compute_clock && @@ -13105,6 +13127,8 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (!needs_modeset(crtc->state)) continue; + intel_pre_plane_update(intel_crtc); + any_ms = true; intel_pre_plane_update(intel_crtc); @@ -14065,6 +14089,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe) intel_crtc->cursor_cntl = ~0; intel_crtc->cursor_size = ~0; + intel_crtc->wm.cxsr_allowed = true; + BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) || dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL); dev_priv->plane_to_crtc_mapping[intel_crtc->plane] = &intel_crtc->base; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8397d1c9005bf..7f2e204b9fb5a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -508,6 +508,7 @@ struct intel_crtc_atomic_commit { bool wait_for_flips; bool disable_fbc; bool disable_ips; + bool disable_cxsr; bool pre_disable_primary; bool update_wm_pre, update_wm_post; unsigned disabled_planes; @@ -566,6 +567,8 @@ struct intel_crtc { struct intel_pipe_wm active; /* SKL wm values currently in use */ struct skl_pipe_wm skl_active; + /* allow CxSR on this pipe */ + bool cxsr_allowed; } wm; int scanline_offset; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0cccc44e1828e..a023b40c046b7 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -335,6 +335,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable) if (IS_VALLEYVIEW(dev)) { I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0); POSTING_READ(FW_BLC_SELF_VLV); + dev_priv->wm.vlv.cxsr = enable; } else if (IS_G4X(dev) || IS_CRESTLINE(dev)) { I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0); POSTING_READ(FW_BLC_SELF); @@ -1116,7 +1117,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc) memset(wm_state, 0, sizeof(*wm_state)); - wm_state->cxsr = crtc->pipe != PIPE_C; + wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed; if (IS_CHERRYVIEW(dev)) wm_state->num_levels = CHV_WM_NUM_LEVELS; else @@ -1369,10 +1370,8 @@ static void vlv_update_wm(struct drm_crtc *crtc) dev_priv->wm.vlv.level >= VLV_WM_LEVEL_PM5) chv_set_memory_pm5(dev_priv, false); - if (!wm.cxsr && dev_priv->wm.vlv.cxsr) { + if (!wm.cxsr && dev_priv->wm.vlv.cxsr) intel_set_memory_cxsr(dev_priv, false); - intel_wait_for_vblank(dev, pipe); - } /* FIXME should be part of crtc atomic commit */ vlv_pipe_set_fifo_size(intel_crtc); @@ -1385,10 +1384,8 @@ static void vlv_update_wm(struct drm_crtc *crtc) wm.pipe[pipe].sprite[0], wm.pipe[pipe].sprite[1], wm.sr.plane, wm.sr.cursor, wm.level, wm.cxsr); - if (wm.cxsr && !dev_priv->wm.vlv.cxsr) { - intel_wait_for_vblank(dev, pipe); + if (wm.cxsr && !dev_priv->wm.vlv.cxsr) intel_set_memory_cxsr(dev_priv, true); - } if (wm.level >= VLV_WM_LEVEL_PM5 && dev_priv->wm.vlv.level < VLV_WM_LEVEL_PM5) -- GitLab From 6f9c784b7ec2cc9fc9fd7c5a8634b70aadd76015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:08 +0300 Subject: [PATCH 0289/7006] drm/i915: Don't do PM5/DDR DVFS with multiple pipes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enabling PM5/DDR DVFS with multiple active pipes isn't a validated configuration. It does seem to work most of the time at least, but there is clearly an additional risk of underruns, so let's not play with fire. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index a023b40c046b7..16ca34fb5380d 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -1327,6 +1327,9 @@ static void vlv_merge_wm(struct drm_device *dev, if (num_active_crtcs != 1) wm->cxsr = false; + if (num_active_crtcs > 1) + wm->level = VLV_WM_LEVEL_PM2; + for_each_intel_crtc(dev, crtc) { struct vlv_wm_state *wm_state = &crtc->wm_state; enum pipe pipe = crtc->pipe; -- GitLab From de38b95cbb2a92ea037c22d41fc1476c0825c0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:09 +0300 Subject: [PATCH 0290/7006] drm/i915: Add debugfs knobs for VLVCHV memory latency values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow tweaking the VLV/CHV memory latencies thorugh sysfs, like we do for ILK+. Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 7d303e721a77a..68a5e868f90bd 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4203,8 +4203,15 @@ static const struct file_operations i915_displayport_test_type_fops = { static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) { struct drm_device *dev = m->private; - int num_levels = ilk_wm_max_level(dev) + 1; int level; + int num_levels; + + if (IS_CHERRYVIEW(dev)) + num_levels = 3; + else if (IS_VALLEYVIEW(dev)) + num_levels = 1; + else + num_levels = ilk_wm_max_level(dev) + 1; drm_modeset_lock_all(dev); @@ -4213,9 +4220,9 @@ static void wm_latency_show(struct seq_file *m, const uint16_t wm[8]) /* * - WM1+ latency values in 0.5us units - * - latencies are in us on gen9 + * - latencies are in us on gen9/vlv/chv */ - if (INTEL_INFO(dev)->gen >= 9) + if (INTEL_INFO(dev)->gen >= 9 || IS_VALLEYVIEW(dev)) latency *= 10; else if (level > 0) latency *= 5; @@ -4279,7 +4286,7 @@ static int pri_wm_latency_open(struct inode *inode, struct file *file) { struct drm_device *dev = inode->i_private; - if (HAS_GMCH_DISPLAY(dev)) + if (INTEL_INFO(dev)->gen < 5) return -ENODEV; return single_open(file, pri_wm_latency_show, dev); @@ -4311,11 +4318,18 @@ static ssize_t wm_latency_write(struct file *file, const char __user *ubuf, struct seq_file *m = file->private_data; struct drm_device *dev = m->private; uint16_t new[8] = { 0 }; - int num_levels = ilk_wm_max_level(dev) + 1; + int num_levels; int level; int ret; char tmp[32]; + if (IS_CHERRYVIEW(dev)) + num_levels = 3; + else if (IS_VALLEYVIEW(dev)) + num_levels = 1; + else + num_levels = ilk_wm_max_level(dev) + 1; + if (len >= sizeof(tmp)) return -EINVAL; -- GitLab From 2cb389b7e4966151d44c505d49ea31a8d6969372 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 24 Jun 2015 22:00:10 +0300 Subject: [PATCH 0291/7006] drm/i915: Zero unused WM1 watermarks on VLV/CHV MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hardware supposedly ignores the WM1 watermarks while the PND deadline mode is enabled, but clear out the register just in case. This is what the other OS does, and it does make register dumps look more consistent when we don't have partial WM1 values lingering in the registers (some WM1 watermarks already get zeroed when the actually used DSPFW registers get written). Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 16ca34fb5380d..6eb5d76e69120 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -927,6 +927,12 @@ static void vlv_write_wm_values(struct intel_crtc *crtc, FW_WM(wm->pipe[PIPE_A].primary >> 8, PLANEA_HI)); } + /* zero (unused) WM1 watermarks */ + I915_WRITE(DSPFW4, 0); + I915_WRITE(DSPFW5, 0); + I915_WRITE(DSPFW6, 0); + I915_WRITE(DSPHOWM1, 0); + POSTING_READ(DSPFW1); } -- GitLab From 4b8a8262086ece4b7eb34bd2e40cce3b3c9c7079 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 19 Nov 2014 18:30:22 +0100 Subject: [PATCH 0292/7006] HID: picoLCD: Deletion of unnecessary checks before three function calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The functions backlight_device_unregister(), lcd_device_unregister() and rc_unregister_device() test whether their argument is NULL and then return immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd_backlight.c | 3 +-- drivers/hid/hid-picolcd_cir.c | 3 +-- drivers/hid/hid-picolcd_lcd.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-picolcd_backlight.c b/drivers/hid/hid-picolcd_backlight.c index a32c5f86b0b3f..808807ad388f9 100644 --- a/drivers/hid/hid-picolcd_backlight.c +++ b/drivers/hid/hid-picolcd_backlight.c @@ -94,8 +94,7 @@ void picolcd_exit_backlight(struct picolcd_data *data) struct backlight_device *bdev = data->backlight; data->backlight = NULL; - if (bdev) - backlight_device_unregister(bdev); + backlight_device_unregister(bdev); } int picolcd_resume_backlight(struct picolcd_data *data) diff --git a/drivers/hid/hid-picolcd_cir.c b/drivers/hid/hid-picolcd_cir.c index 045f8ebf16b53..96286510f42e9 100644 --- a/drivers/hid/hid-picolcd_cir.c +++ b/drivers/hid/hid-picolcd_cir.c @@ -145,7 +145,6 @@ void picolcd_exit_cir(struct picolcd_data *data) struct rc_dev *rdev = data->rc_dev; data->rc_dev = NULL; - if (rdev) - rc_unregister_device(rdev); + rc_unregister_device(rdev); } diff --git a/drivers/hid/hid-picolcd_lcd.c b/drivers/hid/hid-picolcd_lcd.c index 89821c2da6d76..22dcbe13da892 100644 --- a/drivers/hid/hid-picolcd_lcd.c +++ b/drivers/hid/hid-picolcd_lcd.c @@ -92,8 +92,7 @@ void picolcd_exit_lcd(struct picolcd_data *data) struct lcd_device *ldev = data->lcd; data->lcd = NULL; - if (ldev) - lcd_device_unregister(ldev); + lcd_device_unregister(ldev); } int picolcd_resume_lcd(struct picolcd_data *data) -- GitLab From f8896f5d58e64bfd3c2b5f7c5ba5c3f3967e93c7 Mon Sep 17 00:00:00 2001 From: David Weinehall Date: Thu, 25 Jun 2015 11:11:03 +0300 Subject: [PATCH 0293/7006] drm/i915/skl: Buffer translation improvements MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for 0.85V VccIO on Skylake Y, separate buffer translation tables for Skylake U, and support for I_boost for the entries that needs this. Changes in v2: * Refactored the code a bit to move all DDI signal level setup to intel_ddi.c Issue: VIZ-5677 Signed-off-by: David Weinehall Reviewed-by: Antti Koskipää [danvet: Apply style polish checkpatch suggested.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 + drivers/gpu/drm/i915/i915_reg.h | 12 + drivers/gpu/drm/i915/intel_ddi.c | 509 ++++++++++++++++++++++++------- drivers/gpu/drm/i915/intel_dp.c | 104 +------ drivers/gpu/drm/i915/intel_drv.h | 3 +- 5 files changed, 423 insertions(+), 213 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6acc6504863b6..64041e788a1c7 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2436,6 +2436,14 @@ struct drm_i915_cmd_table { /* ULX machines are also considered ULT. */ #define IS_HSW_ULX(dev) (INTEL_DEVID(dev) == 0x0A0E || \ INTEL_DEVID(dev) == 0x0A1E) +#define IS_SKL_ULT(dev) (INTEL_DEVID(dev) == 0x1906 || \ + INTEL_DEVID(dev) == 0x1913 || \ + INTEL_DEVID(dev) == 0x1916 || \ + INTEL_DEVID(dev) == 0x1921 || \ + INTEL_DEVID(dev) == 0x1926) +#define IS_SKL_ULX(dev) (INTEL_DEVID(dev) == 0x190E || \ + INTEL_DEVID(dev) == 0x1915 || \ + INTEL_DEVID(dev) == 0x191E) #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary) #define SKL_REVID_A0 (0x0) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 50e6279d7d562..bdef9f7b629e0 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1384,6 +1384,18 @@ enum skl_disp_power_wells { _PORT_TX_DW14_LN0_C) + \ _BXT_LANE_OFFSET(lane)) +/* UAIMI scratch pad register 1 */ +#define UAIMI_SPR1 0x4F074 +/* SKL VccIO mask */ +#define SKL_VCCIO_MASK 0x1 +/* SKL balance leg register */ +#define DISPIO_CR_TX_BMU_CR0 0x6C00C +/* I_boost values */ +#define BALANCE_LEG_SHIFT(port) (8+3*(port)) +#define BALANCE_LEG_MASK(port) (7<<(8+3*(port))) +/* Balance leg disable bits */ +#define BALANCE_LEG_DISABLE_SHIFT 23 + /* * Fence registers */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 42c14870ef439..b29d103bd706a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -31,6 +31,7 @@ struct ddi_buf_trans { u32 trans1; /* balance leg enable, de-emph level */ u32 trans2; /* vref sel, vswing */ + u8 i_boost; /* SKL: I_boost; valid: 0x0, 0x1, 0x3, 0x7 */ }; /* HDMI/DVI modes ignore everything but the last 2 items. So we share @@ -38,134 +39,213 @@ struct ddi_buf_trans { * automatically adapt to HDMI connections as well */ static const struct ddi_buf_trans hsw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0006000E }, - { 0x00D75FFF, 0x0005000A }, - { 0x00C30FFF, 0x00040006 }, - { 0x80AAAFFF, 0x000B0000 }, - { 0x00FFFFFF, 0x0005000A }, - { 0x00D75FFF, 0x000C0004 }, - { 0x80C30FFF, 0x000B0000 }, - { 0x00FFFFFF, 0x00040006 }, - { 0x80D75FFF, 0x000B0000 }, + { 0x00FFFFFF, 0x0006000E, 0x0 }, + { 0x00D75FFF, 0x0005000A, 0x0 }, + { 0x00C30FFF, 0x00040006, 0x0 }, + { 0x80AAAFFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x0005000A, 0x0 }, + { 0x00D75FFF, 0x000C0004, 0x0 }, + { 0x80C30FFF, 0x000B0000, 0x0 }, + { 0x00FFFFFF, 0x00040006, 0x0 }, + { 0x80D75FFF, 0x000B0000, 0x0 }, }; static const struct ddi_buf_trans hsw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0007000E }, - { 0x00D75FFF, 0x000F000A }, - { 0x00C30FFF, 0x00060006 }, - { 0x00AAAFFF, 0x001E0000 }, - { 0x00FFFFFF, 0x000F000A }, - { 0x00D75FFF, 0x00160004 }, - { 0x00C30FFF, 0x001E0000 }, - { 0x00FFFFFF, 0x00060006 }, - { 0x00D75FFF, 0x001E0000 }, + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000F000A, 0x0 }, + { 0x00C30FFF, 0x00060006, 0x0 }, + { 0x00AAAFFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x000F000A, 0x0 }, + { 0x00D75FFF, 0x00160004, 0x0 }, + { 0x00C30FFF, 0x001E0000, 0x0 }, + { 0x00FFFFFF, 0x00060006, 0x0 }, + { 0x00D75FFF, 0x001E0000, 0x0 }, }; static const struct ddi_buf_trans hsw_ddi_translations_hdmi[] = { /* Idx NT mV d T mV d db */ - { 0x00FFFFFF, 0x0006000E }, /* 0: 400 400 0 */ - { 0x00E79FFF, 0x000E000C }, /* 1: 400 500 2 */ - { 0x00D75FFF, 0x0005000A }, /* 2: 400 600 3.5 */ - { 0x00FFFFFF, 0x0005000A }, /* 3: 600 600 0 */ - { 0x00E79FFF, 0x001D0007 }, /* 4: 600 750 2 */ - { 0x00D75FFF, 0x000C0004 }, /* 5: 600 900 3.5 */ - { 0x00FFFFFF, 0x00040006 }, /* 6: 800 800 0 */ - { 0x80E79FFF, 0x00030002 }, /* 7: 800 1000 2 */ - { 0x00FFFFFF, 0x00140005 }, /* 8: 850 850 0 */ - { 0x00FFFFFF, 0x000C0004 }, /* 9: 900 900 0 */ - { 0x00FFFFFF, 0x001C0003 }, /* 10: 950 950 0 */ - { 0x80FFFFFF, 0x00030002 }, /* 11: 1000 1000 0 */ + { 0x00FFFFFF, 0x0006000E, 0x0 },/* 0: 400 400 0 */ + { 0x00E79FFF, 0x000E000C, 0x0 },/* 1: 400 500 2 */ + { 0x00D75FFF, 0x0005000A, 0x0 },/* 2: 400 600 3.5 */ + { 0x00FFFFFF, 0x0005000A, 0x0 },/* 3: 600 600 0 */ + { 0x00E79FFF, 0x001D0007, 0x0 },/* 4: 600 750 2 */ + { 0x00D75FFF, 0x000C0004, 0x0 },/* 5: 600 900 3.5 */ + { 0x00FFFFFF, 0x00040006, 0x0 },/* 6: 800 800 0 */ + { 0x80E79FFF, 0x00030002, 0x0 },/* 7: 800 1000 2 */ + { 0x00FFFFFF, 0x00140005, 0x0 },/* 8: 850 850 0 */ + { 0x00FFFFFF, 0x000C0004, 0x0 },/* 9: 900 900 0 */ + { 0x00FFFFFF, 0x001C0003, 0x0 },/* 10: 950 950 0 */ + { 0x80FFFFFF, 0x00030002, 0x0 },/* 11: 1000 1000 0 */ }; static const struct ddi_buf_trans bdw_ddi_translations_edp[] = { - { 0x00FFFFFF, 0x00000012 }, - { 0x00EBAFFF, 0x00020011 }, - { 0x00C71FFF, 0x0006000F }, - { 0x00AAAFFF, 0x000E000A }, - { 0x00FFFFFF, 0x00020011 }, - { 0x00DB6FFF, 0x0005000F }, - { 0x00BEEFFF, 0x000A000C }, - { 0x00FFFFFF, 0x0005000F }, - { 0x00DB6FFF, 0x000A000C }, + { 0x00FFFFFF, 0x00000012, 0x0 }, + { 0x00EBAFFF, 0x00020011, 0x0 }, + { 0x00C71FFF, 0x0006000F, 0x0 }, + { 0x00AAAFFF, 0x000E000A, 0x0 }, + { 0x00FFFFFF, 0x00020011, 0x0 }, + { 0x00DB6FFF, 0x0005000F, 0x0 }, + { 0x00BEEFFF, 0x000A000C, 0x0 }, + { 0x00FFFFFF, 0x0005000F, 0x0 }, + { 0x00DB6FFF, 0x000A000C, 0x0 }, }; static const struct ddi_buf_trans bdw_ddi_translations_dp[] = { - { 0x00FFFFFF, 0x0007000E }, - { 0x00D75FFF, 0x000E000A }, - { 0x00BEFFFF, 0x00140006 }, - { 0x80B2CFFF, 0x001B0002 }, - { 0x00FFFFFF, 0x000E000A }, - { 0x00DB6FFF, 0x00160005 }, - { 0x80C71FFF, 0x001A0002 }, - { 0x00F7DFFF, 0x00180004 }, - { 0x80D75FFF, 0x001B0002 }, + { 0x00FFFFFF, 0x0007000E, 0x0 }, + { 0x00D75FFF, 0x000E000A, 0x0 }, + { 0x00BEFFFF, 0x00140006, 0x0 }, + { 0x80B2CFFF, 0x001B0002, 0x0 }, + { 0x00FFFFFF, 0x000E000A, 0x0 }, + { 0x00DB6FFF, 0x00160005, 0x0 }, + { 0x80C71FFF, 0x001A0002, 0x0 }, + { 0x00F7DFFF, 0x00180004, 0x0 }, + { 0x80D75FFF, 0x001B0002, 0x0 }, }; static const struct ddi_buf_trans bdw_ddi_translations_fdi[] = { - { 0x00FFFFFF, 0x0001000E }, - { 0x00D75FFF, 0x0004000A }, - { 0x00C30FFF, 0x00070006 }, - { 0x00AAAFFF, 0x000C0000 }, - { 0x00FFFFFF, 0x0004000A }, - { 0x00D75FFF, 0x00090004 }, - { 0x00C30FFF, 0x000C0000 }, - { 0x00FFFFFF, 0x00070006 }, - { 0x00D75FFF, 0x000C0000 }, + { 0x00FFFFFF, 0x0001000E, 0x0 }, + { 0x00D75FFF, 0x0004000A, 0x0 }, + { 0x00C30FFF, 0x00070006, 0x0 }, + { 0x00AAAFFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x0004000A, 0x0 }, + { 0x00D75FFF, 0x00090004, 0x0 }, + { 0x00C30FFF, 0x000C0000, 0x0 }, + { 0x00FFFFFF, 0x00070006, 0x0 }, + { 0x00D75FFF, 0x000C0000, 0x0 }, }; static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { /* Idx NT mV d T mV df db */ - { 0x00FFFFFF, 0x0007000E }, /* 0: 400 400 0 */ - { 0x00D75FFF, 0x000E000A }, /* 1: 400 600 3.5 */ - { 0x00BEFFFF, 0x00140006 }, /* 2: 400 800 6 */ - { 0x00FFFFFF, 0x0009000D }, /* 3: 450 450 0 */ - { 0x00FFFFFF, 0x000E000A }, /* 4: 600 600 0 */ - { 0x00D7FFFF, 0x00140006 }, /* 5: 600 800 2.5 */ - { 0x80CB2FFF, 0x001B0002 }, /* 6: 600 1000 4.5 */ - { 0x00FFFFFF, 0x00140006 }, /* 7: 800 800 0 */ - { 0x80E79FFF, 0x001B0002 }, /* 8: 800 1000 2 */ - { 0x80FFFFFF, 0x001B0002 }, /* 9: 1000 1000 0 */ + { 0x00FFFFFF, 0x0007000E, 0x0 },/* 0: 400 400 0 */ + { 0x00D75FFF, 0x000E000A, 0x0 },/* 1: 400 600 3.5 */ + { 0x00BEFFFF, 0x00140006, 0x0 },/* 2: 400 800 6 */ + { 0x00FFFFFF, 0x0009000D, 0x0 },/* 3: 450 450 0 */ + { 0x00FFFFFF, 0x000E000A, 0x0 },/* 4: 600 600 0 */ + { 0x00D7FFFF, 0x00140006, 0x0 },/* 5: 600 800 2.5 */ + { 0x80CB2FFF, 0x001B0002, 0x0 },/* 6: 600 1000 4.5 */ + { 0x00FFFFFF, 0x00140006, 0x0 },/* 7: 800 800 0 */ + { 0x80E79FFF, 0x001B0002, 0x0 },/* 8: 800 1000 2 */ + { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ }; +/* Skylake H, S, and Skylake Y with 0.95V VccIO */ static const struct ddi_buf_trans skl_ddi_translations_dp[] = { - { 0x00000018, 0x000000a2 }, - { 0x00004014, 0x0000009B }, - { 0x00006012, 0x00000088 }, - { 0x00008010, 0x00000087 }, - { 0x00000018, 0x0000009B }, - { 0x00004014, 0x00000088 }, - { 0x00006012, 0x00000087 }, - { 0x00000018, 0x00000088 }, - { 0x00004014, 0x00000087 }, + { 0x00002016, 0x000000A0, 0x0 }, + { 0x00005012, 0x0000009B, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x00009010, 0x000000C7, 0x0 }, + { 0x00002016, 0x0000009B, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x00007011, 0x000000C7, 0x0 }, + { 0x00002016, 0x000000DF, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, }; -/* eDP 1.4 low vswing translation parameters */ +/* Skylake U */ +static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { + { 0x00002016, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x00007011, 0x00000087, 0x0 }, + { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost */ + { 0x00002016, 0x0000009D, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, + { 0x00007011, 0x000000C7, 0x0 }, + { 0x00002016, 0x00000088, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, +}; + +/* Skylake Y with 0.85V VccIO */ +static const struct ddi_buf_trans skl_y_085v_ddi_translations_dp[] = { + { 0x00000018, 0x000000A2, 0x0 }, + { 0x00005012, 0x00000088, 0x0 }, + { 0x00007011, 0x00000087, 0x0 }, + { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost */ + { 0x00000018, 0x0000009D, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, + { 0x00007011, 0x000000C7, 0x0 }, + { 0x00000018, 0x00000088, 0x0 }, + { 0x00005012, 0x000000C7, 0x0 }, +}; + +/* + * Skylake H and S, and Skylake Y with 0.95V VccIO + * eDP 1.4 low vswing translation parameters + */ static const struct ddi_buf_trans skl_ddi_translations_edp[] = { - { 0x00000018, 0x000000a8 }, - { 0x00002016, 0x000000ab }, - { 0x00006012, 0x000000a2 }, - { 0x00008010, 0x00000088 }, - { 0x00000018, 0x000000ab }, - { 0x00004014, 0x000000a2 }, - { 0x00006012, 0x000000a6 }, - { 0x00000018, 0x000000a2 }, - { 0x00005013, 0x0000009c }, - { 0x00000018, 0x00000088 }, + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00000018, 0x000000AB, 0x0 }, + { 0x00007013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, }; +/* + * Skylake U + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000A9, 0x0 }, + { 0x00007011, 0x000000A2, 0x0 }, + { 0x00009010, 0x0000009C, 0x0 }, + { 0x00000018, 0x000000A9, 0x0 }, + { 0x00006013, 0x000000A2, 0x0 }, + { 0x00007011, 0x000000A6, 0x0 }, + { 0x00002016, 0x000000AB, 0x0 }, + { 0x00005013, 0x0000009F, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, +}; +/* + * Skylake Y with 0.95V VccIO + * eDP 1.4 low vswing translation parameters + */ +static const struct ddi_buf_trans skl_y_085v_ddi_translations_edp[] = { + { 0x00000018, 0x000000A8, 0x0 }, + { 0x00004013, 0x000000AB, 0x0 }, + { 0x00007011, 0x000000A4, 0x0 }, + { 0x00009010, 0x000000DF, 0x0 }, + { 0x00000018, 0x000000AA, 0x0 }, + { 0x00006013, 0x000000A4, 0x0 }, + { 0x00007011, 0x0000009D, 0x0 }, + { 0x00000018, 0x000000A0, 0x0 }, + { 0x00006012, 0x000000DF, 0x0 }, + { 0x00000018, 0x0000008A, 0x0 }, +}; + +/* Skylake H, S and U, and Skylake Y with 0.95V VccIO */ static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { - { 0x00000018, 0x000000ac }, - { 0x00005012, 0x0000009d }, - { 0x00007011, 0x00000088 }, - { 0x00000018, 0x000000a1 }, - { 0x00000018, 0x00000098 }, - { 0x00004013, 0x00000088 }, - { 0x00006012, 0x00000087 }, - { 0x00000018, 0x000000df }, - { 0x00003015, 0x00000087 }, - { 0x00003015, 0x000000c7 }, - { 0x00000018, 0x000000c7 }, + { 0x00000018, 0x000000AC, 0x0 }, + { 0x00005012, 0x0000009D, 0x0 }, + { 0x00007011, 0x00000088, 0x0 }, + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00000018, 0x00000098, 0x0 }, + { 0x00004013, 0x00000088, 0x0 }, + { 0x00006012, 0x00000087, 0x0 }, + { 0x00000018, 0x000000DF, 0x0 }, + { 0x00003015, 0x00000087, 0x0 }, /* Default */ + { 0x00003015, 0x000000C7, 0x0 }, + { 0x00000018, 0x000000C7, 0x0 }, +}; + +/* Skylake Y with 0.85V VccIO */ +static const struct ddi_buf_trans skl_y_085v_ddi_translations_hdmi[] = { + { 0x00000018, 0x000000A1, 0x0 }, + { 0x00005012, 0x000000DF, 0x0 }, + { 0x00007011, 0x00000084, 0x0 }, + { 0x00000018, 0x000000A4, 0x0 }, + { 0x00000018, 0x0000009D, 0x0 }, + { 0x00004013, 0x00000080, 0x0 }, + { 0x00006013, 0x000000C7, 0x0 }, + { 0x00000018, 0x0000008A, 0x0 }, + { 0x00003015, 0x000000C7, 0x0 }, /* Default */ + { 0x80003015, 0x000000C7, 0x7 }, /* Uses I_boost */ + { 0x00000018, 0x000000C7, 0x0 }, }; struct bxt_ddi_buf_trans { @@ -190,7 +270,7 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_dp[] = { { 154, 0x9A, 0, 64, false }, /* 6: 600 6 */ { 102, 0x9A, 0, 128, false }, /* 7: 800 0 */ { 154, 0x9A, 0, 85, false }, /* 8: 800 3.5 */ - { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ + { 154, 0x9A, 1, 128, false }, /* 9: 1200 0 */ }; /* BSpec has 2 recommended values - entries 0 and 8. @@ -210,6 +290,9 @@ static const struct bxt_ddi_buf_trans bxt_ddi_translations_hdmi[] = { { 154, 0x9A, 1, 128, true }, /* 9: 1200 0 */ }; +static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, + enum port port, int type); + static void ddi_get_encoder_port(struct intel_encoder *intel_encoder, struct intel_digital_port **dig_port, enum port *port) @@ -249,6 +332,102 @@ intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port) return intel_dig_port->hdmi.hdmi_reg; } +static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev, + int *n_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + static int is_095v = -1; + + if (is_095v == -1) { + u32 spr1 = I915_READ(UAIMI_SPR1); + + is_095v = spr1 & SKL_VCCIO_MASK; + } + + if (IS_SKL_ULX(dev) && !is_095v) { + ddi_translations = skl_y_085v_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_dp); + } else if (IS_SKL_ULT(dev)) { + ddi_translations = skl_u_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); + } else { + ddi_translations = skl_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); + } + + return ddi_translations; +} + +static const struct ddi_buf_trans *skl_get_buf_trans_edp(struct drm_device *dev, + int *n_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + static int is_095v = -1; + + if (is_095v == -1) { + u32 spr1 = I915_READ(UAIMI_SPR1); + + is_095v = spr1 & SKL_VCCIO_MASK; + } + + if (IS_SKL_ULX(dev) && !is_095v) { + if (dev_priv->edp_low_vswing) { + ddi_translations = skl_y_085v_ddi_translations_edp; + *n_entries = + ARRAY_SIZE(skl_y_085v_ddi_translations_edp); + } else { + ddi_translations = skl_y_085v_ddi_translations_dp; + *n_entries = + ARRAY_SIZE(skl_y_085v_ddi_translations_dp); + } + } else if (IS_SKL_ULT(dev)) { + if (dev_priv->edp_low_vswing) { + ddi_translations = skl_u_ddi_translations_edp; + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_edp); + } else { + ddi_translations = skl_u_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); + } + } else { + if (dev_priv->edp_low_vswing) { + ddi_translations = skl_ddi_translations_edp; + *n_entries = ARRAY_SIZE(skl_ddi_translations_edp); + } else { + ddi_translations = skl_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_ddi_translations_dp); + } + } + + return ddi_translations; +} + +static const struct ddi_buf_trans * +skl_get_buf_trans_hdmi(struct drm_device *dev, + int *n_entries) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + static int is_095v = -1; + + if (is_095v == -1) { + u32 spr1 = I915_READ(UAIMI_SPR1); + + is_095v = spr1 & SKL_VCCIO_MASK; + } + + if (IS_SKL_ULX(dev) && !is_095v) { + ddi_translations = skl_y_085v_ddi_translations_hdmi; + *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_hdmi); + } else { + ddi_translations = skl_ddi_translations_hdmi; + *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); + } + + return ddi_translations; +} + /* * Starting with Haswell, DDI port buffers must be programmed with correct * values in advance. The buffer values are different for FDI and DP modes, @@ -279,20 +458,13 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, INTEL_OUTPUT_HDMI); return; } else if (IS_SKYLAKE(dev)) { - ddi_translations_fdi = NULL; - ddi_translations_dp = skl_ddi_translations_dp; - n_dp_entries = ARRAY_SIZE(skl_ddi_translations_dp); - if (dev_priv->edp_low_vswing) { - ddi_translations_edp = skl_ddi_translations_edp; - n_edp_entries = ARRAY_SIZE(skl_ddi_translations_edp); - } else { - ddi_translations_edp = skl_ddi_translations_dp; - n_edp_entries = ARRAY_SIZE(skl_ddi_translations_dp); - } - - ddi_translations_hdmi = skl_ddi_translations_hdmi; - n_hdmi_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); - hdmi_default_entry = 7; + ddi_translations_dp = + skl_get_buf_trans_dp(dev, &n_dp_entries); + ddi_translations_edp = + skl_get_buf_trans_edp(dev, &n_edp_entries); + ddi_translations_hdmi = + skl_get_buf_trans_hdmi(dev, &n_hdmi_entries); + hdmi_default_entry = 8; } else if (IS_BROADWELL(dev)) { ddi_translations_fdi = bdw_ddi_translations_fdi; ddi_translations_dp = bdw_ddi_translations_dp; @@ -1883,8 +2055,48 @@ void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc) TRANS_CLK_SEL_DISABLED); } -void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, - enum port port, int type) +static void skl_ddi_set_iboost(struct drm_device *dev, u32 level, + enum port port, int type) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + const struct ddi_buf_trans *ddi_translations; + uint8_t iboost; + int n_entries; + u32 reg; + + if (type == INTEL_OUTPUT_DISPLAYPORT) { + ddi_translations = skl_get_buf_trans_dp(dev, &n_entries); + iboost = ddi_translations[port].i_boost; + } else if (type == INTEL_OUTPUT_EDP) { + ddi_translations = skl_get_buf_trans_edp(dev, &n_entries); + iboost = ddi_translations[port].i_boost; + } else if (type == INTEL_OUTPUT_HDMI) { + ddi_translations = skl_get_buf_trans_hdmi(dev, &n_entries); + iboost = ddi_translations[port].i_boost; + } else { + return; + } + + /* Make sure that the requested I_boost is valid */ + if (iboost && iboost != 0x1 && iboost != 0x3 && iboost != 0x7) { + DRM_ERROR("Invalid I_boost value %u\n", iboost); + return; + } + + reg = I915_READ(DISPIO_CR_TX_BMU_CR0); + reg &= ~BALANCE_LEG_MASK(port); + reg &= ~(1 << (BALANCE_LEG_DISABLE_SHIFT + port)); + + if (iboost) + reg |= iboost << BALANCE_LEG_SHIFT(port); + else + reg |= 1 << (BALANCE_LEG_DISABLE_SHIFT + port); + + I915_WRITE(DISPIO_CR_TX_BMU_CR0, reg); +} + +static void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, + enum port port, int type) { struct drm_i915_private *dev_priv = dev->dev_private; const struct bxt_ddi_buf_trans *ddi_translations; @@ -1944,6 +2156,73 @@ void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, I915_WRITE(BXT_PORT_PCS_DW10_GRP(port), val); } +static uint32_t translate_signal_level(int signal_levels) +{ + uint32_t level; + + switch (signal_levels) { + default: + DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level: 0x%x\n", + signal_levels); + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 0; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1: + level = 1; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2: + level = 2; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3: + level = 3; + break; + + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 4; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1: + level = 5; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2: + level = 6; + break; + + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 7; + break; + case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1: + level = 8; + break; + + case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0: + level = 9; + break; + } + + return level; +} + +uint32_t ddi_signal_levels(struct intel_dp *intel_dp) +{ + struct intel_digital_port *dport = dp_to_dig_port(intel_dp); + struct drm_device *dev = dport->base.base.dev; + struct intel_encoder *encoder = &dport->base; + uint8_t train_set = intel_dp->train_set[0]; + int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | + DP_TRAIN_PRE_EMPHASIS_MASK); + enum port port = dport->port; + uint32_t level; + + level = translate_signal_level(signal_levels); + + if (IS_SKYLAKE(dev)) + skl_ddi_set_iboost(dev, level, port, encoder->type); + else if (IS_BROXTON(dev)) + bxt_ddi_vswing_sequence(dev, level, port, encoder->type); + + return DDI_BUF_TRANS_SELECT(level); +} + static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder) { struct drm_encoder *encoder = &intel_encoder->base; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c43bff90c47a2..367f71224c96a 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -3424,92 +3424,6 @@ gen7_edp_signal_levels(uint8_t train_set) } } -/* Gen7.5's (HSW) DP voltage swing and pre-emphasis control */ -static uint32_t -hsw_signal_levels(uint8_t train_set) -{ - int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | - DP_TRAIN_PRE_EMPHASIS_MASK); - switch (signal_levels) { - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(0); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1: - return DDI_BUF_TRANS_SELECT(1); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2: - return DDI_BUF_TRANS_SELECT(2); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3: - return DDI_BUF_TRANS_SELECT(3); - - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(4); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1: - return DDI_BUF_TRANS_SELECT(5); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2: - return DDI_BUF_TRANS_SELECT(6); - - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(7); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1: - return DDI_BUF_TRANS_SELECT(8); - - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0: - return DDI_BUF_TRANS_SELECT(9); - default: - DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:" - "0x%x\n", signal_levels); - return DDI_BUF_TRANS_SELECT(0); - } -} - -static void bxt_signal_levels(struct intel_dp *intel_dp) -{ - struct intel_digital_port *dport = dp_to_dig_port(intel_dp); - enum port port = dport->port; - struct drm_device *dev = dport->base.base.dev; - struct intel_encoder *encoder = &dport->base; - uint8_t train_set = intel_dp->train_set[0]; - uint32_t level = 0; - - int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK | - DP_TRAIN_PRE_EMPHASIS_MASK); - switch (signal_levels) { - default: - DRM_DEBUG_KMS("Unsupported voltage swing/pre-emph level\n"); - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 0; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_1: - level = 1; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_2: - level = 2; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_0 | DP_TRAIN_PRE_EMPH_LEVEL_3: - level = 3; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 4; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_1: - level = 5; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_1 | DP_TRAIN_PRE_EMPH_LEVEL_2: - level = 6; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 7; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_2 | DP_TRAIN_PRE_EMPH_LEVEL_1: - level = 8; - break; - case DP_TRAIN_VOLTAGE_SWING_LEVEL_3 | DP_TRAIN_PRE_EMPH_LEVEL_0: - level = 9; - break; - } - - bxt_ddi_vswing_sequence(dev, level, port, encoder->type); -} - /* Properly updates "DP" with the correct signal levels. */ static void intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) @@ -3517,22 +3431,20 @@ intel_dp_set_signal_levels(struct intel_dp *intel_dp, uint32_t *DP) struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); enum port port = intel_dig_port->port; struct drm_device *dev = intel_dig_port->base.base.dev; - uint32_t signal_levels, mask; + uint32_t signal_levels, mask = 0; uint8_t train_set = intel_dp->train_set[0]; - if (IS_BROXTON(dev)) { - signal_levels = 0; - bxt_signal_levels(intel_dp); - mask = 0; - } else if (HAS_DDI(dev)) { - signal_levels = hsw_signal_levels(train_set); - mask = DDI_BUF_EMP_MASK; + if (HAS_DDI(dev)) { + signal_levels = ddi_signal_levels(intel_dp); + + if (IS_BROXTON(dev)) + signal_levels = 0; + else + mask = DDI_BUF_EMP_MASK; } else if (IS_CHERRYVIEW(dev)) { signal_levels = chv_signal_levels(intel_dp); - mask = 0; } else if (IS_VALLEYVIEW(dev)) { signal_levels = vlv_signal_levels(intel_dp); - mask = 0; } else if (IS_GEN7(dev) && port == PORT_A) { signal_levels = gen7_edp_signal_levels(train_set); mask = EDP_LINK_TRAIN_VOL_EMP_MASK_IVB; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7f2e204b9fb5a..bb52620a3ce81 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -968,8 +968,7 @@ void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder); void intel_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config); void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state); -void bxt_ddi_vswing_sequence(struct drm_device *dev, u32 level, - enum port port, int type); +uint32_t ddi_signal_levels(struct intel_dp *intel_dp); /* intel_frontbuffer.c */ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, -- GitLab From 05712c1561041d102d3cac7d7e79548b1446caa4 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 18 Jun 2015 17:25:54 +0300 Subject: [PATCH 0294/7006] drm/i915/bxt: add missing DDI PLL registers to the state checking Although we have a fixed setting for the PLL9 and EBB4 registers, it still makes sense to check them together with the rest of PLL registers. While at it also remove a redundant comment about 10 bit clock enabling. Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 3 ++- drivers/gpu/drm/i915/i915_reg.h | 3 ++- drivers/gpu/drm/i915/intel_ddi.c | 16 +++++++++++++--- drivers/gpu/drm/i915/intel_display.c | 6 ++++-- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 64041e788a1c7..1dbd95710bf4f 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -372,7 +372,8 @@ struct intel_dpll_hw_state { uint32_t cfgcr1, cfgcr2; /* bxt */ - uint32_t ebb0, pll0, pll1, pll2, pll3, pll6, pll8, pll10, pcsdw12; + uint32_t ebb0, ebb4, pll0, pll1, pll2, pll3, pll6, pll8, pll9, pll10, + pcsdw12; }; struct intel_shared_dpll_config { diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index bdef9f7b629e0..4d8ef2de4374c 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1208,7 +1208,8 @@ enum skl_disp_power_wells { /* PORT_PLL_8_A */ #define PORT_PLL_TARGET_CNT_MASK 0x3FF /* PORT_PLL_9_A */ -#define PORT_PLL_LOCK_THRESHOLD_MASK 0xe +#define PORT_PLL_LOCK_THRESHOLD_SHIFT 1 +#define PORT_PLL_LOCK_THRESHOLD_MASK (0x7 << PORT_PLL_LOCK_THRESHOLD_SHIFT) /* PORT_PLL_10_A */ #define PORT_PLL_DCO_AMP_OVR_EN_H (1<<27) #define PORT_PLL_DCO_AMP_MASK 0x3c00 diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index b29d103bd706a..cf2896da8ad80 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1722,11 +1722,15 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, crtc_state->dpll_hw_state.pll8 = targ_cnt; + crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; + if (dcoampovr_en_h) crtc_state->dpll_hw_state.pll10 = PORT_PLL_DCO_AMP_OVR_EN_H; crtc_state->dpll_hw_state.pll10 |= PORT_PLL_DCO_AMP(dco_amp); + crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE; + crtc_state->dpll_hw_state.pcsdw12 = LANESTAGGER_STRAP_OVRD | lanestagger; @@ -2767,7 +2771,7 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, temp = I915_READ(BXT_PORT_PLL(port, 9)); temp &= ~PORT_PLL_LOCK_THRESHOLD_MASK; - temp |= (5 << 1); + temp |= pll->config.hw_state.pll9; I915_WRITE(BXT_PORT_PLL(port, 9), temp); temp = I915_READ(BXT_PORT_PLL(port, 10)); @@ -2780,8 +2784,8 @@ static void bxt_ddi_pll_enable(struct drm_i915_private *dev_priv, temp = I915_READ(BXT_PORT_PLL_EBB_4(port)); temp |= PORT_PLL_RECALIBRATE; I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); - /* Enable 10 bit clock */ - temp |= PORT_PLL_10BIT_CLK_ENABLE; + temp &= ~PORT_PLL_10BIT_CLK_ENABLE; + temp |= pll->config.hw_state.ebb4; I915_WRITE(BXT_PORT_PLL_EBB_4(port), temp); /* Enable PLL */ @@ -2832,12 +2836,18 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, return false; hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); + hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port)); + hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; + hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0)); hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1)); hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2)); hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3)); hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6)); hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8)); + hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9)); + hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; + hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10)); /* * While we write to the group register to program all lanes at once we diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b7d42e6aac109..6be8768459318 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12012,17 +12012,19 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide); if (IS_BROXTON(dev)) { - DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, " + DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, " - "pll6: 0x%x, pll8: 0x%x, pcsdw12: 0x%x\n", + "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pcsdw12: 0x%x\n", pipe_config->ddi_pll_sel, pipe_config->dpll_hw_state.ebb0, + pipe_config->dpll_hw_state.ebb4, pipe_config->dpll_hw_state.pll0, pipe_config->dpll_hw_state.pll1, pipe_config->dpll_hw_state.pll2, pipe_config->dpll_hw_state.pll3, pipe_config->dpll_hw_state.pll6, pipe_config->dpll_hw_state.pll8, + pipe_config->dpll_hw_state.pll9, pipe_config->dpll_hw_state.pcsdw12); } else if (IS_SKYLAKE(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: " -- GitLab From c8453338b8218b42b70cc256badeaca52021a42c Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 18 Jun 2015 17:25:55 +0300 Subject: [PATCH 0295/7006] drm/i915/bxt: add PLL10 to the PLL state dumper Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 6be8768459318..dd430ce1f37e6 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12014,7 +12014,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, if (IS_BROXTON(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: ebb0: 0x%x, ebb4: 0x%x," "pll0: 0x%x, pll1: 0x%x, pll2: 0x%x, pll3: 0x%x, " - "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pcsdw12: 0x%x\n", + "pll6: 0x%x, pll8: 0x%x, pll9: 0x%x, pll10: 0x%x, pcsdw12: 0x%x\n", pipe_config->ddi_pll_sel, pipe_config->dpll_hw_state.ebb0, pipe_config->dpll_hw_state.ebb4, @@ -12025,6 +12025,7 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc, pipe_config->dpll_hw_state.pll6, pipe_config->dpll_hw_state.pll8, pipe_config->dpll_hw_state.pll9, + pipe_config->dpll_hw_state.pll10, pipe_config->dpll_hw_state.pcsdw12); } else if (IS_SKYLAKE(dev)) { DRM_DEBUG_KMS("ddi_pll_sel: %u; dpll_hw_state: " -- GitLab From 589eca678a0348687fbfc3194a0d87467a3f6c3f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Jun 2015 23:35:50 +0300 Subject: [PATCH 0296/7006] drm/i915/vlv: move the vlv PLL helper next to its platform counterparts Move the helper next to the PLL helpers of the other platforms for clarity. No functional change. Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index dd430ce1f37e6..8ec0f30f08470 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -418,16 +418,6 @@ static const intel_limit_t intel_limits_bxt = { .p2 = { .p2_slow = 1, .p2_fast = 20 }, }; -static void vlv_clock(int refclk, intel_clock_t *clock) -{ - clock->m = clock->m1 * clock->m2; - clock->p = clock->p1 * clock->p2; - if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; - clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); - clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); -} - static bool needs_modeset(struct drm_crtc_state *state) { @@ -589,6 +579,16 @@ static void i9xx_clock(int refclk, intel_clock_t *clock) clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); } +static void vlv_clock(int refclk, intel_clock_t *clock) +{ + clock->m = clock->m1 * clock->m2; + clock->p = clock->p1 * clock->p2; + if (WARN_ON(clock->n == 0 || clock->p == 0)) + return; + clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); + clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); +} + static void chv_clock(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; -- GitLab From dccbea3b0704c77c5bbd9e5e9240d6eb253d2565 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Jun 2015 23:35:51 +0300 Subject: [PATCH 0297/7006] drm/i915: calculate the port clock rate along with other PLL params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Depending on the platform the port clock fed to the pipe can be the PLL's post-divided fast clock rate or a /5 divided version of it. To make this more obvious across the platforms calculate this port clock along with the rest of the PLL parameters. This is also needed by the next patch where we can reuse the CHV helper for the BXT PLL HW readout code; so export the corresponding helper. While at it also add a more descriptive name to the helpers and a comment explaining what's being calculated. No functional change. Suggested-by: Ville Syrjälä Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 61 ++++++++++++++++------------ drivers/gpu/drm/i915/intel_drv.h | 2 + 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ec0f30f08470..724b0e3a5d37e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -553,15 +553,25 @@ intel_limit(struct intel_crtc_state *crtc_state, int refclk) return limit; } +/* + * Platform specific helpers to calculate the port PLL loopback- (clock.m), + * and post-divider (clock.p) values, pre- (clock.vco) and post-divided fast + * (clock.dot) clock rates. This fast dot clock is fed to the port's IO logic. + * The helpers' return value is the rate of the clock that is fed to the + * display engine's pipe which can be the above fast dot clock rate or a + * divided-down version of it. + */ /* m1 is reserved as 0 in Pineview, n is a ring counter */ -static void pineview_clock(int refclk, intel_clock_t *clock) +static int pnv_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = clock->m2 + 2; clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot; } static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) @@ -569,35 +579,41 @@ static uint32_t i9xx_dpll_compute_m(struct dpll *dpll) return 5 * (dpll->m1 + 2) + (dpll->m2 + 2); } -static void i9xx_clock(int refclk, intel_clock_t *clock) +static int i9xx_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = i9xx_dpll_compute_m(clock); clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n + 2 == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot; } -static void vlv_clock(int refclk, intel_clock_t *clock) +static int vlv_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot / 5; } -static void chv_clock(int refclk, intel_clock_t *clock) +int chv_calc_dpll_params(int refclk, intel_clock_t *clock) { clock->m = clock->m1 * clock->m2; clock->p = clock->p1 * clock->p2; if (WARN_ON(clock->n == 0 || clock->p == 0)) - return; + return 0; clock->vco = DIV_ROUND_CLOSEST_ULL((uint64_t)refclk * clock->m, clock->n << 22); clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p); + + return clock->dot / 5; } #define INTELPllInvalid(s) do { /* DRM_DEBUG(s); */ return false; } while (0) @@ -692,7 +708,7 @@ i9xx_find_best_dpll(const intel_limit_t *limit, clock.p1 <= limit->p1.max; clock.p1++) { int this_err; - i9xx_clock(refclk, &clock); + i9xx_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -737,7 +753,7 @@ pnv_find_best_dpll(const intel_limit_t *limit, clock.p1 <= limit->p1.max; clock.p1++) { int this_err; - pineview_clock(refclk, &clock); + pnv_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -787,7 +803,7 @@ g4x_find_best_dpll(const intel_limit_t *limit, clock.p1 >= limit->p1.min; clock.p1--) { int this_err; - i9xx_clock(refclk, &clock); + i9xx_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -877,7 +893,7 @@ vlv_find_best_dpll(const intel_limit_t *limit, clock.m2 = DIV_ROUND_CLOSEST(target * clock.p * clock.n, refclk * clock.m1); - vlv_clock(refclk, &clock); + vlv_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) @@ -940,7 +956,7 @@ chv_find_best_dpll(const intel_limit_t *limit, clock.m2 = m2; - chv_clock(refclk, &clock); + chv_calc_dpll_params(refclk, &clock); if (!intel_PLL_is_valid(dev, limit, &clock)) continue; @@ -7925,10 +7941,7 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc, clock.p1 = (mdiv >> DPIO_P1_SHIFT) & 7; clock.p2 = (mdiv >> DPIO_P2_SHIFT) & 0x1f; - vlv_clock(refclk, &clock); - - /* clock.dot is the fast clock */ - pipe_config->port_clock = clock.dot / 5; + pipe_config->port_clock = vlv_calc_dpll_params(refclk, &clock); } static void @@ -8024,10 +8037,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc, clock.p1 = (cmn_dw13 >> DPIO_CHV_P1_DIV_SHIFT) & 0x7; clock.p2 = (cmn_dw13 >> DPIO_CHV_P2_DIV_SHIFT) & 0x1f; - chv_clock(refclk, &clock); - - /* clock.dot is the fast clock */ - pipe_config->port_clock = clock.dot / 5; + pipe_config->port_clock = chv_calc_dpll_params(refclk, &clock); } static bool i9xx_get_pipe_config(struct intel_crtc *crtc, @@ -10464,6 +10474,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, u32 dpll = pipe_config->dpll_hw_state.dpll; u32 fp; intel_clock_t clock; + int port_clock; int refclk = i9xx_pll_refclk(dev, pipe_config); if ((dpll & DISPLAY_RATE_SELECT_FPA1) == 0) @@ -10504,9 +10515,9 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, } if (IS_PINEVIEW(dev)) - pineview_clock(refclk, &clock); + port_clock = pnv_calc_dpll_params(refclk, &clock); else - i9xx_clock(refclk, &clock); + port_clock = i9xx_calc_dpll_params(refclk, &clock); } else { u32 lvds = IS_I830(dev) ? 0 : I915_READ(LVDS); bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN); @@ -10532,7 +10543,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, clock.p2 = 2; } - i9xx_clock(refclk, &clock); + port_clock = i9xx_calc_dpll_params(refclk, &clock); } /* @@ -10540,7 +10551,7 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, * port_clock to compute adjusted_mode.crtc_clock in the * encoder's get_config() function. */ - pipe_config->port_clock = clock.dot; + pipe_config->port_clock = port_clock; } int intel_dotclock_calculate(int link_freq, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index bb52620a3ce81..3f0a89060820b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1140,6 +1140,8 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config, int dotclock); bool bxt_find_best_dpll(struct intel_crtc_state *crtc_state, int target_clock, intel_clock_t *best_clock); +int chv_calc_dpll_params(int refclk, intel_clock_t *pll_clock); + bool intel_crtc_active(struct drm_crtc *crtc); void hsw_enable_ips(struct intel_crtc *crtc); void hsw_disable_ips(struct intel_crtc *crtc); -- GitLab From aa610dcb7c1999fe3353562340a72196d9a54ae0 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 22 Jun 2015 23:35:52 +0300 Subject: [PATCH 0298/7006] drm/i915/bxt: add DDI port HW readout support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for reading out the HW state for DDI ports. Since the actual programming is very similar to the CHV/VLV DPIO PLL programming we can reuse much of the logic from there. This fixes the state checker failures I saw on my BXT with HDMI output. v2: - rebased on v2 of patch 4/5 Signed-off-by: Imre Deak Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 15 +++++++++------ drivers/gpu/drm/i915/intel_ddi.c | 22 ++++++++++++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 4d8ef2de4374c..42ba1ef641d8f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1170,10 +1170,12 @@ enum skl_disp_power_wells { #define _PORT_PLL_EBB_0_A 0x162034 #define _PORT_PLL_EBB_0_B 0x6C034 #define _PORT_PLL_EBB_0_C 0x6C340 -#define PORT_PLL_P1_MASK (0x07 << 13) -#define PORT_PLL_P1(x) ((x) << 13) -#define PORT_PLL_P2_MASK (0x1f << 8) -#define PORT_PLL_P2(x) ((x) << 8) +#define PORT_PLL_P1_SHIFT 13 +#define PORT_PLL_P1_MASK (0x07 << PORT_PLL_P1_SHIFT) +#define PORT_PLL_P1(x) ((x) << PORT_PLL_P1_SHIFT) +#define PORT_PLL_P2_SHIFT 8 +#define PORT_PLL_P2_MASK (0x1f << PORT_PLL_P2_SHIFT) +#define PORT_PLL_P2(x) ((x) << PORT_PLL_P2_SHIFT) #define BXT_PORT_PLL_EBB_0(port) _PORT3(port, _PORT_PLL_EBB_0_A, \ _PORT_PLL_EBB_0_B, \ _PORT_PLL_EBB_0_C) @@ -1193,8 +1195,9 @@ enum skl_disp_power_wells { /* PORT_PLL_0_A */ #define PORT_PLL_M2_MASK 0xFF /* PORT_PLL_1_A */ -#define PORT_PLL_N_MASK (0x0F << 8) -#define PORT_PLL_N(x) ((x) << 8) +#define PORT_PLL_N_SHIFT 8 +#define PORT_PLL_N_MASK (0x0F << PORT_PLL_N_SHIFT) +#define PORT_PLL_N(x) ((x) << PORT_PLL_N_SHIFT) /* PORT_PLL_2_A */ #define PORT_PLL_M2_FRAC_MASK 0x3FFFFF /* PORT_PLL_3_A */ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cf2896da8ad80..cef9709fa2bae 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1140,8 +1140,26 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, static int bxt_calc_pll_link(struct drm_i915_private *dev_priv, enum intel_dpll_id dpll) { - /* FIXME formula not available in bspec */ - return 0; + struct intel_shared_dpll *pll; + struct intel_dpll_hw_state *state; + intel_clock_t clock; + + /* For DDI ports we always use a shared PLL. */ + if (WARN_ON(dpll == DPLL_ID_PRIVATE)) + return 0; + + pll = &dev_priv->shared_dplls[dpll]; + state = &pll->config.hw_state; + + clock.m1 = 2; + clock.m2 = (state->pll0 & PORT_PLL_M2_MASK) << 22; + if (state->pll3 & PORT_PLL_M2_FRAC_ENABLE) + clock.m2 |= state->pll2 & PORT_PLL_M2_FRAC_MASK; + clock.n = (state->pll1 & PORT_PLL_N_MASK) >> PORT_PLL_N_SHIFT; + clock.p1 = (state->ebb0 & PORT_PLL_P1_MASK) >> PORT_PLL_P1_SHIFT; + clock.p2 = (state->ebb0 & PORT_PLL_P2_MASK) >> PORT_PLL_P2_SHIFT; + + return chv_calc_dpll_params(100000, &clock); } static void bxt_ddi_clock_get(struct intel_encoder *encoder, -- GitLab From 2f2cfc4a9a5b7be65d61382b58cfb206f13966df Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:01 +0530 Subject: [PATCH 0299/7006] ath10k: Add a table to store hw specific values This is to prepare ath10k to support newer chip set. Values like CE_COUNT, MSI_ASSIGN_CE_MAX and RTC_STATE_V_ON can be different for different chips. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/hw.c | 14 ++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 18 +++++++++++++++--- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f5db43284b97c..b17541b74aaff 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1514,9 +1514,11 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, switch (hw_rev) { case ATH10K_HW_QCA988X: ar->regs = &qca988x_regs; + ar->hw_values = &qca988x_values; break; case ATH10K_HW_QCA6174: ar->regs = &qca6174_regs; + ar->hw_values = &qca6174_values; break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index e9f93045fbd86..993cd362fb0ac 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -560,6 +560,7 @@ struct ath10k { struct completion target_suspend; const struct ath10k_hw_regs *regs; + const struct ath10k_hw_values *hw_values; struct ath10k_bmi bmi; struct ath10k_wmi wmi; struct ath10k_htc htc; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 5997f00afe3b4..48bcd2cfad00e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -58,6 +58,20 @@ const struct ath10k_hw_regs qca6174_regs = { .scratch_3_address = 0x0028, }; +const struct ath10k_hw_values qca988x_values = { + .rtc_state_val_on = 3, + .ce_count = 8, + .msi_assign_ce_max = 7, + .num_target_ce_config_wlan = 7, +}; + +const struct ath10k_hw_values qca6174_values = { + .rtc_state_val_on = 3, + .ce_count = 8, + .msi_assign_ce_max = 7, + .num_target_ce_config_wlan = 7, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 85cca29375fee..b218388131caa 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -169,6 +169,16 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +struct ath10k_hw_values { + u32 rtc_state_val_on; + u8 ce_count; + u8 msi_assign_ce_max; + u8 num_target_ce_config_wlan; +}; + +extern const struct ath10k_hw_values qca988x_values; +extern const struct ath10k_hw_values qca6174_values; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); @@ -310,8 +320,10 @@ enum ath10k_hw_rate_cck { #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +#define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan + /* Number of Copy Engines supported */ -#define CE_COUNT 8 +#define CE_COUNT ar->hw_values->ce_count /* * Total number of PCIe MSI interrupts requested for all interrupt sources. @@ -335,10 +347,10 @@ enum ath10k_hw_rate_cck { /* MSIs for Copy Engines */ #define MSI_ASSIGN_CE_INITIAL 1 -#define MSI_ASSIGN_CE_MAX 7 +#define MSI_ASSIGN_CE_MAX ar->hw_values->msi_assign_ce_max /* as of IP3.7.1 */ -#define RTC_STATE_V_ON 3 +#define RTC_STATE_V_ON ar->hw_values->rtc_state_val_on #define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask #define RTC_STATE_V_LSB 0 -- GitLab From a521ee983d312db76e6c275c32475cb20bdc7d39 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:02 +0530 Subject: [PATCH 0300/7006] ath10k: Add new reg_address/mask to hw register table Add more register address and mask which can be different for newer chip to hw_reg table. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 6 ++++-- drivers/net/wireless/ath/ath10k/hw.c | 22 ++++++++++++++++++---- drivers/net/wireless/ath/ath10k/hw.h | 17 ++++++++++++----- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 0eddb204d85bb..93939de2be19a 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -423,8 +423,10 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id) #define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask)) -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB 8 -#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK 0x0000ff00 +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \ + ar->regs->ce_wrap_intr_sum_host_msi_lsb +#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \ + ar->regs->ce_wrap_intr_sum_host_msi_mask #define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \ (((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \ CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 48bcd2cfad00e..cb09867b55335 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -34,8 +34,15 @@ const struct ath10k_hw_regs qca988x_regs = { .ce7_base_address = 0x00059000, .soc_reset_control_si0_rst_mask = 0x00000001, .soc_reset_control_ce_rst_mask = 0x00040000, - .soc_chip_id_address = 0x00ec, - .scratch_3_address = 0x0030, + .soc_chip_id_address = 0x000000ec, + .scratch_3_address = 0x00000030, + .fw_indicator_address = 0x00009030, + .pcie_local_base_address = 0x00080000, + .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, + .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, + .pcie_intr_fw_mask = 0x00000400, + .pcie_intr_ce_mask_all = 0x0007f800, + .pcie_intr_clr_address = 0x00000014, }; const struct ath10k_hw_regs qca6174_regs = { @@ -54,8 +61,15 @@ const struct ath10k_hw_regs qca6174_regs = { .ce7_base_address = 0x00036000, .soc_reset_control_si0_rst_mask = 0x00000000, .soc_reset_control_ce_rst_mask = 0x00000001, - .soc_chip_id_address = 0x000f0, - .scratch_3_address = 0x0028, + .soc_chip_id_address = 0x000000f0, + .scratch_3_address = 0x00000028, + .fw_indicator_address = 0x00009028, + .pcie_local_base_address = 0x00080000, + .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, + .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, + .pcie_intr_fw_mask = 0x00000400, + .pcie_intr_ce_mask_all = 0x0007f800, + .pcie_intr_clr_address = 0x00000014, }; const struct ath10k_hw_values qca988x_values = { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b218388131caa..5d04317cb3dc0 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -164,6 +164,13 @@ struct ath10k_hw_regs { u32 soc_reset_control_ce_rst_mask; u32 soc_chip_id_address; u32 scratch_3_address; + u32 fw_indicator_address; + u32 pcie_local_base_address; + u32 ce_wrap_intr_sum_host_msi_lsb; + u32 ce_wrap_intr_sum_host_msi_mask; + u32 pcie_intr_fw_mask; + u32 pcie_intr_ce_mask_all; + u32 pcie_intr_clr_address; }; extern const struct ath10k_hw_regs qca988x_regs; @@ -386,7 +393,7 @@ enum ath10k_hw_rate_cck { #define CE7_BASE_ADDRESS ar->regs->ce7_base_address #define DBI_BASE_ADDRESS 0x00060000 #define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000 -#define PCIE_LOCAL_BASE_ADDRESS 0x00080000 +#define PCIE_LOCAL_BASE_ADDRESS ar->regs->pcie_local_base_address #define SOC_RESET_CONTROL_ADDRESS 0x00000000 #define SOC_RESET_CONTROL_OFFSET 0x00000000 @@ -460,7 +467,7 @@ enum ath10k_hw_rate_cck { #define CORE_CTRL_ADDRESS 0x0000 #define PCIE_INTR_ENABLE_ADDRESS 0x0008 #define PCIE_INTR_CAUSE_ADDRESS 0x000c -#define PCIE_INTR_CLR_ADDRESS 0x0014 +#define PCIE_INTR_CLR_ADDRESS ar->regs->pcie_intr_clr_address #define SCRATCH_3_ADDRESS ar->regs->scratch_3_address #define CPU_INTR_ADDRESS 0x0010 @@ -468,13 +475,13 @@ enum ath10k_hw_rate_cck { #define CCNT_TO_MSEC(x) ((x) / 88000) /* Firmware indications to the Host via SCRATCH_3 register. */ -#define FW_INDICATOR_ADDRESS (SOC_CORE_BASE_ADDRESS + SCRATCH_3_ADDRESS) +#define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address #define FW_IND_EVENT_PENDING 1 #define FW_IND_INITIALIZED 2 /* HOST_REG interrupt from firmware */ -#define PCIE_INTR_FIRMWARE_MASK 0x00000400 -#define PCIE_INTR_CE_MASK_ALL 0x0007f800 +#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask +#define PCIE_INTR_CE_MASK_ALL ar->regs->pcie_intr_ce_mask_all #define DRAM_BASE_ADDRESS 0x00400000 -- GitLab From 8bd4702103dca2b06446f85c04222faa8eb553b5 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:03 +0530 Subject: [PATCH 0301/7006] ath10k: Add hw register/values for QCA99X0 chip This is to prepare the driver for QCA99X0 chip support. This commit adds hw_params, hw register table and hw_values table for QCA99X0 chip. Please note this is only a partial patch adding support for QCA99X0, so the device id is not yet added to pci device table. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 18 +++++++++ drivers/net/wireless/ath/ath10k/hw.c | 44 +++++++++++++++++++++ drivers/net/wireless/ath/ath10k/hw.h | 18 +++++++++ drivers/net/wireless/ath/ath10k/pci.c | 5 +++ drivers/net/wireless/ath/ath10k/targaddrs.h | 3 ++ 5 files changed, 88 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index b17541b74aaff..f239e9690831d 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -101,6 +101,20 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ, }, }, + { + .id = QCA99X0_HW_2_0_DEV_VERSION, + .name = "qca99x0 hw2.0", + .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, + .uart_pin = 7, + .fw = { + .dir = QCA99X0_HW_2_0_FW_DIR, + .fw = QCA99X0_HW_2_0_FW_FILE, + .otp = QCA99X0_HW_2_0_OTP_FILE, + .board = QCA99X0_HW_2_0_BOARD_DATA_FILE, + .board_size = QCA99X0_BOARD_DATA_SZ, + .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ, + }, + }, }; static const char *const ath10k_core_fw_feature_str[] = { @@ -1520,6 +1534,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev, ar->regs = &qca6174_regs; ar->hw_values = &qca6174_values; break; + case ATH10K_HW_QCA99X0: + ar->regs = &qca99x0_regs; + ar->hw_values = &qca99x0_values; + break; default: ath10k_err(ar, "unsupported core hardware revision %d\n", hw_rev); diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index cb09867b55335..e5fe33d9ca438 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -72,6 +72,43 @@ const struct ath10k_hw_regs qca6174_regs = { .pcie_intr_clr_address = 0x00000014, }; +const struct ath10k_hw_regs qca99x0_regs = { + .rtc_state_cold_reset_mask = 0x00000400, + .rtc_soc_base_address = 0x00080000, + .rtc_wmac_base_address = 0x00000000, + .soc_core_base_address = 0x00082000, + .ce_wrapper_base_address = 0x0004d000, + .ce0_base_address = 0x0004a000, + .ce1_base_address = 0x0004a400, + .ce2_base_address = 0x0004a800, + .ce3_base_address = 0x0004ac00, + .ce4_base_address = 0x0004b000, + .ce5_base_address = 0x0004b400, + .ce6_base_address = 0x0004b800, + .ce7_base_address = 0x0004bc00, + /* Note: qca99x0 supports upto 12 Copy Engines. Other than address of + * CE0 and CE1 no other copy engine is directly referred in the code. + * It is not really neccessary to assign address for newly supported + * CEs in this address table. + * Copy Engine Address + * CE8 0x0004c000 + * CE9 0x0004c400 + * CE10 0x0004c800 + * CE11 0x0004cc00 + */ + .soc_reset_control_si0_rst_mask = 0x00000001, + .soc_reset_control_ce_rst_mask = 0x00000100, + .soc_chip_id_address = 0x000000ec, + .scratch_3_address = 0x00040050, + .fw_indicator_address = 0x00040050, + .pcie_local_base_address = 0x00000000, + .ce_wrap_intr_sum_host_msi_lsb = 0x0000000c, + .ce_wrap_intr_sum_host_msi_mask = 0x00fff000, + .pcie_intr_fw_mask = 0x00100000, + .pcie_intr_ce_mask_all = 0x000fff00, + .pcie_intr_clr_address = 0x00000010, +}; + const struct ath10k_hw_values qca988x_values = { .rtc_state_val_on = 3, .ce_count = 8, @@ -86,6 +123,13 @@ const struct ath10k_hw_values qca6174_values = { .num_target_ce_config_wlan = 7, }; +const struct ath10k_hw_values qca99x0_values = { + .rtc_state_val_on = 5, + .ce_count = 12, + .msi_assign_ce_max = 12, + .num_target_ce_config_wlan = 10, +}; + void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev) { diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5d04317cb3dc0..76caeab5c7d33 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -72,6 +72,18 @@ enum qca6174_chip_id_rev { #define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin" #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234 +/* QCA99X0 1.0 definitions (unsupported) */ +#define QCA99X0_HW_1_0_CHIP_ID_REV 0x0 + +/* QCA99X0 2.0 definitions */ +#define QCA99X0_HW_2_0_DEV_VERSION 0x01000000 +#define QCA99X0_HW_2_0_CHIP_ID_REV 0x1 +#define QCA99X0_HW_2_0_FW_DIR ATH10K_FW_DIR "/QCA99X0/hw2.0" +#define QCA99X0_HW_2_0_FW_FILE "firmware.bin" +#define QCA99X0_HW_2_0_OTP_FILE "otp.bin" +#define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin" +#define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234 + #define ATH10K_FW_API2_FILE "firmware-2.bin" #define ATH10K_FW_API3_FILE "firmware-3.bin" @@ -144,6 +156,7 @@ enum ath10k_fw_htt_op_version { enum ath10k_hw_rev { ATH10K_HW_QCA988X, ATH10K_HW_QCA6174, + ATH10K_HW_QCA99X0, }; struct ath10k_hw_regs { @@ -175,6 +188,7 @@ struct ath10k_hw_regs { extern const struct ath10k_hw_regs qca988x_regs; extern const struct ath10k_hw_regs qca6174_regs; +extern const struct ath10k_hw_regs qca99x0_regs; struct ath10k_hw_values { u32 rtc_state_val_on; @@ -185,12 +199,14 @@ struct ath10k_hw_values { extern const struct ath10k_hw_values qca988x_values; extern const struct ath10k_hw_values qca6174_values; +extern const struct ath10k_hw_values qca99x0_values; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev); #define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X) #define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174) +#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0) /* Known pecularities: * - current FW doesn't support raw rx mode (last tested v599) @@ -485,6 +501,8 @@ enum ath10k_hw_rate_cck { #define DRAM_BASE_ADDRESS 0x00400000 +#define PCIE_BAR_REG_ADDRESS 0x40030 + #define MISSING 0 #define SYSTEM_SLEEP_OFFSET SOC_SYSTEM_SLEEP_OFFSET diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 41765172297ce..0007e7077f9c5 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -59,6 +59,7 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define QCA988X_2_0_DEVICE_ID (0x003c) #define QCA6174_2_1_DEVICE_ID (0x003e) +#define QCA99X0_2_0_DEVICE_ID (0x0040) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ @@ -1699,6 +1700,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) switch (ar_pci->pdev->device) { case QCA988X_2_0_DEVICE_ID: + case QCA99X0_2_0_DEVICE_ID: return 1; case QCA6174_2_1_DEVICE_ID: switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { @@ -2758,6 +2760,9 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA6174_2_1_DEVICE_ID: hw_rev = ATH10K_HW_QCA6174; break; + case QCA99X0_2_0_DEVICE_ID: + hw_rev = ATH10K_HW_QCA99X0; + break; default: WARN_ON(1); return -ENOTSUPP; diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h index a417aae52623d..768bef6290995 100644 --- a/drivers/net/wireless/ath/ath10k/targaddrs.h +++ b/drivers/net/wireless/ath/ath10k/targaddrs.h @@ -450,4 +450,7 @@ Fw Mode/SubMode Mask #define QCA6174_BOARD_DATA_SZ 8192 #define QCA6174_BOARD_EXT_DATA_SZ 0 +#define QCA99X0_BOARD_DATA_SZ 12288 +#define QCA99X0_BOARD_EXT_DATA_SZ 0 + #endif /* __TARGADDRS_H__ */ -- GitLab From 050af069de03489947023544bfed1977952b8215 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:04 +0530 Subject: [PATCH 0302/7006] ath10k: Copy Engine related changes for QCA99X0 QCA99X0 supports upto 12 Copy engines. Host and target CE configuration table is updated to support new copy engine pipes. This also fixes the assumption of diagnostic CE by making CE_7 as the one instead of CE_COUNT - 1. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.h | 2 +- drivers/net/wireless/ath/ath10k/hw.h | 3 ++ drivers/net/wireless/ath/ath10k/pci.c | 69 ++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index 93939de2be19a..bb4b8f3e7c5c7 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -21,7 +21,7 @@ #include "hif.h" /* Maximum number of Copy Engine's supported */ -#define CE_COUNT_MAX 8 +#define CE_COUNT_MAX 12 #define CE_HTT_H2T_MSG_SRC_NENTRIES 4096 /* Descriptor rings must be aligned to this boundary */ diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 76caeab5c7d33..5819659475941 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -343,6 +343,9 @@ enum ath10k_hw_rate_cck { #define TARGET_TLV_NUM_MSDU_DESC (1024 + 32) #define TARGET_TLV_NUM_WOW_PATTERNS 22 +/* Diagnostic Window */ +#define CE_DIAG_PIPE 7 + #define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan /* Number of Copy Engines supported */ diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0007e7077f9c5..c2aecfe765449 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -156,6 +156,38 @@ static const struct ce_attr host_ce_config_wlan[] = { .src_sz_max = DIAG_TRANSFER_LIMIT, .dest_nentries = 2, }, + + /* CE8: target->host pktlog */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 2048, + .dest_nentries = 128, + }, + + /* CE9 target autonomous qcache memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE10: target autonomous hif memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, + + /* CE11: target autonomous hif memcpy */ + { + .flags = CE_ATTR_FLAGS, + .src_nentries = 0, + .src_sz_max = 0, + .dest_nentries = 0, + }, }; /* Target firmware's Copy Engine configuration. */ @@ -233,6 +265,38 @@ static const struct ce_pipe_config target_ce_config_wlan[] = { }, /* CE7 used only by Host */ + { + .pipenum = __cpu_to_le32(7), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(0), + .nbytes_max = __cpu_to_le32(0), + .flags = __cpu_to_le32(0), + .reserved = __cpu_to_le32(0), + }, + + /* CE8 target->host packtlog */ + { + .pipenum = __cpu_to_le32(8), + .pipedir = __cpu_to_le32(PIPEDIR_IN), + .nentries = __cpu_to_le32(64), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* CE9 target autonomous qcache memcpy */ + { + .pipenum = __cpu_to_le32(9), + .pipedir = __cpu_to_le32(PIPEDIR_INOUT), + .nentries = __cpu_to_le32(32), + .nbytes_max = __cpu_to_le32(2048), + .flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR), + .reserved = __cpu_to_le32(0), + }, + + /* It not necessary to send target wlan configuration for CE10 & CE11 + * as these CEs are not actively used in target. + */ }; /* @@ -1771,7 +1835,8 @@ static int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_write_mem(ar, pipe_cfg_targ_addr, target_ce_config_wlan, - sizeof(target_ce_config_wlan)); + sizeof(struct ce_pipe_config) * + NUM_TARGET_CE_CONFIG_WLAN); if (ret != 0) { ath10k_err(ar, "Failed to write pipe cfg: %d\n", ret); @@ -1885,7 +1950,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar) } /* Last CE is Diagnostic Window */ - if (i == CE_COUNT - 1) { + if (i == CE_DIAG_PIPE) { ar_pci->ce_diag = pipe->ce_hdl; continue; } -- GitLab From 418ca5992e2f91050e0673b3a3a78197f0122bf8 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:05 +0530 Subject: [PATCH 0303/7006] ath10k: Make target cpu address to CE address conversion chip specific Make the helper converting target virtual address space to CE address space a target type specific to support QCA99X0. Also make this as function instead of macro. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 25 ++++++++++++++++++++++--- drivers/net/wireless/ath/ath10k/pci.h | 12 ------------ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index c2aecfe765449..df7d74e751498 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -755,6 +755,26 @@ static void ath10k_pci_rx_replenish_retry(unsigned long ptr) ath10k_pci_rx_post(ar); } +static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) +{ + u32 val = 0; + + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS) & + 0x7fff) << 21; + break; + case ATH10K_HW_QCA99X0: + val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); + break; + } + + val |= 0x100000 | (addr & 0xfffff); + return val; +} + /* * Diagnostic read/write access is provided for startup/config/debug usage. * Caller must guarantee proper alignment, when applicable, and single user @@ -817,8 +837,7 @@ static int ath10k_pci_diag_read_mem(struct ath10k *ar, u32 address, void *data, * convert it from Target CPU virtual address space * to CE address space */ - address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, - address); + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); ret = ath10k_ce_send_nolock(ce_diag, NULL, (u32)address, nbytes, 0, 0); @@ -976,7 +995,7 @@ static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address, * to * CE address space */ - address = TARG_CPU_SPACE_TO_CE_SPACE(ar, ar_pci->mem, address); + address = ath10k_pci_targ_cpu_to_ce_addr(ar, address); remaining_bytes = orig_nbytes; ce_data = ce_data_base; diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h index eea0a0170b00f..8d364fb8f743e 100644 --- a/drivers/net/wireless/ath/ath10k/pci.h +++ b/drivers/net/wireless/ath/ath10k/pci.h @@ -237,18 +237,6 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar) #define CDC_WAR_MAGIC_STR 0xceef0000 #define CDC_WAR_DATA_CE 4 -/* - * TODO: Should be a function call specific to each Target-type. - * This convoluted macro converts from Target CPU Virtual Address Space to CE - * Address Space. As part of this process, we conservatively fetch the current - * PCIE_BAR. MOST of the time, this should match the upper bits of PCI space - * for this device; but that's not guaranteed. - */ -#define TARG_CPU_SPACE_TO_CE_SPACE(ar, pci_addr, addr) \ - (((ath10k_pci_read32(ar, (SOC_CORE_BASE_ADDRESS | \ - CORE_CTRL_ADDRESS)) & 0x7ff) << 21) | \ - 0x100000 | ((addr) & 0xfffff)) - /* Wait up to this many Ms for a Diagnostic Access CE operation to complete */ #define DIAG_ACCESS_CE_TIMEOUT_MS 10 -- GitLab From 6e4202c3ed301dea62885a3ead6506534fcf8db3 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:06 +0530 Subject: [PATCH 0304/7006] ath10k: Add chip reset sequence for QCA99X0 QCA99X0 supports only cold reset. Also, made ath10k_pci_irq_msi_fw_mask() and ath10k_pci_irq_msi_fw_unmask() non-99X0 specific till we get proper register configuration to mask/unmask irq/MSI. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 81 +++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index df7d74e751498..1b4634a6374db 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -82,7 +82,7 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { static void ath10k_pci_buffer_cleanup(struct ath10k *ar); static int ath10k_pci_cold_reset(struct ath10k *ar); -static int ath10k_pci_warm_reset(struct ath10k *ar); +static int ath10k_pci_safe_chip_reset(struct ath10k *ar); static int ath10k_pci_wait_for_target_init(struct ath10k *ar); static int ath10k_pci_init_irq(struct ath10k *ar); static int ath10k_pci_deinit_irq(struct ath10k *ar); @@ -91,6 +91,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar); static int ath10k_pci_bmi_wait(struct ath10k_ce_pipe *tx_pipe, struct ath10k_ce_pipe *rx_pipe, struct bmi_xfer *xfer); +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar); static const struct ce_attr host_ce_config_wlan[] = { /* CE0: host->target HTC control and raw streams */ @@ -1427,20 +1428,42 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); - val &= ~CORE_CTRL_PCIE_REG_31_MASK; - - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS); + val &= ~CORE_CTRL_PCIE_REG_31_MASK; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS, val); + break; + case ATH10K_HW_QCA99X0: + /* TODO: Find appropriate register configuration for QCA99X0 + * to mask irq/MSI. + */ + break; + } } static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar) { u32 val; - val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS); - val |= CORE_CTRL_PCIE_REG_31_MASK; - - ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS, val); + switch (ar->hw_rev) { + case ATH10K_HW_QCA988X: + case ATH10K_HW_QCA6174: + val = ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS); + val |= CORE_CTRL_PCIE_REG_31_MASK; + ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + + CORE_CTRL_ADDRESS, val); + break; + case ATH10K_HW_QCA99X0: + /* TODO: Find appropriate register configuration for QCA99X0 + * to unmask irq/MSI. + */ + break; + } } static void ath10k_pci_irq_disable(struct ath10k *ar) @@ -1602,7 +1625,7 @@ static void ath10k_pci_hif_stop(struct ath10k *ar) * masked. To prevent the device from asserting the interrupt reset it * before proceeding with cleanup. */ - ath10k_pci_warm_reset(ar); + ath10k_pci_safe_chip_reset(ar); ath10k_pci_irq_disable(ar); ath10k_pci_irq_sync(ar); @@ -2114,6 +2137,18 @@ static int ath10k_pci_warm_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_safe_chip_reset(struct ath10k *ar) +{ + if (QCA_REV_988X(ar) || QCA_REV_6174(ar)) { + return ath10k_pci_warm_reset(ar); + } else if (QCA_REV_99X0(ar)) { + ath10k_pci_irq_disable(ar); + return ath10k_pci_qca99x0_chip_reset(ar); + } else { + return -ENOTSUPP; + } +} + static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar) { int i, ret; @@ -2220,12 +2255,38 @@ static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar) return 0; } +static int ath10k_pci_qca99x0_chip_reset(struct ath10k *ar) +{ + int ret; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset\n"); + + ret = ath10k_pci_cold_reset(ar); + if (ret) { + ath10k_warn(ar, "failed to cold reset: %d\n", ret); + return ret; + } + + ret = ath10k_pci_wait_for_target_init(ar); + if (ret) { + ath10k_warn(ar, "failed to wait for target after cold reset: %d\n", + ret); + return ret; + } + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca99x0 chip reset complete (cold)\n"); + + return 0; +} + static int ath10k_pci_chip_reset(struct ath10k *ar) { if (QCA_REV_988X(ar)) return ath10k_pci_qca988x_chip_reset(ar); else if (QCA_REV_6174(ar)) return ath10k_pci_qca6174_chip_reset(ar); + else if (QCA_REV_99X0(ar)) + return ath10k_pci_qca99x0_chip_reset(ar); else return -ENOTSUPP; } -- GitLab From 2adf99ca33ca75c8a702797f77a1652e26f18a6e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:07 +0530 Subject: [PATCH 0305/7006] ath10k: Extend CE src desc flags for interrupt indication QCA99X0 uses two new copy engine src desc flags for interrupt indication. Bit_2 is to mark if host interrupt is disabled after processing the current desc and bit_3 is to mark if target interrupt is diabled after the processing of current descriptor. CE_DESC_FLAGS_META_DATA_MASK and CE_DESC_FLAGS_META_DATA_LSB are based on the target type. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/ce.c | 1 + drivers/net/wireless/ath/ath10k/ce.h | 9 +++++++-- drivers/net/wireless/ath/ath10k/hw.c | 6 ++++++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c index e508c65b6ba8a..cf28fbebaedcf 100644 --- a/drivers/net/wireless/ath/ath10k/ce.c +++ b/drivers/net/wireless/ath/ath10k/ce.c @@ -452,6 +452,7 @@ int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state, { struct ath10k_ce_ring *dest_ring = ce_state->dest_ring; unsigned int nentries_mask = dest_ring->nentries_mask; + struct ath10k *ar = ce_state->ar; unsigned int sw_index = dest_ring->sw_index; struct ce_desc *base = dest_ring->base_addr_owner_space; diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h index bb4b8f3e7c5c7..5c903e15dd65e 100644 --- a/drivers/net/wireless/ath/ath10k/ce.h +++ b/drivers/net/wireless/ath/ath10k/ce.h @@ -38,8 +38,13 @@ struct ath10k_ce_pipe; #define CE_DESC_FLAGS_GATHER (1 << 0) #define CE_DESC_FLAGS_BYTE_SWAP (1 << 1) -#define CE_DESC_FLAGS_META_DATA_MASK 0xFFFC -#define CE_DESC_FLAGS_META_DATA_LSB 2 + +/* Following desc flags are used in QCA99X0 */ +#define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2) +#define CE_DESC_FLAGS_TGT_INT_DIS (1 << 3) + +#define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask +#define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb struct ce_desc { __le32 addr; diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index e5fe33d9ca438..1414e1f3c7ac3 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -114,6 +114,8 @@ const struct ath10k_hw_values qca988x_values = { .ce_count = 8, .msi_assign_ce_max = 7, .num_target_ce_config_wlan = 7, + .ce_desc_meta_data_mask = 0xFFFC, + .ce_desc_meta_data_lsb = 2, }; const struct ath10k_hw_values qca6174_values = { @@ -121,6 +123,8 @@ const struct ath10k_hw_values qca6174_values = { .ce_count = 8, .msi_assign_ce_max = 7, .num_target_ce_config_wlan = 7, + .ce_desc_meta_data_mask = 0xFFFC, + .ce_desc_meta_data_lsb = 2, }; const struct ath10k_hw_values qca99x0_values = { @@ -128,6 +132,8 @@ const struct ath10k_hw_values qca99x0_values = { .ce_count = 12, .msi_assign_ce_max = 12, .num_target_ce_config_wlan = 10, + .ce_desc_meta_data_mask = 0xFFF0, + .ce_desc_meta_data_lsb = 4, }; void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey, diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 5819659475941..35cd8caaf7381 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -195,6 +195,8 @@ struct ath10k_hw_values { u8 ce_count; u8 msi_assign_ce_max; u8 num_target_ce_config_wlan; + u16 ce_desc_meta_data_mask; + u8 ce_desc_meta_data_lsb; }; extern const struct ath10k_hw_values qca988x_values; -- GitLab From fd3d6ffbd035d24b2baff0b5b39751183c289b33 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:08 +0530 Subject: [PATCH 0306/7006] ath10k: Fix BMI communication timeout for QCA99X0 There is more than 1 sec delay in getting response from target through BMI in QCA99X0. Increase the BMI communication timeout to 2*HZ to fix BMI failures. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/bmi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/bmi.h b/drivers/net/wireless/ath/ath10k/bmi.h index 31a990635490a..df7c7616533b0 100644 --- a/drivers/net/wireless/ath/ath10k/bmi.h +++ b/drivers/net/wireless/ath/ath10k/bmi.h @@ -178,7 +178,7 @@ struct bmi_target_info { }; /* in msec */ -#define BMI_COMMUNICATION_TIMEOUT_HZ (1*HZ) +#define BMI_COMMUNICATION_TIMEOUT_HZ (2 * HZ) #define BMI_CE_NUM_TO_TARG 0 #define BMI_CE_NUM_TO_HOST 1 -- GitLab From dcb02db1068b78bd1b4d2bf64317021c2531a7b0 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:09 +0530 Subject: [PATCH 0307/7006] ath10k: Add support for code swap Code swap is a mechanism to use host memory to store some fw binary code segment. Ath10k host driver allocates and loads the code swap binary into the host memory and configures the target with the host allocated memory information at the address taken from code swap binary. This patch adds code swap support for firmware binary. Code swap binary for firmware bin is available in ATH10K_FW_IE_FW_CODE_SWAP_IMAGE. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/Makefile | 3 +- drivers/net/wireless/ath/ath10k/core.c | 24 +++ drivers/net/wireless/ath/ath10k/core.h | 7 + drivers/net/wireless/ath/ath10k/hw.h | 3 + drivers/net/wireless/ath/ath10k/swap.c | 208 +++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/swap.h | 72 ++++++++ 6 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 drivers/net/wireless/ath/ath10k/swap.c create mode 100644 drivers/net/wireless/ath/ath10k/swap.h diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile index 9729e69416358..c04fb00e79302 100644 --- a/drivers/net/wireless/ath/ath10k/Makefile +++ b/drivers/net/wireless/ath/ath10k/Makefile @@ -11,7 +11,8 @@ ath10k_core-y += mac.o \ wmi-tlv.o \ bmi.o \ hw.o \ - p2p.o + p2p.o \ + swap.o ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index f239e9690831d..c5f5d160deb7a 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -470,6 +470,13 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode) data = ar->firmware_data; data_len = ar->firmware_len; mode_name = "normal"; + ret = ath10k_swap_code_seg_configure(ar, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW); + if (ret) { + ath10k_err(ar, "failed to configure fw code swap: %d\n", + ret); + return ret; + } break; case ATH10K_FIRMWARE_MODE_UTF: data = ar->testmode.utf->data; @@ -509,6 +516,8 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) if (!IS_ERR(ar->cal_file)) release_firmware(ar->cal_file); + ath10k_swap_code_seg_release(ar); + ar->board = NULL; ar->board_data = NULL; ar->board_len = 0; @@ -522,6 +531,7 @@ static void ath10k_core_free_firmware_files(struct ath10k *ar) ar->firmware_len = 0; ar->cal_file = NULL; + } static int ath10k_fetch_cal_file(struct ath10k *ar) @@ -795,6 +805,13 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name) ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n", ar->htt.op_version); break; + case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE: + ath10k_dbg(ar, ATH10K_DBG_BOOT, + "found fw code swap image ie (%zd B)\n", + ie_len); + ar->swap.firmware_codeswap_data = data; + ar->swap.firmware_codeswap_len = ie_len; + break; default: ath10k_warn(ar, "Unknown FW IE: %u\n", le32_to_cpu(hdr->id)); @@ -1388,6 +1405,13 @@ static int ath10k_core_probe_fw(struct ath10k *ar) goto err_free_firmware_files; } + ret = ath10k_swap_code_seg_init(ar); + if (ret) { + ath10k_err(ar, "failed to initialize code swap segment: %d\n", + ret); + goto err_free_firmware_files; + } + mutex_lock(&ar->conf_mutex); ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 993cd362fb0ac..b9145f539aa92 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -36,6 +36,7 @@ #include "spectral.h" #include "thermal.h" #include "wow.h" +#include "swap.h" #define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB) #define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK) @@ -603,6 +604,12 @@ struct ath10k { const struct firmware *cal_file; + struct { + const void *firmware_codeswap_data; + size_t firmware_codeswap_len; + struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info; + } swap; + char spec_board_id[100]; bool spec_board_loaded; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 35cd8caaf7381..3e277814ce93d 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -124,6 +124,9 @@ enum ath10k_fw_ie_type { * FW API 5 and above. */ ATH10K_FW_IE_HTT_OP_VERSION = 6, + + /* Code swap image for firmware binary */ + ATH10K_FW_IE_FW_CODE_SWAP_IMAGE = 7, }; enum ath10k_fw_wmi_op_version { diff --git a/drivers/net/wireless/ath/ath10k/swap.c b/drivers/net/wireless/ath/ath10k/swap.c new file mode 100644 index 0000000000000..3ca3fae408a77 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.c @@ -0,0 +1,208 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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. + */ + +/* This file has implementation for code swap logic. With code swap feature, + * target can run the fw binary with even smaller IRAM size by using host + * memory to store some of the code segments. + */ + +#include "core.h" +#include "bmi.h" +#include "debug.h" + +static int ath10k_swap_code_seg_fill(struct ath10k *ar, + struct ath10k_swap_code_seg_info *seg_info, + const void *data, size_t data_len) +{ + u8 *virt_addr = seg_info->virt_address[0]; + u8 swap_magic[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ] = {}; + const u8 *fw_data = data; + union ath10k_swap_code_seg_item *swap_item; + u32 length = 0; + u32 payload_len; + u32 total_payload_len = 0; + u32 size_left = data_len; + + /* Parse swap bin and copy the content to host allocated memory. + * The format is Address, length and value. The last 4-bytes is + * target write address. Currently address field is not used. + */ + seg_info->target_addr = -1; + while (size_left >= sizeof(*swap_item)) { + swap_item = (union ath10k_swap_code_seg_item *)fw_data; + payload_len = __le32_to_cpu(swap_item->tlv.length); + if ((payload_len > size_left) || + (payload_len == 0 && + size_left != sizeof(struct ath10k_swap_code_seg_tail))) { + ath10k_err(ar, "refusing to parse invalid tlv length %d\n", + payload_len); + return -EINVAL; + } + + if (payload_len == 0) { + if (memcmp(swap_item->tail.magic_signature, swap_magic, + ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ)) { + ath10k_err(ar, "refusing an invalid swap file\n"); + return -EINVAL; + } + seg_info->target_addr = + __le32_to_cpu(swap_item->tail.bmi_write_addr); + break; + } + + memcpy(virt_addr, swap_item->tlv.data, payload_len); + virt_addr += payload_len; + length = payload_len + sizeof(struct ath10k_swap_code_seg_tlv); + size_left -= length; + fw_data += length; + total_payload_len += payload_len; + } + + if (seg_info->target_addr == -1) { + ath10k_err(ar, "failed to parse invalid swap file\n"); + return -EINVAL; + } + seg_info->seg_hw_info.swap_size = __cpu_to_le32(total_payload_len); + + return 0; +} + +static void +ath10k_swap_code_seg_free(struct ath10k *ar, + struct ath10k_swap_code_seg_info *seg_info) +{ + u32 seg_size; + + if (!seg_info) + return; + + if (!seg_info->virt_address[0]) + return; + + seg_size = __le32_to_cpu(seg_info->seg_hw_info.size); + dma_free_coherent(ar->dev, seg_size, seg_info->virt_address[0], + seg_info->paddr[0]); +} + +static struct ath10k_swap_code_seg_info * +ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len) +{ + struct ath10k_swap_code_seg_info *seg_info; + void *virt_addr; + dma_addr_t paddr; + + swap_bin_len = roundup(swap_bin_len, 2); + if (swap_bin_len > ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX) { + ath10k_err(ar, "refusing code swap bin because it is too big %zu > %d\n", + swap_bin_len, ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX); + return NULL; + } + + seg_info = devm_kzalloc(ar->dev, sizeof(*seg_info), GFP_KERNEL); + if (!seg_info) + return NULL; + + virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr, + GFP_KERNEL); + if (!virt_addr) { + ath10k_err(ar, "failed to allocate dma coherent memory\n"); + return NULL; + } + + seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr); + seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len); + seg_info->seg_hw_info.swap_size = __cpu_to_le32(swap_bin_len); + seg_info->seg_hw_info.num_segs = + __cpu_to_le32(ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED); + seg_info->seg_hw_info.size_log2 = __cpu_to_le32(ilog2(swap_bin_len)); + seg_info->virt_address[0] = virt_addr; + seg_info->paddr[0] = paddr; + + return seg_info; +} + +int ath10k_swap_code_seg_configure(struct ath10k *ar, + enum ath10k_swap_code_seg_bin_type type) +{ + int ret; + struct ath10k_swap_code_seg_info *seg_info = NULL; + + switch (type) { + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW: + if (!ar->swap.firmware_swap_code_seg_info) + return 0; + + ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n"); + seg_info = ar->swap.firmware_swap_code_seg_info; + break; + default: + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP: + case ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF: + ath10k_warn(ar, "ignoring unknown code swap binary type %d\n", + type); + return 0; + } + + ret = ath10k_bmi_write_memory(ar, seg_info->target_addr, + &seg_info->seg_hw_info, + sizeof(seg_info->seg_hw_info)); + if (ret) { + ath10k_err(ar, "failed to write Code swap segment information (%d)\n", + ret); + return ret; + } + + return 0; +} + +void ath10k_swap_code_seg_release(struct ath10k *ar) +{ + ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info); + ar->swap.firmware_codeswap_data = NULL; + ar->swap.firmware_codeswap_len = 0; + ar->swap.firmware_swap_code_seg_info = NULL; +} + +int ath10k_swap_code_seg_init(struct ath10k *ar) +{ + int ret; + struct ath10k_swap_code_seg_info *seg_info; + + if (!ar->swap.firmware_codeswap_len || !ar->swap.firmware_codeswap_data) + return 0; + + seg_info = ath10k_swap_code_seg_alloc(ar, + ar->swap.firmware_codeswap_len); + if (!seg_info) { + ath10k_err(ar, "failed to allocate fw code swap segment\n"); + return -ENOMEM; + } + + ret = ath10k_swap_code_seg_fill(ar, seg_info, + ar->swap.firmware_codeswap_data, + ar->swap.firmware_codeswap_len); + + if (ret) { + ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n", + ret); + ath10k_swap_code_seg_free(ar, seg_info); + return ret; + } + + ar->swap.firmware_swap_code_seg_info = seg_info; + + return 0; +} diff --git a/drivers/net/wireless/ath/ath10k/swap.h b/drivers/net/wireless/ath/ath10k/swap.h new file mode 100644 index 0000000000000..5c89952dd20f1 --- /dev/null +++ b/drivers/net/wireless/ath/ath10k/swap.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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 _SWAP_H_ +#define _SWAP_H_ + +#define ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX (512 * 1024) +#define ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ 12 +#define ATH10K_SWAP_CODE_SEG_NUM_MAX 16 +/* Currently only one swap segment is supported */ +#define ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED 1 + +struct ath10k_swap_code_seg_tlv { + __le32 address; + __le32 length; + u8 data[0]; +} __packed; + +struct ath10k_swap_code_seg_tail { + u8 magic_signature[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ]; + __le32 bmi_write_addr; +} __packed; + +union ath10k_swap_code_seg_item { + struct ath10k_swap_code_seg_tlv tlv; + struct ath10k_swap_code_seg_tail tail; +} __packed; + +enum ath10k_swap_code_seg_bin_type { + ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW, + ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF, +}; + +struct ath10k_swap_code_seg_hw_info { + /* Swap binary image size */ + __le32 swap_size; + __le32 num_segs; + + /* Swap data size */ + __le32 size; + __le32 size_log2; + __le32 bus_addr[ATH10K_SWAP_CODE_SEG_NUM_MAX]; + __le64 reserved[ATH10K_SWAP_CODE_SEG_NUM_MAX]; +} __packed; + +struct ath10k_swap_code_seg_info { + struct ath10k_swap_code_seg_hw_info seg_hw_info; + void *virt_address[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; + u32 target_addr; + dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED]; +}; + +int ath10k_swap_code_seg_configure(struct ath10k *ar, + enum ath10k_swap_code_seg_bin_type type); +void ath10k_swap_code_seg_release(struct ath10k *ar); +int ath10k_swap_code_seg_init(struct ath10k *ar); + +#endif -- GitLab From d772703e705961dc4bd280373e3679c8c4f95df7 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Thu, 18 Jun 2015 12:31:10 +0530 Subject: [PATCH 0308/7006] ath10k: Add BMI param value to execute otp to hw_param BMI parameter value to execute downloaded otp binary is different for QCA99X0. Have a member in hw_params to hold hw specific BMI param. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 8 +++++++- drivers/net/wireless/ath/ath10k/core.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index c5f5d160deb7a..80f38b50296bd 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -49,6 +49,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .has_shifted_cc_wraparound = true, + .otp_exe_param = 0, .fw = { .dir = QCA988X_HW_2_0_FW_DIR, .fw = QCA988X_HW_2_0_FW_FILE, @@ -63,6 +64,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw2.1", .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { .dir = QCA6174_HW_2_1_FW_DIR, .fw = QCA6174_HW_2_1_FW_FILE, @@ -77,6 +79,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.0", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { .dir = QCA6174_HW_3_0_FW_DIR, .fw = QCA6174_HW_3_0_FW_FILE, @@ -91,6 +94,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca6174 hw3.2", .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR, .uart_pin = 6, + .otp_exe_param = 0, .fw = { /* uses same binaries as hw3.0 */ .dir = QCA6174_HW_3_0_FW_DIR, @@ -106,6 +110,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .name = "qca99x0 hw2.0", .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, + .otp_exe_param = 0x00000700, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, @@ -413,6 +418,7 @@ out: static int ath10k_download_and_run_otp(struct ath10k *ar) { u32 result, address = ar->hw_params.patch_load_addr; + u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param; int ret; ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len); @@ -438,7 +444,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar) return ret; } - ret = ath10k_bmi_execute(ar, address, 0, &result); + ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result); if (ret) { ath10k_err(ar, "could not execute otp (%d)\n", ret); return ret; diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index b9145f539aa92..afd21d5b25ae3 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -572,6 +572,7 @@ struct ath10k { const char *name; u32 patch_load_addr; int uart_pin; + u32 otp_exe_param; /* This is true if given HW chip has a quirky Cycle Counter * wraparound which resets to 0x7fffffff instead of 0. All -- GitLab From 9bd213224654b8c13af8bffcf9bd07ee0baae5ef Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:09 +0530 Subject: [PATCH 0309/7006] ath10k: include new wmi op version for 10.4 fw qca99X0 chip uses firmware version 10.4. Define a new macro ATH10K_FW_WMI_OP_VERSION_10_4 for 10.4 firmware and include in switch cases where ATH10K_FW_WMI_OP_VERSION_* is used to avoid compilation error. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 2 ++ drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 2 ++ drivers/net/wireless/ath/ath10k/wmi.c | 2 ++ 4 files changed, 7 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 80f38b50296bd..5e8d8af5d0d07 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1115,6 +1115,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; break; + case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); @@ -1137,6 +1138,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_TLV: ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV; break; + case ATH10K_FW_WMI_OP_VERSION_10_4: case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 3e277814ce93d..b0c89b48092da 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -137,6 +137,7 @@ enum ath10k_fw_wmi_op_version { ATH10K_FW_WMI_OP_VERSION_10_2 = 3, ATH10K_FW_WMI_OP_VERSION_TLV = 4, ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5, + ATH10K_FW_WMI_OP_VERSION_10_4 = 6, /* keep last */ ATH10K_FW_WMI_OP_VERSION_MAX, diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index e17eb75c508ef..a8561d1f26e3f 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6943,6 +6943,8 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->wiphy->n_iface_combinations = ARRAY_SIZE(ath10k_10x_if_comb); break; + case ATH10K_FW_WMI_OP_VERSION_10_4: + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c046c244705f..b32bb6825f3c4 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5415,6 +5415,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { + case ATH10K_FW_WMI_OP_VERSION_10_4: + break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; ar->wmi.ops = &wmi_10_2_4_ops; -- GitLab From 840357ccc365b650d2321a5690cb5374192619ca Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:10 +0530 Subject: [PATCH 0310/7006] ath10k: add 10.4 fw wmi service bitmap definition Include new enum to define wmi service bitmap definitions for 10.4 firmware and a function wmi_10_4_svc_map() to remap 10.4 firmware wmi service bitmap definitions to ath10k generic wmi services. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 5 + drivers/net/wireless/ath/ath10k/wmi.h | 146 ++++++++++++++++++++++++++ 2 files changed, 151 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index b32bb6825f3c4..52493d14c9b0e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5412,10 +5412,15 @@ static const struct wmi_ops wmi_10_2_4_ops = { /* .gen_adaptive_qcs not implemented */ }; +static const struct wmi_ops wmi_10_4_ops = { + .map_svc = wmi_10_4_svc_map, +}; + int ath10k_wmi_attach(struct ath10k *ar) { switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->wmi.ops = &wmi_10_4_ops; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index cf44a3d080a38..b54d14b008199 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -150,6 +150,12 @@ enum wmi_service { WMI_SERVICE_SAP_AUTH_OFFLOAD, WMI_SERVICE_ATF, WMI_SERVICE_COEX_GPIO, + WMI_SERVICE_ENHANCED_PROXY_STA, + WMI_SERVICE_TT, + WMI_SERVICE_PEER_CACHING, + WMI_SERVICE_AUX_SPECTRAL_INTF, + WMI_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_SERVICE_BSS_CHANNEL_INFO_64, /* keep last */ WMI_SERVICE_MAX, @@ -218,6 +224,51 @@ enum wmi_main_service { WMI_MAIN_SERVICE_TX_ENCAP, }; +enum wmi_10_4_service { + WMI_10_4_SERVICE_BEACON_OFFLOAD = 0, + WMI_10_4_SERVICE_SCAN_OFFLOAD, + WMI_10_4_SERVICE_ROAM_OFFLOAD, + WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, + WMI_10_4_SERVICE_STA_PWRSAVE, + WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_10_4_SERVICE_AP_UAPSD, + WMI_10_4_SERVICE_AP_DFS, + WMI_10_4_SERVICE_11AC, + WMI_10_4_SERVICE_BLOCKACK, + WMI_10_4_SERVICE_PHYERR, + WMI_10_4_SERVICE_BCN_FILTER, + WMI_10_4_SERVICE_RTT, + WMI_10_4_SERVICE_RATECTRL, + WMI_10_4_SERVICE_WOW, + WMI_10_4_SERVICE_RATECTRL_CACHE, + WMI_10_4_SERVICE_IRAM_TIDS, + WMI_10_4_SERVICE_BURST, + WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_10_4_SERVICE_GTK_OFFLOAD, + WMI_10_4_SERVICE_SCAN_SCH, + WMI_10_4_SERVICE_CSA_OFFLOAD, + WMI_10_4_SERVICE_CHATTER, + WMI_10_4_SERVICE_COEX_FREQAVOID, + WMI_10_4_SERVICE_PACKET_POWER_SAVE, + WMI_10_4_SERVICE_FORCE_FW_HANG, + WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_10_4_SERVICE_GPIO, + WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_10_4_SERVICE_STA_KEEP_ALIVE, + WMI_10_4_SERVICE_TX_ENCAP, + WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_10_4_SERVICE_EARLY_RX, + WMI_10_4_SERVICE_ENHANCED_PROXY_STA, + WMI_10_4_SERVICE_TT, + WMI_10_4_SERVICE_ATF, + WMI_10_4_SERVICE_PEER_CACHING, + WMI_10_4_SERVICE_COEX_GPIO, + WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, + WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, +}; + static inline char *wmi_service_name(int service_id) { #define SVCSTR(x) case x: return #x @@ -299,6 +350,12 @@ static inline char *wmi_service_name(int service_id) SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD); SVCSTR(WMI_SERVICE_ATF); SVCSTR(WMI_SERVICE_COEX_GPIO); + SVCSTR(WMI_SERVICE_ENHANCED_PROXY_STA); + SVCSTR(WMI_SERVICE_TT); + SVCSTR(WMI_SERVICE_PEER_CACHING); + SVCSTR(WMI_SERVICE_AUX_SPECTRAL_INTF); + SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF); + SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64); default: return NULL; } @@ -437,6 +494,95 @@ static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out, WMI_SERVICE_TX_ENCAP, len); } +static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out, + size_t len) +{ + SVCMAP(WMI_10_4_SERVICE_BEACON_OFFLOAD, + WMI_SERVICE_BEACON_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_SCAN_OFFLOAD, + WMI_SERVICE_SCAN_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_ROAM_OFFLOAD, + WMI_SERVICE_ROAM_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_BCN_MISS_OFFLOAD, + WMI_SERVICE_BCN_MISS_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_STA_PWRSAVE, + WMI_SERVICE_STA_PWRSAVE, len); + SVCMAP(WMI_10_4_SERVICE_STA_ADVANCED_PWRSAVE, + WMI_SERVICE_STA_ADVANCED_PWRSAVE, len); + SVCMAP(WMI_10_4_SERVICE_AP_UAPSD, + WMI_SERVICE_AP_UAPSD, len); + SVCMAP(WMI_10_4_SERVICE_AP_DFS, + WMI_SERVICE_AP_DFS, len); + SVCMAP(WMI_10_4_SERVICE_11AC, + WMI_SERVICE_11AC, len); + SVCMAP(WMI_10_4_SERVICE_BLOCKACK, + WMI_SERVICE_BLOCKACK, len); + SVCMAP(WMI_10_4_SERVICE_PHYERR, + WMI_SERVICE_PHYERR, len); + SVCMAP(WMI_10_4_SERVICE_BCN_FILTER, + WMI_SERVICE_BCN_FILTER, len); + SVCMAP(WMI_10_4_SERVICE_RTT, + WMI_SERVICE_RTT, len); + SVCMAP(WMI_10_4_SERVICE_RATECTRL, + WMI_SERVICE_RATECTRL, len); + SVCMAP(WMI_10_4_SERVICE_WOW, + WMI_SERVICE_WOW, len); + SVCMAP(WMI_10_4_SERVICE_RATECTRL_CACHE, + WMI_SERVICE_RATECTRL_CACHE, len); + SVCMAP(WMI_10_4_SERVICE_IRAM_TIDS, + WMI_SERVICE_IRAM_TIDS, len); + SVCMAP(WMI_10_4_SERVICE_BURST, + WMI_SERVICE_BURST, len); + SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_SW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_GTK_OFFLOAD, + WMI_SERVICE_GTK_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_SCAN_SCH, + WMI_SERVICE_SCAN_SCH, len); + SVCMAP(WMI_10_4_SERVICE_CSA_OFFLOAD, + WMI_SERVICE_CSA_OFFLOAD, len); + SVCMAP(WMI_10_4_SERVICE_CHATTER, + WMI_SERVICE_CHATTER, len); + SVCMAP(WMI_10_4_SERVICE_COEX_FREQAVOID, + WMI_SERVICE_COEX_FREQAVOID, len); + SVCMAP(WMI_10_4_SERVICE_PACKET_POWER_SAVE, + WMI_SERVICE_PACKET_POWER_SAVE, len); + SVCMAP(WMI_10_4_SERVICE_FORCE_FW_HANG, + WMI_SERVICE_FORCE_FW_HANG, len); + SVCMAP(WMI_10_4_SERVICE_SMART_ANTENNA_HW_SUPPORT, + WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT, len); + SVCMAP(WMI_10_4_SERVICE_GPIO, + WMI_SERVICE_GPIO, len); + SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len); + SVCMAP(WMI_10_4_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, + WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len); + SVCMAP(WMI_10_4_SERVICE_STA_KEEP_ALIVE, + WMI_SERVICE_STA_KEEP_ALIVE, len); + SVCMAP(WMI_10_4_SERVICE_TX_ENCAP, + WMI_SERVICE_TX_ENCAP, len); + SVCMAP(WMI_10_4_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, + WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len); + SVCMAP(WMI_10_4_SERVICE_EARLY_RX, + WMI_SERVICE_EARLY_RX, len); + SVCMAP(WMI_10_4_SERVICE_ENHANCED_PROXY_STA, + WMI_SERVICE_ENHANCED_PROXY_STA, len); + SVCMAP(WMI_10_4_SERVICE_TT, + WMI_SERVICE_TT, len); + SVCMAP(WMI_10_4_SERVICE_ATF, + WMI_SERVICE_ATF, len); + SVCMAP(WMI_10_4_SERVICE_PEER_CACHING, + WMI_SERVICE_PEER_CACHING, len); + SVCMAP(WMI_10_4_SERVICE_COEX_GPIO, + WMI_SERVICE_COEX_GPIO, len); + SVCMAP(WMI_10_4_SERVICE_AUX_SPECTRAL_INTF, + WMI_SERVICE_AUX_SPECTRAL_INTF, len); + SVCMAP(WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF, + WMI_SERVICE_AUX_CHAN_LOAD_INTF, len); + SVCMAP(WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64, + WMI_SERVICE_BSS_CHANNEL_INFO_64, len); +} + #undef SVCMAP /* 2 word representation of MAC addr */ -- GitLab From 2d491e69962a94bbeb0449a060cca2d156f943e9 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:11 +0530 Subject: [PATCH 0311/7006] ath10k: include 10.4 fw specific wmi cmd and event ids 10.4 firmware wmi cmd and event id values are not exactly aligned with previous firmware versions (main, 10.x, 10.2, etc). Add new enum to define wmi cmd & event definitions for 10.4 firmware and prepare wmi_10_4_cmd_map based on 10.4 firmware wmi cmd definitions. wmi_cmd_map is extended to accommodate new wmi commands which are exclusively available in 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 184 +++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 252 ++++++++++++++++++++++++++ 2 files changed, 436 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 52493d14c9b0e..8dc937de98ab6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -395,6 +395,189 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, }; +/* 10.4 WMI cmd track */ +static struct wmi_cmd_map wmi_10_4_cmd_map = { + .init_cmdid = WMI_10_4_INIT_CMDID, + .start_scan_cmdid = WMI_10_4_START_SCAN_CMDID, + .stop_scan_cmdid = WMI_10_4_STOP_SCAN_CMDID, + .scan_chan_list_cmdid = WMI_10_4_SCAN_CHAN_LIST_CMDID, + .scan_sch_prio_tbl_cmdid = WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + .pdev_set_regdomain_cmdid = WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, + .pdev_set_channel_cmdid = WMI_10_4_PDEV_SET_CHANNEL_CMDID, + .pdev_set_param_cmdid = WMI_10_4_PDEV_SET_PARAM_CMDID, + .pdev_pktlog_enable_cmdid = WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, + .pdev_pktlog_disable_cmdid = WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, + .pdev_set_wmm_params_cmdid = WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, + .pdev_set_ht_cap_ie_cmdid = WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, + .pdev_set_vht_cap_ie_cmdid = WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, + .pdev_set_dscp_tid_map_cmdid = WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_set_quiet_mode_cmdid = WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, + .pdev_green_ap_ps_enable_cmdid = WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, + .pdev_get_tpc_config_cmdid = WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, + .pdev_set_base_macaddr_cmdid = WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, + .vdev_create_cmdid = WMI_10_4_VDEV_CREATE_CMDID, + .vdev_delete_cmdid = WMI_10_4_VDEV_DELETE_CMDID, + .vdev_start_request_cmdid = WMI_10_4_VDEV_START_REQUEST_CMDID, + .vdev_restart_request_cmdid = WMI_10_4_VDEV_RESTART_REQUEST_CMDID, + .vdev_up_cmdid = WMI_10_4_VDEV_UP_CMDID, + .vdev_stop_cmdid = WMI_10_4_VDEV_STOP_CMDID, + .vdev_down_cmdid = WMI_10_4_VDEV_DOWN_CMDID, + .vdev_set_param_cmdid = WMI_10_4_VDEV_SET_PARAM_CMDID, + .vdev_install_key_cmdid = WMI_10_4_VDEV_INSTALL_KEY_CMDID, + .peer_create_cmdid = WMI_10_4_PEER_CREATE_CMDID, + .peer_delete_cmdid = WMI_10_4_PEER_DELETE_CMDID, + .peer_flush_tids_cmdid = WMI_10_4_PEER_FLUSH_TIDS_CMDID, + .peer_set_param_cmdid = WMI_10_4_PEER_SET_PARAM_CMDID, + .peer_assoc_cmdid = WMI_10_4_PEER_ASSOC_CMDID, + .peer_add_wds_entry_cmdid = WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, + .peer_remove_wds_entry_cmdid = WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, + .peer_mcast_group_cmdid = WMI_10_4_PEER_MCAST_GROUP_CMDID, + .bcn_tx_cmdid = WMI_10_4_BCN_TX_CMDID, + .pdev_send_bcn_cmdid = WMI_10_4_PDEV_SEND_BCN_CMDID, + .bcn_tmpl_cmdid = WMI_10_4_BCN_PRB_TMPL_CMDID, + .bcn_filter_rx_cmdid = WMI_10_4_BCN_FILTER_RX_CMDID, + .prb_req_filter_rx_cmdid = WMI_10_4_PRB_REQ_FILTER_RX_CMDID, + .mgmt_tx_cmdid = WMI_10_4_MGMT_TX_CMDID, + .prb_tmpl_cmdid = WMI_10_4_PRB_TMPL_CMDID, + .addba_clear_resp_cmdid = WMI_10_4_ADDBA_CLEAR_RESP_CMDID, + .addba_send_cmdid = WMI_10_4_ADDBA_SEND_CMDID, + .addba_status_cmdid = WMI_10_4_ADDBA_STATUS_CMDID, + .delba_send_cmdid = WMI_10_4_DELBA_SEND_CMDID, + .addba_set_resp_cmdid = WMI_10_4_ADDBA_SET_RESP_CMDID, + .send_singleamsdu_cmdid = WMI_10_4_SEND_SINGLEAMSDU_CMDID, + .sta_powersave_mode_cmdid = WMI_10_4_STA_POWERSAVE_MODE_CMDID, + .sta_powersave_param_cmdid = WMI_10_4_STA_POWERSAVE_PARAM_CMDID, + .sta_mimo_ps_mode_cmdid = WMI_10_4_STA_MIMO_PS_MODE_CMDID, + .pdev_dfs_enable_cmdid = WMI_10_4_PDEV_DFS_ENABLE_CMDID, + .pdev_dfs_disable_cmdid = WMI_10_4_PDEV_DFS_DISABLE_CMDID, + .roam_scan_mode = WMI_10_4_ROAM_SCAN_MODE, + .roam_scan_rssi_threshold = WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, + .roam_scan_period = WMI_10_4_ROAM_SCAN_PERIOD, + .roam_scan_rssi_change_threshold = + WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + .roam_ap_profile = WMI_10_4_ROAM_AP_PROFILE, + .ofl_scan_add_ap_profile = WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, + .ofl_scan_remove_ap_profile = WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, + .ofl_scan_period = WMI_10_4_OFL_SCAN_PERIOD, + .p2p_dev_set_device_info = WMI_10_4_P2P_DEV_SET_DEVICE_INFO, + .p2p_dev_set_discoverability = WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, + .p2p_go_set_beacon_ie = WMI_10_4_P2P_GO_SET_BEACON_IE, + .p2p_go_set_probe_resp_ie = WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, + .p2p_set_vendor_ie_data_cmdid = WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, + .ap_ps_peer_param_cmdid = WMI_10_4_AP_PS_PEER_PARAM_CMDID, + .ap_ps_peer_uapsd_coex_cmdid = WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, + .peer_rate_retry_sched_cmdid = WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, + .wlan_profile_trigger_cmdid = WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, + .wlan_profile_set_hist_intvl_cmdid = + WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + .wlan_profile_get_profile_data_cmdid = + WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + .wlan_profile_enable_profile_id_cmdid = + WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + .wlan_profile_list_profile_id_cmdid = + WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + .pdev_suspend_cmdid = WMI_10_4_PDEV_SUSPEND_CMDID, + .pdev_resume_cmdid = WMI_10_4_PDEV_RESUME_CMDID, + .add_bcn_filter_cmdid = WMI_10_4_ADD_BCN_FILTER_CMDID, + .rmv_bcn_filter_cmdid = WMI_10_4_RMV_BCN_FILTER_CMDID, + .wow_add_wake_pattern_cmdid = WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, + .wow_del_wake_pattern_cmdid = WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, + .wow_enable_disable_wake_event_cmdid = + WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + .wow_enable_cmdid = WMI_10_4_WOW_ENABLE_CMDID, + .wow_hostwakeup_from_sleep_cmdid = + WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + .rtt_measreq_cmdid = WMI_10_4_RTT_MEASREQ_CMDID, + .rtt_tsf_cmdid = WMI_10_4_RTT_TSF_CMDID, + .vdev_spectral_scan_configure_cmdid = + WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + .vdev_spectral_scan_enable_cmdid = + WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + .request_stats_cmdid = WMI_10_4_REQUEST_STATS_CMDID, + .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED, + .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED, + .gtk_offload_cmdid = WMI_10_4_GTK_OFFLOAD_CMDID, + .csa_offload_enable_cmdid = WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, + .csa_offload_chanswitch_cmdid = WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, + .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED, + .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED, + .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED, + .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED, + .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED, + .echo_cmdid = WMI_10_4_ECHO_CMDID, + .pdev_utf_cmdid = WMI_10_4_PDEV_UTF_CMDID, + .dbglog_cfg_cmdid = WMI_10_4_DBGLOG_CFG_CMDID, + .pdev_qvit_cmdid = WMI_10_4_PDEV_QVIT_CMDID, + .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_keepalive_cmdid = WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, + .vdev_get_keepalive_cmdid = WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, + .force_fw_hang_cmdid = WMI_10_4_FORCE_FW_HANG_CMDID, + .gpio_config_cmdid = WMI_10_4_GPIO_CONFIG_CMDID, + .gpio_output_cmdid = WMI_10_4_GPIO_OUTPUT_CMDID, + .pdev_get_temperature_cmdid = WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, + .vdev_set_wmm_params_cmdid = WMI_CMD_UNSUPPORTED, + .tdls_set_state_cmdid = WMI_CMD_UNSUPPORTED, + .tdls_peer_update_cmdid = WMI_CMD_UNSUPPORTED, + .adaptive_qcs_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, + .vdev_standby_response_cmdid = WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, + .vdev_resume_response_cmdid = WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, + .wlan_peer_caching_add_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, + .wlan_peer_caching_evict_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, + .wlan_peer_caching_restore_peer_cmdid = + WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, + .wlan_peer_caching_print_all_peers_info_cmdid = + WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, + .peer_update_wds_entry_cmdid = WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, + .peer_add_proxy_sta_entry_cmdid = + WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, + .rtt_keepalive_cmdid = WMI_10_4_RTT_KEEPALIVE_CMDID, + .oem_req_cmdid = WMI_10_4_OEM_REQ_CMDID, + .nan_cmdid = WMI_10_4_NAN_CMDID, + .vdev_ratemask_cmdid = WMI_10_4_VDEV_RATEMASK_CMDID, + .qboost_cfg_cmdid = WMI_10_4_QBOOST_CFG_CMDID, + .pdev_smart_ant_enable_cmdid = WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, + .pdev_smart_ant_set_rx_antenna_cmdid = + WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + .peer_smart_ant_set_tx_antenna_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + .peer_smart_ant_set_train_info_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + .peer_smart_ant_set_node_config_ops_cmdid = + WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + .pdev_set_antenna_switch_table_cmdid = + WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + .pdev_set_ctl_table_cmdid = WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, + .pdev_set_mimogain_table_cmdid = WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, + .pdev_ratepwr_table_cmdid = WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, + .pdev_ratepwr_chainmsk_table_cmdid = + WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + .pdev_fips_cmdid = WMI_10_4_PDEV_FIPS_CMDID, + .tt_set_conf_cmdid = WMI_10_4_TT_SET_CONF_CMDID, + .fwtest_cmdid = WMI_10_4_FWTEST_CMDID, + .vdev_atf_request_cmdid = WMI_10_4_VDEV_ATF_REQUEST_CMDID, + .peer_atf_request_cmdid = WMI_10_4_PEER_ATF_REQUEST_CMDID, + .pdev_get_ani_cck_config_cmdid = WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, + .pdev_get_ani_ofdm_config_cmdid = + WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + .pdev_reserve_ast_entry_cmdid = WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, + .pdev_get_nfcal_power_cmdid = WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, + .pdev_get_tpc_cmdid = WMI_10_4_PDEV_GET_TPC_CMDID, + .pdev_get_ast_info_cmdid = WMI_10_4_PDEV_GET_AST_INFO_CMDID, + .vdev_set_dscp_tid_map_cmdid = WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, + .pdev_get_info_cmdid = WMI_10_4_PDEV_GET_INFO_CMDID, + .vdev_get_info_cmdid = WMI_10_4_VDEV_GET_INFO_CMDID, + .vdev_filter_neighbor_rx_packets_cmdid = + WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + .mu_cal_start_cmdid = WMI_10_4_MU_CAL_START_CMDID, + .set_cca_params_cmdid = WMI_10_4_SET_CCA_PARAMS_CMDID, + .pdev_bss_chan_info_request_cmdid = + WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, +}; + /* MAIN WMI VDEV param map */ static struct wmi_vdev_param_map wmi_vdev_param_map = { .rts_threshold = WMI_VDEV_PARAM_RTS_THRESHOLD, @@ -5421,6 +5604,7 @@ int ath10k_wmi_attach(struct ath10k *ar) switch (ar->wmi.op_version) { case ATH10K_FW_WMI_OP_VERSION_10_4: ar->wmi.ops = &wmi_10_4_ops; + ar->wmi.cmd = &wmi_10_4_cmd_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b54d14b008199..c3a05a9a05aed 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -711,6 +711,48 @@ struct wmi_cmd_map { u32 tdls_set_state_cmdid; u32 tdls_peer_update_cmdid; u32 adaptive_qcs_cmdid; + u32 scan_update_request_cmdid; + u32 vdev_standby_response_cmdid; + u32 vdev_resume_response_cmdid; + u32 wlan_peer_caching_add_peer_cmdid; + u32 wlan_peer_caching_evict_peer_cmdid; + u32 wlan_peer_caching_restore_peer_cmdid; + u32 wlan_peer_caching_print_all_peers_info_cmdid; + u32 peer_update_wds_entry_cmdid; + u32 peer_add_proxy_sta_entry_cmdid; + u32 rtt_keepalive_cmdid; + u32 oem_req_cmdid; + u32 nan_cmdid; + u32 vdev_ratemask_cmdid; + u32 qboost_cfg_cmdid; + u32 pdev_smart_ant_enable_cmdid; + u32 pdev_smart_ant_set_rx_antenna_cmdid; + u32 peer_smart_ant_set_tx_antenna_cmdid; + u32 peer_smart_ant_set_train_info_cmdid; + u32 peer_smart_ant_set_node_config_ops_cmdid; + u32 pdev_set_antenna_switch_table_cmdid; + u32 pdev_set_ctl_table_cmdid; + u32 pdev_set_mimogain_table_cmdid; + u32 pdev_ratepwr_table_cmdid; + u32 pdev_ratepwr_chainmsk_table_cmdid; + u32 pdev_fips_cmdid; + u32 tt_set_conf_cmdid; + u32 fwtest_cmdid; + u32 vdev_atf_request_cmdid; + u32 peer_atf_request_cmdid; + u32 pdev_get_ani_cck_config_cmdid; + u32 pdev_get_ani_ofdm_config_cmdid; + u32 pdev_reserve_ast_entry_cmdid; + u32 pdev_get_nfcal_power_cmdid; + u32 pdev_get_tpc_cmdid; + u32 pdev_get_ast_info_cmdid; + u32 vdev_set_dscp_tid_map_cmdid; + u32 pdev_get_info_cmdid; + u32 vdev_get_info_cmdid; + u32 vdev_filter_neighbor_rx_packets_cmdid; + u32 mu_cal_start_cmdid; + u32 set_cca_params_cmdid; + u32 pdev_bss_chan_info_request_cmdid; }; /* @@ -1366,6 +1408,216 @@ enum wmi_10_2_event_id { WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1, }; +enum wmi_10_4_cmd_id { + WMI_10_4_START_CMDID = 0x9000, + WMI_10_4_END_CMDID = 0x9FFF, + WMI_10_4_INIT_CMDID, + WMI_10_4_START_SCAN_CMDID = WMI_10_4_START_CMDID, + WMI_10_4_STOP_SCAN_CMDID, + WMI_10_4_SCAN_CHAN_LIST_CMDID, + WMI_10_4_SCAN_SCH_PRIO_TBL_CMDID, + WMI_10_4_SCAN_UPDATE_REQUEST_CMDID, + WMI_10_4_ECHO_CMDID, + WMI_10_4_PDEV_SET_REGDOMAIN_CMDID, + WMI_10_4_PDEV_SET_CHANNEL_CMDID, + WMI_10_4_PDEV_SET_PARAM_CMDID, + WMI_10_4_PDEV_PKTLOG_ENABLE_CMDID, + WMI_10_4_PDEV_PKTLOG_DISABLE_CMDID, + WMI_10_4_PDEV_SET_WMM_PARAMS_CMDID, + WMI_10_4_PDEV_SET_HT_CAP_IE_CMDID, + WMI_10_4_PDEV_SET_VHT_CAP_IE_CMDID, + WMI_10_4_PDEV_SET_BASE_MACADDR_CMDID, + WMI_10_4_PDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_4_PDEV_SET_QUIET_MODE_CMDID, + WMI_10_4_PDEV_GREEN_AP_PS_ENABLE_CMDID, + WMI_10_4_PDEV_GET_TPC_CONFIG_CMDID, + WMI_10_4_VDEV_CREATE_CMDID, + WMI_10_4_VDEV_DELETE_CMDID, + WMI_10_4_VDEV_START_REQUEST_CMDID, + WMI_10_4_VDEV_RESTART_REQUEST_CMDID, + WMI_10_4_VDEV_UP_CMDID, + WMI_10_4_VDEV_STOP_CMDID, + WMI_10_4_VDEV_DOWN_CMDID, + WMI_10_4_VDEV_STANDBY_RESPONSE_CMDID, + WMI_10_4_VDEV_RESUME_RESPONSE_CMDID, + WMI_10_4_VDEV_SET_PARAM_CMDID, + WMI_10_4_VDEV_INSTALL_KEY_CMDID, + WMI_10_4_WLAN_PEER_CACHING_ADD_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_EVICT_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_RESTORE_PEER_CMDID, + WMI_10_4_WLAN_PEER_CACHING_PRINT_ALL_PEERS_INFO_CMDID, + WMI_10_4_PEER_CREATE_CMDID, + WMI_10_4_PEER_DELETE_CMDID, + WMI_10_4_PEER_FLUSH_TIDS_CMDID, + WMI_10_4_PEER_SET_PARAM_CMDID, + WMI_10_4_PEER_ASSOC_CMDID, + WMI_10_4_PEER_ADD_WDS_ENTRY_CMDID, + WMI_10_4_PEER_UPDATE_WDS_ENTRY_CMDID, + WMI_10_4_PEER_REMOVE_WDS_ENTRY_CMDID, + WMI_10_4_PEER_ADD_PROXY_STA_ENTRY_CMDID, + WMI_10_4_PEER_MCAST_GROUP_CMDID, + WMI_10_4_BCN_TX_CMDID, + WMI_10_4_PDEV_SEND_BCN_CMDID, + WMI_10_4_BCN_PRB_TMPL_CMDID, + WMI_10_4_BCN_FILTER_RX_CMDID, + WMI_10_4_PRB_REQ_FILTER_RX_CMDID, + WMI_10_4_MGMT_TX_CMDID, + WMI_10_4_PRB_TMPL_CMDID, + WMI_10_4_ADDBA_CLEAR_RESP_CMDID, + WMI_10_4_ADDBA_SEND_CMDID, + WMI_10_4_ADDBA_STATUS_CMDID, + WMI_10_4_DELBA_SEND_CMDID, + WMI_10_4_ADDBA_SET_RESP_CMDID, + WMI_10_4_SEND_SINGLEAMSDU_CMDID, + WMI_10_4_STA_POWERSAVE_MODE_CMDID, + WMI_10_4_STA_POWERSAVE_PARAM_CMDID, + WMI_10_4_STA_MIMO_PS_MODE_CMDID, + WMI_10_4_DBGLOG_CFG_CMDID, + WMI_10_4_PDEV_DFS_ENABLE_CMDID, + WMI_10_4_PDEV_DFS_DISABLE_CMDID, + WMI_10_4_PDEV_QVIT_CMDID, + WMI_10_4_ROAM_SCAN_MODE, + WMI_10_4_ROAM_SCAN_RSSI_THRESHOLD, + WMI_10_4_ROAM_SCAN_PERIOD, + WMI_10_4_ROAM_SCAN_RSSI_CHANGE_THRESHOLD, + WMI_10_4_ROAM_AP_PROFILE, + WMI_10_4_OFL_SCAN_ADD_AP_PROFILE, + WMI_10_4_OFL_SCAN_REMOVE_AP_PROFILE, + WMI_10_4_OFL_SCAN_PERIOD, + WMI_10_4_P2P_DEV_SET_DEVICE_INFO, + WMI_10_4_P2P_DEV_SET_DISCOVERABILITY, + WMI_10_4_P2P_GO_SET_BEACON_IE, + WMI_10_4_P2P_GO_SET_PROBE_RESP_IE, + WMI_10_4_P2P_SET_VENDOR_IE_DATA_CMDID, + WMI_10_4_AP_PS_PEER_PARAM_CMDID, + WMI_10_4_AP_PS_PEER_UAPSD_COEX_CMDID, + WMI_10_4_PEER_RATE_RETRY_SCHED_CMDID, + WMI_10_4_WLAN_PROFILE_TRIGGER_CMDID, + WMI_10_4_WLAN_PROFILE_SET_HIST_INTVL_CMDID, + WMI_10_4_WLAN_PROFILE_GET_PROFILE_DATA_CMDID, + WMI_10_4_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID, + WMI_10_4_WLAN_PROFILE_LIST_PROFILE_ID_CMDID, + WMI_10_4_PDEV_SUSPEND_CMDID, + WMI_10_4_PDEV_RESUME_CMDID, + WMI_10_4_ADD_BCN_FILTER_CMDID, + WMI_10_4_RMV_BCN_FILTER_CMDID, + WMI_10_4_WOW_ADD_WAKE_PATTERN_CMDID, + WMI_10_4_WOW_DEL_WAKE_PATTERN_CMDID, + WMI_10_4_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID, + WMI_10_4_WOW_ENABLE_CMDID, + WMI_10_4_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID, + WMI_10_4_RTT_MEASREQ_CMDID, + WMI_10_4_RTT_TSF_CMDID, + WMI_10_4_RTT_KEEPALIVE_CMDID, + WMI_10_4_OEM_REQ_CMDID, + WMI_10_4_NAN_CMDID, + WMI_10_4_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID, + WMI_10_4_VDEV_SPECTRAL_SCAN_ENABLE_CMDID, + WMI_10_4_REQUEST_STATS_CMDID, + WMI_10_4_GPIO_CONFIG_CMDID, + WMI_10_4_GPIO_OUTPUT_CMDID, + WMI_10_4_VDEV_RATEMASK_CMDID, + WMI_10_4_CSA_OFFLOAD_ENABLE_CMDID, + WMI_10_4_GTK_OFFLOAD_CMDID, + WMI_10_4_QBOOST_CFG_CMDID, + WMI_10_4_CSA_OFFLOAD_CHANSWITCH_CMDID, + WMI_10_4_PDEV_SMART_ANT_ENABLE_CMDID, + WMI_10_4_PDEV_SMART_ANT_SET_RX_ANTENNA_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_TX_ANTENNA_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_TRAIN_INFO_CMDID, + WMI_10_4_PEER_SMART_ANT_SET_NODE_CONFIG_OPS_CMDID, + WMI_10_4_VDEV_SET_KEEPALIVE_CMDID, + WMI_10_4_VDEV_GET_KEEPALIVE_CMDID, + WMI_10_4_FORCE_FW_HANG_CMDID, + WMI_10_4_PDEV_SET_ANTENNA_SWITCH_TABLE_CMDID, + WMI_10_4_PDEV_SET_CTL_TABLE_CMDID, + WMI_10_4_PDEV_SET_MIMOGAIN_TABLE_CMDID, + WMI_10_4_PDEV_RATEPWR_TABLE_CMDID, + WMI_10_4_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID, + WMI_10_4_PDEV_FIPS_CMDID, + WMI_10_4_TT_SET_CONF_CMDID, + WMI_10_4_FWTEST_CMDID, + WMI_10_4_VDEV_ATF_REQUEST_CMDID, + WMI_10_4_PEER_ATF_REQUEST_CMDID, + WMI_10_4_PDEV_GET_ANI_CCK_CONFIG_CMDID, + WMI_10_4_PDEV_GET_ANI_OFDM_CONFIG_CMDID, + WMI_10_4_PDEV_RESERVE_AST_ENTRY_CMDID, + WMI_10_4_PDEV_GET_NFCAL_POWER_CMDID, + WMI_10_4_PDEV_GET_TPC_CMDID, + WMI_10_4_PDEV_GET_AST_INFO_CMDID, + WMI_10_4_VDEV_SET_DSCP_TID_MAP_CMDID, + WMI_10_4_PDEV_GET_TEMPERATURE_CMDID, + WMI_10_4_PDEV_GET_INFO_CMDID, + WMI_10_4_VDEV_GET_INFO_CMDID, + WMI_10_4_VDEV_FILTER_NEIGHBOR_RX_PACKETS_CMDID, + WMI_10_4_MU_CAL_START_CMDID, + WMI_10_4_SET_CCA_PARAMS_CMDID, + WMI_10_4_PDEV_BSS_CHAN_INFO_REQUEST_CMDID, + WMI_10_4_PDEV_UTF_CMDID = WMI_10_4_END_CMDID - 1, +}; + +enum wmi_10_4_event_id { + WMI_10_4_SERVICE_READY_EVENTID = 0x8000, + WMI_10_4_READY_EVENTID, + WMI_10_4_DEBUG_MESG_EVENTID, + WMI_10_4_START_EVENTID = 0x9000, + WMI_10_4_END_EVENTID = 0x9FFF, + WMI_10_4_SCAN_EVENTID = WMI_10_4_START_EVENTID, + WMI_10_4_ECHO_EVENTID, + WMI_10_4_UPDATE_STATS_EVENTID, + WMI_10_4_INST_RSSI_STATS_EVENTID, + WMI_10_4_VDEV_START_RESP_EVENTID, + WMI_10_4_VDEV_STANDBY_REQ_EVENTID, + WMI_10_4_VDEV_RESUME_REQ_EVENTID, + WMI_10_4_VDEV_STOPPED_EVENTID, + WMI_10_4_PEER_STA_KICKOUT_EVENTID, + WMI_10_4_HOST_SWBA_EVENTID, + WMI_10_4_TBTTOFFSET_UPDATE_EVENTID, + WMI_10_4_MGMT_RX_EVENTID, + WMI_10_4_CHAN_INFO_EVENTID, + WMI_10_4_PHYERR_EVENTID, + WMI_10_4_ROAM_EVENTID, + WMI_10_4_PROFILE_MATCH, + WMI_10_4_DEBUG_PRINT_EVENTID, + WMI_10_4_PDEV_QVIT_EVENTID, + WMI_10_4_WLAN_PROFILE_DATA_EVENTID, + WMI_10_4_RTT_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_TSF_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_RTT_ERROR_REPORT_EVENTID, + WMI_10_4_RTT_KEEPALIVE_EVENTID, + WMI_10_4_OEM_CAPABILITY_EVENTID, + WMI_10_4_OEM_MEASUREMENT_REPORT_EVENTID, + WMI_10_4_OEM_ERROR_REPORT_EVENTID, + WMI_10_4_NAN_EVENTID, + WMI_10_4_WOW_WAKEUP_HOST_EVENTID, + WMI_10_4_GTK_OFFLOAD_STATUS_EVENTID, + WMI_10_4_GTK_REKEY_FAIL_EVENTID, + WMI_10_4_DCS_INTERFERENCE_EVENTID, + WMI_10_4_PDEV_TPC_CONFIG_EVENTID, + WMI_10_4_CSA_HANDLING_EVENTID, + WMI_10_4_GPIO_INPUT_EVENTID, + WMI_10_4_PEER_RATECODE_LIST_EVENTID, + WMI_10_4_GENERIC_BUFFER_EVENTID, + WMI_10_4_MCAST_BUF_RELEASE_EVENTID, + WMI_10_4_MCAST_LIST_AGEOUT_EVENTID, + WMI_10_4_VDEV_GET_KEEPALIVE_EVENTID, + WMI_10_4_WDS_PEER_EVENTID, + WMI_10_4_PEER_STA_PS_STATECHG_EVENTID, + WMI_10_4_PDEV_FIPS_EVENTID, + WMI_10_4_TT_STATS_EVENTID, + WMI_10_4_PDEV_CHANNEL_HOPPING_EVENTID, + WMI_10_4_PDEV_ANI_CCK_LEVEL_EVENTID, + WMI_10_4_PDEV_ANI_OFDM_LEVEL_EVENTID, + WMI_10_4_PDEV_RESERVE_AST_ENTRY_EVENTID, + WMI_10_4_PDEV_NFCAL_POWER_EVENTID, + WMI_10_4_PDEV_TPC_EVENTID, + WMI_10_4_PDEV_GET_AST_INFO_EVENTID, + WMI_10_4_PDEV_TEMPERATURE_EVENTID, + WMI_10_4_PDEV_NFCAL_POWER_ALL_CHANNELS_EVENTID, + WMI_10_4_PDEV_BSS_CHAN_INFO_EVENTID, + WMI_10_4_PDEV_UTF_EVENTID = WMI_10_4_END_EVENTID - 1, +}; + enum wmi_phy_mode { MODE_11A = 0, /* 11a Mode */ MODE_11G = 1, /* 11b/g Mode */ -- GitLab From 772b4aeee51a851132abf799de8c07cfbe95ac00 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:12 +0530 Subject: [PATCH 0312/7006] ath10k: set 10.4 fw exclusive wmi cmd as unsupported for other fw versions In fact, explicit assigned to ZERO for unsupported wmi commands are not really needed. Global static variable will have ZERO by default. However, just for better readability setting all wmi cmds in non 10.4 firmware wmi mapping table as unsupported for wmi cmd which are exclusively available only in 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 32 +++++ drivers/net/wireless/ath/ath10k/wmi.c | 158 ++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 8fdba3865c960..7e75dec5b4fbc 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3151,6 +3151,38 @@ static struct wmi_cmd_map wmi_tlv_cmd_map = { .tdls_set_state_cmdid = WMI_TLV_TDLS_SET_STATE_CMDID, .tdls_peer_update_cmdid = WMI_TLV_TDLS_PEER_UPDATE_CMDID, .adaptive_qcs_cmdid = WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 8dc937de98ab6..a58ddb74ac3b3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -148,6 +148,48 @@ static struct wmi_cmd_map wmi_cmd_map = { .gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.X WMI cmd track */ @@ -271,6 +313,48 @@ static struct wmi_cmd_map wmi_10x_cmd_map = { .gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.2.4 WMI cmd track */ @@ -393,6 +477,48 @@ static struct wmi_cmd_map wmi_10_2_4_cmd_map = { .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_nfcal_power_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_tpc_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ast_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_set_dscp_tid_map_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_get_info_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_filter_neighbor_rx_packets_cmdid = WMI_CMD_UNSUPPORTED, + .mu_cal_start_cmdid = WMI_CMD_UNSUPPORTED, + .set_cca_params_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_bss_chan_info_request_cmdid = WMI_CMD_UNSUPPORTED, }; /* 10.4 WMI cmd track */ @@ -1032,6 +1158,38 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID, .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID, .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED, + .scan_update_request_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_standby_response_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_resume_response_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_add_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_evict_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_restore_peer_cmdid = WMI_CMD_UNSUPPORTED, + .wlan_peer_caching_print_all_peers_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_update_wds_entry_cmdid = WMI_CMD_UNSUPPORTED, + .peer_add_proxy_sta_entry_cmdid = WMI_CMD_UNSUPPORTED, + .rtt_keepalive_cmdid = WMI_CMD_UNSUPPORTED, + .oem_req_cmdid = WMI_CMD_UNSUPPORTED, + .nan_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_ratemask_cmdid = WMI_CMD_UNSUPPORTED, + .qboost_cfg_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_enable_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_smart_ant_set_rx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_tx_antenna_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_train_info_cmdid = WMI_CMD_UNSUPPORTED, + .peer_smart_ant_set_node_config_ops_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_antenna_switch_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_ctl_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_set_mimogain_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_ratepwr_chainmsk_table_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_fips_cmdid = WMI_CMD_UNSUPPORTED, + .tt_set_conf_cmdid = WMI_CMD_UNSUPPORTED, + .fwtest_cmdid = WMI_CMD_UNSUPPORTED, + .vdev_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .peer_atf_request_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_cck_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_get_ani_ofdm_config_cmdid = WMI_CMD_UNSUPPORTED, + .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, -- GitLab From 93841a15cce206450cdb31fe9b3f6b00342afe2b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:13 +0530 Subject: [PATCH 0313/7006] ath10k: add 10.4 fw wmi vdev cmd ids Include 10.4 firmware wmi vdev cmd id and make up wmi vdev map table wmi_10_4_vdev_param_map and also update non 10.4 firmware vdev cmd map table with newly added vdev cmd id specifically for 10.4 firmware as unsupported. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 16 +++ drivers/net/wireless/ath/ath10k/wmi.c | 124 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 85 +++++++++++++++ 3 files changed, 225 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 7e75dec5b4fbc..b2a8e327a551f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3294,6 +3294,22 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_TLV_VDEV_PARAM_UNSUPPORTED, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; static const struct wmi_ops wmi_tlv_ops = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a58ddb74ac3b3..087dea85ef7c8 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -761,6 +761,22 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_TX_ENCAP_TYPE, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_VDEV_PARAM_UNSUPPORTED, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; /* 10.X WMI VDEV param map */ @@ -820,6 +836,22 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { @@ -878,6 +910,97 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = { .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED, .ap_detect_out_of_sync_sleeping_sta_time_secs = WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_VDEV_PARAM_UNSUPPORTED, + .cabq_maxdur = WMI_VDEV_PARAM_UNSUPPORTED, + .mfptest_set = WMI_VDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_VDEV_PARAM_UNSUPPORTED, + .vht_sgimask = WMI_VDEV_PARAM_UNSUPPORTED, + .vht80_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_enable = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_tgt_bmiss_num = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_bmiss_sample_cycle = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_slop_step = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_init_slop = WMI_VDEV_PARAM_UNSUPPORTED, + .early_rx_adjust_pause = WMI_VDEV_PARAM_UNSUPPORTED, + .proxy_sta = WMI_VDEV_PARAM_UNSUPPORTED, + .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED, + .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED, + .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED, +}; + +static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = { + .rts_threshold = WMI_10_4_VDEV_PARAM_RTS_THRESHOLD, + .fragmentation_threshold = WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + .beacon_interval = WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, + .listen_interval = WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, + .multicast_rate = WMI_10_4_VDEV_PARAM_MULTICAST_RATE, + .mgmt_tx_rate = WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, + .slot_time = WMI_10_4_VDEV_PARAM_SLOT_TIME, + .preamble = WMI_10_4_VDEV_PARAM_PREAMBLE, + .swba_time = WMI_10_4_VDEV_PARAM_SWBA_TIME, + .wmi_vdev_stats_update_period = WMI_10_4_VDEV_STATS_UPDATE_PERIOD, + .wmi_vdev_pwrsave_ageout_time = WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, + .wmi_vdev_host_swba_interval = WMI_10_4_VDEV_HOST_SWBA_INTERVAL, + .dtim_period = WMI_10_4_VDEV_PARAM_DTIM_PERIOD, + .wmi_vdev_oc_scheduler_air_time_limit = + WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + .wds = WMI_10_4_VDEV_PARAM_WDS, + .atim_window = WMI_10_4_VDEV_PARAM_ATIM_WINDOW, + .bmiss_count_max = WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, + .bmiss_first_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, + .bmiss_final_bcnt = WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, + .feature_wmm = WMI_10_4_VDEV_PARAM_FEATURE_WMM, + .chwidth = WMI_10_4_VDEV_PARAM_CHWIDTH, + .chextoffset = WMI_10_4_VDEV_PARAM_CHEXTOFFSET, + .disable_htprotection = WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, + .sta_quickkickout = WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, + .mgmt_rate = WMI_10_4_VDEV_PARAM_MGMT_RATE, + .protection_mode = WMI_10_4_VDEV_PARAM_PROTECTION_MODE, + .fixed_rate = WMI_10_4_VDEV_PARAM_FIXED_RATE, + .sgi = WMI_10_4_VDEV_PARAM_SGI, + .ldpc = WMI_10_4_VDEV_PARAM_LDPC, + .tx_stbc = WMI_10_4_VDEV_PARAM_TX_STBC, + .rx_stbc = WMI_10_4_VDEV_PARAM_RX_STBC, + .intra_bss_fwd = WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, + .def_keyid = WMI_10_4_VDEV_PARAM_DEF_KEYID, + .nss = WMI_10_4_VDEV_PARAM_NSS, + .bcast_data_rate = WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, + .mcast_data_rate = WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, + .mcast_indicate = WMI_10_4_VDEV_PARAM_MCAST_INDICATE, + .dhcp_indicate = WMI_10_4_VDEV_PARAM_DHCP_INDICATE, + .unknown_dest_indicate = WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + .ap_keepalive_min_idle_inactive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_idle_inactive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + .ap_keepalive_max_unresponsive_time_secs = + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + .ap_enable_nawds = WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, + .mcast2ucast_set = WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, + .enable_rtscts = WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, + .txbf = WMI_10_4_VDEV_PARAM_TXBF, + .packet_powersave = WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, + .drop_unencry = WMI_10_4_VDEV_PARAM_DROP_UNENCRY, + .tx_encap_type = WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, + .ap_detect_out_of_sync_sleeping_sta_time_secs = + WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + .rc_num_retries = WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, + .cabq_maxdur = WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, + .mfptest_set = WMI_10_4_VDEV_PARAM_MFPTEST_SET, + .rts_fixed_rate = WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, + .vht_sgimask = WMI_10_4_VDEV_PARAM_VHT_SGIMASK, + .vht80_ratemask = WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, + .early_rx_adjust_enable = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + .early_rx_tgt_bmiss_num = WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + .early_rx_bmiss_sample_cycle = + WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + .early_rx_slop_step = WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, + .early_rx_init_slop = WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, + .early_rx_adjust_pause = WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + .proxy_sta = WMI_10_4_VDEV_PARAM_PROXY_STA, + .meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC, + .rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, + .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, }; static struct wmi_pdev_param_map wmi_pdev_param_map = { @@ -5763,6 +5886,7 @@ int ath10k_wmi_attach(struct ath10k *ar) case ATH10K_FW_WMI_OP_VERSION_10_4: ar->wmi.ops = &wmi_10_4_ops; ar->wmi.cmd = &wmi_10_4_cmd_map; + ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index c3a05a9a05aed..ecc7288ff119e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3904,6 +3904,22 @@ struct wmi_vdev_param_map { u32 drop_unencry; u32 tx_encap_type; u32 ap_detect_out_of_sync_sleeping_sta_time_secs; + u32 rc_num_retries; + u32 cabq_maxdur; + u32 mfptest_set; + u32 rts_fixed_rate; + u32 vht_sgimask; + u32 vht80_ratemask; + u32 early_rx_adjust_enable; + u32 early_rx_tgt_bmiss_num; + u32 early_rx_bmiss_sample_cycle; + u32 early_rx_slop_step; + u32 early_rx_init_slop; + u32 early_rx_adjust_pause; + u32 proxy_sta; + u32 meru_vc; + u32 rx_decap_type; + u32 bw_nss_ratemask; }; #define WMI_VDEV_PARAM_UNSUPPORTED 0 @@ -4162,6 +4178,75 @@ enum wmi_10x_vdev_param { WMI_10X_VDEV_PARAM_VHT80_RATEMASK, }; +enum wmi_10_4_vdev_param { + WMI_10_4_VDEV_PARAM_RTS_THRESHOLD = 0x1, + WMI_10_4_VDEV_PARAM_FRAGMENTATION_THRESHOLD, + WMI_10_4_VDEV_PARAM_BEACON_INTERVAL, + WMI_10_4_VDEV_PARAM_LISTEN_INTERVAL, + WMI_10_4_VDEV_PARAM_MULTICAST_RATE, + WMI_10_4_VDEV_PARAM_MGMT_TX_RATE, + WMI_10_4_VDEV_PARAM_SLOT_TIME, + WMI_10_4_VDEV_PARAM_PREAMBLE, + WMI_10_4_VDEV_PARAM_SWBA_TIME, + WMI_10_4_VDEV_STATS_UPDATE_PERIOD, + WMI_10_4_VDEV_PWRSAVE_AGEOUT_TIME, + WMI_10_4_VDEV_HOST_SWBA_INTERVAL, + WMI_10_4_VDEV_PARAM_DTIM_PERIOD, + WMI_10_4_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT, + WMI_10_4_VDEV_PARAM_WDS, + WMI_10_4_VDEV_PARAM_ATIM_WINDOW, + WMI_10_4_VDEV_PARAM_BMISS_COUNT_MAX, + WMI_10_4_VDEV_PARAM_BMISS_FIRST_BCNT, + WMI_10_4_VDEV_PARAM_BMISS_FINAL_BCNT, + WMI_10_4_VDEV_PARAM_FEATURE_WMM, + WMI_10_4_VDEV_PARAM_CHWIDTH, + WMI_10_4_VDEV_PARAM_CHEXTOFFSET, + WMI_10_4_VDEV_PARAM_DISABLE_HTPROTECTION, + WMI_10_4_VDEV_PARAM_STA_QUICKKICKOUT, + WMI_10_4_VDEV_PARAM_MGMT_RATE, + WMI_10_4_VDEV_PARAM_PROTECTION_MODE, + WMI_10_4_VDEV_PARAM_FIXED_RATE, + WMI_10_4_VDEV_PARAM_SGI, + WMI_10_4_VDEV_PARAM_LDPC, + WMI_10_4_VDEV_PARAM_TX_STBC, + WMI_10_4_VDEV_PARAM_RX_STBC, + WMI_10_4_VDEV_PARAM_INTRA_BSS_FWD, + WMI_10_4_VDEV_PARAM_DEF_KEYID, + WMI_10_4_VDEV_PARAM_NSS, + WMI_10_4_VDEV_PARAM_BCAST_DATA_RATE, + WMI_10_4_VDEV_PARAM_MCAST_DATA_RATE, + WMI_10_4_VDEV_PARAM_MCAST_INDICATE, + WMI_10_4_VDEV_PARAM_DHCP_INDICATE, + WMI_10_4_VDEV_PARAM_UNKNOWN_DEST_INDICATE, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS, + WMI_10_4_VDEV_PARAM_AP_ENABLE_NAWDS, + WMI_10_4_VDEV_PARAM_MCAST2UCAST_SET, + WMI_10_4_VDEV_PARAM_ENABLE_RTSCTS, + WMI_10_4_VDEV_PARAM_RC_NUM_RETRIES, + WMI_10_4_VDEV_PARAM_TXBF, + WMI_10_4_VDEV_PARAM_PACKET_POWERSAVE, + WMI_10_4_VDEV_PARAM_DROP_UNENCRY, + WMI_10_4_VDEV_PARAM_TX_ENCAP_TYPE, + WMI_10_4_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS, + WMI_10_4_VDEV_PARAM_CABQ_MAXDUR, + WMI_10_4_VDEV_PARAM_MFPTEST_SET, + WMI_10_4_VDEV_PARAM_RTS_FIXED_RATE, + WMI_10_4_VDEV_PARAM_VHT_SGIMASK, + WMI_10_4_VDEV_PARAM_VHT80_RATEMASK, + WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE, + WMI_10_4_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM, + WMI_10_4_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE, + WMI_10_4_VDEV_PARAM_EARLY_RX_SLOP_STEP, + WMI_10_4_VDEV_PARAM_EARLY_RX_INIT_SLOP, + WMI_10_4_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE, + WMI_10_4_VDEV_PARAM_PROXY_STA, + WMI_10_4_VDEV_PARAM_MERU_VC, + WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE, + WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK, +}; + #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0) #define WMI_VDEV_PARAM_TXBF_MU_TX_BFEE BIT(1) #define WMI_VDEV_PARAM_TXBF_SU_TX_BFER BIT(2) -- GitLab From d86561ff677b312424ba53389be80b507941973b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:14 +0530 Subject: [PATCH 0314/7006] ath10k: add 10.4 fw wmi pdev cmd ids Include 10.4 firmware wmi pdev cmd id and prepare wmi vdev map table wmi_10_4_pdev_param_map and update non 10.4 firmware pdev cmd map table with newly added vdev cmd id specifically for 10.4 firmware as unsupported. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 42 ++++ drivers/net/wireless/ath/ath10k/wmi.c | 228 ++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 136 +++++++++++++ 3 files changed, 406 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index b2a8e327a551f..620b37b59784e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -3236,6 +3236,48 @@ static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = { .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 087dea85ef7c8..3f29886dc880e 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1053,6 +1053,48 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = { .burst_dur = WMI_PDEV_PARAM_UNSUPPORTED, .burst_enable = WMI_PDEV_PARAM_UNSUPPORTED, .cal_period = WMI_PDEV_PARAM_UNSUPPORTED, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { @@ -1106,6 +1148,48 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = { .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { @@ -1159,6 +1243,48 @@ static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = { .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR, .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE, .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_decap_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .smart_antenna_default_antenna = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_override = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .antenna_gain = WMI_PDEV_PARAM_UNSUPPORTED, + .rx_filter = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_to_ucast_tid = WMI_PDEV_PARAM_UNSUPPORTED, + .proxy_sta_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_mode = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .remove_mcast2ucast_buffer = WMI_PDEV_PARAM_UNSUPPORTED, + .peer_sta_ps_statechg_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .igmpmld_ac_override = WMI_PDEV_PARAM_UNSUPPORTED, + .block_interbss = WMI_PDEV_PARAM_UNSUPPORTED, + .set_disable_reset_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_msdu_ttl_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_ppdu_duration_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .txbf_sound_period_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_promisc_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .set_burst_mode_cmdid = WMI_PDEV_PARAM_UNSUPPORTED, + .en_stats = WMI_PDEV_PARAM_UNSUPPORTED, + .mu_group_policy = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_detection = WMI_PDEV_PARAM_UNSUPPORTED, + .noise_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .dpd_enable = WMI_PDEV_PARAM_UNSUPPORTED, + .set_mcast_bcast_echo = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_strict_sch = WMI_PDEV_PARAM_UNSUPPORTED, + .atf_sched_duration = WMI_PDEV_PARAM_UNSUPPORTED, + .ant_plzn = WMI_PDEV_PARAM_UNSUPPORTED, + .mgmt_retry_limit = WMI_PDEV_PARAM_UNSUPPORTED, + .sensitivity_level = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_2g = WMI_PDEV_PARAM_UNSUPPORTED, + .signed_txpower_5g = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_amsdu = WMI_PDEV_PARAM_UNSUPPORTED, + .enable_per_tid_ampdu = WMI_PDEV_PARAM_UNSUPPORTED, + .cca_threshold = WMI_PDEV_PARAM_UNSUPPORTED, + .rts_fixed_rate = WMI_PDEV_PARAM_UNSUPPORTED, + .pdev_reset = WMI_PDEV_PARAM_UNSUPPORTED, + .wapi_mbssid_offset = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_srcaddr = WMI_PDEV_PARAM_UNSUPPORTED, + .arp_dstaddr = WMI_PDEV_PARAM_UNSUPPORTED, }; /* firmware 10.2 specific mappings */ @@ -1315,6 +1441,107 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = { .pdev_reserve_ast_entry_cmdid = WMI_CMD_UNSUPPORTED, }; +static struct wmi_pdev_param_map wmi_10_4_pdev_param_map = { + .tx_chain_mask = WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK, + .rx_chain_mask = WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, + .txpower_limit2g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, + .txpower_limit5g = WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, + .txpower_scale = WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, + .beacon_gen_mode = WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, + .beacon_tx_mode = WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, + .resmgr_offchan_mode = WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + .protection_mode = WMI_10_4_PDEV_PARAM_PROTECTION_MODE, + .dynamic_bw = WMI_10_4_PDEV_PARAM_DYNAMIC_BW, + .non_agg_sw_retry_th = WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + .agg_sw_retry_th = WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, + .sta_kickout_th = WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, + .ac_aggrsize_scaling = WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, + .ltr_enable = WMI_10_4_PDEV_PARAM_LTR_ENABLE, + .ltr_ac_latency_be = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, + .ltr_ac_latency_bk = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, + .ltr_ac_latency_vi = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, + .ltr_ac_latency_vo = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, + .ltr_ac_latency_timeout = WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + .ltr_sleep_override = WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + .ltr_rx_override = WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, + .ltr_tx_activity_timeout = WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + .l1ss_enable = WMI_10_4_PDEV_PARAM_L1SS_ENABLE, + .dsleep_enable = WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, + .pcielp_txbuf_flush = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + .pcielp_txbuf_watermark = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + .pcielp_txbuf_tmo_en = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + .pcielp_txbuf_tmo_value = WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + .pdev_stats_update_period = + WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + .vdev_stats_update_period = + WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + .peer_stats_update_period = + WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + .bcnflt_stats_update_period = + WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + .pmf_qos = WMI_10_4_PDEV_PARAM_PMF_QOS, + .arp_ac_override = WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, + .dcs = WMI_10_4_PDEV_PARAM_DCS, + .ani_enable = WMI_10_4_PDEV_PARAM_ANI_ENABLE, + .ani_poll_period = WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, + .ani_listen_period = WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, + .ani_ofdm_level = WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, + .ani_cck_level = WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, + .dyntxchain = WMI_10_4_PDEV_PARAM_DYNTXCHAIN, + .proxy_sta = WMI_10_4_PDEV_PARAM_PROXY_STA, + .idle_ps_config = WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, + .power_gating_sleep = WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, + .fast_channel_reset = WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, + .burst_dur = WMI_10_4_PDEV_PARAM_BURST_DUR, + .burst_enable = WMI_10_4_PDEV_PARAM_BURST_ENABLE, + .cal_period = WMI_10_4_PDEV_PARAM_CAL_PERIOD, + .aggr_burst = WMI_10_4_PDEV_PARAM_AGGR_BURST, + .rx_decap_mode = WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, + .smart_antenna_default_antenna = + WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + .igmpmld_override = WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, + .igmpmld_tid = WMI_10_4_PDEV_PARAM_IGMPMLD_TID, + .antenna_gain = WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, + .rx_filter = WMI_10_4_PDEV_PARAM_RX_FILTER, + .set_mcast_to_ucast_tid = WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, + .proxy_sta_mode = WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, + .set_mcast2ucast_mode = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, + .set_mcast2ucast_buffer = WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + .remove_mcast2ucast_buffer = + WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + .peer_sta_ps_statechg_enable = + WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, + .igmpmld_ac_override = WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + .block_interbss = WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, + .set_disable_reset_cmdid = WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + .set_msdu_ttl_cmdid = WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, + .set_ppdu_duration_cmdid = WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + .txbf_sound_period_cmdid = WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + .set_promisc_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + .set_burst_mode_cmdid = WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, + .en_stats = WMI_10_4_PDEV_PARAM_EN_STATS, + .mu_group_policy = WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, + .noise_detection = WMI_10_4_PDEV_PARAM_NOISE_DETECTION, + .noise_threshold = WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, + .dpd_enable = WMI_10_4_PDEV_PARAM_DPD_ENABLE, + .set_mcast_bcast_echo = WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + .atf_strict_sch = WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, + .atf_sched_duration = WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, + .ant_plzn = WMI_10_4_PDEV_PARAM_ANT_PLZN, + .mgmt_retry_limit = WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, + .sensitivity_level = WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, + .signed_txpower_2g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, + .signed_txpower_5g = WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, + .enable_per_tid_amsdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + .enable_per_tid_ampdu = WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + .cca_threshold = WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, + .rts_fixed_rate = WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, + .pdev_reset = WMI_10_4_PDEV_PARAM_PDEV_RESET, + .wapi_mbssid_offset = WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, + .arp_srcaddr = WMI_10_4_PDEV_PARAM_ARP_SRCADDR, + .arp_dstaddr = WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; + void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, const struct wmi_channel_arg *arg) { @@ -5887,6 +6114,7 @@ int ath10k_wmi_attach(struct ath10k *ar) ar->wmi.ops = &wmi_10_4_ops; ar->wmi.cmd = &wmi_10_4_cmd_map; ar->wmi.vdev_param = &wmi_10_4_vdev_param_map; + ar->wmi.pdev_param = &wmi_10_4_pdev_param_map; break; case ATH10K_FW_WMI_OP_VERSION_10_2_4: ar->wmi.cmd = &wmi_10_2_4_cmd_map; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index ecc7288ff119e..f6ee163259f68 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -3011,6 +3011,48 @@ struct wmi_pdev_param_map { u32 burst_dur; u32 burst_enable; u32 cal_period; + u32 aggr_burst; + u32 rx_decap_mode; + u32 smart_antenna_default_antenna; + u32 igmpmld_override; + u32 igmpmld_tid; + u32 antenna_gain; + u32 rx_filter; + u32 set_mcast_to_ucast_tid; + u32 proxy_sta_mode; + u32 set_mcast2ucast_mode; + u32 set_mcast2ucast_buffer; + u32 remove_mcast2ucast_buffer; + u32 peer_sta_ps_statechg_enable; + u32 igmpmld_ac_override; + u32 block_interbss; + u32 set_disable_reset_cmdid; + u32 set_msdu_ttl_cmdid; + u32 set_ppdu_duration_cmdid; + u32 txbf_sound_period_cmdid; + u32 set_promisc_mode_cmdid; + u32 set_burst_mode_cmdid; + u32 en_stats; + u32 mu_group_policy; + u32 noise_detection; + u32 noise_threshold; + u32 dpd_enable; + u32 set_mcast_bcast_echo; + u32 atf_strict_sch; + u32 atf_sched_duration; + u32 ant_plzn; + u32 mgmt_retry_limit; + u32 sensitivity_level; + u32 signed_txpower_2g; + u32 signed_txpower_5g; + u32 enable_per_tid_amsdu; + u32 enable_per_tid_ampdu; + u32 cca_threshold; + u32 rts_fixed_rate; + u32 pdev_reset; + u32 wapi_mbssid_offset; + u32 arp_srcaddr; + u32 arp_dstaddr; }; #define WMI_PDEV_PARAM_UNSUPPORTED 0 @@ -3226,6 +3268,100 @@ enum wmi_10x_pdev_param { WMI_10X_PDEV_PARAM_CAL_PERIOD }; +enum wmi_10_4_pdev_param { + WMI_10_4_PDEV_PARAM_TX_CHAIN_MASK = 0x1, + WMI_10_4_PDEV_PARAM_RX_CHAIN_MASK, + WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT2G, + WMI_10_4_PDEV_PARAM_TXPOWER_LIMIT5G, + WMI_10_4_PDEV_PARAM_TXPOWER_SCALE, + WMI_10_4_PDEV_PARAM_BEACON_GEN_MODE, + WMI_10_4_PDEV_PARAM_BEACON_TX_MODE, + WMI_10_4_PDEV_PARAM_RESMGR_OFFCHAN_MODE, + WMI_10_4_PDEV_PARAM_PROTECTION_MODE, + WMI_10_4_PDEV_PARAM_DYNAMIC_BW, + WMI_10_4_PDEV_PARAM_NON_AGG_SW_RETRY_TH, + WMI_10_4_PDEV_PARAM_AGG_SW_RETRY_TH, + WMI_10_4_PDEV_PARAM_STA_KICKOUT_TH, + WMI_10_4_PDEV_PARAM_AC_AGGRSIZE_SCALING, + WMI_10_4_PDEV_PARAM_LTR_ENABLE, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BE, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_BK, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VI, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_VO, + WMI_10_4_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT, + WMI_10_4_PDEV_PARAM_LTR_SLEEP_OVERRIDE, + WMI_10_4_PDEV_PARAM_LTR_RX_OVERRIDE, + WMI_10_4_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT, + WMI_10_4_PDEV_PARAM_L1SS_ENABLE, + WMI_10_4_PDEV_PARAM_DSLEEP_ENABLE, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_FLUSH, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_WATERMARK, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_EN, + WMI_10_4_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE, + WMI_10_4_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD, + WMI_10_4_PDEV_PARAM_PMF_QOS, + WMI_10_4_PDEV_PARAM_ARP_AC_OVERRIDE, + WMI_10_4_PDEV_PARAM_DCS, + WMI_10_4_PDEV_PARAM_ANI_ENABLE, + WMI_10_4_PDEV_PARAM_ANI_POLL_PERIOD, + WMI_10_4_PDEV_PARAM_ANI_LISTEN_PERIOD, + WMI_10_4_PDEV_PARAM_ANI_OFDM_LEVEL, + WMI_10_4_PDEV_PARAM_ANI_CCK_LEVEL, + WMI_10_4_PDEV_PARAM_DYNTXCHAIN, + WMI_10_4_PDEV_PARAM_PROXY_STA, + WMI_10_4_PDEV_PARAM_IDLE_PS_CONFIG, + WMI_10_4_PDEV_PARAM_POWER_GATING_SLEEP, + WMI_10_4_PDEV_PARAM_AGGR_BURST, + WMI_10_4_PDEV_PARAM_RX_DECAP_MODE, + WMI_10_4_PDEV_PARAM_FAST_CHANNEL_RESET, + WMI_10_4_PDEV_PARAM_BURST_DUR, + WMI_10_4_PDEV_PARAM_BURST_ENABLE, + WMI_10_4_PDEV_PARAM_SMART_ANTENNA_DEFAULT_ANTENNA, + WMI_10_4_PDEV_PARAM_IGMPMLD_OVERRIDE, + WMI_10_4_PDEV_PARAM_IGMPMLD_TID, + WMI_10_4_PDEV_PARAM_ANTENNA_GAIN, + WMI_10_4_PDEV_PARAM_RX_FILTER, + WMI_10_4_PDEV_SET_MCAST_TO_UCAST_TID, + WMI_10_4_PDEV_PARAM_PROXY_STA_MODE, + WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_MODE, + WMI_10_4_PDEV_PARAM_SET_MCAST2UCAST_BUFFER, + WMI_10_4_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER, + WMI_10_4_PDEV_PEER_STA_PS_STATECHG_ENABLE, + WMI_10_4_PDEV_PARAM_IGMPMLD_AC_OVERRIDE, + WMI_10_4_PDEV_PARAM_BLOCK_INTERBSS, + WMI_10_4_PDEV_PARAM_SET_DISABLE_RESET_CMDID, + WMI_10_4_PDEV_PARAM_SET_MSDU_TTL_CMDID, + WMI_10_4_PDEV_PARAM_SET_PPDU_DURATION_CMDID, + WMI_10_4_PDEV_PARAM_TXBF_SOUND_PERIOD_CMDID, + WMI_10_4_PDEV_PARAM_SET_PROMISC_MODE_CMDID, + WMI_10_4_PDEV_PARAM_SET_BURST_MODE_CMDID, + WMI_10_4_PDEV_PARAM_EN_STATS, + WMI_10_4_PDEV_PARAM_MU_GROUP_POLICY, + WMI_10_4_PDEV_PARAM_NOISE_DETECTION, + WMI_10_4_PDEV_PARAM_NOISE_THRESHOLD, + WMI_10_4_PDEV_PARAM_DPD_ENABLE, + WMI_10_4_PDEV_PARAM_SET_MCAST_BCAST_ECHO, + WMI_10_4_PDEV_PARAM_ATF_STRICT_SCH, + WMI_10_4_PDEV_PARAM_ATF_SCHED_DURATION, + WMI_10_4_PDEV_PARAM_ANT_PLZN, + WMI_10_4_PDEV_PARAM_MGMT_RETRY_LIMIT, + WMI_10_4_PDEV_PARAM_SENSITIVITY_LEVEL, + WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_2G, + WMI_10_4_PDEV_PARAM_SIGNED_TXPOWER_5G, + WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMSDU, + WMI_10_4_PDEV_PARAM_ENABLE_PER_TID_AMPDU, + WMI_10_4_PDEV_PARAM_CCA_THRESHOLD, + WMI_10_4_PDEV_PARAM_RTS_FIXED_RATE, + WMI_10_4_PDEV_PARAM_CAL_PERIOD, + WMI_10_4_PDEV_PARAM_PDEV_RESET, + WMI_10_4_PDEV_PARAM_WAPI_MBSSID_OFFSET, + WMI_10_4_PDEV_PARAM_ARP_SRCADDR, + WMI_10_4_PDEV_PARAM_ARP_DSTADDR, +}; + struct wmi_pdev_set_param_cmd { __le32 param_id; __le32 param_value; -- GitLab From d1e52a8ed2bf34ed5b839c190209deb80828d189 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:15 +0530 Subject: [PATCH 0315/7006] ath10k: fill 10.4 fw wmi init cmd default values Define 10.4 wmi init command structure and introduce new function ath10k_wmi_10_4_op_gen_init() to fill default values for each field which goes as part of wmi init cmd to 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 7 + drivers/net/wireless/ath/ath10k/core.h | 2 + drivers/net/wireless/ath/ath10k/hw.h | 54 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 83 ++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 220 +++++++++++++++++++++++++ 5 files changed, 366 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 5e8d8af5d0d07..020ac9f101686 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1116,6 +1116,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) WMI_STAT_PEER; break; case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->max_num_peers = TARGET_10_4_NUM_PEERS; + ar->max_num_stations = TARGET_10_4_NUM_STATIONS; + ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; + ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; + ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; + ar->fw_stats_req_mask = WMI_STAT_PEER; + break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: WARN_ON(1); diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index afd21d5b25ae3..58b02ae817062 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -684,6 +684,8 @@ struct ath10k { int max_num_stations; int max_num_vdevs; int max_num_tdls_vdevs; + int num_active_peers; + int num_tids; struct work_struct offchan_tx_work; struct sk_buff_head offchan_tx_queue; diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index b0c89b48092da..52fc0249378be 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -354,6 +354,60 @@ enum ath10k_hw_rate_cck { #define NUM_TARGET_CE_CONFIG_WLAN ar->hw_values->num_target_ce_config_wlan +/* Target specific defines for 10.4 firmware */ +#define TARGET_10_4_NUM_VDEVS 16 +#define TARGET_10_4_NUM_STATIONS 32 +#define TARGET_10_4_NUM_PEERS ((TARGET_10_4_NUM_STATIONS) + \ + (TARGET_10_4_NUM_VDEVS)) +#define TARGET_10_4_ACTIVE_PEERS 0 +#define TARGET_10_4_NUM_OFFLOAD_PEERS 0 +#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 +#define TARGET_10_4_NUM_PEER_KEYS 2 +#define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2) +#define TARGET_10_4_AST_SKID_LIMIT 32 +#define TARGET_10_4_TX_CHAIN_MASK (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3)) +#define TARGET_10_4_RX_CHAIN_MASK (BIT(0) | BIT(1) | \ + BIT(2) | BIT(3)) + +/* 100 ms for video, best-effort, and background */ +#define TARGET_10_4_RX_TIMEOUT_LO_PRI 100 + +/* 40 ms for voice */ +#define TARGET_10_4_RX_TIMEOUT_HI_PRI 40 + +#define TARGET_10_4_RX_DECAP_MODE ATH10K_HW_TXRX_NATIVE_WIFI +#define TARGET_10_4_SCAN_MAX_REQS 4 +#define TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES 8 + +/* Note: mcast to ucast is disabled by default */ +#define TARGET_10_4_NUM_MCAST_GROUPS 0 +#define TARGET_10_4_NUM_MCAST_TABLE_ELEMS 0 +#define TARGET_10_4_MCAST2UCAST_MODE 0 + +#define TARGET_10_4_TX_DBG_LOG_SIZE 1024 +#define TARGET_10_4_NUM_WDS_ENTRIES 32 +#define TARGET_10_4_DMA_BURST_SIZE 1 +#define TARGET_10_4_MAC_AGGR_DELIM 0 +#define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1 +#define TARGET_10_4_VOW_CONFIG 0 +#define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV 3 +#define TARGET_10_4_NUM_MSDU_DESC (1024 + 400) +#define TARGET_10_4_11AC_TX_MAX_FRAGS 2 +#define TARGET_10_4_MAX_PEER_EXT_STATS 16 +#define TARGET_10_4_SMART_ANT_CAP 0 +#define TARGET_10_4_BK_MIN_FREE 0 +#define TARGET_10_4_BE_MIN_FREE 0 +#define TARGET_10_4_VI_MIN_FREE 0 +#define TARGET_10_4_VO_MIN_FREE 0 +#define TARGET_10_4_RX_BATCH_MODE 1 +#define TARGET_10_4_THERMAL_THROTTLING_CONFIG 0 +#define TARGET_10_4_ATF_CONFIG 0 +#define TARGET_10_4_IPHDR_PAD_CONFIG 1 +#define TARGET_10_4_QWRAP_CONFIG 0 + /* Number of Copy Engines supported */ #define CE_COUNT ar->hw_values->ce_count diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 3f29886dc880e..6c51b20dc8c5d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4641,6 +4641,88 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar) return buf; } +static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar) +{ + struct wmi_init_cmd_10_4 *cmd; + struct sk_buff *buf; + struct wmi_resource_config_10_4 config = {}; + u32 len; + + config.num_vdevs = __cpu_to_le32(ar->max_num_vdevs); + config.num_peers = __cpu_to_le32(ar->max_num_peers); + config.num_active_peers = __cpu_to_le32(ar->num_active_peers); + config.num_tids = __cpu_to_le32(ar->num_tids); + + config.num_offload_peers = __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_PEERS); + config.num_offload_reorder_buffs = + __cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS); + config.num_peer_keys = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS); + config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT); + config.tx_chain_mask = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK); + config.rx_chain_mask = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK); + + config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[2] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI); + config.rx_timeout_pri[3] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_HI_PRI); + + config.rx_decap_mode = __cpu_to_le32(TARGET_10_4_RX_DECAP_MODE); + config.scan_max_pending_req = __cpu_to_le32(TARGET_10_4_SCAN_MAX_REQS); + config.bmiss_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_BMISS_OFFLOAD_MAX_VDEV); + config.roam_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_VDEV); + config.roam_offload_max_ap_profiles = + __cpu_to_le32(TARGET_10_4_ROAM_OFFLOAD_MAX_PROFILES); + config.num_mcast_groups = __cpu_to_le32(TARGET_10_4_NUM_MCAST_GROUPS); + config.num_mcast_table_elems = + __cpu_to_le32(TARGET_10_4_NUM_MCAST_TABLE_ELEMS); + + config.mcast2ucast_mode = __cpu_to_le32(TARGET_10_4_MCAST2UCAST_MODE); + config.tx_dbg_log_size = __cpu_to_le32(TARGET_10_4_TX_DBG_LOG_SIZE); + config.num_wds_entries = __cpu_to_le32(TARGET_10_4_NUM_WDS_ENTRIES); + config.dma_burst_size = __cpu_to_le32(TARGET_10_4_DMA_BURST_SIZE); + config.mac_aggr_delim = __cpu_to_le32(TARGET_10_4_MAC_AGGR_DELIM); + + config.rx_skip_defrag_timeout_dup_detection_check = + __cpu_to_le32(TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK); + + config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG); + config.gtk_offload_max_vdev = + __cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV); + config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC); + config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS); + config.max_peer_ext_stats = + __cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS); + config.smart_ant_cap = __cpu_to_le32(TARGET_10_4_SMART_ANT_CAP); + + config.bk_minfree = __cpu_to_le32(TARGET_10_4_BK_MIN_FREE); + config.be_minfree = __cpu_to_le32(TARGET_10_4_BE_MIN_FREE); + config.vi_minfree = __cpu_to_le32(TARGET_10_4_VI_MIN_FREE); + config.vo_minfree = __cpu_to_le32(TARGET_10_4_VO_MIN_FREE); + + config.rx_batchmode = __cpu_to_le32(TARGET_10_4_RX_BATCH_MODE); + config.tt_support = + __cpu_to_le32(TARGET_10_4_THERMAL_THROTTLING_CONFIG); + config.atf_config = __cpu_to_le32(TARGET_10_4_ATF_CONFIG); + config.iphdr_pad_config = __cpu_to_le32(TARGET_10_4_IPHDR_PAD_CONFIG); + config.qwrap_config = __cpu_to_le32(TARGET_10_4_QWRAP_CONFIG); + + len = sizeof(*cmd) + + (sizeof(struct host_memory_chunk) * ar->wmi.num_mem_chunks); + + buf = ath10k_wmi_alloc_skb(ar, len); + if (!buf) + return ERR_PTR(-ENOMEM); + + cmd = (struct wmi_init_cmd_10_4 *)buf->data; + memcpy(&cmd->resource_config, &config, sizeof(config)); + ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks); + + ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.4\n"); + return buf; +} + int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg) { if (arg->ie_len && !arg->ie) @@ -6105,6 +6187,7 @@ static const struct wmi_ops wmi_10_2_4_ops = { static const struct wmi_ops wmi_10_4_ops = { .map_svc = wmi_10_4_svc_map, + .gen_init = ath10k_wmi_10_4_op_gen_init, }; int ath10k_wmi_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index f6ee163259f68..dbb9f1c8c917b 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2380,6 +2380,221 @@ struct wmi_resource_config_10_2 { #define NUM_UNITS_IS_NUM_VDEVS 0x1 #define NUM_UNITS_IS_NUM_PEERS 0x2 +struct wmi_resource_config_10_4 { + /* Number of virtual devices (VAPs) to support */ + __le32 num_vdevs; + + /* Number of peer nodes to support */ + __le32 num_peers; + + /* Number of active peer nodes to support */ + __le32 num_active_peers; + + /* In offload mode, target supports features like WOW, chatter and other + * protocol offloads. In order to support them some functionalities like + * reorder buffering, PN checking need to be done in target. + * This determines maximum number of peers supported by target in + * offload mode. + */ + __le32 num_offload_peers; + + /* Number of reorder buffers available for doing target based reorder + * Rx reorder buffering + */ + __le32 num_offload_reorder_buffs; + + /* Number of keys per peer */ + __le32 num_peer_keys; + + /* Total number of TX/RX data TIDs */ + __le32 num_tids; + + /* Max skid for resolving hash collisions. + * The address search table is sparse, so that if two MAC addresses + * result in the same hash value, the second of these conflicting + * entries can slide to the next index in the address search table, + * and use it, if it is unoccupied. This ast_skid_limit parameter + * specifies the upper bound on how many subsequent indices to search + * over to find an unoccupied space. + */ + __le32 ast_skid_limit; + + /* The nominal chain mask for transmit. + * The chain mask may be modified dynamically, e.g. to operate AP tx + * with a reduced number of chains if no clients are associated. + * This configuration parameter specifies the nominal chain-mask that + * should be used when not operating with a reduced set of tx chains. + */ + __le32 tx_chain_mask; + + /* The nominal chain mask for receive. + * The chain mask may be modified dynamically, e.g. for a client to use + * a reduced number of chains for receive if the traffic to the client + * is low enough that it doesn't require downlink MIMO or antenna + * diversity. This configuration parameter specifies the nominal + * chain-mask that should be used when not operating with a reduced + * set of rx chains. + */ + __le32 rx_chain_mask; + + /* What rx reorder timeout (ms) to use for the AC. + * Each WMM access class (voice, video, best-effort, background) will + * have its own timeout value to dictate how long to wait for missing + * rx MPDUs to arrive before flushing subsequent MPDUs that have already + * been received. This parameter specifies the timeout in milliseconds + * for each class. + */ + __le32 rx_timeout_pri[4]; + + /* What mode the rx should decap packets to. + * MAC can decap to RAW (no decap), native wifi or Ethernet types. + * This setting also determines the default TX behavior, however TX + * behavior can be modified on a per VAP basis during VAP init + */ + __le32 rx_decap_mode; + + __le32 scan_max_pending_req; + + __le32 bmiss_offload_max_vdev; + + __le32 roam_offload_max_vdev; + + __le32 roam_offload_max_ap_profiles; + + /* How many groups to use for mcast->ucast conversion. + * The target's WAL maintains a table to hold information regarding + * which peers belong to a given multicast group, so that if + * multicast->unicast conversion is enabled, the target can convert + * multicast tx frames to a series of unicast tx frames, to each peer + * within the multicast group. This num_mcast_groups configuration + * parameter tells the target how many multicast groups to provide + * storage for within its multicast group membership table. + */ + __le32 num_mcast_groups; + + /* Size to alloc for the mcast membership table. + * This num_mcast_table_elems configuration parameter tells the target + * how many peer elements it needs to provide storage for in its + * multicast group membership table. These multicast group membership + * table elements are shared by the multicast groups stored within + * the table. + */ + __le32 num_mcast_table_elems; + + /* Whether/how to do multicast->unicast conversion. + * This configuration parameter specifies whether the target should + * perform multicast --> unicast conversion on transmit, and if so, + * what to do if it finds no entries in its multicast group membership + * table for the multicast IP address in the tx frame. + * Configuration value: + * 0 -> Do not perform multicast to unicast conversion. + * 1 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, drop the frame + * 2 -> Convert multicast frames to unicast, if the IP multicast address + * from the tx frame is found in the multicast group membership + * table. If the IP multicast address is not found, transmit the + * frame as multicast. + */ + __le32 mcast2ucast_mode; + + /* How much memory to allocate for a tx PPDU dbg log. + * This parameter controls how much memory the target will allocate to + * store a log of tx PPDU meta-information (how large the PPDU was, + * when it was sent, whether it was successful, etc.) + */ + __le32 tx_dbg_log_size; + + /* How many AST entries to be allocated for WDS */ + __le32 num_wds_entries; + + /* MAC DMA burst size. 0 -default, 1 -256B */ + __le32 dma_burst_size; + + /* Fixed delimiters to be inserted after every MPDU to account for + * interface latency to avoid underrun. + */ + __le32 mac_aggr_delim; + + /* Determine whether target is responsible for detecting duplicate + * non-aggregate MPDU and timing out stale fragments. A-MPDU reordering + * is always performed on the target. + * + * 0: target responsible for frag timeout and dup checking + * 1: host responsible for frag timeout and dup checking + */ + __le32 rx_skip_defrag_timeout_dup_detection_check; + + /* Configuration for VoW : No of Video nodes to be supported and max + * no of descriptors for each video link (node). + */ + __le32 vow_config; + + /* Maximum vdev that could use gtk offload */ + __le32 gtk_offload_max_vdev; + + /* Number of msdu descriptors target should use */ + __le32 num_msdu_desc; + + /* Max number of tx fragments per MSDU. + * This parameter controls the max number of tx fragments per MSDU. + * This will passed by target as part of the WMI_SERVICE_READY event + * and is overridden by the OS shim as required. + */ + __le32 max_frag_entries; + + /* Max number of extended peer stats. + * This parameter controls the max number of peers for which extended + * statistics are supported by target + */ + __le32 max_peer_ext_stats; + + /* Smart antenna capabilities information. + * 1 - Smart antenna is enabled + * 0 - Smart antenna is disabled + * In future this can contain smart antenna specific capabilities. + */ + __le32 smart_ant_cap; + + /* User can configure the buffers allocated for each AC (BE, BK, VI, VO) + * during init. + */ + __le32 bk_minfree; + __le32 be_minfree; + __le32 vi_minfree; + __le32 vo_minfree; + + /* Rx batch mode capability. + * 1 - Rx batch mode enabled + * 0 - Rx batch mode disabled + */ + __le32 rx_batchmode; + + /* Thermal throttling capability. + * 1 - Capable of thermal throttling + * 0 - Not capable of thermal throttling + */ + __le32 tt_support; + + /* ATF configuration. + * 1 - Enable ATF + * 0 - Disable ATF + */ + __le32 atf_config; + + /* Configure padding to manage IP header un-alignment + * 1 - Enable padding + * 0 - Disable padding + */ + __le32 iphdr_pad_config; + + /* qwrap configuration + * 1 - This is qwrap configuration + * 0 - This is not qwrap + */ + __le32 qwrap_config; +} __packed; + /* strucutre describing host memory chunk. */ struct host_memory_chunk { /* id of the request that is passed up in service ready */ @@ -2412,6 +2627,11 @@ struct wmi_init_cmd_10_2 { struct wmi_host_mem_chunks mem_chunks; } __packed; +struct wmi_init_cmd_10_4 { + struct wmi_resource_config_10_4 resource_config; + struct wmi_host_mem_chunks mem_chunks; +} __packed; + struct wmi_chan_list_entry { __le16 freq; u8 phy_mode; /* valid for 10.2 only */ -- GitLab From 1c0929614ac429a32509307e790e813325562dc1 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:16 +0530 Subject: [PATCH 0316/7006] ath10k: handle 10.4 fw wmi mgmt rx event 10.4 firmware wmi mgmt rx event format differs from non 10.4 firmware and changing existing wmi mgmt rx event parsing function ath10k_wmi_op_pull_mgmt_rx_ev() for 10.4 would add more complex. This patch adds new function to receive any wmi rx event from 10.4 firmware and also introduce new function to parse wmi mgmt rx event. In addition, fw main branch service rdy event parsing function is linked in wmi ops table. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 64 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 15 +++++++ 2 files changed, 79 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6c51b20dc8c5d..9502032f46dcd 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2124,6 +2124,40 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_mgmt_rx_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_mgmt_rx_ev_arg *arg) +{ + struct wmi_10_4_mgmt_rx_event *ev; + struct wmi_10_4_mgmt_rx_hdr *ev_hdr; + size_t pull_len; + u32 msdu_len; + + ev = (struct wmi_10_4_mgmt_rx_event *)skb->data; + ev_hdr = &ev->hdr; + pull_len = sizeof(*ev); + + if (skb->len < pull_len) + return -EPROTO; + + skb_pull(skb, pull_len); + arg->channel = ev_hdr->channel; + arg->buf_len = ev_hdr->buf_len; + arg->status = ev_hdr->status; + arg->snr = ev_hdr->snr; + arg->phy_mode = ev_hdr->phy_mode; + arg->rate = ev_hdr->rate; + + msdu_len = __le32_to_cpu(arg->buf_len); + if (skb->len < msdu_len) + return -EPROTO; + + /* Make sure bytes added for padding are removed. */ + skb_trim(skb, msdu_len); + + return 0; +} + int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb) { struct wmi_mgmt_rx_ev_arg arg = {}; @@ -4267,6 +4301,33 @@ out: dev_kfree_skb(skb); } +static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) +{ + struct wmi_cmd_hdr *cmd_hdr; + enum wmi_10_4_event_id id; + + cmd_hdr = (struct wmi_cmd_hdr *)skb->data; + id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID); + + if (!skb_pull(skb, sizeof(struct wmi_cmd_hdr))) + goto out; + + trace_ath10k_wmi_event(ar, id, skb->data, skb->len); + + switch (id) { + case WMI_10_4_MGMT_RX_EVENTID: + ath10k_wmi_event_mgmt_rx(ar, skb); + /* mgmt_rx() owns the skb now! */ + return; + default: + ath10k_warn(ar, "Unknown eventid: %d\n", id); + break; + } + +out: + dev_kfree_skb(skb); +} + static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb) { int ret; @@ -6186,7 +6247,10 @@ static const struct wmi_ops wmi_10_2_4_ops = { }; static const struct wmi_ops wmi_10_4_ops = { + .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, + .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, }; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index dbb9f1c8c917b..b1bec031c1117 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2947,6 +2947,21 @@ struct wmi_mgmt_rx_event_v2 { u8 buf[0]; } __packed; +struct wmi_10_4_mgmt_rx_hdr { + __le32 channel; + __le32 snr; + u8 rssi_ctl[4]; + __le32 rate; + __le32 phy_mode; + __le32 buf_len; + __le32 status; +} __packed; + +struct wmi_10_4_mgmt_rx_event { + struct wmi_10_4_mgmt_rx_hdr hdr; + u8 buf[0]; +} __packed; + #define WMI_RX_STATUS_OK 0x00 #define WMI_RX_STATUS_ERR_CRC 0x01 #define WMI_RX_STATUS_ERR_DECRYPT 0x08 -- GitLab From b039941704452d8f89e83cba352b5c89a6ebf2ab Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:17 +0530 Subject: [PATCH 0317/7006] ath10k: adjust default peer limits if qcache enabled in 10.4 fw 10.4 firmware supports upto 512 clients when qcache feature is enabled. Make adjustment on default max peer count, active peers, number of tid in such case to meet qcache requirement. 10.4 fw has extra unit info flag NUM_UNITS_IS_NUM_ACTIVE_PEERS which is also handled in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.h | 6 ++++++ drivers/net/wireless/ath/ath10k/wmi.c | 27 +++++++++++++++++++++++---- drivers/net/wireless/ath/ath10k/wmi.h | 5 +++-- 3 files changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 52fc0249378be..568c5ea5561f7 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -360,6 +360,12 @@ enum ath10k_hw_rate_cck { #define TARGET_10_4_NUM_PEERS ((TARGET_10_4_NUM_STATIONS) + \ (TARGET_10_4_NUM_VDEVS)) #define TARGET_10_4_ACTIVE_PEERS 0 + +/* TODO: increase qcache max client limit to 512 after + * testing with 512 client. + */ +#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 256 +#define TARGET_10_4_QCACHE_ACTIVE_PEERS 50 #define TARGET_10_4_NUM_OFFLOAD_PEERS 0 #define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0 #define TARGET_10_4_NUM_PEER_KEYS 2 diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9502032f46dcd..62ea0bca03e19 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3826,20 +3826,39 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) return; } + if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) { + ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX + + TARGET_10_4_NUM_VDEVS; + ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS + + TARGET_10_4_NUM_VDEVS; + ar->num_tids = ar->num_active_peers * 2; + ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX; + } + + /* TODO: Adjust max peer count for cases like WMI_SERVICE_RATECTRL_CACHE + * and WMI_SERVICE_IRAM_TIDS, etc. + */ + for (i = 0; i < num_mem_reqs; ++i) { req_id = __le32_to_cpu(arg.mem_reqs[i]->req_id); num_units = __le32_to_cpu(arg.mem_reqs[i]->num_units); unit_size = __le32_to_cpu(arg.mem_reqs[i]->unit_size); num_unit_info = __le32_to_cpu(arg.mem_reqs[i]->num_unit_info); - if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) + if (num_unit_info & NUM_UNITS_IS_NUM_ACTIVE_PEERS) { + if (ar->num_active_peers) + num_units = ar->num_active_peers + 1; + else + num_units = ar->max_num_peers + 1; + } else if (num_unit_info & NUM_UNITS_IS_NUM_PEERS) { /* number of units to allocate is number of * peers, 1 extra for self peer on target */ /* this needs to be tied, host and target * can get out of sync */ - num_units = TARGET_10X_NUM_PEERS + 1; - else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) - num_units = TARGET_10X_NUM_VDEVS + 1; + num_units = ar->max_num_peers + 1; + } else if (num_unit_info & NUM_UNITS_IS_NUM_VDEVS) { + num_units = ar->max_num_vdevs + 1; + } ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mem_req_id %d num_units %d num_unit_info %d unit size %d actual units %d\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b1bec031c1117..b1e4932f97f9c 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2377,8 +2377,9 @@ struct wmi_resource_config_10_2 { __le32 feature_mask; } __packed; -#define NUM_UNITS_IS_NUM_VDEVS 0x1 -#define NUM_UNITS_IS_NUM_PEERS 0x2 +#define NUM_UNITS_IS_NUM_VDEVS BIT(0) +#define NUM_UNITS_IS_NUM_PEERS BIT(1) +#define NUM_UNITS_IS_NUM_ACTIVE_PEERS BIT(2) struct wmi_resource_config_10_4 { /* Number of virtual devices (VAPs) to support */ -- GitLab From d02e752f732a91e2a6de9a3547c682914ae0bbe7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:10:18 +0530 Subject: [PATCH 0318/7006] ath10k: handle 10.4 fw wmi ready event Reuse existing function ath10k_wmi_op_pull_rdy_ev() to parse WMI_10_4_READY_EVENTID and handle the same event in ath10k_wmi_10_4_op_rx(). Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 62ea0bca03e19..271ad2f86d24d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4338,6 +4338,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_mgmt_rx(ar, skb); /* mgmt_rx() owns the skb now! */ return; + case WMI_10_4_READY_EVENTID: + ath10k_wmi_event_ready(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6270,6 +6273,7 @@ static const struct wmi_ops wmi_10_4_ops = { .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, + .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, }; -- GitLab From b24fc6fc7c0f6425793fd46ccc4ea48f49447617 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 10:34:03 +0200 Subject: [PATCH 0319/7006] ath: DFS - limit number of potential PRI sequences In the PRI detector, after the current radar pulse has been checked agains existing PRI sequences, it is considered as part of a new potential sequence. Previously, the condition to accept a new sequence was to have at least the same number of pulses as the longest matching sequence. This was wrong, since it led to duplicates of PRI sequences. This patch changes the acceptance criteria for new potential sequences from 'at least' to 'more than' the longest existing. Detection performance remains unaffected, while the number of PRI sequences accounted at runtime (and with it CPU load) is reduced by up to 50%. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/dfs_pri_detector.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/dfs_pri_detector.c b/drivers/net/wireless/ath/dfs_pri_detector.c index 1b5ad1965607c..cc5c592fc4c00 100644 --- a/drivers/net/wireless/ath/dfs_pri_detector.c +++ b/drivers/net/wireless/ath/dfs_pri_detector.c @@ -273,7 +273,7 @@ static bool pseq_handler_create_sequences(struct pri_detector *pde, tmp_false_count++; } } - if (ps.count < min_count) + if (ps.count <= min_count) /* did not reach minimum count, drop sequence */ continue; -- GitLab From 33190ebfb1e846f97366a334e45b03caf4a65c84 Mon Sep 17 00:00:00 2001 From: Vladimir Kondratiev Date: Mon, 15 Jun 2015 17:42:32 +0300 Subject: [PATCH 0320/7006] wil6210: restart AP upon change in privacy settings privacy settings might change while AP is running. Inside wil_cfg80211_change_beacon(), detect change in privacy settings and handle it by stopping and re-starting the AP. Firmware cannot handle on-the-fly privacy settings change and so AP restart is required. Signed-off-by: Dedy Lansky Signed-off-by: Hamad Kadmany Signed-off-by: Vladimir Kondratiev Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/wil6210/cfg80211.c | 217 ++++++++++++-------- drivers/net/wireless/ath/wil6210/wil6210.h | 2 + 2 files changed, 135 insertions(+), 84 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c index c79cfe02ec80a..e4be2d9bbac40 100644 --- a/drivers/net/wireless/ath/wil6210/cfg80211.c +++ b/drivers/net/wireless/ath/wil6210/cfg80211.c @@ -736,6 +736,92 @@ static int wil_fix_bcon(struct wil6210_priv *wil, return rc; } +/* internal functions for device reset and starting AP */ +static int _wil_cfg80211_set_ies(struct wiphy *wiphy, + size_t probe_ies_len, const u8 *probe_ies, + size_t assoc_ies_len, const u8 *assoc_ies) + +{ + int rc; + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + + /* FW do not form regular beacon, so bcon IE's are not set + * For the DMG bcon, when it will be supported, bcon IE's will + * be reused; add something like: + * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, + * bcon->beacon_ies); + */ + rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, probe_ies_len, probe_ies); + if (rc) { + wil_err(wil, "set_ie(PROBE_RESP) failed\n"); + return rc; + } + + rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, assoc_ies_len, assoc_ies); + if (rc) { + wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); + return rc; + } + + return 0; +} + +static int _wil_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *ndev, + const u8 *ssid, size_t ssid_len, u32 privacy, + int bi, u8 chan, + size_t probe_ies_len, const u8 *probe_ies, + size_t assoc_ies_len, const u8 *assoc_ies, + u8 hidden_ssid) +{ + struct wil6210_priv *wil = wiphy_to_wil(wiphy); + int rc; + struct wireless_dev *wdev = ndev->ieee80211_ptr; + u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); + + wil_set_recovery_state(wil, fw_recovery_idle); + + mutex_lock(&wil->mutex); + + __wil_down(wil); + rc = __wil_up(wil); + if (rc) + goto out; + + rc = wmi_set_ssid(wil, ssid_len, ssid); + if (rc) + goto out; + + rc = _wil_cfg80211_set_ies(wiphy, probe_ies_len, probe_ies, + assoc_ies_len, assoc_ies); + if (rc) + goto out; + + wil->privacy = privacy; + wil->channel = chan; + wil->hidden_ssid = hidden_ssid; + + netif_carrier_on(ndev); + + rc = wmi_pcp_start(wil, bi, wmi_nettype, chan, hidden_ssid); + if (rc) + goto err_pcp_start; + + rc = wil_bcast_init(wil); + if (rc) + goto err_bcast; + + goto out; /* success */ + +err_bcast: + wmi_pcp_stop(wil); +err_pcp_start: + netif_carrier_off(ndev); +out: + mutex_unlock(&wil->mutex); + return rc; +} + static int wil_cfg80211_change_beacon(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_beacon_data *bcon) @@ -746,6 +832,7 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, const u8 *pr_ies = NULL; size_t pr_ies_len = 0; int rc; + u32 privacy = 0; wil_dbg_misc(wil, "%s()\n", __func__); wil_print_bcon_data(bcon); @@ -760,40 +847,41 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - /* FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); - if (rc) { - wil_err(wil, "set_ie(PROBE_RESP) failed\n"); - return rc; - } + if (pr_ies && cfg80211_find_ie(WLAN_EID_RSN, pr_ies, pr_ies_len)) + privacy = 1; - rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, - bcon->assocresp_ies_len, - bcon->assocresp_ies); - if (rc) { - wil_err(wil, "set_ie(ASSOC_RESP) failed\n"); - return rc; + /* in case privacy has changed, need to restart the AP */ + if (wil->privacy != privacy) { + struct wireless_dev *wdev = ndev->ieee80211_ptr; + + wil_dbg_misc(wil, "privacy changed %d=>%d. Restarting AP\n", + wil->privacy, privacy); + + rc = _wil_cfg80211_start_ap(wiphy, ndev, wdev->ssid, + wdev->ssid_len, privacy, + wdev->beacon_interval, + wil->channel, pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies, + wil->hidden_ssid); + } else { + rc = _wil_cfg80211_set_ies(wiphy, pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies); } - return 0; + return rc; } static int wil_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_ap_settings *info) { - int rc = 0; + int rc; struct wil6210_priv *wil = wiphy_to_wil(wiphy); - struct wireless_dev *wdev = ndev->ieee80211_ptr; struct ieee80211_channel *channel = info->chandef.chan; struct cfg80211_beacon_data *bcon = &info->beacon; struct cfg80211_crypto_settings *crypto = &info->crypto; - u8 wmi_nettype = wil_iftype_nl2wmi(wdev->iftype); struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp; size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); const u8 *pr_ies = NULL; @@ -807,6 +895,23 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, return -EINVAL; } + switch (info->hidden_ssid) { + case NL80211_HIDDEN_SSID_NOT_IN_USE: + hidden_ssid = WMI_HIDDEN_SSID_DISABLED; + break; + + case NL80211_HIDDEN_SSID_ZERO_LEN: + hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; + break; + + case NL80211_HIDDEN_SSID_ZERO_CONTENTS: + hidden_ssid = WMI_HIDDEN_SSID_CLEAR; + break; + + default: + wil_err(wil, "AP: Invalid hidden SSID %d\n", info->hidden_ssid); + return -EOPNOTSUPP; + } wil_dbg_misc(wil, "AP on Channel %d %d MHz, %s\n", channel->hw_value, channel->center_freq, info->privacy ? "secure" : "open"); wil_dbg_misc(wil, "Privacy: %d auth_type %d\n", @@ -830,70 +935,14 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy, wil_print_bcon_data(bcon); } - wil_set_recovery_state(wil, fw_recovery_idle); - - mutex_lock(&wil->mutex); - - __wil_down(wil); - rc = __wil_up(wil); - if (rc) - goto out; - - rc = wmi_set_ssid(wil, info->ssid_len, info->ssid); - if (rc) - goto out; - - /* IE's */ - /* bcon 'head IE's are not relevant for 60g band */ - /* - * FW do not form regular beacon, so bcon IE's are not set - * For the DMG bcon, when it will be supported, bcon IE's will - * be reused; add something like: - * wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->beacon_ies_len, - * bcon->beacon_ies); - */ - wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, pr_ies_len, pr_ies); - wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len, - bcon->assocresp_ies); - - wil->privacy = info->privacy; - - switch (info->hidden_ssid) { - case NL80211_HIDDEN_SSID_NOT_IN_USE: - hidden_ssid = WMI_HIDDEN_SSID_DISABLED; - break; - - case NL80211_HIDDEN_SSID_ZERO_LEN: - hidden_ssid = WMI_HIDDEN_SSID_SEND_EMPTY; - break; - - case NL80211_HIDDEN_SSID_ZERO_CONTENTS: - hidden_ssid = WMI_HIDDEN_SSID_CLEAR; - break; - - default: - rc = -EOPNOTSUPP; - goto out; - } - - netif_carrier_on(ndev); - - rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype, - channel->hw_value, hidden_ssid); - if (rc) - goto err_pcp_start; + rc = _wil_cfg80211_start_ap(wiphy, ndev, + info->ssid, info->ssid_len, info->privacy, + info->beacon_interval, channel->hw_value, + pr_ies_len, pr_ies, + bcon->assocresp_ies_len, + bcon->assocresp_ies, + hidden_ssid); - rc = wil_bcast_init(wil); - if (rc) - goto err_bcast; - - goto out; /* success */ -err_bcast: - wmi_pcp_stop(wil); -err_pcp_start: - netif_carrier_off(ndev); -out: - mutex_unlock(&wil->mutex); return rc; } diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index 275355d46a36f..c63e4a35eaa0f 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -559,6 +559,8 @@ struct wil6210_priv { /* profile */ u32 monitor_flags; u32 privacy; /* secure connection? */ + u8 hidden_ssid; /* relevant in AP mode */ + u16 channel; /* relevant in AP mode */ int sinfo_gen; u32 ap_isolate; /* no intra-BSS communication */ /* interrupt moderation */ -- GitLab From a03fee347cdcbf101820b2984366a37043ffc62b Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:20 +0530 Subject: [PATCH 0321/7006] ath10k: enhance swba event handler to adapt different size tim bitmap Due to 512 client support in 10.4 firmware, size of tim ie is going to be slightly higher than non 10.4 firmware. So, size of tim_bitmap what is carried in swba event from 10.4 firmware is bit higher. The only bottle neck to reuse existing swba handler ath10k_wmi_event_host_swba() for 10.4 is that code designed to deal with fixed size tim bitmap(ie, tim_info[].tim_bitmap in wmi_swba_ev_arg). This patch removes such size limitation and makes it more suitable to handle swba event which has different size tim bitmap. All existing swba event parsing functions are changed to adapt this change. Actual support to handle 10.4 swba event is added in next patch. Only preparation is made in this patch. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 18 +++++++- drivers/net/wireless/ath/ath10k/wmi.c | 53 +++++++++++++++++------ drivers/net/wireless/ath/ath10k/wmi.h | 10 ++++- 3 files changed, 66 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index 620b37b59784e..ced35a1e06750 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -709,6 +709,8 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, const void *ptr, void *data) { struct wmi_tlv_swba_parse *swba = data; + struct wmi_tim_info_arg *tim_info_arg; + const struct wmi_tim_info *tim_info_ev = ptr; if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO) return -EPROTO; @@ -716,7 +718,21 @@ static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len, if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info)) return -ENOBUFS; - swba->arg->tim_info[swba->n_tim++] = ptr; + if (__le32_to_cpu(tim_info_ev->tim_len) > + sizeof(tim_info_ev->tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + tim_info_arg = &swba->arg->tim_info[swba->n_tim]; + tim_info_arg->tim_len = tim_info_ev->tim_len; + tim_info_arg->tim_mcast = tim_info_ev->tim_mcast; + tim_info_arg->tim_bitmap = tim_info_ev->tim_bitmap; + tim_info_arg->tim_changed = tim_info_ev->tim_changed; + tim_info_arg->tim_num_ps_pending = tim_info_ev->tim_num_ps_pending; + + swba->n_tim++; + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 271ad2f86d24d..228c3dd6713a2 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -2874,33 +2874,42 @@ exit: static void ath10k_wmi_update_tim(struct ath10k *ar, struct ath10k_vif *arvif, struct sk_buff *bcn, - const struct wmi_tim_info *tim_info) + const struct wmi_tim_info_arg *tim_info) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data; struct ieee80211_tim_ie *tim; u8 *ies, *ie; u8 ie_len, pvm_len; __le32 t; - u32 v; + u32 v, tim_len; + + /* When FW reports 0 in tim_len, ensure atleast first byte + * in tim_bitmap is considered for pvm calculation. + */ + tim_len = tim_info->tim_len ? __le32_to_cpu(tim_info->tim_len) : 1; /* if next SWBA has no tim_changed the tim_bitmap is garbage. * we must copy the bitmap upon change and reuse it later */ if (__le32_to_cpu(tim_info->tim_changed)) { int i; - BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) != - sizeof(tim_info->tim_bitmap)); + if (sizeof(arvif->u.ap.tim_bitmap) < tim_len) { + ath10k_warn(ar, "SWBA TIM field is too big (%u), truncated it to %zu", + tim_len, sizeof(arvif->u.ap.tim_bitmap)); + tim_len = sizeof(arvif->u.ap.tim_bitmap); + } - for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) { + for (i = 0; i < tim_len; i++) { t = tim_info->tim_bitmap[i / 4]; v = __le32_to_cpu(t); arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF; } - /* FW reports either length 0 or 16 - * so we calculate this on our own */ + /* FW reports either length 0 or length based on max supported + * station. so we calculate this on our own + */ arvif->u.ap.tim_len = 0; - for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) + for (i = 0; i < tim_len; i++) if (arvif->u.ap.tim_bitmap[i]) arvif->u.ap.tim_len = i; @@ -2924,7 +2933,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, pvm_len = ie_len - 3; /* exclude dtim count, dtim period, bmap ctl */ if (pvm_len < arvif->u.ap.tim_len) { - int expand_size = sizeof(arvif->u.ap.tim_bitmap) - pvm_len; + int expand_size = tim_len - pvm_len; int move_size = skb_tail_pointer(bcn) - (ie + 2 + ie_len); void *next_ie = ie + 2 + ie_len; @@ -2939,7 +2948,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar, } } - if (pvm_len > sizeof(arvif->u.ap.tim_bitmap)) { + if (pvm_len > tim_len) { ath10k_warn(ar, "tim pvm length is too great (%d)\n", pvm_len); return; } @@ -3003,7 +3012,21 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) break; - arg->tim_info[i] = &ev->bcn_info[i].tim_info; + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len; + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info; i++; } @@ -3016,7 +3039,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) struct wmi_swba_ev_arg arg = {}; u32 map; int i = -1; - const struct wmi_tim_info *tim_info; + const struct wmi_tim_info_arg *tim_info; const struct wmi_p2p_noa_info *noa_info; struct ath10k_vif *arvif; struct sk_buff *bcn; @@ -3045,7 +3068,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) break; } - tim_info = arg.tim_info[i]; + tim_info = &arg.tim_info[i]; noa_info = arg.noa_info[i]; ath10k_dbg(ar, ATH10K_DBG_MGMT, @@ -3060,6 +3083,10 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) __le32_to_cpu(tim_info->tim_bitmap[1]), __le32_to_cpu(tim_info->tim_bitmap[0])); + /* TODO: Only first 4 word from tim_bitmap is dumped. + * Extend debug code to dump full tim_bitmap. + */ + arvif = ath10k_get_arvif(ar, vdev_id); if (arvif == NULL) { ath10k_warn(ar, "no vif for vdev_id %d found\n", diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index b1e4932f97f9c..7c4a15f1ae77d 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5160,6 +5160,14 @@ struct wmi_tim_info { __le32 tim_num_ps_pending; } __packed; +struct wmi_tim_info_arg { + __le32 tim_len; + __le32 tim_mcast; + const __le32 *tim_bitmap; + __le32 tim_changed; + __le32 tim_num_ps_pending; +} __packed; + /* Maximum number of NOA Descriptors supported */ #define WMI_P2P_MAX_NOA_DESCRIPTORS 4 #define WMI_P2P_OPPPS_ENABLE_BIT BIT(0) @@ -5710,7 +5718,7 @@ struct wmi_peer_kick_ev_arg { struct wmi_swba_ev_arg { __le32 vdev_map; - const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV]; + struct wmi_tim_info_arg tim_info[WMI_MAX_AP_VDEV]; const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV]; }; -- GitLab From 3cec3be3d101bfec7136841cbb9b32ca49ac0328 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:21 +0530 Subject: [PATCH 0322/7006] ath10k: handle 10.4 firmware wmi swba event 10.4 firmware swba event payload has space to accommodate upto 512 client traffic indication info & one p2p noa descriptor. It's is not matching with exiting swba event format defined for non 10.4 firmware. Non 10.4 firmware swba event format is designed to support only upto only 128 client and four p2p notice of absence descriptor. following changes are done in this patch to enable ath10k to handle 10.4 firmware swba event, - link generic ath10k_wmi_event_host_swba() to handle 10.4 swba event in 10.4 wmi rx handler. - add 10.4 specific swba event structure wmi_10_4_host_swba_event. - new function ath10k_wmi_10_4_op_pull_swba_ev() to parse 10.4 swba event. - increase tim_bitmap[] size in ath10k_vif to 64 to hold 512 station power save state. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 4 +- drivers/net/wireless/ath/ath10k/wmi.c | 61 ++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 41 +++++++++++++++++ 3 files changed, 104 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 58b02ae817062..86c4015270e9d 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -328,8 +328,8 @@ struct ath10k_vif { u32 uapsd; } sta; struct { - /* 127 stations; wmi limit */ - u8 tim_bitmap[16]; + /* 512 stations */ + u8 tim_bitmap[64]; u8 tim_len; u32 ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 228c3dd6713a2..7f9800ac15ec3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3034,6 +3034,63 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_swba_ev_arg *arg) +{ + struct wmi_10_4_host_swba_event *ev = (void *)skb->data; + u32 map, tim_len; + size_t i; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->vdev_map = ev->vdev_map; + + for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) { + if (!(map & BIT(0))) + continue; + + /* If this happens there were some changes in firmware and + * ath10k should update the max size of tim_info array. + */ + if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info))) + break; + + if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) > + sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) { + ath10k_warn(ar, "refusing to parse invalid swba structure\n"); + return -EPROTO; + } + + tim_len = __le32_to_cpu(ev->bcn_info[i].tim_info.tim_len); + if (tim_len) { + /* Exclude 4 byte guard length */ + tim_len -= 4; + arg->tim_info[i].tim_len = __cpu_to_le32(tim_len); + } else { + arg->tim_info[i].tim_len = 0; + } + + arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast; + arg->tim_info[i].tim_bitmap = + ev->bcn_info[i].tim_info.tim_bitmap; + arg->tim_info[i].tim_changed = + ev->bcn_info[i].tim_info.tim_changed; + arg->tim_info[i].tim_num_ps_pending = + ev->bcn_info[i].tim_info.tim_num_ps_pending; + + /* 10.4 firmware doesn't have p2p support. notice of absence + * info can be ignored for now. + */ + + i++; + } + + return 0; +} + void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) { struct wmi_swba_ev_arg arg = {}; @@ -4368,6 +4425,9 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_4_HOST_SWBA_EVENTID: + ath10k_wmi_event_host_swba(ar, skb); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6299,6 +6359,7 @@ static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, .gen_init = ath10k_wmi_10_4_op_gen_init, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 7c4a15f1ae77d..395742d3ff615 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -5199,6 +5199,47 @@ struct wmi_host_swba_event { struct wmi_bcn_info bcn_info[0]; } __packed; +/* 16 words = 512 client + 1 word = for guard */ +#define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17 + +struct wmi_10_4_tim_info { + __le32 tim_len; + __le32 tim_mcast; + __le32 tim_bitmap[WMI_10_4_TIM_BITMAP_ARRAY_SIZE]; + __le32 tim_changed; + __le32 tim_num_ps_pending; +} __packed; + +#define WMI_10_4_P2P_MAX_NOA_DESCRIPTORS 1 + +struct wmi_10_4_p2p_noa_info { + /* Bit 0 - Flag to indicate an update in NOA schedule + * Bits 7-1 - Reserved + */ + u8 changed; + /* NOA index */ + u8 index; + /* Bit 0 - Opp PS state of the AP + * Bits 1-7 - Ctwindow in TUs + */ + u8 ctwindow_oppps; + /* Number of NOA descriptors */ + u8 num_descriptors; + + struct wmi_p2p_noa_descriptor + noa_descriptors[WMI_10_4_P2P_MAX_NOA_DESCRIPTORS]; +} __packed; + +struct wmi_10_4_bcn_info { + struct wmi_10_4_tim_info tim_info; + struct wmi_10_4_p2p_noa_info p2p_noa_info; +} __packed; + +struct wmi_10_4_host_swba_event { + __le32 vdev_map; + struct wmi_10_4_bcn_info bcn_info[0]; +} __packed; + #define WMI_MAX_AP_VDEV 16 struct wmi_tbtt_offset_event { -- GitLab From 373b48cfe77ff8c0ff94564a280dbfea56e769d4 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:22 +0530 Subject: [PATCH 0323/7006] ath10k: enable vdev and peer related operations for 10.4 fw Most of existing vdev and peer related functions (vdev create, vdev delete, vdev start, peer create, peer delete, peer flush, etc) are reusable for 10.4 firmware. Link those general vdev and peer functions to 10.4 wmi function table. Existing general pktlog enable/disable, dbglog configuration functions are reusable for 10.4 and add them also in wmi function table. Also handle few wmi events (sevice rdy, echo, dbg msg, tbtt offset update, dbg print) in ath10k_wmi_10_4_op_rx(). wow event is not applicable in 10.4 firmware, have it under not implemented print. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 62 +++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7f9800ac15ec3..a83a3636842b0 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -4422,12 +4422,40 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) ath10k_wmi_event_mgmt_rx(ar, skb); /* mgmt_rx() owns the skb now! */ return; + case WMI_10_4_ECHO_EVENTID: + ath10k_wmi_event_echo(ar, skb); + break; + case WMI_10_4_DEBUG_MESG_EVENTID: + ath10k_wmi_event_debug_mesg(ar, skb); + break; + case WMI_10_4_SERVICE_READY_EVENTID: + ath10k_wmi_event_service_ready(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; + case WMI_10_4_PEER_STA_KICKOUT_EVENTID: + ath10k_wmi_event_peer_sta_kickout(ar, skb); + break; case WMI_10_4_HOST_SWBA_EVENTID: ath10k_wmi_event_host_swba(ar, skb); break; + case WMI_10_4_TBTTOFFSET_UPDATE_EVENTID: + ath10k_wmi_event_tbttoffset_update(ar, skb); + break; + case WMI_10_4_DEBUG_PRINT_EVENTID: + ath10k_wmi_event_debug_print(ar, skb); + break; + case WMI_10_4_VDEV_START_RESP_EVENTID: + ath10k_wmi_event_vdev_start_resp(ar, skb); + break; + case WMI_10_4_VDEV_STOPPED_EVENTID: + ath10k_wmi_event_vdev_stopped(ar, skb); + break; + case WMI_10_4_WOW_WAKEUP_HOST_EVENTID: + ath10k_dbg(ar, ATH10K_DBG_WMI, + "received event id %d not implemented\n", id); + break; default: ath10k_warn(ar, "Unknown eventid: %d\n", id); break; @@ -6359,10 +6387,44 @@ static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, + .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev, .pull_rdy = ath10k_wmi_op_pull_rdy_ev, + + .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend, + .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume, + .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, + .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, .gen_init = ath10k_wmi_10_4_op_gen_init, + .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, + .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, + .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, + .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop, + .gen_vdev_up = ath10k_wmi_op_gen_vdev_up, + .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, + .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, + .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_peer_create = ath10k_wmi_op_gen_peer_create, + .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, + .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, + .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param, + .gen_set_psmode = ath10k_wmi_op_gen_set_psmode, + .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps, + .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps, + .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list, + .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma, + .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm, + .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang, + .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx, + .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg, + .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable, + .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable, + .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode, + + /* shared with 10.2 */ + .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc, }; int ath10k_wmi_attach(struct ath10k *ar) -- GitLab From b2297baa273b2a73d7408a97d0163c5a0dfccf8c Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:23 +0530 Subject: [PATCH 0324/7006] ath10k: add scan support for 10.4 fw Existing non 10.4 firmware scan related events and commands are matching with 10.4 firmware (except chan info event). Link general start scan,stop scan, scan channel list configuration functions to 10.4 wmi function table and add a new handler to parse 10.4 specific chan info event. 10.4 firmware has extra scan completion reason WMI_SCAN_REASON_INTERNAL_FAILURE and new scan event WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT compared to previous firmware versions. These things are added in respective enum. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 42 +++++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/wmi.h | 36 +++++++++++++++++------ 2 files changed, 69 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index a83a3636842b0..9f73c5784f459 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -1923,6 +1923,8 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, return "completed [preempted]"; case WMI_SCAN_REASON_TIMEDOUT: return "completed [timedout]"; + case WMI_SCAN_REASON_INTERNAL_FAILURE: + return "completed [internal err]"; case WMI_SCAN_REASON_MAX: break; } @@ -1937,6 +1939,10 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type, return "preempted"; case WMI_SCAN_EVENT_START_FAILED: return "start failed"; + case WMI_SCAN_EVENT_RESTARTED: + return "restarted"; + case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: + return "foreign channel exit"; default: return "unknown"; } @@ -2012,6 +2018,8 @@ int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb) break; case WMI_SCAN_EVENT_DEQUEUED: case WMI_SCAN_EVENT_PREEMPTED: + case WMI_SCAN_EVENT_RESTARTED: + case WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT: default: break; } @@ -2318,6 +2326,29 @@ static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb, return 0; } +static int ath10k_wmi_10_4_op_pull_ch_info_ev(struct ath10k *ar, + struct sk_buff *skb, + struct wmi_ch_info_ev_arg *arg) +{ + struct wmi_10_4_chan_info_event *ev = (void *)skb->data; + + if (skb->len < sizeof(*ev)) + return -EPROTO; + + skb_pull(skb, sizeof(*ev)); + arg->err_code = ev->err_code; + arg->freq = ev->freq; + arg->cmd_flags = ev->cmd_flags; + arg->noise_floor = ev->noise_floor; + arg->rx_clear_count = ev->rx_clear_count; + arg->cycle_count = ev->cycle_count; + arg->chan_tx_pwr_range = ev->chan_tx_pwr_range; + arg->chan_tx_pwr_tp = ev->chan_tx_pwr_tp; + arg->rx_frame_count = ev->rx_frame_count; + + return 0; +} + void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb) { struct wmi_ch_info_ev_arg arg = {}; @@ -4431,6 +4462,12 @@ static void ath10k_wmi_10_4_op_rx(struct ath10k *ar, struct sk_buff *skb) case WMI_10_4_SERVICE_READY_EVENTID: ath10k_wmi_event_service_ready(ar, skb); break; + case WMI_10_4_SCAN_EVENTID: + ath10k_wmi_event_scan(ar, skb); + break; + case WMI_10_4_CHAN_INFO_EVENTID: + ath10k_wmi_event_chan_info(ar, skb); + break; case WMI_10_4_READY_EVENTID: ath10k_wmi_event_ready(ar, skb); break; @@ -6386,7 +6423,10 @@ static const struct wmi_ops wmi_10_2_4_ops = { static const struct wmi_ops wmi_10_4_ops = { .rx = ath10k_wmi_10_4_op_rx, .map_svc = wmi_10_4_svc_map, + + .pull_scan = ath10k_wmi_op_pull_scan_ev, .pull_mgmt_rx = ath10k_wmi_10_4_op_pull_mgmt_rx_ev, + .pull_ch_info = ath10k_wmi_10_4_op_pull_ch_info_ev, .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev, .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev, .pull_swba = ath10k_wmi_10_4_op_pull_swba_ev, @@ -6398,6 +6438,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd, .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param, .gen_init = ath10k_wmi_10_4_op_gen_init, + .gen_start_scan = ath10k_wmi_op_gen_start_scan, + .gen_stop_scan = ath10k_wmi_op_gen_stop_scan, .gen_vdev_create = ath10k_wmi_op_gen_vdev_create, .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete, .gen_vdev_start = ath10k_wmi_op_gen_vdev_start, diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 395742d3ff615..6e806cb7ebe22 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -2879,15 +2879,17 @@ enum wmi_bss_filter { }; enum wmi_scan_event_type { - WMI_SCAN_EVENT_STARTED = 0x1, - WMI_SCAN_EVENT_COMPLETED = 0x2, - WMI_SCAN_EVENT_BSS_CHANNEL = 0x4, - WMI_SCAN_EVENT_FOREIGN_CHANNEL = 0x8, - WMI_SCAN_EVENT_DEQUEUED = 0x10, - WMI_SCAN_EVENT_PREEMPTED = 0x20, /* possibly by high-prio scan */ - WMI_SCAN_EVENT_START_FAILED = 0x40, - WMI_SCAN_EVENT_RESTARTED = 0x80, - WMI_SCAN_EVENT_MAX = 0x8000 + WMI_SCAN_EVENT_STARTED = BIT(0), + WMI_SCAN_EVENT_COMPLETED = BIT(1), + WMI_SCAN_EVENT_BSS_CHANNEL = BIT(2), + WMI_SCAN_EVENT_FOREIGN_CHANNEL = BIT(3), + WMI_SCAN_EVENT_DEQUEUED = BIT(4), + /* possibly by high-prio scan */ + WMI_SCAN_EVENT_PREEMPTED = BIT(5), + WMI_SCAN_EVENT_START_FAILED = BIT(6), + WMI_SCAN_EVENT_RESTARTED = BIT(7), + WMI_SCAN_EVENT_FOREIGN_CHANNEL_EXIT = BIT(8), + WMI_SCAN_EVENT_MAX = BIT(15), }; enum wmi_scan_completion_reason { @@ -2895,6 +2897,7 @@ enum wmi_scan_completion_reason { WMI_SCAN_REASON_CANCELLED, WMI_SCAN_REASON_PREEMPTED, WMI_SCAN_REASON_TIMEDOUT, + WMI_SCAN_REASON_INTERNAL_FAILURE, WMI_SCAN_REASON_MAX, }; @@ -5564,6 +5567,18 @@ struct wmi_chan_info_event { __le32 cycle_count; } __packed; +struct wmi_10_4_chan_info_event { + __le32 err_code; + __le32 freq; + __le32 cmd_flags; + __le32 noise_floor; + __le32 rx_clear_count; + __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; +} __packed; + struct wmi_peer_sta_kickout_event { struct wmi_mac_addr peer_macaddr; } __packed; @@ -5744,6 +5759,9 @@ struct wmi_ch_info_ev_arg { __le32 noise_floor; __le32 rx_clear_count; __le32 cycle_count; + __le32 chan_tx_pwr_range; + __le32 chan_tx_pwr_tp; + __le32 rx_frame_count; }; struct wmi_vdev_start_ev_arg { -- GitLab From 721ad3ca7956ce66e11fdcb187769130486feb28 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:24 +0530 Subject: [PATCH 0325/7006] ath10k: add 10.4 fw specific htt msg definitions New htt event table is added for 10.4 firmware. Following new htt events are available only 10.4. adding this to generic htt event table, HTT_T2H_MSG_TYPE_EN_STATS, HTT_T2H_MSG_TYPE_TX_FETCH_IND, HTT_T2H_MSG_TYPE_TX_FETCH_CONF, HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/htt.c | 41 ++++++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt.h | 36 +++++++++++++++++++++ drivers/net/wireless/ath/ath10k/htt_rx.c | 4 +++ drivers/net/wireless/ath/ath10k/hw.h | 2 ++ 5 files changed, 84 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 020ac9f101686..7ef960792dbc9 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1121,6 +1121,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS; ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS; ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; + ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6da6ef26143af..6f71f94939fa5 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -102,6 +102,43 @@ static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = { [HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, }; +static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = { + [HTT_10_4_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF, + [HTT_10_4_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH, + [HTT_10_4_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP, + [HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP, + [HTT_10_4_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA, + [HTT_10_4_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA, + [HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND, + [HTT_10_4_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG, + [HTT_10_4_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF, + [HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND, + [HTT_10_4_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND, + [HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND] = + HTT_T2H_MSG_TYPE_TX_INSPECT_IND, + [HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] = + HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION, + [HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE, + [HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] = + HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND, + [HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] = + HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND, + [HTT_10_4_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST, + [HTT_10_4_T2H_MSG_TYPE_EN_STATS] = HTT_T2H_MSG_TYPE_EN_STATS, + [HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] = + HTT_T2H_MSG_TYPE_TX_FETCH_IND, + [HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] = + HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + [HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] = + HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, + [HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] = + HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, +}; + int ath10k_htt_connect(struct ath10k_htt *htt) { struct ath10k_htc_svc_conn_req conn_req; @@ -147,6 +184,10 @@ int ath10k_htt_init(struct ath10k *ar) 2; /* ip4 dscp or ip6 priority */ switch (ar->htt.op_version) { + case ATH10K_FW_HTT_OP_VERSION_10_4: + ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types; + ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS; + break; case ATH10K_FW_HTT_OP_VERSION_10_1: ar->htt.t2h_msg_types = htt_10x_t2h_msg_types; ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 7e8a0d8356637..8e64ace0119b4 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -349,6 +349,38 @@ enum htt_tlv_t2h_msg_type { HTT_TLV_T2H_NUM_MSGS }; +enum htt_10_4_t2h_msg_type { + HTT_10_4_T2H_MSG_TYPE_VERSION_CONF = 0x0, + HTT_10_4_T2H_MSG_TYPE_RX_IND = 0x1, + HTT_10_4_T2H_MSG_TYPE_RX_FLUSH = 0x2, + HTT_10_4_T2H_MSG_TYPE_PEER_MAP = 0x3, + HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP = 0x4, + HTT_10_4_T2H_MSG_TYPE_RX_ADDBA = 0x5, + HTT_10_4_T2H_MSG_TYPE_RX_DELBA = 0x6, + HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND = 0x7, + HTT_10_4_T2H_MSG_TYPE_PKTLOG = 0x8, + HTT_10_4_T2H_MSG_TYPE_STATS_CONF = 0x9, + HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND = 0xa, + HTT_10_4_T2H_MSG_TYPE_SEC_IND = 0xb, + HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc, + HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd, + HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND = 0xe, + HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE = 0xf, + HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0x10, + HTT_10_4_T2H_MSG_TYPE_RX_PN_IND = 0x11, + HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x12, + HTT_10_4_T2H_MSG_TYPE_TEST = 0x13, + HTT_10_4_T2H_MSG_TYPE_EN_STATS = 0x14, + HTT_10_4_T2H_MSG_TYPE_AGGR_CONF = 0x15, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND = 0x16, + HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF = 0x17, + HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18, + /* 0x19 to 0x2f are reserved */ + HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND = 0x30, + /* keep this last */ + HTT_10_4_T2H_NUM_MSGS +}; + enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_VERSION_CONF, HTT_T2H_MSG_TYPE_RX_IND, @@ -375,6 +407,10 @@ enum htt_t2h_msg_type { HTT_T2H_MSG_TYPE_AGGR_CONF, HTT_T2H_MSG_TYPE_STATS_NOUPLOAD, HTT_T2H_MSG_TYPE_TEST, + HTT_T2H_MSG_TYPE_EN_STATS, + HTT_T2H_MSG_TYPE_TX_FETCH_IND, + HTT_T2H_MSG_TYPE_TX_FETCH_CONF, + HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND, /* keep this last */ HTT_T2H_NUM_MSGS }; diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index 7399e45a016ef..d7d118328f31b 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -2072,6 +2072,10 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb) break; case HTT_T2H_MSG_TYPE_CHAN_CHANGE: break; + case HTT_T2H_MSG_TYPE_EN_STATS: + case HTT_T2H_MSG_TYPE_TX_FETCH_IND: + case HTT_T2H_MSG_TYPE_TX_FETCH_CONF: + case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND: default: ath10k_warn(ar, "htt event (%d) not handled\n", resp->hdr.msg_type); diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h index 568c5ea5561f7..9172285175461 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h @@ -153,6 +153,8 @@ enum ath10k_fw_htt_op_version { ATH10K_FW_HTT_OP_VERSION_TLV = 3, + ATH10K_FW_HTT_OP_VERSION_10_4 = 4, + /* keep last */ ATH10K_FW_HTT_OP_VERSION_MAX, }; -- GitLab From cf36fef08a85c815d9358e1571d3d83da02474f7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:25 +0530 Subject: [PATCH 0326/7006] ath10k: advertise 10.4 fw ap and sta iface combination to mac80211 10.4 fw supports upto 16 interface in ap mode and 1 interface in station mode, overall total interfaces supported are 16 interfaces. Populate this limit in wiphy->iface_combinations. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index a8561d1f26e3f..0f3c17c0c8f83 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6620,6 +6620,33 @@ static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { }, }; +static const struct ieee80211_iface_limit ath10k_10_4_if_limits[] = { + { + .max = 1, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 16, + .types = BIT(NL80211_IFTYPE_AP) + }, +}; + +static const struct ieee80211_iface_combination ath10k_10_4_if_comb[] = { + { + .limits = ath10k_10_4_if_limits, + .n_limits = ARRAY_SIZE(ath10k_10_4_if_limits), + .max_interfaces = 16, + .num_different_channels = 1, + .beacon_int_infra_match = true, +#ifdef CONFIG_ATH10K_DFS_CERTIFIED + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), +#endif + }, +}; + static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) { struct ieee80211_sta_vht_cap vht_cap = {0}; @@ -6944,6 +6971,9 @@ int ath10k_mac_register(struct ath10k *ar) ARRAY_SIZE(ath10k_10x_if_comb); break; case ATH10K_FW_WMI_OP_VERSION_10_4: + ar->hw->wiphy->iface_combinations = ath10k_10_4_if_comb; + ar->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(ath10k_10_4_if_comb); break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: -- GitLab From 5c8726eca3e4080615f09328d1f28013b6e5c837 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:26 +0530 Subject: [PATCH 0327/7006] ath10k: set max spatial stream to 4 for 10.4 fw 10.4 fw supports upto 4 spatial stream. Limit max spatial stream to 4 for 10.4 firmware and to 3 for non 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 4 ++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/wmi.c | 6 +++--- drivers/net/wireless/ath/ath10k/wmi.h | 3 ++- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7ef960792dbc9..79d40d9042967 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -1095,6 +1095,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_10_1: case ATH10K_FW_WMI_OP_VERSION_10_2: @@ -1104,6 +1105,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->max_num_vdevs = TARGET_10X_NUM_VDEVS; ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_TLV: ar->max_num_peers = TARGET_TLV_NUM_PEERS; @@ -1114,6 +1116,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->wow.max_num_patterns = TARGET_TLV_NUM_WOW_PATTERNS; ar->fw_stats_req_mask = WMI_STAT_PDEV | WMI_STAT_VDEV | WMI_STAT_PEER; + ar->max_spatial_stream = WMI_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_10_4: ar->max_num_peers = TARGET_10_4_NUM_PEERS; @@ -1123,6 +1126,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar) ar->num_tids = TARGET_10_4_TGT_NUM_TIDS; ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC; ar->fw_stats_req_mask = WMI_STAT_PEER; + ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM; break; case ATH10K_FW_WMI_OP_VERSION_UNSET: case ATH10K_FW_WMI_OP_VERSION_MAX: diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 86c4015270e9d..f0811d0a8a7cf 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -546,6 +546,7 @@ struct ath10k { u32 ht_cap_info; u32 vht_cap_info; u32 num_rf_chains; + u32 max_spatial_stream; /* protected by conf_mutex */ bool ani_enabled; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 9f73c5784f459..638332e969319 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3915,10 +3915,10 @@ void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb) if (ar->fw_api == 1 && ar->fw_version_build > 636) set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features); - if (ar->num_rf_chains > WMI_MAX_SPATIAL_STREAM) { + if (ar->num_rf_chains > ar->max_spatial_stream) { ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n", - ar->num_rf_chains, WMI_MAX_SPATIAL_STREAM); - ar->num_rf_chains = WMI_MAX_SPATIAL_STREAM; + ar->num_rf_chains, ar->max_spatial_stream); + ar->num_rf_chains = ar->max_spatial_stream; } ar->supp_tx_chainmask = (1 << ar->num_rf_chains) - 1; diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h index 6e806cb7ebe22..0d4efc9c57964 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h @@ -1747,7 +1747,8 @@ enum wmi_channel_change_cause { /* Indicate reason for channel switch */ #define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13) -#define WMI_MAX_SPATIAL_STREAM 3 +#define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */ +#define WMI_10_4_MAX_SPATIAL_STREAM 4 /* HT Capabilities*/ #define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */ -- GitLab From d9156b5f6849a1b1185ac62790f36df013b1ade6 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Mon, 22 Jun 2015 20:22:27 +0530 Subject: [PATCH 0328/7006] ath10k: configure frag desc memory to target for qca99X0 Pre qca99X0 chipsets follows the model where dynamically allocate memory for frag desc on getting new skb for TX. But, this is not going to be the case in qca99X0. It expects frag desc memory to be allocated at boot time and let the driver to reuse allocated memory after every TX completion. So there won't be any dynamic frag memory memory allocation in qca99X0 during data transmission. qca99X0 hardware doesn't need fragment desc address to be programmed in msdu descriptor for every data transaction. It needs to know only starting address of fragment descriptor at the time of the boot. During data transmission, qca99X0 hardware can retrieve corresponding frag addr by adding programmed frag desc base addr + msdu id. Allocate continuous fragment descriptor memory (same size as number of descriptor) at the time of target initialization and configure allocated dma address to the target via HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG. How this is allocated continuous memory is going to be used is not covered in this patch. It just allocates memory and hand over to firmware. If we don't do it at init time, qca99X0 will stall when firmware tries to do TX. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 1 + drivers/net/wireless/ath/ath10k/core.h | 6 ++ drivers/net/wireless/ath/ath10k/htt.c | 4 ++ drivers/net/wireless/ath/ath10k/htt.h | 11 ++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 76 +++++++++++++++++++++++- 5 files changed, 96 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 79d40d9042967..f79fa6c67ebc3 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -111,6 +111,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .otp_exe_param = 0x00000700, + .continuous_frag_desc = true, .fw = { .dir = QCA99X0_HW_2_0_FW_DIR, .fw = QCA99X0_HW_2_0_FW_FILE, diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index f0811d0a8a7cf..2e5c935579c46 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -582,6 +582,12 @@ struct ath10k { */ bool has_shifted_cc_wraparound; + /* Some of chip expects fragment descriptor to be continuous + * memory for any TX operation. Set continuous_frag_desc flag + * for the hardware which have such requirement. + */ + bool continuous_frag_desc; + struct ath10k_hw_params_fw { const char *dir; const char *fw; diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c index 6f71f94939fa5..4474c3e839db4 100644 --- a/drivers/net/wireless/ath/ath10k/htt.c +++ b/drivers/net/wireless/ath/ath10k/htt.c @@ -249,5 +249,9 @@ int ath10k_htt_setup(struct ath10k_htt *htt) if (status) return status; + status = ath10k_htt_send_frag_desc_bank_cfg(htt); + if (status) + return status; + return ath10k_htt_send_rx_ring_cfg_ll(htt); } diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8e64ace0119b4..8bdf1e7dd1718 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -87,6 +87,11 @@ struct htt_data_tx_desc_frag { __le32 len; } __packed; +struct htt_msdu_ext_desc { + __le32 tso_flag[4]; + struct htt_data_tx_desc_frag frags[6]; +}; + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, @@ -1466,6 +1471,11 @@ struct ath10k_htt { /* rx_status template */ struct ieee80211_rx_status rx_status; + + struct { + dma_addr_t paddr; + struct htt_msdu_ext_desc *vaddr; + } frag_desc; }; #define RX_HTT_HDR_STATUS_LEN 64 @@ -1533,6 +1543,7 @@ void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb); void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb); int ath10k_htt_h2t_ver_req_msg(struct ath10k_htt *htt); int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie); +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt); int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt); int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt, u8 max_subfrms_ampdu, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index a60ef7d1d5fcb..148d5b607c3cf 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -84,6 +84,7 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id) int ath10k_htt_tx_alloc(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; + int ret, size; ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n", htt->max_num_pending_tx); @@ -94,11 +95,31 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt) htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev, sizeof(struct ath10k_htt_txbuf), 4, 0); if (!htt->tx_pool) { - idr_destroy(&htt->pending_tx); - return -ENOMEM; + ret = -ENOMEM; + goto free_idr_pending_tx; + } + + if (!ar->hw_params.continuous_frag_desc) + goto skip_frag_desc_alloc; + + size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc); + htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size, + &htt->frag_desc.paddr, + GFP_DMA); + if (!htt->frag_desc.vaddr) { + ath10k_warn(ar, "failed to alloc fragment desc memory\n"); + ret = -ENOMEM; + goto free_tx_pool; } +skip_frag_desc_alloc: return 0; + +free_tx_pool: + dma_pool_destroy(htt->tx_pool); +free_idr_pending_tx: + idr_destroy(&htt->pending_tx); + return ret; } static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) @@ -121,9 +142,18 @@ static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx) void ath10k_htt_tx_free(struct ath10k_htt *htt) { + int size; + idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar); idr_destroy(&htt->pending_tx); dma_pool_destroy(htt->tx_pool); + + if (htt->frag_desc.vaddr) { + size = htt->max_num_pending_tx * + sizeof(struct htt_msdu_ext_desc); + dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr, + htt->frag_desc.paddr); + } } void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb) @@ -201,6 +231,48 @@ int ath10k_htt_h2t_stats_req(struct ath10k_htt *htt, u8 mask, u64 cookie) return 0; } +int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) +{ + struct ath10k *ar = htt->ar; + struct sk_buff *skb; + struct htt_cmd *cmd; + int ret, size; + + if (!ar->hw_params.continuous_frag_desc) + return 0; + + if (!htt->frag_desc.paddr) { + ath10k_warn(ar, "invalid frag desc memory\n"); + return -EINVAL; + } + + size = sizeof(cmd->hdr) + sizeof(cmd->frag_desc_bank_cfg); + skb = ath10k_htc_alloc_skb(ar, size); + if (!skb) + return -ENOMEM; + + skb_put(skb, size); + cmd = (struct htt_cmd *)skb->data; + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG; + cmd->frag_desc_bank_cfg.info = 0; + cmd->frag_desc_bank_cfg.num_banks = 1; + cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); + cmd->frag_desc_bank_cfg.bank_base_addrs[0] = + __cpu_to_le32(htt->frag_desc.paddr); + cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = + __cpu_to_le16(htt->max_num_pending_tx - 1); + + ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb); + if (ret) { + ath10k_warn(ar, "failed to send frag desc bank cfg request: %d\n", + ret); + dev_kfree_skb_any(skb); + return ret; + } + + return 0; +} + int ath10k_htt_send_rx_ring_cfg_ll(struct ath10k_htt *htt) { struct ath10k *ar = htt->ar; -- GitLab From 0e975980d435d58df2d430d688b8c18778b42218 Mon Sep 17 00:00:00 2001 From: Peter Antoine Date: Tue, 23 Jun 2015 08:18:49 +0100 Subject: [PATCH 0329/7006] drm: Turn off Legacy Context Functions The context functions are not used by the i915 driver and should not be used by modeset drivers. These driver functions contain several bugs and security holes. This change makes these functions optional can be turned on by a setting, they are turned off by default for modeset driver with the exception of the nouvea driver that may require them with an old version of libdrm. The previous attempt was commit 7c510133d93dd6f15ca040733ba7b2891ed61fd1 Author: Daniel Vetter Date: Thu Aug 8 15:41:21 2013 +0200 drm: mark context support as a legacy subsystem but this had to be reverted commit c21eb21cb50d58e7cbdcb8b9e7ff68b85cfa5095 Author: Dave Airlie Date: Fri Sep 20 08:32:59 2013 +1000 Revert "drm: mark context support as a legacy subsystem" v2: remove returns from void function, and formatting (Daniel Vetter) v3: - s/Nova/nouveau/ in the commit message, and add references to the previous attempts - drop the part touching the drm hw lock, that should be a separate patch. Signed-off-by: Peter Antoine (v2) Cc: Peter Antoine (v2) Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_context.c | 48 +++++++++++++++++++++++++++ drivers/gpu/drm/drm_drv.c | 13 +++++--- drivers/gpu/drm/nouveau/nouveau_drm.c | 3 +- include/drm/drmP.h | 23 +++++++------ 4 files changed, 70 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index 9b23525c0ed04..32958dabd7b0f 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -53,6 +53,10 @@ struct drm_ctx_list { */ void drm_legacy_ctxbitmap_free(struct drm_device * dev, int ctx_handle) { + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return; + mutex_lock(&dev->struct_mutex); idr_remove(&dev->ctx_idr, ctx_handle); mutex_unlock(&dev->struct_mutex); @@ -87,6 +91,10 @@ static int drm_legacy_ctxbitmap_next(struct drm_device * dev) */ int drm_legacy_ctxbitmap_init(struct drm_device * dev) { + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + idr_init(&dev->ctx_idr); return 0; } @@ -101,6 +109,10 @@ int drm_legacy_ctxbitmap_init(struct drm_device * dev) */ void drm_legacy_ctxbitmap_cleanup(struct drm_device * dev) { + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return; + mutex_lock(&dev->struct_mutex); idr_destroy(&dev->ctx_idr); mutex_unlock(&dev->struct_mutex); @@ -119,6 +131,10 @@ void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file) { struct drm_ctx_list *pos, *tmp; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return; + mutex_lock(&dev->ctxlist_mutex); list_for_each_entry_safe(pos, tmp, &dev->ctxlist, head) { @@ -161,6 +177,10 @@ int drm_legacy_getsareactx(struct drm_device *dev, void *data, struct drm_local_map *map; struct drm_map_list *_entry; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->struct_mutex); map = idr_find(&dev->ctx_idr, request->ctx_id); @@ -205,6 +225,10 @@ int drm_legacy_setsareactx(struct drm_device *dev, void *data, struct drm_local_map *map = NULL; struct drm_map_list *r_list = NULL; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + mutex_lock(&dev->struct_mutex); list_for_each_entry(r_list, &dev->maplist, head) { if (r_list->map @@ -305,6 +329,10 @@ int drm_legacy_resctx(struct drm_device *dev, void *data, struct drm_ctx ctx; int i; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if (res->count >= DRM_RESERVED_CONTEXTS) { memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { @@ -335,6 +363,10 @@ int drm_legacy_addctx(struct drm_device *dev, void *data, struct drm_ctx_list *ctx_entry; struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + ctx->handle = drm_legacy_ctxbitmap_next(dev); if (ctx->handle == DRM_KERNEL_CONTEXT) { /* Skip kernel's context and get a new one. */ @@ -378,6 +410,10 @@ int drm_legacy_getctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + /* This is 0, because we don't handle any context flags */ ctx->flags = 0; @@ -400,6 +436,10 @@ int drm_legacy_switchctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + DRM_DEBUG("%d\n", ctx->handle); return drm_context_switch(dev, dev->last_context, ctx->handle); } @@ -420,6 +460,10 @@ int drm_legacy_newctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + DRM_DEBUG("%d\n", ctx->handle); drm_context_switch_complete(dev, file_priv, ctx->handle); @@ -442,6 +486,10 @@ int drm_legacy_rmctx(struct drm_device *dev, void *data, { struct drm_ctx *ctx = data; + if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && + drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + DRM_DEBUG("%d\n", ctx->handle); if (ctx->handle != DRM_KERNEL_CONTEXT) { if (dev->driver->context_dtor) diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index b7bf4ce8c012b..838657503113c 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -582,11 +582,14 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (drm_ht_create(&dev->map_hash, 12)) goto err_minors; - ret = drm_legacy_ctxbitmap_init(dev); - if (ret) { - DRM_ERROR("Cannot allocate memory for context bitmap.\n"); - goto err_ht; - } + if (drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) || + !drm_core_check_feature(dev, DRIVER_MODESET)) + ret = drm_legacy_ctxbitmap_init(dev); + if (ret) { + DRM_ERROR( + "Cannot allocate memory for context bitmap.\n"); + goto err_ht; + } if (drm_core_check_feature(dev, DRIVER_GEM)) { ret = drm_gem_init(dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 89049335b7383..9624b3827c349 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -941,7 +941,8 @@ static struct drm_driver driver_stub = { .driver_features = DRIVER_USE_AGP | - DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER, + DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | + DRIVER_KMS_LEGACY_CONTEXT, .load = nouveau_drm_load, .unload = nouveau_drm_unload, diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 48db6a56975f5..3dc7c16c18f26 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -137,17 +137,18 @@ void drm_err(const char *format, ...); /*@{*/ /* driver capabilities and requirements mask */ -#define DRIVER_USE_AGP 0x1 -#define DRIVER_PCI_DMA 0x8 -#define DRIVER_SG 0x10 -#define DRIVER_HAVE_DMA 0x20 -#define DRIVER_HAVE_IRQ 0x40 -#define DRIVER_IRQ_SHARED 0x80 -#define DRIVER_GEM 0x1000 -#define DRIVER_MODESET 0x2000 -#define DRIVER_PRIME 0x4000 -#define DRIVER_RENDER 0x8000 -#define DRIVER_ATOMIC 0x10000 +#define DRIVER_USE_AGP 0x1 +#define DRIVER_PCI_DMA 0x8 +#define DRIVER_SG 0x10 +#define DRIVER_HAVE_DMA 0x20 +#define DRIVER_HAVE_IRQ 0x40 +#define DRIVER_IRQ_SHARED 0x80 +#define DRIVER_GEM 0x1000 +#define DRIVER_MODESET 0x2000 +#define DRIVER_PRIME 0x4000 +#define DRIVER_RENDER 0x8000 +#define DRIVER_ATOMIC 0x10000 +#define DRIVER_KMS_LEGACY_CONTEXT 0x20000 /***********************************************************************/ /** \name Macros to make printk easier */ -- GitLab From ba6976c129a571464fccbbcf866f4f93d91113c0 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Jun 2015 11:22:36 +0200 Subject: [PATCH 0330/7006] drm: Convert drm_legacy_ctxbitmap_init to void return type It can't fail really. Also remove the redundant kms check Peter added. Cc: Peter Antoine Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_context.c | 5 ++--- drivers/gpu/drm/drm_drv.c | 10 +--------- drivers/gpu/drm/drm_legacy.h | 2 +- 3 files changed, 4 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_context.c b/drivers/gpu/drm/drm_context.c index 32958dabd7b0f..192a5f9eeb742 100644 --- a/drivers/gpu/drm/drm_context.c +++ b/drivers/gpu/drm/drm_context.c @@ -89,14 +89,13 @@ static int drm_legacy_ctxbitmap_next(struct drm_device * dev) * * Initialise the drm_device::ctx_idr */ -int drm_legacy_ctxbitmap_init(struct drm_device * dev) +void drm_legacy_ctxbitmap_init(struct drm_device * dev) { if (!drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) && drm_core_check_feature(dev, DRIVER_MODESET)) - return -EINVAL; + return; idr_init(&dev->ctx_idr); - return 0; } /** diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index 838657503113c..9b51fe11ff192 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -582,14 +582,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, if (drm_ht_create(&dev->map_hash, 12)) goto err_minors; - if (drm_core_check_feature(dev, DRIVER_KMS_LEGACY_CONTEXT) || - !drm_core_check_feature(dev, DRIVER_MODESET)) - ret = drm_legacy_ctxbitmap_init(dev); - if (ret) { - DRM_ERROR( - "Cannot allocate memory for context bitmap.\n"); - goto err_ht; - } + drm_legacy_ctxbitmap_init(dev); if (drm_core_check_feature(dev, DRIVER_GEM)) { ret = drm_gem_init(dev); @@ -603,7 +596,6 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver, err_ctxbitmap: drm_legacy_ctxbitmap_cleanup(dev); -err_ht: drm_ht_remove(&dev->map_hash); err_minors: drm_minor_free(dev, DRM_MINOR_LEGACY); diff --git a/drivers/gpu/drm/drm_legacy.h b/drivers/gpu/drm/drm_legacy.h index c1dc61473db58..9b731786e4db2 100644 --- a/drivers/gpu/drm/drm_legacy.h +++ b/drivers/gpu/drm/drm_legacy.h @@ -42,7 +42,7 @@ struct drm_file; #define DRM_KERNEL_CONTEXT 0 #define DRM_RESERVED_CONTEXTS 1 -int drm_legacy_ctxbitmap_init(struct drm_device *dev); +void drm_legacy_ctxbitmap_init(struct drm_device *dev); void drm_legacy_ctxbitmap_cleanup(struct drm_device *dev); void drm_legacy_ctxbitmap_free(struct drm_device *dev, int ctx_handle); void drm_legacy_ctxbitmap_flush(struct drm_device *dev, struct drm_file *file); -- GitLab From da168d81b44898404d281d5dbe70154ab5f117c1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 23 Jun 2015 11:34:21 +0200 Subject: [PATCH 0331/7006] drm: Reject DRI1 hw lock ioctl functions for kms drivers I've done some extensive history digging across libdrm, mesa and xf86-video-{intel,nouveau,ati}. The only potential user of this with kms drivers I could find was ttmtest, which once used drmGetLock still. But that mistake was quickly fixed up. Even the intel xvmc library (which otherwise was really good with using dri1 stuff in kms mode) managed to never take the hw lock for dri2 (and hence kms). Hence it should be save to unconditionally disallow this. Cc: Peter Antoine Reviewed-by: Peter Antoine Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_lock.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/drm_lock.c b/drivers/gpu/drm/drm_lock.c index f861361a635e0..4924d381b6642 100644 --- a/drivers/gpu/drm/drm_lock.c +++ b/drivers/gpu/drm/drm_lock.c @@ -61,6 +61,9 @@ int drm_legacy_lock(struct drm_device *dev, void *data, struct drm_master *master = file_priv->master; int ret = 0; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + ++file_priv->lock_count; if (lock->context == DRM_KERNEL_CONTEXT) { @@ -153,6 +156,9 @@ int drm_legacy_unlock(struct drm_device *dev, void *data, struct drm_file *file_ struct drm_lock *lock = data; struct drm_master *master = file_priv->master; + if (drm_core_check_feature(dev, DRIVER_MODESET)) + return -EINVAL; + if (lock->context == DRM_KERNEL_CONTEXT) { DRM_ERROR("Process %d using kernel context %d\n", task_pid_nr(current), lock->context); -- GitLab From 0d0b49c51e0c1b5f4facbf7191db82b39ac99b96 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 1 Jul 2015 14:05:09 +0200 Subject: [PATCH 0332/7006] drm: Remove useless blank line Blank lines at the end of a function definition are not useful, so get rid of it. Signed-off-by: Thierry Reding Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b69ed97d447c9..0bf46d5ee221b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4298,7 +4298,6 @@ void drm_property_unreference_blob(struct drm_property_blob *blob) mutex_unlock(&dev->mode_config.blob_lock); else might_lock(&dev->mode_config.blob_lock); - } EXPORT_SYMBOL(drm_property_unreference_blob); -- GitLab From a9cc54eeba635d2feb2ed4bf43d4ea4e08e7e0a9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 24 Jun 2015 08:59:24 +0200 Subject: [PATCH 0333/7006] drm/atomic: Update old_fb after setting a property. This change updates the old_fb pointer only after acquiring the plane lock, if there are no properties the fb cannot have been changed either, so this works out correctly. Found in a discussion with Rob Clark. Cc: Rob Clark Signed-off-by: Maarten Lankhorst Reviewed-by: Rob Clark Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f6f2fb58eb37f..bd7f723c708ee 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1472,12 +1472,6 @@ retry: goto fail; } - if (obj->type == DRM_MODE_OBJECT_PLANE) { - plane = obj_to_plane(obj); - plane_mask |= (1 << drm_plane_index(plane)); - plane->old_fb = plane->fb; - } - if (get_user(count_props, count_props_ptr + copied_objs)) { ret = -EFAULT; goto fail; @@ -1514,6 +1508,12 @@ retry: copied_props++; } + + if (obj->type == DRM_MODE_OBJECT_PLANE && count_props) { + plane = obj_to_plane(obj); + plane_mask |= (1 << drm_plane_index(plane)); + plane->old_fb = plane->fb; + } } if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { -- GitLab From 793dfa59bcfde9d642295480674926827e9adcfc Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Thu, 18 Jun 2015 17:25:53 +0300 Subject: [PATCH 0334/7006] drm/i915/bxt: mask off the DPLL state checker bits we don't program For the purpose of state checking we only care about the DPLL HW flags that we actually program, so mask off the ones that we don't. This fixes one set of DPLL state check failures. Signed-off-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index cef9709fa2bae..15fc66a8da78b 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -2854,19 +2854,38 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, return false; hw_state->ebb0 = I915_READ(BXT_PORT_PLL_EBB_0(port)); + hw_state->ebb0 &= PORT_PLL_P1_MASK | PORT_PLL_P2_MASK; + hw_state->ebb4 = I915_READ(BXT_PORT_PLL_EBB_4(port)); hw_state->ebb4 &= PORT_PLL_10BIT_CLK_ENABLE; hw_state->pll0 = I915_READ(BXT_PORT_PLL(port, 0)); + hw_state->pll0 &= PORT_PLL_M2_MASK; + hw_state->pll1 = I915_READ(BXT_PORT_PLL(port, 1)); + hw_state->pll1 &= PORT_PLL_N_MASK; + hw_state->pll2 = I915_READ(BXT_PORT_PLL(port, 2)); + hw_state->pll2 &= PORT_PLL_M2_FRAC_MASK; + hw_state->pll3 = I915_READ(BXT_PORT_PLL(port, 3)); + hw_state->pll3 &= PORT_PLL_M2_FRAC_ENABLE; + hw_state->pll6 = I915_READ(BXT_PORT_PLL(port, 6)); + hw_state->pll6 &= PORT_PLL_PROP_COEFF_MASK | + PORT_PLL_INT_COEFF_MASK | + PORT_PLL_GAIN_CTL_MASK; + hw_state->pll8 = I915_READ(BXT_PORT_PLL(port, 8)); + hw_state->pll8 &= PORT_PLL_TARGET_CNT_MASK; + hw_state->pll9 = I915_READ(BXT_PORT_PLL(port, 9)); hw_state->pll9 &= PORT_PLL_LOCK_THRESHOLD_MASK; hw_state->pll10 = I915_READ(BXT_PORT_PLL(port, 10)); + hw_state->pll10 &= PORT_PLL_DCO_AMP_OVR_EN_H | + PORT_PLL_DCO_AMP_MASK; + /* * While we write to the group register to program all lanes at once we * can read only lane registers. We configure all lanes the same way, so @@ -2877,6 +2896,7 @@ static bool bxt_ddi_pll_get_hw_state(struct drm_i915_private *dev_priv, DRM_DEBUG_DRIVER("lane stagger config different for lane 01 (%08x) and 23 (%08x)\n", hw_state->pcsdw12, I915_READ(BXT_PORT_PCS_DW12_LN23(port))); + hw_state->pcsdw12 &= LANE_STAGGER_MASK | LANESTAGGER_STRAP_OVRD; return true; } -- GitLab From 79bbcc299fca92ba3558c4966e6ad52ee1052d89 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Tue, 30 Jun 2015 12:40:55 +0100 Subject: [PATCH 0335/7006] drm/i915: Reserve space improvements An earlier patch was added to reserve space in the ring buffer for the commands issued during 'add_request()'. The initial version was pessimistic in the way it handled buffer wrapping and would cause premature wraps and thus waste ring space. This patch updates the code to better handle the wrap case. It no longer enforces that the space being asked for and the reserved space are a single contiguous block. Instead, it allows the reserve to be on the far end of a wrap operation. It still guarantees that the space is available so when the wrap occurs, no wait will happen. Thus the wrap cannot fail which is the whole point of the exercise. Also fixed a merge failure with some comments from the original patch. v2: Incorporated suggestion by David Gordon to move the wrap code inside the prepare function and thus allow a single combined wait_for_space() call rather than doing one before the wrap and another after. This also makes the prepare code much simpler and easier to follow. v3: Fix for 'effective_size' vs 'size' during ring buffer remainder calculations (spotted by Tomas Elf). For: VIZ-5115 CC: Daniel Vetter Signed-off-by: John Harrison Reviewed-by: Tomas Elf Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 73 ++++++++++---------- drivers/gpu/drm/i915/intel_ringbuffer.c | 90 ++++++++++++++----------- drivers/gpu/drm/i915/intel_ringbuffer.h | 4 +- 3 files changed, 90 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8cac4cab1666f..22e9f85f40e43 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -661,12 +661,12 @@ static int logical_ring_wait_for_space(struct drm_i915_gem_request *req, unsigned space; int ret; - /* The whole point of reserving space is to not wait! */ - WARN_ON(ringbuf->reserved_in_use); - if (intel_ring_space(ringbuf) >= bytes) return 0; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + list_for_each_entry(target, &ring->request_list, list) { /* * The request queue is per-engine, so can contain requests @@ -716,22 +716,11 @@ intel_logical_ring_advance_and_submit(struct drm_i915_gem_request *request) execlists_context_queue(request); } -static int logical_ring_wrap_buffer(struct drm_i915_gem_request *req) +static void __wrap_ring_buffer(struct intel_ringbuffer *ringbuf) { - struct intel_ringbuffer *ringbuf = req->ringbuf; uint32_t __iomem *virt; int rem = ringbuf->size - ringbuf->tail; - /* Can't wrap if space has already been reserved! */ - WARN_ON(ringbuf->reserved_in_use); - - if (ringbuf->space < rem) { - int ret = logical_ring_wait_for_space(req, rem); - - if (ret) - return ret; - } - virt = ringbuf->virtual_start + ringbuf->tail; rem /= 4; while (rem--) @@ -739,40 +728,50 @@ static int logical_ring_wrap_buffer(struct drm_i915_gem_request *req) ringbuf->tail = 0; intel_ring_update_space(ringbuf); - - return 0; } static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) { struct intel_ringbuffer *ringbuf = req->ringbuf; - int ret; - - /* - * Add on the reserved size to the request to make sure that after - * the intended commands have been emitted, there is guaranteed to - * still be enough free space to send them to the hardware. - */ - if (!ringbuf->reserved_in_use) - bytes += ringbuf->reserved_size; - - if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { - ret = logical_ring_wrap_buffer(req); - if (unlikely(ret)) - return ret; + int remain_usable = ringbuf->effective_size - ringbuf->tail; + int remain_actual = ringbuf->size - ringbuf->tail; + int ret, total_bytes, wait_bytes = 0; + bool need_wrap = false; - if(ringbuf->reserved_size) { - uint32_t size = ringbuf->reserved_size; + if (ringbuf->reserved_in_use) + total_bytes = bytes; + else + total_bytes = bytes + ringbuf->reserved_size; - intel_ring_reserved_space_cancel(ringbuf); - intel_ring_reserved_space_reserve(ringbuf, size); + if (unlikely(bytes > remain_usable)) { + /* + * Not enough space for the basic request. So need to flush + * out the remainder and then wait for base + reserved. + */ + wait_bytes = remain_actual + total_bytes; + need_wrap = true; + } else { + if (unlikely(total_bytes > remain_usable)) { + /* + * The base request will fit but the reserved space + * falls off the end. So only need to to wait for the + * reserved size after flushing out the remainder. + */ + wait_bytes = remain_actual + ringbuf->reserved_size; + need_wrap = true; + } else if (total_bytes > ringbuf->space) { + /* No wrapping required, just waiting. */ + wait_bytes = total_bytes; } } - if (unlikely(ringbuf->space < bytes)) { - ret = logical_ring_wait_for_space(req, bytes); + if (wait_bytes) { + ret = logical_ring_wait_for_space(req, wait_bytes); if (unlikely(ret)) return ret; + + if (need_wrap) + __wrap_ring_buffer(ringbuf); } return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index af7c12ed0ba7d..e39c8912f673e 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2121,12 +2121,12 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) unsigned space; int ret; - /* The whole point of reserving space is to not wait! */ - WARN_ON(ringbuf->reserved_in_use); - if (intel_ring_space(ringbuf) >= n) return 0; + /* The whole point of reserving space is to not wait! */ + WARN_ON(ringbuf->reserved_in_use); + list_for_each_entry(request, &ring->request_list, list) { space = __intel_ring_space(request->postfix, ringbuf->tail, ringbuf->size); @@ -2145,21 +2145,11 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n) return 0; } -static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) +static void __wrap_ring_buffer(struct intel_ringbuffer *ringbuf) { uint32_t __iomem *virt; - struct intel_ringbuffer *ringbuf = ring->buffer; int rem = ringbuf->size - ringbuf->tail; - /* Can't wrap if space has already been reserved! */ - WARN_ON(ringbuf->reserved_in_use); - - if (ringbuf->space < rem) { - int ret = ring_wait_for_space(ring, rem); - if (ret) - return ret; - } - virt = ringbuf->virtual_start + ringbuf->tail; rem /= 4; while (rem--) @@ -2167,8 +2157,6 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring) ringbuf->tail = 0; intel_ring_update_space(ringbuf); - - return 0; } int intel_ring_idle(struct intel_engine_cs *ring) @@ -2238,9 +2226,21 @@ void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf) void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf) { WARN_ON(!ringbuf->reserved_in_use); - WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size, - "request reserved size too small: %d vs %d!\n", - ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size); + if (ringbuf->tail > ringbuf->reserved_tail) { + WARN(ringbuf->tail > ringbuf->reserved_tail + ringbuf->reserved_size, + "request reserved size too small: %d vs %d!\n", + ringbuf->tail - ringbuf->reserved_tail, ringbuf->reserved_size); + } else { + /* + * The ring was wrapped while the reserved space was in use. + * That means that some unknown amount of the ring tail was + * no-op filled and skipped. Thus simply adding the ring size + * to the tail and doing the above space check will not work. + * Rather than attempt to track how much tail was skipped, + * it is much simpler to say that also skipping the sanity + * check every once in a while is not a big issue. + */ + } ringbuf->reserved_size = 0; ringbuf->reserved_in_use = false; @@ -2249,33 +2249,45 @@ void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf) static int __intel_ring_prepare(struct intel_engine_cs *ring, int bytes) { struct intel_ringbuffer *ringbuf = ring->buffer; - int ret; - - /* - * Add on the reserved size to the request to make sure that after - * the intended commands have been emitted, there is guaranteed to - * still be enough free space to send them to the hardware. - */ - if (!ringbuf->reserved_in_use) - bytes += ringbuf->reserved_size; - - if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) { - ret = intel_wrap_ring_buffer(ring); - if (unlikely(ret)) - return ret; + int remain_usable = ringbuf->effective_size - ringbuf->tail; + int remain_actual = ringbuf->size - ringbuf->tail; + int ret, total_bytes, wait_bytes = 0; + bool need_wrap = false; - if(ringbuf->reserved_size) { - uint32_t size = ringbuf->reserved_size; + if (ringbuf->reserved_in_use) + total_bytes = bytes; + else + total_bytes = bytes + ringbuf->reserved_size; - intel_ring_reserved_space_cancel(ringbuf); - intel_ring_reserved_space_reserve(ringbuf, size); + if (unlikely(bytes > remain_usable)) { + /* + * Not enough space for the basic request. So need to flush + * out the remainder and then wait for base + reserved. + */ + wait_bytes = remain_actual + total_bytes; + need_wrap = true; + } else { + if (unlikely(total_bytes > remain_usable)) { + /* + * The base request will fit but the reserved space + * falls off the end. So only need to to wait for the + * reserved size after flushing out the remainder. + */ + wait_bytes = remain_actual + ringbuf->reserved_size; + need_wrap = true; + } else if (total_bytes > ringbuf->space) { + /* No wrapping required, just waiting. */ + wait_bytes = total_bytes; } } - if (unlikely(ringbuf->space < bytes)) { - ret = ring_wait_for_space(ring, bytes); + if (wait_bytes) { + ret = ring_wait_for_space(ring, wait_bytes); if (unlikely(ret)) return ret; + + if (need_wrap) + __wrap_ring_buffer(ringbuf); } return 0; diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 0e2bbc6a3f8b0..304cac4caf1c0 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -473,7 +473,6 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf) * will always have sufficient room to do its stuff. The request creation * code calls this automatically. */ -int intel_ring_reserve_space(struct drm_i915_gem_request *request); void intel_ring_reserved_space_reserve(struct intel_ringbuffer *ringbuf, int size); /* Cancel the reservation, e.g. because the request is being discarded. */ void intel_ring_reserved_space_cancel(struct intel_ringbuffer *ringbuf); @@ -482,4 +481,7 @@ void intel_ring_reserved_space_use(struct intel_ringbuffer *ringbuf); /* Finish with the reserved space - for use by i915_add_request() only. */ void intel_ring_reserved_space_end(struct intel_ringbuffer *ringbuf); +/* Legacy ringbuffer specific portion of reservation code: */ +int intel_ring_reserve_space(struct drm_i915_gem_request *request); + #endif /* _INTEL_RINGBUFFER_H_ */ -- GitLab From 2e906beac6be0116c557f96d1c07cb7a955f8059 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Jun 2015 18:16:37 +0300 Subject: [PATCH 0336/7006] drm/i915/gtt: Reorder page alloc/free/init functions Maintain base page handling functions in order of alloc, free, init. No functional changes. v2: s/Introduce/Maintain (Michel) v3: Rebase Cc: Michel Thierry Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 166 ++++++++++++++-------------- 1 file changed, 83 insertions(+), 83 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index b94eebe81fd83..ef3019c88eb79 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -384,24 +384,6 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, fill_page_dma(dev, p, v); } -static void free_pt(struct drm_device *dev, struct i915_page_table *pt) -{ - cleanup_px(dev, pt); - kfree(pt->used_ptes); - kfree(pt); -} - -static void gen8_initialize_pt(struct i915_address_space *vm, - struct i915_page_table *pt) -{ - gen8_pte_t scratch_pte; - - scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, true); - - fill_px(vm->dev, pt, scratch_pte); -} - static struct i915_page_table *alloc_pt(struct drm_device *dev) { struct i915_page_table *pt; @@ -433,13 +415,35 @@ fail_bitmap: return ERR_PTR(ret); } -static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) +static void free_pt(struct drm_device *dev, struct i915_page_table *pt) { - if (px_page(pd)) { - cleanup_px(dev, pd); - kfree(pd->used_pdes); - kfree(pd); - } + cleanup_px(dev, pt); + kfree(pt->used_ptes); + kfree(pt); +} + +static void gen8_initialize_pt(struct i915_address_space *vm, + struct i915_page_table *pt) +{ + gen8_pte_t scratch_pte; + + scratch_pte = gen8_pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true); + + fill_px(vm->dev, pt, scratch_pte); +} + +static void gen6_initialize_pt(struct i915_address_space *vm, + struct i915_page_table *pt) +{ + gen6_pte_t scratch_pte; + + WARN_ON(px_dma(vm->scratch_page) == 0); + + scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), + I915_CACHE_LLC, true, 0); + + fill32_px(vm->dev, pt, scratch_pte); } static struct i915_page_directory *alloc_pd(struct drm_device *dev) @@ -470,6 +474,61 @@ fail_bitmap: return ERR_PTR(ret); } +static void free_pd(struct drm_device *dev, struct i915_page_directory *pd) +{ + if (px_page(pd)) { + cleanup_px(dev, pd); + kfree(pd->used_pdes); + kfree(pd); + } +} + +static void gen8_initialize_pd(struct i915_address_space *vm, + struct i915_page_directory *pd) +{ + gen8_pde_t scratch_pde; + + scratch_pde = gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC); + + fill_px(vm->dev, pd, scratch_pde); +} + +static int alloc_scratch_page(struct i915_address_space *vm) +{ + struct i915_page_scratch *sp; + int ret; + + WARN_ON(vm->scratch_page); + + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (sp == NULL) + return -ENOMEM; + + ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); + if (ret) { + kfree(sp); + return ret; + } + + set_pages_uc(px_page(sp), 1); + + vm->scratch_page = sp; + + return 0; +} + +static void free_scratch_page(struct i915_address_space *vm) +{ + struct i915_page_scratch *sp = vm->scratch_page; + + set_pages_wb(px_page(sp), 1); + + cleanup_px(vm->dev, sp); + kfree(sp); + + vm->scratch_page = NULL; +} + /* Broadwell Page Directory Pointer Descriptors */ static int gen8_write_pdp(struct drm_i915_gem_request *req, unsigned entry, @@ -609,16 +668,6 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_px(ppgtt, pt_vaddr); } -static void gen8_initialize_pd(struct i915_address_space *vm, - struct i915_page_directory *pd) -{ - gen8_pde_t scratch_pde; - - scratch_pde = gen8_pde_encode(px_dma(vm->scratch_pt), I915_CACHE_LLC); - - fill_px(vm->dev, pd, scratch_pde); -} - static void gen8_free_page_tables(struct drm_device *dev, struct i915_page_directory *pd) { @@ -1274,19 +1323,6 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm, kunmap_px(ppgtt, pt_vaddr); } -static void gen6_initialize_pt(struct i915_address_space *vm, - struct i915_page_table *pt) -{ - gen6_pte_t scratch_pte; - - WARN_ON(px_dma(vm->scratch_page) == 0); - - scratch_pte = vm->pte_encode(px_dma(vm->scratch_page), - I915_CACHE_LLC, true, 0); - - fill32_px(vm->dev, pt, scratch_pte); -} - static int gen6_alloc_va_range(struct i915_address_space *vm, uint64_t start_in, uint64_t length_in) { @@ -2126,42 +2162,6 @@ void i915_global_gtt_cleanup(struct drm_device *dev) vm->cleanup(vm); } -static int alloc_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp; - int ret; - - WARN_ON(vm->scratch_page); - - sp = kzalloc(sizeof(*sp), GFP_KERNEL); - if (sp == NULL) - return -ENOMEM; - - ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); - if (ret) { - kfree(sp); - return ret; - } - - set_pages_uc(px_page(sp), 1); - - vm->scratch_page = sp; - - return 0; -} - -static void free_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp = vm->scratch_page; - - set_pages_wb(px_page(sp), 1); - - cleanup_px(vm->dev, sp); - kfree(sp); - - vm->scratch_page = NULL; -} - static unsigned int gen6_get_total_gtt_size(u16 snb_gmch_ctl) { snb_gmch_ctl >>= SNB_GMCH_GGMS_SHIFT; -- GitLab From 4ad2af1ed1e972704e1dbc8e7716cd3394a27385 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Jun 2015 18:16:39 +0300 Subject: [PATCH 0337/7006] drm/i915/gtt: Return struct i915_scratch_page from alloc_scratch Every other alloc_* function return the pointer to the page they alloc. Follow the convention with scratch page also. Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 78 ++++++++++++++--------------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index ef3019c88eb79..a4ec1c6f56525 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -384,6 +384,35 @@ static void fill_page_dma_32(struct drm_device *dev, struct i915_page_dma *p, fill_page_dma(dev, p, v); } +static struct i915_page_scratch *alloc_scratch_page(struct drm_device *dev) +{ + struct i915_page_scratch *sp; + int ret; + + sp = kzalloc(sizeof(*sp), GFP_KERNEL); + if (sp == NULL) + return ERR_PTR(-ENOMEM); + + ret = __setup_page_dma(dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); + if (ret) { + kfree(sp); + return ERR_PTR(ret); + } + + set_pages_uc(px_page(sp), 1); + + return sp; +} + +static void free_scratch_page(struct drm_device *dev, + struct i915_page_scratch *sp) +{ + set_pages_wb(px_page(sp), 1); + + cleanup_px(dev, sp); + kfree(sp); +} + static struct i915_page_table *alloc_pt(struct drm_device *dev) { struct i915_page_table *pt; @@ -493,42 +522,6 @@ static void gen8_initialize_pd(struct i915_address_space *vm, fill_px(vm->dev, pd, scratch_pde); } -static int alloc_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp; - int ret; - - WARN_ON(vm->scratch_page); - - sp = kzalloc(sizeof(*sp), GFP_KERNEL); - if (sp == NULL) - return -ENOMEM; - - ret = __setup_page_dma(vm->dev, px_base(sp), GFP_DMA32 | __GFP_ZERO); - if (ret) { - kfree(sp); - return ret; - } - - set_pages_uc(px_page(sp), 1); - - vm->scratch_page = sp; - - return 0; -} - -static void free_scratch_page(struct i915_address_space *vm) -{ - struct i915_page_scratch *sp = vm->scratch_page; - - set_pages_wb(px_page(sp), 1); - - cleanup_px(vm->dev, sp); - kfree(sp); - - vm->scratch_page = NULL; -} - /* Broadwell Page Directory Pointer Descriptors */ static int gen8_write_pdp(struct drm_i915_gem_request *req, unsigned entry, @@ -2244,8 +2237,8 @@ static int ggtt_probe_common(struct drm_device *dev, size_t gtt_size) { struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_page_scratch *scratch_page; phys_addr_t gtt_phys_addr; - int ret; /* For Modern GENs the PTEs and register space are split in the BAR */ gtt_phys_addr = pci_resource_start(dev->pdev, 0) + @@ -2267,14 +2260,17 @@ static int ggtt_probe_common(struct drm_device *dev, return -ENOMEM; } - ret = alloc_scratch_page(&dev_priv->gtt.base); - if (ret) { + scratch_page = alloc_scratch_page(dev); + if (IS_ERR(scratch_page)) { DRM_ERROR("Scratch setup failed\n"); /* iounmap will also get called at remove, but meh */ iounmap(dev_priv->gtt.gsm); + return PTR_ERR(scratch_page); } - return ret; + dev_priv->gtt.base.scratch_page = scratch_page; + + return 0; } /* The GGTT and PPGTT need a private PPAT setup in order to handle cacheability @@ -2446,7 +2442,7 @@ static void gen6_gmch_remove(struct i915_address_space *vm) struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base); iounmap(gtt->gsm); - free_scratch_page(vm); + free_scratch_page(vm->dev, vm->scratch_page); } static int i915_gmch_probe(struct drm_device *dev, -- GitLab From ca1543be2c4233fbc266bf66f4320806e61e05dd Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Wed, 1 Jul 2015 11:51:10 +0100 Subject: [PATCH 0338/7006] drm/i915: Report correct GGTT space usage Currently only normal views were accounted which under-accounts the usage as reported in debugfs. Introduce new helper, i915_gem_obj_total_ggtt_size, and use it from call sites which want to know how much GGTT space are objects using. v2: Single loop in i915_gem_get_aperture_ioctl. (Chris Wilson) v3: Walk GGTT active/inactive lists in i915_gem_get_aperture_ioctl for better efficiency. (Chris Wilson, Daniel Vetter) v4: Make i915_gem_obj_total_ggtt_size private to debugfs. (Chris Wilson) v5: Change unsigned long to u64. (Chris Wilson) Signed-off-by: Tvrtko Ursulin Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 22 ++++++++++++++++++---- drivers/gpu/drm/i915/i915_gem.c | 13 ++++++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 68a5e868f90bd..6a8de04c6a2bb 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -117,6 +117,20 @@ static inline const char *get_global_flag(struct drm_i915_gem_object *obj) return i915_gem_obj_to_ggtt(obj) ? "g" : " "; } +static u64 i915_gem_obj_total_ggtt_size(struct drm_i915_gem_object *obj) +{ + u64 size = 0; + struct i915_vma *vma; + + list_for_each_entry(vma, &obj->vma_list, vma_link) { + if (i915_is_ggtt(vma->vm) && + drm_mm_node_allocated(&vma->node)) + size += vma->node.size; + } + + return size; +} + static void describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj) { @@ -269,7 +283,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) list_add(&obj->obj_exec_link, &stolen); total_obj_size += obj->base.size; - total_gtt_size += i915_gem_obj_ggtt_size(obj); + total_gtt_size += i915_gem_obj_total_ggtt_size(obj); count++; } list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) { @@ -299,7 +313,7 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data) #define count_objects(list, member) do { \ list_for_each_entry(obj, list, member) { \ - size += i915_gem_obj_ggtt_size(obj); \ + size += i915_gem_obj_total_ggtt_size(obj); \ ++count; \ if (obj->map_and_fenceable) { \ mappable_size += i915_gem_obj_ggtt_size(obj); \ @@ -405,7 +419,7 @@ static void print_batch_pool_stats(struct seq_file *m, #define count_vmas(list, member) do { \ list_for_each_entry(vma, list, member) { \ - size += i915_gem_obj_ggtt_size(vma->obj); \ + size += i915_gem_obj_total_ggtt_size(vma->obj); \ ++count; \ if (vma->obj->map_and_fenceable) { \ mappable_size += i915_gem_obj_ggtt_size(vma->obj); \ @@ -535,7 +549,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data) describe_obj(m, obj); seq_putc(m, '\n'); total_obj_size += obj->base.size; - total_gtt_size += i915_gem_obj_ggtt_size(obj); + total_gtt_size += i915_gem_obj_total_ggtt_size(obj); count++; } diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 37cd901c9d750..c8ee13f466c87 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -149,14 +149,18 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data, { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_i915_gem_get_aperture *args = data; - struct drm_i915_gem_object *obj; + struct i915_gtt *ggtt = &dev_priv->gtt; + struct i915_vma *vma; size_t pinned; pinned = 0; mutex_lock(&dev->struct_mutex); - list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) - if (i915_gem_obj_is_pinned(obj)) - pinned += i915_gem_obj_ggtt_size(obj); + list_for_each_entry(vma, &ggtt->base.active_list, mm_list) + if (vma->pin_count) + pinned += vma->node.size; + list_for_each_entry(vma, &ggtt->base.inactive_list, mm_list) + if (vma->pin_count) + pinned += vma->node.size; mutex_unlock(&dev->struct_mutex); args->aper_size = dev_priv->gtt.base.total; @@ -5468,4 +5472,3 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) return false; } - -- GitLab From ce65e47b78789b4f78be1fd7e4c884df74a9f075 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 30 Jun 2015 10:53:05 -0300 Subject: [PATCH 0339/7006] drm/i915: don't increment the FBC threshold at fbc_enable We first set the threshold value when we're allocating the CFB, and then later at {ilk,gen7}_fbc_enable() we increment it in case we're using 16bpp. While that is correct, it is dangerous: if we rework the code a little bit in a way that allows us to call intel_fbc_enable() without necessarily calling i915_gem_stolen_setup_compression() first, we might end up incrementing threshold more than once. To prevent that, increment a temporary variable instead. v2: Rebase. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 50ed3332def1e..9e55b9badb4bc 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -188,14 +188,15 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; + int threshold = dev_priv->fbc.threshold; dev_priv->fbc.enabled = true; dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dev_priv->fbc.threshold++; + threshold++; - switch (dev_priv->fbc.threshold) { + switch (threshold) { case 4: case 3: dpfc_ctl |= DPFC_CTL_LIMIT_4X; @@ -259,6 +260,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; + int threshold = dev_priv->fbc.threshold; dev_priv->fbc.enabled = true; @@ -267,9 +269,9 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) - dev_priv->fbc.threshold++; + threshold++; - switch (dev_priv->fbc.threshold) { + switch (threshold) { case 4: case 3: dpfc_ctl |= DPFC_CTL_LIMIT_4X; -- GitLab From 260c1ad1993d3f17e25c5d848d6d2525ff38913c Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Wed, 1 Jul 2015 15:58:50 +0300 Subject: [PATCH 0340/7006] drm/i915/dsi: abstract dsi bpp derivation from pixel format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nuke three copies of the same switch case. Hopefully we can switch to a drm generic function later on, but that will require us to swich to enum mipi_dsi_pixel_format first. Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 67 ++++++++++------------------ 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index d20cf37b6901b..49ae821e82d8c 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -38,6 +38,27 @@ #define DSI_HFP_PACKET_EXTRA_SIZE 6 #define DSI_EOTP_PACKET_SIZE 4 +static int dsi_pixel_format_bpp(int pixel_format) +{ + int bpp; + + switch (pixel_format) { + default: + case VID_MODE_FORMAT_RGB888: + case VID_MODE_FORMAT_RGB666_LOOSE: + bpp = 24; + break; + case VID_MODE_FORMAT_RGB666: + bpp = 18; + break; + case VID_MODE_FORMAT_RGB565: + bpp = 16; + break; + } + + return bpp; +} + struct dsi_mnp { u32 dsi_pll_ctrl; u32 dsi_pll_div; @@ -65,19 +86,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, u32 dsi_bit_clock_hz; u32 dsi_clk; - switch (pixel_format) { - default: - case VID_MODE_FORMAT_RGB888: - case VID_MODE_FORMAT_RGB666_LOOSE: - bpp = 24; - break; - case VID_MODE_FORMAT_RGB666: - bpp = 18; - break; - case VID_MODE_FORMAT_RGB565: - bpp = 16; - break; - } + bpp = dsi_pixel_format_bpp(pixel_format); hactive = mode->hdisplay; vactive = mode->vdisplay; @@ -137,21 +146,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode, static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count) { u32 dsi_clk_khz; - u32 bpp; - - switch (pixel_format) { - default: - case VID_MODE_FORMAT_RGB888: - case VID_MODE_FORMAT_RGB666_LOOSE: - bpp = 24; - break; - case VID_MODE_FORMAT_RGB666: - bpp = 18; - break; - case VID_MODE_FORMAT_RGB565: - bpp = 16; - break; - } + u32 bpp = dsi_pixel_format_bpp(pixel_format); /* DSI data rate = pixel clock * bits per pixel / lane count pixel clock is converted from KHz to Hz */ @@ -286,21 +281,7 @@ void vlv_disable_dsi_pll(struct intel_encoder *encoder) static void assert_bpp_mismatch(int pixel_format, int pipe_bpp) { - int bpp; - - switch (pixel_format) { - default: - case VID_MODE_FORMAT_RGB888: - case VID_MODE_FORMAT_RGB666_LOOSE: - bpp = 24; - break; - case VID_MODE_FORMAT_RGB666: - bpp = 18; - break; - case VID_MODE_FORMAT_RGB565: - bpp = 16; - break; - } + int bpp = dsi_pixel_format_bpp(pixel_format); WARN(bpp != pipe_bpp, "bpp match assertion failure (expected %d, current %d)\n", -- GitLab From 3c5c6d88855baf9c3b9aa6243a37bb179f5a737e Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Wed, 1 Jul 2015 15:58:51 +0300 Subject: [PATCH 0341/7006] drm/i915: Support for higher DSI clk MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For MIPI panels requiring higher DSI clk, values needs to be added in lfsr_converts table for getting the correct values of pll ctrl and dividor values which gets programmed in cck regs, otherwise DSI PLL does not get locked leading to no display on the MIPI panel. Signed-off-by: Gaurav K Singh Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index 49ae821e82d8c..be0c1e230c488 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -67,8 +67,8 @@ struct dsi_mnp { static const u32 lfsr_converts[] = { 426, 469, 234, 373, 442, 221, 110, 311, 411, /* 62 - 70 */ 461, 486, 243, 377, 188, 350, 175, 343, 427, 213, /* 71 - 80 */ - 106, 53, 282, 397, 354, 227, 113, 56, 284, 142, /* 81 - 90 */ - 71, 35 /* 91 - 92 */ + 106, 53, 282, 397, 454, 227, 113, 56, 284, 142, /* 81 - 90 */ + 71, 35, 273, 136, 324, 418, 465, 488, 500, 506 /* 91 - 100 */ }; #ifdef DSI_CLK_FROM_RR -- GitLab From 20dbe1a1cbf3f1f0a6a07581e5b95ae027c9bea0 Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Wed, 1 Jul 2015 15:58:52 +0300 Subject: [PATCH 0342/7006] drm/i915: Changes required to enable DSI Video Mode on CHT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On CHT, changes are required for calculating the correct m,n & p with minimal error +/- for the required DSI clock, so that the correct dividor & ctrl values are written in cck regs for DSI. This patch has been tested on CHT RVP with 1200 x 1920 panel. v2 by Jani, rebased on earlier refactoring, original at [1]. [1] http://mid.gmane.org/1431368400-1942-5-git-send-email-rodrigo.vivi@intel.com Signed-off-by: Gaurav K Singh Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dsi_pll.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c index be0c1e230c488..c6a8975b128f1 100644 --- a/drivers/gpu/drm/i915/intel_dsi_pll.c +++ b/drivers/gpu/drm/i915/intel_dsi_pll.c @@ -157,11 +157,13 @@ static u32 dsi_clk_from_pclk(u32 pclk, int pixel_format, int lane_count) #endif -static int dsi_calc_mnp(int target_dsi_clk, struct dsi_mnp *dsi_mnp) +static int dsi_calc_mnp(struct drm_i915_private *dev_priv, + struct dsi_mnp *dsi_mnp, int target_dsi_clk) { unsigned int calc_m = 0, calc_p = 0; - unsigned int m, n = 1, p; - int ref_clk = 25000; + unsigned int m_min, m_max, p_min = 2, p_max = 6; + unsigned int m, n, p; + int ref_clk; int delta = target_dsi_clk; u32 m_seed; @@ -171,8 +173,20 @@ static int dsi_calc_mnp(int target_dsi_clk, struct dsi_mnp *dsi_mnp) return -ECHRNG; } - for (m = 62; m <= 92 && delta; m++) { - for (p = 2; p <= 6 && delta; p++) { + if (IS_CHERRYVIEW(dev_priv)) { + ref_clk = 100000; + n = 4; + m_min = 70; + m_max = 96; + } else { + ref_clk = 25000; + n = 1; + m_min = 62; + m_max = 92; + } + + for (m = m_min; m <= m_max && delta; m++) { + for (p = p_min; p <= p_max && delta; p++) { /* * Find the optimal m and p divisors with minimal delta * +/- the required clock @@ -212,7 +226,7 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder) dsi_clk = dsi_clk_from_pclk(intel_dsi->pclk, intel_dsi->pixel_format, intel_dsi->lane_count); - ret = dsi_calc_mnp(dsi_clk, &dsi_mnp); + ret = dsi_calc_mnp(dev_priv, &dsi_mnp, dsi_clk); if (ret) { DRM_DEBUG_KMS("dsi_calc_mnp failed\n"); return; -- GitLab From 8776f02b7c77f17dcf1dfab9954648874f264c89 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Tue, 30 Jun 2015 18:16:40 +0300 Subject: [PATCH 0343/7006] drm/i915/gtt: Per ppgtt scratch page Previously we have pointed the page where the individual ppgtt scratch structures refer to, to be the instance which GGTT setup have allocated. So it has been shared. To achieve full isolation between ppgtts also in this regard, allocate per ppgtt scratch page. Cc: Michel Thierry Cc: Daniel Vetter Signed-off-by: Mika Kuoppala Reviewed-by: Michel Thierry Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_gtt.c | 94 +++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c index a4ec1c6f56525..ed65f24867b42 100644 --- a/drivers/gpu/drm/i915/i915_gem_gtt.c +++ b/drivers/gpu/drm/i915/i915_gem_gtt.c @@ -678,6 +678,42 @@ static void gen8_free_page_tables(struct drm_device *dev, } } +static int gen8_init_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + vm->scratch_page = alloc_scratch_page(dev); + if (IS_ERR(vm->scratch_page)) + return PTR_ERR(vm->scratch_page); + + vm->scratch_pt = alloc_pt(dev); + if (IS_ERR(vm->scratch_pt)) { + free_scratch_page(dev, vm->scratch_page); + return PTR_ERR(vm->scratch_pt); + } + + vm->scratch_pd = alloc_pd(dev); + if (IS_ERR(vm->scratch_pd)) { + free_pt(dev, vm->scratch_pt); + free_scratch_page(dev, vm->scratch_page); + return PTR_ERR(vm->scratch_pd); + } + + gen8_initialize_pt(vm, vm->scratch_pt); + gen8_initialize_pd(vm, vm->scratch_pd); + + return 0; +} + +static void gen8_free_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + free_pd(dev, vm->scratch_pd); + free_pt(dev, vm->scratch_pt); + free_scratch_page(dev, vm->scratch_page); +} + static void gen8_ppgtt_cleanup(struct i915_address_space *vm) { struct i915_hw_ppgtt *ppgtt = @@ -693,8 +729,7 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm) free_pd(ppgtt->base.dev, ppgtt->pdp.page_directory[i]); } - free_pd(vm->dev, vm->scratch_pd); - free_pt(vm->dev, vm->scratch_pt); + gen8_free_scratch(vm); } /** @@ -981,16 +1016,11 @@ err_out: */ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt) { - ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->base.scratch_pt)) - return PTR_ERR(ppgtt->base.scratch_pt); - - ppgtt->base.scratch_pd = alloc_pd(ppgtt->base.dev); - if (IS_ERR(ppgtt->base.scratch_pd)) - return PTR_ERR(ppgtt->base.scratch_pd); + int ret; - gen8_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); - gen8_initialize_pd(&ppgtt->base, ppgtt->base.scratch_pd); + ret = gen8_init_scratch(&ppgtt->base); + if (ret) + return ret; ppgtt->base.start = 0; ppgtt->base.total = 1ULL << 32; @@ -1406,6 +1436,33 @@ unwind_out: return ret; } +static int gen6_init_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + vm->scratch_page = alloc_scratch_page(dev); + if (IS_ERR(vm->scratch_page)) + return PTR_ERR(vm->scratch_page); + + vm->scratch_pt = alloc_pt(dev); + if (IS_ERR(vm->scratch_pt)) { + free_scratch_page(dev, vm->scratch_page); + return PTR_ERR(vm->scratch_pt); + } + + gen6_initialize_pt(vm, vm->scratch_pt); + + return 0; +} + +static void gen6_free_scratch(struct i915_address_space *vm) +{ + struct drm_device *dev = vm->dev; + + free_pt(dev, vm->scratch_pt); + free_scratch_page(dev, vm->scratch_page); +} + static void gen6_ppgtt_cleanup(struct i915_address_space *vm) { struct i915_hw_ppgtt *ppgtt = @@ -1420,11 +1477,12 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm) free_pt(ppgtt->base.dev, pt); } - free_pt(vm->dev, vm->scratch_pt); + gen6_free_scratch(vm); } static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) { + struct i915_address_space *vm = &ppgtt->base; struct drm_device *dev = ppgtt->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; bool retried = false; @@ -1435,11 +1493,10 @@ static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt) * size. We allocate at the top of the GTT to avoid fragmentation. */ BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm)); - ppgtt->base.scratch_pt = alloc_pt(ppgtt->base.dev); - if (IS_ERR(ppgtt->base.scratch_pt)) - return PTR_ERR(ppgtt->base.scratch_pt); - gen6_initialize_pt(&ppgtt->base, ppgtt->base.scratch_pt); + ret = gen6_init_scratch(vm); + if (ret) + return ret; alloc: ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm, @@ -1470,7 +1527,7 @@ alloc: return 0; err_out: - free_pt(ppgtt->base.dev, ppgtt->base.scratch_pt); + gen6_free_scratch(vm); return ret; } @@ -1544,10 +1601,7 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt) static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt) { - struct drm_i915_private *dev_priv = dev->dev_private; - ppgtt->base.dev = dev; - ppgtt->base.scratch_page = dev_priv->gtt.base.scratch_page; if (INTEL_INFO(dev)->gen < 8) return gen6_ppgtt_init(ppgtt); -- GitLab From ce14ec20a1ffcd356f578036617d657be8429c00 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 2 Jul 2015 15:16:39 +0200 Subject: [PATCH 0344/7006] drm/crtc-helper: Fixup error handling in drm_helper_crtc_mode_set In commit 9f658b7b62e7aefc1ee067136126eca3f58cabfd Author: Daniel Stone Date: Fri May 22 13:34:45 2015 +0100 drm/crtc_helper: Replace open-coded CRTC state helpers error handling code was broken, resulting in the first path not being checked correctly. Fix this by using the same pattern as in the transitional plane helper function drm_plane_helper_update. v2: Simplify the cleanup code while at it too. v3: After some debugging with John we realized that the above patch from Daniel also accidentally removed the if (crtc_state) check. This is legal when transitioning to atomic, when the initial state reset isn't all wired up yet properly. Reinstate that check to fix the bug John has hit. Cc: Daniel Stone CC: Sean Paul Cc: John Hunter Signed-off-by: Daniel Vetter Reviewed-by: Daniel Stone Reported-and-tested-by: John Hunter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 393114df88a3d..93104f3555f5f 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -927,15 +927,13 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod if (crtc->funcs->atomic_duplicate_state) crtc_state = crtc->funcs->atomic_duplicate_state(crtc); - else { + else if (crtc->state) + crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc); + else crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); - if (!crtc_state) - return -ENOMEM; - if (crtc->state) - __drm_atomic_helper_crtc_duplicate_state(crtc, crtc_state); - else - crtc_state->crtc = crtc; - } + + if (!crtc_state) + return -ENOMEM; crtc_state->planes_changed = true; crtc_state->mode_changed = true; @@ -957,11 +955,11 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod ret = drm_helper_crtc_mode_set_base(crtc, x, y, old_fb); out: - if (crtc->funcs->atomic_destroy_state) - crtc->funcs->atomic_destroy_state(crtc, crtc_state); - else { - __drm_atomic_helper_crtc_destroy_state(crtc, crtc_state); - kfree(crtc_state); + if (crtc_state) { + if (crtc->funcs->atomic_destroy_state) + crtc->funcs->atomic_destroy_state(crtc, crtc_state); + else + drm_atomic_helper_crtc_destroy_state(crtc, crtc_state); } return ret; -- GitLab From e4f31ad2b7138db449310c9b63d402a29dc0e1c9 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 2 Jul 2015 16:33:53 +0200 Subject: [PATCH 0345/7006] drm: reset empty state in transitional helpers Transitional drivers might not have all the state frobbing lined up yet. But since the initial code has been merged a lot more state was added, so we really need this. Cc: Daniel Stone Signed-off-by: Daniel Vetter Reviewed-by: Daniel Stone Reported-and-tested-by: John Hunter Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc_helper.c | 8 +++++--- drivers/gpu/drm/drm_plane_helper.c | 16 ++++++++++------ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 93104f3555f5f..d3dfb0ebbeb29 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -927,10 +927,12 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod if (crtc->funcs->atomic_duplicate_state) crtc_state = crtc->funcs->atomic_duplicate_state(crtc); - else if (crtc->state) + else { + if (!crtc->state) + drm_atomic_helper_crtc_reset(crtc); + crtc_state = drm_atomic_helper_crtc_duplicate_state(crtc); - else - crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL); + } if (!crtc_state) return -ENOMEM; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 2f0ed11024eb8..b07a213f56554 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -525,10 +525,12 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc, if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); - else if (plane->state) + else { + if (!plane->state) + drm_atomic_helper_plane_reset(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); - else - plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); + } if (!plane_state) return -ENOMEM; plane_state->plane = plane; @@ -572,10 +574,12 @@ int drm_plane_helper_disable(struct drm_plane *plane) if (plane->funcs->atomic_duplicate_state) plane_state = plane->funcs->atomic_duplicate_state(plane); - else if (plane->state) + else { + if (!plane->state) + drm_atomic_helper_plane_reset(plane); + plane_state = drm_atomic_helper_plane_duplicate_state(plane); - else - plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL); + } if (!plane_state) return -ENOMEM; plane_state->plane = plane; -- GitLab From 1f96beec7a44f46bf277e2050a7a5a0308831d61 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Fri, 3 Jul 2015 14:17:29 +0300 Subject: [PATCH 0346/7006] drm: remove redundant code form drm_ioc32.c The compat ioctl handler ends up calling access_ok() twice: first indirectly inside compat_alloc_user_space() and then after returning from that function. This patch fixes issue. v2: there were three invalid removals of access_ok() that I've fixed. Also went through all the changes couple of times and verified that access_ok() is only removed when the buffer is allocated with compat_alloc_user_space(). My deepest apologies for this kind of sloppiness! Signed-off-by: Jarkko Sakkinen Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_ioc32.c | 55 ++++++++++++++++++------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/drm_ioc32.c b/drivers/gpu/drm/drm_ioc32.c index aa8bbb460c571..8dcfa76b09e65 100644 --- a/drivers/gpu/drm/drm_ioc32.c +++ b/drivers/gpu/drm/drm_ioc32.c @@ -93,7 +93,7 @@ static int compat_drm_version(struct file *file, unsigned int cmd, return -EFAULT; version = compat_alloc_user_space(sizeof(*version)); - if (!access_ok(VERIFY_WRITE, version, sizeof(*version))) + if (!version) return -EFAULT; if (__put_user(v32.name_len, &version->name_len) || __put_user((void __user *)(unsigned long)v32.name, @@ -140,7 +140,7 @@ static int compat_drm_getunique(struct file *file, unsigned int cmd, return -EFAULT; u = compat_alloc_user_space(sizeof(*u)); - if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + if (!u) return -EFAULT; if (__put_user(uq32.unique_len, &u->unique_len) || __put_user((void __user *)(unsigned long)uq32.unique, @@ -168,7 +168,7 @@ static int compat_drm_setunique(struct file *file, unsigned int cmd, return -EFAULT; u = compat_alloc_user_space(sizeof(*u)); - if (!access_ok(VERIFY_WRITE, u, sizeof(*u))) + if (!u) return -EFAULT; if (__put_user(uq32.unique_len, &u->unique_len) || __put_user((void __user *)(unsigned long)uq32.unique, @@ -200,7 +200,7 @@ static int compat_drm_getmap(struct file *file, unsigned int cmd, return -EFAULT; map = compat_alloc_user_space(sizeof(*map)); - if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + if (!map) return -EFAULT; if (__put_user(idx, &map->offset)) return -EFAULT; @@ -237,7 +237,7 @@ static int compat_drm_addmap(struct file *file, unsigned int cmd, return -EFAULT; map = compat_alloc_user_space(sizeof(*map)); - if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + if (!map) return -EFAULT; if (__put_user(m32.offset, &map->offset) || __put_user(m32.size, &map->size) @@ -277,7 +277,7 @@ static int compat_drm_rmmap(struct file *file, unsigned int cmd, return -EFAULT; map = compat_alloc_user_space(sizeof(*map)); - if (!access_ok(VERIFY_WRITE, map, sizeof(*map))) + if (!map) return -EFAULT; if (__put_user((void *)(unsigned long)handle, &map->handle)) return -EFAULT; @@ -306,7 +306,7 @@ static int compat_drm_getclient(struct file *file, unsigned int cmd, return -EFAULT; client = compat_alloc_user_space(sizeof(*client)); - if (!access_ok(VERIFY_WRITE, client, sizeof(*client))) + if (!client) return -EFAULT; if (__put_user(idx, &client->idx)) return -EFAULT; @@ -345,7 +345,7 @@ static int compat_drm_getstats(struct file *file, unsigned int cmd, int i, err; stats = compat_alloc_user_space(sizeof(*stats)); - if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats))) + if (!stats) return -EFAULT; err = drm_ioctl(file, DRM_IOCTL_GET_STATS, (unsigned long)stats); @@ -382,8 +382,7 @@ static int compat_drm_addbufs(struct file *file, unsigned int cmd, unsigned long agp_start; buf = compat_alloc_user_space(sizeof(*buf)); - if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf)) - || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))) + if (!buf || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))) return -EFAULT; if (__copy_in_user(buf, argp, offsetof(drm_buf_desc32_t, agp_start)) @@ -414,7 +413,7 @@ static int compat_drm_markbufs(struct file *file, unsigned int cmd, return -EFAULT; buf = compat_alloc_user_space(sizeof(*buf)); - if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))) + if (!buf) return -EFAULT; if (__put_user(b32.size, &buf->size) @@ -455,7 +454,7 @@ static int compat_drm_infobufs(struct file *file, unsigned int cmd, nbytes = sizeof(*request) + count * sizeof(struct drm_buf_desc); request = compat_alloc_user_space(nbytes); - if (!access_ok(VERIFY_WRITE, request, nbytes)) + if (!request) return -EFAULT; list = (struct drm_buf_desc *) (request + 1); @@ -516,7 +515,7 @@ static int compat_drm_mapbufs(struct file *file, unsigned int cmd, return -EINVAL; nbytes = sizeof(*request) + count * sizeof(struct drm_buf_pub); request = compat_alloc_user_space(nbytes); - if (!access_ok(VERIFY_WRITE, request, nbytes)) + if (!request) return -EFAULT; list = (struct drm_buf_pub *) (request + 1); @@ -563,7 +562,7 @@ static int compat_drm_freebufs(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + if (!request) return -EFAULT; if (__put_user(req32.count, &request->count) || __put_user((int __user *)(unsigned long)req32.list, @@ -589,7 +588,7 @@ static int compat_drm_setsareactx(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + if (!request) return -EFAULT; if (__put_user(req32.ctx_id, &request->ctx_id) || __put_user((void *)(unsigned long)req32.handle, @@ -613,7 +612,7 @@ static int compat_drm_getsareactx(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request))) + if (!request) return -EFAULT; if (__put_user(ctx_id, &request->ctx_id)) return -EFAULT; @@ -646,7 +645,7 @@ static int compat_drm_resctx(struct file *file, unsigned int cmd, return -EFAULT; res = compat_alloc_user_space(sizeof(*res)); - if (!access_ok(VERIFY_WRITE, res, sizeof(*res))) + if (!res) return -EFAULT; if (__put_user(res32.count, &res->count) || __put_user((struct drm_ctx __user *) (unsigned long)res32.contexts, @@ -689,7 +688,7 @@ static int compat_drm_dma(struct file *file, unsigned int cmd, return -EFAULT; d = compat_alloc_user_space(sizeof(*d)); - if (!access_ok(VERIFY_WRITE, d, sizeof(*d))) + if (!d) return -EFAULT; if (__put_user(d32.context, &d->context) @@ -764,7 +763,7 @@ static int compat_drm_agp_info(struct file *file, unsigned int cmd, int err; info = compat_alloc_user_space(sizeof(*info)); - if (!access_ok(VERIFY_WRITE, info, sizeof(*info))) + if (!info) return -EFAULT; err = drm_ioctl(file, DRM_IOCTL_AGP_INFO, (unsigned long)info); @@ -807,7 +806,7 @@ static int compat_drm_agp_alloc(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || __put_user(req32.size, &request->size) || __put_user(req32.type, &request->type)) return -EFAULT; @@ -834,7 +833,7 @@ static int compat_drm_agp_free(struct file *file, unsigned int cmd, u32 handle; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || get_user(handle, &argp->handle) || __put_user(handle, &request->handle)) return -EFAULT; @@ -858,7 +857,7 @@ static int compat_drm_agp_bind(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || __put_user(req32.handle, &request->handle) || __put_user(req32.offset, &request->offset)) return -EFAULT; @@ -874,7 +873,7 @@ static int compat_drm_agp_unbind(struct file *file, unsigned int cmd, u32 handle; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || get_user(handle, &argp->handle) || __put_user(handle, &request->handle)) return -EFAULT; @@ -897,8 +896,7 @@ static int compat_drm_sg_alloc(struct file *file, unsigned int cmd, unsigned long x; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + if (!request || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) || __get_user(x, &argp->size) || __put_user(x, &request->size)) return -EFAULT; @@ -923,8 +921,7 @@ static int compat_drm_sg_free(struct file *file, unsigned int cmd, unsigned long x; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) + if (!request || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)) || __get_user(x, &argp->handle) || __put_user(x << PAGE_SHIFT, &request->handle)) return -EFAULT; @@ -952,7 +949,7 @@ static int compat_drm_update_draw(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) || + if (!request || __put_user(update32.handle, &request->handle) || __put_user(update32.type, &request->type) || __put_user(update32.num, &request->num) || @@ -994,7 +991,7 @@ static int compat_drm_wait_vblank(struct file *file, unsigned int cmd, return -EFAULT; request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) + if (!request || __put_user(req32.request.type, &request->request.type) || __put_user(req32.request.sequence, &request->request.sequence) || __put_user(req32.request.signal, &request->request.signal)) -- GitLab From a3d1d001c9c583c79b1d9ab20f0a24333e35a3f8 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 3 Jul 2015 15:53:23 +0200 Subject: [PATCH 0347/7006] drm/i915: Update DRIVER_DATE to 20150703 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 1dbd95710bf4f..950a9811a16f6 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150619" +#define DRIVER_DATE "20150703" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- GitLab From ec530829ed064bc63d260f309e3ef88e0764132b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 5 Jul 2015 21:55:10 +0200 Subject: [PATCH 0348/7006] GPU-DRM: Delete an unnecessary check before drm_property_unreference_blob() The drm_property_unreference_blob() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Reviewed-by: Zhao Junwang Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index b69ed97d447c9..79fe31e5851e8 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4469,9 +4469,7 @@ static int drm_property_replace_global_blob(struct drm_device *dev, goto err_created; } - if (old_blob) - drm_property_unreference_blob(old_blob); - + drm_property_unreference_blob(old_blob); *replace = new_blob; return 0; -- GitLab From 398a017e91d1518e303886398b15b1851c3d902c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 30 Jun 2015 15:33:51 +0300 Subject: [PATCH 0349/7006] drm/i915: Fix HDMI 12bpc and pixel repeat clock readout for DDI platforms MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Take the HDMI 12bpc mode and pixel repeat into account when extracting the dotclock from the hardware on DDI platforms. Tested on HSW only. Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 49 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 15fc66a8da78b..e7f0379453e83 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1027,6 +1027,26 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv, return dco_freq / (p0 * p1 * p2 * 5); } +static void ddi_dotclock_get(struct intel_crtc_state *pipe_config) +{ + int dotclock; + + if (pipe_config->has_pch_encoder) + dotclock = intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->fdi_m_n); + else if (pipe_config->has_dp_encoder) + dotclock = intel_dotclock_calculate(pipe_config->port_clock, + &pipe_config->dp_m_n); + else if (pipe_config->has_hdmi_sink && pipe_config->pipe_bpp == 36) + dotclock = pipe_config->port_clock * 2 / 3; + else + dotclock = pipe_config->port_clock; + + if (pipe_config->pixel_multiplier) + dotclock /= pipe_config->pixel_multiplier; + + pipe_config->base.adjusted_mode.crtc_clock = dotclock; +} static void skl_ddi_clock_get(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) @@ -1073,12 +1093,7 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder, pipe_config->port_clock = link_clock; - if (pipe_config->has_dp_encoder) - pipe_config->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->dp_m_n); - else - pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; + ddi_dotclock_get(pipe_config); } static void hsw_ddi_clock_get(struct intel_encoder *encoder, @@ -1125,16 +1140,7 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder, pipe_config->port_clock = link_clock * 2; - if (pipe_config->has_pch_encoder) - pipe_config->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->fdi_m_n); - else if (pipe_config->has_dp_encoder) - pipe_config->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->dp_m_n); - else - pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock; + ddi_dotclock_get(pipe_config); } static int bxt_calc_pll_link(struct drm_i915_private *dev_priv, @@ -1169,16 +1175,9 @@ static void bxt_ddi_clock_get(struct intel_encoder *encoder, enum port port = intel_ddi_get_encoder_port(encoder); uint32_t dpll = port; - pipe_config->port_clock = - bxt_calc_pll_link(dev_priv, dpll); + pipe_config->port_clock = bxt_calc_pll_link(dev_priv, dpll); - if (pipe_config->has_dp_encoder) - pipe_config->base.adjusted_mode.crtc_clock = - intel_dotclock_calculate(pipe_config->port_clock, - &pipe_config->dp_m_n); - else - pipe_config->base.adjusted_mode.crtc_clock = - pipe_config->port_clock; + ddi_dotclock_get(pipe_config); } void intel_ddi_clock_get(struct intel_encoder *encoder, -- GitLab From 6fd765d0591a79934b268137fc7c0fbfa0e2e3b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 30 Jun 2015 15:33:52 +0300 Subject: [PATCH 0350/7006] drm/i915: Bump HDMI min port clock to 25 MHz MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Increase the HDMI port minimum port clock from 20 to 25 MHz. This is is the minimum listed in the DVI/HDMI specs, and it's also the documented minimum DPLL frequency for most of our platforms. Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 00c4b40e0158b..69244ed2c3522 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1175,7 +1175,7 @@ intel_hdmi_mode_valid(struct drm_connector *connector, if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector), true)) return MODE_CLOCK_HIGH; - if (clock < 20000) + if (clock < 25000) return MODE_CLOCK_LOW; if (mode->flags & DRM_MODE_FLAG_DBLSCAN) -- GitLab From e64e739ed6e5409b86ab5896cad4edb4570bf8ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 30 Jun 2015 19:23:59 +0300 Subject: [PATCH 0351/7006] drm/i915: Account for CHV/BXT DPLL clock limitations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CHV/BXT DPLL can't generate frequencies in the 216-240 MHz range. Account for that when checking whether the HDMI port clock is valid. This is particularly important for BXT since it can otherwise do 12bpc, and standard 1920x1080p60 CEA modes land right in the middle of that range when the clock gets multiplied to account for 12bpc. With the extra checks we will now filter out any mode where both 8bpc and 12bpc clock are within the gap. During modeset we then pick whichever mode works, favoring 12bpc if both are possible. 12bpc isn't supported on CHV so we simply end up filtering out any mode where the 8bpc port clock is in the gap. v2: Fix crtc_clock vs. port_clock fumble in compute_config() (Imre) Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 58 +++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 69244ed2c3522..f5c60d6febeea 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1151,7 +1151,7 @@ static void pch_post_disable_hdmi(struct intel_encoder *encoder) intel_disable_hdmi(encoder); } -static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) +static int hdmi_port_clock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) { struct drm_device *dev = intel_hdmi_to_dev(hdmi); @@ -1163,25 +1163,49 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi, bool respect_dvi_limit) return 225000; } +static enum drm_mode_status +hdmi_port_clock_valid(struct intel_hdmi *hdmi, + int clock, bool respect_dvi_limit) +{ + struct drm_device *dev = intel_hdmi_to_dev(hdmi); + + if (clock < 25000) + return MODE_CLOCK_LOW; + if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit)) + return MODE_CLOCK_HIGH; + + /* CHV/BXT DPLL can't generate 216-240 MHz */ + if ((IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) && + clock > 216000 && clock < 240000) + return MODE_CLOCK_RANGE; + + return MODE_OK; +} + static enum drm_mode_status intel_hdmi_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { - int clock = mode->clock; + struct intel_hdmi *hdmi = intel_attached_hdmi(connector); + struct drm_device *dev = intel_hdmi_to_dev(hdmi); + enum drm_mode_status status; + int clock; + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) + return MODE_NO_DBLESCAN; + clock = mode->clock; if (mode->flags & DRM_MODE_FLAG_DBLCLK) clock *= 2; - if (clock > hdmi_portclock_limit(intel_attached_hdmi(connector), - true)) - return MODE_CLOCK_HIGH; - if (clock < 25000) - return MODE_CLOCK_LOW; + /* check if we can do 8bpc */ + status = hdmi_port_clock_valid(hdmi, clock, true); - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) - return MODE_NO_DBLESCAN; + /* if we can't do 8bpc we may still be able to do 12bpc */ + if (!HAS_GMCH_DISPLAY(dev) && status != MODE_OK) + status = hdmi_port_clock_valid(hdmi, clock * 3 / 2, true); - return MODE_OK; + return status; } static bool hdmi_12bpc_possible(struct intel_crtc_state *crtc_state) @@ -1222,8 +1246,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base); struct drm_device *dev = encoder->base.dev; struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode; - int clock_12bpc = pipe_config->base.adjusted_mode.crtc_clock * 3 / 2; - int portclock_limit = hdmi_portclock_limit(intel_hdmi, false); + int clock_8bpc = pipe_config->base.adjusted_mode.crtc_clock; + int clock_12bpc = clock_8bpc * 3 / 2; int desired_bpp; pipe_config->has_hdmi_sink = intel_hdmi->has_hdmi_sink; @@ -1242,6 +1266,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, if (adjusted_mode->flags & DRM_MODE_FLAG_DBLCLK) { pipe_config->pixel_multiplier = 2; + clock_8bpc *= 2; clock_12bpc *= 2; } @@ -1261,7 +1286,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, * within limits. */ if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && - clock_12bpc <= portclock_limit && + hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK && hdmi_12bpc_possible(pipe_config) && 0 /* FIXME 12bpc support totally broken */) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); @@ -1272,6 +1297,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, } else { DRM_DEBUG_KMS("picking bpc to 8 for HDMI output\n"); desired_bpp = 8*3; + + pipe_config->port_clock = clock_8bpc; } if (!pipe_config->bw_constrained) { @@ -1279,8 +1306,9 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, pipe_config->pipe_bpp = desired_bpp; } - if (adjusted_mode->crtc_clock > portclock_limit) { - DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n"); + if (hdmi_port_clock_valid(intel_hdmi, pipe_config->port_clock, + false) != MODE_OK) { + DRM_DEBUG_KMS("unsupported HDMI clock, rejecting mode\n"); return false; } -- GitLab From 7a0baa6234468aa387f9b8a1a79dc2a4b4821f67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 30 Jun 2015 15:33:54 +0300 Subject: [PATCH 0352/7006] Revert "drm/i915: Disable 12bpc hdmi for now" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HDMI 12bpc should be working fine now. Let it loose. This reverts commit 5e3daaca09f5158eff9c92290faa1d2001ecc6e4. v2: Rebased due to CHV/BXT port clock check improvemnts Signed-off-by: Ville Syrjälä Reviewed-and-tested-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f5c60d6febeea..c7e912bafb876 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1287,8 +1287,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder, */ if (pipe_config->pipe_bpp > 8*3 && pipe_config->has_hdmi_sink && hdmi_port_clock_valid(intel_hdmi, clock_12bpc, false) == MODE_OK && - hdmi_12bpc_possible(pipe_config) && - 0 /* FIXME 12bpc support totally broken */) { + hdmi_12bpc_possible(pipe_config)) { DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n"); desired_bpp = 12*3; -- GitLab From 89ae3d3b9a384e75158f71ea9b878c8a45f3d582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 9 Jun 2015 11:35:25 +0200 Subject: [PATCH 0353/7006] drm/msm/dp: use flags argument of devm_gpiod_get to set direction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Use this to simplify the driver. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Alexandre Courbot Acked-by: Linus Walleij Signed-off-by: Uwe Kleine-König --- drivers/gpu/drm/msm/edp/edp_ctrl.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c index 7991069dd492a..81200e9be3821 100644 --- a/drivers/gpu/drm/msm/edp/edp_ctrl.c +++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c @@ -373,7 +373,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl) struct device *dev = &ctrl->pdev->dev; int ret; - ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd"); + ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd", GPIOD_IN); if (IS_ERR(ctrl->panel_hpd_gpio)) { ret = PTR_ERR(ctrl->panel_hpd_gpio); ctrl->panel_hpd_gpio = NULL; @@ -381,13 +381,7 @@ static int edp_gpio_config(struct edp_ctrl *ctrl) return ret; } - ret = gpiod_direction_input(ctrl->panel_hpd_gpio); - if (ret) { - pr_err("%s: Set direction for hpd failed, %d\n", __func__, ret); - return ret; - } - - ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en"); + ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en", GPIOD_OUT_LOW); if (IS_ERR(ctrl->panel_en_gpio)) { ret = PTR_ERR(ctrl->panel_en_gpio); ctrl->panel_en_gpio = NULL; @@ -395,13 +389,6 @@ static int edp_gpio_config(struct edp_ctrl *ctrl) return ret; } - ret = gpiod_direction_output(ctrl->panel_en_gpio, 0); - if (ret) { - pr_err("%s: Set direction for panel_en failed, %d\n", - __func__, ret); - return ret; - } - DBG("gpio on"); return 0; -- GitLab From 26a5bd26499fba331ecaa1e8ce8cc2b8c6fac569 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 11 Feb 2015 17:32:53 +0100 Subject: [PATCH 0354/7006] drm/tilcdc: panel: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Furthermore there is devm_gpiod_get_optional which is designed to get optional gpios. Simplify driver accordingly. Acked-by: Alexandre Courbot Acked-by: Linus Walleij Signed-off-by: Uwe Kleine-König --- drivers/gpu/drm/tilcdc/tilcdc_panel.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/tilcdc/tilcdc_panel.c b/drivers/gpu/drm/tilcdc/tilcdc_panel.c index 7a0315855e901..0af8bed7ce1ee 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_panel.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_panel.c @@ -375,25 +375,17 @@ static int panel_probe(struct platform_device *pdev) dev_info(&pdev->dev, "found backlight\n"); } - panel_mod->enable_gpio = devm_gpiod_get(&pdev->dev, "enable"); + panel_mod->enable_gpio = devm_gpiod_get_optional(&pdev->dev, "enable", + GPIOD_OUT_LOW); if (IS_ERR(panel_mod->enable_gpio)) { ret = PTR_ERR(panel_mod->enable_gpio); - if (ret != -ENOENT) { - dev_err(&pdev->dev, "failed to request enable GPIO\n"); - goto fail_backlight; - } - - /* Optional GPIO is not here, continue silently. */ - panel_mod->enable_gpio = NULL; - } else { - ret = gpiod_direction_output(panel_mod->enable_gpio, 0); - if (ret < 0) { - dev_err(&pdev->dev, "failed to setup GPIO\n"); - goto fail_backlight; - } - dev_info(&pdev->dev, "found enable GPIO\n"); + dev_err(&pdev->dev, "failed to request enable GPIO\n"); + goto fail_backlight; } + if (panel_mod->enable_gpio) + dev_info(&pdev->dev, "found enable GPIO\n"); + mod = &panel_mod->base; pdev->dev.platform_data = mod; -- GitLab From 7d4eb6f2110d9a9f9fe8d39eabddadbd35eb12b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: [PATCH 0355/7006] iio: light: stk3310: use flags argument of devm_gpiod_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify driver accordingly. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Jonathan Cameron Signed-off-by: Uwe Kleine-König --- drivers/iio/light/stk3310.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/light/stk3310.c b/drivers/iio/light/stk3310.c index fee4297d7c8f8..84c77d42a2c66 100644 --- a/drivers/iio/light/stk3310.c +++ b/drivers/iio/light/stk3310.c @@ -488,16 +488,12 @@ static int stk3310_gpio_probe(struct i2c_client *client) dev = &client->dev; /* gpio interrupt pin */ - gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0); + gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "acpi gpio get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); -- GitLab From 7d891dbee52e0a843ee7724ad4100675cf2fe24c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: [PATCH 0356/7006] iio: magn: bmc150: use flags argument of devm_gpiod_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify driver accordingly. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Jonathan Cameron Signed-off-by: Uwe Kleine-König --- drivers/iio/magnetometer/bmc150_magn.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/iio/magnetometer/bmc150_magn.c b/drivers/iio/magnetometer/bmc150_magn.c index d4c1788699911..187a31fdc35a8 100644 --- a/drivers/iio/magnetometer/bmc150_magn.c +++ b/drivers/iio/magnetometer/bmc150_magn.c @@ -839,16 +839,12 @@ static int bmc150_magn_gpio_probe(struct i2c_client *client) dev = &client->dev; /* data ready GPIO interrupt pin */ - gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0); + gpio = devm_gpiod_get_index(dev, BMC150_MAGN_GPIO_INT, 0, GPIOD_IN); if (IS_ERR(gpio)) { dev_err(dev, "ACPI GPIO get index failed\n"); return PTR_ERR(gpio); } - ret = gpiod_direction_input(gpio); - if (ret) - return ret; - ret = gpiod_to_irq(gpio); dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); -- GitLab From a33c380ef59353e550e852c82395306cf83cc7c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: [PATCH 0357/7006] media: i2c/adp1653: set enable gpio to output MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Without setting the direction of a gpio to output a call to gpiod_set_value doesn't have a defined outcome. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Sakari Ailus Acked-by: Pavel Machek Signed-off-by: Uwe Kleine-König --- drivers/media/i2c/adp1653.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/adp1653.c b/drivers/media/i2c/adp1653.c index c70ababce954d..5dd39775d6ca5 100644 --- a/drivers/media/i2c/adp1653.c +++ b/drivers/media/i2c/adp1653.c @@ -465,7 +465,7 @@ static int adp1653_of_init(struct i2c_client *client, of_node_put(child); - pd->enable_gpio = devm_gpiod_get(&client->dev, "enable"); + pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW); if (!pd->enable_gpio) { dev_err(&client->dev, "Error getting GPIO\n"); return -EINVAL; -- GitLab From 3bfe76806f705a24b82bc43c84c8506f3a44f77b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: [PATCH 0358/7006] NFC: nxp-nci_i2c: use flags argument of devm_gpiod_get_index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Simplify driver accordingly which even makes error checking more correct because gpiod_direction_{in,out}put might fail. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Acked-by: Oleg Zhurakivskyy Signed-off-by: Uwe Kleine-König --- drivers/nfc/nxp-nci/i2c.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/nfc/nxp-nci/i2c.c b/drivers/nfc/nxp-nci/i2c.c index 2f77f1d036385..fac80c691914b 100644 --- a/drivers/nfc/nxp-nci/i2c.c +++ b/drivers/nfc/nxp-nci/i2c.c @@ -318,19 +318,15 @@ static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy) struct i2c_client *client = phy->i2c_dev; struct gpio_desc *gpiod_en, *gpiod_fw, *gpiod_irq; - gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2); - gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1); - gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0); + gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2, GPIOD_OUT_LOW); + gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1, GPIOD_OUT_LOW); + gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN); if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw) || IS_ERR(gpiod_irq)) { nfc_err(&client->dev, "No GPIOs\n"); return -EINVAL; } - gpiod_direction_output(gpiod_en, 0); - gpiod_direction_output(gpiod_fw, 0); - gpiod_direction_input(gpiod_irq); - client->irq = gpiod_to_irq(gpiod_irq); if (client->irq < 0) { nfc_err(&client->dev, "No IRQ\n"); -- GitLab From 8e71c68074ff37348d586c87b0ee530e7440b094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Jun 2015 08:55:30 +0200 Subject: [PATCH 0359/7006] phy: tusb1210: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Furthermore there is devm_gpiod_get_optional which is designed to get optional gpios. Simplify driver accordingly. Signed-off-by: Uwe Kleine-König --- drivers/phy/phy-tusb1210.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/phy/phy-tusb1210.c b/drivers/phy/phy-tusb1210.c index 07efdd318bdc9..93dd45f2f26e2 100644 --- a/drivers/phy/phy-tusb1210.c +++ b/drivers/phy/phy-tusb1210.c @@ -61,32 +61,26 @@ static struct phy_ops phy_ops = { static int tusb1210_probe(struct ulpi *ulpi) { - struct gpio_desc *gpio; struct tusb1210 *tusb; u8 val, reg; - int ret; tusb = devm_kzalloc(&ulpi->dev, sizeof(*tusb), GFP_KERNEL); if (!tusb) return -ENOMEM; - gpio = devm_gpiod_get(&ulpi->dev, "reset"); - if (!IS_ERR(gpio)) { - ret = gpiod_direction_output(gpio, 0); - if (ret) - return ret; - gpiod_set_value_cansleep(gpio, 1); - tusb->gpio_reset = gpio; - } + tusb->gpio_reset = devm_gpiod_get_optional(&ulpi->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(tusb->gpio_reset)) + return PTR_ERR(tusb->gpio_reset); - gpio = devm_gpiod_get(&ulpi->dev, "cs"); - if (!IS_ERR(gpio)) { - ret = gpiod_direction_output(gpio, 0); - if (ret) - return ret; - gpiod_set_value_cansleep(gpio, 1); - tusb->gpio_cs = gpio; - } + gpiod_set_value_cansleep(tusb->gpio_reset, 1); + + tusb->gpio_cs = devm_gpiod_get_optional(&ulpi->dev, "cs", + GPIOD_OUT_LOW); + if (IS_ERR(tusb->gpio_cs)) + return PTR_ERR(tusb->gpio_cs); + + gpiod_set_value_cansleep(tusb->gpio_cs, 1); /* * VENDOR_SPECIFIC2 register in TUSB1210 can be used for configuring eye -- GitLab From 75da3b1c24389fe78680269176de0332d35f7fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 12 Jun 2015 09:04:55 +0200 Subject: [PATCH 0360/7006] usb: dwc3: pci: make better use of gpiod API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Use this additional parameter and the _optional variant to simplify the driver and improve error handling. Also expand the comment to explain why it's not sensible to switch to devm_gpiod_get and why the gpiod_put is also necessary. Furthermore this is one caller less that stops us making the flags argument to gpiod_get*() mandatory. Tested-by: Heikki Krogerus Signed-off-by: Uwe Kleine-König --- drivers/usb/dwc3/dwc3-pci.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 27e4fc896e9d9..f62617999f3c7 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -83,17 +83,23 @@ static int dwc3_pci_quirks(struct pci_dev *pdev) acpi_dev_add_driver_gpios(ACPI_COMPANION(&pdev->dev), acpi_dwc3_byt_gpios); - /* These GPIOs will turn on the USB2 PHY */ - gpio = gpiod_get(&pdev->dev, "cs"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); - gpiod_set_value_cansleep(gpio, 1); - gpiod_put(gpio); - } + /* + * These GPIOs will turn on the USB2 PHY. Note that we have to + * put the gpio descriptors again here because the phy driver + * might want to grab them, too. + */ + gpio = gpiod_get_optional(&pdev->dev, "cs", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); + + gpiod_set_value_cansleep(gpio, 1); + gpiod_put(gpio); + + gpio = gpiod_get_optional(&pdev->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(gpio)) + return PTR_ERR(gpio); - gpio = gpiod_get(&pdev->dev, "reset"); - if (!IS_ERR(gpio)) { - gpiod_direction_output(gpio, 0); + if (gpio) { gpiod_set_value_cansleep(gpio, 1); gpiod_put(gpio); usleep_range(10000, 11000); -- GitLab From eac477801924cac38a273338487cce9f460434bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 5 Mar 2015 09:36:19 +0100 Subject: [PATCH 0361/7006] usb: pass flags parameter to gpiod_get functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since 39b2bbe3d715 (gpio: add flags argument to gpiod_get*() functions) which appeared in v3.17-rc1, the gpiod_get* functions take an additional parameter that allows to specify direction and initial value for output. Currently this parameter is made optional with the help of a cpp trick. To allow dropping this hack convert callers to explictly pass a value for flags. Acked-by: Felipe Balbi Acked-by: Robert Jarzmik Signed-off-by: Uwe Kleine-König --- drivers/usb/gadget/udc/pxa27x_udc.c | 2 +- drivers/usb/phy/phy-generic.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c index b51226abade62..042f06b52677e 100644 --- a/drivers/usb/gadget/udc/pxa27x_udc.c +++ b/drivers/usb/gadget/udc/pxa27x_udc.c @@ -2422,7 +2422,7 @@ static int pxa_udc_probe(struct platform_device *pdev) } udc->udc_command = mach->udc_command; } else { - udc->gpiod = devm_gpiod_get(&pdev->dev, NULL); + udc->gpiod = devm_gpiod_get(&pdev->dev, NULL, GPIOD_ASIS); } regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c index deee68eafb72a..ec6ecd03269cc 100644 --- a/drivers/usb/phy/phy-generic.c +++ b/drivers/usb/phy/phy-generic.c @@ -218,11 +218,13 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop, clk_rate = 0; needs_vcc = of_property_read_bool(node, "vcc-supply"); - nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset"); + nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_reset); if (!err) { nop->gpiod_vbus = devm_gpiod_get_optional(dev, - "vbus-detect"); + "vbus-detect", + GPIOD_ASIS); err = PTR_ERR_OR_ZERO(nop->gpiod_vbus); } } else if (pdata) { -- GitLab From e62925567c7926e78bc8ca976cde5c28ea265a49 Mon Sep 17 00:00:00 2001 From: Vandana Kannan Date: Wed, 1 Jul 2015 17:02:57 +0530 Subject: [PATCH 0362/7006] drm/i915/bxt: BUNs related to port PLL This patch contains changes based on 2 updates to the spec: Port PLL VCO restriction raised up to 6700. Port PLL now needs DCO amp override enable for all VCO frequencies. v2: Sonika's review comment addressed - dcoampovr_en_h variable not required Based on a discussion with Siva, the following changes have been made. - replace dco_amp var with #define BXT_DCO_AMPLITUDE - set pll10 in a single assignment v3: Move DCO amplitude default value to i915_reg.h. Suggested by Siva. Signed-off-by: Vandana Kannan Reviewed-by: Sonika Jindal [v2] [danvet: Spell out BUN since not everyone knows what this means.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ddi.c | 15 +++++---------- drivers/gpu/drm/i915/intel_display.c | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 42ba1ef641d8f..ac8436fc6ced1 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -1215,6 +1215,7 @@ enum skl_disp_power_wells { #define PORT_PLL_LOCK_THRESHOLD_MASK (0x7 << PORT_PLL_LOCK_THRESHOLD_SHIFT) /* PORT_PLL_10_A */ #define PORT_PLL_DCO_AMP_OVR_EN_H (1<<27) +#define PORT_PLL_DCO_AMP_DEFAULT 15 #define PORT_PLL_DCO_AMP_MASK 0x3c00 #define PORT_PLL_DCO_AMP(x) (x<<10) #define _PORT_PLL_BASE(port) _PORT3(port, _PORT_PLL_0_A, \ diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index e7f0379453e83..db22f01730277 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1644,7 +1644,7 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, struct bxt_clk_div clk_div = {0}; int vco = 0; uint32_t prop_coef, int_coef, gain_ctl, targ_cnt; - uint32_t dcoampovr_en_h, dco_amp, lanestagger; + uint32_t lanestagger; if (intel_encoder->type == INTEL_OUTPUT_HDMI) { intel_clock_t best_clock; @@ -1683,9 +1683,7 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, vco = clock * 10 / 2 * clk_div.p1 * clk_div.p2; } - dco_amp = 15; - dcoampovr_en_h = 0; - if (vco >= 6200000 && vco <= 6480000) { + if (vco >= 6200000 && vco <= 6700000) { prop_coef = 4; int_coef = 9; gain_ctl = 3; @@ -1696,8 +1694,6 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, int_coef = 11; gain_ctl = 3; targ_cnt = 9; - if (vco >= 4800000 && vco < 5400000) - dcoampovr_en_h = 1; } else if (vco == 5400000) { prop_coef = 3; int_coef = 8; @@ -1741,10 +1737,9 @@ bxt_ddi_pll_select(struct intel_crtc *intel_crtc, crtc_state->dpll_hw_state.pll9 = 5 << PORT_PLL_LOCK_THRESHOLD_SHIFT; - if (dcoampovr_en_h) - crtc_state->dpll_hw_state.pll10 = PORT_PLL_DCO_AMP_OVR_EN_H; - - crtc_state->dpll_hw_state.pll10 |= PORT_PLL_DCO_AMP(dco_amp); + crtc_state->dpll_hw_state.pll10 = + PORT_PLL_DCO_AMP(PORT_PLL_DCO_AMP_DEFAULT) + | PORT_PLL_DCO_AMP_OVR_EN_H; crtc_state->dpll_hw_state.ebb4 = PORT_PLL_10BIT_CLK_ENABLE; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 724b0e3a5d37e..5ba35bb8e1a54 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -409,7 +409,7 @@ static const intel_limit_t intel_limits_chv = { static const intel_limit_t intel_limits_bxt = { /* FIXME: find real dot limits */ .dot = { .min = 0, .max = INT_MAX }, - .vco = { .min = 4800000, .max = 6480000 }, + .vco = { .min = 4800000, .max = 6700000 }, .n = { .min = 1, .max = 1 }, .m1 = { .min = 2, .max = 2 }, /* FIXME: find real m2 limits */ -- GitLab From 919032ec7c758fd4d65f2a141d1e0a10152198c9 Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Tue, 16 Jun 2015 13:39:40 +0300 Subject: [PATCH 0363/7006] drm/i915: Enable resource streamer bits on MI_BATCH_BUFFER_START Adds support for enabling the resource streamer on the legacy ringbuffer for HSW and GEN8. Reviewed-by: Chris Wilson Signed-off-by: Abdiel Janulgue Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_ringbuffer.c | 8 ++++++-- drivers/gpu/drm/i915/intel_ringbuffer.h | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index ac8436fc6ced1..b932e170c977f 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -361,6 +361,7 @@ #define MI_BATCH_BUFFER_START MI_INSTR(0x31, 0) #define MI_BATCH_GTT (2<<6) /* aliased with (1<<7) on gen4 */ #define MI_BATCH_BUFFER_START_GEN8 MI_INSTR(0x31, 1) +#define MI_BATCH_RESOURCE_STREAMER (1<<10) #define MI_PREDICATE_SRC0 (0x2400) #define MI_PREDICATE_SRC1 (0x2408) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index e39c8912f673e..bddc9032e17ed 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -2448,7 +2448,9 @@ gen8_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, return ret; /* FIXME(BDW): Address space and security selectors. */ - intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8)); + intel_ring_emit(ring, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8) | + (dispatch_flags & I915_DISPATCH_RS ? + MI_BATCH_RESOURCE_STREAMER : 0)); intel_ring_emit(ring, lower_32_bits(offset)); intel_ring_emit(ring, upper_32_bits(offset)); intel_ring_emit(ring, MI_NOOP); @@ -2472,7 +2474,9 @@ hsw_ring_dispatch_execbuffer(struct drm_i915_gem_request *req, intel_ring_emit(ring, MI_BATCH_BUFFER_START | (dispatch_flags & I915_DISPATCH_SECURE ? - 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW)); + 0 : MI_BATCH_PPGTT_HSW | MI_BATCH_NON_SECURE_HSW) | + (dispatch_flags & I915_DISPATCH_RS ? + MI_BATCH_RESOURCE_STREAMER : 0)); /* bit0-7 is the length on GEN6+ */ intel_ring_emit(ring, offset); intel_ring_advance(ring); diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index 304cac4caf1c0..0ea89ea301827 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h @@ -199,6 +199,7 @@ struct intel_engine_cs { unsigned dispatch_flags); #define I915_DISPATCH_SECURE 0x1 #define I915_DISPATCH_PINNED 0x2 +#define I915_DISPATCH_RS 0x4 void (*cleanup)(struct intel_engine_cs *ring); /* GEN8 signal/wait table - never trust comments! -- GitLab From 4c436d55b279bbc6b02aac02e7dc683fc09f884e Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Tue, 16 Jun 2015 13:39:41 +0300 Subject: [PATCH 0364/7006] drm/i915: Enable Resource Streamer state save/restore on MI_SET_CONTEXT Also clarify comments on context size that the extra state for Resource Streamer is included. v2: Don't remove the extended save/restore enabled for older platforms. (Ville) Use new MI_SET_CONTEXT defines for HSW RS save/restore state instead of extended save/restore. (Daniel) Suggested-by: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Abdiel Janulgue Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_context.c | 4 +++- drivers/gpu/drm/i915/i915_reg.h | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c index a7e58a8ae7704..4256b8e97e402 100644 --- a/drivers/gpu/drm/i915/i915_gem_context.c +++ b/drivers/gpu/drm/i915/i915_gem_context.c @@ -501,7 +501,9 @@ mi_set_context(struct drm_i915_gem_request *req, u32 hw_flags) } /* These flags are for resource streamer on HSW+ */ - if (!IS_HASWELL(ring->dev) && INTEL_INFO(ring->dev)->gen < 8) + if (IS_HASWELL(ring->dev) || INTEL_INFO(ring->dev)->gen >= 8) + flags |= (HSW_MI_RS_SAVE_STATE_EN | HSW_MI_RS_RESTORE_STATE_EN); + else if (INTEL_INFO(ring->dev)->gen < 8) flags |= (MI_SAVE_EXT_STATE_EN | MI_RESTORE_EXT_STATE_EN); diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index b932e170c977f..45ff3d3e79c81 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -321,6 +321,8 @@ #define MI_RESTORE_EXT_STATE_EN (1<<2) #define MI_FORCE_RESTORE (1<<1) #define MI_RESTORE_INHIBIT (1<<0) +#define HSW_MI_RS_SAVE_STATE_EN (1<<3) +#define HSW_MI_RS_RESTORE_STATE_EN (1<<2) #define MI_SEMAPHORE_SIGNAL MI_INSTR(0x1b, 0) /* GEN8+ */ #define MI_SEMAPHORE_TARGET(engine) ((engine)<<15) #define MI_SEMAPHORE_WAIT MI_INSTR(0x1c, 2) /* GEN8+ */ @@ -2803,7 +2805,8 @@ enum skl_disp_power_wells { * valid. Now, docs explain in dwords what is in the context object. The full * size is 70720 bytes, however, the power context and execlist context will * never be saved (power context is stored elsewhere, and execlists don't work - * on HSW) - so the final size is 66944 bytes, which rounds to 17 pages. + * on HSW) - so the final size, including the extra state required for the + * Resource Streamer, is 66944 bytes, which rounds to 17 pages. */ #define HSW_CXT_TOTAL_SIZE (17 * PAGE_SIZE) /* Same as Haswell, but 72064 bytes now. */ -- GitLab From 6922528a04a810b2889e82a4dc17eab920379117 Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Tue, 16 Jun 2015 13:39:42 +0300 Subject: [PATCH 0365/7006] drm/i915: Enable resource streamer on Execlists GEN8 and above uses Execlists by default instead of the legacy ringbuffer for batch execution. This patch enables the resource streamer bits when required. Patch is based on the initial work by Minu Mathai This version also adds the required bits to enable GEN8 Resource Streamer context save and restore for Execlists. Cc: ville.syrjala@linux.intel.com Signed-off-by: Abdiel Janulgue Reviewed-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 8 ++++++-- drivers/gpu/drm/i915/intel_lrc.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 22e9f85f40e43..0160bec1e7ba7 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1426,7 +1426,10 @@ static int gen8_emit_bb_start(struct drm_i915_gem_request *req, return ret; /* FIXME(BDW): Address space and security selectors. */ - intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8)); + intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | + (ppgtt<<8) | + (dispatch_flags & I915_DISPATCH_RS ? + MI_BATCH_RESOURCE_STREAMER : 0)); intel_logical_ring_emit(ringbuf, lower_32_bits(offset)); intel_logical_ring_emit(ringbuf, upper_32_bits(offset)); intel_logical_ring_emit(ringbuf, MI_NOOP); @@ -2019,7 +2022,8 @@ populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_o reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring); reg_state[CTX_CONTEXT_CONTROL+1] = _MASKED_BIT_ENABLE(CTX_CTRL_INHIBIT_SYN_CTX_SWITCH | - CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT); + CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT | + CTX_CTRL_RS_CTX_ENABLE); reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base); reg_state[CTX_RING_HEAD+1] = 0; reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index f59940ac1cfc7..d3dd3ac33aefe 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -32,6 +32,7 @@ #define RING_CONTEXT_CONTROL(ring) ((ring)->mmio_base+0x244) #define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH (1 << 3) #define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT (1 << 0) +#define CTX_CTRL_RS_CTX_ENABLE (1 << 1) #define RING_CONTEXT_STATUS_BUF(ring) ((ring)->mmio_base+0x370) #define RING_CONTEXT_STATUS_PTR(ring) ((ring)->mmio_base+0x3a0) -- GitLab From a9ed33ca075f712cc7fd96eb84e3d322012fcaaf Mon Sep 17 00:00:00 2001 From: Abdiel Janulgue Date: Wed, 1 Jul 2015 10:12:23 +0300 Subject: [PATCH 0366/7006] drm/i915: Expose I915_EXEC_RESOURCE_STREAMER flag and getparam Ensures that the batch buffer is executed by the resource streamer. And will let userspace know whether Resource Streamer is supported in the kernel. v2: Don't skip 1<<15 for the exec flags (Jani Nikula) v3: Use HAS_RESOURCE_STREAMER macro for execbuf validation (Chris Wilson) (from getparam patch) v2: Update I915_PARAM_HAS_RESOURCE_STREAMER so it's after I915_PARAM_HAS_GPU_RESET. v3: Only advertise RS support for hardware that supports it. v4: Add HAS_RESOURCE_STREAMER() macro (Chris) Testcase: igt/gem_exec_params Cc: Jani Nikula Cc: Kenneth Graunke Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Abdiel Janulgue [danvet: squash in getparam patch since it'd break bisect, suggested by Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 3 +++ drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/i915_gem_execbuffer.c | 14 ++++++++++++++ include/uapi/drm/i915_drm.h | 8 +++++++- 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index c5349fa3fccef..a42f165924335 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -167,6 +167,9 @@ static int i915_getparam(struct drm_device *dev, void *data, value = i915.enable_hangcheck && intel_has_gpu_reset(dev); break; + case I915_PARAM_HAS_RESOURCE_STREAMER: + value = HAS_RESOURCE_STREAMER(dev); + break; default: DRM_DEBUG("Unknown parameter %d\n", param->param); return -EINVAL; diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 950a9811a16f6..63daf4cd2477a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2539,6 +2539,9 @@ struct drm_i915_cmd_table { #define HAS_CSR(dev) (IS_SKYLAKE(dev)) +#define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \ + INTEL_INFO(dev)->gen >= 8) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 600db7441847b..83577c6159624 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1490,6 +1490,20 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data, return -EINVAL; } + if (args->flags & I915_EXEC_RESOURCE_STREAMER) { + if (!HAS_RESOURCE_STREAMER(dev)) { + DRM_DEBUG("RS is only allowed for Haswell, Gen8 and above\n"); + return -EINVAL; + } + if (ring->id != RCS) { + DRM_DEBUG("RS is not available on %s\n", + ring->name); + return -EINVAL; + } + + dispatch_flags |= I915_DISPATCH_RS; + } + intel_runtime_pm_get(dev_priv); ret = i915_mutex_lock_interruptible(dev); diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index f88cc1cac5d98..e7c29f1659ad1 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -355,6 +355,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_SUBSLICE_TOTAL 33 #define I915_PARAM_EU_TOTAL 34 #define I915_PARAM_HAS_GPU_RESET 35 +#define I915_PARAM_HAS_RESOURCE_STREAMER 36 typedef struct drm_i915_getparam { int param; @@ -765,7 +766,12 @@ struct drm_i915_gem_execbuffer2 { #define I915_EXEC_BSD_RING1 (1<<13) #define I915_EXEC_BSD_RING2 (2<<13) -#define __I915_EXEC_UNKNOWN_FLAGS -(1<<15) +/** Tell the kernel that the batchbuffer is processed by + * the resource streamer. + */ +#define I915_EXEC_RESOURCE_STREAMER (1<<15) + +#define __I915_EXEC_UNKNOWN_FLAGS -(I915_EXEC_RESOURCE_STREAMER<<1) #define I915_EXEC_CONTEXT_ID_MASK (0xffffffff) #define i915_execbuffer2_set_context_id(eb2, context) \ -- GitLab From b17d1bf16cc72a374a48d748940f700009d40ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 11 Feb 2015 11:52:37 +0100 Subject: [PATCH 0367/7006] gpio: make flags mandatory for gpiod_get functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now that all[1] users of the gpiod_get functions are converted to make use of the up to now optional flags parameter, make it mandatory which allows to remove some cpp magic. [1] all but etraxfs-uart which is broken anyhow and I'm allowed to ignore it by Jesper Nilsson :-) Acked-by: Alexandre Courbot Signed-off-by: Uwe Kleine-König --- drivers/gpio/devres.c | 18 ++++---- drivers/gpio/gpiolib.c | 16 +++---- include/linux/gpio/consumer.h | 82 ++++++++++------------------------- 3 files changed, 40 insertions(+), 76 deletions(-) diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c index 07ba82317eceb..903fcf4d04a06 100644 --- a/drivers/gpio/devres.c +++ b/drivers/gpio/devres.c @@ -59,13 +59,13 @@ static int devm_gpiod_match_array(struct device *dev, void *res, void *data) * automatically disposed on driver detach. See gpiod_get() for detailed * information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { return devm_gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL(__devm_gpiod_get); +EXPORT_SYMBOL(devm_gpiod_get); /** * devm_gpiod_get_optional - Resource-managed gpiod_get_optional() @@ -77,13 +77,13 @@ EXPORT_SYMBOL(__devm_gpiod_get); * are automatically disposed on driver detach. See gpiod_get_optional() for * detailed information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return devm_gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL(__devm_gpiod_get_optional); +EXPORT_SYMBOL(devm_gpiod_get_optional); /** * devm_gpiod_get_index - Resource-managed gpiod_get_index() @@ -96,7 +96,7 @@ EXPORT_SYMBOL(__devm_gpiod_get_optional); * automatically disposed on driver detach. See gpiod_get_index() for detailed * information about behavior and return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -120,7 +120,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL(__devm_gpiod_get_index); +EXPORT_SYMBOL(devm_gpiod_get_index); /** * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node @@ -182,10 +182,10 @@ EXPORT_SYMBOL(devm_get_gpiod_from_child); * gpiod_get_index_optional() for detailed information about behavior and * return values. */ -struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, - enum gpiod_flags flags) + enum gpiod_flags flags) { struct gpio_desc *desc; @@ -197,7 +197,7 @@ struct gpio_desc *__must_check __devm_gpiod_get_index_optional(struct device *de return desc; } -EXPORT_SYMBOL(__devm_gpiod_get_index_optional); +EXPORT_SYMBOL(devm_gpiod_get_index_optional); /** * devm_gpiod_get_array - Resource-managed gpiod_get_array() diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c38..4b2f981682252 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1894,12 +1894,12 @@ EXPORT_SYMBOL_GPL(gpiod_count); * dev, -ENOENT if no GPIO has been assigned to the requested function, or * another IS_ERR() code if an error occurred while trying to acquire the GPIO. */ -struct gpio_desc *__must_check __gpiod_get(struct device *dev, const char *con_id, +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { return gpiod_get_index(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(__gpiod_get); +EXPORT_SYMBOL_GPL(gpiod_get); /** * gpiod_get_optional - obtain an optional GPIO for a given GPIO function @@ -1911,13 +1911,13 @@ EXPORT_SYMBOL_GPL(__gpiod_get); * the requested function it will return NULL. This is convenient for drivers * that need to handle optional GPIOs. */ -struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return gpiod_get_index_optional(dev, con_id, 0, flags); } -EXPORT_SYMBOL_GPL(__gpiod_get_optional); +EXPORT_SYMBOL_GPL(gpiod_get_optional); /** @@ -1974,7 +1974,7 @@ static int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id, * requested function and/or index, or another IS_ERR() code if an error * occurred while trying to acquire the GPIO. */ -struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -2023,7 +2023,7 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(__gpiod_get_index); +EXPORT_SYMBOL_GPL(gpiod_get_index); /** * fwnode_get_named_gpiod - obtain a GPIO from firmware node @@ -2092,7 +2092,7 @@ EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod); * specified index was assigned to the requested function it will return NULL. * This is convenient for drivers that need to handle optional GPIOs. */ -struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) @@ -2107,7 +2107,7 @@ struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, return desc; } -EXPORT_SYMBOL_GPL(__gpiod_get_index_optional); +EXPORT_SYMBOL_GPL(gpiod_get_index_optional); /** * gpiod_hog - Hog the specified GPIO desc given the provided flags diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h index adac255aee86e..14cac67c2012b 100644 --- a/include/linux/gpio/consumer.h +++ b/include/linux/gpio/consumer.h @@ -47,17 +47,17 @@ enum gpiod_flags { int gpiod_count(struct device *dev, const char *con_id); /* Acquire and dispose GPIOs */ -struct gpio_desc *__must_check __gpiod_get(struct device *dev, +struct gpio_desc *__must_check gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags); -struct gpio_desc *__must_check __gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags); -struct gpio_desc *__must_check __gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags); -struct gpio_desc *__must_check __gpiod_get_index_optional(struct device *dev, +struct gpio_desc *__must_check gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); @@ -70,18 +70,18 @@ struct gpio_descs *__must_check gpiod_get_array_optional(struct device *dev, void gpiod_put(struct gpio_desc *desc); void gpiod_put_array(struct gpio_descs *descs); -struct gpio_desc *__must_check __devm_gpiod_get(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags); -struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags); -struct gpio_desc *__must_check __devm_gpiod_get_optional(struct device *dev, +struct gpio_desc *__must_check devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags); struct gpio_desc *__must_check -__devm_gpiod_get_index_optional(struct device *dev, const char *con_id, +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags); struct gpio_descs *__must_check devm_gpiod_get_array(struct device *dev, const char *con_id, @@ -146,31 +146,31 @@ static inline int gpiod_count(struct device *dev, const char *con_id) return 0; } -static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev, - const char *con_id, - enum gpiod_flags flags) +static inline struct gpio_desc *__must_check gpiod_get(struct device *dev, + const char *con_id, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__gpiod_get_index(struct device *dev, - const char *con_id, - unsigned int idx, - enum gpiod_flags flags) +gpiod_get_index(struct device *dev, + const char *con_id, + unsigned int idx, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__gpiod_get_optional(struct device *dev, const char *con_id, - enum gpiod_flags flags) +gpiod_get_optional(struct device *dev, const char *con_id, + enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__gpiod_get_index_optional(struct device *dev, const char *con_id, - unsigned int index, enum gpiod_flags flags) +gpiod_get_index_optional(struct device *dev, const char *con_id, + unsigned int index, enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } @@ -206,7 +206,7 @@ static inline void gpiod_put_array(struct gpio_descs *descs) } static inline struct gpio_desc *__must_check -__devm_gpiod_get(struct device *dev, +devm_gpiod_get(struct device *dev, const char *con_id, enum gpiod_flags flags) { @@ -214,7 +214,7 @@ __devm_gpiod_get(struct device *dev, } static inline struct gpio_desc *__must_check -__devm_gpiod_get_index(struct device *dev, +devm_gpiod_get_index(struct device *dev, const char *con_id, unsigned int idx, enum gpiod_flags flags) @@ -223,14 +223,14 @@ __devm_gpiod_get_index(struct device *dev, } static inline struct gpio_desc *__must_check -__devm_gpiod_get_optional(struct device *dev, const char *con_id, +devm_gpiod_get_optional(struct device *dev, const char *con_id, enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); } static inline struct gpio_desc *__must_check -__devm_gpiod_get_index_optional(struct device *dev, const char *con_id, +devm_gpiod_get_index_optional(struct device *dev, const char *con_id, unsigned int index, enum gpiod_flags flags) { return ERR_PTR(-ENOSYS); @@ -424,42 +424,6 @@ static inline struct gpio_desc *devm_get_gpiod_from_child( #endif /* CONFIG_GPIOLIB */ -/* - * Vararg-hacks! This is done to transition the kernel to always pass - * the options flags argument to the below functions. During a transition - * phase these vararg macros make both old-and-newstyle code compile, - * but when all calls to the elder API are removed, these should go away - * and the __gpiod_get() etc functions above be renamed just gpiod_get() - * etc. - */ -#define __gpiod_get(dev, con_id, flags, ...) __gpiod_get(dev, con_id, flags) -#define gpiod_get(varargs...) __gpiod_get(varargs, GPIOD_ASIS) -#define __gpiod_get_index(dev, con_id, index, flags, ...) \ - __gpiod_get_index(dev, con_id, index, flags) -#define gpiod_get_index(varargs...) __gpiod_get_index(varargs, GPIOD_ASIS) -#define __gpiod_get_optional(dev, con_id, flags, ...) \ - __gpiod_get_optional(dev, con_id, flags) -#define gpiod_get_optional(varargs...) __gpiod_get_optional(varargs, GPIOD_ASIS) -#define __gpiod_get_index_optional(dev, con_id, index, flags, ...) \ - __gpiod_get_index_optional(dev, con_id, index, flags) -#define gpiod_get_index_optional(varargs...) \ - __gpiod_get_index_optional(varargs, GPIOD_ASIS) -#define __devm_gpiod_get(dev, con_id, flags, ...) \ - __devm_gpiod_get(dev, con_id, flags) -#define devm_gpiod_get(varargs...) __devm_gpiod_get(varargs, GPIOD_ASIS) -#define __devm_gpiod_get_index(dev, con_id, index, flags, ...) \ - __devm_gpiod_get_index(dev, con_id, index, flags) -#define devm_gpiod_get_index(varargs...) \ - __devm_gpiod_get_index(varargs, GPIOD_ASIS) -#define __devm_gpiod_get_optional(dev, con_id, flags, ...) \ - __devm_gpiod_get_optional(dev, con_id, flags) -#define devm_gpiod_get_optional(varargs...) \ - __devm_gpiod_get_optional(varargs, GPIOD_ASIS) -#define __devm_gpiod_get_index_optional(dev, con_id, index, flags, ...) \ - __devm_gpiod_get_index_optional(dev, con_id, index, flags) -#define devm_gpiod_get_index_optional(varargs...) \ - __devm_gpiod_get_index_optional(varargs, GPIOD_ASIS) - #if IS_ENABLED(CONFIG_GPIOLIB) && IS_ENABLED(CONFIG_GPIO_SYSFS) int gpiod_export(struct gpio_desc *desc, bool direction_may_change); -- GitLab From c30400fcffb70d17bbf33eaff5020b83111bd66c Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 Jul 2015 12:31:30 -0300 Subject: [PATCH 0368/7006] drm/i915: set FDI translations to NULL on SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/gpu/drm/i915/intel_ddi.c: In function ‘intel_prepare_ddi’: drivers/gpu/drm/i915/intel_ddi.c:517:6: warning: ‘ddi_translations_fdi’ may be used uninitialized in this function [-Wmaybe-uninitialized] if (ddi_translations_fdi) ^ drivers/gpu/drm/i915/intel_ddi.c:446:30: note: ‘ddi_translations_fdi’ was declared here const struct ddi_buf_trans *ddi_translations_fdi; ^ This line used to be there, but was removed by: commit f8896f5d58e64bfd3c2b5f7c5ba5c3f3967e93c7 Author: David Weinehall Date: Thu Jun 25 11:11:03 2015 +030 drm/i915/skl: Buffer translation improvements Cc: David Weinehall Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_ddi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index db22f01730277..9a40bfb20e0c8 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -458,6 +458,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port, INTEL_OUTPUT_HDMI); return; } else if (IS_SKYLAKE(dev)) { + ddi_translations_fdi = NULL; ddi_translations_dp = skl_get_buf_trans_dp(dev, &n_dp_entries); ddi_translations_edp = -- GitLab From 3e6da4a9d9005fbc83420686fb897bd8ad749e91 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 16:05:27 +0300 Subject: [PATCH 0369/7006] drm/i915/audio: clarify HD audio documentation wrt modeset Clarify that audio enable/disable sequences are part of the modeset sequence. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_audio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index c4312177b0eed..c4397c1e7e4f2 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -41,7 +41,8 @@ * * The disable sequences must be performed before disabling the transcoder or * port. The enable sequences may only be performed after enabling the - * transcoder and port, and after completed link training. + * transcoder and port, and after completed link training. Therefore the audio + * enable/disable sequences are part of the modeset sequence. * * The codec and controller sequences could be done either parallel or serial, * but generally the ELDV/PD change in the codec sequence indicates to the audio -- GitLab From 856974a401bacf4fee1f3e3b2f601b7abfd5fa2a Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 16:05:28 +0300 Subject: [PATCH 0370/7006] drm/i915/hotplug: document the hotplug handling in the driver Add an overview of the drm/i915 hotplug handling. Signed-off-by: Jani Nikula Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 ++++ drivers/gpu/drm/i915/intel_hotplug.c | 39 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index c0312cbd023d2..e82205ee3d5fd 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4044,6 +4044,11 @@ int num_ioctls; probing, so those sections fully apply. + + Hotplug +!Pdrivers/gpu/drm/i915/intel_hotplug.c Hotplug +!Idrivers/gpu/drm/i915/intel_hotplug.c + High Definition Audio !Pdrivers/gpu/drm/i915/intel_audio.c High Definition Audio over HDMI and Display Port diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 3c53aac71d983..bac91a158ca2e 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -29,6 +29,45 @@ #include "i915_drv.h" #include "intel_drv.h" +/** + * DOC: Hotplug + * + * Simply put, hotplug occurs when a display is connected to or disconnected + * from the system. However, there may be adapters and docking stations and + * Display Port short pulses and MST devices involved, complicating matters. + * + * Hotplug in i915 is handled in many different levels of abstraction. + * + * The platform dependent interrupt handling code in i915_irq.c enables, + * disables, and does preliminary handling of the interrupts. The interrupt + * handlers gather the hotplug detect (HPD) information from relevant registers + * into a platform independent mask of hotplug pins that have fired. + * + * The platform independent interrupt handler intel_hpd_irq_handler() in + * intel_hotplug.c does hotplug irq storm detection and mitigation, and passes + * further processing to appropriate bottom halves (Display Port specific and + * regular hotplug). + * + * The Display Port work function i915_digport_work_func() calls into + * intel_dp_hpd_pulse() via hooks, which handles DP short pulses and DP MST long + * pulses, with failures and non-MST long pulses triggering regular hotplug + * processing on the connector. + * + * The regular hotplug work function i915_hotplug_work_func() calls connector + * detect hooks, and, if connector status changes, triggers sending of hotplug + * uevent to userspace via drm_kms_helper_hotplug_event(). + * + * Finally, the userspace is responsible for triggering a modeset upon receiving + * the hotplug uevent, disabling or enabling the crtc as needed. + * + * The hotplug interrupt storm detection and mitigation code keeps track of the + * number of interrupts per hotplug pin per a period of time, and if the number + * of interrupts exceeds a certain threshold, the interrupt is disabled for a + * while before being re-enabled. The intention is to mitigate issues raising + * from broken hardware triggering massive amounts of interrupts and grinding + * the system to a halt. + */ + enum port intel_hpd_pin_to_port(enum hpd_pin pin) { switch (pin) { -- GitLab From 2d80391d36e698e8dabc3b3ff0969fc6fde156c4 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:21 +0300 Subject: [PATCH 0371/7006] drm/i915/opregion: use BUILD_BUG_ON to verify mailbox struct sizes Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 71e87abdcae7c..c4756a2d77bb9 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -862,6 +862,11 @@ int intel_opregion_setup(struct drm_device *dev) char buf[sizeof(OPREGION_SIGNATURE)]; int err = 0; + BUILD_BUG_ON(sizeof(struct opregion_header) != 0x100); + BUILD_BUG_ON(sizeof(struct opregion_acpi) != 0x100); + BUILD_BUG_ON(sizeof(struct opregion_swsci) != 0x100); + BUILD_BUG_ON(sizeof(struct opregion_asle) != 0x100); + pci_read_config_dword(dev->pdev, PCI_ASLS, &asls); DRM_DEBUG_DRIVER("graphic opregion physical addr: 0x%x\n", asls); if (asls == 0) { -- GitLab From f6a430d8ee8dba13807b75845478a1920187840b Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:22 +0300 Subject: [PATCH 0372/7006] drm/i915/opregion: add new opregion stuff Inluding extended didl and cpdl fields Present since opregion version 3.0. Signed-off-by: Jani Nikula Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index c4756a2d77bb9..d05a504fd1767 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -53,6 +53,7 @@ #define MBOX_ACPI (1<<0) #define MBOX_SWSCI (1<<1) #define MBOX_ASLE (1<<2) +#define MBOX_ASLE_EXT (1<<4) struct opregion_header { u8 signature[16]; @@ -62,7 +63,10 @@ struct opregion_header { u8 vbios_ver[16]; u8 driver_ver[16]; u32 mboxes; - u8 reserved[164]; + u32 driver_model; + u32 pcon; + u8 dver[32]; + u8 rsvd[124]; } __packed; /* OpRegion mailbox #1: public ACPI methods */ @@ -84,7 +88,9 @@ struct opregion_acpi { u32 evts; /* ASL supported events */ u32 cnot; /* current OS notification */ u32 nrdy; /* driver status */ - u8 rsvd2[60]; + u32 did2[7]; /* extended supported display devices ID list */ + u32 cpd2[7]; /* extended attached display devices list */ + u8 rsvd2[4]; } __packed; /* OpRegion mailbox #2: SWSCI */ @@ -113,7 +119,10 @@ struct opregion_asle { u32 pcft; /* power conservation features */ u32 srot; /* supported rotation angles */ u32 iuer; /* IUER events */ - u8 rsvd[86]; + u64 fdss; + u32 fdsp; + u32 stat; + u8 rsvd[70]; } __packed; /* Driver readiness indicator */ -- GitLab From b4fe8156a72da0030f18fd16ce7ded3747f932bb Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:23 +0300 Subject: [PATCH 0373/7006] drm/i915/opregion: prefer DRM logging functions over pr_warn and dev_dbg Conform to same style as the rest of the driver. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index d05a504fd1767..5ab75a6a41315 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -25,8 +25,6 @@ * */ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include @@ -658,14 +656,13 @@ static void intel_didl_outputs(struct drm_device *dev) } if (!acpi_video_bus) { - pr_warn("No ACPI video bus found\n"); + DRM_ERROR("No ACPI video bus found\n"); return; } list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { if (i >= 8) { - dev_dbg(&dev->pdev->dev, - "More than 8 outputs detected via ACPI\n"); + DRM_DEBUG_KMS("More than 8 outputs detected via ACPI\n"); return; } status = @@ -691,8 +688,7 @@ blind_set: list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; if (i >= 8) { - dev_dbg(&dev->pdev->dev, - "More than 8 outputs in connector list\n"); + DRM_DEBUG_KMS("More than 8 outputs in connector list\n"); return; } switch (connector->connector_type) { -- GitLab From d5cbb22fcd0685944bbac80935b59df83e33e28e Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:24 +0300 Subject: [PATCH 0374/7006] drm/i915/opregion: abstract didl and did2 getter and setter Make it easier to handle the extended didl. No functional changes. Signed-off-by: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 50 +++++++++++++++++++++------ 1 file changed, 39 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 5ab75a6a41315..6235d9acce450 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -628,6 +628,38 @@ static struct notifier_block intel_opregion_notifier = { * (version 3) */ +static u32 get_did(struct intel_opregion *opregion, int i) +{ + u32 did; + + if (i < ARRAY_SIZE(opregion->acpi->didl)) { + did = ioread32(&opregion->acpi->didl[i]); + } else { + i -= ARRAY_SIZE(opregion->acpi->didl); + + if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2))) + return 0; + + did = ioread32(&opregion->acpi->did2[i]); + } + + return did; +} + +static void set_did(struct intel_opregion *opregion, int i, u32 val) +{ + if (i < ARRAY_SIZE(opregion->acpi->didl)) { + iowrite32(val, &opregion->acpi->didl[i]); + } else { + i -= ARRAY_SIZE(opregion->acpi->didl); + + if (WARN_ON(i >= ARRAY_SIZE(opregion->acpi->did2))) + return; + + iowrite32(val, &opregion->acpi->did2[i]); + } +} + static void intel_didl_outputs(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -665,22 +697,19 @@ static void intel_didl_outputs(struct drm_device *dev) DRM_DEBUG_KMS("More than 8 outputs detected via ACPI\n"); return; } - status = - acpi_evaluate_integer(acpi_cdev->handle, "_ADR", - NULL, &device_id); + status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR", + NULL, &device_id); if (ACPI_SUCCESS(status)) { if (!device_id) goto blind_set; - iowrite32((u32)(device_id & 0x0f0f), - &opregion->acpi->didl[i]); - i++; + set_did(opregion, i++, (u32)(device_id & 0x0f0f)); } } end: /* If fewer than 8 outputs, the list must be null terminated */ if (i < 8) - iowrite32(0, &opregion->acpi->didl[i]); + set_did(opregion, i, 0); return; blind_set: @@ -713,9 +742,8 @@ blind_set: output_type = ACPI_LVDS_OUTPUT; break; } - temp = ioread32(&opregion->acpi->didl[i]); - iowrite32(temp | (1<<31) | output_type | i, - &opregion->acpi->didl[i]); + temp = get_did(opregion, i); + set_did(opregion, i, temp | (1 << 31) | output_type | i); i++; } goto end; @@ -735,7 +763,7 @@ static void intel_setup_cadls(struct drm_device *dev) * display switching hotkeys. Just like DIDL, CADL is NULL-terminated if * there are less than eight devices. */ do { - disp_id = ioread32(&opregion->acpi->didl[i]); + disp_id = get_did(opregion, i); iowrite32(disp_id, &opregion->acpi->cadl[i]); } while (++i < 8 && disp_id != 0); } -- GitLab From dfc2066d8f8f2d87c1d8d00024478403c04d4e50 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Thu, 2 Jul 2015 17:43:25 +0300 Subject: [PATCH 0375/7006] drm/i915/opregion: start using extended didl Adding support for did2, or the extended support display devices ID list, increases the total to 15. Signed-off-by: Jani Nikula Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_opregion.c | 28 ++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_opregion.c b/drivers/gpu/drm/i915/intel_opregion.c index 6235d9acce450..7df916e914a42 100644 --- a/drivers/gpu/drm/i915/intel_opregion.c +++ b/drivers/gpu/drm/i915/intel_opregion.c @@ -669,7 +669,7 @@ static void intel_didl_outputs(struct drm_device *dev) struct acpi_device *acpi_dev, *acpi_cdev, *acpi_video_bus = NULL; unsigned long long device_id; acpi_status status; - u32 temp; + u32 temp, max_outputs; int i = 0; handle = ACPI_HANDLE(&dev->pdev->dev); @@ -692,9 +692,20 @@ static void intel_didl_outputs(struct drm_device *dev) return; } + /* + * In theory, did2, the extended didl, gets added at opregion version + * 3.0. In practice, however, we're supposed to set it for earlier + * versions as well, since a BIOS that doesn't understand did2 should + * not look at it anyway. Use a variable so we can tweak this if a need + * arises later. + */ + max_outputs = ARRAY_SIZE(opregion->acpi->didl) + + ARRAY_SIZE(opregion->acpi->did2); + list_for_each_entry(acpi_cdev, &acpi_video_bus->children, node) { - if (i >= 8) { - DRM_DEBUG_KMS("More than 8 outputs detected via ACPI\n"); + if (i >= max_outputs) { + DRM_DEBUG_KMS("More than %u outputs detected via ACPI\n", + max_outputs); return; } status = acpi_evaluate_integer(acpi_cdev->handle, "_ADR", @@ -707,8 +718,10 @@ static void intel_didl_outputs(struct drm_device *dev) } end: - /* If fewer than 8 outputs, the list must be null terminated */ - if (i < 8) + DRM_DEBUG_KMS("%d outputs detected\n", i); + + /* If fewer than max outputs, the list must be null terminated */ + if (i < max_outputs) set_did(opregion, i, 0); return; @@ -716,8 +729,9 @@ blind_set: i = 0; list_for_each_entry(connector, &dev->mode_config.connector_list, head) { int output_type = ACPI_OTHER_OUTPUT; - if (i >= 8) { - DRM_DEBUG_KMS("More than 8 outputs in connector list\n"); + if (i >= max_outputs) { + DRM_DEBUG_KMS("More than %u outputs in connector list\n", + max_outputs); return; } switch (connector->connector_type) { -- GitLab From e72072b6d7a49ea09dd833c3bdaa300e86ab0671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Fri, 3 Jul 2015 11:22:27 +0300 Subject: [PATCH 0376/7006] drm/i915: Drop a spurious intel_pre_plane_update() call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Kill the extra intel_pre_plane_update() I accidentally added in commit 852eb00dc44ea2b8896e2fa27c6a36a1f697ba5a Author: Ville Syrjälä Date: Wed Jun 24 22:00:07 2015 +0300 drm/i915: Try to make sure cxsr is disabled around plane enable/disable This fixes a load of warnings from the frontbuffer tracking. Testcase: igt/kms_frontbuffer_tracking/fbc-1p-rte Tested-by: Paulo Zanoni Tested-by: Matt Roper Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5ba35bb8e1a54..136b533718786 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13141,8 +13141,6 @@ static int __intel_set_mode(struct drm_atomic_state *state) if (!needs_modeset(crtc->state)) continue; - intel_pre_plane_update(intel_crtc); - any_ms = true; intel_pre_plane_update(intel_crtc); -- GitLab From e3e30f63389a319ca45161b07eb74e60f1e7ea20 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Jun 2015 06:53:59 -0300 Subject: [PATCH 0377/7006] [media] stk1160: fix sequence handling Fix the sequence counter: we're counting frames, not fields. Also remove the unused 'field' field. That would only be needed if this driver would support V4L2_FIELD_ALTERNATE. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-v4l.c | 2 ++ drivers/media/usb/stk1160/stk1160-video.c | 4 +--- drivers/media/usb/stk1160/stk1160.h | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 4d313ed4c32e1..7291cca587042 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -194,6 +194,8 @@ static int stk1160_start_streaming(struct stk1160 *dev) /* Start saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + dev->sequence = 0; + /* Start stk1160 */ stk1160_write_reg(dev, STK1160_DCTRL, 0xb3); stk1160_write_reg(dev, STK1160_DCTRL+3, 0x00); diff --git a/drivers/media/usb/stk1160/stk1160-video.c b/drivers/media/usb/stk1160/stk1160-video.c index 39f1aae209bcc..940c3eaea507e 100644 --- a/drivers/media/usb/stk1160/stk1160-video.c +++ b/drivers/media/usb/stk1160/stk1160-video.c @@ -96,9 +96,7 @@ void stk1160_buffer_done(struct stk1160 *dev) { struct stk1160_buffer *buf = dev->isoc_ctl.buf; - dev->field_count++; - - buf->vb.v4l2_buf.sequence = dev->field_count >> 1; + buf->vb.v4l2_buf.sequence = dev->sequence++; buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; buf->vb.v4l2_buf.bytesused = buf->bytesused; v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp); diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index abdea484c9987..3922a6cabde29 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -151,8 +151,7 @@ struct stk1160 { v4l2_std_id norm; /* current norm */ struct stk1160_fmt *fmt; /* selected format */ - unsigned int field_count; /* not sure ??? */ - enum v4l2_field field; /* also not sure :/ */ + unsigned int sequence; /* i2c i/o */ struct i2c_adapter i2c_adap; -- GitLab From 9d1b1f61a49c66145ebbf2844124987118e65632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 8 Jun 2015 10:35:05 -0300 Subject: [PATCH 0378/7006] [media] SOLO6x10: Fix G.723 minimum audio period count The period count is fixed, don't confuse ALSA. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-g723.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c index 7ddc76709caaa..4a37a1c51c488 100644 --- a/drivers/media/pci/solo6x10/solo6x10-g723.c +++ b/drivers/media/pci/solo6x10/solo6x10-g723.c @@ -48,10 +48,8 @@ /* The solo writes to 1k byte pages, 32 pages, in the dma. Each 1k page * is broken down to 20 * 48 byte regions (one for each channel possible) * with the rest of the page being dummy data. */ -#define G723_MAX_BUFFER (G723_PERIOD_BYTES * PERIODS_MAX) +#define PERIODS G723_FDMA_PAGES #define G723_INTR_ORDER 4 /* 0 - 4 */ -#define PERIODS_MIN (1 << G723_INTR_ORDER) -#define PERIODS_MAX G723_FDMA_PAGES struct solo_snd_pcm { int on; @@ -130,11 +128,11 @@ static const struct snd_pcm_hardware snd_solo_pcm_hw = { .rate_max = SAMPLERATE, .channels_min = 1, .channels_max = 1, - .buffer_bytes_max = G723_MAX_BUFFER, + .buffer_bytes_max = G723_PERIOD_BYTES * PERIODS, .period_bytes_min = G723_PERIOD_BYTES, .period_bytes_max = G723_PERIOD_BYTES, - .periods_min = PERIODS_MIN, - .periods_max = PERIODS_MAX, + .periods_min = PERIODS, + .periods_max = PERIODS, }; static int snd_solo_pcm_open(struct snd_pcm_substream *ss) @@ -340,7 +338,8 @@ static int solo_snd_pcm_init(struct solo_dev *solo_dev) ret = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, snd_dma_continuous_data(GFP_KERNEL), - G723_MAX_BUFFER, G723_MAX_BUFFER); + G723_PERIOD_BYTES * PERIODS, + G723_PERIOD_BYTES * PERIODS); if (ret < 0) return ret; -- GitLab From dd43a6278a9dbda46f56782b54a7a59216a87d23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 8 Jun 2015 10:37:15 -0300 Subject: [PATCH 0379/7006] [media] SOLO6x10: unmap registers only after free_irq() Fixes a panic on ARM. Diagnosis by Russell King. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 570d119ea18b6..84627e6f7377d 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -164,9 +164,9 @@ static void free_solo_dev(struct solo_dev *solo_dev) /* Now cleanup the PCI device */ solo_irq_off(solo_dev, ~0); - pci_iounmap(pdev, solo_dev->reg_base); if (pdev->irq) free_irq(pdev->irq, solo_dev); + pci_iounmap(pdev, solo_dev->reg_base); } pci_release_regions(pdev); -- GitLab From e1ceb25a1569ce5b61b9c496dd32d038ba8cb936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 8 Jun 2015 10:42:24 -0300 Subject: [PATCH 0380/7006] [media] SOLO6x10: remove unneeded register locking and barriers readl() and writel() are atomic, we don't need the spin lock. Also, flushing posted write buffer isn't required. Especially on read :-) Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-core.c | 1 - drivers/media/pci/solo6x10/solo6x10.h | 26 +--------------------- 2 files changed, 1 insertion(+), 26 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 84627e6f7377d..9c948b1fc1d83 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -483,7 +483,6 @@ static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) solo_dev->type = id->driver_data; solo_dev->pdev = pdev; - spin_lock_init(&solo_dev->reg_io_lock); ret = v4l2_device_register(&pdev->dev, &solo_dev->v4l2_dev); if (ret) goto fail_probe; diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 1ca54b08b3aaa..27423d7f54100 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -199,7 +199,6 @@ struct solo_dev { int nr_ext; u32 irq_mask; u32 motion_mask; - spinlock_t reg_io_lock; struct v4l2_device v4l2_dev; /* tw28xx accounting */ @@ -281,36 +280,13 @@ struct solo_dev { static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) { - unsigned long flags; - u32 ret; - u16 val; - - spin_lock_irqsave(&solo_dev->reg_io_lock, flags); - - ret = readl(solo_dev->reg_base + reg); - rmb(); - pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); - rmb(); - - spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); - - return ret; + return readl(solo_dev->reg_base + reg); } static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) { - unsigned long flags; - u16 val; - - spin_lock_irqsave(&solo_dev->reg_io_lock, flags); - writel(data, solo_dev->reg_base + reg); - wmb(); - pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); - rmb(); - - spin_unlock_irqrestore(&solo_dev->reg_io_lock, flags); } static inline void solo_irq_on(struct solo_dev *dev, u32 mask) -- GitLab From d9b8252202a4cc60a6c5d4fb237d2bd99680e00f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Krzysztof=20Ha=C5=82asa?= Date: Mon, 8 Jun 2015 10:50:22 -0300 Subject: [PATCH 0381/7006] [media] SOLO6x10: Remove dead code solo_dev and pdev cannot be NULL here. It doesn't matter if we initialized the PCI device or not. Signed-off-by: Krzysztof Ha?asa Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-core.c | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c index 9c948b1fc1d83..f50d07229236b 100644 --- a/drivers/media/pci/solo6x10/solo6x10-core.c +++ b/drivers/media/pci/solo6x10/solo6x10-core.c @@ -134,23 +134,11 @@ static irqreturn_t solo_isr(int irq, void *data) static void free_solo_dev(struct solo_dev *solo_dev) { - struct pci_dev *pdev; - - if (!solo_dev) - return; + struct pci_dev *pdev = solo_dev->pdev; if (solo_dev->dev.parent) device_unregister(&solo_dev->dev); - pdev = solo_dev->pdev; - - /* If we never initialized the PCI device, then nothing else - * below here needs cleanup */ - if (!pdev) { - kfree(solo_dev); - return; - } - if (solo_dev->reg_base) { /* Bring down the sub-devices first */ solo_g723_exit(solo_dev); @@ -164,8 +152,7 @@ static void free_solo_dev(struct solo_dev *solo_dev) /* Now cleanup the PCI device */ solo_irq_off(solo_dev, ~0); - if (pdev->irq) - free_irq(pdev->irq, solo_dev); + free_irq(pdev->irq, solo_dev); pci_iounmap(pdev, solo_dev->reg_base); } -- GitLab From e6cf0c409b40349f46427f9fc56f6ce4ec640a5d Mon Sep 17 00:00:00 2001 From: Jan Roemisch Date: Tue, 9 Jun 2015 08:44:33 -0300 Subject: [PATCH 0382/7006] [media] radio-bcm2048: Fix region selection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes region selection for lower bottom_frequency in BCM2048 FM receiver. It also removes "Japan wide band" region since this is impossible to do just like that. Signed-off-by: Jan Roemisch Acked-by: Pali Rohár Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 8bc68e2b4052b..fb55e5941445a 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -342,14 +342,6 @@ static struct region_info region_configs[] = { .deemphasis = 50, .region = 3, }, - /* Japan wide band */ - { - .channel_spacing = 10, - .bottom_frequency = 76000, - .top_frequency = 108000, - .deemphasis = 50, - .region = 4, - }, }; /* @@ -741,6 +733,18 @@ static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region) mutex_lock(&bdev->mutex); bdev->region_info = region_configs[region]; + + if (region_configs[region].bottom_frequency < 87500) + bdev->cache_fm_ctrl |= BCM2048_BAND_SELECT; + else + bdev->cache_fm_ctrl &= ~BCM2048_BAND_SELECT; + + err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL, + bdev->cache_fm_ctrl); + if (err) { + mutex_unlock(&bdev->mutex); + goto done; + } mutex_unlock(&bdev->mutex); if (bdev->frequency < region_configs[region].bottom_frequency || -- GitLab From cfcffe397fae05d6193bbb0dc87a7148323bf3fb Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 9 Jun 2015 10:54:53 -0300 Subject: [PATCH 0383/7006] [media] rc/Kconfig: fix indentation problem The RC_ST and IR_SUNXI entries have weird indentation, and the RC_ST entry is actually malformed. Fix it. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/Kconfig | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index ddfab256b9a53..b6e13116c6f5a 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -371,21 +371,21 @@ config RC_ST tristate "ST remote control receiver" depends on RC_CORE depends on ARCH_STI || COMPILE_TEST - help - Say Y here if you want support for ST remote control driver - which allows both IR and UHF RX. - The driver passes raw pulse and space information to the LIRC decoder. + ---help--- + Say Y here if you want support for ST remote control driver + which allows both IR and UHF RX. + The driver passes raw pulse and space information to the LIRC decoder. - If you're not sure, select N here. + If you're not sure, select N here. config IR_SUNXI - tristate "SUNXI IR remote control" - depends on RC_CORE - depends on ARCH_SUNXI || COMPILE_TEST - ---help--- - Say Y if you want to use sunXi internal IR Controller - - To compile this driver as a module, choose M here: the module will - be called sunxi-ir. + tristate "SUNXI IR remote control" + depends on RC_CORE + depends on ARCH_SUNXI || COMPILE_TEST + ---help--- + Say Y if you want to use sunXi internal IR Controller + + To compile this driver as a module, choose M here: the module will + be called sunxi-ir. endif #RC_DEVICES -- GitLab From fd7524294ccaa6168593042121e3bbd26a529fd5 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:33 -0300 Subject: [PATCH 0384/7006] [media] v4l2-dv-timings: use swap() in v4l2_calc_aspect_ratio() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 04dc71e3ebf0e..eefad4f174975 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -665,7 +665,6 @@ EXPORT_SYMBOL_GPL(v4l2_detect_gtf); struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) { struct v4l2_fract aspect = { 16, 9 }; - u32 tmp; u8 ratio; /* Nothing filled in, fallback to 16:9 */ @@ -697,9 +696,7 @@ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait) if (hor_landscape) return aspect; /* The aspect ratio is for portrait, so swap numerator and denominator */ - tmp = aspect.denominator; - aspect.denominator = aspect.numerator; - aspect.numerator = tmp; + swap(aspect.denominator, aspect.numerator); return aspect; } EXPORT_SYMBOL_GPL(v4l2_calc_aspect_ratio); -- GitLab From 453f847ef2e445a7b1fe6cbe35d36a06c60f58a5 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:39 -0300 Subject: [PATCH 0385/7006] [media] wl128x: use swap() in fm_rdsparse_swapbytes() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 704397f3c106b..ebc73b0342496 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -689,7 +689,6 @@ static void fm_rx_update_af_cache(struct fmdev *fmdev, u8 af) static void fm_rdsparse_swapbytes(struct fmdev *fmdev, struct fm_rdsdata_format *rds_format) { - u8 byte1; u8 index = 0; u8 *rds_buff; @@ -701,9 +700,7 @@ static void fm_rdsparse_swapbytes(struct fmdev *fmdev, if (fmdev->asci_id != 0x6350) { rds_buff = &rds_format->data.groupdatabuff.buff[0]; while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) { - byte1 = rds_buff[index]; - rds_buff[index] = rds_buff[index + 1]; - rds_buff[index + 1] = byte1; + swap(rds_buff[index], rds_buff[index + 1]); index += 2; } } -- GitLab From 2bb00da1484073342a1f3e9f846ac0ad8dc6314d Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:41 -0300 Subject: [PATCH 0386/7006] [media] saa7146: use swap() in sort_and_eliminate() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_hlp.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/media/common/saa7146/saa7146_hlp.c b/drivers/media/common/saa7146/saa7146_hlp.c index be746d1aee9a2..3dc6a838ca6f7 100644 --- a/drivers/media/common/saa7146/saa7146_hlp.c +++ b/drivers/media/common/saa7146/saa7146_hlp.c @@ -307,7 +307,7 @@ static int calculate_v_scale_registers(struct saa7146_dev *dev, enum v4l2_field /* simple bubble-sort algorithm with duplicate elimination */ static int sort_and_eliminate(u32* values, int* count) { - int low = 0, high = 0, top = 0, temp = 0; + int low = 0, high = 0, top = 0; int cur = 0, next = 0; /* sanity checks */ @@ -318,11 +318,8 @@ static int sort_and_eliminate(u32* values, int* count) /* bubble sort the first @count items of the array @values */ for( top = *count; top > 0; top--) { for( low = 0, high = 1; high < top; low++, high++) { - if( values[low] > values[high] ) { - temp = values[low]; - values[low] = values[high]; - values[high] = temp; - } + if( values[low] > values[high] ) + swap(values[low], values[high]); } } -- GitLab From f47c183c20d845af9d747fc1e5b7dbd9c3871e05 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:50 -0300 Subject: [PATCH 0387/7006] [media] saa6588: use swap() in saa6588_i2c_poll() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa6588.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 2960b5a8362a4..2240e0a67db1e 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -301,9 +301,7 @@ static void saa6588_i2c_poll(struct saa6588 *s) first and the last of the 3 bytes block. */ - tmp = tmpbuf[2]; - tmpbuf[2] = tmpbuf[0]; - tmpbuf[0] = tmp; + swap(tmpbuf[2], tmpbuf[0]); /* Map 'Invalid block E' to 'Invalid Block' */ if (blocknum == 6) -- GitLab From 30533ad10b7c3d7c05b757382aee28458167ab75 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:33:45 -0300 Subject: [PATCH 0388/7006] [media] btcx-risc: use swap() in btcx_sort_clips() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/btcx-risc.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c index 00f0880b6d665..57c7f58c3af21 100644 --- a/drivers/media/pci/bt8xx/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -160,7 +160,6 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) { - struct v4l2_clip swap; int i,j,n; if (nclips < 2) @@ -168,9 +167,7 @@ btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips) for (i = nclips-2; i >= 0; i--) { for (n = 0, j = 0; j <= i; j++) { if (clips[j].c.left > clips[j+1].c.left) { - swap = clips[j]; - clips[j] = clips[j+1]; - clips[j+1] = swap; + swap(clips[j], clips[j + 1]); n++; } } -- GitLab From 5fea1bb703c360f323c62f6d34b5e947d0590e80 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Wed, 10 Jun 2015 13:51:42 -0300 Subject: [PATCH 0389/7006] [media] v4l2-dv-timings: add support for reduced blanking v2 Added support for reduced blanking version 2 (RB v2) in cvt timings. Standard specifies a fixed vsync pulse of 8 lines to indicate RB v2 timings. Vertical back porch is fixed at 6 lines and vertical front porch is remainder of vertical blanking time. For RB v2, horizontal blanking is fixed at 80 pixels. Horizontal sync is fixed at 32. All horizontal timing counts (active pixels, front, back porches) can be specified upto a precision of 1. RB v2 allows for non standard aspect ratios. In RB v2 vsync does not indicate aspect ratio. In absence of aspect ratio v4l2_detect_cvt() cannot calculate image width from image height. Hence extending the v4l2_detect_cvt() to pass image width in case of RB v2. Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 2 +- drivers/media/i2c/adv7842.c | 2 +- drivers/media/platform/vivid/vivid-vid-cap.c | 2 +- drivers/media/v4l2-core/v4l2-dv-timings.c | 80 +++++++++++++++----- include/media/v4l2-dv-timings.h | 6 +- 5 files changed, 67 insertions(+), 25 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 808360fd6539a..60630d62e6638 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1328,7 +1328,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } } - if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, + if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), false, timings)) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 4cf79b2422d4a..aa0d1a04543b3 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1442,7 +1442,7 @@ static int stdi2dv_timings(struct v4l2_subdev *sd, } } - if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, + if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0, (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) | (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0), false, timings)) diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index c4268d1b2f82b..ed0b8788a66f8 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1627,7 +1627,7 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) h_freq = (u32)bt->pixelclock / total_h_pixel; if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { - if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, bt->polarities, bt->interlaced, timings)) return true; } diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index eefad4f174975..ddaad3d7f1dd9 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -316,6 +316,7 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); */ #define CVT_PXL_CLK_GRAN 250000 /* pixel clock granularity */ +#define CVT_PXL_CLK_GRAN_RB_V2 1000 /* granularity for reduced blanking v2*/ /* Normal blanking */ #define CVT_MIN_V_BPORCH 7 /* lines */ @@ -335,15 +336,22 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); /* Reduced Blanking */ #define CVT_RB_MIN_V_BPORCH 7 /* lines */ #define CVT_RB_V_FPORCH 3 /* lines */ -#define CVT_RB_MIN_V_BLANK 460 /* us */ +#define CVT_RB_MIN_V_BLANK 460 /* us */ #define CVT_RB_H_SYNC 32 /* pixels */ -#define CVT_RB_H_BPORCH 80 /* pixels */ #define CVT_RB_H_BLANK 160 /* pixels */ +/* Reduce blanking Version 2 */ +#define CVT_RB_V2_H_BLANK 80 /* pixels */ +#define CVT_RB_MIN_V_FPORCH 3 /* lines */ +#define CVT_RB_V2_MIN_V_FPORCH 1 /* lines */ +#define CVT_RB_V_BPORCH 6 /* lines */ /** v4l2_detect_cvt - detect if the given timings follow the CVT standard * @frame_height - the total height of the frame (including blanking) in lines. * @hfreq - the horizontal frequency in Hz. * @vsync - the height of the vertical sync in lines. + * @active_width - active width of image (does not include blanking). This + * information is needed only in case of version 2 of reduced blanking. + * In other cases, this parameter does not have any effect on timings. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format @@ -352,20 +360,22 @@ EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); * This function will attempt to detect if the given values correspond to a * valid CVT format. If so, then it will return true, and fmt will be filled * in with the found CVT timings. - * - * TODO: VESA defined a new version 2 of their reduced blanking - * formula. Support for that is currently missing in this CVT - * detection function. */ -bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, - u32 polarities, bool interlaced, struct v4l2_dv_timings *fmt) +bool v4l2_detect_cvt(unsigned frame_height, + unsigned hfreq, + unsigned vsync, + unsigned active_width, + u32 polarities, + bool interlaced, + struct v4l2_dv_timings *fmt) { int v_fp, v_bp, h_fp, h_bp, hsync; int frame_width, image_height, image_width; bool reduced_blanking; + bool rb_v2 = false; unsigned pix_clk; - if (vsync < 4 || vsync > 7) + if (vsync < 4 || vsync > 8) return false; if (polarities == V4L2_DV_VSYNC_POS_POL) @@ -375,17 +385,35 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; + if (reduced_blanking && vsync == 8) + rb_v2 = true; + + if (rb_v2 && active_width == 0) + return false; + + if (!rb_v2 && vsync > 7) + return false; + if (hfreq == 0) return false; /* Vertical */ if (reduced_blanking) { - v_fp = CVT_RB_V_FPORCH; - v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; - v_bp -= vsync + v_fp; - - if (v_bp < CVT_RB_MIN_V_BPORCH) - v_bp = CVT_RB_MIN_V_BPORCH; + if (rb_v2) { + v_bp = CVT_RB_V_BPORCH; + v_fp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; + v_fp -= vsync + v_bp; + + if (v_fp < CVT_RB_V2_MIN_V_FPORCH) + v_fp = CVT_RB_V2_MIN_V_FPORCH; + } else { + v_fp = CVT_RB_V_FPORCH; + v_bp = (CVT_RB_MIN_V_BLANK * hfreq) / 1000000 + 1; + v_bp -= vsync + v_fp; + + if (v_bp < CVT_RB_MIN_V_BPORCH) + v_bp = CVT_RB_MIN_V_BPORCH; + } } else { v_fp = CVT_MIN_V_PORCH_RND; v_bp = (CVT_MIN_VSYNC_BP * hfreq) / 1000000 + 1 - vsync; @@ -422,22 +450,32 @@ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, else return false; break; + case 8: + image_width = active_width; + break; default: return false; } - image_width = image_width & ~7; + if (!rb_v2) + image_width = image_width & ~7; /* Horizontal */ if (reduced_blanking) { - pix_clk = (image_width + CVT_RB_H_BLANK) * hfreq; - pix_clk = (pix_clk / CVT_PXL_CLK_GRAN) * CVT_PXL_CLK_GRAN; + int h_blank; + int clk_gran; + + h_blank = rb_v2 ? CVT_RB_V2_H_BLANK : CVT_RB_H_BLANK; + clk_gran = rb_v2 ? CVT_PXL_CLK_GRAN_RB_V2 : CVT_PXL_CLK_GRAN; - h_bp = CVT_RB_H_BPORCH; + pix_clk = (image_width + h_blank) * hfreq; + pix_clk = (pix_clk / clk_gran) * clk_gran; + + h_bp = h_blank / 2; hsync = CVT_RB_H_SYNC; - h_fp = CVT_RB_H_BLANK - h_bp - hsync; + h_fp = h_blank - h_bp - hsync; - frame_width = image_width + CVT_RB_H_BLANK; + frame_width = image_width + h_blank; } else { unsigned ideal_duty_cycle_per_myriad = 100 * CVT_C_PRIME - (CVT_M_PRIME * 100000) / hfreq; diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index eecd3102a618c..e18a653549cdb 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h @@ -115,6 +115,9 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, * @frame_height - the total height of the frame (including blanking) in lines. * @hfreq - the horizontal frequency in Hz. * @vsync - the height of the vertical sync in lines. + * @active_width - active width of image (does not include blanking). This + * information is needed only in case of version 2 of reduced blanking. + * In other cases, this parameter does not have any effect on timings. * @polarities - the horizontal and vertical polarities (same as struct * v4l2_bt_timings polarities). * @interlaced - if this flag is true, it indicates interlaced format @@ -125,7 +128,8 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, * in with the found CVT timings. */ bool v4l2_detect_cvt(unsigned frame_height, unsigned hfreq, unsigned vsync, - u32 polarities, bool interlaced, struct v4l2_dv_timings *fmt); + unsigned active_width, u32 polarities, bool interlaced, + struct v4l2_dv_timings *fmt); /** v4l2_detect_gtf - detect if the given timings follow the GTF standard * @frame_height - the total height of the frame (including blanking) in lines. -- GitLab From 1b3b384177b2de010833fefffac6af3d6ffbdfed Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 12 Jun 2015 03:52:54 -0300 Subject: [PATCH 0390/7006] [media] v4l2-dv-timings: log if the timing is reduced blanking V2 The last CVT standard introduced reduced blanking version 2 which is signaled by a vsync of 8. Log this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index ddaad3d7f1dd9..2c7b9fdfa0af5 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -290,9 +290,11 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", bt->il_vsync, bt->il_vbackporch); pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); - pr_info("%s: flags (0x%x):%s%s%s%s%s\n", dev_prefix, bt->flags, + pr_info("%s: flags (0x%x):%s%s%s%s%s%s\n", dev_prefix, bt->flags, (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? " REDUCED_BLANKING" : "", + ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) && + bt->vsync == 8) ? " (V2)" : "", (bt->flags & V4L2_DV_FL_CAN_REDUCE_FPS) ? " CAN_REDUCE_FPS" : "", (bt->flags & V4L2_DV_FL_REDUCED_FPS) ? -- GitLab From 9aee1ae3312daf0de4c9c614680d06d557133317 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sat, 16 May 2015 15:11:40 -0300 Subject: [PATCH 0391/7006] [media] media: uapi: vsp1: Use __u32 instead of u32 Don't use the kernel types in uapi headers. Signed-off-by: Joe Perches Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- include/uapi/linux/vsp1.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h index e18858f6e865b..9a823696d8165 100644 --- a/include/uapi/linux/vsp1.h +++ b/include/uapi/linux/vsp1.h @@ -28,7 +28,7 @@ _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config) struct vsp1_lut_config { - u32 lut[256]; + __u32 lut[256]; }; #endif /* __VSP1_USER_H__ */ -- GitLab From 5d479386983c5f1bb1aff4f88a027b6143f88a39 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 19 May 2015 20:08:05 -0300 Subject: [PATCH 0392/7006] [media] v4l: omap3isp: Fix async notifier registration order The async notifier was registered before the v4l2_device was registered and before the notifier callbacks were set. This could lead to missing the bound() and complete() callbacks and to attempting to spin_lock() and uninitialised spin lock. Also fix unregistering the async notifier in the case of an error --- the function may not fail anymore after the notifier is registered. Fixes: da7f3843d2c7 ("[media] omap3isp: Add support for the Device Tree") Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 18d0a871747fe..d1334bb1fe378 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2000,10 +2000,8 @@ static int isp_register_entities(struct isp_device *isp) ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); done: - if (ret < 0) { + if (ret < 0) isp_unregister_entities(isp); - v4l2_async_notifier_unregister(&isp->notifier); - } return ret; } @@ -2423,10 +2421,6 @@ static int isp_probe(struct platform_device *pdev) ret = isp_of_parse_nodes(&pdev->dev, &isp->notifier); if (ret < 0) return ret; - ret = v4l2_async_notifier_register(&isp->v4l2_dev, - &isp->notifier); - if (ret) - return ret; } else { isp->pdata = pdev->dev.platform_data; isp->syscon = syscon_regmap_lookup_by_pdevname("syscon.0"); @@ -2557,18 +2551,27 @@ static int isp_probe(struct platform_device *pdev) if (ret < 0) goto error_iommu; - isp->notifier.bound = isp_subdev_notifier_bound; - isp->notifier.complete = isp_subdev_notifier_complete; - ret = isp_register_entities(isp); if (ret < 0) goto error_modules; + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + isp->notifier.bound = isp_subdev_notifier_bound; + isp->notifier.complete = isp_subdev_notifier_complete; + + ret = v4l2_async_notifier_register(&isp->v4l2_dev, + &isp->notifier); + if (ret) + goto error_register_entities; + } + isp_core_init(isp, 1); omap3isp_put(isp); return 0; +error_register_entities: + isp_unregister_entities(isp); error_modules: isp_cleanup_modules(isp); error_iommu: -- GitLab From 9d39f05490115bf145e5ea03c0b7ec9d3d015b01 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 12 Jun 2015 20:06:23 -0300 Subject: [PATCH 0393/7006] [media] v4l: omap3isp: Fix sub-device power management code Commit 813f5c0ac5cc ("media: Change media device link_notify behaviour") modified the media controller link setup notification API and updated the OMAP3 ISP driver accordingly. As a side effect it introduced a bug by turning power on after setting the link instead of before. This results in sub-devices not being powered down in some cases when they should be. Fix it. Fixes: 813f5c0ac5cc [media] media: Change media device link_notify behaviour Signed-off-by: Sakari Ailus Cc: stable@vger.kernel.org # since v3.10 Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index d1334bb1fe378..12be830d704fb 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -829,14 +829,14 @@ static int isp_pipeline_link_notify(struct media_link *link, u32 flags, int ret; if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && - !(link->flags & MEDIA_LNK_FL_ENABLED)) { + !(flags & MEDIA_LNK_FL_ENABLED)) { /* Powering off entities is assumed to never fail. */ isp_pipeline_pm_power(source, -sink_use); isp_pipeline_pm_power(sink, -source_use); return 0; } - if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH && + if (notification == MEDIA_DEV_NOTIFY_PRE_LINK_CH && (flags & MEDIA_LNK_FL_ENABLED)) { ret = isp_pipeline_pm_power(source, sink_use); -- GitLab From 44f4294d5ee58ba3f9dcc0da4cc545c21328eb10 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 12 Apr 2015 09:09:05 -0300 Subject: [PATCH 0394/7006] [media] v4l: omap4iss: Enable driver compilation as a module Now that the driver doesn't use the non-exported omap4_ctrl_pad_readl and omap4_ctrl_pad_writel functions nothing prevents it from being compiled as a module anymore. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/Kconfig | 2 +- drivers/staging/media/omap4iss/TODO | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 072dac04a7500..8d4e3bd1bfe1f 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -1,5 +1,5 @@ config VIDEO_OMAP4 - bool "OMAP 4 Camera support" + tristate "OMAP 4 Camera support" depends on VIDEO_V4L2=y && VIDEO_V4L2_SUBDEV_API && I2C=y && ARCH_OMAP4 depends on HAS_DMA select MFD_SYSCON diff --git a/drivers/staging/media/omap4iss/TODO b/drivers/staging/media/omap4iss/TODO index fcde88860a2cb..4d220ef82653e 100644 --- a/drivers/staging/media/omap4iss/TODO +++ b/drivers/staging/media/omap4iss/TODO @@ -1,4 +1,3 @@ -* Make the driver compile as a module * Fix FIFO/buffer overflows and underflows * Replace dummy resizer code with a real implementation * Fix checkpatch errors and warnings -- GitLab From 408131b85509902b100f7045484c7377a40be99d Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Sun, 12 Apr 2015 09:09:05 -0300 Subject: [PATCH 0395/7006] [media] v4l: omap4iss: Remove video node crop support Cropping should be configured on the pipeline subdev nodes, not through the video nodes. Remove crop support on all video nodes. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/omap4iss/iss_video.c | 73 ---------------------- 1 file changed, 73 deletions(-) diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c index 85c54fedddda2..40405d8710a65 100644 --- a/drivers/staging/media/omap4iss/iss_video.c +++ b/drivers/staging/media/omap4iss/iss_video.c @@ -639,76 +639,6 @@ iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format) return 0; } -static int -iss_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = iss_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, cropcap, cropcap); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - -static int -iss_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev_format format; - struct v4l2_subdev *subdev; - u32 pad; - int ret; - - subdev = iss_video_remote_subdev(video, &pad); - if (subdev == NULL) - return -EINVAL; - - /* Try the get crop operation first and fallback to get format if not - * implemented. - */ - ret = v4l2_subdev_call(subdev, video, g_crop, crop); - if (ret != -ENOIOCTLCMD) - return ret; - - format.pad = pad; - format.which = V4L2_SUBDEV_FORMAT_ACTIVE; - ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format); - if (ret < 0) - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; - - crop->c.left = 0; - crop->c.top = 0; - crop->c.width = format.format.width; - crop->c.height = format.format.height; - - return 0; -} - -static int -iss_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop) -{ - struct iss_video *video = video_drvdata(file); - struct v4l2_subdev *subdev; - int ret; - - subdev = iss_video_remote_subdev(video, NULL); - if (subdev == NULL) - return -EINVAL; - - mutex_lock(&video->mutex); - ret = v4l2_subdev_call(subdev, video, s_crop, crop); - mutex_unlock(&video->mutex); - - return ret == -ENOIOCTLCMD ? -ENOTTY : ret; -} - static int iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a) { @@ -1018,9 +948,6 @@ static const struct v4l2_ioctl_ops iss_video_ioctl_ops = { .vidioc_g_fmt_vid_out = iss_video_get_format, .vidioc_s_fmt_vid_out = iss_video_set_format, .vidioc_try_fmt_vid_out = iss_video_try_format, - .vidioc_cropcap = iss_video_cropcap, - .vidioc_g_crop = iss_video_get_crop, - .vidioc_s_crop = iss_video_set_crop, .vidioc_g_parm = iss_video_get_param, .vidioc_s_parm = iss_video_set_param, .vidioc_reqbufs = iss_video_reqbufs, -- GitLab From 8c0378354709058bba3319bb58fd04bd09e1eaa6 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:45 -0300 Subject: [PATCH 0396/7006] [media] atmel-isi: disable ISI even if it has codec request In current code, stop_streaming() will just return if ISI is still working in the codec. But this is incorrect, we need to disable ISI even it is working on the codec, otherwise stop_streaming() will not work as we expected. Signed-off-by: Josh Wu Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 287902681164f..22270225b202b 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -431,11 +431,9 @@ static void stop_streaming(struct vb2_queue *vq) time_before(jiffies, timeout)) msleep(1); - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout)) dev_err(icd->parent, "Timeout waiting for finishing codec request\n"); - return; - } /* Disable interrupts */ isi_writel(isi, ISI_INTDIS, -- GitLab From f3745a3af521d403d4c174e4bad0986e11f4d2f1 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:46 -0300 Subject: [PATCH 0397/7006] [media] atmel-isi: add runtime pm support The runtime pm resume/suspend will enable/disable pclk (ISI peripheral clock). We have to call runtime_pm_get_sync()/runtime_pm_put() when we need to access ISI registers. In atmel_isi_probe(), remove the isi disable code as at that moment ISI peripheral clock is not enable yet. Besides, clock_start()/clock_stop() is used to control the mclk, not the ISI peripheral clock. So move this to start[stop]_streaming() function. Signed-off-by: Josh Wu Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 55 ++++++++++++++++--- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 22270225b202b..0ea360acea817 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -386,10 +387,13 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count) struct atmel_isi *isi = ici->priv; int ret; + pm_runtime_get_sync(ici->v4l2_dev.dev); + /* Reset ISI */ ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET); if (ret < 0) { dev_err(icd->parent, "Reset ISI timed out\n"); + pm_runtime_put(ici->v4l2_dev.dev); return ret; } /* Disable all interrupts */ @@ -443,6 +447,8 @@ static void stop_streaming(struct vb2_queue *vq) ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE); if (ret < 0) dev_err(icd->parent, "Disable ISI timed out\n"); + + pm_runtime_put(ici->v4l2_dev.dev); } static struct vb2_ops isi_video_qops = { @@ -514,7 +520,13 @@ static int isi_camera_set_fmt(struct soc_camera_device *icd, if (mf->code != xlate->code) return -EINVAL; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + ret = configure_geometry(isi, pix->width, pix->height, xlate->code); + + pm_runtime_put(ici->v4l2_dev.dev); + if (ret < 0) return ret; @@ -734,14 +746,9 @@ static int isi_camera_clock_start(struct soc_camera_host *ici) struct atmel_isi *isi = ici->priv; int ret; - ret = clk_prepare_enable(isi->pclk); - if (ret) - return ret; - if (!IS_ERR(isi->mck)) { ret = clk_prepare_enable(isi->mck); if (ret) { - clk_disable_unprepare(isi->pclk); return ret; } } @@ -756,7 +763,6 @@ static void isi_camera_clock_stop(struct soc_camera_host *ici) if (!IS_ERR(isi->mck)) clk_disable_unprepare(isi->mck); - clk_disable_unprepare(isi->pclk); } static unsigned int isi_camera_poll(struct file *file, poll_table *pt) @@ -853,9 +859,14 @@ static int isi_camera_set_bus_param(struct soc_camera_device *icd) cfg1 |= ISI_CFG1_THMASK_BEATS_16; + /* Enable PM and peripheral clock before operate isi registers */ + pm_runtime_get_sync(ici->v4l2_dev.dev); + isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); isi_writel(isi, ISI_CFG1, cfg1); + pm_runtime_put(ici->v4l2_dev.dev); + return 0; } @@ -887,6 +898,7 @@ static int atmel_isi_remove(struct platform_device *pdev) sizeof(struct fbd) * MAX_BUFFER_NUM, isi->p_fb_descriptors, isi->fb_descriptors_phys); + pm_runtime_disable(&pdev->dev); return 0; } @@ -1025,8 +1037,6 @@ static int atmel_isi_probe(struct platform_device *pdev) if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10) isi->width_flags |= 1 << 9; - isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS); - irq = platform_get_irq(pdev, 0); if (IS_ERR_VALUE(irq)) { ret = irq; @@ -1047,6 +1057,9 @@ static int atmel_isi_probe(struct platform_device *pdev) soc_host->v4l2_dev.dev = &pdev->dev; soc_host->nr = pdev->id; + pm_suspend_ignore_children(&pdev->dev, true); + pm_runtime_enable(&pdev->dev); + if (isi->pdata.asd_sizes) { soc_host->asd = isi->pdata.asd; soc_host->asd_sizes = isi->pdata.asd_sizes; @@ -1060,6 +1073,7 @@ static int atmel_isi_probe(struct platform_device *pdev) return 0; err_register_soc_camera_host: + pm_runtime_disable(&pdev->dev); err_req_irq: err_ioremap: vb2_dma_contig_cleanup_ctx(isi->alloc_ctx); @@ -1072,6 +1086,30 @@ err_alloc_ctx: return ret; } +static int atmel_isi_runtime_suspend(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + clk_disable_unprepare(isi->pclk); + + return 0; +} +static int atmel_isi_runtime_resume(struct device *dev) +{ + struct soc_camera_host *soc_host = to_soc_camera_host(dev); + struct atmel_isi *isi = container_of(soc_host, + struct atmel_isi, soc_host); + + return clk_prepare_enable(isi->pclk); +} + +static const struct dev_pm_ops atmel_isi_dev_pm_ops = { + SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend, + atmel_isi_runtime_resume, NULL) +}; + static const struct of_device_id atmel_isi_of_match[] = { { .compatible = "atmel,at91sam9g45-isi" }, { } @@ -1083,6 +1121,7 @@ static struct platform_driver atmel_isi_driver = { .driver = { .name = "atmel_isi", .of_match_table = of_match_ptr(atmel_isi_of_match), + .pm = &atmel_isi_dev_pm_ops, }, }; -- GitLab From 4a99362da734dfdcca5035dfa15b9f3708f1f8a4 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Tue, 26 May 2015 06:54:47 -0300 Subject: [PATCH 0398/7006] [media] atmel-isi: remove mck backward compatibility code The master clock should be handled by sensor itself. Signed-off-by: Josh Wu Acked-by: Laurent Pinchart Signed-off-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/soc_camera/atmel-isi.c | 46 ------------------- 1 file changed, 46 deletions(-) diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c index 0ea360acea817..90701726a06a2 100644 --- a/drivers/media/platform/soc_camera/atmel-isi.c +++ b/drivers/media/platform/soc_camera/atmel-isi.c @@ -35,7 +35,6 @@ #define VID_LIMIT_BYTES (16 * 1024 * 1024) #define MIN_FRAME_RATE 15 #define FRAME_INTERVAL_MILLI_SEC (1000 / MIN_FRAME_RATE) -#define ISI_DEFAULT_MCLK_FREQ 25000000 /* Frame buffer descriptor */ struct fbd { @@ -83,8 +82,6 @@ struct atmel_isi { struct completion complete; /* ISI peripherial clock */ struct clk *pclk; - /* ISI_MCK, feed to camera sensor to generate pixel clock */ - struct clk *mck; unsigned int irq; struct isi_platform_data pdata; @@ -740,31 +737,6 @@ static void isi_camera_remove_device(struct soc_camera_device *icd) icd->devnum); } -/* Called with .host_lock held */ -static int isi_camera_clock_start(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - int ret; - - if (!IS_ERR(isi->mck)) { - ret = clk_prepare_enable(isi->mck); - if (ret) { - return ret; - } - } - - return 0; -} - -/* Called with .host_lock held */ -static void isi_camera_clock_stop(struct soc_camera_host *ici) -{ - struct atmel_isi *isi = ici->priv; - - if (!IS_ERR(isi->mck)) - clk_disable_unprepare(isi->mck); -} - static unsigned int isi_camera_poll(struct file *file, poll_table *pt) { struct soc_camera_device *icd = file->private_data; @@ -874,8 +846,6 @@ static struct soc_camera_host_ops isi_soc_camera_host_ops = { .owner = THIS_MODULE, .add = isi_camera_add_device, .remove = isi_camera_remove_device, - .clock_start = isi_camera_clock_start, - .clock_stop = isi_camera_clock_stop, .set_fmt = isi_camera_set_fmt, .try_fmt = isi_camera_try_fmt, .get_formats = isi_camera_get_formats, @@ -912,7 +882,6 @@ static int atmel_isi_probe_dt(struct atmel_isi *isi, /* Default settings for ISI */ isi->pdata.full_mode = 1; - isi->pdata.mck_hz = ISI_DEFAULT_MCLK_FREQ; isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; np = of_graph_get_next_endpoint(np, NULL); @@ -988,21 +957,6 @@ static int atmel_isi_probe(struct platform_device *pdev) INIT_LIST_HEAD(&isi->video_buffer_list); INIT_LIST_HEAD(&isi->dma_desc_head); - /* ISI_MCK is the sensor master clock. It should be handled by the - * sensor driver directly, as the ISI has no use for that clock. Make - * the clock optional here while platforms transition to the correct - * model. - */ - isi->mck = devm_clk_get(dev, "isi_mck"); - if (!IS_ERR(isi->mck)) { - /* Set ISI_MCK's frequency, it should be faster than pixel - * clock. - */ - ret = clk_set_rate(isi->mck, isi->pdata.mck_hz); - if (ret < 0) - return ret; - } - isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev, sizeof(struct fbd) * MAX_BUFFER_NUM, &isi->fb_descriptors_phys, -- GitLab From 4366dfef377034e97d5b35677b7a1ebb1f1ce6dc Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Wed, 10 Jun 2015 10:38:29 -0300 Subject: [PATCH 0399/7006] [media] media/v4l2-ctrls: Code cleanout validate_new() We can simplify the code removing the if(). v4l2_ctr_new sets ctrls->elems to 1 when !ctrl->is_ptr. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index e3a3468002e69..b6b7dcc1b77d4 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -1678,21 +1678,6 @@ static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new) unsigned idx; int err = 0; - if (!ctrl->is_ptr) { - switch (ctrl->type) { - case V4L2_CTRL_TYPE_INTEGER: - case V4L2_CTRL_TYPE_INTEGER_MENU: - case V4L2_CTRL_TYPE_MENU: - case V4L2_CTRL_TYPE_BITMASK: - case V4L2_CTRL_TYPE_BOOLEAN: - case V4L2_CTRL_TYPE_BUTTON: - case V4L2_CTRL_TYPE_CTRL_CLASS: - case V4L2_CTRL_TYPE_INTEGER64: - return ctrl->type_ops->validate(ctrl, 0, p_new); - default: - break; - } - } for (idx = 0; !err && idx < ctrl->elems; idx++) err = ctrl->type_ops->validate(ctrl, idx, p_new); return err; -- GitLab From 227da85e775065c81e222f443e8379aba4d3f668 Mon Sep 17 00:00:00 2001 From: Prashant Laddha Date: Fri, 12 Jun 2015 08:48:10 -0300 Subject: [PATCH 0400/7006] [media] v4l2-dv-timings: print refresh rate with better precision In many cases, refresh rate is not exact integer. In such cases, fraction was lost and it used to print, say, 59 in case of 59.94. Now, capturing the fraction up to 2 decimal places. Signed-off-by: Prashant Laddha Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-dv-timings.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 2c7b9fdfa0af5..6a83d61916840 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -256,6 +256,7 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, { const struct v4l2_bt_timings *bt = &t->bt; u32 htot, vtot; + u32 fps; if (t->type != V4L2_DV_BT_656_1120) return; @@ -265,13 +266,15 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, if (bt->interlaced) vtot /= 2; + fps = (htot * vtot) > 0 ? div_u64((100 * (u64)bt->pixelclock), + (htot * vtot)) : 0; + if (prefix == NULL) prefix = ""; - pr_info("%s: %s%ux%u%s%u (%ux%u)\n", dev_prefix, prefix, + pr_info("%s: %s%ux%u%s%u.%u (%ux%u)\n", dev_prefix, prefix, bt->width, bt->height, bt->interlaced ? "i" : "p", - (htot * vtot) > 0 ? ((u32)bt->pixelclock / (htot * vtot)) : 0, - htot, vtot); + fps / 100, fps % 100, htot, vtot); if (!detailed) return; -- GitLab From 747d481df3b9b6ef46ccb233d74c8d93ec4819e6 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:07 -0300 Subject: [PATCH 0401/7006] [media] media/i2c/adv7343: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7343.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/adv7343.c b/drivers/media/i2c/adv7343.c index 7c50833e7d172..d272831354906 100644 --- a/drivers/media/i2c/adv7343.c +++ b/drivers/media/i2c/adv7343.c @@ -319,13 +319,6 @@ static const struct v4l2_ctrl_ops adv7343_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7343_core_ops = { .log_status = adv7343_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -- GitLab From 260faaa490d29cd2ad3cad54fbda0ede406c818e Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:08 -0300 Subject: [PATCH 0402/7006] [media] media/i2c/adv7393: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7393.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/adv7393.c b/drivers/media/i2c/adv7393.c index 558f19154eb9c..0215f95c22454 100644 --- a/drivers/media/i2c/adv7393.c +++ b/drivers/media/i2c/adv7393.c @@ -306,13 +306,6 @@ static const struct v4l2_ctrl_ops adv7393_ctrl_ops = { static const struct v4l2_subdev_core_ops adv7393_core_ops = { .log_status = adv7393_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static int adv7393_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std) -- GitLab From 6ceea1f7d021492ed13609fa1cf401484dae0e0d Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:09 -0300 Subject: [PATCH 0403/7006] [media] media/i2c/cs5345: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cs5345.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/cs5345.c b/drivers/media/i2c/cs5345.c index 34b76a9e7515b..8cebf9cc80073 100644 --- a/drivers/media/i2c/cs5345.c +++ b/drivers/media/i2c/cs5345.c @@ -132,13 +132,6 @@ static const struct v4l2_ctrl_ops cs5345_ctrl_ops = { static const struct v4l2_subdev_core_ops cs5345_core_ops = { .log_status = cs5345_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = cs5345_g_register, .s_register = cs5345_s_register, -- GitLab From 3cfa008e3cafa90684f84abbfb995cec437a61ea Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:10 -0300 Subject: [PATCH 0404/7006] [media] media/i2c/saa717x: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/saa717x.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c index 7d517361e419a..c6ba19cf1aa54 100644 --- a/drivers/media/i2c/saa717x.c +++ b/drivers/media/i2c/saa717x.c @@ -1204,13 +1204,6 @@ static const struct v4l2_subdev_core_ops saa717x_core_ops = { .g_register = saa717x_g_register, .s_register = saa717x_s_register, #endif - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, .log_status = saa717x_log_status, }; -- GitLab From fc1a33fed0274efefbfc5f463a69efbaee4d989f Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:12 -0300 Subject: [PATCH 0405/7006] [media] media/i2c/tda7432: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tda7432.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/tda7432.c b/drivers/media/i2c/tda7432.c index cf93021a65009..d3834a4c48da7 100644 --- a/drivers/media/i2c/tda7432.c +++ b/drivers/media/i2c/tda7432.c @@ -331,13 +331,6 @@ static const struct v4l2_ctrl_ops tda7432_ctrl_ops = { static const struct v4l2_subdev_core_ops tda7432_core_ops = { .log_status = tda7432_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_ops tda7432_ops = { -- GitLab From 8b198c6b8b65ef39c3652972c36a43e04b4482dd Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:13 -0300 Subject: [PATCH 0406/7006] [media] media/i2c/tlv320aic23: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tlv320aic23b.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index ef87f7b09ea27..0370dd89f1fcd 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c @@ -122,13 +122,6 @@ static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = { static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = { .log_status = tlv320aic23b_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = { -- GitLab From e5b40d2e11c3e2ed60ecb70313765d48c7786448 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:14 -0300 Subject: [PATCH 0407/7006] [media] media/i2c/tvp514x: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp514x.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index 24e47279e30c1..a93985a9b0703 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -957,16 +957,6 @@ static int tvp514x_set_pad_format(struct v4l2_subdev *sd, return 0; } -static const struct v4l2_subdev_core_ops tvp514x_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - static const struct v4l2_subdev_video_ops tvp514x_video_ops = { .s_std = tvp514x_s_std, .s_routing = tvp514x_s_routing, @@ -983,7 +973,6 @@ static const struct v4l2_subdev_pad_ops tvp514x_pad_ops = { }; static const struct v4l2_subdev_ops tvp514x_ops = { - .core = &tvp514x_core_ops, .video = &tvp514x_video_ops, .pad = &tvp514x_pad_ops, }; -- GitLab From f5f24bc3267b3651e8bb026a5669dfe6855ffe63 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:15 -0300 Subject: [PATCH 0408/7006] [media] media/i2c/tvp7002: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp7002.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c index 05077cffd2351..f617d8b745eec 100644 --- a/drivers/media/i2c/tvp7002.c +++ b/drivers/media/i2c/tvp7002.c @@ -861,13 +861,6 @@ tvp7002_set_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cf /* V4L2 core operation handlers */ static const struct v4l2_subdev_core_ops tvp7002_core_ops = { .log_status = tvp7002_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = tvp7002_g_register, .s_register = tvp7002_s_register, -- GitLab From c2527967c5795815d3422f147af767293b3806eb Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:16 -0300 Subject: [PATCH 0409/7006] [media] i2c/wm8739: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/wm8739.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c index 3be73f6a40e95..534b0e5603174 100644 --- a/drivers/media/i2c/wm8739.c +++ b/drivers/media/i2c/wm8739.c @@ -176,13 +176,6 @@ static const struct v4l2_ctrl_ops wm8739_ctrl_ops = { static const struct v4l2_subdev_core_ops wm8739_core_ops = { .log_status = wm8739_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_audio_ops wm8739_audio_ops = { -- GitLab From 59617e74e20dac9523e34f5461162b19347dacf8 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:17 -0300 Subject: [PATCH 0410/7006] [media] pci/ivtv/ivtv-gpio: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-gpio.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/pci/ivtv/ivtv-gpio.c b/drivers/media/pci/ivtv/ivtv-gpio.c index af52def700cc2..f752f39936874 100644 --- a/drivers/media/pci/ivtv/ivtv-gpio.c +++ b/drivers/media/pci/ivtv/ivtv-gpio.c @@ -313,13 +313,6 @@ static const struct v4l2_ctrl_ops gpio_ctrl_ops = { static const struct v4l2_subdev_core_ops subdev_core_ops = { .log_status = subdev_log_status, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = { -- GitLab From 387a69243890a51be023aef12d0fdcae343f43f2 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:18 -0300 Subject: [PATCH 0411/7006] [media] media/radio/saa7706h: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/saa7706h.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/media/radio/saa7706h.c b/drivers/media/radio/saa7706h.c index ec805b09c6086..183e92719140b 100644 --- a/drivers/media/radio/saa7706h.c +++ b/drivers/media/radio/saa7706h.c @@ -336,19 +336,7 @@ static const struct v4l2_ctrl_ops saa7706h_ctrl_ops = { .s_ctrl = saa7706h_s_ctrl, }; -static const struct v4l2_subdev_core_ops saa7706h_core_ops = { - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, -}; - -static const struct v4l2_subdev_ops saa7706h_ops = { - .core = &saa7706h_core_ops, -}; +static const struct v4l2_subdev_ops empty_ops = {}; /* * Generic i2c probe @@ -373,7 +361,7 @@ static int saa7706h_probe(struct i2c_client *client, if (state == NULL) return -ENOMEM; sd = &state->sd; - v4l2_i2c_subdev_init(sd, client, &saa7706h_ops); + v4l2_i2c_subdev_init(sd, client, &empty_ops); v4l2_ctrl_handler_init(&state->hdl, 4); v4l2_ctrl_new_std(&state->hdl, &saa7706h_ctrl_ops, -- GitLab From 0a2a89c4acbf2ede9cdcc51d7113091978079b7b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 4 Jun 2015 05:52:26 -0300 Subject: [PATCH 0412/7006] [media] gspca: sn9c2028: remove an unneeded condition We already know status is negative because of the earlier check so there is no need to check again. Signed-off-by: Dan Carpenter Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/sn9c2028.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/sn9c2028.c b/drivers/media/usb/gspca/sn9c2028.c index c75b7388a85c7..4f2050a5ec941 100644 --- a/drivers/media/usb/gspca/sn9c2028.c +++ b/drivers/media/usb/gspca/sn9c2028.c @@ -140,7 +140,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command) status = sn9c2028_read1(gspca_dev); if (status < 0) { pr_err("long command status read error %d\n", status); - return (status < 0) ? status : -EIO; + return status; } memset(reading, 0, 4); -- GitLab From 63f2f417526fc54191f2b813f72dc1d5322bede8 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 7 Jun 2015 11:34:40 -0300 Subject: [PATCH 0413/7006] [media] gscpa_m5602: use msecs_to_jiffies for conversions API compliance scanning with coccinelle flagged: ./drivers/media/usb/gspca/m5602/m5602_s5k83a.c:180:9-25: WARNING: timeout (100) seems HZ dependent Numeric constants passed to schedule_timeout() make the effective timeout HZ dependent which makes little sense in a polling loop for the cameras rotation state. Fixed up by converting the constant to jiffies with msecs_to_jiffies() Signed-off-by: Nicholas Mc Guire Signed-off-by: Hans de Goede Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/m5602/m5602_s5k83a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c index 7cbc3a00bda87..bf6b215438e38 100644 --- a/drivers/media/usb/gspca/m5602/m5602_s5k83a.c +++ b/drivers/media/usb/gspca/m5602/m5602_s5k83a.c @@ -177,7 +177,7 @@ static int rotation_thread_function(void *data) __s32 vflip, hflip; set_current_state(TASK_INTERRUPTIBLE); - while (!schedule_timeout(100)) { + while (!schedule_timeout(msecs_to_jiffies(100))) { if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) break; -- GitLab From 03b36e4dcf422a10da8b67bce2ed00b34ec58aac Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 28 Jan 2015 22:53:53 -0200 Subject: [PATCH 0414/7006] [media] v4l: vsp1: Fix VI6_WPF_SZCLIP_SIZE_MASK macro Clipping size bit of VI6_WPFn _HSZCLIP and VI6_WPFn _VSZCLIP register are from 0 bit to 11 bit. But VI6_WPF_SZCLIP_SIZE_MASK is set to 0x1FFF, this will mask until the reserve bits. This fixes size for VI6_WPF_SZCLIP_SIZE_MASK. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index da3c573e1efca..f61e1096f9fc3 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -238,7 +238,7 @@ #define VI6_WPF_SZCLIP_EN (1 << 28) #define VI6_WPF_SZCLIP_OFST_MASK (0xff << 16) #define VI6_WPF_SZCLIP_OFST_SHIFT 16 -#define VI6_WPF_SZCLIP_SIZE_MASK (0x1fff << 0) +#define VI6_WPF_SZCLIP_SIZE_MASK (0xfff << 0) #define VI6_WPF_SZCLIP_SIZE_SHIFT 0 #define VI6_WPF_OUTFMT 0x100c -- GitLab From 1aa7890324b497f96f07c20673fae58f26fabfe7 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 28 Jan 2015 22:53:54 -0200 Subject: [PATCH 0415/7006] [media] v4l: vsp1: Fix VI6_DPR_ROUTE_FP_MASK macro FP bit of VI6_DPR_mod_ROUTE register is 6bit. But VI6_DPR_ROUTE_FP_MASK is set to 0xFF, this will mask until the reserve bit. This fixes size for VI6_DPR_ROUTE_FP_MASK. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index f61e1096f9fc3..4177f98968d6a 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -306,7 +306,7 @@ #define VI6_DPR_BRU_ROUTE 0x204c #define VI6_DPR_ROUTE_FXA_MASK (0xff << 8) #define VI6_DPR_ROUTE_FXA_SHIFT 16 -#define VI6_DPR_ROUTE_FP_MASK (0xff << 8) +#define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) #define VI6_DPR_ROUTE_FP_SHIFT 8 #define VI6_DPR_ROUTE_RT_MASK (0x3f << 0) #define VI6_DPR_ROUTE_RT_SHIFT 0 -- GitLab From 45008ee9295b3ae96d7413ab91871907a671ca82 Mon Sep 17 00:00:00 2001 From: Nobuhiro Iwamatsu Date: Wed, 28 Jan 2015 22:53:55 -0200 Subject: [PATCH 0416/7006] [media] v4l: vsp1: Fix VI6_DPR_ROUTE_FXA_MASK macro FXA bit of VI6_DPR_mod_ROUTE register starts from 16bit. But VI6_DPR_ROUTE_FXA_MASK is set to become start from 8bit. This fixes shift size for VI6_DPR_ROUTE_FXA_MASK. Signed-off-by: Nobuhiro Iwamatsu Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_regs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h index 4177f98968d6a..25b48738b1470 100644 --- a/drivers/media/platform/vsp1/vsp1_regs.h +++ b/drivers/media/platform/vsp1/vsp1_regs.h @@ -304,7 +304,7 @@ #define VI6_DPR_HST_ROUTE 0x2044 #define VI6_DPR_HSI_ROUTE 0x2048 #define VI6_DPR_BRU_ROUTE 0x204c -#define VI6_DPR_ROUTE_FXA_MASK (0xff << 8) +#define VI6_DPR_ROUTE_FXA_MASK (0xff << 16) #define VI6_DPR_ROUTE_FXA_SHIFT 16 #define VI6_DPR_ROUTE_FP_MASK (0x3f << 8) #define VI6_DPR_ROUTE_FP_SHIFT 8 -- GitLab From 139c92866e34bfa4897e644b36147fc86cc7a7a1 Mon Sep 17 00:00:00 2001 From: Sei Fumizono Date: Sun, 15 Mar 2015 11:33:07 -0300 Subject: [PATCH 0417/7006] [media] v4l: vsp1: Fix Suspend-to-RAM Fix Suspend-to-RAM so that VSP1 driver continues to work after resuming. In detail, - Fix the judgment of ref count in resuming. - Add stopping VSP1 during suspend. [Refactor the suspend and resume code to lower suspend delay] Signed-off-by: Sei Fumizono Signed-off-by: Yoshifumi Hosoya Signed-off-by: Yoshihiro Kaneko Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 13 ++++- drivers/media/platform/vsp1/vsp1_video.c | 70 +++++++++++++++++++++++- drivers/media/platform/vsp1/vsp1_video.h | 5 +- 3 files changed, 83 insertions(+), 5 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 913485a90e973..4e61886384e32 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -1,7 +1,7 @@ /* * vsp1_drv.c -- R-Car VSP1 Driver * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -403,7 +403,10 @@ static int vsp1_pm_suspend(struct device *dev) if (vsp1->ref_count == 0) return 0; + vsp1_pipelines_suspend(vsp1); + clk_disable_unprepare(vsp1->clock); + return 0; } @@ -413,10 +416,14 @@ static int vsp1_pm_resume(struct device *dev) WARN_ON(mutex_is_locked(&vsp1->lock)); - if (vsp1->ref_count) + if (vsp1->ref_count == 0) return 0; - return clk_prepare_enable(vsp1->clock); + clk_prepare_enable(vsp1->clock); + + vsp1_pipelines_resume(vsp1); + + return 0; } #endif diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index d91f19a9e1c16..c4b06214b6c18 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -1,7 +1,7 @@ /* * vsp1_video.c -- R-Car VSP1 Video Node * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -703,6 +703,74 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, } } +void vsp1_pipelines_suspend(struct vsp1_device *vsp1) +{ + unsigned long flags; + unsigned int i; + int ret; + + /* To avoid increasing the system suspend time needlessly, loop over the + * pipelines twice, first to set them all to the stopping state, and then + * to wait for the stop to complete. + */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + spin_lock_irqsave(&pipe->irqlock, flags); + if (pipe->state == VSP1_PIPELINE_RUNNING) + pipe->state = VSP1_PIPELINE_STOPPING; + spin_unlock_irqrestore(&pipe->irqlock, flags); + } + + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + ret = wait_event_timeout(pipe->wq, + pipe->state == VSP1_PIPELINE_STOPPED, + msecs_to_jiffies(500)); + if (ret == 0) + dev_warn(vsp1->dev, "pipeline %u stop timeout\n", + wpf->entity.index); + } +} + +void vsp1_pipelines_resume(struct vsp1_device *vsp1) +{ + unsigned int i; + + /* Resume pipeline all running pipelines. */ + for (i = 0; i < vsp1->pdata.wpf_count; ++i) { + struct vsp1_rwpf *wpf = vsp1->wpf[i]; + struct vsp1_pipeline *pipe; + + if (wpf == NULL) + continue; + + pipe = to_vsp1_pipeline(&wpf->entity.subdev.entity); + if (pipe == NULL) + continue; + + if (vsp1_pipeline_ready(pipe)) + vsp1_pipeline_run(pipe); + } +} + /* ----------------------------------------------------------------------------- * videobuf2 Queue Operations */ diff --git a/drivers/media/platform/vsp1/vsp1_video.h b/drivers/media/platform/vsp1/vsp1_video.h index fd2851a82e001..0887a4d2742ca 100644 --- a/drivers/media/platform/vsp1/vsp1_video.h +++ b/drivers/media/platform/vsp1/vsp1_video.h @@ -1,7 +1,7 @@ /* * vsp1_video.h -- R-Car VSP1 Video Node * - * Copyright (C) 2013-2014 Renesas Electronics Corporation + * Copyright (C) 2013-2015 Renesas Electronics Corporation * * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com) * @@ -149,4 +149,7 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe, struct vsp1_entity *input, unsigned int alpha); +void vsp1_pipelines_suspend(struct vsp1_device *vsp1); +void vsp1_pipelines_resume(struct vsp1_device *vsp1); + #endif /* __VSP1_VIDEO_H__ */ -- GitLab From 1c991fee30c72ff49bb96558d5f1c14a60230677 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Wed, 29 Apr 2015 16:54:39 -0300 Subject: [PATCH 0418/7006] [media] v4l: vsp1: Fix race condition when stopping pipeline When stopping the pipeline the driver waits for the pipeline state to be set to VSP1_PIPELINE_STOPPED but fails to lock the pipe irqlock to read the state variable protected by the lock. Fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index c4b06214b6c18..c1b5a09b83312 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -514,6 +514,18 @@ static void vsp1_pipeline_run(struct vsp1_pipeline *pipe) pipe->buffers_ready = 0; } +bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) +{ + unsigned long flags; + bool stopped; + + spin_lock_irqsave(&pipe->irqlock, flags); + stopped = pipe->state == VSP1_PIPELINE_STOPPED, + spin_unlock_irqrestore(&pipe->irqlock, flags); + + return stopped; +} + static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) { struct vsp1_entity *entity; @@ -525,7 +537,7 @@ static int vsp1_pipeline_stop(struct vsp1_pipeline *pipe) pipe->state = VSP1_PIPELINE_STOPPING; spin_unlock_irqrestore(&pipe->irqlock, flags); - ret = wait_event_timeout(pipe->wq, pipe->state == VSP1_PIPELINE_STOPPED, + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), msecs_to_jiffies(500)); ret = ret == 0 ? -ETIMEDOUT : 0; @@ -741,8 +753,7 @@ void vsp1_pipelines_suspend(struct vsp1_device *vsp1) if (pipe == NULL) continue; - ret = wait_event_timeout(pipe->wq, - pipe->state == VSP1_PIPELINE_STOPPED, + ret = wait_event_timeout(pipe->wq, vsp1_pipeline_stopped(pipe), msecs_to_jiffies(500)); if (ret == 0) dev_warn(vsp1->dev, "pipeline %u stop timeout\n", -- GitLab From 85a0638b7855dfb00dc9b66bc2fdd4276d7dc87c Mon Sep 17 00:00:00 2001 From: Damian Hobson-Garcia Date: Thu, 28 May 2015 09:59:39 -0300 Subject: [PATCH 0419/7006] [media] v4l: vsp1: Align crop rectangle to even boundary for YUV formats Make sure that there are valid values in the crop rectangle to ensure that the color plane doesn't get shifted when cropping. Since there is no distinction between 12bit and 16bit YUV formats in at the subdev level, use the more restrictive 12bit limits for all YUV formats. Signed-off-by: Damian Hobson-Garcia Signed-off-by: Yoshihiro Kaneko Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_rwpf.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index fa71f4695e168..9688c219b30e5 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -197,6 +197,17 @@ int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev, */ format = vsp1_entity_get_pad_format(&rwpf->entity, cfg, RWPF_PAD_SINK, sel->which); + + /* Restrict the crop rectangle coordinates to multiples of 2 to avoid + * shifting the color plane. + */ + if (format->code == MEDIA_BUS_FMT_AYUV8_1X32) { + sel->r.left = ALIGN(sel->r.left, 2); + sel->r.top = ALIGN(sel->r.top, 2); + sel->r.width = round_down(sel->r.width, 2); + sel->r.height = round_down(sel->r.height, 2); + } + sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2); sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2); if (rwpf->entity.type == VSP1_ENTITY_WPF) { -- GitLab From e36f1b19e80dfd89d56a5af8f4b20d2fc170c3fe Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:55 -0300 Subject: [PATCH 0420/7006] [media] clock-sh7724.c: fix sh-vou clock identifier Bitrot has set in for this driver and the sh-vou clock was never enabled, since the clock name in clock-sh7724.c was wrong. It should be sh-vou, not sh-vou.0. Signed-off-by: Hans Verkuil Thanks-to: Geert Uytterhoeven Cc: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- arch/sh/kernel/cpu/sh4a/clock-sh7724.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c index c187b9579c212..f27c618de5274 100644 --- a/arch/sh/kernel/cpu/sh4a/clock-sh7724.c +++ b/arch/sh/kernel/cpu/sh4a/clock-sh7724.c @@ -343,7 +343,7 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("2ddmac0", &mstp_clks[HWBLK_2DDMAC]), CLKDEV_DEV_ID("sh_fsi.0", &mstp_clks[HWBLK_SPU]), CLKDEV_CON_ID("jpu0", &mstp_clks[HWBLK_JPU]), - CLKDEV_DEV_ID("sh-vou.0", &mstp_clks[HWBLK_VOU]), + CLKDEV_DEV_ID("sh-vou", &mstp_clks[HWBLK_VOU]), CLKDEV_CON_ID("beu0", &mstp_clks[HWBLK_BEU0]), CLKDEV_DEV_ID("sh_mobile_ceu.0", &mstp_clks[HWBLK_CEU0]), CLKDEV_CON_ID("veu0", &mstp_clks[HWBLK_VEU0]), -- GitLab From 41bdc3cf81c4d0f0dfe09f06ff203dd59d422f37 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 3 Jul 2015 08:35:51 -0300 Subject: [PATCH 0421/7006] [media] vsp1: declar vsp1_pipeline_stopped() as static drivers/media/platform/vsp1/vsp1_video.c:517:6: warning: no previous prototype for 'vsp1_pipeline_stopped' [-Wmissing-prototypes] bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index c1b5a09b83312..770e08dc03f1e 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -514,7 +514,7 @@ static void vsp1_pipeline_run(struct vsp1_pipeline *pipe) pipe->buffers_ready = 0; } -bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) +static bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe) { unsigned long flags; bool stopped; -- GitLab From 4690271ce14cd4cf4796e0b6631978d151abe8e4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:56 -0300 Subject: [PATCH 0422/7006] [media] sh-vou: use resource managed calls Simplify the sh-vou clean up by using devm_* were possible. Signed-off-by: Hans Verkuil Cc: Magnus Damm Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 43 ++++++--------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 8b799bae01b8d..801d5ef4dc289 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1300,7 +1300,7 @@ static int sh_vou_probe(struct platform_device *pdev) struct i2c_adapter *i2c_adap; struct video_device *vdev; struct sh_vou_device *vou_dev; - struct resource *reg_res, *region; + struct resource *reg_res; struct v4l2_subdev *subdev; int irq, ret; @@ -1312,7 +1312,7 @@ static int sh_vou_probe(struct platform_device *pdev) return -ENODEV; } - vou_dev = kzalloc(sizeof(*vou_dev), GFP_KERNEL); + vou_dev = devm_kzalloc(&pdev->dev, sizeof(*vou_dev), GFP_KERNEL); if (!vou_dev) return -ENOMEM; @@ -1340,28 +1340,18 @@ static int sh_vou_probe(struct platform_device *pdev) pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; - region = request_mem_region(reg_res->start, resource_size(reg_res), - pdev->name); - if (!region) { - dev_err(&pdev->dev, "VOU region already claimed\n"); - ret = -EBUSY; - goto ereqmemreg; - } - - vou_dev->base = ioremap(reg_res->start, resource_size(reg_res)); - if (!vou_dev->base) { - ret = -ENOMEM; - goto emap; - } + vou_dev->base = devm_ioremap_resource(&pdev->dev, reg_res); + if (IS_ERR(vou_dev->base)) + return PTR_ERR(vou_dev->base); - ret = request_irq(irq, sh_vou_isr, 0, "vou", vou_dev); + ret = devm_request_irq(&pdev->dev, irq, sh_vou_isr, 0, "vou", vou_dev); if (ret < 0) - goto ereqirq; + return ret; ret = v4l2_device_register(&pdev->dev, &vou_dev->v4l2_dev); if (ret < 0) { dev_err(&pdev->dev, "Error registering v4l2 device\n"); - goto ev4l2devreg; + return ret; } vdev = &vou_dev->vdev; @@ -1407,39 +1397,22 @@ ereset: ei2cgadap: pm_runtime_disable(&pdev->dev); v4l2_device_unregister(&vou_dev->v4l2_dev); -ev4l2devreg: - free_irq(irq, vou_dev); -ereqirq: - iounmap(vou_dev->base); -emap: - release_mem_region(reg_res->start, resource_size(reg_res)); -ereqmemreg: - kfree(vou_dev); return ret; } static int sh_vou_remove(struct platform_device *pdev) { - int irq = platform_get_irq(pdev, 0); struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev); struct sh_vou_device *vou_dev = container_of(v4l2_dev, struct sh_vou_device, v4l2_dev); struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next, struct v4l2_subdev, list); struct i2c_client *client = v4l2_get_subdevdata(sd); - struct resource *reg_res; - if (irq > 0) - free_irq(irq, vou_dev); pm_runtime_disable(&pdev->dev); video_unregister_device(&vou_dev->vdev); i2c_put_adapter(client->adapter); v4l2_device_unregister(&vou_dev->v4l2_dev); - iounmap(vou_dev->base); - reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (reg_res) - release_mem_region(reg_res->start, resource_size(reg_res)); - kfree(vou_dev); return 0; } -- GitLab From d8046ee09f843cb314a660f589a334bce84a7efa Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:57 -0300 Subject: [PATCH 0423/7006] [media] sh-vou: fix querycap support Fix v4l2-compliance errors due to empty driver and bus_info fields. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 801d5ef4dc289..d7a72a9ba90b7 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -396,6 +396,8 @@ static int sh_vou_querycap(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); + strlcpy(cap->driver, "sh-vou", sizeof(cap->driver)); + strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; -- GitLab From c5f98085bf3f1d645aaf76eac7c9ca0e2ab684c6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:58 -0300 Subject: [PATCH 0424/7006] [media] sh-vou: use v4l2_fh This allows us to drop the use_count and you get free G/S_PRIORITY support. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index d7a72a9ba90b7..4994b7ba9236a 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -63,7 +63,6 @@ enum sh_vou_status { struct sh_vou_device { struct v4l2_device v4l2_dev; struct video_device vdev; - atomic_t use_count; struct sh_vou_pdata *pdata; spinlock_t lock; void __iomem *base; @@ -79,6 +78,7 @@ struct sh_vou_device { }; struct sh_vou_file { + struct v4l2_fh fh; struct videobuf_queue vbq; }; @@ -1173,20 +1173,24 @@ static int sh_vou_open(struct file *file) dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + v4l2_fh_init(&vou_file->fh, &vou_dev->vdev); if (mutex_lock_interruptible(&vou_dev->fop_lock)) { kfree(vou_file); return -ERESTARTSYS; } - if (atomic_inc_return(&vou_dev->use_count) == 1) { + v4l2_fh_add(&vou_file->fh); + if (v4l2_fh_is_singular(&vou_file->fh)) { int ret; + /* First open */ vou_dev->status = SH_VOU_INITIALISING; pm_runtime_get_sync(vou_dev->v4l2_dev.dev); ret = sh_vou_hw_init(vou_dev); if (ret < 0) { - atomic_dec(&vou_dev->use_count); pm_runtime_put(vou_dev->v4l2_dev.dev); vou_dev->status = SH_VOU_IDLE; + v4l2_fh_del(&vou_file->fh); + v4l2_fh_exit(&vou_file->fh); mutex_unlock(&vou_dev->fop_lock); kfree(vou_file); return ret; @@ -1213,14 +1217,16 @@ static int sh_vou_release(struct file *file) dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (!atomic_dec_return(&vou_dev->use_count)) { - mutex_lock(&vou_dev->fop_lock); + mutex_lock(&vou_dev->fop_lock); + if (v4l2_fh_is_singular(&vou_file->fh)) { /* Last close */ vou_dev->status = SH_VOU_IDLE; sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); pm_runtime_put(vou_dev->v4l2_dev.dev); - mutex_unlock(&vou_dev->fop_lock); } + v4l2_fh_del(&vou_file->fh); + v4l2_fh_exit(&vou_file->fh); + mutex_unlock(&vou_dev->fop_lock); file->private_data = NULL; kfree(vou_file); @@ -1321,7 +1327,6 @@ static int sh_vou_probe(struct platform_device *pdev) INIT_LIST_HEAD(&vou_dev->queue); spin_lock_init(&vou_dev->lock); mutex_init(&vou_dev->fop_lock); - atomic_set(&vou_dev->use_count, 0); vou_dev->pdata = vou_pdata; vou_dev->status = SH_VOU_IDLE; -- GitLab From 4de00d0efe0a7af8e2ef591effa2a559b7cc38a3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:57:59 -0300 Subject: [PATCH 0425/7006] [media] sh-vou: support compulsory G/S/ENUM_OUTPUT ioctls Video output drivers must support these ioctls. Otherwise applications cannot deduce that these outputs exist and what capabilities they have. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 4994b7ba9236a..d9a4502b4a588 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -872,6 +872,30 @@ static int sh_vou_streamoff(struct file *file, void *priv, return 0; } +static int sh_vou_enum_output(struct file *file, void *fh, + struct v4l2_output *a) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + + if (a->index) + return -EINVAL; + strlcpy(a->name, "Video Out", sizeof(a->name)); + a->type = V4L2_OUTPUT_TYPE_ANALOG; + a->std = vou_dev->vdev.tvnorms; + return 0; +} + +int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) +{ + *i = 0; + return 0; +} + +int sh_vou_s_output(struct file *file, void *fh, unsigned int i) +{ + return i ? -EINVAL : 0; +} + static u32 sh_vou_ntsc_mode(enum sh_vou_bus_fmt bus_fmt) { switch (bus_fmt) { @@ -1276,6 +1300,9 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_dqbuf = sh_vou_dqbuf, .vidioc_streamon = sh_vou_streamon, .vidioc_streamoff = sh_vou_streamoff, + .vidioc_g_output = sh_vou_g_output, + .vidioc_s_output = sh_vou_s_output, + .vidioc_enum_output = sh_vou_enum_output, .vidioc_s_std = sh_vou_s_std, .vidioc_g_std = sh_vou_g_std, .vidioc_cropcap = sh_vou_cropcap, -- GitLab From 22df2e7a390f6cb31c6a5b0d8051d0ec83769ed1 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:00 -0300 Subject: [PATCH 0426/7006] [media] sh-vou: fix incorrect initial pixelformat It was set to a format that wasn't supported. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index d9a4502b4a588..262c244fcc392 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -1368,7 +1368,7 @@ static int sh_vou_probe(struct platform_device *pdev) rect->height = 480; pix->width = VOU_MAX_IMAGE_WIDTH; pix->height = 480; - pix->pixelformat = V4L2_PIX_FMT_YVYU; + pix->pixelformat = V4L2_PIX_FMT_NV16; pix->field = V4L2_FIELD_NONE; pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; -- GitLab From 61fbacc115731d2b0435f959f94ff7eb8c3c1059 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:01 -0300 Subject: [PATCH 0427/7006] [media] sh-vou: replace g/s_crop/cropcap by g/s_selection Implement g/s_selection. The v4l2 core will emulate g/s_crop and cropcap on top of g/s_selection. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 71 ++++++++++++--------------------- 1 file changed, 25 insertions(+), 46 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 262c244fcc392..9479c4429e97d 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -949,24 +949,36 @@ static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } -static int sh_vou_g_crop(struct file *file, void *fh, struct v4l2_crop *a) +static int sh_vou_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct sh_vou_device *vou_dev = video_drvdata(file); - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->c = vou_dev->rect; - + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + switch (sel->target) { + case V4L2_SEL_TGT_COMPOSE: + sel->r = vou_dev->rect; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + sel->r.left = 0; + sel->r.top = 0; + sel->r.width = VOU_MAX_IMAGE_WIDTH; + sel->r.height = VOU_MAX_IMAGE_HEIGHT; + break; + default: + return -EINVAL; + } return 0; } /* Assume a dull encoder, do all the work ourselves. */ -static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) +static int sh_vou_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { - struct v4l2_crop a_writable = *a; + struct v4l2_rect *rect = &sel->r; struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_rect *rect = &a_writable.c; struct v4l2_crop sd_crop = {.type = V4L2_BUF_TYPE_VIDEO_OUTPUT}; struct v4l2_pix_format *pix = &vou_dev->pix; struct sh_vou_geometry geo; @@ -980,10 +992,8 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) unsigned int img_height_max; int ret; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__, - rect->width, rect->height, rect->left, rect->top); - - if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || + sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; if (vou_dev->std & V4L2_STD_525_60) @@ -1047,36 +1057,6 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a) return 0; } -/* - * Total field: NTSC 858 x 2 * 262/263, PAL 864 x 2 * 312/313, default rectangle - * is the initial register values, height takes the interlaced format into - * account. The actual image can only go up to 720 x 2 * 240, So, VOUVPR can - * actually only meaningfully contain values <= 720 and <= 240 respectively, and - * not <= 864 and <= 312. - */ -static int sh_vou_cropcap(struct file *file, void *priv, - struct v4l2_cropcap *a) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - a->bounds.left = 0; - a->bounds.top = 0; - a->bounds.width = VOU_MAX_IMAGE_WIDTH; - a->bounds.height = VOU_MAX_IMAGE_HEIGHT; - /* Default = max, set VOUDPR = 0, which is not hardware default */ - a->defrect.left = 0; - a->defrect.top = 0; - a->defrect.width = VOU_MAX_IMAGE_WIDTH; - a->defrect.height = VOU_MAX_IMAGE_HEIGHT; - a->pixelaspect.numerator = 1; - a->pixelaspect.denominator = 1; - - return 0; -} - static irqreturn_t sh_vou_isr(int irq, void *dev_id) { struct sh_vou_device *vou_dev = dev_id; @@ -1305,9 +1285,8 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_enum_output = sh_vou_enum_output, .vidioc_s_std = sh_vou_s_std, .vidioc_g_std = sh_vou_g_std, - .vidioc_cropcap = sh_vou_cropcap, - .vidioc_g_crop = sh_vou_g_crop, - .vidioc_s_crop = sh_vou_s_crop, + .vidioc_g_selection = sh_vou_g_selection, + .vidioc_s_selection = sh_vou_s_selection, }; static const struct v4l2_file_operations sh_vou_fops = { -- GitLab From 66853ec4e1d096efe406383adc219285e5516af4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:03 -0300 Subject: [PATCH 0428/7006] [media] sh-vou: let sh_vou_s_fmt_vid_out call sh_vou_try_fmt_vid_out This ensures that both do the same checks, and simplifies s_fmt_vid_out a bit. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 86 +++++++++++++++------------------ 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 9479c4429e97d..079910d7062f6 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -673,34 +673,19 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std) vou_scale_v_num[idx_v], vou_scale_v_den[idx_v], best); } -static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) { struct sh_vou_device *vou_dev = video_drvdata(file); struct v4l2_pix_format *pix = &fmt->fmt.pix; unsigned int img_height_max; int pix_idx; - struct sh_vou_geometry geo; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - /* Revisit: is this the correct code? */ - .format.code = MEDIA_BUS_FMT_YUYV8_2X8, - .format.field = V4L2_FIELD_INTERLACED, - .format.colorspace = V4L2_COLORSPACE_SMPTE170M, - }; - struct v4l2_mbus_framefmt *mbfmt = &format.format; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, - vou_dev->rect.width, vou_dev->rect.height, - pix->width, pix->height); - if (pix->field == V4L2_FIELD_ANY) - pix->field = V4L2_FIELD_NONE; + dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (fmt->type != V4L2_BUF_TYPE_VIDEO_OUTPUT || - pix->field != V4L2_FIELD_NONE) - return -EINVAL; + pix->field = V4L2_FIELD_INTERLACED; + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + pix->ycbcr_enc = pix->quantization = 0; for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) if (vou_fmt[pix_idx].pfmt == pix->pixelformat) @@ -714,9 +699,37 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, else img_height_max = 576; - /* Image width must be a multiple of 4 */ v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, &pix->height, 0, img_height_max, 1, 0); + pix->bytesperline = pix->width * 2; + + return 0; +} + +static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + struct v4l2_pix_format *pix = &fmt->fmt.pix; + unsigned int img_height_max; + struct sh_vou_geometry geo; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + /* Revisit: is this the correct code? */ + .format.code = MEDIA_BUS_FMT_YUYV8_2X8, + .format.field = V4L2_FIELD_INTERLACED, + .format.colorspace = V4L2_COLORSPACE_SMPTE170M, + }; + struct v4l2_mbus_framefmt *mbfmt = &format.format; + int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); + int pix_idx; + + if (ret) + return ret; + + for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) + if (vou_fmt[pix_idx].pfmt == pix->pixelformat) + break; geo.in_width = pix->width; geo.in_height = pix->height; @@ -735,6 +748,11 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u -> %ux%u\n", __func__, geo.output.width, geo.output.height, mbfmt->width, mbfmt->height); + if (vou_dev->std & V4L2_STD_525_60) + img_height_max = 480; + else + img_height_max = 576; + /* Sanity checks */ if ((unsigned)mbfmt->width > VOU_MAX_IMAGE_WIDTH || (unsigned)mbfmt->height > img_height_max || @@ -767,30 +785,6 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; - int i; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - fmt->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - pix->field = V4L2_FIELD_NONE; - - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0); - - for (i = 0; i < ARRAY_SIZE(vou_fmt); i++) - if (vou_fmt[i].pfmt == pix->pixelformat) - return 0; - - pix->pixelformat = vou_fmt[0].pfmt; - - return 0; -} - static int sh_vou_reqbufs(struct file *file, void *priv, struct v4l2_requestbuffers *req) { -- GitLab From 5c3edcb225d6690000c2563c573984042747b28d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:04 -0300 Subject: [PATCH 0429/7006] [media] sh-vou: fix bytesperline The bytesperline values were wrong for planar formats where bytesperline is the line length for the first plane. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 079910d7062f6..6cf80835e8bab 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -133,6 +133,7 @@ struct sh_vou_fmt { u32 pfmt; char *desc; unsigned char bpp; + unsigned char bpl; unsigned char rgb; unsigned char yf; unsigned char pkf; @@ -143,6 +144,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_NV12, .bpp = 12, + .bpl = 1, .desc = "YVU420 planar", .yf = 0, .rgb = 0, @@ -150,6 +152,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_NV16, .bpp = 16, + .bpl = 1, .desc = "YVYU planar", .yf = 1, .rgb = 0, @@ -157,6 +160,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB24, .bpp = 24, + .bpl = 3, .desc = "RGB24", .pkf = 2, .rgb = 1, @@ -164,6 +168,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB565, .bpp = 16, + .bpl = 2, .desc = "RGB565", .pkf = 3, .rgb = 1, @@ -171,6 +176,7 @@ static struct sh_vou_fmt vou_fmt[] = { { .pfmt = V4L2_PIX_FMT_RGB565X, .bpp = 16, + .bpl = 2, .desc = "RGB565 byteswapped", .pkf = 3, .rgb = 1, @@ -701,7 +707,8 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, &pix->height, 0, img_height_max, 1, 0); - pix->bytesperline = pix->width * 2; + pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl; + pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3); return 0; } @@ -1343,7 +1350,7 @@ static int sh_vou_probe(struct platform_device *pdev) pix->height = 480; pix->pixelformat = V4L2_PIX_FMT_NV16; pix->field = V4L2_FIELD_NONE; - pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2; + pix->bytesperline = VOU_MAX_IMAGE_WIDTH; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; -- GitLab From 57af3ad59d953f300a1fcb143e72d024aff73550 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 7 Jun 2015 05:58:05 -0300 Subject: [PATCH 0430/7006] [media] sh-vou: convert to vb2 This converts this driver to videobuf2. As usual it is a big and hard to review patch, but this is always a big-bang change. It has been tested with my Renesas board. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 590 ++++++++++++++------------------ 1 file changed, 250 insertions(+), 340 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index 6cf80835e8bab..da8ea6a76327b 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include /* Mirror addresses are not available for all registers */ #define VOUER 0 @@ -57,8 +57,19 @@ enum sh_vou_status { SH_VOU_RUNNING, }; +#define VOU_MIN_IMAGE_WIDTH 16 #define VOU_MAX_IMAGE_WIDTH 720 -#define VOU_MAX_IMAGE_HEIGHT 576 +#define VOU_MIN_IMAGE_HEIGHT 16 + +struct sh_vou_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +static inline struct sh_vou_buffer *to_sh_vou_buffer(struct vb2_buffer *vb2) +{ + return container_of(vb2, struct sh_vou_buffer, vb); +} struct sh_vou_device { struct v4l2_device v4l2_dev; @@ -69,19 +80,17 @@ struct sh_vou_device { /* State information */ struct v4l2_pix_format pix; struct v4l2_rect rect; - struct list_head queue; + struct list_head buf_list; v4l2_std_id std; int pix_idx; - struct videobuf_buffer *active; + struct vb2_queue queue; + struct vb2_alloc_ctx *alloc_ctx; + struct sh_vou_buffer *active; enum sh_vou_status status; + unsigned sequence; struct mutex fop_lock; }; -struct sh_vou_file { - struct v4l2_fh fh; - struct videobuf_queue vbq; -}; - /* Register access routines for sides A, B and mirror addresses */ static void sh_vou_reg_a_write(struct sh_vou_device *vou_dev, unsigned int reg, u32 value) @@ -184,11 +193,11 @@ static struct sh_vou_fmt vou_fmt[] = { }; static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) + struct vb2_buffer *vb) { dma_addr_t addr1, addr2; - addr1 = videobuf_to_dma_contig(vb); + addr1 = vb2_dma_contig_plane_dma_addr(vb, 0); switch (vou_dev->pix.pixelformat) { case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: @@ -202,8 +211,7 @@ static void sh_vou_schedule_next(struct sh_vou_device *vou_dev, sh_vou_reg_m_write(vou_dev, VOUAD2R, addr2); } -static void sh_vou_stream_start(struct sh_vou_device *vou_dev, - struct videobuf_buffer *vb) +static void sh_vou_stream_config(struct sh_vou_device *vou_dev) { unsigned int row_coeff; #ifdef __LITTLE_ENDIAN @@ -230,167 +238,136 @@ static void sh_vou_stream_start(struct sh_vou_device *vou_dev, sh_vou_reg_a_write(vou_dev, VOUSWR, dataswap); sh_vou_reg_ab_write(vou_dev, VOUAIR, vou_dev->pix.width * row_coeff); - sh_vou_schedule_next(vou_dev, vb); -} - -static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb) -{ - BUG_ON(in_interrupt()); - - /* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */ - videobuf_waiton(vq, vb, 0, 0); - videobuf_dma_contig_free(vq, vb); - vb->state = VIDEOBUF_NEEDS_INIT; } /* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count, - unsigned int *size) +static int sh_vou_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], void *alloc_ctxs[]) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); - - *size = vou_fmt[vou_dev->pix_idx].bpp * vou_dev->pix.width * - vou_dev->pix.height / 8; - - if (*count < 2) - *count = 2; - - /* Taking into account maximum frame size, *count will stay >= 2 */ - if (PAGE_ALIGN(*size) * *count > 4 * 1024 * 1024) - *count = 4 * 1024 * 1024 / PAGE_ALIGN(*size); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix = &vou_dev->pix; + int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - dev_dbg(vou_dev->v4l2_dev.dev, "%s(): count=%d, size=%d\n", __func__, - *count, *size); + dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + if (fmt && fmt->fmt.pix.sizeimage < pix->height * bytes_per_line) + return -EINVAL; + *nplanes = 1; + sizes[0] = fmt ? fmt->fmt.pix.sizeimage : pix->height * bytes_per_line; + alloc_ctxs[0] = vou_dev->alloc_ctx; return 0; } -/* Locking: caller holds fop_lock mutex */ -static int sh_vou_buf_prepare(struct videobuf_queue *vq, - struct videobuf_buffer *vb, - enum v4l2_field field) +static int sh_vou_buf_prepare(struct vb2_buffer *vb) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); struct v4l2_pix_format *pix = &vou_dev->pix; - int bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; - int ret; + unsigned bytes_per_line = vou_fmt[vou_dev->pix_idx].bpp * pix->width / 8; + unsigned size = pix->height * bytes_per_line; dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - if (vb->width != pix->width || - vb->height != pix->height || - vb->field != pix->field) { - vb->width = pix->width; - vb->height = pix->height; - vb->field = field; - if (vb->state != VIDEOBUF_NEEDS_INIT) - free_buffer(vq, vb); - } - - vb->size = vb->height * bytes_per_line; - if (vb->baddr && vb->bsize < vb->size) { + if (vb2_plane_size(vb, 0) < size) { /* User buffer too small */ - dev_warn(vq->dev, "User buffer too small: [%zu] @ %lx\n", - vb->bsize, vb->baddr); + dev_warn(vou_dev->v4l2_dev.dev, "buffer too small (%lu < %u)\n", + vb2_plane_size(vb, 0), size); return -EINVAL; } - if (vb->state == VIDEOBUF_NEEDS_INIT) { - ret = videobuf_iolock(vq, vb, NULL); - if (ret < 0) { - dev_warn(vq->dev, "IOLOCK buf-type %d: %d\n", - vb->memory, ret); - return ret; - } - vb->state = VIDEOBUF_PREPARED; - } - - dev_dbg(vou_dev->v4l2_dev.dev, - "%s(): fmt #%d, %u bytes per line, phys %pad, type %d, state %d\n", - __func__, vou_dev->pix_idx, bytes_per_line, - ({ dma_addr_t addr = videobuf_to_dma_contig(vb); &addr; }), - vb->memory, vb->state); - + vb2_set_plane_payload(vb, 0, size); return 0; } /* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */ -static void sh_vou_buf_queue(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_vou_buf_queue(struct vb2_buffer *vb) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vb->vb2_queue); + struct sh_vou_buffer *shbuf = to_sh_vou_buffer(vb); + unsigned long flags; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + spin_lock_irqsave(&vou_dev->lock, flags); + list_add_tail(&shbuf->list, &vou_dev->buf_list); + spin_unlock_irqrestore(&vou_dev->lock, flags); +} - vb->state = VIDEOBUF_QUEUED; - list_add_tail(&vb->queue, &vou_dev->queue); - - if (vou_dev->status == SH_VOU_RUNNING) { - return; - } else if (!vou_dev->active) { - vou_dev->active = vb; - /* Start from side A: we use mirror addresses, so, set B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 1); - dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", - __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); - sh_vou_schedule_next(vou_dev, vb); - /* Only activate VOU after the second buffer */ - } else if (vou_dev->active->queue.next == &vb->queue) { - /* Second buffer - initialise register side B */ - sh_vou_reg_a_write(vou_dev, VOURPR, 0); - sh_vou_stream_start(vou_dev, vb); - - /* Register side switching with frame VSYNC */ - sh_vou_reg_a_write(vou_dev, VOURCR, 5); - dev_dbg(vou_dev->v4l2_dev.dev, "%s: second buffer status 0x%x\n", - __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); - - /* Enable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); - /* Two buffers on the queue - activate the hardware */ - - vou_dev->status = SH_VOU_RUNNING; - sh_vou_reg_a_write(vou_dev, VOUER, 0x107); +static int sh_vou_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct sh_vou_buffer *buf, *node; + int ret; + + vou_dev->sequence = 0; + ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, + video, s_stream, 1); + if (ret < 0 && ret != -ENOIOCTLCMD) { + list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED); + list_del(&buf->list); + } + vou_dev->active = NULL; + return ret; } + + buf = list_entry(vou_dev->buf_list.next, struct sh_vou_buffer, list); + + vou_dev->active = buf; + + /* Start from side A: we use mirror addresses, so, set B */ + sh_vou_reg_a_write(vou_dev, VOURPR, 1); + dev_dbg(vou_dev->v4l2_dev.dev, "%s: first buffer status 0x%x\n", + __func__, sh_vou_reg_a_read(vou_dev, VOUSTR)); + sh_vou_schedule_next(vou_dev, &buf->vb); + + buf = list_entry(buf->list.next, struct sh_vou_buffer, list); + + /* Second buffer - initialise register side B */ + sh_vou_reg_a_write(vou_dev, VOURPR, 0); + sh_vou_schedule_next(vou_dev, &buf->vb); + + /* Register side switching with frame VSYNC */ + sh_vou_reg_a_write(vou_dev, VOURCR, 5); + + sh_vou_stream_config(vou_dev); + /* Enable End-of-Frame (VSYNC) interrupts */ + sh_vou_reg_a_write(vou_dev, VOUIR, 0x10004); + + /* Two buffers on the queue - activate the hardware */ + vou_dev->status = SH_VOU_RUNNING; + sh_vou_reg_a_write(vou_dev, VOUER, 0x107); + return 0; } -static void sh_vou_buf_release(struct videobuf_queue *vq, - struct videobuf_buffer *vb) +static void sh_vou_stop_streaming(struct vb2_queue *vq) { - struct video_device *vdev = vq->priv_data; - struct sh_vou_device *vou_dev = video_get_drvdata(vdev); + struct sh_vou_device *vou_dev = vb2_get_drv_priv(vq); + struct sh_vou_buffer *buf, *node; unsigned long flags; - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - + v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, + video, s_stream, 0); + /* disable output */ + sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); + /* ...but the current frame will complete */ + sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); + msleep(50); spin_lock_irqsave(&vou_dev->lock, flags); - - if (vou_dev->active == vb) { - /* disable output */ - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - /* ...but the current frame will complete */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); - vou_dev->active = NULL; + list_for_each_entry_safe(buf, node, &vou_dev->buf_list, list) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + list_del(&buf->list); } - - if ((vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED)) { - vb->state = VIDEOBUF_ERROR; - list_del(&vb->queue); - } - + vou_dev->active = NULL; spin_unlock_irqrestore(&vou_dev->lock, flags); - - free_buffer(vq, vb); } -static struct videobuf_queue_ops sh_vou_video_qops = { - .buf_setup = sh_vou_buf_setup, - .buf_prepare = sh_vou_buf_prepare, - .buf_queue = sh_vou_buf_queue, - .buf_release = sh_vou_buf_release, +static struct vb2_ops sh_vou_qops = { + .queue_setup = sh_vou_queue_setup, + .buf_prepare = sh_vou_buf_prepare, + .buf_queue = sh_vou_buf_queue, + .start_streaming = sh_vou_start_streaming, + .stop_streaming = sh_vou_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, }; /* Video IOCTLs */ @@ -404,7 +381,8 @@ static int sh_vou_querycap(struct file *file, void *priv, strlcpy(cap->card, "SuperH VOU", sizeof(cap->card)); strlcpy(cap->driver, "sh-vou", sizeof(cap->driver)); strlcpy(cap->bus_info, "platform:sh-vou", sizeof(cap->bus_info)); - cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; + cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_READWRITE | + V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; } @@ -548,8 +526,10 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std) img_height_max = 576; /* Image width must be a multiple of 4 */ - v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &geo->in_height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&geo->in_width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, + &geo->in_height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); /* Select scales to come as close as possible to the output image */ for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) { @@ -705,19 +685,19 @@ static int sh_vou_try_fmt_vid_out(struct file *file, void *priv, else img_height_max = 576; - v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2, - &pix->height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&pix->width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 2, + &pix->height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); pix->bytesperline = pix->width * vou_fmt[pix_idx].bpl; pix->sizeimage = pix->height * ((pix->width * vou_fmt[pix_idx].bpp) >> 3); return 0; } -static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *fmt) +static int sh_vou_set_fmt_vid_out(struct sh_vou_device *vou_dev, + struct v4l2_pix_format *pix) { - struct sh_vou_device *vou_dev = video_drvdata(file); - struct v4l2_pix_format *pix = &fmt->fmt.pix; unsigned int img_height_max; struct sh_vou_geometry geo; struct v4l2_subdev_format format = { @@ -728,11 +708,11 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, .format.colorspace = V4L2_COLORSPACE_SMPTE170M, }; struct v4l2_mbus_framefmt *mbfmt = &format.format; - int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); int pix_idx; + int ret; - if (ret) - return ret; + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; for (pix_idx = 0; pix_idx < ARRAY_SIZE(vou_fmt); pix_idx++) if (vou_fmt[pix_idx].pfmt == pix->pixelformat) @@ -792,85 +772,15 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, return 0; } -static int sh_vou_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *req) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - if (req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - return videobuf_reqbufs(&vou_file->vbq, req); -} - -static int sh_vou_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_querybuf(&vou_file->vbq, b); -} - -static int sh_vou_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_qbuf(&vou_file->vbq, b); -} - -static int sh_vou_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - return videobuf_dqbuf(&vou_file->vbq, b, file->f_flags & O_NONBLOCK); -} - -static int sh_vou_streamon(struct file *file, void *priv, - enum v4l2_buf_type buftype) +static int sh_vou_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *fmt) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + int ret = sh_vou_try_fmt_vid_out(file, priv, fmt); - ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, - video, s_stream, 1); - if (ret < 0 && ret != -ENOIOCTLCMD) + if (ret) return ret; - - /* This calls our .buf_queue() (== sh_vou_buf_queue) */ - return videobuf_streamon(&vou_file->vbq); -} - -static int sh_vou_streamoff(struct file *file, void *priv, - enum v4l2_buf_type buftype) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = priv; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - /* - * This calls buf_release from host driver's videobuf_queue_ops for all - * remaining buffers. When the last buffer is freed, stop streaming - */ - videobuf_streamoff(&vou_file->vbq); - v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_stream, 0); - - return 0; + return sh_vou_set_fmt_vid_out(vou_dev, &fmt->fmt.pix); } static int sh_vou_enum_output(struct file *file, void *fh, @@ -919,8 +829,11 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) dev_dbg(vou_dev->v4l2_dev.dev, "%s(): 0x%llx\n", __func__, std_id); - if (std_id & ~vou_dev->vdev.tvnorms) - return -EINVAL; + if (std_id == vou_dev->std) + return 0; + + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; ret = v4l2_device_call_until_err(&vou_dev->v4l2_dev, 0, video, s_std_output, std_id); @@ -928,13 +841,25 @@ static int sh_vou_s_std(struct file *file, void *priv, v4l2_std_id std_id) if (ret < 0 && ret != -ENOIOCTLCMD) return ret; - if (std_id & V4L2_STD_525_60) + vou_dev->rect.top = vou_dev->rect.left = 0; + vou_dev->rect.width = VOU_MAX_IMAGE_WIDTH; + if (std_id & V4L2_STD_525_60) { sh_vou_reg_ab_set(vou_dev, VOUCR, sh_vou_ntsc_mode(vou_dev->pdata->bus_fmt) << 29, 7 << 29); - else + vou_dev->rect.height = 480; + } else { sh_vou_reg_ab_set(vou_dev, VOUCR, 5 << 29, 7 << 29); + vou_dev->rect.height = 576; + } + vou_dev->pix.width = vou_dev->rect.width; + vou_dev->pix.height = vou_dev->rect.height; + vou_dev->pix.bytesperline = + vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpl; + vou_dev->pix.sizeimage = vou_dev->pix.height * + ((vou_dev->pix.width * vou_fmt[vou_dev->pix_idx].bpp) >> 3); vou_dev->std = std_id; + sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); return 0; } @@ -966,7 +891,10 @@ static int sh_vou_g_selection(struct file *file, void *fh, sel->r.left = 0; sel->r.top = 0; sel->r.width = VOU_MAX_IMAGE_WIDTH; - sel->r.height = VOU_MAX_IMAGE_HEIGHT; + if (vou_dev->std & V4L2_STD_525_60) + sel->r.height = 480; + else + sel->r.height = 576; break; default: return -EINVAL; @@ -997,13 +925,18 @@ static int sh_vou_s_selection(struct file *file, void *fh, sel->target != V4L2_SEL_TGT_COMPOSE) return -EINVAL; + if (vb2_is_busy(&vou_dev->queue)) + return -EBUSY; + if (vou_dev->std & V4L2_STD_525_60) img_height_max = 480; else img_height_max = 576; - v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1, - &rect->height, 0, img_height_max, 1, 0); + v4l_bound_align_image(&rect->width, + VOU_MIN_IMAGE_WIDTH, VOU_MAX_IMAGE_WIDTH, 1, + &rect->height, + VOU_MIN_IMAGE_HEIGHT, img_height_max, 1, 0); if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH) rect->left = VOU_MAX_IMAGE_WIDTH - rect->width; @@ -1062,7 +995,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) { struct sh_vou_device *vou_dev = dev_id; static unsigned long j; - struct videobuf_buffer *vb; + struct sh_vou_buffer *vb; static int cnt; u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked; u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR); @@ -1075,7 +1008,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) } spin_lock(&vou_dev->lock); - if (!vou_dev->active || list_empty(&vou_dev->queue)) { + if (!vou_dev->active || list_empty(&vou_dev->buf_list)) { if (printk_timed_ratelimit(&j, 500)) dev_warn(vou_dev->v4l2_dev.dev, "IRQ without active buffer: %x!\n", irq_status); @@ -1097,33 +1030,30 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id) sh_vou_reg_a_write(vou_dev, VOUIR, masked); vb = vou_dev->active; - list_del(&vb->queue); - - vb->state = VIDEOBUF_DONE; - v4l2_get_timestamp(&vb->ts); - vb->field_count++; - wake_up(&vb->done); - - if (list_empty(&vou_dev->queue)) { - /* Stop VOU */ - dev_dbg(vou_dev->v4l2_dev.dev, "%s: queue empty after %d\n", - __func__, cnt); - sh_vou_reg_a_set(vou_dev, VOUER, 0, 1); - vou_dev->active = NULL; - vou_dev->status = SH_VOU_INITIALISING; - /* Disable End-of-Frame (VSYNC) interrupts */ - sh_vou_reg_a_set(vou_dev, VOUIR, 0, 0x30000); + if (list_is_singular(&vb->list)) { + /* Keep cycling while no next buffer is available */ + sh_vou_schedule_next(vou_dev, &vb->vb); spin_unlock(&vou_dev->lock); return IRQ_HANDLED; } - vou_dev->active = list_entry(vou_dev->queue.next, - struct videobuf_buffer, queue); + list_del(&vb->list); + + v4l2_get_timestamp(&vb->vb.v4l2_buf.timestamp); + vb->vb.v4l2_buf.sequence = vou_dev->sequence++; + vb->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED; + vb2_buffer_done(&vb->vb, VB2_BUF_STATE_DONE); + + vou_dev->active = list_entry(vou_dev->buf_list.next, + struct sh_vou_buffer, list); - if (vou_dev->active->queue.next != &vou_dev->queue) { - struct videobuf_buffer *new = list_entry(vou_dev->active->queue.next, - struct videobuf_buffer, queue); - sh_vou_schedule_next(vou_dev, new); + if (list_is_singular(&vou_dev->buf_list)) { + /* Keep cycling while no next buffer is available */ + sh_vou_schedule_next(vou_dev, &vou_dev->active->vb); + } else { + struct sh_vou_buffer *new = list_entry(vou_dev->active->list.next, + struct sh_vou_buffer, list); + sh_vou_schedule_next(vou_dev, &new->vb); } spin_unlock(&vou_dev->lock); @@ -1163,6 +1093,8 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev) /* Default - fixed HSYNC length, can be made configurable is required */ sh_vou_reg_ab_write(vou_dev, VOUMSR, 0x800000); + sh_vou_set_fmt_vid_out(vou_dev, &vou_dev->pix); + return 0; } @@ -1170,104 +1102,49 @@ static int sh_vou_hw_init(struct sh_vou_device *vou_dev) static int sh_vou_open(struct file *file) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = kzalloc(sizeof(struct sh_vou_file), - GFP_KERNEL); - - if (!vou_file) - return -ENOMEM; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + int err; - v4l2_fh_init(&vou_file->fh, &vou_dev->vdev); - if (mutex_lock_interruptible(&vou_dev->fop_lock)) { - kfree(vou_file); + if (mutex_lock_interruptible(&vou_dev->fop_lock)) return -ERESTARTSYS; - } - v4l2_fh_add(&vou_file->fh); - if (v4l2_fh_is_singular(&vou_file->fh)) { - int ret; + err = v4l2_fh_open(file); + if (err) + goto done_open; + if (v4l2_fh_is_singular_file(file) && + vou_dev->status == SH_VOU_INITIALISING) { /* First open */ - vou_dev->status = SH_VOU_INITIALISING; pm_runtime_get_sync(vou_dev->v4l2_dev.dev); - ret = sh_vou_hw_init(vou_dev); - if (ret < 0) { + err = sh_vou_hw_init(vou_dev); + if (err < 0) { pm_runtime_put(vou_dev->v4l2_dev.dev); + v4l2_fh_release(file); + } else { vou_dev->status = SH_VOU_IDLE; - v4l2_fh_del(&vou_file->fh); - v4l2_fh_exit(&vou_file->fh); - mutex_unlock(&vou_dev->fop_lock); - kfree(vou_file); - return ret; } } - - videobuf_queue_dma_contig_init(&vou_file->vbq, &sh_vou_video_qops, - vou_dev->v4l2_dev.dev, &vou_dev->lock, - V4L2_BUF_TYPE_VIDEO_OUTPUT, - V4L2_FIELD_NONE, - sizeof(struct videobuf_buffer), - &vou_dev->vdev, &vou_dev->fop_lock); +done_open: mutex_unlock(&vou_dev->fop_lock); - - file->private_data = vou_file; - - return 0; + return err; } static int sh_vou_release(struct file *file) { struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); + bool is_last; mutex_lock(&vou_dev->fop_lock); - if (v4l2_fh_is_singular(&vou_file->fh)) { + is_last = v4l2_fh_is_singular_file(file); + _vb2_fop_release(file, NULL); + if (is_last) { /* Last close */ - vou_dev->status = SH_VOU_IDLE; + vou_dev->status = SH_VOU_INITIALISING; sh_vou_reg_a_set(vou_dev, VOUER, 0, 0x101); pm_runtime_put(vou_dev->v4l2_dev.dev); } - v4l2_fh_del(&vou_file->fh); - v4l2_fh_exit(&vou_file->fh); mutex_unlock(&vou_dev->fop_lock); - - file->private_data = NULL; - kfree(vou_file); - return 0; } -static int sh_vou_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - int ret; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - if (mutex_lock_interruptible(&vou_dev->fop_lock)) - return -ERESTARTSYS; - ret = videobuf_mmap_mapper(&vou_file->vbq, vma); - mutex_unlock(&vou_dev->fop_lock); - return ret; -} - -static unsigned int sh_vou_poll(struct file *file, poll_table *wait) -{ - struct sh_vou_device *vou_dev = video_drvdata(file); - struct sh_vou_file *vou_file = file->private_data; - unsigned int res; - - dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__); - - mutex_lock(&vou_dev->fop_lock); - res = videobuf_poll_stream(file, &vou_file->vbq, wait); - mutex_unlock(&vou_dev->fop_lock); - return res; -} - /* sh_vou display ioctl operations */ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_querycap = sh_vou_querycap, @@ -1275,12 +1152,15 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_g_fmt_vid_out = sh_vou_g_fmt_vid_out, .vidioc_s_fmt_vid_out = sh_vou_s_fmt_vid_out, .vidioc_try_fmt_vid_out = sh_vou_try_fmt_vid_out, - .vidioc_reqbufs = sh_vou_reqbufs, - .vidioc_querybuf = sh_vou_querybuf, - .vidioc_qbuf = sh_vou_qbuf, - .vidioc_dqbuf = sh_vou_dqbuf, - .vidioc_streamon = sh_vou_streamon, - .vidioc_streamoff = sh_vou_streamoff, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, .vidioc_g_output = sh_vou_g_output, .vidioc_s_output = sh_vou_s_output, .vidioc_enum_output = sh_vou_enum_output, @@ -1295,8 +1175,9 @@ static const struct v4l2_file_operations sh_vou_fops = { .open = sh_vou_open, .release = sh_vou_release, .unlocked_ioctl = video_ioctl2, - .mmap = sh_vou_mmap, - .poll = sh_vou_poll, + .mmap = vb2_fop_mmap, + .poll = vb2_fop_poll, + .write = vb2_fop_write, }; static const struct video_device sh_vou_video_template = { @@ -1317,6 +1198,7 @@ static int sh_vou_probe(struct platform_device *pdev) struct sh_vou_device *vou_dev; struct resource *reg_res; struct v4l2_subdev *subdev; + struct vb2_queue *q; int irq, ret; reg_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1331,11 +1213,12 @@ static int sh_vou_probe(struct platform_device *pdev) if (!vou_dev) return -ENOMEM; - INIT_LIST_HEAD(&vou_dev->queue); + INIT_LIST_HEAD(&vou_dev->buf_list); spin_lock_init(&vou_dev->lock); mutex_init(&vou_dev->fop_lock); vou_dev->pdata = vou_pdata; - vou_dev->status = SH_VOU_IDLE; + vou_dev->status = SH_VOU_INITIALISING; + vou_dev->pix_idx = 1; rect = &vou_dev->rect; pix = &vou_dev->pix; @@ -1349,7 +1232,7 @@ static int sh_vou_probe(struct platform_device *pdev) pix->width = VOU_MAX_IMAGE_WIDTH; pix->height = 480; pix->pixelformat = V4L2_PIX_FMT_NV16; - pix->field = V4L2_FIELD_NONE; + pix->field = V4L2_FIELD_INTERLACED; pix->bytesperline = VOU_MAX_IMAGE_WIDTH; pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480; pix->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -1378,6 +1261,30 @@ static int sh_vou_probe(struct platform_device *pdev) video_set_drvdata(vdev, vou_dev); + /* Initialize the vb2 queue */ + q = &vou_dev->queue; + q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_WRITE; + q->drv_priv = vou_dev; + q->buf_struct_size = sizeof(struct sh_vou_buffer); + q->ops = &sh_vou_qops; + q->mem_ops = &vb2_dma_contig_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &vou_dev->fop_lock; + ret = vb2_queue_init(q); + if (ret) + goto einitctx; + + vou_dev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev); + if (IS_ERR(vou_dev->alloc_ctx)) { + dev_err(&pdev->dev, "Can't allocate buffer context"); + ret = PTR_ERR(vou_dev->alloc_ctx); + goto einitctx; + } + vdev->queue = q; + INIT_LIST_HEAD(&vou_dev->buf_list); + pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); @@ -1409,6 +1316,8 @@ ei2cnd: ereset: i2c_put_adapter(i2c_adap); ei2cgadap: + vb2_dma_contig_cleanup_ctx(vou_dev->alloc_ctx); +einitctx: pm_runtime_disable(&pdev->dev); v4l2_device_unregister(&vou_dev->v4l2_dev); return ret; @@ -1426,6 +1335,7 @@ static int sh_vou_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); video_unregister_device(&vou_dev->vdev); i2c_put_adapter(client->adapter); + vb2_dma_contig_cleanup_ctx(vou_dev->alloc_ctx); v4l2_device_unregister(&vou_dev->v4l2_dev); return 0; } -- GitLab From 0b3474f0f61b21fc7f4d2a203cbcc2599a4d3aef Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 8 Jun 2015 03:20:15 -0300 Subject: [PATCH 0431/7006] [media] sh-vou: add support for log_status Dump the VOU registers in log_status. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index da8ea6a76327b..e2b2afa0a73da 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -875,6 +875,33 @@ static int sh_vou_g_std(struct file *file, void *priv, v4l2_std_id *std) return 0; } +static int sh_vou_log_status(struct file *file, void *priv) +{ + struct sh_vou_device *vou_dev = video_drvdata(file); + + pr_info("VOUER: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUER)); + pr_info("VOUCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUCR)); + pr_info("VOUSTR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSTR)); + pr_info("VOUVCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVCR)); + pr_info("VOUISR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUISR)); + pr_info("VOUBCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUBCR)); + pr_info("VOUDPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDPR)); + pr_info("VOUDSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDSR)); + pr_info("VOUVPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUVPR)); + pr_info("VOUIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUIR)); + pr_info("VOUSRR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSRR)); + pr_info("VOUMSR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUMSR)); + pr_info("VOUHIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUHIR)); + pr_info("VOUDFR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUDFR)); + pr_info("VOUAD1R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD1R)); + pr_info("VOUAD2R: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAD2R)); + pr_info("VOUAIR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUAIR)); + pr_info("VOUSWR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOUSWR)); + pr_info("VOURCR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURCR)); + pr_info("VOURPR: 0x%08x\n", sh_vou_reg_a_read(vou_dev, VOURPR)); + return 0; +} + static int sh_vou_g_selection(struct file *file, void *fh, struct v4l2_selection *sel) { @@ -1168,6 +1195,7 @@ static const struct v4l2_ioctl_ops sh_vou_ioctl_ops = { .vidioc_g_std = sh_vou_g_std, .vidioc_g_selection = sh_vou_g_selection, .vidioc_s_selection = sh_vou_s_selection, + .vidioc_log_status = sh_vou_log_status, }; static const struct v4l2_file_operations sh_vou_fops = { -- GitLab From 4c34cc5e0f99ced4c7a11d49007bf7a90e2fae7a Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Fri, 12 Jun 2015 13:31:11 -0300 Subject: [PATCH 0432/7006] [media] media/i2c/sr030pc30: Remove compat control ops They are no longer used in old non-control-framework bridge drivers. Reported-by: Hans Verkuil Signed-off-by: Ricardo Ribalda Delgado Acked-by: Sylwester Nawrocki Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/sr030pc30.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c index b62b6ddc43565..229dc76c44a5c 100644 --- a/drivers/media/i2c/sr030pc30.c +++ b/drivers/media/i2c/sr030pc30.c @@ -636,13 +636,6 @@ static const struct v4l2_ctrl_ops sr030pc30_ctrl_ops = { static const struct v4l2_subdev_core_ops sr030pc30_core_ops = { .s_power = sr030pc30_s_power, - .g_ext_ctrls = v4l2_subdev_g_ext_ctrls, - .try_ext_ctrls = v4l2_subdev_try_ext_ctrls, - .s_ext_ctrls = v4l2_subdev_s_ext_ctrls, - .g_ctrl = v4l2_subdev_g_ctrl, - .s_ctrl = v4l2_subdev_s_ctrl, - .queryctrl = v4l2_subdev_queryctrl, - .querymenu = v4l2_subdev_querymenu, }; static const struct v4l2_subdev_pad_ops sr030pc30_pad_ops = { -- GitLab From c046707ff99912878ba63db5f2f2e2916ca961ce Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:41 -0300 Subject: [PATCH 0433/7006] [media] DocBook/media: fix bad spacing in VIDIOC_EXPBUF The VIDIOC_EXPBUF documentation had spurious spaces that made it irritating to read. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../DocBook/media/v4l/vidioc-expbuf.xml | 38 +++++++++---------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml index a78c9207422f7..0ae0b6a915d0d 100644 --- a/Documentation/DocBook/media/v4l/vidioc-expbuf.xml +++ b/Documentation/DocBook/media/v4l/vidioc-expbuf.xml @@ -62,28 +62,28 @@ buffer as a DMABUF file at any time after buffers have been allocated with the &VIDIOC-REQBUFS; ioctl. To export a buffer, applications fill &v4l2-exportbuffer;. The - type field is set to the same buffer type as was -previously used with &v4l2-requestbuffers; type . -Applications must also set the index field. Valid +type field is set to the same buffer type as was +previously used with &v4l2-requestbuffers; type. +Applications must also set the index field. Valid index numbers range from zero to the number of buffers allocated with -&VIDIOC-REQBUFS; (&v4l2-requestbuffers; count ) -minus one. For the multi-planar API, applications set the plane - field to the index of the plane to be exported. Valid planes +&VIDIOC-REQBUFS; (&v4l2-requestbuffers; count) +minus one. For the multi-planar API, applications set the plane +field to the index of the plane to be exported. Valid planes range from zero to the maximal number of valid planes for the currently active -format. For the single-planar API, applications must set plane - to zero. Additional flags may be posted in the -flags field. Refer to a manual for open() for details. +format. For the single-planar API, applications must set plane +to zero. Additional flags may be posted in the flags +field. Refer to a manual for open() for details. Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, and O_RDWR are supported. All other fields must be set to zero. In the case of multi-planar API, every plane is exported separately using -multiple VIDIOC_EXPBUF calls. +multiple VIDIOC_EXPBUF calls. - After calling VIDIOC_EXPBUF the fd - field will be set by a driver. This is a DMABUF file +After calling VIDIOC_EXPBUF the fd +field will be set by a driver. This is a DMABUF file descriptor. The application may pass it to other DMABUF-aware devices. Refer to DMABUF importing for details about importing DMABUF files into V4L2 nodes. It is recommended to close a DMABUF file when it -is no longer used to allow the associated memory to be reclaimed. +is no longer used to allow the associated memory to be reclaimed. @@ -170,9 +170,9 @@ multi-planar API. Otherwise this value must be set to zero. __u32 flags - Flags for the newly created file, currently only -O_CLOEXEC , O_RDONLY, O_WRONLY -, and O_RDWR are supported, refer to the manual + Flags for the newly created file, currently only +O_CLOEXEC, O_RDONLY, O_WRONLY, +and O_RDWR are supported, refer to the manual of open() for more details. @@ -200,9 +200,9 @@ set the array to zero. EINVAL A queue is not in MMAP mode or DMABUF exporting is not -supported or flags or type - or index or plane - fields are invalid. +supported or flags or type +or index or plane fields +are invalid. -- GitLab From 250121d348645675f5ade7e7ebe3fc6b46a9a2c0 Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Wed, 3 Jun 2015 10:59:50 -0300 Subject: [PATCH 0434/7006] [media] media: adv7180: add of match table Add a proper of match id for use when the device is being bound via device tree, to avoid having to use the i2c old-style binding of the device. Signed-off-by: Ben Dooks Signed-off-by: William.Towle Reviewed-by: Rob Taylor Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7180.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c index a493c0b0b5fef..09a96df170d16 100644 --- a/drivers/media/i2c/adv7180.c +++ b/drivers/media/i2c/adv7180.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1324,11 +1325,21 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume); #define ADV7180_PM_OPS NULL #endif +#ifdef CONFIG_OF +static const struct of_device_id adv7180_of_id[] = { + { .compatible = "adi,adv7180", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, adv7180_of_id); +#endif + static struct i2c_driver adv7180_driver = { .driver = { .owner = THIS_MODULE, .name = KBUILD_MODNAME, .pm = ADV7180_PM_OPS, + .of_match_table = of_match_ptr(adv7180_of_id), }, .probe = adv7180_probe, .remove = adv7180_remove, -- GitLab From f862f57dae5f0555552256b67f5bfd523f97a736 Mon Sep 17 00:00:00 2001 From: Pablo Anton Date: Fri, 19 Jun 2015 10:23:06 -0300 Subject: [PATCH 0435/7006] [media] media: i2c: ADV7604: Migrate to regmap This is a preliminary patch in order to add support for ALSA. It replaces all current i2c access with regmap. Signed-off-by: Pablo Anton Signed-off-by: Jean-Michel Hautbois Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 351 ++++++++++++++++++++++++++---------- 1 file changed, 256 insertions(+), 95 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 60630d62e6638..8e39bf60cb169 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -188,6 +189,9 @@ struct adv76xx_state { /* i2c clients */ struct i2c_client *i2c_clients[ADV76XX_PAGE_MAX]; + /* Regmaps */ + struct regmap *regmap[ADV76XX_PAGE_MAX]; + /* controls */ struct v4l2_ctrl *detect_tx_5v_ctrl; struct v4l2_ctrl *analog_sampling_phase_ctrl; @@ -373,66 +377,39 @@ static inline unsigned vtotal(const struct v4l2_bt_timings *t) /* ----------------------------------------------------------------------- */ -static s32 adv_smbus_read_byte_data_check(struct i2c_client *client, - u8 command, bool check) -{ - union i2c_smbus_data data; - - if (!i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_READ, command, - I2C_SMBUS_BYTE_DATA, &data)) - return data.byte; - if (check) - v4l_err(client, "error reading %02x, %02x\n", - client->addr, command); - return -EIO; -} - -static s32 adv_smbus_read_byte_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command) +static int adv76xx_read_check(struct adv76xx_state *state, + int client_page, u8 reg) { - return adv_smbus_read_byte_data_check(state->i2c_clients[page], - command, true); -} - -static s32 adv_smbus_write_byte_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command, - u8 value) -{ - struct i2c_client *client = state->i2c_clients[page]; - union i2c_smbus_data data; + struct i2c_client *client = state->i2c_clients[client_page]; int err; - int i; + unsigned int val; - data.byte = value; - for (i = 0; i < 3; i++) { - err = i2c_smbus_xfer(client->adapter, client->addr, - client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_BYTE_DATA, &data); - if (!err) - break; + err = regmap_read(state->regmap[client_page], reg, &val); + + if (err) { + v4l_err(client, "error reading %02x, %02x\n", + client->addr, reg); + return err; } - if (err < 0) - v4l_err(client, "error writing %02x, %02x, %02x\n", - client->addr, command, value); - return err; + return val; } -static s32 adv_smbus_write_i2c_block_data(struct adv76xx_state *state, - enum adv76xx_page page, u8 command, - unsigned length, const u8 *values) +/* adv76xx_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX + * size to one or more registers. + * + * A value of zero will be returned on success, a negative errno will + * be returned in error cases. + */ +static int adv76xx_write_block(struct adv76xx_state *state, int client_page, + unsigned int init_reg, const void *val, + size_t val_len) { - struct i2c_client *client = state->i2c_clients[page]; - union i2c_smbus_data data; + struct regmap *regmap = state->regmap[client_page]; + + if (val_len > I2C_SMBUS_BLOCK_MAX) + val_len = I2C_SMBUS_BLOCK_MAX; - if (length > I2C_SMBUS_BLOCK_MAX) - length = I2C_SMBUS_BLOCK_MAX; - data.block[0] = length; - memcpy(data.block + 1, values, length); - return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, command, - I2C_SMBUS_I2C_BLOCK_DATA, &data); + return regmap_raw_write(regmap, init_reg, val, val_len); } /* ----------------------------------------------------------------------- */ @@ -441,14 +418,14 @@ static inline int io_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_IO, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_IO, reg); } static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_IO], reg, val); } static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -460,71 +437,70 @@ static inline int avlink_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_AVLINK, reg); + return adv76xx_read_check(state, ADV7604_PAGE_AVLINK, reg); } static inline int avlink_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_AVLINK, reg, val); + return regmap_write(state->regmap[ADV7604_PAGE_AVLINK], reg, val); } static inline int cec_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CEC, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_CEC, reg); } static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_CEC], reg, val); } static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_INFOFRAME, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_INFOFRAME, reg); } static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_INFOFRAME, - reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_INFOFRAME], reg, val); } static inline int afe_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_AFE, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_AFE, reg); } static inline int afe_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_AFE, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_AFE], reg, val); } static inline int rep_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_REP, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_REP, reg); } static inline int rep_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_REP, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_REP], reg, val); } static inline int rep_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -536,28 +512,37 @@ static inline int edid_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_EDID, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_EDID, reg); } static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_EDID, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_EDID], reg, val); } static inline int edid_write_block(struct v4l2_subdev *sd, - unsigned len, const u8 *val) + unsigned int total_len, const u8 *val) { struct adv76xx_state *state = to_state(sd); int err = 0; - int i; + int i = 0; + int len = 0; - v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len); + v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", + __func__, total_len); + + while (!err && i < total_len) { + len = (total_len - i) > I2C_SMBUS_BLOCK_MAX ? + I2C_SMBUS_BLOCK_MAX : + (total_len - i); + + err = adv76xx_write_block(state, ADV76XX_PAGE_EDID, + i, val + i, len); + i += len; + } - for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX) - err = adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_EDID, - i, I2C_SMBUS_BLOCK_MAX, val + i); return err; } @@ -587,7 +572,7 @@ static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_HDMI, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_HDMI, reg); } static u16 hdmi_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -599,7 +584,7 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_HDMI, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_HDMI], reg, val); } static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -611,14 +596,14 @@ static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_TEST, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_TEST], reg, val); } static inline int cp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV76XX_PAGE_CP, reg); + return adv76xx_read_check(state, ADV76XX_PAGE_CP, reg); } static u16 cp_read16(struct v4l2_subdev *sd, u8 reg, u16 mask) @@ -630,7 +615,7 @@ static inline int cp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CP, reg, val); + return regmap_write(state->regmap[ADV76XX_PAGE_CP], reg, val); } static inline int cp_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val) @@ -642,14 +627,14 @@ static inline int vdp_read(struct v4l2_subdev *sd, u8 reg) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_read_byte_data(state, ADV7604_PAGE_VDP, reg); + return adv76xx_read_check(state, ADV7604_PAGE_VDP, reg); } static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val) { struct adv76xx_state *state = to_state(sd); - return adv_smbus_write_byte_data(state, ADV7604_PAGE_VDP, reg, val); + return regmap_write(state->regmap[ADV7604_PAGE_VDP], reg, val); } #define ADV76XX_REG(page, offset) (((page) << 8) | (offset)) @@ -660,13 +645,16 @@ static int adv76xx_read_reg(struct v4l2_subdev *sd, unsigned int reg) { struct adv76xx_state *state = to_state(sd); unsigned int page = reg >> 8; + unsigned int val; + int err; if (!(BIT(page) & state->info->page_mask)) return -EINVAL; reg &= 0xff; + err = regmap_read(state->regmap[page], reg, &val); - return adv_smbus_read_byte_data(state, page, reg); + return err ? err : val; } #endif @@ -680,7 +668,7 @@ static int adv76xx_write_reg(struct v4l2_subdev *sd, unsigned int reg, u8 val) reg &= 0xff; - return adv_smbus_write_byte_data(state, page, reg, val); + return regmap_write(state->regmap[page], reg, val); } static void adv76xx_write_reg_seq(struct v4l2_subdev *sd, @@ -976,8 +964,8 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd, /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */ /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */ /* IO-map reg. 0x16 and 0x17 should be written in sequence */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_IO, - 0x16, 2, pll)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_IO], + 0x16, pll, 2)) v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n"); /* active video - horizontal timing */ @@ -1028,8 +1016,8 @@ static void adv76xx_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 off offset_buf[3] = offset_c & 0x0ff; /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, - 0x77, 4, offset_buf)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP], + 0x77, offset_buf, 4)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__); } @@ -1058,8 +1046,8 @@ static void adv76xx_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, gain_buf[3] = ((gain_c & 0x0ff)); /* Registers must be written in this order with no i2c access in between */ - if (adv_smbus_write_i2c_block_data(state, ADV76XX_PAGE_CP, - 0x73, 4, gain_buf)) + if (regmap_raw_write(state->regmap[ADV76XX_PAGE_CP], + 0x73, gain_buf, 4)) v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__); } @@ -2762,6 +2750,148 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return 0; } +static const struct regmap_config adv76xx_regmap_cnf[] = { + { + .name = "io", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "avlink", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cec", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "infoframe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "esdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "epp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "afe", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "rep", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "edid", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + + { + .name = "hdmi", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "test", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "cp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, + { + .name = "vdp", + .reg_bits = 8, + .val_bits = 8, + + .max_register = 0xff, + .cache_type = REGCACHE_NONE, + }, +}; + +static int configure_regmap(struct adv76xx_state *state, int region) +{ + int err; + + if (!state->i2c_clients[region]) + return -ENODEV; + + state->regmap[region] = + devm_regmap_init_i2c(state->i2c_clients[region], + &adv76xx_regmap_cnf[region]); + + if (IS_ERR(state->regmap[region])) { + err = PTR_ERR(state->regmap[region]); + v4l_err(state->i2c_clients[region], + "Error initializing regmap %d with error %d\n", + region, err); + return -EINVAL; + } + + return 0; +} + +static int configure_regmaps(struct adv76xx_state *state) +{ + int i, err; + + for (i = ADV7604_PAGE_AVLINK ; i < ADV76XX_PAGE_MAX; i++) { + err = configure_regmap(state, i); + if (err && (err != -ENODEV)) + return err; + } + return 0; +} + static int adv76xx_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -2771,7 +2901,7 @@ static int adv76xx_probe(struct i2c_client *client, struct v4l2_ctrl_handler *hdl; struct v4l2_subdev *sd; unsigned int i; - u16 val; + unsigned int val, val2; int err; /* Check if the adapter supports the needed features */ @@ -2835,23 +2965,49 @@ static int adv76xx_probe(struct i2c_client *client, client->addr); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + /* Configure IO Regmap region */ + err = configure_regmap(state, ADV76XX_PAGE_IO); + + if (err) { + v4l2_err(sd, "Error configuring IO regmap region\n"); + return -ENODEV; + } + /* * Verify that the chip is present. On ADV7604 the RD_INFO register only * identifies the revision, while on ADV7611 it identifies the model as * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. */ if (state->info->type == ADV7604) { - val = adv_smbus_read_byte_data_check(client, 0xfb, false); + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xfb, &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } if (val != 0x68) { - v4l2_info(sd, "not an adv7604 on address 0x%x\n", + v4l2_err(sd, "not an adv7604 on address 0x%x\n", client->addr << 1); return -ENODEV; } } else { - val = (adv_smbus_read_byte_data_check(client, 0xea, false) << 8) - | (adv_smbus_read_byte_data_check(client, 0xeb, false) << 0); - if (val != 0x2051) { - v4l2_info(sd, "not an adv7611 on address 0x%x\n", + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], + 0xea, + &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } + val2 = val << 8; + err = regmap_read(state->regmap[ADV76XX_PAGE_IO], + 0xeb, + &val); + if (err) { + v4l2_err(sd, "Error %d reading IO Regmap\n", err); + return -ENODEV; + } + val2 |= val; + if (val2 != 0x2051) { + v4l2_err(sd, "not an adv7611 on address 0x%x\n", client->addr << 1); return -ENODEV; } @@ -2941,6 +3097,11 @@ static int adv76xx_probe(struct i2c_client *client, if (err) goto err_work_queues; + /* Configure regmaps */ + err = configure_regmaps(state); + if (err) + goto err_entity; + err = adv76xx_core_init(sd); if (err) goto err_entity; -- GitLab From 8331d30bf0ccf179c3d03d968c9ae1c8f06eafc4 Mon Sep 17 00:00:00 2001 From: William Towle Date: Wed, 3 Jun 2015 10:59:51 -0300 Subject: [PATCH 0436/7006] [media] media: adv7604: chip info and formats for ADV7612 Add support for the ADV7612 chip as implemented on Renesas' Lager board to adv7604.c, including lists for formats/colourspace/timing selection and an IRQ handler. Signed-off-by: William Towle Signed-off-by: Hans Verkuil [hans.verkuil@cisco.com: fix merge conflicts due to regmap patch] Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 91 +++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 8e39bf60cb169..c8fefeab0513a 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -82,6 +82,7 @@ MODULE_LICENSE("GPL"); enum adv76xx_type { ADV7604, ADV7611, + ADV7612, }; struct adv76xx_reg_seq { @@ -754,6 +755,23 @@ static const struct adv76xx_format_info adv7611_formats[] = { ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_12BIT }, }; +static const struct adv76xx_format_info adv7612_formats[] = { + { MEDIA_BUS_FMT_RGB888_1X24, ADV76XX_OP_CH_SEL_RGB, true, false, + ADV76XX_OP_MODE_SEL_SDR_444 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_2X8, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_2X8, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422 | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_UYVY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_VYUY8_1X16, ADV76XX_OP_CH_SEL_RBG, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YUYV8_1X16, ADV76XX_OP_CH_SEL_RGB, false, false, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, + { MEDIA_BUS_FMT_YVYU8_1X16, ADV76XX_OP_CH_SEL_RGB, false, true, + ADV76XX_OP_MODE_SEL_SDR_422_2X | ADV76XX_OP_FORMAT_SEL_8BIT }, +}; + static const struct adv76xx_format_info * adv76xx_format_info(struct adv76xx_state *state, u32 code) { @@ -2498,6 +2516,11 @@ static void adv7611_setup_irqs(struct v4l2_subdev *sd) io_write(sd, 0x41, 0xd0); /* STDI irq for any change, disable INT2 */ } +static void adv7612_setup_irqs(struct v4l2_subdev *sd) +{ + io_write(sd, 0x41, 0xd0); /* disable INT2 */ +} + static void adv76xx_unregister_clients(struct adv76xx_state *state) { unsigned int i; @@ -2585,6 +2608,19 @@ static const struct adv76xx_reg_seq adv7611_recommended_settings_hdmi[] = { { ADV76XX_REG_SEQ_TERM, 0 }, }; +static const struct adv76xx_reg_seq adv7612_recommended_settings_hdmi[] = { + { ADV76XX_REG(ADV76XX_PAGE_CP, 0x6c), 0x00 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x9b), 0x03 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x6f), 0x08 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x85), 0x1f }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x87), 0x70 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x57), 0xda }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x58), 0x01 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x03), 0x98 }, + { ADV76XX_REG(ADV76XX_PAGE_HDMI, 0x4c), 0x44 }, + { ADV76XX_REG_SEQ_TERM, 0 }, +}; + static const struct adv76xx_chip_info adv76xx_chip_info[] = { [ADV7604] = { .type = ADV7604, @@ -2673,17 +2709,59 @@ static const struct adv76xx_chip_info adv76xx_chip_info[] = { .field1_vsync_mask = 0x3fff, .field1_vbackporch_mask = 0x3fff, }, + [ADV7612] = { + .type = ADV7612, + .has_afe = false, + .max_port = ADV7604_PAD_HDMI_PORT_B, + .num_dv_ports = 2, + .edid_enable_reg = 0x74, + .edid_status_reg = 0x76, + .lcf_reg = 0xa3, + .tdms_lock_mask = 0x43, + .cable_det_mask = 0x01, + .fmt_change_digital_mask = 0x03, + .formats = adv7612_formats, + .nformats = ARRAY_SIZE(adv7612_formats), + .set_termination = adv7611_set_termination, + .setup_irqs = adv7612_setup_irqs, + .read_hdmi_pixelclock = adv7611_read_hdmi_pixelclock, + .read_cable_det = adv7611_read_cable_det, + .recommended_settings = { + [1] = adv7612_recommended_settings_hdmi, + }, + .num_recommended_settings = { + [1] = ARRAY_SIZE(adv7612_recommended_settings_hdmi), + }, + .page_mask = BIT(ADV76XX_PAGE_IO) | BIT(ADV76XX_PAGE_CEC) | + BIT(ADV76XX_PAGE_INFOFRAME) | BIT(ADV76XX_PAGE_AFE) | + BIT(ADV76XX_PAGE_REP) | BIT(ADV76XX_PAGE_EDID) | + BIT(ADV76XX_PAGE_HDMI) | BIT(ADV76XX_PAGE_CP), + .linewidth_mask = 0x1fff, + .field0_height_mask = 0x1fff, + .field1_height_mask = 0x1fff, + .hfrontporch_mask = 0x1fff, + .hsync_mask = 0x1fff, + .hbackporch_mask = 0x1fff, + .field0_vfrontporch_mask = 0x3fff, + .field0_vsync_mask = 0x3fff, + .field0_vbackporch_mask = 0x3fff, + .field1_vfrontporch_mask = 0x3fff, + .field1_vsync_mask = 0x3fff, + .field1_vbackporch_mask = 0x3fff, + }, }; static const struct i2c_device_id adv76xx_i2c_id[] = { { "adv7604", (kernel_ulong_t)&adv76xx_chip_info[ADV7604] }, { "adv7611", (kernel_ulong_t)&adv76xx_chip_info[ADV7611] }, + { "adv7612", (kernel_ulong_t)&adv76xx_chip_info[ADV7612] }, { } }; MODULE_DEVICE_TABLE(i2c, adv76xx_i2c_id); static const struct of_device_id adv76xx_of_id[] __maybe_unused = { { .compatible = "adi,adv7611", .data = &adv76xx_chip_info[ADV7611] }, + { .compatible = "adi,adv7612", .data = &adv76xx_chip_info[ADV7612] }, { } }; MODULE_DEVICE_TABLE(of, adv76xx_of_id); @@ -2978,7 +3056,8 @@ static int adv76xx_probe(struct i2c_client *client, * identifies the revision, while on ADV7611 it identifies the model as * well. Use the HDMI slave address on ADV7604 and RD_INFO on ADV7611. */ - if (state->info->type == ADV7604) { + switch (state->info->type) { + case ADV7604: err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xfb, &val); if (err) { v4l2_err(sd, "Error %d reading IO Regmap\n", err); @@ -2989,7 +3068,9 @@ static int adv76xx_probe(struct i2c_client *client, client->addr << 1); return -ENODEV; } - } else { + break; + case ADV7611: + case ADV7612: err = regmap_read(state->regmap[ADV76XX_PAGE_IO], 0xea, &val); @@ -3006,11 +3087,13 @@ static int adv76xx_probe(struct i2c_client *client, return -ENODEV; } val2 |= val; - if (val2 != 0x2051) { - v4l2_err(sd, "not an adv7611 on address 0x%x\n", + if ((state->info->type == ADV7611 && val != 0x2051) || + (state->info->type == ADV7612 && val != 0x2041)) { + v4l2_err(sd, "not an adv761x on address 0x%x\n", client->addr << 1); return -ENODEV; } + break; } /* control handlers */ -- GitLab From 6a219f15a86812a226d197aa93b2806e9cecda7c Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Wed, 3 Jun 2015 10:59:52 -0300 Subject: [PATCH 0437/7006] [media] media: adv7604: document support for ADV7612 dual HDMI input decoder This documentation accompanies the patch adding support for the ADV7612 dual HDMI decoder / repeater chip. Signed-off-by: Ian Molton Reviewed-by: William Towle Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/i2c/adv7604.txt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt index c27cede3bd68a..7eafdbc055f96 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -1,15 +1,17 @@ -* Analog Devices ADV7604/11 video decoder with HDMI receiver +* Analog Devices ADV7604/11/12 video decoder with HDMI receiver -The ADV7604 and ADV7611 are multiformat video decoders with an integrated HDMI -receiver. The ADV7604 has four multiplexed HDMI inputs and one analog input, -and the ADV7611 has one HDMI input and no analog input. +The ADV7604 and ADV7611/12 are multiformat video decoders with an integrated +HDMI receiver. The ADV7604 has four multiplexed HDMI inputs and one analog +input, and the ADV7611 has one HDMI input and no analog input. The 7612 is +similar to the 7611 but has 2 HDMI inputs. -These device tree bindings support the ADV7611 only at the moment. +These device tree bindings support the ADV7611/12 only at the moment. Required Properties: - compatible: Must contain one of the following - "adi,adv7611" for the ADV7611 + - "adi,adv7612" for the ADV7612 - reg: I2C slave address @@ -22,10 +24,10 @@ port, in accordance with the video interface bindings defined in Documentation/devicetree/bindings/media/video-interfaces.txt. The port nodes are numbered as follows. - Port ADV7611 + Port ADV7611 ADV7612 ------------------------------------------------------------ - HDMI 0 - Digital output 1 + HDMI 0 0, 1 + Digital output 1 2 The digital output port node must contain at least one endpoint. -- GitLab From bf9c82278c348eb6b72496de6a3e5269aadb6b34 Mon Sep 17 00:00:00 2001 From: Ian Molton Date: Wed, 3 Jun 2015 10:59:53 -0300 Subject: [PATCH 0438/7006] [media] media: adv7604: ability to read default input port from DT Adds support to the adv7604 driver for specifying the default input port in the Device tree. If no value is provided, the driver will be unable to select an input without help from userspace. Tested-by: William Towle Signed-off-by: Ian Molton Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/i2c/adv7604.txt | 3 +++ drivers/media/i2c/adv7604.c | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/media/i2c/adv7604.txt b/Documentation/devicetree/bindings/media/i2c/adv7604.txt index 7eafdbc055f96..8337f75c75da6 100644 --- a/Documentation/devicetree/bindings/media/i2c/adv7604.txt +++ b/Documentation/devicetree/bindings/media/i2c/adv7604.txt @@ -47,6 +47,7 @@ Optional Endpoint Properties: If none of hsync-active, vsync-active and pclk-sample is specified the endpoint will use embedded BT.656 synchronization. + - default-input: Select which input is selected after reset. Example: @@ -60,6 +61,8 @@ Example: #address-cells = <1>; #size-cells = <0>; + default-input = <0>; + port@0 { reg = <0>; }; diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index c8fefeab0513a..21b549a8dc744 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2772,6 +2772,7 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) struct device_node *endpoint; struct device_node *np; unsigned int flags; + u32 v; np = state->i2c_clients[ADV76XX_PAGE_IO]->dev.of_node; @@ -2781,6 +2782,12 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return -EINVAL; v4l2_of_parse_endpoint(endpoint, &bus_cfg); + + if (!of_property_read_u32(endpoint, "default-input", &v)) + state->pdata.default_input = v; + else + state->pdata.default_input = -1; + of_node_put(endpoint); flags = bus_cfg.bus.parallel.flags; @@ -2819,7 +2826,6 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) /* Hardcode the remaining platform data fields. */ state->pdata.disable_pwrdnb = 0; state->pdata.disable_cable_det_rst = 0; - state->pdata.default_input = -1; state->pdata.blank_data = 1; state->pdata.alt_data_sat = 1; state->pdata.op_format_mode_sel = ADV7604_OP_FORMAT_MODE0; -- GitLab From 2a1e91a1595f4dec14ab16d63c6348d8fa159911 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 3 Jul 2015 09:12:54 -0300 Subject: [PATCH 0439/7006] [media] sh_vou: declare static functions as such drivers/media/platform/sh_vou.c:799:5: warning: no previous prototype for 'sh_vou_g_output' [-Wmissing-prototypes] int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) ^ drivers/media/platform/sh_vou.c:805:5: warning: no previous prototype for 'sh_vou_s_output' [-Wmissing-prototypes] int sh_vou_s_output(struct file *file, void *fh, unsigned int i) ^ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_vou.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c index e2b2afa0a73da..fe5c8ab06bd5c 100644 --- a/drivers/media/platform/sh_vou.c +++ b/drivers/media/platform/sh_vou.c @@ -796,13 +796,13 @@ static int sh_vou_enum_output(struct file *file, void *fh, return 0; } -int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) +static int sh_vou_g_output(struct file *file, void *fh, unsigned int *i) { *i = 0; return 0; } -int sh_vou_s_output(struct file *file, void *fh, unsigned int i) +static int sh_vou_s_output(struct file *file, void *fh, unsigned int i) { return i ? -EINVAL : 0; } -- GitLab From a66b0c41ad277ae62a3ae6ac430a71882f899557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Tue, 19 May 2015 19:03:12 -0300 Subject: [PATCH 0440/7006] [media] rc-core: fix remove uevent generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The input_dev is already gone when the rc device is being unregistered so checking for its presence only means that no remove uevent will be generated. Cc: stable@kernel.org Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 9d015db652808..84d142bdb7a2c 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1193,9 +1193,6 @@ static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env) { struct rc_dev *dev = to_rc_dev(device); - if (!dev || !dev->input_dev) - return -ENODEV; - if (dev->rc_map.name) ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name); if (dev->driver_name) -- GitLab From fcb13097867757d360d5226d36ed3ffe849dc3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Tue, 19 May 2015 19:03:17 -0300 Subject: [PATCH 0441/7006] [media] rc-core: use an IDA rather than a bitmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch changes rc-core to use the kernel facilities that are already available for handling unique numbers instead of rolling its own bitmap stuff. Signed-off-by: David Härdeman Tested-by: Stefan Lippers-Hollmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-ir-raw.c | 2 +- drivers/media/rc/rc-main.c | 40 ++++++++++++++++++------------------ include/media/rc-core.h | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index b9e4645c731c0..1068f2ba56c62 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -406,7 +406,7 @@ int ir_raw_event_register(struct rc_dev *dev) spin_lock_init(&dev->raw->lock); dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw, - "rc%ld", dev->devno); + "rc%u", dev->minor); if (IS_ERR(dev->raw->thread)) { rc = PTR_ERR(dev->raw->thread); diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 84d142bdb7a2c..20914edd5a102 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -18,17 +18,15 @@ #include #include #include +#include #include #include #include "rc-core-priv.h" -/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */ -#define IRRCV_NUM_DEVICES 256 -static DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES); - /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */ #define IR_TAB_MIN_SIZE 256 #define IR_TAB_MAX_SIZE 8192 +#define RC_DEV_MAX 256 /* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */ #define IR_KEYPRESS_TIMEOUT 250 @@ -38,6 +36,9 @@ static LIST_HEAD(rc_map_list); static DEFINE_SPINLOCK(rc_map_lock); static struct led_trigger *led_feedback; +/* Used to keep track of rc devices */ +static DEFINE_IDA(rc_ida); + static struct rc_map_list *seek_rc_map(const char *name) { struct rc_map_list *map = NULL; @@ -1311,7 +1312,9 @@ int rc_register_device(struct rc_dev *dev) static bool raw_init = false; /* raw decoders loaded? */ struct rc_map *rc_map; const char *path; - int rc, devno, attr = 0; + int attr = 0; + int minor; + int rc; if (!dev || !dev->map_name) return -EINVAL; @@ -1331,13 +1334,13 @@ int rc_register_device(struct rc_dev *dev) if (dev->close) dev->input_dev->close = ir_close; - do { - devno = find_first_zero_bit(ir_core_dev_number, - IRRCV_NUM_DEVICES); - /* No free device slots */ - if (devno >= IRRCV_NUM_DEVICES) - return -ENOMEM; - } while (test_and_set_bit(devno, ir_core_dev_number)); + minor = ida_simple_get(&rc_ida, 0, RC_DEV_MAX, GFP_KERNEL); + if (minor < 0) + return minor; + + dev->minor = minor; + dev_set_name(&dev->dev, "rc%u", dev->minor); + dev_set_drvdata(&dev->dev, dev); dev->dev.groups = dev->sysfs_groups; dev->sysfs_groups[attr++] = &rc_dev_protocol_attr_grp; @@ -1357,9 +1360,6 @@ int rc_register_device(struct rc_dev *dev) */ mutex_lock(&dev->lock); - dev->devno = devno; - dev_set_name(&dev->dev, "rc%ld", dev->devno); - dev_set_drvdata(&dev->dev, dev); rc = device_add(&dev->dev); if (rc) goto out_unlock; @@ -1435,8 +1435,8 @@ int rc_register_device(struct rc_dev *dev) mutex_unlock(&dev->lock); - IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n", - dev->devno, + IR_dprintk(1, "Registered rc%u (driver: %s, remote: %s, mode %s)\n", + dev->minor, dev->driver_name ? dev->driver_name : "unknown", rc_map->name ? rc_map->name : "unknown", dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked"); @@ -1455,7 +1455,7 @@ out_dev: device_del(&dev->dev); out_unlock: mutex_unlock(&dev->lock); - clear_bit(dev->devno, ir_core_dev_number); + ida_simple_remove(&rc_ida, minor); return rc; } EXPORT_SYMBOL_GPL(rc_register_device); @@ -1467,8 +1467,6 @@ void rc_unregister_device(struct rc_dev *dev) del_timer_sync(&dev->timer_keyup); - clear_bit(dev->devno, ir_core_dev_number); - if (dev->driver_type == RC_DRIVER_IR_RAW) ir_raw_event_unregister(dev); @@ -1481,6 +1479,8 @@ void rc_unregister_device(struct rc_dev *dev) device_del(&dev->dev); + ida_simple_remove(&rc_ida, dev->minor); + rc_free_device(dev); } diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 45534da57759a..5642fbea886ec 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -69,7 +69,7 @@ enum rc_filter_type { * @rc_map: current scan/key table * @lock: used to ensure we've filled in all protocol details before * anyone can call show_protocols or store_protocols - * @devno: unique remote control device number + * @minor: unique minor remote control device number * @raw: additional data for raw pulse/space devices * @input_dev: the input child device used to communicate events to userspace * @driver_type: specifies if protocol decoding is done in hardware or software @@ -131,7 +131,7 @@ struct rc_dev { const char *map_name; struct rc_map rc_map; struct mutex lock; - unsigned long devno; + unsigned int minor; struct ir_raw_event_ctrl *raw; struct input_dev *input_dev; enum rc_driver_type driver_type; -- GitLab From 275ddb40bcf686d210d86c6718e42425a6a0bc76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Tue, 19 May 2015 19:03:22 -0300 Subject: [PATCH 0442/7006] [media] rc-core: remove the LIRC "protocol" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The LIRC protocol was always a bad fit and if we're ever going to expose protocol numbers in a user-space API, it'd be better to get rid of the LIRC "protocol" first. The sysfs API is kept backwards compatible by always listing the lirc protocol as present and enabled. Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-lirc-codec.c | 5 +--- drivers/media/rc/keymaps/rc-lirc.c | 2 +- drivers/media/rc/rc-main.c | 14 +++++++---- include/media/rc-map.h | 38 ++++++++++++++---------------- 4 files changed, 29 insertions(+), 30 deletions(-) diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c index 98893a8332c7a..a32659fcd266c 100644 --- a/drivers/media/rc/ir-lirc-codec.c +++ b/drivers/media/rc/ir-lirc-codec.c @@ -35,9 +35,6 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev) struct lirc_codec *lirc = &dev->raw->lirc; int sample; - if (!(dev->enabled_protocols & RC_BIT_LIRC)) - return 0; - if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf) return -EINVAL; @@ -424,7 +421,7 @@ static int ir_lirc_unregister(struct rc_dev *dev) } static struct ir_raw_handler lirc_handler = { - .protocols = RC_BIT_LIRC, + .protocols = 0, .decode = ir_lirc_decode, .raw_register = ir_lirc_register, .raw_unregister = ir_lirc_unregister, diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c index fbf08fa6f46e7..e172f5db58035 100644 --- a/drivers/media/rc/keymaps/rc-lirc.c +++ b/drivers/media/rc/keymaps/rc-lirc.c @@ -20,7 +20,7 @@ static struct rc_map_list lirc_map = { .map = { .scan = lirc, .size = ARRAY_SIZE(lirc), - .rc_type = RC_TYPE_LIRC, + .rc_type = RC_TYPE_OTHER, .name = RC_MAP_LIRC, } }; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 20914edd5a102..c80816561181b 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -800,7 +800,6 @@ static struct { { RC_BIT_SANYO, "sanyo" }, { RC_BIT_SHARP, "sharp" }, { RC_BIT_MCE_KBD, "mce_kbd" }, - { RC_BIT_LIRC, "lirc" }, { RC_BIT_XMP, "xmp" }, }; @@ -885,6 +884,9 @@ static ssize_t show_protocols(struct device *device, allowed &= ~proto_names[i].type; } + if (dev->driver_type == RC_DRIVER_IR_RAW) + tmp += sprintf(tmp, "[lirc] "); + if (tmp != buf) tmp--; *tmp = '\n'; @@ -936,8 +938,12 @@ static int parse_protocol_change(u64 *protocols, const char *buf) } if (i == ARRAY_SIZE(proto_names)) { - IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); - return -EINVAL; + if (!strcasecmp(tmp, "lirc")) + mask = 0; + else { + IR_dprintk(1, "Unknown protocol: '%s'\n", tmp); + return -EINVAL; + } } count++; @@ -1425,8 +1431,6 @@ int rc_register_device(struct rc_dev *dev) if (dev->change_protocol) { u64 rc_type = (1ll << rc_map->rc_type); - if (dev->driver_type == RC_DRIVER_IR_RAW) - rc_type |= RC_BIT_LIRC; rc = dev->change_protocol(dev, &rc_type); if (rc < 0) goto out_raw; diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 27763d5bd2612..7c4bbc4dfab4b 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -14,30 +14,28 @@ enum rc_type { RC_TYPE_UNKNOWN = 0, /* Protocol not known */ RC_TYPE_OTHER = 1, /* Protocol known but proprietary */ - RC_TYPE_LIRC = 2, /* Pass raw IR to lirc userspace */ - RC_TYPE_RC5 = 3, /* Philips RC5 protocol */ - RC_TYPE_RC5X = 4, /* Philips RC5x protocol */ - RC_TYPE_RC5_SZ = 5, /* StreamZap variant of RC5 */ - RC_TYPE_JVC = 6, /* JVC protocol */ - RC_TYPE_SONY12 = 7, /* Sony 12 bit protocol */ - RC_TYPE_SONY15 = 8, /* Sony 15 bit protocol */ - RC_TYPE_SONY20 = 9, /* Sony 20 bit protocol */ - RC_TYPE_NEC = 10, /* NEC protocol */ - RC_TYPE_SANYO = 11, /* Sanyo protocol */ - RC_TYPE_MCE_KBD = 12, /* RC6-ish MCE keyboard/mouse */ - RC_TYPE_RC6_0 = 13, /* Philips RC6-0-16 protocol */ - RC_TYPE_RC6_6A_20 = 14, /* Philips RC6-6A-20 protocol */ - RC_TYPE_RC6_6A_24 = 15, /* Philips RC6-6A-24 protocol */ - RC_TYPE_RC6_6A_32 = 16, /* Philips RC6-6A-32 protocol */ - RC_TYPE_RC6_MCE = 17, /* MCE (Philips RC6-6A-32 subtype) protocol */ - RC_TYPE_SHARP = 18, /* Sharp protocol */ - RC_TYPE_XMP = 19, /* XMP protocol */ + RC_TYPE_RC5 = 2, /* Philips RC5 protocol */ + RC_TYPE_RC5X = 3, /* Philips RC5x protocol */ + RC_TYPE_RC5_SZ = 4, /* StreamZap variant of RC5 */ + RC_TYPE_JVC = 5, /* JVC protocol */ + RC_TYPE_SONY12 = 6, /* Sony 12 bit protocol */ + RC_TYPE_SONY15 = 7, /* Sony 15 bit protocol */ + RC_TYPE_SONY20 = 8, /* Sony 20 bit protocol */ + RC_TYPE_NEC = 9, /* NEC protocol */ + RC_TYPE_SANYO = 10, /* Sanyo protocol */ + RC_TYPE_MCE_KBD = 11, /* RC6-ish MCE keyboard/mouse */ + RC_TYPE_RC6_0 = 12, /* Philips RC6-0-16 protocol */ + RC_TYPE_RC6_6A_20 = 13, /* Philips RC6-6A-20 protocol */ + RC_TYPE_RC6_6A_24 = 14, /* Philips RC6-6A-24 protocol */ + RC_TYPE_RC6_6A_32 = 15, /* Philips RC6-6A-32 protocol */ + RC_TYPE_RC6_MCE = 16, /* MCE (Philips RC6-6A-32 subtype) protocol */ + RC_TYPE_SHARP = 17, /* Sharp protocol */ + RC_TYPE_XMP = 18, /* XMP protocol */ }; #define RC_BIT_NONE 0 #define RC_BIT_UNKNOWN (1 << RC_TYPE_UNKNOWN) #define RC_BIT_OTHER (1 << RC_TYPE_OTHER) -#define RC_BIT_LIRC (1 << RC_TYPE_LIRC) #define RC_BIT_RC5 (1 << RC_TYPE_RC5) #define RC_BIT_RC5X (1 << RC_TYPE_RC5X) #define RC_BIT_RC5_SZ (1 << RC_TYPE_RC5_SZ) @@ -56,7 +54,7 @@ enum rc_type { #define RC_BIT_SHARP (1 << RC_TYPE_SHARP) #define RC_BIT_XMP (1 << RC_TYPE_XMP) -#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \ +#define RC_BIT_ALL (RC_BIT_UNKNOWN | RC_BIT_OTHER | \ RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \ RC_BIT_JVC | \ RC_BIT_SONY12 | RC_BIT_SONY15 | RC_BIT_SONY20 | \ -- GitLab From f459aec2bc81a46b674901424295f8ffe5e29ad0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A4rdeman?= Date: Tue, 19 May 2015 19:03:27 -0300 Subject: [PATCH 0443/7006] [media] lmedm04: NEC scancode cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes the keymap back to the state before commit 616a4b83 and changes the driver to use full NEC32 scancodes following the instructions provided by Malcolm Priestley . Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/keymaps/rc-lme2510.c | 132 ++++++++++++------------- drivers/media/usb/dvb-usb-v2/lmedm04.c | 21 ++-- 2 files changed, 77 insertions(+), 76 deletions(-) diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c index 51f18bb50a371..2b0027c413326 100644 --- a/drivers/media/rc/keymaps/rc-lme2510.c +++ b/drivers/media/rc/keymaps/rc-lme2510.c @@ -15,74 +15,74 @@ static struct rc_map_table lme2510_rc[] = { /* Type 1 - 26 buttons */ - { 0x10ed45, KEY_0 }, - { 0x10ed5f, KEY_1 }, - { 0x10ed50, KEY_2 }, - { 0x10ed5d, KEY_3 }, - { 0x10ed41, KEY_4 }, - { 0x10ed0a, KEY_5 }, - { 0x10ed42, KEY_6 }, - { 0x10ed47, KEY_7 }, - { 0x10ed49, KEY_8 }, - { 0x10ed05, KEY_9 }, - { 0x10ed43, KEY_POWER }, - { 0x10ed46, KEY_SUBTITLE }, - { 0x10ed06, KEY_PAUSE }, - { 0x10ed03, KEY_MEDIA_REPEAT}, - { 0x10ed02, KEY_PAUSE }, - { 0x10ed5e, KEY_VOLUMEUP }, - { 0x10ed5c, KEY_VOLUMEDOWN }, - { 0x10ed09, KEY_CHANNELUP }, - { 0x10ed1a, KEY_CHANNELDOWN }, - { 0x10ed1e, KEY_PLAY }, - { 0x10ed1b, KEY_ZOOM }, - { 0x10ed59, KEY_MUTE }, - { 0x10ed5a, KEY_TV }, - { 0x10ed18, KEY_RECORD }, - { 0x10ed07, KEY_EPG }, - { 0x10ed01, KEY_STOP }, + { 0xef12ba45, KEY_0 }, + { 0xef12a05f, KEY_1 }, + { 0xef12af50, KEY_2 }, + { 0xef12a25d, KEY_3 }, + { 0xef12be41, KEY_4 }, + { 0xef12f50a, KEY_5 }, + { 0xef12bd42, KEY_6 }, + { 0xef12b847, KEY_7 }, + { 0xef12b649, KEY_8 }, + { 0xef12fa05, KEY_9 }, + { 0xef12bc43, KEY_POWER }, + { 0xef12b946, KEY_SUBTITLE }, + { 0xef12f906, KEY_PAUSE }, + { 0xef12fc03, KEY_MEDIA_REPEAT}, + { 0xef12fd02, KEY_PAUSE }, + { 0xef12a15e, KEY_VOLUMEUP }, + { 0xef12a35c, KEY_VOLUMEDOWN }, + { 0xef12f609, KEY_CHANNELUP }, + { 0xef12e51a, KEY_CHANNELDOWN }, + { 0xef12e11e, KEY_PLAY }, + { 0xef12e41b, KEY_ZOOM }, + { 0xef12a659, KEY_MUTE }, + { 0xef12a55a, KEY_TV }, + { 0xef12e718, KEY_RECORD }, + { 0xef12f807, KEY_EPG }, + { 0xef12fe01, KEY_STOP }, /* Type 2 - 20 buttons */ - { 0xbf15, KEY_0 }, - { 0xbf08, KEY_1 }, - { 0xbf09, KEY_2 }, - { 0xbf0a, KEY_3 }, - { 0xbf0c, KEY_4 }, - { 0xbf0d, KEY_5 }, - { 0xbf0e, KEY_6 }, - { 0xbf10, KEY_7 }, - { 0xbf11, KEY_8 }, - { 0xbf12, KEY_9 }, - { 0xbf00, KEY_POWER }, - { 0xbf04, KEY_MEDIA_REPEAT}, /* Recall */ - { 0xbf1a, KEY_PAUSE }, /* Timeshift */ - { 0xbf02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0xbf06, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ - { 0xbf01, KEY_CHANNELUP }, - { 0xbf05, KEY_CHANNELDOWN }, - { 0xbf14, KEY_ZOOM }, - { 0xbf18, KEY_RECORD }, - { 0xbf16, KEY_STOP }, + { 0xff40ea15, KEY_0 }, + { 0xff40f708, KEY_1 }, + { 0xff40f609, KEY_2 }, + { 0xff40f50a, KEY_3 }, + { 0xff40f30c, KEY_4 }, + { 0xff40f20d, KEY_5 }, + { 0xff40f10e, KEY_6 }, + { 0xff40ef10, KEY_7 }, + { 0xff40ee11, KEY_8 }, + { 0xff40ed12, KEY_9 }, + { 0xff40ff00, KEY_POWER }, + { 0xff40fb04, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff40e51a, KEY_PAUSE }, /* Timeshift */ + { 0xff40fd02, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff40f906, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xff40fe01, KEY_CHANNELUP }, + { 0xff40fa05, KEY_CHANNELDOWN }, + { 0xff40eb14, KEY_ZOOM }, + { 0xff40e718, KEY_RECORD }, + { 0xff40e916, KEY_STOP }, /* Type 3 - 20 buttons */ - { 0x1c, KEY_0 }, - { 0x07, KEY_1 }, - { 0x15, KEY_2 }, - { 0x09, KEY_3 }, - { 0x16, KEY_4 }, - { 0x19, KEY_5 }, - { 0x0d, KEY_6 }, - { 0x0c, KEY_7 }, - { 0x18, KEY_8 }, - { 0x5e, KEY_9 }, - { 0x45, KEY_POWER }, - { 0x44, KEY_MEDIA_REPEAT}, /* Recall */ - { 0x4a, KEY_PAUSE }, /* Timeshift */ - { 0x47, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ - { 0x43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ - { 0x46, KEY_CHANNELUP }, - { 0x40, KEY_CHANNELDOWN }, - { 0x08, KEY_ZOOM }, - { 0x42, KEY_RECORD }, - { 0x5a, KEY_STOP }, + { 0xff00e31c, KEY_0 }, + { 0xff00f807, KEY_1 }, + { 0xff00ea15, KEY_2 }, + { 0xff00f609, KEY_3 }, + { 0xff00e916, KEY_4 }, + { 0xff00e619, KEY_5 }, + { 0xff00f20d, KEY_6 }, + { 0xff00f30c, KEY_7 }, + { 0xff00e718, KEY_8 }, + { 0xff00a15e, KEY_9 }, + { 0xff00ba45, KEY_POWER }, + { 0xff00bb44, KEY_MEDIA_REPEAT}, /* Recall */ + { 0xff00b54a, KEY_PAUSE }, /* Timeshift */ + { 0xff00b847, KEY_VOLUMEUP }, /* 2 x -/+ Keys not marked */ + { 0xff00bc43, KEY_VOLUMEDOWN }, /* Volume defined as right hand*/ + { 0xff00b946, KEY_CHANNELUP }, + { 0xff00bf40, KEY_CHANNELDOWN }, + { 0xff00f708, KEY_ZOOM }, + { 0xff00bd42, KEY_RECORD }, + { 0xff00a55a, KEY_STOP }, }; static struct rc_map_list lme2510_map = { diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 4cc55b3a0558f..3721ee63b8fb0 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -348,15 +348,16 @@ static void lme2510_int_response(struct urb *lme_urb) switch (ibuf[0]) { case 0xaa: debug_data_snipet(1, "INT Remote data snipet", ibuf); - if ((ibuf[4] + ibuf[5]) == 0xff) { - key = RC_SCANCODE_NECX((ibuf[2] ^ 0xff) << 8 | - (ibuf[3] > 0) ? (ibuf[3] ^ 0xff) : 0, - ibuf[5]); - deb_info(1, "INT Key =%08x", key); - if (adap_to_d(adap)->rc_dev != NULL) - rc_keydown(adap_to_d(adap)->rc_dev, - RC_TYPE_NEC, key, 0); - } + if (!adap_to_d(adap)->rc_dev) + break; + + key = RC_SCANCODE_NEC32(ibuf[2] << 24 | + ibuf[3] << 16 | + ibuf[4] << 8 | + ibuf[5]); + + deb_info(1, "INT Key = 0x%08x", key); + rc_keydown(adap_to_d(adap)->rc_dev, RC_TYPE_NEC, key, 0); break; case 0xbb: switch (st->tuner_config) { @@ -1344,7 +1345,7 @@ module_usb_driver(lme2510_driver); MODULE_AUTHOR("Malcolm Priestley "); MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0"); -MODULE_VERSION("2.06"); +MODULE_VERSION("2.07"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(LME2510_C_S7395); MODULE_FIRMWARE(LME2510_C_LG); -- GitLab From 8783b9c50400c6279d7c3b716637b98e83d3c933 Mon Sep 17 00:00:00 2001 From: Nibble Max Date: Mon, 29 Jun 2015 11:09:42 -0300 Subject: [PATCH 0444/7006] [media] SMI PCIe IR driver for DVBSky cards Ported from the manufacturer's source tree, available from http://dvbsky.net/download/linux/media_build-bst-150211.tar.gz This is the second patch after a public review. [mchehab@osg.samsung.com: fix inconsistent identing warning] Signed-off-by: Dirk Nehring Reviewd-by: Nibble Max Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/smipcie/Kconfig | 1 + drivers/media/pci/smipcie/Makefile | 3 + drivers/media/pci/smipcie/smipcie-ir.c | 232 ++++++++++++++++++ .../pci/smipcie/{smipcie.c => smipcie-main.c} | 14 +- drivers/media/pci/smipcie/smipcie.h | 19 ++ 5 files changed, 268 insertions(+), 1 deletion(-) create mode 100644 drivers/media/pci/smipcie/smipcie-ir.c rename drivers/media/pci/smipcie/{smipcie.c => smipcie-main.c} (99%) diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig index 21a1583dbd8f9..c11c772830c93 100644 --- a/drivers/media/pci/smipcie/Kconfig +++ b/drivers/media/pci/smipcie/Kconfig @@ -7,6 +7,7 @@ config DVB_SMIPCIE select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT + depends on RC_CORE help Support for cards with SMI PCIe bridge: - DVBSky S950 V3 diff --git a/drivers/media/pci/smipcie/Makefile b/drivers/media/pci/smipcie/Makefile index be55481a6e958..013bc3fe4294f 100644 --- a/drivers/media/pci/smipcie/Makefile +++ b/drivers/media/pci/smipcie/Makefile @@ -1,3 +1,6 @@ + +smipcie-objs := smipcie-main.o smipcie-ir.o + obj-$(CONFIG_DVB_SMIPCIE) += smipcie.o ccflags-y += -Idrivers/media/tuners diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c new file mode 100644 index 0000000000000..d018673c71f67 --- /dev/null +++ b/drivers/media/pci/smipcie/smipcie-ir.c @@ -0,0 +1,232 @@ +/* + * SMI PCIe driver for DVBSky cards. + * + * Copyright (C) 2014 Max nibble + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "smipcie.h" + +static void smi_ir_enableInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_ENA_SET, IR_X_INT); +} + +static void smi_ir_disableInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_ENA_CLR, IR_X_INT); +} + +static void smi_ir_clearInterrupt(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(MSI_INT_STATUS_CLR, IR_X_INT); +} + +static void smi_ir_stop(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_ir_disableInterrupt(ir); + smi_clear(IR_Init_Reg, 0x80); +} + +#define BITS_PER_COMMAND 14 +#define GROUPS_PER_BIT 2 +#define IR_RC5_MIN_BIT 36 +#define IR_RC5_MAX_BIT 52 +static u32 smi_decode_rc5(u8 *pData, u8 size) +{ + u8 index, current_bit, bit_count; + u8 group_array[BITS_PER_COMMAND * GROUPS_PER_BIT + 4]; + u8 group_index = 0; + u32 command = 0xFFFFFFFF; + + group_array[group_index++] = 1; + + for (index = 0; index < size; index++) { + + current_bit = (pData[index] & 0x80) ? 1 : 0; + bit_count = pData[index] & 0x7f; + + if ((current_bit == 1) && (bit_count >= 2*IR_RC5_MAX_BIT + 1)) { + goto process_code; + } else if ((bit_count >= IR_RC5_MIN_BIT) && + (bit_count <= IR_RC5_MAX_BIT)) { + group_array[group_index++] = current_bit; + } else if ((bit_count > IR_RC5_MAX_BIT) && + (bit_count <= 2*IR_RC5_MAX_BIT)) { + group_array[group_index++] = current_bit; + group_array[group_index++] = current_bit; + } else { + goto invalid_timing; + } + if (group_index >= BITS_PER_COMMAND*GROUPS_PER_BIT) + goto process_code; + + if ((group_index == BITS_PER_COMMAND*GROUPS_PER_BIT - 1) + && (group_array[group_index-1] == 0)) { + group_array[group_index++] = 1; + goto process_code; + } + } + +process_code: + if (group_index == (BITS_PER_COMMAND*GROUPS_PER_BIT-1)) + group_array[group_index++] = 1; + + if (group_index == BITS_PER_COMMAND*GROUPS_PER_BIT) { + command = 0; + for (index = 0; index < (BITS_PER_COMMAND*GROUPS_PER_BIT); + index = index + 2) { + if ((group_array[index] == 1) && + (group_array[index+1] == 0)) { + command |= (1 << (BITS_PER_COMMAND - + (index/2) - 1)); + } else if ((group_array[index] == 0) && + (group_array[index+1] == 1)) { + /* */ + } else { + command = 0xFFFFFFFF; + goto invalid_timing; + } + } + } + +invalid_timing: + return command; +} + +static void smi_ir_decode(struct work_struct *work) +{ + struct smi_rc *ir = container_of(work, struct smi_rc, work); + struct smi_dev *dev = ir->dev; + struct rc_dev *rc_dev = ir->rc_dev; + u32 dwIRControl, dwIRData, dwIRCode, scancode; + u8 index, ucIRCount, readLoop, rc5_command, rc5_system, toggle; + + dwIRControl = smi_read(IR_Init_Reg); + if (dwIRControl & rbIRVld) { + ucIRCount = (u8) smi_read(IR_Data_Cnt); + + if (ucIRCount < 4) + goto end_ir_decode; + + readLoop = ucIRCount/4; + if (ucIRCount % 4) + readLoop += 1; + for (index = 0; index < readLoop; index++) { + dwIRData = smi_read(IR_DATA_BUFFER_BASE + (index*4)); + + ir->irData[index*4 + 0] = (u8)(dwIRData); + ir->irData[index*4 + 1] = (u8)(dwIRData >> 8); + ir->irData[index*4 + 2] = (u8)(dwIRData >> 16); + ir->irData[index*4 + 3] = (u8)(dwIRData >> 24); + } + dwIRCode = smi_decode_rc5(ir->irData, ucIRCount); + + if (dwIRCode != 0xFFFFFFFF) { + rc5_command = dwIRCode & 0x3F; + rc5_system = (dwIRCode & 0x7C0) >> 6; + toggle = (dwIRCode & 0x800) ? 1 : 0; + scancode = rc5_system << 8 | rc5_command; + rc_keydown(rc_dev, RC_TYPE_RC5, scancode, toggle); + } + } +end_ir_decode: + smi_set(IR_Init_Reg, 0x04); + smi_ir_enableInterrupt(ir); +} + +/* ir functions call by main driver.*/ +int smi_ir_irq(struct smi_rc *ir, u32 int_status) +{ + int handled = 0; + + if (int_status & IR_X_INT) { + smi_ir_disableInterrupt(ir); + smi_ir_clearInterrupt(ir); + schedule_work(&ir->work); + handled = 1; + } + return handled; +} + +void smi_ir_start(struct smi_rc *ir) +{ + struct smi_dev *dev = ir->dev; + + smi_write(IR_Idle_Cnt_Low, 0x00140070); + msleep(20); + smi_set(IR_Init_Reg, 0x90); + + smi_ir_enableInterrupt(ir); +} + +int smi_ir_init(struct smi_dev *dev) +{ + int ret; + struct rc_dev *rc_dev; + struct smi_rc *ir = &dev->ir; + + rc_dev = rc_allocate_device(); + if (!rc_dev) + return -ENOMEM; + + /* init input device */ + snprintf(ir->input_name, sizeof(ir->input_name), "IR (%s)", + dev->info->name); + snprintf(ir->input_phys, sizeof(ir->input_phys), "pci-%s/ir0", + pci_name(dev->pci_dev)); + + rc_dev->driver_name = "SMI_PCIe"; + rc_dev->input_phys = ir->input_phys; + rc_dev->input_name = ir->input_name; + rc_dev->input_id.bustype = BUS_PCI; + rc_dev->input_id.version = 1; + rc_dev->input_id.vendor = dev->pci_dev->subsystem_vendor; + rc_dev->input_id.product = dev->pci_dev->subsystem_device; + rc_dev->dev.parent = &dev->pci_dev->dev; + + rc_dev->driver_type = RC_DRIVER_SCANCODE; + rc_dev->map_name = RC_MAP_DVBSKY; + + ir->rc_dev = rc_dev; + ir->dev = dev; + + INIT_WORK(&ir->work, smi_ir_decode); + smi_ir_disableInterrupt(ir); + + ret = rc_register_device(rc_dev); + if (ret) + goto ir_err; + + return 0; +ir_err: + rc_free_device(rc_dev); + return ret; +} + +void smi_ir_exit(struct smi_dev *dev) +{ + struct smi_rc *ir = &dev->ir; + struct rc_dev *rc_dev = ir->rc_dev; + + smi_ir_stop(ir); + rc_unregister_device(rc_dev); + ir->rc_dev = NULL; +} diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie-main.c similarity index 99% rename from drivers/media/pci/smipcie/smipcie.c rename to drivers/media/pci/smipcie/smipcie-main.c index 143fd7899ecd3..b039a229b7d2b 100644 --- a/drivers/media/pci/smipcie/smipcie.c +++ b/drivers/media/pci/smipcie/smipcie-main.c @@ -468,6 +468,7 @@ static irqreturn_t smi_irq_handler(int irq, void *dev_id) struct smi_dev *dev = dev_id; struct smi_port *port0 = &dev->ts_port[0]; struct smi_port *port1 = &dev->ts_port[1]; + struct smi_rc *ir = &dev->ir; int handled = 0; u32 intr_status = smi_read(MSI_INT_STATUS); @@ -480,6 +481,9 @@ static irqreturn_t smi_irq_handler(int irq, void *dev_id) if (dev->info->ts_1) handled += smi_port_irq(port1, intr_status); + /* ir interrupt.*/ + handled += smi_ir_irq(ir, intr_status); + return IRQ_RETVAL(handled); } @@ -993,6 +997,10 @@ static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto err_del_port0_attach; } + ret = smi_ir_init(dev); + if (ret < 0) + goto err_del_port1_attach; + #ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/ if (pci_msi_enabled()) ret = pci_enable_msi(dev->pci_dev); @@ -1003,10 +1011,13 @@ static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id) ret = request_irq(dev->pci_dev->irq, smi_irq_handler, IRQF_SHARED, "SMI_PCIE", dev); if (ret < 0) - goto err_del_port1_attach; + goto err_del_ir; + smi_ir_start(&dev->ir); return 0; +err_del_ir: + smi_ir_exit(dev); err_del_port1_attach: if (dev->info->ts_1) smi_port_detach(&dev->ts_port[1]); @@ -1039,6 +1050,7 @@ static void smi_remove(struct pci_dev *pdev) if (dev->info->ts_0) smi_port_detach(&dev->ts_port[0]); + smi_ir_exit(dev); smi_i2c_exit(dev); iounmap(dev->lmmio); pci_set_drvdata(pdev, NULL); diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h index 10cdf20f48391..68cdda28fd984 100644 --- a/drivers/media/pci/smipcie/smipcie.h +++ b/drivers/media/pci/smipcie/smipcie.h @@ -234,6 +234,17 @@ struct smi_cfg_info { int fe_1; }; +struct smi_rc { + struct smi_dev *dev; + struct rc_dev *rc_dev; + char input_phys[64]; + char input_name[64]; + struct work_struct work; + u8 irData[256]; + + int users; +}; + struct smi_port { struct smi_dev *dev; int idx; @@ -284,6 +295,9 @@ struct smi_dev { /* i2c */ struct i2c_adapter i2c_bus[2]; struct i2c_algo_bit_data i2c_bit[2]; + + /* ir */ + struct smi_rc ir; }; #define smi_read(reg) readl(dev->lmmio + ((reg)>>2)) @@ -296,4 +310,9 @@ struct smi_dev { #define smi_set(reg, bit) smi_andor((reg), (bit), (bit)) #define smi_clear(reg, bit) smi_andor((reg), (bit), 0) +int smi_ir_irq(struct smi_rc *ir, u32 int_status); +void smi_ir_start(struct smi_rc *ir); +void smi_ir_exit(struct smi_dev *dev); +int smi_ir_init(struct smi_dev *dev); + #endif /* #ifndef _SMI_PCIE_H_ */ -- GitLab From f7d71f2052555ae57b47322f2c2f6c29ff2438ae Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Fri, 19 Jun 2015 11:50:00 -0400 Subject: [PATCH 0445/7006] locking/qrwlock: Rename functions to queued_*() To sync up with the naming convention used in qspinlock, all the qrwlock functions were renamed to started with "queued" instead of "queue". Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Cc: Arnd Bergmann Cc: Douglas Hatch Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Scott J Norton Cc: Thomas Gleixner Cc: Will Deacon Link: http://lkml.kernel.org/r/1434729002-57724-2-git-send-email-Waiman.Long@hp.com Signed-off-by: Ingo Molnar --- arch/x86/include/asm/qrwlock.h | 4 +-- include/asm-generic/qrwlock.h | 58 +++++++++++++++++----------------- kernel/locking/qrwlock.c | 12 +++---- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/arch/x86/include/asm/qrwlock.h b/arch/x86/include/asm/qrwlock.h index ae0e241e228b8..a8810bf135ab2 100644 --- a/arch/x86/include/asm/qrwlock.h +++ b/arch/x86/include/asm/qrwlock.h @@ -4,8 +4,8 @@ #include #ifndef CONFIG_X86_PPRO_FENCE -#define queue_write_unlock queue_write_unlock -static inline void queue_write_unlock(struct qrwlock *lock) +#define queued_write_unlock queued_write_unlock +static inline void queued_write_unlock(struct qrwlock *lock) { barrier(); ACCESS_ONCE(*(u8 *)&lock->cnts) = 0; diff --git a/include/asm-generic/qrwlock.h b/include/asm-generic/qrwlock.h index 6383d54bf983a..55e3ee1d24152 100644 --- a/include/asm-generic/qrwlock.h +++ b/include/asm-generic/qrwlock.h @@ -36,33 +36,33 @@ /* * External function declarations */ -extern void queue_read_lock_slowpath(struct qrwlock *lock); -extern void queue_write_lock_slowpath(struct qrwlock *lock); +extern void queued_read_lock_slowpath(struct qrwlock *lock); +extern void queued_write_lock_slowpath(struct qrwlock *lock); /** - * queue_read_can_lock- would read_trylock() succeed? + * queued_read_can_lock- would read_trylock() succeed? * @lock: Pointer to queue rwlock structure */ -static inline int queue_read_can_lock(struct qrwlock *lock) +static inline int queued_read_can_lock(struct qrwlock *lock) { return !(atomic_read(&lock->cnts) & _QW_WMASK); } /** - * queue_write_can_lock- would write_trylock() succeed? + * queued_write_can_lock- would write_trylock() succeed? * @lock: Pointer to queue rwlock structure */ -static inline int queue_write_can_lock(struct qrwlock *lock) +static inline int queued_write_can_lock(struct qrwlock *lock) { return !atomic_read(&lock->cnts); } /** - * queue_read_trylock - try to acquire read lock of a queue rwlock + * queued_read_trylock - try to acquire read lock of a queue rwlock * @lock : Pointer to queue rwlock structure * Return: 1 if lock acquired, 0 if failed */ -static inline int queue_read_trylock(struct qrwlock *lock) +static inline int queued_read_trylock(struct qrwlock *lock) { u32 cnts; @@ -77,11 +77,11 @@ static inline int queue_read_trylock(struct qrwlock *lock) } /** - * queue_write_trylock - try to acquire write lock of a queue rwlock + * queued_write_trylock - try to acquire write lock of a queue rwlock * @lock : Pointer to queue rwlock structure * Return: 1 if lock acquired, 0 if failed */ -static inline int queue_write_trylock(struct qrwlock *lock) +static inline int queued_write_trylock(struct qrwlock *lock) { u32 cnts; @@ -93,10 +93,10 @@ static inline int queue_write_trylock(struct qrwlock *lock) cnts, cnts | _QW_LOCKED) == cnts); } /** - * queue_read_lock - acquire read lock of a queue rwlock + * queued_read_lock - acquire read lock of a queue rwlock * @lock: Pointer to queue rwlock structure */ -static inline void queue_read_lock(struct qrwlock *lock) +static inline void queued_read_lock(struct qrwlock *lock) { u32 cnts; @@ -105,27 +105,27 @@ static inline void queue_read_lock(struct qrwlock *lock) return; /* The slowpath will decrement the reader count, if necessary. */ - queue_read_lock_slowpath(lock); + queued_read_lock_slowpath(lock); } /** - * queue_write_lock - acquire write lock of a queue rwlock + * queued_write_lock - acquire write lock of a queue rwlock * @lock : Pointer to queue rwlock structure */ -static inline void queue_write_lock(struct qrwlock *lock) +static inline void queued_write_lock(struct qrwlock *lock) { /* Optimize for the unfair lock case where the fair flag is 0. */ if (atomic_cmpxchg(&lock->cnts, 0, _QW_LOCKED) == 0) return; - queue_write_lock_slowpath(lock); + queued_write_lock_slowpath(lock); } /** - * queue_read_unlock - release read lock of a queue rwlock + * queued_read_unlock - release read lock of a queue rwlock * @lock : Pointer to queue rwlock structure */ -static inline void queue_read_unlock(struct qrwlock *lock) +static inline void queued_read_unlock(struct qrwlock *lock) { /* * Atomically decrement the reader count @@ -134,12 +134,12 @@ static inline void queue_read_unlock(struct qrwlock *lock) atomic_sub(_QR_BIAS, &lock->cnts); } -#ifndef queue_write_unlock +#ifndef queued_write_unlock /** - * queue_write_unlock - release write lock of a queue rwlock + * queued_write_unlock - release write lock of a queue rwlock * @lock : Pointer to queue rwlock structure */ -static inline void queue_write_unlock(struct qrwlock *lock) +static inline void queued_write_unlock(struct qrwlock *lock) { /* * If the writer field is atomic, it can be cleared directly. @@ -154,13 +154,13 @@ static inline void queue_write_unlock(struct qrwlock *lock) * Remapping rwlock architecture specific functions to the corresponding * queue rwlock functions. */ -#define arch_read_can_lock(l) queue_read_can_lock(l) -#define arch_write_can_lock(l) queue_write_can_lock(l) -#define arch_read_lock(l) queue_read_lock(l) -#define arch_write_lock(l) queue_write_lock(l) -#define arch_read_trylock(l) queue_read_trylock(l) -#define arch_write_trylock(l) queue_write_trylock(l) -#define arch_read_unlock(l) queue_read_unlock(l) -#define arch_write_unlock(l) queue_write_unlock(l) +#define arch_read_can_lock(l) queued_read_can_lock(l) +#define arch_write_can_lock(l) queued_write_can_lock(l) +#define arch_read_lock(l) queued_read_lock(l) +#define arch_write_lock(l) queued_write_lock(l) +#define arch_read_trylock(l) queued_read_trylock(l) +#define arch_write_trylock(l) queued_write_trylock(l) +#define arch_read_unlock(l) queued_read_unlock(l) +#define arch_write_unlock(l) queued_write_unlock(l) #endif /* __ASM_GENERIC_QRWLOCK_H */ diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c index 6c5da483966bd..49057d413b6e0 100644 --- a/kernel/locking/qrwlock.c +++ b/kernel/locking/qrwlock.c @@ -60,10 +60,10 @@ rspin_until_writer_unlock(struct qrwlock *lock, u32 cnts) } /** - * queue_read_lock_slowpath - acquire read lock of a queue rwlock + * queued_read_lock_slowpath - acquire read lock of a queue rwlock * @lock: Pointer to queue rwlock structure */ -void queue_read_lock_slowpath(struct qrwlock *lock) +void queued_read_lock_slowpath(struct qrwlock *lock) { u32 cnts; @@ -104,13 +104,13 @@ void queue_read_lock_slowpath(struct qrwlock *lock) */ arch_spin_unlock(&lock->lock); } -EXPORT_SYMBOL(queue_read_lock_slowpath); +EXPORT_SYMBOL(queued_read_lock_slowpath); /** - * queue_write_lock_slowpath - acquire write lock of a queue rwlock + * queued_write_lock_slowpath - acquire write lock of a queue rwlock * @lock : Pointer to queue rwlock structure */ -void queue_write_lock_slowpath(struct qrwlock *lock) +void queued_write_lock_slowpath(struct qrwlock *lock) { u32 cnts; @@ -149,4 +149,4 @@ void queue_write_lock_slowpath(struct qrwlock *lock) unlock: arch_spin_unlock(&lock->lock); } -EXPORT_SYMBOL(queue_write_lock_slowpath); +EXPORT_SYMBOL(queued_write_lock_slowpath); -- GitLab From 0e06e5be70d392aa842c1455ec2d0baf62aeed48 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Fri, 19 Jun 2015 11:50:01 -0400 Subject: [PATCH 0446/7006] locking/qrwlock: Better optimization for interrupt context readers The qrwlock is fair in the process context, but becoming unfair when in the interrupt context to support use cases like the tasklist_lock. The current code isn't that well-documented on what happens when in the interrupt context. The rspin_until_writer_unlock() will only spin if the writer has gotten the lock. If the writer is still in the waiting state, the increment in the reader count will cause the writer to remain in the waiting state and the new interrupt context reader will get the lock and return immediately. The current code, however, does an additional read of the lock value which is not necessary as the information has already been there in the fast path. This may sometime cause an additional cacheline transfer when the lock is highly contended. This patch passes the lock value information gotten in the fast path to the slow path to eliminate the additional read. It also documents the action for the interrupt context readers more clearly. Signed-off-by: Waiman Long Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Will Deacon Cc: Arnd Bergmann Cc: Douglas Hatch Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Scott J Norton Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/1434729002-57724-3-git-send-email-Waiman.Long@hp.com Signed-off-by: Ingo Molnar --- include/asm-generic/qrwlock.h | 4 ++-- kernel/locking/qrwlock.c | 13 +++++++------ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/asm-generic/qrwlock.h b/include/asm-generic/qrwlock.h index 55e3ee1d24152..deb9e8b0eb9ef 100644 --- a/include/asm-generic/qrwlock.h +++ b/include/asm-generic/qrwlock.h @@ -36,7 +36,7 @@ /* * External function declarations */ -extern void queued_read_lock_slowpath(struct qrwlock *lock); +extern void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts); extern void queued_write_lock_slowpath(struct qrwlock *lock); /** @@ -105,7 +105,7 @@ static inline void queued_read_lock(struct qrwlock *lock) return; /* The slowpath will decrement the reader count, if necessary. */ - queued_read_lock_slowpath(lock); + queued_read_lock_slowpath(lock, cnts); } /** diff --git a/kernel/locking/qrwlock.c b/kernel/locking/qrwlock.c index 49057d413b6e0..d9c36c5f57115 100644 --- a/kernel/locking/qrwlock.c +++ b/kernel/locking/qrwlock.c @@ -62,20 +62,21 @@ rspin_until_writer_unlock(struct qrwlock *lock, u32 cnts) /** * queued_read_lock_slowpath - acquire read lock of a queue rwlock * @lock: Pointer to queue rwlock structure + * @cnts: Current qrwlock lock value */ -void queued_read_lock_slowpath(struct qrwlock *lock) +void queued_read_lock_slowpath(struct qrwlock *lock, u32 cnts) { - u32 cnts; - /* * Readers come here when they cannot get the lock without waiting */ if (unlikely(in_interrupt())) { /* - * Readers in interrupt context will spin until the lock is - * available without waiting in the queue. + * Readers in interrupt context will get the lock immediately + * if the writer is just waiting (not holding the lock yet). + * The rspin_until_writer_unlock() function returns immediately + * in this case. Otherwise, they will spin until the lock + * is available without waiting in the queue. */ - cnts = smp_load_acquire((u32 *)&lock->cnts); rspin_until_writer_unlock(lock, cnts); return; } -- GitLab From d713fd4976f2838ca2ebccdc187256edb46bd48e Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:07 -0300 Subject: [PATCH 0447/7006] drm/i915: add simple wrappers for stolen node insertion/removal We want to move the FBC code out of i915_gem_stolen.c, but that code directly adds/removes stolen memory nodes. Let's create this abstraction, so i915_gme_stolen.c is still in control of all the stolen memory handling. The abstraction will also allow us to add locking assertions later. v2: - Add dev_priv as remove_node() argument since we'll need it later (Chris). Requested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 5 +++ drivers/gpu/drm/i915/i915_gem_stolen.c | 48 +++++++++++++++++--------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 63daf4cd2477a..3e746ccf17ffd 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3112,6 +3112,11 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev) } /* i915_gem_stolen.c */ +int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node, u64 size, + unsigned alignment); +void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node); int i915_gem_init_stolen(struct drm_device *dev); int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_cpp); void i915_gem_stolen_cleanup_compression(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index 348ed5abcdbf6..d811b148817f6 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -42,6 +42,23 @@ * for is a boon. */ +int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node, u64 size, + unsigned alignment) +{ + if (!drm_mm_initialized(&dev_priv->mm.stolen)) + return -ENODEV; + + return drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment, + DRM_MM_SEARCH_DEFAULT); +} + +void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, + struct drm_mm_node *node) +{ + drm_mm_remove_node(node); +} + static unsigned long i915_stolen_to_physical(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -168,8 +185,7 @@ static int find_compression_threshold(struct drm_device *dev, */ /* Try to over-allocate to reduce reallocations and fragmentation. */ - ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, - size <<= 1, 4096, DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096); if (ret == 0) return compression_threshold; @@ -179,9 +195,7 @@ again: (fb_cpp == 2 && compression_threshold == 2)) return 0; - ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, - size >>= 1, 4096, - DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); if (ret && INTEL_INFO(dev)->gen <= 4) { return 0; } else if (ret) { @@ -218,8 +232,8 @@ static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp) if (!compressed_llb) goto err_fb; - ret = drm_mm_insert_node(&dev_priv->mm.stolen, compressed_llb, - 4096, 4096, DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, compressed_llb, + 4096, 4096); if (ret) goto err_fb; @@ -240,7 +254,7 @@ static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp) err_fb: kfree(compressed_llb); - drm_mm_remove_node(&dev_priv->fbc.compressed_fb); + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); err_llb: pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); return -ENOSPC; @@ -269,10 +283,11 @@ void i915_gem_stolen_cleanup_compression(struct drm_device *dev) if (dev_priv->fbc.uncompressed_size == 0) return; - drm_mm_remove_node(&dev_priv->fbc.compressed_fb); + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); if (dev_priv->fbc.compressed_llb) { - drm_mm_remove_node(dev_priv->fbc.compressed_llb); + i915_gem_stolen_remove_node(dev_priv, + dev_priv->fbc.compressed_llb); kfree(dev_priv->fbc.compressed_llb); } @@ -386,8 +401,10 @@ static void i915_gem_object_put_pages_stolen(struct drm_i915_gem_object *obj) static void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + if (obj->stolen) { - drm_mm_remove_node(obj->stolen); + i915_gem_stolen_remove_node(dev_priv, obj->stolen); kfree(obj->stolen); obj->stolen = NULL; } @@ -449,8 +466,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) if (!stolen) return NULL; - ret = drm_mm_insert_node(&dev_priv->mm.stolen, stolen, size, - 4096, DRM_MM_SEARCH_DEFAULT); + ret = i915_gem_stolen_insert_node(dev_priv, stolen, size, 4096); if (ret) { kfree(stolen); return NULL; @@ -460,7 +476,7 @@ i915_gem_object_create_stolen(struct drm_device *dev, u32 size) if (obj) return obj; - drm_mm_remove_node(stolen); + i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); return NULL; } @@ -505,7 +521,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, obj = _i915_gem_object_create_stolen(dev, stolen); if (obj == NULL) { DRM_DEBUG_KMS("failed to allocate stolen object\n"); - drm_mm_remove_node(stolen); + i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); return NULL; } @@ -546,7 +562,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, err_vma: i915_gem_vma_destroy(vma); err_out: - drm_mm_remove_node(stolen); + i915_gem_stolen_remove_node(dev_priv, stolen); kfree(stolen); drm_gem_object_unreference(&obj->base); return NULL; -- GitLab From fc786728ee8acc76e22769af3b2df67b94cd49b6 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:08 -0300 Subject: [PATCH 0448/7006] drm/i915: move FBC code out of i915_gem_stolen.c With the abstractions created by the last patch, we can move this code and the only thing inside intel_fbc.c that knows about dev_priv->mm is the code that reads stolen_base. We also had to move a call to i915_gem_stolen_cleanup_compression() - now called intel_fbc_cleanup_cfb() - outside i915_gem_stolen.c. v2: - Rebase after the remove_node() changes on the previous patch. Requested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 1 + drivers/gpu/drm/i915/i915_drv.h | 2 - drivers/gpu/drm/i915/i915_gem_stolen.c | 127 ------------------------ drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 129 ++++++++++++++++++++++++- 5 files changed, 128 insertions(+), 132 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index a42f165924335..066c34c3298a1 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1123,6 +1123,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); + intel_fbc_cleanup_cfb(dev); i915_gem_cleanup_stolen(dev); intel_csr_ucode_fini(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 3e746ccf17ffd..2b78686e23d92 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3118,8 +3118,6 @@ int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node); int i915_gem_init_stolen(struct drm_device *dev); -int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_cpp); -void i915_gem_stolen_cleanup_compression(struct drm_device *dev); void i915_gem_cleanup_stolen(struct drm_device *dev); struct drm_i915_gem_object * i915_gem_object_create_stolen(struct drm_device *dev, u32 size); diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index d811b148817f6..d2d556c691755 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -168,132 +168,6 @@ static unsigned long i915_stolen_to_physical(struct drm_device *dev) return base; } -static int find_compression_threshold(struct drm_device *dev, - struct drm_mm_node *node, - int size, - int fb_cpp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int compression_threshold = 1; - int ret; - - /* HACK: This code depends on what we will do in *_enable_fbc. If that - * code changes, this code needs to change as well. - * - * The enable_fbc code will attempt to use one of our 2 compression - * thresholds, therefore, in that case, we only have 1 resort. - */ - - /* Try to over-allocate to reduce reallocations and fragmentation. */ - ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096); - if (ret == 0) - return compression_threshold; - -again: - /* HW's ability to limit the CFB is 1:4 */ - if (compression_threshold > 4 || - (fb_cpp == 2 && compression_threshold == 2)) - return 0; - - ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); - if (ret && INTEL_INFO(dev)->gen <= 4) { - return 0; - } else if (ret) { - compression_threshold <<= 1; - goto again; - } else { - return compression_threshold; - } -} - -static int i915_setup_compression(struct drm_device *dev, int size, int fb_cpp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_mm_node *uninitialized_var(compressed_llb); - int ret; - - ret = find_compression_threshold(dev, &dev_priv->fbc.compressed_fb, - size, fb_cpp); - if (!ret) - goto err_llb; - else if (ret > 1) { - DRM_INFO("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n"); - - } - - dev_priv->fbc.threshold = ret; - - if (INTEL_INFO(dev_priv)->gen >= 5) - I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); - else if (IS_GM45(dev)) { - I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); - } else { - compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); - if (!compressed_llb) - goto err_fb; - - ret = i915_gem_stolen_insert_node(dev_priv, compressed_llb, - 4096, 4096); - if (ret) - goto err_fb; - - dev_priv->fbc.compressed_llb = compressed_llb; - - I915_WRITE(FBC_CFB_BASE, - dev_priv->mm.stolen_base + dev_priv->fbc.compressed_fb.start); - I915_WRITE(FBC_LL_BASE, - dev_priv->mm.stolen_base + compressed_llb->start); - } - - dev_priv->fbc.uncompressed_size = size; - - DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", - size); - - return 0; - -err_fb: - kfree(compressed_llb); - i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); -err_llb: - pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); - return -ENOSPC; -} - -int i915_gem_stolen_setup_compression(struct drm_device *dev, int size, int fb_cpp) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (!drm_mm_initialized(&dev_priv->mm.stolen)) - return -ENODEV; - - if (size <= dev_priv->fbc.uncompressed_size) - return 0; - - /* Release any current block */ - i915_gem_stolen_cleanup_compression(dev); - - return i915_setup_compression(dev, size, fb_cpp); -} - -void i915_gem_stolen_cleanup_compression(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - if (dev_priv->fbc.uncompressed_size == 0) - return; - - i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); - - if (dev_priv->fbc.compressed_llb) { - i915_gem_stolen_remove_node(dev_priv, - dev_priv->fbc.compressed_llb); - kfree(dev_priv->fbc.compressed_llb); - } - - dev_priv->fbc.uncompressed_size = 0; -} - void i915_gem_cleanup_stolen(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -301,7 +175,6 @@ void i915_gem_cleanup_stolen(struct drm_device *dev) if (!drm_mm_initialized(&dev_priv->mm.stolen)) return; - i915_gem_stolen_cleanup_compression(dev); drm_mm_takedown(&dev_priv->mm.stolen); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 3f0a89060820b..82abbfae4e23e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1258,6 +1258,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); +void intel_fbc_cleanup_cfb(struct drm_device *dev); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 9e55b9badb4bc..55711b452fbf8 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -515,6 +515,129 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) return crtc; } +static int find_compression_threshold(struct drm_device *dev, + struct drm_mm_node *node, + int size, + int fb_cpp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int compression_threshold = 1; + int ret; + + /* HACK: This code depends on what we will do in *_enable_fbc. If that + * code changes, this code needs to change as well. + * + * The enable_fbc code will attempt to use one of our 2 compression + * thresholds, therefore, in that case, we only have 1 resort. + */ + + /* Try to over-allocate to reduce reallocations and fragmentation. */ + ret = i915_gem_stolen_insert_node(dev_priv, node, size <<= 1, 4096); + if (ret == 0) + return compression_threshold; + +again: + /* HW's ability to limit the CFB is 1:4 */ + if (compression_threshold > 4 || + (fb_cpp == 2 && compression_threshold == 2)) + return 0; + + ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); + if (ret && INTEL_INFO(dev)->gen <= 4) { + return 0; + } else if (ret) { + compression_threshold <<= 1; + goto again; + } else { + return compression_threshold; + } +} + +static int intel_fbc_alloc_cfb(struct drm_device *dev, int size, int fb_cpp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_mm_node *uninitialized_var(compressed_llb); + int ret; + + ret = find_compression_threshold(dev, &dev_priv->fbc.compressed_fb, + size, fb_cpp); + if (!ret) + goto err_llb; + else if (ret > 1) { + DRM_INFO("Reducing the compressed framebuffer size. This may lead to less power savings than a non-reduced-size. Try to increase stolen memory size if available in BIOS.\n"); + + } + + dev_priv->fbc.threshold = ret; + + if (INTEL_INFO(dev_priv)->gen >= 5) + I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); + else if (IS_GM45(dev)) { + I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); + } else { + compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); + if (!compressed_llb) + goto err_fb; + + ret = i915_gem_stolen_insert_node(dev_priv, compressed_llb, + 4096, 4096); + if (ret) + goto err_fb; + + dev_priv->fbc.compressed_llb = compressed_llb; + + I915_WRITE(FBC_CFB_BASE, + dev_priv->mm.stolen_base + dev_priv->fbc.compressed_fb.start); + I915_WRITE(FBC_LL_BASE, + dev_priv->mm.stolen_base + compressed_llb->start); + } + + dev_priv->fbc.uncompressed_size = size; + + DRM_DEBUG_KMS("reserved %d bytes of contiguous stolen space for FBC\n", + size); + + return 0; + +err_fb: + kfree(compressed_llb); + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); +err_llb: + pr_info_once("drm: not enough stolen space for compressed buffer (need %d more bytes), disabling. Hint: you may be able to increase stolen memory size in the BIOS to avoid this.\n", size); + return -ENOSPC; +} + +void intel_fbc_cleanup_cfb(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (dev_priv->fbc.uncompressed_size == 0) + return; + + i915_gem_stolen_remove_node(dev_priv, &dev_priv->fbc.compressed_fb); + + if (dev_priv->fbc.compressed_llb) { + i915_gem_stolen_remove_node(dev_priv, + dev_priv->fbc.compressed_llb); + kfree(dev_priv->fbc.compressed_llb); + } + + dev_priv->fbc.uncompressed_size = 0; +} + +static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + if (size <= dev_priv->fbc.uncompressed_size) + return 0; + + /* Release any current block */ + intel_fbc_cleanup_cfb(dev); + + return intel_fbc_alloc_cfb(dev, size, fb_cpp); +} + /** * intel_fbc_update - enable/disable FBC as needed * @dev: the drm_device @@ -624,8 +747,8 @@ void intel_fbc_update(struct drm_device *dev) if (in_dbg_master()) goto out_disable; - if (i915_gem_stolen_setup_compression(dev, obj->base.size, - drm_format_plane_cpp(fb->pixel_format, 0))) { + if (intel_fbc_setup_cfb(dev, obj->base.size, + drm_format_plane_cpp(fb->pixel_format, 0))) { set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; } @@ -678,7 +801,7 @@ out_disable: DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); intel_fbc_disable(dev); } - i915_gem_stolen_cleanup_compression(dev); + intel_fbc_cleanup_cfb(dev); } void intel_fbc_invalidate(struct drm_i915_private *dev_priv, -- GitLab From 92e97d2f47616b144feb86db489e134935b021b8 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:09 -0300 Subject: [PATCH 0449/7006] drm/i915: add dev_priv->mm.stolen_lock Which should protect dev_priv->mm.stolen usage. This will allow us to simplify the relationship between stolen memory, FBC and struct_mutex. v2: - Rebase after the stolen_remove_node() dev_priv patch move. - I realized that after we fixed a few things related to the FBC CFB size checks, we're not reallocating the CFB anymore with FBC enabled, so we can just move all the locking to i915_gem_stolen.c and stop worrying about freezing all the stolen alocations while freeing/rellocating the CFB. This allows us to fix the "Too coarse" observation from Chris. Suggested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++++ drivers/gpu/drm/i915/i915_gem_stolen.c | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2b78686e23d92..eb10c16240067 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1245,6 +1245,10 @@ struct intel_l3_parity { struct i915_gem_mm { /** Memory allocator for GTT stolen memory */ struct drm_mm stolen; + /** Protects the usage of the GTT stolen memory allocator. This is + * always the inner lock when overlapping with struct_mutex. */ + struct mutex stolen_lock; + /** List of all objects in gtt_space. Used to restore gtt * mappings on resume */ struct list_head bound_list; diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index d2d556c691755..de76d886cd1d4 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -46,17 +46,25 @@ int i915_gem_stolen_insert_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node, u64 size, unsigned alignment) { + int ret; + if (!drm_mm_initialized(&dev_priv->mm.stolen)) return -ENODEV; - return drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment, - DRM_MM_SEARCH_DEFAULT); + mutex_lock(&dev_priv->mm.stolen_lock); + ret = drm_mm_insert_node(&dev_priv->mm.stolen, node, size, alignment, + DRM_MM_SEARCH_DEFAULT); + mutex_unlock(&dev_priv->mm.stolen_lock); + + return ret; } void i915_gem_stolen_remove_node(struct drm_i915_private *dev_priv, struct drm_mm_node *node) { + mutex_lock(&dev_priv->mm.stolen_lock); drm_mm_remove_node(node); + mutex_unlock(&dev_priv->mm.stolen_lock); } static unsigned long i915_stolen_to_physical(struct drm_device *dev) @@ -184,6 +192,8 @@ int i915_gem_init_stolen(struct drm_device *dev) u32 tmp; int bios_reserved = 0; + mutex_init(&dev_priv->mm.stolen_lock); + #ifdef CONFIG_INTEL_IOMMU if (intel_iommu_gfx_mapped && INTEL_INFO(dev)->gen < 8) { DRM_INFO("DMAR active, disabling use of stolen memory\n"); @@ -384,7 +394,9 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev, stolen->start = stolen_offset; stolen->size = size; + mutex_lock(&dev_priv->mm.stolen_lock); ret = drm_mm_reserve_node(&dev_priv->mm.stolen, stolen); + mutex_unlock(&dev_priv->mm.stolen_lock); if (ret) { DRM_DEBUG_KMS("failed to allocate stolen space\n"); kfree(stolen); -- GitLab From 25ad93fd9f0513df41f70327cca19d51369f1674 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:10 -0300 Subject: [PATCH 0450/7006] drm/i915: add the FBC mutex Make sure we're not going to have weird races in really weird cases where a lot of different CRTCs are doing rendering and modesets at the same time. With this change and the stolen_lock from the previous patch, we can start removing the struct_mutex locking we have around FBC in the next patches. v2: - Rebase (6 months later) - Also lock debugfs and stolen. v3: - Don't lock a single value read (Chris). - Replace lockdep assertions with WARNs (Daniel). - Improve commit message. - Don't forget intel_pre_plane_update() locking. v4: - Don't remove struct_mutex at intel_pre_plane_update() (Chris). - Add comment regarding locking dependencies (Chris). - Rebase after the stolen code rework. - Rebase again after drm-intel-nightly changes. v5: - Rebase after the new stolen_lock patch. Reviewed-by: Chris Wilson (v4) Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ++ drivers/gpu/drm/i915/i915_drv.h | 3 + drivers/gpu/drm/i915/intel_display.c | 6 +- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 101 +++++++++++++++++++++++---- 5 files changed, 96 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 6a8de04c6a2bb..cc74a92dd3465 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1633,6 +1633,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) } intel_runtime_pm_get(dev_priv); + mutex_lock(&dev_priv->fbc.lock); if (intel_fbc_enabled(dev)) seq_puts(m, "FBC enabled\n"); @@ -1645,6 +1646,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) yesno(I915_READ(FBC_STATUS2) & FBC_COMPRESSION_MASK)); + mutex_unlock(&dev_priv->fbc.lock); intel_runtime_pm_put(dev_priv); return 0; @@ -1675,6 +1677,7 @@ static int i915_fbc_fc_set(void *data, u64 val) return -ENODEV; drm_modeset_lock_all(dev); + mutex_lock(&dev_priv->fbc.lock); reg = I915_READ(ILK_DPFC_CONTROL); dev_priv->fbc.false_color = val; @@ -1683,6 +1686,7 @@ static int i915_fbc_fc_set(void *data, u64 val) (reg | FBC_CTL_FALSE_COLOR) : (reg & ~FBC_CTL_FALSE_COLOR)); + mutex_unlock(&dev_priv->fbc.lock); drm_modeset_unlock_all(dev); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index eb10c16240067..093d6421dddfa 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -899,6 +899,9 @@ enum fb_op_origin { }; struct i915_fbc { + /* This is always the inner lock when overlapping with struct_mutex and + * it's the outer lock when overlapping with stolen_lock. */ + struct mutex lock; unsigned long uncompressed_size; unsigned threshold; unsigned int fb_id; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 136b533718786..93d3bdf242a94 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4783,11 +4783,9 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->wait_for_flips) intel_crtc_wait_for_pending_flips(&crtc->base); - if (atomic->disable_fbc && - dev_priv->fbc.crtc == crtc) { + if (atomic->disable_fbc) { mutex_lock(&dev->struct_mutex); - if (dev_priv->fbc.crtc == crtc) - intel_fbc_disable(dev); + intel_fbc_disable_crtc(crtc); mutex_unlock(&dev->struct_mutex); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 82abbfae4e23e..63d7d32e61230 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1252,6 +1252,7 @@ bool intel_fbc_enabled(struct drm_device *dev); void intel_fbc_update(struct drm_device *dev); void intel_fbc_init(struct drm_i915_private *dev_priv); void intel_fbc_disable(struct drm_device *dev); +void intel_fbc_disable_crtc(struct intel_crtc *crtc); void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 55711b452fbf8..a076c7a25062f 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -336,6 +336,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct drm_i915_private *dev_priv = dev->dev_private; mutex_lock(&dev->struct_mutex); + mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling * the prior work. @@ -350,6 +351,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) dev_priv->fbc.fbc_work = NULL; } + mutex_unlock(&dev_priv->fbc.lock); mutex_unlock(&dev->struct_mutex); kfree(work); @@ -357,6 +359,8 @@ static void intel_fbc_work_fn(struct work_struct *__work) static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) { + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + if (dev_priv->fbc.fbc_work == NULL) return; @@ -384,6 +388,8 @@ static void intel_fbc_enable(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + if (!dev_priv->display.enable_fbc) return; @@ -418,6 +424,21 @@ static void intel_fbc_enable(struct drm_crtc *crtc) schedule_delayed_work(&work->work, msecs_to_jiffies(50)); } +static void __intel_fbc_disable(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + + intel_fbc_cancel_work(dev_priv); + + if (!dev_priv->display.disable_fbc) + return; + + dev_priv->display.disable_fbc(dev); + dev_priv->fbc.crtc = NULL; +} + /** * intel_fbc_disable - disable FBC * @dev: the drm_device @@ -428,13 +449,26 @@ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - intel_fbc_cancel_work(dev_priv); + mutex_lock(&dev_priv->fbc.lock); + __intel_fbc_disable(dev); + mutex_unlock(&dev_priv->fbc.lock); +} - if (!dev_priv->display.disable_fbc) - return; +/* + * intel_fbc_disable_crtc - disable FBC if it's associated with crtc + * @crtc: the CRTC + * + * This function disables FBC if it's associated with the provided CRTC. + */ +void intel_fbc_disable_crtc(struct intel_crtc *crtc) +{ + struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; - dev_priv->display.disable_fbc(dev); - dev_priv->fbc.crtc = NULL; + mutex_lock(&dev_priv->fbc.lock); + if (dev_priv->fbc.crtc == crtc) + __intel_fbc_disable(dev); + mutex_unlock(&dev_priv->fbc.lock); } const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) @@ -607,7 +641,7 @@ err_llb: return -ENOSPC; } -void intel_fbc_cleanup_cfb(struct drm_device *dev) +static void __intel_fbc_cleanup_cfb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -625,6 +659,15 @@ void intel_fbc_cleanup_cfb(struct drm_device *dev) dev_priv->fbc.uncompressed_size = 0; } +void intel_fbc_cleanup_cfb(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->fbc.lock); + __intel_fbc_cleanup_cfb(dev); + mutex_unlock(&dev_priv->fbc.lock); +} + static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -633,13 +676,13 @@ static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) return 0; /* Release any current block */ - intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev); return intel_fbc_alloc_cfb(dev, size, fb_cpp); } /** - * intel_fbc_update - enable/disable FBC as needed + * __intel_fbc_update - enable/disable FBC as needed, unlocked * @dev: the drm_device * * Set up the framebuffer compression hardware at mode set time. We @@ -657,7 +700,7 @@ static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) * * We need to enable/disable FBC on a global basis. */ -void intel_fbc_update(struct drm_device *dev) +static void __intel_fbc_update(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = NULL; @@ -670,6 +713,8 @@ void intel_fbc_update(struct drm_device *dev) if (!HAS_FBC(dev)) return; + WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); + /* disable framebuffer compression in vGPU */ if (intel_vgpu_active(dev)) i915.enable_fbc = 0; @@ -788,7 +833,7 @@ void intel_fbc_update(struct drm_device *dev) * some point. And we wait before enabling FBC anyway. */ DRM_DEBUG_KMS("disabling active FBC for update\n"); - intel_fbc_disable(dev); + __intel_fbc_disable(dev); } intel_fbc_enable(crtc); @@ -799,9 +844,24 @@ out_disable: /* Multiple disables should be harmless */ if (intel_fbc_enabled(dev)) { DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - intel_fbc_disable(dev); + __intel_fbc_disable(dev); } - intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev); +} + +/* + * intel_fbc_update - enable/disable FBC as needed + * @dev: the drm_device + * + * This function reevaluates the overall state and enables or disables FBC. + */ +void intel_fbc_update(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + mutex_lock(&dev_priv->fbc.lock); + __intel_fbc_update(dev); + mutex_unlock(&dev_priv->fbc.lock); } void intel_fbc_invalidate(struct drm_i915_private *dev_priv, @@ -814,6 +874,8 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, if (origin == ORIGIN_GTT) return; + mutex_lock(&dev_priv->fbc.lock); + if (dev_priv->fbc.enabled) fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe); else if (dev_priv->fbc.fbc_work) @@ -825,7 +887,9 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits); if (dev_priv->fbc.busy_bits) - intel_fbc_disable(dev); + __intel_fbc_disable(dev); + + mutex_unlock(&dev_priv->fbc.lock); } void intel_fbc_flush(struct drm_i915_private *dev_priv, @@ -833,13 +897,18 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; + mutex_lock(&dev_priv->fbc.lock); + if (!dev_priv->fbc.busy_bits) - return; + goto out; dev_priv->fbc.busy_bits &= ~frontbuffer_bits; if (!dev_priv->fbc.busy_bits) - intel_fbc_update(dev); + __intel_fbc_update(dev); + +out: + mutex_unlock(&dev_priv->fbc.lock); } /** @@ -852,6 +921,8 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) { enum pipe pipe; + mutex_init(&dev_priv->fbc.lock); + if (!HAS_FBC(dev_priv)) { dev_priv->fbc.enabled = false; dev_priv->fbc.no_fbc_reason = FBC_UNSUPPORTED; -- GitLab From 5abeca4ec5d425538b73af58076990823a744e2a Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:11 -0300 Subject: [PATCH 0451/7006] drm/i915: intel_frontbuffer_flip_prepare() doesn't need struct_mutex So release the lock earlier. Reviewed-by: Chris wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 93d3bdf242a94..e1f9ae69a13a3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11475,9 +11475,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); intel_fbc_disable(dev); + mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); - mutex_unlock(&dev->struct_mutex); trace_i915_flip_request(intel_crtc->plane, obj); -- GitLab From b5e4b84d9f12b093780a4e90e51604c3b4706cde Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:12 -0300 Subject: [PATCH 0452/7006] drm/i915: intel_unregister_dsm_handler() doesn't need struct_mutex So don't grab the lock before calling the function. Reviewed-by: Chris wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index e1f9ae69a13a3..8ddeb294f1ebb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15603,12 +15603,10 @@ void intel_modeset_cleanup(struct drm_device *dev) */ drm_kms_helper_poll_fini(dev); - mutex_lock(&dev->struct_mutex); - intel_unregister_dsm_handler(); + mutex_lock(&dev->struct_mutex); intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); /* flush any delayed tasks or pending work */ -- GitLab From c80ac8548d167dfb7affdb997d99d875bb1a28a3 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Thu, 2 Jul 2015 19:25:13 -0300 Subject: [PATCH 0453/7006] drm/i915: FBC doesn't need struct_mutex anymore Everything is covered either by fbc.lock or mm.stolen_lock, and intel_fbc.c is already responsible for grabbing the appropriate locks when it needs them. Reviewed-by: Chris wilson Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 ---- drivers/gpu/drm/i915/intel_display.c | 14 +++----------- drivers/gpu/drm/i915/intel_fbc.c | 2 -- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index cc74a92dd3465..5b89130eb366b 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1660,9 +1660,7 @@ static int i915_fbc_fc_get(void *data, u64 *val) if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev)) return -ENODEV; - drm_modeset_lock_all(dev); *val = dev_priv->fbc.false_color; - drm_modeset_unlock_all(dev); return 0; } @@ -1676,7 +1674,6 @@ static int i915_fbc_fc_set(void *data, u64 val) if (INTEL_INFO(dev)->gen < 7 || !HAS_FBC(dev)) return -ENODEV; - drm_modeset_lock_all(dev); mutex_lock(&dev_priv->fbc.lock); reg = I915_READ(ILK_DPFC_CONTROL); @@ -1687,7 +1684,6 @@ static int i915_fbc_fc_set(void *data, u64 val) (reg & ~FBC_CTL_FALSE_COLOR)); mutex_unlock(&dev_priv->fbc.lock); - drm_modeset_unlock_all(dev); return 0; } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ddeb294f1ebb..eb50f59d7840a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -4747,11 +4747,8 @@ static void intel_post_plane_update(struct intel_crtc *crtc) if (crtc->atomic.update_wm_post) intel_update_watermarks(&crtc->base); - if (atomic->update_fbc) { - mutex_lock(&dev->struct_mutex); + if (atomic->update_fbc) intel_fbc_update(dev); - mutex_unlock(&dev->struct_mutex); - } if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); @@ -4783,11 +4780,8 @@ static void intel_pre_plane_update(struct intel_crtc *crtc) if (atomic->wait_for_flips) intel_crtc_wait_for_pending_flips(&crtc->base); - if (atomic->disable_fbc) { - mutex_lock(&dev->struct_mutex); + if (atomic->disable_fbc) intel_fbc_disable_crtc(crtc); - mutex_unlock(&dev->struct_mutex); - } if (crtc->atomic.disable_ips) hsw_disable_ips(crtc); @@ -11473,9 +11467,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, i915_gem_track_fb(intel_fb_obj(work->old_fb), obj, to_intel_plane(primary)->frontbuffer_bit); + mutex_unlock(&dev->struct_mutex); intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); @@ -15605,9 +15599,7 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_unregister_dsm_handler(); - mutex_lock(&dev->struct_mutex); intel_fbc_disable(dev); - mutex_unlock(&dev->struct_mutex); /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index a076c7a25062f..cc9b7effec401 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -335,7 +335,6 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct drm_device *dev = work->crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - mutex_lock(&dev->struct_mutex); mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling @@ -352,7 +351,6 @@ static void intel_fbc_work_fn(struct work_struct *__work) dev_priv->fbc.fbc_work = NULL; } mutex_unlock(&dev_priv->fbc.lock); - mutex_unlock(&dev->struct_mutex); kfree(work); } -- GitLab From 0bf73c361f986a04af332600bf06476c8f481c5b Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Fri, 3 Jul 2015 15:40:54 -0300 Subject: [PATCH 0454/7006] drm/i915: protect FBC functions with FBC checks Now all the functions called by other files check whether FBC has been initialized. This allows us to drop the checks on the static functions. v2: - s/HAS_FBC/dev_priv->display.enable_fbc/ everywhere but the init function (Chris). Suggested-by: Chris Wilson Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index cc9b7effec401..65f08e330dc18 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -388,9 +388,6 @@ static void intel_fbc_enable(struct drm_crtc *crtc) WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); - if (!dev_priv->display.enable_fbc) - return; - intel_fbc_cancel_work(dev_priv); work = kzalloc(sizeof(*work), GFP_KERNEL); @@ -430,9 +427,6 @@ static void __intel_fbc_disable(struct drm_device *dev) intel_fbc_cancel_work(dev_priv); - if (!dev_priv->display.disable_fbc) - return; - dev_priv->display.disable_fbc(dev); dev_priv->fbc.crtc = NULL; } @@ -447,6 +441,9 @@ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); __intel_fbc_disable(dev); mutex_unlock(&dev_priv->fbc.lock); @@ -463,6 +460,9 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); if (dev_priv->fbc.crtc == crtc) __intel_fbc_disable(dev); @@ -661,6 +661,9 @@ void intel_fbc_cleanup_cfb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); __intel_fbc_cleanup_cfb(dev); mutex_unlock(&dev_priv->fbc.lock); @@ -708,9 +711,6 @@ static void __intel_fbc_update(struct drm_device *dev) const struct drm_display_mode *adjusted_mode; unsigned int max_width, max_height; - if (!HAS_FBC(dev)) - return; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); /* disable framebuffer compression in vGPU */ @@ -857,6 +857,9 @@ void intel_fbc_update(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); __intel_fbc_update(dev); mutex_unlock(&dev_priv->fbc.lock); @@ -869,6 +872,9 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; unsigned int fbc_bits; + if (!dev_priv->display.enable_fbc) + return; + if (origin == ORIGIN_GTT) return; @@ -895,6 +901,9 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; + if (!dev_priv->display.enable_fbc) + return; + mutex_lock(&dev_priv->fbc.lock); if (!dev_priv->fbc.busy_bits) -- GitLab From 9e00084750c0f0603ec8a6ff15e0bcf78b8202bd Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Fri, 3 Jul 2015 14:27:31 +0100 Subject: [PATCH 0455/7006] drm/i915: Update WaFlushCoherentL3CacheLinesAtContextSwitch In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after PIPE_CONTROL instruction but there is a slight complication as this is applied in WA batch where the values are only initialized once. Dave identified an issue with the current implementation where the register value is read once at the beginning and it is reused; this patch corrects this by saving the register value to memory, update register with the bit of our interest and restore it back with original value. This implementation uses MI_LOAD_REGISTER_MEM which is currently only used by command parser and was using a default length of 0. This is now updated with correct length and moved to appropriate place. Cc: Chris Wilson Cc: Dave Gordon Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_cmd_parser.c | 6 +-- drivers/gpu/drm/i915/i915_reg.h | 3 +- drivers/gpu/drm/i915/intel_lrc.c | 72 +++++++++++++++++++------- 3 files changed, 58 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c index 306d9e4e5cf37..430571b977db9 100644 --- a/drivers/gpu/drm/i915/i915_cmd_parser.c +++ b/drivers/gpu/drm/i915/i915_cmd_parser.c @@ -131,7 +131,7 @@ static const struct drm_i915_cmd_descriptor common_cmds[] = { .mask = MI_GLOBAL_GTT, .expected = 0, }}, ), - CMD( MI_LOAD_REGISTER_MEM, SMI, !F, 0xFF, W | B, + CMD( MI_LOAD_REGISTER_MEM(1), SMI, !F, 0xFF, W | B, .reg = { .offset = 1, .mask = 0x007FFFFC }, .bits = {{ .offset = 0, @@ -1021,7 +1021,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * only MI_LOAD_REGISTER_IMM commands. */ if (reg_addr == OACONTROL) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM(1)) { DRM_DEBUG_DRIVER("CMD: Rejected LRM to OACONTROL\n"); return false; } @@ -1035,7 +1035,7 @@ static bool check_cmd(const struct intel_engine_cs *ring, * allowed mask/value pair given in the whitelist entry. */ if (reg->mask) { - if (desc->cmd.value == MI_LOAD_REGISTER_MEM) { + if (desc->cmd.value == MI_LOAD_REGISTER_MEM(1)) { DRM_DEBUG_DRIVER("CMD: Rejected LRM to masked register 0x%08X\n", reg_addr); return false; diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 45ff3d3e79c81..1c4d7894b429a 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -354,6 +354,8 @@ #define MI_INVALIDATE_BSD (1<<7) #define MI_FLUSH_DW_USE_GTT (1<<2) #define MI_FLUSH_DW_USE_PPGTT (0<<2) +#define MI_LOAD_REGISTER_MEM(x) MI_INSTR(0x29, 2*(x)-1) +#define MI_LOAD_REGISTER_MEM_GEN8(x) MI_INSTR(0x29, 3*(x)-1) #define MI_BATCH_BUFFER MI_INSTR(0x30, 1) #define MI_BATCH_NON_SECURE (1) /* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */ @@ -459,7 +461,6 @@ #define MI_CLFLUSH MI_INSTR(0x27, 0) #define MI_REPORT_PERF_COUNT MI_INSTR(0x28, 0) #define MI_REPORT_PERF_COUNT_GGTT (1<<0) -#define MI_LOAD_REGISTER_MEM MI_INSTR(0x29, 0) #define MI_LOAD_REGISTER_REG MI_INSTR(0x2A, 0) #define MI_RS_STORE_DATA_IMM MI_INSTR(0x2B, 0) #define MI_LOAD_URB_MEM MI_INSTR(0x2C, 0) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0160bec1e7ba7..a499f16db194b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1092,6 +1092,56 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) batch[index++] = (cmd); \ } while (0) + +/* + * In this WA we need to set GEN8_L3SQCREG4[21:21] and reset it after + * PIPE_CONTROL instruction. This is required for the flush to happen correctly + * but there is a slight complication as this is applied in WA batch where the + * values are only initialized once so we cannot take register value at the + * beginning and reuse it further; hence we save its value to memory, upload a + * constant value with bit21 set and then we restore it back with the saved value. + * To simplify the WA, a constant value is formed by using the default value + * of this register. This shouldn't be a problem because we are only modifying + * it for a short period and this batch in non-premptible. We can ofcourse + * use additional instructions that read the actual value of the register + * at that time and set our bit of interest but it makes the WA complicated. + * + * This WA is also required for Gen9 so extracting as a function avoids + * code duplication. + */ +static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, + uint32_t *const batch, + uint32_t index) +{ + uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); + + wa_ctx_emit(batch, (MI_STORE_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, 0); + + wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, l3sqc4_flush); + + wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_DC_FLUSH_ENABLE)); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, 0); + + wa_ctx_emit(batch, (MI_LOAD_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, GEN8_L3SQCREG4); + wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, 0); + + return index; +} + static inline uint32_t wa_ctx_start(struct i915_wa_ctx_bb *wa_ctx, uint32_t offset, uint32_t start_alignment) @@ -1152,25 +1202,9 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ if (IS_BROADWELL(ring->dev)) { - struct drm_i915_private *dev_priv = to_i915(ring->dev); - uint32_t l3sqc4_flush = (I915_READ(GEN8_L3SQCREG4) | - GEN8_LQSC_FLUSH_COHERENT_LINES); - - wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, l3sqc4_flush); - - wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); - wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_DC_FLUSH_ENABLE)); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - - wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, l3sqc4_flush & ~GEN8_LQSC_FLUSH_COHERENT_LINES); + index = gen8_emit_flush_coherentl3_wa(ring, batch, index); + if (index < 0) + return index; } /* WaClearSlmSpaceAtContextSwitch:bdw,chv */ -- GitLab From a647828afc7d7d352aeb076dbc03bd952b09b1e3 Mon Sep 17 00:00:00 2001 From: "Niu,Bing" Date: Sat, 4 Jul 2015 00:27:34 +0800 Subject: [PATCH 0456/7006] drm/i915: Also perform gpu reset under execlist mode. It is found that i915 will not reset gpu under execlist mode when unload module. that will lead to some issues when unload/load module with different submission mode. e.g. from execlist mode to ring buffer mode via loading/unloading i915. Because HW is not in a reset state and registers are not clean under such condition. Signed-off-by: Niu,Bing Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index c8ee13f466c87..672c803a0a27d 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5196,6 +5196,14 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev) for_each_ring(ring, dev_priv, i) dev_priv->gt.cleanup_ring(ring); + + if (i915.enable_execlists) + /* + * Neither the BIOS, ourselves or any other kernel + * expects the system to be in execlists mode on startup, + * so we need to reset the GPU back to legacy mode. + */ + intel_gpu_reset(dev); } static void -- GitLab From 35ca0ee49d2973976f89f07eb842782a39d20a14 Mon Sep 17 00:00:00 2001 From: Ludovic Desroches Date: Mon, 8 Jun 2015 10:33:16 +0200 Subject: [PATCH 0457/7006] dmaengine: at_xdmac: fix indentation Fix indentation. Signed-off-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index cf1213de7865e..86d56058021cc 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -624,12 +624,12 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, enum dma_transfer_direction direction, unsigned long flags, void *context) { - struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); - struct at_xdmac_desc *first = NULL, *prev = NULL; - struct scatterlist *sg; - int i; - unsigned int xfer_size = 0; - unsigned long irqflags; + struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan); + struct at_xdmac_desc *first = NULL, *prev = NULL; + struct scatterlist *sg; + int i; + unsigned int xfer_size = 0; + unsigned long irqflags; struct dma_async_tx_descriptor *ret = NULL; if (!sgl) -- GitLab From d264b48687fab995fe970451ed11f4259d68aee1 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Jun 2015 13:17:42 +0300 Subject: [PATCH 0458/7006] dmaengine: Remove remaining FSF mailing addresses Commit 3b62286d0ef7 ("dmaengine: Remove FSF mailing addresses") left Free Software Foundation mailing address still in two files. Remove it now. Signed-off-by: Jarkko Nikula Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 4 ---- drivers/dma/timb_dma.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index b859792dde955..113605f6fe208 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -11,10 +11,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c index c4c3d93fdd1bf..559cd4073698c 100644 --- a/drivers/dma/timb_dma.c +++ b/drivers/dma/timb_dma.c @@ -10,10 +10,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* Supports: -- GitLab From d8cb8875ac60e2832614a2c48af236b5899cf209 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:32 +0300 Subject: [PATCH 0459/7006] drm/i915: Convert execlist_submit_contexts() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a499f16db194b..7282466ee5678 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -358,29 +358,29 @@ static int execlists_update_context(struct drm_i915_gem_object *ctx_obj, return 0; } -static void execlists_submit_contexts(struct intel_engine_cs *ring, - struct intel_context *to0, u32 tail0, - struct intel_context *to1, u32 tail1) +static void execlists_submit_requests(struct drm_i915_gem_request *rq0, + struct drm_i915_gem_request *rq1) { - struct drm_i915_gem_object *ctx_obj0 = to0->engine[ring->id].state; - struct intel_ringbuffer *ringbuf0 = to0->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = rq0->ring; + struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; struct drm_i915_gem_object *ctx_obj1 = NULL; - struct intel_ringbuffer *ringbuf1 = NULL; BUG_ON(!ctx_obj0); WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0)); - WARN_ON(!i915_gem_obj_is_pinned(ringbuf0->obj)); + WARN_ON(!i915_gem_obj_is_pinned(rq0->ringbuf->obj)); - execlists_update_context(ctx_obj0, ringbuf0->obj, to0->ppgtt, tail0); + execlists_update_context(ctx_obj1, rq0->ringbuf->obj, + rq0->ctx->ppgtt, rq0->tail); + + if (rq1) { + ctx_obj1 = rq1->ctx->engine[ring->id].state; - if (to1) { - ringbuf1 = to1->engine[ring->id].ringbuf; - ctx_obj1 = to1->engine[ring->id].state; BUG_ON(!ctx_obj1); WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1)); - WARN_ON(!i915_gem_obj_is_pinned(ringbuf1->obj)); + WARN_ON(!i915_gem_obj_is_pinned(rq1->ringbuf->obj)); - execlists_update_context(ctx_obj1, ringbuf1->obj, to1->ppgtt, tail1); + execlists_update_context(ctx_obj1, rq1->ringbuf->obj, + rq1->ctx->ppgtt, rq1->tail); } execlists_elsp_write(ring, ctx_obj0, ctx_obj1); @@ -443,9 +443,7 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) WARN_ON(req1 && req1->elsp_submitted); - execlists_submit_contexts(ring, req0->ctx, req0->tail, - req1 ? req1->ctx : NULL, - req1 ? req1->tail : 0); + execlists_submit_requests(req0, req1); req0->elsp_submitted++; if (req1) -- GitLab From 05d9824bfb40e211c8804fee65af1fbb736925a2 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:33 +0300 Subject: [PATCH 0460/7006] drm/i915: Convert execlists_update_context() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 7282466ee5678..8e1619a06f3b6 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -329,19 +329,24 @@ static void execlists_elsp_write(struct intel_engine_cs *ring, spin_unlock(&dev_priv->uncore.lock); } -static int execlists_update_context(struct drm_i915_gem_object *ctx_obj, - struct drm_i915_gem_object *ring_obj, - struct i915_hw_ppgtt *ppgtt, - u32 tail) +static int execlists_update_context(struct drm_i915_gem_request *rq) { + struct intel_engine_cs *ring = rq->ring; + struct i915_hw_ppgtt *ppgtt = rq->ctx->ppgtt; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; + struct drm_i915_gem_object *rb_obj = rq->ringbuf->obj; struct page *page; uint32_t *reg_state; + BUG_ON(!ctx_obj); + WARN_ON(!i915_gem_obj_is_pinned(ctx_obj)); + WARN_ON(!i915_gem_obj_is_pinned(rb_obj)); + page = i915_gem_object_get_page(ctx_obj, 1); reg_state = kmap_atomic(page); - reg_state[CTX_RING_TAIL+1] = tail; - reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj); + reg_state[CTX_RING_TAIL+1] = rq->tail; + reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(rb_obj); /* True PPGTT with dynamic page allocation: update PDP registers and * point the unallocated PDPs to the scratch page @@ -365,22 +370,11 @@ static void execlists_submit_requests(struct drm_i915_gem_request *rq0, struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; struct drm_i915_gem_object *ctx_obj1 = NULL; - BUG_ON(!ctx_obj0); - WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0)); - WARN_ON(!i915_gem_obj_is_pinned(rq0->ringbuf->obj)); - - execlists_update_context(ctx_obj1, rq0->ringbuf->obj, - rq0->ctx->ppgtt, rq0->tail); + execlists_update_context(rq0); if (rq1) { + execlists_update_context(rq1); ctx_obj1 = rq1->ctx->engine[ring->id].state; - - BUG_ON(!ctx_obj1); - WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1)); - WARN_ON(!i915_gem_obj_is_pinned(rq1->ringbuf->obj)); - - execlists_update_context(ctx_obj1, rq1->ringbuf->obj, - rq1->ctx->ppgtt, rq1->tail); } execlists_elsp_write(ring, ctx_obj0, ctx_obj1); -- GitLab From f3cc01f0948c1deb12cfb1da2959f391229c9d4b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 6 Jul 2015 11:08:30 +0300 Subject: [PATCH 0461/7006] drm/i915: Assign request ringbuf before pin In preparation to make intel_lr_context_pin|unpin to accept requests, assign ringbuf into request before we call the pinning. v2: No need to unset ringbuf on error path (Chris) Cc: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 8e1619a06f3b6..fd285d32f62ae 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -633,14 +633,14 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request { int ret; + request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; + if (request->ctx != request->ring->default_context) { ret = intel_lr_context_pin(request->ring, request->ctx); if (ret) return ret; } - request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; - return 0; } -- GitLab From 8ba319da898fcecdac158cb46ca69e38b2b08da3 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:35 +0300 Subject: [PATCH 0462/7006] drm/i915: Convert intel_lr_context_pin() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 8 +++----- drivers/gpu/drm/i915/intel_lrc.c | 31 +++++++++++++++---------------- drivers/gpu/drm/i915/intel_lrc.h | 3 +-- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 672c803a0a27d..82c05b80b7ef0 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2620,10 +2620,8 @@ void i915_gem_request_free(struct kref *req_ref) if (ctx) { if (i915.enable_execlists) { - struct intel_engine_cs *ring = req->ring; - - if (ctx != ring->default_context) - intel_lr_context_unpin(ring, ctx); + if (ctx != req->ring->default_context) + intel_lr_context_unpin(req); } i915_gem_context_unreference(ctx); @@ -2765,7 +2763,7 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, list_del(&submit_req->execlist_link); if (submit_req->ctx != ring->default_context) - intel_lr_context_unpin(ring, submit_req->ctx); + intel_lr_context_unpin(submit_req); i915_gem_request_unreference(submit_req); } diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index fd285d32f62ae..5ae68215e6fb4 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -211,8 +211,7 @@ enum { #define GEN8_CTX_ID_SHIFT 32 #define CTX_RCS_INDIRECT_CTX_OFFSET_DEFAULT 0x17 -static int intel_lr_context_pin(struct intel_engine_cs *ring, - struct intel_context *ctx); +static int intel_lr_context_pin(struct drm_i915_gem_request *rq); /** * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists @@ -541,7 +540,7 @@ static int execlists_context_queue(struct drm_i915_gem_request *request) int num_elements = 0; if (request->ctx != ring->default_context) - intel_lr_context_pin(ring, request->ctx); + intel_lr_context_pin(request); i915_gem_request_reference(request); @@ -636,7 +635,7 @@ int intel_logical_ring_alloc_request_extras(struct drm_i915_gem_request *request request->ringbuf = request->ctx->engine[request->ring->id].ringbuf; if (request->ctx != request->ring->default_context) { - ret = intel_lr_context_pin(request->ring, request->ctx); + ret = intel_lr_context_pin(request); if (ret) return ret; } @@ -950,7 +949,7 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring) ctx->engine[ring->id].state; if (ctx_obj && (ctx != ring->default_context)) - intel_lr_context_unpin(ring, ctx); + intel_lr_context_unpin(req); list_del(&req->execlist_link); i915_gem_request_unreference(req); } @@ -994,15 +993,15 @@ int logical_ring_flush_all_caches(struct drm_i915_gem_request *req) return 0; } -static int intel_lr_context_pin(struct intel_engine_cs *ring, - struct intel_context *ctx) +static int intel_lr_context_pin(struct drm_i915_gem_request *rq) { - struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = rq->ring; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; + struct intel_ringbuffer *ringbuf = rq->ringbuf; int ret = 0; WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); - if (ctx->engine[ring->id].pin_count++ == 0) { + if (rq->ctx->engine[ring->id].pin_count++ == 0) { ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0); if (ret) @@ -1018,20 +1017,20 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring, unpin_ctx_obj: i915_gem_object_ggtt_unpin(ctx_obj); reset_pin_count: - ctx->engine[ring->id].pin_count = 0; + rq->ctx->engine[ring->id].pin_count = 0; return ret; } -void intel_lr_context_unpin(struct intel_engine_cs *ring, - struct intel_context *ctx) +void intel_lr_context_unpin(struct drm_i915_gem_request *rq) { - struct drm_i915_gem_object *ctx_obj = ctx->engine[ring->id].state; - struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf; + struct intel_engine_cs *ring = rq->ring; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; + struct intel_ringbuffer *ringbuf = rq->ringbuf; if (ctx_obj) { WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex)); - if (--ctx->engine[ring->id].pin_count == 0) { + if (--rq->ctx->engine[ring->id].pin_count == 0) { intel_unpin_ringbuffer_obj(ringbuf); i915_gem_object_ggtt_unpin(ctx_obj); } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index d3dd3ac33aefe..e0299fbb1728f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -70,8 +70,7 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf, void intel_lr_context_free(struct intel_context *ctx); int intel_lr_context_deferred_create(struct intel_context *ctx, struct intel_engine_cs *ring); -void intel_lr_context_unpin(struct intel_engine_cs *ring, - struct intel_context *ctx); +void intel_lr_context_unpin(struct drm_i915_gem_request *req); void intel_lr_context_reset(struct drm_device *dev, struct intel_context *ctx); -- GitLab From cc3c42532c312c60f8499e22bbdb895ed5ce1d73 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:36 +0300 Subject: [PATCH 0463/7006] drm/i915: Convert execlists_elsp_writ() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 5ae68215e6fb4..a07284adc3179 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -292,12 +292,16 @@ static uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring, return desc; } -static void execlists_elsp_write(struct intel_engine_cs *ring, - struct drm_i915_gem_object *ctx_obj0, - struct drm_i915_gem_object *ctx_obj1) +static void execlists_elsp_write(struct drm_i915_gem_request *rq0, + struct drm_i915_gem_request *rq1) { + + struct intel_engine_cs *ring = rq0->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; + struct drm_i915_gem_object *ctx_obj1 = rq1 ? + rq1->ctx->engine[ring->id].state : NULL; uint64_t temp = 0; uint32_t desc[4]; @@ -365,18 +369,12 @@ static int execlists_update_context(struct drm_i915_gem_request *rq) static void execlists_submit_requests(struct drm_i915_gem_request *rq0, struct drm_i915_gem_request *rq1) { - struct intel_engine_cs *ring = rq0->ring; - struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; - struct drm_i915_gem_object *ctx_obj1 = NULL; - execlists_update_context(rq0); - if (rq1) { + if (rq1) execlists_update_context(rq1); - ctx_obj1 = rq1->ctx->engine[ring->id].state; - } - execlists_elsp_write(ring, ctx_obj0, ctx_obj1); + execlists_elsp_write(rq0, rq1); } static void execlists_context_unqueue(struct intel_engine_cs *ring) -- GitLab From 8ee36152cfb087af22680ee394dcde262565fd73 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 3 Jul 2015 17:09:37 +0300 Subject: [PATCH 0464/7006] drm/i915: Convert execlists_ctx_descriptor() for requests Pass around requests to carry context deeper in callchain. Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index a07284adc3179..2c39ce0458b2f 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -261,10 +261,11 @@ u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj) return lrca >> 12; } -static uint64_t execlists_ctx_descriptor(struct intel_engine_cs *ring, - struct drm_i915_gem_object *ctx_obj) +static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_request *rq) { + struct intel_engine_cs *ring = rq->ring; struct drm_device *dev = ring->dev; + struct drm_i915_gem_object *ctx_obj = rq->ctx->engine[ring->id].state; uint64_t desc; uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj); @@ -299,21 +300,18 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0, struct intel_engine_cs *ring = rq0->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_gem_object *ctx_obj0 = rq0->ctx->engine[ring->id].state; - struct drm_i915_gem_object *ctx_obj1 = rq1 ? - rq1->ctx->engine[ring->id].state : NULL; uint64_t temp = 0; uint32_t desc[4]; /* XXX: You must always write both descriptors in the order below. */ - if (ctx_obj1) - temp = execlists_ctx_descriptor(ring, ctx_obj1); + if (rq1) + temp = execlists_ctx_descriptor(rq1); else temp = 0; desc[1] = (u32)(temp >> 32); desc[0] = (u32)temp; - temp = execlists_ctx_descriptor(ring, ctx_obj0); + temp = execlists_ctx_descriptor(rq0); desc[3] = (u32)(temp >> 32); desc[2] = (u32)temp; -- GitLab From 1cff8cc35bd310419cd2545ddcb65b329bdc1053 Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Mon, 6 Jul 2015 11:09:25 +0300 Subject: [PATCH 0465/7006] drm/i915: Mark elsps submitted when they are pushed to hw Now when we have requests this deep on call chain, we can mark the elsp being submitted when it actually is. Remove temp variable and readjust commenting to more closely fit to the code. v2: Avoid tmp variable and reduce number of writes (Chris) Cc: Chris Wilson Signed-off-by: Mika Kuoppala Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 36 +++++++++++++------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 2c39ce0458b2f..4c47a64a974ff 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -300,31 +300,29 @@ static void execlists_elsp_write(struct drm_i915_gem_request *rq0, struct intel_engine_cs *ring = rq0->ring; struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; - uint64_t temp = 0; - uint32_t desc[4]; + uint64_t desc[2]; - /* XXX: You must always write both descriptors in the order below. */ - if (rq1) - temp = execlists_ctx_descriptor(rq1); - else - temp = 0; - desc[1] = (u32)(temp >> 32); - desc[0] = (u32)temp; + if (rq1) { + desc[1] = execlists_ctx_descriptor(rq1); + rq1->elsp_submitted++; + } else { + desc[1] = 0; + } - temp = execlists_ctx_descriptor(rq0); - desc[3] = (u32)(temp >> 32); - desc[2] = (u32)temp; + desc[0] = execlists_ctx_descriptor(rq0); + rq0->elsp_submitted++; + /* You must always write both descriptors in the order below. */ spin_lock(&dev_priv->uncore.lock); intel_uncore_forcewake_get__locked(dev_priv, FORCEWAKE_ALL); - I915_WRITE_FW(RING_ELSP(ring), desc[1]); - I915_WRITE_FW(RING_ELSP(ring), desc[0]); - I915_WRITE_FW(RING_ELSP(ring), desc[3]); + I915_WRITE_FW(RING_ELSP(ring), upper_32_bits(desc[1])); + I915_WRITE_FW(RING_ELSP(ring), lower_32_bits(desc[1])); + I915_WRITE_FW(RING_ELSP(ring), upper_32_bits(desc[0])); /* The context is automatically loaded after the following */ - I915_WRITE_FW(RING_ELSP(ring), desc[2]); + I915_WRITE_FW(RING_ELSP(ring), lower_32_bits(desc[0])); - /* ELSP is a wo register, so use another nearby reg for posting instead */ + /* ELSP is a wo register, use another nearby reg for posting */ POSTING_READ_FW(RING_EXECLIST_STATUS(ring)); intel_uncore_forcewake_put__locked(dev_priv, FORCEWAKE_ALL); spin_unlock(&dev_priv->uncore.lock); @@ -433,10 +431,6 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring) WARN_ON(req1 && req1->elsp_submitted); execlists_submit_requests(req0, req1); - - req0->elsp_submitted++; - if (req1) - req1->elsp_submitted++; } static bool execlists_check_remove_request(struct intel_engine_cs *ring, -- GitLab From c07a2d1194fc694785771643c413c44adf7635d3 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 6 Jul 2015 09:19:24 -0700 Subject: [PATCH 0466/7006] drm/i915: Don't dereference NULL plane while setting up scalers intel_atomic_setup_scalers() dereferences 'plane' before the plane has been assigned. The plane ID assignment doing this dereference is only needed for debugging messages later in the function, so just move the assignment farther down the function to a point where plane will no longer be NULL. This was introduced in: commit 133b0d128be39e308ccd3b3d765c31ebdbf5380e Author: Maarten Lankhorst Date: Mon Jun 15 12:33:39 2015 +0200 drm/i915: Clean up intel_atomic_setup_scalers slightly. Cc: Maarten Lankhorst Cc: Bob Paauwe Reported-by: Bob Paauwe Signed-off-by: Matt Roper Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 0aeced82201e4..5c79a31603af6 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -325,7 +325,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev, scaler_id = &scaler_state->scaler_id; } else { name = "PLANE"; - idx = plane->base.id; if (!drm_state) continue; @@ -359,6 +358,7 @@ int intel_atomic_setup_scalers(struct drm_device *dev, } intel_plane = to_intel_plane(plane); + idx = plane->base.id; /* plane on different crtc cannot be a scaler user of this crtc */ if (WARN_ON(intel_plane->pipe != intel_crtc->pipe)) { -- GitLab From d26a5b6e80c87fd8fd136eb0a334fc7960ac9699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 2 Jul 2015 17:42:46 +0300 Subject: [PATCH 0467/7006] drm/i915: Disable LVDS port after the pipe on PCH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Follow the correct pipe vs port disable sequence for the PCH LVDS ports, ie. disable the port after the pipe. Other PCH port were already converted in the following commits: 1ea56e269e136544c0a76dc831c5edc27c47cb3c drm/i915: Disable CRT port after pipe on PCH platforms 3c65d1d1bb92ea959e8bce3eeae90fe5c3daa58a drm/i915: Disable SDVO port after the pipe on PCH platforms a4790cec3adf5eec91f397b1884706a71c70730f drm/i915: Disable HDMI port after the pipe on PCH platforms 08aff3fe26ae7a0d6f302ac2e1b7e2eb9933cd42 drm/i915: Move DP port disable to post_disable for pch platforms but LVDS was forgotten. Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lvds.c | 36 ++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index ea85547611a56..937e8216e9d65 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -239,8 +239,6 @@ static void intel_disable_lvds(struct intel_encoder *encoder) { struct drm_device *dev = encoder->base.dev; struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); - struct intel_connector *intel_connector = - &lvds_encoder->attached_connector->base; struct drm_i915_private *dev_priv = dev->dev_private; u32 ctl_reg, stat_reg; @@ -252,8 +250,6 @@ static void intel_disable_lvds(struct intel_encoder *encoder) stat_reg = PP_STATUS; } - intel_panel_disable_backlight(intel_connector); - I915_WRITE(ctl_reg, I915_READ(ctl_reg) & ~POWER_TARGET_ON); if (wait_for((I915_READ(stat_reg) & PP_ON) == 0, 1000)) DRM_ERROR("timed out waiting for panel to power off\n"); @@ -262,6 +258,31 @@ static void intel_disable_lvds(struct intel_encoder *encoder) POSTING_READ(lvds_encoder->reg); } +static void gmch_disable_lvds(struct intel_encoder *encoder) +{ + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_connector *intel_connector = + &lvds_encoder->attached_connector->base; + + intel_panel_disable_backlight(intel_connector); + + intel_disable_lvds(encoder); +} + +static void pch_disable_lvds(struct intel_encoder *encoder) +{ + struct intel_lvds_encoder *lvds_encoder = to_lvds_encoder(&encoder->base); + struct intel_connector *intel_connector = + &lvds_encoder->attached_connector->base; + + intel_panel_disable_backlight(intel_connector); +} + +static void pch_post_disable_lvds(struct intel_encoder *encoder) +{ + intel_disable_lvds(encoder); +} + static enum drm_mode_status intel_lvds_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) @@ -992,7 +1013,12 @@ void intel_lvds_init(struct drm_device *dev) intel_encoder->enable = intel_enable_lvds; intel_encoder->pre_enable = intel_pre_enable_lvds; intel_encoder->compute_config = intel_lvds_compute_config; - intel_encoder->disable = intel_disable_lvds; + if (HAS_PCH_SPLIT(dev_priv)) { + intel_encoder->disable = pch_disable_lvds; + intel_encoder->post_disable = pch_post_disable_lvds; + } else { + intel_encoder->disable = gmch_disable_lvds; + } intel_encoder->get_hw_state = intel_lvds_get_hw_state; intel_encoder->get_config = intel_lvds_get_config; intel_connector->get_hw_state = intel_connector_get_hw_state; -- GitLab From efc4720dfbf737903ca4c1366bc45ca780d13412 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 20 Jun 2015 22:47:01 +0200 Subject: [PATCH 0468/7006] ASoC: Add gtm601 codec driver This driver add PCM interface to a GTM601 UMTS modem chip. There is no configuration interface. Signed-off-by: Marek Belisko Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 4 ++ sound/soc/codecs/Makefile | 2 + sound/soc/codecs/gtm601.c | 98 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 sound/soc/codecs/gtm601.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce8ba387..1b7c49214c256 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_BT_SCO select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C + select SND_SOC_GTM601 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -446,6 +447,9 @@ config SND_SOC_ES8328_SPI tristate select SND_SOC_ES8328 +config SND_SOC_GTM601 + tristate 'GTM601 UMTS modem audio codec' + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d972cb36..365529d284651 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-gtm601-objs := gtm601.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -242,6 +243,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c new file mode 100644 index 0000000000000..1b77ff2d6d14c --- /dev/null +++ b/sound/soc/codecs/gtm601.c @@ -0,0 +1,98 @@ +/* + * This is a simple driver for the GTM601 Voice PCM interface + * + * Copyright (C) 2015 Goldelico GmbH + * + * Author: Marek Belisko + * + * Based on wm8727.c driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const struct snd_soc_dapm_widget gtm601_dapm_widgets[] = { + SND_SOC_DAPM_OUTPUT("AOUT"), + SND_SOC_DAPM_INPUT("AIN"), +}; + +static const struct snd_soc_dapm_route gtm601_dapm_routes[] = { + { "AOUT", NULL, "Playback" }, + { "Capture", NULL, "AIN" }, +}; + +struct snd_soc_dai_driver gtm601_dai = { + .name = "gtm601", + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 1, + .rates = SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}; + +static struct snd_soc_codec_driver soc_codec_dev_gtm601 = { + .dapm_widgets = gtm601_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets), + .dapm_routes = gtm601_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(gtm601_dapm_routes), +}; + +static int gtm601_platform_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, + &soc_codec_dev_gtm601, >m601_dai, 1); +} + +static int gtm601_platform_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +MODULE_ALIAS("platform:gtm601_codec_audio"); + +#if defined(CONFIG_OF) +static const struct of_device_id gtm601_codec_of_match[] = { + { .compatible = "option,gtm601", }, + {}, +}; +MODULE_DEVICE_TABLE(of, gtm601_codec_of_match); +#endif + +static struct platform_driver gtm601_codec_driver = { + .driver = { + .name = "gtm601", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(gtm601_codec_of_match), + }, + + .probe = gtm601_platform_probe, + .remove = gtm601_platform_remove, +}; + +module_platform_driver(gtm601_codec_driver); + +MODULE_DESCRIPTION("ASoC gtm601 driver"); +MODULE_AUTHOR("Marek Belisko "); +MODULE_LICENSE("GPL"); -- GitLab From 1fdc5ae80868637926e76a32e8c62cdd093b48f4 Mon Sep 17 00:00:00 2001 From: Marek Belisko Date: Sat, 20 Jun 2015 22:47:02 +0200 Subject: [PATCH 0469/7006] Documentation: vendor-prefixes: Add option prefix Add option to vendor-prefixes file which will be used for Option NV company. Signed-off-by: Marek Belisko Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9ec..d247994a43f29 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -150,6 +150,7 @@ nvidia NVIDIA nxp NXP Semiconductors onnn ON Semiconductor Corp. opencores OpenCores.org +option Option NV ortustech Ortus Technology Co., Ltd. ovti OmniVision Technologies panasonic Panasonic Corporation -- GitLab From 726f783e803cc254b1a8a9a1dc3e5808fee02760 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 22 Jun 2015 23:36:03 +0800 Subject: [PATCH 0470/7006] ASoC: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/gtm601.c:86:4-9: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Marek Belisko Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/gtm601.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 1b77ff2d6d14c..393001c20e1ab 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -83,7 +83,6 @@ MODULE_DEVICE_TABLE(of, gtm601_codec_of_match); static struct platform_driver gtm601_codec_driver = { .driver = { .name = "gtm601", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(gtm601_codec_of_match), }, -- GitLab From beb5f8659ccd89a70b0a3ff28e32dbd8065df818 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Mon, 22 Jun 2015 23:48:25 +0800 Subject: [PATCH 0471/7006] ASoC: gtm601_dai can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/gtm601.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 393001c20e1ab..7004eba4b7528 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -33,7 +33,7 @@ static const struct snd_soc_dapm_route gtm601_dapm_routes[] = { { "Capture", NULL, "AIN" }, }; -struct snd_soc_dai_driver gtm601_dai = { +static struct snd_soc_dai_driver gtm601_dai = { .name = "gtm601", .playback = { .stream_name = "Playback", -- GitLab From d49796317d4968b29ccdee7b9586385ae20b60a3 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 24 Jun 2015 10:55:24 +0800 Subject: [PATCH 0472/7006] ASoC: gtm601: Fix modalias The MODULE_ALIAS needs to match the driver name to make module auto-loading work. Also move MODULE_ALIAS close to other MODULE_* macro. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/gtm601.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 7004eba4b7528..12d15e5b50f0c 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -70,8 +70,6 @@ static int gtm601_platform_remove(struct platform_device *pdev) return 0; } -MODULE_ALIAS("platform:gtm601_codec_audio"); - #if defined(CONFIG_OF) static const struct of_device_id gtm601_codec_of_match[] = { { .compatible = "option,gtm601", }, @@ -95,3 +93,4 @@ module_platform_driver(gtm601_codec_driver); MODULE_DESCRIPTION("ASoC gtm601 driver"); MODULE_AUTHOR("Marek Belisko "); MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:gtm601"); -- GitLab From e608aaefd8f3b868866a2438dbad8e01cb0ce993 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:56 +0300 Subject: [PATCH 0473/7006] ASoC: rt286: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 5c43e263b2c1f..2f39843ebd14c 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1157,7 +1157,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c, } if (val != RT286_VENDOR_ID && val != RT288_VENDOR_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt286\n", val); + "Device with ID register %#x is not rt286\n", val); return -ENODEV; } -- GitLab From 818454d1abcc127eef7e7d1cb169c69f53f7cd6d Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:57 +0300 Subject: [PATCH 0474/7006] ASoC: rt5640: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt5640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e57513d7..0cbdac6530418 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2207,7 +2207,7 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, regmap_read(rt5640->regmap, RT5640_VENDOR_ID2, &val); if (val != RT5640_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5640/39\n", val); + "Device with ID register %#x is not rt5640/39\n", val); return -ENODEV; } -- GitLab From 8f68e80f5f434980ab9bae713bab6a3ff1ac07df Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:58 +0300 Subject: [PATCH 0475/7006] ASoC: rt5645: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc5..a5bc96a0e77c9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3296,7 +3296,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, break; default: dev_err(&i2c->dev, - "Device with ID register %x is not rt5645 or rt5650\n", + "Device with ID register %#x is not rt5645 or rt5650\n", val); return -ENODEV; } -- GitLab From 469444fb134259384f3396833f6f1edde8bae203 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:58:59 +0300 Subject: [PATCH 0476/7006] ASoC: rt5651: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt5651.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e193abcd..96bbb7d12a83a 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1769,7 +1769,7 @@ static int rt5651_i2c_probe(struct i2c_client *i2c, regmap_read(rt5651->regmap, RT5651_DEVICE_ID, &ret); if (ret != RT5651_DEVICE_ID_VALUE) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5651\n", ret); + "Device with ID register %#x is not rt5651\n", ret); return -ENODEV; } -- GitLab From 387ad57fe187b10fb4dec521e8d0ba5cefae7b35 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:59:00 +0300 Subject: [PATCH 0477/7006] ASoC: rt5670: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt5670.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4141787..a791d7e133f20 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2863,7 +2863,7 @@ static int rt5670_i2c_probe(struct i2c_client *i2c, regmap_read(rt5670->regmap, RT5670_VENDOR_ID2, &val); if (val != RT5670_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5670/72\n", val); + "Device with ID register %#x is not rt5670/72\n", val); return -ENODEV; } -- GitLab From aa0bcc5c44437457307c8c22e57a67bb57424041 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 25 Jun 2015 13:59:01 +0300 Subject: [PATCH 0478/7006] ASoC: rt5677: Prefix hexadecimal ID register value with 0x in error print Make it obvious that unexpected value read from ID register is printed in hexadecimal. Signed-off-by: Jarkko Nikula Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969ac11920..9048ba7efee1b 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5209,7 +5209,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, regmap_read(rt5677->regmap, RT5677_VENDOR_ID2, &val); if (val != RT5677_DEVICE_ID) { dev_err(&i2c->dev, - "Device with ID register %x is not rt5677\n", val); + "Device with ID register %#x is not rt5677\n", val); return -ENODEV; } -- GitLab From 93d5fc8bd143d94105279796451dcfd3d657453a Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:52:12 +0800 Subject: [PATCH 0479/7006] ASoC: wm0010: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index 6560a66b3f353..e1da49f393341 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -1003,7 +1003,6 @@ static int wm0010_spi_remove(struct spi_device *spi) static struct spi_driver wm0010_spi_driver = { .driver = { .name = "wm0010", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .probe = wm0010_spi_probe, -- GitLab From 0bc7d10c4abb7cec52d4d88f761476ed04225c83 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Jun 2015 11:41:19 +0800 Subject: [PATCH 0480/7006] ASoC: rt5645: Constify dmi_system_id table dmi_check_system() takes "const struct dmi_system_id *", so make the dmi_system_id table const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a5bc96a0e77c9..a07966bebfef7 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3221,7 +3221,7 @@ static int strago_quirk_cb(const struct dmi_system_id *id) return 1; } -static struct dmi_system_id dmi_platform_intel_braswell[] = { +static const struct dmi_system_id dmi_platform_intel_braswell[] = { { .ident = "Intel Strago", .callback = strago_quirk_cb, -- GitLab From fe052a1810ec4687ee7d606290561af504047707 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 29 Jun 2015 13:08:19 +0300 Subject: [PATCH 0481/7006] target: Use struct t10_pi_tuple Its not a good idea to keep target specific definition of the same t10-pi tuple. (Fix v4.2-rc1 patch fuzz - nab) Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_device.c | 2 +- drivers/target/target_core_sbc.c | 10 +++++----- include/target/target_core_base.h | 7 +------ 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 09e682b1c5495..db7034292053b 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -754,7 +754,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) dev->dev_link_magic = SE_DEV_LINK_MAGIC; dev->se_hba = hba; dev->transport = hba->backend->ops; - dev->prot_length = sizeof(struct se_dif_v1_tuple); + dev->prot_length = sizeof(struct t10_pi_tuple); dev->hba_index = hba->hba_index; INIT_LIST_HEAD(&dev->dev_list); diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index e318ddbe15da0..ac7215039e5a7 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -1191,7 +1191,7 @@ void sbc_dif_generate(struct se_cmd *cmd) { struct se_device *dev = cmd->se_dev; - struct se_dif_v1_tuple *sdt; + struct t10_pi_tuple *sdt; struct scatterlist *dsg = cmd->t_data_sg, *psg; sector_t sector = cmd->t_task_lba; void *daddr, *paddr; @@ -1203,7 +1203,7 @@ sbc_dif_generate(struct se_cmd *cmd) daddr = kmap_atomic(sg_page(dsg)) + dsg->offset; for (j = 0; j < psg->length; - j += sizeof(struct se_dif_v1_tuple)) { + j += sizeof(*sdt)) { __u16 crc; unsigned int avail; @@ -1256,7 +1256,7 @@ sbc_dif_generate(struct se_cmd *cmd) } static sense_reason_t -sbc_dif_v1_verify(struct se_cmd *cmd, struct se_dif_v1_tuple *sdt, +sbc_dif_v1_verify(struct se_cmd *cmd, struct t10_pi_tuple *sdt, __u16 crc, sector_t sector, unsigned int ei_lba) { __be16 csum; @@ -1346,7 +1346,7 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, unsigned int ei_lba, struct scatterlist *psg, int psg_off) { struct se_device *dev = cmd->se_dev; - struct se_dif_v1_tuple *sdt; + struct t10_pi_tuple *sdt; struct scatterlist *dsg = cmd->t_data_sg; sector_t sector = start; void *daddr, *paddr; @@ -1361,7 +1361,7 @@ sbc_dif_verify(struct se_cmd *cmd, sector_t start, unsigned int sectors, for (i = psg_off; i < psg->length && sector < start + sectors; - i += sizeof(struct se_dif_v1_tuple)) { + i += sizeof(*sdt)) { __u16 crc; unsigned int avail; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 17ae2d6a4891e..a6816444d81b3 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -426,12 +427,6 @@ enum target_core_dif_check { TARGET_DIF_CHECK_REFTAG = 0x1 << 2, }; -struct se_dif_v1_tuple { - __be16 guard_tag; - __be16 app_tag; - __be32 ref_tag; -}; - /* for sam_task_attr */ #define TCM_SIMPLE_TAG 0x20 #define TCM_HEAD_TAG 0x21 -- GitLab From f3e0f3da1b65e84ea82176c1cda03a4b694c9911 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 02:35:14 -0400 Subject: [PATCH 0482/7006] ufs: kill more lock_ufs() calls a) move it inside ufs_truncate() b) ufs_free_inode() doesn't need it - it's serialized on ->s_lock c) ufs_write_inode() doesn't need it either (and can be called without it anyway). Signed-off-by: Al Viro --- fs/ufs/inode.c | 13 ++----------- fs/ufs/truncate.c | 4 ++-- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index f913a6924b238..0e4d88e0e709c 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -867,11 +867,7 @@ static int ufs_update_inode(struct inode * inode, int do_sync) int ufs_write_inode(struct inode *inode, struct writeback_control *wbc) { - int ret; - lock_ufs(inode->i_sb); - ret = ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); - unlock_ufs(inode->i_sb); - return ret; + return ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL); } int ufs_sync_inode (struct inode *inode) @@ -890,22 +886,17 @@ void ufs_evict_inode(struct inode * inode) if (want_delete) { loff_t old_i_size; /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ - lock_ufs(inode->i_sb); mark_inode_dirty(inode); ufs_update_inode(inode, IS_SYNC(inode)); old_i_size = inode->i_size; inode->i_size = 0; if (inode->i_blocks && ufs_truncate(inode, old_i_size)) ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n"); - unlock_ufs(inode->i_sb); } invalidate_inode_buffers(inode); clear_inode(inode); - if (want_delete) { - lock_ufs(inode->i_sb); + if (want_delete) ufs_free_inode(inode); - unlock_ufs(inode->i_sb); - } } diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 21154704c1680..90cf3a76c500a 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -457,6 +457,7 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; + lock_ufs(sb); err = ufs_alloc_lastblock(inode); if (err) { @@ -486,6 +487,7 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) ufsi->i_lastfrag = DIRECT_FRAGMENT; mark_inode_dirty(inode); out: + unlock_ufs(sb); UFSD("EXIT: err %d\n", err); return err; } @@ -506,9 +508,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr) /* XXX(truncate): truncate_setsize should be called last */ truncate_setsize(inode, attr->ia_size); - lock_ufs(inode->i_sb); error = ufs_truncate(inode, old_i_size); - unlock_ufs(inode->i_sb); if (error) return error; } -- GitLab From d622f167b8435c856376edec130053fb56bf83e4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:04:16 -0400 Subject: [PATCH 0483/7006] ufs: switch ufs_evict_inode() to trimmed-down variant of ufs_truncate() Signed-off-by: Al Viro --- fs/ufs/inode.c | 9 ++----- fs/ufs/truncate.c | 60 ++++++++++++++++++++++++++++++++--------------- fs/ufs/ufs.h | 2 +- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 0e4d88e0e709c..282b0ced62727 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -884,14 +884,9 @@ void ufs_evict_inode(struct inode * inode) truncate_inode_pages_final(&inode->i_data); if (want_delete) { - loff_t old_i_size; - /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ - mark_inode_dirty(inode); - ufs_update_inode(inode, IS_SYNC(inode)); - old_i_size = inode->i_size; inode->i_size = 0; - if (inode->i_blocks && ufs_truncate(inode, old_i_size)) - ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n"); + if (inode->i_blocks) + ufs_truncate_blocks(inode); } invalidate_inode_buffers(inode); diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 90cf3a76c500a..5a2e7082a0ae6 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -440,12 +440,36 @@ out: return err; } -int ufs_truncate(struct inode *inode, loff_t old_i_size) +static void __ufs_truncate_blocks(struct inode *inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - int retry, err = 0; + int retry; + + while (1) { + retry = ufs_trunc_direct(inode); + retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, + ufs_get_direct_data_ptr(uspi, ufsi, + UFS_IND_BLOCK)); + retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, + ufs_get_direct_data_ptr(uspi, ufsi, + UFS_DIND_BLOCK)); + retry |= ufs_trunc_tindirect (inode); + if (!retry) + break; + if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) + ufs_sync_inode (inode); + yield(); + } + + ufsi->i_lastfrag = DIRECT_FRAGMENT; +} + +int ufs_truncate(struct inode *inode, loff_t old_i_size) +{ + struct super_block *sb = inode->i_sb; + int err = 0; UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", inode->i_ino, (unsigned long long)i_size_read(inode), @@ -467,24 +491,8 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); - while (1) { - retry = ufs_trunc_direct(inode); - retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, - ufs_get_direct_data_ptr(uspi, ufsi, - UFS_IND_BLOCK)); - retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, - ufs_get_direct_data_ptr(uspi, ufsi, - UFS_DIND_BLOCK)); - retry |= ufs_trunc_tindirect (inode); - if (!retry) - break; - if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) - ufs_sync_inode (inode); - yield(); - } - + __ufs_truncate_blocks(inode); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - ufsi->i_lastfrag = DIRECT_FRAGMENT; mark_inode_dirty(inode); out: unlock_ufs(sb); @@ -492,6 +500,20 @@ out: return err; } +void ufs_truncate_blocks(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + + lock_ufs(sb); + __ufs_truncate_blocks(inode); + unlock_ufs(sb); +} + int ufs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = d_inode(dentry); diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 2e31ea2e35a3b..43fcab381de1b 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -141,7 +141,7 @@ extern const struct inode_operations ufs_fast_symlink_inode_operations; extern const struct inode_operations ufs_symlink_inode_operations; /* truncate.c */ -extern int ufs_truncate (struct inode *, loff_t); +extern void ufs_truncate_blocks(struct inode *); extern int ufs_setattr(struct dentry *dentry, struct iattr *attr); static inline struct ufs_sb_info *UFS_SB(struct super_block *sb) -- GitLab From 3b7a3a05e8b006a73c406230b3d2d3da920779d9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:06:40 -0400 Subject: [PATCH 0484/7006] ufs: free excessive blocks upon ->write_begin() failure/short copy Broken in "[PATCH] ufs: truncate should allocate block for last byte"; all way back in 2006. ufs_setattr() hadn't been the only user of vmtruncate() and eliminating ->truncate() method required corrections in a bunch of places. Eventually those places had migrated into ->write_begin() failure exit and ->write_end() after short copy... Signed-off-by: Al Viro --- fs/ufs/inode.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 282b0ced62727..a4fc3adfdc4c8 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -530,8 +530,10 @@ static void ufs_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; - if (to > inode->i_size) + if (to > inode->i_size) { truncate_pagecache(inode, inode->i_size); + ufs_truncate_blocks(inode); + } } static int ufs_write_begin(struct file *file, struct address_space *mapping, @@ -548,6 +550,18 @@ static int ufs_write_begin(struct file *file, struct address_space *mapping, return ret; } +static int ufs_write_end(struct file *file, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata) +{ + int ret; + + ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); + if (ret < len) + ufs_write_failed(mapping, pos + len); + return ret; +} + static sector_t ufs_bmap(struct address_space *mapping, sector_t block) { return generic_block_bmap(mapping,block,ufs_getfrag_block); @@ -557,7 +571,7 @@ const struct address_space_operations ufs_aops = { .readpage = ufs_readpage, .writepage = ufs_writepage, .write_begin = ufs_write_begin, - .write_end = generic_write_end, + .write_end = ufs_write_end, .bmap = ufs_bmap }; -- GitLab From 2401aa29ab5c42cc34853a5c1457fbf66593690f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:15:07 -0400 Subject: [PATCH 0485/7006] ufs: move truncate_setsize() down into ufs_truncate() just prior to __ufs_truncate_blocks(), with matching change of calling conventions Signed-off-by: Al Viro --- fs/ufs/truncate.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 5a2e7082a0ae6..6f56036ff7244 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -370,7 +370,7 @@ static int ufs_trunc_tindirect(struct inode *inode) return retry; } -static int ufs_alloc_lastblock(struct inode *inode) +static int ufs_alloc_lastblock(struct inode *inode, loff_t size) { int err = 0; struct super_block *sb = inode->i_sb; @@ -382,7 +382,7 @@ static int ufs_alloc_lastblock(struct inode *inode) struct buffer_head *bh; u64 phys64; - lastfrag = (i_size_read(inode) + uspi->s_fsize - 1) >> uspi->s_fshift; + lastfrag = (size + uspi->s_fsize - 1) >> uspi->s_fshift; if (!lastfrag) goto out; @@ -466,14 +466,14 @@ static void __ufs_truncate_blocks(struct inode *inode) ufsi->i_lastfrag = DIRECT_FRAGMENT; } -int ufs_truncate(struct inode *inode, loff_t old_i_size) +int ufs_truncate(struct inode *inode, loff_t size) { struct super_block *sb = inode->i_sb; int err = 0; UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", - inode->i_ino, (unsigned long long)i_size_read(inode), - (unsigned long long)old_i_size); + inode->i_ino, (unsigned long long)size, + (unsigned long long)i_size_read(inode)); if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) @@ -482,14 +482,14 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) return -EPERM; lock_ufs(sb); - err = ufs_alloc_lastblock(inode); + err = ufs_alloc_lastblock(inode, size); - if (err) { - i_size_write(inode, old_i_size); + if (err) goto out; - } - block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block); + block_truncate_page(inode->i_mapping, size, ufs_getfrag_block); + + truncate_setsize(inode, size); __ufs_truncate_blocks(inode); inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; @@ -525,12 +525,7 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr) return error; if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { - loff_t old_i_size = inode->i_size; - - /* XXX(truncate): truncate_setsize should be called last */ - truncate_setsize(inode, attr->ia_size); - - error = ufs_truncate(inode, old_i_size); + error = ufs_truncate(inode, attr->ia_size); if (error) return error; } -- GitLab From 493b4537a26b104fb3bd07ff4a46b6ede4288e76 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:17:28 -0400 Subject: [PATCH 0486/7006] ufs: move lock_ufs() down into __ufs_truncate_blocks() Signed-off-by: Al Viro --- fs/ufs/truncate.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 6f56036ff7244..155e13aea80cc 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -447,6 +447,7 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; int retry; + lock_ufs(sb); while (1) { retry = ufs_trunc_direct(inode); retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, @@ -464,11 +465,11 @@ static void __ufs_truncate_blocks(struct inode *inode) } ufsi->i_lastfrag = DIRECT_FRAGMENT; + unlock_ufs(sb); } int ufs_truncate(struct inode *inode, loff_t size) { - struct super_block *sb = inode->i_sb; int err = 0; UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", @@ -481,7 +482,6 @@ int ufs_truncate(struct inode *inode, loff_t size) if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return -EPERM; - lock_ufs(sb); err = ufs_alloc_lastblock(inode, size); if (err) @@ -495,23 +495,18 @@ int ufs_truncate(struct inode *inode, loff_t size) inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); out: - unlock_ufs(sb); UFSD("EXIT: err %d\n", err); return err; } void ufs_truncate_blocks(struct inode *inode) { - struct super_block *sb = inode->i_sb; if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) return; if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) return; - - lock_ufs(sb); __ufs_truncate_blocks(inode); - unlock_ufs(sb); } int ufs_setattr(struct dentry *dentry, struct iattr *attr) -- GitLab From 4af7b2c080715b9452fdaefb7ada72b4dc79593e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Jun 2015 19:26:18 -0400 Subject: [PATCH 0487/7006] ufs: bforget() indirect blocks before freeing them right now it doesn't matter (lock_ufs() serializes everything), but when we switch to per-inode locking, it will be needed. Signed-off-by: Al Viro --- fs/ufs/truncate.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 155e13aea80cc..9908a6045d7ae 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -237,9 +237,9 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) tmp = ufs_data_ptr_to_cpu(sb, p); ufs_data_ptr_clear(uspi, p); + ubh_bforget(ind_ubh); ufs_free_blocks (inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); - ubh_bforget(ind_ubh); ind_ubh = NULL; } if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) @@ -299,9 +299,9 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) tmp = ufs_data_ptr_to_cpu(sb, p); ufs_data_ptr_clear(uspi, p); + ubh_bforget(dind_bh); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); - ubh_bforget(dind_bh); dind_bh = NULL; } if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) @@ -357,9 +357,9 @@ static int ufs_trunc_tindirect(struct inode *inode) tmp = ufs_data_ptr_to_cpu(sb, p); ufs_data_ptr_clear(uspi, p); + ubh_bforget(tind_bh); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); - ubh_bforget(tind_bh); tind_bh = NULL; } if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) -- GitLab From 724bb09fdc06d4ff03757b25d6dba9ef1b133e8f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Jun 2015 12:02:56 -0400 Subject: [PATCH 0488/7006] ufs: don't use lock_ufs() for block pointers tree protection * stores to block pointers are under per-inode seqlock (meta_lock) and mutex (truncate_mutex) * fetches of block pointers are either under truncate_mutex, or wrapped into seqretry loop on meta_lock * all changes of ->i_size are under truncate_mutex and i_mutex * all changes of ->i_lastfrag are under truncate_mutex It's similar to what ext2 is doing; the main difference is that unlike ext2 we can't rely upon the atomicity of stores into block pointers - on UFS2 they are 64bit. So we can't cut the corner when switching a pointer from NULL to non-NULL as we could in ext2_splice_branch() and need to use meta_lock on all modifications. We use seqlock where ext2 uses rwlock; ext2 could probably also benefit from such change... Another non-trivial difference is that with UFS we *cannot* have reader grab truncate_mutex in case of race - it has to keep retrying. That might be possible to change, but not until we lift tail unpacking several levels up in call chain. After that commit we do *NOT* hold fs-wide serialization on accesses to block pointers anymore. Moreover, lock_ufs() can become a normal mutex now - it's only used on statfs, remount and sync_fs and none of those uses are recursive. As the matter of fact, *now* it can be collapsed with ->s_lock, and be eventually replaced with saner per-cylinder-group spinlocks, but that's a separate story. Signed-off-by: Al Viro --- fs/ufs/balloc.c | 4 ++ fs/ufs/inode.c | 138 +++++++++++++++++++++++++++++++--------------- fs/ufs/super.c | 2 + fs/ufs/truncate.c | 22 +++++++- fs/ufs/ufs.h | 2 + 5 files changed, 121 insertions(+), 47 deletions(-) diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index a7106eda50241..fb8b54eb77c5d 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -417,7 +417,9 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, if (oldcount == 0) { result = ufs_alloc_fragments (inode, cgno, goal, count, err); if (result) { + write_seqlock(&UFS_I(inode)->meta_lock); ufs_cpu_to_data_ptr(sb, p, result); + write_sequnlock(&UFS_I(inode)->meta_lock); *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); @@ -473,7 +475,9 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, ufs_change_blocknr(inode, fragment - oldcount, oldcount, uspi->s_sbbase + tmp, uspi->s_sbbase + result, locked_page); + write_seqlock(&UFS_I(inode)->meta_lock); ufs_cpu_to_data_ptr(sb, p, result); + write_sequnlock(&UFS_I(inode)->meta_lock); *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index a4fc3adfdc4c8..100f93c6b309b 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -41,8 +41,6 @@ #include "swab.h" #include "util.h" -static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock); - static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4]) { struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; @@ -75,12 +73,53 @@ static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t off return n; } +typedef struct { + void *p; + union { + __fs32 key32; + __fs64 key64; + }; + struct buffer_head *bh; +} Indirect; + +static inline int grow_chain32(struct ufs_inode_info *ufsi, + struct buffer_head *bh, __fs32 *v, + Indirect *from, Indirect *to) +{ + Indirect *p; + unsigned seq; + to->bh = bh; + do { + seq = read_seqbegin(&ufsi->meta_lock); + to->key32 = *(__fs32 *)(to->p = v); + for (p = from; p <= to && p->key32 == *(__fs32 *)p->p; p++) + ; + } while (read_seqretry(&ufsi->meta_lock, seq)); + return (p > to); +} + +static inline int grow_chain64(struct ufs_inode_info *ufsi, + struct buffer_head *bh, __fs64 *v, + Indirect *from, Indirect *to) +{ + Indirect *p; + unsigned seq; + to->bh = bh; + do { + seq = read_seqbegin(&ufsi->meta_lock); + to->key64 = *(__fs64 *)(to->p = v); + for (p = from; p <= to && p->key64 == *(__fs64 *)p->p; p++) + ; + } while (read_seqretry(&ufsi->meta_lock, seq)); + return (p > to); +} + /* * Returns the location of the fragment from * the beginning of the filesystem. */ -static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock) +static u64 ufs_frag_map(struct inode *inode, sector_t frag) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; @@ -88,12 +127,10 @@ static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock) u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; int shift = uspi->s_apbshift-uspi->s_fpbshift; sector_t offsets[4], *p; + Indirect chain[4], *q = chain; int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets); - u64 ret = 0L; - __fs32 block; - __fs64 u2_block = 0L; unsigned flags = UFS_SB(sb)->s_flags; - u64 temp = 0L; + u64 res = 0; UFSD(": frag = %llu depth = %d\n", (unsigned long long)frag, depth); UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", @@ -101,59 +138,73 @@ static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock) (unsigned long long)mask); if (depth == 0) - return 0; + goto no_block; +again: p = offsets; - if (needs_lock) - lock_ufs(sb); if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) goto ufs2; - block = ufsi->i_u1.i_data[*p++]; - if (!block) - goto out; + if (!grow_chain32(ufsi, NULL, &ufsi->i_u1.i_data[*p++], chain, q)) + goto changed; + if (!q->key32) + goto no_block; while (--depth) { + __fs32 *ptr; struct buffer_head *bh; sector_t n = *p++; - bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift)); + bh = sb_bread(sb, uspi->s_sbbase + + fs32_to_cpu(sb, q->key32) + (n>>shift)); if (!bh) - goto out; - block = ((__fs32 *) bh->b_data)[n & mask]; - brelse (bh); - if (!block) - goto out; + goto no_block; + ptr = (__fs32 *)bh->b_data + (n & mask); + if (!grow_chain32(ufsi, bh, ptr, chain, ++q)) + goto changed; + if (!q->key32) + goto no_block; } - ret = (u64) (uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask)); - goto out; -ufs2: - u2_block = ufsi->i_u1.u2_i_data[*p++]; - if (!u2_block) - goto out; + res = fs32_to_cpu(sb, q->key32); + goto found; +ufs2: + if (!grow_chain64(ufsi, NULL, &ufsi->i_u1.u2_i_data[*p++], chain, q)) + goto changed; + if (!q->key64) + goto no_block; while (--depth) { + __fs64 *ptr; struct buffer_head *bh; sector_t n = *p++; - - temp = (u64)(uspi->s_sbbase) + fs64_to_cpu(sb, u2_block); - bh = sb_bread(sb, temp +(u64) (n>>shift)); + bh = sb_bread(sb, uspi->s_sbbase + + fs64_to_cpu(sb, q->key64) + (n>>shift)); if (!bh) - goto out; - u2_block = ((__fs64 *)bh->b_data)[n & mask]; - brelse(bh); - if (!u2_block) - goto out; + goto no_block; + ptr = (__fs64 *)bh->b_data + (n & mask); + if (!grow_chain64(ufsi, bh, ptr, chain, ++q)) + goto changed; + if (!q->key64) + goto no_block; + } + res = fs64_to_cpu(sb, q->key64); +found: + res += uspi->s_sbbase + (frag & uspi->s_fpbmask); +no_block: + while (q > chain) { + brelse(q->bh); + q--; } - temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block); - ret = temp + (u64) (frag & uspi->s_fpbmask); + return res; -out: - if (needs_lock) - unlock_ufs(sb); - return ret; +changed: + while (q > chain) { + brelse(q->bh); + q--; + } + goto again; } /** @@ -421,10 +472,9 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head int ret, err, new; unsigned long ptr,phys; u64 phys64 = 0; - bool needs_lock = (sbi->mutex_owner != current); if (!create) { - phys64 = ufs_frag_map(inode, fragment, needs_lock); + phys64 = ufs_frag_map(inode, fragment); UFSD("phys64 = %llu\n", (unsigned long long)phys64); if (phys64) map_bh(bh_result, sb, phys64); @@ -438,8 +488,7 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head ret = 0; bh = NULL; - if (needs_lock) - lock_ufs(sb); + mutex_lock(&UFS_I(inode)->truncate_mutex); UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); if (fragment > @@ -501,8 +550,7 @@ out: set_buffer_new(bh_result); map_bh(bh_result, sb, phys); abort: - if (needs_lock) - unlock_ufs(sb); + mutex_unlock(&UFS_I(inode)->truncate_mutex); return err; diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 250579a80d90b..15cd3338340c5 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1429,6 +1429,8 @@ static struct inode *ufs_alloc_inode(struct super_block *sb) return NULL; ei->vfs_inode.i_version = 1; + seqlock_init(&ei->meta_lock); + mutex_init(&ei->truncate_mutex); return &ei->vfs_inode; } diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 9908a6045d7ae..ad34b7f4b4997 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -128,7 +128,9 @@ next1: tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) continue; + write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); if (free_count == 0) { frag_to_free = tmp; @@ -157,7 +159,9 @@ next1: if (!tmp ) ufs_panic(sb, "ufs_truncate_direct", "internal error"); frag4 = ufs_fragnum (frag4); + write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); ufs_free_fragments (inode, tmp, frag4); mark_inode_dirty(inode); @@ -199,7 +203,9 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) return 1; } if (!ind_ubh) { + write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); return 0; } @@ -210,7 +216,9 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) if (!tmp) continue; + write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, ind); + write_sequnlock(&UFS_I(inode)->meta_lock); ubh_mark_buffer_dirty(ind_ubh); if (free_count == 0) { frag_to_free = tmp; @@ -235,7 +243,9 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) break; if (i >= uspi->s_apb) { tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); ubh_bforget(ind_ubh); ufs_free_blocks (inode, tmp, uspi->s_fpb); @@ -278,7 +288,9 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) return 1; } if (!dind_bh) { + write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); return 0; } @@ -297,7 +309,9 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) break; if (i >= uspi->s_apb) { tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); ubh_bforget(dind_bh); ufs_free_blocks(inode, tmp, uspi->s_fpb); @@ -339,7 +353,9 @@ static int ufs_trunc_tindirect(struct inode *inode) return 1; } if (!tind_bh) { + write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); return 0; } @@ -355,7 +371,9 @@ static int ufs_trunc_tindirect(struct inode *inode) break; if (i >= uspi->s_apb) { tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); ubh_bforget(tind_bh); ufs_free_blocks(inode, tmp, uspi->s_fpb); @@ -447,7 +465,7 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; int retry; - lock_ufs(sb); + mutex_lock(&ufsi->truncate_mutex); while (1) { retry = ufs_trunc_direct(inode); retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, @@ -465,7 +483,7 @@ static void __ufs_truncate_blocks(struct inode *inode) } ufsi->i_lastfrag = DIRECT_FRAGMENT; - unlock_ufs(sb); + mutex_unlock(&ufsi->truncate_mutex); } int ufs_truncate(struct inode *inode, loff_t size) diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 43fcab381de1b..ea28b73a8b745 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -46,6 +46,8 @@ struct ufs_inode_info { __u32 i_oeftflag; __u16 i_osync; __u64 i_lastfrag; + seqlock_t meta_lock; + struct mutex truncate_mutex; __u32 i_dir_start_lookup; struct inode vfs_inode; }; -- GitLab From dff7cfd36e305488421d82a0ed3dd0209c333745 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 04:27:05 -0400 Subject: [PATCH 0489/7006] ufs: kill lock_ufs() There were 3 remaining users; in two of them we took ->s_lock immediately after lock_ufs() and held it until just before unlock_ufs(); the third one (statfs) could not be called from itself or from other two (remount and sync_fs). Just use ->s_lock in statfs and don't bother with lock_ufs at all. Signed-off-by: Al Viro --- fs/ufs/super.c | 34 ++-------------------------------- fs/ufs/ufs.h | 5 ----- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 15cd3338340c5..f6390eec02cab 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -94,22 +94,6 @@ #include "swab.h" #include "util.h" -void lock_ufs(struct super_block *sb) -{ - struct ufs_sb_info *sbi = UFS_SB(sb); - - mutex_lock(&sbi->mutex); - sbi->mutex_owner = current; -} - -void unlock_ufs(struct super_block *sb) -{ - struct ufs_sb_info *sbi = UFS_SB(sb); - - sbi->mutex_owner = NULL; - mutex_unlock(&sbi->mutex); -} - static struct inode *ufs_nfs_get_inode(struct super_block *sb, u64 ino, u32 generation) { struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -694,7 +678,6 @@ static int ufs_sync_fs(struct super_block *sb, int wait) struct ufs_super_block_third * usb3; unsigned flags; - lock_ufs(sb); mutex_lock(&UFS_SB(sb)->s_lock); UFSD("ENTER\n"); @@ -714,7 +697,6 @@ static int ufs_sync_fs(struct super_block *sb, int wait) UFSD("EXIT\n"); mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return 0; } @@ -758,7 +740,6 @@ static void ufs_put_super(struct super_block *sb) ubh_brelse_uspi (sbi->s_uspi); kfree (sbi->s_uspi); - mutex_destroy(&sbi->mutex); kfree (sbi); sb->s_fs_info = NULL; UFSD("EXIT\n"); @@ -801,7 +782,6 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) UFSD("flag %u\n", (int)(sb->s_flags & MS_RDONLY)); - mutex_init(&sbi->mutex); mutex_init(&sbi->s_lock); spin_lock_init(&sbi->work_lock); INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs); @@ -1257,7 +1237,6 @@ magic_found: return 0; failed: - mutex_destroy(&sbi->mutex); if (ubh) ubh_brelse_uspi (uspi); kfree (uspi); @@ -1280,7 +1259,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) unsigned flags; sync_filesystem(sb); - lock_ufs(sb); mutex_lock(&UFS_SB(sb)->s_lock); uspi = UFS_SB(sb)->s_uspi; flags = UFS_SB(sb)->s_flags; @@ -1296,7 +1274,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) ufs_set_opt (new_mount_opt, ONERROR_LOCK); if (!ufs_parse_options (data, &new_mount_opt)) { mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return -EINVAL; } if (!(new_mount_opt & UFS_MOUNT_UFSTYPE)) { @@ -1304,14 +1281,12 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) } else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) { pr_err("ufstype can't be changed during remount\n"); mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return -EINVAL; } if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { UFS_SB(sb)->s_mount_opt = new_mount_opt; mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return 0; } @@ -1335,7 +1310,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) #ifndef CONFIG_UFS_FS_WRITE pr_err("ufs was compiled with read-only support, can't be mounted as read-write\n"); mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return -EINVAL; #else if (ufstype != UFS_MOUNT_UFSTYPE_SUN && @@ -1345,13 +1319,11 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) ufstype != UFS_MOUNT_UFSTYPE_UFS2) { pr_err("this ufstype is read-only supported\n"); mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return -EINVAL; } if (!ufs_read_cylinder_structures(sb)) { pr_err("failed during remounting\n"); mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return -EPERM; } sb->s_flags &= ~MS_RDONLY; @@ -1359,7 +1331,6 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) } UFS_SB(sb)->s_mount_opt = new_mount_opt; mutex_unlock(&UFS_SB(sb)->s_lock); - unlock_ufs(sb); return 0; } @@ -1391,8 +1362,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) struct ufs_super_block_third *usb3; u64 id = huge_encode_dev(sb->s_bdev->bd_dev); - lock_ufs(sb); - + mutex_lock(&UFS_SB(sb)->s_lock); usb3 = ubh_get_usb_third(uspi); if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { @@ -1413,7 +1383,7 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf) buf->f_fsid.val[0] = (u32)id; buf->f_fsid.val[1] = (u32)(id >> 32); - unlock_ufs(sb); + mutex_unlock(&UFS_SB(sb)->s_lock); return 0; } diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index ea28b73a8b745..478f35b493a62 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -24,8 +24,6 @@ struct ufs_sb_info { unsigned s_cgno[UFS_MAX_GROUP_LOADED]; unsigned short s_cg_loaded; unsigned s_mount_opt; - struct mutex mutex; - struct task_struct *mutex_owner; struct super_block *sb; int work_queued; /* non-zero if the delayed work is queued */ struct delayed_work sync_work; /* FS sync delayed work */ @@ -172,7 +170,4 @@ static inline u32 ufs_dtogd(struct ufs_sb_private_info * uspi, u64 b) return do_div(b, uspi->s_fpg); } -extern void lock_ufs(struct super_block *sb); -extern void unlock_ufs(struct super_block *sb); - #endif /* _UFS_UFS_H */ -- GitLab From 6a799d3514217d217b4e74a1ee4f016428582dc5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:43:08 -0400 Subject: [PATCH 0490/7006] ufs: ufs_trunc_direct() always returns 0 make it return void Signed-off-by: Al Viro --- fs/ufs/truncate.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index ad34b7f4b4997..c56f4ef1cb7a1 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -63,7 +63,7 @@ #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) -static int ufs_trunc_direct(struct inode *inode) +static void ufs_trunc_direct(struct inode *inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block * sb; @@ -72,7 +72,6 @@ static int ufs_trunc_direct(struct inode *inode) u64 frag1, frag2, frag3, frag4, block1, block2; unsigned frag_to_free, free_count; unsigned i, tmp; - int retry; UFSD("ENTER: ino %lu\n", inode->i_ino); @@ -81,7 +80,6 @@ static int ufs_trunc_direct(struct inode *inode) frag_to_free = 0; free_count = 0; - retry = 0; frag1 = DIRECT_FRAGMENT; frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); @@ -168,7 +166,6 @@ next1: next3: UFSD("EXIT: ino %lu\n", inode->i_ino); - return retry; } @@ -467,8 +464,8 @@ static void __ufs_truncate_blocks(struct inode *inode) mutex_lock(&ufsi->truncate_mutex); while (1) { - retry = ufs_trunc_direct(inode); - retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, + ufs_trunc_direct(inode); + retry = ufs_trunc_indirect(inode, UFS_IND_BLOCK, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, -- GitLab From 687857930d9294100a4636e45b78a244e6ba4125 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:45:21 -0400 Subject: [PATCH 0491/7006] ufs: ufs_trunc_...() has exclusion with everything that might cause allocations Currently - on lock_ufs(), eventually - on per-inode mutex. lock_ufs() used to be mere BKL, which is much weaker, so it needed those rechecks. BKL doesn't provide any exclusion once we lose CPU; its blind replacement, OTOH, _does_. Making that per-filesystem was an atrocity, but at least we can simplify life here. And yes, we certainly need to make that sucker per-inode - these days inode.c and truncate.c uses are needed only to protect the block pointers. Signed-off-by: Al Viro --- fs/ufs/truncate.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index c56f4ef1cb7a1..3beaa848e30a8 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -195,10 +195,6 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) if (!tmp) return 0; ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); - if (tmp != ufs_data_ptr_to_cpu(sb, p)) { - ubh_brelse (ind_ubh); - return 1; - } if (!ind_ubh) { write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); @@ -280,10 +276,6 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) if (!tmp) return 0; dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); - if (tmp != ufs_data_ptr_to_cpu(sb, p)) { - ubh_brelse (dind_bh); - return 1; - } if (!dind_bh) { write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); @@ -345,10 +337,6 @@ static int ufs_trunc_tindirect(struct inode *inode) if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) return 0; tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); - if (tmp != ufs_data_ptr_to_cpu(sb, p)) { - ubh_brelse (tind_bh); - return 1; - } if (!tind_bh) { write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); -- GitLab From 0d23cf7616253b7960edeae720b9f5dfdccee445 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 16 Jun 2015 18:52:28 -0400 Subject: [PATCH 0492/7006] ufs: no retries are needed on truncate Signed-off-by: Al Viro --- fs/ufs/truncate.c | 57 ++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 40 deletions(-) diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 3beaa848e30a8..f84dd3078929d 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -169,7 +169,7 @@ next1: } -static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) +static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; @@ -177,7 +177,6 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) void *ind; u64 tmp, indirect_block, i, frag_to_free; unsigned free_count; - int retry; UFSD("ENTER: ino %lu, offset %llu, p: %p\n", inode->i_ino, (unsigned long long)offset, p); @@ -189,17 +188,16 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) frag_to_free = 0; free_count = 0; - retry = 0; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) - return 0; + return; ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); if (!ind_ubh) { write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); write_sequnlock(&UFS_I(inode)->meta_lock); - return 0; + return; } indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; @@ -250,18 +248,15 @@ static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) ubh_brelse (ind_ubh); UFSD("EXIT: ino %lu\n", inode->i_ino); - - return retry; } -static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) +static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head *dind_bh; u64 i, tmp, dindirect_block; void *dind; - int retry = 0; UFSD("ENTER: ino %lu\n", inode->i_ino); @@ -270,17 +265,16 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) dindirect_block = (DIRECT_BLOCK > offset) ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; - retry = 0; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) - return 0; + return; dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); if (!dind_bh) { write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); write_sequnlock(&UFS_I(inode)->meta_lock); - return 0; + return; } for (i = dindirect_block ; i < uspi->s_apb ; i++) { @@ -288,7 +282,7 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) tmp = ufs_data_ptr_to_cpu(sb, dind); if (!tmp) continue; - retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); + ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); ubh_mark_buffer_dirty(dind_bh); } @@ -312,11 +306,9 @@ static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) ubh_brelse (dind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); - - return retry; } -static int ufs_trunc_tindirect(struct inode *inode) +static void ufs_trunc_tindirect(struct inode *inode) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -324,29 +316,26 @@ static int ufs_trunc_tindirect(struct inode *inode) struct ufs_buffer_head * tind_bh; u64 tindirect_block, tmp, i; void *tind, *p; - int retry; UFSD("ENTER: ino %lu\n", inode->i_ino); - retry = 0; - tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) - return 0; + return; tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); if (!tind_bh) { write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); write_sequnlock(&ufsi->meta_lock); - return 0; + return; } for (i = tindirect_block ; i < uspi->s_apb ; i++) { tind = ubh_get_data_ptr(uspi, tind_bh, i); - retry |= ufs_trunc_dindirect(inode, UFS_NDADDR + + ufs_trunc_dindirect(inode, UFS_NDADDR + uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); ubh_mark_buffer_dirty(tind_bh); } @@ -370,7 +359,6 @@ static int ufs_trunc_tindirect(struct inode *inode) ubh_brelse (tind_bh); UFSD("EXIT: ino %lu\n", inode->i_ino); - return retry; } static int ufs_alloc_lastblock(struct inode *inode, loff_t size) @@ -448,25 +436,14 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - int retry; mutex_lock(&ufsi->truncate_mutex); - while (1) { - ufs_trunc_direct(inode); - retry = ufs_trunc_indirect(inode, UFS_IND_BLOCK, - ufs_get_direct_data_ptr(uspi, ufsi, - UFS_IND_BLOCK)); - retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, - ufs_get_direct_data_ptr(uspi, ufsi, - UFS_DIND_BLOCK)); - retry |= ufs_trunc_tindirect (inode); - if (!retry) - break; - if (IS_SYNC(inode) && (inode->i_state & I_DIRTY)) - ufs_sync_inode (inode); - yield(); - } - + ufs_trunc_direct(inode); + ufs_trunc_indirect(inode, UFS_IND_BLOCK, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); + ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); + ufs_trunc_tindirect(inode); ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); } -- GitLab From 010d331fc315c96607aa6ecdfebb9fcdd349fc9b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Jun 2015 12:44:14 -0400 Subject: [PATCH 0493/7006] ufs: move truncate code into inode.c It is closely tied to block pointers handling there, can benefit from existing helpers, etc. - no point keeping them apart. Trimmed the trailing whitespaces in inode.c at the same time. Signed-off-by: Al Viro --- fs/ufs/Makefile | 2 +- fs/ufs/inode.c | 480 ++++++++++++++++++++++++++++++++++++++++-- fs/ufs/truncate.c | 515 ---------------------------------------------- fs/ufs/ufs.h | 6 +- 4 files changed, 470 insertions(+), 533 deletions(-) delete mode 100644 fs/ufs/truncate.c diff --git a/fs/ufs/Makefile b/fs/ufs/Makefile index 4d0e02b022b30..392db25c0b567 100644 --- a/fs/ufs/Makefile +++ b/fs/ufs/Makefile @@ -5,5 +5,5 @@ obj-$(CONFIG_UFS_FS) += ufs.o ufs-objs := balloc.o cylinder.o dir.o file.o ialloc.o inode.o \ - namei.o super.o symlink.o truncate.o util.o + namei.o super.o symlink.o util.o ccflags-$(CONFIG_UFS_DEBUG) += -DDEBUG diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 100f93c6b309b..ec758edbda478 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -126,7 +126,7 @@ static u64 ufs_frag_map(struct inode *inode, sector_t frag) struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; int shift = uspi->s_apbshift-uspi->s_fpbshift; - sector_t offsets[4], *p; + unsigned offsets[4], *p; Indirect chain[4], *q = chain; int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets); unsigned flags = UFS_SB(sb)->s_flags; @@ -290,14 +290,14 @@ repeat: return NULL; } lastfrag = ufsi->i_lastfrag; - + } tmp = ufs_data_ptr_to_cpu(sb, ufs_get_direct_data_ptr(uspi, ufsi, lastblock)); if (tmp) goal = tmp + uspi->s_fpb; - tmp = ufs_new_fragments (inode, p, fragment - blockoff, + tmp = ufs_new_fragments (inode, p, fragment - blockoff, goal, required + blockoff, err, phys != NULL ? locked_page : NULL); @@ -436,7 +436,7 @@ repeat: if (ufs_data_ptr_to_cpu(sb, p)) goto repeat; goto out; - } + } if (!phys) { @@ -463,7 +463,7 @@ out: * readpage, writepage and so on */ -int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) +static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) { struct super_block * sb = inode->i_sb; struct ufs_sb_info * sbi = UFS_SB(sb); @@ -472,7 +472,7 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head int ret, err, new; unsigned long ptr,phys; u64 phys64 = 0; - + if (!create) { phys64 = ufs_frag_map(inode, fragment); UFSD("phys64 = %llu\n", (unsigned long long)phys64); @@ -498,7 +498,7 @@ int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head err = 0; ptr = fragment; - + /* * ok, these macros clean the logic up a bit and make * it much more readable: @@ -574,6 +574,8 @@ int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) return __block_write_begin(page, pos, len, ufs_getfrag_block); } +static void ufs_truncate_blocks(struct inode *); + static void ufs_write_failed(struct address_space *mapping, loff_t to) { struct inode *inode = mapping->host; @@ -661,7 +663,7 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino); return -1; } - + /* * Linux now has 32-bit uid and gid, so we can support EFT. */ @@ -681,7 +683,7 @@ static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); - + if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) { memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr, sizeof(ufs_inode->ui_u2.ui_addr)); @@ -815,7 +817,7 @@ static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) ufs_set_inode_uid(sb, ufs_inode, i_uid_read(inode)); ufs_set_inode_gid(sb, ufs_inode, i_gid_read(inode)); - + ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); ufs_inode->ui_atime.tv_usec = 0; @@ -917,12 +919,12 @@ static int ufs_update_inode(struct inode * inode, int do_sync) ufs1_update_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); } - + mark_buffer_dirty(bh); if (do_sync) sync_dirty_buffer(bh); brelse (bh); - + UFSD("EXIT\n"); return 0; } @@ -957,3 +959,457 @@ void ufs_evict_inode(struct inode * inode) if (want_delete) ufs_free_inode(inode); } + +#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift) +#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) + +static void ufs_trunc_direct(struct inode *inode) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block * sb; + struct ufs_sb_private_info * uspi; + void *p; + u64 frag1, frag2, frag3, frag4, block1, block2; + unsigned frag_to_free, free_count; + unsigned i, tmp; + + UFSD("ENTER: ino %lu\n", inode->i_ino); + + sb = inode->i_sb; + uspi = UFS_SB(sb)->s_uspi; + + frag_to_free = 0; + free_count = 0; + + frag1 = DIRECT_FRAGMENT; + frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); + frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); + frag3 = frag4 & ~uspi->s_fpbmask; + block1 = block2 = 0; + if (frag2 > frag3) { + frag2 = frag4; + frag3 = frag4 = 0; + } else if (frag2 < frag3) { + block1 = ufs_fragstoblks (frag2); + block2 = ufs_fragstoblks (frag3); + } + + UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," + " frag3 %llu, frag4 %llu\n", inode->i_ino, + (unsigned long long)frag1, (unsigned long long)frag2, + (unsigned long long)block1, (unsigned long long)block2, + (unsigned long long)frag3, (unsigned long long)frag4); + + if (frag1 >= frag2) + goto next1; + + /* + * Free first free fragments + */ + p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); + tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp ) + ufs_panic (sb, "ufs_trunc_direct", "internal error"); + frag2 -= frag1; + frag1 = ufs_fragnum (frag1); + + ufs_free_fragments(inode, tmp + frag1, frag2); + mark_inode_dirty(inode); + frag_to_free = tmp + frag1; + +next1: + /* + * Free whole blocks + */ + for (i = block1 ; i < block2; i++) { + p = ufs_get_direct_data_ptr(uspi, ufsi, i); + tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + continue; + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + + if (free_count == 0) { + frag_to_free = tmp; + free_count = uspi->s_fpb; + } else if (free_count > 0 && frag_to_free == tmp - free_count) + free_count += uspi->s_fpb; + else { + ufs_free_blocks (inode, frag_to_free, free_count); + frag_to_free = tmp; + free_count = uspi->s_fpb; + } + mark_inode_dirty(inode); + } + + if (free_count > 0) + ufs_free_blocks (inode, frag_to_free, free_count); + + if (frag3 >= frag4) + goto next3; + + /* + * Free last free fragments + */ + p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); + tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp ) + ufs_panic(sb, "ufs_truncate_direct", "internal error"); + frag4 = ufs_fragnum (frag4); + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + + ufs_free_fragments (inode, tmp, frag4); + mark_inode_dirty(inode); + next3: + + UFSD("EXIT: ino %lu\n", inode->i_ino); +} + + +static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_buffer_head * ind_ubh; + void *ind; + u64 tmp, indirect_block, i, frag_to_free; + unsigned free_count; + + UFSD("ENTER: ino %lu, offset %llu, p: %p\n", + inode->i_ino, (unsigned long long)offset, p); + + BUG_ON(!p); + + sb = inode->i_sb; + uspi = UFS_SB(sb)->s_uspi; + + frag_to_free = 0; + free_count = 0; + + tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + return; + ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); + if (!ind_ubh) { + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + return; + } + + indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; + for (i = indirect_block; i < uspi->s_apb; i++) { + ind = ubh_get_data_ptr(uspi, ind_ubh, i); + tmp = ufs_data_ptr_to_cpu(sb, ind); + if (!tmp) + continue; + + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, ind); + write_sequnlock(&UFS_I(inode)->meta_lock); + ubh_mark_buffer_dirty(ind_ubh); + if (free_count == 0) { + frag_to_free = tmp; + free_count = uspi->s_fpb; + } else if (free_count > 0 && frag_to_free == tmp - free_count) + free_count += uspi->s_fpb; + else { + ufs_free_blocks (inode, frag_to_free, free_count); + frag_to_free = tmp; + free_count = uspi->s_fpb; + } + + mark_inode_dirty(inode); + } + + if (free_count > 0) { + ufs_free_blocks (inode, frag_to_free, free_count); + } + for (i = 0; i < uspi->s_apb; i++) + if (!ufs_is_data_ptr_zero(uspi, + ubh_get_data_ptr(uspi, ind_ubh, i))) + break; + if (i >= uspi->s_apb) { + tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + + ubh_bforget(ind_ubh); + ufs_free_blocks (inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + ind_ubh = NULL; + } + if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) + ubh_sync_block(ind_ubh); + ubh_brelse (ind_ubh); + + UFSD("EXIT: ino %lu\n", inode->i_ino); +} + +static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) +{ + struct super_block * sb; + struct ufs_sb_private_info * uspi; + struct ufs_buffer_head *dind_bh; + u64 i, tmp, dindirect_block; + void *dind; + + UFSD("ENTER: ino %lu\n", inode->i_ino); + + sb = inode->i_sb; + uspi = UFS_SB(sb)->s_uspi; + + dindirect_block = (DIRECT_BLOCK > offset) + ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; + + tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + return; + dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); + if (!dind_bh) { + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + return; + } + + for (i = dindirect_block ; i < uspi->s_apb ; i++) { + dind = ubh_get_data_ptr(uspi, dind_bh, i); + tmp = ufs_data_ptr_to_cpu(sb, dind); + if (!tmp) + continue; + ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); + ubh_mark_buffer_dirty(dind_bh); + } + + for (i = 0; i < uspi->s_apb; i++) + if (!ufs_is_data_ptr_zero(uspi, + ubh_get_data_ptr(uspi, dind_bh, i))) + break; + if (i >= uspi->s_apb) { + tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + + ubh_bforget(dind_bh); + ufs_free_blocks(inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + dind_bh = NULL; + } + if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) + ubh_sync_block(dind_bh); + ubh_brelse (dind_bh); + + UFSD("EXIT: ino %lu\n", inode->i_ino); +} + +static void ufs_trunc_tindirect(struct inode *inode) +{ + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + struct ufs_inode_info *ufsi = UFS_I(inode); + struct ufs_buffer_head * tind_bh; + u64 tindirect_block, tmp, i; + void *tind, *p; + + UFSD("ENTER: ino %lu\n", inode->i_ino); + + tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) + ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; + + p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); + if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) + return; + tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); + if (!tind_bh) { + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + return; + } + + for (i = tindirect_block ; i < uspi->s_apb ; i++) { + tind = ubh_get_data_ptr(uspi, tind_bh, i); + ufs_trunc_dindirect(inode, UFS_NDADDR + + uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); + ubh_mark_buffer_dirty(tind_bh); + } + for (i = 0; i < uspi->s_apb; i++) + if (!ufs_is_data_ptr_zero(uspi, + ubh_get_data_ptr(uspi, tind_bh, i))) + break; + if (i >= uspi->s_apb) { + tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + + ubh_bforget(tind_bh); + ufs_free_blocks(inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + tind_bh = NULL; + } + if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) + ubh_sync_block(tind_bh); + ubh_brelse (tind_bh); + + UFSD("EXIT: ino %lu\n", inode->i_ino); +} + +static int ufs_alloc_lastblock(struct inode *inode, loff_t size) +{ + int err = 0; + struct super_block *sb = inode->i_sb; + struct address_space *mapping = inode->i_mapping; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + unsigned i, end; + sector_t lastfrag; + struct page *lastpage; + struct buffer_head *bh; + u64 phys64; + + lastfrag = (size + uspi->s_fsize - 1) >> uspi->s_fshift; + + if (!lastfrag) + goto out; + + lastfrag--; + + lastpage = ufs_get_locked_page(mapping, lastfrag >> + (PAGE_CACHE_SHIFT - inode->i_blkbits)); + if (IS_ERR(lastpage)) { + err = -EIO; + goto out; + } + + end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); + bh = page_buffers(lastpage); + for (i = 0; i < end; ++i) + bh = bh->b_this_page; + + + err = ufs_getfrag_block(inode, lastfrag, bh, 1); + + if (unlikely(err)) + goto out_unlock; + + if (buffer_new(bh)) { + clear_buffer_new(bh); + unmap_underlying_metadata(bh->b_bdev, + bh->b_blocknr); + /* + * we do not zeroize fragment, because of + * if it maped to hole, it already contains zeroes + */ + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + set_page_dirty(lastpage); + } + + if (lastfrag >= UFS_IND_FRAGMENT) { + end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1; + phys64 = bh->b_blocknr + 1; + for (i = 0; i < end; ++i) { + bh = sb_getblk(sb, i + phys64); + lock_buffer(bh); + memset(bh->b_data, 0, sb->s_blocksize); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + sync_dirty_buffer(bh); + brelse(bh); + } + } +out_unlock: + ufs_put_locked_page(lastpage); +out: + return err; +} + +static void __ufs_truncate_blocks(struct inode *inode) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + + mutex_lock(&ufsi->truncate_mutex); + ufs_trunc_direct(inode); + ufs_trunc_indirect(inode, UFS_IND_BLOCK, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); + ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); + ufs_trunc_tindirect(inode); + ufsi->i_lastfrag = DIRECT_FRAGMENT; + mutex_unlock(&ufsi->truncate_mutex); +} + +static int ufs_truncate(struct inode *inode, loff_t size) +{ + int err = 0; + + UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", + inode->i_ino, (unsigned long long)size, + (unsigned long long)i_size_read(inode)); + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return -EPERM; + + err = ufs_alloc_lastblock(inode, size); + + if (err) + goto out; + + block_truncate_page(inode->i_mapping, size, ufs_getfrag_block); + + truncate_setsize(inode, size); + + __ufs_truncate_blocks(inode); + inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); +out: + UFSD("EXIT: err %d\n", err); + return err; +} + +void ufs_truncate_blocks(struct inode *inode) +{ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + __ufs_truncate_blocks(inode); +} + +int ufs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = d_inode(dentry); + unsigned int ia_valid = attr->ia_valid; + int error; + + error = inode_change_ok(inode, attr); + if (error) + return error; + + if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { + error = ufs_truncate(inode, attr->ia_size); + if (error) + return error; + } + + setattr_copy(inode, attr); + mark_inode_dirty(inode); + return 0; +} + +const struct inode_operations ufs_file_inode_operations = { + .setattr = ufs_setattr, +}; diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c deleted file mode 100644 index f84dd3078929d..0000000000000 --- a/fs/ufs/truncate.c +++ /dev/null @@ -1,515 +0,0 @@ -/* - * linux/fs/ufs/truncate.c - * - * Copyright (C) 1998 - * Daniel Pirkl - * Charles University, Faculty of Mathematics and Physics - * - * from - * - * linux/fs/ext2/truncate.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/truncate.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -/* - * Real random numbers for secure rm added 94/02/18 - * Idea from Pierre del Perugia - */ - -/* - * Adoptation to use page cache and UFS2 write support by - * Evgeniy Dushistov , 2006-2007 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ufs_fs.h" -#include "ufs.h" -#include "swab.h" -#include "util.h" - -/* - * Secure deletion currently doesn't work. It interacts very badly - * with buffers shared with memory mappings, and for that reason - * can't be done in the truncate() routines. It should instead be - * done separately in "release()" before calling the truncate routines - * that will release the actual file blocks. - * - * Linus - */ - -#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift) -#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) - - -static void ufs_trunc_direct(struct inode *inode) -{ - struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; - void *p; - u64 frag1, frag2, frag3, frag4, block1, block2; - unsigned frag_to_free, free_count; - unsigned i, tmp; - - UFSD("ENTER: ino %lu\n", inode->i_ino); - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - frag_to_free = 0; - free_count = 0; - - frag1 = DIRECT_FRAGMENT; - frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); - frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); - frag3 = frag4 & ~uspi->s_fpbmask; - block1 = block2 = 0; - if (frag2 > frag3) { - frag2 = frag4; - frag3 = frag4 = 0; - } else if (frag2 < frag3) { - block1 = ufs_fragstoblks (frag2); - block2 = ufs_fragstoblks (frag3); - } - - UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu," - " frag3 %llu, frag4 %llu\n", inode->i_ino, - (unsigned long long)frag1, (unsigned long long)frag2, - (unsigned long long)block1, (unsigned long long)block2, - (unsigned long long)frag3, (unsigned long long)frag4); - - if (frag1 >= frag2) - goto next1; - - /* - * Free first free fragments - */ - p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp ) - ufs_panic (sb, "ufs_trunc_direct", "internal error"); - frag2 -= frag1; - frag1 = ufs_fragnum (frag1); - - ufs_free_fragments(inode, tmp + frag1, frag2); - mark_inode_dirty(inode); - frag_to_free = tmp + frag1; - -next1: - /* - * Free whole blocks - */ - for (i = block1 ; i < block2; i++) { - p = ufs_get_direct_data_ptr(uspi, ufsi, i); - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp) - continue; - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); - - if (free_count == 0) { - frag_to_free = tmp; - free_count = uspi->s_fpb; - } else if (free_count > 0 && frag_to_free == tmp - free_count) - free_count += uspi->s_fpb; - else { - ufs_free_blocks (inode, frag_to_free, free_count); - frag_to_free = tmp; - free_count = uspi->s_fpb; - } - mark_inode_dirty(inode); - } - - if (free_count > 0) - ufs_free_blocks (inode, frag_to_free, free_count); - - if (frag3 >= frag4) - goto next3; - - /* - * Free last free fragments - */ - p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp ) - ufs_panic(sb, "ufs_truncate_direct", "internal error"); - frag4 = ufs_fragnum (frag4); - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); - - ufs_free_fragments (inode, tmp, frag4); - mark_inode_dirty(inode); - next3: - - UFSD("EXIT: ino %lu\n", inode->i_ino); -} - - -static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) -{ - struct super_block * sb; - struct ufs_sb_private_info * uspi; - struct ufs_buffer_head * ind_ubh; - void *ind; - u64 tmp, indirect_block, i, frag_to_free; - unsigned free_count; - - UFSD("ENTER: ino %lu, offset %llu, p: %p\n", - inode->i_ino, (unsigned long long)offset, p); - - BUG_ON(!p); - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - frag_to_free = 0; - free_count = 0; - - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp) - return; - ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); - if (!ind_ubh) { - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - return; - } - - indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; - for (i = indirect_block; i < uspi->s_apb; i++) { - ind = ubh_get_data_ptr(uspi, ind_ubh, i); - tmp = ufs_data_ptr_to_cpu(sb, ind); - if (!tmp) - continue; - - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, ind); - write_sequnlock(&UFS_I(inode)->meta_lock); - ubh_mark_buffer_dirty(ind_ubh); - if (free_count == 0) { - frag_to_free = tmp; - free_count = uspi->s_fpb; - } else if (free_count > 0 && frag_to_free == tmp - free_count) - free_count += uspi->s_fpb; - else { - ufs_free_blocks (inode, frag_to_free, free_count); - frag_to_free = tmp; - free_count = uspi->s_fpb; - } - - mark_inode_dirty(inode); - } - - if (free_count > 0) { - ufs_free_blocks (inode, frag_to_free, free_count); - } - for (i = 0; i < uspi->s_apb; i++) - if (!ufs_is_data_ptr_zero(uspi, - ubh_get_data_ptr(uspi, ind_ubh, i))) - break; - if (i >= uspi->s_apb) { - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - - ubh_bforget(ind_ubh); - ufs_free_blocks (inode, tmp, uspi->s_fpb); - mark_inode_dirty(inode); - ind_ubh = NULL; - } - if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) - ubh_sync_block(ind_ubh); - ubh_brelse (ind_ubh); - - UFSD("EXIT: ino %lu\n", inode->i_ino); -} - -static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) -{ - struct super_block * sb; - struct ufs_sb_private_info * uspi; - struct ufs_buffer_head *dind_bh; - u64 i, tmp, dindirect_block; - void *dind; - - UFSD("ENTER: ino %lu\n", inode->i_ino); - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - dindirect_block = (DIRECT_BLOCK > offset) - ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; - - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp) - return; - dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); - if (!dind_bh) { - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - return; - } - - for (i = dindirect_block ; i < uspi->s_apb ; i++) { - dind = ubh_get_data_ptr(uspi, dind_bh, i); - tmp = ufs_data_ptr_to_cpu(sb, dind); - if (!tmp) - continue; - ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); - ubh_mark_buffer_dirty(dind_bh); - } - - for (i = 0; i < uspi->s_apb; i++) - if (!ufs_is_data_ptr_zero(uspi, - ubh_get_data_ptr(uspi, dind_bh, i))) - break; - if (i >= uspi->s_apb) { - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - - ubh_bforget(dind_bh); - ufs_free_blocks(inode, tmp, uspi->s_fpb); - mark_inode_dirty(inode); - dind_bh = NULL; - } - if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) - ubh_sync_block(dind_bh); - ubh_brelse (dind_bh); - - UFSD("EXIT: ino %lu\n", inode->i_ino); -} - -static void ufs_trunc_tindirect(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct ufs_inode_info *ufsi = UFS_I(inode); - struct ufs_buffer_head * tind_bh; - u64 tindirect_block, tmp, i; - void *tind, *p; - - UFSD("ENTER: ino %lu\n", inode->i_ino); - - tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) - ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; - - p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); - if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) - return; - tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); - if (!tind_bh) { - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); - return; - } - - for (i = tindirect_block ; i < uspi->s_apb ; i++) { - tind = ubh_get_data_ptr(uspi, tind_bh, i); - ufs_trunc_dindirect(inode, UFS_NDADDR + - uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); - ubh_mark_buffer_dirty(tind_bh); - } - for (i = 0; i < uspi->s_apb; i++) - if (!ufs_is_data_ptr_zero(uspi, - ubh_get_data_ptr(uspi, tind_bh, i))) - break; - if (i >= uspi->s_apb) { - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); - - ubh_bforget(tind_bh); - ufs_free_blocks(inode, tmp, uspi->s_fpb); - mark_inode_dirty(inode); - tind_bh = NULL; - } - if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) - ubh_sync_block(tind_bh); - ubh_brelse (tind_bh); - - UFSD("EXIT: ino %lu\n", inode->i_ino); -} - -static int ufs_alloc_lastblock(struct inode *inode, loff_t size) -{ - int err = 0; - struct super_block *sb = inode->i_sb; - struct address_space *mapping = inode->i_mapping; - struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - unsigned i, end; - sector_t lastfrag; - struct page *lastpage; - struct buffer_head *bh; - u64 phys64; - - lastfrag = (size + uspi->s_fsize - 1) >> uspi->s_fshift; - - if (!lastfrag) - goto out; - - lastfrag--; - - lastpage = ufs_get_locked_page(mapping, lastfrag >> - (PAGE_CACHE_SHIFT - inode->i_blkbits)); - if (IS_ERR(lastpage)) { - err = -EIO; - goto out; - } - - end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1); - bh = page_buffers(lastpage); - for (i = 0; i < end; ++i) - bh = bh->b_this_page; - - - err = ufs_getfrag_block(inode, lastfrag, bh, 1); - - if (unlikely(err)) - goto out_unlock; - - if (buffer_new(bh)) { - clear_buffer_new(bh); - unmap_underlying_metadata(bh->b_bdev, - bh->b_blocknr); - /* - * we do not zeroize fragment, because of - * if it maped to hole, it already contains zeroes - */ - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - set_page_dirty(lastpage); - } - - if (lastfrag >= UFS_IND_FRAGMENT) { - end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1; - phys64 = bh->b_blocknr + 1; - for (i = 0; i < end; ++i) { - bh = sb_getblk(sb, i + phys64); - lock_buffer(bh); - memset(bh->b_data, 0, sb->s_blocksize); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - unlock_buffer(bh); - sync_dirty_buffer(bh); - brelse(bh); - } - } -out_unlock: - ufs_put_locked_page(lastpage); -out: - return err; -} - -static void __ufs_truncate_blocks(struct inode *inode) -{ - struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block *sb = inode->i_sb; - struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - - mutex_lock(&ufsi->truncate_mutex); - ufs_trunc_direct(inode); - ufs_trunc_indirect(inode, UFS_IND_BLOCK, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode); - ufsi->i_lastfrag = DIRECT_FRAGMENT; - mutex_unlock(&ufsi->truncate_mutex); -} - -int ufs_truncate(struct inode *inode, loff_t size) -{ - int err = 0; - - UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", - inode->i_ino, (unsigned long long)size, - (unsigned long long)i_size_read(inode)); - - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return -EINVAL; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return -EPERM; - - err = ufs_alloc_lastblock(inode, size); - - if (err) - goto out; - - block_truncate_page(inode->i_mapping, size, ufs_getfrag_block); - - truncate_setsize(inode, size); - - __ufs_truncate_blocks(inode); - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - mark_inode_dirty(inode); -out: - UFSD("EXIT: err %d\n", err); - return err; -} - -void ufs_truncate_blocks(struct inode *inode) -{ - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode))) - return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; - __ufs_truncate_blocks(inode); -} - -int ufs_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - unsigned int ia_valid = attr->ia_valid; - int error; - - error = inode_change_ok(inode, attr); - if (error) - return error; - - if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { - error = ufs_truncate(inode, attr->ia_size); - if (error) - return error; - } - - setattr_copy(inode, attr); - mark_inode_dirty(inode); - return 0; -} - -const struct inode_operations ufs_file_inode_operations = { - .setattr = ufs_setattr, -}; diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 478f35b493a62..7da4aca868c06 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -122,7 +122,7 @@ extern struct inode *ufs_iget(struct super_block *, unsigned long); extern int ufs_write_inode (struct inode *, struct writeback_control *); extern int ufs_sync_inode (struct inode *); extern void ufs_evict_inode (struct inode *); -extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create); +extern int ufs_setattr(struct dentry *dentry, struct iattr *attr); /* namei.c */ extern const struct file_operations ufs_dir_operations; @@ -140,10 +140,6 @@ void ufs_mark_sb_dirty(struct super_block *sb); extern const struct inode_operations ufs_fast_symlink_inode_operations; extern const struct inode_operations ufs_symlink_inode_operations; -/* truncate.c */ -extern void ufs_truncate_blocks(struct inode *); -extern int ufs_setattr(struct dentry *dentry, struct iattr *attr); - static inline struct ufs_sb_info *UFS_SB(struct super_block *sb) { return sb->s_fs_info; -- GitLab From 4e3911f3d704d681477cdb4e1a2bfd52d5e42d23 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 4 Jun 2015 14:13:14 -0400 Subject: [PATCH 0494/7006] ufs: the offsets ufs_block_to_path() puts into array are not sector_t type makes no sense - those are indices in block number arrays, not block numbers. And no, UFS is not likely to grow indirect blocks with 4Gpointers in them... Signed-off-by: Al Viro --- fs/ufs/inode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index ec758edbda478..43672183fee33 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -41,7 +41,7 @@ #include "swab.h" #include "util.h" -static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4]) +static int ufs_block_to_path(struct inode *inode, sector_t i_block, unsigned offsets[4]) { struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; int ptrs = uspi->s_apb; @@ -153,7 +153,7 @@ again: while (--depth) { __fs32 *ptr; struct buffer_head *bh; - sector_t n = *p++; + unsigned n = *p++; bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, q->key32) + (n>>shift)); @@ -177,7 +177,7 @@ ufs2: while (--depth) { __fs64 *ptr; struct buffer_head *bh; - sector_t n = *p++; + unsigned n = *p++; bh = sb_bread(sb, uspi->s_sbbase + fs64_to_cpu(sb, q->key64) + (n>>shift)); -- GitLab From 31cd043e1a09c579c4cd38ea432200fbeae6af1f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Jun 2015 01:10:03 -0400 Subject: [PATCH 0495/7006] ufs: beginning of __ufs_truncate_block() massage Use ufs_block_to_path() to find the cutoff path in the block pointers' tree. For now just use the information about the depth (to bypass the fully preserved subtrees); subsequent commits will use the information about actual path. Signed-off-by: Al Viro --- fs/ufs/inode.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 43672183fee33..afb0f32b921cf 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1336,14 +1336,22 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + unsigned offsets[4]; + int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); mutex_lock(&ufsi->truncate_mutex); - ufs_trunc_direct(inode); - ufs_trunc_indirect(inode, UFS_IND_BLOCK, + switch (depth) { + case 1: + ufs_trunc_direct(inode); + case 2: + ufs_trunc_indirect(inode, UFS_IND_BLOCK, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, + case 3: + ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode); + case 4: + ufs_trunc_tindirect(inode); + } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); } -- GitLab From 18ca51d8211065f10672374336cd08d495968c73 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 13:45:07 -0400 Subject: [PATCH 0496/7006] ufs_trunc_tindirect(): pass the number of blocks to keep IOW, the distance of cutoff from the begining of the branch (in blocks). That (and the fact that block just prior to cutoff is guaranteed to be present) allows to tell whether to free triple indirect block just by looking at the offset. While we are at it, using u64 for index in the block is wrong - those should be unsigned int. Signed-off-by: Al Viro --- fs/ufs/inode.c | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index afb0f32b921cf..5b3f1c44d4b04 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1208,19 +1208,17 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) UFSD("EXIT: ino %lu\n", inode->i_ino); } -static void ufs_trunc_tindirect(struct inode *inode) +static void ufs_trunc_tindirect(struct inode *inode, u64 offset) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_inode_info *ufsi = UFS_I(inode); struct ufs_buffer_head * tind_bh; - u64 tindirect_block, tmp, i; + u64 tmp; void *tind, *p; - - UFSD("ENTER: ino %lu\n", inode->i_ino); - - tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) - ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; + bool free_it = !offset; + unsigned tindirect_block = offset >> uspi->s_2apbshift; + unsigned i; p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) @@ -1239,11 +1237,7 @@ static void ufs_trunc_tindirect(struct inode *inode) uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); ubh_mark_buffer_dirty(tind_bh); } - for (i = 0; i < uspi->s_apb; i++) - if (!ufs_is_data_ptr_zero(uspi, - ubh_get_data_ptr(uspi, tind_bh, i))) - break; - if (i >= uspi->s_apb) { + if (free_it) { tmp = ufs_data_ptr_to_cpu(sb, p); write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); @@ -1252,13 +1246,11 @@ static void ufs_trunc_tindirect(struct inode *inode) ubh_bforget(tind_bh); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); - tind_bh = NULL; + return; } - if (IS_SYNC(inode) && tind_bh && ubh_buffer_dirty(tind_bh)) + if (IS_SYNC(inode) && ubh_buffer_dirty(tind_bh)) ubh_sync_block(tind_bh); ubh_brelse (tind_bh); - - UFSD("EXIT: ino %lu\n", inode->i_ino); } static int ufs_alloc_lastblock(struct inode *inode, loff_t size) @@ -1349,8 +1341,10 @@ static void __ufs_truncate_blocks(struct inode *inode) case 3: ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); + ufs_trunc_tindirect(inode, 0); + break; case 4: - ufs_trunc_tindirect(inode); + ufs_trunc_tindirect(inode, DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb); } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); -- GitLab From 6ac36b8777d934e3cd7eb0f023a5043d5c03b00c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 17 Jun 2015 01:54:58 -0400 Subject: [PATCH 0497/7006] ufs_trunc_indirect(): pass the index of the first pointer to free ... instead of file offset. Same cleanups as in the tindirect conversion in previous commit. Signed-off-by: Al Viro --- fs/ufs/inode.c | 56 +++++++++++++++++++++----------------------------- 1 file changed, 23 insertions(+), 33 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 5b3f1c44d4b04..9c4471a82d2ff 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1069,25 +1069,16 @@ next1: } -static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) +static void ufs_trunc_indirect(struct inode *inode, unsigned from, void *p) { - struct super_block * sb; - struct ufs_sb_private_info * uspi; + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_buffer_head * ind_ubh; void *ind; - u64 tmp, indirect_block, i, frag_to_free; - unsigned free_count; - - UFSD("ENTER: ino %lu, offset %llu, p: %p\n", - inode->i_ino, (unsigned long long)offset, p); - - BUG_ON(!p); - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - frag_to_free = 0; - free_count = 0; + u64 tmp, frag_to_free = 0; + unsigned free_count = 0; + bool to_free = !from; + unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) @@ -1100,8 +1091,7 @@ static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) return; } - indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; - for (i = indirect_block; i < uspi->s_apb; i++) { + for (i = from; i < uspi->s_apb; i++) { ind = ubh_get_data_ptr(uspi, ind_ubh, i); tmp = ufs_data_ptr_to_cpu(sb, ind); if (!tmp) @@ -1128,11 +1118,7 @@ static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) if (free_count > 0) { ufs_free_blocks (inode, frag_to_free, free_count); } - for (i = 0; i < uspi->s_apb; i++) - if (!ufs_is_data_ptr_zero(uspi, - ubh_get_data_ptr(uspi, ind_ubh, i))) - break; - if (i >= uspi->s_apb) { + if (to_free) { tmp = ufs_data_ptr_to_cpu(sb, p); write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); @@ -1141,13 +1127,11 @@ static void ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) ubh_bforget(ind_ubh); ufs_free_blocks (inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); - ind_ubh = NULL; + return; } - if (IS_SYNC(inode) && ind_ubh && ubh_buffer_dirty(ind_ubh)) + if (IS_SYNC(inode) && ubh_buffer_dirty(ind_ubh)) ubh_sync_block(ind_ubh); ubh_brelse (ind_ubh); - - UFSD("EXIT: ino %lu\n", inode->i_ino); } static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) @@ -1157,14 +1141,20 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) struct ufs_buffer_head *dind_bh; u64 i, tmp, dindirect_block; void *dind; + unsigned from; UFSD("ENTER: ino %lu\n", inode->i_ino); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; - dindirect_block = (DIRECT_BLOCK > offset) - ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; + if (DIRECT_BLOCK <= offset) { + dindirect_block = 0; + from = 0; + } else { + dindirect_block = (DIRECT_BLOCK - offset) >> uspi->s_apbshift; + from = (DIRECT_BLOCK - offset) & uspi->s_apbmask; + } tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) @@ -1177,12 +1167,12 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) return; } - for (i = dindirect_block ; i < uspi->s_apb ; i++) { + for (i = dindirect_block ; i < uspi->s_apb ; i++, from = 0) { dind = ubh_get_data_ptr(uspi, dind_bh, i); tmp = ufs_data_ptr_to_cpu(sb, dind); if (!tmp) continue; - ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); + ufs_trunc_indirect(inode, from, dind); ubh_mark_buffer_dirty(dind_bh); } @@ -1328,7 +1318,7 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - unsigned offsets[4]; + unsigned offsets[4] = {0,}; int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); mutex_lock(&ufsi->truncate_mutex); @@ -1336,7 +1326,7 @@ static void __ufs_truncate_blocks(struct inode *inode) case 1: ufs_trunc_direct(inode); case 2: - ufs_trunc_indirect(inode, UFS_IND_BLOCK, + ufs_trunc_indirect(inode, offsets[1], ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); case 3: ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, -- GitLab From 7bad5939fcd04bb83122bdb90981ec5ae2f90e0d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 14:21:09 -0400 Subject: [PATCH 0498/7006] ufs_trunc_dindirect(): pass the number of blocks to keep same as the previous two. Signed-off-by: Al Viro --- fs/ufs/inode.c | 57 +++++++++++++++++++++++--------------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 9c4471a82d2ff..b4d6398a2d540 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1136,25 +1136,15 @@ static void ufs_trunc_indirect(struct inode *inode, unsigned from, void *p) static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) { - struct super_block * sb; - struct ufs_sb_private_info * uspi; + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_buffer_head *dind_bh; - u64 i, tmp, dindirect_block; + u64 tmp; void *dind; - unsigned from; - - UFSD("ENTER: ino %lu\n", inode->i_ino); - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - - if (DIRECT_BLOCK <= offset) { - dindirect_block = 0; - from = 0; - } else { - dindirect_block = (DIRECT_BLOCK - offset) >> uspi->s_apbshift; - from = (DIRECT_BLOCK - offset) & uspi->s_apbmask; - } + bool free_it = !offset; + unsigned dindirect_block = offset >> uspi->s_apbshift; + unsigned from = offset & uspi->s_apbmask; + unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) @@ -1176,11 +1166,7 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) ubh_mark_buffer_dirty(dind_bh); } - for (i = 0; i < uspi->s_apb; i++) - if (!ufs_is_data_ptr_zero(uspi, - ubh_get_data_ptr(uspi, dind_bh, i))) - break; - if (i >= uspi->s_apb) { + if (free_it) { tmp = ufs_data_ptr_to_cpu(sb, p); write_seqlock(&UFS_I(inode)->meta_lock); ufs_data_ptr_clear(uspi, p); @@ -1189,13 +1175,11 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) ubh_bforget(dind_bh); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); - dind_bh = NULL; + return; } - if (IS_SYNC(inode) && dind_bh && ubh_buffer_dirty(dind_bh)) + if (IS_SYNC(inode) && ubh_buffer_dirty(dind_bh)) ubh_sync_block(dind_bh); ubh_brelse (dind_bh); - - UFSD("EXIT: ino %lu\n", inode->i_ino); } static void ufs_trunc_tindirect(struct inode *inode, u64 offset) @@ -1210,6 +1194,8 @@ static void ufs_trunc_tindirect(struct inode *inode, u64 offset) unsigned tindirect_block = offset >> uspi->s_2apbshift; unsigned i; + offset -= tindirect_block << uspi->s_2apbshift; + p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) return; @@ -1221,10 +1207,9 @@ static void ufs_trunc_tindirect(struct inode *inode, u64 offset) return; } - for (i = tindirect_block ; i < uspi->s_apb ; i++) { + for (i = tindirect_block ; i < uspi->s_apb ; i++, offset = 0) { tind = ubh_get_data_ptr(uspi, tind_bh, i); - ufs_trunc_dindirect(inode, UFS_NDADDR + - uspi->s_apb + ((i + 1) << uspi->s_2apbshift), tind); + ufs_trunc_dindirect(inode, offset, tind); ubh_mark_buffer_dirty(tind_bh); } if (free_it) { @@ -1318,18 +1303,28 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - unsigned offsets[4] = {0,}; + unsigned offsets[4]; int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); mutex_lock(&ufsi->truncate_mutex); switch (depth) { case 1: ufs_trunc_direct(inode); + ufs_trunc_indirect(inode, 0, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); + ufs_trunc_dindirect(inode, 0, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); + ufs_trunc_tindirect(inode, 0); + break; case 2: ufs_trunc_indirect(inode, offsets[1], ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); + ufs_trunc_dindirect(inode, 0, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); + ufs_trunc_tindirect(inode, 0); + break; case 3: - ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, + ufs_trunc_dindirect(inode, DIRECT_BLOCK - UFS_IND_BLOCK - uspi->s_apb, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); ufs_trunc_tindirect(inode, 0); break; -- GitLab From 7a4fdda72451f094374324a552be9fc7de8f3e8d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 14:28:54 -0400 Subject: [PATCH 0499/7006] __ufs_truncate(); find cutoff distances into branches by offsets[] array Signed-off-by: Al Viro --- fs/ufs/inode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index b4d6398a2d540..c2544d62adf20 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1324,12 +1324,16 @@ static void __ufs_truncate_blocks(struct inode *inode) ufs_trunc_tindirect(inode, 0); break; case 3: - ufs_trunc_dindirect(inode, DIRECT_BLOCK - UFS_IND_BLOCK - uspi->s_apb, + ufs_trunc_dindirect(inode, + (offsets[1] << uspi->s_apbshift) + offsets[2], ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); ufs_trunc_tindirect(inode, 0); break; case 4: - ufs_trunc_tindirect(inode, DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb); + ufs_trunc_tindirect(inode, + (offsets[1] << uspi->s_2apbshift) + + (offsets[2] << uspi->s_apbshift) + + offsets[3]); } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); -- GitLab From 85416288bf730cffb61ab6ce8a7b97b17c73458f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 14:36:31 -0400 Subject: [PATCH 0500/7006] ufs_trunc_...indirect(): pass the array of indices instead of offsets rather than bitslicing the offset just formed as sum of shifted indices, pass the array of those indices itself. NULL is used as equivalent of "all zeroes" (== free the entire branch). Signed-off-by: Al Viro --- fs/ufs/inode.c | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index c2544d62adf20..34d8dac4fe8b1 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1069,7 +1069,7 @@ next1: } -static void ufs_trunc_indirect(struct inode *inode, unsigned from, void *p) +static void ufs_trunc_indirect(struct inode *inode, unsigned *offsets, void *p) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -1077,7 +1077,8 @@ static void ufs_trunc_indirect(struct inode *inode, unsigned from, void *p) void *ind; u64 tmp, frag_to_free = 0; unsigned free_count = 0; - bool to_free = !from; + unsigned from = offsets ? *offsets : 0; + bool to_free = !offsets || !from; unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); @@ -1134,16 +1135,15 @@ static void ufs_trunc_indirect(struct inode *inode, unsigned from, void *p) ubh_brelse (ind_ubh); } -static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) +static void ufs_trunc_dindirect(struct inode *inode, unsigned *offsets, void *p) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_buffer_head *dind_bh; u64 tmp; void *dind; - bool free_it = !offset; - unsigned dindirect_block = offset >> uspi->s_apbshift; - unsigned from = offset & uspi->s_apbmask; + bool free_it = !offsets || !(offsets[0] || offsets[1]); + unsigned dindirect_block = offsets ? *offsets++ : 0; unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); @@ -1157,12 +1157,12 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) return; } - for (i = dindirect_block ; i < uspi->s_apb ; i++, from = 0) { + for (i = dindirect_block ; i < uspi->s_apb ; i++, offsets = NULL) { dind = ubh_get_data_ptr(uspi, dind_bh, i); tmp = ufs_data_ptr_to_cpu(sb, dind); if (!tmp) continue; - ufs_trunc_indirect(inode, from, dind); + ufs_trunc_indirect(inode, offsets, dind); ubh_mark_buffer_dirty(dind_bh); } @@ -1182,7 +1182,7 @@ static void ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) ubh_brelse (dind_bh); } -static void ufs_trunc_tindirect(struct inode *inode, u64 offset) +static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -1190,12 +1190,10 @@ static void ufs_trunc_tindirect(struct inode *inode, u64 offset) struct ufs_buffer_head * tind_bh; u64 tmp; void *tind, *p; - bool free_it = !offset; - unsigned tindirect_block = offset >> uspi->s_2apbshift; + bool free_it = !offsets || !(offsets[0] || offsets[1] || offsets[2]); + unsigned tindirect_block = offsets ? *offsets++ : 0; unsigned i; - offset -= tindirect_block << uspi->s_2apbshift; - p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) return; @@ -1207,9 +1205,9 @@ static void ufs_trunc_tindirect(struct inode *inode, u64 offset) return; } - for (i = tindirect_block ; i < uspi->s_apb ; i++, offset = 0) { + for (i = tindirect_block ; i < uspi->s_apb ; i++, offsets = NULL) { tind = ubh_get_data_ptr(uspi, tind_bh, i); - ufs_trunc_dindirect(inode, offset, tind); + ufs_trunc_dindirect(inode, offsets, tind); ubh_mark_buffer_dirty(tind_bh); } if (free_it) { @@ -1310,30 +1308,26 @@ static void __ufs_truncate_blocks(struct inode *inode) switch (depth) { case 1: ufs_trunc_direct(inode); - ufs_trunc_indirect(inode, 0, + ufs_trunc_indirect(inode, NULL, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, 0, + ufs_trunc_dindirect(inode, NULL, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, 0); + ufs_trunc_tindirect(inode, NULL); break; case 2: - ufs_trunc_indirect(inode, offsets[1], + ufs_trunc_indirect(inode, offsets + 1, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, 0, + ufs_trunc_dindirect(inode, NULL, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, 0); + ufs_trunc_tindirect(inode, NULL); break; case 3: - ufs_trunc_dindirect(inode, - (offsets[1] << uspi->s_apbshift) + offsets[2], + ufs_trunc_dindirect(inode, offsets + 1, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, 0); + ufs_trunc_tindirect(inode, NULL); break; case 4: - ufs_trunc_tindirect(inode, - (offsets[1] << uspi->s_2apbshift) + - (offsets[2] << uspi->s_apbshift) + - offsets[3]); + ufs_trunc_tindirect(inode, offsets + 1); } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); -- GitLab From 6775e24d9ccf6a48ebd1d31ca77db5ebfe00ce43 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 14:55:50 -0400 Subject: [PATCH 0501/7006] ufs_trunc_..indirect(): more massage towards unifying Instead of manually checking that the array contains only zeroes, find the position of the last non-zero (in __ufs_truncate(), where we can conveniently do that) and use that to tell if there's any non-zero in the array tail passed to ufs_trunc_...indirect(). The goal of all that clumsiness is to get fold these functions together. Signed-off-by: Al Viro --- fs/ufs/inode.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 34d8dac4fe8b1..e90266a221b88 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1069,7 +1069,7 @@ next1: } -static void ufs_trunc_indirect(struct inode *inode, unsigned *offsets, void *p) +static void ufs_trunc_indirect(struct inode *inode, unsigned *offsets, int depth2, void *p) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -1078,7 +1078,7 @@ static void ufs_trunc_indirect(struct inode *inode, unsigned *offsets, void *p) u64 tmp, frag_to_free = 0; unsigned free_count = 0; unsigned from = offsets ? *offsets : 0; - bool to_free = !offsets || !from; + bool to_free = !offsets || !depth2; unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); @@ -1135,14 +1135,14 @@ static void ufs_trunc_indirect(struct inode *inode, unsigned *offsets, void *p) ubh_brelse (ind_ubh); } -static void ufs_trunc_dindirect(struct inode *inode, unsigned *offsets, void *p) +static void ufs_trunc_dindirect(struct inode *inode, unsigned *offsets, int depth2, void *p) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_buffer_head *dind_bh; u64 tmp; void *dind; - bool free_it = !offsets || !(offsets[0] || offsets[1]); + bool free_it = !offsets || !depth2; unsigned dindirect_block = offsets ? *offsets++ : 0; unsigned i; @@ -1162,7 +1162,7 @@ static void ufs_trunc_dindirect(struct inode *inode, unsigned *offsets, void *p) tmp = ufs_data_ptr_to_cpu(sb, dind); if (!tmp) continue; - ufs_trunc_indirect(inode, offsets, dind); + ufs_trunc_indirect(inode, offsets, depth2 - 1, dind); ubh_mark_buffer_dirty(dind_bh); } @@ -1182,7 +1182,7 @@ static void ufs_trunc_dindirect(struct inode *inode, unsigned *offsets, void *p) ubh_brelse (dind_bh); } -static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets) +static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets, int depth2) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -1190,7 +1190,7 @@ static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets) struct ufs_buffer_head * tind_bh; u64 tmp; void *tind, *p; - bool free_it = !offsets || !(offsets[0] || offsets[1] || offsets[2]); + bool free_it = !offsets || !depth2; unsigned tindirect_block = offsets ? *offsets++ : 0; unsigned i; @@ -1207,7 +1207,7 @@ static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets) for (i = tindirect_block ; i < uspi->s_apb ; i++, offsets = NULL) { tind = ubh_get_data_ptr(uspi, tind_bh, i); - ufs_trunc_dindirect(inode, offsets, tind); + ufs_trunc_dindirect(inode, offsets, depth2 - 1, tind); ubh_mark_buffer_dirty(tind_bh); } if (free_it) { @@ -1303,31 +1303,40 @@ static void __ufs_truncate_blocks(struct inode *inode) struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; unsigned offsets[4]; int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); + int depth2; + + if (!depth) + return; + + /* find the last non-zero in offsets[] */ + for (depth2 = depth - 1; depth2; depth2--) + if (offsets[depth2]) + break; mutex_lock(&ufsi->truncate_mutex); switch (depth) { case 1: ufs_trunc_direct(inode); - ufs_trunc_indirect(inode, NULL, + ufs_trunc_indirect(inode, NULL, 0, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, NULL, + ufs_trunc_dindirect(inode, NULL, 0, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, NULL); + ufs_trunc_tindirect(inode, NULL, 0); break; case 2: - ufs_trunc_indirect(inode, offsets + 1, + ufs_trunc_indirect(inode, offsets + 1, depth2, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, NULL, + ufs_trunc_dindirect(inode, NULL, 0, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, NULL); + ufs_trunc_tindirect(inode, NULL, 0); break; case 3: - ufs_trunc_dindirect(inode, offsets + 1, + ufs_trunc_dindirect(inode, offsets + 1, depth2, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, NULL); + ufs_trunc_tindirect(inode, NULL, 0); break; case 4: - ufs_trunc_tindirect(inode, offsets + 1); + ufs_trunc_tindirect(inode, offsets + 1, depth2); } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); -- GitLab From 9e0fbbde2724d5d3bb9edca6b77e26eb28341154 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 15:33:47 -0400 Subject: [PATCH 0502/7006] unify ufs_trunc_..indirect() Signed-off-by: Al Viro --- fs/ufs/inode.c | 198 +++++++++++++++---------------------------------- 1 file changed, 60 insertions(+), 138 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index e90266a221b88..0d57c41b7705d 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1068,147 +1068,65 @@ next1: UFSD("EXIT: ino %lu\n", inode->i_ino); } - -static void ufs_trunc_indirect(struct inode *inode, unsigned *offsets, int depth2, void *p) -{ - struct super_block *sb = inode->i_sb; - struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct ufs_buffer_head * ind_ubh; - void *ind; - u64 tmp, frag_to_free = 0; - unsigned free_count = 0; - unsigned from = offsets ? *offsets : 0; - bool to_free = !offsets || !depth2; - unsigned i; - - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp) - return; - ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); - if (!ind_ubh) { - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - return; - } - - for (i = from; i < uspi->s_apb; i++) { - ind = ubh_get_data_ptr(uspi, ind_ubh, i); - tmp = ufs_data_ptr_to_cpu(sb, ind); - if (!tmp) - continue; - - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, ind); - write_sequnlock(&UFS_I(inode)->meta_lock); - ubh_mark_buffer_dirty(ind_ubh); - if (free_count == 0) { - frag_to_free = tmp; - free_count = uspi->s_fpb; - } else if (free_count > 0 && frag_to_free == tmp - free_count) - free_count += uspi->s_fpb; - else { - ufs_free_blocks (inode, frag_to_free, free_count); - frag_to_free = tmp; - free_count = uspi->s_fpb; - } - - mark_inode_dirty(inode); - } - - if (free_count > 0) { - ufs_free_blocks (inode, frag_to_free, free_count); - } - if (to_free) { - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - - ubh_bforget(ind_ubh); - ufs_free_blocks (inode, tmp, uspi->s_fpb); - mark_inode_dirty(inode); - return; - } - if (IS_SYNC(inode) && ubh_buffer_dirty(ind_ubh)) - ubh_sync_block(ind_ubh); - ubh_brelse (ind_ubh); -} - -static void ufs_trunc_dindirect(struct inode *inode, unsigned *offsets, int depth2, void *p) +static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, int depth, void *p) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct ufs_buffer_head *dind_bh; + struct ufs_inode_info *ufsi = UFS_I(inode); + struct ufs_buffer_head *ubh; u64 tmp; - void *dind; bool free_it = !offsets || !depth2; - unsigned dindirect_block = offsets ? *offsets++ : 0; + unsigned from = offsets ? *offsets++ : 0; unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) return; - dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); - if (!dind_bh) { - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - return; - } - - for (i = dindirect_block ; i < uspi->s_apb ; i++, offsets = NULL) { - dind = ubh_get_data_ptr(uspi, dind_bh, i); - tmp = ufs_data_ptr_to_cpu(sb, dind); - if (!tmp) - continue; - ufs_trunc_indirect(inode, offsets, depth2 - 1, dind); - ubh_mark_buffer_dirty(dind_bh); - } - - if (free_it) { - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - - ubh_bforget(dind_bh); - ufs_free_blocks(inode, tmp, uspi->s_fpb); - mark_inode_dirty(inode); - return; - } - if (IS_SYNC(inode) && ubh_buffer_dirty(dind_bh)) - ubh_sync_block(dind_bh); - ubh_brelse (dind_bh); -} - -static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets, int depth2) -{ - struct super_block *sb = inode->i_sb; - struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct ufs_inode_info *ufsi = UFS_I(inode); - struct ufs_buffer_head * tind_bh; - u64 tmp; - void *tind, *p; - bool free_it = !offsets || !depth2; - unsigned tindirect_block = offsets ? *offsets++ : 0; - unsigned i; - - p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); - if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) - return; - tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); - if (!tind_bh) { + ubh = ubh_bread (sb, tmp, uspi->s_bsize); + if (!ubh) { write_seqlock(&ufsi->meta_lock); ufs_data_ptr_clear(uspi, p); write_sequnlock(&ufsi->meta_lock); return; } - for (i = tindirect_block ; i < uspi->s_apb ; i++, offsets = NULL) { - tind = ubh_get_data_ptr(uspi, tind_bh, i); - ufs_trunc_dindirect(inode, offsets, depth2 - 1, tind); - ubh_mark_buffer_dirty(tind_bh); + if (--depth) { + for (i = from ; i < uspi->s_apb ; i++, offsets = NULL) { + void *ind = ubh_get_data_ptr(uspi, ubh, i); + ufs_trunc_branch(inode, offsets, depth2 - 1, depth, ind); + ubh_mark_buffer_dirty(ubh); + } + } else { + u64 frag_to_free = 0; + unsigned free_count = 0; + + for (i = from; i < uspi->s_apb; i++) { + void *ind = ubh_get_data_ptr(uspi, ubh, i); + tmp = ufs_data_ptr_to_cpu(sb, ind); + if (!tmp) + continue; + + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, ind); + write_sequnlock(&UFS_I(inode)->meta_lock); + ubh_mark_buffer_dirty(ubh); + if (free_count == 0) { + frag_to_free = tmp; + free_count = uspi->s_fpb; + } else if (free_count > 0 && frag_to_free == tmp - free_count) + free_count += uspi->s_fpb; + else { + ufs_free_blocks (inode, frag_to_free, free_count); + frag_to_free = tmp; + free_count = uspi->s_fpb; + } + + mark_inode_dirty(inode); + } + + if (free_count > 0) { + ufs_free_blocks (inode, frag_to_free, free_count); + } } if (free_it) { tmp = ufs_data_ptr_to_cpu(sb, p); @@ -1216,14 +1134,14 @@ static void ufs_trunc_tindirect(struct inode *inode, unsigned *offsets, int dept ufs_data_ptr_clear(uspi, p); write_sequnlock(&ufsi->meta_lock); - ubh_bforget(tind_bh); + ubh_bforget(ubh); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); return; } - if (IS_SYNC(inode) && ubh_buffer_dirty(tind_bh)) - ubh_sync_block(tind_bh); - ubh_brelse (tind_bh); + if (IS_SYNC(inode) && ubh_buffer_dirty(ubh)) + ubh_sync_block(ubh); + ubh_brelse(ubh); } static int ufs_alloc_lastblock(struct inode *inode, loff_t size) @@ -1317,26 +1235,30 @@ static void __ufs_truncate_blocks(struct inode *inode) switch (depth) { case 1: ufs_trunc_direct(inode); - ufs_trunc_indirect(inode, NULL, 0, + ufs_trunc_branch(inode, NULL, 0, 1, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, NULL, 0, + ufs_trunc_branch(inode, NULL, 0, 2, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, NULL, 0); + ufs_trunc_branch(inode, NULL, 0, 3, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); break; case 2: - ufs_trunc_indirect(inode, offsets + 1, depth2, + ufs_trunc_branch(inode, offsets + 1, depth2, 1, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_dindirect(inode, NULL, 0, + ufs_trunc_branch(inode, NULL, 0, 2, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, NULL, 0); + ufs_trunc_branch(inode, NULL, 0, 3, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); break; case 3: - ufs_trunc_dindirect(inode, offsets + 1, depth2, + ufs_trunc_branch(inode, offsets + 1, depth2, 2, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_tindirect(inode, NULL, 0); + ufs_trunc_branch(inode, NULL, 0, 3, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); break; case 4: - ufs_trunc_tindirect(inode, offsets + 1, depth2); + ufs_trunc_branch(inode, offsets + 1, depth2, 3, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); -- GitLab From ef3a315d4ca179fd0b56597e695cd262a8b559b7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 15:42:25 -0400 Subject: [PATCH 0503/7006] __ufs_truncate_blocks(): unify freeing the full branches Signed-off-by: Al Viro --- fs/ufs/inode.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 0d57c41b7705d..1427d277a690c 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1235,31 +1235,30 @@ static void __ufs_truncate_blocks(struct inode *inode) switch (depth) { case 1: ufs_trunc_direct(inode); - ufs_trunc_branch(inode, NULL, 0, 1, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_branch(inode, NULL, 0, 2, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_branch(inode, NULL, 0, 3, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); - break; + goto l1; case 2: ufs_trunc_branch(inode, offsets + 1, depth2, 1, ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - ufs_trunc_branch(inode, NULL, 0, 2, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_branch(inode, NULL, 0, 3, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); - break; + goto l2; case 3: ufs_trunc_branch(inode, offsets + 1, depth2, 2, ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - ufs_trunc_branch(inode, NULL, 0, 3, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); - break; + goto l3; case 4: ufs_trunc_branch(inode, offsets + 1, depth2, 3, ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); + goto l4; } +l1: + ufs_trunc_branch(inode, NULL, 0, 1, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); +l2: + ufs_trunc_branch(inode, NULL, 0, 2, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); +l3: + ufs_trunc_branch(inode, NULL, 0, 3, + ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); +l4: ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); } -- GitLab From 42432739b5902f72011f701f5cd5b4227ebe991c Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 15:47:17 -0400 Subject: [PATCH 0504/7006] __ufs_trunc_blocks(): turn the part after switch into a loop ... and turn the switch into if (), since all cases with depth != 1 have just become identical. Signed-off-by: Al Viro --- fs/ufs/inode.c | 35 ++++++++++------------------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 1427d277a690c..285eacd02d60a 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1222,6 +1222,7 @@ static void __ufs_truncate_blocks(struct inode *inode) unsigned offsets[4]; int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); int depth2; + unsigned i; if (!depth) return; @@ -1232,33 +1233,17 @@ static void __ufs_truncate_blocks(struct inode *inode) break; mutex_lock(&ufsi->truncate_mutex); - switch (depth) { - case 1: + if (depth == 1) { ufs_trunc_direct(inode); - goto l1; - case 2: - ufs_trunc_branch(inode, offsets + 1, depth2, 1, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); - goto l2; - case 3: - ufs_trunc_branch(inode, offsets + 1, depth2, 2, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); - goto l3; - case 4: - ufs_trunc_branch(inode, offsets + 1, depth2, 3, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); - goto l4; + offsets[0] = UFS_IND_BLOCK; + } else { + ufs_trunc_branch(inode, offsets + 1, depth2, depth - 1, + ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++)); + } + for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { + ufs_trunc_branch(inode, NULL, 0, i - UFS_IND_BLOCK + 1, + ufs_get_direct_data_ptr(uspi, ufsi, i)); } -l1: - ufs_trunc_branch(inode, NULL, 0, 1, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_IND_BLOCK)); -l2: - ufs_trunc_branch(inode, NULL, 0, 2, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_DIND_BLOCK)); -l3: - ufs_trunc_branch(inode, NULL, 0, 3, - ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK)); -l4: ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); } -- GitLab From 97e0f8f87c918620689ce542664a3115b752649d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 16:05:18 -0400 Subject: [PATCH 0505/7006] ufs_trunc_branch(): never call with offsets != NULL && depth2 == 0 For calls in __ufs_truncate_blocks() it's just a matter of not incrementing offsets[0] and not making that call - immediately following loop will be executed one extra time and we'll be just fine. For recursive call in ufs_trunc_branch() itself, just assing NULL to offsets if we would be about to make such call. Signed-off-by: Al Viro --- fs/ufs/inode.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 285eacd02d60a..9e409c12afdfa 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1075,7 +1075,7 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, struct ufs_inode_info *ufsi = UFS_I(inode); struct ufs_buffer_head *ubh; u64 tmp; - bool free_it = !offsets || !depth2; + bool free_it = !offsets; unsigned from = offsets ? *offsets++ : 0; unsigned i; @@ -1091,9 +1091,11 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, } if (--depth) { + if (!--depth2) + offsets = NULL; for (i = from ; i < uspi->s_apb ; i++, offsets = NULL) { void *ind = ubh_get_data_ptr(uspi, ubh, i); - ufs_trunc_branch(inode, offsets, depth2 - 1, depth, ind); + ufs_trunc_branch(inode, offsets, depth2, depth, ind); ubh_mark_buffer_dirty(ubh); } } else { @@ -1237,7 +1239,8 @@ static void __ufs_truncate_blocks(struct inode *inode) ufs_trunc_direct(inode); offsets[0] = UFS_IND_BLOCK; } else { - ufs_trunc_branch(inode, offsets + 1, depth2, depth - 1, + if (depth2) + ufs_trunc_branch(inode, offsets + 1, depth2, depth - 1, ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++)); } for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { -- GitLab From a96574233c5d2e50736d83abf65161ec5fa55852 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 16:13:56 -0400 Subject: [PATCH 0506/7006] ufs_trunc_branch(): separate the calls with non-NULL offsets Signed-off-by: Al Viro --- fs/ufs/inode.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 9e409c12afdfa..480c34ee18059 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1091,13 +1091,16 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, } if (--depth) { - if (!--depth2) - offsets = NULL; - for (i = from ; i < uspi->s_apb ; i++, offsets = NULL) { - void *ind = ubh_get_data_ptr(uspi, ubh, i); + if (offsets && --depth2) { + void *ind = ubh_get_data_ptr(uspi, ubh, from++); ufs_trunc_branch(inode, offsets, depth2, depth, ind); ubh_mark_buffer_dirty(ubh); } + for (i = from ; i < uspi->s_apb ; i++) { + void *ind = ubh_get_data_ptr(uspi, ubh, i); + ufs_trunc_branch(inode, NULL, 0, depth, ind); + ubh_mark_buffer_dirty(ubh); + } } else { u64 frag_to_free = 0; unsigned free_count = 0; -- GitLab From a138b4b688c10eb82044451b81534c382d1cddbd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 02:18:54 -0400 Subject: [PATCH 0507/7006] ufs: unify the logics for collecting adjacent data blocks to free open-coded in several places... Signed-off-by: Al Viro --- fs/ufs/inode.c | 56 ++++++++++++++++++++------------------------------ 1 file changed, 22 insertions(+), 34 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 480c34ee18059..39de7782b7c56 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -960,6 +960,22 @@ void ufs_evict_inode(struct inode * inode) ufs_free_inode(inode); } +struct to_free { + struct inode *inode; + u64 to; + unsigned count; +}; + +static inline void free_data(struct to_free *ctx, u64 from, unsigned count) +{ + if (ctx->count && ctx->to != from) { + ufs_free_blocks(ctx->inode, ctx->to - ctx->count, ctx->count); + ctx->count = 0; + } + ctx->count += count; + ctx->to = from + count; +} + #define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift) #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) @@ -970,7 +986,7 @@ static void ufs_trunc_direct(struct inode *inode) struct ufs_sb_private_info * uspi; void *p; u64 frag1, frag2, frag3, frag4, block1, block2; - unsigned frag_to_free, free_count; + struct to_free ctx = {.inode = inode}; unsigned i, tmp; UFSD("ENTER: ino %lu\n", inode->i_ino); @@ -978,9 +994,6 @@ static void ufs_trunc_direct(struct inode *inode) sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; - frag_to_free = 0; - free_count = 0; - frag1 = DIRECT_FRAGMENT; frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag); frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1); @@ -1015,7 +1028,6 @@ static void ufs_trunc_direct(struct inode *inode) ufs_free_fragments(inode, tmp + frag1, frag2); mark_inode_dirty(inode); - frag_to_free = tmp + frag1; next1: /* @@ -1030,21 +1042,11 @@ next1: ufs_data_ptr_clear(uspi, p); write_sequnlock(&ufsi->meta_lock); - if (free_count == 0) { - frag_to_free = tmp; - free_count = uspi->s_fpb; - } else if (free_count > 0 && frag_to_free == tmp - free_count) - free_count += uspi->s_fpb; - else { - ufs_free_blocks (inode, frag_to_free, free_count); - frag_to_free = tmp; - free_count = uspi->s_fpb; - } + free_data(&ctx, tmp, uspi->s_fpb); mark_inode_dirty(inode); } - if (free_count > 0) - ufs_free_blocks (inode, frag_to_free, free_count); + free_data(&ctx, 0, 0); if (frag3 >= frag4) goto next3; @@ -1102,8 +1104,7 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, ubh_mark_buffer_dirty(ubh); } } else { - u64 frag_to_free = 0; - unsigned free_count = 0; + struct to_free ctx = {.inode = inode}; for (i = from; i < uspi->s_apb; i++) { void *ind = ubh_get_data_ptr(uspi, ubh, i); @@ -1115,23 +1116,10 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, ufs_data_ptr_clear(uspi, ind); write_sequnlock(&UFS_I(inode)->meta_lock); ubh_mark_buffer_dirty(ubh); - if (free_count == 0) { - frag_to_free = tmp; - free_count = uspi->s_fpb; - } else if (free_count > 0 && frag_to_free == tmp - free_count) - free_count += uspi->s_fpb; - else { - ufs_free_blocks (inode, frag_to_free, free_count); - frag_to_free = tmp; - free_count = uspi->s_fpb; - } - + free_data(&ctx, tmp, uspi->s_fpb); mark_inode_dirty(inode); } - - if (free_count > 0) { - ufs_free_blocks (inode, frag_to_free, free_count); - } + free_data(&ctx, 0, 0); } if (free_it) { tmp = ufs_data_ptr_to_cpu(sb, p); -- GitLab From 6d1ebbca2b2fe516ff5f279848cffbd23d2b0270 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 17:11:49 -0400 Subject: [PATCH 0508/7006] split ufs_truncate_branch() into full- and partial-branch variants Signed-off-by: Al Viro --- fs/ufs/inode.c | 74 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 16 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 39de7782b7c56..c06556558c9b9 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1070,6 +1070,60 @@ next1: UFSD("EXIT: ino %lu\n", inode->i_ino); } +static void free_full_branch(struct inode *inode, int depth, void *p) +{ + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + struct ufs_inode_info *ufsi = UFS_I(inode); + struct ufs_buffer_head *ubh; + u64 tmp; + unsigned i; + + tmp = ufs_data_ptr_to_cpu(sb, p); + if (!tmp) + return; + ubh = ubh_bread (sb, tmp, uspi->s_bsize); + if (!ubh) { + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + return; + } + + if (--depth) { + for (i = 0 ; i < uspi->s_apb ; i++) { + void *ind = ubh_get_data_ptr(uspi, ubh, i); + free_full_branch(inode, depth, ind); + ubh_mark_buffer_dirty(ubh); + } + } else { + struct to_free ctx = {.inode = inode}; + + for (i = 0; i < uspi->s_apb; i++) { + void *ind = ubh_get_data_ptr(uspi, ubh, i); + tmp = ufs_data_ptr_to_cpu(sb, ind); + if (!tmp) + continue; + + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, ind); + write_sequnlock(&UFS_I(inode)->meta_lock); + ubh_mark_buffer_dirty(ubh); + free_data(&ctx, tmp, uspi->s_fpb); + mark_inode_dirty(inode); + } + free_data(&ctx, 0, 0); + } + tmp = ufs_data_ptr_to_cpu(sb, p); + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + + ubh_bforget(ubh); + ufs_free_blocks(inode, tmp, uspi->s_fpb); + mark_inode_dirty(inode); +} + static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, int depth, void *p) { struct super_block *sb = inode->i_sb; @@ -1077,8 +1131,7 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, struct ufs_inode_info *ufsi = UFS_I(inode); struct ufs_buffer_head *ubh; u64 tmp; - bool free_it = !offsets; - unsigned from = offsets ? *offsets++ : 0; + unsigned from = *offsets++; unsigned i; tmp = ufs_data_ptr_to_cpu(sb, p); @@ -1093,14 +1146,14 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, } if (--depth) { - if (offsets && --depth2) { + if (--depth2) { void *ind = ubh_get_data_ptr(uspi, ubh, from++); ufs_trunc_branch(inode, offsets, depth2, depth, ind); ubh_mark_buffer_dirty(ubh); } for (i = from ; i < uspi->s_apb ; i++) { void *ind = ubh_get_data_ptr(uspi, ubh, i); - ufs_trunc_branch(inode, NULL, 0, depth, ind); + free_full_branch(inode, depth, ind); ubh_mark_buffer_dirty(ubh); } } else { @@ -1121,17 +1174,6 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, } free_data(&ctx, 0, 0); } - if (free_it) { - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); - - ubh_bforget(ubh); - ufs_free_blocks(inode, tmp, uspi->s_fpb); - mark_inode_dirty(inode); - return; - } if (IS_SYNC(inode) && ubh_buffer_dirty(ubh)) ubh_sync_block(ubh); ubh_brelse(ubh); @@ -1235,7 +1277,7 @@ static void __ufs_truncate_blocks(struct inode *inode) ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++)); } for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { - ufs_trunc_branch(inode, NULL, 0, i - UFS_IND_BLOCK + 1, + free_full_branch(inode, i - UFS_IND_BLOCK + 1, ufs_get_direct_data_ptr(uspi, ufsi, i)); } ufsi->i_lastfrag = DIRECT_FRAGMENT; -- GitLab From 6aab6dd37946d0d592105872bd533bb7d2931f3f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 17:23:34 -0400 Subject: [PATCH 0509/7006] ufs_trunc_branch(): massage towards killing recursion We always have 0 < depth2 <= depth in there, so if (--depth) { if (--depth2) A B } else { C // not using depth2 } D // not using depth2 is equivalent to if (--depth2) A with s/depth/depth - 1/ if (--depth) B else C D Signed-off-by: Al Viro --- fs/ufs/inode.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index c06556558c9b9..dac81c318da71 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1145,12 +1145,12 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, return; } + if (--depth2) { + void *ind = ubh_get_data_ptr(uspi, ubh, from++); + ufs_trunc_branch(inode, offsets, depth2, depth - 1, ind); + ubh_mark_buffer_dirty(ubh); + } if (--depth) { - if (--depth2) { - void *ind = ubh_get_data_ptr(uspi, ubh, from++); - ufs_trunc_branch(inode, offsets, depth2, depth, ind); - ubh_mark_buffer_dirty(ubh); - } for (i = from ; i < uspi->s_apb ; i++) { void *ind = ubh_get_data_ptr(uspi, ubh, i); free_full_branch(inode, depth, ind); -- GitLab From 7b4e4f7f815db0059150a12542b28c787e19c0d7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 19:13:02 -0400 Subject: [PATCH 0510/7006] ufs_trunc_branch(): kill recursion turn recursion into a pair of loops Signed-off-by: Al Viro --- fs/ufs/inode.c | 52 +++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index dac81c318da71..314caad56d835 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1124,34 +1124,14 @@ static void free_full_branch(struct inode *inode, int depth, void *p) mark_inode_dirty(inode); } -static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, int depth, void *p) +static void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buffer_head *ubh, int depth) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct ufs_inode_info *ufsi = UFS_I(inode); - struct ufs_buffer_head *ubh; - u64 tmp; - unsigned from = *offsets++; unsigned i; - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp) - return; - ubh = ubh_bread (sb, tmp, uspi->s_bsize); - if (!ubh) { - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); - return; - } - - if (--depth2) { - void *ind = ubh_get_data_ptr(uspi, ubh, from++); - ufs_trunc_branch(inode, offsets, depth2, depth - 1, ind); - ubh_mark_buffer_dirty(ubh); - } if (--depth) { - for (i = from ; i < uspi->s_apb ; i++) { + for (i = from; i < uspi->s_apb ; i++) { void *ind = ubh_get_data_ptr(uspi, ubh, i); free_full_branch(inode, depth, ind); ubh_mark_buffer_dirty(ubh); @@ -1161,7 +1141,7 @@ static void ufs_trunc_branch(struct inode *inode, unsigned *offsets, int depth2, for (i = from; i < uspi->s_apb; i++) { void *ind = ubh_get_data_ptr(uspi, ubh, i); - tmp = ufs_data_ptr_to_cpu(sb, ind); + u64 tmp = ufs_data_ptr_to_cpu(sb, ind); if (!tmp) continue; @@ -1258,6 +1238,9 @@ static void __ufs_truncate_blocks(struct inode *inode) int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets); int depth2; unsigned i; + struct ufs_buffer_head *ubh[3]; + void *p; + u64 block; if (!depth) return; @@ -1272,9 +1255,26 @@ static void __ufs_truncate_blocks(struct inode *inode) ufs_trunc_direct(inode); offsets[0] = UFS_IND_BLOCK; } else { - if (depth2) - ufs_trunc_branch(inode, offsets + 1, depth2, depth - 1, - ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]++)); + /* get the blocks that should be partially emptied */ + p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]); + for (i = 0; i < depth2; i++) { + offsets[i]++; /* next branch is fully freed */ + block = ufs_data_ptr_to_cpu(sb, p); + if (!block) + break; + ubh[i] = ubh_bread(sb, block, uspi->s_bsize); + if (!ubh[i]) { + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + break; + } + p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]); + } + while (i--) { + ubh_mark_buffer_dirty(ubh[i]); + free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1); + } } for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { free_full_branch(inode, i - UFS_IND_BLOCK + 1, -- GitLab From 163073db51930d1f9c2960b8e5660c269164f29b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 20:07:08 -0400 Subject: [PATCH 0511/7006] free_full_branch(): saner calling conventions Have caller fetch the block number *and* remove it from wherever it was. Pass the block number instead. Signed-off-by: Al Viro --- fs/ufs/inode.c | 100 +++++++++++++++++++++++++------------------------ 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 314caad56d835..efe71e5acb00a 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1070,57 +1070,48 @@ next1: UFSD("EXIT: ino %lu\n", inode->i_ino); } -static void free_full_branch(struct inode *inode, int depth, void *p) +static void free_full_branch(struct inode *inode, u64 ind_block, int depth) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct ufs_inode_info *ufsi = UFS_I(inode); - struct ufs_buffer_head *ubh; - u64 tmp; + struct ufs_buffer_head *ubh = ubh_bread(sb, ind_block, uspi->s_bsize); unsigned i; - tmp = ufs_data_ptr_to_cpu(sb, p); - if (!tmp) - return; - ubh = ubh_bread (sb, tmp, uspi->s_bsize); - if (!ubh) { - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); + if (!ubh) return; - } if (--depth) { - for (i = 0 ; i < uspi->s_apb ; i++) { - void *ind = ubh_get_data_ptr(uspi, ubh, i); - free_full_branch(inode, depth, ind); - ubh_mark_buffer_dirty(ubh); + for (i = 0; i < uspi->s_apb; i++) { + void *p = ubh_get_data_ptr(uspi, ubh, i); + u64 block = ufs_data_ptr_to_cpu(sb, p); + if (block) { + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + free_full_branch(inode, block, depth); + ubh_mark_buffer_dirty(ubh); + } } } else { struct to_free ctx = {.inode = inode}; for (i = 0; i < uspi->s_apb; i++) { - void *ind = ubh_get_data_ptr(uspi, ubh, i); - tmp = ufs_data_ptr_to_cpu(sb, ind); - if (!tmp) - continue; - - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, ind); - write_sequnlock(&UFS_I(inode)->meta_lock); - ubh_mark_buffer_dirty(ubh); - free_data(&ctx, tmp, uspi->s_fpb); - mark_inode_dirty(inode); + void *p = ubh_get_data_ptr(uspi, ubh, i); + u64 block = ufs_data_ptr_to_cpu(sb, p); + if (block) { + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + ubh_mark_buffer_dirty(ubh); + free_data(&ctx, block, uspi->s_fpb); + mark_inode_dirty(inode); + } } free_data(&ctx, 0, 0); } - tmp = ufs_data_ptr_to_cpu(sb, p); - write_seqlock(&ufsi->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&ufsi->meta_lock); ubh_bforget(ubh); - ufs_free_blocks(inode, tmp, uspi->s_fpb); + ufs_free_blocks(inode, ind_block, uspi->s_fpb); mark_inode_dirty(inode); } @@ -1132,25 +1123,30 @@ static void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buff if (--depth) { for (i = from; i < uspi->s_apb ; i++) { - void *ind = ubh_get_data_ptr(uspi, ubh, i); - free_full_branch(inode, depth, ind); - ubh_mark_buffer_dirty(ubh); + void *p = ubh_get_data_ptr(uspi, ubh, i); + u64 block = ufs_data_ptr_to_cpu(sb, p); + if (block) { + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + ubh_mark_buffer_dirty(ubh); + free_full_branch(inode, block, depth); + } } } else { struct to_free ctx = {.inode = inode}; for (i = from; i < uspi->s_apb; i++) { - void *ind = ubh_get_data_ptr(uspi, ubh, i); - u64 tmp = ufs_data_ptr_to_cpu(sb, ind); - if (!tmp) - continue; - - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, ind); - write_sequnlock(&UFS_I(inode)->meta_lock); - ubh_mark_buffer_dirty(ubh); - free_data(&ctx, tmp, uspi->s_fpb); - mark_inode_dirty(inode); + void *p = ubh_get_data_ptr(uspi, ubh, i); + u64 block = ufs_data_ptr_to_cpu(sb, p); + if (block) { + write_seqlock(&UFS_I(inode)->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&UFS_I(inode)->meta_lock); + ubh_mark_buffer_dirty(ubh); + free_data(&ctx, block, uspi->s_fpb); + mark_inode_dirty(inode); + } } free_data(&ctx, 0, 0); } @@ -1277,8 +1273,14 @@ static void __ufs_truncate_blocks(struct inode *inode) } } for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { - free_full_branch(inode, i - UFS_IND_BLOCK + 1, - ufs_get_direct_data_ptr(uspi, ufsi, i)); + p = ufs_get_direct_data_ptr(uspi, ufsi, i); + block = ufs_data_ptr_to_cpu(sb, p); + if (block) { + write_seqlock(&ufsi->meta_lock); + ufs_data_ptr_clear(uspi, p); + write_sequnlock(&ufsi->meta_lock); + free_full_branch(inode, block, i - UFS_IND_BLOCK + 1); + } } ufsi->i_lastfrag = DIRECT_FRAGMENT; mutex_unlock(&ufsi->truncate_mutex); -- GitLab From b6eede0ec642d1be17065110718cb4f4ed7ba5e0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 20:09:39 -0400 Subject: [PATCH 0512/7006] move marking inode dirty to the end of __ufs_truncate_blocks() Signed-off-by: Al Viro --- fs/ufs/inode.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index efe71e5acb00a..26835a80f7ddd 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1027,7 +1027,6 @@ static void ufs_trunc_direct(struct inode *inode) frag1 = ufs_fragnum (frag1); ufs_free_fragments(inode, tmp + frag1, frag2); - mark_inode_dirty(inode); next1: /* @@ -1043,7 +1042,6 @@ next1: write_sequnlock(&ufsi->meta_lock); free_data(&ctx, tmp, uspi->s_fpb); - mark_inode_dirty(inode); } free_data(&ctx, 0, 0); @@ -1064,7 +1062,6 @@ next1: write_sequnlock(&ufsi->meta_lock); ufs_free_fragments (inode, tmp, frag4); - mark_inode_dirty(inode); next3: UFSD("EXIT: ino %lu\n", inode->i_ino); @@ -1104,7 +1101,6 @@ static void free_full_branch(struct inode *inode, u64 ind_block, int depth) write_sequnlock(&UFS_I(inode)->meta_lock); ubh_mark_buffer_dirty(ubh); free_data(&ctx, block, uspi->s_fpb); - mark_inode_dirty(inode); } } free_data(&ctx, 0, 0); @@ -1112,7 +1108,6 @@ static void free_full_branch(struct inode *inode, u64 ind_block, int depth) ubh_bforget(ubh); ufs_free_blocks(inode, ind_block, uspi->s_fpb); - mark_inode_dirty(inode); } static void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buffer_head *ubh, int depth) @@ -1145,7 +1140,6 @@ static void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buff write_sequnlock(&UFS_I(inode)->meta_lock); ubh_mark_buffer_dirty(ubh); free_data(&ctx, block, uspi->s_fpb); - mark_inode_dirty(inode); } } free_data(&ctx, 0, 0); @@ -1283,6 +1277,7 @@ static void __ufs_truncate_blocks(struct inode *inode) } } ufsi->i_lastfrag = DIRECT_FRAGMENT; + mark_inode_dirty(inode); mutex_unlock(&ufsi->truncate_mutex); } -- GitLab From cc7231e30916f5326bdde55a7a4c59431e15bc1b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 20:14:02 -0400 Subject: [PATCH 0513/7006] free_full_branch(): don't bother modifying the block we are going to free Note that it's already made unreachable from the inode, so we don't have to worry about ufs_frag_map() walking into something already freed. Signed-off-by: Al Viro --- fs/ufs/inode.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 26835a80f7ddd..424949f459c8c 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1081,13 +1081,8 @@ static void free_full_branch(struct inode *inode, u64 ind_block, int depth) for (i = 0; i < uspi->s_apb; i++) { void *p = ubh_get_data_ptr(uspi, ubh, i); u64 block = ufs_data_ptr_to_cpu(sb, p); - if (block) { - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); + if (block) free_full_branch(inode, block, depth); - ubh_mark_buffer_dirty(ubh); - } } } else { struct to_free ctx = {.inode = inode}; @@ -1095,13 +1090,8 @@ static void free_full_branch(struct inode *inode, u64 ind_block, int depth) for (i = 0; i < uspi->s_apb; i++) { void *p = ubh_get_data_ptr(uspi, ubh, i); u64 block = ufs_data_ptr_to_cpu(sb, p); - if (block) { - write_seqlock(&UFS_I(inode)->meta_lock); - ufs_data_ptr_clear(uspi, p); - write_sequnlock(&UFS_I(inode)->meta_lock); - ubh_mark_buffer_dirty(ubh); + if (block) free_data(&ctx, block, uspi->s_fpb); - } } free_data(&ctx, 0, 0); } -- GitLab From f53bd1421b3eb84375e9e6964665d23d4190400d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 20:17:32 -0400 Subject: [PATCH 0514/7006] __ufs_truncate_blocks(): avoid excessive dirtying of indirect blocks There's a case when an indirect block gets dirtied for no good reason - when there's a hole starting in the middle of area covered by it and spanning past its end, and truncate() is done precisely to the beginning of the hole. The block is obviously not modified at all - all removals happen beyond it. However, existing code ends up dirtying it just in case. It's trivial to fix and while it's not a real bug by any stretch of imagination, it makes the damn thing harder to follow. Signed-off-by: Al Viro --- fs/ufs/inode.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 424949f459c8c..86cc1eea0fb23 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -1251,10 +1251,8 @@ static void __ufs_truncate_blocks(struct inode *inode) } p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]); } - while (i--) { - ubh_mark_buffer_dirty(ubh[i]); + while (i--) free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1); - } } for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) { p = ufs_get_direct_data_ptr(uspi, ufsi, i); -- GitLab From 5a39c25562aa5eab5a798919855cf41ddeed8b0d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 18 Jun 2015 22:39:46 -0400 Subject: [PATCH 0515/7006] ufs_inode_get{frag,block}(): get rid of retries We are holding ->truncate_mutex, so nobody else can alter our block pointers. Rechecks/retries were needed back when we only held BKL there, and had to cope with write_begin/writepage and writepage/truncate races. Can't happen anymore... Signed-off-by: Al Viro --- fs/ufs/inode.c | 43 ++++++++----------------------------------- 1 file changed, 8 insertions(+), 35 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 86cc1eea0fb23..95cb0a8f5ec92 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -248,20 +248,12 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, goal = 0; -repeat: tmp = ufs_data_ptr_to_cpu(sb, p); lastfrag = ufsi->i_lastfrag; if (tmp && fragment < lastfrag) { if (!phys) { - result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - if (tmp == ufs_data_ptr_to_cpu(sb, p)) { - UFSD("EXIT, result %llu\n", - (unsigned long long)tmp + blockoff); - return result; - } - brelse (result); - goto repeat; + return sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); } else { *phys = uspi->s_sbbase + tmp + blockoff; return NULL; @@ -283,14 +275,9 @@ repeat: ufs_data_ptr_to_cpu(sb, p2), uspi->s_fpb - lastblockoff, err, locked_page); - if (!tmp) { - if (lastfrag != ufsi->i_lastfrag) - goto repeat; - else - return NULL; - } + if (!tmp) + return NULL; lastfrag = ufsi->i_lastfrag; - } tmp = ufs_data_ptr_to_cpu(sb, ufs_get_direct_data_ptr(uspi, ufsi, @@ -325,9 +312,6 @@ repeat: phys != NULL ? locked_page : NULL); } if (!tmp) { - if ((!blockoff && ufs_data_ptr_to_cpu(sb, p)) || - (blockoff && lastfrag != ufsi->i_lastfrag)) - goto repeat; *err = -ENOSPC; return NULL; } @@ -345,7 +329,6 @@ repeat: if (IS_SYNC(inode)) ufs_sync_inode (inode); mark_inode_dirty(inode); - UFSD("EXIT, result %llu\n", (unsigned long long)tmp + blockoff); return result; /* This part : To be implemented .... @@ -409,19 +392,14 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, p = (__fs64 *)bh->b_data + block; else p = (__fs32 *)bh->b_data + block; -repeat: + tmp = ufs_data_ptr_to_cpu(sb, p); if (tmp) { - if (!phys) { + if (!phys) result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - if (tmp == ufs_data_ptr_to_cpu(sb, p)) - goto out; - brelse (result); - goto repeat; - } else { + else *phys = uspi->s_sbbase + tmp + blockoff; - goto out; - } + goto out; } if (block && (uspi->fs_magic == UFS2_MAGIC ? @@ -432,12 +410,8 @@ repeat: goal = bh->b_blocknr + uspi->s_fpb; tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err, locked_page); - if (!tmp) { - if (ufs_data_ptr_to_cpu(sb, p)) - goto repeat; + if (!tmp) goto out; - } - if (!phys) { result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); @@ -451,7 +425,6 @@ repeat: sync_dirty_buffer(bh); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - UFSD("result %llu\n", (unsigned long long)tmp + blockoff); out: brelse (bh); UFSD("EXIT\n"); -- GitLab From 4b7068c8b178401637ef2fb068d6256c97d23f4a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 4 Jun 2015 14:27:23 -0400 Subject: [PATCH 0516/7006] ufs: move calculation of offsets into ufs_getfrag_block() ... and massage ufs_frag_map() to take those instead of fragment number. As it is, we duplicate the damn thing on the write side, open-coded and bloody hard to follow. Signed-off-by: Al Viro --- fs/ufs/inode.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 95cb0a8f5ec92..0f0c6dfccd105 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -119,20 +119,18 @@ static inline int grow_chain64(struct ufs_inode_info *ufsi, * the beginning of the filesystem. */ -static u64 ufs_frag_map(struct inode *inode, sector_t frag) +static u64 ufs_frag_map(struct inode *inode, unsigned offsets[4], int depth) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift; int shift = uspi->s_apbshift-uspi->s_fpbshift; - unsigned offsets[4], *p; Indirect chain[4], *q = chain; - int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets); + unsigned *p; unsigned flags = UFS_SB(sb)->s_flags; u64 res = 0; - UFSD(": frag = %llu depth = %d\n", (unsigned long long)frag, depth); UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n", uspi->s_fpbshift, uspi->s_apbmask, (unsigned long long)mask); @@ -191,7 +189,7 @@ ufs2: } res = fs64_to_cpu(sb, q->key64); found: - res += uspi->s_sbbase + (frag & uspi->s_fpbmask); + res += uspi->s_sbbase; no_block: while (q > chain) { brelse(q->bh); @@ -443,14 +441,17 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff struct ufs_sb_private_info * uspi = sbi->s_uspi; struct buffer_head * bh; int ret, err, new; + unsigned offsets[4]; + int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); unsigned long ptr,phys; u64 phys64 = 0; if (!create) { - phys64 = ufs_frag_map(inode, fragment); - UFSD("phys64 = %llu\n", (unsigned long long)phys64); - if (phys64) + phys64 = ufs_frag_map(inode, offsets, depth); + if (phys64) { + phys64 += fragment & uspi->s_fpbmask; map_bh(bh_result, sb, phys64); + } return 0; } -- GitLab From 71dd42846ffb2bd1a90e9ac2c52df0cc2ed92307 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 4 Jun 2015 14:34:43 -0400 Subject: [PATCH 0517/7006] ufs: use the branch depth in ufs_getfrag_block() we'd already calculated it... Signed-off-by: Al Viro --- fs/ufs/inode.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 0f0c6dfccd105..5c4a4abae6524 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -465,9 +465,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff mutex_lock(&UFS_I(inode)->truncate_mutex); UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); - if (fragment > - ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) - << uspi->s_fpbshift)) + if (!depth) goto abort_too_big; err = 0; @@ -490,17 +488,17 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff ufs_inode_getblock(inode, bh, x, fragment, \ &err, NULL, NULL, NULL) - if (ptr < UFS_NDIR_FRAGMENT) { + if (depth == 1) { bh = GET_INODE_DATABLOCK(ptr); goto out; } ptr -= UFS_NDIR_FRAGMENT; - if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) { + if (depth == 2) { bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift)); goto get_indirect; } ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); - if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) { + if (depth == 3) { bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift)); goto get_double; } -- GitLab From bbb3eb9d3432ce55a620778ecf5670fa7942090e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 00:10:00 -0400 Subject: [PATCH 0518/7006] ufs_inode_get{frag,block}(): consolidate success exits These calling conventions are rudiments of pre-2.3 times; they really need to be sanitized. This is the first step; next will be _always_ returning a block number, instead of this "return a pointer to buffer_head, except when we get to the actual data" crap. Signed-off-by: Al Viro --- fs/ufs/inode.c | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 5c4a4abae6524..d65a89030c91d 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -226,7 +226,6 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct buffer_head * result; unsigned blockoff, lastblockoff; u64 tmp, goal, lastfrag, block, lastblock; void *p, *p2; @@ -249,14 +248,8 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, tmp = ufs_data_ptr_to_cpu(sb, p); lastfrag = ufsi->i_lastfrag; - if (tmp && fragment < lastfrag) { - if (!phys) { - return sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - } else { - *phys = uspi->s_sbbase + tmp + blockoff; - return NULL; - } - } + if (tmp && fragment < lastfrag) + goto out; lastblock = ufs_fragstoblks (lastfrag); lastblockoff = ufs_fragnum (lastfrag); @@ -314,20 +307,22 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, return NULL; } - if (!phys) { - result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - } else { - *phys = uspi->s_sbbase + tmp + blockoff; - result = NULL; + if (phys) { *err = 0; *new = 1; } - inode->i_ctime = CURRENT_TIME_SEC; if (IS_SYNC(inode)) ufs_sync_inode (inode); mark_inode_dirty(inode); - return result; +out: + tmp += uspi->s_sbbase + blockoff; + if (!phys) { + return sb_getblk(sb, tmp); + } else { + *phys = tmp; + return NULL; + } /* This part : To be implemented .... Required only for writing, not required for READ-ONLY. @@ -367,7 +362,7 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct buffer_head * result; unsigned blockoff; - u64 tmp, goal, block; + u64 tmp = 0, goal, block; void *p; block = ufs_fragstoblks (fragment); @@ -392,13 +387,8 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, p = (__fs32 *)bh->b_data + block; tmp = ufs_data_ptr_to_cpu(sb, p); - if (tmp) { - if (!phys) - result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - else - *phys = uspi->s_sbbase + tmp + blockoff; + if (tmp) goto out; - } if (block && (uspi->fs_magic == UFS2_MAGIC ? (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[block-1])) : @@ -411,12 +401,8 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, if (!tmp) goto out; - if (!phys) { - result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - } else { - *phys = uspi->s_sbbase + tmp + blockoff; + if (new) *new = 1; - } mark_buffer_dirty(bh); if (IS_SYNC(inode)) @@ -425,6 +411,14 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, mark_inode_dirty(inode); out: brelse (bh); + if (tmp) { + tmp += uspi->s_sbbase + blockoff; + if (phys) { + *phys = tmp; + } else { + result = sb_getblk(sb, tmp); + } + } UFSD("EXIT\n"); return result; } -- GitLab From 8d9dcf14367388674f4d792f494e6f1d6536ac95 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 00:32:42 -0400 Subject: [PATCH 0519/7006] ufs_getfrag_block(): get rid of macro jungles Signed-off-by: Al Viro --- fs/ufs/inode.c | 51 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index d65a89030c91d..156ba3c269068 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -465,49 +465,42 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff err = 0; ptr = fragment; - /* - * ok, these macros clean the logic up a bit and make - * it much more readable: - */ -#define GET_INODE_DATABLOCK(x) \ - ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\ - bh_result->b_page) -#define GET_INODE_PTR(x) \ - ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\ - bh_result->b_page) -#define GET_INDIRECT_DATABLOCK(x) \ - ufs_inode_getblock(inode, bh, x, fragment, \ - &err, &phys, &new, bh_result->b_page) -#define GET_INDIRECT_PTR(x) \ - ufs_inode_getblock(inode, bh, x, fragment, \ - &err, NULL, NULL, NULL) - if (depth == 1) { - bh = GET_INODE_DATABLOCK(ptr); + bh = ufs_inode_getfrag(inode, ptr, fragment, 1, &err, &phys, + &new, bh_result->b_page); goto out; } ptr -= UFS_NDIR_FRAGMENT; if (depth == 2) { - bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift)); + bh = ufs_inode_getfrag(inode, + UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift), + fragment, uspi->s_fpb, &err, NULL, NULL, + bh_result->b_page); goto get_indirect; } ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); if (depth == 3) { - bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift)); + bh = ufs_inode_getfrag(inode, + UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift), + fragment, uspi->s_fpb, &err, NULL, NULL, + bh_result->b_page); goto get_double; } ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); - bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift)); - bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask); + bh = ufs_inode_getfrag(inode, + UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift), + fragment, uspi->s_fpb, &err, NULL, NULL, + bh_result->b_page); + bh = ufs_inode_getblock(inode, bh, + (ptr >> uspi->s_2apbshift) & uspi->s_apbmask, + fragment, &err, NULL, NULL, NULL); get_double: - bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask); + bh = ufs_inode_getblock(inode, bh, + (ptr >> uspi->s_apbshift) & uspi->s_apbmask, + fragment, &err, NULL, NULL, NULL); get_indirect: - bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask); - -#undef GET_INODE_DATABLOCK -#undef GET_INODE_PTR -#undef GET_INDIRECT_DATABLOCK -#undef GET_INDIRECT_PTR + bh = ufs_inode_getblock(inode, bh, ptr & uspi->s_apbmask, fragment, + &err, &phys, &new, bh_result->b_page); out: if (err) -- GitLab From 177848a018cb2cb196feac2990814ac8d7bb3c8e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 00:53:06 -0400 Subject: [PATCH 0520/7006] ufs_inode_get{frag,block}(): leave sb_getblk() to caller just return the damn block number Signed-off-by: Al Viro --- fs/ufs/inode.c | 88 +++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 156ba3c269068..eeccf45fcd57f 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -218,7 +218,7 @@ changed: * @new: we set it if we allocate new block * @locked_page: for ufs_new_fragments() */ -static struct buffer_head * +static u64 ufs_inode_getfrag(struct inode *inode, u64 fragment, sector_t new_fragment, unsigned int required, int *err, long *phys, int *new, struct page *locked_page) @@ -267,7 +267,7 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, uspi->s_fpb - lastblockoff, err, locked_page); if (!tmp) - return NULL; + return 0; lastfrag = ufsi->i_lastfrag; } tmp = ufs_data_ptr_to_cpu(sb, @@ -304,7 +304,7 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, } if (!tmp) { *err = -ENOSPC; - return NULL; + return 0; } if (phys) { @@ -316,13 +316,7 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, ufs_sync_inode (inode); mark_inode_dirty(inode); out: - tmp += uspi->s_sbbase + blockoff; - if (!phys) { - return sb_getblk(sb, tmp); - } else { - *phys = tmp; - return NULL; - } + return tmp + uspi->s_sbbase; /* This part : To be implemented .... Required only for writing, not required for READ-ONLY. @@ -353,26 +347,22 @@ repeat2: * @new: see ufs_inode_getfrag() * @locked_page: see ufs_inode_getfrag() */ -static struct buffer_head * +static u64 ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, u64 fragment, sector_t new_fragment, int *err, long *phys, int *new, struct page *locked_page) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - struct buffer_head * result; - unsigned blockoff; u64 tmp = 0, goal, block; void *p; block = ufs_fragstoblks (fragment); - blockoff = ufs_fragnum (fragment); UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, metadata %d\n", inode->i_ino, (unsigned long long)fragment, (unsigned long long)new_fragment, !phys); - result = NULL; if (!bh) goto out; if (!buffer_uptodate(bh)) { @@ -411,16 +401,10 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, mark_inode_dirty(inode); out: brelse (bh); - if (tmp) { - tmp += uspi->s_sbbase + blockoff; - if (phys) { - *phys = tmp; - } else { - result = sb_getblk(sb, tmp); - } - } UFSD("EXIT\n"); - return result; + if (tmp) + tmp += uspi->s_sbbase; + return tmp; } /** @@ -439,11 +423,12 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); unsigned long ptr,phys; u64 phys64 = 0; + unsigned frag = fragment & uspi->s_fpbmask; if (!create) { phys64 = ufs_frag_map(inode, offsets, depth); if (phys64) { - phys64 += fragment & uspi->s_fpbmask; + phys64 += frag; map_bh(bh_result, sb, phys64); } return 0; @@ -466,42 +451,79 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff ptr = fragment; if (depth == 1) { - bh = ufs_inode_getfrag(inode, ptr, fragment, 1, &err, &phys, + phys64 = ufs_inode_getfrag(inode, ptr, fragment, 1, &err, &phys, &new, bh_result->b_page); + if (phys64) { + phys64 += frag; + phys = phys64; + } goto out; } ptr -= UFS_NDIR_FRAGMENT; if (depth == 2) { - bh = ufs_inode_getfrag(inode, + phys64 = ufs_inode_getfrag(inode, UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift), fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page); + if (phys64) { + phys64 += (ptr >> uspi->s_apbshift) & uspi->s_fpbmask; + bh = sb_getblk(sb, phys64); + } else { + bh = NULL; + } goto get_indirect; } ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); if (depth == 3) { - bh = ufs_inode_getfrag(inode, + phys64 = ufs_inode_getfrag(inode, UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift), fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page); + if (phys64) { + phys64 += (ptr >> uspi->s_2apbshift) & uspi->s_fpbmask; + bh = sb_getblk(sb, phys64); + } else { + bh = NULL; + } goto get_double; } ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); - bh = ufs_inode_getfrag(inode, + phys64 = ufs_inode_getfrag(inode, UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift), fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page); - bh = ufs_inode_getblock(inode, bh, + if (phys64) { + phys64 += (ptr >> uspi->s_3apbshift) & uspi->s_fpbmask; + bh = sb_getblk(sb, phys64); + } else { + bh = NULL; + } + phys64 = ufs_inode_getblock(inode, bh, (ptr >> uspi->s_2apbshift) & uspi->s_apbmask, fragment, &err, NULL, NULL, NULL); + if (phys64) { + phys64 += (ptr >> uspi->s_2apbshift) & uspi->s_fpbmask, + bh = sb_getblk(sb, phys64); + } else { + bh = NULL; + } get_double: - bh = ufs_inode_getblock(inode, bh, + phys64 = ufs_inode_getblock(inode, bh, (ptr >> uspi->s_apbshift) & uspi->s_apbmask, fragment, &err, NULL, NULL, NULL); + if (phys64) { + phys64 += (ptr >> uspi->s_apbshift) & uspi->s_fpbmask, + bh = sb_getblk(sb, phys64); + } else { + bh = NULL; + } get_indirect: - bh = ufs_inode_getblock(inode, bh, ptr & uspi->s_apbmask, fragment, + phys64 = ufs_inode_getblock(inode, bh, ptr & uspi->s_apbmask, fragment, &err, &phys, &new, bh_result->b_page); - + if (phys64) { + phys64 += frag; + phys = phys64; + } out: if (err) goto abort; -- GitLab From 721435a7679e13f810133dbea769f87ad7bae3a1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 01:06:21 -0400 Subject: [PATCH 0521/7006] ufs_inode_getblock(): pass index instead of 'fragment' The value passed to ufs_inode_getblock() as the 3rd argument had lower bits ignored; the upper bits were shifted down and used and they actually make sense - those are _lower_ bits of index in indirect block (i.e. they form the index within a fragment within an indirect block). Pass those as argument. Upper bits of index (i.e. the number of fragment within indirect block) will join them shortly. Signed-off-by: Al Viro --- fs/ufs/inode.c | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index eeccf45fcd57f..6866b904f148f 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -338,8 +338,7 @@ repeat2: * ufs_inode_getblock() - allocate new block * @inode: pointer to inode * @bh: pointer to block which hold "pointer" to new allocated block - * @fragment: number of `fragment' which hold pointer - * to new allocated block + * @index: number of pointer in the indirect block * @new_fragment: number of new allocated fragment * (block will hold this fragment and also uspi->s_fpb-1) * @err: see ufs_inode_getfrag() @@ -349,20 +348,14 @@ repeat2: */ static u64 ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, - u64 fragment, sector_t new_fragment, int *err, + unsigned index, sector_t new_fragment, int *err, long *phys, int *new, struct page *locked_page) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - u64 tmp = 0, goal, block; + u64 tmp = 0, goal; void *p; - block = ufs_fragstoblks (fragment); - - UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, metadata %d\n", - inode->i_ino, (unsigned long long)fragment, - (unsigned long long)new_fragment, !phys); - if (!bh) goto out; if (!buffer_uptodate(bh)) { @@ -372,17 +365,17 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, goto out; } if (uspi->fs_magic == UFS2_MAGIC) - p = (__fs64 *)bh->b_data + block; + p = (__fs64 *)bh->b_data + index; else - p = (__fs32 *)bh->b_data + block; + p = (__fs32 *)bh->b_data + index; tmp = ufs_data_ptr_to_cpu(sb, p); if (tmp) goto out; - if (block && (uspi->fs_magic == UFS2_MAGIC ? - (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[block-1])) : - (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[block-1])))) + if (index && (uspi->fs_magic == UFS2_MAGIC ? + (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[index-1])) : + (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[index-1])))) goal = tmp + uspi->s_fpb; else goal = bh->b_blocknr + uspi->s_fpb; @@ -424,6 +417,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff unsigned long ptr,phys; u64 phys64 = 0; unsigned frag = fragment & uspi->s_fpbmask; + unsigned mask = uspi->s_apbmask >> uspi->s_fpbshift; if (!create) { phys64 = ufs_frag_map(inode, offsets, depth); @@ -499,7 +493,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff bh = NULL; } phys64 = ufs_inode_getblock(inode, bh, - (ptr >> uspi->s_2apbshift) & uspi->s_apbmask, + offsets[1] & mask, fragment, &err, NULL, NULL, NULL); if (phys64) { phys64 += (ptr >> uspi->s_2apbshift) & uspi->s_fpbmask, @@ -509,7 +503,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff } get_double: phys64 = ufs_inode_getblock(inode, bh, - (ptr >> uspi->s_apbshift) & uspi->s_apbmask, + offsets[depth - 2] & mask, fragment, &err, NULL, NULL, NULL); if (phys64) { phys64 += (ptr >> uspi->s_apbshift) & uspi->s_fpbmask, @@ -518,8 +512,8 @@ get_double: bh = NULL; } get_indirect: - phys64 = ufs_inode_getblock(inode, bh, ptr & uspi->s_apbmask, fragment, - &err, &phys, &new, bh_result->b_page); + phys64 = ufs_inode_getblock(inode, bh, offsets[depth - 1] & mask, + fragment, &err, &phys, &new, bh_result->b_page); if (phys64) { phys64 += frag; phys = phys64; -- GitLab From 619cfac09134b4de7a4f232cf3636cf43728577d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 01:23:08 -0400 Subject: [PATCH 0522/7006] ufs_inode_getblock(): pass indirect block number and full index ... instead of messing with buffer_head. We can bloody well do sb_bread() in there. Signed-off-by: Al Viro --- fs/ufs/inode.c | 62 +++++++++++++------------------------------------- 1 file changed, 16 insertions(+), 46 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 6866b904f148f..25d47df934e29 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -337,8 +337,8 @@ repeat2: /** * ufs_inode_getblock() - allocate new block * @inode: pointer to inode - * @bh: pointer to block which hold "pointer" to new allocated block - * @index: number of pointer in the indirect block + * @ind_block: block number of the indirect block + * @index: number of pointer within the indirect block * @new_fragment: number of new allocated fragment * (block will hold this fragment and also uspi->s_fpb-1) * @err: see ufs_inode_getfrag() @@ -347,23 +347,25 @@ repeat2: * @locked_page: see ufs_inode_getfrag() */ static u64 -ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, +ufs_inode_getblock(struct inode *inode, u64 ind_block, unsigned index, sector_t new_fragment, int *err, long *phys, int *new, struct page *locked_page) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + int shift = uspi->s_apbshift - uspi->s_fpbshift; u64 tmp = 0, goal; + struct buffer_head *bh; void *p; - if (!bh) - goto out; - if (!buffer_uptodate(bh)) { - ll_rw_block (READ, 1, &bh); - wait_on_buffer (bh); - if (!buffer_uptodate(bh)) - goto out; - } + if (!ind_block) + return 0; + + bh = sb_bread(sb, ind_block + (index >> shift)); + if (unlikely(!bh)) + return 0; + + index &= uspi->s_apbmask >> uspi->s_fpbshift; if (uspi->fs_magic == UFS2_MAGIC) p = (__fs64 *)bh->b_data + index; else @@ -459,12 +461,6 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift), fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page); - if (phys64) { - phys64 += (ptr >> uspi->s_apbshift) & uspi->s_fpbmask; - bh = sb_getblk(sb, phys64); - } else { - bh = NULL; - } goto get_indirect; } ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); @@ -473,12 +469,6 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift), fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page); - if (phys64) { - phys64 += (ptr >> uspi->s_2apbshift) & uspi->s_fpbmask; - bh = sb_getblk(sb, phys64); - } else { - bh = NULL; - } goto get_double; } ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); @@ -486,33 +476,13 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift), fragment, uspi->s_fpb, &err, NULL, NULL, bh_result->b_page); - if (phys64) { - phys64 += (ptr >> uspi->s_3apbshift) & uspi->s_fpbmask; - bh = sb_getblk(sb, phys64); - } else { - bh = NULL; - } - phys64 = ufs_inode_getblock(inode, bh, - offsets[1] & mask, + phys64 = ufs_inode_getblock(inode, phys64, offsets[1], fragment, &err, NULL, NULL, NULL); - if (phys64) { - phys64 += (ptr >> uspi->s_2apbshift) & uspi->s_fpbmask, - bh = sb_getblk(sb, phys64); - } else { - bh = NULL; - } get_double: - phys64 = ufs_inode_getblock(inode, bh, - offsets[depth - 2] & mask, + phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 2], fragment, &err, NULL, NULL, NULL); - if (phys64) { - phys64 += (ptr >> uspi->s_apbshift) & uspi->s_fpbmask, - bh = sb_getblk(sb, phys64); - } else { - bh = NULL; - } get_indirect: - phys64 = ufs_inode_getblock(inode, bh, offsets[depth - 1] & mask, + phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], fragment, &err, &phys, &new, bh_result->b_page); if (phys64) { phys64 += frag; -- GitLab From 0f3c1294bedcc4544c68d6b84699bdaa334b11b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 13:40:25 -0400 Subject: [PATCH 0523/7006] ufs_inode_getfrag(): split extending the partial blocks off ufs_extend_tail() is handling that now. Signed-off-by: Al Viro --- fs/ufs/inode.c | 128 +++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 25d47df934e29..d652f64885fdf 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -205,6 +205,40 @@ changed: goto again; } +/* + * Unpacking tails: we have a file with partial final block and + * we had been asked to extend it. If the fragment being written + * is within the same block, we need to extend the tail just to cover + * that fragment. Otherwise the tail is extended to full block. + * + * Note that we might need to create a _new_ tail, but that will + * be handled elsewhere; this is strictly for resizing old + * ones. + */ +static bool +ufs_extend_tail(struct inode *inode, u64 writes_to, + int *err, struct page *locked_page) +{ + struct ufs_inode_info *ufsi = UFS_I(inode); + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + unsigned lastfrag = ufsi->i_lastfrag; /* it's a short file, so unsigned is enough */ + unsigned block = ufs_fragstoblks(lastfrag); + unsigned new_size; + void *p; + u64 tmp; + + if (writes_to < (lastfrag | uspi->s_fpbmask)) + new_size = (writes_to & uspi->s_fpbmask) + 1; + else + new_size = uspi->s_fpb; + + p = ufs_get_direct_data_ptr(uspi, ufsi, block); + tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p), + new_size, err, locked_page); + return tmp != 0; +} + /** * ufs_inode_getfrag() - allocate new fragment(s) * @inode: pointer to inode @@ -226,13 +260,10 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - unsigned blockoff, lastblockoff; - u64 tmp, goal, lastfrag, block, lastblock; - void *p, *p2; - - UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, required %u, " - "metadata %d\n", inode->i_ino, (unsigned long long)fragment, - (unsigned long long)new_fragment, required, !phys); + unsigned blockoff; + u64 tmp, goal, lastfrag, block; + unsigned nfrags = uspi->s_fpb; + void *p; /* TODO : to be done for write support if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) @@ -242,66 +273,27 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, block = ufs_fragstoblks (fragment); blockoff = ufs_fragnum (fragment); p = ufs_get_direct_data_ptr(uspi, ufsi, block); - - goal = 0; - tmp = ufs_data_ptr_to_cpu(sb, p); + if (tmp) + goto out; lastfrag = ufsi->i_lastfrag; - if (tmp && fragment < lastfrag) - goto out; - lastblock = ufs_fragstoblks (lastfrag); - lastblockoff = ufs_fragnum (lastfrag); - /* - * We will extend file into new block beyond last allocated block - */ - if (lastblock < block) { - /* - * We must reallocate last allocated block - */ - if (lastblockoff) { - p2 = ufs_get_direct_data_ptr(uspi, ufsi, lastblock); - tmp = ufs_new_fragments(inode, p2, lastfrag, - ufs_data_ptr_to_cpu(sb, p2), - uspi->s_fpb - lastblockoff, - err, locked_page); - if (!tmp) - return 0; - lastfrag = ufsi->i_lastfrag; - } - tmp = ufs_data_ptr_to_cpu(sb, - ufs_get_direct_data_ptr(uspi, ufsi, - lastblock)); - if (tmp) - goal = tmp + uspi->s_fpb; - tmp = ufs_new_fragments (inode, p, fragment - blockoff, - goal, required + blockoff, - err, - phys != NULL ? locked_page : NULL); - } else if (lastblock == block) { - /* - * We will extend last allocated block - */ - tmp = ufs_new_fragments(inode, p, fragment - - (blockoff - lastblockoff), - ufs_data_ptr_to_cpu(sb, p), - required + (blockoff - lastblockoff), - err, phys != NULL ? locked_page : NULL); - } else /* (lastblock > block) */ { - /* - * We will allocate new block before last allocated block - */ - if (block) { - tmp = ufs_data_ptr_to_cpu(sb, - ufs_get_direct_data_ptr(uspi, ufsi, block - 1)); - if (tmp) - goal = tmp + uspi->s_fpb; - } - tmp = ufs_new_fragments(inode, p, fragment - blockoff, - goal, uspi->s_fpb, err, - phys != NULL ? locked_page : NULL); + /* will that be a new tail? */ + if (new_fragment < UFS_NDIR_FRAGMENT && new_fragment >= lastfrag) + nfrags = (new_fragment & uspi->s_fpbmask) + 1; + + goal = 0; + if (block) { + goal = ufs_data_ptr_to_cpu(sb, + ufs_get_direct_data_ptr(uspi, ufsi, block - 1)); + if (goal) + goal += uspi->s_fpb; } + tmp = ufs_new_fragments(inode, p, fragment - blockoff, + goal, uspi->s_fpb, err, + phys != NULL ? locked_page : NULL); + if (!tmp) { *err = -ENOSPC; return 0; @@ -419,7 +411,6 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff unsigned long ptr,phys; u64 phys64 = 0; unsigned frag = fragment & uspi->s_fpbmask; - unsigned mask = uspi->s_apbmask >> uspi->s_fpbshift; if (!create) { phys64 = ufs_frag_map(inode, offsets, depth); @@ -444,6 +435,17 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff goto abort_too_big; err = 0; + + if (UFS_I(inode)->i_lastfrag < UFS_NDIR_FRAGMENT) { + unsigned lastfrag = UFS_I(inode)->i_lastfrag; + unsigned tailfrags = lastfrag & uspi->s_fpbmask; + if (tailfrags && fragment >= lastfrag) { + if (!ufs_extend_tail(inode, fragment, + &err, bh_result->b_page)) + goto abort; + } + } + ptr = fragment; if (depth == 1) { -- GitLab From 5336970be09becb2b59ac3812718b2cb80d33347 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 13:53:52 -0400 Subject: [PATCH 0524/7006] ufs_inode_getfrag(): pass index instead of 'fragment' same story as with ufs_inode_getblock() Signed-off-by: Al Viro --- fs/ufs/inode.c | 50 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index d652f64885fdf..c05cf14ef8ff4 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -242,10 +242,8 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, /** * ufs_inode_getfrag() - allocate new fragment(s) * @inode: pointer to inode - * @fragment: number of `fragment' which hold pointer - * to new allocated fragment(s) + * @index: number of block pointer within the inode's array. * @new_fragment: number of new allocated fragment(s) - * @required: how many fragment(s) we require * @err: we set it if something wrong * @phys: pointer to where we save physical number of new allocated fragments, * NULL if we allocate not data(indirect blocks for example). @@ -253,15 +251,14 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, * @locked_page: for ufs_new_fragments() */ static u64 -ufs_inode_getfrag(struct inode *inode, u64 fragment, - sector_t new_fragment, unsigned int required, int *err, +ufs_inode_getfrag(struct inode *inode, unsigned index, + sector_t new_fragment, int *err, long *phys, int *new, struct page *locked_page) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; - unsigned blockoff; - u64 tmp, goal, lastfrag, block; + u64 tmp, goal, lastfrag; unsigned nfrags = uspi->s_fpb; void *p; @@ -270,9 +267,7 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, goto ufs2; */ - block = ufs_fragstoblks (fragment); - blockoff = ufs_fragnum (fragment); - p = ufs_get_direct_data_ptr(uspi, ufsi, block); + p = ufs_get_direct_data_ptr(uspi, ufsi, index); tmp = ufs_data_ptr_to_cpu(sb, p); if (tmp) goto out; @@ -284,13 +279,13 @@ ufs_inode_getfrag(struct inode *inode, u64 fragment, nfrags = (new_fragment & uspi->s_fpbmask) + 1; goal = 0; - if (block) { + if (index) { goal = ufs_data_ptr_to_cpu(sb, - ufs_get_direct_data_ptr(uspi, ufsi, block - 1)); + ufs_get_direct_data_ptr(uspi, ufsi, index - 1)); if (goal) goal += uspi->s_fpb; } - tmp = ufs_new_fragments(inode, p, fragment - blockoff, + tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err, phys != NULL ? locked_page : NULL); @@ -408,7 +403,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff int ret, err, new; unsigned offsets[4]; int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); - unsigned long ptr,phys; + unsigned long phys; u64 phys64 = 0; unsigned frag = fragment & uspi->s_fpbmask; @@ -446,38 +441,27 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff } } - ptr = fragment; - if (depth == 1) { - phys64 = ufs_inode_getfrag(inode, ptr, fragment, 1, &err, &phys, - &new, bh_result->b_page); + phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, + &err, &phys, &new, bh_result->b_page); if (phys64) { phys64 += frag; phys = phys64; } goto out; } - ptr -= UFS_NDIR_FRAGMENT; if (depth == 2) { - phys64 = ufs_inode_getfrag(inode, - UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift), - fragment, uspi->s_fpb, &err, NULL, NULL, - bh_result->b_page); + phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, + &err, NULL, NULL, bh_result->b_page); goto get_indirect; } - ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift); if (depth == 3) { - phys64 = ufs_inode_getfrag(inode, - UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift), - fragment, uspi->s_fpb, &err, NULL, NULL, - bh_result->b_page); + phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, + &err, NULL, NULL, bh_result->b_page); goto get_double; } - ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift); - phys64 = ufs_inode_getfrag(inode, - UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift), - fragment, uspi->s_fpb, &err, NULL, NULL, - bh_result->b_page); + phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, + &err, NULL, NULL, bh_result->b_page); phys64 = ufs_inode_getblock(inode, phys64, offsets[1], fragment, &err, NULL, NULL, NULL); get_double: -- GitLab From 4eeff4c9326878ff58ef6fe68d2bf22ef877e5a2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 14:08:16 -0400 Subject: [PATCH 0525/7006] ufs_getfrag_block(): turn following indirects into a loop Signed-off-by: Al Viro --- fs/ufs/inode.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index c05cf14ef8ff4..f2d8cc2166afe 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -444,37 +444,21 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff if (depth == 1) { phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, &err, &phys, &new, bh_result->b_page); - if (phys64) { - phys64 += frag; - phys = phys64; - } - goto out; - } - if (depth == 2) { - phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, - &err, NULL, NULL, bh_result->b_page); - goto get_indirect; - } - if (depth == 3) { + } else { + int i; phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, &err, NULL, NULL, bh_result->b_page); - goto get_double; + for (i = 1; i < depth - 1; i++) + phys64 = ufs_inode_getblock(inode, phys64, offsets[i], + fragment, &err, NULL, NULL, NULL); + phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], + fragment, &err, &phys, &new, bh_result->b_page); } - phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, - &err, NULL, NULL, bh_result->b_page); - phys64 = ufs_inode_getblock(inode, phys64, offsets[1], - fragment, &err, NULL, NULL, NULL); -get_double: - phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 2], - fragment, &err, NULL, NULL, NULL); -get_indirect: - phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], - fragment, &err, &phys, &new, bh_result->b_page); +out: if (phys64) { phys64 += frag; phys = phys64; } -out: if (err) goto abort; if (new) -- GitLab From 5fbfb238f7a0a5c4633438eb5bdfb4810995c76a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 14:10:53 -0400 Subject: [PATCH 0526/7006] ufs_inode_getblock(): failure to read an indirect block is -EIO ... and not "write to beginning of the disk", TYVM... Signed-off-by: Al Viro --- fs/ufs/inode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index f2d8cc2166afe..ed70147e1cb41 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -349,8 +349,10 @@ ufs_inode_getblock(struct inode *inode, u64 ind_block, return 0; bh = sb_bread(sb, ind_block + (index >> shift)); - if (unlikely(!bh)) + if (unlikely(!bh)) { + *err = -EIO; return 0; + } index &= uspi->s_apbmask >> uspi->s_fpbshift; if (uspi->fs_magic == UFS2_MAGIC) @@ -454,7 +456,6 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], fragment, &err, &phys, &new, bh_result->b_page); } -out: if (phys64) { phys64 += frag; phys = phys64; -- GitLab From 0385f1f9e3e5cb17047474037002500383237f47 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 14:20:21 -0400 Subject: [PATCH 0527/7006] ufs_getfrag_block(): tidy up a bit Signed-off-by: Al Viro --- fs/ufs/inode.c | 48 +++++++++++++++--------------------------------- 1 file changed, 15 insertions(+), 33 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index ed70147e1cb41..7f551b3e3ba4f 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -398,40 +398,30 @@ out: static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create) { - struct super_block * sb = inode->i_sb; - struct ufs_sb_info * sbi = UFS_SB(sb); - struct ufs_sb_private_info * uspi = sbi->s_uspi; - struct buffer_head * bh; - int ret, err, new; + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + int err = 0, new = 0; unsigned offsets[4]; int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); - unsigned long phys; u64 phys64 = 0; + unsigned long phys; unsigned frag = fragment & uspi->s_fpbmask; if (!create) { phys64 = ufs_frag_map(inode, offsets, depth); - if (phys64) { - phys64 += frag; - map_bh(bh_result, sb, phys64); - } - return 0; + goto out; } /* This code entered only while writing ....? */ - err = -EIO; - new = 0; - ret = 0; - bh = NULL; - mutex_lock(&UFS_I(inode)->truncate_mutex); UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); - if (!depth) - goto abort_too_big; - - err = 0; + if (unlikely(!depth)) { + ufs_warning(sb, "ufs_get_block", "block > big"); + err = -EIO; + goto out; + } if (UFS_I(inode)->i_lastfrag < UFS_NDIR_FRAGMENT) { unsigned lastfrag = UFS_I(inode)->i_lastfrag; @@ -439,7 +429,7 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff if (tailfrags && fragment >= lastfrag) { if (!ufs_extend_tail(inode, fragment, &err, bh_result->b_page)) - goto abort; + goto out; } } @@ -456,23 +446,15 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], fragment, &err, &phys, &new, bh_result->b_page); } +out: if (phys64) { phys64 += frag; - phys = phys64; + map_bh(bh_result, sb, phys64); + if (new) + set_buffer_new(bh_result); } - if (err) - goto abort; - if (new) - set_buffer_new(bh_result); - map_bh(bh_result, sb, phys); -abort: mutex_unlock(&UFS_I(inode)->truncate_mutex); - return err; - -abort_too_big: - ufs_warning(sb, "ufs_get_block", "block > big"); - goto abort; } static int ufs_writepage(struct page *page, struct writeback_control *wbc) -- GitLab From 4e317ce73aecb735f389ab0d42ae3197a55265e4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 19 Jun 2015 14:27:10 -0400 Subject: [PATCH 0528/7006] ufs_inode_get{frag,block}(): get rid of 'phys' argument Just pass NULL as locked_page in case of first block in the indirect chain. Old calling conventions aside, a reason for having 'phys' was that ufs_inode_getfrag() used to be able to do _two_ allocations - indirect block and extending/reallocating a tail. We needed locked_page for the latter (it's a data), but we also needed to figure out that indirect block is metadata. So we used to pass non-NULL locked_page in all cases *and* used NULL phys as indication of being asked to allocate an indirect. With tail unpacking taken into a separate function we don't need those convolutions anymore. Signed-off-by: Al Viro --- fs/ufs/inode.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 7f551b3e3ba4f..a064cf44b1435 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -245,15 +245,13 @@ ufs_extend_tail(struct inode *inode, u64 writes_to, * @index: number of block pointer within the inode's array. * @new_fragment: number of new allocated fragment(s) * @err: we set it if something wrong - * @phys: pointer to where we save physical number of new allocated fragments, - * NULL if we allocate not data(indirect blocks for example). * @new: we set it if we allocate new block * @locked_page: for ufs_new_fragments() */ static u64 ufs_inode_getfrag(struct inode *inode, unsigned index, sector_t new_fragment, int *err, - long *phys, int *new, struct page *locked_page) + int *new, struct page *locked_page) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block *sb = inode->i_sb; @@ -286,18 +284,15 @@ ufs_inode_getfrag(struct inode *inode, unsigned index, goal += uspi->s_fpb; } tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), - goal, uspi->s_fpb, err, - phys != NULL ? locked_page : NULL); + goal, uspi->s_fpb, err, locked_page); if (!tmp) { *err = -ENOSPC; return 0; } - if (phys) { - *err = 0; + if (new) *new = 1; - } inode->i_ctime = CURRENT_TIME_SEC; if (IS_SYNC(inode)) ufs_sync_inode (inode); @@ -329,14 +324,13 @@ repeat2: * @new_fragment: number of new allocated fragment * (block will hold this fragment and also uspi->s_fpb-1) * @err: see ufs_inode_getfrag() - * @phys: see ufs_inode_getfrag() * @new: see ufs_inode_getfrag() * @locked_page: see ufs_inode_getfrag() */ static u64 ufs_inode_getblock(struct inode *inode, u64 ind_block, unsigned index, sector_t new_fragment, int *err, - long *phys, int *new, struct page *locked_page) + int *new, struct page *locked_page) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; @@ -404,7 +398,6 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff unsigned offsets[4]; int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets); u64 phys64 = 0; - unsigned long phys; unsigned frag = fragment & uspi->s_fpbmask; if (!create) { @@ -435,16 +428,16 @@ static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buff if (depth == 1) { phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, - &err, &phys, &new, bh_result->b_page); + &err, &new, bh_result->b_page); } else { int i; phys64 = ufs_inode_getfrag(inode, offsets[0], fragment, - &err, NULL, NULL, bh_result->b_page); + &err, NULL, NULL); for (i = 1; i < depth - 1; i++) phys64 = ufs_inode_getblock(inode, phys64, offsets[i], - fragment, &err, NULL, NULL, NULL); + fragment, &err, NULL, NULL); phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1], - fragment, &err, &phys, &new, bh_result->b_page); + fragment, &err, &new, bh_result->b_page); } out: if (phys64) { -- GitLab From ec7478fa173f65e5ee5fd2ba42c59ca3e700027b Mon Sep 17 00:00:00 2001 From: shengyong Date: Thu, 25 Jun 2015 02:23:13 +0000 Subject: [PATCH 0529/7006] mtd: nandsim: fix free of NULL pointer If allocating ns->nand_pages_slab fails, do not try to destroy it when cleaning up nandsim resources. Signed-off-by: Sheng Yong Signed-off-by: Brian Norris --- drivers/mtd/nand/nandsim.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 52c0c1a3899cd..6a74f62a00337 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -649,7 +649,8 @@ static void free_device(struct nandsim *ns) kmem_cache_free(ns->nand_pages_slab, ns->pages[i].byte); } - kmem_cache_destroy(ns->nand_pages_slab); + if (ns->nand_pages_slab) + kmem_cache_destroy(ns->nand_pages_slab); vfree(ns->pages); } } -- GitLab From 5891a8d11f79b9a45a7334a63d0fa731875bc308 Mon Sep 17 00:00:00 2001 From: shengyong Date: Thu, 25 Jun 2015 02:23:14 +0000 Subject: [PATCH 0530/7006] mtd: nandsim: fix double free Do not call free_device() in init_nandsim, the caller - ns_init_module - will take care of that if something goes wrong. Signed-off-by: Sheng Yong Signed-off-by: Brian Norris --- drivers/mtd/nand/nandsim.c | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 6a74f62a00337..95d0cc49cfc2f 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -730,8 +730,7 @@ static int init_nandsim(struct mtd_info *mtd) /* Fill the partition_info structure */ if (parts_num > ARRAY_SIZE(ns->partitions)) { NS_ERR("too many partitions.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } remains = ns->geom.totsz; next_offset = 0; @@ -740,14 +739,12 @@ static int init_nandsim(struct mtd_info *mtd) if (!part_sz || part_sz > remains) { NS_ERR("bad partition size.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } ns->partitions[i].name = get_partition_name(i); if (!ns->partitions[i].name) { NS_ERR("unable to allocate memory.\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } ns->partitions[i].offset = next_offset; ns->partitions[i].size = part_sz; @@ -758,14 +755,12 @@ static int init_nandsim(struct mtd_info *mtd) if (remains) { if (parts_num + 1 > ARRAY_SIZE(ns->partitions)) { NS_ERR("too many partitions.\n"); - ret = -EINVAL; - goto error; + return -EINVAL; } ns->partitions[i].name = get_partition_name(i); if (!ns->partitions[i].name) { NS_ERR("unable to allocate memory.\n"); - ret = -ENOMEM; - goto error; + return -ENOMEM; } ns->partitions[i].offset = next_offset; ns->partitions[i].size = remains; @@ -793,24 +788,18 @@ static int init_nandsim(struct mtd_info *mtd) printk("options: %#x\n", ns->options); if ((ret = alloc_device(ns)) != 0) - goto error; + return ret; /* Allocate / initialize the internal buffer */ ns->buf.byte = kmalloc(ns->geom.pgszoob, GFP_KERNEL); if (!ns->buf.byte) { NS_ERR("init_nandsim: unable to allocate %u bytes for the internal buffer\n", ns->geom.pgszoob); - ret = -ENOMEM; - goto error; + return -ENOMEM; } memset(ns->buf.byte, 0xFF, ns->geom.pgszoob); return 0; - -error: - free_device(ns); - - return ret; } /* -- GitLab From fce9a74ba46fb545ad81cf244f3a1af4a877606c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 18:43:44 -0300 Subject: [PATCH 0531/7006] dmaengine: imx-dma: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. While at it, change the label 'err' to a more descriptive naming. Signed-off-by: Fabio Estevam Signed-off-by: Vinod Koul --- drivers/dma/imx-dma.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c index 865501fcc67d7..139c5676cd747 100644 --- a/drivers/dma/imx-dma.c +++ b/drivers/dma/imx-dma.c @@ -1083,8 +1083,12 @@ static int __init imxdma_probe(struct platform_device *pdev) if (IS_ERR(imxdma->dma_ahb)) return PTR_ERR(imxdma->dma_ahb); - clk_prepare_enable(imxdma->dma_ipg); - clk_prepare_enable(imxdma->dma_ahb); + ret = clk_prepare_enable(imxdma->dma_ipg); + if (ret) + return ret; + ret = clk_prepare_enable(imxdma->dma_ahb); + if (ret) + goto disable_dma_ipg_clk; /* reset DMA module */ imx_dmav1_writel(imxdma, DCR_DRST, DMA_DCR); @@ -1094,20 +1098,20 @@ static int __init imxdma_probe(struct platform_device *pdev) dma_irq_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register IRQ for DMA\n"); - goto err; + goto disable_dma_ahb_clk; } irq_err = platform_get_irq(pdev, 1); if (irq_err < 0) { ret = irq_err; - goto err; + goto disable_dma_ahb_clk; } ret = devm_request_irq(&pdev->dev, irq_err, imxdma_err_handler, 0, "DMA", imxdma); if (ret) { dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n"); - goto err; + goto disable_dma_ahb_clk; } } @@ -1144,7 +1148,7 @@ static int __init imxdma_probe(struct platform_device *pdev) dev_warn(imxdma->dev, "Can't register IRQ %d " "for DMA channel %d\n", irq + i, i); - goto err; + goto disable_dma_ahb_clk; } init_timer(&imxdmac->watchdog); imxdmac->watchdog.function = &imxdma_watchdog; @@ -1190,7 +1194,7 @@ static int __init imxdma_probe(struct platform_device *pdev) ret = dma_async_device_register(&imxdma->dma_device); if (ret) { dev_err(&pdev->dev, "unable to register\n"); - goto err; + goto disable_dma_ahb_clk; } if (pdev->dev.of_node) { @@ -1206,9 +1210,10 @@ static int __init imxdma_probe(struct platform_device *pdev) err_of_dma_controller: dma_async_device_unregister(&imxdma->dma_device); -err: - clk_disable_unprepare(imxdma->dma_ipg); +disable_dma_ahb_clk: clk_disable_unprepare(imxdma->dma_ahb); +disable_dma_ipg_clk: + clk_disable_unprepare(imxdma->dma_ipg); return ret; } -- GitLab From 4483320e241c5f6b63caa912343eb73c8b1dfd18 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 26 Jun 2015 16:04:48 +0530 Subject: [PATCH 0532/7006] dmaengine: Use Pointer xt after NULL check. Removing static analysis error:- Possible null pointer dereference: xt Because currently xt is dereferenced before NULL check, Thus Use it after NULL Check. Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Acked-by: Nicolas Ferre Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index 59892126d1758..d313acbb50e00 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -659,14 +659,14 @@ atc_prep_dma_interleaved(struct dma_chan *chan, size_t len = 0; int i; + if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) + return NULL; + dev_info(chan2dev(chan), "%s: src=0x%08x, dest=0x%08x, numf=%d, frame_size=%d, flags=0x%lx\n", __func__, xt->src_start, xt->dst_start, xt->numf, xt->frame_size, flags); - if (unlikely(!xt || xt->numf != 1 || !xt->frame_size)) - return NULL; - /* * The controller can only "skip" X bytes every Y bytes, so we * need to make sure we are given a template that fit that -- GitLab From 7618d0359c167d89d7e904a00487be4945c10a65 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 24 Jun 2015 10:49:59 -0700 Subject: [PATCH 0533/7006] dmaengine: ioatdma: Set non RAID channels to be private capable This allows claiming of non-RAID channels as a private channel. This prevents breakage of MDRAID using the IOATDMA channels via async_tx but also allows agents such as NTB to claim channels exclusively for its usages. Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma_v3.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c index 64790a45ef5d8..8fbffd038113c 100644 --- a/drivers/dma/ioat/dma_v3.c +++ b/drivers/dma/ioat/dma_v3.c @@ -1694,6 +1694,9 @@ int ioat3_dma_probe(struct ioatdma_device *device, int dca) } } + if (!(device->cap & (IOAT_CAP_XOR | IOAT_CAP_PQ))) + dma_cap_set(DMA_PRIVATE, dma->cap_mask); + err = ioat_probe(device); if (err) return err; -- GitLab From 3cb43cc0b408c4672ba94fe28406a90a94b1edfe Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 08:43:03 +0200 Subject: [PATCH 0534/7006] drm: Update plane->fb also for page_flip The legacy page_flip driver entry point is the only one left which requires drivers to update plane->fb themselves. All the other entry hooks will patch things up for the driver as needed since no one seems to reliable get this right, see e.g. drm_mode_set_config_internal or the plane->fb/old_fb handling in drm_mode_atomic_ioctl. Therefore unify things, which allows us to ditch a TODO from drm_atomic_helper_page_flip. This should also help the atomic transition in i915 since we keep a bit of legacy cruft only around because of this special behaviour in ->page_flip. Cc: Maarten Lankhorst Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 4 ---- drivers/gpu/drm/drm_crtc.c | 8 +------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5b59d5ad7d1c2..0898afbc9e23e 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1915,10 +1915,6 @@ retry: if (ret != 0) goto fail; - /* TODO: ->page_flip is the only driver callback where the core - * doesn't update plane->fb. For now patch it up here. */ - plane->fb = plane->state->fb; - /* Driver takes ownership of state on successful async commit. */ return 0; fail: diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 0bf46d5ee221b..2bbb232e80d7b 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -5345,13 +5345,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev, /* Keep the old fb, don't unref it. */ crtc->primary->old_fb = NULL; } else { - /* - * Warn if the driver hasn't properly updated the crtc->fb - * field to reflect that the new framebuffer is now used. - * Failing to do so will screw with the reference counting - * on framebuffers. - */ - WARN_ON(crtc->primary->fb != fb); + crtc->primary->fb = fb; /* Unref only the old framebuffer. */ fb = NULL; } -- GitLab From ec9f932ed41622d120de52a5b525e4d77b9ef17e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Wed, 24 Jun 2015 08:59:25 +0200 Subject: [PATCH 0535/7006] drm/atomic: Cleanup on error properly in the atomic ioctl. It's probably allowed to leave old_fb set to garbage when unlocking, but to prevent undefined behavior unset it just in case. Also crtc_state->event could be NULL on memory allocation failure, in which case event_space is increased for no reason. Note: Contains some general simplification of the cleanup code too. Signed-off-by: Maarten Lankhorst [danvet: Add note about the other changes in here. And fix long line while at it.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 64 +++++++++++++++++------------------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index bd7f723c708ee..acebd1617264c 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1463,18 +1463,18 @@ retry: if (get_user(obj_id, objs_ptr + copied_objs)) { ret = -EFAULT; - goto fail; + goto out; } obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY); if (!obj || !obj->properties) { ret = -ENOENT; - goto fail; + goto out; } if (get_user(count_props, count_props_ptr + copied_objs)) { ret = -EFAULT; - goto fail; + goto out; } copied_objs++; @@ -1486,25 +1486,25 @@ retry: if (get_user(prop_id, props_ptr + copied_props)) { ret = -EFAULT; - goto fail; + goto out; } prop = drm_property_find(dev, prop_id); if (!prop) { ret = -ENOENT; - goto fail; + goto out; } if (copy_from_user(&prop_value, prop_values_ptr + copied_props, sizeof(prop_value))) { ret = -EFAULT; - goto fail; + goto out; } ret = atomic_set_prop(state, obj, prop, prop_value); if (ret) - goto fail; + goto out; copied_props++; } @@ -1523,7 +1523,7 @@ retry: e = create_vblank_event(dev, file_priv, arg->user_data); if (!e) { ret = -ENOMEM; - goto fail; + goto out; } crtc_state->event = e; @@ -1533,13 +1533,15 @@ retry: if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { ret = drm_atomic_check_only(state); /* _check_only() does not free state, unlike _commit() */ - drm_atomic_state_free(state); + if (!ret) + drm_atomic_state_free(state); } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { ret = drm_atomic_async_commit(state); } else { ret = drm_atomic_commit(state); } +out: /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping * locks (ie. while it is still safe to deref plane->state). We * need to do this here because the driver entry points cannot @@ -1552,41 +1554,35 @@ retry: drm_framebuffer_reference(new_fb); plane->fb = new_fb; plane->crtc = plane->state->crtc; - } else { - plane->old_fb = NULL; - } - if (plane->old_fb) { - drm_framebuffer_unreference(plane->old_fb); - plane->old_fb = NULL; + + if (plane->old_fb) + drm_framebuffer_unreference(plane->old_fb); } + plane->old_fb = NULL; } - drm_modeset_drop_locks(&ctx); - drm_modeset_acquire_fini(&ctx); - - return ret; + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(&ctx); + goto retry; + } -fail: - if (ret == -EDEADLK) - goto backoff; + if (ret) { + if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->event) + continue; - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - for_each_crtc_in_state(state, crtc, crtc_state, i) { - destroy_vblank_event(dev, file_priv, crtc_state->event); - crtc_state->event = NULL; + destroy_vblank_event(dev, file_priv, + crtc_state->event); + } } - } - drm_atomic_state_free(state); + drm_atomic_state_free(state); + } drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); return ret; - -backoff: - drm_atomic_state_clear(state); - drm_modeset_backoff(&ctx); - - goto retry; } -- GitLab From 3fec3d2f0a54d7c57c386c430bee2d6e5425ebfb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 09:10:07 +0200 Subject: [PATCH 0536/7006] drm/i915: Ditch SUPPORTS_INTEGRATED_HDMI|DP and use IS_G4X instead MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since that's really what we want to test for. Note remove the gen5 case doesn't change anything: In intel_setup_outputs ilk is handled already in the HAS_PCH_SPLIT case, and the register save/restore code touches registers which simply doesn't exist anymore at all. v2: Drop UMS parts. v3: Update commit message to reflect that the reg save/restore code is gone (Ville). Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 -- drivers/gpu/drm/i915/intel_display.c | 10 +++++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 093d6421dddfa..952e242a6e716 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2519,8 +2519,6 @@ struct drm_i915_cmd_table { #define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) #define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) -#define SUPPORTS_INTEGRATED_HDMI(dev) (IS_G4X(dev) || IS_GEN5(dev)) -#define SUPPORTS_INTEGRATED_DP(dev) (IS_G4X(dev) || IS_GEN5(dev)) #define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) #define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index eb50f59d7840a..99bf147b2f686 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14312,12 +14312,12 @@ static void intel_setup_outputs(struct drm_device *dev) if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { DRM_DEBUG_KMS("probing SDVOB\n"); found = intel_sdvo_init(dev, GEN3_SDVOB, true); - if (!found && SUPPORTS_INTEGRATED_HDMI(dev)) { + if (!found && IS_G4X(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOB\n"); intel_hdmi_init(dev, GEN4_HDMIB, PORT_B); } - if (!found && SUPPORTS_INTEGRATED_DP(dev)) + if (!found && IS_G4X(dev)) intel_dp_init(dev, DP_B, PORT_B); } @@ -14330,15 +14330,15 @@ static void intel_setup_outputs(struct drm_device *dev) if (!found && (I915_READ(GEN3_SDVOC) & SDVO_DETECTED)) { - if (SUPPORTS_INTEGRATED_HDMI(dev)) { + if (IS_G4X(dev)) { DRM_DEBUG_KMS("probing HDMI on SDVOC\n"); intel_hdmi_init(dev, GEN4_HDMIC, PORT_C); } - if (SUPPORTS_INTEGRATED_DP(dev)) + if (IS_G4X(dev)) intel_dp_init(dev, DP_C, PORT_C); } - if (SUPPORTS_INTEGRATED_DP(dev) && + if (IS_G4X(dev) && (I915_READ(DP_D) & DP_DETECTED)) intel_dp_init(dev, DP_D, PORT_D); } else if (IS_GEN2(dev)) -- GitLab From 6adfb1ef106bfe4b5ecb8bd75c4d037741d28a48 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 09:10:40 +0200 Subject: [PATCH 0537/7006] drm/i915: s/mdelay/msleep/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Burning cpu cycles isn't awesome, so use sleeps instead. Signed-off-by: Daniel Vetter Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 99bf147b2f686..737e939cf0f4e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1026,7 +1026,7 @@ static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe) line_mask = DSL_LINEMASK_GEN3; line1 = I915_READ(reg) & line_mask; - mdelay(5); + msleep(5); line2 = I915_READ(reg) & line_mask; return line1 == line2; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 6eb5d76e69120..1efac89cb7383 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4255,7 +4255,7 @@ static void ironlake_enable_drps(struct drm_device *dev) if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) DRM_ERROR("stuck trying to change perf mode\n"); - mdelay(1); + msleep(1); ironlake_set_drps(dev, fstart); @@ -4286,10 +4286,10 @@ static void ironlake_disable_drps(struct drm_device *dev) /* Go back to the starting frequency */ ironlake_set_drps(dev, dev_priv->ips.fstart); - mdelay(1); + msleep(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); - mdelay(1); + msleep(1); spin_unlock_irq(&mchdev_lock); } -- GitLab From 09da55dc84782b9b3fd8291719460da2d13bd27c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 7 Jul 2015 11:44:32 +0200 Subject: [PATCH 0538/7006] drm/i915: Inline SUPPORTS_DIGITAL_OUTPUTS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After the register save/restore code is gone there's just one user left and it just obfuscates that one. Remove it. Cc: Ville Syrjälä Suggested-by: Ville Syrjälä Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/intel_display.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 952e242a6e716..464b28d5e6781 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2518,7 +2518,6 @@ struct drm_i915_cmd_table { */ #define HAS_128_BYTE_Y_TILING(dev) (!IS_GEN2(dev) && !(IS_I915G(dev) || \ IS_I915GM(dev))) -#define SUPPORTS_DIGITAL_OUTPUTS(dev) (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) #define SUPPORTS_TV(dev) (INTEL_INFO(dev)->supports_tv) #define I915_HAS_HOTPLUG(dev) (INTEL_INFO(dev)->has_hotplug) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 737e939cf0f4e..3c2425f5366d3 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14306,7 +14306,7 @@ static void intel_setup_outputs(struct drm_device *dev) } intel_dsi_init(dev); - } else if (SUPPORTS_DIGITAL_OUTPUTS(dev)) { + } else if (!IS_GEN2(dev) && !IS_PINEVIEW(dev)) { bool found = false; if (I915_READ(GEN3_SDVOB) & SDVO_DETECTED) { -- GitLab From e22579713ae1384a3dff545369cebe42b01370fa Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Fri, 5 Jun 2015 10:19:06 +0200 Subject: [PATCH 0539/7006] ASoC: simple card: set cpu-dai sysclk with mclk-fs Allows to request a specific mclk frequency per cpu_dai. To support some codecs with mclk provided by the cpu_dai, the mclk rate must be set depending on frame rate. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/generic/simple-card.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c index d5554939146e8..3ff76d419436e 100644 --- a/sound/soc/generic/simple-card.c +++ b/sound/soc/generic/simple-card.c @@ -76,6 +76,7 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; struct simple_card_data *priv = snd_soc_card_get_drvdata(rtd->card); struct simple_dai_props *dai_props = &priv->dai_props[rtd - rtd->card->rtd]; @@ -91,8 +92,16 @@ static int asoc_simple_card_hw_params(struct snd_pcm_substream *substream, mclk = params_rate(params) * mclk_fs; ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN); + if (ret && ret != -ENOTSUPP) + goto err; + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret && ret != -ENOTSUPP) + goto err; } +err: return ret; } -- GitLab From 6702dfcc571d962df499f7466f54e07d044e6cd1 Mon Sep 17 00:00:00 2001 From: Sergey Kiselev Date: Fri, 5 Jun 2015 11:55:27 -0700 Subject: [PATCH 0540/7006] ASoC: wm8731: initialize the hardware when loading the codec driver This patch moves the requesting supplies, hardware reset and initialization from wm8731_probe to wm8731_i2c_probe and wm8731_spi_probe. So that the codec hardware is initialized when loading the codec driver, and not when loading the machine driver. This avoids unnecesary hardware resets and re-initializations when re-loading the machine driver. Signed-off-by: Sergey Kiselev Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 74 ++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 915ea11ad4b63..f22935a36a0a9 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -84,7 +84,7 @@ static bool wm8731_writeable(struct device *dev, unsigned int reg) return reg <= WM8731_RESET; } -#define wm8731_reset(c) snd_soc_write(c, WM8731_RESET, 0) +#define wm8731_reset(m) regmap_write(m, WM8731_RESET, 0) static const char *wm8731_input_select[] = {"Line In", "Mic"}; @@ -571,69 +571,63 @@ static struct snd_soc_dai_driver wm8731_dai = { .symmetric_rates = 1, }; -static int wm8731_probe(struct snd_soc_codec *codec) +static int wm8731_request_supplies(struct device *dev, + struct wm8731_priv *wm8731) { - struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); int ret = 0, i; for (i = 0; i < ARRAY_SIZE(wm8731->supplies); i++) wm8731->supplies[i].supply = wm8731_supply_names[i]; - ret = devm_regulator_bulk_get(codec->dev, ARRAY_SIZE(wm8731->supplies), + ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(wm8731->supplies), wm8731->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); + dev_err(dev, "Failed to request supplies: %d\n", ret); return ret; } ret = regulator_bulk_enable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); if (ret != 0) { - dev_err(codec->dev, "Failed to enable supplies: %d\n", ret); + dev_err(dev, "Failed to enable supplies: %d\n", ret); return ret; } - ret = wm8731_reset(codec); + return 0; +} + +static int wm8731_hw_init(struct device *dev, struct wm8731_priv *wm8731) +{ + int ret = 0; + + ret = wm8731_reset(wm8731->regmap); if (ret < 0) { - dev_err(codec->dev, "Failed to issue reset: %d\n", ret); + dev_err(dev, "Failed to issue reset: %d\n", ret); goto err_regulator_enable; } - snd_soc_codec_force_bias_level(codec, SND_SOC_BIAS_STANDBY); + /* Clear POWEROFF, keep everything else disabled */ + regmap_write(wm8731->regmap, WM8731_PWR, 0x7f); /* Latch the update bits */ - snd_soc_update_bits(codec, WM8731_LOUT1V, 0x100, 0); - snd_soc_update_bits(codec, WM8731_ROUT1V, 0x100, 0); - snd_soc_update_bits(codec, WM8731_LINVOL, 0x100, 0); - snd_soc_update_bits(codec, WM8731_RINVOL, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_LOUT1V, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_ROUT1V, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_LINVOL, 0x100, 0); + regmap_update_bits(wm8731->regmap, WM8731_RINVOL, 0x100, 0); /* Disable bypass path by default */ - snd_soc_update_bits(codec, WM8731_APANA, 0x8, 0); + regmap_update_bits(wm8731->regmap, WM8731_APANA, 0x8, 0); - /* Regulators will have been enabled by bias management */ - regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); - - return 0; + regcache_mark_dirty(wm8731->regmap); err_regulator_enable: + /* Regulators will be enabled by bias management */ regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); return ret; } -/* power down chip */ -static int wm8731_remove(struct snd_soc_codec *codec) -{ - struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec); - - regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies); - - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_wm8731 = { - .probe = wm8731_probe, - .remove = wm8731_remove, .set_bias_level = wm8731_set_bias_level, .suspend_bias_off = true, @@ -690,6 +684,12 @@ static int wm8731_spi_probe(struct spi_device *spi) mutex_init(&wm8731->lock); + spi_set_drvdata(spi, wm8731); + + ret = wm8731_request_supplies(&spi->dev, wm8731); + if (ret != 0) + return ret; + wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap); if (IS_ERR(wm8731->regmap)) { ret = PTR_ERR(wm8731->regmap); @@ -698,7 +698,9 @@ static int wm8731_spi_probe(struct spi_device *spi) return ret; } - spi_set_drvdata(spi, wm8731); + ret = wm8731_hw_init(&spi->dev, wm8731); + if (ret != 0) + return ret; ret = snd_soc_register_codec(&spi->dev, &soc_codec_dev_wm8731, &wm8731_dai, 1); @@ -754,6 +756,12 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, mutex_init(&wm8731->lock); + i2c_set_clientdata(i2c, wm8731); + + ret = wm8731_request_supplies(&i2c->dev, wm8731); + if (ret != 0) + return ret; + wm8731->regmap = devm_regmap_init_i2c(i2c, &wm8731_regmap); if (IS_ERR(wm8731->regmap)) { ret = PTR_ERR(wm8731->regmap); @@ -762,7 +770,9 @@ static int wm8731_i2c_probe(struct i2c_client *i2c, return ret; } - i2c_set_clientdata(i2c, wm8731); + ret = wm8731_hw_init(&i2c->dev, wm8731); + if (ret != 0) + return ret; ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_wm8731, &wm8731_dai, 1); -- GitLab From 83c09290adfb025d9a109d9c3c2956c81bcb241b Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Mon, 29 Jun 2015 14:20:50 +0800 Subject: [PATCH 0541/7006] ASoC: rt5645: move RT5645 muxes to rt5645_specific_dapm_widgets This is a similar patch to "move RT5650 muxes to rt5650_specific_ dapm_widgets" patch. The purpose is to silence the "has no paths" warnings. Signed-off-by: Bard Liao Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index a07966bebfef7..1d821da370048 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -1697,15 +1697,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0), /* IF1 2 Mux */ - SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc1_in_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc2_in_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc3_in_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM, - 0, 0, &rt5645_if1_adc_in_mux), - SND_SOC_DAPM_MUX("IF2 ADC Mux", SND_SOC_NOPM, 0, 0, &rt5645_if2_adc_in_mux), @@ -1716,14 +1707,6 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_PGA("IF1 DAC1", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC2", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 DAC3", SND_SOC_NOPM, 0, 0, NULL, 0), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac0_tdm_sel_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac1_tdm_sel_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac2_tdm_sel_mux), - SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0, - &rt5645_if1_dac3_tdm_sel_mux), SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 ADC L", SND_SOC_NOPM, 0, 0, NULL, 0), SND_SOC_DAPM_PGA("IF1 ADC R", SND_SOC_NOPM, 0, 0, NULL, 0), @@ -1856,6 +1839,25 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("SPOR"), }; +static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = { + SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 L Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac0_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 DAC1 R Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac1_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 L Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac2_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 DAC2 R Mux", SND_SOC_NOPM, 0, 0, + &rt5645_if1_dac3_tdm_sel_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc_in_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC1 Swap Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc1_in_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC2 Swap Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc2_in_mux), + SND_SOC_DAPM_MUX("RT5645 IF1 ADC3 Swap Mux", SND_SOC_NOPM, + 0, 0, &rt5645_if1_adc3_in_mux), +}; + static const struct snd_soc_dapm_widget rt5650_specific_dapm_widgets[] = { SND_SOC_DAPM_MUX("A DAC1 L Mux", SND_SOC_NOPM, 0, 0, &rt5650_a_dac1_l_mux), @@ -3049,6 +3051,9 @@ static int rt5645_probe(struct snd_soc_codec *codec) switch (rt5645->codec_type) { case CODEC_TYPE_RT5645: + snd_soc_dapm_new_controls(&codec->dapm, + rt5645_specific_dapm_widgets, + ARRAY_SIZE(rt5645_specific_dapm_widgets)); snd_soc_dapm_add_routes(&codec->dapm, rt5645_specific_dapm_routes, ARRAY_SIZE(rt5645_specific_dapm_routes)); -- GitLab From b650247da5a8c5d8991eeb9cf31e2e71d7be1b08 Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Tue, 30 Jun 2015 17:43:02 -0400 Subject: [PATCH 0542/7006] ASoC: codecs: max98088: fix typo in constant This fixes a typo in the M98088_REG_02_JACK_STATUS constant. Signed-off-by: Nik Nyby Signed-off-by: Mark Brown --- sound/soc/codecs/max98088.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/max98088.h b/sound/soc/codecs/max98088.h index be89a4f4aab82..efa39bf467425 100644 --- a/sound/soc/codecs/max98088.h +++ b/sound/soc/codecs/max98088.h @@ -16,7 +16,7 @@ */ #define M98088_REG_00_IRQ_STATUS 0x00 #define M98088_REG_01_MIC_STATUS 0x01 -#define M98088_REG_02_JACK_STAUS 0x02 +#define M98088_REG_02_JACK_STATUS 0x02 #define M98088_REG_03_BATTERY_VOLTAGE 0x03 #define M98088_REG_0F_IRQ_ENABLE 0x0F #define M98088_REG_10_SYS_CLK 0x10 -- GitLab From c05d9a8c7f55a901d9e8ec2a5f0730137bbfea4a Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 25 Jun 2015 09:35:11 +0100 Subject: [PATCH 0543/7006] ASoC: arizona: Implement stability check for EQ coefficients Specifying unstable coefficients for the EQ can have a severe impact on the audio. This patchs adds a stability check on the coefficients written to the EQ, for this it is necessary to merge the mode control and the coefficients as some coefficients may only be unstable with a certain mode setting so it is ideal if these are always updated in sync. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 59 ++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/arizona.h | 10 +++++++ sound/soc/codecs/wm5102.c | 12 +++----- sound/soc/codecs/wm5110.c | 12 +++----- sound/soc/codecs/wm8997.c | 12 +++----- 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05eae3e9d..39967863d2ece 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2313,6 +2313,65 @@ const struct snd_kcontrol_new arizona_adsp2_rate_controls[] = { }; EXPORT_SYMBOL_GPL(arizona_adsp2_rate_controls); +static bool arizona_eq_filter_unstable(bool mode, __be16 _a, __be16 _b) +{ + s16 a = be16_to_cpu(_a); + s16 b = be16_to_cpu(_b); + + if (!mode) { + return abs(a) >= 4096; + } else { + if (abs(b) >= 4096) + return true; + + return (abs((a << 16) / (4096 - b)) >= 4096 << 4); + } +} + +int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct soc_bytes *params = (void *)kcontrol->private_value; + unsigned int val; + __be16 *data; + int len; + int ret; + + len = params->num_regs * regmap_get_val_bytes(arizona->regmap); + + data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA); + if (!data) + return -ENOMEM; + + data[0] &= cpu_to_be16(ARIZONA_EQ1_B1_MODE); + + if (arizona_eq_filter_unstable(!!data[0], data[1], data[2]) || + arizona_eq_filter_unstable(true, data[4], data[5]) || + arizona_eq_filter_unstable(true, data[8], data[9]) || + arizona_eq_filter_unstable(true, data[12], data[13]) || + arizona_eq_filter_unstable(false, data[16], data[17])) { + dev_err(arizona->dev, "Rejecting unstable EQ coefficients\n"); + ret = -EINVAL; + goto out; + } + + ret = regmap_read(arizona->regmap, params->base, &val); + if (ret != 0) + goto out; + + val &= ~ARIZONA_EQ1_B1_MODE; + data[0] |= cpu_to_be16(val); + + ret = regmap_raw_write(arizona->regmap, params->base, data, len); + +out: + kfree(data); + return ret; +} +EXPORT_SYMBOL_GPL(arizona_eq_coeff_put); + MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 43deb0462309e..ebe50cf2f8780 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -194,6 +194,13 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ARIZONA_MIXER_ROUTES(name " Preloader", name "L"), \ ARIZONA_MIXER_ROUTES(name " Preloader", name "R") +#define ARIZONA_EQ_CONTROL(xname, xbase) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ + .put = arizona_eq_coeff_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) { .base = xbase, \ + .num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) } + #define ARIZONA_RATE_ENUM_SIZE 4 extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; @@ -229,6 +236,9 @@ extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event); +extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index d097f09e50f25..556bd9840e915 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -788,8 +788,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), -SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -801,8 +800,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), -SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -814,8 +812,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), -SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -827,8 +824,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), -SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 709fcc6169d81..dfa4d4bad89b1 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -247,8 +247,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), -SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -260,8 +259,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), -SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -273,8 +271,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), -SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -286,8 +283,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), -SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 4134dc7e12434..53e0a467d8de5 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -174,8 +174,7 @@ ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("EQ4", ARIZONA_EQ4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("EQ1 Coefficients", ARIZONA_EQ1_3, 19), -SOC_SINGLE("EQ1 Mode Switch", ARIZONA_EQ1_2, ARIZONA_EQ1_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ1 Coefficients", ARIZONA_EQ1_2), SOC_SINGLE_TLV("EQ1 B1 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ1 B2 Volume", ARIZONA_EQ1_1, ARIZONA_EQ1_B2_GAIN_SHIFT, @@ -187,8 +186,7 @@ SOC_SINGLE_TLV("EQ1 B4 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ1 B5 Volume", ARIZONA_EQ1_2, ARIZONA_EQ1_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ2 Coefficients", ARIZONA_EQ2_3, 19), -SOC_SINGLE("EQ2 Mode Switch", ARIZONA_EQ2_2, ARIZONA_EQ2_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ2 Coefficients", ARIZONA_EQ2_2), SOC_SINGLE_TLV("EQ2 B1 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ2 B2 Volume", ARIZONA_EQ2_1, ARIZONA_EQ2_B2_GAIN_SHIFT, @@ -200,8 +198,7 @@ SOC_SINGLE_TLV("EQ2 B4 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ2 B5 Volume", ARIZONA_EQ2_2, ARIZONA_EQ2_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ3 Coefficients", ARIZONA_EQ3_3, 19), -SOC_SINGLE("EQ3 Mode Switch", ARIZONA_EQ3_2, ARIZONA_EQ3_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ3 Coefficients", ARIZONA_EQ3_2), SOC_SINGLE_TLV("EQ3 B1 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ3 B2 Volume", ARIZONA_EQ3_1, ARIZONA_EQ3_B2_GAIN_SHIFT, @@ -213,8 +210,7 @@ SOC_SINGLE_TLV("EQ3 B4 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B4_GAIN_SHIFT, SOC_SINGLE_TLV("EQ3 B5 Volume", ARIZONA_EQ3_2, ARIZONA_EQ3_B5_GAIN_SHIFT, 24, 0, eq_tlv), -SND_SOC_BYTES("EQ4 Coefficients", ARIZONA_EQ4_3, 19), -SOC_SINGLE("EQ4 Mode Switch", ARIZONA_EQ4_2, ARIZONA_EQ4_B1_MODE, 1, 0), +ARIZONA_EQ_CONTROL("EQ4 Coefficients", ARIZONA_EQ4_2), SOC_SINGLE_TLV("EQ4 B1 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B1_GAIN_SHIFT, 24, 0, eq_tlv), SOC_SINGLE_TLV("EQ4 B2 Volume", ARIZONA_EQ4_1, ARIZONA_EQ4_B2_GAIN_SHIFT, -- GitLab From 5f8e671a49e1d608fcf52c8944ea7818cd4c99a9 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 25 Jun 2015 09:35:12 +0100 Subject: [PATCH 0544/7006] ASoC: arizona: Implement stability check for LHPF coefficients Specifying unstable coefficients for the low/high pass filters can have a severe impact on the audio. This patchs adds a stability check on the coefficients written to the low/high pass filter block to prevent this. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 17 +++++++++++++++++ sound/soc/codecs/arizona.h | 9 +++++++++ sound/soc/codecs/wm5102.c | 8 ++++---- sound/soc/codecs/wm5110.c | 8 ++++---- sound/soc/codecs/wm8997.c | 8 ++++---- 5 files changed, 38 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 39967863d2ece..a88202d768f45 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -2372,6 +2372,23 @@ out: } EXPORT_SYMBOL_GPL(arizona_eq_coeff_put); +int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + __be16 *data = (__be16 *)ucontrol->value.bytes.data; + s16 val = be16_to_cpu(*data); + + if (abs(val) >= 4096) { + dev_err(arizona->dev, "Rejecting unstable LHPF coefficients\n"); + return -EINVAL; + } + + return snd_soc_bytes_put(kcontrol, ucontrol); +} +EXPORT_SYMBOL_GPL(arizona_lhpf_coeff_put); + MODULE_DESCRIPTION("ASoC Wolfson Arizona class device support"); MODULE_AUTHOR("Mark Brown "); MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index ebe50cf2f8780..13598b0572ee9 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -201,6 +201,13 @@ extern int arizona_mixer_values[ARIZONA_NUM_MIXER_INPUTS]; ((unsigned long)&(struct soc_bytes) { .base = xbase, \ .num_regs = 20, .mask = ~ARIZONA_EQ1_B1_MODE }) } +#define ARIZONA_LHPF_CONTROL(xname, xbase) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_soc_bytes_info, .get = snd_soc_bytes_get, \ + .put = arizona_lhpf_coeff_put, .private_value = \ + ((unsigned long)&(struct soc_bytes) { .base = xbase, \ + .num_regs = 1 }) } + #define ARIZONA_RATE_ENUM_SIZE 4 extern const char *arizona_rate_text[ARIZONA_RATE_ENUM_SIZE]; extern const int arizona_rate_val[ARIZONA_RATE_ENUM_SIZE]; @@ -238,6 +245,8 @@ extern int arizona_hp_ev(struct snd_soc_dapm_widget *w, extern int arizona_eq_coeff_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +extern int arizona_lhpf_coeff_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); extern int arizona_set_sysclk(struct snd_soc_codec *codec, int clk_id, int source, unsigned int freq, int dir); diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 556bd9840e915..6ddee999bc517 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -847,10 +847,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), ARIZONA_MIXER_CONTROLS("DSP1L", ARIZONA_DSP1LMIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("DSP1R", ARIZONA_DSP1RMIX_INPUT_1_SOURCE), diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index dfa4d4bad89b1..05aa5bca97cfd 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -310,10 +310,10 @@ ARIZONA_MIXER_CONTROLS("LHPF2", ARIZONA_HPLP2MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF3", ARIZONA_HPLP3MIX_INPUT_1_SOURCE), ARIZONA_MIXER_CONTROLS("LHPF4", ARIZONA_HPLP4MIX_INPUT_1_SOURCE), -SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), SOC_ENUM("LHPF1 Mode", arizona_lhpf1_mode), SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), diff --git a/sound/soc/codecs/wm8997.c b/sound/soc/codecs/wm8997.c index 53e0a467d8de5..b4dba3a02abaf 100644 --- a/sound/soc/codecs/wm8997.c +++ b/sound/soc/codecs/wm8997.c @@ -238,10 +238,10 @@ SOC_ENUM("LHPF2 Mode", arizona_lhpf2_mode), SOC_ENUM("LHPF3 Mode", arizona_lhpf3_mode), SOC_ENUM("LHPF4 Mode", arizona_lhpf4_mode), -SND_SOC_BYTES("LHPF1 Coefficients", ARIZONA_HPLPF1_2, 1), -SND_SOC_BYTES("LHPF2 Coefficients", ARIZONA_HPLPF2_2, 1), -SND_SOC_BYTES("LHPF3 Coefficients", ARIZONA_HPLPF3_2, 1), -SND_SOC_BYTES("LHPF4 Coefficients", ARIZONA_HPLPF4_2, 1), +ARIZONA_LHPF_CONTROL("LHPF1 Coefficients", ARIZONA_HPLPF1_2), +ARIZONA_LHPF_CONTROL("LHPF2 Coefficients", ARIZONA_HPLPF2_2), +ARIZONA_LHPF_CONTROL("LHPF3 Coefficients", ARIZONA_HPLPF3_2), +ARIZONA_LHPF_CONTROL("LHPF4 Coefficients", ARIZONA_HPLPF4_2), SOC_ENUM("ISRC1 FSL", arizona_isrc_fsl[0]), SOC_ENUM("ISRC2 FSL", arizona_isrc_fsl[1]), -- GitLab From 0d69e0dddf5fe86675c56bc0f0520ffb0cbf1fcd Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Tue, 23 Jun 2015 18:23:53 +0800 Subject: [PATCH 0545/7006] ASoC: fsl: Add dedicated DMA buffer size for each cpu dai As the ssi is not the only cpu dai, there are esai, spdif, sai. and imx_pcm_dma can be used by all of them. Especially ESAI need a larger DMA buffer size. So Add dedicated DMA buffer for each cpu dai. Signed-off-by: Shengjiu Wang Acked-by: Nicolin Chen Acked-by: Timur Tabi Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_esai.c | 2 +- sound/soc/fsl/fsl_sai.c | 2 +- sound/soc/fsl/fsl_spdif.c | 2 +- sound/soc/fsl/fsl_ssi.c | 2 +- sound/soc/fsl/imx-pcm-dma.c | 25 +++++++++++++++++++++---- sound/soc/fsl/imx-pcm.h | 9 +++++++-- sound/soc/fsl/imx-ssi.c | 2 +- 7 files changed, 33 insertions(+), 11 deletions(-) diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 5c7597191e3ff..8c2ddc1ea954c 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -839,7 +839,7 @@ static int fsl_esai_probe(struct platform_device *pdev) return ret; } - ret = imx_pcm_dma_init(pdev); + ret = imx_pcm_dma_init(pdev, IMX_ESAI_DMABUF_SIZE); if (ret) dev_err(&pdev->dev, "failed to init imx pcm dma: %d\n", ret); diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 5c73bea7b11ef..a18fd92c4a85c 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -791,7 +791,7 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; if (sai->sai_on_imx) - return imx_pcm_dma_init(pdev); + return imx_pcm_dma_init(pdev, IMX_SAI_DMABUF_SIZE); else return devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); } diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8e932219cb3af..d1e9be771f84e 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -1255,7 +1255,7 @@ static int fsl_spdif_probe(struct platform_device *pdev) return ret; } - ret = imx_pcm_dma_init(pdev); + ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); if (ret) dev_err(&pdev->dev, "imx_pcm_dma_init failed: %d\n", ret); diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index c7647e066cfd7..e122dab944f4f 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -1257,7 +1257,7 @@ static int fsl_ssi_imx_probe(struct platform_device *pdev, if (ret) goto error_pcm; } else { - ret = imx_pcm_dma_init(pdev); + ret = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE); if (ret) goto error_pcm; } diff --git a/sound/soc/fsl/imx-pcm-dma.c b/sound/soc/fsl/imx-pcm-dma.c index 0db94f492e97d..1fc01ed3279db 100644 --- a/sound/soc/fsl/imx-pcm-dma.c +++ b/sound/soc/fsl/imx-pcm-dma.c @@ -40,7 +40,7 @@ static const struct snd_pcm_hardware imx_pcm_hardware = { SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, - .buffer_bytes_max = IMX_SSI_DMABUF_SIZE, + .buffer_bytes_max = IMX_DEFAULT_DMABUF_SIZE, .period_bytes_min = 128, .period_bytes_max = 65535, /* Limited by SDMA engine */ .periods_min = 2, @@ -52,13 +52,30 @@ static const struct snd_dmaengine_pcm_config imx_dmaengine_pcm_config = { .pcm_hardware = &imx_pcm_hardware, .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, .compat_filter_fn = filter, - .prealloc_buffer_size = IMX_SSI_DMABUF_SIZE, + .prealloc_buffer_size = IMX_DEFAULT_DMABUF_SIZE, }; -int imx_pcm_dma_init(struct platform_device *pdev) +int imx_pcm_dma_init(struct platform_device *pdev, size_t size) { + struct snd_dmaengine_pcm_config *config; + struct snd_pcm_hardware *pcm_hardware; + + config = devm_kzalloc(&pdev->dev, + sizeof(struct snd_dmaengine_pcm_config), GFP_KERNEL); + *config = imx_dmaengine_pcm_config; + if (size) + config->prealloc_buffer_size = size; + + pcm_hardware = devm_kzalloc(&pdev->dev, + sizeof(struct snd_pcm_hardware), GFP_KERNEL); + *pcm_hardware = imx_pcm_hardware; + if (size) + pcm_hardware->buffer_bytes_max = size; + + config->pcm_hardware = pcm_hardware; + return devm_snd_dmaengine_pcm_register(&pdev->dev, - &imx_dmaengine_pcm_config, + config, SND_DMAENGINE_PCM_FLAG_COMPAT); } EXPORT_SYMBOL_GPL(imx_pcm_dma_init); diff --git a/sound/soc/fsl/imx-pcm.h b/sound/soc/fsl/imx-pcm.h index c79cb27473be7..133c4470acad6 100644 --- a/sound/soc/fsl/imx-pcm.h +++ b/sound/soc/fsl/imx-pcm.h @@ -20,6 +20,11 @@ */ #define IMX_SSI_DMABUF_SIZE (64 * 1024) +#define IMX_DEFAULT_DMABUF_SIZE (64 * 1024) +#define IMX_SAI_DMABUF_SIZE (64 * 1024) +#define IMX_SPDIF_DMABUF_SIZE (64 * 1024) +#define IMX_ESAI_DMABUF_SIZE (256 * 1024) + static inline void imx_pcm_dma_params_init_data(struct imx_dma_data *dma_data, int dma, enum sdma_peripheral_type peripheral_type) @@ -39,9 +44,9 @@ struct imx_pcm_fiq_params { }; #if IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA) -int imx_pcm_dma_init(struct platform_device *pdev); +int imx_pcm_dma_init(struct platform_device *pdev, size_t size); #else -static inline int imx_pcm_dma_init(struct platform_device *pdev) +static inline int imx_pcm_dma_init(struct platform_device *pdev, size_t size) { return -ENODEV; } diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c index 461ce27b884f0..48b2d24dd1f0a 100644 --- a/sound/soc/fsl/imx-ssi.c +++ b/sound/soc/fsl/imx-ssi.c @@ -603,7 +603,7 @@ static int imx_ssi_probe(struct platform_device *pdev) ssi->fiq_params.dma_params_tx = &ssi->dma_params_tx; ssi->fiq_init = imx_pcm_fiq_init(pdev, &ssi->fiq_params); - ssi->dma_init = imx_pcm_dma_init(pdev); + ssi->dma_init = imx_pcm_dma_init(pdev, IMX_SSI_DMABUF_SIZE); if (ssi->fiq_init && ssi->dma_init) { ret = ssi->fiq_init; -- GitLab From b1ade0f2afe283d59eb313e5717870fdb831fc4e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 18:00:13 -0300 Subject: [PATCH 0546/7006] ASoC: fsl: fsl_asrc: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_asrc.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index c068494bae305..9f087d4f73ed7 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -931,14 +931,29 @@ static int fsl_asrc_probe(struct platform_device *pdev) static int fsl_asrc_runtime_resume(struct device *dev) { struct fsl_asrc *asrc_priv = dev_get_drvdata(dev); - int i; + int i, ret; - clk_prepare_enable(asrc_priv->mem_clk); - clk_prepare_enable(asrc_priv->ipg_clk); - for (i = 0; i < ASRC_CLK_MAX_NUM; i++) - clk_prepare_enable(asrc_priv->asrck_clk[i]); + ret = clk_prepare_enable(asrc_priv->mem_clk); + if (ret) + return ret; + ret = clk_prepare_enable(asrc_priv->ipg_clk); + if (ret) + goto disable_mem_clk; + for (i = 0; i < ASRC_CLK_MAX_NUM; i++) { + ret = clk_prepare_enable(asrc_priv->asrck_clk[i]); + if (ret) + goto disable_asrck_clk; + } return 0; + +disable_asrck_clk: + for (i--; i >= 0; i--) + clk_disable_unprepare(asrc_priv->asrck_clk[i]); + clk_disable_unprepare(asrc_priv->ipg_clk); +disable_mem_clk: + clk_disable_unprepare(asrc_priv->mem_clk); + return ret; } static int fsl_asrc_runtime_suspend(struct device *dev) -- GitLab From fa3be9208dcb21ae4185f6122137fe7d5cf29d74 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 18:18:06 -0300 Subject: [PATCH 0547/7006] ASoC: fsl: fsl_spdif: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8e932219cb3af..489fa86eb7451 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -482,13 +482,18 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | SCR_TXFIFO_FSEL_MASK; - for (i = 0; i < SPDIF_TXRATE_MAX; i++) - clk_prepare_enable(spdif_priv->txclk[i]); + for (i = 0; i < SPDIF_TXRATE_MAX; i++) { + ret = clk_prepare_enable(spdif_priv->txclk[i]); + if (ret) + goto disable_txclk; + } } else { scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; - clk_prepare_enable(spdif_priv->rxclk); + ret = clk_prepare_enable(spdif_priv->rxclk); + if (ret) + goto err; } regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); @@ -497,6 +502,9 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, return 0; +disable_txclk: + for (i--; i >= 0; i--) + clk_disable_unprepare(spdif_priv->txclk[i]); err: clk_disable_unprepare(spdif_priv->coreclk); -- GitLab From efd901ee4bc8312e3bbf5561fdab8e3765e26334 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 22 Jun 2015 11:12:59 -0700 Subject: [PATCH 0548/7006] ASoC: rt5677: Switch to use descriptor-based gpiod API This patch makes the driver use the new descriptor-based gpiod API so that gpio assignment info can be provided by Device Tree, ACPI or board files. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 85 ++++++++++++++------------------------- sound/soc/codecs/rt5677.h | 5 ++- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 9048ba7efee1b..232243009e1ec 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -15,13 +15,11 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include #include @@ -4764,10 +4762,10 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 0); + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } @@ -4781,10 +4779,10 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 0); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 0); + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; @@ -4795,12 +4793,11 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { - if (gpio_is_valid(rt5677->pow_ldo2)) - gpio_set_value_cansleep(rt5677->pow_ldo2, 1); - if (gpio_is_valid(rt5677->reset_pin)) - gpio_set_value_cansleep(rt5677->reset_pin, 1); - if (gpio_is_valid(rt5677->pow_ldo2) || - gpio_is_valid(rt5677->reset_pin)) + if (rt5677->pow_ldo2) + gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); + if (rt5677->reset_pin) + gpiod_set_value_cansleep(rt5677->reset_pin, 1); + if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); regcache_cache_only(rt5677->regmap, false); @@ -5037,24 +5034,6 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) rt5677->pdata.lout3_diff = of_property_read_bool(np, "realtek,lout3-differential"); - rt5677->pow_ldo2 = of_get_named_gpio(np, - "realtek,pow-ldo2-gpio", 0); - rt5677->reset_pin = of_get_named_gpio(np, - "realtek,reset-gpio", 0); - - /* - * POW_LDO2 is optional (it may be statically tied on the board). - * -ENOENT means that the property doesn't exist, i.e. there is no - * GPIO, so is not an error. Any other error code means the property - * exists, but could not be parsed. - */ - if (!gpio_is_valid(rt5677->pow_ldo2) && - (rt5677->pow_ldo2 != -ENOENT)) - return rt5677->pow_ldo2; - if (!gpio_is_valid(rt5677->reset_pin) && - (rt5677->reset_pin != -ENOENT)) - return rt5677->reset_pin; - of_property_read_u8_array(np, "realtek,gpio-config", rt5677->pdata.gpio_config, RT5677_GPIO_NUM); @@ -5158,30 +5137,26 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, rt5677->reset_pin = -EINVAL; } - if (gpio_is_valid(rt5677->pow_ldo2)) { - ret = devm_gpio_request_one(&i2c->dev, rt5677->pow_ldo2, - GPIOF_OUT_INIT_HIGH, - "RT5677 POW_LDO2"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request POW_LDO2 %d: %d\n", - rt5677->pow_ldo2, ret); - return ret; - } + /* pow-ldo2 and reset are optional. The codec pins may be statically + * connected on the board without gpios. If the gpio device property + * isn't specified, devm_gpiod_get_optional returns NULL. + */ + rt5677->pow_ldo2 = devm_gpiod_get_optional(&i2c->dev, + "realtek,pow-ldo2", GPIOD_OUT_HIGH); + if (IS_ERR(rt5677->pow_ldo2)) { + ret = PTR_ERR(rt5677->pow_ldo2); + dev_err(&i2c->dev, "Failed to request POW_LDO2: %d\n", ret); + rt5677->pow_ldo2 = 0; } - - if (gpio_is_valid(rt5677->reset_pin)) { - ret = devm_gpio_request_one(&i2c->dev, rt5677->reset_pin, - GPIOF_OUT_INIT_HIGH, - "RT5677 RESET"); - if (ret < 0) { - dev_err(&i2c->dev, "Failed to request RESET %d: %d\n", - rt5677->reset_pin, ret); - return ret; - } + rt5677->reset_pin = devm_gpiod_get_optional(&i2c->dev, + "realtek,reset", GPIOD_OUT_HIGH); + if (IS_ERR(rt5677->reset_pin)) { + ret = PTR_ERR(rt5677->reset_pin); + dev_err(&i2c->dev, "Failed to request RESET: %d\n", ret); + rt5677->reset_pin = 0; } - if (gpio_is_valid(rt5677->pow_ldo2) || - gpio_is_valid(rt5677->reset_pin)) { + if (rt5677->pow_ldo2 || rt5677->reset_pin) { /* Wait a while until I2C bus becomes available. The datasheet * does not specify the exact we should wait but startup * sequence mentiones at least a few milliseconds. diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h index 7eca38a232556..d46855a42c408 100644 --- a/sound/soc/codecs/rt5677.h +++ b/sound/soc/codecs/rt5677.h @@ -14,6 +14,7 @@ #include #include +#include /* Info */ #define RT5677_RESET 0x00 @@ -1775,8 +1776,8 @@ struct rt5677_priv { int pll_src; int pll_in; int pll_out; - int pow_ldo2; /* POW_LDO2 pin */ - int reset_pin; /* RESET pin */ + struct gpio_desc *pow_ldo2; /* POW_LDO2 pin */ + struct gpio_desc *reset_pin; /* RESET pin */ enum rt5677_type type; #ifdef CONFIG_GPIOLIB struct gpio_chip gpio_chip; -- GitLab From 9bfde72157036f4eaa44f3e8982217ce1b3e14b6 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Mon, 22 Jun 2015 11:13:00 -0700 Subject: [PATCH 0549/7006] ASoC: rt5677: Switch to use unified device property API This patch makes the driver use the unified device property API so that platform data can be provided by Device Tree, ACPI or board files. Signed-off-by: Ben Zhang Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 57 +++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 232243009e1ec..13b871f110230 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -5021,27 +5022,29 @@ static const struct i2c_device_id rt5677_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, rt5677_i2c_id); -static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np) +static void rt5677_read_device_properties(struct rt5677_priv *rt5677, + struct device *dev) { - rt5677->pdata.in1_diff = of_property_read_bool(np, - "realtek,in1-differential"); - rt5677->pdata.in2_diff = of_property_read_bool(np, - "realtek,in2-differential"); - rt5677->pdata.lout1_diff = of_property_read_bool(np, - "realtek,lout1-differential"); - rt5677->pdata.lout2_diff = of_property_read_bool(np, - "realtek,lout2-differential"); - rt5677->pdata.lout3_diff = of_property_read_bool(np, - "realtek,lout3-differential"); - - of_property_read_u8_array(np, "realtek,gpio-config", - rt5677->pdata.gpio_config, RT5677_GPIO_NUM); - - of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio); - of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio); - of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio); - - return 0; + rt5677->pdata.in1_diff = device_property_read_bool(dev, + "realtek,in1-differential"); + rt5677->pdata.in2_diff = device_property_read_bool(dev, + "realtek,in2-differential"); + rt5677->pdata.lout1_diff = device_property_read_bool(dev, + "realtek,lout1-differential"); + rt5677->pdata.lout2_diff = device_property_read_bool(dev, + "realtek,lout2-differential"); + rt5677->pdata.lout3_diff = device_property_read_bool(dev, + "realtek,lout3-differential"); + + device_property_read_u8_array(dev, "realtek,gpio-config", + rt5677->pdata.gpio_config, RT5677_GPIO_NUM); + + device_property_read_u32(dev, "realtek,jd1-gpio", + &rt5677->pdata.jd1_gpio); + device_property_read_u32(dev, "realtek,jd2-gpio", + &rt5677->pdata.jd2_gpio); + device_property_read_u32(dev, "realtek,jd3-gpio", + &rt5677->pdata.jd3_gpio); } static struct regmap_irq rt5677_irqs[] = { @@ -5124,18 +5127,8 @@ static int rt5677_i2c_probe(struct i2c_client *i2c, if (pdata) rt5677->pdata = *pdata; - - if (i2c->dev.of_node) { - ret = rt5677_parse_dt(rt5677, i2c->dev.of_node); - if (ret) { - dev_err(&i2c->dev, "Failed to parse device tree: %d\n", - ret); - return ret; - } - } else { - rt5677->pow_ldo2 = -EINVAL; - rt5677->reset_pin = -EINVAL; - } + else + rt5677_read_device_properties(rt5677, &i2c->dev); /* pow-ldo2 and reset are optional. The codec pins may be statically * connected on the board without gpios. If the gpio device property -- GitLab From d375d0abcd625cd09cd90a252ad22a1085452e3c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Jun 2015 21:41:43 +0800 Subject: [PATCH 0550/7006] ASoC: cs42xx8: Move the code checking *regmap argument earlier Slightly improve the readability by moving the code checking *regmap argument earlier. Also move the assignment of of_id close to the place testing it. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index e1d46862e81f1..ab395144b2327 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -435,16 +435,24 @@ EXPORT_SYMBOL_GPL(cs42xx8_of_match); int cs42xx8_probe(struct device *dev, struct regmap *regmap) { - const struct of_device_id *of_id = of_match_device(cs42xx8_of_match, dev); + const struct of_device_id *of_id; struct cs42xx8_priv *cs42xx8; int ret, val, i; + if (IS_ERR(regmap)) { + ret = PTR_ERR(regmap); + dev_err(dev, "failed to allocate regmap: %d\n", ret); + return ret; + } + cs42xx8 = devm_kzalloc(dev, sizeof(*cs42xx8), GFP_KERNEL); if (cs42xx8 == NULL) return -ENOMEM; + cs42xx8->regmap = regmap; dev_set_drvdata(dev, cs42xx8); + of_id = of_match_device(cs42xx8_of_match, dev); if (of_id) cs42xx8->drvdata = of_id->data; @@ -482,13 +490,6 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap) /* Make sure hardware reset done */ msleep(5); - cs42xx8->regmap = regmap; - if (IS_ERR(cs42xx8->regmap)) { - ret = PTR_ERR(cs42xx8->regmap); - dev_err(dev, "failed to allocate regmap: %d\n", ret); - goto err_enable; - } - /* * We haven't marked the chip revision as volatile due to * sharing a register with the right input volume; explicitly -- GitLab From 5e4cb7b60833b0124a9f71dbc5118144ca79c3c4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Jun 2015 21:44:13 +0800 Subject: [PATCH 0551/7006] ASoC: cs42xx8: Setup of_match_table Setup of_match_table and since cs42xx8_of_match is exported and used in cs42xx8-i2c.c, it cannot be static. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42xx8-i2c.c | 3 ++- sound/soc/codecs/cs42xx8.c | 2 +- sound/soc/codecs/cs42xx8.h | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 657dce27eade3..5a71c9e5b4417 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -20,7 +20,7 @@ static int cs42xx8_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { - u32 ret = cs42xx8_probe(&i2c->dev, + int ret = cs42xx8_probe(&i2c->dev, devm_regmap_init_i2c(i2c, &cs42xx8_regmap_config)); if (ret) return ret; @@ -51,6 +51,7 @@ static struct i2c_driver cs42xx8_i2c_driver = { .name = "cs42xx8", .owner = THIS_MODULE, .pm = &cs42xx8_pm, + .of_match_table = cs42xx8_of_match, }, .probe = cs42xx8_i2c_probe, .remove = cs42xx8_i2c_remove, diff --git a/sound/soc/codecs/cs42xx8.c b/sound/soc/codecs/cs42xx8.c index ab395144b2327..d562e1b9a5d16 100644 --- a/sound/soc/codecs/cs42xx8.c +++ b/sound/soc/codecs/cs42xx8.c @@ -425,7 +425,7 @@ const struct cs42xx8_driver_data cs42888_data = { }; EXPORT_SYMBOL_GPL(cs42888_data); -static const struct of_device_id cs42xx8_of_match[] = { +const struct of_device_id cs42xx8_of_match[] = { { .compatible = "cirrus,cs42448", .data = &cs42448_data, }, { .compatible = "cirrus,cs42888", .data = &cs42888_data, }, { /* sentinel */ } diff --git a/sound/soc/codecs/cs42xx8.h b/sound/soc/codecs/cs42xx8.h index b2c10e537ef6c..d36c61b6df747 100644 --- a/sound/soc/codecs/cs42xx8.h +++ b/sound/soc/codecs/cs42xx8.h @@ -22,6 +22,7 @@ extern const struct dev_pm_ops cs42xx8_pm; extern const struct cs42xx8_driver_data cs42448_data; extern const struct cs42xx8_driver_data cs42888_data; extern const struct regmap_config cs42xx8_regmap_config; +extern const struct of_device_id cs42xx8_of_match[]; int cs42xx8_probe(struct device *dev, struct regmap *regmap); /* CS42888 register map */ -- GitLab From 93ec3a1ad5b86aef8ca90d2b149ded0f6bb689f5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 29 Jun 2015 11:15:23 +0800 Subject: [PATCH 0552/7006] ASoC: 88pm860x: Don't change pm860x->dir setting if pm860x_set_dai_sysclk fails 88pm860x does not support slave mode, so it returns -EINVAL for PM860X_CLK_DIR_IN. Current code changes pm860x->dir setting before return error, so it has impact on the logic of pm860x_pcm_set_dai_fmt. This patch adds comment for the reason to return -EINVAL for PM860X_CLK_DIR_IN, and avoid changing pm860x->dir setting if pm860x_set_dai_sysclk fails. Signed-off-by: Axel Lin Acked-by: Haojian Zhuang Signed-off-by: Mark Brown --- sound/soc/codecs/88pm860x-codec.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/codecs/88pm860x-codec.c b/sound/soc/codecs/88pm860x-codec.c index 38b3dad9d48ac..4d91a6aa696b8 100644 --- a/sound/soc/codecs/88pm860x-codec.c +++ b/sound/soc/codecs/88pm860x-codec.c @@ -1028,10 +1028,8 @@ static int pm860x_set_dai_sysclk(struct snd_soc_dai *codec_dai, if (dir == PM860X_CLK_DIR_OUT) pm860x->dir = PM860X_CLK_DIR_OUT; - else { - pm860x->dir = PM860X_CLK_DIR_IN; + else /* Slave mode is not supported */ return -EINVAL; - } return 0; } -- GitLab From f8ea6cebcfa6499949392da71fc427567c9e5a0e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 1 Jul 2015 00:56:36 +0800 Subject: [PATCH 0553/7006] ASoC: ak4642: Fix up max_register setting The max_register setting for ak4642, ak4643 and ak4648 are wrong, fix it. According to the datasheet: the maximum valid register for ak4642 is 0x1f the maximum valid register for ak4643 is 0x24 the maximum valid register for ak4648 is 0x27 The default settings for ak4642 and ak4643 are the same for 0x0 ~ 0x1f registers, so it's fine to use the same reg_default table with differnt num_reg_defaults setting. Signed-off-by: Axel Lin Tested-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/codecs/ak4642.c | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 7c0f6552c229b..fe963e17ceb47 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -64,12 +64,15 @@ #define FIL1_0 0x1c #define FIL1_1 0x1d #define FIL1_2 0x1e -#define FIL1_3 0x1f +#define FIL1_3 0x1f /* The maximum valid register for ak4642 */ #define PW_MGMT4 0x20 #define MD_CTL5 0x21 #define LO_MS 0x22 #define HP_MS 0x23 -#define SPK_MS 0x24 +#define SPK_MS 0x24 /* The maximum valid register for ak4643 */ +#define EQ_FBEQAB 0x25 +#define EQ_FBEQCD 0x26 +#define EQ_FBEQE 0x27 /* The maximum valid register for ak4648 */ /* PW_MGMT1*/ #define PMVCM (1 << 6) /* VCOM Power Management */ @@ -241,7 +244,7 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { /* * ak4642 register cache */ -static const struct reg_default ak4642_reg[] = { +static const struct reg_default ak4643_reg[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 }, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 }, { 8, 0xe1 }, { 9, 0xe1 }, { 10, 0x18 }, { 11, 0x00 }, @@ -254,6 +257,14 @@ static const struct reg_default ak4642_reg[] = { { 36, 0x00 }, }; +/* The default settings for 0x0 ~ 0x1f registers are the same for ak4642 + and ak4643. So we reuse the ak4643 reg_default for ak4642. + The valid registers for ak4642 are 0x0 ~ 0x1f which is a subset of ak4643, + so define NUM_AK4642_REG_DEFAULTS for ak4642. +*/ +#define ak4642_reg ak4643_reg +#define NUM_AK4642_REG_DEFAULTS (FIL1_3 + 1) + static const struct reg_default ak4648_reg[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x01 }, { 3, 0x00 }, { 4, 0x02 }, { 5, 0x00 }, { 6, 0x00 }, { 7, 0x00 }, @@ -535,15 +546,23 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { static const struct regmap_config ak4642_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = ARRAY_SIZE(ak4642_reg) + 1, + .max_register = FIL1_3, .reg_defaults = ak4642_reg, - .num_reg_defaults = ARRAY_SIZE(ak4642_reg), + .num_reg_defaults = NUM_AK4642_REG_DEFAULTS, +}; + +static const struct regmap_config ak4643_regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = SPK_MS, + .reg_defaults = ak4643_reg, + .num_reg_defaults = ARRAY_SIZE(ak4643_reg), }; static const struct regmap_config ak4648_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = ARRAY_SIZE(ak4648_reg) + 1, + .max_register = EQ_FBEQE, .reg_defaults = ak4648_reg, .num_reg_defaults = ARRAY_SIZE(ak4648_reg), }; @@ -553,7 +572,7 @@ static const struct ak4642_drvdata ak4642_drvdata = { }; static const struct ak4642_drvdata ak4643_drvdata = { - .regmap_config = &ak4642_regmap, + .regmap_config = &ak4643_regmap, }; static const struct ak4642_drvdata ak4648_drvdata = { -- GitLab From 6f4397949689d74c3bd0016c80d59a90c6e8afee Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 25 Jun 2015 17:01:14 +0800 Subject: [PATCH 0554/7006] ASoC: lm49453: Remove fs_rate from struct lm49453_priv fs_rate is only used in lm49453_hw_params() so don't need to store it in private data. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/lm49453.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0a33dc5..5b4086d4109a4 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -188,7 +188,6 @@ static struct reg_default lm49453_reg_defs[] = { /* codec private data */ struct lm49453_priv { struct regmap *regmap; - int fs_rate; }; /* capture path controls */ @@ -1112,13 +1111,10 @@ static int lm49453_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct snd_soc_codec *codec = dai->codec; - struct lm49453_priv *lm49453 = snd_soc_codec_get_drvdata(codec); u16 clk_div = 0; - lm49453->fs_rate = params_rate(params); - /* Setting DAC clock dividers based on substream sample rate. */ - switch (lm49453->fs_rate) { + switch (params_rate(params)) { case 8000: case 16000: case 32000: -- GitLab From 02a9547e9b3f10d73fde66f52fc8b2a375a300cd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 7 Jul 2015 12:57:19 +0800 Subject: [PATCH 0555/7006] ASoC: gtm601: Constify soc_codec_dev_gtm601 Also clean up the code a bit by fixing indent. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/gtm601.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/gtm601.c b/sound/soc/codecs/gtm601.c index 12d15e5b50f0c..0b80052996d3d 100644 --- a/sound/soc/codecs/gtm601.c +++ b/sound/soc/codecs/gtm601.c @@ -51,7 +51,7 @@ static struct snd_soc_dai_driver gtm601_dai = { }, }; -static struct snd_soc_codec_driver soc_codec_dev_gtm601 = { +static const struct snd_soc_codec_driver soc_codec_dev_gtm601 = { .dapm_widgets = gtm601_dapm_widgets, .num_dapm_widgets = ARRAY_SIZE(gtm601_dapm_widgets), .dapm_routes = gtm601_dapm_routes, @@ -80,10 +80,9 @@ MODULE_DEVICE_TABLE(of, gtm601_codec_of_match); static struct platform_driver gtm601_codec_driver = { .driver = { - .name = "gtm601", - .of_match_table = of_match_ptr(gtm601_codec_of_match), + .name = "gtm601", + .of_match_table = of_match_ptr(gtm601_codec_of_match), }, - .probe = gtm601_platform_probe, .remove = gtm601_platform_remove, }; -- GitLab From c418a84a8c8f98b1a0f30cd68d0cdf40d77aed01 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 5 Jul 2015 17:48:29 +0800 Subject: [PATCH 0556/7006] ASoC: Constify reg_default tables Signed-off-by: Axel Lin Acked-by: Peter Rosin Acked-by: Charles Keepax Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/adav80x.c | 2 +- sound/soc/codecs/alc5632.c | 2 +- sound/soc/codecs/da7210.c | 6 +++--- sound/soc/codecs/da7213.c | 2 +- sound/soc/codecs/da732x.c | 2 +- sound/soc/codecs/da9055.c | 2 +- sound/soc/codecs/isabelle.c | 2 +- sound/soc/codecs/lm49453.c | 2 +- sound/soc/codecs/max9768.c | 2 +- sound/soc/codecs/max9877.c | 2 +- sound/soc/codecs/ml26124.c | 2 +- sound/soc/codecs/rt286.c | 4 ++-- sound/soc/codecs/rt5651.c | 2 +- sound/soc/codecs/tas2552.c | 2 +- sound/soc/codecs/tfa9879.c | 2 +- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm8962.c | 2 +- sound/soc/codecs/wm8993.c | 4 ++-- sound/soc/codecs/wm8996.c | 2 +- sound/soc/codecs/wm9081.c | 2 +- 20 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index 36d8425707459..88fd37c683cdb 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c @@ -113,7 +113,7 @@ #define ADAV80X_PLL_OUTE_SYSCLKPD(x) BIT(2 - (x)) -static struct reg_default adav80x_reg_defaults[] = { +static const struct reg_default adav80x_reg_defaults[] = { { ADAV80X_PLAYBACK_CTRL, 0x01 }, { ADAV80X_AUX_IN_CTRL, 0x01 }, { ADAV80X_REC_CTRL, 0x02 }, diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 607a63b9705f9..29a26455ce256 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -35,7 +35,7 @@ /* * ALC5632 register cache */ -static struct reg_default alc5632_reg_defaults[] = { +static const struct reg_default alc5632_reg_defaults[] = { { 2, 0x8080 }, /* R2 - Speaker Output Volume */ { 4, 0x8080 }, /* R4 - Headphone Output Volume */ { 6, 0x8080 }, /* R6 - AUXOUT Volume */ diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5f3321c..a44ead615b675 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -680,7 +680,7 @@ struct da7210_priv { int master; }; -static struct reg_default da7210_reg_defaults[] = { +static const struct reg_default da7210_reg_defaults[] = { { 0x00, 0x00 }, { 0x01, 0x11 }, { 0x03, 0x00 }, @@ -1182,7 +1182,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = { #if IS_ENABLED(CONFIG_I2C) -static struct reg_default da7210_regmap_i2c_patch[] = { +static const struct reg_default da7210_regmap_i2c_patch[] = { /* System controller master disable */ { DA7210_STARTUP1, 0x00 }, @@ -1269,7 +1269,7 @@ static struct i2c_driver da7210_i2c_driver = { #if defined(CONFIG_SPI_MASTER) -static struct reg_default da7210_regmap_spi_patch[] = { +static const struct reg_default da7210_regmap_spi_patch[] = { /* Dummy read to give two pulses over nCS for SPI */ { DA7210_AUX2, 0x00 }, { DA7210_AUX2, 0x00 }, diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 238e48a3a4fe7..baa36f6fd4052 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -954,7 +954,7 @@ static const struct snd_soc_dapm_route da7213_audio_map[] = { {"LINE", NULL, "Lineout PGA"}, }; -static struct reg_default da7213_reg_defaults[] = { +static const struct reg_default da7213_reg_defaults[] = { { DA7213_DIG_ROUTING_DAI, 0x10 }, { DA7213_SR, 0x0A }, { DA7213_REFERENCES, 0x80 }, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 207523686bd55..b1cb4656a49ca 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -43,7 +43,7 @@ struct da732x_priv { /* * da732x register cache - default settings */ -static struct reg_default da732x_reg_cache[] = { +static const struct reg_default da732x_reg_cache[] = { { DA732X_REG_REF1 , 0x02 }, { DA732X_REG_BIAS_EN , 0x80 }, { DA732X_REG_BIAS1 , 0x00 }, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 66bb446473b86..925d822782498 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -948,7 +948,7 @@ struct da9055_priv { struct da9055_platform_data *pdata; }; -static struct reg_default da9055_reg_defaults[] = { +static const struct reg_default da9055_reg_defaults[] = { { 0x21, 0x10 }, { 0x22, 0x0A }, { 0x23, 0x00 }, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index ebd90283c9604..ac7dfe79c53bd 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -33,7 +33,7 @@ /* Register default values for ISABELLE driver. */ -static struct reg_default isabelle_reg_defs[] = { +static const struct reg_default isabelle_reg_defs[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0a33dc5..bf77462961290 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -30,7 +30,7 @@ #include #include "lm49453.h" -static struct reg_default lm49453_reg_defs[] = { +static const struct reg_default lm49453_reg_defs[] = { { 0, 0x00 }, { 1, 0x00 }, { 2, 0x00 }, diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index e1c196a419303..e3ccea229160f 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -35,7 +35,7 @@ struct max9768 { u32 flags; }; -static struct reg_default max9768_default_regs[] = { +static const struct reg_default max9768_default_regs[] = { { 0, 0 }, { 3, MAX9768_CTRL_FILTERLESS}, }; diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 29549cdbf4c1c..8df99fb69ab13 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -22,7 +22,7 @@ static struct regmap *regmap; -static struct reg_default max9877_regs[] = { +static const struct reg_default max9877_regs[] = { { 0, 0x40 }, { 1, 0x00 }, { 2, 0x00 }, diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index b74118e019fbe..1e8ede8454afb 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -199,7 +199,7 @@ static const struct clk_coeff coeff_div[] = { {12288000, 48000, 0xc, 0x0, 0x30, 0x0, 0x4}, }; -static struct reg_default ml26124_reg[] = { +static const struct reg_default ml26124_reg[] = { /* CLOCK control Register */ {0x00, 0x00 }, /* Sampling Rate */ {0x02, 0x00}, /* PLL NL */ diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 5c43e263b2c1f..7069fe8ba74c6 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -38,7 +38,7 @@ #define RT288_VENDOR_ID 0x10ec0288 struct rt286_priv { - struct reg_default *index_cache; + const struct reg_default *index_cache; int index_cache_size; struct regmap *regmap; struct snd_soc_codec *codec; @@ -50,7 +50,7 @@ struct rt286_priv { int clk_id; }; -static struct reg_default rt286_index_def[] = { +static const struct reg_default rt286_index_def[] = { { 0x01, 0xaaaa }, { 0x02, 0x8aaa }, { 0x03, 0x0002 }, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e193abcd..3ee0574794db4 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = { .window_len = 0x1, }, }; -static struct reg_default init_list[] = { +static const struct reg_default init_list[] = { {RT5651_PR_BASE + 0x3d, 0x3e00}, }; diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d0efa2a..71cfae0de3ee7 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -38,7 +38,7 @@ #include "tas2552.h" -static struct reg_default tas2552_reg_defs[] = { +static const struct reg_default tas2552_reg_defs[] = { {TAS2552_CFG_1, 0x22}, {TAS2552_CFG_3, 0x80}, {TAS2552_DOUT, 0x00}, diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index aab0af681e8cb..bf7596ba49f33 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -160,7 +160,7 @@ static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) return 0; } -static struct reg_default tfa9879_regs[] = { +static const struct reg_default tfa9879_regs[] = { { TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */ { TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */ { TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */ diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c83083285e532..01aeb75dd7741 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -166,7 +166,7 @@ static const struct wm_adsp_region wm2200_dsp2_regions[] = { { .type = WMFW_ADSP1_ZM, .base = WM2200_DSP2_ZM_BASE }, }; -static struct reg_default wm2200_reg_defaults[] = { +static const struct reg_default wm2200_reg_defaults[] = { { 0x000B, 0x0000 }, /* R11 - Tone Generator 1 */ { 0x0102, 0x0000 }, /* R258 - Clocking 3 */ { 0x0103, 0x0011 }, /* R259 - Clocking 4 */ diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd4f2962..8edc6d2034046 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -113,7 +113,7 @@ WM8962_REGULATOR_EVENT(5) WM8962_REGULATOR_EVENT(6) WM8962_REGULATOR_EVENT(7) -static struct reg_default wm8962_reg[] = { +static const struct reg_default wm8962_reg[] = { { 0, 0x009F }, /* R0 - Left Input volume */ { 1, 0x049F }, /* R1 - Right Input volume */ { 2, 0x0000 }, /* R2 - HPOUTL volume */ diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db8605dc2e..f2d5211a9a96a 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -41,7 +41,7 @@ static const char *wm8993_supply_names[WM8993_NUM_SUPPLIES] = { "SPKVDD", }; -static struct reg_default wm8993_reg_defaults[] = { +static const struct reg_default wm8993_reg_defaults[] = { { 1, 0x0000 }, /* R1 - Power Management (1) */ { 2, 0x6000 }, /* R2 - Power Management (2) */ { 3, 0x0000 }, /* R3 - Power Management (3) */ @@ -1595,7 +1595,7 @@ static int wm8993_resume(struct snd_soc_codec *codec) #endif /* Tune DC servo configuration */ -static struct reg_default wm8993_regmap_patch[] = { +static const struct reg_default wm8993_regmap_patch[] = { { 0x44, 3 }, { 0x56, 3 }, { 0x44, 0 }, diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f682b29..66f32be52da8e 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -117,7 +117,7 @@ WM8996_REGULATOR_EVENT(0) WM8996_REGULATOR_EVENT(1) WM8996_REGULATOR_EVENT(2) -static struct reg_default wm8996_reg[] = { +static const struct reg_default wm8996_reg[] = { { WM8996_POWER_MANAGEMENT_1, 0x0 }, { WM8996_POWER_MANAGEMENT_2, 0x0 }, { WM8996_POWER_MANAGEMENT_3, 0x0 }, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 8a8b1c0f91421..ec91ce8a7ca86 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -30,7 +30,7 @@ #include #include "wm9081.h" -static struct reg_default wm9081_reg[] = { +static const struct reg_default wm9081_reg[] = { { 2, 0x00B9 }, /* R2 - Analogue Lineout */ { 3, 0x00B9 }, /* R3 - Analogue Speaker PGA */ { 4, 0x0001 }, /* R4 - VMID Control */ -- GitLab From 02c4b9c28b973d999073c810a78375e38346d7a3 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Thu, 18 Jun 2015 15:16:07 -0700 Subject: [PATCH 0557/7006] ASoC: qcom: move board Kconfig deps to parent config Rather than have each board define the same set of dependencies; move the common dependencies to the SND_SOC_QCOM parent config. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 807fedfa1c76e..d6ccda7b881f4 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -1,5 +1,6 @@ config SND_SOC_QCOM tristate "ASoC support for QCOM platforms" + depends on ARCH_QCOM || COMPILE_TEST help Say Y or M if you want to add support to use audio devices in Qualcomm Technologies SOC-based platforms. @@ -26,7 +27,7 @@ config SND_SOC_LPASS_APQ8016 config SND_SOC_STORM tristate "ASoC I2S support for Storm boards" - depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST) + depends on SND_SOC_QCOM select SND_SOC_LPASS_IPQ806X select SND_SOC_MAX98357A help @@ -35,7 +36,7 @@ config SND_SOC_STORM config SND_SOC_APQ8016_SBC tristate "SoC Audio support for APQ8016 SBC platforms" - depends on SND_SOC_QCOM && (ARCH_QCOM || COMPILE_TEST) + depends on SND_SOC_QCOM select SND_SOC_LPASS_APQ8016 help Support for Qualcomm Technologies LPASS audio block in -- GitLab From 7f005256f70a8c1c60b2f8a7449137da0c5e5bd9 Mon Sep 17 00:00:00 2001 From: Kenneth Westfield Date: Thu, 18 Jun 2015 15:16:08 -0700 Subject: [PATCH 0558/7006] ASoC: qcom: remove Kconfig deps from variant configs Remove the SND_SOC_QCOM dependency from the variant configs. The board configs, which select the variants, already have this dependency. Signed-off-by: Kenneth Westfield Signed-off-by: Mark Brown --- sound/soc/qcom/Kconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index d6ccda7b881f4..3cc252e55468e 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -15,13 +15,11 @@ config SND_SOC_LPASS_PLATFORM config SND_SOC_LPASS_IPQ806X tristate - depends on SND_SOC_QCOM select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM config SND_SOC_LPASS_APQ8016 tristate - depends on SND_SOC_QCOM select SND_SOC_LPASS_CPU select SND_SOC_LPASS_PLATFORM -- GitLab From e2ada8187bc8b46c30a623e7d6b5a72c209f70cd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:06 +0200 Subject: [PATCH 0559/7006] ASoC: rt5645: Replace direct snd_soc_codec dapm field access The dapm field of the snd_soc_codec struct is eventually going to be removed, in preparation for this replace all manual access to codec->dapm.bias_level with snd_soc_codec_get_bias_level() and replace all other manual access to codec->dapm with snd_soc_codec_get_dapm(). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 73 +++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 41 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc5..571e4b5895e20 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2642,7 +2642,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_PREPARE: - if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) { + if (SND_SOC_BIAS_STANDBY == snd_soc_codec_get_bias_level(codec)) { snd_soc_update_bits(codec, RT5645_PWR_ANLG1, RT5645_PWR_VREF1 | RT5645_PWR_MB | RT5645_PWR_BG | RT5645_PWR_VREF2, @@ -2760,20 +2760,17 @@ static int rt5650_calibration(struct rt5645_priv *rt5645) static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); if (enable) { - snd_soc_dapm_mutex_lock(&codec->dapm); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "ADC L power"); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "ADC R power"); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "LDO2"); - snd_soc_dapm_force_enable_pin_unlocked(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync_unlocked(&codec->dapm); - snd_soc_dapm_mutex_unlock(&codec->dapm); + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC L power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC R power"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Det Power"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); @@ -2786,23 +2783,20 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0); - snd_soc_dapm_mutex_lock(&codec->dapm); - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "ADC L power"); - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "ADC R power"); + snd_soc_dapm_mutex_lock(dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "ADC L power"); + snd_soc_dapm_disable_pin_unlocked(dapm, "ADC R power"); if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "LDO2"); - snd_soc_dapm_disable_pin_unlocked(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync_unlocked(&codec->dapm); - snd_soc_dapm_mutex_unlock(&codec->dapm); + snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); + snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Det Power"); + snd_soc_dapm_sync_unlocked(dapm); + snd_soc_dapm_mutex_unlock(dapm); } } static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); unsigned int val; @@ -2811,10 +2805,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (codec->component.card->instantiated) { /* for jack type detect */ - snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); - snd_soc_dapm_force_enable_pin(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } else { /* Power up necessary bits for JD if dapm is not ready yet */ @@ -2847,9 +2840,8 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } } else { if (codec->component.card->instantiated) { - snd_soc_dapm_disable_pin(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } else regmap_update_bits(rt5645->regmap, RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); @@ -2863,11 +2855,9 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) else { if (codec->component.card->instantiated) { if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin(&codec->dapm, - "LDO2"); - snd_soc_dapm_disable_pin(&codec->dapm, - "Mic Det Power"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_disable_pin(dapm, "LDO2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } else { if (rt5645->pdata.jd_mode == 0) regmap_update_bits(rt5645->regmap, @@ -3043,21 +3033,22 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645) static int rt5645_probe(struct snd_soc_codec *codec) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); rt5645->codec = codec; switch (rt5645->codec_type) { case CODEC_TYPE_RT5645: - snd_soc_dapm_add_routes(&codec->dapm, + snd_soc_dapm_add_routes(dapm, rt5645_specific_dapm_routes, ARRAY_SIZE(rt5645_specific_dapm_routes)); break; case CODEC_TYPE_RT5650: - snd_soc_dapm_new_controls(&codec->dapm, + snd_soc_dapm_new_controls(dapm, rt5650_specific_dapm_widgets, ARRAY_SIZE(rt5650_specific_dapm_widgets)); - snd_soc_dapm_add_routes(&codec->dapm, + snd_soc_dapm_add_routes(dapm, rt5650_specific_dapm_routes, ARRAY_SIZE(rt5650_specific_dapm_routes)); break; @@ -3067,9 +3058,9 @@ static int rt5645_probe(struct snd_soc_codec *codec) /* for JD function */ if (rt5645->pdata.jd_mode) { - snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_force_enable_pin(dapm, "JD Power"); + snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + snd_soc_dapm_sync(dapm); } return 0; -- GitLab From 8f218fa93d20a7b4ef8a088e5eed2d84b8ef4ab5 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:07 +0200 Subject: [PATCH 0560/7006] ASoC: tas571x: Replace direct snd_soc_codec dapm field access The dapm field of the snd_soc_codec struct is eventually going to be removed, in preparation for this replace all manual access to codec->dapm.bias_level with snd_soc_codec_get_bias_level(). Signed-off-by: Lars-Peter Clausen Acked-by: Kevin Cernekee Signed-off-by: Mark Brown --- sound/soc/codecs/tas571x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index 85bcc374c8e8e..39307ad41a34f 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -179,7 +179,7 @@ static int tas571x_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_OFF) { if (!IS_ERR(priv->mclk)) { ret = clk_prepare_enable(priv->mclk); if (ret) { -- GitLab From 987731bb7c80b170228e6e1acf2e7b91efb51100 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:08 +0200 Subject: [PATCH 0561/7006] ASoC: omap3pandora: Use card DAPM context to access widgets The dapm field of the snd_soc_codec struct will eventually be removed (replaced with the DAPM context from the component embedded inside the CODEC). Replace its usage with the card's DAPM context. The idea is that DAPM is hierarchical and with the card at the root it is possible to access widgets from other contexts through the card context. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/omap/omap3pandora.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/omap/omap3pandora.c b/sound/soc/omap/omap3pandora.c index 076bec606d78a..732e749a1f8ed 100644 --- a/sound/soc/omap/omap3pandora.c +++ b/sound/soc/omap/omap3pandora.c @@ -154,8 +154,7 @@ static const struct snd_soc_dapm_route omap3pandora_map[] = { static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; /* All TWL4030 output pins are floating */ snd_soc_dapm_nc_pin(dapm, "EARPIECE"); @@ -174,8 +173,7 @@ static int omap3pandora_out_init(struct snd_soc_pcm_runtime *rtd) static int omap3pandora_in_init(struct snd_soc_pcm_runtime *rtd) { - struct snd_soc_codec *codec = rtd->codec; - struct snd_soc_dapm_context *dapm = &codec->dapm; + struct snd_soc_dapm_context *dapm = &rtd->card->dapm; /* Not comnnected */ snd_soc_dapm_nc_pin(dapm, "HSMIC"); -- GitLab From c68c2be5f6ae4a27d548921bf8b32413c5eab8ed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:09 +0200 Subject: [PATCH 0562/7006] ASoC: cht_bsw_max98090_ti: Use card DAPM context to access widgets The dapm field of the snd_soc_codec struct will eventually be removed (replaced with the DAPM context from the component embedded inside the CODEC). Replace its usage with the card's DAPM context. The idea is that DAPM is hierarchical and with the card at the root it is possible to access widgets from other contexts through the card context. While we are at it also remove some extra newlines. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/intel/boards/cht_bsw_max98090_ti.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/sound/soc/intel/boards/cht_bsw_max98090_ti.c b/sound/soc/intel/boards/cht_bsw_max98090_ti.c index d604ee80eda4b..afcd6baa3cbce 100644 --- a/sound/soc/intel/boards/cht_bsw_max98090_ti.c +++ b/sound/soc/intel/boards/cht_bsw_max98090_ti.c @@ -104,21 +104,17 @@ static int cht_aif1_hw_params(struct snd_pcm_substream *substream, static int cht_ti_jack_event(struct notifier_block *nb, unsigned long event, void *data) { - struct snd_soc_jack *jack = (struct snd_soc_jack *)data; - struct snd_soc_dai *codec_dai = jack->card->rtd->codec_dai; - struct snd_soc_codec *codec = codec_dai->codec; + struct snd_soc_dapm_context *dapm = &jack->card->dapm; if (event & SND_JACK_MICROPHONE) { - - snd_soc_dapm_force_enable_pin(&codec->dapm, "SHDN"); - snd_soc_dapm_force_enable_pin(&codec->dapm, "MICBIAS"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_force_enable_pin(dapm, "SHDN"); + snd_soc_dapm_force_enable_pin(dapm, "MICBIAS"); + snd_soc_dapm_sync(dapm); } else { - - snd_soc_dapm_disable_pin(&codec->dapm, "MICBIAS"); - snd_soc_dapm_disable_pin(&codec->dapm, "SHDN"); - snd_soc_dapm_sync(&codec->dapm); + snd_soc_dapm_disable_pin(dapm, "MICBIAS"); + snd_soc_dapm_disable_pin(dapm, "SHDN"); + snd_soc_dapm_sync(dapm); } return 0; -- GitLab From b3c25fb7caa30afa5d5cc6b414a5b4d66bed77a7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:10 +0200 Subject: [PATCH 0563/7006] ASoC: dapm_widget_show_codec: Use component instead of CODEC There is nothing snd_soc_codec specific in this function, just use snd_soc_component instead. With this also the last reference of snd_soc_codec form soc-dapm.c. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index aa327c92480c5..a6c0ed15fc146 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2220,14 +2220,16 @@ int snd_soc_dapm_mixer_update_power(struct snd_soc_dapm_context *dapm, } EXPORT_SYMBOL_GPL(snd_soc_dapm_mixer_update_power); -static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf) +static ssize_t dapm_widget_show_component(struct snd_soc_component *cmpnt, + char *buf) { + struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(cmpnt); struct snd_soc_dapm_widget *w; int count = 0; char *state = "not set"; - list_for_each_entry(w, &codec->component.card->widgets, list) { - if (w->dapm != &codec->dapm) + list_for_each_entry(w, &cmpnt->card->widgets, list) { + if (w->dapm != dapm) continue; /* only display widgets that burnm power */ @@ -2255,7 +2257,7 @@ static ssize_t dapm_widget_show_codec(struct snd_soc_codec *codec, char *buf) } } - switch (codec->dapm.bias_level) { + switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_ON: state = "On"; break; @@ -2282,8 +2284,9 @@ static ssize_t dapm_widget_show(struct device *dev, int i, count = 0; for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_codec *codec = rtd->codec_dais[i]->codec; - count += dapm_widget_show_codec(codec, buf + count); + struct snd_soc_component *cmpnt = rtd->codec_dais[i]->component; + + count += dapm_widget_show_component(cmpnt, buf + count); } return count; -- GitLab From 4890140f3888b4a4baef90d84e278858afe45248 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 6 Jul 2015 15:38:11 +0200 Subject: [PATCH 0564/7006] ASoC: Remove snd_soc_codec dapm field There are no more direct users of the snd_soc_codec DAPM field left. So we can finally remove it and switch over to directly using the component DAPM context and remove the dapm_ptr indirection. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 10 +++------- sound/soc/soc-core.c | 23 ++++++++++++----------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf9d54a9..3ccd82a16d549 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -792,7 +792,6 @@ struct snd_soc_component { /* Don't use these, use snd_soc_component_get_dapm() */ struct snd_soc_dapm_context dapm; - struct snd_soc_dapm_context *dapm_ptr; const struct snd_kcontrol_new *controls; unsigned int num_controls; @@ -832,9 +831,6 @@ struct snd_soc_codec { /* component */ struct snd_soc_component component; - /* Don't access this directly, use snd_soc_codec_get_dapm() */ - struct snd_soc_dapm_context dapm; - #ifdef CONFIG_DEBUG_FS struct dentry *debugfs_reg; #endif @@ -1277,7 +1273,7 @@ static inline struct snd_soc_component *snd_soc_dapm_to_component( static inline struct snd_soc_codec *snd_soc_dapm_to_codec( struct snd_soc_dapm_context *dapm) { - return container_of(dapm, struct snd_soc_codec, dapm); + return snd_soc_component_to_codec(snd_soc_dapm_to_component(dapm)); } /** @@ -1302,7 +1298,7 @@ static inline struct snd_soc_platform *snd_soc_dapm_to_platform( static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( struct snd_soc_component *component) { - return component->dapm_ptr; + return &component->dapm; } /** @@ -1314,7 +1310,7 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm( static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm( struct snd_soc_codec *codec) { - return &codec->dapm; + return snd_soc_component_get_dapm(&codec->component); } /** diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0e3f973..3747111f87598 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -654,10 +654,12 @@ int snd_soc_suspend(struct device *dev) /* suspend all CODECs */ list_for_each_entry(codec, &card->codec_dev_list, card_list) { + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + /* If there are paths active then the CODEC will be held with * bias _ON and should not be suspended. */ if (!codec->suspended) { - switch (codec->dapm.bias_level) { + switch (snd_soc_dapm_get_bias_level(dapm)) { case SND_SOC_BIAS_STANDBY: /* * If the CODEC is capable of idle @@ -665,7 +667,7 @@ int snd_soc_suspend(struct device *dev) * means it's doing something, * otherwise fall through. */ - if (codec->dapm.idle_bias_off) { + if (dapm->idle_bias_off) { dev_dbg(codec->dev, "ASoC: idle_bias_off CODEC on over suspend\n"); break; @@ -2651,10 +2653,7 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, component->probe = component->driver->probe; component->remove = component->driver->remove; - if (!component->dapm_ptr) - component->dapm_ptr = &component->dapm; - - dapm = component->dapm_ptr; + dapm = &component->dapm; dapm->dev = dev; dapm->component = component; dapm->bias_level = SND_SOC_BIAS_OFF; @@ -3036,6 +3035,7 @@ int snd_soc_register_codec(struct device *dev, struct snd_soc_dai_driver *dai_drv, int num_dai) { + struct snd_soc_dapm_context *dapm; struct snd_soc_codec *codec; struct snd_soc_dai *dai; int ret, i; @@ -3046,7 +3046,6 @@ int snd_soc_register_codec(struct device *dev, if (codec == NULL) return -ENOMEM; - codec->component.dapm_ptr = &codec->dapm; codec->component.codec = codec; ret = snd_soc_component_initialize(&codec->component, @@ -3076,12 +3075,14 @@ int snd_soc_register_codec(struct device *dev, if (codec_drv->read) codec->component.read = snd_soc_codec_drv_read; codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; - codec->dapm.idle_bias_off = codec_drv->idle_bias_off; - codec->dapm.suspend_bias_off = codec_drv->suspend_bias_off; + + dapm = snd_soc_codec_get_dapm(codec); + dapm->idle_bias_off = codec_drv->idle_bias_off; + dapm->suspend_bias_off = codec_drv->suspend_bias_off; if (codec_drv->seq_notifier) - codec->dapm.seq_notifier = codec_drv->seq_notifier; + dapm->seq_notifier = codec_drv->seq_notifier; if (codec_drv->set_bias_level) - codec->dapm.set_bias_level = snd_soc_codec_set_bias_level; + dapm->set_bias_level = snd_soc_codec_set_bias_level; codec->dev = dev; codec->driver = codec_drv; codec->component.val_bytes = codec_drv->reg_word_size; -- GitLab From c5b8540dca22526517f4d96857678466613467d1 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Mon, 6 Jul 2015 10:02:10 +0800 Subject: [PATCH 0565/7006] ASoC: dpcm: Add checks of playback/capture before dpcm_get_be In dpcm_get_be(), it looks for a BE rtd that has the DAI widget according to current stream type. Only playback_widgets are searched in the case of playback stream and vice versa. However, the DAI widget itself can be playback or capture. If the DAI widget is capture, but current stream type is playback, dpcm_get_be() will always fail to find a rtd, print error messages, and continue to the next DAI widget in list. We can just skip this DAI widget to further suppress error messages. This happens in a special case when 2 codecs are inter-connected, and the 1st codec's "capture" widget is used to send data to the 2nd codec during "playback": mtk-rt5650-rt5676 sound: ASoC: can't get playback BE for Sub AIF2 Capture rt5650_rt5676 Playback: ASoC: no BE found for Sub AIF2 Capture Add checks to continue to next DAI widget if current DAI widget's direction does not match the stream type. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/soc-pcm.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 256b9c91aa943..a6d33136d7552 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -1306,7 +1306,12 @@ static int dpcm_add_paths(struct snd_soc_pcm_runtime *fe, int stream, switch (list->widgets[i]->id) { case snd_soc_dapm_dai_in: + if (stream != SNDRV_PCM_STREAM_PLAYBACK) + continue; + break; case snd_soc_dapm_dai_out: + if (stream != SNDRV_PCM_STREAM_CAPTURE) + continue; break; default: continue; -- GitLab From 9acc7f08716b98730e1ead7e785fb0f3ad3a2d07 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:50 -0300 Subject: [PATCH 0566/7006] ASoC: max98090: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/max98090.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f0514e95..1697340c38429 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -1801,10 +1801,13 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec, if (IS_ERR(max98090->mclk)) break; - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { clk_disable_unprepare(max98090->mclk); - else - clk_prepare_enable(max98090->mclk); + } else { + ret = clk_prepare_enable(max98090->mclk); + if (ret) + return ret; + } break; case SND_SOC_BIAS_STANDBY: -- GitLab From 6e78108bda78adbb2d4ef55ec60a388aba975797 Mon Sep 17 00:00:00 2001 From: Shengjiu Wang Date: Fri, 3 Jul 2015 16:30:30 +0800 Subject: [PATCH 0567/7006] ASoC: core: Don't probe the component which is dummy Dummy dai can be used by multiple sound card. But it only belong to one card's dapm list. If another card use it, there will be dapm_assert_locked warning. [ 20.015782] WARNING: CPU: 1 PID: 661 at sound/soc/soc-dapm.c:124 dapm_assert_locked.isra.36+0x4c/0x58() [ 20.025249] Modules linked in: [ 20.028349] CPU: 1 PID: 661 Comm: aplay Not tainted 4.1.0-rc6-next-20150605-00004-gaee05d8-dirty #92 [ 20.037528] Hardware name: Freescale i.MX6 Quad/DualLite (Device Tree) [ 20.044110] Backtrace: [ 20.046614] [<80012e00>] (dump_backtrace) from [<80012fa0>] (show_stack+0x18/0x1c) [ 20.054229] r6:809e8060 r5:00000000 r4:00000000 r3:00000000 [ 20.060002] [<80012f88>] (show_stack) from [<807a0f74>] (dump_stack+0x80/0x9c) [ 20.067293] [<807a0ef4>] (dump_stack) from [<8002b144>] (warn_slowpath_common+0x7c/0xb4) [ 20.075427] r5:0000007c r4:00000000 [ 20.079065] [<8002b0c8>] (warn_slowpath_common) from [<8002b1a0>] (warn_slowpath_null+0x24/0x2c) [ 20.087898] r8:00000001 r7:88007c28 r6:ed94a680 r5:809e83e4 r4:ed83d6c0 [ 20.094747] [<8002b17c>] (warn_slowpath_null) from [<8058403c>] (dapm_assert_locked.isra.36+0x4c/0x58) [ 20.104101] [<80583ff0>] (dapm_assert_locked.isra.36) from [<805842ec>] (dapm_mark_dirty+0x64/0xa4) [ 20.113165] [<80584288>] (dapm_mark_dirty) from [<805853a8>] (soc_dapm_dai_stream_event.isra.42+0x30/0xc8) [ 20.122863] r8:ed9b5dbc r7:00000000 r6:00000001 r5:00000001 r4:ed83d6c0 [ 20.129706] [<80585378>] (soc_dapm_dai_stream_event.isra.42) from [<80587e28>] (snd_soc_dapm_stream_event+0x78/0xa0) [ 20.140264] r5:ee2ee62c r4:00000001 [ 20.143918] [<80587db0>] (snd_soc_dapm_stream_event) from [<8058957c>] (soc_pcm_prepare+0x138/0x21c) [ 20.153058] r8:ed8d9480 r7:00000000 r6:ed9b0e00 r5:00000001 r4:ee2ee62c r3:00000000 ... This patch is to not probe the dummy component in soc_probe_component. Then there is no widget created for dummy DAI, and also don't need to check the dummy dai in dapm_connect_dai_link_widgets(). Signed-off-by: Shengjiu Wang Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- sound/soc/soc-dapm.c | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0e3f973..6ce621749f8d0 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1102,7 +1102,7 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_dai *dai; int ret; - if (component->probed) + if (!strcmp(component->name, "snd-soc-dummy") || component->probed) return 0; component->card = card; diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index aa327c92480c5..37ab6b9b6902e 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -3820,11 +3820,6 @@ static void dapm_connect_dai_link_widgets(struct snd_soc_card *card, for (i = 0; i < rtd->num_codecs; i++) { struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - /* there is no point in connecting BE DAI links with dummies */ - if (snd_soc_dai_is_dummy(codec_dai) || - snd_soc_dai_is_dummy(cpu_dai)) - continue; - /* connect BE DAI playback if widgets are valid */ if (codec_dai->playback_widget && cpu_dai->playback_widget) { source = cpu_dai->playback_widget; -- GitLab From b7e79329c4e34d63cd374e603ece91f2b2c3331e Mon Sep 17 00:00:00 2001 From: Martin Kepplinger Date: Mon, 6 Jul 2015 15:52:21 -0700 Subject: [PATCH 0568/7006] Input: bma150 - use sign_extend32() for sign extending Despite it's name, sign_extend32() is used for 16 bit values aswell. Signed-off-by: Martin Kepplinger Signed-off-by: Dmitry Torokhov --- drivers/input/misc/bma150.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index b36831c828d3f..c2780493b0edb 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -333,10 +333,9 @@ static void bma150_report_xyz(struct bma150_data *bma150) y = ((0xc0 & data[2]) >> 6) | (data[3] << 2); z = ((0xc0 & data[4]) >> 6) | (data[5] << 2); - /* sign extension */ - x = (s16) (x << 6) >> 6; - y = (s16) (y << 6) >> 6; - z = (s16) (z << 6) >> 6; + x = sign_extend32(x, 9); + y = sign_extend32(y, 9); + z = sign_extend32(z, 9); input_report_abs(bma150->input, ABS_X, x); input_report_abs(bma150->input, ABS_Y, y); -- GitLab From 4c62dbbce902cf2afa88cac89ec67c828160f431 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Fri, 26 Jun 2015 11:27:41 +0300 Subject: [PATCH 0569/7006] ACPI: Remove FSF mailing addresses There is no need to carry potentially outdated Free Software Foundation mailing address in file headers since the COPYING file includes it. Signed-off-by: Jarkko Nikula Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ac.c | 4 ---- drivers/acpi/acpi_ipmi.c | 4 ---- drivers/acpi/acpi_memhotplug.c | 5 ----- drivers/acpi/acpi_pad.c | 4 ---- drivers/acpi/acpi_video.c | 4 ---- drivers/acpi/apei/apei-base.c | 4 ---- drivers/acpi/apei/einj.c | 4 ---- drivers/acpi/apei/erst-dbg.c | 4 ---- drivers/acpi/apei/erst.c | 4 ---- drivers/acpi/apei/ghes.c | 4 ---- drivers/acpi/apei/hest.c | 4 ---- drivers/acpi/battery.c | 4 ---- drivers/acpi/blacklist.c | 4 ---- drivers/acpi/bus.c | 4 ---- drivers/acpi/button.c | 4 ---- drivers/acpi/cm_sbs.c | 4 ---- drivers/acpi/container.c | 4 ---- drivers/acpi/device_pm.c | 4 ---- drivers/acpi/dock.c | 4 ---- drivers/acpi/ec.c | 4 ---- drivers/acpi/fan.c | 4 ---- drivers/acpi/hed.c | 4 ---- drivers/acpi/internal.h | 3 --- drivers/acpi/numa.c | 4 ---- drivers/acpi/osl.c | 4 ---- drivers/acpi/pci_irq.c | 4 ---- drivers/acpi/pci_link.c | 4 ---- drivers/acpi/pci_root.c | 4 ---- drivers/acpi/pci_slot.c | 4 ---- drivers/acpi/power.c | 4 ---- drivers/acpi/processor_driver.c | 4 ---- drivers/acpi/processor_idle.c | 4 ---- drivers/acpi/processor_perflib.c | 4 ---- drivers/acpi/processor_thermal.c | 4 ---- drivers/acpi/processor_throttling.c | 4 ---- drivers/acpi/resource.c | 4 ---- drivers/acpi/sbs.c | 4 ---- drivers/acpi/tables.c | 4 ---- drivers/acpi/thermal.c | 4 ---- drivers/acpi/utils.c | 4 ---- include/acpi/acpi_bus.h | 4 ---- include/acpi/acpi_drivers.h | 4 ---- include/linux/acpi.h | 4 ---- 43 files changed, 172 deletions(-) diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c index 9b5354a2cd089..f71b756b05c40 100644 --- a/drivers/acpi/ac.c +++ b/drivers/acpi/ac.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/acpi_ipmi.c b/drivers/acpi/acpi_ipmi.c index ac0f52f6df2b8..f77956c3fd45f 100644 --- a/drivers/acpi/acpi_ipmi.c +++ b/drivers/acpi/acpi_ipmi.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c index ee28f4d15625f..6b0d3ef7309cb 100644 --- a/drivers/acpi/acpi_memhotplug.c +++ b/drivers/acpi/acpi_memhotplug.c @@ -16,11 +16,6 @@ * NON INFRINGEMENT. See the GNU General Public License for more * details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * * ACPI based HotPlug driver that supports Memory Hotplug * This driver fields notifications from firmware for memory add * and remove operations and alerts the VM of the affected memory diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 00b39802d7ecf..ae307ff36acb9 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c @@ -12,10 +12,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * */ #include diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 8c2fe2f2f9fdc..5778e8e4313a1 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c index a85ac07f3da3a..a2c8d7adb6eb5 100644 --- a/drivers/acpi/apei/apei-base.c +++ b/drivers/acpi/apei/apei-base.c @@ -24,10 +24,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/einj.c b/drivers/acpi/apei/einj.c index a095d4f858da7..0431883653bed 100644 --- a/drivers/acpi/apei/einj.c +++ b/drivers/acpi/apei/einj.c @@ -18,10 +18,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/erst-dbg.c b/drivers/acpi/apei/erst-dbg.c index 04ab5c9d3cedc..6330f557a2c88 100644 --- a/drivers/acpi/apei/erst-dbg.c +++ b/drivers/acpi/apei/erst-dbg.c @@ -17,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c index 3670bbab57a34..6682c5daf7426 100644 --- a/drivers/acpi/apei/erst.c +++ b/drivers/acpi/apei/erst.c @@ -18,10 +18,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c index 2bfd53cbfe807..23981ac1c6c21 100644 --- a/drivers/acpi/apei/ghes.c +++ b/drivers/acpi/apei/ghes.c @@ -23,10 +23,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/apei/hest.c b/drivers/acpi/apei/hest.c index 06e9b411a0a2c..20b3fcf4007ca 100644 --- a/drivers/acpi/apei/hest.c +++ b/drivers/acpi/apei/hest.c @@ -21,10 +21,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index b3628cc01a535..b719ab3090bb2 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -18,10 +18,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c index 278dc4be992a4..96809cd99ace8 100644 --- a/drivers/acpi/blacklist.c +++ b/drivers/acpi/blacklist.c @@ -20,10 +20,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 513e7230e3d04..c8356eb799116 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 6d5d1832a5880..5c3b0918d5fda 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/cm_sbs.c b/drivers/acpi/cm_sbs.c index 6c9ee68e46fb0..d0918d421f90a 100644 --- a/drivers/acpi/cm_sbs.c +++ b/drivers/acpi/cm_sbs.c @@ -11,10 +11,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index c8ead9f973753..12c240903c183 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -20,10 +20,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 717afcdb5f4a9..d06cd59b5906f 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index a688aa243f6c0..e8e128dede299 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9d4761d2f6b77..9904466299356 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -22,10 +22,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index bea0bbaafa979..e297a480e1350 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c index a322710b5ba47..5c67a6d8f803b 100644 --- a/drivers/acpi/hed.c +++ b/drivers/acpi/hed.c @@ -15,10 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4683a96932b91..8c71cb8335c0c 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -13,9 +13,6 @@ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _ACPI_INTERNAL_H_ diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index acaa3b4ea504c..72b6e9ef0ae9b 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index c262e4acd68d8..5e1f1bc5421ea 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -19,10 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 304eccb0ae5cf..25fff35df82c1 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -19,10 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index cfd7581cc19fa..2f5f84ced85fb 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * TBD: diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1b5569c092c6e..393706a5261b0 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c index 139d9e4793703..7188e53b6b7c5 100644 --- a/drivers/acpi/pci_slot.c +++ b/drivers/acpi/pci_slot.c @@ -20,10 +20,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. */ #include diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 93eac53b5110b..45b47f2c9f03c 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d9f71581b79b2..3af8dc30f129d 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -21,10 +21,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index d540f42c92328..175c86bee3a95 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -21,10 +21,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cfc8aba72f86d..53cfe8ba9799f 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -20,10 +20,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * */ #include diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index e003663b2f8e5..1fed84a092c21 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -19,10 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index 84243c32e29c5..f170d746336d3 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -19,10 +19,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 10561ce16ed13..64ea0d10b7881 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c index 01504c819e8f6..cb3dedb1beaed 100644 --- a/drivers/acpi/sbs.c +++ b/drivers/acpi/sbs.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 2e19189da0ee4..17a6fa01a3384 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * */ diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 6d4e44ea74acc..fc28b9f5aa84b 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This driver fully implements the ACPI thermal policy as described in the diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 67c548ad3764c..475c9079bf856 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 83061cac719bc..5ba8fb64f664e 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h index ea6428b7dacb6..29c691265b493 100644 --- a/include/acpi/acpi_drivers.h +++ b/include/acpi/acpi_drivers.h @@ -16,10 +16,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ diff --git a/include/linux/acpi.h b/include/linux/acpi.h index c471dfc93b716..1c116ee53b1eb 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -15,10 +15,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ -- GitLab From 274b2000a09220bb2b930af432a2262db7063bd9 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Tue, 7 Jul 2015 21:52:24 +0200 Subject: [PATCH 0570/7006] ALSA: emu10k1: remove unused AC'97 mixer controls on Audigy AC'97 Headphone output and EAPD control aren't used on Audigy so remove them from mixer. Also remove AC'97 3D control as the driver is already doing for Audigys with 1361T ADC. Signed-off-by: Maciej Szmigiero Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 55e57166256e9..f1cb7b37c8ec9 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1830,10 +1830,16 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Capture Switch", "Capture Volume", "Mic Select", + "Headphone Playback Switch", + "Headphone Playback Volume", + "3D Control - Center", + "3D Control - Depth", + "3D Control - Switch", "Video Playback Switch", "Video Playback Volume", "Mic Playback Switch", "Mic Playback Volume", + "External Amplifier", NULL }; static char *audigy_rename_ctls[] = { @@ -1996,11 +2002,6 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, rename_ctl(card, "Analog Mix Capture Volume", "Line2 Capture Volume"); rename_ctl(card, "Aux2 Capture Volume", "Line3 Capture Volume"); rename_ctl(card, "Mic Capture Volume", "Unknown1 Capture Volume"); - remove_ctl(card, "Headphone Playback Switch"); - remove_ctl(card, "Headphone Playback Volume"); - remove_ctl(card, "3D Control - Center"); - remove_ctl(card, "3D Control - Depth"); - remove_ctl(card, "3D Control - Switch"); } if ((kctl = emu->ctl_send_routing = snd_ctl_new1(&snd_emu10k1_send_routing_control, emu)) == NULL) return -ENOMEM; -- GitLab From 52051942943f4ef95a8e953aeed84360291380d8 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Tue, 7 Jul 2015 21:53:15 +0200 Subject: [PATCH 0571/7006] ALSA: emu10k1: enable TAD mic out on Audigy Enable TAD output on Audigy naming it "Phone Output", to be consistent with TAD input which is called "Phone". According to Creative doc ( http://support.creative.com/kb/ShowArticle.aspx?sid=3026 ) this should output just mic signal. Signed-off-by: Maciej Szmigiero Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index f1cb7b37c8ec9..567b5cb247538 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1819,8 +1819,6 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, * the Philips ADC for 24bit capture */ "PCM Playback Switch", "PCM Playback Volume", - "Master Mono Playback Switch", - "Master Mono Playback Volume", "Master Playback Switch", "Master Playback Volume", "PCM Out Path & Mute", @@ -1848,6 +1846,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, /* "Wave Capture Volume", "PCM Capture Volume", */ "Wave Master Playback Volume", "Master Playback Volume", "AMic Playback Volume", "Mic Playback Volume", + "Master Mono Playback Switch", "Phone Output Playback Switch", + "Master Mono Playback Volume", "Phone Output Playback Volume", NULL }; static char *audigy_rename_ctls_i2c_adc[] = { @@ -1873,8 +1873,6 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, * the Philips ADC for 24bit capture */ "PCM Playback Switch", "PCM Playback Volume", - "Master Mono Playback Switch", - "Master Mono Playback Volume", "Capture Source", "Capture Switch", "Capture Volume", @@ -1906,7 +1904,8 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Aux Playback Volume", "Aux Capture Volume", "Video Playback Switch", "Video Capture Switch", "Video Playback Volume", "Video Capture Volume", - + "Master Mono Playback Switch", "Phone Output Playback Switch", + "Master Mono Playback Volume", "Phone Output Playback Volume", NULL }; @@ -1941,6 +1940,9 @@ int snd_emu10k1_mixer(struct snd_emu10k1 *emu, snd_ac97_write_cache(emu->ac97, AC97_MASTER, 0x0000); /* set capture source to mic */ snd_ac97_write_cache(emu->ac97, AC97_REC_SEL, 0x0000); + /* set mono output (TAD) to mic */ + snd_ac97_update_bits(emu->ac97, AC97_GENERAL_PURPOSE, + 0x0200, 0x0200); if (emu->card_capabilities->adc_1361t) c = audigy_remove_ctls_1361t_adc; else -- GitLab From 2a52feb1805aaef9ce356e5a5c64d498b65e7e81 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Tue, 7 Jul 2015 21:54:02 +0200 Subject: [PATCH 0572/7006] ALSA: emu10k1: rename Audigy Analog Capture Boost control Audigy has "Analog Capture Boost" mixer control, however now this only controls mic level, not other analog sources. It applies also both to playback and capture, so rename it to something more descriptive. Signed-off-by: Maciej Szmigiero Signed-off-by: Takashi Iwai --- sound/pci/emu10k1/emumixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 567b5cb247538..076b117009c58 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1741,7 +1741,7 @@ static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_audigy_capture_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Capture Boost", + .name = "Mic Extra Boost", .info = snd_audigy_capture_boost_info, .get = snd_audigy_capture_boost_get, .put = snd_audigy_capture_boost_put -- GitLab From 21589ebda68172baeb03f35533ee2ec34543bf55 Mon Sep 17 00:00:00 2001 From: Guilhem Lettron Date: Sat, 27 Jun 2015 17:02:23 +0200 Subject: [PATCH 0573/7006] HID: sensor-hub: Add in quirk for Lenovo Yogas with ITE Like yogas with TEXAS_INSTRUMENTS, yogas with ITE chips needs to be initialized with enumeration quirks. Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-sensor-hub.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d8163..9a59810a0b217 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -497,6 +497,9 @@ #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 +#define USB_VENDOR_ID_ITE 0x048d +#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386 + #define USB_VENDOR_ID_JABRA 0x0b0e #define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412 #define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420 diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c index 090a1ba0abb6f..a76eb2a0a987b 100644 --- a/drivers/hid/hid-sensor-hub.c +++ b/drivers/hid/hid-sensor-hub.c @@ -774,6 +774,9 @@ static const struct hid_device_id sensor_hub_devices[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_TEXAS_INSTRUMENTS, USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA), .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_ITE, + USB_DEVICE_ID_ITE_LENOVO_YOGA), + .driver_data = HID_SENSOR_HUB_ENUM_QUIRK}, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID, HID_ANY_ID) }, { } -- GitLab From 615322f6ac358f9c94b483d0a16f3f46fcb27b1c Mon Sep 17 00:00:00 2001 From: Oliver Neukum Date: Mon, 29 Jun 2015 11:10:41 +0200 Subject: [PATCH 0574/7006] HID: usbhid: no flushing if device is already polled During open() it is unnecessary to wait for the device to flush stale inputs if the device is polled while closed due to a quirk or opening fails. Signed-off-by: Oliver Neukum Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index bfbe1bedda7f3..1a23d78fe5e70 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -710,7 +710,8 @@ int usbhid_open(struct hid_device *hid) * Wait 50 msec for the queue to empty before allowing events * to go through hid. */ - msleep(50); + if (res == 0 && !(hid->quirks & HID_QUIRK_ALWAYS_POLL)) + msleep(50); clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); } done: -- GitLab From ff2a31171016771829fd1689af65752175de1940 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:03 -0300 Subject: [PATCH 0575/7006] drm/i915: move FBC vfuncs to struct i915_fbc Because it makes more sense there, IMHO. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 7 +++-- drivers/gpu/drm/i915/intel_display.c | 4 +-- drivers/gpu/drm/i915/intel_fbc.c | 44 ++++++++++++++-------------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 464b28d5e6781..79d7ecec1bbf0 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -598,9 +598,6 @@ struct intel_limit; struct dpll; struct drm_i915_display_funcs { - bool (*fbc_enabled)(struct drm_device *dev); - void (*enable_fbc)(struct drm_crtc *crtc); - void (*disable_fbc)(struct drm_device *dev); int (*get_display_clock_speed)(struct drm_device *dev); int (*get_fifo_size)(struct drm_device *dev, int plane); /** @@ -939,6 +936,10 @@ struct i915_fbc { FBC_CHIP_DEFAULT, /* disabled by default on this chip */ FBC_ROTATION, /* rotation is not supported */ } no_fbc_reason; + + bool (*fbc_enabled)(struct drm_device *dev); + void (*enable_fbc)(struct drm_crtc *crtc); + void (*disable_fbc)(struct drm_device *dev); }; /** diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3c2425f5366d3..aefcf028fd920 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3134,8 +3134,8 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_device *dev = crtc->dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->display.disable_fbc) - dev_priv->display.disable_fbc(dev); + if (dev_priv->fbc.disable_fbc) + dev_priv->fbc.disable_fbc(dev); dev_priv->display.update_primary_plane(crtc, fb, x, y); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 65f08e330dc18..07ea5b311d27f 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -341,7 +341,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) * the prior work. */ if (work->crtc->primary->fb == work->fb) { - dev_priv->display.enable_fbc(work->crtc); + dev_priv->fbc.enable_fbc(work->crtc); dev_priv->fbc.crtc = to_intel_crtc(work->crtc); dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; @@ -393,7 +393,7 @@ static void intel_fbc_enable(struct drm_crtc *crtc) work = kzalloc(sizeof(*work), GFP_KERNEL); if (work == NULL) { DRM_ERROR("Failed to allocate FBC work structure\n"); - dev_priv->display.enable_fbc(crtc); + dev_priv->fbc.enable_fbc(crtc); return; } @@ -427,7 +427,7 @@ static void __intel_fbc_disable(struct drm_device *dev) intel_fbc_cancel_work(dev_priv); - dev_priv->display.disable_fbc(dev); + dev_priv->fbc.disable_fbc(dev); dev_priv->fbc.crtc = NULL; } @@ -441,7 +441,7 @@ void intel_fbc_disable(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -460,7 +460,7 @@ void intel_fbc_disable_crtc(struct intel_crtc *crtc) struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -661,7 +661,7 @@ void intel_fbc_cleanup_cfb(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -857,7 +857,7 @@ void intel_fbc_update(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -872,7 +872,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, struct drm_device *dev = dev_priv->dev; unsigned int fbc_bits; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; if (origin == ORIGIN_GTT) @@ -901,7 +901,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, { struct drm_device *dev = dev_priv->dev; - if (!dev_priv->display.enable_fbc) + if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); @@ -945,25 +945,25 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) } if (INTEL_INFO(dev_priv)->gen >= 7) { - dev_priv->display.fbc_enabled = ilk_fbc_enabled; - dev_priv->display.enable_fbc = gen7_fbc_enable; - dev_priv->display.disable_fbc = ilk_fbc_disable; + dev_priv->fbc.fbc_enabled = ilk_fbc_enabled; + dev_priv->fbc.enable_fbc = gen7_fbc_enable; + dev_priv->fbc.disable_fbc = ilk_fbc_disable; } else if (INTEL_INFO(dev_priv)->gen >= 5) { - dev_priv->display.fbc_enabled = ilk_fbc_enabled; - dev_priv->display.enable_fbc = ilk_fbc_enable; - dev_priv->display.disable_fbc = ilk_fbc_disable; + dev_priv->fbc.fbc_enabled = ilk_fbc_enabled; + dev_priv->fbc.enable_fbc = ilk_fbc_enable; + dev_priv->fbc.disable_fbc = ilk_fbc_disable; } else if (IS_GM45(dev_priv)) { - dev_priv->display.fbc_enabled = g4x_fbc_enabled; - dev_priv->display.enable_fbc = g4x_fbc_enable; - dev_priv->display.disable_fbc = g4x_fbc_disable; + dev_priv->fbc.fbc_enabled = g4x_fbc_enabled; + dev_priv->fbc.enable_fbc = g4x_fbc_enable; + dev_priv->fbc.disable_fbc = g4x_fbc_disable; } else { - dev_priv->display.fbc_enabled = i8xx_fbc_enabled; - dev_priv->display.enable_fbc = i8xx_fbc_enable; - dev_priv->display.disable_fbc = i8xx_fbc_disable; + dev_priv->fbc.fbc_enabled = i8xx_fbc_enabled; + dev_priv->fbc.enable_fbc = i8xx_fbc_enable; + dev_priv->fbc.disable_fbc = i8xx_fbc_disable; /* This value was pulled out of someone's hat */ I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev); + dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv->dev); } -- GitLab From 7733b49bb03ee10b8889f8f5edf11d755115b230 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:04 -0300 Subject: [PATCH 0576/7006] drm/i915: use dev_priv for the FBC functions Because the cool kids use dev_priv and FBC wants to be cool too. We've been historically using struct drm_device on the FBC function arguments, but we only really need it for intel_vgpu_active(): we can use dev_priv everywhere else. So let's fully switch to dev_priv since I'm getting tired of adding "struct drm_device *dev = dev_priv->dev" everywhere. If I get a NACK here I'll propose the opposite: convert all the functions that currently take dev_priv to take dev. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_dma.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/i915_suspend.c | 2 +- drivers/gpu/drm/i915/intel_display.c | 14 +-- drivers/gpu/drm/i915/intel_drv.h | 8 +- drivers/gpu/drm/i915/intel_fbc.c | 154 +++++++++++---------------- drivers/gpu/drm/i915/intel_pm.c | 4 +- 8 files changed, 80 insertions(+), 110 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 5b89130eb366b..73aaea22bbef1 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1635,7 +1635,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused) intel_runtime_pm_get(dev_priv); mutex_lock(&dev_priv->fbc.lock); - if (intel_fbc_enabled(dev)) + if (intel_fbc_enabled(dev_priv)) seq_puts(m, "FBC enabled\n"); else seq_printf(m, "FBC disabled: %s\n", diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 066c34c3298a1..5e63076cc7690 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1123,7 +1123,7 @@ int i915_driver_unload(struct drm_device *dev) i915_gem_cleanup_ringbuffer(dev); i915_gem_context_fini(dev); mutex_unlock(&dev->struct_mutex); - intel_fbc_cleanup_cfb(dev); + intel_fbc_cleanup_cfb(dev_priv); i915_gem_cleanup_stolen(dev); intel_csr_ucode_fini(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 79d7ecec1bbf0..7f75ff36245b4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -937,9 +937,9 @@ struct i915_fbc { FBC_ROTATION, /* rotation is not supported */ } no_fbc_reason; - bool (*fbc_enabled)(struct drm_device *dev); + bool (*fbc_enabled)(struct drm_i915_private *dev_priv); void (*enable_fbc)(struct drm_crtc *crtc); - void (*disable_fbc)(struct drm_device *dev); + void (*disable_fbc)(struct drm_i915_private *dev_priv); }; /** diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c index cf67f82f7b7fc..1ccac618468ef 100644 --- a/drivers/gpu/drm/i915/i915_suspend.c +++ b/drivers/gpu/drm/i915/i915_suspend.c @@ -92,7 +92,7 @@ static void i915_restore_display(struct drm_device *dev) } /* only restore FBC info on the platform that supports FBC*/ - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); /* restore FBC interval */ if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev)) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index aefcf028fd920..4bcbff9793d43 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -3135,7 +3135,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_i915_private *dev_priv = dev->dev_private; if (dev_priv->fbc.disable_fbc) - dev_priv->fbc.disable_fbc(dev); + dev_priv->fbc.disable_fbc(dev_priv); dev_priv->display.update_primary_plane(crtc, fb, x, y); @@ -4734,6 +4734,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) { struct intel_crtc_atomic_commit *atomic = &crtc->atomic; struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_plane *plane; if (atomic->wait_vblank) @@ -4748,7 +4749,7 @@ static void intel_post_plane_update(struct intel_crtc *crtc) intel_update_watermarks(&crtc->base); if (atomic->update_fbc) - intel_fbc_update(dev); + intel_fbc_update(dev_priv); if (atomic->post_enable_primary) intel_post_enable_primary(&crtc->base); @@ -10688,13 +10689,14 @@ static void intel_unpin_work_fn(struct work_struct *__work) container_of(__work, struct intel_unpin_work, work); struct intel_crtc *crtc = to_intel_crtc(work->crtc); struct drm_device *dev = crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; struct drm_plane *primary = crtc->base.primary; mutex_lock(&dev->struct_mutex); intel_unpin_fb_obj(work->old_fb, primary->state); drm_gem_object_unreference(&work->pending_flip_obj->base); - intel_fbc_update(dev); + intel_fbc_update(dev_priv); if (work->flip_queued_req) i915_gem_request_assign(&work->flip_queued_req, NULL); @@ -11469,7 +11471,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, to_intel_plane(primary)->frontbuffer_bit); mutex_unlock(&dev->struct_mutex); - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); intel_frontbuffer_flip_prepare(dev, to_intel_plane(primary)->frontbuffer_bit); @@ -15045,7 +15047,7 @@ void intel_modeset_init(struct drm_device *dev) intel_setup_outputs(dev); /* Just in case the BIOS is doing something questionable. */ - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); drm_modeset_lock_all(dev); intel_modeset_setup_hw_state(dev, false); @@ -15599,7 +15601,7 @@ void intel_modeset_cleanup(struct drm_device *dev) intel_unregister_dsm_handler(); - intel_fbc_disable(dev); + intel_fbc_disable(dev_priv); /* flush any delayed tasks or pending work */ flush_scheduled_work(); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 63d7d32e61230..082d0e7dfb14b 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1248,10 +1248,10 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev) #endif /* intel_fbc.c */ -bool intel_fbc_enabled(struct drm_device *dev); -void intel_fbc_update(struct drm_device *dev); +bool intel_fbc_enabled(struct drm_i915_private *dev_priv); +void intel_fbc_update(struct drm_i915_private *dev_priv); void intel_fbc_init(struct drm_i915_private *dev_priv); -void intel_fbc_disable(struct drm_device *dev); +void intel_fbc_disable(struct drm_i915_private *dev_priv); void intel_fbc_disable_crtc(struct intel_crtc *crtc); void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, @@ -1259,7 +1259,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits); const char *intel_no_fbc_reason_str(enum no_fbc_reason reason); -void intel_fbc_cleanup_cfb(struct drm_device *dev); +void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv); /* intel_hdmi.c */ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 07ea5b311d27f..449dbe42569f9 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -41,9 +41,8 @@ #include "intel_drv.h" #include "i915_drv.h" -static void i8xx_fbc_disable(struct drm_device *dev) +static void i8xx_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 fbc_ctl; dev_priv->fbc.enabled = false; @@ -67,8 +66,7 @@ static void i8xx_fbc_disable(struct drm_device *dev) static void i8xx_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -84,7 +82,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) cfb_pitch = fb->pitches[0]; /* FBC_CTL wants 32B or 64B units */ - if (IS_GEN2(dev)) + if (IS_GEN2(dev_priv)) cfb_pitch = (cfb_pitch / 32) - 1; else cfb_pitch = (cfb_pitch / 64) - 1; @@ -93,7 +91,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++) I915_WRITE(FBC_TAG + (i * 4), 0); - if (IS_GEN4(dev)) { + if (IS_GEN4(dev_priv)) { u32 fbc_ctl2; /* Set it up... */ @@ -107,7 +105,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) fbc_ctl = I915_READ(FBC_CONTROL); fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT; fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC; - if (IS_I945GM(dev)) + if (IS_I945GM(dev_priv)) fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT; fbc_ctl |= obj->fence_reg; @@ -117,17 +115,14 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); } -static bool i8xx_fbc_enabled(struct drm_device *dev) +static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } static void g4x_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -150,9 +145,8 @@ static void g4x_fbc_enable(struct drm_crtc *crtc) DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } -static void g4x_fbc_disable(struct drm_device *dev) +static void g4x_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 dpfc_ctl; dev_priv->fbc.enabled = false; @@ -167,10 +161,8 @@ static void g4x_fbc_disable(struct drm_device *dev) } } -static bool g4x_fbc_enabled(struct drm_device *dev) +static bool g4x_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN; } @@ -182,8 +174,7 @@ static void intel_fbc_nuke(struct drm_i915_private *dev_priv) static void ilk_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -209,7 +200,7 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) break; } dpfc_ctl |= DPFC_CTL_FENCE_EN; - if (IS_GEN5(dev)) + if (IS_GEN5(dev_priv)) dpfc_ctl |= obj->fence_reg; I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); @@ -217,7 +208,7 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - if (IS_GEN6(dev)) { + if (IS_GEN6(dev_priv)) { I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); @@ -228,9 +219,8 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); } -static void ilk_fbc_disable(struct drm_device *dev) +static void ilk_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; u32 dpfc_ctl; dev_priv->fbc.enabled = false; @@ -245,17 +235,14 @@ static void ilk_fbc_disable(struct drm_device *dev) } } -static bool ilk_fbc_enabled(struct drm_device *dev) +static bool ilk_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } static void gen7_fbc_enable(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; struct drm_framebuffer *fb = crtc->primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -265,7 +252,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dev_priv->fbc.enabled = true; dpfc_ctl = 0; - if (IS_IVYBRIDGE(dev)) + if (IS_IVYBRIDGE(dev_priv)) dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) @@ -291,7 +278,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - if (IS_IVYBRIDGE(dev)) { + if (IS_IVYBRIDGE(dev_priv)) { /* WaFbcAsynchFlipDisableFbcQueue:ivb */ I915_WRITE(ILK_DISPLAY_CHICKEN1, I915_READ(ILK_DISPLAY_CHICKEN1) | @@ -314,16 +301,14 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) /** * intel_fbc_enabled - Is FBC enabled? - * @dev: the drm_device + * @dev_priv: i915 device instance * * This function is used to verify the current state of FBC. * FIXME: This should be tracked in the plane config eventually * instead of queried at runtime for most callers. */ -bool intel_fbc_enabled(struct drm_device *dev) +bool intel_fbc_enabled(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - return dev_priv->fbc.enabled; } @@ -332,8 +317,7 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct intel_fbc_work *work = container_of(to_delayed_work(__work), struct intel_fbc_work, work); - struct drm_device *dev = work->crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = work->crtc->dev->dev_private; mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { @@ -383,8 +367,7 @@ static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) static void intel_fbc_enable(struct drm_crtc *crtc) { struct intel_fbc_work *work; - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); @@ -419,33 +402,29 @@ static void intel_fbc_enable(struct drm_crtc *crtc) schedule_delayed_work(&work->work, msecs_to_jiffies(50)); } -static void __intel_fbc_disable(struct drm_device *dev) +static void __intel_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); intel_fbc_cancel_work(dev_priv); - dev_priv->fbc.disable_fbc(dev); + dev_priv->fbc.disable_fbc(dev_priv); dev_priv->fbc.crtc = NULL; } /** * intel_fbc_disable - disable FBC - * @dev: the drm_device + * @dev_priv: i915 device instance * * This function disables FBC. */ -void intel_fbc_disable(struct drm_device *dev) +void intel_fbc_disable(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -457,15 +436,14 @@ void intel_fbc_disable(struct drm_device *dev) */ void intel_fbc_disable_crtc(struct intel_crtc *crtc) { - struct drm_device *dev = crtc->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); if (dev_priv->fbc.crtc == crtc) - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -547,12 +525,11 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) return crtc; } -static int find_compression_threshold(struct drm_device *dev, +static int find_compression_threshold(struct drm_i915_private *dev_priv, struct drm_mm_node *node, int size, int fb_cpp) { - struct drm_i915_private *dev_priv = dev->dev_private; int compression_threshold = 1; int ret; @@ -575,7 +552,7 @@ again: return 0; ret = i915_gem_stolen_insert_node(dev_priv, node, size >>= 1, 4096); - if (ret && INTEL_INFO(dev)->gen <= 4) { + if (ret && INTEL_INFO(dev_priv)->gen <= 4) { return 0; } else if (ret) { compression_threshold <<= 1; @@ -585,13 +562,13 @@ again: } } -static int intel_fbc_alloc_cfb(struct drm_device *dev, int size, int fb_cpp) +static int intel_fbc_alloc_cfb(struct drm_i915_private *dev_priv, int size, + int fb_cpp) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_mm_node *uninitialized_var(compressed_llb); int ret; - ret = find_compression_threshold(dev, &dev_priv->fbc.compressed_fb, + ret = find_compression_threshold(dev_priv, &dev_priv->fbc.compressed_fb, size, fb_cpp); if (!ret) goto err_llb; @@ -604,7 +581,7 @@ static int intel_fbc_alloc_cfb(struct drm_device *dev, int size, int fb_cpp) if (INTEL_INFO(dev_priv)->gen >= 5) I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); - else if (IS_GM45(dev)) { + else if (IS_GM45(dev_priv)) { I915_WRITE(DPFC_CB_BASE, dev_priv->fbc.compressed_fb.start); } else { compressed_llb = kzalloc(sizeof(*compressed_llb), GFP_KERNEL); @@ -639,10 +616,8 @@ err_llb: return -ENOSPC; } -static void __intel_fbc_cleanup_cfb(struct drm_device *dev) +static void __intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (dev_priv->fbc.uncompressed_size == 0) return; @@ -657,34 +632,31 @@ static void __intel_fbc_cleanup_cfb(struct drm_device *dev) dev_priv->fbc.uncompressed_size = 0; } -void intel_fbc_cleanup_cfb(struct drm_device *dev) +void intel_fbc_cleanup_cfb(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); - __intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } -static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) +static int intel_fbc_setup_cfb(struct drm_i915_private *dev_priv, int size, + int fb_cpp) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (size <= dev_priv->fbc.uncompressed_size) return 0; /* Release any current block */ - __intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev_priv); - return intel_fbc_alloc_cfb(dev, size, fb_cpp); + return intel_fbc_alloc_cfb(dev_priv, size, fb_cpp); } /** * __intel_fbc_update - enable/disable FBC as needed, unlocked - * @dev: the drm_device + * @dev_priv: i915 device instance * * Set up the framebuffer compression hardware at mode set time. We * enable it if possible: @@ -701,9 +673,8 @@ static int intel_fbc_setup_cfb(struct drm_device *dev, int size, int fb_cpp) * * We need to enable/disable FBC on a global basis. */ -static void __intel_fbc_update(struct drm_device *dev) +static void __intel_fbc_update(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc = NULL; struct intel_crtc *intel_crtc; struct drm_framebuffer *fb; @@ -714,7 +685,7 @@ static void __intel_fbc_update(struct drm_device *dev) WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); /* disable framebuffer compression in vGPU */ - if (intel_vgpu_active(dev)) + if (intel_vgpu_active(dev_priv->dev)) i915.enable_fbc = 0; if (i915.enable_fbc < 0) { @@ -751,10 +722,10 @@ static void __intel_fbc_update(struct drm_device *dev) goto out_disable; } - if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) { + if (INTEL_INFO(dev_priv)->gen >= 8 || IS_HASWELL(dev_priv)) { max_width = 4096; max_height = 4096; - } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) { + } else if (IS_G4X(dev_priv) || INTEL_INFO(dev_priv)->gen >= 5) { max_width = 4096; max_height = 2048; } else { @@ -766,7 +737,7 @@ static void __intel_fbc_update(struct drm_device *dev) set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE); goto out_disable; } - if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) && + if ((INTEL_INFO(dev_priv)->gen < 4 || HAS_DDI(dev_priv)) && intel_crtc->plane != PLANE_A) { set_no_fbc_reason(dev_priv, FBC_BAD_PLANE); goto out_disable; @@ -780,7 +751,7 @@ static void __intel_fbc_update(struct drm_device *dev) set_no_fbc_reason(dev_priv, FBC_NOT_TILED); goto out_disable; } - if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) && + if (INTEL_INFO(dev_priv)->gen <= 4 && !IS_G4X(dev_priv) && crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) { set_no_fbc_reason(dev_priv, FBC_ROTATION); goto out_disable; @@ -790,7 +761,7 @@ static void __intel_fbc_update(struct drm_device *dev) if (in_dbg_master()) goto out_disable; - if (intel_fbc_setup_cfb(dev, obj->base.size, + if (intel_fbc_setup_cfb(dev_priv, obj->base.size, drm_format_plane_cpp(fb->pixel_format, 0))) { set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL); goto out_disable; @@ -806,7 +777,7 @@ static void __intel_fbc_update(struct drm_device *dev) dev_priv->fbc.y == crtc->y) return; - if (intel_fbc_enabled(dev)) { + if (intel_fbc_enabled(dev_priv)) { /* We update FBC along two paths, after changing fb/crtc * configuration (modeswitching) and after page-flipping * finishes. For the latter, we know that not only did @@ -831,7 +802,7 @@ static void __intel_fbc_update(struct drm_device *dev) * some point. And we wait before enabling FBC anyway. */ DRM_DEBUG_KMS("disabling active FBC for update\n"); - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); } intel_fbc_enable(crtc); @@ -840,28 +811,26 @@ static void __intel_fbc_update(struct drm_device *dev) out_disable: /* Multiple disables should be harmless */ - if (intel_fbc_enabled(dev)) { + if (intel_fbc_enabled(dev_priv)) { DRM_DEBUG_KMS("unsupported config, disabling FBC\n"); - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); } - __intel_fbc_cleanup_cfb(dev); + __intel_fbc_cleanup_cfb(dev_priv); } /* * intel_fbc_update - enable/disable FBC as needed - * @dev: the drm_device + * @dev_priv: i915 device instance * * This function reevaluates the overall state and enables or disables FBC. */ -void intel_fbc_update(struct drm_device *dev) +void intel_fbc_update(struct drm_i915_private *dev_priv) { - struct drm_i915_private *dev_priv = dev->dev_private; - if (!dev_priv->fbc.enable_fbc) return; mutex_lock(&dev_priv->fbc.lock); - __intel_fbc_update(dev); + __intel_fbc_update(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -869,7 +838,6 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits, enum fb_op_origin origin) { - struct drm_device *dev = dev_priv->dev; unsigned int fbc_bits; if (!dev_priv->fbc.enable_fbc) @@ -891,7 +859,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, dev_priv->fbc.busy_bits |= (fbc_bits & frontbuffer_bits); if (dev_priv->fbc.busy_bits) - __intel_fbc_disable(dev); + __intel_fbc_disable(dev_priv); mutex_unlock(&dev_priv->fbc.lock); } @@ -899,8 +867,6 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, void intel_fbc_flush(struct drm_i915_private *dev_priv, unsigned int frontbuffer_bits) { - struct drm_device *dev = dev_priv->dev; - if (!dev_priv->fbc.enable_fbc) return; @@ -912,7 +878,7 @@ void intel_fbc_flush(struct drm_i915_private *dev_priv, dev_priv->fbc.busy_bits &= ~frontbuffer_bits; if (!dev_priv->fbc.busy_bits) - __intel_fbc_update(dev); + __intel_fbc_update(dev_priv); out: mutex_unlock(&dev_priv->fbc.lock); @@ -965,5 +931,5 @@ void intel_fbc_init(struct drm_i915_private *dev_priv) I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT); } - dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv->dev); + dev_priv->fbc.enabled = dev_priv->fbc.fbc_enabled(dev_priv); } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 1efac89cb7383..4e24d2b13e4c5 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2479,6 +2479,7 @@ static void ilk_wm_merge(struct drm_device *dev, const struct ilk_wm_maximums *max, struct intel_pipe_wm *merged) { + struct drm_i915_private *dev_priv = dev->dev_private; int level, max_level = ilk_wm_max_level(dev); int last_enabled_level = max_level; @@ -2519,7 +2520,8 @@ static void ilk_wm_merge(struct drm_device *dev, * What we should check here is whether FBC can be * enabled sometime later. */ - if (IS_GEN5(dev) && !merged->fbc_wm_enabled && intel_fbc_enabled(dev)) { + if (IS_GEN5(dev) && !merged->fbc_wm_enabled && + intel_fbc_enabled(dev_priv)) { for (level = 2; level <= max_level; level++) { struct intel_wm_level *wm = &merged->wm[level]; -- GitLab From 220285f2281515f4e8a9ec7892f7de40d857c290 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:05 -0300 Subject: [PATCH 0577/7006] drm/i915: use intel_crtc for the FBC functions This is all internal i915.ko work, let's start using intel_crtc for everything. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 +- drivers/gpu/drm/i915/intel_fbc.c | 79 +++++++++++++++----------------- 2 files changed, 40 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 7f75ff36245b4..4ef1764aa8a55 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -918,7 +918,7 @@ struct i915_fbc { struct intel_fbc_work { struct delayed_work work; - struct drm_crtc *crtc; + struct intel_crtc *crtc; struct drm_framebuffer *fb; } *fbc_work; @@ -938,7 +938,7 @@ struct i915_fbc { } no_fbc_reason; bool (*fbc_enabled)(struct drm_i915_private *dev_priv); - void (*enable_fbc)(struct drm_crtc *crtc); + void (*enable_fbc)(struct intel_crtc *crtc); void (*disable_fbc)(struct drm_i915_private *dev_priv); }; diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 449dbe42569f9..9ef5b6ca5db70 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -64,12 +64,11 @@ static void i8xx_fbc_disable(struct drm_i915_private *dev_priv) DRM_DEBUG_KMS("disabled FBC\n"); } -static void i8xx_fbc_enable(struct drm_crtc *crtc) +static void i8xx_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); int cfb_pitch; int i; u32 fbc_ctl; @@ -96,9 +95,9 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) /* Set it up... */ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE; - fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane); + fbc_ctl2 |= FBC_CTL_PLANE(crtc->plane); I915_WRITE(FBC_CONTROL2, fbc_ctl2); - I915_WRITE(FBC_FENCE_OFF, crtc->y); + I915_WRITE(FBC_FENCE_OFF, crtc->base.y); } /* enable it... */ @@ -112,7 +111,7 @@ static void i8xx_fbc_enable(struct drm_crtc *crtc) I915_WRITE(FBC_CONTROL, fbc_ctl); DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n", - cfb_pitch, crtc->y, plane_name(intel_crtc->plane)); + cfb_pitch, crtc->base.y, plane_name(crtc->plane)); } static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv) @@ -120,29 +119,28 @@ static bool i8xx_fbc_enabled(struct drm_i915_private *dev_priv) return I915_READ(FBC_CONTROL) & FBC_CTL_EN; } -static void g4x_fbc_enable(struct drm_crtc *crtc) +static void g4x_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; dev_priv->fbc.enabled = true; - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN; + dpfc_ctl = DPFC_CTL_PLANE(crtc->plane) | DPFC_SR_EN; if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) dpfc_ctl |= DPFC_CTL_LIMIT_2X; else dpfc_ctl |= DPFC_CTL_LIMIT_1X; dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg; - I915_WRITE(DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(DPFC_FENCE_YOFF, crtc->base.y); /* enable it... */ I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } static void g4x_fbc_disable(struct drm_i915_private *dev_priv) @@ -172,18 +170,17 @@ static void intel_fbc_nuke(struct drm_i915_private *dev_priv) POSTING_READ(MSG_FBC_REND_STATE); } -static void ilk_fbc_enable(struct drm_crtc *crtc) +static void ilk_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; dev_priv->fbc.enabled = true; - dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl = DPFC_CTL_PLANE(crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) threshold++; @@ -203,7 +200,7 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) if (IS_GEN5(dev_priv)) dpfc_ctl |= obj->fence_reg; - I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y); + I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->base.y); I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID); /* enable it... */ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN); @@ -211,12 +208,12 @@ static void ilk_fbc_enable(struct drm_crtc *crtc) if (IS_GEN6(dev_priv)) { I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->base.y); } intel_fbc_nuke(dev_priv); - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } static void ilk_fbc_disable(struct drm_i915_private *dev_priv) @@ -240,12 +237,11 @@ static bool ilk_fbc_enabled(struct drm_i915_private *dev_priv) return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN; } -static void gen7_fbc_enable(struct drm_crtc *crtc) +static void gen7_fbc_enable(struct intel_crtc *crtc) { - struct drm_i915_private *dev_priv = crtc->dev->dev_private; - struct drm_framebuffer *fb = crtc->primary->fb; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; + struct drm_framebuffer *fb = crtc->base.primary->fb; struct drm_i915_gem_object *obj = intel_fb_obj(fb); - struct intel_crtc *intel_crtc = to_intel_crtc(crtc); u32 dpfc_ctl; int threshold = dev_priv->fbc.threshold; @@ -253,7 +249,7 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) dpfc_ctl = 0; if (IS_IVYBRIDGE(dev_priv)) - dpfc_ctl |= IVB_DPFC_CTL_PLANE(intel_crtc->plane); + dpfc_ctl |= IVB_DPFC_CTL_PLANE(crtc->plane); if (drm_format_plane_cpp(fb->pixel_format, 0) == 2) threshold++; @@ -285,18 +281,18 @@ static void gen7_fbc_enable(struct drm_crtc *crtc) ILK_FBCQ_DIS); } else { /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */ - I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe), - I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) | + I915_WRITE(CHICKEN_PIPESL_1(crtc->pipe), + I915_READ(CHICKEN_PIPESL_1(crtc->pipe)) | HSW_FBCQ_DIS); } I915_WRITE(SNB_DPFC_CTL_SA, SNB_CPU_FENCE_ENABLE | obj->fence_reg); - I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y); + I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->base.y); intel_fbc_nuke(dev_priv); - DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane)); + DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(crtc->plane)); } /** @@ -317,19 +313,20 @@ static void intel_fbc_work_fn(struct work_struct *__work) struct intel_fbc_work *work = container_of(to_delayed_work(__work), struct intel_fbc_work, work); - struct drm_i915_private *dev_priv = work->crtc->dev->dev_private; + struct drm_i915_private *dev_priv = work->crtc->base.dev->dev_private; + struct drm_framebuffer *crtc_fb = work->crtc->base.primary->fb; mutex_lock(&dev_priv->fbc.lock); if (work == dev_priv->fbc.fbc_work) { /* Double check that we haven't switched fb without cancelling * the prior work. */ - if (work->crtc->primary->fb == work->fb) { + if (crtc_fb == work->fb) { dev_priv->fbc.enable_fbc(work->crtc); - dev_priv->fbc.crtc = to_intel_crtc(work->crtc); - dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id; - dev_priv->fbc.y = work->crtc->y; + dev_priv->fbc.crtc = work->crtc; + dev_priv->fbc.fb_id = crtc_fb->base.id; + dev_priv->fbc.y = work->crtc->base.y; } dev_priv->fbc.fbc_work = NULL; @@ -364,10 +361,10 @@ static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv) dev_priv->fbc.fbc_work = NULL; } -static void intel_fbc_enable(struct drm_crtc *crtc) +static void intel_fbc_enable(struct intel_crtc *crtc) { struct intel_fbc_work *work; - struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct drm_i915_private *dev_priv = crtc->base.dev->dev_private; WARN_ON(!mutex_is_locked(&dev_priv->fbc.lock)); @@ -381,7 +378,7 @@ static void intel_fbc_enable(struct drm_crtc *crtc) } work->crtc = crtc; - work->fb = crtc->primary->fb; + work->fb = crtc->base.primary->fb; INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn); dev_priv->fbc.fbc_work = work; @@ -805,7 +802,7 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) __intel_fbc_disable(dev_priv); } - intel_fbc_enable(crtc); + intel_fbc_enable(intel_crtc); dev_priv->fbc.no_fbc_reason = FBC_OK; return; @@ -852,7 +849,7 @@ void intel_fbc_invalidate(struct drm_i915_private *dev_priv, fbc_bits = INTEL_FRONTBUFFER_PRIMARY(dev_priv->fbc.crtc->pipe); else if (dev_priv->fbc.fbc_work) fbc_bits = INTEL_FRONTBUFFER_PRIMARY( - to_intel_crtc(dev_priv->fbc.fbc_work->crtc)->pipe); + dev_priv->fbc.fbc_work->crtc->pipe); else fbc_bits = dev_priv->fbc.possible_framebuffer_bits; -- GitLab From 8935108528194918966757fa00ac986176fe9497 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:06 -0300 Subject: [PATCH 0578/7006] drm/i915: add FBC_IN_DBG_MASTER no_fbc_reason The poor in_dbg_master() check was the only one without a reason string. Give it a reason string so it won't feel excluded. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_fbc.c | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 4ef1764aa8a55..52d07fbd9cc8c 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -935,6 +935,7 @@ struct i915_fbc { FBC_MODULE_PARAM, FBC_CHIP_DEFAULT, /* disabled by default on this chip */ FBC_ROTATION, /* rotation is not supported */ + FBC_IN_DBG_MASTER, /* kernel debugger is active */ } no_fbc_reason; bool (*fbc_enabled)(struct drm_i915_private *dev_priv); diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 9ef5b6ca5db70..8d39893b75508 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -471,6 +471,8 @@ const char *intel_no_fbc_reason_str(enum no_fbc_reason reason) return "disabled per chip default"; case FBC_ROTATION: return "rotation unsupported"; + case FBC_IN_DBG_MASTER: + return "Kernel debugger is active"; default: MISSING_CASE(reason); return "unknown reason"; @@ -755,8 +757,10 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) } /* If the kernel debugger is active, always disable compression */ - if (in_dbg_master()) + if (in_dbg_master()) { + set_no_fbc_reason(dev_priv, FBC_IN_DBG_MASTER); goto out_disable; + } if (intel_fbc_setup_cfb(dev_priv, obj->base.size, drm_format_plane_cpp(fb->pixel_format, 0))) { -- GitLab From 232fd934a4b458e5a0dacdd17efc1faffb9df615 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:07 -0300 Subject: [PATCH 0579/7006] drm/i915: extract FBC_MULTIPLE_PIPES check I have two separate refactor ideas that require extracting this to a separate function. I'm not sure which idea I'll end choosing, but since both will require extracting this function, let's do this now. Notice that this is just code moving. Any possible problems with the current multiple pipes check should be fixed in later commits. Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 36 ++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 8d39893b75508..790edb3a2f39a 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -493,24 +493,17 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) { struct drm_crtc *crtc = NULL, *tmp_crtc; enum pipe pipe; - bool pipe_a_only = false, one_pipe_only = false; + bool pipe_a_only = false; if (IS_HASWELL(dev_priv) || INTEL_INFO(dev_priv)->gen >= 8) pipe_a_only = true; - else if (INTEL_INFO(dev_priv)->gen <= 4) - one_pipe_only = true; for_each_pipe(dev_priv, pipe) { tmp_crtc = dev_priv->pipe_to_crtc_mapping[pipe]; if (intel_crtc_active(tmp_crtc) && - to_intel_plane_state(tmp_crtc->primary->state)->visible) { - if (one_pipe_only && crtc) { - set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); - return NULL; - } + to_intel_plane_state(tmp_crtc->primary->state)->visible) crtc = tmp_crtc; - } if (pipe_a_only) break; @@ -524,6 +517,26 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) return crtc; } +static bool multiple_pipes_ok(struct drm_i915_private *dev_priv) +{ + enum pipe pipe; + int n_pipes = 0; + struct drm_crtc *crtc; + + if (INTEL_INFO(dev_priv)->gen > 4) + return true; + + for_each_pipe(dev_priv, pipe) { + crtc = dev_priv->pipe_to_crtc_mapping[pipe]; + + if (intel_crtc_active(crtc) && + to_intel_plane_state(crtc->primary->state)->visible) + n_pipes++; + } + + return (n_pipes < 2); +} + static int find_compression_threshold(struct drm_i915_private *dev_priv, struct drm_mm_node *node, int size, @@ -710,6 +723,11 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) if (!crtc) goto out_disable; + if (!multiple_pipes_ok(dev_priv)) { + set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); + goto out_disable; + } + intel_crtc = to_intel_crtc(crtc); fb = crtc->primary->fb; obj = intel_fb_obj(fb); -- GitLab From 8df5dd57fd2f4e7f02793457a3bd61e5d4a644d5 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 7 Jul 2015 15:26:08 -0300 Subject: [PATCH 0580/7006] drm/i915: move set_no_fbc_reason() call out of intel_fbc_find_crtc() So now all the calls are inside __intel_fbc_update(). Consistency! Signed-off-by: Paulo Zanoni Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c index 790edb3a2f39a..c271af7679815 100644 --- a/drivers/gpu/drm/i915/intel_fbc.c +++ b/drivers/gpu/drm/i915/intel_fbc.c @@ -509,10 +509,8 @@ static struct drm_crtc *intel_fbc_find_crtc(struct drm_i915_private *dev_priv) break; } - if (!crtc || crtc->primary->fb == NULL) { - set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); + if (!crtc || crtc->primary->fb == NULL) return NULL; - } return crtc; } @@ -720,8 +718,10 @@ static void __intel_fbc_update(struct drm_i915_private *dev_priv) * - going to an unsupported config (interlace, pixel multiply, etc.) */ crtc = intel_fbc_find_crtc(dev_priv); - if (!crtc) + if (!crtc) { + set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT); goto out_disable; + } if (!multiple_pipes_ok(dev_priv)) { set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES); -- GitLab From 72010aca55264cfe6516a955066c846d3885b0c6 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:22:20 +0000 Subject: [PATCH 0581/7006] pcmcia: sa11x0: fix missing clk_put() in sa11x0 socket drivers Fix the lack of clk_put() in sa11xx_base.c's error cleanup paths by converting the driver to the devm_* API. Fixes: 86d88bfca475 ("ARM: 8247/2: pcmcia: sa1100: make use of device clock") Signed-off-by: Russell King --- drivers/pcmcia/sa1100_generic.c | 1 - drivers/pcmcia/sa11xx_base.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 803945259da80..42861cc701580 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -93,7 +93,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) for (i = 0; i < sinfo->nskt; i++) soc_pcmcia_remove_one(&sinfo->skt[i]); - clk_put(sinfo->clk); kfree(sinfo); return 0; } diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index cf6de2c2b3293..553d70a67f808 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -222,7 +222,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, int i, ret = 0; struct clk *clk; - clk = clk_get(dev, NULL); + clk = devm_clk_get(dev, NULL); if (IS_ERR(clk)) return PTR_ERR(clk); @@ -251,7 +251,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, if (ret) { while (--i >= 0) soc_pcmcia_remove_one(&sinfo->skt[i]); - clk_put(clk); kfree(sinfo); } else { dev_set_drvdata(dev, sinfo); -- GitLab From e33e640ad0b76151534a2b9387b98eb02d6ddda7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:33:16 +0000 Subject: [PATCH 0582/7006] pcmcia: sa11x0: convert memory allocation to devm_* API Convert the sa11x0 socket driver memory allocation to use devm_kzalloc() to simplify the cleanup path. Signed-off-by: Russell King --- drivers/pcmcia/sa1100_generic.c | 1 - drivers/pcmcia/sa11xx_base.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c index 42861cc701580..66acdc85727cc 100644 --- a/drivers/pcmcia/sa1100_generic.c +++ b/drivers/pcmcia/sa1100_generic.c @@ -93,7 +93,6 @@ static int sa11x0_drv_pcmcia_remove(struct platform_device *dev) for (i = 0; i < sinfo->nskt; i++) soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); return 0; } diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 553d70a67f808..6e6336d47d4ac 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -228,7 +228,7 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, sa11xx_drv_pcmcia_ops(ops); - sinfo = kzalloc(SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); + sinfo = devm_kzalloc(dev, SKT_DEV_INFO_SIZE(nr), GFP_KERNEL); if (!sinfo) return -ENOMEM; @@ -251,7 +251,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, if (ret) { while (--i >= 0) soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); } else { dev_set_drvdata(dev, sinfo); } -- GitLab From af4739c281621017a8a84dd6ba3471bba2dd6c6a Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Tue, 7 Jul 2015 21:58:02 +0200 Subject: [PATCH 0583/7006] HID: i2c-hid: Call device suspend callback before disabling irq i2c-hid takes care of requesting and handling IRQs for HID devices which in turns might expect them to be always active when working in normal conditions. Hence, disabling IRQs before calling the suspend callbacks can potentially cause problems since device drivers might try to perform operations needing them. Fix this by disabling IRQs only after the suspend callbacks had been executed. Signed-off-by: Gabriele Mazzotta Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index f77469d4edfb0..9ed69b5121f71 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1092,13 +1092,13 @@ static int i2c_hid_suspend(struct device *dev) struct hid_device *hid = ihid->hid; int ret = 0; + if (hid->driver && hid->driver->suspend) + ret = hid->driver->suspend(hid, PMSG_SUSPEND); + disable_irq(ihid->irq); if (device_may_wakeup(&client->dev)) enable_irq_wake(ihid->irq); - if (hid->driver && hid->driver->suspend) - ret = hid->driver->suspend(hid, PMSG_SUSPEND); - /* Save some power */ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP); -- GitLab From aaf5ec2e51ab1d9c5e962b4728a1107ed3ff7a3e Mon Sep 17 00:00:00 2001 From: Sonika Jindal Date: Wed, 8 Jul 2015 17:07:47 +0530 Subject: [PATCH 0584/7006] drm/i915: Handle HPD when it has actually occurred MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing to PCH_PORT_HOTPLUG for each interrupt is not required. Handle it only if hpd has actually occurred like we handle other interrupts. v2: Make few variables local to if block (Ville) v3: Add check for ibx/cpt both (Ville). While at it, remove the redundant check for hotplug_trigger from pch_get_hpd_pins v4: Indentation (Ville) Reviewed-by: Ville Syrjälä Signed-off-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index a6fbe6443d63b..a897f68485c2a 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1266,9 +1266,6 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask = 0; *long_mask = 0; - if (!hotplug_trigger) - return; - for_each_hpd_pin(i) { if ((hpd[i] & hotplug_trigger) == 0) continue; @@ -1658,14 +1655,17 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK; - u32 dig_hotplug_reg; - u32 pin_mask, long_mask; - dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); - I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + if (hotplug_trigger) { + u32 dig_hotplug_reg, pin_mask, long_mask; - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_ibx); - intel_hpd_irq_handler(dev, pin_mask, long_mask); + dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); + I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_ibx); + intel_hpd_irq_handler(dev, pin_mask, long_mask); + } if (pch_iir & SDE_AUDIO_POWER_MASK) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK) >> @@ -1757,14 +1757,16 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) struct drm_i915_private *dev_priv = dev->dev_private; int pipe; u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; - u32 dig_hotplug_reg; - u32 pin_mask, long_mask; - dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); - I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + if (hotplug_trigger) { + u32 dig_hotplug_reg, pin_mask, long_mask; - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, dig_hotplug_reg, hpd_cpt); - intel_hpd_irq_handler(dev, pin_mask, long_mask); + dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); + I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); + pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_cpt); + intel_hpd_irq_handler(dev, pin_mask, long_mask); + } if (pch_iir & SDE_AUDIO_POWER_MASK_CPT) { int port = ffs((pch_iir & SDE_AUDIO_POWER_MASK_CPT) >> -- GitLab From 83b8a982b101c48fc025066a7b08beaf6fa756f0 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Wed, 8 Jul 2015 10:27:05 +0100 Subject: [PATCH 0585/7006] drm/i915: Update wa_ctx_emit() macro as per kernel coding guidelines wa_ctx_emit() depends on the name of a local variable; if the name of that variable is changed then we get compile errors. In this case it is unlikely to be changed as this macro is only used in this set of functions but Kernel coding guidelines doesn't recommend doing this. It was my mistake as I should have corrected it at the beginning but missed so correct this before there are more usages of this macro (Bob Beckett). https://www.kernel.org/doc/Documentation/CodingStyle, Chapter 12, "Things to avoid when using macros", point 2): " 2) macros that depend on having a local variable with a magic name: #define FOO(val) bar(index, val) might look like a good thing, but it's confusing as hell when one reads the code and it's prone to breakage from seemingly innocent changes. " v2: Optimization to avoid multiple evaluation of 'index' in the macro. Since we invoke it multiple times, compiler, if it can, should be able to coalesce them into a single condition and remove multiple WARN_ON checks (Chris). Suggested-by: Robert Beckett Cc: Robert Beckett Cc: Chris Wilson Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 79 ++++++++++++++++---------------- 1 file changed, 40 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 4c47a64a974ff..971d7b0ae0174 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1065,12 +1065,13 @@ static int intel_logical_ring_workarounds_emit(struct drm_i915_gem_request *req) return 0; } -#define wa_ctx_emit(batch, cmd) \ +#define wa_ctx_emit(batch, index, cmd) \ do { \ - if (WARN_ON(index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ + int __index = (index)++; \ + if (WARN_ON(__index >= (PAGE_SIZE / sizeof(uint32_t)))) { \ return -ENOSPC; \ } \ - batch[index++] = (cmd); \ + batch[__index] = (cmd); \ } while (0) @@ -1096,29 +1097,29 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, { uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); - wa_ctx_emit(batch, (MI_STORE_REGISTER_MEM_GEN8(1) | - MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); - wa_ctx_emit(batch, 0); - - wa_ctx_emit(batch, MI_LOAD_REGISTER_IMM(1)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, l3sqc4_flush); - - wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); - wa_ctx_emit(batch, (PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_DC_FLUSH_ENABLE)); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - - wa_ctx_emit(batch, (MI_LOAD_REGISTER_MEM_GEN8(1) | - MI_SRM_LRM_GLOBAL_GTT)); - wa_ctx_emit(batch, GEN8_L3SQCREG4); - wa_ctx_emit(batch, ring->scratch.gtt_offset + 256); - wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, index, 0); + + wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit(batch, index, l3sqc4_flush); + + wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, index, (PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_DC_FLUSH_ENABLE)); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + + wa_ctx_emit(batch, index, (MI_LOAD_REGISTER_MEM_GEN8(1) | + MI_SRM_LRM_GLOBAL_GTT)); + wa_ctx_emit(batch, index, GEN8_L3SQCREG4); + wa_ctx_emit(batch, index, ring->scratch.gtt_offset + 256); + wa_ctx_emit(batch, index, 0); return index; } @@ -1179,7 +1180,7 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:bdw,chv */ - wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_DISABLE); + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* WaFlushCoherentL3CacheLinesAtContextSwitch:bdw */ if (IS_BROADWELL(ring->dev)) { @@ -1192,19 +1193,19 @@ static int gen8_init_indirectctx_bb(struct intel_engine_cs *ring, /* Actual scratch location is at 128 bytes offset */ scratch_addr = ring->scratch.gtt_offset + 2*CACHELINE_BYTES; - wa_ctx_emit(batch, GFX_OP_PIPE_CONTROL(6)); - wa_ctx_emit(batch, (PIPE_CONTROL_FLUSH_L3 | - PIPE_CONTROL_GLOBAL_GTT_IVB | - PIPE_CONTROL_CS_STALL | - PIPE_CONTROL_QW_WRITE)); - wa_ctx_emit(batch, scratch_addr); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); - wa_ctx_emit(batch, 0); + wa_ctx_emit(batch, index, GFX_OP_PIPE_CONTROL(6)); + wa_ctx_emit(batch, index, (PIPE_CONTROL_FLUSH_L3 | + PIPE_CONTROL_GLOBAL_GTT_IVB | + PIPE_CONTROL_CS_STALL | + PIPE_CONTROL_QW_WRITE)); + wa_ctx_emit(batch, index, scratch_addr); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); + wa_ctx_emit(batch, index, 0); /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) - wa_ctx_emit(batch, MI_NOOP); + wa_ctx_emit(batch, index, MI_NOOP); /* * MI_BATCH_BUFFER_END is not required in Indirect ctx BB because @@ -1240,9 +1241,9 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *ring, uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); /* WaDisableCtxRestoreArbitration:bdw,chv */ - wa_ctx_emit(batch, MI_ARB_ON_OFF | MI_ARB_ENABLE); + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); - wa_ctx_emit(batch, MI_BATCH_BUFFER_END); + wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); return wa_ctx_end(wa_ctx, *offset = index, 1); } -- GitLab From de152b627eb3018de91ec5c5a50b38e17d80a88b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 7 Jul 2015 16:28:51 -0700 Subject: [PATCH 0586/7006] drm/i915: Add origin to frontbuffer tracking flush This will be useful to PSR and FBC once we start making dirty fb calls to also flush frontbuffer. Cc: Daniel Vetter Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem.c | 12 ++++++------ drivers/gpu/drm/i915/intel_drv.h | 8 ++++---- drivers/gpu/drm/i915/intel_frontbuffer.c | 12 +++++++----- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 82c05b80b7ef0..aaabf3c259d50 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -375,7 +375,7 @@ i915_gem_phys_pwrite(struct drm_i915_gem_object *obj, i915_gem_chipset_flush(dev); out: - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_CPU); return ret; } @@ -839,7 +839,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev, } out_flush: - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_GTT); out_unpin: i915_gem_object_ggtt_unpin(obj); out: @@ -1032,7 +1032,7 @@ out: if (needs_clflush_after) i915_gem_chipset_flush(dev); - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_CPU); return ret; } @@ -2375,7 +2375,7 @@ i915_gem_object_retire__write(struct drm_i915_gem_object *obj) RQ_BUG_ON(!(obj->active & intel_ring_flag(obj->last_write_req->ring))); i915_gem_request_assign(&obj->last_write_req, NULL); - intel_fb_obj_flush(obj, true); + intel_fb_obj_flush(obj, true, ORIGIN_CS); } static void @@ -3905,7 +3905,7 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj) old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_GTT); trace_i915_gem_object_change_domain(obj, obj->base.read_domains, @@ -3927,7 +3927,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj) old_write_domain = obj->base.write_domain; obj->base.write_domain = 0; - intel_fb_obj_flush(obj, false); + intel_fb_obj_flush(obj, false, ORIGIN_CPU); trace_i915_gem_object_change_domain(obj, obj->base.read_domains, diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 082d0e7dfb14b..beeb4d326cbea 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -978,16 +978,16 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits); void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits, + enum fb_op_origin origin); void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits); - unsigned int intel_fb_align_height(struct drm_device *dev, unsigned int height, uint32_t pixel_format, uint64_t fb_format_modifier); -void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire); - +void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire, + enum fb_op_origin origin); u32 intel_fb_stride_alignment(struct drm_device *dev, uint64_t fb_modifier, uint32_t pixel_format); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index 6e90e2b0293d5..cb5a6f0447e7c 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -105,6 +105,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, * intel_frontbuffer_flush - flush frontbuffer * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits + * @origin: which operation caused the flush * * This function gets called every time rendering on the given planes has * completed and frontbuffer caching can be started again. Flushes will get @@ -113,7 +114,8 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, * Can be called without any locks held. */ void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits, + enum fb_op_origin origin) { struct drm_i915_private *dev_priv = to_i915(dev); @@ -140,7 +142,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, * then any delayed flushes will be unblocked. */ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, - bool retire) + bool retire, enum fb_op_origin origin) { struct drm_device *dev = obj->base.dev; struct drm_i915_private *dev_priv = to_i915(dev); @@ -162,7 +164,7 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, mutex_unlock(&dev_priv->fb_tracking.lock); } - intel_frontbuffer_flush(dev, frontbuffer_bits); + intel_frontbuffer_flush(dev, frontbuffer_bits, origin); } /** @@ -212,7 +214,7 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, dev_priv->fb_tracking.flip_bits &= ~frontbuffer_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_frontbuffer_flush(dev, frontbuffer_bits); + intel_frontbuffer_flush(dev, frontbuffer_bits, ORIGIN_FLIP); } /** @@ -237,5 +239,5 @@ void intel_frontbuffer_flip(struct drm_device *dev, dev_priv->fb_tracking.busy_bits &= ~frontbuffer_bits; mutex_unlock(&dev_priv->fb_tracking.lock); - intel_frontbuffer_flush(dev, frontbuffer_bits); + intel_frontbuffer_flush(dev, frontbuffer_bits, ORIGIN_FLIP); } -- GitLab From c4a99a4b4f6ef56e9c8182920680b84a7129ca80 Mon Sep 17 00:00:00 2001 From: "Fang, Yang A" Date: Tue, 7 Jul 2015 14:21:47 -0700 Subject: [PATCH 0587/7006] ASoC: ts3a227e: do not report jack status when there is i2c read err After suspend -> resume the ts3a227e_interrupt sometimes comes before i2c controller resume is called .regmap_read will return incorrect status and report a wrong jack status.This patch will disable irq on suspend and enable irq again on the resume to make sure interrupt is coming after TI resumes. Also We should return if there is read err,the interrupt will come again since it is level triggered and we are not yet clear the interrupt. In addtion,cht_bsw_max98090_ti machine driver registered additional notifier base on jack event which will program the audio codec.there will be codec timeout err if such event occurs prior to i2c controller is resumed. Signed-off-by: Fang, Yang A Signed-off-by: Mark Brown --- sound/soc/codecs/ts3a227e.c | 47 +++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index 12232d7db4c52..ffc6f3028cc54 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -23,11 +23,13 @@ #include "ts3a227e.h" struct ts3a227e { + struct device *dev; struct regmap *regmap; struct snd_soc_jack *jack; bool plugged; bool mic_present; unsigned int buttons_held; + int irq; }; /* Button values to be reported on the jack */ @@ -189,16 +191,28 @@ static irqreturn_t ts3a227e_interrupt(int irq, void *data) struct ts3a227e *ts3a227e = (struct ts3a227e *)data; struct regmap *regmap = ts3a227e->regmap; unsigned int int_reg, kp_int_reg, acc_reg, i; + struct device *dev = ts3a227e->dev; + int ret; /* Check for plug/unplug. */ - regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); + ret = regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg); + if (ret) { + dev_err(dev, "failed to clear interrupt ret=%d\n", ret); + return IRQ_NONE; + } + if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) { regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg); ts3a227e_new_jack_state(ts3a227e, acc_reg); } /* Report any key events. */ - regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); + ret = regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg); + if (ret) { + dev_err(dev, "failed to clear key interrupt ret=%d\n", ret); + return IRQ_NONE; + } + for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) { if (kp_int_reg & PRESS_MASK(i)) ts3a227e->buttons_held |= (1 << i); @@ -283,6 +297,8 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, return -ENOMEM; i2c_set_clientdata(i2c, ts3a227e); + ts3a227e->dev = dev; + ts3a227e->irq = i2c->irq; ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config); if (IS_ERR(ts3a227e->regmap)) @@ -320,6 +336,32 @@ static int ts3a227e_i2c_probe(struct i2c_client *i2c, return 0; } +#ifdef CONFIG_PM_SLEEP +static int ts3a227e_suspend(struct device *dev) +{ + struct ts3a227e *ts3a227e = dev_get_drvdata(dev); + + dev_dbg(ts3a227e->dev, "suspend disable irq\n"); + disable_irq(ts3a227e->irq); + + return 0; +} + +static int ts3a227e_resume(struct device *dev) +{ + struct ts3a227e *ts3a227e = dev_get_drvdata(dev); + + dev_dbg(ts3a227e->dev, "resume enable irq\n"); + enable_irq(ts3a227e->irq); + + return 0; +} +#endif + +static const struct dev_pm_ops ts3a227e_pm = { + SET_SYSTEM_SLEEP_PM_OPS(ts3a227e_suspend, ts3a227e_resume) +}; + static const struct i2c_device_id ts3a227e_i2c_ids[] = { { "ts3a227e", 0 }, { } @@ -336,6 +378,7 @@ static struct i2c_driver ts3a227e_driver = { .driver = { .name = "ts3a227e", .owner = THIS_MODULE, + .pm = &ts3a227e_pm, .of_match_table = of_match_ptr(ts3a227e_of_match), }, .probe = ts3a227e_i2c_probe, -- GitLab From 779ea47399bae5d9418451f5283a3b2e35869627 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:51 -0300 Subject: [PATCH 0588/7006] ASoC: wm8904: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/wm8904.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 265a4a58a2d1b..07dc40022d4f4 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -1837,7 +1837,9 @@ static int wm8904_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - clk_prepare_enable(wm8904->mclk); + ret = clk_prepare_enable(wm8904->mclk); + if (ret) + return ret; break; case SND_SOC_BIAS_PREPARE: -- GitLab From cef6daa919c6912c4da629c3cee9c789f90583b1 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:52 -0300 Subject: [PATCH 0589/7006] ASoC: wm8731: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/wm8731.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index f22935a36a0a9..628d50c40cc4d 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -496,8 +496,11 @@ static int wm8731_set_bias_level(struct snd_soc_codec *codec, switch (level) { case SND_SOC_BIAS_ON: - if (wm8731->mclk) - clk_prepare_enable(wm8731->mclk); + if (wm8731->mclk) { + ret = clk_prepare_enable(wm8731->mclk); + if (ret) + return ret; + } break; case SND_SOC_BIAS_PREPARE: break; -- GitLab From 402f2a4f808a5d284de724689751dcd018835579 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sat, 20 Jun 2015 15:55:53 -0300 Subject: [PATCH 0590/7006] ASoC: max98095: Check for clk_prepare_enable() error clk_prepare_enable() may fail, so we should better check its return value and propagate it in the case of error. Signed-off-by: Fabio Estevam Signed-off-by: Mark Brown --- sound/soc/codecs/max98095.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 9a46d3dcf7035..66afd2b781e9c 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -1653,10 +1653,13 @@ static int max98095_set_bias_level(struct snd_soc_codec *codec, if (IS_ERR(max98095->mclk)) break; - if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) + if (snd_soc_codec_get_bias_level(codec) == SND_SOC_BIAS_ON) { clk_disable_unprepare(max98095->mclk); - else - clk_prepare_enable(max98095->mclk); + } else { + ret = clk_prepare_enable(max98095->mclk); + if (ret) + return ret; + } break; case SND_SOC_BIAS_STANDBY: -- GitLab From 7dd6bd8926f3142a237316035e72676c0c5c026f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:27 +0530 Subject: [PATCH 0591/7006] ASoC: intel: kconfig - Move DW_DMAC_CORE dependency to machines Some HSW and BYT machines depend on the DW_DMAC_CORE so they should have have depends on this symbol rather than common IPC lib as SKL onwards IPC lib is used but we don't depend on DW_DMAC_CORE Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index f3060a4ca040b..6f9a54af9c643 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -29,7 +29,6 @@ config SND_SOC_INTEL_SST tristate "ASoC support for Intel(R) Smart Sound Technology" select SND_SOC_INTEL_SST_ACPI if ACPI depends on (X86 || COMPILE_TEST) - depends on DW_DMAC_CORE help This adds support for Intel(R) Smart Sound Technology (SST). Say Y if you have such a device @@ -48,6 +47,7 @@ config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \ I2C_DESIGNWARE_PLATFORM + depends on DW_DMAC_CORE select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -59,6 +59,7 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on DW_DMAC_CORE select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -68,6 +69,7 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on DW_DMAC_CORE select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -78,6 +80,7 @@ config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM + depends on DW_DMAC_CORE select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help -- GitLab From 13735d1cecec1b3825f6834c74e67f82ab8cfe68 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:28 +0530 Subject: [PATCH 0592/7006] ASoC: intel - kconfig: remove SND_SOC_INTEL_SST prompt The SND_SOC_INTEL_SST is for common IPC lib and this should ideally be not selectable symbol but selected by respective machine driver So remove the prompt and get respective machines select it Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 6f9a54af9c643..32262be80871f 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -26,13 +26,9 @@ config SND_SST_IPC_ACPI depends on ACPI config SND_SOC_INTEL_SST - tristate "ASoC support for Intel(R) Smart Sound Technology" + tristate select SND_SOC_INTEL_SST_ACPI if ACPI depends on (X86 || COMPILE_TEST) - help - This adds support for Intel(R) Smart Sound Technology (SST). - Say Y if you have such a device - If unsure select "N". config SND_SOC_INTEL_SST_ACPI tristate @@ -45,9 +41,9 @@ config SND_SOC_INTEL_BAYTRAIL config SND_SOC_INTEL_HASWELL_MACH tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \ - I2C_DESIGNWARE_PLATFORM + depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT5640 help @@ -58,8 +54,9 @@ config SND_SOC_INTEL_HASWELL_MACH config SND_SOC_INTEL_BYT_RT5640_MACH tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on X86_INTEL_LPSS && I2C depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_RT5640 help @@ -68,8 +65,9 @@ config SND_SOC_INTEL_BYT_RT5640_MACH config SND_SOC_INTEL_BYT_MAX98090_MACH tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C + depends on X86_INTEL_LPSS && I2C depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_BAYTRAIL select SND_SOC_MAX98090 help @@ -78,9 +76,10 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH config SND_SOC_INTEL_BROADWELL_MACH tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \ + depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ I2C_DESIGNWARE_PLATFORM depends on DW_DMAC_CORE + select SND_SOC_INTEL_SST select SND_SOC_INTEL_HASWELL select SND_SOC_RT286 help -- GitLab From 9569909f4dda3810be05223e4deb278b794f309b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:30 +0530 Subject: [PATCH 0593/7006] ASoC: intel - atom: statify sst_slot_enum_info Sparse complains that sst_slot_enum_info should be static, so make it static sound/soc/intel/atom/sst-atom-controls.c:135:5: warning: symbol 'sst_slot_enum_info' was not declared. Should it be static? Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-atom-controls.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-atom-controls.c b/sound/soc/intel/atom/sst-atom-controls.c index 31e9b9ecbb8a5..c95bc52dcd74b 100644 --- a/sound/soc/intel/atom/sst-atom-controls.c +++ b/sound/soc/intel/atom/sst-atom-controls.c @@ -132,7 +132,7 @@ static int sst_send_slot_map(struct sst_data *drv) sizeof(cmd.header) + cmd.header.length); } -int sst_slot_enum_info(struct snd_kcontrol *kcontrol, +static int sst_slot_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct sst_enum *e = (struct sst_enum *)kcontrol->private_value; -- GitLab From 47a7bfc2bc99625e376e59fb01abf779c2d8a7b0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 19 Jun 2015 23:55:31 +0530 Subject: [PATCH 0594/7006] ASoC: intel - atom: fix sst_platform_compr_ops declaration Sparse complains that sst_platform_compr_ops should be static, but the declaration of this symbol was not correct so declare the symbol as extern in header file sound/soc/intel/atom/sst-mfld-platform-compress.c:257:22: warning: symbol 'sst_platform_compr_ops' was not declared. Should it be static? Signed-off-by: Vinod Koul Acked-by: Liam Girdwood Signed-off-by: Mark Brown --- sound/soc/intel/atom/sst-mfld-platform-pcm.c | 1 - sound/soc/intel/atom/sst-mfld-platform.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/intel/atom/sst-mfld-platform-pcm.c b/sound/soc/intel/atom/sst-mfld-platform-pcm.c index 641ebe61dc08b..683e501161524 100644 --- a/sound/soc/intel/atom/sst-mfld-platform-pcm.c +++ b/sound/soc/intel/atom/sst-mfld-platform-pcm.c @@ -33,7 +33,6 @@ struct sst_device *sst; static DEFINE_MUTEX(sst_lock); -extern struct snd_compr_ops sst_platform_compr_ops; int sst_register_dsp(struct sst_device *dev) { diff --git a/sound/soc/intel/atom/sst-mfld-platform.h b/sound/soc/intel/atom/sst-mfld-platform.h index 2409b23eeacf4..cb32cc7e5ec1f 100644 --- a/sound/soc/intel/atom/sst-mfld-platform.h +++ b/sound/soc/intel/atom/sst-mfld-platform.h @@ -25,6 +25,7 @@ #include "sst-atom-controls.h" extern struct sst_device *sst; +extern struct snd_compr_ops sst_platform_compr_ops; #define SST_MONO 1 #define SST_STEREO 2 -- GitLab From a5afdc5bf53995385b621361c976b8a29e07f701 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 28 Jun 2015 11:40:22 +0800 Subject: [PATCH 0595/7006] ASoC: rt286: Constify dmi_system_id table dmi_check_system() takes "const struct dmi_system_id *", so make the dmi_system_id table const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt286.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 2f39843ebd14c..491ed16dd5d2f 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1108,7 +1108,7 @@ static const struct acpi_device_id rt286_acpi_match[] = { }; MODULE_DEVICE_TABLE(acpi, rt286_acpi_match); -static struct dmi_system_id force_combo_jack_table[] = { +static const struct dmi_system_id force_combo_jack_table[] = { { .ident = "Intel Wilson Beach", .matches = { @@ -1118,7 +1118,7 @@ static struct dmi_system_id force_combo_jack_table[] = { { } }; -static struct dmi_system_id dmi_dell_dino[] = { +static const struct dmi_system_id dmi_dell_dino[] = { { .ident = "Dell Dino", .matches = { -- GitLab From 030e6ee241f0586308622bcdd273a317976b3169 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jul 2015 21:26:44 +0800 Subject: [PATCH 0596/7006] ASoC: wm0010: Remove spurious missing IRQF_ONESHOT This reverts 58d468328646 ("ASoC: wm0010: Add missing IRQF_ONESHOT"). The coccinelle warnings is false positive because the original code does set IRQF_ONESHOT by "trigger |= IRQF_ONESHOT;". Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm0010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/wm0010.c b/sound/soc/codecs/wm0010.c index e1da49f393341..f2c6ad4b8fde0 100644 --- a/sound/soc/codecs/wm0010.c +++ b/sound/soc/codecs/wm0010.c @@ -953,7 +953,7 @@ static int wm0010_spi_probe(struct spi_device *spi) trigger = IRQF_TRIGGER_FALLING; trigger |= IRQF_ONESHOT; - ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger | IRQF_ONESHOT, + ret = request_threaded_irq(irq, NULL, wm0010_irq, trigger, "wm0010", wm0010); if (ret) { dev_err(wm0010->dev, "Failed to request IRQ %d: %d\n", -- GitLab From efc04ca22303dee1f34d038af3addc13621bed58 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jul 2015 21:27:48 +0800 Subject: [PATCH 0597/7006] ASoC: wm5100: Remove spurious IRQF_ONESHOT flag This reverts 3d907cc30d07 ("ASoC: wm5100: Pass the IRQF_ONESHOT flag"). The coccinelle warnings is false positive because the original code does set IRQF_ONESHOT by "trigger |= IRQF_ONESHOT;". Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5100.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd88c1af6..98495dd612399 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2570,13 +2570,11 @@ static int wm5100_i2c_probe(struct i2c_client *i2c, if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) ret = request_threaded_irq(i2c->irq, NULL, - wm5100_edge_irq, - irq_flags | IRQF_ONESHOT, + wm5100_edge_irq, irq_flags, "wm5100", wm5100); else ret = request_threaded_irq(i2c->irq, NULL, wm5100_irq, - irq_flags | IRQF_ONESHOT, - "wm5100", + irq_flags, "wm5100", wm5100); if (ret != 0) { -- GitLab From ca94085139d4874701af4f149bebfb05e105b245 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 2 Jul 2015 21:29:01 +0800 Subject: [PATCH 0598/7006] ASoC: wm8996: Remove spurious IRQF_ONESHOT flag This reverts ed043aebe6ec ("ASoC: wm8996: Pass the IRQF_ONESHOT flag"). The coccinelle warnings is false positive because the original code does set IRQF_ONESHOT by "trigger |= IRQF_ONESHOT;". Signed-off-by: Axel Lin Acked-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm8996.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f682b29..370459fcf21cb 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -2647,12 +2647,10 @@ static int wm8996_probe(struct snd_soc_codec *codec) if (irq_flags & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) ret = request_threaded_irq(i2c->irq, NULL, wm8996_edge_irq, - irq_flags | IRQF_ONESHOT, - "wm8996", codec); + irq_flags, "wm8996", codec); else ret = request_threaded_irq(i2c->irq, NULL, wm8996_irq, - irq_flags | IRQF_ONESHOT, - "wm8996", codec); + irq_flags, "wm8996", codec); if (ret == 0) { /* Unmask the interrupt */ -- GitLab From 3582f9ae07613302eb2967704ed2cef741db9a8d Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 3 Jul 2015 16:04:03 +0530 Subject: [PATCH 0599/7006] ASoC: Intel: Define SKL ADSP IPC and general purpose registers Signed-off-by: Subhransu S. Prusty Signed-off-by: Kp, Jeeja Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.h | 62 +++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-dsp.h diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h new file mode 100644 index 0000000000000..2ac120c18bead --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -0,0 +1,62 @@ +/* + * Skylake SST DSP Support + * + * Copyright (C) 2014-15, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __SKL_SST_DSP_H__ +#define __SKL_SST_DSP_H__ + +/* Intel HD Audio General DSP Registers */ +#define SKL_ADSP_GEN_BASE 0x0 +#define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04) +#define SKL_ADSP_REG_ADSPIC (SKL_ADSP_GEN_BASE + 0x08) +#define SKL_ADSP_REG_ADSPIS (SKL_ADSP_GEN_BASE + 0x0C) +#define SKL_ADSP_REG_ADSPIC2 (SKL_ADSP_GEN_BASE + 0x10) +#define SKL_ADSP_REG_ADSPIS2 (SKL_ADSP_GEN_BASE + 0x14) + +/* Intel HD Audio Inter-Processor Communication Registers */ +#define SKL_ADSP_IPC_BASE 0x40 +#define SKL_ADSP_REG_HIPCT (SKL_ADSP_IPC_BASE + 0x00) +#define SKL_ADSP_REG_HIPCTE (SKL_ADSP_IPC_BASE + 0x04) +#define SKL_ADSP_REG_HIPCI (SKL_ADSP_IPC_BASE + 0x08) +#define SKL_ADSP_REG_HIPCIE (SKL_ADSP_IPC_BASE + 0x0C) +#define SKL_ADSP_REG_HIPCCTL (SKL_ADSP_IPC_BASE + 0x10) + +/* HIPCI */ +#define SKL_ADSP_REG_HIPCI_BUSY BIT(31) + +/* HIPCIE */ +#define SKL_ADSP_REG_HIPCIE_DONE BIT(30) + +/* HIPCCTL */ +#define SKL_ADSP_REG_HIPCCTL_DONE BIT(1) +#define SKL_ADSP_REG_HIPCCTL_BUSY BIT(0) + +/* HIPCT */ +#define SKL_ADSP_REG_HIPCT_BUSY BIT(31) + +/* Intel HD Audio SRAM Window 1 */ +#define SKL_ADSP_SRAM1_BASE 0xA000 + +#define SKL_ADSP_MMIO_LEN 0x10000 + +#define SKL_ADSP_W0_STAT_SZ 0x800 + +#define SKL_ADSP_W0_UP_SZ 0x800 + +#define SKL_ADSP_W1_SZ 0x1000 + +#define SKL_ADSPIC_IPC 1 +#define SKL_ADSPIS_IPC 1 + +#endif /*__SKL_SST_DSP_H__*/ -- GitLab From f7c765e604a22dd898ac414d59b5a8edfe428b65 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 3 Jul 2015 16:04:04 +0530 Subject: [PATCH 0600/7006] ASoC: Intel: Reorganize the common dsp structure We will add SKL platform data. So organizing common and platform specific data helps. Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 396d54510350e..50af167b7bc78 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -258,6 +258,8 @@ struct sst_mem_block { */ struct sst_dsp { + /* Shared for all platforms */ + /* runtime */ struct sst_dsp_device *sst_dev; spinlock_t spinlock; /* IPC locking */ @@ -268,10 +270,6 @@ struct sst_dsp { int irq; u32 id; - /* list of free and used ADSP memory blocks */ - struct list_head used_block_list; - struct list_head free_block_list; - /* operations */ struct sst_ops *ops; @@ -284,6 +282,12 @@ struct sst_dsp { /* mailbox */ struct sst_mailbox mailbox; + /* HSW/Byt data */ + + /* list of free and used ADSP memory blocks */ + struct list_head used_block_list; + struct list_head free_block_list; + /* SST FW files loaded and their modules */ struct list_head module_list; struct list_head fw_list; -- GitLab From 1b7c12316982f74a5b8e7704c24cf5524d0723a3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 8 Jul 2015 20:47:43 +0200 Subject: [PATCH 0601/7006] ASoC: Prevent components from being bound to multiple cards A component can only be bound to a single card at a time. Binding it to card while it is already bound to another will result in undefined behavior. As the undefined behavior might only manifest itself later on it is not necessarily always straight forward to find the cause. To prevent this add a check that refuses to bind a component to multiple cards as well as prints a error describing the problem. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 6ce621749f8d0..96bb71aea529b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1102,9 +1102,19 @@ static int soc_probe_component(struct snd_soc_card *card, struct snd_soc_dai *dai; int ret; - if (!strcmp(component->name, "snd-soc-dummy") || component->probed) + if (!strcmp(component->name, "snd-soc-dummy")) return 0; + if (component->probed) { + if (component->card != card) { + dev_err(component->dev, + "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", + card->name, component->card->name); + return -ENODEV; + } + return 0; + } + component->card = card; dapm->card = card; soc_set_name_prefix(card, component); -- GitLab From abd31b32dde4683df6fd0439caa314aafd751698 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 8 Jul 2015 20:47:44 +0200 Subject: [PATCH 0602/7006] ASoC: Use card field to indicate whether a component is bound Use the card field of a component to indicate whether it is bound or not. This makes a certain sense given that the field contains the card the component is bound to and a component can only be bound to one card at a time. And it also requires to unset the card field when the component is unbound from the card. This makes the probded flag redundant and it can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc.h | 1 - sound/soc/soc-core.c | 16 ++++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf9d54a9..59635a12c3be7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -758,7 +758,6 @@ struct snd_soc_component { unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ unsigned int registered_as_component:1; - unsigned int probed:1; struct list_head list; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 96bb71aea529b..42575b03411eb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -978,7 +978,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) static void soc_remove_component(struct snd_soc_component *component) { - if (!component->probed) + if (!component->card) return; /* This is a HACK and will be removed soon */ @@ -991,7 +991,7 @@ static void soc_remove_component(struct snd_soc_component *component) snd_soc_dapm_free(snd_soc_component_get_dapm(component)); soc_cleanup_component_debugfs(component); - component->probed = 0; + component->card = NULL; module_put(component->dev->driver->owner); } @@ -1105,7 +1105,7 @@ static int soc_probe_component(struct snd_soc_card *card, if (!strcmp(component->name, "snd-soc-dummy")) return 0; - if (component->probed) { + if (component->card) { if (component->card != card) { dev_err(component->dev, "Trying to bind component to card \"%s\" but is already bound to card \"%s\"\n", @@ -1115,13 +1115,13 @@ static int soc_probe_component(struct snd_soc_card *card, return 0; } + if (!try_module_get(component->dev->driver->owner)) + return -ENODEV; + component->card = card; dapm->card = card; soc_set_name_prefix(card, component); - if (!try_module_get(component->dev->driver->owner)) - return -ENODEV; - soc_init_component_debugfs(component); if (component->dapm_widgets) { @@ -1165,7 +1165,6 @@ static int soc_probe_component(struct snd_soc_card *card, snd_soc_dapm_add_routes(dapm, component->dapm_routes, component->num_dapm_routes); - component->probed = 1; list_add(&dapm->list, &card->dapm_list); /* This is a HACK and will be removed soon */ @@ -1176,6 +1175,7 @@ static int soc_probe_component(struct snd_soc_card *card, err_probe: soc_cleanup_component_debugfs(component); + component->card = NULL; module_put(component->dev->driver->owner); return ret; @@ -1459,7 +1459,7 @@ static void soc_remove_aux_dev(struct snd_soc_card *card, int num) rtd->dev_registered = 0; } - if (component && component->probed) + if (component) soc_remove_component(component); } -- GitLab From f089d4d20fcbcf16a62ef3b4b57f41ecf59a5d83 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:12 +0100 Subject: [PATCH 0603/7006] mfd: wm5110: Add registers for custom write sequence triggers This register will be needed as part of some additional support for the headphone path on wm5110, so this patch adds the register and sets up its regmap config. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 2 ++ include/linux/mfd/arizona/registers.h | 37 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 12cad94b40354..62a4aa13cb98f 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -676,6 +676,7 @@ static const struct reg_default wm5110_reg_default[] = { { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ { 0x00000040, 0x0000 }, /* R64 - Wake control */ { 0x00000041, 0x0000 }, /* R65 - Sequence control */ + { 0x00000042, 0x0000 }, /* R66 - Spare Triggers */ { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ @@ -1716,6 +1717,7 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg) case ARIZONA_PWM_DRIVE_3: case ARIZONA_WAKE_CONTROL: case ARIZONA_SEQUENCE_CONTROL: + case ARIZONA_SPARE_TRIGGERS: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2: case ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3: diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h index 3499d36e60672..11affb3c2768a 100644 --- a/include/linux/mfd/arizona/registers.h +++ b/include/linux/mfd/arizona/registers.h @@ -39,6 +39,7 @@ #define ARIZONA_PWM_DRIVE_3 0x32 #define ARIZONA_WAKE_CONTROL 0x40 #define ARIZONA_SEQUENCE_CONTROL 0x41 +#define ARIZONA_SPARE_TRIGGERS 0x42 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_1 0x61 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_2 0x62 #define ARIZONA_SAMPLE_RATE_SEQUENCE_SELECT_3 0x63 @@ -1430,6 +1431,42 @@ #define ARIZONA_WSEQ_ENA_JD2_RISE_SHIFT 0 /* WSEQ_ENA_JD2_RISE */ #define ARIZONA_WSEQ_ENA_JD2_RISE_WIDTH 1 /* WSEQ_ENA_JD2_RISE */ +/* + * R66 (0x42) - Spare Triggers + */ +#define ARIZONA_WS_TRG8 0x0080 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_MASK 0x0080 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_SHIFT 7 /* WS_TRG8 */ +#define ARIZONA_WS_TRG8_WIDTH 1 /* WS_TRG8 */ +#define ARIZONA_WS_TRG7 0x0040 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_MASK 0x0040 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_SHIFT 6 /* WS_TRG7 */ +#define ARIZONA_WS_TRG7_WIDTH 1 /* WS_TRG7 */ +#define ARIZONA_WS_TRG6 0x0020 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_MASK 0x0020 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_SHIFT 5 /* WS_TRG6 */ +#define ARIZONA_WS_TRG6_WIDTH 1 /* WS_TRG6 */ +#define ARIZONA_WS_TRG5 0x0010 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_MASK 0x0010 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_SHIFT 4 /* WS_TRG5 */ +#define ARIZONA_WS_TRG5_WIDTH 1 /* WS_TRG5 */ +#define ARIZONA_WS_TRG4 0x0008 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_MASK 0x0008 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_SHIFT 3 /* WS_TRG4 */ +#define ARIZONA_WS_TRG4_WIDTH 1 /* WS_TRG4 */ +#define ARIZONA_WS_TRG3 0x0004 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_MASK 0x0004 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_SHIFT 2 /* WS_TRG3 */ +#define ARIZONA_WS_TRG3_WIDTH 1 /* WS_TRG3 */ +#define ARIZONA_WS_TRG2 0x0002 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_MASK 0x0002 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_SHIFT 1 /* WS_TRG2 */ +#define ARIZONA_WS_TRG2_WIDTH 1 /* WS_TRG2 */ +#define ARIZONA_WS_TRG1 0x0001 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_MASK 0x0001 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_SHIFT 0 /* WS_TRG1 */ +#define ARIZONA_WS_TRG1_WIDTH 1 /* WS_TRG1 */ + /* * R97 (0x61) - Sample Rate Sequence Select 1 */ -- GitLab From 81207880cef207cd89db863f9aa1d65f22b4f2a2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:13 +0100 Subject: [PATCH 0604/7006] mfd: wm5110: Add register patch for rev E and above Add a register patch for rev E and above that configures the location of some write sequences to assist with the headphone enables. Signed-off-by: Charles Keepax Acked-by: Lee Jones Signed-off-by: Mark Brown --- drivers/mfd/wm5110-tables.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 62a4aa13cb98f..e08924261fef3 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -249,6 +249,16 @@ static const struct reg_default wm5110_revd_patch[] = { { 0x80, 0x0 }, }; +/* Add extra headphone write sequence locations */ +static const struct reg_default wm5110_reve_patch[] = { + { 0x80, 0x3 }, + { 0x80, 0x3 }, + { 0x4b, 0x138 }, + { 0x4c, 0x13d }, + { 0x80, 0x0 }, + { 0x80, 0x0 }, +}; + /* We use a function so we can use ARRAY_SIZE() */ int wm5110_patch(struct arizona *arizona) { @@ -266,7 +276,9 @@ int wm5110_patch(struct arizona *arizona) wm5110_revd_patch, ARRAY_SIZE(wm5110_revd_patch)); default: - return 0; + return regmap_register_patch(arizona->regmap, + wm5110_reve_patch, + ARRAY_SIZE(wm5110_reve_patch)); } } EXPORT_SYMBOL_GPL(wm5110_patch); -- GitLab From d1acd31883d78f905a930493ff145ca4a25ad680 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 7 Jul 2015 15:28:14 +0100 Subject: [PATCH 0605/7006] ASoC: wm5110: Add special DRE on/off handling for the headphone path For the best performance the headphone path enable/disable must be handled specially for the situations of DRE on and DRE off. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 285 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 276 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 709fcc6169d81..b5c201b1e454b 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -131,6 +131,25 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = { { 0x33fb, 0xfe00 }, }; +static const struct reg_default wm5110_sysclk_reve_patch[] = { + { 0x3270, 0xE410 }, + { 0x3271, 0x3078 }, + { 0x3272, 0xE410 }, + { 0x3273, 0x3070 }, + { 0x3274, 0xE410 }, + { 0x3275, 0x3066 }, + { 0x3276, 0xE410 }, + { 0x3277, 0x3056 }, + { 0x327A, 0xE414 }, + { 0x327B, 0x3078 }, + { 0x327C, 0xE414 }, + { 0x327D, 0x3070 }, + { 0x327E, 0xE414 }, + { 0x327F, 0x3066 }, + { 0x3280, 0xE414 }, + { 0x3281, 0x3056 }, +}; + static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, int event) { @@ -146,7 +165,9 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, patch_size = ARRAY_SIZE(wm5110_sysclk_revd_patch); break; default: - return 0; + patch = wm5110_sysclk_reve_patch; + patch_size = ARRAY_SIZE(wm5110_sysclk_reve_patch); + break; } switch (event) { @@ -164,6 +185,249 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } +static const struct reg_default wm5110_no_dre_left_enable[] = { + { 0x3024, 0xE410 }, + { 0x3025, 0x0056 }, + { 0x301B, 0x0224 }, + { 0x301F, 0x4263 }, + { 0x3021, 0x5291 }, + { 0x3030, 0xE410 }, + { 0x3031, 0x3066 }, + { 0x3032, 0xE410 }, + { 0x3033, 0x3070 }, + { 0x3034, 0xE410 }, + { 0x3035, 0x3078 }, + { 0x3036, 0xE410 }, + { 0x3037, 0x3080 }, + { 0x3038, 0xE410 }, + { 0x3039, 0x3080 }, +}; + +static const struct reg_default wm5110_dre_left_enable[] = { + { 0x3024, 0x0231 }, + { 0x3025, 0x0B00 }, + { 0x301B, 0x0227 }, + { 0x301F, 0x4266 }, + { 0x3021, 0x5294 }, + { 0x3030, 0xE231 }, + { 0x3031, 0x0266 }, + { 0x3032, 0x8231 }, + { 0x3033, 0x4B15 }, + { 0x3034, 0x8231 }, + { 0x3035, 0x0B15 }, + { 0x3036, 0xE231 }, + { 0x3037, 0x5294 }, + { 0x3038, 0x0231 }, + { 0x3039, 0x0B00 }, +}; + +static const struct reg_default wm5110_no_dre_right_enable[] = { + { 0x3074, 0xE414 }, + { 0x3075, 0x0056 }, + { 0x306B, 0x0224 }, + { 0x306F, 0x4263 }, + { 0x3071, 0x5291 }, + { 0x3080, 0xE414 }, + { 0x3081, 0x3066 }, + { 0x3082, 0xE414 }, + { 0x3083, 0x3070 }, + { 0x3084, 0xE414 }, + { 0x3085, 0x3078 }, + { 0x3086, 0xE414 }, + { 0x3087, 0x3080 }, + { 0x3088, 0xE414 }, + { 0x3089, 0x3080 }, +}; + +static const struct reg_default wm5110_dre_right_enable[] = { + { 0x3074, 0x0231 }, + { 0x3075, 0x0B00 }, + { 0x306B, 0x0227 }, + { 0x306F, 0x4266 }, + { 0x3071, 0x5294 }, + { 0x3080, 0xE231 }, + { 0x3081, 0x0266 }, + { 0x3082, 0x8231 }, + { 0x3083, 0x4B17 }, + { 0x3084, 0x8231 }, + { 0x3085, 0x0B17 }, + { 0x3086, 0xE231 }, + { 0x3087, 0x5294 }, + { 0x3088, 0x0231 }, + { 0x3089, 0x0B00 }, +}; + +static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->arizona; + unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE); + const struct reg_default *wseq; + int nregs; + + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + if (val & ARIZONA_DRE1L_ENA_MASK) { + wseq = wm5110_dre_left_enable; + nregs = ARRAY_SIZE(wm5110_dre_left_enable); + } else { + wseq = wm5110_no_dre_left_enable; + nregs = ARRAY_SIZE(wm5110_no_dre_left_enable); + priv->out_up_delay += 10; + } + break; + case ARIZONA_OUT1R_ENA_SHIFT: + if (val & ARIZONA_DRE1R_ENA_MASK) { + wseq = wm5110_dre_right_enable; + nregs = ARRAY_SIZE(wm5110_dre_right_enable); + } else { + wseq = wm5110_no_dre_right_enable; + nregs = ARRAY_SIZE(wm5110_no_dre_right_enable); + priv->out_up_delay += 10; + } + break; + default: + return 0; + } + + return regmap_multi_reg_write(arizona->regmap, wseq, nregs); +} + +static int wm5110_hp_pre_disable(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE); + + switch (w->shift) { + case ARIZONA_OUT1L_ENA_SHIFT: + if (!(val & ARIZONA_DRE1L_ENA_MASK)) { + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG1, ARIZONA_WS_TRG1); + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG1, 0); + priv->out_down_delay += 27; + } + break; + case ARIZONA_OUT1R_ENA_SHIFT: + if (!(val & ARIZONA_DRE1R_ENA_MASK)) { + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG2, ARIZONA_WS_TRG2); + snd_soc_update_bits(codec, ARIZONA_SPARE_TRIGGERS, + ARIZONA_WS_TRG2, 0); + priv->out_down_delay += 27; + } + break; + default: + break; + } + + return 0; +} + +static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); + + switch (priv->arizona->rev) { + case 0 ... 3: + break; + default: + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wm5110_hp_pre_enable(w); + break; + case SND_SOC_DAPM_PRE_PMD: + wm5110_hp_pre_disable(w); + break; + default: + break; + } + break; + } + + return arizona_hp_ev(w, kcontrol, event); +} + +static int wm5110_clear_pga_volume(struct arizona *arizona, int output) +{ + struct reg_default clear_pga = { + ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 + }; + int ret; + + ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1); + if (ret) + dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n", + clear_pga.reg, ret); + + return ret; +} + +static int wm5110_put_dre(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct arizona *arizona = dev_get_drvdata(codec->dev->parent); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + unsigned int ena, dre; + unsigned int mask = (0x1 << mc->shift) | (0x1 << mc->rshift); + unsigned int lnew = (!!ucontrol->value.integer.value[0]) << mc->shift; + unsigned int rnew = (!!ucontrol->value.integer.value[1]) << mc->rshift; + unsigned int lold, rold; + unsigned int lena, rena; + int ret; + + snd_soc_dapm_mutex_lock(dapm); + + ret = regmap_read(arizona->regmap, ARIZONA_OUTPUT_ENABLES_1, &ena); + if (ret) { + dev_err(arizona->dev, "Failed to read output state: %d\n", ret); + goto err; + } + ret = regmap_read(arizona->regmap, ARIZONA_DRE_ENABLE, &dre); + if (ret) { + dev_err(arizona->dev, "Failed to read DRE state: %d\n", ret); + goto err; + } + + lold = dre & (1 << mc->shift); + rold = dre & (1 << mc->rshift); + /* Enables are channel wise swapped from the DRE enables */ + lena = ena & (1 << mc->rshift); + rena = ena & (1 << mc->shift); + + if ((lena && lnew != lold) || (rena && rnew != rold)) { + dev_err(arizona->dev, "Can't change DRE on active outputs\n"); + ret = -EBUSY; + goto err; + } + + ret = regmap_update_bits(arizona->regmap, ARIZONA_DRE_ENABLE, + mask, lnew | rnew); + if (ret) { + dev_err(arizona->dev, "Failed to set DRE: %d\n", ret); + goto err; + } + + /* Force reset of PGA volumes, if turning DRE off */ + if (!lnew && lold) + wm5110_clear_pga_volume(arizona, mc->shift); + + if (!rnew && rold) + wm5110_clear_pga_volume(arizona, mc->rshift); + +err: + snd_soc_dapm_mutex_unlock(dapm); + + return ret; +} + static DECLARE_TLV_DB_SCALE(ana_tlv, 0, 100, 0); static DECLARE_TLV_DB_SCALE(eq_tlv, -1200, 100, 0); static DECLARE_TLV_DB_SCALE(digital_tlv, -6400, 50, 0); @@ -409,12 +673,15 @@ SOC_DOUBLE("SPKDAT1 Switch", ARIZONA_PDM_SPK1_CTRL_1, ARIZONA_SPK1L_MUTE_SHIFT, SOC_DOUBLE("SPKDAT2 Switch", ARIZONA_PDM_SPK2_CTRL_1, ARIZONA_SPK2L_MUTE_SHIFT, ARIZONA_SPK2R_MUTE_SHIFT, 1, 1), -SOC_DOUBLE("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, - ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0), -SOC_DOUBLE("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE, - ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0), -SOC_DOUBLE("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE, - ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0), +SOC_DOUBLE_EXT("HPOUT1 DRE Switch", ARIZONA_DRE_ENABLE, + ARIZONA_DRE1L_ENA_SHIFT, ARIZONA_DRE1R_ENA_SHIFT, 1, 0, + snd_soc_get_volsw, wm5110_put_dre), +SOC_DOUBLE_EXT("HPOUT2 DRE Switch", ARIZONA_DRE_ENABLE, + ARIZONA_DRE2L_ENA_SHIFT, ARIZONA_DRE2R_ENA_SHIFT, 1, 0, + snd_soc_get_volsw, wm5110_put_dre), +SOC_DOUBLE_EXT("HPOUT3 DRE Switch", ARIZONA_DRE_ENABLE, + ARIZONA_DRE3L_ENA_SHIFT, ARIZONA_DRE3R_ENA_SHIFT, 1, 0, + snd_soc_get_volsw, wm5110_put_dre), SOC_ENUM("Output Ramp Up", arizona_out_vi_ramp), SOC_ENUM("Output Ramp Down", arizona_out_vd_ramp), @@ -904,11 +1171,11 @@ SND_SOC_DAPM_AIF_IN("AIF3RX2", NULL, 0, ARIZONA_AIF3_RX_ENABLES, ARIZONA_AIF3RX2_ENA_SHIFT, 0), SND_SOC_DAPM_PGA_E("OUT1L", SND_SOC_NOPM, - ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + ARIZONA_OUT1L_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT1R", SND_SOC_NOPM, - ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, arizona_hp_ev, + ARIZONA_OUT1R_ENA_SHIFT, 0, NULL, 0, wm5110_hp_ev, SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU), SND_SOC_DAPM_PGA_E("OUT2L", ARIZONA_OUTPUT_ENABLES_1, -- GitLab From 291a00d1a70f96b393da9ac90c58a82bc7949fc8 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 1 Jul 2015 14:11:14 -0700 Subject: [PATCH 0606/7006] tcp: reduce cwnd if retransmit is lost in CA_Loss If the retransmission in CA_Loss is lost again, we should not continue to slow start or raise cwnd in congestion avoidance mode. Instead we should enter fast recovery and use PRR to reduce cwnd, following the principle in RFC5681: "... or the loss of a retransmission, should be taken as two indications of congestion and, therefore, cwnd (and ssthresh) MUST be lowered twice in this case." This is especially important to reduce loss when the CA_Loss state was caused by a traffic policer dropping the entire inflight. The CA_Loss state has a problem where a loss of L packets causes the sender to send a burst of L packets. So a policer that's dropping most packets in a given RTT can cause a huge retransmit storm. By contrast, PRR includes logic to bound the number of outbound packets that result from a given ACK. So switching to CA_Recovery on lost retransmits in CA_Loss avoids this retransmit storm problem when in CA_Loss. Signed-off-by: Yuchung Cheng Signed-off-by: Nandita Dukkipati Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 684f095d196e2..923e0e568bfa6 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -109,6 +109,7 @@ int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; #define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ #define FLAG_DATA_SACKED 0x20 /* New SACK. */ #define FLAG_ECE 0x40 /* ECE in this ACK */ +#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ #define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ #define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ #define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ @@ -1037,7 +1038,7 @@ static bool tcp_is_sackblock_valid(struct tcp_sock *tp, bool is_dsack, * highest SACK block). Also calculate the lowest snd_nxt among the remaining * retransmitted skbs to avoid some costly processing per ACKs. */ -static void tcp_mark_lost_retrans(struct sock *sk) +static void tcp_mark_lost_retrans(struct sock *sk, int *flag) { const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); @@ -1078,7 +1079,7 @@ static void tcp_mark_lost_retrans(struct sock *sk) if (after(received_upto, ack_seq)) { TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; tp->retrans_out -= tcp_skb_pcount(skb); - + *flag |= FLAG_LOST_RETRANS; tcp_skb_mark_lost_uncond_verify(tp, skb); NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPLOSTRETRANSMIT); } else { @@ -1818,7 +1819,7 @@ advance_sp: ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker)) tcp_update_reordering(sk, tp->fackets_out - state->reord, 0); - tcp_mark_lost_retrans(sk); + tcp_mark_lost_retrans(sk, &state->flag); tcp_verify_left_out(tp); out: @@ -2676,7 +2677,7 @@ static void tcp_enter_recovery(struct sock *sk, bool ece_ack) tp->prior_ssthresh = 0; tcp_init_undo(tp); - if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { + if (!tcp_in_cwnd_reduction(sk)) { if (!ece_ack) tp->prior_ssthresh = tcp_current_ssthresh(sk); tcp_init_cwnd_reduction(sk); @@ -2852,9 +2853,10 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, break; case TCP_CA_Loss: tcp_process_loss(sk, flag, is_dupack); - if (icsk->icsk_ca_state != TCP_CA_Open) + if (icsk->icsk_ca_state != TCP_CA_Open && + !(flag & FLAG_LOST_RETRANS)) return; - /* Fall through to processing in Open state. */ + /* Change state if cwnd is undone or retransmits are lost */ default: if (tcp_is_reno(tp)) { if (flag & FLAG_SND_UNA_ADVANCED) -- GitLab From 3759824da87b30ce7a35b4873b62b0ba38905ef5 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Wed, 1 Jul 2015 14:11:15 -0700 Subject: [PATCH 0607/7006] tcp: PRR uses CRB mode by default and SS mode conditionally PRR slow start is often too aggressive especially when drops are caused by traffic policers. The policers mainly use token bucket to enforce the rate so sending (twice) faster than the delivery rate causes excessive drops. This patch changes PRR to the conservative reduction bound (CRB) mode in RFC 6937 by default. CRB follows the packet conservation rule to send at most the delivery rate by default. But if many packets are lost and the pipe is empty, CRB may take N round trips to repair N losses. We conditionally turn on slow start mode if all these conditions are made to speed up the recovery: 1) on the second round or later in recovery 2) retransmission sent in the previous round is delivered on this ACK 3) no retransmission is marked lost on this ACK By using packet conservation by default, this change reduces the loss retransmits signicantly on networks that deploy traffic policers, up to 20% reduction of overall loss rate. Signed-off-by: Yuchung Cheng Signed-off-by: Nandita Dukkipati Signed-off-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 923e0e568bfa6..ad1482dd215ef 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2476,15 +2476,14 @@ static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo) return false; } -/* The cwnd reduction in CWR and Recovery use the PRR algorithm - * https://datatracker.ietf.org/doc/draft-ietf-tcpm-proportional-rate-reduction/ +/* The cwnd reduction in CWR and Recovery uses the PRR algorithm in RFC 6937. * It computes the number of packets to send (sndcnt) based on packets newly * delivered: * 1) If the packets in flight is larger than ssthresh, PRR spreads the * cwnd reductions across a full RTT. - * 2) If packets in flight is lower than ssthresh (such as due to excess - * losses and/or application stalls), do not perform any further cwnd - * reductions, but instead slow start up to ssthresh. + * 2) Otherwise PRR uses packet conservation to send as much as delivered. + * But when the retransmits are acked without further losses, PRR + * slow starts cwnd up to ssthresh to speed up the recovery. */ static void tcp_init_cwnd_reduction(struct sock *sk) { @@ -2501,7 +2500,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk) } static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked, - int fast_rexmit) + int fast_rexmit, int flag) { struct tcp_sock *tp = tcp_sk(sk); int sndcnt = 0; @@ -2510,16 +2509,18 @@ static void tcp_cwnd_reduction(struct sock *sk, const int prior_unsacked, (tp->packets_out - tp->sacked_out); tp->prr_delivered += newly_acked_sacked; - if (tcp_packets_in_flight(tp) > tp->snd_ssthresh) { + if (delta < 0) { u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered + tp->prior_cwnd - 1; sndcnt = div_u64(dividend, tp->prior_cwnd) - tp->prr_out; - } else { + } else if ((flag & FLAG_RETRANS_DATA_ACKED) && + !(flag & FLAG_LOST_RETRANS)) { sndcnt = min_t(int, delta, max_t(int, tp->prr_delivered - tp->prr_out, newly_acked_sacked) + 1); + } else { + sndcnt = min(delta, newly_acked_sacked); } - sndcnt = max(sndcnt, (fast_rexmit ? 1 : 0)); tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt; } @@ -2580,7 +2581,7 @@ static void tcp_try_to_open(struct sock *sk, int flag, const int prior_unsacked) if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { tcp_try_keep_open(sk); } else { - tcp_cwnd_reduction(sk, prior_unsacked, 0); + tcp_cwnd_reduction(sk, prior_unsacked, 0, flag); } } @@ -2737,7 +2738,7 @@ static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack) /* Undo during fast recovery after partial ACK. */ static bool tcp_try_undo_partial(struct sock *sk, const int acked, - const int prior_unsacked) + const int prior_unsacked, int flag) { struct tcp_sock *tp = tcp_sk(sk); @@ -2753,7 +2754,7 @@ static bool tcp_try_undo_partial(struct sock *sk, const int acked, * mark more packets lost or retransmit more. */ if (tp->retrans_out) { - tcp_cwnd_reduction(sk, prior_unsacked, 0); + tcp_cwnd_reduction(sk, prior_unsacked, 0, flag); return true; } @@ -2840,7 +2841,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, if (tcp_is_reno(tp) && is_dupack) tcp_add_reno_sack(sk); } else { - if (tcp_try_undo_partial(sk, acked, prior_unsacked)) + if (tcp_try_undo_partial(sk, acked, prior_unsacked, flag)) return; /* Partial ACK arrived. Force fast retransmit. */ do_lost = tcp_is_reno(tp) || @@ -2891,7 +2892,7 @@ static void tcp_fastretrans_alert(struct sock *sk, const int acked, if (do_lost) tcp_update_scoreboard(sk, fast_rexmit); - tcp_cwnd_reduction(sk, prior_unsacked, fast_rexmit); + tcp_cwnd_reduction(sk, prior_unsacked, fast_rexmit, flag); tcp_xmit_retransmit_queue(sk); } -- GitLab From 0a6d4245691173eb953c440b8c6fc0b1688e6b25 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 2 Jul 2015 13:24:44 +0200 Subject: [PATCH 0608/7006] mlx4: TCP/UDP packets have L4 hash Mellanox driver has the knowledge if rxhash is a L4 hash, if it receives a non fragmented TCP or UDP frame and NETIF_F_RXCSUM is enabled on netdev. ip_summed value is CHECKSUM_UNNECESSARY in this case. Signed-off-by: Eric Dumazet Cc: Amir Vadai Cc: Ido Shamay Acked-by: Ido Shamay Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 7a4f20bb7fcb4..12c65e1ad6a93 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -917,7 +917,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud if (dev->features & NETIF_F_RXHASH) skb_set_hash(gro_skb, be32_to_cpu(cqe->immed_rss_invalid), - PKT_HASH_TYPE_L3); + (ip_summed == CHECKSUM_UNNECESSARY) ? + PKT_HASH_TYPE_L4 : + PKT_HASH_TYPE_L3); skb_record_rx_queue(gro_skb, cq->ring); skb_mark_napi_id(gro_skb, &cq->napi); @@ -963,7 +965,9 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud if (dev->features & NETIF_F_RXHASH) skb_set_hash(skb, be32_to_cpu(cqe->immed_rss_invalid), - PKT_HASH_TYPE_L3); + (ip_summed == CHECKSUM_UNNECESSARY) ? + PKT_HASH_TYPE_L4 : + PKT_HASH_TYPE_L3); if ((be32_to_cpu(cqe->vlan_my_qpn) & MLX4_CQE_VLAN_PRESENT_MASK) && -- GitLab From 24ea591d2201c3257d666466e8fac50a6cf3c52f Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:03 -0700 Subject: [PATCH 0609/7006] net: sched: extend percpu stats helpers qdisc_bstats_update_cpu() and other helpers were added to support percpu stats for qdisc. We want to add percpu stats for tc action, so this patch add common helpers. qdisc_bstats_update_cpu() is renamed to qdisc_bstats_cpu_update() qdisc_qstats_drop_cpu() is renamed to qdisc_qstats_cpu_drop() Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/net/sch_generic.h | 31 +++++++++++++++++++++---------- net/core/dev.c | 4 ++-- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 2738f6f879083..2eab08c38e328 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -513,17 +513,20 @@ static inline void bstats_update(struct gnet_stats_basic_packed *bstats, bstats->packets += skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1; } -static inline void qdisc_bstats_update_cpu(struct Qdisc *sch, - const struct sk_buff *skb) +static inline void bstats_cpu_update(struct gnet_stats_basic_cpu *bstats, + const struct sk_buff *skb) { - struct gnet_stats_basic_cpu *bstats = - this_cpu_ptr(sch->cpu_bstats); - u64_stats_update_begin(&bstats->syncp); bstats_update(&bstats->bstats, skb); u64_stats_update_end(&bstats->syncp); } +static inline void qdisc_bstats_cpu_update(struct Qdisc *sch, + const struct sk_buff *skb) +{ + bstats_cpu_update(this_cpu_ptr(sch->cpu_bstats), skb); +} + static inline void qdisc_bstats_update(struct Qdisc *sch, const struct sk_buff *skb) { @@ -547,16 +550,24 @@ static inline void __qdisc_qstats_drop(struct Qdisc *sch, int count) sch->qstats.drops += count; } -static inline void qdisc_qstats_drop(struct Qdisc *sch) +static inline void qstats_drop_inc(struct gnet_stats_queue *qstats) { - sch->qstats.drops++; + qstats->drops++; } -static inline void qdisc_qstats_drop_cpu(struct Qdisc *sch) +static inline void qstats_overlimit_inc(struct gnet_stats_queue *qstats) { - struct gnet_stats_queue *qstats = this_cpu_ptr(sch->cpu_qstats); + qstats->overlimits++; +} - qstats->drops++; +static inline void qdisc_qstats_drop(struct Qdisc *sch) +{ + qstats_drop_inc(&sch->qstats); +} + +static inline void qdisc_qstats_cpu_drop(struct Qdisc *sch) +{ + qstats_drop_inc(this_cpu_ptr(sch->cpu_qstats)); } static inline void qdisc_qstats_overlimit(struct Qdisc *sch) diff --git a/net/core/dev.c b/net/core/dev.c index 6778a9999d525..e0d270143fc79 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3646,7 +3646,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, qdisc_skb_cb(skb)->pkt_len = skb->len; skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); - qdisc_bstats_update_cpu(cl->q, skb); + qdisc_bstats_cpu_update(cl->q, skb); switch (tc_classify(skb, cl, &cl_res)) { case TC_ACT_OK: @@ -3654,7 +3654,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, skb->tc_index = TC_H_MIN(cl_res.classid); break; case TC_ACT_SHOT: - qdisc_qstats_drop_cpu(cl->q); + qdisc_qstats_cpu_drop(cl->q); case TC_ACT_STOLEN: case TC_ACT_QUEUED: kfree_skb(skb); -- GitLab From 519c818e8fb646eef1e8bfedd18519bec47bc9a9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:04 -0700 Subject: [PATCH 0610/7006] net: sched: add percpu stats to actions Reuse existing percpu infrastructure John Fastabend added for qdisc. This patch adds a new cpustats parameter to tcf_hash_create() and all actions pass false, meaning this patch should have no effect yet. Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Signed-off-by: David S. Miller --- include/net/act_api.h | 4 +++- net/sched/act_api.c | 44 +++++++++++++++++++++++++++++++--------- net/sched/act_bpf.c | 2 +- net/sched/act_connmark.c | 3 ++- net/sched/act_csum.c | 3 ++- net/sched/act_gact.c | 3 ++- net/sched/act_ipt.c | 2 +- net/sched/act_mirred.c | 3 ++- net/sched/act_nat.c | 3 ++- net/sched/act_pedit.c | 3 ++- net/sched/act_simple.c | 3 ++- net/sched/act_skbedit.c | 3 ++- net/sched/act_vlan.c | 3 ++- 13 files changed, 57 insertions(+), 22 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 3ee4c92afd1bd..db2063ffd1812 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -21,6 +21,8 @@ struct tcf_common { struct gnet_stats_rate_est64 tcfc_rate_est; spinlock_t tcfc_lock; struct rcu_head tcfc_rcu; + struct gnet_stats_basic_cpu __percpu *cpu_bstats; + struct gnet_stats_queue __percpu *cpu_qstats; }; #define tcf_head common.tcfc_head #define tcf_index common.tcfc_index @@ -103,7 +105,7 @@ int tcf_hash_release(struct tc_action *a, int bind); u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo); int tcf_hash_check(u32 index, struct tc_action *a, int bind); int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, - int size, int bind); + int size, int bind, bool cpustats); void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est); void tcf_hash_insert(struct tc_action *a); diff --git a/net/sched/act_api.c b/net/sched/act_api.c index af427a3dbcba2..074a32f466f8f 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -27,6 +27,15 @@ #include #include +static void free_tcf(struct rcu_head *head) +{ + struct tcf_common *p = container_of(head, struct tcf_common, tcfc_rcu); + + free_percpu(p->cpu_bstats); + free_percpu(p->cpu_qstats); + kfree(p); +} + void tcf_hash_destroy(struct tc_action *a) { struct tcf_common *p = a->priv; @@ -41,7 +50,7 @@ void tcf_hash_destroy(struct tc_action *a) * gen_estimator est_timer() might access p->tcfc_lock * or bstats, wait a RCU grace period before freeing p */ - kfree_rcu(p, tcfc_rcu); + call_rcu(&p->tcfc_rcu, free_tcf); } EXPORT_SYMBOL(tcf_hash_destroy); @@ -230,15 +239,16 @@ void tcf_hash_cleanup(struct tc_action *a, struct nlattr *est) if (est) gen_kill_estimator(&pc->tcfc_bstats, &pc->tcfc_rate_est); - kfree_rcu(pc, tcfc_rcu); + call_rcu(&pc->tcfc_rcu, free_tcf); } EXPORT_SYMBOL(tcf_hash_cleanup); int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, - int size, int bind) + int size, int bind, bool cpustats) { struct tcf_hashinfo *hinfo = a->ops->hinfo; struct tcf_common *p = kzalloc(size, GFP_KERNEL); + int err = -ENOMEM; if (unlikely(!p)) return -ENOMEM; @@ -246,18 +256,32 @@ int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, if (bind) p->tcfc_bindcnt = 1; + if (cpustats) { + p->cpu_bstats = netdev_alloc_pcpu_stats(struct gnet_stats_basic_cpu); + if (!p->cpu_bstats) { +err1: + kfree(p); + return err; + } + p->cpu_qstats = alloc_percpu(struct gnet_stats_queue); + if (!p->cpu_qstats) { +err2: + free_percpu(p->cpu_bstats); + goto err1; + } + } spin_lock_init(&p->tcfc_lock); INIT_HLIST_NODE(&p->tcfc_head); p->tcfc_index = index ? index : tcf_hash_new_index(hinfo); p->tcfc_tm.install = jiffies; p->tcfc_tm.lastuse = jiffies; if (est) { - int err = gen_new_estimator(&p->tcfc_bstats, NULL, - &p->tcfc_rate_est, - &p->tcfc_lock, est); + err = gen_new_estimator(&p->tcfc_bstats, p->cpu_bstats, + &p->tcfc_rate_est, + &p->tcfc_lock, est); if (err) { - kfree(p); - return err; + free_percpu(p->cpu_qstats); + goto err2; } } @@ -615,10 +639,10 @@ int tcf_action_copy_stats(struct sk_buff *skb, struct tc_action *a, if (err < 0) goto errout; - if (gnet_stats_copy_basic(&d, NULL, &p->tcfc_bstats) < 0 || + if (gnet_stats_copy_basic(&d, p->cpu_bstats, &p->tcfc_bstats) < 0 || gnet_stats_copy_rate_est(&d, &p->tcfc_bstats, &p->tcfc_rate_est) < 0 || - gnet_stats_copy_queue(&d, NULL, + gnet_stats_copy_queue(&d, p->cpu_qstats, &p->tcfc_qstats, p->tcfc_qstats.qlen) < 0) goto errout; diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 1d56903fd4c79..99aa271633e90 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -281,7 +281,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, if (!tcf_hash_check(parm->index, act, bind)) { ret = tcf_hash_create(parm->index, est, act, - sizeof(*prog), bind); + sizeof(*prog), bind, false); if (ret < 0) goto destroy_fp; diff --git a/net/sched/act_connmark.c b/net/sched/act_connmark.c index 295d14bd6c678..f2b540220ad02 100644 --- a/net/sched/act_connmark.c +++ b/net/sched/act_connmark.c @@ -108,7 +108,8 @@ static int tcf_connmark_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_CONNMARK_PARMS]); if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*ci), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*ci), + bind, false); if (ret) return ret; diff --git a/net/sched/act_csum.c b/net/sched/act_csum.c index 4cd5cf1aedf8b..b07c535ba8e7c 100644 --- a/net/sched/act_csum.c +++ b/net/sched/act_csum.c @@ -62,7 +62,8 @@ static int tcf_csum_init(struct net *n, struct nlattr *nla, struct nlattr *est, parm = nla_data(tb[TCA_CSUM_PARMS]); if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*p), + bind, false); if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 7fffc2272701a..a4f8af29ee300 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -85,7 +85,8 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, #endif if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*gact), + bind, false); if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index cbc8dd7dd48a5..99c9cc1c7af92 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -114,7 +114,7 @@ static int tcf_ipt_init(struct net *net, struct nlattr *nla, struct nlattr *est, index = nla_get_u32(tb[TCA_IPT_INDEX]); if (!tcf_hash_check(index, a, bind) ) { - ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind); + ret = tcf_hash_create(index, est, a, sizeof(*ipt), bind, false); if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index a42a3b2572261..002cd6c83dc61 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -93,7 +93,8 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, if (!tcf_hash_check(parm->index, a, bind)) { if (dev == NULL) return -EINVAL; - ret = tcf_hash_create(parm->index, est, a, sizeof(*m), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*m), + bind, false); if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 270a030d5fd09..5be0b3c1c5b0c 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -55,7 +55,8 @@ static int tcf_nat_init(struct net *net, struct nlattr *nla, struct nlattr *est, parm = nla_data(tb[TCA_NAT_PARMS]); if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*p), + bind, false); if (ret) return ret; ret = ACT_P_CREATED; diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index 17e6d6669c7fd..ce8676ad892f2 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -57,7 +57,8 @@ static int tcf_pedit_init(struct net *net, struct nlattr *nla, if (!tcf_hash_check(parm->index, a, bind)) { if (!parm->nkeys) return -EINVAL; - ret = tcf_hash_create(parm->index, est, a, sizeof(*p), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*p), + bind, false); if (ret) return ret; p = to_pedit(a); diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index 6a8d9488613a7..d6b708d6afdf3 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -103,7 +103,8 @@ static int tcf_simp_init(struct net *net, struct nlattr *nla, defdata = nla_data(tb[TCA_DEF_DATA]); if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*d), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*d), + bind, false); if (ret) return ret; diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index fcfeeaf838beb..6751b5f8c046a 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -99,7 +99,8 @@ static int tcf_skbedit_init(struct net *net, struct nlattr *nla, parm = nla_data(tb[TCA_SKBEDIT_PARMS]); if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*d), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*d), + bind, false); if (ret) return ret; diff --git a/net/sched/act_vlan.c b/net/sched/act_vlan.c index d735ecf0b1a78..796785e0bf96b 100644 --- a/net/sched/act_vlan.c +++ b/net/sched/act_vlan.c @@ -116,7 +116,8 @@ static int tcf_vlan_init(struct net *net, struct nlattr *nla, action = parm->v_action; if (!tcf_hash_check(parm->index, a, bind)) { - ret = tcf_hash_create(parm->index, est, a, sizeof(*v), bind); + ret = tcf_hash_create(parm->index, est, a, sizeof(*v), + bind, false); if (ret) return ret; -- GitLab From cef5ecf96b28dc91c4e9f398a336c578fb9e1a0c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:05 -0700 Subject: [PATCH 0611/7006] net_sched: act_gact: make tcfg_pval non zero First step for gact RCU operation : Instead of testing if tcfg_pval is zero or not, just make it 1. No change in behavior, but slightly faster code. The smp_rmb()/smp_wmb() barriers, while not strictly needed at this stage are added for upcoming spinlock removal. Signed-off-by: Eric Dumazet Acked-by: Alexei Starovoitov Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Signed-off-by: David S. Miller --- net/sched/act_gact.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index a4f8af29ee300..22a3a61aa090e 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -28,14 +28,16 @@ #ifdef CONFIG_GACT_PROB static int gact_net_rand(struct tcf_gact *gact) { - if (!gact->tcfg_pval || prandom_u32() % gact->tcfg_pval) + smp_rmb(); /* coupled with smp_wmb() in tcf_gact_init() */ + if (prandom_u32() % gact->tcfg_pval) return gact->tcf_action; return gact->tcfg_paction; } static int gact_determ(struct tcf_gact *gact) { - if (!gact->tcfg_pval || gact->tcf_bstats.packets % gact->tcfg_pval) + smp_rmb(); /* coupled with smp_wmb() in tcf_gact_init() */ + if (gact->tcf_bstats.packets % gact->tcfg_pval) return gact->tcf_action; return gact->tcfg_paction; } @@ -105,7 +107,11 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, #ifdef CONFIG_GACT_PROB if (p_parm) { gact->tcfg_paction = p_parm->paction; - gact->tcfg_pval = p_parm->pval; + gact->tcfg_pval = max_t(u16, 1, p_parm->pval); + /* Make sure tcfg_pval is written before tcfg_ptype + * coupled with smp_rmb() in gact_net_rand() & gact_determ() + */ + smp_wmb(); gact->tcfg_ptype = p_parm->ptype; } #endif -- GitLab From cc6510a9504fd3c03d76bd68d99653148342eecc Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:06 -0700 Subject: [PATCH 0612/7006] net_sched: act_gact: use a separate packet counters for gact_determ() Second step for gact RCU operation : We want to get rid of the spinlock protecting gact operations. Stats (packets/bytes) will soon be per cpu. gact_determ() would not work without a central packet counter, so lets add it for this mode. Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Signed-off-by: David S. Miller --- include/net/tc_act/tc_gact.h | 7 ++++--- net/sched/act_gact.c | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/net/tc_act/tc_gact.h b/include/net/tc_act/tc_gact.h index 9fc9b578908ab..592a6bc02b0b5 100644 --- a/include/net/tc_act/tc_gact.h +++ b/include/net/tc_act/tc_gact.h @@ -6,9 +6,10 @@ struct tcf_gact { struct tcf_common common; #ifdef CONFIG_GACT_PROB - u16 tcfg_ptype; - u16 tcfg_pval; - int tcfg_paction; + u16 tcfg_ptype; + u16 tcfg_pval; + int tcfg_paction; + atomic_t packets; #endif }; #define to_gact(a) \ diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 22a3a61aa090e..2f9bec584b3fc 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -36,8 +36,10 @@ static int gact_net_rand(struct tcf_gact *gact) static int gact_determ(struct tcf_gact *gact) { + u32 pack = atomic_inc_return(&gact->packets); + smp_rmb(); /* coupled with smp_wmb() in tcf_gact_init() */ - if (gact->tcf_bstats.packets % gact->tcfg_pval) + if (pack % gact->tcfg_pval) return gact->tcf_action; return gact->tcfg_paction; } -- GitLab From 8f2ae965b7ef4f4ddab6110f06388e270723d694 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:07 -0700 Subject: [PATCH 0613/7006] net_sched: act_gact: read tcfg_ptype once Third step for gact RCU operation : Following patch will get rid of spinlock protection, so we need to read tcfg_ptype once. Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Signed-off-by: David S. Miller --- net/sched/act_gact.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index 2f9bec584b3fc..e4eb88d3d8dc7 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -127,16 +127,16 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_gact *gact = a->priv; - int action = TC_ACT_SHOT; + int action = gact->tcf_action; spin_lock(&gact->tcf_lock); #ifdef CONFIG_GACT_PROB - if (gact->tcfg_ptype) - action = gact_rand[gact->tcfg_ptype](gact); - else - action = gact->tcf_action; -#else - action = gact->tcf_action; + { + u32 ptype = READ_ONCE(gact->tcfg_ptype); + + if (ptype) + action = gact_rand[ptype](gact); + } #endif gact->tcf_bstats.bytes += qdisc_pkt_len(skb); gact->tcf_bstats.packets++; -- GitLab From 56e5d1ca183d8616fab377d7d466c244b4dbb3b9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:08 -0700 Subject: [PATCH 0614/7006] net_sched: act_gact: remove spinlock in fast path Final step for gact RCU operation : 1) Use percpu stats 2) update lastuse only every clock tick to avoid false sharing 3) Remove spinlock acquisition, as it is no longer needed. Since this is the last contended lock in packet RX when tc gact is used, this gives impressive gain. My host with 8 RX queues was handling 5 Mpps before the patch, and more than 11 Mpps after patch. Tested: On receiver : dev=eth0 tc qdisc del dev $dev ingress 2>/dev/null tc qdisc add dev $dev ingress tc filter del dev $dev root pref 10 2>/dev/null tc filter del dev $dev pref 10 2>/dev/null tc filter add dev $dev est 1sec 4sec parent ffff: protocol ip prio 1 \ u32 match ip src 7.0.0.0/8 flowid 1:15 action drop Sender sends packets flood from 7/8 network Signed-off-by: Eric Dumazet Acked-by: Alexei Starovoitov Acked-by: Jamal Hadi Salim Acked-by: John Fastabend Signed-off-by: David S. Miller --- include/net/act_api.h | 11 +++++++++++ net/sched/act_gact.c | 17 +++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index db2063ffd1812..8d2a707a9e876 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -70,6 +70,17 @@ static inline void tcf_hashinfo_destroy(struct tcf_hashinfo *hf) kfree(hf->htab); } +/* Update lastuse only if needed, to avoid dirtying a cache line. + * We use a temp variable to avoid fetching jiffies twice. + */ +static inline void tcf_lastuse_update(struct tcf_t *tm) +{ + unsigned long now = jiffies; + + if (tm->lastuse != now) + tm->lastuse = now; +} + #ifdef CONFIG_NET_CLS_ACT #define ACT_P_CREATED 1 diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index e4eb88d3d8dc7..5c1b051707363 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -90,7 +90,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, if (!tcf_hash_check(parm->index, a, bind)) { ret = tcf_hash_create(parm->index, est, a, sizeof(*gact), - bind, false); + bind, true); if (ret) return ret; ret = ACT_P_CREATED; @@ -104,7 +104,7 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, gact = to_gact(a); - spin_lock_bh(&gact->tcf_lock); + ASSERT_RTNL(); gact->tcf_action = parm->action; #ifdef CONFIG_GACT_PROB if (p_parm) { @@ -117,7 +117,6 @@ static int tcf_gact_init(struct net *net, struct nlattr *nla, gact->tcfg_ptype = p_parm->ptype; } #endif - spin_unlock_bh(&gact->tcf_lock); if (ret == ACT_P_CREATED) tcf_hash_insert(a); return ret; @@ -127,9 +126,8 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, struct tcf_result *res) { struct tcf_gact *gact = a->priv; - int action = gact->tcf_action; + int action = READ_ONCE(gact->tcf_action); - spin_lock(&gact->tcf_lock); #ifdef CONFIG_GACT_PROB { u32 ptype = READ_ONCE(gact->tcfg_ptype); @@ -138,12 +136,11 @@ static int tcf_gact(struct sk_buff *skb, const struct tc_action *a, action = gact_rand[ptype](gact); } #endif - gact->tcf_bstats.bytes += qdisc_pkt_len(skb); - gact->tcf_bstats.packets++; + bstats_cpu_update(this_cpu_ptr(gact->common.cpu_bstats), skb); if (action == TC_ACT_SHOT) - gact->tcf_qstats.drops++; - gact->tcf_tm.lastuse = jiffies; - spin_unlock(&gact->tcf_lock); + qstats_drop_inc(this_cpu_ptr(gact->common.cpu_qstats)); + + tcf_lastuse_update(&gact->tcf_tm); return action; } -- GitLab From 2ee22a90c7afac265bb6f7abea610b938195e2b8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 05:18:09 -0700 Subject: [PATCH 0615/7006] net_sched: act_mirred: remove spinlock in fast path Like act_gact, act_mirred can be lockless in packet processing 1) Use percpu stats 2) update lastuse only every clock tick to avoid false sharing 3) use rcu to protect tcfm_dev 4) Remove spinlock usage, as it is no longer needed. Next step : add multi queue capability to ifb device Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Cc: Jamal Hadi Salim Cc: John Fastabend Acked-by: Jamal Hadi Salim Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/net/tc_act/tc_mirred.h | 2 +- net/sched/act_mirred.c | 57 ++++++++++++++++++---------------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/include/net/tc_act/tc_mirred.h b/include/net/tc_act/tc_mirred.h index 4dd77a1c106b2..dae96bae1c19c 100644 --- a/include/net/tc_act/tc_mirred.h +++ b/include/net/tc_act/tc_mirred.h @@ -8,7 +8,7 @@ struct tcf_mirred { int tcfm_eaction; int tcfm_ifindex; int tcfm_ok_push; - struct net_device *tcfm_dev; + struct net_device __rcu *tcfm_dev; struct list_head tcfm_list; }; #define to_mirred(a) \ diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 002cd6c83dc61..19cd8904efa0a 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -35,9 +35,11 @@ static LIST_HEAD(mirred_list); static void tcf_mirred_release(struct tc_action *a, int bind) { struct tcf_mirred *m = to_mirred(a); + struct net_device *dev = rcu_dereference_protected(m->tcfm_dev, 1); + list_del(&m->tcfm_list); - if (m->tcfm_dev) - dev_put(m->tcfm_dev); + if (dev) + dev_put(dev); } static const struct nla_policy mirred_policy[TCA_MIRRED_MAX + 1] = { @@ -94,7 +96,7 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, if (dev == NULL) return -EINVAL; ret = tcf_hash_create(parm->index, est, a, sizeof(*m), - bind, false); + bind, true); if (ret) return ret; ret = ACT_P_CREATED; @@ -106,18 +108,18 @@ static int tcf_mirred_init(struct net *net, struct nlattr *nla, } m = to_mirred(a); - spin_lock_bh(&m->tcf_lock); + ASSERT_RTNL(); m->tcf_action = parm->action; m->tcfm_eaction = parm->eaction; if (dev != NULL) { m->tcfm_ifindex = parm->ifindex; if (ret != ACT_P_CREATED) - dev_put(m->tcfm_dev); + dev_put(rcu_dereference_protected(m->tcfm_dev, 1)); dev_hold(dev); - m->tcfm_dev = dev; + rcu_assign_pointer(m->tcfm_dev, dev); m->tcfm_ok_push = ok_push; } - spin_unlock_bh(&m->tcf_lock); + if (ret == ACT_P_CREATED) { list_add(&m->tcfm_list, &mirred_list); tcf_hash_insert(a); @@ -132,20 +134,22 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, struct tcf_mirred *m = a->priv; struct net_device *dev; struct sk_buff *skb2; + int retval, err; u32 at; - int retval, err = 1; - spin_lock(&m->tcf_lock); - m->tcf_tm.lastuse = jiffies; - bstats_update(&m->tcf_bstats, skb); + tcf_lastuse_update(&m->tcf_tm); + + bstats_cpu_update(this_cpu_ptr(m->common.cpu_bstats), skb); - dev = m->tcfm_dev; - if (!dev) { - printk_once(KERN_NOTICE "tc mirred: target device is gone\n"); + rcu_read_lock(); + retval = READ_ONCE(m->tcf_action); + dev = rcu_dereference(m->tcfm_dev); + if (unlikely(!dev)) { + pr_notice_once("tc mirred: target device is gone\n"); goto out; } - if (!(dev->flags & IFF_UP)) { + if (unlikely(!(dev->flags & IFF_UP))) { net_notice_ratelimited("tc mirred to Houston: device %s is down\n", dev->name); goto out; @@ -153,7 +157,7 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, at = G_TC_AT(skb->tc_verd); skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 == NULL) + if (!skb2) goto out; if (!(at & AT_EGRESS)) { @@ -169,16 +173,13 @@ static int tcf_mirred(struct sk_buff *skb, const struct tc_action *a, skb2->dev = dev; err = dev_queue_xmit(skb2); -out: if (err) { - m->tcf_qstats.overlimits++; +out: + qstats_overlimit_inc(this_cpu_ptr(m->common.cpu_qstats)); if (m->tcfm_eaction != TCA_EGRESS_MIRROR) retval = TC_ACT_SHOT; - else - retval = m->tcf_action; - } else - retval = m->tcf_action; - spin_unlock(&m->tcf_lock); + } + rcu_read_unlock(); return retval; } @@ -217,14 +218,16 @@ static int mirred_device_event(struct notifier_block *unused, struct net_device *dev = netdev_notifier_info_to_dev(ptr); struct tcf_mirred *m; + ASSERT_RTNL(); if (event == NETDEV_UNREGISTER) list_for_each_entry(m, &mirred_list, tcfm_list) { - spin_lock_bh(&m->tcf_lock); - if (m->tcfm_dev == dev) { + if (rcu_access_pointer(m->tcfm_dev) == dev) { dev_put(dev); - m->tcfm_dev = NULL; + /* Note : no rcu grace period necessary, as + * net_device are already rcu protected. + */ + RCU_INIT_POINTER(m->tcfm_dev, NULL); } - spin_unlock_bh(&m->tcf_lock); } return NOTIFY_DONE; -- GitLab From 6ab13b27699e5a71cca20d301c3c424653bd0841 Mon Sep 17 00:00:00 2001 From: "Li, Liang Z" Date: Mon, 6 Jul 2015 08:42:56 +0800 Subject: [PATCH 0616/7006] xen-netback: remove duplicated function definition There are two duplicated xenvif_zerocopy_callback() definitions. Remove one of them. Signed-off-by: Liang Li Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 8a495b318b6f2..c6cb85a85c896 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -325,9 +325,6 @@ static inline pending_ring_idx_t nr_pending_reqs(struct xenvif_queue *queue) queue->pending_prod + queue->pending_cons; } -/* Callback from stack when TX packet can be released */ -void xenvif_zerocopy_callback(struct ubuf_info *ubuf, bool zerocopy_success); - irqreturn_t xenvif_interrupt(int irq, void *dev_id); extern bool separate_tx_rx_irq; -- GitLab From 7baaa9092dedad5f670a7b1716b2ce9e1175ba02 Mon Sep 17 00:00:00 2001 From: Punnaiah Choudary Kalluri Date: Mon, 6 Jul 2015 10:02:53 +0530 Subject: [PATCH 0617/7006] net: macb: Add SG support for Zynq SOC family Enable SG support for Zynq SOC family devices. Signed-off-by: Punnaiah Choudary Kalluri Acked-by: Nicolas Ferre Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index caeb395615672..a4e3f8655cb8c 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -2741,8 +2741,7 @@ static const struct macb_config emac_config = { static const struct macb_config zynqmp_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | - MACB_CAPS_JUMBO, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, @@ -2750,8 +2749,7 @@ static const struct macb_config zynqmp_config = { }; static const struct macb_config zynq_config = { - .caps = MACB_CAPS_SG_DISABLED | MACB_CAPS_GIGABIT_MODE_AVAILABLE | - MACB_CAPS_NO_GIGABIT_HALF, + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_NO_GIGABIT_HALF, .dma_burst_length = 16, .clk_init = macb_clk_init, .init = macb_init, -- GitLab From d912557b346099584bbbfa8d3c1e101c46e33b59 Mon Sep 17 00:00:00 2001 From: Michael Holzheu Date: Mon, 6 Jul 2015 16:20:07 +0200 Subject: [PATCH 0618/7006] samples: bpf: enable trace samples for s390x The trace bpf samples do not compile on s390x because they use x86 specific fields from the "pt_regs" structure. Fix this and access the fields via new PT_REGS macros. Signed-off-by: Michael Holzheu Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- samples/bpf/bpf_helpers.h | 25 +++++++++++++++++++++++++ samples/bpf/tracex1_kern.c | 2 +- samples/bpf/tracex2_kern.c | 6 +++--- samples/bpf/tracex3_kern.c | 4 ++-- samples/bpf/tracex4_kern.c | 6 +++--- samples/bpf/tracex5_kern.c | 6 +++--- 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/samples/bpf/bpf_helpers.h b/samples/bpf/bpf_helpers.h index bdf1c1607b808..c77c872fe8ee4 100644 --- a/samples/bpf/bpf_helpers.h +++ b/samples/bpf/bpf_helpers.h @@ -60,4 +60,29 @@ static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flag static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) = (void *) BPF_FUNC_l4_csum_replace; +#if defined(__x86_64__) + +#define PT_REGS_PARM1(x) ((x)->di) +#define PT_REGS_PARM2(x) ((x)->si) +#define PT_REGS_PARM3(x) ((x)->dx) +#define PT_REGS_PARM4(x) ((x)->cx) +#define PT_REGS_PARM5(x) ((x)->r8) +#define PT_REGS_RET(x) ((x)->sp) +#define PT_REGS_FP(x) ((x)->bp) +#define PT_REGS_RC(x) ((x)->ax) +#define PT_REGS_SP(x) ((x)->sp) + +#elif defined(__s390x__) + +#define PT_REGS_PARM1(x) ((x)->gprs[2]) +#define PT_REGS_PARM2(x) ((x)->gprs[3]) +#define PT_REGS_PARM3(x) ((x)->gprs[4]) +#define PT_REGS_PARM4(x) ((x)->gprs[5]) +#define PT_REGS_PARM5(x) ((x)->gprs[6]) +#define PT_REGS_RET(x) ((x)->gprs[14]) +#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC(x) ((x)->gprs[2]) +#define PT_REGS_SP(x) ((x)->gprs[15]) + +#endif #endif diff --git a/samples/bpf/tracex1_kern.c b/samples/bpf/tracex1_kern.c index 31620463701a5..3f450a8fa1f34 100644 --- a/samples/bpf/tracex1_kern.c +++ b/samples/bpf/tracex1_kern.c @@ -29,7 +29,7 @@ int bpf_prog1(struct pt_regs *ctx) int len; /* non-portable! works for the given kernel only */ - skb = (struct sk_buff *) ctx->di; + skb = (struct sk_buff *) PT_REGS_PARM1(ctx); dev = _(skb->dev); diff --git a/samples/bpf/tracex2_kern.c b/samples/bpf/tracex2_kern.c index dc50f4f2943f9..b32367cfbff4a 100644 --- a/samples/bpf/tracex2_kern.c +++ b/samples/bpf/tracex2_kern.c @@ -27,10 +27,10 @@ int bpf_prog2(struct pt_regs *ctx) long init_val = 1; long *value; - /* x64 specific: read ip of kfree_skb caller. + /* x64/s390x specific: read ip of kfree_skb caller. * non-portable version of __builtin_return_address(0) */ - bpf_probe_read(&loc, sizeof(loc), (void *)ctx->sp); + bpf_probe_read(&loc, sizeof(loc), (void *)PT_REGS_RET(ctx)); value = bpf_map_lookup_elem(&my_map, &loc); if (value) @@ -79,7 +79,7 @@ struct bpf_map_def SEC("maps") my_hist_map = { SEC("kprobe/sys_write") int bpf_prog3(struct pt_regs *ctx) { - long write_size = ctx->dx; /* arg3 */ + long write_size = PT_REGS_PARM3(ctx); long init_val = 1; long *value; struct hist_key key = {}; diff --git a/samples/bpf/tracex3_kern.c b/samples/bpf/tracex3_kern.c index 255ff27923666..bf337fbb09472 100644 --- a/samples/bpf/tracex3_kern.c +++ b/samples/bpf/tracex3_kern.c @@ -23,7 +23,7 @@ struct bpf_map_def SEC("maps") my_map = { SEC("kprobe/blk_mq_start_request") int bpf_prog1(struct pt_regs *ctx) { - long rq = ctx->di; + long rq = PT_REGS_PARM1(ctx); u64 val = bpf_ktime_get_ns(); bpf_map_update_elem(&my_map, &rq, &val, BPF_ANY); @@ -51,7 +51,7 @@ struct bpf_map_def SEC("maps") lat_map = { SEC("kprobe/blk_update_request") int bpf_prog2(struct pt_regs *ctx) { - long rq = ctx->di; + long rq = PT_REGS_PARM1(ctx); u64 *value, l, base; u32 index; diff --git a/samples/bpf/tracex4_kern.c b/samples/bpf/tracex4_kern.c index 126b80512228a..ac4671420cf15 100644 --- a/samples/bpf/tracex4_kern.c +++ b/samples/bpf/tracex4_kern.c @@ -27,7 +27,7 @@ struct bpf_map_def SEC("maps") my_map = { SEC("kprobe/kmem_cache_free") int bpf_prog1(struct pt_regs *ctx) { - long ptr = ctx->si; + long ptr = PT_REGS_PARM2(ctx); bpf_map_delete_elem(&my_map, &ptr); return 0; @@ -36,11 +36,11 @@ int bpf_prog1(struct pt_regs *ctx) SEC("kretprobe/kmem_cache_alloc_node") int bpf_prog2(struct pt_regs *ctx) { - long ptr = ctx->ax; + long ptr = PT_REGS_RC(ctx); long ip = 0; /* get ip address of kmem_cache_alloc_node() caller */ - bpf_probe_read(&ip, sizeof(ip), (void *)(ctx->bp + sizeof(ip))); + bpf_probe_read(&ip, sizeof(ip), (void *)(PT_REGS_FP(ctx) + sizeof(ip))); struct pair v = { .val = bpf_ktime_get_ns(), diff --git a/samples/bpf/tracex5_kern.c b/samples/bpf/tracex5_kern.c index b71fe07a7a7a4..b3f4295bf2885 100644 --- a/samples/bpf/tracex5_kern.c +++ b/samples/bpf/tracex5_kern.c @@ -24,7 +24,7 @@ int bpf_prog1(struct pt_regs *ctx) { struct seccomp_data sd = {}; - bpf_probe_read(&sd, sizeof(sd), (void *)ctx->di); + bpf_probe_read(&sd, sizeof(sd), (void *)PT_REGS_PARM1(ctx)); /* dispatch into next BPF program depending on syscall number */ bpf_tail_call(ctx, &progs, sd.nr); @@ -42,7 +42,7 @@ PROG(__NR_write)(struct pt_regs *ctx) { struct seccomp_data sd = {}; - bpf_probe_read(&sd, sizeof(sd), (void *)ctx->di); + bpf_probe_read(&sd, sizeof(sd), (void *)PT_REGS_PARM1(ctx)); if (sd.args[2] == 512) { char fmt[] = "write(fd=%d, buf=%p, size=%d)\n"; bpf_trace_printk(fmt, sizeof(fmt), @@ -55,7 +55,7 @@ PROG(__NR_read)(struct pt_regs *ctx) { struct seccomp_data sd = {}; - bpf_probe_read(&sd, sizeof(sd), (void *)ctx->di); + bpf_probe_read(&sd, sizeof(sd), (void *)PT_REGS_PARM1(ctx)); if (sd.args[2] > 128 && sd.args[2] <= 1024) { char fmt[] = "read(fd=%d, buf=%p, size=%d)\n"; bpf_trace_printk(fmt, sizeof(fmt), -- GitLab From 0beb44b0653978c0f180f902fb93a1b0b61833b8 Mon Sep 17 00:00:00 2001 From: Carol Soto Date: Mon, 6 Jul 2015 09:20:19 -0500 Subject: [PATCH 0619/7006] net/mlx4_core: Add extra check for total vfs for SRIOV Add extra check for total vfs for SRIOV to check if that value is bigger than total vfs in pci SRIOV capabalities. Fix a check and print of the number of maximum vfs that hw can handle. Fix a check and print of the number of maximum vfs per port that driver can handle. Signed-off-by: Carol L Soto Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 12fbfcb44d8ac..d76f4257e305b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2907,6 +2907,8 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, { u64 dev_flags = dev->flags; int err = 0; + int fw_enabled_sriov_vfs = min(pci_sriov_get_totalvfs(pdev), + MLX4_MAX_NUM_VF); if (reset_flow) { dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs), @@ -2932,6 +2934,12 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev, } if (!(dev->flags & MLX4_FLAG_SRIOV)) { + if (total_vfs > fw_enabled_sriov_vfs) { + mlx4_err(dev, "requested vfs (%d) > available vfs (%d). Continuing without SR_IOV\n", + total_vfs, fw_enabled_sriov_vfs); + err = -ENOMEM; + goto disable_sriov; + } mlx4_warn(dev, "Enabling SR-IOV with %d VFs\n", total_vfs); err = pci_enable_sriov(pdev, total_vfs); } @@ -3413,20 +3421,20 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data, goto err_disable_pdev; } } - if (total_vfs >= MLX4_MAX_NUM_VF) { + if (total_vfs > MLX4_MAX_NUM_VF) { dev_err(&pdev->dev, - "Requested more VF's (%d) than allowed (%d)\n", - total_vfs, MLX4_MAX_NUM_VF - 1); + "Requested more VF's (%d) than allowed by hw (%d)\n", + total_vfs, MLX4_MAX_NUM_VF); err = -EINVAL; goto err_disable_pdev; } for (i = 0; i < MLX4_MAX_PORTS; i++) { - if (nvfs[i] + nvfs[2] >= MLX4_MAX_NUM_VF_P_PORT) { + if (nvfs[i] + nvfs[2] > MLX4_MAX_NUM_VF_P_PORT) { dev_err(&pdev->dev, - "Requested more VF's (%d) for port (%d) than allowed (%d)\n", + "Requested more VF's (%d) for port (%d) than allowed by driver (%d)\n", nvfs[i] + nvfs[2], i + 1, - MLX4_MAX_NUM_VF_P_PORT - 1); + MLX4_MAX_NUM_VF_P_PORT); err = -EINVAL; goto err_disable_pdev; } -- GitLab From 81aa507981bd785da84ac8bbed942495257dcaa3 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Mon, 6 Jul 2015 22:38:34 +0530 Subject: [PATCH 0620/7006] cxgb4: Add PCI device ids for few more T5 and T6 adapters Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h index d7ca106927b0d..8353a6cbfcc21 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h @@ -142,6 +142,8 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x5013), /* T580-chr */ CH_PCI_ID_TABLE_FENTRY(0x5014), /* T580-so */ CH_PCI_ID_TABLE_FENTRY(0x5015), /* T502-bt */ + CH_PCI_ID_TABLE_FENTRY(0x5016), /* T580-OCP-SO */ + CH_PCI_ID_TABLE_FENTRY(0x5017), /* T520-OCP-SO */ CH_PCI_ID_TABLE_FENTRY(0x5080), /* Custom T540-cr */ CH_PCI_ID_TABLE_FENTRY(0x5081), /* Custom T540-LL-cr */ CH_PCI_ID_TABLE_FENTRY(0x5082), /* Custom T504-cr */ @@ -155,6 +157,22 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN CH_PCI_ID_TABLE_FENTRY(0x5090), /* Custom T540-CR */ CH_PCI_ID_TABLE_FENTRY(0x5091), /* Custom T522-CR */ CH_PCI_ID_TABLE_FENTRY(0x5092), /* Custom T520-CR */ + + /* T6 adapters: + */ + CH_PCI_ID_TABLE_FENTRY(0x6001), + CH_PCI_ID_TABLE_FENTRY(0x6002), + CH_PCI_ID_TABLE_FENTRY(0x6003), + CH_PCI_ID_TABLE_FENTRY(0x6004), + CH_PCI_ID_TABLE_FENTRY(0x6005), + CH_PCI_ID_TABLE_FENTRY(0x6006), + CH_PCI_ID_TABLE_FENTRY(0x6007), + CH_PCI_ID_TABLE_FENTRY(0x6009), + CH_PCI_ID_TABLE_FENTRY(0x600d), + CH_PCI_ID_TABLE_FENTRY(0x6010), + CH_PCI_ID_TABLE_FENTRY(0x6011), + CH_PCI_ID_TABLE_FENTRY(0x6014), + CH_PCI_ID_TABLE_FENTRY(0x6015), CH_PCI_DEVICE_ID_TABLE_DEFINE_END; #endif /* __T4_PCI_ID_TBL_H__ */ -- GitLab From 9e29e21a9bbfb2204bab875f0ef6dbaed66592e7 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 6 Jul 2015 22:05:28 +0200 Subject: [PATCH 0621/7006] ifb: add multiqueue operation Add multiqueue capabilities to ifb netdevice. This removes last bottleneck for ingress when mq qdisc can be used to shard load from multiple RX queues on physical device. Tested: # netem based setup, installed at receiver side ETH=eth0 IFB=ifb10 EST="est 1sec 4sec" # Optional rate estimator RTT_HALF=2ms #REORDER=20us #LOSS="loss 1" TXQ=8 ip link add ifb10 numtxqueues $TXQ type ifb ip link set dev $IFB up tc qdisc add dev $ETH ingress 2>/dev/null tc filter add dev $ETH parent ffff: \ protocol ip u32 match u32 0 0 flowid 1:1 \ action mirred egress redirect dev $IFB tc qdisc del dev $IFB root 2>/dev/null tc qdisc add dev $IFB root handle 1: mq for i in `seq 1 $TXQ` do slot=$( printf %x $(( i )) ) tc qd add dev $IFB parent 1:$slot $EST netem \ limit 100000 delay $RTT_HALF $REORDER $LOSS done lpaa24:~# tc -s -d qd sh dev ifb10 qdisc mq 1: root Sent 316544766 bytes 5265927 pkt (dropped 0, overlimits 0 requeues 0) backlog 98880b 1648p requeues 0 qdisc netem 8002: parent 1:1 limit 100000 delay 2.0ms Sent 39601416 bytes 658721 pkt (dropped 0, overlimits 0 requeues 0) rate 38235Kbit 79657pps backlog 12240b 204p requeues 0 qdisc netem 8003: parent 1:2 limit 100000 delay 2.0ms Sent 39472866 bytes 657227 pkt (dropped 0, overlimits 0 requeues 0) rate 38234Kbit 79655pps backlog 10620b 176p requeues 0 qdisc netem 8004: parent 1:3 limit 100000 delay 2.0ms Sent 39703417 bytes 659699 pkt (dropped 0, overlimits 0 requeues 0) rate 38320Kbit 79831pps backlog 12780b 213p requeues 0 qdisc netem 8005: parent 1:4 limit 100000 delay 2.0ms Sent 39565149 bytes 658011 pkt (dropped 0, overlimits 0 requeues 0) rate 38174Kbit 79530pps backlog 11880b 198p requeues 0 qdisc netem 8006: parent 1:5 limit 100000 delay 2.0ms Sent 39506078 bytes 657354 pkt (dropped 0, overlimits 0 requeues 0) rate 38195Kbit 79571pps backlog 12480b 208p requeues 0 qdisc netem 8007: parent 1:6 limit 100000 delay 2.0ms Sent 39675994 bytes 658849 pkt (dropped 0, overlimits 0 requeues 0) rate 38323Kbit 79838pps backlog 12600b 210p requeues 0 qdisc netem 8008: parent 1:7 limit 100000 delay 2.0ms Sent 39532042 bytes 658367 pkt (dropped 0, overlimits 0 requeues 0) rate 38177Kbit 79536pps backlog 13140b 219p requeues 0 qdisc netem 8009: parent 1:8 limit 100000 delay 2.0ms Sent 39488164 bytes 657705 pkt (dropped 0, overlimits 0 requeues 0) rate 38192Kbit 79568pps backlog 13Kb 222p requeues 0 Signed-off-by: Eric Dumazet Cc: Alexei Starovoitov Cc: Jamal Hadi Salim Cc: John Fastabend Acked-by: Alexei Starovoitov Acked-by: Jamal Hadi Salim Signed-off-by: David S. Miller --- drivers/net/ifb.c | 207 +++++++++++++++++++++++++++------------------- 1 file changed, 120 insertions(+), 87 deletions(-) diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 94570aace2414..cc56fac3c3f83 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -38,69 +38,68 @@ #include #define TX_Q_LIMIT 32 -struct ifb_private { +struct ifb_q_private { + struct net_device *dev; struct tasklet_struct ifb_tasklet; - int tasklet_pending; - - struct u64_stats_sync rsync; + int tasklet_pending; + int txqnum; struct sk_buff_head rq; - u64 rx_packets; - u64 rx_bytes; + u64 rx_packets; + u64 rx_bytes; + struct u64_stats_sync rsync; struct u64_stats_sync tsync; + u64 tx_packets; + u64 tx_bytes; struct sk_buff_head tq; - u64 tx_packets; - u64 tx_bytes; -}; +} ____cacheline_aligned_in_smp; -static int numifbs = 2; +struct ifb_dev_private { + struct ifb_q_private *tx_private; +}; -static void ri_tasklet(unsigned long dev); static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev); static int ifb_open(struct net_device *dev); static int ifb_close(struct net_device *dev); -static void ri_tasklet(unsigned long dev) +static void ifb_ri_tasklet(unsigned long _txp) { - struct net_device *_dev = (struct net_device *)dev; - struct ifb_private *dp = netdev_priv(_dev); + struct ifb_q_private *txp = (struct ifb_q_private *)_txp; struct netdev_queue *txq; struct sk_buff *skb; - txq = netdev_get_tx_queue(_dev, 0); - if ((skb = skb_peek(&dp->tq)) == NULL) { - if (__netif_tx_trylock(txq)) { - skb_queue_splice_tail_init(&dp->rq, &dp->tq); - __netif_tx_unlock(txq); - } else { - /* reschedule */ + txq = netdev_get_tx_queue(txp->dev, txp->txqnum); + skb = skb_peek(&txp->tq); + if (!skb) { + if (!__netif_tx_trylock(txq)) goto resched; - } + skb_queue_splice_tail_init(&txp->rq, &txp->tq); + __netif_tx_unlock(txq); } - while ((skb = __skb_dequeue(&dp->tq)) != NULL) { + while ((skb = __skb_dequeue(&txp->tq)) != NULL) { u32 from = G_TC_FROM(skb->tc_verd); skb->tc_verd = 0; skb->tc_verd = SET_TC_NCLS(skb->tc_verd); - u64_stats_update_begin(&dp->tsync); - dp->tx_packets++; - dp->tx_bytes += skb->len; - u64_stats_update_end(&dp->tsync); + u64_stats_update_begin(&txp->tsync); + txp->tx_packets++; + txp->tx_bytes += skb->len; + u64_stats_update_end(&txp->tsync); rcu_read_lock(); - skb->dev = dev_get_by_index_rcu(dev_net(_dev), skb->skb_iif); + skb->dev = dev_get_by_index_rcu(dev_net(txp->dev), skb->skb_iif); if (!skb->dev) { rcu_read_unlock(); dev_kfree_skb(skb); - _dev->stats.tx_dropped++; - if (skb_queue_len(&dp->tq) != 0) + txp->dev->stats.tx_dropped++; + if (skb_queue_len(&txp->tq) != 0) goto resched; break; } rcu_read_unlock(); - skb->skb_iif = _dev->ifindex; + skb->skb_iif = txp->dev->ifindex; if (from & AT_EGRESS) { dev_queue_xmit(skb); @@ -112,10 +111,11 @@ static void ri_tasklet(unsigned long dev) } if (__netif_tx_trylock(txq)) { - if ((skb = skb_peek(&dp->rq)) == NULL) { - dp->tasklet_pending = 0; - if (netif_queue_stopped(_dev)) - netif_wake_queue(_dev); + skb = skb_peek(&txp->rq); + if (!skb) { + txp->tasklet_pending = 0; + if (netif_tx_queue_stopped(txq)) + netif_tx_wake_queue(txq); } else { __netif_tx_unlock(txq); goto resched; @@ -123,8 +123,8 @@ static void ri_tasklet(unsigned long dev) __netif_tx_unlock(txq); } else { resched: - dp->tasklet_pending = 1; - tasklet_schedule(&dp->ifb_tasklet); + txp->tasklet_pending = 1; + tasklet_schedule(&txp->ifb_tasklet); } } @@ -132,29 +132,58 @@ resched: static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { - struct ifb_private *dp = netdev_priv(dev); + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp = dp->tx_private; unsigned int start; - - do { - start = u64_stats_fetch_begin_irq(&dp->rsync); - stats->rx_packets = dp->rx_packets; - stats->rx_bytes = dp->rx_bytes; - } while (u64_stats_fetch_retry_irq(&dp->rsync, start)); - - do { - start = u64_stats_fetch_begin_irq(&dp->tsync); - - stats->tx_packets = dp->tx_packets; - stats->tx_bytes = dp->tx_bytes; - - } while (u64_stats_fetch_retry_irq(&dp->tsync, start)); - + u64 packets, bytes; + int i; + + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + do { + start = u64_stats_fetch_begin_irq(&txp->rsync); + packets = txp->rx_packets; + bytes = txp->rx_bytes; + } while (u64_stats_fetch_retry_irq(&txp->rsync, start)); + stats->rx_packets += packets; + stats->rx_bytes += bytes; + + do { + start = u64_stats_fetch_begin_irq(&txp->tsync); + packets = txp->tx_packets; + bytes = txp->tx_bytes; + } while (u64_stats_fetch_retry_irq(&txp->tsync, start)); + stats->tx_packets += packets; + stats->tx_bytes += bytes; + } stats->rx_dropped = dev->stats.rx_dropped; stats->tx_dropped = dev->stats.tx_dropped; return stats; } +static int ifb_dev_init(struct net_device *dev) +{ + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp; + int i; + + txp = kcalloc(dev->num_tx_queues, sizeof(*txp), GFP_KERNEL); + if (!txp) + return -ENOMEM; + dp->tx_private = txp; + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + txp->txqnum = i; + txp->dev = dev; + __skb_queue_head_init(&txp->rq); + __skb_queue_head_init(&txp->tq); + u64_stats_init(&txp->rsync); + u64_stats_init(&txp->tsync); + tasklet_init(&txp->ifb_tasklet, ifb_ri_tasklet, + (unsigned long)txp); + netif_tx_start_queue(netdev_get_tx_queue(dev, i)); + } + return 0; +} static const struct net_device_ops ifb_netdev_ops = { .ndo_open = ifb_open, @@ -162,6 +191,7 @@ static const struct net_device_ops ifb_netdev_ops = { .ndo_get_stats64 = ifb_stats64, .ndo_start_xmit = ifb_xmit, .ndo_validate_addr = eth_validate_addr, + .ndo_init = ifb_dev_init, }; #define IFB_FEATURES (NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_FRAGLIST | \ @@ -169,10 +199,24 @@ static const struct net_device_ops ifb_netdev_ops = { NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_CTAG_TX | \ NETIF_F_HW_VLAN_STAG_TX) +static void ifb_dev_free(struct net_device *dev) +{ + struct ifb_dev_private *dp = netdev_priv(dev); + struct ifb_q_private *txp = dp->tx_private; + int i; + + for (i = 0; i < dev->num_tx_queues; i++,txp++) { + tasklet_kill(&txp->ifb_tasklet); + __skb_queue_purge(&txp->rq); + __skb_queue_purge(&txp->tq); + } + kfree(dp->tx_private); + free_netdev(dev); +} + static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->destructor = free_netdev; dev->netdev_ops = &ifb_netdev_ops; /* Fill in device structure with ethernet-generic values. */ @@ -188,17 +232,19 @@ static void ifb_setup(struct net_device *dev) dev->priv_flags &= ~IFF_TX_SKB_SHARING; netif_keep_dst(dev); eth_hw_addr_random(dev); + dev->destructor = ifb_dev_free; } static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ifb_private *dp = netdev_priv(dev); + struct ifb_dev_private *dp = netdev_priv(dev); u32 from = G_TC_FROM(skb->tc_verd); + struct ifb_q_private *txp = dp->tx_private + skb_get_queue_mapping(skb); - u64_stats_update_begin(&dp->rsync); - dp->rx_packets++; - dp->rx_bytes += skb->len; - u64_stats_update_end(&dp->rsync); + u64_stats_update_begin(&txp->rsync); + txp->rx_packets++; + txp->rx_bytes += skb->len; + u64_stats_update_end(&txp->rsync); if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) { dev_kfree_skb(skb); @@ -206,14 +252,13 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } - if (skb_queue_len(&dp->rq) >= dev->tx_queue_len) { - netif_stop_queue(dev); - } + if (skb_queue_len(&txp->rq) >= dev->tx_queue_len) + netif_tx_stop_queue(netdev_get_tx_queue(dev, txp->txqnum)); - __skb_queue_tail(&dp->rq, skb); - if (!dp->tasklet_pending) { - dp->tasklet_pending = 1; - tasklet_schedule(&dp->ifb_tasklet); + __skb_queue_tail(&txp->rq, skb); + if (!txp->tasklet_pending) { + txp->tasklet_pending = 1; + tasklet_schedule(&txp->ifb_tasklet); } return NETDEV_TX_OK; @@ -221,24 +266,13 @@ static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev) static int ifb_close(struct net_device *dev) { - struct ifb_private *dp = netdev_priv(dev); - - tasklet_kill(&dp->ifb_tasklet); - netif_stop_queue(dev); - __skb_queue_purge(&dp->rq); - __skb_queue_purge(&dp->tq); + netif_tx_stop_all_queues(dev); return 0; } static int ifb_open(struct net_device *dev) { - struct ifb_private *dp = netdev_priv(dev); - - tasklet_init(&dp->ifb_tasklet, ri_tasklet, (unsigned long)dev); - __skb_queue_head_init(&dp->rq); - __skb_queue_head_init(&dp->tq); - netif_start_queue(dev); - + netif_tx_start_all_queues(dev); return 0; } @@ -255,31 +289,30 @@ static int ifb_validate(struct nlattr *tb[], struct nlattr *data[]) static struct rtnl_link_ops ifb_link_ops __read_mostly = { .kind = "ifb", - .priv_size = sizeof(struct ifb_private), + .priv_size = sizeof(struct ifb_dev_private), .setup = ifb_setup, .validate = ifb_validate, }; -/* Number of ifb devices to be set up by this module. */ +/* Number of ifb devices to be set up by this module. + * Note that these legacy devices have one queue. + * Prefer something like : ip link add ifb10 numtxqueues 8 type ifb + */ +static int numifbs = 2; module_param(numifbs, int, 0); MODULE_PARM_DESC(numifbs, "Number of ifb devices"); static int __init ifb_init_one(int index) { struct net_device *dev_ifb; - struct ifb_private *dp; int err; - dev_ifb = alloc_netdev(sizeof(struct ifb_private), "ifb%d", + dev_ifb = alloc_netdev(sizeof(struct ifb_dev_private), "ifb%d", NET_NAME_UNKNOWN, ifb_setup); if (!dev_ifb) return -ENOMEM; - dp = netdev_priv(dev_ifb); - u64_stats_init(&dp->rsync); - u64_stats_init(&dp->tsync); - dev_ifb->rtnl_link_ops = &ifb_link_ops; err = register_netdevice(dev_ifb); if (err < 0) -- GitLab From f9cbce34c34bcc05ea0dd78c8999bfe88b5b6b86 Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 6 Jul 2015 14:11:37 -0700 Subject: [PATCH 0622/7006] hv_netvsc: Add support to set MTU reservation from guest side When packet encapsulation is in use, the MTU needs to be reduced for headroom reservation. The existing code takes the updated MTU value only from the host side. But vSwitch extensions, such as Open vSwitch, require the flexibility to change the MTU to different values from within a guest during the lifecycle of a vNIC, when the encapsulation protocol is changed. The patch supports this kind of MTU changes. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 1 + drivers/net/hyperv/netvsc_drv.c | 3 +-- drivers/net/hyperv/rndis_filter.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index dd4544085db32..26cd14ccf4d56 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -589,6 +589,7 @@ struct nvsp_message { #define NETVSC_MTU 65536 +#define NETVSC_MTU_MIN 68 #define NETVSC_RECEIVE_BUFFER_SIZE (1024*1024*16) /* 16MB */ #define NETVSC_RECEIVE_BUFFER_SIZE_LEGACY (1024*1024*15) /* 15MB */ diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 358475ed9b596..b855ba9a507d5 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -743,8 +743,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) if (nvdev->nvsp_version >= NVSP_PROTOCOL_VERSION_2) limit = NETVSC_MTU - ETH_HLEN; - /* Hyper-V hosts don't support MTU < ETH_DATA_LEN (1500) */ - if (mtu < ETH_DATA_LEN || mtu > limit) + if (mtu < NETVSC_MTU_MIN || mtu > limit) return -EINVAL; nvdev->start_remove = true; diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 236aeb76ef224..2e40417a80878 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -1054,7 +1054,7 @@ int rndis_filter_device_add(struct hv_device *dev, ret = rndis_filter_query_device(rndis_device, RNDIS_OID_GEN_MAXIMUM_FRAME_SIZE, &mtu, &size); - if (ret == 0 && size == sizeof(u32)) + if (ret == 0 && size == sizeof(u32) && mtu < net_device->ndev->mtu) net_device->ndev->mtu = mtu; /* Get the mac address */ -- GitLab From b11b6ed0f97f900f5c4bba9b3abcd2d2dab73ca7 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 7 Jul 2015 12:32:54 +0530 Subject: [PATCH 0623/7006] net: ec_bhf: Use module_pci_driver Use module_pci_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return pci_register_driver(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { pci_unregister_driver(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_pci_driver; @@ -module_exit(e); +module_pci_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: David S. Miller --- drivers/net/ethernet/ec_bhf.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/net/ethernet/ec_bhf.c b/drivers/net/ethernet/ec_bhf.c index d1017509b08ac..f7b42483921c5 100644 --- a/drivers/net/ethernet/ec_bhf.c +++ b/drivers/net/ethernet/ec_bhf.c @@ -604,19 +604,7 @@ static struct pci_driver pci_driver = { .probe = ec_bhf_probe, .remove = ec_bhf_remove, }; - -static int __init ec_bhf_init(void) -{ - return pci_register_driver(&pci_driver); -} - -static void __exit ec_bhf_exit(void) -{ - pci_unregister_driver(&pci_driver); -} - -module_init(ec_bhf_init); -module_exit(ec_bhf_exit); +module_pci_driver(pci_driver); module_param(polling_frequency, long, S_IRUGO); MODULE_PARM_DESC(polling_frequency, "Polling timer frequency in ns"); -- GitLab From 5be9ed8d49754c22fffd8ddd9cb751d591f31a08 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:18 +0530 Subject: [PATCH 0624/7006] cxgb4: Don't use entire L2T table, use only its slice The driver was retrieving the parameters for the bounds of its slice of the L2T from the firmware and then throwing those away and using the entire table. This corrects that problem. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/l2t.c | 94 +++++++++++-------- drivers/net/ethernet/chelsio/cxgb4/l2t.h | 18 +++- drivers/net/ethernet/chelsio/cxgb4/t4_hw.h | 1 - 4 files changed, 71 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 351f3b1bf8002..d582e175dfb61 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4757,7 +4757,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) */ cfg_queues(adapter); - adapter->l2t = t4_init_l2t(); + adapter->l2t = t4_init_l2t(adapter->l2t_start, adapter->l2t_end); if (!adapter->l2t) { /* We tolerate a lack of L2T, giving up some functionality */ dev_warn(&pdev->dev, "could not allocate L2T, continuing\n"); diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c index 252efc29321f4..ac27898c6ab0b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c @@ -51,24 +51,17 @@ #define VLAN_NONE 0xfff /* identifies sync vs async L2T_WRITE_REQs */ -#define F_SYNC_WR (1 << 12) - -enum { - L2T_STATE_VALID, /* entry is up to date */ - L2T_STATE_STALE, /* entry may be used but needs revalidation */ - L2T_STATE_RESOLVING, /* entry needs address resolution */ - L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ - - /* when state is one of the below the entry is not hashed */ - L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ - L2T_STATE_UNUSED /* entry not in use */ -}; +#define SYNC_WR_S 12 +#define SYNC_WR_V(x) ((x) << SYNC_WR_S) +#define SYNC_WR_F SYNC_WR_V(1) struct l2t_data { + unsigned int l2t_start; /* start index of our piece of the L2T */ + unsigned int l2t_size; /* number of entries in l2tab */ rwlock_t lock; atomic_t nfree; /* number of free entries */ struct l2t_entry *rover; /* starting point for next allocation */ - struct l2t_entry l2tab[L2T_SIZE]; + struct l2t_entry l2tab[0]; /* MUST BE LAST */ }; static inline unsigned int vlan_prio(const struct l2t_entry *e) @@ -85,29 +78,36 @@ static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e) /* * To avoid having to check address families we do not allow v4 and v6 * neighbors to be on the same hash chain. We keep v4 entries in the first - * half of available hash buckets and v6 in the second. + * half of available hash buckets and v6 in the second. We need at least two + * entries in our L2T for this scheme to work. */ enum { - L2T_SZ_HALF = L2T_SIZE / 2, - L2T_HASH_MASK = L2T_SZ_HALF - 1 + L2T_MIN_HASH_BUCKETS = 2, }; -static inline unsigned int arp_hash(const u32 *key, int ifindex) +static inline unsigned int arp_hash(struct l2t_data *d, const u32 *key, + int ifindex) { - return jhash_2words(*key, ifindex, 0) & L2T_HASH_MASK; + unsigned int l2t_size_half = d->l2t_size / 2; + + return jhash_2words(*key, ifindex, 0) % l2t_size_half; } -static inline unsigned int ipv6_hash(const u32 *key, int ifindex) +static inline unsigned int ipv6_hash(struct l2t_data *d, const u32 *key, + int ifindex) { + unsigned int l2t_size_half = d->l2t_size / 2; u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3]; - return L2T_SZ_HALF + (jhash_2words(xor, ifindex, 0) & L2T_HASH_MASK); + return (l2t_size_half + + (jhash_2words(xor, ifindex, 0) % l2t_size_half)); } -static unsigned int addr_hash(const u32 *addr, int addr_len, int ifindex) +static unsigned int addr_hash(struct l2t_data *d, const u32 *addr, + int addr_len, int ifindex) { - return addr_len == 4 ? arp_hash(addr, ifindex) : - ipv6_hash(addr, ifindex); + return addr_len == 4 ? arp_hash(d, addr, ifindex) : + ipv6_hash(d, addr, ifindex); } /* @@ -139,6 +139,8 @@ static void neigh_replace(struct l2t_entry *e, struct neighbour *n) */ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) { + struct l2t_data *d = adap->l2t; + unsigned int l2t_idx = e->idx + d->l2t_start; struct sk_buff *skb; struct cpl_l2t_write_req *req; @@ -150,10 +152,10 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync) INIT_TP_WR(req, 0); OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, - e->idx | (sync ? F_SYNC_WR : 0) | + l2t_idx | (sync ? SYNC_WR_F : 0) | TID_QID_V(adap->sge.fw_evtq.abs_id))); req->params = htons(L2T_W_PORT_V(e->lport) | L2T_W_NOREPLY_V(!sync)); - req->l2t_idx = htons(e->idx); + req->l2t_idx = htons(l2t_idx); req->vlan = htons(e->vlan); if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK)) memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac)); @@ -190,18 +192,19 @@ static void send_pending(struct adapter *adap, struct l2t_entry *e) */ void do_l2t_write_rpl(struct adapter *adap, const struct cpl_l2t_write_rpl *rpl) { + struct l2t_data *d = adap->l2t; unsigned int tid = GET_TID(rpl); - unsigned int idx = tid & (L2T_SIZE - 1); + unsigned int l2t_idx = tid % L2T_SIZE; if (unlikely(rpl->status != CPL_ERR_NONE)) { dev_err(adap->pdev_dev, "Unexpected L2T_WRITE_RPL status %u for entry %u\n", - rpl->status, idx); + rpl->status, l2t_idx); return; } - if (tid & F_SYNC_WR) { - struct l2t_entry *e = &adap->l2t->l2tab[idx]; + if (tid & SYNC_WR_F) { + struct l2t_entry *e = &d->l2tab[l2t_idx - d->l2t_start]; spin_lock(&e->lock); if (e->state != L2T_STATE_SWITCHING) { @@ -276,7 +279,7 @@ static struct l2t_entry *alloc_l2e(struct l2t_data *d) return NULL; /* there's definitely a free entry */ - for (e = d->rover, end = &d->l2tab[L2T_SIZE]; e != end; ++e) + for (e = d->rover, end = &d->l2tab[d->l2t_size]; e != end; ++e) if (atomic_read(&e->refcnt) == 0) goto found; @@ -368,7 +371,7 @@ struct l2t_entry *cxgb4_l2t_get(struct l2t_data *d, struct neighbour *neigh, int addr_len = neigh->tbl->key_len; u32 *addr = (u32 *)neigh->primary_key; int ifidx = neigh->dev->ifindex; - int hash = addr_hash(addr, addr_len, ifidx); + int hash = addr_hash(d, addr, addr_len, ifidx); if (neigh->dev->flags & IFF_LOOPBACK) lport = netdev2pinfo(physdev)->tx_chan + 4; @@ -481,7 +484,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh) int addr_len = neigh->tbl->key_len; u32 *addr = (u32 *) neigh->primary_key; int ifidx = neigh->dev->ifindex; - int hash = addr_hash(addr, addr_len, ifidx); + int hash = addr_hash(d, addr, addr_len, ifidx); read_lock_bh(&d->lock); for (e = d->l2tab[hash].first; e; e = e->next) @@ -554,20 +557,30 @@ int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan, return write_l2e(adap, e, 0); } -struct l2t_data *t4_init_l2t(void) +struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end) { + unsigned int l2t_size; int i; struct l2t_data *d; - d = t4_alloc_mem(sizeof(*d)); + if (l2t_start >= l2t_end || l2t_end >= L2T_SIZE) + return NULL; + l2t_size = l2t_end - l2t_start + 1; + if (l2t_size < L2T_MIN_HASH_BUCKETS) + return NULL; + + d = t4_alloc_mem(sizeof(*d) + l2t_size * sizeof(struct l2t_entry)); if (!d) return NULL; + d->l2t_start = l2t_start; + d->l2t_size = l2t_size; + d->rover = d->l2tab; - atomic_set(&d->nfree, L2T_SIZE); + atomic_set(&d->nfree, l2t_size); rwlock_init(&d->lock); - for (i = 0; i < L2T_SIZE; ++i) { + for (i = 0; i < d->l2t_size; ++i) { d->l2tab[i].idx = i; d->l2tab[i].state = L2T_STATE_UNUSED; spin_lock_init(&d->l2tab[i].lock); @@ -578,9 +591,9 @@ struct l2t_data *t4_init_l2t(void) static inline void *l2t_get_idx(struct seq_file *seq, loff_t pos) { - struct l2t_entry *l2tab = seq->private; + struct l2t_data *d = seq->private; - return pos >= L2T_SIZE ? NULL : &l2tab[pos]; + return pos >= d->l2t_size ? NULL : &d->l2tab[pos]; } static void *l2t_seq_start(struct seq_file *seq, loff_t *pos) @@ -620,6 +633,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v) "Ethernet address VLAN/P LP State Users Port\n"); else { char ip[60]; + struct l2t_data *d = seq->private; struct l2t_entry *e = v; spin_lock_bh(&e->lock); @@ -628,7 +642,7 @@ static int l2t_seq_show(struct seq_file *seq, void *v) else sprintf(ip, e->v6 ? "%pI6c" : "%pI4", e->addr); seq_printf(seq, "%4u %-25s %17pM %4d %u %2u %c %5u %s\n", - e->idx, ip, e->dmac, + e->idx + d->l2t_start, ip, e->dmac, e->vlan & VLAN_VID_MASK, vlan_prio(e), e->lport, l2e_state(e), atomic_read(&e->refcnt), e->neigh ? e->neigh->dev->name : ""); @@ -652,7 +666,7 @@ static int l2t_seq_open(struct inode *inode, struct file *file) struct adapter *adap = inode->i_private; struct seq_file *seq = file->private_data; - seq->private = adap->l2t->l2tab; + seq->private = adap->l2t; } return rc; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.h b/drivers/net/ethernet/chelsio/cxgb4/l2t.h index a30126ce90cba..b38dc526aad56 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/l2t.h +++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.h @@ -39,6 +39,20 @@ #include #include +enum { L2T_SIZE = 4096 }; /* # of L2T entries */ + +enum { + L2T_STATE_VALID, /* entry is up to date */ + L2T_STATE_STALE, /* entry may be used but needs revalidation */ + L2T_STATE_RESOLVING, /* entry needs address resolution */ + L2T_STATE_SYNC_WRITE, /* synchronous write of entry underway */ + L2T_STATE_NOARP, /* Netdev down or removed*/ + + /* when state is one of the below the entry is not hashed */ + L2T_STATE_SWITCHING, /* entry is being used by a switching filter */ + L2T_STATE_UNUSED /* entry not in use */ +}; + struct adapter; struct l2t_data; struct neighbour; @@ -56,7 +70,7 @@ struct cpl_l2t_write_rpl; */ struct l2t_entry { u16 state; /* entry state */ - u16 idx; /* entry index */ + u16 idx; /* entry index within in-memory table */ u32 addr[4]; /* next hop IP or IPv6 address */ int ifindex; /* neighbor's net_device's ifindex */ struct neighbour *neigh; /* associated neighbour */ @@ -104,7 +118,7 @@ void t4_l2t_update(struct adapter *adap, struct neighbour *neigh); struct l2t_entry *t4_l2t_alloc_switching(struct l2t_data *d); int t4_l2t_set_switching(struct adapter *adap, struct l2t_entry *e, u16 vlan, u8 port, u8 *eth_addr); -struct l2t_data *t4_init_l2t(void); +struct l2t_data *t4_init_l2t(unsigned int l2t_start, unsigned int l2t_end); void do_l2t_write_rpl(struct adapter *p, const struct cpl_l2t_write_rpl *rpl); extern const struct file_operations t4_l2t_fops; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h index c8488f430d197..640369df8b3a3 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h @@ -47,7 +47,6 @@ enum { TCB_SIZE = 128, /* TCB size */ NMTUS = 16, /* size of MTU table */ NCCTRL_WIN = 32, /* # of congestion control windows */ - L2T_SIZE = 4096, /* # of L2T entries */ PM_NSTATS = 5, /* # of PM stats */ MBOX_LEN = 64, /* mailbox size in bytes */ TRACE_LEN = 112, /* length of trace data and mask */ -- GitLab From 5b4e83e133c7e610fdb6063f64bd404fc0836fe0 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:19 +0530 Subject: [PATCH 0625/7006] cxgb4: Update register ranges for T6 adapter Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 2b52aae7ec86d..ba2be1e93ec3f 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -1345,9 +1345,9 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x5a80, 0x5a9c, 0x5b94, 0x5bfc, 0x5c10, 0x5ec0, - 0x5ec8, 0x5ec8, + 0x5ec8, 0x5ecc, 0x6000, 0x6040, - 0x6058, 0x6154, + 0x6058, 0x615c, 0x7700, 0x7798, 0x77c0, 0x7880, 0x78cc, 0x78fc, @@ -1371,20 +1371,22 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x9f00, 0x9f6c, 0x9f80, 0xa020, 0xd004, 0xd03c, + 0xd100, 0xd118, + 0xd200, 0xd31c, 0xdfc0, 0xdfe0, 0xe000, 0xf008, 0x11000, 0x11014, 0x11048, 0x11110, 0x11118, 0x1117c, - 0x11190, 0x11260, + 0x11190, 0x11264, 0x11300, 0x1130c, - 0x12000, 0x1205c, + 0x12000, 0x1206c, 0x19040, 0x1906c, 0x19078, 0x19080, 0x1908c, 0x19124, 0x19150, 0x191b0, 0x191d0, 0x191e8, - 0x19238, 0x192b8, + 0x19238, 0x192bc, 0x193f8, 0x19474, 0x19490, 0x194cc, 0x194f0, 0x194f8, @@ -1466,7 +1468,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x30200, 0x30318, 0x30400, 0x3052c, 0x30540, 0x3061c, - 0x30800, 0x3088c, + 0x30800, 0x30890, 0x308c0, 0x30908, 0x30910, 0x309b8, 0x30a00, 0x30a04, @@ -1544,7 +1546,7 @@ void t4_get_regs(struct adapter *adap, void *buf, size_t buf_size) 0x34200, 0x34318, 0x34400, 0x3452c, 0x34540, 0x3461c, - 0x34800, 0x3488c, + 0x34800, 0x34890, 0x348c0, 0x34908, 0x34910, 0x349b8, 0x34a00, 0x34a04, -- GitLab From df459ebc33324e6e2932b0236a7e1a53a14182b2 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:20 +0530 Subject: [PATCH 0626/7006] cxgb4: Read stats for only available channels Updating the driver to read the stats of only available channels. T6 and later has only 2 channels Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 73 ++++++++-------------- 1 file changed, 26 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index ba2be1e93ec3f..1e6597dc87365 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3926,43 +3926,25 @@ void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4, */ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) { - /* T6 and later has 2 channels */ - if (adap->params.arch.nchan == NCHAN) { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->mac_in_errs, 12, TP_MIB_MAC_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_cong_drops, 8, - TP_MIB_TNL_CNG_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_tx_drops, 4, - TP_MIB_TNL_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->ofld_vlan_drops, 4, - TP_MIB_OFD_VLN_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tcp6_in_errs, 4, - TP_MIB_TCP_V6IN_ERR_0_A); - } else { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->mac_in_errs, 2, TP_MIB_MAC_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->hdr_in_errs, 2, TP_MIB_HDR_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tcp_in_errs, 2, TP_MIB_TCP_IN_ERR_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_cong_drops, 2, - TP_MIB_TNL_CNG_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->ofld_chan_drops, 2, - TP_MIB_OFD_CHN_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tnl_tx_drops, 2, TP_MIB_TNL_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->ofld_vlan_drops, 2, - TP_MIB_OFD_VLN_DROP_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, - st->tcp6_in_errs, 2, TP_MIB_TCP_V6IN_ERR_0_A); - } + int nchan = adap->params.arch.nchan; + + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->mac_in_errs, nchan, TP_MIB_MAC_IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->hdr_in_errs, nchan, TP_MIB_HDR_IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tcp_in_errs, nchan, TP_MIB_TCP_IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tnl_cong_drops, nchan, TP_MIB_TNL_CNG_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->ofld_chan_drops, nchan, TP_MIB_OFD_CHN_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tnl_tx_drops, nchan, TP_MIB_TNL_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->ofld_vlan_drops, nchan, TP_MIB_OFD_VLN_DROP_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, + st->tcp6_in_errs, nchan, TP_MIB_TCP_V6IN_ERR_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, &st->ofld_no_neigh, 2, TP_MIB_OFD_ARP_DROP_A); } @@ -3976,16 +3958,13 @@ void t4_tp_get_err_stats(struct adapter *adap, struct tp_err_stats *st) */ void t4_tp_get_cpl_stats(struct adapter *adap, struct tp_cpl_stats *st) { - /* T6 and later has 2 channels */ - if (adap->params.arch.nchan == NCHAN) { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req, - 8, TP_MIB_CPL_IN_REQ_0_A); - } else { - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req, - 2, TP_MIB_CPL_IN_REQ_0_A); - t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp, - 2, TP_MIB_CPL_OUT_RSP_0_A); - } + int nchan = adap->params.arch.nchan; + + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->req, + nchan, TP_MIB_CPL_IN_REQ_0_A); + t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, st->rsp, + nchan, TP_MIB_CPL_OUT_RSP_0_A); + } /** -- GitLab From b7660642b77b6aa7fae6c0f832d0290af331bd7e Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 7 Jul 2015 21:49:21 +0530 Subject: [PATCH 0627/7006] cxgb4: Enable cim_la dump to support T6 Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- .../ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 54 +++++++++++++++++-- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index a11485fbb33f2..b135d05c9984c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -151,6 +151,45 @@ static int cim_la_show_3in1(struct seq_file *seq, void *v, int idx) return 0; } +static int cim_la_show_t6(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Status Inst Data PC LS0Stat " + "LS0Addr LS0Data LS1Stat LS1Addr LS1Data\n"); + } else { + const u32 *p = v; + + seq_printf(seq, " %02x %04x%04x %04x%04x %04x%04x %08x %08x %08x %08x %08x %08x\n", + (p[9] >> 16) & 0xff, /* Status */ + p[9] & 0xffff, p[8] >> 16, /* Inst */ + p[8] & 0xffff, p[7] >> 16, /* Data */ + p[7] & 0xffff, p[6] >> 16, /* PC */ + p[2], p[1], p[0], /* LS0 Stat, Addr and Data */ + p[5], p[4], p[3]); /* LS1 Stat, Addr and Data */ + } + return 0; +} + +static int cim_la_show_pc_t6(struct seq_file *seq, void *v, int idx) +{ + if (v == SEQ_START_TOKEN) { + seq_puts(seq, "Status Inst Data PC\n"); + } else { + const u32 *p = v; + + seq_printf(seq, " %02x %08x %08x %08x\n", + p[3] & 0xff, p[2], p[1], p[0]); + seq_printf(seq, " %02x %02x%06x %02x%06x %02x%06x\n", + (p[6] >> 8) & 0xff, p[6] & 0xff, p[5] >> 8, + p[5] & 0xff, p[4] >> 8, p[4] & 0xff, p[3] >> 8); + seq_printf(seq, " %02x %04x%04x %04x%04x %04x%04x\n", + (p[9] >> 16) & 0xff, p[9] & 0xffff, p[8] >> 16, + p[8] & 0xffff, p[7] >> 16, p[7] & 0xffff, + p[6] >> 16); + } + return 0; +} + static int cim_la_open(struct inode *inode, struct file *file) { int ret; @@ -162,9 +201,18 @@ static int cim_la_open(struct inode *inode, struct file *file) if (ret) return ret; - p = seq_open_tab(file, adap->params.cim_la_size / 8, 8 * sizeof(u32), 1, - cfg & UPDBGLACAPTPCONLY_F ? - cim_la_show_3in1 : cim_la_show); + if (is_t6(adap->params.chip)) { + /* +1 to account for integer division of CIMLA_SIZE/10 */ + p = seq_open_tab(file, (adap->params.cim_la_size / 10) + 1, + 10 * sizeof(u32), 1, + cfg & UPDBGLACAPTPCONLY_F ? + cim_la_show_pc_t6 : cim_la_show_t6); + } else { + p = seq_open_tab(file, adap->params.cim_la_size / 8, + 8 * sizeof(u32), 1, + cfg & UPDBGLACAPTPCONLY_F ? cim_la_show_3in1 : + cim_la_show); + } if (!p) return -ENOMEM; -- GitLab From ba29becd770ffec90f3af896daffac6b9acec608 Mon Sep 17 00:00:00 2001 From: Xi Wang Date: Wed, 8 Jul 2015 14:00:56 -0700 Subject: [PATCH 0628/7006] test_bpf: extend tests for 32-bit endianness conversion Currently "ALU_END_FROM_BE 32" and "ALU_END_FROM_LE 32" do not test if the upper bits of the result are zeros (the arm64 JIT had such bugs). Extend the two tests to catch this. Acked-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: Xi Wang Signed-off-by: David S. Miller --- lib/test_bpf.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 7f58c735d7450..9198f28a5528f 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -3674,6 +3674,9 @@ static struct bpf_test tests[] = { .u.insns_int = { BPF_LD_IMM64(R0, 0x0123456789abcdefLL), BPF_ENDIAN(BPF_FROM_BE, R0, 32), + BPF_ALU64_REG(BPF_MOV, R1, R0), + BPF_ALU64_IMM(BPF_RSH, R1, 32), + BPF_ALU32_REG(BPF_ADD, R0, R1), /* R1 = 0 */ BPF_EXIT_INSN(), }, INTERNAL, @@ -3708,6 +3711,9 @@ static struct bpf_test tests[] = { .u.insns_int = { BPF_LD_IMM64(R0, 0x0123456789abcdefLL), BPF_ENDIAN(BPF_FROM_LE, R0, 32), + BPF_ALU64_REG(BPF_MOV, R1, R0), + BPF_ALU64_IMM(BPF_RSH, R1, 32), + BPF_ALU32_REG(BPF_ADD, R0, R1), /* R1 = 0 */ BPF_EXIT_INSN(), }, INTERNAL, -- GitLab From 2d53809594afaf2ae66a90a3142c1b702fd3bcea Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 6 Jul 2015 15:57:44 -0700 Subject: [PATCH 0629/7006] Input: zforce_ts - convert to use the gpiod interface Use the new GPIO descriptor interface to handle the zForce GPIOs. This simplifies the code and allows transparently handle GPIO polarity, as specified in device tree data. Also switch to using gpio_{set|get}_value_cansleep() since none of the callers is in atomic context and cansleep variant allows more GPIO controllers to be used with the touchscreen. Signed-off-by: Dirk Behme Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 58 +++++++++++++------------ include/linux/platform_data/zforce_ts.h | 3 -- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index f58a196521a9a..c4cffcfb03d38 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -24,14 +24,13 @@ #include #include #include -#include +#include #include #include #include #include #include #include -#include #define WAIT_TIMEOUT msecs_to_jiffies(1000) @@ -120,6 +119,9 @@ struct zforce_ts { struct regulator *reg_vdd; + struct gpio_desc *gpio_int; + struct gpio_desc *gpio_rst; + bool suspending; bool suspended; bool boot_complete; @@ -161,6 +163,16 @@ static int zforce_command(struct zforce_ts *ts, u8 cmd) return 0; } +static void zforce_reset_assert(struct zforce_ts *ts) +{ + gpiod_set_value_cansleep(ts->gpio_rst, 1); +} + +static void zforce_reset_deassert(struct zforce_ts *ts) +{ + gpiod_set_value_cansleep(ts->gpio_rst, 0); +} + static int zforce_send_wait(struct zforce_ts *ts, const char *buf, int len) { struct i2c_client *client = ts->client; @@ -479,7 +491,6 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) { struct zforce_ts *ts = dev_id; struct i2c_client *client = ts->client; - const struct zforce_ts_platdata *pdata = ts->pdata; int ret; u8 payload_buffer[FRAME_MAXSIZE]; u8 *payload; @@ -499,7 +510,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) if (!ts->suspending && device_may_wakeup(&client->dev)) pm_stay_awake(&client->dev); - while (!gpio_get_value(pdata->gpio_int)) { + while (!gpiod_get_value_cansleep(ts->gpio_int)) { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { dev_err(&client->dev, @@ -690,7 +701,7 @@ static void zforce_reset(void *data) { struct zforce_ts *ts = data; - gpio_set_value(ts->pdata->gpio_rst, 0); + zforce_reset_assert(ts); udelay(10); @@ -712,18 +723,6 @@ static struct zforce_ts_platdata *zforce_parse_dt(struct device *dev) return ERR_PTR(-ENOMEM); } - pdata->gpio_int = of_get_gpio(np, 0); - if (!gpio_is_valid(pdata->gpio_int)) { - dev_err(dev, "failed to get interrupt gpio\n"); - return ERR_PTR(-EINVAL); - } - - pdata->gpio_rst = of_get_gpio(np, 1); - if (!gpio_is_valid(pdata->gpio_rst)) { - dev_err(dev, "failed to get reset gpio\n"); - return ERR_PTR(-EINVAL); - } - if (of_property_read_u32(np, "x-size", &pdata->x_max)) { dev_err(dev, "failed to get x-size property\n"); return ERR_PTR(-EINVAL); @@ -755,19 +754,22 @@ static int zforce_probe(struct i2c_client *client, if (!ts) return -ENOMEM; - ret = devm_gpio_request_one(&client->dev, pdata->gpio_int, GPIOF_IN, - "zforce_ts_int"); - if (ret) { - dev_err(&client->dev, "request of gpio %d failed, %d\n", - pdata->gpio_int, ret); + /* INT GPIO */ + ts->gpio_int = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN); + if (IS_ERR(ts->gpio_int)) { + ret = PTR_ERR(ts->gpio_int); + dev_err(&client->dev, + "failed to request interrupt GPIO: %d\n", ret); return ret; } - ret = devm_gpio_request_one(&client->dev, pdata->gpio_rst, - GPIOF_OUT_INIT_LOW, "zforce_ts_rst"); - if (ret) { - dev_err(&client->dev, "request of gpio %d failed, %d\n", - pdata->gpio_rst, ret); + /* RST GPIO */ + ts->gpio_rst = devm_gpiod_get_index(&client->dev, NULL, 1, + GPIOD_OUT_HIGH); + if (IS_ERR(ts->gpio_rst)) { + ret = PTR_ERR(ts->gpio_rst); + dev_err(&client->dev, + "failed to request reset GPIO: %d\n", ret); return ret; } @@ -863,7 +865,7 @@ static int zforce_probe(struct i2c_client *client, i2c_set_clientdata(client, ts); /* let the controller boot */ - gpio_set_value(pdata->gpio_rst, 1); + zforce_reset_deassert(ts); ts->command_waiting = NOTIFICATION_BOOTCOMPLETE; if (wait_for_completion_timeout(&ts->command_done, WAIT_TIMEOUT) == 0) diff --git a/include/linux/platform_data/zforce_ts.h b/include/linux/platform_data/zforce_ts.h index 0472ab2f6ede1..7bdece8ef33ea 100644 --- a/include/linux/platform_data/zforce_ts.h +++ b/include/linux/platform_data/zforce_ts.h @@ -16,9 +16,6 @@ #define _LINUX_INPUT_ZFORCE_TS_H struct zforce_ts_platdata { - int gpio_int; - int gpio_rst; - unsigned int x_max; unsigned int y_max; }; -- GitLab From ec0843fabe29ad44bdaaa16c8d6cda4537716de5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 8 Jul 2015 08:25:50 -0700 Subject: [PATCH 0630/7006] Input: drv260x/drv2665/drv2667 - constify reg_default tables These reg_default tables are not modified after initialized, so make them const. Signed-off-by: Axel Lin Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 2 +- drivers/input/misc/drv2665.c | 2 +- drivers/input/misc/drv2667.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index e5d60ecd29a4d..0e3af55d9e257 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -204,7 +204,7 @@ struct drv260x_data { int overdrive_voltage; }; -static struct reg_default drv260x_reg_defs[] = { +static const struct reg_default drv260x_reg_defs[] = { { DRV260X_STATUS, 0xe0 }, { DRV260X_MODE, 0x40 }, { DRV260X_RT_PB_IN, 0x00 }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 0afaa33de07d2..e9501fdca5ef6 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -74,7 +74,7 @@ static const u8 drv2665_sine_wave_form[] = { 0x9b, 0x9f, 0xa5, 0xad, 0xb8, 0xc4, 0xd2, 0xe0, 0xf0, 0x00, }; -static struct reg_default drv2665_reg_defs[] = { +static const struct reg_default drv2665_reg_defs[] = { { DRV2665_STATUS, 0x02 }, { DRV2665_CTRL_1, 0x28 }, { DRV2665_CTRL_2, 0x40 }, diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index fc0fddf0896a7..a231342207f9c 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -116,7 +116,7 @@ struct drv2667_data { u32 frequency; }; -static struct reg_default drv2667_reg_defs[] = { +static const struct reg_default drv2667_reg_defs[] = { { DRV2667_STATUS, 0x02 }, { DRV2667_CTRL_1, 0x28 }, { DRV2667_CTRL_2, 0x40 }, -- GitLab From f23487cdbe3bd002e99f41250143014e522c34de Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Wed, 8 Jul 2015 16:41:39 -0700 Subject: [PATCH 0631/7006] Input: joydev - use for_each_set_bit where appropriate Use for_each_set_bit to check for set bits in bitmap as it is more efficient than checking individual bits. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f362883c94e37..46862602a5f7d 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -798,12 +798,11 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, joydev->handle.handler = handler; joydev->handle.private = joydev; - for (i = 0; i < ABS_CNT; i++) - if (test_bit(i, dev->absbit)) { - joydev->absmap[i] = joydev->nabs; - joydev->abspam[joydev->nabs] = i; - joydev->nabs++; - } + for_each_set_bit(i, dev->absbit, ABS_CNT) { + joydev->absmap[i] = joydev->nabs; + joydev->abspam[joydev->nabs] = i; + joydev->nabs++; + } for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) if (test_bit(i + BTN_MISC, dev->keybit)) { -- GitLab From 948cea14487af7d6e8b8007dc24a5361869f410b Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Wed, 8 Jul 2015 16:43:20 -0700 Subject: [PATCH 0632/7006] Input: ff-core - use for_each_set_bit where appropriate Use for_each_set_bit to check for set bits in bitmap as it is more efficient than checking individual bits. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/ff-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/input/ff-core.c b/drivers/input/ff-core.c index 8f4a30fccbb67..c642082671987 100644 --- a/drivers/input/ff-core.c +++ b/drivers/input/ff-core.c @@ -343,9 +343,8 @@ int input_ff_create(struct input_dev *dev, unsigned int max_effects) __set_bit(EV_FF, dev->evbit); /* Copy "true" bits into ff device bitmap */ - for (i = 0; i <= FF_MAX; i++) - if (test_bit(i, dev->ffbit)) - __set_bit(i, ff->ffbit); + for_each_set_bit(i, dev->ffbit, FF_CNT) + __set_bit(i, ff->ffbit); /* we can emulate RUMBLE with periodic effects */ if (test_bit(FF_PERIODIC, ff->ffbit)) -- GitLab From 71d3c0b49a72fd092b7490b923d1721ceced8170 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 9 Jul 2015 14:55:46 +0530 Subject: [PATCH 0633/7006] cxgb4vf: Fix check to use new User Doorbell mechanism If we don't have access to the new User GTS (T5+), use the old doorbell mechanism; otherwise use the new BAR2 mechanism. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index ad53e5ad2acd0..1d5e77a566e16 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -1898,7 +1898,10 @@ static int napi_rx_handler(struct napi_struct *napi, int budget) rspq->unhandled_irqs++; val = CIDXINC_V(work_done) | SEINTARM_V(intr_params); - if (is_t4(rspq->adapter->params.chip)) { + /* If we don't have access to the new User GTS (T5+), use the old + * doorbell mechanism; otherwise use the new BAR2 mechanism. + */ + if (unlikely(!rspq->bar2_addr)) { t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, val | INGRESSQID_V((u32)rspq->cntxt_id)); @@ -1998,10 +2001,13 @@ static unsigned int process_intrq(struct adapter *adapter) } val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params); - if (is_t4(adapter->params.chip)) + /* If we don't have access to the new User GTS (T5+), use the old + * doorbell mechanism; otherwise use the new BAR2 mechanism. + */ + if (unlikely(!intrq->bar2_addr)) { t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS, val | INGRESSQID_V(intrq->cntxt_id)); - else { + } else { writel(val | INGRESSQID_V(intrq->bar2_qid), intrq->bar2_addr + SGE_UDB_GTS); wmb(); -- GitLab From 910be1abbec9cac102fde8ab6dd68a9b410ca441 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 9 Jul 2015 10:25:39 +0530 Subject: [PATCH 0634/7006] neterion: s2io: Use module_pci_driver Use module_pci_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return pci_register_driver(&x); } @b depends on a@ identifier e, a.x; statement S; @@ -static e(...) { -pci_unregister_driver(&x); -DBG_PRINT(INIT_DBG,"S"); - } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_pci_driver; @@ -module_exit(e); +module_pci_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: David S. Miller --- drivers/net/ethernet/neterion/s2io.c | 26 +------------------------- drivers/net/ethernet/neterion/s2io.h | 2 -- 2 files changed, 1 insertion(+), 27 deletions(-) diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c index c28111749e1f9..2d1b942740798 100644 --- a/drivers/net/ethernet/neterion/s2io.c +++ b/drivers/net/ethernet/neterion/s2io.c @@ -8226,31 +8226,7 @@ static void s2io_rem_nic(struct pci_dev *pdev) pci_disable_device(pdev); } -/** - * s2io_starter - Entry point for the driver - * Description: This function is the entry point for the driver. It verifies - * the module loadable parameters and initializes PCI configuration space. - */ - -static int __init s2io_starter(void) -{ - return pci_register_driver(&s2io_driver); -} - -/** - * s2io_closer - Cleanup routine for the driver - * Description: This function is the cleanup routine for the driver. It - * unregisters the driver. - */ - -static __exit void s2io_closer(void) -{ - pci_unregister_driver(&s2io_driver); - DBG_PRINT(INIT_DBG, "cleanup done\n"); -} - -module_init(s2io_starter); -module_exit(s2io_closer); +module_pci_driver(s2io_driver); static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip, struct tcphdr **tcp, struct RxD_t *rxdp, diff --git a/drivers/net/ethernet/neterion/s2io.h b/drivers/net/ethernet/neterion/s2io.h index d89b6ed82c51a..6c5997dc8afc0 100644 --- a/drivers/net/ethernet/neterion/s2io.h +++ b/drivers/net/ethernet/neterion/s2io.h @@ -1085,8 +1085,6 @@ static void s2io_txpic_intr_handle(struct s2io_nic *sp); static void tx_intr_handler(struct fifo_info *fifo_data); static void s2io_handle_errors(void * dev_id); -static int s2io_starter(void); -static void s2io_closer(void); static void s2io_tx_watchdog(struct net_device *dev); static void s2io_set_multicast(struct net_device *dev); static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp); -- GitLab From 77a58c741df1b91258cc4df3e6893ff61e8293a4 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Wed, 8 Jul 2015 16:06:47 -0700 Subject: [PATCH 0635/7006] rocker: add change MTU support Implement ndo_change_mtu: on MTU change, reallocate Rx ring bufs and signal HW of new port MTU value. Signed-off-by: Scott Feldman Reviewed-by: Simon Horman Tested-by: Simon Horman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 61 ++++++++++++++++++++++++++++ drivers/net/ethernet/rocker/rocker.h | 1 + 2 files changed, 62 insertions(+) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 2d8578cade037..c0051673c9fad 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -1817,6 +1817,30 @@ rocker_cmd_set_port_settings_macaddr_prep(const struct rocker_port *rocker_port, return 0; } +static int +rocker_cmd_set_port_settings_mtu_prep(const struct rocker_port *rocker_port, + struct rocker_desc_info *desc_info, + void *priv) +{ + int mtu = *(int *)priv; + struct rocker_tlv *cmd_info; + + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, + ROCKER_TLV_CMD_TYPE_SET_PORT_SETTINGS)) + return -EMSGSIZE; + cmd_info = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO); + if (!cmd_info) + return -EMSGSIZE; + if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_PPORT, + rocker_port->pport)) + return -EMSGSIZE; + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_PORT_SETTINGS_MTU, + mtu)) + return -EMSGSIZE; + rocker_tlv_nest_end(desc_info, cmd_info); + return 0; +} + static int rocker_cmd_set_port_learning_prep(const struct rocker_port *rocker_port, struct rocker_desc_info *desc_info, @@ -1874,6 +1898,14 @@ static int rocker_cmd_set_port_settings_macaddr(struct rocker_port *rocker_port, macaddr, NULL, NULL); } +static int rocker_cmd_set_port_settings_mtu(struct rocker_port *rocker_port, + int mtu) +{ + return rocker_cmd_exec(rocker_port, SWITCHDEV_TRANS_NONE, 0, + rocker_cmd_set_port_settings_mtu_prep, + &mtu, NULL, NULL); +} + static int rocker_port_set_learning(struct rocker_port *rocker_port, enum switchdev_trans trans) { @@ -4152,6 +4184,34 @@ static int rocker_port_set_mac_address(struct net_device *dev, void *p) return 0; } +static int rocker_port_change_mtu(struct net_device *dev, int new_mtu) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + int running = netif_running(dev); + int err; + +#define ROCKER_PORT_MIN_MTU 68 +#define ROCKER_PORT_MAX_MTU 9000 + + if (new_mtu < ROCKER_PORT_MIN_MTU || new_mtu > ROCKER_PORT_MAX_MTU) + return -EINVAL; + + if (running) + rocker_port_stop(dev); + + netdev_info(dev, "MTU change from %d to %d\n", dev->mtu, new_mtu); + dev->mtu = new_mtu; + + err = rocker_cmd_set_port_settings_mtu(rocker_port, new_mtu); + if (err) + return err; + + if (running) + err = rocker_port_open(dev); + + return err; +} + static int rocker_port_get_phys_port_name(struct net_device *dev, char *buf, size_t len) { @@ -4172,6 +4232,7 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_stop = rocker_port_stop, .ndo_start_xmit = rocker_port_xmit, .ndo_set_mac_address = rocker_port_set_mac_address, + .ndo_change_mtu = rocker_port_change_mtu, .ndo_bridge_getlink = switchdev_port_bridge_getlink, .ndo_bridge_setlink = switchdev_port_bridge_setlink, .ndo_bridge_dellink = switchdev_port_bridge_dellink, diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index c61fbf968036a..08b2c3d961887 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -159,6 +159,7 @@ enum { ROCKER_TLV_CMD_PORT_SETTINGS_MODE, /* u8 */ ROCKER_TLV_CMD_PORT_SETTINGS_LEARNING, /* u8 */ ROCKER_TLV_CMD_PORT_SETTINGS_PHYS_NAME, /* binary */ + ROCKER_TLV_CMD_PORT_SETTINGS_MTU, /* u16 */ __ROCKER_TLV_CMD_PORT_SETTINGS_MAX, ROCKER_TLV_CMD_PORT_SETTINGS_MAX = -- GitLab From 5ed68f0a28f96c5127246d1743dd57b58a090f07 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Thu, 9 Jul 2015 11:28:46 +0100 Subject: [PATCH 0636/7006] ASoC: arizona: Use the more idiomatic params_width Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/arizona.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index a88202d768f45..c246fbd708817 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1504,7 +1504,7 @@ static int arizona_hw_params(struct snd_pcm_substream *substream, else rates = &arizona_48k_bclk_rates[0]; - wl = snd_pcm_format_width(params_format(params)); + wl = params_width(params); if (tdm_slots) { arizona_aif_dbg(dai, "Configuring for %d %d bit TDM slots\n", -- GitLab From a40e693c7f5ee3a1a7d1f6aef63c5dadbec64e10 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:08 +0530 Subject: [PATCH 0637/7006] ASoC: Intel: Add Skylake HDA platform driver This patch starts to add the Skylake HDA platform driver by defining SoC CPU dais, DMA driver ops and implements ALSA operations Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 586 ++++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl.h | 71 ++++ 2 files changed, 657 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-pcm.c create mode 100644 sound/soc/intel/skylake/skl.h diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c new file mode 100644 index 0000000000000..c171def2fcc9c --- /dev/null +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -0,0 +1,586 @@ +/* + * skl-pcm.c -ASoC HDA Platform driver file implementing PCM functionality + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Jeeja KP + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#include +#include +#include +#include +#include "skl.h" + +#define HDA_MONO 1 +#define HDA_STEREO 2 + +static struct snd_pcm_hardware azx_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_HAS_WALL_CLOCK | /* legacy */ + SNDRV_PCM_INFO_HAS_LINK_ATIME | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = AZX_MAX_BUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = AZX_MAX_BUF_SIZE / 2, + .periods_min = 2, + .periods_max = AZX_MAX_FRAG, + .fifo_size = 0, +}; + +static inline +struct hdac_ext_stream *get_hdac_ext_stream(struct snd_pcm_substream *substream) +{ + return substream->runtime->private_data; +} + +static struct hdac_ext_bus *get_bus_ctx(struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + struct hdac_stream *hstream = hdac_stream(stream); + struct hdac_bus *bus = hstream->bus; + + return hbus_to_ebus(bus); +} + +static int skl_substream_alloc_pages(struct hdac_ext_bus *ebus, + struct snd_pcm_substream *substream, + size_t size) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + + hdac_stream(stream)->bufsize = 0; + hdac_stream(stream)->period_bytes = 0; + hdac_stream(stream)->format_val = 0; + + return snd_pcm_lib_malloc_pages(substream, size); +} + +static int skl_substream_free_pages(struct hdac_bus *bus, + struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, + struct snd_pcm_runtime *runtime) +{ + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + + /* avoid wrap-around with wall-clock */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, + 20, 178000000); +} + +static int skl_pcm_open(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *stream; + struct snd_pcm_runtime *runtime = substream->runtime; + struct skl_dma_params *dma_params; + int ret; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + ret = pm_runtime_get_sync(dai->dev); + if (ret) + return ret; + + stream = snd_hdac_ext_stream_assign(ebus, substream, + HDAC_EXT_STREAM_TYPE_COUPLED); + if (stream == NULL) + return -EBUSY; + + skl_set_pcm_constrains(ebus, runtime); + + /* + * disable WALLCLOCK timestamps for capture streams + * until we figure out how to handle digital inputs + */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; /* legacy */ + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_LINK_ATIME; + } + + runtime->private_data = stream; + + dma_params = kzalloc(sizeof(*dma_params), GFP_KERNEL); + if (!dma_params) + return -ENOMEM; + + dma_params->stream_tag = hdac_stream(stream)->stream_tag; + snd_soc_dai_set_dma_data(dai, substream, dma_params); + + dev_dbg(dai->dev, "stream tag set in dma params=%d\n", + dma_params->stream_tag); + snd_pcm_set_sync(substream); + + return 0; +} + +static int skl_get_format(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct skl_dma_params *dma_params; + int format_val = 0; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + format_val = dma_params->format; + + return format_val; +} + +static int skl_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + unsigned int format_val; + int err; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + if (hdac_stream(stream)->prepared) { + dev_dbg(dai->dev, "already stream is prepared - returning\n"); + return 0; + } + + format_val = skl_get_format(substream, dai); + dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d\n", + hdac_stream(stream)->stream_tag, format_val); + snd_hdac_stream_reset(hdac_stream(stream)); + + err = snd_hdac_stream_set_params(hdac_stream(stream), format_val); + if (err < 0) + return err; + + err = snd_hdac_stream_setup(hdac_stream(stream)); + if (err < 0) + return err; + + hdac_stream(stream)->prepared = 1; + + return err; +} + +static int skl_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + int ret; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + ret = skl_substream_alloc_pages(ebus, substream, + params_buffer_bytes(params)); + if (ret < 0) + return ret; + + dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + + return 0; +} + +static void skl_pcm_close(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + struct skl_dma_params *dma_params = NULL; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_COUPLED); + + dma_params = snd_soc_dai_get_dma_data(dai, substream); + /* + * now we should set this to NULL as we are freeing by the + * dma_params + */ + snd_soc_dai_set_dma_data(dai, substream, NULL); + + pm_runtime_mark_last_busy(dai->dev); + pm_runtime_put_autosuspend(dai->dev); + kfree(dma_params); +} + +static int skl_pcm_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + snd_hdac_stream_cleanup(hdac_stream(stream)); + hdac_stream(stream)->prepared = 0; + + return skl_substream_free_pages(ebus_to_hbus(ebus), substream); +} + +static struct snd_soc_dai_ops skl_pcm_dai_ops = { + .startup = skl_pcm_open, + .shutdown = skl_pcm_close, + .prepare = skl_pcm_prepare, + .hw_params = skl_pcm_hw_params, + .hw_free = skl_pcm_hw_free, +}; + +static struct snd_soc_dai_driver skl_platform_dai[] = { +{ + .name = "System Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "System Playback", + .channels_min = HDA_MONO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_8000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, + .capture = { + .stream_name = "System Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "Deepbuffer Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "Deepbuffer Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "LowLatency Pin", + .ops = &skl_pcm_dai_ops, + .playback = { + .stream_name = "Low Latency Playback", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +}; + +static int skl_platform_open(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai_link *dai_link = rtd->dai_link; + + dev_dbg(rtd->cpu_dai->dev, "In %s:%s\n", __func__, + dai_link->cpu_dai_name); + + runtime = substream->runtime; + snd_soc_set_runtime_hwparams(substream, &azx_pcm_hw); + + return 0; +} + +static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_ext_stream *stream; + struct snd_pcm_substream *s; + bool start; + int sbits = 0; + unsigned long cookie; + struct hdac_stream *hstr; + + stream = get_hdac_ext_stream(substream); + hstr = hdac_stream(stream); + + dev_dbg(bus->dev, "In %s cmd=%d\n", __func__, cmd); + + if (!hstr->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = true; + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = false; + break; + + default: + return -EINVAL; + } + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + stream = get_hdac_ext_stream(s); + sbits |= 1 << hdac_stream(stream)->index; + snd_pcm_trigger_done(s, substream); + } + + spin_lock_irqsave(&bus->reg_lock, cookie); + + /* first, set SYNC bits of corresponding streams */ + snd_hdac_stream_sync_trigger(hstr, true, sbits, AZX_REG_SSYNC); + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + stream = get_hdac_ext_stream(s); + if (start) + snd_hdac_stream_start(hdac_stream(stream), true); + else + snd_hdac_stream_stop(hdac_stream(stream)); + } + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + snd_hdac_stream_sync(hstr, start, sbits); + + spin_lock_irqsave(&bus->reg_lock, cookie); + + /* reset SYNC bits */ + snd_hdac_stream_sync_trigger(hstr, false, sbits, AZX_REG_SSYNC); + if (start) + snd_hdac_stream_timecounter_init(hstr, sbits); + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + return 0; +} + +/* calculate runtime delay from LPIB */ +static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, + struct hdac_ext_stream *sstream, + unsigned int pos) +{ + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct hdac_stream *hstream = hdac_stream(sstream); + struct snd_pcm_substream *substream = hstream->substream; + int stream = substream->stream; + unsigned int lpib_pos = snd_hdac_stream_get_pos_lpib(hstream); + int delay; + + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = pos - lpib_pos; + else + delay = lpib_pos - pos; + + if (delay < 0) { + if (delay >= hstream->delay_negative_threshold) + delay = 0; + else + delay += hstream->bufsize; + } + + if (delay >= hstream->period_bytes) { + dev_info(bus->dev, + "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", + delay, hstream->period_bytes); + delay = 0; + } + + return bytes_to_frames(substream->runtime, delay); +} + +static unsigned int skl_get_position(struct hdac_ext_stream *hstream, + int codec_delay) +{ + struct hdac_stream *hstr = hdac_stream(hstream); + struct snd_pcm_substream *substream = hstr->substream; + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + unsigned int pos; + int delay; + + /* use the position buffer as default */ + pos = snd_hdac_stream_get_pos_posbuf(hdac_stream(hstream)); + + if (pos >= hdac_stream(hstream)->bufsize) + pos = 0; + + if (substream->runtime) { + delay = skl_get_delay_from_lpib(ebus, hstream, pos) + + codec_delay; + substream->runtime->delay += delay; + } + + return pos; +} + +static snd_pcm_uframes_t skl_platform_pcm_pointer + (struct snd_pcm_substream *substream) +{ + struct hdac_ext_stream *hstream = get_hdac_ext_stream(substream); + + return bytes_to_frames(substream->runtime, + skl_get_position(hstream, 0)); +} + +static u64 skl_adjust_codec_delay(struct snd_pcm_substream *substream, + u64 nsec) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *codec_dai = rtd->codec_dai; + u64 codec_frames, codec_nsecs; + + if (!codec_dai->driver->ops->delay) + return nsec; + + codec_frames = codec_dai->driver->ops->delay(substream, codec_dai); + codec_nsecs = div_u64(codec_frames * 1000000000LL, + substream->runtime->rate); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + return nsec + codec_nsecs; + + return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; +} + +static int skl_get_time_info(struct snd_pcm_substream *substream, + struct timespec *system_ts, struct timespec *audio_ts, + struct snd_pcm_audio_tstamp_config *audio_tstamp_config, + struct snd_pcm_audio_tstamp_report *audio_tstamp_report) +{ + struct hdac_ext_stream *sstream = get_hdac_ext_stream(substream); + struct hdac_stream *hstr = hdac_stream(sstream); + u64 nsec; + + if ((substream->runtime->hw.info & SNDRV_PCM_INFO_HAS_LINK_ATIME) && + (audio_tstamp_config->type_requested == SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK)) { + + snd_pcm_gettime(substream->runtime, system_ts); + + nsec = timecounter_read(&hstr->tc); + nsec = div_u64(nsec, 3); /* can be optimized */ + if (audio_tstamp_config->report_delay) + nsec = skl_adjust_codec_delay(substream, nsec); + + *audio_ts = ns_to_timespec(nsec); + + audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK; + audio_tstamp_report->accuracy_report = 1; /* rest of struct is valid */ + audio_tstamp_report->accuracy = 42; /* 24MHzWallClk == 42ns resolution */ + + } else { + audio_tstamp_report->actual_type = SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT; + } + + return 0; +} + +static struct snd_pcm_ops skl_platform_ops = { + .open = skl_platform_open, + .ioctl = snd_pcm_lib_ioctl, + .trigger = skl_platform_pcm_trigger, + .pointer = skl_platform_pcm_pointer, + .get_time_info = skl_get_time_info, + .mmap = snd_pcm_lib_default_mmap, + .page = snd_pcm_sgbuf_ops_page, +}; + +static void skl_pcm_free(struct snd_pcm *pcm) +{ + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) + +static int skl_pcm_new(struct snd_soc_pcm_runtime *rtd) +{ + struct snd_soc_dai *dai = rtd->cpu_dai; + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_pcm *pcm = rtd->pcm; + unsigned int size; + int retval = 0; + struct skl *skl = ebus_to_skl(ebus); + + if (dai->driver->playback.channels_min || + dai->driver->capture.channels_min) { + /* buffer pre-allocation */ + size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; + if (size > MAX_PREALLOC_SIZE) + size = MAX_PREALLOC_SIZE; + retval = snd_pcm_lib_preallocate_pages_for_all(pcm, + SNDRV_DMA_TYPE_DEV_SG, + snd_dma_pci_data(skl->pci), + size, MAX_PREALLOC_SIZE); + if (retval) { + dev_err(dai->dev, "dma buffer allocationf fail\n"); + return retval; + } + } + + return retval; +} + +static struct snd_soc_platform_driver skl_platform_drv = { + .ops = &skl_platform_ops, + .pcm_new = skl_pcm_new, + .pcm_free = skl_pcm_free, +}; + +static const struct snd_soc_component_driver skl_component = { + .name = "pcm", +}; + +int skl_platform_register(struct device *dev) +{ + int ret; + + ret = snd_soc_register_platform(dev, &skl_platform_drv); + if (ret) { + dev_err(dev, "soc platform registration failed %d\n", ret); + return ret; + } + ret = snd_soc_register_component(dev, &skl_component, + skl_platform_dai, + ARRAY_SIZE(skl_platform_dai)); + if (ret) { + dev_err(dev, "soc component registration failed %d\n", ret); + snd_soc_unregister_platform(dev); + } + + return ret; + +} + +int skl_platform_unregister(struct device *dev) +{ + snd_soc_unregister_component(dev); + snd_soc_unregister_platform(dev); + return 0; +} diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h new file mode 100644 index 0000000000000..cc0f3e263495f --- /dev/null +++ b/sound/soc/intel/skylake/skl.h @@ -0,0 +1,71 @@ +/* + * skl.h - HD Audio skylake defintions. + * + * Copyright (C) 2015 Intel Corp + * Author: Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ + +#ifndef __SOUND_SOC_SKL_H +#define __SOUND_SOC_SKL_H + +#include +#include + +#define SKL_SUSPEND_DELAY 2000 + +/* Vendor Specific Registers */ +#define AZX_REG_VS_EM1 0x1000 +#define AZX_REG_VS_INRC 0x1004 +#define AZX_REG_VS_OUTRC 0x1008 +#define AZX_REG_VS_FIFOTRK 0x100C +#define AZX_REG_VS_FIFOTRK2 0x1010 +#define AZX_REG_VS_EM2 0x1030 +#define AZX_REG_VS_EM3L 0x1038 +#define AZX_REG_VS_EM3U 0x103C +#define AZX_REG_VS_EM4L 0x1040 +#define AZX_REG_VS_EM4U 0x1044 +#define AZX_REG_VS_LTRC 0x1048 +#define AZX_REG_VS_D0I3C 0x104A +#define AZX_REG_VS_PCE 0x104B +#define AZX_REG_VS_L2MAGC 0x1050 +#define AZX_REG_VS_L2LAHPT 0x1054 +#define AZX_REG_VS_SDXDPIB_XBASE 0x1084 +#define AZX_REG_VS_SDXDPIB_XINTERVAL 0x20 +#define AZX_REG_VS_SDXEFIFOS_XBASE 0x1094 +#define AZX_REG_VS_SDXEFIFOS_XINTERVAL 0x20 + +struct skl { + struct hdac_ext_bus ebus; + struct pci_dev *pci; + + unsigned int init_failed:1; /* delayed init failed */ + struct platform_device *dmic_dev; +}; + +#define skl_to_ebus(s) (&(s)->ebus) +#define ebus_to_skl(sbus) \ + container_of(sbus, struct skl, sbus) + +/* to pass dai dma data */ +struct skl_dma_params { + u32 format; + u8 stream_tag; +}; + +int skl_platform_unregister(struct device *dev); +int skl_platform_register(struct device *dev); + +#endif /* __SOUND_SOC_SKL_H */ -- GitLab From d8c2dab8381d58376d127c64553e499569f4d22a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:09 +0530 Subject: [PATCH 0638/7006] ASoC: Intel: Add Skylake HDA audio driver This patch follows up by adding the HDA controller operations. This code is mostly derived from Intel HDA PCI driver without legacy bits Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl.c | 525 ++++++++++++++++++++++++++++++++++ 1 file changed, 525 insertions(+) create mode 100644 sound/soc/intel/skylake/skl.c diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c new file mode 100644 index 0000000000000..dfbc15c2ac7b0 --- /dev/null +++ b/sound/soc/intel/skylake/skl.c @@ -0,0 +1,525 @@ +/* + * skl.c - Implementation of ASoC Intel SKL HD Audio driver + * + * Copyright (C) 2014-2015 Intel Corp + * Author: Jeeja KP + * + * Derived mostly from Intel HDA driver with following copyrights: + * Copyright (c) 2004 Takashi Iwai + * PeiSen Hou + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include +#include +#include "skl.h" + +/* + * initialize the PCI registers + */ +static void skl_update_pci_byte(struct pci_dev *pci, unsigned int reg, + unsigned char mask, unsigned char val) +{ + unsigned char data; + + pci_read_config_byte(pci, reg, &data); + data &= ~mask; + data |= (val & mask); + pci_write_config_byte(pci, reg, data); +} + +static void skl_init_pci(struct skl *skl) +{ + struct hdac_ext_bus *ebus = &skl->ebus; + + /* + * Clear bits 0-2 of PCI register TCSEL (at offset 0x44) + * TCSEL == Traffic Class Select Register, which sets PCI express QOS + * Ensuring these bits are 0 clears playback static on some HD Audio + * codecs. + * The PCI register TCSEL is defined in the Intel manuals. + */ + dev_dbg(ebus_to_hbus(ebus)->dev, "Clearing TCSEL\n"); + skl_update_pci_byte(skl->pci, AZX_PCIREG_TCSEL, 0x07, 0); +} + +/* called from IRQ */ +static void skl_stream_update(struct hdac_bus *bus, struct hdac_stream *hstr) +{ + snd_pcm_period_elapsed(hstr->substream); +} + +static irqreturn_t skl_interrupt(int irq, void *dev_id) +{ + struct hdac_ext_bus *ebus = dev_id; + struct hdac_bus *bus = ebus_to_hbus(ebus); + u32 status; + + if (!pm_runtime_active(bus->dev)) + return IRQ_NONE; + + spin_lock(&bus->reg_lock); + + status = snd_hdac_chip_readl(bus, INTSTS); + if (status == 0 || status == 0xffffffff) { + spin_unlock(&bus->reg_lock); + return IRQ_NONE; + } + + /* clear rirb int */ + status = snd_hdac_chip_readb(bus, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) + snd_hdac_bus_update_rirb(bus); + snd_hdac_chip_writeb(bus, RIRBSTS, RIRB_INT_MASK); + } + + spin_unlock(&bus->reg_lock); + + return snd_hdac_chip_readl(bus, INTSTS) ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +static irqreturn_t skl_threaded_handler(int irq, void *dev_id) +{ + struct hdac_ext_bus *ebus = dev_id; + struct hdac_bus *bus = ebus_to_hbus(ebus); + u32 status; + + status = snd_hdac_chip_readl(bus, INTSTS); + + snd_hdac_bus_handle_stream_irq(bus, status, skl_stream_update); + + return IRQ_HANDLED; +} + +static int skl_acquire_irq(struct hdac_ext_bus *ebus, int do_disconnect) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + int ret; + + ret = request_threaded_irq(skl->pci->irq, skl_interrupt, + skl_threaded_handler, + IRQF_SHARED, + KBUILD_MODNAME, ebus); + if (ret) { + dev_err(bus->dev, + "unable to grab IRQ %d, disabling device\n", + skl->pci->irq); + return ret; + } + + bus->irq = skl->pci->irq; + pci_intx(skl->pci, 1); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/* + * power management + */ +static int skl_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_enter_link_reset(bus); + + return 0; +} + +static int skl_resume(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl *hda = ebus_to_skl(ebus); + + skl_init_pci(hda); + + snd_hdac_bus_init_chip(bus, 1); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM +static int skl_runtime_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + dev_dbg(bus->dev, "in %s\n", __func__); + + /* enable controller wake up event */ + snd_hdac_chip_updatew(bus, WAKEEN, 0, STATESTS_INT_MASK); + + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_enter_link_reset(bus); + + return 0; +} + +static int skl_runtime_resume(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl *hda = ebus_to_skl(ebus); + int status; + + dev_dbg(bus->dev, "in %s\n", __func__); + + /* Read STATESTS before controller reset */ + status = snd_hdac_chip_readw(bus, STATESTS); + + skl_init_pci(hda); + snd_hdac_bus_init_chip(bus, true); + /* disable controller Wake Up event */ + snd_hdac_chip_updatew(bus, WAKEEN, STATESTS_INT_MASK, 0); + + return 0; +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops skl_pm = { + SET_SYSTEM_SLEEP_PM_OPS(skl_suspend, skl_resume) + SET_RUNTIME_PM_OPS(skl_runtime_suspend, skl_runtime_resume, NULL) +}; + +/* + * destructor + */ +static int skl_free(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + skl->init_failed = 1; /* to be sure */ + + snd_hdac_ext_stop_streams(ebus); + + if (bus->irq >= 0) + free_irq(bus->irq, (void *)bus); + if (bus->remap_addr) + iounmap(bus->remap_addr); + + snd_hdac_bus_free_stream_pages(bus); + snd_hdac_stream_free_all(ebus); + snd_hdac_link_free_all(ebus); + pci_release_regions(skl->pci); + pci_disable_device(skl->pci); + + snd_hdac_ext_bus_exit(ebus); + + return 0; +} + +static int skl_dmic_device_register(struct skl *skl) +{ + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct platform_device *pdev; + int ret; + + /* SKL has one dmic port, so allocate dmic device for this */ + pdev = platform_device_alloc("dmic-codec", -1); + if (!pdev) { + dev_err(bus->dev, "failed to allocate dmic device\n"); + return -ENOMEM; + } + + ret = platform_device_add(pdev); + if (ret) { + dev_err(bus->dev, "failed to add dmic device: %d\n", ret); + platform_device_put(pdev); + return ret; + } + skl->dmic_dev = pdev; + + return 0; +} + +static void skl_dmic_device_unregister(struct skl *skl) +{ + if (skl->dmic_dev) + platform_device_unregister(skl->dmic_dev); +} + +/* + * Probe the given codec address + */ +static int probe_codec(struct hdac_ext_bus *ebus, int addr) +{ + struct hdac_bus *bus = ebus_to_hbus(ebus); + unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + unsigned int res; + + mutex_lock(&bus->cmd_mutex); + snd_hdac_bus_send_cmd(bus, cmd); + snd_hdac_bus_get_response(bus, addr, &res); + mutex_unlock(&bus->cmd_mutex); + if (res == -1) + return -EIO; + dev_dbg(bus->dev, "codec #%d probed OK\n", addr); + + return snd_hdac_ext_bus_device_init(ebus, addr); +} + +/* Codec initialization */ +static int skl_codec_create(struct hdac_ext_bus *ebus) +{ + struct hdac_bus *bus = ebus_to_hbus(ebus); + int c, max_slots; + + max_slots = HDA_MAX_CODECS; + + /* First try to probe all given codec slots */ + for (c = 0; c < max_slots; c++) { + if ((bus->codec_mask & (1 << c))) { + if (probe_codec(ebus, c) < 0) { + /* + * Some BIOSen give you wrong codec addresses + * that don't exist + */ + dev_warn(bus->dev, + "Codec #%d probe error; disabling it...\n", c); + bus->codec_mask &= ~(1 << c); + /* + * More badly, accessing to a non-existing + * codec often screws up the controller bus, + * and disturbs the further communications. + * Thus if an error occurs during probing, + * better to reset the controller bus to get + * back to the sanity state. + */ + snd_hdac_bus_stop_chip(bus); + snd_hdac_bus_init_chip(bus, true); + } + } + } + + return 0; +} + +static const struct hdac_bus_ops bus_core_ops = { + .command = snd_hdac_bus_send_cmd, + .get_response = snd_hdac_bus_get_response, +}; + +/* + * constructor + */ +static int skl_create(struct pci_dev *pci, + const struct hdac_io_ops *io_ops, + struct skl **rskl) +{ + struct skl *skl; + struct hdac_ext_bus *ebus; + + int err; + + *rskl = NULL; + + err = pci_enable_device(pci); + if (err < 0) + return err; + + skl = devm_kzalloc(&pci->dev, sizeof(*skl), GFP_KERNEL); + if (!skl) { + pci_disable_device(pci); + return -ENOMEM; + } + ebus = &skl->ebus; + snd_hdac_ext_bus_init(ebus, &pci->dev, &bus_core_ops, io_ops); + ebus->bus.use_posbuf = 1; + skl->pci = pci; + + ebus->bus.bdl_pos_adj = 0; + + *rskl = skl; + + return 0; +} + +static int skl_first_init(struct hdac_ext_bus *ebus) +{ + struct skl *skl = ebus_to_skl(ebus); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct pci_dev *pci = skl->pci; + int err; + unsigned short gcap; + int cp_streams, pb_streams, start_idx; + + err = pci_request_regions(pci, "Skylake HD audio"); + if (err < 0) + return err; + + bus->addr = pci_resource_start(pci, 0); + bus->remap_addr = pci_ioremap_bar(pci, 0); + if (bus->remap_addr == NULL) { + dev_err(bus->dev, "ioremap error\n"); + return -ENXIO; + } + + if (skl_acquire_irq(ebus, 0) < 0) + return -EBUSY; + + pci_set_master(pci); + synchronize_irq(bus->irq); + + gcap = snd_hdac_chip_readw(bus, GCAP); + dev_dbg(bus->dev, "chipset global capabilities = 0x%x\n", gcap); + + /* allow 64bit DMA address if supported by H/W */ + if (!dma_set_mask(bus->dev, DMA_BIT_MASK(64))) { + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(64)); + } else { + dma_set_mask(bus->dev, DMA_BIT_MASK(32)); + dma_set_coherent_mask(bus->dev, DMA_BIT_MASK(32)); + } + + /* read number of streams from GCAP register */ + cp_streams = (gcap >> 8) & 0x0f; + pb_streams = (gcap >> 12) & 0x0f; + + if (!pb_streams && !cp_streams) + return -EIO; + + ebus->num_streams = cp_streams + pb_streams; + + /* initialize streams */ + snd_hdac_ext_stream_init_all + (ebus, 0, cp_streams, SNDRV_PCM_STREAM_CAPTURE); + start_idx = cp_streams; + snd_hdac_ext_stream_init_all + (ebus, start_idx, pb_streams, SNDRV_PCM_STREAM_PLAYBACK); + + err = snd_hdac_bus_alloc_stream_pages(bus); + if (err < 0) + return err; + + /* initialize chip */ + skl_init_pci(skl); + + snd_hdac_bus_init_chip(bus, true); + + /* codec detection */ + if (!bus->codec_mask) { + dev_err(bus->dev, "no codecs found!\n"); + return -ENODEV; + } + + return 0; +} + +static int skl_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + struct skl *skl; + struct hdac_ext_bus *ebus = NULL; + struct hdac_bus *bus = NULL; + int err; + + /* we use ext core ops, so provide NULL for ops here */ + err = skl_create(pci, NULL, &skl); + if (err < 0) + return err; + + ebus = &skl->ebus; + bus = ebus_to_hbus(ebus); + + err = skl_first_init(ebus); + if (err < 0) + goto out_free; + + pci_set_drvdata(skl->pci, ebus); + + /* create device for soc dmic */ + err = skl_dmic_device_register(skl); + if (err < 0) + goto out_free; + + /* register platform dai and controls */ + err = skl_platform_register(bus->dev); + if (err < 0) + goto out_dmic_free; + + /* create codec instances */ + err = skl_codec_create(ebus); + if (err < 0) + goto out_unregister; + + /*configure PM */ + pm_runtime_set_autosuspend_delay(bus->dev, SKL_SUSPEND_DELAY); + pm_runtime_use_autosuspend(bus->dev); + pm_runtime_put_noidle(bus->dev); + pm_runtime_allow(bus->dev); + + return 0; + +out_unregister: + skl_platform_unregister(bus->dev); +out_dmic_free: + skl_dmic_device_unregister(skl); +out_free: + skl->init_failed = 1; + skl_free(ebus); + + return err; +} + +static void skl_remove(struct pci_dev *pci) +{ + struct hdac_ext_bus *ebus = pci_get_drvdata(pci); + struct skl *skl = ebus_to_skl(ebus); + + if (pci_dev_run_wake(pci)) + pm_runtime_get_noresume(&pci->dev); + pci_dev_put(pci); + skl_platform_unregister(&pci->dev); + skl_dmic_device_unregister(skl); + skl_free(ebus); + dev_set_drvdata(&pci->dev, NULL); +} + +/* PCI IDs */ +static const struct pci_device_id skl_ids[] = { + /* Sunrise Point-LP */ + { PCI_DEVICE(0x8086, 0x9d70), 0}, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, skl_ids); + +/* pci_driver definition */ +static struct pci_driver skl_driver = { + .name = KBUILD_MODNAME, + .id_table = skl_ids, + .probe = skl_probe, + .remove = skl_remove, + .driver = { + .pm = &skl_pm, + }, +}; +module_pci_driver(skl_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Skylake ASoC HDA driver"); -- GitLab From eb965e3686f5cea669444d120f3723efa88ed56a Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:10 +0530 Subject: [PATCH 0639/7006] ASoC: Intel: Add makefile support for SKL driver This adds makefile and Kconfig to enable Skylake HD audio PCM driver Signed-off-by: Jeeja KP Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 4 ++++ sound/soc/intel/Makefile | 1 + sound/soc/intel/skylake/Makefile | 3 +++ 3 files changed, 8 insertions(+) create mode 100644 sound/soc/intel/skylake/Makefile diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index 32262be80871f..d8b99434e6997 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -134,3 +134,7 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell platforms with MAX98090 audio codec it also can support TI jack chip as aux device. If unsure select "N". + +config SND_SOC_INTEL_SKYLAKE + tristate + select SND_HDA_EXT_CORE diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile index 6de5d5cd3280a..2b45435e6245c 100644 --- a/sound/soc/intel/Makefile +++ b/sound/soc/intel/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_SND_SOC_INTEL_SST) += common/ obj-$(CONFIG_SND_SOC_INTEL_HASWELL) += haswell/ obj-$(CONFIG_SND_SOC_INTEL_BAYTRAIL) += baytrail/ obj-$(CONFIG_SND_SST_MFLD_PLATFORM) += atom/ +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += skylake/ # Machine support obj-$(CONFIG_SND_SOC) += boards/ diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile new file mode 100644 index 0000000000000..734d17cafde7b --- /dev/null +++ b/sound/soc/intel/skylake/Makefile @@ -0,0 +1,3 @@ +snd-soc-skl-objs := skl.o skl-pcm.o + +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o -- GitLab From 0505700104cd98da6d11c01b8063cffdb1b8d7d7 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Thu, 9 Jul 2015 15:20:11 +0530 Subject: [PATCH 0640/7006] ASoC: Intel: Add support for decoupled mode in skl driver Decoupled mode is where audio link is broken to frontend HDA and backend (hda/i2s/dmic/hdmi) links. This patch adds support for decoupled mode and then adds dais, dai ops for be/fe cpu dais and interrupt handler change to support decoupled mode Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-pcm.c | 346 +++++++++++++++++++++++++++++- sound/soc/intel/skylake/skl.c | 11 + 2 files changed, 349 insertions(+), 8 deletions(-) diff --git a/sound/soc/intel/skylake/skl-pcm.c b/sound/soc/intel/skylake/skl-pcm.c index c171def2fcc9c..7d617bf493bc7 100644 --- a/sound/soc/intel/skylake/skl-pcm.c +++ b/sound/soc/intel/skylake/skl-pcm.c @@ -96,6 +96,14 @@ static void skl_set_pcm_constrains(struct hdac_ext_bus *ebus, 20, 178000000); } +static enum hdac_ext_stream_type skl_get_host_stream_type(struct hdac_ext_bus *ebus) +{ + if (ebus->ppcap) + return HDAC_EXT_STREAM_TYPE_HOST; + else + return HDAC_EXT_STREAM_TYPE_COUPLED; +} + static int skl_pcm_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { @@ -111,7 +119,7 @@ static int skl_pcm_open(struct snd_pcm_substream *substream, return ret; stream = snd_hdac_ext_stream_assign(ebus, substream, - HDAC_EXT_STREAM_TYPE_COUPLED); + skl_get_host_stream_type(ebus)); if (stream == NULL) return -EBUSY; @@ -147,12 +155,23 @@ static int skl_get_format(struct snd_pcm_substream *substream, { struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); struct skl_dma_params *dma_params; + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); int format_val = 0; - struct snd_soc_dai *codec_dai = rtd->codec_dai; - dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); - if (dma_params) - format_val = dma_params->format; + if (ebus->ppcap) { + struct snd_pcm_runtime *runtime = substream->runtime; + + format_val = snd_hdac_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, + 32, 0); + } else { + struct snd_soc_dai *codec_dai = rtd->codec_dai; + + dma_params = snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + format_val = dma_params->format; + } return format_val; } @@ -193,8 +212,9 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); struct snd_pcm_runtime *runtime = substream->runtime; - int ret; + int ret, dma_id; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); ret = skl_substream_alloc_pages(ebus, substream, @@ -205,6 +225,9 @@ static int skl_pcm_hw_params(struct snd_pcm_substream *substream, dev_dbg(dai->dev, "format_val, rate=%d, ch=%d, format=%d\n", runtime->rate, runtime->channels, runtime->format); + dma_id = hdac_stream(stream)->stream_tag - 1; + dev_dbg(dai->dev, "dma_id=%d\n", dma_id); + return 0; } @@ -212,10 +235,12 @@ static void skl_pcm_close(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdac_ext_stream *stream = get_hdac_ext_stream(substream); + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); struct skl_dma_params *dma_params = NULL; dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); - snd_hdac_ext_stream_release(stream, HDAC_EXT_STREAM_TYPE_COUPLED); + + snd_hdac_ext_stream_release(stream, skl_get_host_stream_type(ebus)); dma_params = snd_soc_dai_get_dma_data(dai, substream); /* @@ -243,6 +268,150 @@ static int skl_pcm_hw_free(struct snd_pcm_substream *substream, return skl_substream_free_pages(ebus_to_hbus(ebus), substream); } +static int skl_link_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *link_dev; + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct skl_dma_params *dma_params; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int dma_id; + + pr_debug("%s\n", __func__); + link_dev = snd_hdac_ext_stream_assign(ebus, substream, + HDAC_EXT_STREAM_TYPE_LINK); + if (!link_dev) + return -EBUSY; + + snd_soc_dai_set_dma_data(dai, substream, (void *)link_dev); + + /* set the stream tag in the codec dai dma params */ + dma_params = (struct skl_dma_params *) + snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + dma_params->stream_tag = hdac_stream(link_dev)->stream_tag; + snd_soc_dai_set_dma_data(codec_dai, substream, (void *)dma_params); + dma_id = hdac_stream(link_dev)->stream_tag - 1; + + return 0; +} + +static int skl_link_pcm_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + unsigned int format_val = 0; + struct skl_dma_params *dma_params; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + struct snd_pcm_hw_params *params; + struct snd_interval *channels, *rate; + struct hdac_ext_link *link; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + if (link_dev->link_prepared) { + dev_dbg(dai->dev, "already stream is prepared - returning\n"); + return 0; + } + params = devm_kzalloc(dai->dev, sizeof(*params), GFP_KERNEL); + if (params == NULL) + return -ENOMEM; + + channels = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + channels->min = channels->max = substream->runtime->channels; + rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); + rate->min = rate->max = substream->runtime->rate; + snd_mask_set(¶ms->masks[SNDRV_PCM_HW_PARAM_FORMAT - + SNDRV_PCM_HW_PARAM_FIRST_MASK], + substream->runtime->format); + + + dma_params = (struct skl_dma_params *) + snd_soc_dai_get_dma_data(codec_dai, substream); + if (dma_params) + format_val = dma_params->format; + dev_dbg(dai->dev, "stream_tag=%d formatvalue=%d codec_dai_name=%s\n", + hdac_stream(link_dev)->stream_tag, format_val, codec_dai->name); + + snd_hdac_ext_link_stream_reset(link_dev); + + snd_hdac_ext_link_stream_setup(link_dev, format_val); + + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + + snd_hdac_ext_link_set_stream_id(link, hdac_stream(link_dev)->stream_tag); + link_dev->link_prepared = 1; + + return 0; +} + +static int skl_link_pcm_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + + dev_dbg(dai->dev, "In %s cmd=%d\n", __func__, cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + snd_hdac_ext_link_stream_start(link_dev); + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + snd_hdac_ext_link_stream_clear(link_dev); + break; + + default: + return -EINVAL; + } + return 0; +} + +static int skl_link_hw_free(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dai->dev); + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct hdac_ext_stream *link_dev = + snd_soc_dai_get_dma_data(dai, substream); + struct hdac_ext_link *link; + + dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + + link_dev->link_prepared = 0; + + link = snd_hdac_ext_bus_get_link(ebus, rtd->codec->component.name); + if (!link) + return -EINVAL; + + snd_hdac_ext_link_clear_stream_id(link, hdac_stream(link_dev)->stream_tag); + snd_hdac_ext_stream_release(link_dev, HDAC_EXT_STREAM_TYPE_LINK); + return 0; +} + +static int skl_hda_be_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + return pm_runtime_get_sync(dai->dev); +} + +static void skl_hda_be_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + pm_runtime_mark_last_busy(dai->dev); + pm_runtime_put_autosuspend(dai->dev); +} + static struct snd_soc_dai_ops skl_pcm_dai_ops = { .startup = skl_pcm_open, .shutdown = skl_pcm_close, @@ -251,6 +420,20 @@ static struct snd_soc_dai_ops skl_pcm_dai_ops = { .hw_free = skl_pcm_hw_free, }; +static struct snd_soc_dai_ops skl_dmic_dai_ops = { + .startup = skl_hda_be_startup, + .shutdown = skl_hda_be_shutdown, +}; + +static struct snd_soc_dai_ops skl_link_dai_ops = { + .startup = skl_hda_be_startup, + .prepare = skl_link_pcm_prepare, + .hw_params = skl_link_hw_params, + .hw_free = skl_link_hw_free, + .trigger = skl_link_pcm_trigger, + .shutdown = skl_hda_be_shutdown, +}; + static struct snd_soc_dai_driver skl_platform_dai[] = { { .name = "System Pin", @@ -270,6 +453,17 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +{ + .name = "Reference Pin", + .ops = &skl_pcm_dai_ops, + .capture = { + .stream_name = "Reference Capture", + .channels_min = HDA_MONO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, { .name = "Deepbuffer Pin", .ops = &skl_pcm_dai_ops, @@ -292,6 +486,80 @@ static struct snd_soc_dai_driver skl_platform_dai[] = { .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, }, }, +/* BE CPU Dais */ +{ + .name = "iDisp Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "iDisp Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "DMIC01 Pin", + .ops = &skl_dmic_dai_ops, + .capture = { + .stream_name = "DMIC01 Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "DMIC23 Pin", + .ops = &skl_dmic_dai_ops, + .capture = { + .stream_name = "DMIC23 Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE, + }, +}, +{ + .name = "HD-Codec Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "HD-Codec Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .capture = { + .stream_name = "HD-Codec Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "HD-Codec-SPK Pin", + .ops = &skl_link_dai_ops, + .playback = { + .stream_name = "HD-Codec-SPK Tx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, +{ + .name = "HD-Codec-AMIC Pin", + .ops = &skl_link_dai_ops, + .capture = { + .stream_name = "HD-Codec-AMIC Rx", + .channels_min = HDA_STEREO, + .channels_max = HDA_STEREO, + .rates = SNDRV_PCM_RATE_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, +}, }; static int skl_platform_open(struct snd_pcm_substream *substream) @@ -309,7 +577,7 @@ static int skl_platform_open(struct snd_pcm_substream *substream) return 0; } -static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, +static int skl_pcm_trigger(struct snd_pcm_substream *substream, int cmd) { struct hdac_ext_bus *ebus = get_bus_ctx(substream); @@ -383,6 +651,68 @@ static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, return 0; } +static int skl_dsp_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct snd_soc_pcm_runtime *rtd = snd_pcm_substream_chip(substream); + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct hdac_ext_stream *stream; + int start; + unsigned long cookie; + struct hdac_stream *hstr; + + dev_dbg(bus->dev, "In %s cmd=%d streamname=%s\n", __func__, cmd, cpu_dai->name); + + stream = get_hdac_ext_stream(substream); + hstr = hdac_stream(stream); + + if (!hstr->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + + default: + return -EINVAL; + } + + spin_lock_irqsave(&bus->reg_lock, cookie); + + if (start) + snd_hdac_stream_start(hdac_stream(stream), true); + else + snd_hdac_stream_stop(hdac_stream(stream)); + + if (start) + snd_hdac_stream_timecounter_init(hstr, 0); + + spin_unlock_irqrestore(&bus->reg_lock, cookie); + + return 0; +} +static int skl_platform_pcm_trigger(struct snd_pcm_substream *substream, + int cmd) +{ + struct hdac_ext_bus *ebus = get_bus_ctx(substream); + + if (ebus->ppcap) + return skl_dsp_trigger(substream, cmd); + else + return skl_pcm_trigger(substream, cmd); +} + /* calculate runtime delay from LPIB */ static int skl_get_delay_from_lpib(struct hdac_ext_bus *ebus, struct hdac_ext_stream *sstream, diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index dfbc15c2ac7b0..348d094e81d66 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -380,6 +380,8 @@ static int skl_first_init(struct hdac_ext_bus *ebus) return -ENXIO; } + snd_hdac_ext_bus_parse_capabilities(ebus); + if (skl_acquire_irq(ebus, 0) < 0) return -EBUSY; @@ -453,6 +455,15 @@ static int skl_probe(struct pci_dev *pci, pci_set_drvdata(skl->pci, ebus); + /* check if dsp is there */ + if (ebus->ppcap) { + /* TODO register with dsp IPC */ + dev_dbg(bus->dev, "Register dsp\n"); + } + + if (ebus->mlcap) + snd_hdac_ext_bus_get_ml_capabilities(ebus); + /* create device for soc dmic */ err = skl_dmic_device_register(skl); if (err < 0) -- GitLab From 6adcafae6ed20fe380addc8e7c628e529751ade3 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Fri, 26 Jun 2015 10:59:49 +0800 Subject: [PATCH 0641/7006] ASoC: add rt298 codec driver It is the initial version of ALC298 codec driver. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- include/sound/rt298.h | 20 + sound/soc/codecs/Kconfig | 7 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/rt298.c | 1274 +++++++++++++++++++++++++++++++++++++ sound/soc/codecs/rt298.h | 206 ++++++ 5 files changed, 1509 insertions(+) create mode 100644 include/sound/rt298.h create mode 100644 sound/soc/codecs/rt298.c create mode 100644 sound/soc/codecs/rt298.h diff --git a/include/sound/rt298.h b/include/sound/rt298.h new file mode 100644 index 0000000000000..7fffeaa84f645 --- /dev/null +++ b/include/sound/rt298.h @@ -0,0 +1,20 @@ +/* + * linux/sound/rt286.h -- Platform data for RT286 + * + * Copyright 2013 Realtek Microelectronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __LINUX_SND_RT298_H +#define __LINUX_SND_RT298_H + +struct rt298_platform_data { + bool cbj_en; /*combo jack enable*/ + bool gpio2_en; /*GPIO2 enable*/ + bool suspend_power_off; /* power is off during suspend */ +}; + +#endif diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce8ba387..76125a2815570 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -83,6 +83,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_PCM512x_I2C if I2C select SND_SOC_PCM512x_SPI if SPI_MASTER select SND_SOC_RT286 if I2C + select SND_SOC_RT298 if I2C select SND_SOC_RT5631 if I2C select SND_SOC_RT5640 if I2C select SND_SOC_RT5645 if I2C @@ -512,12 +513,18 @@ config SND_SOC_RL6231 config SND_SOC_RL6347A tristate default y if SND_SOC_RT286=y + default y if SND_SOC_RT298=y default m if SND_SOC_RT286=m + default m if SND_SOC_RT298=m config SND_SOC_RT286 tristate depends on I2C +config SND_SOC_RT298 + tristate + depends on I2C + config SND_SOC_RT5631 tristate "Realtek ALC5631/RT5631 CODEC" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d972cb36..3b58c4571859d 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -79,6 +79,7 @@ snd-soc-pcm512x-spi-objs := pcm512x-spi.o snd-soc-rl6231-objs := rl6231.o snd-soc-rl6347a-objs := rl6347a.o snd-soc-rt286-objs := rt286.o +snd-soc-rt298-objs := rt298.o snd-soc-rt5631-objs := rt5631.o snd-soc-rt5640-objs := rt5640.o snd-soc-rt5645-objs := rt5645.o @@ -266,6 +267,7 @@ obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o +obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c new file mode 100644 index 0000000000000..7c4bcb65ef2c8 --- /dev/null +++ b/sound/soc/codecs/rt298.c @@ -0,0 +1,1274 @@ +/* + * rt298.c -- RT298 ALSA SoC audio codec driver + * + * Copyright 2015 Realtek Semiconductor Corp. + * Author: Bard Liao + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rl6347a.h" +#include "rt298.h" + +#define RT298_VENDOR_ID 0x10ec0298 + +struct rt298_priv { + struct reg_default *index_cache; + int index_cache_size; + struct regmap *regmap; + struct snd_soc_codec *codec; + struct rt298_platform_data pdata; + struct i2c_client *i2c; + struct snd_soc_jack *jack; + struct delayed_work jack_detect_work; + int sys_clk; + int clk_id; + int is_hp_in; +}; + +static struct reg_default rt298_index_def[] = { + { 0x01, 0xaaaa }, + { 0x02, 0x8aaa }, + { 0x03, 0x0002 }, + { 0x04, 0xaf01 }, + { 0x08, 0x000d }, + { 0x09, 0xd810 }, + { 0x0a, 0x0120 }, + { 0x0b, 0x0000 }, + { 0x0d, 0x2800 }, + { 0x0f, 0x0000 }, + { 0x19, 0x0a17 }, + { 0x20, 0x0020 }, + { 0x33, 0x0208 }, + { 0x46, 0x0300 }, + { 0x49, 0x0004 }, + { 0x4f, 0x50e9 }, + { 0x50, 0x2000 }, + { 0x63, 0x2902 }, + { 0x67, 0x1111 }, + { 0x68, 0x1016 }, + { 0x69, 0x273f }, +}; +#define INDEX_CACHE_SIZE ARRAY_SIZE(rt298_index_def) + +static const struct reg_default rt298_reg[] = { + { 0x00170500, 0x00000400 }, + { 0x00220000, 0x00000031 }, + { 0x00239000, 0x0000007f }, + { 0x0023a000, 0x0000007f }, + { 0x00270500, 0x00000400 }, + { 0x00370500, 0x00000400 }, + { 0x00870500, 0x00000400 }, + { 0x00920000, 0x00000031 }, + { 0x00935000, 0x000000c3 }, + { 0x00936000, 0x000000c3 }, + { 0x00970500, 0x00000400 }, + { 0x00b37000, 0x00000097 }, + { 0x00b37200, 0x00000097 }, + { 0x00b37300, 0x00000097 }, + { 0x00c37000, 0x00000000 }, + { 0x00c37100, 0x00000080 }, + { 0x01270500, 0x00000400 }, + { 0x01370500, 0x00000400 }, + { 0x01371f00, 0x411111f0 }, + { 0x01439000, 0x00000080 }, + { 0x0143a000, 0x00000080 }, + { 0x01470700, 0x00000000 }, + { 0x01470500, 0x00000400 }, + { 0x01470c00, 0x00000000 }, + { 0x01470100, 0x00000000 }, + { 0x01837000, 0x00000000 }, + { 0x01870500, 0x00000400 }, + { 0x02050000, 0x00000000 }, + { 0x02139000, 0x00000080 }, + { 0x0213a000, 0x00000080 }, + { 0x02170100, 0x00000000 }, + { 0x02170500, 0x00000400 }, + { 0x02170700, 0x00000000 }, + { 0x02270100, 0x00000000 }, + { 0x02370100, 0x00000000 }, + { 0x01870700, 0x00000020 }, + { 0x00830000, 0x000000c3 }, + { 0x00930000, 0x000000c3 }, + { 0x01270700, 0x00000000 }, +}; + +static bool rt298_volatile_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT298_GET_HP_SENSE: + case RT298_GET_MIC1_SENSE: + case RT298_PROC_COEF: + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0): + return true; + default: + return true; + } + + +} + +static bool rt298_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case 0 ... 0xff: + case RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID): + case RT298_GET_HP_SENSE: + case RT298_GET_MIC1_SENSE: + case RT298_SET_AUDIO_POWER: + case RT298_SET_HPO_POWER: + case RT298_SET_SPK_POWER: + case RT298_SET_DMIC1_POWER: + case RT298_SPK_MUX: + case RT298_HPO_MUX: + case RT298_ADC0_MUX: + case RT298_ADC1_MUX: + case RT298_SET_MIC1: + case RT298_SET_PIN_HPO: + case RT298_SET_PIN_SPK: + case RT298_SET_PIN_DMIC1: + case RT298_SPK_EAPD: + case RT298_SET_AMP_GAIN_HPO: + case RT298_SET_DMIC2_DEFAULT: + case RT298_DACL_GAIN: + case RT298_DACR_GAIN: + case RT298_ADCL_GAIN: + case RT298_ADCR_GAIN: + case RT298_MIC_GAIN: + case RT298_SPOL_GAIN: + case RT298_SPOR_GAIN: + case RT298_HPOL_GAIN: + case RT298_HPOR_GAIN: + case RT298_F_DAC_SWITCH: + case RT298_F_RECMIX_SWITCH: + case RT298_REC_MIC_SWITCH: + case RT298_REC_I2S_SWITCH: + case RT298_REC_LINE_SWITCH: + case RT298_REC_BEEP_SWITCH: + case RT298_DAC_FORMAT: + case RT298_ADC_FORMAT: + case RT298_COEF_INDEX: + case RT298_PROC_COEF: + case RT298_SET_AMP_GAIN_ADC_IN1: + case RT298_SET_AMP_GAIN_ADC_IN2: + case RT298_SET_POWER(RT298_DAC_OUT1): + case RT298_SET_POWER(RT298_DAC_OUT2): + case RT298_SET_POWER(RT298_ADC_IN1): + case RT298_SET_POWER(RT298_ADC_IN2): + case RT298_SET_POWER(RT298_DMIC2): + case RT298_SET_POWER(RT298_MIC1): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_MIC1, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_SPK_OUT, 0): + case VERB_CMD(AC_VERB_GET_EAPD_BTLENABLE, RT298_HP_OUT, 0): + return true; + default: + return false; + } +} + +#ifdef CONFIG_PM +static void rt298_index_sync(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + int i; + + for (i = 0; i < INDEX_CACHE_SIZE; i++) { + snd_soc_write(codec, rt298->index_cache[i].reg, + rt298->index_cache[i].def); + } +} +#endif + +static int rt298_support_power_controls[] = { + RT298_DAC_OUT1, + RT298_DAC_OUT2, + RT298_ADC_IN1, + RT298_ADC_IN2, + RT298_MIC1, + RT298_DMIC1, + RT298_DMIC2, + RT298_SPK_OUT, + RT298_HP_OUT, +}; +#define RT298_POWER_REG_LEN ARRAY_SIZE(rt298_support_power_controls) + +static int rt298_jack_detect(struct rt298_priv *rt298, bool *hp, bool *mic) +{ + struct snd_soc_dapm_context *dapm; + unsigned int val, buf; + + *hp = false; + *mic = false; + + if (!rt298->codec) + return -EINVAL; + + dapm = snd_soc_codec_get_dapm(rt298->codec); + + if (rt298->pdata.cbj_en) { + regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + if (*hp == rt298->is_hp_in) + return -1; + rt298->is_hp_in = *hp; + if (*hp) { + /* power on HV,VERF */ + regmap_update_bits(rt298->regmap, + RT298_DC_GAIN, 0x200, 0x200); + + snd_soc_dapm_force_enable_pin(dapm, "HV"); + snd_soc_dapm_force_enable_pin(dapm, "VREF"); + /* power LDO1 */ + snd_soc_dapm_force_enable_pin(dapm, "LDO1"); + snd_soc_dapm_sync(dapm); + + regmap_write(rt298->regmap, RT298_SET_MIC1, 0x24); + msleep(50); + + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xfcc0, 0xd400); + msleep(300); + regmap_read(rt298->regmap, RT298_CBJ_CTRL2, &val); + + if (0x0070 == (val & 0x0070)) { + *mic = true; + } else { + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xfcc0, 0xe400); + msleep(300); + regmap_read(rt298->regmap, + RT298_CBJ_CTRL2, &val); + if (0x0070 == (val & 0x0070)) + *mic = true; + else + *mic = false; + } + regmap_update_bits(rt298->regmap, + RT298_DC_GAIN, 0x200, 0x0); + + } else { + *mic = false; + regmap_write(rt298->regmap, RT298_SET_MIC1, 0x20); + } + } else { + regmap_read(rt298->regmap, RT298_GET_HP_SENSE, &buf); + *hp = buf & 0x80000000; + regmap_read(rt298->regmap, RT298_GET_MIC1_SENSE, &buf); + *mic = buf & 0x80000000; + } + + snd_soc_dapm_disable_pin(dapm, "HV"); + snd_soc_dapm_disable_pin(dapm, "VREF"); + if (!*hp) + snd_soc_dapm_disable_pin(dapm, "LDO1"); + snd_soc_dapm_sync(dapm); + + pr_debug("*hp = %d *mic = %d\n", *hp, *mic); + + return 0; +} + +static void rt298_jack_detect_work(struct work_struct *work) +{ + struct rt298_priv *rt298 = + container_of(work, struct rt298_priv, jack_detect_work.work); + int status = 0; + bool hp = false; + bool mic = false; + + if (rt298_jack_detect(rt298, &hp, &mic) < 0) + return; + + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt298->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); +} + +int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + rt298->jack = jack; + + /* Send an initial empty report */ + snd_soc_jack_report(rt298->jack, 0, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + return 0; +} +EXPORT_SYMBOL_GPL(rt298_mic_detect); + +static int is_mclk_mode(struct snd_soc_dapm_widget *source, + struct snd_soc_dapm_widget *sink) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm); + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + if (rt298->clk_id == RT298_SCLK_S_MCLK) + return 1; + else + return 0; +} + +static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0); +static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0); + +static const struct snd_kcontrol_new rt298_snd_controls[] = { + SOC_DOUBLE_R_TLV("DAC0 Playback Volume", RT298_DACL_GAIN, + RT298_DACR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_DOUBLE_R_TLV("ADC0 Capture Volume", RT298_ADCL_GAIN, + RT298_ADCR_GAIN, 0, 0x7f, 0, out_vol_tlv), + SOC_SINGLE_TLV("AMIC Volume", RT298_MIC_GAIN, + 0, 0x3, 0, mic_vol_tlv), + SOC_DOUBLE_R("Speaker Playback Switch", RT298_SPOL_GAIN, + RT298_SPOR_GAIN, RT298_MUTE_SFT, 1, 1), +}; + +/* Digital Mixer */ +static const struct snd_kcontrol_new rt298_front_mix[] = { + SOC_DAPM_SINGLE("DAC Switch", RT298_F_DAC_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("RECMIX Switch", RT298_F_RECMIX_SWITCH, + RT298_MUTE_SFT, 1, 1), +}; + +/* Analog Input Mixer */ +static const struct snd_kcontrol_new rt298_rec_mix[] = { + SOC_DAPM_SINGLE("Mic1 Switch", RT298_REC_MIC_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("I2S Switch", RT298_REC_I2S_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("Line1 Switch", RT298_REC_LINE_SWITCH, + RT298_MUTE_SFT, 1, 1), + SOC_DAPM_SINGLE("Beep Switch", RT298_REC_BEEP_SWITCH, + RT298_MUTE_SFT, 1, 1), +}; + +static const struct snd_kcontrol_new spo_enable_control = + SOC_DAPM_SINGLE("Switch", RT298_SET_PIN_SPK, + RT298_SET_PIN_SFT, 1, 0); + +static const struct snd_kcontrol_new hpol_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOL_GAIN, + RT298_MUTE_SFT, 1, 1); + +static const struct snd_kcontrol_new hpor_enable_control = + SOC_DAPM_SINGLE_AUTODISABLE("Switch", RT298_HPOR_GAIN, + RT298_MUTE_SFT, 1, 1); + +/* ADC0 source */ +static const char * const rt298_adc_src[] = { + "Mic", "RECMIX", "Dmic" +}; + +static const int rt298_adc_values[] = { + 0, 4, 5, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL( + rt298_adc0_enum, RT298_ADC0_MUX, RT298_ADC_SEL_SFT, + RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values); + +static const struct snd_kcontrol_new rt298_adc0_mux = + SOC_DAPM_ENUM("ADC 0 source", rt298_adc0_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL( + rt298_adc1_enum, RT298_ADC1_MUX, RT298_ADC_SEL_SFT, + RT298_ADC_SEL_MASK, rt298_adc_src, rt298_adc_values); + +static const struct snd_kcontrol_new rt298_adc1_mux = + SOC_DAPM_ENUM("ADC 1 source", rt298_adc1_enum); + +static const char * const rt298_dac_src[] = { + "Front", "Surround" +}; +/* HP-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt298_hpo_enum, RT298_HPO_MUX, + 0, rt298_dac_src); + +static const struct snd_kcontrol_new rt298_hpo_mux = +SOC_DAPM_ENUM("HPO source", rt298_hpo_enum); + +/* SPK-OUT source */ +static SOC_ENUM_SINGLE_DECL(rt298_spo_enum, RT298_SPK_MUX, + 0, rt298_dac_src); + +static const struct snd_kcontrol_new rt298_spo_mux = +SOC_DAPM_ENUM("SPO source", rt298_spo_enum); + +static int rt298_spk_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, + RT298_SPK_EAPD, RT298_SET_EAPD_HIGH); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, + RT298_SPK_EAPD, RT298_SET_EAPD_LOW); + break; + + default: + return 0; + } + + return 0; +} + +static int rt298_set_dmic1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0x20); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_write(codec, RT298_SET_PIN_DMIC1, 0); + break; + default: + return 0; + } + + return 0; +} + +static int rt298_adc_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + unsigned int nid; + + nid = (w->reg >> 20) & 0xff; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + snd_soc_update_bits(codec, + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), + 0x7080, 0x7000); + break; + case SND_SOC_DAPM_PRE_PMD: + snd_soc_update_bits(codec, + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, nid, 0), + 0x7080, 0x7080); + break; + default: + return 0; + } + + return 0; +} + +static int rt298_mic1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL3, 0xc000, 0x8000); + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL2, 0xc000, 0x8000); + break; + case SND_SOC_DAPM_POST_PMD: + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL3, 0xc000, 0x0000); + snd_soc_update_bits(codec, + RT298_A_BIAS_CTRL2, 0xc000, 0x0000); + break; + default: + return 0; + } + + return 0; +} + +static int rt298_vref_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + snd_soc_update_bits(codec, + RT298_CBJ_CTRL1, 0x0400, 0x0000); + mdelay(50); + break; + default: + return 0; + } + + return 0; +} + +static const struct snd_soc_dapm_widget rt298_dapm_widgets[] = { + + SND_SOC_DAPM_SUPPLY_S("HV", 1, RT298_POWER_CTRL1, + 12, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY("VREF", RT298_POWER_CTRL1, + 0, 1, rt298_vref_event, SND_SOC_DAPM_PRE_PMU), + SND_SOC_DAPM_SUPPLY_S("BG_MBIAS", 1, RT298_POWER_CTRL2, + 1, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT298_POWER_CTRL2, + 2, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LDO2", 1, RT298_POWER_CTRL2, + 3, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("VREF1", 1, RT298_POWER_CTRL2, + 4, 1, NULL, 0), + SND_SOC_DAPM_SUPPLY_S("LV", 2, RT298_POWER_CTRL1, + 13, 1, NULL, 0), + + + SND_SOC_DAPM_SUPPLY("MCLK MODE", RT298_PLL_CTRL1, + 5, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM, + 0, 0, rt298_mic1_event, SND_SOC_DAPM_PRE_PMU | + SND_SOC_DAPM_POST_PMD), + + /* Input Lines */ + SND_SOC_DAPM_INPUT("DMIC1 Pin"), + SND_SOC_DAPM_INPUT("DMIC2 Pin"), + SND_SOC_DAPM_INPUT("MIC1"), + SND_SOC_DAPM_INPUT("LINE1"), + SND_SOC_DAPM_INPUT("Beep"), + + /* DMIC */ + SND_SOC_DAPM_PGA_E("DMIC1", RT298_SET_POWER(RT298_DMIC1), 0, 1, + NULL, 0, rt298_set_dmic1_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_PGA("DMIC2", RT298_SET_POWER(RT298_DMIC2), 0, 1, + NULL, 0), + SND_SOC_DAPM_SUPPLY("DMIC Receiver", SND_SOC_NOPM, + 0, 0, NULL, 0), + + /* REC Mixer */ + SND_SOC_DAPM_MIXER("RECMIX", SND_SOC_NOPM, 0, 0, + rt298_rec_mix, ARRAY_SIZE(rt298_rec_mix)), + + /* ADCs */ + SND_SOC_DAPM_ADC("ADC 0", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_ADC("ADC 1", NULL, SND_SOC_NOPM, 0, 0), + + /* ADC Mux */ + SND_SOC_DAPM_MUX_E("ADC 0 Mux", RT298_SET_POWER(RT298_ADC_IN1), 0, 1, + &rt298_adc0_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_MUX_E("ADC 1 Mux", RT298_SET_POWER(RT298_ADC_IN2), 0, 1, + &rt298_adc1_mux, rt298_adc_event, SND_SOC_DAPM_PRE_PMD | + SND_SOC_DAPM_POST_PMU), + + /* Audio Interface */ + SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("AIF2RX", "AIF2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("AIF2TX", "AIF2 Capture", 0, SND_SOC_NOPM, 0, 0), + + /* Output Side */ + /* DACs */ + SND_SOC_DAPM_DAC("DAC 0", NULL, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC 1", NULL, SND_SOC_NOPM, 0, 0), + + /* Output Mux */ + SND_SOC_DAPM_MUX("SPK Mux", SND_SOC_NOPM, 0, 0, &rt298_spo_mux), + SND_SOC_DAPM_MUX("HPO Mux", SND_SOC_NOPM, 0, 0, &rt298_hpo_mux), + + SND_SOC_DAPM_SUPPLY("HP Power", RT298_SET_PIN_HPO, + RT298_SET_PIN_SFT, 0, NULL, 0), + + /* Output Mixer */ + SND_SOC_DAPM_MIXER("Front", RT298_SET_POWER(RT298_DAC_OUT1), 0, 1, + rt298_front_mix, ARRAY_SIZE(rt298_front_mix)), + SND_SOC_DAPM_PGA("Surround", RT298_SET_POWER(RT298_DAC_OUT2), 0, 1, + NULL, 0), + + /* Output Pga */ + SND_SOC_DAPM_SWITCH_E("SPO", SND_SOC_NOPM, 0, 0, + &spo_enable_control, rt298_spk_event, + SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_SWITCH("HPO L", SND_SOC_NOPM, 0, 0, + &hpol_enable_control), + SND_SOC_DAPM_SWITCH("HPO R", SND_SOC_NOPM, 0, 0, + &hpor_enable_control), + + /* Output Lines */ + SND_SOC_DAPM_OUTPUT("SPOL"), + SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_OUTPUT("HPO Pin"), + SND_SOC_DAPM_OUTPUT("SPDIF"), +}; + +static const struct snd_soc_dapm_route rt298_dapm_routes[] = { + + {"ADC 0", NULL, "MCLK MODE", is_mclk_mode}, + {"ADC 1", NULL, "MCLK MODE", is_mclk_mode}, + {"Front", NULL, "MCLK MODE", is_mclk_mode}, + {"Surround", NULL, "MCLK MODE", is_mclk_mode}, + + {"HP Power", NULL, "LDO1"}, + {"HP Power", NULL, "LDO2"}, + {"HP Power", NULL, "LV"}, + {"HP Power", NULL, "VREF1"}, + {"HP Power", NULL, "BG_MBIAS"}, + + {"MIC1", NULL, "LDO1"}, + {"MIC1", NULL, "LDO2"}, + {"MIC1", NULL, "HV"}, + {"MIC1", NULL, "LV"}, + {"MIC1", NULL, "VREF"}, + {"MIC1", NULL, "VREF1"}, + {"MIC1", NULL, "BG_MBIAS"}, + {"MIC1", NULL, "MIC1 Input Buffer"}, + + {"SPO", NULL, "LDO1"}, + {"SPO", NULL, "LDO2"}, + {"SPO", NULL, "HV"}, + {"SPO", NULL, "LV"}, + {"SPO", NULL, "VREF"}, + {"SPO", NULL, "VREF1"}, + {"SPO", NULL, "BG_MBIAS"}, + + {"DMIC1", NULL, "DMIC1 Pin"}, + {"DMIC2", NULL, "DMIC2 Pin"}, + {"DMIC1", NULL, "DMIC Receiver"}, + {"DMIC2", NULL, "DMIC Receiver"}, + + {"RECMIX", "Beep Switch", "Beep"}, + {"RECMIX", "Line1 Switch", "LINE1"}, + {"RECMIX", "Mic1 Switch", "MIC1"}, + + {"ADC 0 Mux", "Dmic", "DMIC1"}, + {"ADC 0 Mux", "RECMIX", "RECMIX"}, + {"ADC 0 Mux", "Mic", "MIC1"}, + {"ADC 1 Mux", "Dmic", "DMIC2"}, + {"ADC 1 Mux", "RECMIX", "RECMIX"}, + {"ADC 1 Mux", "Mic", "MIC1"}, + + {"ADC 0", NULL, "ADC 0 Mux"}, + {"ADC 1", NULL, "ADC 1 Mux"}, + + {"AIF1TX", NULL, "ADC 0"}, + {"AIF2TX", NULL, "ADC 1"}, + + {"DAC 0", NULL, "AIF1RX"}, + {"DAC 1", NULL, "AIF2RX"}, + + {"Front", "DAC Switch", "DAC 0"}, + {"Front", "RECMIX Switch", "RECMIX"}, + + {"Surround", NULL, "DAC 1"}, + + {"SPK Mux", "Front", "Front"}, + {"SPK Mux", "Surround", "Surround"}, + + {"HPO Mux", "Front", "Front"}, + {"HPO Mux", "Surround", "Surround"}, + + {"SPO", "Switch", "SPK Mux"}, + {"HPO L", "Switch", "HPO Mux"}, + {"HPO R", "Switch", "HPO Mux"}, + {"HPO L", NULL, "HP Power"}, + {"HPO R", NULL, "HP Power"}, + + {"SPOL", NULL, "SPO"}, + {"SPOR", NULL, "SPO"}, + {"HPO Pin", NULL, "HPO L"}, + {"HPO Pin", NULL, "HPO R"}, +}; + +static int rt298_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + unsigned int val = 0; + int d_len_code; + + switch (params_rate(params)) { + /* bit 14 0:48K 1:44.1K */ + case 44100: + case 48000: + break; + default: + dev_err(codec->dev, "Unsupported sample rate %d\n", + params_rate(params)); + return -EINVAL; + } + switch (rt298->sys_clk) { + case 12288000: + case 24576000: + if (params_rate(params) != 48000) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt298->sys_clk); + return -EINVAL; + } + break; + case 11289600: + case 22579200: + if (params_rate(params) != 44100) { + dev_err(codec->dev, "Sys_clk is not matched (%d %d)\n", + params_rate(params), rt298->sys_clk); + return -EINVAL; + } + break; + } + + if (params_channels(params) <= 16) { + /* bit 3:0 Number of Channel */ + val |= (params_channels(params) - 1); + } else { + dev_err(codec->dev, "Unsupported channels %d\n", + params_channels(params)); + return -EINVAL; + } + + d_len_code = 0; + switch (params_width(params)) { + /* bit 6:4 Bits per Sample */ + case 16: + d_len_code = 0; + val |= (0x1 << 4); + break; + case 32: + d_len_code = 2; + val |= (0x4 << 4); + break; + case 20: + d_len_code = 1; + val |= (0x2 << 4); + break; + case 24: + d_len_code = 2; + val |= (0x3 << 4); + break; + case 8: + d_len_code = 3; + break; + default: + return -EINVAL; + } + + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x0018, d_len_code << 3); + dev_dbg(codec->dev, "format val = 0x%x\n", val); + + snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x407f, val); + snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x407f, val); + + return 0; +} + +static int rt298_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_codec *codec = dai->codec; + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x800, 0x800); + break; + case SND_SOC_DAIFMT_CBS_CFS: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x800, 0x0); + break; + default: + return -EINVAL; + } + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x0); + break; + case SND_SOC_DAIFMT_LEFT_J: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x1 << 8); + break; + case SND_SOC_DAIFMT_DSP_A: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x2 << 8); + break; + case SND_SOC_DAIFMT_DSP_B: + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x300, 0x3 << 8); + break; + default: + return -EINVAL; + } + /* bit 15 Stream Type 0:PCM 1:Non-PCM */ + snd_soc_update_bits(codec, RT298_DAC_FORMAT, 0x8000, 0); + snd_soc_update_bits(codec, RT298_ADC_FORMAT, 0x8000, 0); + + return 0; +} + +static int rt298_set_dai_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(codec->dev, "%s freq=%d\n", __func__, freq); + + if (RT298_SCLK_S_MCLK == clk_id) { + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x0100, 0x0); + snd_soc_update_bits(codec, + RT298_PLL_CTRL1, 0x20, 0x20); + } else { + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x0100, 0x0100); + snd_soc_update_bits(codec, + RT298_PLL_CTRL, 0x4, 0x4); + snd_soc_update_bits(codec, + RT298_PLL_CTRL1, 0x20, 0x0); + } + + switch (freq) { + case 19200000: + if (RT298_SCLK_S_MCLK == clk_id) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x40, 0x40); + break; + case 24000000: + if (RT298_SCLK_S_MCLK == clk_id) { + dev_err(codec->dev, "Should not use MCLK\n"); + return -EINVAL; + } + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x40, 0x0); + break; + case 12288000: + case 11289600: + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x8, 0x0); + snd_soc_update_bits(codec, + RT298_CLK_DIV, 0xfc1e, 0x0004); + break; + case 24576000: + case 22579200: + snd_soc_update_bits(codec, + RT298_I2S_CTRL2, 0x8, 0x8); + snd_soc_update_bits(codec, + RT298_CLK_DIV, 0xfc1e, 0x5406); + break; + default: + dev_err(codec->dev, "Unsupported system clock\n"); + return -EINVAL; + } + + rt298->sys_clk = freq; + rt298->clk_id = clk_id; + + return 0; +} + +static int rt298_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio) +{ + struct snd_soc_codec *codec = dai->codec; + + dev_dbg(codec->dev, "%s ratio=%d\n", __func__, ratio); + if (50 == ratio) + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x1000, 0x1000); + else + snd_soc_update_bits(codec, + RT298_I2S_CTRL1, 0x1000, 0x0); + + + return 0; +} + +static int rt298_set_bias_level(struct snd_soc_codec *codec, + enum snd_soc_bias_level level) +{ + switch (level) { + case SND_SOC_BIAS_PREPARE: + if (SND_SOC_BIAS_STANDBY == + snd_soc_codec_get_bias_level(codec)) { + snd_soc_write(codec, + RT298_SET_AUDIO_POWER, AC_PWRST_D0); + snd_soc_update_bits(codec, 0x0d, 0x200, 0x200); + snd_soc_update_bits(codec, 0x52, 0x80, 0x0); + mdelay(20); + snd_soc_update_bits(codec, 0x0d, 0x200, 0x0); + snd_soc_update_bits(codec, 0x52, 0x80, 0x80); + } + break; + + case SND_SOC_BIAS_ON: + mdelay(30); + snd_soc_update_bits(codec, + RT298_CBJ_CTRL1, 0x0400, 0x0400); + + break; + + case SND_SOC_BIAS_STANDBY: + snd_soc_write(codec, + RT298_SET_AUDIO_POWER, AC_PWRST_D3); + snd_soc_update_bits(codec, + RT298_CBJ_CTRL1, 0x0400, 0x0000); + break; + + default: + break; + } + + return 0; +} + +static irqreturn_t rt298_irq(int irq, void *data) +{ + struct rt298_priv *rt298 = data; + bool hp = false; + bool mic = false; + int ret, status = 0; + + ret = rt298_jack_detect(rt298, &hp, &mic); + + /* Clear IRQ */ + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x1, 0x1); + + if (ret == 0) { + if (hp == true) + status |= SND_JACK_HEADPHONE; + + if (mic == true) + status |= SND_JACK_MICROPHONE; + + snd_soc_jack_report(rt298->jack, status, + SND_JACK_MICROPHONE | SND_JACK_HEADPHONE); + + pm_wakeup_event(&rt298->i2c->dev, 300); + } + + return IRQ_HANDLED; +} + +static int rt298_probe(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + rt298->codec = codec; + + if (rt298->i2c->irq) { + regmap_update_bits(rt298->regmap, + RT298_IRQ_CTRL, 0x2, 0x2); + + INIT_DELAYED_WORK(&rt298->jack_detect_work, + rt298_jack_detect_work); + schedule_delayed_work(&rt298->jack_detect_work, + msecs_to_jiffies(1250)); + } + + return 0; +} + +static int rt298_remove(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + cancel_delayed_work_sync(&rt298->jack_detect_work); + + return 0; +} + +#ifdef CONFIG_PM +static int rt298_suspend(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + rt298->is_hp_in = -1; + regcache_cache_only(rt298->regmap, true); + regcache_mark_dirty(rt298->regmap); + + return 0; +} + +static int rt298_resume(struct snd_soc_codec *codec) +{ + struct rt298_priv *rt298 = snd_soc_codec_get_drvdata(codec); + + regcache_cache_only(rt298->regmap, false); + rt298_index_sync(codec); + regcache_sync(rt298->regmap); + + return 0; +} +#else +#define rt298_suspend NULL +#define rt298_resume NULL +#endif + +#define RT298_STEREO_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) +#define RT298_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) + +static const struct snd_soc_dai_ops rt298_aif_dai_ops = { + .hw_params = rt298_hw_params, + .set_fmt = rt298_set_dai_fmt, + .set_sysclk = rt298_set_dai_sysclk, + .set_bclk_ratio = rt298_set_bclk_ratio, +}; + +static struct snd_soc_dai_driver rt298_dai[] = { + { + .name = "rt298-aif1", + .id = RT298_AIF1, + .playback = { + .stream_name = "AIF1 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .capture = { + .stream_name = "AIF1 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .ops = &rt298_aif_dai_ops, + .symmetric_rates = 1, + }, + { + .name = "rt298-aif2", + .id = RT298_AIF2, + .playback = { + .stream_name = "AIF2 Playback", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .capture = { + .stream_name = "AIF2 Capture", + .channels_min = 1, + .channels_max = 2, + .rates = RT298_STEREO_RATES, + .formats = RT298_FORMATS, + }, + .ops = &rt298_aif_dai_ops, + .symmetric_rates = 1, + }, + +}; + +static struct snd_soc_codec_driver soc_codec_dev_rt298 = { + .probe = rt298_probe, + .remove = rt298_remove, + .suspend = rt298_suspend, + .resume = rt298_resume, + .set_bias_level = rt298_set_bias_level, + .idle_bias_off = true, + .controls = rt298_snd_controls, + .num_controls = ARRAY_SIZE(rt298_snd_controls), + .dapm_widgets = rt298_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rt298_dapm_widgets), + .dapm_routes = rt298_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(rt298_dapm_routes), +}; + +static const struct regmap_config rt298_regmap = { + .reg_bits = 32, + .val_bits = 32, + .max_register = 0x02370100, + .volatile_reg = rt298_volatile_register, + .readable_reg = rt298_readable_register, + .reg_write = rl6347a_hw_write, + .reg_read = rl6347a_hw_read, + .cache_type = REGCACHE_RBTREE, + .reg_defaults = rt298_reg, + .num_reg_defaults = ARRAY_SIZE(rt298_reg), +}; + +static const struct i2c_device_id rt298_i2c_id[] = { + {"rt298", 0}, + {} +}; +MODULE_DEVICE_TABLE(i2c, rt298_i2c_id); + +static const struct acpi_device_id rt298_acpi_match[] = { + { "INT343A", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, rt298_acpi_match); + +static int rt298_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct rt298_platform_data *pdata = dev_get_platdata(&i2c->dev); + struct rt298_priv *rt298; + struct device *dev = &i2c->dev; + const struct acpi_device_id *acpiid; + int i, ret; + + pr_info("%s\n", __func__); + + rt298 = devm_kzalloc(&i2c->dev, sizeof(*rt298), + GFP_KERNEL); + if (NULL == rt298) + return -ENOMEM; + + rt298->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt298_regmap); + if (IS_ERR(rt298->regmap)) { + ret = PTR_ERR(rt298->regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + regmap_read(rt298->regmap, + RT298_GET_PARAM(AC_NODE_ROOT, AC_PAR_VENDOR_ID), &ret); + if (ret != RT298_VENDOR_ID) { + dev_err(&i2c->dev, + "Device with ID register %#x is not rt298\n", ret); + return -ENODEV; + } + + rt298->index_cache = rt298_index_def; + rt298->index_cache_size = INDEX_CACHE_SIZE; + rt298->i2c = i2c; + i2c_set_clientdata(i2c, rt298); + + /* restore codec default */ + for (i = 0; i < INDEX_CACHE_SIZE; i++) + regmap_write(rt298->regmap, rt298->index_cache[i].reg, + rt298->index_cache[i].def); + for (i = 0; i < ARRAY_SIZE(rt298_reg); i++) + regmap_write(rt298->regmap, rt298_reg[i].reg, + rt298_reg[i].def); + + if (pdata) + rt298->pdata = *pdata; + + /* enable jack combo mode on supported devices */ + acpiid = acpi_match_device(dev->driver->acpi_match_table, dev); + if (acpiid) { + rt298->pdata = *(struct rt298_platform_data *) + acpiid->driver_data; + } + + /* VREF Charging */ + regmap_update_bits(rt298->regmap, 0x04, 0x80, 0x80); + regmap_update_bits(rt298->regmap, 0x1b, 0x860, 0x860); + /* Vref2 */ + regmap_update_bits(rt298->regmap, 0x08, 0x20, 0x20); + + regmap_write(rt298->regmap, RT298_SET_AUDIO_POWER, AC_PWRST_D3); + + for (i = 0; i < RT298_POWER_REG_LEN; i++) + regmap_write(rt298->regmap, + RT298_SET_POWER(rt298_support_power_controls[i]), + AC_PWRST_D1); + + if (!rt298->pdata.cbj_en) { + regmap_write(rt298->regmap, RT298_CBJ_CTRL2, 0x0000); + regmap_write(rt298->regmap, RT298_MIC1_DET_CTRL, 0x0816); + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xf000, 0xb000); + } else { + regmap_update_bits(rt298->regmap, + RT298_CBJ_CTRL1, 0xf000, 0x5000); + } + + mdelay(10); + + if (!rt298->pdata.gpio2_en) + regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0x4000); + else + regmap_write(rt298->regmap, RT298_SET_DMIC2_DEFAULT, 0); + + mdelay(10); + + regmap_write(rt298->regmap, RT298_MISC_CTRL1, 0x0000); + regmap_update_bits(rt298->regmap, + RT298_WIND_FILTER_CTRL, 0x0082, 0x0082); + regmap_update_bits(rt298->regmap, RT298_IRQ_CTRL, 0x2, 0x2); + rt298->is_hp_in = -1; + + if (rt298->i2c->irq) { + ret = request_threaded_irq(rt298->i2c->irq, NULL, rt298_irq, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt298", rt298); + if (ret != 0) { + dev_err(&i2c->dev, + "Failed to reguest IRQ: %d\n", ret); + return ret; + } + } + + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt298, + rt298_dai, ARRAY_SIZE(rt298_dai)); + + return ret; +} + +static int rt298_i2c_remove(struct i2c_client *i2c) +{ + struct rt298_priv *rt298 = i2c_get_clientdata(i2c); + + if (i2c->irq) + free_irq(i2c->irq, rt298); + snd_soc_unregister_codec(&i2c->dev); + + return 0; +} + + +static struct i2c_driver rt298_i2c_driver = { + .driver = { + .name = "rt298", + .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(rt298_acpi_match), + }, + .probe = rt298_i2c_probe, + .remove = rt298_i2c_remove, + .id_table = rt298_i2c_id, +}; + +module_i2c_driver(rt298_i2c_driver); + +MODULE_DESCRIPTION("ASoC RT298 driver"); +MODULE_AUTHOR("Bard Liao "); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/rt298.h b/sound/soc/codecs/rt298.h new file mode 100644 index 0000000000000..31da16265f2b1 --- /dev/null +++ b/sound/soc/codecs/rt298.h @@ -0,0 +1,206 @@ +/* + * rt298.h -- RT298 ALSA SoC audio driver + * + * Copyright 2011 Realtek Microelectronics + * Author: Johnny Hsu + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __RT298_H__ +#define __RT298_H__ + +#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D) + +#define RT298_AUDIO_FUNCTION_GROUP 0x01 +#define RT298_DAC_OUT1 0x02 +#define RT298_DAC_OUT2 0x03 +#define RT298_DIG_CVT 0x06 +#define RT298_ADC_IN1 0x09 +#define RT298_ADC_IN2 0x08 +#define RT298_MIXER_IN 0x0b +#define RT298_MIXER_OUT1 0x0c +#define RT298_MIXER_OUT2 0x0d +#define RT298_DMIC1 0x12 +#define RT298_DMIC2 0x13 +#define RT298_SPK_OUT 0x14 +#define RT298_MIC1 0x18 +#define RT298_LINE1 0x1a +#define RT298_BEEP 0x1d +#define RT298_SPDIF 0x1e +#define RT298_VENDOR_REGISTERS 0x20 +#define RT298_HP_OUT 0x21 +#define RT298_MIXER_IN1 0x22 +#define RT298_MIXER_IN2 0x23 + +#define RT298_SET_PIN_SFT 6 +#define RT298_SET_PIN_ENABLE 0x40 +#define RT298_SET_PIN_DISABLE 0 +#define RT298_SET_EAPD_HIGH 0x2 +#define RT298_SET_EAPD_LOW 0 + +#define RT298_MUTE_SFT 7 + +/* Verb commands */ +#define RT298_GET_PARAM(NID, PARAM) VERB_CMD(AC_VERB_PARAMETERS, NID, PARAM) +#define RT298_SET_POWER(NID) VERB_CMD(AC_VERB_SET_POWER_STATE, NID, 0) +#define RT298_SET_AUDIO_POWER RT298_SET_POWER(RT298_AUDIO_FUNCTION_GROUP) +#define RT298_SET_HPO_POWER RT298_SET_POWER(RT298_HP_OUT) +#define RT298_SET_SPK_POWER RT298_SET_POWER(RT298_SPK_OUT) +#define RT298_SET_DMIC1_POWER RT298_SET_POWER(RT298_DMIC1) +#define RT298_SPK_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_SPK_OUT, 0) +#define RT298_HPO_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_HP_OUT, 0) +#define RT298_ADC0_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN1, 0) +#define RT298_ADC1_MUX\ + VERB_CMD(AC_VERB_SET_CONNECT_SEL, RT298_MIXER_IN2, 0) +#define RT298_SET_MIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_MIC1, 0) +#define RT298_SET_PIN_HPO\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_HP_OUT, 0) +#define RT298_SET_PIN_SPK\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPK_OUT, 0) +#define RT298_SET_PIN_DMIC1\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_DMIC1, 0) +#define RT298_SET_PIN_SPDIF\ + VERB_CMD(AC_VERB_SET_PIN_WIDGET_CONTROL, RT298_SPDIF, 0) +#define RT298_SET_PIN_DIG_CVT\ + VERB_CMD(AC_VERB_SET_DIGI_CONVERT_1, RT298_DIG_CVT, 0) +#define RT298_SPK_EAPD\ + VERB_CMD(AC_VERB_SET_EAPD_BTLENABLE, RT298_SPK_OUT, 0) +#define RT298_SET_AMP_GAIN_HPO\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0) +#define RT298_SET_AMP_GAIN_ADC_IN1\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0) +#define RT298_SET_AMP_GAIN_ADC_IN2\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN2, 0) +#define RT298_GET_HP_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_HP_OUT, 0) +#define RT298_GET_MIC1_SENSE\ + VERB_CMD(AC_VERB_GET_PIN_SENSE, RT298_MIC1, 0) +#define RT298_SET_DMIC2_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_DMIC2, 0) +#define RT298_SET_SPDIF_DEFAULT\ + VERB_CMD(AC_VERB_SET_CONFIG_DEFAULT_BYTES_3, RT298_SPDIF, 0) +#define RT298_DACL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0xa000) +#define RT298_DACR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_DAC_OUT1, 0x9000) +#define RT298_ADCL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x6000) +#define RT298_ADCR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_ADC_IN1, 0x5000) +#define RT298_MIC_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIC1, 0x7000) +#define RT298_SPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0xa000) +#define RT298_SPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_SPK_OUT, 0x9000) +#define RT298_HPOL_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0xa000) +#define RT298_HPOR_GAIN\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_HP_OUT, 0x9000) +#define RT298_F_DAC_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7000) +#define RT298_F_RECMIX_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_OUT1, 0x7100) +#define RT298_REC_MIC_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7000) +#define RT298_REC_I2S_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7100) +#define RT298_REC_LINE_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7200) +#define RT298_REC_BEEP_SWITCH\ + VERB_CMD(AC_VERB_SET_AMP_GAIN_MUTE, RT298_MIXER_IN, 0x7300) +#define RT298_DAC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_DAC_OUT1, 0) +#define RT298_ADC_FORMAT\ + VERB_CMD(AC_VERB_SET_STREAM_FORMAT, RT298_ADC_IN1, 0) +#define RT298_COEF_INDEX\ + VERB_CMD(AC_VERB_SET_COEF_INDEX, RT298_VENDOR_REGISTERS, 0) +#define RT298_PROC_COEF\ + VERB_CMD(AC_VERB_SET_PROC_COEF, RT298_VENDOR_REGISTERS, 0) + +/* Index registers */ +#define RT298_A_BIAS_CTRL1 0x01 +#define RT298_A_BIAS_CTRL2 0x02 +#define RT298_POWER_CTRL1 0x03 +#define RT298_A_BIAS_CTRL3 0x04 +#define RT298_POWER_CTRL2 0x08 +#define RT298_I2S_CTRL1 0x09 +#define RT298_I2S_CTRL2 0x0a +#define RT298_CLK_DIV 0x0b +#define RT298_DC_GAIN 0x0d +#define RT298_POWER_CTRL3 0x0f +#define RT298_MIC1_DET_CTRL 0x19 +#define RT298_MISC_CTRL1 0x20 +#define RT298_IRQ_CTRL 0x33 +#define RT298_WIND_FILTER_CTRL 0x46 +#define RT298_PLL_CTRL1 0x49 +#define RT298_CBJ_CTRL1 0x4f +#define RT298_CBJ_CTRL2 0x50 +#define RT298_PLL_CTRL 0x63 +#define RT298_DEPOP_CTRL1 0x66 +#define RT298_DEPOP_CTRL2 0x67 +#define RT298_DEPOP_CTRL3 0x68 +#define RT298_DEPOP_CTRL4 0x69 + +/* SPDIF (0x06) */ +#define RT298_SPDIF_SEL_SFT 0 +#define RT298_SPDIF_SEL_PCM0 0 +#define RT298_SPDIF_SEL_PCM1 1 +#define RT298_SPDIF_SEL_SPOUT 2 +#define RT298_SPDIF_SEL_PP 3 + +/* RECMIX (0x0b) */ +#define RT298_M_REC_BEEP_SFT 0 +#define RT298_M_REC_LINE1_SFT 1 +#define RT298_M_REC_MIC1_SFT 2 +#define RT298_M_REC_I2S_SFT 3 + +/* Front (0x0c) */ +#define RT298_M_FRONT_DAC_SFT 0 +#define RT298_M_FRONT_REC_SFT 1 + +/* SPK-OUT (0x14) */ +#define RT298_M_SPK_MUX_SFT 14 +#define RT298_SPK_SEL_MASK 0x1 +#define RT298_SPK_SEL_SFT 0 +#define RT298_SPK_SEL_F 0 +#define RT298_SPK_SEL_S 1 + +/* HP-OUT (0x21) */ +#define RT298_M_HP_MUX_SFT 14 +#define RT298_HP_SEL_MASK 0x1 +#define RT298_HP_SEL_SFT 0 +#define RT298_HP_SEL_F 0 +#define RT298_HP_SEL_S 1 + +/* ADC (0x22) (0x23) */ +#define RT298_ADC_SEL_MASK 0x7 +#define RT298_ADC_SEL_SFT 0 +#define RT298_ADC_SEL_SURR 0 +#define RT298_ADC_SEL_FRONT 1 +#define RT298_ADC_SEL_DMIC 2 +#define RT298_ADC_SEL_BEEP 4 +#define RT298_ADC_SEL_LINE1 5 +#define RT298_ADC_SEL_I2S 6 +#define RT298_ADC_SEL_MIC1 7 + +#define RT298_SCLK_S_MCLK 0 +#define RT298_SCLK_S_PLL 1 + +enum { + RT298_AIF1, + RT298_AIF2, + RT298_AIFS, +}; + +int rt298_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack); + +#endif /* __RT298_H__ */ + -- GitLab From 5ddfb12e90c73cf86881345be422e09c367f6981 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Wed, 8 Jul 2015 11:17:39 -0700 Subject: [PATCH 0642/7006] HID: cp2112: support large i2c transfers cp2112_i2c_xfer() only reads up to 61 bytes, returning EIO on longers reads. The fix is to wrap a loop around cp2112_read() to pick up all the returned data. Signed-off-by: Ellen Wang Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index a2dbbbe0d8d7e..75398cb84fde2 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -511,13 +511,30 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (!(msgs->flags & I2C_M_RD)) goto finish; - ret = cp2112_read(dev, msgs->buf, msgs->len); - if (ret < 0) - goto power_normal; - if (ret != msgs->len) { - hid_warn(hdev, "short read: %d < %d\n", ret, msgs->len); - ret = -EIO; - goto power_normal; + for (count = 0; count < msgs->len;) { + ret = cp2112_read(dev, msgs->buf + count, msgs->len - count); + if (ret < 0) + goto power_normal; + if (ret == 0) { + hid_err(hdev, "read returned 0\n"); + ret = -EIO; + goto power_normal; + } + count += ret; + if (count > msgs->len) { + /* + * The hardware returned too much data. + * This is mostly harmless because cp2112_read() + * has a limit check so didn't overrun our + * buffer. Nevertheless, we return an error + * because something is seriously wrong and + * it shouldn't go unnoticed. + */ + hid_err(hdev, "long read: %d > %zd\n", + ret, msgs->len - count + ret); + ret = -EIO; + goto power_normal; + } } finish: -- GitLab From 24d9b755ab2b44ec56723cd8e6b578985a1f1c76 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 8 Jul 2015 21:26:02 +0200 Subject: [PATCH 0643/7006] ALSA: hda: Delete an unnecessary check before the function call "kobject_put" The kobject_put() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Takashi Iwai --- sound/hda/hdac_sysfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index 0a6ce3b84cc47..089b35f6f1086 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -321,8 +321,7 @@ static void widget_tree_free(struct hdac_device *codec) free_widget_node(*p, &widget_node_group); kfree(tree->nodes); } - if (tree->root) - kobject_put(tree->root); + kobject_put(tree->root); kfree(tree); codec->widgets = NULL; } -- GitLab From 0925636042170e0b6716cd86635899c5f4258f69 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Mon, 6 Jul 2015 16:48:31 -0700 Subject: [PATCH 0644/7006] HID: rmi: Disable scanning if the device is not a wake source Some touchpads are configured with firmware which continues to scan for fingers at a minimal scan rate even after receiving the HID power sleep command. This allows a finger touching the touchpad to genrate a wake event. This patch ensures that scanning is disabled if the touchpad is not a wake source and ensures scanning is enabled on resume. Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 56 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 4cf80bb276dc3..af191a265b80f 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -33,6 +33,9 @@ #define RMI_READ_DATA_PENDING 1 #define RMI_STARTED 2 +#define RMI_SLEEP_NORMAL 0x0 +#define RMI_SLEEP_DEEP_SLEEP 0x1 + /* device flags */ #define RMI_DEVICE BIT(0) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) @@ -126,6 +129,8 @@ struct rmi_data { unsigned long device_flags; unsigned long firmware_id; + + u8 f01_ctrl0; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -532,9 +537,51 @@ static int rmi_event(struct hid_device *hdev, struct hid_field *field, } #ifdef CONFIG_PM +static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + u8 f01_ctrl0; + + f01_ctrl0 = (data->f01_ctrl0 & ~0x3) | sleep_mode; + + ret = rmi_write(hdev, data->f01.control_base_addr, + &f01_ctrl0); + if (ret) { + hid_err(hdev, "can not write sleep mode\n"); + return ret; + } + + return 0; +} + +static int rmi_suspend(struct hid_device *hdev, pm_message_t message) +{ + if (!device_may_wakeup(hdev->dev.parent)) + return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP); + + return 0; +} + static int rmi_post_reset(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + int ret; + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret) { + hid_err(hdev, "can not set rmi mode\n"); + return ret; + } + + if (!device_may_wakeup(hdev->dev.parent)) { + ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL); + if (ret) { + hid_err(hdev, "can not write sleep mode\n"); + return ret; + } + } + + return ret; } static int rmi_post_resume(struct hid_device *hdev) @@ -732,6 +779,12 @@ static int rmi_populate_f01(struct hid_device *hdev) data->firmware_id += info[2] * 65536; } + ret = rmi_read(hdev, data->f01.control_base_addr, &data->f01_ctrl0); + + if (ret) { + hid_err(hdev, "can not read f01 ctrl0\n"); + return ret; + } return 0; } @@ -1273,6 +1326,7 @@ static struct hid_driver rmi_driver = { .input_mapping = rmi_input_mapping, .input_configured = rmi_input_configured, #ifdef CONFIG_PM + .suspend = rmi_suspend, .resume = rmi_post_resume, .reset_resume = rmi_post_reset, #endif -- GitLab From 67e123ff0e9a71fcf19f83827d59f73076f5bd1a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 9 Jul 2015 08:08:15 +0200 Subject: [PATCH 0645/7006] HID: wacom: Delete unnecessary checks before the function call "input_free_device" The input_free_device() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 4c0ffca97befd..936ad7770ec3a 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1149,12 +1149,9 @@ static void wacom_free_inputs(struct wacom *wacom) { struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - if (wacom_wac->pen_input) - input_free_device(wacom_wac->pen_input); - if (wacom_wac->touch_input) - input_free_device(wacom_wac->touch_input); - if (wacom_wac->pad_input) - input_free_device(wacom_wac->pad_input); + input_free_device(wacom_wac->pen_input); + input_free_device(wacom_wac->touch_input); + input_free_device(wacom_wac->pad_input); wacom_wac->pen_input = NULL; wacom_wac->touch_input = NULL; wacom_wac->pad_input = NULL; -- GitLab From 1055e0687f581cf988bb2239a00d1396e18ef114 Mon Sep 17 00:00:00 2001 From: Chad Versace Date: Thu, 9 Jul 2015 01:38:42 -0700 Subject: [PATCH 0646/7006] drm/fourcc: Add formats R8, RG88, GR88 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Kodi/XBMC developers want to transcode NV12 to RGB with OpenGL shaders, importing the two source planes through EGL_EXT_image_dma_buf_import. That requires importing the Y plane as an R8 EGLImage and the UV plane as either an RG88 or GR88 EGLImage. CC: Peter Frühberger Cc: Rainer Hochecker Cc: Benjamin Widawsky Reviewed-by: Pekka Paalanen Signed-off-by: Chad Versace --- include/uapi/drm/drm_fourcc.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/include/uapi/drm/drm_fourcc.h b/include/uapi/drm/drm_fourcc.h index 2f295cde657e2..8c5e8b91a3cbb 100644 --- a/include/uapi/drm/drm_fourcc.h +++ b/include/uapi/drm/drm_fourcc.h @@ -34,6 +34,13 @@ /* color index */ #define DRM_FORMAT_C8 fourcc_code('C', '8', ' ', ' ') /* [7:0] C */ +/* 8 bpp Red */ +#define DRM_FORMAT_R8 fourcc_code('R', '8', ' ', ' ') /* [7:0] R */ + +/* 16 bpp RG */ +#define DRM_FORMAT_RG88 fourcc_code('R', 'G', '8', '8') /* [15:0] R:G 8:8 little endian */ +#define DRM_FORMAT_GR88 fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */ + /* 8 bpp RGB */ #define DRM_FORMAT_RGB332 fourcc_code('R', 'G', 'B', '8') /* [7:0] R:G:B 3:3:2 */ #define DRM_FORMAT_BGR233 fourcc_code('B', 'G', 'R', '8') /* [7:0] B:G:R 2:3:3 */ -- GitLab From 169de1316c1e69ad169d81c60549479640461630 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 8 Jul 2015 16:21:31 -0700 Subject: [PATCH 0647/7006] drm/i915: PSR: Flush means invalidate + flush Since flush actually means invalidate + flush we need to force psr exit on PSR flush. On Core platforms there is no way to disable hw tracking and do the pure sw tracking so we simulate it by fully disable psr and reschedule a enable back. So a good idea is to minimize sequential disable/enable in cases we know that HW tracking like when flush has been originated by a flip. Also flip had just invalidated it already. It also uses origin to minimize the a bit the amount of disable/enabled, mainly when flip already had invalidated. With this patch in place it is possible to do a flush on dirty areas properly in a following patch. v2: Remove duplicated exit on HSW+Sprites as pointed out by Paulo. Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 3 +- drivers/gpu/drm/i915/intel_frontbuffer.c | 2 +- drivers/gpu/drm/i915/intel_psr.c | 40 +++++++++++++----------- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index beeb4d326cbea..c8635110a96db 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1329,7 +1329,8 @@ void intel_psr_disable(struct intel_dp *intel_dp); void intel_psr_invalidate(struct drm_device *dev, unsigned frontbuffer_bits); void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits); + unsigned frontbuffer_bits, + enum fb_op_origin origin); void intel_psr_init(struct drm_device *dev); void intel_psr_single_frame_update(struct drm_device *dev, unsigned frontbuffer_bits); diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index cb5a6f0447e7c..e73d2ff0d9b82 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -128,7 +128,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, return; intel_edp_drrs_flush(dev, frontbuffer_bits); - intel_psr_flush(dev, frontbuffer_bits); + intel_psr_flush(dev, frontbuffer_bits, origin); intel_fbc_flush(dev_priv, frontbuffer_bits); } diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index d79ba58637d72..6db043f3c1ad7 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -680,6 +680,7 @@ void intel_psr_invalidate(struct drm_device *dev, * intel_psr_flush - Flush PSR * @dev: DRM device * @frontbuffer_bits: frontbuffer plane tracking bits + * @origin: which operation caused the flush * * Since the hardware frontbuffer tracking has gaps we need to integrate * with the software frontbuffer tracking. This function gets called every @@ -689,7 +690,7 @@ void intel_psr_invalidate(struct drm_device *dev, * Dirty frontbuffers relevant to PSR are tracked in busy_frontbuffer_bits. */ void intel_psr_flush(struct drm_device *dev, - unsigned frontbuffer_bits) + unsigned frontbuffer_bits, enum fb_op_origin origin) { struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; @@ -707,24 +708,25 @@ void intel_psr_flush(struct drm_device *dev, frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe); dev_priv->psr.busy_frontbuffer_bits &= ~frontbuffer_bits; - /* - * On Haswell sprite plane updates don't result in a psr invalidating - * signal in the hardware. Which means we need to manually fake this in - * software for all flushes, not just when we've seen a preceding - * invalidation through frontbuffer rendering. - */ - if (IS_HASWELL(dev) && - (frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe))) - intel_psr_exit(dev); - - /* - * On Valleyview and Cherryview we don't use hardware tracking so - * any plane updates or cursor moves don't result in a PSR - * invalidating. Which means we need to manually fake this in - * software for all flushes, not just when we've seen a preceding - * invalidation through frontbuffer rendering. */ - if (frontbuffer_bits && !HAS_DDI(dev)) - intel_psr_exit(dev); + if (HAS_DDI(dev)) { + /* + * By definition every flush should mean invalidate + flush, + * however on core platforms let's minimize the + * disable/re-enable so we can avoid the invalidate when flip + * originated the flush. + */ + if (frontbuffer_bits && origin != ORIGIN_FLIP) + intel_psr_exit(dev); + } else { + /* + * On Valleyview and Cherryview we don't use hardware tracking + * so any plane updates or cursor moves don't result in a PSR + * invalidating. Which means we need to manually fake this in + * software for all flushes. + */ + if (frontbuffer_bits) + intel_psr_exit(dev); + } if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits) schedule_delayed_work(&dev_priv->psr.work, -- GitLab From 86c985883edeba570c9b6679827556bed2c6ecdc Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 8 Jul 2015 16:22:45 -0700 Subject: [PATCH 0648/7006] drm/i915: dirty fb operation flushsing frontbuffer Let's do a frontbuffer flush on dirty fb. To be used for DIRTYFB drm ioctl. This patch solves the biggest PSR known issue, that is missed screen updates during boot, mainly when there is a splash screen involved like Plymouth. Previously PSR was being invalidated by fbdev and Plymounth was taking control with PSR yet invalidated and could get screen updates normally. However with some atomic modeset changes Pymouth modeset over ioctl was now causing frontbuffer flushes making PSR gets back to work while it cannot track the screen updates and exit properly. By adding this flush on dirtyfb we properly track frontbuffer writes and properly exit PSR. Actually all mmap_wc users should call this dirty callback in order to have a proper frontbuffer tracking. In the future it can be extended to return 0 if the whole screen has being flushed or the number of rects flushed as Chris suggested. v2: Remove ORIGIN_FB_DIRTY and use ORIGIN_GTT instead since dirty callback is just called after few screen updates and not on everyone as pointed by Daniel. v3: Use flush instead of invalidate since flush means invalidate + flush and dirty means drawn had finished and it can be flushed. v4: Remove PSR from subject since it is purely frontbuffer tracking change and that can be useful for FBC as well. Cc: Chris Wilson Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni [danvet: Fix alignment as spotted by Paulo.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4bcbff9793d43..c465a52a38bc0 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14385,9 +14385,27 @@ static int intel_user_framebuffer_create_handle(struct drm_framebuffer *fb, return drm_gem_handle_create(file, &obj->base, handle); } +static int intel_user_framebuffer_dirty(struct drm_framebuffer *fb, + struct drm_file *file, + unsigned flags, unsigned color, + struct drm_clip_rect *clips, + unsigned num_clips) +{ + struct drm_device *dev = fb->dev; + struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb); + struct drm_i915_gem_object *obj = intel_fb->obj; + + mutex_lock(&dev->struct_mutex); + intel_fb_obj_flush(obj, false, ORIGIN_GTT); + mutex_unlock(&dev->struct_mutex); + + return 0; +} + static const struct drm_framebuffer_funcs intel_fb_funcs = { .destroy = intel_user_framebuffer_destroy, .create_handle = intel_user_framebuffer_create_handle, + .dirty = intel_user_framebuffer_dirty, }; static -- GitLab From 76f2e13d5597d72c4f88509d0d183e4a8512b01f Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 8 Jul 2015 18:08:38 -0300 Subject: [PATCH 0649/7006] drm/i915: fix intel_fb_obj_flush documentation Reported by the kbuild test robot. Regression introduced by: commit de152b627eb3018de91ec5c5a50b38e17d80a88b Author: Rodrigo Vivi Date: Tue Jul 7 16:28:51 2015 -0700 drm/i915: Add origin to frontbuffer tracking flush (I reviewed this commit, so it's also my fault) Signed-off-by: Paulo Zanoni Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_frontbuffer.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index e73d2ff0d9b82..e22d0b1423923 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -136,6 +136,7 @@ void intel_frontbuffer_flush(struct drm_device *dev, * intel_fb_obj_flush - flush frontbuffer object * @obj: GEM object to flush * @retire: set when retiring asynchronous rendering + * @origin: which operation caused the flush * * This function gets called every time rendering on the given object has * completed and frontbuffer caching can be started again. If @retire is true -- GitLab From b6c2aa5187ac59c8c6728ae09934390c3757f2bf Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 8 Jul 2015 18:08:37 -0300 Subject: [PATCH 0650/7006] drm/i915: intel_frontbuffer_flush can now be static So make it static. Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 3 --- drivers/gpu/drm/i915/intel_frontbuffer.c | 6 +++--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index c8635110a96db..b9c01c5b881fd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -977,9 +977,6 @@ void intel_frontbuffer_flip_prepare(struct drm_device *dev, unsigned frontbuffer_bits); void intel_frontbuffer_flip_complete(struct drm_device *dev, unsigned frontbuffer_bits); -void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits, - enum fb_op_origin origin); void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits); unsigned int intel_fb_align_height(struct drm_device *dev, diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index e22d0b1423923..c405c2deb8bf8 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -113,9 +113,9 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj, * * Can be called without any locks held. */ -void intel_frontbuffer_flush(struct drm_device *dev, - unsigned frontbuffer_bits, - enum fb_op_origin origin) +static void intel_frontbuffer_flush(struct drm_device *dev, + unsigned frontbuffer_bits, + enum fb_op_origin origin) { struct drm_i915_private *dev_priv = to_i915(dev); -- GitLab From cc2e26a7c57924b31e9c5ac7b3d0d814253c9285 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 8 Jul 2015 18:08:39 -0300 Subject: [PATCH 0651/7006] drm/i915: fix intel_frontbuffer_flip documentation Reported by the kbuild test robot. Regression introduced by: commit fdbff9282c0f5f61ffc87d57461b04d943250910 Author: Daniel Vetter Date: Thu Jun 18 11:23:24 2015 +0200 drm/i915: Clear fb_tracking.busy_bits also for synchronous flips (I reviewed this commit, so it's also my fault) Signed-off-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 1 - drivers/gpu/drm/i915/intel_frontbuffer.c | 1 - 2 files changed, 2 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index e82205ee3d5fd..1ca1171b16e51 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4012,7 +4012,6 @@ int num_ioctls; Frontbuffer Tracking !Pdrivers/gpu/drm/i915/intel_frontbuffer.c frontbuffer tracking !Idrivers/gpu/drm/i915/intel_frontbuffer.c -!Fdrivers/gpu/drm/i915/intel_drv.h intel_frontbuffer_flip !Fdrivers/gpu/drm/i915/i915_gem.c i915_gem_track_fb diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c index c405c2deb8bf8..777b1d3ccd419 100644 --- a/drivers/gpu/drm/i915/intel_frontbuffer.c +++ b/drivers/gpu/drm/i915/intel_frontbuffer.c @@ -229,7 +229,6 @@ void intel_frontbuffer_flip_complete(struct drm_device *dev, * * Can be called without any locks held. */ - void intel_frontbuffer_flip(struct drm_device *dev, unsigned frontbuffer_bits) { -- GitLab From 7a2c52b61fd71eddda3385006962630444d15b9e Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:52 +0530 Subject: [PATCH 0652/7006] ASoC: Intel: Add helper to poll register for DSP status This patch adds helper to poll register for DSP status. Signed-off-by: Subhransu S. Prusty Signed-off-by: Kp, Jeeja Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp.c | 43 ++++++++++++++++++++++++++++++++ sound/soc/intel/common/sst-dsp.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index 64e94212d2d2b..cc25f4c202afe 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "sst-dsp.h" #include "sst-dsp-priv.h" @@ -222,6 +223,48 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, } EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); +int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, + u32 target, u32 timeout, char *operation) +{ + int time, ret; + u32 reg; + bool done = false; + + /* + * we will poll for couple of ms using mdelay, if not successful + * then go to longer sleep using usleep_range + */ + + /* check if set state successful */ + for (time = 0; time < 5; time++) { + if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) { + done = true; + break; + } + mdelay(1); + } + + if (done == false) { + /* sleeping in 10ms steps so adjust timeout value */ + timeout /= 10; + + for (time = 0; time < timeout; time++) { + if ((sst_dsp_shim_read_unlocked(ctx, offset) & mask) == target) + break; + + usleep_range(5000, 10000); + } + } + + reg = sst_dsp_shim_read_unlocked(ctx, offset); + dev_info(ctx->dev, "FW Poll Status: reg=%#x %s %s\n", reg, operation, + (time < timeout) ? "successful" : "timedout"); + ret = time < timeout ? 0 : -ETIME; + + return ret; +} +EXPORT_SYMBOL_GPL(sst_dsp_register_poll); + void sst_dsp_dump(struct sst_dsp *sst) { if (sst->ops->dump) diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index 96aeb2556ad40..cc3197be4cf73 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -278,6 +278,8 @@ void sst_dsp_inbox_read(struct sst_dsp *dsp, void *message, size_t bytes); void sst_dsp_outbox_write(struct sst_dsp *dsp, void *message, size_t bytes); void sst_dsp_outbox_read(struct sst_dsp *dsp, void *message, size_t bytes); void sst_dsp_mailbox_dump(struct sst_dsp *dsp, size_t bytes); +int sst_dsp_register_poll(struct sst_dsp *dsp, u32 offset, u32 mask, + u32 expected_value, u32 timeout, char *operation); /* Debug */ void sst_dsp_dump(struct sst_dsp *sst); -- GitLab From d15b1ae17c79f682760483b56074e980720f52eb Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:53 +0530 Subject: [PATCH 0653/7006] ASoC: Intel: Add helper to update register bits with attr RWC For SKL IPC, we have some register bits with attribute RWC. So we need to force update them. Add helper to force update this type of registers bits. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp.c | 28 ++++++++++++++++++++++++++++ sound/soc/intel/common/sst-dsp.h | 4 ++++ 2 files changed, 32 insertions(+) diff --git a/sound/soc/intel/common/sst-dsp.c b/sound/soc/intel/common/sst-dsp.c index cc25f4c202afe..a627236dd1f5b 100644 --- a/sound/soc/intel/common/sst-dsp.c +++ b/sound/soc/intel/common/sst-dsp.c @@ -197,6 +197,22 @@ int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, } EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64_unlocked); +/* This is for registers bits with attribute RWC */ +void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value) +{ + unsigned int old, new; + u32 ret; + + ret = sst_dsp_shim_read_unlocked(sst, offset); + + old = ret; + new = (old & (~mask)) | (value & mask); + + sst_dsp_shim_write_unlocked(sst, offset, new); +} +EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced_unlocked); + int sst_dsp_shim_update_bits(struct sst_dsp *sst, u32 offset, u32 mask, u32 value) { @@ -223,6 +239,18 @@ int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, } EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits64); +/* This is for registers bits with attribute RWC */ +void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value) +{ + unsigned long flags; + + spin_lock_irqsave(&sst->spinlock, flags); + sst_dsp_shim_update_bits_forced_unlocked(sst, offset, mask, value); + spin_unlock_irqrestore(&sst->spinlock, flags); +} +EXPORT_SYMBOL_GPL(sst_dsp_shim_update_bits_forced); + int sst_dsp_register_poll(struct sst_dsp *ctx, u32 offset, u32 mask, u32 target, u32 timeout, char *operation) { diff --git a/sound/soc/intel/common/sst-dsp.h b/sound/soc/intel/common/sst-dsp.h index cc3197be4cf73..1f45f18715c09 100644 --- a/sound/soc/intel/common/sst-dsp.h +++ b/sound/soc/intel/common/sst-dsp.h @@ -230,6 +230,8 @@ void sst_dsp_shim_write64(struct sst_dsp *sst, u32 offset, u64 value); u64 sst_dsp_shim_read64(struct sst_dsp *sst, u32 offset); int sst_dsp_shim_update_bits64(struct sst_dsp *sst, u32 offset, u64 mask, u64 value); +void sst_dsp_shim_update_bits_forced(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value); /* SHIM Read / Write Unlocked for callers already holding sst lock */ void sst_dsp_shim_write_unlocked(struct sst_dsp *sst, u32 offset, u32 value); @@ -240,6 +242,8 @@ void sst_dsp_shim_write64_unlocked(struct sst_dsp *sst, u32 offset, u64 value); u64 sst_dsp_shim_read64_unlocked(struct sst_dsp *sst, u32 offset); int sst_dsp_shim_update_bits64_unlocked(struct sst_dsp *sst, u32 offset, u64 mask, u64 value); +void sst_dsp_shim_update_bits_forced_unlocked(struct sst_dsp *sst, u32 offset, + u32 mask, u32 value); /* Internal generic low-level SST IO functions - can be overidden */ void sst_shim32_write(void __iomem *addr, u32 offset, u32 value); -- GitLab From b81fd26359f04370f3c972652302717498f8790c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:54 +0530 Subject: [PATCH 0654/7006] ASoC: Intel: Add Skylake IPC library This adds base SKL IPC library which uses common SST IPC lib. Here we add definition for IPC types, sending and receiving IPC messages from aDSP, handling interrupt, sending different types of messages etc Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/Kconfig | 1 + sound/soc/intel/common/sst-dsp-priv.h | 4 + sound/soc/intel/skylake/Makefile | 5 + sound/soc/intel/skylake/skl-sst-ipc.c | 760 ++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-ipc.h | 125 +++++ 5 files changed, 895 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-ipc.c create mode 100644 sound/soc/intel/skylake/skl-sst-ipc.h diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig index d8b99434e6997..05fde5e6e2578 100644 --- a/sound/soc/intel/Kconfig +++ b/sound/soc/intel/Kconfig @@ -138,3 +138,4 @@ config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH config SND_SOC_INTEL_SKYLAKE tristate select SND_HDA_EXT_CORE + select SND_SOC_INTEL_SST diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index 50af167b7bc78..cd6c7ecf62882 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -303,6 +303,10 @@ struct sst_dsp { /* DMA FW loading */ struct sst_dma *dma; bool fw_use_dma; + + /* SKL data */ + + u32 intr_status; }; /* Size optimised DRAM/IRAM memcpy */ diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 734d17cafde7b..18fbe647abca9 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,3 +1,8 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o + +# Skylake IPC Support +snd-soc-skl-ipc-objs := skl-sst-ipc.o + +obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c new file mode 100644 index 0000000000000..94be6cbf2698b --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -0,0 +1,760 @@ +/* + * skl-sst-ipc.c - Intel skl IPC Support + * + * Copyright (C) 2014-15, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include + +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" + + +#define IPC_IXC_STATUS_BITS 24 + +/* Global Message - Generic */ +#define IPC_GLB_TYPE_SHIFT 24 +#define IPC_GLB_TYPE_MASK (0xf << IPC_GLB_TYPE_SHIFT) +#define IPC_GLB_TYPE(x) ((x) << IPC_GLB_TYPE_SHIFT) + +/* Global Message - Reply */ +#define IPC_GLB_REPLY_STATUS_SHIFT 24 +#define IPC_GLB_REPLY_STATUS_MASK ((0x1 << IPC_GLB_REPLY_STATUS_SHIFT) - 1) +#define IPC_GLB_REPLY_STATUS(x) ((x) << IPC_GLB_REPLY_STATUS_SHIFT) + +#define IPC_TIMEOUT_MSECS 3000 + +#define IPC_EMPTY_LIST_SIZE 8 + +#define IPC_MSG_TARGET_SHIFT 30 +#define IPC_MSG_TARGET_MASK 0x1 +#define IPC_MSG_TARGET(x) (((x) & IPC_MSG_TARGET_MASK) \ + << IPC_MSG_TARGET_SHIFT) + +#define IPC_MSG_DIR_SHIFT 29 +#define IPC_MSG_DIR_MASK 0x1 +#define IPC_MSG_DIR(x) (((x) & IPC_MSG_DIR_MASK) \ + << IPC_MSG_DIR_SHIFT) +/* Global Notification Message */ +#define IPC_GLB_NOTIFY_TYPE_SHIFT 16 +#define IPC_GLB_NOTIFY_TYPE_MASK 0xFF +#define IPC_GLB_NOTIFY_TYPE(x) (((x) >> IPC_GLB_NOTIFY_TYPE_SHIFT) \ + & IPC_GLB_NOTIFY_TYPE_MASK) + +#define IPC_GLB_NOTIFY_MSG_TYPE_SHIFT 24 +#define IPC_GLB_NOTIFY_MSG_TYPE_MASK 0x1F +#define IPC_GLB_NOTIFY_MSG_TYPE(x) (((x) >> IPC_GLB_NOTIFY_MSG_TYPE_SHIFT) \ + & IPC_GLB_NOTIFY_MSG_TYPE_MASK) + +#define IPC_GLB_NOTIFY_RSP_SHIFT 29 +#define IPC_GLB_NOTIFY_RSP_MASK 0x1 +#define IPC_GLB_NOTIFY_RSP_TYPE(x) (((x) >> IPC_GLB_NOTIFY_RSP_SHIFT) \ + & IPC_GLB_NOTIFY_RSP_MASK) + +/* Pipeline operations */ + +/* Create pipeline message */ +#define IPC_PPL_MEM_SIZE_SHIFT 0 +#define IPC_PPL_MEM_SIZE_MASK 0x7FF +#define IPC_PPL_MEM_SIZE(x) (((x) & IPC_PPL_MEM_SIZE_MASK) \ + << IPC_PPL_MEM_SIZE_SHIFT) + +#define IPC_PPL_TYPE_SHIFT 11 +#define IPC_PPL_TYPE_MASK 0x1F +#define IPC_PPL_TYPE(x) (((x) & IPC_PPL_TYPE_MASK) \ + << IPC_PPL_TYPE_SHIFT) + +#define IPC_INSTANCE_ID_SHIFT 16 +#define IPC_INSTANCE_ID_MASK 0xFF +#define IPC_INSTANCE_ID(x) (((x) & IPC_INSTANCE_ID_MASK) \ + << IPC_INSTANCE_ID_SHIFT) + +/* Set pipeline state message */ +#define IPC_PPL_STATE_SHIFT 0 +#define IPC_PPL_STATE_MASK 0x1F +#define IPC_PPL_STATE(x) (((x) & IPC_PPL_STATE_MASK) \ + << IPC_PPL_STATE_SHIFT) + +/* Module operations primary register */ +#define IPC_MOD_ID_SHIFT 0 +#define IPC_MOD_ID_MASK 0xFFFF +#define IPC_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ + << IPC_MOD_ID_SHIFT) + +#define IPC_MOD_INSTANCE_ID_SHIFT 16 +#define IPC_MOD_INSTANCE_ID_MASK 0xFF +#define IPC_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ + << IPC_MOD_INSTANCE_ID_SHIFT) + +/* Init instance message extension register */ +#define IPC_PARAM_BLOCK_SIZE_SHIFT 0 +#define IPC_PARAM_BLOCK_SIZE_MASK 0xFFFF +#define IPC_PARAM_BLOCK_SIZE(x) (((x) & IPC_PARAM_BLOCK_SIZE_MASK) \ + << IPC_PARAM_BLOCK_SIZE_SHIFT) + +#define IPC_PPL_INSTANCE_ID_SHIFT 16 +#define IPC_PPL_INSTANCE_ID_MASK 0xFF +#define IPC_PPL_INSTANCE_ID(x) (((x) & IPC_PPL_INSTANCE_ID_MASK) \ + << IPC_PPL_INSTANCE_ID_SHIFT) + +#define IPC_CORE_ID_SHIFT 24 +#define IPC_CORE_ID_MASK 0x1F +#define IPC_CORE_ID(x) (((x) & IPC_CORE_ID_MASK) \ + << IPC_CORE_ID_SHIFT) + +/* Bind/Unbind message extension register */ +#define IPC_DST_MOD_ID_SHIFT 0 +#define IPC_DST_MOD_ID(x) (((x) & IPC_MOD_ID_MASK) \ + << IPC_DST_MOD_ID_SHIFT) + +#define IPC_DST_MOD_INSTANCE_ID_SHIFT 16 +#define IPC_DST_MOD_INSTANCE_ID(x) (((x) & IPC_MOD_INSTANCE_ID_MASK) \ + << IPC_DST_MOD_INSTANCE_ID_SHIFT) + +#define IPC_DST_QUEUE_SHIFT 24 +#define IPC_DST_QUEUE_MASK 0x7 +#define IPC_DST_QUEUE(x) (((x) & IPC_DST_QUEUE_MASK) \ + << IPC_DST_QUEUE_SHIFT) + +#define IPC_SRC_QUEUE_SHIFT 27 +#define IPC_SRC_QUEUE_MASK 0x7 +#define IPC_SRC_QUEUE(x) (((x) & IPC_SRC_QUEUE_MASK) \ + << IPC_SRC_QUEUE_SHIFT) + +/* Save pipeline messgae extension register */ +#define IPC_DMA_ID_SHIFT 0 +#define IPC_DMA_ID_MASK 0x1F +#define IPC_DMA_ID(x) (((x) & IPC_DMA_ID_MASK) \ + << IPC_DMA_ID_SHIFT) +/* Large Config message extension register */ +#define IPC_DATA_OFFSET_SZ_SHIFT 0 +#define IPC_DATA_OFFSET_SZ_MASK 0xFFFFF +#define IPC_DATA_OFFSET_SZ(x) (((x) & IPC_DATA_OFFSET_SZ_MASK) \ + << IPC_DATA_OFFSET_SZ_SHIFT) +#define IPC_DATA_OFFSET_SZ_CLEAR ~(IPC_DATA_OFFSET_SZ_MASK \ + << IPC_DATA_OFFSET_SZ_SHIFT) + +#define IPC_LARGE_PARAM_ID_SHIFT 20 +#define IPC_LARGE_PARAM_ID_MASK 0xFF +#define IPC_LARGE_PARAM_ID(x) (((x) & IPC_LARGE_PARAM_ID_MASK) \ + << IPC_LARGE_PARAM_ID_SHIFT) + +#define IPC_FINAL_BLOCK_SHIFT 28 +#define IPC_FINAL_BLOCK_MASK 0x1 +#define IPC_FINAL_BLOCK(x) (((x) & IPC_FINAL_BLOCK_MASK) \ + << IPC_FINAL_BLOCK_SHIFT) + +#define IPC_INITIAL_BLOCK_SHIFT 29 +#define IPC_INITIAL_BLOCK_MASK 0x1 +#define IPC_INITIAL_BLOCK(x) (((x) & IPC_INITIAL_BLOCK_MASK) \ + << IPC_INITIAL_BLOCK_SHIFT) +#define IPC_INITIAL_BLOCK_CLEAR ~(IPC_INITIAL_BLOCK_MASK \ + << IPC_INITIAL_BLOCK_SHIFT) + +enum skl_ipc_msg_target { + IPC_FW_GEN_MSG = 0, + IPC_MOD_MSG = 1 +}; + +enum skl_ipc_msg_direction { + IPC_MSG_REQUEST = 0, + IPC_MSG_REPLY = 1 +}; + +/* Global Message Types */ +enum skl_ipc_glb_type { + IPC_GLB_GET_FW_VERSION = 0, /* Retrieves firmware version */ + IPC_GLB_LOAD_MULTIPLE_MODS = 15, + IPC_GLB_UNLOAD_MULTIPLE_MODS = 16, + IPC_GLB_CREATE_PPL = 17, + IPC_GLB_DELETE_PPL = 18, + IPC_GLB_SET_PPL_STATE = 19, + IPC_GLB_GET_PPL_STATE = 20, + IPC_GLB_GET_PPL_CONTEXT_SIZE = 21, + IPC_GLB_SAVE_PPL = 22, + IPC_GLB_RESTORE_PPL = 23, + IPC_GLB_NOTIFY = 26, + IPC_GLB_MAX_IPC_MSG_NUMBER = 31 /* Maximum message number */ +}; + +enum skl_ipc_glb_reply { + IPC_GLB_REPLY_SUCCESS = 0, + + IPC_GLB_REPLY_UNKNOWN_MSG_TYPE = 1, + IPC_GLB_REPLY_ERROR_INVALID_PARAM = 2, + + IPC_GLB_REPLY_BUSY = 3, + IPC_GLB_REPLY_PENDING = 4, + IPC_GLB_REPLY_FAILURE = 5, + IPC_GLB_REPLY_INVALID_REQUEST = 6, + + IPC_GLB_REPLY_OUT_OF_MEMORY = 7, + IPC_GLB_REPLY_OUT_OF_MIPS = 8, + + IPC_GLB_REPLY_INVALID_RESOURCE_ID = 9, + IPC_GLB_REPLY_INVALID_RESOURCE_STATE = 10, + + IPC_GLB_REPLY_MOD_MGMT_ERROR = 100, + IPC_GLB_REPLY_MOD_LOAD_CL_FAILED = 101, + IPC_GLB_REPLY_MOD_LOAD_INVALID_HASH = 102, + + IPC_GLB_REPLY_MOD_UNLOAD_INST_EXIST = 103, + IPC_GLB_REPLY_MOD_NOT_INITIALIZED = 104, + + IPC_GLB_REPLY_INVALID_CONFIG_PARAM_ID = 120, + IPC_GLB_REPLY_INVALID_CONFIG_DATA_LEN = 121, + IPC_GLB_REPLY_GATEWAY_NOT_INITIALIZED = 140, + IPC_GLB_REPLY_GATEWAY_NOT_EXIST = 141, + + IPC_GLB_REPLY_PPL_NOT_INITIALIZED = 160, + IPC_GLB_REPLY_PPL_NOT_EXIST = 161, + IPC_GLB_REPLY_PPL_SAVE_FAILED = 162, + IPC_GLB_REPLY_PPL_RESTORE_FAILED = 163, + + IPC_MAX_STATUS = ((1<tx_data, tx_data, tx_size); +} + +static bool skl_ipc_is_dsp_busy(struct sst_dsp *dsp) +{ + u32 hipci; + + hipci = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCI); + return (hipci & SKL_ADSP_REG_HIPCI_BUSY); +} + +/* Lock to be held by caller */ +static void skl_ipc_tx_msg(struct sst_generic_ipc *ipc, struct ipc_message *msg) +{ + struct skl_ipc_header *header = (struct skl_ipc_header *)(&msg->header); + + if (msg->tx_size) + sst_dsp_outbox_write(ipc->dsp, msg->tx_data, msg->tx_size); + sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCIE, + header->extension); + sst_dsp_shim_write_unlocked(ipc->dsp, SKL_ADSP_REG_HIPCI, + header->primary | SKL_ADSP_REG_HIPCI_BUSY); +} + +static struct ipc_message *skl_ipc_reply_get_msg(struct sst_generic_ipc *ipc, + u64 ipc_header) +{ + struct ipc_message *msg = NULL; + struct skl_ipc_header *header = (struct skl_ipc_header *)(&ipc_header); + + if (list_empty(&ipc->rx_list)) { + dev_err(ipc->dev, "ipc: rx list is empty but received 0x%x\n", + header->primary); + goto out; + } + + msg = list_first_entry(&ipc->rx_list, struct ipc_message, list); + +out: + return msg; + +} + +static int skl_ipc_process_notification(struct sst_generic_ipc *ipc, + struct skl_ipc_header header) +{ + struct skl_sst *skl = container_of(ipc, struct skl_sst, ipc); + + if (IPC_GLB_NOTIFY_MSG_TYPE(header.primary)) { + switch (IPC_GLB_NOTIFY_TYPE(header.primary)) { + + case IPC_GLB_NOTIFY_UNDERRUN: + dev_err(ipc->dev, "FW Underrun %x\n", header.primary); + break; + + case IPC_GLB_NOTIFY_RESOURCE_EVENT: + dev_err(ipc->dev, "MCPS Budget Violation: %x\n", + header.primary); + break; + + case IPC_GLB_NOTIFY_FW_READY: + skl->boot_complete = true; + wake_up(&skl->boot_wait); + break; + + default: + dev_err(ipc->dev, "ipc: Unhandled error msg=%x", + header.primary); + break; + } + } + + return 0; +} + +static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, + struct skl_ipc_header header) +{ + struct ipc_message *msg; + u32 reply = header.primary & IPC_GLB_REPLY_STATUS_MASK; + u64 *ipc_header = (u64 *)(&header); + + msg = skl_ipc_reply_get_msg(ipc, *ipc_header); + if (msg == NULL) { + dev_dbg(ipc->dev, "ipc: rx list is empty\n"); + return; + } + + /* first process the header */ + switch (reply) { + case IPC_GLB_REPLY_SUCCESS: + dev_info(ipc->dev, "ipc FW reply %x: success\n", header.primary); + break; + + case IPC_GLB_REPLY_OUT_OF_MEMORY: + dev_err(ipc->dev, "ipc fw reply: %x: no memory\n", header.primary); + msg->errno = -ENOMEM; + break; + + case IPC_GLB_REPLY_BUSY: + dev_err(ipc->dev, "ipc fw reply: %x: Busy\n", header.primary); + msg->errno = -EBUSY; + break; + + default: + dev_err(ipc->dev, "Unknown ipc reply: 0x%x", reply); + msg->errno = -EINVAL; + break; + } + + list_del(&msg->list); + sst_ipc_tx_msg_reply_complete(ipc, msg); +} + +irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) +{ + struct sst_dsp *dsp = context; + struct skl_sst *skl = sst_dsp_get_thread_context(dsp); + struct sst_generic_ipc *ipc = &skl->ipc; + struct skl_ipc_header header = {0}; + u32 hipcie, hipct, hipcte; + int ipc_irq = 0; + + /* Here we handle IPC interrupts only */ + if (!(dsp->intr_status & SKL_ADSPIS_IPC)) + return IRQ_NONE; + + hipcie = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCIE); + hipct = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCT); + + /* reply message from DSP */ + if (hipcie & SKL_ADSP_REG_HIPCIE_DONE) { + sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, 0); + + /* clear DONE bit - tell DSP we have completed the operation */ + sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCIE, + SKL_ADSP_REG_HIPCIE_DONE, SKL_ADSP_REG_HIPCIE_DONE); + + ipc_irq = 1; + + /* unmask Done interrupt */ + sst_dsp_shim_update_bits(dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); + } + + /* New message from DSP */ + if (hipct & SKL_ADSP_REG_HIPCT_BUSY) { + hipcte = sst_dsp_shim_read_unlocked(dsp, SKL_ADSP_REG_HIPCTE); + header.primary = hipct; + header.extension = hipcte; + dev_dbg(dsp->dev, "IPC irq: Firmware respond primary:%x", + header.primary); + dev_dbg(dsp->dev, "IPC irq: Firmware respond extension:%x", + header.extension); + + if (IPC_GLB_NOTIFY_RSP_TYPE(header.primary)) { + /* Handle Immediate reply from DSP Core */ + skl_ipc_process_reply(ipc, header); + } else { + dev_dbg(dsp->dev, "IPC irq: Notification from firmware\n"); + skl_ipc_process_notification(ipc, header); + } + /* clear busy interrupt */ + sst_dsp_shim_update_bits_forced(dsp, SKL_ADSP_REG_HIPCT, + SKL_ADSP_REG_HIPCT_BUSY, SKL_ADSP_REG_HIPCT_BUSY); + ipc_irq = 1; + } + + if (ipc_irq == 0) + return IRQ_NONE; + + skl_ipc_int_enable(dsp); + + /* continue to send any remaining messages... */ + queue_kthread_work(&ipc->kworker, &ipc->kwork); + + return IRQ_HANDLED; +} + +void skl_ipc_int_enable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_IPC, SKL_ADSPIC_IPC); +} + +void skl_ipc_int_disable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_IPC, 0); +} + +void skl_ipc_op_int_enable(struct sst_dsp *ctx) +{ + /* enable IPC DONE interrupt */ + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, SKL_ADSP_REG_HIPCCTL_DONE); + + /* Enable IPC BUSY interrupt */ + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_BUSY, SKL_ADSP_REG_HIPCCTL_BUSY); +} + +bool skl_ipc_int_status(struct sst_dsp *ctx) +{ + return sst_dsp_shim_read_unlocked(ctx, + SKL_ADSP_REG_ADSPIS) & SKL_ADSPIS_IPC; +} + +int skl_ipc_init(struct device *dev, struct skl_sst *skl) +{ + struct sst_generic_ipc *ipc; + int err; + + ipc = &skl->ipc; + ipc->dsp = skl->dsp; + ipc->dev = dev; + + ipc->tx_data_max_size = SKL_ADSP_W1_SZ; + ipc->rx_data_max_size = SKL_ADSP_W0_UP_SZ; + + err = sst_ipc_init(ipc); + if (err) + return err; + + ipc->ops.tx_msg = skl_ipc_tx_msg; + ipc->ops.tx_data_copy = skl_ipc_tx_data_copy; + ipc->ops.is_dsp_busy = skl_ipc_is_dsp_busy; + + return 0; +} + +void skl_ipc_free(struct sst_generic_ipc *ipc) +{ + /* Disable IPC DONE interrupt */ + sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_DONE, 0); + + /* Disable IPC BUSY interrupt */ + sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, + SKL_ADSP_REG_HIPCCTL_BUSY, 0); +} + +int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, + u16 ppl_mem_size, u8 ppl_type, u8 instance_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_CREATE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + header.primary |= IPC_PPL_TYPE(ppl_type); + header.primary |= IPC_PPL_MEM_SIZE(ppl_mem_size); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: create pipeline fail, err: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_create_pipeline); + +int skl_ipc_delete_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_DELETE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: delete pipeline failed, err %d\n", ret); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(skl_ipc_delete_pipeline); + +int skl_ipc_set_pipeline_state(struct sst_generic_ipc *ipc, + u8 instance_id, enum skl_ipc_pipeline_state state) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_SET_PPL_STATE); + header.primary |= IPC_INSTANCE_ID(instance_id); + header.primary |= IPC_PPL_STATE(state); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: set pipeline state failed, err: %d\n", ret); + return ret; + } + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_pipeline_state); + +int +skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, u8 instance_id, int dma_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_SAVE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + + header.extension = IPC_DMA_ID(dma_id); + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: save pipeline failed, err: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_save_pipeline); + +int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_FW_GEN_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_GLB_RESTORE_PPL); + header.primary |= IPC_INSTANCE_ID(instance_id); + + dev_dbg(ipc->dev, "In %s header=%d\n", __func__, header.primary); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: restore pipeline failed, err: %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_restore_pipeline); + +int skl_ipc_set_dx(struct sst_generic_ipc *ipc, u8 instance_id, + u16 module_id, struct skl_ipc_dxstate_info *dx) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_SET_DX); + header.primary |= IPC_MOD_INSTANCE_ID(instance_id); + header.primary |= IPC_MOD_ID(module_id); + + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, + header.primary, header.extension); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, + dx, sizeof(dx), NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: set dx failed, err %d\n", ret); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_dx); + +int skl_ipc_init_instance(struct sst_generic_ipc *ipc, + struct skl_ipc_init_instance_msg *msg, void *param_data) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret; + u32 *buffer = (u32 *)param_data; + /* param_block_size must be in dwords */ + u16 param_block_size = msg->param_data_size / sizeof(u32); + + print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE, + 16, 4, buffer, param_block_size, false); + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_INIT_INSTANCE); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_CORE_ID(msg->core_id); + header.extension |= IPC_PPL_INSTANCE_ID(msg->ppl_instance_id); + header.extension |= IPC_PARAM_BLOCK_SIZE(param_block_size); + + dev_dbg(ipc->dev, "In %s primary =%x ext=%x\n", __func__, + header.primary, header.extension); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, param_data, + msg->param_data_size, NULL, 0); + + if (ret < 0) { + dev_err(ipc->dev, "ipc: init instance failed\n"); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_init_instance); + +int skl_ipc_bind_unbind(struct sst_generic_ipc *ipc, + struct skl_ipc_bind_unbind_msg *msg) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + u8 bind_unbind = msg->bind ? IPC_MOD_BIND : IPC_MOD_UNBIND; + int ret; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(bind_unbind); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_DST_MOD_ID(msg->dst_module_id); + header.extension |= IPC_DST_MOD_INSTANCE_ID(msg->dst_instance_id); + header.extension |= IPC_DST_QUEUE(msg->dst_queue); + header.extension |= IPC_SRC_QUEUE(msg->src_queue); + + dev_dbg(ipc->dev, "In %s hdr=%x ext=%x\n", __func__, header.primary, + header.extension); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, NULL, 0, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, "ipc: bind/unbind faileden"); + return ret; + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_bind_unbind); + +int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param) +{ + struct skl_ipc_header header = {0}; + u64 *ipc_header = (u64 *)(&header); + int ret = 0; + size_t sz_remaining, tx_size, data_offset; + + header.primary = IPC_MSG_TARGET(IPC_MOD_MSG); + header.primary |= IPC_MSG_DIR(IPC_MSG_REQUEST); + header.primary |= IPC_GLB_TYPE(IPC_MOD_LARGE_CONFIG_SET); + header.primary |= IPC_MOD_INSTANCE_ID(msg->instance_id); + header.primary |= IPC_MOD_ID(msg->module_id); + + header.extension = IPC_DATA_OFFSET_SZ(msg->param_data_size); + header.extension |= IPC_LARGE_PARAM_ID(msg->large_param_id); + header.extension |= IPC_FINAL_BLOCK(0); + header.extension |= IPC_INITIAL_BLOCK(1); + + sz_remaining = msg->param_data_size; + data_offset = 0; + while (sz_remaining != 0) { + tx_size = sz_remaining > SKL_ADSP_W1_SZ + ? SKL_ADSP_W1_SZ : sz_remaining; + if (tx_size == sz_remaining) + header.extension |= IPC_FINAL_BLOCK(1); + + dev_dbg(ipc->dev, "In %s primary=%#x ext=%#x\n", __func__, + header.primary, header.extension); + dev_dbg(ipc->dev, "transmitting offset: %#x, size: %#x\n", + (unsigned)data_offset, (unsigned)tx_size); + ret = sst_ipc_tx_message_wait(ipc, *ipc_header, + ((char *)param) + data_offset, + tx_size, NULL, 0); + if (ret < 0) { + dev_err(ipc->dev, + "ipc: set large config fail, err: %d\n", ret); + return ret; + } + sz_remaining -= tx_size; + data_offset = msg->param_data_size - sz_remaining; + + /* clear the fields */ + header.extension &= IPC_INITIAL_BLOCK_CLEAR; + header.extension &= IPC_DATA_OFFSET_SZ_CLEAR; + /* fill the fields */ + header.extension |= IPC_INITIAL_BLOCK(0); + header.extension |= IPC_DATA_OFFSET_SZ(data_offset); + } + + return ret; +} +EXPORT_SYMBOL_GPL(skl_ipc_set_large_config); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h new file mode 100644 index 0000000000000..9f5f67202858f --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -0,0 +1,125 @@ +/* + * Intel SKL IPC Support + * + * Copyright (C) 2014-15, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef __SKL_IPC_H +#define __SKL_IPC_H + +#include +#include +#include "../common/sst-ipc.h" + +struct sst_dsp; +struct skl_sst; +struct sst_generic_ipc; + +enum skl_ipc_pipeline_state { + PPL_INVALID_STATE = 0, + PPL_UNINITIALIZED = 1, + PPL_RESET = 2, + PPL_PAUSED = 3, + PPL_RUNNING = 4, + PPL_ERROR_STOP = 5, + PPL_SAVED = 6, + PPL_RESTORED = 7 +}; + +struct skl_ipc_dxstate_info { + u32 core_mask; + u32 dx_mask; +}; + +struct skl_ipc_header { + u32 primary; + u32 extension; +}; + +struct skl_sst { + struct device *dev; + struct sst_dsp *dsp; + + /* boot */ + wait_queue_head_t boot_wait; + bool boot_complete; + + /* IPC messaging */ + struct sst_generic_ipc ipc; +}; + +struct skl_ipc_init_instance_msg { + u32 module_id; + u32 instance_id; + u16 param_data_size; + u8 ppl_instance_id; + u8 core_id; +}; + +struct skl_ipc_bind_unbind_msg { + u32 module_id; + u32 instance_id; + u32 dst_module_id; + u32 dst_instance_id; + u8 src_queue; + u8 dst_queue; + bool bind; +}; + +struct skl_ipc_large_config_msg { + u32 module_id; + u32 instance_id; + u32 large_param_id; + u32 param_data_size; +}; + +#define SKL_IPC_BOOT_MSECS 3000 + +#define SKL_IPC_D3_MASK 0 +#define SKL_IPC_D0_MASK 3 + +irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context); + +int skl_ipc_create_pipeline(struct sst_generic_ipc *sst_ipc, + u16 ppl_mem_size, u8 ppl_type, u8 instance_id); + +int skl_ipc_delete_pipeline(struct sst_generic_ipc *sst_ipc, u8 instance_id); + +int skl_ipc_set_pipeline_state(struct sst_generic_ipc *sst_ipc, + u8 instance_id, enum skl_ipc_pipeline_state state); + +int skl_ipc_save_pipeline(struct sst_generic_ipc *ipc, + u8 instance_id, int dma_id); + +int skl_ipc_restore_pipeline(struct sst_generic_ipc *ipc, u8 instance_id); + +int skl_ipc_init_instance(struct sst_generic_ipc *sst_ipc, + struct skl_ipc_init_instance_msg *msg, void *param_data); + +int skl_ipc_bind_unbind(struct sst_generic_ipc *sst_ipc, + struct skl_ipc_bind_unbind_msg *msg); + +int skl_ipc_set_dx(struct sst_generic_ipc *ipc, + u8 instance_id, u16 module_id, struct skl_ipc_dxstate_info *dx); + +int skl_ipc_set_large_config(struct sst_generic_ipc *ipc, + struct skl_ipc_large_config_msg *msg, u32 *param); + +void skl_ipc_int_enable(struct sst_dsp *dsp); +void skl_ipc_op_int_enable(struct sst_dsp *ctx); +void skl_ipc_int_disable(struct sst_dsp *dsp); + +bool skl_ipc_int_status(struct sst_dsp *dsp); +void skl_ipc_free(struct sst_generic_ipc *ipc); +int skl_ipc_init(struct device *dev, struct skl_sst *skl); + +#endif /* __SKL_IPC_H */ -- GitLab From e973e31a02c32fc830986e62f82e69934134f5ce Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Thu, 9 Jul 2015 21:38:55 +0530 Subject: [PATCH 0655/7006] ASoC: Intel: Add DSP init and boot up functionality for SKL This patch adds code to enable, disable and boot DSP core. Also provide some helpers to reset and power up/down the core. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 4 + sound/soc/intel/skylake/Makefile | 2 +- sound/soc/intel/skylake/skl-sst-dsp.c | 337 ++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 57 +++++ 4 files changed, 399 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-sst-dsp.c diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index cd6c7ecf62882..dd79648dfb3a5 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -22,6 +22,8 @@ #include #include +#include "../skylake/skl-sst-dsp.h" + struct sst_mem_block; struct sst_module; struct sst_fw; @@ -306,6 +308,8 @@ struct sst_dsp { /* SKL data */ + struct skl_dsp_fw_ops fw_ops; + int sst_state; u32 intr_status; }; diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 18fbe647abca9..10c1319f7ed52 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,6 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c new file mode 100644 index 0000000000000..313ca7c6ca7f9 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -0,0 +1,337 @@ +/* + * skl-sst-dsp.c - SKL SST library generic function + * + * Copyright (C) 2014-15, Intel Corporation. + * Author:Rafal Redzimski + * Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include + +#include "../common/sst-dsp.h" +#include "../common/sst-ipc.h" +#include "../common/sst-dsp-priv.h" +#include "skl-sst-ipc.h" + +/* various timeout values */ +#define SKL_DSP_PU_TO 50 +#define SKL_DSP_PD_TO 50 +#define SKL_DSP_RESET_TO 50 + +void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state) +{ + mutex_lock(&ctx->mutex); + ctx->sst_state = state; + mutex_unlock(&ctx->mutex); +} + +static int skl_dsp_core_set_reset_state(struct sst_dsp *ctx) +{ + int ret; + + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_ADSPCS, SKL_ADSPCS_CRST_MASK, + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)); + + /* poll with timeout to check if operation successful */ + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CRST_MASK, + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK), + SKL_DSP_RESET_TO, + "Set reset"); + if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) { + dev_err(ctx->dev, "Set reset state failed\n"); + ret = -EIO; + } + + return ret; +} + +static int skl_dsp_core_unset_reset_state(struct sst_dsp *ctx) +{ + int ret; + + dev_dbg(ctx->dev, "In %s\n", __func__); + + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CRST_MASK, 0); + + /* poll with timeout to check if operation successful */ + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CRST_MASK, + 0, + SKL_DSP_RESET_TO, + "Unset reset"); + + if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) != 0) { + dev_err(ctx->dev, "Unset reset state failed\n"); + ret = -EIO; + } + + return ret; +} + +static bool is_skl_dsp_core_enable(struct sst_dsp *ctx) +{ + int val; + bool is_enable; + + val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS); + + is_enable = ((val & SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) && + (val & SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)) && + !(val & SKL_ADSPCS_CRST(SKL_DSP_CORES_MASK)) && + !(val & SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK))); + + dev_dbg(ctx->dev, "DSP core is enabled=%d\n", is_enable); + return is_enable; +} + +static int skl_dsp_reset_core(struct sst_dsp *ctx) +{ + /* stall core */ + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); + + /* set reset state */ + return skl_dsp_core_set_reset_state(ctx); +} + +static int skl_dsp_start_core(struct sst_dsp *ctx) +{ + int ret; + + /* unset reset state */ + ret = skl_dsp_core_unset_reset_state(ctx); + if (ret < 0) { + dev_dbg(ctx->dev, "dsp unset reset fails\n"); + return ret; + } + + /* run core */ + dev_dbg(ctx->dev, "run core...\n"); + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + ~SKL_ADSPCS_CSTALL(SKL_DSP_CORES_MASK)); + + if (!is_skl_dsp_core_enable(ctx)) { + skl_dsp_reset_core(ctx); + dev_err(ctx->dev, "DSP core enable failed\n"); + ret = -EIO; + } + + return ret; +} + +static int skl_dsp_core_power_up(struct sst_dsp *ctx) +{ + int ret; + + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_SPA_MASK, SKL_ADSPCS_SPA(SKL_DSP_CORES_MASK)); + + /* poll with timeout to check if operation successful */ + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_CPA_MASK, + SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK), + SKL_DSP_PU_TO, + "Power up"); + + if ((sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPCS) & + SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) != + SKL_ADSPCS_CPA(SKL_DSP_CORES_MASK)) { + dev_err(ctx->dev, "DSP core power up failed\n"); + ret = -EIO; + } + + return ret; +} + +static int skl_dsp_core_power_down(struct sst_dsp *ctx) +{ + /* update bits */ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_SPA_MASK, 0); + + /* poll with timeout to check if operation successful */ + return sst_dsp_register_poll(ctx, + SKL_ADSP_REG_ADSPCS, + SKL_ADSPCS_SPA_MASK, + 0, + SKL_DSP_PD_TO, + "Power down"); +} + +static int skl_dsp_enable_core(struct sst_dsp *ctx) +{ + int ret; + + /* power up */ + ret = skl_dsp_core_power_up(ctx); + if (ret < 0) { + dev_dbg(ctx->dev, "dsp core power up failed\n"); + return ret; + } + + return skl_dsp_start_core(ctx); +} + +int skl_dsp_disable_core(struct sst_dsp *ctx) +{ + int ret; + + ret = skl_dsp_reset_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp core reset failed\n"); + return ret; + } + + /* power down core*/ + ret = skl_dsp_core_power_down(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp core power down failed\n"); + return ret; + } + + if (is_skl_dsp_core_enable(ctx)) { + dev_err(ctx->dev, "DSP core disable failed\n"); + ret = -EIO; + } + + return ret; +} + +int skl_dsp_boot(struct sst_dsp *ctx) +{ + int ret; + + if (is_skl_dsp_core_enable(ctx)) { + dev_dbg(ctx->dev, "dsp core is already enabled, so reset the dap core\n"); + ret = skl_dsp_reset_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp reset failed\n"); + return ret; + } + + ret = skl_dsp_start_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "dsp start failed\n"); + return ret; + } + } else { + dev_dbg(ctx->dev, "disable and enable to make sure DSP is invalid state\n"); + ret = skl_dsp_disable_core(ctx); + + if (ret < 0) { + dev_err(ctx->dev, "dsp disable core failes\n"); + return ret; + } + ret = skl_dsp_enable_core(ctx); + } + + return ret; +} + +irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) +{ + struct sst_dsp *ctx = dev_id; + u32 val; + irqreturn_t result = IRQ_NONE; + + spin_lock(&ctx->spinlock); + + val = sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_ADSPIS); + ctx->intr_status = val; + + if (val & SKL_ADSPIS_IPC) { + skl_ipc_int_disable(ctx); + result = IRQ_WAKE_THREAD; + } + + spin_unlock(&ctx->spinlock); + + return result; +} + +int skl_dsp_wake(struct sst_dsp *ctx) +{ + return ctx->fw_ops.set_state_D0(ctx); +} +EXPORT_SYMBOL_GPL(skl_dsp_wake); + +int skl_dsp_sleep(struct sst_dsp *ctx) +{ + return ctx->fw_ops.set_state_D3(ctx); +} +EXPORT_SYMBOL_GPL(skl_dsp_sleep); + +struct sst_dsp *skl_dsp_ctx_init(struct device *dev, + struct sst_dsp_device *sst_dev, int irq) +{ + int ret; + struct sst_dsp *sst; + + sst = devm_kzalloc(dev, sizeof(*sst), GFP_KERNEL); + if (sst == NULL) + return NULL; + + spin_lock_init(&sst->spinlock); + mutex_init(&sst->mutex); + sst->dev = dev; + sst->sst_dev = sst_dev; + sst->irq = irq; + sst->ops = sst_dev->ops; + sst->thread_context = sst_dev->thread_context; + + /* Initialise SST Audio DSP */ + if (sst->ops->init) { + ret = sst->ops->init(sst, NULL); + if (ret < 0) + return NULL; + } + + /* Register the ISR */ + ret = request_threaded_irq(sst->irq, sst->ops->irq_handler, + sst_dev->thread, IRQF_SHARED, "AudioDSP", sst); + if (ret) { + dev_err(sst->dev, "unable to grab threaded IRQ %d, disabling device\n", + sst->irq); + return NULL; + } + + return sst; +} + +void skl_dsp_free(struct sst_dsp *dsp) +{ + skl_ipc_int_disable(dsp); + + free_irq(dsp->irq, dsp); + skl_dsp_disable_core(dsp); +} +EXPORT_SYMBOL_GPL(skl_dsp_free); + +bool is_skl_dsp_running(struct sst_dsp *ctx) +{ + return (ctx->sst_state == SKL_DSP_RUNNING); +} +EXPORT_SYMBOL_GPL(is_skl_dsp_running); diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index 2ac120c18bead..cdfca9be4120a 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,6 +16,8 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__ +struct sst_dsp_device; + /* Intel HD Audio General DSP Registers */ #define SKL_ADSP_GEN_BASE 0x0 #define SKL_ADSP_REG_ADSPCS (SKL_ADSP_GEN_BASE + 0x04) @@ -59,4 +61,59 @@ #define SKL_ADSPIC_IPC 1 #define SKL_ADSPIS_IPC 1 +/* ADSPCS - Audio DSP Control & Status */ +#define SKL_DSP_CORES 1 +#define SKL_DSP_CORE0_MASK 1 +#define SKL_DSP_CORES_MASK ((1 << SKL_DSP_CORES) - 1) + +/* Core Reset - asserted high */ +#define SKL_ADSPCS_CRST_SHIFT 0 +#define SKL_ADSPCS_CRST_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CRST_SHIFT) +#define SKL_ADSPCS_CRST(x) ((x << SKL_ADSPCS_CRST_SHIFT) & SKL_ADSPCS_CRST_MASK) + +/* Core run/stall - when set to '1' core is stalled */ +#define SKL_ADSPCS_CSTALL_SHIFT 8 +#define SKL_ADSPCS_CSTALL_MASK (SKL_DSP_CORES_MASK << \ + SKL_ADSPCS_CSTALL_SHIFT) +#define SKL_ADSPCS_CSTALL(x) ((x << SKL_ADSPCS_CSTALL_SHIFT) & \ + SKL_ADSPCS_CSTALL_MASK) + +/* Set Power Active - when set to '1' turn cores on */ +#define SKL_ADSPCS_SPA_SHIFT 16 +#define SKL_ADSPCS_SPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_SPA_SHIFT) +#define SKL_ADSPCS_SPA(x) ((x << SKL_ADSPCS_SPA_SHIFT) & SKL_ADSPCS_SPA_MASK) + +/* Current Power Active - power status of cores, set by hardware */ +#define SKL_ADSPCS_CPA_SHIFT 24 +#define SKL_ADSPCS_CPA_MASK (SKL_DSP_CORES_MASK << SKL_ADSPCS_CPA_SHIFT) +#define SKL_ADSPCS_CPA(x) ((x << SKL_ADSPCS_CPA_SHIFT) & SKL_ADSPCS_CPA_MASK) + +#define SST_DSP_POWER_D0 0x0 /* full On */ +#define SST_DSP_POWER_D3 0x3 /* Off */ + +enum skl_dsp_states { + SKL_DSP_RUNNING = 1, + SKL_DSP_RESET, +}; + +struct skl_dsp_fw_ops { + int (*load_fw)(struct sst_dsp *ctx); + /* FW module parser/loader */ + int (*parse_fw)(struct sst_dsp *ctx); + int (*set_state_D0)(struct sst_dsp *ctx); + int (*set_state_D3)(struct sst_dsp *ctx); +}; + +void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); +struct sst_dsp *skl_dsp_ctx_init(struct device *dev, + struct sst_dsp_device *sst_dev, int irq); +int skl_dsp_disable_core(struct sst_dsp *ctx); +bool is_skl_dsp_running(struct sst_dsp *ctx); +irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id); +int skl_dsp_wake(struct sst_dsp *ctx); +int skl_dsp_sleep(struct sst_dsp *ctx); +void skl_dsp_free(struct sst_dsp *dsp); + +int skl_dsp_boot(struct sst_dsp *ctx); + #endif /*__SKL_SST_DSP_H__*/ -- GitLab From b6d30968d86c45a7bb599eaca13ff048d3fa576c Mon Sep 17 00:00:00 2001 From: Anshul Garg Date: Thu, 9 Jul 2015 10:18:22 -0700 Subject: [PATCH 0656/7006] Input: uinput - switch to using for_each_set_bit() Use for_each_set_bit to check for set bits in bitmap as it is more efficient and compact. Signed-off-by: Anshul Garg Signed-off-by: Dmitry Torokhov --- drivers/input/misc/uinput.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c index 421e29e4cd811..345df9b03aed7 100644 --- a/drivers/input/misc/uinput.c +++ b/drivers/input/misc/uinput.c @@ -320,10 +320,8 @@ static int uinput_validate_absbits(struct input_dev *dev) * Check if absmin/absmax/absfuzz/absflat are sane. */ - for (cnt = 0; cnt < ABS_CNT; cnt++) { + for_each_set_bit(cnt, dev->absbit, ABS_CNT) { int min, max; - if (!test_bit(cnt, dev->absbit)) - continue; min = input_abs_get_min(dev, cnt); max = input_abs_get_max(dev, cnt); @@ -416,7 +414,7 @@ static int uinput_setup_device(struct uinput_device *udev, dev->id.product = user_dev->id.product; dev->id.version = user_dev->id.version; - for (i = 0; i < ABS_CNT; i++) { + for_each_set_bit(i, dev->absbit, ABS_CNT) { input_abs_set_max(dev, i, user_dev->absmax[i]); input_abs_set_min(dev, i, user_dev->absmin[i]); input_abs_set_fuzz(dev, i, user_dev->absfuzz[i]); -- GitLab From 09108b90f0404587b7afac64023ec11a7f1b1406 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 7 Jul 2015 16:28:54 -0700 Subject: [PATCH 0657/7006] drm/i915: PSR: Remove Low Power HW tracking mask. By Spec we should only mask memup and hotplug detection for hardware tracking cases. However we always masked LPSP because with power well always enabled on audio PSR was never being activated and residency was always zeroed. Apparently audio driver is tying power well management and runtime PM for some reason. But with audio runtime PM working or with audio completely out of picture we should remove this mask, otherwise we have a high risk of miss screen updates as faced by Matthew. WARNING: With this patch if snd_intel_hda driver is running and not releasing power well properly PSR will constant Exit and Performance Counter will be 0. But the best thing of this patch is that with one more HW tracking working the risks of missed blank screen are minimized at most. This affects just core platforms where PSR exit are also helped by HW tracking: Haswell, Broadwell and Skylake for now. v2: Fix commit message explanation. It has nothing to do with runtime PM on i915 as previously advertised. Cc: Daniel Vetter Cc: Matthew Garrett Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 6db043f3c1ad7..24fa3c7e947f7 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -400,7 +400,7 @@ void intel_psr_enable(struct intel_dp *intel_dp) /* Avoid continuous PSR exit by masking memup and hpd */ I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP | - EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP); + EDP_PSR_DEBUG_MASK_HPD); /* Enable PSR on the panel */ hsw_psr_enable_sink(intel_dp); -- GitLab From 97173eaf5f33b1e85efdb06d593d333480b60bf3 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 7 Jul 2015 16:28:55 -0700 Subject: [PATCH 0658/7006] drm/i915: PSR: Increase idle_frames Idle frames the number of identical frames needed before panel can enter PSR. There are some panels that requires up to minimum of 4 idle frames available on the market. For these cases usually VBT should be used to configure the number of idle frames, but unfortunately this isn't always true and VBT isn't being set at all. Let's trust VBT when it is set + 1 and use minimum of 4 + 1 when VBT isn't set. "+1" covers the "of-by-one" case. Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_psr.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 24fa3c7e947f7..acd8ec859f71b 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -254,10 +254,13 @@ static void hsw_psr_enable_source(struct intel_dp *intel_dp) uint32_t max_sleep_time = 0x1f; /* Lately it was identified that depending on panel idle frame count * calculated at HW can be off by 1. So let's use what came - * from VBT + 1 and at minimum 2 to be on the safe side. + * from VBT + 1. + * There are also other cases where panel demands at least 4 + * but VBT is not being set. To cover these 2 cases lets use + * at least 5 when VBT isn't set to be on the safest side. */ uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ? - dev_priv->vbt.psr.idle_frames + 1 : 2; + dev_priv->vbt.psr.idle_frames + 1 : 5; uint32_t val = 0x0; const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES; -- GitLab From aba6da3e61779186a7bd45e2206d88524f422e5b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 Jul 2015 09:56:41 -0700 Subject: [PATCH 0659/7006] drm/i915: fbdev_set_par reliably invalidating frontbuffer fbdev_set_par is called when fbcon is taking over control. In the past frontbuffer was being invalidated on set_to_gtt_domain, but it moved to set_domain fixing that case, but left this behind and broken in commit 031b698a77a70a6c394568034437b5486a44e868 Author: Daniel Vetter Date: Fri Jun 26 19:35:16 2015 +0200 drm/i915: Unconditionally do fb tracking invalidate in set_domain Note that even before this commit it wasn't perfect since the invalidate was omitted if the fbcon was already in the GTT domain, which it usually was. Since we are also invalidating in other fbdev cases this one was masked here. At least until now that I found this corner case: On boot with plymouth doing a splash screen when returning to the console frontbuffer wans't being invalidated causing missed screen updates with PSR enabled. So this patch fixes this issue. v2: Make invalidate directly and unconditionally and fix commit message indicating the set_domain fix as pointed out by Daniel. v3: Remove unecessary if(obj) added by mistake Cc: Paulo Zanoni Cc: Daniel Vetter Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni [danvet: Try to clarify commit message a bit and make it clear the referenced commit made this worse.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 2a1724e34a36a..25ce7b62d4d58 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -63,8 +63,7 @@ static int intel_fbdev_set_par(struct fb_info *info) * now until we solve this for real. */ mutex_lock(&fb_helper->dev->struct_mutex); - ret = i915_gem_object_set_to_gtt_domain(ifbdev->fb->obj, - true); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); mutex_unlock(&fb_helper->dev->struct_mutex); } -- GitLab From d04df7325ac9def8c4a68b49822c1d0a0c5379c6 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 8 Jul 2015 16:25:21 -0700 Subject: [PATCH 0660/7006] drm/i915: fbdev restore mode needs to invalidate frontbuffer This fbdev restore mode was another corner case that was now calling frontbuffer flip and flush and making we miss screen updates with PSR enabled. So let's also add the invalidate hack here while we don't have a reliable dirty fbdev op. v2: As pointed by Paulo: removed seg fault risk, used fb_helper when possible and put brackets on if. Cc: Paulo Zanoni Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni Testcase: igt/kms_fbcon_fbt/psr Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 25ce7b62d4d58..33b3c9233eacb 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -824,11 +824,20 @@ void intel_fbdev_restore_mode(struct drm_device *dev) { int ret; struct drm_i915_private *dev_priv = dev->dev_private; + struct intel_fbdev *ifbdev = dev_priv->fbdev; + struct drm_fb_helper *fb_helper; - if (!dev_priv->fbdev) + if (!ifbdev) return; - ret = drm_fb_helper_restore_fbdev_mode_unlocked(&dev_priv->fbdev->helper); - if (ret) + fb_helper = &ifbdev->helper; + + ret = drm_fb_helper_restore_fbdev_mode_unlocked(fb_helper); + if (ret) { DRM_DEBUG("failed to restore crtc mode\n"); + } else { + mutex_lock(&fb_helper->dev->struct_mutex); + intel_fb_obj_invalidate(ifbdev->fb->obj, ORIGIN_GTT); + mutex_unlock(&fb_helper->dev->struct_mutex); + } } -- GitLab From 2251ae46af72d013a6a537e7681e94b18b63e332 Mon Sep 17 00:00:00 2001 From: Jon Maxwell Date: Wed, 8 Jul 2015 10:12:28 +1000 Subject: [PATCH 0661/7006] tcp: v1 always send a quick ack when quickacks are enabled V1 of this patch contains Eric Dumazet's suggestion to move the per dst RTAX_QUICKACK check into tcp_in_quickack_mode(). Thanks Eric. I ran some tests and after setting the "ip route change quickack 1" knob there were still many delayed ACKs sent. This occured because when icsk_ack.quick=0 the !icsk_ack.pingpong value is subsequently ignored as tcp_in_quickack_mode() checks both these values. The condition for a quick ack to trigger requires that both icsk_ack.quick != 0 and icsk_ack.pingpong=0. Currently only icsk_ack.pingpong is controlled by the knob. But the icsk_ack.quick value changes dynamically depending on heuristics. The crux of the matter is that delayed acks still cannot be entirely disabled even with the RTAX_QUICKACK per dst knob enabled. This patch ensures that a quick ack is always sent when the RTAX_QUICKACK per dst knob is turned on. The "ip route change quickack 1" knob was recently added to enable quickacks. It was modeled around the TCP_QUICKACK setsockopt() option. This issue is that even with "ip route change quickack 1" enabled we still see delayed ACKs under some conditions. It would be nice to be able to completely disable delayed ACKs. Here is an example: # netstat -s|grep dela 3 delayed acks sent For all routes enable the knob # ip route change quickack 1 Generate some traffic across a slow link and we still see the delayed acks. # netstat -s|grep dela 106 delayed acks sent 1 delayed acks further delayed because of locked socket The issue is that both the "ip route change quickack 1" knob and the TCP_QUICKACK option set the icsk_ack.pingpong variable to 0. However at the business end in the __tcp_ack_snd_check() routine, tcp_in_quickack_mode() checks that both icsk_ack.quick != 0 and icsk_ack.pingpong=0 in order to trigger a quickack. As icsk_ack.quick is determined by heuristics it can be 0. When that occurs the icsk_ack.pingpong value is ignored and a delayed ACK is sent regardless. This patch moves the RTAX_QUICKACK per dst check into the tcp_in_quickack_mode() routine which ensures that a quickack is always sent when the quickack knob is enabled for that dst. Signed-off-by: Jon Maxwell Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 11 +++++------ net/ipv4/tcp_output.c | 6 ++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ad1482dd215ef..7f4a8d5f6eb0f 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -197,11 +197,13 @@ static void tcp_enter_quickack_mode(struct sock *sk) * and the session is not interactive. */ -static inline bool tcp_in_quickack_mode(const struct sock *sk) +static bool tcp_in_quickack_mode(struct sock *sk) { const struct inet_connection_sock *icsk = inet_csk(sk); + const struct dst_entry *dst = __sk_dst_get(sk); - return icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong; + return (dst && dst_metric(dst, RTAX_QUICKACK)) || + (icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong); } static void tcp_ecn_queue_cwr(struct tcp_sock *tp) @@ -3951,7 +3953,6 @@ void tcp_reset(struct sock *sk) static void tcp_fin(struct sock *sk) { struct tcp_sock *tp = tcp_sk(sk); - const struct dst_entry *dst; inet_csk_schedule_ack(sk); @@ -3963,9 +3964,7 @@ static void tcp_fin(struct sock *sk) case TCP_ESTABLISHED: /* Move to CLOSE_WAIT */ tcp_set_state(sk, TCP_CLOSE_WAIT); - dst = __sk_dst_get(sk); - if (!dst || !dst_metric(dst, RTAX_QUICKACK)) - inet_csk(sk)->icsk_ack.pingpong = 1; + inet_csk(sk)->icsk_ack.pingpong = 1; break; case TCP_CLOSE_WAIT: diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index b1c218df2c855..71057849593ac 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -163,7 +163,6 @@ static void tcp_event_data_sent(struct tcp_sock *tp, { struct inet_connection_sock *icsk = inet_csk(sk); const u32 now = tcp_time_stamp; - const struct dst_entry *dst = __sk_dst_get(sk); if (sysctl_tcp_slow_start_after_idle && (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto)) @@ -174,9 +173,8 @@ static void tcp_event_data_sent(struct tcp_sock *tp, /* If it is a reply for ato after last received * packet, enter pingpong mode. */ - if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato && - (!dst || !dst_metric(dst, RTAX_QUICKACK))) - icsk->icsk_ack.pingpong = 1; + if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato) + icsk->icsk_ack.pingpong = 1; } /* Account for an ACK we sent. */ -- GitLab From 1007f59dce53a22cba164f854d7bdc171c85dc79 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Thu, 9 Jul 2015 11:02:52 -0700 Subject: [PATCH 0662/7006] net: skb_defer_rx_timestamp should check for phydev before setting up classify This change makes it so that the call skb_defer_rx_timestamp will first check for a phydev before going in and manipulating the skb->data and skb->len values. By doing this we can avoid unnecessary work on network devices that don't support phydev. As a result we reduce the total instruction count needed to process this on most devices. Signed-off-by: Alexander Duyck Signed-off-by: David S. Miller --- net/core/timestamping.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/core/timestamping.c b/net/core/timestamping.c index 43d3dd62fcc8e..42689d5c468cb 100644 --- a/net/core/timestamping.c +++ b/net/core/timestamping.c @@ -60,11 +60,15 @@ bool skb_defer_rx_timestamp(struct sk_buff *skb) struct phy_device *phydev; unsigned int type; + if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->drv) + return false; + if (skb_headroom(skb) < ETH_HLEN) return false; + __skb_push(skb, ETH_HLEN); - type = classify(skb); + type = ptp_classify_raw(skb); __skb_pull(skb, ETH_HLEN); -- GitLab From 071d5080e33d6f24139e4213c2d9f97a2c21b602 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 9 Jul 2015 13:16:29 -0700 Subject: [PATCH 0663/7006] tcp: add tcp_in_slow_start helper Add a helper to test the slow start condition in various congestion control modules and other places. This is to prepare a slight improvement in policy as to exactly when to slow start. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: Nandita Dukkipati Signed-off-by: David S. Miller --- include/net/tcp.h | 7 ++++++- net/ipv4/tcp_bic.c | 2 +- net/ipv4/tcp_cong.c | 2 +- net/ipv4/tcp_cubic.c | 4 ++-- net/ipv4/tcp_highspeed.c | 2 +- net/ipv4/tcp_htcp.c | 2 +- net/ipv4/tcp_illinois.c | 2 +- net/ipv4/tcp_metrics.c | 2 +- net/ipv4/tcp_scalable.c | 2 +- net/ipv4/tcp_vegas.c | 6 +++--- net/ipv4/tcp_veno.c | 2 +- 11 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 950cfecaad3c0..dba22fc1b065a 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -989,6 +989,11 @@ static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) #define TCP_INFINITE_SSTHRESH 0x7fffffff +static inline bool tcp_in_slow_start(const struct tcp_sock *tp) +{ + return tp->snd_cwnd <= tp->snd_ssthresh; +} + static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp) { return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH; @@ -1065,7 +1070,7 @@ static inline bool tcp_is_cwnd_limited(const struct sock *sk) const struct tcp_sock *tp = tcp_sk(sk); /* If in slow start, ensure cwnd grows to twice what was ACKed. */ - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tcp_in_slow_start(tp)) return tp->snd_cwnd < 2 * tp->max_packets_out; return tp->is_cwnd_limited; diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c index c037644eafb7c..fd1405d37c149 100644 --- a/net/ipv4/tcp_bic.c +++ b/net/ipv4/tcp_bic.c @@ -146,7 +146,7 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) if (!tcp_is_cwnd_limited(sk)) return; - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tcp_in_slow_start(tp)) tcp_slow_start(tp, acked); else { bictcp_update(ca, tp->snd_cwnd); diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 84be008c945c6..654729a8cb23f 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -413,7 +413,7 @@ void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked) return; /* In "safe" area, increase. */ - if (tp->snd_cwnd <= tp->snd_ssthresh) { + if (tcp_in_slow_start(tp)) { acked = tcp_slow_start(tp, acked); if (!acked) return; diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 06d3d665a9fd1..28011fb1f4a21 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -320,7 +320,7 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) if (!tcp_is_cwnd_limited(sk)) return; - if (tp->snd_cwnd <= tp->snd_ssthresh) { + if (tcp_in_slow_start(tp)) { if (hystart && after(ack, ca->end_seq)) bictcp_hystart_reset(sk); acked = tcp_slow_start(tp, acked); @@ -439,7 +439,7 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us) ca->delay_min = delay; /* hystart triggers when cwnd is larger than some threshold */ - if (hystart && tp->snd_cwnd <= tp->snd_ssthresh && + if (hystart && tcp_in_slow_start(tp) && tp->snd_cwnd >= hystart_low_window) hystart_update(sk, delay); } diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c index 882c08aae2f58..db7842495a641 100644 --- a/net/ipv4/tcp_highspeed.c +++ b/net/ipv4/tcp_highspeed.c @@ -116,7 +116,7 @@ static void hstcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) if (!tcp_is_cwnd_limited(sk)) return; - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tcp_in_slow_start(tp)) tcp_slow_start(tp, acked); else { /* Update AIMD parameters. diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c index 58469fff6c18f..82f0d9ed60f50 100644 --- a/net/ipv4/tcp_htcp.c +++ b/net/ipv4/tcp_htcp.c @@ -236,7 +236,7 @@ static void htcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) if (!tcp_is_cwnd_limited(sk)) return; - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tcp_in_slow_start(tp)) tcp_slow_start(tp, acked); else { /* In dangerous area, increase slowly. diff --git a/net/ipv4/tcp_illinois.c b/net/ipv4/tcp_illinois.c index f71002e4db0ba..2ab9bbb6faffb 100644 --- a/net/ipv4/tcp_illinois.c +++ b/net/ipv4/tcp_illinois.c @@ -268,7 +268,7 @@ static void tcp_illinois_cong_avoid(struct sock *sk, u32 ack, u32 acked) return; /* In slow start */ - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tcp_in_slow_start(tp)) tcp_slow_start(tp, acked); else { diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index a51d63a43e33a..b3d64f61d922e 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -461,7 +461,7 @@ void tcp_update_metrics(struct sock *sk) tcp_metric_set(tm, TCP_METRIC_CWND, tp->snd_cwnd); } - } else if (tp->snd_cwnd > tp->snd_ssthresh && + } else if (!tcp_in_slow_start(tp) && icsk->icsk_ca_state == TCP_CA_Open) { /* Cong. avoidance phase, cwnd is reliable. */ if (!tcp_metric_locked(tm, TCP_METRIC_SSTHRESH)) diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c index 333bcb2415ffc..bf5ea9e9bbc1e 100644 --- a/net/ipv4/tcp_scalable.c +++ b/net/ipv4/tcp_scalable.c @@ -22,7 +22,7 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 acked) if (!tcp_is_cwnd_limited(sk)) return; - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tcp_in_slow_start(tp)) tcp_slow_start(tp, acked); else tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT), diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index a6cea1d5e20d4..13951c4087d40 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c @@ -225,7 +225,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) */ diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT; - if (diff > gamma && tp->snd_cwnd <= tp->snd_ssthresh) { + if (diff > gamma && tcp_in_slow_start(tp)) { /* Going too fast. Time to slow down * and switch to congestion avoidance. */ @@ -240,7 +240,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); tp->snd_ssthresh = tcp_vegas_ssthresh(tp); - } else if (tp->snd_cwnd <= tp->snd_ssthresh) { + } else if (tcp_in_slow_start(tp)) { /* Slow start. */ tcp_slow_start(tp, acked); } else { @@ -281,7 +281,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked) vegas->minRTT = 0x7fffffff; } /* Use normal slow start */ - else if (tp->snd_cwnd <= tp->snd_ssthresh) + else if (tcp_in_slow_start(tp)) tcp_slow_start(tp, acked); } diff --git a/net/ipv4/tcp_veno.c b/net/ipv4/tcp_veno.c index 112151eeee45b..0d094b995cd96 100644 --- a/net/ipv4/tcp_veno.c +++ b/net/ipv4/tcp_veno.c @@ -150,7 +150,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 acked) veno->diff = (tp->snd_cwnd << V_PARAM_SHIFT) - target_cwnd; - if (tp->snd_cwnd <= tp->snd_ssthresh) { + if (tcp_in_slow_start(tp)) { /* Slow start. */ tcp_slow_start(tp, acked); } else { -- GitLab From 76174004a0f19785a328f40388e87e982bbf69b9 Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 9 Jul 2015 13:16:30 -0700 Subject: [PATCH 0664/7006] tcp: do not slow start when cwnd equals ssthresh In the original design slow start is only used to raise cwnd when cwnd is stricly below ssthresh. It makes little sense to slow start when cwnd == ssthresh: especially when hystart has set ssthresh in the initial ramp, or after recovery when cwnd resets to ssthresh. Not doing so will also help reduce the buffer bloat slightly. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: Nandita Dukkipati Signed-off-by: David S. Miller --- include/net/tcp.h | 2 +- net/ipv4/tcp_cdg.c | 2 +- net/ipv4/tcp_cong.c | 4 +--- net/ipv4/tcp_hybla.c | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index dba22fc1b065a..364426a2be5a0 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -991,7 +991,7 @@ static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) static inline bool tcp_in_slow_start(const struct tcp_sock *tp) { - return tp->snd_cwnd <= tp->snd_ssthresh; + return tp->snd_cwnd < tp->snd_ssthresh; } static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp) diff --git a/net/ipv4/tcp_cdg.c b/net/ipv4/tcp_cdg.c index 8c6fd3d5e40fe..167b6a3e1b986 100644 --- a/net/ipv4/tcp_cdg.c +++ b/net/ipv4/tcp_cdg.c @@ -264,7 +264,7 @@ static void tcp_cdg_cong_avoid(struct sock *sk, u32 ack, u32 acked) u32 prior_snd_cwnd; u32 incr; - if (tp->snd_cwnd < tp->snd_ssthresh && hystart_detect) + if (tcp_in_slow_start(tp) && hystart_detect) tcp_cdg_hystart_update(sk); if (after(ack, ca->rtt_seq) && ca->rtt.v64) { diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index 654729a8cb23f..a2ed23c595cf1 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -365,10 +365,8 @@ int tcp_set_congestion_control(struct sock *sk, const char *name) */ u32 tcp_slow_start(struct tcp_sock *tp, u32 acked) { - u32 cwnd = tp->snd_cwnd + acked; + u32 cwnd = min(tp->snd_cwnd + acked, tp->snd_ssthresh); - if (cwnd > tp->snd_ssthresh) - cwnd = tp->snd_ssthresh + 1; acked -= cwnd - tp->snd_cwnd; tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp); diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c index f963b274f2b04..083831e359df9 100644 --- a/net/ipv4/tcp_hybla.c +++ b/net/ipv4/tcp_hybla.c @@ -112,7 +112,7 @@ static void hybla_cong_avoid(struct sock *sk, u32 ack, u32 acked) rho_fractions = ca->rho_3ls - (ca->rho << 3); - if (tp->snd_cwnd < tp->snd_ssthresh) { + if (tcp_in_slow_start(tp)) { /* * slow start * INC = 2^RHO - 1 -- GitLab From b20a3fa30a281b52b2576b509efbe5cd47a5a79b Mon Sep 17 00:00:00 2001 From: Yuchung Cheng Date: Thu, 9 Jul 2015 13:16:31 -0700 Subject: [PATCH 0665/7006] tcp: update congestion state first before raising cwnd The congestion state and cwnd can be updated in the wrong order. For example, upon receiving a dubious ACK, we incorrectly raise the cwnd first (tcp_may_raise_cwnd()/tcp_cong_avoid()) because the state is still Open, then enter recovery state to reduce cwnd. For another example, if the ACK indicates spurious timeout or retransmits, we first revert the cwnd reduction and congestion state back to Open state. But we don't raise the cwnd even though the ACK does not indicate any congestion. To fix this problem we should first call tcp_fastretrans_alert() to process the dubious ACK and update the congestion state, then call tcp_may_raise_cwnd() that raises cwnd based on the current state. Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: Nandita Dukkipati Signed-off-by: David S. Miller --- net/ipv4/tcp_input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7f4a8d5f6eb0f..1578fc2a6f39b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3568,10 +3568,6 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) &sack_state); acked -= tp->packets_out; - /* Advance cwnd if state allows */ - if (tcp_may_raise_cwnd(sk, flag)) - tcp_cong_avoid(sk, ack, acked); - if (tcp_ack_is_dubious(sk, flag)) { is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); tcp_fastretrans_alert(sk, acked, prior_unsacked, @@ -3580,6 +3576,10 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) if (tp->tlp_high_seq) tcp_process_tlp_ack(sk, ack, flag); + /* Advance cwnd if state allows */ + if (tcp_may_raise_cwnd(sk, flag)) + tcp_cong_avoid(sk, ack, acked); + if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) { struct dst_entry *dst = __sk_dst_get(sk); if (dst) -- GitLab From 7c3d0d67d5ddb2aeb3fdae540a567a56c2831d2a Mon Sep 17 00:00:00 2001 From: "Aleksey S. Kazantsev" Date: Tue, 7 Jul 2015 20:38:15 -0700 Subject: [PATCH 0666/7006] dsa: mv88e6352/mv88e6xxx: Add support for Marvell 88E6320 and 88E6321 MV88E6320 and MV88E6321 are largely compatible to MV886352, but are members of a different chip family. Signed-off-by: Aleksey S. Kazantsev Signed-off-by: Guenter Roeck Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/Kconfig | 6 +++--- drivers/net/dsa/mv88e6352.c | 31 +++++++++++++++++++++------ drivers/net/dsa/mv88e6xxx.c | 42 ++++++++++++++++++++++++++----------- drivers/net/dsa/mv88e6xxx.h | 8 ++++++- 4 files changed, 65 insertions(+), 22 deletions(-) diff --git a/drivers/net/dsa/Kconfig b/drivers/net/dsa/Kconfig index 7ad0a4d8e475f..4c483d9374817 100644 --- a/drivers/net/dsa/Kconfig +++ b/drivers/net/dsa/Kconfig @@ -46,13 +46,13 @@ config NET_DSA_MV88E6171 ethernet switches chips. config NET_DSA_MV88E6352 - tristate "Marvell 88E6172/88E6176/88E6352 ethernet switch chip support" + tristate "Marvell 88E6172/6176/6320/6321/6352 ethernet switch chip support" depends on NET_DSA select NET_DSA_MV88E6XXX select NET_DSA_TAG_EDSA ---help--- - This enables support for the Marvell 88E6172, 88E6176 and 88E6352 - ethernet switch chips. + This enables support for the Marvell 88E6172, 88E6176, 88E6320, + 88E6321 and 88E6352 ethernet switch chips. config NET_DSA_BCM_SF2 tristate "Broadcom Starfighter 2 Ethernet switch support" diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 632815c10a401..cfece5ae9d5fd 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -36,6 +36,18 @@ static char *mv88e6352_probe(struct device *host_dev, int sw_addr) return "Marvell 88E6172"; if ((ret & 0xfff0) == PORT_SWITCH_ID_6176) return "Marvell 88E6176"; + if (ret == PORT_SWITCH_ID_6320_A1) + return "Marvell 88E6320 (A1)"; + if (ret == PORT_SWITCH_ID_6320_A2) + return "Marvell 88e6320 (A2)"; + if ((ret & 0xfff0) == PORT_SWITCH_ID_6320) + return "Marvell 88E6320"; + if (ret == PORT_SWITCH_ID_6321_A1) + return "Marvell 88E6321 (A1)"; + if (ret == PORT_SWITCH_ID_6321_A2) + return "Marvell 88e6321 (A2)"; + if ((ret & 0xfff0) == PORT_SWITCH_ID_6321) + return "Marvell 88E6321"; if (ret == PORT_SWITCH_ID_6352_A0) return "Marvell 88E6352 (A0)"; if (ret == PORT_SWITCH_ID_6352_A1) @@ -84,11 +96,12 @@ static int mv88e6352_setup_global(struct dsa_switch *ds) static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; *temp = 0; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 27); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); if (ret < 0) return ret; @@ -99,11 +112,12 @@ static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; *temp = 0; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); if (ret < 0) return ret; @@ -114,23 +128,25 @@ static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); if (ret < 0) return ret; temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - return mv88e6xxx_phy_page_write(ds, 0, 6, 26, + return mv88e6xxx_phy_page_write(ds, phy, 6, 26, (ret & 0xe0ff) | (temp << 8)); } static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm) { + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; int ret; *alarm = false; - ret = mv88e6xxx_phy_page_read(ds, 0, 6, 26); + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); if (ret < 0) return ret; @@ -394,5 +410,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .fdb_getnext = mv88e6xxx_port_fdb_getnext, }; -MODULE_ALIAS("platform:mv88e6352"); MODULE_ALIAS("platform:mv88e6172"); +MODULE_ALIAS("platform:mv88e6176"); +MODULE_ALIAS("platform:mv88e6320"); +MODULE_ALIAS("platform:mv88e6321"); +MODULE_ALIAS("platform:mv88e6352"); diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index fd8547c2b79d4..f394e4d4d9e00 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -517,6 +517,18 @@ static bool mv88e6xxx_6185_family(struct dsa_switch *ds) return false; } +bool mv88e6xxx_6320_family(struct dsa_switch *ds) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + + switch (ps->id) { + case PORT_SWITCH_ID_6320: + case PORT_SWITCH_ID_6321: + return true; + } + return false; +} + static bool mv88e6xxx_6351_family(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -565,7 +577,7 @@ static int _mv88e6xxx_stats_snapshot(struct dsa_switch *ds, int port) { int ret; - if (mv88e6xxx_6352_family(ds)) + if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds)) port = (port + 1) << 5; /* Snapshot the hardware statistics counters for this port. */ @@ -1377,7 +1389,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || - mv88e6xxx_6065_family(ds)) { + mv88e6xxx_6065_family(ds) || mv88e6xxx_6320_family(ds)) { /* MAC Forcing register: don't force link, speed, * duplex or flow control state to any particular * values on physical ports, but force the CPU port @@ -1423,7 +1435,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || - mv88e6xxx_6185_family(ds)) + mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) reg = PORT_CONTROL_IGMP_MLD_SNOOP | PORT_CONTROL_USE_TAG | PORT_CONTROL_USE_IP | PORT_CONTROL_STATE_FORWARDING; @@ -1431,7 +1443,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) reg |= PORT_CONTROL_DSA_TAG; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6320_family(ds)) { if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) reg |= PORT_CONTROL_FRAME_ETHER_TYPE_DSA; else @@ -1441,14 +1454,15 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || - mv88e6xxx_6185_family(ds)) { + mv88e6xxx_6185_family(ds) || mv88e6xxx_6320_family(ds)) { if (ds->dst->tag_protocol == DSA_TAG_PROTO_EDSA) reg |= PORT_CONTROL_EGRESS_ADD_TAG; } } if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds)) { + mv88e6xxx_6095_family(ds) || mv88e6xxx_6065_family(ds) || + mv88e6xxx_6320_family(ds)) { if (ds->dsa_port_mask & (1 << port)) reg |= PORT_CONTROL_FRAME_MODE_DSA; if (port == dsa_upstream_port(ds)) @@ -1473,11 +1487,11 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) reg = 0; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6095_family(ds)) + mv88e6xxx_6095_family(ds) || mv88e6xxx_6320_family(ds)) reg = PORT_CONTROL_2_MAP_DA; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds)) + mv88e6xxx_6165_family(ds) || mv88e6xxx_6320_family(ds)) reg |= PORT_CONTROL_2_JUMBO_10240; if (mv88e6xxx_6095_family(ds) || mv88e6xxx_6185_family(ds)) { @@ -1514,7 +1528,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) goto abort; if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Do not limit the period of time that this port can * be paused for by the remote end or the period of * time that this port can pause the remote end. @@ -1564,7 +1579,8 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Rate Control: disable ingress rate limiting. */ ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_RATE_CONTROL, 0x0001); @@ -1976,7 +1992,8 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) (i << GLOBAL2_TRUNK_MAPPING_ID_SHIFT)); if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || - mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds)) { + mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Send all frames with destination addresses matching * 01:80:c2:00:00:2x to the CPU port. */ @@ -1995,7 +2012,8 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds) if (mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds) || mv88e6xxx_6165_family(ds) || mv88e6xxx_6097_family(ds) || - mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds)) { + mv88e6xxx_6185_family(ds) || mv88e6xxx_6095_family(ds) || + mv88e6xxx_6320_family(ds)) { /* Disable ingress rate limiting by resetting all * ingress rate limit registers to their initial * state. diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index a650b2656de9f..64786cb89a93b 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -89,7 +89,12 @@ #define PORT_SWITCH_ID_6182 0x1a60 #define PORT_SWITCH_ID_6185 0x1a70 #define PORT_SWITCH_ID_6240 0x2400 -#define PORT_SWITCH_ID_6320 0x1250 +#define PORT_SWITCH_ID_6320 0x1150 +#define PORT_SWITCH_ID_6320_A1 0x1151 +#define PORT_SWITCH_ID_6320_A2 0x1152 +#define PORT_SWITCH_ID_6321 0x3100 +#define PORT_SWITCH_ID_6321_A1 0x3101 +#define PORT_SWITCH_ID_6321_A2 0x3102 #define PORT_SWITCH_ID_6350 0x3710 #define PORT_SWITCH_ID_6351 0x3750 #define PORT_SWITCH_ID_6352 0x3520 @@ -410,6 +415,7 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int reg, int val); +bool mv88e6xxx_6320_family(struct dsa_switch *ds); extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; extern struct dsa_switch_driver mv88e6352_switch_driver; -- GitLab From 8b58a39846568dcd7d0c98b2fadc25018e59dedf Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 8 Jul 2015 23:32:12 +0200 Subject: [PATCH 0667/7006] ipv6: use flag instead of u16 for hop in inet6_skb_parm Hop was always either 0 or sizeof(struct ipv6hdr). Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/linux/ipv6.h | 2 +- net/ipv6/af_inet6.c | 4 ++-- net/ipv6/datagram.c | 8 ++++---- net/ipv6/exthdrs.c | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 82806c60aa427..1319a6bb6b82b 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -94,7 +94,6 @@ static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb) struct inet6_skb_parm { int iif; __be16 ra; - __u16 hop; __u16 dst0; __u16 srcrt; __u16 dst1; @@ -111,6 +110,7 @@ struct inet6_skb_parm { #define IP6SKB_REROUTED 4 #define IP6SKB_ROUTERALERT 8 #define IP6SKB_FRAGMENTED 16 +#define IP6SKB_HOPBYHOP 32 }; #define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 7de52b65173fa..39e670a915969 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -679,8 +679,8 @@ bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, const struct ipv6_pinfo *np = inet6_sk(sk); if (np->rxopt.all) { - if ((opt->hop && (np->rxopt.bits.hopopts || - np->rxopt.bits.ohopopts)) || + if (((opt->flags & IP6SKB_HOPBYHOP) && + (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || (ip6_flowinfo((struct ipv6hdr *) skb_network_header(skb)) && np->rxopt.bits.rxflow) || (opt->srcrt && (np->rxopt.bits.srcrt || diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 62d908e64eeb5..50115522e80f1 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -558,8 +558,8 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, } /* HbH is allowed only once */ - if (np->rxopt.bits.hopopts && opt->hop) { - u8 *ptr = nh + opt->hop; + if (np->rxopt.bits.hopopts && (opt->flags & IP6SKB_HOPBYHOP)) { + u8 *ptr = nh + sizeof(struct ipv6hdr); put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr); } @@ -620,8 +620,8 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, int hlim = ipv6_hdr(skb)->hop_limit; put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); } - if (np->rxopt.bits.ohopopts && opt->hop) { - u8 *ptr = nh + opt->hop; + if (np->rxopt.bits.ohopopts && (opt->flags & IP6SKB_HOPBYHOP)) { + u8 *ptr = nh + sizeof(struct ipv6hdr); put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr); } if (np->rxopt.bits.odstopts && opt->dst0) { diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index a7bbbe45570b2..ce203b0402bea 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -632,7 +632,7 @@ int ipv6_parse_hopopts(struct sk_buff *skb) return -1; } - opt->hop = sizeof(struct ipv6hdr); + opt->flags |= IP6SKB_HOPBYHOP; if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; opt = IP6CB(skb); -- GitLab From 3fd2f1b9d91284afb957ab9899a83279d0e09f29 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jul 2015 14:28:28 -0700 Subject: [PATCH 0668/7006] inet: remove BUG_ON() in twsk_destructor() Kernel will crash the same if one of the pointer is NULL anyway. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/timewait_sock.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/net/timewait_sock.h b/include/net/timewait_sock.h index 68f0ecad6c6e2..1a47946f95ba4 100644 --- a/include/net/timewait_sock.h +++ b/include/net/timewait_sock.h @@ -33,9 +33,6 @@ static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) static inline void twsk_destructor(struct sock *sk) { - BUG_ON(sk == NULL); - BUG_ON(sk->sk_prot == NULL); - BUG_ON(sk->sk_prot->twsk_prot == NULL); if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) sk->sk_prot->twsk_prot->twsk_destructor(sk); } -- GitLab From fc01538f9fb75572c969ca9988176ffc2a8741d6 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jul 2015 14:28:29 -0700 Subject: [PATCH 0669/7006] inet: simplify timewait refcounting timewait sockets have a complex refcounting logic. Once we realize it should be similar to established and syn_recv sockets, we can use sk_nulls_del_node_init_rcu() and remove inet_twsk_unhash() In particular, deferred inet_twsk_put() added in commit 13475a30b66cd ("tcp: connect() race with timewait reuse") looks unecessary : When removing a timewait socket from ehash or bhash, caller must own a reference on the socket anyway. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_hashtables.h | 4 +-- include/net/inet_timewait_sock.h | 6 ++--- net/ipv4/inet_hashtables.c | 31 ++++++++--------------- net/ipv4/inet_timewait_sock.c | 42 +++++--------------------------- net/ipv6/inet6_hashtables.c | 6 +---- 5 files changed, 21 insertions(+), 68 deletions(-) diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index b73c88a19dd40..b07d126694a7a 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -205,8 +205,8 @@ void inet_put_port(struct sock *sk); void inet_hashinfo_init(struct inet_hashinfo *h); -int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw); -int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw); +void __inet_hash_nolisten(struct sock *sk, struct sock *osk); +void __inet_hash(struct sock *sk, struct sock *osk); void inet_hash(struct sock *sk); void inet_unhash(struct sock *sk); diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 360c4802288db..96f52a4711c8b 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -100,10 +100,8 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk) void inet_twsk_free(struct inet_timewait_sock *tw); void inet_twsk_put(struct inet_timewait_sock *tw); -int inet_twsk_unhash(struct inet_timewait_sock *tw); - -int inet_twsk_bind_unhash(struct inet_timewait_sock *tw, - struct inet_hashinfo *hashinfo); +void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, + struct inet_hashinfo *hashinfo); struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, struct inet_timewait_death_row *dr, diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 5f9b063bbe8ab..e58840330da7e 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -343,7 +343,6 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_nulls_node *node; struct inet_timewait_sock *tw = NULL; - int twrefcnt = 0; spin_lock(lock); @@ -371,12 +370,10 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, WARN_ON(!sk_unhashed(sk)); __sk_nulls_add_node_rcu(sk, &head->chain); if (tw) { - twrefcnt = inet_twsk_unhash(tw); + sk_nulls_del_node_init_rcu((struct sock *)tw); NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); } spin_unlock(lock); - if (twrefcnt) - inet_twsk_put(tw); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); if (twp) { @@ -384,7 +381,6 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, } else if (tw) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw); - inet_twsk_put(tw); } return 0; @@ -403,13 +399,12 @@ static u32 inet_sk_port_offset(const struct sock *sk) inet->inet_dport); } -int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw) +void __inet_hash_nolisten(struct sock *sk, struct sock *osk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct hlist_nulls_head *list; struct inet_ehash_bucket *head; spinlock_t *lock; - int twrefcnt = 0; WARN_ON(!sk_unhashed(sk)); @@ -420,23 +415,22 @@ int __inet_hash_nolisten(struct sock *sk, struct inet_timewait_sock *tw) spin_lock(lock); __sk_nulls_add_node_rcu(sk, list); - if (tw) { - WARN_ON(sk->sk_hash != tw->tw_hash); - twrefcnt = inet_twsk_unhash(tw); + if (osk) { + WARN_ON(sk->sk_hash != osk->sk_hash); + sk_nulls_del_node_init_rcu(osk); } spin_unlock(lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - return twrefcnt; } EXPORT_SYMBOL_GPL(__inet_hash_nolisten); -int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw) +void __inet_hash(struct sock *sk, struct sock *osk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; struct inet_listen_hashbucket *ilb; if (sk->sk_state != TCP_LISTEN) - return __inet_hash_nolisten(sk, tw); + return __inet_hash_nolisten(sk, osk); WARN_ON(!sk_unhashed(sk)); ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; @@ -445,7 +439,6 @@ int __inet_hash(struct sock *sk, struct inet_timewait_sock *tw) __sk_nulls_add_node_rcu(sk, &ilb->head); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); spin_unlock(&ilb->lock); - return 0; } EXPORT_SYMBOL(__inet_hash); @@ -492,7 +485,6 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, struct inet_bind_bucket *tb; int ret; struct net *net = sock_net(sk); - int twrefcnt = 1; if (!snum) { int i, remaining, low, high, port; @@ -560,18 +552,15 @@ ok: inet_bind_hash(sk, tb, port); if (sk_unhashed(sk)) { inet_sk(sk)->inet_sport = htons(port); - twrefcnt += __inet_hash_nolisten(sk, tw); + __inet_hash_nolisten(sk, (struct sock *)tw); } if (tw) - twrefcnt += inet_twsk_bind_unhash(tw, hinfo); + inet_twsk_bind_unhash(tw, hinfo); spin_unlock(&head->lock); if (tw) { inet_twsk_deschedule(tw); - while (twrefcnt) { - twrefcnt--; - inet_twsk_put(tw); - } + inet_twsk_put(tw); } ret = 0; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 2ffbd16b79e00..92cd4d50404eb 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -17,28 +17,6 @@ #include -/** - * inet_twsk_unhash - unhash a timewait socket from established hash - * @tw: timewait socket - * - * unhash a timewait socket from established hash, if hashed. - * ehash lock must be held by caller. - * Returns 1 if caller should call inet_twsk_put() after lock release. - */ -int inet_twsk_unhash(struct inet_timewait_sock *tw) -{ - if (hlist_nulls_unhashed(&tw->tw_node)) - return 0; - - hlist_nulls_del_rcu(&tw->tw_node); - sk_nulls_node_init(&tw->tw_node); - /* - * We cannot call inet_twsk_put() ourself under lock, - * caller must call it for us. - */ - return 1; -} - /** * inet_twsk_bind_unhash - unhash a timewait socket from bind hash * @tw: timewait socket @@ -48,35 +26,29 @@ int inet_twsk_unhash(struct inet_timewait_sock *tw) * bind hash lock must be held by caller. * Returns 1 if caller should call inet_twsk_put() after lock release. */ -int inet_twsk_bind_unhash(struct inet_timewait_sock *tw, +void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, struct inet_hashinfo *hashinfo) { struct inet_bind_bucket *tb = tw->tw_tb; if (!tb) - return 0; + return; __hlist_del(&tw->tw_bind_node); tw->tw_tb = NULL; inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); - /* - * We cannot call inet_twsk_put() ourself under lock, - * caller must call it for us. - */ - return 1; + __sock_put((struct sock *)tw); } /* Must be called with locally disabled BHs. */ static void inet_twsk_kill(struct inet_timewait_sock *tw) { struct inet_hashinfo *hashinfo = tw->tw_dr->hashinfo; - struct inet_bind_hashbucket *bhead; - int refcnt; - /* Unlink from established hashes. */ spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); + struct inet_bind_hashbucket *bhead; spin_lock(lock); - refcnt = inet_twsk_unhash(tw); + sk_nulls_del_node_init_rcu((struct sock *)tw); spin_unlock(lock); /* Disassociate with bind bucket. */ @@ -84,11 +56,9 @@ static void inet_twsk_kill(struct inet_timewait_sock *tw) hashinfo->bhash_size)]; spin_lock(&bhead->lock); - refcnt += inet_twsk_bind_unhash(tw, hashinfo); + inet_twsk_bind_unhash(tw, hashinfo); spin_unlock(&bhead->lock); - BUG_ON(refcnt >= atomic_read(&tw->tw_refcnt)); - atomic_sub(refcnt, &tw->tw_refcnt); atomic_dec(&tw->tw_dr->tw_count); inet_twsk_put(tw); } diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index b4fd96de97e61..a237398aa2b49 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -207,7 +207,6 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, struct sock *sk2; const struct hlist_nulls_node *node; struct inet_timewait_sock *tw = NULL; - int twrefcnt = 0; spin_lock(lock); @@ -234,12 +233,10 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, WARN_ON(!sk_unhashed(sk)); __sk_nulls_add_node_rcu(sk, &head->chain); if (tw) { - twrefcnt = inet_twsk_unhash(tw); + sk_nulls_del_node_init_rcu((struct sock *)tw); NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED); } spin_unlock(lock); - if (twrefcnt) - inet_twsk_put(tw); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); if (twp) { @@ -247,7 +244,6 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, } else if (tw) { /* Silly. Should hash-dance instead... */ inet_twsk_deschedule(tw); - inet_twsk_put(tw); } return 0; -- GitLab From dbe7faa4045ea83a37b691b12bb02a8f86c2d2e9 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 8 Jul 2015 14:28:30 -0700 Subject: [PATCH 0670/7006] inet: inet_twsk_deschedule factorization inet_twsk_deschedule() calls are followed by inet_twsk_put(). Only particular case is in inet_twsk_purge() but there is no point to defer the inet_twsk_put() after re-enabling BH. Lets rename inet_twsk_deschedule() to inet_twsk_deschedule_put() and move the inet_twsk_put() inside. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/inet_timewait_sock.h | 2 +- net/ipv4/inet_hashtables.c | 9 +++------ net/ipv4/inet_timewait_sock.c | 13 ++++++++----- net/ipv4/tcp_ipv4.c | 3 +-- net/ipv4/tcp_minisocks.c | 6 ++---- net/ipv6/inet6_hashtables.c | 3 +-- net/ipv6/tcp_ipv6.c | 3 +-- net/netfilter/xt_TPROXY.c | 6 ++---- 8 files changed, 19 insertions(+), 26 deletions(-) diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 96f52a4711c8b..879d6e5a973b4 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -111,7 +111,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, struct inet_hashinfo *hashinfo); void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo); -void inet_twsk_deschedule(struct inet_timewait_sock *tw); +void inet_twsk_deschedule_put(struct inet_timewait_sock *tw); void inet_twsk_purge(struct inet_hashinfo *hashinfo, struct inet_timewait_death_row *twdr, int family); diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index e58840330da7e..f8b3701a6c3c6 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -380,8 +380,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, *twp = tw; } else if (tw) { /* Silly. Should hash-dance instead... */ - inet_twsk_deschedule(tw); - inet_twsk_put(tw); + inet_twsk_deschedule_put(tw); } return 0; @@ -558,10 +557,8 @@ ok: inet_twsk_bind_unhash(tw, hinfo); spin_unlock(&head->lock); - if (tw) { - inet_twsk_deschedule(tw); - inet_twsk_put(tw); - } + if (tw) + inet_twsk_deschedule_put(tw); ret = 0; goto out; diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 92cd4d50404eb..ae22cc24fbe89 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -205,13 +205,17 @@ EXPORT_SYMBOL_GPL(inet_twsk_alloc); * tcp_input.c to verify this. */ -/* This is for handling early-kills of TIME_WAIT sockets. */ -void inet_twsk_deschedule(struct inet_timewait_sock *tw) +/* This is for handling early-kills of TIME_WAIT sockets. + * Warning : consume reference. + * Caller should not access tw anymore. + */ +void inet_twsk_deschedule_put(struct inet_timewait_sock *tw) { if (del_timer_sync(&tw->tw_timer)) inet_twsk_kill(tw); + inet_twsk_put(tw); } -EXPORT_SYMBOL(inet_twsk_deschedule); +EXPORT_SYMBOL(inet_twsk_deschedule_put); void inet_twsk_schedule(struct inet_timewait_sock *tw, const int timeo) { @@ -281,9 +285,8 @@ restart: rcu_read_unlock(); local_bh_disable(); - inet_twsk_deschedule(tw); + inet_twsk_deschedule_put(tw); local_bh_enable(); - inet_twsk_put(tw); goto restart_rcu; } /* If the nulls value we got at the end of this lookup is diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index d7d4c2b79cf2f..486ba96ae91a7 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1683,8 +1683,7 @@ do_time_wait: iph->daddr, th->dest, inet_iif(skb)); if (sk2) { - inet_twsk_deschedule(inet_twsk(sk)); - inet_twsk_put(inet_twsk(sk)); + inet_twsk_deschedule_put(inet_twsk(sk)); sk = sk2; goto process; } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 4bc00cb79e603..6d8795b066aca 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -147,8 +147,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, if (!th->fin || TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1) { kill_with_rst: - inet_twsk_deschedule(tw); - inet_twsk_put(tw); + inet_twsk_deschedule_put(tw); return TCP_TW_RST; } @@ -198,8 +197,7 @@ kill_with_rst: */ if (sysctl_tcp_rfc1337 == 0) { kill: - inet_twsk_deschedule(tw); - inet_twsk_put(tw); + inet_twsk_deschedule_put(tw); return TCP_TW_SUCCESS; } } diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index a237398aa2b49..6ac8dad0138a6 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -243,8 +243,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, *twp = tw; } else if (tw) { /* Silly. Should hash-dance instead... */ - inet_twsk_deschedule(tw); - inet_twsk_put(tw); + inet_twsk_deschedule_put(tw); } return 0; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 6748c4277affa..d540846a1a79e 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -1481,8 +1481,7 @@ do_time_wait: ntohs(th->dest), tcp_v6_iif(skb)); if (sk2) { struct inet_timewait_sock *tw = inet_twsk(sk); - inet_twsk_deschedule(tw); - inet_twsk_put(tw); + inet_twsk_deschedule_put(tw); sk = sk2; tcp_v6_restore_cb(skb); goto process; diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index cca96cec1b689..d0c96c5ae29aa 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c @@ -272,8 +272,7 @@ tproxy_handle_time_wait4(struct sk_buff *skb, __be32 laddr, __be16 lport, hp->source, lport ? lport : hp->dest, skb->dev, NFT_LOOKUP_LISTENER); if (sk2) { - inet_twsk_deschedule(inet_twsk(sk)); - inet_twsk_put(inet_twsk(sk)); + inet_twsk_deschedule_put(inet_twsk(sk)); sk = sk2; } } @@ -437,8 +436,7 @@ tproxy_handle_time_wait6(struct sk_buff *skb, int tproto, int thoff, tgi->lport ? tgi->lport : hp->dest, skb->dev, NFT_LOOKUP_LISTENER); if (sk2) { - inet_twsk_deschedule(inet_twsk(sk)); - inet_twsk_put(inet_twsk(sk)); + inet_twsk_deschedule_put(inet_twsk(sk)); sk = sk2; } } -- GitLab From 35a256fee52c7c207796302681fa95189c85b408 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 8 Jul 2015 16:58:22 -0700 Subject: [PATCH 0671/7006] ipv6: Nonlocal bind Add support to allow non-local binds similar to how this was done for IPv4. Non-local binds are very useful in emulating the Internet in a box, etc. This add the ip_nonlocal_bind sysctl under ipv6. Testing: Set up nonlocal binding and receive routing on a host, e.g.: ip -6 rule add from ::/0 iif eth0 lookup 200 ip -6 route add local 2001:0:0:1::/64 dev lo proto kernel scope host table 200 sysctl -w net.ipv6.ip_nonlocal_bind=1 Set up routing to 2001:0:0:1::/64 on peer to go to first host ping6 -I 2001:0:0:1::1 peer-address -- to verify Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 5 +++++ include/net/netns/ipv6.h | 1 + net/ipv4/ping.c | 3 ++- net/ipv6/af_inet6.c | 3 ++- net/ipv6/raw.c | 3 ++- net/ipv6/sysctl_net_ipv6.c | 8 ++++++++ 6 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 5fae7704daab2..f63aeefd2c240 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1435,6 +1435,11 @@ mtu - INTEGER Default Maximum Transfer Unit Default: 1280 (IPv6 required minimum) +ip_nonlocal_bind - BOOLEAN + If set, allows processes to bind() to non-local IPv6 addresses, + which can be quite useful - but may break some applications. + Default: 0 + router_probe_interval - INTEGER Minimum interval (in seconds) between Router Probing described in RFC4191. diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 8d93544a2d2b5..c0368db6df54d 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -31,6 +31,7 @@ struct netns_sysctl_ipv6 { int auto_flowlabels; int icmpv6_time; int anycast_src_echo_reply; + int ip_nonlocal_bind; int fwmark_reflect; int idgen_retries; int idgen_delay; diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c index 05ff44b758dfe..e89094ab5ddb8 100644 --- a/net/ipv4/ping.c +++ b/net/ipv4/ping.c @@ -363,7 +363,8 @@ static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk, scoped); rcu_read_unlock(); - if (!(isk->freebind || isk->transparent || has_addr || + if (!(net->ipv6.sysctl.ip_nonlocal_bind || + isk->freebind || isk->transparent || has_addr || addr_type == IPV6_ADDR_ANY)) return -EADDRNOTAVAIL; diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 39e670a915969..7bc92ea4ae8fd 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -342,7 +342,8 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { - if (!(inet->freebind || inet->transparent) && + if (!net->ipv6.sysctl.ip_nonlocal_bind && + !(inet->freebind || inet->transparent) && !ipv6_chk_addr(net, &addr->sin6_addr, dev, 0)) { err = -EADDRNOTAVAIL; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index ca4700cb26c4f..fdbada1569a37 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -295,7 +295,8 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) * unspecified and mapped address have a v4 equivalent. */ v4addr = LOOPBACK4_IPV6; - if (!(addr_type & IPV6_ADDR_MULTICAST)) { + if (!(addr_type & IPV6_ADDR_MULTICAST) && + !sock_net(sk)->ipv6.sysctl.ip_nonlocal_bind) { err = -EADDRNOTAVAIL; if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, dev, 0)) { diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 4e705add4f187..db48aebd9c470 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -75,6 +75,13 @@ static struct ctl_table ipv6_table_template[] = { .mode = 0644, .proc_handler = proc_dointvec }, + { + .procname = "ip_nonlocal_bind", + .data = &init_net.ipv6.sysctl.ip_nonlocal_bind, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { } }; @@ -117,6 +124,7 @@ static int __net_init ipv6_sysctl_net_init(struct net *net) ipv6_table[5].data = &net->ipv6.sysctl.idgen_retries; ipv6_table[6].data = &net->ipv6.sysctl.idgen_delay; ipv6_table[7].data = &net->ipv6.sysctl.flowlabel_state_ranges; + ipv6_table[8].data = &net->ipv6.sysctl.ip_nonlocal_bind; ipv6_route_table = ipv6_route_sysctl_init(net); if (!ipv6_route_table) -- GitLab From cb1c61680d29a054b91a23c7a504cea8a72bdcff Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Thu, 9 Jul 2015 12:46:35 +0900 Subject: [PATCH 0672/7006] route: remove unsed variable in __mkroute_input flags local variable in __mkroute_input is not used as a variable. Signed-off-by: Masatake YAMATO Signed-off-by: David S. Miller --- net/ipv4/route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index d0362a2de3d38..04c83de4f79e3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1546,7 +1546,6 @@ static int __mkroute_input(struct sk_buff *skb, struct rtable *rth; int err; struct in_device *out_dev; - unsigned int flags = 0; bool do_cache; u32 itag = 0; @@ -1610,7 +1609,7 @@ static int __mkroute_input(struct sk_buff *skb, } rth->rt_genid = rt_genid_ipv4(dev_net(rth->dst.dev)); - rth->rt_flags = flags; + rth->rt_flags = 0; rth->rt_type = res->type; rth->rt_is_input = 1; rth->rt_iif = 0; -- GitLab From 09cf0211f970311383fdb453bbd5b3beeb294324 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 9 Jul 2015 03:11:10 -0700 Subject: [PATCH 0673/7006] bridge: mdb: fill state in br_mdb_notify Fill also the port group state when sending notifications. Signed-off-by: Satish Ashok Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_mdb.c | 5 +++-- net/bridge/br_multicast.c | 5 +++-- net/bridge/br_private.h | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index e29ad70b3000b..1fb7d076f15c3 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -230,7 +230,7 @@ errout: } void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, - struct br_ip *group, int type) + struct br_ip *group, int type, u8 state) { struct br_mdb_entry entry; @@ -241,6 +241,7 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, #if IS_ENABLED(CONFIG_IPV6) entry.addr.u.ip6 = group->u.ip6; #endif + entry.state = state; __br_mdb_notify(dev, &entry, type); } @@ -348,7 +349,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port, return -ENOMEM; rcu_assign_pointer(*pp, p); - br_mdb_notify(br->dev, port, group, RTM_NEWMDB); + br_mdb_notify(br->dev, port, group, RTM_NEWMDB, state); return 0; } diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 742a6c27d7a22..5a44cd9473f2e 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -694,7 +694,7 @@ static int br_multicast_add_group(struct net_bridge *br, if (unlikely(!p)) goto err; rcu_assign_pointer(*pp, p); - br_mdb_notify(br->dev, port, group, RTM_NEWMDB); + br_mdb_notify(br->dev, port, group, RTM_NEWMDB, MDB_TEMPORARY); found: mod_timer(&p->timer, now + br->multicast_membership_interval); @@ -1439,8 +1439,9 @@ br_multicast_leave_group(struct net_bridge *br, rcu_assign_pointer(*pp, p->next); hlist_del_init(&p->mglist); del_timer(&p->timer); + br_mdb_notify(br->dev, port, group, RTM_DELMDB, + p->state); call_rcu_bh(&p->rcu, br_multicast_free_pg); - br_mdb_notify(br->dev, port, group, RTM_DELMDB); if (!mp->ports && !mp->mglist && netif_running(br->dev)) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 8b21146b24a05..c73fd785654da 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -488,7 +488,7 @@ br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group, void br_mdb_init(void); void br_mdb_uninit(void); void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, - struct br_ip *group, int type); + struct br_ip *group, int type, u8 state); #define mlock_dereference(X, br) \ rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) -- GitLab From a4e2405cc5d20ed6d58c4874325856e80e76a7f8 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Thu, 9 Jul 2015 18:01:40 +0200 Subject: [PATCH 0674/7006] tcp: do not export tcp_init_xmit_timers() After commit 900f65d361d3 ("tcp: move duplicate code from tcp_v4_init_sock()/tcp_v6_init_sock()"), we no longer need to export tcp_init_xmit_timers() Signed-off-by: Eric Dumazet Cc: Neal Cardwell Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_timer.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 5b752f58a9006..7149ebc820c7d 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -649,4 +649,3 @@ void tcp_init_xmit_timers(struct sock *sk) inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, &tcp_keepalive_timer); } -EXPORT_SYMBOL(tcp_init_xmit_timers); -- GitLab From 3ce095c16263630dde46d6051854073edaacf3d7 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:02 +0900 Subject: [PATCH 0675/7006] ALSA: aoa: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Takashi Iwai --- sound/aoa/codecs/onyx.c | 1 - sound/aoa/codecs/tas.c | 1 - 2 files changed, 2 deletions(-) diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c index 23c371ecfb6b3..a04edff8b729e 100644 --- a/sound/aoa/codecs/onyx.c +++ b/sound/aoa/codecs/onyx.c @@ -1050,7 +1050,6 @@ MODULE_DEVICE_TABLE(i2c,onyx_i2c_id); static struct i2c_driver onyx_driver = { .driver = { .name = "aoa_codec_onyx", - .owner = THIS_MODULE, }, .probe = onyx_i2c_probe, .remove = onyx_i2c_remove, diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c index 364c7c4416e8b..78ed1ffbf786e 100644 --- a/sound/aoa/codecs/tas.c +++ b/sound/aoa/codecs/tas.c @@ -939,7 +939,6 @@ MODULE_DEVICE_TABLE(i2c,tas_i2c_id); static struct i2c_driver tas_driver = { .driver = { .name = "aoa_codec_tas", - .owner = THIS_MODULE, }, .probe = tas_i2c_probe, .remove = tas_i2c_remove, -- GitLab From 44eda784a2229d25e2724ef1734fe67453716231 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Thu, 9 Jul 2015 21:55:06 -0700 Subject: [PATCH 0676/7006] HID: cp2112: support i2c write-read transfers in hid-cp2112 cp2112_i2c_xfer() only supports a single i2c_msg. More than one message at a time just returns EIO. This breaks certain important cases. For example, the at24 eeprom driver generates paired write and read messages (for eeprom address and data). Since the device doesn't support i2c repeated starts in general, but does support a single write-repeated-start-read pair (since hardware rev 1), we recognize the latter case and implement only that. Signed-off-by: Ellen Wang Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 74 +++++++++++++++++++++++++++++----------- 1 file changed, 55 insertions(+), 19 deletions(-) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 75398cb84fde2..1d24a65b42952 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -156,6 +156,7 @@ struct cp2112_device { wait_queue_head_t wait; u8 read_data[61]; u8 read_length; + u8 hwversion; int xfer_status; atomic_t read_avail; atomic_t xfer_avail; @@ -446,6 +447,24 @@ static int cp2112_i2c_write_req(void *buf, u8 slave_address, u8 *data, return data_length + 3; } +static int cp2112_i2c_write_read_req(void *buf, u8 slave_address, + u8 *addr, int addr_length, + int read_length) +{ + struct cp2112_write_read_req_report *report = buf; + + if (read_length < 1 || read_length > 512 || + addr_length > sizeof(report->target_address)) + return -EINVAL; + + report->report = CP2112_DATA_WRITE_READ_REQUEST; + report->slave_address = slave_address << 1; + report->length = cpu_to_be16(read_length); + report->target_address_length = addr_length; + memcpy(report->target_address, addr, addr_length); + return addr_length + 5; +} + static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { @@ -453,26 +472,46 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, struct hid_device *hdev = dev->hdev; u8 buf[64]; ssize_t count; + ssize_t read_length = 0; + u8 *read_buf = NULL; unsigned int retries; int ret; hid_dbg(hdev, "I2C %d messages\n", num); - if (num != 1) { + if (num == 1) { + if (msgs->flags & I2C_M_RD) { + hid_dbg(hdev, "I2C read %#04x len %d\n", + msgs->addr, msgs->len); + read_length = msgs->len; + read_buf = msgs->buf; + count = cp2112_read_req(buf, msgs->addr, msgs->len); + } else { + hid_dbg(hdev, "I2C write %#04x len %d\n", + msgs->addr, msgs->len); + count = cp2112_i2c_write_req(buf, msgs->addr, + msgs->buf, msgs->len); + } + if (count < 0) + return count; + } else if (dev->hwversion > 1 && /* no repeated start in rev 1 */ + num == 2 && + msgs[0].addr == msgs[1].addr && + !(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD)) { + hid_dbg(hdev, "I2C write-read %#04x wlen %d rlen %d\n", + msgs[0].addr, msgs[0].len, msgs[1].len); + read_length = msgs[1].len; + read_buf = msgs[1].buf; + count = cp2112_i2c_write_read_req(buf, msgs[0].addr, + msgs[0].buf, msgs[0].len, msgs[1].len); + if (count < 0) + return count; + } else { hid_err(hdev, "Multi-message I2C transactions not supported\n"); return -EOPNOTSUPP; } - if (msgs->flags & I2C_M_RD) - count = cp2112_read_req(buf, msgs->addr, msgs->len); - else - count = cp2112_i2c_write_req(buf, msgs->addr, msgs->buf, - msgs->len); - - if (count < 0) - return count; - ret = hid_hw_power(hdev, PM_HINT_FULLON); if (ret < 0) { hid_err(hdev, "power management error: %d\n", ret); @@ -508,11 +547,8 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto power_normal; } - if (!(msgs->flags & I2C_M_RD)) - goto finish; - - for (count = 0; count < msgs->len;) { - ret = cp2112_read(dev, msgs->buf + count, msgs->len - count); + for (count = 0; count < read_length;) { + ret = cp2112_read(dev, read_buf + count, read_length - count); if (ret < 0) goto power_normal; if (ret == 0) { @@ -521,7 +557,7 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto power_normal; } count += ret; - if (count > msgs->len) { + if (count > read_length) { /* * The hardware returned too much data. * This is mostly harmless because cp2112_read() @@ -531,15 +567,14 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, * it shouldn't go unnoticed. */ hid_err(hdev, "long read: %d > %zd\n", - ret, msgs->len - count + ret); + ret, read_length - count + ret); ret = -EIO; goto power_normal; } } -finish: /* return the number of transferred messages */ - ret = 1; + ret = num; power_normal: hid_hw_power(hdev, PM_HINT_NORMAL); @@ -1047,6 +1082,7 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) dev->adap.dev.parent = &hdev->dev; snprintf(dev->adap.name, sizeof(dev->adap.name), "CP2112 SMBus Bridge on hiddev%d", hdev->minor); + dev->hwversion = buf[2]; init_waitqueue_head(&dev->wait); hid_device_io_start(hdev); -- GitLab From 3eb4351af42bd8b6de20daab07b204a85c35248f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 9 Jul 2015 14:33:21 -0700 Subject: [PATCH 0677/7006] HID: input: call input_sync() when automatically releasing a key We need to emit EV_SYN/SYN_REPORT between key press and release, otherwise userspace is allowed to "swallow" the event. [jkosina@suse.com: Dmitry says that he's observing this behavior with Plantronics headset] Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 3511bbaba505a..14aebe4832194 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1163,8 +1163,11 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct input_event(input, usage->type, usage->code, value); - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY)) + if ((field->flags & HID_MAIN_ITEM_RELATIVE) && + usage->type == EV_KEY && value) { + input_sync(input); input_event(input, usage->type, usage->code, 0); + } } void hidinput_report_event(struct hid_device *hid, struct hid_report *report) -- GitLab From eeedcea69e927857d32aaf089725eddd2c79dd0a Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 26 Jun 2015 08:09:29 +0100 Subject: [PATCH 0678/7006] ARM: 8395/1: l2c: Add support for the "arm,shared-override" property "CoreLink Level 2 Cache Controller L2C-310", p. 2-15, section 2.3.2 Shareable attribute" states: "The default behavior of the cache controller with respect to the shareable attribute is to transform Normal Memory Non-cacheable transactions into: - cacheable no allocate for reads - write through no write allocate for writes." Depending on the system architecture, this may cause memory corruption in the presence of bus mastering devices (e.g. OHCI). To avoid such corruption, the default behavior can be disabled by setting the Shared Override bit in the Auxiliary Control register. Currently the Shared Override bit can be set only using C code: - by calling l2x0_init() directly, which is deprecated, - by setting/clearing the bit in the machine_desc.l2c_aux_val/mask fields, but using values differing from 0/~0 is also deprecated. Hence add support for an "arm,shared-override" device tree property for the l2c device node. By specifying this property, affected systems can indicate that non-cacheable transactions must not be transformed. Then, it's up to the OS to decide. The current behavior is to set the "shared attribute override enable" bit, as there may exist kernel linear mappings and cacheable aliases for the DMA buffers, even if CMA is enabled. See also commit 1a8e41cd672f894b ("ARM: 6395/1: VExpress: Set bit 22 in the PL310 (cache controller) AuxCtlr register"): "Clearing bit 22 in the PL310 Auxiliary Control register (shared attribute override enable) has the side effect of transforming Normal Shared Non-cacheable reads into Cacheable no-allocate reads. Coherent DMA buffers in Linux always have a Cacheable alias via the kernel linear mapping and the processor can speculatively load cache lines into the PL310 controller. With bit 22 cleared, Non-cacheable reads would unexpectedly hit such cache lines leading to buffer corruption." Signed-off-by: Geert Uytterhoeven Acked-by: Catalin Marinas Signed-off-by: Russell King --- Documentation/devicetree/bindings/arm/l2cc.txt | 6 ++++++ arch/arm/mm/cache-l2x0.c | 5 +++++ 2 files changed, 11 insertions(+) diff --git a/Documentation/devicetree/bindings/arm/l2cc.txt b/Documentation/devicetree/bindings/arm/l2cc.txt index 2251dccb141ea..06c88a4d28ace 100644 --- a/Documentation/devicetree/bindings/arm/l2cc.txt +++ b/Documentation/devicetree/bindings/arm/l2cc.txt @@ -67,6 +67,12 @@ Optional properties: disable if zero. - arm,prefetch-offset : Override prefetch offset value. Valid values are 0-7, 15, 23, and 31. +- arm,shared-override : The default behavior of the pl310 cache controller with + respect to the shareable attribute is to transform "normal memory + non-cacheable transactions" into "cacheable no allocate" (for reads) or + "write through no write allocate" (for writes). + On systems where this may cause DMA buffer corruption, this property must be + specified to indicate that such transforms are precluded. - prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1> (forcibly enable), property absent (retain settings set by firmware) - prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable), diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index 71b3d33090244..493692d838c67 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c @@ -1171,6 +1171,11 @@ static void __init l2c310_of_parse(const struct device_node *np, } } + if (of_property_read_bool(np, "arm,shared-override")) { + *aux_val |= L2C_AUX_CTRL_SHARED_OVERRIDE; + *aux_mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE; + } + prefetch = l2x0_saved_regs.prefetch_ctrl; ret = of_property_read_u32(np, "arm,double-linefill", &val); -- GitLab From 8ded1e1a92daa96307e4b84b707fee5993bc6047 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 7 Jul 2015 18:16:15 +0100 Subject: [PATCH 0679/7006] ARM: 8401/1: perf: Set affinity for PPI based PMUs For PPI based PMUs, we bail out early in of_pmu_irq_cfg() without setting the PMU's supported_cpus bitmap. This causes the smp_call_function_any() in armv7_probe_num_events() to fail. Set the bitmap to be all CPUs so that we properly probe PMUs that use PPIs. Fixes: cc88116da0d1 ("arm: perf: treat PMUs as CPU affine") Cc: Mark Rutland Signed-off-by: Stephen Boyd Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/perf_event.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 357f57ea83f4b..f3ddd0ff2d8b0 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -795,8 +795,10 @@ static int of_pmu_irq_cfg(struct arm_pmu *pmu) /* Don't bother with PPIs; they're already affine */ irq = platform_get_irq(pdev, 0); - if (irq >= 0 && irq_is_percpu(irq)) + if (irq >= 0 && irq_is_percpu(irq)) { + cpumask_setall(&pmu->supported_cpus); return 0; + } irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL); if (!irqs) -- GitLab From 57853e8906a04a86c32fb96d8421b923c6d64162 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 7 Jul 2015 18:19:38 +0100 Subject: [PATCH 0680/7006] ARM: 8403/1: kbuild: don't use generic mcs_spinlock.h header We provide our own implementation of asm/mcs_spinlock.h, so there's no need to ask for the (empty) generic version. Signed-off-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/Kbuild | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/arm/include/asm/Kbuild b/arch/arm/include/asm/Kbuild index 83c50193626ce..517ef6dd22b9e 100644 --- a/arch/arm/include/asm/Kbuild +++ b/arch/arm/include/asm/Kbuild @@ -12,7 +12,6 @@ generic-y += irq_regs.h generic-y += kdebug.h generic-y += local.h generic-y += local64.h -generic-y += mcs_spinlock.h generic-y += msgbuf.h generic-y += param.h generic-y += parport.h -- GitLab From 7ff0589c7bff4ca31b255ac2028f633f14047762 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:22 +0000 Subject: [PATCH 0681/7006] regmap: add force_write option on _regmap_update_bits() Sometimes we want to write data even though it doesn't change value. Then, force_write option on _regmap_update_bits() helps this purpose. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f26218..69ec411ce7224 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -34,7 +34,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change); + bool *change, bool force_write); static int _regmap_bus_reg_read(void *context, unsigned int reg, unsigned int *val); @@ -1178,7 +1178,7 @@ static int _regmap_select_page(struct regmap *map, unsigned int *reg, ret = _regmap_update_bits(map, range->selector_reg, range->selector_mask, win_page << range->selector_shift, - &page_chg); + &page_chg, false); map->work_buf = orig_work_buf; @@ -2327,7 +2327,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_read); static int _regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val, - bool *change) + bool *change, bool force_write) { int ret; unsigned int tmp, orig; @@ -2339,7 +2339,7 @@ static int _regmap_update_bits(struct regmap *map, unsigned int reg, tmp = orig & ~mask; tmp |= val & mask; - if (tmp != orig) { + if (force_write || (tmp != orig)) { ret = _regmap_write(map, reg, tmp); if (change) *change = true; @@ -2367,7 +2367,7 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->unlock(map->lock_arg); return ret; @@ -2398,7 +2398,7 @@ int regmap_update_bits_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, NULL); + ret = _regmap_update_bits(map, reg, mask, val, NULL, false); map->async = false; @@ -2427,7 +2427,7 @@ int regmap_update_bits_check(struct regmap *map, unsigned int reg, int ret; map->lock(map->lock_arg); - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->unlock(map->lock_arg); return ret; } @@ -2460,7 +2460,7 @@ int regmap_update_bits_check_async(struct regmap *map, unsigned int reg, map->async = true; - ret = _regmap_update_bits(map, reg, mask, val, change); + ret = _regmap_update_bits(map, reg, mask, val, change, false); map->async = false; -- GitLab From fd4b7286ccc469bf5dde22db6b8fcc455c3c4a66 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:39 +0000 Subject: [PATCH 0682/7006] regmap: add regmap_write_bits() regmap_write_bits() is similar to regmap_update_bits(), but regmap_write_bits() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 23 +++++++++++++++++++++++ include/linux/regmap.h | 9 +++++++++ 2 files changed, 32 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 69ec411ce7224..d93bb9a8ab98c 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2374,6 +2374,29 @@ int regmap_update_bits(struct regmap *map, unsigned int reg, } EXPORT_SYMBOL_GPL(regmap_update_bits); +/** + * regmap_write_bits: Perform a read/modify/write cycle on the register map + * + * @map: Register map to update + * @reg: Register to update + * @mask: Bitmask to change + * @val: New value for bitmask + * + * Returns zero for success, a negative number on error. + */ +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + int ret; + + map->lock(map->lock_arg); + ret = _regmap_update_bits(map, reg, mask, val, NULL, true); + map->unlock(map->lock_arg); + + return ret; +} +EXPORT_SYMBOL_GPL(regmap_write_bits); + /** * regmap_update_bits_async: Perform a read/modify/write cycle on the register * map asynchronously diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea0f0b50..e4b9ad4f05ef3 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -424,6 +424,8 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, size_t val_count); int regmap_update_bits(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); +int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val); int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val); int regmap_update_bits_check(struct regmap *map, unsigned int reg, @@ -645,6 +647,13 @@ static inline int regmap_update_bits(struct regmap *map, unsigned int reg, return -EINVAL; } +static inline int regmap_write_bits(struct regmap *map, unsigned int reg, + unsigned int mask, unsigned int val) +{ + WARN_ONCE(1, "regmap API is disabled"); + return -EINVAL; +} + static inline int regmap_update_bits_async(struct regmap *map, unsigned int reg, unsigned int mask, unsigned int val) -- GitLab From e874e6c7edc43436f73cf84157d9221f8b807c36 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:52:55 +0000 Subject: [PATCH 0683/7006] regmap: add regmap_fields_force_write() regmap_fields_force_write() is similar to regmap_fields_write(), but regmap_fields_force_write() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 12 ++++++++++++ include/linux/regmap.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d93bb9a8ab98c..dd63bcbbf8a53 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1624,6 +1624,18 @@ int regmap_fields_write(struct regmap_field *field, unsigned int id, } EXPORT_SYMBOL_GPL(regmap_fields_write); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val) +{ + if (id >= field->id_size) + return -EINVAL; + + return regmap_write_bits(field->regmap, + field->reg + (field->id_offset * id), + field->mask, val << field->shift); +} +EXPORT_SYMBOL_GPL(regmap_fields_force_write); + /** * regmap_fields_update_bits(): Perform a read/modify/write cycle * on the register field diff --git a/include/linux/regmap.h b/include/linux/regmap.h index e4b9ad4f05ef3..519c96231a91e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -505,6 +505,8 @@ int regmap_field_update_bits(struct regmap_field *field, int regmap_fields_write(struct regmap_field *field, unsigned int id, unsigned int val); +int regmap_fields_force_write(struct regmap_field *field, unsigned int id, + unsigned int val); int regmap_fields_read(struct regmap_field *field, unsigned int id, unsigned int *val); int regmap_fields_update_bits(struct regmap_field *field, unsigned int id, -- GitLab From 7b47ab47b3938e2274834dbde7915df98fc74368 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 16 Jun 2015 08:53:11 +0000 Subject: [PATCH 0684/7006] ASoC: rsnd: gen: add rsnd_force_write() rsnd_force_write() is similar to rsnd_write(), but rsnd_force_write() write data to register even though it is same value. Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 16 ++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 4 ++++ 2 files changed, 20 insertions(+) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 8c7dc51b1c4fd..48f704b1d80e3 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -103,6 +103,22 @@ void rsnd_write(struct rsnd_priv *priv, regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); } +void rsnd_force_write(struct rsnd_priv *priv, + struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data) +{ + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_gen *gen = rsnd_priv_to_gen(priv); + + if (!rsnd_is_accessible_reg(priv, gen, reg)) + return; + + dev_dbg(dev, "w %s[%d] - %4d : %08x\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); + + regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); +} + void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data) { diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 09fcc54a8ee06..f729646e3d180 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -157,12 +157,16 @@ struct rsnd_dai_stream; rsnd_read(rsnd_mod_to_priv(m), m, RSND_REG_##r) #define rsnd_mod_write(m, r, d) \ rsnd_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) +#define rsnd_mod_force_write(m, r, d) \ + rsnd_force_write(rsnd_mod_to_priv(m), m, RSND_REG_##r, d) #define rsnd_mod_bset(m, r, s, d) \ rsnd_bset(rsnd_mod_to_priv(m), m, RSND_REG_##r, s, d) u32 rsnd_read(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg); void rsnd_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); +void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, + enum rsnd_reg reg, u32 data); void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); -- GitLab From ca12bb14fee138603d17b1d68906abeebaa09b30 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:47:23 +0900 Subject: [PATCH 0685/7006] EDAC, xgene: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Cc: linux-edac Cc: Loc Ho Cc: Mauro Carvalho Chehab Link: http://lkml.kernel.org/r/1436507243-11159-1-git-send-email-k.kozlowski@samsung.com Signed-off-by: Borislav Petkov --- drivers/edac/xgene_edac.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index 14636e4b6a08b..ba06904af2e1c 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c @@ -1168,7 +1168,6 @@ static struct platform_driver xgene_edac_driver = { .remove = xgene_edac_remove, .driver = { .name = "xgene-edac", - .owner = THIS_MODULE, .of_match_table = xgene_edac_of_match, }, }; -- GitLab From 90f8572b0f021fdd1baa68e00a8c30482ee9e5f4 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Mon, 29 Jun 2015 14:42:03 -0500 Subject: [PATCH 0686/7006] vfs: Commit to never having exectuables on proc and sysfs. Today proc and sysfs do not contain any executable files. Several applications today mount proc or sysfs without noexec and nosuid and then depend on there being no exectuables files on proc or sysfs. Having any executable files show on proc or sysfs would cause a user space visible regression, and most likely security problems. Therefore commit to never allowing executables on proc and sysfs by adding a new flag to mark them as filesystems without executables and enforce that flag. Test the flag where MNT_NOEXEC is tested today, so that the only user visible effect will be that exectuables will be treated as if the execute bit is cleared. The filesystems proc and sysfs do not currently incoporate any executable files so this does not result in any user visible effects. This makes it unnecessary to vet changes to proc and sysfs tightly for adding exectuable files or changes to chattr that would modify existing files, as no matter what the individual file say they will not be treated as exectuable files by the vfs. Not having to vet changes to closely is important as without this we are only one proc_create call (or another goof up in the implementation of notify_change) from having problematic executables on proc. Those mistakes are all too easy to make and would create a situation where there are security issues or the assumptions of some program having to be broken (and cause userspace regressions). Signed-off-by: "Eric W. Biederman" --- fs/exec.c | 10 ++++++++-- fs/open.c | 2 +- fs/proc/root.c | 2 ++ fs/sysfs/mount.c | 4 ++++ include/linux/fs.h | 3 +++ kernel/sys.c | 3 +-- mm/mmap.c | 4 ++-- mm/nommu.c | 2 +- security/security.c | 2 +- 9 files changed, 23 insertions(+), 9 deletions(-) diff --git a/fs/exec.c b/fs/exec.c index 1977c2a553aca..b06623a9347f4 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -98,6 +98,12 @@ static inline void put_binfmt(struct linux_binfmt * fmt) module_put(fmt->module); } +bool path_noexec(const struct path *path) +{ + return (path->mnt->mnt_flags & MNT_NOEXEC) || + (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); +} + #ifdef CONFIG_USELIB /* * Note that a shared library must be both readable and executable due to @@ -132,7 +138,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) goto exit; error = -EACCES; - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) + if (path_noexec(&file->f_path)) goto exit; fsnotify_open(file); @@ -777,7 +783,7 @@ static struct file *do_open_execat(int fd, struct filename *name, int flags) if (!S_ISREG(file_inode(file)->i_mode)) goto exit; - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) + if (path_noexec(&file->f_path)) goto exit; err = deny_write_access(file); diff --git a/fs/open.c b/fs/open.c index e33dab287fa00..b6f1e96a7c0b3 100644 --- a/fs/open.c +++ b/fs/open.c @@ -377,7 +377,7 @@ retry: * with the "noexec" flag. */ res = -EACCES; - if (path.mnt->mnt_flags & MNT_NOEXEC) + if (path_noexec(&path)) goto out_path_release; } diff --git a/fs/proc/root.c b/fs/proc/root.c index 68feb0f70e635..361ab4ee42fc3 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -134,6 +134,8 @@ static struct dentry *proc_mount(struct file_system_type *fs_type, } sb->s_flags |= MS_ACTIVE; + /* User space would break if executables appear on proc */ + sb->s_iflags |= SB_I_NOEXEC; } return dget(sb->s_root); diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 1c6ac6fcee9fb..f3db82071cfbd 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -40,6 +40,10 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, SYSFS_MAGIC, &new_sb, ns); if (IS_ERR(root) || !new_sb) kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); + else if (new_sb) + /* Userspace would break if executables appear on sysfs */ + root->d_sb->s_iflags |= SB_I_NOEXEC; + return root; } diff --git a/include/linux/fs.h b/include/linux/fs.h index a0653e560c267..42912f8d286eb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1244,6 +1244,7 @@ struct mm_struct; /* sb->s_iflags */ #define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ +#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ /* Possible states of 'frozen' field */ enum { @@ -3030,4 +3031,6 @@ static inline bool dir_relax(struct inode *inode) return !IS_DEADDIR(inode); } +extern bool path_noexec(const struct path *path); + #endif /* _LINUX_FS_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 259fda25eb6ba..fa2f2f671a5ca 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1668,8 +1668,7 @@ static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) * overall picture. */ err = -EACCES; - if (!S_ISREG(inode->i_mode) || - exe.file->f_path.mnt->mnt_flags & MNT_NOEXEC) + if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path)) goto exit; err = inode_permission(inode, MAY_EXEC); diff --git a/mm/mmap.c b/mm/mmap.c index aa632ade2be79..f126923ce683c 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1268,7 +1268,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, * mounted, in which case we dont add PROT_EXEC.) */ if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) - if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC))) + if (!(file && path_noexec(&file->f_path))) prot |= PROT_EXEC; if (!(flags & MAP_FIXED)) @@ -1337,7 +1337,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, case MAP_PRIVATE: if (!(file->f_mode & FMODE_READ)) return -EACCES; - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) { + if (path_noexec(&file->f_path)) { if (vm_flags & VM_EXEC) return -EPERM; vm_flags &= ~VM_MAYEXEC; diff --git a/mm/nommu.c b/mm/nommu.c index 58ea3643b9e99..ce17abf087ff5 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1035,7 +1035,7 @@ static int validate_mmap_request(struct file *file, /* handle executable mappings and implied executable * mappings */ - if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) { + if (path_noexec(&file->f_path)) { if (prot & PROT_EXEC) return -EPERM; } else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) { diff --git a/security/security.c b/security/security.c index 595fffab48b0a..062f3c997fdc3 100644 --- a/security/security.c +++ b/security/security.c @@ -776,7 +776,7 @@ static inline unsigned long mmap_prot(struct file *file, unsigned long prot) * ditto if it's not on noexec mount, except that on !MMU we need * NOMMU_MAP_EXEC (== VM_MAYEXEC) in this case */ - if (!(file->f_path.mnt->mnt_flags & MNT_NOEXEC)) { + if (!path_noexec(&file->f_path)) { #ifndef CONFIG_MMU if (file->f_op->mmap_capabilities) { unsigned caps = file->f_op->mmap_capabilities(file); -- GitLab From 77b1a97d218277d55a15016826d1fd79290f1df2 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Thu, 4 Jun 2015 09:43:11 -0500 Subject: [PATCH 0687/7006] mnt: fs_fully_visible enforce noexec and nosuid if !SB_I_NOEXEC The filesystems proc and sysfs do not have executable files do not have exectuable files today and portions of userspace break if we do enforce nosuid and noexec consistency of nosuid and noexec flags between previous mounts and new mounts of proc and sysfs. Add the code to enforce consistency of the nosuid and noexec flags, and use the presence of SB_I_NOEXEC to signal that there is no need to bother. This results in a completely userspace invisible change that makes it clear fs_fully_visible can only skip the enforcement of noexec and nosuid because it is known the filesystems in question do not support executables. Signed-off-by: "Eric W. Biederman" --- fs/namespace.c | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index c7cb8a526c05f..ce428cadd41f5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3194,6 +3194,8 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) down_read(&namespace_sem); list_for_each_entry(mnt, &ns->list, mnt_list) { struct mount *child; + int mnt_flags; + if (mnt->mnt.mnt_sb->s_type != type) continue; @@ -3203,17 +3205,30 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) continue; + /* Read the mount flags and filter out flags that + * may safely be ignored. + */ + mnt_flags = mnt->mnt.mnt_flags; + if (mnt->mnt.mnt_sb->s_iflags & SB_I_NOEXEC) + mnt_flags &= ~(MNT_LOCK_NOSUID | MNT_LOCK_NOEXEC); + /* Verify the mount flags are equal to or more permissive * than the proposed new mount. */ - if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && + if ((mnt_flags & MNT_LOCK_READONLY) && !(new_flags & MNT_READONLY)) continue; - if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && + if ((mnt_flags & MNT_LOCK_NODEV) && !(new_flags & MNT_NODEV)) continue; - if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && - ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) + if ((mnt_flags & MNT_LOCK_NOSUID) && + !(new_flags & MNT_NOSUID)) + continue; + if ((mnt_flags & MNT_LOCK_NOEXEC) && + !(new_flags & MNT_NOEXEC)) + continue; + if ((mnt_flags & MNT_LOCK_ATIME) && + ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) continue; /* This mount is not fully visible if there are any @@ -3223,16 +3238,18 @@ static bool fs_fully_visible(struct file_system_type *type, int *new_mnt_flags) list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { struct inode *inode = child->mnt_mountpoint->d_inode; /* Only worry about locked mounts */ - if (!(mnt->mnt.mnt_flags & MNT_LOCKED)) + if (!(mnt_flags & MNT_LOCKED)) continue; /* Is the directory permanetly empty? */ if (!is_empty_dir_inode(inode)) goto next; } /* Preserve the locked attributes */ - *new_mnt_flags |= mnt->mnt.mnt_flags & (MNT_LOCK_READONLY | \ - MNT_LOCK_NODEV | \ - MNT_LOCK_ATIME); + *new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \ + MNT_LOCK_NODEV | \ + MNT_LOCK_NOSUID | \ + MNT_LOCK_NOEXEC | \ + MNT_LOCK_ATIME); visible = true; goto found; next: ; -- GitLab From d90c6cc242045115c5c4973114cc93e1c20e2ea8 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 10 Jul 2015 14:37:25 +0100 Subject: [PATCH 0688/7006] ASoC: arizona: Fix error path in codec probe If we fail to add some DSPs or fail to add the controls we should call wm_adsp2_codec_remove for all the cores we have already added. This patch fixes this up on the wm5102 and wm5110. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown --- sound/soc/codecs/wm5102.c | 7 ++++++- sound/soc/codecs/wm5110.c | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c index 6ddee999bc517..64637d1cf4e56 100644 --- a/sound/soc/codecs/wm5102.c +++ b/sound/soc/codecs/wm5102.c @@ -1879,7 +1879,7 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) ret = snd_soc_add_codec_controls(codec, arizona_adsp2_rate_controls, 1); if (ret) - return ret; + goto err_adsp2_codec_probe; arizona_init_spk(codec); arizona_init_gpio(codec); @@ -1889,6 +1889,11 @@ static int wm5102_codec_probe(struct snd_soc_codec *codec) priv->core.arizona->dapm = dapm; return 0; + +err_adsp2_codec_probe: + wm_adsp2_codec_remove(&priv->core.adsp[0], codec); + + return ret; } static int wm5102_codec_remove(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index 05aa5bca97cfd..2d1168c768d98 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -1607,18 +1607,24 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) - return ret; + goto err_adsp2_codec_probe; } ret = snd_soc_add_codec_controls(codec, arizona_adsp2_rate_controls, WM5110_NUM_ADSP); if (ret) - return ret; + goto err_adsp2_codec_probe; snd_soc_dapm_disable_pin(dapm, "HAPTICS"); return 0; + +err_adsp2_codec_probe: + for (--i; i >= 0; --i) + wm_adsp2_codec_remove(&priv->core.adsp[i], codec); + + return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) -- GitLab From 32a726b2e089ec1851965290a610c4ae9cab3303 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:11 +0200 Subject: [PATCH 0689/7006] ASoC: sti-sas: Add sti platform codec Codec part of the sti platform that supports codec IPs. This first version does not support HDMI, but only DAC and SPDIF out. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/sti-sas.c | 627 +++++++++++++++++++++++++++++++++++++ 3 files changed, 634 insertions(+) create mode 100644 sound/soc/codecs/sti-sas.c diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce8ba387..46802eff292e3 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -102,6 +102,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STA350 if I2C select SND_SOC_STA529 if I2C select SND_SOC_STAC9766 if SND_SOC_AC97_BUS + select SND_SOC_STI_SAS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C select SND_SOC_TAS571X if I2C @@ -610,6 +611,10 @@ config SND_SOC_STA529 config SND_SOC_STAC9766 tristate +config SND_SOC_STI_SAS + tristate "codec Audio support for STI SAS codec" + depends on SND_SOC_STI + config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d972cb36..7b4ce1b6e6243 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta32x-objs := sta32x.o snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o +snd-soc-sti-sas-objs := sti-sas.o snd-soc-tas5086-objs := tas5086.o snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o @@ -289,6 +290,7 @@ obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o +obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c new file mode 100644 index 0000000000000..32db2c25a33fc --- /dev/null +++ b/sound/soc/codecs/sti-sas.c @@ -0,0 +1,627 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include + +#include +#include + +/* chipID supported */ +#define CHIPID_STIH416 0 +#define CHIPID_STIH407 1 + +/* DAC definitions */ + +/* stih416 DAC registers */ +/* sysconf 2517: Audio-DAC-Control */ +#define STIH416_AUDIO_DAC_CTRL 0x00000814 +/* sysconf 2519: Audio-Gue-Control */ +#define STIH416_AUDIO_GLUE_CTRL 0x0000081C + +#define STIH416_DAC_NOT_STANDBY 0x3 +#define STIH416_DAC_SOFTMUTE 0x4 +#define STIH416_DAC_ANA_NOT_PWR 0x5 +#define STIH416_DAC_NOT_PNDBG 0x6 + +#define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY) +#define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE) +#define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR) +#define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG) + +/* stih407 DAC registers */ +/* sysconf 5041: Audio-Gue-Control */ +#define STIH407_AUDIO_GLUE_CTRL 0x000000A4 +/* sysconf 5042: Audio-DAC-Control */ +#define STIH407_AUDIO_DAC_CTRL 0x000000A8 + +/* DAC definitions */ +#define STIH407_DAC_SOFTMUTE 0x0 +#define STIH407_DAC_STANDBY_ANA 0x1 +#define STIH407_DAC_STANDBY 0x2 + +#define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE) +#define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA) +#define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY) + +/* SPDIF definitions */ +#define SPDIF_BIPHASE_ENABLE 0x6 +#define SPDIF_BIPHASE_IDLE 0x7 + +#define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE) +#define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE) + +enum { + STI_SAS_DAI_SPDIF_OUT, + STI_SAS_DAI_ANALOG_OUT, +}; + +static const struct reg_default stih416_sas_reg_defaults[] = { + { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, + { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, +}; + +static const struct reg_default stih407_sas_reg_defaults[] = { + { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, + { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, +}; + +struct sti_dac_audio { + struct regmap *regmap; + struct regmap *virt_regmap; + struct regmap_field **field; + struct reset_control *rst; + int mclk; +}; + +struct sti_spdif_audio { + struct regmap *regmap; + struct regmap_field **field; + int mclk; +}; + +/* device data structure */ +struct sti_sas_dev_data { + const int chipid; /* IC version */ + const struct regmap_config *regmap; + const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ + const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ + const int num_dapm_widgets; /* dapms declaration */ + const struct snd_soc_dapm_route *dapm_routes; /* route declaration */ + const int num_dapm_routes; /* route declaration */ +}; + +/* driver data structure */ +struct sti_sas_data { + struct device *dev; + const struct sti_sas_dev_data *dev_data; + struct sti_dac_audio dac; + struct sti_spdif_audio spdif; +}; + +/* Read a register from the sysconf reg bank */ +static int sti_sas_read_reg(void *context, unsigned int reg, + unsigned int *value) +{ + struct sti_sas_data *drvdata = context; + int status; + u32 val; + + status = regmap_read(drvdata->dac.regmap, reg, &val); + *value = (unsigned int)val; + + return status; +} + +/* Read a register from the sysconf reg bank */ +static int sti_sas_write_reg(void *context, unsigned int reg, + unsigned int value) +{ + struct sti_sas_data *drvdata = context; + int status; + + status = regmap_write(drvdata->dac.regmap, reg, value); + + return status; +} + +static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, + struct sti_sas_data *data) +{ + int ret; + /* + * DAC and SPDIF are activated by default + * put them in IDLE to save power + */ + + /* Initialise bi-phase formatter to disabled */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_ENABLE_MASK, 0); + + if (!ret) + /* Initialise bi-phase formatter idle value to 0 */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_IDLE_MASK, 0); + if (ret < 0) { + dev_err(codec->dev, "Failed to update SPDIF registers"); + return ret; + } + + /* Init DAC configuration */ + switch (data->dev_data->chipid) { + case CHIPID_STIH407: + /* init configuration */ + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_MASK, + STIH407_DAC_STANDBY_MASK); + + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_ANA_MASK, + STIH407_DAC_STANDBY_ANA_MASK); + if (!ret) + ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + STIH407_DAC_SOFTMUTE_MASK); + break; + case CHIPID_STIH416: + ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_STANDBY_MASK, 0); + if (!ret) + ret = snd_soc_update_bits(codec, + STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_ANA_NOT_PWR, 0); + if (!ret) + ret = snd_soc_update_bits(codec, + STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_PNDBG_MASK, + 0); + if (!ret) + ret = snd_soc_update_bits(codec, + STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_SOFTMUTE_MASK, + STIH416_DAC_SOFTMUTE_MASK); + break; + default: + return -EINVAL; + } + + if (ret < 0) { + dev_err(codec->dev, "Failed to update DAC registers"); + return ret; + } + + return ret; +} + +/* + * DAC + */ +static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + /* Sanity check only */ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(dai->codec->dev, + "%s: ERROR: Unsupporter master mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + return 0; +} + +static int stih416_dac_probe(struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + struct sti_dac_audio *dac = &drvdata->dac; + + /* Get reset control */ + dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); + if (IS_ERR(dac->rst)) { + dev_err(dai->codec->dev, + "%s: ERROR: DAC reset control not defined (%d)!\n", + __func__, (int)dac->rst); + dac->rst = NULL; + return -EFAULT; + } + /* Put the DAC into reset */ + reset_control_assert(dac->rst); + + return 0; +} + +const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { + SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), + SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), + SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_NOT_STANDBY, 0), + SND_SOC_DAPM_OUTPUT("DAC Output"), +}; + +const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { + SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY_ANA, 1, NULL, 0), + SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_STANDBY, 1), + SND_SOC_DAPM_OUTPUT("DAC Output"), +}; + +const struct snd_soc_dapm_route stih416_sas_route[] = { + {"DAC Output", NULL, "DAC bandgap"}, + {"DAC Output", NULL, "DAC standby ana"}, + {"DAC standby ana", NULL, "DAC standby"}, +}; + +const struct snd_soc_dapm_route stih407_sas_route[] = { + {"DAC Output", NULL, "DAC standby ana"}, + {"DAC standby ana", NULL, "DAC standby"}, +}; + +static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_SOFTMUTE_MASK, + STIH416_DAC_SOFTMUTE_MASK); + } else { + return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, + STIH416_DAC_SOFTMUTE_MASK, 0); + } +} + +static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_codec *codec = dai->codec; + + if (mute) { + return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + STIH407_DAC_SOFTMUTE_MASK); + } else { + return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, + STIH407_DAC_SOFTMUTE_MASK, + 0); + } +} + +/* + * SPDIF + */ +static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) +{ + if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { + dev_err(dai->codec->dev, + "%s: ERROR: Unsupporter master mask 0x%x\n", + __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); + return -EINVAL; + } + + return 0; +} + +/* + * sti_sas_spdif_trigger: + * Trigger function is used to ensure that BiPhase Formater is disabled + * before CPU dai is stopped. + * This is mandatory to avoid that BPF is stalled + */ +static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_ENABLE_MASK, + SPDIF_BIPHASE_ENABLE_MASK); + case SNDRV_PCM_TRIGGER_RESUME: + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_STOP: + case SNDRV_PCM_TRIGGER_SUSPEND: + return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, + SPDIF_BIPHASE_ENABLE_MASK, + 0); + default: + return -EINVAL; + } +} + +static bool sti_sas_volatile_register(struct device *dev, unsigned int reg) +{ + if (reg == STIH407_AUDIO_GLUE_CTRL) + return true; + + return false; +} + +/* + * CODEC DAIS + */ + +/* + * sti_sas_set_sysclk: + * get MCLK input frequency to check that MCLK-FS ratio is coherent + */ +static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + + if (dir == SND_SOC_CLOCK_OUT) + return 0; + + if (clk_id != 0) + return -EINVAL; + + switch (dai->id) { + case STI_SAS_DAI_SPDIF_OUT: + drvdata->spdif.mclk = freq; + break; + + case STI_SAS_DAI_ANALOG_OUT: + drvdata->dac.mclk = freq; + break; + } + + return 0; +} + +static int sti_sas_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + struct snd_pcm_runtime *runtime = substream->runtime; + + switch (dai->id) { + case STI_SAS_DAI_SPDIF_OUT: + if ((drvdata->spdif.mclk / runtime->rate) != 128) { + dev_err(codec->dev, "unexpected mclk-fs ratio"); + return -EINVAL; + } + break; + case STI_SAS_DAI_ANALOG_OUT: + if ((drvdata->dac.mclk / runtime->rate) != 256) { + dev_err(codec->dev, "unexpected mclk-fs ratio"); + return -EINVAL; + } + break; + } + + return 0; +} + +const struct snd_soc_dai_ops stih416_dac_ops = { + .set_fmt = sti_sas_dac_set_fmt, + .mute_stream = stih416_sas_dac_mute, + .prepare = sti_sas_prepare, + .set_sysclk = sti_sas_set_sysclk, +}; + +const struct snd_soc_dai_ops stih407_dac_ops = { + .set_fmt = sti_sas_dac_set_fmt, + .mute_stream = stih407_sas_dac_mute, + .prepare = sti_sas_prepare, + .set_sysclk = sti_sas_set_sysclk, +}; + +const struct regmap_config stih407_sas_regmap = { + .reg_bits = 32, + .val_bits = 32, + + .max_register = STIH407_AUDIO_DAC_CTRL, + .reg_defaults = stih407_sas_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), + .volatile_reg = sti_sas_volatile_register, + .cache_type = REGCACHE_RBTREE, + .reg_read = sti_sas_read_reg, + .reg_write = sti_sas_write_reg, +}; + +const struct regmap_config stih416_sas_regmap = { + .reg_bits = 32, + .val_bits = 32, + + .max_register = STIH416_AUDIO_DAC_CTRL, + .reg_defaults = stih416_sas_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), + .volatile_reg = sti_sas_volatile_register, + .cache_type = REGCACHE_RBTREE, + .reg_read = sti_sas_read_reg, + .reg_write = sti_sas_write_reg, +}; + +const struct sti_sas_dev_data stih416_data = { + .chipid = CHIPID_STIH416, + .regmap = &stih416_sas_regmap, + .dac_ops = &stih416_dac_ops, + .dapm_widgets = stih416_sas_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), + .dapm_routes = stih416_sas_route, + .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), +}; + +const struct sti_sas_dev_data stih407_data = { + .chipid = CHIPID_STIH407, + .regmap = &stih407_sas_regmap, + .dac_ops = &stih407_dac_ops, + .dapm_widgets = stih407_sas_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets), + .dapm_routes = stih407_sas_route, + .num_dapm_routes = ARRAY_SIZE(stih407_sas_route), +}; + +static struct snd_soc_dai_driver sti_sas_dai[] = { + { + .name = "sas-dai-spdif-out", + .id = STI_SAS_DAI_SPDIF_OUT, + .playback = { + .stream_name = "spdif_p", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = (struct snd_soc_dai_ops[]) { + { + .set_fmt = sti_sas_spdif_set_fmt, + .trigger = sti_sas_spdif_trigger, + .set_sysclk = sti_sas_set_sysclk, + .prepare = sti_sas_prepare, + } + }, + }, + { + .name = "sas-dai-dac", + .id = STI_SAS_DAI_ANALOG_OUT, + .playback = { + .stream_name = "dac_p", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_48000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S32_LE, + }, + }, +}; + +#ifdef CONFIG_PM_SLEEP +static int sti_sas_resume(struct snd_soc_codec *codec) +{ + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + + return sti_sas_init_sas_registers(codec, drvdata); +} +#else +#define sti_sas_resume NULL +#endif + +static int sti_sas_codec_probe(struct snd_soc_codec *codec) +{ + struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); + int ret; + + ret = sti_sas_init_sas_registers(codec, drvdata); + + return ret; +} + +static struct snd_soc_codec_driver sti_sas_driver = { + .probe = sti_sas_codec_probe, + .resume = sti_sas_resume, +}; + +static const struct of_device_id sti_sas_dev_match[] = { + { + .compatible = "st,stih416-sas-codec", + .data = &stih416_data, + }, + { + .compatible = "st,stih407-sas-codec", + .data = &stih407_data, + }, + {}, +}; + +static int sti_sas_driver_probe(struct platform_device *pdev) +{ + struct device_node *pnode = pdev->dev.of_node; + struct sti_sas_data *drvdata; + + /* Allocate device structure */ + drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + /* Populate data structure depending on compatibility */ + if (!of_match_node(sti_sas_dev_match, pnode)->data) { + dev_err(&pdev->dev, "data associated to device is missing"); + return -EINVAL; + } + + drvdata->dev_data = of_match_node(sti_sas_dev_match, pnode)->data; + + /* Initialise device structure */ + drvdata->dev = &pdev->dev; + + /* Request the DAC & SPDIF registers memory region */ + drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata, + drvdata->dev_data->regmap); + if (!drvdata->dac.virt_regmap) { + dev_err(&pdev->dev, "audio registers not enabled\n"); + return -EFAULT; + } + + /* Request the syscon region */ + drvdata->dac.regmap = + syscon_regmap_lookup_by_phandle(pnode, "st,syscfg"); + if (!drvdata->dac.regmap) { + dev_err(&pdev->dev, "syscon registers not available\n"); + return -EFAULT; + } + drvdata->spdif.regmap = drvdata->dac.regmap; + + /* Set DAC dai probe */ + if (drvdata->dev_data->chipid == CHIPID_STIH416) + sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; + + sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; + + /* Set dapms*/ + sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; + sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; + + sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; + sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; + + /* Store context */ + dev_set_drvdata(&pdev->dev, drvdata); + + return snd_soc_register_codec(&pdev->dev, &sti_sas_driver, + sti_sas_dai, + ARRAY_SIZE(sti_sas_dai)); +} + +static int sti_sas_driver_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + + return 0; +} + +static struct platform_driver sti_sas_platform_driver = { + .driver = { + .name = "sti-sas-codec", + .owner = THIS_MODULE, + .of_match_table = sti_sas_dev_match, + }, + .probe = sti_sas_driver_probe, + .remove = sti_sas_driver_remove, +}; + +module_platform_driver(sti_sas_platform_driver); + +MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms"); +MODULE_AUTHOR("Arnaud.pouliquen@st.com"); +MODULE_LICENSE("GPL v2"); -- GitLab From 05e85d4e0180dbbce823e19d81388e60ac924be1 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:05 +0200 Subject: [PATCH 0690/7006] ASoC: sti: add binding for ASoC driver Add ASoC driver bindings documentation. Describe the required properties for each of the hardware IPs drivers. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- .../bindings/sound/st,sti-asoc-card.txt | 155 ++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt new file mode 100644 index 0000000000000..028fa1c82f507 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt @@ -0,0 +1,155 @@ +STMicroelectronics sti ASoC cards + +The sti ASoC Sound Card can be used, for all sti SoCs using internal sti-sas +codec or external codecs. + +sti sound drivers allows to expose sti SoC audio interface through the +generic ASoC simple card. For details about sound card declaration please refer to +Documentation/devicetree/bindings/sound/simple-card.txt. + +1) sti-uniperiph-dai: audio dai device. +--------------------------------------- + +Required properties: + - compatible: "st,sti-uni-player" or "st,sti-uni-reader" + + - st,syscfg: phandle to boot-device system configuration registers + + - clock-names: name of the clocks listed in clocks property in the same order + + - reg: CPU DAI IP Base address and size entries, listed in same + order than the CPU_DAI properties. + + - reg-names: names of the mapped memory regions listed in regs property in + the same order. + + - interrupts: CPU_DAI interrupt line, listed in the same order than the + CPU_DAI properties. + + - dma: CPU_DAI DMA controller phandle and DMA request line, listed in the same + order than the CPU_DAI properties. + + - dma-names: identifier string for each DMA request line in the dmas property. + "tx" for "st,sti-uni-player" compatibility + "rx" for "st,sti-uni-reader" compatibility + + - version: IP version integrated in SOC. + + - dai-name: DAI name that describes the IP. + +Required properties ("st,sti-uni-player" compatibility only): + - clocks: CPU_DAI IP clock source, listed in the same order than the + CPU_DAI properties. + + - uniperiph-id: internal SOC IP instance ID. + + - IP mode: IP working mode depending on associated codec. + "HDMI" connected to HDMI codec IP and IEC HDMI formats. + "SPDIF"connected to SPDIF codec and support SPDIF formats. + "PCM" PCM standard mode for I2S or TDM bus. + +Optional properties: + - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for + external codecs connection. + + - pinctrl-names: should contain only one value - "default". + +Example: + + sti_uni_player2: sti-uni-player@2 { + compatible = "st,sti-uni-player"; + status = "okay"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_PCM_2>; + reg = <0x8D82000 0x158>; + interrupts = ; + dmas = <&fdma0 4 0 1>; + dai-name = "Uni Player #1 (DAC)"; + dma-names = "tx"; + uniperiph-id = <2>; + version = <5>; + mode = "PCM"; + }; + + sti_uni_player3: sti-uni-player@3 { + compatible = "st,sti-uni-player"; + status = "okay"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + clocks = <&clk_s_d0_flexgen CLK_SPDIFF>; + reg = <0x8D85000 0x158>; + interrupts = ; + dmas = <&fdma0 7 0 1>; + dma-names = "tx"; + dai-name = "Uni Player #1 (PIO)"; + uniperiph-id = <3>; + version = <5>; + mode = "SPDIF"; + }; + + sti_uni_reader1: sti-uni-reader@1 { + compatible = "st,sti-uni-reader"; + status = "disabled"; + #sound-dai-cells = <0>; + st,syscfg = <&syscfg_core>; + reg = <0x8D84000 0x158>; + interrupts = ; + dmas = <&fdma0 6 0 1>; + dma-names = "rx"; + dai-name = "Uni Reader #1 (HDMI RX)"; + version = <3>; + }; + +2) sti-sas-codec: internal audio codec IPs driver +------------------------------------------------- + +Required properties: + - compatible: "st,sti-sas-codec" . + Should be chip "st,stih416-sas-codec" or "st,stih407-sas-codec" + + - st,syscfg: phandle to boot-device system configuration registers. + + - pinctrl-0: SPDIF PIO description. + + - pinctrl-names: should contain only one value - "default". + +Example: + sti_sas_codec: sti-sas-codec { + compatible = "st,stih407-sas-codec"; + #sound-dai-cells = <1>; + st,reg_audio = <&syscfg_core>; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_spdif_out >; + }; + +Example of audio card declaration: + sound { + compatible = "simple-audio-card"; + simple-audio-card,name = "sti audio card"; + status = "okay"; + + simple-audio-card,dai-link@0 { + /* DAC */ + format = "i2s"; + dai-tdm-slot-width = <32>; + cpu { + sound-dai = <&sti_uni_player2>; + }; + + codec { + sound-dai = <&sti_sasg_codec 1>; + }; + }; + simple-audio-card,dai-link@1 { + /* SPDIF */ + format = "left_j"; + cpu { + sound-dai = <&sti_uni_player3>; + }; + + codec { + sound-dai = <&sti_sasg_codec 0>; + }; + }; + }; -- GitLab From e1ecace6a68518a6751987ab2032b0ec1b3bd5fe Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:06 +0200 Subject: [PATCH 0691/7006] ASoC: sti: Add uniperipheral header file Add the Uniperipheral header file for uniperipheral IPs registers definition. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif.h | 1099 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 1099 insertions(+) create mode 100644 sound/soc/sti/uniperif.h diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h new file mode 100644 index 0000000000000..043853e093a5b --- /dev/null +++ b/sound/soc/sti/uniperif.h @@ -0,0 +1,1099 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#ifndef __SND_ST_AUD_UNIPERIF_H +#define __SND_ST_AUD_UNIPERIF_H + +#include + +/* + * Register access macros + */ + +#define GET_UNIPERIF_REG(ip, offset, shift, mask) \ + ((readl_relaxed(ip->base + offset) >> shift) & mask) +#define SET_UNIPERIF_REG(ip, offset, shift, mask, value) \ + writel_relaxed(((readl_relaxed(ip->base + offset) & \ + ~(mask << shift)) | (((value) & mask) << shift)), ip->base + offset) +#define SET_UNIPERIF_BIT_REG(ip, offset, shift, mask, value) \ + writel_relaxed((((value) & mask) << shift), ip->base + offset) + +/* + * AUD_UNIPERIF_SOFT_RST reg + */ + +#define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 +#define GET_UNIPERIF_SOFT_RST(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + readl_relaxed(ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) : 0) +#define SET_UNIPERIF_SOFT_RST(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) + +/* SOFT_RST */ +#define UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip) 0x0 +#define UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip) 0x1 +#define SET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \ + SET_UNIPERIF_BIT_REG(ip, \ + UNIPERIF_SOFT_RST_OFFSET(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip), 1) +#define GET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_SOFT_RST_OFFSET(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \ + UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) + +/* + * AUD_UNIPERIF_FIFO_DATA reg + */ + +#define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 +#define SET_UNIPERIF_DATA(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) + +/* + * AUD_UNIPERIF_CHANNEL_STA_REGN reg + */ + +#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) +#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n)) +#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \ + writel_relaxed(value, ip->base + \ + UNIPERIF_CHANNEL_STA_REGN(ip, n)) + +#define UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip) 0x0060 +#define GET_UNIPERIF_CHANNEL_STA_REG0(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG0(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip) 0x0064 +#define GET_UNIPERIF_CHANNEL_STA_REG1(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG1(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip) 0x0068 +#define GET_UNIPERIF_CHANNEL_STA_REG2(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG2(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip) 0x006C +#define GET_UNIPERIF_CHANNEL_STA_REG3(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG3(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip) 0x0070 +#define GET_UNIPERIF_CHANNEL_STA_REG4(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG4(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip)) + +#define UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip) 0x0074 +#define GET_UNIPERIF_CHANNEL_STA_REG5(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) +#define SET_UNIPERIF_CHANNEL_STA_REG5(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) + +/* + * AUD_UNIPERIF_ITS reg + */ + +#define UNIPERIF_ITS_OFFSET(ip) 0x000C +#define GET_UNIPERIF_ITS(ip) \ + readl_relaxed(ip->base + UNIPERIF_ITS_OFFSET(ip)) + +/* MEM_BLK_READ */ +#define UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip) 5 +#define UNIPERIF_ITS_MEM_BLK_READ_MASK(ip) \ + (BIT(UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip))) + +/* FIFO_ERROR */ +#define UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITS_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip))) + +/* DMA_ERROR */ +#define UNIPERIF_ITS_DMA_ERROR_SHIFT(ip) 9 +#define UNIPERIF_ITS_DMA_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITS_DMA_ERROR_SHIFT(ip))) + +/* UNDERFLOW_REC_DONE */ +#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) +#define UNIPERIF_ITS_UNDERFLOW_REC_DONE_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip)))) + +/* UNDERFLOW_REC_FAILED */ +#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) +#define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) + +/* + * AUD_UNIPERIF_ITS_BCLR reg + */ + +/* FIFO_ERROR */ +#define UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(ip) \ + SET_UNIPERIF_ITS_BCLR(ip, \ + UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip)) + +#define UNIPERIF_ITS_BCLR_OFFSET(ip) 0x0010 +#define SET_UNIPERIF_ITS_BCLR(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) + +/* + * AUD_UNIPERIF_ITM reg + */ + +#define UNIPERIF_ITM_OFFSET(ip) 0x0018 +#define GET_UNIPERIF_ITM(ip) \ + readl_relaxed(ip->base + UNIPERIF_ITM_OFFSET(ip)) + +/* FIFO_ERROR */ +#define UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITM_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip))) + +/* UNDERFLOW_REC_DONE */ +#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) +#define UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip)))) + +/* UNDERFLOW_REC_FAILED */ +#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) +#define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) + +/* + * AUD_UNIPERIF_ITM_BCLR reg + */ + +#define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c +#define SET_UNIPERIF_ITM_BCLR(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_ITM_BCLR_OFFSET(ip)) + +/* FIFO_ERROR */ +#define UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(ip) \ + SET_UNIPERIF_ITM_BCLR(ip, \ + UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip)) + +/* DMA_ERROR */ +#define UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip) 9 +#define UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BCLR_DMA_ERROR(ip) \ + SET_UNIPERIF_ITM_BCLR(ip, \ + UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) + +/* + * AUD_UNIPERIF_ITM_BSET reg + */ + +#define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 +#define SET_UNIPERIF_ITM_BSET(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_ITM_BSET_OFFSET(ip)) + +/* FIFO_ERROR */ +#define UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) +#define UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BSET_FIFO_ERROR(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip)) + +/* MEM_BLK_READ */ +#define UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip) 5 +#define UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip) \ + (BIT(UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip)) + +/* DMA_ERROR */ +#define UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip) 9 +#define UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip) \ + (BIT(UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip))) +#define SET_UNIPERIF_ITM_BSET_DMA_ERROR(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip)) + +/* UNDERFLOW_REC_DONE */ +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip)))) +#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip)) + +/* UNDERFLOW_REC_FAILED */ +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) +#define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ + 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip)))) +#define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(ip) \ + SET_UNIPERIF_ITM_BSET(ip, \ + UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip)) + +/* + * UNIPERIF_CONFIG reg + */ + +#define UNIPERIF_CONFIG_OFFSET(ip) 0x0040 +#define GET_UNIPERIF_CONFIG(ip) \ + readl_relaxed(ip->base + UNIPERIF_CONFIG_OFFSET(ip)) +#define SET_UNIPERIF_CONFIG(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CONFIG_OFFSET(ip)) + +/* PARITY_CNTR */ +#define UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip) 0 +#define UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_PARITY_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 1) + +/* CHANNEL_STA_CNTR */ +#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip) 1 +#define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 1) + +/* USER_DAT_CNTR */ +#define UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip) 2 +#define UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_USER_DAT_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 0) + +/* VALIDITY_DAT_CNTR */ +#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip) 3 +#define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip)) +#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ + UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 1) + +/* ONE_BIT_AUD_SUPPORT */ +#define UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip) 4 +#define UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_ONE_BIT_AUD(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip)) +#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ + UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 1) + +/* MEMORY_FMT */ +#define UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip) 5 +#define UNIPERIF_CONFIG_MEM_FMT_MASK(ip) 0x1 +#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) 0 +#define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) 1 +#define GET_UNIPERIF_CONFIG_MEM_FMT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \ + UNIPERIF_CONFIG_MEM_FMT_MASK(ip)) +#define SET_UNIPERIF_CONFIG_MEM_FMT(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \ + UNIPERIF_CONFIG_MEM_FMT_MASK(ip), value) +#define SET_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) \ + SET_UNIPERIF_CONFIG_MEM_FMT(ip, \ + VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip)) +#define SET_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) \ + SET_UNIPERIF_CONFIG_MEM_FMT(ip, \ + VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip)) + +/* REPEAT_CHL_STS */ +#define UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip) 6 +#define UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_REPEAT_CHL_STS(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip)) +#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ + UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 1) + +/* BACK_STALL_REQ */ +#define UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 7 : -1) +#define UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_BACK_STALL_REQ(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip)) +#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ + UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 1) + +/* FDMA_TRIGGER_LIMIT */ +#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip) 8 +#define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip) 0x7F +#define GET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip)) +#define SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \ + UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip), value) + +/* CHL_STS_UPDATE */ +#define UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1) +#define UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip)) +#define SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip), 1) + +/* IDLE_MOD */ +#define UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip) 18 +#define UNIPERIF_CONFIG_IDLE_MOD_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_IDLE_MOD(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_MASK(ip)) +#define SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 0) +#define SET_UNIPERIF_CONFIG_IDLE_MOD_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ + UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 1) + +/* SUBFRAME_SELECTION */ +#define UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip) 19 +#define UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_SUBFRAME_SEL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip)) +#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF0_SUBF1(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ + UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 0) + +/* FULL_SW_CONTROL */ +#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip) 20 +#define UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_SPDIF_SW_CTRL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip)) +#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_ENABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ + UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 0) + +/* MASTER_CLKEDGE */ +#define UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 24 : -1) +#define UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip) 0x1 +#define GET_UNIPERIF_CONFIG_MSTR_CLKEDGE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip)) +#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_FALLING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 1) +#define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_RISING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CONFIG_OFFSET(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ + UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 0) + +/* + * UNIPERIF_CTRL reg + */ + +#define UNIPERIF_CTRL_OFFSET(ip) 0x0044 +#define GET_UNIPERIF_CTRL(ip) \ + readl_relaxed(ip->base + UNIPERIF_CTRL_OFFSET(ip)) +#define SET_UNIPERIF_CTRL(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_CTRL_OFFSET(ip)) + +/* OPERATION */ +#define UNIPERIF_CTRL_OPERATION_SHIFT(ip) 0 +#define UNIPERIF_CTRL_OPERATION_MASK(ip) 0x7 +#define GET_UNIPERIF_CTRL_OPERATION(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip) 0 +#define SET_UNIPERIF_CTRL_OPERATION_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 1 : -1) +#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 2 : -1) +#define SET_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) 3 +#define SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip)) +/* This is the same as above! */ +#define VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) 3 +#define SET_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) 4 +#define SET_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 5 : -1) +#define SET_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip)) +#define VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 7) +#define SET_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ + UNIPERIF_CTRL_OPERATION_MASK(ip), \ + VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip)) + +/* EXIT_STBY_ON_EOBLOCK */ +#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 3) +#define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip)) +#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ + UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 1) + +/* ROUNDING */ +#define UNIPERIF_CTRL_ROUNDING_SHIFT(ip) 4 +#define UNIPERIF_CTRL_ROUNDING_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_ROUNDING(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ + UNIPERIF_CTRL_ROUNDING_MASK(ip)) +#define SET_UNIPERIF_CTRL_ROUNDING_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ + UNIPERIF_CTRL_ROUNDING_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_ROUNDING_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ + UNIPERIF_CTRL_ROUNDING_MASK(ip), 1) + +/* DIVIDER */ +#define UNIPERIF_CTRL_DIVIDER_SHIFT(ip) 5 +#define UNIPERIF_CTRL_DIVIDER_MASK(ip) 0xff +#define GET_UNIPERIF_CTRL_DIVIDER(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \ + UNIPERIF_CTRL_DIVIDER_MASK(ip)) +#define SET_UNIPERIF_CTRL_DIVIDER(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \ + UNIPERIF_CTRL_DIVIDER_MASK(ip), value) + +/* BYTE_SWAP */ +#define UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 13 : -1) +#define UNIPERIF_CTRL_BYTE_SWP_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_BYTE_SWP(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ + UNIPERIF_CTRL_BYTE_SWP_MASK(ip)) +#define SET_UNIPERIF_CTRL_BYTE_SWP_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ + UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_BYTE_SWP_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ + UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 1) + +/* ZERO_STUFFING_HW_SW */ +#define UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 14 : -1) +#define UNIPERIF_CTRL_ZERO_STUFF_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_ZERO_STUFF(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_MASK(ip)) +#define SET_UNIPERIF_CTRL_ZERO_STUFF_HW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 1) +#define SET_UNIPERIF_CTRL_ZERO_STUFF_SW(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ + UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 0) + +/* SPDIF_LAT */ +#define UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1) +#define UNIPERIF_CTRL_SPDIF_LAT_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_SPDIF_LAT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_MASK(ip)) +#define SET_UNIPERIF_CTRL_SPDIF_LAT_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 1) +#define SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 0) + +/* EN_SPDIF_FORMATTING */ +#define UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip) 17 +#define UNIPERIF_CTRL_SPDIF_FMT_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_SPDIF_FMT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_MASK(ip)) +#define SET_UNIPERIF_CTRL_SPDIF_FMT_ON(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 1) +#define SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ + UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 0) + +/* READER_OUT_SELECT */ +#define UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 18 : -1) +#define UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip) 0x1 +#define GET_UNIPERIF_CTRL_READER_OUT_SEL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip)) +#define SET_UNIPERIF_CTRL_READER_OUT_SEL_IN_MEM(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 0) +#define SET_UNIPERIF_CTRL_READER_OUT_SEL_ON_I2S_LINE(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ + CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) + +/* UNDERFLOW_REC_WINDOW */ +#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 +#define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip) 0xff +#define GET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip)) +#define SET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_CTRL_OFFSET(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \ + UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip), value) + +/* + * UNIPERIF_I2S_FMT a.k.a UNIPERIF_FORMAT reg + */ + +#define UNIPERIF_I2S_FMT_OFFSET(ip) 0x0048 +#define GET_UNIPERIF_I2S_FMT(ip) \ + readl_relaxed(ip->base + UNIPERIF_I2S_FMT_OFFSET(ip)) +#define SET_UNIPERIF_I2S_FMT(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_I2S_FMT_OFFSET(ip)) + +/* NBIT */ +#define UNIPERIF_I2S_FMT_NBIT_SHIFT(ip) 0 +#define UNIPERIF_I2S_FMT_NBIT_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_NBIT(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NBIT_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_NBIT_32(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NBIT_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_NBIT_16(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NBIT_MASK(ip), 1) + +/* DATA_SIZE */ +#define UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip) 1 +#define UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip) 0x7 +#define GET_UNIPERIF_I2S_FMT_DATA_SIZE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_18(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 1) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_20(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 2) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 3) +#define SET_UNIPERIF_I2S_FMTL_DATA_SIZE_28(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 4) +#define SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 5) + +/* LR_POL */ +#define UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip) 4 +#define UNIPERIF_I2S_FMT_LR_POL_MASK(ip) 0x1 +#define VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) 0x0 +#define VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_LR_POL(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \ + UNIPERIF_I2S_FMT_LR_POL_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_LR_POL(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \ + UNIPERIF_I2S_FMT_LR_POL_MASK(ip), value) +#define SET_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) \ + SET_UNIPERIF_I2S_FMT_LR_POL(ip, \ + VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip)) +#define SET_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) \ + SET_UNIPERIF_I2S_FMT_LR_POL(ip, \ + VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip)) + +/* SCLK_EDGE */ +#define UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip) 5 +#define UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_SCLK_EDGE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ + UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 1) + +/* PADDING */ +#define UNIPERIF_I2S_FMT_PADDING_SHIFT(ip) 6 +#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1 +#define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1 +#define VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) 0x0 +#define VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_PADDING(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \ + UNIPERIF_I2S_FMT_PADDING_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_PADDING(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \ + UNIPERIF_I2S_FMT_PADDING_MASK(ip), value) +#define SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) \ + SET_UNIPERIF_I2S_FMT_PADDING(ip, \ + VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip)) +#define SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) \ + SET_UNIPERIF_I2S_FMT_PADDING(ip, \ + VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip)) + +/* ALIGN */ +#define UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip) 7 +#define UNIPERIF_I2S_FMT_ALIGN_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_ALIGN(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ALIGN_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 1) + +/* ORDER */ +#define UNIPERIF_I2S_FMT_ORDER_SHIFT(ip) 8 +#define UNIPERIF_I2S_FMT_ORDER_MASK(ip) 0x1 +#define GET_UNIPERIF_I2S_FMT_ORDER(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ORDER_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_ORDER_LSB(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ORDER_MASK(ip), 0) +#define SET_UNIPERIF_I2S_FMT_ORDER_MSB(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ + UNIPERIF_I2S_FMT_ORDER_MASK(ip), 1) + +/* NUM_CH */ +#define UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip) 9 +#define UNIPERIF_I2S_FMT_NUM_CH_MASK(ip) 0x7 +#define GET_UNIPERIF_I2S_FMT_NUM_CH(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_NUM_CH(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NUM_CH_MASK(ip), value) + +/* NO_OF_SAMPLES_TO_READ */ +#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip) 12 +#define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip) 0xfffff +#define GET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip)) +#define SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_I2S_FMT_OFFSET(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \ + UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip), value) + +/* + * UNIPERIF_BIT_CONTROL reg + */ + +#define UNIPERIF_BIT_CONTROL_OFFSET(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0x004c) +#define GET_UNIPERIF_BIT_CONTROL(ip) \ + readl_relaxed(ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip)) +#define SET_UNIPERIF_BIT_CONTROL(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip)) + +/* CLR_UNDERFLOW_DURATION */ +#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip) 0 +#define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip) 0x1 +#define GET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip)) +#define SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip), 1) + +/* CHL_STS_UPDATE */ +#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip) 1 +#define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip) 0x1 +#define GET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip)) +#define SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \ + SET_UNIPERIF_BIT_REG(ip, \ + UNIPERIF_BIT_CONTROL_OFFSET(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \ + UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip), 1) + +/* + * UNIPERIF_STATUS_1 reg + */ + +#define UNIPERIF_STATUS_1_OFFSET(ip) 0x0050 +#define GET_UNIPERIF_STATUS_1(ip) \ + readl_relaxed(ip->base + UNIPERIF_STATUS_1_OFFSET(ip)) +#define SET_UNIPERIF_STATUS_1(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_STATUS_1_OFFSET(ip)) + +/* UNDERFLOW_DURATION */ +#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0) +#define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip) 0xff +#define GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_STATUS_1_OFFSET(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip)) +#define SET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_STATUS_1_OFFSET(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \ + UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) + +/* + * AUD_UNIPERIF_CHANNEL_STA_REGN reg + */ + +#define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) +#define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \ + readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n)) +#define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \ + writel_relaxed(value, ip->base + \ + UNIPERIF_CHANNEL_STA_REGN(ip, n)) + +/* + * AUD_UNIPERIF_USER_VALIDITY reg + */ + +#define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 +#define GET_UNIPERIF_USER_VALIDITY(ip) \ + readl_relaxed(ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip)) +#define SET_UNIPERIF_USER_VALIDITY(ip, value) \ + writel_relaxed(value, ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip)) + +/* VALIDITY_LEFT_AND_RIGHT */ +#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip) 0 +#define UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip) 0x3 +#define GET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_USER_VALIDITY_OFFSET(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip)) +#define SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_USER_VALIDITY_OFFSET(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \ + UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip), \ + value ? 0x3 : 0) + +/* + * UNIPERIF_DBG_STANDBY_LEFT_SP reg + */ +#define UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip) 0x0150 +#define UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0) +#define UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip) \ + ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 0xFFFFFF) +#define GET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip) \ + GET_UNIPERIF_REG(ip, \ + UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip)) +#define SET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip, value) \ + SET_UNIPERIF_REG(ip, \ + UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ + UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) -- GitLab From 76c2145ded6b83488dec4afc46a29a57cee90552 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Mon, 22 Jun 2015 16:31:07 +0200 Subject: [PATCH 0692/7006] ASoC: sti: Add CPU DAI driver for playback Add code to manage Uniperipheral player IP instances. These DAIs are dedicated to playback and support I2S and IEC modes. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif.h | 116 +++++ sound/soc/sti/uniperif_player.c | 890 ++++++++++++++++++++++++++++++++ 2 files changed, 1006 insertions(+) create mode 100644 sound/soc/sti/uniperif_player.c diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index 043853e093a5b..a8d9e94d80410 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -10,6 +10,8 @@ #include +#include + /* * Register access macros */ @@ -1097,3 +1099,117 @@ UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) + +/* + * uniperipheral IP capabilities + */ + +#define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ +#define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ + +/* + * Uniperipheral IP revisions + */ +enum uniperif_version { + SND_ST_UNIPERIF_VERSION_UNKNOWN, + /* SASG1 (Orly), Newman */ + SND_ST_UNIPERIF_VERSION_C6AUD0_UNI_1_0, + /* SASC1, SASG2 (Orly2) */ + SND_ST_UNIPERIF_VERSION_UNI_PLR_1_0, + /* SASC1, SASG2 (Orly2), TELSS, Cannes */ + SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, + /* TELSS (SASC1) */ + SND_ST_UNIPERIF_VERSION_TDM_PLR_1_0, + /* Cannes/Monaco */ + SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 +}; + +enum uniperif_type { + SND_ST_UNIPERIF_PLAYER_TYPE_NONE, + SND_ST_UNIPERIF_PLAYER_TYPE_HDMI, + SND_ST_UNIPERIF_PLAYER_TYPE_PCM, + SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF +}; + +enum uniperif_state { + UNIPERIF_STATE_STOPPED, + UNIPERIF_STATE_STARTED, + UNIPERIF_STATE_STANDBY, + UNIPERIF_STATE_UNDERFLOW, + UNIPERIF_STATE_OVERFLOW = UNIPERIF_STATE_UNDERFLOW, + UNIPERIF_STATE_XRUN +}; + +enum uniperif_iec958_encoding_mode { + UNIPERIF_IEC958_ENCODING_MODE_PCM, + UNIPERIF_IEC958_ENCODING_MODE_ENCODED +}; + +struct uniperif_info { + int id; /* instance value of the uniperipheral IP */ + enum uniperif_type player_type; + int underflow_enabled; /* Underflow recovery mode */ +}; + +struct uniperif_iec958_settings { + enum uniperif_iec958_encoding_mode encoding_mode; + struct snd_aes_iec958 iec958; +}; + +struct uniperif { + /* System information */ + struct uniperif_info *info; + struct device *dev; + int ver; /* IP version, used by register access macros */ + struct regmap_field *clk_sel; + + /* capabilities */ + const struct snd_pcm_hardware *hw; + + /* Resources */ + struct resource *mem_region; + void *base; + unsigned long fifo_phys_address; + int irq; + + /* Clocks */ + struct clk *clk; + int mclk; + + /* Runtime data */ + enum uniperif_state state; + + struct snd_pcm_substream *substream; + + /* Specific to IEC958 player */ + struct uniperif_iec958_settings stream_settings; + + /*alsa ctrl*/ + struct snd_kcontrol_new *snd_ctrls; + int num_ctrls; + + /* dai properties */ + unsigned int daifmt; + + /* DAI callbacks */ + const struct snd_soc_dai_ops *dai_ops; +}; + +struct sti_uniperiph_dai { + int stream; + struct uniperif *uni; + struct snd_dmaengine_dai_dma_data dma_data; +}; + +struct sti_uniperiph_data { + struct platform_device *pdev; + struct snd_soc_dai_driver *dai; + struct sti_uniperiph_dai dai_data; +}; + +/* uniperiph player*/ +int uni_player_init(struct platform_device *pdev, + struct uniperif *uni_player); +int uni_player_resume(struct uniperif *player); + +#endif diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c new file mode 100644 index 0000000000000..d66d633f0b29f --- /dev/null +++ b/sound/soc/sti/uniperif_player.c @@ -0,0 +1,890 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include + +#include +#include + +#include "uniperif.h" + +/* + * Some hardware-related definitions + */ + +/* sys config registers definitions */ +#define SYS_CFG_AUDIO_GLUE 0xA4 +#define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 + +/* + * Driver specific types. + */ +#define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ + ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) +#define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ + ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) +#define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ + ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) +#define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ + (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ + UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) + +/* + * Note: snd_pcm_hardware is linked to DMA controller but is declared here to + * integrate DAI_CPU capability in term of rate and supported channels + */ +const struct snd_pcm_hardware uni_player_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 192000, + + .channels_min = 2, + .channels_max = 8, + + .periods_min = 2, + .periods_max = 48, + + .period_bytes_min = 128, + .period_bytes_max = 64 * PAGE_SIZE, + .buffer_bytes_max = 256 * PAGE_SIZE +}; + +static inline int reset_player(struct uniperif *player) +{ + int count = 10; + + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { + while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { + udelay(5); + count--; + } + } + + if (!count) { + dev_err(player->dev, "Failed to reset uniperif"); + return -EIO; + } + + return 0; +} + +/* + * uni_player_irq_handler + * In case of error audio stream is stopped; stop action is protected via PCM + * stream lock to avoid race condition with trigger callback. + */ +static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct uniperif *player = dev_id; + unsigned int status; + unsigned int tmp; + + if (player->state == UNIPERIF_STATE_STOPPED) { + /* Unexpected IRQ: do nothing */ + return IRQ_NONE; + } + + /* Get interrupt status & clear them immediately */ + status = GET_UNIPERIF_ITS(player); + SET_UNIPERIF_ITS_BCLR(player, status); + + /* Check for fifo error (underrun) */ + if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { + dev_err(player->dev, "FIFO underflow error detected"); + + /* Interrupt is just for information when underflow recovery */ + if (player->info->underflow_enabled) { + /* Update state to underflow */ + player->state = UNIPERIF_STATE_UNDERFLOW; + + } else { + /* Disable interrupt so doesn't continually fire */ + SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); + + /* Stop the player */ + snd_pcm_stream_lock(player->substream); + snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(player->substream); + } + + ret = IRQ_HANDLED; + } + + /* Check for dma error (overrun) */ + if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { + dev_err(player->dev, "DMA error detected"); + + /* Disable interrupt so doesn't continually fire */ + SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); + + /* Stop the player */ + snd_pcm_stream_lock(player->substream); + snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(player->substream); + + ret = IRQ_HANDLED; + } + + /* Check for underflow recovery done */ + if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { + if (!player->info->underflow_enabled) { + dev_err(player->dev, "unexpected Underflow recovering"); + return -EPERM; + } + /* Read the underflow recovery duration */ + tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); + + /* Clear the underflow recovery duration */ + SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); + + /* Update state to started */ + player->state = UNIPERIF_STATE_STARTED; + + ret = IRQ_HANDLED; + } + + /* Check if underflow recovery failed */ + if (unlikely(status & + UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { + dev_err(player->dev, "Underflow recovery failed"); + + /* Stop the player */ + snd_pcm_stream_lock(player->substream); + snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(player->substream); + + ret = IRQ_HANDLED; + } + + return ret; +} + +static void uni_player_set_channel_status(struct uniperif *player, + struct snd_pcm_runtime *runtime) +{ + int n; + unsigned int status; + + /* + * Some AVRs and TVs require the channel status to contain a correct + * sampling frequency. If no sample rate is already specified, then + * set one. + */ + if (runtime && (player->stream_settings.iec958.status[3] + == IEC958_AES3_CON_FS_NOTID)) { + switch (runtime->rate) { + case 22050: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_22050; + break; + case 44100: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_44100; + break; + case 88200: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_88200; + break; + case 176400: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_176400; + break; + case 24000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_24000; + break; + case 48000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_48000; + break; + case 96000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_96000; + break; + case 192000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_192000; + break; + case 32000: + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_32000; + break; + default: + /* Mark as sampling frequency not indicated */ + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_NOTID; + break; + } + } + + /* Audio mode: + * Use audio mode status to select PCM or encoded mode + */ + if (player->stream_settings.iec958.status[0] & IEC958_AES0_NONAUDIO) + player->stream_settings.encoding_mode = + UNIPERIF_IEC958_ENCODING_MODE_ENCODED; + else + player->stream_settings.encoding_mode = + UNIPERIF_IEC958_ENCODING_MODE_PCM; + + if (player->stream_settings.encoding_mode == + UNIPERIF_IEC958_ENCODING_MODE_PCM) + /* Clear user validity bits */ + SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); + else + /* Set user validity bits */ + SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 1); + + /* Program the new channel status */ + for (n = 0; n < 6; ++n) { + status = + player->stream_settings.iec958.status[0 + (n * 4)] & 0xf; + status |= + player->stream_settings.iec958.status[1 + (n * 4)] << 8; + status |= + player->stream_settings.iec958.status[2 + (n * 4)] << 16; + status |= + player->stream_settings.iec958.status[3 + (n * 4)] << 24; + SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); + } + + /* Update the channel status */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); + else + SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); +} + +static int uni_player_prepare_iec958(struct uniperif *player, + struct snd_pcm_runtime *runtime) +{ + int clk_div; + + clk_div = player->mclk / runtime->rate; + + /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ + if ((clk_div % 128) || (clk_div <= 0)) { + dev_err(player->dev, "%s: invalid clk_div %d", + __func__, clk_div); + return -EINVAL; + } + + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + /* 16/16 memory format */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); + /* 16-bits per sub-frame */ + SET_UNIPERIF_I2S_FMT_NBIT_32(player); + /* Set 16-bit sample precision */ + SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); + break; + case SNDRV_PCM_FORMAT_S32_LE: + /* 16/0 memory format */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); + /* 32-bits per sub-frame */ + SET_UNIPERIF_I2S_FMT_NBIT_32(player); + /* Set 24-bit sample precision */ + SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); + break; + default: + dev_err(player->dev, "format not supported"); + return -EINVAL; + } + + /* Set parity to be calculated by the hardware */ + SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(player); + + /* Set channel status bits to be inserted by the hardware */ + SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(player); + + /* Set user data bits to be inserted by the hardware */ + SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(player); + + /* Set validity bits to be inserted by the hardware */ + SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(player); + + /* Set full software control to disabled */ + SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(player); + + SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); + + /* Update the channel status */ + uni_player_set_channel_status(player, runtime); + + /* Clear the user validity user bits */ + SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); + + /* Disable one-bit audio mode */ + SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); + + /* Enable consecutive frames repetition of Z preamble (not for HBRA) */ + SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(player); + + /* Change to SUF0_SUBF1 and left/right channels swap! */ + SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(player); + + /* Set data output as MSB first */ + SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); + + if (player->stream_settings.encoding_mode == + UNIPERIF_IEC958_ENCODING_MODE_ENCODED) + SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(player); + else + SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(player); + + SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); + + /* Set rounding to off */ + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + + /* Set clock divisor */ + SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / 128); + + /* Set the spdif latency to not wait before starting player */ + SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); + + /* + * Ensure iec958 formatting is off. It will be enabled in function + * uni_player_start() at the same time as the operation + * mode is set to work around a silicon issue. + */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); + else + SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); + + return 0; +} + +static int uni_player_prepare_pcm(struct uniperif *player, + struct snd_pcm_runtime *runtime) +{ + int output_frame_size, slot_width, clk_div; + + /* Force slot width to 32 in I2S mode (HW constraint) */ + if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == + SND_SOC_DAIFMT_I2S) { + slot_width = 32; + } else { + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + slot_width = 16; + break; + default: + slot_width = 32; + break; + } + } + output_frame_size = slot_width * runtime->channels; + + clk_div = player->mclk / runtime->rate; + /* + * For 32 bits subframe clk_div must be a multiple of 128, + * for 16 bits must be a multiple of 64 + */ + if ((slot_width == 32) && (clk_div % 128)) { + dev_err(player->dev, "%s: invalid clk_div", __func__); + return -EINVAL; + } + + if ((slot_width == 16) && (clk_div % 64)) { + dev_err(player->dev, "%s: invalid clk_div", __func__); + return -EINVAL; + } + + /* + * Number of bits per subframe (which is one channel sample) + * on output - Transfer 16 or 32 bits from FIFO + */ + switch (slot_width) { + case 32: + SET_UNIPERIF_I2S_FMT_NBIT_32(player); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); + break; + case 16: + SET_UNIPERIF_I2S_FMT_NBIT_16(player); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); + break; + default: + dev_err(player->dev, "subframe format not supported"); + return -EINVAL; + } + + /* Configure data memory format */ + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + /* One data word contains two samples */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + /* + * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits + * on the left than zeros (if less than 32 bytes)"... ;-) + */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); + break; + + default: + dev_err(player->dev, "format not supported"); + return -EINVAL; + } + + /* Set rounding to off */ + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + + /* Set clock divisor */ + SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / (2 * output_frame_size)); + + /* Number of channelsmust be even*/ + if ((runtime->channels % 2) || (runtime->channels < 2) || + (runtime->channels > 10)) { + dev_err(player->dev, "%s: invalid nb of channels", __func__); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); + + /* Set 1-bit audio format to disabled */ + SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); + + SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + + /* No iec958 formatting as outputting to DAC */ + SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); + + return 0; +} + +static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, + unsigned int freq, int dir) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + if (dir == SND_SOC_CLOCK_IN) + return 0; + + if (clk_id != 0) + return -EINVAL; + + player->mclk = freq; + + return clk_set_rate(player->clk, freq); +} + +static int uni_player_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + struct snd_pcm_runtime *runtime = substream->runtime; + int transfer_size, trigger_limit; + int ret; + + /* The player should be stopped */ + if (player->state != UNIPERIF_STATE_STOPPED) { + dev_err(player->dev, "%s: invalid player state %d", __func__, + player->state); + return -EINVAL; + } + + /* Calculate transfer size (in fifo cells and bytes) for frame count */ + transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; + + /* Calculate number of empty cells available before asserting DREQ */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { + trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; + } else { + /* + * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 + * FDMA_TRIGGER_LIMIT also controls when the state switches + * from OFF or STANDBY to AUDIO DATA. + */ + trigger_limit = transfer_size; + } + + /* Trigger limit must be an even number */ + if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || + (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { + dev_err(player->dev, "invalid trigger limit %d", trigger_limit); + return -EINVAL; + } + + SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); + + /* Uniperipheral setup depends on player type */ + switch (player->info->player_type) { + case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: + ret = uni_player_prepare_iec958(player, runtime); + break; + case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: + ret = uni_player_prepare_pcm(player, runtime); + break; + case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: + ret = uni_player_prepare_iec958(player, runtime); + break; + default: + dev_err(player->dev, "invalid player type"); + return -EINVAL; + } + + if (ret) + return ret; + + switch (player->daifmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_NF: + SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); + break; + case SND_SOC_DAIFMT_NB_IF: + SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); + break; + case SND_SOC_DAIFMT_IB_NF: + SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + break; + case SND_SOC_DAIFMT_IB_IF: + SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + } + + switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); + SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(player); + break; + case SND_SOC_DAIFMT_LEFT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); + break; + case SND_SOC_DAIFMT_RIGHT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(player); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); + break; + default: + dev_err(player->dev, "format not supported"); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); + + /* Reset uniperipheral player */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(player); + + return reset_player(player); +} + +static int uni_player_start(struct uniperif *player) +{ + int ret; + + /* The player should be stopped */ + if (player->state != UNIPERIF_STATE_STOPPED) { + dev_err(player->dev, "%s: invalid player state", __func__); + return -EINVAL; + } + + ret = clk_prepare_enable(player->clk); + if (ret) { + dev_err(player->dev, "%s: Failed to enable clock", __func__); + return ret; + } + + /* Clear any pending interrupts */ + SET_UNIPERIF_ITS_BCLR(player, GET_UNIPERIF_ITS(player)); + + /* Set the interrupt mask */ + SET_UNIPERIF_ITM_BSET_DMA_ERROR(player); + SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player); + + /* Enable underflow recovery interrupts */ + if (player->info->underflow_enabled) { + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player); + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); + } + + /* Reset uniperipheral player */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(player); + + ret = reset_player(player); + if (ret < 0) + return ret; + + /* + * Does not use IEC61937 features of the uniperipheral hardware. + * Instead it performs IEC61937 in software and inserts it directly + * into the audio data stream. As such, when encoded mode is selected, + * linear pcm mode is still used, but with the differences of the + * channel status bits set for encoded mode and the validity bits set. + */ + SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(player); + + /* + * If iec958 formatting is required for hdmi or spdif, then it must be + * enabled after the operation mode is set. If set prior to this, it + * will not take affect and hang the player. + */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) + SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); + + /* Force channel status update (no update if clk disable) */ + if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); + else + SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); + + /* Update state to started */ + player->state = UNIPERIF_STATE_STARTED; + + return 0; +} + +static int uni_player_stop(struct uniperif *player) +{ + int ret; + + /* The player should not be in stopped state */ + if (player->state == UNIPERIF_STATE_STOPPED) { + dev_err(player->dev, "%s: invalid player state", __func__); + return -EINVAL; + } + + /* Turn the player off */ + SET_UNIPERIF_CTRL_OPERATION_OFF(player); + + /* Soft reset the player */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(player); + + ret = reset_player(player); + if (ret < 0) + return ret; + + /* Disable interrupts */ + SET_UNIPERIF_ITM_BCLR(player, GET_UNIPERIF_ITM(player)); + + /* Disable clock */ + clk_disable_unprepare(player->clk); + + /* Update state to stopped and return */ + player->state = UNIPERIF_STATE_STOPPED; + + return 0; +} + +int uni_player_resume(struct uniperif *player) +{ + int ret; + + /* Select the frequency synthesizer clock */ + if (player->clk_sel) { + ret = regmap_field_write(player->clk_sel, 1); + if (ret) { + dev_err(player->dev, + "%s: Failed to select freq synth clock", + __func__); + return ret; + } + } + + SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); + SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); + + return 0; +} +EXPORT_SYMBOL_GPL(uni_player_resume); + +static int uni_player_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + return uni_player_start(player); + case SNDRV_PCM_TRIGGER_STOP: + return uni_player_stop(player); + case SNDRV_PCM_TRIGGER_RESUME: + return uni_player_resume(player); + default: + return -EINVAL; + } +} + +static void uni_player_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + if (player->state != UNIPERIF_STATE_STOPPED) + /* Stop the player */ + uni_player_stop(player); +} + +static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, + struct uniperif *player) +{ + int bit_offset; + struct device_node *node = pdev->dev.of_node; + struct regmap *regmap; + + bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; + + regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); + + if (regmap) { + struct reg_field regfield = + REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); + + player->clk_sel = regmap_field_alloc(regmap, regfield); + } else { + dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); + return -EINVAL; + } + + return 0; +} + +static int uni_player_parse_dt(struct platform_device *pdev, + struct uniperif *player) +{ + struct uniperif_info *info; + struct device *dev = &pdev->dev; + struct device_node *pnode = pdev->dev.of_node; + const char *mode; + + /* Allocate memory for the info structure */ + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + of_property_read_u32(pnode, "version", &player->ver); + if (player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { + dev_err(dev, "Unknown uniperipheral version "); + return -EINVAL; + } + /* Underflow recovery is only supported on later ip revisions */ + if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + info->underflow_enabled = 1; + + of_property_read_u32(pnode, "uniperiph-id", &info->id); + + /* Read the device mode property */ + of_property_read_string(pnode, "mode", &mode); + + if (strcasecmp(mode, "hdmi") == 0) + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; + else if (strcasecmp(mode, "pcm") == 0) + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; + else if (strcasecmp(mode, "spdif") == 0) + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; + else + info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; + + /* Save the info structure */ + player->info = info; + + /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ + if (uni_player_parse_dt_clk_glue(pdev, player)) + return -EINVAL; + + return 0; +} + +const struct snd_soc_dai_ops uni_player_dai_ops = { + .shutdown = uni_player_shutdown, + .prepare = uni_player_prepare, + .trigger = uni_player_trigger, + .hw_params = sti_uniperiph_dai_hw_params, + .set_fmt = sti_uniperiph_dai_set_fmt, + .set_sysclk = uni_player_set_sysclk +}; + +int uni_player_init(struct platform_device *pdev, + struct uniperif *player) +{ + int ret = 0; + + player->dev = &pdev->dev; + player->state = UNIPERIF_STATE_STOPPED; + player->hw = &uni_player_pcm_hw; + player->dai_ops = &uni_player_dai_ops; + + ret = uni_player_parse_dt(pdev, player); + + if (ret < 0) { + dev_err(player->dev, "Failed to parse DeviceTree"); + return ret; + } + + /* Get uniperif resource */ + player->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(player->clk)) + ret = (int)PTR_ERR(player->clk); + + /* Select the frequency synthesizer clock */ + if (player->clk_sel) { + ret = regmap_field_write(player->clk_sel, 1); + if (ret) { + dev_err(player->dev, + "%s: Failed to select freq synth clock", + __func__); + return ret; + } + } + + ret = devm_request_irq(&pdev->dev, player->irq, + uni_player_irq_handler, IRQF_SHARED, + dev_name(&pdev->dev), player); + if (ret < 0) + return ret; + + /* Ensure that disabled by default */ + SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); + SET_UNIPERIF_CTRL_ROUNDING_OFF(player); + SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); + SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); + + if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { + /* Set default iec958 status bits */ + + /* Consumer, PCM, copyright, 2ch, mode 0 */ + player->stream_settings.iec958.status[0] = 0x00; + /* Broadcast reception category */ + player->stream_settings.iec958.status[1] = + IEC958_AES1_CON_GENERAL; + /* Do not take into account source or channel number */ + player->stream_settings.iec958.status[2] = + IEC958_AES2_CON_SOURCE_UNSPEC; + /* Sampling frequency not indicated */ + player->stream_settings.iec958.status[3] = + IEC958_AES3_CON_FS_NOTID; + /* Max sample word 24-bit, sample word length not indicated */ + player->stream_settings.iec958.status[4] = + IEC958_AES4_CON_MAX_WORDLEN_24 | + IEC958_AES4_CON_WORDLEN_24_20; + } + + return 0; +} +EXPORT_SYMBOL_GPL(uni_player_init); -- GitLab From 634ec36cc0ab9d8dda0f2c101fa28d2e2a61b9eb Mon Sep 17 00:00:00 2001 From: David Thomson Date: Fri, 10 Jul 2015 13:56:54 +1200 Subject: [PATCH 0693/7006] net: phy: Pass mdix ethtool setting through to phy driver Pass the mdix setting from ethtool down to the phy driver, to allow driver specific implementations of manually setting the polarity. Signed-off-by: David Thomson Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 2 ++ include/linux/phy.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index b2197b506acbe..47693a9ebd3ae 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -353,6 +353,8 @@ int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd) phydev->duplex = cmd->duplex; + phydev->mdix = cmd->eth_tp_mdix_ctrl; + /* Restart the PHY */ phy_start_aneg(phydev); diff --git a/include/linux/phy.h b/include/linux/phy.h index a26c3f84b8ddc..e5fb1d4159619 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -424,6 +424,8 @@ struct phy_device { struct net_device *attached_dev; + u8 mdix; + void (*adjust_link)(struct net_device *dev); }; #define to_phy_device(d) container_of(d, struct phy_device, dev) -- GitLab From 239aa55b9496144f89670b545b5698e6c989f710 Mon Sep 17 00:00:00 2001 From: David Thomson Date: Fri, 10 Jul 2015 16:28:25 +1200 Subject: [PATCH 0694/7006] net: phy: Support setting polarity in marvell phy driver Support manually setting the polarity to mdi or mdix Signed-off-by: David Thomson Signed-off-by: David S. Miller --- drivers/net/phy/marvell.c | 42 +++++++++++++++++++++++++++++++++++++-- drivers/net/phy/phy.c | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/marvell.c b/drivers/net/phy/marvell.c index f721444c2b0a9..3320a179ee360 100644 --- a/drivers/net/phy/marvell.c +++ b/drivers/net/phy/marvell.c @@ -48,6 +48,8 @@ #define MII_M1011_IMASK_CLEAR 0x0000 #define MII_M1011_PHY_SCR 0x10 +#define MII_M1011_PHY_SCR_MDI 0x0000 +#define MII_M1011_PHY_SCR_MDI_X 0x0020 #define MII_M1011_PHY_SCR_AUTO_CROSS 0x0060 #define MII_M1145_PHY_EXT_SR 0x1b @@ -159,6 +161,43 @@ static int marvell_config_intr(struct phy_device *phydev) return err; } +static int marvell_set_polarity(struct phy_device *phydev, int polarity) +{ + int reg; + int err; + int val; + + /* get the current settings */ + reg = phy_read(phydev, MII_M1011_PHY_SCR); + if (reg < 0) + return reg; + + val = reg; + val &= ~MII_M1011_PHY_SCR_AUTO_CROSS; + switch (polarity) { + case ETH_TP_MDI: + val |= MII_M1011_PHY_SCR_MDI; + break; + case ETH_TP_MDI_X: + val |= MII_M1011_PHY_SCR_MDI_X; + break; + case ETH_TP_MDI_AUTO: + case ETH_TP_MDI_INVALID: + default: + val |= MII_M1011_PHY_SCR_AUTO_CROSS; + break; + } + + if (val != reg) { + /* Set the new polarity value in the register */ + err = phy_write(phydev, MII_M1011_PHY_SCR, val); + if (err) + return err; + } + + return 0; +} + static int marvell_config_aneg(struct phy_device *phydev) { int err; @@ -191,8 +230,7 @@ static int marvell_config_aneg(struct phy_device *phydev) if (err < 0) return err; - err = phy_write(phydev, MII_M1011_PHY_SCR, - MII_M1011_PHY_SCR_AUTO_CROSS); + err = marvell_set_polarity(phydev, phydev->mdix); if (err < 0) return err; diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index 47693a9ebd3ae..84b1fba58ac3c 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -379,6 +379,7 @@ int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd) cmd->transceiver = phy_is_internal(phydev) ? XCVR_INTERNAL : XCVR_EXTERNAL; cmd->autoneg = phydev->autoneg; + cmd->eth_tp_mdix_ctrl = phydev->mdix; return 0; } -- GitLab From 6979b9cf58c86d14ceb1702b5b3fa4f63c98c013 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:29:23 +0900 Subject: [PATCH 0695/7006] net: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 1 - drivers/net/ethernet/hisilicon/hip04_mdio.c | 1 - drivers/net/ethernet/ti/netcp_core.c | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index d49bee38cd319..cc2d8b4b18e3e 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -965,7 +965,6 @@ static struct platform_driver hip04_mac_driver = { .remove = hip04_remove, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .of_match_table = hip04_mac_match, }, }; diff --git a/drivers/net/ethernet/hisilicon/hip04_mdio.c b/drivers/net/ethernet/hisilicon/hip04_mdio.c index b3bac25db99cf..fca0a5be1f0f7 100644 --- a/drivers/net/ethernet/hisilicon/hip04_mdio.c +++ b/drivers/net/ethernet/hisilicon/hip04_mdio.c @@ -174,7 +174,6 @@ static struct platform_driver hip04_mdio_driver = { .remove = hip04_mdio_remove, .driver = { .name = "hip04-mdio", - .owner = THIS_MODULE, .of_match_table = hip04_mdio_match, }, }; diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c index 5ec4ed3f6c8de..3e47202b90102 100644 --- a/drivers/net/ethernet/ti/netcp_core.c +++ b/drivers/net/ethernet/ti/netcp_core.c @@ -2142,7 +2142,6 @@ MODULE_DEVICE_TABLE(of, of_match); static struct platform_driver netcp_driver = { .driver = { .name = "netcp-1.0", - .owner = THIS_MODULE, .of_match_table = of_match, }, .probe = netcp_probe, -- GitLab From 9131f3de24db4dc12199aede7d931e6703e97f3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki/=E5=90=89=E8=97=A4=E8=8B=B1=E6=98=8E?= Date: Fri, 10 Jul 2015 16:58:31 +0900 Subject: [PATCH 0696/7006] ipv6: Do not iterate over all interfaces when finding source address on specific interface. If outgoing interface is specified and the candidate address is restricted to the outgoing interface, it is enough to iterate over that given interface only. Signed-off-by: YOSHIFUJI Hideaki Acked-by: Erik Kline Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 197 ++++++++++++++++++++++++-------------------- 1 file changed, 107 insertions(+), 90 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 21c2c818df3b8..4ab74d56f65a1 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1358,15 +1358,94 @@ out: return ret; } +static void __ipv6_dev_get_saddr(struct net *net, + struct ipv6_saddr_dst *dst, + unsigned int prefs, + const struct in6_addr *saddr, + struct inet6_dev *idev, + struct ipv6_saddr_score *scores) +{ + struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1]; + + read_lock_bh(&idev->lock); + list_for_each_entry(score->ifa, &idev->addr_list, if_list) { + int i; + + /* + * - Tentative Address (RFC2462 section 5.4) + * - A tentative address is not considered + * "assigned to an interface" in the traditional + * sense, unless it is also flagged as optimistic. + * - Candidate Source Address (section 4) + * - In any case, anycast addresses, multicast + * addresses, and the unspecified address MUST + * NOT be included in a candidate set. + */ + if ((score->ifa->flags & IFA_F_TENTATIVE) && + (!(score->ifa->flags & IFA_F_OPTIMISTIC))) + continue; + + score->addr_type = __ipv6_addr_type(&score->ifa->addr); + + if (unlikely(score->addr_type == IPV6_ADDR_ANY || + score->addr_type & IPV6_ADDR_MULTICAST)) { + net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s", + idev->dev->name); + continue; + } + + score->rule = -1; + bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); + + for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { + int minihiscore, miniscore; + + minihiscore = ipv6_get_saddr_eval(net, hiscore, dst, i); + miniscore = ipv6_get_saddr_eval(net, score, dst, i); + + if (minihiscore > miniscore) { + if (i == IPV6_SADDR_RULE_SCOPE && + score->scopedist > 0) { + /* + * special case: + * each remaining entry + * has too small (not enough) + * scope, because ifa entries + * are sorted by their scope + * values. + */ + goto out; + } + break; + } else if (minihiscore < miniscore) { + if (hiscore->ifa) + in6_ifa_put(hiscore->ifa); + + in6_ifa_hold(score->ifa); + + swap(hiscore, score); + + /* restore our iterator */ + score->ifa = hiscore->ifa; + + break; + } + } + } +out: + read_unlock_bh(&idev->lock); +} + int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, const struct in6_addr *daddr, unsigned int prefs, struct in6_addr *saddr) { - struct ipv6_saddr_score scores[2], - *score = &scores[0], *hiscore = &scores[1]; + struct ipv6_saddr_score scores[2], *hiscore = &scores[1]; struct ipv6_saddr_dst dst; + struct inet6_dev *idev; struct net_device *dev; int dst_type; + bool use_oif_addr = false; dst_type = __ipv6_addr_type(daddr); dst.addr = daddr; @@ -1380,97 +1459,35 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - struct inet6_dev *idev; - - /* Candidate Source Address (section 4) - * - multicast and link-local destination address, - * the set of candidate source address MUST only - * include addresses assigned to interfaces - * belonging to the same link as the outgoing - * interface. - * (- For site-local destination addresses, the - * set of candidate source addresses MUST only - * include addresses assigned to interfaces - * belonging to the same site as the outgoing - * interface.) - */ - if (((dst_type & IPV6_ADDR_MULTICAST) || - dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) && - dst.ifindex && dev->ifindex != dst.ifindex) - continue; - - idev = __in6_dev_get(dev); - if (!idev) - continue; - - read_lock_bh(&idev->lock); - list_for_each_entry(score->ifa, &idev->addr_list, if_list) { - int i; - - /* - * - Tentative Address (RFC2462 section 5.4) - * - A tentative address is not considered - * "assigned to an interface" in the traditional - * sense, unless it is also flagged as optimistic. - * - Candidate Source Address (section 4) - * - In any case, anycast addresses, multicast - * addresses, and the unspecified address MUST - * NOT be included in a candidate set. - */ - if ((score->ifa->flags & IFA_F_TENTATIVE) && - (!(score->ifa->flags & IFA_F_OPTIMISTIC))) - continue; - - score->addr_type = __ipv6_addr_type(&score->ifa->addr); + /* Candidate Source Address (section 4) + * - multicast and link-local destination address, + * the set of candidate source address MUST only + * include addresses assigned to interfaces + * belonging to the same link as the outgoing + * interface. + * (- For site-local destination addresses, the + * set of candidate source addresses MUST only + * include addresses assigned to interfaces + * belonging to the same site as the outgoing + * interface.) + */ + if (dst_dev) { + if ((dst_type & IPV6_ADDR_MULTICAST) || + dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) { + idev = __in6_dev_get(dst_dev); + use_oif_addr = true; + } + } - if (unlikely(score->addr_type == IPV6_ADDR_ANY || - score->addr_type & IPV6_ADDR_MULTICAST)) { - net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s", - dev->name); + if (use_oif_addr) { + __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores); + } else { + for_each_netdev_rcu(net, dev) { + idev = __in6_dev_get(dev); + if (!idev) continue; - } - - score->rule = -1; - bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); - - for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { - int minihiscore, miniscore; - - minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i); - miniscore = ipv6_get_saddr_eval(net, score, &dst, i); - - if (minihiscore > miniscore) { - if (i == IPV6_SADDR_RULE_SCOPE && - score->scopedist > 0) { - /* - * special case: - * each remaining entry - * has too small (not enough) - * scope, because ifa entries - * are sorted by their scope - * values. - */ - goto try_nextdev; - } - break; - } else if (minihiscore < miniscore) { - if (hiscore->ifa) - in6_ifa_put(hiscore->ifa); - - in6_ifa_hold(score->ifa); - - swap(hiscore, score); - - /* restore our iterator */ - score->ifa = hiscore->ifa; - - break; - } - } + __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores); } -try_nextdev: - read_unlock_bh(&idev->lock); } rcu_read_unlock(); -- GitLab From 145155e786ccee898f6ed665f6dd3bce7c14830f Mon Sep 17 00:00:00 2001 From: Kalesh Purayil Date: Fri, 10 Jul 2015 05:32:43 -0400 Subject: [PATCH 0697/7006] be2net: remove duplicate code in be_setup_wol() This change will make be_setup_wol() routine more compact and readable by removing some duplicate code. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 28 ++++++++------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 6f642426308c6..635c62fa319ca 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -3529,15 +3529,15 @@ err: static int be_setup_wol(struct be_adapter *adapter, bool enable) { + struct device *dev = &adapter->pdev->dev; struct be_dma_mem cmd; - int status = 0; u8 mac[ETH_ALEN]; + int status; eth_zero_addr(mac); cmd.size = sizeof(struct be_cmd_req_acpi_wol_magic_config); - cmd.va = dma_zalloc_coherent(&adapter->pdev->dev, cmd.size, &cmd.dma, - GFP_KERNEL); + cmd.va = dma_zalloc_coherent(dev, cmd.size, &cmd.dma, GFP_KERNEL); if (!cmd.va) return -ENOMEM; @@ -3546,24 +3546,18 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable) PCICFG_PM_CONTROL_OFFSET, PCICFG_PM_CONTROL_MASK); if (status) { - dev_err(&adapter->pdev->dev, - "Could not enable Wake-on-lan\n"); - dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, - cmd.dma); - return status; + dev_err(dev, "Could not enable Wake-on-lan\n"); + goto err; } - status = be_cmd_enable_magic_wol(adapter, - adapter->netdev->dev_addr, - &cmd); - pci_enable_wake(adapter->pdev, PCI_D3hot, 1); - pci_enable_wake(adapter->pdev, PCI_D3cold, 1); } else { - status = be_cmd_enable_magic_wol(adapter, mac, &cmd); - pci_enable_wake(adapter->pdev, PCI_D3hot, 0); - pci_enable_wake(adapter->pdev, PCI_D3cold, 0); + ether_addr_copy(mac, adapter->netdev->dev_addr); } - dma_free_coherent(&adapter->pdev->dev, cmd.size, cmd.va, cmd.dma); + status = be_cmd_enable_magic_wol(adapter, mac, &cmd); + pci_enable_wake(adapter->pdev, PCI_D3hot, enable); + pci_enable_wake(adapter->pdev, PCI_D3cold, enable); +err: + dma_free_coherent(dev, cmd.size, cmd.va, cmd.dma); return status; } -- GitLab From ff9ed19d263d9678394b6ac079abd68efb3c55c0 Mon Sep 17 00:00:00 2001 From: Kalesh Purayil Date: Fri, 10 Jul 2015 05:32:44 -0400 Subject: [PATCH 0698/7006] be2net: query FW to check if EVB is enabled The current code assumes that bridge functionality (EVB) in the adapter is enabled only when SR-IOV is enabled. This is not always true. This patch uses the GET_HSW_CONFIG FW cmd to query this from the FW. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.h | 1 + drivers/net/ethernet/emulex/benet/be_main.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index 2716e6f30d9a0..f0a92b7e4e7d3 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1758,6 +1758,7 @@ struct be_cmd_req_set_mac_list { /*********************** HSW Config ***********************/ #define PORT_FWD_TYPE_VEPA 0x3 #define PORT_FWD_TYPE_VEB 0x2 +#define PORT_FWD_TYPE_PASSTHRU 0x1 #define ENABLE_MAC_SPOOFCHK 0x2 #define DISABLE_MAC_SPOOFCHK 0x3 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 635c62fa319ca..f21c56abd5c25 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5073,9 +5073,6 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, int status = 0; u8 hsw_mode; - if (!sriov_enabled(adapter)) - return 0; - /* BE and Lancer chips support VEB mode only */ if (BEx_chip(adapter) || lancer_chip(adapter)) { hsw_mode = PORT_FWD_TYPE_VEB; @@ -5085,6 +5082,9 @@ static int be_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, NULL); if (status) return 0; + + if (hsw_mode == PORT_FWD_TYPE_PASSTHRU) + return 0; } return ndo_dflt_bridge_getlink(skb, pid, seq, dev, -- GitLab From bc23d6b7ab051106b700869e7ee09e8aec6864f2 Mon Sep 17 00:00:00 2001 From: Kalesh Purayil Date: Fri, 10 Jul 2015 05:32:45 -0400 Subject: [PATCH 0699/7006] be2net: remove redundant D0 power state set pci_enable_device() call sets device power state to D0; there is no need doing it again. Signed-off-by: Kalesh AP Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index f21c56abd5c25..8b81e23ae9ba1 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5807,7 +5807,6 @@ static int be_pci_resume(struct pci_dev *pdev) if (status) return status; - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); status = be_resume(adapter); @@ -5887,7 +5886,6 @@ static pci_ers_result_t be_eeh_reset(struct pci_dev *pdev) return PCI_ERS_RESULT_DISCONNECT; pci_set_master(pdev); - pci_set_power_state(pdev, PCI_D0); pci_restore_state(pdev); /* Check if card is ok and fw is ready */ -- GitLab From 887a65c4ab1511a9afc8a20e5507bec3d074f867 Mon Sep 17 00:00:00 2001 From: Vasundhara Volam Date: Fri, 10 Jul 2015 05:32:46 -0400 Subject: [PATCH 0700/7006] be2net: fix wrong return value in be_check_ufi_compatibility() In the commit a6e6ff6eee12f3e ("be2net: simplify UFI compatibility checking"), a return value of "-1" was incorrectly used in place of "false". This patch fixes it. Fixes: a6e6ff6eee12f3e ("be2net: simplify UFI compatibility checking") Signed-off-by: Vasundhara Volam Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 8b81e23ae9ba1..8ef7ea5d8f4a1 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -4918,7 +4918,7 @@ static bool be_check_ufi_compatibility(struct be_adapter *adapter, { if (!fhdr) { dev_err(&adapter->pdev->dev, "Invalid FW UFI file"); - return -1; + return false; } /* First letter of the build version is used to identify -- GitLab From 1645d99768e00d3148ebded5d8c4ab55cdb19a5c Mon Sep 17 00:00:00 2001 From: Venkat Duvvuru Date: Fri, 10 Jul 2015 05:32:47 -0400 Subject: [PATCH 0701/7006] be2net: convert dest field in udp-hdr to host-endian The "dest" field in the UDP-hdr of a TX skb is in network endian format. Convert it to host endian before accessing it. The os2bmc patch, mentioned below introduced this code. Fixes: 760c295e0e8d ("be2net: Support for OS2BMC") Signed-off-by: Venkat Duvvuru Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 8ef7ea5d8f4a1..c996dd76f5461 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1254,7 +1254,7 @@ static bool be_send_pkt_to_bmc(struct be_adapter *adapter, if (is_udp_pkt((*skb))) { struct udphdr *udp = udp_hdr((*skb)); - switch (udp->dest) { + switch (ntohs(udp->dest)) { case DHCP_CLIENT_PORT: os2bmc = is_dhcp_client_filt_enabled(adapter); goto done; -- GitLab From efaa408e964012225897e87d9aad97a4d0ebc1d5 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Fri, 10 Jul 2015 05:32:48 -0400 Subject: [PATCH 0702/7006] be2net: return error status from be_mcc_notify() When the adapter is in error state, return error from be_mcc_notify() so that the caller routines need not sleep waiting for a response. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 39 +++++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 9eac3227d2cab..a299f7bca7ba7 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -88,19 +88,21 @@ static inline void *embedded_payload(struct be_mcc_wrb *wrb) return wrb->payload.embedded_payload; } -static void be_mcc_notify(struct be_adapter *adapter) +static int be_mcc_notify(struct be_adapter *adapter) { struct be_queue_info *mccq = &adapter->mcc_obj.q; u32 val = 0; if (be_check_error(adapter, BE_ERROR_ANY)) - return; + return -EIO; val |= mccq->id & DB_MCCQ_RING_ID_MASK; val |= 1 << DB_MCCQ_NUM_POSTED_SHIFT; wmb(); iowrite32(val, adapter->db + DB_MCCQ_OFFSET); + + return 0; } /* To check if valid bit is set, check the entire word as we don't know @@ -541,7 +543,9 @@ static int be_mcc_notify_wait(struct be_adapter *adapter) resp = be_decode_resp_hdr(wrb->tag0, wrb->tag1); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto out; status = be_mcc_wait_compl(adapter); if (status == -EIO) @@ -1547,7 +1551,10 @@ int be_cmd_get_stats(struct be_adapter *adapter, struct be_dma_mem *nonemb_cmd) else hdr->version = 2; - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err; + adapter->stats_cmd_sent = true; err: @@ -1583,7 +1590,10 @@ int lancer_cmd_get_pport_stats(struct be_adapter *adapter, req->cmd_params.params.pport_num = cpu_to_le16(adapter->hba_port_num); req->cmd_params.params.reset_stats = 0; - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err; + adapter->stats_cmd_sent = true; err: @@ -1687,8 +1697,7 @@ int be_cmd_get_die_temperature(struct be_adapter *adapter) OPCODE_COMMON_GET_CNTL_ADDITIONAL_ATTRIBUTES, sizeof(*req), wrb, NULL); - be_mcc_notify(adapter); - + status = be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; @@ -1860,7 +1869,7 @@ static int __be_cmd_modify_eqd(struct be_adapter *adapter, cpu_to_le32(set_eqd[i].delay_multiplier); } - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; @@ -2320,7 +2329,10 @@ int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd, req->addr_high = cpu_to_le32(upper_32_bits(cmd->dma + sizeof(struct lancer_cmd_req_write_object))); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err_unlock; + spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->et_cmd_compl, @@ -2491,7 +2503,10 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd, req->params.op_code = cpu_to_le32(flash_opcode); req->params.data_buf_size = cpu_to_le32(buf_size); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err_unlock; + spin_unlock_bh(&adapter->mcc_lock); if (!wait_for_completion_timeout(&adapter->et_cmd_compl, @@ -2636,7 +2651,9 @@ int be_cmd_loopback_test(struct be_adapter *adapter, u32 port_num, req->num_pkts = cpu_to_le32(num_pkts); req->loopback_type = cpu_to_le32(loopback_type); - be_mcc_notify(adapter); + status = be_mcc_notify(adapter); + if (status) + goto err; spin_unlock_bh(&adapter->mcc_lock); -- GitLab From 8af65c2f4deeb02a128c5cf29fa351b70bf16424 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Fri, 10 Jul 2015 05:32:49 -0400 Subject: [PATCH 0703/7006] be2net: make the RX_FILTER command asynchronous This fix makes the RX_FILTER cmd asynchronous, i.e., the caller issues this cmd and doesn't wait for a completion from the FW. If the FW/adapter is in an error state, this change helps in not holding up the rtnl_lock and keeping bottom halves disabled while the driver timesout waiting for a response from the FW. Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index a299f7bca7ba7..93934d347a235 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1962,7 +1962,7 @@ static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); } - status = be_mcc_notify_wait(adapter); + status = be_mcc_notify(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; -- GitLab From 9c8559750cd7b7936dd38810fc2110fc91d7d527 Mon Sep 17 00:00:00 2001 From: Suresh Reddy Date: Fri, 10 Jul 2015 05:32:50 -0400 Subject: [PATCH 0704/7006] be2net: make SET_LOOPBACK_MODE cmd asynchrounous The SET_LOOPBACK_MODE command is always issued from ethtool only in a process context. So, while waiting for the cmd to complete, the driver can sleep instead of holding spin_lock_bh() on the mcc_lock. This is done by calling be_mcc_notify() instead of be_mcc_notify_wait() (that returns only after the cmd completes while the MCCQ is locked). Signed-off-by: Suresh Reddy Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 23 ++++++++++++++++--- drivers/net/ethernet/emulex/benet/be_cmds.h | 2 ++ .../net/ethernet/emulex/benet/be_ethtool.c | 15 ++++++++++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 93934d347a235..ecad46f796539 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -172,6 +172,12 @@ static void be_async_cmd_process(struct be_adapter *adapter, return; } + if (opcode == OPCODE_LOWLEVEL_SET_LOOPBACK_MODE && + subsystem == CMD_SUBSYSTEM_LOWLEVEL) { + complete(&adapter->et_cmd_compl); + return; + } + if ((opcode == OPCODE_COMMON_WRITE_FLASHROM || opcode == OPCODE_COMMON_WRITE_OBJECT) && subsystem == CMD_SUBSYSTEM_COMMON) { @@ -2600,7 +2606,7 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, wrb = wrb_from_mccq(adapter); if (!wrb) { status = -EBUSY; - goto err; + goto err_unlock; } req = embedded_payload(wrb); @@ -2614,8 +2620,19 @@ int be_cmd_set_loopback(struct be_adapter *adapter, u8 port_num, req->loopback_type = loopback_type; req->loopback_state = enable; - status = be_mcc_notify_wait(adapter); -err: + status = be_mcc_notify(adapter); + if (status) + goto err_unlock; + + spin_unlock_bh(&adapter->mcc_lock); + + if (!wait_for_completion_timeout(&adapter->et_cmd_compl, + msecs_to_jiffies(SET_LB_MODE_TIMEOUT))) + status = -ETIMEDOUT; + + return status; + +err_unlock: spin_unlock_bh(&adapter->mcc_lock); return status; } diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index f0a92b7e4e7d3..a4479f7488d3c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1495,6 +1495,8 @@ struct be_cmd_resp_acpi_wol_magic_config_v1 { #define BE_PME_D3COLD_CAP 0x80 /********************** LoopBack test *********************/ +#define SET_LB_MODE_TIMEOUT 12000 + struct be_cmd_req_loopback_test { struct be_cmd_req_hdr hdr; u32 loopback_type; diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c index b2476dbfd1031..d20ff054c1f78 100644 --- a/drivers/net/ethernet/emulex/benet/be_ethtool.c +++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c @@ -847,10 +847,21 @@ err: static u64 be_loopback_test(struct be_adapter *adapter, u8 loopback_type, u64 *status) { - be_cmd_set_loopback(adapter, adapter->hba_port_num, loopback_type, 1); + int ret; + + ret = be_cmd_set_loopback(adapter, adapter->hba_port_num, + loopback_type, 1); + if (ret) + return ret; + *status = be_cmd_loopback_test(adapter, adapter->hba_port_num, loopback_type, 1500, 2, 0xabc); - be_cmd_set_loopback(adapter, adapter->hba_port_num, BE_NO_LOOPBACK, 1); + + ret = be_cmd_set_loopback(adapter, adapter->hba_port_num, + BE_NO_LOOPBACK, 1); + if (ret) + return ret; + return *status; } -- GitLab From a78dfcb38492ccc127023e9ee3a35d214009b02f Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Fri, 10 Jul 2015 05:32:51 -0400 Subject: [PATCH 0705/7006] be2net: bump up the driver version to 10.6.0.3 Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 8d12b41b3b199..cb5777bb74292 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -37,7 +37,7 @@ #include "be_hw.h" #include "be_roce.h" -#define DRV_VER "10.6.0.2" +#define DRV_VER "10.6.0.3" #define DRV_NAME "be2net" #define BE_NAME "Emulex BladeEngine2" #define BE3_NAME "Emulex BladeEngine3" -- GitLab From a052158aa981ca470673f49c636b289ee16894ea Mon Sep 17 00:00:00 2001 From: Bartosz Markowski Date: Fri, 3 Jul 2015 15:33:49 +0200 Subject: [PATCH 0706/7006] ath10k: fix QCA61X4 boot up commit a521ee983d312db7 ("ath10k: Add new reg_address/mask to hw register table") broke QCA61x4 support by providing wrong fw_indicator_address, which should have been 0x0003a028 instead of 0x00009028. User experience was a failing boot up sequence (crashing device during initialization): [ 181.663874] ath10k_pci 0000:02:00.0: enabling device (0000 -> 0002) [ 181.664787] ath10k_pci 0000:02:00.0: pci irq msi-x interrupts 8 irq_mode 0 reset_mode 0 [ 181.688886] ath10k_pci 0000:02:00.0: device has crashed during init [ 181.688897] ath10k_pci 0000:02:00.0: failed to wait for target after cold reset: -70 [ 181.688902] ath10k_pci 0000:02:00.0: failed to reset chip: -70 [ 181.689774] ath10k_pci: probe of 0000:02:00.0 failed with error -70 Fix it by updating the address with correct value. Fixes: a521ee983d31 ("ath10k: Add new reg_address/mask to hw register table") Signed-off-by: Bartosz Markowski Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c index 1414e1f3c7ac3..fef7ccf6e185e 100644 --- a/drivers/net/wireless/ath/ath10k/hw.c +++ b/drivers/net/wireless/ath/ath10k/hw.c @@ -63,7 +63,7 @@ const struct ath10k_hw_regs qca6174_regs = { .soc_reset_control_ce_rst_mask = 0x00000001, .soc_chip_id_address = 0x000000f0, .scratch_3_address = 0x00000028, - .fw_indicator_address = 0x00009028, + .fw_indicator_address = 0x0003a028, .pcie_local_base_address = 0x00080000, .ce_wrap_intr_sum_host_msi_lsb = 0x00000008, .ce_wrap_intr_sum_host_msi_mask = 0x0000ff00, -- GitLab From 3c7e256a6de378e01098147527082abae05b146e Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 3 Jul 2015 19:25:27 +0530 Subject: [PATCH 0707/7006] ath10k: Fix target to cpu address conversion logic In commit 418ca5992e2f ("ath10k: Make target cpu address to CE address conversion chip specific") mask 0x7fff is added by mistake instead of 0x7ff. Fix this regression. Fixes: 418ca5992e2f ("ath10k: Make target cpu address to CE address conversion chip specific") Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 1b4634a6374db..5778e5277823c 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -765,7 +765,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr) case ATH10K_HW_QCA6174: val = (ath10k_pci_read32(ar, SOC_CORE_BASE_ADDRESS + CORE_CTRL_ADDRESS) & - 0x7fff) << 21; + 0x7ff) << 21; break; case ATH10K_HW_QCA99X0: val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS); -- GitLab From 835d56a10c1fcfb0fee28bb6aceb722e1a6f643a Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:34 +0200 Subject: [PATCH 0708/7006] ath10k: don't set cck/ofdm scan flags mac80211 already does provide complete IEs for Probe Requests for hw scan and ath10k firmware was appending duplicate Supported Rates IEs unnecessarily. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 --- drivers/net/wireless/ath/ath10k/wmi.c | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 0f3c17c0c8f83..1a3368dc98a15 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4641,9 +4641,6 @@ static int ath10k_hw_scan(struct ieee80211_hw *hw, arg.vdev_id = arvif->vdev_id; arg.scan_id = ATH10K_SCAN_ID; - if (!req->no_cck) - arg.scan_ctrl_flags |= WMI_SCAN_ADD_CCK_RATES; - if (req->ie_len) { arg.ie_len = req->ie_len; memcpy(arg.ie, req->ie, arg.ie_len); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 638332e969319..0791a4336e80f 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -5180,7 +5180,6 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar, | WMI_SCAN_EVENT_BSS_CHANNEL | WMI_SCAN_EVENT_FOREIGN_CHANNEL | WMI_SCAN_EVENT_DEQUEUED; - arg->scan_ctrl_flags |= WMI_SCAN_ADD_OFDM_RATES; arg->scan_ctrl_flags |= WMI_SCAN_CHAN_STAT_EVENT; arg->n_bssids = 1; arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF"; -- GitLab From 424f26301467daf241a4afe4b6fe82750d4ac624 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:35 +0200 Subject: [PATCH 0709/7006] ath10k: limit multi-vif ps more aggresivelly Further testing proved that multi-channel AP+STA on QCA6174 with RM.2.0-00088 should have powersave force-disabled to avoid beacon misses/skipping on either side which in turn could disrupt communication. Since AP never has arvif->ps don't even bother checking it. Other combinations may be broken as well so disallow powersave with multivif outright unless firmware advertises otherwise. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 1a3368dc98a15..c08ad1d994cdc 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -1668,7 +1668,7 @@ static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif) return 0; } -static int ath10k_mac_ps_vif_count(struct ath10k *ar) +static int ath10k_mac_num_vifs_started(struct ath10k *ar) { struct ath10k_vif *arvif; int num = 0; @@ -1676,7 +1676,7 @@ static int ath10k_mac_ps_vif_count(struct ath10k *ar) lockdep_assert_held(&ar->conf_mutex); list_for_each_entry(arvif, &ar->arvifs, list) - if (arvif->ps) + if (arvif->is_started) num++; return num; @@ -1700,7 +1700,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif) enable_ps = arvif->ps; - if (enable_ps && ath10k_mac_ps_vif_count(ar) > 1 && + if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 && !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT, ar->fw_features)) { ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n", -- GitLab From d710e75d1050cb66fbf6e906addb4a661e444729 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:36 +0200 Subject: [PATCH 0710/7006] ath10k: fix hw roc expiration notifcation The expiration function must not be called when roc is explicitly cancelled by mac80211. However since fcf9844636be ("ath10k: fix hw roc expiration") the notification was never sent when roc actually expired. This fixes some P2P connection setup issues. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/mac.c | 12 +++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 2e5c935579c46..78e07051b8970 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -633,6 +633,7 @@ struct ath10k { bool is_roc; int vdev_id; int roc_freq; + bool roc_notify; } scan; struct { diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c08ad1d994cdc..b842612e0b619 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3449,14 +3449,13 @@ void __ath10k_scan_finish(struct ath10k *ar) case ATH10K_SCAN_IDLE: break; case ATH10K_SCAN_RUNNING: - if (ar->scan.is_roc) - ieee80211_remain_on_channel_expired(ar->hw); - /* fall through */ case ATH10K_SCAN_ABORTING: if (!ar->scan.is_roc) ieee80211_scan_completed(ar->hw, (ar->scan.state == ATH10K_SCAN_ABORTING)); + else if (ar->scan.roc_notify) + ieee80211_remain_on_channel_expired(ar->hw); /* fall through */ case ATH10K_SCAN_STARTING: ar->scan.state = ATH10K_SCAN_IDLE; @@ -5459,6 +5458,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw, ar->scan.is_roc = true; ar->scan.vdev_id = arvif->vdev_id; ar->scan.roc_freq = chan->center_freq; + ar->scan.roc_notify = true; ret = 0; break; case ATH10K_SCAN_STARTING: @@ -5522,7 +5522,13 @@ static int ath10k_cancel_remain_on_channel(struct ieee80211_hw *hw) struct ath10k *ar = hw->priv; mutex_lock(&ar->conf_mutex); + + spin_lock_bh(&ar->data_lock); + ar->scan.roc_notify = false; + spin_unlock_bh(&ar->data_lock); + ath10k_scan_abort(ar); + mutex_unlock(&ar->conf_mutex); cancel_delayed_work_sync(&ar->scan.timeout); -- GitLab From f23e587e55f3607741e29a789efa61ea999f13f8 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:37 +0200 Subject: [PATCH 0711/7006] ath10k: update vdev ps state on start Psmode can be forcefully enabled when vdev isn't started. It isn't guaranteed that mac80211 will re-issue psmode setting after vdev is started unless actual bss_conf.ps value has changed. Even if this doesn't fix any problems now it may prevent future breakage. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b842612e0b619..8049d77cfc350 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6222,6 +6222,13 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, arvif->is_started = true; + ret = ath10k_mac_vif_setup_ps(arvif); + if (ret) { + ath10k_warn(ar, "failed to update vdev %i ps: %d\n", + arvif->vdev_id, ret); + goto err_stop; + } + if (vif->type == NL80211_IFTYPE_MONITOR) { ret = ath10k_wmi_vdev_up(ar, arvif->vdev_id, 0, vif->addr); if (ret) { @@ -6239,6 +6246,7 @@ ath10k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw, err_stop: ath10k_vdev_stop(arvif); arvif->is_started = false; + ath10k_mac_vif_setup_ps(arvif); err: mutex_unlock(&ar->conf_mutex); -- GitLab From acd0b27bb13a09dd0a56d4562d3eb4137a7318b2 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:38 +0200 Subject: [PATCH 0712/7006] ath10k: fix per-vif queue locking Whenever any vdev was supposed to be paused all Tx queues were stopped (except offchannel) instead of only these associated with the given vdev. This caused subtle issues with multi-channel/multi-vif scenarios, e.g. authentication of station vif could sometimes fail depending on fw tx pause request timing. Fixes: b4aa539dd8f2 ("ath10k: implement tx pause wmi event") Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 47 +++++++---------------- drivers/net/wireless/ath/ath10k/mac.h | 6 +-- drivers/net/wireless/ath/ath10k/wmi-tlv.c | 34 +++++++++++++--- 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 8049d77cfc350..b2e3fe9a9caeb 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -3034,38 +3034,16 @@ static void ath10k_mac_vif_handle_tx_pause(struct ath10k_vif *arvif, lockdep_assert_held(&ar->htt.tx_lock); - switch (pause_id) { - case WMI_TLV_TX_PAUSE_ID_MCC: - case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: - case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: - case WMI_TLV_TX_PAUSE_ID_AP_PS: - case WMI_TLV_TX_PAUSE_ID_IBSS_PS: - switch (action) { - case WMI_TLV_TX_PAUSE_ACTION_STOP: - ath10k_mac_vif_tx_lock(arvif, pause_id); - break; - case WMI_TLV_TX_PAUSE_ACTION_WAKE: - ath10k_mac_vif_tx_unlock(arvif, pause_id); - break; - default: - ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", - action, arvif->vdev_id); - break; - } + switch (action) { + case WMI_TLV_TX_PAUSE_ACTION_STOP: + ath10k_mac_vif_tx_lock(arvif, pause_id); + break; + case WMI_TLV_TX_PAUSE_ACTION_WAKE: + ath10k_mac_vif_tx_unlock(arvif, pause_id); break; - case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: - case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: - case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: - case WMI_TLV_TX_PAUSE_ID_HOST: default: - /* FIXME: Some pause_ids aren't vdev specific. Instead they - * target peer_id and tid. Implementing these could improve - * traffic scheduling fairness across multiple connected - * stations in AP/IBSS modes. - */ - ath10k_dbg(ar, ATH10K_DBG_MAC, - "mac ignoring unsupported tx pause vdev %i id %d\n", - arvif->vdev_id, pause_id); + ath10k_warn(ar, "received unknown tx pause action %d on vdev %i, ignoring\n", + action, arvif->vdev_id); break; } } @@ -3082,12 +3060,15 @@ static void ath10k_mac_handle_tx_pause_iter(void *data, u8 *mac, struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif); struct ath10k_mac_tx_pause *arg = data; + if (arvif->vdev_id != arg->vdev_id) + return; + ath10k_mac_vif_handle_tx_pause(arvif, arg->pause_id, arg->action); } -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, - enum wmi_tlv_tx_pause_id pause_id, - enum wmi_tlv_tx_pause_action action) +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, + enum wmi_tlv_tx_pause_id pause_id, + enum wmi_tlv_tx_pause_action action) { struct ath10k_mac_tx_pause arg = { .vdev_id = vdev_id, diff --git a/drivers/net/wireless/ath/ath10k/mac.h b/drivers/net/wireless/ath/ath10k/mac.h index b291f063705c3..e3cefe4c7cfd0 100644 --- a/drivers/net/wireless/ath/ath10k/mac.h +++ b/drivers/net/wireless/ath/ath10k/mac.h @@ -61,9 +61,9 @@ int ath10k_mac_vif_chan(struct ieee80211_vif *vif, void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb); void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id); -void ath10k_mac_handle_tx_pause(struct ath10k *ar, u32 vdev_id, - enum wmi_tlv_tx_pause_id pause_id, - enum wmi_tlv_tx_pause_action action); +void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id, + enum wmi_tlv_tx_pause_id pause_id, + enum wmi_tlv_tx_pause_action action); u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband, u8 hw_rate); diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c index ced35a1e06750..4189d4a90ce0a 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c @@ -377,12 +377,34 @@ static int ath10k_wmi_tlv_event_tx_pause(struct ath10k *ar, "wmi tlv tx pause pause_id %u action %u vdev_map 0x%08x peer_id %u tid_map 0x%08x\n", pause_id, action, vdev_map, peer_id, tid_map); - for (vdev_id = 0; vdev_map; vdev_id++) { - if (!(vdev_map & BIT(vdev_id))) - continue; - - vdev_map &= ~BIT(vdev_id); - ath10k_mac_handle_tx_pause(ar, vdev_id, pause_id, action); + switch (pause_id) { + case WMI_TLV_TX_PAUSE_ID_MCC: + case WMI_TLV_TX_PAUSE_ID_P2P_CLI_NOA: + case WMI_TLV_TX_PAUSE_ID_P2P_GO_PS: + case WMI_TLV_TX_PAUSE_ID_AP_PS: + case WMI_TLV_TX_PAUSE_ID_IBSS_PS: + for (vdev_id = 0; vdev_map; vdev_id++) { + if (!(vdev_map & BIT(vdev_id))) + continue; + + vdev_map &= ~BIT(vdev_id); + ath10k_mac_handle_tx_pause_vdev(ar, vdev_id, pause_id, + action); + } + break; + case WMI_TLV_TX_PAUSE_ID_AP_PEER_PS: + case WMI_TLV_TX_PAUSE_ID_AP_PEER_UAPSD: + case WMI_TLV_TX_PAUSE_ID_STA_ADD_BA: + case WMI_TLV_TX_PAUSE_ID_HOST: + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac ignoring unsupported tx pause id %d\n", + pause_id); + break; + default: + ath10k_dbg(ar, ATH10K_DBG_MAC, + "mac ignoring unknown tx pause vdev %d\n", + pause_id); + break; } kfree(tb); -- GitLab From ed25b113a955e62aeaba49a3ec71faea4f25bf34 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 13:08:39 +0200 Subject: [PATCH 0713/7006] ath10k: tweak interface combinations Concurrent AP/GO operation on different channels isn't really supported well by the firmware so it's better to remove it from being advertised. Also tune the way station and p2p client interface limits are expressed to allow station + 2x p2p client or station + p2p client + p2p go. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 39 +++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index b2e3fe9a9caeb..caa56ce5d9073 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -6557,8 +6557,11 @@ static const struct ieee80211_iface_combination ath10k_10x_if_comb[] = { static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { { .max = 2, - .types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP) | + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO), }, @@ -6568,6 +6571,26 @@ static const struct ieee80211_iface_limit ath10k_tlv_if_limit[] = { }, }; +static const struct ieee80211_iface_limit ath10k_tlv_qcs_if_limit[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 2, + .types = BIT(NL80211_IFTYPE_P2P_CLIENT), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_P2P_DEVICE), + }, +}; + static const struct ieee80211_iface_limit ath10k_tlv_if_limit_ibss[] = { { .max = 1, @@ -6586,7 +6609,7 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { { .limits = ath10k_tlv_if_limit, .num_different_channels = 1, - .max_interfaces = 3, + .max_interfaces = 4, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), }, { @@ -6600,10 +6623,16 @@ static struct ieee80211_iface_combination ath10k_tlv_if_comb[] = { static struct ieee80211_iface_combination ath10k_tlv_qcs_if_comb[] = { { .limits = ath10k_tlv_if_limit, - .num_different_channels = 2, - .max_interfaces = 3, + .num_different_channels = 1, + .max_interfaces = 4, .n_limits = ARRAY_SIZE(ath10k_tlv_if_limit), }, + { + .limits = ath10k_tlv_qcs_if_limit, + .num_different_channels = 2, + .max_interfaces = 4, + .n_limits = ARRAY_SIZE(ath10k_tlv_qcs_if_limit), + }, { .limits = ath10k_tlv_if_limit_ibss, .num_different_channels = 1, -- GitLab From 75509fd88fbd580c793780b0001c71c3510f2726 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sun, 24 May 2015 12:49:04 -0500 Subject: [PATCH 0714/7006] nsfs: Add a show_path method to fix mountinfo Today mountinfo displays a very unhelpful "/" for nsfs files. Add a show_path method returning the same string as ns_dname. This results in a bind mount of /proc//ns/net showing up in /proc//mountinfo as "net:[1234...]" instead of "/". Signed-off-by: "Eric W. Biederman" --- fs/nsfs.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/nsfs.c b/fs/nsfs.c index 99521e7c492b0..e4905fbf33969 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -4,6 +4,7 @@ #include #include #include +#include static struct vfsmount *nsfs_mnt; @@ -136,9 +137,18 @@ out_invalid: return ERR_PTR(-EINVAL); } +static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry) +{ + struct inode *inode = d_inode(dentry); + const struct proc_ns_operations *ns_ops = dentry->d_fsdata; + + return seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); +} + static const struct super_operations nsfs_ops = { .statfs = simple_statfs, .evict_inode = nsfs_evict, + .show_path = nsfs_show_path, }; static struct dentry *nsfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) -- GitLab From 00798c38f49eb028b0c5fac01293783206af29fb Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Mon, 15 Jun 2015 19:24:35 +0200 Subject: [PATCH 0715/7006] ipw2100: fix timeout bug - always evaluated to 0 commit 2c86c275015c ("Add ipw2100 wireless driver.") introduced HW_PHY_OFF_LOOP_DELAY (HZ / 5000) which always evaluated to 0. Clarified by Stanislav Yakovlev that it should be 50 milliseconds thus fixed up to msecs_to_jiffies(50). Signed-off-by: Nicholas Mc Guire Acked-by: Stanislav Yakovlev Signed-off-by: Kalle Valo --- drivers/net/wireless/ipw2x00/ipw2100.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ipw2x00/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c index 08eb229e78160..36818c7f30b96 100644 --- a/drivers/net/wireless/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -1410,7 +1410,7 @@ static int ipw2100_power_cycle_adapter(struct ipw2100_priv *priv) static int ipw2100_hw_phy_off(struct ipw2100_priv *priv) { -#define HW_PHY_OFF_LOOP_DELAY (HZ / 5000) +#define HW_PHY_OFF_LOOP_DELAY (msecs_to_jiffies(50)) struct host_command cmd = { .host_command = CARD_DISABLE_PHY_OFF, -- GitLab From 8f010d9ca88f9023650b2e54b74c84ab63a19d02 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 11:46:42 +0200 Subject: [PATCH 0716/7006] ath9k: DFS - consider ext_channel pulses only in HT40 mode The chip reports radar pulses on extension channel even if operating in HT20 mode. This patch adds a sanity check for HT40 mode before it feeds pulses on extension channel to the pattern detector. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index e98a9eaba7ff3..5025a4e91a8bd 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -198,7 +198,8 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, sc->dfs_prev_pulse_ts = pe.ts; if (ard.pulse_bw_info & PRI_CH_RADAR_FOUND) ath9k_dfs_process_radar_pulse(sc, &pe); - if (ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { + if (IS_CHAN_HT40(ah->curchan) && + ard.pulse_bw_info & EXT_CH_RADAR_FOUND) { pe.freq += IS_CHAN_HT40PLUS(ah->curchan) ? 20 : -20; ath9k_dfs_process_radar_pulse(sc, &pe); } -- GitLab From 8fc2b61a36fe17f744b445a26599a6cac9e6c1c0 Mon Sep 17 00:00:00 2001 From: Zefir Kurtisi Date: Tue, 16 Jun 2015 12:52:16 +0200 Subject: [PATCH 0717/7006] ath9k: DFS - add pulse chirp detection for FCC FCC long pulse radar (type 5) requires pulses to be checked for chirping. This patch implements chirp detection based on the FFT data provided for long pulses. A chirp is detected when a set of criteria defined by FCC pulse characteristics is met, including * have at least 4 FFT samples * max_bin index moves equidistantly between samples * the gradient is within defined range The chirp detection has been tested with reference radar generating devices and proved to work reliably. Signed-off-by: Zefir Kurtisi Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/dfs.c | 167 ++++++++++++++++++++++++++- 1 file changed, 161 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/dfs.c b/drivers/net/wireless/ath/ath9k/dfs.c index 5025a4e91a8bd..1ece42c2443d7 100644 --- a/drivers/net/wireless/ath/ath9k/dfs.c +++ b/drivers/net/wireless/ath/ath9k/dfs.c @@ -30,6 +30,157 @@ struct ath_radar_data { u8 pulse_length_pri; }; +/**** begin: CHIRP ************************************************************/ + +/* min and max gradients for defined FCC chirping pulses, given by + * - 20MHz chirp width over a pulse width of 50us + * - 5MHz chirp width over a pulse width of 100us + */ +static const int BIN_DELTA_MIN = 1; +static const int BIN_DELTA_MAX = 10; + +/* we need at least 3 deltas / 4 samples for a reliable chirp detection */ +#define NUM_DIFFS 3 +static const int FFT_NUM_SAMPLES = (NUM_DIFFS + 1); + +/* Threshold for difference of delta peaks */ +static const int MAX_DIFF = 2; + +/* width range to be checked for chirping */ +static const int MIN_CHIRP_PULSE_WIDTH = 20; +static const int MAX_CHIRP_PULSE_WIDTH = 110; + +struct ath9k_dfs_fft_20 { + u8 bin[28]; + u8 lower_bins[3]; +} __packed; +struct ath9k_dfs_fft_40 { + u8 bin[64]; + u8 lower_bins[3]; + u8 upper_bins[3]; +} __packed; + +static inline int fft_max_index(u8 *bins) +{ + return (bins[2] & 0xfc) >> 2; +} +static inline int fft_max_magnitude(u8 *bins) +{ + return (bins[0] & 0xc0) >> 6 | bins[1] << 2 | (bins[2] & 0x03) << 10; +} +static inline u8 fft_bitmap_weight(u8 *bins) +{ + return bins[0] & 0x3f; +} + +static int ath9k_get_max_index_ht40(struct ath9k_dfs_fft_40 *fft, + bool is_ctl, bool is_ext) +{ + const int DFS_UPPER_BIN_OFFSET = 64; + /* if detected radar on both channels, select the significant one */ + if (is_ctl && is_ext) { + /* first check wether channels have 'strong' bins */ + is_ctl = fft_bitmap_weight(fft->lower_bins) != 0; + is_ext = fft_bitmap_weight(fft->upper_bins) != 0; + + /* if still unclear, take higher magnitude */ + if (is_ctl && is_ext) { + int mag_lower = fft_max_magnitude(fft->lower_bins); + int mag_upper = fft_max_magnitude(fft->upper_bins); + if (mag_upper > mag_lower) + is_ctl = false; + else + is_ext = false; + } + } + if (is_ctl) + return fft_max_index(fft->lower_bins); + return fft_max_index(fft->upper_bins) + DFS_UPPER_BIN_OFFSET; +} +static bool ath9k_check_chirping(struct ath_softc *sc, u8 *data, + int datalen, bool is_ctl, bool is_ext) +{ + int i; + int max_bin[FFT_NUM_SAMPLES]; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + int prev_delta; + + if (IS_CHAN_HT40(ah->curchan)) { + struct ath9k_dfs_fft_40 *fft = (struct ath9k_dfs_fft_40 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + + ath_dbg(common, DFS, "HT40: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < (FFT_NUM_SAMPLES)) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* HW sometimes adds 2 garbage bytes in front of FFT samples */ + if ((datalen % sizeof(*fft)) == 2) { + fft = (struct ath9k_dfs_fft_40 *) (data + 2); + ath_dbg(common, DFS, "fixing datalen by 2\n"); + } + if (IS_CHAN_HT40MINUS(ah->curchan)) { + int temp = is_ctl; + is_ctl = is_ext; + is_ext = temp; + } + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = ath9k_get_max_index_ht40(fft + i, is_ctl, + is_ext); + } else { + struct ath9k_dfs_fft_20 *fft = (struct ath9k_dfs_fft_20 *) data; + int num_fft_packets = datalen / sizeof(*fft); + if (num_fft_packets == 0) + return false; + ath_dbg(common, DFS, "HT20: datalen=%d, num_fft_packets=%d\n", + datalen, num_fft_packets); + if (num_fft_packets < (FFT_NUM_SAMPLES)) { + ath_dbg(common, DFS, "not enough packets for chirp\n"); + return false; + } + /* in ht20, this is a 6-bit signed number => shift it to 0 */ + for (i = 0; i < FFT_NUM_SAMPLES; i++) + max_bin[i] = fft_max_index(fft[i].lower_bins) ^ 0x20; + } + ath_dbg(common, DFS, "bin_max = [%d, %d, %d, %d]\n", + max_bin[0], max_bin[1], max_bin[2], max_bin[3]); + + /* Check for chirp attributes within specs + * a) delta of adjacent max_bins is within range + * b) delta of adjacent deltas are within tolerance + */ + prev_delta = 0; + for (i = 0; i < NUM_DIFFS; i++) { + int ddelta = -1; + int delta = max_bin[i + 1] - max_bin[i]; + + /* ensure gradient is within valid range */ + if (abs(delta) < BIN_DELTA_MIN || abs(delta) > BIN_DELTA_MAX) { + ath_dbg(common, DFS, "CHIRP: invalid delta %d " + "in sample %d\n", delta, i); + return false; + } + if (i == 0) + goto done; + ddelta = delta - prev_delta; + if (abs(ddelta) > MAX_DIFF) { + ath_dbg(common, DFS, "CHIRP: ddelta %d too high\n", + ddelta); + return false; + } +done: + ath_dbg(common, DFS, "CHIRP - %d: delta=%d, ddelta=%d\n", + i, delta, ddelta); + prev_delta = delta; + } + return true; +} +/**** end: CHIRP **************************************************************/ + /* convert pulse duration to usecs, considering clock mode */ static u32 dur_to_usecs(struct ath_hw *ah, u32 dur) { @@ -113,12 +264,6 @@ ath9k_postprocess_radar_event(struct ath_softc *sc, return false; } - /* - * TODO: check chirping pulses - * checks for chirping are dependent on the DFS regulatory domain - * used, which is yet TBD - */ - /* convert duration to usecs */ pe->width = dur_to_usecs(sc->sc_ah, dur); pe->rssi = rssi; @@ -190,6 +335,16 @@ void ath9k_dfs_process_phyerr(struct ath_softc *sc, void *data, if (!ath9k_postprocess_radar_event(sc, &ard, &pe)) return; + if (pe.width > MIN_CHIRP_PULSE_WIDTH && + pe.width < MAX_CHIRP_PULSE_WIDTH) { + bool is_ctl = !!(ard.pulse_bw_info & PRI_CH_RADAR_FOUND); + bool is_ext = !!(ard.pulse_bw_info & EXT_CH_RADAR_FOUND); + int clen = datalen - 3; + pe.chirp = ath9k_check_chirping(sc, data, clen, is_ctl, is_ext); + } else { + pe.chirp = false; + } + ath_dbg(common, DFS, "ath9k_dfs_process_phyerr: type=%d, freq=%d, ts=%llu, " "width=%d, rssi=%d, delta_ts=%llu\n", -- GitLab From f61fd21dea1b9b40edfab07bdcd60d6a3bd95ba1 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 14:45:25 -0700 Subject: [PATCH 0718/7006] Input: of_touchscreen - always issue warning if axis is not set up Do issue warning about axis that is present in device tree but not specified by the driver even in case of multi-touch axis as callers now tell us if they expect multi-touch data or not. Reviewed-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/of_touchscreen.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 806cd0ad160f9..759cf4b8ba096 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -39,13 +39,9 @@ static void touchscreen_set_params(struct input_dev *dev, struct input_absinfo *absinfo; if (!test_bit(axis, dev->absbit)) { - /* - * Emit a warning only if the axis is not a multitouch - * axis, which might not be set by the driver. - */ - if (!input_is_mt_axis(axis)) - dev_warn(&dev->dev, - "DT specifies parameters but the axis is not set up\n"); + dev_warn(&dev->dev, + "DT specifies parameters but the axis %lu is not set up\n", + axis); return; } -- GitLab From 517178692ccd730a95b278bd8cd67e11498a9a84 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 14:57:54 -0700 Subject: [PATCH 0719/7006] Input: of_touchscreen - fix setting max values on X/Y axis The binding specification says that "touchscreen-size-x" and "-y" specify horizontal and vertical resolution of the touchscreen and therefore maximum absolute coordinates should be reduced by 1 since we are starting with 0. Reviewed-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/of_touchscreen.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 759cf4b8ba096..50bc0f219547a 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -71,23 +71,25 @@ void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) axis = multitouch ? ABS_MT_POSITION_X : ABS_X; data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", - input_abs_get_max(dev, axis), + input_abs_get_max(dev, + axis) + 1, &maximum) | touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", input_abs_get_fuzz(dev, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(dev, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", - input_abs_get_max(dev, axis), + input_abs_get_max(dev, + axis) + 1, &maximum) | touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", input_abs_get_fuzz(dev, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(dev, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", -- GitLab From 4200e831e4a8fd09fa4e78de2e571ab270c12d06 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 15:18:24 -0700 Subject: [PATCH 0720/7006] Input: of_touchscreen - switch to using device properties Let's switch form OF to device properties so that common parsing code could work not only on device tree but also on ACPI-based platforms. Reviewed-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 4 +- drivers/input/touchscreen/Makefile | 2 +- drivers/input/touchscreen/edt-ft5x06.c | 2 +- drivers/input/touchscreen/of_touchscreen.c | 56 ++++++++++++---------- drivers/input/touchscreen/tsc2005.c | 2 +- include/linux/input/touchscreen.h | 11 +---- 6 files changed, 37 insertions(+), 40 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index aa2b5f21b89b4..27035ecbd4f5c 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,9 +11,9 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN -config OF_TOUCHSCREEN +config TOUCHSCREEN_PROPERTIES def_tristate INPUT - depends on INPUT && OF + depends on INPUT config TOUCHSCREEN_88PM860X tristate "Marvell 88PM860x touchscreen" diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index fa3d33bac7fc0..c85aae23e7f84 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -6,7 +6,7 @@ wm97xx-ts-y := wm97xx-core.o -obj-$(CONFIG_OF_TOUCHSCREEN) += of_touchscreen.o +obj-$(CONFIG_TOUCHSCREEN_PROPERTIES) += of_touchscreen.o obj-$(CONFIG_TOUCHSCREEN_88PM860X) += 88pm860x-ts.o obj-$(CONFIG_TOUCHSCREEN_AD7877) += ad7877.o obj-$(CONFIG_TOUCHSCREEN_AD7879) += ad7879.o diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 394b1de9a2a3f..8f8f3199be394 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1041,7 +1041,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client, 0, tsdata->num_y * 64 - 1, 0, 0); if (!pdata) - touchscreen_parse_of_params(input, true); + touchscreen_parse_properties(input, true); error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, INPUT_MT_DIRECT); if (error) { diff --git a/drivers/input/touchscreen/of_touchscreen.c b/drivers/input/touchscreen/of_touchscreen.c index 50bc0f219547a..bb6f2fe146672 100644 --- a/drivers/input/touchscreen/of_touchscreen.c +++ b/drivers/input/touchscreen/of_touchscreen.c @@ -9,12 +9,12 @@ * */ -#include +#include #include #include #include -static bool touchscreen_get_prop_u32(struct device_node *np, +static bool touchscreen_get_prop_u32(struct device *dev, const char *property, unsigned int default_value, unsigned int *value) @@ -22,7 +22,7 @@ static bool touchscreen_get_prop_u32(struct device_node *np, u32 val; int error; - error = of_property_read_u32(np, property, &val); + error = device_property_read_u32(dev, property, &val); if (error) { *value = default_value; return false; @@ -51,54 +51,58 @@ static void touchscreen_set_params(struct input_dev *dev, } /** - * touchscreen_parse_of_params - parse common touchscreen DT properties - * @dev: device that should be parsed + * touchscreen_parse_properties - parse common touchscreen DT properties + * @input: input device that should be parsed + * @multitouch: specifies whether parsed properties should be applied to + * single-touch or multi-touch axes * * This function parses common DT properties for touchscreens and setups the - * input device accordingly. The function keeps previously setuped default + * input device accordingly. The function keeps previously set up default * values if no value is specified via DT. */ -void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch) +void touchscreen_parse_properties(struct input_dev *input, bool multitouch) { - struct device_node *np = dev->dev.parent->of_node; + struct device *dev = input->dev.parent; unsigned int axis; unsigned int maximum, fuzz; bool data_present; - input_alloc_absinfo(dev); - if (!dev->absinfo) + input_alloc_absinfo(input); + if (!input->absinfo) return; axis = multitouch ? ABS_MT_POSITION_X : ABS_X; - data_present = touchscreen_get_prop_u32(np, "touchscreen-size-x", - input_abs_get_max(dev, + data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-x", + input_abs_get_max(input, axis) + 1, &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-x", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, "touchscreen-fuzz-x", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum - 1, fuzz); + touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_POSITION_Y : ABS_Y; - data_present = touchscreen_get_prop_u32(np, "touchscreen-size-y", - input_abs_get_max(dev, + data_present = touchscreen_get_prop_u32(dev, "touchscreen-size-y", + input_abs_get_max(input, axis) + 1, &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-y", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, "touchscreen-fuzz-y", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum - 1, fuzz); + touchscreen_set_params(input, axis, maximum - 1, fuzz); axis = multitouch ? ABS_MT_PRESSURE : ABS_PRESSURE; - data_present = touchscreen_get_prop_u32(np, "touchscreen-max-pressure", - input_abs_get_max(dev, axis), + data_present = touchscreen_get_prop_u32(dev, + "touchscreen-max-pressure", + input_abs_get_max(input, axis), &maximum) | - touchscreen_get_prop_u32(np, "touchscreen-fuzz-pressure", - input_abs_get_fuzz(dev, axis), + touchscreen_get_prop_u32(dev, + "touchscreen-fuzz-pressure", + input_abs_get_fuzz(input, axis), &fuzz); if (data_present) - touchscreen_set_params(dev, axis, maximum, fuzz); + touchscreen_set_params(input, axis, maximum, fuzz); } -EXPORT_SYMBOL(touchscreen_parse_of_params); +EXPORT_SYMBOL(touchscreen_parse_properties); diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index d8c025b0f88cd..aaf947525cd96 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -709,7 +709,7 @@ static int tsc2005_probe(struct spi_device *spi) input_set_abs_params(input_dev, ABS_PRESSURE, 0, max_p, fudge_p, 0); if (np) - touchscreen_parse_of_params(input_dev, false); + touchscreen_parse_properties(input_dev, false); input_dev->open = tsc2005_open; input_dev->close = tsc2005_close; diff --git a/include/linux/input/touchscreen.h b/include/linux/input/touchscreen.h index eecc9ea6cd587..c91e1376132b6 100644 --- a/include/linux/input/touchscreen.h +++ b/include/linux/input/touchscreen.h @@ -9,15 +9,8 @@ #ifndef _TOUCHSCREEN_H #define _TOUCHSCREEN_H -#include +struct input_dev; -#ifdef CONFIG_OF -void touchscreen_parse_of_params(struct input_dev *dev, bool multitouch); -#else -static inline void touchscreen_parse_of_params(struct input_dev *dev, - bool multitouch) -{ -} -#endif +void touchscreen_parse_properties(struct input_dev *dev, bool multitouch); #endif -- GitLab From 28a74c050060c17b1edaee2d60470a33be476941 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 11:48:47 -0700 Subject: [PATCH 0721/7006] Input: pixcir_i2c_ts - move platform data Let's move driver's platform data definitions from include/linux/input/ into include/linux/platform_data/ so that it stays with the rest of platform data definitions. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 2 +- .../linux/{input/pixcir_ts.h => platform_data/pixcir_i2c_ts.h} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename include/linux/{input/pixcir_ts.h => platform_data/pixcir_i2c_ts.h} (100%) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 2c2107147319e..f7d90997a7866 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,11 +24,11 @@ #include #include #include -#include #include #include #include #include +#include #define PIXCIR_MAX_SLOTS 5 /* Max fingers supported by driver */ diff --git a/include/linux/input/pixcir_ts.h b/include/linux/platform_data/pixcir_i2c_ts.h similarity index 100% rename from include/linux/input/pixcir_ts.h rename to include/linux/platform_data/pixcir_i2c_ts.h -- GitLab From cb4a5f068096c0cea954f363e70020aabb3555f4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 11:56:21 -0700 Subject: [PATCH 0722/7006] Input: pixcir_i2c_ts - switch the device over to gpiod This allows uniform parsing on legacy, DT and ACPI systems. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 26 +++++++-------------- include/linux/platform_data/pixcir_i2c_ts.h | 1 - 2 files changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index f7d90997a7866..19732b573227d 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include @@ -35,6 +35,7 @@ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; + struct gpio_desc *gpio_attb; const struct pixcir_ts_platform_data *pdata; bool running; int max_fingers; /* Max fingers supported in this instance */ @@ -161,7 +162,6 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) { struct pixcir_i2c_ts_data *tsdata = dev_id; - const struct pixcir_ts_platform_data *pdata = tsdata->pdata; struct pixcir_report_data report; while (tsdata->running) { @@ -171,7 +171,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) /* report it */ pixcir_ts_report(tsdata, &report); - if (gpio_get_value(pdata->gpio_attb)) { + if (gpiod_get_value(tsdata->gpio_attb)) { if (report.num_touches) { /* * Last report with no finger up? @@ -427,9 +427,6 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data; - pdata->gpio_attb = of_get_named_gpio(np, "attb-gpio", 0); - /* gpio_attb validity is checked in probe */ - if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) { dev_err(dev, "Failed to get touchscreen-size-x property\n"); return ERR_PTR(-EINVAL); @@ -442,8 +439,8 @@ static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) } pdata->y_max -= 1; - dev_dbg(dev, "%s: x %d, y %d, gpio %d\n", __func__, - pdata->x_max + 1, pdata->y_max + 1, pdata->gpio_attb); + dev_dbg(dev, "%s: x %d, y %d\n", __func__, + pdata->x_max + 1, pdata->y_max + 1); return pdata; } @@ -476,11 +473,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return -EINVAL; } - if (!gpio_is_valid(pdata->gpio_attb)) { - dev_err(dev, "Invalid gpio_attb in pdata\n"); - return -EINVAL; - } - if (!pdata->chip.max_fingers) { dev_err(dev, "Invalid max_fingers in pdata\n"); return -EINVAL; @@ -530,10 +522,10 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input_set_drvdata(input, tsdata); - error = devm_gpio_request_one(dev, pdata->gpio_attb, - GPIOF_DIR_IN, "pixcir_i2c_attb"); - if (error) { - dev_err(dev, "Failed to request ATTB gpio\n"); + tsdata->gpio_attb = devm_gpiod_get(dev, "attb", GPIOD_IN); + if (IS_ERR(tsdata->gpio_attb)) { + error = PTR_ERR(tsdata->gpio_attb); + dev_err(dev, "Failed to request ATTB gpio: %d\n", error); return error; } diff --git a/include/linux/platform_data/pixcir_i2c_ts.h b/include/linux/platform_data/pixcir_i2c_ts.h index 7bae83b7c396e..646af6f8b838e 100644 --- a/include/linux/platform_data/pixcir_i2c_ts.h +++ b/include/linux/platform_data/pixcir_i2c_ts.h @@ -57,7 +57,6 @@ struct pixcir_i2c_chip_data { struct pixcir_ts_platform_data { int x_max; int y_max; - int gpio_attb; /* GPIO connected to ATTB line */ struct pixcir_i2c_chip_data chip; }; -- GitLab From 127520caebd9ae1b77c7026bf538a81b8fcd19a8 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 13:27:00 -0700 Subject: [PATCH 0723/7006] Input: pixcir_i2c_ts - allow using with GPIO expanders We are using threaded interrupt handler and thus are allowed to sleep. Let's switch over to gpiod_get_value_cansleep() so that we do not get ugly warnings in case GPIO controller might sleep when accessing GPIO. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 19732b573227d..5330c04465400 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -171,7 +171,7 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) /* report it */ pixcir_ts_report(tsdata, &report); - if (gpiod_get_value(tsdata->gpio_attb)) { + if (gpiod_get_value_cansleep(tsdata->gpio_attb)) { if (report.num_touches) { /* * Last report with no finger up? -- GitLab From 40929167e6e8450a06501d292c5e5c81455d1c47 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 6 Jul 2015 13:27:43 -0700 Subject: [PATCH 0724/7006] Input: pixcir_i2c_ts - add RESET gpio The controller has a RESET pin which is usually controlled over a GPIO line. If such a GPIO is provided, perform a RESET during probe. Signed-off-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/pixcir_i2c_ts.txt | 3 +++ drivers/input/touchscreen/pixcir_i2c_ts.c | 22 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt index 6e551090f4653..8eb240a287c8a 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/pixcir_i2c_ts.txt @@ -8,6 +8,9 @@ Required properties: - touchscreen-size-x: horizontal resolution of touchscreen (in pixels) - touchscreen-size-y: vertical resolution of touchscreen (in pixels) +Optional properties: +- reset-gpio: GPIO connected to the RESET line of the chip + Example: i2c@00000000 { diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 5330c04465400..a5a83139aad05 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -36,6 +36,7 @@ struct pixcir_i2c_ts_data { struct i2c_client *client; struct input_dev *input; struct gpio_desc *gpio_attb; + struct gpio_desc *gpio_reset; const struct pixcir_ts_platform_data *pdata; bool running; int max_fingers; /* Max fingers supported in this instance */ @@ -189,6 +190,17 @@ static irqreturn_t pixcir_ts_isr(int irq, void *dev_id) return IRQ_HANDLED; } +static void pixcir_reset(struct pixcir_i2c_ts_data *tsdata) +{ + if (!IS_ERR_OR_NULL(tsdata->gpio_reset)) { + gpiod_set_value_cansleep(tsdata->gpio_reset, 1); + ndelay(100); /* datasheet section 1.2.3 says 80ns min. */ + gpiod_set_value_cansleep(tsdata->gpio_reset, 0); + /* wait for controller ready. 100ms guess. */ + msleep(100); + } +} + static int pixcir_set_power_mode(struct pixcir_i2c_ts_data *ts, enum pixcir_power_mode mode) { @@ -529,6 +541,14 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + tsdata->gpio_reset = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(tsdata->gpio_reset)) { + error = PTR_ERR(tsdata->gpio_reset); + dev_err(dev, "Failed to request RESET gpio: %d\n", error); + return error; + } + error = devm_request_threaded_irq(dev, client->irq, NULL, pixcir_ts_isr, IRQF_TRIGGER_FALLING | IRQF_ONESHOT, client->name, tsdata); @@ -537,6 +557,8 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, return error; } + pixcir_reset(tsdata); + /* Always be in IDLE mode to save power, device supports auto wake */ error = pixcir_set_power_mode(tsdata, PIXCIR_POWER_IDLE); if (error) { -- GitLab From 69b8c2a50c59a3b1c70666059a85c646f897eb96 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 13:43:31 -0700 Subject: [PATCH 0725/7006] Input: pixcir_i2c_ts - simplify input device initialization input_mt_init_slots() will perform necessary settings for performing multi-touch to single-touch emulation, we do not need to do that ourselves. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index a5a83139aad05..f47480e8dff88 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -510,11 +510,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->close = pixcir_input_close; input->dev.parent = &client->dev; - __set_bit(EV_KEY, input->evbit); - __set_bit(EV_ABS, input->evbit); - __set_bit(BTN_TOUCH, input->keybit); - input_set_abs_params(input, ABS_X, 0, pdata->x_max, 0, 0); - input_set_abs_params(input, ABS_Y, 0, pdata->y_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); -- GitLab From d48259a0d2c6820d26ea2077c8d330cf1b33877d Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 14:29:29 -0700 Subject: [PATCH 0726/7006] Input: pixcir_i2c_ts - use standard OF touchscreen parsing code Let's switch to using standard touchscreen device properties parsing module instead of doing it by hand in the driver. Acked-by: Roger Quadros Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/pixcir_i2c_ts.c | 95 +++++++++++------------ 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index f47480e8dff88..68d0d549797c4 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -24,9 +24,10 @@ #include #include #include +#include #include #include -#include +/*#include */ #include #include @@ -37,9 +38,9 @@ struct pixcir_i2c_ts_data { struct input_dev *input; struct gpio_desc *gpio_attb; struct gpio_desc *gpio_reset; - const struct pixcir_ts_platform_data *pdata; - bool running; + const struct pixcir_i2c_chip_data *chip; int max_fingers; /* Max fingers supported in this instance */ + bool running; }; struct pixcir_touch { @@ -62,7 +63,7 @@ static void pixcir_ts_parse(struct pixcir_i2c_ts_data *tsdata, u8 touch; int ret, i; int readsize; - const struct pixcir_i2c_chip_data *chip = &tsdata->pdata->chip; + const struct pixcir_i2c_chip_data *chip = tsdata->chip; memset(report, 0, sizeof(struct pixcir_report_data)); @@ -115,13 +116,13 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts, struct pixcir_touch *touch; int n, i, slot; struct device *dev = &ts->client->dev; - const struct pixcir_i2c_chip_data *chip = &ts->pdata->chip; + const struct pixcir_i2c_chip_data *chip = ts->chip; n = report->num_touches; if (n > PIXCIR_MAX_SLOTS) n = PIXCIR_MAX_SLOTS; - if (!chip->has_hw_ids) { + if (!ts->chip->has_hw_ids) { for (i = 0; i < n; i++) { touch = &report->touches[i]; pos[i].x = touch->x; @@ -423,77 +424,59 @@ static SIMPLE_DEV_PM_OPS(pixcir_dev_pm_ops, #ifdef CONFIG_OF static const struct of_device_id pixcir_of_match[]; -static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +static int pixcir_parse_dt(struct device *dev, + struct pixcir_i2c_ts_data *tsdata) { - struct pixcir_ts_platform_data *pdata; - struct device_node *np = dev->of_node; const struct of_device_id *match; match = of_match_device(of_match_ptr(pixcir_of_match), dev); if (!match) - return ERR_PTR(-EINVAL); - - pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); - if (!pdata) - return ERR_PTR(-ENOMEM); - - pdata->chip = *(const struct pixcir_i2c_chip_data *)match->data; - - if (of_property_read_u32(np, "touchscreen-size-x", &pdata->x_max)) { - dev_err(dev, "Failed to get touchscreen-size-x property\n"); - return ERR_PTR(-EINVAL); - } - pdata->x_max -= 1; - - if (of_property_read_u32(np, "touchscreen-size-y", &pdata->y_max)) { - dev_err(dev, "Failed to get touchscreen-size-y property\n"); - return ERR_PTR(-EINVAL); - } - pdata->y_max -= 1; + return -EINVAL; - dev_dbg(dev, "%s: x %d, y %d\n", __func__, - pdata->x_max + 1, pdata->y_max + 1); + tsdata->chip = (const struct pixcir_i2c_chip_data *)match->data; + if (!tsdata->chip) + return -EINVAL; - return pdata; + return 0; } #else -static struct pixcir_ts_platform_data *pixcir_parse_dt(struct device *dev) +static int pixcir_parse_dt(struct device *dev, + struct pixcir_i2c_ts_data *tsdata) { - return ERR_PTR(-EINVAL); + return -EINVAL; } #endif static int pixcir_i2c_ts_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *id) { const struct pixcir_ts_platform_data *pdata = dev_get_platdata(&client->dev); struct device *dev = &client->dev; - struct device_node *np = dev->of_node; struct pixcir_i2c_ts_data *tsdata; struct input_dev *input; int error; - if (np && !pdata) { - pdata = pixcir_parse_dt(dev); - if (IS_ERR(pdata)) - return PTR_ERR(pdata); - } + tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); + if (!tsdata) + return -ENOMEM; - if (!pdata) { + if (pdata) { + tsdata->chip = &pdata->chip; + } else if (dev->of_node) { + error = pixcir_parse_dt(dev, tsdata); + if (error) + return error; + } else { dev_err(&client->dev, "platform data not defined\n"); return -EINVAL; } - if (!pdata->chip.max_fingers) { - dev_err(dev, "Invalid max_fingers in pdata\n"); + if (!tsdata->chip->max_fingers) { + dev_err(dev, "Invalid max_fingers in chip data\n"); return -EINVAL; } - tsdata = devm_kzalloc(dev, sizeof(*tsdata), GFP_KERNEL); - if (!tsdata) - return -ENOMEM; - input = devm_input_allocate_device(dev); if (!input) { dev_err(dev, "Failed to allocate input device\n"); @@ -502,7 +485,6 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, tsdata->client = client; tsdata->input = input; - tsdata->pdata = pdata; input->name = client->name; input->id.bustype = BUS_I2C; @@ -510,10 +492,21 @@ static int pixcir_i2c_ts_probe(struct i2c_client *client, input->close = pixcir_input_close; input->dev.parent = &client->dev; - input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); + if (pdata) { + input_set_abs_params(input, ABS_MT_POSITION_X, 0, pdata->x_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 0, pdata->y_max, 0, 0); + } else { + input_set_capability(input, EV_ABS, ABS_MT_POSITION_X); + input_set_capability(input, EV_ABS, ABS_MT_POSITION_Y); + touchscreen_parse_properties(input, true); + if (!input_abs_get_max(input, ABS_MT_POSITION_X) || + !input_abs_get_max(input, ABS_MT_POSITION_Y)) { + dev_err(dev, "Touchscreen size is not specified\n"); + return -EINVAL; + } + } - tsdata->max_fingers = tsdata->pdata->chip.max_fingers; + tsdata->max_fingers = tsdata->chip->max_fingers; if (tsdata->max_fingers > PIXCIR_MAX_SLOTS) { tsdata->max_fingers = PIXCIR_MAX_SLOTS; dev_info(dev, "Limiting maximum fingers to %d\n", -- GitLab From 14fe22e334623e451b5592193415c644005461ea Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Sat, 11 Jul 2015 01:37:36 +0200 Subject: [PATCH 0727/7006] Revert "ipv4: use skb coalescing in defragmentation" This reverts commit 3cc4949269e01f39443d0fcfffb5bc6b47878d45. There is nothing wrong with coalescing during defragmentation, it reduces truesize overhead and simplifies things for the receiving socket (no fraglist walk needed). However, it also destroys geometry of the original fragments. While that doesn't cause any breakage (we make sure to not exceed largest original size) ip_do_fragment contains a 'fastpath' that takes advantage of a present frag list and results in fragments that (in most cases) match what was received. In case its needed the coalescing could be done later, when we're sure the skb is not forwarded. But discussion during NFWS resulted in 'lets just remove this for now'. Cc: Eric Dumazet Signed-off-by: Florian Westphal Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv4/ip_fragment.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index a50dc6d408d11..4d3fffafbe247 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -522,7 +522,6 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, int len; int ihlen; int err; - int sum_truesize; u8 ecn; ipq_kill(qp); @@ -590,32 +589,19 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, add_frag_mem_limit(&qp->q, clone->truesize); } + skb_shinfo(head)->frag_list = head->next; skb_push(head, head->data - skb_network_header(head)); - sum_truesize = head->truesize; - for (fp = head->next; fp;) { - bool headstolen; - int delta; - struct sk_buff *next = fp->next; - - sum_truesize += fp->truesize; + for (fp=head->next; fp; fp = fp->next) { + head->data_len += fp->len; + head->len += fp->len; if (head->ip_summed != fp->ip_summed) head->ip_summed = CHECKSUM_NONE; else if (head->ip_summed == CHECKSUM_COMPLETE) head->csum = csum_add(head->csum, fp->csum); - - if (skb_try_coalesce(head, fp, &headstolen, &delta)) { - kfree_skb_partial(fp, headstolen); - } else { - if (!skb_shinfo(head)->frag_list) - skb_shinfo(head)->frag_list = fp; - head->data_len += fp->len; - head->len += fp->len; - head->truesize += fp->truesize; - } - fp = next; + head->truesize += fp->truesize; } - sub_frag_mem_limit(&qp->q, sum_truesize); + sub_frag_mem_limit(&qp->q, head->truesize); head->next = NULL; head->dev = dev; -- GitLab From d5ebe37e8cded781bb91ac63dda2da180ecb90b6 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Thu, 9 Jul 2015 10:27:02 -0700 Subject: [PATCH 0728/7006] Input: wdt87xx_i2c - populate vendor and product in input device These attributes can be used to identify controllers present in the system. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 46 ++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index fb92ae1c5fae7..764d8f28203c1 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -23,7 +23,7 @@ #include #define WDT87XX_NAME "wdt87xx_i2c" -#define WDT87XX_DRV_VER "0.9.6" +#define WDT87XX_DRV_VER "0.9.7" #define WDT87XX_FW_NAME "wdt87xx_fw.bin" #define WDT87XX_CFG_NAME "wdt87xx_cfg.bin" @@ -85,6 +85,11 @@ #define CTL_PARAM_OFFSET_PHY_H 24 #define CTL_PARAM_OFFSET_FACTOR 32 +/* The definition of the device descriptor */ +#define WDT_GD_DEVICE 1 +#define DEV_DESC_OFFSET_VID 8 +#define DEV_DESC_OFFSET_PID 10 + /* Communication commands */ #define PACKET_SIZE 56 #define VND_REQ_READ 0x06 @@ -165,6 +170,8 @@ struct wdt87xx_sys_param { u16 scaling_factor; u32 max_x; u32 max_y; + u16 vendor_id; + u16 product_id; }; struct wdt87xx_data { @@ -208,6 +215,32 @@ static int wdt87xx_i2c_xfer(struct i2c_client *client, return 0; } +static int wdt87xx_get_desc(struct i2c_client *client, u8 desc_idx, + u8 *buf, size_t len) +{ + u8 tx_buf[] = { 0x22, 0x00, 0x10, 0x0E, 0x23, 0x00 }; + int error; + + tx_buf[2] |= desc_idx & 0xF; + + error = wdt87xx_i2c_xfer(client, tx_buf, sizeof(tx_buf), + buf, len); + if (error) { + dev_err(&client->dev, "get desc failed: %d\n", error); + return error; + } + + if (buf[0] != len) { + dev_err(&client->dev, "unexpected response to get desc: %d\n", + buf[0]); + return -EINVAL; + } + + mdelay(WDT_COMMAND_DELAY_MS); + + return 0; +} + static int wdt87xx_get_string(struct i2c_client *client, u8 str_idx, u8 *buf, size_t len) { @@ -403,6 +436,15 @@ static int wdt87xx_get_sysparam(struct i2c_client *client, u8 buf[PKT_READ_SIZE]; int error; + error = wdt87xx_get_desc(client, WDT_GD_DEVICE, buf, 18); + if (error) { + dev_err(&client->dev, "failed to get device desc\n"); + return error; + } + + param->vendor_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_VID); + param->product_id = get_unaligned_le16(buf + DEV_DESC_OFFSET_PID); + error = wdt87xx_get_string(client, STRIDX_PARAMETERS, buf, 34); if (error) { dev_err(&client->dev, "failed to get parameters\n"); @@ -994,6 +1036,8 @@ static int wdt87xx_ts_create_input_device(struct wdt87xx_data *wdt) input->name = "WDT87xx Touchscreen"; input->id.bustype = BUS_I2C; + input->id.vendor = wdt->param.vendor_id; + input->id.product = wdt->param.product_id; input->phys = wdt->phys; input_set_abs_params(input, ABS_MT_POSITION_X, 0, -- GitLab From 339d6b88e872f8369495a7224916a4d1d8376ca3 Mon Sep 17 00:00:00 2001 From: HungNien Chen Date: Sat, 11 Jul 2015 17:30:19 -0700 Subject: [PATCH 0729/7006] Input: wdt87xx_i2c - change the sleep time to 2500ms after the sw reset The original wait time was 200ms which was enough for the firmware to finish loading and boot. After that the firmware will perform initialization and touch calibration, which will take about 1.1 second. The touch calibration will change controller frequency to scan at the most optimal frequency and during calibration/frequency switching process we may run into i2c data errors. To avoid them we extend the sleep to 2500ms after issuing the sw reset. Signed-off-by: HungNien Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/wdt87xx_i2c.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/wdt87xx_i2c.c b/drivers/input/touchscreen/wdt87xx_i2c.c index 764d8f28203c1..515c20a6e10fa 100644 --- a/drivers/input/touchscreen/wdt87xx_i2c.c +++ b/drivers/input/touchscreen/wdt87xx_i2c.c @@ -157,6 +157,7 @@ /* Controller requires minimum 300us between commands */ #define WDT_COMMAND_DELAY_MS 2 #define WDT_FLASH_WRITE_DELAY_MS 4 +#define WDT_FW_RESET_TIME 2500 struct wdt87xx_sys_param { u16 fw_id; @@ -406,7 +407,7 @@ static int wdt87xx_sw_reset(struct i2c_client *client) } /* Wait the device to be ready */ - msleep(200); + msleep(WDT_FW_RESET_TIME); return 0; } -- GitLab From 6e06ae88edae77379bef7c0cb7d3c2dd88676867 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Sun, 12 Jul 2015 18:11:30 -0400 Subject: [PATCH 0730/7006] jbd2: speedup jbd2_journal_dirty_metadata() It is often the case that we mark buffer as having dirty metadata when the buffer is already in that state (frequent for bitmaps, inode table blocks, superblock). Thus it is unnecessary to contend on grabbing journal head reference and bh_state lock. Avoid that by checking whether any modification to the buffer is needed before grabbing any locks or references. [ Note: this is a fixed version of commit 2143c1965a761, which was reverted in ebeaa8ddb3663b5 due to a false positive triggering of an assertion check. -- Ted ] Signed-off-by: Jan Kara Signed-off-by: Theodore Ts'o --- fs/jbd2/transaction.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index f3d06174b0510..a6eec9747c743 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c @@ -1280,8 +1280,6 @@ void jbd2_buffer_abort_trigger(struct journal_head *jh, triggers->t_abort(triggers, jh2bh(jh)); } - - /** * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata * @handle: transaction to add buffer to. @@ -1314,12 +1312,41 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) if (is_handle_aborted(handle)) return -EROFS; - journal = transaction->t_journal; - jh = jbd2_journal_grab_journal_head(bh); - if (!jh) { + if (!buffer_jbd(bh)) { ret = -EUCLEAN; goto out; } + /* + * We don't grab jh reference here since the buffer must be part + * of the running transaction. + */ + jh = bh2jh(bh); + /* + * This and the following assertions are unreliable since we may see jh + * in inconsistent state unless we grab bh_state lock. But this is + * crucial to catch bugs so let's do a reliable check until the + * lockless handling is fully proven. + */ + if (jh->b_transaction != transaction && + jh->b_next_transaction != transaction) { + jbd_lock_bh_state(bh); + J_ASSERT_JH(jh, jh->b_transaction == transaction || + jh->b_next_transaction == transaction); + jbd_unlock_bh_state(bh); + } + if (jh->b_modified == 1) { + /* If it's in our transaction it must be in BJ_Metadata list. */ + if (jh->b_transaction == transaction && + jh->b_jlist != BJ_Metadata) { + jbd_lock_bh_state(bh); + J_ASSERT_JH(jh, jh->b_transaction != transaction || + jh->b_jlist == BJ_Metadata); + jbd_unlock_bh_state(bh); + } + goto out; + } + + journal = transaction->t_journal; jbd_debug(5, "journal_head %p\n", jh); JBUFFER_TRACE(jh, "entry"); @@ -1410,7 +1437,6 @@ int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) spin_unlock(&journal->j_list_lock); out_unlock_bh: jbd_unlock_bh_state(bh); - jbd2_journal_put_journal_head(jh); out: JBUFFER_TRACE(jh, "exit"); return ret; -- GitLab From 80c394fab89649585089f5bd5013f2d99e5756ef Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 11 Jun 2015 13:27:51 +0200 Subject: [PATCH 0731/7006] cxl: Add explicit precision specifiers C99 says that a precision given as simply '.' with no following digits or * should be interpreted as 0. The kernel's printf implementation, however, treats this case as if the precision was omitted. C99 also says that if both the precision and value are 0, no digits should be printed. Even if the kernel followed C99 to the letter, I don't think that would be particularly useful in these cases. For consistency with most other format strings in the file, use an explicit precision of 16 and add a 0x prefix. Signed-off-by: Rasmus Villemoes Signed-off-by: Michael Ellerman --- drivers/misc/cxl/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index 680cd263436db..2b64bb43b304a 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -147,7 +147,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) if (dsisr & CXL_PSL_DSISR_An_PE) return handle_psl_slice_error(ctx, dsisr, irq_info->errstat); if (dsisr & CXL_PSL_DSISR_An_AE) { - pr_devel("CXL interrupt: AFU Error %.llx\n", irq_info->afu_err); + pr_devel("CXL interrupt: AFU Error 0x%.16llx\n", irq_info->afu_err); if (ctx->pending_afu_err) { /* @@ -158,7 +158,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) * probably best that we log them somewhere: */ dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " - "undelivered to pe %i: %.llx\n", + "undelivered to pe %i: 0x%.16llx\n", ctx->pe, irq_info->afu_err); } else { spin_lock(&ctx->lock); -- GitLab From de369538436ae0caf784c69187ad0e53152b7ddf Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 11 Jun 2015 13:27:52 +0200 Subject: [PATCH 0732/7006] cxl: use more common format specifier A precision of 16 (%.16llx) has the same effect as a field width of 16 along with passing the 0 flag (%016llx), but the latter is much more common in the kernel tree. Update cxl to use that. Signed-off-by: Rasmus Villemoes Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/irq.c | 32 ++++++++++++++++---------------- drivers/misc/cxl/native.c | 10 +++++----- drivers/misc/cxl/pci.c | 10 +++++----- drivers/misc/cxl/trace.h | 10 +++++----- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index 2b64bb43b304a..abfce494ca6b8 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -30,12 +30,12 @@ static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u6 serr = cxl_p1n_read(ctx->afu, CXL_PSL_SERR_An); afu_debug = cxl_p1n_read(ctx->afu, CXL_AFU_DEBUG_An); - dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%.16llx\n", errstat); - dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%.16llx\n", fir1); - dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%.16llx\n", fir2); - dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); - dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice); - dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug); + dev_crit(&ctx->afu->dev, "PSL ERROR STATUS: 0x%016llx\n", errstat); + dev_crit(&ctx->afu->dev, "PSL_FIR1: 0x%016llx\n", fir1); + dev_crit(&ctx->afu->dev, "PSL_FIR2: 0x%016llx\n", fir2); + dev_crit(&ctx->afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); + dev_crit(&ctx->afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); + dev_crit(&ctx->afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); dev_crit(&ctx->afu->dev, "STOPPING CXL TRACE\n"); cxl_stop_trace(ctx->afu->adapter); @@ -54,10 +54,10 @@ irqreturn_t cxl_slice_irq_err(int irq, void *data) fir_slice = cxl_p1n_read(afu, CXL_PSL_FIR_SLICE_An); errstat = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); afu_debug = cxl_p1n_read(afu, CXL_AFU_DEBUG_An); - dev_crit(&afu->dev, "PSL_SERR_An: 0x%.16llx\n", serr); - dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%.16llx\n", fir_slice); - dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%.16llx\n", errstat); - dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%.16llx\n", afu_debug); + dev_crit(&afu->dev, "PSL_SERR_An: 0x%016llx\n", serr); + dev_crit(&afu->dev, "PSL_FIR_SLICE_An: 0x%016llx\n", fir_slice); + dev_crit(&afu->dev, "CXL_PSL_ErrStat_An: 0x%016llx\n", errstat); + dev_crit(&afu->dev, "CXL_PSL_AFU_DEBUG_An: 0x%016llx\n", afu_debug); cxl_p1n_write(afu, CXL_PSL_SERR_An, serr); @@ -72,7 +72,7 @@ static irqreturn_t cxl_irq_err(int irq, void *data) WARN(1, "CXL ERROR interrupt %i\n", irq); err_ivte = cxl_p1_read(adapter, CXL_PSL_ErrIVTE); - dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%.16llx\n", err_ivte); + dev_crit(&adapter->dev, "PSL_ErrIVTE: 0x%016llx\n", err_ivte); dev_crit(&adapter->dev, "STOPPING CXL TRACE\n"); cxl_stop_trace(adapter); @@ -80,7 +80,7 @@ static irqreturn_t cxl_irq_err(int irq, void *data) fir1 = cxl_p1_read(adapter, CXL_PSL_FIR1); fir2 = cxl_p1_read(adapter, CXL_PSL_FIR2); - dev_crit(&adapter->dev, "PSL_FIR1: 0x%.16llx\nPSL_FIR2: 0x%.16llx\n", fir1, fir2); + dev_crit(&adapter->dev, "PSL_FIR1: 0x%016llx\nPSL_FIR2: 0x%016llx\n", fir1, fir2); return IRQ_HANDLED; } @@ -147,7 +147,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) if (dsisr & CXL_PSL_DSISR_An_PE) return handle_psl_slice_error(ctx, dsisr, irq_info->errstat); if (dsisr & CXL_PSL_DSISR_An_AE) { - pr_devel("CXL interrupt: AFU Error 0x%.16llx\n", irq_info->afu_err); + pr_devel("CXL interrupt: AFU Error 0x%016llx\n", irq_info->afu_err); if (ctx->pending_afu_err) { /* @@ -158,7 +158,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info) * probably best that we log them somewhere: */ dev_err_ratelimited(&ctx->afu->dev, "CXL AFU Error " - "undelivered to pe %i: 0x%.16llx\n", + "undelivered to pe %i: 0x%016llx\n", ctx->pe, irq_info->afu_err); } else { spin_lock(&ctx->lock); @@ -211,8 +211,8 @@ static irqreturn_t cxl_irq_multiplexed(int irq, void *data) } rcu_read_unlock(); - WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %.16llx DAR" - " %.16llx\n(Possible AFU HW issue - was a term/remove acked" + WARN(1, "Unable to demultiplex CXL PSL IRQ for PE %i DSISR %016llx DAR" + " %016llx\n(Possible AFU HW issue - was a term/remove acked" " with outstanding transactions?)\n", ph, irq_info.dsisr, irq_info.dar); return fail_psl_irq(afu, &irq_info); diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index 10567f245818b..fc9310dd2367d 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -41,7 +41,7 @@ static int afu_control(struct cxl_afu *afu, u64 command, rc = -EBUSY; goto out; } - pr_devel_ratelimited("AFU control... (0x%.16llx)\n", + pr_devel_ratelimited("AFU control... (0x%016llx)\n", AFU_Cntl | command); cpu_relax(); AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); @@ -120,13 +120,13 @@ int cxl_psl_purge(struct cxl_afu *afu) goto out; } dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); - pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr); + pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%016llx PSL_DSISR: 0x%016llx\n", PSL_CNTL, dsisr); if (dsisr & CXL_PSL_DSISR_TRANS) { dar = cxl_p2n_read(afu, CXL_PSL_DAR_An); - dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%.16llx, DAR: 0x%.16llx\n", dsisr, dar); + dev_notice(&afu->dev, "PSL purge terminating pending translation, DSISR: 0x%016llx, DAR: 0x%016llx\n", dsisr, dar); cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); } else if (dsisr) { - dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%.16llx\n", dsisr); + dev_notice(&afu->dev, "PSL purge acknowledging pending non-translation fault, DSISR: 0x%016llx\n", dsisr); cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_A); } else { cpu_relax(); @@ -684,7 +684,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat) { u64 dsisr; - pr_devel("RECOVERING FROM PSL ERROR... (0x%.16llx)\n", errstat); + pr_devel("RECOVERING FROM PSL ERROR... (0x%016llx)\n", errstat); /* Clear PSL_DSISR[PE] */ dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An); diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 32ad097059498..eb05efb74eed8 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -656,7 +656,7 @@ static int sanitise_afu_regs(struct cxl_afu *afu) */ reg = cxl_p2n_read(afu, CXL_AFU_Cntl_An); if ((reg & CXL_AFU_Cntl_An_ES_MASK) != CXL_AFU_Cntl_An_ES_Disabled) { - dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#.16llx\n", reg); + dev_warn(&afu->dev, "WARNING: AFU was not disabled: %#016llx\n", reg); if (__cxl_afu_reset(afu)) return -EIO; if (cxl_afu_disable(afu)) @@ -677,7 +677,7 @@ static int sanitise_afu_regs(struct cxl_afu *afu) cxl_p2n_write(afu, CXL_SSTP0_An, 0x0000000000000000); reg = cxl_p2n_read(afu, CXL_PSL_DSISR_An); if (reg) { - dev_warn(&afu->dev, "AFU had pending DSISR: %#.16llx\n", reg); + dev_warn(&afu->dev, "AFU had pending DSISR: %#016llx\n", reg); if (reg & CXL_PSL_DSISR_TRANS) cxl_p2n_write(afu, CXL_PSL_TFC_An, CXL_PSL_TFC_An_AE); else @@ -686,12 +686,12 @@ static int sanitise_afu_regs(struct cxl_afu *afu) reg = cxl_p1n_read(afu, CXL_PSL_SERR_An); if (reg) { if (reg & ~0xffff) - dev_warn(&afu->dev, "AFU had pending SERR: %#.16llx\n", reg); + dev_warn(&afu->dev, "AFU had pending SERR: %#016llx\n", reg); cxl_p1n_write(afu, CXL_PSL_SERR_An, reg & ~0xffff); } reg = cxl_p2n_read(afu, CXL_PSL_ErrStat_An); if (reg) { - dev_warn(&afu->dev, "AFU had pending error status: %#.16llx\n", reg); + dev_warn(&afu->dev, "AFU had pending error status: %#016llx\n", reg); cxl_p2n_write(afu, CXL_PSL_ErrStat_An, reg); } @@ -893,7 +893,7 @@ static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev) if (pci_request_region(dev, 0, "priv 1 regs")) goto err2; - pr_devel("cxl_map_adapter_regs: p1: %#.16llx %#llx, p2: %#.16llx %#llx", + pr_devel("cxl_map_adapter_regs: p1: %#016llx %#llx, p2: %#016llx %#llx", p1_base(dev), p1_size(dev), p2_base(dev), p2_size(dev)); if (!(adapter->p1_mmio = ioremap(p1_base(dev), p1_size(dev)))) diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h index ae434d87887e8..6e1e2adfba8ec 100644 --- a/drivers/misc/cxl/trace.h +++ b/drivers/misc/cxl/trace.h @@ -105,7 +105,7 @@ TRACE_EVENT(cxl_attach, __entry->num_interrupts = num_interrupts; ), - TP_printk("afu%i.%i pid=%i pe=%i wed=0x%.16llx irqs=%i amr=0x%llx", + TP_printk("afu%i.%i pid=%i pe=%i wed=0x%016llx irqs=%i amr=0x%llx", __entry->card, __entry->afu, __entry->pid, @@ -177,7 +177,7 @@ TRACE_EVENT(cxl_psl_irq, __entry->dar = dar; ), - TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%.16llx", + TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%016llx", __entry->card, __entry->afu, __entry->pe, @@ -233,7 +233,7 @@ TRACE_EVENT(cxl_ste_miss, __entry->dar = dar; ), - TP_printk("afu%i.%i pe=%i dar=0x%.16llx", + TP_printk("afu%i.%i pe=%i dar=0x%016llx", __entry->card, __entry->afu, __entry->pe, @@ -264,7 +264,7 @@ TRACE_EVENT(cxl_ste_write, __entry->v = v; ), - TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%.16llx V=0x%.16llx", + TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%016llx V=0x%016llx", __entry->card, __entry->afu, __entry->pe, @@ -295,7 +295,7 @@ TRACE_EVENT(cxl_pte_miss, __entry->dar = dar; ), - TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%.16llx", + TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%016llx", __entry->card, __entry->afu, __entry->pe, -- GitLab From 2db4928bb559f8b43ca75879548111dc13a7de31 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 24 Jun 2015 15:25:22 +1000 Subject: [PATCH 0733/7006] powerpc/iommu: Remove dma_data union To support "hybrid" DMA ops in a subsequent patch, we will need both a direct DMA offset and an iommu pointer. Those are currently exclusive (a union), so change them to be separate fields. While there, also type iommu_table_base properly and make exist only on CONFIG_PPC64 since it's not referenced on 32-bit at all. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/device.h | 15 ++++++++----- arch/powerpc/include/asm/dma-mapping.h | 4 ++-- arch/powerpc/include/asm/iommu.h | 31 +++++++++++++++++++++----- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/arch/powerpc/include/asm/device.h b/arch/powerpc/include/asm/device.h index e9bdda88f1fbb..406c2b1ff82d6 100644 --- a/arch/powerpc/include/asm/device.h +++ b/arch/powerpc/include/asm/device.h @@ -10,6 +10,7 @@ struct dma_map_ops; struct device_node; #ifdef CONFIG_PPC64 struct pci_dn; +struct iommu_table; #endif /* @@ -23,13 +24,15 @@ struct dev_archdata { struct dma_map_ops *dma_ops; /* - * When an iommu is in use, dma_data is used as a ptr to the base of the - * iommu_table. Otherwise, it is a simple numerical offset. + * These two used to be a union. However, with the hybrid ops we need + * both so here we store both a DMA offset for direct mappings and + * an iommu_table for remapped DMA. */ - union { - dma_addr_t dma_offset; - void *iommu_table_base; - } dma_data; + dma_addr_t dma_offset; + +#ifdef CONFIG_PPC64 + struct iommu_table *iommu_table_base; +#endif #ifdef CONFIG_IOMMU_API void *iommu_domain; diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 9103687b04363..9cbbc9e415fe2 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -106,7 +106,7 @@ static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) static inline dma_addr_t get_dma_offset(struct device *dev) { if (dev) - return dev->archdata.dma_data.dma_offset; + return dev->archdata.dma_offset; return PCI_DRAM_OFFSET; } @@ -114,7 +114,7 @@ static inline dma_addr_t get_dma_offset(struct device *dev) static inline void set_dma_offset(struct device *dev, dma_addr_t off) { if (dev) - dev->archdata.dma_data.dma_offset = off; + dev->archdata.dma_offset = off; } /* this will be removed soon */ diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h index ca18cff909006..7b87bab095641 100644 --- a/arch/powerpc/include/asm/iommu.h +++ b/arch/powerpc/include/asm/iommu.h @@ -2,17 +2,17 @@ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen, IBM Corporation * Rewrite, cleanup: * Copyright (C) 2004 Olof Johansson , IBM Corporation - * + * * 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. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -131,16 +131,21 @@ int get_iommu_order(unsigned long size, struct iommu_table *tbl) struct scatterlist; -static inline void set_iommu_table_base(struct device *dev, void *base) +#ifdef CONFIG_PPC64 + +static inline void set_iommu_table_base(struct device *dev, + struct iommu_table *base) { - dev->archdata.dma_data.iommu_table_base = base; + dev->archdata.iommu_table_base = base; } static inline void *get_iommu_table_base(struct device *dev) { - return dev->archdata.dma_data.iommu_table_base; + return dev->archdata.iommu_table_base; } +extern int dma_iommu_dma_supported(struct device *dev, u64 mask); + /* Frees table for an individual device node */ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name); @@ -225,6 +230,20 @@ static inline int __init tce_iommu_bus_notifier_init(void) } #endif /* !CONFIG_IOMMU_API */ +#else + +static inline void *get_iommu_table_base(struct device *dev) +{ + return NULL; +} + +static inline int dma_iommu_dma_supported(struct device *dev, u64 mask) +{ + return 0; +} + +#endif /* CONFIG_PPC64 */ + extern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl, struct scatterlist *sglist, int nelems, unsigned long mask, -- GitLab From e91c25111aa373af7439d97ab0e606bcffd599ef Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 24 Jun 2015 15:25:27 +1000 Subject: [PATCH 0734/7006] powerpc/iommu: Cleanup setting of DMA base/offset Now that the table and the offset can co-exist, we no longer need to flip/flop, we can just establish both once at boot time. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 3 +-- arch/powerpc/platforms/pseries/iommu.c | 3 +-- arch/powerpc/sysdev/dart_iommu.c | 16 +++------------- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 5738d315248b2..2c286b57e520e 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1620,11 +1620,9 @@ static int pnv_pci_ioda_dma_set_mask(struct pci_dev *pdev, u64 dma_mask) if (bypass) { dev_info(&pdev->dev, "Using 64-bit DMA iommu bypass\n"); set_dma_ops(&pdev->dev, &dma_direct_ops); - set_dma_offset(&pdev->dev, pe->tce_bypass_base); } else { dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n"); set_dma_ops(&pdev->dev, &dma_iommu_ops); - set_iommu_table_base(&pdev->dev, pe->table_group.tables[0]); } *pdev->dev.dma_mask = dma_mask; return 0; @@ -1659,6 +1657,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, list_for_each_entry(dev, &bus->devices, bus_list) { set_iommu_table_base(&dev->dev, pe->table_group.tables[0]); + set_dma_offset(&dev->dev, pe->tce_bypass_base); iommu_add_device(&dev->dev); if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate) diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 10510dea16b31..0946b98d75d41 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -1253,11 +1253,10 @@ static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask) } } - /* fall back on iommu ops, restore table pointer with ops */ + /* fall back on iommu ops */ if (!ddw_enabled && get_dma_ops(dev) != &dma_iommu_ops) { dev_info(dev, "Restoring 32-bit DMA via iommu\n"); set_dma_ops(dev, &dma_iommu_ops); - pci_dma_dev_setup_pSeriesLP(pdev); } check_mask: diff --git a/arch/powerpc/sysdev/dart_iommu.c b/arch/powerpc/sysdev/dart_iommu.c index 90bcdfeedf482..b7348637eae00 100644 --- a/arch/powerpc/sysdev/dart_iommu.c +++ b/arch/powerpc/sysdev/dart_iommu.c @@ -313,20 +313,11 @@ static void iommu_table_dart_setup(void) set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map); } -static void dma_dev_setup_dart(struct device *dev) -{ - /* We only have one iommu table on the mac for now, which makes - * things simple. Setup all PCI devices to point to this table - */ - if (get_dma_ops(dev) == &dma_direct_ops) - set_dma_offset(dev, DART_U4_BYPASS_BASE); - else - set_iommu_table_base(dev, &iommu_table_dart); -} - static void pci_dma_dev_setup_dart(struct pci_dev *dev) { - dma_dev_setup_dart(&dev->dev); + if (dart_is_u4) + set_dma_offset(&dev->dev, DART_U4_BYPASS_BASE); + set_iommu_table_base(&dev->dev, &iommu_table_dart); } static void pci_dma_bus_setup_dart(struct pci_bus *bus) @@ -370,7 +361,6 @@ static int dart_dma_set_mask(struct device *dev, u64 dma_mask) dev_info(dev, "Using 32-bit DMA via iommu\n"); set_dma_ops(dev, &dma_iommu_ops); } - dma_dev_setup_dart(dev); *dev->dma_mask = dma_mask; return 0; -- GitLab From 817820b0226a1376f0fc68827ab8e42d86431117 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Wed, 24 Jun 2015 15:25:31 +1000 Subject: [PATCH 0735/7006] powerpc/iommu: Support "hybrid" iommu/direct DMA ops for coherent_mask < dma_mask This patch adds the ability to the DMA direct ops to fallback to the IOMMU ops for coherent alloc/free if the coherent mask of the device isn't suitable for accessing the direct DMA space and the device also happens to have an active IOMMU table. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Michael Ellerman --- arch/powerpc/Kconfig | 4 + arch/powerpc/include/asm/dma-mapping.h | 10 +-- arch/powerpc/kernel/dma-iommu.c | 2 +- arch/powerpc/kernel/dma-swiotlb.c | 4 +- arch/powerpc/kernel/dma.c | 111 +++++++++++++++++++++---- 5 files changed, 105 insertions(+), 26 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index 5ef27113b898c..fe2f2c595fd9f 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -82,6 +82,9 @@ config GENERIC_HWEIGHT bool default y +config ARCH_HAS_DMA_SET_COHERENT_MASK + bool + config PPC bool default y @@ -155,6 +158,7 @@ config PPC select HAVE_PERF_EVENTS_NMI if PPC64 select EDAC_SUPPORT select EDAC_ATOMIC_SCRUB + select ARCH_HAS_DMA_SET_COHERENT_MASK config GENERIC_CSUM def_bool CPU_LITTLE_ENDIAN diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 9cbbc9e415fe2..710f60e380e07 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -21,12 +21,12 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0x0) /* Some dma direct funcs must be visible for use in other dma_ops */ -extern void *dma_direct_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, +extern void *__dma_direct_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag, + struct dma_attrs *attrs); +extern void __dma_direct_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs); -extern void dma_direct_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs); extern int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t handle, diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c index 4c68bfe4108a9..41a7d9d49a5a3 100644 --- a/arch/powerpc/kernel/dma-iommu.c +++ b/arch/powerpc/kernel/dma-iommu.c @@ -73,7 +73,7 @@ static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist, } /* We support DMA to/from any memory page via the iommu */ -static int dma_iommu_dma_supported(struct device *dev, u64 mask) +int dma_iommu_dma_supported(struct device *dev, u64 mask) { struct iommu_table *tbl = get_iommu_table_base(dev); diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c index 6e8d764ce47bc..c6689f658b50f 100644 --- a/arch/powerpc/kernel/dma-swiotlb.c +++ b/arch/powerpc/kernel/dma-swiotlb.c @@ -47,8 +47,8 @@ static u64 swiotlb_powerpc_get_required(struct device *dev) * for everything else. */ struct dma_map_ops swiotlb_dma_ops = { - .alloc = dma_direct_alloc_coherent, - .free = dma_direct_free_coherent, + .alloc = __dma_direct_alloc_coherent, + .free = __dma_direct_free_coherent, .mmap = dma_direct_mmap_coherent, .map_sg = swiotlb_map_sg_attrs, .unmap_sg = swiotlb_unmap_sg_attrs, diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 35e4dcc5dce36..1558f81ac1ff5 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c @@ -16,6 +16,7 @@ #include #include #include +#include /* * Generic direct DMA implementation @@ -39,9 +40,31 @@ static u64 __maybe_unused get_pfn_limit(struct device *dev) return pfn; } -void *dma_direct_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) +static int dma_direct_dma_supported(struct device *dev, u64 mask) +{ +#ifdef CONFIG_PPC64 + u64 limit = get_dma_offset(dev) + (memblock_end_of_DRAM() - 1); + + /* Limit fits in the mask, we are good */ + if (mask >= limit) + return 1; + +#ifdef CONFIG_FSL_SOC + /* Freescale gets another chance via ZONE_DMA/ZONE_DMA32, however + * that will have to be refined if/when they support iommus + */ + return 1; +#endif + /* Sorry ... */ + return 0; +#else + return 1; +#endif +} + +void *__dma_direct_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag, + struct dma_attrs *attrs) { void *ret; #ifdef CONFIG_NOT_COHERENT_CACHE @@ -96,9 +119,9 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size, #endif } -void dma_direct_free_coherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs) +void __dma_direct_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs) { #ifdef CONFIG_NOT_COHERENT_CACHE __dma_free_coherent(size, vaddr); @@ -107,6 +130,51 @@ void dma_direct_free_coherent(struct device *dev, size_t size, #endif } +static void *dma_direct_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag, + struct dma_attrs *attrs) +{ + struct iommu_table *iommu; + + /* The coherent mask may be smaller than the real mask, check if + * we can really use the direct ops + */ + if (dma_direct_dma_supported(dev, dev->coherent_dma_mask)) + return __dma_direct_alloc_coherent(dev, size, dma_handle, + flag, attrs); + + /* Ok we can't ... do we have an iommu ? If not, fail */ + iommu = get_iommu_table_base(dev); + if (!iommu) + return NULL; + + /* Try to use the iommu */ + return iommu_alloc_coherent(dev, iommu, size, dma_handle, + dev->coherent_dma_mask, flag, + dev_to_node(dev)); +} + +static void dma_direct_free_coherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle, + struct dma_attrs *attrs) +{ + struct iommu_table *iommu; + + /* See comments in dma_direct_alloc_coherent() */ + if (dma_direct_dma_supported(dev, dev->coherent_dma_mask)) + return __dma_direct_free_coherent(dev, size, vaddr, dma_handle, + attrs); + /* Maybe we used an iommu ... */ + iommu = get_iommu_table_base(dev); + + /* If we hit that we should have never allocated in the first + * place so how come we are freeing ? + */ + if (WARN_ON(!iommu)) + return; + iommu_free_coherent(iommu, size, vaddr, dma_handle); +} + int dma_direct_mmap_coherent(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, dma_addr_t handle, size_t size, struct dma_attrs *attrs) @@ -147,18 +215,6 @@ static void dma_direct_unmap_sg(struct device *dev, struct scatterlist *sg, { } -static int dma_direct_dma_supported(struct device *dev, u64 mask) -{ -#ifdef CONFIG_PPC64 - /* Could be improved so platforms can set the limit in case - * they have limited DMA windows - */ - return mask >= get_dma_offset(dev) + (memblock_end_of_DRAM() - 1); -#else - return 1; -#endif -} - static u64 dma_direct_get_required_mask(struct device *dev) { u64 end, mask; @@ -230,6 +286,25 @@ struct dma_map_ops dma_direct_ops = { }; EXPORT_SYMBOL(dma_direct_ops); +int dma_set_coherent_mask(struct device *dev, u64 mask) +{ + if (!dma_supported(dev, mask)) { + /* + * We need to special case the direct DMA ops which can + * support a fallback for coherent allocations. There + * is no dma_op->set_coherent_mask() so we have to do + * things the hard way: + */ + if (get_dma_ops(dev) != &dma_direct_ops || + get_iommu_table_base(dev) == NULL || + !dma_iommu_dma_supported(dev, mask)) + return -EIO; + } + dev->coherent_dma_mask = mask; + return 0; +} +EXPORT_SYMBOL_GPL(dma_set_coherent_mask); + #define PREALLOC_DMA_DEBUG_ENTRIES (1 << 16) int __dma_set_mask(struct device *dev, u64 dma_mask) -- GitLab From e8a4fd0afe05d5213d809fa686d3b8319464acfd Mon Sep 17 00:00:00 2001 From: Michael Ellerman Date: Fri, 29 Aug 2014 17:01:43 +1000 Subject: [PATCH 0736/7006] powerpc: Add macros for the ibm_architecture_vec[] lengths The encoding of the lengths in the ibm_architecture_vec array is "interesting" to say the least. It's non-obvious how the number of bytes we provide relates to the length value. In fact we already got it wrong once, see 11e9ed43ca8a "Fix up ibm_architecture_vec definition". So add some macros to make it (hopefully) clearer. These at least have the property that the integer present in the code is equal to the number of bytes that follows it. Signed-off-by: Michael Ellerman Reviewed-by: Stewart Smith --- arch/powerpc/kernel/prom_init.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/kernel/prom_init.c b/arch/powerpc/kernel/prom_init.c index fcca8077e6a29..15099c41622e9 100644 --- a/arch/powerpc/kernel/prom_init.c +++ b/arch/powerpc/kernel/prom_init.c @@ -641,6 +641,15 @@ static void __init early_cmdline_parse(void) #define W(x) ((x) >> 24) & 0xff, ((x) >> 16) & 0xff, \ ((x) >> 8) & 0xff, (x) & 0xff +/* Firmware expects the value to be n - 1, where n is the # of vectors */ +#define NUM_VECTORS(n) ((n) - 1) + +/* + * Firmware expects 1 + n - 2, where n is the length of the option vector in + * bytes. The 1 accounts for the length byte itself, the - 2 .. ? + */ +#define VECTOR_LENGTH(n) (1 + (n) - 2) + unsigned char ibm_architecture_vec[] = { W(0xfffe0000), W(0x003a0000), /* POWER5/POWER5+ */ W(0xffff0000), W(0x003e0000), /* POWER6 */ @@ -651,16 +660,16 @@ unsigned char ibm_architecture_vec[] = { W(0xffffffff), W(0x0f000003), /* all 2.06-compliant */ W(0xffffffff), W(0x0f000002), /* all 2.05-compliant */ W(0xfffffffe), W(0x0f000001), /* all 2.04-compliant and earlier */ - 6 - 1, /* 6 option vectors */ + NUM_VECTORS(6), /* 6 option vectors */ /* option vector 1: processor architectures supported */ - 3 - 2, /* length */ + VECTOR_LENGTH(2), /* length */ 0, /* don't ignore, don't halt */ OV1_PPC_2_00 | OV1_PPC_2_01 | OV1_PPC_2_02 | OV1_PPC_2_03 | OV1_PPC_2_04 | OV1_PPC_2_05 | OV1_PPC_2_06 | OV1_PPC_2_07, /* option vector 2: Open Firmware options supported */ - 34 - 2, /* length */ + VECTOR_LENGTH(33), /* length */ OV2_REAL_MODE, 0, 0, W(0xffffffff), /* real_base */ @@ -674,17 +683,17 @@ unsigned char ibm_architecture_vec[] = { 48, /* max log_2(hash table size) */ /* option vector 3: processor options supported */ - 3 - 2, /* length */ + VECTOR_LENGTH(2), /* length */ 0, /* don't ignore, don't halt */ OV3_FP | OV3_VMX | OV3_DFP, /* option vector 4: IBM PAPR implementation */ - 3 - 2, /* length */ + VECTOR_LENGTH(2), /* length */ 0, /* don't halt */ OV4_MIN_ENT_CAP, /* minimum VP entitled capacity */ /* option vector 5: PAPR/OF options */ - 19 - 2, /* length */ + VECTOR_LENGTH(18), /* length */ 0, /* don't ignore, don't halt */ OV5_FEAT(OV5_LPAR) | OV5_FEAT(OV5_SPLPAR) | OV5_FEAT(OV5_LARGE_PAGES) | OV5_FEAT(OV5_DRCONF_MEMORY) | OV5_FEAT(OV5_DONATE_DEDICATE_CPU) | @@ -717,12 +726,12 @@ unsigned char ibm_architecture_vec[] = { OV5_FEAT(OV5_PFO_HW_RNG) | OV5_FEAT(OV5_PFO_HW_ENCR) | OV5_FEAT(OV5_PFO_HW_842), OV5_FEAT(OV5_SUB_PROCESSORS), + /* option vector 6: IBM PAPR hints */ - 4 - 2, /* length */ + VECTOR_LENGTH(3), /* length */ 0, 0, OV6_LINUX, - }; /* Old method - ELF header with PT_NOTE sections only works on BE */ -- GitLab From 1c53973172f84fafa8ad94f17ac427fdd4f260a2 Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 7 Jul 2015 13:56:59 +1000 Subject: [PATCH 0737/7006] powerpc: Remove mtmsrd(), use existing mtmsr() mtmsr() does the right thing on 32bit and 64bit, so use it everywhere. Signed-off-by: Anton Blanchard Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/reg.h | 3 +-- arch/powerpc/oprofile/op_model_power4.c | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/arch/powerpc/include/asm/reg.h b/arch/powerpc/include/asm/reg.h index af56b5c6c81ab..bb2758819bc92 100644 --- a/arch/powerpc/include/asm/reg.h +++ b/arch/powerpc/include/asm/reg.h @@ -1193,8 +1193,7 @@ #ifdef CONFIG_PPC_BOOK3S_64 #define __mtmsrd(v, l) asm volatile("mtmsrd %0," __stringify(l) \ : : "r" (v) : "memory") -#define mtmsrd(v) __mtmsrd((v), 0) -#define mtmsr(v) mtmsrd(v) +#define mtmsr(v) __mtmsrd((v), 0) #else #define mtmsr(v) asm volatile("mtmsr %0" : \ : "r" ((unsigned long)(v)) \ diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c index 962fe7b3e3fb1..4b32e9404bbef 100644 --- a/arch/powerpc/oprofile/op_model_power4.c +++ b/arch/powerpc/oprofile/op_model_power4.c @@ -207,7 +207,7 @@ static int power4_start(struct op_counter_config *ctr) unsigned int mmcr0; /* set the PMM bit (see comment below) */ - mtmsrd(mfmsr() | MSR_PMM); + mtmsr(mfmsr() | MSR_PMM); for (i = 0; i < cur_cpu_spec->num_pmcs; ++i) { if (ctr[i].enabled) { @@ -377,7 +377,7 @@ static void power4_handle_interrupt(struct pt_regs *regs, is_kernel = get_kernel(pc, mmcra); /* set the PMM bit (see comment below) */ - mtmsrd(mfmsr() | MSR_PMM); + mtmsr(mfmsr() | MSR_PMM); /* Check that the SIAR valid bit in MMCRA is set to 1. */ if ((mmcra & MMCRA_SIAR_VALID_MASK) == MMCRA_SIAR_VALID_MASK) -- GitLab From e9dc4d7f72a375020ecbc9ca35b098fd9018910b Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 19 Jun 2015 12:26:16 +1000 Subject: [PATCH 0738/7006] powerpc/powernv: Allow to reserve one PE for multiple times The PE numbers are reserved according to root port's M64 window, which is aligned to M64 segment finely. So one PE shouldn't be reserved for multiple times. We will reserve PE numbers according to the M64 BARs of PCI device in subsequent patches, which aren't aligned to M64 segment size finely. It means one particular PE could be reserved for multiple times. The patch allows one PE to be reserved for multiple times and we print the warning message at debugging level. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 2c286b57e520e..4775f9544f5cc 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -140,11 +140,9 @@ static void pnv_ioda_reserve_pe(struct pnv_phb *phb, int pe_no) return; } - if (test_and_set_bit(pe_no, phb->ioda.pe_alloc)) { - pr_warn("%s: PE %d was assigned on PHB#%x\n", - __func__, pe_no, phb->hose->global_number); - return; - } + if (test_and_set_bit(pe_no, phb->ioda.pe_alloc)) + pr_debug("%s: PE %d was reserved on PHB#%x\n", + __func__, pe_no, phb->hose->global_number); phb->ioda.pe_array[pe_no].phb = phb; phb->ioda.pe_array[pe_no].pe_number = pe_no; -- GitLab From 96a2f92bf8a4d0bf4a49bdd6539561a2c3289f37 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 19 Jun 2015 12:26:17 +1000 Subject: [PATCH 0739/7006] powerpc/powernv: Reserve M64 PEs based on BARs On PHB3, some PEs might be reserved in advance to reflect the M64 segments consumed by those PEs. We're reserving PEs based on the M64 window of root port, which might contain VF BAR. The PEs for VFs are allocated dynamically, not reserved based on the consumed M64 segments. So the M64 window of root port isn't reliable for the task. Instead, we go through M64 BARs (VF BARs excluded) of PCI devices under the specified root bus and reserve PEs accordingly, as the patch does. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 56 +++++++++++++++-------- arch/powerpc/platforms/powernv/pci.h | 3 +- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 4775f9544f5cc..51a4dfe588d2a 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -229,32 +229,48 @@ fail: return -EIO; } -static void pnv_ioda2_reserve_m64_pe(struct pnv_phb *phb) +static void pnv_ioda2_reserve_dev_m64_pe(struct pci_dev *pdev, + unsigned long *pe_bitmap) { - resource_size_t sgsz = phb->ioda.m64_segsize; - struct pci_dev *pdev; + struct pci_controller *hose = pci_bus_to_host(pdev->bus); + struct pnv_phb *phb = hose->private_data; struct resource *r; - int base, step, i; - - /* - * Root bus always has full M64 range and root port has - * M64 range used in reality. So we're checking root port - * instead of root bus. - */ - list_for_each_entry(pdev, &phb->hose->bus->devices, bus_list) { - for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) { - r = &pdev->resource[PCI_BRIDGE_RESOURCES + i]; - if (!r->parent || - !pnv_pci_is_mem_pref_64(r->flags)) - continue; + resource_size_t base, sgsz, start, end; + int segno, i; + + base = phb->ioda.m64_base; + sgsz = phb->ioda.m64_segsize; + for (i = 0; i <= PCI_ROM_RESOURCE; i++) { + r = &pdev->resource[i]; + if (!r->parent || !pnv_pci_is_mem_pref_64(r->flags)) + continue; - base = (r->start - phb->ioda.m64_base) / sgsz; - for (step = 0; step < resource_size(r) / sgsz; step++) - pnv_ioda_reserve_pe(phb, base + step); + start = _ALIGN_DOWN(r->start - base, sgsz); + end = _ALIGN_UP(r->end - base, sgsz); + for (segno = start / sgsz; segno < end / sgsz; segno++) { + if (pe_bitmap) + set_bit(segno, pe_bitmap); + else + pnv_ioda_reserve_pe(phb, segno); } } } +static void pnv_ioda2_reserve_m64_pe(struct pci_bus *bus, + unsigned long *pe_bitmap, + bool all) +{ + struct pci_dev *pdev; + + list_for_each_entry(pdev, &bus->devices, bus_list) { + pnv_ioda2_reserve_dev_m64_pe(pdev, pe_bitmap); + + if (all && pdev->subordinate) + pnv_ioda2_reserve_m64_pe(pdev->subordinate, + pe_bitmap, all); + } +} + static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb, struct pci_bus *bus, int all) { @@ -1145,7 +1161,7 @@ static void pnv_pci_ioda_setup_PEs(void) /* M64 layout might affect PE allocation */ if (phb->reserve_m64_pe) - phb->reserve_m64_pe(phb); + phb->reserve_m64_pe(hose->bus, NULL, true); pnv_ioda_setup_PEs(hose->bus); } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 8ef2d28aded0f..c6ddd18841b4e 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -110,7 +110,8 @@ struct pnv_phb { void (*fixup_phb)(struct pci_controller *hose); u32 (*bdfn_to_pe)(struct pnv_phb *phb, struct pci_bus *bus, u32 devfn); int (*init_m64)(struct pnv_phb *phb); - void (*reserve_m64_pe)(struct pnv_phb *phb); + void (*reserve_m64_pe)(struct pci_bus *bus, + unsigned long *pe_bitmap, bool all); int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all); int (*get_pe_state)(struct pnv_phb *phb, int pe_no); void (*freeze_pe)(struct pnv_phb *phb, int pe_no); -- GitLab From d1203852dfbbbd043bbd831761c117af752d1eda Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 19 Jun 2015 12:26:18 +1000 Subject: [PATCH 0740/7006] powerpc/powernv: Boolean argument for pnv_ioda_setup_bus_PE() The patch changes the type of last argument of pnv_ioda_setup_bus_PE() and phb::pick_m64_pe() to boolean. No functional change. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 8 ++++---- arch/powerpc/platforms/powernv/pci.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 51a4dfe588d2a..15d9dfcaf840a 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -272,7 +272,7 @@ static void pnv_ioda2_reserve_m64_pe(struct pci_bus *bus, } static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb, - struct pci_bus *bus, int all) + struct pci_bus *bus, bool all) { resource_size_t segsz = phb->ioda.m64_segsize; struct pci_dev *pdev; @@ -1064,7 +1064,7 @@ static void pnv_ioda_setup_same_PE(struct pci_bus *bus, struct pnv_ioda_pe *pe) * subordinate PCI devices and buses. The second type of PE is normally * orgiriated by PCIe-to-PCI bridge or PLX switch downstream ports. */ -static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, int all) +static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all) { struct pci_controller *hose = pci_bus_to_host(bus); struct pnv_phb *phb = hose->private_data; @@ -1131,12 +1131,12 @@ static void pnv_ioda_setup_PEs(struct pci_bus *bus) { struct pci_dev *dev; - pnv_ioda_setup_bus_PE(bus, 0); + pnv_ioda_setup_bus_PE(bus, false); list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->subordinate) { if (pci_pcie_type(dev) == PCI_EXP_TYPE_PCI_BRIDGE) - pnv_ioda_setup_bus_PE(dev->subordinate, 1); + pnv_ioda_setup_bus_PE(dev->subordinate, true); else pnv_ioda_setup_PEs(dev->subordinate); } diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index c6ddd18841b4e..5915cd244a5e8 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -112,7 +112,7 @@ struct pnv_phb { int (*init_m64)(struct pnv_phb *phb); void (*reserve_m64_pe)(struct pci_bus *bus, unsigned long *pe_bitmap, bool all); - int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, int all); + int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, bool all); int (*get_pe_state)(struct pnv_phb *phb, int pe_no); void (*freeze_pe)(struct pnv_phb *phb, int pe_no); int (*unfreeze_pe)(struct pnv_phb *phb, int pe_no, int opt); -- GitLab From 26ba248d52854b267a3d728f2281efa89259eae4 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 19 Jun 2015 12:26:19 +1000 Subject: [PATCH 0741/7006] powerpc/powernv: Pick M64 PEs based on BARs On PHB3, PE might be reserved in advance to reflect the M64 segments consumed by the PE according to M64 BARs (exclude VF BARs) of the PCI devices included in the PE. The PE is picked based on M64 BARs instead of the bridge's M64 windows, which might include VF BARs. Otherwise, wrong PE could be picked. The patch calculates the used M64 segments and PE numbers according to the M64 BARs, excluding VF BARs, of PCI devices in one particular PE, instead of the bridge's M64 windows. Then the right PE number is picked. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 59 +++-------------------- arch/powerpc/platforms/powernv/pci.h | 2 +- 2 files changed, 8 insertions(+), 53 deletions(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 15d9dfcaf840a..70641617ff20d 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -271,35 +271,18 @@ static void pnv_ioda2_reserve_m64_pe(struct pci_bus *bus, } } -static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb, - struct pci_bus *bus, bool all) +static int pnv_ioda2_pick_m64_pe(struct pci_bus *bus, bool all) { - resource_size_t segsz = phb->ioda.m64_segsize; - struct pci_dev *pdev; - struct resource *r; + struct pci_controller *hose = pci_bus_to_host(bus); + struct pnv_phb *phb = hose->private_data; struct pnv_ioda_pe *master_pe, *pe; unsigned long size, *pe_alloc; - bool found; - int start, i, j; + int i; /* Root bus shouldn't use M64 */ if (pci_is_root_bus(bus)) return IODA_INVALID_PE; - /* We support only one M64 window on each bus */ - found = false; - pci_bus_for_each_resource(bus, r, i) { - if (r && r->parent && - pnv_pci_is_mem_pref_64(r->flags)) { - found = true; - break; - } - } - - /* No M64 window found ? */ - if (!found) - return IODA_INVALID_PE; - /* Allocate bitmap */ size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long)); pe_alloc = kzalloc(size, GFP_KERNEL); @@ -309,35 +292,8 @@ static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb, return IODA_INVALID_PE; } - /* - * Figure out reserved PE numbers by the PE - * the its child PEs. - */ - start = (r->start - phb->ioda.m64_base) / segsz; - for (i = 0; i < resource_size(r) / segsz; i++) - set_bit(start + i, pe_alloc); - - if (all) - goto done; - - /* - * If the PE doesn't cover all subordinate buses, - * we need subtract from reserved PEs for children. - */ - list_for_each_entry(pdev, &bus->devices, bus_list) { - if (!pdev->subordinate) - continue; - - pci_bus_for_each_resource(pdev->subordinate, r, i) { - if (!r || !r->parent || - !pnv_pci_is_mem_pref_64(r->flags)) - continue; - - start = (r->start - phb->ioda.m64_base) / segsz; - for (j = 0; j < resource_size(r) / segsz ; j++) - clear_bit(start + j, pe_alloc); - } - } + /* Figure out reserved PE numbers by the PE */ + pnv_ioda2_reserve_m64_pe(bus, pe_alloc, all); /* * the current bus might not own M64 window and that's all @@ -353,7 +309,6 @@ static int pnv_ioda2_pick_m64_pe(struct pnv_phb *phb, * Figure out the master PE and put all slave PEs to master * PE's list to form compound PE. */ -done: master_pe = NULL; i = -1; while ((i = find_next_bit(pe_alloc, phb->ioda.total_pe, i + 1)) < @@ -1073,7 +1028,7 @@ static void pnv_ioda_setup_bus_PE(struct pci_bus *bus, bool all) /* Check if PE is determined by M64 */ if (phb->pick_m64_pe) - pe_num = phb->pick_m64_pe(phb, bus, all); + pe_num = phb->pick_m64_pe(bus, all); /* The PE number isn't pinned by M64 */ if (pe_num == IODA_INVALID_PE) diff --git a/arch/powerpc/platforms/powernv/pci.h b/arch/powerpc/platforms/powernv/pci.h index 5915cd244a5e8..e891ff48d7e69 100644 --- a/arch/powerpc/platforms/powernv/pci.h +++ b/arch/powerpc/platforms/powernv/pci.h @@ -112,7 +112,7 @@ struct pnv_phb { int (*init_m64)(struct pnv_phb *phb); void (*reserve_m64_pe)(struct pci_bus *bus, unsigned long *pe_bitmap, bool all); - int (*pick_m64_pe)(struct pnv_phb *phb, struct pci_bus *bus, bool all); + int (*pick_m64_pe)(struct pci_bus *bus, bool all); int (*get_pe_state)(struct pnv_phb *phb, int pe_no); void (*freeze_pe)(struct pnv_phb *phb, int pe_no); int (*unfreeze_pe)(struct pnv_phb *phb, int pe_no, int opt); -- GitLab From 283e2d8a594bc902d0c830bb324c15d5be755900 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Mon, 22 Jun 2015 13:45:47 +1000 Subject: [PATCH 0742/7006] powerpc/powernv: Include VF PE in PELTV of PF PE The PELTV of PF PE should include VF PE, which is missed by current code, so that the VF PE is frozen automatically when freezing PF PE. The patch fixes the PELTV of PF PE to include VF PE. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 70641617ff20d..e1ea449e48118 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -622,7 +622,7 @@ static int pnv_ioda_set_peltv(struct pnv_phb *phb, pdev = pe->pdev->bus->self; #ifdef CONFIG_PCI_IOV else if (pe->flags & PNV_IODA_PE_VF) - pdev = pe->parent_dev->bus->self; + pdev = pe->parent_dev; #endif /* CONFIG_PCI_IOV */ while (pdev) { struct pci_dn *pdn = pci_get_pdn(pdev); -- GitLab From f951e51003860705fc9fc663fbce90f8263a6804 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 23 Jun 2015 17:01:13 +1000 Subject: [PATCH 0743/7006] powerpc/powernv: Unfreeze VF PE on releasing it When releasing PE for SRIOV VF, the PE is forced to be frozen wrongly. When the same PE is picked for another VF, it won't work anyhow. The patch fixes the issue by unfreezing, not freezing the VF PE when releasing it. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index e1ea449e48118..fdafbaccafbe4 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -701,7 +701,7 @@ static int pnv_ioda_deconfigure_pe(struct pnv_phb *phb, struct pnv_ioda_pe *pe) parent = parent->bus->self; } - opal_pci_eeh_freeze_set(phb->opal_id, pe->pe_number, + opal_pci_eeh_freeze_clear(phb->opal_id, pe->pe_number, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); /* Disassociate PE in PELT */ -- GitLab From c5e0688cc75e46b0e9be39224d8e4646593ef375 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:19 +0530 Subject: [PATCH 0744/7006] drm/i915/skl: Retrieve the Rpe value from Pcode Read the efficient frequency (aka RPe) value through the the mailbox command (0x1A) from the pcode, as done on Haswell and Broadwell. The turbo minimum frequency softlimit is not revised as per the efficient frequency value. v2: Replaced the conditional expression operator with 'if' statement (Tom) v3: Corrected the derivation of efficient frequency & shifted the GEN9_FREQ_SCALER multiplications downwards (Ville) Issue: VIZ-5143 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 4e24d2b13e4c5..ca82ad23e3f83 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4703,18 +4703,11 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) dev_priv->rps.min_freq = (rp_state_cap >> 16) & 0xff; } - if (IS_SKYLAKE(dev)) { - /* Store the frequency values in 16.66 MHZ units, which is - the natural hardware unit for SKL */ - dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER; - dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER; - dev_priv->rps.min_freq *= GEN9_FREQ_SCALER; - } /* hw_max = RP0 until we check for overclocking */ dev_priv->rps.max_freq = dev_priv->rps.rp0_freq; dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) { + if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) { ret = sandybridge_pcode_read(dev_priv, HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL, &ddcc_status); @@ -4726,6 +4719,16 @@ static void gen6_init_rps_frequencies(struct drm_device *dev) dev_priv->rps.max_freq); } + if (IS_SKYLAKE(dev)) { + /* Store the frequency values in 16.66 MHZ units, which is + the natural hardware unit for SKL */ + dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.rp1_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.min_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.max_freq *= GEN9_FREQ_SCALER; + dev_priv->rps.efficient_freq *= GEN9_FREQ_SCALER; + } + dev_priv->rps.idle_freq = dev_priv->rps.min_freq; /* Preserve min/max settings in case of re-init */ -- GitLab From 4c8c7743b53fb169ef2cb07a9eaa80c1b6c1d04e Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:20 +0530 Subject: [PATCH 0745/7006] drm/i915/skl: Ring frequency table programming changes Ring frequency table programming changes for SKL. No need for a floor on ring frequency, as the issue of performance impact with ring running below DDR frequency, is believed to be fixed on SKL v2: Removed the check for avoiding ring frequency programming for BXT (Rodrigo) Issue: VIZ-5144 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index ca82ad23e3f83..9d98f4074eaea 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5021,6 +5021,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev) int min_freq = 15; unsigned int gpu_freq; unsigned int max_ia_freq, min_ring_freq; + unsigned int max_gpu_freq, min_gpu_freq; int scaling_factor = 180; struct cpufreq_policy *policy; @@ -5045,17 +5046,31 @@ static void __gen6_update_ring_freq(struct drm_device *dev) /* convert DDR frequency from units of 266.6MHz to bandwidth */ min_ring_freq = mult_frac(min_ring_freq, 8, 3); + if (IS_SKYLAKE(dev)) { + /* Convert GT frequency to 50 HZ units */ + min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER; + max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER; + } else { + min_gpu_freq = dev_priv->rps.min_freq; + max_gpu_freq = dev_priv->rps.max_freq; + } + /* * For each potential GPU frequency, load a ring frequency we'd like * to use for memory access. We do this by specifying the IA frequency * the PCU should use as a reference to determine the ring frequency. */ - for (gpu_freq = dev_priv->rps.max_freq; gpu_freq >= dev_priv->rps.min_freq; - gpu_freq--) { - int diff = dev_priv->rps.max_freq - gpu_freq; + for (gpu_freq = max_gpu_freq; gpu_freq >= min_gpu_freq; gpu_freq--) { + int diff = max_gpu_freq - gpu_freq; unsigned int ia_freq = 0, ring_freq = 0; - if (INTEL_INFO(dev)->gen >= 8) { + if (IS_SKYLAKE(dev)) { + /* + * ring_freq = 2 * GT. ring_freq is in 100MHz units + * No floor required for ring frequency on SKL. + */ + ring_freq = gpu_freq; + } else if (INTEL_INFO(dev)->gen >= 8) { /* max(2 * GT, DDR). NB: GT is 50MHz units */ ring_freq = max(min_ring_freq, gpu_freq); } else if (IS_HASWELL(dev)) { -- GitLab From f936ec34dea8da6f38340c1ae2cb35207d8d78cb Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:22 +0530 Subject: [PATCH 0746/7006] drm/i915/skl: Updated the i915_ring_freq_table debugfs function Updated the i915_ring_freq_table debugfs function to support the read of ring frequency table, through Punit interface, for SKL also. Issue: VIZ-5144 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 73aaea22bbef1..27f0a0d98e3ac 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1782,6 +1782,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) struct drm_i915_private *dev_priv = dev->dev_private; int ret = 0; int gpu_freq, ia_freq; + unsigned int max_gpu_freq, min_gpu_freq; if (!(IS_GEN6(dev) || IS_GEN7(dev))) { seq_puts(m, "unsupported on this chipset\n"); @@ -1796,17 +1797,27 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) if (ret) goto out; + if (IS_SKYLAKE(dev)) { + /* Convert GT frequency to 50 HZ units */ + min_gpu_freq = + dev_priv->rps.min_freq_softlimit / GEN9_FREQ_SCALER; + max_gpu_freq = + dev_priv->rps.max_freq_softlimit / GEN9_FREQ_SCALER; + } else { + min_gpu_freq = dev_priv->rps.min_freq_softlimit; + max_gpu_freq = dev_priv->rps.max_freq_softlimit; + } + seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n"); - for (gpu_freq = dev_priv->rps.min_freq_softlimit; - gpu_freq <= dev_priv->rps.max_freq_softlimit; - gpu_freq++) { + for (gpu_freq = min_gpu_freq; gpu_freq <= max_gpu_freq; gpu_freq++) { ia_freq = gpu_freq; sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_MIN_FREQ_TABLE, &ia_freq); seq_printf(m, "%d\t\t%d\t\t\t\t%d\n", - intel_gpu_freq(dev_priv, gpu_freq), + intel_gpu_freq(dev_priv, (gpu_freq * + (IS_SKYLAKE(dev) ? GEN9_FREQ_SCALER : 1))), ((ia_freq >> 0) & 0xff) * 100, ((ia_freq >> 8) & 0xff) * 100); } -- GitLab From b8afb9113c519a8bd742f7df8c424b0af69a75cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 29 Jun 2015 15:25:48 +0300 Subject: [PATCH 0747/7006] drm/i915: Keep GMCH DPLL VGA mode always disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We disable the DPLL VGA mode when enabling the DPLL, but we enaable it again when disabling the DPLL. Having VGA mode enabled even in unused DPLLs can cause problems for CHV, so it seems wiser to always keep it disabled. And let's just do that on all GMCH platforms to keep things as similar as possible between them. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 8 +++++--- drivers/gpu/drm/i915/intel_dsi.c | 2 +- drivers/gpu/drm/i915/intel_runtime_pm.c | 8 ++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c465a52a38bc0..59986377ba8ac 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1790,13 +1790,13 @@ static void i9xx_disable_pll(struct intel_crtc *crtc) /* Make sure the pipe isn't still relying on us */ assert_pipe_disabled(dev_priv, pipe); - I915_WRITE(DPLL(pipe), 0); + I915_WRITE(DPLL(pipe), DPLL_VGA_MODE_DIS); POSTING_READ(DPLL(pipe)); } static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) { - u32 val = 0; + u32 val; /* Make sure the pipe isn't still relying on us */ assert_pipe_disabled(dev_priv, pipe); @@ -1805,6 +1805,7 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) * Leave integrated clock source and reference clock enabled for pipe B. * The latter is needed for VGA hotplug / manual detection. */ + val = DPLL_VGA_MODE_DIS; if (pipe == PIPE_B) val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), val); @@ -1821,7 +1822,8 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) assert_pipe_disabled(dev_priv, pipe); /* Set PLL en = 0 */ - val = DPLL_SSC_REF_CLOCK_CHV | DPLL_REFA_CLK_ENABLE_VLV; + val = DPLL_SSC_REF_CLOCK_CHV | + DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; if (pipe != PIPE_A) val |= DPLL_INTEGRATED_CRI_CLK_VLV; I915_WRITE(DPLL(pipe), val); diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 98998e976dbba..5381ddcc2a796 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -418,7 +418,7 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* update the hw state for DPLL */ intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV | - DPLL_REFA_CLK_ENABLE_VLV; + DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; tmp = I915_READ(DSPCLK_GATE_D); tmp |= DPOUNIT_CLOCK_GATE_DISABLE; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 1a45385f4d669..f0e6f49ee33a7 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -882,7 +882,7 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, * display and the reference clock for VGA * hotplug / manual detection. */ - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ @@ -933,13 +933,13 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, */ if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { phy = DPIO_PHY0; - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV); - I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | + I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } else { phy = DPIO_PHY1; - I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | + I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | DPLL_VGA_MODE_DIS | DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ -- GitLab From 60bfe44f83c0a9d7293e821c4ddae3770d60acf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 29 Jun 2015 15:25:49 +0300 Subject: [PATCH 0748/7006] drm/i915: Apply OCD to VLV/CHV DPLL defines MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the spurious 'A' from the VLV/CHV ref clock enable define, and add the "REF" to the VLV ref clock selection bit. Also s/CLOCK/CLK/ for extra consistency. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 6 +++--- drivers/gpu/drm/i915/intel_display.c | 14 +++++++------- drivers/gpu/drm/i915/intel_dsi.c | 6 +++--- drivers/gpu/drm/i915/intel_runtime_pm.c | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 1c4d7894b429a..0650a3d8a40f8 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -2150,7 +2150,7 @@ enum skl_disp_power_wells { #define DPLL_DVO_2X_MODE (1 << 30) #define DPLL_EXT_BUFFER_ENABLE_VLV (1 << 30) #define DPLL_SYNCLOCK_ENABLE (1 << 29) -#define DPLL_REFA_CLK_ENABLE_VLV (1 << 29) +#define DPLL_REF_CLK_ENABLE_VLV (1 << 29) #define DPLL_VGA_MODE_DIS (1 << 28) #define DPLLB_MODE_DAC_SERIAL (1 << 26) /* i915 */ #define DPLLB_MODE_LVDS (2 << 26) /* i915 */ @@ -2164,8 +2164,8 @@ enum skl_disp_power_wells { #define DPLL_FPA01_P1_POST_DIV_MASK_PINEVIEW 0x00ff8000 /* Pineview */ #define DPLL_LOCK_VLV (1<<15) #define DPLL_INTEGRATED_CRI_CLK_VLV (1<<14) -#define DPLL_INTEGRATED_CLOCK_VLV (1<<13) -#define DPLL_SSC_REF_CLOCK_CHV (1<<13) +#define DPLL_INTEGRATED_REF_CLK_VLV (1<<13) +#define DPLL_SSC_REF_CLK_CHV (1<<13) #define DPLL_PORTC_READY_MASK (0xf << 4) #define DPLL_PORTB_READY_MASK (0xf) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 59986377ba8ac..a7482ab140e1a 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1807,7 +1807,7 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) */ val = DPLL_VGA_MODE_DIS; if (pipe == PIPE_B) - val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV; + val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REF_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), val); POSTING_READ(DPLL(pipe)); @@ -1822,8 +1822,8 @@ static void chv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe) assert_pipe_disabled(dev_priv, pipe); /* Set PLL en = 0 */ - val = DPLL_SSC_REF_CLOCK_CHV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + val = DPLL_SSC_REF_CLK_CHV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; if (pipe != PIPE_A) val |= DPLL_INTEGRATED_CRI_CLK_VLV; I915_WRITE(DPLL(pipe), val); @@ -7224,8 +7224,8 @@ static void vlv_compute_dpll(struct intel_crtc *crtc, * clock for pipe B, since VGA hotplug / manual detection depends * on it. */ - dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV | - DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV; + dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REF_CLK_ENABLE_VLV | + DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_REF_CLK_VLV; /* We should never disable this, set it here for state tracking */ if (crtc->pipe == PIPE_B) dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; @@ -7331,8 +7331,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, static void chv_compute_dpll(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config) { - pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | + pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLK_CHV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS | DPLL_VCO_ENABLE; if (crtc->pipe != PIPE_A) pipe_config->dpll_hw_state.dpll |= DPLL_INTEGRATED_CRI_CLK_VLV; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 5381ddcc2a796..f4438eb5b4587 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -413,12 +413,12 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* Disable DPOunit clock gating, can stall pipe * and we need DPLL REFA always enabled */ tmp = I915_READ(DPLL(pipe)); - tmp |= DPLL_REFA_CLK_ENABLE_VLV; + tmp |= DPLL_REF_CLK_ENABLE_VLV; I915_WRITE(DPLL(pipe), tmp); /* update the hw state for DPLL */ - intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; + intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_REF_CLK_VLV | + DPLL_REF_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS; tmp = I915_READ(DSPCLK_GATE_D); tmp |= DPOUNIT_CLOCK_GATE_DISABLE; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index f0e6f49ee33a7..932d96332eca1 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -883,7 +883,7 @@ static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, * hotplug / manual detection. */ I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ vlv_set_power_well(dev_priv, power_well, true); @@ -934,13 +934,13 @@ static void chv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, if (power_well->data == PUNIT_POWER_WELL_DPIO_CMN_BC) { phy = DPIO_PHY0; I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV); + DPLL_REF_CLK_ENABLE_VLV); I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } else { phy = DPIO_PHY1; I915_WRITE(DPLL(PIPE_C), I915_READ(DPLL(PIPE_C)) | DPLL_VGA_MODE_DIS | - DPLL_REFA_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); + DPLL_REF_CLK_ENABLE_VLV | DPLL_INTEGRATED_CRI_CLK_VLV); } udelay(1); /* >10ns for cmnreset, >0ns for sidereset */ vlv_set_power_well(dev_priv, power_well, true); -- GitLab From 8fcd5cd8b3cb29019937ab4b773da27a37e8e79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 29 Jun 2015 15:25:50 +0300 Subject: [PATCH 0749/7006] drm/i915: Simplify CHV pipe A power well code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipe A power well is the "disp2d" well on CHV and pipe B and C wells don't even exist. Thereforce we can remove the checks for pipe A vs. others and just assume it's always pipe A. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 47 +++++++++++-------------- 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 932d96332eca1..1bd947ad21631 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1042,53 +1042,46 @@ out: static void chv_pipe_power_well_sync_hw(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { + WARN_ON_ONCE(power_well->data != PIPE_A); + chv_set_pipe_power_well(dev_priv, power_well, power_well->count > 0); } static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->data != PIPE_A && - power_well->data != PIPE_B && - power_well->data != PIPE_C); + WARN_ON_ONCE(power_well->data != PIPE_A); chv_set_pipe_power_well(dev_priv, power_well, true); - if (power_well->data == PIPE_A) { - spin_lock_irq(&dev_priv->irq_lock); - valleyview_enable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); + spin_lock_irq(&dev_priv->irq_lock); + valleyview_enable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); - /* - * During driver initialization/resume we can avoid restoring the - * part of the HW/SW state that will be inited anyway explicitly. - */ - if (dev_priv->power_domains.initializing) - return; + /* + * During driver initialization/resume we can avoid restoring the + * part of the HW/SW state that will be inited anyway explicitly. + */ + if (dev_priv->power_domains.initializing) + return; - intel_hpd_init(dev_priv); + intel_hpd_init(dev_priv); - i915_redisable_vga_power_on(dev_priv->dev); - } + i915_redisable_vga_power_on(dev_priv->dev); } static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { - WARN_ON_ONCE(power_well->data != PIPE_A && - power_well->data != PIPE_B && - power_well->data != PIPE_C); - - if (power_well->data == PIPE_A) { - spin_lock_irq(&dev_priv->irq_lock); - valleyview_disable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); - } + WARN_ON_ONCE(power_well->data != PIPE_A); + + spin_lock_irq(&dev_priv->irq_lock); + valleyview_disable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); chv_set_pipe_power_well(dev_priv, power_well, false); - if (power_well->data == PIPE_A) - vlv_power_sequencer_reset(dev_priv); + vlv_power_sequencer_reset(dev_priv); } /** -- GitLab From 2be7d540fde3f82e404cbddeeb2fdf05cf33af3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 29 Jun 2015 15:25:51 +0300 Subject: [PATCH 0750/7006] drm/i915: Refactor VLV display power well init/deinit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We do the exact same steps around the disp2d/pipe A power well enable/disable on VLV and CHV. Refactor the shared code into some helpers. Note that this means we now call vlv_power_sequencer_reset() before turning off the power well, whereas before we did it after. That doesn't matter though since vlv_power_sequencer_reset() just resets the power sequencer software tracking and doesn't touch the hardware at all. Signed-off-by: Ville Syrjälä Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_runtime_pm.c | 52 +++++++++++-------------- 1 file changed, 23 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 1bd947ad21631..6393b76f87ffa 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -835,12 +835,8 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, return enabled; } -static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, - struct i915_power_well *power_well) +static void vlv_display_power_well_init(struct drm_i915_private *dev_priv) { - WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D); - - vlv_set_power_well(dev_priv, power_well, true); spin_lock_irq(&dev_priv->irq_lock); valleyview_enable_display_irqs(dev_priv); @@ -858,18 +854,33 @@ static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, i915_redisable_vga_power_on(dev_priv->dev); } +static void vlv_display_power_well_deinit(struct drm_i915_private *dev_priv) +{ + spin_lock_irq(&dev_priv->irq_lock); + valleyview_disable_display_irqs(dev_priv); + spin_unlock_irq(&dev_priv->irq_lock); + + vlv_power_sequencer_reset(dev_priv); +} + +static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv, + struct i915_power_well *power_well) +{ + WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D); + + vlv_set_power_well(dev_priv, power_well, true); + + vlv_display_power_well_init(dev_priv); +} + static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv, struct i915_power_well *power_well) { WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D); - spin_lock_irq(&dev_priv->irq_lock); - valleyview_disable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); + vlv_display_power_well_deinit(dev_priv); vlv_set_power_well(dev_priv, power_well, false); - - vlv_power_sequencer_reset(dev_priv); } static void vlv_dpio_cmn_power_well_enable(struct drm_i915_private *dev_priv, @@ -1054,20 +1065,7 @@ static void chv_pipe_power_well_enable(struct drm_i915_private *dev_priv, chv_set_pipe_power_well(dev_priv, power_well, true); - spin_lock_irq(&dev_priv->irq_lock); - valleyview_enable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); - - /* - * During driver initialization/resume we can avoid restoring the - * part of the HW/SW state that will be inited anyway explicitly. - */ - if (dev_priv->power_domains.initializing) - return; - - intel_hpd_init(dev_priv); - - i915_redisable_vga_power_on(dev_priv->dev); + vlv_display_power_well_init(dev_priv); } static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, @@ -1075,13 +1073,9 @@ static void chv_pipe_power_well_disable(struct drm_i915_private *dev_priv, { WARN_ON_ONCE(power_well->data != PIPE_A); - spin_lock_irq(&dev_priv->irq_lock); - valleyview_disable_display_irqs(dev_priv); - spin_unlock_irq(&dev_priv->irq_lock); + vlv_display_power_well_deinit(dev_priv); chv_set_pipe_power_well(dev_priv, power_well, false); - - vlv_power_sequencer_reset(dev_priv); } /** -- GitLab From 5e6ccc0b3d16725028caccceb2460fc3473d7d55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Mon, 6 Jul 2015 14:44:11 +0300 Subject: [PATCH 0751/7006] drm/i915: Adjust BXT HDMI port clock limits MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit e62925567c7926e78bc8ca976cde5c28ea265a49 Author: Vandana Kannan Date: Wed Jul 1 17:02:57 2015 +0530 drm/i915/bxt: BUNs related to port PLL BXT DPLL can now generate frequencies in the 216-223 MHz range. Adjust the HDMI port clock checks to account for the reduced range of invalid frequencies. Cc: Vandana Kannan Cc: Imre Deak Signed-off-by: Ville Syrjälä Reviewed-by: Imre Deak Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hdmi.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index c7e912bafb876..70bad5bf1d48b 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1174,9 +1174,12 @@ hdmi_port_clock_valid(struct intel_hdmi *hdmi, if (clock > hdmi_port_clock_limit(hdmi, respect_dvi_limit)) return MODE_CLOCK_HIGH; - /* CHV/BXT DPLL can't generate 216-240 MHz */ - if ((IS_CHERRYVIEW(dev) || IS_BROXTON(dev)) && - clock > 216000 && clock < 240000) + /* BXT DPLL can't generate 223-240 MHz */ + if (IS_BROXTON(dev) && clock > 223333 && clock < 240000) + return MODE_CLOCK_RANGE; + + /* CHV DPLL can't generate 216-240 MHz */ + if (IS_CHERRYVIEW(dev) && clock > 216000 && clock < 240000) return MODE_CLOCK_RANGE; return MODE_OK; -- GitLab From feecb691007831263e6285a25a323f175a081f42 Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Fri, 10 Jul 2015 12:30:43 +0530 Subject: [PATCH 0752/7006] drm/i915: storm detection documentation update Update the hotplug documentation to explain that hotplug storm is not expected for Display port panels and hence is not handled in current code. v2: update the statements as recommended by Daniel Signed-off-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_hotplug.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index bac91a158ca2e..3c9171f115310 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -66,6 +66,14 @@ * while before being re-enabled. The intention is to mitigate issues raising * from broken hardware triggering massive amounts of interrupts and grinding * the system to a halt. + * + * Current implementation expects that hotplug interrupt storm will not be + * seen when display port sink is connected, hence on platforms whose DP + * callback is handled by i915_digport_work_func reenabling of hpd is not + * performed (it was never expected to be disabled in the first place ;) ) + * this is specific to DP sinks handled by this routine and any other display + * such as HDMI or DVI enabled on the same port will have proper logic since + * it will use i915_hotplug_work_func where this logic is handled. */ enum port intel_hpd_pin_to_port(enum hpd_pin pin) -- GitLab From cd25dd5b766858b730af00d5b2bbaf6ad2b80c27 Mon Sep 17 00:00:00 2001 From: Deepak S Date: Fri, 10 Jul 2015 18:31:40 +0530 Subject: [PATCH 0753/7006] drm/i915: Update PM interrupts before updating the freq Currently we update the freq before masking the interrupts, which can allow new interrupts to occur before the frequency has changed. These extra interrupts might waste some cpu cycles. This patch corrects this by masking interrupts prior to updating the frequency. Note from Chris: "Well it won't waste CPU cycles as the interrupt is also masked by the threshold limits, but there should be no harm at all in reordering the patch so, and it does make a certain amount of sense." Signed-off-by: Deepak S Signed-off-by: Praveen Paneri Reviewed-by: Chris Wilson [danvet: Add note from Chris.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 9d98f4074eaea..135fb974dfff0 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4482,14 +4482,14 @@ static void valleyview_set_rps(struct drm_device *dev, u8 val) "Odd GPU freq value\n")) val &= ~1; + I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val)); + if (val != dev_priv->rps.cur_freq) { vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val); if (!IS_CHERRYVIEW(dev_priv)) gen6_set_rps_thresholds(dev_priv, val); } - I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val)); - dev_priv->rps.cur_freq = val; trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val)); } -- GitLab From 04dc91ce2cca5927159c689aa1f47663f8c51530 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:44 +0200 Subject: [PATCH 0754/7006] regmap: Add better support for devices without readback support Currently regmap requires that a reg_read callback is supplied, otherwise a warning is emitted each time regmap_read() is called. This means a device or bus without readback support needs to supply dummy reg_read callback. Apart from that regmap_read() will still work fine if a cache is used. Remove the warning and let regmap_readable() return false if not reg_read callback is supplied. This means a device no longer has to supply a dummy callback if it does not support readback and it also doesn't have to have a readable_reg callback that always returns false since this is now implicit. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f26218..8894b992043e0 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -93,6 +93,9 @@ bool regmap_writeable(struct regmap *map, unsigned int reg) bool regmap_readable(struct regmap *map, unsigned int reg) { + if (!map->reg_read) + return false; + if (map->max_register && reg > map->max_register) return false; @@ -2097,8 +2100,6 @@ static int _regmap_read(struct regmap *map, unsigned int reg, int ret; void *context = _regmap_map_get_context(map); - WARN_ON(!map->reg_read); - if (!map->cache_bypass) { ret = regcache_read(map, reg, val); if (ret == 0) -- GitLab From f15c444e58ed5b5dfc6056249ef8a74d00118be3 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:45 +0200 Subject: [PATCH 0755/7006] ASoC: uda134x: Move state struct allocation to bus probe Resource allocations should be done in the bus probe rather than the CODEC probe. Move the allocation of the drivers state struct there. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index 913edf2832399..a89f98a773d66 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -478,8 +478,8 @@ static struct snd_soc_dai_driver uda134x_dai = { static int uda134x_soc_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct uda134x_priv *uda134x; struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); const struct snd_soc_dapm_widget *widgets; unsigned num_widgets; @@ -506,10 +506,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) return -EINVAL; } - uda134x = kzalloc(sizeof(struct uda134x_priv), GFP_KERNEL); - if (uda134x == NULL) - return -ENOMEM; - snd_soc_codec_set_drvdata(codec, uda134x); codec->control_data = pd; @@ -530,7 +526,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) if (ret) { printk(KERN_ERR "%s failed to register dapm controls: %d", __func__, ret); - kfree(uda134x); return ret; } @@ -551,31 +546,19 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) default: printk(KERN_ERR "%s unknown codec type: %d", __func__, pd->model); - kfree(uda134x); return -EINVAL; } if (ret < 0) { printk(KERN_ERR "UDA134X: failed to register controls\n"); - kfree(uda134x); return ret; } return 0; } -/* power down chip */ -static int uda134x_soc_remove(struct snd_soc_codec *codec) -{ - struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - - kfree(uda134x); - return 0; -} - static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, - .remove = uda134x_soc_remove, .reg_cache_size = sizeof(uda134x_reg), .reg_word_size = sizeof(u8), .reg_cache_default = uda134x_reg, @@ -592,6 +575,14 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { static int uda134x_codec_probe(struct platform_device *pdev) { + struct uda134x_priv *uda134x; + + uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL); + if (!uda134x) + return -ENOMEM; + + platform_set_drvdata(pdev, uda134x); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_uda134x, &uda134x_dai, 1); } -- GitLab From 82c7b531f3328dbbb7a53d0f1dc53b92846c411c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:46 +0200 Subject: [PATCH 0756/7006] ASoC: uda134x: Explicitly handle in-data addresses The UDA134X family extends the rather limited L3 register set by using part of the register value as additional address bits. These extra address bits are currently stored in the default register cache and rely on them remaining constant. While this works it is rather idiomatic and slightly confusing. Change it so that the additional address bits are explicitly added when writing a register. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index a89f98a773d66..d47da0ec8f479 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -39,12 +39,11 @@ struct uda134x_priv { struct snd_pcm_substream *slave_substream; }; -/* In-data addresses are hard-coded into the reg-cache values */ static const char uda134x_reg[UDA134X_REGS_NUM] = { /* Extended address registers */ 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, /* Status, data regs */ - 0x00, 0x83, 0x00, 0x40, 0x80, 0xC0, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, }; /* @@ -99,12 +98,14 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, case UDA134X_STATUS0: case UDA134X_STATUS1: addr = UDA134X_STATUS_ADDR; + data |= (reg - UDA134X_STATUS0) << 7; break; case UDA134X_DATA000: case UDA134X_DATA001: case UDA134X_DATA010: case UDA134X_DATA011: addr = UDA134X_DATA0_ADDR; + data |= (reg - UDA134X_DATA000) << 6; break; case UDA134X_DATA1: addr = UDA134X_DATA1_ADDR; -- GitLab From f33c340a51e81a2e6af316b1b8b9b769d32ce8b7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:47 +0200 Subject: [PATCH 0757/7006] ASoC: uda134x: Convert to regmap Use regmap rather then the legacy ASoC IO for the uda134x driver. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 115 ++++++++++++++++++++----------------- sound/soc/codecs/uda134x.h | 2 - 2 files changed, 62 insertions(+), 55 deletions(-) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index d47da0ec8f479..d25a9f3968d01 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -37,13 +37,27 @@ struct uda134x_priv { struct snd_pcm_substream *master_substream; struct snd_pcm_substream *slave_substream; + + struct regmap *regmap; + struct uda134x_platform_data *pd; }; -static const char uda134x_reg[UDA134X_REGS_NUM] = { - /* Extended address registers */ - 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, - /* Status, data regs */ - 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, +static const struct reg_default uda134x_reg_defaults[] = { + { UDA134X_EA000, 0x04 }, + { UDA134X_EA001, 0x04 }, + { UDA134X_EA010, 0x04 }, + { UDA134X_EA011, 0x00 }, + { UDA134X_EA100, 0x00 }, + { UDA134X_EA101, 0x00 }, + { UDA134X_EA110, 0x00 }, + { UDA134X_EA111, 0x00 }, + { UDA134X_STATUS0, 0x00 }, + { UDA134X_STATUS1, 0x03 }, + { UDA134X_DATA000, 0x00 }, + { UDA134X_DATA001, 0x00 }, + { UDA134X_DATA010, 0x00 }, + { UDA134X_DATA011, 0x00 }, + { UDA134X_DATA1, 0x00 }, }; /* @@ -52,47 +66,36 @@ static const char uda134x_reg[UDA134X_REGS_NUM] = { static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, unsigned int reg) { - u8 *cache = codec->reg_cache; + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + unsigned int val; + int ret; - if (reg >= UDA134X_REGS_NUM) + ret = regmap_read(uda134x->regmap, reg, &val); + if (ret) return -1; - return cache[reg]; + + return val; } -/* - * Write the register cache - */ -static inline void uda134x_write_reg_cache(struct snd_soc_codec *codec, - u8 reg, unsigned int value) +static void uda134x_write(struct snd_soc_codec *codec, unsigned int reg, + unsigned int val) { - u8 *cache = codec->reg_cache; + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - if (reg >= UDA134X_REGS_NUM) - return; - cache[reg] = value; + regmap_write(uda134x->regmap, reg, val); } /* * Write to the uda134x registers * */ -static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, +static int uda134x_regmap_write(void *context, unsigned int reg, unsigned int value) { + struct uda134x_platform_data *pd = context; int ret; u8 addr; u8 data = value; - struct uda134x_platform_data *pd = codec->control_data; - - pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); - - if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unknown register: reg: %u", - __func__, reg); - return -EINVAL; - } - - uda134x_write_reg_cache(codec, reg, value); switch (reg) { case UDA134X_STATUS0: @@ -325,10 +328,8 @@ static int uda134x_set_dai_fmt(struct snd_soc_dai *codec_dai, static int uda134x_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { - struct uda134x_platform_data *pd = codec->control_data; - int i; - u8 *cache = codec->reg_cache; - + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + struct uda134x_platform_data *pd = uda134x->pd; pr_debug("%s bias level %d\n", __func__, level); switch (level) { @@ -338,17 +339,17 @@ static int uda134x_set_bias_level(struct snd_soc_codec *codec, /* power on */ if (pd->power) { pd->power(1); - /* Sync reg_cache with the hardware */ - for (i = 0; i < ARRAY_SIZE(uda134x_reg); i++) - codec->driver->write(codec, i, *cache++); + regcache_sync(uda134x->regmap); } break; case SND_SOC_BIAS_STANDBY: break; case SND_SOC_BIAS_OFF: /* power off */ - if (pd->power) + if (pd->power) { pd->power(0); + regcache_mark_dirty(uda134x->regmap); + } break; } return 0; @@ -479,21 +480,14 @@ static struct snd_soc_dai_driver uda134x_dai = { static int uda134x_soc_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct uda134x_platform_data *pd = codec->component.card->dev->platform_data; struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + struct uda134x_platform_data *pd = uda134x->pd; const struct snd_soc_dapm_widget *widgets; unsigned num_widgets; - int ret; printk(KERN_INFO "UDA134X SoC Audio Codec\n"); - if (!pd) { - printk(KERN_ERR "UDA134X SoC codec: " - "missing L3 bitbang function\n"); - return -ENODEV; - } - switch (pd->model) { case UDA134X_UDA1340: case UDA134X_UDA1341: @@ -507,9 +501,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) return -EINVAL; } - - codec->control_data = pd; - if (pd->power) pd->power(1); @@ -560,11 +551,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec) static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .probe = uda134x_soc_probe, - .reg_cache_size = sizeof(uda134x_reg), - .reg_word_size = sizeof(u8), - .reg_cache_default = uda134x_reg, - .reg_cache_step = 1, - .read = uda134x_read_reg_cache, .set_bias_level = uda134x_set_bias_level, .suspend_bias_off = true, @@ -574,16 +560,39 @@ static struct snd_soc_codec_driver soc_codec_dev_uda134x = { .num_dapm_routes = ARRAY_SIZE(uda134x_dapm_routes), }; +static const struct regmap_config uda134x_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = UDA134X_DATA1, + .reg_defaults = uda134x_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(uda134x_reg_defaults), + .cache_type = REGCACHE_RBTREE, + + .reg_write = uda134x_regmap_write, +}; + static int uda134x_codec_probe(struct platform_device *pdev) { + struct uda134x_platform_data *pd = pdev->dev.platform_data; struct uda134x_priv *uda134x; + if (!pd) { + dev_err(&pdev->dev, "Missing L3 bitbang function\n"); + return -ENODEV; + } + uda134x = devm_kzalloc(&pdev->dev, sizeof(*uda134x), GFP_KERNEL); if (!uda134x) return -ENOMEM; + uda134x->pd = pd; platform_set_drvdata(pdev, uda134x); + uda134x->regmap = devm_regmap_init(&pdev->dev, NULL, pd, + &uda134x_regmap_config); + if (IS_ERR(uda134x->regmap)) + return PTR_ERR(uda134x->regmap); + return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_uda134x, &uda134x_dai, 1); } diff --git a/sound/soc/codecs/uda134x.h b/sound/soc/codecs/uda134x.h index 9faae06972b32..e41ab38c6f69b 100644 --- a/sound/soc/codecs/uda134x.h +++ b/sound/soc/codecs/uda134x.h @@ -26,8 +26,6 @@ #define UDA134X_DATA011 13 #define UDA134X_DATA1 14 -#define UDA134X_REGS_NUM 15 - #define STATUS0_DAIFMT_MASK (~(7<<1)) #define STATUS0_SYSCLK_MASK (~(3<<4)) -- GitLab From ef3355d22046f4b2c00b0fdf964d6c92fd3f050d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 12:26:48 +0200 Subject: [PATCH 0758/7006] ASoC: uda134x: Use regmap_update_bits() were appropriate Instead of doing the read-modify-update cycle by hand when updating a register use regmap_update_bits(). This also means we can now remove uda134x_read_reg_cache() and uda134x_write() since they are unused. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/uda134x.c | 57 ++++++++++---------------------------- 1 file changed, 14 insertions(+), 43 deletions(-) diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index d25a9f3968d01..e190263805349 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -60,31 +60,6 @@ static const struct reg_default uda134x_reg_defaults[] = { { UDA134X_DATA1, 0x00 }, }; -/* - * The codec has no support for reading its registers except for peak level... - */ -static inline unsigned int uda134x_read_reg_cache(struct snd_soc_codec *codec, - unsigned int reg) -{ - struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - unsigned int val; - int ret; - - ret = regmap_read(uda134x->regmap, reg, &val); - if (ret) - return -1; - - return val; -} - -static void uda134x_write(struct snd_soc_codec *codec, unsigned int reg, - unsigned int val) -{ - struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - - regmap_write(uda134x->regmap, reg, val); -} - /* * Write to the uda134x registers * @@ -137,27 +112,28 @@ static int uda134x_regmap_write(void *context, unsigned int reg, static inline void uda134x_reset(struct snd_soc_codec *codec) { - u8 reset_reg = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - uda134x_write(codec, UDA134X_STATUS0, reset_reg | (1<<6)); + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); + unsigned int mask = 1<<6; + + regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, mask); msleep(1); - uda134x_write(codec, UDA134X_STATUS0, reset_reg & ~(1<<6)); + regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, mask, 0); } static int uda134x_mute(struct snd_soc_dai *dai, int mute) { - struct snd_soc_codec *codec = dai->codec; - u8 mute_reg = uda134x_read_reg_cache(codec, UDA134X_DATA010); + struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(dai->codec); + unsigned int mask = 1<<2; + unsigned int val; pr_debug("%s mute: %d\n", __func__, mute); if (mute) - mute_reg |= (1<<2); + val = mask; else - mute_reg &= ~(1<<2); - - uda134x_write(codec, UDA134X_DATA010, mute_reg); + val = 0; - return 0; + return regmap_update_bits(uda134x->regmap, UDA134X_DATA010, mask, val); } static int uda134x_startup(struct snd_pcm_substream *substream, @@ -209,7 +185,7 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec); - u8 hw_params; + unsigned int hw_params = 0; if (substream == uda134x->slave_substream) { pr_debug("%s ignoring hw_params for slave substream\n", @@ -217,10 +193,6 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, return 0; } - hw_params = uda134x_read_reg_cache(codec, UDA134X_STATUS0); - hw_params &= STATUS0_SYSCLK_MASK; - hw_params &= STATUS0_DAIFMT_MASK; - pr_debug("%s sysclk: %d, rate:%d\n", __func__, uda134x->sysclk, params_rate(params)); @@ -271,9 +243,8 @@ static int uda134x_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - uda134x_write(codec, UDA134X_STATUS0, hw_params); - - return 0; + return regmap_update_bits(uda134x->regmap, UDA134X_STATUS0, + STATUS0_SYSCLK_MASK | STATUS0_DAIFMT_MASK, hw_params); } static int uda134x_set_dai_sysclk(struct snd_soc_dai *codec_dai, -- GitLab From e27d9ee6e709db070145847f9b5f52008f6eab84 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 13 Jul 2015 13:25:34 +0800 Subject: [PATCH 0759/7006] ASoC: sti-sas: Fix checking return value for ERR_PTR Both devm_regmap_init and syscon_regmap_lookup_by_phandle return ERR_PTR on failure. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 32db2c25a33fc..4168b88ba3b15 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -568,17 +568,17 @@ static int sti_sas_driver_probe(struct platform_device *pdev) /* Request the DAC & SPDIF registers memory region */ drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata, drvdata->dev_data->regmap); - if (!drvdata->dac.virt_regmap) { + if (IS_ERR(drvdata->dac.virt_regmap)) { dev_err(&pdev->dev, "audio registers not enabled\n"); - return -EFAULT; + return PTR_ERR(drvdata->dac.virt_regmap); } /* Request the syscon region */ drvdata->dac.regmap = syscon_regmap_lookup_by_phandle(pnode, "st,syscfg"); - if (!drvdata->dac.regmap) { + if (IS_ERR(drvdata->dac.regmap)) { dev_err(&pdev->dev, "syscon registers not available\n"); - return -EFAULT; + return PTR_ERR(drvdata->dac.regmap); } drvdata->spdif.regmap = drvdata->dac.regmap; -- GitLab From 589bef3296317b5507a9a6e2e14fb30dd40ee764 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 13 Jul 2015 13:26:45 +0800 Subject: [PATCH 0760/7006] ASoC: sti-sas: Staticise local symbols Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 4168b88ba3b15..6c0bbe8b495e0 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -238,7 +238,7 @@ static int stih416_dac_probe(struct snd_soc_dai *dai) return 0; } -const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { +static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, @@ -248,7 +248,7 @@ const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DAC Output"), }; -const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { +static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, STIH407_DAC_STANDBY_ANA, 1, NULL, 0), SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL, @@ -256,13 +256,13 @@ const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("DAC Output"), }; -const struct snd_soc_dapm_route stih416_sas_route[] = { +static const struct snd_soc_dapm_route stih416_sas_route[] = { {"DAC Output", NULL, "DAC bandgap"}, {"DAC Output", NULL, "DAC standby ana"}, {"DAC standby ana", NULL, "DAC standby"}, }; -const struct snd_soc_dapm_route stih407_sas_route[] = { +static const struct snd_soc_dapm_route stih407_sas_route[] = { {"DAC Output", NULL, "DAC standby ana"}, {"DAC standby ana", NULL, "DAC standby"}, }; @@ -407,21 +407,21 @@ static int sti_sas_prepare(struct snd_pcm_substream *substream, return 0; } -const struct snd_soc_dai_ops stih416_dac_ops = { +static const struct snd_soc_dai_ops stih416_dac_ops = { .set_fmt = sti_sas_dac_set_fmt, .mute_stream = stih416_sas_dac_mute, .prepare = sti_sas_prepare, .set_sysclk = sti_sas_set_sysclk, }; -const struct snd_soc_dai_ops stih407_dac_ops = { +static const struct snd_soc_dai_ops stih407_dac_ops = { .set_fmt = sti_sas_dac_set_fmt, .mute_stream = stih407_sas_dac_mute, .prepare = sti_sas_prepare, .set_sysclk = sti_sas_set_sysclk, }; -const struct regmap_config stih407_sas_regmap = { +static const struct regmap_config stih407_sas_regmap = { .reg_bits = 32, .val_bits = 32, @@ -434,7 +434,7 @@ const struct regmap_config stih407_sas_regmap = { .reg_write = sti_sas_write_reg, }; -const struct regmap_config stih416_sas_regmap = { +static const struct regmap_config stih416_sas_regmap = { .reg_bits = 32, .val_bits = 32, @@ -447,7 +447,7 @@ const struct regmap_config stih416_sas_regmap = { .reg_write = sti_sas_write_reg, }; -const struct sti_sas_dev_data stih416_data = { +static const struct sti_sas_dev_data stih416_data = { .chipid = CHIPID_STIH416, .regmap = &stih416_sas_regmap, .dac_ops = &stih416_dac_ops, @@ -457,7 +457,7 @@ const struct sti_sas_dev_data stih416_data = { .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), }; -const struct sti_sas_dev_data stih407_data = { +static const struct sti_sas_dev_data stih407_data = { .chipid = CHIPID_STIH407, .regmap = &stih407_sas_regmap, .dac_ops = &stih407_dac_ops, -- GitLab From a2f3a8ca5219651292447f0e1124b3412bc3abff Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 13 Jul 2015 11:53:08 +0100 Subject: [PATCH 0761/7006] ASoC: sti-sas: Remove spurious dependency on SND_SOC_STI Signed-off-by: Mark Brown --- sound/soc/codecs/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 46802eff292e3..e20834818bcb7 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -613,7 +613,6 @@ config SND_SOC_STAC9766 config SND_SOC_STI_SAS tristate "codec Audio support for STI SAS codec" - depends on SND_SOC_STI config SND_SOC_TAS2552 tristate "Texas Instruments TAS2552 Mono Audio amplifier" -- GitLab From 9cae85f5e26fb59e4436e0676a9aceb461f30c63 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sat, 11 Jul 2015 08:18:59 +0800 Subject: [PATCH 0762/7006] ASoC: sti-sas: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/sti-sas.c:616:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index 6c0bbe8b495e0..adc2c3472382c 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -613,7 +613,6 @@ static int sti_sas_driver_remove(struct platform_device *pdev) static struct platform_driver sti_sas_platform_driver = { .driver = { .name = "sti-sas-codec", - .owner = THIS_MODULE, .of_match_table = sti_sas_dev_match, }, .probe = sti_sas_driver_probe, -- GitLab From 7035f3a4e2444490d461f8b17c2275d61fefd980 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Fri, 10 Jul 2015 12:48:21 -0700 Subject: [PATCH 0763/7006] HID: rmi: Write updated F11 control registers after reset When a device is reset the values of control registers will be reset to the defaults. This patch reapplies the control register values set for F11 by the driver. Signed-off-by: Andrew Duggan Tested-by: Gabriele Mazzotta Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 56 +++++++++++++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index af191a265b80f..9a792e725ea39 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -40,6 +40,14 @@ #define RMI_DEVICE BIT(0) #define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) +/* + * retrieve the ctrl registers + * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, + * and there is no way to know if the first 20 bytes are here or not. + * We use only the first 12 bytes, so get only them. + */ +#define RMI_F11_CTRL_REG_COUNT 12 + enum rmi_mode_type { RMI_MODE_OFF = 0, RMI_MODE_ATTN_REPORTS = 1, @@ -116,6 +124,8 @@ struct rmi_data { unsigned int max_y; unsigned int x_size_mm; unsigned int y_size_mm; + bool read_f11_ctrl_regs; + u8 f11_ctrl_regs[RMI_F11_CTRL_REG_COUNT]; unsigned int gpio_led_count; unsigned int button_count; @@ -557,6 +567,18 @@ static int rmi_set_sleep_mode(struct hid_device *hdev, int sleep_mode) static int rmi_suspend(struct hid_device *hdev, pm_message_t message) { + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + u8 buf[RMI_F11_CTRL_REG_COUNT]; + + ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, + RMI_F11_CTRL_REG_COUNT); + if (ret) + hid_warn(hdev, "can not read F11 control registers\n"); + else + memcpy(data->f11_ctrl_regs, buf, RMI_F11_CTRL_REG_COUNT); + + if (!device_may_wakeup(hdev->dev.parent)) return rmi_set_sleep_mode(hdev, RMI_SLEEP_DEEP_SLEEP); @@ -565,6 +587,7 @@ static int rmi_suspend(struct hid_device *hdev, pm_message_t message) static int rmi_post_reset(struct hid_device *hdev) { + struct rmi_data *data = hid_get_drvdata(hdev); int ret; ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); @@ -573,6 +596,14 @@ static int rmi_post_reset(struct hid_device *hdev) return ret; } + if (data->read_f11_ctrl_regs) { + ret = rmi_write_block(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); + if (ret) + hid_warn(hdev, + "can not write F11 control registers after reset\n"); + } + if (!device_may_wakeup(hdev->dev.parent)) { ret = rmi_set_sleep_mode(hdev, RMI_SLEEP_NORMAL); if (ret) { @@ -957,24 +988,23 @@ static int rmi_populate_f11(struct hid_device *hdev) if (has_data40) data->f11.report_size += data->max_fingers * 2; - /* - * retrieve the ctrl registers - * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, - * and there is no way to know if the first 20 bytes are here or not. - * We use only the first 12 bytes, so get only them. - */ - ret = rmi_read_block(hdev, data->f11.control_base_addr, buf, 12); + ret = rmi_read_block(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs, RMI_F11_CTRL_REG_COUNT); if (ret) { hid_err(hdev, "can not read ctrl block of size 11: %d.\n", ret); return ret; } - data->max_x = buf[6] | (buf[7] << 8); - data->max_y = buf[8] | (buf[9] << 8); + /* data->f11_ctrl_regs now contains valid register data */ + data->read_f11_ctrl_regs = true; + + data->max_x = data->f11_ctrl_regs[6] | (data->f11_ctrl_regs[7] << 8); + data->max_y = data->f11_ctrl_regs[8] | (data->f11_ctrl_regs[9] << 8); if (has_dribble) { - buf[0] = buf[0] & ~BIT(6); - ret = rmi_write(hdev, data->f11.control_base_addr, buf); + data->f11_ctrl_regs[0] = data->f11_ctrl_regs[0] & ~BIT(6); + ret = rmi_write(hdev, data->f11.control_base_addr, + data->f11_ctrl_regs); if (ret) { hid_err(hdev, "can not write to control reg 0: %d.\n", ret); @@ -983,9 +1013,9 @@ static int rmi_populate_f11(struct hid_device *hdev) } if (has_palm_detect) { - buf[11] = buf[11] & ~BIT(0); + data->f11_ctrl_regs[11] = data->f11_ctrl_regs[11] & ~BIT(0); ret = rmi_write(hdev, data->f11.control_base_addr + 11, - &buf[11]); + &data->f11_ctrl_regs[11]); if (ret) { hid_err(hdev, "can not write to control reg 11: %d.\n", ret); -- GitLab From 70caee0a3721956a98cb4bfbfa0eaa38c9182e44 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 9 Jul 2015 14:11:51 -0400 Subject: [PATCH 0764/7006] HID: wacom: remove the extra Pen interface for Wacom Bamboo PAD As mentioned in the comment in the code, both the pen and touch data come from the interface tagged as BAMBOO_PAD. The driver re-routes the events for the Pen to the generic HID interface and keeps the ones for the touch through this current interface. Clearing the WACOM_DEVICETYPE_PEN bit removes the extra unused interface added in 2a6cdbd ("HID: wacom: Introduce new 'touch_input' device") and makes the Bamboo PAD to behave like in 4.1. Reviewed-by: Jason Gerecke Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 232da89f4e886..f5a0d3c64520d 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2220,10 +2220,10 @@ void wacom_setup_device_quirks(struct wacom *wacom) * 0, whose HID descriptor has an application usage of 0xFF0D * (i.e., WACOM_VENDORDEFINED_PEN). We route pen packets back * out through the HID_GENERIC device created for interface 1, - * so rewrite this one to be of type BTN_TOOL_FINGER. + * so rewrite this one to be of type WACOM_DEVICETYPE_TOUCH. */ if (features->type == BAMBOO_PAD) - features->device_type |= WACOM_DEVICETYPE_TOUCH; + features->device_type = WACOM_DEVICETYPE_TOUCH; if (wacom->hdev->bus == BUS_BLUETOOTH) features->quirks |= WACOM_QUIRK_BATTERY; -- GitLab From 2259b5bbaac847f9f322659953966ebb53cfd9bc Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Fri, 10 Jul 2015 00:10:21 -0600 Subject: [PATCH 0765/7006] HID: sony: Navigator Axis for L1 button Patch HID report descriptor to add joystick axis for the L1 button (previously missing). Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index ed2f008f84037..69586b3164094 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -296,7 +296,14 @@ static __u8 navigation_rdesc[] = { 0x09, 0x01, /* Usage (Pointer), */ 0x81, 0x02, /* Input (Variable), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x95, 0x20, /* Report Count (26), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x95, 0x01, /* Report Count (1), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x1E, /* Report Count (24), */ 0x81, 0x02, /* Input (Variable), */ 0x75, 0x08, /* Report Size (8), */ 0x95, 0x30, /* Report Count (48), */ -- GitLab From e4ca061275ec6a48b66c6edebe08644e666994c0 Mon Sep 17 00:00:00 2001 From: Patrik Jakobsson Date: Wed, 8 Jul 2015 15:31:52 +0200 Subject: [PATCH 0766/7006] drm/i915: Don't forget to mark crtc as inactive after disable Watermark calculations depend on the intel_crtc->active flag to be set properly. Suspend/resume is broken on SKL and we also get DDB mismatches without this patch. The regression was introduced in: commit eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Author: Maarten Lankhorst Date: Mon Jun 15 12:33:53 2015 +0200 drm/i915: Update less state during modeset. No need to repeatedly call update_watermarks, or update_fbc. Down to a single call to update_watermarks in .crtc_enable Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter v2: Don't touch disable_shared_dpll() Signed-off-by: Patrik Jakobsson Reviewed-by: Maarten Lankhorst Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91203 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a7482ab140e1a..00c60c1c5162e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5049,6 +5049,9 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc) ironlake_fdi_pll_disable(intel_crtc); } + + intel_crtc->active = false; + intel_update_watermarks(crtc); } static void haswell_crtc_disable(struct drm_crtc *crtc) @@ -5094,6 +5097,9 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) for_each_encoder_on_crtc(dev, crtc, encoder) if (encoder->post_disable) encoder->post_disable(encoder); + + intel_crtc->active = false; + intel_update_watermarks(crtc); } static void i9xx_pfit_enable(struct intel_crtc *crtc) @@ -6158,6 +6164,9 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc) if (!IS_GEN2(dev)) intel_set_cpu_fifo_underrun_reporting(dev_priv, pipe, false); + + intel_crtc->active = false; + intel_update_watermarks(crtc); } static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) -- GitLab From 671a2781ff01abf4fdc8904881fc3abd3a8279af Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 10 Jul 2015 17:19:55 -0400 Subject: [PATCH 0767/7006] security: add ioctl specific auditing to lsm_audit Add information about ioctl calls to the LSM audit data. Log the file path and command number. Signed-off-by: Jeff Vander Stoep Acked-by: Nick Kralevich [PM: subject line tweak] Signed-off-by: Paul Moore --- include/linux/lsm_audit.h | 7 +++++++ security/lsm_audit.c | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/linux/lsm_audit.h b/include/linux/lsm_audit.h index 1cc89e9df480c..ffb9c9da4f39f 100644 --- a/include/linux/lsm_audit.h +++ b/include/linux/lsm_audit.h @@ -40,6 +40,11 @@ struct lsm_network_audit { } fam; }; +struct lsm_ioctlop_audit { + struct path path; + u16 cmd; +}; + /* Auxiliary data to use in generating the audit record. */ struct common_audit_data { char type; @@ -53,6 +58,7 @@ struct common_audit_data { #define LSM_AUDIT_DATA_KMOD 8 #define LSM_AUDIT_DATA_INODE 9 #define LSM_AUDIT_DATA_DENTRY 10 +#define LSM_AUDIT_DATA_IOCTL_OP 11 union { struct path path; struct dentry *dentry; @@ -68,6 +74,7 @@ struct common_audit_data { } key_struct; #endif char *kmod_name; + struct lsm_ioctlop_audit *op; } u; /* this union contains LSM specific data */ union { diff --git a/security/lsm_audit.c b/security/lsm_audit.c index 1d34277dc402b..9f6c649c65e92 100644 --- a/security/lsm_audit.c +++ b/security/lsm_audit.c @@ -245,6 +245,21 @@ static void dump_common_audit_data(struct audit_buffer *ab, } break; } + case LSM_AUDIT_DATA_IOCTL_OP: { + struct inode *inode; + + audit_log_d_path(ab, " path=", &a->u.op->path); + + inode = a->u.op->path.dentry->d_inode; + if (inode) { + audit_log_format(ab, " dev="); + audit_log_untrustedstring(ab, inode->i_sb->s_id); + audit_log_format(ab, " ino=%lu", inode->i_ino); + } + + audit_log_format(ab, " ioctlcmd=%hx", a->u.op->cmd); + break; + } case LSM_AUDIT_DATA_DENTRY: { struct inode *inode; -- GitLab From fa1aa143ac4a682c7f5fd52a3cf05f5a6fe44a0a Mon Sep 17 00:00:00 2001 From: Jeff Vander Stoep Date: Fri, 10 Jul 2015 17:19:56 -0400 Subject: [PATCH 0768/7006] selinux: extended permissions for ioctls Add extended permissions logic to selinux. Extended permissions provides additional permissions in 256 bit increments. Extend the generic ioctl permission check to use the extended permissions for per-command filtering. Source/target/class sets including the ioctl permission may additionally include a set of commands. Example: allowxperm : ioctl unpriv_app_socket_cmds auditallowxperm : ioctl priv_gpu_cmds Where unpriv_app_socket_cmds and priv_gpu_cmds are macros representing commonly granted sets of ioctl commands. When ioctl commands are omitted only the permissions are checked. This feature is intended to provide finer granularity for the ioctl permission that may be too imprecise. For example, the same driver may use ioctls to provide important and benign functionality such as driver version or socket type as well as dangerous capabilities such as debugging features, read/write/execute to physical memory or access to sensitive data. Per-command filtering provides a mechanism to reduce the attack surface of the kernel, and limit applications to the subset of commands required. The format of the policy binary has been modified to include ioctl commands, and the policy version number has been incremented to POLICYDB_VERSION_XPERMS_IOCTL=30 to account for the format change. The extended permissions logic is deliberately generic to allow components to be reused e.g. netlink filters Signed-off-by: Jeff Vander Stoep Acked-by: Nick Kralevich Signed-off-by: Paul Moore --- security/selinux/avc.c | 415 +++++++++++++++++++++++++++- security/selinux/hooks.c | 42 ++- security/selinux/include/avc.h | 6 + security/selinux/include/security.h | 32 ++- security/selinux/ss/avtab.c | 104 ++++++- security/selinux/ss/avtab.h | 33 ++- security/selinux/ss/conditional.c | 32 ++- security/selinux/ss/conditional.h | 6 +- security/selinux/ss/policydb.c | 5 + security/selinux/ss/services.c | 213 ++++++++++++-- security/selinux/ss/services.h | 6 + 11 files changed, 834 insertions(+), 60 deletions(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 3c17dda9571d4..2d5e1b04cd502 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -48,6 +49,7 @@ struct avc_entry { u32 tsid; u16 tclass; struct av_decision avd; + struct avc_xperms_node *xp_node; }; struct avc_node { @@ -56,6 +58,16 @@ struct avc_node { struct rcu_head rhead; }; +struct avc_xperms_decision_node { + struct extended_perms_decision xpd; + struct list_head xpd_list; /* list of extended_perms_decision */ +}; + +struct avc_xperms_node { + struct extended_perms xp; + struct list_head xpd_head; /* list head of extended_perms_decision */ +}; + struct avc_cache { struct hlist_head slots[AVC_CACHE_SLOTS]; /* head for avc_node->list */ spinlock_t slots_lock[AVC_CACHE_SLOTS]; /* lock for writes */ @@ -80,6 +92,9 @@ DEFINE_PER_CPU(struct avc_cache_stats, avc_cache_stats) = { 0 }; static struct avc_cache avc_cache; static struct avc_callback_node *avc_callbacks; static struct kmem_cache *avc_node_cachep; +static struct kmem_cache *avc_xperms_data_cachep; +static struct kmem_cache *avc_xperms_decision_cachep; +static struct kmem_cache *avc_xperms_cachep; static inline int avc_hash(u32 ssid, u32 tsid, u16 tclass) { @@ -170,7 +185,17 @@ void __init avc_init(void) atomic_set(&avc_cache.lru_hint, 0); avc_node_cachep = kmem_cache_create("avc_node", sizeof(struct avc_node), - 0, SLAB_PANIC, NULL); + 0, SLAB_PANIC, NULL); + avc_xperms_cachep = kmem_cache_create("avc_xperms_node", + sizeof(struct avc_xperms_node), + 0, SLAB_PANIC, NULL); + avc_xperms_decision_cachep = kmem_cache_create( + "avc_xperms_decision_node", + sizeof(struct avc_xperms_decision_node), + 0, SLAB_PANIC, NULL); + avc_xperms_data_cachep = kmem_cache_create("avc_xperms_data", + sizeof(struct extended_perms_data), + 0, SLAB_PANIC, NULL); audit_log(current->audit_context, GFP_KERNEL, AUDIT_KERNEL, "AVC INITIALIZED\n"); } @@ -205,9 +230,261 @@ int avc_get_hash_stats(char *page) slots_used, AVC_CACHE_SLOTS, max_chain_len); } +/* + * using a linked list for extended_perms_decision lookup because the list is + * always small. i.e. less than 5, typically 1 + */ +static struct extended_perms_decision *avc_xperms_decision_lookup(u8 driver, + struct avc_xperms_node *xp_node) +{ + struct avc_xperms_decision_node *xpd_node; + + list_for_each_entry(xpd_node, &xp_node->xpd_head, xpd_list) { + if (xpd_node->xpd.driver == driver) + return &xpd_node->xpd; + } + return NULL; +} + +static inline unsigned int +avc_xperms_has_perm(struct extended_perms_decision *xpd, + u8 perm, u8 which) +{ + unsigned int rc = 0; + + if ((which == XPERMS_ALLOWED) && + (xpd->used & XPERMS_ALLOWED)) + rc = security_xperm_test(xpd->allowed->p, perm); + else if ((which == XPERMS_AUDITALLOW) && + (xpd->used & XPERMS_AUDITALLOW)) + rc = security_xperm_test(xpd->auditallow->p, perm); + else if ((which == XPERMS_DONTAUDIT) && + (xpd->used & XPERMS_DONTAUDIT)) + rc = security_xperm_test(xpd->dontaudit->p, perm); + return rc; +} + +static void avc_xperms_allow_perm(struct avc_xperms_node *xp_node, + u8 driver, u8 perm) +{ + struct extended_perms_decision *xpd; + security_xperm_set(xp_node->xp.drivers.p, driver); + xpd = avc_xperms_decision_lookup(driver, xp_node); + if (xpd && xpd->allowed) + security_xperm_set(xpd->allowed->p, perm); +} + +static void avc_xperms_decision_free(struct avc_xperms_decision_node *xpd_node) +{ + struct extended_perms_decision *xpd; + + xpd = &xpd_node->xpd; + if (xpd->allowed) + kmem_cache_free(avc_xperms_data_cachep, xpd->allowed); + if (xpd->auditallow) + kmem_cache_free(avc_xperms_data_cachep, xpd->auditallow); + if (xpd->dontaudit) + kmem_cache_free(avc_xperms_data_cachep, xpd->dontaudit); + kmem_cache_free(avc_xperms_decision_cachep, xpd_node); +} + +static void avc_xperms_free(struct avc_xperms_node *xp_node) +{ + struct avc_xperms_decision_node *xpd_node, *tmp; + + if (!xp_node) + return; + + list_for_each_entry_safe(xpd_node, tmp, &xp_node->xpd_head, xpd_list) { + list_del(&xpd_node->xpd_list); + avc_xperms_decision_free(xpd_node); + } + kmem_cache_free(avc_xperms_cachep, xp_node); +} + +static void avc_copy_xperms_decision(struct extended_perms_decision *dest, + struct extended_perms_decision *src) +{ + dest->driver = src->driver; + dest->used = src->used; + if (dest->used & XPERMS_ALLOWED) + memcpy(dest->allowed->p, src->allowed->p, + sizeof(src->allowed->p)); + if (dest->used & XPERMS_AUDITALLOW) + memcpy(dest->auditallow->p, src->auditallow->p, + sizeof(src->auditallow->p)); + if (dest->used & XPERMS_DONTAUDIT) + memcpy(dest->dontaudit->p, src->dontaudit->p, + sizeof(src->dontaudit->p)); +} + +/* + * similar to avc_copy_xperms_decision, but only copy decision + * information relevant to this perm + */ +static inline void avc_quick_copy_xperms_decision(u8 perm, + struct extended_perms_decision *dest, + struct extended_perms_decision *src) +{ + /* + * compute index of the u32 of the 256 bits (8 u32s) that contain this + * command permission + */ + u8 i = perm >> 5; + + dest->used = src->used; + if (dest->used & XPERMS_ALLOWED) + dest->allowed->p[i] = src->allowed->p[i]; + if (dest->used & XPERMS_AUDITALLOW) + dest->auditallow->p[i] = src->auditallow->p[i]; + if (dest->used & XPERMS_DONTAUDIT) + dest->dontaudit->p[i] = src->dontaudit->p[i]; +} + +static struct avc_xperms_decision_node + *avc_xperms_decision_alloc(u8 which) +{ + struct avc_xperms_decision_node *xpd_node; + struct extended_perms_decision *xpd; + + xpd_node = kmem_cache_zalloc(avc_xperms_decision_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!xpd_node) + return NULL; + + xpd = &xpd_node->xpd; + if (which & XPERMS_ALLOWED) { + xpd->allowed = kmem_cache_zalloc(avc_xperms_data_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!xpd->allowed) + goto error; + } + if (which & XPERMS_AUDITALLOW) { + xpd->auditallow = kmem_cache_zalloc(avc_xperms_data_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!xpd->auditallow) + goto error; + } + if (which & XPERMS_DONTAUDIT) { + xpd->dontaudit = kmem_cache_zalloc(avc_xperms_data_cachep, + GFP_ATOMIC | __GFP_NOMEMALLOC); + if (!xpd->dontaudit) + goto error; + } + return xpd_node; +error: + avc_xperms_decision_free(xpd_node); + return NULL; +} + +static int avc_add_xperms_decision(struct avc_node *node, + struct extended_perms_decision *src) +{ + struct avc_xperms_decision_node *dest_xpd; + + node->ae.xp_node->xp.len++; + dest_xpd = avc_xperms_decision_alloc(src->used); + if (!dest_xpd) + return -ENOMEM; + avc_copy_xperms_decision(&dest_xpd->xpd, src); + list_add(&dest_xpd->xpd_list, &node->ae.xp_node->xpd_head); + return 0; +} + +static struct avc_xperms_node *avc_xperms_alloc(void) +{ + struct avc_xperms_node *xp_node; + + xp_node = kmem_cache_zalloc(avc_xperms_cachep, + GFP_ATOMIC|__GFP_NOMEMALLOC); + if (!xp_node) + return xp_node; + INIT_LIST_HEAD(&xp_node->xpd_head); + return xp_node; +} + +static int avc_xperms_populate(struct avc_node *node, + struct avc_xperms_node *src) +{ + struct avc_xperms_node *dest; + struct avc_xperms_decision_node *dest_xpd; + struct avc_xperms_decision_node *src_xpd; + + if (src->xp.len == 0) + return 0; + dest = avc_xperms_alloc(); + if (!dest) + return -ENOMEM; + + memcpy(dest->xp.drivers.p, src->xp.drivers.p, sizeof(dest->xp.drivers.p)); + dest->xp.len = src->xp.len; + + /* for each source xpd allocate a destination xpd and copy */ + list_for_each_entry(src_xpd, &src->xpd_head, xpd_list) { + dest_xpd = avc_xperms_decision_alloc(src_xpd->xpd.used); + if (!dest_xpd) + goto error; + avc_copy_xperms_decision(&dest_xpd->xpd, &src_xpd->xpd); + list_add(&dest_xpd->xpd_list, &dest->xpd_head); + } + node->ae.xp_node = dest; + return 0; +error: + avc_xperms_free(dest); + return -ENOMEM; + +} + +static inline u32 avc_xperms_audit_required(u32 requested, + struct av_decision *avd, + struct extended_perms_decision *xpd, + u8 perm, + int result, + u32 *deniedp) +{ + u32 denied, audited; + + denied = requested & ~avd->allowed; + if (unlikely(denied)) { + audited = denied & avd->auditdeny; + if (audited && xpd) { + if (avc_xperms_has_perm(xpd, perm, XPERMS_DONTAUDIT)) + audited &= ~requested; + } + } else if (result) { + audited = denied = requested; + } else { + audited = requested & avd->auditallow; + if (audited && xpd) { + if (!avc_xperms_has_perm(xpd, perm, XPERMS_AUDITALLOW)) + audited &= ~requested; + } + } + + *deniedp = denied; + return audited; +} + +static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass, + u32 requested, struct av_decision *avd, + struct extended_perms_decision *xpd, + u8 perm, int result, + struct common_audit_data *ad) +{ + u32 audited, denied; + + audited = avc_xperms_audit_required( + requested, avd, xpd, perm, result, &denied); + if (likely(!audited)) + return 0; + return slow_avc_audit(ssid, tsid, tclass, requested, + audited, denied, result, ad, 0); +} + static void avc_node_free(struct rcu_head *rhead) { struct avc_node *node = container_of(rhead, struct avc_node, rhead); + avc_xperms_free(node->ae.xp_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); } @@ -221,6 +498,7 @@ static void avc_node_delete(struct avc_node *node) static void avc_node_kill(struct avc_node *node) { + avc_xperms_free(node->ae.xp_node); kmem_cache_free(avc_node_cachep, node); avc_cache_stats_incr(frees); atomic_dec(&avc_cache.active_nodes); @@ -367,6 +645,7 @@ static int avc_latest_notif_update(int seqno, int is_insert) * @tsid: target security identifier * @tclass: target security class * @avd: resulting av decision + * @xp_node: resulting extended permissions * * Insert an AVC entry for the SID pair * (@ssid, @tsid) and class @tclass. @@ -378,7 +657,9 @@ static int avc_latest_notif_update(int seqno, int is_insert) * the access vectors into a cache entry, returns * avc_node inserted. Otherwise, this function returns NULL. */ -static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd) +static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, + struct av_decision *avd, + struct avc_xperms_node *xp_node) { struct avc_node *pos, *node = NULL; int hvalue; @@ -391,10 +672,15 @@ static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass, struct av_dec if (node) { struct hlist_head *head; spinlock_t *lock; + int rc = 0; hvalue = avc_hash(ssid, tsid, tclass); avc_node_populate(node, ssid, tsid, tclass, avd); - + rc = avc_xperms_populate(node, xp_node); + if (rc) { + kmem_cache_free(avc_node_cachep, node); + return NULL; + } head = &avc_cache.slots[hvalue]; lock = &avc_cache.slots_lock[hvalue]; @@ -523,14 +809,17 @@ out: * @perms : Permission mask bits * @ssid,@tsid,@tclass : identifier of an AVC entry * @seqno : sequence number when decision was made + * @xpd: extended_perms_decision to be added to the node * * if a valid AVC entry doesn't exist,this function returns -ENOENT. * if kmalloc() called internal returns NULL, this function returns -ENOMEM. * otherwise, this function updates the AVC entry. The original AVC-entry object * will release later by RCU. */ -static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, - u32 seqno) +static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid, + u32 tsid, u16 tclass, u32 seqno, + struct extended_perms_decision *xpd, + u32 flags) { int hvalue, rc = 0; unsigned long flag; @@ -574,9 +863,19 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, avc_node_populate(node, ssid, tsid, tclass, &orig->ae.avd); + if (orig->ae.xp_node) { + rc = avc_xperms_populate(node, orig->ae.xp_node); + if (rc) { + kmem_cache_free(avc_node_cachep, node); + goto out_unlock; + } + } + switch (event) { case AVC_CALLBACK_GRANT: node->ae.avd.allowed |= perms; + if (node->ae.xp_node && (flags & AVC_EXTENDED_PERMS)) + avc_xperms_allow_perm(node->ae.xp_node, driver, xperm); break; case AVC_CALLBACK_TRY_REVOKE: case AVC_CALLBACK_REVOKE: @@ -594,6 +893,9 @@ static int avc_update_node(u32 event, u32 perms, u32 ssid, u32 tsid, u16 tclass, case AVC_CALLBACK_AUDITDENY_DISABLE: node->ae.avd.auditdeny &= ~perms; break; + case AVC_CALLBACK_ADD_XPERMS: + avc_add_xperms_decision(node, xpd); + break; } avc_node_replace(node, orig); out_unlock: @@ -665,18 +967,20 @@ int avc_ss_reset(u32 seqno) * results in a bigger stack frame. */ static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, - u16 tclass, struct av_decision *avd) + u16 tclass, struct av_decision *avd, + struct avc_xperms_node *xp_node) { rcu_read_unlock(); - security_compute_av(ssid, tsid, tclass, avd); + INIT_LIST_HEAD(&xp_node->xpd_head); + security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp); rcu_read_lock(); - return avc_insert(ssid, tsid, tclass, avd); + return avc_insert(ssid, tsid, tclass, avd, xp_node); } static noinline int avc_denied(u32 ssid, u32 tsid, - u16 tclass, u32 requested, - unsigned flags, - struct av_decision *avd) + u16 tclass, u32 requested, + u8 driver, u8 xperm, unsigned flags, + struct av_decision *avd) { if (flags & AVC_STRICT) return -EACCES; @@ -684,11 +988,91 @@ static noinline int avc_denied(u32 ssid, u32 tsid, if (selinux_enforcing && !(avd->flags & AVD_FLAGS_PERMISSIVE)) return -EACCES; - avc_update_node(AVC_CALLBACK_GRANT, requested, ssid, - tsid, tclass, avd->seqno); + avc_update_node(AVC_CALLBACK_GRANT, requested, driver, xperm, ssid, + tsid, tclass, avd->seqno, NULL, flags); return 0; } +/* + * The avc extended permissions logic adds an additional 256 bits of + * permissions to an avc node when extended permissions for that node are + * specified in the avtab. If the additional 256 permissions is not adequate, + * as-is the case with ioctls, then multiple may be chained together and the + * driver field is used to specify which set contains the permission. + */ +int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, + u8 driver, u8 xperm, struct common_audit_data *ad) +{ + struct avc_node *node; + struct av_decision avd; + u32 denied; + struct extended_perms_decision local_xpd; + struct extended_perms_decision *xpd = NULL; + struct extended_perms_data allowed; + struct extended_perms_data auditallow; + struct extended_perms_data dontaudit; + struct avc_xperms_node local_xp_node; + struct avc_xperms_node *xp_node; + int rc = 0, rc2; + + xp_node = &local_xp_node; + BUG_ON(!requested); + + rcu_read_lock(); + + node = avc_lookup(ssid, tsid, tclass); + if (unlikely(!node)) { + node = avc_compute_av(ssid, tsid, tclass, &avd, xp_node); + } else { + memcpy(&avd, &node->ae.avd, sizeof(avd)); + xp_node = node->ae.xp_node; + } + /* if extended permissions are not defined, only consider av_decision */ + if (!xp_node || !xp_node->xp.len) + goto decision; + + local_xpd.allowed = &allowed; + local_xpd.auditallow = &auditallow; + local_xpd.dontaudit = &dontaudit; + + xpd = avc_xperms_decision_lookup(driver, xp_node); + if (unlikely(!xpd)) { + /* + * Compute the extended_perms_decision only if the driver + * is flagged + */ + if (!security_xperm_test(xp_node->xp.drivers.p, driver)) { + avd.allowed &= ~requested; + goto decision; + } + rcu_read_unlock(); + security_compute_xperms_decision(ssid, tsid, tclass, driver, + &local_xpd); + rcu_read_lock(); + avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested, driver, xperm, + ssid, tsid, tclass, avd.seqno, &local_xpd, 0); + } else { + avc_quick_copy_xperms_decision(xperm, &local_xpd, xpd); + } + xpd = &local_xpd; + + if (!avc_xperms_has_perm(xpd, xperm, XPERMS_ALLOWED)) + avd.allowed &= ~requested; + +decision: + denied = requested & ~(avd.allowed); + if (unlikely(denied)) + rc = avc_denied(ssid, tsid, tclass, requested, driver, xperm, + AVC_EXTENDED_PERMS, &avd); + + rcu_read_unlock(); + + rc2 = avc_xperms_audit(ssid, tsid, tclass, requested, + &avd, xpd, xperm, rc, ad); + if (rc2) + return rc2; + return rc; +} /** * avc_has_perm_noaudit - Check permissions but perform no auditing. @@ -716,6 +1100,7 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, struct av_decision *avd) { struct avc_node *node; + struct avc_xperms_node xp_node; int rc = 0; u32 denied; @@ -725,13 +1110,13 @@ inline int avc_has_perm_noaudit(u32 ssid, u32 tsid, node = avc_lookup(ssid, tsid, tclass); if (unlikely(!node)) - node = avc_compute_av(ssid, tsid, tclass, avd); + node = avc_compute_av(ssid, tsid, tclass, avd, &xp_node); else memcpy(avd, &node->ae.avd, sizeof(*avd)); denied = requested & ~(avd->allowed); if (unlikely(denied)) - rc = avc_denied(ssid, tsid, tclass, requested, flags, avd); + rc = avc_denied(ssid, tsid, tclass, requested, 0, 0, flags, avd); rcu_read_unlock(); return rc; diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 692e3cc8ce239..a049b72162707 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -3216,6 +3216,46 @@ static void selinux_file_free_security(struct file *file) file_free_security(file); } +/* + * Check whether a task has the ioctl permission and cmd + * operation to an inode. + */ +int ioctl_has_perm(const struct cred *cred, struct file *file, + u32 requested, u16 cmd) +{ + struct common_audit_data ad; + struct file_security_struct *fsec = file->f_security; + struct inode *inode = file_inode(file); + struct inode_security_struct *isec = inode->i_security; + struct lsm_ioctlop_audit ioctl; + u32 ssid = cred_sid(cred); + int rc; + u8 driver = cmd >> 8; + u8 xperm = cmd & 0xff; + + ad.type = LSM_AUDIT_DATA_IOCTL_OP; + ad.u.op = &ioctl; + ad.u.op->cmd = cmd; + ad.u.op->path = file->f_path; + + if (ssid != fsec->sid) { + rc = avc_has_perm(ssid, fsec->sid, + SECCLASS_FD, + FD__USE, + &ad); + if (rc) + goto out; + } + + if (unlikely(IS_PRIVATE(inode))) + return 0; + + rc = avc_has_extended_perms(ssid, isec->sid, isec->sclass, + requested, driver, xperm, &ad); +out: + return rc; +} + static int selinux_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { @@ -3258,7 +3298,7 @@ static int selinux_file_ioctl(struct file *file, unsigned int cmd, * to the file's ioctl() function. */ default: - error = file_has_perm(cred, file, FILE__IOCTL); + error = ioctl_has_perm(cred, file, FILE__IOCTL, (u16) cmd); } return error; } diff --git a/security/selinux/include/avc.h b/security/selinux/include/avc.h index ddf8eec03f211..db12ff14277b2 100644 --- a/security/selinux/include/avc.h +++ b/security/selinux/include/avc.h @@ -142,6 +142,7 @@ static inline int avc_audit(u32 ssid, u32 tsid, } #define AVC_STRICT 1 /* Ignore permissive mode. */ +#define AVC_EXTENDED_PERMS 2 /* update extended permissions */ int avc_has_perm_noaudit(u32 ssid, u32 tsid, u16 tclass, u32 requested, unsigned flags, @@ -151,6 +152,10 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct common_audit_data *auditdata); +int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested, + u8 driver, u8 perm, struct common_audit_data *ad); + + u32 avc_policy_seqno(void); #define AVC_CALLBACK_GRANT 1 @@ -161,6 +166,7 @@ u32 avc_policy_seqno(void); #define AVC_CALLBACK_AUDITALLOW_DISABLE 32 #define AVC_CALLBACK_AUDITDENY_ENABLE 64 #define AVC_CALLBACK_AUDITDENY_DISABLE 128 +#define AVC_CALLBACK_ADD_XPERMS 256 int avc_add_callback(int (*callback)(u32 event), u32 events); diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h index 36993ad1c067a..6a681d26bf20a 100644 --- a/security/selinux/include/security.h +++ b/security/selinux/include/security.h @@ -35,13 +35,14 @@ #define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27 #define POLICYDB_VERSION_DEFAULT_TYPE 28 #define POLICYDB_VERSION_CONSTRAINT_NAMES 29 +#define POLICYDB_VERSION_XPERMS_IOCTL 30 /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE #ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX #define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE #else -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_XPERMS_IOCTL #endif /* Mask for just the mount related flags */ @@ -109,11 +110,38 @@ struct av_decision { u32 flags; }; +#define XPERMS_ALLOWED 1 +#define XPERMS_AUDITALLOW 2 +#define XPERMS_DONTAUDIT 4 + +#define security_xperm_set(perms, x) (perms[x >> 5] |= 1 << (x & 0x1f)) +#define security_xperm_test(perms, x) (1 & (perms[x >> 5] >> (x & 0x1f))) +struct extended_perms_data { + u32 p[8]; +}; + +struct extended_perms_decision { + u8 used; + u8 driver; + struct extended_perms_data *allowed; + struct extended_perms_data *auditallow; + struct extended_perms_data *dontaudit; +}; + +struct extended_perms { + u16 len; /* length associated decision chain */ + struct extended_perms_data drivers; /* flag drivers that are used */ +}; + /* definitions of av_decision.flags */ #define AVD_FLAGS_PERMISSIVE 0x0001 void security_compute_av(u32 ssid, u32 tsid, - u16 tclass, struct av_decision *avd); + u16 tclass, struct av_decision *avd, + struct extended_perms *xperms); + +void security_compute_xperms_decision(u32 ssid, u32 tsid, u16 tclass, + u8 driver, struct extended_perms_decision *xpermd); void security_compute_av_user(u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd); diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index b64f2772b0301..3628d3a868b66 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -24,6 +24,7 @@ #include "policydb.h" static struct kmem_cache *avtab_node_cachep; +static struct kmem_cache *avtab_xperms_cachep; /* Based on MurmurHash3, written by Austin Appleby and placed in the * public domain. @@ -70,11 +71,24 @@ avtab_insert_node(struct avtab *h, int hvalue, struct avtab_key *key, struct avtab_datum *datum) { struct avtab_node *newnode; + struct avtab_extended_perms *xperms; newnode = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); if (newnode == NULL) return NULL; newnode->key = *key; - newnode->datum = *datum; + + if (key->specified & AVTAB_XPERMS) { + xperms = kmem_cache_zalloc(avtab_xperms_cachep, GFP_KERNEL); + if (xperms == NULL) { + kmem_cache_free(avtab_node_cachep, newnode); + return NULL; + } + *xperms = *(datum->u.xperms); + newnode->datum.u.xperms = xperms; + } else { + newnode->datum.u.data = datum->u.data; + } + if (prev) { newnode->next = prev->next; prev->next = newnode; @@ -107,8 +121,12 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat if (key->source_type == cur->key.source_type && key->target_type == cur->key.target_type && key->target_class == cur->key.target_class && - (specified & cur->key.specified)) + (specified & cur->key.specified)) { + /* extended perms may not be unique */ + if (specified & AVTAB_XPERMS) + break; return -EEXIST; + } if (key->source_type < cur->key.source_type) break; if (key->source_type == cur->key.source_type && @@ -271,6 +289,9 @@ void avtab_destroy(struct avtab *h) while (cur) { temp = cur; cur = cur->next; + if (temp->key.specified & AVTAB_XPERMS) + kmem_cache_free(avtab_xperms_cachep, + temp->datum.u.xperms); kmem_cache_free(avtab_node_cachep, temp); } } @@ -359,7 +380,10 @@ static uint16_t spec_order[] = { AVTAB_AUDITALLOW, AVTAB_TRANSITION, AVTAB_CHANGE, - AVTAB_MEMBER + AVTAB_MEMBER, + AVTAB_XPERMS_ALLOWED, + AVTAB_XPERMS_AUDITALLOW, + AVTAB_XPERMS_DONTAUDIT }; int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, @@ -369,10 +393,11 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, { __le16 buf16[4]; u16 enabled; - __le32 buf32[7]; u32 items, items2, val, vers = pol->policyvers; struct avtab_key key; struct avtab_datum datum; + struct avtab_extended_perms xperms; + __le32 buf32[ARRAY_SIZE(xperms.perms.p)]; int i, rc; unsigned set; @@ -429,11 +454,15 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, printk(KERN_ERR "SELinux: avtab: entry has both access vectors and types\n"); return -EINVAL; } + if (val & AVTAB_XPERMS) { + printk(KERN_ERR "SELinux: avtab: entry has extended permissions\n"); + return -EINVAL; + } for (i = 0; i < ARRAY_SIZE(spec_order); i++) { if (val & spec_order[i]) { key.specified = spec_order[i] | enabled; - datum.data = le32_to_cpu(buf32[items++]); + datum.u.data = le32_to_cpu(buf32[items++]); rc = insertf(a, &key, &datum, p); if (rc) return rc; @@ -476,14 +505,42 @@ int avtab_read_item(struct avtab *a, void *fp, struct policydb *pol, return -EINVAL; } - rc = next_entry(buf32, fp, sizeof(u32)); - if (rc) { - printk(KERN_ERR "SELinux: avtab: truncated entry\n"); - return rc; + if ((vers < POLICYDB_VERSION_XPERMS_IOCTL) && + (key.specified & AVTAB_XPERMS)) { + printk(KERN_ERR "SELinux: avtab: policy version %u does not " + "support extended permissions rules and one " + "was specified\n", vers); + return -EINVAL; + } else if (key.specified & AVTAB_XPERMS) { + memset(&xperms, 0, sizeof(struct avtab_extended_perms)); + rc = next_entry(&xperms.specified, fp, sizeof(u8)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + rc = next_entry(&xperms.driver, fp, sizeof(u8)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + rc = next_entry(buf32, fp, sizeof(u32)*ARRAY_SIZE(xperms.perms.p)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + for (i = 0; i < ARRAY_SIZE(xperms.perms.p); i++) + xperms.perms.p[i] = le32_to_cpu(buf32[i]); + datum.u.xperms = &xperms; + } else { + rc = next_entry(buf32, fp, sizeof(u32)); + if (rc) { + printk(KERN_ERR "SELinux: avtab: truncated entry\n"); + return rc; + } + datum.u.data = le32_to_cpu(*buf32); } - datum.data = le32_to_cpu(*buf32); if ((key.specified & AVTAB_TYPE) && - !policydb_type_isvalid(pol, datum.data)) { + !policydb_type_isvalid(pol, datum.u.data)) { printk(KERN_ERR "SELinux: avtab: invalid type\n"); return -EINVAL; } @@ -543,8 +600,9 @@ bad: int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) { __le16 buf16[4]; - __le32 buf32[1]; + __le32 buf32[ARRAY_SIZE(cur->datum.u.xperms->perms.p)]; int rc; + unsigned int i; buf16[0] = cpu_to_le16(cur->key.source_type); buf16[1] = cpu_to_le16(cur->key.target_type); @@ -553,8 +611,22 @@ int avtab_write_item(struct policydb *p, struct avtab_node *cur, void *fp) rc = put_entry(buf16, sizeof(u16), 4, fp); if (rc) return rc; - buf32[0] = cpu_to_le32(cur->datum.data); - rc = put_entry(buf32, sizeof(u32), 1, fp); + + if (cur->key.specified & AVTAB_XPERMS) { + rc = put_entry(&cur->datum.u.xperms->specified, sizeof(u8), 1, fp); + if (rc) + return rc; + rc = put_entry(&cur->datum.u.xperms->driver, sizeof(u8), 1, fp); + if (rc) + return rc; + for (i = 0; i < ARRAY_SIZE(cur->datum.u.xperms->perms.p); i++) + buf32[i] = cpu_to_le32(cur->datum.u.xperms->perms.p[i]); + rc = put_entry(buf32, sizeof(u32), + ARRAY_SIZE(cur->datum.u.xperms->perms.p), fp); + } else { + buf32[0] = cpu_to_le32(cur->datum.u.data); + rc = put_entry(buf32, sizeof(u32), 1, fp); + } if (rc) return rc; return 0; @@ -588,9 +660,13 @@ void avtab_cache_init(void) avtab_node_cachep = kmem_cache_create("avtab_node", sizeof(struct avtab_node), 0, SLAB_PANIC, NULL); + avtab_xperms_cachep = kmem_cache_create("avtab_extended_perms", + sizeof(struct avtab_extended_perms), + 0, SLAB_PANIC, NULL); } void avtab_cache_destroy(void) { kmem_cache_destroy(avtab_node_cachep); + kmem_cache_destroy(avtab_xperms_cachep); } diff --git a/security/selinux/ss/avtab.h b/security/selinux/ss/avtab.h index adb451cd44f9d..d946c9dc3c9ca 100644 --- a/security/selinux/ss/avtab.h +++ b/security/selinux/ss/avtab.h @@ -23,6 +23,7 @@ #ifndef _SS_AVTAB_H_ #define _SS_AVTAB_H_ +#include "security.h" #include struct avtab_key { @@ -37,13 +38,43 @@ struct avtab_key { #define AVTAB_MEMBER 0x0020 #define AVTAB_CHANGE 0x0040 #define AVTAB_TYPE (AVTAB_TRANSITION | AVTAB_MEMBER | AVTAB_CHANGE) +/* extended permissions */ +#define AVTAB_XPERMS_ALLOWED 0x0100 +#define AVTAB_XPERMS_AUDITALLOW 0x0200 +#define AVTAB_XPERMS_DONTAUDIT 0x0400 +#define AVTAB_XPERMS (AVTAB_XPERMS_ALLOWED | \ + AVTAB_XPERMS_AUDITALLOW | \ + AVTAB_XPERMS_DONTAUDIT) #define AVTAB_ENABLED_OLD 0x80000000 /* reserved for used in cond_avtab */ #define AVTAB_ENABLED 0x8000 /* reserved for used in cond_avtab */ u16 specified; /* what field is specified */ }; +/* + * For operations that require more than the 32 permissions provided by the avc + * extended permissions may be used to provide 256 bits of permissions. + */ +struct avtab_extended_perms { +/* These are not flags. All 256 values may be used */ +#define AVTAB_XPERMS_IOCTLFUNCTION 0x01 +#define AVTAB_XPERMS_IOCTLDRIVER 0x02 + /* extension of the avtab_key specified */ + u8 specified; /* ioctl, netfilter, ... */ + /* + * if 256 bits is not adequate as is often the case with ioctls, then + * multiple extended perms may be used and the driver field + * specifies which permissions are included. + */ + u8 driver; + /* 256 bits of permissions */ + struct extended_perms_data perms; +}; + struct avtab_datum { - u32 data; /* access vector or type value */ + union { + u32 data; /* access vector or type value */ + struct avtab_extended_perms *xperms; + } u; }; struct avtab_node { diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c index 62c6773be0b75..18643bf9894d5 100644 --- a/security/selinux/ss/conditional.c +++ b/security/selinux/ss/conditional.c @@ -15,6 +15,7 @@ #include "security.h" #include "conditional.h" +#include "services.h" /* * cond_evaluate_expr evaluates a conditional expr @@ -612,21 +613,39 @@ int cond_write_list(struct policydb *p, struct cond_node *list, void *fp) return 0; } + +void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, + struct extended_perms_decision *xpermd) +{ + struct avtab_node *node; + + if (!ctab || !key || !xpermd) + return; + + for (node = avtab_search_node(ctab, key); node; + node = avtab_search_node_next(node, key->specified)) { + if (node->key.specified & AVTAB_ENABLED) + services_compute_xperms_decision(xpermd, node); + } + return; + +} /* Determine whether additional permissions are granted by the conditional * av table, and if so, add them to the result */ -void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd) +void cond_compute_av(struct avtab *ctab, struct avtab_key *key, + struct av_decision *avd, struct extended_perms *xperms) { struct avtab_node *node; - if (!ctab || !key || !avd) + if (!ctab || !key || !avd || !xperms) return; for (node = avtab_search_node(ctab, key); node; node = avtab_search_node_next(node, key->specified)) { if ((u16)(AVTAB_ALLOWED|AVTAB_ENABLED) == (node->key.specified & (AVTAB_ALLOWED|AVTAB_ENABLED))) - avd->allowed |= node->datum.data; + avd->allowed |= node->datum.u.data; if ((u16)(AVTAB_AUDITDENY|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITDENY|AVTAB_ENABLED))) /* Since a '0' in an auditdeny mask represents a @@ -634,10 +653,13 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decisi * the '&' operand to ensure that all '0's in the mask * are retained (much unlike the allow and auditallow cases). */ - avd->auditdeny &= node->datum.data; + avd->auditdeny &= node->datum.u.data; if ((u16)(AVTAB_AUDITALLOW|AVTAB_ENABLED) == (node->key.specified & (AVTAB_AUDITALLOW|AVTAB_ENABLED))) - avd->auditallow |= node->datum.data; + avd->auditallow |= node->datum.u.data; + if ((node->key.specified & AVTAB_ENABLED) && + (node->key.specified & AVTAB_XPERMS)) + services_compute_xperms_drivers(xperms, node); } return; } diff --git a/security/selinux/ss/conditional.h b/security/selinux/ss/conditional.h index 4d1f87466508f..ddb43e7e1c756 100644 --- a/security/selinux/ss/conditional.h +++ b/security/selinux/ss/conditional.h @@ -73,8 +73,10 @@ int cond_read_list(struct policydb *p, void *fp); int cond_write_bool(void *key, void *datum, void *ptr); int cond_write_list(struct policydb *p, struct cond_node *list, void *fp); -void cond_compute_av(struct avtab *ctab, struct avtab_key *key, struct av_decision *avd); - +void cond_compute_av(struct avtab *ctab, struct avtab_key *key, + struct av_decision *avd, struct extended_perms *xperms); +void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key, + struct extended_perms_decision *xpermd); int evaluate_cond_node(struct policydb *p, struct cond_node *node); #endif /* _CONDITIONAL_H_ */ diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index 74aa224267c11..992a315308258 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -148,6 +148,11 @@ static struct policydb_compat_info policydb_compat[] = { .sym_num = SYM_NUM, .ocon_num = OCON_NUM, }, + { + .version = POLICYDB_VERSION_XPERMS_IOCTL, + .sym_num = SYM_NUM, + .ocon_num = OCON_NUM, + }, }; static struct policydb_compat_info *policydb_lookup_compat(int version) diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index 9e2d820709153..b7df12ba61d83 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -93,9 +93,10 @@ static int context_struct_to_string(struct context *context, char **scontext, u32 *scontext_len); static void context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - struct av_decision *avd); + struct context *tcontext, + u16 tclass, + struct av_decision *avd, + struct extended_perms *xperms); struct selinux_mapping { u16 value; /* policy value */ @@ -565,7 +566,8 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, tcontext, tclass, - &lo_avd); + &lo_avd, + NULL); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; @@ -580,7 +582,8 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(scontext, &lo_tcontext, tclass, - &lo_avd); + &lo_avd, + NULL); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; @@ -596,7 +599,8 @@ static void type_attribute_bounds_av(struct context *scontext, context_struct_compute_av(&lo_scontext, &lo_tcontext, tclass, - &lo_avd); + &lo_avd, + NULL); if ((lo_avd.allowed & avd->allowed) == avd->allowed) return; /* no masked permission */ masked = ~lo_avd.allowed & avd->allowed; @@ -613,13 +617,39 @@ static void type_attribute_bounds_av(struct context *scontext, } /* - * Compute access vectors based on a context structure pair for - * the permissions in a particular class. + * flag which drivers have permissions + * only looking for ioctl based extended permssions + */ +void services_compute_xperms_drivers( + struct extended_perms *xperms, + struct avtab_node *node) +{ + unsigned int i; + + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + /* if one or more driver has all permissions allowed */ + for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++) + xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i]; + } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + /* if allowing permissions within a driver */ + security_xperm_set(xperms->drivers.p, + node->datum.u.xperms->driver); + } + + /* If no ioctl commands are allowed, ignore auditallow and auditdeny */ + if (node->key.specified & AVTAB_XPERMS_ALLOWED) + xperms->len = 1; +} + +/* + * Compute access vectors and extended permissions based on a context + * structure pair for the permissions in a particular class. */ static void context_struct_compute_av(struct context *scontext, - struct context *tcontext, - u16 tclass, - struct av_decision *avd) + struct context *tcontext, + u16 tclass, + struct av_decision *avd, + struct extended_perms *xperms) { struct constraint_node *constraint; struct role_allow *ra; @@ -633,6 +663,10 @@ static void context_struct_compute_av(struct context *scontext, avd->allowed = 0; avd->auditallow = 0; avd->auditdeny = 0xffffffff; + if (xperms) { + memset(&xperms->drivers, 0, sizeof(xperms->drivers)); + xperms->len = 0; + } if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { if (printk_ratelimit()) @@ -647,7 +681,7 @@ static void context_struct_compute_av(struct context *scontext, * this permission check, then use it. */ avkey.target_class = tclass; - avkey.specified = AVTAB_AV; + avkey.specified = AVTAB_AV | AVTAB_XPERMS; sattr = flex_array_get(policydb.type_attr_map_array, scontext->type - 1); BUG_ON(!sattr); tattr = flex_array_get(policydb.type_attr_map_array, tcontext->type - 1); @@ -660,15 +694,18 @@ static void context_struct_compute_av(struct context *scontext, node; node = avtab_search_node_next(node, avkey.specified)) { if (node->key.specified == AVTAB_ALLOWED) - avd->allowed |= node->datum.data; + avd->allowed |= node->datum.u.data; else if (node->key.specified == AVTAB_AUDITALLOW) - avd->auditallow |= node->datum.data; + avd->auditallow |= node->datum.u.data; else if (node->key.specified == AVTAB_AUDITDENY) - avd->auditdeny &= node->datum.data; + avd->auditdeny &= node->datum.u.data; + else if (xperms && (node->key.specified & AVTAB_XPERMS)) + services_compute_xperms_drivers(xperms, node); } /* Check conditional av table for additional permissions */ - cond_compute_av(&policydb.te_cond_avtab, &avkey, avd); + cond_compute_av(&policydb.te_cond_avtab, &avkey, + avd, xperms); } } @@ -899,6 +936,139 @@ static void avd_init(struct av_decision *avd) avd->flags = 0; } +void services_compute_xperms_decision(struct extended_perms_decision *xpermd, + struct avtab_node *node) +{ + unsigned int i; + + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + if (xpermd->driver != node->datum.u.xperms->driver) + return; + } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + if (!security_xperm_test(node->datum.u.xperms->perms.p, + xpermd->driver)) + return; + } else { + BUG(); + } + + if (node->key.specified == AVTAB_XPERMS_ALLOWED) { + xpermd->used |= XPERMS_ALLOWED; + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + memset(xpermd->allowed->p, 0xff, + sizeof(xpermd->allowed->p)); + } + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++) + xpermd->allowed->p[i] |= + node->datum.u.xperms->perms.p[i]; + } + } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) { + xpermd->used |= XPERMS_AUDITALLOW; + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + memset(xpermd->auditallow->p, 0xff, + sizeof(xpermd->auditallow->p)); + } + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++) + xpermd->auditallow->p[i] |= + node->datum.u.xperms->perms.p[i]; + } + } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) { + xpermd->used |= XPERMS_DONTAUDIT; + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) { + memset(xpermd->dontaudit->p, 0xff, + sizeof(xpermd->dontaudit->p)); + } + if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) { + for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++) + xpermd->dontaudit->p[i] |= + node->datum.u.xperms->perms.p[i]; + } + } else { + BUG(); + } +} + +void security_compute_xperms_decision(u32 ssid, + u32 tsid, + u16 orig_tclass, + u8 driver, + struct extended_perms_decision *xpermd) +{ + u16 tclass; + struct context *scontext, *tcontext; + struct avtab_key avkey; + struct avtab_node *node; + struct ebitmap *sattr, *tattr; + struct ebitmap_node *snode, *tnode; + unsigned int i, j; + + xpermd->driver = driver; + xpermd->used = 0; + memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p)); + memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p)); + memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p)); + + read_lock(&policy_rwlock); + if (!ss_initialized) + goto allow; + + scontext = sidtab_search(&sidtab, ssid); + if (!scontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, ssid); + goto out; + } + + tcontext = sidtab_search(&sidtab, tsid); + if (!tcontext) { + printk(KERN_ERR "SELinux: %s: unrecognized SID %d\n", + __func__, tsid); + goto out; + } + + tclass = unmap_class(orig_tclass); + if (unlikely(orig_tclass && !tclass)) { + if (policydb.allow_unknown) + goto allow; + goto out; + } + + + if (unlikely(!tclass || tclass > policydb.p_classes.nprim)) { + pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass); + goto out; + } + + avkey.target_class = tclass; + avkey.specified = AVTAB_XPERMS; + sattr = flex_array_get(policydb.type_attr_map_array, + scontext->type - 1); + BUG_ON(!sattr); + tattr = flex_array_get(policydb.type_attr_map_array, + tcontext->type - 1); + BUG_ON(!tattr); + ebitmap_for_each_positive_bit(sattr, snode, i) { + ebitmap_for_each_positive_bit(tattr, tnode, j) { + avkey.source_type = i + 1; + avkey.target_type = j + 1; + for (node = avtab_search_node(&policydb.te_avtab, &avkey); + node; + node = avtab_search_node_next(node, avkey.specified)) + services_compute_xperms_decision(xpermd, node); + + cond_compute_xperms(&policydb.te_cond_avtab, + &avkey, xpermd); + } + } +out: + read_unlock(&policy_rwlock); + return; +allow: + memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p)); + goto out; +} /** * security_compute_av - Compute access vector decisions. @@ -906,6 +1076,7 @@ static void avd_init(struct av_decision *avd) * @tsid: target security identifier * @tclass: target security class * @avd: access vector decisions + * @xperms: extended permissions * * Compute a set of access vector decisions based on the * SID pair (@ssid, @tsid) for the permissions in @tclass. @@ -913,13 +1084,15 @@ static void avd_init(struct av_decision *avd) void security_compute_av(u32 ssid, u32 tsid, u16 orig_tclass, - struct av_decision *avd) + struct av_decision *avd, + struct extended_perms *xperms) { u16 tclass; struct context *scontext = NULL, *tcontext = NULL; read_lock(&policy_rwlock); avd_init(avd); + xperms->len = 0; if (!ss_initialized) goto allow; @@ -947,7 +1120,7 @@ void security_compute_av(u32 ssid, goto allow; goto out; } - context_struct_compute_av(scontext, tcontext, tclass, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd, xperms); map_decision(orig_tclass, avd, policydb.allow_unknown); out: read_unlock(&policy_rwlock); @@ -993,7 +1166,7 @@ void security_compute_av_user(u32 ssid, goto out; } - context_struct_compute_av(scontext, tcontext, tclass, avd); + context_struct_compute_av(scontext, tcontext, tclass, avd, NULL); out: read_unlock(&policy_rwlock); return; @@ -1515,7 +1688,7 @@ static int security_compute_sid(u32 ssid, if (avdatum) { /* Use the type from the type transition/member/change rule. */ - newcontext.type = avdatum->data; + newcontext.type = avdatum->u.data; } /* if we have a objname this is a file trans check so check those rules */ diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h index e8d907e903cdb..6abcd8729ec3a 100644 --- a/security/selinux/ss/services.h +++ b/security/selinux/ss/services.h @@ -11,5 +11,11 @@ extern struct policydb policydb; +void services_compute_xperms_drivers(struct extended_perms *xperms, + struct avtab_node *node); + +void services_compute_xperms_decision(struct extended_perms_decision *xpermd, + struct avtab_node *node); + #endif /* _SS_SERVICES_H_ */ -- GitLab From 9629d04ae06812f217846b69728c969afee690b4 Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Fri, 10 Jul 2015 17:19:56 -0400 Subject: [PATCH 0769/7006] selinux: reduce locking overhead in inode_free_security() The inode_free_security() function just took the superblock's isec_lock before checking and trying to remove the inode security struct from the linked list. In many cases, the list was empty and so the lock taking is wasteful as no useful work is done. On multi-socket systems with a large number of CPUs, there can also be a fair amount of spinlock contention on the isec_lock if many tasks are exiting at the same time. This patch changes the code to check the state of the list first before taking the lock and attempting to dequeue it. The list_del_init() can be called more than once on the same list with no harm as long as they are properly serialized. It should not be possible to have inode_free_security() called concurrently with list_add(). For better safety, however, we use list_empty_careful() here even though it is still not completely safe in case that happens. Signed-off-by: Waiman Long Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index a049b72162707..4de09f0227b4e 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -254,10 +254,21 @@ static void inode_free_security(struct inode *inode) struct inode_security_struct *isec = inode->i_security; struct superblock_security_struct *sbsec = inode->i_sb->s_security; - spin_lock(&sbsec->isec_lock); - if (!list_empty(&isec->list)) + /* + * As not all inode security structures are in a list, we check for + * empty list outside of the lock to make sure that we won't waste + * time taking a lock doing nothing. + * + * The list_del_init() function can be safely called more than once. + * It should not be possible for this function to be called with + * concurrent list_add(), but for better safety against future changes + * in the code, we use list_empty_careful() here. + */ + if (!list_empty_careful(&isec->list)) { + spin_lock(&sbsec->isec_lock); list_del_init(&isec->list); - spin_unlock(&sbsec->isec_lock); + spin_unlock(&sbsec->isec_lock); + } /* * The inode may still be referenced in a path walk and -- GitLab From 5dee25d08eac01472904b0ab32ce35edee5c0518 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Fri, 10 Jul 2015 17:19:57 -0400 Subject: [PATCH 0770/7006] selinux: initialize sock security class to default value Initialize the security class of sock security structures to the generic socket class. This is similar to what is already done in inode_alloc_security for files. Generally the sclass field will later by set by socket_post_create or sk_clone or sock_graft, but for protocol implementations that fail to call any of these for newly accepted sockets, we want some sane default that will yield a legitimate avc denied message with non-garbage values for class and permission. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 4de09f0227b4e..ef310f82717d7 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4559,6 +4559,7 @@ static int selinux_sk_alloc_security(struct sock *sk, int family, gfp_t priority sksec->peer_sid = SECINITSID_UNLABELED; sksec->sid = SECINITSID_UNLABELED; + sksec->sclass = SECCLASS_SOCKET; selinux_netlbl_sk_security_reset(sksec); sk->sk_security = sksec; -- GitLab From bd1741f4cf05d7709348f591d16eeb5f786de673 Mon Sep 17 00:00:00 2001 From: Stephen Smalley Date: Fri, 10 Jul 2015 17:19:57 -0400 Subject: [PATCH 0771/7006] selinux: Augment BUG_ON assertion for secclass_map. Ensure that we catch any cases where tclass == 0. Signed-off-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/avc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/security/selinux/avc.c b/security/selinux/avc.c index 2d5e1b04cd502..324acc62f7e07 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -116,6 +116,7 @@ static void avc_dump_av(struct audit_buffer *ab, u16 tclass, u32 av) return; } + BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); perms = secclass_map[tclass-1].perms; audit_log_format(ab, " {"); @@ -164,7 +165,7 @@ static void avc_dump_query(struct audit_buffer *ab, u32 ssid, u32 tsid, u16 tcla kfree(scontext); } - BUG_ON(tclass >= ARRAY_SIZE(secclass_map)); + BUG_ON(!tclass || tclass >= ARRAY_SIZE(secclass_map)); audit_log_format(ab, " tclass=%s", secclass_map[tclass-1].name); } -- GitLab From c3c188b2c3ed29effe8693672ee1c84184103b4e Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 10 Jul 2015 17:19:58 -0400 Subject: [PATCH 0772/7006] selinux: Create a common helper to determine an inode label [ver #3] Create a common helper function to determine the label for a new inode. This is then used by: - may_create() - selinux_dentry_init_security() - selinux_inode_init_security() This will change the behaviour of the functions slightly, bringing them all into line. Suggested-by: Stephen Smalley Signed-off-by: David Howells Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- security/selinux/hooks.c | 87 +++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 46 deletions(-) diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index ef310f82717d7..f4be0a1107881 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1709,6 +1709,32 @@ out: return rc; } +/* + * Determine the label for an inode that might be unioned. + */ +static int selinux_determine_inode_label(const struct inode *dir, + const struct qstr *name, + u16 tclass, + u32 *_new_isid) +{ + const struct superblock_security_struct *sbsec = dir->i_sb->s_security; + const struct inode_security_struct *dsec = dir->i_security; + const struct task_security_struct *tsec = current_security(); + + if ((sbsec->flags & SE_SBINITIALIZED) && + (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) { + *_new_isid = sbsec->mntpoint_sid; + } else if ((sbsec->flags & SBLABEL_MNT) && + tsec->create_sid) { + *_new_isid = tsec->create_sid; + } else { + return security_transition_sid(tsec->sid, dsec->sid, tclass, + name, _new_isid); + } + + return 0; +} + /* Check whether a task can create a file. */ static int may_create(struct inode *dir, struct dentry *dentry, @@ -1725,7 +1751,6 @@ static int may_create(struct inode *dir, sbsec = dir->i_sb->s_security; sid = tsec->sid; - newsid = tsec->create_sid; ad.type = LSM_AUDIT_DATA_DENTRY; ad.u.dentry = dentry; @@ -1736,12 +1761,10 @@ static int may_create(struct inode *dir, if (rc) return rc; - if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { - rc = security_transition_sid(sid, dsec->sid, tclass, - &dentry->d_name, &newsid); - if (rc) - return rc; - } + rc = selinux_determine_inode_label(dir, &dentry->d_name, tclass, + &newsid); + if (rc) + return rc; rc = avc_has_perm(sid, newsid, tclass, FILE__CREATE, &ad); if (rc) @@ -2715,32 +2738,14 @@ static int selinux_dentry_init_security(struct dentry *dentry, int mode, struct qstr *name, void **ctx, u32 *ctxlen) { - const struct cred *cred = current_cred(); - struct task_security_struct *tsec; - struct inode_security_struct *dsec; - struct superblock_security_struct *sbsec; - struct inode *dir = d_backing_inode(dentry->d_parent); u32 newsid; int rc; - tsec = cred->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; - - if (tsec->create_sid && sbsec->behavior != SECURITY_FS_USE_MNTPOINT) { - newsid = tsec->create_sid; - } else { - rc = security_transition_sid(tsec->sid, dsec->sid, - inode_mode_to_security_class(mode), - name, - &newsid); - if (rc) { - printk(KERN_WARNING - "%s: security_transition_sid failed, rc=%d\n", - __func__, -rc); - return rc; - } - } + rc = selinux_determine_inode_label(d_inode(dentry->d_parent), name, + inode_mode_to_security_class(mode), + &newsid); + if (rc) + return rc; return security_sid_to_context(newsid, (char **)ctx, ctxlen); } @@ -2763,22 +2768,12 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir, sid = tsec->sid; newsid = tsec->create_sid; - if ((sbsec->flags & SE_SBINITIALIZED) && - (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)) - newsid = sbsec->mntpoint_sid; - else if (!newsid || !(sbsec->flags & SBLABEL_MNT)) { - rc = security_transition_sid(sid, dsec->sid, - inode_mode_to_security_class(inode->i_mode), - qstr, &newsid); - if (rc) { - printk(KERN_WARNING "%s: " - "security_transition_sid failed, rc=%d (dev=%s " - "ino=%ld)\n", - __func__, - -rc, inode->i_sb->s_id, inode->i_ino); - return rc; - } - } + rc = selinux_determine_inode_label( + dir, qstr, + inode_mode_to_security_class(inode->i_mode), + &newsid); + if (rc) + return rc; /* Possibly defer initialization to selinux_complete_init. */ if (sbsec->flags & SE_SBINITIALIZED) { -- GitLab From fda4d578ed0a7e1d116f56a15efea0e4ba78acad Mon Sep 17 00:00:00 2001 From: Laurent Bigonville Date: Tue, 7 Jul 2015 23:10:52 +0200 Subject: [PATCH 0773/7006] selinux: explicitly declare the role "base_r" This fixes the compilation of policy generated by mdp with the recent version of checkpolicy. Signed-off-by: Laurent Bigonville Acked-by: Stephen Smalley Signed-off-by: Paul Moore --- scripts/selinux/mdp/mdp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/selinux/mdp/mdp.c b/scripts/selinux/mdp/mdp.c index 62b34ce1f50dd..e10beb11b696e 100644 --- a/scripts/selinux/mdp/mdp.c +++ b/scripts/selinux/mdp/mdp.c @@ -98,6 +98,7 @@ int main(int argc, char *argv[]) /* types, roles, and allows */ fprintf(fout, "type base_t;\n"); + fprintf(fout, "role base_r;\n"); fprintf(fout, "role base_r types { base_t };\n"); for (i = 0; secclass_map[i].name; i++) fprintf(fout, "allow base_t base_t:%s *;\n", -- GitLab From 5119222f2e3de2e51a3b3270036d53c55ce68236 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Sun, 12 Jul 2015 08:14:19 -0700 Subject: [PATCH 0774/7006] ASoC: max98357a: Make 'sdmode-gpios' dts property optional The option is not needed if chip is always on or managed by some other part of system like platform card driver. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/sound/max98357a.txt | 6 +++++- sound/soc/codecs/max98357a.c | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/max98357a.txt b/Documentation/devicetree/bindings/sound/max98357a.txt index a7a149a236e55..28645a2ff885e 100644 --- a/Documentation/devicetree/bindings/sound/max98357a.txt +++ b/Documentation/devicetree/bindings/sound/max98357a.txt @@ -4,7 +4,11 @@ This node models the Maxim MAX98357A DAC. Required properties: - compatible : "maxim,max98357a" -- sdmode-gpios : GPIO specifier for the GPIO -> DAC SDMODE pin + +Optional properties: +- sdmode-gpios : GPIO specifier for the chip's SD_MODE pin. + If this option is not specified then driver does not manage + the pin state (e.g. chip is always on). Example: diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 3a2fda08a893c..fa1b79302bb3b 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -31,6 +31,9 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, { struct gpio_desc *sdmode = snd_soc_dai_get_drvdata(dai); + if (!sdmode) + return 0; + switch (cmd) { case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_RESUME: @@ -60,7 +63,7 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) { struct gpio_desc *sdmode; - sdmode = devm_gpiod_get(codec->dev, "sdmode", GPIOD_OUT_LOW); + sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW); if (IS_ERR(sdmode)) { dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", __func__, PTR_ERR(sdmode)); -- GitLab From 508e61953f7b2c5c828412e5b46fa99b8a3fbaa1 Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Sun, 12 Jul 2015 08:14:20 -0700 Subject: [PATCH 0775/7006] ASoC: max98357a: Use DAI input as a dapm widget Spec does not say anything about DAC called SDMode. It makes more sense to use DAI input that created automatically by DAPM and route it to Speaker output. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- sound/soc/codecs/max98357a.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index fa1b79302bb3b..b9e1131bab74e 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -51,12 +51,11 @@ static int max98357a_daiops_trigger(struct snd_pcm_substream *substream, } static const struct snd_soc_dapm_widget max98357a_dapm_widgets[] = { - SND_SOC_DAPM_DAC("SDMode", NULL, SND_SOC_NOPM, 0, 0), SND_SOC_DAPM_OUTPUT("Speaker"), }; static const struct snd_soc_dapm_route max98357a_dapm_routes[] = { - {"Speaker", NULL, "SDMode"}, + {"Speaker", NULL, "HiFi Playback"}, }; static int max98357a_codec_probe(struct snd_soc_codec *codec) -- GitLab From 4ab0c591c1482c90d14c1d11bf4b469c54a31ecc Mon Sep 17 00:00:00 2001 From: Anatol Pomozov Date: Sun, 12 Jul 2015 08:14:21 -0700 Subject: [PATCH 0776/7006] ASoC: max98357a: Do not print error message on asoc/gpio errors gpiolib/asoc system already prints enough info if there are any problems. Signed-off-by: Anatol Pomozov Signed-off-by: Mark Brown --- sound/soc/codecs/max98357a.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index b9e1131bab74e..e88119a71b84f 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -63,11 +63,9 @@ static int max98357a_codec_probe(struct snd_soc_codec *codec) struct gpio_desc *sdmode; sdmode = devm_gpiod_get_optional(codec->dev, "sdmode", GPIOD_OUT_LOW); - if (IS_ERR(sdmode)) { - dev_err(codec->dev, "%s() unable to get sdmode GPIO: %ld\n", - __func__, PTR_ERR(sdmode)); + if (IS_ERR(sdmode)) return PTR_ERR(sdmode); - } + snd_soc_codec_set_drvdata(codec, sdmode); return 0; @@ -106,15 +104,8 @@ static struct snd_soc_dai_driver max98357a_dai_driver = { static int max98357a_platform_probe(struct platform_device *pdev) { - int ret; - - ret = snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, + return snd_soc_register_codec(&pdev->dev, &max98357a_codec_driver, &max98357a_dai_driver, 1); - if (ret) - dev_err(&pdev->dev, "%s() error registering codec driver: %d\n", - __func__, ret); - - return ret; } static int max98357a_platform_remove(struct platform_device *pdev) -- GitLab From de551f2eb22a77a498cea9686f39e79f25329109 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 13 Jul 2015 08:48:00 -0700 Subject: [PATCH 0777/7006] net: Build IPv6 into kernel by default This patch makes the default to build IPv6 into the kernel. IPv6 now has significant traction and any remaining vestiges of IPv6 not being provided parity with IPv4 should be swept away. IPv6 is now core to the Internet and kernel. Points on IPv6 adoption: - Per Google statistics, IPv6 usage has reached 7% on the Internet and continues to exhibit an exponential growth rate https://www.google.com/intl/en/ipv6/statistics.html - Just a few days ago ARIN officially depleted its IPv4 pool - IPv6 only data centers are being successfully built (e.g. at Facebook) This patch changes the IPv6 Kconfig for IPV6. Default for CONFIG_IPV6 is set to "y" and the text has been updated to reflect the maturity of IPv6. Impact: Under some circumstances building modules in to kernel might have a performance advantage. In my testing, I did notice a very slight improvement. This will obviously increase the size of the kernel image. In my configuration I see: IPv6 as module: text data bss dec hex filename 9703666 1899288 933888 12536842 bf4c0a vmlinux IPv6 built into kernel text data bss dec hex filename 9436490 1879600 913408 12229498 ba9b7a vmlinux Which increases text size by ~270K (2.8% increase in size for me). If image size is an issue, presumably for a device which does not do IP networking (IMO we should be discouraging IPv4-only devices), IPV6 can be disabled or still built as a module. Acked-by: YOSHIFUJI Hideaki Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/ipv6/Kconfig | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index 438a73aa777cf..643f61339e7b4 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -5,16 +5,15 @@ # IPv6 as module will cause a CRASH if you try to unload it menuconfig IPV6 tristate "The IPv6 protocol" - default m + default y ---help--- - This is complemental support for the IP version 6. - You will still be able to do traditional IPv4 networking as well. + Support for IP version 6 (IPv6). For general information about IPv6, see . - For Linux IPv6 development information, see . - For specific information about IPv6 under Linux, read the HOWTO at - . + For specific information about IPv6 under Linux, see + Documentation/networking/ipv6.txt and read the HOWTO at + To compile this protocol support as a module, choose M here: the module will be called ipv6. -- GitLab From c4675f935399cbdd3ba3869b0bf6c60528c8111a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 13 Jul 2015 20:49:32 +0200 Subject: [PATCH 0778/7006] ebpf: remove self-assignment in interpreter's tail call ARG1 = BPF_R1 as it stands, evaluates to regs[BPF_REG_1] = regs[BPF_REG_1] and thus has no effect. Add a comment instead, explaining what happens and why it's okay to just remove it. Since from user space side, a tail call is invoked as a pseudo helper function via bpf_tail_call_proto, the verifier checks the arguments just like with any other helper function and makes sure that the first argument (regs[BPF_REG_1])'s type is ARG_PTR_TO_CTX. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- kernel/bpf/core.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index c5bedc82bc1c5..bf38f5e8196c1 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -453,7 +453,11 @@ select_insn: if (unlikely(!prog)) goto out; - ARG1 = BPF_R1; + /* ARG1 at this point is guaranteed to point to CTX from + * the verifier side due to the fact that the tail call is + * handeled like a helper, that is, bpf_tail_call_proto, + * where arg1_type is ARG_PTR_TO_CTX. + */ insn = prog->insnsi; goto select_insn; out: -- GitLab From 74fe61f17e999a458d5f64ca2aa9a0282ca32198 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 10 Jul 2015 08:02:08 -0700 Subject: [PATCH 0779/7006] bridge: mdb: add vlan support for user entries Until now all user mdb entries were added in vlan 0, this patch adds support to allow the user to specify the vlan for the entry. About the uapi change a hole in struct br_mdb_entry is used so the size and offsets are kept the same (verified with pahole and tested with older iproute2). Example: $ bridge mdb dev br0 port eth1 grp 239.0.0.1 permanent vlan 2000 dev br0 port eth1 grp 239.0.0.1 permanent vlan 200 dev br0 port eth1 grp 239.0.0.1 permanent Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/uapi/linux/if_bridge.h | 1 + net/bridge/br_mdb.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h index eaaea6208b424..3635b77975085 100644 --- a/include/uapi/linux/if_bridge.h +++ b/include/uapi/linux/if_bridge.h @@ -182,6 +182,7 @@ struct br_mdb_entry { #define MDB_TEMPORARY 0 #define MDB_PERMANENT 1 __u8 state; + __u16 vid; struct { union { __be32 ip4; diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 1fb7d076f15c3..a8d0e93d43f24 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -85,6 +85,7 @@ static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb, memset(&e, 0, sizeof(e)); e.ifindex = port->dev->ifindex; e.state = p->state; + e.vid = p->addr.vid; if (p->addr.proto == htons(ETH_P_IP)) e.addr.u.ip4 = p->addr.u.ip4; #if IS_ENABLED(CONFIG_IPV6) @@ -242,6 +243,7 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, entry.addr.u.ip6 = group->u.ip6; #endif entry.state = state; + entry.vid = group->vid; __br_mdb_notify(dev, &entry, type); } @@ -264,6 +266,8 @@ static bool is_valid_mdb_entry(struct br_mdb_entry *entry) return false; if (entry->state != MDB_PERMANENT && entry->state != MDB_TEMPORARY) return false; + if (entry->vid >= VLAN_VID_MASK) + return false; return true; } @@ -372,6 +376,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br, if (!p || p->br != br || p->state == BR_STATE_DISABLED) return -EINVAL; + ip.vid = entry->vid; ip.proto = entry->addr.proto; if (ip.proto == htons(ETH_P_IP)) ip.u.ip4 = entry->addr.u.ip4; @@ -418,6 +423,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) if (!netif_running(br->dev) || br->multicast_disabled) return -EINVAL; + ip.vid = entry->vid; ip.proto = entry->addr.proto; if (ip.proto == htons(ETH_P_IP)) { if (timer_pending(&br->ip4_other_query.timer)) -- GitLab From 99e1dfb7d2094d9afc1dca57d525f7b36aa18079 Mon Sep 17 00:00:00 2001 From: Aravind Gopalakrishnan Date: Mon, 13 Jul 2015 06:53:02 -0500 Subject: [PATCH 0780/7006] EDAC, mce_amd: Don't emit 'CE' for Deferred error Currently, when decoding an MCE, we display 'CE' for a Deferred error, like this: [Hardware Error]: CPU:0 (15:2:0) MC4_STATUS[Over|CE|MiscV|-|AddrV|Deferred|-|UECC]: 0xdc04b00095080813 When the 'UC' bit in the MCx_STATUS register is clear, the error status is either a Corrected error or Deferred error as determined by the 'Deferred' bit. So do not print 'CE' on a deferred error. Refer to AMD Error Scope Hierarchy table in a newer BKDG (example: 49125_15h_Models_30h-3Fh_BKDG.pdf, section "RAS Features"). Signed-off-by: Aravind Gopalakrishnan Cc: Mauro Carvalho Chehab Cc: linux-edac Link: http://lkml.kernel.org/r/1436788382-6463-1-git-send-email-aravind.gopalakrishnan@amd.com Signed-off-by: Borislav Petkov --- drivers/edac/mce_amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index 58586d59bf8ed..e3a945ce374b8 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c @@ -763,7 +763,8 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) c->x86, c->x86_model, c->x86_mask, m->bank, ((m->status & MCI_STATUS_OVER) ? "Over" : "-"), - ((m->status & MCI_STATUS_UC) ? "UE" : "CE"), + ((m->status & MCI_STATUS_UC) ? "UE" : + (m->status & MCI_STATUS_DEFERRED) ? "-" : "CE"), ((m->status & MCI_STATUS_MISCV) ? "MiscV" : "-"), ((m->status & MCI_STATUS_PCC) ? "PCC" : "-"), ((m->status & MCI_STATUS_ADDRV) ? "AddrV" : "-")); -- GitLab From 7ce0c22b07871402f9fb8939e09fb4c10811438a Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 14 Jul 2015 09:32:32 +0100 Subject: [PATCH 0781/7006] metag/irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner Signed-off-by: James Hogan --- arch/metag/kernel/irq.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c index 4f8f1f87ef116..a336094a7a6c9 100644 --- a/arch/metag/kernel/irq.c +++ b/arch/metag/kernel/irq.c @@ -270,23 +270,25 @@ void migrate_irqs(void) for_each_active_irq(i) { struct irq_data *data = irq_get_irq_data(i); + struct cpumask *mask; unsigned int newcpu; if (irqd_is_per_cpu(data)) continue; - if (!cpumask_test_cpu(cpu, data->affinity)) + mask = irq_data_get_affinity_mask(data); + if (!cpumask_test_cpu(cpu, mask)) continue; - newcpu = cpumask_any_and(data->affinity, cpu_online_mask); + newcpu = cpumask_any_and(mask, cpu_online_mask); if (newcpu >= nr_cpu_ids) { pr_info_ratelimited("IRQ%u no longer affine to CPU%u\n", i, cpu); - cpumask_setall(data->affinity); + cpumask_setall(mask); } - irq_set_affinity(i, data->affinity); + irq_set_affinity(i, mask); } } #endif /* CONFIG_HOTPLUG_CPU */ -- GitLab From f6d1a814844efc4b326538bd35a8daecd37921ed Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 13 Jul 2015 19:40:52 +0200 Subject: [PATCH 0782/7006] ASoC: max98925: Remove control_data initialization The control_data field of the snd_soc_codec struct is no longer used by ASoC drivers using standard regmap IO. There is no need to initialize the field to point to the drivers regmap struct, so drop that. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index aad664225dc3a..eddf8bc073146 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -523,7 +523,6 @@ static int max98925_probe(struct snd_soc_codec *codec) struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); max98925->codec = codec; - codec->control_data = max98925->regmap; regmap_write(max98925->regmap, MAX98925_GLOBAL_ENABLE, 0x00); /* It's not the default but we need to set DAI_DLY */ regmap_write(max98925->regmap, -- GitLab From cc017fb4d7a3308725afc02af9fd84a171e6e028 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:21 +0530 Subject: [PATCH 0783/7006] drm/i915/skl: Restrict the ring frequency table programming to SKL Ring frequency table programming is not required on BXT. Added separate checks to enable the programming only for SKL & skip for BXT. v2: Removed the BXT check from gen6_update_ring_freq function Issue: VIZ-5144 Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 135fb974dfff0..f2be1cedb52fc 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -6219,7 +6219,8 @@ static void intel_gen6_powersave_work(struct work_struct *work) } else if (INTEL_INFO(dev)->gen >= 9) { gen9_enable_rc6(dev); gen9_enable_rps(dev); - __gen6_update_ring_freq(dev); + if (IS_SKYLAKE(dev)) + __gen6_update_ring_freq(dev); } else if (IS_BROADWELL(dev)) { gen8_enable_rps(dev); __gen6_update_ring_freq(dev); -- GitLab From 05379818e489bd9fec892f79f202b2ff41fd6ff8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:46 +0200 Subject: [PATCH 0784/7006] gpio/mpc8xxx: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-mpc8xxx.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 20aa66f34f6e0..da8e89205f371 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -396,8 +396,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) out_be32(mm_gc->regs + GPIO_IER, 0xffffffff); out_be32(mm_gc->regs + GPIO_IMR, 0); - irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc); - irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade); + irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, + mpc8xxx_gpio_irq_cascade, mpc8xxx_gc); return 0; } @@ -407,8 +407,7 @@ static int mpc8xxx_remove(struct platform_device *pdev) struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev); if (mpc8xxx_gc->irq) { - irq_set_handler_data(mpc8xxx_gc->irqn, NULL); - irq_set_chained_handler(mpc8xxx_gc->irqn, NULL); + irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL); irq_domain_remove(mpc8xxx_gc->irq); } -- GitLab From d68cd06ce40d7227598912bb1a0c75980d2b5a4b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:47 +0200 Subject: [PATCH 0785/7006] gpio/mvebu: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-mvebu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index 1a54205860f59..ab660e44a6721 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -787,8 +787,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev) if (irq < 0) continue; - irq_set_handler_data(irq, mvchip); - irq_set_chained_handler(irq, mvebu_gpio_irq_handler); + irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, + mvchip); } mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1); -- GitLab From 8a52211ad8d8c97fede3707c938126002e11ec79 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:47 +0200 Subject: [PATCH 0786/7006] gpio/timberdale: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-timberdale.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index e8f97e03c9bb6..fd1970ed15e61 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -299,8 +299,7 @@ static int timbgpio_probe(struct platform_device *pdev) #endif } - irq_set_handler_data(irq, tgpio); - irq_set_chained_handler(irq, timbgpio_irq); + irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio); return 0; } -- GitLab From 77c77e3f074f576a39534bb9b10b6f1b4d91a8db Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:48 +0200 Subject: [PATCH 0787/7006] gpio/tz1090: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-tz1090.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c index 445660adc8989..bbac92ae4c328 100644 --- a/drivers/gpio/gpio-tz1090.c +++ b/drivers/gpio/gpio-tz1090.c @@ -510,8 +510,8 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info) gc->chip_types[1].chip.flags = IRQCHIP_MASK_ON_SUSPEND; /* Setup chained handler for this GPIO bank */ - irq_set_handler_data(bank->irq, bank); - irq_set_chained_handler(bank->irq, tz1090_gpio_irq_handler); + irq_set_chained_handler_and_data(bank->irq, tz1090_gpio_irq_handler, + bank); return 0; } -- GitLab From f7f877533c11029e4b4caf8aae9968c5fd561625 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:10:48 +0200 Subject: [PATCH 0788/7006] gpiolib: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle: Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c38..78a738bca53fa 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -443,8 +443,8 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip, * The parent irqchip is already using the chip_data for this * irqchip, so our callbacks simply use the handler_data. */ - irq_set_handler_data(parent_irq, gpiochip); - irq_set_chained_handler(parent_irq, parent_handler); + irq_set_chained_handler_and_data(parent_irq, parent_handler, + gpiochip); gpiochip->irq_parent = parent_irq; } -- GitLab From 47c08462921f17de890c2574b2893ecae44cfd76 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 14:37:42 +0200 Subject: [PATCH 0789/7006] gpio/zynq: Use irq_set_chip_handler_name_locked() Hand in irq_data and avoid the redundant lookup of irq_desc. Originally-from: Jiang Liu Signed-off-by: Thomas Gleixner --- drivers/gpio/gpio-zynq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 2e87c4b8da26d..53b297473724a 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -441,10 +441,10 @@ static int zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num)); if (type & IRQ_TYPE_LEVEL_MASK) { - __irq_set_chip_handler_name_locked(irq_data->irq, + irq_set_chip_handler_name_locked(irq_data, &zynq_gpio_level_irqchip, handle_fasteoi_irq, NULL); } else { - __irq_set_chip_handler_name_locked(irq_data->irq, + irq_set_chip_handler_name_locked(irq_data, &zynq_gpio_edge_irqchip, handle_level_irq, NULL); } -- GitLab From 72b2a9ef9c5fffe274cca0be63a4f3998fa0b641 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:38 +0200 Subject: [PATCH 0790/7006] gpio/ep93xx: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: @@ struct irq_data *d; expression E1; @@ -__irq_set_handler_locked(d->irq, E1); +irq_set_handler_locked(d, E1); Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-ep93xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 45684f36ddb15..8664cf041b1f6 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -208,7 +208,7 @@ static int ep93xx_gpio_irq_type(struct irq_data *d, unsigned int type) return -EINVAL; } - __irq_set_handler_locked(d->irq, handler); + irq_set_handler_locked(d, handler); gpio_int_enabled[port] |= port_mask; -- GitLab From b11b7af97883da01082e318abac51cec7162a347 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:38 +0200 Subject: [PATCH 0791/7006] gpio/msm-v2: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-msm-v2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 52ff18229fdc8..cbf383f7270d7 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -281,14 +281,14 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) if (flow_type & IRQ_TYPE_EDGE_BOTH) { bits |= BIT(INTR_DECT_CTL); - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); if ((flow_type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) __set_bit(gpio, msm_gpio.dual_edge_irqs); else __clear_bit(gpio, msm_gpio.dual_edge_irqs); } else { bits &= ~BIT(INTR_DECT_CTL); - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); __clear_bit(gpio, msm_gpio.dual_edge_irqs); } -- GitLab From 43ec2e4316047e9eecf7df86768708395888eb96 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:39 +0200 Subject: [PATCH 0792/7006] gpio/omap: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Kevin Hilman Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-omap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index b0c57d505be75..1a7c2ded9d6fb 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -511,9 +511,9 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; -- GitLab From 2456d869c45eeaefa7c5c96d30d1e884a12709e3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:40 +0200 Subject: [PATCH 0793/7006] gpio/pch: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-pch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-pch.c b/drivers/gpio/gpio-pch.c index 2d9a950ca2d46..34ed176df15a9 100644 --- a/drivers/gpio/gpio-pch.c +++ b/drivers/gpio/gpio-pch.c @@ -281,9 +281,9 @@ static int pch_irq_type(struct irq_data *d, unsigned int type) /* And the handler */ if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); unlock: spin_unlock_irqrestore(&chip->spinlock, flags); -- GitLab From f170d71eb2eb5de968dbedfd74bc53944a080391 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:40 +0200 Subject: [PATCH 0794/7006] gpio/gpio-tegra: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle: Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot Cc: Stephen Warren Cc: Thierry Reding Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-tegra.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 9b25c90f725c2..271c4cf5e0cc3 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -252,9 +252,9 @@ static int tegra_gpio_irq_set_type(struct irq_data *d, unsigned int type) tegra_gpio_enable(gpio); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; } -- GitLab From c16edb8b3a070be758a97bc6cd00855c7bbccec4 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 1 Jun 2015 16:05:19 +0800 Subject: [PATCH 0795/7006] gpio/davinci: Use accessor function irq_data_get_irq_handler_data() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Thomas Gleixner --- drivers/gpio/gpio-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index c5e05c82d67c6..477d5b8616ab9 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -396,7 +396,7 @@ static int gpio_irq_type_unbanked(struct irq_data *data, unsigned trigger) struct davinci_gpio_regs __iomem *g; u32 mask; - d = (struct davinci_gpio_controller *)data->handler_data; + d = (struct davinci_gpio_controller *)irq_data_get_irq_handler_data(data); g = (struct davinci_gpio_regs __iomem *)d->regs; mask = __gpio_mask(data->irq - d->gpio_irq); -- GitLab From 476f8b4c94a90d1167961d90a5ed68dbe87c62da Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:15 +0800 Subject: [PATCH 0796/7006] gpio: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Preparatory patch for the removal of the 'irq' argument from irq flow handlers. Signed-off-by: Jiang Liu Acked-by: Linus Walleij Cc: Alexandre Courbot Signed-off-by: Thomas Gleixner --- drivers/gpio/gpio-bcm-kona.c | 2 +- drivers/gpio/gpio-dwapb.c | 2 +- drivers/gpio/gpio-mvebu.c | 2 +- drivers/gpio/gpio-mxc.c | 6 +++--- drivers/gpio/gpio-mxs.c | 2 +- drivers/gpio/gpio-omap.c | 2 +- drivers/gpio/gpio-tegra.c | 4 +--- drivers/gpio/gpio-timberdale.c | 5 +++-- drivers/gpio/gpio-vf610.c | 2 +- drivers/gpio/gpio-zynq.c | 2 +- 10 files changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 40343fa92c7b9..109083f652486 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -438,7 +438,7 @@ static void bcm_kona_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) void __iomem *reg_base; int bit, bank_id; unsigned long sta; - struct bcm_kona_gpio_bank *bank = irq_get_handler_data(irq); + struct bcm_kona_gpio_bank *bank = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c index 55fa9853a7f22..c5be4b9b8baf7 100644 --- a/drivers/gpio/gpio-dwapb.c +++ b/drivers/gpio/gpio-dwapb.c @@ -149,7 +149,7 @@ static u32 dwapb_do_irq(struct dwapb_gpio *gpio) static void dwapb_irq_handler(u32 irq, struct irq_desc *desc) { - struct dwapb_gpio *gpio = irq_get_handler_data(irq); + struct dwapb_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); dwapb_do_irq(gpio); diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index ab660e44a6721..b65d2b8d3b959 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -460,7 +460,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct mvebu_gpio_chip *mvchip = irq_get_handler_data(irq); + struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); u32 cause, type; int i; diff --git a/drivers/gpio/gpio-mxc.c b/drivers/gpio/gpio-mxc.c index ec1eb1b7250ff..0f740276ed2b5 100644 --- a/drivers/gpio/gpio-mxc.c +++ b/drivers/gpio/gpio-mxc.c @@ -275,8 +275,8 @@ static void mxc_gpio_irq_handler(struct mxc_gpio_port *port, u32 irq_stat) static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; - struct mxc_gpio_port *port = irq_get_handler_data(irq); - struct irq_chip *chip = irq_get_chip(irq); + struct mxc_gpio_port *port = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); @@ -292,7 +292,7 @@ static void mx2_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_msk, irq_stat; struct mxc_gpio_port *port; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); diff --git a/drivers/gpio/gpio-mxs.c b/drivers/gpio/gpio-mxs.c index 551d15d7c369c..b7f383eb18d91 100644 --- a/drivers/gpio/gpio-mxs.c +++ b/drivers/gpio/gpio-mxs.c @@ -157,7 +157,7 @@ static void mxs_flip_edge(struct mxs_gpio_port *port, u32 gpio) static void mxs_gpio_irq_handler(u32 irq, struct irq_desc *desc) { u32 irq_stat; - struct mxs_gpio_port *port = irq_get_handler_data(irq); + struct mxs_gpio_port *port = irq_desc_get_handler_data(desc); desc->irq_data.chip->irq_ack(&desc->irq_data); diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 1a7c2ded9d6fb..04ea23ba37ccd 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -714,7 +714,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) struct gpio_bank *bank; int unmasked = 0; struct irq_chip *irqchip = irq_desc_get_chip(desc); - struct gpio_chip *chip = irq_get_handler_data(irq); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); chained_irq_enter(irqchip, desc); diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 271c4cf5e0cc3..530b27f9d66f3 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -268,16 +268,14 @@ static void tegra_gpio_irq_shutdown(struct irq_data *d) static void tegra_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct tegra_gpio_bank *bank; int port; int pin; int unmasked = 0; struct irq_chip *chip = irq_desc_get_chip(desc); + struct tegra_gpio_bank *bank = irq_desc_get_handler_data(desc); chained_irq_enter(chip, desc); - bank = irq_get_handler_data(irq); - for (port = 0; port < 4; port++) { int gpio = tegra_gpio_compose(bank->bank, port, 0); unsigned long sta = tegra_gpio_readl(GPIO_INT_STA(gpio)) & diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index fd1970ed15e61..ac53ff0a80866 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -194,11 +194,12 @@ out: static void timbgpio_irq(unsigned int irq, struct irq_desc *desc) { - struct timbgpio *tgpio = irq_get_handler_data(irq); + struct timbgpio *tgpio = irq_desc_get_handler_data(desc); + struct irq_data *data = irq_desc_get_irq_data(desc); unsigned long ipr; int offset; - desc->irq_data.chip->irq_ack(irq_get_irq_data(irq)); + data->chip->irq_ack(data); ipr = ioread32(tgpio->membase + TGPIO_IPR); iowrite32(ipr, tgpio->membase + TGPIO_ICR); diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index 7bd9f209ffa81..fa344388f4daa 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -120,7 +120,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, static void vf610_gpio_irq_handler(u32 irq, struct irq_desc *desc) { - struct vf610_gpio_port *port = irq_get_handler_data(irq); + struct vf610_gpio_port *port = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); int pin; unsigned long irq_isfr; diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 53b297473724a..db8a61b8ca0c3 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -518,7 +518,7 @@ static void zynq_gpio_irqhandler(unsigned int irq, struct irq_desc *desc) { u32 int_sts, int_enb; unsigned int bank_num; - struct zynq_gpio *gpio = irq_get_handler_data(irq); + struct zynq_gpio *gpio = irq_desc_get_handler_data(desc); struct irq_chip *irqchip = irq_desc_get_chip(desc); chained_irq_enter(irqchip, desc); -- GitLab From c3ca1e6f1849a6bce3a4a57e483d13ab7a544dd4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 12 Jul 2015 23:47:32 +0200 Subject: [PATCH 0797/7006] gpio/davinci: Prepare gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-davinci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 477d5b8616ab9..9a738f5d409bf 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -327,8 +327,9 @@ static struct irq_chip gpio_irqchip = { }; static void -gpio_irq_handler(unsigned irq, struct irq_desc *desc) +gpio_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct davinci_gpio_regs __iomem *g; u32 mask = 0xffff; struct davinci_gpio_controller *d; -- GitLab From e43ea7a7736bb29fd088e83a7b66195eb2854814 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 00:06:41 +0200 Subject: [PATCH 0798/7006] gpio/ep93xx: Prepare ep93xx_gpio_f_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-ep93xx.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index 8664cf041b1f6..dc0c409359404 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -100,13 +100,15 @@ static void ep93xx_gpio_ab_irq_handler(unsigned int irq, struct irq_desc *desc) } } -static void ep93xx_gpio_f_irq_handler(unsigned int irq, struct irq_desc *desc) +static void ep93xx_gpio_f_irq_handler(unsigned int __irq, + struct irq_desc *desc) { /* * map discontiguous hw irq range to continuous sw irq range: * * IRQ_EP93XX_GPIO{0..7}MUX -> gpio_to_irq(EP93XX_GPIO_LINE_F({0..7}) */ + unsigned int irq = irq_desc_get_irq(desc); int port_f_idx = ((irq + 1) & 7) ^ 4; /* {19..22,47..50} -> {0..7} */ int gpio_irq = gpio_to_irq(EP93XX_GPIO_LINE_F(0)) + port_f_idx; -- GitLab From 364ea44b24deec90c1ba88dc427d5bc4864096f5 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 00:09:04 +0200 Subject: [PATCH 0799/7006] gpio/mvebu: Prepare mvebu_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-mvebu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c index b65d2b8d3b959..b396bf3bf2946 100644 --- a/drivers/gpio/gpio-mvebu.c +++ b/drivers/gpio/gpio-mvebu.c @@ -458,7 +458,7 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) return 0; } -static void mvebu_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void mvebu_gpio_irq_handler(unsigned int __irq, struct irq_desc *desc) { struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); struct irq_chip *chip = irq_desc_get_chip(desc); -- GitLab From 2951a7990c4aac3bfa05ea8474eb2948ca73eaba Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 00:11:27 +0200 Subject: [PATCH 0800/7006] gpio/sa1100: Prepare sa1100_gpio_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: Alexandre Courbot Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-sa1100.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index 3fa22dade243e..e847a4cf93266 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -173,9 +173,9 @@ static struct irq_domain *sa1100_gpio_irqdomain; * and call the handler. */ static void -sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc) +sa1100_gpio_handler(unsigned int __irq, struct irq_desc *desc) { - unsigned int mask; + unsigned int irq, mask; mask = GEDR; do { -- GitLab From 789f9dabfe44c1f7056aa0a7c9a9205de4d5261f Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:07:01 +0200 Subject: [PATCH 0801/7006] gpio/msm-v2: Avoid redundant lookup of irq_data It's pretty silly to do irq_data *d = irq_get_irq_data(irq_data->irq); because that results in d = irq_data, but goes through a lookup of the irq_data. Use irq_data directly. Signed-off-by: Thomas Gleixner Cc: Linus Walleij Cc: Alexandre Courbot Cc: Jiang Liu Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-msm-v2.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index cbf383f7270d7..1f0fb19209bf9 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -187,14 +187,6 @@ static int msm_gpio_to_irq(struct gpio_chip *chip, unsigned offset) return irq_create_mapping(domain, offset); } -static inline int msm_irq_to_gpio(struct gpio_chip *chip, unsigned irq) -{ - struct irq_data *irq_data = irq_get_irq_data(irq); - - return irq_data->hwirq; -} - - /* For dual-edge interrupts in software, since the hardware has no * such support: * @@ -238,7 +230,7 @@ static void msm_gpio_update_dual_edge_pos(unsigned gpio) static void msm_gpio_irq_ack(struct irq_data *d) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); + int gpio = d->hwirq; writel(BIT(INTR_STATUS), GPIO_INTR_STATUS(gpio)); if (test_bit(gpio, msm_gpio.dual_edge_irqs)) @@ -247,8 +239,8 @@ static void msm_gpio_irq_ack(struct irq_data *d) static void msm_gpio_irq_mask(struct irq_data *d) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); unsigned long irq_flags; + int gpio = d->hwirq; spin_lock_irqsave(&tlmm_lock, irq_flags); writel(TARGET_PROC_NONE, GPIO_INTR_CFG_SU(gpio)); @@ -259,8 +251,8 @@ static void msm_gpio_irq_mask(struct irq_data *d) static void msm_gpio_irq_unmask(struct irq_data *d) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); unsigned long irq_flags; + int gpio = d->hwirq; spin_lock_irqsave(&tlmm_lock, irq_flags); __set_bit(gpio, msm_gpio.enabled_irqs); @@ -271,8 +263,8 @@ static void msm_gpio_irq_unmask(struct irq_data *d) static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int flow_type) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); unsigned long irq_flags; + int gpio = d->hwirq; uint32_t bits; spin_lock_irqsave(&tlmm_lock, irq_flags); @@ -331,7 +323,7 @@ static void msm_summary_irq_handler(unsigned int irq, struct irq_desc *desc) static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) { - int gpio = msm_irq_to_gpio(&msm_gpio.gpio_chip, d->irq); + int gpio = d->hwirq; if (on) { if (bitmap_empty(msm_gpio.wake_irqs, MAX_NR_GPIO)) -- GitLab From 1765d671b18e58fdd6341edac9c22e57d90ef6a8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:18:56 +0200 Subject: [PATCH 0802/7006] gpio/davinci: Avoid redundant lookup of irq_data It's pretty silly to do void *cd = irq_get_chip_data(irq_data->irq); because that results in cd = irq_data->chip_data, but goes through a redundant lookup of the irq_data. Use irq_data directly. Signed-off-by: Thomas Gleixner Cc: Linus Walleij Cc: Alexandre Courbot Cc: Jiang Liu Cc: linux-gpio@vger.kernel.org --- drivers/gpio/gpio-davinci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 9a738f5d409bf..d885d98fe1617 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -65,11 +65,11 @@ static struct davinci_gpio_regs __iomem *gpio2regs(unsigned gpio) return ptr; } -static inline struct davinci_gpio_regs __iomem *irq2regs(int irq) +static inline struct davinci_gpio_regs __iomem *irq2regs(struct irq_data *d) { struct davinci_gpio_regs __iomem *g; - g = (__force struct davinci_gpio_regs __iomem *)irq_get_chip_data(irq); + g = (__force struct davinci_gpio_regs __iomem *)irq_data_get_irq_chip_data(d); return g; } @@ -287,7 +287,7 @@ static int davinci_gpio_probe(struct platform_device *pdev) static void gpio_irq_disable(struct irq_data *d) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + struct davinci_gpio_regs __iomem *g = irq2regs(d); u32 mask = (u32) irq_data_get_irq_handler_data(d); writel_relaxed(mask, &g->clr_falling); @@ -296,7 +296,7 @@ static void gpio_irq_disable(struct irq_data *d) static void gpio_irq_enable(struct irq_data *d) { - struct davinci_gpio_regs __iomem *g = irq2regs(d->irq); + struct davinci_gpio_regs __iomem *g = irq2regs(d); u32 mask = (u32) irq_data_get_irq_handler_data(d); unsigned status = irqd_get_trigger_type(d); -- GitLab From bdac2b6dc7392668a8530d67a5f762366f57f9b4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 23:22:44 +0200 Subject: [PATCH 0803/7006] gpio/davinci: Fix race in installing chained irq handler Fix a race where a pending interrupt could be received and the handler called before the handler's data has been setup, by converting to irq_set_chained_handler_and_data(). Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: Alexandre Courbot --- drivers/gpio/gpio-davinci.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index d885d98fe1617..b23cbcea2d98e 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -579,15 +579,13 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) writel_relaxed(~0, &g->clr_falling); writel_relaxed(~0, &g->clr_rising); - /* set up all irqs in this bank */ - irq_set_chained_handler(bank_irq, gpio_irq_handler); - /* * Each chip handles 32 gpios, and each irq bank consists of 16 * gpio irqs. Pass the irq bank's corresponding controller to * the chained irq handler. */ - irq_set_handler_data(bank_irq, &chips[gpio / 32]); + irq_set_chained_handler_and_data(bank_irq, gpio_irq_handler, + &chips[gpio / 32]); binten |= BIT(bank); } -- GitLab From 131e663bd6f1055caaff128f9aa5071d227eeb72 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:33 +0200 Subject: [PATCH 0804/7006] drm/gem: rip out drm vma accounting for gem mmaps Doesn't really add anything which can't be figured out through proc files. And more clearly separates the new gem mmap handling code from the old drm maps mmap handling code, which is surely a good thing. Cc: Martin Peres Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_gem.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c index 16a1647707136..27a4228b43431 100644 --- a/drivers/gpu/drm/drm_gem.c +++ b/drivers/gpu/drm/drm_gem.c @@ -778,22 +778,14 @@ void drm_gem_vm_open(struct vm_area_struct *vma) struct drm_gem_object *obj = vma->vm_private_data; drm_gem_object_reference(obj); - - mutex_lock(&obj->dev->struct_mutex); - drm_vm_open_locked(obj->dev, vma); - mutex_unlock(&obj->dev->struct_mutex); } EXPORT_SYMBOL(drm_gem_vm_open); void drm_gem_vm_close(struct vm_area_struct *vma) { struct drm_gem_object *obj = vma->vm_private_data; - struct drm_device *dev = obj->dev; - mutex_lock(&dev->struct_mutex); - drm_vm_close_locked(obj->dev, vma); - drm_gem_object_unreference(obj); - mutex_unlock(&dev->struct_mutex); + drm_gem_object_unreference_unlocked(obj); } EXPORT_SYMBOL(drm_gem_vm_close); @@ -850,7 +842,6 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size, */ drm_gem_object_reference(obj); - drm_vm_open_locked(dev, vma); return 0; } EXPORT_SYMBOL(drm_gem_mmap_obj); -- GitLab From fa3eec7791b0fe27e3112804a71ba445ff336a6b Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 1 Jul 2015 23:51:43 +0100 Subject: [PATCH 0805/7006] regmap: Silence warning on invalid zero length read Zero length reads make no sense in a regmap context and are likely to trigger bugs further down the stack so insert an error check, also silencing compiler warnings about use of ret in cases where we iterate per register. Reported-by: Russell King Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 8894b992043e0..9c1f856842a3a 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2180,6 +2180,8 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, return -EINVAL; if (reg % map->reg_stride) return -EINVAL; + if (val_count == 0) + return -EINVAL; map->lock(map->lock_arg); -- GitLab From 8a75d157ccddc2c1fb5aeefe6a1a45a9eb0c0176 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:14 +0200 Subject: [PATCH 0806/7006] drm/i915: Only update state on crtc's that are part of the atomic state. This is probably hard to hit right now because in most cases all atomic locks are taken, but after conversion to atomic this will make it more likely to corrupt the crtc->config pointer, resulting in hard to find bugs. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 00c60c1c5162e..9995df578fa8d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12312,6 +12312,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; struct drm_connector *connector; + int i; intel_shared_dpll_commit(state); @@ -12331,7 +12332,7 @@ intel_modeset_update_state(struct drm_atomic_state *state) intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ - for_each_crtc(dev, crtc) { + for_each_crtc_in_state(state, crtc, crtc_state, i) { WARN_ON(crtc->state->enable != intel_crtc_in_use(crtc)); to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); -- GitLab From e435d6e52b164c041d3b0f88be3f7b8c5a14462a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:15 +0200 Subject: [PATCH 0807/7006] drm/i915: Do not update pfit state when toggling crtc enabled. There's not much point for calculating the changes for the old state. Instead just disable all scalers when disabling. It's probably good enough to just disable the crtc_scaler, but just in case there's a bug disable all scalers. This means intel_atomic_setup_scalers is only called in the crtc check function now, so all the transitional code can be removed. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 14 ++---- drivers/gpu/drm/i915/intel_display.c | 68 ++++++++++++++++++---------- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index 5c79a31603af6..b92b8581efc2b 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -272,17 +272,12 @@ int intel_atomic_setup_scalers(struct drm_device *dev, struct drm_plane *plane = NULL; struct intel_plane *intel_plane; struct intel_plane_state *plane_state = NULL; - struct intel_crtc_scaler_state *scaler_state; - struct drm_atomic_state *drm_state; + struct intel_crtc_scaler_state *scaler_state = + &crtc_state->scaler_state; + struct drm_atomic_state *drm_state = crtc_state->base.state; int num_scalers_need; int i, j; - if (INTEL_INFO(dev)->gen < 9 || !intel_crtc || !crtc_state) - return 0; - - scaler_state = &crtc_state->scaler_state; - drm_state = crtc_state->base.state; - num_scalers_need = hweight32(scaler_state->scaler_users); DRM_DEBUG_KMS("crtc_state = %p need = %d avail = %d scaler_users = 0x%x\n", crtc_state, num_scalers_need, intel_crtc->num_scalers, @@ -326,9 +321,6 @@ int intel_atomic_setup_scalers(struct drm_device *dev, } else { name = "PLANE"; - if (!drm_state) - continue; - /* plane scaler case: assign as a plane scaler */ /* find the plane that set the bit as scaler_user */ plane = drm_state->planes[i]; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9995df578fa8d..99897b152091f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2911,29 +2911,32 @@ unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, return i915_gem_obj_ggtt_offset_view(obj, view); } +static void skl_detach_scaler(struct intel_crtc *intel_crtc, int id) +{ + struct drm_device *dev = intel_crtc->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + + I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, id), 0); + I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, id), 0); + I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, id), 0); + DRM_DEBUG_KMS("CRTC:%d Disabled scaler id %u.%u\n", + intel_crtc->base.base.id, intel_crtc->pipe, id); +} + /* * This function detaches (aka. unbinds) unused scalers in hardware */ static void skl_detach_scalers(struct intel_crtc *intel_crtc) { - struct drm_device *dev; - struct drm_i915_private *dev_priv; struct intel_crtc_scaler_state *scaler_state; int i; - dev = intel_crtc->base.dev; - dev_priv = dev->dev_private; scaler_state = &intel_crtc->config->scaler_state; /* loop through and disable scalers that aren't in use */ for (i = 0; i < intel_crtc->num_scalers; i++) { - if (!scaler_state->scalers[i].in_use) { - I915_WRITE(SKL_PS_CTRL(intel_crtc->pipe, i), 0); - I915_WRITE(SKL_PS_WIN_POS(intel_crtc->pipe, i), 0); - I915_WRITE(SKL_PS_WIN_SZ(intel_crtc->pipe, i), 0); - DRM_DEBUG_KMS("CRTC:%d Disabled scaler id %u.%u\n", - intel_crtc->base.base.id, intel_crtc->pipe, i); - } + if (!scaler_state->scalers[i].in_use) + skl_detach_scaler(intel_crtc, i); } } @@ -4364,13 +4367,12 @@ skl_update_scaler(struct intel_crtc_state *crtc_state, bool force_detach, * skl_update_scaler_crtc - Stages update to scaler state for a given crtc. * * @state: crtc's scaler state - * @force_detach: whether to forcibly disable scaler * * Return * 0 - scaler_usage updated successfully * error - requested scaling cannot be supported or other error condition */ -int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) +int skl_update_scaler_crtc(struct intel_crtc_state *state) { struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc); struct drm_display_mode *adjusted_mode = @@ -4379,7 +4381,7 @@ int skl_update_scaler_crtc(struct intel_crtc_state *state, int force_detach) DRM_DEBUG_KMS("Updating scaler for [CRTC:%i] scaler_user index %u.%u\n", intel_crtc->base.base.id, intel_crtc->pipe, SKL_CRTC_INDEX); - return skl_update_scaler(state, force_detach, SKL_CRTC_INDEX, + return skl_update_scaler(state, !state->base.active, SKL_CRTC_INDEX, &state->scaler_state.scaler_id, DRM_ROTATE_0, state->pipe_src_w, state->pipe_src_h, adjusted_mode->hdisplay, adjusted_mode->vdisplay); @@ -4453,7 +4455,15 @@ static int skl_update_scaler_plane(struct intel_crtc_state *crtc_state, return 0; } -static void skylake_pfit_update(struct intel_crtc *crtc, int enable) +static void skylake_scaler_disable(struct intel_crtc *crtc) +{ + int i; + + for (i = 0; i < crtc->num_scalers; i++) + skl_detach_scaler(crtc, i); +} + +static void skylake_pfit_enable(struct intel_crtc *crtc) { struct drm_device *dev = crtc->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; @@ -4463,13 +4473,6 @@ static void skylake_pfit_update(struct intel_crtc *crtc, int enable) DRM_DEBUG_KMS("for crtc_state = %p\n", crtc->config); - /* To update pfit, first update scaler state */ - skl_update_scaler_crtc(crtc->config, !enable); - intel_atomic_setup_scalers(crtc->base.dev, crtc, crtc->config); - skl_detach_scalers(crtc); - if (!enable) - return; - if (crtc->config->pch_pfit.enabled) { int id; @@ -4944,7 +4947,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc) intel_ddi_enable_pipe_clock(intel_crtc); if (INTEL_INFO(dev)->gen == 9) - skylake_pfit_update(intel_crtc, 1); + skylake_pfit_enable(intel_crtc); else if (INTEL_INFO(dev)->gen < 9) ironlake_pfit_enable(intel_crtc); else @@ -5081,7 +5084,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc) intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder); if (INTEL_INFO(dev)->gen == 9) - skylake_pfit_update(intel_crtc, 0); + skylake_scaler_disable(intel_crtc); else if (INTEL_INFO(dev)->gen < 9) ironlake_pfit_disable(intel_crtc); else @@ -11834,7 +11837,17 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, return ret; } - return intel_atomic_setup_scalers(dev, intel_crtc, pipe_config); + ret = 0; + if (INTEL_INFO(dev)->gen >= 9) { + if (mode_changed) + ret = skl_update_scaler_crtc(pipe_config); + + if (!ret) + ret = intel_atomic_setup_scalers(dev, intel_crtc, + pipe_config); + } + + return ret; } static const struct drm_crtc_helper_funcs intel_helper_funcs = { @@ -15355,6 +15368,11 @@ static void readout_plane_state(struct intel_crtc *crtc, continue; drm_plane_state = p->base.state; + + /* Plane scaler state is not touched here. The first atomic + * commit will restore all plane scalers to its old state. + */ + if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { visible = primary_get_hw_state(crtc); to_intel_plane_state(drm_plane_state)->visible = visible; diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 367f71224c96a..085d841560085 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1382,7 +1382,7 @@ intel_dp_compute_config(struct intel_encoder *encoder, if (INTEL_INFO(dev)->gen >= 9) { int ret; - ret = skl_update_scaler_crtc(pipe_config, 0); + ret = skl_update_scaler_crtc(pipe_config); if (ret) return ret; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b9c01c5b881fd..09a0a9222a3af 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1149,7 +1149,7 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc); void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file); -int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state, int force_detach); +int skl_update_scaler_crtc(struct intel_crtc_state *crtc_state); int skl_max_scale(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state); unsigned long intel_plane_obj_offset(struct intel_plane *intel_plane, -- GitLab From 8e9ba31a0f6c217e05f84efe9c569f9010a8ad26 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:16 +0200 Subject: [PATCH 0808/7006] drm/i915: Do not use plane_config in intel_fbdev.c Use the atomic state instead, this allows removing plane_config from the crtc after the full hw readout is completed. The size can be found in the fb, no need for the plane_config. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_fbdev.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index 33b3c9233eacb..b791f2374f3b5 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -581,7 +581,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, struct intel_framebuffer *fb = NULL; struct drm_crtc *crtc; struct intel_crtc *intel_crtc; - struct intel_initial_plane_config *plane_config = NULL; unsigned int max_size = 0; if (!i915.fastboot) @@ -589,20 +588,21 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, /* Find the largest fb */ for_each_crtc(dev, crtc) { + struct drm_i915_gem_object *obj = + intel_fb_obj(crtc->primary->state->fb); intel_crtc = to_intel_crtc(crtc); - if (!intel_crtc->active || !crtc->primary->fb) { + if (!intel_crtc->active || !obj) { DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n", pipe_name(intel_crtc->pipe)); continue; } - if (intel_crtc->plane_config.size > max_size) { + if (obj->base.size > max_size) { DRM_DEBUG_KMS("found possible fb from plane %c\n", pipe_name(intel_crtc->pipe)); - plane_config = &intel_crtc->plane_config; - fb = to_intel_framebuffer(crtc->primary->fb); - max_size = plane_config->size; + fb = to_intel_framebuffer(crtc->primary->state->fb); + max_size = obj->base.size; } } @@ -637,7 +637,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n", pipe_name(intel_crtc->pipe), cur_size, fb->base.pitches[0]); - plane_config = NULL; fb = NULL; break; } @@ -658,7 +657,6 @@ static bool intel_fbdev_init_bios(struct drm_device *dev, DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n", pipe_name(intel_crtc->pipe), cur_size, max_size); - plane_config = NULL; fb = NULL; break; } -- GitLab From cfb23ed622d040619abb91e625fcba74d356b8a8 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 12:17:40 +0200 Subject: [PATCH 0809/7006] drm/i915: Allow fuzzy matching in pipe_config_compare, v2. Instead of doing ad-hoc checks we already have a way of checking if the state is compatible or not. Use this to force a modeset. Only during modesets, or with PIPE_CONFIG_QUIRK_INHERITED_MODE we should check if a full modeset is really needed. Fastboot will allow the adjust parameter to ignore some stuff too, and it will fix up differences in state that are ignored by the compare function. Changes since v1: - Increase the value of the lowest m/n to prevent truncation. - Dump pipe config when fastboot's used, without a modeset. - Add adjust parameter to intel_compare_link_m_n, which is used to adjust m2_n2 if it's a multiple of m_n. - Add exact parameter intel_compare_m_n. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 218 +++++++++++++++++++-------- 1 file changed, 157 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 99897b152091f..541d2a8412799 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12288,19 +12288,6 @@ encoder_retry: DRM_DEBUG_KMS("plane bpp: %i, pipe bpp: %i, dithering: %i\n", base_bpp, pipe_config->pipe_bpp, pipe_config->dither); - /* Check if we need to force a modeset */ - if (pipe_config->has_audio != - to_intel_crtc_state(crtc->state)->has_audio) { - pipe_config->base.mode_changed = true; - ret = drm_atomic_add_affected_planes(state, crtc); - } - - /* - * Note we have an issue here with infoframes: current code - * only updates them on the full mode set path per hw - * requirements. So here we should be checking for any - * required changes and forcing a mode set. - */ fail: return ret; } @@ -12404,27 +12391,133 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2) base.head) \ if (mask & (1 <<(intel_crtc)->pipe)) + +static bool +intel_compare_m_n(unsigned int m, unsigned int n, + unsigned int m2, unsigned int n2, + bool exact) +{ + if (m == m2 && n == n2) + return true; + + if (exact || !m || !n || !m2 || !n2) + return false; + + BUILD_BUG_ON(DATA_LINK_M_N_MASK > INT_MAX); + + if (m > m2) { + while (m > m2) { + m2 <<= 1; + n2 <<= 1; + } + } else if (m < m2) { + while (m < m2) { + m <<= 1; + n <<= 1; + } + } + + return m == m2 && n == n2; +} + +static bool +intel_compare_link_m_n(const struct intel_link_m_n *m_n, + struct intel_link_m_n *m2_n2, + bool adjust) +{ + if (m_n->tu == m2_n2->tu && + intel_compare_m_n(m_n->gmch_m, m_n->gmch_n, + m2_n2->gmch_m, m2_n2->gmch_n, !adjust) && + intel_compare_m_n(m_n->link_m, m_n->link_n, + m2_n2->link_m, m2_n2->link_n, !adjust)) { + if (adjust) + *m2_n2 = *m_n; + + return true; + } + + return false; +} + static bool intel_pipe_config_compare(struct drm_device *dev, struct intel_crtc_state *current_config, - struct intel_crtc_state *pipe_config) + struct intel_crtc_state *pipe_config, + bool adjust) { + bool ret = true; + +#define INTEL_ERR_OR_DBG_KMS(fmt, ...) \ + do { \ + if (!adjust) \ + DRM_ERROR(fmt, ##__VA_ARGS__); \ + else \ + DRM_DEBUG_KMS(fmt, ##__VA_ARGS__); \ + } while (0) + #define PIPE_CONF_CHECK_X(name) \ if (current_config->name != pipe_config->name) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected 0x%08x, found 0x%08x)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_I(name) \ if (current_config->name != pipe_config->name) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i, found %i)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ + } + +#define PIPE_CONF_CHECK_M_N(name) \ + if (!intel_compare_link_m_n(¤t_config->name, \ + &pipe_config->name,\ + adjust)) { \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ + "(expected tu %i gmch %i/%i link %i/%i, " \ + "found tu %i, gmch %i/%i link %i/%i)\n", \ + current_config->name.tu, \ + current_config->name.gmch_m, \ + current_config->name.gmch_n, \ + current_config->name.link_m, \ + current_config->name.link_n, \ + pipe_config->name.tu, \ + pipe_config->name.gmch_m, \ + pipe_config->name.gmch_n, \ + pipe_config->name.link_m, \ + pipe_config->name.link_n); \ + ret = false; \ + } + +#define PIPE_CONF_CHECK_M_N_ALT(name, alt_name) \ + if (!intel_compare_link_m_n(¤t_config->name, \ + &pipe_config->name, adjust) && \ + !intel_compare_link_m_n(¤t_config->alt_name, \ + &pipe_config->name, adjust)) { \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ + "(expected tu %i gmch %i/%i link %i/%i, " \ + "or tu %i gmch %i/%i link %i/%i, " \ + "found tu %i, gmch %i/%i link %i/%i)\n", \ + current_config->name.tu, \ + current_config->name.gmch_m, \ + current_config->name.gmch_n, \ + current_config->name.link_m, \ + current_config->name.link_n, \ + current_config->alt_name.tu, \ + current_config->alt_name.gmch_m, \ + current_config->alt_name.gmch_n, \ + current_config->alt_name.link_m, \ + current_config->alt_name.link_n, \ + pipe_config->name.tu, \ + pipe_config->name.gmch_m, \ + pipe_config->name.gmch_n, \ + pipe_config->name.link_m, \ + pipe_config->name.link_n); \ + ret = false; \ } /* This is required for BDW+ where there is only one set of registers for @@ -12435,30 +12528,30 @@ intel_pipe_config_compare(struct drm_device *dev, #define PIPE_CONF_CHECK_I_ALT(name, alt_name) \ if ((current_config->name != pipe_config->name) && \ (current_config->alt_name != pipe_config->name)) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i or %i, found %i)\n", \ current_config->name, \ current_config->alt_name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_FLAGS(name, mask) \ if ((current_config->name ^ pipe_config->name) & (mask)) { \ - DRM_ERROR("mismatch in " #name "(" #mask ") " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name "(" #mask ") " \ "(expected %i, found %i)\n", \ current_config->name & (mask), \ pipe_config->name & (mask)); \ - return false; \ + ret = false; \ } #define PIPE_CONF_CHECK_CLOCK_FUZZY(name) \ if (!intel_fuzzy_clock_check(current_config->name, pipe_config->name)) { \ - DRM_ERROR("mismatch in " #name " " \ + INTEL_ERR_OR_DBG_KMS("mismatch in " #name " " \ "(expected %i, found %i)\n", \ current_config->name, \ pipe_config->name); \ - return false; \ + ret = false; \ } #define PIPE_CONF_QUIRK(quirk) \ @@ -12468,35 +12561,18 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(has_pch_encoder); PIPE_CONF_CHECK_I(fdi_lanes); - PIPE_CONF_CHECK_I(fdi_m_n.gmch_m); - PIPE_CONF_CHECK_I(fdi_m_n.gmch_n); - PIPE_CONF_CHECK_I(fdi_m_n.link_m); - PIPE_CONF_CHECK_I(fdi_m_n.link_n); - PIPE_CONF_CHECK_I(fdi_m_n.tu); + PIPE_CONF_CHECK_M_N(fdi_m_n); PIPE_CONF_CHECK_I(has_dp_encoder); if (INTEL_INFO(dev)->gen < 8) { - PIPE_CONF_CHECK_I(dp_m_n.gmch_m); - PIPE_CONF_CHECK_I(dp_m_n.gmch_n); - PIPE_CONF_CHECK_I(dp_m_n.link_m); - PIPE_CONF_CHECK_I(dp_m_n.link_n); - PIPE_CONF_CHECK_I(dp_m_n.tu); - - if (current_config->has_drrs) { - PIPE_CONF_CHECK_I(dp_m2_n2.gmch_m); - PIPE_CONF_CHECK_I(dp_m2_n2.gmch_n); - PIPE_CONF_CHECK_I(dp_m2_n2.link_m); - PIPE_CONF_CHECK_I(dp_m2_n2.link_n); - PIPE_CONF_CHECK_I(dp_m2_n2.tu); - } - } else { - PIPE_CONF_CHECK_I_ALT(dp_m_n.gmch_m, dp_m2_n2.gmch_m); - PIPE_CONF_CHECK_I_ALT(dp_m_n.gmch_n, dp_m2_n2.gmch_n); - PIPE_CONF_CHECK_I_ALT(dp_m_n.link_m, dp_m2_n2.link_m); - PIPE_CONF_CHECK_I_ALT(dp_m_n.link_n, dp_m2_n2.link_n); - PIPE_CONF_CHECK_I_ALT(dp_m_n.tu, dp_m2_n2.tu); - } + PIPE_CONF_CHECK_M_N(dp_m_n); + + PIPE_CONF_CHECK_I(has_drrs); + if (current_config->has_drrs) + PIPE_CONF_CHECK_M_N(dp_m2_n2); + } else + PIPE_CONF_CHECK_M_N_ALT(dp_m_n, dp_m2_n2); PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay); PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal); @@ -12592,8 +12668,9 @@ intel_pipe_config_compare(struct drm_device *dev, #undef PIPE_CONF_CHECK_FLAGS #undef PIPE_CONF_CHECK_CLOCK_FUZZY #undef PIPE_CONF_QUIRK +#undef INTEL_ERR_OR_DBG_KMS - return true; + return ret; } static void check_wm_state(struct drm_device *dev) @@ -12785,8 +12862,11 @@ check_crtc_state(struct drm_device *dev) "transitional active state does not match atomic hw state " "(expected %i, found %i)\n", crtc->base.state->active, crtc->active); - if (active && - !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) { + if (!active) + continue; + + if (!intel_pipe_config_compare(dev, crtc->config, + &pipe_config, false)) { I915_STATE_WARN(1, "pipe state doesn't match!\n"); intel_dump_pipe_config(crtc, &pipe_config, "[hw state]"); @@ -13087,14 +13167,17 @@ intel_modeset_compute_config(struct drm_atomic_state *state) return ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct intel_crtc_state *pipe_config = + to_intel_crtc_state(crtc_state); + bool modeset, recalc; + if (!crtc_state->enable) { if (needs_modeset(crtc_state)) any_ms = true; continue; } - if (to_intel_crtc_state(crtc_state)->quirks & - PIPE_CONFIG_QUIRK_INITIAL_PLANES) { + if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { ret = drm_atomic_add_affected_planes(state, crtc); if (ret) return ret; @@ -13107,23 +13190,36 @@ intel_modeset_compute_config(struct drm_atomic_state *state) */ } - if (!needs_modeset(crtc_state)) { + modeset = needs_modeset(crtc_state); + recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE; + + if (!modeset && !recalc) + continue; + + if (recalc) { ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) return ret; } - ret = intel_modeset_pipe_config(crtc, - to_intel_crtc_state(crtc_state)); + ret = intel_modeset_pipe_config(crtc, pipe_config); if (ret) return ret; - if (needs_modeset(crtc_state)) - any_ms = true; + if (recalc && !intel_pipe_config_compare(state->dev, + to_intel_crtc_state(crtc->state), + pipe_config, true)) { + modeset = crtc_state->mode_changed = true; + + ret = drm_atomic_add_affected_planes(state, crtc); + if (ret) + return ret; + } + any_ms = modeset; intel_dump_pipe_config(to_intel_crtc(crtc), - to_intel_crtc_state(crtc_state), - "[modeset]"); + pipe_config, + modeset ? "[modeset]" : "[fastboot]"); } if (any_ms) { -- GitLab From be5651f2d5814cefbe89b17c187309ad4c1d3967 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:18 +0200 Subject: [PATCH 0810/7006] drm/i915: Update missing properties in find_initial_plane_obj The src and crtc rectangles were never set, resulting in the primary plane being made invisible on first atomic update. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 541d2a8412799..d013a34dde7fd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -2588,6 +2588,7 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, struct intel_crtc *i; struct drm_i915_gem_object *obj; struct drm_plane *primary = intel_crtc->base.primary; + struct drm_plane_state *plane_state = primary->state; struct drm_framebuffer *fb; if (!plane_config->fb) @@ -2627,13 +2628,21 @@ intel_find_initial_plane_obj(struct intel_crtc *intel_crtc, return; valid_fb: + plane_state->src_x = plane_state->src_y = 0; + plane_state->src_w = fb->width << 16; + plane_state->src_h = fb->height << 16; + + plane_state->crtc_x = plane_state->src_y = 0; + plane_state->crtc_w = fb->width; + plane_state->crtc_h = fb->height; + obj = intel_fb_obj(fb); if (obj->tiling_mode != I915_TILING_NONE) dev_priv->preserve_bios_swizzle = true; - primary->fb = fb; + drm_framebuffer_reference(fb); + primary->fb = primary->state->fb = fb; primary->crtc = primary->state->crtc = &intel_crtc->base; - update_state_fb(primary); intel_crtc->base.state->plane_mask |= (1 << drm_plane_index(primary)); obj->frontbuffer_bits |= to_intel_plane(primary)->frontbuffer_bit; } -- GitLab From eeebeac5e476800991ea1d10827307c41650ba11 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 12:33:29 +0200 Subject: [PATCH 0811/7006] drm/i915: Remove plane_config from struct intel_crtc, v2. Nothing depends on this outside initial hw readout, so keep this struct on the stack instead. Changes since v1: - Remove unrelated changes. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 19 ++++++++++--------- drivers/gpu/drm/i915/intel_drv.h | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index d013a34dde7fd..b0a3120c6da11 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15202,6 +15202,8 @@ void intel_modeset_init(struct drm_device *dev) drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { + struct intel_initial_plane_config plane_config = {}; + if (!crtc->active) continue; @@ -15212,15 +15214,14 @@ void intel_modeset_init(struct drm_device *dev) * can even allow for smooth boot transitions if the BIOS * fb is large enough for the active pipe configuration. */ - if (dev_priv->display.get_initial_plane_config) { - dev_priv->display.get_initial_plane_config(crtc, - &crtc->plane_config); - /* - * If the fb is shared between multiple heads, we'll - * just get the first one. - */ - intel_find_initial_plane_obj(crtc, &crtc->plane_config); - } + dev_priv->display.get_initial_plane_config(crtc, + &plane_config); + + /* + * If the fb is shared between multiple heads, we'll + * just get the first one. + */ + intel_find_initial_plane_obj(crtc, &plane_config); } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 09a0a9222a3af..09e3581c84411 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -550,7 +550,6 @@ struct intel_crtc { uint32_t cursor_size; uint32_t cursor_base; - struct intel_initial_plane_config plane_config; struct intel_crtc_state *config; bool new_enabled; -- GitLab From 6d00d153f00097d259f86304e11858a50a1b8ad1 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Mon, 13 Jul 2015 15:23:54 -0700 Subject: [PATCH 0812/7006] HID: cp2112: fix I2C_SMBUS_BYTE write When doing an I2C_SMBUS_BYTE write (one byte write, no address), the data to be written is in "command" not "data->byte". Signed-off-by: Ellen Wang Acked-by: Wolfram Sang Reviewed-by: Antonio Borneo Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 1d24a65b42952..a84d3700e740e 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -606,7 +606,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, if (I2C_SMBUS_READ == read_write) count = cp2112_read_req(buf, addr, read_length); else - count = cp2112_write_req(buf, addr, data->byte, NULL, + count = cp2112_write_req(buf, addr, command, NULL, 0); break; case I2C_SMBUS_BYTE_DATA: -- GitLab From f312bc59d21bed7593199a1921468868150954fa Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Tue, 14 Jul 2015 14:51:26 +0800 Subject: [PATCH 0813/7006] ASoC: rt5645: Remove irq_jack_detection function irq_jack_detection is only called from rt5645_jack_detect_work: remove the function to simplify the code. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 53 ++++++++++++++++----------------------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9dfa431b337d7..8693a25830d3d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2874,7 +2874,18 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) return rt5645->jack_type; } -static int rt5645_irq_detection(struct rt5645_priv *rt5645); +static int rt5645_button_detect(struct snd_soc_codec *codec) +{ + int btn_type, val; + + val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1); + pr_debug("val=0x%x\n", val); + btn_type = val & 0xfff0; + snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val); + + return btn_type; +} + static irqreturn_t rt5645_irq(int irq, void *data); int rt5645_set_jack_detect(struct snd_soc_codec *codec, @@ -2905,34 +2916,6 @@ static void rt5645_jack_detect_work(struct work_struct *work) { struct rt5645_priv *rt5645 = container_of(work, struct rt5645_priv, jack_detect_work.work); - - rt5645_irq_detection(rt5645); -} - -static irqreturn_t rt5645_irq(int irq, void *data) -{ - struct rt5645_priv *rt5645 = data; - - queue_delayed_work(system_power_efficient_wq, - &rt5645->jack_detect_work, msecs_to_jiffies(250)); - - return IRQ_HANDLED; -} - -static int rt5645_button_detect(struct snd_soc_codec *codec) -{ - int btn_type, val; - - val = snd_soc_read(codec, RT5650_4BTN_IL_CMD1); - pr_debug("val=0x%x\n", val); - btn_type = val & 0xfff0; - snd_soc_write(codec, RT5650_4BTN_IL_CMD1, val); - - return btn_type; -} - -static int rt5645_irq_detection(struct rt5645_priv *rt5645) -{ int val, btn_type, gpio_state = 0, report = 0; switch (rt5645->pdata.jd_mode) { @@ -2947,7 +2930,7 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645) report, SND_JACK_HEADPHONE); snd_soc_jack_report(rt5645->mic_jack, report, SND_JACK_MICROPHONE); - return report; + return; case 1: /* 2 port */ val = snd_soc_read(rt5645->codec, RT5645_A_JD_CTRL1) & 0x0070; break; @@ -3029,8 +3012,16 @@ static int rt5645_irq_detection(struct rt5645_priv *rt5645) snd_soc_jack_report(rt5645->btn_jack, report, SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3); +} - return report; +static irqreturn_t rt5645_irq(int irq, void *data) +{ + struct rt5645_priv *rt5645 = data; + + queue_delayed_work(system_power_efficient_wq, + &rt5645->jack_detect_work, msecs_to_jiffies(250)); + + return IRQ_HANDLED; } static int rt5645_probe(struct snd_soc_codec *codec) -- GitLab From faf4ffe031df41c067f3b89632ce3d3667bb64ad Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Jul 2015 10:59:30 +0200 Subject: [PATCH 0814/7006] drm/i915: Remove unused compat32 code Totatlly forgotten that we have these when nuking all the UMS code. Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_ioc32.c | 125 ------------------------------ 1 file changed, 125 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index 176de6322e4d0..6eec2221b44e9 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -35,98 +35,6 @@ #include #include "i915_drv.h" -typedef struct _drm_i915_batchbuffer32 { - int start; /* agp offset */ - int used; /* nr bytes in use */ - int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ - int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ - int num_cliprects; /* mulitpass with multiple cliprects? */ - u32 cliprects; /* pointer to userspace cliprects */ -} drm_i915_batchbuffer32_t; - -static int compat_i915_batchbuffer(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_batchbuffer32_t batchbuffer32; - drm_i915_batchbuffer_t __user *batchbuffer; - - if (copy_from_user - (&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32))) - return -EFAULT; - - batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer)); - if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer)) - || __put_user(batchbuffer32.start, &batchbuffer->start) - || __put_user(batchbuffer32.used, &batchbuffer->used) - || __put_user(batchbuffer32.DR1, &batchbuffer->DR1) - || __put_user(batchbuffer32.DR4, &batchbuffer->DR4) - || __put_user(batchbuffer32.num_cliprects, - &batchbuffer->num_cliprects) - || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects, - &batchbuffer->cliprects)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_BATCHBUFFER, - (unsigned long)batchbuffer); -} - -typedef struct _drm_i915_cmdbuffer32 { - u32 buf; /* pointer to userspace command buffer */ - int sz; /* nr bytes in buf */ - int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ - int DR4; /* window origin for GFX_OP_DRAWRECT_INFO */ - int num_cliprects; /* mulitpass with multiple cliprects? */ - u32 cliprects; /* pointer to userspace cliprects */ -} drm_i915_cmdbuffer32_t; - -static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_cmdbuffer32_t cmdbuffer32; - drm_i915_cmdbuffer_t __user *cmdbuffer; - - if (copy_from_user - (&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32))) - return -EFAULT; - - cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer)); - if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer)) - || __put_user((int __user *)(unsigned long)cmdbuffer32.buf, - &cmdbuffer->buf) - || __put_user(cmdbuffer32.sz, &cmdbuffer->sz) - || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1) - || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4) - || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects) - || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects, - &cmdbuffer->cliprects)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_CMDBUFFER, - (unsigned long)cmdbuffer); -} - -typedef struct drm_i915_irq_emit32 { - u32 irq_seq; -} drm_i915_irq_emit32_t; - -static int compat_i915_irq_emit(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_irq_emit32_t req32; - drm_i915_irq_emit_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user((int __user *)(unsigned long)req32.irq_seq, - &request->irq_seq)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_IRQ_EMIT, - (unsigned long)request); -} typedef struct drm_i915_getparam32 { int param; u32 value; @@ -152,41 +60,8 @@ static int compat_i915_getparam(struct file *file, unsigned int cmd, (unsigned long)request); } -typedef struct drm_i915_mem_alloc32 { - int region; - int alignment; - int size; - u32 region_offset; /* offset from start of fb or agp */ -} drm_i915_mem_alloc32_t; - -static int compat_i915_alloc(struct file *file, unsigned int cmd, - unsigned long arg) -{ - drm_i915_mem_alloc32_t req32; - drm_i915_mem_alloc_t __user *request; - - if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) - return -EFAULT; - - request = compat_alloc_user_space(sizeof(*request)); - if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) - || __put_user(req32.region, &request->region) - || __put_user(req32.alignment, &request->alignment) - || __put_user(req32.size, &request->size) - || __put_user((void __user *)(unsigned long)req32.region_offset, - &request->region_offset)) - return -EFAULT; - - return drm_ioctl(file, DRM_IOCTL_I915_ALLOC, - (unsigned long)request); -} - static drm_ioctl_compat_t *i915_compat_ioctls[] = { - [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer, - [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer, [DRM_I915_GETPARAM] = compat_i915_getparam, - [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit, - [DRM_I915_ALLOC] = compat_i915_alloc }; /** -- GitLab From 3bbaba0ceaa254c9ee261e329bfd92e4ba4fe32a Mon Sep 17 00:00:00 2001 From: Peter Antoine Date: Fri, 10 Jul 2015 20:13:11 +0300 Subject: [PATCH 0815/7006] drm/i915: Added Programming of the MOCS This change adds the programming of the MOCS registers to the gen 9+ platforms. The set of MOCS configuration entries introduced by this patch is intended to be minimal but sufficient to cover the needs of current userspace - i.e. a good set of defaults. It is expected to be extended in the future to provide further default values or to allow userspace to redefine its private MOCS tables based on its demand for additional caching configurations. In this setup, userspace should only utilize the first N entries, higher entries are reserved for future use. It creates a fixed register set that is programmed across the different engines so that all engines have the same table. This is done as the main RCS context only holds the registers for itself and the shared L3 values. By trying to keep the registers consistent across the different engines it should make the programming for the registers consistent. v2: -'static const' for private data structures and style changes.(Matt Turner) v3: - Make the tables "slightly" more readable. (Damien Lespiau) - Updated tables fix performance regression. v4: - Code formatting. (Chris Wilson) - re-privatised mocs code. (Daniel Vetter) v5: - Changed the name of a function. (Chris Wilson) v6: - re-based - Added Mesa table entry (skylake & broxton) (Francisco Jerez) - Tidied up the readability defines (Francisco Jerez) - NUMBER of entries defines wrong. (Jim Bish) - Added comments to clear up the meaning of the tables (Jim Bish) Signed-off-by: Peter Antoine v7 (Francisco Jerez): - Don't write L3-specific MOCS_ESC/SCC values into the e/LLC control tables. Prefix L3-specific defines consistently with L3_ and e/LLC-specific defines with LE_ to avoid this kind of confusion in the future. - Change L3CC WT define back to RESERVED (matches my hardware documentation and the original patch, probably a misunderstanding of my own previous comment). - Drop Android tables, define new minimal tables more suitable for the open source stack. - Add comment that the MOCS tables are part of the kernel ABI. - Move intel_logical_ring_begin() and _advance() calls one level down (Chris Wilson). - Minor formatting and style fixes. v8 (Francisco Jerez): - Add table size sanity check to emit_mocs_control/l3cc_table() (Chris Wilson). - Add comment about undefined entries being implicitly set to uncached for forwards compatibility. v9 (Francisco Jerez): - Minor style fixes. Signed-off-by: Francisco Jerez Acked-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_reg.h | 9 + drivers/gpu/drm/i915/intel_lrc.c | 12 +- drivers/gpu/drm/i915/intel_lrc.h | 1 + drivers/gpu/drm/i915/intel_mocs.c | 335 ++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_mocs.h | 57 +++++ 6 files changed, 413 insertions(+), 2 deletions(-) create mode 100644 drivers/gpu/drm/i915/intel_mocs.c create mode 100644 drivers/gpu/drm/i915/intel_mocs.h diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index de21965433676..e52e012516445 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -36,6 +36,7 @@ i915-y += i915_cmd_parser.o \ i915_trace_points.o \ intel_hotplug.o \ intel_lrc.o \ + intel_mocs.o \ intel_ringbuffer.o \ intel_uncore.o diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 0650a3d8a40f8..97794bc753f27 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -7902,4 +7902,13 @@ enum skl_disp_power_wells { #define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000) #define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800) +/* MOCS (Memory Object Control State) registers */ +#define GEN9_LNCFCMOCS0 0xb020 /* L3 Cache Control base */ + +#define GEN9_GFX_MOCS_0 0xc800 /* Graphics MOCS base register*/ +#define GEN9_MFX0_MOCS_0 0xc900 /* Media 0 MOCS base register*/ +#define GEN9_MFX1_MOCS_0 0xca00 /* Media 1 MOCS base register*/ +#define GEN9_VEBOX_MOCS_0 0xcb00 /* Video MOCS base register*/ +#define GEN9_BLT_MOCS_0 0xcc00 /* Blitter MOCS base register*/ + #endif /* _I915_REG_H_ */ diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 971d7b0ae0174..d7f66d2899702 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -135,6 +135,7 @@ #include #include #include "i915_drv.h" +#include "intel_mocs.h" #define GEN9_LR_CONTEXT_RENDER_SIZE (22 * PAGE_SIZE) #define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE) @@ -772,8 +773,7 @@ static int logical_ring_prepare(struct drm_i915_gem_request *req, int bytes) * * Return: non-zero if the ringbuffer is not ready to be written to. */ -static int intel_logical_ring_begin(struct drm_i915_gem_request *req, - int num_dwords) +int intel_logical_ring_begin(struct drm_i915_gem_request *req, int num_dwords) { struct drm_i915_private *dev_priv; int ret; @@ -1670,6 +1670,14 @@ static int gen8_init_rcs_context(struct drm_i915_gem_request *req) if (ret) return ret; + ret = intel_rcs_context_init_mocs(req); + /* + * Failing to program the MOCS is non-fatal.The system will not + * run at peak performance. So generate an error and carry on. + */ + if (ret) + DRM_ERROR("MOCS failed to program: expect performance issues.\n"); + return intel_lr_context_render_state_init(req); } diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index e0299fbb1728f..64f89f9982a20 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -42,6 +42,7 @@ int intel_logical_ring_reserve_space(struct drm_i915_gem_request *request); void intel_logical_ring_stop(struct intel_engine_cs *ring); void intel_logical_ring_cleanup(struct intel_engine_cs *ring); int intel_logical_rings_init(struct drm_device *dev); +int intel_logical_ring_begin(struct drm_i915_gem_request *req, int num_dwords); int logical_ring_flush_all_caches(struct drm_i915_gem_request *req); /** diff --git a/drivers/gpu/drm/i915/intel_mocs.c b/drivers/gpu/drm/i915/intel_mocs.c new file mode 100644 index 0000000000000..6d3c6c0a5c621 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_mocs.c @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2015 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. + */ + +#include "intel_mocs.h" +#include "intel_lrc.h" +#include "intel_ringbuffer.h" + +/* structures required */ +struct drm_i915_mocs_entry { + u32 control_value; + u16 l3cc_value; +}; + +struct drm_i915_mocs_table { + u32 size; + const struct drm_i915_mocs_entry *table; +}; + +/* Defines for the tables (XXX_MOCS_0 - XXX_MOCS_63) */ +#define LE_CACHEABILITY(value) ((value) << 0) +#define LE_TGT_CACHE(value) ((value) << 2) +#define LE_LRUM(value) ((value) << 4) +#define LE_AOM(value) ((value) << 6) +#define LE_RSC(value) ((value) << 7) +#define LE_SCC(value) ((value) << 8) +#define LE_PFM(value) ((value) << 11) +#define LE_SCF(value) ((value) << 14) + +/* Defines for the tables (LNCFMOCS0 - LNCFMOCS31) - two entries per word */ +#define L3_ESC(value) ((value) << 0) +#define L3_SCC(value) ((value) << 1) +#define L3_CACHEABILITY(value) ((value) << 4) + +/* Helper defines */ +#define GEN9_NUM_MOCS_ENTRIES 62 /* 62 out of 64 - 63 & 64 are reserved. */ + +/* (e)LLC caching options */ +#define LE_PAGETABLE 0 +#define LE_UC 1 +#define LE_WT 2 +#define LE_WB 3 + +/* L3 caching options */ +#define L3_DIRECT 0 +#define L3_UC 1 +#define L3_RESERVED 2 +#define L3_WB 3 + +/* Target cache */ +#define ELLC 0 +#define LLC 1 +#define LLC_ELLC 2 + +/* + * MOCS tables + * + * These are the MOCS tables that are programmed across all the rings. + * The control value is programmed to all the rings that support the + * MOCS registers. While the l3cc_values are only programmed to the + * LNCFCMOCS0 - LNCFCMOCS32 registers. + * + * These tables are intended to be kept reasonably consistent across + * platforms. However some of the fields are not applicable to all of + * them. + * + * Entries not part of the following tables are undefined as far as + * userspace is concerned and shouldn't be relied upon. For the time + * being they will be implicitly initialized to the strictest caching + * configuration (uncached) to guarantee forwards compatibility with + * userspace programs written against more recent kernels providing + * additional MOCS entries. + * + * NOTE: These tables MUST start with being uncached and the length + * MUST be less than 63 as the last two registers are reserved + * by the hardware. These tables are part of the kernel ABI and + * may only be updated incrementally by adding entries at the + * end. + */ +static const struct drm_i915_mocs_entry skylake_mocs_table[] = { + /* { 0x00000009, 0x0010 } */ + { (LE_CACHEABILITY(LE_UC) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(0) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC)) }, + /* { 0x00000038, 0x0030 } */ + { (LE_CACHEABILITY(LE_PAGETABLE) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) }, + /* { 0x0000003b, 0x0030 } */ + { (LE_CACHEABILITY(LE_WB) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) } +}; + +/* NOTE: the LE_TGT_CACHE is not used on Broxton */ +static const struct drm_i915_mocs_entry broxton_mocs_table[] = { + /* { 0x00000009, 0x0010 } */ + { (LE_CACHEABILITY(LE_UC) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(0) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_UC)) }, + /* { 0x00000038, 0x0030 } */ + { (LE_CACHEABILITY(LE_PAGETABLE) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) }, + /* { 0x0000003b, 0x0030 } */ + { (LE_CACHEABILITY(LE_WB) | LE_TGT_CACHE(LLC_ELLC) | LE_LRUM(3) | + LE_AOM(0) | LE_RSC(0) | LE_SCC(0) | LE_PFM(0) | LE_SCF(0)), + (L3_ESC(0) | L3_SCC(0) | L3_CACHEABILITY(L3_WB)) } +}; + +/** + * get_mocs_settings() + * @dev: DRM device. + * @table: Output table that will be made to point at appropriate + * MOCS values for the device. + * + * This function will return the values of the MOCS table that needs to + * be programmed for the platform. It will return the values that need + * to be programmed and if they need to be programmed. + * + * Return: true if there are applicable MOCS settings for the device. + */ +static bool get_mocs_settings(struct drm_device *dev, + struct drm_i915_mocs_table *table) +{ + bool result = false; + + if (IS_SKYLAKE(dev)) { + table->size = ARRAY_SIZE(skylake_mocs_table); + table->table = skylake_mocs_table; + result = true; + } else if (IS_BROXTON(dev)) { + table->size = ARRAY_SIZE(broxton_mocs_table); + table->table = broxton_mocs_table; + result = true; + } else { + WARN_ONCE(INTEL_INFO(dev)->gen >= 9, + "Platform that should have a MOCS table does not.\n"); + } + + return result; +} + +/** + * emit_mocs_control_table() - emit the mocs control table + * @req: Request to set up the MOCS table for. + * @table: The values to program into the control regs. + * @reg_base: The base for the engine that needs to be programmed. + * + * This function simply emits a MI_LOAD_REGISTER_IMM command for the + * given table starting at the given address. + * + * Return: 0 on success, otherwise the error status. + */ +static int emit_mocs_control_table(struct drm_i915_gem_request *req, + const struct drm_i915_mocs_table *table, + u32 reg_base) +{ + struct intel_ringbuffer *ringbuf = req->ringbuf; + unsigned int index; + int ret; + + if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES)) + return -ENODEV; + + ret = intel_logical_ring_begin(req, 2 + 2 * GEN9_NUM_MOCS_ENTRIES); + if (ret) { + DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret); + return ret; + } + + intel_logical_ring_emit(ringbuf, + MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES)); + + for (index = 0; index < table->size; index++) { + intel_logical_ring_emit(ringbuf, reg_base + index * 4); + intel_logical_ring_emit(ringbuf, + table->table[index].control_value); + } + + /* + * Ok, now set the unused entries to uncached. These entries + * are officially undefined and no contract for the contents + * and settings is given for these entries. + * + * Entry 0 in the table is uncached - so we are just writing + * that value to all the used entries. + */ + for (; index < GEN9_NUM_MOCS_ENTRIES; index++) { + intel_logical_ring_emit(ringbuf, reg_base + index * 4); + intel_logical_ring_emit(ringbuf, table->table[0].control_value); + } + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + +/** + * emit_mocs_l3cc_table() - emit the mocs control table + * @req: Request to set up the MOCS table for. + * @table: The values to program into the control regs. + * + * This function simply emits a MI_LOAD_REGISTER_IMM command for the + * given table starting at the given address. This register set is + * programmed in pairs. + * + * Return: 0 on success, otherwise the error status. + */ +static int emit_mocs_l3cc_table(struct drm_i915_gem_request *req, + const struct drm_i915_mocs_table *table) +{ + struct intel_ringbuffer *ringbuf = req->ringbuf; + unsigned int count; + unsigned int i; + u32 value; + u32 filler = (table->table[0].l3cc_value & 0xffff) | + ((table->table[0].l3cc_value & 0xffff) << 16); + int ret; + + if (WARN_ON(table->size > GEN9_NUM_MOCS_ENTRIES)) + return -ENODEV; + + ret = intel_logical_ring_begin(req, 2 + GEN9_NUM_MOCS_ENTRIES); + if (ret) { + DRM_DEBUG("intel_logical_ring_begin failed %d\n", ret); + return ret; + } + + intel_logical_ring_emit(ringbuf, + MI_LOAD_REGISTER_IMM(GEN9_NUM_MOCS_ENTRIES / 2)); + + for (i = 0, count = 0; i < table->size / 2; i++, count += 2) { + value = (table->table[count].l3cc_value & 0xffff) | + ((table->table[count + 1].l3cc_value & 0xffff) << 16); + + intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4); + intel_logical_ring_emit(ringbuf, value); + } + + if (table->size & 0x01) { + /* Odd table size - 1 left over */ + value = (table->table[count].l3cc_value & 0xffff) | + ((table->table[0].l3cc_value & 0xffff) << 16); + } else + value = filler; + + /* + * Now set the rest of the table to uncached - use entry 0 as + * this will be uncached. Leave the last pair uninitialised as + * they are reserved by the hardware. + */ + for (; i < GEN9_NUM_MOCS_ENTRIES / 2; i++) { + intel_logical_ring_emit(ringbuf, GEN9_LNCFCMOCS0 + i * 4); + intel_logical_ring_emit(ringbuf, value); + + value = filler; + } + + intel_logical_ring_emit(ringbuf, MI_NOOP); + intel_logical_ring_advance(ringbuf); + + return 0; +} + +/** + * intel_rcs_context_init_mocs() - program the MOCS register. + * @req: Request to set up the MOCS tables for. + * + * This function will emit a batch buffer with the values required for + * programming the MOCS register values for all the currently supported + * rings. + * + * These registers are partially stored in the RCS context, so they are + * emitted at the same time so that when a context is created these registers + * are set up. These registers have to be emitted into the start of the + * context as setting the ELSP will re-init some of these registers back + * to the hw values. + * + * Return: 0 on success, otherwise the error status. + */ +int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req) +{ + struct drm_i915_mocs_table t; + int ret; + + if (get_mocs_settings(req->ring->dev, &t)) { + /* Program the control registers */ + ret = emit_mocs_control_table(req, &t, GEN9_GFX_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_MFX0_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_MFX1_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_VEBOX_MOCS_0); + if (ret) + return ret; + + ret = emit_mocs_control_table(req, &t, GEN9_BLT_MOCS_0); + if (ret) + return ret; + + /* Now program the l3cc registers */ + ret = emit_mocs_l3cc_table(req, &t); + if (ret) + return ret; + } + + return 0; +} diff --git a/drivers/gpu/drm/i915/intel_mocs.h b/drivers/gpu/drm/i915/intel_mocs.h new file mode 100644 index 0000000000000..76e45b1748b31 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_mocs.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2015 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. + */ + +#ifndef INTEL_MOCS_H +#define INTEL_MOCS_H + +/** + * DOC: Memory Objects Control State (MOCS) + * + * Motivation: + * In previous Gens the MOCS settings was a value that was set by user land as + * part of the batch. In Gen9 this has changed to be a single table (per ring) + * that all batches now reference by index instead of programming the MOCS + * directly. + * + * The one wrinkle in this is that only PART of the MOCS tables are included + * in context (The GFX_MOCS_0 - GFX_MOCS_64 and the LNCFCMOCS0 - LNCFCMOCS32 + * registers). The rest are not (the settings for the other rings). + * + * This table needs to be set at system start-up because the way the table + * interacts with the contexts and the GmmLib interface. + * + * + * Implementation: + * + * The tables (one per supported platform) are defined in intel_mocs.c + * and are programmed in the first batch after the context is loaded + * (with the hardware workarounds). This will then let the usual + * context handling keep the MOCS in step. + */ + +#include +#include "i915_drv.h" + +int intel_rcs_context_init_mocs(struct drm_i915_gem_request *req); + +#endif -- GitLab From 4cf0ebbd4fafbdf8e6431dbb315e5511c3efdc3b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:20 +0200 Subject: [PATCH 0816/7006] drm/i915: Rework plane readout. All non-primary planes get disabled during hw readout, this reduces complexity and means not having to do some plane visibility checks during the first commit. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_atomic.c | 7 --- drivers/gpu/drm/i915/intel_display.c | 86 +++------------------------- drivers/gpu/drm/i915/intel_drv.h | 1 - 3 files changed, 8 insertions(+), 86 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index b92b8581efc2b..dcf4fb458649a 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -98,13 +98,6 @@ int intel_atomic_check(struct drm_device *dev, return -EINVAL; } - if (crtc_state && - crtc_state->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { - ret = drm_atomic_add_affected_planes(state, &nuclear_crtc->base); - if (ret) - return ret; - } - ret = drm_atomic_helper_check_planes(dev, state); if (ret) return ret; diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b0a3120c6da11..ba2c933fcea22 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11781,34 +11781,6 @@ static bool check_encoder_cloning(struct drm_atomic_state *state, return true; } -static void intel_crtc_check_initial_planes(struct drm_crtc *crtc, - struct drm_crtc_state *crtc_state) -{ - struct intel_crtc_state *pipe_config = - to_intel_crtc_state(crtc_state); - struct drm_plane *p; - unsigned visible_mask = 0; - - drm_for_each_plane_mask(p, crtc->dev, crtc_state->plane_mask) { - struct drm_plane_state *plane_state = - drm_atomic_get_existing_plane_state(crtc_state->state, p); - - if (WARN_ON(!plane_state)) - continue; - - if (!plane_state->fb) - crtc_state->plane_mask &= - ~(1 << drm_plane_index(p)); - else if (to_intel_plane_state(plane_state)->visible) - visible_mask |= 1 << drm_plane_index(p); - } - - if (!visible_mask) - return; - - pipe_config->quirks &= ~PIPE_CONFIG_QUIRK_INITIAL_PLANES; -} - static int intel_crtc_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *crtc_state) { @@ -11830,10 +11802,6 @@ static int intel_crtc_atomic_check(struct drm_crtc *crtc, "[CRTC:%i] mismatch between state->active(%i) and crtc->active(%i)\n", idx, crtc->state->active, intel_crtc->active); - /* plane mask is fixed up after all initial planes are calculated */ - if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) - intel_crtc_check_initial_planes(crtc, crtc_state); - if (mode_changed && !crtc_state->active) intel_crtc->atomic.update_wm_post = true; @@ -13186,19 +13154,6 @@ intel_modeset_compute_config(struct drm_atomic_state *state) continue; } - if (pipe_config->quirks & PIPE_CONFIG_QUIRK_INITIAL_PLANES) { - ret = drm_atomic_add_affected_planes(state, crtc); - if (ret) - return ret; - - /* - * We ought to handle i915.fastboot here. - * If no modeset is required and the primary plane has - * a fb, update the members of crtc_state as needed, - * and run the necessary updates during vblank evasion. - */ - } - modeset = needs_modeset(crtc_state); recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE; @@ -15456,47 +15411,22 @@ static void readout_plane_state(struct intel_crtc *crtc, struct intel_crtc_state *crtc_state) { struct intel_plane *p; - struct drm_plane_state *drm_plane_state; + struct intel_plane_state *plane_state; bool active = crtc_state->base.active; - if (active) { - crtc_state->quirks |= PIPE_CONFIG_QUIRK_INITIAL_PLANES; - - /* apply to previous sw state too */ - to_intel_crtc_state(crtc->base.state)->quirks |= - PIPE_CONFIG_QUIRK_INITIAL_PLANES; - } - for_each_intel_plane(crtc->base.dev, p) { - bool visible = active; - if (crtc->pipe != p->pipe) continue; - drm_plane_state = p->base.state; - - /* Plane scaler state is not touched here. The first atomic - * commit will restore all plane scalers to its old state. - */ + plane_state = to_intel_plane_state(p->base.state); - if (active && p->base.type == DRM_PLANE_TYPE_PRIMARY) { - visible = primary_get_hw_state(crtc); - to_intel_plane_state(drm_plane_state)->visible = visible; - } else { - /* - * unknown state, assume it's off to force a transition - * to on when calculating state changes. - */ - to_intel_plane_state(drm_plane_state)->visible = false; - } + if (p->base.type == DRM_PLANE_TYPE_PRIMARY) + plane_state->visible = primary_get_hw_state(crtc); + else { + if (active) + p->disable_plane(&p->base, &crtc->base); - if (visible) { - crtc_state->base.plane_mask |= - 1 << drm_plane_index(&p->base); - } else if (crtc_state->base.state) { - /* Make this unconditional for atomic hw readout. */ - crtc_state->base.plane_mask &= - ~(1 << drm_plane_index(&p->base)); + plane_state->visible = false; } } } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 09e3581c84411..2c23900b491fd 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -341,7 +341,6 @@ struct intel_crtc_state { */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ #define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ -#define PIPE_CONFIG_QUIRK_INITIAL_PLANES (1<<2) /* planes are in unknown state */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) -- GitLab From b06f8b0df73dea39337e394805827491d0b1585c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 13:42:49 +0200 Subject: [PATCH 0817/7006] drm/i915: Fix reference leak in intel_modeset_readout_hw_state. Unreference the old mode_blob by calling the crtc_destroy_state helper before zeroing the crtc_state. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ba2c933fcea22..4325d00a45989 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15441,6 +15441,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) int i; for_each_intel_crtc(dev, crtc) { + __drm_atomic_helper_crtc_destroy_state(&crtc->base, crtc->base.state); memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->base.crtc = &crtc->base; -- GitLab From 4be40c987aa0867a8fa77c12d5ed6fa2f8853dbc Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 13:45:32 +0200 Subject: [PATCH 0818/7006] drm/i915: Zero the mode in intel_sanitize_crtc when force disabling. There is a WARN_ON in drm_atomic_crtc_check for this when exposing the atomic property. If the mode_blob still exists, but enable = false then all updates are rejected with -EINVAL. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4325d00a45989..5254a3a5a2685 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15291,7 +15291,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) crtc->base.state->enable ? "enabled" : "disabled", crtc->active ? "enabled" : "disabled"); - crtc->base.state->enable = crtc->active; + WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, NULL) < 0); crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; -- GitLab From 3a03dfb057d0ee5f3146ffe40179af3ed7e48213 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 13:46:40 +0200 Subject: [PATCH 0819/7006] drm/i915: Calculate vblank timestamping constants before enabling vblank. This is required to properly initialize vblanks on the active crtc. Without it drm_calc_vbltimestamp_from_scanoutpos can fail with crtc 0: Noop due to uninitialized mode. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 5254a3a5a2685..1b8a17c67ff5d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15239,6 +15239,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc) /* restore vblank interrupts to correct state */ drm_crtc_vblank_reset(&crtc->base); if (crtc->active) { + drm_calc_timestamping_constants(&crtc->base, &crtc->base.hwmode); update_scanline_offset(crtc); drm_crtc_vblank_on(&crtc->base); } -- GitLab From 5c1e34261907736dc3b3a7219b2f48f353f10a93 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 15:58:28 +0200 Subject: [PATCH 0820/7006] drm/i915: Readout initial hw mode. drm/i915: Readout initial hw mode, v2. Atomic requires a mode blob when crtc_state->enable is true, or you get a huge warn_on. With a few tweaks the mode we read out from hardware could be used as the real mode without a modeset, but this requires too much testing, so for now force a modeset the first time the mode blob's updated. This preserves the old behavior, because previously we never set the initial mode, which always meant that a modeset happened when the mode was first set. Changes since v1: - Add a description in intel_modeset_readout_hw_state of how the recalculation is done. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 62 ++++++++++++++++++---------- drivers/gpu/drm/i915/intel_fbdev.c | 11 ++--- 2 files changed, 44 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 1b8a17c67ff5d..a1341cbd40e09 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13146,7 +13146,7 @@ intel_modeset_compute_config(struct drm_atomic_state *state) for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); - bool modeset, recalc; + bool modeset, recalc = false; if (!crtc_state->enable) { if (needs_modeset(crtc_state)) @@ -13155,7 +13155,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state) } modeset = needs_modeset(crtc_state); - recalc = pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE; + /* see comment in intel_modeset_readout_hw_state */ + if (!modeset && crtc_state->mode_blob != crtc->state->mode_blob && + pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE) + recalc = true; if (!modeset && !recalc) continue; @@ -13170,9 +13173,10 @@ intel_modeset_compute_config(struct drm_atomic_state *state) if (ret) return ret; - if (recalc && !intel_pipe_config_compare(state->dev, + if (recalc && (!i915.fastboot || + !intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), - pipe_config, true)) { + pipe_config, true))) { modeset = crtc_state->mode_changed = true; ret = drm_atomic_add_affected_planes(state, crtc); @@ -15451,11 +15455,42 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) crtc->active = dev_priv->display.get_pipe_config(crtc, crtc->config); - crtc->base.state->enable = crtc->active; crtc->base.state->active = crtc->active; crtc->base.enabled = crtc->active; - crtc->base.hwmode = crtc->config->base.adjusted_mode; + memset(&crtc->base.mode, 0, sizeof(crtc->base.mode)); + if (crtc->base.state->active) { + intel_mode_from_pipe_config(&crtc->base.mode, crtc->config); + intel_mode_from_pipe_config(&crtc->base.state->adjusted_mode, crtc->config); + WARN_ON(drm_atomic_set_mode_for_crtc(crtc->base.state, &crtc->base.mode)); + + /* + * The initial mode needs to be set in order to keep + * the atomic core happy. It wants a valid mode if the + * crtc's enabled, so we do the above call. + * + * At this point some state updated by the connectors + * in their ->detect() callback has not run yet, so + * no recalculation can be done yet. + * + * Even if we could do a recalculation and modeset + * right now it would cause a double modeset if + * fbdev or userspace chooses a different initial mode. + * + * So to prevent the double modeset, fail the memcmp + * test in drm_atomic_set_mode_for_crtc to get a new + * mode blob, and compare if the mode blob changed + * when the PIPE_CONFIG_QUIRK_INHERITED_MODE quirk is + * set. + * + * If that happens, someone indicated they wanted a + * mode change, which means it's safe to do a full + * recalculation. + */ + crtc->base.state->mode.private_flags = ~0; + } + + crtc->base.hwmode = crtc->config->base.adjusted_mode; readout_plane_state(crtc, to_intel_crtc_state(crtc->base.state)); DRM_DEBUG_KMS("[CRTC:%d] hw state readout: %s\n", @@ -15532,21 +15567,6 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, intel_modeset_readout_hw_state(dev); - /* - * Now that we have the config, copy it to each CRTC struct - * Note that this could go away if we move to using crtc_config - * checking everywhere. - */ - for_each_intel_crtc(dev, crtc) { - if (crtc->active && i915.fastboot) { - intel_mode_from_pipe_config(&crtc->base.mode, - crtc->config); - DRM_DEBUG_KMS("[CRTC:%d] found active mode: ", - crtc->base.base.id); - drm_mode_debug_printmodeline(&crtc->base.mode); - } - } - /* HW state is read out, now we need to sanitize this mess. */ for_each_intel_encoder(dev, encoder) { intel_sanitize_encoder(encoder); diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c index b791f2374f3b5..7eff33ff84f69 100644 --- a/drivers/gpu/drm/i915/intel_fbdev.c +++ b/drivers/gpu/drm/i915/intel_fbdev.c @@ -483,18 +483,13 @@ retry: * IMPORTANT: We want to use the adjusted mode (i.e. * after the panel fitter upscaling) as the initial * config, not the input mode, which is what crtc->mode - * usually contains. But since our current fastboot + * usually contains. But since our current * code puts a mode derived from the post-pfit timings - * into crtc->mode this works out correctly. We don't - * use hwmode anywhere right now, so use it for this - * since the fb helper layer wants a pointer to - * something we own. + * into crtc->mode this works out correctly. */ DRM_DEBUG_KMS("looking for current mode on connector %s\n", connector->name); - intel_mode_from_pipe_config(&encoder->crtc->hwmode, - to_intel_crtc(encoder->crtc)->config); - modes[i] = &encoder->crtc->hwmode; + modes[i] = &encoder->crtc->mode; } crtcs[i] = new_crtc; -- GitLab From 043e9bda6b7bf6ff83576c65a40becc5054e827d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:25 +0200 Subject: [PATCH 0821/7006] drm/i915: Convert resume to atomic. Instead of all the ad-hoc updating, duplicate the old state first before reading out the hw state, then restore it. intel_display_resume is a new function that duplicates the sw state, then reads out the hw state, and commits the old state. intel_display_setup_hw_state now only reads out the atomic state. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=90396 Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 +- drivers/gpu/drm/i915/intel_display.c | 77 ++++++++++++++++++++-------- drivers/gpu/drm/i915/intel_lvds.c | 2 +- 4 files changed, 60 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index e44dc0d6656fa..db48aee7f1405 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -741,7 +741,7 @@ static int i915_drm_resume(struct drm_device *dev) spin_unlock_irq(&dev_priv->irq_lock); drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); drm_modeset_unlock_all(dev); intel_dp_mst_resume(dev); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 52d07fbd9cc8c..45bbc19883f10 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3277,8 +3277,7 @@ extern void intel_modeset_gem_init(struct drm_device *dev); extern void intel_modeset_cleanup(struct drm_device *dev); extern void intel_connector_unregister(struct intel_connector *); extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state); -extern void intel_modeset_setup_hw_state(struct drm_device *dev, - bool force_restore); +extern void intel_display_resume(struct drm_device *dev); extern void i915_redisable_vga(struct drm_device *dev); extern void i915_redisable_vga_power_on(struct drm_device *dev); extern bool ironlake_set_drps(struct drm_device *dev, u8 val); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a1341cbd40e09..b7f17e8a556ed 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -109,6 +109,7 @@ static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_cr struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); +static void intel_modeset_setup_hw_state(struct drm_device *dev); static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) { @@ -3251,7 +3252,7 @@ void intel_finish_reset(struct drm_device *dev) dev_priv->display.hpd_irq_setup(dev); spin_unlock_irq(&dev_priv->irq_lock); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); intel_hpd_init(dev_priv); @@ -15157,7 +15158,7 @@ void intel_modeset_init(struct drm_device *dev) intel_fbc_disable(dev_priv); drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, false); + intel_modeset_setup_hw_state(dev); drm_modeset_unlock_all(dev); for_each_intel_crtc(dev, crtc) { @@ -15554,10 +15555,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) } } -/* Scan out the current hw modeset state, sanitizes it and maps it into the drm - * and i915 state tracking structures. */ -void intel_modeset_setup_hw_state(struct drm_device *dev, - bool force_restore) +/* Scan out the current hw modeset state, + * and sanitizes it to the current state + */ +static void +intel_modeset_setup_hw_state(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; enum pipe pipe; @@ -15600,24 +15602,59 @@ void intel_modeset_setup_hw_state(struct drm_device *dev, else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); - if (force_restore) { - i915_redisable_vga(dev); + intel_modeset_update_staged_output_state(dev); +} - /* - * We need to use raw interfaces for restoring state to avoid - * checking (bogus) intermediate states. - */ - for_each_pipe(dev_priv, pipe) { - struct drm_crtc *crtc = - dev_priv->pipe_to_crtc_mapping[pipe]; +void intel_display_resume(struct drm_device *dev) +{ + struct drm_atomic_state *state = drm_atomic_state_alloc(dev); + struct intel_connector *conn; + struct intel_plane *plane; + struct drm_crtc *crtc; + int ret; - intel_crtc_restore_mode(crtc); - } - } else { - intel_modeset_update_staged_output_state(dev); + if (!state) + return; + + state->acquire_ctx = dev->mode_config.acquire_ctx; + + /* preserve complete old state, including dpll */ + intel_atomic_get_shared_dpll_state(state); + + for_each_crtc(dev, crtc) { + struct drm_crtc_state *crtc_state = + drm_atomic_get_crtc_state(state, crtc); + + ret = PTR_ERR_OR_ZERO(crtc_state); + if (ret) + goto err; + + /* force a restore */ + crtc_state->mode_changed = true; } - intel_modeset_check_state(dev); + for_each_intel_plane(dev, plane) { + ret = PTR_ERR_OR_ZERO(drm_atomic_get_plane_state(state, &plane->base)); + if (ret) + goto err; + } + + for_each_intel_connector(dev, conn) { + ret = PTR_ERR_OR_ZERO(drm_atomic_get_connector_state(state, &conn->base)); + if (ret) + goto err; + } + + intel_modeset_setup_hw_state(dev); + + i915_redisable_vga(dev); + ret = intel_set_mode(state); + if (!ret) + return; + +err: + DRM_ERROR("Restoring old state failed with %i\n", ret); + drm_atomic_state_free(state); } void intel_modeset_gem_init(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 937e8216e9d65..cb634f48e7d96 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c @@ -473,7 +473,7 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val, */ if (!HAS_PCH_SPLIT(dev)) { drm_modeset_lock_all(dev); - intel_modeset_setup_hw_state(dev, true); + intel_display_resume(dev); drm_modeset_unlock_all(dev); } -- GitLab From ad3c558fb92f725858494f6b3f0befcd89cbb41c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:26 +0200 Subject: [PATCH 0822/7006] drm/i915: Get rid of unused transitional members. The previous commit converted hw readout to atomic, all the new_* members were used for restoring the old state, but with the conversion of suspend to atomic there's no use left for them. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 80 +++++++--------------------- drivers/gpu/drm/i915/intel_drv.h | 12 ----- 2 files changed, 18 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index b7f17e8a556ed..bb9edd049e909 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -10247,7 +10247,7 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector, retry: ret = drm_modeset_lock(&config->connection_mutex, ctx); if (ret) - goto fail_unlock; + goto fail; /* * Algorithm gets a little messy: @@ -10265,10 +10265,10 @@ retry: ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; old->dpms_mode = connector->dpms; old->load_detect_temp = false; @@ -10287,9 +10287,6 @@ retry: continue; if (possible_crtc->state->enable) continue; - /* This can occur when applying the pipe A quirk on resume. */ - if (to_intel_crtc(possible_crtc)->new_enabled) - continue; crtc = possible_crtc; break; @@ -10300,20 +10297,17 @@ retry: */ if (!crtc) { DRM_DEBUG_KMS("no pipe available for load-detect\n"); - goto fail_unlock; + goto fail; } ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) - goto fail_unlock; + goto fail; ret = drm_modeset_lock(&crtc->primary->mutex, ctx); if (ret) - goto fail_unlock; - intel_encoder->new_crtc = to_intel_crtc(crtc); - to_intel_connector(connector)->new_encoder = intel_encoder; + goto fail; intel_crtc = to_intel_crtc(crtc); - intel_crtc->new_enabled = true; old->dpms_mode = connector->dpms; old->load_detect_temp = true; old->release_fb = NULL; @@ -10381,9 +10375,7 @@ retry: intel_wait_for_vblank(dev, intel_crtc->pipe); return true; - fail: - intel_crtc->new_enabled = crtc->state->enable; -fail_unlock: +fail: drm_atomic_state_free(state); state = NULL; @@ -10429,10 +10421,6 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (IS_ERR(crtc_state)) goto fail; - to_intel_connector(connector)->new_encoder = NULL; - intel_encoder->new_crtc = NULL; - intel_crtc->new_enabled = false; - connector_state->best_encoder = NULL; connector_state->crtc = NULL; @@ -11836,37 +11824,6 @@ static const struct drm_crtc_helper_funcs intel_helper_funcs = { .atomic_check = intel_crtc_atomic_check, }; -/** - * intel_modeset_update_staged_output_state - * - * Updates the staged output configuration state, e.g. after we've read out the - * current hw state. - */ -static void intel_modeset_update_staged_output_state(struct drm_device *dev) -{ - struct intel_crtc *crtc; - struct intel_encoder *encoder; - struct intel_connector *connector; - - for_each_intel_connector(dev, connector) { - connector->new_encoder = - to_intel_encoder(connector->base.encoder); - } - - for_each_intel_encoder(dev, encoder) { - encoder->new_crtc = - to_intel_crtc(encoder->base.crtc); - } - - for_each_intel_crtc(dev, crtc) { - crtc->new_enabled = crtc->base.state->enable; - } -} - -/* Transitional helper to copy current connector/encoder state to - * connector->state. This is needed so that code that is partially - * converted to atomic does the right thing. - */ static void intel_modeset_update_connector_atomic_state(struct drm_device *dev) { struct intel_connector *connector; @@ -12307,7 +12264,6 @@ intel_modeset_update_state(struct drm_atomic_state *state) } drm_atomic_helper_update_legacy_modeset_state(state->dev, state); - intel_modeset_update_staged_output_state(state->dev); /* Double check state. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { @@ -12707,11 +12663,14 @@ check_connector_state(struct drm_device *dev) struct intel_connector *connector; for_each_intel_connector(dev, connector) { + struct drm_encoder *encoder = connector->base.encoder; + struct drm_connector_state *state = connector->base.state; + /* This also checks the encoder/connector hw state with the * ->get_hw_state callbacks. */ intel_connector_check_state(connector); - I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder, + I915_STATE_WARN(state->best_encoder != encoder, "connector's staged encoder doesn't match current encoder\n"); } } @@ -12731,8 +12690,6 @@ check_encoder_state(struct drm_device *dev) encoder->base.base.id, encoder->base.name); - I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc, - "encoder's stage crtc doesn't match current crtc\n"); I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc, "encoder's active_connectors set, but no crtc\n"); @@ -12742,6 +12699,10 @@ check_encoder_state(struct drm_device *dev) enabled = true; if (connector->base.dpms != DRM_MODE_DPMS_OFF) active = true; + + I915_STATE_WARN(connector->base.state->crtc != + encoder->base.crtc, + "connector's crtc doesn't match encoder crtc\n"); } /* * for MST connectors if we unplug the connector is gone @@ -13312,11 +13273,12 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) * need to copy the staged config to the atomic state, otherwise the * mode set will just reapply the state the HW is already in. */ for_each_intel_encoder(dev, encoder) { - if (&encoder->new_crtc->base != crtc) + if (encoder->base.crtc != crtc) continue; for_each_intel_connector(dev, connector) { - if (connector->new_encoder != encoder) + if (connector->base.state->best_encoder != + &encoder->base) continue; connector_state = drm_atomic_get_connector_state(state, &connector->base); @@ -13329,7 +13291,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) } connector_state->crtc = crtc; - connector_state->best_encoder = &encoder->base; } } @@ -13341,9 +13302,6 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) return; } - crtc_state->base.active = crtc_state->base.enable = - to_intel_crtc(crtc)->new_enabled; - drm_mode_copy(&crtc_state->base.mode, &crtc->mode); intel_modeset_setup_plane_state(state, crtc, &crtc->mode, @@ -15601,8 +15559,6 @@ intel_modeset_setup_hw_state(struct drm_device *dev) skl_wm_get_hw_state(dev); else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); - - intel_modeset_update_staged_output_state(dev); } void intel_display_resume(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2c23900b491fd..217b773e06736 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -130,11 +130,6 @@ struct intel_fbdev { struct intel_encoder { struct drm_encoder base; - /* - * The new crtc this encoder will be driven from. Only differs from - * base->crtc while a modeset is in progress. - */ - struct intel_crtc *new_crtc; enum intel_output_type type; unsigned int cloneable; @@ -195,12 +190,6 @@ struct intel_connector { */ struct intel_encoder *encoder; - /* - * The new encoder this connector will be driven. Only differs from - * encoder while a modeset is in progress. - */ - struct intel_encoder *new_encoder; - /* Reads out the current hw, returning true if the connector is enabled * and active (i.e. dpms ON state). */ bool (*get_hw_state)(struct intel_connector *); @@ -550,7 +539,6 @@ struct intel_crtc { uint32_t cursor_base; struct intel_crtc_state *config; - bool new_enabled; /* reset counter value when the last flip was submitted */ unsigned int reset_counter; -- GitLab From 292b990e86abc42cba683fda1a56dc5f253a1d3e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:27 +0200 Subject: [PATCH 0823/7006] drm/i915: Update power domains on readout. This allows us to get rid of the set_init_power in modeset_update_crtc_domains. The state should be sanitized enough after setup_hw_state to not need the init power. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 76 ++++++++++++++++++---------- 1 file changed, 50 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index bb9edd049e909..ee1124813af96 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5196,6 +5196,9 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) unsigned long mask; enum transcoder transcoder; + if (!crtc->state->active) + return 0; + transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe); mask = BIT(POWER_DOMAIN_PIPE(pipe)); @@ -5210,27 +5213,46 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc) return mask; } -static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) +static unsigned long modeset_get_crtc_power_domains(struct drm_crtc *crtc) { - struct drm_device *dev = state->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long pipe_domains[I915_MAX_PIPES] = { 0, }; - struct intel_crtc *crtc; + struct drm_i915_private *dev_priv = crtc->dev->dev_private; + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + enum intel_display_power_domain domain; + unsigned long domains, new_domains, old_domains; - /* - * First get all needed power domains, then put all unneeded, to avoid - * any unnecessary toggling of the power wells. - */ - for_each_intel_crtc(dev, crtc) { - enum intel_display_power_domain domain; + old_domains = intel_crtc->enabled_power_domains; + intel_crtc->enabled_power_domains = new_domains = get_crtc_power_domains(crtc); - if (!crtc->base.state->enable) - continue; + domains = new_domains & ~old_domains; + + for_each_power_domain(domain, domains) + intel_display_power_get(dev_priv, domain); + + return old_domains & ~new_domains; +} + +static void modeset_put_power_domains(struct drm_i915_private *dev_priv, + unsigned long domains) +{ + enum intel_display_power_domain domain; + + for_each_power_domain(domain, domains) + intel_display_power_put(dev_priv, domain); +} - pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base); +static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) +{ + struct drm_device *dev = state->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long put_domains[I915_MAX_PIPES] = {}; + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i; - for_each_power_domain(domain, pipe_domains[crtc->pipe]) - intel_display_power_get(dev_priv, domain); + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (needs_modeset(crtc->state)) + put_domains[to_intel_crtc(crtc)->pipe] = + modeset_get_crtc_power_domains(crtc); } if (dev_priv->display.modeset_commit_cdclk) { @@ -5241,16 +5263,9 @@ static void modeset_update_crtc_power_domains(struct drm_atomic_state *state) dev_priv->display.modeset_commit_cdclk(state); } - for_each_intel_crtc(dev, crtc) { - enum intel_display_power_domain domain; - - for_each_power_domain(domain, crtc->enabled_power_domains) - intel_display_power_put(dev_priv, domain); - - crtc->enabled_power_domains = pipe_domains[crtc->pipe]; - } - - intel_display_set_init_power(dev_priv, false); + for (i = 0; i < I915_MAX_PIPES; i++) + if (put_domains[i]) + modeset_put_power_domains(dev_priv, put_domains[i]); } static void intel_update_max_cdclk(struct drm_device *dev) @@ -15559,6 +15574,15 @@ intel_modeset_setup_hw_state(struct drm_device *dev) skl_wm_get_hw_state(dev); else if (HAS_PCH_SPLIT(dev)) ilk_wm_get_hw_state(dev); + + for_each_intel_crtc(dev, crtc) { + unsigned long put_domains; + + put_domains = modeset_get_crtc_power_domains(&crtc->base); + if (WARN_ON(put_domains)) + modeset_put_power_domains(dev_priv, put_domains); + } + intel_display_set_init_power(dev_priv, false); } void intel_display_resume(struct drm_device *dev) -- GitLab From e694eb020f12949a3eb12d4bb4957f0237961b2d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 16:19:12 +0200 Subject: [PATCH 0824/7006] drm/i915: Always force a modeset in intel_crtc_restore_mode, v2. And get rid of things that are no longer true. This function is only used for forcing a modeset when encoder properties are changed. Because this is not yet done atomically, assume a full modeset is needed and force a modeset on the crtc. Changes since v1: - s/reset/force modeset/ Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 58 ++++++++-------------------- 1 file changed, 16 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ee1124813af96..f9ed3732f95fc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13267,63 +13267,37 @@ void intel_crtc_restore_mode(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; struct drm_atomic_state *state; - struct intel_encoder *encoder; - struct intel_connector *connector; - struct drm_connector_state *connector_state; - struct intel_crtc_state *crtc_state; + struct drm_crtc_state *crtc_state; int ret; state = drm_atomic_state_alloc(dev); if (!state) { - DRM_DEBUG_KMS("[CRTC:%d] mode restore failed, out of memory", + DRM_DEBUG_KMS("[CRTC:%d] crtc restore failed, out of memory", crtc->base.id); return; } - state->acquire_ctx = dev->mode_config.acquire_ctx; - - /* The force restore path in the HW readout code relies on the staged - * config still keeping the user requested config while the actual - * state has been overwritten by the configuration read from HW. We - * need to copy the staged config to the atomic state, otherwise the - * mode set will just reapply the state the HW is already in. */ - for_each_intel_encoder(dev, encoder) { - if (encoder->base.crtc != crtc) - continue; + state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); - for_each_intel_connector(dev, connector) { - if (connector->base.state->best_encoder != - &encoder->base) - continue; - - connector_state = drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) { - DRM_DEBUG_KMS("Failed to add [CONNECTOR:%d:%s] to state: %ld\n", - connector->base.base.id, - connector->base.name, - PTR_ERR(connector_state)); - continue; - } +retry: + crtc_state = drm_atomic_get_crtc_state(state, crtc); + ret = PTR_ERR_OR_ZERO(crtc_state); + if (!ret) { + if (!crtc_state->active) + goto out; - connector_state->crtc = crtc; - } + crtc_state->mode_changed = true; + ret = intel_set_mode(state); } - crtc_state = intel_atomic_get_crtc_state(state, to_intel_crtc(crtc)); - if (IS_ERR(crtc_state)) { - DRM_DEBUG_KMS("Failed to add [CRTC:%d] to state: %ld\n", - crtc->base.id, PTR_ERR(crtc_state)); - drm_atomic_state_free(state); - return; + if (ret == -EDEADLK) { + drm_atomic_state_clear(state); + drm_modeset_backoff(state->acquire_ctx); + goto retry; } - drm_mode_copy(&crtc_state->base.mode, &crtc->mode); - - intel_modeset_setup_plane_state(state, crtc, &crtc->mode, - crtc->primary->fb, crtc->x, crtc->y); - - ret = intel_set_mode(state); if (ret) +out: drm_atomic_state_free(state); } -- GitLab From 70e0bd74b9a22ecaa25793bf4f461cf84a1f348a Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:29 +0200 Subject: [PATCH 0825/7006] drm/i915: Make intel_display_suspend atomic, try 2. Calculate all state using a normal transition, but afterwards fudge crtc->state->active back to its old value. This should still allow state restore in setup_hw_state to work properly. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 52 ++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index f9ed3732f95fc..4e64dae783608 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6225,12 +6225,58 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) * turn all crtc's off, but do not adjust state * This has to be paired with a call to intel_modeset_setup_hw_state. */ -void intel_display_suspend(struct drm_device *dev) +int intel_display_suspend(struct drm_device *dev) { + struct drm_mode_config *config = &dev->mode_config; + struct drm_modeset_acquire_ctx *ctx = config->acquire_ctx; + struct drm_atomic_state *state; struct drm_crtc *crtc; + unsigned crtc_mask = 0; + int ret = 0; + + if (WARN_ON(!ctx)) + return 0; + + lockdep_assert_held(&ctx->ww_ctx); + state = drm_atomic_state_alloc(dev); + if (WARN_ON(!state)) + return -ENOMEM; + + state->acquire_ctx = ctx; + state->allow_modeset = true; + + for_each_crtc(dev, crtc) { + struct drm_crtc_state *crtc_state = + drm_atomic_get_crtc_state(state, crtc); - for_each_crtc(dev, crtc) - intel_crtc_disable_noatomic(crtc); + ret = PTR_ERR_OR_ZERO(crtc_state); + if (ret) + goto free; + + if (!crtc_state->active) + continue; + + crtc_state->active = false; + crtc_mask |= 1 << drm_crtc_index(crtc); + } + + if (crtc_mask) { + ret = intel_set_mode(state); + + if (!ret) { + for_each_crtc(dev, crtc) + if (crtc_mask & (1 << drm_crtc_index(crtc))) + crtc->state->active = true; + + return ret; + } + } + +free: + if (ret) + DRM_ERROR("Suspending crtc's failed with %i\n", ret); + drm_atomic_state_free(state); + return ret; } /* Master function to enable/disable CRTC and corresponding power wells */ diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 217b773e06736..f4abce1032217 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -988,7 +988,7 @@ int intel_pch_rawclk(struct drm_device *dev); void intel_mark_busy(struct drm_device *dev); void intel_mark_idle(struct drm_device *dev); void intel_crtc_restore_mode(struct drm_crtc *crtc); -void intel_display_suspend(struct drm_device *dev); +int intel_display_suspend(struct drm_device *dev); int intel_crtc_control(struct drm_crtc *crtc, bool enable); void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); -- GitLab From 97d3308ab245c51ae237b3444afa7ae87aa9bcd4 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:23 +0530 Subject: [PATCH 0826/7006] drm/i915: Add HAS_CORE_RING_FREQ macro Added a new HAS_CORE_RING_FREQ macro, currently used in gen6_update_ring_freq & i915_ring_freq_table debugfs function. The programming & read of ring frequency table is needed for newer GEN(>=6) platforms, except VLV/CHV. Issue: VIZ-5144 Suggested-by: Daniel Vetter Signed-off-by: Akash Goel Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 3 +++ drivers/gpu/drm/i915/intel_pm.c | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 27f0a0d98e3ac..f3f014df61a35 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1784,7 +1784,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused) int gpu_freq, ia_freq; unsigned int max_gpu_freq, min_gpu_freq; - if (!(IS_GEN6(dev) || IS_GEN7(dev))) { + if (!HAS_CORE_RING_FREQ(dev)) { seq_puts(m, "unsupported on this chipset\n"); return 0; } diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 45bbc19883f10..661135691d6b1 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2548,6 +2548,9 @@ struct drm_i915_cmd_table { #define HAS_RESOURCE_STREAMER(dev) (IS_HASWELL(dev) || \ INTEL_INFO(dev)->gen >= 8) +#define HAS_CORE_RING_FREQ(dev) (INTEL_INFO(dev)->gen >= 6 && \ + !IS_VALLEYVIEW(dev)) + #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 #define INTEL_PCH_CPT_DEVICE_ID_TYPE 0x1c00 diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index f2be1cedb52fc..025978548fb6b 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -5104,7 +5104,7 @@ void gen6_update_ring_freq(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; - if (INTEL_INFO(dev)->gen < 6 || IS_VALLEYVIEW(dev)) + if (!HAS_CORE_RING_FREQ(dev)) return; mutex_lock(&dev_priv->rps.hw_lock); -- GitLab From 430b7ad5d3d07e9869085d777264a37ae2dd5c26 Mon Sep 17 00:00:00 2001 From: Akash Goel Date: Mon, 29 Jun 2015 14:50:24 +0530 Subject: [PATCH 0827/7006] drm/i915: Added BXT check in HAS_CORE_RING_FREQ macro Updated the HAS_CORE_RING_FREQ macro to add the broxton check, so as to disallow the programming & read of ring frequency table for it. Issue: VIZ-5144 Suggested-by: Daniel Vetter Signed-off-by: Akash Goel Reviewed-by: Rodrigo Vivi Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 661135691d6b1..2714228e34561 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2549,7 +2549,7 @@ struct drm_i915_cmd_table { INTEL_INFO(dev)->gen >= 8) #define HAS_CORE_RING_FREQ(dev) (INTEL_INFO(dev)->gen >= 6 && \ - !IS_VALLEYVIEW(dev)) + !IS_VALLEYVIEW(dev) && !IS_BROXTON(dev)) #define INTEL_PCH_DEVICE_ID_MASK 0xff00 #define INTEL_PCH_IBX_DEVICE_ID_TYPE 0x3b00 -- GitLab From 27bc1dd24488ce2a13e5c59aaf6d3202e519e21e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:30:31 +0900 Subject: [PATCH 0828/7006] ASoC: mediatek: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Acked-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/mediatek/mt8173-max98090.c | 1 - sound/soc/mediatek/mt8173-rt5650-rt5676.c | 1 - sound/soc/mediatek/mtk-afe-pcm.c | 1 - 3 files changed, 3 deletions(-) diff --git a/sound/soc/mediatek/mt8173-max98090.c b/sound/soc/mediatek/mt8173-max98090.c index 4d44b5803e552..6311f31fa669a 100644 --- a/sound/soc/mediatek/mt8173-max98090.c +++ b/sound/soc/mediatek/mt8173-max98090.c @@ -193,7 +193,6 @@ MODULE_DEVICE_TABLE(of, mt8173_max98090_dt_match); static struct platform_driver mt8173_max98090_driver = { .driver = { .name = "mt8173-max98090", - .owner = THIS_MODULE, .of_match_table = mt8173_max98090_dt_match, #ifdef CONFIG_PM .pm = &snd_soc_pm_ops, diff --git a/sound/soc/mediatek/mt8173-rt5650-rt5676.c b/sound/soc/mediatek/mt8173-rt5650-rt5676.c index 0940553230596..4fd7dff15fe7e 100644 --- a/sound/soc/mediatek/mt8173-rt5650-rt5676.c +++ b/sound/soc/mediatek/mt8173-rt5650-rt5676.c @@ -258,7 +258,6 @@ MODULE_DEVICE_TABLE(of, mt8173_rt5650_rt5676_dt_match); static struct platform_driver mt8173_rt5650_rt5676_driver = { .driver = { .name = "mtk-rt5650-rt5676", - .owner = THIS_MODULE, .of_match_table = mt8173_rt5650_rt5676_dt_match, #ifdef CONFIG_PM .pm = &snd_soc_pm_ops, diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index cc228db5fb760..5b74afb59c5cf 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -1218,7 +1218,6 @@ static const struct dev_pm_ops mtk_afe_pm_ops = { static struct platform_driver mtk_afe_pcm_driver = { .driver = { .name = "mtk-afe-pcm", - .owner = THIS_MODULE, .of_match_table = mtk_afe_pcm_dt_match, .pm = &mtk_afe_pm_ops, }, -- GitLab From 89e0e250f92b0b0233337043ddf76f261916036c Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 9 Jul 2015 11:21:03 +0300 Subject: [PATCH 0829/7006] ASoC: fsl: fsl_spdif: signedness bug in fsl_spdif_startup() We need "i" to be signed or it leads to a forever loop in the error handling. Fixes: fa3be9208dcb ('ASoC: fsl: fsl_spdif: Check for clk_prepare_enable() error') Signed-off-by: Dan Carpenter Acked-by: Nicolin Chen Signed-off-by: Mark Brown --- sound/soc/fsl/fsl_spdif.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 8e932219cb3af..851b83373d4ce 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -454,7 +454,8 @@ static int fsl_spdif_startup(struct snd_pcm_substream *substream, struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(rtd->cpu_dai); struct platform_device *pdev = spdif_priv->pdev; struct regmap *regmap = spdif_priv->regmap; - u32 scr, mask, i; + u32 scr, mask; + int i; int ret; /* Reset module and interrupts only for first initialization */ -- GitLab From 6ce12a977b7e484540482febe47d1e65f7427abf Mon Sep 17 00:00:00 2001 From: SungEun Kim Date: Fri, 3 Jul 2015 15:57:20 +0900 Subject: [PATCH 0830/7006] PM / autosleep: Use workqueue for user space wakeup sources garbage collector The synchronous synchronize_rcu() in wakeup_source_remove() makes user process which writes to /sys/kernel/wake_unlock blocked sometimes. For example, when android eventhub tries to release a wakelock, this blocking process can occur, and eventhub can't get input events for a while. Using a work item instead of direct function call at pm_wake_unlock() can prevent this unnecessary delay from happening. Signed-off-by: SungEun Kim Signed-off-by: Rafael J. Wysocki --- kernel/power/wakelock.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c index 019069c84ff6b..1896386e16bbe 100644 --- a/kernel/power/wakelock.c +++ b/kernel/power/wakelock.c @@ -17,6 +17,7 @@ #include #include #include +#include #include "power.h" @@ -83,7 +84,9 @@ static inline void decrement_wakelocks_number(void) {} #define WL_GC_COUNT_MAX 100 #define WL_GC_TIME_SEC 300 +static void __wakelocks_gc(struct work_struct *work); static LIST_HEAD(wakelocks_lru_list); +static DECLARE_WORK(wakelock_work, __wakelocks_gc); static unsigned int wakelocks_gc_count; static inline void wakelocks_lru_add(struct wakelock *wl) @@ -96,13 +99,12 @@ static inline void wakelocks_lru_most_recent(struct wakelock *wl) list_move(&wl->lru, &wakelocks_lru_list); } -static void wakelocks_gc(void) +static void __wakelocks_gc(struct work_struct *work) { struct wakelock *wl, *aux; ktime_t now; - if (++wakelocks_gc_count <= WL_GC_COUNT_MAX) - return; + mutex_lock(&wakelocks_lock); now = ktime_get(); list_for_each_entry_safe_reverse(wl, aux, &wakelocks_lru_list, lru) { @@ -127,6 +129,16 @@ static void wakelocks_gc(void) } } wakelocks_gc_count = 0; + + mutex_unlock(&wakelocks_lock); +} + +static void wakelocks_gc(void) +{ + if (++wakelocks_gc_count <= WL_GC_COUNT_MAX) + return; + + schedule_work(&wakelock_work); } #else /* !CONFIG_PM_WAKELOCKS_GC */ static inline void wakelocks_lru_add(struct wakelock *wl) {} -- GitLab From 29e2d6d1f6f61ba2b5cc9d9867e01d8c31a6c4f7 Mon Sep 17 00:00:00 2001 From: Ellen Wang Date: Thu, 9 Jul 2015 22:04:31 -0700 Subject: [PATCH 0831/7006] HID: cp2112: fix byte order in SMBUS operations Change all occurrences of be16 to le16 in cp2112_xfer(), because SMBUS words are little endian, not big endian. Signed-off-by: Ellen Wang Cc: stable@vger.kernel.org Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index a84d3700e740e..7afc3fcc122c4 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -589,7 +589,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, struct cp2112_device *dev = (struct cp2112_device *)adap->algo_data; struct hid_device *hdev = dev->hdev; u8 buf[64]; - __be16 word; + __le16 word; ssize_t count; size_t read_length = 0; unsigned int retries; @@ -621,7 +621,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, break; case I2C_SMBUS_WORD_DATA: read_length = 2; - word = cpu_to_be16(data->word); + word = cpu_to_le16(data->word); if (I2C_SMBUS_READ == read_write) count = cp2112_write_read_req(buf, addr, read_length, @@ -634,7 +634,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, size = I2C_SMBUS_WORD_DATA; read_write = I2C_SMBUS_READ; read_length = 2; - word = cpu_to_be16(data->word); + word = cpu_to_le16(data->word); count = cp2112_write_read_req(buf, addr, read_length, command, (u8 *)&word, 2); @@ -727,7 +727,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr, data->byte = buf[0]; break; case I2C_SMBUS_WORD_DATA: - data->word = be16_to_cpup((__be16 *)buf); + data->word = le16_to_cpup((__le16 *)buf); break; case I2C_SMBUS_BLOCK_DATA: if (read_length > I2C_SMBUS_BLOCK_MAX) { -- GitLab From 225f58fbcc02ace232fc49f05036042f9d58263e Mon Sep 17 00:00:00 2001 From: Minfei Huang Date: Tue, 14 Jul 2015 11:15:37 +0800 Subject: [PATCH 0832/7006] livepatch: Improve error handling in klp_disable_func() In case of func->state or func->old_addr not having expected values, we'd rather bail out immediately from klp_disable_func(). This can't really happen with the current codebase, but fix this anyway in the sake of robustness. [jkosina@suse.com: reworded the changelog a bit] Signed-off-by: Minfei Huang Acked-by: Josh Poimboeuf Signed-off-by: Jiri Kosina --- kernel/livepatch/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index c40ebcca0495f..6e5344112419c 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -348,8 +348,10 @@ static void klp_disable_func(struct klp_func *func) { struct klp_ops *ops; - WARN_ON(func->state != KLP_ENABLED); - WARN_ON(!func->old_addr); + if (WARN_ON(func->state != KLP_ENABLED)) + return; + if (WARN_ON(!func->old_addr)) + return; ops = klp_find_ops(func->old_addr); if (WARN_ON(!ops)) -- GitLab From 7e47682ea555e7c1edef1d8fd96e2aa4c12abe59 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Tue, 9 Jun 2015 21:32:09 +1000 Subject: [PATCH 0833/7006] cgroup: allow a cgroup subsystem to reject a fork Add a new cgroup subsystem callback can_fork that conditionally states whether or not the fork is accepted or rejected by a cgroup policy. In addition, add a cancel_fork callback so that if an error occurs later in the forking process, any state modified by can_fork can be reverted. Allow for a private opaque pointer to be passed from cgroup_can_fork to cgroup_post_fork, allowing for the fork state to be stored by each subsystem separately. Also add a tagging system for cgroup_subsys.h to allow for CGROUP_ enumerations to be be defined and used. In addition, explicitly add a CGROUP_CANFORK_COUNT macro to make arrays easier to define. This is in preparation for implementing the pids cgroup subsystem. Signed-off-by: Aleksa Sarai Signed-off-by: Tejun Heo --- include/linux/cgroup-defs.h | 10 ++++- include/linux/cgroup.h | 15 ++++++- include/linux/cgroup_subsys.h | 23 +++++++++++ kernel/cgroup.c | 73 ++++++++++++++++++++++++++++++++++- kernel/cgroup_freezer.c | 2 +- kernel/fork.c | 17 +++++++- kernel/sched/core.c | 2 +- 7 files changed, 133 insertions(+), 9 deletions(-) diff --git a/include/linux/cgroup-defs.h b/include/linux/cgroup-defs.h index 93755a6292995..83e37d8c4d80f 100644 --- a/include/linux/cgroup-defs.h +++ b/include/linux/cgroup-defs.h @@ -34,12 +34,17 @@ struct seq_file; /* define the enumeration of all cgroup subsystems */ #define SUBSYS(_x) _x ## _cgrp_id, +#define SUBSYS_TAG(_t) CGROUP_ ## _t, \ + __unused_tag_ ## _t = CGROUP_ ## _t - 1, enum cgroup_subsys_id { #include CGROUP_SUBSYS_COUNT, }; +#undef SUBSYS_TAG #undef SUBSYS +#define CGROUP_CANFORK_COUNT (CGROUP_CANFORK_END - CGROUP_CANFORK_START) + /* bits in struct cgroup_subsys_state flags field */ enum { CSS_NO_REF = (1 << 0), /* no reference counting for this css */ @@ -406,7 +411,9 @@ struct cgroup_subsys { struct cgroup_taskset *tset); void (*attach)(struct cgroup_subsys_state *css, struct cgroup_taskset *tset); - void (*fork)(struct task_struct *task); + int (*can_fork)(struct task_struct *task, void **priv_p); + void (*cancel_fork)(struct task_struct *task, void *priv); + void (*fork)(struct task_struct *task, void *priv); void (*exit)(struct cgroup_subsys_state *css, struct cgroup_subsys_state *old_css, struct task_struct *task); @@ -491,6 +498,7 @@ static inline void cgroup_threadgroup_change_end(struct task_struct *tsk) #else /* CONFIG_CGROUPS */ +#define CGROUP_CANFORK_COUNT 0 #define CGROUP_SUBSYS_COUNT 0 static inline void cgroup_threadgroup_change_begin(struct task_struct *tsk) {} diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h index a593e299162eb..a71fe2a3984ef 100644 --- a/include/linux/cgroup.h +++ b/include/linux/cgroup.h @@ -62,7 +62,12 @@ int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *tsk); void cgroup_fork(struct task_struct *p); -void cgroup_post_fork(struct task_struct *p); +extern int cgroup_can_fork(struct task_struct *p, + void *ss_priv[CGROUP_CANFORK_COUNT]); +extern void cgroup_cancel_fork(struct task_struct *p, + void *ss_priv[CGROUP_CANFORK_COUNT]); +extern void cgroup_post_fork(struct task_struct *p, + void *old_ss_priv[CGROUP_CANFORK_COUNT]); void cgroup_exit(struct task_struct *p); int cgroup_init_early(void); @@ -524,7 +529,13 @@ static inline int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry) { return -EINVAL; } static inline void cgroup_fork(struct task_struct *p) {} -static inline void cgroup_post_fork(struct task_struct *p) {} +static inline int cgroup_can_fork(struct task_struct *p, + void *ss_priv[CGROUP_CANFORK_COUNT]) +{ return 0; } +static inline void cgroup_cancel_fork(struct task_struct *p, + void *ss_priv[CGROUP_CANFORK_COUNT]) {} +static inline void cgroup_post_fork(struct task_struct *p, + void *ss_priv[CGROUP_CANFORK_COUNT]) {} static inline void cgroup_exit(struct task_struct *p) {} static inline int cgroup_init_early(void) { return 0; } diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index e4a96fb144035..ec43bce7e1ea1 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -3,6 +3,17 @@ * * DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS. */ + +/* + * This file *must* be included with SUBSYS() defined. + * SUBSYS_TAG() is a noop if undefined. + */ + +#ifndef SUBSYS_TAG +#define __TMP_SUBSYS_TAG +#define SUBSYS_TAG(_x) +#endif + #if IS_ENABLED(CONFIG_CPUSETS) SUBSYS(cpuset) #endif @@ -47,12 +58,24 @@ SUBSYS(net_prio) SUBSYS(hugetlb) #endif +/* + * Subsystems that implement the can_fork() family of callbacks. + */ +SUBSYS_TAG(CANFORK_START) +SUBSYS_TAG(CANFORK_END) + /* * The following subsystems are not supported on the default hierarchy. */ #if IS_ENABLED(CONFIG_CGROUP_DEBUG) SUBSYS(debug) #endif + +#ifdef __TMP_SUBSYS_TAG +#undef __TMP_SUBSYS_TAG +#undef SUBSYS_TAG +#endif + /* * DO NOT ADD ANY SUBSYSTEM WITHOUT EXPLICIT ACKS FROM CGROUP MAINTAINERS. */ diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f89d9292eee62..a59dd1a6b74a8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -186,6 +186,9 @@ static u64 css_serial_nr_next = 1; static unsigned long have_fork_callback __read_mostly; static unsigned long have_exit_callback __read_mostly; +/* Ditto for the can_fork callback. */ +static unsigned long have_canfork_callback __read_mostly; + static struct cftype cgroup_dfl_base_files[]; static struct cftype cgroup_legacy_base_files[]; @@ -4955,6 +4958,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early) have_fork_callback |= (bool)ss->fork << ss->id; have_exit_callback |= (bool)ss->exit << ss->id; + have_canfork_callback |= (bool)ss->can_fork << ss->id; /* At system boot, before all subsystems have been * registered, no tasks have been forked, so we don't @@ -5197,6 +5201,19 @@ static const struct file_operations proc_cgroupstats_operations = { .release = single_release, }; +static void **subsys_canfork_priv_p(void *ss_priv[CGROUP_CANFORK_COUNT], int i) +{ + if (CGROUP_CANFORK_START <= i && i < CGROUP_CANFORK_END) + return &ss_priv[i - CGROUP_CANFORK_START]; + return NULL; +} + +static void *subsys_canfork_priv(void *ss_priv[CGROUP_CANFORK_COUNT], int i) +{ + void **private = subsys_canfork_priv_p(ss_priv, i); + return private ? *private : NULL; +} + /** * cgroup_fork - initialize cgroup related fields during copy_process() * @child: pointer to task_struct of forking parent process. @@ -5211,6 +5228,57 @@ void cgroup_fork(struct task_struct *child) INIT_LIST_HEAD(&child->cg_list); } +/** + * cgroup_can_fork - called on a new task before the process is exposed + * @child: the task in question. + * + * This calls the subsystem can_fork() callbacks. If the can_fork() callback + * returns an error, the fork aborts with that error code. This allows for + * a cgroup subsystem to conditionally allow or deny new forks. + */ +int cgroup_can_fork(struct task_struct *child, + void *ss_priv[CGROUP_CANFORK_COUNT]) +{ + struct cgroup_subsys *ss; + int i, j, ret; + + for_each_subsys_which(ss, i, &have_canfork_callback) { + ret = ss->can_fork(child, subsys_canfork_priv_p(ss_priv, i)); + if (ret) + goto out_revert; + } + + return 0; + +out_revert: + for_each_subsys(ss, j) { + if (j >= i) + break; + if (ss->cancel_fork) + ss->cancel_fork(child, subsys_canfork_priv(ss_priv, j)); + } + + return ret; +} + +/** + * cgroup_cancel_fork - called if a fork failed after cgroup_can_fork() + * @child: the task in question + * + * This calls the cancel_fork() callbacks if a fork failed *after* + * cgroup_can_fork() succeded. + */ +void cgroup_cancel_fork(struct task_struct *child, + void *ss_priv[CGROUP_CANFORK_COUNT]) +{ + struct cgroup_subsys *ss; + int i; + + for_each_subsys(ss, i) + if (ss->cancel_fork) + ss->cancel_fork(child, subsys_canfork_priv(ss_priv, i)); +} + /** * cgroup_post_fork - called on a new task after adding it to the task list * @child: the task in question @@ -5221,7 +5289,8 @@ void cgroup_fork(struct task_struct *child) * cgroup_task_iter_start() - to guarantee that the new task ends up on its * list. */ -void cgroup_post_fork(struct task_struct *child) +void cgroup_post_fork(struct task_struct *child, + void *old_ss_priv[CGROUP_CANFORK_COUNT]) { struct cgroup_subsys *ss; int i; @@ -5266,7 +5335,7 @@ void cgroup_post_fork(struct task_struct *child) * and addition to css_set. */ for_each_subsys_which(ss, i, &have_fork_callback) - ss->fork(child); + ss->fork(child, subsys_canfork_priv(old_ss_priv, i)); } /** diff --git a/kernel/cgroup_freezer.c b/kernel/cgroup_freezer.c index 92b98cc0ee763..f1b30ad5dc6d9 100644 --- a/kernel/cgroup_freezer.c +++ b/kernel/cgroup_freezer.c @@ -203,7 +203,7 @@ static void freezer_attach(struct cgroup_subsys_state *new_css, * to do anything as freezer_attach() will put @task into the appropriate * state. */ -static void freezer_fork(struct task_struct *task) +static void freezer_fork(struct task_struct *task, void *private) { struct freezer *freezer; diff --git a/kernel/fork.c b/kernel/fork.c index 1bfefc6f96a4e..40e3af12c55e5 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -1239,6 +1239,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, { int retval; struct task_struct *p; + void *cgrp_ss_priv[CGROUP_CANFORK_COUNT] = {}; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -1512,6 +1513,16 @@ static struct task_struct *copy_process(unsigned long clone_flags, INIT_LIST_HEAD(&p->thread_group); p->task_works = NULL; + /* + * Ensure that the cgroup subsystem policies allow the new process to be + * forked. It should be noted the the new process's css_set can be changed + * between here and cgroup_post_fork() if an organisation operation is in + * progress. + */ + retval = cgroup_can_fork(p, cgrp_ss_priv); + if (retval) + goto bad_fork_free_pid; + /* * Make it visible to the rest of the system, but dont wake it up yet. * Need tasklist lock for parent etc handling! @@ -1548,7 +1559,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, spin_unlock(¤t->sighand->siglock); write_unlock_irq(&tasklist_lock); retval = -ERESTARTNOINTR; - goto bad_fork_free_pid; + goto bad_fork_cancel_cgroup; } if (likely(p->pid)) { @@ -1590,7 +1601,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, write_unlock_irq(&tasklist_lock); proc_fork_connector(p); - cgroup_post_fork(p); + cgroup_post_fork(p, cgrp_ss_priv); if (clone_flags & CLONE_THREAD) threadgroup_change_end(current); perf_event_fork(p); @@ -1600,6 +1611,8 @@ static struct task_struct *copy_process(unsigned long clone_flags, return p; +bad_fork_cancel_cgroup: + cgroup_cancel_fork(p, cgrp_ss_priv); bad_fork_free_pid: if (pid != &init_struct_pid) free_pid(pid); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 78b4bad10081c..d811652fe6f59 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -8068,7 +8068,7 @@ static void cpu_cgroup_css_offline(struct cgroup_subsys_state *css) sched_offline_group(tg); } -static void cpu_cgroup_fork(struct task_struct *task) +static void cpu_cgroup_fork(struct task_struct *task, void *private) { sched_move_task(task); } -- GitLab From 49b786ea146f69c371df18e81ce0a2d5839f865c Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Tue, 9 Jun 2015 21:32:10 +1000 Subject: [PATCH 0834/7006] cgroup: implement the PIDs subsystem Adds a new single-purpose PIDs subsystem to limit the number of tasks that can be forked inside a cgroup. Essentially this is an implementation of RLIMIT_NPROC that applies to a cgroup rather than a process tree. However, it should be noted that organisational operations (adding and removing tasks from a PIDs hierarchy) will *not* be prevented. Rather, the number of tasks in the hierarchy cannot exceed the limit through forking. This is due to the fact that, in the unified hierarchy, attach cannot fail (and it is not possible for a task to overcome its PIDs cgroup policy limit by attaching to a child cgroup -- even if migrating mid-fork it must be able to fork in the parent first). PIDs are fundamentally a global resource, and it is possible to reach PID exhaustion inside a cgroup without hitting any reasonable kmemcg policy. Once you've hit PID exhaustion, you're only in a marginally better state than OOM. This subsystem allows PID exhaustion inside a cgroup to be prevented. Signed-off-by: Aleksa Sarai Signed-off-by: Tejun Heo --- CREDITS | 5 + include/linux/cgroup_subsys.h | 5 + init/Kconfig | 16 ++ kernel/Makefile | 1 + kernel/cgroup_pids.c | 366 ++++++++++++++++++++++++++++++++++ 5 files changed, 393 insertions(+) create mode 100644 kernel/cgroup_pids.c diff --git a/CREDITS b/CREDITS index 1d616640bbf64..4fcf9cd8544cb 100644 --- a/CREDITS +++ b/CREDITS @@ -3219,6 +3219,11 @@ S: 69 rue Dunois S: 75013 Paris S: France +N: Aleksa Sarai +E: cyphar@cyphar.com +W: https://www.cyphar.com/ +D: `pids` cgroup subsystem + N: Dipankar Sarma E: dipankar@in.ibm.com D: RCU diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index ec43bce7e1ea1..1f36945fd23da 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -62,6 +62,11 @@ SUBSYS(hugetlb) * Subsystems that implement the can_fork() family of callbacks. */ SUBSYS_TAG(CANFORK_START) + +#if IS_ENABLED(CONFIG_CGROUP_PIDS) +SUBSYS(pids) +#endif + SUBSYS_TAG(CANFORK_END) /* diff --git a/init/Kconfig b/init/Kconfig index af09b4fb43d29..2184b34cbf73f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -955,6 +955,22 @@ config CGROUP_FREEZER Provides a way to freeze and unfreeze all tasks in a cgroup. +config CGROUP_PIDS + bool "PIDs cgroup subsystem" + help + Provides enforcement of process number limits in the scope of a + cgroup. Any attempt to fork more processes than is allowed in the + cgroup will fail. PIDs are fundamentally a global resource because it + is fairly trivial to reach PID exhaustion before you reach even a + conservative kmemcg limit. As a result, it is possible to grind a + system to halt without being limited by other cgroup policies. The + PIDs cgroup subsystem is designed to stop this from happening. + + It should be noted that organisational operations (such as attaching + to a cgroup hierarchy will *not* be blocked by the PIDs subsystem), + since the PIDs limit only affects a process's ability to fork, not to + attach to a cgroup. + config CGROUP_DEVICE bool "Device controller for cgroups" help diff --git a/kernel/Makefile b/kernel/Makefile index 43c4c920f30a9..718fb8afab7af 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_CGROUPS) += cgroup.o obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o +obj-$(CONFIG_CGROUP_PIDS) += cgroup_pids.o obj-$(CONFIG_CPUSETS) += cpuset.o obj-$(CONFIG_UTS_NS) += utsname.o obj-$(CONFIG_USER_NS) += user_namespace.o diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c new file mode 100644 index 0000000000000..d75488824ae22 --- /dev/null +++ b/kernel/cgroup_pids.c @@ -0,0 +1,366 @@ +/* + * Process number limiting controller for cgroups. + * + * Used to allow a cgroup hierarchy to stop any new processes from fork()ing + * after a certain limit is reached. + * + * Since it is trivial to hit the task limit without hitting any kmemcg limits + * in place, PIDs are a fundamental resource. As such, PID exhaustion must be + * preventable in the scope of a cgroup hierarchy by allowing resource limiting + * of the number of tasks in a cgroup. + * + * In order to use the `pids` controller, set the maximum number of tasks in + * pids.max (this is not available in the root cgroup for obvious reasons). The + * number of processes currently in the cgroup is given by pids.current. + * Organisational operations are not blocked by cgroup policies, so it is + * possible to have pids.current > pids.max. However, it is not possible to + * violate a cgroup policy through fork(). fork() will return -EAGAIN if forking + * would cause a cgroup policy to be violated. + * + * To set a cgroup to have no limit, set pids.max to "max". This is the default + * for all new cgroups (N.B. that PID limits are hierarchical, so the most + * stringent limit in the hierarchy is followed). + * + * pids.current tracks all child cgroup hierarchies, so parent/pids.current is + * a superset of parent/child/pids.current. + * + * Copyright (C) 2015 Aleksa Sarai + * + * This file is subject to the terms and conditions of version 2 of the GNU + * General Public License. See the file COPYING in the main directory of the + * Linux distribution for more details. + */ + +#include +#include +#include +#include +#include + +#define PIDS_MAX (PID_MAX_LIMIT + 1ULL) +#define PIDS_MAX_STR "max" + +struct pids_cgroup { + struct cgroup_subsys_state css; + + /* + * Use 64-bit types so that we can safely represent "max" as + * %PIDS_MAX = (%PID_MAX_LIMIT + 1). + */ + atomic64_t counter; + int64_t limit; +}; + +static struct pids_cgroup *css_pids(struct cgroup_subsys_state *css) +{ + return container_of(css, struct pids_cgroup, css); +} + +static struct pids_cgroup *parent_pids(struct pids_cgroup *pids) +{ + return css_pids(pids->css.parent); +} + +static struct cgroup_subsys_state * +pids_css_alloc(struct cgroup_subsys_state *parent) +{ + struct pids_cgroup *pids; + + pids = kzalloc(sizeof(struct pids_cgroup), GFP_KERNEL); + if (!pids) + return ERR_PTR(-ENOMEM); + + pids->limit = PIDS_MAX; + atomic64_set(&pids->counter, 0); + return &pids->css; +} + +static void pids_css_free(struct cgroup_subsys_state *css) +{ + kfree(css_pids(css)); +} + +/** + * pids_cancel - uncharge the local pid count + * @pids: the pid cgroup state + * @num: the number of pids to cancel + * + * This function will WARN if the pid count goes under 0, because such a case is + * a bug in the pids controller proper. + */ +static void pids_cancel(struct pids_cgroup *pids, int num) +{ + /* + * A negative count (or overflow for that matter) is invalid, + * and indicates a bug in the `pids` controller proper. + */ + WARN_ON_ONCE(atomic64_add_negative(-num, &pids->counter)); +} + +/** + * pids_uncharge - hierarchically uncharge the pid count + * @pids: the pid cgroup state + * @num: the number of pids to uncharge + */ +static void pids_uncharge(struct pids_cgroup *pids, int num) +{ + struct pids_cgroup *p; + + for (p = pids; p; p = parent_pids(p)) + pids_cancel(p, num); +} + +/** + * pids_charge - hierarchically charge the pid count + * @pids: the pid cgroup state + * @num: the number of pids to charge + * + * This function does *not* follow the pid limit set. It cannot fail and the new + * pid count may exceed the limit. This is only used for reverting failed + * attaches, where there is no other way out than violating the limit. + */ +static void pids_charge(struct pids_cgroup *pids, int num) +{ + struct pids_cgroup *p; + + for (p = pids; p; p = parent_pids(p)) + atomic64_add(num, &p->counter); +} + +/** + * pids_try_charge - hierarchically try to charge the pid count + * @pids: the pid cgroup state + * @num: the number of pids to charge + * + * This function follows the set limit. It will fail if the charge would cause + * the new value to exceed the hierarchical limit. Returns 0 if the charge + * succeded, otherwise -EAGAIN. + */ +static int pids_try_charge(struct pids_cgroup *pids, int num) +{ + struct pids_cgroup *p, *q; + + for (p = pids; p; p = parent_pids(p)) { + int64_t new = atomic64_add_return(num, &p->counter); + + /* + * Since new is capped to the maximum number of pid_t, if + * p->limit is %PIDS_MAX then we know that this test will never + * fail. + */ + if (new > p->limit) + goto revert; + } + + return 0; + +revert: + for (q = pids; q != p; q = parent_pids(q)) + pids_cancel(q, num); + pids_cancel(p, num); + + return -EAGAIN; +} + +static int pids_can_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset) +{ + struct pids_cgroup *pids = css_pids(css); + struct task_struct *task; + + cgroup_taskset_for_each(task, tset) { + struct cgroup_subsys_state *old_css; + struct pids_cgroup *old_pids; + + /* + * Grab a ref to each task's css. We don't drop the ref until + * we either fail and hit ->cancel_attach() or succeed and hit + * ->attach(). + */ + old_css = task_get_css(task, pids_cgrp_id); + old_pids = css_pids(old_css); + + pids_charge(pids, 1); + pids_uncharge(old_pids, 1); + } + + return 0; +} + +static void pids_cancel_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset) +{ + struct pids_cgroup *pids = css_pids(css); + struct task_struct *task; + + cgroup_taskset_for_each(task, tset) { + struct cgroup_subsys_state *old_css; + struct pids_cgroup *old_pids; + + old_css = task_css(task, pids_cgrp_id); + old_pids = css_pids(old_css); + + pids_charge(old_pids, 1); + pids_uncharge(pids, 1); + css_put(old_css); + } +} + +static void pids_attach(struct cgroup_subsys_state *css, + struct cgroup_taskset *tset) +{ + struct task_struct *task; + + cgroup_taskset_for_each(task, tset) + css_put(task_css(task, pids_cgrp_id)); +} + +static int pids_can_fork(struct task_struct *task, void **priv_p) +{ + struct cgroup_subsys_state *css; + struct pids_cgroup *pids; + int err; + + /* + * Use the "current" task_css for the pids subsystem as the tentative + * css. It is possible we will charge the wrong hierarchy, in which + * case we will forcefully revert/reapply the charge on the right + * hierarchy after it is committed to the task proper. + */ + css = task_get_css(current, pids_cgrp_id); + pids = css_pids(css); + + err = pids_try_charge(pids, 1); + if (err) + goto err_css_put; + + *priv_p = css; + return 0; + +err_css_put: + css_put(css); + return err; +} + +static void pids_cancel_fork(struct task_struct *task, void *priv) +{ + struct cgroup_subsys_state *css = priv; + struct pids_cgroup *pids = css_pids(css); + + pids_uncharge(pids, 1); + css_put(css); +} + +static void pids_fork(struct task_struct *task, void *priv) +{ + struct cgroup_subsys_state *css; + struct cgroup_subsys_state *old_css = priv; + struct pids_cgroup *pids; + struct pids_cgroup *old_pids = css_pids(old_css); + + css = task_get_css(task, pids_cgrp_id); + pids = css_pids(css); + + /* + * If the association has changed, we have to revert and reapply the + * charge/uncharge on the wrong hierarchy to the current one. Since + * the association can only change due to an organisation event, its + * okay for us to ignore the limit in this case. + */ + if (pids != old_pids) { + pids_uncharge(old_pids, 1); + pids_charge(pids, 1); + } + + css_put(css); + css_put(old_css); +} + +static void pids_exit(struct cgroup_subsys_state *css, + struct cgroup_subsys_state *old_css, + struct task_struct *task) +{ + struct pids_cgroup *pids = css_pids(old_css); + + pids_uncharge(pids, 1); +} + +static ssize_t pids_max_write(struct kernfs_open_file *of, char *buf, + size_t nbytes, loff_t off) +{ + struct cgroup_subsys_state *css = of_css(of); + struct pids_cgroup *pids = css_pids(css); + int64_t limit; + int err; + + buf = strstrip(buf); + if (!strcmp(buf, PIDS_MAX_STR)) { + limit = PIDS_MAX; + goto set_limit; + } + + err = kstrtoll(buf, 0, &limit); + if (err) + return err; + + if (limit < 0 || limit >= PIDS_MAX) + return -EINVAL; + +set_limit: + /* + * Limit updates don't need to be mutex'd, since it isn't + * critical that any racing fork()s follow the new limit. + */ + pids->limit = limit; + return nbytes; +} + +static int pids_max_show(struct seq_file *sf, void *v) +{ + struct cgroup_subsys_state *css = seq_css(sf); + struct pids_cgroup *pids = css_pids(css); + int64_t limit = pids->limit; + + if (limit >= PIDS_MAX) + seq_printf(sf, "%s\n", PIDS_MAX_STR); + else + seq_printf(sf, "%lld\n", limit); + + return 0; +} + +static s64 pids_current_read(struct cgroup_subsys_state *css, + struct cftype *cft) +{ + struct pids_cgroup *pids = css_pids(css); + + return atomic64_read(&pids->counter); +} + +static struct cftype pids_files[] = { + { + .name = "max", + .write = pids_max_write, + .seq_show = pids_max_show, + .flags = CFTYPE_NOT_ON_ROOT, + }, + { + .name = "current", + .read_s64 = pids_current_read, + }, + { } /* terminate */ +}; + +struct cgroup_subsys pids_cgrp_subsys = { + .css_alloc = pids_css_alloc, + .css_free = pids_css_free, + .attach = pids_attach, + .can_attach = pids_can_attach, + .cancel_attach = pids_cancel_attach, + .can_fork = pids_can_fork, + .cancel_fork = pids_cancel_fork, + .fork = pids_fork, + .exit = pids_exit, + .legacy_cftypes = pids_files, + .dfl_cftypes = pids_files, +}; -- GitLab From 917d8e2d10f40e28aa9e0d824b2e5b8197d79fc2 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sat, 13 Jun 2015 03:21:58 +1000 Subject: [PATCH 0835/7006] cgroup: add documentation for the PIDs controller Add documentation derived from kernel/cgroup_pids.c to the relevant Documentation/ directory, along with a few examples of how to use the PIDs controller as well an explanation of its peculiarities. Signed-off-by: Aleksa Sarai Signed-off-by: Tejun Heo --- Documentation/cgroups/00-INDEX | 2 + Documentation/cgroups/pids.txt | 85 ++++++++++++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 Documentation/cgroups/pids.txt diff --git a/Documentation/cgroups/00-INDEX b/Documentation/cgroups/00-INDEX index 96ce071a36339..3f5a40f57d4a4 100644 --- a/Documentation/cgroups/00-INDEX +++ b/Documentation/cgroups/00-INDEX @@ -22,6 +22,8 @@ net_cls.txt - Network classifier cgroups details and usages. net_prio.txt - Network priority cgroups details and usages. +pids.txt + - Process number cgroups details and usages. resource_counter.txt - Resource Counter API. unified-hierarchy.txt diff --git a/Documentation/cgroups/pids.txt b/Documentation/cgroups/pids.txt new file mode 100644 index 0000000000000..1a078b5d281ae --- /dev/null +++ b/Documentation/cgroups/pids.txt @@ -0,0 +1,85 @@ + Process Number Controller + ========================= + +Abstract +-------- + +The process number controller is used to allow a cgroup hierarchy to stop any +new tasks from being fork()'d or clone()'d after a certain limit is reached. + +Since it is trivial to hit the task limit without hitting any kmemcg limits in +place, PIDs are a fundamental resource. As such, PID exhaustion must be +preventable in the scope of a cgroup hierarchy by allowing resource limiting of +the number of tasks in a cgroup. + +Usage +----- + +In order to use the `pids` controller, set the maximum number of tasks in +pids.max (this is not available in the root cgroup for obvious reasons). The +number of processes currently in the cgroup is given by pids.current. + +Organisational operations are not blocked by cgroup policies, so it is possible +to have pids.current > pids.max. This can be done by either setting the limit to +be smaller than pids.current, or attaching enough processes to the cgroup such +that pids.current > pids.max. However, it is not possible to violate a cgroup +policy through fork() or clone(). fork() and clone() will return -EAGAIN if the +creation of a new process would cause a cgroup policy to be violated. + +To set a cgroup to have no limit, set pids.max to "max". This is the default for +all new cgroups (N.B. that PID limits are hierarchical, so the most stringent +limit in the hierarchy is followed). + +pids.current tracks all child cgroup hierarchies, so parent/pids.current is a +superset of parent/child/pids.current. + +Example +------- + +First, we mount the pids controller: +# mkdir -p /sys/fs/cgroup/pids +# mount -t cgroup -o pids none /sys/fs/cgroup/pids + +Then we create a hierarchy, set limits and attach processes to it: +# mkdir -p /sys/fs/cgroup/pids/parent/child +# echo 2 > /sys/fs/cgroup/pids/parent/pids.max +# echo $$ > /sys/fs/cgroup/pids/parent/cgroup.procs +# cat /sys/fs/cgroup/pids/parent/pids.current +2 +# + +It should be noted that attempts to overcome the set limit (2 in this case) will +fail: + +# cat /sys/fs/cgroup/pids/parent/pids.current +2 +# ( /bin/echo "Here's some processes for you." | cat ) +sh: fork: Resource temporary unavailable +# + +Even if we migrate to a child cgroup (which doesn't have a set limit), we will +not be able to overcome the most stringent limit in the hierarchy (in this case, +parent's): + +# echo $$ > /sys/fs/cgroup/pids/parent/child/cgroup.procs +# cat /sys/fs/cgroup/pids/parent/pids.current +2 +# cat /sys/fs/cgroup/pids/parent/child/pids.current +2 +# cat /sys/fs/cgroup/pids/parent/child/pids.max +max +# ( /bin/echo "Here's some processes for you." | cat ) +sh: fork: Resource temporary unavailable +# + +We can set a limit that is smaller than pids.current, which will stop any new +processes from being forked at all (note that the shell itself counts towards +pids.current): + +# echo 1 > /sys/fs/cgroup/pids/parent/pids.max +# /bin/echo "We can't even spawn a single process now." +sh: fork: Resource temporary unavailable +# echo 0 > /sys/fs/cgroup/pids/parent/pids.max +# /bin/echo "We can't even spawn a single process now." +sh: fork: Resource temporary unavailable +# -- GitLab From 5dbc247c2a11f6b9febb854a55be5ae6be720df6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 14:55:13 +0200 Subject: [PATCH 0836/7006] ata: sata_rcar: Remove obsolete sata-r8a779* platform_device_id entries Since commit a483dcbfa21f919c ("ARM: shmobile: lager: Remove legacy board support"), R-Car Gen2 SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Signed-off-by: Tejun Heo --- drivers/ata/sata_rcar.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c index d49a5193b7de9..8804127b108c0 100644 --- a/drivers/ata/sata_rcar.c +++ b/drivers/ata/sata_rcar.c @@ -861,10 +861,6 @@ MODULE_DEVICE_TABLE(of, sata_rcar_match); static const struct platform_device_id sata_rcar_id_table[] = { { "sata_rcar", RCAR_GEN1_SATA }, /* Deprecated by "sata-r8a7779" */ { "sata-r8a7779", RCAR_GEN1_SATA }, - { "sata-r8a7790", RCAR_GEN2_SATA }, - { "sata-r8a7790-es1", RCAR_R8A7790_ES1_SATA }, - { "sata-r8a7791", RCAR_GEN2_SATA }, - { "sata-r8a7793", RCAR_GEN2_SATA }, { }, }; MODULE_DEVICE_TABLE(platform, sata_rcar_id_table); -- GitLab From 83cb8557e8d2c8e5eddc64840c437299343a7960 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Fri, 26 Jun 2015 17:21:28 -0400 Subject: [PATCH 0837/7006] percpu: update incorrect comment for this_cpu_*() operations this_cpu_*() ops have been protected against both preemption and interrupts for quite a while now. We apparently forgot to update the comment. Fix it. Signed-off-by: Tejun Heo Cc: Christoph Lameter --- include/linux/percpu-defs.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/linux/percpu-defs.h b/include/linux/percpu-defs.h index 57f3a1c550dc6..8f16299ca0683 100644 --- a/include/linux/percpu-defs.h +++ b/include/linux/percpu-defs.h @@ -488,10 +488,8 @@ do { \ #define __this_cpu_dec_return(pcp) __this_cpu_add_return(pcp, -1) /* - * Operations with implied preemption protection. These operations can be - * used without worrying about preemption. Note that interrupts may still - * occur while an operation is in progress and if the interrupt modifies - * the variable too then RMW actions may not be reliable. + * Operations with implied preemption/interrupt protection. These + * operations can be used without worrying about preemption or interrupt. */ #define this_cpu_read(pcp) __pcpu_size_call_return(this_cpu_read_, pcp) #define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) -- GitLab From badb7f5e8bddf74a2f2dcc7d9d88accabfc000f5 Mon Sep 17 00:00:00 2001 From: Lai Jiangshan Date: Wed, 1 Jul 2015 15:38:04 +0800 Subject: [PATCH 0838/7006] workqueue: add myself as a dedicated reviwer I am one of the dedicated reviwers of workqueue.c. Now I add myself to the MAINTAINERS entry with the updated email address. The old laijs@cn.fujitsu.com will be ended soon. Signed-off-by: Lai Jiangshan Signed-off-by: Lai Jiangshan Signed-off-by: Tejun Heo --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 8133cefb6b6e2..f136c296c421d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11165,6 +11165,7 @@ F: sound/soc/codecs/wm* WORKQUEUE M: Tejun Heo +R: Lai Jiangshan T: git git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git S: Maintained F: include/linux/workqueue.h -- GitLab From aad0d51e933f8656880592020319d2dbd09532a2 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 10 Jul 2015 21:10:10 +0300 Subject: [PATCH 0839/7006] ravb: kill useless initializers Some of the local variable intializers in the driver turned out to be pointless, kill them. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index fd9745714d903..47287c1cc7e0b 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -223,9 +223,9 @@ static void ravb_ring_free(struct net_device *ndev, int q) static void ravb_ring_format(struct net_device *ndev, int q) { struct ravb_private *priv = netdev_priv(ndev); - struct ravb_ex_rx_desc *rx_desc = NULL; - struct ravb_tx_desc *tx_desc = NULL; - struct ravb_desc *desc = NULL; + struct ravb_ex_rx_desc *rx_desc; + struct ravb_tx_desc *tx_desc; + struct ravb_desc *desc; int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q]; struct sk_buff *skb; @@ -435,7 +435,7 @@ static int ravb_tx_free(struct net_device *ndev, int q) struct net_device_stats *stats = &priv->stats[q]; struct ravb_tx_desc *desc; int free_num = 0; - int entry = 0; + int entry; u32 size; for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { @@ -508,8 +508,8 @@ static bool ravb_rx(struct net_device *ndev, int *quota, int q) struct sk_buff *skb; dma_addr_t dma_addr; struct timespec64 ts; - u16 pkt_len = 0; u8 desc_status; + u16 pkt_len; int limit; boguscnt = min(boguscnt, *quota); @@ -1272,8 +1272,8 @@ static void ravb_tx_timeout_work(struct work_struct *work) static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) { struct ravb_private *priv = netdev_priv(ndev); - struct ravb_tstamp_skb *ts_skb = NULL; u16 q = skb_get_queue_mapping(skb); + struct ravb_tstamp_skb *ts_skb; struct ravb_tx_desc *desc; unsigned long flags; u32 dma_addr; -- GitLab From f44a75e27d5eb4b1788f59c2bc185baaaf732f75 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Tue, 14 Apr 2015 17:09:14 -0700 Subject: [PATCH 0840/7006] i40e: Implement ndo_features_check() i40e supports UDP tunnel headers up to 80 bytes in length, so this adds a check to ensure that it doesn't try to offload packets that exceed that. Signed-off-by: Joe Stringer Signed-off-by: Jesse Gross Acked-by: Jesse Brandeburg Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 48a52b35b6142..b44eb357cff7e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8099,6 +8099,25 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, } #endif /* HAVE_BRIDGE_ATTRIBS */ +#define I40E_MAX_TUNNEL_HDR_LEN 80 +/** + * i40e_features_check - Validate encapsulated packet conforms to limits + * @skb: skb buff + * @netdev: This physical port's netdev + * @features: Offload features that the stack believes apply + **/ +static netdev_features_t i40e_features_check(struct sk_buff *skb, + struct net_device *dev, + netdev_features_t features) +{ + if (skb->encapsulation && + (skb_inner_mac_header(skb) - skb_transport_header(skb) > + I40E_MAX_TUNNEL_HDR_LEN)) + return features & ~(NETIF_F_ALL_CSUM | NETIF_F_GSO_MASK); + + return features; +} + static const struct net_device_ops i40e_netdev_ops = { .ndo_open = i40e_open, .ndo_stop = i40e_close, @@ -8133,6 +8152,7 @@ static const struct net_device_ops i40e_netdev_ops = { #endif .ndo_get_phys_port_id = i40e_get_phys_port_id, .ndo_fdb_add = i40e_ndo_fdb_add, + .ndo_features_check = i40e_features_check, #ifdef HAVE_BRIDGE_ATTRIBS .ndo_bridge_getlink = i40e_ndo_bridge_getlink, .ndo_bridge_setlink = i40e_ndo_bridge_setlink, -- GitLab From d0389e51fc9b3c74e7935ded5d22eab4ea004589 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Wed, 22 Apr 2015 19:34:05 -0400 Subject: [PATCH 0841/7006] i40e/i40evf: Add stats to track FD ATR and SB dynamic enable state Since the driver can dynamically enable/disable FD ATR and SB features, these stats help keep track of the current state and along with fd_flush count provide a means to debug what could be going on with the flow director filters. This will take away the need for being verbose in our debug logs with respect to FD. Change-ID: I29224f750fe6602391043655d18996570720377d Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_main.c | 12 ++++++++++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 2 ++ 4 files changed, 18 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 9a68c65b17ea0..0b68f61eeb0c0 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -148,7 +148,9 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("fdir_flush_cnt", fd_flush_cnt), I40E_PF_STAT("fdir_atr_match", stats.fd_atr_match), I40E_PF_STAT("fdir_atr_tunnel_match", stats.fd_atr_tunnel_match), + I40E_PF_STAT("fdir_atr_status", stats.fd_atr_status), I40E_PF_STAT("fdir_sb_match", stats.fd_sb_match), + I40E_PF_STAT("fdir_sb_status", stats.fd_sb_status), /* LPI stats */ I40E_PF_STAT("tx_lpi_status", stats.tx_lpi_status), diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b44eb357cff7e..b5fc6544fb69a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1123,6 +1123,18 @@ static void i40e_update_pf_stats(struct i40e_pf *pf) pf->stat_offsets_loaded, &osd->rx_lpi_count, &nsd->rx_lpi_count); + if (pf->flags & I40E_FLAG_FD_SB_ENABLED && + !(pf->auto_disable_flags & I40E_FLAG_FD_SB_ENABLED)) + nsd->fd_sb_status = true; + else + nsd->fd_sb_status = false; + + if (pf->flags & I40E_FLAG_FD_ATR_ENABLED && + !(pf->auto_disable_flags & I40E_FLAG_FD_ATR_ENABLED)) + nsd->fd_atr_status = true; + else + nsd->fd_atr_status = false; + pf->stat_offsets_loaded = true; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 9a5a75b1e2bc0..350c5ee85ec39 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1134,6 +1134,8 @@ struct i40e_hw_port_stats { u64 fd_atr_match; u64 fd_sb_match; u64 fd_atr_tunnel_match; + u32 fd_atr_status; + u32 fd_sb_status; /* EEE LPI */ u32 tx_lpi_status; u32 rx_lpi_status; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index c463ec41579c7..068813d3c7a30 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -1109,6 +1109,8 @@ struct i40e_hw_port_stats { u64 fd_atr_match; u64 fd_sb_match; u64 fd_atr_tunnel_match; + u32 fd_atr_status; + u32 fd_sb_status; /* EEE LPI */ u32 tx_lpi_status; u32 rx_lpi_status; -- GitLab From c78b953e0f189824f5eaa2d60123cfd12ea6db0d Mon Sep 17 00:00:00 2001 From: Pawel Orlowski Date: Wed, 22 Apr 2015 19:34:06 -0400 Subject: [PATCH 0842/7006] i40e/i40evf: Update Flex-10 related device/function capabilities The Flex10 device/function capability has been upgraded to include information needed to support Flex-10 configurations. This patch adds new fields to the i40e_hw_capabilities structure and updates i40e_parse_discover_capabilities functions to extract them from the AQ response. Naming convention has changed to use flex10 mode instead of existing mfp_mode_1. Change-ID: I305dd888866985a30293acb3fb14fa43ca6b79ea Signed-off-by: Pawel Orlowski Signed-off-by: Akeem G Abodunrin Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 24 +++++++++++++++---- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40e/i40e_type.h | 12 +++++++++- drivers/net/ethernet/intel/i40evf/i40e_type.h | 12 +++++++++- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 0bae22da014db..07032229ee60f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -2391,7 +2391,7 @@ i40e_aq_erase_nvm_exit: #define I40E_DEV_FUNC_CAP_MSIX_VF 0x44 #define I40E_DEV_FUNC_CAP_FLOW_DIRECTOR 0x45 #define I40E_DEV_FUNC_CAP_IEEE_1588 0x46 -#define I40E_DEV_FUNC_CAP_MFP_MODE_1 0xF1 +#define I40E_DEV_FUNC_CAP_FLEX10 0xF1 #define I40E_DEV_FUNC_CAP_CEM 0xF2 #define I40E_DEV_FUNC_CAP_IWARP 0x51 #define I40E_DEV_FUNC_CAP_LED 0x61 @@ -2416,6 +2416,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, u32 valid_functions, num_functions; u32 number, logical_id, phys_id; struct i40e_hw_capabilities *p; + u8 major_rev; u32 i = 0; u16 id; @@ -2433,6 +2434,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, number = le32_to_cpu(cap->number); logical_id = le32_to_cpu(cap->logical_id); phys_id = le32_to_cpu(cap->phys_id); + major_rev = cap->major_rev; switch (id) { case I40E_DEV_FUNC_CAP_SWITCH_MODE: @@ -2507,9 +2509,21 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, case I40E_DEV_FUNC_CAP_MSIX_VF: p->num_msix_vectors_vf = number; break; - case I40E_DEV_FUNC_CAP_MFP_MODE_1: - if (number == 1) - p->mfp_mode_1 = true; + case I40E_DEV_FUNC_CAP_FLEX10: + if (major_rev == 1) { + if (number == 1) { + p->flex10_enable = true; + p->flex10_capable = true; + } + } else { + /* Capability revision >= 2 */ + if (number & 1) + p->flex10_enable = true; + if (number & 2) + p->flex10_capable = true; + } + p->flex10_mode = logical_id; + p->flex10_status = phys_id; break; case I40E_DEV_FUNC_CAP_CEM: if (number == 1) @@ -2557,7 +2571,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff, /* Software override ensuring FCoE is disabled if npar or mfp * mode because it is not supported in these modes. */ - if (p->npar_enable || p->mfp_mode_1) + if (p->npar_enable || p->flex10_enable) p->fcoe = false; /* count the enabled ports (aka the "not disabled" ports) */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index b5fc6544fb69a..ed6fc52362af2 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7685,7 +7685,7 @@ static int i40e_sw_init(struct i40e_pf *pf) } /* MFP mode enabled */ - if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.mfp_mode_1) { + if (pf->hw.func_caps.npar_enable || pf->hw.func_caps.flex10_enable) { pf->flags |= I40E_FLAG_MFP_ENABLED; dev_info(&pf->pdev->dev, "MFP mode Enabled\n"); if (i40e_get_npar_bw_setting(pf)) diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 350c5ee85ec39..220371ece7c43 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -213,7 +213,17 @@ struct i40e_hw_capabilities { bool dcb; bool fcoe; bool iscsi; /* Indicates iSCSI enabled */ - bool mfp_mode_1; + bool flex10_enable; + bool flex10_capable; + u32 flex10_mode; +#define I40E_FLEX10_MODE_UNKNOWN 0x0 +#define I40E_FLEX10_MODE_DCC 0x1 +#define I40E_FLEX10_MODE_DCI 0x2 + + u32 flex10_status; +#define I40E_FLEX10_STATUS_DCC_ERROR 0x1 +#define I40E_FLEX10_STATUS_VC_MODE 0x2 + bool mgmt_cem; bool ieee_1588; bool iwarp; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 068813d3c7a30..3969c6548af05 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -213,7 +213,17 @@ struct i40e_hw_capabilities { bool dcb; bool fcoe; bool iscsi; /* Indicates iSCSI enabled */ - bool mfp_mode_1; + bool flex10_enable; + bool flex10_capable; + u32 flex10_mode; +#define I40E_FLEX10_MODE_UNKNOWN 0x0 +#define I40E_FLEX10_MODE_DCC 0x1 +#define I40E_FLEX10_MODE_DCI 0x2 + + u32 flex10_status; +#define I40E_FLEX10_STATUS_DCC_ERROR 0x1 +#define I40E_FLEX10_STATUS_VC_MODE 0x2 + bool mgmt_cem; bool ieee_1588; bool iwarp; -- GitLab From 489ce7a46306052ab4ef26c6305051c5f1b24bb4 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Mon, 27 Apr 2015 14:57:08 -0400 Subject: [PATCH 0843/7006] i40e/i40evf: improve Tx performance with a small tweak Add a prefetch for the next Tx descriptor to be used when we know there are more coming. Change-ID: Ibb9acab11d508eec2db7da795df74debc16eeacb Signed-off-by: Jesse Brandeburg Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 2 ++ drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 9a4f2bc70cd2c..1fe230d2be5d6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -2616,6 +2616,8 @@ static inline void i40e_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index))) writel(i, tx_ring->tail); + else + prefetchw(tx_desc + 1); return; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 395f32f226c08..0f0e185b5c66a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1841,6 +1841,8 @@ static inline void i40evf_tx_map(struct i40e_ring *tx_ring, struct sk_buff *skb, netif_xmit_stopped(netdev_get_tx_queue(tx_ring->netdev, tx_ring->queue_index))) writel(i, tx_ring->tail); + else + prefetchw(tx_desc + 1); return; -- GitLab From 973371da4d66b96736143bd3f2b2ff2331faae8f Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:09 -0400 Subject: [PATCH 0844/7006] i40evf: Allow for an abundance of vectors The driver currently only maps TX and RX queues to a single MSI-X vector per queue pair if there are exactly enough vectors for this. Unfortunately, if we have too many vectors it will fail and allocate queues to vectors in a suboptimal manner. Change the condition check to allow for excess vectors. In this case, the extras just won't be used. Change-ID: I23e1e2955c64739c86612db88a25583e6a7e0b17 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 4ab4ebba07a18..94eff4a269e69 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -406,7 +406,7 @@ static int i40evf_map_rings_to_vectors(struct i40evf_adapter *adapter) /* The ideal configuration... * We have enough vectors to map one per queue. */ - if (q_vectors == (rxr_remaining * 2)) { + if (q_vectors >= (rxr_remaining * 2)) { for (; rxr_idx < rxr_remaining; v_start++, rxr_idx++) i40evf_map_vector_to_rxq(adapter, v_start, rxr_idx); -- GitLab From 85927ec1b369c880407aa82eba70d49c04c35062 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:10 -0400 Subject: [PATCH 0845/7006] i40e: ignore duplicate port VLAN requests If user attempts to set a port VLAN on a VF that already has the same port VLAN configured, the driver will go through a completely unnecessary flurry of filter removals and filter adds. Just check for this condition and return success instead of doing a bunch of busywork. Change-ID: Ia1a9e83e6ed48b3f4658bc20dfc6af0cf525d54a Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 23f95cdbdfcc2..433e80320eeaa 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2088,6 +2088,10 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, goto error_pvid; } + if (vsi->info.pvid == (vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT))) + /* duplicate request, so just return success */ + goto error_pvid; + if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) { dev_err(&pf->pdev->dev, "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n", -- GitLab From 9df70b66418e284dc1e7f272ac445c1d1e990b97 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Mon, 27 Apr 2015 14:57:11 -0400 Subject: [PATCH 0846/7006] i40e: Remove incorrect #ifdef's This patch removes some #ifdef's that should not be there. They were stopping code that is needed from being compiled in. With these #ifdef's removed, changes are needed in the driver to fix some compile errors: adding missing parameters to the definition of ndo_bridge_setlink and a ndo_dflt_brige_getlink call. Change-ID: I5516614e1bc50b6bca0647cef971bc96161ba2de Signed-off-by: Carolyn Wyborny Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ed6fc52362af2..c7f2a0a74dcf9 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -7993,7 +7993,6 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], return err; } -#ifdef HAVE_BRIDGE_ATTRIBS /** * i40e_ndo_bridge_setlink - Set the hardware bridge mode * @dev: the netdev being configured @@ -8007,7 +8006,8 @@ static int i40e_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], * bridge mode enabled. **/ static int i40e_ndo_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh) + struct nlmsghdr *nlh, + u16 flags) { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; @@ -8078,14 +8078,9 @@ static int i40e_ndo_bridge_setlink(struct net_device *dev, * Return the mode in which the hardware bridge is operating in * i.e VEB or VEPA. **/ -#ifdef HAVE_BRIDGE_FILTER static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u32 filter_mask, int nlflags) -#else -static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, int nlflags) -#endif /* HAVE_BRIDGE_FILTER */ { struct i40e_netdev_priv *np = netdev_priv(dev); struct i40e_vsi *vsi = np->vsi; @@ -8109,7 +8104,6 @@ static int i40e_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, return ndo_dflt_bridge_getlink(skb, pid, seq, dev, veb->bridge_mode, nlflags, 0, 0, filter_mask, NULL); } -#endif /* HAVE_BRIDGE_ATTRIBS */ #define I40E_MAX_TUNNEL_HDR_LEN 80 /** @@ -8165,10 +8159,8 @@ static const struct net_device_ops i40e_netdev_ops = { .ndo_get_phys_port_id = i40e_get_phys_port_id, .ndo_fdb_add = i40e_ndo_fdb_add, .ndo_features_check = i40e_features_check, -#ifdef HAVE_BRIDGE_ATTRIBS .ndo_bridge_getlink = i40e_ndo_bridge_getlink, .ndo_bridge_setlink = i40e_ndo_bridge_setlink, -#endif /* HAVE_BRIDGE_ATTRIBS */ }; /** -- GitLab From cb2f65bc0c64015e8fa45fe1065ad241bf31a994 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Mon, 27 Apr 2015 14:57:12 -0400 Subject: [PATCH 0847/7006] i40e/i40evf: Update the admin queue command header Make the necessary updates to i40e_adminq_cmd.h. Change-ID: Ib031c86cc6cab78e5aa44c64d8ce5474be8d7e42 Signed-off-by: Greg Rose Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_adminq_cmd.h | 24 ++++++++++--------- .../ethernet/intel/i40evf/i40e_adminq_cmd.h | 18 ++++++-------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index 929e3d72a01e5..9101f5c00f371 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -34,7 +34,7 @@ */ #define I40E_FW_API_VERSION_MAJOR 0x0001 -#define I40E_FW_API_VERSION_MINOR 0x0002 +#define I40E_FW_API_VERSION_MINOR 0x0004 struct i40e_aq_desc { __le16 flags; @@ -132,12 +132,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_list_func_capabilities = 0x000A, i40e_aqc_opc_list_dev_capabilities = 0x000B, - i40e_aqc_opc_set_cppm_configuration = 0x0103, - i40e_aqc_opc_set_arp_proxy_entry = 0x0104, - i40e_aqc_opc_set_ns_proxy_entry = 0x0105, - /* LAA */ - i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */ i40e_aqc_opc_mac_address_read = 0x0107, i40e_aqc_opc_mac_address_write = 0x0108, @@ -262,7 +257,6 @@ enum i40e_admin_queue_opc { /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, i40e_aqc_opc_del_udp_tunnel = 0x0B01, - i40e_aqc_opc_tunnel_key_structure = 0x0B10, /* Async Events */ i40e_aqc_opc_event_lan_overflow = 0x1001, @@ -274,8 +268,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ - i40e_aqc_opc_debug_get_deviceid = 0xFF00, - i40e_aqc_opc_debug_set_mode = 0xFF01, i40e_aqc_opc_debug_read_reg = 0xFF03, i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, @@ -509,7 +501,8 @@ struct i40e_aqc_mac_address_read { #define I40E_AQC_SAN_ADDR_VALID 0x20 #define I40E_AQC_PORT_ADDR_VALID 0x40 #define I40E_AQC_WOL_ADDR_VALID 0x80 -#define I40E_AQC_ADDR_VALID_MASK 0xf0 +#define I40E_AQC_MC_MAG_EN_VALID 0x100 +#define I40E_AQC_ADDR_VALID_MASK 0x1F0 u8 reserved[6]; __le32 addr_high; __le32 addr_low; @@ -532,7 +525,9 @@ struct i40e_aqc_mac_address_write { #define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000 #define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000 #define I40E_AQC_WRITE_TYPE_PORT 0x8000 -#define I40E_AQC_WRITE_TYPE_MASK 0xc000 +#define I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG 0xC000 +#define I40E_AQC_WRITE_TYPE_MASK 0xC000 + __le16 mac_sah; __le32 mac_sal; u8 reserved[8]; @@ -1068,6 +1063,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes { __le16 seid; #define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF __le16 vlan_tag; +#define I40E_AQC_SET_VSI_VLAN_MASK 0x0FFF #define I40E_AQC_SET_VSI_VLAN_VALID 0x8000 u8 reserved[8]; }; @@ -2064,6 +2060,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_start); #define I40E_AQC_CEE_PFC_STATUS_MASK (0x7 << I40E_AQC_CEE_PFC_STATUS_SHIFT) #define I40E_AQC_CEE_APP_STATUS_SHIFT 0x8 #define I40E_AQC_CEE_APP_STATUS_MASK (0x7 << I40E_AQC_CEE_APP_STATUS_SHIFT) +#define I40E_AQC_CEE_FCOE_STATUS_SHIFT 0x8 +#define I40E_AQC_CEE_FCOE_STATUS_MASK (0x7 << I40E_AQC_CEE_FCOE_STATUS_SHIFT) +#define I40E_AQC_CEE_ISCSI_STATUS_SHIFT 0xA +#define I40E_AQC_CEE_ISCSI_STATUS_MASK (0x7 << I40E_AQC_CEE_ISCSI_STATUS_SHIFT) +#define I40E_AQC_CEE_FIP_STATUS_SHIFT 0x10 +#define I40E_AQC_CEE_FIP_STATUS_MASK (0x7 << I40E_AQC_CEE_FIP_STATUS_SHIFT) struct i40e_aqc_get_cee_dcb_cfg_v1_resp { u8 reserved1; u8 oper_num_tc; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h index e715bccfb5d25..d5bd6f0669213 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h @@ -34,7 +34,7 @@ */ #define I40E_FW_API_VERSION_MAJOR 0x0001 -#define I40E_FW_API_VERSION_MINOR 0x0002 +#define I40E_FW_API_VERSION_MINOR 0x0004 #define I40E_FW_API_VERSION_A0_MINOR 0x0000 struct i40e_aq_desc { @@ -133,12 +133,7 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_list_func_capabilities = 0x000A, i40e_aqc_opc_list_dev_capabilities = 0x000B, - i40e_aqc_opc_set_cppm_configuration = 0x0103, - i40e_aqc_opc_set_arp_proxy_entry = 0x0104, - i40e_aqc_opc_set_ns_proxy_entry = 0x0105, - /* LAA */ - i40e_aqc_opc_mng_laa = 0x0106, /* AQ obsolete */ i40e_aqc_opc_mac_address_read = 0x0107, i40e_aqc_opc_mac_address_write = 0x0108, @@ -260,7 +255,6 @@ enum i40e_admin_queue_opc { /* Tunnel commands */ i40e_aqc_opc_add_udp_tunnel = 0x0B00, i40e_aqc_opc_del_udp_tunnel = 0x0B01, - i40e_aqc_opc_tunnel_key_structure = 0x0B10, /* Async Events */ i40e_aqc_opc_event_lan_overflow = 0x1001, @@ -272,8 +266,6 @@ enum i40e_admin_queue_opc { i40e_aqc_opc_oem_ocbb_initialize = 0xFE03, /* debug commands */ - i40e_aqc_opc_debug_get_deviceid = 0xFF00, - i40e_aqc_opc_debug_set_mode = 0xFF01, i40e_aqc_opc_debug_read_reg = 0xFF03, i40e_aqc_opc_debug_write_reg = 0xFF04, i40e_aqc_opc_debug_modify_reg = 0xFF07, @@ -507,7 +499,8 @@ struct i40e_aqc_mac_address_read { #define I40E_AQC_SAN_ADDR_VALID 0x20 #define I40E_AQC_PORT_ADDR_VALID 0x40 #define I40E_AQC_WOL_ADDR_VALID 0x80 -#define I40E_AQC_ADDR_VALID_MASK 0xf0 +#define I40E_AQC_MC_MAG_EN_VALID 0x100 +#define I40E_AQC_ADDR_VALID_MASK 0x1F0 u8 reserved[6]; __le32 addr_high; __le32 addr_low; @@ -530,7 +523,9 @@ struct i40e_aqc_mac_address_write { #define I40E_AQC_WRITE_TYPE_LAA_ONLY 0x0000 #define I40E_AQC_WRITE_TYPE_LAA_WOL 0x4000 #define I40E_AQC_WRITE_TYPE_PORT 0x8000 -#define I40E_AQC_WRITE_TYPE_MASK 0xc000 +#define I40E_AQC_WRITE_TYPE_UPDATE_MC_MAG 0xC000 +#define I40E_AQC_WRITE_TYPE_MASK 0xC000 + __le16 mac_sah; __le32 mac_sal; u8 reserved[8]; @@ -1066,6 +1061,7 @@ struct i40e_aqc_set_vsi_promiscuous_modes { __le16 seid; #define I40E_AQC_VSI_PROM_CMD_SEID_MASK 0x3FF __le16 vlan_tag; +#define I40E_AQC_SET_VSI_VLAN_MASK 0x0FFF #define I40E_AQC_SET_VSI_VLAN_VALID 0x8000 u8 reserved[8]; }; -- GitLab From e995163cdcf9b70c7840a8d6a7ea7c0ce81c761b Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:13 -0400 Subject: [PATCH 0848/7006] i40e: correctly program filters for VFs MAC filters for VFs were being programmed with 0 for the VLAN value when there was no VLAN assigned. This is incorrect and actually assigns the VF to VLAN 0. Instead, we must use -1 to indicate that no VLAN is in use. This change programs the filters correctly and gets rid of a bogus error message when setting a port VLAN on an active VF. Change-ID: Ica9a9906d768405377ff3308e27f7d0b5b2ea96e Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 433e80320eeaa..4070a22f16c8a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -542,11 +542,13 @@ static int i40e_alloc_vsi_res(struct i40e_vf *vf, enum i40e_vsi_type type) if (vf->port_vlan_id) i40e_vsi_add_pvid(vsi, vf->port_vlan_id); f = i40e_add_filter(vsi, vf->default_lan_addr.addr, - vf->port_vlan_id, true, false); + vf->port_vlan_id ? vf->port_vlan_id : -1, + true, false); if (!f) dev_info(&pf->pdev->dev, "Could not allocate VF MAC addr\n"); - f = i40e_add_filter(vsi, brdcast, vf->port_vlan_id, + f = i40e_add_filter(vsi, brdcast, + vf->port_vlan_id ? vf->port_vlan_id : -1, true, false); if (!f) dev_info(&pf->pdev->dev, @@ -2023,7 +2025,8 @@ int i40e_ndo_set_vf_mac(struct net_device *netdev, int vf_id, u8 *mac) } /* delete the temporary mac address */ - i40e_del_filter(vsi, vf->default_lan_addr.addr, vf->port_vlan_id, + i40e_del_filter(vsi, vf->default_lan_addr.addr, + vf->port_vlan_id ? vf->port_vlan_id : -1, true, false); /* Delete all the filters for this VSI - we're going to kill it -- GitLab From 54f455eeb56c0ab92db87bed6bd767d206d9e743 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:14 -0400 Subject: [PATCH 0849/7006] i40e: do a proper reset when disabling a VF The VF disable code was just whanging on the reset bit without properly cleaning up the VF, which would leave the VF in an indeterminate state from which it could not recover. Fix this by notifying the VF and then by calling the normal VF reset routine. Change-ID: I862b9dfa919368773cbdc212b805b520db2f7430 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 4070a22f16c8a..55b19f5e436ad 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -160,13 +160,8 @@ void i40e_vc_notify_vf_reset(struct i40e_vf *vf) **/ static inline void i40e_vc_disable_vf(struct i40e_pf *pf, struct i40e_vf *vf) { - struct i40e_hw *hw = &pf->hw; - u32 reg; - - reg = rd32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id)); - reg |= I40E_VPGEN_VFRTRIG_VFSWR_MASK; - wr32(hw, I40E_VPGEN_VFRTRIG(vf->vf_id), reg); - i40e_flush(hw); + i40e_vc_notify_vf_reset(vf); + i40e_reset_vf(vf, false); } /** -- GitLab From 5b8f8505d37c63d492391e5fafcd43332671b36b Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:15 -0400 Subject: [PATCH 0850/7006] i40e: un-disable VF after reset When a VF is disabled, there is no way for it to recover until either the PF driver is reloaded or SR-IOV is disabled and enabled. To correct this, enable the VF after a successful reset. Change-ID: I9e0788476c4d53d5407961b503febdfff2b8a7c6 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 55b19f5e436ad..fdd7f5e3a66b1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -832,6 +832,7 @@ complete_reset: i40e_alloc_vf_res(vf); i40e_enable_vf_mappings(vf); set_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states); + clear_bit(I40E_VF_STAT_DISABLED, &vf->vf_states); /* tell the VF the reset is done */ wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE); -- GitLab From 68ef169204e3a88ea4823645038d5496f66200f6 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:16 -0400 Subject: [PATCH 0851/7006] i40evf: don't delete all the filters Due to an inverted conditional, the driver was marking all of its MAC filters for deletion every time set_rx_mode was called. Depending upon the timing of the calls to set_rx_mode and the processing of the admin queue, the driver would (accidentally) end up with a varying number of functional filters. Correct this logic so that MAC filters are added and removed correctly. Add a check for the driver's "hardware" MAC address so that this filter doesn't get removed incorrectly. Change-ID: Ib3e7c4a5b53df6835f164fe44cb778cb71f8aff8 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 94eff4a269e69..1c2ee97d18446 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -892,8 +892,10 @@ static void i40evf_set_rx_mode(struct net_device *netdev) break; } } + if (ether_addr_equal(f->macaddr, adapter->hw.mac.addr)) + found = true; } - if (found) { + if (!found) { f->remove = true; adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER; } -- GitLab From 44151cd32deb1074530f3beba51d535fa0887d9a Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Mon, 27 Apr 2015 14:57:17 -0400 Subject: [PATCH 0852/7006] i40evf: add MAC address filter in open, not init During close, all of the MAC filters are cleared, so the driver would be unable to receive unicast packets after being closed and reopened. Add the adapter's "hardware" MAC address filter in open, not init. This ensures that the correct filter is present each time. Change-ID: I51a11e9c1200139dab6f66a5353bd38c7d26f875 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 1c2ee97d18446..802e158ea981b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1858,6 +1858,7 @@ static int i40evf_open(struct net_device *netdev) if (err) goto err_req_irq; + i40evf_add_filter(adapter, adapter->hw.mac.addr); i40evf_configure(adapter); err = i40evf_up_complete(adapter); @@ -1998,7 +1999,6 @@ static void i40evf_init_task(struct work_struct *work) struct i40evf_adapter, init_task.work); struct net_device *netdev = adapter->netdev; - struct i40evf_mac_filter *f; struct i40e_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; int i, err, bufsz; @@ -2132,16 +2132,6 @@ static void i40evf_init_task(struct work_struct *work) ether_addr_copy(netdev->dev_addr, adapter->hw.mac.addr); ether_addr_copy(netdev->perm_addr, adapter->hw.mac.addr); - f = kzalloc(sizeof(*f), GFP_ATOMIC); - if (!f) - goto err_sw_init; - - ether_addr_copy(f->macaddr, adapter->hw.mac.addr); - f->add = true; - adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; - - list_add(&f->list, &adapter->mac_filter_list); - init_timer(&adapter->watchdog_timer); adapter->watchdog_timer.function = &i40evf_watchdog_timer; adapter->watchdog_timer.data = (unsigned long)adapter; -- GitLab From 3bbf0faa90cb8d541d8b2ce01610dcec6828bd00 Mon Sep 17 00:00:00 2001 From: Faisal Latif Date: Mon, 27 Apr 2015 14:57:19 -0400 Subject: [PATCH 0853/7006] i40e/i40evf: Add support for pre-allocated pages for PD The i40e_add_pd_table_entry() routine is being modified to handle both cases where a backing page is passed and where backing page is allocated in i40e_add_pd_table_entry(). For PBLE resource management, it is more efficient for it to manage its backing pages. For VF, PBLE backing page addresses will be send to PF driver for PBLE resource. The i40e_remove_pd_bp() is also modified to not free pre-allocated pages and free only ones which were allocated in i40e_add_pd_table_entry(). Change-ID: Ie673f0403f22979e9406f5a94048dceb91bcf9a8 Signed-off-by: Faisal Latif Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_hmc.c | 30 ++++++++++++------- drivers/net/ethernet/intel/i40e/i40e_hmc.h | 4 ++- .../net/ethernet/intel/i40e/i40e_lan_hmc.c | 2 +- drivers/net/ethernet/intel/i40evf/i40e_hmc.h | 4 ++- 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c index 9b987ccc9e828..b89856a5e313b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c @@ -116,6 +116,7 @@ exit: * @hw: pointer to our HW structure * @hmc_info: pointer to the HMC configuration information structure * @pd_index: which page descriptor index to manipulate + * @rsrc_pg: if not NULL, use preallocated page instead of allocating new one. * * This function: * 1. Initializes the pd entry @@ -129,12 +130,14 @@ exit: **/ i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, - u32 pd_index) + u32 pd_index, + struct i40e_dma_mem *rsrc_pg) { i40e_status ret_code = 0; struct i40e_hmc_pd_table *pd_table; struct i40e_hmc_pd_entry *pd_entry; struct i40e_dma_mem mem; + struct i40e_dma_mem *page = &mem; u32 sd_idx, rel_pd_idx; u64 *pd_addr; u64 page_desc; @@ -155,18 +158,24 @@ i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, pd_table = &hmc_info->sd_table.sd_entry[sd_idx].u.pd_table; pd_entry = &pd_table->pd_entry[rel_pd_idx]; if (!pd_entry->valid) { - /* allocate a 4K backing page */ - ret_code = i40e_allocate_dma_mem(hw, &mem, i40e_mem_bp, - I40E_HMC_PAGED_BP_SIZE, - I40E_HMC_PD_BP_BUF_ALIGNMENT); - if (ret_code) - goto exit; + if (rsrc_pg) { + pd_entry->rsrc_pg = true; + page = rsrc_pg; + } else { + /* allocate a 4K backing page */ + ret_code = i40e_allocate_dma_mem(hw, page, i40e_mem_bp, + I40E_HMC_PAGED_BP_SIZE, + I40E_HMC_PD_BP_BUF_ALIGNMENT); + if (ret_code) + goto exit; + pd_entry->rsrc_pg = false; + } - pd_entry->bp.addr = mem; + pd_entry->bp.addr = *page; pd_entry->bp.sd_pd_index = pd_index; pd_entry->bp.entry_type = I40E_SD_TYPE_PAGED; /* Set page address and valid bit */ - page_desc = mem.pa | 0x1; + page_desc = page->pa | 0x1; pd_addr = (u64 *)pd_table->pd_page_addr.va; pd_addr += rel_pd_idx; @@ -240,7 +249,8 @@ i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, I40E_INVALIDATE_PF_HMC_PD(hw, sd_idx, idx); /* free memory here */ - ret_code = i40e_free_dma_mem(hw, &(pd_entry->bp.addr)); + if (!pd_entry->rsrc_pg) + ret_code = i40e_free_dma_mem(hw, &pd_entry->bp.addr); if (ret_code) goto exit; if (!pd_table->ref_cnt) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index 732a026603306..386416bf72674 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -62,6 +62,7 @@ struct i40e_hmc_bp { struct i40e_hmc_pd_entry { struct i40e_hmc_bp bp; u32 sd_index; + bool rsrc_pg; bool valid; }; @@ -218,7 +219,8 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, - u32 pd_index); + u32 pd_index, + struct i40e_dma_mem *rsrc_pg); i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, u32 idx); diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index 0079ad7bcd0e1..d399eaf5aad5d 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -387,7 +387,7 @@ static i40e_status i40e_create_lan_hmc_object(struct i40e_hw *hw, /* update the pd table entry */ ret_code = i40e_add_pd_table_entry(hw, info->hmc_info, - i); + i, NULL); if (ret_code) { pd_error = true; break; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h index 931c880443003..adc6f71f40a8c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h @@ -62,6 +62,7 @@ struct i40e_hmc_bp { struct i40e_hmc_pd_entry { struct i40e_hmc_bp bp; u32 sd_index; + bool rsrc_pg; bool valid; }; @@ -218,7 +219,8 @@ i40e_status i40e_add_sd_table_entry(struct i40e_hw *hw, i40e_status i40e_add_pd_table_entry(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, - u32 pd_index); + u32 pd_index, + struct i40e_dma_mem *rsrc_pg); i40e_status i40e_remove_pd_bp(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, u32 idx); -- GitLab From b2a75c5819ec910f430a2ff12fec6cce202899a0 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Mon, 27 Apr 2015 14:57:20 -0400 Subject: [PATCH 0854/7006] i40e: Refine an error message to avoid confusion Change a warning message to indicate what may have really happened when the init_shared_code call fails. Change-ID: I616ace40fed120d0dec86dfc91ab2d7cde466904 Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c7f2a0a74dcf9..9ec6fa292b20e 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -9767,7 +9767,8 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = i40e_init_shared_code(hw); if (err) { - dev_info(&pdev->dev, "init_shared_code failed: %d\n", err); + dev_warn(&pdev->dev, "unidentified MAC or BLANK NVM: %d\n", + err); goto err_pf_reset; } -- GitLab From 76945bf9ff8a2433f1efb777ec64475c1eec08ab Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Mon, 27 Apr 2015 14:57:22 -0400 Subject: [PATCH 0855/7006] i40e/i40evf: Bump version to 1.3.6 for i40e and 1.3.2 for i40evf Bump. Change-ID: I84573d9fa51effc5b29bf5b8c74e3cc8b2673f48 Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 9ec6fa292b20e..6ce9086e558a4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 4 +#define DRV_VERSION_BUILD 6 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 802e158ea981b..c698523923e4d 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -34,7 +34,7 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "1.2.25" +#define DRV_VERSION "1.3.2" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = "Copyright (c) 2013 - 2014 Intel Corporation."; -- GitLab From cd13f5ab42a63d267f452ac5fd641136c7b8f17c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 14 Jul 2015 14:12:02 +0200 Subject: [PATCH 0856/7006] drm/i915: fill in more mode members Fill in driver type, hsync, vrefresh and name. Those members are not read out but can be calculated from the mode. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4e64dae783608..cec0a6c4ef2a8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -7817,9 +7817,14 @@ void intel_mode_from_pipe_config(struct drm_display_mode *mode, mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end; mode->flags = pipe_config->base.adjusted_mode.flags; + mode->type = DRM_MODE_TYPE_DRIVER; mode->clock = pipe_config->base.adjusted_mode.crtc_clock; mode->flags |= pipe_config->base.adjusted_mode.flags; + + mode->hsync = drm_mode_hsync(mode); + mode->vrefresh = drm_mode_vrefresh(mode); + drm_mode_set_name(mode); } static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc) -- GitLab From 1f7457b135b075e7a60c9133723363045084c333 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 11:55:05 +0200 Subject: [PATCH 0857/7006] drm/i915: Fix noatomic crtc disabling, v2. This fixes the breakage caused by commit eddfcbcdc27fbecb33bff098967bbdd7ca75bfa6 Author: Maarten Lankhorst Date: Mon Jun 15 12:33:53 2015 +0200 drm/i915: Update less state during modeset. No need to repeatedly call update_watermarks, or update_fbc. Down to a single call to update_watermarks in .crtc_enable Signed-off-by: Maarten Lankhorst Reviewed-by: Matt Roper Tested-by(IVB): Matt Roper Signed-off-by: Daniel Vetter Add missing shared dpll disable to the noatomic disable function. This function will be replaced by its atomic counterpart soon. Changes since v1: - intel_crtc->active and watermarks are fixed by a patch from Patrik Jakobsson Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index cec0a6c4ef2a8..10a1726811384 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6214,6 +6214,7 @@ static void intel_crtc_disable_noatomic(struct drm_crtc *crtc) intel_crtc_disable_planes(crtc, crtc->state->plane_mask); dev_priv->display.crtc_disable(crtc); + intel_disable_shared_dpll(intel_crtc); domains = intel_crtc->enabled_power_domains; for_each_power_domain(domain, domains) -- GitLab From 346add7834557b5b9628b9bf2387106d42e631d4 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 14 Jul 2015 18:07:30 +0200 Subject: [PATCH 0858/7006] drm/i915: Use expcitly fixed type in compat32 structs I was confused shortly whether the compat was needed for the int, until I noticed the pointer in the original. Also remove typedef. v2: Review from Chris. - Add comments. - Also change the int param in the original structure. Cc: Chris Wilson Signed-off-by: Daniel Vetter Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_ioc32.c | 13 +++++++++---- include/uapi/drm/i915_drm.h | 6 +++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_ioc32.c b/drivers/gpu/drm/i915/i915_ioc32.c index 6eec2221b44e9..a5a2d5b3f44bc 100644 --- a/drivers/gpu/drm/i915/i915_ioc32.c +++ b/drivers/gpu/drm/i915/i915_ioc32.c @@ -35,15 +35,20 @@ #include #include "i915_drv.h" -typedef struct drm_i915_getparam32 { - int param; +struct drm_i915_getparam32 { + s32 param; + /* + * We screwed up the generic ioctl struct here and used a variable-sized + * pointer. Use u32 in the compat struct to match the 32bit pointer + * userspace expects. + */ u32 value; -} drm_i915_getparam32_t; +}; static int compat_i915_getparam(struct file *file, unsigned int cmd, unsigned long arg) { - drm_i915_getparam32_t req32; + struct drm_i915_getparam32 req32; drm_i915_getparam_t __user *request; if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index e7c29f1659ad1..192027b4f0314 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -358,7 +358,11 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_RESOURCE_STREAMER 36 typedef struct drm_i915_getparam { - int param; + s32 param; + /* + * WARNING: Using pointers instead of fixed-size u64 means we need to write + * compat32 code. Don't repeat this mistake. + */ int __user *value; } drm_i915_getparam_t; -- GitLab From 64793047558781330a1d13b159a2bc9385bdf97f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 15:38:14 +0800 Subject: [PATCH 0859/7006] ASoC: Constify snd_soc_dai_ops variables The snd_soc_dai_ops variables are not modified after initialization in these drivers, so make them const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l52.c | 2 +- sound/soc/codecs/cs42l56.c | 2 +- sound/soc/codecs/isabelle.c | 8 ++++---- sound/soc/codecs/lm49453.c | 10 +++++----- sound/soc/codecs/max98090.c | 2 +- sound/soc/codecs/max98357a.c | 2 +- sound/soc/codecs/mc13783.c | 6 +++--- sound/soc/codecs/rt5645.c | 2 +- sound/soc/codecs/rt5670.c | 2 +- sound/soc/codecs/rt5677.c | 2 +- sound/soc/codecs/si476x.c | 2 +- sound/soc/codecs/tas2552.c | 2 +- sound/soc/codecs/tlv320aic31xx.c | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9957ac5..c8f4af230ac06 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -919,7 +919,7 @@ static int cs42l52_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_U20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_U24_LE) -static struct snd_soc_dai_ops cs42l52_ops = { +static const struct snd_soc_dai_ops cs42l52_ops = { .hw_params = cs42l52_pcm_hw_params, .digital_mute = cs42l52_digital_mute, .set_fmt = cs42l52_set_fmt, diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 1e11ba45a79f0..22bc2f3460a55 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -989,7 +989,7 @@ static int cs42l56_set_bias_level(struct snd_soc_codec *codec, SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops cs42l56_ops = { +static const struct snd_soc_dai_ops cs42l56_ops = { .hw_params = cs42l56_pcm_hw_params, .digital_mute = cs42l56_digital_mute, .set_fmt = cs42l56_set_dai_fmt, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index ebd90283c9604..00dca1fdfcff8 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1016,25 +1016,25 @@ static int isabelle_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) #define ISABELLE_FORMATS (SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops isabelle_hs_dai_ops = { +static const struct snd_soc_dai_ops isabelle_hs_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, .digital_mute = isabelle_hs_mute, }; -static struct snd_soc_dai_ops isabelle_hf_dai_ops = { +static const struct snd_soc_dai_ops isabelle_hf_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, .digital_mute = isabelle_hf_mute, }; -static struct snd_soc_dai_ops isabelle_line_dai_ops = { +static const struct snd_soc_dai_ops isabelle_line_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, .digital_mute = isabelle_line_mute, }; -static struct snd_soc_dai_ops isabelle_ul_dai_ops = { +static const struct snd_soc_dai_ops isabelle_ul_dai_ops = { .hw_params = isabelle_hw_params, .set_fmt = isabelle_set_dai_fmt, }; diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0a33dc5..081d96d6df29f 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1291,35 +1291,35 @@ static int lm49453_set_bias_level(struct snd_soc_codec *codec, #define LM49453_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops lm49453_headset_dai_ops = { +static const struct snd_soc_dai_ops lm49453_headset_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_hp_mute, }; -static struct snd_soc_dai_ops lm49453_speaker_dai_ops = { +static const struct snd_soc_dai_ops lm49453_speaker_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_ls_mute, }; -static struct snd_soc_dai_ops lm49453_haptic_dai_ops = { +static const struct snd_soc_dai_ops lm49453_haptic_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_ha_mute, }; -static struct snd_soc_dai_ops lm49453_ep_dai_ops = { +static const struct snd_soc_dai_ops lm49453_ep_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, .digital_mute = lm49453_ep_mute, }; -static struct snd_soc_dai_ops lm49453_lineout_dai_ops = { +static const struct snd_soc_dai_ops lm49453_lineout_dai_ops = { .hw_params = lm49453_hw_params, .set_sysclk = lm49453_set_dai_sysclk, .set_fmt = lm49453_set_dai_fmt, diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f0514e95..b1b436f05ebe2 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2383,7 +2383,7 @@ EXPORT_SYMBOL_GPL(max98090_mic_detect); #define MAX98090_RATES SNDRV_PCM_RATE_8000_96000 #define MAX98090_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops max98090_dai_ops = { +static const struct snd_soc_dai_ops max98090_dai_ops = { .set_sysclk = max98090_dai_set_sysclk, .set_fmt = max98090_dai_set_fmt, .set_tdm_slot = max98090_set_tdm_slot, diff --git a/sound/soc/codecs/max98357a.c b/sound/soc/codecs/max98357a.c index 3a2fda08a893c..c4a211d3646c8 100644 --- a/sound/soc/codecs/max98357a.c +++ b/sound/soc/codecs/max98357a.c @@ -79,7 +79,7 @@ static struct snd_soc_codec_driver max98357a_codec_driver = { .num_dapm_routes = ARRAY_SIZE(max98357a_dapm_routes), }; -static struct snd_soc_dai_ops max98357a_dai_ops = { +static const struct snd_soc_dai_ops max98357a_dai_ops = { .trigger = max98357a_daiops_trigger, }; diff --git a/sound/soc/codecs/mc13783.c b/sound/soc/codecs/mc13783.c index 3d44fc50e4d0c..3e770cbe7f0f4 100644 --- a/sound/soc/codecs/mc13783.c +++ b/sound/soc/codecs/mc13783.c @@ -650,14 +650,14 @@ static int mc13783_remove(struct snd_soc_codec *codec) #define MC13783_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE) -static struct snd_soc_dai_ops mc13783_ops_dac = { +static const struct snd_soc_dai_ops mc13783_ops_dac = { .hw_params = mc13783_pcm_hw_params_dac, .set_fmt = mc13783_set_fmt_async, .set_sysclk = mc13783_set_sysclk_dac, .set_tdm_slot = mc13783_set_tdm_slot_dac, }; -static struct snd_soc_dai_ops mc13783_ops_codec = { +static const struct snd_soc_dai_ops mc13783_ops_codec = { .hw_params = mc13783_pcm_hw_params_codec, .set_fmt = mc13783_set_fmt_async, .set_sysclk = mc13783_set_sysclk_codec, @@ -698,7 +698,7 @@ static struct snd_soc_dai_driver mc13783_dai_async[] = { }, }; -static struct snd_soc_dai_ops mc13783_ops_sync = { +static const struct snd_soc_dai_ops mc13783_ops_sync = { .hw_params = mc13783_pcm_hw_params_sync, .set_fmt = mc13783_set_fmt_sync, .set_sysclk = mc13783_set_sysclk_sync, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc5..7c59326dce3e7 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3110,7 +3110,7 @@ static int rt5645_resume(struct snd_soc_codec *codec) #define RT5645_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5645_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5645_aif_dai_ops = { .hw_params = rt5645_hw_params, .set_fmt = rt5645_set_dai_fmt, .set_sysclk = rt5645_set_dai_sysclk, diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4141787..d583510ac026f 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -2720,7 +2720,7 @@ static int rt5670_resume(struct snd_soc_codec *codec) #define RT5670_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5670_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5670_aif_dai_ops = { .hw_params = rt5670_hw_params, .set_fmt = rt5670_set_dai_fmt, .set_sysclk = rt5670_set_dai_sysclk, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969ac11920..4b584f90eb919 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4863,7 +4863,7 @@ static int rt5677_write(void *context, unsigned int reg, unsigned int val) #define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8) -static struct snd_soc_dai_ops rt5677_aif_dai_ops = { +static const struct snd_soc_dai_ops rt5677_aif_dai_ops = { .hw_params = rt5677_hw_params, .set_fmt = rt5677_set_dai_fmt, .set_sysclk = rt5677_set_dai_sysclk, diff --git a/sound/soc/codecs/si476x.c b/sound/soc/codecs/si476x.c index 3e72964280c6e..a8402d0af0ea8 100644 --- a/sound/soc/codecs/si476x.c +++ b/sound/soc/codecs/si476x.c @@ -208,7 +208,7 @@ out: return err; } -static struct snd_soc_dai_ops si476x_dai_ops = { +static const struct snd_soc_dai_ops si476x_dai_ops = { .hw_params = si476x_codec_hw_params, .set_fmt = si476x_codec_set_dai_fmt, }; diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d0efa2a..d1552c308f778 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -520,7 +520,7 @@ static const struct dev_pm_ops tas2552_pm = { NULL) }; -static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { +static const struct snd_soc_dai_ops tas2552_speaker_dai_ops = { .hw_params = tas2552_hw_params, .prepare = tas2552_prepare, .set_sysclk = tas2552_set_dai_sysclk, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c4c960f592a1f..df01feca449f4 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1121,7 +1121,7 @@ static struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .num_dapm_routes = ARRAY_SIZE(aic31xx_audio_map), }; -static struct snd_soc_dai_ops aic31xx_dai_ops = { +static const struct snd_soc_dai_ops aic31xx_dai_ops = { .hw_params = aic31xx_hw_params, .set_sysclk = aic31xx_set_dai_sysclk, .set_fmt = aic31xx_set_dai_fmt, -- GitLab From a01da00cbccc162a86c78f61ed4ca55dad35440f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 09:51:33 +0800 Subject: [PATCH 0860/7006] ASoC: da732x: Merge da732x_dai1_ops and da732x_dai2_ops da732x_dai1_ops is identical to da732x_dai2_ops, so merge them to da732x_dai_ops. The da732x_dai_ops is not modified after initialization, so make it const. Signed-off-by: Axel Lin Acked-by: Adam Thomson Signed-off-by: Mark Brown --- sound/soc/codecs/da732x.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 207523686bd55..760935ac9fd92 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1196,13 +1196,7 @@ static int da732x_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, #define DA732X_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \ SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) -static struct snd_soc_dai_ops da732x_dai1_ops = { - .hw_params = da732x_hw_params, - .set_fmt = da732x_set_dai_fmt, - .set_sysclk = da732x_set_dai_sysclk, -}; - -static struct snd_soc_dai_ops da732x_dai2_ops = { +static const struct snd_soc_dai_ops da732x_dai_ops = { .hw_params = da732x_hw_params, .set_fmt = da732x_set_dai_fmt, .set_sysclk = da732x_set_dai_sysclk, @@ -1227,7 +1221,7 @@ static struct snd_soc_dai_driver da732x_dai[] = { .rates = DA732X_RATES, .formats = DA732X_FORMATS, }, - .ops = &da732x_dai1_ops, + .ops = &da732x_dai_ops, }, { .name = "DA732X_AIFB", @@ -1247,7 +1241,7 @@ static struct snd_soc_dai_driver da732x_dai[] = { .rates = DA732X_RATES, .formats = DA732X_FORMATS, }, - .ops = &da732x_dai2_ops, + .ops = &da732x_dai_ops, }, }; -- GitLab From 8e2175d42e435b7957bfaa921fc27cb40e923372 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 15 Jul 2015 13:50:49 +0800 Subject: [PATCH 0861/7006] ASoC: sirf-audio-codec: Staticise local symbols Also make sirf_audio_codec_dai_ops const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/sirf-audio-codec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c index 29cb44256044c..6bfd25c289d19 100644 --- a/sound/soc/codecs/sirf-audio-codec.c +++ b/sound/soc/codecs/sirf-audio-codec.c @@ -370,11 +370,11 @@ static int sirf_audio_codec_trigger(struct snd_pcm_substream *substream, return 0; } -struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { +static const struct snd_soc_dai_ops sirf_audio_codec_dai_ops = { .trigger = sirf_audio_codec_trigger, }; -struct snd_soc_dai_driver sirf_audio_codec_dai = { +static struct snd_soc_dai_driver sirf_audio_codec_dai = { .name = "sirf-audio-codec", .playback = { .stream_name = "Playback", -- GitLab From 1c07a4de5baad76585f7ffb86b5b0bc34c33e8a6 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Wed, 15 Jul 2015 13:21:44 +0900 Subject: [PATCH 0862/7006] ASoC: drivers: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/codecs/adau1373.c | 1 - sound/soc/codecs/adau1701.c | 1 - sound/soc/codecs/adau1761-i2c.c | 1 - sound/soc/codecs/adau1781-i2c.c | 1 - sound/soc/codecs/adau1977-i2c.c | 1 - sound/soc/codecs/adav803.c | 1 - sound/soc/codecs/ak4535.c | 1 - sound/soc/codecs/ak4641.c | 1 - sound/soc/codecs/ak4642.c | 1 - sound/soc/codecs/ak4671.c | 1 - sound/soc/codecs/alc5623.c | 1 - sound/soc/codecs/alc5632.c | 1 - sound/soc/codecs/cs35l32.c | 1 - sound/soc/codecs/cs4265.c | 1 - sound/soc/codecs/cs4270.c | 1 - sound/soc/codecs/cs4271-i2c.c | 1 - sound/soc/codecs/cs42l51-i2c.c | 1 - sound/soc/codecs/cs42l52.c | 1 - sound/soc/codecs/cs42l56.c | 1 - sound/soc/codecs/cs42l73.c | 1 - sound/soc/codecs/cs42xx8-i2c.c | 1 - sound/soc/codecs/da7210.c | 1 - sound/soc/codecs/da7213.c | 1 - sound/soc/codecs/da732x.c | 1 - sound/soc/codecs/da9055.c | 1 - sound/soc/codecs/isabelle.c | 1 - sound/soc/codecs/lm4857.c | 1 - sound/soc/codecs/lm49453.c | 1 - sound/soc/codecs/max9768.c | 1 - sound/soc/codecs/max98088.c | 1 - sound/soc/codecs/max98090.c | 1 - sound/soc/codecs/max98095.c | 1 - sound/soc/codecs/max9850.c | 1 - sound/soc/codecs/max9877.c | 1 - sound/soc/codecs/max98925.c | 1 - sound/soc/codecs/ml26124.c | 1 - sound/soc/codecs/pcm1681.c | 1 - sound/soc/codecs/pcm512x-i2c.c | 1 - sound/soc/codecs/rt286.c | 1 - sound/soc/codecs/rt298.c | 1 - sound/soc/codecs/rt5631.c | 1 - sound/soc/codecs/rt5640.c | 1 - sound/soc/codecs/rt5645.c | 1 - sound/soc/codecs/rt5651.c | 1 - sound/soc/codecs/rt5670.c | 1 - sound/soc/codecs/rt5677.c | 1 - sound/soc/codecs/sgtl5000.c | 1 - sound/soc/codecs/ssm2518.c | 1 - sound/soc/codecs/ssm2602-i2c.c | 1 - sound/soc/codecs/ssm4567.c | 1 - sound/soc/codecs/sta32x.c | 1 - sound/soc/codecs/sta350.c | 1 - sound/soc/codecs/sta529.c | 1 - sound/soc/codecs/tas2552.c | 1 - sound/soc/codecs/tas5086.c | 1 - sound/soc/codecs/tfa9879.c | 1 - sound/soc/codecs/tlv320aic31xx.c | 1 - sound/soc/codecs/tlv320aic32x4.c | 1 - sound/soc/codecs/tlv320aic3x.c | 1 - sound/soc/codecs/tlv320dac33.c | 1 - sound/soc/codecs/tpa6130a2.c | 1 - sound/soc/codecs/ts3a227e.c | 1 - sound/soc/codecs/uda1380.c | 1 - sound/soc/codecs/wm1250-ev1.c | 1 - sound/soc/codecs/wm2000.c | 1 - sound/soc/codecs/wm2200.c | 1 - sound/soc/codecs/wm5100.c | 1 - sound/soc/codecs/wm8510.c | 1 - sound/soc/codecs/wm8523.c | 1 - sound/soc/codecs/wm8580.c | 1 - sound/soc/codecs/wm8711.c | 1 - sound/soc/codecs/wm8728.c | 1 - sound/soc/codecs/wm8731.c | 1 - sound/soc/codecs/wm8737.c | 1 - sound/soc/codecs/wm8741.c | 1 - sound/soc/codecs/wm8750.c | 1 - sound/soc/codecs/wm8753.c | 1 - sound/soc/codecs/wm8776.c | 1 - sound/soc/codecs/wm8804-i2c.c | 1 - sound/soc/codecs/wm8900.c | 1 - sound/soc/codecs/wm8903.c | 1 - sound/soc/codecs/wm8904.c | 1 - sound/soc/codecs/wm8940.c | 1 - sound/soc/codecs/wm8955.c | 1 - sound/soc/codecs/wm8960.c | 1 - sound/soc/codecs/wm8961.c | 1 - sound/soc/codecs/wm8962.c | 1 - sound/soc/codecs/wm8971.c | 1 - sound/soc/codecs/wm8974.c | 1 - sound/soc/codecs/wm8978.c | 1 - sound/soc/codecs/wm8983.c | 1 - sound/soc/codecs/wm8985.c | 1 - sound/soc/codecs/wm8988.c | 1 - sound/soc/codecs/wm8990.c | 1 - sound/soc/codecs/wm8991.c | 1 - sound/soc/codecs/wm8993.c | 1 - sound/soc/codecs/wm8995.c | 1 - sound/soc/codecs/wm8996.c | 1 - sound/soc/codecs/wm9081.c | 1 - sound/soc/codecs/wm9090.c | 1 - 100 files changed, 100 deletions(-) diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c index a43160254929d..6c96860f46de6 100644 --- a/sound/soc/codecs/adau1373.c +++ b/sound/soc/codecs/adau1373.c @@ -1534,7 +1534,6 @@ MODULE_DEVICE_TABLE(i2c, adau1373_i2c_id); static struct i2c_driver adau1373_i2c_driver = { .driver = { .name = "adau1373", - .owner = THIS_MODULE, }, .probe = adau1373_i2c_probe, .remove = adau1373_i2c_remove, diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c index ff7f846e3b765..de53c0d7bf101 100644 --- a/sound/soc/codecs/adau1701.c +++ b/sound/soc/codecs/adau1701.c @@ -915,7 +915,6 @@ MODULE_DEVICE_TABLE(i2c, adau1701_i2c_id); static struct i2c_driver adau1701_i2c_driver = { .driver = { .name = "adau1701", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(adau1701_dt_ids), }, .probe = adau1701_i2c_probe, diff --git a/sound/soc/codecs/adau1761-i2c.c b/sound/soc/codecs/adau1761-i2c.c index 862796dec693b..348ccb17d3cc9 100644 --- a/sound/soc/codecs/adau1761-i2c.c +++ b/sound/soc/codecs/adau1761-i2c.c @@ -47,7 +47,6 @@ MODULE_DEVICE_TABLE(i2c, adau1761_i2c_ids); static struct i2c_driver adau1761_i2c_driver = { .driver = { .name = "adau1761", - .owner = THIS_MODULE, }, .probe = adau1761_i2c_probe, .remove = adau1761_i2c_remove, diff --git a/sound/soc/codecs/adau1781-i2c.c b/sound/soc/codecs/adau1781-i2c.c index 2ce4362ccec15..0e32bba92339b 100644 --- a/sound/soc/codecs/adau1781-i2c.c +++ b/sound/soc/codecs/adau1781-i2c.c @@ -45,7 +45,6 @@ MODULE_DEVICE_TABLE(i2c, adau1781_i2c_ids); static struct i2c_driver adau1781_i2c_driver = { .driver = { .name = "adau1781", - .owner = THIS_MODULE, }, .probe = adau1781_i2c_probe, .remove = adau1781_i2c_remove, diff --git a/sound/soc/codecs/adau1977-i2c.c b/sound/soc/codecs/adau1977-i2c.c index 9700e8c838c9d..21e7394a972ae 100644 --- a/sound/soc/codecs/adau1977-i2c.c +++ b/sound/soc/codecs/adau1977-i2c.c @@ -46,7 +46,6 @@ MODULE_DEVICE_TABLE(i2c, adau1977_i2c_ids); static struct i2c_driver adau1977_i2c_driver = { .driver = { .name = "adau1977", - .owner = THIS_MODULE, }, .probe = adau1977_i2c_probe, .remove = adau1977_i2c_remove, diff --git a/sound/soc/codecs/adav803.c b/sound/soc/codecs/adav803.c index 66d9fce34e625..52881faedcf61 100644 --- a/sound/soc/codecs/adav803.c +++ b/sound/soc/codecs/adav803.c @@ -36,7 +36,6 @@ static int adav803_remove(struct i2c_client *client) static struct i2c_driver adav803_driver = { .driver = { .name = "adav803", - .owner = THIS_MODULE, }, .probe = adav803_probe, .remove = adav803_remove, diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c index 8670861e5bec8..54428c64387bc 100644 --- a/sound/soc/codecs/ak4535.c +++ b/sound/soc/codecs/ak4535.c @@ -444,7 +444,6 @@ MODULE_DEVICE_TABLE(i2c, ak4535_i2c_id); static struct i2c_driver ak4535_i2c_driver = { .driver = { .name = "ak4535", - .owner = THIS_MODULE, }, .probe = ak4535_i2c_probe, .remove = ak4535_i2c_remove, diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c index 2d0ff4595ea00..b14176f8d884a 100644 --- a/sound/soc/codecs/ak4641.c +++ b/sound/soc/codecs/ak4641.c @@ -609,7 +609,6 @@ MODULE_DEVICE_TABLE(i2c, ak4641_i2c_id); static struct i2c_driver ak4641_i2c_driver = { .driver = { .name = "ak4641", - .owner = THIS_MODULE, }, .probe = ak4641_i2c_probe, .remove = ak4641_i2c_remove, diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 7c0f6552c229b..66352f70ac47f 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -626,7 +626,6 @@ MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id); static struct i2c_driver ak4642_i2c_driver = { .driver = { .name = "ak4642-codec", - .owner = THIS_MODULE, .of_match_table = ak4642_of_match, }, .probe = ak4642_i2c_probe, diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c index 0e59063aeb6f7..c73a9f6914b63 100644 --- a/sound/soc/codecs/ak4671.c +++ b/sound/soc/codecs/ak4671.c @@ -663,7 +663,6 @@ MODULE_DEVICE_TABLE(i2c, ak4671_i2c_id); static struct i2c_driver ak4671_i2c_driver = { .driver = { .name = "ak4671-codec", - .owner = THIS_MODULE, }, .probe = ak4671_i2c_probe, .remove = ak4671_i2c_remove, diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c index 0fc24e0d518c4..cf99c4e90acc3 100644 --- a/sound/soc/codecs/alc5623.c +++ b/sound/soc/codecs/alc5623.c @@ -1085,7 +1085,6 @@ MODULE_DEVICE_TABLE(of, alc5623_of_match); static struct i2c_driver alc5623_i2c_driver = { .driver = { .name = "alc562x-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(alc5623_of_match), }, .probe = alc5623_i2c_probe, diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c index 607a63b9705f9..9277ac68b6962 100644 --- a/sound/soc/codecs/alc5632.c +++ b/sound/soc/codecs/alc5632.c @@ -1183,7 +1183,6 @@ MODULE_DEVICE_TABLE(of, alc5632_of_match); static struct i2c_driver alc5632_i2c_driver = { .driver = { .name = "alc5632", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(alc5632_of_match), }, .probe = alc5632_i2c_probe, diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025b7e7ca..76564dc752d34 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -607,7 +607,6 @@ MODULE_DEVICE_TABLE(i2c, cs35l32_id); static struct i2c_driver cs35l32_i2c_driver = { .driver = { .name = "cs35l32", - .owner = THIS_MODULE, .pm = &cs35l32_runtime_pm, .of_match_table = cs35l32_of_match, }, diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d7ec4756e45bf..d1a77c7489d87 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -658,7 +658,6 @@ MODULE_DEVICE_TABLE(i2c, cs4265_id); static struct i2c_driver cs4265_i2c_driver = { .driver = { .name = "cs4265", - .owner = THIS_MODULE, .of_match_table = cs4265_of_match, }, .id_table = cs4265_id, diff --git a/sound/soc/codecs/cs4270.c b/sound/soc/codecs/cs4270.c index e6d4ff9fd9920..e07807d96b680 100644 --- a/sound/soc/codecs/cs4270.c +++ b/sound/soc/codecs/cs4270.c @@ -751,7 +751,6 @@ MODULE_DEVICE_TABLE(i2c, cs4270_id); static struct i2c_driver cs4270_i2c_driver = { .driver = { .name = "cs4270", - .owner = THIS_MODULE, .of_match_table = cs4270_of_match, }, .id_table = cs4270_id, diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c index b264da030340d..dcb3223d7d8f7 100644 --- a/sound/soc/codecs/cs4271-i2c.c +++ b/sound/soc/codecs/cs4271-i2c.c @@ -48,7 +48,6 @@ MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id); static struct i2c_driver cs4271_i2c_driver = { .driver = { .name = "cs4271", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(cs4271_dt_ids), }, .probe = cs4271_i2c_probe, diff --git a/sound/soc/codecs/cs42l51-i2c.c b/sound/soc/codecs/cs42l51-i2c.c index c40428f25ba5c..9bad478474fa3 100644 --- a/sound/soc/codecs/cs42l51-i2c.c +++ b/sound/soc/codecs/cs42l51-i2c.c @@ -45,7 +45,6 @@ static int cs42l51_i2c_remove(struct i2c_client *i2c) static struct i2c_driver cs42l51_i2c_driver = { .driver = { .name = "cs42l51", - .owner = THIS_MODULE, .of_match_table = cs42l51_of_match, }, .probe = cs42l51_i2c_probe, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9957ac5..b82d8e5b76ed9 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1285,7 +1285,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l52_id); static struct i2c_driver cs42l52_i2c_driver = { .driver = { .name = "cs42l52", - .owner = THIS_MODULE, .of_match_table = cs42l52_of_match, }, .id_table = cs42l52_id, diff --git a/sound/soc/codecs/cs42l56.c b/sound/soc/codecs/cs42l56.c index 1e11ba45a79f0..4ae7933659857 100644 --- a/sound/soc/codecs/cs42l56.c +++ b/sound/soc/codecs/cs42l56.c @@ -1408,7 +1408,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l56_id); static struct i2c_driver cs42l56_i2c_driver = { .driver = { .name = "cs42l56", - .owner = THIS_MODULE, .of_match_table = cs42l56_of_match, }, .id_table = cs42l56_id, diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index b7853b9d3a60b..7cb1d7091dae3 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1491,7 +1491,6 @@ MODULE_DEVICE_TABLE(i2c, cs42l73_id); static struct i2c_driver cs42l73_i2c_driver = { .driver = { .name = "cs42l73", - .owner = THIS_MODULE, .of_match_table = cs42l73_of_match, }, .id_table = cs42l73_id, diff --git a/sound/soc/codecs/cs42xx8-i2c.c b/sound/soc/codecs/cs42xx8-i2c.c index 5a71c9e5b4417..800c1d5493471 100644 --- a/sound/soc/codecs/cs42xx8-i2c.c +++ b/sound/soc/codecs/cs42xx8-i2c.c @@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(i2c, cs42xx8_i2c_id); static struct i2c_driver cs42xx8_i2c_driver = { .driver = { .name = "cs42xx8", - .owner = THIS_MODULE, .pm = &cs42xx8_pm, .of_match_table = cs42xx8_of_match, }, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5f3321c..9c7b41a8642d6 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1259,7 +1259,6 @@ MODULE_DEVICE_TABLE(i2c, da7210_i2c_id); static struct i2c_driver da7210_i2c_driver = { .driver = { .name = "da7210", - .owner = THIS_MODULE, }, .probe = da7210_i2c_probe, .remove = da7210_i2c_remove, diff --git a/sound/soc/codecs/da7213.c b/sound/soc/codecs/da7213.c index 238e48a3a4fe7..f635401b77300 100644 --- a/sound/soc/codecs/da7213.c +++ b/sound/soc/codecs/da7213.c @@ -1585,7 +1585,6 @@ MODULE_DEVICE_TABLE(i2c, da7213_i2c_id); static struct i2c_driver da7213_i2c_driver = { .driver = { .name = "da7213", - .owner = THIS_MODULE, }, .probe = da7213_i2c_probe, .remove = da7213_remove, diff --git a/sound/soc/codecs/da732x.c b/sound/soc/codecs/da732x.c index 207523686bd55..5446d047d2de3 100644 --- a/sound/soc/codecs/da732x.c +++ b/sound/soc/codecs/da732x.c @@ -1572,7 +1572,6 @@ MODULE_DEVICE_TABLE(i2c, da732x_i2c_id); static struct i2c_driver da732x_i2c_driver = { .driver = { .name = "da7320", - .owner = THIS_MODULE, }, .probe = da732x_i2c_probe, .remove = da732x_i2c_remove, diff --git a/sound/soc/codecs/da9055.c b/sound/soc/codecs/da9055.c index 66bb446473b86..7d5baa66b132b 100644 --- a/sound/soc/codecs/da9055.c +++ b/sound/soc/codecs/da9055.c @@ -1538,7 +1538,6 @@ static const struct of_device_id da9055_of_match[] = { static struct i2c_driver da9055_i2c_driver = { .driver = { .name = "da9055-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(da9055_of_match), }, .probe = da9055_i2c_probe, diff --git a/sound/soc/codecs/isabelle.c b/sound/soc/codecs/isabelle.c index ebd90283c9604..58a43b11eb7e7 100644 --- a/sound/soc/codecs/isabelle.c +++ b/sound/soc/codecs/isabelle.c @@ -1149,7 +1149,6 @@ MODULE_DEVICE_TABLE(i2c, isabelle_i2c_id); static struct i2c_driver isabelle_i2c_driver = { .driver = { .name = "isabelle", - .owner = THIS_MODULE, }, .probe = isabelle_i2c_probe, .remove = isabelle_i2c_remove, diff --git a/sound/soc/codecs/lm4857.c b/sound/soc/codecs/lm4857.c index 99ffc49aa7799..558de1053f73c 100644 --- a/sound/soc/codecs/lm4857.c +++ b/sound/soc/codecs/lm4857.c @@ -142,7 +142,6 @@ MODULE_DEVICE_TABLE(i2c, lm4857_i2c_id); static struct i2c_driver lm4857_i2c_driver = { .driver = { .name = "lm4857", - .owner = THIS_MODULE, }, .probe = lm4857_i2c_probe, .id_table = lm4857_i2c_id, diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c index 6600aa0a33dc5..9b2e38395eb92 100644 --- a/sound/soc/codecs/lm49453.c +++ b/sound/soc/codecs/lm49453.c @@ -1460,7 +1460,6 @@ MODULE_DEVICE_TABLE(i2c, lm49453_i2c_id); static struct i2c_driver lm49453_i2c_driver = { .driver = { .name = "lm49453", - .owner = THIS_MODULE, }, .probe = lm49453_i2c_probe, .remove = lm49453_i2c_remove, diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index e1c196a419303..1526aef2f2a9c 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -242,7 +242,6 @@ MODULE_DEVICE_TABLE(i2c, max9768_i2c_id); static struct i2c_driver max9768_i2c_driver = { .driver = { .name = "max9768", - .owner = THIS_MODULE, }, .probe = max9768_i2c_probe, .remove = max9768_i2c_remove, diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c index d0f45348bfbbc..99c2daa0eebfa 100644 --- a/sound/soc/codecs/max98088.c +++ b/sound/soc/codecs/max98088.c @@ -2011,7 +2011,6 @@ MODULE_DEVICE_TABLE(i2c, max98088_i2c_id); static struct i2c_driver max98088_i2c_driver = { .driver = { .name = "max98088", - .owner = THIS_MODULE, }, .probe = max98088_i2c_probe, .remove = max98088_i2c_remove, diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c index 78268f0514e95..c9db085e6cf10 100644 --- a/sound/soc/codecs/max98090.c +++ b/sound/soc/codecs/max98090.c @@ -2714,7 +2714,6 @@ MODULE_DEVICE_TABLE(acpi, max98090_acpi_match); static struct i2c_driver max98090_i2c_driver = { .driver = { .name = "max98090", - .owner = THIS_MODULE, .pm = &max98090_pm, .of_match_table = of_match_ptr(max98090_of_match), .acpi_match_table = ACPI_PTR(max98090_acpi_match), diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c index 9a46d3dcf7035..ea45c355d3243 100644 --- a/sound/soc/codecs/max98095.c +++ b/sound/soc/codecs/max98095.c @@ -2431,7 +2431,6 @@ MODULE_DEVICE_TABLE(of, max98095_of_match); static struct i2c_driver max98095_i2c_driver = { .driver = { .name = "max98095", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max98095_of_match), }, .probe = max98095_i2c_probe, diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c index 481d58f1cb3f6..7c990521638c6 100644 --- a/sound/soc/codecs/max9850.c +++ b/sound/soc/codecs/max9850.c @@ -352,7 +352,6 @@ MODULE_DEVICE_TABLE(i2c, max9850_i2c_id); static struct i2c_driver max9850_i2c_driver = { .driver = { .name = "max9850", - .owner = THIS_MODULE, }, .probe = max9850_i2c_probe, .remove = max9850_i2c_remove, diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index 29549cdbf4c1c..7692623ad5c37 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -174,7 +174,6 @@ MODULE_DEVICE_TABLE(i2c, max9877_i2c_id); static struct i2c_driver max9877_i2c_driver = { .driver = { .name = "max9877", - .owner = THIS_MODULE, }, .probe = max9877_i2c_probe, .remove = max9877_i2c_remove, diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index aad664225dc3a..ce551eecbf95f 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -639,7 +639,6 @@ MODULE_DEVICE_TABLE(of, max98925_of_match); static struct i2c_driver max98925_i2c_driver = { .driver = { .name = "max98925", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max98925_of_match), .pm = NULL, }, diff --git a/sound/soc/codecs/ml26124.c b/sound/soc/codecs/ml26124.c index b74118e019fbe..bda2bd751be4f 100644 --- a/sound/soc/codecs/ml26124.c +++ b/sound/soc/codecs/ml26124.c @@ -597,7 +597,6 @@ MODULE_DEVICE_TABLE(i2c, ml26124_i2c_id); static struct i2c_driver ml26124_i2c_driver = { .driver = { .name = "ml26124", - .owner = THIS_MODULE, }, .probe = ml26124_i2c_probe, .remove = ml26124_i2c_remove, diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index 477e13d309713..b2c990f08aa39 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -330,7 +330,6 @@ static int pcm1681_i2c_remove(struct i2c_client *client) static struct i2c_driver pcm1681_i2c_driver = { .driver = { .name = "pcm1681", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcm1681_dt_ids), }, .id_table = pcm1681_i2c_id, diff --git a/sound/soc/codecs/pcm512x-i2c.c b/sound/soc/codecs/pcm512x-i2c.c index dcdfac0ffeb15..dbff416e38be7 100644 --- a/sound/soc/codecs/pcm512x-i2c.c +++ b/sound/soc/codecs/pcm512x-i2c.c @@ -67,7 +67,6 @@ static struct i2c_driver pcm512x_i2c_driver = { .id_table = pcm512x_i2c_id, .driver = { .name = "pcm512x", - .owner = THIS_MODULE, .of_match_table = pcm512x_of_match, .pm = &pcm512x_pm_ops, }, diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 5c43e263b2c1f..83029e4613095 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c @@ -1259,7 +1259,6 @@ static int rt286_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt286_i2c_driver = { .driver = { .name = "rt286", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt286_acpi_match), }, .probe = rt286_i2c_probe, diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 7c4bcb65ef2c8..75e5679dfef8f 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1259,7 +1259,6 @@ static int rt298_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt298_i2c_driver = { .driver = { .name = "rt298", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt298_acpi_match), }, .probe = rt298_i2c_probe, diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c index 058167c80d714..d8771020299da 100644 --- a/sound/soc/codecs/rt5631.c +++ b/sound/soc/codecs/rt5631.c @@ -1725,7 +1725,6 @@ static int rt5631_i2c_remove(struct i2c_client *client) static struct i2c_driver rt5631_i2c_driver = { .driver = { .name = "rt5631", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rt5631_i2c_dt_ids), }, .probe = rt5631_i2c_probe, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e57513d7..4a780efdd7285 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -2242,7 +2242,6 @@ static int rt5640_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5640_i2c_driver = { .driver = { .name = "rt5640", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt5640_acpi_match), .of_match_table = of_match_ptr(rt5640_of_match), }, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc5..23a7e8d61429d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3459,7 +3459,6 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, .probe = rt5645_i2c_probe, diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e193abcd..872121015dfc3 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -1806,7 +1806,6 @@ static int rt5651_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5651_i2c_driver = { .driver = { .name = "rt5651", - .owner = THIS_MODULE, }, .probe = rt5651_i2c_probe, .remove = rt5651_i2c_remove, diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4141787..8f9ab2b493ec2 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -3043,7 +3043,6 @@ static int rt5670_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5670_i2c_driver = { .driver = { .name = "rt5670", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(rt5670_acpi_match), }, .probe = rt5670_i2c_probe, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969ac11920..03afec78a1700 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -5273,7 +5273,6 @@ static int rt5677_i2c_remove(struct i2c_client *i2c) static struct i2c_driver rt5677_i2c_driver = { .driver = { .name = "rt5677", - .owner = THIS_MODULE, }, .probe = rt5677_i2c_probe, .remove = rt5677_i2c_remove, diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c index e673f6ceb5213..f3e646757215e 100644 --- a/sound/soc/codecs/sgtl5000.c +++ b/sound/soc/codecs/sgtl5000.c @@ -1601,7 +1601,6 @@ MODULE_DEVICE_TABLE(of, sgtl5000_dt_ids); static struct i2c_driver sgtl5000_i2c_driver = { .driver = { .name = "sgtl5000", - .owner = THIS_MODULE, .of_match_table = sgtl5000_dt_ids, }, .probe = sgtl5000_i2c_probe, diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index f30de7639bb9c..5d94d6c7ad33b 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c @@ -815,7 +815,6 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids); static struct i2c_driver ssm2518_driver = { .driver = { .name = "ssm2518", - .owner = THIS_MODULE, }, .probe = ssm2518_i2c_probe, .remove = ssm2518_i2c_remove, diff --git a/sound/soc/codecs/ssm2602-i2c.c b/sound/soc/codecs/ssm2602-i2c.c index 0d9779d6bfda7..173ba85ff59e4 100644 --- a/sound/soc/codecs/ssm2602-i2c.c +++ b/sound/soc/codecs/ssm2602-i2c.c @@ -52,7 +52,6 @@ MODULE_DEVICE_TABLE(of, ssm2602_of_match); static struct i2c_driver ssm2602_i2c_driver = { .driver = { .name = "ssm2602", - .owner = THIS_MODULE, .of_match_table = ssm2602_of_match, }, .probe = ssm2602_i2c_probe, diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 938d2cb6d78be..f3f1f6874c724 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -453,7 +453,6 @@ MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); static struct i2c_driver ssm4567_driver = { .driver = { .name = "ssm4567", - .owner = THIS_MODULE, }, .probe = ssm4567_i2c_probe, .remove = ssm4567_i2c_remove, diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c index 60eff36260cbd..a9844b2ac829d 100644 --- a/sound/soc/codecs/sta32x.c +++ b/sound/soc/codecs/sta32x.c @@ -1144,7 +1144,6 @@ MODULE_DEVICE_TABLE(i2c, sta32x_i2c_id); static struct i2c_driver sta32x_i2c_driver = { .driver = { .name = "sta32x", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st32x_dt_ids), }, .probe = sta32x_i2c_probe, diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c index bd819a3f205ae..33a4612f0a078 100644 --- a/sound/soc/codecs/sta350.c +++ b/sound/soc/codecs/sta350.c @@ -1264,7 +1264,6 @@ MODULE_DEVICE_TABLE(i2c, sta350_i2c_id); static struct i2c_driver sta350_i2c_driver = { .driver = { .name = "sta350", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st350_dt_ids), }, .probe = sta350_i2c_probe, diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 4f70378b2cfb4..3430f444c1aee 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -379,7 +379,6 @@ MODULE_DEVICE_TABLE(i2c, sta529_i2c_id); static struct i2c_driver sta529_i2c_driver = { .driver = { .name = "sta529", - .owner = THIS_MODULE, }, .probe = sta529_i2c_probe, .remove = sta529_i2c_remove, diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c index 4f25a7d0efa2a..083b6b3e6cd29 100644 --- a/sound/soc/codecs/tas2552.c +++ b/sound/soc/codecs/tas2552.c @@ -769,7 +769,6 @@ MODULE_DEVICE_TABLE(of, tas2552_of_match); static struct i2c_driver tas2552_i2c_driver = { .driver = { .name = "tas2552", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tas2552_of_match), .pm = &tas2552_pm, }, diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 32942bed34b1e..0a49fc851577f 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -994,7 +994,6 @@ static int tas5086_i2c_remove(struct i2c_client *i2c) static struct i2c_driver tas5086_i2c_driver = { .driver = { .name = "tas5086", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tas5086_dt_ids), }, .id_table = tas5086_i2c_id, diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c index aab0af681e8cb..86d05f01e5f99 100644 --- a/sound/soc/codecs/tfa9879.c +++ b/sound/soc/codecs/tfa9879.c @@ -314,7 +314,6 @@ MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id); static struct i2c_driver tfa9879_i2c_driver = { .driver = { .name = "tfa9879", - .owner = THIS_MODULE, }, .probe = tfa9879_i2c_probe, .remove = tfa9879_i2c_remove, diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index c4c960f592a1f..48dd9b2cd0fa7 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1283,7 +1283,6 @@ MODULE_DEVICE_TABLE(i2c, aic31xx_i2c_id); static struct i2c_driver aic31xx_i2c_driver = { .driver = { .name = "tlv320aic31xx-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tlv320aic31xx_of_match), }, .probe = aic31xx_i2c_probe, diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index ad6cb90e5f9b3..f2d3191961e14 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -871,7 +871,6 @@ MODULE_DEVICE_TABLE(of, aic32x4_of_id); static struct i2c_driver aic32x4_i2c_driver = { .driver = { .name = "tlv320aic32x4", - .owner = THIS_MODULE, .of_match_table = aic32x4_of_id, }, .probe = aic32x4_i2c_probe, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index a7cf19b53fb2d..125a93517cdb4 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1825,7 +1825,6 @@ MODULE_DEVICE_TABLE(of, tlv320aic3x_of_match); static struct i2c_driver aic3x_i2c_driver = { .driver = { .name = "tlv320aic3x-codec", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tlv320aic3x_of_match), }, .probe = aic3x_i2c_probe, diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index d67a311f0e750..781398fb28415 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -1585,7 +1585,6 @@ MODULE_DEVICE_TABLE(i2c, tlv320dac33_i2c_id); static struct i2c_driver tlv320dac33_i2c_driver = { .driver = { .name = "tlv320dac33-codec", - .owner = THIS_MODULE, }, .probe = dac33_i2c_probe, .remove = dac33_i2c_remove, diff --git a/sound/soc/codecs/tpa6130a2.c b/sound/soc/codecs/tpa6130a2.c index 6fac9e034c483..265c4c38804d9 100644 --- a/sound/soc/codecs/tpa6130a2.c +++ b/sound/soc/codecs/tpa6130a2.c @@ -488,7 +488,6 @@ MODULE_DEVICE_TABLE(of, tpa6130a2_of_match); static struct i2c_driver tpa6130a2_i2c_driver = { .driver = { .name = "tpa6130a2", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tpa6130a2_of_match), }, .probe = tpa6130a2_probe, diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c index ffc6f3028cc54..43568435c208f 100644 --- a/sound/soc/codecs/ts3a227e.c +++ b/sound/soc/codecs/ts3a227e.c @@ -377,7 +377,6 @@ MODULE_DEVICE_TABLE(of, ts3a227e_of_match); static struct i2c_driver ts3a227e_driver = { .driver = { .name = "ts3a227e", - .owner = THIS_MODULE, .pm = &ts3a227e_pm, .of_match_table = of_match_ptr(ts3a227e_of_match), }, diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 6e159f59d219b..5cafb16ccf1a3 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -810,7 +810,6 @@ MODULE_DEVICE_TABLE(i2c, uda1380_i2c_id); static struct i2c_driver uda1380_i2c_driver = { .driver = { .name = "uda1380-codec", - .owner = THIS_MODULE, }, .probe = uda1380_i2c_probe, .remove = uda1380_i2c_remove, diff --git a/sound/soc/codecs/wm1250-ev1.c b/sound/soc/codecs/wm1250-ev1.c index 048f00568260a..ec45c5b220b10 100644 --- a/sound/soc/codecs/wm1250-ev1.c +++ b/sound/soc/codecs/wm1250-ev1.c @@ -251,7 +251,6 @@ MODULE_DEVICE_TABLE(i2c, wm1250_ev1_i2c_id); static struct i2c_driver wm1250_ev1_i2c_driver = { .driver = { .name = "wm1250-ev1", - .owner = THIS_MODULE, }, .probe = wm1250_ev1_probe, .remove = wm1250_ev1_remove, diff --git a/sound/soc/codecs/wm2000.c b/sound/soc/codecs/wm2000.c index 21d5402e343fb..786abd02b1406 100644 --- a/sound/soc/codecs/wm2000.c +++ b/sound/soc/codecs/wm2000.c @@ -942,7 +942,6 @@ MODULE_DEVICE_TABLE(i2c, wm2000_i2c_id); static struct i2c_driver wm2000_i2c_driver = { .driver = { .name = "wm2000", - .owner = THIS_MODULE, }, .probe = wm2000_i2c_probe, .remove = wm2000_i2c_remove, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c83083285e532..d4fa224d68b18 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2495,7 +2495,6 @@ MODULE_DEVICE_TABLE(i2c, wm2200_i2c_id); static struct i2c_driver wm2200_i2c_driver = { .driver = { .name = "wm2200", - .owner = THIS_MODULE, .pm = &wm2200_pm, }, .probe = wm2200_i2c_probe, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd88c1af6..b9594d6feb71b 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2722,7 +2722,6 @@ MODULE_DEVICE_TABLE(i2c, wm5100_i2c_id); static struct i2c_driver wm5100_i2c_driver = { .driver = { .name = "wm5100", - .owner = THIS_MODULE, .pm = &wm5100_pm, }, .probe = wm5100_i2c_probe, diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c index dac5beb4d0235..3cff5a699e574 100644 --- a/sound/soc/codecs/wm8510.c +++ b/sound/soc/codecs/wm8510.c @@ -690,7 +690,6 @@ MODULE_DEVICE_TABLE(i2c, wm8510_i2c_id); static struct i2c_driver wm8510_i2c_driver = { .driver = { .name = "wm8510", - .owner = THIS_MODULE, .of_match_table = wm8510_of_match, }, .probe = wm8510_i2c_probe, diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c index 43ea8ae5f871d..5f8fde56e68b4 100644 --- a/sound/soc/codecs/wm8523.c +++ b/sound/soc/codecs/wm8523.c @@ -534,7 +534,6 @@ MODULE_DEVICE_TABLE(i2c, wm8523_i2c_id); static struct i2c_driver wm8523_i2c_driver = { .driver = { .name = "wm8523", - .owner = THIS_MODULE, .of_match_table = wm8523_of_match, }, .probe = wm8523_i2c_probe, diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c index 759a7928ac3ee..abf60355f7f74 100644 --- a/sound/soc/codecs/wm8580.c +++ b/sound/soc/codecs/wm8580.c @@ -978,7 +978,6 @@ MODULE_DEVICE_TABLE(i2c, wm8580_i2c_id); static struct i2c_driver wm8580_i2c_driver = { .driver = { .name = "wm8580", - .owner = THIS_MODULE, .of_match_table = wm8580_of_match, }, .probe = wm8580_i2c_probe, diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index cc8251f09f8ab..44b9e0ae74518 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c @@ -478,7 +478,6 @@ MODULE_DEVICE_TABLE(i2c, wm8711_i2c_id); static struct i2c_driver wm8711_i2c_driver = { .driver = { .name = "wm8711", - .owner = THIS_MODULE, .of_match_table = wm8711_of_match, }, .probe = wm8711_i2c_probe, diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c index f1a173e6ec33b..cd7b02413ccf2 100644 --- a/sound/soc/codecs/wm8728.c +++ b/sound/soc/codecs/wm8728.c @@ -319,7 +319,6 @@ MODULE_DEVICE_TABLE(i2c, wm8728_i2c_id); static struct i2c_driver wm8728_i2c_driver = { .driver = { .name = "wm8728", - .owner = THIS_MODULE, .of_match_table = wm8728_of_match, }, .probe = wm8728_i2c_probe, diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c index 915ea11ad4b63..4846842522f30 100644 --- a/sound/soc/codecs/wm8731.c +++ b/sound/soc/codecs/wm8731.c @@ -789,7 +789,6 @@ MODULE_DEVICE_TABLE(i2c, wm8731_i2c_id); static struct i2c_driver wm8731_i2c_driver = { .driver = { .name = "wm8731", - .owner = THIS_MODULE, .of_match_table = wm8731_of_match, }, .probe = wm8731_i2c_probe, diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c index 6ad606fd8b690..b54a7b78f5621 100644 --- a/sound/soc/codecs/wm8737.c +++ b/sound/soc/codecs/wm8737.c @@ -657,7 +657,6 @@ MODULE_DEVICE_TABLE(i2c, wm8737_i2c_id); static struct i2c_driver wm8737_i2c_driver = { .driver = { .name = "wm8737", - .owner = THIS_MODULE, .of_match_table = wm8737_of_match, }, .probe = wm8737_i2c_probe, diff --git a/sound/soc/codecs/wm8741.c b/sound/soc/codecs/wm8741.c index b34623786e35d..430fa7ded7134 100644 --- a/sound/soc/codecs/wm8741.c +++ b/sound/soc/codecs/wm8741.c @@ -633,7 +633,6 @@ MODULE_DEVICE_TABLE(i2c, wm8741_i2c_id); static struct i2c_driver wm8741_i2c_driver = { .driver = { .name = "wm8741", - .owner = THIS_MODULE, .of_match_table = wm8741_of_match, }, .probe = wm8741_i2c_probe, diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c index 56d89b0865fa6..873933a7966f9 100644 --- a/sound/soc/codecs/wm8750.c +++ b/sound/soc/codecs/wm8750.c @@ -826,7 +826,6 @@ MODULE_DEVICE_TABLE(i2c, wm8750_i2c_id); static struct i2c_driver wm8750_i2c_driver = { .driver = { .name = "wm8750", - .owner = THIS_MODULE, .of_match_table = wm8750_of_match, }, .probe = wm8750_i2c_probe, diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index feb2997a377aa..b5e50ffbf99f1 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c @@ -1609,7 +1609,6 @@ MODULE_DEVICE_TABLE(i2c, wm8753_i2c_id); static struct i2c_driver wm8753_i2c_driver = { .driver = { .name = "wm8753", - .owner = THIS_MODULE, .of_match_table = wm8753_of_match, }, .probe = wm8753_i2c_probe, diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ece9b44567676..592866dd60c78 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -536,7 +536,6 @@ MODULE_DEVICE_TABLE(i2c, wm8776_i2c_id); static struct i2c_driver wm8776_i2c_driver = { .driver = { .name = "wm8776", - .owner = THIS_MODULE, .of_match_table = wm8776_of_match, }, .probe = wm8776_i2c_probe, diff --git a/sound/soc/codecs/wm8804-i2c.c b/sound/soc/codecs/wm8804-i2c.c index 6596f5f3a0c35..f27464c2c5bad 100644 --- a/sound/soc/codecs/wm8804-i2c.c +++ b/sound/soc/codecs/wm8804-i2c.c @@ -49,7 +49,6 @@ MODULE_DEVICE_TABLE(of, wm8804_of_match); static struct i2c_driver wm8804_i2c_driver = { .driver = { .name = "wm8804", - .owner = THIS_MODULE, .pm = &wm8804_pm, .of_match_table = wm8804_of_match, }, diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c index f3759ec5a8638..98900aa66dc30 100644 --- a/sound/soc/codecs/wm8900.c +++ b/sound/soc/codecs/wm8900.c @@ -1312,7 +1312,6 @@ MODULE_DEVICE_TABLE(i2c, wm8900_i2c_id); static struct i2c_driver wm8900_i2c_driver = { .driver = { .name = "wm8900", - .owner = THIS_MODULE, }, .probe = wm8900_i2c_probe, .remove = wm8900_i2c_remove, diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index b5322c1544fba..b011253459af9 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -2193,7 +2193,6 @@ MODULE_DEVICE_TABLE(i2c, wm8903_i2c_id); static struct i2c_driver wm8903_i2c_driver = { .driver = { .name = "wm8903", - .owner = THIS_MODULE, .of_match_table = wm8903_of_match, }, .probe = wm8903_i2c_probe, diff --git a/sound/soc/codecs/wm8904.c b/sound/soc/codecs/wm8904.c index 265a4a58a2d1b..145f5f9d581bb 100644 --- a/sound/soc/codecs/wm8904.c +++ b/sound/soc/codecs/wm8904.c @@ -2292,7 +2292,6 @@ MODULE_DEVICE_TABLE(i2c, wm8904_i2c_id); static struct i2c_driver wm8904_i2c_driver = { .driver = { .name = "wm8904", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(wm8904_of_match), }, .probe = wm8904_i2c_probe, diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c index 98ef0ba5c2a45..f6f9395ea38ef 100644 --- a/sound/soc/codecs/wm8940.c +++ b/sound/soc/codecs/wm8940.c @@ -787,7 +787,6 @@ MODULE_DEVICE_TABLE(i2c, wm8940_i2c_id); static struct i2c_driver wm8940_i2c_driver = { .driver = { .name = "wm8940", - .owner = THIS_MODULE, }, .probe = wm8940_i2c_probe, .remove = wm8940_i2c_remove, diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c index 2d591c24704be..12e4435f00f85 100644 --- a/sound/soc/codecs/wm8955.c +++ b/sound/soc/codecs/wm8955.c @@ -1009,7 +1009,6 @@ MODULE_DEVICE_TABLE(i2c, wm8955_i2c_id); static struct i2c_driver wm8955_i2c_driver = { .driver = { .name = "wm8955", - .owner = THIS_MODULE, }, .probe = wm8955_i2c_probe, .remove = wm8955_i2c_remove, diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 94c5c4681ce5c..1ed0720b41f0b 100644 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -1216,7 +1216,6 @@ MODULE_DEVICE_TABLE(of, wm8960_of_match); static struct i2c_driver wm8960_i2c_driver = { .driver = { .name = "wm8960", - .owner = THIS_MODULE, .of_match_table = wm8960_of_match, }, .probe = wm8960_i2c_probe, diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c index a057662632ffa..20a010344fd55 100644 --- a/sound/soc/codecs/wm8961.c +++ b/sound/soc/codecs/wm8961.c @@ -982,7 +982,6 @@ MODULE_DEVICE_TABLE(i2c, wm8961_i2c_id); static struct i2c_driver wm8961_i2c_driver = { .driver = { .name = "wm8961", - .owner = THIS_MODULE, }, .probe = wm8961_i2c_probe, .remove = wm8961_i2c_remove, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd4f2962..40c4617e3ef19 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3878,7 +3878,6 @@ MODULE_DEVICE_TABLE(of, wm8962_of_match); static struct i2c_driver wm8962_i2c_driver = { .driver = { .name = "wm8962", - .owner = THIS_MODULE, .of_match_table = wm8962_of_match, .pm = &wm8962_pm, }, diff --git a/sound/soc/codecs/wm8971.c b/sound/soc/codecs/wm8971.c index b51184c4e8163..2cdde32c43c63 100644 --- a/sound/soc/codecs/wm8971.c +++ b/sound/soc/codecs/wm8971.c @@ -710,7 +710,6 @@ MODULE_DEVICE_TABLE(i2c, wm8971_i2c_id); static struct i2c_driver wm8971_i2c_driver = { .driver = { .name = "wm8971", - .owner = THIS_MODULE, }, .probe = wm8971_i2c_probe, .remove = wm8971_i2c_remove, diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c index 33b16a7ba82ef..0a60677397b3d 100644 --- a/sound/soc/codecs/wm8974.c +++ b/sound/soc/codecs/wm8974.c @@ -634,7 +634,6 @@ MODULE_DEVICE_TABLE(i2c, wm8974_i2c_id); static struct i2c_driver wm8974_i2c_driver = { .driver = { .name = "wm8974", - .owner = THIS_MODULE, }, .probe = wm8974_i2c_probe, .remove = wm8974_i2c_remove, diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c index cfc8cdf499707..d36d6001fbb7e 100644 --- a/sound/soc/codecs/wm8978.c +++ b/sound/soc/codecs/wm8978.c @@ -1072,7 +1072,6 @@ MODULE_DEVICE_TABLE(i2c, wm8978_i2c_id); static struct i2c_driver wm8978_i2c_driver = { .driver = { .name = "wm8978", - .owner = THIS_MODULE, }, .probe = wm8978_i2c_probe, .remove = wm8978_i2c_remove, diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c index 2fdd2c6cc09d3..f6861cc4c3217 100644 --- a/sound/soc/codecs/wm8983.c +++ b/sound/soc/codecs/wm8983.c @@ -1133,7 +1133,6 @@ MODULE_DEVICE_TABLE(i2c, wm8983_i2c_id); static struct i2c_driver wm8983_i2c_driver = { .driver = { .name = "wm8983", - .owner = THIS_MODULE, }, .probe = wm8983_i2c_probe, .remove = wm8983_i2c_remove, diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c index 8a85f5004d41c..9c3c1517a4f3a 100644 --- a/sound/soc/codecs/wm8985.c +++ b/sound/soc/codecs/wm8985.c @@ -1144,7 +1144,6 @@ MODULE_DEVICE_TABLE(i2c, wm8985_i2c_id); static struct i2c_driver wm8985_i2c_driver = { .driver = { .name = "wm8985", - .owner = THIS_MODULE, }, .probe = wm8985_i2c_probe, .remove = wm8985_i2c_remove, diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c index f13a995af2773..c88ce99ce9e17 100644 --- a/sound/soc/codecs/wm8988.c +++ b/sound/soc/codecs/wm8988.c @@ -919,7 +919,6 @@ MODULE_DEVICE_TABLE(i2c, wm8988_i2c_id); static struct i2c_driver wm8988_i2c_driver = { .driver = { .name = "wm8988", - .owner = THIS_MODULE, }, .probe = wm8988_i2c_probe, .remove = wm8988_i2c_remove, diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index 1993fd2a6f15b..83d72d8bc51be 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -1356,7 +1356,6 @@ MODULE_DEVICE_TABLE(i2c, wm8990_i2c_id); static struct i2c_driver wm8990_i2c_driver = { .driver = { .name = "wm8990", - .owner = THIS_MODULE, }, .probe = wm8990_i2c_probe, .remove = wm8990_i2c_remove, diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c index 44a677720828e..709d16e338d9a 100644 --- a/sound/soc/codecs/wm8991.c +++ b/sound/soc/codecs/wm8991.c @@ -1363,7 +1363,6 @@ MODULE_DEVICE_TABLE(i2c, wm8991_i2c_id); static struct i2c_driver wm8991_i2c_driver = { .driver = { .name = "wm8991", - .owner = THIS_MODULE, }, .probe = wm8991_i2c_probe, .remove = wm8991_i2c_remove, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db8605dc2e..3f4dfb95d2d7a 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1742,7 +1742,6 @@ MODULE_DEVICE_TABLE(i2c, wm8993_i2c_id); static struct i2c_driver wm8993_i2c_driver = { .driver = { .name = "wm8993", - .owner = THIS_MODULE, }, .probe = wm8993_i2c_probe, .remove = wm8993_i2c_remove, diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c index 505b65f5734f1..eda52a96c1fa5 100644 --- a/sound/soc/codecs/wm8995.c +++ b/sound/soc/codecs/wm8995.c @@ -2298,7 +2298,6 @@ MODULE_DEVICE_TABLE(i2c, wm8995_i2c_id); static struct i2c_driver wm8995_i2c_driver = { .driver = { .name = "wm8995", - .owner = THIS_MODULE, }, .probe = wm8995_i2c_probe, .remove = wm8995_i2c_remove, diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f682b29..29b6688fb6ee2 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -3100,7 +3100,6 @@ MODULE_DEVICE_TABLE(i2c, wm8996_i2c_id); static struct i2c_driver wm8996_i2c_driver = { .driver = { .name = "wm8996", - .owner = THIS_MODULE, }, .probe = wm8996_i2c_probe, .remove = wm8996_i2c_remove, diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c index 8a8b1c0f91421..011516eec4b5b 100644 --- a/sound/soc/codecs/wm9081.c +++ b/sound/soc/codecs/wm9081.c @@ -1378,7 +1378,6 @@ MODULE_DEVICE_TABLE(i2c, wm9081_i2c_id); static struct i2c_driver wm9081_i2c_driver = { .driver = { .name = "wm9081", - .owner = THIS_MODULE, }, .probe = wm9081_i2c_probe, .remove = wm9081_i2c_remove, diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c index 13d23fc797dbb..12baf725d4a57 100644 --- a/sound/soc/codecs/wm9090.c +++ b/sound/soc/codecs/wm9090.c @@ -636,7 +636,6 @@ MODULE_DEVICE_TABLE(i2c, wm9090_id); static struct i2c_driver wm9090_i2c_driver = { .driver = { .name = "wm9090", - .owner = THIS_MODULE, }, .probe = wm9090_i2c_probe, .remove = wm9090_i2c_remove, -- GitLab From ec081cb337a1edc793d7aa53baa9b8afa096678d Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jul 2015 19:25:42 +0900 Subject: [PATCH 0863/7006] drm: Fix warning with make xmldocs caused by drm_irq.c This patch fix following warnings. Warning(.//drivers/gpu/drm/drm_irq.c:1279): No description found for parameter drm_crtc' Warning(.//drivers/gpu/drm/drm_irq.c:1279): Excess function parameter 'crtc' description in 'drm_crtc_vblank_reset' Signed-off-by: Masanari Iida Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c index f9cc68fbd2a3e..9fd784b8966b9 100644 --- a/drivers/gpu/drm/drm_irq.c +++ b/drivers/gpu/drm/drm_irq.c @@ -1267,7 +1267,7 @@ EXPORT_SYMBOL(drm_crtc_vblank_off); /** * drm_crtc_vblank_reset - reset vblank state to off on a CRTC - * @crtc: CRTC in question + * @drm_crtc: CRTC in question * * Drivers can use this function to reset the vblank state to off at load time. * Drivers should use this together with the drm_crtc_vblank_off() and -- GitLab From 6381b55016ec76f18cbc8685ca0774dd4584651b Mon Sep 17 00:00:00 2001 From: Nick Hoath Date: Tue, 14 Jul 2015 14:41:15 +0100 Subject: [PATCH 0864/7006] drm/i915/gen9: Implement WaDisableKillLogic for gen 9 v2: Patch leakage fixed Signed-off-by: Nick Hoath Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_pm.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 97794bc753f27..ef5f69a1607f2 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -160,6 +160,7 @@ #define GAM_ECOCHK 0x4090 #define BDW_DISABLE_HDC_INVALIDATION (1<<25) #define ECOCHK_SNB_BIT (1<<10) +#define ECOCHK_DIS_TLB (1<<8) #define HSW_ECOCHK_ARB_PRIO_SOL (1<<6) #define ECOCHK_PPGTT_CACHE64B (0x3<<3) #define ECOCHK_PPGTT_CACHE4B (0x0<<3) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 025978548fb6b..3a48c4f21f118 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -59,6 +59,10 @@ static void gen9_init_clock_gating(struct drm_device *dev) /* WaEnableLbsSlaRetryTimerDecrement:skl */ I915_WRITE(BDW_SCRATCH1, I915_READ(BDW_SCRATCH1) | GEN9_LBS_SLA_RETRY_TIMER_DECREMENT_ENABLE); + + /* WaDisableKillLogic:bxt,skl */ + I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | + ECOCHK_DIS_TLB); } static void skl_init_clock_gating(struct drm_device *dev) -- GitLab From 0504cffc7b128dc4bd751821abe7c47203d7bd62 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:27 +0100 Subject: [PATCH 0865/7006] drm/i915: Enable WA batch buffers for Gen9 This patch only enables support for Gen9, the actual WA will be initialized in subsequent patches. The WARN that we use to warn user if WA batch support is not available for a particular Gen is replaced with DRM_ERROR as warning here doesn't really add much value. v2: include all infrastructure bits in this patch so that subsequent changes only correspond the WA added (Chris) v3: use updated macro. Reviewed-by: Mika Kuoppala Cc: Imre Deak Cc: Mika Kuoppala Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 50 ++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index d7f66d2899702..f1a382c685a5a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1248,6 +1248,35 @@ static int gen8_init_perctx_bb(struct intel_engine_cs *ring, return wa_ctx_end(wa_ctx, *offset = index, 1); } +static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + /* FIXME: Replace me with WA */ + wa_ctx_emit(batch, index, MI_NOOP); + + /* Pad to end of cacheline */ + while (index % CACHELINE_DWORDS) + wa_ctx_emit(batch, index, MI_NOOP); + + return wa_ctx_end(wa_ctx, *offset = index, CACHELINE_DWORDS); +} + +static int gen9_init_perctx_bb(struct intel_engine_cs *ring, + struct i915_wa_ctx_bb *wa_ctx, + uint32_t *const batch, + uint32_t *offset) +{ + uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + + wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); + + return wa_ctx_end(wa_ctx, *offset = index, 1); +} + static int lrc_setup_wa_ctx_obj(struct intel_engine_cs *ring, u32 size) { int ret; @@ -1289,10 +1318,11 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) WARN_ON(ring->id != RCS); /* update this when WA for higher Gen are added */ - if (WARN(INTEL_INFO(ring->dev)->gen > 8, - "WA batch buffer is not initialized for Gen%d\n", - INTEL_INFO(ring->dev)->gen)) + if (INTEL_INFO(ring->dev)->gen > 9) { + DRM_ERROR("WA batch buffer is not initialized for Gen%d\n", + INTEL_INFO(ring->dev)->gen); return 0; + } /* some WA perform writes to scratch page, ensure it is valid */ if (ring->scratch.obj == NULL) { @@ -1324,6 +1354,20 @@ static int intel_init_workaround_bb(struct intel_engine_cs *ring) &offset); if (ret) goto out; + } else if (INTEL_INFO(ring->dev)->gen == 9) { + ret = gen9_init_indirectctx_bb(ring, + &wa_ctx->indirect_ctx, + batch, + &offset); + if (ret) + goto out; + + ret = gen9_init_perctx_bb(ring, + &wa_ctx->per_ctx, + batch, + &offset); + if (ret) + goto out; } out: -- GitLab From 0907c8f7e0047956dabdd70368a710dc048793eb Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:28 +0100 Subject: [PATCH 0866/7006] drm/i915/gen9: Add WaDisableCtxRestoreArbitration workaround In Indirect and Per context w/a batch buffer, +WaDisableCtxRestoreArbitration v2: SKL revision id was used for BXT, copy paste error found during internal review (Bob Beckett). v3: use updated macro. Reviewed-by: Mika Kuoppala Cc: Robert Beckett Cc: Mika Kuoppala Cc: Imre Deak Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index f1a382c685a5a..07fce8c6e8743 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1253,10 +1253,13 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); - /* FIXME: Replace me with WA */ - wa_ctx_emit(batch, index, MI_NOOP); + /* WaDisableCtxRestoreArbitration:skl,bxt */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) @@ -1270,8 +1273,14 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + /* WaDisableCtxRestoreArbitration:skl,bxt */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) + wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_ENABLE); + wa_ctx_emit(batch, index, MI_BATCH_BUFFER_END); return wa_ctx_end(wa_ctx, *offset = index, 1); -- GitLab From a4106a782d11d44f6740ec8868ad1863546f832a Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:29 +0100 Subject: [PATCH 0867/7006] drm/i915/gen9: Add WaFlushCoherentL3CacheLinesAtContextSwitch workaround In Indirect context w/a batch buffer, +WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt v2: address static checker warning where unsigned value was checked for less than zero which is never true (Dan Carpenter). v3: The WA uses default value of GEN8_L3SQCREG4 during flush but that disables some other WA; update default value to retain it and document dependency (Mika). Cc: Mika Kuoppala Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 16 ++++++++++++++++ drivers/gpu/drm/i915/intel_pm.c | 3 +++ 2 files changed, 19 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 07fce8c6e8743..b7e16293b9a9d 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1097,6 +1097,15 @@ static inline int gen8_emit_flush_coherentl3_wa(struct intel_engine_cs *ring, { uint32_t l3sqc4_flush = (0x40400000 | GEN8_LQSC_FLUSH_COHERENT_LINES); + /* + * WaDisableLSQCROPERFforOCL:skl + * This WA is implemented in skl_init_clock_gating() but since + * this batch updates GEN8_L3SQCREG4 with default value we need to + * set this bit here to retain the WA during flush. + */ + if (IS_SKYLAKE(ring->dev) && INTEL_REVID(ring->dev) <= SKL_REVID_E0) + l3sqc4_flush |= GEN8_LQSC_RO_PERF_DIS; + wa_ctx_emit(batch, index, (MI_STORE_REGISTER_MEM_GEN8(1) | MI_SRM_LRM_GLOBAL_GTT)); wa_ctx_emit(batch, index, GEN8_L3SQCREG4); @@ -1253,6 +1262,7 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, uint32_t *const batch, uint32_t *offset) { + int ret; struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); @@ -1261,6 +1271,12 @@ static int gen9_init_indirectctx_bb(struct intel_engine_cs *ring, (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) wa_ctx_emit(batch, index, MI_ARB_ON_OFF | MI_ARB_DISABLE); + /* WaFlushCoherentL3CacheLinesAtContextSwitch:skl,bxt */ + ret = gen8_emit_flush_coherentl3_wa(ring, batch, index); + if (ret < 0) + return ret; + index = ret; + /* Pad to end of cacheline */ while (index % CACHELINE_DWORDS) wa_ctx_emit(batch, index, MI_NOOP); diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 3a48c4f21f118..5eeddc97ca2a2 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -95,6 +95,9 @@ static void skl_init_clock_gating(struct drm_device *dev) _MASKED_BIT_ENABLE(GEN9_TSG_BARRIER_ACK_DISABLE)); } + /* GEN8_L3SQCREG4 has a dependency with WA batch so any new changes + * involving this register should also be added to WA batch as required. + */ if (INTEL_REVID(dev) <= SKL_REVID_E0) /* WaDisableLSQCROPERFforOCL:skl */ I915_WRITE(GEN8_L3SQCREG4, I915_READ(GEN8_L3SQCREG4) | -- GitLab From 9b01435d2802148fcf6e061df0e4926768eeb133 Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Tue, 14 Jul 2015 15:01:30 +0100 Subject: [PATCH 0868/7006] drm/i915/gen9: Add WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken In Indirect context w/a batch buffer, +WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken v2: SKL revision id was used for BXT, copy paste error found during internal review (Bob Beckett). v3: explain why part of the WA is in Per ctx batch (Mika) Cc: Mika Kuoppala Cc: Imre Deak Signed-off-by: Arun Siluvery Reviewed-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_lrc.c | 10 ++++++++++ drivers/gpu/drm/i915/intel_ringbuffer.c | 7 +++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index b7e16293b9a9d..83ed0f7fcbe24 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1292,6 +1292,16 @@ static int gen9_init_perctx_bb(struct intel_engine_cs *ring, struct drm_device *dev = ring->dev; uint32_t index = wa_ctx_start(wa_ctx, *offset, CACHELINE_DWORDS); + /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ + if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_B0)) || + (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) { + wa_ctx_emit(batch, index, MI_LOAD_REGISTER_IMM(1)); + wa_ctx_emit(batch, index, GEN9_SLICE_COMMON_ECO_CHICKEN0); + wa_ctx_emit(batch, index, + _MASKED_BIT_ENABLE(DISABLE_PIXEL_MASK_CAMMING)); + wa_ctx_emit(batch, index, MI_NOOP); + } + /* WaDisableCtxRestoreArbitration:skl,bxt */ if ((IS_SKYLAKE(dev) && (INTEL_REVID(dev) <= SKL_REVID_D0)) || (IS_BROXTON(dev) && (INTEL_REVID(dev) == BXT_REVID_A0))) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index bddc9032e17ed..1c14233d179f1 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -946,8 +946,11 @@ static int gen9_init_workarounds(struct intel_engine_cs *ring) /* WaSetDisablePixMaskCammingAndRhwoInCommonSliceChicken:skl,bxt */ WA_SET_BIT_MASKED(GEN7_COMMON_SLICE_CHICKEN1, GEN9_RHWO_OPTIMIZATION_DISABLE); - WA_SET_BIT_MASKED(GEN9_SLICE_COMMON_ECO_CHICKEN0, - DISABLE_PIXEL_MASK_CAMMING); + /* + * WA also requires GEN9_SLICE_COMMON_ECO_CHICKEN0[14:14] to be set + * but we do that in per ctx batchbuffer as there is an issue + * with this register not getting restored on ctx restore + */ } if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) >= SKL_REVID_C0) || -- GitLab From 74c090b1bdc57b1c9f1361908cca5a3d8a80fb08 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:30 +0200 Subject: [PATCH 0869/7006] drm/i915: Use full atomic modeset. Huzzah! \o/ Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_drv.h | 1 - drivers/gpu/drm/i915/i915_params.c | 5 - drivers/gpu/drm/i915/intel_atomic.c | 123 ------------ drivers/gpu/drm/i915/intel_display.c | 279 ++++----------------------- drivers/gpu/drm/i915/intel_drv.h | 5 - 6 files changed, 43 insertions(+), 372 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index db48aee7f1405..f13ed1ef66410 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -1731,7 +1731,7 @@ static int __init i915_init(void) * to the atomic ioctl and the atomic properties. Only plane operations on * a single CRTC will actually work. */ - if (i915.nuclear_pageflip) + if (driver.driver_features & DRIVER_MODESET) driver.driver_features |= DRIVER_ATOMIC; return drm_pci_init(&driver, &i915_pci_driver); diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2714228e34561..4af33d59d5070 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2614,7 +2614,6 @@ struct i915_params { int use_mmio_flip; int mmio_debug; bool verbose_state_checks; - bool nuclear_pageflip; int edp_vswing; }; extern struct i915_params i915 __read_mostly; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 7983fe48a6549..5f4e7295295ff 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -51,7 +51,6 @@ struct i915_params i915 __read_mostly = { .use_mmio_flip = 0, .mmio_debug = 0, .verbose_state_checks = 1, - .nuclear_pageflip = 0, .edp_vswing = 0, }; @@ -176,10 +175,6 @@ module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600); MODULE_PARM_DESC(verbose_state_checks, "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions."); -module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600); -MODULE_PARM_DESC(nuclear_pageflip, - "Force atomic modeset functionality; only planes work for now (default: false)."); - /* WA to get away with the default setting in VBT for early platforms.Will be removed */ module_param_named_unsafe(edp_vswing, i915.edp_vswing, int, 0400); MODULE_PARM_DESC(edp_vswing, diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c index dcf4fb458649a..e2531cf59266e 100644 --- a/drivers/gpu/drm/i915/intel_atomic.c +++ b/drivers/gpu/drm/i915/intel_atomic.c @@ -35,129 +35,6 @@ #include #include "intel_drv.h" - -/** - * intel_atomic_check - validate state object - * @dev: drm device - * @state: state to validate - */ -int intel_atomic_check(struct drm_device *dev, - struct drm_atomic_state *state) -{ - int nplanes = dev->mode_config.num_total_plane; - int ncrtcs = dev->mode_config.num_crtc; - int nconnectors = dev->mode_config.num_connector; - enum pipe nuclear_pipe = INVALID_PIPE; - struct intel_crtc *nuclear_crtc = NULL; - struct intel_crtc_state *crtc_state = NULL; - int ret; - int i; - bool not_nuclear = false; - - to_intel_atomic_state(state)->cdclk = to_i915(dev)->cdclk_freq; - - /* - * FIXME: At the moment, we only support "nuclear pageflip" on a - * single CRTC. Cross-crtc updates will be added later. - */ - for (i = 0; i < nplanes; i++) { - struct intel_plane *plane = to_intel_plane(state->planes[i]); - if (!plane) - continue; - - if (nuclear_pipe == INVALID_PIPE) { - nuclear_pipe = plane->pipe; - } else if (nuclear_pipe != plane->pipe) { - DRM_DEBUG_KMS("i915 only support atomic plane operations on a single CRTC at the moment\n"); - return -EINVAL; - } - } - - /* - * FIXME: We only handle planes for now; make sure there are no CRTC's - * or connectors involved. - */ - state->allow_modeset = false; - for (i = 0; i < ncrtcs; i++) { - struct intel_crtc *crtc = to_intel_crtc(state->crtcs[i]); - if (crtc) - memset(&crtc->atomic, 0, sizeof(crtc->atomic)); - if (crtc && crtc->pipe != nuclear_pipe) - not_nuclear = true; - if (crtc && crtc->pipe == nuclear_pipe) { - nuclear_crtc = crtc; - crtc_state = to_intel_crtc_state(state->crtc_states[i]); - } - } - for (i = 0; i < nconnectors; i++) - if (state->connectors[i] != NULL) - not_nuclear = true; - - if (not_nuclear) { - DRM_DEBUG_KMS("i915 only supports atomic plane operations at the moment\n"); - return -EINVAL; - } - - ret = drm_atomic_helper_check_planes(dev, state); - if (ret) - return ret; - - return ret; -} - - -/** - * intel_atomic_commit - commit validated state object - * @dev: DRM device - * @state: the top-level driver state object - * @async: asynchronous commit - * - * This function commits a top-level state object that has been validated - * with drm_atomic_helper_check(). - * - * FIXME: Atomic modeset support for i915 is not yet complete. At the moment - * we can only handle plane-related operations and do not yet support - * asynchronous commit. - * - * RETURNS - * Zero for success or -errno. - */ -int intel_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool async) -{ - struct drm_crtc_state *crtc_state; - struct drm_crtc *crtc; - int ret; - int i; - - if (async) { - DRM_DEBUG_KMS("i915 does not yet support async commit\n"); - return -EINVAL; - } - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - /* Point of no return */ - drm_atomic_helper_swap_state(dev, state); - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - to_intel_crtc(crtc)->config = to_intel_crtc_state(crtc->state); - - drm_atomic_helper_commit_planes_on_crtc(crtc_state); - } - - /* FIXME: This function should eventually call __intel_set_mode when needed */ - - drm_atomic_helper_wait_for_vblanks(dev, state); - drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); - - return 0; -} - /** * intel_connector_atomic_get_property - fetch connector property value * @connector: connector to fetch property for diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 10a1726811384..83d7753b8b07f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -86,7 +86,6 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc, static void ironlake_pch_clock_get(struct intel_crtc *crtc, struct intel_crtc_state *pipe_config); -static int intel_set_mode(struct drm_atomic_state *state); static int intel_framebuffer_init(struct drm_device *dev, struct intel_framebuffer *ifb, struct drm_mode_fb_cmd2 *mode_cmd, @@ -111,14 +110,6 @@ static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, int num_connectors); static void intel_modeset_setup_hw_state(struct drm_device *dev); -static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe) -{ - if (!connector->mst_port) - return connector->encoder; - else - return &connector->mst_port->mst_encoders[pipe]->base; -} - typedef struct { int min, max; } intel_range_t; @@ -6262,7 +6253,7 @@ int intel_display_suspend(struct drm_device *dev) } if (crtc_mask) { - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (!ret) { for_each_crtc(dev, crtc) @@ -6316,7 +6307,7 @@ int intel_crtc_control(struct drm_crtc *crtc, bool enable) } pipe_config->base.active = enable; - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (!ret) return ret; @@ -10430,7 +10421,7 @@ retry: drm_mode_copy(&crtc_state->base.mode, mode); - if (intel_set_mode(state)) { + if (drm_atomic_commit(state)) { DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n"); if (old->release_fb) old->release_fb->funcs->destroy(old->release_fb); @@ -10498,7 +10489,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector, if (ret) goto fail; - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (ret) goto fail; @@ -13119,7 +13110,6 @@ static int intel_modeset_all_pipes(struct drm_atomic_state *state) } -/* Code that should eventually be part of atomic_check() */ static int intel_modeset_checks(struct drm_atomic_state *state) { struct drm_device *dev = state->dev; @@ -13160,15 +13150,20 @@ static int intel_modeset_checks(struct drm_atomic_state *state) return 0; } -static int -intel_modeset_compute_config(struct drm_atomic_state *state) +/** + * intel_atomic_check - validate state object + * @dev: drm device + * @state: state to validate + */ +static int intel_atomic_check(struct drm_device *dev, + struct drm_atomic_state *state) { struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; int ret, i; bool any_ms = false; - ret = drm_atomic_helper_check_modeset(state->dev, state); + ret = drm_atomic_helper_check_modeset(dev, state); if (ret) return ret; @@ -13231,9 +13226,26 @@ intel_modeset_compute_config(struct drm_atomic_state *state) return drm_atomic_helper_check_planes(state->dev, state); } -static int __intel_set_mode(struct drm_atomic_state *state) +/** + * intel_atomic_commit - commit validated state object + * @dev: DRM device + * @state: the top-level driver state object + * @async: asynchronous commit + * + * This function commits a top-level state object that has been validated + * with drm_atomic_helper_check(). + * + * FIXME: Atomic modeset support for i915 is not yet complete. At the moment + * we can only handle plane-related operations and do not yet support + * asynchronous commit. + * + * RETURNS + * Zero for success or -errno. + */ +static int intel_atomic_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool async) { - struct drm_device *dev = state->dev; struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *crtc; struct drm_crtc_state *crtc_state; @@ -13241,6 +13253,11 @@ static int __intel_set_mode(struct drm_atomic_state *state) int i; bool any_ms = false; + if (async) { + DRM_DEBUG_KMS("i915 does not yet support async commit\n"); + return -EINVAL; + } + ret = drm_atomic_helper_prepare_planes(dev, state); if (ret) return ret; @@ -13285,34 +13302,14 @@ static int __intel_set_mode(struct drm_atomic_state *state) /* FIXME: add subpixel order */ + drm_atomic_helper_wait_for_vblanks(dev, state); drm_atomic_helper_cleanup_planes(dev, state); - drm_atomic_state_free(state); - return 0; -} - -static int intel_set_mode_checked(struct drm_atomic_state *state) -{ - struct drm_device *dev = state->dev; - int ret; - - ret = __intel_set_mode(state); - if (ret == 0) + if (any_ms) intel_modeset_check_state(dev); - return ret; -} - -static int intel_set_mode(struct drm_atomic_state *state) -{ - int ret; - - ret = intel_modeset_compute_config(state); - if (ret) - return ret; - - return intel_set_mode_checked(state); + return 0; } void intel_crtc_restore_mode(struct drm_crtc *crtc) @@ -13339,7 +13336,7 @@ retry: goto out; crtc_state->mode_changed = true; - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); } if (ret == -EDEADLK) { @@ -13355,201 +13352,9 @@ out: #undef for_each_intel_crtc_masked -static bool intel_connector_in_mode_set(struct intel_connector *connector, - struct drm_mode_set *set) -{ - int ro; - - for (ro = 0; ro < set->num_connectors; ro++) - if (set->connectors[ro] == &connector->base) - return true; - - return false; -} - -static int -intel_modeset_stage_output_state(struct drm_device *dev, - struct drm_mode_set *set, - struct drm_atomic_state *state) -{ - struct intel_connector *connector; - struct drm_connector *drm_connector; - struct drm_connector_state *connector_state; - struct drm_crtc *crtc; - struct drm_crtc_state *crtc_state; - int i, ret; - - /* The upper layers ensure that we either disable a crtc or have a list - * of connectors. For paranoia, double-check this. */ - WARN_ON(!set->fb && (set->num_connectors != 0)); - WARN_ON(set->fb && (set->num_connectors == 0)); - - for_each_intel_connector(dev, connector) { - bool in_mode_set = intel_connector_in_mode_set(connector, set); - - if (!in_mode_set && connector->base.state->crtc != set->crtc) - continue; - - connector_state = - drm_atomic_get_connector_state(state, &connector->base); - if (IS_ERR(connector_state)) - return PTR_ERR(connector_state); - - if (in_mode_set) { - int pipe = to_intel_crtc(set->crtc)->pipe; - connector_state->best_encoder = - &intel_find_encoder(connector, pipe)->base; - } - - if (connector->base.state->crtc != set->crtc) - continue; - - /* If we disable the crtc, disable all its connectors. Also, if - * the connector is on the changing crtc but not on the new - * connector list, disable it. */ - if (!set->fb || !in_mode_set) { - connector_state->best_encoder = NULL; - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [NOCRTC]\n", - connector->base.base.id, - connector->base.name); - } - } - /* connector->new_encoder is now updated for all connectors. */ - - for_each_connector_in_state(state, drm_connector, connector_state, i) { - connector = to_intel_connector(drm_connector); - - if (!connector_state->best_encoder) { - ret = drm_atomic_set_crtc_for_connector(connector_state, - NULL); - if (ret) - return ret; - - continue; - } - - if (intel_connector_in_mode_set(connector, set)) { - struct drm_crtc *crtc = connector->base.state->crtc; - - /* If this connector was in a previous crtc, add it - * to the state. We might need to disable it. */ - if (crtc) { - crtc_state = - drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - } - - ret = drm_atomic_set_crtc_for_connector(connector_state, - set->crtc); - if (ret) - return ret; - } - - /* Make sure the new CRTC will work with the encoder */ - if (!drm_encoder_crtc_ok(connector_state->best_encoder, - connector_state->crtc)) { - return -EINVAL; - } - - DRM_DEBUG_KMS("[CONNECTOR:%d:%s] to [CRTC:%d]\n", - connector->base.base.id, - connector->base.name, - connector_state->crtc->base.id); - - if (connector_state->best_encoder != &connector->encoder->base) - connector->encoder = - to_intel_encoder(connector_state->best_encoder); - } - - for_each_crtc_in_state(state, crtc, crtc_state, i) { - bool has_connectors; - - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ret; - - has_connectors = !!drm_atomic_connectors_for_crtc(state, crtc); - if (has_connectors != crtc_state->enable) - crtc_state->enable = - crtc_state->active = has_connectors; - } - - ret = intel_modeset_setup_plane_state(state, set->crtc, set->mode, - set->fb, set->x, set->y); - if (ret) - return ret; - - crtc_state = drm_atomic_get_crtc_state(state, set->crtc); - if (IS_ERR(crtc_state)) - return PTR_ERR(crtc_state); - - ret = drm_atomic_set_mode_for_crtc(crtc_state, set->mode); - if (ret) - return ret; - - if (set->num_connectors) - crtc_state->active = true; - - return 0; -} - -static int intel_crtc_set_config(struct drm_mode_set *set) -{ - struct drm_device *dev; - struct drm_atomic_state *state = NULL; - int ret; - - BUG_ON(!set); - BUG_ON(!set->crtc); - BUG_ON(!set->crtc->helper_private); - - /* Enforce sane interface api - has been abused by the fb helper. */ - BUG_ON(!set->mode && set->fb); - BUG_ON(set->fb && set->num_connectors == 0); - - if (set->fb) { - DRM_DEBUG_KMS("[CRTC:%d] [FB:%d] #connectors=%d (x y) (%i %i)\n", - set->crtc->base.id, set->fb->base.id, - (int)set->num_connectors, set->x, set->y); - } else { - DRM_DEBUG_KMS("[CRTC:%d] [NOFB]\n", set->crtc->base.id); - } - - dev = set->crtc->dev; - - state = drm_atomic_state_alloc(dev); - if (!state) - return -ENOMEM; - - state->acquire_ctx = dev->mode_config.acquire_ctx; - - ret = intel_modeset_stage_output_state(dev, set, state); - if (ret) - goto out; - - ret = intel_modeset_compute_config(state); - if (ret) - goto out; - - intel_update_pipe_size(to_intel_crtc(set->crtc)); - - ret = intel_set_mode_checked(state); - if (ret) { - DRM_DEBUG_KMS("failed to set mode on [CRTC:%d], err = %d\n", - set->crtc->base.id, ret); - } - -out: - if (ret) - drm_atomic_state_free(state); - return ret; -} - static const struct drm_crtc_funcs intel_crtc_funcs = { .gamma_set = intel_crtc_gamma_set, - .set_config = intel_crtc_set_config, + .set_config = drm_atomic_helper_set_config, .destroy = intel_crtc_destroy, .page_flip = intel_crtc_page_flip, .atomic_duplicate_state = intel_crtc_duplicate_state, @@ -15654,7 +15459,7 @@ void intel_display_resume(struct drm_device *dev) intel_modeset_setup_hw_state(dev); i915_redisable_vga(dev); - ret = intel_set_mode(state); + ret = drm_atomic_commit(state); if (!ret) return; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index f4abce1032217..cc91ea370c99f 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1393,11 +1393,6 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count); void intel_tv_init(struct drm_device *dev); /* intel_atomic.c */ -int intel_atomic_check(struct drm_device *dev, - struct drm_atomic_state *state); -int intel_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool async); int intel_connector_atomic_get_property(struct drm_connector *connector, const struct drm_connector_state *state, struct drm_property *property, -- GitLab From f6ac4b2a121fd3362407b21e36ec71d9886ce379 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:31 +0200 Subject: [PATCH 0870/7006] drm/i915: Call plane update functions directly from intel_atomic_commit. Now that there's only a single path for all atomic updates we can call intel_(pre/post)_plane_update from intel_atomic_commit directly. This makes the intention more clear. Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 83d7753b8b07f..67c9c4f2a8bc7 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13292,12 +13292,19 @@ static int intel_atomic_commit(struct drm_device *dev, /* Now enable the clocks, plane, pipe, and connectors that we set up. */ for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (needs_modeset(crtc->state) && crtc->state->active) { + struct intel_crtc *intel_crtc = to_intel_crtc(crtc); + bool modeset = needs_modeset(crtc->state); + + if (modeset && crtc->state->active) { update_scanline_offset(to_intel_crtc(crtc)); dev_priv->display.crtc_enable(crtc); } + if (!modeset) + intel_pre_plane_update(intel_crtc); + drm_atomic_helper_commit_planes_on_crtc(crtc_state); + intel_post_plane_update(intel_crtc); } /* FIXME: add subpixel order */ @@ -13635,9 +13642,6 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (!needs_modeset(crtc->state)) - intel_pre_plane_update(intel_crtc); - if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); @@ -13664,8 +13668,6 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) intel_crtc->atomic.start_vbl_count); intel_runtime_pm_put(dev_priv); - - intel_post_plane_update(intel_crtc); } /** -- GitLab From 342defd8646dff96f87cf44c4eee4dfdf0dd8d00 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:33 +0200 Subject: [PATCH 0871/7006] drm/i915: Remove use of runtime pm in atomic commit functions We needed this originally for updating pagetables in plane commit functions. But that's extracted into prepare/cleanup now. The other issue was running updates when the pipe was off. That's also now fixed. Suggested-by: Daniel Vetter Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 67c9c4f2a8bc7..755389f18dfeb 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13639,14 +13639,11 @@ intel_disable_primary_plane(struct drm_plane *plane, static void intel_begin_crtc_commit(struct drm_crtc *crtc) { struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); if (intel_crtc->atomic.update_wm_pre) intel_update_watermarks(crtc); - intel_runtime_pm_get(dev_priv); - /* Perform vblank evasion around commit operation */ if (crtc->state->active) intel_crtc->atomic.evade = @@ -13659,15 +13656,11 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) static void intel_finish_crtc_commit(struct drm_crtc *crtc) { - struct drm_device *dev = crtc->dev; - struct drm_i915_private *dev_priv = dev->dev_private; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); if (intel_crtc->atomic.evade) intel_pipe_update_end(intel_crtc, intel_crtc->atomic.start_vbl_count); - - intel_runtime_pm_put(dev_priv); } /** -- GitLab From 8f539a83efa7dceb7c2257ca96e2dfc846bd12f6 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 13 Jul 2015 16:30:32 +0200 Subject: [PATCH 0872/7006] drm/i915: always disable irqs in intel_pipe_update_start This can only fail because of a bug in the code. Suggested-by: Daniel Vetter Signed-off-by: Maarten Lankhorst [danvet: Squash in follow-up to also remove start_vbl_count from intel_crtc->atomic and put it into the intel_crtc directly - it's not precomputed state.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 15 +++++---------- drivers/gpu/drm/i915/intel_drv.h | 7 ++----- drivers/gpu/drm/i915/intel_sprite.c | 17 +++++++---------- 3 files changed, 14 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 755389f18dfeb..bd92e9ce4127c 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -11247,12 +11247,11 @@ static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc) static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) { struct drm_device *dev = intel_crtc->base.dev; - bool atomic_update; u32 start_vbl_count; intel_mark_page_flip_active(intel_crtc); - atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count); + intel_pipe_update_start(intel_crtc, &start_vbl_count); if (INTEL_INFO(dev)->gen >= 9) skl_do_mmio_flip(intel_crtc); @@ -11260,8 +11259,7 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc) /* use_mmio_flip() retricts MMIO flips to ilk+ */ ilk_do_mmio_flip(intel_crtc); - if (atomic_update) - intel_pipe_update_end(intel_crtc, start_vbl_count); + intel_pipe_update_end(intel_crtc, start_vbl_count); } static void intel_mmio_flip_work_func(struct work_struct *work) @@ -13646,9 +13644,7 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) /* Perform vblank evasion around commit operation */ if (crtc->state->active) - intel_crtc->atomic.evade = - intel_pipe_update_start(intel_crtc, - &intel_crtc->atomic.start_vbl_count); + intel_pipe_update_start(intel_crtc, &intel_crtc->start_vbl_count); if (!needs_modeset(crtc->state) && INTEL_INFO(dev)->gen >= 9) skl_detach_scalers(intel_crtc); @@ -13658,9 +13654,8 @@ static void intel_finish_crtc_commit(struct drm_crtc *crtc) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); - if (intel_crtc->atomic.evade) - intel_pipe_update_end(intel_crtc, - intel_crtc->atomic.start_vbl_count); + if (crtc->state->active) + intel_pipe_update_end(intel_crtc, intel_crtc->start_vbl_count); } /** diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index cc91ea370c99f..0fcfa7f179c4d 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -488,10 +488,6 @@ struct skl_pipe_wm { * and thus can't be run with interrupts disabled. */ struct intel_crtc_atomic_commit { - /* vblank evasion */ - bool evade; - unsigned start_vbl_count; - /* Sleepable operations to perform before commit */ bool wait_for_flips; bool disable_fbc; @@ -559,6 +555,7 @@ struct intel_crtc { int scanline_offset; + unsigned start_vbl_count; struct intel_crtc_atomic_commit atomic; /* scalers available on this crtc */ @@ -1385,7 +1382,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob); int intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane); int intel_sprite_set_colorkey(struct drm_device *dev, void *data, struct drm_file *file_priv); -bool intel_pipe_update_start(struct intel_crtc *crtc, +void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count); void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count); diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c index cd21525df3526..9d8af2f8a8759 100644 --- a/drivers/gpu/drm/i915/intel_sprite.c +++ b/drivers/gpu/drm/i915/intel_sprite.c @@ -75,10 +75,8 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs) * until a subsequent call to intel_pipe_update_end(). That is done to * avoid random delays. The value written to @start_vbl_count should be * supplied to intel_pipe_update_end() for error checking. - * - * Return: true if the call was successful */ -bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) +void intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) { struct drm_device *dev = crtc->base.dev; const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode; @@ -96,13 +94,14 @@ bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) min = vblank_start - usecs_to_scanlines(mode, 100); max = vblank_start - 1; + local_irq_disable(); + *start_vbl_count = 0; + if (min <= 0 || max <= 0) - return false; + return; if (WARN_ON(drm_crtc_vblank_get(&crtc->base))) - return false; - - local_irq_disable(); + return; trace_i915_pipe_update_start(crtc, min, max); @@ -138,8 +137,6 @@ bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count) *start_vbl_count = dev->driver->get_vblank_counter(dev, pipe); trace_i915_pipe_update_vblank_evaded(crtc, min, max, *start_vbl_count); - - return true; } /** @@ -161,7 +158,7 @@ void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count) local_irq_enable(); - if (start_vbl_count != end_vbl_count) + if (start_vbl_count && start_vbl_count != end_vbl_count) DRM_ERROR("Atomic update failure on pipe %c (start=%u end=%u)\n", pipe_name(pipe), start_vbl_count, end_vbl_count); } -- GitLab From e2ff2d4a467511ef88ae574555ddc0e952777f0c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 15 Jul 2015 14:15:50 +0200 Subject: [PATCH 0873/7006] drm/i915: Unconditionally check gmch pfit state Now that we recompute the pipe config for all CRTCs that have changed we don't have problems with stale configuration data for the global pfit and can remove this hack. Yay! Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ede6528675969..c29e7ed5fbb74 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12607,21 +12607,11 @@ intel_pipe_config_compare(struct drm_device *dev, PIPE_CONF_CHECK_I(pipe_src_w); PIPE_CONF_CHECK_I(pipe_src_h); - /* - * FIXME: BIOS likes to set up a cloned config with lvds+external - * screen. Since we don't yet re-compute the pipe config when moving - * just the lvds port away to another pipe the sw tracking won't match. - * - * Proper atomic modesets with recomputed global state will fix this. - * Until then just don't check gmch state for inherited modes. - */ - if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_INHERITED_MODE)) { - PIPE_CONF_CHECK_I(gmch_pfit.control); - /* pfit ratios are autocomputed by the hw on gen4+ */ - if (INTEL_INFO(dev)->gen < 4) - PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); - PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); - } + PIPE_CONF_CHECK_I(gmch_pfit.control); + /* pfit ratios are autocomputed by the hw on gen4+ */ + if (INTEL_INFO(dev)->gen < 4) + PIPE_CONF_CHECK_I(gmch_pfit.pgm_ratios); + PIPE_CONF_CHECK_I(gmch_pfit.lvds_border_bits); PIPE_CONF_CHECK_I(pch_pfit.enabled); if (current_config->pch_pfit.enabled) { -- GitLab From 1ed51de9ca9170d1c5361924a17e7c483050aeb6 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 15 Jul 2015 14:15:51 +0200 Subject: [PATCH 0874/7006] drm/i915: Clarify logic for initial modeset Currently we both set mode->private_flags to some value and also use the pipe_config quirk. But since the pipe_config quirk isn't tied to the lifetime of the mode object we need to check both. Simplify this by only using mode.private_flags and stop using the INHERITED_MODE quirk. Also for clarity add an explicit #define for that driver priavete mode flag. By using crtc_state->mode_changed we can also remove the recalc local variable. Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 34 ++++++++++------------------ drivers/gpu/drm/i915/intel_drv.h | 4 +++- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index c29e7ed5fbb74..ce71552d4498e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13161,7 +13161,11 @@ static int intel_atomic_check(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); - bool modeset, recalc = false; + bool modeset; + + /* Catch I915_MODE_FLAG_INHERITED */ + if (crtc_state->mode.private_flags != crtc->state->mode.private_flags) + crtc_state->mode_changed = true; if (!crtc_state->enable) { if (needs_modeset(crtc_state)) @@ -13170,28 +13174,22 @@ static int intel_atomic_check(struct drm_device *dev, } modeset = needs_modeset(crtc_state); - /* see comment in intel_modeset_readout_hw_state */ - if (!modeset && crtc_state->mode_blob != crtc->state->mode_blob && - pipe_config->quirks & PIPE_CONFIG_QUIRK_INHERITED_MODE) - recalc = true; - if (!modeset && !recalc) + if (!modeset) continue; - if (recalc) { - ret = drm_atomic_add_affected_connectors(state, crtc); - if (ret) - return ret; - } + ret = drm_atomic_add_affected_connectors(state, crtc); + if (ret) + return ret; ret = intel_modeset_pipe_config(crtc, pipe_config); if (ret) return ret; - if (recalc && (!i915.fastboot || + if (!i915.fastboot || !intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), - pipe_config, true))) { + pipe_config, true)) { modeset = crtc_state->mode_changed = true; ret = drm_atomic_add_affected_planes(state, crtc); @@ -15238,8 +15236,6 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) memset(crtc->config, 0, sizeof(*crtc->config)); crtc->config->base.crtc = &crtc->base; - crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE; - crtc->active = dev_priv->display.get_pipe_config(crtc, crtc->config); @@ -15265,17 +15261,11 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev) * right now it would cause a double modeset if * fbdev or userspace chooses a different initial mode. * - * So to prevent the double modeset, fail the memcmp - * test in drm_atomic_set_mode_for_crtc to get a new - * mode blob, and compare if the mode blob changed - * when the PIPE_CONFIG_QUIRK_INHERITED_MODE quirk is - * set. - * * If that happens, someone indicated they wanted a * mode change, which means it's safe to do a full * recalculation. */ - crtc->base.state->mode.private_flags = ~0; + crtc->base.state->mode.private_flags = I915_MODE_FLAG_INHERITED; } crtc->base.hwmode = crtc->config->base.adjusted_mode; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 0fcfa7f179c4d..3b00d00c0bc06 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -317,6 +317,9 @@ struct intel_crtc_scaler_state { int scaler_id; }; +/* drm_mode->private_flags */ +#define I915_MODE_FLAG_INHERITED 1 + struct intel_crtc_state { struct drm_crtc_state base; @@ -329,7 +332,6 @@ struct intel_crtc_state { * accordingly. */ #define PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS (1<<0) /* unreliable sync mode.flags */ -#define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */ unsigned long quirks; /* Pipe source size (ie. panel fitter input size) -- GitLab From 264954811af62dcfe17fc44cef379b315bb066eb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Wed, 15 Jul 2015 14:15:52 +0200 Subject: [PATCH 0875/7006] drm/i915: Invert fastboot check Fastboot should only downgrade a modeset if we have a match, not be used to upgrade to a full modeset. Otherwise we can only use it in a very restricted way: Initial modeset when the request mode is the preferred one of the panel and there's still a pfit active. And that only works because our mode_from_pipe_config fills in the wrong mode (it takes the adjusted mode, not the requested one). But we want fast modesets everywhere even after boot-up (especially for testing, but not only there). Hence we need to be able to make any modeset a fast one, which means we need to invert the logic and optionally downgrade a modeset. Note that this needs ->connector_changed split out from ->mode_changed otherwise it's not going to work (because we might loose a modeset because connectors changed but otherwise the config matches). As soon as that's merged we can drop the i915.fastboot check from this code. Also make sure that we don't accidentally clear any_ms and that we add the planes for any kind of modeset. Finally rename fastboot to fastset (yeah it's a silly name) since this really isn't about booting all that much. Cc: Maarten Lankhorst Signed-off-by: Daniel Vetter Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_display.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ce71552d4498e..af0bcfee4771f 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13161,7 +13161,6 @@ static int intel_atomic_check(struct drm_device *dev, for_each_crtc_in_state(state, crtc, crtc_state, i) { struct intel_crtc_state *pipe_config = to_intel_crtc_state(crtc_state); - bool modeset; /* Catch I915_MODE_FLAG_INHERITED */ if (crtc_state->mode.private_flags != crtc->state->mode.private_flags) @@ -13173,11 +13172,12 @@ static int intel_atomic_check(struct drm_device *dev, continue; } - modeset = needs_modeset(crtc_state); - - if (!modeset) + if (!needs_modeset(crtc_state)) continue; + /* FIXME: For only active_changed we shouldn't need to do any + * state recomputation at all. */ + ret = drm_atomic_add_affected_connectors(state, crtc); if (ret) return ret; @@ -13186,21 +13186,24 @@ static int intel_atomic_check(struct drm_device *dev, if (ret) return ret; - if (!i915.fastboot || - !intel_pipe_config_compare(state->dev, + if (i915.fastboot && + intel_pipe_config_compare(state->dev, to_intel_crtc_state(crtc->state), pipe_config, true)) { - modeset = crtc_state->mode_changed = true; + crtc_state->mode_changed = false; + } + + if (needs_modeset(crtc_state)) { + any_ms = true; ret = drm_atomic_add_affected_planes(state, crtc); if (ret) return ret; } - any_ms = modeset; - intel_dump_pipe_config(to_intel_crtc(crtc), - pipe_config, - modeset ? "[modeset]" : "[fastboot]"); + intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config, + needs_modeset(crtc_state) ? + "[modeset]" : "[fastset]"); } if (any_ms) { -- GitLab From 0d6ef0688d8744454646298b85336407be05e309 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 10 Jul 2015 15:42:49 +0900 Subject: [PATCH 0876/7006] ipvs: Delete an unnecessary check before the function call "module_put" The module_put() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipvs/ip_vs_sched.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/netfilter/ipvs/ip_vs_sched.c b/net/netfilter/ipvs/ip_vs_sched.c index 199760c71f399..e50221b9d95f8 100644 --- a/net/netfilter/ipvs/ip_vs_sched.c +++ b/net/netfilter/ipvs/ip_vs_sched.c @@ -137,7 +137,7 @@ struct ip_vs_scheduler *ip_vs_scheduler_get(const char *sched_name) void ip_vs_scheduler_put(struct ip_vs_scheduler *scheduler) { - if (scheduler && scheduler->module) + if (scheduler) module_put(scheduler->module); } -- GitLab From 70aa996601335ca3069190ebcdae8870828086a8 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 10 Jul 2015 18:13:20 -0500 Subject: [PATCH 0877/7006] netfilter: kill nf_hooks_active The function obscures what is going on in nf_hook_thresh and it's existence requires computing the hook list twice. Signed-off-by: "Eric W. Biederman" Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 00050dfd9f230..60e89348a91de 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -150,11 +150,6 @@ static inline bool nf_hook_list_active(struct list_head *nf_hook_list, } #endif -static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) -{ - return nf_hook_list_active(&nf_hooks[pf][hook], pf, hook); -} - int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state); /** @@ -172,10 +167,12 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, int (*okfn)(struct sock *, struct sk_buff *), int thresh) { - if (nf_hooks_active(pf, hook)) { + struct list_head *nf_hook_list = &nf_hooks[pf][hook]; + + if (nf_hook_list_active(nf_hook_list, pf, hook)) { struct nf_hook_state state; - nf_hook_state_init(&state, &nf_hooks[pf][hook], hook, thresh, + nf_hook_state_init(&state, nf_hook_list, hook, thresh, pf, indev, outdev, sk, okfn); return nf_hook_slow(skb, &state); } -- GitLab From 4c0911566dec7755d15cb89239fb2db4447f7a62 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 10 Jul 2015 18:13:58 -0500 Subject: [PATCH 0878/7006] netfilter: Simply the tests for enabling and disabling the ingress queue hook Replace an overcomplicated switch statement with a simple if statement. This also removes the ingress queue enable outside of nf_hook_mutex as the protection provided by the mutex is not necessary and the code is clearer having both of the static key increments together. Signed-off-by: "Eric W. Biederman" Signed-off-by: Pablo Neira Ayuso --- net/netfilter/core.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/net/netfilter/core.c b/net/netfilter/core.c index a0e54974e2c90..c4c3b85a25381 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -74,7 +74,6 @@ int nf_register_hook(struct nf_hook_ops *reg) if (reg->hooknum == NF_NETDEV_INGRESS) { BUG_ON(reg->dev == NULL); nf_hook_list = ®->dev->nf_hooks_ingress; - net_inc_ingress_queue(); break; } #endif @@ -90,6 +89,10 @@ int nf_register_hook(struct nf_hook_ops *reg) } list_add_rcu(®->list, elem->list.prev); mutex_unlock(&nf_hook_mutex); +#ifdef CONFIG_NETFILTER_INGRESS + if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) + net_inc_ingress_queue(); +#endif #ifdef HAVE_JUMP_LABEL static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif @@ -102,18 +105,10 @@ void nf_unregister_hook(struct nf_hook_ops *reg) mutex_lock(&nf_hook_mutex); list_del_rcu(®->list); mutex_unlock(&nf_hook_mutex); - switch (reg->pf) { - case NFPROTO_NETDEV: #ifdef CONFIG_NETFILTER_INGRESS - if (reg->hooknum == NF_NETDEV_INGRESS) { - net_dec_ingress_queue(); - break; - } - break; + if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) + net_dec_ingress_queue(); #endif - default: - break; - } #ifdef HAVE_JUMP_LABEL static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif -- GitLab From 0edcf282b0a6f38168294264837cf7d52a2f5255 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 10 Jul 2015 18:14:30 -0500 Subject: [PATCH 0879/7006] netfilter: Factor out the hook list selection from nf_register_hook - Add a new function find_nf_hook_list to select the nf_hook_list - Fail nf_register_hook when asked for a per netdevice hook list when support for per netdevice hook lists is not built into the kernel. - Move the hook list head selection outside of nf_hook_mutex as nothing in the selection requires the hook list, and error handling is simpler if a mutex is not held. Signed-off-by: "Eric W. Biederman" Signed-off-by: Pablo Neira Ayuso --- net/netfilter/core.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/net/netfilter/core.c b/net/netfilter/core.c index c4c3b85a25381..fa4d3c111d3fb 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -62,27 +62,31 @@ EXPORT_SYMBOL(nf_hooks_needed); static DEFINE_MUTEX(nf_hook_mutex); -int nf_register_hook(struct nf_hook_ops *reg) +static struct list_head *find_nf_hook_list(const struct nf_hook_ops *reg) { - struct list_head *nf_hook_list; - struct nf_hook_ops *elem; + struct list_head *nf_hook_list = NULL; - mutex_lock(&nf_hook_mutex); - switch (reg->pf) { - case NFPROTO_NETDEV: + if (reg->pf != NFPROTO_NETDEV) + nf_hook_list = &nf_hooks[reg->pf][reg->hooknum]; + else if (reg->hooknum == NF_NETDEV_INGRESS) { #ifdef CONFIG_NETFILTER_INGRESS - if (reg->hooknum == NF_NETDEV_INGRESS) { - BUG_ON(reg->dev == NULL); + if (reg->dev) nf_hook_list = ®->dev->nf_hooks_ingress; - break; - } #endif - /* Fall through. */ - default: - nf_hook_list = &nf_hooks[reg->pf][reg->hooknum]; - break; } + return nf_hook_list; +} + +int nf_register_hook(struct nf_hook_ops *reg) +{ + struct list_head *nf_hook_list; + struct nf_hook_ops *elem; + nf_hook_list = find_nf_hook_list(reg); + if (!nf_hook_list) + return -ENOENT; + + mutex_lock(&nf_hook_mutex); list_for_each_entry(elem, nf_hook_list, list) { if (reg->priority < elem->priority) break; -- GitLab From 085db2c04557d31db61541f361bd8b4de92c9939 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 10 Jul 2015 18:15:06 -0500 Subject: [PATCH 0880/7006] netfilter: Per network namespace netfilter hooks. - Add a new set of functions for registering and unregistering per network namespace hooks. - Modify the old global namespace hook functions to use the per network namespace hooks in their implementation, so their remains a single list that needs to be walked for any hook (this is important for keeping the hook priority working and for keeping the code walking the hooks simple). - Only allow registering the per netdevice hooks in the network namespace where the network device lives. - Dynamically allocate the structures in the per network namespace hook list in nf_register_net_hook, and unregister them in nf_unregister_net_hook. Dynamic allocate is required somewhere as the number of network namespaces are not fixed so we might as well allocate them in the registration function. The chain of registered hooks on any list is expected to be small so the cost of walking that list to find the entry we are unregistering should also be small. Performing the management of the dynamically allocated list entries in the registration and unregistration functions keeps the complexity from spreading. Signed-off-by: "Eric W. Biederman" --- include/linux/netfilter.h | 14 ++- include/net/netns/netfilter.h | 1 + net/netfilter/core.c | 182 ++++++++++++++++++++++++++++++---- 3 files changed, 173 insertions(+), 24 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 60e89348a91de..9bbd110ec81be 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #ifdef CONFIG_NETFILTER static inline int NF_DROP_GETERR(int verdict) @@ -118,6 +120,13 @@ struct nf_sockopt_ops { }; /* Function to register/unregister hook points. */ +int nf_register_net_hook(struct net *net, const struct nf_hook_ops *ops); +void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *ops); +int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, + unsigned int n); +void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg, + unsigned int n); + int nf_register_hook(struct nf_hook_ops *reg); void nf_unregister_hook(struct nf_hook_ops *reg); int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n); @@ -128,8 +137,6 @@ void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n); int nf_register_sockopt(struct nf_sockopt_ops *reg); void nf_unregister_sockopt(struct nf_sockopt_ops *reg); -extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; - #ifdef HAVE_JUMP_LABEL extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; @@ -167,7 +174,8 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, int (*okfn)(struct sock *, struct sk_buff *), int thresh) { - struct list_head *nf_hook_list = &nf_hooks[pf][hook]; + struct net *net = dev_net(indev ? indev : outdev); + struct list_head *nf_hook_list = &net->nf.hooks[pf][hook]; if (nf_hook_list_active(nf_hook_list, pf, hook)) { struct nf_hook_state state; diff --git a/include/net/netns/netfilter.h b/include/net/netns/netfilter.h index 532e4ba64f49a..38aa4983e2a90 100644 --- a/include/net/netns/netfilter.h +++ b/include/net/netns/netfilter.h @@ -14,5 +14,6 @@ struct netns_nf { #ifdef CONFIG_SYSCTL struct ctl_table_header *nf_log_dir_header; #endif + struct list_head hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; }; #endif diff --git a/net/netfilter/core.c b/net/netfilter/core.c index fa4d3c111d3fb..56ead1a1711c9 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -52,9 +52,6 @@ void nf_unregister_afinfo(const struct nf_afinfo *afinfo) } EXPORT_SYMBOL_GPL(nf_unregister_afinfo); -struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly; -EXPORT_SYMBOL(nf_hooks); - #ifdef HAVE_JUMP_LABEL struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; EXPORT_SYMBOL(nf_hooks_needed); @@ -62,27 +59,40 @@ EXPORT_SYMBOL(nf_hooks_needed); static DEFINE_MUTEX(nf_hook_mutex); -static struct list_head *find_nf_hook_list(const struct nf_hook_ops *reg) +static struct list_head *find_nf_hook_list(struct net *net, + const struct nf_hook_ops *reg) { struct list_head *nf_hook_list = NULL; if (reg->pf != NFPROTO_NETDEV) - nf_hook_list = &nf_hooks[reg->pf][reg->hooknum]; + nf_hook_list = &net->nf.hooks[reg->pf][reg->hooknum]; else if (reg->hooknum == NF_NETDEV_INGRESS) { #ifdef CONFIG_NETFILTER_INGRESS - if (reg->dev) + if (reg->dev && dev_net(reg->dev) == net) nf_hook_list = ®->dev->nf_hooks_ingress; #endif } return nf_hook_list; } -int nf_register_hook(struct nf_hook_ops *reg) +int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) { struct list_head *nf_hook_list; - struct nf_hook_ops *elem; + struct nf_hook_ops *elem, *new; + + new = kzalloc(sizeof(*new), GFP_KERNEL); + if (!new) + return -ENOMEM; - nf_hook_list = find_nf_hook_list(reg); + new->hook = reg->hook; + new->dev = reg->dev; + new->owner = reg->owner; + new->priv = reg->priv; + new->pf = reg->pf; + new->hooknum = reg->hooknum; + new->priority = reg->priority; + + nf_hook_list = find_nf_hook_list(net, reg); if (!nf_hook_list) return -ENOENT; @@ -91,7 +101,7 @@ int nf_register_hook(struct nf_hook_ops *reg) if (reg->priority < elem->priority) break; } - list_add_rcu(®->list, elem->list.prev); + list_add_rcu(&new->list, elem->list.prev); mutex_unlock(&nf_hook_mutex); #ifdef CONFIG_NETFILTER_INGRESS if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) @@ -102,13 +112,35 @@ int nf_register_hook(struct nf_hook_ops *reg) #endif return 0; } -EXPORT_SYMBOL(nf_register_hook); +EXPORT_SYMBOL(nf_register_net_hook); -void nf_unregister_hook(struct nf_hook_ops *reg) +void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) { + struct list_head *nf_hook_list; + struct nf_hook_ops *elem; + + nf_hook_list = find_nf_hook_list(net, reg); + if (!nf_hook_list) + return; + mutex_lock(&nf_hook_mutex); - list_del_rcu(®->list); + list_for_each_entry(elem, nf_hook_list, list) { + if ((reg->hook == elem->hook) && + (reg->dev == elem->dev) && + (reg->owner == elem->owner) && + (reg->priv == elem->priv) && + (reg->pf == elem->pf) && + (reg->hooknum == elem->hooknum) && + (reg->priority == elem->priority)) { + list_del_rcu(&elem->list); + break; + } + } mutex_unlock(&nf_hook_mutex); + if (&elem->list == nf_hook_list) { + WARN(1, "nf_unregister_net_hook: hook not found!\n"); + return; + } #ifdef CONFIG_NETFILTER_INGRESS if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) net_dec_ingress_queue(); @@ -117,7 +149,77 @@ void nf_unregister_hook(struct nf_hook_ops *reg) static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif synchronize_net(); - nf_queue_nf_hook_drop(reg); + nf_queue_nf_hook_drop(elem); + kfree(elem); +} +EXPORT_SYMBOL(nf_unregister_net_hook); + +int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, + unsigned int n) +{ + unsigned int i; + int err = 0; + + for (i = 0; i < n; i++) { + err = nf_register_net_hook(net, ®[i]); + if (err) + goto err; + } + return err; + +err: + if (i > 0) + nf_unregister_net_hooks(net, reg, i); + return err; +} +EXPORT_SYMBOL(nf_register_net_hooks); + +void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg, + unsigned int n) +{ + while (n-- > 0) + nf_unregister_net_hook(net, ®[n]); +} +EXPORT_SYMBOL(nf_unregister_net_hooks); + +static LIST_HEAD(nf_hook_list); + +int nf_register_hook(struct nf_hook_ops *reg) +{ + struct net *net, *last; + int ret; + + rtnl_lock(); + for_each_net(net) { + ret = nf_register_net_hook(net, reg); + if (ret && ret != -ENOENT) + goto rollback; + } + list_add_tail(®->list, &nf_hook_list); + rtnl_unlock(); + + return 0; +rollback: + last = net; + for_each_net(net) { + if (net == last) + break; + nf_unregister_net_hook(net, reg); + } + rtnl_unlock(); + return ret; +} +EXPORT_SYMBOL(nf_register_hook); + +void nf_unregister_hook(struct nf_hook_ops *reg) +{ + struct net *net; + + rtnl_lock(); + list_del(®->list); + for_each_net(net) + nf_unregister_net_hook(net, reg); + rtnl_unlock(); } EXPORT_SYMBOL(nf_unregister_hook); @@ -294,8 +396,46 @@ void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); EXPORT_SYMBOL(nf_nat_decode_session_hook); #endif +static int nf_register_hook_list(struct net *net) +{ + struct nf_hook_ops *elem; + int ret; + + rtnl_lock(); + list_for_each_entry(elem, &nf_hook_list, list) { + ret = nf_register_net_hook(net, elem); + if (ret && ret != -ENOENT) + goto out_undo; + } + rtnl_unlock(); + return 0; + +out_undo: + list_for_each_entry_continue_reverse(elem, &nf_hook_list, list) + nf_unregister_net_hook(net, elem); + rtnl_unlock(); + return ret; +} + +static void nf_unregister_hook_list(struct net *net) +{ + struct nf_hook_ops *elem; + + rtnl_lock(); + list_for_each_entry(elem, &nf_hook_list, list) + nf_unregister_net_hook(net, elem); + rtnl_unlock(); +} + static int __net_init netfilter_net_init(struct net *net) { + int i, h, ret; + + for (i = 0; i < ARRAY_SIZE(net->nf.hooks); i++) { + for (h = 0; h < NF_MAX_HOOKS; h++) + INIT_LIST_HEAD(&net->nf.hooks[i][h]); + } + #ifdef CONFIG_PROC_FS net->nf.proc_netfilter = proc_net_mkdir(net, "netfilter", net->proc_net); @@ -306,11 +446,16 @@ static int __net_init netfilter_net_init(struct net *net) return -ENOMEM; } #endif - return 0; + ret = nf_register_hook_list(net); + if (ret) + remove_proc_entry("netfilter", net->proc_net); + + return ret; } static void __net_exit netfilter_net_exit(struct net *net) { + nf_unregister_hook_list(net); remove_proc_entry("netfilter", net->proc_net); } @@ -321,12 +466,7 @@ static struct pernet_operations netfilter_net_ops = { int __init netfilter_init(void) { - int i, h, ret; - - for (i = 0; i < ARRAY_SIZE(nf_hooks); i++) { - for (h = 0; h < NF_MAX_HOOKS; h++) - INIT_LIST_HEAD(&nf_hooks[i][h]); - } + int ret; ret = register_pernet_subsys(&netfilter_net_ops); if (ret < 0) -- GitLab From fd2ecda0341960d0ce361d648cf4dd98187afb06 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 10 Jul 2015 18:15:44 -0500 Subject: [PATCH 0881/7006] netfilter: nftables: Only run the nftables chains in the proper netns - Register the nftables chains in the network namespace that they need to run in. - Remove the hacks that stopped chains running in the wrong network namespace. Signed-off-by: "Eric W. Biederman" Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nf_tables_api.c | 8 ++++++-- net/netfilter/nf_tables_core.c | 5 ----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index cfe636808541a..4a41eb92bcc0a 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c @@ -130,20 +130,24 @@ static void nft_trans_destroy(struct nft_trans *trans) int nft_register_basechain(struct nft_base_chain *basechain, unsigned int hook_nops) { + struct net *net = read_pnet(&basechain->pnet); + if (basechain->flags & NFT_BASECHAIN_DISABLED) return 0; - return nf_register_hooks(basechain->ops, hook_nops); + return nf_register_net_hooks(net, basechain->ops, hook_nops); } EXPORT_SYMBOL_GPL(nft_register_basechain); void nft_unregister_basechain(struct nft_base_chain *basechain, unsigned int hook_nops) { + struct net *net = read_pnet(&basechain->pnet); + if (basechain->flags & NFT_BASECHAIN_DISABLED) return; - nf_unregister_hooks(basechain->ops, hook_nops); + nf_unregister_net_hooks(net, basechain->ops, hook_nops); } EXPORT_SYMBOL_GPL(nft_unregister_basechain); diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c index f77bad46ac683..05d0b03530f6b 100644 --- a/net/netfilter/nf_tables_core.c +++ b/net/netfilter/nf_tables_core.c @@ -114,7 +114,6 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) { const struct nft_chain *chain = ops->priv, *basechain = chain; - const struct net *chain_net = read_pnet(&nft_base_chain(basechain)->pnet); const struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); const struct nft_rule *rule; const struct nft_expr *expr, *last; @@ -125,10 +124,6 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) int rulenum; unsigned int gencursor = nft_genmask_cur(net); - /* Ignore chains that are not for the current network namespace */ - if (!net_eq(net, chain_net)) - return NF_ACCEPT; - do_chain: rulenum = 0; rule = list_entry(&chain->rules, struct nft_rule, list); -- GitLab From 98d1bd802cdbc8f56868fae51edec13e86b59515 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Jul 2015 17:51:06 +0200 Subject: [PATCH 0882/7006] netfilter: xtables: compute exact size needed for jumpstack The {arp,ip,ip6tables} jump stack is currently sized based on the number of user chains. However, its rather unlikely that every user defined chain jumps to the next, so lets use the existing loop detection logic to also track the chain depths. The stacksize is then set to the largest chain depth seen. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/arp_tables.c | 19 ++++++++++++------- net/ipv4/netfilter/ip_tables.c | 28 ++++++++++++++++++---------- net/ipv6/netfilter/ip6_tables.c | 23 +++++++++++++++-------- net/netfilter/x_tables.c | 4 ++++ 4 files changed, 49 insertions(+), 25 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 92305a1a021a7..ae6d0a1242133 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -372,10 +372,13 @@ static inline bool unconditional(const struct arpt_arp *arp) /* Figures out from what hook each rule can be called: returns 0 if * there are loops. Puts hook bitmask in comefrom. + * + * Keeps track of largest call depth seen and stores it in newinfo->stacksize. */ -static int mark_source_chains(const struct xt_table_info *newinfo, +static int mark_source_chains(struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { + unsigned int calldepth, max_calldepth = 0; unsigned int hook; /* No recursion; use packet counter to save back ptrs (reset @@ -391,6 +394,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo, /* Set initial back pointer. */ e->counters.pcnt = pos; + calldepth = 0; for (;;) { const struct xt_standard_target *t @@ -445,6 +449,8 @@ static int mark_source_chains(const struct xt_table_info *newinfo, (entry0 + pos + size); e->counters.pcnt = pos; pos += size; + if (calldepth > 0) + --calldepth; } else { int newpos = t->verdict; @@ -459,6 +465,10 @@ static int mark_source_chains(const struct xt_table_info *newinfo, return 0; } + if (entry0 + newpos != arpt_next_entry(e) && + ++calldepth > max_calldepth) + max_calldepth = calldepth; + /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -475,6 +485,7 @@ static int mark_source_chains(const struct xt_table_info *newinfo, next: duprintf("Finished chain %u\n", hook); } + newinfo->stacksize = max_calldepth; return 1; } @@ -664,9 +675,6 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, if (ret != 0) break; ++i; - if (strcmp(arpt_get_target(iter)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; } duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); if (ret != 0) @@ -1439,9 +1447,6 @@ static int translate_compat_table(const char *name, break; } ++i; - if (strcmp(arpt_get_target(iter1)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 6c72fbb7b49eb..5e44b35a8de82 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -439,11 +439,15 @@ ipt_do_table(struct sk_buff *skb, } /* Figures out from what hook each rule can be called: returns 0 if - there are loops. Puts hook bitmask in comefrom. */ + * there are loops. Puts hook bitmask in comefrom. + * + * Keeps track of largest call depth seen and stores it in newinfo->stacksize. + */ static int -mark_source_chains(const struct xt_table_info *newinfo, +mark_source_chains(struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { + unsigned int calldepth, max_calldepth = 0; unsigned int hook; /* No recursion; use packet counter to save back ptrs (reset @@ -457,6 +461,7 @@ mark_source_chains(const struct xt_table_info *newinfo, /* Set initial back pointer. */ e->counters.pcnt = pos; + calldepth = 0; for (;;) { const struct xt_standard_target *t @@ -518,6 +523,9 @@ mark_source_chains(const struct xt_table_info *newinfo, (entry0 + pos + size); e->counters.pcnt = pos; pos += size; + WARN_ON_ONCE(calldepth == 0); + if (calldepth > 0) + --calldepth; } else { int newpos = t->verdict; @@ -531,9 +539,14 @@ mark_source_chains(const struct xt_table_info *newinfo, newpos); return 0; } + if (entry0 + newpos != ipt_next_entry(e) && + !(e->ip.flags & IPT_F_GOTO) && + ++calldepth > max_calldepth) + max_calldepth = calldepth; + /* This a jump; chase it. */ - duprintf("Jump rule %u -> %u\n", - pos, newpos); + duprintf("Jump rule %u -> %u, calldepth %d\n", + pos, newpos, calldepth); } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; @@ -547,6 +560,7 @@ mark_source_chains(const struct xt_table_info *newinfo, next: duprintf("Finished chain %u\n", hook); } + newinfo->stacksize = max_calldepth; return 1; } @@ -826,9 +840,6 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, if (ret != 0) return ret; ++i; - if (strcmp(ipt_get_target(iter)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; } if (i != repl->num_entries) { @@ -1744,9 +1755,6 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; - if (strcmp(ipt_get_target(iter1)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 3c35ced39b42b..baf0321799182 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -452,11 +452,15 @@ ip6t_do_table(struct sk_buff *skb, } /* Figures out from what hook each rule can be called: returns 0 if - there are loops. Puts hook bitmask in comefrom. */ + * there are loops. Puts hook bitmask in comefrom. + * + * Keeps track of largest call depth seen and stores it in newinfo->stacksize. + */ static int -mark_source_chains(const struct xt_table_info *newinfo, +mark_source_chains(struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { + unsigned int calldepth, max_calldepth = 0; unsigned int hook; /* No recursion; use packet counter to save back ptrs (reset @@ -470,6 +474,7 @@ mark_source_chains(const struct xt_table_info *newinfo, /* Set initial back pointer. */ e->counters.pcnt = pos; + calldepth = 0; for (;;) { const struct xt_standard_target *t @@ -531,6 +536,8 @@ mark_source_chains(const struct xt_table_info *newinfo, (entry0 + pos + size); e->counters.pcnt = pos; pos += size; + if (calldepth > 0) + --calldepth; } else { int newpos = t->verdict; @@ -544,6 +551,11 @@ mark_source_chains(const struct xt_table_info *newinfo, newpos); return 0; } + if (entry0 + newpos != ip6t_next_entry(e) && + !(e->ipv6.flags & IP6T_F_GOTO) && + ++calldepth > max_calldepth) + max_calldepth = calldepth; + /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -560,6 +572,7 @@ mark_source_chains(const struct xt_table_info *newinfo, next: duprintf("Finished chain %u\n", hook); } + newinfo->stacksize = max_calldepth; return 1; } @@ -839,9 +852,6 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, if (ret != 0) return ret; ++i; - if (strcmp(ip6t_get_target(iter)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; } if (i != repl->num_entries) { @@ -1754,9 +1764,6 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; - if (strcmp(ip6t_get_target(iter1)->u.user.name, - XT_ERROR_TARGET) == 0) - ++newinfo->stacksize; } if (ret) { /* diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index d324fe71260c9..4db7d60d42fae 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -749,6 +749,10 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) if (i->jumpstack == NULL) return -ENOMEM; + /* ruleset without jumps -- no stack needed */ + if (i->stacksize == 0) + return 0; + i->stacksize *= xt_jumpstack_multiplier; size = sizeof(void *) * i->stacksize; for_each_possible_cpu(cpu) { -- GitLab From e7c8899f3e6f2830136cf6e115c4a55ce7a3920a Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Jul 2015 17:51:07 +0200 Subject: [PATCH 0883/7006] netfilter: move tee_active to core This prepares for a TEE like expression in nftables. We want to ensure only one duplicate is sent, so both will use the same percpu variable to detect duplication. The other use case is detection of recursive call to xtables, but since we don't want dependency from nft to xtables core its put into core.c instead of the x_tables core. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter.h | 11 +++++++++++ net/netfilter/core.c | 3 +++ net/netfilter/xt_TEE.c | 13 ++++++------- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index 9bbd110ec81be..e01da73ee6c4c 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -390,4 +390,15 @@ extern struct nfq_ct_hook __rcu *nfq_ct_hook; static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} #endif +/** + * nf_skb_duplicated - TEE target has sent a packet + * + * When a xtables target sends a packet, the OUTPUT and POSTROUTING + * hooks are traversed again, i.e. nft and xtables are invoked recursively. + * + * This is used by xtables TEE target to prevent the duplicated skb from + * being duplicated again. + */ +DECLARE_PER_CPU(bool, nf_skb_duplicated); + #endif /*__LINUX_NETFILTER_H*/ diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 56ead1a1711c9..6896cee8b7334 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -34,6 +34,9 @@ EXPORT_SYMBOL(nf_afinfo); const struct nf_ipv6_ops __rcu *nf_ipv6_ops __read_mostly; EXPORT_SYMBOL_GPL(nf_ipv6_ops); +DEFINE_PER_CPU(bool, nf_skb_duplicated); +EXPORT_SYMBOL_GPL(nf_skb_duplicated); + int nf_register_afinfo(const struct nf_afinfo *afinfo) { mutex_lock(&afinfo_mutex); diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index a747eb475b68e..8950e79c4dc93 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c @@ -37,7 +37,6 @@ struct xt_tee_priv { }; static const union nf_inet_addr tee_zero_address; -static DEFINE_PER_CPU(bool, tee_active); static struct net *pick_net(struct sk_buff *skb) { @@ -88,7 +87,7 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) const struct xt_tee_tginfo *info = par->targinfo; struct iphdr *iph; - if (__this_cpu_read(tee_active)) + if (__this_cpu_read(nf_skb_duplicated)) return XT_CONTINUE; /* * Copy the skb, and route the copy. Will later return %XT_CONTINUE for @@ -125,9 +124,9 @@ tee_tg4(struct sk_buff *skb, const struct xt_action_param *par) ip_send_check(iph); if (tee_tg_route4(skb, info)) { - __this_cpu_write(tee_active, true); + __this_cpu_write(nf_skb_duplicated, true); ip_local_out(skb); - __this_cpu_write(tee_active, false); + __this_cpu_write(nf_skb_duplicated, false); } else { kfree_skb(skb); } @@ -170,7 +169,7 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) { const struct xt_tee_tginfo *info = par->targinfo; - if (__this_cpu_read(tee_active)) + if (__this_cpu_read(nf_skb_duplicated)) return XT_CONTINUE; skb = pskb_copy(skb, GFP_ATOMIC); if (skb == NULL) @@ -188,9 +187,9 @@ tee_tg6(struct sk_buff *skb, const struct xt_action_param *par) --iph->hop_limit; } if (tee_tg_route6(skb, info)) { - __this_cpu_write(tee_active, true); + __this_cpu_write(nf_skb_duplicated, true); ip6_local_out(skb); - __this_cpu_write(tee_active, false); + __this_cpu_write(nf_skb_duplicated, false); } else { kfree_skb(skb); } -- GitLab From 7814b6ec6d0d63444abdb49554166c8cfcbd063e Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Jul 2015 17:51:08 +0200 Subject: [PATCH 0884/7006] netfilter: xtables: don't save/restore jumpstack offset In most cases there is no reentrancy into ip/ip6tables. For skbs sent by REJECT or SYNPROXY targets, there is one level of reentrancy, but its not relevant as those targets issue an absolute verdict, i.e. the jumpstack can be clobbered since its not used after the target issues absolute verdict (ACCEPT, DROP, STOLEN, etc). So the only special case where it is relevant is the TEE target, which returns XT_CONTINUE. This patch changes ip(6)_do_table to always use the jump stack starting from 0. When we detect we're operating on an skb sent via TEE (percpu nf_skb_duplicated is 1) we switch to an alternate stack to leave the original one alone. Since there is no TEE support for arptables, it doesn't need to test if tee is active. The jump stack overflow tests are no longer needed as well -- since ->stacksize is the largest call depth we cannot exceed it. A much better alternative to the external jumpstack would be to just declare a jumps[32] stack on the local stack frame, but that would mean we'd have to reject iptables rulesets that used to work before. Another alternative would be to start rejecting rulesets with a larger call depth, e.g. 1000 -- in this case it would be feasible to allocate the entire stack in the percpu area which would avoid one dereference. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/x_tables.h | 1 - net/ipv4/netfilter/arp_tables.c | 11 +++------ net/ipv4/netfilter/ip_tables.c | 37 ++++++++++++++++-------------- net/ipv6/netfilter/ip6_tables.c | 26 +++++++++++---------- net/netfilter/x_tables.c | 22 +++++++++--------- 5 files changed, 48 insertions(+), 49 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 286098a5667f5..149284557ca70 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -222,7 +222,6 @@ struct xt_table_info { * @stacksize jumps (number of user chains) can possibly be made. */ unsigned int stacksize; - unsigned int __percpu *stackptr; void ***jumpstack; unsigned char entries[0] __aligned(8); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index ae6d0a1242133..969fdbe6fbb5b 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -280,6 +280,9 @@ unsigned int arpt_do_table(struct sk_buff *skb, table_base = private->entries; jumpstack = (struct arpt_entry **)private->jumpstack[cpu]; + /* No TEE support for arptables, so no need to switch to alternate + * stack. All targets that reenter must return absolute verdicts. + */ e = get_entry(table_base, private->hook_entry[hook]); acpar.in = state->in; @@ -325,11 +328,6 @@ unsigned int arpt_do_table(struct sk_buff *skb, } if (table_base + v != arpt_next_entry(e)) { - - if (stackidx >= private->stacksize) { - verdict = NF_DROP; - break; - } jumpstack[stackidx++] = e; } @@ -337,9 +335,6 @@ unsigned int arpt_do_table(struct sk_buff *skb, continue; } - /* Targets which reenter must return - * abs. verdicts - */ acpar.target = t->u.kernel.target; acpar.targinfo = t->data; verdict = t->u.kernel.target->target(skb, &acpar); diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 5e44b35a8de82..a2e4b018a254f 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -296,12 +296,13 @@ ipt_do_table(struct sk_buff *skb, const char *indev, *outdev; const void *table_base; struct ipt_entry *e, **jumpstack; - unsigned int *stackptr, origptr, cpu; + unsigned int stackidx, cpu; const struct xt_table_info *private; struct xt_action_param acpar; unsigned int addend; /* Initialization */ + stackidx = 0; ip = ip_hdr(skb); indev = state->in ? state->in->name : nulldevname; outdev = state->out ? state->out->name : nulldevname; @@ -331,13 +332,20 @@ ipt_do_table(struct sk_buff *skb, smp_read_barrier_depends(); table_base = private->entries; jumpstack = (struct ipt_entry **)private->jumpstack[cpu]; - stackptr = per_cpu_ptr(private->stackptr, cpu); - origptr = *stackptr; + + /* Switch to alternate jumpstack if we're being invoked via TEE. + * TEE issues XT_CONTINUE verdict on original skb so we must not + * clobber the jumpstack. + * + * For recursion via REJECT or SYNPROXY the stack will be clobbered + * but it is no problem since absolute verdict is issued by these. + */ + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); e = get_entry(table_base, private->hook_entry[hook]); - pr_debug("Entering %s(hook %u); sp at %u (UF %p)\n", - table->name, hook, origptr, + pr_debug("Entering %s(hook %u), UF %p\n", + table->name, hook, get_entry(table_base, private->underflow[hook])); do { @@ -383,28 +391,24 @@ ipt_do_table(struct sk_buff *skb, verdict = (unsigned int)(-v) - 1; break; } - if (*stackptr <= origptr) { + if (stackidx == 0) { e = get_entry(table_base, private->underflow[hook]); pr_debug("Underflow (this is normal) " "to %p\n", e); } else { - e = jumpstack[--*stackptr]; + e = jumpstack[--stackidx]; pr_debug("Pulled %p out from pos %u\n", - e, *stackptr); + e, stackidx); e = ipt_next_entry(e); } continue; } if (table_base + v != ipt_next_entry(e) && !(e->ip.flags & IPT_F_GOTO)) { - if (*stackptr >= private->stacksize) { - verdict = NF_DROP; - break; - } - jumpstack[(*stackptr)++] = e; + jumpstack[stackidx++] = e; pr_debug("Pushed %p into pos %u\n", - e, *stackptr - 1); + e, stackidx - 1); } e = get_entry(table_base, v); @@ -423,9 +427,8 @@ ipt_do_table(struct sk_buff *skb, /* Verdict */ break; } while (!acpar.hotdrop); - pr_debug("Exiting %s; resetting sp from %u to %u\n", - __func__, *stackptr, origptr); - *stackptr = origptr; + pr_debug("Exiting %s; sp at %u\n", __func__, stackidx); + xt_write_recseq_end(addend); local_bh_enable(); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index baf0321799182..531281f0ff86e 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -324,12 +324,13 @@ ip6t_do_table(struct sk_buff *skb, const char *indev, *outdev; const void *table_base; struct ip6t_entry *e, **jumpstack; - unsigned int *stackptr, origptr, cpu; + unsigned int stackidx, cpu; const struct xt_table_info *private; struct xt_action_param acpar; unsigned int addend; /* Initialization */ + stackidx = 0; indev = state->in ? state->in->name : nulldevname; outdev = state->out ? state->out->name : nulldevname; /* We handle fragments by dealing with the first fragment as @@ -357,8 +358,15 @@ ip6t_do_table(struct sk_buff *skb, cpu = smp_processor_id(); table_base = private->entries; jumpstack = (struct ip6t_entry **)private->jumpstack[cpu]; - stackptr = per_cpu_ptr(private->stackptr, cpu); - origptr = *stackptr; + + /* Switch to alternate jumpstack if we're being invoked via TEE. + * TEE issues XT_CONTINUE verdict on original skb so we must not + * clobber the jumpstack. + * + * For recursion via REJECT or SYNPROXY the stack will be clobbered + * but it is no problem since absolute verdict is issued by these. + */ + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); e = get_entry(table_base, private->hook_entry[hook]); @@ -406,20 +414,16 @@ ip6t_do_table(struct sk_buff *skb, verdict = (unsigned int)(-v) - 1; break; } - if (*stackptr <= origptr) + if (stackidx == 0) e = get_entry(table_base, private->underflow[hook]); else - e = ip6t_next_entry(jumpstack[--*stackptr]); + e = ip6t_next_entry(jumpstack[--stackidx]); continue; } if (table_base + v != ip6t_next_entry(e) && !(e->ipv6.flags & IP6T_F_GOTO)) { - if (*stackptr >= private->stacksize) { - verdict = NF_DROP; - break; - } - jumpstack[(*stackptr)++] = e; + jumpstack[stackidx++] = e; } e = get_entry(table_base, v); @@ -437,8 +441,6 @@ ip6t_do_table(struct sk_buff *skb, break; } while (!acpar.hotdrop); - *stackptr = origptr; - xt_write_recseq_end(addend); local_bh_enable(); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 4db7d60d42fae..154447e519ab1 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -67,9 +67,6 @@ static const char *const xt_prefix[NFPROTO_NUMPROTO] = { [NFPROTO_IPV6] = "ip6", }; -/* Allow this many total (re)entries. */ -static const unsigned int xt_jumpstack_multiplier = 2; - /* Registration hooks for targets. */ int xt_register_target(struct xt_target *target) { @@ -688,8 +685,6 @@ void xt_free_table_info(struct xt_table_info *info) kvfree(info->jumpstack); } - free_percpu(info->stackptr); - kvfree(info); } EXPORT_SYMBOL(xt_free_table_info); @@ -737,10 +732,6 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) unsigned int size; int cpu; - i->stackptr = alloc_percpu(unsigned int); - if (i->stackptr == NULL) - return -ENOMEM; - size = sizeof(void **) * nr_cpu_ids; if (size > PAGE_SIZE) i->jumpstack = vzalloc(size); @@ -753,8 +744,17 @@ static int xt_jumpstack_alloc(struct xt_table_info *i) if (i->stacksize == 0) return 0; - i->stacksize *= xt_jumpstack_multiplier; - size = sizeof(void *) * i->stacksize; + /* Jumpstack needs to be able to record two full callchains, one + * from the first rule set traversal, plus one table reentrancy + * via -j TEE without clobbering the callchain that brought us to + * TEE target. + * + * This is done by allocating two jumpstacks per cpu, on reentry + * the upper half of the stack is used. + * + * see the jumpstack setup in ipt_do_table() for more details. + */ + size = sizeof(void *) * i->stacksize * 2u; for_each_possible_cpu(cpu) { if (size > PAGE_SIZE) i->jumpstack[cpu] = vmalloc_node(size, -- GitLab From dcebd3153e0a7749bb054ab73fa4e1ca33e9d3f9 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Jul 2015 17:51:09 +0200 Subject: [PATCH 0885/7006] netfilter: add and use jump label for xt_tee Don't bother testing if we need to switch to alternate stack unless TEE target is used. Suggested-by: Eric Dumazet Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- include/linux/netfilter/x_tables.h | 7 +++++++ net/ipv4/netfilter/ip_tables.c | 3 ++- net/ipv6/netfilter/ip6_tables.c | 3 ++- net/netfilter/x_tables.c | 3 +++ net/netfilter/xt_TEE.c | 2 ++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h index 149284557ca70..b006b719183fc 100644 --- a/include/linux/netfilter/x_tables.h +++ b/include/linux/netfilter/x_tables.h @@ -3,6 +3,7 @@ #include +#include #include /** @@ -280,6 +281,12 @@ void xt_free_table_info(struct xt_table_info *info); */ DECLARE_PER_CPU(seqcount_t, xt_recseq); +/* xt_tee_enabled - true if x_tables needs to handle reentrancy + * + * Enabled if current ip(6)tables ruleset has at least one -j TEE rule. + */ +extern struct static_key xt_tee_enabled; + /** * xt_write_recseq_begin - start of a write section * diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index a2e4b018a254f..ff585bdbf850a 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -340,7 +340,8 @@ ipt_do_table(struct sk_buff *skb, * For recursion via REJECT or SYNPROXY the stack will be clobbered * but it is no problem since absolute verdict is issued by these. */ - jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); + if (static_key_false(&xt_tee_enabled)) + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); e = get_entry(table_base, private->hook_entry[hook]); diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 531281f0ff86e..ea6d105063c2d 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -366,7 +366,8 @@ ip6t_do_table(struct sk_buff *skb, * For recursion via REJECT or SYNPROXY the stack will be clobbered * but it is no problem since absolute verdict is issued by these. */ - jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); + if (static_key_false(&xt_tee_enabled)) + jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated); e = get_entry(table_base, private->hook_entry[hook]); diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 154447e519ab1..9b42b5ea6dcd6 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c @@ -727,6 +727,9 @@ EXPORT_SYMBOL_GPL(xt_compat_unlock); DEFINE_PER_CPU(seqcount_t, xt_recseq); EXPORT_PER_CPU_SYMBOL_GPL(xt_recseq); +struct static_key xt_tee_enabled __read_mostly; +EXPORT_SYMBOL_GPL(xt_tee_enabled); + static int xt_jumpstack_alloc(struct xt_table_info *i) { unsigned int size; diff --git a/net/netfilter/xt_TEE.c b/net/netfilter/xt_TEE.c index 8950e79c4dc93..c5d6556dbc5e4 100644 --- a/net/netfilter/xt_TEE.c +++ b/net/netfilter/xt_TEE.c @@ -251,6 +251,7 @@ static int tee_tg_check(const struct xt_tgchk_param *par) } else info->priv = NULL; + static_key_slow_inc(&xt_tee_enabled); return 0; } @@ -262,6 +263,7 @@ static void tee_tg_destroy(const struct xt_tgdtor_param *par) unregister_netdevice_notifier(&info->priv->notifier); kfree(info->priv); } + static_key_slow_dec(&xt_tee_enabled); } static struct xt_target tee_tg_reg[] __read_mostly = { -- GitLab From 6c7941dee9c41d6ab5a8be06ec44aa579a6123e1 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 14 Jul 2015 17:51:10 +0200 Subject: [PATCH 0886/7006] netfilter: xtables: remove __pure annotation sparse complains: ip_tables.c:361:27: warning: incorrect type in assignment (different modifiers) ip_tables.c:361:27: expected struct ipt_entry *[assigned] e ip_tables.c:361:27: got struct ipt_entry [pure] * doesn't change generated code. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/arp_tables.c | 2 +- net/ipv4/netfilter/ip_tables.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 969fdbe6fbb5b..c416cb355cb0c 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -240,7 +240,7 @@ get_entry(const void *base, unsigned int offset) return (struct arpt_entry *)(base + offset); } -static inline __pure +static inline struct arpt_entry *arpt_next_entry(const struct arpt_entry *entry) { return (void *)entry + entry->next_offset; diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index ff585bdbf850a..787f99ed55e26 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -276,7 +276,7 @@ static void trace_packet(const struct sk_buff *skb, } #endif -static inline __pure +static inline struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry) { return (void *)entry + entry->next_offset; diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index ea6d105063c2d..4e21f80228be2 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -305,7 +305,7 @@ static void trace_packet(const struct sk_buff *skb, } #endif -static inline __pure struct ip6t_entry * +static inline struct ip6t_entry * ip6t_next_entry(const struct ip6t_entry *entry) { return (void *)entry + entry->next_offset; -- GitLab From 231b86b1d81a75e5212329e2c42faefddcaa9208 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jul 2015 23:02:38 +0900 Subject: [PATCH 0887/7006] ASoC: Fix warning while make xmldocs caused by soc-core.c This patch fix following warning while make xmldocs. Warning(.//sound/soc/soc-core.c:2148): No description found for parameter 'ratio' Add missing ":" Signed-off-by: Masanari Iida Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0e3f973..68e54144467e6 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2127,7 +2127,7 @@ EXPORT_SYMBOL_GPL(snd_soc_codec_set_pll); /** * snd_soc_dai_set_bclk_ratio - configure BCLK to sample rate ratio. * @dai: DAI - * @ratio Ratio of BCLK to Sample rate. + * @ratio: Ratio of BCLK to Sample rate. * * Configures the DAI for a preset BCLK to sample rate ratio. */ -- GitLab From 7d1442b4c4142d94a83451d4e7a11db8aee132ab Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 15 Jul 2015 23:02:39 +0900 Subject: [PATCH 0888/7006] ASoC: Fix warning caused by a typo in comments of snd_soc_add_platform() This patch fix following warnings. Warning(.//sound/soc/soc-core.c:2855): No description found for parameter 'platform_drv' Warning(.//sound/soc/soc-core.c:2855): Excess function parameter 'platform_driver' description in 'snd_soc_add_platform' Signed-off-by: Masanari Iida Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 68e54144467e6..90d6335de17a8 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2838,7 +2838,7 @@ static void snd_soc_platform_drv_remove(struct snd_soc_component *component) * snd_soc_add_platform - Add a platform to the ASoC core * @dev: The parent device for the platform * @platform: The platform to add - * @platform_driver: The driver for the platform + * @platform_drv: The driver for the platform */ int snd_soc_add_platform(struct device *dev, struct snd_soc_platform *platform, const struct snd_soc_platform_driver *platform_drv) -- GitLab From 8225d3853f34f6cf9caff15d8c385a528e0d7cb1 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 21 Nov 2014 10:06:01 -0500 Subject: [PATCH 0889/7006] seccomp: Replace smp_read_barrier_depends() with lockless_dereference() Recently lockless_dereference() was added which can be used in place of hard-coding smp_read_barrier_depends(). The following PATCH makes the change. Signed-off-by: Pranith Kumar Signed-off-by: Kees Cook --- kernel/seccomp.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 4f44028943e66..980fd26da22e0 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -175,17 +175,16 @@ static int seccomp_check_filter(struct sock_filter *filter, unsigned int flen) */ static u32 seccomp_run_filters(struct seccomp_data *sd) { - struct seccomp_filter *f = ACCESS_ONCE(current->seccomp.filter); struct seccomp_data sd_local; u32 ret = SECCOMP_RET_ALLOW; + /* Make sure cross-thread synced filter points somewhere sane. */ + struct seccomp_filter *f = + lockless_dereference(current->seccomp.filter); /* Ensure unexpected behavior doesn't result in failing open. */ if (unlikely(WARN_ON(f == NULL))) return SECCOMP_RET_KILL; - /* Make sure cross-thread synced filter points somewhere sane. */ - smp_read_barrier_depends(); - if (!sd) { populate_seccomp_data(&sd_local); sd = &sd_local; -- GitLab From 13c4a90119d28cfcb6b5bdd820c233b86c2b0237 Mon Sep 17 00:00:00 2001 From: Tycho Andersen Date: Sat, 13 Jun 2015 09:02:48 -0600 Subject: [PATCH 0890/7006] seccomp: add ptrace options for suspend/resume This patch is the first step in enabling checkpoint/restore of processes with seccomp enabled. One of the things CRIU does while dumping tasks is inject code into them via ptrace to collect information that is only available to the process itself. However, if we are in a seccomp mode where these processes are prohibited from making these syscalls, then what CRIU does kills the task. This patch adds a new ptrace option, PTRACE_O_SUSPEND_SECCOMP, that enables a task from the init user namespace which has CAP_SYS_ADMIN and no seccomp filters to disable (and re-enable) seccomp filters for another task so that they can be successfully dumped (and restored). We restrict the set of processes that can disable seccomp through ptrace because although today ptrace can be used to bypass seccomp, there is some discussion of closing this loophole in the future and we would like this patch to not depend on that behavior and be future proofed for when it is removed. Note that seccomp can be suspended before any filters are actually installed; this behavior is useful on criu restore, so that we can suspend seccomp, restore the filters, unmap our restore code from the restored process' address space, and then resume the task by detaching and have the filters resumed as well. v2 changes: * require that the tracer have no seccomp filters installed * drop TIF_NOTSC manipulation from the patch * change from ptrace command to a ptrace option and use this ptrace option as the flag to check. This means that as soon as the tracer detaches/dies, seccomp is re-enabled and as a corrollary that one can not disable seccomp across PTRACE_ATTACHs. v3 changes: * get rid of various #ifdefs everywhere * report more sensible errors when PTRACE_O_SUSPEND_SECCOMP is incorrectly used v4 changes: * get rid of may_suspend_seccomp() in favor of a capable() check in ptrace directly v5 changes: * check that seccomp is not enabled (or suspended) on the tracer Signed-off-by: Tycho Andersen CC: Will Drewry CC: Roland McGrath CC: Pavel Emelyanov CC: Serge E. Hallyn Acked-by: Oleg Nesterov Acked-by: Andy Lutomirski [kees: access seccomp.mode through seccomp_mode() instead] Signed-off-by: Kees Cook --- include/linux/ptrace.h | 1 + include/uapi/linux/ptrace.h | 6 ++++-- kernel/ptrace.c | 13 +++++++++++++ kernel/seccomp.c | 8 ++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h index 987a73a40ef84..061265f928767 100644 --- a/include/linux/ptrace.h +++ b/include/linux/ptrace.h @@ -34,6 +34,7 @@ #define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP) #define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT) +#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT) /* single stepping state bits (used on ARM and PA-RISC) */ #define PT_SINGLESTEP_BIT 31 diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h index cf1019e15f5bc..a7a6979866144 100644 --- a/include/uapi/linux/ptrace.h +++ b/include/uapi/linux/ptrace.h @@ -89,9 +89,11 @@ struct ptrace_peeksiginfo_args { #define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP) /* eventless options */ -#define PTRACE_O_EXITKILL (1 << 20) +#define PTRACE_O_EXITKILL (1 << 20) +#define PTRACE_O_SUSPEND_SECCOMP (1 << 21) -#define PTRACE_O_MASK (0x000000ff | PTRACE_O_EXITKILL) +#define PTRACE_O_MASK (\ + 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP) #include diff --git a/kernel/ptrace.c b/kernel/ptrace.c index c8e0e050a36af..787320de68e02 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -556,6 +556,19 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data) if (data & ~(unsigned long)PTRACE_O_MASK) return -EINVAL; + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { + if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) || + !config_enabled(CONFIG_SECCOMP)) + return -EINVAL; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || + current->ptrace & PT_SUSPEND_SECCOMP) + return -EPERM; + } + /* Avoid intermediate state when all opts are cleared */ flags = child->ptrace; flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT); diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 980fd26da22e0..645e42d6fa4d2 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -590,6 +590,10 @@ void secure_computing_strict(int this_syscall) { int mode = current->seccomp.mode; + if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && + unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) + return; + if (mode == 0) return; else if (mode == SECCOMP_MODE_STRICT) @@ -691,6 +695,10 @@ u32 seccomp_phase1(struct seccomp_data *sd) int this_syscall = sd ? sd->nr : syscall_get_nr(current, task_pt_regs(current)); + if (config_enabled(CONFIG_CHECKPOINT_RESTORE) && + unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) + return SECCOMP_PHASE1_OK; + switch (mode) { case SECCOMP_MODE_STRICT: __secure_computing_strict(this_syscall); /* may call do_exit */ -- GitLab From 221272f97ca528048a577a3ff23d7774286ca5fd Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Mon, 15 Jun 2015 15:29:16 -0700 Subject: [PATCH 0891/7006] seccomp: swap hard-coded zeros to defined name For clarity, if CONFIG_SECCOMP isn't defined, seccomp_mode() is returning "disabled". This makes that more clear, along with another 0-use, and results in no operational change. Signed-off-by: Kees Cook --- include/linux/seccomp.h | 2 +- kernel/seccomp.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h index a19ddacdac30a..f4265039a94c8 100644 --- a/include/linux/seccomp.h +++ b/include/linux/seccomp.h @@ -78,7 +78,7 @@ static inline long prctl_set_seccomp(unsigned long arg2, char __user *arg3) static inline int seccomp_mode(struct seccomp *s) { - return 0; + return SECCOMP_MODE_DISABLED; } #endif /* CONFIG_SECCOMP */ diff --git a/kernel/seccomp.c b/kernel/seccomp.c index 645e42d6fa4d2..383bd6caca815 100644 --- a/kernel/seccomp.c +++ b/kernel/seccomp.c @@ -594,7 +594,7 @@ void secure_computing_strict(int this_syscall) unlikely(current->ptrace & PT_SUSPEND_SECCOMP)) return; - if (mode == 0) + if (mode == SECCOMP_MODE_DISABLED) return; else if (mode == SECCOMP_MODE_STRICT) __secure_computing_strict(this_syscall); -- GitLab From db3b0fcc5adbda0c7060c9298c2514778547fee2 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 12 Jun 2015 18:20:35 +0200 Subject: [PATCH 0892/7006] gpio: generic: add get_direction support Allow to determine the current direction configuration by reading back from the direction register. Signed-off-by: Philipp Zabel Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 9bda3727fac12..802e6d2c64e9e 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -302,6 +302,14 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ? + GPIOF_DIR_OUT : GPIOF_DIR_IN; +} + static int bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -351,6 +359,14 @@ static int bgpio_dir_out_inv(struct gpio_chip *gc, unsigned int gpio, int val) return 0; } +static int bgpio_get_dir_inv(struct gpio_chip *gc, unsigned int gpio) +{ + struct bgpio_chip *bgc = to_bgpio_chip(gc); + + return (bgc->read_reg(bgc->reg_dir) & bgc->pin2mask(bgc, gpio)) ? + GPIOF_DIR_IN : GPIOF_DIR_OUT; +} + static int bgpio_setup_accessors(struct device *dev, struct bgpio_chip *bgc, bool bit_be, @@ -468,10 +484,12 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, bgc->reg_dir = dirout; bgc->gc.direction_output = bgpio_dir_out; bgc->gc.direction_input = bgpio_dir_in; + bgc->gc.get_direction = bgpio_get_dir; } else if (dirin) { bgc->reg_dir = dirin; bgc->gc.direction_output = bgpio_dir_out_inv; bgc->gc.direction_input = bgpio_dir_in_inv; + bgc->gc.get_direction = bgpio_get_dir_inv; } else { bgc->gc.direction_output = bgpio_simple_dir_out; bgc->gc.direction_input = bgpio_simple_dir_in; -- GitLab From d32651f68785bd8d73b24481b62e428ca30a2546 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Wed, 17 Jun 2015 15:42:11 +0200 Subject: [PATCH 0893/7006] gpiolib: Fix docs for gpiochip_add_pingroup_range gpiochip_add_pingroup_range() has a pctldev argument, not pinctrl. Signed-off-by: Tomeu Vizoso Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c38..b1b08b3fa626a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -671,7 +671,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {} /** * gpiochip_add_pingroup_range() - add a range for GPIO <-> pin mapping * @chip: the gpiochip to add the range for - * @pinctrl: the dev_name() of the pin controller to map to + * @pctldev: the pin controller to map to * @gpio_offset: the start offset in the current gpio_chip number space * @pin_group: name of the pin group inside the pin controller */ -- GitLab From 7c50181b69ce65b0a7db6936aca26f86b70e4436 Mon Sep 17 00:00:00 2001 From: Gregory Fong Date: Wed, 17 Jun 2015 18:00:41 -0700 Subject: [PATCH 0894/7006] dt-bindings: brcmstb-gpio: document properties for wakeup Some brcmstb GPIO controllers can be used to wake from suspend, so use the de facto standard property 'wakeup-source' to mark the nodes of controllers with that capability. Also document interrupts-extended, which will be used for wakeup handling because the interrupt parent for the wake IRQ is different from the regular IRQ. While we're at it, a few more fixes: We don't actually use the "interrupt-names" property, so remove it from the listed optional properties and from the examples. And since we're modifying the examples, also follow Brian's suggestions to: - change #gpio-cells, #interrupt-cells, and brcm,gpio-bank-widths from hex to dec - use phandles Reviewed-by: Brian Norris Signed-off-by: Gregory Fong Signed-off-by: Linus Walleij --- .../bindings/gpio/brcm,brcmstb-gpio.txt | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt index 435f1bcca3415..b405b4410bfb8 100644 --- a/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt +++ b/Documentation/devicetree/bindings/gpio/brcm,brcmstb-gpio.txt @@ -33,6 +33,13 @@ Optional properties: - interrupt-parent: phandle of the parent interrupt controller +- interrupts-extended: + Alternate form of specifying interrupts and parents that allows for + multiple parents. This takes precedence over 'interrupts' and + 'interrupt-parent'. Wakeup-capable GPIO controllers often route their + wakeup interrupt lines through a different interrupt controller than the + primary interrupt line, making this property necessary. + - #interrupt-cells: Should be <2>. The first cell is the GPIO number, the second should specify flags. The following subset of flags is supported: @@ -47,19 +54,33 @@ Optional properties: - interrupt-controller: Marks the device node as an interrupt controller -- interrupt-names: - The name of the IRQ resource used by this controller +- wakeup-source: + GPIOs for this controller can be used as a wakeup source Example: upg_gio: gpio@f040a700 { - #gpio-cells = <0x2>; - #interrupt-cells = <0x2>; + #gpio-cells = <2>; + #interrupt-cells = <2>; compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio"; gpio-controller; interrupt-controller; reg = <0xf040a700 0x80>; - interrupt-parent = <0xf>; + interrupt-parent = <&irq0_intc>; + interrupts = <0x6>; + brcm,gpio-bank-widths = <32 32 32 24>; + }; + + upg_gio_aon: gpio@f04172c0 { + #gpio-cells = <2>; + #interrupt-cells = <2>; + compatible = "brcm,bcm7445-gpio", "brcm,brcmstb-gpio"; + gpio-controller; + interrupt-controller; + reg = <0xf04172c0 0x40>; + interrupt-parent = <&irq0_aon_intc>; interrupts = <0x6>; - interrupt-names = "upg_gio"; - brcm,gpio-bank-widths = <0x20 0x20 0x20 0x18>; + interrupts-extended = <&irq0_aon_intc 0x6>, + <&aon_pm_l2_intc 0x5>; + wakeup-source; + brcm,gpio-bank-widths = <18 4>; }; -- GitLab From 80d2bf55a1257a277a808128f377ac69216b6587 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 17 Jun 2015 17:51:41 +0900 Subject: [PATCH 0895/7006] gpio: zynq: add missing module_exit function This driver is tristate, so it should be cleanable. Signed-off-by: Masahiro Yamada Tested-by: Michal Simek Signed-off-by: Linus Walleij --- drivers/gpio/gpio-zynq.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c index 2e87c4b8da26d..399c4be9e63cb 100644 --- a/drivers/gpio/gpio-zynq.c +++ b/drivers/gpio/gpio-zynq.c @@ -781,6 +781,12 @@ static int __init zynq_gpio_init(void) } postcore_initcall(zynq_gpio_init); +static void __exit zynq_gpio_exit(void) +{ + platform_driver_unregister(&zynq_gpio_driver); +} +module_exit(zynq_gpio_exit); + MODULE_AUTHOR("Xilinx Inc."); MODULE_DESCRIPTION("Zynq GPIO driver"); MODULE_LICENSE("GPL"); -- GitLab From d58ec58f40dc188fbb08edaa8c17840f71fe8a0e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Jun 2015 20:31:02 +0900 Subject: [PATCH 0896/7006] gpio: altera: kill bogus dependency on GPIO_GENERIC The driver gpio-altera.c does not depend on gpio-generic.c at all. Drop unneeded "select GPIO_GENERIC". Signed-off-by: Masahiro Yamada Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 8f1fe739c985e..29c2340bffe93 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -113,7 +113,6 @@ config GPIO_74XX_MMIO config GPIO_ALTERA tristate "Altera GPIO" depends on OF_GPIO - select GPIO_GENERIC select GPIOLIB_IRQCHIP help Say Y or M here to build support for the Altera PIO device. -- GitLab From 1c8b5d688d7ef401c209f3fc84b7de8296f8908a Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 17 Jun 2015 20:59:43 +0900 Subject: [PATCH 0897/7006] gpio: altera: fix return value of altera_gpio_remove() The remove callback never succeeds, which seems odd. Signed-off-by: Masahiro Yamada Reviewed-by: Alexandre Courbot Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- drivers/gpio/gpio-altera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 0f3d336d6303e..675d15d6e9be7 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -340,7 +340,7 @@ static int altera_gpio_remove(struct platform_device *pdev) gpiochip_remove(&altera_gc->mmchip.gc); - return -EIO; + return 0; } static const struct of_device_id altera_gpio_of_match[] = { -- GitLab From 41ec66c92299889ad30871aeede89b960f08a458 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 17 Jun 2015 20:59:42 +0900 Subject: [PATCH 0898/7006] gpio: altera: use of_mm_gpiochip_remove() to fix memory leak This driver calls of_mm_gpiochip_add() to add a memory mapped gpio chip. So, of_mm_gpiochip_remove() should be used when removing it. The direct call of gpiochip_remove() misses unmapping the register and freeing the label. Signed-off-by: Masahiro Yamada Reviewed-by: Alexandre Courbot Acked-by: Tien Hock Loh Signed-off-by: Linus Walleij --- drivers/gpio/gpio-altera.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-altera.c b/drivers/gpio/gpio-altera.c index 675d15d6e9be7..9b7e0b3db3872 100644 --- a/drivers/gpio/gpio-altera.c +++ b/drivers/gpio/gpio-altera.c @@ -338,7 +338,7 @@ static int altera_gpio_remove(struct platform_device *pdev) { struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev); - gpiochip_remove(&altera_gc->mmchip.gc); + of_mm_gpiochip_remove(&altera_gc->mmchip); return 0; } -- GitLab From 4c52bd5c61118a47166ed5857f17698ce520b5fd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 19 Jun 2015 20:31:03 +0900 Subject: [PATCH 0899/7006] gpio: mvebu: kill bogus dependency on GPIO_GENERIC The driver gpio-mvebu.c does not depend on gpio-generic.c at all. Drop unneeded "select GPIO_GENERIC". Signed-off-by: Masahiro Yamada Acked-by: Gregory CLEMENT Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 29c2340bffe93..4c9fa58c56434 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -307,7 +307,6 @@ config GPIO_MVEBU def_bool y depends on PLAT_ORION depends on OF - select GPIO_GENERIC select GENERIC_IRQ_CHIP config GPIO_MXC -- GitLab From 39561e8bbb49752092b6afd9764d3f3aeef4e1d2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 10:01:44 +0900 Subject: [PATCH 0900/7006] gpio: of: remove unnecessary variable in of_get_gpio_hog() The variable "desc" is only used for storing the return value at the end of the function. It is unneeded. Signed-off-by: Masahiro Yamada Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 9a0ec48a47375..fd2db4b3a709e 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -136,7 +136,6 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np, { struct device_node *chip_np; enum of_gpio_flags xlate_flags; - struct gpio_desc *desc; struct gg_data gg_data = { .flags = &xlate_flags, }; @@ -193,9 +192,7 @@ static struct gpio_desc *of_get_gpio_hog(struct device_node *np, if (name && of_property_read_string(np, "line-name", name)) *name = np->name; - desc = gg_data.out_gpio; - - return desc; + return gg_data.out_gpio; } /** -- GitLab From aa57aca8e15a4e11749640e16ac9814f14be24d2 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 16 Jul 2015 02:01:28 +0200 Subject: [PATCH 0901/7006] ACPI / PM: Update the copyright notice and description of power.c The description and copyright notice of drivers/acpi/power.c is out of date, so update it as appropriate. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/power.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 93eac53b5110b..ce68ae68840d9 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c @@ -1,8 +1,10 @@ /* - * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $) + * drivers/acpi/power.c - ACPI Power Resources management. * - * Copyright (C) 2001, 2002 Andy Grover - * Copyright (C) 2001, 2002 Paul Diefenbaugh + * Copyright (C) 2001 - 2015 Intel Corp. + * Author: Andy Grover + * Author: Paul Diefenbaugh + * Author: Rafael J. Wysocki * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * @@ -27,10 +29,11 @@ * ACPI power-managed devices may be controlled in two ways: * 1. via "Device Specific (D-State) Control" * 2. via "Power Resource Control". - * This module is used to manage devices relying on Power Resource Control. + * The code below deals with ACPI Power Resources control. * - * An ACPI "power resource object" describes a software controllable power - * plane, clock plane, or other resource used by a power managed device. + * An ACPI "power resource object" represents a software controllable power + * plane, clock plane, or other resource depended on by a device. + * * A device may rely on multiple power resources, and a power resource * may be shared by multiple devices. */ -- GitLab From 76f31e8b0911e620ac9191c8d3775cc91ed65c4c Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:03 +0300 Subject: [PATCH 0902/7006] gianfar: Bundle Rx allocation, cleanup Use a more common consumer/ producer index design to improve rx buffer allocation. Instead of allocating a single new buffer (skb) on each iteration, bundle the allocation of several rx buffers at a time. This also opens the path for further memory optimizations. Remove useless check of rxq->rfbptr, since this patch touches rx pause frame handling code as well. rxq->rfbptr is always initialized as part of Rx BD ring init. Remove redundant (and misleading) 'amount_pull' parameter. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 201 +++++++++--------- drivers/net/ethernet/freescale/gianfar.h | 39 +++- .../net/ethernet/freescale/gianfar_ethtool.c | 3 + 3 files changed, 136 insertions(+), 107 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index ff875028fdff5..b35bf3de44e0d 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -116,8 +116,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); static void gfar_reset_task(struct work_struct *work); static void gfar_timeout(struct net_device *dev); static int gfar_close(struct net_device *dev); -static struct sk_buff *gfar_new_skb(struct net_device *dev, - dma_addr_t *bufaddr); +static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, + int alloc_cnt); static int gfar_set_mac_address(struct net_device *dev); static int gfar_change_mtu(struct net_device *dev, int new_mtu); static irqreturn_t gfar_error(int irq, void *dev_id); @@ -142,7 +142,7 @@ static void gfar_netpoll(struct net_device *dev); int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int amount_pull, struct napi_struct *napi); + struct napi_struct *napi); static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, @@ -169,17 +169,15 @@ static void gfar_init_rxbdp(struct gfar_priv_rx_q *rx_queue, struct rxbd8 *bdp, bdp->lstatus = cpu_to_be32(lstatus); } -static int gfar_init_bds(struct net_device *ndev) +static void gfar_init_bds(struct net_device *ndev) { struct gfar_private *priv = netdev_priv(ndev); struct gfar __iomem *regs = priv->gfargrp[0].regs; struct gfar_priv_tx_q *tx_queue = NULL; struct gfar_priv_rx_q *rx_queue = NULL; struct txbd8 *txbdp; - struct rxbd8 *rxbdp; u32 __iomem *rfbptr; int i, j; - dma_addr_t bufaddr; for (i = 0; i < priv->num_tx_queues; i++) { tx_queue = priv->tx_queue[i]; @@ -207,33 +205,18 @@ static int gfar_init_bds(struct net_device *ndev) rfbptr = ®s->rfbptr0; for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - rx_queue->cur_rx = rx_queue->rx_bd_base; - rx_queue->skb_currx = 0; - rxbdp = rx_queue->rx_bd_base; - - for (j = 0; j < rx_queue->rx_ring_size; j++) { - struct sk_buff *skb = rx_queue->rx_skbuff[j]; - if (skb) { - bufaddr = be32_to_cpu(rxbdp->bufPtr); - } else { - skb = gfar_new_skb(ndev, &bufaddr); - if (!skb) { - netdev_err(ndev, "Can't allocate RX buffers\n"); - return -ENOMEM; - } - rx_queue->rx_skbuff[j] = skb; - } + rx_queue->next_to_clean = 0; + rx_queue->next_to_use = 0; - gfar_init_rxbdp(rx_queue, rxbdp, bufaddr); - rxbdp++; - } + /* make sure next_to_clean != next_to_use after this + * by leaving at least 1 unused descriptor + */ + gfar_alloc_rx_buffs(rx_queue, gfar_rxbd_unused(rx_queue)); rx_queue->rfbptr = rfbptr; rfbptr += 2; } - - return 0; } static int gfar_alloc_skb_resources(struct net_device *ndev) @@ -311,8 +294,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) rx_queue->rx_skbuff[j] = NULL; } - if (gfar_init_bds(ndev)) - goto cleanup; + gfar_init_bds(ndev); return 0; @@ -1639,10 +1621,7 @@ static int gfar_restore(struct device *dev) return 0; } - if (gfar_init_bds(ndev)) { - free_skb_resources(priv); - return -ENOMEM; - } + gfar_init_bds(ndev); gfar_mac_reset(priv); @@ -2704,30 +2683,19 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static struct sk_buff *gfar_alloc_skb(struct net_device *dev) +static struct sk_buff *gfar_new_skb(struct net_device *ndev, + dma_addr_t *bufaddr) { - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); struct sk_buff *skb; + dma_addr_t addr; - skb = netdev_alloc_skb(dev, priv->rx_buffer_size + RXBUF_ALIGNMENT); + skb = netdev_alloc_skb(ndev, priv->rx_buffer_size + RXBUF_ALIGNMENT); if (!skb) return NULL; gfar_align_skb(skb); - return skb; -} - -static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) -{ - struct gfar_private *priv = netdev_priv(dev); - struct sk_buff *skb; - dma_addr_t addr; - - skb = gfar_alloc_skb(dev); - if (!skb) - return NULL; - addr = dma_map_single(priv->dev, skb->data, priv->rx_buffer_size, DMA_FROM_DEVICE); if (unlikely(dma_mapping_error(priv->dev, addr))) { @@ -2739,6 +2707,55 @@ static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr) return skb; } +static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) +{ + struct gfar_private *priv = netdev_priv(rx_queue->dev); + struct gfar_extra_stats *estats = &priv->extra_stats; + + netdev_err(rx_queue->dev, "Can't alloc RX buffers\n"); + atomic64_inc(&estats->rx_alloc_err); +} + +static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, + int alloc_cnt) +{ + struct net_device *ndev = rx_queue->dev; + struct rxbd8 *bdp, *base; + dma_addr_t bufaddr; + int i; + + i = rx_queue->next_to_use; + base = rx_queue->rx_bd_base; + bdp = &rx_queue->rx_bd_base[i]; + + while (alloc_cnt--) { + struct sk_buff *skb = rx_queue->rx_skbuff[i]; + + if (likely(!skb)) { + skb = gfar_new_skb(ndev, &bufaddr); + if (unlikely(!skb)) { + gfar_rx_alloc_err(rx_queue); + break; + } + } else { /* restore from sleep state */ + bufaddr = be32_to_cpu(bdp->bufPtr); + } + + rx_queue->rx_skbuff[i] = skb; + + /* Setup the new RxBD */ + gfar_init_rxbdp(rx_queue, bdp, bufaddr); + + /* Update to the next pointer */ + bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0; + } + + rx_queue->next_to_use = i; +} + static inline void count_errors(unsigned short status, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); @@ -2838,7 +2855,7 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int amount_pull, struct napi_struct *napi) + struct napi_struct *napi) { struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; @@ -2849,9 +2866,9 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, /* Remove the FCB from the skb * Remove the padded bytes, if there are any */ - if (amount_pull) { + if (priv->uses_rxfcb) { skb_record_rx_queue(skb, fcb->rq); - skb_pull(skb, amount_pull); + skb_pull(skb, GMAC_FCB_LEN); } /* Get receive timestamp from the skb */ @@ -2895,27 +2912,30 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) struct net_device *dev = rx_queue->dev; struct rxbd8 *bdp, *base; struct sk_buff *skb; - int pkt_len; - int amount_pull; - int howmany = 0; + int i, howmany = 0; + int cleaned_cnt = gfar_rxbd_unused(rx_queue); struct gfar_private *priv = netdev_priv(dev); /* Get the first full descriptor */ - bdp = rx_queue->cur_rx; base = rx_queue->rx_bd_base; + i = rx_queue->next_to_clean; - amount_pull = priv->uses_rxfcb ? GMAC_FCB_LEN : 0; + while (rx_work_limit--) { - while (!(be16_to_cpu(bdp->status) & RXBD_EMPTY) && rx_work_limit--) { - struct sk_buff *newskb; - dma_addr_t bufaddr; + if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) { + gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); + cleaned_cnt = 0; + } - rmb(); + bdp = &rx_queue->rx_bd_base[i]; + if (be16_to_cpu(bdp->status) & RXBD_EMPTY) + break; - /* Add another skb for the future */ - newskb = gfar_new_skb(dev, &bufaddr); + /* order rx buffer descriptor reads */ + rmb(); - skb = rx_queue->rx_skbuff[rx_queue->skb_currx]; + /* fetch next to clean buffer from the ring */ + skb = rx_queue->rx_skbuff[i]; dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), priv->rx_buffer_size, DMA_FROM_DEVICE); @@ -2924,30 +2944,26 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) be16_to_cpu(bdp->length) > priv->rx_buffer_size)) bdp->status = cpu_to_be16(RXBD_LARGE); - /* We drop the frame if we failed to allocate a new buffer */ - if (unlikely(!newskb || - !(be16_to_cpu(bdp->status) & RXBD_LAST) || + if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_LAST) || be16_to_cpu(bdp->status) & RXBD_ERR)) { count_errors(be16_to_cpu(bdp->status), dev); - if (unlikely(!newskb)) { - newskb = skb; - bufaddr = be32_to_cpu(bdp->bufPtr); - } else if (skb) - dev_kfree_skb(skb); + /* discard faulty buffer */ + dev_kfree_skb(skb); + } else { /* Increment the number of packets */ rx_queue->stats.rx_packets++; howmany++; if (likely(skb)) { - pkt_len = be16_to_cpu(bdp->length) - + int pkt_len = be16_to_cpu(bdp->length) - ETH_FCS_LEN; /* Remove the FCS from the packet length */ skb_put(skb, pkt_len); rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(dev, skb, amount_pull, + gfar_process_frame(dev, skb, &rx_queue->grp->napi_rx); } else { @@ -2958,26 +2974,23 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) } - rx_queue->rx_skbuff[rx_queue->skb_currx] = newskb; - - /* Setup the new bdp */ - gfar_init_rxbdp(rx_queue, bdp, bufaddr); + rx_queue->rx_skbuff[i] = NULL; + cleaned_cnt++; + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0; + } - /* Update Last Free RxBD pointer for LFC */ - if (unlikely(rx_queue->rfbptr && priv->tx_actual_en)) - gfar_write(rx_queue->rfbptr, (u32)bdp); + rx_queue->next_to_clean = i; - /* Update to the next pointer */ - bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + if (cleaned_cnt) + gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); - /* update to point at the next skb */ - rx_queue->skb_currx = (rx_queue->skb_currx + 1) & - RX_RING_MOD_MASK(rx_queue->rx_ring_size); + /* Update Last Free RxBD pointer for LFC */ + if (unlikely(priv->tx_actual_en)) { + bdp = gfar_rxbd_lastfree(rx_queue); + gfar_write(rx_queue->rfbptr, (u32)bdp); } - /* Update the current rxbd pointer to be the next one */ - rx_queue->cur_rx = bdp; - return howmany; } @@ -3552,14 +3565,8 @@ static noinline void gfar_update_link_state(struct gfar_private *priv) if ((tempval1 & MACCFG1_TX_FLOW) && !tx_flow_oldval) { for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - bdp = rx_queue->cur_rx; - /* skip to previous bd */ - bdp = skip_bd(bdp, rx_queue->rx_ring_size - 1, - rx_queue->rx_bd_base, - rx_queue->rx_ring_size); - - if (rx_queue->rfbptr) - gfar_write(rx_queue->rfbptr, (u32)bdp); + bdp = gfar_rxbd_lastfree(rx_queue); + gfar_write(rx_queue->rfbptr, (u32)bdp); } priv->tx_actual_en = 1; diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index daa1d37de6427..cadb068cb37f7 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -92,6 +92,8 @@ extern const char gfar_driver_version[]; #define DEFAULT_TX_RING_SIZE 256 #define DEFAULT_RX_RING_SIZE 256 +#define GFAR_RX_BUFF_ALLOC 16 + #define GFAR_RX_MAX_RING_SIZE 256 #define GFAR_TX_MAX_RING_SIZE 256 @@ -640,6 +642,7 @@ struct rmon_mib }; struct gfar_extra_stats { + atomic64_t rx_alloc_err; atomic64_t rx_large; atomic64_t rx_short; atomic64_t rx_nonoctet; @@ -1015,9 +1018,9 @@ struct rx_q_stats { /** * struct gfar_priv_rx_q - per rx queue structure * @rx_skbuff: skb pointers - * @skb_currx: currently use skb pointer * @rx_bd_base: First rx buffer descriptor - * @cur_rx: Next free rx ring entry + * @next_to_use: index of the next buffer to be alloc'd + * @next_to_clean: index of the next buffer to be cleaned * @qindex: index of this queue * @dev: back pointer to the dev structure * @rx_ring_size: Rx ring size @@ -1027,19 +1030,18 @@ struct rx_q_stats { struct gfar_priv_rx_q { struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); - dma_addr_t rx_bd_dma_base; struct rxbd8 *rx_bd_base; - struct rxbd8 *cur_rx; struct net_device *dev; - struct gfar_priv_grp *grp; + struct gfar_priv_grp *grp; + u16 rx_ring_size; + u16 qindex; + u16 next_to_clean; + u16 next_to_use; struct rx_q_stats stats; - u16 skb_currx; - u16 qindex; - unsigned int rx_ring_size; - /* RX Coalescing values */ + u32 __iomem *rfbptr; unsigned char rxcoalescing; unsigned long rxic; - u32 __iomem *rfbptr; + dma_addr_t rx_bd_dma_base; }; enum gfar_irqinfo_id { @@ -1295,6 +1297,23 @@ static inline void gfar_clear_txbd_status(struct txbd8 *bdp) bdp->lstatus = cpu_to_be32(lstatus); } +static inline int gfar_rxbd_unused(struct gfar_priv_rx_q *rxq) +{ + if (rxq->next_to_clean > rxq->next_to_use) + return rxq->next_to_clean - rxq->next_to_use - 1; + + return rxq->rx_ring_size + rxq->next_to_clean - rxq->next_to_use - 1; +} + +static inline struct rxbd8 *gfar_rxbd_lastfree(struct gfar_priv_rx_q *rxq) +{ + int i; + + i = rxq->next_to_use ? rxq->next_to_use - 1 : rxq->rx_ring_size - 1; + + return &rxq->rx_bd_base[i]; +} + irqreturn_t gfar_receive(int irq, void *dev_id); int startup_gfar(struct net_device *dev); void stop_gfar(struct net_device *dev); diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index fda12fb32ec77..012fa4e79ffab 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -61,6 +61,8 @@ static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo); static const char stat_gstrings[][ETH_GSTRING_LEN] = { + /* extra stats */ + "rx-allocation-errors", "rx-large-frame-errors", "rx-short-frame-errors", "rx-non-octet-errors", @@ -74,6 +76,7 @@ static const char stat_gstrings[][ETH_GSTRING_LEN] = { "tx-underrun-errors", "rx-skb-missing-errors", "tx-timeout-errors", + /* rmon stats */ "tx-rx-64-frames", "tx-rx-65-127-frames", "tx-rx-128-255-frames", -- GitLab From f966082e2065d223942cc40e0bc4841f84f0604d Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:04 +0300 Subject: [PATCH 0903/7006] gianfar: Fix and cleanup rxbd status handling There are several (long standing) problems about how the status field of the rx buffer descriptor (rxbd) is currently handled on the error path: - too many unnecessary 16bit reads of the two halves of the rxbd status field (32bit), also resulting in overuse of endianness convesion macros; - "bdp->status = RXBD_LARGE" makes no sense, since the "large" flag is read only (only eTSEC can write it), and trying to clear the other status bits is also error prone in this context (most of the rx status bits are read only anyway). This is fixed with a single 32bit read of the "status" field, and then the appropriate 16bit shifting is applied to access the various status bits or the rx frame length. Also corrected the use of the RXBD_LARGE flag. Additional fix: "rx_over_errors" stat is incremented instead of "rx_crc_errors" in case of RXBD_OVERRUN occurrence. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 34 +++++++++++++----------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index b35bf3de44e0d..c839e7628181f 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -2756,14 +2756,14 @@ static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, rx_queue->next_to_use = i; } -static inline void count_errors(unsigned short status, struct net_device *dev) +static void count_errors(u32 lstatus, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct net_device_stats *stats = &dev->stats; struct gfar_extra_stats *estats = &priv->extra_stats; /* If the packet was truncated, none of the other errors matter */ - if (status & RXBD_TRUNCATED) { + if (lstatus & BD_LFLAG(RXBD_TRUNCATED)) { stats->rx_length_errors++; atomic64_inc(&estats->rx_trunc); @@ -2771,25 +2771,25 @@ static inline void count_errors(unsigned short status, struct net_device *dev) return; } /* Count the errors, if there were any */ - if (status & (RXBD_LARGE | RXBD_SHORT)) { + if (lstatus & BD_LFLAG(RXBD_LARGE | RXBD_SHORT)) { stats->rx_length_errors++; - if (status & RXBD_LARGE) + if (lstatus & BD_LFLAG(RXBD_LARGE)) atomic64_inc(&estats->rx_large); else atomic64_inc(&estats->rx_short); } - if (status & RXBD_NONOCTET) { + if (lstatus & BD_LFLAG(RXBD_NONOCTET)) { stats->rx_frame_errors++; atomic64_inc(&estats->rx_nonoctet); } - if (status & RXBD_CRCERR) { + if (lstatus & BD_LFLAG(RXBD_CRCERR)) { atomic64_inc(&estats->rx_crcerr); stats->rx_crc_errors++; } - if (status & RXBD_OVERRUN) { + if (lstatus & BD_LFLAG(RXBD_OVERRUN)) { atomic64_inc(&estats->rx_overrun); - stats->rx_crc_errors++; + stats->rx_over_errors++; } } @@ -2921,6 +2921,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) i = rx_queue->next_to_clean; while (rx_work_limit--) { + u32 lstatus; if (cleaned_cnt >= GFAR_RX_BUFF_ALLOC) { gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); @@ -2928,7 +2929,8 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) } bdp = &rx_queue->rx_bd_base[i]; - if (be16_to_cpu(bdp->status) & RXBD_EMPTY) + lstatus = be32_to_cpu(bdp->lstatus); + if (lstatus & BD_LFLAG(RXBD_EMPTY)) break; /* order rx buffer descriptor reads */ @@ -2940,13 +2942,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), priv->rx_buffer_size, DMA_FROM_DEVICE); - if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_ERR) && - be16_to_cpu(bdp->length) > priv->rx_buffer_size)) - bdp->status = cpu_to_be16(RXBD_LARGE); + if (unlikely(!(lstatus & BD_LFLAG(RXBD_ERR)) && + (lstatus & BD_LENGTH_MASK) > priv->rx_buffer_size)) + lstatus |= BD_LFLAG(RXBD_LARGE); - if (unlikely(!(be16_to_cpu(bdp->status) & RXBD_LAST) || - be16_to_cpu(bdp->status) & RXBD_ERR)) { - count_errors(be16_to_cpu(bdp->status), dev); + if (unlikely(!(lstatus & BD_LFLAG(RXBD_LAST)) || + (lstatus & BD_LFLAG(RXBD_ERR)))) { + count_errors(lstatus, dev); /* discard faulty buffer */ dev_kfree_skb(skb); @@ -2957,7 +2959,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) howmany++; if (likely(skb)) { - int pkt_len = be16_to_cpu(bdp->length) - + int pkt_len = (lstatus & BD_LENGTH_MASK) - ETH_FCS_LEN; /* Remove the FCS from the packet length */ skb_put(skb, pkt_len); -- GitLab From f23223f15fd7d359a08ea346a0a537ccaf417014 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:05 +0300 Subject: [PATCH 0904/7006] gianfar: Use ndev, more Rx path cleanup Use "ndev" instead of "dev", as the rx queue back pointer to a net_device struct, to avoid name clashing with a "struct device" reference. This prepares the addition of a "struct device" back pointer to the rx queue structure. Remove duplicated rxq registration in the process. Move napi_gro_receive() outside gfar_process_frame(). Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 54 +++++++++++------------- drivers/net/ethernet/freescale/gianfar.h | 4 +- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index c839e7628181f..7654d5eafeeb4 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -141,8 +141,7 @@ static void gfar_netpoll(struct net_device *dev); #endif int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit); static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue); -static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - struct napi_struct *napi); +static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb); static void gfar_halt_nodisable(struct gfar_private *priv); static void gfar_clear_exact_match(struct net_device *dev); static void gfar_set_mac_for_addr(struct net_device *dev, int num, @@ -262,7 +261,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) rx_queue = priv->rx_queue[i]; rx_queue->rx_bd_base = vaddr; rx_queue->rx_bd_dma_base = addr; - rx_queue->dev = ndev; + rx_queue->ndev = ndev; addr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; } @@ -593,7 +592,7 @@ static int gfar_alloc_rx_queues(struct gfar_private *priv) priv->rx_queue[i]->rx_skbuff = NULL; priv->rx_queue[i]->qindex = i; - priv->rx_queue[i]->dev = priv->ndev; + priv->rx_queue[i]->ndev = priv->ndev; } return 0; } @@ -1913,7 +1912,7 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue) static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) { struct rxbd8 *rxbdp; - struct gfar_private *priv = netdev_priv(rx_queue->dev); + struct gfar_private *priv = netdev_priv(rx_queue->ndev); int i; rxbdp = rx_queue->rx_bd_base; @@ -2709,17 +2708,17 @@ static struct sk_buff *gfar_new_skb(struct net_device *ndev, static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) { - struct gfar_private *priv = netdev_priv(rx_queue->dev); + struct gfar_private *priv = netdev_priv(rx_queue->ndev); struct gfar_extra_stats *estats = &priv->extra_stats; - netdev_err(rx_queue->dev, "Can't alloc RX buffers\n"); + netdev_err(rx_queue->ndev, "Can't alloc RX buffers\n"); atomic64_inc(&estats->rx_alloc_err); } static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, int alloc_cnt) { - struct net_device *ndev = rx_queue->dev; + struct net_device *ndev = rx_queue->ndev; struct rxbd8 *bdp, *base; dma_addr_t bufaddr; int i; @@ -2756,10 +2755,10 @@ static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, rx_queue->next_to_use = i; } -static void count_errors(u32 lstatus, struct net_device *dev) +static void count_errors(u32 lstatus, struct net_device *ndev) { - struct gfar_private *priv = netdev_priv(dev); - struct net_device_stats *stats = &dev->stats; + struct gfar_private *priv = netdev_priv(ndev); + struct net_device_stats *stats = &ndev->stats; struct gfar_extra_stats *estats = &priv->extra_stats; /* If the packet was truncated, none of the other errors matter */ @@ -2854,10 +2853,9 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) } /* gfar_process_frame() -- handle one incoming packet if skb isn't NULL. */ -static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - struct napi_struct *napi) +static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) { - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); struct rxfcb *fcb = NULL; /* fcb is at the beginning if exists */ @@ -2866,10 +2864,8 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, /* Remove the FCB from the skb * Remove the padded bytes, if there are any */ - if (priv->uses_rxfcb) { - skb_record_rx_queue(skb, fcb->rq); + if (priv->uses_rxfcb) skb_pull(skb, GMAC_FCB_LEN); - } /* Get receive timestamp from the skb */ if (priv->hwts_rx_en) { @@ -2883,24 +2879,20 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, if (priv->padding) skb_pull(skb, priv->padding); - if (dev->features & NETIF_F_RXCSUM) + if (ndev->features & NETIF_F_RXCSUM) gfar_rx_checksum(skb, fcb); /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, dev); + skb->protocol = eth_type_trans(skb, ndev); /* There's need to check for NETIF_F_HW_VLAN_CTAG_RX here. * Even if vlan rx accel is disabled, on some chips * RXFCB_VLN is pseudo randomly set. */ - if (dev->features & NETIF_F_HW_VLAN_CTAG_RX && + if (ndev->features & NETIF_F_HW_VLAN_CTAG_RX && be16_to_cpu(fcb->flags) & RXFCB_VLN) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(fcb->vlctl)); - - /* Send the packet up the stack */ - napi_gro_receive(napi, skb); - } /* gfar_clean_rx_ring() -- Processes each frame in the rx ring @@ -2909,12 +2901,12 @@ static void gfar_process_frame(struct net_device *dev, struct sk_buff *skb, */ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) { - struct net_device *dev = rx_queue->dev; + struct net_device *ndev = rx_queue->ndev; struct rxbd8 *bdp, *base; struct sk_buff *skb; int i, howmany = 0; int cleaned_cnt = gfar_rxbd_unused(rx_queue); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = netdev_priv(ndev); /* Get the first full descriptor */ base = rx_queue->rx_bd_base; @@ -2948,7 +2940,7 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) if (unlikely(!(lstatus & BD_LFLAG(RXBD_LAST)) || (lstatus & BD_LFLAG(RXBD_ERR)))) { - count_errors(lstatus, dev); + count_errors(lstatus, ndev); /* discard faulty buffer */ dev_kfree_skb(skb); @@ -2965,11 +2957,13 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) skb_put(skb, pkt_len); rx_queue->stats.rx_bytes += pkt_len; skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(dev, skb, - &rx_queue->grp->napi_rx); + gfar_process_frame(ndev, skb); + + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); } else { - netif_warn(priv, rx_err, dev, "Missing skb!\n"); + netif_warn(priv, rx_err, ndev, "Missing skb!\n"); rx_queue->stats.rx_dropped++; atomic64_inc(&priv->extra_stats.rx_skbmissing); } diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index cadb068cb37f7..edf8529ed3565 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -1022,7 +1022,7 @@ struct rx_q_stats { * @next_to_use: index of the next buffer to be alloc'd * @next_to_clean: index of the next buffer to be cleaned * @qindex: index of this queue - * @dev: back pointer to the dev structure + * @ndev: back pointer to net_device * @rx_ring_size: Rx ring size * @rxcoalescing: enable/disable rx-coalescing * @rxic: receive interrupt coalescing vlaue @@ -1031,7 +1031,7 @@ struct rx_q_stats { struct gfar_priv_rx_q { struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); struct rxbd8 *rx_bd_base; - struct net_device *dev; + struct net_device *ndev; struct gfar_priv_grp *grp; u16 rx_ring_size; u16 qindex; -- GitLab From 75354148ce697266b57c13d051ddffa3bb75fc9e Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Mon, 13 Jul 2015 16:22:06 +0300 Subject: [PATCH 0905/7006] gianfar: Add paged allocation and Rx S/G The eTSEC h/w is capable of scatter/gather on the receive side too if MAXFRM > MRBLR, when the allowed maximum Rx frame size is set to be greater than the maximum Rx buffer size (MRBLR). It's about time the driver makes use of this h/w capability, by supporting fixed buffer sizes and Rx S/G. The buffer size given to eTSEC for reception is fixed to 1536B (must be multiple of 64), which is the same default buffer size as before, used to accommodate standard MTU (1500B) size frames. As before, eTSEC can receive frames of up to 9600B. Individual Rx buffers are mapped to page halves (page size for eTSEC systems is 4KB). The skb is built around the first buffer of a frame (using build_skb()). In case the frame spans multiple buffers, the trailing buffers are added as Rx fragments to the skb. The last buffer in frame is marked by the L status flag. A mechanism is in place to reuse the pages owned by the driver (for Rx) for subsequent receptions. Supporting fixed size buffers allows the implementation of Rx S/G, which in turn removes the memory pressure issues the driver had before when MTU was set for jumbo frame reception. Also, in most cases, the Rx path becomes faster due to Rx page reusal, since the overhead of allocating new rx buffers is removed from the fast path. Signed-off-by: Claudiu Manoil Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/gianfar.c | 320 +++++++++++------- drivers/net/ethernet/freescale/gianfar.h | 31 +- .../net/ethernet/freescale/gianfar_ethtool.c | 1 - 3 files changed, 208 insertions(+), 144 deletions(-) diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 7654d5eafeeb4..648ca85c5859b 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -109,7 +109,7 @@ #define TX_TIMEOUT (1*HZ) -const char gfar_driver_version[] = "1.3"; +const char gfar_driver_version[] = "2.0"; static int gfar_enet_open(struct net_device *dev); static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev); @@ -207,6 +207,7 @@ static void gfar_init_bds(struct net_device *ndev) rx_queue->next_to_clean = 0; rx_queue->next_to_use = 0; + rx_queue->next_to_alloc = 0; /* make sure next_to_clean != next_to_use after this * by leaving at least 1 unused descriptor @@ -222,7 +223,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) { void *vaddr; dma_addr_t addr; - int i, j, k; + int i, j; struct gfar_private *priv = netdev_priv(ndev); struct device *dev = priv->dev; struct gfar_priv_tx_q *tx_queue = NULL; @@ -262,6 +263,7 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) rx_queue->rx_bd_base = vaddr; rx_queue->rx_bd_dma_base = addr; rx_queue->ndev = ndev; + rx_queue->dev = dev; addr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; vaddr += sizeof(struct rxbd8) * rx_queue->rx_ring_size; } @@ -276,21 +278,17 @@ static int gfar_alloc_skb_resources(struct net_device *ndev) if (!tx_queue->tx_skbuff) goto cleanup; - for (k = 0; k < tx_queue->tx_ring_size; k++) - tx_queue->tx_skbuff[k] = NULL; + for (j = 0; j < tx_queue->tx_ring_size; j++) + tx_queue->tx_skbuff[j] = NULL; } for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - rx_queue->rx_skbuff = - kmalloc_array(rx_queue->rx_ring_size, - sizeof(*rx_queue->rx_skbuff), - GFP_KERNEL); - if (!rx_queue->rx_skbuff) + rx_queue->rx_buff = kcalloc(rx_queue->rx_ring_size, + sizeof(*rx_queue->rx_buff), + GFP_KERNEL); + if (!rx_queue->rx_buff) goto cleanup; - - for (j = 0; j < rx_queue->rx_ring_size; j++) - rx_queue->rx_skbuff[j] = NULL; } gfar_init_bds(ndev); @@ -335,10 +333,8 @@ static void gfar_init_rqprm(struct gfar_private *priv) } } -static void gfar_rx_buff_size_config(struct gfar_private *priv) +static void gfar_rx_offload_en(struct gfar_private *priv) { - int frame_size = priv->ndev->mtu + ETH_HLEN + ETH_FCS_LEN; - /* set this when rx hw offload (TOE) functions are being used */ priv->uses_rxfcb = 0; @@ -347,16 +343,6 @@ static void gfar_rx_buff_size_config(struct gfar_private *priv) if (priv->hwts_rx_en) priv->uses_rxfcb = 1; - - if (priv->uses_rxfcb) - frame_size += GMAC_FCB_LEN; - - frame_size += priv->padding; - - frame_size = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + - INCREMENTAL_BUFFER_SIZE; - - priv->rx_buffer_size = frame_size; } static void gfar_mac_rx_config(struct gfar_private *priv) @@ -590,7 +576,6 @@ static int gfar_alloc_rx_queues(struct gfar_private *priv) if (!priv->rx_queue[i]) return -ENOMEM; - priv->rx_queue[i]->rx_skbuff = NULL; priv->rx_queue[i]->qindex = i; priv->rx_queue[i]->ndev = priv->ndev; } @@ -1184,12 +1169,11 @@ void gfar_mac_reset(struct gfar_private *priv) udelay(3); - /* Compute rx_buff_size based on config flags */ - gfar_rx_buff_size_config(priv); + gfar_rx_offload_en(priv); /* Initialize the max receive frame/buffer lengths */ - gfar_write(®s->maxfrm, priv->rx_buffer_size); - gfar_write(®s->mrblr, priv->rx_buffer_size); + gfar_write(®s->maxfrm, GFAR_JUMBO_FRAME_SIZE); + gfar_write(®s->mrblr, GFAR_RXB_SIZE); /* Initialize the Minimum Frame Length Register */ gfar_write(®s->minflr, MINFLR_INIT_SETTINGS); @@ -1197,12 +1181,11 @@ void gfar_mac_reset(struct gfar_private *priv) /* Initialize MACCFG2. */ tempval = MACCFG2_INIT_SETTINGS; - /* If the mtu is larger than the max size for standard - * ethernet frames (ie, a jumbo frame), then set maccfg2 - * to allow huge frames, and to check the length + /* eTSEC74 erratum: Rx frames of length MAXFRM or MAXFRM-1 + * are marked as truncated. Avoid this by MACCFG2[Huge Frame]=1, + * and by checking RxBD[LG] and discarding larger than MAXFRM. */ - if (priv->rx_buffer_size > DEFAULT_RX_BUFFER_SIZE || - gfar_has_errata(priv, GFAR_ERRATA_74)) + if (gfar_has_errata(priv, GFAR_ERRATA_74)) tempval |= MACCFG2_HUGEFRAME | MACCFG2_LENGTHCHECK; gfar_write(®s->maccfg2, tempval); @@ -1413,8 +1396,6 @@ static int gfar_probe(struct platform_device *ofdev) priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) dev->needed_headroom = GMAC_FCB_LEN; - priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; - /* Initializing some of the rx/tx queue level parameters */ for (i = 0; i < priv->num_tx_queues; i++) { priv->tx_queue[i]->tx_ring_size = DEFAULT_TX_RING_SIZE; @@ -1911,26 +1892,32 @@ static void free_skb_tx_queue(struct gfar_priv_tx_q *tx_queue) static void free_skb_rx_queue(struct gfar_priv_rx_q *rx_queue) { - struct rxbd8 *rxbdp; - struct gfar_private *priv = netdev_priv(rx_queue->ndev); int i; - rxbdp = rx_queue->rx_bd_base; + struct rxbd8 *rxbdp = rx_queue->rx_bd_base; + + if (rx_queue->skb) + dev_kfree_skb(rx_queue->skb); for (i = 0; i < rx_queue->rx_ring_size; i++) { - if (rx_queue->rx_skbuff[i]) { - dma_unmap_single(priv->dev, be32_to_cpu(rxbdp->bufPtr), - priv->rx_buffer_size, - DMA_FROM_DEVICE); - dev_kfree_skb_any(rx_queue->rx_skbuff[i]); - rx_queue->rx_skbuff[i] = NULL; - } + struct gfar_rx_buff *rxb = &rx_queue->rx_buff[i]; + rxbdp->lstatus = 0; rxbdp->bufPtr = 0; rxbdp++; + + if (!rxb->page) + continue; + + dma_unmap_single(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); + __free_page(rxb->page); + + rxb->page = NULL; } - kfree(rx_queue->rx_skbuff); - rx_queue->rx_skbuff = NULL; + + kfree(rx_queue->rx_buff); + rx_queue->rx_buff = NULL; } /* If there are any tx skbs or rx skbs still around, free them. @@ -1955,7 +1942,7 @@ static void free_skb_resources(struct gfar_private *priv) for (i = 0; i < priv->num_rx_queues; i++) { rx_queue = priv->rx_queue[i]; - if (rx_queue->rx_skbuff) + if (rx_queue->rx_buff) free_skb_rx_queue(rx_queue); } @@ -2513,7 +2500,7 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) struct gfar_private *priv = netdev_priv(dev); int frame_size = new_mtu + ETH_HLEN; - if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { + if ((frame_size < 64) || (frame_size > GFAR_JUMBO_FRAME_SIZE)) { netif_err(priv, drv, dev, "Invalid MTU setting\n"); return -EINVAL; } @@ -2567,15 +2554,6 @@ static void gfar_timeout(struct net_device *dev) schedule_work(&priv->reset_task); } -static void gfar_align_skb(struct sk_buff *skb) -{ - /* We need the data buffer to be aligned properly. We will reserve - * as many bytes as needed to align the data properly - */ - skb_reserve(skb, RXBUF_ALIGNMENT - - (((unsigned long) skb->data) & (RXBUF_ALIGNMENT - 1))); -} - /* Interrupt Handler for Transmit complete */ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) { @@ -2682,28 +2660,27 @@ static void gfar_clean_tx_ring(struct gfar_priv_tx_q *tx_queue) netdev_tx_completed_queue(txq, howmany, bytes_sent); } -static struct sk_buff *gfar_new_skb(struct net_device *ndev, - dma_addr_t *bufaddr) +static bool gfar_new_page(struct gfar_priv_rx_q *rxq, struct gfar_rx_buff *rxb) { - struct gfar_private *priv = netdev_priv(ndev); - struct sk_buff *skb; + struct page *page; dma_addr_t addr; - skb = netdev_alloc_skb(ndev, priv->rx_buffer_size + RXBUF_ALIGNMENT); - if (!skb) - return NULL; + page = dev_alloc_page(); + if (unlikely(!page)) + return false; - gfar_align_skb(skb); + addr = dma_map_page(rxq->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(rxq->dev, addr))) { + __free_page(page); - addr = dma_map_single(priv->dev, skb->data, - priv->rx_buffer_size, DMA_FROM_DEVICE); - if (unlikely(dma_mapping_error(priv->dev, addr))) { - dev_kfree_skb_any(skb); - return NULL; + return false; } - *bufaddr = addr; - return skb; + rxb->dma = addr; + rxb->page = page; + rxb->page_offset = 0; + + return true; } static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) @@ -2718,41 +2695,40 @@ static void gfar_rx_alloc_err(struct gfar_priv_rx_q *rx_queue) static void gfar_alloc_rx_buffs(struct gfar_priv_rx_q *rx_queue, int alloc_cnt) { - struct net_device *ndev = rx_queue->ndev; - struct rxbd8 *bdp, *base; - dma_addr_t bufaddr; + struct rxbd8 *bdp; + struct gfar_rx_buff *rxb; int i; i = rx_queue->next_to_use; - base = rx_queue->rx_bd_base; bdp = &rx_queue->rx_bd_base[i]; + rxb = &rx_queue->rx_buff[i]; while (alloc_cnt--) { - struct sk_buff *skb = rx_queue->rx_skbuff[i]; - - if (likely(!skb)) { - skb = gfar_new_skb(ndev, &bufaddr); - if (unlikely(!skb)) { + /* try reuse page */ + if (unlikely(!rxb->page)) { + if (unlikely(!gfar_new_page(rx_queue, rxb))) { gfar_rx_alloc_err(rx_queue); break; } - } else { /* restore from sleep state */ - bufaddr = be32_to_cpu(bdp->bufPtr); } - rx_queue->rx_skbuff[i] = skb; - /* Setup the new RxBD */ - gfar_init_rxbdp(rx_queue, bdp, bufaddr); + gfar_init_rxbdp(rx_queue, bdp, + rxb->dma + rxb->page_offset + RXBUF_ALIGNMENT); /* Update to the next pointer */ - bdp = next_bd(bdp, base, rx_queue->rx_ring_size); + bdp++; + rxb++; - if (unlikely(++i == rx_queue->rx_ring_size)) + if (unlikely(++i == rx_queue->rx_ring_size)) { i = 0; + bdp = rx_queue->rx_bd_base; + rxb = rx_queue->rx_buff; + } } rx_queue->next_to_use = i; + rx_queue->next_to_alloc = i; } static void count_errors(u32 lstatus, struct net_device *ndev) @@ -2839,6 +2815,93 @@ static irqreturn_t gfar_transmit(int irq, void *grp_id) return IRQ_HANDLED; } +static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus, + struct sk_buff *skb, bool first) +{ + unsigned int size = lstatus & BD_LENGTH_MASK; + struct page *page = rxb->page; + + /* Remove the FCS from the packet length */ + if (likely(lstatus & BD_LFLAG(RXBD_LAST))) + size -= ETH_FCS_LEN; + + if (likely(first)) + skb_put(skb, size); + else + skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, + rxb->page_offset + RXBUF_ALIGNMENT, + size, GFAR_RXB_TRUESIZE); + + /* try reuse page */ + if (unlikely(page_count(page) != 1)) + return false; + + /* change offset to the other half */ + rxb->page_offset ^= GFAR_RXB_TRUESIZE; + + atomic_inc(&page->_count); + + return true; +} + +static void gfar_reuse_rx_page(struct gfar_priv_rx_q *rxq, + struct gfar_rx_buff *old_rxb) +{ + struct gfar_rx_buff *new_rxb; + u16 nta = rxq->next_to_alloc; + + new_rxb = &rxq->rx_buff[nta]; + + /* find next buf that can reuse a page */ + nta++; + rxq->next_to_alloc = (nta < rxq->rx_ring_size) ? nta : 0; + + /* copy page reference */ + *new_rxb = *old_rxb; + + /* sync for use by the device */ + dma_sync_single_range_for_device(rxq->dev, old_rxb->dma, + old_rxb->page_offset, + GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE); +} + +static struct sk_buff *gfar_get_next_rxbuff(struct gfar_priv_rx_q *rx_queue, + u32 lstatus, struct sk_buff *skb) +{ + struct gfar_rx_buff *rxb = &rx_queue->rx_buff[rx_queue->next_to_clean]; + struct page *page = rxb->page; + bool first = false; + + if (likely(!skb)) { + void *buff_addr = page_address(page) + rxb->page_offset; + + skb = build_skb(buff_addr, GFAR_SKBFRAG_SIZE); + if (unlikely(!skb)) { + gfar_rx_alloc_err(rx_queue); + return NULL; + } + skb_reserve(skb, RXBUF_ALIGNMENT); + first = true; + } + + dma_sync_single_range_for_cpu(rx_queue->dev, rxb->dma, rxb->page_offset, + GFAR_RXB_TRUESIZE, DMA_FROM_DEVICE); + + if (gfar_add_rx_frag(rxb, lstatus, skb, first)) { + /* reuse the free half of the page */ + gfar_reuse_rx_page(rx_queue, rxb); + } else { + /* page cannot be reused, unmap it */ + dma_unmap_page(rx_queue->dev, rxb->dma, + PAGE_SIZE, DMA_FROM_DEVICE); + } + + /* clear rxb content */ + rxb->page = NULL; + + return skb; +} + static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) { /* If valid headers were found, and valid sums @@ -2902,14 +2965,14 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb) int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) { struct net_device *ndev = rx_queue->ndev; - struct rxbd8 *bdp, *base; - struct sk_buff *skb; + struct gfar_private *priv = netdev_priv(ndev); + struct rxbd8 *bdp; int i, howmany = 0; + struct sk_buff *skb = rx_queue->skb; int cleaned_cnt = gfar_rxbd_unused(rx_queue); - struct gfar_private *priv = netdev_priv(ndev); + unsigned int total_bytes = 0, total_pkts = 0; /* Get the first full descriptor */ - base = rx_queue->rx_bd_base; i = rx_queue->next_to_clean; while (rx_work_limit--) { @@ -2929,54 +2992,51 @@ int gfar_clean_rx_ring(struct gfar_priv_rx_q *rx_queue, int rx_work_limit) rmb(); /* fetch next to clean buffer from the ring */ - skb = rx_queue->rx_skbuff[i]; + skb = gfar_get_next_rxbuff(rx_queue, lstatus, skb); + if (unlikely(!skb)) + break; - dma_unmap_single(priv->dev, be32_to_cpu(bdp->bufPtr), - priv->rx_buffer_size, DMA_FROM_DEVICE); + cleaned_cnt++; + howmany++; - if (unlikely(!(lstatus & BD_LFLAG(RXBD_ERR)) && - (lstatus & BD_LENGTH_MASK) > priv->rx_buffer_size)) - lstatus |= BD_LFLAG(RXBD_LARGE); + if (unlikely(++i == rx_queue->rx_ring_size)) + i = 0; + + rx_queue->next_to_clean = i; + + /* fetch next buffer if not the last in frame */ + if (!(lstatus & BD_LFLAG(RXBD_LAST))) + continue; - if (unlikely(!(lstatus & BD_LFLAG(RXBD_LAST)) || - (lstatus & BD_LFLAG(RXBD_ERR)))) { + if (unlikely(lstatus & BD_LFLAG(RXBD_ERR))) { count_errors(lstatus, ndev); /* discard faulty buffer */ dev_kfree_skb(skb); + skb = NULL; + rx_queue->stats.rx_dropped++; + continue; + } - } else { - /* Increment the number of packets */ - rx_queue->stats.rx_packets++; - howmany++; - - if (likely(skb)) { - int pkt_len = (lstatus & BD_LENGTH_MASK) - - ETH_FCS_LEN; - /* Remove the FCS from the packet length */ - skb_put(skb, pkt_len); - rx_queue->stats.rx_bytes += pkt_len; - skb_record_rx_queue(skb, rx_queue->qindex); - gfar_process_frame(ndev, skb); - - /* Send the packet up the stack */ - napi_gro_receive(&rx_queue->grp->napi_rx, skb); + /* Increment the number of packets */ + total_pkts++; + total_bytes += skb->len; - } else { - netif_warn(priv, rx_err, ndev, "Missing skb!\n"); - rx_queue->stats.rx_dropped++; - atomic64_inc(&priv->extra_stats.rx_skbmissing); - } + skb_record_rx_queue(skb, rx_queue->qindex); - } + gfar_process_frame(ndev, skb); - rx_queue->rx_skbuff[i] = NULL; - cleaned_cnt++; - if (unlikely(++i == rx_queue->rx_ring_size)) - i = 0; + /* Send the packet up the stack */ + napi_gro_receive(&rx_queue->grp->napi_rx, skb); + + skb = NULL; } - rx_queue->next_to_clean = i; + /* Store incomplete frames for completion */ + rx_queue->skb = skb; + + rx_queue->stats.rx_packets += total_pkts; + rx_queue->stats.rx_bytes += total_bytes; if (cleaned_cnt) gfar_alloc_rx_buffs(rx_queue, cleaned_cnt); diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index edf8529ed3565..44021243c187c 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -71,11 +71,6 @@ struct ethtool_rx_list { /* Number of bytes to align the rx bufs to */ #define RXBUF_ALIGNMENT 64 -/* The number of bytes which composes a unit for the purpose of - * allocating data buffers. ie-for any given MTU, the data buffer - * will be the next highest multiple of 512 bytes. */ -#define INCREMENTAL_BUFFER_SIZE 512 - #define PHY_INIT_TIMEOUT 100000 #define DRV_NAME "gfar-enet" @@ -105,11 +100,14 @@ extern const char gfar_driver_version[]; #define DEFAULT_RX_LFC_THR 16 #define DEFAULT_LFC_PTVVAL 4 -#define DEFAULT_RX_BUFFER_SIZE 1536 +#define GFAR_RXB_SIZE 1536 +#define GFAR_SKBFRAG_SIZE (RXBUF_ALIGNMENT + GFAR_RXB_SIZE \ + + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define GFAR_RXB_TRUESIZE 2048 + #define TX_RING_MOD_MASK(size) (size-1) #define RX_RING_MOD_MASK(size) (size-1) -#define JUMBO_BUFFER_SIZE 9728 -#define JUMBO_FRAME_SIZE 9600 +#define GFAR_JUMBO_FRAME_SIZE 9600 #define DEFAULT_FIFO_TX_THR 0x100 #define DEFAULT_FIFO_TX_STARVE 0x40 @@ -654,7 +652,6 @@ struct gfar_extra_stats { atomic64_t eberr; atomic64_t tx_babt; atomic64_t tx_underrun; - atomic64_t rx_skbmissing; atomic64_t tx_timeout; }; @@ -1015,9 +1012,15 @@ struct rx_q_stats { unsigned long rx_dropped; }; +struct gfar_rx_buff { + dma_addr_t dma; + struct page *page; + unsigned int page_offset; +}; + /** * struct gfar_priv_rx_q - per rx queue structure - * @rx_skbuff: skb pointers + * @rx_buff: Array of buffer info metadata structs * @rx_bd_base: First rx buffer descriptor * @next_to_use: index of the next buffer to be alloc'd * @next_to_clean: index of the next buffer to be cleaned @@ -1029,14 +1032,17 @@ struct rx_q_stats { */ struct gfar_priv_rx_q { - struct sk_buff **rx_skbuff __aligned(SMP_CACHE_BYTES); + struct gfar_rx_buff *rx_buff __aligned(SMP_CACHE_BYTES); struct rxbd8 *rx_bd_base; struct net_device *ndev; - struct gfar_priv_grp *grp; + struct device *dev; u16 rx_ring_size; u16 qindex; + struct gfar_priv_grp *grp; u16 next_to_clean; u16 next_to_use; + u16 next_to_alloc; + struct sk_buff *skb; struct rx_q_stats stats; u32 __iomem *rfbptr; unsigned char rxcoalescing; @@ -1111,7 +1117,6 @@ struct gfar_private { struct device *dev; struct net_device *ndev; enum gfar_errata errata; - unsigned int rx_buffer_size; u16 uses_rxfcb; u16 padding; diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 012fa4e79ffab..3020aaabf0e40 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -74,7 +74,6 @@ static const char stat_gstrings[][ETH_GSTRING_LEN] = { "ethernet-bus-error", "tx-babbling-errors", "tx-underrun-errors", - "rx-skb-missing-errors", "tx-timeout-errors", /* rmon stats */ "tx-rx-64-frames", -- GitLab From e29dd44325e2fe121088094dcb3055c8d9e5202a Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Mon, 13 Jul 2015 21:51:38 +0200 Subject: [PATCH 0906/7006] net: qlcnic: Deletion of unnecessary memset There is no need to memset memory allocated with vzalloc. Signed-off-by: Christophe JAILLET Acked-by: Shahed Shaikh Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c index 2f6cc423ab1df..7dbab3c20db58 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c @@ -2403,7 +2403,6 @@ int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter, qlcnic_free_tx_rings(adapter); return -ENOMEM; } - memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring)); tx_ring->cmd_buf_arr = cmd_buf_arr; spin_lock_init(&tx_ring->tx_clean_lock); } -- GitLab From 40bdc5360d0919b537e27d7c3feb78fd784c31f5 Mon Sep 17 00:00:00 2001 From: Andrea Parri Date: Tue, 14 Jul 2015 00:12:05 +0200 Subject: [PATCH 0907/7006] pkt_sched: sch_qfq: remove unused member of struct qfq_sched The member (u32) "num_active_agg" of struct qfq_sched has been unused since its introduction in 462dbc9101acd38e92eda93c0726857517a24bbd "pkt_sched: QFQ Plus: fair-queueing service at DRR cost" and (AFAICT) there is no active plan to use it; this removes the member. Signed-off-by: Andrea Parri Acked-by: Paolo Valente Signed-off-by: David S. Miller --- net/sched/sch_qfq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index b8d73bca683cc..ffaeea63d4738 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -186,7 +186,6 @@ struct qfq_sched { u64 oldV, V; /* Precise virtual times. */ struct qfq_aggregate *in_serv_agg; /* Aggregate being served. */ - u32 num_active_agg; /* Num. of active aggregates */ u32 wsum; /* weight sum */ u32 iwsum; /* inverse weight sum */ -- GitLab From a01e72fbc41e322ed229465de8b595a7e3ec6549 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 15 Jul 2015 21:49:41 -0400 Subject: [PATCH 0908/7006] tools/power turbostat: fix parameter passing for forked command turbostat supports forked command when sampling cpu state. However, the forked command is not allowed to be executed with options, otherwise turbostat might regard these options as invalid turbostat options. For example: ./turbostat stress -c 4 -t 10 ./turbostat: unrecognized option '-t' Reported-by: Chen Yu Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 5a793bed453a3..915eb2846a2d6 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -3118,7 +3118,7 @@ void cmdline(int argc, char **argv) progname = argv[0]; - while ((opt = getopt_long_only(argc, argv, "C:c:Ddhi:JM:m:PpST:v", + while ((opt = getopt_long_only(argc, argv, "+C:c:Ddhi:JM:m:PpST:v", long_options, &option_index)) != -1) { switch (opt) { case 'C': -- GitLab From 3b476aadbc1409fef6be85f601117f2c6a331faa Mon Sep 17 00:00:00 2001 From: Vipin K Parashar Date: Wed, 8 Jul 2015 16:36:01 +0530 Subject: [PATCH 0909/7006] powerpc/powernv: Add poweroff (EPOW, DPO) events support for PowerNV platform This patch adds support for OPAL EPOW (Environmental and Power Warnings) and DPO (Delayed Power Off) events for the PowerNV platform. These events are generated on FSP (Flexible Service Processor) based systems. EPOW events are generated due to various critical system conditions that require system shutdown. A few examples of these conditions are high ambient temperature or system running on UPS power with low UPS battery. DPO event is generated in response to admin initiated system shutdown request. Upon receipt of EPOW and DPO events the host kernel invokes orderly_poweroff() for performing graceful system shutdown. Signed-off-by: Vipin K Parashar Acked-by: Vaibhav Jain Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/opal-api.h | 40 +++++ arch/powerpc/include/asm/opal.h | 3 +- arch/powerpc/platforms/powernv/opal-power.c | 147 ++++++++++++++++-- .../powerpc/platforms/powernv/opal-wrappers.S | 1 + 4 files changed, 173 insertions(+), 18 deletions(-) diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h index e9e4c52f36854..442995bacb339 100644 --- a/arch/powerpc/include/asm/opal-api.h +++ b/arch/powerpc/include/asm/opal-api.h @@ -756,6 +756,46 @@ struct opal_i2c_request { __be64 buffer_ra; /* Buffer real address */ }; +/* + * EPOW status sharing (OPAL and the host) + * + * The host will pass on OPAL, a buffer of length OPAL_SYSEPOW_MAX + * with individual elements being 16 bits wide to fetch the system + * wide EPOW status. Each element in the buffer will contain the + * EPOW status in it's bit representation for a particular EPOW sub + * class as defiend here. So multiple detailed EPOW status bits + * specific for any sub class can be represented in a single buffer + * element as it's bit representation. + */ + +/* System EPOW type */ +enum OpalSysEpow { + OPAL_SYSEPOW_POWER = 0, /* Power EPOW */ + OPAL_SYSEPOW_TEMP = 1, /* Temperature EPOW */ + OPAL_SYSEPOW_COOLING = 2, /* Cooling EPOW */ + OPAL_SYSEPOW_MAX = 3, /* Max EPOW categories */ +}; + +/* Power EPOW */ +enum OpalSysPower { + OPAL_SYSPOWER_UPS = 0x0001, /* System on UPS power */ + OPAL_SYSPOWER_CHNG = 0x0002, /* System power config change */ + OPAL_SYSPOWER_FAIL = 0x0004, /* System impending power failure */ + OPAL_SYSPOWER_INCL = 0x0008, /* System incomplete power */ +}; + +/* Temperature EPOW */ +enum OpalSysTemp { + OPAL_SYSTEMP_AMB = 0x0001, /* System over ambient temperature */ + OPAL_SYSTEMP_INT = 0x0002, /* System over internal temperature */ + OPAL_SYSTEMP_HMD = 0x0004, /* System over ambient humidity */ +}; + +/* Cooling EPOW */ +enum OpalSysCooling { + OPAL_SYSCOOL_INSF = 0x0001, /* System insufficient cooling */ +}; + #endif /* __ASSEMBLY__ */ #endif /* __OPAL_API_H */ diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h index 958e941c0cda8..a091c2701d943 100644 --- a/arch/powerpc/include/asm/opal.h +++ b/arch/powerpc/include/asm/opal.h @@ -141,7 +141,8 @@ int64_t opal_pci_fence_phb(uint64_t phb_id); int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data); int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action); int64_t opal_set_slot_led_status(uint64_t phb_id, uint64_t slot_id, uint8_t led_type, uint8_t led_action); -int64_t opal_get_epow_status(__be64 *status); +int64_t opal_get_epow_status(__be16 *epow_status, __be16 *num_epow_classes); +int64_t opal_get_dpo_status(__be64 *dpo_timeout); int64_t opal_set_system_attention_led(uint8_t led_action); int64_t opal_pci_next_error(uint64_t phb_id, __be64 *first_frozen_pe, __be16 *pci_error_type, __be16 *severity); diff --git a/arch/powerpc/platforms/powernv/opal-power.c b/arch/powerpc/platforms/powernv/opal-power.c index ac46c2c24f99e..58dc3308237f6 100644 --- a/arch/powerpc/platforms/powernv/opal-power.c +++ b/arch/powerpc/platforms/powernv/opal-power.c @@ -9,9 +9,12 @@ * 2 of the License, or (at your option) any later version. */ +#define pr_fmt(fmt) "opal-power: " fmt + #include #include #include +#include #include #include @@ -19,30 +22,116 @@ #define SOFT_OFF 0x00 #define SOFT_REBOOT 0x01 +/* Detect EPOW event */ +static bool detect_epow(void) +{ + u16 epow; + int i, rc; + __be16 epow_classes; + __be16 opal_epow_status[OPAL_SYSEPOW_MAX] = {0}; + + /* + * Check for EPOW event. Kernel sends supported EPOW classes info + * to OPAL. OPAL returns EPOW info along with classes present. + */ + epow_classes = cpu_to_be16(OPAL_SYSEPOW_MAX); + rc = opal_get_epow_status(opal_epow_status, &epow_classes); + if (rc != OPAL_SUCCESS) { + pr_err("Failed to get EPOW event information\n"); + return false; + } + + /* Look for EPOW events present */ + for (i = 0; i < be16_to_cpu(epow_classes); i++) { + epow = be16_to_cpu(opal_epow_status[i]); + + /* Filter events which do not need shutdown. */ + if (i == OPAL_SYSEPOW_POWER) + epow &= ~(OPAL_SYSPOWER_CHNG | OPAL_SYSPOWER_FAIL | + OPAL_SYSPOWER_INCL); + if (epow) + return true; + } + + return false; +} + +/* Check for existing EPOW, DPO events */ +static bool poweroff_pending(void) +{ + int rc; + __be64 opal_dpo_timeout; + + /* Check for DPO event */ + rc = opal_get_dpo_status(&opal_dpo_timeout); + if (rc == OPAL_SUCCESS) { + pr_info("Existing DPO event detected.\n"); + return true; + } + + /* Check for EPOW event */ + if (detect_epow()) { + pr_info("Existing EPOW event detected.\n"); + return true; + } + + return false; +} + +/* OPAL power-control events notifier */ static int opal_power_control_event(struct notifier_block *nb, - unsigned long msg_type, void *msg) + unsigned long msg_type, void *msg) { - struct opal_msg *power_msg = msg; uint64_t type; - type = be64_to_cpu(power_msg->params[0]); - - switch (type) { - case SOFT_REBOOT: - pr_info("OPAL: reboot requested\n"); - orderly_reboot(); + switch (msg_type) { + case OPAL_MSG_EPOW: + if (detect_epow()) { + pr_info("EPOW msg received. Powering off system\n"); + orderly_poweroff(true); + } break; - case SOFT_OFF: - pr_info("OPAL: poweroff requested\n"); + case OPAL_MSG_DPO: + pr_info("DPO msg received. Powering off system\n"); orderly_poweroff(true); break; + case OPAL_MSG_SHUTDOWN: + type = be64_to_cpu(((struct opal_msg *)msg)->params[0]); + switch (type) { + case SOFT_REBOOT: + pr_info("Reboot requested\n"); + orderly_reboot(); + break; + case SOFT_OFF: + pr_info("Poweroff requested\n"); + orderly_poweroff(true); + break; + default: + pr_err("Unknown power-control type %llu\n", type); + } + break; default: - pr_err("OPAL: power control type unexpected %016llx\n", type); + pr_err("Unknown OPAL message type %lu\n", msg_type); } return 0; } +/* OPAL EPOW event notifier block */ +static struct notifier_block opal_epow_nb = { + .notifier_call = opal_power_control_event, + .next = NULL, + .priority = 0, +}; + +/* OPAL DPO event notifier block */ +static struct notifier_block opal_dpo_nb = { + .notifier_call = opal_power_control_event, + .next = NULL, + .priority = 0, +}; + +/* OPAL power-control event notifier block */ static struct notifier_block opal_power_control_nb = { .notifier_call = opal_power_control_event, .next = NULL, @@ -51,16 +140,40 @@ static struct notifier_block opal_power_control_nb = { static int __init opal_power_control_init(void) { - int ret; + int ret, supported = 0; + struct device_node *np; + /* Register OPAL power-control events notifier */ ret = opal_message_notifier_register(OPAL_MSG_SHUTDOWN, - &opal_power_control_nb); - if (ret) { - pr_err("%s: Can't register OPAL event notifier (%d)\n", - __func__, ret); - return ret; + &opal_power_control_nb); + if (ret) + pr_err("Failed to register SHUTDOWN notifier, ret = %d\n", ret); + + /* Determine OPAL EPOW, DPO support */ + np = of_find_node_by_path("/ibm,opal/epow"); + if (np) { + supported = of_device_is_compatible(np, "ibm,opal-v3-epow"); + of_node_put(np); } + if (!supported) + return 0; + pr_info("OPAL EPOW, DPO support detected.\n"); + + /* Register EPOW event notifier */ + ret = opal_message_notifier_register(OPAL_MSG_EPOW, &opal_epow_nb); + if (ret) + pr_err("Failed to register EPOW notifier, ret = %d\n", ret); + + /* Register DPO event notifier */ + ret = opal_message_notifier_register(OPAL_MSG_DPO, &opal_dpo_nb); + if (ret) + pr_err("Failed to register DPO notifier, ret = %d\n", ret); + + /* Check for any pending EPOW or DPO events. */ + if (poweroff_pending()) + orderly_poweroff(true); + return 0; } machine_subsys_initcall(powernv, opal_power_control_init); diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S index d6a7b8252e4da..88e4333573718 100644 --- a/arch/powerpc/platforms/powernv/opal-wrappers.S +++ b/arch/powerpc/platforms/powernv/opal-wrappers.S @@ -249,6 +249,7 @@ OPAL_CALL(opal_pci_reinit, OPAL_PCI_REINIT); OPAL_CALL(opal_pci_mask_pe_error, OPAL_PCI_MASK_PE_ERROR); OPAL_CALL(opal_set_slot_led_status, OPAL_SET_SLOT_LED_STATUS); OPAL_CALL(opal_get_epow_status, OPAL_GET_EPOW_STATUS); +OPAL_CALL(opal_get_dpo_status, OPAL_GET_DPO_STATUS); OPAL_CALL(opal_set_system_attention_led, OPAL_SET_SYSTEM_ATTENTION_LED); OPAL_CALL(opal_pci_next_error, OPAL_PCI_NEXT_ERROR); OPAL_CALL(opal_pci_poll, OPAL_PCI_POLL); -- GitLab From c0b8da1e7613a11ce7e44560aae507b62da1f846 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YOSHIFUJI=20Hideaki/=E5=90=89=E8=97=A4=E8=8B=B1=E6=98=8E?= Date: Mon, 13 Jul 2015 23:28:10 +0900 Subject: [PATCH 0910/7006] ipv6: Fix finding best source address in ipv6_dev_get_saddr(). Commit 9131f3de2 ("ipv6: Do not iterate over all interfaces when finding source address on specific interface.") did not properly update best source address available. Plus, it introduced possible NULL pointer dereference. Bug was reported by Erik Kline . Based on patch proposed by Hajime Tazaki . Fixes: 9131f3de24db4dc12199aede7d931e6703e97f3b ("ipv6: Do not iterate over all interfaces when finding source address on specific interface.") Signed-off-by: YOSHIFUJI Hideaki Acked-by: Hajime Tazaki Acked-by: Erik Kline Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4ab74d56f65a1..4c9a0246ef486 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1358,14 +1358,15 @@ out: return ret; } -static void __ipv6_dev_get_saddr(struct net *net, - struct ipv6_saddr_dst *dst, - unsigned int prefs, - const struct in6_addr *saddr, - struct inet6_dev *idev, - struct ipv6_saddr_score *scores) +static int __ipv6_dev_get_saddr(struct net *net, + struct ipv6_saddr_dst *dst, + unsigned int prefs, + const struct in6_addr *saddr, + struct inet6_dev *idev, + struct ipv6_saddr_score *scores, + int hiscore_idx) { - struct ipv6_saddr_score *score = &scores[0], *hiscore = &scores[1]; + struct ipv6_saddr_score *score = &scores[1 - hiscore_idx], *hiscore = &scores[hiscore_idx]; read_lock_bh(&idev->lock); list_for_each_entry(score->ifa, &idev->addr_list, if_list) { @@ -1424,6 +1425,7 @@ static void __ipv6_dev_get_saddr(struct net *net, in6_ifa_hold(score->ifa); swap(hiscore, score); + hiscore_idx = 1 - hiscore_idx; /* restore our iterator */ score->ifa = hiscore->ifa; @@ -1434,18 +1436,20 @@ static void __ipv6_dev_get_saddr(struct net *net, } out: read_unlock_bh(&idev->lock); + return hiscore_idx; } int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, const struct in6_addr *daddr, unsigned int prefs, struct in6_addr *saddr) { - struct ipv6_saddr_score scores[2], *hiscore = &scores[1]; + struct ipv6_saddr_score scores[2], *hiscore; struct ipv6_saddr_dst dst; struct inet6_dev *idev; struct net_device *dev; int dst_type; bool use_oif_addr = false; + int hiscore_idx = 0; dst_type = __ipv6_addr_type(daddr); dst.addr = daddr; @@ -1454,8 +1458,8 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex); dst.prefs = prefs; - hiscore->rule = -1; - hiscore->ifa = NULL; + scores[hiscore_idx].rule = -1; + scores[hiscore_idx].ifa = NULL; rcu_read_lock(); @@ -1480,17 +1484,19 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, } if (use_oif_addr) { - __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores); + if (idev) + hiscore_idx = __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores, hiscore_idx); } else { for_each_netdev_rcu(net, dev) { idev = __in6_dev_get(dev); if (!idev) continue; - __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores); + hiscore_idx = __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores, hiscore_idx); } } rcu_read_unlock(); + hiscore = &scores[hiscore_idx]; if (!hiscore->ifa) return -EADDRNOTAVAIL; -- GitLab From 2de8530ba0c71a2fba02590681af0f3a2a187a9b Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Mon, 13 Jul 2015 13:09:16 -0700 Subject: [PATCH 0911/7006] hv_netvsc: Add close of RNDIS filter into change mtu call The current change mtu call only stops tx before removing RNDIS filter. In case ringbufer is not empty, the rndis_filter_device_remove() may hang on removing the buffers. This patch adds close of RNDIS filter before removing it, also a gradual waiting loop until the ring is empty. The change_mtu hang issue under heavy traffic is solved by this patch. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/netvsc_drv.c | 58 +++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index b855ba9a507d5..7b36d5fecc1f2 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -106,7 +106,7 @@ static int netvsc_open(struct net_device *net) return ret; } - netif_tx_start_all_queues(net); + netif_tx_wake_all_queues(net); nvdev = hv_get_drvdata(device_obj); rdev = nvdev->extension; @@ -120,15 +120,56 @@ static int netvsc_close(struct net_device *net) { struct net_device_context *net_device_ctx = netdev_priv(net); struct hv_device *device_obj = net_device_ctx->device_ctx; + struct netvsc_device *nvdev = hv_get_drvdata(device_obj); int ret; + u32 aread, awrite, i, msec = 10, retry = 0, retry_max = 20; + struct vmbus_channel *chn; netif_tx_disable(net); /* Make sure netvsc_set_multicast_list doesn't re-enable filter! */ cancel_work_sync(&net_device_ctx->work); ret = rndis_filter_close(device_obj); - if (ret != 0) + if (ret != 0) { netdev_err(net, "unable to close device (ret %d).\n", ret); + return ret; + } + + /* Ensure pending bytes in ring are read */ + while (true) { + aread = 0; + for (i = 0; i < nvdev->num_chn; i++) { + chn = nvdev->chn_table[i]; + if (!chn) + continue; + + hv_get_ringbuffer_availbytes(&chn->inbound, &aread, + &awrite); + + if (aread) + break; + + hv_get_ringbuffer_availbytes(&chn->outbound, &aread, + &awrite); + + if (aread) + break; + } + + retry++; + if (retry > retry_max || aread == 0) + break; + + msleep(msec); + + if (msec < 1000) + msec *= 2; + } + + if (aread) { + netdev_err(net, "Ring buffer not empty after closing rndis\n"); + ret = -ETIMEDOUT; + } return ret; } @@ -736,6 +777,7 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) struct netvsc_device *nvdev = hv_get_drvdata(hdev); struct netvsc_device_info device_info; int limit = ETH_DATA_LEN; + int ret = 0; if (nvdev == NULL || nvdev->destroy) return -ENODEV; @@ -746,9 +788,11 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) if (mtu < NETVSC_MTU_MIN || mtu > limit) return -EINVAL; + ret = netvsc_close(ndev); + if (ret) + goto out; + nvdev->start_remove = true; - cancel_work_sync(&ndevctx->work); - netif_tx_disable(ndev); rndis_filter_device_remove(hdev); ndev->mtu = mtu; @@ -758,9 +802,11 @@ static int netvsc_change_mtu(struct net_device *ndev, int mtu) device_info.ring_size = ring_size; device_info.max_num_vrss_chns = max_num_vrss_chns; rndis_filter_device_add(hdev, &device_info); - netif_tx_wake_all_queues(ndev); - return 0; +out: + netvsc_open(ndev); + + return ret; } static struct rtnl_link_stats64 *netvsc_get_stats64(struct net_device *net, -- GitLab From b2a02ac65e40fb3900d176828a407b44bb33f9f4 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 8 Jul 2015 17:14:36 +0200 Subject: [PATCH 0912/7006] cxl: Destroy cxl_adapter_idr on module_exit Destroy cxl_adapter_idr on module exit, reclaiming the allocated memory. This was detected by the following semantic patch (written by Luis Rodriguez ) @ defines_module_init @ declarer name module_init, module_exit; declarer name DEFINE_IDR; identifier init; @@ module_init(init); @ defines_module_exit @ identifier exit; @@ module_exit(exit); @ declares_idr depends on defines_module_init && defines_module_exit @ identifier idr; @@ DEFINE_IDR(idr); @ on_exit_calls_destroy depends on declares_idr && defines_module_exit @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... idr_destroy(&idr); ... } @ missing_module_idr_destroy depends on declares_idr && defines_module_exit && !on_exit_calls_destroy @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... +idr_destroy(&idr); } Signed-off-by: Johannes Thumshirn Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c index 4a164ab8b35a6..9fde75ed4facd 100644 --- a/drivers/misc/cxl/main.c +++ b/drivers/misc/cxl/main.c @@ -222,6 +222,7 @@ static void exit_cxl(void) cxl_debugfs_exit(); cxl_file_exit(); unregister_cxl_calls(&cxl_calls); + idr_destroy(&cxl_adapter_idr); } module_init(init_cxl); -- GitLab From bd664f892e3e2b01c79197cad3111d54b7aedf39 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 9 Jul 2015 09:39:42 +0200 Subject: [PATCH 0913/7006] cxl: Destroy afu->contexts_idr on release of an afu Destroy afu->contexts_idr on release of an afu, reclaiming the allocated memory. Signed-off-by: Johannes Thumshirn Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index eb05efb74eed8..1d314f1f95fed 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -551,6 +551,7 @@ static void cxl_release_afu(struct device *dev) pr_devel("cxl_release_afu\n"); + idr_destroy(&afu->contexts_idr); kfree(afu); } -- GitLab From 07e6a97da1eba064bb35cfd5c121e90865393a60 Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 14 Jul 2015 10:51:51 -0500 Subject: [PATCH 0914/7006] ibmveth: add support for TSO6 This patch adds support for a new method of signalling the firmware that TSO packets are being sent. The new method removes the need to alter the ip and tcp checksums and allows TSO6 support. Signed-off-by: Thomas Falcon Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 145 ++++++++++++++++++++++++----- drivers/net/ethernet/ibm/ibmveth.h | 18 +++- 2 files changed, 135 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index 29bbb628d712b..7af870a3c5495 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -79,6 +79,11 @@ static unsigned int rx_flush __read_mostly = 0; module_param(rx_flush, uint, 0644); MODULE_PARM_DESC(rx_flush, "Flush receive buffers before use"); +static bool old_large_send __read_mostly; +module_param(old_large_send, bool, S_IRUGO); +MODULE_PARM_DESC(old_large_send, + "Use old large send method on firmware that supports the new method"); + struct ibmveth_stat { char name[ETH_GSTRING_LEN]; int offset; @@ -101,7 +106,8 @@ struct ibmveth_stat ibmveth_stats[] = { { "fw_enabled_ipv4_csum", IBMVETH_STAT_OFF(fw_ipv4_csum_support) }, { "fw_enabled_ipv6_csum", IBMVETH_STAT_OFF(fw_ipv6_csum_support) }, { "tx_large_packets", IBMVETH_STAT_OFF(tx_large_packets) }, - { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) } + { "rx_large_packets", IBMVETH_STAT_OFF(rx_large_packets) }, + { "fw_enabled_large_send", IBMVETH_STAT_OFF(fw_large_send_support) } }; /* simple methods of getting data from the current rxq entry */ @@ -848,25 +854,91 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data) return rc1 ? rc1 : rc2; } +static int ibmveth_set_tso(struct net_device *dev, u32 data) +{ + struct ibmveth_adapter *adapter = netdev_priv(dev); + unsigned long set_attr, clr_attr, ret_attr; + long ret1, ret2; + int rc1 = 0, rc2 = 0; + int restart = 0; + + if (netif_running(dev)) { + restart = 1; + adapter->pool_config = 1; + ibmveth_close(dev); + adapter->pool_config = 0; + } + + set_attr = 0; + clr_attr = 0; + + if (data) + set_attr = IBMVETH_ILLAN_LRG_SR_ENABLED; + else + clr_attr = IBMVETH_ILLAN_LRG_SR_ENABLED; + + ret1 = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); + + if (ret1 == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_LRG_SND_SUPPORT) && + !old_large_send) { + ret2 = h_illan_attributes(adapter->vdev->unit_address, clr_attr, + set_attr, &ret_attr); + + if (ret2 != H_SUCCESS) { + netdev_err(dev, "unable to change tso settings. %d rc=%ld\n", + data, ret2); + + h_illan_attributes(adapter->vdev->unit_address, + set_attr, clr_attr, &ret_attr); + + if (data == 1) + dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6); + rc1 = -EIO; + + } else { + adapter->fw_large_send_support = data; + adapter->large_send = data; + } + } else { + /* Older firmware version of large send offload does not + * support tcp6/ipv6 + */ + if (data == 1) { + dev->features &= ~NETIF_F_TSO6; + netdev_info(dev, "TSO feature requires all partitions to have updated driver"); + } + adapter->large_send = data; + } + + if (restart) + rc2 = ibmveth_open(dev); + + return rc1 ? rc1 : rc2; +} + static int ibmveth_set_features(struct net_device *dev, netdev_features_t features) { struct ibmveth_adapter *adapter = netdev_priv(dev); int rx_csum = !!(features & NETIF_F_RXCSUM); - int rc; - netdev_features_t changed = features ^ dev->features; - - if (features & NETIF_F_TSO & changed) - netdev_info(dev, "TSO feature requires all partitions to have updated driver"); + int large_send = !!(features & (NETIF_F_TSO | NETIF_F_TSO6)); + int rc1 = 0, rc2 = 0; - if (rx_csum == adapter->rx_csum) - return 0; + if (rx_csum != adapter->rx_csum) { + rc1 = ibmveth_set_csum_offload(dev, rx_csum); + if (rc1 && !adapter->rx_csum) + dev->features = + features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + } - rc = ibmveth_set_csum_offload(dev, rx_csum); - if (rc && !adapter->rx_csum) - dev->features = features & ~(NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); + if (large_send != adapter->large_send) { + rc2 = ibmveth_set_tso(dev, large_send); + if (rc2 && !adapter->large_send) + dev->features = + features & ~(NETIF_F_TSO | NETIF_F_TSO6); + } - return rc; + return rc1 ? rc1 : rc2; } static void ibmveth_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -917,7 +989,7 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) #define page_offset(v) ((unsigned long)(v) & ((1 << 12) - 1)) static int ibmveth_send(struct ibmveth_adapter *adapter, - union ibmveth_buf_desc *descs) + union ibmveth_buf_desc *descs, unsigned long mss) { unsigned long correlator; unsigned int retry_count; @@ -934,7 +1006,8 @@ static int ibmveth_send(struct ibmveth_adapter *adapter, descs[0].desc, descs[1].desc, descs[2].desc, descs[3].desc, descs[4].desc, descs[5].desc, - correlator, &correlator); + correlator, &correlator, mss, + adapter->fw_large_send_support); } while ((ret == H_BUSY) && (retry_count--)); if (ret != H_SUCCESS && ret != H_DROPPED) { @@ -955,6 +1028,7 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, int last, i; int force_bounce = 0; dma_addr_t dma_addr; + unsigned long mss = 0; /* * veth handles a maximum of 6 segments including the header, so @@ -980,6 +1054,9 @@ static netdev_tx_t ibmveth_start_xmit(struct sk_buff *skb, desc_flags = IBMVETH_BUF_VALID; + if (skb_is_gso(skb) && adapter->fw_large_send_support) + desc_flags |= IBMVETH_BUF_LRG_SND; + if (skb->ip_summed == CHECKSUM_PARTIAL) { unsigned char *buf = skb_transport_header(skb) + skb->csum_offset; @@ -1007,7 +1084,7 @@ retry_bounce: descs[0].fields.flags_len = desc_flags | skb->len; descs[0].fields.address = adapter->bounce_buffer_dma; - if (ibmveth_send(adapter, descs)) { + if (ibmveth_send(adapter, descs, 0)) { adapter->tx_send_failed++; netdev->stats.tx_dropped++; } else { @@ -1041,16 +1118,23 @@ retry_bounce: descs[i+1].fields.address = dma_addr; } - if (skb_is_gso(skb) && !skb_is_gso_v6(skb)) { - /* Put -1 in the IP checksum to tell phyp it - * is a largesend packet and put the mss in the TCP checksum. - */ - ip_hdr(skb)->check = 0xffff; - tcp_hdr(skb)->check = cpu_to_be16(skb_shinfo(skb)->gso_size); - adapter->tx_large_packets++; + if (skb_is_gso(skb)) { + if (adapter->fw_large_send_support) { + mss = (unsigned long)skb_shinfo(skb)->gso_size; + adapter->tx_large_packets++; + } else if (!skb_is_gso_v6(skb)) { + /* Put -1 in the IP checksum to tell phyp it + * is a largesend packet. Put the mss in + * the TCP checksum. + */ + ip_hdr(skb)->check = 0xffff; + tcp_hdr(skb)->check = + cpu_to_be16(skb_shinfo(skb)->gso_size); + adapter->tx_large_packets++; + } } - if (ibmveth_send(adapter, descs)) { + if (ibmveth_send(adapter, descs, mss)) { adapter->tx_send_failed++; netdev->stats.tx_dropped++; } else { @@ -1401,6 +1485,8 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) struct ibmveth_adapter *adapter; unsigned char *mac_addr_p; unsigned int *mcastFilterSize_p; + long ret; + unsigned long ret_attr; dev_dbg(&dev->dev, "entering ibmveth_probe for UA 0x%x\n", dev->unit_address); @@ -1449,10 +1535,19 @@ static int ibmveth_probe(struct vio_dev *dev, const struct vio_device_id *id) SET_NETDEV_DEV(netdev, &dev->dev); netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + netdev->features |= netdev->hw_features; - /* TSO is disabled by default */ - netdev->hw_features |= NETIF_F_TSO; + ret = h_illan_attributes(adapter->vdev->unit_address, 0, 0, &ret_attr); + + /* If running older firmware, TSO should not be enabled by default */ + if (ret == H_SUCCESS && (ret_attr & IBMVETH_ILLAN_LRG_SND_SUPPORT) && + !old_large_send) { + netdev->hw_features |= NETIF_F_TSO | NETIF_F_TSO6; + netdev->features |= netdev->hw_features; + } else { + netdev->hw_features |= NETIF_F_TSO; + } memcpy(netdev->dev_addr, mac_addr_p, ETH_ALEN); diff --git a/drivers/net/ethernet/ibm/ibmveth.h b/drivers/net/ethernet/ibm/ibmveth.h index 41dedb1fb2ae7..4eade67fe30c3 100644 --- a/drivers/net/ethernet/ibm/ibmveth.h +++ b/drivers/net/ethernet/ibm/ibmveth.h @@ -40,6 +40,8 @@ #define IbmVethMcastRemoveFilter 0x2UL #define IbmVethMcastClearFilterTable 0x3UL +#define IBMVETH_ILLAN_LRG_SR_ENABLED 0x0000000000010000UL +#define IBMVETH_ILLAN_LRG_SND_SUPPORT 0x0000000000008000UL #define IBMVETH_ILLAN_PADDED_PKT_CSUM 0x0000000000002000UL #define IBMVETH_ILLAN_TRUNK_PRI_MASK 0x0000000000000F00UL #define IBMVETH_ILLAN_IPV6_TCP_CSUM 0x0000000000000004UL @@ -59,13 +61,20 @@ static inline long h_send_logical_lan(unsigned long unit_address, unsigned long desc1, unsigned long desc2, unsigned long desc3, unsigned long desc4, unsigned long desc5, unsigned long desc6, - unsigned long corellator_in, unsigned long *corellator_out) + unsigned long corellator_in, unsigned long *corellator_out, + unsigned long mss, unsigned long large_send_support) { long rc; unsigned long retbuf[PLPAR_HCALL9_BUFSIZE]; - rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, desc1, - desc2, desc3, desc4, desc5, desc6, corellator_in); + if (large_send_support) + rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, + desc1, desc2, desc3, desc4, desc5, desc6, + corellator_in, mss); + else + rc = plpar_hcall9(H_SEND_LOGICAL_LAN, retbuf, unit_address, + desc1, desc2, desc3, desc4, desc5, desc6, + corellator_in); *corellator_out = retbuf[0]; @@ -147,11 +156,13 @@ struct ibmveth_adapter { struct ibmveth_rx_q rx_queue; int pool_config; int rx_csum; + int large_send; void *bounce_buffer; dma_addr_t bounce_buffer_dma; u64 fw_ipv6_csum_support; u64 fw_ipv4_csum_support; + u64 fw_large_send_support; /* adapter specific stats */ u64 replenish_task_cycles; u64 replenish_no_mem; @@ -182,6 +193,7 @@ struct ibmveth_buf_desc_fields { #endif #define IBMVETH_BUF_VALID 0x80000000 #define IBMVETH_BUF_TOGGLE 0x40000000 +#define IBMVETH_BUF_LRG_SND 0x04000000 #define IBMVETH_BUF_NO_CSUM 0x02000000 #define IBMVETH_BUF_CSUM_GOOD 0x01000000 #define IBMVETH_BUF_LEN_MASK 0x00FFFFFF -- GitLab From d746d707a8b1421a4ba46b497cb5d59e20161645 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 14 Jul 2015 13:43:19 -0700 Subject: [PATCH 0915/7006] net core: Add protodown support. This patch introduces the proto_down flag that can be used by user space applications to notify switch drivers that errors have been detected on the device. The switch driver can react to protodown notification by doing a phys down on the associated switch port. Signed-off-by: Anuradha Karuppiah Signed-off-by: Andy Gospodarek Signed-off-by: Roopa Prabhu Signed-off-by: Wilson Kok Signed-off-by: David S. Miller --- include/linux/netdevice.h | 14 ++++++++++++++ net/core/dev.c | 20 ++++++++++++++++++++ net/core/net-sysfs.c | 14 ++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e20979dfd6a99..45cfd797eb77e 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1041,6 +1041,12 @@ typedef u16 (*select_queue_fallback_t)(struct net_device *dev, * TX queue. * int (*ndo_get_iflink)(const struct net_device *dev); * Called to get the iflink value of this device. + * void (*ndo_change_proto_down)(struct net_device *dev, + * bool proto_down); + * This function is used to pass protocol port error state information + * to the switch driver. The switch driver can react to the proto_down + * by doing a phys down on the associated switch port. + * */ struct net_device_ops { int (*ndo_init)(struct net_device *dev); @@ -1211,6 +1217,8 @@ struct net_device_ops { int queue_index, u32 maxrate); int (*ndo_get_iflink)(const struct net_device *dev); + int (*ndo_change_proto_down)(struct net_device *dev, + bool proto_down); }; /** @@ -1502,6 +1510,10 @@ enum netdev_priv_flags { * * @qdisc_tx_busylock: XXX: need comments on this one * + * @proto_down: protocol port state information can be sent to the + * switch driver and used to set the phys state of the + * switch port. + * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ @@ -1762,6 +1774,7 @@ struct net_device { #endif struct phy_device *phydev; struct lock_class_key *qdisc_tx_busylock; + bool proto_down; }; #define to_net_dev(d) container_of(d, struct net_device, dev) @@ -2982,6 +2995,7 @@ int dev_get_phys_port_id(struct net_device *dev, struct netdev_phys_item_id *ppid); int dev_get_phys_port_name(struct net_device *dev, char *name, size_t len); +int dev_change_proto_down(struct net_device *dev, bool proto_down); struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev); struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq, int *ret); diff --git a/net/core/dev.c b/net/core/dev.c index 69445a33ace65..8810b6bbebfea 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -6074,6 +6074,26 @@ int dev_get_phys_port_name(struct net_device *dev, } EXPORT_SYMBOL(dev_get_phys_port_name); +/** + * dev_change_proto_down - update protocol port state information + * @dev: device + * @proto_down: new value + * + * This info can be used by switch drivers to set the phys state of the + * port. + */ +int dev_change_proto_down(struct net_device *dev, bool proto_down) +{ + const struct net_device_ops *ops = dev->netdev_ops; + + if (!ops->ndo_change_proto_down) + return -EOPNOTSUPP; + if (!netif_device_present(dev)) + return -ENODEV; + return ops->ndo_change_proto_down(dev, proto_down); +} +EXPORT_SYMBOL(dev_change_proto_down); + /** * dev_new_index - allocate an ifindex * @net: the applicable net namespace diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 18b34d771ed4d..194c1d03b2b3b 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -404,6 +404,19 @@ static ssize_t group_store(struct device *dev, struct device_attribute *attr, NETDEVICE_SHOW(group, fmt_dec); static DEVICE_ATTR(netdev_group, S_IRUGO | S_IWUSR, group_show, group_store); +static int change_proto_down(struct net_device *dev, unsigned long proto_down) +{ + return dev_change_proto_down(dev, (bool) proto_down); +} + +static ssize_t proto_down_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return netdev_store(dev, attr, buf, len, change_proto_down); +} +NETDEVICE_SHOW_RW(proto_down, fmt_dec); + static ssize_t phys_port_id_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -501,6 +514,7 @@ static struct attribute *net_class_attrs[] = { &dev_attr_phys_port_id.attr, &dev_attr_phys_port_name.attr, &dev_attr_phys_switch_id.attr, + &dev_attr_proto_down.attr, NULL, }; ATTRIBUTE_GROUPS(net_class); -- GitLab From 88d6378bd6c096cb8440face3ae3f33d55a2e6e4 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 14 Jul 2015 13:43:20 -0700 Subject: [PATCH 0916/7006] netlink: changes for setting and clearing protodown via netlink. Signed-off-by: Anuradha Karuppiah Signed-off-by: Andy Gospodarek Signed-off-by: Roopa Prabhu Signed-off-by: Wilson Kok Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 1 + net/core/rtnetlink.c | 16 ++++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 2c7e8e3d3981e..24d68b797c596 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -148,6 +148,7 @@ enum { IFLA_PHYS_SWITCH_ID, IFLA_LINK_NETNSID, IFLA_PHYS_PORT_NAME, + IFLA_PROTO_DOWN, __IFLA_MAX }; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 9e433d58d2651..03d61b54aac03 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -896,7 +896,9 @@ static noinline size_t if_nlmsg_size(const struct net_device *dev, + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ + rtnl_link_get_af_size(dev) /* IFLA_AF_SPEC */ + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_PORT_ID */ - + nla_total_size(MAX_PHYS_ITEM_ID_LEN); /* IFLA_PHYS_SWITCH_ID */ + + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_SWITCH_ID */ + + nla_total_size(1); /* IFLA_PROTO_DOWN */ + } static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) @@ -1082,7 +1084,8 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, (dev->ifalias && nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)) || nla_put_u32(skb, IFLA_CARRIER_CHANGES, - atomic_read(&dev->carrier_changes))) + atomic_read(&dev->carrier_changes)) || + nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down)) goto nla_put_failure; if (1) { @@ -1319,6 +1322,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */ [IFLA_PHYS_SWITCH_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, [IFLA_LINK_NETNSID] = { .type = NLA_S32 }, + [IFLA_PROTO_DOWN] = { .type = NLA_U8 }, }; static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { @@ -1858,6 +1862,14 @@ static int do_setlink(const struct sk_buff *skb, } err = 0; + if (tb[IFLA_PROTO_DOWN]) { + err = dev_change_proto_down(dev, + nla_get_u8(tb[IFLA_PROTO_DOWN])); + if (err) + goto errout; + status |= DO_SETLINK_NOTIFY; + } + errout: if (status & DO_SETLINK_MODIFIED) { if (status & DO_SETLINK_NOTIFY) -- GitLab From c305524617dcd617d698dfe2682f3212e698f781 Mon Sep 17 00:00:00 2001 From: Anuradha Karuppiah Date: Tue, 14 Jul 2015 13:43:21 -0700 Subject: [PATCH 0917/7006] rocker: Handle protodown notifications. protodown can be set by user space applications like MLAG on detecting errors on a switch port. This patch provides sample switch driver changes for handling protodown. Rocker PHYS disables the port in response to protodown. Signed-off-by: Anuradha Karuppiah Signed-off-by: Andy Gospodarek Signed-off-by: Roopa Prabhu Signed-off-by: Wilson Kok Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index c0051673c9fad..932428314b800 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4015,7 +4015,8 @@ static int rocker_port_open(struct net_device *dev) napi_enable(&rocker_port->napi_tx); napi_enable(&rocker_port->napi_rx); - rocker_port_set_enable(rocker_port, true); + if (!dev->proto_down) + rocker_port_set_enable(rocker_port, true); netif_start_queue(dev); return 0; @@ -4227,6 +4228,17 @@ static int rocker_port_get_phys_port_name(struct net_device *dev, return err ? -EOPNOTSUPP : 0; } +static int rocker_port_change_proto_down(struct net_device *dev, + bool proto_down) +{ + struct rocker_port *rocker_port = netdev_priv(dev); + + if (rocker_port->dev->flags & IFF_UP) + rocker_port_set_enable(rocker_port, !proto_down); + rocker_port->dev->proto_down = proto_down; + return 0; +} + static const struct net_device_ops rocker_port_netdev_ops = { .ndo_open = rocker_port_open, .ndo_stop = rocker_port_stop, @@ -4240,6 +4252,7 @@ static const struct net_device_ops rocker_port_netdev_ops = { .ndo_fdb_del = switchdev_port_fdb_del, .ndo_fdb_dump = switchdev_port_fdb_dump, .ndo_get_phys_port_name = rocker_port_get_phys_port_name, + .ndo_change_proto_down = rocker_port_change_proto_down, }; /******************** -- GitLab From 829023df86d4ec39b110860cd5f106b7ac58f772 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Mon, 6 Jul 2015 16:24:10 +0530 Subject: [PATCH 0918/7006] powerpc/tm: Drop tm_orig_msr from thread_struct Currently tm_orig_msr is getting used during process context switch only. Then there is ckpt_regs which saves the checkpointed userspace context The MSR slot contained in ckpt_regs structure can be used during process context switch instead of tm_orig_msr, thus allowing us to drop it from thread_struct structure. This patch does that change. Acked-by: Michael Neuling Signed-off-by: Anshuman Khandual Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/processor.h | 1 - arch/powerpc/kernel/process.c | 14 +++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/powerpc/include/asm/processor.h b/arch/powerpc/include/asm/processor.h index 28ded5d9b5796..5afea361beaae 100644 --- a/arch/powerpc/include/asm/processor.h +++ b/arch/powerpc/include/asm/processor.h @@ -264,7 +264,6 @@ struct thread_struct { u64 tm_tfhar; /* Transaction fail handler addr */ u64 tm_texasr; /* Transaction exception & summary */ u64 tm_tfiar; /* Transaction fail instr address reg */ - unsigned long tm_orig_msr; /* Thread's MSR on ctx switch */ struct pt_regs ckpt_regs; /* Checkpointed registers */ unsigned long tm_tar; diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c index 8005e18d1b403..99adcbad36906 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -86,7 +86,7 @@ void giveup_fpu_maybe_transactional(struct task_struct *tsk) if (tsk == current && tsk->thread.regs && MSR_TM_ACTIVE(tsk->thread.regs->msr) && !test_thread_flag(TIF_RESTORE_TM)) { - tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + tsk->thread.ckpt_regs.msr = tsk->thread.regs->msr; set_thread_flag(TIF_RESTORE_TM); } @@ -104,7 +104,7 @@ void giveup_altivec_maybe_transactional(struct task_struct *tsk) if (tsk == current && tsk->thread.regs && MSR_TM_ACTIVE(tsk->thread.regs->msr) && !test_thread_flag(TIF_RESTORE_TM)) { - tsk->thread.tm_orig_msr = tsk->thread.regs->msr; + tsk->thread.ckpt_regs.msr = tsk->thread.regs->msr; set_thread_flag(TIF_RESTORE_TM); } @@ -543,7 +543,7 @@ static void tm_reclaim_thread(struct thread_struct *thr, * the thread will no longer be transactional. */ if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) { - msr_diff = thr->tm_orig_msr & ~thr->regs->msr; + msr_diff = thr->ckpt_regs.msr & ~thr->regs->msr; if (msr_diff & MSR_FP) memcpy(&thr->transact_fp, &thr->fp_state, sizeof(struct thread_fp_state)); @@ -594,10 +594,10 @@ static inline void tm_reclaim_task(struct task_struct *tsk) /* Stash the original thread MSR, as giveup_fpu et al will * modify it. We hold onto it to see whether the task used * FP & vector regs. If the TIF_RESTORE_TM flag is set, - * tm_orig_msr is already set. + * ckpt_regs.msr is already set. */ if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM)) - thr->tm_orig_msr = thr->regs->msr; + thr->ckpt_regs.msr = thr->regs->msr; TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, " "ccr=%lx, msr=%lx, trap=%lx)\n", @@ -666,7 +666,7 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new) tm_restore_sprs(&new->thread); return; } - msr = new->thread.tm_orig_msr; + msr = new->thread.ckpt_regs.msr; /* Recheckpoint to restore original checkpointed register state. */ TM_DEBUG("*** tm_recheckpoint of pid %d " "(new->msr 0x%lx, new->origmsr 0x%lx)\n", @@ -726,7 +726,7 @@ void restore_tm_state(struct pt_regs *regs) if (!MSR_TM_ACTIVE(regs->msr)) return; - msr_diff = current->thread.tm_orig_msr & ~regs->msr; + msr_diff = current->thread.ckpt_regs.msr & ~regs->msr; msr_diff &= MSR_FP | MSR_VEC | MSR_VSX; if (msr_diff & MSR_FP) { fp_enable(); -- GitLab From 4c576229ac371bc9d96f2b365ebcd296aa266cec Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Mon, 6 Jul 2015 15:55:33 +0530 Subject: [PATCH 0919/7006] powerpc/signal: Fix confusing header documentation in sigcontext.h Commit ce48b2100785 "powerpc: Add VSX context save/restore, ptrace and signal support" expanded the 'vmx_reserve' array element to contain 101 double words, but the comment block above was not updated. Also reorder the constants in the array size declaration to reflect the logic mentioned in the comment block above. This change helps in explaining how the HW registers are represented in the array. But no functional change. Signed-off-by: Anshuman Khandual [mpe: Reworded change log and added whitespace around +'s] Signed-off-by: Michael Ellerman --- arch/powerpc/include/uapi/asm/sigcontext.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/include/uapi/asm/sigcontext.h b/arch/powerpc/include/uapi/asm/sigcontext.h index 9c1f24fd5d112..3ad0c7f001a95 100644 --- a/arch/powerpc/include/uapi/asm/sigcontext.h +++ b/arch/powerpc/include/uapi/asm/sigcontext.h @@ -28,7 +28,7 @@ struct sigcontext { /* * To maintain compatibility with current implementations the sigcontext is * extended by appending a pointer (v_regs) to a quadword type (elf_vrreg_t) - * followed by an unstructured (vmx_reserve) field of 69 doublewords. This + * followed by an unstructured (vmx_reserve) field of 101 doublewords. This * allows the array of vector registers to be quadword aligned independent of * the alignment of the containing sigcontext or ucontext. It is the * responsibility of the code setting the sigcontext to set this pointer to @@ -80,7 +80,7 @@ struct sigcontext { * registers and vscr/vrsave. */ elf_vrreg_t __user *v_regs; - long vmx_reserve[ELF_NVRREG+ELF_NVRREG+32+1]; + long vmx_reserve[ELF_NVRREG + ELF_NVRREG + 1 + 32]; #endif }; -- GitLab From 13b8a68a9c08410f03047fc888706299b5b75754 Mon Sep 17 00:00:00 2001 From: Mario Bambagini Date: Tue, 16 Jun 2015 22:32:30 +0200 Subject: [PATCH 0920/7006] added tabs instead of spaces Tabs have been inserted instead of spaces to indent the code correctly. Same error fixed four times. Signed-off-by: Mario Bambagini Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-adi2-bf60x.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/pinctrl-adi2-bf60x.c b/drivers/pinctrl/pinctrl-adi2-bf60x.c index 4cb59fe9be703..fcfa00821f122 100644 --- a/drivers/pinctrl/pinctrl-adi2-bf60x.c +++ b/drivers/pinctrl/pinctrl-adi2-bf60x.c @@ -394,25 +394,25 @@ static const unsigned short ppi2_16b_mux[] = { static const unsigned short lp0_mux[] = { P_LP0_CLK, P_LP0_ACK, P_LP0_D0, P_LP0_D1, P_LP0_D2, P_LP0_D3, P_LP0_D4, P_LP0_D5, P_LP0_D6, P_LP0_D7, - 0 + 0 }; static const unsigned short lp1_mux[] = { P_LP1_CLK, P_LP1_ACK, P_LP1_D0, P_LP1_D1, P_LP1_D2, P_LP1_D3, P_LP1_D4, P_LP1_D5, P_LP1_D6, P_LP1_D7, - 0 + 0 }; static const unsigned short lp2_mux[] = { P_LP2_CLK, P_LP2_ACK, P_LP2_D0, P_LP2_D1, P_LP2_D2, P_LP2_D3, P_LP2_D4, P_LP2_D5, P_LP2_D6, P_LP2_D7, - 0 + 0 }; static const unsigned short lp3_mux[] = { P_LP3_CLK, P_LP3_ACK, P_LP3_D0, P_LP3_D1, P_LP3_D2, P_LP3_D3, P_LP3_D4, P_LP3_D5, P_LP3_D6, P_LP3_D7, - 0 + 0 }; static const struct adi_pin_group adi_pin_groups[] = { -- GitLab From b5599df20f1ee45cef811a7ab1c7358d9faf7bf8 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 26 Jun 2015 01:42:04 +0300 Subject: [PATCH 0921/7006] sh-pfc: r8a7790: remove non-existing GPIO pins GPIO banks 1 and 2 are missing pins 30 and 31. Remove them. Signed-off-by: Laurent Pinchart Signed-off-by: Sergei Shtylyov Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7790.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c index baab81ead9ff4..fc344a7c2b538 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c @@ -27,10 +27,27 @@ #include "core.h" #include "sh_pfc.h" +#define PORT_GP_30(bank, fn, sfx) \ + PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \ + PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \ + PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \ + PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \ + PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \ + PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \ + PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \ + PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \ + PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \ + PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \ + PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \ + PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \ + PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx), \ + PORT_GP_1(bank, 26, fn, sfx), PORT_GP_1(bank, 27, fn, sfx), \ + PORT_GP_1(bank, 28, fn, sfx), PORT_GP_1(bank, 29, fn, sfx) + #define CPU_ALL_PORT(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ - PORT_GP_32(1, fn, sfx), \ - PORT_GP_32(2, fn, sfx), \ + PORT_GP_30(1, fn, sfx), \ + PORT_GP_30(2, fn, sfx), \ PORT_GP_32(3, fn, sfx), \ PORT_GP_32(4, fn, sfx), \ PORT_GP_32(5, fn, sfx) -- GitLab From 441f77dcf8defcebb4477fea6db03624259fef42 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 26 Jun 2015 01:43:07 +0300 Subject: [PATCH 0922/7006] sh-pfc: r8a7791: remove non-existing GPIO pins GPIO banks 1 and 7 are missing pins 26 to 31. Remove them. Signed-off-by: Laurent Pinchart Signed-off-by: Sergei Shtylyov Tested-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7791.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c index 3ddf23ec9f0b2..25e8117f5a1ac 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c @@ -14,15 +14,30 @@ #include "core.h" #include "sh_pfc.h" +#define PORT_GP_26(bank, fn, sfx) \ + PORT_GP_1(bank, 0, fn, sfx), PORT_GP_1(bank, 1, fn, sfx), \ + PORT_GP_1(bank, 2, fn, sfx), PORT_GP_1(bank, 3, fn, sfx), \ + PORT_GP_1(bank, 4, fn, sfx), PORT_GP_1(bank, 5, fn, sfx), \ + PORT_GP_1(bank, 6, fn, sfx), PORT_GP_1(bank, 7, fn, sfx), \ + PORT_GP_1(bank, 8, fn, sfx), PORT_GP_1(bank, 9, fn, sfx), \ + PORT_GP_1(bank, 10, fn, sfx), PORT_GP_1(bank, 11, fn, sfx), \ + PORT_GP_1(bank, 12, fn, sfx), PORT_GP_1(bank, 13, fn, sfx), \ + PORT_GP_1(bank, 14, fn, sfx), PORT_GP_1(bank, 15, fn, sfx), \ + PORT_GP_1(bank, 16, fn, sfx), PORT_GP_1(bank, 17, fn, sfx), \ + PORT_GP_1(bank, 18, fn, sfx), PORT_GP_1(bank, 19, fn, sfx), \ + PORT_GP_1(bank, 20, fn, sfx), PORT_GP_1(bank, 21, fn, sfx), \ + PORT_GP_1(bank, 22, fn, sfx), PORT_GP_1(bank, 23, fn, sfx), \ + PORT_GP_1(bank, 24, fn, sfx), PORT_GP_1(bank, 25, fn, sfx) + #define CPU_ALL_PORT(fn, sfx) \ PORT_GP_32(0, fn, sfx), \ - PORT_GP_32(1, fn, sfx), \ + PORT_GP_26(1, fn, sfx), \ PORT_GP_32(2, fn, sfx), \ PORT_GP_32(3, fn, sfx), \ PORT_GP_32(4, fn, sfx), \ PORT_GP_32(5, fn, sfx), \ PORT_GP_32(6, fn, sfx), \ - PORT_GP_32(7, fn, sfx) + PORT_GP_26(7, fn, sfx) enum { PINMUX_RESERVED = 0, -- GitLab From 9612327c1ffcdacc863b3baf0a3c8c9b0837ffd2 Mon Sep 17 00:00:00 2001 From: Frank Li Date: Fri, 19 Jun 2015 23:32:27 +0800 Subject: [PATCH 0923/7006] pinctrl: imx: add i.mx6ul subdriver Add i.MX6UL pinctrl driver support. Signed-off-by: Anson Huang Signed-off-by: Frank Li Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/Kconfig | 7 + drivers/pinctrl/freescale/Makefile | 1 + drivers/pinctrl/freescale/pinctrl-imx6ul.c | 323 +++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 drivers/pinctrl/freescale/pinctrl-imx6ul.c diff --git a/drivers/pinctrl/freescale/Kconfig b/drivers/pinctrl/freescale/Kconfig index 12ef544b48942..debe1219d76d6 100644 --- a/drivers/pinctrl/freescale/Kconfig +++ b/drivers/pinctrl/freescale/Kconfig @@ -87,6 +87,13 @@ config PINCTRL_IMX6SX help Say Y here to enable the imx6sx pinctrl driver +config PINCTRL_IMX6UL + bool "IMX6UL pinctrl driver" + depends on SOC_IMX6UL + select PINCTRL_IMX + help + Say Y here to enable the imx6ul pinctrl driver + config PINCTRL_IMX7D bool "IMX7D pinctrl driver" depends on SOC_IMX7D diff --git a/drivers/pinctrl/freescale/Makefile b/drivers/pinctrl/freescale/Makefile index 343cb436ab175..d44c9e253f216 100644 --- a/drivers/pinctrl/freescale/Makefile +++ b/drivers/pinctrl/freescale/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o obj-$(CONFIG_PINCTRL_IMX6SX) += pinctrl-imx6sx.o +obj-$(CONFIG_PINCTRL_IMX6UL) += pinctrl-imx6ul.o obj-$(CONFIG_PINCTRL_IMX7D) += pinctrl-imx7d.o obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c new file mode 100644 index 0000000000000..b182be7293825 --- /dev/null +++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c @@ -0,0 +1,323 @@ +/* + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pinctrl-imx.h" + +enum imx6ul_pads { + MX6UL_PAD_RESERVE0 = 0, + MX6UL_PAD_RESERVE1 = 1, + MX6UL_PAD_RESERVE2 = 2, + MX6UL_PAD_RESERVE3 = 3, + MX6UL_PAD_RESERVE4 = 4, + MX6UL_PAD_RESERVE5 = 5, + MX6UL_PAD_RESERVE6 = 6, + MX6UL_PAD_RESERVE7 = 7, + MX6UL_PAD_RESERVE8 = 8, + MX6UL_PAD_RESERVE9 = 9, + MX6UL_PAD_RESERVE10 = 10, + MX6UL_PAD_SNVS_TAMPER4 = 11, + MX6UL_PAD_RESERVE12 = 12, + MX6UL_PAD_RESERVE13 = 13, + MX6UL_PAD_RESERVE14 = 14, + MX6UL_PAD_RESERVE15 = 15, + MX6UL_PAD_RESERVE16 = 16, + MX6UL_PAD_JTAG_MOD = 17, + MX6UL_PAD_JTAG_TMS = 18, + MX6UL_PAD_JTAG_TDO = 19, + MX6UL_PAD_JTAG_TDI = 20, + MX6UL_PAD_JTAG_TCK = 21, + MX6UL_PAD_JTAG_TRST_B = 22, + MX6UL_PAD_GPIO1_IO00 = 23, + MX6UL_PAD_GPIO1_IO01 = 24, + MX6UL_PAD_GPIO1_IO02 = 25, + MX6UL_PAD_GPIO1_IO03 = 26, + MX6UL_PAD_GPIO1_IO04 = 27, + MX6UL_PAD_GPIO1_IO05 = 28, + MX6UL_PAD_GPIO1_IO06 = 29, + MX6UL_PAD_GPIO1_IO07 = 30, + MX6UL_PAD_GPIO1_IO08 = 31, + MX6UL_PAD_GPIO1_IO09 = 32, + MX6UL_PAD_UART1_TX_DATA = 33, + MX6UL_PAD_UART1_RX_DATA = 34, + MX6UL_PAD_UART1_CTS_B = 35, + MX6UL_PAD_UART1_RTS_B = 36, + MX6UL_PAD_UART2_TX_DATA = 37, + MX6UL_PAD_UART2_RX_DATA = 38, + MX6UL_PAD_UART2_CTS_B = 39, + MX6UL_PAD_UART2_RTS_B = 40, + MX6UL_PAD_UART3_TX_DATA = 41, + MX6UL_PAD_UART3_RX_DATA = 42, + MX6UL_PAD_UART3_CTS_B = 43, + MX6UL_PAD_UART3_RTS_B = 44, + MX6UL_PAD_UART4_TX_DATA = 45, + MX6UL_PAD_UART4_RX_DATA = 46, + MX6UL_PAD_UART5_TX_DATA = 47, + MX6UL_PAD_UART5_RX_DATA = 48, + MX6UL_PAD_ENET1_RX_DATA0 = 49, + MX6UL_PAD_ENET1_RX_DATA1 = 50, + MX6UL_PAD_ENET1_RX_EN = 51, + MX6UL_PAD_ENET1_TX_DATA0 = 52, + MX6UL_PAD_ENET1_TX_DATA1 = 53, + MX6UL_PAD_ENET1_TX_EN = 54, + MX6UL_PAD_ENET1_TX_CLK = 55, + MX6UL_PAD_ENET1_RX_ER = 56, + MX6UL_PAD_ENET2_RX_DATA0 = 57, + MX6UL_PAD_ENET2_RX_DATA1 = 58, + MX6UL_PAD_ENET2_RX_EN = 59, + MX6UL_PAD_ENET2_TX_DATA0 = 60, + MX6UL_PAD_ENET2_TX_DATA1 = 61, + MX6UL_PAD_ENET2_TX_EN = 62, + MX6UL_PAD_ENET2_TX_CLK = 63, + MX6UL_PAD_ENET2_RX_ER = 64, + MX6UL_PAD_LCD_CLK = 65, + MX6UL_PAD_LCD_ENABLE = 66, + MX6UL_PAD_LCD_HSYNC = 67, + MX6UL_PAD_LCD_VSYNC = 68, + MX6UL_PAD_LCD_RESET = 69, + MX6UL_PAD_LCD_DATA00 = 70, + MX6UL_PAD_LCD_DATA01 = 71, + MX6UL_PAD_LCD_DATA02 = 72, + MX6UL_PAD_LCD_DATA03 = 73, + MX6UL_PAD_LCD_DATA04 = 74, + MX6UL_PAD_LCD_DATA05 = 75, + MX6UL_PAD_LCD_DATA06 = 76, + MX6UL_PAD_LCD_DATA07 = 77, + MX6UL_PAD_LCD_DATA08 = 78, + MX6UL_PAD_LCD_DATA09 = 79, + MX6UL_PAD_LCD_DATA10 = 80, + MX6UL_PAD_LCD_DATA11 = 81, + MX6UL_PAD_LCD_DATA12 = 82, + MX6UL_PAD_LCD_DATA13 = 83, + MX6UL_PAD_LCD_DATA14 = 84, + MX6UL_PAD_LCD_DATA15 = 85, + MX6UL_PAD_LCD_DATA16 = 86, + MX6UL_PAD_LCD_DATA17 = 87, + MX6UL_PAD_LCD_DATA18 = 88, + MX6UL_PAD_LCD_DATA19 = 89, + MX6UL_PAD_LCD_DATA20 = 90, + MX6UL_PAD_LCD_DATA21 = 91, + MX6UL_PAD_LCD_DATA22 = 92, + MX6UL_PAD_LCD_DATA23 = 93, + MX6UL_PAD_NAND_RE_B = 94, + MX6UL_PAD_NAND_WE_B = 95, + MX6UL_PAD_NAND_DATA00 = 96, + MX6UL_PAD_NAND_DATA01 = 97, + MX6UL_PAD_NAND_DATA02 = 98, + MX6UL_PAD_NAND_DATA03 = 99, + MX6UL_PAD_NAND_DATA04 = 100, + MX6UL_PAD_NAND_DATA05 = 101, + MX6UL_PAD_NAND_DATA06 = 102, + MX6UL_PAD_NAND_DATA07 = 103, + MX6UL_PAD_NAND_ALE = 104, + MX6UL_PAD_NAND_WP_B = 105, + MX6UL_PAD_NAND_READY_B = 106, + MX6UL_PAD_NAND_CE0_B = 107, + MX6UL_PAD_NAND_CE1_B = 108, + MX6UL_PAD_NAND_CLE = 109, + MX6UL_PAD_NAND_DQS = 110, + MX6UL_PAD_SD1_CMD = 111, + MX6UL_PAD_SD1_CLK = 112, + MX6UL_PAD_SD1_DATA0 = 113, + MX6UL_PAD_SD1_DATA1 = 114, + MX6UL_PAD_SD1_DATA2 = 115, + MX6UL_PAD_SD1_DATA3 = 116, + MX6UL_PAD_CSI_MCLK = 117, + MX6UL_PAD_CSI_PIXCLK = 118, + MX6UL_PAD_CSI_VSYNC = 119, + MX6UL_PAD_CSI_HSYNC = 120, + MX6UL_PAD_CSI_DATA00 = 121, + MX6UL_PAD_CSI_DATA01 = 122, + MX6UL_PAD_CSI_DATA02 = 123, + MX6UL_PAD_CSI_DATA03 = 124, + MX6UL_PAD_CSI_DATA04 = 125, + MX6UL_PAD_CSI_DATA05 = 126, + MX6UL_PAD_CSI_DATA06 = 127, + MX6UL_PAD_CSI_DATA07 = 128, +}; + +/* Pad names for the pinmux subsystem */ +static const struct pinctrl_pin_desc imx6ul_pinctrl_pads[] = { + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE0), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE1), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE2), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE3), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE4), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE5), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE6), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE7), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE8), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE9), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE10), + IMX_PINCTRL_PIN(MX6UL_PAD_SNVS_TAMPER4), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE12), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE13), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE14), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE15), + IMX_PINCTRL_PIN(MX6UL_PAD_RESERVE16), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_MOD), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TMS), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TDO), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TDI), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TCK), + IMX_PINCTRL_PIN(MX6UL_PAD_JTAG_TRST_B), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO00), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO01), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO02), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO03), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO04), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO05), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO06), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO07), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO08), + IMX_PINCTRL_PIN(MX6UL_PAD_GPIO1_IO09), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_CTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART1_RTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_CTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART2_RTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_CTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART3_RTS_B), + IMX_PINCTRL_PIN(MX6UL_PAD_UART4_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART4_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART5_TX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_UART5_RX_DATA), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_TX_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET1_RX_ER), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_EN), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_TX_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_ENET2_RX_ER), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_ENABLE), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_HSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_VSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_RESET), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA00), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA01), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA02), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA03), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA04), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA05), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA06), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA07), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA08), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA09), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA10), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA11), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA12), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA13), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA14), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA15), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA16), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA17), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA18), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA19), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA20), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA21), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA22), + IMX_PINCTRL_PIN(MX6UL_PAD_LCD_DATA23), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_RE_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_WE_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA00), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA01), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA02), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA03), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA04), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA05), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA06), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DATA07), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_ALE), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_WP_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_READY_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_CE0_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_CE1_B), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_CLE), + IMX_PINCTRL_PIN(MX6UL_PAD_NAND_DQS), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_CMD), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_CLK), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA0), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA1), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA2), + IMX_PINCTRL_PIN(MX6UL_PAD_SD1_DATA3), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_MCLK), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_PIXCLK), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_VSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_HSYNC), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA00), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA01), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA02), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA03), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA04), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA05), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA06), + IMX_PINCTRL_PIN(MX6UL_PAD_CSI_DATA07), +}; + +static struct imx_pinctrl_soc_info imx6ul_pinctrl_info = { + .pins = imx6ul_pinctrl_pads, + .npins = ARRAY_SIZE(imx6ul_pinctrl_pads), +}; + +static struct of_device_id imx6ul_pinctrl_of_match[] = { + { .compatible = "fsl,imx6ul-iomuxc", }, + { /* sentinel */ } +}; + +static int imx6ul_pinctrl_probe(struct platform_device *pdev) +{ + return imx_pinctrl_probe(pdev, &imx6ul_pinctrl_info); +} + +static struct platform_driver imx6ul_pinctrl_driver = { + .driver = { + .name = "imx6ul-pinctrl", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match), + }, + .probe = imx6ul_pinctrl_probe, + .remove = imx_pinctrl_remove, +}; + +static int __init imx6ul_pinctrl_init(void) +{ + return platform_driver_register(&imx6ul_pinctrl_driver); +} +arch_initcall(imx6ul_pinctrl_init); + +static void __exit imx6ul_pinctrl_exit(void) +{ + platform_driver_unregister(&imx6ul_pinctrl_driver); +} +module_exit(imx6ul_pinctrl_exit); + +MODULE_AUTHOR("Anson Huang "); +MODULE_DESCRIPTION("Freescale imx6ul pinctrl driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From fb00de771b0c35fc42212272596ddb07bf120b21 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 18 Jun 2015 14:42:45 +0900 Subject: [PATCH 0924/7006] pinctrl: simplify of_pinctrl_get() This commit does not change the logic at all. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/devicetree.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/pinctrl/devicetree.c b/drivers/pinctrl/devicetree.c index 0bbf7d71b2811..fe04e748dfe4b 100644 --- a/drivers/pinctrl/devicetree.c +++ b/drivers/pinctrl/devicetree.c @@ -97,13 +97,7 @@ static int dt_remember_or_free_map(struct pinctrl *p, const char *statename, struct pinctrl_dev *of_pinctrl_get(struct device_node *np) { - struct pinctrl_dev *pctldev; - - pctldev = get_pinctrl_dev_from_of_node(np); - if (!pctldev) - return NULL; - - return pctldev; + return get_pinctrl_dev_from_of_node(np); } static int dt_to_map_one_config(struct pinctrl *p, const char *statename, -- GitLab From ba5f94cd566ac562c9374729baab156886759946 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:25 -0700 Subject: [PATCH 0925/7006] pinctrl: qcom: spmi-mpp: Transition to generic dt binding parser Use the newly introduced extensible generic dt parser instead of rolling our own dt parsing functions. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 130 +++--------------------- 1 file changed, 16 insertions(+), 114 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 3121de9b63310..b247a17bc2af3 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -129,15 +129,17 @@ struct pmic_mpp_state { struct gpio_chip chip; }; -struct pmic_mpp_bindings { - const char *property; - unsigned param; +static const struct pinconf_generic_params pmic_mpp_bindings[] = { + {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, + {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, }; -static struct pmic_mpp_bindings pmic_mpp_bindings[] = { - {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE}, - {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE}, +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pmic_conf_items[] = { + PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), + PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), }; +#endif static const char *const pmic_mpp_groups[] = { "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", @@ -204,118 +206,11 @@ static int pmic_mpp_get_group_pins(struct pinctrl_dev *pctldev, return 0; } -static int pmic_mpp_parse_dt_config(struct device_node *np, - struct pinctrl_dev *pctldev, - unsigned long **configs, - unsigned int *nconfs) -{ - struct pmic_mpp_bindings *par; - unsigned long cfg; - int ret, i; - u32 val; - - for (i = 0; i < ARRAY_SIZE(pmic_mpp_bindings); i++) { - par = &pmic_mpp_bindings[i]; - ret = of_property_read_u32(np, par->property, &val); - - /* property not found */ - if (ret == -EINVAL) - continue; - - /* use zero as default value, when no value is specified */ - if (ret) - val = 0; - - dev_dbg(pctldev->dev, "found %s with value %u\n", - par->property, val); - - cfg = pinconf_to_config_packed(par->param, val); - - ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg); - if (ret) - return ret; - } - - return 0; -} - -static int pmic_mpp_dt_subnode_to_map(struct pinctrl_dev *pctldev, - struct device_node *np, - struct pinctrl_map **map, - unsigned *reserv, unsigned *nmaps, - enum pinctrl_map_type type) -{ - unsigned long *configs = NULL; - unsigned nconfs = 0; - struct property *prop; - const char *group; - int ret; - - ret = pmic_mpp_parse_dt_config(np, pctldev, &configs, &nconfs); - if (ret < 0) - return ret; - - if (!nconfs) - return 0; - - ret = of_property_count_strings(np, "pins"); - if (ret < 0) - goto exit; - - ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret); - if (ret < 0) - goto exit; - - of_property_for_each_string(np, "pins", prop, group) { - ret = pinctrl_utils_add_map_configs(pctldev, map, - reserv, nmaps, group, - configs, nconfs, type); - if (ret < 0) - break; - } -exit: - kfree(configs); - return ret; -} - -static int pmic_mpp_dt_node_to_map(struct pinctrl_dev *pctldev, - struct device_node *np_config, - struct pinctrl_map **map, unsigned *nmaps) -{ - struct device_node *np; - enum pinctrl_map_type type; - unsigned reserv; - int ret; - - ret = 0; - *map = NULL; - *nmaps = 0; - reserv = 0; - type = PIN_MAP_TYPE_CONFIGS_GROUP; - - for_each_child_of_node(np_config, np) { - ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map, - &reserv, nmaps, type); - if (ret) - break; - - ret = pmic_mpp_dt_subnode_to_map(pctldev, np, map, &reserv, - nmaps, type); - if (ret) - break; - } - - if (ret < 0) - pinctrl_utils_dt_free_map(pctldev, *map, *nmaps); - - return ret; -} - static const struct pinctrl_ops pmic_mpp_pinctrl_ops = { .get_groups_count = pmic_mpp_get_groups_count, .get_group_name = pmic_mpp_get_group_name, .get_group_pins = pmic_mpp_get_group_pins, - .dt_node_to_map = pmic_mpp_dt_node_to_map, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_dt_free_map, }; @@ -594,6 +489,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, } static const struct pinconf_ops pmic_mpp_pinconf_ops = { + .is_generic = true, .pin_config_group_get = pmic_mpp_config_get, .pin_config_group_set = pmic_mpp_config_set, .pin_config_group_dbg_show = pmic_mpp_config_dbg_show, @@ -866,6 +762,12 @@ static int pmic_mpp_probe(struct platform_device *pdev) pctrldesc->pins = pindesc; pctrldesc->npins = npins; + pctrldesc->num_custom_params = ARRAY_SIZE(pmic_mpp_bindings); + pctrldesc->custom_params = pmic_mpp_bindings; +#ifdef CONFIG_DEBUG_FS + pctrldesc->custom_conf_items = pmic_conf_items; +#endif + for (i = 0; i < npins; i++, pindesc++) { pad = &pads[i]; pindesc->drv_data = pad; -- GitLab From 7682b3740dd7e3039ec9885b423f7e68f0dc24d0 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:26 -0700 Subject: [PATCH 0926/7006] pinctrl: qcom: spmi-mpp: Fixes related to enable handling There's currently no way to re-enable a mpp block once you've entered a state that disables the state, this patch makes it possible to leave the bias-high-impedance state. Also read the enable state from the hardware on probe. With this in place the is_enabled variable is accurately tracking the state of the hardware and we can use that for the debug output as well. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index b247a17bc2af3..6d9abeea810da 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -354,6 +354,9 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad = pctldev->desc->pins[pin].drv_data; + /* Make it possible to enable the pin, by not setting high impedance */ + pad->is_enabled = true; + for (i = 0; i < nconfs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); @@ -445,7 +448,13 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; - return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + if (ret < 0) + return ret; + + val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; + + return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val); } static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, @@ -453,7 +462,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, { struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); struct pmic_mpp_pad *pad; - int ret, val; + int ret; static const char *const biases[] = { "0.6kOhm", "10kOhm", "30kOhm", "Disabled" @@ -464,9 +473,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET); - val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); - - if (val < 0 || !(val >> PMIC_MPP_REG_MASTER_EN_SHIFT)) { + if (!pad->is_enabled) { seq_puts(s, " ---"); } else { @@ -706,8 +713,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; - /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */ - pad->is_enabled = true; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); + if (val < 0) + return val; + + pad->is_enabled = !!val; + return 0; } -- GitLab From eaaf5dd46457c4fa3a9e2d1be775821d4e72773c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:27 -0700 Subject: [PATCH 0927/7006] pinctrl: qcom: spmi-mpp: Introduce defines for MODE_CTL Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 32 +++++++++++++++---------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 6d9abeea810da..745c37dea7d07 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -85,6 +85,14 @@ #define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0 #define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7 +#define PMIC_MPP_MODE_DIGITAL_INPUT 0 +#define PMIC_MPP_MODE_DIGITAL_OUTPUT 1 +#define PMIC_MPP_MODE_DIGITAL_BIDIR 2 +#define PMIC_MPP_MODE_ANALOG_BIDIR 3 +#define PMIC_MPP_MODE_ANALOG_INPUT 4 +#define PMIC_MPP_MODE_ANALOG_OUTPUT 5 +#define PMIC_MPP_MODE_CURRENT_SINK 6 + #define PMIC_MPP_PHYSICAL_OFFSET 1 /* Qualcomm specific pin configurations */ @@ -248,20 +256,20 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, pad->function = function; if (!pad->analog_mode) { - val = 0; /* just digital input */ + val = PMIC_MPP_MODE_DIGITAL_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = 2; /* digital input and output */ + val = PMIC_MPP_MODE_DIGITAL_BIDIR; else - val = 1; /* just digital output */ + val = PMIC_MPP_MODE_DIGITAL_OUTPUT; } } else { - val = 4; /* just analog input */ + val = PMIC_MPP_MODE_ANALOG_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = 3; /* analog input and output */ + val = PMIC_MPP_MODE_ANALOG_BIDIR; else - val = 5; /* just analog output */ + val = PMIC_MPP_MODE_ANALOG_OUTPUT; } } @@ -654,32 +662,32 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, dir &= PMIC_MPP_REG_MODE_DIR_MASK; switch (dir) { - case 0: + case PMIC_MPP_MODE_DIGITAL_INPUT: pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = false; break; - case 1: + case PMIC_MPP_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = false; break; - case 2: + case PMIC_MPP_MODE_DIGITAL_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = false; break; - case 3: + case PMIC_MPP_MODE_ANALOG_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = true; break; - case 4: + case PMIC_MPP_MODE_ANALOG_INPUT: pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = true; break; - case 5: + case PMIC_MPP_MODE_ANALOG_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = true; -- GitLab From 0e948042c4203b97e44370993ef042c945308282 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:28 -0700 Subject: [PATCH 0928/7006] pinctrl: qcom: spmi-mpp: Implement support for sink mode The MPP supports three modes; digital, analog and sink mode. This patch implements support for the latter. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../bindings/pinctrl/qcom,pmic-mpp.txt | 5 + drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 115 +++++++++++------- 2 files changed, 76 insertions(+), 44 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index ed19991aad35e..d29fb96a57d34 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -134,6 +134,11 @@ to specify in a pin configuration subnode: and/or output-high, output-low MPP could operate as Bidirectional Logic, Analog Input, Analog Output. +- qcom,sink-mode: + Usage: optional + Value type: or + Definition: Selects sink mode of operation + - qcom,amux-route: Usage: optional Value type: diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 745c37dea7d07..9dde023640baa 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -62,6 +62,7 @@ #define PMIC_MPP_REG_DIG_IN_CTL 0x43 #define PMIC_MPP_REG_EN_CTL 0x46 #define PMIC_MPP_REG_AIN_CTL 0x4a +#define PMIC_MPP_REG_SINK_CTL 0x4c /* PMIC_MPP_REG_MODE_CTL */ #define PMIC_MPP_REG_MODE_VALUE_MASK 0x1 @@ -98,6 +99,7 @@ /* Qualcomm specific pin configurations */ #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) #define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) +#define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3) /** * struct pmic_mpp_pad - keep current MPP settings @@ -109,11 +111,13 @@ * @input_enabled: Set to true if MPP input buffer logic is enabled. * @analog_mode: Set to true when MPP should operate in Analog Input, Analog * Output or Bidirectional Analog mode. + * @sink_mode: Boolean indicating if ink mode is slected * @num_sources: Number of power-sources supported by this MPP. * @power_source: Current power-source used. * @amux_input: Set the source for analog input. * @pullup: Pullup resistor value. Valid in Bidirectional mode only. * @function: See pmic_mpp_functions[]. + * @drive_strength: Amount of current in sink mode */ struct pmic_mpp_pad { u16 base; @@ -123,11 +127,13 @@ struct pmic_mpp_pad { bool output_enabled; bool input_enabled; bool analog_mode; + bool sink_mode; unsigned int num_sources; unsigned int power_source; unsigned int amux_input; unsigned int pullup; unsigned int function; + unsigned int drive_strength; }; struct pmic_mpp_state { @@ -140,12 +146,14 @@ struct pmic_mpp_state { static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, + {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0}, }; #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), + PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false), }; #endif @@ -243,33 +251,28 @@ static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev, return 0; } -static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, - unsigned pin) +static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state, + struct pmic_mpp_pad *pad) { - struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); - struct pmic_mpp_pad *pad; unsigned int val; - int ret; - - pad = pctldev->desc->pins[pin].drv_data; - - pad->function = function; - if (!pad->analog_mode) { - val = PMIC_MPP_MODE_DIGITAL_INPUT; + if (pad->analog_mode) { + val = PMIC_MPP_MODE_ANALOG_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = PMIC_MPP_MODE_DIGITAL_BIDIR; + val = PMIC_MPP_MODE_ANALOG_BIDIR; else - val = PMIC_MPP_MODE_DIGITAL_OUTPUT; + val = PMIC_MPP_MODE_ANALOG_OUTPUT; } + } else if (pad->sink_mode) { + val = PMIC_MPP_MODE_CURRENT_SINK; } else { - val = PMIC_MPP_MODE_ANALOG_INPUT; + val = PMIC_MPP_MODE_DIGITAL_INPUT; if (pad->output_enabled) { if (pad->input_enabled) - val = PMIC_MPP_MODE_ANALOG_BIDIR; + val = PMIC_MPP_MODE_DIGITAL_BIDIR; else - val = PMIC_MPP_MODE_ANALOG_OUTPUT; + val = PMIC_MPP_MODE_DIGITAL_OUTPUT; } } @@ -277,9 +280,22 @@ static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; - ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); - if (ret < 0) - return ret; + return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); +} + +static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function, + unsigned pin) +{ + struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev); + struct pmic_mpp_pad *pad; + unsigned int val; + int ret; + + pad = pctldev->desc->pins[pin].drv_data; + + pad->function = function; + + ret = pmic_mpp_write_mode_ctl(state, pad); val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT; @@ -339,9 +355,15 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PMIC_MPP_CONF_AMUX_ROUTE: arg = pad->amux_input; break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = pad->drive_strength; + break; case PMIC_MPP_CONF_ANALOG_MODE: arg = pad->analog_mode; break; + case PMIC_MPP_CONF_SINK_MODE: + arg = pad->sink_mode; + break; default: return -EINVAL; } @@ -403,13 +425,19 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->output_enabled = true; pad->out_value = arg; break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = pad->drive_strength; + break; case PMIC_MPP_CONF_AMUX_ROUTE: if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4) return -EINVAL; pad->amux_input = arg; break; case PMIC_MPP_CONF_ANALOG_MODE: - pad->analog_mode = true; + pad->analog_mode = !!arg; + break; + case PMIC_MPP_CONF_SINK_MODE: + pad->sink_mode = !!arg; break; default: return -EINVAL; @@ -434,29 +462,7 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; - if (!pad->analog_mode) { - val = 0; /* just digital input */ - if (pad->output_enabled) { - if (pad->input_enabled) - val = 2; /* digital input and output */ - else - val = 1; /* just digital output */ - } - } else { - val = 4; /* just analog input */ - if (pad->output_enabled) { - if (pad->input_enabled) - val = 3; /* analog input and output */ - else - val = 5; /* just analog output */ - } - } - - val = val << PMIC_MPP_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; - - ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); + ret = pmic_mpp_write_mode_ctl(state, pad); if (ret < 0) return ret; @@ -476,6 +482,9 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, "0.6kOhm", "10kOhm", "30kOhm", "Disabled" }; + static const char *const modes[] = { + "digital", "analog", "sink" + }; pad = pctldev->desc->pins[pin].drv_data; @@ -495,7 +504,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); - seq_printf(s, " %-4s", pad->analog_mode ? "ana" : "dig"); + seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]); seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); seq_printf(s, " vin-%d", pad->power_source); seq_printf(s, " %-8s", biases[pad->pullup]); @@ -666,31 +675,43 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = false; + pad->sink_mode = false; break; case PMIC_MPP_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = false; + pad->sink_mode = false; break; case PMIC_MPP_MODE_DIGITAL_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = false; + pad->sink_mode = false; break; case PMIC_MPP_MODE_ANALOG_BIDIR: pad->input_enabled = true; pad->output_enabled = true; pad->analog_mode = true; + pad->sink_mode = false; break; case PMIC_MPP_MODE_ANALOG_INPUT: pad->input_enabled = true; pad->output_enabled = false; pad->analog_mode = true; + pad->sink_mode = false; break; case PMIC_MPP_MODE_ANALOG_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; pad->analog_mode = true; + pad->sink_mode = false; + break; + case PMIC_MPP_MODE_CURRENT_SINK: + pad->input_enabled = false; + pad->output_enabled = true; + pad->analog_mode = false; + pad->sink_mode = true; break; default: dev_err(state->dev, "unknown MPP direction\n"); @@ -721,6 +742,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT; pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_SINK_CTL); + if (val < 0) + return val; + + pad->drive_strength = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); if (val < 0) return val; -- GitLab From 6e908892025885b07e804dc6c05aab6ce1e06832 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:01 +0900 Subject: [PATCH 0929/7006] pinctrl: UniPhier: add UniPhier pinctrl core support The core support for the pinctrl drivers for all the UniPhier SoCs. Changes in v2: - drop vogus THIS_MODULE because this file is always built-in - drop vogus "include because this file is always built-in Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 1 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/uniphier/Kconfig | 8 + drivers/pinctrl/uniphier/Makefile | 1 + .../pinctrl/uniphier/pinctrl-uniphier-core.c | 684 ++++++++++++++++++ drivers/pinctrl/uniphier/pinctrl-uniphier.h | 217 ++++++ 6 files changed, 912 insertions(+) create mode 100644 drivers/pinctrl/uniphier/Kconfig create mode 100644 drivers/pinctrl/uniphier/Makefile create mode 100644 drivers/pinctrl/uniphier/pinctrl-uniphier-core.c create mode 100644 drivers/pinctrl/uniphier/pinctrl-uniphier.h diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 100d9ac2ae1f6..e6362c61b5604 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -240,6 +240,7 @@ source "drivers/pinctrl/samsung/Kconfig" source "drivers/pinctrl/sh-pfc/Kconfig" source "drivers/pinctrl/spear/Kconfig" source "drivers/pinctrl/sunxi/Kconfig" +source "drivers/pinctrl/uniphier/Kconfig" source "drivers/pinctrl/vt8500/Kconfig" source "drivers/pinctrl/mediatek/Kconfig" diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f4216d9347e2c..f6710a8a15032 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -51,5 +51,6 @@ obj-$(CONFIG_PINCTRL_SAMSUNG) += samsung/ obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc/ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ +obj-$(CONFIG_ARCH_UNIPHIER) += uniphier/ obj-$(CONFIG_ARCH_VT8500) += vt8500/ obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig new file mode 100644 index 0000000000000..37e39c8dd030d --- /dev/null +++ b/drivers/pinctrl/uniphier/Kconfig @@ -0,0 +1,8 @@ +if ARCH_UNIPHIER + +config PINCTRL_UNIPHIER_CORE + bool + select PINMUX + select GENERIC_PINCONF + +endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile new file mode 100644 index 0000000000000..748aa1b4e4203 --- /dev/null +++ b/drivers/pinctrl/uniphier/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c new file mode 100644 index 0000000000000..918f3b643f1b0 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier-core.c @@ -0,0 +1,684 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../core.h" +#include "../pinctrl-utils.h" +#include "pinctrl-uniphier.h" + +struct uniphier_pinctrl_priv { + struct pinctrl_dev *pctldev; + struct regmap *regmap; + struct uniphier_pinctrl_socdata *socdata; +}; + +static int uniphier_pctl_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->groups_count; +} + +static const char *uniphier_pctl_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->groups[selector].name; +} + +static int uniphier_pctl_get_group_pins(struct pinctrl_dev *pctldev, + unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + *pins = priv->socdata->groups[selector].pins; + *num_pins = priv->socdata->groups[selector].num_pins; + + return 0; +} + +#ifdef CONFIG_DEBUG_FS +static void uniphier_pctl_pin_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, unsigned offset) +{ + const struct pinctrl_pin_desc *pin = &pctldev->desc->pins[offset]; + const char *pull_dir, *drv_str; + + switch (uniphier_pin_get_pull_dir(pin->drv_data)) { + case UNIPHIER_PIN_PULL_UP: + pull_dir = "UP"; + break; + case UNIPHIER_PIN_PULL_DOWN: + pull_dir = "DOWN"; + break; + case UNIPHIER_PIN_PULL_NONE: + pull_dir = "NONE"; + break; + default: + BUG(); + } + + switch (uniphier_pin_get_drv_str(pin->drv_data)) { + case UNIPHIER_PIN_DRV_4_8: + drv_str = "4/8(mA)"; + break; + case UNIPHIER_PIN_DRV_8_12_16_20: + drv_str = "8/12/16/20(mA)"; + break; + case UNIPHIER_PIN_DRV_FIXED_4: + drv_str = "4(mA)"; + break; + case UNIPHIER_PIN_DRV_FIXED_5: + drv_str = "5(mA)"; + break; + case UNIPHIER_PIN_DRV_FIXED_8: + drv_str = "8(mA)"; + break; + case UNIPHIER_PIN_DRV_NONE: + drv_str = "NONE"; + break; + default: + BUG(); + } + + seq_printf(s, " PULL_DIR=%s DRV_STR=%s", pull_dir, drv_str); +} +#endif + +static const struct pinctrl_ops uniphier_pctlops = { + .get_groups_count = uniphier_pctl_get_groups_count, + .get_group_name = uniphier_pctl_get_group_name, + .get_group_pins = uniphier_pctl_get_group_pins, +#ifdef CONFIG_DEBUG_FS + .pin_dbg_show = uniphier_pctl_pin_dbg_show, +#endif + .dt_node_to_map = pinconf_generic_dt_node_to_map_all, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int uniphier_conf_pin_bias_get(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + enum pin_config_param param) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_pull_dir pull_dir = + uniphier_pin_get_pull_dir(pin->drv_data); + unsigned int pupdctrl, reg, shift, val; + unsigned int expected = 1; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (pull_dir == UNIPHIER_PIN_PULL_NONE) + return 0; + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || + pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) + return -EINVAL; + expected = 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_UP) + return -EINVAL; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_DOWN) + return -EINVAL; + break; + default: + BUG(); + } + + pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); + + reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; + shift = pupdctrl % 32; + + ret = regmap_read(priv->regmap, reg, &val); + if (ret) + return ret; + + val = (val >> shift) & 1; + + return (val == expected) ? 0 : -EINVAL; +} + +static int uniphier_conf_pin_drive_get(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + u16 *strength) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_drv_str drv_str = + uniphier_pin_get_drv_str(pin->drv_data); + const unsigned int strength_4_8[] = {4, 8}; + const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20}; + const unsigned int *supported_strength; + unsigned int drvctrl, reg, shift, mask, width, val; + int ret; + + switch (drv_str) { + case UNIPHIER_PIN_DRV_4_8: + supported_strength = strength_4_8; + width = 1; + break; + case UNIPHIER_PIN_DRV_8_12_16_20: + supported_strength = strength_8_12_16_20; + width = 2; + break; + case UNIPHIER_PIN_DRV_FIXED_4: + *strength = 4; + return 0; + case UNIPHIER_PIN_DRV_FIXED_5: + *strength = 5; + return 0; + case UNIPHIER_PIN_DRV_FIXED_8: + *strength = 8; + return 0; + default: + /* drive strength control is not supported for this pin */ + return -EINVAL; + } + + drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); + drvctrl *= width; + + reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : + UNIPHIER_PINCTRL_DRVCTRL_BASE; + + reg += drvctrl / 32 * 4; + shift = drvctrl % 32; + mask = (1U << width) - 1; + + ret = regmap_read(priv->regmap, reg, &val); + if (ret) + return ret; + + *strength = supported_strength[(val >> shift) & mask]; + + return 0; +} + +static int uniphier_conf_pin_input_enable_get(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); + unsigned int val; + int ret; + + if (iectrl == UNIPHIER_PIN_IECTRL_NONE) + /* This pin is always input-enabled. */ + return 0; + + ret = regmap_read(priv->regmap, UNIPHIER_PINCTRL_IECTRL, &val); + if (ret) + return ret; + + return val & BIT(iectrl) ? 0 : -EINVAL; +} + +static int uniphier_conf_pin_config_get(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs) +{ + const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; + enum pin_config_param param = pinconf_to_config_param(*configs); + bool has_arg = false; + u16 arg; + int ret; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + ret = uniphier_conf_pin_bias_get(pctldev, pin_desc, param); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ret = uniphier_conf_pin_drive_get(pctldev, pin_desc, &arg); + has_arg = true; + break; + case PIN_CONFIG_INPUT_ENABLE: + ret = uniphier_conf_pin_input_enable_get(pctldev, pin_desc); + break; + default: + /* unsupported parameter */ + ret = -EINVAL; + break; + } + + if (ret == 0 && has_arg) + *configs = pinconf_to_config_packed(param, arg); + + return ret; +} + +static int uniphier_conf_pin_bias_set(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + enum pin_config_param param, + u16 arg) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_pull_dir pull_dir = + uniphier_pin_get_pull_dir(pin->drv_data); + unsigned int pupdctrl, reg, shift; + unsigned int val = 1; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + if (pull_dir == UNIPHIER_PIN_PULL_NONE) + return 0; + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED || + pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED) { + dev_err(pctldev->dev, + "can not disable pull register for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + val = 0; + break; + case PIN_CONFIG_BIAS_PULL_UP: + if (pull_dir == UNIPHIER_PIN_PULL_UP_FIXED && arg != 0) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_UP) { + dev_err(pctldev->dev, + "pull-up is unsupported for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + if (arg == 0) { + dev_err(pctldev->dev, "pull-up can not be total\n"); + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + if (pull_dir == UNIPHIER_PIN_PULL_DOWN_FIXED && arg != 0) + return 0; + if (pull_dir != UNIPHIER_PIN_PULL_DOWN) { + dev_err(pctldev->dev, + "pull-down is unsupported for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + if (arg == 0) { + dev_err(pctldev->dev, "pull-down can not be total\n"); + return -EINVAL; + } + break; + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + if (pull_dir == UNIPHIER_PIN_PULL_NONE) { + dev_err(pctldev->dev, + "pull-up/down is unsupported for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + + if (arg == 0) + return 0; /* configuration ingored */ + break; + default: + BUG(); + } + + pupdctrl = uniphier_pin_get_pupdctrl(pin->drv_data); + + reg = UNIPHIER_PINCTRL_PUPDCTRL_BASE + pupdctrl / 32 * 4; + shift = pupdctrl % 32; + + return regmap_update_bits(priv->regmap, reg, 1 << shift, val << shift); +} + +static int uniphier_conf_pin_drive_set(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + u16 strength) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + enum uniphier_pin_drv_str drv_str = + uniphier_pin_get_drv_str(pin->drv_data); + const unsigned int strength_4_8[] = {4, 8, -1}; + const unsigned int strength_8_12_16_20[] = {8, 12, 16, 20, -1}; + const unsigned int *supported_strength; + unsigned int drvctrl, reg, shift, mask, width, val; + + switch (drv_str) { + case UNIPHIER_PIN_DRV_4_8: + supported_strength = strength_4_8; + width = 1; + break; + case UNIPHIER_PIN_DRV_8_12_16_20: + supported_strength = strength_8_12_16_20; + width = 2; + break; + default: + dev_err(pctldev->dev, + "cannot change drive strength for pin %u (%s)\n", + pin->number, pin->name); + return -EINVAL; + } + + for (val = 0; supported_strength[val] > 0; val++) { + if (supported_strength[val] > strength) + break; + } + + if (val == 0) { + dev_err(pctldev->dev, + "unsupported drive strength %u mA for pin %u (%s)\n", + strength, pin->number, pin->name); + return -EINVAL; + } + + val--; + + drvctrl = uniphier_pin_get_drvctrl(pin->drv_data); + drvctrl *= width; + + reg = (width == 2) ? UNIPHIER_PINCTRL_DRV2CTRL_BASE : + UNIPHIER_PINCTRL_DRVCTRL_BASE; + + reg += drvctrl / 32 * 4; + shift = drvctrl % 32; + mask = (1U << width) - 1; + + return regmap_update_bits(priv->regmap, reg, + mask << shift, val << shift); +} + +static int uniphier_conf_pin_input_enable(struct pinctrl_dev *pctldev, + const struct pinctrl_pin_desc *pin, + u16 enable) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned int iectrl = uniphier_pin_get_iectrl(pin->drv_data); + + if (enable == 0) { + /* + * Multiple pins share one input enable, so per-pin disabling + * is impossible. + */ + dev_err(pctldev->dev, "unable to disable input\n"); + return -EINVAL; + } + + if (iectrl == UNIPHIER_PIN_IECTRL_NONE) + /* This pin is always input-enabled. nothing to do. */ + return 0; + + return regmap_update_bits(priv->regmap, UNIPHIER_PINCTRL_IECTRL, + BIT(iectrl), BIT(iectrl)); +} + +static int uniphier_conf_pin_config_set(struct pinctrl_dev *pctldev, + unsigned pin, + unsigned long *configs, + unsigned num_configs) +{ + const struct pinctrl_pin_desc *pin_desc = &pctldev->desc->pins[pin]; + int i, ret; + + for (i = 0; i < num_configs; i++) { + enum pin_config_param param = + pinconf_to_config_param(configs[i]); + u16 arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + case PIN_CONFIG_BIAS_PULL_UP: + case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT: + ret = uniphier_conf_pin_bias_set(pctldev, pin_desc, + param, arg); + break; + case PIN_CONFIG_DRIVE_STRENGTH: + ret = uniphier_conf_pin_drive_set(pctldev, pin_desc, + arg); + break; + case PIN_CONFIG_INPUT_ENABLE: + ret = uniphier_conf_pin_input_enable(pctldev, + pin_desc, arg); + break; + default: + dev_err(pctldev->dev, + "unsupported configuration parameter %u\n", + param); + return -EINVAL; + } + + if (ret) + return ret; + } + + return 0; +} + +static int uniphier_conf_pin_config_group_set(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long *configs, + unsigned num_configs) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + const unsigned *pins = priv->socdata->groups[selector].pins; + unsigned num_pins = priv->socdata->groups[selector].num_pins; + int i, ret; + + for (i = 0; i < num_pins; i++) { + ret = uniphier_conf_pin_config_set(pctldev, pins[i], + configs, num_configs); + if (ret) + return ret; + } + + return 0; +} + +static const struct pinconf_ops uniphier_confops = { + .is_generic = true, + .pin_config_get = uniphier_conf_pin_config_get, + .pin_config_set = uniphier_conf_pin_config_set, + .pin_config_group_set = uniphier_conf_pin_config_group_set, +}; + +static int uniphier_pmx_get_functions_count(struct pinctrl_dev *pctldev) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->functions_count; +} + +static const char *uniphier_pmx_get_function_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + return priv->socdata->functions[selector].name; +} + +static int uniphier_pmx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned selector, + const char * const **groups, + unsigned *num_groups) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + + *groups = priv->socdata->functions[selector].groups; + *num_groups = priv->socdata->functions[selector].num_groups; + + return 0; +} + +static int uniphier_pmx_set_one_mux(struct pinctrl_dev *pctldev, unsigned pin, + unsigned muxval) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + unsigned mux_bits = priv->socdata->mux_bits; + unsigned reg_stride = priv->socdata->reg_stride; + unsigned reg, reg_end, shift, mask; + int ret; + + reg = UNIPHIER_PINCTRL_PINMUX_BASE + pin * mux_bits / 32 * reg_stride; + reg_end = reg + reg_stride; + shift = pin * mux_bits % 32; + mask = (1U << mux_bits) - 1; + + /* + * If reg_stride is greater than 4, the MSB of each pinsel shall be + * stored in the offset+4. + */ + for (; reg < reg_end; reg += 4) { + ret = regmap_update_bits(priv->regmap, reg, + mask << shift, muxval << shift); + if (ret) + return ret; + muxval >>= mux_bits; + } + + if (priv->socdata->load_pinctrl) { + ret = regmap_write(priv->regmap, + UNIPHIER_PINCTRL_LOAD_PINMUX, 1); + if (ret) + return ret; + } + + /* some pins need input-enabling */ + return uniphier_conf_pin_input_enable(pctldev, + &pctldev->desc->pins[pin], 1); +} + +static int uniphier_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned func_selector, + unsigned group_selector) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + const struct uniphier_pinctrl_group *grp = + &priv->socdata->groups[group_selector]; + int i; + int ret; + + for (i = 0; i < grp->num_pins; i++) { + ret = uniphier_pmx_set_one_mux(pctldev, grp->pins[i], + grp->muxvals[i]); + if (ret) + return ret; + } + + return 0; +} + +static int uniphier_pmx_gpio_request_enable(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct uniphier_pinctrl_priv *priv = pinctrl_dev_get_drvdata(pctldev); + const struct uniphier_pinctrl_group *groups = priv->socdata->groups; + int groups_count = priv->socdata->groups_count; + enum uniphier_pinmux_gpio_range_type range_type; + int i, j; + + if (strstr(range->name, "irq")) + range_type = UNIPHIER_PINMUX_GPIO_RANGE_IRQ; + else + range_type = UNIPHIER_PINMUX_GPIO_RANGE_PORT; + + for (i = 0; i < groups_count; i++) { + if (groups[i].range_type != range_type) + continue; + + for (j = 0; j < groups[i].num_pins; j++) + if (groups[i].pins[j] == offset) + goto found; + } + + dev_err(pctldev->dev, "pin %u does not support GPIO\n", offset); + return -EINVAL; + +found: + return uniphier_pmx_set_one_mux(pctldev, offset, groups[i].muxvals[j]); +} + +static const struct pinmux_ops uniphier_pmxops = { + .get_functions_count = uniphier_pmx_get_functions_count, + .get_function_name = uniphier_pmx_get_function_name, + .get_function_groups = uniphier_pmx_get_function_groups, + .set_mux = uniphier_pmx_set_mux, + .gpio_request_enable = uniphier_pmx_gpio_request_enable, + .strict = true, +}; + +int uniphier_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *desc, + struct uniphier_pinctrl_socdata *socdata) +{ + struct device *dev = &pdev->dev; + struct uniphier_pinctrl_priv *priv; + + if (!socdata || + !socdata->groups || + !socdata->groups_count || + !socdata->functions || + !socdata->functions_count || + !socdata->mux_bits || + !socdata->reg_stride) { + dev_err(dev, "pinctrl socdata lacks necessary members\n"); + return -EINVAL; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->regmap = syscon_node_to_regmap(dev->of_node); + if (IS_ERR(priv->regmap)) { + dev_err(dev, "failed to get regmap\n"); + return PTR_ERR(priv->regmap); + } + + priv->socdata = socdata; + desc->pctlops = &uniphier_pctlops; + desc->pmxops = &uniphier_pmxops; + desc->confops = &uniphier_confops; + + priv->pctldev = pinctrl_register(desc, dev, priv); + if (IS_ERR(priv->pctldev)) { + dev_err(dev, "failed to register UniPhier pinctrl driver\n"); + return PTR_ERR(priv->pctldev); + } + + platform_set_drvdata(pdev, priv); + + return 0; +} +EXPORT_SYMBOL_GPL(uniphier_pinctrl_probe); + +int uniphier_pinctrl_remove(struct platform_device *pdev) +{ + struct uniphier_pinctrl_priv *priv = platform_get_drvdata(pdev); + + pinctrl_unregister(priv->pctldev); + + return 0; +} +EXPORT_SYMBOL_GPL(uniphier_pinctrl_remove); diff --git a/drivers/pinctrl/uniphier/pinctrl-uniphier.h b/drivers/pinctrl/uniphier/pinctrl-uniphier.h new file mode 100644 index 0000000000000..e1e98b868be50 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-uniphier.h @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __PINCTRL_UNIPHIER_H__ +#define __PINCTRL_UNIPHIER_H__ + +#include +#include +#include + +#define UNIPHIER_PINCTRL_PINMUX_BASE 0x0 +#define UNIPHIER_PINCTRL_LOAD_PINMUX 0x700 +#define UNIPHIER_PINCTRL_DRVCTRL_BASE 0x800 +#define UNIPHIER_PINCTRL_DRV2CTRL_BASE 0x900 +#define UNIPHIER_PINCTRL_PUPDCTRL_BASE 0xa00 +#define UNIPHIER_PINCTRL_IECTRL 0xd00 + +/* input enable control register bit */ +#define UNIPHIER_PIN_IECTRL_SHIFT 0 +#define UNIPHIER_PIN_IECTRL_BITS 8 +#define UNIPHIER_PIN_IECTRL_MASK ((1UL << (UNIPHIER_PIN_IECTRL_BITS)) \ + - 1) + +/* drive strength control register number */ +#define UNIPHIER_PIN_DRVCTRL_SHIFT ((UNIPHIER_PIN_IECTRL_SHIFT) + \ + (UNIPHIER_PIN_IECTRL_BITS)) +#define UNIPHIER_PIN_DRVCTRL_BITS 9 +#define UNIPHIER_PIN_DRVCTRL_MASK ((1UL << (UNIPHIER_PIN_DRVCTRL_BITS)) \ + - 1) + +/* supported drive strength (mA) */ +#define UNIPHIER_PIN_DRV_STR_SHIFT ((UNIPHIER_PIN_DRVCTRL_SHIFT) + \ + (UNIPHIER_PIN_DRVCTRL_BITS)) +#define UNIPHIER_PIN_DRV_STR_BITS 3 +#define UNIPHIER_PIN_DRV_STR_MASK ((1UL << (UNIPHIER_PIN_DRV_STR_BITS)) \ + - 1) + +/* pull-up / pull-down register number */ +#define UNIPHIER_PIN_PUPDCTRL_SHIFT ((UNIPHIER_PIN_DRV_STR_SHIFT) + \ + (UNIPHIER_PIN_DRV_STR_BITS)) +#define UNIPHIER_PIN_PUPDCTRL_BITS 9 +#define UNIPHIER_PIN_PUPDCTRL_MASK ((1UL << (UNIPHIER_PIN_PUPDCTRL_BITS))\ + - 1) + +/* direction of pull register */ +#define UNIPHIER_PIN_PULL_DIR_SHIFT ((UNIPHIER_PIN_PUPDCTRL_SHIFT) + \ + (UNIPHIER_PIN_PUPDCTRL_BITS)) +#define UNIPHIER_PIN_PULL_DIR_BITS 3 +#define UNIPHIER_PIN_PULL_DIR_MASK ((1UL << (UNIPHIER_PIN_PULL_DIR_BITS))\ + - 1) + +#if UNIPHIER_PIN_PULL_DIR_SHIFT + UNIPHIER_PIN_PULL_DIR_BITS > BITS_PER_LONG +#error "unable to pack pin attributes." +#endif + +#define UNIPHIER_PIN_IECTRL_NONE (UNIPHIER_PIN_IECTRL_MASK) + +/* selectable drive strength */ +enum uniphier_pin_drv_str { + UNIPHIER_PIN_DRV_4_8, /* 2 level control: 4/8 mA */ + UNIPHIER_PIN_DRV_8_12_16_20, /* 4 level control: 8/12/16/20 mA */ + UNIPHIER_PIN_DRV_FIXED_4, /* fixed to 4mA */ + UNIPHIER_PIN_DRV_FIXED_5, /* fixed to 5mA */ + UNIPHIER_PIN_DRV_FIXED_8, /* fixed to 8mA */ + UNIPHIER_PIN_DRV_NONE, /* no support (input only pin) */ +}; + +/* direction of pull register (no pin supports bi-directional pull biasing) */ +enum uniphier_pin_pull_dir { + UNIPHIER_PIN_PULL_UP, /* pull-up or disabled */ + UNIPHIER_PIN_PULL_DOWN, /* pull-down or disabled */ + UNIPHIER_PIN_PULL_UP_FIXED, /* always pull-up */ + UNIPHIER_PIN_PULL_DOWN_FIXED, /* always pull-down */ + UNIPHIER_PIN_PULL_NONE, /* no pull register */ +}; + +#define UNIPHIER_PIN_IECTRL(x) \ + (((x) & (UNIPHIER_PIN_IECTRL_MASK)) << (UNIPHIER_PIN_IECTRL_SHIFT)) +#define UNIPHIER_PIN_DRVCTRL(x) \ + (((x) & (UNIPHIER_PIN_DRVCTRL_MASK)) << (UNIPHIER_PIN_DRVCTRL_SHIFT)) +#define UNIPHIER_PIN_DRV_STR(x) \ + (((x) & (UNIPHIER_PIN_DRV_STR_MASK)) << (UNIPHIER_PIN_DRV_STR_SHIFT)) +#define UNIPHIER_PIN_PUPDCTRL(x) \ + (((x) & (UNIPHIER_PIN_PUPDCTRL_MASK)) << (UNIPHIER_PIN_PUPDCTRL_SHIFT)) +#define UNIPHIER_PIN_PULL_DIR(x) \ + (((x) & (UNIPHIER_PIN_PULL_DIR_MASK)) << (UNIPHIER_PIN_PULL_DIR_SHIFT)) + +#define UNIPHIER_PIN_ATTR_PACKED(iectrl, drvctrl, drv_str, pupdctrl, pull_dir)\ + (UNIPHIER_PIN_IECTRL(iectrl) | \ + UNIPHIER_PIN_DRVCTRL(drvctrl) | \ + UNIPHIER_PIN_DRV_STR(drv_str) | \ + UNIPHIER_PIN_PUPDCTRL(pupdctrl) | \ + UNIPHIER_PIN_PULL_DIR(pull_dir)) + +static inline unsigned int uniphier_pin_get_iectrl(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_IECTRL_SHIFT) & + UNIPHIER_PIN_IECTRL_MASK; +} + +static inline unsigned int uniphier_pin_get_drvctrl(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_DRVCTRL_SHIFT) & + UNIPHIER_PIN_DRVCTRL_MASK; +} + +static inline unsigned int uniphier_pin_get_drv_str(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_DRV_STR_SHIFT) & + UNIPHIER_PIN_DRV_STR_MASK; +} + +static inline unsigned int uniphier_pin_get_pupdctrl(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_PUPDCTRL_SHIFT) & + UNIPHIER_PIN_PUPDCTRL_MASK; +} + +static inline unsigned int uniphier_pin_get_pull_dir(void *drv_data) +{ + return ((unsigned long)drv_data >> UNIPHIER_PIN_PULL_DIR_SHIFT) & + UNIPHIER_PIN_PULL_DIR_MASK; +} + +enum uniphier_pinmux_gpio_range_type { + UNIPHIER_PINMUX_GPIO_RANGE_PORT, + UNIPHIER_PINMUX_GPIO_RANGE_IRQ, + UNIPHIER_PINMUX_GPIO_RANGE_NONE, +}; + +struct uniphier_pinctrl_group { + const char *name; + const unsigned *pins; + unsigned num_pins; + const unsigned *muxvals; + enum uniphier_pinmux_gpio_range_type range_type; +}; + +struct uniphier_pinmux_function { + const char *name; + const char * const *groups; + unsigned num_groups; +}; + +struct uniphier_pinctrl_socdata { + const struct uniphier_pinctrl_group *groups; + int groups_count; + const struct uniphier_pinmux_function *functions; + int functions_count; + unsigned mux_bits; + unsigned reg_stride; + bool load_pinctrl; +}; + +#define UNIPHIER_PINCTRL_PIN(a, b, c, d, e, f, g) \ +{ \ + .number = a, \ + .name = b, \ + .drv_data = (void *)UNIPHIER_PIN_ATTR_PACKED(c, d, e, f, g), \ +} + +#define __UNIPHIER_PINCTRL_GROUP(grp, type) \ + { \ + .name = #grp, \ + .pins = grp##_pins, \ + .num_pins = ARRAY_SIZE(grp##_pins), \ + .muxvals = grp##_muxvals + \ + BUILD_BUG_ON_ZERO(ARRAY_SIZE(grp##_pins) != \ + ARRAY_SIZE(grp##_muxvals)), \ + .range_type = type, \ + } + +#define UNIPHIER_PINCTRL_GROUP(grp) \ + __UNIPHIER_PINCTRL_GROUP(grp, UNIPHIER_PINMUX_GPIO_RANGE_NONE) + +#define UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(grp) \ + __UNIPHIER_PINCTRL_GROUP(grp, UNIPHIER_PINMUX_GPIO_RANGE_PORT) + +#define UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(grp) \ + __UNIPHIER_PINCTRL_GROUP(grp, UNIPHIER_PINMUX_GPIO_RANGE_IRQ) + +#define UNIPHIER_PINCTRL_GROUP_SINGLE(grp, array, ofst) \ + { \ + .name = #grp, \ + .pins = array##_pins + ofst, \ + .num_pins = 1, \ + .muxvals = array##_muxvals + ofst, \ + } + +#define UNIPHIER_PINMUX_FUNCTION(func) \ + { \ + .name = #func, \ + .groups = func##_groups, \ + .num_groups = ARRAY_SIZE(func##_groups), \ + } + +struct platform_device; +struct pinctrl_desc; + +int uniphier_pinctrl_probe(struct platform_device *pdev, + struct pinctrl_desc *desc, + struct uniphier_pinctrl_socdata *socdata); + +int uniphier_pinctrl_remove(struct platform_device *pdev); + +#endif /* __PINCTRL_UNIPHIER_H__ */ -- GitLab From edd95a4a95f32c701e291e06016c6ca110ef65b7 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:02 +0900 Subject: [PATCH 0930/7006] pinctrl: UniPhier: add UniPhier PH1-LD4 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-LD4 SoC. Changes in v2: - sort groups and funcs alphabetically - add missing "emmc_dat8" group - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 2 + drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c | 886 +++++++++++++++++++++ 3 files changed, 892 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 37e39c8dd030d..78d25df6d0fdb 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -5,4 +5,8 @@ config PINCTRL_UNIPHIER_CORE select PINMUX select GENERIC_PINCONF +config PINCTRL_UNIPHIER_PH1_LD4 + tristate "UniPhier PH1-LD4 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index 748aa1b4e4203..b4bd042ac4f61 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -1 +1,3 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o + +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c b/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c new file mode 100644 index 0000000000000..7beb87e8f499a --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-ld4.c @@ -0,0 +1,886 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-ld4-pinctrl" + +static const struct pinctrl_pin_desc ph1_ld4_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "EA1", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "EA2", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "EA3", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "EA4", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "EA5", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "EA6", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "EA7", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "EA8", 0, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "EA9", 0, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "EA10", 0, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "EA11", 0, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "EA12", 0, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "EA13", 0, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "EA14", 0, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "EA15", 0, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "ECLK", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(17, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(18, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(19, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(20, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(21, "XERST", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(22, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + 146, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(23, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + 147, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(24, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + 148, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + 149, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + 150, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + 151, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_8_12_16_20, + 152, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(29, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_8_12_16_20, + 153, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(30, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_8_12_16_20, + 154, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_8_12_16_20, + 155, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "RMII_RXD0", 6, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "RMII_RXD1", 6, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "RMII_CRS_DV", 6, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "RMII_RXER", 6, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(36, "RMII_REFCLK", 6, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(37, "RMII_TXD0", 6, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(38, "RMII_TXD1", 6, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(39, "RMII_TXEN", 6, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "MDC", 6, + 47, UNIPHIER_PIN_DRV_4_8, + 47, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "MDIO", 6, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "MDIO_INTL", 6, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "PHYRSTL", 6, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_8_12_16_20, + 156, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(45, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_8_12_16_20, + 157, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(46, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_8_12_16_20, + 158, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(47, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_8_12_16_20, + 159, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(48, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_8_12_16_20, + 160, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(49, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_8_12_16_20, + 161, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(50, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + 51, UNIPHIER_PIN_DRV_4_8, + 51, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(51, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(52, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + 53, UNIPHIER_PIN_DRV_4_8, + 53, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(53, "USB0VBUS", 0, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "USB0OD", 0, + 55, UNIPHIER_PIN_DRV_4_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "USB1VBUS", 0, + 56, UNIPHIER_PIN_DRV_4_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "USB1OD", 0, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "PCRESET", 0, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "PCREG", 0, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "PCCE2", 0, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "PCVS1", 0, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "PCCD2", 0, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "PCCD1", 0, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "PCREADY", 0, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "PCDOE", 0, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "PCCE1", 0, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "PCWE", 0, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "PCOE", 0, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "PCWAIT", 0, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "PCIOWR", 0, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "PCIORD", 0, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "HS0DIN0", 0, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "HS0DIN1", 0, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "HS0DIN2", 0, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "HS0DIN3", 0, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "HS0DIN4", 0, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "HS0DIN5", 0, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "HS0DIN6", 0, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "HS0DIN7", 0, + 79, UNIPHIER_PIN_DRV_4_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "HS0BCLKIN", 0, + 80, UNIPHIER_PIN_DRV_4_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "HS0VALIN", 0, + 81, UNIPHIER_PIN_DRV_4_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "HS0SYNCIN", 0, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "HSDOUT0", 0, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "HSDOUT1", 0, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "HSDOUT2", 0, + 85, UNIPHIER_PIN_DRV_4_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "HSDOUT3", 0, + 86, UNIPHIER_PIN_DRV_4_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "HSDOUT4", 0, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "HSDOUT5", 0, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "HSDOUT6", 0, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "HSDOUT7", 0, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "HSBCLKOUT", 0, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "HSVALOUT", 0, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "HSSYNCOUT", 0, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "AGCI", 3, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "AGCR", 4, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "AGCBS", 5, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "IECOUT", 0, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "ASMCK", 0, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "ABCKO", UNIPHIER_PIN_IECTRL_NONE, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "ARCOUT", 0, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(103, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(104, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(105, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "HIN", 1, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(113, "VIN", 2, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(114, "TCON0", UNIPHIER_PIN_IECTRL_NONE, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(115, "TCON1", UNIPHIER_PIN_IECTRL_NONE, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(116, "TCON2", UNIPHIER_PIN_IECTRL_NONE, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(117, "TCON3", UNIPHIER_PIN_IECTRL_NONE, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(118, "TCON4", UNIPHIER_PIN_IECTRL_NONE, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "TCON5", UNIPHIER_PIN_IECTRL_NONE, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "TCON6", 0, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "TCON7", 0, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "PWMA", 0, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "XIRQ1", 0, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "XIRQ2", 0, + 112, UNIPHIER_PIN_DRV_4_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "XIRQ3", 0, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "XIRQ4", 0, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "XIRQ5", 0, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "XIRQ6", 0, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "XIRQ7", 0, + 117, UNIPHIER_PIN_DRV_4_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "XIRQ8", 0, + 118, UNIPHIER_PIN_DRV_4_8, + 118, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "XIRQ9", 0, + 119, UNIPHIER_PIN_DRV_4_8, + 119, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "XIRQ10", 0, + 120, UNIPHIER_PIN_DRV_4_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "XIRQ11", 0, + 121, UNIPHIER_PIN_DRV_4_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "XIRQ14", 0, + 122, UNIPHIER_PIN_DRV_4_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "PORT00", 0, + 123, UNIPHIER_PIN_DRV_4_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "PORT01", 0, + 124, UNIPHIER_PIN_DRV_4_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "PORT02", 0, + 125, UNIPHIER_PIN_DRV_4_8, + 125, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "PORT03", 0, + 126, UNIPHIER_PIN_DRV_4_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "PORT04", 0, + 127, UNIPHIER_PIN_DRV_4_8, + 127, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "PORT05", 0, + 128, UNIPHIER_PIN_DRV_4_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "PORT06", 0, + 129, UNIPHIER_PIN_DRV_4_8, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "PORT07", 0, + 130, UNIPHIER_PIN_DRV_4_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "PORT10", 0, + 131, UNIPHIER_PIN_DRV_4_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "PORT11", 0, + 132, UNIPHIER_PIN_DRV_4_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "PORT12", 0, + 133, UNIPHIER_PIN_DRV_4_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "PORT13", 0, + 134, UNIPHIER_PIN_DRV_4_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "PORT14", 0, + 135, UNIPHIER_PIN_DRV_4_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "PORT15", 0, + 136, UNIPHIER_PIN_DRV_4_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "PORT16", 0, + 137, UNIPHIER_PIN_DRV_4_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "PORT17", UNIPHIER_PIN_IECTRL_NONE, + 138, UNIPHIER_PIN_DRV_4_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "PORT20", 0, + 139, UNIPHIER_PIN_DRV_4_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "PORT21", 0, + 140, UNIPHIER_PIN_DRV_4_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "PORT22", 0, + 141, UNIPHIER_PIN_DRV_4_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "PORT23", 0, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "PORT24", UNIPHIER_PIN_IECTRL_NONE, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "PORT25", 0, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "PORT26", 0, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(159, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(160, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(164, "NANDRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), +}; + +static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27}; +static const unsigned emmc_muxvals[] = {0, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {102, 103}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {104, 105}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {108, 109}; +static const unsigned i2c2_muxvals[] = {2, 2}; +static const unsigned i2c3_pins[] = {108, 109}; +static const unsigned i2c3_muxvals[] = {3, 3}; +static const unsigned nand_pins[] = {24, 25, 26, 27, 28, 29, 30, 31, 158, 159, + 160, 161, 162, 163, 164}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {22, 23}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {85, 88}; +static const unsigned uart0_muxvals[] = {1, 1}; +static const unsigned uart1_pins[] = {155, 156}; +static const unsigned uart1_muxvals[] = {13, 13}; +static const unsigned uart1b_pins[] = {69, 70}; +static const unsigned uart1b_muxvals[] = {23, 23}; +static const unsigned uart2_pins[] = {128, 129}; +static const unsigned uart2_muxvals[] = {13, 13}; +static const unsigned uart3_pins[] = {110, 111}; +static const unsigned uart3_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {53, 54}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {55, 56}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {155, 156}; +static const unsigned usb2_muxvals[] = {4, 4}; +static const unsigned usb2b_pins[] = {67, 68}; +static const unsigned usb2b_muxvals[] = {23, 23}; +static const unsigned port_range0_pins[] = { + 135, 136, 137, 138, 139, 140, 141, 142, /* PORT0x */ + 143, 144, 145, 146, 147, 148, 149, 150, /* PORT1x */ + 151, 152, 153, 154, 155, 156, 157, 0, /* PORT2x */ + 1, 2, 3, 4, 5, 120, 121, 122, /* PORT3x */ + 24, 25, 26, 27, 28, 29, 30, 31, /* PORT4x */ + 40, 41, 42, 43, 44, 45, 46, 47, /* PORT5x */ + 48, 49, 50, 51, 52, 53, 54, 55, /* PORT6x */ + 56, 85, 84, 59, 82, 61, 64, 65, /* PORT7x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT8x */ + 66, 67, 68, 69, 70, 71, 72, 73, /* PORT9x */ + 74, 75, 89, 86, 78, 79, 80, 81, /* PORT10x */ + 60, 83, 58, 57, 88, 87, 77, 76, /* PORT11x */ + 90, 91, 92, 93, 94, 95, 96, 97, /* PORT12x */ + 98, 99, 100, 6, 101, 114, 115, 116, /* PORT13x */ + 103, 108, 21, 22, 23, 117, 118, 119, /* PORT14x */ +}; +static const unsigned port_range0_muxvals[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* PORT0x */ + 0, 0, 0, 0, 0, 0, 0, 0, /* PORT1x */ + 0, 0, 0, 0, 0, 0, 0, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT11x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ +}; +static const unsigned port_range1_pins[] = { + 7, /* PORT166 */ +}; +static const unsigned port_range1_muxvals[] = { + 15, /* PORT166 */ +}; +static const unsigned xirq_range0_pins[] = { + 151, 123, 124, 125, 126, 127, 128, 129, /* XIRQ0-7 */ + 130, 131, 132, 133, 62, /* XIRQ8-12 */ +}; +static const unsigned xirq_range0_muxvals[] = { + 14, 0, 0, 0, 0, 0, 0, 0, /* XIRQ0-7 */ + 0, 0, 0, 0, 14, /* XIRQ8-12 */ +}; +static const unsigned xirq_range1_pins[] = { + 134, 63, /* XIRQ14-15 */ +}; +static const unsigned xirq_range1_muxvals[] = { + 0, 14, /* XIRQ14-15 */ +}; + +static const struct uniphier_pinctrl_group ph1_ld4_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart1b), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb2b), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range0, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range0, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range0, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range0, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range0, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range0, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range0, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range0, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range0, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range0, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range0, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range0, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range0, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range0, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range0, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range0, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range0, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range0, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range0, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port165, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq_range1, 1), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0"}; +static const char * const uart1_groups[] = {"uart1", "uart1b"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2", "usb2b"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-164 missing */ + /* none */ "port165", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", /* none*/ "xirq14", "xirq15", +}; + +static const struct uniphier_pinmux_function ph1_ld4_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_ld4_pindata = { + .groups = ph1_ld4_groups, + .groups_count = ARRAY_SIZE(ph1_ld4_groups), + .functions = ph1_ld4_functions, + .functions_count = ARRAY_SIZE(ph1_ld4_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc ph1_ld4_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_ld4_pins, + .npins = ARRAY_SIZE(ph1_ld4_pins), + .owner = THIS_MODULE, +}; + +static int ph1_ld4_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_ld4_pinctrl_desc, + &ph1_ld4_pindata); +} + +static const struct of_device_id ph1_ld4_pinctrl_match[] = { + { .compatible = "socionext,ph1-ld4-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_ld4_pinctrl_match); + +static struct platform_driver ph1_ld4_pinctrl_driver = { + .probe = ph1_ld4_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_ld4_pinctrl_match, + }, +}; +module_platform_driver(ph1_ld4_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-LD4 pinctrl driver"); +MODULE_LICENSE("GPL"); -- GitLab From b5cf4161ca8a54c79a05beaaf5d18c2c67193105 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:03 +0900 Subject: [PATCH 0931/7006] pinctrl: UniPhier: add UniPhier PH1-Pro4 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-Pro4 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c | 1554 +++++++++++++++++++ 3 files changed, 1559 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 78d25df6d0fdb..944803ffb5ccf 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -9,4 +9,8 @@ config PINCTRL_UNIPHIER_PH1_LD4 tristate "UniPhier PH1-LD4 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_PRO4 + tristate "UniPhier PH1-Pro4 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index b4bd042ac4f61..b1b597e0dccba 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c b/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c new file mode 100644 index 0000000000000..96921e40da5f9 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-pro4.c @@ -0,0 +1,1554 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program5 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-pro4-pinctrl" + +static const struct pinctrl_pin_desc ph1_pro4_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "CK24O", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "VC27A", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "CK27AI", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "CK27AO", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "CKSEL", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(5, "CK27AV", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "AEXCKA", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ASEL", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "ARCRESET", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "ARCUNLOCK", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "XSRST", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "XNMIRQ", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(12, "XSCIRQ", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(13, "EXTRG", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "TRCCLK", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "TRCCTL", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "TRCD0", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(17, "TRCD1", UNIPHIER_PIN_IECTRL_NONE, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "TRCD2", UNIPHIER_PIN_IECTRL_NONE, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "TRCD3", UNIPHIER_PIN_IECTRL_NONE, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "TRCD4", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(21, "TRCD5", UNIPHIER_PIN_IECTRL_NONE, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "TRCD6", UNIPHIER_PIN_IECTRL_NONE, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "TRCD7", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 26, UNIPHIER_PIN_DRV_4_8, + 26, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(29, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(30, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(31, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(32, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(36, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(37, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(38, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(39, "BOOTSWAP", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_NONE, + 39, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(40, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_8_12_16_20, + 40, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(41, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_8_12_16_20, + 41, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(42, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + 42, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(43, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_8_12_16_20, + 43, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(44, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_8_12_16_20, + 44, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(45, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_8_12_16_20, + 45, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(46, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + 46, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(47, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_8_12_16_20, + 47, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(48, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(49, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(50, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(51, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + 51, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(52, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(53, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_8_12_16_20, + 53, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(54, "NRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(55, "DMDSCLTST", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_NONE, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(56, "DMDSDATST", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(57, "AGCI0", 3, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(59, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(60, "AGCBS0", 5, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(62, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(63, "ANTSHORT", UNIPHIER_PIN_IECTRL_NONE, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE, + 79, UNIPHIER_PIN_DRV_4_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 80, UNIPHIER_PIN_DRV_4_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE, + 81, UNIPHIER_PIN_DRV_4_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE, + 85, UNIPHIER_PIN_DRV_4_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "CKFEO", UNIPHIER_PIN_IECTRL_NONE, + 86, UNIPHIER_PIN_DRV_4_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "XFERST", UNIPHIER_PIN_IECTRL_NONE, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "P_FE_ON", UNIPHIER_PIN_IECTRL_NONE, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "P_TU0_ON", UNIPHIER_PIN_IECTRL_NONE, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "XFEIRQ0", UNIPHIER_PIN_IECTRL_NONE, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "XFEIRQ1", UNIPHIER_PIN_IECTRL_NONE, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "XFEIRQ2", UNIPHIER_PIN_IECTRL_NONE, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "XFEIRQ3", UNIPHIER_PIN_IECTRL_NONE, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "XFEIRQ4", UNIPHIER_PIN_IECTRL_NONE, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "XFEIRQ5", UNIPHIER_PIN_IECTRL_NONE, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "XFEIRQ6", UNIPHIER_PIN_IECTRL_NONE, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(106, "SMTD0", UNIPHIER_PIN_IECTRL_NONE, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(107, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(109, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(110, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(111, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "SMTD1", UNIPHIER_PIN_IECTRL_NONE, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(113, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(114, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "XINTM", UNIPHIER_PIN_IECTRL_NONE, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "SCLKM", UNIPHIER_PIN_IECTRL_NONE, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "SBMTP", UNIPHIER_PIN_IECTRL_NONE, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(118, "SBPTM", UNIPHIER_PIN_IECTRL_NONE, + 112, UNIPHIER_PIN_DRV_4_8, + 112, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(119, "XMPREQ", UNIPHIER_PIN_IECTRL_NONE, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(120, "XINTP", UNIPHIER_PIN_IECTRL_NONE, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(121, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "SDBOOT", UNIPHIER_PIN_IECTRL_NONE, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(123, "BFAIL", UNIPHIER_PIN_IECTRL_NONE, + 117, UNIPHIER_PIN_DRV_4_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "XFWE", UNIPHIER_PIN_IECTRL_NONE, + 118, UNIPHIER_PIN_DRV_4_8, + 118, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(125, "RF_COM_RDY", UNIPHIER_PIN_IECTRL_NONE, + 119, UNIPHIER_PIN_DRV_4_8, + 119, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(126, "XDIAG0", UNIPHIER_PIN_IECTRL_NONE, + 120, UNIPHIER_PIN_DRV_4_8, + 120, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(127, "RXD0", UNIPHIER_PIN_IECTRL_NONE, + 121, UNIPHIER_PIN_DRV_4_8, + 121, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(128, "TXD0", UNIPHIER_PIN_IECTRL_NONE, + 122, UNIPHIER_PIN_DRV_4_8, + 122, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(129, "RXD1", UNIPHIER_PIN_IECTRL_NONE, + 123, UNIPHIER_PIN_DRV_4_8, + 123, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(130, "TXD1", UNIPHIER_PIN_IECTRL_NONE, + 124, UNIPHIER_PIN_DRV_4_8, + 124, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(131, "RXD2", UNIPHIER_PIN_IECTRL_NONE, + 125, UNIPHIER_PIN_DRV_4_8, + 125, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(132, "TXD2", UNIPHIER_PIN_IECTRL_NONE, + 126, UNIPHIER_PIN_DRV_4_8, + 126, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(133, "SS0CS", UNIPHIER_PIN_IECTRL_NONE, + 127, UNIPHIER_PIN_DRV_4_8, + 127, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(134, "SS0CLK", UNIPHIER_PIN_IECTRL_NONE, + 128, UNIPHIER_PIN_DRV_4_8, + 128, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(135, "SS0DO", UNIPHIER_PIN_IECTRL_NONE, + 129, UNIPHIER_PIN_DRV_4_8, + 129, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(136, "SS0DI", UNIPHIER_PIN_IECTRL_NONE, + 130, UNIPHIER_PIN_DRV_4_8, + 130, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(137, "MS0CS0", UNIPHIER_PIN_IECTRL_NONE, + 131, UNIPHIER_PIN_DRV_4_8, + 131, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(138, "MS0CLK", UNIPHIER_PIN_IECTRL_NONE, + 132, UNIPHIER_PIN_DRV_4_8, + 132, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(139, "MS0DI", UNIPHIER_PIN_IECTRL_NONE, + 133, UNIPHIER_PIN_DRV_4_8, + 133, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(140, "MS0DO", UNIPHIER_PIN_IECTRL_NONE, + 134, UNIPHIER_PIN_DRV_4_8, + 134, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(141, "XMDMRST", UNIPHIER_PIN_IECTRL_NONE, + 135, UNIPHIER_PIN_DRV_4_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(143, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(144, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(145, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(146, "SCL2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(147, "SDA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(148, "SCL3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(149, "SDA3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(150, "SD0DAT0", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + 136, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(151, "SD0DAT1", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_8_12_16_20, + 137, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(152, "SD0DAT2", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_8_12_16_20, + 138, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(153, "SD0DAT3", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_8_12_16_20, + 139, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(154, "SD0CMD", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_8_12_16_20, + 141, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(155, "SD0CLK", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_8_12_16_20, + 140, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(156, "SD0CD", UNIPHIER_PIN_IECTRL_NONE, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(157, "SD0WP", UNIPHIER_PIN_IECTRL_NONE, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(158, "SD0VTCG", UNIPHIER_PIN_IECTRL_NONE, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(159, "CK25O", UNIPHIER_PIN_IECTRL_NONE, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(160, "RGMII_TXCLK", 6, + 146, UNIPHIER_PIN_DRV_4_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "RGMII_TXD0", 6, + 147, UNIPHIER_PIN_DRV_4_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "RGMII_TXD1", 6, + 148, UNIPHIER_PIN_DRV_4_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "RGMII_TXD2", 6, + 149, UNIPHIER_PIN_DRV_4_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "RGMII_TXD3", 6, + 150, UNIPHIER_PIN_DRV_4_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "RGMII_TXCTL", 6, + 151, UNIPHIER_PIN_DRV_4_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "MII_TXER", UNIPHIER_PIN_IECTRL_NONE, + 152, UNIPHIER_PIN_DRV_4_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "RGMII_RXCLK", 6, + 153, UNIPHIER_PIN_DRV_4_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "RGMII_RXD0", 6, + 154, UNIPHIER_PIN_DRV_4_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "RGMII_RXD1", 6, + 155, UNIPHIER_PIN_DRV_4_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "RGMII_RXD2", 6, + 156, UNIPHIER_PIN_DRV_4_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "RGMII_RXD3", 6, + 157, UNIPHIER_PIN_DRV_4_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "RGMII_RXCTL", 6, + 158, UNIPHIER_PIN_DRV_4_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "MII_RXER", 6, + 159, UNIPHIER_PIN_DRV_4_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "MII_CRS", 6, + 160, UNIPHIER_PIN_DRV_4_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "MII_COL", 6, + 161, UNIPHIER_PIN_DRV_4_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "MDC", 6, + 162, UNIPHIER_PIN_DRV_4_8, + 162, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(177, "MDIO", 6, + 163, UNIPHIER_PIN_DRV_4_8, + 163, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(178, "MDIO_INTL", 6, + 164, UNIPHIER_PIN_DRV_4_8, + 164, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(179, "XETH_RST", 6, + 165, UNIPHIER_PIN_DRV_4_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + 166, UNIPHIER_PIN_DRV_4_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + 167, UNIPHIER_PIN_DRV_4_8, + 167, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(182, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + 168, UNIPHIER_PIN_DRV_4_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + 169, UNIPHIER_PIN_DRV_4_8, + 169, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(184, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + 170, UNIPHIER_PIN_DRV_4_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + 171, UNIPHIER_PIN_DRV_4_8, + 171, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(186, "USB2ID", UNIPHIER_PIN_IECTRL_NONE, + 172, UNIPHIER_PIN_DRV_4_8, + 172, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(187, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE, + 173, UNIPHIER_PIN_DRV_4_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "USB3OD", UNIPHIER_PIN_IECTRL_NONE, + 174, UNIPHIER_PIN_DRV_4_8, + 174, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(189, "LINKCLK", UNIPHIER_PIN_IECTRL_NONE, + 175, UNIPHIER_PIN_DRV_4_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "LINKREQ", UNIPHIER_PIN_IECTRL_NONE, + 176, UNIPHIER_PIN_DRV_4_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "LINKCTL0", UNIPHIER_PIN_IECTRL_NONE, + 177, UNIPHIER_PIN_DRV_4_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "LINKCTL1", UNIPHIER_PIN_IECTRL_NONE, + 178, UNIPHIER_PIN_DRV_4_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "LINKDT0", UNIPHIER_PIN_IECTRL_NONE, + 179, UNIPHIER_PIN_DRV_4_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "LINKDT1", UNIPHIER_PIN_IECTRL_NONE, + 180, UNIPHIER_PIN_DRV_4_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "LINKDT2", UNIPHIER_PIN_IECTRL_NONE, + 181, UNIPHIER_PIN_DRV_4_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "LINKDT3", UNIPHIER_PIN_IECTRL_NONE, + 182, UNIPHIER_PIN_DRV_4_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(197, "LINKDT4", UNIPHIER_PIN_IECTRL_NONE, + 183, UNIPHIER_PIN_DRV_4_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(198, "LINKDT5", UNIPHIER_PIN_IECTRL_NONE, + 184, UNIPHIER_PIN_DRV_4_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "LINKDT6", UNIPHIER_PIN_IECTRL_NONE, + 185, UNIPHIER_PIN_DRV_4_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "LINKDT7", UNIPHIER_PIN_IECTRL_NONE, + 186, UNIPHIER_PIN_DRV_4_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "CKDVO", UNIPHIER_PIN_IECTRL_NONE, + 187, UNIPHIER_PIN_DRV_4_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "PHY_PD", UNIPHIER_PIN_IECTRL_NONE, + 188, UNIPHIER_PIN_DRV_4_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "X1394_RST", UNIPHIER_PIN_IECTRL_NONE, + 189, UNIPHIER_PIN_DRV_4_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "VOUT_MUTE_L", UNIPHIER_PIN_IECTRL_NONE, + 190, UNIPHIER_PIN_DRV_4_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "CLK54O", UNIPHIER_PIN_IECTRL_NONE, + 191, UNIPHIER_PIN_DRV_4_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "CLK54I", UNIPHIER_PIN_IECTRL_NONE, + 192, UNIPHIER_PIN_DRV_NONE, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "YIN0", UNIPHIER_PIN_IECTRL_NONE, + 193, UNIPHIER_PIN_DRV_4_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "YIN1", UNIPHIER_PIN_IECTRL_NONE, + 194, UNIPHIER_PIN_DRV_4_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "YIN2", UNIPHIER_PIN_IECTRL_NONE, + 195, UNIPHIER_PIN_DRV_4_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "YIN3", UNIPHIER_PIN_IECTRL_NONE, + 196, UNIPHIER_PIN_DRV_4_8, + 196, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "YIN4", UNIPHIER_PIN_IECTRL_NONE, + 197, UNIPHIER_PIN_DRV_4_8, + 197, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "YIN5", UNIPHIER_PIN_IECTRL_NONE, + 198, UNIPHIER_PIN_DRV_4_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "CIN0", UNIPHIER_PIN_IECTRL_NONE, + 199, UNIPHIER_PIN_DRV_4_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "CIN1", UNIPHIER_PIN_IECTRL_NONE, + 200, UNIPHIER_PIN_DRV_4_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "CIN2", UNIPHIER_PIN_IECTRL_NONE, + 201, UNIPHIER_PIN_DRV_4_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "CIN3", UNIPHIER_PIN_IECTRL_NONE, + 202, UNIPHIER_PIN_DRV_4_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "CIN4", UNIPHIER_PIN_IECTRL_NONE, + 203, UNIPHIER_PIN_DRV_4_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "CIN5", UNIPHIER_PIN_IECTRL_NONE, + 204, UNIPHIER_PIN_DRV_4_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "GCP", UNIPHIER_PIN_IECTRL_NONE, + 205, UNIPHIER_PIN_DRV_4_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "ADFLG", UNIPHIER_PIN_IECTRL_NONE, + 206, UNIPHIER_PIN_DRV_4_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "CK27AIOF", UNIPHIER_PIN_IECTRL_NONE, + 207, UNIPHIER_PIN_DRV_4_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "DACOUT", UNIPHIER_PIN_IECTRL_NONE, + 208, UNIPHIER_PIN_DRV_4_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "DAFLG", UNIPHIER_PIN_IECTRL_NONE, + 209, UNIPHIER_PIN_DRV_4_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "VBIH", UNIPHIER_PIN_IECTRL_NONE, + 210, UNIPHIER_PIN_DRV_4_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "VBIL", UNIPHIER_PIN_IECTRL_NONE, + 211, UNIPHIER_PIN_DRV_4_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "XSUB_RST", UNIPHIER_PIN_IECTRL_NONE, + 212, UNIPHIER_PIN_DRV_4_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "XADC_PD", UNIPHIER_PIN_IECTRL_NONE, + 213, UNIPHIER_PIN_DRV_4_8, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE, + 214, UNIPHIER_PIN_DRV_4_8, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE, + 215, UNIPHIER_PIN_DRV_4_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE, + 216, UNIPHIER_PIN_DRV_4_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "AI1DMIX", UNIPHIER_PIN_IECTRL_NONE, + 217, UNIPHIER_PIN_DRV_4_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "CK27HD", UNIPHIER_PIN_IECTRL_NONE, + 218, UNIPHIER_PIN_DRV_4_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "XHD_RST", UNIPHIER_PIN_IECTRL_NONE, + 219, UNIPHIER_PIN_DRV_4_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "INTHD", UNIPHIER_PIN_IECTRL_NONE, + 220, UNIPHIER_PIN_DRV_4_8, + 220, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(235, "VO1HDCK", UNIPHIER_PIN_IECTRL_NONE, + 221, UNIPHIER_PIN_DRV_4_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(236, "VO1HSYNC", UNIPHIER_PIN_IECTRL_NONE, + 222, UNIPHIER_PIN_DRV_4_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(237, "VO1VSYNC", UNIPHIER_PIN_IECTRL_NONE, + 223, UNIPHIER_PIN_DRV_4_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(238, "VO1DE", UNIPHIER_PIN_IECTRL_NONE, + 224, UNIPHIER_PIN_DRV_4_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(239, "VO1Y0", UNIPHIER_PIN_IECTRL_NONE, + 225, UNIPHIER_PIN_DRV_4_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(240, "VO1Y1", UNIPHIER_PIN_IECTRL_NONE, + 226, UNIPHIER_PIN_DRV_4_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(241, "VO1Y2", UNIPHIER_PIN_IECTRL_NONE, + 227, UNIPHIER_PIN_DRV_4_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(242, "VO1Y3", UNIPHIER_PIN_IECTRL_NONE, + 228, UNIPHIER_PIN_DRV_4_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(243, "VO1Y4", UNIPHIER_PIN_IECTRL_NONE, + 229, UNIPHIER_PIN_DRV_4_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(244, "VO1Y5", UNIPHIER_PIN_IECTRL_NONE, + 230, UNIPHIER_PIN_DRV_4_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(245, "VO1Y6", UNIPHIER_PIN_IECTRL_NONE, + 231, UNIPHIER_PIN_DRV_4_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(246, "VO1Y7", UNIPHIER_PIN_IECTRL_NONE, + 232, UNIPHIER_PIN_DRV_4_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(247, "VO1Y8", UNIPHIER_PIN_IECTRL_NONE, + 233, UNIPHIER_PIN_DRV_4_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(248, "VO1Y9", UNIPHIER_PIN_IECTRL_NONE, + 234, UNIPHIER_PIN_DRV_4_8, + 234, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(249, "VO1Y10", UNIPHIER_PIN_IECTRL_NONE, + 235, UNIPHIER_PIN_DRV_4_8, + 235, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(250, "VO1Y11", UNIPHIER_PIN_IECTRL_NONE, + 236, UNIPHIER_PIN_DRV_4_8, + 236, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(251, "VO1CB0", UNIPHIER_PIN_IECTRL_NONE, + 237, UNIPHIER_PIN_DRV_4_8, + 237, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(252, "VO1CB1", UNIPHIER_PIN_IECTRL_NONE, + 238, UNIPHIER_PIN_DRV_4_8, + 238, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(253, "VO1CB2", UNIPHIER_PIN_IECTRL_NONE, + 239, UNIPHIER_PIN_DRV_4_8, + 239, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(254, "VO1CB3", UNIPHIER_PIN_IECTRL_NONE, + 240, UNIPHIER_PIN_DRV_4_8, + 240, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(255, "VO1CB4", UNIPHIER_PIN_IECTRL_NONE, + 241, UNIPHIER_PIN_DRV_4_8, + 241, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(256, "VO1CB5", UNIPHIER_PIN_IECTRL_NONE, + 242, UNIPHIER_PIN_DRV_4_8, + 242, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(257, "VO1CB6", UNIPHIER_PIN_IECTRL_NONE, + 243, UNIPHIER_PIN_DRV_4_8, + 243, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(258, "VO1CB7", UNIPHIER_PIN_IECTRL_NONE, + 244, UNIPHIER_PIN_DRV_4_8, + 244, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(259, "VO1CB8", UNIPHIER_PIN_IECTRL_NONE, + 245, UNIPHIER_PIN_DRV_4_8, + 245, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(260, "VO1CB9", UNIPHIER_PIN_IECTRL_NONE, + 246, UNIPHIER_PIN_DRV_4_8, + 246, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(261, "VO1CB10", UNIPHIER_PIN_IECTRL_NONE, + 247, UNIPHIER_PIN_DRV_4_8, + 247, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(262, "VO1CB11", UNIPHIER_PIN_IECTRL_NONE, + 248, UNIPHIER_PIN_DRV_4_8, + 248, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(263, "VO1CR0", UNIPHIER_PIN_IECTRL_NONE, + 249, UNIPHIER_PIN_DRV_4_8, + 249, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(264, "VO1CR1", UNIPHIER_PIN_IECTRL_NONE, + 250, UNIPHIER_PIN_DRV_4_8, + 250, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(265, "VO1CR2", UNIPHIER_PIN_IECTRL_NONE, + 251, UNIPHIER_PIN_DRV_4_8, + 251, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(266, "VO1CR3", UNIPHIER_PIN_IECTRL_NONE, + 252, UNIPHIER_PIN_DRV_4_8, + 252, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(267, "VO1CR4", UNIPHIER_PIN_IECTRL_NONE, + 253, UNIPHIER_PIN_DRV_4_8, + 253, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(268, "VO1CR5", UNIPHIER_PIN_IECTRL_NONE, + 254, UNIPHIER_PIN_DRV_4_8, + 254, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(269, "VO1CR6", UNIPHIER_PIN_IECTRL_NONE, + 255, UNIPHIER_PIN_DRV_4_8, + 255, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(270, "VO1CR7", UNIPHIER_PIN_IECTRL_NONE, + 256, UNIPHIER_PIN_DRV_4_8, + 256, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(271, "VO1CR8", UNIPHIER_PIN_IECTRL_NONE, + 257, UNIPHIER_PIN_DRV_4_8, + 257, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(272, "VO1CR9", UNIPHIER_PIN_IECTRL_NONE, + 258, UNIPHIER_PIN_DRV_4_8, + 258, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(273, "VO1CR10", UNIPHIER_PIN_IECTRL_NONE, + 259, UNIPHIER_PIN_DRV_4_8, + 259, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(274, "VO1CR11", UNIPHIER_PIN_IECTRL_NONE, + 260, UNIPHIER_PIN_DRV_4_8, + 260, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(275, "VO1EX0", UNIPHIER_PIN_IECTRL_NONE, + 261, UNIPHIER_PIN_DRV_4_8, + 261, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(276, "VO1EX1", UNIPHIER_PIN_IECTRL_NONE, + 262, UNIPHIER_PIN_DRV_4_8, + 262, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(277, "VO1EX2", UNIPHIER_PIN_IECTRL_NONE, + 263, UNIPHIER_PIN_DRV_4_8, + 263, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(278, "VO1EX3", UNIPHIER_PIN_IECTRL_NONE, + 264, UNIPHIER_PIN_DRV_4_8, + 264, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(279, "VEXCKA", UNIPHIER_PIN_IECTRL_NONE, + 265, UNIPHIER_PIN_DRV_4_8, + 265, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(280, "VSEL0", UNIPHIER_PIN_IECTRL_NONE, + 266, UNIPHIER_PIN_DRV_4_8, + 266, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(281, "VSEL1", UNIPHIER_PIN_IECTRL_NONE, + 267, UNIPHIER_PIN_DRV_4_8, + 267, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(282, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE, + 268, UNIPHIER_PIN_DRV_4_8, + 268, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(283, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE, + 269, UNIPHIER_PIN_DRV_4_8, + 269, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(284, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE, + 270, UNIPHIER_PIN_DRV_4_8, + 270, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(285, "AO1D0", UNIPHIER_PIN_IECTRL_NONE, + 271, UNIPHIER_PIN_DRV_4_8, + 271, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(286, "AO1D1", UNIPHIER_PIN_IECTRL_NONE, + 272, UNIPHIER_PIN_DRV_4_8, + 272, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(287, "AO1D2", UNIPHIER_PIN_IECTRL_NONE, + 273, UNIPHIER_PIN_DRV_4_8, + 273, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(288, "AO1D3", UNIPHIER_PIN_IECTRL_NONE, + 274, UNIPHIER_PIN_DRV_4_8, + 274, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(289, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE, + 275, UNIPHIER_PIN_DRV_4_8, + 275, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(290, "XDAC_PD", UNIPHIER_PIN_IECTRL_NONE, + 276, UNIPHIER_PIN_DRV_4_8, + 276, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(291, "EX_A_MUTE", UNIPHIER_PIN_IECTRL_NONE, + 277, UNIPHIER_PIN_DRV_4_8, + 277, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(292, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + 278, UNIPHIER_PIN_DRV_4_8, + 278, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(293, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + 279, UNIPHIER_PIN_DRV_4_8, + 279, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(294, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + 280, UNIPHIER_PIN_DRV_4_8, + 280, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(295, "AO2DMIX", UNIPHIER_PIN_IECTRL_NONE, + 281, UNIPHIER_PIN_DRV_4_8, + 281, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(296, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE, + 282, UNIPHIER_PIN_DRV_4_8, + 282, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(297, "HTHPD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(298, "HTSCL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(299, "HTSDA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(300, "PORT00", UNIPHIER_PIN_IECTRL_NONE, + 284, UNIPHIER_PIN_DRV_4_8, + 284, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(301, "PORT01", UNIPHIER_PIN_IECTRL_NONE, + 285, UNIPHIER_PIN_DRV_4_8, + 285, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(302, "PORT02", UNIPHIER_PIN_IECTRL_NONE, + 286, UNIPHIER_PIN_DRV_4_8, + 286, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(303, "PORT03", UNIPHIER_PIN_IECTRL_NONE, + 287, UNIPHIER_PIN_DRV_4_8, + 287, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(304, "PORT04", UNIPHIER_PIN_IECTRL_NONE, + 288, UNIPHIER_PIN_DRV_4_8, + 288, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(305, "PORT05", UNIPHIER_PIN_IECTRL_NONE, + 289, UNIPHIER_PIN_DRV_4_8, + 289, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(306, "PORT06", UNIPHIER_PIN_IECTRL_NONE, + 290, UNIPHIER_PIN_DRV_4_8, + 290, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(307, "PORT07", UNIPHIER_PIN_IECTRL_NONE, + 291, UNIPHIER_PIN_DRV_4_8, + 291, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(308, "PORT10", UNIPHIER_PIN_IECTRL_NONE, + 292, UNIPHIER_PIN_DRV_4_8, + 292, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(309, "PORT11", UNIPHIER_PIN_IECTRL_NONE, + 293, UNIPHIER_PIN_DRV_4_8, + 293, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(310, "PORT12", UNIPHIER_PIN_IECTRL_NONE, + 294, UNIPHIER_PIN_DRV_4_8, + 294, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(311, "PORT13", UNIPHIER_PIN_IECTRL_NONE, + 295, UNIPHIER_PIN_DRV_4_8, + 295, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(312, "PORT14", UNIPHIER_PIN_IECTRL_NONE, + 296, UNIPHIER_PIN_DRV_4_8, + 296, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(313, "PORT15", UNIPHIER_PIN_IECTRL_NONE, + 297, UNIPHIER_PIN_DRV_4_8, + 297, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(314, "PORT16", UNIPHIER_PIN_IECTRL_NONE, + 298, UNIPHIER_PIN_DRV_4_8, + 298, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(315, "PORT17", UNIPHIER_PIN_IECTRL_NONE, + 299, UNIPHIER_PIN_DRV_4_8, + 299, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(316, "PORT20", UNIPHIER_PIN_IECTRL_NONE, + 300, UNIPHIER_PIN_DRV_4_8, + 300, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(317, "PORT21", UNIPHIER_PIN_IECTRL_NONE, + 301, UNIPHIER_PIN_DRV_4_8, + 301, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(318, "PORT22", UNIPHIER_PIN_IECTRL_NONE, + 302, UNIPHIER_PIN_DRV_4_8, + 302, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(319, "SD1DAT0", UNIPHIER_PIN_IECTRL_NONE, + 303, UNIPHIER_PIN_DRV_4_8, + 303, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(320, "SD1DAT1", UNIPHIER_PIN_IECTRL_NONE, + 304, UNIPHIER_PIN_DRV_4_8, + 304, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(321, "SD1DAT2", UNIPHIER_PIN_IECTRL_NONE, + 305, UNIPHIER_PIN_DRV_4_8, + 305, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(322, "SD1DAT3", UNIPHIER_PIN_IECTRL_NONE, + 306, UNIPHIER_PIN_DRV_4_8, + 306, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(323, "SD1CMD", UNIPHIER_PIN_IECTRL_NONE, + 307, UNIPHIER_PIN_DRV_4_8, + 307, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(324, "SD1CLK", UNIPHIER_PIN_IECTRL_NONE, + 308, UNIPHIER_PIN_DRV_4_8, + 308, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(325, "SD1CD", UNIPHIER_PIN_IECTRL_NONE, + 309, UNIPHIER_PIN_DRV_4_8, + 309, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(326, "SD1WP", UNIPHIER_PIN_IECTRL_NONE, + 310, UNIPHIER_PIN_DRV_4_8, + 310, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(327, "SD1VTCG", UNIPHIER_PIN_IECTRL_NONE, + 311, UNIPHIER_PIN_DRV_4_8, + 311, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(328, "DMDISO", UNIPHIER_PIN_IECTRL_NONE, + 312, UNIPHIER_PIN_DRV_NONE, + 312, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned emmc_pins[] = {40, 41, 42, 43, 51, 52, 53}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {44, 45, 46, 47}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {142, 143}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {144, 145}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {146, 147}; +static const unsigned i2c2_muxvals[] = {0, 0}; +static const unsigned i2c3_pins[] = {148, 149}; +static const unsigned i2c3_muxvals[] = {0, 0}; +static const unsigned i2c6_pins[] = {308, 309}; +static const unsigned i2c6_muxvals[] = {6, 6}; +static const unsigned nand_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {131, 132}; +static const unsigned nand_cs1_muxvals[] = {1, 1}; +static const unsigned uart0_pins[] = {127, 128}; +static const unsigned uart0_muxvals[] = {0, 0}; +static const unsigned uart1_pins[] = {129, 130}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {131, 132}; +static const unsigned uart2_muxvals[] = {0, 0}; +static const unsigned uart3_pins[] = {88, 89}; +static const unsigned uart3_muxvals[] = {2, 2}; +static const unsigned usb0_pins[] = {180, 181}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {182, 183}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {184, 185}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned usb3_pins[] = {186, 187}; +static const unsigned usb3_muxvals[] = {0, 0}; +static const unsigned port_range0_pins[] = { + 300, 301, 302, 303, 304, 305, 306, 307, /* PORT0x */ + 308, 309, 310, 311, 312, 313, 314, 315, /* PORT1x */ + 316, 317, 318, 16, 17, 18, 19, 20, /* PORT2x */ + 21, 22, 23, 4, 93, 94, 95, 63, /* PORT3x */ + 123, 122, 124, 125, 126, 141, 202, 203, /* PORT4x */ + 204, 226, 227, 290, 291, 233, 280, 281, /* PORT5x */ + 8, 7, 10, 29, 30, 48, 49, 50, /* PORT6x */ + 40, 41, 42, 43, 44, 45, 46, 47, /* PORT7x */ + 54, 51, 52, 53, 127, 128, 129, 130, /* PORT8x */ + 131, 132, 57, 60, 134, 133, 135, 136, /* PORT9x */ + 138, 137, 140, 139, 64, 65, 66, 67, /* PORT10x */ + 107, 106, 105, 104, 113, 112, 111, 110, /* PORT11x */ + 68, 69, 70, 71, 72, 73, 74, 75, /* PORT12x */ + 76, 77, 78, 79, 80, 81, 82, 83, /* PORT13x */ + 84, 85, 86, 87, 88, 89, 90, 91, /* PORT14x */ +}; +static const unsigned port_range0_muxvals[] = { + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT0x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT1x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT2x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT3x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT4x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT5x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT6x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT7x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT8x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT9x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT10x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT11x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT12x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT13x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT14x */ +}; +static const unsigned port_range1_pins[] = { + 13, 14, 15, /* PORT175-177 */ + 157, 158, 156, 154, 150, 151, 152, 153, /* PORT18x */ + 326, 327, 325, 323, 319, 320, 321, 322, /* PORT19x */ + 160, 161, 162, 163, 164, 165, 166, 167, /* PORT20x */ + 168, 169, 170, 171, 172, 173, 174, 175, /* PORT21x */ + 180, 181, 182, 183, 184, 185, 187, 188, /* PORT22x */ + 193, 194, 195, 196, 197, 198, 199, 200, /* PORT23x */ + 191, 192, 215, 216, 217, 218, 219, 220, /* PORT24x */ + 222, 223, 224, 225, 228, 229, 230, 231, /* PORT25x */ + 282, 283, 284, 285, 286, 287, 288, 289, /* PORT26x */ + 292, 293, 294, 295, 296, 236, 237, 238, /* PORT27x */ + 275, 276, 277, 278, 239, 240, 249, 250, /* PORT28x */ + 251, 252, 261, 262, 263, 264, 273, 274, /* PORT29x */ + 31, 32, 33, 34, 35, 36, 37, 38, /* PORT30x */ +}; +static const unsigned port_range1_muxvals[] = { + 7, 7, 7, /* PORT175-177 */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT18x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT19x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT20x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT21x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT22x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT23x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT24x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT25x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT26x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT27x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT28x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT29x */ + 7, 7, 7, 7, 7, 7, 7, 7, /* PORT30x */ +}; +static const unsigned xirq_pins[] = { + 11, 9, 12, 96, 97, 98, 108, 114, /* XIRQ0-7 */ + 234, 186, 99, 100, 101, 102, 184, 301, /* XIRQ8-15 */ + 302, 303, 304, 305, 306, /* XIRQ16-20 */ +}; +static const unsigned xirq_muxvals[] = { + 7, 7, 7, 7, 7, 7, 7, 7, /* XIRQ0-7 */ + 7, 7, 7, 7, 7, 7, 2, 2, /* XIRQ8-15 */ + 2, 2, 2, 2, 2, /* XIRQ16-20 */ +}; +static const unsigned xirq_alternatives_pins[] = { + 184, 310, 316, +}; +static const unsigned xirq_alternatives_muxvals[] = { + 2, 2, 2, +}; + +static const struct uniphier_pinctrl_group ph1_pro4_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range0, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range0, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range0, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range0, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range0, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range0, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range0, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range0, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range0, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range0, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range0, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range0, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range0, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range0, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range0, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range0, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range0, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range0, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range0, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port290, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port291, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port292, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port293, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port294, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port295, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port296, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port297, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port300, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port301, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port302, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port303, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port304, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port305, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port306, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port307, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14b, xirq_alternatives, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 2), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const i2c6_groups[] = {"i2c6"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const usb3_groups[] = {"usb3"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-174 missing */ + /* none */ "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", + "port290", "port291", "port292", "port293", + "port294", "port295", "port296", "port297", + "port300", "port301", "port302", "port303", + "port304", "port305", "port306", "port307", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", + "xirq14b", "xirq17b", "xirq18b", +}; + +static const struct uniphier_pinmux_function ph1_pro4_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(i2c6), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(usb3), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_pro4_pindata = { + .groups = ph1_pro4_groups, + .groups_count = ARRAY_SIZE(ph1_pro4_groups), + .functions = ph1_pro4_functions, + .functions_count = ARRAY_SIZE(ph1_pro4_functions), + .mux_bits = 4, + .reg_stride = 8, + .load_pinctrl = true, +}; + +static struct pinctrl_desc ph1_pro4_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_pro4_pins, + .npins = ARRAY_SIZE(ph1_pro4_pins), + .owner = THIS_MODULE, +}; + +static int ph1_pro4_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_pro4_pinctrl_desc, + &ph1_pro4_pindata); +} + +static const struct of_device_id ph1_pro4_pinctrl_match[] = { + { .compatible = "socionext,ph1-pro4-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_pro4_pinctrl_match); + +static struct platform_driver ph1_pro4_pinctrl_driver = { + .probe = ph1_pro4_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_pro4_pinctrl_match, + }, +}; +module_platform_driver(ph1_pro4_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-Pro4 pinctrl driver"); +MODULE_LICENSE("GPL"); -- GitLab From 95372f9dc892a79bce1e81b8862bb4ad15cf4f76 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:04 +0900 Subject: [PATCH 0932/7006] pinctrl: UniPhier: add UniPhier PH1-sLD8 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-sLD8 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c | 794 ++++++++++++++++++++ 3 files changed, 799 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 944803ffb5ccf..f4a21feeff612 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -13,4 +13,8 @@ config PINCTRL_UNIPHIER_PH1_PRO4 tristate "UniPhier PH1-Pro4 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_SLD8 + tristate "UniPhier PH1-sLD8 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index b1b597e0dccba..3349fff80aa99 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c b/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c new file mode 100644 index 0000000000000..7e9dae54fcb22 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-sld8.c @@ -0,0 +1,794 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-sld8-pinctrl" + +static const struct pinctrl_pin_desc ph1_sld8_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "PCA00", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "PCA01", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "PCA02", UNIPHIER_PIN_IECTRL_NONE, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "PCA03", UNIPHIER_PIN_IECTRL_NONE, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "PCA04", UNIPHIER_PIN_IECTRL_NONE, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "PCA05", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "PCA06", UNIPHIER_PIN_IECTRL_NONE, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "PCA07", UNIPHIER_PIN_IECTRL_NONE, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "PCA08", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "PCA09", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "PCA10", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "PCA11", UNIPHIER_PIN_IECTRL_NONE, + 26, UNIPHIER_PIN_DRV_4_8, + 26, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "PCA12", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "PCA13", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "PCA14", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "XNFRE_GB", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(16, "XNFWE_GB", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(17, "NFALE_GB", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "NFCLE_GB", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "XNFWP_GB", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "XNFCE0_GB", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(21, "NANDRYBY0_GB", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(22, "XNFCE1_GB", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + 119, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(23, "NANDRYBY1_GB", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + 120, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(24, "NFD0_GB", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + 121, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "NFD1_GB", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + 122, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "NFD2_GB", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + 123, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "NFD3_GB", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + 124, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "NFD4_GB", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_8_12_16_20, + 125, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(29, "NFD5_GB", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_8_12_16_20, + 126, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(30, "NFD6_GB", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_8_12_16_20, + 127, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "NFD7_GB", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_8_12_16_20, + 128, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(33, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(34, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(35, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(36, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(37, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(38, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(39, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(45, "PCRESET", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(46, "PCREG", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(47, "PCCE2", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(48, "PCVS1", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(49, "PCCD2", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(50, "PCCD1", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(51, "PCREADY", UNIPHIER_PIN_IECTRL_NONE, + 47, UNIPHIER_PIN_DRV_4_8, + 47, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(52, "PCDOE", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(53, "PCCE1", UNIPHIER_PIN_IECTRL_NONE, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "PCWE", UNIPHIER_PIN_IECTRL_NONE, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "PCOE", UNIPHIER_PIN_IECTRL_NONE, + 51, UNIPHIER_PIN_DRV_4_8, + 51, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "PCWAIT", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "PCIOWR", UNIPHIER_PIN_IECTRL_NONE, + 53, UNIPHIER_PIN_DRV_4_8, + 53, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "PCIORD", UNIPHIER_PIN_IECTRL_NONE, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "HS0DIN0", UNIPHIER_PIN_IECTRL_NONE, + 55, UNIPHIER_PIN_DRV_4_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "HS0DIN1", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_4_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "HS0DIN2", UNIPHIER_PIN_IECTRL_NONE, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "HS0DIN3", UNIPHIER_PIN_IECTRL_NONE, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "HS0DIN4", UNIPHIER_PIN_IECTRL_NONE, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "HS0DIN5", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "HS0DIN6", UNIPHIER_PIN_IECTRL_NONE, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "HS0DIN7", UNIPHIER_PIN_IECTRL_NONE, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "HS0BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "HS0VALIN", UNIPHIER_PIN_IECTRL_NONE, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "HS0SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "HSDOUT0", UNIPHIER_PIN_IECTRL_NONE, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "HSDOUT1", UNIPHIER_PIN_IECTRL_NONE, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "HSDOUT2", UNIPHIER_PIN_IECTRL_NONE, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "HSDOUT3", UNIPHIER_PIN_IECTRL_NONE, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "HSDOUT4", UNIPHIER_PIN_IECTRL_NONE, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "HSDOUT5", UNIPHIER_PIN_IECTRL_NONE, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "HSDOUT6", UNIPHIER_PIN_IECTRL_NONE, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "HSDOUT7", UNIPHIER_PIN_IECTRL_NONE, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "HSBCLKOUT", UNIPHIER_PIN_IECTRL_NONE, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "HSVALOUT", UNIPHIER_PIN_IECTRL_NONE, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "HSSYNCOUT", UNIPHIER_PIN_IECTRL_NONE, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "HS1DIN0", UNIPHIER_PIN_IECTRL_NONE, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "HS1DIN1", UNIPHIER_PIN_IECTRL_NONE, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "HS1DIN2", UNIPHIER_PIN_IECTRL_NONE, + 79, UNIPHIER_PIN_DRV_4_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "HS1DIN3", UNIPHIER_PIN_IECTRL_NONE, + 80, UNIPHIER_PIN_DRV_4_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "HS1DIN4", UNIPHIER_PIN_IECTRL_NONE, + 81, UNIPHIER_PIN_DRV_4_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "HS1DIN5", UNIPHIER_PIN_IECTRL_NONE, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "HS1DIN6", UNIPHIER_PIN_IECTRL_NONE, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "HS1DIN7", UNIPHIER_PIN_IECTRL_NONE, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "HS1BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + 85, UNIPHIER_PIN_DRV_4_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "HS1VALIN", UNIPHIER_PIN_IECTRL_NONE, + 86, UNIPHIER_PIN_DRV_4_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "HS1SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "AGCI", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "AGCR", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "AGCBS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "IECOUT", UNIPHIER_PIN_IECTRL_NONE, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "ASMCK", UNIPHIER_PIN_IECTRL_NONE, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "ABCKO", UNIPHIER_PIN_IECTRL_NONE, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "ALRCKO", UNIPHIER_PIN_IECTRL_NONE, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "ASDOUT0", UNIPHIER_PIN_IECTRL_NONE, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "ASDOUT1", UNIPHIER_PIN_IECTRL_NONE, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(101, "ARCOUT", UNIPHIER_PIN_IECTRL_NONE, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(103, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(104, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(105, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(106, "DMDSDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(107, "DMDSCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(108, "DMDSDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(109, "DMDSCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(110, "SBO0", UNIPHIER_PIN_IECTRL_NONE, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(111, "SBI0", UNIPHIER_PIN_IECTRL_NONE, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "SBO1", UNIPHIER_PIN_IECTRL_NONE, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(113, "SBI1", UNIPHIER_PIN_IECTRL_NONE, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "TXD1", UNIPHIER_PIN_IECTRL_NONE, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "RXD1", UNIPHIER_PIN_IECTRL_NONE, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "HIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(117, "VIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_5, + -1, UNIPHIER_PIN_PULL_NONE), + UNIPHIER_PINCTRL_PIN(118, "TCON0", UNIPHIER_PIN_IECTRL_NONE, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "TCON1", UNIPHIER_PIN_IECTRL_NONE, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "TCON2", UNIPHIER_PIN_IECTRL_NONE, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "TCON3", UNIPHIER_PIN_IECTRL_NONE, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "TCON4", UNIPHIER_PIN_IECTRL_NONE, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "TCON5", UNIPHIER_PIN_IECTRL_NONE, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "TCON6", UNIPHIER_PIN_IECTRL_NONE, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "TCON7", UNIPHIER_PIN_IECTRL_NONE, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "TCON8", UNIPHIER_PIN_IECTRL_NONE, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "PWMA", UNIPHIER_PIN_IECTRL_NONE, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "XIRQ0", UNIPHIER_PIN_IECTRL_NONE, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "XIRQ1", UNIPHIER_PIN_IECTRL_NONE, + 112, UNIPHIER_PIN_DRV_4_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "XIRQ2", UNIPHIER_PIN_IECTRL_NONE, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "XIRQ5", UNIPHIER_PIN_IECTRL_NONE, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "XIRQ6", UNIPHIER_PIN_IECTRL_NONE, + 117, UNIPHIER_PIN_DRV_4_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "XIRQ7", UNIPHIER_PIN_IECTRL_NONE, + 118, UNIPHIER_PIN_DRV_4_8, + 118, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned emmc_pins[] = {21, 22, 23, 24, 25, 26, 27}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {28, 29, 30, 31}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {102, 103}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {104, 105}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {108, 109}; +static const unsigned i2c2_muxvals[] = {2, 2}; +static const unsigned i2c3_pins[] = {108, 109}; +static const unsigned i2c3_muxvals[] = {3, 3}; +static const unsigned nand_pins[] = {15, 16, 17, 18, 19, 20, 21, 24, 25, 26, + 27, 28, 29, 30, 31}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {22, 23}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {70, 71}; +static const unsigned uart0_muxvals[] = {3, 3}; +static const unsigned uart1_pins[] = {114, 115}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {112, 113}; +static const unsigned uart2_muxvals[] = {1, 1}; +static const unsigned uart3_pins[] = {110, 111}; +static const unsigned uart3_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {41, 42}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {43, 44}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {114, 115}; +static const unsigned usb2_muxvals[] = {1, 1}; +static const unsigned port_range0_pins[] = { + 0, 1, 2, 3, 4, 5, 6, 7, /* PORT0x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT1x */ + 32, 33, 34, 35, 36, 37, 38, 39, /* PORT2x */ + 59, 60, 61, 62, 63, 64, 65, 66, /* PORT3x */ + 95, 96, 97, 98, 99, 100, 101, 57, /* PORT4x */ + 70, 71, 72, 73, 74, 75, 76, 77, /* PORT5x */ + 81, 83, 84, 85, 86, 89, 90, 91, /* PORT6x */ + 118, 119, 120, 121, 122, 53, 54, 55, /* PORT7x */ + 41, 42, 43, 44, 79, 80, 18, 19, /* PORT8x */ + 110, 111, 112, 113, 114, 115, 16, 17, /* PORT9x */ + 40, 67, 68, 69, 78, 92, 93, 94, /* PORT10x */ + 48, 49, 46, 45, 123, 124, 125, 126, /* PORT11x */ + 47, 127, 20, 56, 22, /* PORT120-124 */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT11x */ + 15, 15, 15, 15, 15, /* PORT120-124 */ +}; +static const unsigned port_range1_pins[] = { + 116, 117, /* PORT130-131 */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, /* PORT130-131 */ +}; +static const unsigned port_range2_pins[] = { + 102, 103, 104, 105, 106, 107, 108, 109, /* PORT14x */ +}; +static const unsigned port_range2_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ +}; +static const unsigned port_range3_pins[] = { + 23, /* PORT166 */ +}; +static const unsigned port_range3_muxvals[] = { + 15, /* PORT166 */ +}; +static const unsigned xirq_range0_pins[] = { + 128, 129, 130, 131, 132, 133, 134, 135, /* XIRQ0-7 */ + 82, 87, 88, 50, 51, /* XIRQ8-12 */ +}; +static const unsigned xirq_range0_muxvals[] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, /* XIRQ8-12 */ +}; +static const unsigned xirq_range1_pins[] = { + 52, 58, /* XIRQ14-15 */ +}; +static const unsigned xirq_range1_muxvals[] = { + 14, 14, /* XIRQ14-15 */ +}; + +static const struct uniphier_pinctrl_group ph1_sld8_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range2), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_range1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range2, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range2, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range2, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range2, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range2, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range2, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range2, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range2, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port166, port_range3, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq_range1, 1), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-164 missing */ + /* none */ "port165", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", /* none*/ "xirq14", "xirq15", +}; + +static const struct uniphier_pinmux_function ph1_sld8_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_sld8_pindata = { + .groups = ph1_sld8_groups, + .groups_count = ARRAY_SIZE(ph1_sld8_groups), + .functions = ph1_sld8_functions, + .functions_count = ARRAY_SIZE(ph1_sld8_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc ph1_sld8_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_sld8_pins, + .npins = ARRAY_SIZE(ph1_sld8_pins), + .owner = THIS_MODULE, +}; + +static int ph1_sld8_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_sld8_pinctrl_desc, + &ph1_sld8_pindata); +} + +static const struct of_device_id ph1_sld8_pinctrl_match[] = { + { .compatible = "socionext,ph1-sld8-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_sld8_pinctrl_match); + +static struct platform_driver ph1_sld8_pinctrl_driver = { + .probe = ph1_sld8_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_sld8_pinctrl_match, + }, +}; +module_platform_driver(ph1_sld8_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-sLD8 pinctrl driver"); +MODULE_LICENSE("GPL"); -- GitLab From 1950b0488780d0d93481e17c56bc7a97a6037459 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:05 +0900 Subject: [PATCH 0933/7006] pinctrl: UniPhier: add UniPhier PH1-Pro5 pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-Pro5 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c | 1346 +++++++++++++++++++ 3 files changed, 1351 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index f4a21feeff612..89bda60066bda 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -17,4 +17,8 @@ config PINCTRL_UNIPHIER_PH1_SLD8 tristate "UniPhier PH1-sLD8 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_PRO5 + tristate "UniPhier PH1-Pro5 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index 3349fff80aa99..b0cd3e86bc94c 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -3,3 +3,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_CORE) += pinctrl-uniphier-core.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c b/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c new file mode 100644 index 0000000000000..b35cf4a24bb71 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-pro5.c @@ -0,0 +1,1346 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program5 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-pro5-pinctrl" + +static const struct pinctrl_pin_desc ph1_pro5_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "AEXCKA1", 0, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "AEXCKA2", 0, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "CK27EXI", 0, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "CK54EXI", 0, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(13, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(14, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(15, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 15, UNIPHIER_PIN_DRV_4_8, + 15, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(16, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_4_8, + 16, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(17, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 17, UNIPHIER_PIN_DRV_4_8, + 17, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(18, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 18, UNIPHIER_PIN_DRV_4_8, + 18, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(19, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 19, UNIPHIER_PIN_DRV_4_8, + 19, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(20, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_4_8, + 20, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(21, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 21, UNIPHIER_PIN_DRV_4_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 22, UNIPHIER_PIN_DRV_4_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 23, UNIPHIER_PIN_DRV_4_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 24, UNIPHIER_PIN_DRV_4_8, + 24, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(25, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 25, UNIPHIER_PIN_DRV_4_8, + 25, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(26, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE, + 26, UNIPHIER_PIN_DRV_4_8, + 26, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(27, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE, + 27, UNIPHIER_PIN_DRV_4_8, + 27, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(28, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 28, UNIPHIER_PIN_DRV_4_8, + 28, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(29, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 29, UNIPHIER_PIN_DRV_4_8, + 29, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(30, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(33, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(34, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(35, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(36, "XERST", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(37, "MMCCLK", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(38, "MMCCMD", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(39, "MMCDAT0", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(40, "MMCDAT1", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(41, "MMCDAT2", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(42, "MMCDAT3", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(43, "MMCDAT4", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(44, "MMCDAT5", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(45, "MMCDAT6", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(46, "MMCDAT7", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(47, "TXD0", 0, + 47, UNIPHIER_PIN_DRV_4_8, + 47, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(48, "RXD0", 0, + 48, UNIPHIER_PIN_DRV_4_8, + 48, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(49, "TXD1", 0, + 49, UNIPHIER_PIN_DRV_4_8, + 49, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(50, "RXD1", 0, + 50, UNIPHIER_PIN_DRV_4_8, + 50, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(51, "TXD2", UNIPHIER_PIN_IECTRL_NONE, + 51, UNIPHIER_PIN_DRV_4_8, + 51, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(52, "RXD2", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_4_8, + 52, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(53, "TXD3", 0, + 53, UNIPHIER_PIN_DRV_4_8, + 53, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(54, "RXD3", 0, + 54, UNIPHIER_PIN_DRV_4_8, + 54, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(55, "MS0CS0", 0, + 55, UNIPHIER_PIN_DRV_4_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "MS0DO", 0, + 56, UNIPHIER_PIN_DRV_4_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "MS0DI", 0, + 57, UNIPHIER_PIN_DRV_4_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "MS0CLK", 0, + 58, UNIPHIER_PIN_DRV_4_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "CSCLK", 0, + 59, UNIPHIER_PIN_DRV_4_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "CSBPTM", 0, + 60, UNIPHIER_PIN_DRV_4_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "CSBMTP", 0, + 61, UNIPHIER_PIN_DRV_4_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "XCINTP", 0, + 62, UNIPHIER_PIN_DRV_4_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "XCINTM", 0, + 63, UNIPHIER_PIN_DRV_4_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "XCMPREQ", 0, + 64, UNIPHIER_PIN_DRV_4_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "XSRST", 0, + 65, UNIPHIER_PIN_DRV_4_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 66, UNIPHIER_PIN_DRV_4_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "PWMA", 0, + 67, UNIPHIER_PIN_DRV_4_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "XIRQ0", 0, + 68, UNIPHIER_PIN_DRV_4_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "XIRQ1", 0, + 69, UNIPHIER_PIN_DRV_4_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "XIRQ2", 0, + 70, UNIPHIER_PIN_DRV_4_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "XIRQ3", 0, + 71, UNIPHIER_PIN_DRV_4_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "XIRQ4", 0, + 72, UNIPHIER_PIN_DRV_4_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "XIRQ5", 0, + 73, UNIPHIER_PIN_DRV_4_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "XIRQ6", 0, + 74, UNIPHIER_PIN_DRV_4_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "XIRQ7", 0, + 75, UNIPHIER_PIN_DRV_4_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "XIRQ8", 0, + 76, UNIPHIER_PIN_DRV_4_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "XIRQ9", 0, + 77, UNIPHIER_PIN_DRV_4_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "XIRQ10", 0, + 78, UNIPHIER_PIN_DRV_4_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "XIRQ11", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "XIRQ12", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "XIRQ13", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "XIRQ14", 0, + 82, UNIPHIER_PIN_DRV_4_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "XIRQ15", 0, + 83, UNIPHIER_PIN_DRV_4_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "XIRQ16", 0, + 84, UNIPHIER_PIN_DRV_4_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "XIRQ19", 0, + 87, UNIPHIER_PIN_DRV_4_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "XIRQ20", 0, + 88, UNIPHIER_PIN_DRV_4_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "PORT00", 0, + 89, UNIPHIER_PIN_DRV_4_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "PORT01", 0, + 90, UNIPHIER_PIN_DRV_4_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "PORT02", 0, + 91, UNIPHIER_PIN_DRV_4_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "PORT03", 0, + 92, UNIPHIER_PIN_DRV_4_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "PORT04", 0, + 93, UNIPHIER_PIN_DRV_4_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "PORT05", 0, + 94, UNIPHIER_PIN_DRV_4_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "PORT06", 0, + 95, UNIPHIER_PIN_DRV_4_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "PORT07", 0, + 96, UNIPHIER_PIN_DRV_4_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "PORT10", 0, + 97, UNIPHIER_PIN_DRV_4_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "PORT11", 0, + 98, UNIPHIER_PIN_DRV_4_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "PORT12", 0, + 99, UNIPHIER_PIN_DRV_4_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "PORT13", 0, + 100, UNIPHIER_PIN_DRV_4_8, + 100, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "PORT14", 0, + 101, UNIPHIER_PIN_DRV_4_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "PORT15", 0, + 102, UNIPHIER_PIN_DRV_4_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "PORT16", 0, + 103, UNIPHIER_PIN_DRV_4_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "PORT17", 0, + 104, UNIPHIER_PIN_DRV_4_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "T0HPD", 0, + 105, UNIPHIER_PIN_DRV_4_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(106, "T1HPD", 0, + 106, UNIPHIER_PIN_DRV_4_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(107, "R0HPD", 0, + 107, UNIPHIER_PIN_DRV_4_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "R1HPD", 0, + 108, UNIPHIER_PIN_DRV_4_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(109, "XPERST", 0, + 109, UNIPHIER_PIN_DRV_4_8, + 109, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(110, "XPEWAKE", 0, + 110, UNIPHIER_PIN_DRV_4_8, + 110, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(111, "XPECLKRQ", 0, + 111, UNIPHIER_PIN_DRV_4_8, + 111, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(112, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 112, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(113, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 115, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "SDA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "SCL2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 117, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(118, "SDA3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 118, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(119, "SCL3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 119, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(120, "SPISYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "SPISCLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "SPITXD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "SPIRXD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 125, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(126, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 127, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(128, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 129, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(130, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "SMTD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "SMTCLK0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "SMTD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "SMTCLK1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(159, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(160, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 167, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "CH7CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "CH7PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 169, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "CH7VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "CH7DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 171, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 172, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 174, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "AI1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "AI1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(177, "AI1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(178, "AI1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(179, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(182, "AI2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "AI2D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(184, "AI2D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "AI2D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(186, "AI3ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(187, "AI3BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "AI3LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(189, "AI3D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "AO1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "AO1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "AO1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 196, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(197, "AO1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 197, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(198, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "AO2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "AO2D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "AO2D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "AO2D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "AO4DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "AO4BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "AO4LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "AO4DMIX", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "VI1C0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "VI1C1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "VI1C2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "VI1C3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "VI1C4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "VI1C5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 220, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "VI1C6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "VI1C7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "VI1C8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "VI1C9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "VI1Y0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "VI1Y1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "VI1Y2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "VI1Y3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "VI1Y4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "VI1Y5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "VI1Y6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "VI1Y7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "VI1Y8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "VI1Y9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 234, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(235, "VI1DE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 235, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(236, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 236, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(237, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 237, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(238, "VO1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 238, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(239, "VO1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 239, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(240, "VO1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 240, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(241, "VO1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 241, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(242, "VO1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 242, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(243, "VO1D4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 243, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(244, "VO1D5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 244, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(245, "VO1D6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 245, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(246, "VO1D7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 246, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(247, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 247, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(248, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 248, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(249, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 249, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(250, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(251, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(252, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 48, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(253, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 52, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(254, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 56, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(255, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 60, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {0, 0, 0, 0, 0, 0, 0}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {0, 0, 0, 0}; +static const unsigned i2c0_pins[] = {112, 113}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {114, 115}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {116, 117}; +static const unsigned i2c2_muxvals[] = {0, 0}; +static const unsigned i2c3_pins[] = {118, 119}; +static const unsigned i2c3_muxvals[] = {0, 0}; +static const unsigned i2c5_pins[] = {87, 88}; +static const unsigned i2c5_muxvals[] = {2, 2}; +static const unsigned i2c5b_pins[] = {196, 197}; +static const unsigned i2c5b_muxvals[] = {2, 2}; +static const unsigned i2c5c_pins[] = {215, 216}; +static const unsigned i2c5c_muxvals[] = {2, 2}; +static const unsigned nand_pins[] = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30, + 31, 32, 33, 34, 35}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {26, 27}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {47, 48}; +static const unsigned uart0_muxvals[] = {0, 0}; +static const unsigned uart0b_pins[] = {227, 228}; +static const unsigned uart0b_muxvals[] = {3, 3}; +static const unsigned uart1_pins[] = {49, 50}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart2_pins[] = {51, 52}; +static const unsigned uart2_muxvals[] = {0, 0}; +static const unsigned uart3_pins[] = {53, 54}; +static const unsigned uart3_muxvals[] = {0, 0}; +static const unsigned usb0_pins[] = {124, 125}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {126, 127}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {128, 129}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned port_range0_pins[] = { + 89, 90, 91, 92, 93, 94, 95, 96, /* PORT0x */ + 97, 98, 99, 100, 101, 102, 103, 104, /* PORT1x */ + 251, 252, 253, 254, 255, 247, 248, 249, /* PORT2x */ + 39, 40, 41, 42, 43, 44, 45, 46, /* PORT3x */ + 156, 157, 158, 159, 160, 161, 162, 163, /* PORT4x */ + 164, 165, 166, 167, 168, 169, 170, 171, /* PORT5x */ + 190, 191, 192, 193, 194, 195, 196, 197, /* PORT6x */ + 198, 199, 200, 201, 202, 203, 204, 205, /* PORT7x */ + 120, 121, 122, 123, 55, 56, 57, 58, /* PORT8x */ + 124, 125, 126, 127, 49, 50, 53, 54, /* PORT9x */ + 148, 149, 150, 151, 152, 153, 154, 155, /* PORT10x */ + 133, 134, 131, 130, 138, 139, 136, 135, /* PORT11x */ + 28, 29, 30, 31, 32, 33, 34, 35, /* PORT12x */ + 179, 180, 181, 182, 186, 187, 188, 189, /* PORT13x */ + 4, 5, 6, 7, 8, 9, 10, 11, /* PORT14x */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT11x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ +}; +static const unsigned port_range1_pins[] = { + 109, 110, 111, /* PORT175-177 */ + 206, 207, 208, 209, 210, 211, 212, 213, /* PORT18x */ + 12, 13, 14, 15, 16, 17, 107, 108, /* PORT19x */ + 140, 141, 142, 143, 144, 145, 146, 147, /* PORT20x */ + 59, 60, 61, 62, 63, 64, 65, 66, /* PORT21x */ + 214, 215, 216, 217, 218, 219, 220, 221, /* PORT22x */ + 222, 223, 224, 225, 226, 227, 228, 229, /* PORT23x */ + 19, 20, 21, 22, 23, 24, 25, 26, /* PORT24x */ + 230, 231, 232, 233, 234, 235, 236, 237, /* PORT25x */ + 239, 240, 241, 242, 243, 244, 245, 246, /* PORT26x */ + 172, 173, 174, 175, 176, 177, 178, 129, /* PORT27x */ + 0, 1, 2, 67, 85, 86, 87, 88, /* PORT28x */ + 105, 106, 18, 27, 36, 128, 132, 137, /* PORT29x */ + 183, 184, 185, 84, 47, 48, 51, 52, /* PORT30x */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, 15, /* PORT175-177 */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT19x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT25x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT26x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT27x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT28x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT29x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT30x */ +}; +static const unsigned xirq_pins[] = { + 68, 69, 70, 71, 72, 73, 74, 75, /* XIRQ0-7 */ + 76, 77, 78, 79, 80, 81, 82, 83, /* XIRQ8-15 */ + 84, 85, 86, 87, 88, /* XIRQ16-20 */ +}; +static const unsigned xirq_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ8-15 */ + 14, 14, 14, 14, 14, /* XIRQ16-20 */ +}; +static const unsigned xirq_alternatives_pins[] = { + 91, 92, 239, 144, 240, 156, 241, 106, 128, +}; +static const unsigned xirq_alternatives_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, 14, +}; + +static const struct uniphier_pinctrl_group ph1_pro5_groups[] = { + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c5), + UNIPHIER_PINCTRL_GROUP(i2c5b), + UNIPHIER_PINCTRL_GROUP(i2c5c), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq_alternatives), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port110, port_range0, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port111, port_range0, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port112, port_range0, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port113, port_range0, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port114, port_range0, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port115, port_range0, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port116, port_range0, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port117, port_range0, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range0, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range0, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range0, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range0, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range0, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range0, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range0, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range0, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range0, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range0, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range0, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range0, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range0, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range0, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range0, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range0, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range0, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range0, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range0, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range0, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range0, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range0, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range0, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range0, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port290, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port291, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port292, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port293, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port294, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port295, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port296, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port297, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port300, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port301, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port302, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port303, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port304, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port305, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port306, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port307, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3b, xirq_alternatives, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4b, xirq_alternatives, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16b, xirq_alternatives, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17b, xirq_alternatives, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17c, xirq_alternatives, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18b, xirq_alternatives, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18c, xirq_alternatives, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19b, xirq_alternatives, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20b, xirq_alternatives, 8), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const i2c5_groups[] = {"i2c5", "i2c5b", "i2c5c"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0", "uart0b"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + "port110", "port111", "port112", "port113", + "port114", "port115", "port116", "port117", + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + /* port150-174 missing */ + /* none */ "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", + "port290", "port291", "port292", "port293", + "port294", "port295", "port296", "port297", + "port300", "port301", "port302", "port303", + "port304", "port305", "port306", "port307", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", + "xirq3b", "xirq4b", "xirq16b", "xirq17b", "xirq17c", + "xirq18b", "xirq18c", "xirq19b", "xirq20b", +}; + +static const struct uniphier_pinmux_function ph1_pro5_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(i2c5), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_pro5_pindata = { + .groups = ph1_pro5_groups, + .groups_count = ARRAY_SIZE(ph1_pro5_groups), + .functions = ph1_pro5_functions, + .functions_count = ARRAY_SIZE(ph1_pro5_functions), + .mux_bits = 4, + .reg_stride = 8, + .load_pinctrl = true, +}; + +static struct pinctrl_desc ph1_pro5_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_pro5_pins, + .npins = ARRAY_SIZE(ph1_pro5_pins), + .owner = THIS_MODULE, +}; + +static int ph1_pro5_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_pro5_pinctrl_desc, + &ph1_pro5_pindata); +} + +static const struct of_device_id ph1_pro5_pinctrl_match[] = { + { .compatible = "socionext,ph1-pro5-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_pro5_pinctrl_match); + +static struct platform_driver ph1_pro5_pinctrl_driver = { + .probe = ph1_pro5_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_pro5_pinctrl_match, + }, +}; +module_platform_driver(ph1_pro5_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-Pro5 pinctrl driver"); +MODULE_LICENSE("GPL"); -- GitLab From 3c0fd8e3de93fc12b35cf5be585a5d8dc68b7162 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:06 +0900 Subject: [PATCH 0934/7006] pinctrl: UniPhier: add UniPhier ProXstream2 pinctrl driver Add pin configuration and pinmux support for UniPhier ProXstream2 SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + .../pinctrl/uniphier/pinctrl-proxstream2.c | 1269 +++++++++++++++++ 3 files changed, 1274 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-proxstream2.c diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 89bda60066bda..69c5d5fa61dac 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -21,4 +21,8 @@ config PINCTRL_UNIPHIER_PH1_PRO5 tristate "UniPhier PH1-Pro5 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PROXSTREAM2 + tristate "UniPhier ProXstream2 SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index b0cd3e86bc94c..aed038c59f049 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD4) += pinctrl-ph1-ld4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2) += pinctrl-proxstream2.o diff --git a/drivers/pinctrl/uniphier/pinctrl-proxstream2.c b/drivers/pinctrl/uniphier/pinctrl-proxstream2.c new file mode 100644 index 0000000000000..3f036e236ad90 --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-proxstream2.c @@ -0,0 +1,1269 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "proxstream2-pinctrl" + +static const struct pinctrl_pin_desc proxstream2_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "SMTRST0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "SMTCMD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(17, "SMTD0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "SMTSEL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "SMTCLK0CG", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "SMTDET0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(21, "SMTRST1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "SMTCMD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "SMTD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "SMTSEL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 24, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(25, "SMTCLK1CG", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 25, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(26, "SMTDET1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 26, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(27, "XIRQ18", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 27, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(28, "XIRQ19", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(29, "XIRQ20", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 53, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "CH0CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "CH0PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "CH0VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "CH0DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "CH1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "CH1PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "CH1VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "CH1DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "XIRQ9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "XIRQ10", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "XIRQ16", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "CH4CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "CH4PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "CH4VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "CH4DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "CH5CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "CH5PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "CH5VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "CH5DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "CH6CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "CH6PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "CH6VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "CH6DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "STS0CLKO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "STS0SYNCO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "STS0VALO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "STS0DATAO", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "XIRQ17", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "PORT163", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "PORT165", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "PORT166", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "PORT132", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "PORT133", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "AO2IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "AI2ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "AI2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "AI2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 100, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "AI2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "AI2D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "AI2D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "AI2D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "AO3DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(106, "AO3BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(107, "AO3LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "AO3DMIX", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(113, "TXD2", 0, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "RXD2", 0, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "TXD1", 0, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "RXD1", 0, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "PORT190", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(118, "VI1HSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 118, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "VI1VSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 119, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "VI1DE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "VI1G2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "VI1G3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "VI1G4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 125, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "VI1G5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "VI1G6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 127, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "VI1G7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "VI1G8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "VI1G9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "VI1CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "VI1R2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "VI1R3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "VI1R4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "VI1R5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "VI1R6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "VI1R7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "VI1R8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "VI1R9", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "MDC", 0, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "MDIO", 0, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0, + 146, UNIPHIER_PIN_DRV_4_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0, + 147, UNIPHIER_PIN_DRV_4_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0, + 148, UNIPHIER_PIN_DRV_4_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0, + 149, UNIPHIER_PIN_DRV_4_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0, + 150, UNIPHIER_PIN_DRV_4_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0, + 151, UNIPHIER_PIN_DRV_4_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0, + 152, UNIPHIER_PIN_DRV_4_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0, + 153, UNIPHIER_PIN_DRV_4_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0, + 154, UNIPHIER_PIN_DRV_4_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0, + 155, UNIPHIER_PIN_DRV_4_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0, + 156, UNIPHIER_PIN_DRV_4_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0, + 157, UNIPHIER_PIN_DRV_4_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0, + 158, UNIPHIER_PIN_DRV_4_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(159, "SDA3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(160, "SCL3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "AI1ADCCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "AI1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "CH2CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "CH2PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "CH2VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "CH2DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "CH3CLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 167, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "CH3PSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "CH3VAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 169, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "CH3DATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "SDA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 171, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "SCL2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 172, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "AI1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "AI1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 174, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "AO2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(177, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(178, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(179, "PORT222", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "PORT223", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "PORT224", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(182, "PORT225", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "PORT226", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(184, "PORT227", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "PORT230", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(186, "FANPWM", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(187, "HRDDCSDA0", 0, + 187, UNIPHIER_PIN_DRV_4_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "HRDDCSCL0", 0, + 188, UNIPHIER_PIN_DRV_4_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(189, "HRDDCSDA1", 0, + 189, UNIPHIER_PIN_DRV_4_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "HRDDCSCL1", 0, + 190, UNIPHIER_PIN_DRV_4_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "HTDDCSDA0", 0, + 191, UNIPHIER_PIN_DRV_4_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "HTDDCSCL0", 0, + 192, UNIPHIER_PIN_DRV_4_8, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "HTDDCSDA1", 0, + 193, UNIPHIER_PIN_DRV_4_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "HTDDCSCL1", 0, + 194, UNIPHIER_PIN_DRV_4_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "PORT241", 0, + 195, UNIPHIER_PIN_DRV_4_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "PORT242", 0, + 196, UNIPHIER_PIN_DRV_4_8, + 196, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(197, "PORT243", 0, + 197, UNIPHIER_PIN_DRV_4_8, + 197, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(198, "MVSYNC", 0, + 198, UNIPHIER_PIN_DRV_4_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "SPISYNC0", UNIPHIER_PIN_IECTRL_NONE, + 199, UNIPHIER_PIN_DRV_4_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "SPISCLK0", UNIPHIER_PIN_IECTRL_NONE, + 200, UNIPHIER_PIN_DRV_4_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "SPITXD0", UNIPHIER_PIN_IECTRL_NONE, + 201, UNIPHIER_PIN_DRV_4_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "SPIRXD0", UNIPHIER_PIN_IECTRL_NONE, + 202, UNIPHIER_PIN_DRV_4_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "CK54EXI", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "AEXCKA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "AEXCKA2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "CK27EXI", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "STCDIN", 0, + 207, UNIPHIER_PIN_DRV_4_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "PHSYNI", 0, + 208, UNIPHIER_PIN_DRV_4_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "PVSYNI", 0, + 209, UNIPHIER_PIN_DRV_4_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "MVSYN", UNIPHIER_PIN_IECTRL_NONE, + 210, UNIPHIER_PIN_DRV_4_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "STCV", UNIPHIER_PIN_IECTRL_NONE, + 211, UNIPHIER_PIN_DRV_4_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "PORT262", UNIPHIER_PIN_IECTRL_NONE, + 212, UNIPHIER_PIN_DRV_4_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "USB0VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "USB1VBUS_IRQ", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "PORT265", UNIPHIER_PIN_IECTRL_NONE, + 215, UNIPHIER_PIN_DRV_4_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "CK25O", 0, + 216, UNIPHIER_PIN_DRV_4_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "TXD0", 0, + 217, UNIPHIER_PIN_DRV_4_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "RXD0", 0, + 218, UNIPHIER_PIN_DRV_4_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "TXD3", 0, + 219, UNIPHIER_PIN_DRV_4_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "RXD3", 0, + 220, UNIPHIER_PIN_DRV_4_8, + 220, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "PORT273", 0, + 221, UNIPHIER_PIN_DRV_4_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "STCDOUTC", 0, + 222, UNIPHIER_PIN_DRV_4_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "PORT274", 0, + 223, UNIPHIER_PIN_DRV_4_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "PORT275", 0, + 224, UNIPHIER_PIN_DRV_4_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "PORT276", 0, + 225, UNIPHIER_PIN_DRV_4_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "PORT277", 0, + 226, UNIPHIER_PIN_DRV_4_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "PORT280", 0, + 227, UNIPHIER_PIN_DRV_4_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "PORT281", 0, + 228, UNIPHIER_PIN_DRV_4_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "PORT282", 0, + 229, UNIPHIER_PIN_DRV_4_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "PORT283", 0, + 230, UNIPHIER_PIN_DRV_4_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "PORT284", 0, + 231, UNIPHIER_PIN_DRV_4_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "PORT285", 0, + 232, UNIPHIER_PIN_DRV_4_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "T0HPD", 0, + 233, UNIPHIER_PIN_DRV_4_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "T1HPD", 0, + 234, UNIPHIER_PIN_DRV_4_8, + 234, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {9, 9, 9, 9, 9, 9, 9}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {9, 9, 9, 9}; +static const unsigned i2c0_pins[] = {109, 110}; +static const unsigned i2c0_muxvals[] = {8, 8}; +static const unsigned i2c1_pins[] = {111, 112}; +static const unsigned i2c1_muxvals[] = {8, 8}; +static const unsigned i2c2_pins[] = {171, 172}; +static const unsigned i2c2_muxvals[] = {8, 8}; +static const unsigned i2c3_pins[] = {159, 160}; +static const unsigned i2c3_muxvals[] = {8, 8}; +static const unsigned i2c5_pins[] = {183, 184}; +static const unsigned i2c5_muxvals[] = {11, 11}; +static const unsigned i2c6_pins[] = {185, 186}; +static const unsigned i2c6_muxvals[] = {11, 11}; +static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41, + 42, 43, 44, 45, 46}; +static const unsigned nand_muxvals[] = {8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 8, 8}; +static const unsigned nand_cs1_pins[] = {37, 38}; +static const unsigned nand_cs1_muxvals[] = {8, 8}; +static const unsigned uart0_pins[] = {217, 218}; +static const unsigned uart0_muxvals[] = {8, 8}; +static const unsigned uart0b_pins[] = {179, 180}; +static const unsigned uart0b_muxvals[] = {10, 10}; +static const unsigned uart1_pins[] = {115, 116}; +static const unsigned uart1_muxvals[] = {8, 8}; +static const unsigned uart2_pins[] = {113, 114}; +static const unsigned uart2_muxvals[] = {8, 8}; +static const unsigned uart3_pins[] = {219, 220}; +static const unsigned uart3_muxvals[] = {8, 8}; +static const unsigned uart3b_pins[] = {181, 182}; +static const unsigned uart3b_muxvals[] = {10, 10}; +static const unsigned usb0_pins[] = {56, 57}; +static const unsigned usb0_muxvals[] = {8, 8}; +static const unsigned usb1_pins[] = {58, 59}; +static const unsigned usb1_muxvals[] = {8, 8}; +static const unsigned usb2_pins[] = {60, 61}; +static const unsigned usb2_muxvals[] = {8, 8}; +static const unsigned usb3_pins[] = {62, 63}; +static const unsigned usb3_muxvals[] = {8, 8}; +static const unsigned port_range0_pins[] = { + 127, 128, 129, 130, 131, 132, 133, 134, /* PORT0x */ + 135, 136, 137, 138, 139, 140, 141, 142, /* PORT1x */ + 0, 1, 2, 3, 4, 5, 6, 7, /* PORT2x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT3x */ + 16, 17, 18, 19, 21, 22, 23, 24, /* PORT4x */ + 25, 30, 31, 32, 33, 34, 35, 36, /* PORT5x */ + 37, 38, 39, 40, 41, 42, 43, 44, /* PORT6x */ + 45, 46, 47, 48, 49, 50, 51, 52, /* PORT7x */ + 53, 54, 55, 56, 57, 58, 59, 60, /* PORT8x */ + 61, 62, 63, 64, 65, 66, 67, 68, /* PORT9x */ + 69, 70, 71, 76, 77, 78, 79, 80, /* PORT10x */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ +}; +static const unsigned port_range1_pins[] = { + 81, 82, 83, 84, 85, 86, 87, 88, /* PORT12x */ + 89, 90, 95, 96, 97, 98, 99, 100, /* PORT13x */ + 101, 102, 103, 104, 105, 106, 107, 108, /* PORT14x */ + 118, 119, 120, 121, 122, 123, 124, 125, /* PORT15x */ + 126, 72, 73, 92, 177, 93, 94, 176, /* PORT16x */ + 74, 91, 27, 28, 29, 75, 20, 26, /* PORT17x */ + 109, 110, 111, 112, 113, 114, 115, 116, /* PORT18x */ + 117, 143, 144, 145, 146, 147, 148, 149, /* PORT19x */ + 150, 151, 152, 153, 154, 155, 156, 157, /* PORT20x */ + 158, 159, 160, 161, 162, 163, 164, 165, /* PORT21x */ + 166, 178, 179, 180, 181, 182, 183, 184, /* PORT22x */ + 185, 187, 188, 189, 190, 191, 192, 193, /* PORT23x */ + 194, 195, 196, 197, 198, 199, 200, 201, /* PORT24x */ + 202, 203, 204, 205, 206, 207, 208, 209, /* PORT25x */ + 210, 211, 212, 213, 214, 215, 216, 217, /* PORT26x */ + 218, 219, 220, 221, 223, 224, 225, 226, /* PORT27x */ + 227, 228, 229, 230, 231, 232, 233, 234, /* PORT28x */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT15x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT16x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT17x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT19x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT25x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT26x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT27x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT28x */ +}; +static const unsigned xirq_pins[] = { + 118, 119, 120, 121, 122, 123, 124, 125, /* XIRQ0-7 */ + 126, 72, 73, 92, 177, 93, 94, 176, /* XIRQ8-15 */ + 74, 91, 27, 28, 29, 75, 20, 26, /* XIRQ16-23 */ +}; +static const unsigned xirq_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ8-15 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ16-23 */ +}; + +static const struct uniphier_pinctrl_group proxstream2_groups[] = { + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(i2c5), + UNIPHIER_PINCTRL_GROUP(i2c6), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart3), + UNIPHIER_PINCTRL_GROUP(uart3b), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port150, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port151, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port152, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port153, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port154, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port155, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port156, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port157, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port160, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port161, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port162, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port163, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port164, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port165, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port166, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port167, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port170, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port171, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port172, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port173, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port174, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 120), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 121), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 122), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 123), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 124), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 125), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 126), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 127), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 128), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 129), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 130), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 131), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 132), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 133), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 134), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 135), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23), +}; + +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const i2c5_groups[] = {"i2c5"}; +static const char * const i2c6_groups[] = {"i2c6"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0", "uart0b"}; +static const char * const uart1_groups[] = {"uart1"}; +static const char * const uart2_groups[] = {"uart2"}; +static const char * const uart3_groups[] = {"uart3", "uart3b"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const usb3_groups[] = {"usb3"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + /* port110-117 missing */ + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + "port150", "port151", "port152", "port153", + "port154", "port155", "port156", "port157", + "port160", "port161", "port162", "port163", + "port164", "port165", "port166", "port167", + "port170", "port171", "port172", "port173", + "port174", "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", "xirq21", "xirq22", "xirq23", +}; + +static const struct uniphier_pinmux_function proxstream2_functions[] = { + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(i2c5), + UNIPHIER_PINMUX_FUNCTION(i2c6), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(uart3), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(usb3), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata proxstream2_pindata = { + .groups = proxstream2_groups, + .groups_count = ARRAY_SIZE(proxstream2_groups), + .functions = proxstream2_functions, + .functions_count = ARRAY_SIZE(proxstream2_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc proxstream2_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = proxstream2_pins, + .npins = ARRAY_SIZE(proxstream2_pins), + .owner = THIS_MODULE, +}; + +static int proxstream2_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &proxstream2_pinctrl_desc, + &proxstream2_pindata); +} + +static const struct of_device_id proxstream2_pinctrl_match[] = { + { .compatible = "socionext,proxstream2-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, proxstream2_pinctrl_match); + +static struct platform_driver proxstream2_pinctrl_driver = { + .probe = proxstream2_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = proxstream2_pinctrl_match, + }, +}; +module_platform_driver(proxstream2_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier ProXstream2 pinctrl driver"); +MODULE_LICENSE("GPL"); -- GitLab From b3b6616378a4dcf1e903c8ad70fabfe4c2ad529b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 14 Jul 2015 11:40:07 +0900 Subject: [PATCH 0935/7006] pinctrl: UniPhier: add UniPhier PH1-LD6b pinctrl driver Add pin configuration and pinmux support for UniPhier PH1-LD6b SoC. Changes in v2: - sort groups and funcs alphabetically - add i2c pin-mux settings - sort members of platform_driver - change to tristate - add THIS_MODULE to pinctrl_desc - use module_platform_driver Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/uniphier/Kconfig | 4 + drivers/pinctrl/uniphier/Makefile | 1 + drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c | 1274 +++++++++++++++++++ 3 files changed, 1279 insertions(+) create mode 100644 drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c diff --git a/drivers/pinctrl/uniphier/Kconfig b/drivers/pinctrl/uniphier/Kconfig index 69c5d5fa61dac..eab23ef9ddbf9 100644 --- a/drivers/pinctrl/uniphier/Kconfig +++ b/drivers/pinctrl/uniphier/Kconfig @@ -25,4 +25,8 @@ config PINCTRL_UNIPHIER_PROXSTREAM2 tristate "UniPhier ProXstream2 SoC pinctrl driver" select PINCTRL_UNIPHIER_CORE +config PINCTRL_UNIPHIER_PH1_LD6B + tristate "UniPhier PH1-LD6b SoC pinctrl driver" + select PINCTRL_UNIPHIER_CORE + endif diff --git a/drivers/pinctrl/uniphier/Makefile b/drivers/pinctrl/uniphier/Makefile index aed038c59f049..e215b1097297a 100644 --- a/drivers/pinctrl/uniphier/Makefile +++ b/drivers/pinctrl/uniphier/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO4) += pinctrl-ph1-pro4.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_SLD8) += pinctrl-ph1-sld8.o obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_PRO5) += pinctrl-ph1-pro5.o obj-$(CONFIG_PINCTRL_UNIPHIER_PROXSTREAM2) += pinctrl-proxstream2.o +obj-$(CONFIG_PINCTRL_UNIPHIER_PH1_LD6B) += pinctrl-ph1-ld6b.o diff --git a/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c b/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c new file mode 100644 index 0000000000000..9720e697fbc1f --- /dev/null +++ b/drivers/pinctrl/uniphier/pinctrl-ph1-ld6b.c @@ -0,0 +1,1274 @@ +/* + * Copyright (C) 2015 Masahiro Yamada + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#include "pinctrl-uniphier.h" + +#define DRIVER_NAME "ph1-ld6b-pinctrl" + +static const struct pinctrl_pin_desc ph1_ld6b_pins[] = { + UNIPHIER_PINCTRL_PIN(0, "ED0", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_4_8, + 0, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(1, "ED1", UNIPHIER_PIN_IECTRL_NONE, + 1, UNIPHIER_PIN_DRV_4_8, + 1, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(2, "ED2", UNIPHIER_PIN_IECTRL_NONE, + 2, UNIPHIER_PIN_DRV_4_8, + 2, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(3, "ED3", UNIPHIER_PIN_IECTRL_NONE, + 3, UNIPHIER_PIN_DRV_4_8, + 3, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(4, "ED4", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_4_8, + 4, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(5, "ED5", UNIPHIER_PIN_IECTRL_NONE, + 5, UNIPHIER_PIN_DRV_4_8, + 5, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(6, "ED6", UNIPHIER_PIN_IECTRL_NONE, + 6, UNIPHIER_PIN_DRV_4_8, + 6, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(7, "ED7", UNIPHIER_PIN_IECTRL_NONE, + 7, UNIPHIER_PIN_DRV_4_8, + 7, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(8, "XERWE0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_4_8, + 8, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(9, "XERWE1", UNIPHIER_PIN_IECTRL_NONE, + 9, UNIPHIER_PIN_DRV_4_8, + 9, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(10, "ERXW", UNIPHIER_PIN_IECTRL_NONE, + 10, UNIPHIER_PIN_DRV_4_8, + 10, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(11, "ES0", UNIPHIER_PIN_IECTRL_NONE, + 11, UNIPHIER_PIN_DRV_4_8, + 11, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(12, "ES1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_4_8, + 12, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(13, "ES2", UNIPHIER_PIN_IECTRL_NONE, + 13, UNIPHIER_PIN_DRV_4_8, + 13, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(14, "XECS1", UNIPHIER_PIN_IECTRL_NONE, + 14, UNIPHIER_PIN_DRV_4_8, + 14, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(15, "PCA00", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 15, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(16, "PCA01", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 16, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(17, "PCA02", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 17, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(18, "PCA03", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 18, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(19, "PCA04", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 19, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(20, "PCA05", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 20, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(21, "PCA06", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 21, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(22, "PCA07", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 22, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(23, "PCA08", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 23, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(24, "PCA09", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 24, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(25, "PCA10", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 25, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(26, "PCA11", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 26, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(27, "PCA12", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 27, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(28, "PCA13", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 28, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(29, "PCA14", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 29, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(30, "XNFRE", UNIPHIER_PIN_IECTRL_NONE, + 30, UNIPHIER_PIN_DRV_4_8, + 30, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(31, "XNFWE", UNIPHIER_PIN_IECTRL_NONE, + 31, UNIPHIER_PIN_DRV_4_8, + 31, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(32, "NFALE", UNIPHIER_PIN_IECTRL_NONE, + 32, UNIPHIER_PIN_DRV_4_8, + 32, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(33, "NFCLE", UNIPHIER_PIN_IECTRL_NONE, + 33, UNIPHIER_PIN_DRV_4_8, + 33, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(34, "XNFWP", UNIPHIER_PIN_IECTRL_NONE, + 34, UNIPHIER_PIN_DRV_4_8, + 34, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(35, "XNFCE0", UNIPHIER_PIN_IECTRL_NONE, + 35, UNIPHIER_PIN_DRV_4_8, + 35, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(36, "NFRYBY0", UNIPHIER_PIN_IECTRL_NONE, + 36, UNIPHIER_PIN_DRV_4_8, + 36, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(37, "XNFCE1", UNIPHIER_PIN_IECTRL_NONE, + 37, UNIPHIER_PIN_DRV_4_8, + 37, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(38, "NFRYBY1", UNIPHIER_PIN_IECTRL_NONE, + 38, UNIPHIER_PIN_DRV_4_8, + 38, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(39, "NFD0", UNIPHIER_PIN_IECTRL_NONE, + 39, UNIPHIER_PIN_DRV_4_8, + 39, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(40, "NFD1", UNIPHIER_PIN_IECTRL_NONE, + 40, UNIPHIER_PIN_DRV_4_8, + 40, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(41, "NFD2", UNIPHIER_PIN_IECTRL_NONE, + 41, UNIPHIER_PIN_DRV_4_8, + 41, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(42, "NFD3", UNIPHIER_PIN_IECTRL_NONE, + 42, UNIPHIER_PIN_DRV_4_8, + 42, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(43, "NFD4", UNIPHIER_PIN_IECTRL_NONE, + 43, UNIPHIER_PIN_DRV_4_8, + 43, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(44, "NFD5", UNIPHIER_PIN_IECTRL_NONE, + 44, UNIPHIER_PIN_DRV_4_8, + 44, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(45, "NFD6", UNIPHIER_PIN_IECTRL_NONE, + 45, UNIPHIER_PIN_DRV_4_8, + 45, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(46, "NFD7", UNIPHIER_PIN_IECTRL_NONE, + 46, UNIPHIER_PIN_DRV_4_8, + 46, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(47, "SDCLK", UNIPHIER_PIN_IECTRL_NONE, + 0, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(48, "SDCMD", UNIPHIER_PIN_IECTRL_NONE, + 4, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(49, "SDDAT0", UNIPHIER_PIN_IECTRL_NONE, + 8, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(50, "SDDAT1", UNIPHIER_PIN_IECTRL_NONE, + 12, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(51, "SDDAT2", UNIPHIER_PIN_IECTRL_NONE, + 16, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(52, "SDDAT3", UNIPHIER_PIN_IECTRL_NONE, + 20, UNIPHIER_PIN_DRV_8_12_16_20, + -1, UNIPHIER_PIN_PULL_UP_FIXED), + UNIPHIER_PINCTRL_PIN(53, "SDCD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 53, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(54, "SDWP", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 54, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(55, "SDVOLC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 55, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(56, "USB0VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 56, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(57, "USB0OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 57, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(58, "USB1VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 58, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(59, "USB1OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 59, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(60, "USB2VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 60, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(61, "USB2OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 61, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(62, "USB3VBUS", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 62, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(63, "USB3OD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 63, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(64, "HS0BCLKOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 64, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(65, "HS0SYNCOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 65, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(66, "HS0VALOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 66, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(67, "HS0DOUT0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 67, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(68, "HS0DOUT1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 68, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(69, "HS0DOUT2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 69, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(70, "HS0DOUT3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 70, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(71, "HS0DOUT4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 71, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(72, "HS0DOUT5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 72, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(73, "HS0DOUT6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 73, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(74, "HS0DOUT7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 74, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(75, "HS1BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 75, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(76, "HS1SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 76, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(77, "HS1VALIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 77, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(78, "HS1DIN0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 78, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(79, "HS1DIN1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 79, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(80, "HS1DIN2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 80, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(81, "HS1DIN3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 81, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(82, "HS1DIN4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 82, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(83, "HS1DIN5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 83, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(84, "HS1DIN6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 84, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(85, "HS1DIN7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 85, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(86, "HS2BCLKIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 86, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(87, "HS2SYNCIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 87, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(88, "HS2VALIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 88, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(89, "HS2DIN0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 89, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(90, "HS2DIN1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 90, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(91, "HS2DIN2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 91, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(92, "HS2DIN3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 92, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(93, "HS2DIN4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 93, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(94, "HS2DIN5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 94, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(95, "HS2DIN6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 95, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(96, "HS2DIN7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 96, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(97, "AO1IEC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 97, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(98, "AO1DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 98, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(99, "AO1BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 99, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(100, "AO1LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 100, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(101, "AO1D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 101, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(102, "AO1D1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 102, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(103, "AO1D2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 103, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(104, "AO1D3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 104, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(105, "AO2DACCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 105, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(106, "AO2BCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 106, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(107, "AO2LRCK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 107, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(108, "AO2D0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 108, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(109, "SDA0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 109, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(110, "SCL0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 110, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(111, "SDA1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 111, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(112, "SCL1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 112, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(113, "SBO0", 0, + 113, UNIPHIER_PIN_DRV_4_8, + 113, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(114, "SBI0", 0, + 114, UNIPHIER_PIN_DRV_4_8, + 114, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(115, "TXD1", 0, + 115, UNIPHIER_PIN_DRV_4_8, + 115, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(116, "RXD1", 0, + 116, UNIPHIER_PIN_DRV_4_8, + 116, UNIPHIER_PIN_PULL_UP), + UNIPHIER_PINCTRL_PIN(117, "PWSRA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 117, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(118, "XIRQ0", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 118, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(119, "XIRQ1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 119, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(120, "XIRQ2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 120, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(121, "XIRQ3", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 121, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(122, "XIRQ4", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 122, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(123, "XIRQ5", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 123, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(124, "XIRQ6", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 124, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(125, "XIRQ7", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 125, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(126, "XIRQ8", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 126, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(127, "PORT00", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 127, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(128, "PORT01", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 128, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(129, "PORT02", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 129, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(130, "PORT03", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 130, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(131, "PORT04", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 131, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(132, "PORT05", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 132, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(133, "PORT06", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 133, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(134, "PORT07", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 134, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(135, "PORT10", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 135, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(136, "PORT11", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 136, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(137, "PORT12", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 137, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(138, "PORT13", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 138, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(139, "PORT14", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 139, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(140, "PORT15", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 140, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(141, "PORT16", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 141, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(142, "LPST", UNIPHIER_PIN_IECTRL_NONE, + 142, UNIPHIER_PIN_DRV_4_8, + 142, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(143, "MDC", 0, + 143, UNIPHIER_PIN_DRV_4_8, + 143, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(144, "MDIO", 0, + 144, UNIPHIER_PIN_DRV_4_8, + 144, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(145, "MDIO_INTL", 0, + 145, UNIPHIER_PIN_DRV_4_8, + 145, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(146, "PHYRSTL", 0, + 146, UNIPHIER_PIN_DRV_4_8, + 146, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(147, "RGMII_RXCLK", 0, + 147, UNIPHIER_PIN_DRV_4_8, + 147, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(148, "RGMII_RXD0", 0, + 148, UNIPHIER_PIN_DRV_4_8, + 148, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(149, "RGMII_RXD1", 0, + 149, UNIPHIER_PIN_DRV_4_8, + 149, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(150, "RGMII_RXD2", 0, + 150, UNIPHIER_PIN_DRV_4_8, + 150, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(151, "RGMII_RXD3", 0, + 151, UNIPHIER_PIN_DRV_4_8, + 151, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(152, "RGMII_RXCTL", 0, + 152, UNIPHIER_PIN_DRV_4_8, + 152, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(153, "RGMII_TXCLK", 0, + 153, UNIPHIER_PIN_DRV_4_8, + 153, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(154, "RGMII_TXD0", 0, + 154, UNIPHIER_PIN_DRV_4_8, + 154, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(155, "RGMII_TXD1", 0, + 155, UNIPHIER_PIN_DRV_4_8, + 155, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(156, "RGMII_TXD2", 0, + 156, UNIPHIER_PIN_DRV_4_8, + 156, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(157, "RGMII_TXD3", 0, + 157, UNIPHIER_PIN_DRV_4_8, + 157, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(158, "RGMII_TXCTL", 0, + 158, UNIPHIER_PIN_DRV_4_8, + 158, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(159, "A_D_PCD00OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 159, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(160, "A_D_PCD01OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 160, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(161, "A_D_PCD02OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 161, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(162, "A_D_PCD03OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 162, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(163, "A_D_PCD04OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 163, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(164, "A_D_PCD05OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 164, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(165, "A_D_PCD06OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 165, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(166, "A_D_PCD07OUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 166, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(167, "A_D_PCD00IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 167, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(168, "A_D_PCD01IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 168, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(169, "A_D_PCD02IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 169, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(170, "A_D_PCD03IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 170, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(171, "A_D_PCD04IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 171, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(172, "A_D_PCD05IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 172, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(173, "A_D_PCD06IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 173, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(174, "A_D_PCD07IN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 174, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(175, "A_D_PCDNOE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 175, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(176, "A_D_PC0READY", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 176, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(177, "A_D_PC0CD1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 177, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(178, "A_D_PC0CD2", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 178, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(179, "A_D_PC0WAIT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 179, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(180, "A_D_PC0RESET", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 180, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(181, "A_D_PC0CE1", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 181, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(182, "A_D_PC0WE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 182, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(183, "A_D_PC0OE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 183, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(184, "A_D_PC0IOWR", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 184, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(185, "A_D_PC0IORD", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 185, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(186, "A_D_PC0NOE", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 186, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(187, "A_D_HS0BCLKIN", 0, + 187, UNIPHIER_PIN_DRV_4_8, + 187, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(188, "A_D_HS0SYNCIN", 0, + 188, UNIPHIER_PIN_DRV_4_8, + 188, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(189, "A_D_HS0VALIN", 0, + 189, UNIPHIER_PIN_DRV_4_8, + 189, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(190, "A_D_HS0DIN0", 0, + 190, UNIPHIER_PIN_DRV_4_8, + 190, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(191, "A_D_HS0DIN1", 0, + 191, UNIPHIER_PIN_DRV_4_8, + 191, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(192, "A_D_HS0DIN2", 0, + 192, UNIPHIER_PIN_DRV_4_8, + 192, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(193, "A_D_HS0DIN3", 0, + 193, UNIPHIER_PIN_DRV_4_8, + 193, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(194, "A_D_HS0DIN4", 0, + 194, UNIPHIER_PIN_DRV_4_8, + 194, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(195, "A_D_HS0DIN5", 0, + 195, UNIPHIER_PIN_DRV_4_8, + 195, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(196, "A_D_HS0DIN6", 0, + 196, UNIPHIER_PIN_DRV_4_8, + 196, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(197, "A_D_HS0DIN7", 0, + 197, UNIPHIER_PIN_DRV_4_8, + 197, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(198, "A_D_AO1ARC", 0, + 198, UNIPHIER_PIN_DRV_4_8, + 198, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(199, "A_D_SPIXRST", UNIPHIER_PIN_IECTRL_NONE, + 199, UNIPHIER_PIN_DRV_4_8, + 199, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(200, "A_D_SPISCLK0", UNIPHIER_PIN_IECTRL_NONE, + 200, UNIPHIER_PIN_DRV_4_8, + 200, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(201, "A_D_SPITXD0", UNIPHIER_PIN_IECTRL_NONE, + 201, UNIPHIER_PIN_DRV_4_8, + 201, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(202, "A_D_SPIRXD0", UNIPHIER_PIN_IECTRL_NONE, + 202, UNIPHIER_PIN_DRV_4_8, + 202, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(203, "A_D_DMDCLK", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 203, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(204, "A_D_DMDPSYNC", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 204, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(205, "A_D_DMDVAL", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 205, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(206, "A_D_DMDDATA", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_8, + 206, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(207, "A_D_HDMIRXXIRQ", 0, + 207, UNIPHIER_PIN_DRV_4_8, + 207, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(208, "A_D_VBIXIRQ", 0, + 208, UNIPHIER_PIN_DRV_4_8, + 208, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(209, "A_D_HDMITXXIRQ", 0, + 209, UNIPHIER_PIN_DRV_4_8, + 209, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(210, "A_D_DMDIRQ", UNIPHIER_PIN_IECTRL_NONE, + 210, UNIPHIER_PIN_DRV_4_8, + 210, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(211, "A_D_SPICIRQ", UNIPHIER_PIN_IECTRL_NONE, + 211, UNIPHIER_PIN_DRV_4_8, + 211, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(212, "A_D_SPIBIRQ", UNIPHIER_PIN_IECTRL_NONE, + 212, UNIPHIER_PIN_DRV_4_8, + 212, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(213, "A_D_BESDAOUT", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 213, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(214, "A_D_BESDAIN", UNIPHIER_PIN_IECTRL_NONE, + -1, UNIPHIER_PIN_DRV_FIXED_4, + 214, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(215, "A_D_BESCLOUT", UNIPHIER_PIN_IECTRL_NONE, + 215, UNIPHIER_PIN_DRV_4_8, + 215, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(216, "A_D_VDACCLKOUT", 0, + 216, UNIPHIER_PIN_DRV_4_8, + 216, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(217, "A_D_VDACDOUT5", 0, + 217, UNIPHIER_PIN_DRV_4_8, + 217, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(218, "A_D_VDACDOUT6", 0, + 218, UNIPHIER_PIN_DRV_4_8, + 218, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(219, "A_D_VDACDOUT7", 0, + 219, UNIPHIER_PIN_DRV_4_8, + 219, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(220, "A_D_VDACDOUT8", 0, + 220, UNIPHIER_PIN_DRV_4_8, + 220, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(221, "A_D_VDACDOUT9", 0, + 221, UNIPHIER_PIN_DRV_4_8, + 221, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(222, "A_D_SIFBCKIN", 0, + 222, UNIPHIER_PIN_DRV_4_8, + 222, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(223, "A_D_SIFLRCKIN", 0, + 223, UNIPHIER_PIN_DRV_4_8, + 223, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(224, "A_D_SIFDIN", 0, + 224, UNIPHIER_PIN_DRV_4_8, + 224, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(225, "A_D_LIBCKOUT", 0, + 225, UNIPHIER_PIN_DRV_4_8, + 225, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(226, "A_D_LILRCKOUT", 0, + 226, UNIPHIER_PIN_DRV_4_8, + 226, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(227, "A_D_LIDIN", 0, + 227, UNIPHIER_PIN_DRV_4_8, + 227, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(228, "A_D_LODOUT", 0, + 228, UNIPHIER_PIN_DRV_4_8, + 228, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(229, "A_D_HPDOUT", 0, + 229, UNIPHIER_PIN_DRV_4_8, + 229, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(230, "A_D_MCLK", 0, + 230, UNIPHIER_PIN_DRV_4_8, + 230, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(231, "A_D_A2PLLREFOUT", 0, + 231, UNIPHIER_PIN_DRV_4_8, + 231, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(232, "A_D_HDMI3DSDAOUT", 0, + 232, UNIPHIER_PIN_DRV_4_8, + 232, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(233, "A_D_HDMI3DSDAIN", 0, + 233, UNIPHIER_PIN_DRV_4_8, + 233, UNIPHIER_PIN_PULL_DOWN), + UNIPHIER_PINCTRL_PIN(234, "A_D_HDMI3DSCLIN", 0, + 234, UNIPHIER_PIN_DRV_4_8, + 234, UNIPHIER_PIN_PULL_DOWN), +}; + +static const unsigned adinter_pins[] = { + 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, + 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, + 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, + 229, 230, 231, 232, 233, 234, +}; +static const unsigned adinter_muxvals[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, +}; +static const unsigned emmc_pins[] = {36, 37, 38, 39, 40, 41, 42}; +static const unsigned emmc_muxvals[] = {1, 1, 1, 1, 1, 1, 1}; +static const unsigned emmc_dat8_pins[] = {43, 44, 45, 46}; +static const unsigned emmc_dat8_muxvals[] = {1, 1, 1, 1}; +static const unsigned i2c0_pins[] = {109, 110}; +static const unsigned i2c0_muxvals[] = {0, 0}; +static const unsigned i2c1_pins[] = {111, 112}; +static const unsigned i2c1_muxvals[] = {0, 0}; +static const unsigned i2c2_pins[] = {115, 116}; +static const unsigned i2c2_muxvals[] = {1, 1}; +static const unsigned i2c3_pins[] = {118, 119}; +static const unsigned i2c3_muxvals[] = {1, 1}; +static const unsigned nand_pins[] = {30, 31, 32, 33, 34, 35, 36, 39, 40, 41, + 42, 43, 44, 45, 46}; +static const unsigned nand_muxvals[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0}; +static const unsigned nand_cs1_pins[] = {37, 38}; +static const unsigned nand_cs1_muxvals[] = {0, 0}; +static const unsigned uart0_pins[] = {135, 136}; +static const unsigned uart0_muxvals[] = {3, 3}; +static const unsigned uart0b_pins[] = {11, 12}; +static const unsigned uart0b_muxvals[] = {2, 2}; +static const unsigned uart1_pins[] = {115, 116}; +static const unsigned uart1_muxvals[] = {0, 0}; +static const unsigned uart1b_pins[] = {113, 114}; +static const unsigned uart1b_muxvals[] = {1, 1}; +static const unsigned uart2_pins[] = {113, 114}; +static const unsigned uart2_muxvals[] = {2, 2}; +static const unsigned uart2b_pins[] = {86, 87}; +static const unsigned uart2b_muxvals[] = {1, 1}; +static const unsigned usb0_pins[] = {56, 57}; +static const unsigned usb0_muxvals[] = {0, 0}; +static const unsigned usb1_pins[] = {58, 59}; +static const unsigned usb1_muxvals[] = {0, 0}; +static const unsigned usb2_pins[] = {60, 61}; +static const unsigned usb2_muxvals[] = {0, 0}; +static const unsigned usb3_pins[] = {62, 63}; +static const unsigned usb3_muxvals[] = {0, 0}; +static const unsigned port_range0_pins[] = { + 127, 128, 129, 130, 131, 132, 133, 134, /* PORT0x */ + 135, 136, 137, 138, 139, 140, 141, 142, /* PORT1x */ + 0, 1, 2, 3, 4, 5, 6, 7, /* PORT2x */ + 8, 9, 10, 11, 12, 13, 14, 15, /* PORT3x */ + 16, 17, 18, 19, 21, 22, 23, 24, /* PORT4x */ + 25, 30, 31, 32, 33, 34, 35, 36, /* PORT5x */ + 37, 38, 39, 40, 41, 42, 43, 44, /* PORT6x */ + 45, 46, 47, 48, 49, 50, 51, 52, /* PORT7x */ + 53, 54, 55, 56, 57, 58, 59, 60, /* PORT8x */ + 61, 62, 63, 64, 65, 66, 67, 68, /* PORT9x */ + 69, 70, 71, 76, 77, 78, 79, 80, /* PORT10x */ +}; +static const unsigned port_range0_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT0x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT1x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT2x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT3x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT4x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT5x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT6x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT7x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT8x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT9x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT10x */ +}; +static const unsigned port_range1_pins[] = { + 81, 82, 83, 84, 85, 86, 87, 88, /* PORT12x */ + 89, 90, 95, 96, 97, 98, 99, 100, /* PORT13x */ + 101, 102, 103, 104, 105, 106, 107, 108, /* PORT14x */ + 118, 119, 120, 121, 122, 123, 124, 125, /* PORT15x */ + 126, 72, 73, 92, 177, 93, 94, 176, /* PORT16x */ + 74, 91, 27, 28, 29, 75, 20, 26, /* PORT17x */ + 109, 110, 111, 112, 113, 114, 115, 116, /* PORT18x */ + 117, 143, 144, 145, 146, 147, 148, 149, /* PORT19x */ + 150, 151, 152, 153, 154, 155, 156, 157, /* PORT20x */ + 158, 159, 160, 161, 162, 163, 164, 165, /* PORT21x */ + 166, 178, 179, 180, 181, 182, 183, 184, /* PORT22x */ + 185, 187, 188, 189, 190, 191, 192, 193, /* PORT23x */ + 194, 195, 196, 197, 198, 199, 200, 201, /* PORT24x */ + 202, 203, 204, 205, 206, 207, 208, 209, /* PORT25x */ + 210, 211, 212, 213, 214, 215, 216, 217, /* PORT26x */ + 218, 219, 220, 221, 223, 224, 225, 226, /* PORT27x */ + 227, 228, 229, 230, 231, 232, 233, 234, /* PORT28x */ +}; +static const unsigned port_range1_muxvals[] = { + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT12x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT13x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT14x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT15x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT16x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT17x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT18x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT19x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT20x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT21x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT22x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT23x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT24x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT25x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT26x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT27x */ + 15, 15, 15, 15, 15, 15, 15, 15, /* PORT28x */ +}; +static const unsigned xirq_pins[] = { + 118, 119, 120, 121, 122, 123, 124, 125, /* XIRQ0-7 */ + 126, 72, 73, 92, 177, 93, 94, 176, /* XIRQ8-15 */ + 74, 91, 27, 28, 29, 75, 20, 26, /* XIRQ16-23 */ +}; +static const unsigned xirq_muxvals[] = { + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ0-7 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ8-15 */ + 14, 14, 14, 14, 14, 14, 14, 14, /* XIRQ16-23 */ +}; + +static const struct uniphier_pinctrl_group ph1_ld6b_groups[] = { + UNIPHIER_PINCTRL_GROUP(adinter), + UNIPHIER_PINCTRL_GROUP(emmc), + UNIPHIER_PINCTRL_GROUP(emmc_dat8), + UNIPHIER_PINCTRL_GROUP(i2c0), + UNIPHIER_PINCTRL_GROUP(i2c1), + UNIPHIER_PINCTRL_GROUP(i2c2), + UNIPHIER_PINCTRL_GROUP(i2c3), + UNIPHIER_PINCTRL_GROUP(nand), + UNIPHIER_PINCTRL_GROUP(nand_cs1), + UNIPHIER_PINCTRL_GROUP(uart0), + UNIPHIER_PINCTRL_GROUP(uart0b), + UNIPHIER_PINCTRL_GROUP(uart1), + UNIPHIER_PINCTRL_GROUP(uart1b), + UNIPHIER_PINCTRL_GROUP(uart2), + UNIPHIER_PINCTRL_GROUP(uart2b), + UNIPHIER_PINCTRL_GROUP(usb0), + UNIPHIER_PINCTRL_GROUP(usb1), + UNIPHIER_PINCTRL_GROUP(usb2), + UNIPHIER_PINCTRL_GROUP(usb3), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range0), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_PORT(port_range1), + UNIPHIER_PINCTRL_GROUP_GPIO_RANGE_IRQ(xirq), + UNIPHIER_PINCTRL_GROUP_SINGLE(port00, port_range0, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port01, port_range0, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port02, port_range0, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port03, port_range0, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port04, port_range0, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port05, port_range0, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port06, port_range0, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port07, port_range0, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port10, port_range0, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port11, port_range0, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port12, port_range0, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port13, port_range0, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port14, port_range0, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port15, port_range0, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port16, port_range0, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port17, port_range0, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port20, port_range0, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port21, port_range0, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port22, port_range0, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port23, port_range0, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port24, port_range0, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port25, port_range0, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port26, port_range0, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port27, port_range0, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port30, port_range0, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port31, port_range0, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port32, port_range0, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port33, port_range0, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port34, port_range0, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port35, port_range0, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port36, port_range0, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port37, port_range0, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port40, port_range0, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port41, port_range0, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port42, port_range0, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port43, port_range0, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port44, port_range0, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port45, port_range0, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port46, port_range0, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port47, port_range0, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port50, port_range0, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port51, port_range0, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port52, port_range0, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port53, port_range0, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port54, port_range0, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port55, port_range0, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port56, port_range0, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port57, port_range0, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port60, port_range0, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port61, port_range0, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port62, port_range0, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port63, port_range0, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port64, port_range0, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port65, port_range0, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port66, port_range0, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port67, port_range0, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port70, port_range0, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port71, port_range0, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port72, port_range0, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port73, port_range0, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port74, port_range0, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port75, port_range0, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port76, port_range0, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port77, port_range0, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port80, port_range0, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port81, port_range0, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port82, port_range0, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port83, port_range0, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port84, port_range0, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port85, port_range0, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port86, port_range0, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port87, port_range0, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port90, port_range0, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port91, port_range0, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port92, port_range0, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port93, port_range0, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port94, port_range0, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port95, port_range0, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port96, port_range0, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port97, port_range0, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port100, port_range0, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port101, port_range0, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port102, port_range0, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port103, port_range0, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port104, port_range0, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port105, port_range0, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port106, port_range0, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port107, port_range0, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port120, port_range1, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(port121, port_range1, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(port122, port_range1, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(port123, port_range1, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(port124, port_range1, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(port125, port_range1, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(port126, port_range1, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(port127, port_range1, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(port130, port_range1, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(port131, port_range1, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(port132, port_range1, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(port133, port_range1, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(port134, port_range1, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(port135, port_range1, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(port136, port_range1, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(port137, port_range1, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(port140, port_range1, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(port141, port_range1, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(port142, port_range1, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(port143, port_range1, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(port144, port_range1, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(port145, port_range1, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(port146, port_range1, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(port147, port_range1, 23), + UNIPHIER_PINCTRL_GROUP_SINGLE(port150, port_range1, 24), + UNIPHIER_PINCTRL_GROUP_SINGLE(port151, port_range1, 25), + UNIPHIER_PINCTRL_GROUP_SINGLE(port152, port_range1, 26), + UNIPHIER_PINCTRL_GROUP_SINGLE(port153, port_range1, 27), + UNIPHIER_PINCTRL_GROUP_SINGLE(port154, port_range1, 28), + UNIPHIER_PINCTRL_GROUP_SINGLE(port155, port_range1, 29), + UNIPHIER_PINCTRL_GROUP_SINGLE(port156, port_range1, 30), + UNIPHIER_PINCTRL_GROUP_SINGLE(port157, port_range1, 31), + UNIPHIER_PINCTRL_GROUP_SINGLE(port160, port_range1, 32), + UNIPHIER_PINCTRL_GROUP_SINGLE(port161, port_range1, 33), + UNIPHIER_PINCTRL_GROUP_SINGLE(port162, port_range1, 34), + UNIPHIER_PINCTRL_GROUP_SINGLE(port163, port_range1, 35), + UNIPHIER_PINCTRL_GROUP_SINGLE(port164, port_range1, 36), + UNIPHIER_PINCTRL_GROUP_SINGLE(port165, port_range1, 37), + UNIPHIER_PINCTRL_GROUP_SINGLE(port166, port_range1, 38), + UNIPHIER_PINCTRL_GROUP_SINGLE(port167, port_range1, 39), + UNIPHIER_PINCTRL_GROUP_SINGLE(port170, port_range1, 40), + UNIPHIER_PINCTRL_GROUP_SINGLE(port171, port_range1, 41), + UNIPHIER_PINCTRL_GROUP_SINGLE(port172, port_range1, 42), + UNIPHIER_PINCTRL_GROUP_SINGLE(port173, port_range1, 43), + UNIPHIER_PINCTRL_GROUP_SINGLE(port174, port_range1, 44), + UNIPHIER_PINCTRL_GROUP_SINGLE(port175, port_range1, 45), + UNIPHIER_PINCTRL_GROUP_SINGLE(port176, port_range1, 46), + UNIPHIER_PINCTRL_GROUP_SINGLE(port177, port_range1, 47), + UNIPHIER_PINCTRL_GROUP_SINGLE(port180, port_range1, 48), + UNIPHIER_PINCTRL_GROUP_SINGLE(port181, port_range1, 49), + UNIPHIER_PINCTRL_GROUP_SINGLE(port182, port_range1, 50), + UNIPHIER_PINCTRL_GROUP_SINGLE(port183, port_range1, 51), + UNIPHIER_PINCTRL_GROUP_SINGLE(port184, port_range1, 52), + UNIPHIER_PINCTRL_GROUP_SINGLE(port185, port_range1, 53), + UNIPHIER_PINCTRL_GROUP_SINGLE(port186, port_range1, 54), + UNIPHIER_PINCTRL_GROUP_SINGLE(port187, port_range1, 55), + UNIPHIER_PINCTRL_GROUP_SINGLE(port190, port_range1, 56), + UNIPHIER_PINCTRL_GROUP_SINGLE(port191, port_range1, 57), + UNIPHIER_PINCTRL_GROUP_SINGLE(port192, port_range1, 58), + UNIPHIER_PINCTRL_GROUP_SINGLE(port193, port_range1, 59), + UNIPHIER_PINCTRL_GROUP_SINGLE(port194, port_range1, 60), + UNIPHIER_PINCTRL_GROUP_SINGLE(port195, port_range1, 61), + UNIPHIER_PINCTRL_GROUP_SINGLE(port196, port_range1, 62), + UNIPHIER_PINCTRL_GROUP_SINGLE(port197, port_range1, 63), + UNIPHIER_PINCTRL_GROUP_SINGLE(port200, port_range1, 64), + UNIPHIER_PINCTRL_GROUP_SINGLE(port201, port_range1, 65), + UNIPHIER_PINCTRL_GROUP_SINGLE(port202, port_range1, 66), + UNIPHIER_PINCTRL_GROUP_SINGLE(port203, port_range1, 67), + UNIPHIER_PINCTRL_GROUP_SINGLE(port204, port_range1, 68), + UNIPHIER_PINCTRL_GROUP_SINGLE(port205, port_range1, 69), + UNIPHIER_PINCTRL_GROUP_SINGLE(port206, port_range1, 70), + UNIPHIER_PINCTRL_GROUP_SINGLE(port207, port_range1, 71), + UNIPHIER_PINCTRL_GROUP_SINGLE(port210, port_range1, 72), + UNIPHIER_PINCTRL_GROUP_SINGLE(port211, port_range1, 73), + UNIPHIER_PINCTRL_GROUP_SINGLE(port212, port_range1, 74), + UNIPHIER_PINCTRL_GROUP_SINGLE(port213, port_range1, 75), + UNIPHIER_PINCTRL_GROUP_SINGLE(port214, port_range1, 76), + UNIPHIER_PINCTRL_GROUP_SINGLE(port215, port_range1, 77), + UNIPHIER_PINCTRL_GROUP_SINGLE(port216, port_range1, 78), + UNIPHIER_PINCTRL_GROUP_SINGLE(port217, port_range1, 79), + UNIPHIER_PINCTRL_GROUP_SINGLE(port220, port_range1, 80), + UNIPHIER_PINCTRL_GROUP_SINGLE(port221, port_range1, 81), + UNIPHIER_PINCTRL_GROUP_SINGLE(port222, port_range1, 82), + UNIPHIER_PINCTRL_GROUP_SINGLE(port223, port_range1, 83), + UNIPHIER_PINCTRL_GROUP_SINGLE(port224, port_range1, 84), + UNIPHIER_PINCTRL_GROUP_SINGLE(port225, port_range1, 85), + UNIPHIER_PINCTRL_GROUP_SINGLE(port226, port_range1, 86), + UNIPHIER_PINCTRL_GROUP_SINGLE(port227, port_range1, 87), + UNIPHIER_PINCTRL_GROUP_SINGLE(port230, port_range1, 88), + UNIPHIER_PINCTRL_GROUP_SINGLE(port231, port_range1, 89), + UNIPHIER_PINCTRL_GROUP_SINGLE(port232, port_range1, 90), + UNIPHIER_PINCTRL_GROUP_SINGLE(port233, port_range1, 91), + UNIPHIER_PINCTRL_GROUP_SINGLE(port234, port_range1, 92), + UNIPHIER_PINCTRL_GROUP_SINGLE(port235, port_range1, 93), + UNIPHIER_PINCTRL_GROUP_SINGLE(port236, port_range1, 94), + UNIPHIER_PINCTRL_GROUP_SINGLE(port237, port_range1, 95), + UNIPHIER_PINCTRL_GROUP_SINGLE(port240, port_range1, 96), + UNIPHIER_PINCTRL_GROUP_SINGLE(port241, port_range1, 97), + UNIPHIER_PINCTRL_GROUP_SINGLE(port242, port_range1, 98), + UNIPHIER_PINCTRL_GROUP_SINGLE(port243, port_range1, 99), + UNIPHIER_PINCTRL_GROUP_SINGLE(port244, port_range1, 100), + UNIPHIER_PINCTRL_GROUP_SINGLE(port245, port_range1, 101), + UNIPHIER_PINCTRL_GROUP_SINGLE(port246, port_range1, 102), + UNIPHIER_PINCTRL_GROUP_SINGLE(port247, port_range1, 103), + UNIPHIER_PINCTRL_GROUP_SINGLE(port250, port_range1, 104), + UNIPHIER_PINCTRL_GROUP_SINGLE(port251, port_range1, 105), + UNIPHIER_PINCTRL_GROUP_SINGLE(port252, port_range1, 106), + UNIPHIER_PINCTRL_GROUP_SINGLE(port253, port_range1, 107), + UNIPHIER_PINCTRL_GROUP_SINGLE(port254, port_range1, 108), + UNIPHIER_PINCTRL_GROUP_SINGLE(port255, port_range1, 109), + UNIPHIER_PINCTRL_GROUP_SINGLE(port256, port_range1, 110), + UNIPHIER_PINCTRL_GROUP_SINGLE(port257, port_range1, 111), + UNIPHIER_PINCTRL_GROUP_SINGLE(port260, port_range1, 112), + UNIPHIER_PINCTRL_GROUP_SINGLE(port261, port_range1, 113), + UNIPHIER_PINCTRL_GROUP_SINGLE(port262, port_range1, 114), + UNIPHIER_PINCTRL_GROUP_SINGLE(port263, port_range1, 115), + UNIPHIER_PINCTRL_GROUP_SINGLE(port264, port_range1, 116), + UNIPHIER_PINCTRL_GROUP_SINGLE(port265, port_range1, 117), + UNIPHIER_PINCTRL_GROUP_SINGLE(port266, port_range1, 118), + UNIPHIER_PINCTRL_GROUP_SINGLE(port267, port_range1, 119), + UNIPHIER_PINCTRL_GROUP_SINGLE(port270, port_range1, 120), + UNIPHIER_PINCTRL_GROUP_SINGLE(port271, port_range1, 121), + UNIPHIER_PINCTRL_GROUP_SINGLE(port272, port_range1, 122), + UNIPHIER_PINCTRL_GROUP_SINGLE(port273, port_range1, 123), + UNIPHIER_PINCTRL_GROUP_SINGLE(port274, port_range1, 124), + UNIPHIER_PINCTRL_GROUP_SINGLE(port275, port_range1, 125), + UNIPHIER_PINCTRL_GROUP_SINGLE(port276, port_range1, 126), + UNIPHIER_PINCTRL_GROUP_SINGLE(port277, port_range1, 127), + UNIPHIER_PINCTRL_GROUP_SINGLE(port280, port_range1, 128), + UNIPHIER_PINCTRL_GROUP_SINGLE(port281, port_range1, 129), + UNIPHIER_PINCTRL_GROUP_SINGLE(port282, port_range1, 130), + UNIPHIER_PINCTRL_GROUP_SINGLE(port283, port_range1, 131), + UNIPHIER_PINCTRL_GROUP_SINGLE(port284, port_range1, 132), + UNIPHIER_PINCTRL_GROUP_SINGLE(port285, port_range1, 133), + UNIPHIER_PINCTRL_GROUP_SINGLE(port286, port_range1, 134), + UNIPHIER_PINCTRL_GROUP_SINGLE(port287, port_range1, 135), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq0, xirq, 0), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq1, xirq, 1), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq2, xirq, 2), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq3, xirq, 3), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq4, xirq, 4), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq5, xirq, 5), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq6, xirq, 6), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq7, xirq, 7), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq8, xirq, 8), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq9, xirq, 9), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq10, xirq, 10), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq11, xirq, 11), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq12, xirq, 12), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq13, xirq, 13), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq14, xirq, 14), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq15, xirq, 15), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq16, xirq, 16), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq17, xirq, 17), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq18, xirq, 18), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq19, xirq, 19), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq20, xirq, 20), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq21, xirq, 21), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq22, xirq, 22), + UNIPHIER_PINCTRL_GROUP_SINGLE(xirq23, xirq, 23), +}; + +static const char * const adinter_groups[] = {"adinter"}; +static const char * const emmc_groups[] = {"emmc", "emmc_dat8"}; +static const char * const i2c0_groups[] = {"i2c0"}; +static const char * const i2c1_groups[] = {"i2c1"}; +static const char * const i2c2_groups[] = {"i2c2"}; +static const char * const i2c3_groups[] = {"i2c3"}; +static const char * const nand_groups[] = {"nand", "nand_cs1"}; +static const char * const uart0_groups[] = {"uart0", "uart0b"}; +static const char * const uart1_groups[] = {"uart1", "uart1b"}; +static const char * const uart2_groups[] = {"uart2", "uart2b"}; +static const char * const usb0_groups[] = {"usb0"}; +static const char * const usb1_groups[] = {"usb1"}; +static const char * const usb2_groups[] = {"usb2"}; +static const char * const usb3_groups[] = {"usb3"}; +static const char * const port_groups[] = { + "port00", "port01", "port02", "port03", + "port04", "port05", "port06", "port07", + "port10", "port11", "port12", "port13", + "port14", "port15", "port16", "port17", + "port20", "port21", "port22", "port23", + "port24", "port25", "port26", "port27", + "port30", "port31", "port32", "port33", + "port34", "port35", "port36", "port37", + "port40", "port41", "port42", "port43", + "port44", "port45", "port46", "port47", + "port50", "port51", "port52", "port53", + "port54", "port55", "port56", "port57", + "port60", "port61", "port62", "port63", + "port64", "port65", "port66", "port67", + "port70", "port71", "port72", "port73", + "port74", "port75", "port76", "port77", + "port80", "port81", "port82", "port83", + "port84", "port85", "port86", "port87", + "port90", "port91", "port92", "port93", + "port94", "port95", "port96", "port97", + "port100", "port101", "port102", "port103", + "port104", "port105", "port106", "port107", + /* port110-117 missing */ + "port120", "port121", "port122", "port123", + "port124", "port125", "port126", "port127", + "port130", "port131", "port132", "port133", + "port134", "port135", "port136", "port137", + "port140", "port141", "port142", "port143", + "port144", "port145", "port146", "port147", + "port150", "port151", "port152", "port153", + "port154", "port155", "port156", "port157", + "port160", "port161", "port162", "port163", + "port164", "port165", "port166", "port167", + "port170", "port171", "port172", "port173", + "port174", "port175", "port176", "port177", + "port180", "port181", "port182", "port183", + "port184", "port185", "port186", "port187", + "port190", "port191", "port192", "port193", + "port194", "port195", "port196", "port197", + "port200", "port201", "port202", "port203", + "port204", "port205", "port206", "port207", + "port210", "port211", "port212", "port213", + "port214", "port215", "port216", "port217", + "port220", "port221", "port222", "port223", + "port224", "port225", "port226", "port227", + "port230", "port231", "port232", "port233", + "port234", "port235", "port236", "port237", + "port240", "port241", "port242", "port243", + "port244", "port245", "port246", "port247", + "port250", "port251", "port252", "port253", + "port254", "port255", "port256", "port257", + "port260", "port261", "port262", "port263", + "port264", "port265", "port266", "port267", + "port270", "port271", "port272", "port273", + "port274", "port275", "port276", "port277", + "port280", "port281", "port282", "port283", + "port284", "port285", "port286", "port287", +}; +static const char * const xirq_groups[] = { + "xirq0", "xirq1", "xirq2", "xirq3", + "xirq4", "xirq5", "xirq6", "xirq7", + "xirq8", "xirq9", "xirq10", "xirq11", + "xirq12", "xirq13", "xirq14", "xirq15", + "xirq16", "xirq17", "xirq18", "xirq19", + "xirq20", "xirq21", "xirq22", "xirq23", +}; + +static const struct uniphier_pinmux_function ph1_ld6b_functions[] = { + UNIPHIER_PINMUX_FUNCTION(adinter), /* Achip-Dchip interconnect */ + UNIPHIER_PINMUX_FUNCTION(emmc), + UNIPHIER_PINMUX_FUNCTION(i2c0), + UNIPHIER_PINMUX_FUNCTION(i2c1), + UNIPHIER_PINMUX_FUNCTION(i2c2), + UNIPHIER_PINMUX_FUNCTION(i2c3), + UNIPHIER_PINMUX_FUNCTION(nand), + UNIPHIER_PINMUX_FUNCTION(uart0), + UNIPHIER_PINMUX_FUNCTION(uart1), + UNIPHIER_PINMUX_FUNCTION(uart2), + UNIPHIER_PINMUX_FUNCTION(usb0), + UNIPHIER_PINMUX_FUNCTION(usb1), + UNIPHIER_PINMUX_FUNCTION(usb2), + UNIPHIER_PINMUX_FUNCTION(usb3), + UNIPHIER_PINMUX_FUNCTION(port), + UNIPHIER_PINMUX_FUNCTION(xirq), +}; + +static struct uniphier_pinctrl_socdata ph1_ld6b_pindata = { + .groups = ph1_ld6b_groups, + .groups_count = ARRAY_SIZE(ph1_ld6b_groups), + .functions = ph1_ld6b_functions, + .functions_count = ARRAY_SIZE(ph1_ld6b_functions), + .mux_bits = 8, + .reg_stride = 4, + .load_pinctrl = false, +}; + +static struct pinctrl_desc ph1_ld6b_pinctrl_desc = { + .name = DRIVER_NAME, + .pins = ph1_ld6b_pins, + .npins = ARRAY_SIZE(ph1_ld6b_pins), + .owner = THIS_MODULE, +}; + +static int ph1_ld6b_pinctrl_probe(struct platform_device *pdev) +{ + return uniphier_pinctrl_probe(pdev, &ph1_ld6b_pinctrl_desc, + &ph1_ld6b_pindata); +} + +static const struct of_device_id ph1_ld6b_pinctrl_match[] = { + { .compatible = "socionext,ph1-ld6b-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ph1_ld6b_pinctrl_match); + +static struct platform_driver ph1_ld6b_pinctrl_driver = { + .probe = ph1_ld6b_pinctrl_probe, + .remove = uniphier_pinctrl_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = ph1_ld6b_pinctrl_match, + }, +}; +module_platform_driver(ph1_ld6b_pinctrl_driver); + +MODULE_AUTHOR("Masahiro Yamada "); +MODULE_DESCRIPTION("UniPhier PH1-LD6b pinctrl driver"); +MODULE_LICENSE("GPL"); -- GitLab From 95b612cc6c7f95f4e08f1b3dbc6588fda49b1b12 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 9 Jul 2015 10:55:01 +0900 Subject: [PATCH 0936/7006] pinctrl: move CONFIG_PINCTRL to drivers/Makefile Kbuild should descend into drivers/pinctrl/ only when CONFIG_PINCTRL is enabled because everything under that directory depends on CONFIG_PINCTRL. We can avoid the conditional, ifeq ($(CONFIG_OF),y) ... endif. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/Makefile | 2 +- drivers/pinctrl/Makefile | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/Makefile b/drivers/Makefile index b64b49f6e01bf..e4b260ecec155 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -11,7 +11,7 @@ obj-y += bus/ obj-$(CONFIG_GENERIC_PHY) += phy/ # GPIO must come after pinctrl as gpios may need to mux pins etc -obj-y += pinctrl/ +obj-$(CONFIG_PINCTRL) += pinctrl/ obj-y += gpio/ obj-y += pwm/ obj-$(CONFIG_PCI) += pci/ diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f6710a8a15032..76ba976cb9cad 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -2,12 +2,10 @@ subdir-ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG -obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o +obj-y += core.o pinctrl-utils.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINCONF) += pinconf.o -ifeq ($(CONFIG_OF),y) -obj-$(CONFIG_PINCTRL) += devicetree.o -endif +obj-$(CONFIG_OF) += devicetree.o obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o -- GitLab From c15df306fc79c672573f1cc2ebdfcb32d7e68780 Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Thu, 16 Jul 2015 16:51:30 +0900 Subject: [PATCH 0937/7006] ipv6: Remove unused arguments for __ipv6_dev_get_saddr(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 4c9a0246ef486..32153c248959c 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1360,8 +1360,6 @@ out: static int __ipv6_dev_get_saddr(struct net *net, struct ipv6_saddr_dst *dst, - unsigned int prefs, - const struct in6_addr *saddr, struct inet6_dev *idev, struct ipv6_saddr_score *scores, int hiscore_idx) @@ -1485,13 +1483,13 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, if (use_oif_addr) { if (idev) - hiscore_idx = __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores, hiscore_idx); + hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx); } else { for_each_netdev_rcu(net, dev) { idev = __in6_dev_get(dev); if (!idev) continue; - hiscore_idx = __ipv6_dev_get_saddr(net, &dst, prefs, saddr, idev, scores, hiscore_idx); + hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx); } } rcu_read_unlock(); -- GitLab From 24f743a0f06675da4e7c6a07b88e90d425edd30a Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Mon, 29 Jun 2015 10:35:56 +0800 Subject: [PATCH 0938/7006] gpio: Document ZTE zx296702 GPIO DT binding Add document of ZTE zx296702 GPIO binding Signed-off-by: Jun Nie Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- .../bindings/gpio/zx296702-gpio.txt | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/zx296702-gpio.txt diff --git a/Documentation/devicetree/bindings/gpio/zx296702-gpio.txt b/Documentation/devicetree/bindings/gpio/zx296702-gpio.txt new file mode 100644 index 0000000000000..0dab156fcf417 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/zx296702-gpio.txt @@ -0,0 +1,24 @@ +ZTE ZX296702 GPIO controller + +Required properties: +- compatible : "zte,zx296702-gpio" +- #gpio-cells : Should be two. The first cell is the pin number and the + second cell is used to specify optional parameters: + - bit 0 specifies polarity (0 for normal, 1 for inverted) +- gpio-controller : Marks the device node as a GPIO controller. +- interrupts : Interrupt mapping for GPIO IRQ. +- gpio-ranges : Interaction with the PINCTRL subsystem. + +gpio1: gpio@b008040 { + compatible = "zte,zx296702-gpio"; + reg = <0xb008040 0x40>; + gpio-controller; + #gpio-cells = <2>; + gpio-ranges = < &pmx0 0 54 2 &pmx0 2 59 14>; + interrupts = ; + interrupt-parent = <&intc>; + interrupt-controller; + #interrupt-cells = <2>; + clock-names = "gpio_pclk"; + clocks = <&lsp0clk ZX296702_GPIO_CLK>; +}; -- GitLab From e7aa6d8c1ba2429deef75fb24d029e00ab71bebf Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Mon, 29 Jun 2015 10:35:57 +0800 Subject: [PATCH 0939/7006] gpio: zx: Add ZTE zx296702 GPIO support Add ZTE zx296702 GPIO controller support Signed-off-by: Jun Nie Acked-by: Shawn Guo Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-zx.c | 324 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 331 insertions(+) create mode 100644 drivers/gpio/gpio-zx.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4c9fa58c56434..3a9dc1a8f56e0 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1003,6 +1003,12 @@ config GPIO_MC33880 SPI driver for Freescale MC33880 high-side/low-side switch. This provides GPIO interface supporting inputs and outputs. +config GPIO_ZX + bool "ZTE ZX GPIO support" + select GPIOLIB_IRQCHIP + help + Say yes here to support the GPIO device on ZTE ZX SoCs. + endmenu menu "USB GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f82cd678ce086..558b867ccebb9 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -116,3 +116,4 @@ obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o +obj-$(CONFIG_GPIO_ZX) += gpio-zx.o diff --git a/drivers/gpio/gpio-zx.c b/drivers/gpio/gpio-zx.c new file mode 100644 index 0000000000000..12ee1969298cc --- /dev/null +++ b/drivers/gpio/gpio-zx.c @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2015 Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ZX_GPIO_DIR 0x00 +#define ZX_GPIO_IVE 0x04 +#define ZX_GPIO_IV 0x08 +#define ZX_GPIO_IEP 0x0C +#define ZX_GPIO_IEN 0x10 +#define ZX_GPIO_DI 0x14 +#define ZX_GPIO_DO1 0x18 +#define ZX_GPIO_DO0 0x1C +#define ZX_GPIO_DO 0x20 + +#define ZX_GPIO_IM 0x28 +#define ZX_GPIO_IE 0x2C + +#define ZX_GPIO_MIS 0x30 +#define ZX_GPIO_IC 0x34 + +#define ZX_GPIO_NR 16 + +struct zx_gpio { + spinlock_t lock; + + void __iomem *base; + struct gpio_chip gc; + bool uses_pinctrl; +}; + +static inline struct zx_gpio *to_zx(struct gpio_chip *gc) +{ + return container_of(gc, struct zx_gpio, gc); +} + +static int zx_gpio_request(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + int gpio = gc->base + offset; + + if (chip->uses_pinctrl) + return pinctrl_request_gpio(gpio); + return 0; +} + +static void zx_gpio_free(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + int gpio = gc->base + offset; + + if (chip->uses_pinctrl) + pinctrl_free_gpio(gpio); +} + +static int zx_direction_input(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + unsigned long flags; + u16 gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); + gpiodir &= ~BIT(offset); + writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int zx_direction_output(struct gpio_chip *gc, unsigned offset, + int value) +{ + struct zx_gpio *chip = to_zx(gc); + unsigned long flags; + u16 gpiodir; + + if (offset >= gc->ngpio) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + gpiodir = readw_relaxed(chip->base + ZX_GPIO_DIR); + gpiodir |= BIT(offset); + writew_relaxed(gpiodir, chip->base + ZX_GPIO_DIR); + + if (value) + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); + else + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int zx_get_value(struct gpio_chip *gc, unsigned offset) +{ + struct zx_gpio *chip = to_zx(gc); + + return !!(readw_relaxed(chip->base + ZX_GPIO_DI) & BIT(offset)); +} + +static void zx_set_value(struct gpio_chip *gc, unsigned offset, int value) +{ + struct zx_gpio *chip = to_zx(gc); + + if (value) + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO1); + else + writew_relaxed(BIT(offset), chip->base + ZX_GPIO_DO0); +} + +static int zx_irq_type(struct irq_data *d, unsigned trigger) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + int offset = irqd_to_hwirq(d); + unsigned long flags; + u16 gpiois, gpioi_epos, gpioi_eneg, gpioiev; + u16 bit = BIT(offset); + + if (offset < 0 || offset >= ZX_GPIO_NR) + return -EINVAL; + + spin_lock_irqsave(&chip->lock, flags); + + gpioiev = readw_relaxed(chip->base + ZX_GPIO_IV); + gpiois = readw_relaxed(chip->base + ZX_GPIO_IVE); + gpioi_epos = readw_relaxed(chip->base + ZX_GPIO_IEP); + gpioi_eneg = readw_relaxed(chip->base + ZX_GPIO_IEN); + + if (trigger & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) { + gpiois |= bit; + if (trigger & IRQ_TYPE_LEVEL_HIGH) + gpioiev |= bit; + else + gpioiev &= ~bit; + } else + gpiois &= ~bit; + + if ((trigger & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) { + gpioi_epos |= bit; + gpioi_eneg |= bit; + } else { + if (trigger & IRQ_TYPE_EDGE_RISING) { + gpioi_epos |= bit; + gpioi_eneg &= ~bit; + } else if (trigger & IRQ_TYPE_EDGE_FALLING) { + gpioi_eneg |= bit; + gpioi_epos &= ~bit; + } + } + + writew_relaxed(gpiois, chip->base + ZX_GPIO_IVE); + writew_relaxed(gpioi_epos, chip->base + ZX_GPIO_IEP); + writew_relaxed(gpioi_eneg, chip->base + ZX_GPIO_IEN); + writew_relaxed(gpioiev, chip->base + ZX_GPIO_IV); + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static void zx_irq_handler(unsigned irq, struct irq_desc *desc) +{ + unsigned long pending; + int offset; + struct gpio_chip *gc = irq_desc_get_handler_data(desc); + struct zx_gpio *chip = to_zx(gc); + struct irq_chip *irqchip = irq_desc_get_chip(desc); + + chained_irq_enter(irqchip, desc); + + pending = readw_relaxed(chip->base + ZX_GPIO_MIS); + writew_relaxed(pending, chip->base + ZX_GPIO_IC); + if (pending) { + for_each_set_bit(offset, &pending, ZX_GPIO_NR) + generic_handle_irq(irq_find_mapping(gc->irqdomain, + offset)); + } + + chained_irq_exit(irqchip, desc); +} + +static void zx_irq_mask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); + u16 gpioie; + + spin_lock(&chip->lock); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) | mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) & ~mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); + spin_unlock(&chip->lock); +} + +static void zx_irq_unmask(struct irq_data *d) +{ + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct zx_gpio *chip = to_zx(gc); + u16 mask = BIT(irqd_to_hwirq(d) % ZX_GPIO_NR); + u16 gpioie; + + spin_lock(&chip->lock); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IM) & ~mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IM); + gpioie = readw_relaxed(chip->base + ZX_GPIO_IE) | mask; + writew_relaxed(gpioie, chip->base + ZX_GPIO_IE); + spin_unlock(&chip->lock); +} + +static struct irq_chip zx_irqchip = { + .name = "zx-gpio", + .irq_mask = zx_irq_mask, + .irq_unmask = zx_irq_unmask, + .irq_set_type = zx_irq_type, +}; + +static int zx_gpio_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct zx_gpio *chip; + struct resource *res; + int irq, id, ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->base = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->base)) + return PTR_ERR(chip->base); + + spin_lock_init(&chip->lock); + if (of_property_read_bool(dev->of_node, "gpio-ranges")) + chip->uses_pinctrl = true; + + id = of_alias_get_id(dev->of_node, "gpio"); + chip->gc.request = zx_gpio_request; + chip->gc.free = zx_gpio_free; + chip->gc.direction_input = zx_direction_input; + chip->gc.direction_output = zx_direction_output; + chip->gc.get = zx_get_value; + chip->gc.set = zx_set_value; + chip->gc.base = ZX_GPIO_NR * id; + chip->gc.ngpio = ZX_GPIO_NR; + chip->gc.label = dev_name(dev); + chip->gc.dev = dev; + chip->gc.owner = THIS_MODULE; + + ret = gpiochip_add(&chip->gc); + if (ret) + return ret; + + /* + * irq_chip support + */ + writew_relaxed(0xffff, chip->base + ZX_GPIO_IM); + writew_relaxed(0, chip->base + ZX_GPIO_IE); + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "invalid IRQ\n"); + gpiochip_remove(&chip->gc); + return -ENODEV; + } + + ret = gpiochip_irqchip_add(&chip->gc, &zx_irqchip, + 0, handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(dev, "could not add irqchip\n"); + gpiochip_remove(&chip->gc); + return ret; + } + gpiochip_set_chained_irqchip(&chip->gc, &zx_irqchip, + irq, zx_irq_handler); + + platform_set_drvdata(pdev, chip); + dev_info(dev, "ZX GPIO chip registered\n"); + + return 0; +} + +static const struct of_device_id zx_gpio_match[] = { + { + .compatible = "zte,zx296702-gpio", + }, + { }, +}; +MODULE_DEVICE_TABLE(of, zx_gpio_match); + +static struct platform_driver zx_gpio_driver = { + .probe = zx_gpio_probe, + .driver = { + .name = "zx_gpio", + .of_match_table = of_match_ptr(zx_gpio_match), + }, +}; + +module_platform_driver(zx_gpio_driver) + +MODULE_AUTHOR("Jun Nie "); +MODULE_DESCRIPTION("ZTE ZX296702 GPIO driver"); +MODULE_LICENSE("GPL"); -- GitLab From 8749f8ed5cc07f4f130f2e5b2c41da78388146ec Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Jun 2015 18:12:24 +0300 Subject: [PATCH 0940/7006] pinctrl: samsung: don't truncate the last char We were allocating enough space because sizeof("-grp") and sizeof("-mux") are both equal to 5 but in the snprintf() we only allowed for 4 characters so the last 'p' and 'x' characters were truncated. The allocate and sprintf can be done in one step with the kasprintf(). Signed-off-by: Dan Carpenter Reviewed-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/samsung/pinctrl-exynos5440.c | 22 +++++++------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index f5619fb504473..fa84db6a5b15e 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -44,9 +44,7 @@ #define PIN_NAME_LENGTH 10 #define GROUP_SUFFIX "-grp" -#define GSUFFIX_LEN sizeof(GROUP_SUFFIX) #define FUNCTION_SUFFIX "-mux" -#define FSUFFIX_LEN sizeof(FUNCTION_SUFFIX) /* * pin configuration type and its value are packed together into a 16-bits. @@ -215,12 +213,11 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, * Allocate memory for pin group name. The pin group name is derived * from the node name from which these map entries are be created. */ - gname = kzalloc(strlen(np->name) + GSUFFIX_LEN, GFP_KERNEL); + gname = kasprintf(GFP_KERNEL, "%s%s", np->name, GROUP_SUFFIX); if (!gname) { dev_err(dev, "failed to alloc memory for group name\n"); goto free_map; } - snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX); /* * don't have config options? then skip over to creating function @@ -254,13 +251,12 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, skip_cfgs: /* create the function map entry */ if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { - fname = kzalloc(strlen(np->name) + FSUFFIX_LEN, GFP_KERNEL); + fname = kasprintf(GFP_KERNEL, + "%s%s", np->name, FUNCTION_SUFFIX); if (!fname) { dev_err(dev, "failed to alloc memory for func name\n"); goto free_cfg; } - snprintf(fname, strlen(np->name) + 4, "%s%s", np->name, - FUNCTION_SUFFIX); map[*nmaps].data.mux.group = gname; map[*nmaps].data.mux.function = fname; @@ -710,14 +706,12 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, } /* derive pin group name from the node name */ - gname = devm_kzalloc(dev, strlen(cfg_np->name) + GSUFFIX_LEN, - GFP_KERNEL); + gname = devm_kasprintf(dev, GFP_KERNEL, + "%s%s", cfg_np->name, GROUP_SUFFIX); if (!gname) { dev_err(dev, "failed to alloc memory for group name\n"); return -ENOMEM; } - snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, - GROUP_SUFFIX); grp->name = gname; grp->pins = pin_list; @@ -731,14 +725,12 @@ skip_to_pin_function: continue; /* derive function name from the node name */ - fname = devm_kzalloc(dev, strlen(cfg_np->name) + FSUFFIX_LEN, - GFP_KERNEL); + fname = devm_kasprintf(dev, GFP_KERNEL, + "%s%s", cfg_np->name, FUNCTION_SUFFIX); if (!fname) { dev_err(dev, "failed to alloc memory for func name\n"); return -ENOMEM; } - snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name, - FUNCTION_SUFFIX); func->name = fname; func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); -- GitLab From 583facb6ae27dfb4d0fb5a952dade5aa990a05c9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 22 Jun 2015 18:13:15 +0300 Subject: [PATCH 0941/7006] pinctrl: samsung: remove "out of memory" messages Checkpatch.pl complains about these: WARNING: Possible unnecessary 'out of memory' message The messages use a little extra RAM and they add a few extra lines of code. We're probably never going to hit these out of memory situations but if we did then kmalloc() has pretty good error messages built-in. Signed-off-by: Dan Carpenter Reviewed-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/samsung/pinctrl-exynos5440.c | 67 ++++++-------------- 1 file changed, 18 insertions(+), 49 deletions(-) diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index fa84db6a5b15e..5574b8ae59497 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -203,10 +203,8 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, /* Allocate memory for pin-map entries */ map = kzalloc(sizeof(*map) * map_cnt, GFP_KERNEL); - if (!map) { - dev_err(dev, "could not alloc memory for pin-maps\n"); + if (!map) return -ENOMEM; - } *nmaps = 0; /* @@ -214,10 +212,8 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, * from the node name from which these map entries are be created. */ gname = kasprintf(GFP_KERNEL, "%s%s", np->name, GROUP_SUFFIX); - if (!gname) { - dev_err(dev, "failed to alloc memory for group name\n"); + if (!gname) goto free_map; - } /* * don't have config options? then skip over to creating function @@ -228,10 +224,8 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev, /* Allocate memory for config entries */ cfg = kzalloc(sizeof(*cfg) * cfg_cnt, GFP_KERNEL); - if (!cfg) { - dev_err(dev, "failed to alloc memory for configs\n"); + if (!cfg) goto free_gname; - } /* Prepare a list of config settings */ for (idx = 0, cfg_cnt = 0; idx < ARRAY_SIZE(pcfgs); idx++) { @@ -253,10 +247,8 @@ skip_cfgs: if (of_find_property(np, "samsung,exynos5440-pin-function", NULL)) { fname = kasprintf(GFP_KERNEL, "%s%s", np->name, FUNCTION_SUFFIX); - if (!fname) { - dev_err(dev, "failed to alloc memory for func name\n"); + if (!fname) goto free_cfg; - } map[*nmaps].data.mux.group = gname; map[*nmaps].data.mux.function = fname; @@ -647,10 +639,8 @@ static int exynos5440_pinctrl_parse_dt_pins(struct platform_device *pdev, } *pin_list = devm_kzalloc(dev, *npins * sizeof(**pin_list), GFP_KERNEL); - if (!*pin_list) { - dev_err(dev, "failed to allocate memory for pin list\n"); + if (!*pin_list) return -ENOMEM; - } return of_property_read_u32_array(cfg_np, "samsung,exynos5440-pins", *pin_list, *npins); @@ -678,17 +668,15 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, return -EINVAL; groups = devm_kzalloc(dev, grp_cnt * sizeof(*groups), GFP_KERNEL); - if (!groups) { - dev_err(dev, "failed allocate memory for ping group list\n"); + if (!groups) return -EINVAL; - } + grp = groups; functions = devm_kzalloc(dev, grp_cnt * sizeof(*functions), GFP_KERNEL); - if (!functions) { - dev_err(dev, "failed to allocate memory for function list\n"); + if (!functions) return -EINVAL; - } + func = functions; /* @@ -708,10 +696,8 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev, /* derive pin group name from the node name */ gname = devm_kasprintf(dev, GFP_KERNEL, "%s%s", cfg_np->name, GROUP_SUFFIX); - if (!gname) { - dev_err(dev, "failed to alloc memory for group name\n"); + if (!gname) return -ENOMEM; - } grp->name = gname; grp->pins = pin_list; @@ -727,18 +713,13 @@ skip_to_pin_function: /* derive function name from the node name */ fname = devm_kasprintf(dev, GFP_KERNEL, "%s%s", cfg_np->name, FUNCTION_SUFFIX); - if (!fname) { - dev_err(dev, "failed to alloc memory for func name\n"); + if (!fname) return -ENOMEM; - } func->name = fname; func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL); - if (!func->groups) { - dev_err(dev, "failed to alloc memory for group list " - "in pin function"); + if (!func->groups) return -ENOMEM; - } func->groups[0] = gname; func->num_groups = gname ? 1 : 0; func->function = function; @@ -766,10 +747,8 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, int pin, ret; ctrldesc = devm_kzalloc(dev, sizeof(*ctrldesc), GFP_KERNEL); - if (!ctrldesc) { - dev_err(dev, "could not allocate memory for pinctrl desc\n"); + if (!ctrldesc) return -ENOMEM; - } ctrldesc->name = "exynos5440-pinctrl"; ctrldesc->owner = THIS_MODULE; @@ -779,10 +758,8 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) * EXYNOS5440_MAX_PINS, GFP_KERNEL); - if (!pindesc) { - dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n"); + if (!pindesc) return -ENOMEM; - } ctrldesc->pins = pindesc; ctrldesc->npins = EXYNOS5440_MAX_PINS; @@ -796,10 +773,8 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev, */ pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH * ctrldesc->npins, GFP_KERNEL); - if (!pin_names) { - dev_err(&pdev->dev, "mem alloc for pin names failed\n"); + if (!pin_names) return -ENOMEM; - } /* for each pin, set the name of the pin */ for (pin = 0; pin < ctrldesc->npins; pin++) { @@ -836,10 +811,8 @@ static int exynos5440_gpiolib_register(struct platform_device *pdev, int ret; gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); - if (!gc) { - dev_err(&pdev->dev, "mem alloc for gpio_chip failed\n"); + if (!gc) return -ENOMEM; - } priv->gc = gc; gc->base = 0; @@ -941,10 +914,8 @@ static int exynos5440_gpio_irq_init(struct platform_device *pdev, intd = devm_kzalloc(dev, sizeof(*intd) * EXYNOS5440_MAX_GPIO_INT, GFP_KERNEL); - if (!intd) { - dev_err(dev, "failed to allocate memory for gpio intr data\n"); + if (!intd) return -ENOMEM; - } for (i = 0; i < EXYNOS5440_MAX_GPIO_INT; i++) { irq = irq_of_parse_and_map(dev->of_node, i); @@ -987,10 +958,8 @@ static int exynos5440_pinctrl_probe(struct platform_device *pdev) } priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); - if (!priv) { - dev_err(dev, "could not allocate memory for private data\n"); + if (!priv) return -ENOMEM; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->reg_base = devm_ioremap_resource(&pdev->dev, res); -- GitLab From 527b397a7a3647b8ba2eae2e7a12b237bf411476 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 23 Jun 2015 15:48:02 +0200 Subject: [PATCH 0942/7006] gpio: em: Remove obsolete platform data support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 59032702ead90562 ("ARM: shmobile: Remove legacy platform devices from EMEV2 SoC code"), EMMA Mobile SoCs are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to use platform data anymore, hence remove platform data configuration. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Tested-by: Niklas Söderlund Signed-off-by: Linus Walleij --- drivers/gpio/gpio-em.c | 34 +++++++-------------------- include/linux/platform_data/gpio-em.h | 11 --------- 2 files changed, 8 insertions(+), 37 deletions(-) delete mode 100644 include/linux/platform_data/gpio-em.h diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index fbf287307c4cc..a77f16c8d1422 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -31,7 +31,6 @@ #include #include #include -#include struct em_gio_priv { void __iomem *base0; @@ -273,13 +272,12 @@ static const struct irq_domain_ops em_gio_irq_domain_ops = { static int em_gio_probe(struct platform_device *pdev) { - struct gpio_em_config pdata_dt; - struct gpio_em_config *pdata = dev_get_platdata(&pdev->dev); struct em_gio_priv *p; struct resource *io[2], *irq[2]; struct gpio_chip *gpio_chip; struct irq_chip *irq_chip; const char *name = dev_name(&pdev->dev); + unsigned int ngpios; int ret; p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL); @@ -319,18 +317,10 @@ static int em_gio_probe(struct platform_device *pdev) goto err0; } - if (!pdata) { - memset(&pdata_dt, 0, sizeof(pdata_dt)); - pdata = &pdata_dt; - - if (of_property_read_u32(pdev->dev.of_node, "ngpios", - &pdata->number_of_pins)) { - dev_err(&pdev->dev, "Missing ngpios OF property\n"); - ret = -EINVAL; - goto err0; - } - - pdata->gpio_base = -1; + if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { + dev_err(&pdev->dev, "Missing ngpios OF property\n"); + ret = -EINVAL; + goto err0; } gpio_chip = &p->gpio_chip; @@ -345,8 +335,8 @@ static int em_gio_probe(struct platform_device *pdev) gpio_chip->label = name; gpio_chip->dev = &pdev->dev; gpio_chip->owner = THIS_MODULE; - gpio_chip->base = pdata->gpio_base; - gpio_chip->ngpio = pdata->number_of_pins; + gpio_chip->base = -1; + gpio_chip->ngpio = ngpios; irq_chip = &p->irq_chip; irq_chip->name = name; @@ -357,9 +347,7 @@ static int em_gio_probe(struct platform_device *pdev) irq_chip->irq_release_resources = em_gio_irq_relres; irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND; - p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, - pdata->number_of_pins, - pdata->irq_base, + p->irq_domain = irq_domain_add_simple(pdev->dev.of_node, ngpios, 0, &em_gio_irq_domain_ops, p); if (!p->irq_domain) { ret = -ENXIO; @@ -387,12 +375,6 @@ static int em_gio_probe(struct platform_device *pdev) goto err1; } - if (pdata->pctl_name) { - ret = gpiochip_add_pin_range(gpio_chip, pdata->pctl_name, 0, - gpio_chip->base, gpio_chip->ngpio); - if (ret < 0) - dev_warn(&pdev->dev, "failed to add pin range\n"); - } return 0; err1: diff --git a/include/linux/platform_data/gpio-em.h b/include/linux/platform_data/gpio-em.h deleted file mode 100644 index 7c5a519d2dcde..0000000000000 --- a/include/linux/platform_data/gpio-em.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __GPIO_EM_H__ -#define __GPIO_EM_H__ - -struct gpio_em_config { - unsigned int gpio_base; - unsigned int irq_base; - unsigned int number_of_pins; - const char *pctl_name; -}; - -#endif /* __GPIO_EM_H__ */ -- GitLab From 65194cb174b873448b208eb6e04ecb72237af76e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Jun 2015 16:45:57 +0200 Subject: [PATCH 0943/7006] gpio: rcar: Fine-grained Runtime PM support Currently gpio modules are runtime-resumed at probe time. This means the gpio module will be active all the time (except during system suspend, if not configured as a wake-up source). While an R-Car Gen2 gpio module retains pins configured for output at the requested level while put in standby mode, gpio registercannot be accessed while suspended. Unfortunately pm_runtime_get_sync() cannot be called from all contexts where gpio register access is needed. Hence move the Runtime PM handling from probe/remove time to gpio request/free time, which is probably the best we can do. On r8a7791/koelsch, gpio modules 0, 1, 3, and 4 are now suspended during normal use (gpio2 is used for LEDs and regulators, gpio5 for keys, gpio6 for SD-Card CD & WP, gpio7 for keys and regulators). Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/gpio/gpio-rcar.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 1e14a6c74ed13..4fc13ce9c60ad 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -251,17 +251,32 @@ static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip, static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset) { - return pinctrl_request_gpio(chip->base + offset); + struct gpio_rcar_priv *p = gpio_to_priv(chip); + int error; + + error = pm_runtime_get_sync(&p->pdev->dev); + if (error < 0) + return error; + + error = pinctrl_request_gpio(chip->base + offset); + if (error) + pm_runtime_put(&p->pdev->dev); + + return error; } static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset) { + struct gpio_rcar_priv *p = gpio_to_priv(chip); + pinctrl_free_gpio(chip->base + offset); /* Set the GPIO as an input to ensure that the next GPIO request won't * drive the GPIO pin as an output. */ gpio_rcar_config_general_input_output_mode(chip, offset, false); + + pm_runtime_put(&p->pdev->dev); } static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset) @@ -405,7 +420,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) } pm_runtime_enable(dev); - pm_runtime_get_sync(dev); io = platform_get_resource(pdev, IORESOURCE_MEM, 0); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); @@ -487,7 +501,6 @@ static int gpio_rcar_probe(struct platform_device *pdev) err1: gpiochip_remove(gpio_chip); err0: - pm_runtime_put(dev); pm_runtime_disable(dev); return ret; } @@ -498,7 +511,6 @@ static int gpio_rcar_remove(struct platform_device *pdev) gpiochip_remove(&p->gpio_chip); - pm_runtime_put(&pdev->dev); pm_runtime_disable(&pdev->dev); return 0; } -- GitLab From 049aaf9f7e30731ce030eef3e4fd255cf8b1ae02 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jun 2015 18:18:11 +0300 Subject: [PATCH 0944/7006] gpio: pcf857x: get rid of slock spinlock The spinlock 'slock' is used now to protect pcf857x_irq() from itself which is unnecessary (especially after switching to use threaded IRQs). Hence, remove it and use mutex to protect device data in IRQ handler. Cc: Geert Uytterhoeven Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-pcf857x.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-pcf857x.c b/drivers/gpio/gpio-pcf857x.c index 404f3c61ef9b1..1d4d9bc8b69db 100644 --- a/drivers/gpio/gpio-pcf857x.c +++ b/drivers/gpio/gpio-pcf857x.c @@ -88,7 +88,6 @@ struct pcf857x { struct gpio_chip chip; struct i2c_client *client; struct mutex lock; /* protect 'out' */ - spinlock_t slock; /* protect irq demux */ unsigned out; /* software latch */ unsigned status; /* current status */ unsigned int irq_parent; @@ -185,23 +184,21 @@ static void pcf857x_set(struct gpio_chip *chip, unsigned offset, int value) static irqreturn_t pcf857x_irq(int irq, void *data) { struct pcf857x *gpio = data; - unsigned long change, i, status, flags; + unsigned long change, i, status; status = gpio->read(gpio->client); - spin_lock_irqsave(&gpio->slock, flags); - /* * call the interrupt handler iff gpio is used as * interrupt source, just to avoid bad irqs */ - + mutex_lock(&gpio->lock); change = (gpio->status ^ status) & gpio->irq_enabled; - for_each_set_bit(i, &change, gpio->chip.ngpio) - handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); gpio->status = status; + mutex_unlock(&gpio->lock); - spin_unlock_irqrestore(&gpio->slock, flags); + for_each_set_bit(i, &change, gpio->chip.ngpio) + handle_nested_irq(irq_find_mapping(gpio->chip.irqdomain, i)); return IRQ_HANDLED; } @@ -293,7 +290,6 @@ static int pcf857x_probe(struct i2c_client *client, return -ENOMEM; mutex_init(&gpio->lock); - spin_lock_init(&gpio->slock); gpio->chip.base = pdata ? pdata->gpio_base : -1; gpio->chip.can_sleep = true; -- GitLab From be9ae230924083772ea74ea6958c846f79df5253 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:59:34 +0200 Subject: [PATCH 0945/7006] ASoC: fsi: Remove obsolete sh_fsi2 platform_device_id entry Since the removal of the r8a7740 legacy board code in commit 1fa59bda21c7fa36 ("ARM: shmobile: Remove legacy board code for Armadillo-800 EVA"), all former users of the "sh_fsi2" platform device name are only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Signed-off-by: Mark Brown --- sound/soc/sh/fsi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c index 142c066eaee2e..0215c78cbddf5 100644 --- a/sound/soc/sh/fsi.c +++ b/sound/soc/sh/fsi.c @@ -1911,7 +1911,6 @@ MODULE_DEVICE_TABLE(of, fsi_of_match); static const struct platform_device_id fsi_id_table[] = { { "sh_fsi", (kernel_ulong_t)&fsi1_core }, - { "sh_fsi2", (kernel_ulong_t)&fsi2_core }, {}, }; MODULE_DEVICE_TABLE(platform, fsi_id_table); -- GitLab From 601b9d9c7bd04f81a96896c9859cd37bd6a78d51 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 10:43:20 +0200 Subject: [PATCH 0946/7006] ASoC: sti-sas: fix x86 compilation issue. Fixes for compilation warnings and errors reported by Kbuild test robot for x86_64 and i386. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/codecs/sti-sas.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c index adc2c3472382c..160d61a66204b 100644 --- a/sound/soc/codecs/sti-sas.c +++ b/sound/soc/codecs/sti-sas.c @@ -227,8 +227,8 @@ static int stih416_dac_probe(struct snd_soc_dai *dai) dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); if (IS_ERR(dac->rst)) { dev_err(dai->codec->dev, - "%s: ERROR: DAC reset control not defined (%d)!\n", - __func__, (int)dac->rst); + "%s: ERROR: DAC reset control not defined !\n", + __func__); dac->rst = NULL; return -EFAULT; } @@ -547,6 +547,7 @@ static int sti_sas_driver_probe(struct platform_device *pdev) { struct device_node *pnode = pdev->dev.of_node; struct sti_sas_data *drvdata; + const struct of_device_id *of_id; /* Allocate device structure */ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data), @@ -555,12 +556,13 @@ static int sti_sas_driver_probe(struct platform_device *pdev) return -ENOMEM; /* Populate data structure depending on compatibility */ - if (!of_match_node(sti_sas_dev_match, pnode)->data) { + of_id = of_match_node(sti_sas_dev_match, pnode); + if (!of_id->data) { dev_err(&pdev->dev, "data associated to device is missing"); return -EINVAL; } - drvdata->dev_data = of_match_node(sti_sas_dev_match, pnode)->data; + drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data; /* Initialise device structure */ drvdata->dev = &pdev->dev; -- GitLab From 6066677cfd9d73734ab678b9d14013c860f0f732 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 9 Jul 2015 13:15:34 +1000 Subject: [PATCH 0947/7006] drm/fb: drop panic handling This really doesn't seem to have much chance of working anymore, esp for irq context, qxl at least tries to talk to the hw, and waits for irqs, and fails. with runtime pm and other stuff I think we should just bail on this for now. Signed-off-by: Dave Airlie Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index cac422916c7af..eaf652b389d93 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -429,24 +429,6 @@ static bool drm_fb_helper_force_kernel_mode(void) return error; } -static int drm_fb_helper_panic(struct notifier_block *n, unsigned long ununsed, - void *panic_str) -{ - /* - * It's a waste of time and effort to switch back to text console - * if the kernel should reboot before panic messages can be seen. - */ - if (panic_timeout < 0) - return 0; - - pr_err("panic occurred, switching back to text console\n"); - return drm_fb_helper_force_kernel_mode(); -} - -static struct notifier_block paniced = { - .notifier_call = drm_fb_helper_panic, -}; - static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) { struct drm_device *dev = fb_helper->dev; @@ -672,9 +654,6 @@ void drm_fb_helper_fini(struct drm_fb_helper *fb_helper) if (!list_empty(&fb_helper->kernel_fb_list)) { list_del(&fb_helper->kernel_fb_list); if (list_empty(&kernel_fb_helper_list)) { - pr_info("drm: unregistered panic notifier\n"); - atomic_notifier_chain_unregister(&panic_notifier_list, - &paniced); unregister_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); } } @@ -1109,12 +1088,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, dev_info(fb_helper->dev->dev, "fb%d: %s frame buffer device\n", info->node, info->fix.id); - /* Switch back to kernel console on panic */ - /* multi card linked list maybe */ if (list_empty(&kernel_fb_helper_list)) { - dev_info(fb_helper->dev->dev, "registered panic notifier\n"); - atomic_notifier_chain_register(&panic_notifier_list, - &paniced); register_sysrq_key('v', &sysrq_drm_fb_helper_restore_op); } -- GitLab From 16ccaf5bb5a52372bfebd3dfbb79dd810ad49c09 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 30 Jun 2015 11:29:57 +0300 Subject: [PATCH 0948/7006] pinctrl: sh-pfc: Accept standard function, pins and groups properties The "function", "pins" and "groups" pinmux and pinctrl properties have been standardized. Support them in addition to the custom "renesas,*" properties. New-style and old-style properties can't be mixed in DT. Signed-off-by: Laurent Pinchart Signed-off-by: Linus Walleij --- .../bindings/pinctrl/renesas,pfc-pinctrl.txt | 20 ++++----- drivers/pinctrl/sh-pfc/pinctrl.c | 42 +++++++++++++++---- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index 51cee44fc1406..e089142cfb141 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -58,12 +58,12 @@ are parsed through phandles and processed purely based on their content. Pin Configuration Node Properties: -- renesas,pins : An array of strings, each string containing the name of a pin. -- renesas,groups : An array of strings, each string containing the name of a pin +- pins : An array of strings, each string containing the name of a pin. +- groups : An array of strings, each string containing the name of a pin group. -- renesas,function: A string containing the name of the function to mux to the - pin group(s) specified by the renesas,groups property +- function: A string containing the name of the function to mux to the pin + group(s) specified by the groups property. Valid values for pin, group and function names can be found in the group and function arrays of the PFC data file corresponding to the SoC @@ -141,19 +141,19 @@ Example 3: KZM-A9-GT (SH-Mobile AG5) default pin state hog and pin control maps mmcif_pins: mmcif { mux { - renesas,groups = "mmc0_data8_0", "mmc0_ctrl_0"; - renesas,function = "mmc0"; + groups = "mmc0_data8_0", "mmc0_ctrl_0"; + function = "mmc0"; }; cfg { - renesas,groups = "mmc0_data8_0"; - renesas,pins = "PORT279"; + groups = "mmc0_data8_0"; + pins = "PORT279"; bias-pull-up; }; }; scifa4_pins: scifa4 { - renesas,groups = "scifa4_data", "scifa4_ctrl"; - renesas,function = "scifa4"; + groups = "scifa4_data", "scifa4_ctrl"; + function = "scifa4"; }; }; diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index ff678966008b7..6fe7459f0ccb8 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -40,6 +40,10 @@ struct sh_pfc_pinctrl { struct pinctrl_pin_desc *pins; struct sh_pfc_pin_config *configs; + + const char *func_prop_name; + const char *groups_prop_name; + const char *pins_prop_name; }; static int sh_pfc_get_groups_count(struct pinctrl_dev *pctldev) @@ -96,10 +100,13 @@ static int sh_pfc_map_add_config(struct pinctrl_map *map, return 0; } -static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, +static int sh_pfc_dt_subnode_to_map(struct pinctrl_dev *pctldev, + struct device_node *np, struct pinctrl_map **map, unsigned int *num_maps, unsigned int *index) { + struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev); + struct device *dev = pmx->pfc->dev; struct pinctrl_map *maps = *map; unsigned int nmaps = *num_maps; unsigned int idx = *index; @@ -113,10 +120,27 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, const char *pin; int ret; + /* Support both the old Renesas-specific properties and the new standard + * properties. Mixing old and new properties isn't allowed, neither + * inside a subnode nor across subnodes. + */ + if (!pmx->func_prop_name) { + if (of_find_property(np, "groups", NULL) || + of_find_property(np, "pins", NULL)) { + pmx->func_prop_name = "function"; + pmx->groups_prop_name = "groups"; + pmx->pins_prop_name = "pins"; + } else { + pmx->func_prop_name = "renesas,function"; + pmx->groups_prop_name = "renesas,groups"; + pmx->pins_prop_name = "renesas,pins"; + } + } + /* Parse the function and configuration properties. At least a function * or one configuration must be specified. */ - ret = of_property_read_string(np, "renesas,function", &function); + ret = of_property_read_string(np, pmx->func_prop_name, &function); if (ret < 0 && ret != -EINVAL) { dev_err(dev, "Invalid function in DT\n"); return ret; @@ -129,11 +153,12 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, if (!function && num_configs == 0) { dev_err(dev, "DT node must contain at least a function or config\n"); + ret = -ENODEV; goto done; } /* Count the number of pins and groups and reallocate mappings. */ - ret = of_property_count_strings(np, "renesas,pins"); + ret = of_property_count_strings(np, pmx->pins_prop_name); if (ret == -EINVAL) { num_pins = 0; } else if (ret < 0) { @@ -143,7 +168,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, num_pins = ret; } - ret = of_property_count_strings(np, "renesas,groups"); + ret = of_property_count_strings(np, pmx->groups_prop_name); if (ret == -EINVAL) { num_groups = 0; } else if (ret < 0) { @@ -174,7 +199,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, *num_maps = nmaps; /* Iterate over pins and groups and create the mappings. */ - of_property_for_each_string(np, "renesas,groups", prop, group) { + of_property_for_each_string(np, pmx->groups_prop_name, prop, group) { if (function) { maps[idx].type = PIN_MAP_TYPE_MUX_GROUP; maps[idx].data.mux.group = group; @@ -198,7 +223,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np, goto done; } - of_property_for_each_string(np, "renesas,pins", prop, pin) { + of_property_for_each_string(np, pmx->pins_prop_name, prop, pin) { ret = sh_pfc_map_add_config(&maps[idx], pin, PIN_MAP_TYPE_CONFIGS_PIN, configs, num_configs); @@ -246,7 +271,7 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, index = 0; for_each_child_of_node(np, child) { - ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps, + ret = sh_pfc_dt_subnode_to_map(pctldev, child, map, num_maps, &index); if (ret < 0) goto done; @@ -254,7 +279,8 @@ static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev, /* If no mapping has been found in child nodes try the config node. */ if (*num_maps == 0) { - ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index); + ret = sh_pfc_dt_subnode_to_map(pctldev, np, map, num_maps, + &index); if (ret < 0) goto done; } -- GitLab From c7977ec4a33633c8e8d9267dd014356cf857351c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 25 Jun 2015 11:39:53 +0200 Subject: [PATCH 0949/7006] pinctrl: sh-pfc: Convert to platform_get_*() If the pin function controller (which can be a GPIO controller) is instantiated before the interrupt controllers, due to the ordering in the DTS, the irq domains for the interrupt controllers referenced by its "interrupts-extended" property cannot be found yet: irq: no irq domain found for /interrupt-controller@e61c0000 ! As the sh-pfc driver accesses the platform device's resources directly, it cannot find the (optional) IRQ resources, and thinks no interrupts are available. This may lead to failures later, when GPIOs are used as interupts: gpio-keys keyboard: Unable to claim irq 0; error -22 gpio-keys: probe of keyboard failed with error -22 To fix this, add support for deferred probing to sh-pfc, by converting the driver from direct platform device resource access to using the platform_get_resource() and platform_get_irq() helpers. Note that while this fixes the root cause worked around by commit e4ba0a9bddff3ba5 ("ARM: shmobile: r8a73a4: Move pfc node to work around probe ordering bug"), I strongly recommend against reverting the workaround now, as this would lead to lots of probe deferrals in drivers relying on pinctrl. This may be reconsidered once the DT code starts taking into account phandle dependencies during device instantation. Signed-off-by: Geert Uytterhoeven Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/core.c | 46 ++++++++++++++++------------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 865d235612c52..9796238959047 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -29,24 +29,25 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, struct platform_device *pdev) { - unsigned int num_windows = 0; - unsigned int num_irqs = 0; + unsigned int num_windows, num_irqs; struct sh_pfc_window *windows; unsigned int *irqs = NULL; struct resource *res; unsigned int i; + int irq; /* Count the MEM and IRQ resources. */ - for (i = 0; i < pdev->num_resources; ++i) { - switch (resource_type(&pdev->resource[i])) { - case IORESOURCE_MEM: - num_windows++; + for (num_windows = 0;; num_windows++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, num_windows); + if (!res) break; - - case IORESOURCE_IRQ: - num_irqs++; + } + for (num_irqs = 0;; num_irqs++) { + irq = platform_get_irq(pdev, num_irqs); + if (irq == -EPROBE_DEFER) + return irq; + if (irq < 0) break; - } } if (num_windows == 0) @@ -72,22 +73,17 @@ static int sh_pfc_map_resources(struct sh_pfc *pfc, } /* Fill them. */ - for (i = 0, res = pdev->resource; i < pdev->num_resources; i++, res++) { - switch (resource_type(res)) { - case IORESOURCE_MEM: - windows->phys = res->start; - windows->size = resource_size(res); - windows->virt = devm_ioremap_resource(pfc->dev, res); - if (IS_ERR(windows->virt)) - return -ENOMEM; - windows++; - break; - - case IORESOURCE_IRQ: - *irqs++ = res->start; - break; - } + for (i = 0; i < num_windows; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + windows->phys = res->start; + windows->size = resource_size(res); + windows->virt = devm_ioremap_resource(pfc->dev, res); + if (IS_ERR(windows->virt)) + return -ENOMEM; + windows++; } + for (i = 0; i < num_irqs; i++) + *irqs++ = platform_get_irq(pdev, i); return 0; } -- GitLab From 9f21c67da6a62aa082a1f20feb983ab5ed89a915 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:52 +0200 Subject: [PATCH 0950/7006] pinctrl: sh-pfc: sh73a0: Remove obsolete multi-platform check Since the removal of the sh73a0 legacy SoC code in commit 9a9863987bf7307f ("ARM: shmobile: Remove legacy SoC code for SH-Mobile AG5"), sh73a0 is only supported in generic ARM multi-platform builds. Hence CONFIG_ARCH_MULTIPLATFORM is always set, and the check can be removed. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-sh73a0.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c index d2efbfb776ac5..097526576f881 100644 --- a/drivers/pinctrl/sh-pfc/pfc-sh73a0.c +++ b/drivers/pinctrl/sh-pfc/pfc-sh73a0.c @@ -26,10 +26,6 @@ #include #include -#ifndef CONFIG_ARCH_MULTIPLATFORM -#include -#endif - #include "core.h" #include "sh_pfc.h" -- GitLab From 39ad6ff12cd54607b64642562ad850bb09176734 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:53 +0200 Subject: [PATCH 0951/7006] pinctrl: sh-pfc: Remove obsolete sh73a0 platform_device_id entry Since the removal of the sh73a0 legacy SoC code in commit 9a9863987bf7307f ("ARM: shmobile: Remove legacy SoC code for SH-Mobile AG5"), sh73a0 is only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 9796238959047..23b2b3be26fda 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -605,9 +605,6 @@ static const struct platform_device_id sh_pfc_id_table[] = { #ifdef CONFIG_PINCTRL_PFC_SH7269 { "pfc-sh7269", (kernel_ulong_t)&sh7269_pinmux_info }, #endif -#ifdef CONFIG_PINCTRL_PFC_SH73A0 - { "pfc-sh73a0", (kernel_ulong_t)&sh73a0_pinmux_info }, -#endif #ifdef CONFIG_PINCTRL_PFC_SH7720 { "pfc-sh7720", (kernel_ulong_t)&sh7720_pinmux_info }, #endif -- GitLab From d009fa3b2b28b28f58920aaa76fa0abeb573828c Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:54 +0200 Subject: [PATCH 0952/7006] pinctrl: sh-pfc: r8a7740: Remove obsolete multi-platform check Since the removal of the r8a7740 legacy SoC code in commit 44d88c754e57a6d9 ("ARM: shmobile: Remove legacy SoC code for R-Mobile A1"), r8a7740 is only supported in generic ARM multi-platform builds. Hence CONFIG_ARCH_MULTIPLATFORM is always set, and the check can be removed. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7740.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c index d0bb1459783a1..82ef1862dd1ba 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7740.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7740.c @@ -22,10 +22,6 @@ #include #include -#ifndef CONFIG_ARCH_MULTIPLATFORM -#include -#endif - #include "core.h" #include "sh_pfc.h" -- GitLab From 03c42c3e5216e2777f8ae819d6a076e94dcdfbdd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 14 Jul 2015 13:56:55 +0200 Subject: [PATCH 0953/7006] pinctrl: sh-pfc: Remove obsolete r8a7740 platform_device_id entry Since the removal of the r8a7740 legacy SoC code in commit 44d88c754e57a6d9 ("ARM: shmobile: Remove legacy SoC code for R-Mobile A1"), r8a7740 is only supported in generic DT-only ARM multi-platform builds. The driver doesn't need to match platform devices by name anymore, hence remove the corresponding platform_device_id entry. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/core.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c index 23b2b3be26fda..fb9c448052343 100644 --- a/drivers/pinctrl/sh-pfc/core.c +++ b/drivers/pinctrl/sh-pfc/core.c @@ -587,9 +587,6 @@ static int sh_pfc_remove(struct platform_device *pdev) } static const struct platform_device_id sh_pfc_id_table[] = { -#ifdef CONFIG_PINCTRL_PFC_R8A7740 - { "pfc-r8a7740", (kernel_ulong_t)&r8a7740_pinmux_info }, -#endif #ifdef CONFIG_PINCTRL_PFC_R8A7778 { "pfc-r8a7778", (kernel_ulong_t)&r8a7778_pinmux_info }, #endif -- GitLab From 5b76e79c772648991e700f004205e9ac861c77c0 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jun 2015 20:30:50 +0300 Subject: [PATCH 0954/7006] gpiolib: irqchip: prevent driver unloading if gpio is used as irq only Now nothing prevents GPIO driver from being unloaded if its gpios were requested as GPIO IRQs only (without calling gpio_request()). Hence, add calls of try_module_get()/module_put() into gpiochip_irq_reqres/relres() to track such scenario properly. Cc: Johan Hovold Signed-off-by: Grygorii Strashko Reviewed-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b1b08b3fa626a..debd7c56187de 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -522,10 +522,14 @@ static int gpiochip_irq_reqres(struct irq_data *d) { struct gpio_chip *chip = irq_data_get_irq_chip_data(d); + if (!try_module_get(chip->owner)) + return -ENODEV; + if (gpiochip_lock_as_irq(chip, d->hwirq)) { chip_err(chip, "unable to lock HW IRQ %lu for IRQ\n", d->hwirq); + module_put(chip->owner); return -EINVAL; } return 0; @@ -536,6 +540,7 @@ static void gpiochip_irq_relres(struct irq_data *d) struct gpio_chip *chip = irq_data_get_irq_chip_data(d); gpiochip_unlock_as_irq(chip, d->hwirq); + module_put(chip->owner); } static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset) -- GitLab From 3726960edc63bb1e09678841df44b44feee20305 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Thu, 25 Jun 2015 20:30:51 +0300 Subject: [PATCH 0955/7006] gpiolib: assign chip owner to dev->driver->owner if not set Assign GPIO chip owner field to chip->dev->driver->owner if it was not configured by GPIO driver. Cc: Johan Hovold Signed-off-by: Grygorii Strashko Acked-by: Alexandre Courbot Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index debd7c56187de..d11f325eeea3f 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -287,6 +287,9 @@ int gpiochip_add(struct gpio_chip *chip) INIT_LIST_HEAD(&chip->pin_ranges); #endif + if (!chip->owner && chip->dev && chip->dev->driver) + chip->owner = chip->dev->driver->owner; + of_gpiochip_add(chip); acpi_gpiochip_add(chip); -- GitLab From 54442658d8e83b0589731620bd958cc8b2857167 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Sat, 4 Jul 2015 16:34:32 -0400 Subject: [PATCH 0956/7006] gpio: 74xx: Fix build warning about void to integer cast This fixes the build warning , warning: cast from pointer to integer of different size when building this file on a x86 allmodconfig configuration. In order for me to fix this build warning I changed the cast in the function mmio_74xx_gpio_probe from casting the variable data of the stucture pointer of_id to uintptr_t rather then unsigned when assigning to the variable flag of the structure pointer priv of the structure type mmio_74xx_gpio_priv. Signed-off-by: Nicholas Krause Signed-off-by: Linus Walleij --- drivers/gpio/gpio-74xx-mmio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-74xx-mmio.c b/drivers/gpio/gpio-74xx-mmio.c index 0763655cca6cc..6ed7c0fb3378e 100644 --- a/drivers/gpio/gpio-74xx-mmio.c +++ b/drivers/gpio/gpio-74xx-mmio.c @@ -129,7 +129,7 @@ static int mmio_74xx_gpio_probe(struct platform_device *pdev) if (IS_ERR(dat)) return PTR_ERR(dat); - priv->flags = (unsigned)of_id->data; + priv->flags = (uintptr_t) of_id->data; err = bgpio_init(&priv->bgc, &pdev->dev, DIV_ROUND_UP(MMIO_74XX_BIT_CNT(priv->flags), 8), -- GitLab From 5efe58c44312a7f8a1f3ec77c2b88f6d22b74880 Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Thu, 16 Jul 2015 10:01:33 +0800 Subject: [PATCH 0957/7006] ASoC: rt298: remove meanless pr_info This line doesn't include any information. So, remove it. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rt298.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/rt298.c b/sound/soc/codecs/rt298.c index 7c4bcb65ef2c8..6ff68a355da16 100644 --- a/sound/soc/codecs/rt298.c +++ b/sound/soc/codecs/rt298.c @@ -1144,8 +1144,6 @@ static int rt298_i2c_probe(struct i2c_client *i2c, const struct acpi_device_id *acpiid; int i, ret; - pr_info("%s\n", __func__); - rt298 = devm_kzalloc(&i2c->dev, sizeof(*rt298), GFP_KERNEL); if (NULL == rt298) -- GitLab From b14c917409f47dbfdff93e69effd6740f6a809f7 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 16 Jul 2015 13:42:33 +0800 Subject: [PATCH 0958/7006] ASoC: rt5645: Update dapm pins when the card is not instantiated yet This makes sure the dapm state is consistent when the card is instantiated. However, if the card is not instantiated yet, we still update the registers manually in the "jack in" case, so that we can immediately report if a mic is present or not. Disabling "Mic Det Power" after detection, and on jack out, can wait until the card gets instantiated. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 36 +++++++++++------------------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 8693a25830d3d..33d1aff38d5ff 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2805,12 +2805,11 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (jack_insert) { regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); - if (codec->component.card->instantiated) { - /* for jack type detect */ - snd_soc_dapm_force_enable_pin(dapm, "LDO2"); - snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } else { + /* for jack type detect */ + snd_soc_dapm_force_enable_pin(dapm, "LDO2"); + snd_soc_dapm_force_enable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); + if (!dapm->card->instantiated) { /* Power up necessary bits for JD if dapm is not ready yet */ regmap_update_bits(rt5645->regmap, RT5645_PWR_ANLG1, @@ -2841,12 +2840,8 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) rt5645_enable_push_button_irq(codec, true); } } else { - if (codec->component.card->instantiated) { - snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } else - regmap_update_bits(rt5645->regmap, - RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); rt5645->jack_type = SND_JACK_HEADPHONE; } @@ -2855,19 +2850,10 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); else { - if (codec->component.card->instantiated) { - if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin(dapm, "LDO2"); - snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } else { - if (rt5645->pdata.jd_mode == 0) - regmap_update_bits(rt5645->regmap, - RT5645_PWR_MIXER, - RT5645_PWR_LDO2, 0); - regmap_update_bits(rt5645->regmap, - RT5645_PWR_VOL, RT5645_PWR_MIC_DET, 0); - } + if (rt5645->pdata.jd_mode == 0) + snd_soc_dapm_disable_pin(dapm, "LDO2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } } -- GitLab From a4e3c5fa955ce0934774f3f3684377dbf2c20eca Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Thu, 16 Jul 2015 13:42:34 +0800 Subject: [PATCH 0959/7006] ASoC: rt5645: Simplify rt5645_enable_push_button_irq LDO2/Mic Det Power pins are already enabled/disabled in rt5645_jack_detect (the jack out code path previously did not disable those if button function is enabled: modify it to make it so). Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 33d1aff38d5ff..11a2bfc4a0599 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2766,13 +2766,9 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); if (enable) { - snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC L power"); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "ADC R power"); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "LDO2"); - snd_soc_dapm_force_enable_pin_unlocked(dapm, "Mic Det Power"); - snd_soc_dapm_sync_unlocked(dapm); - snd_soc_dapm_mutex_unlock(dapm); + snd_soc_dapm_force_enable_pin(dapm, "ADC L power"); + snd_soc_dapm_force_enable_pin(dapm, "ADC R power"); + snd_soc_dapm_sync(dapm); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x8); @@ -2785,14 +2781,9 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, snd_soc_update_bits(codec, RT5650_4BTN_IL_CMD2, 0x8000, 0x0); snd_soc_update_bits(codec, RT5645_INT_IRQ_ST, 0x8, 0x0); - snd_soc_dapm_mutex_lock(dapm); - snd_soc_dapm_disable_pin_unlocked(dapm, "ADC L power"); - snd_soc_dapm_disable_pin_unlocked(dapm, "ADC R power"); - if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin_unlocked(dapm, "LDO2"); - snd_soc_dapm_disable_pin_unlocked(dapm, "Mic Det Power"); - snd_soc_dapm_sync_unlocked(dapm); - snd_soc_dapm_mutex_unlock(dapm); + snd_soc_dapm_disable_pin(dapm, "ADC L power"); + snd_soc_dapm_disable_pin(dapm, "ADC R power"); + snd_soc_dapm_sync(dapm); } } @@ -2847,14 +2838,14 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } else { /* jack out */ rt5645->jack_type = 0; + if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); - else { - if (rt5645->pdata.jd_mode == 0) - snd_soc_dapm_disable_pin(dapm, "LDO2"); - snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); - snd_soc_dapm_sync(dapm); - } + + if (rt5645->pdata.jd_mode == 0) + snd_soc_dapm_disable_pin(dapm, "LDO2"); + snd_soc_dapm_disable_pin(dapm, "Mic Det Power"); + snd_soc_dapm_sync(dapm); } return rt5645->jack_type; -- GitLab From 6417049f662d85a6f3a6b7cb8bc98bae3edae0a4 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 6 Jul 2015 18:11:50 +0300 Subject: [PATCH 0960/7006] pinctrl: single: dra7: remove PCS_QUIRK_SHARED_IRQ On DRA7 there is one pinctrl domain (dra7_pmx_core) and PRCM wake-up IRQ is not shared, so remove quirk. Cc: Nishanth Menon Fixes: 31320beaa3d3 ('pinctrl: single: Add DRA7 pinctrl compatibility') Signed-off-by: Grygorii Strashko Acked-by: Tero Kristo Acked-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-single.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index b2de09d3b1a0c..1cd085d921474 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1982,7 +1982,6 @@ static const struct pcs_soc_data pinctrl_single_omap_wkup = { }; static const struct pcs_soc_data pinctrl_single_dra7 = { - .flags = PCS_QUIRK_SHARED_IRQ, .irq_enable_mask = (1 << 24), /* WAKEUPENABLE */ .irq_status_mask = (1 << 25), /* WAKEUPEVENT */ }; -- GitLab From b6c52c634506d52b3a2dc18503980d717e478739 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Wed, 8 Jul 2015 15:41:42 +0800 Subject: [PATCH 0961/7006] dmaengine: ioatdma: Ignore IOAT devices under hotplug-capable PCI host bridge The dmaengine core assumes that async DMA devices will only be removed when they not used anymore, or it assumes dma_async_device_unregister() will only be called by dma driver exit routines. But this assumption is not true for the IOAT driver, which calls dma_async_device_unregister() from ioat_remove(). So current IOAT driver doesn't support device hot-removal because it may cause system crash to hot-remove an inuse IOAT device. To support CPU socket hot-removal, all PCI devices, including IOAT devices embedded in the socket, will be hot-removed. The idea solution is to enhance the dmaengine core and IOAT driver to support hot-removal, but that's too hard. This patch implements a hack to disable IOAT devices under hotplug-capable CPU socket so it won't break socket hot-removal. Signed-off-by: Jiang Liu Signed-off-by: Vinod Koul --- drivers/dma/ioat/pci.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c index 76f0dc688a199..3b8c9b03f4b38 100644 --- a/drivers/dma/ioat/pci.c +++ b/drivers/dma/ioat/pci.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "dma.h" #include "dma_v2.h" #include "registers.h" @@ -148,6 +149,34 @@ alloc_ioatdma(struct pci_dev *pdev, void __iomem *iobase) return d; } +/* + * The dmaengine core assumes that async DMA devices will only be removed + * when they not used anymore, or it assumes dma_async_device_unregister() + * will only be called by dma driver exit routines. But this assumption is + * not true for the IOAT driver, which calls dma_async_device_unregister() + * from ioat_remove(). So current IOAT driver doesn't support device + * hot-removal because it may cause system crash to hot-remove inuse IOAT + * devices. + * + * This is a hack to disable IOAT devices under ejectable PCI host bridge + * so it won't break PCI host bridge hot-removal. + */ +static bool ioat_pci_has_ejectable_acpi_ancestor(struct pci_dev *pdev) +{ +#ifdef CONFIG_ACPI + struct pci_bus *bus = pdev->bus; + struct acpi_device *adev; + + while (bus->parent) + bus = bus->parent; + for (adev = ACPI_COMPANION(bus->bridge); adev; adev = adev->parent) + if (adev->flags.ejectable) + return true; +#endif + + return false; +} + static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { void __iomem * const *iomap; @@ -155,6 +184,11 @@ static int ioat_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) struct ioatdma_device *device; int err; + if (ioat_pci_has_ejectable_acpi_ancestor(pdev)) { + dev_dbg(&pdev->dev, "ignore ejectable IOAT device.\n"); + return -ENODEV; + } + err = pcim_enable_device(pdev); if (err) return err; -- GitLab From 03734485b71129a954861f298825a490bcade986 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 9 Jul 2015 13:25:37 +0300 Subject: [PATCH 0962/7006] dmaengine: hsu: remove excessive lock All hardware accesses are done under virtual channel lock. That's why specific channel lock is excessive and can be removed safely. This has been tested on Intel Medfield and Merrifield. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/hsu/hsu.c | 39 ++++----------------------------------- drivers/dma/hsu/hsu.h | 1 - 2 files changed, 4 insertions(+), 36 deletions(-) diff --git a/drivers/dma/hsu/hsu.c b/drivers/dma/hsu/hsu.c index f42f71e37e737..7669c7dd1e344 100644 --- a/drivers/dma/hsu/hsu.c +++ b/drivers/dma/hsu/hsu.c @@ -99,21 +99,13 @@ static void hsu_dma_chan_start(struct hsu_dma_chan *hsuc) static void hsu_dma_stop_channel(struct hsu_dma_chan *hsuc) { - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); hsu_chan_disable(hsuc); hsu_chan_writel(hsuc, HSU_CH_DCR, 0); - spin_unlock_irqrestore(&hsuc->lock, flags); } static void hsu_dma_start_channel(struct hsu_dma_chan *hsuc) { - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); hsu_dma_chan_start(hsuc); - spin_unlock_irqrestore(&hsuc->lock, flags); } static void hsu_dma_start_transfer(struct hsu_dma_chan *hsuc) @@ -139,9 +131,9 @@ static u32 hsu_dma_chan_get_sr(struct hsu_dma_chan *hsuc) unsigned long flags; u32 sr; - spin_lock_irqsave(&hsuc->lock, flags); + spin_lock_irqsave(&hsuc->vchan.lock, flags); sr = hsu_chan_readl(hsuc, HSU_CH_SR); - spin_unlock_irqrestore(&hsuc->lock, flags); + spin_unlock_irqrestore(&hsuc->vchan.lock, flags); return sr; } @@ -273,14 +265,11 @@ static size_t hsu_dma_active_desc_size(struct hsu_dma_chan *hsuc) struct hsu_dma_desc *desc = hsuc->desc; size_t bytes = hsu_dma_desc_size(desc); int i; - unsigned long flags; - spin_lock_irqsave(&hsuc->lock, flags); i = desc->active % HSU_DMA_CHAN_NR_DESC; do { bytes += hsu_chan_readl(hsuc, HSU_CH_DxTSR(i)); } while (--i >= 0); - spin_unlock_irqrestore(&hsuc->lock, flags); return bytes; } @@ -327,24 +316,6 @@ static int hsu_dma_slave_config(struct dma_chan *chan, return 0; } -static void hsu_dma_chan_deactivate(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); - hsu_chan_disable(hsuc); - spin_unlock_irqrestore(&hsuc->lock, flags); -} - -static void hsu_dma_chan_activate(struct hsu_dma_chan *hsuc) -{ - unsigned long flags; - - spin_lock_irqsave(&hsuc->lock, flags); - hsu_chan_enable(hsuc); - spin_unlock_irqrestore(&hsuc->lock, flags); -} - static int hsu_dma_pause(struct dma_chan *chan) { struct hsu_dma_chan *hsuc = to_hsu_dma_chan(chan); @@ -352,7 +323,7 @@ static int hsu_dma_pause(struct dma_chan *chan) spin_lock_irqsave(&hsuc->vchan.lock, flags); if (hsuc->desc && hsuc->desc->status == DMA_IN_PROGRESS) { - hsu_dma_chan_deactivate(hsuc); + hsu_chan_disable(hsuc); hsuc->desc->status = DMA_PAUSED; } spin_unlock_irqrestore(&hsuc->vchan.lock, flags); @@ -368,7 +339,7 @@ static int hsu_dma_resume(struct dma_chan *chan) spin_lock_irqsave(&hsuc->vchan.lock, flags); if (hsuc->desc && hsuc->desc->status == DMA_PAUSED) { hsuc->desc->status = DMA_IN_PROGRESS; - hsu_dma_chan_activate(hsuc); + hsu_chan_enable(hsuc); } spin_unlock_irqrestore(&hsuc->vchan.lock, flags); @@ -441,8 +412,6 @@ int hsu_dma_probe(struct hsu_dma_chip *chip) hsuc->direction = (i & 0x1) ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; hsuc->reg = addr + i * HSU_DMA_CHAN_LENGTH; - - spin_lock_init(&hsuc->lock); } dma_cap_set(DMA_SLAVE, hsu->dma.cap_mask); diff --git a/drivers/dma/hsu/hsu.h b/drivers/dma/hsu/hsu.h index 0275233cf550e..eeb9fff669672 100644 --- a/drivers/dma/hsu/hsu.h +++ b/drivers/dma/hsu/hsu.h @@ -78,7 +78,6 @@ struct hsu_dma_chan { struct virt_dma_chan vchan; void __iomem *reg; - spinlock_t lock; /* hardware configuration */ enum dma_transfer_direction direction; -- GitLab From d7fdb356902a13bb92229722d88a836523a3c6e3 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:39:52 +0000 Subject: [PATCH 0963/7006] dmaengine: ipu: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Dan Williams Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 2e284a4438bca..8d36f07b58017 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -382,11 +382,9 @@ int __init ipu_irq_attach_irq(struct ipu *ipu, struct platform_device *dev) #endif } - irq_set_handler_data(ipu->irq_fn, ipu); - irq_set_chained_handler(ipu->irq_fn, ipu_irq_fn); + irq_set_chained_handler_and_data(ipu->irq_fn, ipu_irq_fn, ipu); - irq_set_handler_data(ipu->irq_err, ipu); - irq_set_chained_handler(ipu->irq_err, ipu_irq_err); + irq_set_chained_handler_and_data(ipu->irq_err, ipu_irq_err, ipu); ipu->irq_base = irq_base; @@ -399,11 +397,9 @@ void ipu_irq_detach_irq(struct ipu *ipu, struct platform_device *dev) irq_base = ipu->irq_base; - irq_set_chained_handler(ipu->irq_fn, NULL); - irq_set_handler_data(ipu->irq_fn, NULL); + irq_set_chained_handler_and_data(ipu->irq_fn, NULL, NULL); - irq_set_chained_handler(ipu->irq_err, NULL); - irq_set_handler_data(ipu->irq_err, NULL); + irq_set_chained_handler_and_data(ipu->irq_err, NULL, NULL); for (irq = irq_base; irq < irq_base + CONFIG_MX3_IPU_IRQS; irq++) { #ifdef CONFIG_ARM -- GitLab From 4d9efdfce73c8f0c9e39d118833e4776719a8d40 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:39:54 +0000 Subject: [PATCH 0964/7006] dmaengine: ipu: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. This is also a preparation for the removal of the 'irq' argument from interrupt flow handlers. Signed-off-by: Jiang Liu Cc: Dan Williams Cc: Vinod Koul Cc: dmaengine@vger.kernel.org Signed-off-by: Thomas Gleixner Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 2 +- drivers/gpu/ipu-v3/ipu-common.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 8d36f07b58017..4357063980e19 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -268,7 +268,7 @@ int ipu_irq_unmap(unsigned int source) /* Chained IRQ handler for IPU error interrupt */ static void ipu_irq_err(unsigned int irq, struct irq_desc *desc) { - struct ipu *ipu = irq_get_handler_data(irq); + struct ipu *ipu = irq_desc_get_handler_data(desc); u32 status; int i, line; diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c index 6d2f39d36e445..5521787990628 100644 --- a/drivers/gpu/ipu-v3/ipu-common.c +++ b/drivers/gpu/ipu-v3/ipu-common.c @@ -915,8 +915,8 @@ static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs) static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; - struct irq_chip *chip = irq_get_chip(irq); chained_irq_enter(chip, desc); @@ -928,8 +928,8 @@ static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc) static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) { struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_chip(desc); const int int_reg[] = { 4, 5, 8, 9}; - struct irq_chip *chip = irq_get_chip(irq); chained_irq_enter(chip, desc); -- GitLab From e3f3aaac06657e6fc834e217ae450f51a6e0968c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:27:30 +0900 Subject: [PATCH 0965/7006] pinctrl: sirf: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 9384e0aa39960..d6e80fe1c7f79 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -4621,7 +4621,6 @@ failed: static struct platform_driver atlas7_gpio_driver = { .driver = { .name = "atlas7-gpio", - .owner = THIS_MODULE, .of_match_table = atlas7_gpio_ids, }, .probe = atlas7_gpio_probe, -- GitLab From 7f37a3d80b6d687717685cb7156ef7c9acbd2964 Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 5 May 2015 22:06:07 +0800 Subject: [PATCH 0966/7006] Documentation: dma: Add documentation for ZTE DMA This patch adds documentation for the ZTE ZX296702 SoC DMA device DTS binding. Signed-off-by: Jun Nie Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/zxdma.txt | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/zxdma.txt diff --git a/Documentation/devicetree/bindings/dma/zxdma.txt b/Documentation/devicetree/bindings/dma/zxdma.txt new file mode 100644 index 0000000000000..3207ceb04d0bd --- /dev/null +++ b/Documentation/devicetree/bindings/dma/zxdma.txt @@ -0,0 +1,38 @@ +* ZTE ZX296702 DMA controller + +Required properties: +- compatible: Should be "zte,zx296702-dma" +- reg: Should contain DMA registers location and length. +- interrupts: Should contain one interrupt shared by all channel +- #dma-cells: see dma.txt, should be 1, para number +- dma-channels: physical channels supported +- dma-requests: virtual channels supported, each virtual channel + have specific request line +- clocks: clock required + +Example: + +Controller: + dma: dma-controller@0x09c00000{ + compatible = "zte,zx296702-dma"; + reg = <0x09c00000 0x1000>; + clocks = <&topclk ZX296702_DMA_ACLK>; + interrupts = ; + #dma-cells = <1>; + dma-channels = <24>; + dma-requests = <24>; + }; + +Client: +Use specific request line passing from dmax +For example, spdif0 tx channel request line is 4 + spdif0: spdif0@0b004000 { + #sound-dai-cells = <0>; + compatible = "zte,zx296702-spdif"; + reg = <0x0b004000 0x1000>; + clocks = <&lsp0clk ZX296702_SPDIF0_DIV>; + clock-names = "tx"; + interrupts = ; + dmas = <&dma 4>; + dma-names = "tx"; + } -- GitLab From e3fa9841d309ae7992b658eba0f973543b97ed1f Mon Sep 17 00:00:00 2001 From: Jun Nie Date: Tue, 5 May 2015 22:06:08 +0800 Subject: [PATCH 0967/7006] dmaengine: zxdma: Support ZTE ZX296702 dma Add ZTE ZX296702 dma controller support. Only device tree probe is support currently. Signed-off-by: Jun Nie Reviewed-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 7 + drivers/dma/Makefile | 1 + drivers/dma/zx296702_dma.c | 870 +++++++++++++++++++++++++++++++++++++ 3 files changed, 878 insertions(+) create mode 100644 drivers/dma/zx296702_dma.c diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 88d474b780766..bcbfc6b3b71b5 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -458,6 +458,13 @@ config XGENE_DMA select ASYNC_TX_ENABLE_CHANNEL_SWITCH help Enable support for the APM X-Gene SoC DMA engine. +config ZX_DMA + tristate "ZTE ZX296702 DMA support" + depends on ARCH_ZX + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support the DMA engine for ZTE ZX296702 platform devices. config DMA_ENGINE bool diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 6a4d6f2827da4..c4c1ccb001384 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -56,3 +56,4 @@ obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o +obj-$(CONFIG_ZX_DMA) += zx296702_dma.o diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c new file mode 100644 index 0000000000000..c99f0d1ac88a8 --- /dev/null +++ b/drivers/dma/zx296702_dma.c @@ -0,0 +1,870 @@ +/* + * Copyright 2015 Linaro. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "virt-dma.h" + +#define DRIVER_NAME "zx-dma" +#define DMA_ALIGN 4 +#define DMA_MAX_SIZE (0x10000 - PAGE_SIZE) +#define LLI_BLOCK_SIZE (4 * PAGE_SIZE) + +#define REG_ZX_SRC_ADDR 0x00 +#define REG_ZX_DST_ADDR 0x04 +#define REG_ZX_TX_X_COUNT 0x08 +#define REG_ZX_TX_ZY_COUNT 0x0c +#define REG_ZX_SRC_ZY_STEP 0x10 +#define REG_ZX_DST_ZY_STEP 0x14 +#define REG_ZX_LLI_ADDR 0x1c +#define REG_ZX_CTRL 0x20 +#define REG_ZX_TC_IRQ 0x800 +#define REG_ZX_SRC_ERR_IRQ 0x804 +#define REG_ZX_DST_ERR_IRQ 0x808 +#define REG_ZX_CFG_ERR_IRQ 0x80c +#define REG_ZX_TC_IRQ_RAW 0x810 +#define REG_ZX_SRC_ERR_IRQ_RAW 0x814 +#define REG_ZX_DST_ERR_IRQ_RAW 0x818 +#define REG_ZX_CFG_ERR_IRQ_RAW 0x81c +#define REG_ZX_STATUS 0x820 +#define REG_ZX_DMA_GRP_PRIO 0x824 +#define REG_ZX_DMA_ARB 0x828 + +#define ZX_FORCE_CLOSE BIT(31) +#define ZX_DST_BURST_WIDTH(x) (((x) & 0x7) << 13) +#define ZX_MAX_BURST_LEN 16 +#define ZX_SRC_BURST_LEN(x) (((x) & 0xf) << 9) +#define ZX_SRC_BURST_WIDTH(x) (((x) & 0x7) << 6) +#define ZX_IRQ_ENABLE_ALL (3 << 4) +#define ZX_DST_FIFO_MODE BIT(3) +#define ZX_SRC_FIFO_MODE BIT(2) +#define ZX_SOFT_REQ BIT(1) +#define ZX_CH_ENABLE BIT(0) + +#define ZX_DMA_BUSWIDTHS \ + (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) + +enum zx_dma_burst_width { + ZX_DMA_WIDTH_8BIT = 0, + ZX_DMA_WIDTH_16BIT = 1, + ZX_DMA_WIDTH_32BIT = 2, + ZX_DMA_WIDTH_64BIT = 3, +}; + +struct zx_desc_hw { + u32 saddr; + u32 daddr; + u32 src_x; + u32 src_zy; + u32 src_zy_step; + u32 dst_zy_step; + u32 reserved1; + u32 lli; + u32 ctr; + u32 reserved[7]; /* pack as hardware registers region size */ +} __aligned(32); + +struct zx_dma_desc_sw { + struct virt_dma_desc vd; + dma_addr_t desc_hw_lli; + size_t desc_num; + size_t size; + struct zx_desc_hw *desc_hw; +}; + +struct zx_dma_phy; + +struct zx_dma_chan { + struct dma_slave_config slave_cfg; + int id; /* Request phy chan id */ + u32 ccfg; + struct virt_dma_chan vc; + struct zx_dma_phy *phy; + struct list_head node; + dma_addr_t dev_addr; + enum dma_status status; +}; + +struct zx_dma_phy { + u32 idx; + void __iomem *base; + struct zx_dma_chan *vchan; + struct zx_dma_desc_sw *ds_run; + struct zx_dma_desc_sw *ds_done; +}; + +struct zx_dma_dev { + struct dma_device slave; + void __iomem *base; + spinlock_t lock; /* lock for ch and phy */ + struct list_head chan_pending; + struct zx_dma_phy *phy; + struct zx_dma_chan *chans; + struct clk *clk; + struct dma_pool *pool; + u32 dma_channels; + u32 dma_requests; +}; + +#define to_zx_dma(dmadev) container_of(dmadev, struct zx_dma_dev, slave) + +static struct zx_dma_chan *to_zx_chan(struct dma_chan *chan) +{ + return container_of(chan, struct zx_dma_chan, vc.chan); +} + +static void zx_dma_terminate_chan(struct zx_dma_phy *phy, struct zx_dma_dev *d) +{ + u32 val = 0; + + val = readl_relaxed(phy->base + REG_ZX_CTRL); + val &= ~ZX_CH_ENABLE; + writel_relaxed(val, phy->base + REG_ZX_CTRL); + + val = 0x1 << phy->idx; + writel_relaxed(val, d->base + REG_ZX_TC_IRQ_RAW); + writel_relaxed(val, d->base + REG_ZX_SRC_ERR_IRQ_RAW); + writel_relaxed(val, d->base + REG_ZX_DST_ERR_IRQ_RAW); + writel_relaxed(val, d->base + REG_ZX_CFG_ERR_IRQ_RAW); +} + +static void zx_dma_set_desc(struct zx_dma_phy *phy, struct zx_desc_hw *hw) +{ + writel_relaxed(hw->saddr, phy->base + REG_ZX_SRC_ADDR); + writel_relaxed(hw->daddr, phy->base + REG_ZX_DST_ADDR); + writel_relaxed(hw->src_x, phy->base + REG_ZX_TX_X_COUNT); + writel_relaxed(0, phy->base + REG_ZX_TX_ZY_COUNT); + writel_relaxed(0, phy->base + REG_ZX_SRC_ZY_STEP); + writel_relaxed(0, phy->base + REG_ZX_DST_ZY_STEP); + writel_relaxed(hw->lli, phy->base + REG_ZX_LLI_ADDR); + writel_relaxed(hw->ctr, phy->base + REG_ZX_CTRL); +} + +static u32 zx_dma_get_curr_lli(struct zx_dma_phy *phy) +{ + return readl_relaxed(phy->base + REG_ZX_LLI_ADDR); +} + +static u32 zx_dma_get_chan_stat(struct zx_dma_dev *d) +{ + return readl_relaxed(d->base + REG_ZX_STATUS); +} + +static void zx_dma_init_state(struct zx_dma_dev *d) +{ + /* set same priority */ + writel_relaxed(0x0, d->base + REG_ZX_DMA_ARB); + /* clear all irq */ + writel_relaxed(0xffffffff, d->base + REG_ZX_TC_IRQ_RAW); + writel_relaxed(0xffffffff, d->base + REG_ZX_SRC_ERR_IRQ_RAW); + writel_relaxed(0xffffffff, d->base + REG_ZX_DST_ERR_IRQ_RAW); + writel_relaxed(0xffffffff, d->base + REG_ZX_CFG_ERR_IRQ_RAW); +} + +static int zx_dma_start_txd(struct zx_dma_chan *c) +{ + struct zx_dma_dev *d = to_zx_dma(c->vc.chan.device); + struct virt_dma_desc *vd = vchan_next_desc(&c->vc); + + if (!c->phy) + return -EAGAIN; + + if (BIT(c->phy->idx) & zx_dma_get_chan_stat(d)) + return -EAGAIN; + + if (vd) { + struct zx_dma_desc_sw *ds = + container_of(vd, struct zx_dma_desc_sw, vd); + /* + * fetch and remove request from vc->desc_issued + * so vc->desc_issued only contains desc pending + */ + list_del(&ds->vd.node); + c->phy->ds_run = ds; + c->phy->ds_done = NULL; + /* start dma */ + zx_dma_set_desc(c->phy, ds->desc_hw); + return 0; + } + c->phy->ds_done = NULL; + c->phy->ds_run = NULL; + return -EAGAIN; +} + +static void zx_dma_task(struct zx_dma_dev *d) +{ + struct zx_dma_phy *p; + struct zx_dma_chan *c, *cn; + unsigned pch, pch_alloc = 0; + unsigned long flags; + + /* check new dma request of running channel in vc->desc_issued */ + list_for_each_entry_safe(c, cn, &d->slave.channels, + vc.chan.device_node) { + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + if (p && p->ds_done && zx_dma_start_txd(c)) { + /* No current txd associated with this channel */ + dev_dbg(d->slave.dev, "pchan %u: free\n", p->idx); + /* Mark this channel free */ + c->phy = NULL; + p->vchan = NULL; + } + spin_unlock_irqrestore(&c->vc.lock, flags); + } + + /* check new channel request in d->chan_pending */ + spin_lock_irqsave(&d->lock, flags); + while (!list_empty(&d->chan_pending)) { + c = list_first_entry(&d->chan_pending, + struct zx_dma_chan, node); + p = &d->phy[c->id]; + if (!p->vchan) { + /* remove from d->chan_pending */ + list_del_init(&c->node); + pch_alloc |= 1 << c->id; + /* Mark this channel allocated */ + p->vchan = c; + c->phy = p; + } else { + dev_dbg(d->slave.dev, "pchan %u: busy!\n", c->id); + } + } + spin_unlock_irqrestore(&d->lock, flags); + + for (pch = 0; pch < d->dma_channels; pch++) { + if (pch_alloc & (1 << pch)) { + p = &d->phy[pch]; + c = p->vchan; + if (c) { + spin_lock_irqsave(&c->vc.lock, flags); + zx_dma_start_txd(c); + spin_unlock_irqrestore(&c->vc.lock, flags); + } + } + } +} + +static irqreturn_t zx_dma_int_handler(int irq, void *dev_id) +{ + struct zx_dma_dev *d = (struct zx_dma_dev *)dev_id; + struct zx_dma_phy *p; + struct zx_dma_chan *c; + u32 tc = readl_relaxed(d->base + REG_ZX_TC_IRQ); + u32 serr = readl_relaxed(d->base + REG_ZX_SRC_ERR_IRQ); + u32 derr = readl_relaxed(d->base + REG_ZX_DST_ERR_IRQ); + u32 cfg = readl_relaxed(d->base + REG_ZX_CFG_ERR_IRQ); + u32 i, irq_chan = 0; + + while (tc) { + i = __ffs(tc); + tc &= ~BIT(i); + p = &d->phy[i]; + c = p->vchan; + if (c) { + unsigned long flags; + + spin_lock_irqsave(&c->vc.lock, flags); + vchan_cookie_complete(&p->ds_run->vd); + p->ds_done = p->ds_run; + spin_unlock_irqrestore(&c->vc.lock, flags); + } + irq_chan |= BIT(i); + } + + if (serr || derr || cfg) + dev_warn(d->slave.dev, "DMA ERR src 0x%x, dst 0x%x, cfg 0x%x\n", + serr, derr, cfg); + + writel_relaxed(irq_chan, d->base + REG_ZX_TC_IRQ_RAW); + writel_relaxed(serr, d->base + REG_ZX_SRC_ERR_IRQ_RAW); + writel_relaxed(derr, d->base + REG_ZX_DST_ERR_IRQ_RAW); + writel_relaxed(cfg, d->base + REG_ZX_CFG_ERR_IRQ_RAW); + + if (irq_chan) { + zx_dma_task(d); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } +} + +static void zx_dma_free_chan_resources(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_dev *d = to_zx_dma(chan->device); + unsigned long flags; + + spin_lock_irqsave(&d->lock, flags); + list_del_init(&c->node); + spin_unlock_irqrestore(&d->lock, flags); + + vchan_free_chan_resources(&c->vc); + c->ccfg = 0; +} + +static enum dma_status zx_dma_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, + struct dma_tx_state *state) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_phy *p; + struct virt_dma_desc *vd; + unsigned long flags; + enum dma_status ret; + size_t bytes = 0; + + ret = dma_cookie_status(&c->vc.chan, cookie, state); + if (ret == DMA_COMPLETE || !state) + return ret; + + spin_lock_irqsave(&c->vc.lock, flags); + p = c->phy; + ret = c->status; + + /* + * If the cookie is on our issue queue, then the residue is + * its total size. + */ + vd = vchan_find_desc(&c->vc, cookie); + if (vd) { + bytes = container_of(vd, struct zx_dma_desc_sw, vd)->size; + } else if ((!p) || (!p->ds_run)) { + bytes = 0; + } else { + struct zx_dma_desc_sw *ds = p->ds_run; + u32 clli = 0, index = 0; + + bytes = 0; + clli = zx_dma_get_curr_lli(p); + index = (clli - ds->desc_hw_lli) / sizeof(struct zx_desc_hw); + for (; index < ds->desc_num; index++) { + bytes += ds->desc_hw[index].src_x; + /* end of lli */ + if (!ds->desc_hw[index].lli) + break; + } + } + spin_unlock_irqrestore(&c->vc.lock, flags); + dma_set_residue(state, bytes); + return ret; +} + +static void zx_dma_issue_pending(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_dev *d = to_zx_dma(chan->device); + unsigned long flags; + int issue = 0; + + spin_lock_irqsave(&c->vc.lock, flags); + /* add request to vc->desc_issued */ + if (vchan_issue_pending(&c->vc)) { + spin_lock(&d->lock); + if (!c->phy && list_empty(&c->node)) { + /* if new channel, add chan_pending */ + list_add_tail(&c->node, &d->chan_pending); + issue = 1; + dev_dbg(d->slave.dev, "vchan %p: issued\n", &c->vc); + } + spin_unlock(&d->lock); + } else { + dev_dbg(d->slave.dev, "vchan %p: nothing to issue\n", &c->vc); + } + spin_unlock_irqrestore(&c->vc.lock, flags); + + if (issue) + zx_dma_task(d); +} + +static void zx_dma_fill_desc(struct zx_dma_desc_sw *ds, dma_addr_t dst, + dma_addr_t src, size_t len, u32 num, u32 ccfg) +{ + if ((num + 1) < ds->desc_num) + ds->desc_hw[num].lli = ds->desc_hw_lli + (num + 1) * + sizeof(struct zx_desc_hw); + ds->desc_hw[num].saddr = src; + ds->desc_hw[num].daddr = dst; + ds->desc_hw[num].src_x = len; + ds->desc_hw[num].ctr = ccfg; +} + +static struct zx_dma_desc_sw *zx_alloc_desc_resource(int num, + struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + struct zx_dma_dev *d = to_zx_dma(chan->device); + int lli_limit = LLI_BLOCK_SIZE / sizeof(struct zx_desc_hw); + + if (num > lli_limit) { + dev_dbg(chan->device->dev, "vch %p: sg num %d exceed max %d\n", + &c->vc, num, lli_limit); + return NULL; + } + + ds = kzalloc(sizeof(*ds), GFP_ATOMIC); + if (!ds) + return NULL; + + ds->desc_hw = dma_pool_alloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); + if (!ds->desc_hw) { + dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc); + kfree(ds); + return NULL; + } + memset(ds->desc_hw, sizeof(struct zx_desc_hw) * num, 0); + ds->desc_num = num; + return ds; +} + +static enum zx_dma_burst_width zx_dma_burst_width(enum dma_slave_buswidth width) +{ + switch (width) { + case DMA_SLAVE_BUSWIDTH_1_BYTE: + case DMA_SLAVE_BUSWIDTH_2_BYTES: + case DMA_SLAVE_BUSWIDTH_4_BYTES: + case DMA_SLAVE_BUSWIDTH_8_BYTES: + return ffs(width) - 1; + default: + return ZX_DMA_WIDTH_32BIT; + } +} + +static int zx_pre_config(struct zx_dma_chan *c, enum dma_transfer_direction dir) +{ + struct dma_slave_config *cfg = &c->slave_cfg; + enum zx_dma_burst_width src_width; + enum zx_dma_burst_width dst_width; + u32 maxburst = 0; + + switch (dir) { + case DMA_MEM_TO_MEM: + c->ccfg = ZX_CH_ENABLE | ZX_SOFT_REQ + | ZX_SRC_BURST_LEN(ZX_MAX_BURST_LEN - 1) + | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_32BIT) + | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_32BIT); + break; + case DMA_MEM_TO_DEV: + c->dev_addr = cfg->dst_addr; + /* dst len is calculated from src width, len and dst width. + * We need make sure dst len not exceed MAX LEN. + */ + dst_width = zx_dma_burst_width(cfg->dst_addr_width); + maxburst = cfg->dst_maxburst * cfg->dst_addr_width + / DMA_SLAVE_BUSWIDTH_8_BYTES; + maxburst = maxburst < ZX_MAX_BURST_LEN ? + maxburst : ZX_MAX_BURST_LEN; + c->ccfg = ZX_DST_FIFO_MODE | ZX_CH_ENABLE + | ZX_SRC_BURST_LEN(maxburst - 1) + | ZX_SRC_BURST_WIDTH(ZX_DMA_WIDTH_64BIT) + | ZX_DST_BURST_WIDTH(dst_width); + break; + case DMA_DEV_TO_MEM: + c->dev_addr = cfg->src_addr; + src_width = zx_dma_burst_width(cfg->src_addr_width); + maxburst = cfg->src_maxburst; + maxburst = maxburst < ZX_MAX_BURST_LEN ? + maxburst : ZX_MAX_BURST_LEN; + c->ccfg = ZX_SRC_FIFO_MODE | ZX_CH_ENABLE + | ZX_SRC_BURST_LEN(maxburst - 1) + | ZX_SRC_BURST_WIDTH(src_width) + | ZX_DST_BURST_WIDTH(ZX_DMA_WIDTH_64BIT); + break; + default: + return -EINVAL; + } + return 0; +} + +static struct dma_async_tx_descriptor *zx_dma_prep_memcpy( + struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, + size_t len, unsigned long flags) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + size_t copy = 0; + int num = 0; + + if (!len) + return NULL; + + if (zx_pre_config(c, DMA_MEM_TO_MEM)) + return NULL; + + num = DIV_ROUND_UP(len, DMA_MAX_SIZE); + + ds = zx_alloc_desc_resource(num, chan); + if (!ds) + return NULL; + + ds->size = len; + num = 0; + + do { + copy = min_t(size_t, len, DMA_MAX_SIZE); + zx_dma_fill_desc(ds, dst, src, copy, num++, c->ccfg); + + src += copy; + dst += copy; + len -= copy; + } while (len); + + ds->desc_hw[num - 1].lli = 0; /* end of link */ + ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static struct dma_async_tx_descriptor *zx_dma_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, unsigned int sglen, + enum dma_transfer_direction dir, unsigned long flags, void *context) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_desc_sw *ds; + size_t len, avail, total = 0; + struct scatterlist *sg; + dma_addr_t addr, src = 0, dst = 0; + int num = sglen, i; + + if (!sgl) + return NULL; + + if (zx_pre_config(c, dir)) + return NULL; + + for_each_sg(sgl, sg, sglen, i) { + avail = sg_dma_len(sg); + if (avail > DMA_MAX_SIZE) + num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1; + } + + ds = zx_alloc_desc_resource(num, chan); + if (!ds) + return NULL; + + num = 0; + for_each_sg(sgl, sg, sglen, i) { + addr = sg_dma_address(sg); + avail = sg_dma_len(sg); + total += avail; + + do { + len = min_t(size_t, avail, DMA_MAX_SIZE); + + if (dir == DMA_MEM_TO_DEV) { + src = addr; + dst = c->dev_addr; + } else if (dir == DMA_DEV_TO_MEM) { + src = c->dev_addr; + dst = addr; + } + + zx_dma_fill_desc(ds, dst, src, len, num++, c->ccfg); + + addr += len; + avail -= len; + } while (avail); + } + + ds->desc_hw[num - 1].lli = 0; /* end of link */ + ds->desc_hw[num - 1].ctr |= ZX_IRQ_ENABLE_ALL; + ds->size = total; + return vchan_tx_prep(&c->vc, &ds->vd, flags); +} + +static int zx_dma_config(struct dma_chan *chan, + struct dma_slave_config *cfg) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + + if (!cfg) + return -EINVAL; + + memcpy(&c->slave_cfg, cfg, sizeof(*cfg)); + + return 0; +} + +static int zx_dma_terminate_all(struct dma_chan *chan) +{ + struct zx_dma_chan *c = to_zx_chan(chan); + struct zx_dma_dev *d = to_zx_dma(chan->device); + struct zx_dma_phy *p = c->phy; + unsigned long flags; + LIST_HEAD(head); + + dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc); + + /* Prevent this channel being scheduled */ + spin_lock(&d->lock); + list_del_init(&c->node); + spin_unlock(&d->lock); + + /* Clear the tx descriptor lists */ + spin_lock_irqsave(&c->vc.lock, flags); + vchan_get_all_descriptors(&c->vc, &head); + if (p) { + /* vchan is assigned to a pchan - stop the channel */ + zx_dma_terminate_chan(p, d); + c->phy = NULL; + p->vchan = NULL; + p->ds_run = NULL; + p->ds_done = NULL; + } + spin_unlock_irqrestore(&c->vc.lock, flags); + vchan_dma_desc_free_list(&c->vc, &head); + + return 0; +} + +static void zx_dma_free_desc(struct virt_dma_desc *vd) +{ + struct zx_dma_desc_sw *ds = + container_of(vd, struct zx_dma_desc_sw, vd); + struct zx_dma_dev *d = to_zx_dma(vd->tx.chan->device); + + dma_pool_free(d->pool, ds->desc_hw, ds->desc_hw_lli); + kfree(ds); +} + +static const struct of_device_id zx6702_dma_dt_ids[] = { + { .compatible = "zte,zx296702-dma", }, + {} +}; +MODULE_DEVICE_TABLE(of, zx6702_dma_dt_ids); + +static struct dma_chan *zx_of_dma_simple_xlate(struct of_phandle_args *dma_spec, + struct of_dma *ofdma) +{ + struct zx_dma_dev *d = ofdma->of_dma_data; + unsigned int request = dma_spec->args[0]; + struct dma_chan *chan; + struct zx_dma_chan *c; + + if (request > d->dma_requests) + return NULL; + + chan = dma_get_any_slave_channel(&d->slave); + if (!chan) { + dev_err(d->slave.dev, "get channel fail in %s.\n", __func__); + return NULL; + } + c = to_zx_chan(chan); + c->id = request; + dev_info(d->slave.dev, "zx_dma: pchan %u: alloc vchan %p\n", + c->id, &c->vc); + return chan; +} + +static int zx_dma_probe(struct platform_device *op) +{ + struct zx_dma_dev *d; + struct resource *iores; + int i, ret = 0, irq = 0; + + iores = platform_get_resource(op, IORESOURCE_MEM, 0); + if (!iores) + return -EINVAL; + + d = devm_kzalloc(&op->dev, sizeof(*d), GFP_KERNEL); + if (!d) + return -ENOMEM; + + d->base = devm_ioremap_resource(&op->dev, iores); + if (IS_ERR(d->base)) + return PTR_ERR(d->base); + + of_property_read_u32((&op->dev)->of_node, + "dma-channels", &d->dma_channels); + of_property_read_u32((&op->dev)->of_node, + "dma-requests", &d->dma_requests); + if (!d->dma_requests || !d->dma_channels) + return -EINVAL; + + d->clk = devm_clk_get(&op->dev, NULL); + if (IS_ERR(d->clk)) { + dev_err(&op->dev, "no dma clk\n"); + return PTR_ERR(d->clk); + } + + irq = platform_get_irq(op, 0); + ret = devm_request_irq(&op->dev, irq, zx_dma_int_handler, + 0, DRIVER_NAME, d); + if (ret) + return ret; + + /* A DMA memory pool for LLIs, align on 32-byte boundary */ + d->pool = dmam_pool_create(DRIVER_NAME, &op->dev, + LLI_BLOCK_SIZE, 32, 0); + if (!d->pool) + return -ENOMEM; + + /* init phy channel */ + d->phy = devm_kzalloc(&op->dev, + d->dma_channels * sizeof(struct zx_dma_phy), GFP_KERNEL); + if (!d->phy) + return -ENOMEM; + + for (i = 0; i < d->dma_channels; i++) { + struct zx_dma_phy *p = &d->phy[i]; + + p->idx = i; + p->base = d->base + i * 0x40; + } + + INIT_LIST_HEAD(&d->slave.channels); + dma_cap_set(DMA_SLAVE, d->slave.cap_mask); + dma_cap_set(DMA_MEMCPY, d->slave.cap_mask); + dma_cap_set(DMA_PRIVATE, d->slave.cap_mask); + d->slave.dev = &op->dev; + d->slave.device_free_chan_resources = zx_dma_free_chan_resources; + d->slave.device_tx_status = zx_dma_tx_status; + d->slave.device_prep_dma_memcpy = zx_dma_prep_memcpy; + d->slave.device_prep_slave_sg = zx_dma_prep_slave_sg; + d->slave.device_issue_pending = zx_dma_issue_pending; + d->slave.device_config = zx_dma_config; + d->slave.device_terminate_all = zx_dma_terminate_all; + d->slave.copy_align = DMA_ALIGN; + d->slave.src_addr_widths = ZX_DMA_BUSWIDTHS; + d->slave.dst_addr_widths = ZX_DMA_BUSWIDTHS; + d->slave.directions = BIT(DMA_MEM_TO_MEM) | BIT(DMA_MEM_TO_DEV) + | BIT(DMA_DEV_TO_MEM); + d->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT; + + /* init virtual channel */ + d->chans = devm_kzalloc(&op->dev, + d->dma_requests * sizeof(struct zx_dma_chan), GFP_KERNEL); + if (!d->chans) + return -ENOMEM; + + for (i = 0; i < d->dma_requests; i++) { + struct zx_dma_chan *c = &d->chans[i]; + + c->status = DMA_IN_PROGRESS; + INIT_LIST_HEAD(&c->node); + c->vc.desc_free = zx_dma_free_desc; + vchan_init(&c->vc, &d->slave); + } + + /* Enable clock before accessing registers */ + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(&op->dev, "clk_prepare_enable failed: %d\n", ret); + goto zx_dma_out; + } + + zx_dma_init_state(d); + + spin_lock_init(&d->lock); + INIT_LIST_HEAD(&d->chan_pending); + platform_set_drvdata(op, d); + + ret = dma_async_device_register(&d->slave); + if (ret) + goto clk_dis; + + ret = of_dma_controller_register((&op->dev)->of_node, + zx_of_dma_simple_xlate, d); + if (ret) + goto of_dma_register_fail; + + dev_info(&op->dev, "initialized\n"); + return 0; + +of_dma_register_fail: + dma_async_device_unregister(&d->slave); +clk_dis: + clk_disable_unprepare(d->clk); +zx_dma_out: + return ret; +} + +static int zx_dma_remove(struct platform_device *op) +{ + struct zx_dma_chan *c, *cn; + struct zx_dma_dev *d = platform_get_drvdata(op); + + dma_async_device_unregister(&d->slave); + of_dma_controller_free((&op->dev)->of_node); + + list_for_each_entry_safe(c, cn, &d->slave.channels, + vc.chan.device_node) { + list_del(&c->vc.chan.device_node); + } + clk_disable_unprepare(d->clk); + dmam_pool_destroy(d->pool); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int zx_dma_suspend_dev(struct device *dev) +{ + struct zx_dma_dev *d = dev_get_drvdata(dev); + u32 stat = 0; + + stat = zx_dma_get_chan_stat(d); + if (stat) { + dev_warn(d->slave.dev, + "chan %d is running fail to suspend\n", stat); + return -1; + } + clk_disable_unprepare(d->clk); + return 0; +} + +static int zx_dma_resume_dev(struct device *dev) +{ + struct zx_dma_dev *d = dev_get_drvdata(dev); + int ret = 0; + + ret = clk_prepare_enable(d->clk); + if (ret < 0) { + dev_err(d->slave.dev, "clk_prepare_enable failed: %d\n", ret); + return ret; + } + zx_dma_init_state(d); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(zx_dma_pmops, zx_dma_suspend_dev, zx_dma_resume_dev); + +static struct platform_driver zx_pdma_driver = { + .driver = { + .name = DRIVER_NAME, + .pm = &zx_dma_pmops, + .of_match_table = zx6702_dma_dt_ids, + }, + .probe = zx_dma_probe, + .remove = zx_dma_remove, +}; + +module_platform_driver(zx_pdma_driver); + +MODULE_DESCRIPTION("ZTE ZX296702 DMA Driver"); +MODULE_AUTHOR("Jun Nie jun.nie@linaro.org"); +MODULE_LICENSE("GPL v2"); -- GitLab From 9bde2823dcb97997456645f9b18f8c3468b727ca Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 18 May 2015 15:33:13 +0530 Subject: [PATCH 0968/7006] dmaengine: zxdma: explicitly free irq on device removal At device removal, tasklets are not disabled and irqs are still enabled, so free the irq explicitly on device removal Signed-off-by: Vinod Koul --- drivers/dma/zx296702_dma.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index c99f0d1ac88a8..ec470bc74df8d 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -127,6 +127,7 @@ struct zx_dma_dev { struct dma_pool *pool; u32 dma_channels; u32 dma_requests; + int irq; }; #define to_zx_dma(dmadev) container_of(dmadev, struct zx_dma_dev, slave) @@ -683,7 +684,7 @@ static int zx_dma_probe(struct platform_device *op) { struct zx_dma_dev *d; struct resource *iores; - int i, ret = 0, irq = 0; + int i, ret = 0; iores = platform_get_resource(op, IORESOURCE_MEM, 0); if (!iores) @@ -710,8 +711,8 @@ static int zx_dma_probe(struct platform_device *op) return PTR_ERR(d->clk); } - irq = platform_get_irq(op, 0); - ret = devm_request_irq(&op->dev, irq, zx_dma_int_handler, + d->irq = platform_get_irq(op, 0); + ret = devm_request_irq(&op->dev, d->irq, zx_dma_int_handler, 0, DRIVER_NAME, d); if (ret) return ret; @@ -807,6 +808,9 @@ static int zx_dma_remove(struct platform_device *op) struct zx_dma_chan *c, *cn; struct zx_dma_dev *d = platform_get_drvdata(op); + /* explictly free the irq */ + devm_free_irq(&op->dev, d->irq, d); + dma_async_device_unregister(&d->slave); of_dma_controller_free((&op->dev)->of_node); -- GitLab From 72858602e167ea2d7487337bac279beec7a99c84 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Tue, 7 Jul 2015 22:22:15 +0200 Subject: [PATCH 0969/7006] gpiolib: remove unneeded assignation ret is assigned value from of_property_read_string_index but is overwritten before being used so remove it. Also fix coverity CID 1309759 Reported-by: coverity (CID 1309759) Signed-off-by: Laurent Navet Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index fd2db4b3a709e..1e36ec5e2e0c0 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -362,7 +362,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) if (pinspec.args[2]) { if (group_names) { - ret = of_property_read_string_index(np, + of_property_read_string_index(np, group_names_propname, index, &name); if (strlen(name)) { -- GitLab From 2660801f7323b84fc2ad46449a5d1f331266d9f7 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 16 Jul 2015 15:51:01 +0200 Subject: [PATCH 0970/7006] drm/atomic: Only update crtc->x/y if it's part of the state, v2. Universal planes may not be assigned to the current crtc, so only update crtc->x/y when the primary is part of the state and bound to the current crtc. Changes since v1: - Add the crtc check. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 0898afbc9e23e..f94cc371742ef 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -665,10 +665,16 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, /* set legacy state in the crtc structure */ for_each_crtc_in_state(old_state, crtc, old_crtc_state, i) { + struct drm_plane *primary = crtc->primary; + crtc->mode = crtc->state->mode; crtc->enabled = crtc->state->enable; - crtc->x = crtc->primary->state->src_x >> 16; - crtc->y = crtc->primary->state->src_y >> 16; + + if (drm_atomic_get_existing_plane_state(old_state, primary) && + primary->state->crtc == crtc) { + crtc->x = primary->state->src_x >> 16; + crtc->y = primary->state->src_y >> 16; + } if (crtc->state->enable) drm_calc_timestamping_constants(crtc, -- GitLab From e1443d2849b146be4ed8d4ef89ae7e215aafaa5b Mon Sep 17 00:00:00 2001 From: Stephen Chandler Paul Date: Wed, 15 Jul 2015 10:20:17 -0700 Subject: [PATCH 0971/7006] Input: i8042 - add unmask_kbd_data option A big problem with the current i8042 debugging option is that it outputs data going to and from the keyboard by default. As a result, many dmesg logs uploaded by users will unintentionally contain sensitive information such as their password, as such it's probably a good idea not to output data coming from the keyboard unless specifically enabled by the user. Signed-off-by: Stephen Chandler Paul Reviewed-by: Andreas Mohr Reviewed-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- Documentation/kernel-parameters.txt | 4 +++ drivers/input/serio/i8042.c | 43 ++++++++++++++++++++++++++--- drivers/input/serio/i8042.h | 13 +++++++++ drivers/input/serio/serio.c | 5 ++-- include/linux/serio.h | 2 ++ 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index bfcb1a62a7b48..fd0f7cd8e4967 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -1274,6 +1274,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. , i8042.debug [HW] Toggle i8042 debug mode + i8042.unmask_kbd_data + [HW] Enable printing of interrupt data from the KBD port + (disabled by default, and as a pre-condition + requires that i8042.debug=1 be enabled) i8042.direct [HW] Put keyboard port into non-translated mode i8042.dumbkbd [HW] Pretend that controller can only read data from keyboard and cannot control its state diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index cb5ece77fd7d8..c9c98f0ab284f 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -88,6 +88,10 @@ MODULE_PARM_DESC(nopnp, "Do not use PNP to detect controller settings"); static bool i8042_debug; module_param_named(debug, i8042_debug, bool, 0600); MODULE_PARM_DESC(debug, "Turn i8042 debugging mode on and off"); + +static bool i8042_unmask_kbd_data; +module_param_named(unmask_kbd_data, i8042_unmask_kbd_data, bool, 0600); +MODULE_PARM_DESC(unmask_kbd_data, "Unconditional enable (may reveal sensitive data) of normally sanitize-filtered kbd data traffic debug log [pre-condition: i8042.debug=1 enabled]"); #endif static bool i8042_bypass_aux_irq_test; @@ -116,6 +120,7 @@ struct i8042_port { struct serio *serio; int irq; bool exists; + bool driver_bound; signed char mux; }; @@ -133,6 +138,7 @@ static bool i8042_kbd_irq_registered; static bool i8042_aux_irq_registered; static unsigned char i8042_suppress_kbd_ack; static struct platform_device *i8042_platform_device; +static struct notifier_block i8042_kbd_bind_notifier_block; static irqreturn_t i8042_interrupt(int irq, void *dev_id); static bool (*i8042_platform_filter)(unsigned char data, unsigned char str, @@ -528,10 +534,10 @@ static irqreturn_t i8042_interrupt(int irq, void *dev_id) port = &i8042_ports[port_no]; serio = port->exists ? port->serio : NULL; - dbg("%02x <- i8042 (interrupt, %d, %d%s%s)\n", - data, port_no, irq, - dfl & SERIO_PARITY ? ", bad parity" : "", - dfl & SERIO_TIMEOUT ? ", timeout" : ""); + filter_dbg(port->driver_bound, data, "<- i8042 (interrupt, %d, %d%s%s)\n", + port_no, irq, + dfl & SERIO_PARITY ? ", bad parity" : "", + dfl & SERIO_TIMEOUT ? ", timeout" : ""); filtered = i8042_filter(data, str, serio); @@ -1438,6 +1444,29 @@ static int __init i8042_setup_kbd(void) return error; } +static int i8042_kbd_bind_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct serio *serio = to_serio_port(dev); + struct i8042_port *port = serio->port_data; + + if (serio != i8042_ports[I8042_KBD_PORT_NO].serio) + return 0; + + switch (action) { + case BUS_NOTIFY_BOUND_DRIVER: + port->driver_bound = true; + break; + + case BUS_NOTIFY_UNBIND_DRIVER: + port->driver_bound = false; + break; + } + + return 0; +} + static int __init i8042_probe(struct platform_device *dev) { int error; @@ -1507,6 +1536,10 @@ static struct platform_driver i8042_driver = { .shutdown = i8042_shutdown, }; +static struct notifier_block i8042_kbd_bind_notifier_block = { + .notifier_call = i8042_kbd_bind_notifier, +}; + static int __init i8042_init(void) { struct platform_device *pdev; @@ -1528,6 +1561,7 @@ static int __init i8042_init(void) goto err_platform_exit; } + bus_register_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); panic_blink = i8042_panic_blink; return 0; @@ -1543,6 +1577,7 @@ static void __exit i8042_exit(void) platform_driver_unregister(&i8042_driver); i8042_platform_exit(); + bus_unregister_notifier(&serio_bus, &i8042_kbd_bind_notifier_block); panic_blink = NULL; } diff --git a/drivers/input/serio/i8042.h b/drivers/input/serio/i8042.h index fc080beffedc2..1db0a40c9bab7 100644 --- a/drivers/input/serio/i8042.h +++ b/drivers/input/serio/i8042.h @@ -73,6 +73,17 @@ static unsigned long i8042_start_time; printk(KERN_DEBUG KBUILD_MODNAME ": [%d] " format, \ (int) (jiffies - i8042_start_time), ##arg); \ } while (0) + +#define filter_dbg(filter, data, format, args...) \ + do { \ + if (!i8042_debug) \ + break; \ + \ + if (!filter || i8042_unmask_kbd_data) \ + dbg("%02x " format, data, ##args); \ + else \ + dbg("** " format, ##args); \ + } while (0) #else #define dbg_init() do { } while (0) #define dbg(format, arg...) \ @@ -80,6 +91,8 @@ static unsigned long i8042_start_time; if (0) \ printk(KERN_DEBUG pr_fmt(format), ##arg); \ } while (0) + +#define filter_dbg(filter, data, format, args...) do { } while (0) #endif #endif /* _I8042_H */ diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index a05a5179da325..8f828975ab10b 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c @@ -49,8 +49,6 @@ static DEFINE_MUTEX(serio_mutex); static LIST_HEAD(serio_list); -static struct bus_type serio_bus; - static void serio_add_port(struct serio *serio); static int serio_reconnect_port(struct serio *serio); static void serio_disconnect_port(struct serio *serio); @@ -1017,7 +1015,7 @@ irqreturn_t serio_interrupt(struct serio *serio, } EXPORT_SYMBOL(serio_interrupt); -static struct bus_type serio_bus = { +struct bus_type serio_bus = { .name = "serio", .drv_groups = serio_driver_groups, .match = serio_bus_match, @@ -1029,6 +1027,7 @@ static struct bus_type serio_bus = { .pm = &serio_pm_ops, #endif }; +EXPORT_SYMBOL(serio_bus); static int __init serio_init(void) { diff --git a/include/linux/serio.h b/include/linux/serio.h index 9f779c7a2da46..df4ab5de15862 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h @@ -18,6 +18,8 @@ #include #include +extern struct bus_type serio_bus; + struct serio { void *port_data; -- GitLab From cee3d8ccbecb8af6788edaaac46befca78b000dc Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Thu, 16 Jul 2015 10:32:40 -0700 Subject: [PATCH 0972/7006] Input: ambakmi - fix system PM by converting to modern callbacks The legacy system PM support has long time ago been dropped from the AMBA bus. Align to that by converting to the modern system PM callbacks. Fixes: 26825cfd90f9 (ARM: 7914/1: amba: Drop legacy PM support ...) Signed-off-by: Ulf Hansson Signed-off-by: Dmitry Torokhov --- drivers/input/serio/ambakmi.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c index 8b748d99b934f..c6606cacb6a7a 100644 --- a/drivers/input/serio/ambakmi.c +++ b/drivers/input/serio/ambakmi.c @@ -175,9 +175,9 @@ static int amba_kmi_remove(struct amba_device *dev) return 0; } -static int amba_kmi_resume(struct amba_device *dev) +static int __maybe_unused amba_kmi_resume(struct device *dev) { - struct amba_kmi_port *kmi = amba_get_drvdata(dev); + struct amba_kmi_port *kmi = dev_get_drvdata(dev); /* kick the serio layer to rescan this port */ serio_reconnect(kmi->io); @@ -185,6 +185,8 @@ static int amba_kmi_resume(struct amba_device *dev) return 0; } +static SIMPLE_DEV_PM_OPS(amba_kmi_dev_pm_ops, NULL, amba_kmi_resume); + static struct amba_id amba_kmi_idtable[] = { { .id = 0x00041050, @@ -199,11 +201,11 @@ static struct amba_driver ambakmi_driver = { .drv = { .name = "kmi-pl050", .owner = THIS_MODULE, + .pm = &amba_kmi_dev_pm_ops, }, .id_table = amba_kmi_idtable, .probe = amba_kmi_probe, .remove = amba_kmi_remove, - .resume = amba_kmi_resume, }; module_amba_driver(ambakmi_driver); -- GitLab From df2e268226e2e3d79980a5dddfd683126f79ddb4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:49 +0200 Subject: [PATCH 0973/7006] ASoC: max9877: Make driver global regmap struct local Use a stack local variable to handle function local state rather than a global static variable. The later has a potential for race conditions if the probe function runs for two devices concurrently. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max9877.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index e1df06fab7564..b469e1c82ea2e 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -20,8 +20,6 @@ #include "max9877.h" -static struct regmap *regmap; - static const struct reg_default max9877_regs[] = { { 0, 0x40 }, { 1, 0x00 }, @@ -145,6 +143,7 @@ static const struct regmap_config max9877_regmap = { static int max9877_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { + struct regmap *regmap; int i; regmap = devm_regmap_init_i2c(client, &max9877_regmap); -- GitLab From 623436af42ef2b37fee8f6058a85f4664bd32c74 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:50 +0200 Subject: [PATCH 0974/7006] ASoC: max9877: Convert to component The driver does not use any CODEC specific constructs anymore. Convert it to snd_soc_component. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max9877.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/sound/soc/codecs/max9877.c b/sound/soc/codecs/max9877.c index b469e1c82ea2e..fb448dde018da 100644 --- a/sound/soc/codecs/max9877.c +++ b/sound/soc/codecs/max9877.c @@ -121,7 +121,7 @@ static const struct snd_soc_dapm_route max9877_dapm_routes[] = { { "HPR", NULL, "SHDN" }, }; -static const struct snd_soc_codec_driver max9877_codec = { +static const struct snd_soc_component_driver max9877_component_driver = { .controls = max9877_controls, .num_controls = ARRAY_SIZE(max9877_controls), @@ -154,14 +154,8 @@ static int max9877_i2c_probe(struct i2c_client *client, for (i = 0; i < ARRAY_SIZE(max9877_regs); i++) regmap_write(regmap, max9877_regs[i].reg, max9877_regs[i].def); - return snd_soc_register_codec(&client->dev, &max9877_codec, NULL, 0); -} - -static int max9877_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - - return 0; + return devm_snd_soc_register_component(&client->dev, + &max9877_component_driver, NULL, 0); } static const struct i2c_device_id max9877_i2c_id[] = { @@ -175,7 +169,6 @@ static struct i2c_driver max9877_i2c_driver = { .name = "max9877", }, .probe = max9877_i2c_probe, - .remove = max9877_i2c_remove, .id_table = max9877_i2c_id, }; -- GitLab From d79cca1a994f6f4f1cf3d92909f2a73df6b84874 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:51 +0200 Subject: [PATCH 0975/7006] ASoC: max9768: Use managed gpio request Makes the code a bit shorter and simpler. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max9768.c | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index 1526aef2f2a9c..d70a8205c6adb 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -183,11 +183,13 @@ static int max9768_i2c_probe(struct i2c_client *client, if (pdata) { /* Mute on powerup to avoid clicks */ - err = gpio_request_one(pdata->mute_gpio, GPIOF_INIT_HIGH, "MAX9768 Mute"); + err = devm_gpio_request_one(&client->dev, pdata->mute_gpio, + GPIOF_INIT_HIGH, "MAX9768 Mute"); max9768->mute_gpio = err ?: pdata->mute_gpio; /* Activate chip by releasing shutdown, enables I2C */ - err = gpio_request_one(pdata->shdn_gpio, GPIOF_INIT_HIGH, "MAX9768 Shutdown"); + err = devm_gpio_request_one(&client->dev, pdata->shdn_gpio, + GPIOF_INIT_HIGH, "MAX9768 Shutdown"); max9768->shdn_gpio = err ?: pdata->shdn_gpio; max9768->flags = pdata->flags; @@ -199,37 +201,17 @@ static int max9768_i2c_probe(struct i2c_client *client, i2c_set_clientdata(client, max9768); max9768->regmap = devm_regmap_init_i2c(client, &max9768_i2c_regmap_config); - if (IS_ERR(max9768->regmap)) { - err = PTR_ERR(max9768->regmap); - goto err_gpio_free; - } - - err = snd_soc_register_codec(&client->dev, &max9768_codec_driver, NULL, 0); - if (err) - goto err_gpio_free; - - return 0; + if (IS_ERR(max9768->regmap)) + return PTR_ERR(max9768->regmap); - err_gpio_free: - if (gpio_is_valid(max9768->shdn_gpio)) - gpio_free(max9768->shdn_gpio); - if (gpio_is_valid(max9768->mute_gpio)) - gpio_free(max9768->mute_gpio); - - return err; + return snd_soc_register_codec(&client->dev, &max9768_codec_driver, + NULL, 0); } static int max9768_i2c_remove(struct i2c_client *client) { - struct max9768 *max9768 = i2c_get_clientdata(client); - snd_soc_unregister_codec(&client->dev); - if (gpio_is_valid(max9768->shdn_gpio)) - gpio_free(max9768->shdn_gpio); - if (gpio_is_valid(max9768->mute_gpio)) - gpio_free(max9768->mute_gpio); - return 0; } -- GitLab From 04b5cbd80af899c6a4d51835b069b96ae8864e5a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 16 Jul 2015 21:22:52 +0200 Subject: [PATCH 0976/7006] ASoC: max9768: Convert to component The driver does not use any CODEC specific constructs anymore. Convert it to snd_soc_component. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/max9768.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/sound/soc/codecs/max9768.c b/sound/soc/codecs/max9768.c index d70a8205c6adb..4c300f317c3ae 100644 --- a/sound/soc/codecs/max9768.c +++ b/sound/soc/codecs/max9768.c @@ -43,8 +43,8 @@ static struct reg_default max9768_default_regs[] = { static int max9768_get_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct max9768 *max9768 = snd_soc_component_get_drvdata(c); int val = gpio_get_value_cansleep(max9768->mute_gpio); ucontrol->value.integer.value[0] = !val; @@ -55,8 +55,8 @@ static int max9768_get_gpio(struct snd_kcontrol *kcontrol, static int max9768_set_gpio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); - struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol); + struct max9768 *max9768 = snd_soc_component_get_drvdata(c); gpio_set_value_cansleep(max9768->mute_gpio, !ucontrol->value.integer.value[0]); @@ -130,19 +130,20 @@ static const struct snd_soc_dapm_route max9768_dapm_routes[] = { { "OUT-", NULL, "IN" }, }; -static int max9768_probe(struct snd_soc_codec *codec) +static int max9768_probe(struct snd_soc_component *component) { - struct max9768 *max9768 = snd_soc_codec_get_drvdata(codec); + struct max9768 *max9768 = snd_soc_component_get_drvdata(component); int ret; if (max9768->flags & MAX9768_FLAG_CLASSIC_PWM) { - ret = snd_soc_write(codec, MAX9768_CTRL, MAX9768_CTRL_PWM); + ret = regmap_write(max9768->regmap, MAX9768_CTRL, + MAX9768_CTRL_PWM); if (ret) return ret; } if (gpio_is_valid(max9768->mute_gpio)) { - ret = snd_soc_add_codec_controls(codec, max9768_mute, + ret = snd_soc_add_component_controls(component, max9768_mute, ARRAY_SIZE(max9768_mute)); if (ret) return ret; @@ -151,7 +152,7 @@ static int max9768_probe(struct snd_soc_codec *codec) return 0; } -static struct snd_soc_codec_driver max9768_codec_driver = { +static struct snd_soc_component_driver max9768_component_driver = { .probe = max9768_probe, .controls = max9768_volume, .num_controls = ARRAY_SIZE(max9768_volume), @@ -204,15 +205,8 @@ static int max9768_i2c_probe(struct i2c_client *client, if (IS_ERR(max9768->regmap)) return PTR_ERR(max9768->regmap); - return snd_soc_register_codec(&client->dev, &max9768_codec_driver, - NULL, 0); -} - -static int max9768_i2c_remove(struct i2c_client *client) -{ - snd_soc_unregister_codec(&client->dev); - - return 0; + return devm_snd_soc_register_component(&client->dev, + &max9768_component_driver, NULL, 0); } static const struct i2c_device_id max9768_i2c_id[] = { @@ -226,7 +220,6 @@ static struct i2c_driver max9768_i2c_driver = { .name = "max9768", }, .probe = max9768_i2c_probe, - .remove = max9768_i2c_remove, .id_table = max9768_i2c_id, }; module_i2c_driver(max9768_i2c_driver); -- GitLab From ed6c75f23383ba4e0fbc935c0b6ab165bc9ff65e Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:02 +0200 Subject: [PATCH 0977/7006] ASoC: sti: minor corrections for uniplayer Minor corrections after code review. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif_player.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d66d633f0b29f..d12d0502545eb 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -475,6 +475,7 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *player = priv->dai_data.uni; + int ret; if (dir == SND_SOC_CLOCK_IN) return 0; @@ -482,9 +483,11 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, if (clk_id != 0) return -EINVAL; - player->mclk = freq; + ret = clk_set_rate(player->clk, freq); + if (!ret) + player->mclk = freq; - return clk_set_rate(player->clk, freq); + return ret; } static int uni_player_prepare(struct snd_pcm_substream *substream, @@ -562,6 +565,7 @@ static int uni_player_prepare(struct snd_pcm_substream *substream, case SND_SOC_DAIFMT_IB_IF: SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); + break; } switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { @@ -840,7 +844,7 @@ int uni_player_init(struct platform_device *pdev, /* Get uniperif resource */ player->clk = of_clk_get(pdev->dev.of_node, 0); if (IS_ERR(player->clk)) - ret = (int)PTR_ERR(player->clk); + ret = PTR_ERR(player->clk); /* Select the frequency synthesizer clock */ if (player->clk_sel) { -- GitLab From c3a0003aaf0dc2ffd006a3bb5abc1f5b639552a7 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:03 +0200 Subject: [PATCH 0978/7006] ASoC: sti: Add CPU DAI driver for capture Add code to manage Uniperipheral reader IP instances. These DAIs are dedicated to capture and support I2S and IEC modes. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif.h | 3 + sound/soc/sti/uniperif_reader.c | 362 ++++++++++++++++++++++++++++++++ 2 files changed, 365 insertions(+) create mode 100644 sound/soc/sti/uniperif_reader.c diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index a8d9e94d80410..f396958e8a085 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1212,4 +1212,7 @@ int uni_player_init(struct platform_device *pdev, struct uniperif *uni_player); int uni_player_resume(struct uniperif *player); +/* uniperiph reader */ +int uni_reader_init(struct platform_device *pdev, + struct uniperif *uni_reader); #endif diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c new file mode 100644 index 0000000000000..7d83827ba6601 --- /dev/null +++ b/sound/soc/sti/uniperif_reader.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include + +#include + +#include "uniperif.h" + +/* + * Note: snd_pcm_hardware is linked to DMA controller but is declared here to + * integrate unireader capability in term of rate and supported channels + */ +const struct snd_pcm_hardware uni_reader_pcm_hw = { + .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID, + .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, + + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 8000, + .rate_max = 96000, + + .channels_min = 2, + .channels_max = 8, + + .periods_min = 2, + .periods_max = 48, + + .period_bytes_min = 128, + .period_bytes_max = 64 * PAGE_SIZE, + .buffer_bytes_max = 256 * PAGE_SIZE +}; + +/* + * uni_reader_irq_handler + * In case of error audio stream is stopped; stop action is protected via PCM + * stream lock to avoid race condition with trigger callback. + */ +static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) +{ + irqreturn_t ret = IRQ_NONE; + struct uniperif *reader = dev_id; + unsigned int status; + + if (reader->state == UNIPERIF_STATE_STOPPED) { + /* Unexpected IRQ: do nothing */ + dev_warn(reader->dev, "unexpected IRQ "); + return IRQ_HANDLED; + } + + /* Get interrupt status & clear them immediately */ + status = GET_UNIPERIF_ITS(reader); + SET_UNIPERIF_ITS_BCLR(reader, status); + + /* Check for fifo overflow error */ + if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { + dev_err(reader->dev, "FIFO error detected"); + + snd_pcm_stream_lock(reader->substream); + snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(reader->substream); + + return IRQ_HANDLED; + } + + return ret; +} + +static int uni_reader_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *reader = priv->dai_data.uni; + struct snd_pcm_runtime *runtime = substream->runtime; + int transfer_size, trigger_limit; + int slot_width; + int count = 10; + + /* The reader should be stopped */ + if (reader->state != UNIPERIF_STATE_STOPPED) { + dev_err(reader->dev, "%s: invalid reader state %d", __func__, + reader->state); + return -EINVAL; + } + + /* Calculate transfer size (in fifo cells and bytes) for frame count */ + transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; + + /* Calculate number of empty cells available before asserting DREQ */ + if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) + trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; + else + /* + * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 + * FDMA_TRIGGER_LIMIT also controls when the state switches + * from OFF or STANDBY to AUDIO DATA. + */ + trigger_limit = transfer_size; + + /* Trigger limit must be an even number */ + if ((!trigger_limit % 2) || + (trigger_limit != 1 && transfer_size % 2) || + (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { + dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); + return -EINVAL; + } + + SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); + + switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_IB_IF: + case SND_SOC_DAIFMT_NB_IF: + SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); + break; + default: + SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); + } + + /* Force slot width to 32 in I2S mode */ + if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) + == SND_SOC_DAIFMT_I2S) { + slot_width = 32; + } else { + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + slot_width = 16; + break; + default: + slot_width = 32; + break; + } + } + + /* Number of bits per subframe (i.e one channel sample) on input. */ + switch (slot_width) { + case 32: + SET_UNIPERIF_I2S_FMT_NBIT_32(reader); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader); + break; + case 16: + SET_UNIPERIF_I2S_FMT_NBIT_16(reader); + SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader); + break; + default: + dev_err(reader->dev, "subframe format not supported"); + return -EINVAL; + } + + /* Configure data memory format */ + switch (runtime->format) { + case SNDRV_PCM_FORMAT_S16_LE: + /* One data word contains two samples */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_16(reader); + break; + + case SNDRV_PCM_FORMAT_S32_LE: + /* + * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits + * on the MSB then zeros (if less than 32 bytes)"... + */ + SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader); + break; + + default: + dev_err(reader->dev, "format not supported"); + return -EINVAL; + } + + switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); + SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(reader); + break; + case SND_SOC_DAIFMT_LEFT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); + break; + case SND_SOC_DAIFMT_RIGHT_J: + SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(reader); + SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); + break; + default: + dev_err(reader->dev, "format not supported"); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); + + /* Data clocking (changing) on the rising edge */ + SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); + + /* Number of channels must be even */ + + if ((runtime->channels % 2) || (runtime->channels < 2) || + (runtime->channels > 10)) { + dev_err(reader->dev, "%s: invalid nb of channels", __func__); + return -EINVAL; + } + + SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); + + /* Clear any pending interrupts */ + SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); + + SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(reader, 0); + + /* Set the interrupt mask */ + SET_UNIPERIF_ITM_BSET_DMA_ERROR(reader); + SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader); + SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader); + + /* Enable underflow recovery interrupts */ + if (reader->info->underflow_enabled) { + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader); + SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader); + } + + /* Reset uniperipheral reader */ + SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); + + while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) { + udelay(5); + count--; + } + if (!count) { + dev_err(reader->dev, "Failed to reset uniperif"); + return -EIO; + } + + return 0; +} + +static int uni_reader_start(struct uniperif *reader) +{ + /* The reader should be stopped */ + if (reader->state != UNIPERIF_STATE_STOPPED) { + dev_err(reader->dev, "%s: invalid reader state", __func__); + return -EINVAL; + } + + /* Enable reader interrupts (and clear possible stalled ones) */ + SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(reader); + SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader); + + /* Launch the reader */ + SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(reader); + + /* Update state to started */ + reader->state = UNIPERIF_STATE_STARTED; + return 0; +} + +static int uni_reader_stop(struct uniperif *reader) +{ + /* The reader should not be in stopped state */ + if (reader->state == UNIPERIF_STATE_STOPPED) { + dev_err(reader->dev, "%s: invalid reader state", __func__); + return -EINVAL; + } + + /* Turn the reader off */ + SET_UNIPERIF_CTRL_OPERATION_OFF(reader); + + /* Disable interrupts */ + SET_UNIPERIF_ITM_BCLR(reader, GET_UNIPERIF_ITM(reader)); + + /* Update state to stopped and return */ + reader->state = UNIPERIF_STATE_STOPPED; + + return 0; +} + +static int uni_reader_trigger(struct snd_pcm_substream *substream, + int cmd, struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *reader = priv->dai_data.uni; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + return uni_reader_start(reader); + case SNDRV_PCM_TRIGGER_STOP: + return uni_reader_stop(reader); + default: + return -EINVAL; + } +} + +static void uni_reader_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *reader = priv->dai_data.uni; + + if (reader->state != UNIPERIF_STATE_STOPPED) { + /* Stop the reader */ + uni_reader_stop(reader); + } +} + +static int uni_reader_parse_dt(struct platform_device *pdev, + struct uniperif *reader) +{ + struct uniperif_info *info; + struct device_node *node = pdev->dev.of_node; + + /* Allocate memory for the info structure */ + info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + of_property_read_u32(node, "version", &reader->ver); + + /* Save the info structure */ + reader->info = info; + + return 0; +} + +const struct snd_soc_dai_ops uni_reader_dai_ops = { + .shutdown = uni_reader_shutdown, + .prepare = uni_reader_prepare, + .trigger = uni_reader_trigger, + .hw_params = sti_uniperiph_dai_hw_params, + .set_fmt = sti_uniperiph_dai_set_fmt, +}; + +int uni_reader_init(struct platform_device *pdev, + struct uniperif *reader) +{ + int ret = 0; + + reader->dev = &pdev->dev; + reader->state = UNIPERIF_STATE_STOPPED; + reader->hw = &uni_reader_pcm_hw; + reader->dai_ops = &uni_reader_dai_ops; + + dev_err(reader->dev, "%s: enter\n", __func__); + ret = uni_reader_parse_dt(pdev, reader); + if (ret < 0) { + dev_err(reader->dev, "Failed to parse DeviceTree"); + return ret; + } + + ret = devm_request_irq(&pdev->dev, reader->irq, + uni_reader_irq_handler, IRQF_SHARED, + dev_name(&pdev->dev), reader); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to request IRQ"); + return -EBUSY; + } + + return 0; +} +EXPORT_SYMBOL_GPL(uni_reader_init); -- GitLab From f3bd847eb0a7744b1a86f6b585149434cc6f57ff Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:04 +0200 Subject: [PATCH 0979/7006] ASoC: sti: Add uniperipheral dai driver ASoc uniperipheral dai driver that manages uniperipheral DAIs and registers associated generic dma engine platform. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 253 +++++++++++++++++++++++++++++++++++ sound/soc/sti/uniperif.h | 9 ++ 2 files changed, 262 insertions(+) create mode 100644 sound/soc/sti/sti_uniperif.c diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c new file mode 100644 index 0000000000000..749e6b2941849 --- /dev/null +++ b/sound/soc/sti/sti_uniperif.c @@ -0,0 +1,253 @@ +/* + * Copyright (C) STMicroelectronics SA 2015 + * Authors: Arnaud Pouliquen + * for STMicroelectronics. + * License terms: GNU General Public License (GPL), version 2 + */ + +#include + +#include "uniperif.h" + +/* + * sti_uniperiph_dai_create_ctrl + * This function is used to create Ctrl associated to DAI but also pcm device. + * Request is done by front end to associate ctrl with pcm device id + */ +int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + struct snd_kcontrol_new *ctrl; + int i; + + if (!uni->num_ctrls) + return 0; + + for (i = 0; i < uni->num_ctrls; i++) { + /* + * Several Control can have same name. Controls are indexed on + * Uniperipheral instance ID + */ + ctrl = &uni->snd_ctrls[i]; + ctrl->index = uni->info->id; + ctrl->device = uni->info->id; + } + + return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); +} + +/* + * DAI + */ +int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_dmaengine_dai_dma_data *dma_data; + int transfer_size; + + transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; + + dma_data = snd_soc_dai_get_dma_data(dai, substream); + dma_data->maxburst = transfer_size; + + return 0; +} + +int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + + priv->dai_data.uni->daifmt = fmt; + + return 0; +} + +static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + int ret; + + /* The uniperipheral should be in stopped state */ + if (uni->state != UNIPERIF_STATE_STOPPED) { + dev_err(uni->dev, "%s: invalid uni state( %d)", + __func__, (int)uni->state); + return -EBUSY; + } + + /* Pinctrl: switch pinstate to sleep */ + ret = pinctrl_pm_select_sleep_state(uni->dev); + if (ret) + dev_err(uni->dev, "%s: failed to select pinctrl state", + __func__); + + return ret; +} + +static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *uni = priv->dai_data.uni; + int ret; + + if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { + ret = uni_player_resume(uni); + if (ret) + return ret; + } + + /* pinctrl: switch pinstate to default */ + ret = pinctrl_pm_select_default_state(uni->dev); + if (ret) + dev_err(uni->dev, "%s: failed to select pinctrl state", + __func__); + + return ret; +} + +static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct sti_uniperiph_dai *dai_data = &priv->dai_data; + + /* DMA settings*/ + if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) + snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); + else + snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); + + dai_data->dma_data.addr = dai_data->uni->fifo_phys_address; + dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; + + return sti_uniperiph_dai_create_ctrl(dai); +} + +static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { + .probe = sti_uniperiph_dai_probe, + .suspend = sti_uniperiph_dai_suspend, + .resume = sti_uniperiph_dai_resume +}; + +static const struct snd_soc_component_driver sti_uniperiph_dai_component = { + .name = "sti_cpu_dai", +}; + +static int sti_uniperiph_cpu_dai_of(struct device_node *node, + struct sti_uniperiph_data *priv) +{ + const char *str; + int ret; + struct device *dev = &priv->pdev->dev; + struct sti_uniperiph_dai *dai_data = &priv->dai_data; + struct snd_soc_dai_driver *dai = priv->dai; + struct snd_soc_pcm_stream *stream; + struct uniperif *uni; + + uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); + if (!uni) + return -ENOMEM; + + *dai = sti_uniperiph_dai_template; + ret = of_property_read_string(node, "dai-name", &str); + if (ret < 0) { + dev_err(dev, "%s: dai name missing.\n", __func__); + return -EINVAL; + } + dai->name = str; + + /* Get resources */ + uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); + + if (!uni->mem_region) { + dev_err(dev, "Failed to get memory resource"); + return -ENODEV; + } + + uni->base = devm_ioremap_resource(dev, uni->mem_region); + + if (IS_ERR(uni->base)) + return PTR_ERR(uni->base); + + uni->fifo_phys_address = uni->mem_region->start + + UNIPERIF_FIFO_DATA_OFFSET(uni); + + uni->irq = platform_get_irq(priv->pdev, 0); + if (!uni->irq < 0) { + dev_err(dev, "Failed to get IRQ resource"); + return -ENXIO; + } + + dai_data->uni = uni; + + if (of_device_is_compatible(node, "st,sti-uni-player")) { + uni_player_init(priv->pdev, uni); + stream = &dai->playback; + } else { + uni_reader_init(priv->pdev, uni); + stream = &dai->capture; + } + dai->ops = uni->dai_ops; + + stream->stream_name = dai->name; + stream->channels_min = uni->hw->channels_min; + stream->channels_max = uni->hw->channels_max; + stream->rates = uni->hw->rates; + stream->formats = uni->hw->formats; + + return 0; +} + +static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { + .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, +}; + +static int sti_uniperiph_probe(struct platform_device *pdev) +{ + struct sti_uniperiph_data *priv; + struct device_node *node = pdev->dev.of_node; + int ret; + + /* Allocate the private data and the CPU_DAI array */ + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL); + if (!priv->dai) + return -ENOMEM; + + priv->pdev = pdev; + + ret = sti_uniperiph_cpu_dai_of(node, priv); + + dev_set_drvdata(&pdev->dev, priv); + + ret = snd_soc_register_component(&pdev->dev, + &sti_uniperiph_dai_component, + priv->dai, 1); + if (ret < 0) + return ret; + + return devm_snd_dmaengine_pcm_register(&pdev->dev, + &dmaengine_pcm_config, 0); +} + +static const struct of_device_id snd_soc_sti_match[] = { + { .compatible = "st,sti-uni-player", }, + { .compatible = "st,sti-uni-reader", }, + {}, +}; + +static struct platform_driver sti_uniperiph_driver = { + .driver = { + .name = "sti-uniperiph-dai", + .of_match_table = snd_soc_sti_match, + }, + .probe = sti_uniperiph_probe, +}; +module_platform_driver(sti_uniperiph_driver); + +MODULE_DESCRIPTION("uniperipheral DAI driver"); +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f396958e8a085..f1e583de3c6f1 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1215,4 +1215,13 @@ int uni_player_resume(struct uniperif *player); /* uniperiph reader */ int uni_reader_init(struct platform_device *pdev, struct uniperif *uni_reader); + +/* common */ +int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt); + +int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai); + #endif -- GitLab From 1e6babb417f76bd6d1a4d1d633e5c46435acbfe7 Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:05 +0200 Subject: [PATCH 0980/7006] ASoC: Add ability to build sti drivers Define the platform and codec drivers, and how to build them. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/Kconfig | 1 + sound/soc/Makefile | 1 + sound/soc/sti/Kconfig | 11 +++++++++++ sound/soc/sti/Makefile | 4 ++++ 4 files changed, 17 insertions(+) create mode 100644 sound/soc/sti/Kconfig create mode 100644 sound/soc/sti/Makefile diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 2ae9619443d15..467ee1a00dd63 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig @@ -54,6 +54,7 @@ source "sound/soc/samsung/Kconfig" source "sound/soc/sh/Kconfig" source "sound/soc/sirf/Kconfig" source "sound/soc/spear/Kconfig" +source "sound/soc/sti/Kconfig" source "sound/soc/tegra/Kconfig" source "sound/soc/txx9/Kconfig" source "sound/soc/ux500/Kconfig" diff --git a/sound/soc/Makefile b/sound/soc/Makefile index e189903fabf42..19fd711034e25 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile @@ -36,6 +36,7 @@ obj-$(CONFIG_SND_SOC) += samsung/ obj-$(CONFIG_SND_SOC) += sh/ obj-$(CONFIG_SND_SOC) += sirf/ obj-$(CONFIG_SND_SOC) += spear/ +obj-$(CONFIG_SND_SOC) += sti/ obj-$(CONFIG_SND_SOC) += tegra/ obj-$(CONFIG_SND_SOC) += txx9/ obj-$(CONFIG_SND_SOC) += ux500/ diff --git a/sound/soc/sti/Kconfig b/sound/soc/sti/Kconfig new file mode 100644 index 0000000000000..64a690077023a --- /dev/null +++ b/sound/soc/sti/Kconfig @@ -0,0 +1,11 @@ +# +# STM SoC audio configuration +# +menuconfig SND_SOC_STI + tristate "SoC Audio support for STI System-On-Chip" + depends on SND_SOC + depends on ARCH_STI || COMPILE_TEST + select SND_SOC_GENERIC_DMAENGINE_PCM + help + Say Y if you want to enable ASoC-support for + any of the STI platforms (e.g. STIH416). diff --git a/sound/soc/sti/Makefile b/sound/soc/sti/Makefile new file mode 100644 index 0000000000000..4b188d2d76b8e --- /dev/null +++ b/sound/soc/sti/Makefile @@ -0,0 +1,4 @@ +# STI platform support +snd-soc-sti-objs := sti_uniperif.o uniperif_player.o uniperif_reader.o + +obj-$(CONFIG_SND_SOC_STI) += snd-soc-sti.o -- GitLab From fa050796b35c80ac948c4d24c95262daa905e2ef Mon Sep 17 00:00:00 2001 From: Arnaud Pouliquen Date: Thu, 16 Jul 2015 11:36:06 +0200 Subject: [PATCH 0981/7006] ASoC: sti: Add clock adjustement control Add capability to adjust player clock, for clocks drift management. Signed-off-by: Arnaud Pouliquen Signed-off-by: Mark Brown --- sound/soc/sti/uniperif.h | 2 + sound/soc/sti/uniperif_player.c | 149 +++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h index f1e583de3c6f1..ee462f7daaff9 100644 --- a/sound/soc/sti/uniperif.h +++ b/sound/soc/sti/uniperif.h @@ -1175,6 +1175,7 @@ struct uniperif { /* Clocks */ struct clk *clk; int mclk; + int clk_adj; /* Runtime data */ enum uniperif_state state; @@ -1183,6 +1184,7 @@ struct uniperif { /* Specific to IEC958 player */ struct uniperif_iec958_settings stream_settings; + struct mutex ctrl_lock; /* For resource updated by stream and controls*/ /*alsa ctrl*/ struct snd_kcontrol_new *snd_ctrls; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d12d0502545eb..d990d2c81a5d4 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -36,6 +36,9 @@ (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) +#define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 +#define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 + /* * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate DAI_CPU capability in term of rate and supported channels @@ -172,6 +175,70 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) return ret; } +int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) +{ + int rate_adjusted, rate_achieved, delta, ret; + int adjustment = player->clk_adj; + + /* + * a + * F = f + --------- * f = f + d + * 1000000 + * + * a + * d = --------- * f + * 1000000 + * + * where: + * f - nominal rate + * a - adjustment in ppm (parts per milion) + * F - rate to be set in synthesizer + * d - delta (difference) between f and F + */ + if (adjustment < 0) { + /* div64_64 operates on unsigned values... */ + delta = -1; + adjustment = -adjustment; + } else { + delta = 1; + } + /* 500000 ppm is 0.5, which is used to round up values */ + delta *= (int)div64_u64((uint64_t)rate * + (uint64_t)adjustment + 500000, 1000000); + rate_adjusted = rate + delta; + + /* Adjusted rate should never be == 0 */ + if (!rate_adjusted) + return -EINVAL; + + ret = clk_set_rate(player->clk, rate_adjusted); + if (ret < 0) + return ret; + + rate_achieved = clk_get_rate(player->clk); + if (!rate_achieved) + /* If value is 0 means that clock or parent not valid */ + return -EINVAL; + + /* + * Using ALSA's adjustment control, we can modify the rate to be up + * to twice as much as requested, but no more + */ + delta = rate_achieved - rate; + if (delta < 0) { + /* div64_64 operates on unsigned values... */ + delta = -delta; + adjustment = -1; + } else { + adjustment = 1; + } + /* Frequency/2 is added to round up result */ + adjustment *= (int)div64_u64((uint64_t)delta * 1000000 + rate / 2, + rate); + player->clk_adj = adjustment; + return 0; +} + static void uni_player_set_channel_status(struct uniperif *player, struct snd_pcm_runtime *runtime) { @@ -470,6 +537,78 @@ static int uni_player_prepare_pcm(struct uniperif *player, return 0; } +/* + * uniperif rate adjustement control + */ +static int snd_sti_clk_adjustment_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = UNIPERIF_PLAYER_CLK_ADJ_MIN; + uinfo->value.integer.max = UNIPERIF_PLAYER_CLK_ADJ_MAX; + uinfo->value.integer.step = 1; + + return 0; +} + +static int snd_sti_clk_adjustment_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + ucontrol->value.integer.value[0] = player->clk_adj; + + return 0; +} + +static int snd_sti_clk_adjustment_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + int ret = 0; + + if ((ucontrol->value.integer.value[0] < UNIPERIF_PLAYER_CLK_ADJ_MIN) || + (ucontrol->value.integer.value[0] > UNIPERIF_PLAYER_CLK_ADJ_MAX)) + return -EINVAL; + + mutex_lock(&player->ctrl_lock); + player->clk_adj = ucontrol->value.integer.value[0]; + + if (player->mclk) + ret = uni_player_clk_set_rate(player, player->mclk); + mutex_unlock(&player->ctrl_lock); + + return ret; +} + +static struct snd_kcontrol_new uni_player_clk_adj_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "PCM Playback Oversampling Freq. Adjustment", + .info = snd_sti_clk_adjustment_info, + .get = snd_sti_clk_adjustment_get, + .put = snd_sti_clk_adjustment_put, +}; + +static struct snd_kcontrol_new *snd_sti_ctl[] = { + &uni_player_clk_adj_ctl, +}; + +static int uni_player_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); + struct uniperif *player = priv->dai_data.uni; + + player->clk_adj = 0; + + return 0; +} + static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { @@ -483,9 +622,11 @@ static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, if (clk_id != 0) return -EINVAL; - ret = clk_set_rate(player->clk, freq); + mutex_lock(&player->ctrl_lock); + ret = uni_player_clk_set_rate(player, freq); if (!ret) player->mclk = freq; + mutex_unlock(&player->ctrl_lock); return ret; } @@ -816,6 +957,7 @@ static int uni_player_parse_dt(struct platform_device *pdev, } const struct snd_soc_dai_ops uni_player_dai_ops = { + .startup = uni_player_startup, .shutdown = uni_player_shutdown, .prepare = uni_player_prepare, .trigger = uni_player_trigger, @@ -863,6 +1005,8 @@ int uni_player_init(struct platform_device *pdev, if (ret < 0) return ret; + mutex_init(&player->ctrl_lock); + /* Ensure that disabled by default */ SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); SET_UNIPERIF_CTRL_ROUNDING_OFF(player); @@ -889,6 +1033,9 @@ int uni_player_init(struct platform_device *pdev, IEC958_AES4_CON_WORDLEN_24_20; } + player->num_ctrls = ARRAY_SIZE(snd_sti_ctl); + player->snd_ctrls = snd_sti_ctl[0]; + return 0; } EXPORT_SYMBOL_GPL(uni_player_init); -- GitLab From b662680252fa6e3bc53ad087078dd1fe7496449c Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 10 Jul 2015 22:18:39 +0530 Subject: [PATCH 0982/7006] ASoC: Intel: Skylake: Add dsp loader ops The ops is initialized during the dsp registration and used for the allocating dma buffers. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index cdfca9be4120a..c2d28781309a1 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,6 +16,8 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__ +#include + struct sst_dsp_device; /* Intel HD Audio General DSP Registers */ @@ -104,6 +106,13 @@ struct skl_dsp_fw_ops { int (*set_state_D3)(struct sst_dsp *ctx); }; +struct skl_dsp_loader_ops { + int (*alloc_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab, size_t size); + int (*free_dma_buf)(struct device *dev, + struct snd_dma_buffer *dmab); +}; + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); -- GitLab From e30903877fde33192b80100b7f63f2af97b2bd86 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 10 Jul 2015 22:18:40 +0530 Subject: [PATCH 0983/7006] ASoC: Intel: Skylake: Add code loader DMA registers Skylake has a DMA controller for loading DSP code and modules to memory. Add the register defines for this DMA Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.h | 191 ++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.h diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h new file mode 100644 index 0000000000000..34c366f050ee6 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -0,0 +1,191 @@ +/* + * Intel Code Loader DMA support + * + * Copyright (C) 2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef SKL_SST_CLDMA_H_ +#define SKL_SST_CLDMA_H_ + +#define FW_CL_STREAM_NUMBER 0x1 + +#define DMA_ADDRESS_128_BITS_ALIGNMENT 7 +#define BDL_ALIGN(x) (x >> DMA_ADDRESS_128_BITS_ALIGNMENT) + +#define SKL_ADSPIC_CL_DMA 0x2 +#define SKL_ADSPIS_CL_DMA 0x2 +#define SKL_CL_DMA_SD_INT_DESC_ERR 0x10 /* Descriptor error interrupt */ +#define SKL_CL_DMA_SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SKL_CL_DMA_SD_INT_COMPLETE 0x04 /* Buffer completion interrupt */ + +/* Intel HD Audio Code Loader DMA Registers */ + +#define HDA_ADSP_LOADER_BASE 0x80 + +/* Stream Registers */ +#define SKL_ADSP_REG_CL_SD_CTL (HDA_ADSP_LOADER_BASE + 0x00) +#define SKL_ADSP_REG_CL_SD_STS (HDA_ADSP_LOADER_BASE + 0x03) +#define SKL_ADSP_REG_CL_SD_LPIB (HDA_ADSP_LOADER_BASE + 0x04) +#define SKL_ADSP_REG_CL_SD_CBL (HDA_ADSP_LOADER_BASE + 0x08) +#define SKL_ADSP_REG_CL_SD_LVI (HDA_ADSP_LOADER_BASE + 0x0c) +#define SKL_ADSP_REG_CL_SD_FIFOW (HDA_ADSP_LOADER_BASE + 0x0e) +#define SKL_ADSP_REG_CL_SD_FIFOSIZE (HDA_ADSP_LOADER_BASE + 0x10) +#define SKL_ADSP_REG_CL_SD_FORMAT (HDA_ADSP_LOADER_BASE + 0x12) +#define SKL_ADSP_REG_CL_SD_FIFOL (HDA_ADSP_LOADER_BASE + 0x14) +#define SKL_ADSP_REG_CL_SD_BDLPL (HDA_ADSP_LOADER_BASE + 0x18) +#define SKL_ADSP_REG_CL_SD_BDLPU (HDA_ADSP_LOADER_BASE + 0x1c) + +/* CL: Software Position Based FIFO Capability Registers */ +#define SKL_ADSP_REG_CL_SPBFIFO (HDA_ADSP_LOADER_BASE + 0x20) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCH (SKL_ADSP_REG_CL_SPBFIFO + 0x0) +#define SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL (SKL_ADSP_REG_CL_SPBFIFO + 0x4) +#define SKL_ADSP_REG_CL_SPBFIFO_SPIB (SKL_ADSP_REG_CL_SPBFIFO + 0x8) +#define SKL_ADSP_REG_CL_SPBFIFO_MAXFIFOS (SKL_ADSP_REG_CL_SPBFIFO + 0xc) + +/* CL: Stream Descriptor x Control */ + +/* Stream Reset */ +#define CL_SD_CTL_SRST_SHIFT 0 +#define CL_SD_CTL_SRST_MASK (1 << CL_SD_CTL_SRST_SHIFT) +#define CL_SD_CTL_SRST(x) \ + ((x << CL_SD_CTL_SRST_SHIFT) & CL_SD_CTL_SRST_MASK) + +/* Stream Run */ +#define CL_SD_CTL_RUN_SHIFT 1 +#define CL_SD_CTL_RUN_MASK (1 << CL_SD_CTL_RUN_SHIFT) +#define CL_SD_CTL_RUN(x) \ + ((x << CL_SD_CTL_RUN_SHIFT) & CL_SD_CTL_RUN_MASK) + +/* Interrupt On Completion Enable */ +#define CL_SD_CTL_IOCE_SHIFT 2 +#define CL_SD_CTL_IOCE_MASK (1 << CL_SD_CTL_IOCE_SHIFT) +#define CL_SD_CTL_IOCE(x) \ + ((x << CL_SD_CTL_IOCE_SHIFT) & CL_SD_CTL_IOCE_MASK) + +/* FIFO Error Interrupt Enable */ +#define CL_SD_CTL_FEIE_SHIFT 3 +#define CL_SD_CTL_FEIE_MASK (1 << CL_SD_CTL_FEIE_SHIFT) +#define CL_SD_CTL_FEIE(x) \ + ((x << CL_SD_CTL_FEIE_SHIFT) & CL_SD_CTL_FEIE_MASK) + +/* Descriptor Error Interrupt Enable */ +#define CL_SD_CTL_DEIE_SHIFT 4 +#define CL_SD_CTL_DEIE_MASK (1 << CL_SD_CTL_DEIE_SHIFT) +#define CL_SD_CTL_DEIE(x) \ + ((x << CL_SD_CTL_DEIE_SHIFT) & CL_SD_CTL_DEIE_MASK) + +/* FIFO Limit Change */ +#define CL_SD_CTL_FIFOLC_SHIFT 5 +#define CL_SD_CTL_FIFOLC_MASK (1 << CL_SD_CTL_FIFOLC_SHIFT) +#define CL_SD_CTL_FIFOLC(x) \ + ((x << CL_SD_CTL_FIFOLC_SHIFT) & CL_SD_CTL_FIFOLC_MASK) + +/* Stripe Control */ +#define CL_SD_CTL_STRIPE_SHIFT 16 +#define CL_SD_CTL_STRIPE_MASK (0x3 << CL_SD_CTL_STRIPE_SHIFT) +#define CL_SD_CTL_STRIPE(x) \ + ((x << CL_SD_CTL_STRIPE_SHIFT) & CL_SD_CTL_STRIPE_MASK) + +/* Traffic Priority */ +#define CL_SD_CTL_TP_SHIFT 18 +#define CL_SD_CTL_TP_MASK (1 << CL_SD_CTL_TP_SHIFT) +#define CL_SD_CTL_TP(x) \ + ((x << CL_SD_CTL_TP_SHIFT) & CL_SD_CTL_TP_MASK) + +/* Bidirectional Direction Control */ +#define CL_SD_CTL_DIR_SHIFT 19 +#define CL_SD_CTL_DIR_MASK (1 << CL_SD_CTL_DIR_SHIFT) +#define CL_SD_CTL_DIR(x) \ + ((x << CL_SD_CTL_DIR_SHIFT) & CL_SD_CTL_DIR_MASK) + +/* Stream Number */ +#define CL_SD_CTL_STRM_SHIFT 20 +#define CL_SD_CTL_STRM_MASK (0xf << CL_SD_CTL_STRM_SHIFT) +#define CL_SD_CTL_STRM(x) \ + ((x << CL_SD_CTL_STRM_SHIFT) & CL_SD_CTL_STRM_MASK) + +/* CL: Stream Descriptor x Status */ + +/* Buffer Completion Interrupt Status */ +#define CL_SD_STS_BCIS(x) CL_SD_CTL_IOCE(x) + +/* FIFO Error */ +#define CL_SD_STS_FIFOE(x) CL_SD_CTL_FEIE(x) + +/* Descriptor Error */ +#define CL_SD_STS_DESE(x) CL_SD_CTL_DEIE(x) + +/* FIFO Ready */ +#define CL_SD_STS_FIFORDY(x) CL_SD_CTL_FIFOLC(x) + + +/* CL: Stream Descriptor x Last Valid Index */ +#define CL_SD_LVI_SHIFT 0 +#define CL_SD_LVI_MASK (0xff << CL_SD_LVI_SHIFT) +#define CL_SD_LVI(x) ((x << CL_SD_LVI_SHIFT) & CL_SD_LVI_MASK) + +/* CL: Stream Descriptor x FIFO Eviction Watermark */ +#define CL_SD_FIFOW_SHIFT 0 +#define CL_SD_FIFOW_MASK (0x7 << CL_SD_FIFOW_SHIFT) +#define CL_SD_FIFOW(x) \ + ((x << CL_SD_FIFOW_SHIFT) & CL_SD_FIFOW_MASK) + +/* CL: Stream Descriptor x Buffer Descriptor List Pointer Lower Base Address */ + +/* Protect Bits */ +#define CL_SD_BDLPLBA_PROT_SHIFT 0 +#define CL_SD_BDLPLBA_PROT_MASK (1 << CL_SD_BDLPLBA_PROT_SHIFT) +#define CL_SD_BDLPLBA_PROT(x) \ + ((x << CL_SD_BDLPLBA_PROT_SHIFT) & CL_SD_BDLPLBA_PROT_MASK) + +/* Buffer Descriptor List Lower Base Address */ +#define CL_SD_BDLPLBA_SHIFT 7 +#define CL_SD_BDLPLBA_MASK (0x1ffffff << CL_SD_BDLPLBA_SHIFT) +#define CL_SD_BDLPLBA(x) \ + ((BDL_ALIGN(lower_32_bits(x)) << CL_SD_BDLPLBA_SHIFT) & CL_SD_BDLPLBA_MASK) + +/* Buffer Descriptor List Upper Base Address */ +#define CL_SD_BDLPUBA_SHIFT 0 +#define CL_SD_BDLPUBA_MASK (0xffffffff << CL_SD_BDLPUBA_SHIFT) +#define CL_SD_BDLPUBA(x) \ + ((upper_32_bits(x) << CL_SD_BDLPUBA_SHIFT) & CL_SD_BDLPUBA_MASK) + +/* + * Code Loader - Software Position Based FIFO + * Capability Registers x Software Position Based FIFO Header + */ + +/* Next Capability Pointer */ +#define CL_SPBFIFO_SPBFCH_PTR_SHIFT 0 +#define CL_SPBFIFO_SPBFCH_PTR_MASK (0xff << CL_SPBFIFO_SPBFCH_PTR_SHIFT) +#define CL_SPBFIFO_SPBFCH_PTR(x) \ + ((x << CL_SPBFIFO_SPBFCH_PTR_SHIFT) & CL_SPBFIFO_SPBFCH_PTR_MASK) + +/* Capability Identifier */ +#define CL_SPBFIFO_SPBFCH_ID_SHIFT 16 +#define CL_SPBFIFO_SPBFCH_ID_MASK (0xfff << CL_SPBFIFO_SPBFCH_ID_SHIFT) +#define CL_SPBFIFO_SPBFCH_ID(x) \ + ((x << CL_SPBFIFO_SPBFCH_ID_SHIFT) & CL_SPBFIFO_SPBFCH_ID_MASK) + +/* Capability Version */ +#define CL_SPBFIFO_SPBFCH_VER_SHIFT 28 +#define CL_SPBFIFO_SPBFCH_VER_MASK (0xf << CL_SPBFIFO_SPBFCH_VER_SHIFT) +#define CL_SPBFIFO_SPBFCH_VER(x) \ + ((x << CL_SPBFIFO_SPBFCH_VER_SHIFT) & CL_SPBFIFO_SPBFCH_VER_MASK) + +/* Software Position in Buffer Enable */ +#define CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT 0 +#define CL_SPBFIFO_SPBFCCTL_SPIBE_MASK (1 << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) +#define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ + ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) + +#endif /* SKL_SST_CLDMA_H_ */ -- GitLab From 914426c8657c1e934b015ffa32e7bfd0cb34f47f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 10 Jul 2015 22:18:41 +0530 Subject: [PATCH 0984/7006] ASoC: Intel: Skylake: add code loader DMA operations This patch starts adding code loader DMA handling internal operations for setting up bdle, controller, spb, cleanup routines and buffer filling Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-cldma.c | 194 ++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-cldma.h | 60 ++++++++ 2 files changed, 254 insertions(+) create mode 100644 sound/soc/intel/skylake/skl-sst-cldma.c diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c new file mode 100644 index 0000000000000..44019eef61149 --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -0,0 +1,194 @@ +/* + * skl-sst-cldma.c - Code Loader DMA handler + * + * Copyright (C) 2015, Intel Corporation. + * Author: Subhransu S. Prusty + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" + +static void skl_cldma_int_enable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, SKL_ADSP_REG_ADSPIC, + SKL_ADSPIC_CL_DMA, SKL_ADSPIC_CL_DMA); +} + +void skl_cldma_int_disable(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_ADSPIC, SKL_ADSPIC_CL_DMA, 0); +} + +/* Code loader helper APIs */ +static void skl_cldma_setup_bdle(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc) +{ + u32 *bdl = *bdlp; + + ctx->cl_dev.frags = 0; + while (size > 0) { + phys_addr_t addr = virt_to_phys(dmab_data->area + + (ctx->cl_dev.frags * ctx->cl_dev.bufsize)); + + bdl[0] = cpu_to_le32(lower_32_bits(addr)); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + + bdl[2] = cpu_to_le32(ctx->cl_dev.bufsize); + + size -= ctx->cl_dev.bufsize; + bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + + bdl += 4; + ctx->cl_dev.frags++; + } +} + +/* + * Setup controller + * Configure the registers to update the dma buffer address and + * enable interrupts. + * Note: Using the channel 1 for transfer + */ +static void skl_cldma_setup_controller(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, unsigned int max_size, + u32 count) +{ + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, + CL_SD_BDLPLBA(dmab_bdl->addr)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, + CL_SD_BDLPUBA(dmab_bdl->addr)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, max_size); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, count - 1); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(1)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(FW_CL_STREAM_NUMBER)); +} + +static void skl_cldma_setup_spb(struct sst_dsp *ctx, + unsigned int size, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(1)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, size); +} + +static void skl_cldma_cleanup_spb(struct sst_dsp *ctx) +{ + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SPBFIFO_SPBFCCTL, + CL_SPBFIFO_SPBFCCTL_SPIBE_MASK, + CL_SPBFIFO_SPBFCCTL_SPIBE(0)); + + sst_dsp_shim_write_unlocked(ctx, SKL_ADSP_REG_CL_SPBFIFO_SPIB, 0); +} + +static void skl_cldma_trigger(struct sst_dsp *ctx, bool enable) +{ + if (enable) + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(1)); + else + sst_dsp_shim_update_bits_unlocked(ctx, + SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_RUN_MASK, CL_SD_CTL_RUN(0)); +} + +static void skl_cldma_cleanup(struct sst_dsp *ctx) +{ + skl_cldma_cleanup_spb(ctx); + + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_IOCE_MASK, CL_SD_CTL_IOCE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_FEIE_MASK, CL_SD_CTL_FEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_DEIE_MASK, CL_SD_CTL_DEIE(0)); + sst_dsp_shim_update_bits(ctx, SKL_ADSP_REG_CL_SD_CTL, + CL_SD_CTL_STRM_MASK, CL_SD_CTL_STRM(0)); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPL, CL_SD_BDLPLBA(0)); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_BDLPU, 0); + + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_CBL, 0); + sst_dsp_shim_write(ctx, SKL_ADSP_REG_CL_SD_LVI, 0); +} + +static int skl_cldma_wait_interruptible(struct sst_dsp *ctx) +{ + int ret = 0; + + if (!wait_event_timeout(ctx->cl_dev.wait_queue, + ctx->cl_dev.wait_condition, + msecs_to_jiffies(SKL_WAIT_TIMEOUT))) { + dev_err(ctx->dev, "%s: Wait timeout\n", __func__); + ret = -EIO; + goto cleanup; + } + + dev_dbg(ctx->dev, "%s: Event wake\n", __func__); + if (ctx->cl_dev.wake_status != SKL_CL_DMA_BUF_COMPLETE) { + dev_err(ctx->dev, "%s: DMA Error\n", __func__); + ret = -EIO; + } + +cleanup: + ctx->cl_dev.wake_status = SKL_CL_DMA_STATUS_NONE; + return ret; +} + +static void skl_cldma_stop(struct sst_dsp *ctx) +{ + ctx->cl_dev.ops.cl_trigger(ctx, false); +} + +static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, + const void *curr_pos, bool intr_enable, bool trigger) +{ + dev_dbg(ctx->dev, "Size: %x, intr_enable: %d\n", size, intr_enable); + dev_dbg(ctx->dev, "buf_pos_index:%d, trigger:%d\n", + ctx->cl_dev.dma_buffer_offset, trigger); + dev_dbg(ctx->dev, "spib position: %d\n", ctx->cl_dev.curr_spib_pos); + + memcpy(ctx->cl_dev.dmab_data.area + ctx->cl_dev.dma_buffer_offset, + curr_pos, size); + + if (ctx->cl_dev.curr_spib_pos == ctx->cl_dev.bufsize) + ctx->cl_dev.dma_buffer_offset = 0; + else + ctx->cl_dev.dma_buffer_offset = ctx->cl_dev.curr_spib_pos; + + ctx->cl_dev.wait_condition = false; + + if (intr_enable) + skl_cldma_int_enable(ctx); + + ctx->cl_dev.ops.cl_setup_spb(ctx, ctx->cl_dev.curr_spib_pos, trigger); + if (trigger) + ctx->cl_dev.ops.cl_trigger(ctx, true); +} diff --git a/sound/soc/intel/skylake/skl-sst-cldma.h b/sound/soc/intel/skylake/skl-sst-cldma.h index 34c366f050ee6..99e4c86b63585 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.h +++ b/sound/soc/intel/skylake/skl-sst-cldma.h @@ -188,4 +188,64 @@ #define CL_SPBFIFO_SPBFCCTL_SPIBE(x) \ ((x << CL_SPBFIFO_SPBFCCTL_SPIBE_SHIFT) & CL_SPBFIFO_SPBFCCTL_SPIBE_MASK) +/* SST IPC SKL defines */ +#define SKL_WAIT_TIMEOUT 500 /* 500 msec */ +#define SKL_MAX_BUFFER_SIZE (32 * PAGE_SIZE) + +enum skl_cl_dma_wake_states { + SKL_CL_DMA_STATUS_NONE = 0, + SKL_CL_DMA_BUF_COMPLETE, + SKL_CL_DMA_ERR, /* TODO: Expand the error states */ +}; + +struct sst_dsp; + +struct skl_cl_dev_ops { + void (*cl_setup_bdle)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_data, + u32 **bdlp, int size, int with_ioc); + void (*cl_setup_controller)(struct sst_dsp *ctx, + struct snd_dma_buffer *dmab_bdl, + unsigned int max_size, u32 page_count); + void (*cl_setup_spb)(struct sst_dsp *ctx, + unsigned int size, bool enable); + void (*cl_cleanup_spb)(struct sst_dsp *ctx); + void (*cl_trigger)(struct sst_dsp *ctx, bool enable); + void (*cl_cleanup_controller)(struct sst_dsp *ctx); + int (*cl_copy_to_dmabuf)(struct sst_dsp *ctx, + const void *bin, u32 size); + void (*cl_stop_dma)(struct sst_dsp *ctx); +}; + +/** + * skl_cl_dev - holds information for code loader dma transfer + * + * @dmab_data: buffer pointer + * @dmab_bdl: buffer descriptor list + * @bufsize: ring buffer size + * @frags: Last valid buffer descriptor index in the BDL + * @curr_spib_pos: Current position in ring buffer + * @dma_buffer_offset: dma buffer offset + * @ops: operations supported on CL dma + * @wait_queue: wait queue to wake for wake event + * @wake_status: DMA wake status + * @wait_condition: condition to wait on wait queue + * @cl_dma_lock: for synchronized access to cldma + */ +struct skl_cl_dev { + struct snd_dma_buffer dmab_data; + struct snd_dma_buffer dmab_bdl; + + unsigned int bufsize; + unsigned int frags; + + unsigned int curr_spib_pos; + unsigned int dma_buffer_offset; + struct skl_cl_dev_ops ops; + + wait_queue_head_t wait_queue; + int wake_status; + bool wait_condition; +}; + #endif /* SKL_SST_CLDMA_H_ */ -- GitLab From 3e40a78461739d86fe1084c515ec227507ba993d Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 10 Jul 2015 22:18:42 +0530 Subject: [PATCH 0985/7006] ASoC: Intel: Skylake: Add code loader DMA APIs This patch adds the last piece of code loader DMA APIs by adding the code loader DMA APIs for the driver to use Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/common/sst-dsp-priv.h | 3 + sound/soc/intel/skylake/Makefile | 2 +- sound/soc/intel/skylake/skl-sst-cldma.c | 133 ++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-dsp.h | 6 ++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/sound/soc/intel/common/sst-dsp-priv.h b/sound/soc/intel/common/sst-dsp-priv.h index dd79648dfb3a5..cbd568eac033e 100644 --- a/sound/soc/intel/common/sst-dsp-priv.h +++ b/sound/soc/intel/common/sst-dsp-priv.h @@ -308,8 +308,11 @@ struct sst_dsp { /* SKL data */ + /* To allocate CL dma buffers */ + struct skl_dsp_loader_ops dsp_ops; struct skl_dsp_fw_ops fw_ops; int sst_state; + struct skl_cl_dev cl_dev; u32 intr_status; }; diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 10c1319f7ed52..eff3e1758b897 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,6 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-cldma.c b/sound/soc/intel/skylake/skl-sst-cldma.c index 44019eef61149..44748ba98da29 100644 --- a/sound/soc/intel/skylake/skl-sst-cldma.c +++ b/sound/soc/intel/skylake/skl-sst-cldma.c @@ -192,3 +192,136 @@ static void skl_cldma_fill_buffer(struct sst_dsp *ctx, unsigned int size, if (trigger) ctx->cl_dev.ops.cl_trigger(ctx, true); } + +/* + * The CL dma doesn't have any way to update the transfer status until a BDL + * buffer is fully transferred + * + * So Copying is divided in two parts. + * 1. Interrupt on buffer done where the size to be transferred is more than + * ring buffer size. + * 2. Polling on fw register to identify if data left to transferred doesn't + * fill the ring buffer. Caller takes care of polling the required status + * register to identify the transfer status. + */ +static int +skl_cldma_copy_to_buf(struct sst_dsp *ctx, const void *bin, u32 total_size) +{ + int ret = 0; + bool start = true; + unsigned int excess_bytes; + u32 size; + unsigned int bytes_left = total_size; + const void *curr_pos = bin; + + if (total_size <= 0) + return -EINVAL; + + dev_dbg(ctx->dev, "%s: Total binary size: %u\n", __func__, bytes_left); + + while (bytes_left) { + if (bytes_left > ctx->cl_dev.bufsize) { + + /* + * dma transfers only till the write pointer as + * updated in spib + */ + if (ctx->cl_dev.curr_spib_pos == 0) + ctx->cl_dev.curr_spib_pos = ctx->cl_dev.bufsize; + + size = ctx->cl_dev.bufsize; + skl_cldma_fill_buffer(ctx, size, curr_pos, true, start); + + start = false; + ret = skl_cldma_wait_interruptible(ctx); + if (ret < 0) { + skl_cldma_stop(ctx); + return ret; + } + + } else { + skl_cldma_int_disable(ctx); + + if ((ctx->cl_dev.curr_spib_pos + bytes_left) + <= ctx->cl_dev.bufsize) { + ctx->cl_dev.curr_spib_pos += bytes_left; + } else { + excess_bytes = bytes_left - + (ctx->cl_dev.bufsize - + ctx->cl_dev.curr_spib_pos); + ctx->cl_dev.curr_spib_pos = excess_bytes; + } + + size = bytes_left; + skl_cldma_fill_buffer(ctx, size, + curr_pos, false, start); + } + bytes_left -= size; + curr_pos = curr_pos + size; + } + + return ret; +} + +void skl_cldma_process_intr(struct sst_dsp *ctx) +{ + u8 cl_dma_intr_status; + + cl_dma_intr_status = + sst_dsp_shim_read_unlocked(ctx, SKL_ADSP_REG_CL_SD_STS); + + if (!(cl_dma_intr_status & SKL_CL_DMA_SD_INT_COMPLETE)) + ctx->cl_dev.wake_status = SKL_CL_DMA_ERR; + else + ctx->cl_dev.wake_status = SKL_CL_DMA_BUF_COMPLETE; + + ctx->cl_dev.wait_condition = true; + wake_up(&ctx->cl_dev.wait_queue); +} + +int skl_cldma_prepare(struct sst_dsp *ctx) +{ + int ret; + u32 *bdl; + + ctx->cl_dev.bufsize = SKL_MAX_BUFFER_SIZE; + + /* Allocate cl ops */ + ctx->cl_dev.ops.cl_setup_bdle = skl_cldma_setup_bdle; + ctx->cl_dev.ops.cl_setup_controller = skl_cldma_setup_controller; + ctx->cl_dev.ops.cl_setup_spb = skl_cldma_setup_spb; + ctx->cl_dev.ops.cl_cleanup_spb = skl_cldma_cleanup_spb; + ctx->cl_dev.ops.cl_trigger = skl_cldma_trigger; + ctx->cl_dev.ops.cl_cleanup_controller = skl_cldma_cleanup; + ctx->cl_dev.ops.cl_copy_to_dmabuf = skl_cldma_copy_to_buf; + ctx->cl_dev.ops.cl_stop_dma = skl_cldma_stop; + + /* Allocate buffer*/ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_data, ctx->cl_dev.bufsize); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for base fw failed: %x", ret); + return ret; + } + /* Setup Code loader BDL */ + ret = ctx->dsp_ops.alloc_dma_buf(ctx->dev, + &ctx->cl_dev.dmab_bdl, PAGE_SIZE); + if (ret < 0) { + dev_err(ctx->dev, "Alloc buffer for blde failed: %x", ret); + ctx->dsp_ops.free_dma_buf(ctx->dev, &ctx->cl_dev.dmab_data); + return ret; + } + bdl = (u32 *)ctx->cl_dev.dmab_bdl.area; + + /* Allocate BDLs */ + ctx->cl_dev.ops.cl_setup_bdle(ctx, &ctx->cl_dev.dmab_data, + &bdl, ctx->cl_dev.bufsize, 1); + ctx->cl_dev.ops.cl_setup_controller(ctx, &ctx->cl_dev.dmab_bdl, + ctx->cl_dev.bufsize, ctx->cl_dev.frags); + + ctx->cl_dev.curr_spib_pos = 0; + ctx->cl_dev.dma_buffer_offset = 0; + init_waitqueue_head(&ctx->cl_dev.wait_queue); + + return ret; +} diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index c2d28781309a1..e8ce1364bf7b9 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -17,7 +17,9 @@ #define __SKL_SST_DSP_H__ #include +#include "skl-sst-cldma.h" +struct sst_dsp; struct sst_dsp_device; /* Intel HD Audio General DSP Registers */ @@ -113,6 +115,10 @@ struct skl_dsp_loader_ops { struct snd_dma_buffer *dmab); }; +void skl_cldma_process_intr(struct sst_dsp *ctx); +void skl_cldma_int_disable(struct sst_dsp *ctx); +int skl_cldma_prepare(struct sst_dsp *ctx); + void skl_dsp_set_state_locked(struct sst_dsp *ctx, int state); struct sst_dsp *skl_dsp_ctx_init(struct device *dev, struct sst_dsp_device *sst_dev, int irq); -- GitLab From 6cb0033380ec6297589e68bfcf19aeda7ba95e99 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 10 Jul 2015 22:18:43 +0530 Subject: [PATCH 0986/7006] ASoC: Intel: Skylake: Process code loader DMA interrupt The code loader DMA interrupt is received by main interrupt handler which dispatches it to cldma routines Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-dsp.c | 5 +++++ sound/soc/intel/skylake/skl-sst-ipc.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/sound/soc/intel/skylake/skl-sst-dsp.c b/sound/soc/intel/skylake/skl-sst-dsp.c index 313ca7c6ca7f9..94875b008b0b8 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.c +++ b/sound/soc/intel/skylake/skl-sst-dsp.c @@ -267,6 +267,11 @@ irqreturn_t skl_dsp_sst_interrupt(int irq, void *dev_id) result = IRQ_WAKE_THREAD; } + if (val & SKL_ADSPIS_CL_DMA) { + skl_cldma_int_disable(ctx); + result = IRQ_WAKE_THREAD; + } + spin_unlock(&ctx->spinlock); return result; diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index 94be6cbf2698b..bd5ac4165151e 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -375,6 +375,9 @@ irqreturn_t skl_dsp_irq_thread_handler(int irq, void *context) u32 hipcie, hipct, hipcte; int ipc_irq = 0; + if (dsp->intr_status & SKL_ADSPIS_CL_DMA) + skl_cldma_process_intr(dsp); + /* Here we handle IPC interrupts only */ if (!(dsp->intr_status & SKL_ADSPIS_IPC)) return IRQ_NONE; -- GitLab From a750ba5f5a564732ed2be87de836a5a74f9cc586 Mon Sep 17 00:00:00 2001 From: "Subhransu S. Prusty" Date: Fri, 10 Jul 2015 22:18:44 +0530 Subject: [PATCH 0987/7006] ASoC: Intel: Skylake: Add SKL DSP initialization This adds the dsp and ipc initialization for the Skylake platform. It also requests firmware and uses code loader dma to load it. Signed-off-by: Subhransu S. Prusty Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/Makefile | 3 +- sound/soc/intel/skylake/skl-sst-dsp.h | 11 + sound/soc/intel/skylake/skl-sst-ipc.c | 2 + sound/soc/intel/skylake/skl-sst.c | 280 ++++++++++++++++++++++++++ 4 files changed, 295 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-sst.c diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index eff3e1758b897..1fccb378e62ce 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -3,6 +3,7 @@ snd-soc-skl-objs := skl.o skl-pcm.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o # Skylake IPC Support -snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o +snd-soc-skl-ipc-objs := skl-sst-ipc.o skl-sst-dsp.o skl-sst-cldma.o \ + skl-sst.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl-ipc.o diff --git a/sound/soc/intel/skylake/skl-sst-dsp.h b/sound/soc/intel/skylake/skl-sst-dsp.h index e8ce1364bf7b9..6bfcef449bdc5 100644 --- a/sound/soc/intel/skylake/skl-sst-dsp.h +++ b/sound/soc/intel/skylake/skl-sst-dsp.h @@ -16,10 +16,12 @@ #ifndef __SKL_SST_DSP_H__ #define __SKL_SST_DSP_H__ +#include #include #include "skl-sst-cldma.h" struct sst_dsp; +struct skl_sst; struct sst_dsp_device; /* Intel HD Audio General DSP Registers */ @@ -62,6 +64,11 @@ struct sst_dsp_device; #define SKL_ADSP_W1_SZ 0x1000 +#define SKL_FW_STS_MASK 0xf + +#define SKL_FW_INIT 0x1 +#define SKL_FW_RFW_START 0xf + #define SKL_ADSPIC_IPC 1 #define SKL_ADSPIS_IPC 1 @@ -106,6 +113,7 @@ struct skl_dsp_fw_ops { int (*parse_fw)(struct sst_dsp *ctx); int (*set_state_D0)(struct sst_dsp *ctx); int (*set_state_D3)(struct sst_dsp *ctx); + unsigned int (*get_fw_errcode)(struct sst_dsp *ctx); }; struct skl_dsp_loader_ops { @@ -130,5 +138,8 @@ int skl_dsp_sleep(struct sst_dsp *ctx); void skl_dsp_free(struct sst_dsp *dsp); int skl_dsp_boot(struct sst_dsp *ctx); +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp); +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx); #endif /*__SKL_SST_DSP_H__*/ diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index bd5ac4165151e..c0d0928613375 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -496,6 +496,8 @@ void skl_ipc_free(struct sst_generic_ipc *ipc) /* Disable IPC BUSY interrupt */ sst_dsp_shim_update_bits(ipc->dsp, SKL_ADSP_REG_HIPCCTL, SKL_ADSP_REG_HIPCCTL_BUSY, 0); + + sst_ipc_fini(ipc); } int skl_ipc_create_pipeline(struct sst_generic_ipc *ipc, diff --git a/sound/soc/intel/skylake/skl-sst.c b/sound/soc/intel/skylake/skl-sst.c new file mode 100644 index 0000000000000..c18ea51b7484d --- /dev/null +++ b/sound/soc/intel/skylake/skl-sst.c @@ -0,0 +1,280 @@ +/* + * skl-sst.c - HDA DSP library functions for SKL platform + * + * Copyright (C) 2014-15, Intel Corporation. + * Author:Rafal Redzimski + * Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" +#include "../common/sst-ipc.h" +#include "skl-sst-ipc.h" + +#define SKL_BASEFW_TIMEOUT 300 +#define SKL_INIT_TIMEOUT 1000 + +/* Intel HD Audio SRAM Window 0*/ +#define SKL_ADSP_SRAM0_BASE 0x8000 + +/* Firmware status window */ +#define SKL_ADSP_FW_STATUS SKL_ADSP_SRAM0_BASE +#define SKL_ADSP_ERROR_CODE (SKL_ADSP_FW_STATUS + 0x4) + +#define SKL_INSTANCE_ID 0 +#define SKL_BASE_FW_MODULE_ID 0 + +static bool skl_check_fw_status(struct sst_dsp *ctx, u32 status) +{ + u32 cur_sts; + + cur_sts = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS) & SKL_FW_STS_MASK; + + return (cur_sts == status); +} + +static int skl_transfer_firmware(struct sst_dsp *ctx, + const void *basefw, u32 base_fw_size) +{ + int ret = 0; + + ret = ctx->cl_dev.ops.cl_copy_to_dmabuf(ctx, basefw, base_fw_size); + if (ret < 0) + return ret; + + ret = sst_dsp_register_poll(ctx, + SKL_ADSP_FW_STATUS, + SKL_FW_STS_MASK, + SKL_FW_RFW_START, + SKL_BASEFW_TIMEOUT, + "Firmware boot"); + + ctx->cl_dev.ops.cl_stop_dma(ctx); + + return ret; +} + +static int skl_load_base_firmware(struct sst_dsp *ctx) +{ + int ret = 0, i; + const struct firmware *fw = NULL; + struct skl_sst *skl = ctx->thread_context; + u32 reg; + + ret = request_firmware(&fw, "dsp_fw_release.bin", ctx->dev); + if (ret < 0) { + dev_err(ctx->dev, "Request firmware failed %d\n", ret); + skl_dsp_disable_core(ctx); + return -EIO; + } + + /* enable Interrupt */ + skl_ipc_int_enable(ctx); + skl_ipc_op_int_enable(ctx); + + /* check ROM Status */ + for (i = SKL_INIT_TIMEOUT; i > 0; --i) { + if (skl_check_fw_status(ctx, SKL_FW_INIT)) { + dev_dbg(ctx->dev, + "ROM loaded, we can continue with FW loading\n"); + break; + } + mdelay(1); + } + if (!i) { + reg = sst_dsp_shim_read(ctx, SKL_ADSP_FW_STATUS); + dev_err(ctx->dev, + "Timeout waiting for ROM init done, reg:0x%x\n", reg); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + ret = skl_transfer_firmware(ctx, fw->data, fw->size); + if (ret < 0) { + dev_err(ctx->dev, "Transfer firmware failed%d\n", ret); + goto skl_load_base_firmware_failed; + } else { + ret = wait_event_timeout(skl->boot_wait, skl->boot_complete, + msecs_to_jiffies(SKL_IPC_BOOT_MSECS)); + if (ret == 0) { + dev_err(ctx->dev, "DSP boot failed, FW Ready timed-out\n"); + ret = -EIO; + goto skl_load_base_firmware_failed; + } + + dev_dbg(ctx->dev, "Download firmware successful%d\n", ret); + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + } + release_firmware(fw); + + return 0; + +skl_load_base_firmware_failed: + skl_dsp_disable_core(ctx); + release_firmware(fw); + return ret; +} + +static int skl_set_dsp_D0(struct sst_dsp *ctx) +{ + int ret; + + ret = skl_load_base_firmware(ctx); + if (ret < 0) { + dev_err(ctx->dev, "unable to load firmware\n"); + return ret; + } + + skl_dsp_set_state_locked(ctx, SKL_DSP_RUNNING); + + return ret; +} + +static int skl_set_dsp_D3(struct sst_dsp *ctx) +{ + int ret; + struct skl_ipc_dxstate_info dx; + struct skl_sst *skl = ctx->thread_context; + + dev_dbg(ctx->dev, "In %s:\n", __func__); + mutex_lock(&ctx->mutex); + if (!is_skl_dsp_running(ctx)) { + mutex_unlock(&ctx->mutex); + return 0; + } + mutex_unlock(&ctx->mutex); + + dx.core_mask = SKL_DSP_CORE0_MASK; + dx.dx_mask = SKL_IPC_D3_MASK; + ret = skl_ipc_set_dx(&skl->ipc, SKL_INSTANCE_ID, SKL_BASE_FW_MODULE_ID, &dx); + if (ret < 0) { + dev_err(ctx->dev, "Failed to set DSP to D3 state\n"); + return ret; + } + + ret = skl_dsp_disable_core(ctx); + if (ret < 0) { + dev_err(ctx->dev, "disable dsp core failed ret: %d\n", ret); + ret = -EIO; + } + skl_dsp_set_state_locked(ctx, SKL_DSP_RESET); + + return ret; +} + +static unsigned int skl_get_errorcode(struct sst_dsp *ctx) +{ + return sst_dsp_shim_read(ctx, SKL_ADSP_ERROR_CODE); +} + +static struct skl_dsp_fw_ops skl_fw_ops = { + .set_state_D0 = skl_set_dsp_D0, + .set_state_D3 = skl_set_dsp_D3, + .load_fw = skl_load_base_firmware, + .get_fw_errcode = skl_get_errorcode, +}; + +static struct sst_ops skl_ops = { + .irq_handler = skl_dsp_sst_interrupt, + .write = sst_shim32_write, + .read = sst_shim32_read, + .ram_read = sst_memcpy_fromio_32, + .ram_write = sst_memcpy_toio_32, + .free = skl_dsp_free, +}; + +static struct sst_dsp_device skl_dev = { + .thread = skl_dsp_irq_thread_handler, + .ops = &skl_ops, +}; + +int skl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, + struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) +{ + struct skl_sst *skl; + struct sst_dsp *sst; + int ret; + + skl = devm_kzalloc(dev, sizeof(*skl), GFP_KERNEL); + if (skl == NULL) + return -ENOMEM; + + skl->dev = dev; + skl_dev.thread_context = skl; + + skl->dsp = skl_dsp_ctx_init(dev, &skl_dev, irq); + if (!skl->dsp) { + dev_err(skl->dev, "%s: no device\n", __func__); + return -ENODEV; + } + + sst = skl->dsp; + + sst->addr.lpe = mmio_base; + sst->addr.shim = mmio_base; + sst_dsp_mailbox_init(sst, (SKL_ADSP_SRAM0_BASE + SKL_ADSP_W0_STAT_SZ), + SKL_ADSP_W0_UP_SZ, SKL_ADSP_SRAM1_BASE, SKL_ADSP_W1_SZ); + + sst->dsp_ops = dsp_ops; + sst->fw_ops = skl_fw_ops; + + ret = skl_ipc_init(dev, skl); + if (ret) + return ret; + + skl->boot_complete = false; + init_waitqueue_head(&skl->boot_wait); + + ret = skl_dsp_boot(sst); + if (ret < 0) { + dev_err(skl->dev, "Boot dsp core failed ret: %d", ret); + goto free_ipc; + } + + ret = skl_cldma_prepare(sst); + if (ret < 0) { + dev_err(dev, "CL dma prepare failed : %d", ret); + goto free_ipc; + } + + + ret = sst->fw_ops.load_fw(sst); + if (ret < 0) { + dev_err(dev, "Load base fw failed : %d", ret); + return ret; + } + + if (dsp) + *dsp = skl; + + return 0; + +free_ipc: + skl_ipc_free(&skl->ipc); + return ret; +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_init); + +void skl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) +{ + skl_ipc_free(&ctx->ipc); + ctx->dsp->cl_dev.ops.cl_cleanup_controller(ctx->dsp); + ctx->dsp->ops->free(ctx->dsp); +} +EXPORT_SYMBOL_GPL(skl_sst_dsp_cleanup); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Intel Skylake IPC driver"); -- GitLab From 28f3b6f113186ff69bdc5e63126ae7fd5e35a138 Mon Sep 17 00:00:00 2001 From: Omair M Abdullah Date: Fri, 10 Jul 2015 22:18:45 +0530 Subject: [PATCH 0988/7006] ASoC: Intel: Skylake: Print error code in IPC for SKL Signed-off-by: Omair M Abdullah Signed-off-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/skl-sst-ipc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sound/soc/intel/skylake/skl-sst-ipc.c b/sound/soc/intel/skylake/skl-sst-ipc.c index c0d0928613375..937a0a3a63a0f 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.c +++ b/sound/soc/intel/skylake/skl-sst-ipc.c @@ -362,6 +362,12 @@ static void skl_ipc_process_reply(struct sst_generic_ipc *ipc, break; } + if (reply != IPC_GLB_REPLY_SUCCESS) { + dev_err(ipc->dev, "ipc FW reply: reply=%d", reply); + dev_err(ipc->dev, "FW Error Code: %u\n", + ipc->dsp->fw_ops.get_fw_errcode(ipc->dsp)); + } + list_del(&msg->list); sst_ipc_tx_msg_reply_complete(ipc, msg); } -- GitLab From e40da86a37f64c73b810bc7a63d77c44dc61accb Mon Sep 17 00:00:00 2001 From: Tim Howe Date: Thu, 16 Jul 2015 14:51:40 -0500 Subject: [PATCH 0989/7006] ASoC: cs4349: Add support for Cirrus Logic CS4349 Signed-off-by: Tim Howe Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/cs4349.txt | 19 + sound/soc/codecs/Kconfig | 6 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/cs4349.c | 401 ++++++++++++++++++ sound/soc/codecs/cs4349.h | 146 +++++++ 5 files changed, 574 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/cs4349.txt create mode 100644 sound/soc/codecs/cs4349.c create mode 100644 sound/soc/codecs/cs4349.h diff --git a/Documentation/devicetree/bindings/sound/cs4349.txt b/Documentation/devicetree/bindings/sound/cs4349.txt new file mode 100644 index 0000000000000..54c117b59dba5 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/cs4349.txt @@ -0,0 +1,19 @@ +CS4349 audio CODEC + +Required properties: + + - compatible : "cirrus,cs4349" + + - reg : the I2C address of the device for I2C + +Optional properties: + + - reset-gpios : a GPIO spec for the reset pin. + +Example: + +codec: cs4349@48 { + compatible = "cirrus,cs4349"; + reg = <0x48>; + reset-gpios = <&gpio 54 0>; +}; diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce8ba387..6a759d13ef22f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -53,6 +53,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_CS4271_I2C if I2C select SND_SOC_CS4271_SPI if SPI_MASTER select SND_SOC_CS42XX8_I2C if I2C + select SND_SOC_CS4349 if I2C select SND_SOC_CX20442 if TTY select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI select SND_SOC_DA7213 if I2C @@ -403,6 +404,11 @@ config SND_SOC_CS42XX8_I2C select SND_SOC_CS42XX8 select REGMAP_I2C +# Cirrus Logic CS4349 HiFi DAC +config SND_SOC_CS4349 + tristate "Cirrus Logic CS4349 CODEC" + depends on I2C + config SND_SOC_CX20442 tristate depends on TTY diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d972cb36..f19e8d29f89dd 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -45,6 +45,7 @@ snd-soc-cs4271-i2c-objs := cs4271-i2c.o snd-soc-cs4271-spi-objs := cs4271-spi.o snd-soc-cs42xx8-objs := cs42xx8.o snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o +snd-soc-cs4349-objs := cs4349.o snd-soc-cx20442-objs := cx20442.o snd-soc-da7210-objs := da7210.o snd-soc-da7213-objs := da7213.o @@ -232,6 +233,7 @@ obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o +obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c new file mode 100644 index 0000000000000..a8df8a7496071 --- /dev/null +++ b/sound/soc/codecs/cs4349.c @@ -0,0 +1,401 @@ +/* + * cs4349.c -- CS4349 ALSA Soc Audio driver + * + * Copyright 2015 Cirrus Logic, Inc. + * + * Authors: Tim Howe + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cs4349.h" + + +static const struct reg_default cs4349_reg_defaults[] = { + { 2, 0x00 }, /* r02 - Mode Control */ + { 3, 0x09 }, /* r03 - Volume, Mixing and Inversion Control */ + { 4, 0x81 }, /* r04 - Mute Control */ + { 5, 0x00 }, /* r05 - Channel A Volume Control */ + { 6, 0x00 }, /* r06 - Channel B Volume Control */ + { 7, 0xB1 }, /* r07 - Ramp and Filter Control */ + { 8, 0x1C }, /* r08 - Misc. Control */ +}; + +/* Private data for the CS4349 */ +struct cs4349_private { + struct regmap *regmap; + struct cs4349_platform_data pdata; + struct gpio_desc *reset_gpio; + unsigned int mode; + int rate; +}; + +static bool cs4349_readable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS4349_CHIPID: + case CS4349_MODE: + case CS4349_VMI: + case CS4349_MUTE: + case CS4349_VOLA: + case CS4349_VOLB: + case CS4349_RMPFLT: + case CS4349_MISC: + return true; + default: + return false; + } +} + +static int cs4349_set_dai_fmt(struct snd_soc_dai *codec_dai, + unsigned int format) +{ + struct snd_soc_codec *codec = codec_dai->codec; + struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); + unsigned int fmt; + + fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; + + switch (fmt) { + case SND_SOC_DAIFMT_I2S: + case SND_SOC_DAIFMT_LEFT_J: + case SND_SOC_DAIFMT_RIGHT_J: + cs4349->mode = format & SND_SOC_DAIFMT_FORMAT_MASK; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_codec *codec = rtd->codec; + struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); + int mode, fmt, ret; + + mode = snd_soc_read(codec, CS4349_MODE); + cs4349->rate = params_rate(params); + + switch (cs4349->mode) { + case SND_SOC_DAIFMT_I2S: + mode |= MODE_FORMAT(DIF_I2S); + break; + case SND_SOC_DAIFMT_LEFT_J: + mode |= MODE_FORMAT(DIF_LEFT_JST); + break; + case SND_SOC_DAIFMT_RIGHT_J: + switch (params_width(params)) { + case 16: + fmt = DIF_RGHT_JST16; + break; + case 24: + fmt = DIF_RGHT_JST24; + break; + default: + return -EINVAL; + } + mode |= MODE_FORMAT(fmt); + break; + default: + return -EINVAL; + } + + ret = snd_soc_write(codec, CS4349_MODE, mode); + if (ret < 0) + return ret; + + return 0; +} + +static int cs4349_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + int reg; + + reg = 0; + if (mute) + reg = MUTE_AB_MASK; + + return snd_soc_update_bits(codec, CS4349_MUTE, MUTE_AB_MASK, reg); +} + +static DECLARE_TLV_DB_SCALE(dig_tlv, -12750, 50, 0); + +static const char * const chan_mix_texts[] = { + "Mute", "MuteA", "MuteA SwapB", "MuteA MonoB", "SwapA MuteB", + "BothR", "Swap", "SwapA MonoB", "MuteB", "Normal", "BothL", + "MonoB", "MonoA MuteB", "MonoA", "MonoA SwapB", "Mono", + /*Normal == Channel A = Left, Channel B = Right*/ +}; + +static const char * const fm_texts[] = { + "Auto", "Single", "Double", "Quad", +}; + +static const char * const deemph_texts[] = { + "None", "44.1k", "48k", "32k", +}; + +static const char * const softr_zeroc_texts[] = { + "Immediate", "Zero Cross", "Soft Ramp", "SR on ZC", +}; + +static int deemph_values[] = { + 0, 4, 8, 12, +}; + +static int softr_zeroc_values[] = { + 0, 64, 128, 192, +}; + +static const struct soc_enum chan_mix_enum = + SOC_ENUM_SINGLE(CS4349_VMI, 0, + ARRAY_SIZE(chan_mix_texts), + chan_mix_texts); + +static const struct soc_enum fm_mode_enum = + SOC_ENUM_SINGLE(CS4349_MODE, 0, + ARRAY_SIZE(fm_texts), + fm_texts); + +static SOC_VALUE_ENUM_SINGLE_DECL(deemph_enum, CS4349_MODE, 0, DEM_MASK, + deemph_texts, deemph_values); + +static SOC_VALUE_ENUM_SINGLE_DECL(softr_zeroc_enum, CS4349_RMPFLT, 0, + SR_ZC_MASK, softr_zeroc_texts, + softr_zeroc_values); + +static const struct snd_kcontrol_new cs4349_snd_controls[] = { + SOC_DOUBLE_R_TLV("Master Playback Volume", + CS4349_VOLA, CS4349_VOLB, 0, 0xFF, 1, dig_tlv), + SOC_ENUM("Functional Mode", fm_mode_enum), + SOC_ENUM("De-Emphasis Control", deemph_enum), + SOC_ENUM("Soft Ramp Zero Cross Control", softr_zeroc_enum), + SOC_ENUM("Channel Mixer", chan_mix_enum), + SOC_SINGLE("VolA = VolB Switch", CS4349_VMI, 7, 1, 0), + SOC_SINGLE("InvertA Switch", CS4349_VMI, 6, 1, 0), + SOC_SINGLE("InvertB Switch", CS4349_VMI, 5, 1, 0), + SOC_SINGLE("Auto-Mute Switch", CS4349_MUTE, 7, 1, 0), + SOC_SINGLE("MUTEC A = B Switch", CS4349_MUTE, 5, 1, 0), + SOC_SINGLE("Soft Ramp Up Switch", CS4349_RMPFLT, 5, 1, 0), + SOC_SINGLE("Soft Ramp Down Switch", CS4349_RMPFLT, 4, 1, 0), + SOC_SINGLE("Slow Roll Off Filter Switch", CS4349_RMPFLT, 2, 1, 0), + SOC_SINGLE("Freeze Switch", CS4349_MISC, 5, 1, 0), + SOC_SINGLE("Popguard Switch", CS4349_MISC, 4, 1, 0), +}; + +static const struct snd_soc_dapm_widget cs4349_dapm_widgets[] = { + SND_SOC_DAPM_DAC("HiFi DAC", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUTPUT("OutputA"), + SND_SOC_DAPM_OUTPUT("OutputB"), +}; + +static const struct snd_soc_dapm_route cs4349_routes[] = { + {"DAC Playback", NULL, "OutputA"}, + {"DAC Playback", NULL, "OutputB"}, + + {"OutputA", NULL, "HiFi DAC"}, + {"OutputB", NULL, "HiFi DAC"}, +}; + +#define CS4349_PCM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \ + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | \ + SNDRV_PCM_FMTBIT_S18_3LE | SNDRV_PCM_FMTBIT_S18_3BE | \ + SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE | \ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | \ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | \ + SNDRV_PCM_FMTBIT_S32_LE) + +#define CS4349_PCM_RATES SNDRV_PCM_RATE_8000_192000 + +static const struct snd_soc_dai_ops cs4349_dai_ops = { + .hw_params = cs4349_pcm_hw_params, + .set_fmt = cs4349_set_dai_fmt, + .digital_mute = cs4349_digital_mute, +}; + +static struct snd_soc_dai_driver cs4349_dai = { + .name = "cs4349_hifi", + .playback = { + .stream_name = "DAC Playback", + .channels_min = 1, + .channels_max = 2, + .rates = CS4349_PCM_RATES, + .formats = CS4349_PCM_FORMATS, + }, + .ops = &cs4349_dai_ops, + .symmetric_rates = 1, +}; + +static struct snd_soc_codec_driver soc_codec_dev_cs4349 = { + .controls = cs4349_snd_controls, + .num_controls = ARRAY_SIZE(cs4349_snd_controls), + + .dapm_widgets = cs4349_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs4349_dapm_widgets), + .dapm_routes = cs4349_routes, + .num_dapm_routes = ARRAY_SIZE(cs4349_routes), +}; + +static struct regmap_config cs4349_regmap = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = CS4349_NUMREGS, + .reg_defaults = cs4349_reg_defaults, + .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), + .readable_reg = cs4349_readable_register, + .cache_type = REGCACHE_RBTREE, +}; + +static int cs4349_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs4349_private *cs4349; + struct cs4349_platform_data *pdata = dev_get_platdata(&client->dev); + int ret = 0; + + cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL); + if (!cs4349) + return -ENOMEM; + + cs4349->regmap = devm_regmap_init_i2c(client, &cs4349_regmap); + if (IS_ERR(cs4349->regmap)) { + ret = PTR_ERR(cs4349->regmap); + dev_err(&client->dev, "regmap_init() failed: %d\n", ret); + return ret; + } + + if (pdata) + cs4349->pdata = *pdata; + + /* Reset the Device */ + cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev, + "reset", GPIOD_OUT_LOW); + if (IS_ERR(cs4349->reset_gpio)) + return PTR_ERR(cs4349->reset_gpio); + + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + + i2c_set_clientdata(client, cs4349); + + return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4349, + &cs4349_dai, 1); +} + +static int cs4349_i2c_remove(struct i2c_client *client) +{ + struct cs4349_private *cs4349 = i2c_get_clientdata(client); + + snd_soc_unregister_codec(&client->dev); + + /* Hold down reset */ + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + + return 0; +} + +#ifdef CONFIG_PM +static int cs4349_runtime_suspend(struct device *dev) +{ + struct cs4349_private *cs4349 = dev_get_drvdata(dev); + struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + int ret; + + ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 1); + if (ret < 0) + return ret; + + regcache_cache_only(cs4349->regmap, true); + + /* Hold down reset */ + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + + return 0; +} + +static int cs4349_runtime_resume(struct device *dev) +{ + struct cs4349_private *cs4349 = dev_get_drvdata(dev); + struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); + int ret; + + ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 0); + if (ret < 0) + return ret; + + if (cs4349->reset_gpio) + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + + regcache_cache_only(cs4349->regmap, false); + regcache_sync(cs4349->regmap); + + return 0; +} +#endif + +static const struct dev_pm_ops cs4349_runtime_pm = { + SET_RUNTIME_PM_OPS(cs4349_runtime_suspend, cs4349_runtime_resume, + NULL) +}; + +static const struct of_device_id cs4349_of_match[] = { + { .compatible = "cirrus,cs4349", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, cs4349_of_match); + +static const struct i2c_device_id cs4349_i2c_id[] = { + {"cs4349", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs4349_i2c_id); + +static struct i2c_driver cs4349_i2c_driver = { + .driver = { + .name = "cs4349", + .owner = THIS_MODULE, + .of_match_table = cs4349_of_match, + }, + .id_table = cs4349_i2c_id, + .probe = cs4349_i2c_probe, + .remove = cs4349_i2c_remove, +}; + +module_i2c_driver(cs4349_i2c_driver); + +MODULE_AUTHOR("Tim Howe "); +MODULE_DESCRIPTION("Cirrus Logic CS4349 ALSA SoC Codec Driver"); +MODULE_LICENSE("GPL"); diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h new file mode 100644 index 0000000000000..3884a8907d23d --- /dev/null +++ b/sound/soc/codecs/cs4349.h @@ -0,0 +1,146 @@ +/* + * ALSA SoC CS4349 codec driver + * + * Copyright 2015 Cirrus Logic, Inc. + * + * Author: Tim Howe + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + */ + +#ifndef __CS4349_H__ +#define __CS4349_H__ + +struct cs4349_platform_data { + + /* GPIO for Reset */ + unsigned int gpio_nreset; + +}; + +/* CS4349 registers addresses */ +#define CS4349_CHIPID 0x01 /* Device and Rev ID, Read Only */ +#define CS4349_MODE 0x02 /* Mode Control */ +#define CS4349_VMI 0x03 /* Volume, Mixing, Inversion Control */ +#define CS4349_MUTE 0x04 /* Mute Control */ +#define CS4349_VOLA 0x05 /* DAC Channel A Volume Control */ +#define CS4349_VOLB 0x06 /* DAC Channel B Volume Control */ +#define CS4349_RMPFLT 0x07 /* Ramp and Filter Control */ +#define CS4349_MISC 0x08 /* Power Down,Freeze Control,Pop Stop*/ + +#define CS4349_FIRSTREG 0x01 +#define CS4349_LASTREG 0x08 +#define CS4349_NUMREGS (CS4349_LASTREG - CS4349_FIRSTREG + 1) +#define CS4349_I2C_INCR 0x80 + + +/* Device and Revision ID */ +#define CS4349_REVA 0xF0 /* Rev A */ +#define CS4349_REVB 0xF1 /* Rev B */ +#define CS4349_REVC2 0xFF /* Rev C2 */ + + +/* PDN_DONE Poll Maximum + * If soft ramp is set it will take much longer to power down + * the system. + */ +#define PDN_POLL_MAX 900 + + +/* Bitfield Definitions */ + +/* CS4349_MODE */ +/* (Digital Interface Format, De-Emphasis Control, Functional Mode */ +#define DIF2 (1 << 6) +#define DIF1 (1 << 5) +#define DIF0 (1 << 4) +#define DEM1 (1 << 3) +#define DEM0 (1 << 2) +#define FM1 (1 << 1) +#define DIF_LEFT_JST 0x00 +#define DIF_I2S 0x01 +#define DIF_RGHT_JST16 0x02 +#define DIF_RGHT_JST24 0x03 +#define DIF_TDM0 0x04 +#define DIF_TDM1 0x05 +#define DIF_TDM2 0x06 +#define DIF_TDM3 0x07 +#define DIF_MASK 0x70 +#define MODE_FORMAT(x) (((x)&7)<<4) +#define DEM_MASK 0x0C +#define NO_DEM 0x00 +#define DEM_441 0x04 +#define DEM_48K 0x08 +#define DEM_32K 0x0C +#define FM_AUTO 0x00 +#define FM_SNGL 0x01 +#define FM_DBL 0x02 +#define FM_QUAD 0x03 +#define FM_SNGL_MIN 30000 +#define FM_SNGL_MAX 54000 +#define FM_DBL_MAX 108000 +#define FM_QUAD_MAX 216000 +#define FM_MASK 0x03 + +/* CS4349_VMI (VMI = Volume, Mixing and Inversion Controls) */ +#define VOLBISA (1 << 7) +#define VOLAISB (1 << 7) +/* INVERT_A only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */ +#define INVERT_A (1 << 6) +/* INVERT_B only available for Left Jstfd, Right Jstfd16 and Right Jstfd24 */ +#define INVERT_B (1 << 5) +#define ATAPI3 (1 << 3) +#define ATAPI2 (1 << 2) +#define ATAPI1 (1 << 1) +#define ATAPI0 (1 << 0) +#define MUTEAB 0x00 +#define MUTEA_RIGHTB 0x01 +#define MUTEA_LEFTB 0x02 +#define MUTEA_SUMLRDIV2B 0x03 +#define RIGHTA_MUTEB 0x04 +#define RIGHTA_RIGHTB 0x05 +#define RIGHTA_LEFTB 0x06 +#define RIGHTA_SUMLRDIV2B 0x07 +#define LEFTA_MUTEB 0x08 +#define LEFTA_RIGHTB 0x09 /* Default */ +#define LEFTA_LEFTB 0x0A +#define LEFTA_SUMLRDIV2B 0x0B +#define SUMLRDIV2A_MUTEB 0x0C +#define SUMLRDIV2A_RIGHTB 0x0D +#define SUMLRDIV2A_LEFTB 0x0E +#define SUMLRDIV2_AB 0x0F +#define CHMIX_MASK 0x0F + +/* CS4349_MUTE */ +#define AUTOMUTE (1 << 7) +#define MUTEC_AB (1 << 5) +#define MUTE_A (1 << 4) +#define MUTE_B (1 << 3) +#define MUTE_AB_MASK 0x18 + +/* CS4349_RMPFLT (Ramp and Filter Control) */ +#define SCZ1 (1 << 7) +#define SCZ0 (1 << 6) +#define RMP_UP (1 << 5) +#define RMP_DN (1 << 4) +#define FILT_SEL (1 << 2) +#define IMMDT_CHNG 0x31 +#define ZEROCRSS 0x71 +#define SOFT_RMP 0xB1 +#define SFTRMP_ZEROCRSS 0xF1 +#define SR_ZC_MASK 0xC0 + +/* CS4349_MISC */ +#define PWR_DWN (1 << 7) +#define FREEZE (1 << 5) +#define POPG_EN (1 << 4) + +#endif /* __CS4349_H__ */ -- GitLab From 5e3cdaa20816dd2fe4dc17d06a9f0dae0abc930c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:07:42 +0000 Subject: [PATCH 0990/7006] ASoC: core: add snd_soc_of_parse_audio_prefix() Current ASoC can add name_prefix for DAPM, and it is necessary for route settings. This patch adds snd_soc_of_parse_audio_prefix() for this purpose. It will be used with snd_soc_of_parse_audio_routing(). Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- include/sound/soc.h | 4 ++++ sound/soc/soc-core.c | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf9d54a9..75cd19ced804e 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1604,6 +1604,10 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, int snd_soc_of_parse_tdm_slot(struct device_node *np, unsigned int *slots, unsigned int *slot_width); +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname); int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname); unsigned int snd_soc_of_parse_daifmt(struct device_node *np, diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 3a4a5c0e3f973..fd15d5418647c 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3303,6 +3303,26 @@ int snd_soc_of_parse_tdm_slot(struct device_node *np, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_tdm_slot); +void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card, + struct snd_soc_codec_conf *codec_conf, + struct device_node *of_node, + const char *propname) +{ + struct device_node *np = card->dev->of_node; + const char *str; + int ret; + + ret = of_property_read_string(np, propname, &str); + if (ret < 0) { + /* no prefix is not error */ + return; + } + + codec_conf->of_node = of_node; + codec_conf->name_prefix = str; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_prefix); + int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, const char *propname) { -- GitLab From 8019ff6cfc0440415fcfb6352c58c3951e6ab053 Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Thu, 16 Jul 2015 16:36:21 +0100 Subject: [PATCH 0991/7006] regmap: Use reg_sequence for multi_reg_write / register_patch Separate the functionality using sequences of register writes from the functions that take register defaults. This change renames the arguments in order to support the extension of reg_sequence to take an optional delay to be applied after any given register in a sequence is written. This avoids adding an int to all register defaults, which could substantially increase memory usage for regmaps with large default tables. This also updates all the clients of multi_reg_write/register_patch. Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 2 +- drivers/base/regmap/regmap.c | 22 +++++++++++----------- drivers/gpu/drm/i2c/adv7511.c | 2 +- drivers/input/misc/drv260x.c | 6 +++--- drivers/input/misc/drv2665.c | 2 +- drivers/input/misc/drv2667.c | 4 ++-- drivers/mfd/arizona-core.c | 2 +- drivers/mfd/twl6040.c | 2 +- drivers/mfd/wm5102-tables.c | 6 +++--- drivers/mfd/wm5110-tables.c | 6 +++--- drivers/mfd/wm8994-core.c | 8 ++++---- drivers/mfd/wm8997-tables.c | 2 +- include/linux/regmap.h | 17 ++++++++++++++--- sound/soc/codecs/arizona.c | 2 +- sound/soc/codecs/cs35l32.c | 2 +- sound/soc/codecs/cs42l52.c | 2 +- sound/soc/codecs/da7210.c | 4 ++-- sound/soc/codecs/rt5640.c | 2 +- sound/soc/codecs/rt5645.c | 4 ++-- sound/soc/codecs/rt5651.c | 2 +- sound/soc/codecs/rt5670.c | 2 +- sound/soc/codecs/rt5677.c | 2 +- sound/soc/codecs/tlv320aic3x.c | 2 +- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm5100.c | 2 +- sound/soc/codecs/wm8962.c | 2 +- sound/soc/codecs/wm8993.c | 2 +- 27 files changed, 62 insertions(+), 51 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index b2b2849fc6d3b..873ddf91c9d3e 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -136,7 +136,7 @@ struct regmap { /* if set, the HW registers are known to match map->reg_defaults */ bool no_sync_defaults; - struct reg_default *patch; + struct reg_sequence *patch; int patch_regs; /* if set, converts bulk rw to single rw */ diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7111d04f26218..2cbb4502747d8 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1743,7 +1743,7 @@ EXPORT_SYMBOL_GPL(regmap_bulk_write); * relative. The page register has been written if that was neccessary. */ static int _regmap_raw_multi_reg_write(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, size_t num_regs) { int ret; @@ -1800,12 +1800,12 @@ static unsigned int _regmap_register_page(struct regmap *map, } static int _regmap_range_multi_paged_reg_write(struct regmap *map, - struct reg_default *regs, + struct reg_sequence *regs, size_t num_regs) { int ret; int i, n; - struct reg_default *base; + struct reg_sequence *base; unsigned int this_page = 0; /* * the set of registers are not neccessarily in order, but @@ -1843,7 +1843,7 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, } static int _regmap_multi_reg_write(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, size_t num_regs) { int i; @@ -1895,8 +1895,8 @@ static int _regmap_multi_reg_write(struct regmap *map, struct regmap_range_node *range; range = _regmap_range_lookup(map, reg); if (range) { - size_t len = sizeof(struct reg_default)*num_regs; - struct reg_default *base = kmemdup(regs, len, + size_t len = sizeof(struct reg_sequence)*num_regs; + struct reg_sequence *base = kmemdup(regs, len, GFP_KERNEL); if (!base) return -ENOMEM; @@ -1929,7 +1929,7 @@ static int _regmap_multi_reg_write(struct regmap *map, * A value of zero will be returned on success, a negative errno will be * returned in error cases. */ -int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, +int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs) { int ret; @@ -1962,7 +1962,7 @@ EXPORT_SYMBOL_GPL(regmap_multi_reg_write); * be returned in error cases. */ int regmap_multi_reg_write_bypassed(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, int num_regs) { int ret; @@ -2552,10 +2552,10 @@ EXPORT_SYMBOL_GPL(regmap_async_complete); * The caller must ensure that this function cannot be called * concurrently with either itself or regcache_sync(). */ -int regmap_register_patch(struct regmap *map, const struct reg_default *regs, +int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs) { - struct reg_default *p; + struct reg_sequence *p; int ret; bool bypass; @@ -2564,7 +2564,7 @@ int regmap_register_patch(struct regmap *map, const struct reg_default *regs, return 0; p = krealloc(map->patch, - sizeof(struct reg_default) * (map->patch_regs + num_regs), + sizeof(struct reg_sequence) * (map->patch_regs + num_regs), GFP_KERNEL); if (p) { memcpy(p + map->patch_regs, regs, num_regs * sizeof(*regs)); diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c index 2aaa3c88999e3..00416f23b5cb5 100644 --- a/drivers/gpu/drm/i2c/adv7511.c +++ b/drivers/gpu/drm/i2c/adv7511.c @@ -54,7 +54,7 @@ static struct adv7511 *encoder_to_adv7511(struct drm_encoder *encoder) } /* ADI recommended values for proper operation. */ -static const struct reg_default adv7511_fixed_registers[] = { +static const struct reg_sequence adv7511_fixed_registers[] = { { 0x98, 0x03 }, { 0x9a, 0xe0 }, { 0x9c, 0x30 }, diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index e5d60ecd29a4d..f5c9cf2f4073a 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -313,14 +313,14 @@ static void drv260x_close(struct input_dev *input) gpiod_set_value(haptics->enable_gpio, 0); } -static const struct reg_default drv260x_lra_cal_regs[] = { +static const struct reg_sequence drv260x_lra_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, { DRV260X_CTRL3, DRV260X_NG_THRESH_2 }, { DRV260X_FEEDBACK_CTRL, DRV260X_FB_REG_LRA_MODE | DRV260X_BRAKE_FACTOR_4X | DRV260X_LOOP_GAIN_HIGH }, }; -static const struct reg_default drv260x_lra_init_regs[] = { +static const struct reg_sequence drv260x_lra_init_regs[] = { { DRV260X_MODE, DRV260X_RT_PLAYBACK }, { DRV260X_A_TO_V_CTRL, DRV260X_AUDIO_HAPTICS_PEAK_20MS | DRV260X_AUDIO_HAPTICS_FILTER_125HZ }, @@ -337,7 +337,7 @@ static const struct reg_default drv260x_lra_init_regs[] = { { DRV260X_CTRL4, DRV260X_AUTOCAL_TIME_500MS }, }; -static const struct reg_default drv260x_erm_cal_regs[] = { +static const struct reg_sequence drv260x_erm_cal_regs[] = { { DRV260X_MODE, DRV260X_AUTO_CAL }, { DRV260X_A_TO_V_MIN_INPUT, DRV260X_AUDIO_HAPTICS_MIN_IN_VOLT }, { DRV260X_A_TO_V_MAX_INPUT, DRV260X_AUDIO_HAPTICS_MAX_IN_VOLT }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index 0afaa33de07d2..924456e3ca75d 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -132,7 +132,7 @@ static void drv2665_close(struct input_dev *input) "Failed to enter standby mode: %d\n", error); } -static const struct reg_default drv2665_init_regs[] = { +static const struct reg_sequence drv2665_init_regs[] = { { DRV2665_CTRL_2, 0 | DRV2665_10_MS_IDLE_TOUT }, { DRV2665_CTRL_1, DRV2665_25_VPP_GAIN }, }; diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index fc0fddf0896a7..047136aa646f2 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -262,14 +262,14 @@ static void drv2667_close(struct input_dev *input) "Failed to enter standby mode: %d\n", error); } -static const struct reg_default drv2667_init_regs[] = { +static const struct reg_sequence drv2667_init_regs[] = { { DRV2667_CTRL_2, 0 }, { DRV2667_CTRL_1, DRV2667_25_VPP_GAIN }, { DRV2667_WV_SEQ_0, 1 }, { DRV2667_WV_SEQ_1, 0 } }; -static const struct reg_default drv2667_page1_init[] = { +static const struct reg_sequence drv2667_page1_init[] = { { DRV2667_RAM_HDR_SZ, 0x05 }, { DRV2667_RAM_START_HI, 0x80 }, { DRV2667_RAM_START_LO, 0x06 }, diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index bebf58a06a6b2..66d50be119604 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -392,7 +392,7 @@ err: * Register patch to some of the CODECs internal write sequences * to ensure a clean exit from the low power sleep state. */ -static const struct reg_default wm5110_sleep_patch[] = { +static const struct reg_sequence wm5110_sleep_patch[] = { { 0x337A, 0xC100 }, { 0x337B, 0x0041 }, { 0x3300, 0xA210 }, diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c index c5265c1262c50..583dc33432f31 100644 --- a/drivers/mfd/twl6040.c +++ b/drivers/mfd/twl6040.c @@ -86,7 +86,7 @@ static const struct reg_default twl6040_defaults[] = { { 0x2E, 0x00 }, /* REG_STATUS (ro) */ }; -static struct reg_default twl6040_patch[] = { +static struct reg_sequence twl6040_patch[] = { /* * Select I2C bus access to dual access registers * Interrupt register is cleared on read diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index aeae6ec123b3a..423fb3730dc71 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -21,7 +21,7 @@ #define WM5102_NUM_AOD_ISR 2 #define WM5102_NUM_ISR 5 -static const struct reg_default wm5102_reva_patch[] = { +static const struct reg_sequence wm5102_reva_patch[] = { { 0x80, 0x0003 }, { 0x221, 0x0090 }, { 0x211, 0x0014 }, @@ -57,7 +57,7 @@ static const struct reg_default wm5102_reva_patch[] = { { 0x80, 0x0000 }, }; -static const struct reg_default wm5102_revb_patch[] = { +static const struct reg_sequence wm5102_revb_patch[] = { { 0x19, 0x0001 }, { 0x80, 0x0003 }, { 0x081, 0xE022 }, @@ -80,7 +80,7 @@ static const struct reg_default wm5102_revb_patch[] = { /* We use a function so we can use ARRAY_SIZE() */ int wm5102_patch(struct arizona *arizona) { - const struct reg_default *wm5102_patch; + const struct reg_sequence *wm5102_patch; int patch_size; switch (arizona->rev) { diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c index 12cad94b40354..26ce14f903fee 100644 --- a/drivers/mfd/wm5110-tables.c +++ b/drivers/mfd/wm5110-tables.c @@ -21,7 +21,7 @@ #define WM5110_NUM_AOD_ISR 2 #define WM5110_NUM_ISR 5 -static const struct reg_default wm5110_reva_patch[] = { +static const struct reg_sequence wm5110_reva_patch[] = { { 0x80, 0x3 }, { 0x44, 0x20 }, { 0x45, 0x40 }, @@ -134,7 +134,7 @@ static const struct reg_default wm5110_reva_patch[] = { { 0x209, 0x002A }, }; -static const struct reg_default wm5110_revb_patch[] = { +static const struct reg_sequence wm5110_revb_patch[] = { { 0x80, 0x3 }, { 0x36e, 0x0210 }, { 0x370, 0x0210 }, @@ -224,7 +224,7 @@ static const struct reg_default wm5110_revb_patch[] = { { 0x80, 0x0 }, }; -static const struct reg_default wm5110_revd_patch[] = { +static const struct reg_sequence wm5110_revd_patch[] = { { 0x80, 0x3 }, { 0x80, 0x3 }, { 0x393, 0x27 }, diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 53ae5af5d6e4f..0f4169a3a5d4c 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -243,21 +243,21 @@ static int wm8994_ldo_in_use(struct wm8994_pdata *pdata, int ldo) } #endif -static const struct reg_default wm8994_revc_patch[] = { +static const struct reg_sequence wm8994_revc_patch[] = { { 0x102, 0x3 }, { 0x56, 0x3 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const struct reg_default wm8958_reva_patch[] = { +static const struct reg_sequence wm8958_reva_patch[] = { { 0x102, 0x3 }, { 0xcb, 0x81 }, { 0x817, 0x0 }, { 0x102, 0x0 }, }; -static const struct reg_default wm1811_reva_patch[] = { +static const struct reg_sequence wm1811_reva_patch[] = { { 0x102, 0x3 }, { 0x56, 0xc07 }, { 0x5d, 0x7e }, @@ -326,7 +326,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) { struct wm8994_pdata *pdata; struct regmap_config *regmap_config; - const struct reg_default *regmap_patch = NULL; + const struct reg_sequence *regmap_patch = NULL; const char *devname; int ret, i, patch_regs = 0; int pulls = 0; diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c index c0c25d75aaccb..cab2c68f17378 100644 --- a/drivers/mfd/wm8997-tables.c +++ b/drivers/mfd/wm8997-tables.c @@ -17,7 +17,7 @@ #include "arizona.h" -static const struct reg_default wm8997_reva_patch[] = { +static const struct reg_sequence wm8997_reva_patch[] = { { 0x80, 0x0003 }, { 0x214, 0x0008 }, { 0x458, 0x0000 }, diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 59c55ea0f0b50..c9ef2ec69142e 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -50,6 +50,17 @@ struct reg_default { unsigned int def; }; +/** + * Register/value pairs for sequences of writes + * + * @reg: Register address. + * @def: Register value. + */ +struct reg_sequence { + unsigned int reg; + unsigned int def; +}; + #ifdef CONFIG_REGMAP enum regmap_endian { @@ -410,10 +421,10 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, const void *val, size_t val_len); int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, size_t val_count); -int regmap_multi_reg_write(struct regmap *map, const struct reg_default *regs, +int regmap_multi_reg_write(struct regmap *map, const struct reg_sequence *regs, int num_regs); int regmap_multi_reg_write_bypassed(struct regmap *map, - const struct reg_default *regs, + const struct reg_sequence *regs, int num_regs); int regmap_raw_write_async(struct regmap *map, unsigned int reg, const void *val, size_t val_len); @@ -450,7 +461,7 @@ void regcache_mark_dirty(struct regmap *map); bool regmap_check_range_table(struct regmap *map, unsigned int reg, const struct regmap_access_table *table); -int regmap_register_patch(struct regmap *map, const struct reg_default *regs, +int regmap_register_patch(struct regmap *map, const struct reg_sequence *regs, int num_regs); int regmap_parse_val(struct regmap *map, const void *buf, unsigned int *val); diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 802e05eae3e9d..5edd33fcd68c6 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1366,7 +1366,7 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec, { struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; - struct reg_default dac_comp[] = { + struct reg_sequence dac_comp[] = { { 0x80, 0x3 }, { ARIZONA_DAC_COMP_1, 0 }, { ARIZONA_DAC_COMP_2, 0 }, diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025b7e7ca..2813a1b0c949d 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -276,7 +276,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs35l32 = { }; /* Current and threshold powerup sequence Pg37 in datasheet */ -static const struct reg_default cs35l32_monitor_patch[] = { +static const struct reg_sequence cs35l32_monitor_patch[] = { { 0x00, 0x99 }, { 0x48, 0x17 }, diff --git a/sound/soc/codecs/cs42l52.c b/sound/soc/codecs/cs42l52.c index 4de52c9957ac5..8b2d059335949 100644 --- a/sound/soc/codecs/cs42l52.c +++ b/sound/soc/codecs/cs42l52.c @@ -1118,7 +1118,7 @@ static const struct snd_soc_codec_driver soc_codec_dev_cs42l52 = { }; /* Current and threshold powerup sequence Pg37 */ -static const struct reg_default cs42l52_threshold_patch[] = { +static const struct reg_sequence cs42l52_threshold_patch[] = { { 0x00, 0x99 }, { 0x3E, 0xBA }, diff --git a/sound/soc/codecs/da7210.c b/sound/soc/codecs/da7210.c index 21810e5f3321c..bf0fb3d4df227 100644 --- a/sound/soc/codecs/da7210.c +++ b/sound/soc/codecs/da7210.c @@ -1182,7 +1182,7 @@ static struct snd_soc_codec_driver soc_codec_dev_da7210 = { #if IS_ENABLED(CONFIG_I2C) -static struct reg_default da7210_regmap_i2c_patch[] = { +static struct reg_sequence da7210_regmap_i2c_patch[] = { /* System controller master disable */ { DA7210_STARTUP1, 0x00 }, @@ -1269,7 +1269,7 @@ static struct i2c_driver da7210_i2c_driver = { #if defined(CONFIG_SPI_MASTER) -static struct reg_default da7210_regmap_spi_patch[] = { +static struct reg_sequence da7210_regmap_spi_patch[] = { /* Dummy read to give two pulses over nCS for SPI */ { DA7210_AUX2, 0x00 }, { DA7210_AUX2, 0x00 }, diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index 9bc78e57513d7..1ed1f8895e124 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c @@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5640_ranges[] = { .window_len = 0x1, }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5640_PR_BASE + 0x3d, 0x3600}, {RT5640_PR_BASE + 0x12, 0x0aa8}, {RT5640_PR_BASE + 0x14, 0x0aaa}, diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc5..c0f4be430e703 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5645_ranges[] = { }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5645_PR_BASE + 0x3d, 0x3600}, {RT5645_PR_BASE + 0x1c, 0xfd20}, {RT5645_PR_BASE + 0x20, 0x611f}, @@ -63,7 +63,7 @@ static const struct reg_default init_list[] = { }; #define RT5645_INIT_REG_LEN ARRAY_SIZE(init_list) -static const struct reg_default rt5650_init_list[] = { +static const struct reg_sequence rt5650_init_list[] = { {0xf6, 0x0100}, }; diff --git a/sound/soc/codecs/rt5651.c b/sound/soc/codecs/rt5651.c index a3506e193abcd..db9b8667f136b 100644 --- a/sound/soc/codecs/rt5651.c +++ b/sound/soc/codecs/rt5651.c @@ -46,7 +46,7 @@ static const struct regmap_range_cfg rt5651_ranges[] = { .window_len = 0x1, }, }; -static struct reg_default init_list[] = { +static struct reg_sequence init_list[] = { {RT5651_PR_BASE + 0x3d, 0x3e00}, }; diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c index a9123d4141787..462a91f7cf683 100644 --- a/sound/soc/codecs/rt5670.c +++ b/sound/soc/codecs/rt5670.c @@ -51,7 +51,7 @@ static const struct regmap_range_cfg rt5670_ranges[] = { .window_len = 0x1, }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { { RT5670_PR_BASE + 0x14, 0x9a8a }, { RT5670_PR_BASE + 0x38, 0x3ba1 }, { RT5670_PR_BASE + 0x3d, 0x3640 }, diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 31d969ac11920..b897752514702 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -54,7 +54,7 @@ static const struct regmap_range_cfg rt5677_ranges[] = { }, }; -static const struct reg_default init_list[] = { +static const struct reg_sequence init_list[] = { {RT5677_ASRC_12, 0x0018}, {RT5677_PR_BASE + 0x3d, 0x364d}, {RT5677_PR_BASE + 0x17, 0x4fc0}, diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c index a7cf19b53fb2d..83ae1eb44d4fb 100644 --- a/sound/soc/codecs/tlv320aic3x.c +++ b/sound/soc/codecs/tlv320aic3x.c @@ -1668,7 +1668,7 @@ static const struct i2c_device_id aic3x_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic3x_i2c_id); -static const struct reg_default aic3007_class_d[] = { +static const struct reg_sequence aic3007_class_d[] = { /* Class-D speaker driver init; datasheet p. 46 */ { AIC3X_PAGE_SELECT, 0x0D }, { 0xD, 0x0D }, diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c83083285e532..6c607928fb9b2 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -897,7 +897,7 @@ static bool wm2200_readable_register(struct device *dev, unsigned int reg) } } -static const struct reg_default wm2200_reva_patch[] = { +static const struct reg_sequence wm2200_reva_patch[] = { { 0x07, 0x0003 }, { 0x102, 0x0200 }, { 0x203, 0x0084 }, diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd88c1af6..26d79bbb75999 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1247,7 +1247,7 @@ static const struct snd_soc_dapm_route wm5100_dapm_routes[] = { { "PWM2", NULL, "PWM2 Driver" }, }; -static const struct reg_default wm5100_reva_patches[] = { +static const struct reg_sequence wm5100_reva_patches[] = { { WM5100_AUDIO_IF_1_10, 0 }, { WM5100_AUDIO_IF_1_11, 1 }, { WM5100_AUDIO_IF_1_12, 2 }, diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd4f2962..05492e826aea7 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3495,7 +3495,7 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8962 = { }; /* Improve power consumption for IN4 DC measurement mode */ -static const struct reg_default wm8962_dc_measure[] = { +static const struct reg_sequence wm8962_dc_measure[] = { { 0xfd, 0x1 }, { 0xcc, 0x40 }, { 0xfd, 0 }, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index 8a8db8605dc2e..52ec64d8502d2 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -1595,7 +1595,7 @@ static int wm8993_resume(struct snd_soc_codec *codec) #endif /* Tune DC servo configuration */ -static struct reg_default wm8993_regmap_patch[] = { +static struct reg_sequence wm8993_regmap_patch[] = { { 0x44, 3 }, { 0x56, 3 }, { 0x44, 0 }, -- GitLab From 2de9d6006c190bb0f706e8404de94cd94293801f Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Thu, 16 Jul 2015 16:36:22 +0100 Subject: [PATCH 0992/7006] regmap: Apply optional delay in multi_reg_write/register_patch Add an optional delay_us field in reg_sequence to allow the client to specify a delay (in microseconds) to be applied after any given write in a sequence of writes. We treat a delay in a sequence the same way we treat a page change as they are logically similar in that you can coalesce all write before a delay (in the same way you can coalesce all writes before a page change is needed) Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 54 ++++++++++++++++++++++++++++++++---- include/linux/regmap.h | 5 +++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 2cbb4502747d8..b3a5aa5cd580c 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -18,6 +18,7 @@ #include #include #include +#include #define CREATE_TRACE_POINTS #include "trace.h" @@ -1807,10 +1808,12 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, int i, n; struct reg_sequence *base; unsigned int this_page = 0; + unsigned int page_change = 0; /* * the set of registers are not neccessarily in order, but * since the order of write must be preserved this algorithm - * chops the set each time the page changes + * chops the set each time the page changes. This also applies + * if there is a delay required at any point in the sequence. */ base = regs; for (i = 0, n = 0; i < num_regs; i++, n++) { @@ -1826,16 +1829,48 @@ static int _regmap_range_multi_paged_reg_write(struct regmap *map, this_page = win_page; if (win_page != this_page) { this_page = win_page; + page_change = 1; + } + } + + /* If we have both a page change and a delay make sure to + * write the regs and apply the delay before we change the + * page. + */ + + if (page_change || regs[i].delay_us) { + + /* For situations where the first write requires + * a delay we need to make sure we don't call + * raw_multi_reg_write with n=0 + * This can't occur with page breaks as we + * never write on the first iteration + */ + if (regs[i].delay_us && i == 0) + n = 1; + ret = _regmap_raw_multi_reg_write(map, base, n); if (ret != 0) return ret; + + if (regs[i].delay_us) + udelay(regs[i].delay_us); + base += n; n = 0; - } - ret = _regmap_select_page(map, &base[n].reg, range, 1); - if (ret != 0) - return ret; + + if (page_change) { + ret = _regmap_select_page(map, + &base[n].reg, + range, 1); + if (ret != 0) + return ret; + + page_change = 0; + } + } + } if (n > 0) return _regmap_raw_multi_reg_write(map, base, n); @@ -1854,6 +1889,9 @@ static int _regmap_multi_reg_write(struct regmap *map, ret = _regmap_write(map, regs[i].reg, regs[i].def); if (ret != 0) return ret; + + if (regs[i].delay_us) + udelay(regs[i].delay_us); } return 0; } @@ -1893,8 +1931,12 @@ static int _regmap_multi_reg_write(struct regmap *map, for (i = 0; i < num_regs; i++) { unsigned int reg = regs[i].reg; struct regmap_range_node *range; + + /* Coalesce all the writes between a page break or a delay + * in a sequence + */ range = _regmap_range_lookup(map, reg); - if (range) { + if (range || regs[i].delay_us) { size_t len = sizeof(struct reg_sequence)*num_regs; struct reg_sequence *base = kmemdup(regs, len, GFP_KERNEL); diff --git a/include/linux/regmap.h b/include/linux/regmap.h index c9ef2ec69142e..5a7cf2136c81f 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -51,14 +51,17 @@ struct reg_default { }; /** - * Register/value pairs for sequences of writes + * Register/value pairs for sequences of writes with an optional delay in + * microseconds to be applied after each write. * * @reg: Register address. * @def: Register value. + * @delay_us: Delay to be applied after the register write in microseconds */ struct reg_sequence { unsigned int reg; unsigned int def; + unsigned int delay_us; }; #ifdef CONFIG_REGMAP -- GitLab From b7419dd73606118b8797d49b53a9fbe2e2dfa863 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:08:05 +0000 Subject: [PATCH 0993/7006] ASoC: rsrc-card: use snd_soc_of_parse_audio_route/prefix for routing using common audio routing path method makes sense. Let's use snd_soc_of_parse_audio_route/prefix. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsrc-card.txt | 7 ++++++ sound/soc/sh/rcar/rsrc-card.c | 22 +++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt index c64155027288e..962748a8d9194 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt @@ -6,6 +6,7 @@ Required properties: - compatible : "renesas,rsrc-card," Examples with soctypes are: + - "renesas,rsrc-card" - "renesas,rsrc-card,lager" - "renesas,rsrc-card,koelsch" Optional properties: @@ -29,6 +30,12 @@ Optional subnode properties: - frame-inversion : bool property. Add this if the dai-link uses frame clock inversion. - convert-rate : platform specified sampling rate convert +- audio-prefix : see audio-routing +- audio-routing : A list of the connections between audio components. + Each entry is a pair of strings, the first being the connection's sink, + the second being the connection's source. Valid names for sources. + use audio-prefix if some components is using same sink/sources naming. + it can be used if compatible was "renesas,rsrc-card"; Required CPU/CODEC subnodes properties: diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 84e935711e29e..d61db9c385eaf 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c @@ -41,6 +41,7 @@ static const struct rsrc_card_of_data routes_of_ssi0_ak4642 = { static const struct of_device_id rsrc_card_of_match[] = { { .compatible = "renesas,rsrc-card,lager", .data = &routes_of_ssi0_ak4642 }, { .compatible = "renesas,rsrc-card,koelsch", .data = &routes_of_ssi0_ak4642 }, + { .compatible = "renesas,rsrc-card", }, {}, }; MODULE_DEVICE_TABLE(of, rsrc_card_of_match); @@ -242,8 +243,15 @@ static int rsrc_card_parse_links(struct device_node *np, snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); /* additional name prefix */ - priv->codec_conf.of_node = dai_link->codec_of_node; - priv->codec_conf.name_prefix = of_data->prefix; + if (of_data) { + priv->codec_conf.of_node = dai_link->codec_of_node; + priv->codec_conf.name_prefix = of_data->prefix; + } else { + snd_soc_of_parse_audio_prefix(&priv->snd_card, + &priv->codec_conf, + dai_link->codec_of_node, + "audio-prefix"); + } /* set dai_name */ snprintf(dai_props->dai_name, DAI_NAME_NUM, "be.%s", @@ -361,8 +369,14 @@ static int rsrc_card_parse_of(struct device_node *node, priv->snd_card.num_links = num; priv->snd_card.codec_conf = &priv->codec_conf; priv->snd_card.num_configs = 1; - priv->snd_card.of_dapm_routes = of_data->routes; - priv->snd_card.num_of_dapm_routes = of_data->num_routes; + + if (of_data) { + priv->snd_card.of_dapm_routes = of_data->routes; + priv->snd_card.num_of_dapm_routes = of_data->num_routes; + } else { + snd_soc_of_parse_audio_routing(&priv->snd_card, + "audio-routing"); + } /* Parse the card name from DT */ snd_soc_of_parse_card_name(&priv->snd_card, "card-name"); -- GitLab From afa700729646761f58cc068d86a37e09a70e4cf6 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:08:24 +0000 Subject: [PATCH 0994/7006] ASoC: rsnd: remove unnecessary 'out of memory' message from SSI Current checkpatch.pl indicates 'out of memory' message is unnecessary. Let's remove it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/ssi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 2fbe59f7f9b5a..d45b9a7e324ef 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c @@ -770,10 +770,8 @@ int rsnd_ssi_probe(struct platform_device *pdev, */ nr = info->ssi_info_nr; ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); - if (!ssi) { - dev_err(dev, "SSI allocate failed\n"); + if (!ssi) return -ENOMEM; - } priv->ssi = ssi; priv->ssi_nr = nr; -- GitLab From 33363f7a18f3baaa04b678aac8819c43296c8c9c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:08:44 +0000 Subject: [PATCH 0995/7006] ASoC: rsnd: remove unnecessary 'out of memory' message from SRC Current checkpatch.pl indicates 'out of memory' message is unnecessary. Let's remove it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c61c171801423..37927ca66162b 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -1047,10 +1047,8 @@ int rsnd_src_probe(struct platform_device *pdev, return 0; src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); - if (!src) { - dev_err(dev, "SRC allocate failed\n"); + if (!src) return -ENOMEM; - } priv->src_nr = nr; priv->src = src; -- GitLab From 6abcae32ea68899bfd4b770433860a71f8c3500b Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:09:07 +0000 Subject: [PATCH 0996/7006] ASoC: rsnd: remove unnecessary 'out of memory' message from DVC Current checkpatch.pl indicates 'out of memory' message is unnecessary. Let's remove it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 36fc020cbc180..dbf0da6ce8a52 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -354,10 +354,8 @@ int rsnd_dvc_probe(struct platform_device *pdev, } dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); - if (!dvc) { - dev_err(dev, "CMD allocate failed\n"); + if (!dvc) return -ENOMEM; - } priv->dvc_nr = nr; priv->dvc = dvc; -- GitLab From cdde84d10d3cb4d35051bc5fdb268f6faf33d1c8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:09:27 +0000 Subject: [PATCH 0997/7006] ASoC: rsnd: rename BUSIF_DALIGN to SSI_BUSIF_DALIGN based on datasheet Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 48f704b1d80e3..9dc1968d6f375 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -216,7 +216,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, /* FIXME: it needs SSI_MODE2/3 in the future */ RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), - RSND_GEN_M_REG(BUSIF_DALIGN, 0x8, 0x80), + RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), }; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f729646e3d180..f49b0cb1f5a2d 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -136,7 +136,7 @@ enum rsnd_reg { #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 -#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22 +#define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22 #define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 #define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 #define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 37927ca66162b..3f6f4df7318d7 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,7 +189,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, val |= 0x76543210 & ~mask; break; } - rsnd_mod_write(ssi_mod, BUSIF_DALIGN, val); + rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); } -- GitLab From efa991dc9143815179fd55a88e846cc39792608c Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:09:47 +0000 Subject: [PATCH 0998/7006] ASoC: rsnd: rename INT_ENABLE to SSI_INT_ENABLE based on datasheet Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/gen.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 9 ++++----- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 9dc1968d6f375..5d3592dfc3824 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -218,7 +218,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), - RSND_GEN_M_REG(INT_ENABLE, 0x18, 0x80), + RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), }; struct rsnd_regmap_field_conf conf_scu[] = { RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f49b0cb1f5a2d..9ecd15180184e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -119,7 +119,7 @@ enum rsnd_reg { #define RSND_REG_SSI_CTRL RSND_REG_SHARE02 #define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 #define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 -#define RSND_REG_INT_ENABLE RSND_REG_SHARE05 +#define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05 #define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 #define RSND_REG_SRC_BSISR RSND_REG_SHARE07 #define RSND_REG_DIV_EN RSND_REG_SHARE08 diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 3f6f4df7318d7..9e11f731a3a15 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -215,10 +215,9 @@ int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod) return 0; /* enable SSI interrupt if Gen2 */ - if (rsnd_ssi_is_dma_mode(ssi_mod)) - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000); - else - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000); + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, + rsnd_ssi_is_dma_mode(ssi_mod) ? + 0x0e000000 : 0x0f000000); return 0; } @@ -231,7 +230,7 @@ int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) return 0; /* disable SSI interrupt if Gen2 */ - rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000); + rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); return 0; } -- GitLab From a48e3f9747fd62b385221a892cd4726b82dacd11 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:10:04 +0000 Subject: [PATCH 0999/7006] ASoC: rsnd: fixup each module counter on __rsnd_mod_call() '5451ea443b ("ASoC: rsnd: count each mod (SSI/SRC/DVC)")' counts each module's callback status, but counts 1st callback only. This patch fixup it. Otherwise, multi-called function will be trouble Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f1e5920654f6f..d44bfb79779a1 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -242,9 +242,9 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (val == __rsnd_mod_call_##func) { \ called = 1; \ ret = (mod)->ops->func(mod, io, param); \ - mod->status = (mod->status & ~mask) + \ - (add << __rsnd_mod_shift_##func); \ } \ + mod->status = (mod->status & ~mask) + \ + (add << __rsnd_mod_shift_##func); \ dev_dbg(dev, "%s[%d] 0x%08x %s\n", \ rsnd_mod_name(mod), rsnd_mod_id(mod), mod->status, \ called ? #func : ""); \ -- GitLab From 1a1bf58aafd09b3cb148eead3d709e2d7974a1f3 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:10:22 +0000 Subject: [PATCH 1000/7006] ASoC: rsnd: add workaround for SRC sync convert + DVC We couldn't use SRC sync convert mode together with DVC, but we can use workaround for it. This patch adds workaround and can use SRC sync convert + DVC Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 43 ++++++++++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 9e11f731a3a15..38d0aba7426eb 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -616,6 +616,14 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) int_val = 0; } + /* + * WORKAROUND + * + * ignore over flow error when rsnd_enable_sync_convert() + */ + if (rsnd_enable_sync_convert(src)) + sys_int_val = sys_int_val & 0xffff; + rsnd_mod_write(mod, SRC_INT_ENABLE0, int_val); rsnd_mod_bset(mod, SCU_SYS_INT_EN0, sys_int_mask, sys_int_val); rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); @@ -631,11 +639,22 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) { - u32 val = OUF_SRC(rsnd_mod_id(mod)); + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val0, val1; bool ret = false; - if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val) || - (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val)) { + val0 = val1 = OUF_SRC(rsnd_mod_id(mod)); + + /* + * WORKAROUND + * + * ignore over flow error when rsnd_enable_sync_convert() + */ + if (rsnd_enable_sync_convert(src)) + val0 = val0 & 0xffff; + + if ((rsnd_mod_read(mod, SCU_SYS_STATUS0) & val0) || + (rsnd_mod_read(mod, SCU_SYS_STATUS1) & val1)) { struct rsnd_src *src = rsnd_mod_to_src(mod); src->err++; @@ -651,7 +670,16 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) static int _rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - u32 val = rsnd_io_to_mod_dvc(io) ? 0x01 : 0x11; + struct rsnd_src *src = rsnd_mod_to_src(mod); + u32 val; + + /* + * WORKAROUND + * + * Enable SRC output if you want to use sync convert together with DVC + */ + val = (rsnd_io_to_mod_dvc(io) && !rsnd_enable_sync_convert(src)) ? + 0x01 : 0x11; rsnd_mod_write(mod, SRC_CTRL, val); @@ -920,13 +948,6 @@ static int rsnd_src_pcm_new(struct rsnd_mod *mod, if (!rsnd_rdai_is_clk_master(rdai)) return 0; - /* - * We can't use SRC sync convert - * if it has DVC - */ - if (rsnd_io_to_mod_dvc(io)) - return 0; - /* * enable sync convert */ -- GitLab From 72413c107e81386a7da438bcf888ee2af5d3b72f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:10:43 +0000 Subject: [PATCH 1001/7006] ASoC: rsnd: rsnd_mod_id() return -1 if mod was NULL enabling to use same method for exception case is useful. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 9ecd15180184e..46eb4daa14610 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -316,7 +316,7 @@ struct rsnd_mod { #define rsnd_mod_to_priv(mod) ((mod)->priv) #define rsnd_mod_to_dma(mod) (&(mod)->dma) -#define rsnd_mod_id(mod) ((mod)->id) +#define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) #define rsnd_mod_hw_start(mod) clk_enable((mod)->clk) #define rsnd_mod_hw_stop(mod) clk_disable((mod)->clk) -- GitLab From 4f35fabaa30b116d549d95fe7dae907510c71862 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:11:02 +0000 Subject: [PATCH 1002/7006] ASoC: rsnd: move DVC specific macro into dvc.c rsnd_dvc_nr() is used only from dvc.c Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 1 + sound/soc/sh/rcar/rsnd.h | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index dbf0da6ce8a52..8a61aa3963061 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -24,6 +24,7 @@ struct rsnd_dvc { struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ }; +#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) #define rsnd_dvc_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 46eb4daa14610..8f793f020b084 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -579,7 +579,4 @@ void rsnd_dvc_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); -#define rsnd_dvc_nr(priv) ((priv)->dvc_nr) - - #endif -- GitLab From da599fd34b1f2f14f2c387e6b3a909f9ff519c8a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:11:21 +0000 Subject: [PATCH 1003/7006] ASoC: rsnd: move SRC specific macro into src.c rsnd_src_nr() is used only from src.c Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 2 -- sound/soc/sh/rcar/src.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 8f793f020b084..c8d202939e258 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -554,8 +554,6 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); -#define rsnd_src_nr(priv) ((priv)->src_nr) - /* * R-Car SSI */ diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 38d0aba7426eb..0b06ac8dbeec7 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -30,6 +30,7 @@ struct rsnd_src { #define RSND_SRC_NAME_SIZE 16 +#define rsnd_src_nr(priv) ((priv)->src_nr) #define rsnd_enable_sync_convert(src) ((src)->sen.val) #define rsnd_src_of_node(priv) \ of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") -- GitLab From 636e4bad5cca947839c09d3e13ad6feeb7fa45da Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:00 +0000 Subject: [PATCH 1004/7006] ASoC: rsnd: dvc: make sure DVC soft reset Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxRSR (Software reset Register) is one of them. These xxxRSR need be set to 1 to 0 when software reset. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_dvc_soft_reset() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 8a61aa3963061..24d07634c7499 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -64,6 +64,12 @@ static const char * const dvc_ramp_rate[] = { "0.125 dB/8192 steps", /* 10111 */ }; +static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, DVC_SWRSR, 0); + rsnd_mod_write(mod, DVC_SWRSR, 1); +} + static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -160,15 +166,14 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, rsnd_mod_hw_start(dvc_mod); + rsnd_dvc_soft_reset(dvc_mod); + /* * fixme * it doesn't support CTU/MIX */ rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]); - rsnd_mod_write(dvc_mod, DVC_SWRSR, 0); - rsnd_mod_write(dvc_mod, DVC_SWRSR, 1); - rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io)); -- GitLab From 379febfd2e30ec8db5baccd9f9403bf650c6afa1 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:18 +0000 Subject: [PATCH 1005/7006] ASoC: rsnd: src: make sure SRC soft reset Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxRSR (Software reset Register) is one of them. These xxxRSR need be set to 1 to 0 when software reset. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_src_soft_reset() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 0b06ac8dbeec7..74ab644c688e9 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -118,6 +118,12 @@ struct rsnd_src { /* * Gen1/Gen2 common functions */ +static void rsnd_src_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, SRC_SWRSR, 0); + rsnd_mod_write(mod, SRC_SWRSR, 1); +} + static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -294,10 +300,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, if (convert_rate) fsrate = 0x0400000 / convert_rate * runtime->rate; - /* set/clear soft reset */ - rsnd_mod_write(mod, SRC_SWRSR, 0); - rsnd_mod_write(mod, SRC_SWRSR, 1); - /* Set channel number and output bit length */ rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io)); @@ -358,6 +360,8 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_mod_hw_start(mod); + rsnd_src_soft_reset(mod); + src->err = 0; /* reset sync convert_rate */ -- GitLab From d6f8d5b4422a5a391c02df97af9ef7da5a929d71 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:36 +0000 Subject: [PATCH 1006/7006] ASoC: rsnd: enable module multi connection '8a4e379b54f8("ASoC: rsnd: remove io from rsnd_mod")' removed mod/io relationship. rsnd_dai_connect() mod/io check is no longer needed Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index d44bfb79779a1..ff4f15a2666a3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -277,16 +277,6 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, if (!mod) return -EIO; - if (io->mod[mod->type]) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); - - dev_err(dev, "%s[%d] is not empty\n", - rsnd_mod_name(mod), - rsnd_mod_id(mod)); - return -EIO; - } - io->mod[mod->type] = mod; return 0; -- GitLab From c8cf15f64f8ddb3169987c2f26df3341b8556296 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:12:52 +0000 Subject: [PATCH 1007/7006] ASoC: rsnd: rename rsnd_path_parse/break() into add/remove parse/break is a little ambiguous/confusable name for rsnd module path. Especially for CTU/MIX support. It was renamed to add/remove Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index ff4f15a2666a3..93fed5031c696 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -507,7 +507,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { .set_fmt = rsnd_soc_dai_set_fmt, }; -#define rsnd_path_parse(priv, io, type) \ +#define rsnd_path_add(priv, io, type) \ ({ \ struct rsnd_mod *mod; \ int ret = 0; \ @@ -523,7 +523,7 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { ret; \ }) -#define rsnd_path_break(priv, io, type) \ +#define rsnd_path_remove(priv, io, type) \ { \ struct rsnd_mod *mod; \ int id = -1; \ @@ -555,17 +555,17 @@ static int rsnd_path_init(struct rsnd_priv *priv, */ /* SRC */ - ret = rsnd_path_parse(priv, io, src); + ret = rsnd_path_add(priv, io, src); if (ret < 0) return ret; /* SSI */ - ret = rsnd_path_parse(priv, io, ssi); + ret = rsnd_path_add(priv, io, ssi); if (ret < 0) return ret; /* DVC */ - ret = rsnd_path_parse(priv, io, dvc); + ret = rsnd_path_add(priv, io, dvc); if (ret < 0) return ret; @@ -1023,8 +1023,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, /* * remove SRC/DVC from DAI, */ - rsnd_path_break(priv, io, src); - rsnd_path_break(priv, io, dvc); + rsnd_path_remove(priv, io, src); + rsnd_path_remove(priv, io, dvc); /* * fallback -- GitLab From e2c08416196bd10a6575057fdd1347a307ce3a15 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:13:10 +0000 Subject: [PATCH 1008/7006] ASoC: rsnd: add rsnd_path_parse() for CTU/MIX/DVC route setting Current sound data route settings is done in dvc.c, and it doesn't care about CTU/MIX at this poinnt, but we need to care about these. OTOH, rsnd driver already has rsnd_path_xxx() functions for data path which are good match for CTU/MIX/DVC path selectio. This patch adds new rsnd_path_parse() to select sound data route which will care about CTU/MIX/DVC path. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 22 ++++++++++++++++++++++ sound/soc/sh/rcar/dvc.c | 40 +++++++++------------------------------- sound/soc/sh/rcar/rsnd.h | 2 ++ 3 files changed, 33 insertions(+), 31 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 93fed5031c696..cb82067212834 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -537,6 +537,28 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { } \ } +void rsnd_path_parse(struct rsnd_priv *priv, + struct rsnd_dai_stream *io) +{ + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); + int src_id = rsnd_mod_id(src); + u32 path[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + /* Gen1 is not supported */ + if (rsnd_is_gen1(priv)) + return; + + rsnd_mod_write(dvc, CMD_ROUTE_SLCT, path[src_id]); +} + static int rsnd_path_init(struct rsnd_priv *priv, struct rsnd_dai *rdai, struct rsnd_dai_stream *io) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 24d07634c7499..9392507b5651f 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -142,48 +142,26 @@ static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, return 0; } -static int rsnd_dvc_init(struct rsnd_mod *dvc_mod, +static int rsnd_dvc_init(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { - struct rsnd_mod *src_mod = rsnd_io_to_mod_src(io); - struct device *dev = rsnd_priv_to_dev(priv); - int dvc_id = rsnd_mod_id(dvc_mod); - int src_id = rsnd_mod_id(src_mod); - u32 route[] = { - [0] = 0x30000, - [1] = 0x30001, - [2] = 0x40000, - [3] = 0x10000, - [4] = 0x20000, - [5] = 0x40100 - }; - - if (src_id >= ARRAY_SIZE(route)) { - dev_err(dev, "DVC%d isn't connected to SRC%d\n", dvc_id, src_id); - return -EINVAL; - } - - rsnd_mod_hw_start(dvc_mod); + rsnd_mod_hw_start(mod); - rsnd_dvc_soft_reset(dvc_mod); + rsnd_dvc_soft_reset(mod); - /* - * fixme - * it doesn't support CTU/MIX - */ - rsnd_mod_write(dvc_mod, CMD_ROUTE_SLCT, route[src_id]); + rsnd_path_parse(priv, io); - rsnd_mod_write(dvc_mod, DVC_DVUIR, 1); + rsnd_mod_write(mod, DVC_DVUIR, 1); - rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod, io)); + rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr(mod, io)); /* ch0/ch1 Volume */ - rsnd_dvc_volume_update(io, dvc_mod); + rsnd_dvc_volume_update(io, mod); - rsnd_mod_write(dvc_mod, DVC_DVUIR, 0); + rsnd_mod_write(mod, DVC_DVUIR, 0); - rsnd_adg_set_cmd_timsel_gen2(dvc_mod, io); + rsnd_adg_set_cmd_timsel_gen2(mod, io); return 0; } diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index c8d202939e258..6a87757879191 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -170,6 +170,8 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +void rsnd_path_parse(struct rsnd_priv *priv, + struct rsnd_dai_stream *io); /* * R-Car DMA -- GitLab From 3bb3d363e50d371289f0bd63b48da771ea807c02 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:13:29 +0000 Subject: [PATCH 1009/7006] ASoC: rsnd: add rsnd_dvc_initialize_lock/unlock() Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxIR (Initialization Register) is one of them. These xxxIR need be set to 1 during initialization. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_dvc_initialize_lock/unlock() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 9392507b5651f..343d44625fa52 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -70,6 +70,13 @@ static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) rsnd_mod_write(mod, DVC_SWRSR, 1); } +#define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1) +#define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0) +static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, DVC_DVUIR, enable); +} + static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -150,17 +157,15 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, rsnd_dvc_soft_reset(mod); - rsnd_path_parse(priv, io); + rsnd_dvc_initialize_lock(mod); - rsnd_mod_write(mod, DVC_DVUIR, 1); + rsnd_path_parse(priv, io); rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr(mod, io)); /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); - rsnd_mod_write(mod, DVC_DVUIR, 0); - rsnd_adg_set_cmd_timsel_gen2(mod, io); return 0; @@ -179,6 +184,8 @@ static int rsnd_dvc_start(struct rsnd_mod *mod, struct rsnd_dai_stream *io, struct rsnd_priv *priv) { + rsnd_dvc_initialize_unlock(mod); + rsnd_mod_write(mod, CMD_CTRL, 0x10); return 0; -- GitLab From d1ade514e84ea55cba999edb04cb88daa4da94b8 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:13:47 +0000 Subject: [PATCH 1010/7006] ASoC: rsnd: add rsnd_src_initialize_lock/unlock() Renesas SCU (Sampling Rate Convert Unit) includes SRC/CTU/MIX/DVC, and these have similar register. xxxIR (Initialization Register) is one of them. These xxxIR need be set to 1 during initialization. Current rsnd driver has src.c / dvc.c, and we will have mix.c. It is readable if these have same named function. This patch adds rsnd_src_initialize_lock/unlock() and make sure it Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/src.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 74ab644c688e9..b3d965ee9b776 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -124,6 +124,14 @@ static void rsnd_src_soft_reset(struct rsnd_mod *mod) rsnd_mod_write(mod, SRC_SWRSR, 1); } + +#define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1) +#define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0) +static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, SRC_SRCIR, enable); +} + static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, struct rsnd_mod *mod) { @@ -362,17 +370,13 @@ static int rsnd_src_init(struct rsnd_mod *mod, rsnd_src_soft_reset(mod); + rsnd_src_initialize_lock(mod); + src->err = 0; /* reset sync convert_rate */ src->sync.val = 0; - /* - * Initialize the operation of the SRC internal circuits - * see rsnd_src_start() - */ - rsnd_mod_write(mod, SRC_SRCIR, 1); - return 0; } @@ -399,11 +403,7 @@ static int rsnd_src_quit(struct rsnd_mod *mod, static int rsnd_src_start(struct rsnd_mod *mod) { - /* - * Cancel the initialization and operate the SRC function - * see rsnd_src_init() - */ - rsnd_mod_write(mod, SRC_SRCIR, 0); + rsnd_src_initialize_unlock(mod); return 0; } -- GitLab From 3023b384d0c9da49028131b91fe64b24b5b84e6d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:14:05 +0000 Subject: [PATCH 1011/7006] ASoC: rsnd: tidyup ADINR function name Renesas sound IP (= SSIU/SRC/CTU/MIX/DVC) have ADINR (= Audio Information Register), but some of them (= SSIU/SRC/DVC) are for audio data bits, some of them (= CTU/MIX) are for audio data channels. Current rsnd driver is supporting SSIU/SRC/DVC, and these ADINR were for bits. This patch rename rsnd_get_adinr() to rsnd_get_adinr_bit(), and we will have rsnd_get_adinr_chan() for CTU/MIX. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 4 ++-- sound/soc/sh/rcar/dvc.c | 2 +- sound/soc/sh/rcar/rsnd.h | 2 +- sound/soc/sh/rcar/src.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index cb82067212834..0ca6d0268b560 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -203,9 +203,9 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) } /* - * settting function + * ADINR function */ -u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { struct rsnd_priv *priv = rsnd_mod_to_priv(mod); struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 343d44625fa52..d06e4ee91f8d9 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -161,7 +161,7 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, rsnd_path_parse(priv, io); - rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr(mod, io)); + rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); /* ch0/ch1 Volume */ rsnd_dvc_volume_update(io, mod); diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6a87757879191..224a4a9eabd73 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -169,7 +169,7 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 data); void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); -u32 rsnd_get_adinr(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index b3d965ee9b776..c45da610fedac 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -189,7 +189,7 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, u32 mask = ~0; rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, - rsnd_get_adinr(ssi_mod, io)); + rsnd_get_adinr_bit(ssi_mod, io)); rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); @@ -309,7 +309,7 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, fsrate = 0x0400000 / convert_rate * runtime->rate; /* Set channel number and output bit length */ - rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod, io)); + rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io)); /* Enable the initial value of IFS */ if (fsrate) { -- GitLab From bfe1360d79210f9c1d330a07c26a8d5cb202159d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:14:29 +0000 Subject: [PATCH 1012/7006] ASoC: rsnd: add rsnd_get_adinr_chan() Current rsnd driver has rsnd_get_adinr_bit() to get bit settings for ADINR (= Audio Information Register) of SSIU/SRC/DVC. This patch adds rsnd_get_adinr_chan() to get channel settings for ADINR (= Audio Information Register) of CTU/MIX. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 22 ++++++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 1 + 2 files changed, 23 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 0ca6d0268b560..a3637b92b1876 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -227,6 +227,28 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) return adinr; } +u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +{ + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + struct device *dev = rsnd_priv_to_dev(priv); + u32 chan = runtime->channels; + + switch (chan) { + case 1: + case 2: + case 4: + case 6: + case 8: + break; + default: + dev_warn(dev, "not supported channel\n"); + chan = 0; + break; + } + + return chan; +} /* * rsnd_dai functions */ diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 224a4a9eabd73..1296b3525fa69 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -170,6 +170,7 @@ void rsnd_force_write(struct rsnd_priv *priv, struct rsnd_mod *mod, void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io); -- GitLab From 4689032b11d1af10e5eb755eb575f9761a455a72 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:14:47 +0000 Subject: [PATCH 1013/7006] ASoC: rsnd: tidyup data align position Sound L/R order of SSI is different from Linux sound data order. So current rsnd driver is using DALIGN (= data align) to exchange data align on SSIU. OTOH, CMD/SRC/SSIU have DALIGN register. Now inverted sound volume will be exchanged if user used volume control on DVC. Because SSIU which exchanges data align is located after DVC. MEM -> SRC -> DVC -> SSI This patch exchanges data align SRC if possible Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 36 ++++++++++++++++++++++++++++++++++++ sound/soc/sh/rcar/gen.c | 1 + sound/soc/sh/rcar/rsnd.h | 3 +++ sound/soc/sh/rcar/src.c | 20 +++++--------------- 4 files changed, 45 insertions(+), 15 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index a3637b92b1876..0f9323f2c0495 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -249,6 +249,42 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) return chan; } + +/* + * DALIGN function + */ +u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) +{ + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *target = src ? src : ssi; + struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); + u32 val = 0x76543210; + u32 mask = ~0; + + mask <<= runtime->channels * 4; + val = val & mask; + + switch (runtime->sample_bits) { + case 16: + val |= 0x67452301 & ~mask; + break; + case 32: + val |= 0x76543210 & ~mask; + break; + } + + /* + * exchange channeles on SRC if possible, + * otherwise, R/L volume settings on DVC + * changes inverted channels + */ + if (mod == target) + return val; + else + return 0x76543210; +} + /* * rsnd_dai functions */ diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 5d3592dfc3824..a2d5df4d5d176 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -222,6 +222,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, }; struct rsnd_regmap_field_conf conf_scu[] = { RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), + RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 1296b3525fa69..6c10a8b9210e3 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -99,6 +99,7 @@ enum rsnd_reg { RSND_REG_SHARE26, RSND_REG_SHARE27, RSND_REG_SHARE28, + RSND_REG_SHARE29, RSND_REG_MAX, }; @@ -143,6 +144,7 @@ enum rsnd_reg { #define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26 #define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27 #define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28 +#define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29 struct rsnd_of_data; struct rsnd_priv; @@ -171,6 +173,7 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, u32 mask, u32 data); u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); +u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io); diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index c45da610fedac..89a18e102feb1 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c @@ -148,7 +148,6 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, int use_busif) { struct rsnd_dai *rdai = rsnd_io_to_rdai(io); - struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); int ssi_id = rsnd_mod_id(ssi_mod); /* @@ -185,27 +184,14 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, * DMA settings for SSIU */ if (use_busif) { - u32 val = 0x76543210; - u32 mask = ~0; + u32 val = rsnd_get_dalign(ssi_mod, io); rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, rsnd_get_adinr_bit(ssi_mod, io)); rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); - mask <<= runtime->channels * 4; - val = val & mask; - - switch (runtime->sample_bits) { - case 16: - val |= 0x67452301 & ~mask; - break; - case 32: - val |= 0x76543210 & ~mask; - break; - } rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); - } return 0; @@ -678,6 +664,10 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod, struct rsnd_src *src = rsnd_mod_to_src(mod); u32 val; + val = rsnd_get_dalign(mod, io); + + rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val); + /* * WORKAROUND * -- GitLab From 84e95355602c59865be8a3bd18cd2f0b3863b4cb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:15:10 +0000 Subject: [PATCH 1014/7006] ASoC: rsnd: show debug message for SSI/SRC/DVC connection It can help for connection debug Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 0f9323f2c0495..8919afabe48f2 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -332,11 +332,18 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) static int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { + struct rsnd_priv *priv = rsnd_mod_to_priv(mod); + struct device *dev = rsnd_priv_to_dev(priv); + if (!mod) return -EIO; io->mod[mod->type] = mod; + dev_dbg(dev, "%s[%d] is connected to io (%s)\n", + rsnd_mod_name(mod), rsnd_mod_id(mod), + rsnd_io_is_play(io) ? "Playback" : "Capture"); + return 0; } -- GitLab From 98d358af07aa6fc4cd6cdfd3256ab792eb3675cd Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:15:27 +0000 Subject: [PATCH 1015/7006] ASoC: rsnd: tidyup rsnd_dma_ops definition place rsnd_dma_ops is used only from dma.c, rsnd.h doesn't need it. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 8 ++++++++ sound/soc/sh/rcar/rsnd.h | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index d306e298c63dc..943106136d99d 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -27,6 +27,14 @@ struct rsnd_dma_ctrl { int dmapp_num; }; +struct rsnd_dma_ops { + void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); + void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); + int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, + struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); + void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); +}; + #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) /* diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 6c10a8b9210e3..705e66f66ab8a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -181,13 +181,6 @@ void rsnd_path_parse(struct rsnd_priv *priv, * R-Car DMA */ struct rsnd_dma; -struct rsnd_dma_ops { - void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); - int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, - struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); - void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); -}; struct rsnd_dmaen { struct dma_chan *chan; -- GitLab From 9469b8b6092d347ef8a5fa9d2d7dde4c857a0994 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:15:47 +0000 Subject: [PATCH 1016/7006] ASoC: rsnd: check the Gen1 at the beginning of DVC probe DVC doesn't support Gen1, check it beginning of probe Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dvc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index d06e4ee91f8d9..57796387d4823 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c @@ -332,18 +332,18 @@ int rsnd_dvc_probe(struct platform_device *pdev, char name[RSND_DVC_NAME_SIZE]; int i, nr, ret; - rsnd_of_parse_dvc(pdev, of_data, priv); - - nr = info->dvc_info_nr; - if (!nr) - return 0; - /* This driver doesn't support Gen1 at this point */ if (rsnd_is_gen1(priv)) { dev_warn(dev, "CMD is not supported on Gen1\n"); return -EINVAL; } + rsnd_of_parse_dvc(pdev, of_data, priv); + + nr = info->dvc_info_nr; + if (!nr) + return 0; + dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); if (!dvc) return -ENOMEM; -- GitLab From ddea1b2e83c379840aa54fadc587e418cf986ccb Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:03 +0000 Subject: [PATCH 1017/7006] ASoC: rsnd: dma: add DMA name on .ops Current rsnd driver is using Audio DMAC (via DMAEngine) and Audio DMAC peri peri (via original method), and usage of these DMAC are different. Indicates its naming is useful for debugging. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 943106136d99d..a175863d239c5 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -28,6 +28,7 @@ struct rsnd_dma_ctrl { }; struct rsnd_dma_ops { + char *name; void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, @@ -190,7 +191,8 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io, cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - dev_dbg(dev, "dma : %pad -> %pad\n", + dev_dbg(dev, "%s %pad -> %pad\n", + dma->ops->name, &cfg.src_addr, &cfg.dst_addr); ret = dmaengine_slave_config(dmaen->chan, &cfg); @@ -223,6 +225,7 @@ static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) } static struct rsnd_dma_ops rsnd_dmaen_ops = { + .name = "audmac", .start = rsnd_dmaen_start, .stop = rsnd_dmaen_stop, .init = rsnd_dmaen_init, @@ -368,6 +371,7 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io, } static struct rsnd_dma_ops rsnd_dmapp_ops = { + .name = "audmac-pp", .start = rsnd_dmapp_start, .stop = rsnd_dmapp_stop, .init = rsnd_dmapp_init, @@ -580,6 +584,7 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) struct rsnd_mod *mod_to; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); + struct device *dev = rsnd_priv_to_dev(priv); int is_play = rsnd_io_is_play(io); /* @@ -606,6 +611,11 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) if (rsnd_is_gen1(priv)) dma->ops = &rsnd_dmaen_ops; + dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", + dma->ops->name, + rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), + rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); + return dma->ops->init(io, dma, id, mod_from, mod_to); } -- GitLab From 5cbbadd3d507eeb7711266e3932f4c427cbcbd61 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:19 +0000 Subject: [PATCH 1018/7006] ASoC: rsnd: add rsnd_io_to_mod() Sometimes we would like to get each module directly, especially data path searching. this patch adds rsnd_io_to_mod() macro, and existing rsnd_io_to_mod_xxx() use it. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/rsnd.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 705e66f66ab8a..5f5b8b1118b23 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -348,9 +348,10 @@ struct rsnd_dai_stream { int byte_per_period; int next_period_byte; }; -#define rsnd_io_to_mod_ssi(io) ((io)->mod[RSND_MOD_SSI]) -#define rsnd_io_to_mod_src(io) ((io)->mod[RSND_MOD_SRC]) -#define rsnd_io_to_mod_dvc(io) ((io)->mod[RSND_MOD_DVC]) +#define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) +#define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) +#define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) +#define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) -- GitLab From 78edead4494219640d9fdf37d76beae24f79de9e Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:37 +0000 Subject: [PATCH 1019/7006] ASoC: rsnd: tidyup SRC position on each code This is cleanup for CTU/MIX support Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/Makefile | 2 +- sound/soc/sh/rcar/core.c | 8 ++++---- sound/soc/sh/rcar/rsnd.h | 38 +++++++++++++++++++------------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index f1b445173fba7..3a274fd3593c2 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o src.o adg.o ssi.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 8919afabe48f2..e20d8ea0aafe8 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -641,13 +641,13 @@ static int rsnd_path_init(struct rsnd_priv *priv, * using fixed path. */ - /* SRC */ - ret = rsnd_path_add(priv, io, src); + /* SSI */ + ret = rsnd_path_add(priv, io, ssi); if (ret < 0) return ret; - /* SSI */ - ret = rsnd_path_add(priv, io, ssi); + /* SRC */ + ret = rsnd_path_add(priv, io, src); if (ret < 0) return ret; diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 5f5b8b1118b23..7fee2079ba5ab 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -440,12 +440,6 @@ struct rsnd_priv { */ void *gen; - /* - * below value will be filled on rsnd_src_probe() - */ - void *src; - int src_nr; - /* * below value will be filled on rsnd_adg_probe() */ @@ -462,6 +456,12 @@ struct rsnd_priv { void *ssi; int ssi_nr; + /* + * below value will be filled on rsnd_src_probe() + */ + void *src; + int src_nr; + /* * below value will be filled on rsnd_dvc_probe() */ @@ -534,6 +534,19 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, const char * const *texts, u32 max); +/* + * R-Car SSI + */ +int rsnd_ssi_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); +void rsnd_ssi_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); +int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); +int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); +int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod); + /* * R-Car SRC */ @@ -554,19 +567,6 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); -/* - * R-Car SSI - */ -int rsnd_ssi_probe(struct platform_device *pdev, - const struct rsnd_of_data *of_data, - struct rsnd_priv *priv); -void rsnd_ssi_remove(struct platform_device *pdev, - struct rsnd_priv *priv); -struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); -int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); -int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); -int rsnd_ssi_use_busif(struct rsnd_dai_stream *io, struct rsnd_mod *mod); - /* * R-Car DVC */ -- GitLab From eb0b3e78e6290e5a1bf970830939d5c8c9151892 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Tue, 7 Jul 2015 20:43:26 +0800 Subject: [PATCH 1020/7006] acpi-cpufreq: replace per_cpu with driver_data of policy Drivers can store their internal per-policy information in policy->driver_data, lets use it. we have benefits after this replacing. 1) memory saving. 2) policy is shared by several cpus, per_cpu seems not correct. using *driver_data* is more reasonable. 3) fix a memory leak in acpi_cpufreq_cpu_exit. as policy->cpu might change during cpu hotplug. So sometimes we cant't free *data*, use *driver_data* to fix it. 4) fix a zero return value of get_cur_freq_on_cpu. Only per_cpu of policy->cpu is set to *data*, if we try to get cpufreq on other cpus, we get zero instead of correct values. Use *driver_data* to fix it. Signed-off-by: Pan Xinhui Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 40 +++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 0136dfcdabf0b..e7fcaa6eedbda 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -72,8 +72,6 @@ struct acpi_cpufreq_data { cpumask_var_t freqdomain_cpus; }; -static DEFINE_PER_CPU(struct acpi_cpufreq_data *, acfreq_data); - /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance __percpu *acpi_perf_data; @@ -144,7 +142,7 @@ static int _store_boost(int val) static ssize_t show_freqdomain_cpus(struct cpufreq_policy *policy, char *buf) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; return cpufreq_show_cpus(data->freqdomain_cpus, buf); } @@ -327,7 +325,8 @@ static void drv_write(struct drv_cmd *cmd) put_cpu(); } -static u32 get_cur_val(const struct cpumask *mask) +static u32 +get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data) { struct acpi_processor_performance *perf; struct drv_cmd cmd; @@ -335,7 +334,7 @@ static u32 get_cur_val(const struct cpumask *mask) if (unlikely(cpumask_empty(mask))) return 0; - switch (per_cpu(acfreq_data, cpumask_first(mask))->cpu_feature) { + switch (data->cpu_feature) { case SYSTEM_INTEL_MSR_CAPABLE: cmd.type = SYSTEM_INTEL_MSR_CAPABLE; cmd.addr.msr.reg = MSR_IA32_PERF_CTL; @@ -346,7 +345,7 @@ static u32 get_cur_val(const struct cpumask *mask) break; case SYSTEM_IO_CAPABLE: cmd.type = SYSTEM_IO_CAPABLE; - perf = per_cpu(acfreq_data, cpumask_first(mask))->acpi_data; + perf = data->acpi_data; cmd.addr.io.port = perf->control_register.address; cmd.addr.io.bit_width = perf->control_register.bit_width; break; @@ -364,19 +363,24 @@ static u32 get_cur_val(const struct cpumask *mask) static unsigned int get_cur_freq_on_cpu(unsigned int cpu) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, cpu); + struct acpi_cpufreq_data *data; + struct cpufreq_policy *policy; unsigned int freq; unsigned int cached_freq; pr_debug("get_cur_freq_on_cpu (%d)\n", cpu); - if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { + policy = cpufreq_cpu_get(cpu); + if (unlikely(!policy)) + return 0; + + data = policy->driver_data; + cpufreq_cpu_put(policy); + if (unlikely(!data || !data->acpi_data || !data->freq_table)) return 0; - } cached_freq = data->freq_table[data->acpi_data->state].frequency; - freq = extract_freq(get_cur_val(cpumask_of(cpu)), data); + freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data); if (freq != cached_freq) { /* * The dreaded BIOS frequency change behind our back. @@ -397,7 +401,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, unsigned int i; for (i = 0; i < 100; i++) { - cur_freq = extract_freq(get_cur_val(mask), data); + cur_freq = extract_freq(get_cur_val(mask, data), data); if (cur_freq == freq) return 1; udelay(10); @@ -408,7 +412,7 @@ static unsigned int check_freqs(const struct cpumask *mask, unsigned int freq, static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; struct acpi_processor_performance *perf; struct drv_cmd cmd; unsigned int next_perf_state = 0; /* Index into perf table */ @@ -673,7 +677,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) } data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); - per_cpu(acfreq_data, cpu) = data; + policy->driver_data = data; if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; @@ -843,19 +847,19 @@ err_free_mask: free_cpumask_var(data->freqdomain_cpus); err_free: kfree(data); - per_cpu(acfreq_data, cpu) = NULL; + policy->driver_data = NULL; return result; } static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; pr_debug("acpi_cpufreq_cpu_exit\n"); if (data) { - per_cpu(acfreq_data, policy->cpu) = NULL; + policy->driver_data = NULL; acpi_processor_unregister_performance(data->acpi_data, policy->cpu); free_cpumask_var(data->freqdomain_cpus); @@ -868,7 +872,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) static int acpi_cpufreq_resume(struct cpufreq_policy *policy) { - struct acpi_cpufreq_data *data = per_cpu(acfreq_data, policy->cpu); + struct acpi_cpufreq_data *data = policy->driver_data; pr_debug("acpi_cpufreq_resume\n"); -- GitLab From 8101f99703048ceaa31c756abe1098d099249ad9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Jul 2015 15:12:15 +0530 Subject: [PATCH 1021/7006] cpufreq: cpufreq_add_dev: name goto labels based on what they do These labels are are named in two ways normally: - Based on what caused to jump to such labels - Based on what we do under such labels We follow the first naming convention today and that leads to multiple labels for doing the same work. Fix it by switching to the second way of naming them. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 26063afb3eba4..702777b1d645c 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1288,7 +1288,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) recover_policy = false; policy = cpufreq_policy_alloc(dev); if (!policy) - goto nomem_out; + goto out_release_rwsem; } cpumask_copy(policy->cpus, cpumask_of(cpu)); @@ -1299,7 +1299,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) ret = cpufreq_driver->init(policy); if (ret) { pr_debug("initialization failed\n"); - goto err_set_policy_cpu; + goto out_free_policy; } down_write(&policy->rwsem); @@ -1327,7 +1327,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) policy->cur = cpufreq_driver->get(policy->cpu); if (!policy->cur) { pr_err("%s: ->get() failed\n", __func__); - goto err_get_freq; + goto out_exit_policy; } } @@ -1377,7 +1377,7 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) if (!recover_policy) { ret = cpufreq_add_dev_interface(policy, dev); if (ret) - goto err_out_unregister; + goto out_exit_policy; blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_CREATE_POLICY, policy); @@ -1406,15 +1406,14 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) return 0; -err_out_unregister: -err_get_freq: +out_exit_policy: up_write(&policy->rwsem); if (cpufreq_driver->exit) cpufreq_driver->exit(policy); -err_set_policy_cpu: +out_free_policy: cpufreq_policy_free(policy, recover_policy); -nomem_out: +out_release_rwsem: up_read(&cpufreq_rwsem); return ret; -- GitLab From 7f0fa40f5a587c2a026de776cc6a26373ac0f244 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 8 Jul 2015 15:12:16 +0530 Subject: [PATCH 1022/7006] cpufreq: Properly handle errors from cpufreq_init_policy() cpufreq_init_policy() can fail, and we don't do anything except a call to ->exit() on that. The policy should be freed if this happens. Do it properly. Reported-and-tested-by: "Jon Medhurst (Tixy)" Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 702777b1d645c..a7b6ac6e048e9 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1060,11 +1060,10 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy, return cpufreq_add_dev_symlink(policy); } -static void cpufreq_init_policy(struct cpufreq_policy *policy) +static int cpufreq_init_policy(struct cpufreq_policy *policy) { struct cpufreq_governor *gov = NULL; struct cpufreq_policy new_policy; - int ret = 0; memcpy(&new_policy, policy, sizeof(*policy)); @@ -1083,12 +1082,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy) cpufreq_parse_governor(gov->name, &new_policy.policy, NULL); /* set default policy */ - ret = cpufreq_set_policy(policy, &new_policy); - if (ret) { - pr_debug("setting policy failed\n"); - if (cpufreq_driver->exit) - cpufreq_driver->exit(policy); - } + return cpufreq_set_policy(policy, &new_policy); } static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy, @@ -1386,7 +1380,12 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) write_unlock_irqrestore(&cpufreq_driver_lock, flags); } - cpufreq_init_policy(policy); + ret = cpufreq_init_policy(policy); + if (ret) { + pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n", + __func__, cpu, ret); + goto out_remove_policy_notify; + } if (!recover_policy) { policy->user_policy.policy = policy->policy; @@ -1406,6 +1405,9 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) return 0; +out_remove_policy_notify: + /* cpufreq_policy_free() will notify based on this */ + recover_policy = true; out_exit_policy: up_write(&policy->rwsem); -- GitLab From 8cfcfd39000d54188e0df1e0fafe63f53897b62a Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Fri, 10 Jul 2015 14:36:20 +0800 Subject: [PATCH 1023/7006] acpi-cpufreq: Fix an ACPI perf unregister issue As policy->cpu may not be same in acpi_cpufreq_cpu_init() and acpi_cpufreq_cpu_exit(). There is a risk that we use different CPU to un/register ACPI performance. So acpi_processor_unregister_performance() may not be able to do the cleanup work. That causes a memory leak. And if there will be another acpi_processor_register_performance() call, it may also fail thanks to the internal check of pr->performace. So add a new struct acpi_cpufreq_data field, acpi_perf_cpu, to fix this issue. Signed-off-by: Pan Xinhui Acked-by: Viresh Kumar [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index e7fcaa6eedbda..de54ce14eb395 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -69,6 +69,7 @@ struct acpi_cpufreq_data { struct cpufreq_frequency_table *freq_table; unsigned int resume; unsigned int cpu_feature; + unsigned int acpi_perf_cpu; cpumask_var_t freqdomain_cpus; }; @@ -677,6 +678,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) } data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); + data->acpi_perf_cpu = cpu; policy->driver_data = data; if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) @@ -861,7 +863,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) if (data) { policy->driver_data = NULL; acpi_processor_unregister_performance(data->acpi_data, - policy->cpu); + data->acpi_perf_cpu); free_cpumask_var(data->freqdomain_cpus); kfree(data->freq_table); kfree(data); -- GitLab From 3a5f5b2e3b4ba165e342c4e969c7fa8d85be0d94 Mon Sep 17 00:00:00 2001 From: Cristian Ardelean Date: Fri, 10 Jul 2015 14:42:15 -0400 Subject: [PATCH 1024/7006] cpufreq: integrator: fixed coding style issues Fixed coding style issues found by checkpatch.pl tool. Changed space indentation to tab, removed unneccesary braces, removed space between MODULE macros and parentheses. REMARKS: failed to 'make' this file with error message 'fatal error: asm/mach-types.h: No such file or directory'. Signed-off-by: Cristian Ardelean Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/integrator-cpufreq.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/integrator-cpufreq.c b/drivers/cpufreq/integrator-cpufreq.c index 129e266f76218..2faa4216bf2a1 100644 --- a/drivers/cpufreq/integrator-cpufreq.c +++ b/drivers/cpufreq/integrator-cpufreq.c @@ -98,11 +98,10 @@ static int integrator_set_target(struct cpufreq_policy *policy, /* get current setting */ cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); - if (machine_is_integrator()) { + if (machine_is_integrator()) vco.s = (cm_osc >> 8) & 7; - } else if (machine_is_cintegrator()) { + else if (machine_is_cintegrator()) vco.s = 1; - } vco.v = cm_osc & 255; vco.r = 22; freqs.old = icst_hz(&cclk_params, vco) / 1000; @@ -163,11 +162,10 @@ static unsigned int integrator_get(unsigned int cpu) /* detect memory etc. */ cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET); - if (machine_is_integrator()) { + if (machine_is_integrator()) vco.s = (cm_osc >> 8) & 7; - } else { + else vco.s = 1; - } vco.v = cm_osc & 255; vco.r = 22; @@ -203,7 +201,7 @@ static int __init integrator_cpufreq_probe(struct platform_device *pdev) struct resource *res; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) + if (!res) return -ENODEV; cm_base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); @@ -234,6 +232,6 @@ static struct platform_driver integrator_cpufreq_driver = { module_platform_driver_probe(integrator_cpufreq_driver, integrator_cpufreq_probe); -MODULE_AUTHOR ("Russell M. King"); -MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs"); -MODULE_LICENSE ("GPL"); +MODULE_AUTHOR("Russell M. King"); +MODULE_DESCRIPTION("cpufreq driver for ARM Integrator CPUs"); +MODULE_LICENSE("GPL"); -- GitLab From ba88d4338f226766f510e207911dde8c1875e072 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Tue, 14 Jul 2015 09:46:23 -0700 Subject: [PATCH 1025/7006] intel_pstate: enable HWP per CPU HWP previously was only enabled at driver load time, on the boot CPU, however, HWP must be enabled per package. Move the code to enable HWP to the cpufreq driver init path so that it will be called per CPU. Signed-off-by: Kristen Carlson Accardi Tested-by: David Zhuang Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 15ada47bb720b..763d8f34ab496 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -484,12 +484,11 @@ static void __init intel_pstate_sysfs_expose_params(void) } /************************** sysfs end ************************/ -static void intel_pstate_hwp_enable(void) +static void intel_pstate_hwp_enable(struct cpudata *cpudata) { - hwp_active++; pr_info("intel_pstate: HWP enabled\n"); - wrmsrl( MSR_PM_ENABLE, 0x1); + wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1); } static int byt_get_min_pstate(void) @@ -932,6 +931,10 @@ static int intel_pstate_init_cpu(unsigned int cpunum) cpu = all_cpu_data[cpunum]; cpu->cpu = cpunum; + + if (hwp_active) + intel_pstate_hwp_enable(cpu); + intel_pstate_get_cpu_pstates(cpu); init_timer_deferrable(&cpu->timer); @@ -1245,7 +1248,7 @@ static int __init intel_pstate_init(void) return -ENOMEM; if (static_cpu_has_safe(X86_FEATURE_HWP) && !no_hwp) - intel_pstate_hwp_enable(); + hwp_active++; if (!hwp_active && hwp_only) goto out; -- GitLab From f2da4542268503d22869617b7dbcb40d364c78bb Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 17 Jul 2015 07:44:09 +0800 Subject: [PATCH 1026/7006] ASoC: sti: sti_uniperiph_dai_create_ctrl() can be static Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 2 +- sound/soc/sti/uniperif_player.c | 4 ++-- sound/soc/sti/uniperif_reader.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 749e6b2941849..83a301f2aa66f 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -14,7 +14,7 @@ * This function is used to create Ctrl associated to DAI but also pcm device. * Request is done by front end to associate ctrl with pcm device id */ -int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) +static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) { struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); struct uniperif *uni = priv->dai_data.uni; diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c index d990d2c81a5d4..f609089a6e00e 100644 --- a/sound/soc/sti/uniperif_player.c +++ b/sound/soc/sti/uniperif_player.c @@ -43,7 +43,7 @@ * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate DAI_CPU capability in term of rate and supported channels */ -const struct snd_pcm_hardware uni_player_pcm_hw = { +static const struct snd_pcm_hardware uni_player_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, @@ -175,7 +175,7 @@ static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) return ret; } -int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) +static int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) { int rate_adjusted, rate_achieved, delta, ret; int adjustment = player->clk_adj; diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c index 7d83827ba6601..c502626f339b8 100644 --- a/sound/soc/sti/uniperif_reader.c +++ b/sound/soc/sti/uniperif_reader.c @@ -17,7 +17,7 @@ * Note: snd_pcm_hardware is linked to DMA controller but is declared here to * integrate unireader capability in term of rate and supported channels */ -const struct snd_pcm_hardware uni_reader_pcm_hw = { +static const struct snd_pcm_hardware uni_reader_pcm_hw = { .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID, @@ -324,7 +324,7 @@ static int uni_reader_parse_dt(struct platform_device *pdev, return 0; } -const struct snd_soc_dai_ops uni_reader_dai_ops = { +static const struct snd_soc_dai_ops uni_reader_dai_ops = { .shutdown = uni_reader_shutdown, .prepare = uni_reader_prepare, .trigger = uni_reader_trigger, -- GitLab From 546aee51ecacf6605b15f6a2580926f956dc5a3e Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 1 Jul 2015 17:12:45 +0530 Subject: [PATCH 1027/7006] drm/mgag200: remove unused variables These variables were assigned some values but they were never used. Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_fb.c | 2 -- drivers/gpu/drm/mgag200/mgag200_mode.c | 9 +++------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c index c36b8304042b7..958cf3cf082dc 100644 --- a/drivers/gpu/drm/mgag200/mgag200_fb.c +++ b/drivers/gpu/drm/mgag200/mgag200_fb.c @@ -167,7 +167,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, struct drm_framebuffer *fb; struct drm_gem_object *gobj = NULL; struct device *device = &dev->pdev->dev; - struct mgag200_bo *bo; int ret; void *sysram; int size; @@ -185,7 +184,6 @@ static int mgag200fb_create(struct drm_fb_helper *helper, DRM_ERROR("failed to create fbcon backing object %d\n", ret); return ret; } - bo = gem_to_mga_bo(gobj); sysram = vmalloc(size); if (!sysram) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 6e84df9369a65..67ae9f79dbd2d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -158,7 +158,7 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; - unsigned int delta, tmpdelta, permitteddelta; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; @@ -172,7 +172,6 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) pllreffreq = 48000; delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; for (testp = 1; testp < 9; testp++) { if (clock * testp > vcomax) @@ -298,7 +297,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; - unsigned int delta, tmpdelta, permitteddelta; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; @@ -310,7 +309,6 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) pllreffreq = 50000; delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; for (testp = 16; testp > 0; testp--) { if (clock * testp > vcomax) @@ -392,7 +390,7 @@ static int mga_g200ev_set_plls(struct mga_device *mdev, long clock) static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; - unsigned int delta, tmpdelta, permitteddelta; + unsigned int delta, tmpdelta; unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; @@ -406,7 +404,6 @@ static int mga_g200eh_set_plls(struct mga_device *mdev, long clock) pllreffreq = 33333; delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; for (testp = 16; testp > 0; testp >>= 1) { if (clock * testp > vcomax) -- GitLab From f9fe4b9b2ad4f2b801fdff3d634b07c9f9fc4327 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 1 Jul 2015 17:12:46 +0530 Subject: [PATCH 1028/7006] drm/mgag200: remove unneeded variable ttm_bo_validate() returns 0 or error. So we can return the value directly and remove the variable 'ret'. Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/mgag200/mgag200_ttm.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_ttm.c b/drivers/gpu/drm/mgag200/mgag200_ttm.c index d16964ea0ed48..05108b505fbfa 100644 --- a/drivers/gpu/drm/mgag200/mgag200_ttm.c +++ b/drivers/gpu/drm/mgag200/mgag200_ttm.c @@ -378,7 +378,7 @@ int mgag200_bo_pin(struct mgag200_bo *bo, u32 pl_flag, u64 *gpu_addr) int mgag200_bo_unpin(struct mgag200_bo *bo) { - int i, ret; + int i; if (!bo->pin_count) { DRM_ERROR("unpin bad %p\n", bo); return 0; @@ -389,11 +389,7 @@ int mgag200_bo_unpin(struct mgag200_bo *bo) for (i = 0; i < bo->placement.num_placement ; i++) bo->placements[i].flags &= ~TTM_PL_FLAG_NO_EVICT; - ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false); - if (ret) - return ret; - - return 0; + return ttm_bo_validate(&bo->bo, &bo->placement, false, false); } int mgag200_bo_push_sysram(struct mgag200_bo *bo) -- GitLab From 661abfc028886eb1c6b5b9dbc433ef8cfb11217d Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Thu, 16 Jul 2015 19:36:51 +0300 Subject: [PATCH 1029/7006] drm/i915: Fix divide by zero on watermark update Fix divide by zero if we end up updating the watermarks with zero dotclock. This is a stop gap measure to allow module load in cases where our state keeping fails. v2: WARN_ON added (Paulo) Cc: Paulo Zanoni Cc: Damien Lespiau Signed-off-by: Mika Kuoppala Reviewed-by: Paulo Zanoni Reviewed-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 5eeddc97ca2a2..0d3e01434860f 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -3316,8 +3316,10 @@ skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p) if (!to_intel_crtc(crtc)->active) return 0; - return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); + if (WARN_ON(p->pixel_rate == 0)) + return 0; + return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate); } static void skl_compute_transition_wm(struct drm_crtc *crtc, -- GitLab From edd43ed8cebafd29cc24e4798cdf0412c668e644 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 16 Jul 2015 17:08:08 +0100 Subject: [PATCH 1030/7006] drm/i915/skl: Don't expose the top most plane on gen9 display on SKL/BXT, the top most plane hardware is shared between the legacy cursor registers and an actual plane. Daniel and Ville don't want to expose 2 DRM planes and would rather expose a CURSOR plane that has all the usual plane properties, and that's a blocker for lifting the prelimary_hw_support flag. Unfortunately noone has had the time to finish this yet, but lifting the prelimary_hw_support flag is long overdue. As an intermediate solution we can merely not expose the top most plane Cc: Imre Deak Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index 5e63076cc7690..b1f9e5561cf2c 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -726,11 +726,19 @@ static void intel_device_info_runtime_init(struct drm_device *dev) info = (struct intel_device_info *)&dev_priv->info; + /* + * Skylake and Broxton currently don't expose the topmost plane as its + * use is exclusive with the legacy cursor and we only want to expose + * one of those, not both. Until we can safely expose the topmost plane + * as a DRM_PLANE_TYPE_CURSOR with all the features exposed/supported, + * we don't expose the topmost plane at all to prevent ABI breakage + * down the line. + */ if (IS_BROXTON(dev)) { - info->num_sprites[PIPE_A] = 3; - info->num_sprites[PIPE_B] = 3; - info->num_sprites[PIPE_C] = 2; - } else if (IS_VALLEYVIEW(dev) || INTEL_INFO(dev)->gen == 9) + info->num_sprites[PIPE_A] = 2; + info->num_sprites[PIPE_B] = 2; + info->num_sprites[PIPE_C] = 1; + } else if (IS_VALLEYVIEW(dev)) for_each_pipe(dev_priv, pipe) info->num_sprites[pipe] = 2; else -- GitLab From 4b0c8bb016e7f36e2d6ec230f9177f88def690d5 Mon Sep 17 00:00:00 2001 From: Damien Lespiau Date: Thu, 16 Jul 2015 17:08:09 +0100 Subject: [PATCH 1031/7006] drm/i915/skl: Drop the preliminary_hw_support flag Time to light a candle and remove the preliminary_hw_support flag. Signed-off-by: Damien Lespiau Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index f13ed1ef66410..0d6775a3e88c3 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -356,7 +356,6 @@ static const struct intel_device_info intel_cherryview_info = { }; static const struct intel_device_info intel_skylake_info = { - .is_preliminary = 1, .is_skylake = 1, .gen = 9, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, @@ -369,7 +368,6 @@ static const struct intel_device_info intel_skylake_info = { }; static const struct intel_device_info intel_skylake_gt3_info = { - .is_preliminary = 1, .is_skylake = 1, .gen = 9, .num_pipes = 3, .need_gfx_hws = 1, .has_hotplug = 1, -- GitLab From 015403145a65f0a0f7c4d9badfb12759349d1e13 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Thu, 9 Jul 2015 22:19:53 +0900 Subject: [PATCH 1032/7006] gpio: etraxfs: Fix devm_ioremap_resource return value check Value returned by devm_ioremap_resource() was checked for non-NULL but devm_ioremap_resource() returns IOMEM_ERR_PTR, not NULL. In case of error this could lead to dereference of ERR_PTR. Signed-off-by: Krzysztof Kozlowski Acked-by: Alexandre Courbot Acked-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/gpio-etraxfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 28071f4a56724..0e643140efdef 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -117,8 +117,8 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); regs = devm_ioremap_resource(dev, res); - if (!regs) - return -ENOMEM; + if (IS_ERR(regs)) + return PTR_ERR(regs); match = of_match_node(etraxfs_gpio_of_table, dev->of_node); if (!match) -- GitLab From ad64498762dd6f262f8c7c37926cd56693e109ba Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 6 Jul 2015 18:09:30 -0700 Subject: [PATCH 1033/7006] pinctrl: qcom: Hook pm_power_down for shutdown support Assign pm_power_off() if we have the PS_HOLD functionality so that we can properly shutdown the SoC. Otherwise, shutdown won't do anything besides put the CPU into a tight loop. Unfortunately, we have to use a singleton here because pm_power_off() doesn't take any arguments. Fortunately there's only one instance of the pinctrl device on a running system so this isn't a problem. Cc: Pramod Gurav Signed-off-by: Stephen Boyd Acked-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/pinctrl-msm.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index e457d52302a20..6242af8a42d5f 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "../core.h" #include "../pinconf.h" @@ -855,6 +856,13 @@ static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, return NOTIFY_DONE; } +static struct msm_pinctrl *poweroff_pctrl; + +static void msm_ps_hold_poweroff(void) +{ + msm_ps_hold_restart(&poweroff_pctrl->restart_nb, 0, NULL); +} + static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) { int i; @@ -867,6 +875,8 @@ static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) if (register_restart_handler(&pctrl->restart_nb)) dev_err(pctrl->dev, "failed to setup restart handler.\n"); + poweroff_pctrl = pctrl; + pm_power_off = msm_ps_hold_poweroff; break; } } -- GitLab From d9f2d203ab42f099b32ec4580e43eb08b3e4c412 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 13 Jul 2015 18:03:44 -0700 Subject: [PATCH 1034/7006] HID: wacom: Properly free inputs if 'wacom_allocate_inputs' fails The 'wacom_allocate_inputs' function tries to allocate three input devices: one each for the pen, touch, and pad. The pointers that are returned by the 'wacom_allocate_input' calls are temporarily stored to local variables where they are checked to ensure they're non-null before storing them in the 'wacom_wac' structure. If an allocation fails, the 'wacom_free_inputs' function is called to reclaim the memory. Unfortunately, 'wacom_free_inputs' is called prior to the pointers being copied, so it is not actually able to free anything. This patch has the calls to 'wacom_allocate_input' store the pointer directly in the 'wacom_wac' structure where they can be freed. Also, it replaces the call to 'wacom_free_inputs' with the (more general) 'wacom_clean_inputs' and removes the no-longer-used function. [jkosina@suse.com: modify to resolve conflict with 67e123f ("Delete unnecessary checks")] Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 52 ++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 34 deletions(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 936ad7770ec3a..3512d833cc24d 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1145,40 +1145,6 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) return input_dev; } -static void wacom_free_inputs(struct wacom *wacom) -{ - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - input_free_device(wacom_wac->pen_input); - input_free_device(wacom_wac->touch_input); - input_free_device(wacom_wac->pad_input); - wacom_wac->pen_input = NULL; - wacom_wac->touch_input = NULL; - wacom_wac->pad_input = NULL; -} - -static int wacom_allocate_inputs(struct wacom *wacom) -{ - struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; - struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - - pen_input_dev = wacom_allocate_input(wacom); - touch_input_dev = wacom_allocate_input(wacom); - pad_input_dev = wacom_allocate_input(wacom); - if (!pen_input_dev || !touch_input_dev || !pad_input_dev) { - wacom_free_inputs(wacom); - return -ENOMEM; - } - - wacom_wac->pen_input = pen_input_dev; - wacom_wac->touch_input = touch_input_dev; - wacom_wac->touch_input->name = wacom_wac->touch_name; - wacom_wac->pad_input = pad_input_dev; - wacom_wac->pad_input->name = wacom_wac->pad_name; - - return 0; -} - static void wacom_clean_inputs(struct wacom *wacom) { if (wacom->wacom_wac.pen_input) { @@ -1205,6 +1171,24 @@ static void wacom_clean_inputs(struct wacom *wacom) wacom_destroy_leds(wacom); } +static int wacom_allocate_inputs(struct wacom *wacom) +{ + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + + wacom_wac->pen_input = wacom_allocate_input(wacom); + wacom_wac->touch_input = wacom_allocate_input(wacom); + wacom_wac->pad_input = wacom_allocate_input(wacom); + if (!wacom_wac->pen_input || !wacom_wac->touch_input || !wacom_wac->pad_input) { + wacom_clean_inputs(wacom); + return -ENOMEM; + } + + wacom_wac->touch_input->name = wacom_wac->touch_name; + wacom_wac->pad_input->name = wacom_wac->pad_name; + + return 0; +} + static int wacom_register_inputs(struct wacom *wacom) { struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; -- GitLab From 2bdd163cfd262914e8f6152e37aebea2034f801e Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 13 Jul 2015 18:03:45 -0700 Subject: [PATCH 1035/7006] HID: wacom: Set default device name to value from wacom->features Allocated input devices should not use the 'pen_name' by default since we do not know at that point in time if that is an appropriate choice of name. Instead, use the (tool-agnostic) name that is stored in the device's 'wacom_features' structure. This also has the nice side-effect of requring us to be explicit about the naming of the pen device, as we already are for touch and pad devices. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 3512d833cc24d..2a221630d8dcc 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1130,7 +1130,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) if (!input_dev) return NULL; - input_dev->name = wacom_wac->pen_name; + input_dev->name = wacom_wac->features.name; input_dev->phys = hdev->phys; input_dev->dev.parent = &hdev->dev; input_dev->open = wacom_open; @@ -1183,6 +1183,7 @@ static int wacom_allocate_inputs(struct wacom *wacom) return -ENOMEM; } + wacom_wac->pen_input->name = wacom_wac->pen_name; wacom_wac->touch_input->name = wacom_wac->touch_name; wacom_wac->pad_input->name = wacom_wac->pad_name; -- GitLab From 9a98b3387e7bd9af5a6495b32e07d6f25071f4ba Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Thu, 16 Jul 2015 17:14:00 -0700 Subject: [PATCH 1036/7006] HID: rmi: Set F01 interrupt enable register when not set A firmware bug in some touchpads causes the F01 interrupt enable register to be cleared on reset. This register controls which RMI functions generate interrupts and when it is cleared, the touchpad stops reporting all data. This patch looks for the cleared F01 control register and writes the correct value based on interrupt mask computed while scanning the PDT. Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=91102 Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 57 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 5 deletions(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 9a792e725ea39..2c148129beb2f 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -141,6 +141,8 @@ struct rmi_data { unsigned long firmware_id; u8 f01_ctrl0; + u8 interrupt_enable_mask; + bool restore_interrupt_mask; }; #define RMI_PAGE(addr) (((addr) >> 8) & 0xff) @@ -361,13 +363,34 @@ static void rmi_f11_process_touch(struct rmi_data *hdata, int slot, } } +static int rmi_reset_attn_mode(struct hid_device *hdev) +{ + struct rmi_data *data = hid_get_drvdata(hdev); + int ret; + + ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + if (ret) + return ret; + + if (data->restore_interrupt_mask) { + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write F01 control register\n"); + return ret; + } + } + + return 0; +} + static void rmi_reset_work(struct work_struct *work) { struct rmi_data *hdata = container_of(work, struct rmi_data, reset_work); /* switch the device to RMI if we receive a generic mouse report */ - rmi_set_mode(hdata->hdev, RMI_MODE_ATTN_REPORTS); + rmi_reset_attn_mode(hdata->hdev); } static inline int rmi_schedule_reset(struct hid_device *hdev) @@ -590,7 +613,7 @@ static int rmi_post_reset(struct hid_device *hdev) struct rmi_data *data = hid_get_drvdata(hdev); int ret; - ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + ret = rmi_reset_attn_mode(hdev); if (ret) { hid_err(hdev, "can not set rmi mode\n"); return ret; @@ -617,7 +640,7 @@ static int rmi_post_reset(struct hid_device *hdev) static int rmi_post_resume(struct hid_device *hdev) { - return rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); + return rmi_reset_attn_mode(hdev); } #endif /* CONFIG_PM */ @@ -673,6 +696,7 @@ static void rmi_register_function(struct rmi_data *data, f->interrupt_count = pdt_entry->interrupt_source_count; f->irq_mask = rmi_gen_mask(f->interrupt_base, f->interrupt_count); + data->interrupt_enable_mask |= f->irq_mask; } } @@ -810,12 +834,35 @@ static int rmi_populate_f01(struct hid_device *hdev) data->firmware_id += info[2] * 65536; } - ret = rmi_read(hdev, data->f01.control_base_addr, &data->f01_ctrl0); + ret = rmi_read_block(hdev, data->f01.control_base_addr, info, + 2); if (ret) { - hid_err(hdev, "can not read f01 ctrl0\n"); + hid_err(hdev, "can not read f01 ctrl registers\n"); return ret; } + + data->f01_ctrl0 = info[0]; + + if (!info[1]) { + /* + * Do to a firmware bug in some touchpads the F01 interrupt + * enable control register will be cleared on reset. + * This will stop the touchpad from reporting data, so + * if F01 CTRL1 is 0 then we need to explicitly enable + * interrupts for the functions we want data for. + */ + data->restore_interrupt_mask = true; + + ret = rmi_write(hdev, data->f01.control_base_addr + 1, + &data->interrupt_enable_mask); + if (ret) { + hid_err(hdev, "can not write to control reg 1: %d.\n", + ret); + return ret; + } + } + return 0; } -- GitLab From 42d1b8ce2973c2f5956f4d4e4af002986ccc5748 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jul 2015 10:54:49 +0800 Subject: [PATCH 1037/7006] ASoC: Constify dev_pm_ops variables The dev_pm_ops variables are not modified after initialization in these drivers, so make them const. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm5100.c | 2 +- sound/soc/codecs/wm8962.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c83083285e532..3e3f638210a04 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -2481,7 +2481,7 @@ static int wm2200_runtime_resume(struct device *dev) } #endif -static struct dev_pm_ops wm2200_pm = { +static const struct dev_pm_ops wm2200_pm = { SET_RUNTIME_PM_OPS(wm2200_runtime_suspend, wm2200_runtime_resume, NULL) }; diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd88c1af6..3ea29cfe51fca 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -2708,7 +2708,7 @@ static int wm5100_runtime_resume(struct device *dev) } #endif -static struct dev_pm_ops wm5100_pm = { +static const struct dev_pm_ops wm5100_pm = { SET_RUNTIME_PM_OPS(wm5100_runtime_suspend, wm5100_runtime_resume, NULL) }; diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c index c5748fd4f2962..ad16414b28e7d 100644 --- a/sound/soc/codecs/wm8962.c +++ b/sound/soc/codecs/wm8962.c @@ -3859,7 +3859,7 @@ static int wm8962_runtime_suspend(struct device *dev) } #endif -static struct dev_pm_ops wm8962_pm = { +static const struct dev_pm_ops wm8962_pm = { SET_RUNTIME_PM_OPS(wm8962_runtime_suspend, wm8962_runtime_resume, NULL) }; -- GitLab From 582edace0b2af5f5fd44446ff6651a23417f1aee Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Fri, 17 Jul 2015 10:58:40 +0800 Subject: [PATCH 1038/7006] ASoC: rt5645: Remove unused rt5645 variable "ASoC: rt5645: Simplify rt5645_enable_push_button_irq" removes the test that accessed rt5645->pdata.jd_mode (that test is now done in rt5645_jack_detect only), so we do not need that variable anymore. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 11a2bfc4a0599..c16adf4bac0db 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2763,7 +2763,6 @@ static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); if (enable) { snd_soc_dapm_force_enable_pin(dapm, "ADC L power"); -- GitLab From 5168c5476a07233ecafaed0effaa59859327e366 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Fri, 17 Jul 2015 11:33:11 +0800 Subject: [PATCH 1039/7006] ASoC: rt5645: Fix missing free_irq The driver does not free irq when snd_soc_register_codec returns error. It does not return error when request irq failed, either. Add return when request irq failed, and free_irq if snd_soc_register_codec failed. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index c16adf4bac0db..827e3bf82d292 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3397,12 +3397,23 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, "rt5645", rt5645); - if (ret) + if (ret) { dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); + return ret; + } } - return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, - rt5645_dai, ARRAY_SIZE(rt5645_dai)); + ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, + rt5645_dai, ARRAY_SIZE(rt5645_dai)); + if (ret) + goto err_irq; + + return 0; + +err_irq: + if (rt5645->i2c->irq) + free_irq(rt5645->i2c->irq, rt5645); + return ret; } static int rt5645_i2c_remove(struct i2c_client *i2c) -- GitLab From 9fc114c5d7af6cfb72a2d983e16b83161716d6d0 Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Fri, 17 Jul 2015 11:33:12 +0800 Subject: [PATCH 1040/7006] ASoC: rt5645: Add regulator support This adds basic regulator support for rt5645. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 61 +++++++++++++++++++++++++++++++++++++-- sound/soc/codecs/rt5645.h | 26 ----------------- 2 files changed, 58 insertions(+), 29 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 827e3bf82d292..5f5d8adf6f422 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -223,6 +224,38 @@ static const struct reg_default rt5645_reg[] = { { 0xff, 0x6308 }, }; +static const char *const rt5645_supply_names[] = { + "avdd", + "cpvdd", +}; + +struct rt5645_priv { + struct snd_soc_codec *codec; + struct rt5645_platform_data pdata; + struct regmap *regmap; + struct i2c_client *i2c; + struct gpio_desc *gpiod_hp_det; + struct snd_soc_jack *hp_jack; + struct snd_soc_jack *mic_jack; + struct snd_soc_jack *btn_jack; + struct delayed_work jack_detect_work; + struct regulator_bulk_data supplies[ARRAY_SIZE(rt5645_supply_names)]; + + int codec_type; + int sysclk; + int sysclk_src; + int lrck[RT5645_AIFS]; + int bclk[RT5645_AIFS]; + int master[RT5645_AIFS]; + + int pll_src; + int pll_in; + int pll_out; + + int jack_type; + bool en_button_func; +}; + static int rt5645_reset(struct snd_soc_codec *codec) { return snd_soc_write(codec, RT5645_RESET, 0); @@ -3214,7 +3247,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, { struct rt5645_platform_data *pdata = dev_get_platdata(&i2c->dev); struct rt5645_priv *rt5645; - int ret; + int ret, i; unsigned int val; rt5645 = devm_kzalloc(&i2c->dev, sizeof(struct rt5645_priv), @@ -3248,6 +3281,24 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, return ret; } + for (i = 0; i < ARRAY_SIZE(rt5645->supplies); i++) + rt5645->supplies[i].supply = rt5645_supply_names[i]; + + ret = devm_regulator_bulk_get(&i2c->dev, + ARRAY_SIZE(rt5645->supplies), + rt5645->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to request supplies: %d\n", ret); + return ret; + } + + ret = regulator_bulk_enable(ARRAY_SIZE(rt5645->supplies), + rt5645->supplies); + if (ret) { + dev_err(&i2c->dev, "Failed to enable supplies: %d\n", ret); + return ret; + } + regmap_read(rt5645->regmap, RT5645_VENDOR_ID2, &val); switch (val) { @@ -3261,7 +3312,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, dev_err(&i2c->dev, "Device with ID register %#x is not rt5645 or rt5650\n", val); - return -ENODEV; + ret = -ENODEV; + goto err_enable; } if (rt5645->codec_type == CODEC_TYPE_RT5650) { @@ -3399,7 +3451,7 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | IRQF_ONESHOT, "rt5645", rt5645); if (ret) { dev_err(&i2c->dev, "Failed to reguest IRQ: %d\n", ret); - return ret; + goto err_enable; } } @@ -3413,6 +3465,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, err_irq: if (rt5645->i2c->irq) free_irq(rt5645->i2c->irq, rt5645); +err_enable: + regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); return ret; } @@ -3426,6 +3480,7 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) cancel_delayed_work_sync(&rt5645->jack_detect_work); snd_soc_unregister_codec(&i2c->dev); + regulator_bulk_disable(ARRAY_SIZE(rt5645->supplies), rt5645->supplies); return 0; } diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 0353a6a273ab4..199b22fe1bf36 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2177,32 +2177,6 @@ enum { int rt5645_sel_asrc_clk_src(struct snd_soc_codec *codec, unsigned int filter_mask, unsigned int clk_src); -struct rt5645_priv { - struct snd_soc_codec *codec; - struct rt5645_platform_data pdata; - struct regmap *regmap; - struct i2c_client *i2c; - struct gpio_desc *gpiod_hp_det; - struct snd_soc_jack *hp_jack; - struct snd_soc_jack *mic_jack; - struct snd_soc_jack *btn_jack; - struct delayed_work jack_detect_work; - - int codec_type; - int sysclk; - int sysclk_src; - int lrck[RT5645_AIFS]; - int bclk[RT5645_AIFS]; - int master[RT5645_AIFS]; - - int pll_src; - int pll_in; - int pll_out; - - int jack_type; - bool en_button_func; -}; - int rt5645_set_jack_detect(struct snd_soc_codec *codec, struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack, struct snd_soc_jack *btn_jack); -- GitLab From b2c0b2cbb282f0cf42518ffacbe197e6f2884168 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 3 Sep 2014 23:57:13 +0100 Subject: [PATCH 1041/7006] nmi: create generic NMI backtrace implementation x86s NMI backtrace implementation (for arch_trigger_all_cpu_backtrace()) is fairly generic in nature - the only architecture specific bits are the act of raising the NMI to other CPUs, and reporting the status of the NMI handler. These are fairly simple to factor out, and produce a generic implementation which can be shared between ARM and x86. Reviewed-by: Thomas Gleixner Signed-off-by: Russell King --- include/linux/nmi.h | 6 ++ lib/Makefile | 2 +- lib/nmi_backtrace.c | 162 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 lib/nmi_backtrace.c diff --git a/include/linux/nmi.h b/include/linux/nmi.h index f94da0e65dea9..5791e3229068f 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -49,6 +49,12 @@ static inline bool trigger_allbutself_cpu_backtrace(void) arch_trigger_all_cpu_backtrace(false); return true; } + +/* generic implementation */ +void nmi_trigger_all_cpu_backtrace(bool include_self, + void (*raise)(cpumask_t *mask)); +bool nmi_cpu_backtrace(struct pt_regs *regs); + #else static inline bool trigger_all_cpu_backtrace(void) { diff --git a/lib/Makefile b/lib/Makefile index 6897b527581a8..392169c5bc4ed 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -13,7 +13,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ sha1.o md5.o irq_regs.o argv_split.o \ proportions.o flex_proportions.o ratelimit.o show_mem.o \ is_single_threaded.o plist.o decompress.o kobject_uevent.o \ - earlycpio.o seq_buf.o + earlycpio.o seq_buf.o nmi_backtrace.o obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o lib-$(CONFIG_MMU) += ioremap.o diff --git a/lib/nmi_backtrace.c b/lib/nmi_backtrace.c new file mode 100644 index 0000000000000..88d3d32e59236 --- /dev/null +++ b/lib/nmi_backtrace.c @@ -0,0 +1,162 @@ +/* + * NMI backtrace support + * + * Gratuitously copied from arch/x86/kernel/apic/hw_nmi.c by Russell King, + * with the following header: + * + * HW NMI watchdog support + * + * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. + * + * Arch specific calls to support NMI watchdog + * + * Bits copied from original nmi.c file + */ +#include +#include +#include +#include +#include + +#ifdef arch_trigger_all_cpu_backtrace +/* For reliability, we're prepared to waste bits here. */ +static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; +static cpumask_t printtrace_mask; + +#define NMI_BUF_SIZE 4096 + +struct nmi_seq_buf { + unsigned char buffer[NMI_BUF_SIZE]; + struct seq_buf seq; +}; + +/* Safe printing in NMI context */ +static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq); + +/* "in progress" flag of arch_trigger_all_cpu_backtrace */ +static unsigned long backtrace_flag; + +static void print_seq_line(struct nmi_seq_buf *s, int start, int end) +{ + const char *buf = s->buffer + start; + + printk("%.*s", (end - start) + 1, buf); +} + +void nmi_trigger_all_cpu_backtrace(bool include_self, + void (*raise)(cpumask_t *mask)) +{ + struct nmi_seq_buf *s; + int i, cpu, this_cpu = get_cpu(); + + if (test_and_set_bit(0, &backtrace_flag)) { + /* + * If there is already a trigger_all_cpu_backtrace() in progress + * (backtrace_flag == 1), don't output double cpu dump infos. + */ + put_cpu(); + return; + } + + cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); + if (!include_self) + cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); + + cpumask_copy(&printtrace_mask, to_cpumask(backtrace_mask)); + + /* + * Set up per_cpu seq_buf buffers that the NMIs running on the other + * CPUs will write to. + */ + for_each_cpu(cpu, to_cpumask(backtrace_mask)) { + s = &per_cpu(nmi_print_seq, cpu); + seq_buf_init(&s->seq, s->buffer, NMI_BUF_SIZE); + } + + if (!cpumask_empty(to_cpumask(backtrace_mask))) { + pr_info("Sending NMI to %s CPUs:\n", + (include_self ? "all" : "other")); + raise(to_cpumask(backtrace_mask)); + } + + /* Wait for up to 10 seconds for all CPUs to do the backtrace */ + for (i = 0; i < 10 * 1000; i++) { + if (cpumask_empty(to_cpumask(backtrace_mask))) + break; + mdelay(1); + touch_softlockup_watchdog(); + } + + /* + * Now that all the NMIs have triggered, we can dump out their + * back traces safely to the console. + */ + for_each_cpu(cpu, &printtrace_mask) { + int len, last_i = 0; + + s = &per_cpu(nmi_print_seq, cpu); + len = seq_buf_used(&s->seq); + if (!len) + continue; + + /* Print line by line. */ + for (i = 0; i < len; i++) { + if (s->buffer[i] == '\n') { + print_seq_line(s, last_i, i); + last_i = i + 1; + } + } + /* Check if there was a partial line. */ + if (last_i < len) { + print_seq_line(s, last_i, len - 1); + pr_cont("\n"); + } + } + + clear_bit(0, &backtrace_flag); + smp_mb__after_atomic(); + put_cpu(); +} + +/* + * It is not safe to call printk() directly from NMI handlers. + * It may be fine if the NMI detected a lock up and we have no choice + * but to do so, but doing a NMI on all other CPUs to get a back trace + * can be done with a sysrq-l. We don't want that to lock up, which + * can happen if the NMI interrupts a printk in progress. + * + * Instead, we redirect the vprintk() to this nmi_vprintk() that writes + * the content into a per cpu seq_buf buffer. Then when the NMIs are + * all done, we can safely dump the contents of the seq_buf to a printk() + * from a non NMI context. + */ +static int nmi_vprintk(const char *fmt, va_list args) +{ + struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq); + unsigned int len = seq_buf_used(&s->seq); + + seq_buf_vprintf(&s->seq, fmt, args); + return seq_buf_used(&s->seq) - len; +} + +bool nmi_cpu_backtrace(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { + printk_func_t printk_func_save = this_cpu_read(printk_func); + + /* Replace printk to write into the NMI seq */ + this_cpu_write(printk_func, nmi_vprintk); + pr_warn("NMI backtrace for cpu %d\n", cpu); + show_regs(regs); + this_cpu_write(printk_func, printk_func_save); + + cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); + return true; + } + + return false; +} +NOKPROBE_SYMBOL(nmi_cpu_backtrace); +#endif -- GitLab From 4d7489ffba0aef4d2c708b6ff1428efd6ccf41df Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 10 Jul 2015 21:47:36 +0100 Subject: [PATCH 1042/7006] nmi: x86: convert to generic nmi handler Convert x86 to use the generic nmi handler code which can be shared between architectures. Reviewed-and-tested-by: Thomas Gleixner Signed-off-by: Russell King --- arch/x86/kernel/apic/hw_nmi.c | 133 +--------------------------------- 1 file changed, 4 insertions(+), 129 deletions(-) diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c index 6873ab925d00a..045e424fb3680 100644 --- a/arch/x86/kernel/apic/hw_nmi.c +++ b/arch/x86/kernel/apic/hw_nmi.c @@ -28,146 +28,21 @@ u64 hw_nmi_get_sample_period(int watchdog_thresh) #endif #ifdef arch_trigger_all_cpu_backtrace -/* For reliability, we're prepared to waste bits here. */ -static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; -static cpumask_t printtrace_mask; - -#define NMI_BUF_SIZE 4096 - -struct nmi_seq_buf { - unsigned char buffer[NMI_BUF_SIZE]; - struct seq_buf seq; -}; - -/* Safe printing in NMI context */ -static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq); - -/* "in progress" flag of arch_trigger_all_cpu_backtrace */ -static unsigned long backtrace_flag; - -static void print_seq_line(struct nmi_seq_buf *s, int start, int end) +static void nmi_raise_cpu_backtrace(cpumask_t *mask) { - const char *buf = s->buffer + start; - - printk("%.*s", (end - start) + 1, buf); + apic->send_IPI_mask(mask, NMI_VECTOR); } void arch_trigger_all_cpu_backtrace(bool include_self) { - struct nmi_seq_buf *s; - int len; - int cpu; - int i; - int this_cpu = get_cpu(); - - if (test_and_set_bit(0, &backtrace_flag)) { - /* - * If there is already a trigger_all_cpu_backtrace() in progress - * (backtrace_flag == 1), don't output double cpu dump infos. - */ - put_cpu(); - return; - } - - cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask); - if (!include_self) - cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); - - cpumask_copy(&printtrace_mask, to_cpumask(backtrace_mask)); - /* - * Set up per_cpu seq_buf buffers that the NMIs running on the other - * CPUs will write to. - */ - for_each_cpu(cpu, to_cpumask(backtrace_mask)) { - s = &per_cpu(nmi_print_seq, cpu); - seq_buf_init(&s->seq, s->buffer, NMI_BUF_SIZE); - } - - if (!cpumask_empty(to_cpumask(backtrace_mask))) { - pr_info("sending NMI to %s CPUs:\n", - (include_self ? "all" : "other")); - apic->send_IPI_mask(to_cpumask(backtrace_mask), NMI_VECTOR); - } - - /* Wait for up to 10 seconds for all CPUs to do the backtrace */ - for (i = 0; i < 10 * 1000; i++) { - if (cpumask_empty(to_cpumask(backtrace_mask))) - break; - mdelay(1); - touch_softlockup_watchdog(); - } - - /* - * Now that all the NMIs have triggered, we can dump out their - * back traces safely to the console. - */ - for_each_cpu(cpu, &printtrace_mask) { - int last_i = 0; - - s = &per_cpu(nmi_print_seq, cpu); - len = seq_buf_used(&s->seq); - if (!len) - continue; - - /* Print line by line. */ - for (i = 0; i < len; i++) { - if (s->buffer[i] == '\n') { - print_seq_line(s, last_i, i); - last_i = i + 1; - } - } - /* Check if there was a partial line. */ - if (last_i < len) { - print_seq_line(s, last_i, len - 1); - pr_cont("\n"); - } - } - - clear_bit(0, &backtrace_flag); - smp_mb__after_atomic(); - put_cpu(); -} - -/* - * It is not safe to call printk() directly from NMI handlers. - * It may be fine if the NMI detected a lock up and we have no choice - * but to do so, but doing a NMI on all other CPUs to get a back trace - * can be done with a sysrq-l. We don't want that to lock up, which - * can happen if the NMI interrupts a printk in progress. - * - * Instead, we redirect the vprintk() to this nmi_vprintk() that writes - * the content into a per cpu seq_buf buffer. Then when the NMIs are - * all done, we can safely dump the contents of the seq_buf to a printk() - * from a non NMI context. - */ -static int nmi_vprintk(const char *fmt, va_list args) -{ - struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq); - unsigned int len = seq_buf_used(&s->seq); - - seq_buf_vprintf(&s->seq, fmt, args); - return seq_buf_used(&s->seq) - len; + nmi_trigger_all_cpu_backtrace(include_self, nmi_raise_cpu_backtrace); } static int arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs) { - int cpu; - - cpu = smp_processor_id(); - - if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { - printk_func_t printk_func_save = this_cpu_read(printk_func); - - /* Replace printk to write into the NMI seq */ - this_cpu_write(printk_func, nmi_vprintk); - printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu); - show_regs(regs); - this_cpu_write(printk_func, printk_func_save); - - cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); + if (nmi_cpu_backtrace(regs)) return NMI_HANDLED; - } return NMI_DONE; } -- GitLab From 96f0e00378d4a1fc1b79933ef84e1595015de808 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 3 Sep 2014 23:57:13 +0100 Subject: [PATCH 1043/7006] ARM: add basic support for on-demand backtrace of other CPUs As we now have generic infrastructure to support backtracing of other CPUs in the system on lockups, we can start to implement this for ARM. Initially, we add an IPI based implementation, as the GIC code needs modification to support the generation of FIQ IPIs, and not all ARM platforms have the ability to raise a FIQ in the non-secure world. This provides us with a "best efforts" implementation in the absence of FIQs. Signed-off-by: Russell King --- arch/arm/include/asm/irq.h | 5 +++++ arch/arm/kernel/smp.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/arch/arm/include/asm/irq.h b/arch/arm/include/asm/irq.h index 53c15dec7af6a..be1d07d59ee97 100644 --- a/arch/arm/include/asm/irq.h +++ b/arch/arm/include/asm/irq.h @@ -35,6 +35,11 @@ extern void (*handle_arch_irq)(struct pt_regs *); extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); #endif +#ifdef CONFIG_SMP +extern void arch_trigger_all_cpu_backtrace(bool); +#define arch_trigger_all_cpu_backtrace(x) arch_trigger_all_cpu_backtrace(x) +#endif + #endif #endif diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 90dfbedfbfb85..3a20c386fd33f 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ enum ipi_msg_type { IPI_CPU_STOP, IPI_IRQ_WORK, IPI_COMPLETION, + IPI_CPU_BACKTRACE = 15, }; static DECLARE_COMPLETION(cpu_running); @@ -630,6 +632,12 @@ void handle_IPI(int ipinr, struct pt_regs *regs) irq_exit(); break; + case IPI_CPU_BACKTRACE: + irq_enter(); + nmi_cpu_backtrace(regs); + irq_exit(); + break; + default: pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); @@ -724,3 +732,13 @@ static int __init register_cpufreq_notifier(void) core_initcall(register_cpufreq_notifier); #endif + +static void raise_nmi(cpumask_t *mask) +{ + smp_cross_call(mask, IPI_CPU_BACKTRACE); +} + +void arch_trigger_all_cpu_backtrace(bool include_self) +{ + nmi_trigger_all_cpu_backtrace(include_self, raise_nmi); +} -- GitLab From 41cc14ba11d7d8532ef4f615c39eb6ebdcdeef61 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 13:32:44 -0300 Subject: [PATCH 1044/7006] [media] ttusb-dec: use swap() in swap_bytes() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-dec/ttusb_dec.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 322b53a4f1dde..7c3a7c55d9693 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -593,14 +593,9 @@ static void ttusb_dec_process_packet(struct ttusb_dec *dec) static void swap_bytes(u8 *b, int length) { - u8 c; - length -= length % 2; - for (; length; b += 2, length -= 2) { - c = *b; - *b = *(b + 1); - *(b + 1) = c; - } + for (; length; b += 2, length -= 2) + swap(*b, *(b + 1)); } static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, -- GitLab From 3685bbce2ea6142e81c78e6f3d5b2a1cdc37660e Mon Sep 17 00:00:00 2001 From: Vitaly Andrianov Date: Thu, 2 Jul 2015 14:31:30 -0400 Subject: [PATCH 1045/7006] gpio/davinci: add interrupt support for GPIOs 16-31 Interrupts for GPIOs 16 through 31 are enabled by bit 1 in the "binten" register (offset 8). Previous versions of GPIO only used bit 0, which enables GPIO 0-15 interrupts. Signed-off-by: Vitaly Andrianov Reviewed-by: Grygorii Strashko Reviewed-by: Sekhar Nori Signed-off-by: Linus Walleij --- drivers/gpio/gpio-davinci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index c5e05c82d67c6..86cfe1892caea 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -545,7 +545,7 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev) chips[0].chip.to_irq = gpio_to_irq_unbanked; chips[0].gpio_irq = bank_irq; chips[0].gpio_unbanked = pdata->gpio_unbanked; - binten = BIT(0); + binten = GENMASK(pdata->gpio_unbanked / 16, 0); /* AINTC handles mask/unmask; GPIO handles triggering */ irq = bank_irq; -- GitLab From fb8dfda980bdaf178a7addb0a4f68574e390a9d9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 23 Jun 2015 06:20:23 -0300 Subject: [PATCH 1046/7006] [media] v4l2-event: v4l2_event_queue: do nothing if vdev == NULL If the vdev pointer == NULL, then just return. This makes it easier for subdev drivers to use this function without having to check if the sd->devnode pointer is NULL or not. Signed-off-by: Hans Verkuil Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-event.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-event.c b/drivers/media/v4l2-core/v4l2-event.c index 8761aab99de95..8d3171c6bee8e 100644 --- a/drivers/media/v4l2-core/v4l2-event.c +++ b/drivers/media/v4l2-core/v4l2-event.c @@ -172,6 +172,9 @@ void v4l2_event_queue(struct video_device *vdev, const struct v4l2_event *ev) unsigned long flags; struct timespec timestamp; + if (vdev == NULL) + return; + ktime_get_ts(×tamp); spin_lock_irqsave(&vdev->fh_lock, flags); -- GitLab From 75629981069cf194336426bbbfb03f9c93d7ad67 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Jul 2015 11:17:58 +0100 Subject: [PATCH 1047/7006] pinctrl: pinconf: Allow groups to be configured via debugfs The function pinconf_dbg_config_write() currently only supports configuring a pin configuration mapping via the debugfs. Allow group mappings to also be configured via the debugfs. Signed-off-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 1fc09dc201990..4744d6363dfb2 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -470,10 +470,12 @@ exit: * pinconf_dbg_config_write() - modify the pinctrl config in the pinctrl * map, of a dev/pin/state entry based on user entries to pinconf-config * @user_buf: contains the modification request with expected format: - * modify config_pin + * modify * modify is literal string, alternatives like add/delete not supported yet - * config_pin is literal, alternatives like config_mux not supported yet - * are values that should match the pinctrl-maps + * is the configuration to be changed. Supported configs are + * "config_pin" or "config_group", alternatives like config_mux are not + * supported yet. + * are values that should match the pinctrl-maps * reflects the new config and is driver dependant */ static ssize_t pinconf_dbg_config_write(struct file *file, @@ -511,13 +513,19 @@ static ssize_t pinconf_dbg_config_write(struct file *file, if (strcmp(token, "modify")) return -EINVAL; - /* Get arg type: "config_pin" type supported so far */ + /* + * Get arg type: "config_pin" and "config_group" + * types are supported so far + */ token = strsep(&b, " "); if (!token) return -EINVAL; - if (strcmp(token, "config_pin")) + if (!strcmp(token, "config_pin")) + dbg->map_type = PIN_MAP_TYPE_CONFIGS_PIN; + else if (!strcmp(token, "config_group")) + dbg->map_type = PIN_MAP_TYPE_CONFIGS_GROUP; + else return -EINVAL; - dbg->map_type = PIN_MAP_TYPE_CONFIGS_PIN; /* get arg 'device_name' */ token = strsep(&b, " "); -- GitLab From d96310aeddc692cf1f06861cf722c4843e0a3f28 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Tue, 14 Jul 2015 11:17:59 +0100 Subject: [PATCH 1048/7006] pinctrl: pinconf: Fix display of configs The function pinconf_dbg_config_print() only prints the configuration of the 1st pin config in an array of pin configurations. Fix this so that all pin configurations in the array are displayed. There are a few places in the code where the pin configs are displayed and so add a helper function to display the pin configs to simplify the code. Signed-off-by: Jon Hunter Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 64 +++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index 4744d6363dfb2..cbf26a6992a03 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -202,18 +202,34 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) #ifdef CONFIG_DEBUG_FS -void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, + unsigned long *configs, unsigned num_configs) { - struct pinctrl_dev *pctldev; const struct pinconf_ops *confops; int i; - pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); if (pctldev) confops = pctldev->desc->confops; else confops = NULL; + for (i = 0; i < num_configs; i++) { + seq_puts(s, "config "); + if (confops && confops->pin_config_config_dbg_show) + confops->pin_config_config_dbg_show(pctldev, s, + configs[i]); + else + seq_printf(s, "%08lx", configs[i]); + seq_puts(s, "\n"); + } +} + +void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) +{ + struct pinctrl_dev *pctldev; + + pctldev = get_pinctrl_dev_from_devname(map->ctrl_dev_name); + switch (map->type) { case PIN_MAP_TYPE_CONFIGS_PIN: seq_printf(s, "pin "); @@ -227,15 +243,8 @@ void pinconf_show_map(struct seq_file *s, struct pinctrl_map const *map) seq_printf(s, "%s\n", map->data.configs.group_or_pin); - for (i = 0; i < map->data.configs.num_configs; i++) { - seq_printf(s, "config "); - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, - map->data.configs.configs[i]); - else - seq_printf(s, "%08lx", map->data.configs.configs[i]); - seq_printf(s, "\n"); - } + pinconf_show_config(s, pctldev, map->data.configs.configs, + map->data.configs.num_configs); } void pinconf_show_setting(struct seq_file *s, @@ -243,9 +252,7 @@ void pinconf_show_setting(struct seq_file *s, { struct pinctrl_dev *pctldev = setting->pctldev; const struct pinctrl_ops *pctlops = pctldev->desc->pctlops; - const struct pinconf_ops *confops = pctldev->desc->confops; struct pin_desc *desc; - int i; switch (setting->type) { case PIN_MAP_TYPE_CONFIGS_PIN: @@ -269,17 +276,8 @@ void pinconf_show_setting(struct seq_file *s, * FIXME: We should really get the pin controler to dump the config * values, so they can be decoded to something meaningful. */ - for (i = 0; i < setting->data.configs.num_configs; i++) { - seq_printf(s, " "); - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, - setting->data.configs.configs[i]); - else - seq_printf(s, "%08lx", - setting->data.configs.configs[i]); - } - - seq_printf(s, "\n"); + pinconf_show_config(s, pctldev, setting->data.configs.configs, + setting->data.configs.num_configs); } static void pinconf_dump_pin(struct pinctrl_dev *pctldev, @@ -412,10 +410,8 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) const struct pinctrl_map *map; const struct pinctrl_map *found = NULL; struct pinctrl_dev *pctldev; - const struct pinconf_ops *confops = NULL; struct dbg_cfg *dbg = &pinconf_dbg_conf; int i, j; - unsigned long config; mutex_lock(&pinctrl_maps_mutex); @@ -449,16 +445,10 @@ static int pinconf_dbg_config_print(struct seq_file *s, void *d) } pctldev = get_pinctrl_dev_from_devname(found->ctrl_dev_name); - config = *found->data.configs.configs; - seq_printf(s, "Dev %s has config of %s in state %s: 0x%08lX\n", - dbg->dev_name, dbg->pin_name, - dbg->state_name, config); - - if (pctldev) - confops = pctldev->desc->confops; - - if (confops && confops->pin_config_config_dbg_show) - confops->pin_config_config_dbg_show(pctldev, s, config); + seq_printf(s, "Dev %s has config of %s in state %s:\n", + dbg->dev_name, dbg->pin_name, dbg->state_name); + pinconf_show_config(s, pctldev, found->data.configs.configs, + found->data.configs.num_configs); exit: mutex_unlock(&pinctrl_maps_mutex); -- GitLab From bd6eab90073814a3211fc9688c2d59ce369ccff2 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Wed, 15 Jul 2015 00:25:27 +0200 Subject: [PATCH 1049/7006] pinctrl: lpc18xx: add support for usb1 pinconf The dedicated USB1 pins can be configured with pull-down and for low power mode (suspend). Add support for this in the pinctrl driver. Signed-off-by: Joachim Eastwood Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-lpc18xx.c | 54 ++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/pinctrl/pinctrl-lpc18xx.c b/drivers/pinctrl/pinctrl-lpc18xx.c index ef0b697639a71..e56f9203cc872 100644 --- a/drivers/pinctrl/pinctrl-lpc18xx.c +++ b/drivers/pinctrl/pinctrl-lpc18xx.c @@ -37,6 +37,9 @@ #define LPC18XX_SCU_PIN_EHD_MASK 0x300 #define LPC18XX_SCU_PIN_EHD_POS 8 +#define LPC18XX_SCU_USB1_EPD BIT(2) +#define LPC18XX_SCU_USB1_EPWR BIT(4) + #define LPC18XX_SCU_I2C0_EFP BIT(0) #define LPC18XX_SCU_I2C0_EHD BIT(2) #define LPC18XX_SCU_I2C0_EZI BIT(3) @@ -617,8 +620,31 @@ static const struct pinctrl_pin_desc lpc18xx_pins[] = { static int lpc18xx_pconf_get_usb1(enum pin_config_param param, int *arg, u32 reg) { - /* TODO */ - return -ENOTSUPP; + switch (param) { + case PIN_CONFIG_LOW_POWER_MODE: + if (reg & LPC18XX_SCU_USB1_EPWR) + *arg = 0; + else + *arg = 1; + break; + + case PIN_CONFIG_BIAS_DISABLE: + if (reg & LPC18XX_SCU_USB1_EPD) + return -EINVAL; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + if (reg & LPC18XX_SCU_USB1_EPD) + *arg = 1; + else + return -EINVAL; + break; + + default: + return -ENOTSUPP; + } + + return 0; } static int lpc18xx_pconf_get_i2c0(enum pin_config_param param, int *arg, u32 reg, @@ -782,8 +808,28 @@ static int lpc18xx_pconf_set_usb1(struct pinctrl_dev *pctldev, enum pin_config_param param, u16 param_val, u32 *reg) { - /* TODO */ - return -ENOTSUPP; + switch (param) { + case PIN_CONFIG_LOW_POWER_MODE: + if (param_val) + *reg &= ~LPC18XX_SCU_USB1_EPWR; + else + *reg |= LPC18XX_SCU_USB1_EPWR; + break; + + case PIN_CONFIG_BIAS_DISABLE: + *reg &= ~LPC18XX_SCU_USB1_EPD; + break; + + case PIN_CONFIG_BIAS_PULL_DOWN: + *reg |= LPC18XX_SCU_USB1_EPD; + break; + + default: + dev_err(pctldev->dev, "Property not supported\n"); + return -ENOTSUPP; + } + + return 0; } static int lpc18xx_pconf_set_i2c0(struct pinctrl_dev *pctldev, -- GitLab From 099f3e4adddc8fe9899fb879053887a95e9aed7d Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 14 Jul 2015 23:40:33 -0700 Subject: [PATCH 1050/7006] pinctrl: qcom: spmi-mpp: Add support for setting analog output level When the MPP is configured for analog output the output level is selected by the AOUT_CTL register, this patch makes it possible to control this. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../bindings/pinctrl/qcom,pmic-mpp.txt | 7 ++++++ drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 23 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index d29fb96a57d34..0e4d4e62e2200 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -127,6 +127,13 @@ to specify in a pin configuration subnode: Definition: Selects the power source for the specified pins. Valid power sources are defined in +- qcom,analog-level: + Usage: optional + Value type: + Definition: Selects the source for analog output. Valued values are + defined in + PMIC_MPP_AOUT_LVL_* + - qcom,analog-mode: Usage: optional Value type: diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index 9dde023640baa..e52a72348a67f 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -61,6 +61,7 @@ #define PMIC_MPP_REG_DIG_PULL_CTL 0x42 #define PMIC_MPP_REG_DIG_IN_CTL 0x43 #define PMIC_MPP_REG_EN_CTL 0x46 +#define PMIC_MPP_REG_AOUT_CTL 0x48 #define PMIC_MPP_REG_AIN_CTL 0x4a #define PMIC_MPP_REG_SINK_CTL 0x4c @@ -100,6 +101,7 @@ #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) #define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) #define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3) +#define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 4) /** * struct pmic_mpp_pad - keep current MPP settings @@ -115,6 +117,7 @@ * @num_sources: Number of power-sources supported by this MPP. * @power_source: Current power-source used. * @amux_input: Set the source for analog input. + * @aout_level: Analog output level * @pullup: Pullup resistor value. Valid in Bidirectional mode only. * @function: See pmic_mpp_functions[]. * @drive_strength: Amount of current in sink mode @@ -131,6 +134,7 @@ struct pmic_mpp_pad { unsigned int num_sources; unsigned int power_source; unsigned int amux_input; + unsigned int aout_level; unsigned int pullup; unsigned int function; unsigned int drive_strength; @@ -145,6 +149,7 @@ struct pmic_mpp_state { static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, + {"qcom,analog-level", PMIC_MPP_CONF_ANALOG_LEVEL, 0}, {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0}, }; @@ -152,6 +157,7 @@ static const struct pinconf_generic_params pmic_mpp_bindings[] = { #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), + PCONFDUMP(PMIC_MPP_CONF_ANALOG_LEVEL, "analog level", NULL, true), PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false), }; @@ -358,6 +364,9 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; break; + case PMIC_MPP_CONF_ANALOG_LEVEL: + arg = pad->aout_level; + break; case PMIC_MPP_CONF_ANALOG_MODE: arg = pad->analog_mode; break; @@ -433,6 +442,9 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, return -EINVAL; pad->amux_input = arg; break; + case PMIC_MPP_CONF_ANALOG_LEVEL: + pad->aout_level = arg; + break; case PMIC_MPP_CONF_ANALOG_MODE: pad->analog_mode = !!arg; break; @@ -462,6 +474,10 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, if (ret < 0) return ret; + ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AOUT_CTL, pad->aout_level); + if (ret < 0) + return ret; + ret = pmic_mpp_write_mode_ctl(state, pad); if (ret < 0) return ret; @@ -507,6 +523,7 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]); seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); seq_printf(s, " vin-%d", pad->power_source); + seq_printf(s, " %d", pad->aout_level); seq_printf(s, " %-8s", biases[pad->pullup]); seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); } @@ -748,6 +765,12 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, pad->drive_strength = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AOUT_CTL); + if (val < 0) + return val; + + pad->aout_level = val; + val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL); if (val < 0) return val; -- GitLab From eb5c144cbbc0ca9bb9a77c7c83fddc87469318de Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Wed, 17 Jun 2015 23:47:30 -0700 Subject: [PATCH 1051/7006] pinctrl: qcom: spmi-mpp: Transpose pinmux function The "function" of the MPP driver was inherited from the GPIO driver, but the differences between the two hardware blocks makes both the driver and the device tree binding to be awkward. Instead of overloading the "normal" function with various modes this patch transposes the pinmux function to represent the three operating modes of the MPP (digital, analog and current sink). The properties of pin pairing and DTEST routing is moved to separate properties. Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../bindings/pinctrl/qcom,pmic-mpp.txt | 29 ++-- drivers/pinctrl/qcom/pinctrl-spmi-mpp.c | 157 ++++++++++-------- 2 files changed, 99 insertions(+), 87 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index 0e4d4e62e2200..b096d8351b8fc 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -77,12 +77,9 @@ to specify in a pin configuration subnode: Value type: Definition: Specify the alternative function to be configured for the specified pins. Valid values are: - "normal", - "paired", - "dtest1", - "dtest2", - "dtest3", - "dtest4" + "digital", + "analog", + "sink" - bias-disable: Usage: optional @@ -134,17 +131,11 @@ to specify in a pin configuration subnode: defined in PMIC_MPP_AOUT_LVL_* -- qcom,analog-mode: +- qcom,dtest: Usage: optional - Value type: - Definition: Selects Analog mode of operation: combined with input-enable - and/or output-high, output-low MPP could operate as - Bidirectional Logic, Analog Input, Analog Output. - -- qcom,sink-mode: - Usage: optional - Value type: or - Definition: Selects sink mode of operation + Value type: + Definition: Selects which dtest rail to be routed in the various functions. + Valid values are 1-4 - qcom,amux-route: Usage: optional @@ -152,6 +143,10 @@ to specify in a pin configuration subnode: Definition: Selects the source for analog input. Valid values are defined in PMIC_MPP_AMUX_ROUTE_CH5, PMIC_MPP_AMUX_ROUTE_CH6... +- qcom,paired: + Usage: optional + Value type: + Definition: Indicates that the pin should be operating in paired mode. Example: @@ -168,7 +163,7 @@ Example: pm8841_default: default { gpio { pins = "mpp1", "mpp2", "mpp3", "mpp4"; - function = "normal"; + function = "digital"; input-enable; power-source = ; }; diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c index e52a72348a67f..e3be3ce2cada2 100644 --- a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c +++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c @@ -95,13 +95,17 @@ #define PMIC_MPP_MODE_ANALOG_OUTPUT 5 #define PMIC_MPP_MODE_CURRENT_SINK 6 +#define PMIC_MPP_SELECTOR_NORMAL 0 +#define PMIC_MPP_SELECTOR_PAIRED 1 +#define PMIC_MPP_SELECTOR_DTEST_FIRST 4 + #define PMIC_MPP_PHYSICAL_OFFSET 1 /* Qualcomm specific pin configurations */ #define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1) -#define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2) -#define PMIC_MPP_CONF_SINK_MODE (PIN_CONFIG_END + 3) -#define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 4) +#define PMIC_MPP_CONF_ANALOG_LEVEL (PIN_CONFIG_END + 2) +#define PMIC_MPP_CONF_DTEST_SELECTOR (PIN_CONFIG_END + 3) +#define PMIC_MPP_CONF_PAIRED (PIN_CONFIG_END + 4) /** * struct pmic_mpp_pad - keep current MPP settings @@ -111,9 +115,7 @@ * @out_value: Cached pin output value. * @output_enabled: Set to true if MPP output logic is enabled. * @input_enabled: Set to true if MPP input buffer logic is enabled. - * @analog_mode: Set to true when MPP should operate in Analog Input, Analog - * Output or Bidirectional Analog mode. - * @sink_mode: Boolean indicating if ink mode is slected + * @paired: Pin operates in paired mode * @num_sources: Number of power-sources supported by this MPP. * @power_source: Current power-source used. * @amux_input: Set the source for analog input. @@ -121,6 +123,7 @@ * @pullup: Pullup resistor value. Valid in Bidirectional mode only. * @function: See pmic_mpp_functions[]. * @drive_strength: Amount of current in sink mode + * @dtest: DTEST route selector */ struct pmic_mpp_pad { u16 base; @@ -129,8 +132,7 @@ struct pmic_mpp_pad { bool out_value; bool output_enabled; bool input_enabled; - bool analog_mode; - bool sink_mode; + bool paired; unsigned int num_sources; unsigned int power_source; unsigned int amux_input; @@ -138,6 +140,7 @@ struct pmic_mpp_pad { unsigned int pullup; unsigned int function; unsigned int drive_strength; + unsigned int dtest; }; struct pmic_mpp_state { @@ -150,16 +153,16 @@ struct pmic_mpp_state { static const struct pinconf_generic_params pmic_mpp_bindings[] = { {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE, 0}, {"qcom,analog-level", PMIC_MPP_CONF_ANALOG_LEVEL, 0}, - {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE, 0}, - {"qcom,sink-mode", PMIC_MPP_CONF_SINK_MODE, 0}, + {"qcom,dtest", PMIC_MPP_CONF_DTEST_SELECTOR, 0}, + {"qcom,paired", PMIC_MPP_CONF_PAIRED, 0}, }; #ifdef CONFIG_DEBUG_FS static const struct pin_config_item pmic_conf_items[] = { PCONFDUMP(PMIC_MPP_CONF_AMUX_ROUTE, "analog mux", NULL, true), PCONFDUMP(PMIC_MPP_CONF_ANALOG_LEVEL, "analog level", NULL, true), - PCONFDUMP(PMIC_MPP_CONF_ANALOG_MODE, "analog output", NULL, false), - PCONFDUMP(PMIC_MPP_CONF_SINK_MODE, "sink mode", NULL, false), + PCONFDUMP(PMIC_MPP_CONF_DTEST_SELECTOR, "dtest", NULL, true), + PCONFDUMP(PMIC_MPP_CONF_PAIRED, "paired", NULL, false), }; #endif @@ -167,11 +170,12 @@ static const char *const pmic_mpp_groups[] = { "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", }; +#define PMIC_MPP_DIGITAL 0 +#define PMIC_MPP_ANALOG 1 +#define PMIC_MPP_SINK 2 + static const char *const pmic_mpp_functions[] = { - PMIC_MPP_FUNC_NORMAL, PMIC_MPP_FUNC_PAIRED, - "reserved1", "reserved2", - PMIC_MPP_FUNC_DTEST1, PMIC_MPP_FUNC_DTEST2, - PMIC_MPP_FUNC_DTEST3, PMIC_MPP_FUNC_DTEST4, + "digital", "analog", "sink" }; static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip) @@ -260,31 +264,46 @@ static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev, static int pmic_mpp_write_mode_ctl(struct pmic_mpp_state *state, struct pmic_mpp_pad *pad) { + unsigned int mode; + unsigned int sel; unsigned int val; - - if (pad->analog_mode) { - val = PMIC_MPP_MODE_ANALOG_INPUT; - if (pad->output_enabled) { - if (pad->input_enabled) - val = PMIC_MPP_MODE_ANALOG_BIDIR; - else - val = PMIC_MPP_MODE_ANALOG_OUTPUT; - } - } else if (pad->sink_mode) { - val = PMIC_MPP_MODE_CURRENT_SINK; - } else { - val = PMIC_MPP_MODE_DIGITAL_INPUT; - if (pad->output_enabled) { - if (pad->input_enabled) - val = PMIC_MPP_MODE_DIGITAL_BIDIR; - else - val = PMIC_MPP_MODE_DIGITAL_OUTPUT; - } + unsigned int en; + + switch (pad->function) { + case PMIC_MPP_ANALOG: + if (pad->input_enabled && pad->output_enabled) + mode = PMIC_MPP_MODE_ANALOG_BIDIR; + else if (pad->input_enabled) + mode = PMIC_MPP_MODE_ANALOG_INPUT; + else + mode = PMIC_MPP_MODE_ANALOG_OUTPUT; + break; + case PMIC_MPP_DIGITAL: + if (pad->input_enabled && pad->output_enabled) + mode = PMIC_MPP_MODE_DIGITAL_BIDIR; + else if (pad->input_enabled) + mode = PMIC_MPP_MODE_DIGITAL_INPUT; + else + mode = PMIC_MPP_MODE_DIGITAL_OUTPUT; + break; + case PMIC_MPP_SINK: + default: + mode = PMIC_MPP_MODE_CURRENT_SINK; + break; } - val = val << PMIC_MPP_REG_MODE_DIR_SHIFT; - val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT; - val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK; + if (pad->dtest) + sel = PMIC_MPP_SELECTOR_DTEST_FIRST + pad->dtest - 1; + else if (pad->paired) + sel = PMIC_MPP_SELECTOR_PAIRED; + else + sel = PMIC_MPP_SELECTOR_NORMAL; + + en = !!pad->out_value; + + val = mode << PMIC_MPP_REG_MODE_DIR_SHIFT | + sel << PMIC_MPP_REG_MODE_FUNCTION_SHIFT | + en; return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val); } @@ -358,21 +377,21 @@ static int pmic_mpp_config_get(struct pinctrl_dev *pctldev, case PIN_CONFIG_OUTPUT: arg = pad->out_value; break; + case PMIC_MPP_CONF_DTEST_SELECTOR: + arg = pad->dtest; + break; case PMIC_MPP_CONF_AMUX_ROUTE: arg = pad->amux_input; break; + case PMIC_MPP_CONF_PAIRED: + arg = pad->paired; + break; case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; break; case PMIC_MPP_CONF_ANALOG_LEVEL: arg = pad->aout_level; break; - case PMIC_MPP_CONF_ANALOG_MODE: - arg = pad->analog_mode; - break; - case PMIC_MPP_CONF_SINK_MODE: - arg = pad->sink_mode; - break; default: return -EINVAL; } @@ -434,6 +453,9 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, pad->output_enabled = true; pad->out_value = arg; break; + case PMIC_MPP_CONF_DTEST_SELECTOR: + pad->dtest = arg; + break; case PIN_CONFIG_DRIVE_STRENGTH: arg = pad->drive_strength; break; @@ -445,11 +467,8 @@ static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin, case PMIC_MPP_CONF_ANALOG_LEVEL: pad->aout_level = arg; break; - case PMIC_MPP_CONF_ANALOG_MODE: - pad->analog_mode = !!arg; - break; - case PMIC_MPP_CONF_SINK_MODE: - pad->sink_mode = !!arg; + case PMIC_MPP_CONF_PAIRED: + pad->paired = !!arg; break; default: return -EINVAL; @@ -498,10 +517,6 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, "0.6kOhm", "10kOhm", "30kOhm", "Disabled" }; - static const char *const modes[] = { - "digital", "analog", "sink" - }; - pad = pctldev->desc->pins[pin].drv_data; seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET); @@ -520,12 +535,15 @@ static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev, } seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in"); - seq_printf(s, " %-7s", modes[pad->analog_mode ? 1 : (pad->sink_mode ? 2 : 0)]); seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]); seq_printf(s, " vin-%d", pad->power_source); seq_printf(s, " %d", pad->aout_level); seq_printf(s, " %-8s", biases[pad->pullup]); seq_printf(s, " %-4s", pad->out_value ? "high" : "low"); + if (pad->dtest) + seq_printf(s, " dtest%d", pad->dtest); + if (pad->paired) + seq_puts(s, " paired"); } } @@ -646,6 +664,7 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, struct pmic_mpp_pad *pad) { int type, subtype, val, dir; + unsigned int sel; type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE); if (type < 0) @@ -691,52 +710,50 @@ static int pmic_mpp_populate(struct pmic_mpp_state *state, case PMIC_MPP_MODE_DIGITAL_INPUT: pad->input_enabled = true; pad->output_enabled = false; - pad->analog_mode = false; - pad->sink_mode = false; + pad->function = PMIC_MPP_DIGITAL; break; case PMIC_MPP_MODE_DIGITAL_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; - pad->analog_mode = false; - pad->sink_mode = false; + pad->function = PMIC_MPP_DIGITAL; break; case PMIC_MPP_MODE_DIGITAL_BIDIR: pad->input_enabled = true; pad->output_enabled = true; - pad->analog_mode = false; - pad->sink_mode = false; + pad->function = PMIC_MPP_DIGITAL; break; case PMIC_MPP_MODE_ANALOG_BIDIR: pad->input_enabled = true; pad->output_enabled = true; - pad->analog_mode = true; - pad->sink_mode = false; + pad->function = PMIC_MPP_ANALOG; break; case PMIC_MPP_MODE_ANALOG_INPUT: pad->input_enabled = true; pad->output_enabled = false; - pad->analog_mode = true; - pad->sink_mode = false; + pad->function = PMIC_MPP_ANALOG; break; case PMIC_MPP_MODE_ANALOG_OUTPUT: pad->input_enabled = false; pad->output_enabled = true; - pad->analog_mode = true; - pad->sink_mode = false; + pad->function = PMIC_MPP_ANALOG; break; case PMIC_MPP_MODE_CURRENT_SINK: pad->input_enabled = false; pad->output_enabled = true; - pad->analog_mode = false; - pad->sink_mode = true; + pad->function = PMIC_MPP_SINK; break; default: dev_err(state->dev, "unknown MPP direction\n"); return -ENODEV; } - pad->function = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT; - pad->function &= PMIC_MPP_REG_MODE_FUNCTION_MASK; + sel = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT; + sel &= PMIC_MPP_REG_MODE_FUNCTION_MASK; + + if (sel >= PMIC_MPP_SELECTOR_DTEST_FIRST) + pad->dtest = sel + 1; + else if (sel == PMIC_MPP_SELECTOR_PAIRED) + pad->paired = true; val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL); if (val < 0) -- GitLab From 0975626d08b623ad42c89a6294b7c2f8391c69af Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:27 -0300 Subject: [PATCH 1052/7006] [media] adv7604: Add support for control event notifications Allow userspace applications to subscribe to control change events. This can e.g. be used to monitor the 5V detect control to be notified when a source is connected or disconnected. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 21b549a8dc744..a7d47e0793439 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -2362,6 +2363,8 @@ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { static const struct v4l2_subdev_core_ops adv76xx_core_ops = { .log_status = adv76xx_log_status, .interrupt_service_routine = adv76xx_isr, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv76xx_g_register, .s_register = adv76xx_s_register, @@ -3047,7 +3050,7 @@ static int adv76xx_probe(struct i2c_client *client, snprintf(sd->name, sizeof(sd->name), "%s %d-%04x", id->name, i2c_adapter_id(client->adapter), client->addr); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* Configure IO Regmap region */ err = configure_regmap(state, ADV76XX_PAGE_IO); -- GitLab From aef5159ffc6bbf65d77af3a2e5b3d377c7c4f37a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:28 -0300 Subject: [PATCH 1053/7006] [media] adv7842: Add support for control event notifications Allow userspace applications to subscribe to control change events. This can e.g. be used to monitor the 5V detect control to be notified when a source is connected or disconnected. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index aa0d1a04543b3..0535463d2fed2 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -3015,6 +3016,8 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = { .log_status = adv7842_log_status, .ioctl = adv7842_ioctl, .interrupt_service_routine = adv7842_isr, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv7842_g_register, .s_register = adv7842_s_register, @@ -3210,7 +3213,7 @@ static int adv7842_probe(struct i2c_client *client, sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &adv7842_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; state->mode = pdata->mode; state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A; -- GitLab From 8ae5640f1b4af2e903802f771ba6a8f0c3497cab Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:29 -0300 Subject: [PATCH 1054/7006] [media] Add helper function for subdev event notifications Add a new helper function called v4l2_subdev_notify_event() which will deliver the specified event to both the v4l2 subdev event queue as well as to the notify callback. The former is typically used by userspace applications to listen to notification events while the later is used by bridge drivers. Combining both into the same function avoids boilerplate code in subdev drivers. Signed-off-by: Lars-Peter Clausen Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 18 ++++++++++++++++++ include/media/v4l2-subdev.h | 4 ++++ 2 files changed, 22 insertions(+) diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 63596063b2136..83615b8fb46ad 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -588,3 +588,21 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops) #endif } EXPORT_SYMBOL(v4l2_subdev_init); + +/** + * v4l2_subdev_notify_event() - Delivers event notification for subdevice + * @sd: The subdev for which to deliver the event + * @ev: The event to deliver + * + * Will deliver the specified event to all userspace event listeners which are + * subscribed to the v42l subdev event queue as well as to the bridge driver + * using the notify callback. The notification type for the notify callback + * will be V4L2_DEVICE_NOTIFY_EVENT. + */ +void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev) +{ + v4l2_event_queue(sd->devnode, ev); + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, (void *)ev); +} +EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event); diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 4e18318eb425f..370fc38c34f1a 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -44,6 +44,7 @@ struct v4l2_device; struct v4l2_ctrl_handler; +struct v4l2_event; struct v4l2_event_subscription; struct v4l2_fh; struct v4l2_subdev; @@ -695,4 +696,7 @@ void v4l2_subdev_init(struct v4l2_subdev *sd, #define v4l2_subdev_has_op(sd, o, f) \ ((sd)->ops->o && (sd)->ops->o->f) +void v4l2_subdev_notify_event(struct v4l2_subdev *sd, + const struct v4l2_event *ev); + #endif -- GitLab From 6f5bcfc30e1918c6029ebfdc9ed5002d618ab3de Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:30 -0300 Subject: [PATCH 1055/7006] [media] adv7604: Deliver resolution change events to userspace Use the new v4l2_subdev_notify_event() helper function to deliver the resolution change event to userspace via the v4l2 subdev event queue as well as to the bridge driver using the callback notify mechanism. This allows userspace applications to react to changes in resolution. This is useful and often necessary for video pipelines where there is no direct 1-to-1 relationship between the subdevice converter and the video capture device and hence it does not make sense to directly forward the event to the video capture device node. Signed-off-by: Lars-Peter Clausen [hans.verkuil@cisco.com: fix obvious mistake: v4l2_event_subdev_unsubscribe -> v4l2_ctrl_subdev_subscribe_event] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index a7d47e0793439..bfb0b6a72bbc4 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1767,8 +1767,8 @@ static int adv76xx_s_routing(struct v4l2_subdev *sd, select_input(sd); enable_input(sd); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv76xx_ev_fmt); + v4l2_subdev_notify_event(sd, &adv76xx_ev_fmt); + return 0; } @@ -1935,8 +1935,7 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n", __func__, fmt_change, fmt_change_digital); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv76xx_ev_fmt); + v4l2_subdev_notify_event(sd, &adv76xx_ev_fmt); if (handled) *handled = true; @@ -2354,6 +2353,20 @@ static int adv76xx_log_status(struct v4l2_subdev *sd) return 0; } +static int adv76xx_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + /* ----------------------------------------------------------------------- */ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { @@ -2363,7 +2376,7 @@ static const struct v4l2_ctrl_ops adv76xx_ctrl_ops = { static const struct v4l2_subdev_core_ops adv76xx_core_ops = { .log_status = adv76xx_log_status, .interrupt_service_routine = adv76xx_isr, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .subscribe_event = adv76xx_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv76xx_g_register, -- GitLab From 2cf4090fc8db8f9c2f3778a6a3768357a2b6aa6e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Wed, 24 Jun 2015 13:50:31 -0300 Subject: [PATCH 1056/7006] [media] adv7842: Deliver resolution change events to userspace Use the new v4l2_subdev_notify_event() helper function to deliver the resolution change event to userspace via the v4l2 subdev event queue as well as to the bridge driver using the callback notify mechanism. This allows userspace applications to react to changes in resolution. This is useful and often necessary for video pipelines where there is no direct 1-to-1 relationship between the subdevice converter and the video capture device and hence it does not make sense to directly forward the event to the video capture device node. Signed-off-by: Lars-Peter Clausen [hans.verkuil@cisco.com: fix obvious mistake: v4l2_event_subdev_unsubscribe -> v4l2_ctrl_subdev_subscribe_event] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7842.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 0535463d2fed2..897d68c78b065 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -1981,8 +1981,7 @@ static int adv7842_s_routing(struct v4l2_subdev *sd, select_input(sd, state->vid_std_select); enable_input(sd); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv7842_ev_fmt); + v4l2_subdev_notify_event(sd, &adv7842_ev_fmt); return 0; } @@ -2215,8 +2214,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled) "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n", __func__, fmt_change_cp, fmt_change_digital, fmt_change_sdp); - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&adv7842_ev_fmt); + v4l2_subdev_notify_event(sd, &adv7842_ev_fmt); if (handled) *handled = true; } @@ -3006,6 +3004,20 @@ static long adv7842_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) return -ENOTTY; } +static int adv7842_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + /* ----------------------------------------------------------------------- */ static const struct v4l2_ctrl_ops adv7842_ctrl_ops = { @@ -3016,7 +3028,7 @@ static const struct v4l2_subdev_core_ops adv7842_core_ops = { .log_status = adv7842_log_status, .ioctl = adv7842_ioctl, .interrupt_service_routine = adv7842_isr, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .subscribe_event = adv7842_subscribe_event, .unsubscribe_event = v4l2_event_subdev_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .g_register = adv7842_g_register, -- GitLab From 86e46aa80d7456663afeac51971d4234dbc59e5d Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 2 Jul 2015 10:32:39 -0300 Subject: [PATCH 1057/7006] [media] DocBook: fix media-ioc-device-info.xml type The documentation had two media_version entries. The second one was a typo and it should be driver_version instead. Correct this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/media-ioc-device-info.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/media-ioc-device-info.xml b/Documentation/DocBook/media/v4l/media-ioc-device-info.xml index 2ce521419e67e..b0a21ac300b8c 100644 --- a/Documentation/DocBook/media/v4l/media-ioc-device-info.xml +++ b/Documentation/DocBook/media/v4l/media-ioc-device-info.xml @@ -102,7 +102,7 @@ __u32 - media_version + driver_version Media device driver version, formatted with the KERNEL_VERSION() macro. Together with the driver field this identifies a particular -- GitLab From ee5da769b3f238f818045e7630ed9ee3788690bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 8 Jul 2015 05:47:08 -0300 Subject: [PATCH 1058/7006] [media] DocBook media: fix typo in V4L2_CTRL_FLAG_EXECUTE_ON_WRITE Fix small typo (missing 'it') in the documentation for V4L2_CTRL_FLAG_EXECUTE_ON_WRITE. Signed-off-by: Hans Verkuil Acked-by: Ricardo Ribalda Delgado Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/vidioc-queryctrl.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml index dc83ad70f8dc8..6ec39c698baf3 100644 --- a/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml +++ b/Documentation/DocBook/media/v4l/vidioc-queryctrl.xml @@ -616,7 +616,7 @@ pointer to memory containing the payload of the control. V4L2_CTRL_FLAG_EXECUTE_ON_WRITE 0x0200 The value provided to the control will be propagated to the driver -even if remains constant. This is required when the control represents an action +even if it remains constant. This is required when the control represents an action on the hardware. For example: clearing an error flag or triggering the flash. All the controls of the type V4L2_CTRL_TYPE_BUTTON have this flag set. -- GitLab From 2f8e75d2762496bb2fcea7fa437a3339d2a6d9d4 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 29 Jun 2015 10:45:56 -0300 Subject: [PATCH 1059/7006] [media] adv7604/cobalt: Allow compile test if !GPIOLIB The GPIO subsystem provides dummy GPIO consumer functions if GPIOLIB is not enabled. Hence drivers that depend on GPIOLIB, but use GPIO consumer functionality only, can still be compiled if GPIOLIB is not enabled. Relax the dependency of VIDEO_ADV7604 and VIDEO_COBALT (the latter selects the former) on GPIOLIB if COMPILE_TEST is enabled. Signed-off-by: Geert Uytterhoeven Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 3 ++- drivers/media/pci/cobalt/Kconfig | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 71ee8f5864309..8d1268648fe0b 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -196,7 +196,8 @@ config VIDEO_ADV7183 config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && GPIOLIB + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on GPIOLIB || COMPILE_TEST select HDMI ---help--- Support for the Analog Devices ADV7604 video decoder. diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index 6a1c0089bb627..1f88ccc174daa 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -1,7 +1,8 @@ config VIDEO_COBALT tristate "Cisco Cobalt support" depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER - depends on PCI_MSI && MTD_COMPLEX_MAPPINGS && GPIOLIB + depends on PCI_MSI && MTD_COMPLEX_MAPPINGS + depends on GPIOLIB || COMPILE_TEST depends on SND select I2C_ALGOBIT select VIDEO_ADV7604 -- GitLab From f47c9045643f91e76d8a9030828b9fe1cf4a6bcf Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Mon, 29 Jun 2015 18:19:06 -0300 Subject: [PATCH 1060/7006] [media] media: am437x-vpfe: Requested frame size and fmt overwritten by current sensor setting Upon a S_FMT the input/requested frame size and pixel format is overwritten by the current sub-device settings. Fix this so application can actually set the frame size and format. Fixes: 417d2e507edc ("[media] media: platform: add VPFE capture driver support for AM437X") Cc: # v4.0+ Signed-off-by: Benoit Parrot Acked-by: Lad, Prabhakar Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 1fba339cddc15..1fed7a56c8ae4 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1565,7 +1565,7 @@ static int vpfe_s_fmt(struct file *file, void *priv, return -EBUSY; } - ret = vpfe_try_fmt(file, priv, fmt); + ret = vpfe_try_fmt(file, priv, &format); if (ret) return ret; -- GitLab From 890024ad144902bfa637f23b94b396701a88ed88 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 3 Jul 2015 16:11:41 -0300 Subject: [PATCH 1061/7006] [media] stk1160: Reduce driver verbosity These messages are not really informational, and just makes the driver's output too verbose. This commit changes some messages to a debug level, removes a really useless "driver loaded" message and finally undefines the DEBUG macro. Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-core.c | 5 +---- drivers/media/usb/stk1160/stk1160-v4l.c | 16 ++++++++-------- drivers/media/usb/stk1160/stk1160.h | 1 - 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/drivers/media/usb/stk1160/stk1160-core.c b/drivers/media/usb/stk1160/stk1160-core.c index 03504dcf3c524..1b6836f15370d 100644 --- a/drivers/media/usb/stk1160/stk1160-core.c +++ b/drivers/media/usb/stk1160/stk1160-core.c @@ -162,7 +162,7 @@ static void stk1160_release(struct v4l2_device *v4l2_dev) { struct stk1160 *dev = container_of(v4l2_dev, struct stk1160, v4l2_dev); - stk1160_info("releasing all resources\n"); + stk1160_dbg("releasing all resources\n"); stk1160_i2c_unregister(dev); @@ -363,9 +363,6 @@ static int stk1160_probe(struct usb_interface *interface, dev->sd_saa7115 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap, "saa7115_auto", 0, saa7113_addrs); - stk1160_info("driver ver %s successfully loaded\n", - STK1160_VERSION); - /* i2c reset saa711x */ v4l2_device_call_all(&dev->v4l2_dev, 0, core, reset, 0); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 7291cca587042..b4b737b0b35a7 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -136,7 +136,7 @@ static bool stk1160_set_alternate(struct stk1160 *dev) dev->alt = i; } - stk1160_info("setting alternate %d\n", dev->alt); + stk1160_dbg("setting alternate %d\n", dev->alt); if (dev->alt != prev_alt) { stk1160_dbg("minimum isoc packet size: %u (alt=%d)\n", @@ -226,7 +226,7 @@ static void stk1160_stop_hw(struct stk1160 *dev) /* set alternate 0 */ dev->alt = 0; - stk1160_info("setting alternate %d\n", dev->alt); + stk1160_dbg("setting alternate %d\n", dev->alt); usb_set_interface(dev->udev, 0, 0); /* Stop stk1160 */ @@ -540,8 +540,8 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *v4l_fmt, sizes[0] = size; - stk1160_info("%s: buffer count %d, each %ld bytes\n", - __func__, *nbuffers, size); + stk1160_dbg("%s: buffer count %d, each %ld bytes\n", + __func__, *nbuffers, size); return 0; } @@ -625,8 +625,8 @@ void stk1160_clear_queue(struct stk1160 *dev) struct stk1160_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - stk1160_info("buffer [%p/%d] aborted\n", - buf, buf->vb.v4l2_buf.index); + stk1160_dbg("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); } /* It's important to release the current buffer */ @@ -635,8 +635,8 @@ void stk1160_clear_queue(struct stk1160 *dev) dev->isoc_ctl.buf = NULL; vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); - stk1160_info("buffer [%p/%d] aborted\n", - buf, buf->vb.v4l2_buf.index); + stk1160_dbg("buffer [%p/%d] aborted\n", + buf, buf->vb.v4l2_buf.index); } spin_unlock_irqrestore(&dev->buf_lock, flags); } diff --git a/drivers/media/usb/stk1160/stk1160.h b/drivers/media/usb/stk1160/stk1160.h index 3922a6cabde29..72cc8e8cbef78 100644 --- a/drivers/media/usb/stk1160/stk1160.h +++ b/drivers/media/usb/stk1160/stk1160.h @@ -58,7 +58,6 @@ * new drivers should use. * */ -#define DEBUG #ifdef DEBUG #define stk1160_dbg(fmt, args...) \ printk(KERN_DEBUG "stk1160: " fmt, ## args) -- GitLab From d3194520e2790591b5fabeb913dd74af908ca160 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 3 Jul 2015 16:11:42 -0300 Subject: [PATCH 1062/7006] [media] stk1160: Add frame scaling support This commit implements frame decimation for stk1160, which allows to support format changes instead of a static frame size. The stk1160 supports independent row and column decimation, in two different modes: * set a number of rows/columns units to skip for each unit sent. * set a number of rows/columns units to send for each unit skipped. This effectively allows to achieve different frame scaling ratios. The unit number can be set to either two row/columns sent/skipped, or four row/columns sent/skipped. Since the video format (UYVY) has 4-bytes, using a unit number of two row/columns results in frame color 'shifting', so set to four row/columns sent/skipped. Signed-off-by: Michael Stegemann Signed-off-by: Dale Hamel Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stk1160/stk1160-reg.h | 34 ++++ drivers/media/usb/stk1160/stk1160-v4l.c | 201 ++++++++++++++++++++---- 2 files changed, 207 insertions(+), 28 deletions(-) diff --git a/drivers/media/usb/stk1160/stk1160-reg.h b/drivers/media/usb/stk1160/stk1160-reg.h index 3e49da6e7edd0..81ff3a15d96ee 100644 --- a/drivers/media/usb/stk1160/stk1160-reg.h +++ b/drivers/media/usb/stk1160/stk1160-reg.h @@ -33,6 +33,40 @@ */ #define STK1160_DCTRL 0x100 +/* + * Decimation Control Register: + * Byte 104: Horizontal Decimation Line Unit Count + * Byte 105: Vertical Decimation Line Unit Count + * Byte 106: Decimation Control + * Bit 0 - Horizontal Decimation Control + * 0 Horizontal decimation is disabled. + * 1 Horizontal decimation is enabled. + * Bit 1 - Decimates Half or More Column + * 0 Decimates less than half from original column, + * send count unit (0x105) before each unit skipped. + * 1 Decimates half or more from original column, + * skip count unit (0x105) before each unit sent. + * Bit 2 - Vertical Decimation Control + * 0 Vertical decimation is disabled. + * 1 Vertical decimation is enabled. + * Bit 3 - Vertical Greater or Equal to Half + * 0 Decimates less than half from original row, + * send count unit (0x105) before each unit skipped. + * 1 Decimates half or more from original row, + * skip count unit (0x105) before each unit sent. + * Bit 4 - Decimation Unit + * 0 Decimation will work with 2 rows or columns per unit. + * 1 Decimation will work with 4 rows or columns per unit. + */ +#define STK1160_DMCTRL_H_UNITS 0x104 +#define STK1160_DMCTRL_V_UNITS 0x105 +#define STK1160_DMCTRL 0x106 +#define STK1160_H_DEC_EN BIT(0) +#define STK1160_H_DEC_MODE BIT(1) +#define STK1160_V_DEC_EN BIT(2) +#define STK1160_V_DEC_MODE BIT(3) +#define STK1160_DEC_UNIT_SIZE BIT(4) + /* Capture Frame Start Position */ #define STK116_CFSPO 0x110 #define STK116_CFSPO_STX_L 0x110 diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index b4b737b0b35a7..e12b103528711 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -42,6 +42,17 @@ static bool keep_buffers; module_param(keep_buffers, bool, 0644); MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming"); +enum stk1160_decimate_mode { + STK1160_DECIMATE_MORE_THAN_HALF, + STK1160_DECIMATE_LESS_THAN_HALF, +}; + +struct stk1160_decimate_ctrl { + bool col_en, row_en; + enum stk1160_decimate_mode col_mode, row_mode; + unsigned int col_n, row_n; +}; + /* supported video standards */ static struct stk1160_fmt format[] = { { @@ -51,6 +62,19 @@ static struct stk1160_fmt format[] = { } }; +/* + * Helper to find the next divisor that results in modulo being zero. + * This is required to guarantee valid decimation unit counts. + */ +static unsigned int +div_round_integer(unsigned int x, unsigned int y) +{ + for (;; y++) { + if (x % y == 0) + return x / y; + } +} + static void stk1160_set_std(struct stk1160 *dev) { int i; @@ -106,6 +130,41 @@ static void stk1160_set_std(struct stk1160 *dev) } +static void stk1160_set_fmt(struct stk1160 *dev, + struct stk1160_decimate_ctrl *ctrl) +{ + u32 val = 0; + + if (ctrl) { + /* + * Since the format is UYVY, the device must skip or send + * a number of rows/columns multiple of four. This way, the + * colour format is preserved. The STK1160_DEC_UNIT_SIZE bit + * does exactly this. + */ + val |= STK1160_DEC_UNIT_SIZE; + val |= ctrl->col_en ? STK1160_H_DEC_EN : 0; + val |= ctrl->row_en ? STK1160_V_DEC_EN : 0; + val |= ctrl->col_mode == + STK1160_DECIMATE_MORE_THAN_HALF ? + STK1160_H_DEC_MODE : 0; + val |= ctrl->row_mode == + STK1160_DECIMATE_MORE_THAN_HALF ? + STK1160_V_DEC_MODE : 0; + + /* Horizontal count units */ + stk1160_write_reg(dev, STK1160_DMCTRL_H_UNITS, ctrl->col_n); + /* Vertical count units */ + stk1160_write_reg(dev, STK1160_DMCTRL_V_UNITS, ctrl->row_n); + + stk1160_dbg("decimate 0x%x, column units %d, row units %d\n", + val, ctrl->col_n, ctrl->row_n); + } + + /* Decimation control */ + stk1160_write_reg(dev, STK1160_DMCTRL, val); +} + /* * Set a new alternate setting. * Returns true is dev->max_pkt_size has changed, false otherwise. @@ -323,41 +382,134 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) +static int stk1160_try_fmt(struct stk1160 *dev, struct v4l2_format *f, + struct stk1160_decimate_ctrl *ctrl) { - struct stk1160 *dev = video_drvdata(file); + unsigned int width, height; + unsigned int base_width, base_height; + unsigned int col_n, row_n; + enum stk1160_decimate_mode col_mode, row_mode; + bool col_en, row_en; + + base_width = 720; + base_height = (dev->norm & V4L2_STD_525_60) ? 480 : 576; + + /* Minimum width and height is 5% the frame size */ + width = clamp_t(unsigned int, f->fmt.pix.width, + base_width / 20, base_width); + height = clamp_t(unsigned int, f->fmt.pix.height, + base_height / 20, base_height); + + /* Let's set default no decimation values */ + col_n = 0; + row_n = 0; + col_en = false; + row_en = false; + f->fmt.pix.width = base_width; + f->fmt.pix.height = base_height; + row_mode = STK1160_DECIMATE_LESS_THAN_HALF; + col_mode = STK1160_DECIMATE_LESS_THAN_HALF; + + if (width < base_width && width > base_width / 2) { + /* + * The device will send count units for each + * unit skipped. This means count unit is: + * + * n = width / (frame width - width) + * + * And the width is: + * + * width = (n / n + 1) * frame width + */ + col_n = div_round_integer(width, base_width - width); + if (col_n > 0 && col_n <= 255) { + col_en = true; + col_mode = STK1160_DECIMATE_LESS_THAN_HALF; + f->fmt.pix.width = (base_width * col_n) / (col_n + 1); + } - /* - * User can't choose size at his own will, - * so we just return him the current size chosen - * at standard selection. - * TODO: Implement frame scaling? - */ + } else if (width <= base_width / 2) { + + /* + * The device will skip count units for each + * unit sent. This means count is: + * + * n = (frame width / width) - 1 + * + * And the width is: + * + * width = frame width / (n + 1) + */ + col_n = div_round_integer(base_width, width) - 1; + if (col_n > 0 && col_n <= 255) { + col_en = true; + col_mode = STK1160_DECIMATE_MORE_THAN_HALF; + f->fmt.pix.width = base_width / (col_n + 1); + } + } + + if (height < base_height && height > base_height / 2) { + row_n = div_round_integer(height, base_height - height); + if (row_n > 0 && row_n <= 255) { + row_en = true; + row_mode = STK1160_DECIMATE_LESS_THAN_HALF; + f->fmt.pix.height = (base_height * row_n) / (row_n + 1); + } + + } else if (height <= base_height / 2) { + row_n = div_round_integer(base_height, height) - 1; + if (row_n > 0 && row_n <= 255) { + row_en = true; + row_mode = STK1160_DECIMATE_MORE_THAN_HALF; + f->fmt.pix.height = base_height / (row_n + 1); + } + } f->fmt.pix.pixelformat = dev->fmt->fourcc; - f->fmt.pix.width = dev->width; - f->fmt.pix.height = dev->height; f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.bytesperline = dev->width * 2; - f->fmt.pix.sizeimage = dev->height * f->fmt.pix.bytesperline; + f->fmt.pix.bytesperline = f->fmt.pix.width * 2; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + if (ctrl) { + ctrl->col_en = col_en; + ctrl->col_n = col_n; + ctrl->col_mode = col_mode; + ctrl->row_en = row_en; + ctrl->row_n = row_n; + ctrl->row_mode = row_mode; + } + + stk1160_dbg("width %d, height %d\n", + f->fmt.pix.width, f->fmt.pix.height); return 0; } +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct stk1160 *dev = video_drvdata(file); + + return stk1160_try_fmt(dev, f, NULL); +} + static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct stk1160 *dev = video_drvdata(file); struct vb2_queue *q = &dev->vb_vidq; + struct stk1160_decimate_ctrl ctrl; + int rc; if (vb2_is_busy(q)) return -EBUSY; - vidioc_try_fmt_vid_cap(file, priv, f); - - /* We don't support any format changes */ + rc = stk1160_try_fmt(dev, f, &ctrl); + if (rc < 0) + return rc; + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; + stk1160_set_fmt(dev, &ctrl); return 0; } @@ -393,22 +545,15 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) return -ENODEV; /* We need to set this now, before we call stk1160_set_std */ + dev->width = 720; + dev->height = (norm & V4L2_STD_525_60) ? 480 : 576; dev->norm = norm; - /* This is taken from saa7115 video decoder */ - if (dev->norm & V4L2_STD_525_60) { - dev->width = 720; - dev->height = 480; - } else if (dev->norm & V4L2_STD_625_50) { - dev->width = 720; - dev->height = 576; - } else { - stk1160_err("invalid standard\n"); - return -EINVAL; - } - stk1160_set_std(dev); + /* Calling with NULL disables frame decimation */ + stk1160_set_fmt(dev, NULL); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, dev->norm); -- GitLab From 3d8bffe88316c0c8b5edad633fc8a25cae644bb4 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Fri, 10 Jul 2015 05:29:22 -0300 Subject: [PATCH 1063/7006] [media] bdisp: composing support Support the composing (at VIDEO_CAPTURE) with the _selection API. v4l2-compliance successfully run ("test Composing: OK") Signed-off-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-hw.c | 8 +- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 76 +++++++++++++------ 2 files changed, 55 insertions(+), 29 deletions(-) diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c index 465828e859e20..c83f9c2fbe3c7 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-hw.c +++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c @@ -336,8 +336,8 @@ static int bdisp_hw_get_hv_inc(struct bdisp_ctx *ctx, u16 *h_inc, u16 *v_inc) src_w = ctx->src.crop.width; src_h = ctx->src.crop.height; - dst_w = ctx->dst.width; - dst_h = ctx->dst.height; + dst_w = ctx->dst.crop.width; + dst_h = ctx->dst.crop.height; if (bdisp_hw_get_inc(src_w, dst_w, h_inc) || bdisp_hw_get_inc(src_h, dst_h, v_inc)) { @@ -483,9 +483,9 @@ static void bdisp_hw_build_node(struct bdisp_ctx *ctx, src_rect.width -= src_x_offset; src_rect.width = min_t(__s32, MAX_SRC_WIDTH, src_rect.width); - dst_x_offset = (src_x_offset * dst->width) / ctx->src.crop.width; + dst_x_offset = (src_x_offset * dst_width) / ctx->src.crop.width; dst_rect.left += dst_x_offset; - dst_rect.width = (src_rect.width * dst->width) / ctx->src.crop.width; + dst_rect.width = (src_rect.width * dst_width) / ctx->src.crop.width; /* General */ src_fmt = src->fmt->pixelformat; diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 9e782ebe18dad..df61355b46f1a 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -851,33 +851,56 @@ static int bdisp_g_selection(struct file *file, void *fh, struct bdisp_frame *frame; struct bdisp_ctx *ctx = fh_to_ctx(fh); - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* Composing / capture is not supported */ - dev_dbg(ctx->bdisp_dev->dev, "Not supported for capture\n"); - return -EINVAL; - } - frame = ctx_get_frame(ctx, s->type); if (IS_ERR(frame)) { dev_err(ctx->bdisp_dev->dev, "Invalid frame (%p)\n", frame); return PTR_ERR(frame); } - switch (s->target) { - case V4L2_SEL_TGT_CROP: - /* cropped frame */ - s->r = frame->crop; + switch (s->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + switch (s->target) { + case V4L2_SEL_TGT_CROP: + /* cropped frame */ + s->r = frame->crop; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + /* complete frame */ + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->width; + s->r.height = frame->height; + break; + default: + dev_err(ctx->bdisp_dev->dev, "Invalid target\n"); + return -EINVAL; + } break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - /* complete frame */ - s->r.left = 0; - s->r.top = 0; - s->r.width = frame->width; - s->r.height = frame->height; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_COMPOSE_PADDED: + /* composed (cropped) frame */ + s->r = frame->crop; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + /* complete frame */ + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->width; + s->r.height = frame->height; + break; + default: + dev_err(ctx->bdisp_dev->dev, "Invalid target\n"); + return -EINVAL; + } break; + default: - dev_dbg(ctx->bdisp_dev->dev, "Invalid target\n"); + dev_err(ctx->bdisp_dev->dev, "Invalid type\n"); return -EINVAL; } @@ -906,15 +929,18 @@ static int bdisp_s_selection(struct file *file, void *fh, struct bdisp_frame *frame; struct bdisp_ctx *ctx = fh_to_ctx(fh); struct v4l2_rect *in, out; + bool valid = false; - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { - /* Composing / capture is not supported */ - dev_dbg(ctx->bdisp_dev->dev, "Not supported for capture\n"); - return -EINVAL; - } + if ((s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) && + (s->target == V4L2_SEL_TGT_CROP)) + valid = true; + + if ((s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && + (s->target == V4L2_SEL_TGT_COMPOSE)) + valid = true; - if (s->target != V4L2_SEL_TGT_CROP) { - dev_dbg(ctx->bdisp_dev->dev, "Invalid target\n"); + if (!valid) { + dev_err(ctx->bdisp_dev->dev, "Invalid type / target\n"); return -EINVAL; } -- GitLab From 24310279eb2851a2bdef9b267b43b98e252ce435 Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Fri, 10 Jul 2015 05:29:37 -0300 Subject: [PATCH 1064/7006] [media] bdisp: add debug info for RGB24 format Add this missing debug information Signed-off-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-debug.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c index 18282a0f80c97..79c56356a7c7a 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-debug.c +++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c @@ -116,6 +116,9 @@ static void bdisp_dbg_dump_tty(struct seq_file *s, u32 val) case BDISP_RGB565: seq_puts(s, "RGB565 - "); break; + case BDISP_RGB888: + seq_puts(s, "RGB888 - "); + break; case BDISP_XRGB8888: seq_puts(s, "xRGB888 - "); break; @@ -185,6 +188,9 @@ static void bdisp_dbg_dump_sty(struct seq_file *s, case BDISP_RGB565: seq_puts(s, "RGB565 - "); break; + case BDISP_RGB888: + seq_puts(s, "RGB888 - "); + break; case BDISP_XRGB8888: seq_puts(s, "xRGB888 - "); break; @@ -420,6 +426,8 @@ static const char *bdisp_fmt_to_str(struct bdisp_frame frame) return "NV12"; case V4L2_PIX_FMT_RGB565: return "RGB16"; + case V4L2_PIX_FMT_RGB24: + return "RGB24"; case V4L2_PIX_FMT_XBGR32: return "XRGB"; case V4L2_PIX_FMT_ABGR32: -- GitLab From bde2b96d6dfb1c14e5d27a4e7e7d492e9be102cd Mon Sep 17 00:00:00 2001 From: Fabien Dessenne Date: Mon, 13 Jul 2015 06:54:11 -0300 Subject: [PATCH 1065/7006] [media] bdisp: fix debug info memory access bdisp_dev->dbg.copy_node shall be a copy of (and not point to) bdisp_ctx->node, since this resource is freed upon driver release. Signed-off-by: Fabien Dessenne Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-hw.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sti/bdisp/bdisp-hw.c b/drivers/media/platform/sti/bdisp/bdisp-hw.c index c83f9c2fbe3c7..052c932ac9426 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-hw.c +++ b/drivers/media/platform/sti/bdisp/bdisp-hw.c @@ -768,12 +768,12 @@ static void bdisp_hw_save_request(struct bdisp_ctx *ctx) /* Allocate memory if not done yet */ if (!copy_node[i]) { copy_node[i] = devm_kzalloc(ctx->bdisp_dev->dev, - sizeof(*copy_node), + sizeof(*copy_node[i]), GFP_KERNEL); if (!copy_node[i]) return; } - copy_node[i] = node[i]; + *copy_node[i] = *node[i]; } } -- GitLab From 6986a0e2556df3dfb54c624b50b02936bd1e00ef Mon Sep 17 00:00:00 2001 From: Heloise NH Date: Fri, 17 Jul 2015 09:42:06 +0800 Subject: [PATCH 1066/7006] ALSA: hda: fix kstrdup return value In kstrdup we should return -ENOMEM when it reports an memory allocation failure, while the -ENODEV is referred to a failure in finding the cpu node in the device tree. Signed-off-by: Heloise NH Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5de3c5d8c2c00..d78fa713c103d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -975,7 +975,7 @@ int snd_hda_codec_new(struct hda_bus *bus, struct snd_card *card, if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { - err = -ENODEV; + err = -ENOMEM; goto error; } } -- GitLab From d32d98642de66048f9534a05f3641558e811bbc9 Mon Sep 17 00:00:00 2001 From: Mats Randgaard Date: Thu, 9 Jul 2015 05:45:47 -0300 Subject: [PATCH 1067/7006] [media] Driver for Toshiba TC358743 HDMI to CSI-2 bridge The driver is tested on our hardware and all the implemented features works as expected. Missing features: - CEC support - HDCP repeater support - IR support Signed-off-by: Mats Randgaard [hans.verkuil@cisco.com: updated copyright year to 2015] [hans.verkuil@cisco.com: update confusing confctl_mutex comment] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 7 + drivers/media/i2c/Kconfig | 9 + drivers/media/i2c/Makefile | 1 + drivers/media/i2c/tc358743.c | 1778 ++++++++++++++++++++++++++++ drivers/media/i2c/tc358743_regs.h | 681 +++++++++++ include/media/tc358743.h | 131 ++ include/uapi/linux/v4l2-controls.h | 4 + 7 files changed, 2611 insertions(+) create mode 100644 drivers/media/i2c/tc358743.c create mode 100644 drivers/media/i2c/tc358743_regs.h create mode 100644 include/media/tc358743.h diff --git a/MAINTAINERS b/MAINTAINERS index fd60784430838..2bb989be111d3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10319,6 +10319,13 @@ F: drivers/char/toshiba.c F: include/linux/toshiba.h F: include/uapi/linux/toshiba.h +TOSHIBA TC358743 DRIVER +M: Mats Randgaard +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/i2c/tc358743* +F: include/media/tc358743.h + TMIO MMC DRIVER M: Ian Molton L: linux-mmc@vger.kernel.org diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 8d1268648fe0b..0e0490d60e7e0 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -287,6 +287,15 @@ config VIDEO_SAA711X To compile this driver as a module, choose M here: the module will be called saa7115. +config VIDEO_TC358743 + tristate "Toshiba TC358743 decoder" + depends on VIDEO_V4L2 && I2C + ---help--- + Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge. + + To compile this driver as a module, choose M here: the + module will be called tc358743. + config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" depends on VIDEO_V4L2 && I2C diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index f165faea5b3f9..07db257abfc1a 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -78,3 +78,4 @@ obj-$(CONFIG_VIDEO_AK881X) += ak881x.o obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o obj-$(CONFIG_VIDEO_OV2659) += ov2659.o +obj-$(CONFIG_VIDEO_TC358743) += tc358743.o diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c new file mode 100644 index 0000000000000..4e8811c3e7710 --- /dev/null +++ b/drivers/media/i2c/tc358743.c @@ -0,0 +1,1778 @@ +/* + * tc358743 - Toshiba HDMI to CSI-2 bridge + * + * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights + * reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + */ + +/* + * References (c = chapter, p = page): + * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 + * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tc358743_regs.h" + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-3)"); + +MODULE_DESCRIPTION("Toshiba TC358743 HDMI to CSI-2 bridge driver"); +MODULE_AUTHOR("Ramakrishnan Muthukrishnan "); +MODULE_AUTHOR("Mikhail Khelik "); +MODULE_AUTHOR("Mats Randgaard "); +MODULE_LICENSE("GPL"); + +#define EDID_NUM_BLOCKS_MAX 8 +#define EDID_BLOCK_SIZE 128 + +static const struct v4l2_dv_timings_cap tc358743_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + /* Pixel clock from REF_01 p. 20. Min/max height/width are unknown */ + V4L2_INIT_BT_TIMINGS(1, 10000, 1, 10000, 0, 165000000, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_GTF | V4L2_DV_BT_STD_CVT, + V4L2_DV_BT_CAP_PROGRESSIVE | + V4L2_DV_BT_CAP_REDUCED_BLANKING | + V4L2_DV_BT_CAP_CUSTOM) +}; + +struct tc358743_state { + struct tc358743_platform_data pdata; + struct v4l2_subdev sd; + struct media_pad pad; + struct v4l2_ctrl_handler hdl; + struct i2c_client *i2c_client; + /* CONFCTL is modified in ops and tc358743_hdmi_sys_int_handler */ + struct mutex confctl_mutex; + + /* controls */ + struct v4l2_ctrl *detect_tx_5v_ctrl; + struct v4l2_ctrl *audio_sampling_rate_ctrl; + struct v4l2_ctrl *audio_present_ctrl; + + /* work queues */ + struct workqueue_struct *work_queues; + struct delayed_work delayed_work_enable_hotplug; + + /* edid */ + u8 edid_blocks_written; + + struct v4l2_dv_timings timings; + u32 mbus_fmt_code; +}; + +static void tc358743_enable_interrupts(struct v4l2_subdev *sd, + bool cable_connected); +static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd); + +static inline struct tc358743_state *to_state(struct v4l2_subdev *sd) +{ + return container_of(sd, struct tc358743_state, sd); +} + +/* --------------- I2C --------------- */ + +static void i2c_rd(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) +{ + struct tc358743_state *state = to_state(sd); + struct i2c_client *client = state->i2c_client; + int err; + u8 buf[2] = { reg >> 8, reg & 0xff }; + struct i2c_msg msgs[] = { + { + .addr = client->addr, + .flags = 0, + .len = 2, + .buf = buf, + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = n, + .buf = values, + }, + }; + + err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (err != ARRAY_SIZE(msgs)) { + v4l2_err(sd, "%s: reading register 0x%x from 0x%x failed\n", + __func__, reg, client->addr); + } +} + +static void i2c_wr(struct v4l2_subdev *sd, u16 reg, u8 *values, u32 n) +{ + struct tc358743_state *state = to_state(sd); + struct i2c_client *client = state->i2c_client; + int err, i; + struct i2c_msg msg; + u8 data[2 + n]; + + msg.addr = client->addr; + msg.buf = data; + msg.len = 2 + n; + msg.flags = 0; + + data[0] = reg >> 8; + data[1] = reg & 0xff; + + for (i = 0; i < n; i++) + data[2 + i] = values[i]; + + err = i2c_transfer(client->adapter, &msg, 1); + if (err != 1) { + v4l2_err(sd, "%s: writing register 0x%x from 0x%x failed\n", + __func__, reg, client->addr); + return; + } + + if (debug < 3) + return; + + switch (n) { + case 1: + v4l2_info(sd, "I2C write 0x%04x = 0x%02x", + reg, data[2]); + break; + case 2: + v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x", + reg, data[3], data[2]); + break; + case 4: + v4l2_info(sd, "I2C write 0x%04x = 0x%02x%02x%02x%02x", + reg, data[5], data[4], data[3], data[2]); + break; + default: + v4l2_info(sd, "I2C write %d bytes from address 0x%04x\n", + n, reg); + } +} + +static u8 i2c_rd8(struct v4l2_subdev *sd, u16 reg) +{ + u8 val; + + i2c_rd(sd, reg, &val, 1); + + return val; +} + +static void i2c_wr8(struct v4l2_subdev *sd, u16 reg, u8 val) +{ + i2c_wr(sd, reg, &val, 1); +} + +static void i2c_wr8_and_or(struct v4l2_subdev *sd, u16 reg, + u8 mask, u8 val) +{ + i2c_wr8(sd, reg, (i2c_rd8(sd, reg) & mask) | val); +} + +static u16 i2c_rd16(struct v4l2_subdev *sd, u16 reg) +{ + u16 val; + + i2c_rd(sd, reg, (u8 *)&val, 2); + + return val; +} + +static void i2c_wr16(struct v4l2_subdev *sd, u16 reg, u16 val) +{ + i2c_wr(sd, reg, (u8 *)&val, 2); +} + +static void i2c_wr16_and_or(struct v4l2_subdev *sd, u16 reg, u16 mask, u16 val) +{ + i2c_wr16(sd, reg, (i2c_rd16(sd, reg) & mask) | val); +} + +static u32 i2c_rd32(struct v4l2_subdev *sd, u16 reg) +{ + u32 val; + + i2c_rd(sd, reg, (u8 *)&val, 4); + + return val; +} + +static void i2c_wr32(struct v4l2_subdev *sd, u16 reg, u32 val) +{ + i2c_wr(sd, reg, (u8 *)&val, 4); +} + +/* --------------- STATUS --------------- */ + +static inline bool is_hdmi(struct v4l2_subdev *sd) +{ + return i2c_rd8(sd, SYS_STATUS) & MASK_S_HDMI; +} + +static inline bool tx_5v_power_present(struct v4l2_subdev *sd) +{ + return i2c_rd8(sd, SYS_STATUS) & MASK_S_DDC5V; +} + +static inline bool no_signal(struct v4l2_subdev *sd) +{ + return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_TMDS); +} + +static inline bool no_sync(struct v4l2_subdev *sd) +{ + return !(i2c_rd8(sd, SYS_STATUS) & MASK_S_SYNC); +} + +static inline bool audio_present(struct v4l2_subdev *sd) +{ + return i2c_rd8(sd, AU_STATUS0) & MASK_S_A_SAMPLE; +} + +static int get_audio_sampling_rate(struct v4l2_subdev *sd) +{ + static const int code_to_rate[] = { + 44100, 0, 48000, 32000, 22050, 384000, 24000, 352800, + 88200, 768000, 96000, 705600, 176400, 0, 192000, 0 + }; + + /* Register FS_SET is not cleared when the cable is disconnected */ + if (no_signal(sd)) + return 0; + + return code_to_rate[i2c_rd8(sd, FS_SET) & MASK_FS]; +} + +static unsigned tc358743_num_csi_lanes_in_use(struct v4l2_subdev *sd) +{ + return ((i2c_rd32(sd, CSI_CONTROL) & MASK_NOL) >> 1) + 1; +} + +/* --------------- TIMINGS --------------- */ + +static inline unsigned fps(const struct v4l2_bt_timings *t) +{ + if (!V4L2_DV_BT_FRAME_HEIGHT(t) || !V4L2_DV_BT_FRAME_WIDTH(t)) + return 0; + + return DIV_ROUND_CLOSEST((unsigned)t->pixelclock, + V4L2_DV_BT_FRAME_HEIGHT(t) * V4L2_DV_BT_FRAME_WIDTH(t)); +} + +static int tc358743_get_detected_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct v4l2_bt_timings *bt = &timings->bt; + unsigned width, height, frame_width, frame_height, frame_interval, fps; + + memset(timings, 0, sizeof(struct v4l2_dv_timings)); + + if (no_signal(sd)) { + v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__); + return -ENOLINK; + } + if (no_sync(sd)) { + v4l2_dbg(1, debug, sd, "%s: no sync on signal\n", __func__); + return -ENOLCK; + } + + timings->type = V4L2_DV_BT_656_1120; + bt->interlaced = i2c_rd8(sd, VI_STATUS1) & MASK_S_V_INTERLACE ? + V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; + + width = ((i2c_rd8(sd, DE_WIDTH_H_HI) & 0x1f) << 8) + + i2c_rd8(sd, DE_WIDTH_H_LO); + height = ((i2c_rd8(sd, DE_WIDTH_V_HI) & 0x1f) << 8) + + i2c_rd8(sd, DE_WIDTH_V_LO); + frame_width = ((i2c_rd8(sd, H_SIZE_HI) & 0x1f) << 8) + + i2c_rd8(sd, H_SIZE_LO); + frame_height = (((i2c_rd8(sd, V_SIZE_HI) & 0x3f) << 8) + + i2c_rd8(sd, V_SIZE_LO)) / 2; + /* frame interval in milliseconds * 10 + * Require SYS_FREQ0 and SYS_FREQ1 are precisely set */ + frame_interval = ((i2c_rd8(sd, FV_CNT_HI) & 0x3) << 8) + + i2c_rd8(sd, FV_CNT_LO); + fps = (frame_interval > 0) ? + DIV_ROUND_CLOSEST(10000, frame_interval) : 0; + + bt->width = width; + bt->height = height; + bt->vsync = frame_height - height; + bt->hsync = frame_width - width; + bt->pixelclock = frame_width * frame_height * fps; + if (bt->interlaced == V4L2_DV_INTERLACED) { + bt->height *= 2; + bt->il_vsync = bt->vsync + 1; + bt->pixelclock /= 2; + } + + return 0; +} + +/* --------------- HOTPLUG / HDCP / EDID --------------- */ + +static void tc358743_delayed_work_enable_hotplug(struct work_struct *work) +{ + struct delayed_work *dwork = to_delayed_work(work); + struct tc358743_state *state = container_of(dwork, + struct tc358743_state, delayed_work_enable_hotplug); + struct v4l2_subdev *sd = &state->sd; + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, MASK_HPD_OUT0); +} + +static void tc358743_set_hdmi_hdcp(struct v4l2_subdev *sd, bool enable) +{ + v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? + "enable" : "disable"); + + i2c_wr8_and_or(sd, HDCP_REG1, + ~(MASK_AUTH_UNAUTH_SEL | MASK_AUTH_UNAUTH), + MASK_AUTH_UNAUTH_SEL_16_FRAMES | MASK_AUTH_UNAUTH_AUTO); + + i2c_wr8_and_or(sd, HDCP_REG2, ~MASK_AUTO_P3_RESET, + SET_AUTO_P3_RESET_FRAMES(0x0f)); + + /* HDCP is disabled by configuring the receiver as HDCP repeater. The + * repeater mode require software support to work, so HDCP + * authentication will fail. + */ + i2c_wr8_and_or(sd, HDCP_REG3, ~KEY_RD_CMD, enable ? KEY_RD_CMD : 0); + i2c_wr8_and_or(sd, HDCP_MODE, ~(MASK_AUTO_CLR | MASK_MODE_RST_TN), + enable ? (MASK_AUTO_CLR | MASK_MODE_RST_TN) : 0); + + /* Apple MacBook Pro gen.8 has a bug that makes it freeze every fifth + * second when HDCP is disabled, but the MAX_EXCED bit is handled + * correctly and HDCP is disabled on the HDMI output. + */ + i2c_wr8_and_or(sd, BSTATUS1, ~MASK_MAX_EXCED, + enable ? 0 : MASK_MAX_EXCED); + i2c_wr8_and_or(sd, BCAPS, ~(MASK_REPEATER | MASK_READY), + enable ? 0 : MASK_REPEATER | MASK_READY); +} + +static void tc358743_disable_edid(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + cancel_delayed_work_sync(&state->delayed_work_enable_hotplug); + + /* DDC access to EDID is also disabled when hotplug is disabled. See + * register DDC_CTL */ + i2c_wr8_and_or(sd, HPD_CTL, ~MASK_HPD_OUT0, 0x0); +} + +static void tc358743_enable_edid(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + if (state->edid_blocks_written == 0) { + v4l2_dbg(2, debug, sd, "%s: no EDID -> no hotplug\n", __func__); + return; + } + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + /* Enable hotplug after 100 ms. DDC access to EDID is also enabled when + * hotplug is enabled. See register DDC_CTL */ + queue_delayed_work(state->work_queues, + &state->delayed_work_enable_hotplug, HZ / 10); + + tc358743_enable_interrupts(sd, true); + tc358743_s_ctrl_detect_tx_5v(sd); +} + +static void tc358743_erase_bksv(struct v4l2_subdev *sd) +{ + int i; + + for (i = 0; i < 5; i++) + i2c_wr8(sd, BKSV + i, 0); +} + +/* --------------- AVI infoframe --------------- */ + +static void print_avi_infoframe(struct v4l2_subdev *sd) +{ + struct i2c_client *client = v4l2_get_subdevdata(sd); + struct device *dev = &client->dev; + union hdmi_infoframe frame; + u8 buffer[HDMI_INFOFRAME_SIZE(AVI)]; + + if (!is_hdmi(sd)) { + v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n"); + return; + } + + i2c_rd(sd, PK_AVI_0HEAD, buffer, HDMI_INFOFRAME_SIZE(AVI)); + + if (hdmi_infoframe_unpack(&frame, buffer) < 0) { + v4l2_err(sd, "%s: unpack of AVI infoframe failed\n", __func__); + return; + } + + hdmi_infoframe_log(KERN_INFO, dev, &frame); +} + +/* --------------- CTRLS --------------- */ + +static int tc358743_s_ctrl_detect_tx_5v(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl, + tx_5v_power_present(sd)); +} + +static int tc358743_s_ctrl_audio_sampling_rate(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + return v4l2_ctrl_s_ctrl(state->audio_sampling_rate_ctrl, + get_audio_sampling_rate(sd)); +} + +static int tc358743_s_ctrl_audio_present(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + return v4l2_ctrl_s_ctrl(state->audio_present_ctrl, + audio_present(sd)); +} + +static int tc358743_update_controls(struct v4l2_subdev *sd) +{ + int ret = 0; + + ret |= tc358743_s_ctrl_detect_tx_5v(sd); + ret |= tc358743_s_ctrl_audio_sampling_rate(sd); + ret |= tc358743_s_ctrl_audio_present(sd); + + return ret; +} + +/* --------------- INIT --------------- */ + +static void tc358743_reset_phy(struct v4l2_subdev *sd) +{ + v4l2_dbg(1, debug, sd, "%s:\n", __func__); + + i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, 0); + i2c_wr8_and_or(sd, PHY_RST, ~MASK_RESET_CTRL, MASK_RESET_CTRL); +} + +static void tc358743_reset(struct v4l2_subdev *sd, uint16_t mask) +{ + u16 sysctl = i2c_rd16(sd, SYSCTL); + + i2c_wr16(sd, SYSCTL, sysctl | mask); + i2c_wr16(sd, SYSCTL, sysctl & ~mask); +} + +static inline void tc358743_sleep_mode(struct v4l2_subdev *sd, bool enable) +{ + i2c_wr16_and_or(sd, SYSCTL, ~MASK_SLEEP, + enable ? MASK_SLEEP : 0); +} + +static inline void enable_stream(struct v4l2_subdev *sd, bool enable) +{ + struct tc358743_state *state = to_state(sd); + + v4l2_dbg(3, debug, sd, "%s: %sable\n", + __func__, enable ? "en" : "dis"); + + if (enable) { + /* It is critical for CSI receiver to see lane transition + * LP11->HS. Set to non-continuous mode to enable clock lane + * LP11 state. */ + i2c_wr32(sd, TXOPTIONCNTRL, 0); + /* Set to continuous mode to trigger LP11->HS transition */ + i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); + /* Unmute video */ + i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE); + } else { + /* Mute video so that all data lanes go to LSP11 state. + * No data is output to CSI Tx block. */ + i2c_wr8(sd, VI_MUTE, MASK_AUTO_MUTE | MASK_VI_MUTE); + } + + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, ~(MASK_VBUFEN | MASK_ABUFEN), + enable ? (MASK_VBUFEN | MASK_ABUFEN) : 0x0); + mutex_unlock(&state->confctl_mutex); +} + +static void tc358743_set_pll(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + u16 pllctl0 = i2c_rd16(sd, PLLCTL0); + u16 pllctl1 = i2c_rd16(sd, PLLCTL1); + u16 pllctl0_new = SET_PLL_PRD(pdata->pll_prd) | + SET_PLL_FBD(pdata->pll_fbd); + u32 hsck = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; + + v4l2_dbg(2, debug, sd, "%s:\n", __func__); + + /* Only rewrite when needed (new value or disabled), since rewriting + * triggers another format change event. */ + if ((pllctl0 != pllctl0_new) || ((pllctl1 & MASK_PLL_EN) == 0)) { + u16 pll_frs; + + if (hsck > 500000000) + pll_frs = 0x0; + else if (hsck > 250000000) + pll_frs = 0x1; + else if (hsck > 125000000) + pll_frs = 0x2; + else + pll_frs = 0x3; + + v4l2_dbg(1, debug, sd, "%s: updating PLL clock\n", __func__); + tc358743_sleep_mode(sd, true); + i2c_wr16(sd, PLLCTL0, pllctl0_new); + i2c_wr16_and_or(sd, PLLCTL1, + ~(MASK_PLL_FRS | MASK_RESETB | MASK_PLL_EN), + (SET_PLL_FRS(pll_frs) | MASK_RESETB | + MASK_PLL_EN)); + udelay(10); /* REF_02, Sheet "Source HDMI" */ + i2c_wr16_and_or(sd, PLLCTL1, ~MASK_CKEN, MASK_CKEN); + tc358743_sleep_mode(sd, false); + } +} + +static void tc358743_set_ref_clk(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + u32 sys_freq; + u32 lockdet_ref; + u16 fh_min; + u16 fh_max; + + BUG_ON(!(pdata->refclk_hz == 26000000 || + pdata->refclk_hz == 27000000 || + pdata->refclk_hz == 42000000)); + + sys_freq = pdata->refclk_hz / 10000; + i2c_wr8(sd, SYS_FREQ0, sys_freq & 0x00ff); + i2c_wr8(sd, SYS_FREQ1, (sys_freq & 0xff00) >> 8); + + i2c_wr8_and_or(sd, PHY_CTL0, ~MASK_PHY_SYSCLK_IND, + (pdata->refclk_hz == 42000000) ? + MASK_PHY_SYSCLK_IND : 0x0); + + fh_min = pdata->refclk_hz / 100000; + i2c_wr8(sd, FH_MIN0, fh_min & 0x00ff); + i2c_wr8(sd, FH_MIN1, (fh_min & 0xff00) >> 8); + + fh_max = (fh_min * 66) / 10; + i2c_wr8(sd, FH_MAX0, fh_max & 0x00ff); + i2c_wr8(sd, FH_MAX1, (fh_max & 0xff00) >> 8); + + lockdet_ref = pdata->refclk_hz / 100; + i2c_wr8(sd, LOCKDET_REF0, lockdet_ref & 0x0000ff); + i2c_wr8(sd, LOCKDET_REF1, (lockdet_ref & 0x00ff00) >> 8); + i2c_wr8(sd, LOCKDET_REF2, (lockdet_ref & 0x0f0000) >> 16); + + i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD, + (pdata->refclk_hz == 27000000) ? + MASK_NCO_F0_MOD_27MHZ : 0x0); +} + +static void tc358743_set_csi_color_space(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + switch (state->mbus_fmt_code) { + case MEDIA_BUS_FMT_UYVY8_1X16: + v4l2_dbg(2, debug, sd, "%s: YCbCr 422 16-bit\n", __func__); + i2c_wr8_and_or(sd, VOUT_SET2, + ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, + MASK_SEL422 | MASK_VOUT_422FIL_100); + i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, + MASK_VOUT_COLOR_601_YCBCR_LIMITED); + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, + MASK_YCBCRFMT_422_8_BIT); + mutex_unlock(&state->confctl_mutex); + break; + case MEDIA_BUS_FMT_RGB888_1X24: + v4l2_dbg(2, debug, sd, "%s: RGB 888 24-bit\n", __func__); + i2c_wr8_and_or(sd, VOUT_SET2, + ~(MASK_SEL422 | MASK_VOUT_422FIL_100) & 0xff, + 0x00); + i2c_wr8_and_or(sd, VI_REP, ~MASK_VOUT_COLOR_SEL & 0xff, + MASK_VOUT_COLOR_RGB_FULL); + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, ~MASK_YCBCRFMT, 0); + mutex_unlock(&state->confctl_mutex); + break; + default: + v4l2_dbg(2, debug, sd, "%s: Unsupported format code 0x%x\n", + __func__, state->mbus_fmt_code); + } +} + +static unsigned tc358743_num_csi_lanes_needed(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_bt_timings *bt = &state->timings.bt; + struct tc358743_platform_data *pdata = &state->pdata; + u32 bits_pr_pixel = + (state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16) ? 16 : 24; + u32 bps = bt->width * bt->height * fps(bt) * bits_pr_pixel; + u32 bps_pr_lane = (pdata->refclk_hz / pdata->pll_prd) * pdata->pll_fbd; + + return DIV_ROUND_UP(bps, bps_pr_lane); +} + +static void tc358743_set_csi(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + unsigned lanes = tc358743_num_csi_lanes_needed(sd); + + v4l2_dbg(3, debug, sd, "%s:\n", __func__); + + tc358743_reset(sd, MASK_CTXRST); + + if (lanes < 1) + i2c_wr32(sd, CLW_CNTRL, MASK_CLW_LANEDISABLE); + if (lanes < 1) + i2c_wr32(sd, D0W_CNTRL, MASK_D0W_LANEDISABLE); + if (lanes < 2) + i2c_wr32(sd, D1W_CNTRL, MASK_D1W_LANEDISABLE); + if (lanes < 3) + i2c_wr32(sd, D2W_CNTRL, MASK_D2W_LANEDISABLE); + if (lanes < 4) + i2c_wr32(sd, D3W_CNTRL, MASK_D3W_LANEDISABLE); + + i2c_wr32(sd, LINEINITCNT, pdata->lineinitcnt); + i2c_wr32(sd, LPTXTIMECNT, pdata->lptxtimecnt); + i2c_wr32(sd, TCLK_HEADERCNT, pdata->tclk_headercnt); + i2c_wr32(sd, TCLK_TRAILCNT, pdata->tclk_trailcnt); + i2c_wr32(sd, THS_HEADERCNT, pdata->ths_headercnt); + i2c_wr32(sd, TWAKEUP, pdata->twakeup); + i2c_wr32(sd, TCLK_POSTCNT, pdata->tclk_postcnt); + i2c_wr32(sd, THS_TRAILCNT, pdata->ths_trailcnt); + i2c_wr32(sd, HSTXVREGCNT, pdata->hstxvregcnt); + + i2c_wr32(sd, HSTXVREGEN, + ((lanes > 0) ? MASK_CLM_HSTXVREGEN : 0x0) | + ((lanes > 0) ? MASK_D0M_HSTXVREGEN : 0x0) | + ((lanes > 1) ? MASK_D1M_HSTXVREGEN : 0x0) | + ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | + ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); + + i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); + i2c_wr32(sd, STARTCNTRL, MASK_START); + i2c_wr32(sd, CSI_START, MASK_STRT); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | + MASK_ADDRESS_CSI_CONTROL | + MASK_CSI_MODE | + MASK_TXHSMD | + ((lanes == 4) ? MASK_NOL_4 : + (lanes == 3) ? MASK_NOL_3 : + (lanes == 2) ? MASK_NOL_2 : MASK_NOL_1)); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | + MASK_ADDRESS_CSI_ERR_INTENA | MASK_TXBRK | MASK_QUNK | + MASK_WCER | MASK_INER); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_CLEAR | + MASK_ADDRESS_CSI_ERR_HALT | MASK_TXBRK | MASK_QUNK); + + i2c_wr32(sd, CSI_CONFW, MASK_MODE_SET | + MASK_ADDRESS_CSI_INT_ENA | MASK_INTER); +} + +static void tc358743_set_hdmi_phy(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + + /* Default settings from REF_02, sheet "Source HDMI" + * and custom settings as platform data */ + i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, 0x0); + i2c_wr8(sd, PHY_CTL1, SET_PHY_AUTO_RST1_US(1600) | + SET_FREQ_RANGE_MODE_CYCLES(1)); + i2c_wr8_and_or(sd, PHY_CTL2, ~MASK_PHY_AUTO_RSTn, + (pdata->hdmi_phy_auto_reset_tmds_detected ? + MASK_PHY_AUTO_RST2 : 0) | + (pdata->hdmi_phy_auto_reset_tmds_in_range ? + MASK_PHY_AUTO_RST3 : 0) | + (pdata->hdmi_phy_auto_reset_tmds_valid ? + MASK_PHY_AUTO_RST4 : 0)); + i2c_wr8(sd, PHY_BIAS, 0x40); + i2c_wr8(sd, PHY_CSQ, SET_CSQ_CNT_LEVEL(0x0a)); + i2c_wr8(sd, AVM_CTL, 45); + i2c_wr8_and_or(sd, HDMI_DET, ~MASK_HDMI_DET_V, + pdata->hdmi_detection_delay << 4); + i2c_wr8_and_or(sd, HV_RST, ~(MASK_H_PI_RST | MASK_V_PI_RST), + (pdata->hdmi_phy_auto_reset_hsync_out_of_range ? + MASK_H_PI_RST : 0) | + (pdata->hdmi_phy_auto_reset_vsync_out_of_range ? + MASK_V_PI_RST : 0)); + i2c_wr8_and_or(sd, PHY_EN, ~MASK_ENABLE_PHY, MASK_ENABLE_PHY); +} + +static void tc358743_set_hdmi_audio(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + + /* Default settings from REF_02, sheet "Source HDMI" */ + i2c_wr8(sd, FORCE_MUTE, 0x00); + i2c_wr8(sd, AUTO_CMD0, MASK_AUTO_MUTE7 | MASK_AUTO_MUTE6 | + MASK_AUTO_MUTE5 | MASK_AUTO_MUTE4 | + MASK_AUTO_MUTE1 | MASK_AUTO_MUTE0); + i2c_wr8(sd, AUTO_CMD1, MASK_AUTO_MUTE9); + i2c_wr8(sd, AUTO_CMD2, MASK_AUTO_PLAY3 | MASK_AUTO_PLAY2); + i2c_wr8(sd, BUFINIT_START, SET_BUFINIT_START_MS(500)); + i2c_wr8(sd, FS_MUTE, 0x00); + i2c_wr8(sd, FS_IMODE, MASK_NLPCM_SMODE | MASK_FS_SMODE); + i2c_wr8(sd, ACR_MODE, MASK_CTS_MODE); + i2c_wr8(sd, ACR_MDF0, MASK_ACR_L2MDF_1976_PPM | MASK_ACR_L1MDF_976_PPM); + i2c_wr8(sd, ACR_MDF1, MASK_ACR_L3MDF_3906_PPM); + i2c_wr8(sd, SDO_MODE1, MASK_SDO_FMT_I2S); + i2c_wr8(sd, DIV_MODE, SET_DIV_DLY_MS(100)); + + mutex_lock(&state->confctl_mutex); + i2c_wr16_and_or(sd, CONFCTL, 0xffff, MASK_AUDCHNUM_2 | + MASK_AUDOUTSEL_I2S | MASK_AUTOINDEX); + mutex_unlock(&state->confctl_mutex); +} + +static void tc358743_set_hdmi_info_frame_mode(struct v4l2_subdev *sd) +{ + /* Default settings from REF_02, sheet "Source HDMI" */ + i2c_wr8(sd, PK_INT_MODE, MASK_ISRC2_INT_MODE | MASK_ISRC_INT_MODE | + MASK_ACP_INT_MODE | MASK_VS_INT_MODE | + MASK_SPD_INT_MODE | MASK_MS_INT_MODE | + MASK_AUD_INT_MODE | MASK_AVI_INT_MODE); + i2c_wr8(sd, NO_PKT_LIMIT, 0x2c); + i2c_wr8(sd, NO_PKT_CLR, 0x53); + i2c_wr8(sd, ERR_PK_LIMIT, 0x01); + i2c_wr8(sd, NO_PKT_LIMIT2, 0x30); + i2c_wr8(sd, NO_GDB_LIMIT, 0x10); +} + +static void tc358743_initial_setup(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct tc358743_platform_data *pdata = &state->pdata; + + /* CEC and IR are not supported by this driver */ + i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST), + (MASK_CECRST | MASK_IRRST)); + + tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST); + tc358743_sleep_mode(sd, false); + + i2c_wr16(sd, FIFOCTL, pdata->fifo_level); + + tc358743_set_ref_clk(sd); + + i2c_wr8_and_or(sd, DDC_CTL, ~MASK_DDC5V_MODE, + pdata->ddc5v_delay & MASK_DDC5V_MODE); + i2c_wr8_and_or(sd, EDID_MODE, ~MASK_EDID_MODE, MASK_EDID_MODE_E_DDC); + + tc358743_set_hdmi_phy(sd); + tc358743_set_hdmi_hdcp(sd, pdata->enable_hdcp); + tc358743_set_hdmi_audio(sd); + tc358743_set_hdmi_info_frame_mode(sd); + + /* All CE and IT formats are detected as RGB full range in DVI mode */ + i2c_wr8_and_or(sd, VI_MODE, ~MASK_RGB_DVI, 0); + + i2c_wr8_and_or(sd, VOUT_SET2, ~MASK_VOUTCOLORMODE, + MASK_VOUTCOLORMODE_AUTO); + i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT); +} + +/* --------------- IRQ --------------- */ + +static void tc358743_format_change(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_dv_timings timings; + const struct v4l2_event tc358743_ev_fmt = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + if (tc358743_get_detected_timings(sd, &timings)) { + enable_stream(sd, false); + + v4l2_dbg(1, debug, sd, "%s: Format changed. No signal\n", + __func__); + } else { + if (!v4l2_match_dv_timings(&state->timings, &timings, 0)) + enable_stream(sd, false); + + v4l2_print_dv_timings(sd->name, + "tc358743_format_change: Format changed. New format: ", + &timings, false); + } + + v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, + (void *)&tc358743_ev_fmt); +} + +static void tc358743_init_interrupts(struct v4l2_subdev *sd) +{ + u16 i; + + /* clear interrupt status registers */ + for (i = SYS_INT; i <= KEY_INT; i++) + i2c_wr8(sd, i, 0xff); + + i2c_wr16(sd, INTSTATUS, 0xffff); +} + +static void tc358743_enable_interrupts(struct v4l2_subdev *sd, + bool cable_connected) +{ + v4l2_dbg(2, debug, sd, "%s: cable connected = %d\n", __func__, + cable_connected); + + if (cable_connected) { + i2c_wr8(sd, SYS_INTM, ~(MASK_M_DDC | MASK_M_DVI_DET | + MASK_M_HDMI_DET) & 0xff); + i2c_wr8(sd, CLK_INTM, ~MASK_M_IN_DE_CHG); + i2c_wr8(sd, CBIT_INTM, ~(MASK_M_CBIT_FS | MASK_M_AF_LOCK | + MASK_M_AF_UNLOCK) & 0xff); + i2c_wr8(sd, AUDIO_INTM, ~MASK_M_BUFINIT_END); + i2c_wr8(sd, MISC_INTM, ~MASK_M_SYNC_CHG); + } else { + i2c_wr8(sd, SYS_INTM, ~MASK_M_DDC & 0xff); + i2c_wr8(sd, CLK_INTM, 0xff); + i2c_wr8(sd, CBIT_INTM, 0xff); + i2c_wr8(sd, AUDIO_INTM, 0xff); + i2c_wr8(sd, MISC_INTM, 0xff); + } +} + +static void tc358743_hdmi_audio_int_handler(struct v4l2_subdev *sd, + bool *handled) +{ + u8 audio_int_mask = i2c_rd8(sd, AUDIO_INTM); + u8 audio_int = i2c_rd8(sd, AUDIO_INT) & ~audio_int_mask; + + i2c_wr8(sd, AUDIO_INT, audio_int); + + v4l2_dbg(3, debug, sd, "%s: AUDIO_INT = 0x%02x\n", __func__, audio_int); + + tc358743_s_ctrl_audio_sampling_rate(sd); + tc358743_s_ctrl_audio_present(sd); +} + +static void tc358743_csi_err_int_handler(struct v4l2_subdev *sd, bool *handled) +{ + v4l2_err(sd, "%s: CSI_ERR = 0x%x\n", __func__, i2c_rd32(sd, CSI_ERR)); + + i2c_wr32(sd, CSI_INT_CLR, MASK_ICRER); +} + +static void tc358743_hdmi_misc_int_handler(struct v4l2_subdev *sd, + bool *handled) +{ + u8 misc_int_mask = i2c_rd8(sd, MISC_INTM); + u8 misc_int = i2c_rd8(sd, MISC_INT) & ~misc_int_mask; + + i2c_wr8(sd, MISC_INT, misc_int); + + v4l2_dbg(3, debug, sd, "%s: MISC_INT = 0x%02x\n", __func__, misc_int); + + if (misc_int & MASK_I_SYNC_CHG) { + /* Reset the HDMI PHY to try to trigger proper lock on the + * incoming video format. Erase BKSV to prevent that old keys + * are used when a new source is connected. */ + if (no_sync(sd) || no_signal(sd)) { + tc358743_reset_phy(sd); + tc358743_erase_bksv(sd); + } + + tc358743_format_change(sd); + + misc_int &= ~MASK_I_SYNC_CHG; + if (handled) + *handled = true; + } + + if (misc_int) { + v4l2_err(sd, "%s: Unhandled MISC_INT interrupts: 0x%02x\n", + __func__, misc_int); + } +} + +static void tc358743_hdmi_cbit_int_handler(struct v4l2_subdev *sd, + bool *handled) +{ + u8 cbit_int_mask = i2c_rd8(sd, CBIT_INTM); + u8 cbit_int = i2c_rd8(sd, CBIT_INT) & ~cbit_int_mask; + + i2c_wr8(sd, CBIT_INT, cbit_int); + + v4l2_dbg(3, debug, sd, "%s: CBIT_INT = 0x%02x\n", __func__, cbit_int); + + if (cbit_int & MASK_I_CBIT_FS) { + + v4l2_dbg(1, debug, sd, "%s: Audio sample rate changed\n", + __func__); + tc358743_s_ctrl_audio_sampling_rate(sd); + + cbit_int &= ~MASK_I_CBIT_FS; + if (handled) + *handled = true; + } + + if (cbit_int & (MASK_I_AF_LOCK | MASK_I_AF_UNLOCK)) { + + v4l2_dbg(1, debug, sd, "%s: Audio present changed\n", + __func__); + tc358743_s_ctrl_audio_present(sd); + + cbit_int &= ~(MASK_I_AF_LOCK | MASK_I_AF_UNLOCK); + if (handled) + *handled = true; + } + + if (cbit_int) { + v4l2_err(sd, "%s: Unhandled CBIT_INT interrupts: 0x%02x\n", + __func__, cbit_int); + } +} + +static void tc358743_hdmi_clk_int_handler(struct v4l2_subdev *sd, bool *handled) +{ + u8 clk_int_mask = i2c_rd8(sd, CLK_INTM); + u8 clk_int = i2c_rd8(sd, CLK_INT) & ~clk_int_mask; + + /* Bit 7 and bit 6 are set even when they are masked */ + i2c_wr8(sd, CLK_INT, clk_int | 0x80 | MASK_I_OUT_H_CHG); + + v4l2_dbg(3, debug, sd, "%s: CLK_INT = 0x%02x\n", __func__, clk_int); + + if (clk_int & (MASK_I_IN_DE_CHG)) { + + v4l2_dbg(1, debug, sd, "%s: DE size or position has changed\n", + __func__); + + /* If the source switch to a new resolution with the same pixel + * frequency as the existing (e.g. 1080p25 -> 720p50), the + * I_SYNC_CHG interrupt is not always triggered, while the + * I_IN_DE_CHG interrupt seems to work fine. Format change + * notifications are only sent when the signal is stable to + * reduce the number of notifications. */ + if (!no_signal(sd) && !no_sync(sd)) + tc358743_format_change(sd); + + clk_int &= ~(MASK_I_IN_DE_CHG); + if (handled) + *handled = true; + } + + if (clk_int) { + v4l2_err(sd, "%s: Unhandled CLK_INT interrupts: 0x%02x\n", + __func__, clk_int); + } +} + +static void tc358743_hdmi_sys_int_handler(struct v4l2_subdev *sd, bool *handled) +{ + struct tc358743_state *state = to_state(sd); + u8 sys_int_mask = i2c_rd8(sd, SYS_INTM); + u8 sys_int = i2c_rd8(sd, SYS_INT) & ~sys_int_mask; + + i2c_wr8(sd, SYS_INT, sys_int); + + v4l2_dbg(3, debug, sd, "%s: SYS_INT = 0x%02x\n", __func__, sys_int); + + if (sys_int & MASK_I_DDC) { + bool tx_5v = tx_5v_power_present(sd); + + v4l2_dbg(1, debug, sd, "%s: Tx 5V power present: %s\n", + __func__, tx_5v ? "yes" : "no"); + + if (tx_5v) { + tc358743_enable_edid(sd); + } else { + tc358743_enable_interrupts(sd, false); + tc358743_disable_edid(sd); + memset(&state->timings, 0, sizeof(state->timings)); + tc358743_erase_bksv(sd); + tc358743_update_controls(sd); + } + + sys_int &= ~MASK_I_DDC; + if (handled) + *handled = true; + } + + if (sys_int & MASK_I_DVI) { + v4l2_dbg(1, debug, sd, "%s: HDMI->DVI change detected\n", + __func__); + + /* Reset the HDMI PHY to try to trigger proper lock on the + * incoming video format. Erase BKSV to prevent that old keys + * are used when a new source is connected. */ + if (no_sync(sd) || no_signal(sd)) { + tc358743_reset_phy(sd); + tc358743_erase_bksv(sd); + } + + sys_int &= ~MASK_I_DVI; + if (handled) + *handled = true; + } + + if (sys_int & MASK_I_HDMI) { + v4l2_dbg(1, debug, sd, "%s: DVI->HDMI change detected\n", + __func__); + + /* Register is reset in DVI mode (REF_01, c. 6.6.41) */ + i2c_wr8(sd, ANA_CTL, MASK_APPL_PCSX_NORMAL | MASK_ANALOG_ON); + + sys_int &= ~MASK_I_HDMI; + if (handled) + *handled = true; + } + + if (sys_int) { + v4l2_err(sd, "%s: Unhandled SYS_INT interrupts: 0x%02x\n", + __func__, sys_int); + } +} + +/* --------------- CORE OPS --------------- */ + +static int tc358743_log_status(struct v4l2_subdev *sd) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_dv_timings timings; + uint8_t hdmi_sys_status = i2c_rd8(sd, SYS_STATUS); + uint16_t sysctl = i2c_rd16(sd, SYSCTL); + u8 vi_status3 = i2c_rd8(sd, VI_STATUS3); + const int deep_color_mode[4] = { 8, 10, 12, 16 }; + static const char * const input_color_space[] = { + "RGB", "YCbCr 601", "Adobe RGB", "YCbCr 709", "NA (4)", + "xvYCC 601", "NA(6)", "xvYCC 709", "NA(8)", "sYCC601", + "NA(10)", "NA(11)", "NA(12)", "Adobe YCC 601"}; + + v4l2_info(sd, "-----Chip status-----\n"); + v4l2_info(sd, "Chip ID: 0x%02x\n", + (i2c_rd16(sd, CHIPID) & MASK_CHIPID) >> 8); + v4l2_info(sd, "Chip revision: 0x%02x\n", + i2c_rd16(sd, CHIPID) & MASK_REVID); + v4l2_info(sd, "Reset: IR: %d, CEC: %d, CSI TX: %d, HDMI: %d\n", + !!(sysctl & MASK_IRRST), + !!(sysctl & MASK_CECRST), + !!(sysctl & MASK_CTXRST), + !!(sysctl & MASK_HDMIRST)); + v4l2_info(sd, "Sleep mode: %s\n", sysctl & MASK_SLEEP ? "on" : "off"); + v4l2_info(sd, "Cable detected (+5V power): %s\n", + hdmi_sys_status & MASK_S_DDC5V ? "yes" : "no"); + v4l2_info(sd, "DDC lines enabled: %s\n", + (i2c_rd8(sd, EDID_MODE) & MASK_EDID_MODE_E_DDC) ? + "yes" : "no"); + v4l2_info(sd, "Hotplug enabled: %s\n", + (i2c_rd8(sd, HPD_CTL) & MASK_HPD_OUT0) ? + "yes" : "no"); + v4l2_info(sd, "CEC enabled: %s\n", + (i2c_rd16(sd, CECEN) & MASK_CECEN) ? "yes" : "no"); + v4l2_info(sd, "-----Signal status-----\n"); + v4l2_info(sd, "TMDS signal detected: %s\n", + hdmi_sys_status & MASK_S_TMDS ? "yes" : "no"); + v4l2_info(sd, "Stable sync signal: %s\n", + hdmi_sys_status & MASK_S_SYNC ? "yes" : "no"); + v4l2_info(sd, "PHY PLL locked: %s\n", + hdmi_sys_status & MASK_S_PHY_PLL ? "yes" : "no"); + v4l2_info(sd, "PHY DE detected: %s\n", + hdmi_sys_status & MASK_S_PHY_SCDT ? "yes" : "no"); + + if (tc358743_get_detected_timings(sd, &timings)) { + v4l2_info(sd, "No video detected\n"); + } else { + v4l2_print_dv_timings(sd->name, "Detected format: ", &timings, + true); + } + v4l2_print_dv_timings(sd->name, "Configured format: ", &state->timings, + true); + + v4l2_info(sd, "-----CSI-TX status-----\n"); + v4l2_info(sd, "Lanes needed: %d\n", + tc358743_num_csi_lanes_needed(sd)); + v4l2_info(sd, "Lanes in use: %d\n", + tc358743_num_csi_lanes_in_use(sd)); + v4l2_info(sd, "Waiting for particular sync signal: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_WSYNC) ? + "yes" : "no"); + v4l2_info(sd, "Transmit mode: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_TXACT) ? + "yes" : "no"); + v4l2_info(sd, "Receive mode: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_RXACT) ? + "yes" : "no"); + v4l2_info(sd, "Stopped: %s\n", + (i2c_rd16(sd, CSI_STATUS) & MASK_S_HLT) ? + "yes" : "no"); + v4l2_info(sd, "Color space: %s\n", + state->mbus_fmt_code == MEDIA_BUS_FMT_UYVY8_1X16 ? + "YCbCr 422 16-bit" : + state->mbus_fmt_code == MEDIA_BUS_FMT_RGB888_1X24 ? + "RGB 888 24-bit" : "Unsupported"); + + v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D"); + v4l2_info(sd, "HDCP encrypted content: %s\n", + hdmi_sys_status & MASK_S_HDCP ? "yes" : "no"); + v4l2_info(sd, "Input color space: %s %s range\n", + input_color_space[(vi_status3 & MASK_S_V_COLOR) >> 1], + (vi_status3 & MASK_LIMITED) ? "limited" : "full"); + if (!is_hdmi(sd)) + return 0; + v4l2_info(sd, "AV Mute: %s\n", hdmi_sys_status & MASK_S_AVMUTE ? "on" : + "off"); + v4l2_info(sd, "Deep color mode: %d-bits per channel\n", + deep_color_mode[(i2c_rd8(sd, VI_STATUS1) & + MASK_S_DEEPCOLOR) >> 2]); + print_avi_infoframe(sd); + + return 0; +} + +#ifdef CONFIG_VIDEO_ADV_DEBUG +static void tc358743_print_register_map(struct v4l2_subdev *sd) +{ + v4l2_info(sd, "0x0000–0x00FF: Global Control Register\n"); + v4l2_info(sd, "0x0100–0x01FF: CSI2-TX PHY Register\n"); + v4l2_info(sd, "0x0200–0x03FF: CSI2-TX PPI Register\n"); + v4l2_info(sd, "0x0400–0x05FF: Reserved\n"); + v4l2_info(sd, "0x0600–0x06FF: CEC Register\n"); + v4l2_info(sd, "0x0700–0x84FF: Reserved\n"); + v4l2_info(sd, "0x8500–0x85FF: HDMIRX System Control Register\n"); + v4l2_info(sd, "0x8600–0x86FF: HDMIRX Audio Control Register\n"); + v4l2_info(sd, "0x8700–0x87FF: HDMIRX InfoFrame packet data Register\n"); + v4l2_info(sd, "0x8800–0x88FF: HDMIRX HDCP Port Register\n"); + v4l2_info(sd, "0x8900–0x89FF: HDMIRX Video Output Port & 3D Register\n"); + v4l2_info(sd, "0x8A00–0x8BFF: Reserved\n"); + v4l2_info(sd, "0x8C00–0x8FFF: HDMIRX EDID-RAM (1024bytes)\n"); + v4l2_info(sd, "0x9000–0x90FF: HDMIRX GBD Extraction Control\n"); + v4l2_info(sd, "0x9100–0x92FF: HDMIRX GBD RAM read\n"); + v4l2_info(sd, "0x9300- : Reserved\n"); +} + +static int tc358743_get_reg_size(u16 address) +{ + /* REF_01 p. 66-72 */ + if (address <= 0x00ff) + return 2; + else if ((address >= 0x0100) && (address <= 0x06FF)) + return 4; + else if ((address >= 0x0700) && (address <= 0x84ff)) + return 2; + else + return 1; +} + +static int tc358743_g_register(struct v4l2_subdev *sd, + struct v4l2_dbg_register *reg) +{ + if (reg->reg > 0xffff) { + tc358743_print_register_map(sd); + return -EINVAL; + } + + reg->size = tc358743_get_reg_size(reg->reg); + + i2c_rd(sd, reg->reg, (u8 *)®->val, reg->size); + + return 0; +} + +static int tc358743_s_register(struct v4l2_subdev *sd, + const struct v4l2_dbg_register *reg) +{ + if (reg->reg > 0xffff) { + tc358743_print_register_map(sd); + return -EINVAL; + } + + /* It should not be possible for the user to enable HDCP with a simple + * v4l2-dbg command. + * + * DO NOT REMOVE THIS unless all other issues with HDCP have been + * resolved. + */ + if (reg->reg == HDCP_MODE || + reg->reg == HDCP_REG1 || + reg->reg == HDCP_REG2 || + reg->reg == HDCP_REG3 || + reg->reg == BCAPS) + return 0; + + i2c_wr(sd, (u16)reg->reg, (u8 *)®->val, + tc358743_get_reg_size(reg->reg)); + + return 0; +} +#endif + +static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) +{ + u16 intstatus = i2c_rd16(sd, INTSTATUS); + + v4l2_dbg(1, debug, sd, "%s: IntStatus = 0x%04x\n", __func__, intstatus); + + if (intstatus & MASK_HDMI_INT) { + u8 hdmi_int0 = i2c_rd8(sd, HDMI_INT0); + u8 hdmi_int1 = i2c_rd8(sd, HDMI_INT1); + + if (hdmi_int0 & MASK_I_MISC) + tc358743_hdmi_misc_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_CBIT) + tc358743_hdmi_cbit_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_CLK) + tc358743_hdmi_clk_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_SYS) + tc358743_hdmi_sys_int_handler(sd, handled); + if (hdmi_int1 & MASK_I_AUD) + tc358743_hdmi_audio_int_handler(sd, handled); + + i2c_wr16(sd, INTSTATUS, MASK_HDMI_INT); + intstatus &= ~MASK_HDMI_INT; + } + + if (intstatus & MASK_CSI_INT) { + u32 csi_int = i2c_rd32(sd, CSI_INT); + + if (csi_int & MASK_INTER) + tc358743_csi_err_int_handler(sd, handled); + + i2c_wr16(sd, INTSTATUS, MASK_CSI_INT); + intstatus &= ~MASK_CSI_INT; + } + + intstatus = i2c_rd16(sd, INTSTATUS); + if (intstatus) { + v4l2_dbg(1, debug, sd, + "%s: Unhandled IntStatus interrupts: 0x%02x\n", + __func__, intstatus); + } + + return 0; +} + +/* --------------- VIDEO OPS --------------- */ + +static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) +{ + *status = 0; + *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0; + *status |= no_sync(sd) ? V4L2_IN_ST_NO_SYNC : 0; + + v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status); + + return 0; +} + +static int tc358743_s_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tc358743_state *state = to_state(sd); + struct v4l2_bt_timings *bt; + + if (!timings) + return -EINVAL; + + if (debug) + v4l2_print_dv_timings(sd->name, "tc358743_s_dv_timings: ", + timings, false); + + if (v4l2_match_dv_timings(&state->timings, timings, 0)) { + v4l2_dbg(1, debug, sd, "%s: no change\n", __func__); + return 0; + } + + bt = &timings->bt; + + if (!v4l2_valid_dv_timings(timings, + &tc358743_timings_cap, NULL, NULL)) { + v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); + return -ERANGE; + } + + state->timings = *timings; + + enable_stream(sd, false); + tc358743_set_pll(sd); + tc358743_set_csi(sd); + + return 0; +} + +static int tc358743_g_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + struct tc358743_state *state = to_state(sd); + + *timings = state->timings; + + return 0; +} + +static int tc358743_enum_dv_timings(struct v4l2_subdev *sd, + struct v4l2_enum_dv_timings *timings) +{ + if (timings->pad != 0) + return -EINVAL; + + return v4l2_enum_dv_timings_cap(timings, + &tc358743_timings_cap, NULL, NULL); +} + +static int tc358743_query_dv_timings(struct v4l2_subdev *sd, + struct v4l2_dv_timings *timings) +{ + int ret; + + ret = tc358743_get_detected_timings(sd, timings); + if (ret) + return ret; + + if (debug) + v4l2_print_dv_timings(sd->name, "tc358743_query_dv_timings: ", + timings, false); + + if (!v4l2_valid_dv_timings(timings, + &tc358743_timings_cap, NULL, NULL)) { + v4l2_dbg(1, debug, sd, "%s: timings out of range\n", __func__); + return -ERANGE; + } + + return 0; +} + +static int tc358743_dv_timings_cap(struct v4l2_subdev *sd, + struct v4l2_dv_timings_cap *cap) +{ + if (cap->pad != 0) + return -EINVAL; + + *cap = tc358743_timings_cap; + + return 0; +} + +static int tc358743_g_mbus_config(struct v4l2_subdev *sd, + struct v4l2_mbus_config *cfg) +{ + cfg->type = V4L2_MBUS_CSI2; + + /* Support for non-continuous CSI-2 clock is missing in the driver */ + cfg->flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + + switch (tc358743_num_csi_lanes_in_use(sd)) { + case 1: + cfg->flags |= V4L2_MBUS_CSI2_1_LANE; + break; + case 2: + cfg->flags |= V4L2_MBUS_CSI2_2_LANE; + break; + case 3: + cfg->flags |= V4L2_MBUS_CSI2_3_LANE; + break; + case 4: + cfg->flags |= V4L2_MBUS_CSI2_4_LANE; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int tc358743_s_stream(struct v4l2_subdev *sd, int enable) +{ + enable_stream(sd, enable); + + return 0; +} + +/* --------------- PAD OPS --------------- */ + +static int tc358743_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct tc358743_state *state = to_state(sd); + u8 vi_rep = i2c_rd8(sd, VI_REP); + + if (format->pad != 0) + return -EINVAL; + + format->format.code = state->mbus_fmt_code; + format->format.width = state->timings.bt.width; + format->format.height = state->timings.bt.height; + format->format.field = V4L2_FIELD_NONE; + + switch (vi_rep & MASK_VOUT_COLOR_SEL) { + case MASK_VOUT_COLOR_RGB_FULL: + case MASK_VOUT_COLOR_RGB_LIMITED: + format->format.colorspace = V4L2_COLORSPACE_SRGB; + break; + case MASK_VOUT_COLOR_601_YCBCR_LIMITED: + case MASK_VOUT_COLOR_601_YCBCR_FULL: + format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; + break; + case MASK_VOUT_COLOR_709_YCBCR_FULL: + case MASK_VOUT_COLOR_709_YCBCR_LIMITED: + format->format.colorspace = V4L2_COLORSPACE_REC709; + break; + default: + format->format.colorspace = 0; + break; + } + + return 0; +} + +static int tc358743_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct tc358743_state *state = to_state(sd); + + u32 code = format->format.code; /* is overwritten by get_fmt */ + int ret = tc358743_get_fmt(sd, cfg, format); + + format->format.code = code; + + if (ret) + return ret; + + switch (code) { + case MEDIA_BUS_FMT_RGB888_1X24: + case MEDIA_BUS_FMT_UYVY8_1X16: + break; + default: + return -EINVAL; + } + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + return 0; + + state->mbus_fmt_code = format->format.code; + + enable_stream(sd, false); + tc358743_set_pll(sd); + tc358743_set_csi(sd); + tc358743_set_csi_color_space(sd); + + return 0; +} + +static int tc358743_g_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) +{ + struct tc358743_state *state = to_state(sd); + + if (edid->pad != 0) + return -EINVAL; + + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = state->edid_blocks_written; + return 0; + } + + if (state->edid_blocks_written == 0) + return -ENODATA; + + if (edid->start_block >= state->edid_blocks_written || + edid->blocks == 0) + return -EINVAL; + + if (edid->start_block + edid->blocks > state->edid_blocks_written) + edid->blocks = state->edid_blocks_written - edid->start_block; + + i2c_rd(sd, EDID_RAM + (edid->start_block * EDID_BLOCK_SIZE), edid->edid, + edid->blocks * EDID_BLOCK_SIZE); + + return 0; +} + +static int tc358743_s_edid(struct v4l2_subdev *sd, + struct v4l2_subdev_edid *edid) +{ + struct tc358743_state *state = to_state(sd); + u16 edid_len = edid->blocks * EDID_BLOCK_SIZE; + + v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n", + __func__, edid->pad, edid->start_block, edid->blocks); + + if (edid->pad != 0) + return -EINVAL; + + if (edid->start_block != 0) + return -EINVAL; + + if (edid->blocks > EDID_NUM_BLOCKS_MAX) { + edid->blocks = EDID_NUM_BLOCKS_MAX; + return -E2BIG; + } + + tc358743_disable_edid(sd); + + i2c_wr8(sd, EDID_LEN1, edid_len & 0xff); + i2c_wr8(sd, EDID_LEN2, edid_len >> 8); + + if (edid->blocks == 0) { + state->edid_blocks_written = 0; + return 0; + } + + i2c_wr(sd, EDID_RAM, edid->edid, edid_len); + + state->edid_blocks_written = edid->blocks; + + if (tx_5v_power_present(sd)) + tc358743_enable_edid(sd); + + return 0; +} + +/* -------------------------------------------------------------------------- */ + +static const struct v4l2_subdev_core_ops tc358743_core_ops = { + .log_status = tc358743_log_status, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .g_register = tc358743_g_register, + .s_register = tc358743_s_register, +#endif + .interrupt_service_routine = tc358743_isr, +}; + +static const struct v4l2_subdev_video_ops tc358743_video_ops = { + .g_input_status = tc358743_g_input_status, + .s_dv_timings = tc358743_s_dv_timings, + .g_dv_timings = tc358743_g_dv_timings, + .query_dv_timings = tc358743_query_dv_timings, + .g_mbus_config = tc358743_g_mbus_config, + .s_stream = tc358743_s_stream, +}; + +static const struct v4l2_subdev_pad_ops tc358743_pad_ops = { + .set_fmt = tc358743_set_fmt, + .get_fmt = tc358743_get_fmt, + .get_edid = tc358743_g_edid, + .set_edid = tc358743_s_edid, + .enum_dv_timings = tc358743_enum_dv_timings, + .dv_timings_cap = tc358743_dv_timings_cap, +}; + +static const struct v4l2_subdev_ops tc358743_ops = { + .core = &tc358743_core_ops, + .video = &tc358743_video_ops, + .pad = &tc358743_pad_ops, +}; + +/* --------------- CUSTOM CTRLS --------------- */ + +static const struct v4l2_ctrl_config tc358743_ctrl_audio_sampling_rate = { + .id = TC358743_CID_AUDIO_SAMPLING_RATE, + .name = "Audio sampling rate", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 768000, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, +}; + +static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { + .id = TC358743_CID_AUDIO_PRESENT, + .name = "Audio present", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 0, + .flags = V4L2_CTRL_FLAG_READ_ONLY, +}; + +/* --------------- PROBE / REMOVE --------------- */ + +static int tc358743_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + static struct v4l2_dv_timings default_timing = + V4L2_DV_BT_CEA_640X480P59_94; + struct tc358743_state *state; + struct tc358743_platform_data *pdata = client->dev.platform_data; + struct v4l2_subdev *sd; + int err; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + return -EIO; + v4l_dbg(1, debug, client, "chip found @ 0x%x (%s)\n", + client->addr << 1, client->adapter->name); + + state = devm_kzalloc(&client->dev, sizeof(struct tc358743_state), + GFP_KERNEL); + if (!state) + return -ENOMEM; + + /* platform data */ + if (!pdata) { + v4l_err(client, "No platform data!\n"); + return -ENODEV; + } + state->pdata = *pdata; + + state->i2c_client = client; + sd = &state->sd; + v4l2_i2c_subdev_init(sd, client, &tc358743_ops); + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + + /* i2c access */ + if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { + v4l2_info(sd, "not a TC358743 on address 0x%x\n", + client->addr << 1); + return -ENODEV; + } + + /* control handlers */ + v4l2_ctrl_handler_init(&state->hdl, 3); + + /* private controls */ + state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL, + V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0); + + /* custom controls */ + state->audio_sampling_rate_ctrl = v4l2_ctrl_new_custom(&state->hdl, + &tc358743_ctrl_audio_sampling_rate, NULL); + + state->audio_present_ctrl = v4l2_ctrl_new_custom(&state->hdl, + &tc358743_ctrl_audio_present, NULL); + + sd->ctrl_handler = &state->hdl; + if (state->hdl.error) { + err = state->hdl.error; + goto err_hdl; + } + + if (tc358743_update_controls(sd)) { + err = -ENODEV; + goto err_hdl; + } + + /* work queues */ + state->work_queues = create_singlethread_workqueue(client->name); + if (!state->work_queues) { + v4l2_err(sd, "Could not create work queue\n"); + err = -ENOMEM; + goto err_hdl; + } + + mutex_init(&state->confctl_mutex); + + INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, + tc358743_delayed_work_enable_hotplug); + + tc358743_initial_setup(sd); + + tc358743_s_dv_timings(sd, &default_timing); + + state->mbus_fmt_code = MEDIA_BUS_FMT_RGB888_1X24; + tc358743_set_csi_color_space(sd); + + tc358743_init_interrupts(sd); + tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); + i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); + + err = v4l2_ctrl_handler_setup(sd->ctrl_handler); + if (err) + goto err_work_queues; + + v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name, + client->addr << 1, client->adapter->name); + + return 0; + +err_work_queues: + cancel_delayed_work(&state->delayed_work_enable_hotplug); + destroy_workqueue(state->work_queues); + mutex_destroy(&state->confctl_mutex); +err_hdl: + v4l2_ctrl_handler_free(&state->hdl); + return err; +} + +static int tc358743_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct tc358743_state *state = to_state(sd); + + cancel_delayed_work(&state->delayed_work_enable_hotplug); + destroy_workqueue(state->work_queues); + v4l2_device_unregister_subdev(sd); + mutex_destroy(&state->confctl_mutex); + v4l2_ctrl_handler_free(&state->hdl); + + return 0; +} + +static struct i2c_device_id tc358743_id[] = { + {"tc358743", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tc358743_id); + +static struct i2c_driver tc358743_driver = { + .driver = { + .owner = THIS_MODULE, + .name = "tc358743", + }, + .probe = tc358743_probe, + .remove = tc358743_remove, + .id_table = tc358743_id, +}; + +module_i2c_driver(tc358743_driver); diff --git a/drivers/media/i2c/tc358743_regs.h b/drivers/media/i2c/tc358743_regs.h new file mode 100644 index 0000000000000..81f1db558e7c7 --- /dev/null +++ b/drivers/media/i2c/tc358743_regs.h @@ -0,0 +1,681 @@ +/* + * tc358743 - Toshiba HDMI to CSI-2 bridge - register names and bit masks + * + * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights + * reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + */ + +/* + * References (c = chapter, p = page): + * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 + */ + +/* Bit masks has prefix 'MASK_' and options after '_'. */ + +#ifndef __TC358743_REGS_H +#define __TC358743_REGS_H + +#define CHIPID 0x0000 +#define MASK_CHIPID 0xff00 +#define MASK_REVID 0x00ff + +#define SYSCTL 0x0002 +#define MASK_IRRST 0x0800 +#define MASK_CECRST 0x0400 +#define MASK_CTXRST 0x0200 +#define MASK_HDMIRST 0x0100 +#define MASK_SLEEP 0x0001 + +#define CONFCTL 0x0004 +#define MASK_PWRISO 0x8000 +#define MASK_ACLKOPT 0x1000 +#define MASK_AUDCHNUM 0x0c00 +#define MASK_AUDCHNUM_8 0x0000 +#define MASK_AUDCHNUM_6 0x0400 +#define MASK_AUDCHNUM_4 0x0800 +#define MASK_AUDCHNUM_2 0x0c00 +#define MASK_AUDCHSEL 0x0200 +#define MASK_I2SDLYOPT 0x0100 +#define MASK_YCBCRFMT 0x00c0 +#define MASK_YCBCRFMT_444 0x0000 +#define MASK_YCBCRFMT_422_12_BIT 0x0040 +#define MASK_YCBCRFMT_COLORBAR 0x0080 +#define MASK_YCBCRFMT_422_8_BIT 0x00c0 +#define MASK_INFRMEN 0x0020 +#define MASK_AUDOUTSEL 0x0018 +#define MASK_AUDOUTSEL_CSI 0x0000 +#define MASK_AUDOUTSEL_I2S 0x0010 +#define MASK_AUDOUTSEL_TDM 0x0018 +#define MASK_AUTOINDEX 0x0004 +#define MASK_ABUFEN 0x0002 +#define MASK_VBUFEN 0x0001 + +#define FIFOCTL 0x0006 + +#define INTSTATUS 0x0014 +#define MASK_AMUTE_INT 0x0400 +#define MASK_HDMI_INT 0x0200 +#define MASK_CSI_INT 0x0100 +#define MASK_SYS_INT 0x0020 +#define MASK_CEC_EINT 0x0010 +#define MASK_CEC_TINT 0x0008 +#define MASK_CEC_RINT 0x0004 +#define MASK_IR_EINT 0x0002 +#define MASK_IR_DINT 0x0001 + +#define INTMASK 0x0016 +#define MASK_AMUTE_MSK 0x0400 +#define MASK_HDMI_MSK 0x0200 +#define MASK_CSI_MSK 0x0100 +#define MASK_SYS_MSK 0x0020 +#define MASK_CEC_EMSK 0x0010 +#define MASK_CEC_TMSK 0x0008 +#define MASK_CEC_RMSK 0x0004 +#define MASK_IR_EMSK 0x0002 +#define MASK_IR_DMSK 0x0001 + +#define INTFLAG 0x0018 +#define INTSYSSTATUS 0x001A + +#define PLLCTL0 0x0020 +#define MASK_PLL_PRD 0xf000 +#define SET_PLL_PRD(prd) ((((prd) - 1) << 12) &\ + MASK_PLL_PRD) +#define MASK_PLL_FBD 0x01ff +#define SET_PLL_FBD(fbd) (((fbd) - 1) & MASK_PLL_FBD) + +#define PLLCTL1 0x0022 +#define MASK_PLL_FRS 0x0c00 +#define SET_PLL_FRS(frs) (((frs) << 10) & MASK_PLL_FRS) +#define MASK_PLL_LBWS 0x0300 +#define MASK_LFBREN 0x0040 +#define MASK_BYPCKEN 0x0020 +#define MASK_CKEN 0x0010 +#define MASK_RESETB 0x0002 +#define MASK_PLL_EN 0x0001 + +#define CLW_CNTRL 0x0140 +#define MASK_CLW_LANEDISABLE 0x0001 + +#define D0W_CNTRL 0x0144 +#define MASK_D0W_LANEDISABLE 0x0001 + +#define D1W_CNTRL 0x0148 +#define MASK_D1W_LANEDISABLE 0x0001 + +#define D2W_CNTRL 0x014C +#define MASK_D2W_LANEDISABLE 0x0001 + +#define D3W_CNTRL 0x0150 +#define MASK_D3W_LANEDISABLE 0x0001 + +#define STARTCNTRL 0x0204 +#define MASK_START 0x00000001 + +#define LINEINITCNT 0x0210 +#define LPTXTIMECNT 0x0214 +#define TCLK_HEADERCNT 0x0218 +#define TCLK_TRAILCNT 0x021C +#define THS_HEADERCNT 0x0220 +#define TWAKEUP 0x0224 +#define TCLK_POSTCNT 0x0228 +#define THS_TRAILCNT 0x022C +#define HSTXVREGCNT 0x0230 + +#define HSTXVREGEN 0x0234 +#define MASK_D3M_HSTXVREGEN 0x0010 +#define MASK_D2M_HSTXVREGEN 0x0008 +#define MASK_D1M_HSTXVREGEN 0x0004 +#define MASK_D0M_HSTXVREGEN 0x0002 +#define MASK_CLM_HSTXVREGEN 0x0001 + + +#define TXOPTIONCNTRL 0x0238 +#define MASK_CONTCLKMODE 0x00000001 + +#define CSI_CONTROL 0x040C +#define MASK_CSI_MODE 0x8000 +#define MASK_HTXTOEN 0x0400 +#define MASK_TXHSMD 0x0080 +#define MASK_HSCKMD 0x0020 +#define MASK_NOL 0x0006 +#define MASK_NOL_1 0x0000 +#define MASK_NOL_2 0x0002 +#define MASK_NOL_3 0x0004 +#define MASK_NOL_4 0x0006 +#define MASK_EOTDIS 0x0001 + +#define CSI_INT 0x0414 +#define MASK_INTHLT 0x00000008 +#define MASK_INTER 0x00000004 + +#define CSI_INT_ENA 0x0418 +#define MASK_IENHLT 0x00000008 +#define MASK_IENER 0x00000004 + +#define CSI_ERR 0x044C +#define MASK_INER 0x00000200 +#define MASK_WCER 0x00000100 +#define MASK_QUNK 0x00000010 +#define MASK_TXBRK 0x00000002 + +#define CSI_ERR_INTENA 0x0450 +#define CSI_ERR_HALT 0x0454 + +#define CSI_CONFW 0x0500 +#define MASK_MODE 0xe0000000 +#define MASK_MODE_SET 0xa0000000 +#define MASK_MODE_CLEAR 0xc0000000 +#define MASK_ADDRESS 0x1f000000 +#define MASK_ADDRESS_CSI_CONTROL 0x03000000 +#define MASK_ADDRESS_CSI_INT_ENA 0x06000000 +#define MASK_ADDRESS_CSI_ERR_INTENA 0x14000000 +#define MASK_ADDRESS_CSI_ERR_HALT 0x15000000 +#define MASK_DATA 0x0000ffff + +#define CSI_INT_CLR 0x050C +#define MASK_ICRER 0x00000004 + +#define CSI_START 0x0518 +#define MASK_STRT 0x00000001 + +#define CECEN 0x0600 +#define MASK_CECEN 0x0001 + +#define HDMI_INT0 0x8500 +#define MASK_I_KEY 0x80 +#define MASK_I_MISC 0x02 +#define MASK_I_PHYERR 0x01 + +#define HDMI_INT1 0x8501 +#define MASK_I_GBD 0x80 +#define MASK_I_HDCP 0x40 +#define MASK_I_ERR 0x20 +#define MASK_I_AUD 0x10 +#define MASK_I_CBIT 0x08 +#define MASK_I_PACKET 0x04 +#define MASK_I_CLK 0x02 +#define MASK_I_SYS 0x01 + +#define SYS_INT 0x8502 +#define MASK_I_ACR_CTS 0x80 +#define MASK_I_ACRN 0x40 +#define MASK_I_DVI 0x20 +#define MASK_I_HDMI 0x10 +#define MASK_I_NOPMBDET 0x08 +#define MASK_I_DPMBDET 0x04 +#define MASK_I_TMDS 0x02 +#define MASK_I_DDC 0x01 + +#define CLK_INT 0x8503 +#define MASK_I_OUT_H_CHG 0x40 +#define MASK_I_IN_DE_CHG 0x20 +#define MASK_I_IN_HV_CHG 0x10 +#define MASK_I_DC_CHG 0x08 +#define MASK_I_PXCLK_CHG 0x04 +#define MASK_I_PHYCLK_CHG 0x02 +#define MASK_I_TMDSCLK_CHG 0x01 + +#define CBIT_INT 0x8505 +#define MASK_I_AF_LOCK 0x80 +#define MASK_I_AF_UNLOCK 0x40 +#define MASK_I_CBIT_FS 0x02 + +#define AUDIO_INT 0x8506 + +#define ERR_INT 0x8507 +#define MASK_I_EESS_ERR 0x80 + +#define HDCP_INT 0x8508 +#define MASK_I_AVM_SET 0x80 +#define MASK_I_AVM_CLR 0x40 +#define MASK_I_LINKERR 0x20 +#define MASK_I_SHA_END 0x10 +#define MASK_I_R0_END 0x08 +#define MASK_I_KM_END 0x04 +#define MASK_I_AKSV_END 0x02 +#define MASK_I_AN_END 0x01 + +#define MISC_INT 0x850B +#define MASK_I_AS_LAYOUT 0x10 +#define MASK_I_NO_SPD 0x08 +#define MASK_I_NO_VS 0x03 +#define MASK_I_SYNC_CHG 0x02 +#define MASK_I_AUDIO_MUTE 0x01 + +#define KEY_INT 0x850F + +#define SYS_INTM 0x8512 +#define MASK_M_ACR_CTS 0x80 +#define MASK_M_ACR_N 0x40 +#define MASK_M_DVI_DET 0x20 +#define MASK_M_HDMI_DET 0x10 +#define MASK_M_NOPMBDET 0x08 +#define MASK_M_BPMBDET 0x04 +#define MASK_M_TMDS 0x02 +#define MASK_M_DDC 0x01 + +#define CLK_INTM 0x8513 +#define MASK_M_OUT_H_CHG 0x40 +#define MASK_M_IN_DE_CHG 0x20 +#define MASK_M_IN_HV_CHG 0x10 +#define MASK_M_DC_CHG 0x08 +#define MASK_M_PXCLK_CHG 0x04 +#define MASK_M_PHYCLK_CHG 0x02 +#define MASK_M_TMDS_CHG 0x01 + +#define PACKET_INTM 0x8514 + +#define CBIT_INTM 0x8515 +#define MASK_M_AF_LOCK 0x80 +#define MASK_M_AF_UNLOCK 0x40 +#define MASK_M_CBIT_FS 0x02 + +#define AUDIO_INTM 0x8516 +#define MASK_M_BUFINIT_END 0x01 + +#define ERR_INTM 0x8517 +#define MASK_M_EESS_ERR 0x80 + +#define HDCP_INTM 0x8518 +#define MASK_M_AVM_SET 0x80 +#define MASK_M_AVM_CLR 0x40 +#define MASK_M_LINKERR 0x20 +#define MASK_M_SHA_END 0x10 +#define MASK_M_R0_END 0x08 +#define MASK_M_KM_END 0x04 +#define MASK_M_AKSV_END 0x02 +#define MASK_M_AN_END 0x01 + +#define MISC_INTM 0x851B +#define MASK_M_AS_LAYOUT 0x10 +#define MASK_M_NO_SPD 0x08 +#define MASK_M_NO_VS 0x03 +#define MASK_M_SYNC_CHG 0x02 +#define MASK_M_AUDIO_MUTE 0x01 + +#define KEY_INTM 0x851F + +#define SYS_STATUS 0x8520 +#define MASK_S_SYNC 0x80 +#define MASK_S_AVMUTE 0x40 +#define MASK_S_HDCP 0x20 +#define MASK_S_HDMI 0x10 +#define MASK_S_PHY_SCDT 0x08 +#define MASK_S_PHY_PLL 0x04 +#define MASK_S_TMDS 0x02 +#define MASK_S_DDC5V 0x01 + +#define CSI_STATUS 0x0410 +#define MASK_S_WSYNC 0x0400 +#define MASK_S_TXACT 0x0200 +#define MASK_S_RXACT 0x0100 +#define MASK_S_HLT 0x0001 + +#define VI_STATUS1 0x8522 +#define MASK_S_V_GBD 0x08 +#define MASK_S_DEEPCOLOR 0x0c +#define MASK_S_V_422 0x02 +#define MASK_S_V_INTERLACE 0x01 + +#define AU_STATUS0 0x8523 +#define MASK_S_A_SAMPLE 0x01 + +#define VI_STATUS3 0x8528 +#define MASK_S_V_COLOR 0x1e +#define MASK_LIMITED 0x01 + +#define PHY_CTL0 0x8531 +#define MASK_PHY_SYSCLK_IND 0x02 +#define MASK_PHY_CTL 0x01 + + +#define PHY_CTL1 0x8532 /* Not in REF_01 */ +#define MASK_PHY_AUTO_RST1 0xf0 +#define MASK_PHY_AUTO_RST1_OFF 0x00 +#define SET_PHY_AUTO_RST1_US(us) ((((us) / 200) << 4) & \ + MASK_PHY_AUTO_RST1) +#define MASK_FREQ_RANGE_MODE 0x0f +#define SET_FREQ_RANGE_MODE_CYCLES(cycles) (((cycles) - 1) & \ + MASK_FREQ_RANGE_MODE) + +#define PHY_CTL2 0x8533 /* Not in REF_01 */ +#define MASK_PHY_AUTO_RST4 0x04 +#define MASK_PHY_AUTO_RST3 0x02 +#define MASK_PHY_AUTO_RST2 0x01 +#define MASK_PHY_AUTO_RSTn (MASK_PHY_AUTO_RST4 | \ + MASK_PHY_AUTO_RST3 | \ + MASK_PHY_AUTO_RST2) + +#define PHY_EN 0x8534 +#define MASK_ENABLE_PHY 0x01 + +#define PHY_RST 0x8535 +#define MASK_RESET_CTRL 0x01 /* Reset active low */ + +#define PHY_BIAS 0x8536 /* Not in REF_01 */ + +#define PHY_CSQ 0x853F /* Not in REF_01 */ +#define MASK_CSQ_CNT 0x0f +#define SET_CSQ_CNT_LEVEL(n) (n & MASK_CSQ_CNT) + +#define SYS_FREQ0 0x8540 +#define SYS_FREQ1 0x8541 + +#define SYS_CLK 0x8542 /* Not in REF_01 */ +#define MASK_CLK_DIFF 0x0C +#define MASK_CLK_DIV 0x03 + +#define DDC_CTL 0x8543 +#define MASK_DDC_ACK_POL 0x08 +#define MASK_DDC_ACTION 0x04 +#define MASK_DDC5V_MODE 0x03 +#define MASK_DDC5V_MODE_0MS 0x00 +#define MASK_DDC5V_MODE_50MS 0x01 +#define MASK_DDC5V_MODE_100MS 0x02 +#define MASK_DDC5V_MODE_200MS 0x03 + +#define HPD_CTL 0x8544 +#define MASK_HPD_CTL0 0x10 +#define MASK_HPD_OUT0 0x01 + +#define ANA_CTL 0x8545 +#define MASK_APPL_PCSX 0x30 +#define MASK_APPL_PCSX_HIZ 0x00 +#define MASK_APPL_PCSX_L_FIX 0x10 +#define MASK_APPL_PCSX_H_FIX 0x20 +#define MASK_APPL_PCSX_NORMAL 0x30 +#define MASK_ANALOG_ON 0x01 + +#define AVM_CTL 0x8546 + +#define INIT_END 0x854A +#define MASK_INIT_END 0x01 + +#define HDMI_DET 0x8552 /* Not in REF_01 */ +#define MASK_HDMI_DET_MOD1 0x80 +#define MASK_HDMI_DET_MOD0 0x40 +#define MASK_HDMI_DET_V 0x30 +#define MASK_HDMI_DET_V_SYNC 0x00 +#define MASK_HDMI_DET_V_ASYNC_25MS 0x10 +#define MASK_HDMI_DET_V_ASYNC_50MS 0x20 +#define MASK_HDMI_DET_V_ASYNC_100MS 0x30 +#define MASK_HDMI_DET_NUM 0x0f + +#define HDCP_MODE 0x8560 +#define MASK_MODE_RST_TN 0x20 +#define MASK_LINE_REKEY 0x10 +#define MASK_AUTO_CLR 0x04 + +#define HDCP_REG1 0x8563 /* Not in REF_01 */ +#define MASK_AUTH_UNAUTH_SEL 0x70 +#define MASK_AUTH_UNAUTH_SEL_12_FRAMES 0x70 +#define MASK_AUTH_UNAUTH_SEL_8_FRAMES 0x60 +#define MASK_AUTH_UNAUTH_SEL_4_FRAMES 0x50 +#define MASK_AUTH_UNAUTH_SEL_2_FRAMES 0x40 +#define MASK_AUTH_UNAUTH_SEL_64_FRAMES 0x30 +#define MASK_AUTH_UNAUTH_SEL_32_FRAMES 0x20 +#define MASK_AUTH_UNAUTH_SEL_16_FRAMES 0x10 +#define MASK_AUTH_UNAUTH_SEL_ONCE 0x00 +#define MASK_AUTH_UNAUTH 0x01 +#define MASK_AUTH_UNAUTH_AUTO 0x01 + +#define HDCP_REG2 0x8564 /* Not in REF_01 */ +#define MASK_AUTO_P3_RESET 0x0F +#define SET_AUTO_P3_RESET_FRAMES(n) (n & MASK_AUTO_P3_RESET) +#define MASK_AUTO_P3_RESET_OFF 0x00 + +#define VI_MODE 0x8570 +#define MASK_RGB_DVI 0x08 /* Not in REF_01 */ + +#define VOUT_SET2 0x8573 +#define MASK_SEL422 0x80 +#define MASK_VOUT_422FIL_100 0x40 +#define MASK_VOUTCOLORMODE 0x03 +#define MASK_VOUTCOLORMODE_THROUGH 0x00 +#define MASK_VOUTCOLORMODE_AUTO 0x01 +#define MASK_VOUTCOLORMODE_MANUAL 0x03 + +#define VOUT_SET3 0x8574 +#define MASK_VOUT_EXTCNT 0x08 + +#define VI_REP 0x8576 +#define MASK_VOUT_COLOR_SEL 0xe0 +#define MASK_VOUT_COLOR_RGB_FULL 0x00 +#define MASK_VOUT_COLOR_RGB_LIMITED 0x20 +#define MASK_VOUT_COLOR_601_YCBCR_FULL 0x40 +#define MASK_VOUT_COLOR_601_YCBCR_LIMITED 0x60 +#define MASK_VOUT_COLOR_709_YCBCR_FULL 0x80 +#define MASK_VOUT_COLOR_709_YCBCR_LIMITED 0xa0 +#define MASK_VOUT_COLOR_FULL_TO_LIMITED 0xc0 +#define MASK_VOUT_COLOR_LIMITED_TO_FULL 0xe0 +#define MASK_IN_REP_HEN 0x10 +#define MASK_IN_REP 0x0f + +#define VI_MUTE 0x857F +#define MASK_AUTO_MUTE 0xc0 +#define MASK_VI_MUTE 0x10 + +#define DE_WIDTH_H_LO 0x8582 /* Not in REF_01 */ +#define DE_WIDTH_H_HI 0x8583 /* Not in REF_01 */ +#define DE_WIDTH_V_LO 0x8588 /* Not in REF_01 */ +#define DE_WIDTH_V_HI 0x8589 /* Not in REF_01 */ +#define H_SIZE_LO 0x858A /* Not in REF_01 */ +#define H_SIZE_HI 0x858B /* Not in REF_01 */ +#define V_SIZE_LO 0x858C /* Not in REF_01 */ +#define V_SIZE_HI 0x858D /* Not in REF_01 */ +#define FV_CNT_LO 0x85A1 /* Not in REF_01 */ +#define FV_CNT_HI 0x85A2 /* Not in REF_01 */ + +#define FH_MIN0 0x85AA /* Not in REF_01 */ +#define FH_MIN1 0x85AB /* Not in REF_01 */ +#define FH_MAX0 0x85AC /* Not in REF_01 */ +#define FH_MAX1 0x85AD /* Not in REF_01 */ + +#define HV_RST 0x85AF /* Not in REF_01 */ +#define MASK_H_PI_RST 0x20 +#define MASK_V_PI_RST 0x10 + +#define EDID_MODE 0x85C7 +#define MASK_EDID_SPEED 0x40 +#define MASK_EDID_MODE 0x03 +#define MASK_EDID_MODE_DISABLE 0x00 +#define MASK_EDID_MODE_DDC2B 0x01 +#define MASK_EDID_MODE_E_DDC 0x02 + +#define EDID_LEN1 0x85CA +#define EDID_LEN2 0x85CB + +#define HDCP_REG3 0x85D1 /* Not in REF_01 */ +#define KEY_RD_CMD 0x01 + +#define FORCE_MUTE 0x8600 +#define MASK_FORCE_AMUTE 0x10 +#define MASK_FORCE_DMUTE 0x01 + +#define CMD_AUD 0x8601 +#define MASK_CMD_BUFINIT 0x04 +#define MASK_CMD_LOCKDET 0x02 +#define MASK_CMD_MUTE 0x01 + +#define AUTO_CMD0 0x8602 +#define MASK_AUTO_MUTE7 0x80 +#define MASK_AUTO_MUTE6 0x40 +#define MASK_AUTO_MUTE5 0x20 +#define MASK_AUTO_MUTE4 0x10 +#define MASK_AUTO_MUTE3 0x08 +#define MASK_AUTO_MUTE2 0x04 +#define MASK_AUTO_MUTE1 0x02 +#define MASK_AUTO_MUTE0 0x01 + +#define AUTO_CMD1 0x8603 +#define MASK_AUTO_MUTE10 0x04 +#define MASK_AUTO_MUTE9 0x02 +#define MASK_AUTO_MUTE8 0x01 + +#define AUTO_CMD2 0x8604 +#define MASK_AUTO_PLAY3 0x08 +#define MASK_AUTO_PLAY2 0x04 + +#define BUFINIT_START 0x8606 +#define SET_BUFINIT_START_MS(milliseconds) ((milliseconds) / 100) + +#define FS_MUTE 0x8607 +#define MASK_FS_ELSE_MUTE 0x80 +#define MASK_FS22_MUTE 0x40 +#define MASK_FS24_MUTE 0x20 +#define MASK_FS88_MUTE 0x10 +#define MASK_FS96_MUTE 0x08 +#define MASK_FS176_MUTE 0x04 +#define MASK_FS192_MUTE 0x02 +#define MASK_FS_NO_MUTE 0x01 + +#define FS_IMODE 0x8620 +#define MASK_NLPCM_HMODE 0x40 +#define MASK_NLPCM_SMODE 0x20 +#define MASK_NLPCM_IMODE 0x10 +#define MASK_FS_HMODE 0x08 +#define MASK_FS_AMODE 0x04 +#define MASK_FS_SMODE 0x02 +#define MASK_FS_IMODE 0x01 + +#define FS_SET 0x8621 +#define MASK_FS 0x0f + +#define LOCKDET_REF0 0x8630 +#define LOCKDET_REF1 0x8631 +#define LOCKDET_REF2 0x8632 + +#define ACR_MODE 0x8640 +#define MASK_ACR_LOAD 0x10 +#define MASK_N_MODE 0x04 +#define MASK_CTS_MODE 0x01 + +#define ACR_MDF0 0x8641 +#define MASK_ACR_L2MDF 0x70 +#define MASK_ACR_L2MDF_0_PPM 0x00 +#define MASK_ACR_L2MDF_61_PPM 0x10 +#define MASK_ACR_L2MDF_122_PPM 0x20 +#define MASK_ACR_L2MDF_244_PPM 0x30 +#define MASK_ACR_L2MDF_488_PPM 0x40 +#define MASK_ACR_L2MDF_976_PPM 0x50 +#define MASK_ACR_L2MDF_1976_PPM 0x60 +#define MASK_ACR_L2MDF_3906_PPM 0x70 +#define MASK_ACR_L1MDF 0x07 +#define MASK_ACR_L1MDF_0_PPM 0x00 +#define MASK_ACR_L1MDF_61_PPM 0x01 +#define MASK_ACR_L1MDF_122_PPM 0x02 +#define MASK_ACR_L1MDF_244_PPM 0x03 +#define MASK_ACR_L1MDF_488_PPM 0x04 +#define MASK_ACR_L1MDF_976_PPM 0x05 +#define MASK_ACR_L1MDF_1976_PPM 0x06 +#define MASK_ACR_L1MDF_3906_PPM 0x07 + +#define ACR_MDF1 0x8642 +#define MASK_ACR_L3MDF 0x07 +#define MASK_ACR_L3MDF_0_PPM 0x00 +#define MASK_ACR_L3MDF_61_PPM 0x01 +#define MASK_ACR_L3MDF_122_PPM 0x02 +#define MASK_ACR_L3MDF_244_PPM 0x03 +#define MASK_ACR_L3MDF_488_PPM 0x04 +#define MASK_ACR_L3MDF_976_PPM 0x05 +#define MASK_ACR_L3MDF_1976_PPM 0x06 +#define MASK_ACR_L3MDF_3906_PPM 0x07 + +#define SDO_MODE1 0x8652 +#define MASK_SDO_BIT_LENG 0x70 +#define MASK_SDO_FMT 0x03 +#define MASK_SDO_FMT_RIGHT 0x00 +#define MASK_SDO_FMT_LEFT 0x01 +#define MASK_SDO_FMT_I2S 0x02 + +#define DIV_MODE 0x8665 /* Not in REF_01 */ +#define MASK_DIV_DLY 0xf0 +#define SET_DIV_DLY_MS(milliseconds) ((((milliseconds) / 100) << 4) & \ + MASK_DIV_DLY) +#define MASK_DIV_MODE 0x01 + +#define NCO_F0_MOD 0x8670 +#define MASK_NCO_F0_MOD 0x03 +#define MASK_NCO_F0_MOD_42MHZ 0x00 +#define MASK_NCO_F0_MOD_27MHZ 0x01 + +#define PK_INT_MODE 0x8709 +#define MASK_ISRC2_INT_MODE 0x80 +#define MASK_ISRC_INT_MODE 0x40 +#define MASK_ACP_INT_MODE 0x20 +#define MASK_VS_INT_MODE 0x10 +#define MASK_SPD_INT_MODE 0x08 +#define MASK_MS_INT_MODE 0x04 +#define MASK_AUD_INT_MODE 0x02 +#define MASK_AVI_INT_MODE 0x01 + +#define NO_PKT_LIMIT 0x870B +#define MASK_NO_ACP_LIMIT 0xf0 +#define SET_NO_ACP_LIMIT_MS(milliseconds) ((((milliseconds) / 80) << 4) & \ + MASK_NO_ACP_LIMIT) +#define MASK_NO_AVI_LIMIT 0x0f +#define SET_NO_AVI_LIMIT_MS(milliseconds) (((milliseconds) / 80) & \ + MASK_NO_AVI_LIMIT) + +#define NO_PKT_CLR 0x870C +#define MASK_NO_VS_CLR 0x40 +#define MASK_NO_SPD_CLR 0x20 +#define MASK_NO_ACP_CLR 0x10 +#define MASK_NO_AVI_CLR1 0x02 +#define MASK_NO_AVI_CLR0 0x01 + +#define ERR_PK_LIMIT 0x870D +#define NO_PKT_LIMIT2 0x870E +#define PK_AVI_0HEAD 0x8710 +#define PK_AVI_1HEAD 0x8711 +#define PK_AVI_2HEAD 0x8712 +#define PK_AVI_0BYTE 0x8713 +#define PK_AVI_1BYTE 0x8714 +#define PK_AVI_2BYTE 0x8715 +#define PK_AVI_3BYTE 0x8716 +#define PK_AVI_4BYTE 0x8717 +#define PK_AVI_5BYTE 0x8718 +#define PK_AVI_6BYTE 0x8719 +#define PK_AVI_7BYTE 0x871A +#define PK_AVI_8BYTE 0x871B +#define PK_AVI_9BYTE 0x871C +#define PK_AVI_10BYTE 0x871D +#define PK_AVI_11BYTE 0x871E +#define PK_AVI_12BYTE 0x871F +#define PK_AVI_13BYTE 0x8720 +#define PK_AVI_14BYTE 0x8721 +#define PK_AVI_15BYTE 0x8722 +#define PK_AVI_16BYTE 0x8723 + +#define BKSV 0x8800 + +#define BCAPS 0x8840 +#define MASK_HDMI_RSVD 0x80 +#define MASK_REPEATER 0x40 +#define MASK_READY 0x20 +#define MASK_FASTI2C 0x10 +#define MASK_1_1_FEA 0x02 +#define MASK_FAST_REAU 0x01 + +#define BSTATUS1 0x8842 +#define MASK_MAX_EXCED 0x08 + +#define EDID_RAM 0x8C00 +#define NO_GDB_LIMIT 0x9007 + +#endif diff --git a/include/media/tc358743.h b/include/media/tc358743.h new file mode 100644 index 0000000000000..4513f2f9cfbce --- /dev/null +++ b/include/media/tc358743.h @@ -0,0 +1,131 @@ +/* + * tc358743 - Toshiba HDMI to CSI-2 bridge + * + * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights + * reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * 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. + * + */ + +/* + * References (c = chapter, p = page): + * REF_01 - Toshiba, TC358743XBG (H2C), Functional Specification, Rev 0.60 + * REF_02 - Toshiba, TC358743XBG_HDMI-CSI_Tv11p_nm.xls + */ + +#ifndef _TC358743_ +#define _TC358743_ + +enum tc358743_ddc5v_delays { + DDC5V_DELAY_0_MS, + DDC5V_DELAY_50_MS, + DDC5V_DELAY_100_MS, + DDC5V_DELAY_200_MS, +}; + +enum tc358743_hdmi_detection_delay { + HDMI_MODE_DELAY_0_MS, + HDMI_MODE_DELAY_25_MS, + HDMI_MODE_DELAY_50_MS, + HDMI_MODE_DELAY_100_MS, +}; + +struct tc358743_platform_data { + /* System clock connected to REFCLK (pin H5) */ + u32 refclk_hz; /* 26 MHz, 27 MHz or 42 MHz */ + + /* DDC +5V debounce delay to avoid spurious interrupts when the cable + * is connected. + * Sets DDC5V_MODE in register DDC_CTL. + * Default: DDC5V_DELAY_0_MS + */ + enum tc358743_ddc5v_delays ddc5v_delay; + + bool enable_hdcp; + + /* + * The FIFO size is 512x32, so Toshiba recommend to set the default FIFO + * level to somewhere in the middle (e.g. 300), so it can cover speed + * mismatches in input and output ports. + */ + u16 fifo_level; + + /* Bps pr lane is (refclk_hz / pll_prd) * pll_fbd */ + u16 pll_prd; + u16 pll_fbd; + + /* CSI + * Calculate CSI parameters with REF_02 for the highest resolution your + * CSI interface can handle. The driver will adjust the number of CSI + * lanes in use according to the pixel clock. + * + * The values in brackets are calculated with REF_02 when the number of + * bps pr lane is 823.5 MHz, and can serve as a starting point. + */ + u32 lineinitcnt; /* (0x00001770) */ + u32 lptxtimecnt; /* (0x00000005) */ + u32 tclk_headercnt; /* (0x00001d04) */ + u32 tclk_trailcnt; /* (0x00000000) */ + u32 ths_headercnt; /* (0x00000505) */ + u32 twakeup; /* (0x00004650) */ + u32 tclk_postcnt; /* (0x00000000) */ + u32 ths_trailcnt; /* (0x00000004) */ + u32 hstxvregcnt; /* (0x00000005) */ + + /* DVI->HDMI detection delay to avoid unnecessary switching between DVI + * and HDMI mode. + * Sets HDMI_DET_V in register HDMI_DET. + * Default: HDMI_MODE_DELAY_0_MS + */ + enum tc358743_hdmi_detection_delay hdmi_detection_delay; + + /* Reset PHY automatically when TMDS clock goes from DC to AC. + * Sets PHY_AUTO_RST2 in register PHY_CTL2. + * Default: false + */ + bool hdmi_phy_auto_reset_tmds_detected; + + /* Reset PHY automatically when TMDS clock passes 21 MHz. + * Sets PHY_AUTO_RST3 in register PHY_CTL2. + * Default: false + */ + bool hdmi_phy_auto_reset_tmds_in_range; + + /* Reset PHY automatically when TMDS clock is detected. + * Sets PHY_AUTO_RST4 in register PHY_CTL2. + * Default: false + */ + bool hdmi_phy_auto_reset_tmds_valid; + + /* Reset HDMI PHY automatically when hsync period is out of range. + * Sets H_PI_RST in register HV_RST. + * Default: false + */ + bool hdmi_phy_auto_reset_hsync_out_of_range; + + /* Reset HDMI PHY automatically when vsync period is out of range. + * Sets V_PI_RST in register HV_RST. + * Default: false + */ + bool hdmi_phy_auto_reset_vsync_out_of_range; +}; + +/* custom controls */ +/* Audio sample rate in Hz */ +#define TC358743_CID_AUDIO_SAMPLING_RATE (V4L2_CID_USER_TC358743_BASE + 0) +/* Audio present status */ +#define TC358743_CID_AUDIO_PRESENT (V4L2_CID_USER_TC358743_BASE + 1) + +#endif diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 9f6e108ff4a08..d448c536b49d5 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -174,6 +174,10 @@ enum v4l2_colorfx { * We reserve 16 controls for this driver. */ #define V4L2_CID_USER_ADV7180_BASE (V4L2_CID_USER_BASE + 0x1070) +/* The base for the tc358743 driver controls. + * We reserve 16 controls for this driver. */ +#define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080) + /* MPEG-class control IDs */ /* The MPEG controls are applicable to all codec controls * and the 'MPEG' part of the define is historical */ -- GitLab From e31f8f00bfc081ec1881d92a2dd192aeddf1d9d7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 24 Jun 2015 11:28:31 -0300 Subject: [PATCH 1068/7006] [media] v4l: xilinx: missing error code We should set "ret" on this error path instead of returning success. Fixes: df3305156f98 ('[media] v4l: xilinx: Add Xilinx Video IP core') Signed-off-by: Dan Carpenter Acked-by: Hyun Kwon Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/xilinx/xilinx-dma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c index 98e50e446d57a..e779c93cb0158 100644 --- a/drivers/media/platform/xilinx/xilinx-dma.c +++ b/drivers/media/platform/xilinx/xilinx-dma.c @@ -699,8 +699,10 @@ int xvip_dma_init(struct xvip_composite_device *xdev, struct xvip_dma *dma, /* ... and the buffers queue... */ dma->alloc_ctx = vb2_dma_contig_init_ctx(dma->xdev->dev); - if (IS_ERR(dma->alloc_ctx)) + if (IS_ERR(dma->alloc_ctx)) { + ret = PTR_ERR(dma->alloc_ctx); goto error; + } /* Don't enable VB2_READ and VB2_WRITE, as using the read() and write() * V4L2 APIs would be inefficient. Testing on the command line with a -- GitLab From df5c3e7c8a87a4384ff7a0adba16baae9a40a566 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Fri, 19 Jun 2015 08:51:22 -0300 Subject: [PATCH 1069/7006] [media] v4l: vsp1: Fix plane stride and size checks The checks need to be performed on up to two planes, as the third plane, if present, must have the same stride and size as the second plane. The code incorrectly performs the checks on at least two planes instead of at most two planes, fix it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index 770e08dc03f1e..3c124c14ce14f 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -245,7 +245,7 @@ static int __vsp1_video_try_format(struct vsp1_video *video, * the datasheet, strides not aligned to a multiple of 128 bytes result * in image corruption. */ - for (i = 0; i < max(info->planes, 2U); ++i) { + for (i = 0; i < min(info->planes, 2U); ++i) { unsigned int hsub = i > 0 ? info->hsub : 1; unsigned int vsub = i > 0 ? info->vsub : 1; unsigned int align = 128; -- GitLab From adb8963f27e00273c912a53f28f7af5d14cfd32e Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Mon, 13 Apr 2015 11:43:40 -0300 Subject: [PATCH 1070/7006] [media] v4l: vsp1: Don't sleep in atomic context The vsp1_entity_is_streaming() function is called in atomic context when queuing buffers, and sleeps due to a mutex. As the mutex just protects access to one structure field, fix this by replace the mutex with a spinlock. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_entity.c | 18 +++++++++--------- drivers/media/platform/vsp1/vsp1_entity.h | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c index a453bb4ddd37d..fd95a75b04f4c 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.c +++ b/drivers/media/platform/vsp1/vsp1_entity.c @@ -24,22 +24,24 @@ bool vsp1_entity_is_streaming(struct vsp1_entity *entity) { + unsigned long flags; bool streaming; - mutex_lock(&entity->lock); + spin_lock_irqsave(&entity->lock, flags); streaming = entity->streaming; - mutex_unlock(&entity->lock); + spin_unlock_irqrestore(&entity->lock, flags); return streaming; } int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) { + unsigned long flags; int ret; - mutex_lock(&entity->lock); + spin_lock_irqsave(&entity->lock, flags); entity->streaming = streaming; - mutex_unlock(&entity->lock); + spin_unlock_irqrestore(&entity->lock, flags); if (!streaming) return 0; @@ -49,9 +51,9 @@ int vsp1_entity_set_streaming(struct vsp1_entity *entity, bool streaming) ret = v4l2_ctrl_handler_setup(entity->subdev.ctrl_handler); if (ret < 0) { - mutex_lock(&entity->lock); + spin_lock_irqsave(&entity->lock, flags); entity->streaming = false; - mutex_unlock(&entity->lock); + spin_unlock_irqrestore(&entity->lock, flags); } return ret; @@ -193,7 +195,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity, if (i == ARRAY_SIZE(vsp1_routes)) return -EINVAL; - mutex_init(&entity->lock); + spin_lock_init(&entity->lock); entity->vsp1 = vsp1; entity->source_pad = num_pads - 1; @@ -228,6 +230,4 @@ void vsp1_entity_destroy(struct vsp1_entity *entity) if (entity->subdev.ctrl_handler) v4l2_ctrl_handler_free(entity->subdev.ctrl_handler); media_entity_cleanup(&entity->subdev.entity); - - mutex_destroy(&entity->lock); } diff --git a/drivers/media/platform/vsp1/vsp1_entity.h b/drivers/media/platform/vsp1/vsp1_entity.h index 62c768d1c6aa9..8867a5787c285 100644 --- a/drivers/media/platform/vsp1/vsp1_entity.h +++ b/drivers/media/platform/vsp1/vsp1_entity.h @@ -14,7 +14,7 @@ #define __VSP1_ENTITY_H__ #include -#include +#include #include @@ -73,7 +73,7 @@ struct vsp1_entity { struct vsp1_video *video; - struct mutex lock; /* Protects the streaming field */ + spinlock_t lock; /* Protects the streaming field */ bool streaming; }; -- GitLab From 5c48f1201744233d4f235c7dd916d5196ed20716 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2015 09:58:06 +0200 Subject: [PATCH 1071/7006] mac80211: remove exposing 'mfp' to drivers There's no driver using this, so remove it. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 -- net/mac80211/cfg.c | 1 - net/mac80211/mlme.c | 6 +----- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 6b1077c2a63fa..43dbddfa06c00 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1675,7 +1675,6 @@ struct ieee80211_sta_rates { * @tdls: indicates whether the STA is a TDLS peer * @tdls_initiator: indicates the STA is an initiator of the TDLS link. Only * valid if the STA is a TDLS peer in the first place. - * @mfp: indicates whether the STA uses management frame protection or not. * @txq: per-TID data TX queues (if driver uses the TXQ abstraction) */ struct ieee80211_sta { @@ -1693,7 +1692,6 @@ struct ieee80211_sta { struct ieee80211_sta_rates __rcu *rates; bool tdls; bool tdls_initiator; - bool mfp; struct ieee80211_txq *txq[IEEE80211_NUM_TIDS]; diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index bf7023f6c3278..5fc7788e2ff26 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1076,7 +1076,6 @@ static int sta_apply_parameters(struct ieee80211_local *local, } if (mask & BIT(NL80211_STA_FLAG_MFP)) { - sta->sta.mfp = !!(set & BIT(NL80211_STA_FLAG_MFP)); if (set & BIT(NL80211_STA_FLAG_MFP)) set_sta_flag(sta, WLAN_STA_MFP); else diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 9b2cc278ac2af..ae5d6c48272d1 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -3034,12 +3034,8 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, rate_control_rate_init(sta); - if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) { + if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED) set_sta_flag(sta, WLAN_STA_MFP); - sta->sta.mfp = true; - } else { - sta->sta.mfp = false; - } sta->sta.wme = elems.wmm_param && local->hw.queues >= IEEE80211_NUM_ACS; -- GitLab From cf47161ad26c293dd5f98186c0cc45d125da952c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 16:16:38 +0200 Subject: [PATCH 1072/7006] mac80211: rename 'sta_inf' variable to more common 'sta' We typically use 'sta' for the station info struct, and if needed 'pubsta' for the public (driver-visible) portion thereof. Do this in the ieee80211_sta_ps_transition() function. Signed-off-by: Johannes Berg --- net/mac80211/rx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 5dae166cb7f56..9fb8ce982c2de 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1240,22 +1240,22 @@ static void sta_ps_end(struct sta_info *sta) ieee80211_sta_ps_deliver_wakeup(sta); } -int ieee80211_sta_ps_transition(struct ieee80211_sta *sta, bool start) +int ieee80211_sta_ps_transition(struct ieee80211_sta *pubsta, bool start) { - struct sta_info *sta_inf = container_of(sta, struct sta_info, sta); + struct sta_info *sta = container_of(pubsta, struct sta_info, sta); bool in_ps; - WARN_ON(!ieee80211_hw_check(&sta_inf->local->hw, AP_LINK_PS)); + WARN_ON(!ieee80211_hw_check(&sta->local->hw, AP_LINK_PS)); /* Don't let the same PS state be set twice */ - in_ps = test_sta_flag(sta_inf, WLAN_STA_PS_STA); + in_ps = test_sta_flag(sta, WLAN_STA_PS_STA); if ((start && in_ps) || (!start && !in_ps)) return -EINVAL; if (start) - sta_ps_start(sta_inf); + sta_ps_start(sta); else - sta_ps_end(sta_inf); + sta_ps_end(sta); return 0; } -- GitLab From 16bf948081d0ea0f6cdef54b79a0250d4b099970 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 16:10:30 +0200 Subject: [PATCH 1073/7006] mac80211: remove sta_info.gtk_idx This struct member is only assigned, never used otherwise; remove it. Signed-off-by: Johannes Berg --- net/mac80211/key.c | 1 - net/mac80211/sta_info.h | 2 -- 2 files changed, 3 deletions(-) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b22df3a79a417..44388d6a1d8e6 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -336,7 +336,6 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ieee80211_check_fast_xmit(sta); } else { rcu_assign_pointer(sta->gtk[idx], new); - sta->gtk_idx = idx; } } else { defunikey = old && diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 226f8ca47ad67..147464dbc4558 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -283,7 +283,6 @@ struct ieee80211_fast_tx { * @ptk: peer keys negotiated with this station, if any * @ptk_idx: last installed peer key index * @gtk: group keys negotiated with this station, if any - * @gtk_idx: last installed group key index * @rate_ctrl: rate control algorithm reference * @rate_ctrl_lock: spinlock used to protect rate control data * (data inside the algorithm, so serializes calls there) @@ -381,7 +380,6 @@ struct sta_info { struct ieee80211_sub_if_data *sdata; struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; struct ieee80211_key __rcu *ptk[NUM_DEFAULT_KEYS]; - u8 gtk_idx; u8 ptk_idx; struct rate_control_ref *rate_ctrl; void *rate_ctrl_priv; -- GitLab From 9ad8b21b742503030d543cd272de6a4eb3e3cc27 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 15:05:57 +0200 Subject: [PATCH 1074/7006] mac80211: remove short frame test and counter Short frames less than 16 octets are already blocked in the monitor code by the should_drop_frame() function, and cannot get into the regular RX path. Therefore, this check can never trigger and the counter invariably stays zero. Remove the useless code. Signed-off-by: Johannes Berg --- net/mac80211/debugfs.c | 1 - net/mac80211/ieee80211_i.h | 1 - net/mac80211/rx.c | 5 ----- 3 files changed, 7 deletions(-) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 3ea8b7de96336..2c79d777f0e46 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -277,7 +277,6 @@ void debugfs_hw_add(struct ieee80211_local *local) DEBUGFS_STATS_ADD(rx_handlers_queued); DEBUGFS_STATS_ADD(rx_handlers_drop_nullfunc); DEBUGFS_STATS_ADD(rx_handlers_drop_defrag); - DEBUGFS_STATS_ADD(rx_handlers_drop_short); DEBUGFS_STATS_ADD(tx_expand_skb_head); DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned); DEBUGFS_STATS_ADD(rx_expand_skb_head_defrag); diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index b12f61507f9f9..eb91102e48096 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1286,7 +1286,6 @@ struct ieee80211_local { unsigned int rx_handlers_queued; unsigned int rx_handlers_drop_nullfunc; unsigned int rx_handlers_drop_defrag; - unsigned int rx_handlers_drop_short; unsigned int tx_expand_skb_head; unsigned int tx_expand_skb_head_cloned; unsigned int rx_expand_skb_head_defrag; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9fb8ce982c2de..aa57a2ab82459 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1093,11 +1093,6 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data; - if (unlikely(rx->skb->len < 16)) { - I802_DEBUG_INC(rx->local->rx_handlers_drop_short); - return RX_DROP_MONITOR; - } - /* Drop disallowed frame classes based on STA auth/assoc state; * IEEE 802.11, Chap 5.5. * -- GitLab From a682849329ad5df5fd13a7b1ab08cbc39df5484b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 15:17:15 +0200 Subject: [PATCH 1075/7006] mac80211: move ieee80211_get_bssid into RX file This function is only used in the RX code, so moving it into that file gives the compiler better optimisation possibilities and also allows us to remove the check for short frames (which in the RX path cannot happen, but as a generic utility needed to be checked.) Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/rx.c | 45 ++++++++++++++++++++++++++++++++++ net/mac80211/util.c | 49 -------------------------------------- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index eb91102e48096..361bb3ca335c6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1762,8 +1762,6 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw) /* utility functions/constants */ extern const void *const mac80211_wiphy_privid; /* for wiphy privid */ -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, - enum nl80211_iftype type); int ieee80211_frame_duration(enum ieee80211_band band, size_t len, int rate, int erp, int short_preamble, int shift); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index aa57a2ab82459..dd6bb2a54d45f 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -42,6 +42,51 @@ static inline void ieee80211_rx_stats(struct net_device *dev, u32 len) u64_stats_update_end(&tstats->syncp); } +static u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, + enum nl80211_iftype type) +{ + __le16 fc = hdr->frame_control; + + if (ieee80211_is_data(fc)) { + if (len < 24) /* drop incorrect hdr len (data) */ + return NULL; + + if (ieee80211_has_a4(fc)) + return NULL; + if (ieee80211_has_tods(fc)) + return hdr->addr1; + if (ieee80211_has_fromds(fc)) + return hdr->addr2; + + return hdr->addr3; + } + + if (ieee80211_is_mgmt(fc)) { + if (len < 24) /* drop incorrect hdr len (mgmt) */ + return NULL; + return hdr->addr3; + } + + if (ieee80211_is_ctl(fc)) { + if (ieee80211_is_pspoll(fc)) + return hdr->addr1; + + if (ieee80211_is_back_req(fc)) { + switch (type) { + case NL80211_IFTYPE_STATION: + return hdr->addr2; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + return hdr->addr1; + default: + break; /* fall through to the return */ + } + } + } + + return NULL; +} + /* * monitor mode reception * diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 43e5aadd7a894..7fb2c7bacc8cf 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -47,55 +47,6 @@ struct ieee80211_hw *wiphy_to_ieee80211_hw(struct wiphy *wiphy) } EXPORT_SYMBOL(wiphy_to_ieee80211_hw); -u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len, - enum nl80211_iftype type) -{ - __le16 fc = hdr->frame_control; - - /* drop ACK/CTS frames and incorrect hdr len (ctrl) */ - if (len < 16) - return NULL; - - if (ieee80211_is_data(fc)) { - if (len < 24) /* drop incorrect hdr len (data) */ - return NULL; - - if (ieee80211_has_a4(fc)) - return NULL; - if (ieee80211_has_tods(fc)) - return hdr->addr1; - if (ieee80211_has_fromds(fc)) - return hdr->addr2; - - return hdr->addr3; - } - - if (ieee80211_is_mgmt(fc)) { - if (len < 24) /* drop incorrect hdr len (mgmt) */ - return NULL; - return hdr->addr3; - } - - if (ieee80211_is_ctl(fc)) { - if (ieee80211_is_pspoll(fc)) - return hdr->addr1; - - if (ieee80211_is_back_req(fc)) { - switch (type) { - case NL80211_IFTYPE_STATION: - return hdr->addr2; - case NL80211_IFTYPE_AP: - case NL80211_IFTYPE_AP_VLAN: - return hdr->addr1; - default: - break; /* fall through to the return */ - } - } - } - - return NULL; -} - void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx) { struct sk_buff *skb; -- GitLab From 798a457dfb232535ebc9670082b8dfccdab684ff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 15:58:22 +0200 Subject: [PATCH 1076/7006] mac80211: fix comment referring to RX queue There are no RX queues in mac80211 (yet), the comment should refer to the TID (including one slot for non-QoS) rather than 'RX queue'. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 147464dbc4558..db76103b44455 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -317,7 +317,8 @@ struct ieee80211_fast_tx { * @last_signal: signal of last received frame from this STA * @avg_signal: moving average of signal of received frames from this STA * @last_ack_signal: signal of last received Ack frame from this STA - * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) + * @last_seq_ctrl: last received seq/frag number from this STA (per TID + * plus one for non-QoS frames) * @tx_filtered_count: number of frames the hardware filtered for this STA * @tx_retry_failed: number of frames that failed retry * @tx_retry_count: total number of retries for frames to this STA -- GitLab From af9f9b22beee70aae58651cdbb9d6375e6e51797 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 11 Jun 2015 16:02:32 +0200 Subject: [PATCH 1077/7006] mac80211: don't store napi struct When introducing multiple RX queues, a single NAPI struct will not be sufficient. Instead of trying to store multiple, simply change the API to have the NAPI struct passed to the RX function. This of course means that drivers using rx_irqsafe() cannot use NAPI, but that seems a reasonable trade-off, particularly since only two of all drivers are currently using it at all. While at it, we can now remove the IEEE80211_RX_REORDER_TIMER flag again since this code path cannot have a napi struct anyway. Signed-off-by: Johannes Berg --- drivers/net/wireless/iwlwifi/dvm/dev.h | 2 ++ drivers/net/wireless/iwlwifi/dvm/main.c | 3 +- drivers/net/wireless/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/mvm.h | 1 + drivers/net/wireless/iwlwifi/mvm/ops.c | 3 +- drivers/net/wireless/iwlwifi/mvm/rx.c | 2 +- include/net/mac80211.h | 37 ++++++++++++++++--------- net/mac80211/ieee80211_i.h | 6 +--- net/mac80211/main.c | 12 -------- net/mac80211/rx.c | 18 ++++++------ 10 files changed, 44 insertions(+), 42 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 3811878ab9cd2..074977ede3439 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -669,6 +669,8 @@ struct iwl_priv { /* ieee device used by generic ieee processing code */ struct ieee80211_hw *hw; + struct napi_struct *napi; + struct list_head calib_results; struct workqueue_struct *workqueue; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 234e30f498b2d..644819563cf0e 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -2037,7 +2037,8 @@ static void iwl_napi_add(struct iwl_op_mode *op_mode, { struct iwl_priv *priv = IWL_OP_MODE_GET_DVM(op_mode); - ieee80211_napi_add(priv->hw, napi, napi_dev, poll, weight); + netif_napi_add(napi_dev, napi, poll, weight); + priv->napi = napi; } static const struct iwl_op_mode_ops iwl_dvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index debec963c610d..5a91f5d6b1dcc 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -786,7 +786,7 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv, memcpy(IEEE80211_SKB_RXCB(skb), stats, sizeof(*stats)); - ieee80211_rx(priv->hw, skb); + ieee80211_rx_napi(priv->hw, skb, priv->napi); } static u32 iwlagn_translate_rx_status(struct iwl_priv *priv, u32 decrypt_in) diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 2d4bad5fe825f..605f57a2c6be4 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h @@ -559,6 +559,7 @@ struct iwl_mvm { const struct iwl_cfg *cfg; struct iwl_phy_db *phy_db; struct ieee80211_hw *hw; + struct napi_struct *napi; /* for protecting access to iwl_mvm */ struct mutex mutex; diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index e4fa50075ffdc..3967df63e0f38 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -1316,7 +1316,8 @@ static void iwl_mvm_napi_add(struct iwl_op_mode *op_mode, { struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); - ieee80211_napi_add(mvm->hw, napi, napi_dev, poll, weight); + netif_napi_add(napi_dev, napi, poll, weight); + mvm->napi = napi; } static const struct iwl_op_mode_ops iwl_mvm_ops = { diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c index 8f1d93b7a13aa..9ff0b4321df3b 100644 --- a/drivers/net/wireless/iwlwifi/mvm/rx.c +++ b/drivers/net/wireless/iwlwifi/mvm/rx.c @@ -129,7 +129,7 @@ static void iwl_mvm_pass_packet_to_mac80211(struct iwl_mvm *mvm, fraglen, rxb->truesize); } - ieee80211_rx(mvm->hw, skb); + ieee80211_rx_napi(mvm->hw, skb, mvm->napi); } /* diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 43dbddfa06c00..ff68b8c4ab351 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3694,20 +3694,28 @@ void ieee80211_free_hw(struct ieee80211_hw *hw); void ieee80211_restart_hw(struct ieee80211_hw *hw); /** - * ieee80211_napi_add - initialize mac80211 NAPI context - * @hw: the hardware to initialize the NAPI context on - * @napi: the NAPI context to initialize - * @napi_dev: dummy NAPI netdevice, here to not waste the space if the - * driver doesn't use NAPI - * @poll: poll function - * @weight: default weight + * ieee80211_rx_napi - receive frame from NAPI context * - * See also netif_napi_add(). + * Use this function to hand received frames to mac80211. The receive + * buffer in @skb must start with an IEEE 802.11 header. In case of a + * paged @skb is used, the driver is recommended to put the ieee80211 + * header of the frame on the linear part of the @skb to avoid memory + * allocation and/or memcpy by the stack. + * + * This function may not be called in IRQ context. Calls to this function + * for a single hardware must be synchronized against each other. Calls to + * this function, ieee80211_rx_ni() and ieee80211_rx_irqsafe() may not be + * mixed for a single hardware. Must not run concurrently with + * ieee80211_tx_status() or ieee80211_tx_status_ni(). + * + * This function must be called with BHs disabled. + * + * @hw: the hardware this frame came in on + * @skb: the buffer to receive, owned by mac80211 after this call + * @napi: the NAPI context */ -void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight); +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb, + struct napi_struct *napi); /** * ieee80211_rx - receive frame @@ -3729,7 +3737,10 @@ void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, * @hw: the hardware this frame came in on * @skb: the buffer to receive, owned by mac80211 after this call */ -void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb); +static inline void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +{ + ieee80211_rx_napi(hw, skb, NULL); +} /** * ieee80211_rx_irqsafe - receive frame diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 361bb3ca335c6..7d75f93bac7d5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -202,8 +202,6 @@ enum ieee80211_packet_rx_flags { * @IEEE80211_RX_CMNTR: received on cooked monitor already * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported * to cfg80211_report_obss_beacon(). - * @IEEE80211_RX_REORDER_TIMER: this frame is released by the - * reorder buffer timeout timer, not the normal RX path * * These flags are used across handling multiple interfaces * for a single frame. @@ -211,10 +209,10 @@ enum ieee80211_packet_rx_flags { enum ieee80211_rx_flags { IEEE80211_RX_CMNTR = BIT(0), IEEE80211_RX_BEACON_REPORTED = BIT(1), - IEEE80211_RX_REORDER_TIMER = BIT(2), }; struct ieee80211_rx_data { + struct napi_struct *napi; struct sk_buff *skb; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; @@ -1347,8 +1345,6 @@ struct ieee80211_local { struct ieee80211_sub_if_data __rcu *p2p_sdata; - struct napi_struct *napi; - /* virtual monitor interface */ struct ieee80211_sub_if_data __rcu *monitor_sdata; struct cfg80211_chan_def monitor_chandef; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index 3c63468b4dfb5..dba0a86dee18e 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -1132,18 +1132,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_register_hw); -void ieee80211_napi_add(struct ieee80211_hw *hw, struct napi_struct *napi, - struct net_device *napi_dev, - int (*poll)(struct napi_struct *, int), - int weight) -{ - struct ieee80211_local *local = hw_to_local(hw); - - netif_napi_add(napi_dev, napi, poll, weight); - local->napi = napi; -} -EXPORT_SYMBOL_GPL(ieee80211_napi_add); - void ieee80211_unregister_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index dd6bb2a54d45f..817bf22dad5a1 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2148,9 +2148,8 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) /* deliver to local stack */ skb->protocol = eth_type_trans(skb, dev); memset(skb->cb, 0, sizeof(skb->cb)); - if (!(rx->flags & IEEE80211_RX_REORDER_TIMER) && - rx->local->napi) - napi_gro_receive(rx->local->napi, skb); + if (rx->napi) + napi_gro_receive(rx->napi, skb); else netif_receive_skb(skb); } @@ -3256,7 +3255,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) /* This is OK -- must be QoS data frame */ .security_idx = tid, .seqno_idx = tid, - .flags = IEEE80211_RX_REORDER_TIMER, + .napi = NULL, /* must be NULL to not have races */ }; struct tid_ampdu_rx *tid_agg_rx; @@ -3433,7 +3432,8 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, * be called with rcu_read_lock protection. */ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, - struct sk_buff *skb) + struct sk_buff *skb, + struct napi_struct *napi) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; @@ -3449,6 +3449,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, memset(&rx, 0, sizeof(rx)); rx.skb = skb; rx.local = local; + rx.napi = napi; if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) I802_DEBUG_INC(local->dot11ReceivedFragmentCount); @@ -3550,7 +3551,8 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, * This is the receive path handler. It is called by a low level driver when an * 802.11 MPDU is received from the hardware. */ -void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) +void ieee80211_rx_napi(struct ieee80211_hw *hw, struct sk_buff *skb, + struct napi_struct *napi) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rate *rate = NULL; @@ -3649,7 +3651,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) ieee80211_tpt_led_trig_rx(local, ((struct ieee80211_hdr *)skb->data)->frame_control, skb->len); - __ieee80211_rx_handle_packet(hw, skb); + __ieee80211_rx_handle_packet(hw, skb, napi); rcu_read_unlock(); @@ -3657,7 +3659,7 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) drop: kfree_skb(skb); } -EXPORT_SYMBOL(ieee80211_rx); +EXPORT_SYMBOL(ieee80211_rx_napi); /* This is a version of the rx handler that can be called from hard irq * context. Post the skb on the queue and schedule the tasklet */ -- GitLab From 0c028b5fd1bd10d5777756e571c6c1971f04062b Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Jun 2015 14:33:54 +0200 Subject: [PATCH 1078/7006] mac80211: remove zero-length A-MPDU subframe reporting As there's no driver using this capability and reporting zero-length A-MPDU subframes for radiotap monitoring, remove the capability to free up two RX flags. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 6 +----- net/mac80211/rx.c | 7 +------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index ff68b8c4ab351..7417fee181852 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -997,9 +997,6 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_AMPDU_DETAILS: A-MPDU details are known, in particular the reference * number (@ampdu_reference) must be populated and be a distinct number for * each A-MPDU - * @RX_FLAG_AMPDU_REPORT_ZEROLEN: driver reports 0-length subframes - * @RX_FLAG_AMPDU_IS_ZEROLEN: This is a zero-length subframe, for - * monitoring purposes only * @RX_FLAG_AMPDU_LAST_KNOWN: last subframe is known, should be set on all * subframes of a single A-MPDU * @RX_FLAG_AMPDU_IS_LAST: this subframe is the last subframe of the A-MPDU @@ -1039,8 +1036,7 @@ enum mac80211_rx_flags { RX_FLAG_NO_SIGNAL_VAL = BIT(12), RX_FLAG_HT_GF = BIT(13), RX_FLAG_AMPDU_DETAILS = BIT(14), - RX_FLAG_AMPDU_REPORT_ZEROLEN = BIT(15), - RX_FLAG_AMPDU_IS_ZEROLEN = BIT(16), + /* bits 15/16 free */ RX_FLAG_AMPDU_LAST_KNOWN = BIT(17), RX_FLAG_AMPDU_IS_LAST = BIT(18), RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19), diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 817bf22dad5a1..9d95cb8e8e955 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -122,8 +122,7 @@ static inline bool should_drop_frame(struct sk_buff *skb, int present_fcs_len, hdr = (void *)(skb->data + rtap_vendor_space); if (status->flag & (RX_FLAG_FAILED_FCS_CRC | - RX_FLAG_FAILED_PLCP_CRC | - RX_FLAG_AMPDU_IS_ZEROLEN)) + RX_FLAG_FAILED_PLCP_CRC)) return true; if (unlikely(skb->len < 16 + present_fcs_len + rtap_vendor_space)) @@ -391,10 +390,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, cpu_to_le32(1 << IEEE80211_RADIOTAP_AMPDU_STATUS); put_unaligned_le32(status->ampdu_reference, pos); pos += 4; - if (status->flag & RX_FLAG_AMPDU_REPORT_ZEROLEN) - flags |= IEEE80211_RADIOTAP_AMPDU_REPORT_ZEROLEN; - if (status->flag & RX_FLAG_AMPDU_IS_ZEROLEN) - flags |= IEEE80211_RADIOTAP_AMPDU_IS_ZEROLEN; if (status->flag & RX_FLAG_AMPDU_LAST_KNOWN) flags |= IEEE80211_RADIOTAP_AMPDU_LAST_KNOWN; if (status->flag & RX_FLAG_AMPDU_IS_LAST) -- GitLab From 77c96404a4cf16ffa0720a3fbf45839cc16018ac Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Jun 2015 14:40:45 +0200 Subject: [PATCH 1079/7006] mac80211: remove key TX/RX counter This counter is inherently racy (since it can be incremented by RX as well as by concurrent TX) and only available in debugfs. Instead of fixing it to be per-CPU or similar, remove it for now. If needed it should be added without races and with proper nl80211, perhaps even addressing the threshold reporting TODO item that's been there since the code was originally added. Signed-off-by: Johannes Berg --- net/mac80211/debugfs_key.c | 2 -- net/mac80211/key.h | 3 --- net/mac80211/rx.c | 1 - net/mac80211/tx.c | 1 - 4 files changed, 7 deletions(-) diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index e82bf1e9d7a83..702ca122c4989 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -57,7 +57,6 @@ KEY_CONF_FILE(keylen, D); KEY_CONF_FILE(keyidx, D); KEY_CONF_FILE(hw_key_idx, D); KEY_FILE(flags, X); -KEY_FILE(tx_rx_count, D); KEY_READ(ifindex, sdata->name, "%s\n"); KEY_OPS(ifindex); @@ -310,7 +309,6 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) DEBUGFS_ADD(flags); DEBUGFS_ADD(keyidx); DEBUGFS_ADD(hw_key_idx); - DEBUGFS_ADD(tx_rx_count); DEBUGFS_ADD(algorithm); DEBUGFS_ADD(tx_spec); DEBUGFS_ADD(rx_spec); diff --git a/net/mac80211/key.h b/net/mac80211/key.h index 3f4f9eaac1400..9951ef06323e7 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h @@ -115,9 +115,6 @@ struct ieee80211_key { } gen; } u; - /* number of times this key has been used */ - int tx_rx_count; - #ifdef CONFIG_MAC80211_DEBUGFS struct { struct dentry *stalink; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 9d95cb8e8e955..3037bd152ffaa 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1682,7 +1682,6 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) if (unlikely(rx->key->flags & KEY_FLAG_TAINTED)) return RX_DROP_MONITOR; - rx->key->tx_rx_count++; /* TODO: add threshold stuff again */ } else { return RX_DROP_MONITOR; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 8410bb3bf5e8d..87b9b4e27d225 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -610,7 +610,6 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) if (tx->key) { bool skip_hw = false; - tx->key->tx_rx_count++; /* TODO: add threshold stuff again */ switch (tx->key->conf.cipher) { -- GitLab From 981d94a80174e4f33bd5015fb49051bfc2eb00d2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Jun 2015 14:39:02 +0200 Subject: [PATCH 1080/7006] mac80211: support device/driver PN check for CCMP/GCMP When there are multiple RX queues, the PN checks in mac80211 cannot be used since packets might be processed out of order on different CPUs. Allow the driver to report that the PN has been checked, drivers that will use multi-queue RX will have to set this flag. For now, the flag is only valid when the frame has been decrypted, in theory that restriction doesn't have to be there, but in practice the hardware will have decrypted the frame already. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 7 +++- net/mac80211/wpa.c | 83 +++++++++++++++++++++++------------------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 7417fee181852..4d3d2686f2787 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -973,6 +973,10 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_IV_STRIPPED: The IV/ICV are stripped from this frame. * If this flag is set, the stack cannot do any replay detection * hence the driver or hardware will have to do that. + * @RX_FLAG_PN_VALIDATED: Currently only valid for CCMP/GCMP frames, this + * flag indicates that the PN was verified for replay protection. + * Note that this flag is also currently only supported when a frame + * is also decrypted (ie. @RX_FLAG_DECRYPTED must be set) * @RX_FLAG_FAILED_FCS_CRC: Set this flag if the FCS check failed on * the frame. * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on @@ -1036,7 +1040,8 @@ enum mac80211_rx_flags { RX_FLAG_NO_SIGNAL_VAL = BIT(12), RX_FLAG_HT_GF = BIT(13), RX_FLAG_AMPDU_DETAILS = BIT(14), - /* bits 15/16 free */ + RX_FLAG_PN_VALIDATED = BIT(15), + /* bit 16 free */ RX_FLAG_AMPDU_LAST_KNOWN = BIT(17), RX_FLAG_AMPDU_IS_LAST = BIT(18), RX_FLAG_AMPDU_DELIM_CRC_ERROR = BIT(19), diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 943f7606527e2..feb547dc8643a 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -516,31 +516,34 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx, return RX_DROP_UNUSABLE; } - ccmp_hdr2pn(pn, skb->data + hdrlen); + if (!(status->flag & RX_FLAG_PN_VALIDATED)) { + ccmp_hdr2pn(pn, skb->data + hdrlen); - queue = rx->security_idx; + queue = rx->security_idx; - if (memcmp(pn, key->u.ccmp.rx_pn[queue], IEEE80211_CCMP_PN_LEN) <= 0) { - key->u.ccmp.replays++; - return RX_DROP_UNUSABLE; - } + if (memcmp(pn, key->u.ccmp.rx_pn[queue], + IEEE80211_CCMP_PN_LEN) <= 0) { + key->u.ccmp.replays++; + return RX_DROP_UNUSABLE; + } - if (!(status->flag & RX_FLAG_DECRYPTED)) { - u8 aad[2 * AES_BLOCK_SIZE]; - u8 b_0[AES_BLOCK_SIZE]; - /* hardware didn't decrypt/verify MIC */ - ccmp_special_blocks(skb, pn, b_0, aad); + if (!(status->flag & RX_FLAG_DECRYPTED)) { + u8 aad[2 * AES_BLOCK_SIZE]; + u8 b_0[AES_BLOCK_SIZE]; + /* hardware didn't decrypt/verify MIC */ + ccmp_special_blocks(skb, pn, b_0, aad); + + if (ieee80211_aes_ccm_decrypt( + key->u.ccmp.tfm, b_0, aad, + skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN, + data_len, + skb->data + skb->len - mic_len, mic_len)) + return RX_DROP_UNUSABLE; + } - if (ieee80211_aes_ccm_decrypt( - key->u.ccmp.tfm, b_0, aad, - skb->data + hdrlen + IEEE80211_CCMP_HDR_LEN, - data_len, - skb->data + skb->len - mic_len, mic_len)) - return RX_DROP_UNUSABLE; + memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN); } - memcpy(key->u.ccmp.rx_pn[queue], pn, IEEE80211_CCMP_PN_LEN); - /* Remove CCMP header and MIC */ if (pskb_trim(skb, skb->len - mic_len)) return RX_DROP_UNUSABLE; @@ -739,31 +742,35 @@ ieee80211_crypto_gcmp_decrypt(struct ieee80211_rx_data *rx) return RX_DROP_UNUSABLE; } - gcmp_hdr2pn(pn, skb->data + hdrlen); + if (!(status->flag & RX_FLAG_PN_VALIDATED)) { + gcmp_hdr2pn(pn, skb->data + hdrlen); - queue = rx->security_idx; + queue = rx->security_idx; - if (memcmp(pn, key->u.gcmp.rx_pn[queue], IEEE80211_GCMP_PN_LEN) <= 0) { - key->u.gcmp.replays++; - return RX_DROP_UNUSABLE; - } + if (memcmp(pn, key->u.gcmp.rx_pn[queue], + IEEE80211_GCMP_PN_LEN) <= 0) { + key->u.gcmp.replays++; + return RX_DROP_UNUSABLE; + } - if (!(status->flag & RX_FLAG_DECRYPTED)) { - u8 aad[2 * AES_BLOCK_SIZE]; - u8 j_0[AES_BLOCK_SIZE]; - /* hardware didn't decrypt/verify MIC */ - gcmp_special_blocks(skb, pn, j_0, aad); + if (!(status->flag & RX_FLAG_DECRYPTED)) { + u8 aad[2 * AES_BLOCK_SIZE]; + u8 j_0[AES_BLOCK_SIZE]; + /* hardware didn't decrypt/verify MIC */ + gcmp_special_blocks(skb, pn, j_0, aad); + + if (ieee80211_aes_gcm_decrypt( + key->u.gcmp.tfm, j_0, aad, + skb->data + hdrlen + IEEE80211_GCMP_HDR_LEN, + data_len, + skb->data + skb->len - + IEEE80211_GCMP_MIC_LEN)) + return RX_DROP_UNUSABLE; + } - if (ieee80211_aes_gcm_decrypt( - key->u.gcmp.tfm, j_0, aad, - skb->data + hdrlen + IEEE80211_GCMP_HDR_LEN, - data_len, - skb->data + skb->len - IEEE80211_GCMP_MIC_LEN)) - return RX_DROP_UNUSABLE; + memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN); } - memcpy(key->u.gcmp.rx_pn[queue], pn, IEEE80211_GCMP_PN_LEN); - /* Remove GCMP header and MIC */ if (pskb_trim(skb, skb->len - IEEE80211_GCMP_MIC_LEN)) return RX_DROP_UNUSABLE; -- GitLab From ac100ce52a2d3b6261a06939d22e4382d9aa0bb2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 16:22:12 +0200 Subject: [PATCH 1081/7006] mac80211: duplicate station's MAC address for hash table Currently, the station hash table lookup (or iteration) must access two cachelines for each station - the one with the hash table node, and the one with the MAC address. Duplicate the MAC address next to the hash node to get rid of this. Since the MAC address is static there's no consistency problem introduced by this. Signed-off-by: Johannes Berg --- net/mac80211/sta_info.c | 3 ++- net/mac80211/sta_info.h | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 666ddac3c87c6..d573a499750eb 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -68,7 +68,7 @@ static const struct rhashtable_params sta_rht_params = { .nelem_hint = 3, /* start small */ .automatic_shrinking = true, .head_offset = offsetof(struct sta_info, hash_node), - .key_offset = offsetof(struct sta_info, sta.addr), + .key_offset = offsetof(struct sta_info, addr), .key_len = ETH_ALEN, .hashfn = sta_addr_hash, .max_size = CONFIG_MAC80211_STA_HASH_MAX_SIZE, @@ -320,6 +320,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, sta->nonpeer_pm = NL80211_MESH_POWER_ACTIVE; #endif + memcpy(sta->addr, addr, ETH_ALEN); memcpy(sta->sta.addr, addr, ETH_ALEN); sta->local = local; sta->sdata = sdata; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index db76103b44455..4229849862638 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -278,6 +278,8 @@ struct ieee80211_fast_tx { * @list: global linked list entry * @free_list: list entry for keeping track of stations to free * @hash_node: hash node for rhashtable + * @addr: station's MAC address - duplicated from public part to + * let the hash table work with just a single cacheline * @local: pointer to the global information * @sdata: virtual interface this station belongs to * @ptk: peer keys negotiated with this station, if any @@ -377,6 +379,7 @@ struct sta_info { struct list_head list, free_list; struct rcu_head rcu_head; struct rhash_head hash_node; + u8 addr[ETH_ALEN]; struct ieee80211_local *local; struct ieee80211_sub_if_data *sdata; struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; @@ -607,7 +610,7 @@ u32 sta_addr_hash(const void *key, u32 length, u32 seed); _sta_bucket_idx(tbl, _addr), \ hash_node) \ /* compare address and run code only if it matches */ \ - if (ether_addr_equal(_sta->sta.addr, (_addr))) + if (ether_addr_equal(_sta->addr, (_addr))) /* * Get STA info by index, BROKEN! -- GitLab From e414eea77d1ae1201d5252964406a22adfa9f3c2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 16 Jun 2015 12:53:10 +0200 Subject: [PATCH 1082/7006] mac80211: remove IEEE80211_RX_FRAGMENTED There's a long-standing TODO item to use this flag in the cooked monitor RX, but clearly it was never needed and now this hasn't been used by userspace for a long time, so no userspace changes could require it now. Remove the unused flag. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 -- net/mac80211/rx.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 7d75f93bac7d5..68b091a0cae15 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -181,7 +181,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; /** * enum ieee80211_packet_rx_flags - packet RX flags - * @IEEE80211_RX_FRAGMENTED: fragmented frame * @IEEE80211_RX_AMSDU: a-MSDU packet * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed * @IEEE80211_RX_DEFERRED_RELEASE: frame was subjected to receive reordering @@ -190,7 +189,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * @rx_flags field of &struct ieee80211_rx_status. */ enum ieee80211_packet_rx_flags { - IEEE80211_RX_FRAGMENTED = BIT(2), IEEE80211_RX_AMSDU = BIT(3), IEEE80211_RX_MALFORMED_ACTION_FRM = BIT(4), IEEE80211_RX_DEFERRED_RELEASE = BIT(5), diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3037bd152ffaa..3a1462810c8e2 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -1917,7 +1917,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) /* Complete frame has been reassembled - process it now */ status = IEEE80211_SKB_RXCB(rx->skb); - status->rx_flags |= IEEE80211_RX_FRAGMENTED; out: ieee80211_led_rx(rx->local); @@ -3037,7 +3036,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx) return RX_QUEUED; } -/* TODO: use IEEE80211_RX_FRAGMENTED */ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx, struct ieee80211_rate *rate) { -- GitLab From 433f5bc1c0efc67a86433e47a14b115510fc1409 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2015 10:31:00 +0200 Subject: [PATCH 1083/7006] mac80211: move mesh related station fields to own struct There are now a fairly large number of mesh fields that really aren't needed in any other modes; move those into their own structure and allocate them separately. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 8 +- net/mac80211/mesh.c | 2 +- net/mac80211/mesh_hwmp.c | 2 +- net/mac80211/mesh_plink.c | 177 +++++++++++++++++++------------------- net/mac80211/mesh_ps.c | 42 ++++----- net/mac80211/mesh_sync.c | 16 ++-- net/mac80211/sta_info.c | 37 +++++--- net/mac80211/sta_info.h | 88 ++++++++++--------- 8 files changed, 196 insertions(+), 176 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5fc7788e2ff26..c9f8f34ac7289 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1150,10 +1150,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { switch (params->plink_state) { case NL80211_PLINK_ESTAB: - if (sta->plink_state != NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) changed = mesh_plink_inc_estab_count( sdata); - sta->plink_state = params->plink_state; + sta->mesh->plink_state = params->plink_state; ieee80211_mps_sta_status_update(sta); changed |= ieee80211_mps_set_sta_local_pm(sta, @@ -1165,10 +1165,10 @@ static int sta_apply_parameters(struct ieee80211_local *local, case NL80211_PLINK_OPN_RCVD: case NL80211_PLINK_CNF_RCVD: case NL80211_PLINK_HOLDING: - if (sta->plink_state == NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) changed = mesh_plink_dec_estab_count( sdata); - sta->plink_state = params->plink_state; + sta->mesh->plink_state = params->plink_state; ieee80211_mps_sta_status_update(sta); changed |= ieee80211_mps_set_sta_local_pm(sta, diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 817098add1d67..e06a5ca7c9a99 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -158,7 +158,7 @@ void mesh_sta_cleanup(struct sta_info *sta) changed = mesh_accept_plinks_update(sdata); if (!sdata->u.mesh.user_mpm) { changed |= mesh_plink_deactivate(sta); - del_timer_sync(&sta->plink_timer); + del_timer_sync(&sta->mesh->plink_timer); } if (changed) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 085edc1d056bf..cd02810038cb4 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -862,7 +862,7 @@ void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); - if (!sta || sta->plink_state != NL80211_PLINK_ESTAB) { + if (!sta || sta->mesh->plink_state != NL80211_PLINK_ESTAB) { rcu_read_unlock(); return; } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 5438d13e2f007..1a7d983986262 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -16,7 +16,7 @@ #define PLINK_GET_LLID(p) (p + 2) #define PLINK_GET_PLID(p) (p + 4) -#define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \ +#define mod_plink_timer(s, t) (mod_timer(&s->mesh->plink_timer, \ jiffies + msecs_to_jiffies(t))) enum plink_event { @@ -72,14 +72,14 @@ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata, * * @sta: mesh peer link to restart * - * Locking: this function must be called holding sta->plink_lock + * Locking: this function must be called holding sta->mesh->plink_lock */ static inline void mesh_plink_fsm_restart(struct sta_info *sta) { - lockdep_assert_held(&sta->plink_lock); - sta->plink_state = NL80211_PLINK_LISTEN; - sta->llid = sta->plid = sta->reason = 0; - sta->plink_retries = 0; + lockdep_assert_held(&sta->mesh->plink_lock); + sta->mesh->plink_state = NL80211_PLINK_LISTEN; + sta->mesh->llid = sta->mesh->plid = sta->mesh->reason = 0; + sta->mesh->plink_retries = 0; } /* @@ -119,7 +119,7 @@ static u32 mesh_set_short_slot_time(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { if (sdata != sta->sdata || - sta->plink_state != NL80211_PLINK_ESTAB) + sta->mesh->plink_state != NL80211_PLINK_ESTAB) continue; short_slot = false; @@ -169,7 +169,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { if (sdata != sta->sdata || - sta->plink_state != NL80211_PLINK_ESTAB) + sta->mesh->plink_state != NL80211_PLINK_ESTAB) continue; if (sta->sta.bandwidth > IEEE80211_STA_RX_BW_20) @@ -212,18 +212,18 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) * All mesh paths with this peer as next hop will be flushed * Returns beacon changed flag if the beacon content changed. * - * Locking: the caller must hold sta->plink_lock + * Locking: the caller must hold sta->mesh->plink_lock */ static u32 __mesh_plink_deactivate(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; u32 changed = 0; - lockdep_assert_held(&sta->plink_lock); + lockdep_assert_held(&sta->mesh->plink_lock); - if (sta->plink_state == NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) changed = mesh_plink_dec_estab_count(sdata); - sta->plink_state = NL80211_PLINK_BLOCKED; + sta->mesh->plink_state = NL80211_PLINK_BLOCKED; mesh_path_flush_by_nexthop(sta); ieee80211_mps_sta_status_update(sta); @@ -245,13 +245,13 @@ u32 mesh_plink_deactivate(struct sta_info *sta) struct ieee80211_sub_if_data *sdata = sta->sdata; u32 changed; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->mesh->plink_lock); changed = __mesh_plink_deactivate(sta); - sta->reason = WLAN_REASON_MESH_PEER_CANCELED; + sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED; mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, sta->llid, sta->plid, - sta->reason); - spin_unlock_bh(&sta->plink_lock); + sta->sta.addr, sta->mesh->llid, sta->mesh->plid, + sta->mesh->reason); + spin_unlock_bh(&sta->mesh->plink_lock); return changed; } @@ -388,13 +388,14 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, sband = local->hw.wiphy->bands[band]; rates = ieee80211_sta_get_rates(sdata, elems, band, &basic_rates); - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->mesh->plink_lock); sta->last_rx = jiffies; /* rates and capabilities don't change during peering */ - if (sta->plink_state == NL80211_PLINK_ESTAB && sta->processed_beacon) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB && + sta->mesh->processed_beacon) goto out; - sta->processed_beacon = true; + sta->mesh->processed_beacon = true; if (sta->sta.supp_rates[band] != rates) changed |= IEEE80211_RC_SUPP_RATES_CHANGED; @@ -421,7 +422,7 @@ static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, else rate_control_rate_update(local, sband, sta, changed); out: - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->mesh->plink_lock); } static struct sta_info * @@ -436,7 +437,7 @@ __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) if (!sta) return NULL; - sta->plink_state = NL80211_PLINK_LISTEN; + sta->mesh->plink_state = NL80211_PLINK_LISTEN; sta->sta.wme = true; sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); @@ -524,7 +525,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, goto out; if (mesh_peer_accepts_plinks(elems) && - sta->plink_state == NL80211_PLINK_LISTEN && + sta->mesh->plink_state == NL80211_PLINK_LISTEN && sdata->u.mesh.accepting_plinks && sdata->u.mesh.mshcfg.auto_open_plinks && rssi_threshold_check(sdata, sta)) @@ -554,52 +555,52 @@ static void mesh_plink_timer(unsigned long data) if (sta->sdata->local->quiescing) return; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->mesh->plink_lock); /* If a timer fires just before a state transition on another CPU, * we may have already extended the timeout and changed state by the * time we've acquired the lock and arrived here. In that case, * skip this timer and wait for the new one. */ - if (time_before(jiffies, sta->plink_timer.expires)) { + if (time_before(jiffies, sta->mesh->plink_timer.expires)) { mpl_dbg(sta->sdata, "Ignoring timer for %pM in state %s (timer adjusted)", - sta->sta.addr, mplstates[sta->plink_state]); - spin_unlock_bh(&sta->plink_lock); + sta->sta.addr, mplstates[sta->mesh->plink_state]); + spin_unlock_bh(&sta->mesh->plink_lock); return; } /* del_timer() and handler may race when entering these states */ - if (sta->plink_state == NL80211_PLINK_LISTEN || - sta->plink_state == NL80211_PLINK_ESTAB) { + if (sta->mesh->plink_state == NL80211_PLINK_LISTEN || + sta->mesh->plink_state == NL80211_PLINK_ESTAB) { mpl_dbg(sta->sdata, "Ignoring timer for %pM in state %s (timer deleted)", - sta->sta.addr, mplstates[sta->plink_state]); - spin_unlock_bh(&sta->plink_lock); + sta->sta.addr, mplstates[sta->mesh->plink_state]); + spin_unlock_bh(&sta->mesh->plink_lock); return; } mpl_dbg(sta->sdata, "Mesh plink timer for %pM fired on state %s\n", - sta->sta.addr, mplstates[sta->plink_state]); + sta->sta.addr, mplstates[sta->mesh->plink_state]); sdata = sta->sdata; mshcfg = &sdata->u.mesh.mshcfg; - switch (sta->plink_state) { + switch (sta->mesh->plink_state) { case NL80211_PLINK_OPN_RCVD: case NL80211_PLINK_OPN_SNT: /* retry timer */ - if (sta->plink_retries < mshcfg->dot11MeshMaxRetries) { + if (sta->mesh->plink_retries < mshcfg->dot11MeshMaxRetries) { u32 rand; mpl_dbg(sta->sdata, "Mesh plink for %pM (retry, timeout): %d %d\n", - sta->sta.addr, sta->plink_retries, - sta->plink_timeout); + sta->sta.addr, sta->mesh->plink_retries, + sta->mesh->plink_timeout); get_random_bytes(&rand, sizeof(u32)); - sta->plink_timeout = sta->plink_timeout + - rand % sta->plink_timeout; - ++sta->plink_retries; - mod_plink_timer(sta, sta->plink_timeout); + sta->mesh->plink_timeout = sta->mesh->plink_timeout + + rand % sta->mesh->plink_timeout; + ++sta->mesh->plink_retries; + mod_plink_timer(sta, sta->mesh->plink_timeout); action = WLAN_SP_MESH_PEERING_OPEN; break; } @@ -609,31 +610,31 @@ static void mesh_plink_timer(unsigned long data) /* confirm timer */ if (!reason) reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT; - sta->plink_state = NL80211_PLINK_HOLDING; + sta->mesh->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); action = WLAN_SP_MESH_PEERING_CLOSE; break; case NL80211_PLINK_HOLDING: /* holding timer */ - del_timer(&sta->plink_timer); + del_timer(&sta->mesh->plink_timer); mesh_plink_fsm_restart(sta); break; default: break; } - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->mesh->plink_lock); if (action) mesh_plink_frame_tx(sdata, action, sta->sta.addr, - sta->llid, sta->plid, reason); + sta->mesh->llid, sta->mesh->plid, reason); } static inline void mesh_plink_timer_set(struct sta_info *sta, u32 timeout) { - sta->plink_timer.expires = jiffies + msecs_to_jiffies(timeout); - sta->plink_timer.data = (unsigned long) sta; - sta->plink_timer.function = mesh_plink_timer; - sta->plink_timeout = timeout; - add_timer(&sta->plink_timer); + sta->mesh->plink_timer.expires = jiffies + msecs_to_jiffies(timeout); + sta->mesh->plink_timer.data = (unsigned long) sta; + sta->mesh->plink_timer.function = mesh_plink_timer; + sta->mesh->plink_timeout = timeout; + add_timer(&sta->mesh->plink_timer); } static bool llid_in_use(struct ieee80211_sub_if_data *sdata, @@ -645,7 +646,7 @@ static bool llid_in_use(struct ieee80211_sub_if_data *sdata, rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (!memcmp(&sta->llid, &llid, sizeof(llid))) { + if (!memcmp(&sta->mesh->llid, &llid, sizeof(llid))) { in_use = true; break; } @@ -676,16 +677,16 @@ u32 mesh_plink_open(struct sta_info *sta) if (!test_sta_flag(sta, WLAN_STA_AUTH)) return 0; - spin_lock_bh(&sta->plink_lock); - sta->llid = mesh_get_new_llid(sdata); - if (sta->plink_state != NL80211_PLINK_LISTEN && - sta->plink_state != NL80211_PLINK_BLOCKED) { - spin_unlock_bh(&sta->plink_lock); + spin_lock_bh(&sta->mesh->plink_lock); + sta->mesh->llid = mesh_get_new_llid(sdata); + if (sta->mesh->plink_state != NL80211_PLINK_LISTEN && + sta->mesh->plink_state != NL80211_PLINK_BLOCKED) { + spin_unlock_bh(&sta->mesh->plink_lock); return 0; } - sta->plink_state = NL80211_PLINK_OPN_SNT; + sta->mesh->plink_state = NL80211_PLINK_OPN_SNT; mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout); - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->mesh->plink_lock); mpl_dbg(sdata, "Mesh plink: starting establishment with %pM\n", sta->sta.addr); @@ -694,7 +695,7 @@ u32 mesh_plink_open(struct sta_info *sta) changed = ieee80211_mps_local_status_update(sdata); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, - sta->sta.addr, sta->llid, 0, 0); + sta->sta.addr, sta->mesh->llid, 0, 0); return changed; } @@ -702,10 +703,10 @@ u32 mesh_plink_block(struct sta_info *sta) { u32 changed; - spin_lock_bh(&sta->plink_lock); + spin_lock_bh(&sta->mesh->plink_lock); changed = __mesh_plink_deactivate(sta); - sta->plink_state = NL80211_PLINK_BLOCKED; - spin_unlock_bh(&sta->plink_lock); + sta->mesh->plink_state = NL80211_PLINK_BLOCKED; + spin_unlock_bh(&sta->mesh->plink_lock); return changed; } @@ -715,12 +716,11 @@ static void mesh_plink_close(struct ieee80211_sub_if_data *sdata, enum plink_event event) { struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; - u16 reason = (event == CLS_ACPT) ? WLAN_REASON_MESH_CLOSE : WLAN_REASON_MESH_CONFIG; - sta->reason = reason; - sta->plink_state = NL80211_PLINK_HOLDING; + sta->mesh->reason = reason; + sta->mesh->plink_state = NL80211_PLINK_HOLDING; mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout); } @@ -730,8 +730,8 @@ static u32 mesh_plink_establish(struct ieee80211_sub_if_data *sdata, struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg; u32 changed = 0; - del_timer(&sta->plink_timer); - sta->plink_state = NL80211_PLINK_ESTAB; + del_timer(&sta->mesh->plink_timer); + sta->mesh->plink_state = NL80211_PLINK_ESTAB; changed |= mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= mesh_set_short_slot_time(sdata); @@ -758,18 +758,18 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, u32 changed = 0; mpl_dbg(sdata, "peer %pM in state %s got event %s\n", sta->sta.addr, - mplstates[sta->plink_state], mplevents[event]); + mplstates[sta->mesh->plink_state], mplevents[event]); - spin_lock_bh(&sta->plink_lock); - switch (sta->plink_state) { + spin_lock_bh(&sta->mesh->plink_lock); + switch (sta->mesh->plink_state) { case NL80211_PLINK_LISTEN: switch (event) { case CLS_ACPT: mesh_plink_fsm_restart(sta); break; case OPN_ACPT: - sta->plink_state = NL80211_PLINK_OPN_RCVD; - sta->llid = mesh_get_new_llid(sdata); + sta->mesh->plink_state = NL80211_PLINK_OPN_RCVD; + sta->mesh->llid = mesh_get_new_llid(sdata); mesh_plink_timer_set(sta, mshcfg->dot11MeshRetryTimeout); @@ -791,11 +791,11 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, break; case OPN_ACPT: /* retry timer is left untouched */ - sta->plink_state = NL80211_PLINK_OPN_RCVD; + sta->mesh->plink_state = NL80211_PLINK_OPN_RCVD; action = WLAN_SP_MESH_PEERING_CONFIRM; break; case CNF_ACPT: - sta->plink_state = NL80211_PLINK_CNF_RCVD; + sta->mesh->plink_state = NL80211_PLINK_CNF_RCVD; mod_plink_timer(sta, mshcfg->dot11MeshConfirmTimeout); break; default: @@ -855,7 +855,7 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, case NL80211_PLINK_HOLDING: switch (event) { case CLS_ACPT: - del_timer(&sta->plink_timer); + del_timer(&sta->mesh->plink_timer); mesh_plink_fsm_restart(sta); break; case OPN_ACPT: @@ -874,17 +874,18 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, */ break; } - spin_unlock_bh(&sta->plink_lock); + spin_unlock_bh(&sta->mesh->plink_lock); if (action) { mesh_plink_frame_tx(sdata, action, sta->sta.addr, - sta->llid, sta->plid, sta->reason); + sta->mesh->llid, sta->mesh->plid, + sta->mesh->reason); /* also send confirm in open case */ if (action == WLAN_SP_MESH_PEERING_OPEN) { mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CONFIRM, - sta->sta.addr, sta->llid, - sta->plid, 0); + sta->sta.addr, sta->mesh->llid, + sta->mesh->plid, 0); } } @@ -939,7 +940,7 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); goto out; } - if (sta->plink_state == NL80211_PLINK_BLOCKED) + if (sta->mesh->plink_state == NL80211_PLINK_BLOCKED) goto out; } @@ -954,7 +955,7 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, if (!matches_local) event = OPN_RJCT; if (!mesh_plink_free_count(sdata) || - (sta->plid && sta->plid != plid)) + (sta->mesh->plid && sta->mesh->plid != plid)) event = OPN_IGNR; else event = OPN_ACPT; @@ -963,14 +964,14 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, if (!matches_local) event = CNF_RJCT; if (!mesh_plink_free_count(sdata) || - sta->llid != llid || - (sta->plid && sta->plid != plid)) + sta->mesh->llid != llid || + (sta->mesh->plid && sta->mesh->plid != plid)) event = CNF_IGNR; else event = CNF_ACPT; break; case WLAN_SP_MESH_PEERING_CLOSE: - if (sta->plink_state == NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) /* Do not check for llid or plid. This does not * follow the standard but since multiple plinks * per sta are not supported, it is necessary in @@ -981,9 +982,9 @@ mesh_plink_get_event(struct ieee80211_sub_if_data *sdata, * restarted. */ event = CLS_ACPT; - else if (sta->plid != plid) + else if (sta->mesh->plid != plid) event = CLS_IGNR; - else if (ie_len == 8 && sta->llid != llid) + else if (ie_len == 8 && sta->mesh->llid != llid) event = CLS_IGNR; else event = CLS_ACPT; @@ -1070,7 +1071,7 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); goto unlock_rcu; } - sta->plid = plid; + sta->mesh->plid = plid; } else if (!sta && event == OPN_RJCT) { mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, mgmt->sa, 0, plid, @@ -1082,8 +1083,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, } /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ - if (!sta->plid && event == CNF_ACPT) - sta->plid = plid; + if (!sta->mesh->plid && event == CNF_ACPT) + sta->mesh->plid = plid; changed |= mesh_plink_fsm(sdata, sta, event); diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index ad8b377b4b9f6..29747f92b9b02 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c @@ -92,16 +92,16 @@ u32 ieee80211_mps_local_status_update(struct ieee80211_sub_if_data *sdata) if (sdata != sta->sdata) continue; - switch (sta->plink_state) { + switch (sta->mesh->plink_state) { case NL80211_PLINK_OPN_SNT: case NL80211_PLINK_OPN_RCVD: case NL80211_PLINK_CNF_RCVD: peering = true; break; case NL80211_PLINK_ESTAB: - if (sta->local_pm == NL80211_MESH_POWER_LIGHT_SLEEP) + if (sta->mesh->local_pm == NL80211_MESH_POWER_LIGHT_SLEEP) light_sleep_cnt++; - else if (sta->local_pm == NL80211_MESH_POWER_DEEP_SLEEP) + else if (sta->mesh->local_pm == NL80211_MESH_POWER_DEEP_SLEEP) deep_sleep_cnt++; break; default: @@ -153,19 +153,19 @@ u32 ieee80211_mps_set_sta_local_pm(struct sta_info *sta, { struct ieee80211_sub_if_data *sdata = sta->sdata; - if (sta->local_pm == pm) + if (sta->mesh->local_pm == pm) return 0; mps_dbg(sdata, "local STA operates in mode %d with %pM\n", pm, sta->sta.addr); - sta->local_pm = pm; + sta->mesh->local_pm = pm; /* * announce peer-specific power mode transition * (see IEEE802.11-2012 13.14.3.2 and 13.14.3.3) */ - if (sta->plink_state == NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) mps_qos_null_tx(sta); return ieee80211_mps_local_status_update(sdata); @@ -197,8 +197,8 @@ void ieee80211_mps_set_frame_flags(struct ieee80211_sub_if_data *sdata, if (is_unicast_ether_addr(hdr->addr1) && ieee80211_is_data_qos(hdr->frame_control) && - sta->plink_state == NL80211_PLINK_ESTAB) - pm = sta->local_pm; + sta->mesh->plink_state == NL80211_PLINK_ESTAB) + pm = sta->mesh->local_pm; else pm = sdata->u.mesh.nonpeer_pm; @@ -241,16 +241,16 @@ void ieee80211_mps_sta_status_update(struct sta_info *sta) * use peer-specific power mode if peering is established and the * peer's power mode is known */ - if (sta->plink_state == NL80211_PLINK_ESTAB && - sta->peer_pm != NL80211_MESH_POWER_UNKNOWN) - pm = sta->peer_pm; + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB && + sta->mesh->peer_pm != NL80211_MESH_POWER_UNKNOWN) + pm = sta->mesh->peer_pm; else - pm = sta->nonpeer_pm; + pm = sta->mesh->nonpeer_pm; do_buffer = (pm != NL80211_MESH_POWER_ACTIVE); /* clear the MPSP flags for non-peers or active STA */ - if (sta->plink_state != NL80211_PLINK_ESTAB) { + if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) { clear_sta_flag(sta, WLAN_STA_MPSP_OWNER); clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); } else if (!do_buffer) { @@ -296,13 +296,13 @@ static void mps_set_sta_peer_pm(struct sta_info *sta, pm = NL80211_MESH_POWER_ACTIVE; } - if (sta->peer_pm == pm) + if (sta->mesh->peer_pm == pm) return; mps_dbg(sta->sdata, "STA %pM enters mode %d\n", sta->sta.addr, pm); - sta->peer_pm = pm; + sta->mesh->peer_pm = pm; ieee80211_mps_sta_status_update(sta); } @@ -317,13 +317,13 @@ static void mps_set_sta_nonpeer_pm(struct sta_info *sta, else pm = NL80211_MESH_POWER_ACTIVE; - if (sta->nonpeer_pm == pm) + if (sta->mesh->nonpeer_pm == pm) return; mps_dbg(sta->sdata, "STA %pM sets non-peer mode to %d\n", sta->sta.addr, pm); - sta->nonpeer_pm = pm; + sta->mesh->nonpeer_pm = pm; ieee80211_mps_sta_status_update(sta); } @@ -552,7 +552,7 @@ void ieee80211_mpsp_trigger_process(u8 *qc, struct sta_info *sta, } else { if (eosp) clear_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); - else if (sta->local_pm != NL80211_MESH_POWER_ACTIVE) + else if (sta->mesh->local_pm != NL80211_MESH_POWER_ACTIVE) set_sta_flag(sta, WLAN_STA_MPSP_RECIPIENT); if (rspi && !test_and_set_sta_flag(sta, WLAN_STA_MPSP_OWNER)) @@ -577,9 +577,9 @@ void ieee80211_mps_frame_release(struct sta_info *sta, int ac, buffer_local = 0; bool has_buffered = false; - if (sta->plink_state == NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, - sta->llid); + sta->mesh->llid); if (has_buffered) mps_dbg(sta->sdata, "%pM indicates buffered frames\n", @@ -598,7 +598,7 @@ void ieee80211_mps_frame_release(struct sta_info *sta, if (!has_buffered && !buffer_local) return; - if (sta->plink_state == NL80211_PLINK_ESTAB) + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) mpsp_trigger_send(sta, has_buffered, !buffer_local); else mps_frame_deliver(sta, 1); diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 09625d6205c31..64bc22ad94965 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -127,14 +127,14 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, /* Timing offset calculation (see 13.13.2.2.2) */ t_t = le64_to_cpu(mgmt->u.beacon.timestamp); - sta->t_offset = t_t - t_r; + sta->mesh->t_offset = t_t - t_r; if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { - s64 t_clockdrift = sta->t_offset_setpoint - sta->t_offset; + s64 t_clockdrift = sta->mesh->t_offset_setpoint - sta->mesh->t_offset; msync_dbg(sdata, - "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n", - sta->sta.addr, (long long) sta->t_offset, - (long long) sta->t_offset_setpoint, + "STA %pM : t_offset=%lld, t_offset_setpoint=%lld, t_clockdrift=%lld\n", + sta->sta.addr, (long long) sta->mesh->t_offset, + (long long) sta->mesh->t_offset_setpoint, (long long) t_clockdrift); if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT || @@ -152,12 +152,12 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, ifmsh->sync_offset_clockdrift_max = t_clockdrift; spin_unlock_bh(&ifmsh->sync_offset_lock); } else { - sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN; + sta->mesh->t_offset_setpoint = sta->mesh->t_offset - TOFFSET_SET_MARGIN; set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); msync_dbg(sdata, - "STA %pM : offset was invalid, sta->t_offset=%lld\n", + "STA %pM : offset was invalid, t_offset=%lld\n", sta->sta.addr, - (long long) sta->t_offset); + (long long) sta->mesh->t_offset); } no_sync: diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d573a499750eb..9da7d2bc271ac 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -249,6 +249,9 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) if (sta->sta.txq[0]) kfree(to_txq_info(sta->sta.txq[0])); kfree(rcu_dereference_raw(sta->sta.rates)); +#ifdef CONFIG_MAC80211_MESH + kfree(sta->mesh); +#endif kfree(sta); } @@ -313,11 +316,16 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); #ifdef CONFIG_MAC80211_MESH - spin_lock_init(&sta->plink_lock); - if (ieee80211_vif_is_mesh(&sdata->vif) && - !sdata->u.mesh.user_mpm) - init_timer(&sta->plink_timer); - sta->nonpeer_pm = NL80211_MESH_POWER_ACTIVE; + if (ieee80211_vif_is_mesh(&sdata->vif)) { + sta->mesh = kzalloc(sizeof(*sta->mesh), gfp); + if (!sta->mesh) + goto free; + spin_lock_init(&sta->mesh->plink_lock); + if (ieee80211_vif_is_mesh(&sdata->vif) && + !sdata->u.mesh.user_mpm) + init_timer(&sta->mesh->plink_timer); + sta->mesh->nonpeer_pm = NL80211_MESH_POWER_ACTIVE; + } #endif memcpy(sta->addr, addr, ETH_ALEN); @@ -406,6 +414,9 @@ free_txq: if (sta->sta.txq[0]) kfree(to_txq_info(sta->sta.txq[0])); free: +#ifdef CONFIG_MAC80211_MESH + kfree(sta->mesh); +#endif kfree(sta); return NULL; } @@ -637,7 +648,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { ps = &sta->sdata->u.mesh.ps; /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */ - id = sta->plid % (IEEE80211_MAX_AID + 1); + id = sta->mesh->plid % (IEEE80211_MAX_AID + 1); #endif } else { return; @@ -1957,16 +1968,16 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) BIT(NL80211_STA_INFO_PEER_PM) | BIT(NL80211_STA_INFO_NONPEER_PM); - sinfo->llid = sta->llid; - sinfo->plid = sta->plid; - sinfo->plink_state = sta->plink_state; + sinfo->llid = sta->mesh->llid; + sinfo->plid = sta->mesh->plid; + sinfo->plink_state = sta->mesh->plink_state; if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { sinfo->filled |= BIT(NL80211_STA_INFO_T_OFFSET); - sinfo->t_offset = sta->t_offset; + sinfo->t_offset = sta->mesh->t_offset; } - sinfo->local_pm = sta->local_pm; - sinfo->peer_pm = sta->peer_pm; - sinfo->nonpeer_pm = sta->nonpeer_pm; + sinfo->local_pm = sta->mesh->local_pm; + sinfo->peer_pm = sta->mesh->peer_pm; + sinfo->nonpeer_pm = sta->mesh->nonpeer_pm; #endif } diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 4229849862638..9e568927c080e 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -269,6 +269,48 @@ struct ieee80211_fast_tx { struct rcu_head rcu_head; }; +/** + * struct mesh_sta - mesh STA information + * @plink_lock: serialize access to plink fields + * @llid: Local link ID + * @plid: Peer link ID + * @reason: Cancel reason on PLINK_HOLDING state + * @plink_retries: Retries in establishment + * @plink_state: peer link state + * @plink_timeout: timeout of peer link + * @plink_timer: peer link watch timer + * @t_offset: timing offset relative to this host + * @t_offset_setpoint: reference timing offset of this sta to be used when + * calculating clockdrift + * @local_pm: local link-specific power save mode + * @peer_pm: peer-specific power save mode towards local STA + * @nonpeer_pm: STA power save mode towards non-peer neighbors + * @processed_beacon: set to true after peer rates and capabilities are + * processed + */ +struct mesh_sta { + struct timer_list plink_timer; + + s64 t_offset; + s64 t_offset_setpoint; + + spinlock_t plink_lock; + u16 llid; + u16 plid; + u16 reason; + u8 plink_retries; + + bool processed_beacon; + + enum nl80211_plink_state plink_state; + u32 plink_timeout; + + /* mesh power save */ + enum nl80211_mesh_power_mode local_pm; + enum nl80211_mesh_power_mode peer_pm; + enum nl80211_mesh_power_mode nonpeer_pm; +}; + /** * struct sta_info - STA information * @@ -330,20 +372,7 @@ struct ieee80211_fast_tx { * @tid_seq: per-TID sequence numbers for sending to this STA * @ampdu_mlme: A-MPDU state machine state * @timer_to_tid: identity mapping to ID timers - * @plink_lock: serialize access to plink fields - * @llid: Local link ID - * @plid: Peer link ID - * @reason: Cancel reason on PLINK_HOLDING state - * @plink_retries: Retries in establishment - * @plink_state: peer link state - * @plink_timeout: timeout of peer link - * @plink_timer: peer link watch timer - * @t_offset: timing offset relative to this host - * @t_offset_setpoint: reference timing offset of this sta to be used when - * calculating clockdrift - * @local_pm: local link-specific power save mode - * @peer_pm: peer-specific power save mode towards local STA - * @nonpeer_pm: STA power save mode towards non-peer neighbors + * @mesh: mesh STA information * @debugfs: debug filesystem info * @dead: set to true when sta is unlinked * @uploaded: set to true when sta is uploaded to the driver @@ -371,8 +400,6 @@ struct ieee80211_fast_tx { * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID * entry for non-QoS frames * @fast_tx: TX fastpath information - * @processed_beacon: set to true after peer rates and capabilities are - * processed */ struct sta_info { /* General information, mostly static */ @@ -392,6 +419,10 @@ struct sta_info { struct ieee80211_fast_tx __rcu *fast_tx; +#ifdef CONFIG_MAC80211_MESH + struct mesh_sta *mesh; +#endif + struct work_struct drv_deliver_wk; u16 listen_interval; @@ -457,29 +488,6 @@ struct sta_info { struct sta_ampdu_mlme ampdu_mlme; u8 timer_to_tid[IEEE80211_NUM_TIDS]; -#ifdef CONFIG_MAC80211_MESH - /* - * Mesh peer link attributes, protected by plink_lock. - * TODO: move to a sub-structure that is referenced with pointer? - */ - spinlock_t plink_lock; - u16 llid; - u16 plid; - u16 reason; - u8 plink_retries; - enum nl80211_plink_state plink_state; - u32 plink_timeout; - struct timer_list plink_timer; - - s64 t_offset; - s64 t_offset_setpoint; - /* mesh power save */ - enum nl80211_mesh_power_mode local_pm; - enum nl80211_mesh_power_mode peer_pm; - enum nl80211_mesh_power_mode nonpeer_pm; - bool processed_beacon; -#endif - #ifdef CONFIG_MAC80211_DEBUGFS struct sta_info_debugfsdentries { struct dentry *dir; @@ -507,7 +515,7 @@ struct sta_info { static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta) { #ifdef CONFIG_MAC80211_MESH - return sta->plink_state; + return sta->mesh->plink_state; #endif return NL80211_PLINK_LISTEN; } -- GitLab From 1365770248c122dd155351e714b44fe77036292c Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2015 10:34:54 +0200 Subject: [PATCH 1084/7006] mac80211: move mesh STA parameters code to own function The code was always a bit awkward due to the 80-col restriction and got worse in the previous patch. Refactor it a bit into its own function to make it read nicer. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 117 +++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 56 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index c9f8f34ac7289..b145942a76243 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1019,6 +1019,65 @@ static int sta_apply_auth_flags(struct ieee80211_local *local, return 0; } +static void sta_apply_mesh_params(struct ieee80211_local *local, + struct sta_info *sta, + struct station_parameters *params) +{ +#ifdef CONFIG_MAC80211_MESH + struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 changed = 0; + + if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { + switch (params->plink_state) { + case NL80211_PLINK_ESTAB: + if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) + changed = mesh_plink_inc_estab_count(sdata); + sta->mesh->plink_state = params->plink_state; + + ieee80211_mps_sta_status_update(sta); + changed |= ieee80211_mps_set_sta_local_pm(sta, + sdata->u.mesh.mshcfg.power_mode); + break; + case NL80211_PLINK_LISTEN: + case NL80211_PLINK_BLOCKED: + case NL80211_PLINK_OPN_SNT: + case NL80211_PLINK_OPN_RCVD: + case NL80211_PLINK_CNF_RCVD: + case NL80211_PLINK_HOLDING: + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) + changed = mesh_plink_dec_estab_count(sdata); + sta->mesh->plink_state = params->plink_state; + + ieee80211_mps_sta_status_update(sta); + changed |= ieee80211_mps_set_sta_local_pm(sta, + NL80211_MESH_POWER_UNKNOWN); + break; + default: + /* nothing */ + break; + } + } + + switch (params->plink_action) { + case NL80211_PLINK_ACTION_NO_ACTION: + /* nothing */ + break; + case NL80211_PLINK_ACTION_OPEN: + changed |= mesh_plink_open(sta); + break; + case NL80211_PLINK_ACTION_BLOCK: + changed |= mesh_plink_block(sta); + break; + } + + if (params->local_pm) + changed |= ieee80211_mps_set_sta_local_pm(sta, + params->local_pm); + + ieee80211_mbss_info_change_notify(sdata, changed); +#endif +} + static int sta_apply_parameters(struct ieee80211_local *local, struct sta_info *sta, struct station_parameters *params) @@ -1143,62 +1202,8 @@ static int sta_apply_parameters(struct ieee80211_local *local, band, false); } - if (ieee80211_vif_is_mesh(&sdata->vif)) { -#ifdef CONFIG_MAC80211_MESH - u32 changed = 0; - - if (params->sta_modify_mask & STATION_PARAM_APPLY_PLINK_STATE) { - switch (params->plink_state) { - case NL80211_PLINK_ESTAB: - if (sta->mesh->plink_state != NL80211_PLINK_ESTAB) - changed = mesh_plink_inc_estab_count( - sdata); - sta->mesh->plink_state = params->plink_state; - - ieee80211_mps_sta_status_update(sta); - changed |= ieee80211_mps_set_sta_local_pm(sta, - sdata->u.mesh.mshcfg.power_mode); - break; - case NL80211_PLINK_LISTEN: - case NL80211_PLINK_BLOCKED: - case NL80211_PLINK_OPN_SNT: - case NL80211_PLINK_OPN_RCVD: - case NL80211_PLINK_CNF_RCVD: - case NL80211_PLINK_HOLDING: - if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) - changed = mesh_plink_dec_estab_count( - sdata); - sta->mesh->plink_state = params->plink_state; - - ieee80211_mps_sta_status_update(sta); - changed |= ieee80211_mps_set_sta_local_pm(sta, - NL80211_MESH_POWER_UNKNOWN); - break; - default: - /* nothing */ - break; - } - } - - switch (params->plink_action) { - case NL80211_PLINK_ACTION_NO_ACTION: - /* nothing */ - break; - case NL80211_PLINK_ACTION_OPEN: - changed |= mesh_plink_open(sta); - break; - case NL80211_PLINK_ACTION_BLOCK: - changed |= mesh_plink_block(sta); - break; - } - - if (params->local_pm) - changed |= - ieee80211_mps_set_sta_local_pm(sta, - params->local_pm); - ieee80211_mbss_info_change_notify(sdata, changed); -#endif - } + if (ieee80211_vif_is_mesh(&sdata->vif)) + sta_apply_mesh_params(local, sta, params); /* set the STA state after all sta info from usermode has been set */ if (test_sta_flag(sta, WLAN_STA_TDLS_PEER)) { -- GitLab From e996ec2a4ddb53164262990d33304c429709f687 Mon Sep 17 00:00:00 2001 From: Wojciech Dubowik Date: Wed, 10 Jun 2015 13:06:53 +0200 Subject: [PATCH 1085/7006] mac80211: avoid unnecessary beacon deref on CSA counter update The beacon struct is already available in many contexts that are also already in an RCU read-locked section. Avoid that by using the existing beacon struct pointer directly. Signed-off-by: Wojciech Dubowik [rewrite subject/add commit message] Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 87b9b4e27d225..7c6832f91dc38 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -3210,6 +3210,16 @@ static void ieee80211_set_csa(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); } +static u8 __ieee80211_csa_update_counter(struct beacon_data *beacon) +{ + beacon->csa_current_counter--; + + /* the counter should never reach 0 */ + WARN_ON_ONCE(!beacon->csa_current_counter); + + return beacon->csa_current_counter; +} + u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); @@ -3228,11 +3238,7 @@ u8 ieee80211_csa_update_counter(struct ieee80211_vif *vif) if (!beacon) goto unlock; - beacon->csa_current_counter--; - - /* the counter should never reach 0 */ - WARN_ON_ONCE(!beacon->csa_current_counter); - count = beacon->csa_current_counter; + count = __ieee80211_csa_update_counter(beacon); unlock: rcu_read_unlock(); @@ -3332,7 +3338,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (beacon) { if (beacon->csa_counter_offsets[0]) { if (!is_template) - ieee80211_csa_update_counter(vif); + __ieee80211_csa_update_counter(beacon); ieee80211_set_csa(sdata, beacon); } @@ -3378,7 +3384,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, if (beacon->csa_counter_offsets[0]) { if (!is_template) - ieee80211_csa_update_counter(vif); + __ieee80211_csa_update_counter(beacon); ieee80211_set_csa(sdata, beacon); } @@ -3408,7 +3414,7 @@ __ieee80211_beacon_get(struct ieee80211_hw *hw, * for now we leave it consistent with overall * mac80211's behavior. */ - ieee80211_csa_update_counter(vif); + __ieee80211_csa_update_counter(beacon); ieee80211_set_csa(sdata, beacon); } -- GitLab From 6513e98e05ccb8eca77adaf93beae44aa7bf4a45 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 10 Jun 2015 20:18:55 +0300 Subject: [PATCH 1086/7006] mac80211: allow passing NULL to ieee80211_vif_to_wdev() Simply return NULL in this case, instead of crashing. This can simplify callers that would otherwise have to check for this explicitly. Signed-off-by: Johannes Berg --- net/mac80211/util.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 7fb2c7bacc8cf..89e089c452c17 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -703,7 +703,12 @@ EXPORT_SYMBOL_GPL(wdev_to_ieee80211_vif); struct wireless_dev *ieee80211_vif_to_wdev(struct ieee80211_vif *vif) { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); + struct ieee80211_sub_if_data *sdata; + + if (!vif) + return NULL; + + sdata = vif_to_sdata(vif); if (!ieee80211_sdata_running(sdata) || !(sdata->flags & IEEE80211_SDATA_IN_DRIVER)) -- GitLab From 7584f88f9e30d36c2c1041831121f1cd3a194bf1 Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 10 Jun 2015 20:19:37 +0300 Subject: [PATCH 1087/7006] mac80211: clear local->in_reconfig on reconfig error If reconfiguration fails, local->in_reconfig is never cleaned, resulting in rx frames being dropped next time the device is started. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/util.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 89e089c452c17..e54596f956638 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1665,6 +1665,7 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local) local->resuming = false; local->suspended = false; local->started = false; + local->in_reconfig = false; /* scheduled scan clearly can't be running any more, but tell * cfg80211 and clear local state -- GitLab From b98fb44ffceeac717789e8f2fb3497e6b8c5c65b Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 10 Jun 2015 20:42:59 +0300 Subject: [PATCH 1088/7006] mac80211: define TDLS wider BW support bits Allow a device to specify support for the TDLS wider-bandwidth feature. Indicate this support during TDLS setup in the ext-capab IE and set an appropriate station flag when our TDLS peer supports it. This feature gives TDLS peers the ability to use a wider channel than the base width of the BSS. For instance VHT capable TDLS peers connected on a 20MHz channel can extend the channel to 80MHz, if regulatory considerations allow it. Do not cap the bandwidth of such stations by the current BSS channel width in mac80211. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++++ net/mac80211/cfg.c | 6 ++++++ net/mac80211/debugfs.c | 1 + net/mac80211/sta_info.h | 3 +++ net/mac80211/tdls.c | 18 +++++++++++++----- net/mac80211/vht.c | 8 ++++++-- 6 files changed, 33 insertions(+), 7 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4d3d2686f2787..8f61a230c4826 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1887,6 +1887,9 @@ struct ieee80211_txq { * @IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS: The HW supports scanning on all bands * in one command, mac80211 doesn't have to run separate scans per band. * + * @IEEE80211_HW_TDLS_WIDER_BW: The device/driver supports wider bandwidth + * than then BSS bandwidth for a TDLS link on the base channel. + * * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays */ enum ieee80211_hw_flags { @@ -1919,6 +1922,7 @@ enum ieee80211_hw_flags { IEEE80211_HW_CHANCTX_STA_CSA, IEEE80211_HW_SUPPORTS_CLONED_SKBS, IEEE80211_HW_SINGLE_SCAN_ON_ALL_BANDS, + IEEE80211_HW_TDLS_WIDER_BW, /* keep last, obviously */ NUM_IEEE80211_HW_FLAGS diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index b145942a76243..a32575bf05465 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -1155,6 +1155,12 @@ static int sta_apply_parameters(struct ieee80211_local *local, params->ext_capab[3] & WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) set_sta_flag(sta, WLAN_STA_TDLS_CHAN_SWITCH); + if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && + ieee80211_hw_check(&local->hw, TDLS_WIDER_BW) && + params->ext_capab_len >= 8 && + params->ext_capab[7] & WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED) + set_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW); + if (params->sta_modify_mask & STATION_PARAM_APPLY_UAPSD) { sta->sta.uapsd_queues = params->uapsd_queues; sta->sta.max_sp = params->max_sp; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 2c79d777f0e46..ced6bf3be8d6c 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -122,6 +122,7 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = { FLAG(CHANCTX_STA_CSA), FLAG(SUPPORTS_CLONED_SKBS), FLAG(SINGLE_SCAN_ON_ALL_BANDS), + FLAG(TDLS_WIDER_BW), /* keep last for the build bug below */ (void *)0x1 diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 9e568927c080e..b9c1aaaa01ffa 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -53,6 +53,8 @@ * @WLAN_STA_TDLS_CHAN_SWITCH: This TDLS peer supports TDLS channel-switching * @WLAN_STA_TDLS_OFF_CHANNEL: The local STA is currently off-channel with this * TDLS peer + * @WLAN_STA_TDLS_WIDER_BW: This TDLS peer supports working on a wider bw on + * the BSS base channel. * @WLAN_STA_UAPSD: Station requested unscheduled SP while driver was * keeping station in power-save mode, reply when the driver * unblocks the station. @@ -84,6 +86,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_TDLS_INITIATOR, WLAN_STA_TDLS_CHAN_SWITCH, WLAN_STA_TDLS_OFF_CHANNEL, + WLAN_STA_TDLS_WIDER_BW, WLAN_STA_UAPSD, WLAN_STA_SP, WLAN_STA_4ADDR_EVENT, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index ad31b2dab4f5a..fec1b336d03cd 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -35,20 +35,28 @@ void ieee80211_tdls_peer_del_work(struct work_struct *wk) mutex_unlock(&local->mtx); } -static void ieee80211_tdls_add_ext_capab(struct ieee80211_local *local, +static void ieee80211_tdls_add_ext_capab(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { - u8 *pos = (void *)skb_put(skb, 7); + struct ieee80211_local *local = sdata->local; bool chan_switch = local->hw.wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH; + bool wider_band = ieee80211_hw_check(&local->hw, TDLS_WIDER_BW); + enum ieee80211_band band = ieee80211_get_sdata_band(sdata); + struct ieee80211_supported_band *sband = local->hw.wiphy->bands[band]; + bool vht = sband && sband->vht_cap.vht_supported; + u8 *pos = (void *)skb_put(skb, 10); *pos++ = WLAN_EID_EXT_CAPABILITY; - *pos++ = 5; /* len */ + *pos++ = 8; /* len */ *pos++ = 0x0; *pos++ = 0x0; *pos++ = 0x0; *pos++ = chan_switch ? WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH : 0; *pos++ = WLAN_EXT_CAPA5_TDLS_ENABLED; + *pos++ = 0; + *pos++ = 0; + *pos++ = (vht && wider_band) ? WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED : 0; } static u8 @@ -320,7 +328,7 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, offset = noffset; } - ieee80211_tdls_add_ext_capab(local, skb); + ieee80211_tdls_add_ext_capab(sdata, skb); /* add the QoS element if we support it */ if (local->hw.queues >= IEEE80211_NUM_ACS && @@ -784,7 +792,7 @@ ieee80211_tdls_build_mgmt_packet_data(struct ieee80211_sub_if_data *sdata, max(sizeof(struct ieee80211_mgmt), sizeof(struct ieee80211_tdls_data)) + 50 + /* supported rates */ - 7 + /* ext capab */ + 10 + /* ext capab */ 26 + /* max(WMM-info, WMM-param) */ 2 + max(sizeof(struct ieee80211_ht_cap), sizeof(struct ieee80211_ht_operation)) + diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 80694d55db740..f05808d0d80f0 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -308,11 +308,15 @@ enum ieee80211_sta_rx_bandwidth ieee80211_sta_cur_vht_bw(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; enum ieee80211_sta_rx_bandwidth bw; + enum nl80211_chan_width bss_width = sdata->vif.bss_conf.chandef.width; - bw = ieee80211_chan_width_to_rx_bw(sdata->vif.bss_conf.chandef.width); - bw = min(bw, ieee80211_sta_cap_rx_bw(sta)); + bw = ieee80211_sta_cap_rx_bw(sta); bw = min(bw, sta->cur_max_bandwidth); + /* do not cap the BW of TDLS WIDER_BW peers by the bss */ + if (!test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) + bw = min(bw, ieee80211_chan_width_to_rx_bw(bss_width)); + return bw; } -- GitLab From 0fabfaafec3ae017fc7c82997035872ff385752f Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 10 Jun 2015 20:41:23 +0300 Subject: [PATCH 1089/7006] mac80211: upgrade BW of TDLS peers when possible Define a station chandef, to be used for wider-bw TDLS peers. When both peers support the feature, upgrade the channel bandwidth to the maximum allowed by both peers and regulatory. Currently widths up to 80MHz are supported in the 5GHz band. When a TDLS peer connects/disconnects recalculate the channel type of the current chanctx. Make the chanctx width calculation consider wider-bw TDLS peers and similarly fix the max_required_bw calculation for the chanctx min_def. Since the sta->bandwidth is calculated only later on, take bss_conf.chandef.width as the minimal width for station interface. Set the upgraded channel width in the VHT-operation set during TDLS setup. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/chan.c | 31 +++++++++-- net/mac80211/ieee80211_i.h | 3 ++ net/mac80211/sta_info.h | 4 ++ net/mac80211/tdls.c | 105 ++++++++++++++++++++++++++++++++++--- 4 files changed, 132 insertions(+), 11 deletions(-) diff --git a/net/mac80211/chan.c b/net/mac80211/chan.c index f01c18a3160e1..1d1b9b7bdefe7 100644 --- a/net/mac80211/chan.c +++ b/net/mac80211/chan.c @@ -190,7 +190,7 @@ ieee80211_find_reservation_chanctx(struct ieee80211_local *local, return NULL; } -static enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) +enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta) { switch (sta->bandwidth) { case IEEE80211_STA_RX_BW_20: @@ -264,9 +264,17 @@ ieee80211_get_chanctx_max_required_bw(struct ieee80211_local *local, case NL80211_IFTYPE_AP_VLAN: width = ieee80211_get_max_required_bw(sdata); break; + case NL80211_IFTYPE_STATION: + /* + * The ap's sta->bandwidth is not set yet at this + * point, so take the width from the chandef, but + * account also for TDLS peers + */ + width = max(vif->bss_conf.chandef.width, + ieee80211_get_max_required_bw(sdata)); + break; case NL80211_IFTYPE_P2P_DEVICE: continue; - case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_WDS: case NL80211_IFTYPE_MESH_POINT: @@ -554,12 +562,13 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local, kfree_rcu(ctx, rcu_head); } -static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, - struct ieee80211_chanctx *ctx) +void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx) { struct ieee80211_chanctx_conf *conf = &ctx->conf; struct ieee80211_sub_if_data *sdata; const struct cfg80211_chan_def *compat = NULL; + struct sta_info *sta; lockdep_assert_held(&local->chanctx_mtx); @@ -581,6 +590,20 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, if (WARN_ON_ONCE(!compat)) break; } + + /* TDLS peers can sometimes affect the chandef width */ + list_for_each_entry_rcu(sta, &local->sta_list, list) { + if (!sta->uploaded || + !test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW) || + !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || + !sta->tdls_chandef.chan) + continue; + + compat = cfg80211_chandef_compatible(&sta->tdls_chandef, + compat); + if (WARN_ON_ONCE(!compat)) + break; + } rcu_read_unlock(); if (!compat) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 68b091a0cae15..6376c673a9fec 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2033,6 +2033,9 @@ int ieee80211_check_combinations(struct ieee80211_sub_if_data *sdata, enum ieee80211_chanctx_mode chanmode, u8 radar_detect); int ieee80211_max_num_channels(struct ieee80211_local *local); +enum nl80211_chan_width ieee80211_get_sta_bw(struct ieee80211_sta *sta); +void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local, + struct ieee80211_chanctx *ctx); /* TDLS */ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index b9c1aaaa01ffa..0fbf3f3484466 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -403,6 +403,8 @@ struct mesh_sta { * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID * entry for non-QoS frames * @fast_tx: TX fastpath information + * @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to + * the BSS one. */ struct sta_info { /* General information, mostly static */ @@ -511,6 +513,8 @@ struct sta_info { u8 reserved_tid; + struct cfg80211_chan_def tdls_chandef; + /* keep last! */ struct ieee80211_sta sta; }; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index fec1b336d03cd..fb846cb047d6c 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -291,6 +291,60 @@ static void ieee80211_tdls_add_wmm_param_ie(struct ieee80211_sub_if_data *sdata, } } +static void +ieee80211_tdls_chandef_vht_upgrade(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + /* IEEE802.11ac-2013 Table E-4 */ + u16 centers_80mhz[] = { 5210, 5290, 5530, 5610, 5690, 5775 }; + struct cfg80211_chan_def uc = sta->tdls_chandef; + enum nl80211_chan_width max_width = ieee80211_get_sta_bw(&sta->sta); + int i; + + /* only support upgrading non-narrow channels up to 80Mhz */ + if (max_width == NL80211_CHAN_WIDTH_5 || + max_width == NL80211_CHAN_WIDTH_10) + return; + + if (max_width > NL80211_CHAN_WIDTH_80) + max_width = NL80211_CHAN_WIDTH_80; + + if (uc.width == max_width) + return; + /* + * Channel usage constrains in the IEEE802.11ac-2013 specification only + * allow expanding a 20MHz channel to 80MHz in a single way. In + * addition, there are no 40MHz allowed channels that are not part of + * the allowed 80MHz range in the 5GHz spectrum (the relevant one here). + */ + for (i = 0; i < ARRAY_SIZE(centers_80mhz); i++) + if (abs(uc.chan->center_freq - centers_80mhz[i]) <= 30) { + uc.center_freq1 = centers_80mhz[i]; + uc.width = NL80211_CHAN_WIDTH_80; + break; + } + + if (!uc.center_freq1) + return; + + /* proceed to downgrade the chandef until usable or the same */ + while (uc.width > max_width && + !cfg80211_reg_can_beacon(sdata->local->hw.wiphy, + &uc, sdata->wdev.iftype)) + ieee80211_chandef_downgrade(&uc); + + if (!cfg80211_chandef_identical(&uc, &sta->tdls_chandef)) { + tdls_dbg(sdata, "TDLS ch width upgraded %d -> %d\n", + sta->tdls_chandef.width, uc.width); + + /* + * the station is not yet authorized when BW upgrade is done, + * locking is not required + */ + sta->tdls_chandef = uc; + } +} + static void ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, const u8 *peer, @@ -358,15 +412,17 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, offset = noffset; } - rcu_read_lock(); + mutex_lock(&local->sta_mtx); /* we should have the peer STA if we're already responding */ if (action_code == WLAN_TDLS_SETUP_RESPONSE) { sta = sta_info_get(sdata, peer); if (WARN_ON_ONCE(!sta)) { - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); return; } + + sta->tdls_chandef = sdata->vif.bss_conf.chandef; } ieee80211_tdls_add_oper_classes(sdata, skb); @@ -456,9 +512,16 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, sizeof(struct ieee80211_vht_cap) + 2); ieee80211_ie_build_vht_cap(pos, &vht_cap, vht_cap.cap); + + /* + * if both peers support WIDER_BW, we can expand the chandef to + * a wider compatible one, up to 80MHz + */ + if (test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) + ieee80211_tdls_chandef_vht_upgrade(sdata, sta); } - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); /* add any remaining IEs */ if (extra_ies_len) { @@ -482,15 +545,17 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, enum ieee80211_band band = ieee80211_get_sdata_band(sdata); u8 *pos; - rcu_read_lock(); + mutex_lock(&local->sta_mtx); sta = sta_info_get(sdata, peer); ap_sta = sta_info_get(sdata, ifmgd->bssid); if (WARN_ON_ONCE(!sta || !ap_sta)) { - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); return; } + sta->tdls_chandef = sdata->vif.bss_conf.chandef; + /* add any custom IEs that go before the QoS IE */ if (extra_ies_len) { static const u8 before_qos[] = { @@ -538,12 +603,19 @@ ieee80211_tdls_add_setup_cfm_ies(struct ieee80211_sub_if_data *sdata, /* only include VHT-operation if not on the 2.4GHz band */ if (band != IEEE80211_BAND_2GHZ && sta->sta.vht_cap.vht_supported) { + /* + * if both peers support WIDER_BW, we can expand the chandef to + * a wider compatible one, up to 80MHz + */ + if (test_sta_flag(sta, WLAN_STA_TDLS_WIDER_BW)) + ieee80211_tdls_chandef_vht_upgrade(sdata, sta); + pos = skb_put(skb, 2 + sizeof(struct ieee80211_vht_operation)); ieee80211_ie_build_vht_oper(pos, &sta->sta.vht_cap, - &sdata->vif.bss_conf.chandef); + &sta->tdls_chandef); } - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); /* add any remaining IEs */ if (extra_ies_len) { @@ -1154,6 +1226,22 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, return ret; } +static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata) +{ + struct ieee80211_local *local = sdata->local; + struct ieee80211_chanctx_conf *conf; + struct ieee80211_chanctx *ctx; + + mutex_lock(&local->chanctx_mtx); + conf = rcu_dereference_protected(sdata->vif.chanctx_conf, + lockdep_is_held(&local->chanctx_mtx)); + if (conf) { + ctx = container_of(conf, struct ieee80211_chanctx, conf); + ieee80211_recalc_chanctx_chantype(local, ctx); + } + mutex_unlock(&local->chanctx_mtx); +} + int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper) { @@ -1190,6 +1278,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, break; } + iee80211_tdls_recalc_chanctx(sdata); + rcu_read_lock(); sta = sta_info_get(sdata, peer); if (!sta) { @@ -1221,6 +1311,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, ieee80211_flush_queues(local, sdata, false); ret = sta_info_destroy_addr(sdata, peer); + iee80211_tdls_recalc_chanctx(sdata); break; default: ret = -ENOTSUPP; -- GitLab From 703ee73a41a74210dde9050c6669053866b133a0 Mon Sep 17 00:00:00 2001 From: Alexis Green Date: Wed, 10 Jun 2015 11:02:09 -0700 Subject: [PATCH 1090/7006] mac80211: mesh: add missing case to PERR processing When the nexthop is unable to resolve its own nexthop it will send back a PERR with a zero target_sn. According to section 13.10.11.4.3 step b in the 2012 standard that perr should be forwarded and the associated mpath->sn should be incremented. Neither one of those was happening which is rather bad because the originator was not told that packets are black holing. Signed-off-by: Alexis Green CC: Jesse Jones Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index cd02810038cb4..d31d48f403f5b 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -736,9 +736,12 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata, if (mpath->flags & MESH_PATH_ACTIVE && ether_addr_equal(ta, sta->sta.addr) && (!(mpath->flags & MESH_PATH_SN_VALID) || - SN_GT(target_sn, mpath->sn))) { + SN_GT(target_sn, mpath->sn) || target_sn == 0)) { mpath->flags &= ~MESH_PATH_ACTIVE; - mpath->sn = target_sn; + if (target_sn != 0) + mpath->sn = target_sn; + else + mpath->sn += 1; spin_unlock_bh(&mpath->state_lock); if (!ifmsh->mshcfg.dot11MeshForwarding) goto endperr; -- GitLab From d82547106ff9dee43e6ee4f4b3d70b5314ae266f Mon Sep 17 00:00:00 2001 From: Jesse Jones Date: Fri, 12 Jun 2015 14:13:09 -0700 Subject: [PATCH 1091/7006] mac80211: mesh: don't invalidate SN on discovery failure The 2012 spec mentions that path SNs can be invalid when created (see section 13.10.8.4 table 13-9) but AFAICT never talks about invalidating SNs. Which makes sense: if we have figured out the path to a target at a certain SN then we want to remember that fact. Failing to do so can lead to routing loops because if we don't have a valid SN then we have no way of knowing whether an incoming path message leads to or away from the target. However currently when discovery fails we zero out mpath->flags which clears MESH_PATH_SN_VALID. This patch fixes that so that only the discovery relevant flags are cleared. Signed-off-by: Alexis Green Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index d31d48f403f5b..5ed38c5a998f9 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -1179,7 +1179,9 @@ void mesh_path_timer(unsigned long data) spin_unlock_bh(&mpath->state_lock); mesh_queue_preq(mpath, 0); } else { - mpath->flags = 0; + mpath->flags &= ~(MESH_PATH_RESOLVING | + MESH_PATH_RESOLVED | + MESH_PATH_REQ_QUEUED); mpath->exp_time = jiffies; spin_unlock_bh(&mpath->state_lock); if (!mpath->is_gate && mesh_gate_num(sdata) > 0) { -- GitLab From d8f0300a7aca5cd9208112104c64d894ad82da1f Mon Sep 17 00:00:00 2001 From: Jesse Jones Date: Fri, 12 Jun 2015 15:38:07 -0700 Subject: [PATCH 1092/7006] mac80211: mac80211: Check SN for deactivated mpaths When processing a PREQ or PREP it's critical to use the incoming SN. If that is improperly done routing loops and other types of badness can happen. But the code was always processing path messages for deactivated paths. This path fixes that so that if we have a valid SN then we use it to verify that it is a message we can accept. For reference the relevant section of the standard is 13.10.8.4 which doesn't address the deactivated path case at all. I also included a special case for when our peer reboots or restarts networking. This is an important case because without it there can be a very long delay before we accept path messages from that peer. It's also a simple case and intimately associated with processing messages for deactivated paths so I used one patch instead of two. Signed-off-by: Alexis Green Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 5ed38c5a998f9..f053213e5adbf 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -79,6 +79,12 @@ static inline u16 u16_field_get(const u8 *preq_elem, int offset, bool ae) #define MSEC_TO_TU(x) (x*1000/1024) #define SN_GT(x, y) ((s32)(y - x) < 0) #define SN_LT(x, y) ((s32)(x - y) < 0) +#define MAX_SANE_SN_DELTA 32 + +static inline u32 SN_DELTA(u32 x, u32 y) +{ + return x >= y ? x - y : y - x; +} #define net_traversal_jiffies(s) \ msecs_to_jiffies(s->u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime) @@ -441,6 +447,26 @@ static u32 hwmp_route_info_get(struct ieee80211_sub_if_data *sdata, process = false; fresh_info = false; } + } else if (!(mpath->flags & MESH_PATH_ACTIVE)) { + bool have_sn, newer_sn, bounced; + + have_sn = mpath->flags & MESH_PATH_SN_VALID; + newer_sn = have_sn && SN_GT(orig_sn, mpath->sn); + bounced = have_sn && + (SN_DELTA(orig_sn, mpath->sn) > + MAX_SANE_SN_DELTA); + + if (!have_sn || newer_sn) { + /* if SN is newer than what we had + * then we can take it */; + } else if (bounced) { + /* if SN is way different than what + * we had then assume the other side + * rebooted or restarted */; + } else { + process = false; + fresh_info = false; + } } } else { mpath = mesh_path_add(sdata, orig_addr); -- GitLab From 3633ebebab2bbe88124388b7620442315c968e8f Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Sat, 13 Jun 2015 10:16:31 -0400 Subject: [PATCH 1093/7006] mac80211: enable assoc check for mesh interfaces We already set a station to be associated when peering completes, both in user space and in the kernel. Thus we should always have an associated sta before sending data frames to that station. Failure to check assoc state can cause crashes in the lower-level driver due to transmitting unicast data frames before driver sta structures (e.g. ampdu state in ath9k) are initialized. This occurred when forwarding in the presence of fixed mesh paths: frames were transmitted to stations with whom we hadn't yet completed peering. Cc: stable@vger.kernel.org Reported-by: Alexis Green Tested-by: Jesse Jones Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 7c6832f91dc38..c0d6af809640f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -311,9 +311,6 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (tx->sdata->vif.type == NL80211_IFTYPE_WDS) return TX_CONTINUE; - if (tx->sdata->vif.type == NL80211_IFTYPE_MESH_POINT) - return TX_CONTINUE; - if (tx->flags & IEEE80211_TX_PS_BUFFERED) return TX_CONTINUE; -- GitLab From d51c2ea3704be07f030c78d57641d6b972e301ee Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sun, 14 Jun 2015 16:53:46 +0300 Subject: [PATCH 1094/7006] mac80211: TDLS: correctly configure SMPS state The IEEE802.11-2012 specification is vague regarding SMPS operation during TDLS. It does not define a clear way to transition between SMPS states. To avoid interop issues, set SMPS to off when TDLS peers are connected. Accomplish this by extending the definition of the AUTOMATIC state. If the driver forces a state other than OFF, disconnect all TDLS peers. While at it, avoid changing the SMPS state of the peer STA. We have no way to control it, so try and behave correctly towards it. Move the TDLS peer-teardown function to where the rest of the TDLS code resides. Signed-off-by: Arik Nemtsov Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 21 ++++++++++++++++++--- net/mac80211/ieee80211_i.h | 1 + net/mac80211/mlme.c | 18 ------------------ net/mac80211/tdls.c | 36 ++++++++++++++++++++++++++++++++---- 4 files changed, 51 insertions(+), 25 deletions(-) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index a32575bf05465..5789d83535059 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2368,6 +2368,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, const u8 *ap; enum ieee80211_smps_mode old_req; int err; + struct sta_info *sta; + bool tdls_peer_found = false; lockdep_assert_held(&sdata->wdev.mtx); @@ -2392,11 +2394,22 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, ap = sdata->u.mgd.associated->bssid; + rcu_read_lock(); + list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { + if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded || + !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) + continue; + + tdls_peer_found = true; + break; + } + rcu_read_unlock(); + if (smps_mode == IEEE80211_SMPS_AUTOMATIC) { - if (sdata->u.mgd.powersave) - smps_mode = IEEE80211_SMPS_DYNAMIC; - else + if (tdls_peer_found || !sdata->u.mgd.powersave) smps_mode = IEEE80211_SMPS_OFF; + else + smps_mode = IEEE80211_SMPS_DYNAMIC; } /* send SM PS frame to AP */ @@ -2404,6 +2417,8 @@ int __ieee80211_request_smps_mgd(struct ieee80211_sub_if_data *sdata, ap, ap); if (err) sdata->u.mgd.req_smps = old_req; + else if (smps_mode != IEEE80211_SMPS_OFF && tdls_peer_found) + ieee80211_teardown_tdls_peers(sdata); return err; } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 6376c673a9fec..dd131e9b41d7e 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -2054,6 +2054,7 @@ void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, const u8 *addr); void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata); extern const struct ethtool_ops ieee80211_ethtool_ops; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index ae5d6c48272d1..6332ff705ec38 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1096,24 +1096,6 @@ static void ieee80211_chswitch_timer(unsigned long data) ieee80211_queue_work(&sdata->local->hw, &sdata->u.mgd.chswitch_work); } -static void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata) -{ - struct sta_info *sta; - u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; - - rcu_read_lock(); - list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { - if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded || - !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) - continue; - - ieee80211_tdls_oper_request(&sdata->vif, sta->sta.addr, - NL80211_TDLS_TEARDOWN, reason, - GFP_ATOMIC); - } - rcu_read_unlock(); -} - static void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata, u64 timestamp, u32 device_timestamp, diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index fb846cb047d6c..8536789da17d2 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -4,6 +4,7 @@ * Copyright 2006-2010 Johannes Berg * Copyright 2014, Intel Corporation * Copyright 2014 Intel Mobile Communications GmbH + * Copyright 2015 Intel Deutschland GmbH * * This file is GPLv2 as found in COPYING. */ @@ -448,10 +449,6 @@ ieee80211_tdls_add_setup_start_ies(struct ieee80211_sub_if_data *sdata, ieee80211_ie_build_ht_cap(pos, &ht_cap, ht_cap.cap); } else if (action_code == WLAN_TDLS_SETUP_RESPONSE && ht_cap.ht_supported && sta->sta.ht_cap.ht_supported) { - /* disable SMPS in TDLS responder */ - sta->sta.ht_cap.cap |= WLAN_HT_CAP_SM_PS_DISABLED - << IEEE80211_HT_CAP_SM_PS_SHIFT; - /* the peer caps are already intersected with our own */ memcpy(&ht_cap, &sta->sta.ht_cap, sizeof(ht_cap)); @@ -1063,8 +1060,17 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev, { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = sdata->local; + enum ieee80211_smps_mode smps_mode = sdata->u.mgd.driver_smps_mode; int ret; + /* don't support setup with forced SMPS mode that's not off */ + if (smps_mode != IEEE80211_SMPS_AUTOMATIC && + smps_mode != IEEE80211_SMPS_OFF) { + tdls_dbg(sdata, "Aborting TDLS setup due to SMPS mode %d\n", + smps_mode); + return -ENOTSUPP; + } + mutex_lock(&local->mtx); /* we don't support concurrent TDLS peer setups */ @@ -1323,6 +1329,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, eth_zero_addr(sdata->u.mgd.tdls_peer); } + if (ret == 0) + ieee80211_queue_work(&sdata->local->hw, + &sdata->u.mgd.request_smps_work); + mutex_unlock(&local->mtx); return ret; } @@ -1819,3 +1829,21 @@ void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, return; } } + +void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata) +{ + struct sta_info *sta; + u16 reason = WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED; + + rcu_read_lock(); + list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { + if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded || + !test_sta_flag(sta, WLAN_STA_AUTHORIZED)) + continue; + + ieee80211_tdls_oper_request(&sdata->vif, sta->sta.addr, + NL80211_TDLS_TEARDOWN, reason, + GFP_ATOMIC); + } + rcu_read_unlock(); +} -- GitLab From 932e628da2fe9be759e19b14e3e5bf1e0e6f0984 Mon Sep 17 00:00:00 2001 From: Chun-Yeow Yeoh Date: Mon, 15 Jun 2015 11:58:53 +0800 Subject: [PATCH 1095/7006] mac80211: mesh process the target only subfield for mesh hwmp This patch does the following: - Remove unnecessary flags field used by PERR element - Use the per target flags defined in - Process the target only subfield based on case E2 of IEEE802.11-2012 13.10.9.3 Signed-off-by: Chun-Yeow Yeoh Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index f053213e5adbf..be635341c8028 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -19,15 +19,6 @@ #define MAX_PREQ_QUEUE_LEN 64 -/* Destination only */ -#define MP_F_DO 0x1 -/* Reply and forward */ -#define MP_F_RF 0x2 -/* Unknown Sequence Number */ -#define MP_F_USN 0x01 -/* Reason code Present */ -#define MP_F_RCODE 0x02 - static void mesh_queue_preq(struct mesh_path *, u8); static inline u32 u32_field_get(const u8 *preq_elem, int offset, bool ae) @@ -285,15 +276,10 @@ int mesh_path_error_tx(struct ieee80211_sub_if_data *sdata, *pos++ = ttl; /* number of destinations */ *pos++ = 1; - /* - * flags bit, bit 1 is unset if we know the sequence number and - * bit 2 is set if we have a reason code + /* Flags field has AE bit only as defined in + * sec 8.4.2.117 IEEE802.11-2012 */ *pos = 0; - if (!target_sn) - *pos |= MP_F_USN; - if (target_rcode) - *pos |= MP_F_RCODE; pos++; memcpy(pos, target, ETH_ALEN); pos += ETH_ALEN; @@ -596,15 +582,13 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, SN_LT(mpath->sn, target_sn)) { mpath->sn = target_sn; mpath->flags |= MESH_PATH_SN_VALID; - } else if ((!(target_flags & MP_F_DO)) && + } else if ((!(target_flags & IEEE80211_PREQ_TO_FLAG)) && (mpath->flags & MESH_PATH_ACTIVE)) { reply = true; target_metric = mpath->metric; target_sn = mpath->sn; - if (target_flags & MP_F_RF) - target_flags |= MP_F_DO; - else - forward = false; + /* Case E2 of sec 13.10.9.3 IEEE 802.11-2012*/ + target_flags |= IEEE80211_PREQ_TO_FLAG; } } rcu_read_unlock(); @@ -1003,7 +987,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; struct mesh_preq_queue *preq_node; struct mesh_path *mpath; - u8 ttl, target_flags; + u8 ttl, target_flags = 0; const u8 *da; u32 lifetime; @@ -1062,9 +1046,9 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata) } if (preq_node->flags & PREQ_Q_F_REFRESH) - target_flags = MP_F_DO; + target_flags |= IEEE80211_PREQ_TO_FLAG; else - target_flags = MP_F_RF; + target_flags &= ~IEEE80211_PREQ_TO_FLAG; spin_unlock_bh(&mpath->state_lock); da = (mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; -- GitLab From a3ebb4e1b76346156e8e7233c262ce24e3a86a24 Mon Sep 17 00:00:00 2001 From: Krishna Chaitanya Date: Fri, 12 Jun 2015 02:34:52 +0530 Subject: [PATCH 1096/7006] mac80211: minstrel_ht: handle peers in dynamic SMPS In case of Dynamic SMPS enable RTS/CTS for all rates. Signed-off-by: Chaitanya T K [change comment] Signed-off-by: Johannes Berg --- net/mac80211/rc80211_minstrel_ht.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 543b672335353..3928dbd24e257 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -867,7 +867,13 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, else idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; - if (offset > 0) { + /* enable RTS/CTS if needed: + * - if station is in dynamic SMPS (and streams > 1) + * - for fallback rates, to increase chances of getting through + */ + if (offset > 0 && + (mi->sta->smps_mode == IEEE80211_SMPS_DYNAMIC && + group->streams > 1)) { ratetbl->rate[offset].count = ratetbl->rate[offset].count_rts; flags |= IEEE80211_TX_RC_USE_RTS_CTS; } -- GitLab From 33c2f538d8080845e11af500993cc61ad30934e2 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 17 Jun 2015 13:07:14 +0200 Subject: [PATCH 1097/7006] mac80211_hwsim: support wider TDLS bandwidth There's no reason not to support this, allow it to test those code paths. Signed-off-by: Johannes Berg --- drivers/net/wireless/mac80211_hwsim.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 99e873dc86847..08022ded63071 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -2399,6 +2399,7 @@ static int mac80211_hwsim_new_radio(struct genl_info *info, ieee80211_hw_set(hw, AMPDU_AGGREGATION); ieee80211_hw_set(hw, MFP_CAPABLE); ieee80211_hw_set(hw, SIGNAL_DBM); + ieee80211_hw_set(hw, TDLS_WIDER_BW); if (rctbl) ieee80211_hw_set(hw, SUPPORTS_RC_TABLE); -- GitLab From f9a060f4b2003eb7350762e60dfc576447e44bad Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 12 Jun 2015 14:55:34 +0200 Subject: [PATCH 1098/7006] mac80211: add pointer for driver use to key Some drivers may need to store data per key, for example for PN validation. Allow this by adding a pointer to the struct that the driver can assign. Signed-off-by: Johannes Berg --- include/net/mac80211.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 8f61a230c4826..484cc14fb9474 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -1492,8 +1492,10 @@ enum ieee80211_key_flags { * - Temporal Authenticator Rx MIC Key (64 bits) * @icv_len: The ICV length for this key type * @iv_len: The IV length for this key type + * @drv_priv: pointer for driver use */ struct ieee80211_key_conf { + void *drv_priv; atomic64_t tx_pn; u32 cipher; u8 icv_len; -- GitLab From a76d5e0a2311ad6b5a8bfa92d3d627194c8c389a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Thu, 18 Jun 2015 16:20:08 +0200 Subject: [PATCH 1099/7006] mac80211: mesh: move fail_avg into mesh struct This value is only used in mesh, so move it into the new mesh sub-struct of the station info. Signed-off-by: Johannes Berg --- net/mac80211/mesh_hwmp.c | 9 +++++---- net/mac80211/sta_info.h | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index be635341c8028..d80e0a4c16cf9 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -308,8 +308,9 @@ void ieee80211s_update_metric(struct ieee80211_local *local, failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); /* moving average, scaled to 100 */ - sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed); - if (sta->fail_avg > 95) + sta->mesh->fail_avg = + ((80 * sta->mesh->fail_avg + 5) / 100 + 20 * failed); + if (sta->mesh->fail_avg > 95) mesh_plink_broken(sta); } @@ -325,7 +326,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, u32 tx_time, estimated_retx; u64 result; - if (sta->fail_avg >= 100) + if (sta->mesh->fail_avg >= 100) return MAX_METRIC; sta_set_rate_info_tx(sta, &sta->last_tx_rate, &rinfo); @@ -333,7 +334,7 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (WARN_ON(!rate)) return MAX_METRIC; - err = (sta->fail_avg << ARITH_SHIFT) / 100; + err = (sta->mesh->fail_avg << ARITH_SHIFT) / 100; /* bitrate is in units of 100 Kbps, while we need rate in units of * 1Mbps. This will be corrected on tx_time computation. diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 0fbf3f3484466..6dcb33484eac4 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -290,6 +290,7 @@ struct ieee80211_fast_tx { * @nonpeer_pm: STA power save mode towards non-peer neighbors * @processed_beacon: set to true after peer rates and capabilities are * processed + * @fail_avg: moving percentage of failed MSDUs */ struct mesh_sta { struct timer_list plink_timer; @@ -312,6 +313,9 @@ struct mesh_sta { enum nl80211_mesh_power_mode local_pm; enum nl80211_mesh_power_mode peer_pm; enum nl80211_mesh_power_mode nonpeer_pm; + + /* moving percentage of failed MSDUs */ + unsigned int fail_avg; }; /** @@ -369,7 +373,6 @@ struct mesh_sta { * @tx_filtered_count: number of frames the hardware filtered for this STA * @tx_retry_failed: number of frames that failed retry * @tx_retry_count: total number of retries for frames to this STA - * @fail_avg: moving percentage of failed MSDUs * @tx_packets: number of RX/TX MSDUs * @tx_bytes: number of bytes transmitted to this STA * @tid_seq: per-TID sequence numbers for sending to this STA @@ -470,8 +473,6 @@ struct sta_info { /* Updated from TX status path only, no locking requirements */ unsigned long tx_filtered_count; unsigned long tx_retry_failed, tx_retry_count; - /* moving percentage of failed MSDUs */ - unsigned int fail_avg; /* Updated from TX path only, no locking requirements */ u64 tx_packets[IEEE80211_NUM_ACS]; -- GitLab From 69f132236827ce7d4531846cc2b9447dd5620aff Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 26 Jun 2015 09:21:01 +0200 Subject: [PATCH 1100/7006] mac80211: shrink struct ieee80211_fragment_entry Most of the fields in this struct use too wide types, change that to shrink the struct from 64 to 48 bytes (on 64-bit.) This results in a total saving of 64 bytes for each interface. Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index dd131e9b41d7e..52930e91c0fd6 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -84,13 +84,13 @@ struct ieee80211_local; #define IEEE80211_DEAUTH_FRAME_LEN (24 /* hdr */ + 2 /* reason */) struct ieee80211_fragment_entry { - unsigned long first_frag_time; - unsigned int seq; - unsigned int rx_queue; - unsigned int last_frag; - unsigned int extra_len; struct sk_buff_head skb_list; - int ccmp; /* Whether fragments were encrypted with CCMP */ + unsigned long first_frag_time; + u16 seq; + u16 extra_len; + u16 last_frag; + u8 rx_queue; + bool ccmp; /* Whether fragments were encrypted with CCMP */ u8 last_pn[6]; /* PN of the last fragment if CCMP was used */ }; -- GitLab From 33d8783c58427683b533664f67f8c4378ed64495 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 17:47:05 +0200 Subject: [PATCH 1101/7006] cfg80211: allow mgmt_frame_register callback to sleep This callback is currently not allowed to sleep, which makes it more difficult to implement proper driver methods in mac80211 than it has to be. Instead of doing asynchronous work here in mac80211, make it possible for the callback to sleep by doing some asynchronous work in cfg80211. This also enables improvements to other drivers, like ath6kl, that would like to sleep in this callback. While at it, also fix the code to call the driver on the implicit unregistration when an interface is removed, and do that also when a P2P-Device wdev is destroyed (otherwise we leak the structs.) Signed-off-by: Johannes Berg --- include/net/cfg80211.h | 3 +- net/wireless/core.c | 5 +++ net/wireless/core.h | 5 +++ net/wireless/mlme.c | 75 ++++++++++++++++++++++++++++++++--------- net/wireless/rdev-ops.h | 2 ++ 5 files changed, 73 insertions(+), 17 deletions(-) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index a741678f24a26..9a529c48f6caa 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -2369,8 +2369,7 @@ struct cfg80211_qos_map { * method returns 0.) * * @mgmt_frame_register: Notify driver that a management frame type was - * registered. Note that this callback may not sleep, and cannot run - * concurrently with itself. + * registered. The callback is allowed to sleep. * * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device. * Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may diff --git a/net/wireless/core.c b/net/wireless/core.c index 2a0bbd22854bd..3893409dee95b 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -407,6 +407,9 @@ use_default_name: INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results); + INIT_LIST_HEAD(&rdev->mlme_unreg); + spin_lock_init(&rdev->mlme_unreg_lock); + INIT_WORK(&rdev->mlme_unreg_wk, cfg80211_mlme_unreg_wk); INIT_DELAYED_WORK(&rdev->dfs_update_channels_wk, cfg80211_dfs_channels_update_work); #ifdef CONFIG_CFG80211_WEXT @@ -802,6 +805,7 @@ void wiphy_unregister(struct wiphy *wiphy) cancel_delayed_work_sync(&rdev->dfs_update_channels_wk); flush_work(&rdev->destroy_work); flush_work(&rdev->sched_scan_stop_wk); + flush_work(&rdev->mlme_unreg_wk); #ifdef CONFIG_PM if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup) @@ -855,6 +859,7 @@ void cfg80211_unregister_wdev(struct wireless_dev *wdev) switch (wdev->iftype) { case NL80211_IFTYPE_P2P_DEVICE: + cfg80211_mlme_purge_registrations(wdev); cfg80211_stop_p2p_device(rdev, wdev); break; default: diff --git a/net/wireless/core.h b/net/wireless/core.h index 311eef26bf88b..b9d5bc8c148d3 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -59,6 +59,10 @@ struct cfg80211_registered_device { struct list_head beacon_registrations; spinlock_t beacon_registrations_lock; + struct list_head mlme_unreg; + spinlock_t mlme_unreg_lock; + struct work_struct mlme_unreg_wk; + /* protected by RTNL only */ int num_running_ifaces; int num_running_monitor_ifaces; @@ -348,6 +352,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, u16 frame_type, const u8 *match_data, int match_len); +void cfg80211_mlme_unreg_wk(struct work_struct *wk); void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index 7aae329e2b4e4..fb44fa3bf4efa 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -2,6 +2,7 @@ * cfg80211 MLME SAP interface * * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2015 Intel Deutschland GmbH */ #include @@ -389,6 +390,7 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, struct cfg80211_mgmt_registration { struct list_head list; + struct wireless_dev *wdev; u32 nlportid; @@ -399,6 +401,46 @@ struct cfg80211_mgmt_registration { u8 match[]; }; +static void +cfg80211_process_mlme_unregistrations(struct cfg80211_registered_device *rdev) +{ + struct cfg80211_mgmt_registration *reg; + + ASSERT_RTNL(); + + spin_lock_bh(&rdev->mlme_unreg_lock); + while ((reg = list_first_entry_or_null(&rdev->mlme_unreg, + struct cfg80211_mgmt_registration, + list))) { + list_del(®->list); + spin_unlock_bh(&rdev->mlme_unreg_lock); + + if (rdev->ops->mgmt_frame_register) { + u16 frame_type = le16_to_cpu(reg->frame_type); + + rdev_mgmt_frame_register(rdev, reg->wdev, + frame_type, false); + } + + kfree(reg); + + spin_lock_bh(&rdev->mlme_unreg_lock); + } + spin_unlock_bh(&rdev->mlme_unreg_lock); +} + +void cfg80211_mlme_unreg_wk(struct work_struct *wk) +{ + struct cfg80211_registered_device *rdev; + + rdev = container_of(wk, struct cfg80211_registered_device, + mlme_unreg_wk); + + rtnl_lock(); + cfg80211_process_mlme_unregistrations(rdev); + rtnl_unlock(); +} + int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, u16 frame_type, const u8 *match_data, int match_len) @@ -449,11 +491,18 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_portid, nreg->match_len = match_len; nreg->nlportid = snd_portid; nreg->frame_type = cpu_to_le16(frame_type); + nreg->wdev = wdev; list_add(&nreg->list, &wdev->mgmt_registrations); + spin_unlock_bh(&wdev->mgmt_registrations_lock); + + /* process all unregistrations to avoid driver confusion */ + cfg80211_process_mlme_unregistrations(rdev); if (rdev->ops->mgmt_frame_register) rdev_mgmt_frame_register(rdev, wdev, frame_type, true); + return 0; + out: spin_unlock_bh(&wdev->mgmt_registrations_lock); @@ -472,15 +521,12 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) if (reg->nlportid != nlportid) continue; - if (rdev->ops->mgmt_frame_register) { - u16 frame_type = le16_to_cpu(reg->frame_type); - - rdev_mgmt_frame_register(rdev, wdev, - frame_type, false); - } - list_del(®->list); - kfree(reg); + spin_lock(&rdev->mlme_unreg_lock); + list_add_tail(®->list, &rdev->mlme_unreg); + spin_unlock(&rdev->mlme_unreg_lock); + + schedule_work(&rdev->mlme_unreg_wk); } spin_unlock_bh(&wdev->mgmt_registrations_lock); @@ -496,16 +542,15 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlportid) void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) { - struct cfg80211_mgmt_registration *reg, *tmp; + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); spin_lock_bh(&wdev->mgmt_registrations_lock); - - list_for_each_entry_safe(reg, tmp, &wdev->mgmt_registrations, list) { - list_del(®->list); - kfree(reg); - } - + spin_lock(&rdev->mlme_unreg_lock); + list_splice_tail_init(&wdev->mgmt_registrations, &rdev->mlme_unreg); + spin_unlock(&rdev->mlme_unreg_lock); spin_unlock_bh(&wdev->mgmt_registrations_lock); + + cfg80211_process_mlme_unregistrations(rdev); } int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, diff --git a/net/wireless/rdev-ops.h b/net/wireless/rdev-ops.h index c6e83a7468c0c..c23516d0f8079 100644 --- a/net/wireless/rdev-ops.h +++ b/net/wireless/rdev-ops.h @@ -733,6 +733,8 @@ static inline void rdev_mgmt_frame_register(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, u16 frame_type, bool reg) { + might_sleep(); + trace_rdev_mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); rdev->ops->mgmt_frame_register(&rdev->wiphy, wdev , frame_type, reg); trace_rdev_return_void(&rdev->wiphy); -- GitLab From 841b351cf98e0b4ef25f6459d35251e63c0a7a49 Mon Sep 17 00:00:00 2001 From: John Linville Date: Wed, 24 Jun 2015 11:42:25 -0400 Subject: [PATCH 1102/7006] wireless: remove superfluous if statement in regulatory code Commit eeca9fce1d71 ('cfg80211: Schedule timeout for all CRDA calls') left behind a superfluous check after it removed some earlier code. In reg_process_hint, the test of "treatment == REG_REQ_IGNORE || treatment == REG_REQ_ALREADY_SET" is superfluous because the code in the if-then branch is identical to the code after the if statement. Coverity CID #1295939 I also removed the unnecessary assignment of treatment in this case, and added a comment reminding any future patch authors to ensure that treatment is properly assigned before it is used after the switch. Signed-off-by: John W. Linville Signed-off-by: Johannes Berg --- net/wireless/reg.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index d359e0610198c..62d8ea42dbfb0 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2079,10 +2079,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) reg_process_hint_core(reg_request); return; case NL80211_REGDOM_SET_BY_USER: - treatment = reg_process_hint_user(reg_request); - if (treatment == REG_REQ_IGNORE || - treatment == REG_REQ_ALREADY_SET) - return; + reg_process_hint_user(reg_request); return; case NL80211_REGDOM_SET_BY_DRIVER: if (!wiphy) @@ -2099,7 +2096,9 @@ static void reg_process_hint(struct regulatory_request *reg_request) goto out_free; } - /* This is required so that the orig_* parameters are saved */ + /* This is required so that the orig_* parameters are saved. + * NOTE: treatment must be set for any case that reaches here! + */ if (treatment == REG_REQ_ALREADY_SET && wiphy && wiphy->regulatory_flags & REGULATORY_STRICT_REG) { wiphy_update_regulatory(wiphy, reg_request->initiator); -- GitLab From ccc6bb96ff058ad737fb8236e15aeaa56e822296 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 23 Jun 2015 11:50:52 +0200 Subject: [PATCH 1103/7006] mac80211: account TX MSDUs properly with segmentation offload If an SKB will be segmented by the driver, count it for multiple MSDUs that are being transmitted rather than just a single. Signed-off-by: Johannes Berg --- net/mac80211/tx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c0d6af809640f..d14f3618069f0 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -2771,7 +2771,11 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, sdata->sequence_number += 0x10; } - sta->tx_msdu[tid]++; + if (skb_shinfo(skb)->gso_size) + sta->tx_msdu[tid] += + DIV_ROUND_UP(skb->len, skb_shinfo(skb)->gso_size); + else + sta->tx_msdu[tid]++; info->hw_queue = sdata->vif.hw_queue[skb_get_queue_mapping(skb)]; -- GitLab From 322cd406da0b102dda9c0eec46181458a3667dbb Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 8 Jul 2015 15:41:43 +0300 Subject: [PATCH 1104/7006] mac80211: Add support for declaring MU-MIMO capability Add support for declaring MU-MIMO beamformee capability for relevant hardware. When sending association request, the capability is included if both hardware and the AP support it, and no other virtual interface is using it. This is in order to avoid multiple interfaces using MU-MIMO in parallel which might lead to contradictions in the group-id mechanism. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 2 ++ net/mac80211/mlme.c | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 52930e91c0fd6..90580e903926b 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -721,6 +721,7 @@ struct ieee80211_if_mesh { * back to wireless media and to the local net stack. * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume. * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver + * @IEEE80211_SDATA_MU_MIMO_OWNER: indicates interface owns MU-MIMO capability */ enum ieee80211_sub_if_data_flags { IEEE80211_SDATA_ALLMULTI = BIT(0), @@ -728,6 +729,7 @@ enum ieee80211_sub_if_data_flags { IEEE80211_SDATA_DONT_BRIDGE_PACKETS = BIT(3), IEEE80211_SDATA_DISCONNECT_RESUME = BIT(4), IEEE80211_SDATA_IN_DRIVER = BIT(5), + IEEE80211_SDATA_MU_MIMO_OWNER = BIT(6), }; /** diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 6332ff705ec38..705ef1d040edf 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -6,6 +6,7 @@ * Copyright 2006-2007 Jiri Benc * Copyright 2007, Michael Wu * Copyright 2013-2014 Intel Mobile Communications GmbH + * Copyright (C) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -538,11 +539,16 @@ static void ieee80211_add_ht_ie(struct ieee80211_sub_if_data *sdata, ieee80211_ie_build_ht_cap(pos, &ht_cap, cap); } +/* This function determines vht capability flags for the association + * and builds the IE. + * Note - the function may set the owner of the MU-MIMO capability + */ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_supported_band *sband, struct ieee80211_vht_cap *ap_vht_cap) { + struct ieee80211_local *local = sdata->local; u8 *pos; u32 cap; struct ieee80211_sta_vht_cap vht_cap; @@ -576,7 +582,34 @@ static void ieee80211_add_vht_ie(struct ieee80211_sub_if_data *sdata, */ if (!(ap_vht_cap->vht_cap_info & cpu_to_le32(IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE))) - cap &= ~IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE; + cap &= ~(IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE | + IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE); + else if (!(ap_vht_cap->vht_cap_info & + cpu_to_le32(IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE))) + cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + + /* + * If some other vif is using the MU-MIMO capablity we cannot associate + * using MU-MIMO - this will lead to contradictions in the group-id + * mechanism. + * Ownership is defined since association request, in order to avoid + * simultaneous associations with MU-MIMO. + */ + if (cap & IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE) { + bool disable_mu_mimo = false; + struct ieee80211_sub_if_data *other; + + list_for_each_entry_rcu(other, &local->interfaces, list) { + if (other->flags & IEEE80211_SDATA_MU_MIMO_OWNER) { + disable_mu_mimo = true; + break; + } + } + if (disable_mu_mimo) + cap &= ~IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE; + else + sdata->flags |= IEEE80211_SDATA_MU_MIMO_OWNER; + } mask = IEEE80211_VHT_CAP_BEAMFORMEE_STS_MASK; @@ -2058,6 +2091,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask)); memset(&ifmgd->vht_capa, 0, sizeof(ifmgd->vht_capa)); memset(&ifmgd->vht_capa_mask, 0, sizeof(ifmgd->vht_capa_mask)); + sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER; sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL; @@ -2520,6 +2554,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata, eth_zero_addr(sdata->u.mgd.bssid); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID); sdata->u.mgd.flags = 0; + sdata->flags &= ~IEEE80211_SDATA_MU_MIMO_OWNER; mutex_lock(&sdata->local->mtx); ieee80211_vif_release_channel(sdata); mutex_unlock(&sdata->local->mtx); -- GitLab From c8ff71e667d9fcf775e8b8bbd568d32d48cfb864 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 8 Jul 2015 15:41:45 +0300 Subject: [PATCH 1105/7006] mac80211: TDLS: handle chan-switch in RTNL locked work Move TDLS channel-switch Rx handling into an RTNL locked work. This is required to add proper regulatory checking to incoming channel-switch requests. Queue incoming requests in a dedicated skb queue and handle the request in a device-specific work to avoid deadlocking on interface removal. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/ieee80211_i.h | 8 +++++--- net/mac80211/iface.c | 2 -- net/mac80211/main.c | 5 +++++ net/mac80211/rx.c | 5 ++--- net/mac80211/tdls.c | 34 ++++++++++++++++++++++++++++++++-- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 90580e903926b..36f217e842d84 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1008,7 +1008,6 @@ enum sdata_queue_type { IEEE80211_SDATA_QUEUE_AGG_STOP = 2, IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, - IEEE80211_SDATA_QUEUE_TDLS_CHSW = 5, }; enum { @@ -1351,6 +1350,10 @@ struct ieee80211_local { /* extended capabilities provided by mac80211 */ u8 ext_capa[8]; + + /* TDLS channel switch */ + struct work_struct tdls_chsw_work; + struct sk_buff_head skb_queue_tdls_chsw; }; static inline struct ieee80211_sub_if_data * @@ -2054,9 +2057,8 @@ int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev, void ieee80211_tdls_cancel_channel_switch(struct wiphy *wiphy, struct net_device *dev, const u8 *addr); -void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb); void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata); +void ieee80211_tdls_chsw_work(struct work_struct *wk); extern const struct ethtool_ops ieee80211_ethtool_ops; diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 553ac6dd48674..0fba7f97a963f 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -1242,8 +1242,6 @@ static void ieee80211_iface_work(struct work_struct *work) WLAN_BACK_RECIPIENT, 0, false); mutex_unlock(&local->sta_mtx); - } else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_TDLS_CHSW) { - ieee80211_process_tdls_channel_switch(sdata, skb); } else if (ieee80211_is_action(mgmt->frame_control) && mgmt->u.action.category == WLAN_CATEGORY_BACK) { int len = skb->len; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index dba0a86dee18e..ff79a13d231db 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -629,6 +629,8 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, INIT_WORK(&local->sched_scan_stopped_work, ieee80211_sched_scan_stopped_work); + INIT_WORK(&local->tdls_chsw_work, ieee80211_tdls_chsw_work); + spin_lock_init(&local->ack_status_lock); idr_init(&local->ack_status_frames); @@ -645,6 +647,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, skb_queue_head_init(&local->skb_queue); skb_queue_head_init(&local->skb_queue_unreliable); + skb_queue_head_init(&local->skb_queue_tdls_chsw); ieee80211_alloc_led_names(local); @@ -1161,6 +1164,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) cancel_work_sync(&local->restart_work); cancel_work_sync(&local->reconfig_filter); + cancel_work_sync(&local->tdls_chsw_work); flush_work(&local->sched_scan_stopped_work); ieee80211_clear_tx_pending(local); @@ -1171,6 +1175,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) wiphy_warn(local->hw.wiphy, "skb_queue not empty\n"); skb_queue_purge(&local->skb_queue); skb_queue_purge(&local->skb_queue_unreliable); + skb_queue_purge(&local->skb_queue_tdls_chsw); destroy_workqueue(local->workqueue); wiphy_unregister(local->hw.wiphy); diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 3a1462810c8e2..f673304f70f5b 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -2410,9 +2410,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) tf->category == WLAN_CATEGORY_TDLS && (tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST || tf->action_code == WLAN_TDLS_CHANNEL_SWITCH_RESPONSE)) { - rx->skb->pkt_type = IEEE80211_SDATA_QUEUE_TDLS_CHSW; - skb_queue_tail(&sdata->skb_queue, rx->skb); - ieee80211_queue_work(&rx->local->hw, &sdata->work); + skb_queue_tail(&local->skb_queue_tdls_chsw, rx->skb); + schedule_work(&local->tdls_chsw_work); if (rx->sta) rx->sta->rx_packets++; diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 20c9dbde3b2bb..91e86bf768671 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "ieee80211_i.h" #include "driver-ops.h" @@ -1800,12 +1801,15 @@ out: return ret; } -void ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb) +static void +ieee80211_process_tdls_channel_switch(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb) { struct ieee80211_tdls_data *tf = (void *)skb->data; struct wiphy *wiphy = sdata->local->hw.wiphy; + ASSERT_RTNL(); + /* make sure the driver supports it */ if (!(wiphy->features & NL80211_FEATURE_TDLS_CHANNEL_SWITCH)) return; @@ -1847,3 +1851,29 @@ void ieee80211_teardown_tdls_peers(struct ieee80211_sub_if_data *sdata) } rcu_read_unlock(); } + +void ieee80211_tdls_chsw_work(struct work_struct *wk) +{ + struct ieee80211_local *local = + container_of(wk, struct ieee80211_local, tdls_chsw_work); + struct ieee80211_sub_if_data *sdata; + struct sk_buff *skb; + struct ieee80211_tdls_data *tf; + + rtnl_lock(); + while ((skb = skb_dequeue(&local->skb_queue_tdls_chsw))) { + tf = (struct ieee80211_tdls_data *)skb->data; + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata) || + sdata->vif.type != NL80211_IFTYPE_STATION || + !ether_addr_equal(tf->da, sdata->vif.addr)) + continue; + + ieee80211_process_tdls_channel_switch(sdata, skb); + break; + } + + kfree_skb(skb); + } + rtnl_unlock(); +} -- GitLab From 42d8d789615d539cb13733e516b94e874a34f775 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Wed, 8 Jul 2015 15:41:46 +0300 Subject: [PATCH 1106/7006] mac80211: TDLS: deny ch-switch req on disallowed channels If a TDLS station is not allowed to beacon on a channel, don't accept a channel switch request to this channel. Move channel building code up to avoid lockdep violations - reg_can_beacon needs to take the wdev lock. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/tdls.c | 49 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index 91e86bf768671..aee701a5649e5 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1737,6 +1737,31 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, return -EINVAL; } + if (!elems.sec_chan_offs) { + chan_type = NL80211_CHAN_HT20; + } else { + switch (elems.sec_chan_offs->sec_chan_offs) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + chan_type = NL80211_CHAN_HT40PLUS; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + chan_type = NL80211_CHAN_HT40MINUS; + break; + default: + chan_type = NL80211_CHAN_HT20; + break; + } + } + + cfg80211_chandef_create(&chandef, chan, chan_type); + + /* we will be active on the TDLS link */ + if (!cfg80211_reg_can_beacon_relax(sdata->local->hw.wiphy, &chandef, + sdata->wdev.iftype)) { + tdls_dbg(sdata, "TDLS chan switch to forbidden channel\n"); + return -EINVAL; + } + mutex_lock(&local->sta_mtx); sta = sta_info_get(sdata, tf->sa); if (!sta || !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) { @@ -1757,27 +1782,15 @@ ieee80211_process_tdls_channel_switch_req(struct ieee80211_sub_if_data *sdata, goto out; } - if (!sta->sta.ht_cap.ht_supported) { - chan_type = NL80211_CHAN_NO_HT; - } else if (!elems.sec_chan_offs) { - chan_type = NL80211_CHAN_HT20; - } else { - switch (elems.sec_chan_offs->sec_chan_offs) { - case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: - chan_type = NL80211_CHAN_HT40PLUS; - break; - case IEEE80211_HT_PARAM_CHA_SEC_BELOW: - chan_type = NL80211_CHAN_HT40MINUS; - break; - default: - chan_type = NL80211_CHAN_HT20; - break; - } + /* peer should have known better */ + if (!sta->sta.ht_cap.ht_supported && elems.sec_chan_offs && + elems.sec_chan_offs->sec_chan_offs) { + tdls_dbg(sdata, "TDLS chan switch - wide chan unsupported\n"); + ret = -ENOTSUPP; + goto out; } - cfg80211_chandef_create(&chandef, chan, chan_type); params.chandef = &chandef; - params.switch_time = le16_to_cpu(elems.ch_sw_timing->switch_time); params.switch_timeout = le16_to_cpu(elems.ch_sw_timing->switch_timeout); -- GitLab From b0485e9f3defbed6effcde595df9b9fdbdb2524e Mon Sep 17 00:00:00 2001 From: Eliad Peller Date: Wed, 8 Jul 2015 15:41:47 +0300 Subject: [PATCH 1107/7006] mac80211: clear local->suspended before calling drv_resume() Currently, mac80211 calls drv_resume() on wowlan resume, but drops any incoming frame until local->suspended is cleared later on. This requires the low-level driver to support a new state, in which it is expected to fully work (as it was resumed) but not passing rx frames yet (as they will be dropped). iwlwifi (and probably other drivers as well) has issues supporting such mode. Since in the wowlan case we already short-circuit ieee80211_reconfig, there's nothing that prevents us from clearing local->suspend before calling drv_resume(), and letting the low-level driver work normally. Signed-off-by: Eliad Peller Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/util.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index e54596f956638..1104421bc5255 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -1716,16 +1716,24 @@ int ieee80211_reconfig(struct ieee80211_local *local) struct ieee80211_sub_if_data *sched_scan_sdata; struct cfg80211_sched_scan_request *sched_scan_req; bool sched_scan_stopped = false; + bool suspended = local->suspended; /* nothing to do if HW shouldn't run */ if (!local->open_count) goto wake_up; #ifdef CONFIG_PM - if (local->suspended) + if (suspended) local->resuming = true; if (local->wowlan) { + /* + * In the wowlan case, both mac80211 and the device + * are functional when the resume op is called, so + * clear local->suspended so the device could operate + * normally (e.g. pass rx frames). + */ + local->suspended = false; res = drv_resume(local); local->wowlan = false; if (res < 0) { @@ -1738,8 +1746,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) /* * res is 1, which means the driver requested * to go through a regular reset on wakeup. + * restore local->suspended in this case. */ reconfig_due_to_wowlan = true; + local->suspended = true; } #endif @@ -1751,7 +1761,7 @@ int ieee80211_reconfig(struct ieee80211_local *local) */ res = drv_start(local); if (res) { - if (local->suspended) + if (suspended) WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n"); else WARN(1, "Hardware became unavailable during restart.\n"); @@ -2045,10 +2055,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) * If this is for hw restart things are still running. * We may want to change that later, however. */ - if (local->open_count && (!local->suspended || reconfig_due_to_wowlan)) + if (local->open_count && (!suspended || reconfig_due_to_wowlan)) drv_reconfig_complete(local, IEEE80211_RECONFIG_TYPE_RESTART); - if (!local->suspended) + if (!suspended) return 0; #ifdef CONFIG_PM -- GitLab From fa87a6566ca8f17a92ba81980bd47c456262907c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 14 Jul 2015 08:31:57 -0400 Subject: [PATCH 1108/7006] mac80211: reorder mesh_plink to remove forward decl Move mesh_plink_frame_tx() above the first caller to remove the forward declaration. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 109 ++++++++++++++++++-------------------- 1 file changed, 52 insertions(+), 57 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index ac1029f28133e..a5aa0345dd7e1 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -53,11 +53,6 @@ static const char * const mplevents[] = { [CLS_IGNR] = "CLS_IGNR" }; -static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, - enum ieee80211_self_protected_actioncode action, - u8 *da, u16 llid, u16 plid, u16 reason); - - /* We only need a valid sta if user configured a minimum rssi_threshold. */ static bool rssi_threshold_check(struct ieee80211_sub_if_data *sdata, struct sta_info *sta) @@ -204,58 +199,6 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) return BSS_CHANGED_HT; } -/** - * __mesh_plink_deactivate - deactivate mesh peer link - * - * @sta: mesh peer link to deactivate - * - * All mesh paths with this peer as next hop will be flushed - * Returns beacon changed flag if the beacon content changed. - * - * Locking: the caller must hold sta->mesh->plink_lock - */ -static u32 __mesh_plink_deactivate(struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed = 0; - - lockdep_assert_held(&sta->mesh->plink_lock); - - if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) - changed = mesh_plink_dec_estab_count(sdata); - sta->mesh->plink_state = NL80211_PLINK_BLOCKED; - mesh_path_flush_by_nexthop(sta); - - ieee80211_mps_sta_status_update(sta); - changed |= ieee80211_mps_set_sta_local_pm(sta, - NL80211_MESH_POWER_UNKNOWN); - - return changed; -} - -/** - * mesh_plink_deactivate - deactivate mesh peer link - * - * @sta: mesh peer link to deactivate - * - * All mesh paths with this peer as next hop will be flushed - */ -u32 mesh_plink_deactivate(struct sta_info *sta) -{ - struct ieee80211_sub_if_data *sdata = sta->sdata; - u32 changed; - - spin_lock_bh(&sta->mesh->plink_lock); - changed = __mesh_plink_deactivate(sta); - sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED; - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, - sta->sta.addr, sta->mesh->llid, sta->mesh->plid, - sta->mesh->reason); - spin_unlock_bh(&sta->mesh->plink_lock); - - return changed; -} - static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, enum ieee80211_self_protected_actioncode action, u8 *da, u16 llid, u16 plid, u16 reason) @@ -375,6 +318,58 @@ free: return err; } +/** + * __mesh_plink_deactivate - deactivate mesh peer link + * + * @sta: mesh peer link to deactivate + * + * All mesh paths with this peer as next hop will be flushed + * Returns beacon changed flag if the beacon content changed. + * + * Locking: the caller must hold sta->mesh->plink_lock + */ +static u32 __mesh_plink_deactivate(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 changed = 0; + + lockdep_assert_held(&sta->mesh->plink_lock); + + if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) + changed = mesh_plink_dec_estab_count(sdata); + sta->mesh->plink_state = NL80211_PLINK_BLOCKED; + mesh_path_flush_by_nexthop(sta); + + ieee80211_mps_sta_status_update(sta); + changed |= ieee80211_mps_set_sta_local_pm(sta, + NL80211_MESH_POWER_UNKNOWN); + + return changed; +} + +/** + * mesh_plink_deactivate - deactivate mesh peer link + * + * @sta: mesh peer link to deactivate + * + * All mesh paths with this peer as next hop will be flushed + */ +u32 mesh_plink_deactivate(struct sta_info *sta) +{ + struct ieee80211_sub_if_data *sdata = sta->sdata; + u32 changed; + + spin_lock_bh(&sta->mesh->plink_lock); + changed = __mesh_plink_deactivate(sta); + sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED; + mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, + sta->sta.addr, sta->mesh->llid, sta->mesh->plid, + sta->mesh->reason); + spin_unlock_bh(&sta->mesh->plink_lock); + + return changed; +} + static void mesh_sta_info_init(struct ieee80211_sub_if_data *sdata, struct sta_info *sta, struct ieee802_11_elems *elems, bool insert) -- GitLab From a69bd8e60b02946896c097439b94eb77c0c2c9e4 Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 14 Jul 2015 08:31:58 -0400 Subject: [PATCH 1109/7006] mac80211: mesh: separate plid and aid concepts According to 802.11-2012 13.3.1, a mesh STA should assign an AID upon receipt of a mesh peering open frame rather than using the link id of the peer. Using the peer link id has two potential issues: it may not be unique among the peers, and by its nature it is random, so the TIM may not compress well. In preparation for allocating it properly, use sta->sta.aid, but keep the existing behavior of using the plid in the aid we send. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 29 +++++++++++++++++++---------- net/mac80211/mesh_ps.c | 2 +- net/mac80211/sta_info.c | 5 +---- net/mac80211/sta_info.h | 2 ++ 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index a5aa0345dd7e1..3323413acb77b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -13,6 +13,7 @@ #include "rate.h" #include "mesh.h" +#define PLINK_CNF_AID(mgmt) ((mgmt)->u.action.u.self_prot.variable + 2) #define PLINK_GET_LLID(p) (p + 2) #define PLINK_GET_PLID(p) (p + 4) @@ -200,6 +201,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) } static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, enum ieee80211_self_protected_actioncode action, u8 *da, u16 llid, u16 plid, u16 reason) { @@ -249,7 +251,7 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, if (action == WLAN_SP_MESH_PEERING_CONFIRM) { /* AID */ pos = skb_put(skb, 2); - put_unaligned_le16(plid, pos); + put_unaligned_le16(sta->sta.aid, pos); } if (ieee80211_add_srates_ie(sdata, skb, true, band) || ieee80211_add_ext_srates_ie(sdata, skb, true, band) || @@ -362,7 +364,7 @@ u32 mesh_plink_deactivate(struct sta_info *sta) spin_lock_bh(&sta->mesh->plink_lock); changed = __mesh_plink_deactivate(sta); sta->mesh->reason = WLAN_REASON_MESH_PEER_CANCELED; - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, + mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_CLOSE, sta->sta.addr, sta->mesh->llid, sta->mesh->plid, sta->mesh->reason); spin_unlock_bh(&sta->mesh->plink_lock); @@ -619,7 +621,7 @@ static void mesh_plink_timer(unsigned long data) } spin_unlock_bh(&sta->mesh->plink_lock); if (action) - mesh_plink_frame_tx(sdata, action, sta->sta.addr, + mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr, sta->mesh->llid, sta->mesh->plid, reason); } @@ -689,7 +691,7 @@ u32 mesh_plink_open(struct sta_info *sta) /* set the non-peer mode to active during peering */ changed = ieee80211_mps_local_status_update(sdata); - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, + mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_OPEN, sta->sta.addr, sta->mesh->llid, 0, 0); return changed; } @@ -871,13 +873,13 @@ static u32 mesh_plink_fsm(struct ieee80211_sub_if_data *sdata, } spin_unlock_bh(&sta->mesh->plink_lock); if (action) { - mesh_plink_frame_tx(sdata, action, sta->sta.addr, + mesh_plink_frame_tx(sdata, sta, action, sta->sta.addr, sta->mesh->llid, sta->mesh->plid, sta->mesh->reason); /* also send confirm in open case */ if (action == WLAN_SP_MESH_PEERING_OPEN) { - mesh_plink_frame_tx(sdata, + mesh_plink_frame_tx(sdata, sta, WLAN_SP_MESH_PEERING_CONFIRM, sta->sta.addr, sta->mesh->llid, sta->mesh->plid, 0); @@ -1067,8 +1069,9 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, goto unlock_rcu; } sta->mesh->plid = plid; + sta->sta.aid = plid; } else if (!sta && event == OPN_RJCT) { - mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE, + mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE, mgmt->sa, 0, plid, WLAN_REASON_MESH_CONFIG); goto unlock_rcu; @@ -1077,9 +1080,15 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, goto unlock_rcu; } - /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ - if (!sta->mesh->plid && event == CNF_ACPT) - sta->mesh->plid = plid; + if (event == CNF_ACPT) { + /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ + if (!sta->mesh->plid) { + sta->mesh->plid = plid; + sta->sta.aid = sta->mesh->plid; + } + + sta->mesh->aid = get_unaligned_le16(PLINK_CNF_AID(mgmt)); + } changed |= mesh_plink_fsm(sdata, sta, event); diff --git a/net/mac80211/mesh_ps.c b/net/mac80211/mesh_ps.c index 29747f92b9b02..90a268abea171 100644 --- a/net/mac80211/mesh_ps.c +++ b/net/mac80211/mesh_ps.c @@ -579,7 +579,7 @@ void ieee80211_mps_frame_release(struct sta_info *sta, if (sta->mesh->plink_state == NL80211_PLINK_ESTAB) has_buffered = ieee80211_check_tim(elems->tim, elems->tim_len, - sta->mesh->llid); + sta->mesh->aid); if (has_buffered) mps_dbg(sta->sdata, "%pM indicates buffered frames\n", diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 9da7d2bc271ac..70cd9fa574245 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -635,7 +635,7 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) bool indicate_tim = false; u8 ignore_for_tim = sta->sta.uapsd_queues; int ac; - u16 id; + u16 id = sta->sta.aid; if (sta->sdata->vif.type == NL80211_IFTYPE_AP || sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) { @@ -643,12 +643,9 @@ static void __sta_info_recalc_tim(struct sta_info *sta, bool ignore_pending) return; ps = &sta->sdata->bss->ps; - id = sta->sta.aid; #ifdef CONFIG_MAC80211_MESH } else if (ieee80211_vif_is_mesh(&sta->sdata->vif)) { ps = &sta->sdata->u.mesh.ps; - /* TIM map only for 1 <= PLID <= IEEE80211_MAX_AID */ - id = sta->mesh->plid % (IEEE80211_MAX_AID + 1); #endif } else { return; diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 6dcb33484eac4..1d2805c598c05 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -277,6 +277,7 @@ struct ieee80211_fast_tx { * @plink_lock: serialize access to plink fields * @llid: Local link ID * @plid: Peer link ID + * @aid: local aid supplied by peer * @reason: Cancel reason on PLINK_HOLDING state * @plink_retries: Retries in establishment * @plink_state: peer link state @@ -301,6 +302,7 @@ struct mesh_sta { spinlock_t plink_lock; u16 llid; u16 plid; + u16 aid; u16 reason; u8 plink_retries; -- GitLab From 0e0060fcfb3d0f5a53ef43e7b6a50227b934ab7c Mon Sep 17 00:00:00 2001 From: Bob Copeland Date: Tue, 14 Jul 2015 08:31:59 -0400 Subject: [PATCH 1110/7006] mac80211: select an AID when creating new mesh STAs Instead of using peer link id for AID, generate a new AID when creating mesh STAs in the kernel peering manager. This enables smaller TIM elements and more closely follows the standard, and it also enables mesh to work on drivers that require a valid AID when the STA is inserted (ath10k firmware has this requirement, for example). In the case of userspace-managed stations, we use the AID from NL80211_CMD_NEW_STATION. Signed-off-by: Bob Copeland Signed-off-by: Johannes Berg --- net/mac80211/mesh_plink.c | 41 +++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 3323413acb77b..e12be2e4e8df0 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -422,20 +422,54 @@ out: spin_unlock_bh(&sta->mesh->plink_lock); } +static int mesh_allocate_aid(struct ieee80211_sub_if_data *sdata) +{ + struct sta_info *sta; + unsigned long *aid_map; + int aid; + + aid_map = kcalloc(BITS_TO_LONGS(IEEE80211_MAX_AID + 1), + sizeof(*aid_map), GFP_KERNEL); + if (!aid_map) + return -ENOMEM; + + /* reserve aid 0 for mcast indication */ + __set_bit(0, aid_map); + + rcu_read_lock(); + list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) + __set_bit(sta->sta.aid, aid_map); + rcu_read_unlock(); + + aid = find_first_zero_bit(aid_map, IEEE80211_MAX_AID + 1); + kfree(aid_map); + + if (aid > IEEE80211_MAX_AID) + return -ENOBUFS; + + return aid; +} + static struct sta_info * __mesh_sta_info_alloc(struct ieee80211_sub_if_data *sdata, u8 *hw_addr) { struct sta_info *sta; + int aid; if (sdata->local->num_sta >= MESH_MAX_PLINKS) return NULL; + aid = mesh_allocate_aid(sdata); + if (aid < 0) + return NULL; + sta = sta_info_alloc(sdata, hw_addr, GFP_KERNEL); if (!sta) return NULL; sta->mesh->plink_state = NL80211_PLINK_LISTEN; sta->sta.wme = true; + sta->sta.aid = aid; sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); @@ -659,8 +693,6 @@ static u16 mesh_get_new_llid(struct ieee80211_sub_if_data *sdata) do { get_random_bytes(&llid, sizeof(llid)); - /* for mesh PS we still only have the AID range for TIM bits */ - llid = (llid % IEEE80211_MAX_AID) + 1; } while (llid_in_use(sdata, llid)); return llid; @@ -1069,7 +1101,6 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, goto unlock_rcu; } sta->mesh->plid = plid; - sta->sta.aid = plid; } else if (!sta && event == OPN_RJCT) { mesh_plink_frame_tx(sdata, NULL, WLAN_SP_MESH_PEERING_CLOSE, mgmt->sa, 0, plid, @@ -1082,10 +1113,8 @@ mesh_process_plink_frame(struct ieee80211_sub_if_data *sdata, if (event == CNF_ACPT) { /* 802.11-2012 13.3.7.2 - update plid on CNF if not set */ - if (!sta->mesh->plid) { + if (!sta->mesh->plid) sta->mesh->plid = plid; - sta->sta.aid = sta->mesh->plid; - } sta->mesh->aid = get_unaligned_le16(PLINK_CNF_AID(mgmt)); } -- GitLab From 727da60be91c9fd59f1b084ca537b5123ab97744 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 15 Jul 2015 14:56:05 +0200 Subject: [PATCH 1111/7006] mac80211: deinline drv_sta_state With this .config: http://busybox.net/~vda/kernel_config, after deinlining the function size is 3132 bytes and there are 7 callsites. Total size reduction: about 20 kbytes. Signed-off-by: Denys Vlasenko CC: John Linville CC: Michal Kazior Cc: Johannes Berg Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Johannes Berg --- net/mac80211/Makefile | 1 + net/mac80211/driver-ops.c | 41 +++++++++++++++++++++++++++++++++++++++ net/mac80211/driver-ops.h | 29 ++------------------------- 3 files changed, 44 insertions(+), 27 deletions(-) create mode 100644 net/mac80211/driver-ops.c diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 3275f01881bee..783e891b7525c 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -3,6 +3,7 @@ obj-$(CONFIG_MAC80211) += mac80211.o # mac80211 objects mac80211-y := \ main.o status.o \ + driver-ops.o \ sta_info.o \ wep.o \ wpa.o \ diff --git a/net/mac80211/driver-ops.c b/net/mac80211/driver-ops.c new file mode 100644 index 0000000000000..267c3b1ca0475 --- /dev/null +++ b/net/mac80211/driver-ops.c @@ -0,0 +1,41 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include "ieee80211_i.h" +#include "trace.h" +#include "driver-ops.h" + +__must_check +int drv_sta_state(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct sta_info *sta, + enum ieee80211_sta_state old_state, + enum ieee80211_sta_state new_state) +{ + int ret = 0; + + might_sleep(); + + sdata = get_bss_sdata(sdata); + if (!check_sdata_in_driver(sdata)) + return -EIO; + + trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); + if (local->ops->sta_state) { + ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, + old_state, new_state); + } else if (old_state == IEEE80211_STA_AUTH && + new_state == IEEE80211_STA_ASSOC) { + ret = drv_sta_add(local, sdata, &sta->sta); + if (ret == 0) + sta->uploaded = true; + } else if (old_state == IEEE80211_STA_ASSOC && + new_state == IEEE80211_STA_AUTH) { + drv_sta_remove(local, sdata, &sta->sta); + } + trace_drv_return_int(local, ret); + return ret; +} diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 32a2e707e2226..02d91332d7ddd 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -573,37 +573,12 @@ static inline void drv_sta_pre_rcu_remove(struct ieee80211_local *local, trace_drv_return_void(local); } -static inline __must_check +__must_check int drv_sta_state(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, struct sta_info *sta, enum ieee80211_sta_state old_state, - enum ieee80211_sta_state new_state) -{ - int ret = 0; - - might_sleep(); - - sdata = get_bss_sdata(sdata); - if (!check_sdata_in_driver(sdata)) - return -EIO; - - trace_drv_sta_state(local, sdata, &sta->sta, old_state, new_state); - if (local->ops->sta_state) { - ret = local->ops->sta_state(&local->hw, &sdata->vif, &sta->sta, - old_state, new_state); - } else if (old_state == IEEE80211_STA_AUTH && - new_state == IEEE80211_STA_ASSOC) { - ret = drv_sta_add(local, sdata, &sta->sta); - if (ret == 0) - sta->uploaded = true; - } else if (old_state == IEEE80211_STA_ASSOC && - new_state == IEEE80211_STA_AUTH) { - drv_sta_remove(local, sdata, &sta->sta); - } - trace_drv_return_int(local, ret); - return ret; -} + enum ieee80211_sta_state new_state); static inline void drv_sta_rc_update(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, -- GitLab From eb6d9293dfed245a114cad7d975259963e1e04c2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 15 Jul 2015 14:56:06 +0200 Subject: [PATCH 1112/7006] mac80211: deinline rate_control_rate_init, rate_control_rate_update With this .config: http://busybox.net/~vda/kernel_config, after deinlining these functions have sizes and callsite counts as follows: rate_control_rate_init: 554 bytes, 8 calls rate_control_rate_update: 1596 bytes, 5 calls Total size reduction: about 11 kbytes. Signed-off-by: Denys Vlasenko CC: John Linville CC: Michal Kazior CC: Johannes Berg Cc: linux-wireless@vger.kernel.org Cc: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Johannes Berg --- net/mac80211/rate.c | 59 ++++++++++++++++++++++++++++++++++++++++++++ net/mac80211/rate.h | 60 +++------------------------------------------ 2 files changed, 62 insertions(+), 57 deletions(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index fda33f961d83c..03687d22b405a 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -29,6 +29,65 @@ module_param(ieee80211_default_rc_algo, charp, 0644); MODULE_PARM_DESC(ieee80211_default_rc_algo, "Default rate control algorithm for mac80211 to use"); +void rate_control_rate_init(struct sta_info *sta) +{ + struct ieee80211_local *local = sta->sdata->local; + struct rate_control_ref *ref = sta->rate_ctrl; + struct ieee80211_sta *ista = &sta->sta; + void *priv_sta = sta->rate_ctrl_priv; + struct ieee80211_supported_band *sband; + struct ieee80211_chanctx_conf *chanctx_conf; + + ieee80211_sta_set_rx_nss(sta); + + if (!ref) + return; + + rcu_read_lock(); + + chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return; + } + + sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; + + spin_lock_bh(&sta->rate_ctrl_lock); + ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, + priv_sta); + spin_unlock_bh(&sta->rate_ctrl_lock); + rcu_read_unlock(); + set_sta_flag(sta, WLAN_STA_RATE_CONTROL); +} + +void rate_control_rate_update(struct ieee80211_local *local, + struct ieee80211_supported_band *sband, + struct sta_info *sta, u32 changed) +{ + struct rate_control_ref *ref = local->rate_ctrl; + struct ieee80211_sta *ista = &sta->sta; + void *priv_sta = sta->rate_ctrl_priv; + struct ieee80211_chanctx_conf *chanctx_conf; + + if (ref && ref->ops->rate_update) { + rcu_read_lock(); + + chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); + if (WARN_ON(!chanctx_conf)) { + rcu_read_unlock(); + return; + } + + spin_lock_bh(&sta->rate_ctrl_lock); + ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, + ista, priv_sta, changed); + spin_unlock_bh(&sta->rate_ctrl_lock); + rcu_read_unlock(); + } + drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); +} + int ieee80211_rate_control_register(const struct rate_control_ops *ops) { struct rate_control_alg *alg; diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index 25c9be5dd7fd8..624fe5b81615e 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -71,64 +71,10 @@ rate_control_tx_status_noskb(struct ieee80211_local *local, spin_unlock_bh(&sta->rate_ctrl_lock); } -static inline void rate_control_rate_init(struct sta_info *sta) -{ - struct ieee80211_local *local = sta->sdata->local; - struct rate_control_ref *ref = sta->rate_ctrl; - struct ieee80211_sta *ista = &sta->sta; - void *priv_sta = sta->rate_ctrl_priv; - struct ieee80211_supported_band *sband; - struct ieee80211_chanctx_conf *chanctx_conf; - - ieee80211_sta_set_rx_nss(sta); - - if (!ref) - return; - - rcu_read_lock(); - - chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); - if (WARN_ON(!chanctx_conf)) { - rcu_read_unlock(); - return; - } - - sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band]; - - spin_lock_bh(&sta->rate_ctrl_lock); - ref->ops->rate_init(ref->priv, sband, &chanctx_conf->def, ista, - priv_sta); - spin_unlock_bh(&sta->rate_ctrl_lock); - rcu_read_unlock(); - set_sta_flag(sta, WLAN_STA_RATE_CONTROL); -} - -static inline void rate_control_rate_update(struct ieee80211_local *local, +void rate_control_rate_init(struct sta_info *sta); +void rate_control_rate_update(struct ieee80211_local *local, struct ieee80211_supported_band *sband, - struct sta_info *sta, u32 changed) -{ - struct rate_control_ref *ref = local->rate_ctrl; - struct ieee80211_sta *ista = &sta->sta; - void *priv_sta = sta->rate_ctrl_priv; - struct ieee80211_chanctx_conf *chanctx_conf; - - if (ref && ref->ops->rate_update) { - rcu_read_lock(); - - chanctx_conf = rcu_dereference(sta->sdata->vif.chanctx_conf); - if (WARN_ON(!chanctx_conf)) { - rcu_read_unlock(); - return; - } - - spin_lock_bh(&sta->rate_ctrl_lock); - ref->ops->rate_update(ref->priv, sband, &chanctx_conf->def, - ista, priv_sta, changed); - spin_unlock_bh(&sta->rate_ctrl_lock); - rcu_read_unlock(); - } - drv_sta_rc_update(local, sta->sdata, &sta->sta, changed); -} + struct sta_info *sta, u32 changed); static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, struct sta_info *sta, gfp_t gfp) -- GitLab From f964c409f7cc626335cf2370f55690660a273dad Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Thu, 9 Jul 2015 07:10:12 -0300 Subject: [PATCH 1113/7006] [media] coda: clamp frame sequence counters to 16 bit This is already done for one side of the comparison with the expectation that the HW counter rolls over at the 16 bit boundary. This is true when decoding a h.264 stream, but doesn't hold for at least MJPEG. As we don't know the exact wrap-around point for this format just clamp the HW counter to the same 16 bits. This should be enough to detect most of the errors and saves us from doing different comparisons based on the decoded format. Signed-off-by: Lucas Stach Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 109797bb8fbb4..9fbff248d7fa2 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1902,7 +1902,14 @@ static void coda_finish_decode(struct coda_ctx *ctx) meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); - if (val != (meta->sequence & 0xffff)) { + /* + * Clamp counters to 16 bits for comparison, as the HW + * counter rolls over at this point for h.264. This + * may be different for other formats, but using 16 bits + * should be enough to detect most errors and saves us + * from doing different things based on the format. + */ + if ((val & 0xffff) != (meta->sequence & 0xffff)) { v4l2_err(&dev->v4l2_dev, "sequence number mismatch (%d(%d) != %d)\n", val, ctx->sequence_offset, -- GitLab From b05959c66e865fb9eb5b93e223da925572130d7f Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:13 -0300 Subject: [PATCH 1114/7006] [media] coda: fix mvcol buffer for MPEG4 decoding The mvcol buffer is allocated at the end of the first internal buffer. This patch fixes an out of bounds array access. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 9fbff248d7fa2..47fc2f19a4a9a 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -384,7 +384,7 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, /* mvcol buffer for mpeg4 */ if ((dev->devtype->product != CODA_DX6) && (ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4)) - coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr + + coda_parabuf_write(ctx, 97, ctx->internal_frames[0].paddr + ysize + ysize/4 + ysize/4); return 0; -- GitLab From 58bc7edf1d9a16073761031a03291af887ccdf66 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:14 -0300 Subject: [PATCH 1115/7006] [media] coda: fix bitstream preloading for MPEG4 decoding All decoder instances using the BIT processor should preload buffers into the bitstream ring buffer, including MPEG4 decoding. Fix this by explicitly stating the above condition instead of listing all relevant input formats. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 58f65486de332..3259ea61cd9b7 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1244,9 +1244,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - if (q_data_src->fourcc == V4L2_PIX_FMT_H264 || - (q_data_src->fourcc == V4L2_PIX_FMT_JPEG && - ctx->dev->devtype->product == CODA_7541)) { + if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { /* copy the buffers that were queued before streamon */ mutex_lock(&ctx->bitstream_mutex); coda_fill_bitstream(ctx, false); -- GitLab From 30a09579b2e238646bca4e7cc443db24d91436d6 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:15 -0300 Subject: [PATCH 1116/7006] [media] coda: keep buffers on the queue in bitstream end mode In stream end mode the hardware will read the bitstream to its end, overshooting the write pointer. Do not write additional data into the bitstream in this mode. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 47fc2f19a4a9a..0f8dcea065afa 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -228,6 +228,9 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) struct coda_buffer_meta *meta; u32 start; + if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) + return; + while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) { /* * Only queue a single JPEG into the bitstream buffer, except -- GitLab From 5c718bb323aef02ea580073a3640b072fb2f6838 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:16 -0300 Subject: [PATCH 1117/7006] [media] coda: avoid calling SEQ_END twice Allow coda_seq_end_work to be called multiple times, move the setting of ctx->initialized from coda_start/stop_streaming() into coda_start_encoding/decoding and coda_seq_end_work, respectively, and skip the SEQ_END command in coda_seq_end_work if the context is already deinitialized before. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 8 ++++++++ drivers/media/platform/coda/coda-common.c | 4 +--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 0f8dcea065afa..ac4dcb1f446ad 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -999,6 +999,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) ret = -EFAULT; goto out; } + ctx->initialized = 1; if (dst_fourcc != V4L2_PIX_FMT_JPEG) { if (dev->devtype->product == CODA_960) @@ -1329,6 +1330,9 @@ static void coda_seq_end_work(struct work_struct *work) mutex_lock(&ctx->buffer_mutex); mutex_lock(&dev->coda_mutex); + if (ctx->initialized == 0) + goto out; + v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "%d: %s: sent command 'SEQ_END' to coda\n", ctx->idx, __func__); @@ -1342,6 +1346,9 @@ static void coda_seq_end_work(struct work_struct *work) coda_free_framebuffers(ctx); + ctx->initialized = 0; + +out: mutex_unlock(&dev->coda_mutex); mutex_unlock(&ctx->buffer_mutex); } @@ -1499,6 +1506,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx) coda_write(dev, 0, CODA_REG_BIT_BIT_STREAM_PARAM); return -ETIMEDOUT; } + ctx->initialized = 1; /* Update kfifo out pointer from coda bitstream read pointer */ coda_kfifo_sync_from_device(ctx); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 3259ea61cd9b7..de0e245337272 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1313,7 +1313,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) goto err; } - ctx->initialized = 1; return ret; err: @@ -1376,7 +1375,6 @@ static void coda_stop_streaming(struct vb2_queue *q) mutex_unlock(&ctx->bitstream_mutex); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); - ctx->initialized = 0; ctx->runcounter = 0; ctx->aborting = 0; } @@ -1767,7 +1765,7 @@ static int coda_release(struct file *file) v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); /* In case the instance was not running, we still need to call SEQ_END */ - if (ctx->initialized && ctx->ops->seq_end_work) { + if (ctx->ops->seq_end_work) { queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } -- GitLab From c1ae0b283d13ad8b53bf3be379b1207085da4b22 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:17 -0300 Subject: [PATCH 1118/7006] [media] coda: reset stream end in stop_streaming Otherwise a restarted stream won't queue buffers. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index de0e245337272..8b91bda784a7d 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1378,6 +1378,9 @@ static void coda_stop_streaming(struct vb2_queue *q) ctx->runcounter = 0; ctx->aborting = 0; } + + if (!ctx->streamon_out && !ctx->streamon_cap) + ctx->bit_stream_param &= ~CODA_BIT_STREAM_END_FLAG; } static const struct vb2_ops coda_qops = { -- GitLab From 8076c7e3f68547ee1d8e07715329f26f7883152a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:18 -0300 Subject: [PATCH 1119/7006] [media] coda: drop custom list of pixel format descriptions Since commit ba3002045f80 ("[media] v4l2-ioctl: fill in the description for VIDIOC_ENUM_FMT"), all pixel formats are assigned their description in a central place. We can now drop the custom list. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 75 +++-------------------- 1 file changed, 7 insertions(+), 68 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 8b91bda784a7d..b265edd8d2778 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -61,11 +61,6 @@ int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); -struct coda_fmt { - char *name; - u32 fourcc; -}; - void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(2, coda_debug, &dev->v4l2_dev, @@ -111,40 +106,6 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, coda_write(ctx->dev, base_cr, reg_y + 8); } -/* - * Array of all formats supported by any version of Coda: - */ -static const struct coda_fmt coda_formats[] = { - { - .name = "YUV 4:2:0 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV420, - }, - { - .name = "YUV 4:2:0 Planar, YCrCb", - .fourcc = V4L2_PIX_FMT_YVU420, - }, - { - .name = "YUV 4:2:0 Partial interleaved Y/CbCr", - .fourcc = V4L2_PIX_FMT_NV12, - }, - { - .name = "YUV 4:2:2 Planar, YCbCr", - .fourcc = V4L2_PIX_FMT_YUV422P, - }, - { - .name = "H264 Encoded Stream", - .fourcc = V4L2_PIX_FMT_H264, - }, - { - .name = "MPEG4 Encoded Stream", - .fourcc = V4L2_PIX_FMT_MPEG4, - }, - { - .name = "JPEG Encoded Images", - .fourcc = V4L2_PIX_FMT_JPEG, - }, -}; - #define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \ { mode, src_fourcc, dst_fourcc, max_w, max_h } @@ -261,40 +222,23 @@ static const struct coda_video_device *coda9_video_devices[] = { &coda_bit_decoder, }; -static bool coda_format_is_yuv(u32 fourcc) +/* + * Normalize all supported YUV 4:2:0 formats to the value used in the codec + * tables. + */ +static u32 coda_format_normalize_yuv(u32 fourcc) { switch (fourcc) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV422P: - return true; + return V4L2_PIX_FMT_YUV420; default: - return false; + return fourcc; } } -static const char *coda_format_name(u32 fourcc) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(coda_formats); i++) { - if (coda_formats[i].fourcc == fourcc) - return coda_formats[i].name; - } - - return NULL; -} - -/* - * Normalize all supported YUV 4:2:0 formats to the value used in the codec - * tables. - */ -static u32 coda_format_normalize_yuv(u32 fourcc) -{ - return coda_format_is_yuv(fourcc) ? V4L2_PIX_FMT_YUV420 : fourcc; -} - static const struct coda_codec *coda_find_codec(struct coda_dev *dev, int src_fourcc, int dst_fourcc) { @@ -396,7 +340,6 @@ static int coda_enum_fmt(struct file *file, void *priv, struct video_device *vdev = video_devdata(file); const struct coda_video_device *cvd = to_coda_video_device(vdev); const u32 *formats; - const char *name; if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) formats = cvd->src_formats; @@ -408,11 +351,7 @@ static int coda_enum_fmt(struct file *file, void *priv, if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0) return -EINVAL; - name = coda_format_name(formats[f->index]); - strlcpy(f->description, name, sizeof(f->description)); f->pixelformat = formats[f->index]; - if (!coda_format_is_yuv(formats[f->index])) - f->flags |= V4L2_FMT_FLAG_COMPRESSED; return 0; } -- GitLab From f0710815a0e17c63d3f17d365ae556ab15eccb03 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:19 -0300 Subject: [PATCH 1120/7006] [media] coda: use event class to deduplicate v4l2 trace events Trace events with exactly the same parameters and trace output, such as coda_enc_pic_run and coda_enc_pic_done, are supposed to use the DECLARE_EVENT_CLASS and DEFINE_EVENT macros instead of duplicated TRACE_EVENT macro calls. This patch changes the order of parameters to coda_dec_rot_done and adds a timestamp so it can share an event class with coda_bit_queue. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 2 +- drivers/media/platform/coda/trace.h | 89 ++++++++------------------ 2 files changed, 26 insertions(+), 65 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index ac4dcb1f446ad..226ce4a786ea1 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1978,7 +1978,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) dst_buf->v4l2_buf.timecode = meta->timecode; dst_buf->v4l2_buf.timestamp = meta->timestamp; - trace_coda_dec_rot_done(ctx, meta, dst_buf); + trace_coda_dec_rot_done(ctx, dst_buf, meta); switch (q_data_dst->fourcc) { case V4L2_PIX_FMT_YUV420: diff --git a/drivers/media/platform/coda/trace.h b/drivers/media/platform/coda/trace.h index 781bf7286d531..d9099a0f7c327 100644 --- a/drivers/media/platform/coda/trace.h +++ b/drivers/media/platform/coda/trace.h @@ -48,7 +48,7 @@ TRACE_EVENT(coda_bit_done, TP_printk("minor = %d, ctx = %d", __entry->minor, __entry->ctx) ); -TRACE_EVENT(coda_enc_pic_run, +DECLARE_EVENT_CLASS(coda_buf_class, TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), TP_ARGS(ctx, buf), @@ -69,28 +69,17 @@ TRACE_EVENT(coda_enc_pic_run, __entry->minor, __entry->index, __entry->ctx) ); -TRACE_EVENT(coda_enc_pic_done, +DEFINE_EVENT(coda_buf_class, coda_enc_pic_run, TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), + TP_ARGS(ctx, buf) +); - TP_ARGS(ctx, buf), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, index) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->index = buf->v4l2_buf.index; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, index = %d, ctx = %d", - __entry->minor, __entry->index, __entry->ctx) +DEFINE_EVENT(coda_buf_class, coda_enc_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf), + TP_ARGS(ctx, buf) ); -TRACE_EVENT(coda_bit_queue, +DECLARE_EVENT_CLASS(coda_buf_meta_class, TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, struct coda_buffer_meta *meta), @@ -117,7 +106,13 @@ TRACE_EVENT(coda_bit_queue, __entry->ctx) ); -TRACE_EVENT(coda_dec_pic_run, +DEFINE_EVENT(coda_buf_meta_class, coda_bit_queue, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, + struct coda_buffer_meta *meta), + TP_ARGS(ctx, buf, meta) +); + +DECLARE_EVENT_CLASS(coda_meta_class, TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), TP_ARGS(ctx, meta), @@ -140,54 +135,20 @@ TRACE_EVENT(coda_dec_pic_run, __entry->minor, __entry->start, __entry->end, __entry->ctx) ); -TRACE_EVENT(coda_dec_pic_done, +DEFINE_EVENT(coda_meta_class, coda_dec_pic_run, TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), - - TP_ARGS(ctx, meta), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, start) - __field(int, end) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->start = meta->start; - __entry->end = meta->end; - __entry->ctx = ctx->idx; - ), - - TP_printk("minor = %d, start = 0x%x, end = 0x%x, ctx = %d", - __entry->minor, __entry->start, __entry->end, __entry->ctx) + TP_ARGS(ctx, meta) ); -TRACE_EVENT(coda_dec_rot_done, - TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta, - struct vb2_buffer *buf), - - TP_ARGS(ctx, meta, buf), - - TP_STRUCT__entry( - __field(int, minor) - __field(int, start) - __field(int, end) - __field(int, index) - __field(int, ctx) - ), - - TP_fast_assign( - __entry->minor = ctx->fh.vdev->minor; - __entry->start = meta->start; - __entry->end = meta->end; - __entry->index = buf->v4l2_buf.index; - __entry->ctx = ctx->idx; - ), +DEFINE_EVENT(coda_meta_class, coda_dec_pic_done, + TP_PROTO(struct coda_ctx *ctx, struct coda_buffer_meta *meta), + TP_ARGS(ctx, meta) +); - TP_printk("minor = %d, start = 0x%x, end = 0x%x, index = %d, ctx = %d", - __entry->minor, __entry->start, __entry->end, __entry->index, - __entry->ctx) +DEFINE_EVENT(coda_buf_meta_class, coda_dec_rot_done, + TP_PROTO(struct coda_ctx *ctx, struct vb2_buffer *buf, + struct coda_buffer_meta *meta), + TP_ARGS(ctx, buf, meta) ); #endif /* __CODA_TRACE_H__ */ -- GitLab From 2cf251c0c3961bd467e086033c6073ef62b29b02 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:20 -0300 Subject: [PATCH 1121/7006] [media] coda: reuse src_bufs in coda_job_ready The v4l2_m2m_num_src_bufs_ready() function is called in multiple places in coda_cob_ready, and there already is a variable src_bufs that is assigned to its result. Move it to the beginning and use it everywhere. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index b265edd8d2778..267fda760b38d 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -888,14 +888,14 @@ static void coda_pic_run_work(struct work_struct *work) static int coda_job_ready(void *m2m_priv) { struct coda_ctx *ctx = m2m_priv; + int src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); /* * For both 'P' and 'key' frame cases 1 picture * and 1 frame are needed. In the decoder case, * the compressed frame can be in the bitstream. */ - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - ctx->inst_type != CODA_INST_DECODER) { + if (!src_bufs && ctx->inst_type != CODA_INST_DECODER) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "not ready: not enough video buffers.\n"); return 0; @@ -911,9 +911,8 @@ static int coda_job_ready(void *m2m_priv) struct list_head *meta; bool stream_end; int num_metas; - int src_bufs; - if (ctx->hold && !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) { + if (ctx->hold && !src_bufs) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: on hold for more buffers.\n", ctx->idx); @@ -927,8 +926,6 @@ static int coda_job_ready(void *m2m_priv) list_for_each(meta, &ctx->buffer_meta_list) num_metas++; - src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx); - if (!stream_end && (num_metas + src_bufs) < 2) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: need 2 buffers available (%d, %d)\n", @@ -937,8 +934,8 @@ static int coda_job_ready(void *m2m_priv) } - if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) && - !stream_end && (coda_get_bitstream_payload(ctx) < 512)) { + if (!src_bufs && !stream_end && + (coda_get_bitstream_payload(ctx) < 512)) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: not enough bitstream data (%d).\n", ctx->idx, coda_get_bitstream_payload(ctx)); -- GitLab From 47f3fa63ee5c0e6bdf9c9d5ed73fc791981336e4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 9 Jul 2015 07:10:21 -0300 Subject: [PATCH 1122/7006] [media] coda: rework meta counting and add separate lock Keep count of number of buffer meta structures in the list and use a separate spinlock for operations on this counted list instead of reusing the bitstream mutex in some places and none at all in others. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 16 ++++++++++++++-- drivers/media/platform/coda/coda-common.c | 21 +++++++++------------ drivers/media/platform/coda/coda.h | 2 ++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 226ce4a786ea1..25910ccd2da08 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -226,6 +226,7 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) { struct vb2_buffer *src_buf; struct coda_buffer_meta *meta; + unsigned long flags; u32 start; if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG) @@ -274,8 +275,13 @@ void coda_fill_bitstream(struct coda_ctx *ctx, bool streaming) meta->start = start; meta->end = ctx->bitstream_fifo.kfifo.in & ctx->bitstream_fifo.kfifo.mask; + spin_lock_irqsave(&ctx->buffer_meta_lock, + flags); list_add_tail(&meta->list, &ctx->buffer_meta_list); + ctx->num_metas++; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, + flags); trace_coda_bit_queue(ctx, src_buf, meta); } @@ -1665,6 +1671,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) struct coda_dev *dev = ctx->dev; struct coda_q_data *q_data_dst; struct coda_buffer_meta *meta; + unsigned long flags; u32 reg_addr, reg_stride; dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); @@ -1743,6 +1750,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.axi_sram_use, CODA7_REG_BIT_AXI_SRAM_USE); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); meta = list_first_entry_or_null(&ctx->buffer_meta_list, struct coda_buffer_meta, list); @@ -1762,6 +1770,7 @@ static int coda_prepare_decode(struct coda_ctx *ctx) kfifo_in(&ctx->bitstream_fifo, buf, pad); } } + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); coda_kfifo_sync_to_device_full(ctx); @@ -1783,6 +1792,7 @@ static void coda_finish_decode(struct coda_ctx *ctx) struct vb2_buffer *dst_buf; struct coda_buffer_meta *meta; unsigned long payload; + unsigned long flags; int width, height; int decoded_idx; int display_idx; @@ -1908,11 +1918,13 @@ static void coda_finish_decode(struct coda_ctx *ctx) } else { val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1; val -= ctx->sequence_offset; - mutex_lock(&ctx->bitstream_mutex); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); if (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); + ctx->num_metas--; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); /* * Clamp counters to 16 bits for comparison, as the HW * counter rolls over at this point for h.264. This @@ -1929,13 +1941,13 @@ static void coda_finish_decode(struct coda_ctx *ctx) ctx->frame_metas[decoded_idx] = *meta; kfree(meta); } else { + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n"); memset(&ctx->frame_metas[decoded_idx], 0, sizeof(struct coda_buffer_meta)); ctx->frame_metas[decoded_idx].sequence = val; ctx->sequence_offset++; } - mutex_unlock(&ctx->bitstream_mutex); trace_coda_dec_pic_done(ctx, &ctx->frame_metas[decoded_idx]); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 267fda760b38d..367b6baa8f31b 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -908,9 +908,9 @@ static int coda_job_ready(void *m2m_priv) } if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) { - struct list_head *meta; - bool stream_end; - int num_metas; + bool stream_end = ctx->bit_stream_param & + CODA_BIT_STREAM_END_FLAG; + int num_metas = ctx->num_metas; if (ctx->hold && !src_bufs) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, @@ -919,13 +919,6 @@ static int coda_job_ready(void *m2m_priv) return 0; } - stream_end = ctx->bit_stream_param & - CODA_BIT_STREAM_END_FLAG; - - num_metas = 0; - list_for_each(meta, &ctx->buffer_meta_list) - num_metas++; - if (!stream_end && (num_metas + src_bufs) < 2) { v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "%d: not ready: need 2 buffers available (%d, %d)\n", @@ -951,6 +944,7 @@ static int coda_job_ready(void *m2m_priv) v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "job ready\n"); + return 1; } @@ -1267,6 +1261,7 @@ static void coda_stop_streaming(struct vb2_queue *q) struct coda_ctx *ctx = vb2_get_drv_priv(q); struct coda_dev *dev = ctx->dev; struct vb2_buffer *buf; + unsigned long flags; bool stop; stop = ctx->streamon_out && ctx->streamon_cap; @@ -1301,14 +1296,15 @@ static void coda_stop_streaming(struct vb2_queue *q) queue_work(dev->workqueue, &ctx->seq_end_work); flush_work(&ctx->seq_end_work); } - mutex_lock(&ctx->bitstream_mutex); + spin_lock_irqsave(&ctx->buffer_meta_lock, flags); while (!list_empty(&ctx->buffer_meta_list)) { meta = list_first_entry(&ctx->buffer_meta_list, struct coda_buffer_meta, list); list_del(&meta->list); kfree(meta); } - mutex_unlock(&ctx->bitstream_mutex); + ctx->num_metas = 0; + spin_unlock_irqrestore(&ctx->buffer_meta_lock, flags); kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); ctx->runcounter = 0; @@ -1661,6 +1657,7 @@ static int coda_open(struct file *file) mutex_init(&ctx->bitstream_mutex); mutex_init(&ctx->buffer_mutex); INIT_LIST_HEAD(&ctx->buffer_meta_list); + spin_lock_init(&ctx->buffer_meta_lock); coda_lock(ctx); list_add(&ctx->list, &dev->instances); diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 8e0af221b2e9e..a3d70ccd10204 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -227,6 +227,8 @@ struct coda_ctx { struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS]; u32 frame_errors[CODA_MAX_FRAMEBUFFERS]; struct list_head buffer_meta_list; + spinlock_t buffer_meta_lock; + int num_metas; struct coda_aux_buf workbuf; int num_internal_frames; int idx; -- GitLab From 68aa7ee15cd683006ec1ac91ad60c019bf62d978 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:37:44 -0300 Subject: [PATCH 1123/7006] [media] coda: reset CODA960 hardware after sequence end On i.MX6, sometimes after decoding a stream, encoding will produce macroblock errors caused by missing 8-byte sequences in the output stream. Until the cause for this is found, reset the hardware after sequence end, which seems to help. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 25910ccd2da08..bcb9911d5e3f1 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -1347,6 +1347,14 @@ static void coda_seq_end_work(struct work_struct *work) "CODA_COMMAND_SEQ_END failed\n"); } + /* + * FIXME: Sometimes h.264 encoding fails with 8-byte sequences missing + * from the output stream after the h.264 decoder has run. Resetting the + * hardware after the decoder has finished seems to help. + */ + if (dev->devtype->product == CODA_960) + coda_hw_reset(ctx); + kfifo_init(&ctx->bitstream_fifo, ctx->bitstream.vaddr, ctx->bitstream.size); -- GitLab From da2b3b3e115d2793b5475039ca4d7f364135fcf4 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:37:52 -0300 Subject: [PATCH 1124/7006] [media] coda: implement VBV delay and buffer size controls The encoder allows to specify the VBV model reference decoder's initial delay and buffer size. Export the corresponding V4L2 controls. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 5 ++++- drivers/media/platform/coda/coda-common.c | 14 ++++++++++++++ drivers/media/platform/coda/coda.h | 2 ++ 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index bcb9911d5e3f1..b14affcf8dc01 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -922,6 +922,9 @@ static int coda_start_encoding(struct coda_ctx *ctx) value = (ctx->params.bitrate & CODA_RATECONTROL_BITRATE_MASK) << CODA_RATECONTROL_BITRATE_OFFSET; value |= 1 & CODA_RATECONTROL_ENABLE_MASK; + value |= (ctx->params.vbv_delay & + CODA_RATECONTROL_INITIALDELAY_MASK) + << CODA_RATECONTROL_INITIALDELAY_OFFSET; if (dev->devtype->product == CODA_960) value |= BIT(31); /* disable autoskip */ } else { @@ -929,7 +932,7 @@ static int coda_start_encoding(struct coda_ctx *ctx) } coda_write(dev, value, CODA_CMD_ENC_SEQ_RC_PARA); - coda_write(dev, 0, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); + coda_write(dev, ctx->params.vbv_size, CODA_CMD_ENC_SEQ_RC_BUF_SIZE); coda_write(dev, ctx->params.intra_refresh, CODA_CMD_ENC_SEQ_INTRA_REFRESH); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 367b6baa8f31b..24737f1a1a1bb 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -1400,6 +1400,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_JPEG_RESTART_INTERVAL: ctx->params.jpeg_restart_interval = ctrl->val; break; + case V4L2_CID_MPEG_VIDEO_VBV_DELAY: + ctx->params.vbv_delay = ctrl->val; + break; + case V4L2_CID_MPEG_VIDEO_VBV_SIZE: + ctx->params.vbv_size = min(ctrl->val * 8192, 0x7fffffff); + break; default: v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Invalid control, id=%d, val=%d\n", @@ -1459,6 +1465,14 @@ static void coda_encode_ctrls(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0, 1920 * 1088 / 256, 1, 0); + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_DELAY, 0, 0x7fff, 1, 0); + /* + * The maximum VBV size value is 0x7fffffff bits, + * one bit less than 262144 KiB + */ + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MPEG_VIDEO_VBV_SIZE, 0, 262144, 1, 0); } static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index a3d70ccd10204..26c9c4bb6e4a4 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -128,6 +128,8 @@ struct coda_params { enum v4l2_mpeg_video_multi_slice_mode slice_mode; u32 framerate; u16 bitrate; + u16 vbv_delay; + u32 vbv_size; u32 slice_max_bits; u32 slice_max_mb; }; -- GitLab From cde29ef313de391ec9a1e461458274623ab1eb87 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:13:24 -0300 Subject: [PATCH 1125/7006] [media] coda: Use S_PARM to set nominal framerate for h.264 encoder The encoder needs to know the nominal framerate for the constant bitrate control mechanism to work. Currently the only way to set the framerate is by using VIDIOC_S_PARM on the output queue. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 102 ++++++++++++++++++++++ drivers/media/platform/coda/coda_regs.h | 4 + 2 files changed, 106 insertions(+) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 24737f1a1a1bb..a7cab14d10c96 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -770,6 +771,104 @@ static int coda_decoder_cmd(struct file *file, void *fh, return 0; } +static int coda_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + a->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + tpf = &a->parm.output.timeperframe; + tpf->denominator = ctx->params.framerate & CODA_FRATE_RES_MASK; + tpf->numerator = 1 + (ctx->params.framerate >> + CODA_FRATE_DIV_OFFSET); + + return 0; +} + +/* + * Approximate timeperframe v4l2_fract with values that can be written + * into the 16-bit CODA_FRATE_DIV and CODA_FRATE_RES fields. + */ +static void coda_approximate_timeperframe(struct v4l2_fract *timeperframe) +{ + struct v4l2_fract s = *timeperframe; + struct v4l2_fract f0; + struct v4l2_fract f1 = { 1, 0 }; + struct v4l2_fract f2 = { 0, 1 }; + unsigned int i, div, s_denominator; + + /* Lower bound is 1/65535 */ + if (s.numerator == 0 || s.denominator / s.numerator > 65535) { + timeperframe->numerator = 1; + timeperframe->denominator = 65535; + return; + } + + /* Upper bound is 65536/1, map everything above to infinity */ + if (s.denominator == 0 || s.numerator / s.denominator > 65536) { + timeperframe->numerator = 1; + timeperframe->denominator = 0; + return; + } + + /* Reduce fraction to lowest terms */ + div = gcd(s.numerator, s.denominator); + if (div > 1) { + s.numerator /= div; + s.denominator /= div; + } + + if (s.numerator <= 65536 && s.denominator < 65536) { + *timeperframe = s; + return; + } + + /* Find successive convergents from continued fraction expansion */ + while (f2.numerator <= 65536 && f2.denominator < 65536) { + f0 = f1; + f1 = f2; + + /* Stop when f2 exactly equals timeperframe */ + if (s.numerator == 0) + break; + + i = s.denominator / s.numerator; + + f2.numerator = f0.numerator + i * f1.numerator; + f2.denominator = f0.denominator + i * f2.denominator; + + s_denominator = s.numerator; + s.numerator = s.denominator % s.numerator; + s.denominator = s_denominator; + } + + *timeperframe = f1; +} + +static uint32_t coda_timeperframe_to_frate(struct v4l2_fract *timeperframe) +{ + return ((timeperframe->numerator - 1) << CODA_FRATE_DIV_OFFSET) | + timeperframe->denominator; +} + +static int coda_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct v4l2_fract *tpf; + + if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + tpf = &a->parm.output.timeperframe; + coda_approximate_timeperframe(tpf); + ctx->params.framerate = coda_timeperframe_to_frate(tpf); + + return 0; +} + static int coda_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) { @@ -810,6 +909,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_try_decoder_cmd = coda_try_decoder_cmd, .vidioc_decoder_cmd = coda_decoder_cmd, + .vidioc_g_parm = coda_g_parm, + .vidioc_s_parm = coda_s_parm, + .vidioc_subscribe_event = coda_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 7d026241171bc..00e4f5160c1f2 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -263,6 +263,10 @@ #define CODADX6_PICHEIGHT_MASK 0x3ff #define CODA7_PICHEIGHT_MASK 0xffff #define CODA_CMD_ENC_SEQ_SRC_F_RATE 0x194 +#define CODA_FRATE_RES_OFFSET 0 +#define CODA_FRATE_RES_MASK 0xffff +#define CODA_FRATE_DIV_OFFSET 16 +#define CODA_FRATE_DIV_MASK 0xffff #define CODA_CMD_ENC_SEQ_MP4_PARA 0x198 #define CODA_MP4PARAM_VERID_OFFSET 6 #define CODA_MP4PARAM_VERID_MASK 0x01 -- GitLab From 4e447ff199cfc4bc04ddb515d3d9ab46bb19530a Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:19:37 -0300 Subject: [PATCH 1126/7006] [media] coda: move cache setup into coda9_set_frame_cache, also use it in start_encoding The frame cache should be set up correctly to encode NV12 source frames. This was not done before, so move the cache setup out of start_decoding into its own function and call it from both start_encoding and start_decoding. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-bit.c | 45 ++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b14affcf8dc01..46c70547fc12f 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -721,6 +721,26 @@ err_clk_per: return ret; } +static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) +{ + u32 cache_size, cache_config; + + /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ + cache_size = 0x20262024; + cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); + if (fourcc == V4L2_PIX_FMT_NV12) { + cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 16 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | + 0 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; + } else { + cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET | + 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET; + } + coda_write(ctx->dev, cache_config, CODA9_CMD_SET_FRAME_CACHE_CONFIG); +} + /* * Encoder context operations */ @@ -1049,6 +1069,8 @@ static int coda_start_encoding(struct coda_ctx *ctx) coda_write(dev, ctx->iram_info.buf_btp_use, CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); + coda9_set_frame_cache(ctx, q_data_src->fourcc); + /* FIXME */ coda_write(dev, ctx->internal_frames[2].paddr, CODA9_CMD_SET_FRAME_SUBSAMP_A); @@ -1606,30 +1628,13 @@ static int __coda_start_decoding(struct coda_ctx *ctx) CODA7_CMD_SET_FRAME_AXI_DBKC_ADDR); coda_write(dev, ctx->iram_info.buf_ovl_use, CODA7_CMD_SET_FRAME_AXI_OVL_ADDR); - if (dev->devtype->product == CODA_960) + if (dev->devtype->product == CODA_960) { coda_write(dev, ctx->iram_info.buf_btp_use, CODA9_CMD_SET_FRAME_AXI_BTP_ADDR); - } - - if (dev->devtype->product == CODA_960) { - int cbb_size, crb_size; - - coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); - /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ - coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE); - if (dst_fourcc == V4L2_PIX_FMT_NV12) { - cbb_size = 0; - crb_size = 16; - } else { - cbb_size = 8; - crb_size = 8; + coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY); + coda9_set_frame_cache(ctx, dst_fourcc); } - coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET | - 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | - cbb_size << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET | - crb_size << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET, - CODA9_CMD_SET_FRAME_CACHE_CONFIG); } if (src_fourcc == V4L2_PIX_FMT_H264) { -- GitLab From fbce23a0b95763dfc4961ce6240e055c39f497ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 17 Jul 2015 16:27:33 +0200 Subject: [PATCH 1127/7006] ALSA: hda - Check the return value from pm_runtime_get/put*() This patch changes the return type of snd_hdac_power_up/down() and variants to pass the error code from the underlying pm_runtime_get/put() calls. Currently they are ignored, but in most places, these should be handled properly. As an example, the regmap handler is updated to check the return value and accesses the register only when the wakeup succeeds. Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 16 ++++++++-------- sound/hda/hdac_device.c | 26 ++++++++++++++++++-------- sound/hda/hdac_regmap.c | 10 ++++++---- 3 files changed, 32 insertions(+), 20 deletions(-) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 4caf1fde8a4f8..288c7fa509d84 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -164,15 +164,15 @@ static inline int snd_hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, } #ifdef CONFIG_PM -void snd_hdac_power_up(struct hdac_device *codec); -void snd_hdac_power_down(struct hdac_device *codec); -void snd_hdac_power_up_pm(struct hdac_device *codec); -void snd_hdac_power_down_pm(struct hdac_device *codec); +int snd_hdac_power_up(struct hdac_device *codec); +int snd_hdac_power_down(struct hdac_device *codec); +int snd_hdac_power_up_pm(struct hdac_device *codec); +int snd_hdac_power_down_pm(struct hdac_device *codec); #else -static inline void snd_hdac_power_up(struct hdac_device *codec) {} -static inline void snd_hdac_power_down(struct hdac_device *codec) {} -static inline void snd_hdac_power_up_pm(struct hdac_device *codec) {} -static inline void snd_hdac_power_down_pm(struct hdac_device *codec) {} +static inline int snd_hdac_power_up(struct hdac_device *codec) { return 0; } +static inline int snd_hdac_power_down(struct hdac_device *codec) { return 0; } +static inline int snd_hdac_power_up_pm(struct hdac_device *codec) { return 0; } +static inline int snd_hdac_power_down_pm(struct hdac_device *codec) { return 0; } #endif /* diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index cdee7103f6492..df7039ebe1faa 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -501,23 +501,27 @@ EXPORT_SYMBOL_GPL(snd_hdac_get_connections); * This function calls the runtime PM helper to power up the given codec. * Unlike snd_hdac_power_up_pm(), you should call this only for the code * path that isn't included in PM path. Otherwise it gets stuck. + * + * Returns zero if successful, or a negative error code. */ -void snd_hdac_power_up(struct hdac_device *codec) +int snd_hdac_power_up(struct hdac_device *codec) { - pm_runtime_get_sync(&codec->dev); + return pm_runtime_get_sync(&codec->dev); } EXPORT_SYMBOL_GPL(snd_hdac_power_up); /** * snd_hdac_power_down - power down the codec * @codec: the codec object + * + * Returns zero if successful, or a negative error code. */ -void snd_hdac_power_down(struct hdac_device *codec) +int snd_hdac_power_down(struct hdac_device *codec) { struct device *dev = &codec->dev; pm_runtime_mark_last_busy(dev); - pm_runtime_put_autosuspend(dev); + return pm_runtime_put_autosuspend(dev); } EXPORT_SYMBOL_GPL(snd_hdac_power_down); @@ -529,11 +533,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_power_down); * which may be called by PM suspend/resume again. OTOH, if a power-up * call must wake up the sleeper (e.g. in a kctl callback), use * snd_hdac_power_up() instead. + * + * Returns zero if successful, or a negative error code. */ -void snd_hdac_power_up_pm(struct hdac_device *codec) +int snd_hdac_power_up_pm(struct hdac_device *codec) { if (!atomic_inc_not_zero(&codec->in_pm)) - snd_hdac_power_up(codec); + return snd_hdac_power_up(codec); + return 0; } EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm); @@ -543,11 +550,14 @@ EXPORT_SYMBOL_GPL(snd_hdac_power_up_pm); * * Like snd_hdac_power_up_pm(), this function is used in a recursive * code path like init code which may be called by PM suspend/resume again. + * + * Returns zero if successful, or a negative error code. */ -void snd_hdac_power_down_pm(struct hdac_device *codec) +int snd_hdac_power_down_pm(struct hdac_device *codec) { if (atomic_dec_if_positive(&codec->in_pm) < 0) - snd_hdac_power_down(codec); + return snd_hdac_power_down(codec); + return 0; } EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); #endif diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index 1eabcdf694573..b0ed870ffb88e 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c @@ -410,8 +410,9 @@ int snd_hdac_regmap_write_raw(struct hdac_device *codec, unsigned int reg, err = reg_raw_write(codec, reg, val); if (err == -EAGAIN) { - snd_hdac_power_up_pm(codec); - err = reg_raw_write(codec, reg, val); + err = snd_hdac_power_up_pm(codec); + if (!err) + err = reg_raw_write(codec, reg, val); snd_hdac_power_down_pm(codec); } return err; @@ -442,8 +443,9 @@ int snd_hdac_regmap_read_raw(struct hdac_device *codec, unsigned int reg, err = reg_raw_read(codec, reg, val); if (err == -EAGAIN) { - snd_hdac_power_up_pm(codec); - err = reg_raw_read(codec, reg, val); + err = snd_hdac_power_up_pm(codec); + if (!err) + err = reg_raw_read(codec, reg, val); snd_hdac_power_down_pm(codec); } return err; -- GitLab From a269e53b1aa87157311e53e5b69699ba8f3ba4d0 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:19:38 -0300 Subject: [PATCH 1128/7006] [media] coda: add macroblock tiling support Storing internal frames in macroblock tiled order improves memory access patterns by allowing increased burst sizes when transferring the uncompressed macroblocks to or from main memory. The translation logic only supports a single chroma base address, so this is only supported for the chroma interleaved NV12 format. Since the rotator used to copy the decoder output into the v4l2 capture buffers does not seem to support the tiled format correctly, only enable it in the encoder for now. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/Makefile | 2 +- drivers/media/platform/coda/coda-bit.c | 48 +++++-- drivers/media/platform/coda/coda-common.c | 74 ++++------- drivers/media/platform/coda/coda-gdi.c | 150 ++++++++++++++++++++++ drivers/media/platform/coda/coda.h | 11 +- drivers/media/platform/coda/coda_regs.h | 6 + 6 files changed, 221 insertions(+), 70 deletions(-) create mode 100644 drivers/media/platform/coda/coda-gdi.c diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile index 834e504bf0854..9342ac57b2306 100644 --- a/drivers/media/platform/coda/Makefile +++ b/drivers/media/platform/coda/Makefile @@ -1,5 +1,5 @@ ccflags-y += -I$(src) -coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o +coda-objs := coda-common.o coda-bit.o coda-gdi.o coda-h264.o coda-jpeg.o obj-$(CONFIG_VIDEO_CODA) += coda.o diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index 46c70547fc12f..3d434a4ed537d 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -340,7 +340,6 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, { struct coda_dev *dev = ctx->dev; int width, height; - dma_addr_t paddr; int ysize; int ret; int i; @@ -360,7 +359,10 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, size_t size; char *name; - size = ysize + ysize / 2; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + size = round_up(ysize, 4096) + ysize / 2; + else + size = ysize + ysize / 2; if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != CODA_DX6) size += ysize / 4; @@ -376,11 +378,23 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, /* Register frame buffers in the parameter buffer */ for (i = 0; i < ctx->num_internal_frames; i++) { - paddr = ctx->internal_frames[i].paddr; + u32 y, cb, cr; + /* Start addresses of Y, Cb, Cr planes */ - coda_parabuf_write(ctx, i * 3 + 0, paddr); - coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); - coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize / 4); + y = ctx->internal_frames[i].paddr; + cb = y + ysize; + cr = y + ysize + ysize/4; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) { + cb = round_up(cb, 4096); + cr = 0; + /* Packed 20-bit MSB of base addresses */ + /* YYYYYCCC, CCyyyyyc, cccc.... */ + y = (y & 0xfffff000) | cb >> 20; + cb = (cb & 0x000ff000) << 12; + } + coda_parabuf_write(ctx, i * 3 + 0, y); + coda_parabuf_write(ctx, i * 3 + 1, cb); + coda_parabuf_write(ctx, i * 3 + 2, cr); /* mvcol buffer for h.264 */ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 && @@ -725,9 +739,15 @@ static void coda9_set_frame_cache(struct coda_ctx *ctx, u32 fourcc) { u32 cache_size, cache_config; - /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ - cache_size = 0x20262024; - cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + if (ctx->tiled_map_type == GDI_LINEAR_FRAME_MAP) { + /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */ + cache_size = 0x20262024; + cache_config = 2 << CODA9_CACHE_PAGEMERGE_OFFSET; + } else { + /* Luma 0x2 page, 4x4 cache, chroma 0x2 page, 4x3 cache size */ + cache_size = 0x02440243; + cache_config = 1 << CODA9_CACHE_PAGEMERGE_OFFSET; + } coda_write(ctx->dev, cache_size, CODA9_CMD_SET_FRAME_CACHE_SIZE); if (fourcc == V4L2_PIX_FMT_NV12) { cache_config |= 32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET | @@ -818,9 +838,12 @@ static int coda_start_encoding(struct coda_ctx *ctx) break; } - ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE; + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); if (q_data_src->fourcc == V4L2_PIX_FMT_NV12) ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); if (dev->devtype->product == CODA_DX6) { @@ -1497,9 +1520,12 @@ static int __coda_start_decoding(struct coda_ctx *ctx) /* Update coda bitstream read and write pointers from kfifo */ coda_kfifo_sync_to_device_full(ctx); - ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE; + ctx->frame_mem_ctrl &= ~(CODA_FRAME_CHROMA_INTERLEAVE | (0x3 << 9) | + CODA9_FRAME_TILED2LINEAR); if (dst_fourcc == V4L2_PIX_FMT_NV12) ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE; + if (ctx->tiled_map_type == GDI_TILED_FRAME_MB_RASTER_MAP) + ctx->frame_mem_ctrl |= (0x3 << 9) | CODA9_FRAME_TILED2LINEAR; coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL); ctx->display_idx = -1; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index a7cab14d10c96..d62b828460378 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -62,6 +62,10 @@ int coda_debug; module_param(coda_debug, int, 0644); MODULE_PARM_DESC(coda_debug, "Debug level (0-2)"); +static int disable_tiling; +module_param(disable_tiling, int, 0644); +MODULE_PARM_DESC(disable_tiling, "Disable tiled frame buffers"); + void coda_write(struct coda_dev *dev, u32 data, u32 reg) { v4l2_dbg(2, coda_debug, &dev->v4l2_dev, @@ -585,6 +589,22 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f) q_data->rect.width = f->fmt.pix.width; q_data->rect.height = f->fmt.pix.height; + switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP; + if (!disable_tiling) + break; + } + /* else fall through */ + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YVU420: + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; + break; + default: + break; + } + v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev, "Setting format for type %d, wxh: %dx%d, fmt: %d\n", f->type, q_data->width, q_data->height, q_data->fourcc); @@ -916,27 +936,6 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -void coda_set_gdi_regs(struct coda_ctx *ctx) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - struct coda_dev *dev = ctx->dev; - int i; - - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ca_map[i], - CODA9_GDI_XY2_CAS_0 + 4 * i); - for (i = 0; i < 4; i++) - coda_write(dev, tiled_map->xy2ba_map[i], - CODA9_GDI_XY2_BA_0 + 4 * i); - for (i = 0; i < 16; i++) - coda_write(dev, tiled_map->xy2ra_map[i], - CODA9_GDI_XY2_RAS_0 + 4 * i); - coda_write(dev, tiled_map->xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); - for (i = 0; i < 32; i++) - coda_write(dev, tiled_map->rbc2axi_map[i], - CODA9_GDI_RBC2_AXI_0 + 4 * i); -} - /* * Mem-to-mem operations. */ @@ -1084,32 +1083,6 @@ static const struct v4l2_m2m_ops coda_m2m_ops = { .unlock = coda_unlock, }; -static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type) -{ - struct gdi_tiled_map *tiled_map = &ctx->tiled_map; - int luma_map, chro_map, i; - - memset(tiled_map, 0, sizeof(*tiled_map)); - - luma_map = 64; - chro_map = 64; - tiled_map->map_type = tiled_map_type; - for (i = 0; i < 16; i++) - tiled_map->xy2ca_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 4; i++) - tiled_map->xy2ba_map[i] = luma_map << 8 | chro_map; - for (i = 0; i < 16; i++) - tiled_map->xy2ra_map[i] = luma_map << 8 | chro_map; - - if (tiled_map_type == GDI_LINEAR_FRAME_MAP) { - tiled_map->xy2rbc_config = 0; - } else { - dev_err(&ctx->dev->plat_dev->dev, "invalid map type: %d\n", - tiled_map_type); - return; - } -} - static void set_default_params(struct coda_ctx *ctx) { unsigned int max_w, max_h, usize, csize; @@ -1148,8 +1121,11 @@ static void set_default_params(struct coda_ctx *ctx) ctx->q_data[V4L2_M2M_DST].rect.width = max_w; ctx->q_data[V4L2_M2M_DST].rect.height = max_h; - if (ctx->dev->devtype->product == CODA_960) - coda_set_tiled_map_type(ctx, GDI_LINEAR_FRAME_MAP); + /* + * Since the RBC2AXI logic only supports a single chroma plane, + * macroblock tiling only works for to NV12 pixel format. + */ + ctx->tiled_map_type = GDI_LINEAR_FRAME_MAP; } /* diff --git a/drivers/media/platform/coda/coda-gdi.c b/drivers/media/platform/coda/coda-gdi.c new file mode 100644 index 0000000000000..aaa7afc6870f5 --- /dev/null +++ b/drivers/media/platform/coda/coda-gdi.c @@ -0,0 +1,150 @@ +/* + * Coda multi-standard codec IP + * + * Copyright (C) 2014 Philipp Zabel, Pengutronix + * + * 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 +#include "coda.h" + +#define XY2_INVERT BIT(7) +#define XY2_ZERO BIT(6) +#define XY2_TB_XOR BIT(5) +#define XY2_XYSEL BIT(4) +#define XY2_Y (1 << 4) +#define XY2_X (0 << 4) + +#define XY2(luma_sel, luma_bit, chroma_sel, chroma_bit) \ + (((XY2_##luma_sel) | (luma_bit)) << 8 | \ + (XY2_##chroma_sel) | (chroma_bit)) + +static const u16 xy2ca_zero_map[16] = { + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), +}; + +static const u16 xy2ca_tiled_map[16] = { + XY2(Y, 0, Y, 0), + XY2(Y, 1, Y, 1), + XY2(Y, 2, Y, 2), + XY2(Y, 3, X, 3), + XY2(X, 3, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), + XY2(ZERO, 0, ZERO, 0), +}; + +/* + * RA[15:0], CA[15:8] are hardwired to contain the 24-bit macroblock + * start offset (macroblock size is 16x16 for luma, 16x8 for chroma). + * Bits CA[4:0] are set using XY2CA above. BA[3:0] seems to be unused. + */ + +#define RBC_CA (0 << 4) +#define RBC_BA (1 << 4) +#define RBC_RA (2 << 4) +#define RBC_ZERO (3 << 4) + +#define RBC(luma_sel, luma_bit, chroma_sel, chroma_bit) \ + (((RBC_##luma_sel) | (luma_bit)) << 6 | \ + (RBC_##chroma_sel) | (chroma_bit)) + +static const u16 rbc2axi_tiled_map[32] = { + RBC(ZERO, 0, ZERO, 0), + RBC(ZERO, 0, ZERO, 0), + RBC(ZERO, 0, ZERO, 0), + RBC(CA, 0, CA, 0), + RBC(CA, 1, CA, 1), + RBC(CA, 2, CA, 2), + RBC(CA, 3, CA, 3), + RBC(CA, 4, CA, 8), + RBC(CA, 8, CA, 9), + RBC(CA, 9, CA, 10), + RBC(CA, 10, CA, 11), + RBC(CA, 11, CA, 12), + RBC(CA, 12, CA, 13), + RBC(CA, 13, CA, 14), + RBC(CA, 14, CA, 15), + RBC(CA, 15, RA, 0), + RBC(RA, 0, RA, 1), + RBC(RA, 1, RA, 2), + RBC(RA, 2, RA, 3), + RBC(RA, 3, RA, 4), + RBC(RA, 4, RA, 5), + RBC(RA, 5, RA, 6), + RBC(RA, 6, RA, 7), + RBC(RA, 7, RA, 8), + RBC(RA, 8, RA, 9), + RBC(RA, 9, RA, 10), + RBC(RA, 10, RA, 11), + RBC(RA, 11, RA, 12), + RBC(RA, 12, RA, 13), + RBC(RA, 13, RA, 14), + RBC(RA, 14, RA, 15), + RBC(RA, 15, ZERO, 0), +}; + +void coda_set_gdi_regs(struct coda_ctx *ctx) +{ + struct coda_dev *dev = ctx->dev; + const u16 *xy2ca_map; + u32 xy2rbc_config; + int i; + + switch (ctx->tiled_map_type) { + case GDI_LINEAR_FRAME_MAP: + default: + xy2ca_map = xy2ca_zero_map; + xy2rbc_config = 0; + break; + case GDI_TILED_FRAME_MB_RASTER_MAP: + xy2ca_map = xy2ca_tiled_map; + xy2rbc_config = CODA9_XY2RBC_TILED_MAP | + CODA9_XY2RBC_CA_INC_HOR | + (16 - 1) << 12 | (8 - 1) << 4; + break; + } + + for (i = 0; i < 16; i++) + coda_write(dev, xy2ca_map[i], + CODA9_GDI_XY2_CAS_0 + 4 * i); + for (i = 0; i < 4; i++) + coda_write(dev, XY2(ZERO, 0, ZERO, 0), + CODA9_GDI_XY2_BA_0 + 4 * i); + for (i = 0; i < 16; i++) + coda_write(dev, XY2(ZERO, 0, ZERO, 0), + CODA9_GDI_XY2_RAS_0 + 4 * i); + coda_write(dev, xy2rbc_config, CODA9_GDI_XY2_RBC_CONFIG); + if (xy2rbc_config) { + for (i = 0; i < 32; i++) + coda_write(dev, rbc2axi_tiled_map[i], + CODA9_GDI_RBC2_AXI_0 + 4 * i); + } +} diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h index 26c9c4bb6e4a4..59b2af9c77492 100644 --- a/drivers/media/platform/coda/coda.h +++ b/drivers/media/platform/coda/coda.h @@ -167,15 +167,8 @@ struct coda_iram_info { phys_addr_t next_paddr; }; -struct gdi_tiled_map { - int xy2ca_map[16]; - int xy2ba_map[16]; - int xy2ra_map[16]; - int rbc2axi_map[32]; - int xy2rbc_config; - int map_type; #define GDI_LINEAR_FRAME_MAP 0 -}; +#define GDI_TILED_FRAME_MB_RASTER_MAP 1 struct coda_ctx; @@ -236,7 +229,7 @@ struct coda_ctx { int idx; int reg_idx; struct coda_iram_info iram_info; - struct gdi_tiled_map tiled_map; + int tiled_map_type; u32 bit_stream_param; u32 frm_dis_flg; u32 frame_mem_ctrl; diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h index 00e4f5160c1f2..3490602fa6e1e 100644 --- a/drivers/media/platform/coda/coda_regs.h +++ b/drivers/media/platform/coda/coda_regs.h @@ -51,6 +51,7 @@ #define CODA7_STREAM_SEL_64BITS_ENDIAN (1 << 1) #define CODA_STREAM_ENDIAN_SELECT (1 << 0) #define CODA_REG_BIT_FRAME_MEM_CTRL 0x110 +#define CODA9_FRAME_TILED2LINEAR (1 << 11) #define CODA_FRAME_CHROMA_INTERLEAVE (1 << 2) #define CODA_IMAGE_ENDIAN_SELECT (1 << 0) #define CODA_REG_BIT_BIT_STREAM_PARAM 0x114 @@ -452,7 +453,12 @@ #define CODA9_GDI_XY2_RAS_F (CODA9_GDMA_BASE + 0x88c) #define CODA9_GDI_XY2_RBC_CONFIG (CODA9_GDMA_BASE + 0x890) +#define CODA9_XY2RBC_SEPARATE_MAP BIT(19) +#define CODA9_XY2RBC_TOP_BOT_SPLIT BIT(18) +#define CODA9_XY2RBC_TILED_MAP BIT(17) +#define CODA9_XY2RBC_CA_INC_HOR BIT(16) #define CODA9_GDI_RBC2_AXI_0 (CODA9_GDMA_BASE + 0x8a0) #define CODA9_GDI_RBC2_AXI_1F (CODA9_GDMA_BASE + 0x91c) +#define CODA9_GDI_TILEDBUF_BASE (CODA9_GDMA_BASE + 0x920) #endif -- GitLab From 6727d4fce95586e60922bdaf57b8a0eb99482557 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 16 Jul 2015 13:19:39 -0300 Subject: [PATCH 1129/7006] [media] coda: make NV12 format default The chroma interleaved NV12 format has higher memory bandwidth efficiency because the chroma planes can be read/written with longer burst lengths. Use NV12 as default format if available and consistently sort it first. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 28 +++++++++++------------ 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index d62b828460378..04310cd35bc1a 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -90,17 +90,17 @@ void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 base_cb, base_cr; switch (q_data->fourcc) { - case V4L2_PIX_FMT_YVU420: - /* Switch Cb and Cr for YVU420 format */ - base_cr = base_y + q_data->bytesperline * q_data->height; - base_cb = base_cr + q_data->bytesperline * q_data->height / 4; - break; - case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_YUV420: default: base_cb = base_y + q_data->bytesperline * q_data->height; base_cr = base_cb + q_data->bytesperline * q_data->height / 4; break; + case V4L2_PIX_FMT_YVU420: + /* Switch Cb and Cr for YVU420 format */ + base_cr = base_y + q_data->bytesperline * q_data->height; + base_cb = base_cr + q_data->bytesperline * q_data->height / 4; + break; case V4L2_PIX_FMT_YUV422P: base_cb = base_y + q_data->bytesperline * q_data->height; base_cr = base_cb + q_data->bytesperline * q_data->height / 2; @@ -156,9 +156,9 @@ static const struct coda_video_device coda_bit_encoder = { .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, }, .dst_formats = { V4L2_PIX_FMT_H264, @@ -171,9 +171,9 @@ static const struct coda_video_device coda_bit_jpeg_encoder = { .type = CODA_INST_ENCODER, .ops = &coda_bit_encode_ops, .src_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV422P, }, .dst_formats = { @@ -190,9 +190,9 @@ static const struct coda_video_device coda_bit_decoder = { V4L2_PIX_FMT_MPEG4, }, .dst_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, }, }; @@ -204,9 +204,9 @@ static const struct coda_video_device coda_bit_jpeg_decoder = { V4L2_PIX_FMT_JPEG, }, .dst_formats = { + V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, - V4L2_PIX_FMT_NV12, V4L2_PIX_FMT_YUV422P, }, }; @@ -234,9 +234,9 @@ static const struct coda_video_device *coda9_video_devices[] = { static u32 coda_format_normalize_yuv(u32 fourcc) { switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV422P: return V4L2_PIX_FMT_YUV420; default: @@ -448,9 +448,9 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec, S_ALIGN); switch (f->fmt.pix.pixelformat) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: - case V4L2_PIX_FMT_NV12: /* * Frame stride must be at least multiple of 8, * but multiple of 16 for h.264 or JPEG 4:2:x @@ -1099,8 +1099,8 @@ static void set_default_params(struct coda_ctx *ctx) ctx->params.framerate = 30; /* Default formats for output and input queues */ - ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc; - ctx->q_data[V4L2_M2M_DST].fourcc = ctx->codec->dst_fourcc; + ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->cvd->src_formats[0]; + ctx->q_data[V4L2_M2M_DST].fourcc = ctx->cvd->dst_formats[0]; ctx->q_data[V4L2_M2M_SRC].width = max_w; ctx->q_data[V4L2_M2M_SRC].height = max_h; ctx->q_data[V4L2_M2M_DST].width = max_w; -- GitLab From b54e5ed8f285d62c0d242c4ef9da90937994db02 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2015 11:16:44 +0800 Subject: [PATCH 1130/7006] block: partition: introduce hd_free_part() So the helper can be used in both generic partition case and part0 case. Signed-off-by: Ming Lei Signed-off-by: Jens Axboe --- block/genhd.c | 3 +-- block/partition-generic.c | 3 +-- include/linux/genhd.h | 6 ++++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 59a1395eedac4..85df45292dbaf 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1110,8 +1110,7 @@ static void disk_release(struct device *dev) disk_release_events(disk); kfree(disk->random); disk_replace_part_tbl(disk, NULL); - free_part_stats(&disk->part0); - free_part_info(&disk->part0); + hd_free_part(&disk->part0); if (disk->queue) blk_put_queue(disk->queue); kfree(disk); diff --git a/block/partition-generic.c b/block/partition-generic.c index 0d9e5f97f0a8a..eca0d02a607c2 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -212,8 +212,7 @@ static void part_release(struct device *dev) { struct hd_struct *p = dev_to_part(dev); blk_free_devt(dev->devt); - free_part_stats(p); - free_part_info(p); + hd_free_part(p); kfree(p); } diff --git a/include/linux/genhd.h b/include/linux/genhd.h index ec274e0f4ed28..a221220ffcb2d 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -663,6 +663,12 @@ static inline void hd_struct_put(struct hd_struct *part) __delete_partition(part); } +static inline void hd_free_part(struct hd_struct *part) +{ + free_part_stats(part); + free_part_info(part); +} + /* * Any access of part->nr_sects which is not protected by partition * bd_mutex or gendisk bdev bd_mutex, should be done using this -- GitLab From 6c71013ecb7e2bddbed9f5b95e7aed22c491daa9 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Thu, 16 Jul 2015 11:16:45 +0800 Subject: [PATCH 1131/7006] block: partition: convert percpu ref Percpu refcount is the perfect match for partition's case, and the conversion is quite straight. With the convertion, one pair of atomic inc/dec can be saved for accounting block I/O, which is run in hot path of block I/O. Signed-off-by: Ming Lei Acked-by: Tejun Heo Signed-off-by: Jens Axboe --- block/genhd.c | 6 +++++- block/partition-generic.c | 9 +++++---- include/linux/genhd.h | 27 +++++++++++++++++---------- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/block/genhd.c b/block/genhd.c index 85df45292dbaf..0c706f33a599a 100644 --- a/block/genhd.c +++ b/block/genhd.c @@ -1284,7 +1284,11 @@ struct gendisk *alloc_disk_node(int minors, int node_id) * converted to make use of bd_mutex and sequence counters. */ seqcount_init(&disk->part0.nr_sects_seq); - hd_ref_init(&disk->part0); + if (hd_ref_init(&disk->part0)) { + hd_free_part(&disk->part0); + kfree(disk); + return NULL; + } disk->minors = minors; rand_initialize_disk(disk); diff --git a/block/partition-generic.c b/block/partition-generic.c index eca0d02a607c2..e7711133284e1 100644 --- a/block/partition-generic.c +++ b/block/partition-generic.c @@ -232,8 +232,9 @@ static void delete_partition_rcu_cb(struct rcu_head *head) put_device(part_to_dev(part)); } -void __delete_partition(struct hd_struct *part) +void __delete_partition(struct percpu_ref *ref) { + struct hd_struct *part = container_of(ref, struct hd_struct, ref); call_rcu(&part->rcu_head, delete_partition_rcu_cb); } @@ -254,7 +255,7 @@ void delete_partition(struct gendisk *disk, int partno) kobject_put(part->holder_dir); device_del(part_to_dev(part)); - hd_struct_put(part); + hd_struct_kill(part); } static ssize_t whole_disk_show(struct device *dev, @@ -355,8 +356,8 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno, if (!dev_get_uevent_suppress(ddev)) kobject_uevent(&pdev->kobj, KOBJ_ADD); - hd_ref_init(p); - return p; + if (!hd_ref_init(p)) + return p; out_free_info: free_part_info(p); diff --git a/include/linux/genhd.h b/include/linux/genhd.h index a221220ffcb2d..2adbfa6d02bc4 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_BLOCK @@ -124,7 +125,7 @@ struct hd_struct { #else struct disk_stats dkstats; #endif - atomic_t ref; + struct percpu_ref ref; struct rcu_head rcu_head; }; @@ -611,7 +612,7 @@ extern struct hd_struct * __must_check add_partition(struct gendisk *disk, sector_t len, int flags, struct partition_meta_info *info); -extern void __delete_partition(struct hd_struct *); +extern void __delete_partition(struct percpu_ref *); extern void delete_partition(struct gendisk *, int); extern void printk_all_partitions(void); @@ -640,33 +641,39 @@ extern ssize_t part_fail_store(struct device *dev, const char *buf, size_t count); #endif /* CONFIG_FAIL_MAKE_REQUEST */ -static inline void hd_ref_init(struct hd_struct *part) +static inline int hd_ref_init(struct hd_struct *part) { - atomic_set(&part->ref, 1); - smp_mb(); + if (percpu_ref_init(&part->ref, __delete_partition, 0, + GFP_KERNEL)) + return -ENOMEM; + return 0; } static inline void hd_struct_get(struct hd_struct *part) { - atomic_inc(&part->ref); - smp_mb__after_atomic(); + percpu_ref_get(&part->ref); } static inline int hd_struct_try_get(struct hd_struct *part) { - return atomic_inc_not_zero(&part->ref); + return percpu_ref_tryget_live(&part->ref); } static inline void hd_struct_put(struct hd_struct *part) { - if (atomic_dec_and_test(&part->ref)) - __delete_partition(part); + percpu_ref_put(&part->ref); +} + +static inline void hd_struct_kill(struct hd_struct *part) +{ + percpu_ref_kill(&part->ref); } static inline void hd_free_part(struct hd_struct *part) { free_part_stats(part); free_part_info(part); + percpu_ref_exit(&part->ref); } /* -- GitLab From 2bb4cd5cc472b191a46938becb7dafdd44644329 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Tue, 14 Jul 2015 08:15:12 -0600 Subject: [PATCH 1132/7006] block: have drivers use blk_queue_max_discard_sectors() Some drivers use it now, others just set the limits field manually. But in preparation for splitting this into a hard and soft limit, ensure that they all call the proper function for setting the hw limit for discards. Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- drivers/block/brd.c | 2 +- drivers/block/drbd/drbd_nl.c | 4 ++-- drivers/block/loop.c | 4 ++-- drivers/block/nbd.c | 2 +- drivers/block/nvme-core.c | 2 +- drivers/block/rbd.c | 2 +- drivers/block/skd_main.c | 2 +- drivers/block/zram/zram_drv.c | 2 +- drivers/md/bcache/super.c | 2 +- drivers/mmc/card/queue.c | 2 +- drivers/mtd/mtd_blkdevs.c | 2 +- drivers/scsi/sd.c | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/drivers/block/brd.c b/drivers/block/brd.c index 64ab4951e9d67..e573e470bd8ab 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -500,7 +500,7 @@ static struct brd_device *brd_alloc(int i) blk_queue_physical_block_size(brd->brd_queue, PAGE_SIZE); brd->brd_queue->limits.discard_granularity = PAGE_SIZE; - brd->brd_queue->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(brd->brd_queue, UINT_MAX); brd->brd_queue->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue); diff --git a/drivers/block/drbd/drbd_nl.c b/drivers/block/drbd/drbd_nl.c index 74df8cfad414f..e80cbefbc2b54 100644 --- a/drivers/block/drbd/drbd_nl.c +++ b/drivers/block/drbd/drbd_nl.c @@ -1156,14 +1156,14 @@ static void drbd_setup_queue_param(struct drbd_device *device, struct drbd_backi /* For now, don't allow more than one activity log extent worth of data * to be discarded in one go. We may need to rework drbd_al_begin_io() * to allow for even larger discard ranges */ - q->limits.max_discard_sectors = DRBD_MAX_DISCARD_SECTORS; + blk_queue_max_discard_sectors(q, DRBD_MAX_DISCARD_SECTORS); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); /* REALLY? Is stacking secdiscard "legal"? */ if (blk_queue_secdiscard(b)) queue_flag_set_unlocked(QUEUE_FLAG_SECDISCARD, q); } else { - q->limits.max_discard_sectors = 0; + blk_queue_max_discard_sectors(q, 0); queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); queue_flag_clear_unlocked(QUEUE_FLAG_SECDISCARD, q); } diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f7a4c9d7f7218..f9889b6bc02c3 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -675,7 +675,7 @@ static void loop_config_discard(struct loop_device *lo) lo->lo_encrypt_key_size) { q->limits.discard_granularity = 0; q->limits.discard_alignment = 0; - q->limits.max_discard_sectors = 0; + blk_queue_max_discard_sectors(q, 0); q->limits.discard_zeroes_data = 0; queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); return; @@ -683,7 +683,7 @@ static void loop_config_discard(struct loop_device *lo) q->limits.discard_granularity = inode->i_sb->s_blocksize; q->limits.discard_alignment = 0; - q->limits.max_discard_sectors = UINT_MAX >> 9; + blk_queue_max_discard_sectors(q, UINT_MAX >> 9); q->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); } diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 0e385d8e9b86e..f169faf9838a7 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -822,7 +822,7 @@ static int __init nbd_init(void) queue_flag_set_unlocked(QUEUE_FLAG_NONROT, disk->queue); queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, disk->queue); disk->queue->limits.discard_granularity = 512; - disk->queue->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(disk->queue, UINT_MAX); disk->queue->limits.discard_zeroes_data = 0; blk_queue_max_hw_sectors(disk->queue, 65536); disk->queue->limits.max_sectors = 256; diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 7920c2741b47d..d844ec4a2b85e 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1935,7 +1935,7 @@ static void nvme_config_discard(struct nvme_ns *ns) ns->queue->limits.discard_zeroes_data = 0; ns->queue->limits.discard_alignment = logical_block_size; ns->queue->limits.discard_granularity = logical_block_size; - ns->queue->limits.max_discard_sectors = 0xffffffff; + blk_queue_max_discard_sectors(ns->queue, 0xffffffff); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue); } diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index d94529d5c8e95..dcc86937f55ca 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3803,7 +3803,7 @@ static int rbd_init_disk(struct rbd_device *rbd_dev) queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); q->limits.discard_granularity = segment_size; q->limits.discard_alignment = segment_size; - q->limits.max_discard_sectors = segment_size / SECTOR_SIZE; + blk_queue_max_discard_sectors(q, segment_size / SECTOR_SIZE); q->limits.discard_zeroes_data = 1; blk_queue_merge_bvec(q, rbd_merge_bvec); diff --git a/drivers/block/skd_main.c b/drivers/block/skd_main.c index 1e46eb2305c04..586f9168ffa48 100644 --- a/drivers/block/skd_main.c +++ b/drivers/block/skd_main.c @@ -4422,7 +4422,7 @@ static int skd_cons_disk(struct skd_device *skdev) /* DISCARD Flag initialization. */ q->limits.discard_granularity = 8192; q->limits.discard_alignment = 0; - q->limits.max_discard_sectors = UINT_MAX >> 9; + blk_queue_max_discard_sectors(q, UINT_MAX >> 9); q->limits.discard_zeroes_data = 1; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, q); diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index fb655e8d1e3b1..f439ad2800da9 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -1244,7 +1244,7 @@ static int zram_add(void) blk_queue_io_min(zram->disk->queue, PAGE_SIZE); blk_queue_io_opt(zram->disk->queue, PAGE_SIZE); zram->disk->queue->limits.discard_granularity = PAGE_SIZE; - zram->disk->queue->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(zram->disk->queue, UINT_MAX); /* * zram_bio_discard() will clear all logical blocks if logical block * size is identical with physical block size(PAGE_SIZE). But if it is diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 94980bfca4347..fc8e545ced184 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -830,7 +830,7 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size, q->limits.max_sectors = UINT_MAX; q->limits.max_segment_size = UINT_MAX; q->limits.max_segments = BIO_MAX_PAGES; - q->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(q, UINT_MAX); q->limits.discard_granularity = 512; q->limits.io_min = block_size; q->limits.logical_block_size = block_size; diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index b5a2b145d89f6..5daf302835b1e 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -165,7 +165,7 @@ static void mmc_queue_setup_discard(struct request_queue *q, return; queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); - q->limits.max_discard_sectors = max_discard; + blk_queue_max_discard_sectors(q, max_discard); if (card->erased_byte == 0 && !mmc_can_discard(card)) q->limits.discard_zeroes_data = 1; q->limits.discard_granularity = card->pref_erase << 9; diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 41acc507b22ed..1b96cf771d2b5 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -423,7 +423,7 @@ int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) if (tr->discard) { queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, new->rq); - new->rq->limits.max_discard_sectors = UINT_MAX; + blk_queue_max_discard_sectors(new->rq, UINT_MAX); } gd->queue = new->rq; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3b2fcb4fada04..160e44e7b24a2 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -647,7 +647,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) switch (mode) { case SD_LBP_DISABLE: - q->limits.max_discard_sectors = 0; + blk_queue_max_discard_sectors(q, 0); queue_flag_clear_unlocked(QUEUE_FLAG_DISCARD, q); return; @@ -675,7 +675,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode) break; } - q->limits.max_discard_sectors = max_blocks * (logical_block_size >> 9); + blk_queue_max_discard_sectors(q, max_blocks * (logical_block_size >> 9)); queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, q); } -- GitLab From 0034af036554c39eefd14d835a8ec3496ac46712 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Thu, 16 Jul 2015 09:14:26 -0600 Subject: [PATCH 1133/7006] block: make /sys/block//queue/discard_max_bytes writeable Lots of devices support huge discard sizes these days. Depending on how the device handles them internally, huge discards can introduce massive latencies (hundreds of msec) on the device side. We have a sysfs file, discard_max_bytes, that advertises the max hardware supported discard size. Make this writeable, and split the settings into a soft and hard limit. This can be set from 'discard_granularity' and up to the hardware limit. Add a new sysfs file, 'discard_max_hw_bytes', that shows the hw set limit. Reviewed-by: Jeff Moyer Signed-off-by: Jens Axboe --- Documentation/block/queue-sysfs.txt | 10 +++++++- block/blk-settings.c | 4 +++ block/blk-sysfs.c | 40 ++++++++++++++++++++++++++++- include/linux/blkdev.h | 1 + 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Documentation/block/queue-sysfs.txt b/Documentation/block/queue-sysfs.txt index 3a29f8914df9c..e5d914845be6d 100644 --- a/Documentation/block/queue-sysfs.txt +++ b/Documentation/block/queue-sysfs.txt @@ -20,7 +20,7 @@ This shows the size of internal allocation of the device in bytes, if reported by the device. A value of '0' means device does not support the discard functionality. -discard_max_bytes (RO) +discard_max_hw_bytes (RO) ---------------------- Devices that support discard functionality may have internal limits on the number of bytes that can be trimmed or unmapped in a single operation. @@ -29,6 +29,14 @@ number of bytes that can be discarded in a single operation. Discard requests issued to the device must not exceed this limit. A discard_max_bytes value of 0 means that the device does not support discard functionality. +discard_max_bytes (RW) +---------------------- +While discard_max_hw_bytes is the hardware limit for the device, this +setting is the software limit. Some devices exhibit large latencies when +large discards are issued, setting this value lower will make Linux issue +smaller discards and potentially help reduce latencies induced by large +discard operations. + discard_zeroes_data (RO) ------------------------ When read, this file will show if the discarded block are zeroed by the diff --git a/block/blk-settings.c b/block/blk-settings.c index 12600bfffca93..b38d8d7232762 100644 --- a/block/blk-settings.c +++ b/block/blk-settings.c @@ -116,6 +116,7 @@ void blk_set_default_limits(struct queue_limits *lim) lim->chunk_sectors = 0; lim->max_write_same_sectors = 0; lim->max_discard_sectors = 0; + lim->max_hw_discard_sectors = 0; lim->discard_granularity = 0; lim->discard_alignment = 0; lim->discard_misaligned = 0; @@ -303,6 +304,7 @@ EXPORT_SYMBOL(blk_queue_chunk_sectors); void blk_queue_max_discard_sectors(struct request_queue *q, unsigned int max_discard_sectors) { + q->limits.max_hw_discard_sectors = max_discard_sectors; q->limits.max_discard_sectors = max_discard_sectors; } EXPORT_SYMBOL(blk_queue_max_discard_sectors); @@ -641,6 +643,8 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, t->max_discard_sectors = min_not_zero(t->max_discard_sectors, b->max_discard_sectors); + t->max_hw_discard_sectors = min_not_zero(t->max_hw_discard_sectors, + b->max_hw_discard_sectors); t->discard_granularity = max(t->discard_granularity, b->discard_granularity); t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) % diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c index 6264b382d4d1b..b1f34e463c0f0 100644 --- a/block/blk-sysfs.c +++ b/block/blk-sysfs.c @@ -145,12 +145,43 @@ static ssize_t queue_discard_granularity_show(struct request_queue *q, char *pag return queue_var_show(q->limits.discard_granularity, page); } +static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page) +{ + unsigned long long val; + + val = q->limits.max_hw_discard_sectors << 9; + return sprintf(page, "%llu\n", val); +} + static ssize_t queue_discard_max_show(struct request_queue *q, char *page) { return sprintf(page, "%llu\n", (unsigned long long)q->limits.max_discard_sectors << 9); } +static ssize_t queue_discard_max_store(struct request_queue *q, + const char *page, size_t count) +{ + unsigned long max_discard; + ssize_t ret = queue_var_store(&max_discard, page, count); + + if (ret < 0) + return ret; + + if (max_discard & (q->limits.discard_granularity - 1)) + return -EINVAL; + + max_discard >>= 9; + if (max_discard > UINT_MAX) + return -EINVAL; + + if (max_discard > q->limits.max_hw_discard_sectors) + max_discard = q->limits.max_hw_discard_sectors; + + q->limits.max_discard_sectors = max_discard; + return ret; +} + static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page) { return queue_var_show(queue_discard_zeroes_data(q), page); @@ -360,9 +391,15 @@ static struct queue_sysfs_entry queue_discard_granularity_entry = { .show = queue_discard_granularity_show, }; +static struct queue_sysfs_entry queue_discard_max_hw_entry = { + .attr = {.name = "discard_max_hw_bytes", .mode = S_IRUGO }, + .show = queue_discard_max_hw_show, +}; + static struct queue_sysfs_entry queue_discard_max_entry = { - .attr = {.name = "discard_max_bytes", .mode = S_IRUGO }, + .attr = {.name = "discard_max_bytes", .mode = S_IRUGO | S_IWUSR }, .show = queue_discard_max_show, + .store = queue_discard_max_store, }; static struct queue_sysfs_entry queue_discard_zeroes_data_entry = { @@ -421,6 +458,7 @@ static struct attribute *default_attrs[] = { &queue_io_opt_entry.attr, &queue_discard_granularity_entry.attr, &queue_discard_max_entry.attr, + &queue_discard_max_hw_entry.attr, &queue_discard_zeroes_data_entry.attr, &queue_write_same_max_entry.attr, &queue_nonrot_entry.attr, diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index d4068c17d0df9..243f29e779ec5 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -268,6 +268,7 @@ struct queue_limits { unsigned int io_min; unsigned int io_opt; unsigned int max_discard_sectors; + unsigned int max_hw_discard_sectors; unsigned int max_write_same_sectors; unsigned int discard_granularity; unsigned int discard_alignment; -- GitLab From 85efe4e5082c381262f5303d20f808ac455b028e Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:49:24 -0300 Subject: [PATCH 1134/7006] [media] v4l2-dev: use event class to deduplicate v4l2 trace events Trace events with exactly the same parameters and trace output, such as v4l2_qbuf and v4l2_dqbuf, are supposed to use the DECLARE_EVENT_CLASS and DEFINE_EVENT macros instead of duplicated TRACE_EVENT macro calls. Suggested-by: Steven Rostedt Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/trace/events/v4l2.h | 160 ++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 82 deletions(-) diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h index 89d0497c058a8..4c88a3241c18d 100644 --- a/include/trace/events/v4l2.h +++ b/include/trace/events/v4l2.h @@ -93,90 +93,86 @@ SHOW_FIELD { V4L2_TC_USERBITS_USERDEFINED, "USERBITS_USERDEFINED" }, \ { V4L2_TC_USERBITS_8BITCHARS, "USERBITS_8BITCHARS" }) -#define V4L2_TRACE_EVENT(event_name) \ - TRACE_EVENT(event_name, \ - TP_PROTO(int minor, struct v4l2_buffer *buf), \ - \ - TP_ARGS(minor, buf), \ - \ - TP_STRUCT__entry( \ - __field(int, minor) \ - __field(u32, index) \ - __field(u32, type) \ - __field(u32, bytesused) \ - __field(u32, flags) \ - __field(u32, field) \ - __field(s64, timestamp) \ - __field(u32, timecode_type) \ - __field(u32, timecode_flags) \ - __field(u8, timecode_frames) \ - __field(u8, timecode_seconds) \ - __field(u8, timecode_minutes) \ - __field(u8, timecode_hours) \ - __field(u8, timecode_userbits0) \ - __field(u8, timecode_userbits1) \ - __field(u8, timecode_userbits2) \ - __field(u8, timecode_userbits3) \ - __field(u32, sequence) \ - ), \ - \ - TP_fast_assign( \ - __entry->minor = minor; \ - __entry->index = buf->index; \ - __entry->type = buf->type; \ - __entry->bytesused = buf->bytesused; \ - __entry->flags = buf->flags; \ - __entry->field = buf->field; \ - __entry->timestamp = \ - timeval_to_ns(&buf->timestamp); \ - __entry->timecode_type = buf->timecode.type; \ - __entry->timecode_flags = buf->timecode.flags; \ - __entry->timecode_frames = \ - buf->timecode.frames; \ - __entry->timecode_seconds = \ - buf->timecode.seconds; \ - __entry->timecode_minutes = \ - buf->timecode.minutes; \ - __entry->timecode_hours = buf->timecode.hours; \ - __entry->timecode_userbits0 = \ - buf->timecode.userbits[0]; \ - __entry->timecode_userbits1 = \ - buf->timecode.userbits[1]; \ - __entry->timecode_userbits2 = \ - buf->timecode.userbits[2]; \ - __entry->timecode_userbits3 = \ - buf->timecode.userbits[3]; \ - __entry->sequence = buf->sequence; \ - ), \ - \ - TP_printk("minor = %d, index = %u, type = %s, " \ - "bytesused = %u, flags = %s, " \ - "field = %s, timestamp = %llu, timecode = { " \ - "type = %s, flags = %s, frames = %u, " \ - "seconds = %u, minutes = %u, hours = %u, " \ - "userbits = { %u %u %u %u } }, " \ - "sequence = %u", __entry->minor, \ - __entry->index, show_type(__entry->type), \ - __entry->bytesused, \ - show_flags(__entry->flags), \ - show_field(__entry->field), \ - __entry->timestamp, \ - show_timecode_type(__entry->timecode_type), \ - show_timecode_flags(__entry->timecode_flags), \ - __entry->timecode_frames, \ - __entry->timecode_seconds, \ - __entry->timecode_minutes, \ - __entry->timecode_hours, \ - __entry->timecode_userbits0, \ - __entry->timecode_userbits1, \ - __entry->timecode_userbits2, \ - __entry->timecode_userbits3, \ - __entry->sequence \ - ) \ +DECLARE_EVENT_CLASS(v4l2_event_class, + TP_PROTO(int minor, struct v4l2_buffer *buf), + + TP_ARGS(minor, buf), + + TP_STRUCT__entry( + __field(int, minor) + __field(u32, index) + __field(u32, type) + __field(u32, bytesused) + __field(u32, flags) + __field(u32, field) + __field(s64, timestamp) + __field(u32, timecode_type) + __field(u32, timecode_flags) + __field(u8, timecode_frames) + __field(u8, timecode_seconds) + __field(u8, timecode_minutes) + __field(u8, timecode_hours) + __field(u8, timecode_userbits0) + __field(u8, timecode_userbits1) + __field(u8, timecode_userbits2) + __field(u8, timecode_userbits3) + __field(u32, sequence) + ), + + TP_fast_assign( + __entry->minor = minor; + __entry->index = buf->index; + __entry->type = buf->type; + __entry->bytesused = buf->bytesused; + __entry->flags = buf->flags; + __entry->field = buf->field; + __entry->timestamp = timeval_to_ns(&buf->timestamp); + __entry->timecode_type = buf->timecode.type; + __entry->timecode_flags = buf->timecode.flags; + __entry->timecode_frames = buf->timecode.frames; + __entry->timecode_seconds = buf->timecode.seconds; + __entry->timecode_minutes = buf->timecode.minutes; + __entry->timecode_hours = buf->timecode.hours; + __entry->timecode_userbits0 = buf->timecode.userbits[0]; + __entry->timecode_userbits1 = buf->timecode.userbits[1]; + __entry->timecode_userbits2 = buf->timecode.userbits[2]; + __entry->timecode_userbits3 = buf->timecode.userbits[3]; + __entry->sequence = buf->sequence; + ), + + TP_printk("minor = %d, index = %u, type = %s, bytesused = %u, " + "flags = %s, field = %s, timestamp = %llu, " + "timecode = { type = %s, flags = %s, frames = %u, " + "seconds = %u, minutes = %u, hours = %u, " + "userbits = { %u %u %u %u } }, sequence = %u", __entry->minor, + __entry->index, show_type(__entry->type), + __entry->bytesused, + show_flags(__entry->flags), + show_field(__entry->field), + __entry->timestamp, + show_timecode_type(__entry->timecode_type), + show_timecode_flags(__entry->timecode_flags), + __entry->timecode_frames, + __entry->timecode_seconds, + __entry->timecode_minutes, + __entry->timecode_hours, + __entry->timecode_userbits0, + __entry->timecode_userbits1, + __entry->timecode_userbits2, + __entry->timecode_userbits3, + __entry->sequence ) +) -V4L2_TRACE_EVENT(v4l2_dqbuf); -V4L2_TRACE_EVENT(v4l2_qbuf); +DEFINE_EVENT(v4l2_event_class, v4l2_dqbuf, + TP_PROTO(int minor, struct v4l2_buffer *buf), + TP_ARGS(minor, buf) +); + +DEFINE_EVENT(v4l2_event_class, v4l2_qbuf, + TP_PROTO(int minor, struct v4l2_buffer *buf), + TP_ARGS(minor, buf) +); #endif /* if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ) */ -- GitLab From c13a5ccf5da86239213033214658b8a170eeab87 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:49:25 -0300 Subject: [PATCH 1135/7006] [media] v4l2-mem2mem: set the queue owner field just as vb2_ioctl_reqbufs does The queue owner will be used by videobuf2 trace events to determine and record the device minor number. It is set in v4l2_m2m_reqbufs instead of v4l2_m2m_ioctl_reqbufs because several drivers implement their own vidioc_reqbufs handlers that still call v4l2_m2m_reqbufs directly. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mem2mem.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c index dc853e57f91f6..af8d6b4aa807b 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -357,9 +357,16 @@ int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx, struct v4l2_requestbuffers *reqbufs) { struct vb2_queue *vq; + int ret; vq = v4l2_m2m_get_vq(m2m_ctx, reqbufs->type); - return vb2_reqbufs(vq, reqbufs); + ret = vb2_reqbufs(vq, reqbufs); + /* If count == 0, then the owner has released all buffers and he + is no longer owner of the queue. Otherwise we have an owner. */ + if (ret == 0) + vq->owner = reqbufs->count ? file->private_data : NULL; + + return ret; } EXPORT_SYMBOL_GPL(v4l2_m2m_reqbufs); -- GitLab From 2091f5181c66b3617a977e79843aba10e087be6c Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 10 Jul 2015 10:49:26 -0300 Subject: [PATCH 1136/7006] [media] videobuf2: add trace events Add videobuf2 specific vb2_qbuf and vb2_dqbuf trace events that mirror the v4l2_qbuf and v4l2_dqbuf trace events, only they include additional information about queue fill state and are emitted right before the buffer is enqueued in the driver or userspace is woken up. This allows to make sense of the timeline of trace events in combination with others that might be triggered by __enqueue_in_driver. Also two new trace events vb2_buf_queue and vb2_buf_done are added, allowing to trace the handover between videobuf2 framework and driver. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/videobuf2-core.c | 11 +++ include/trace/events/v4l2.h | 97 ++++++++++++++++++++++++ 2 files changed, 108 insertions(+) diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 93b3154590989..b866a6becd993 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -30,6 +30,8 @@ #include #include +#include + static int debug; module_param(debug, int, 0644); @@ -1207,6 +1209,8 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) atomic_dec(&q->owned_by_drv_count); spin_unlock_irqrestore(&q->done_lock, flags); + trace_vb2_buf_done(q, vb); + if (state == VB2_BUF_STATE_QUEUED) { if (q->start_streaming_called) __enqueue_in_driver(vb); @@ -1629,6 +1633,8 @@ static void __enqueue_in_driver(struct vb2_buffer *vb) vb->state = VB2_BUF_STATE_ACTIVE; atomic_inc(&q->owned_by_drv_count); + trace_vb2_buf_queue(q, vb); + /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, prepare, vb->planes[plane].mem_priv); @@ -1878,6 +1884,8 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b) vb->v4l2_buf.timecode = b->timecode; } + trace_vb2_qbuf(q, vb); + /* * If already streaming, give the buffer to driver for processing. * If not, the buffer will be given to driver on next streamon. @@ -2123,6 +2131,9 @@ static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool n /* Remove from videobuf queue */ list_del(&vb->queued_entry); q->queued_count--; + + trace_vb2_dqbuf(q, vb); + if (!V4L2_TYPE_IS_OUTPUT(q->type) && vb->v4l2_buf.flags & V4L2_BUF_FLAG_LAST) q->last_buffer_dequeued = true; diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h index 4c88a3241c18d..dbf017bfddd92 100644 --- a/include/trace/events/v4l2.h +++ b/include/trace/events/v4l2.h @@ -174,6 +174,103 @@ DEFINE_EVENT(v4l2_event_class, v4l2_qbuf, TP_ARGS(minor, buf) ); +DECLARE_EVENT_CLASS(vb2_event_class, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb), + + TP_STRUCT__entry( + __field(int, minor) + __field(u32, queued_count) + __field(int, owned_by_drv_count) + __field(u32, index) + __field(u32, type) + __field(u32, bytesused) + __field(u32, flags) + __field(u32, field) + __field(s64, timestamp) + __field(u32, timecode_type) + __field(u32, timecode_flags) + __field(u8, timecode_frames) + __field(u8, timecode_seconds) + __field(u8, timecode_minutes) + __field(u8, timecode_hours) + __field(u8, timecode_userbits0) + __field(u8, timecode_userbits1) + __field(u8, timecode_userbits2) + __field(u8, timecode_userbits3) + __field(u32, sequence) + ), + + TP_fast_assign( + __entry->minor = q->owner ? q->owner->vdev->minor : -1; + __entry->queued_count = q->queued_count; + __entry->owned_by_drv_count = + atomic_read(&q->owned_by_drv_count); + __entry->index = vb->v4l2_buf.index; + __entry->type = vb->v4l2_buf.type; + __entry->bytesused = vb->v4l2_planes[0].bytesused; + __entry->flags = vb->v4l2_buf.flags; + __entry->field = vb->v4l2_buf.field; + __entry->timestamp = timeval_to_ns(&vb->v4l2_buf.timestamp); + __entry->timecode_type = vb->v4l2_buf.timecode.type; + __entry->timecode_flags = vb->v4l2_buf.timecode.flags; + __entry->timecode_frames = vb->v4l2_buf.timecode.frames; + __entry->timecode_seconds = vb->v4l2_buf.timecode.seconds; + __entry->timecode_minutes = vb->v4l2_buf.timecode.minutes; + __entry->timecode_hours = vb->v4l2_buf.timecode.hours; + __entry->timecode_userbits0 = vb->v4l2_buf.timecode.userbits[0]; + __entry->timecode_userbits1 = vb->v4l2_buf.timecode.userbits[1]; + __entry->timecode_userbits2 = vb->v4l2_buf.timecode.userbits[2]; + __entry->timecode_userbits3 = vb->v4l2_buf.timecode.userbits[3]; + __entry->sequence = vb->v4l2_buf.sequence; + ), + + TP_printk("minor = %d, queued = %u, owned_by_drv = %d, index = %u, " + "type = %s, bytesused = %u, flags = %s, field = %s, " + "timestamp = %llu, timecode = { type = %s, flags = %s, " + "frames = %u, seconds = %u, minutes = %u, hours = %u, " + "userbits = { %u %u %u %u } }, sequence = %u", __entry->minor, + __entry->queued_count, + __entry->owned_by_drv_count, + __entry->index, show_type(__entry->type), + __entry->bytesused, + show_flags(__entry->flags), + show_field(__entry->field), + __entry->timestamp, + show_timecode_type(__entry->timecode_type), + show_timecode_flags(__entry->timecode_flags), + __entry->timecode_frames, + __entry->timecode_seconds, + __entry->timecode_minutes, + __entry->timecode_hours, + __entry->timecode_userbits0, + __entry->timecode_userbits1, + __entry->timecode_userbits2, + __entry->timecode_userbits3, + __entry->sequence + ) +) + +DEFINE_EVENT(vb2_event_class, vb2_buf_done, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + +DEFINE_EVENT(vb2_event_class, vb2_buf_queue, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + +DEFINE_EVENT(vb2_event_class, vb2_dqbuf, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + +DEFINE_EVENT(vb2_event_class, vb2_qbuf, + TP_PROTO(struct vb2_queue *q, struct vb2_buffer *vb), + TP_ARGS(q, vb) +); + #endif /* if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ) */ /* This part must be outside protection */ -- GitLab From 806c24adf74ec02543e4dcad989c0336f9fe82c4 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 17 Jul 2015 11:16:47 -0400 Subject: [PATCH 1137/7006] ext4 crypto: use a jbd2 transaction when adding a crypto policy Start a jbd2 transaction, and mark the inode dirty on the inode under that transaction after setting the encrypt flag. Otherwise if the directory isn't modified after setting the crypto policy, the encrypted flag might not survive the inode getting pushed out from memory, or the the file system getting unmounted and remounted. Signed-off-by: Theodore Ts'o --- fs/ext4/crypto_policy.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/fs/ext4/crypto_policy.c b/fs/ext4/crypto_policy.c index 02c4e5df7afb9..a640ec2c4b134 100644 --- a/fs/ext4/crypto_policy.c +++ b/fs/ext4/crypto_policy.c @@ -12,6 +12,7 @@ #include #include +#include "ext4_jbd2.h" #include "ext4.h" #include "xattr.h" @@ -49,7 +50,8 @@ static int ext4_create_encryption_context_from_policy( struct inode *inode, const struct ext4_encryption_policy *policy) { struct ext4_encryption_context ctx; - int res = 0; + handle_t *handle; + int res, res2; res = ext4_convert_inline_data(inode); if (res) @@ -78,11 +80,22 @@ static int ext4_create_encryption_context_from_policy( BUILD_BUG_ON(sizeof(ctx.nonce) != EXT4_KEY_DERIVATION_NONCE_SIZE); get_random_bytes(ctx.nonce, EXT4_KEY_DERIVATION_NONCE_SIZE); + handle = ext4_journal_start(inode, EXT4_HT_MISC, + ext4_jbd2_credits_xattr(inode)); + if (IS_ERR(handle)) + return PTR_ERR(handle); res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION, EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, &ctx, sizeof(ctx), 0); - if (!res) + if (!res) { ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); + res = ext4_mark_inode_dirty(handle, inode); + if (res) + EXT4_ERROR_INODE(inode, "Failed to mark inode dirty"); + } + res2 = ext4_journal_stop(handle); + if (!res) + res = res2; return res; } -- GitLab From 27977b69e493c9b259eb0490534e0f74bc325ba8 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Fri, 17 Jul 2015 11:33:16 -0400 Subject: [PATCH 1138/7006] ext4 crypto: check for too-short encrypted file names An encrypted file name should never be shorter than an 16 bytes, the AES block size. The 3.10 crypto layer will oops and crash the kernel if ciphertext shorter than the block size is passed to it. Fortunately, in modern kernels the crypto layer will not crash the kernel in this scenario, but nevertheless, it represents a corrupted directory, and we should detect it and mark the file system as corrupted so that e2fsck can fix this. Signed-off-by: Theodore Ts'o --- fs/ext4/crypto_fname.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/crypto_fname.c b/fs/ext4/crypto_fname.c index 7dc4eb55913c4..86ee996a2bd4b 100644 --- a/fs/ext4/crypto_fname.c +++ b/fs/ext4/crypto_fname.c @@ -329,6 +329,10 @@ int _ext4_fname_disk_to_usr(struct inode *inode, return oname->len; } } + if (iname->len < EXT4_CRYPTO_BLOCK_SIZE) { + EXT4_ERROR_INODE(inode, "encrypted inode too small"); + return -EUCLEAN; + } if (EXT4_I(inode)->i_crypt_info) return ext4_fname_decrypt(inode, iname, oname); -- GitLab From dc606e05468fc5e3b125bffdd54253f853bfbb8e Mon Sep 17 00:00:00 2001 From: Nariman Poushin Date: Fri, 17 Jul 2015 15:11:10 +0100 Subject: [PATCH 1139/7006] ASoC: wm5110: Use reg_sequence for multi_reg_write/register_patch Introduced by: commit 8019ff6cfc04 ("regmap: Use reg_sequence for multi_reg_write / register_patch") Interacting with: commit d1acd31883d7 ("ASoC: wm5110: Add special DRE on/off handling for the headphone path") Signed-off-by: Nariman Poushin Signed-off-by: Mark Brown --- sound/soc/codecs/wm5110.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index b5c201b1e454b..1f29991c1f714 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -185,7 +185,7 @@ static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w, return 0; } -static const struct reg_default wm5110_no_dre_left_enable[] = { +static const struct reg_sequence wm5110_no_dre_left_enable[] = { { 0x3024, 0xE410 }, { 0x3025, 0x0056 }, { 0x301B, 0x0224 }, @@ -203,7 +203,7 @@ static const struct reg_default wm5110_no_dre_left_enable[] = { { 0x3039, 0x3080 }, }; -static const struct reg_default wm5110_dre_left_enable[] = { +static const struct reg_sequence wm5110_dre_left_enable[] = { { 0x3024, 0x0231 }, { 0x3025, 0x0B00 }, { 0x301B, 0x0227 }, @@ -221,7 +221,7 @@ static const struct reg_default wm5110_dre_left_enable[] = { { 0x3039, 0x0B00 }, }; -static const struct reg_default wm5110_no_dre_right_enable[] = { +static const struct reg_sequence wm5110_no_dre_right_enable[] = { { 0x3074, 0xE414 }, { 0x3075, 0x0056 }, { 0x306B, 0x0224 }, @@ -239,7 +239,7 @@ static const struct reg_default wm5110_no_dre_right_enable[] = { { 0x3089, 0x3080 }, }; -static const struct reg_default wm5110_dre_right_enable[] = { +static const struct reg_sequence wm5110_dre_right_enable[] = { { 0x3074, 0x0231 }, { 0x3075, 0x0B00 }, { 0x306B, 0x0227 }, @@ -263,7 +263,7 @@ static int wm5110_hp_pre_enable(struct snd_soc_dapm_widget *w) struct arizona_priv *priv = snd_soc_codec_get_drvdata(codec); struct arizona *arizona = priv->arizona; unsigned int val = snd_soc_read(codec, ARIZONA_DRE_ENABLE); - const struct reg_default *wseq; + const struct reg_sequence *wseq; int nregs; switch (w->shift) { @@ -354,7 +354,7 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, static int wm5110_clear_pga_volume(struct arizona *arizona, int output) { - struct reg_default clear_pga = { + struct reg_sequence clear_pga = { ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 }; int ret; -- GitLab From 7dfb49194557ccf27ab99c8c04c021320e7ae458 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:16:56 +0000 Subject: [PATCH 1140/7006] ASoC: rsnd: update Audio DMA path search method Current rsnd driver is assuming Audio DMAC / Audio DMAC peri peri are used from SSI/SSIU/SRC/DVC. But we will add CTU/MIX to this driver. Then, current DMA path searching method is not understandable, and good enough for this purpose. This patch update DMA path search method, more simply. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- sound/soc/sh/rcar/dma.c | 88 +++++++++++++++++++++++++---------------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index a175863d239c5..23282f48f71f1 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -494,7 +494,7 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, return rsnd_gen2_dma_addr(io, mod, is_play, is_from); } -#define MOD_MAX 4 /* MEM/SSI/SRC/DVC */ +#define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_dai_stream *io, int is_play, @@ -506,53 +506,71 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; - int i, index; + struct rsnd_mod *mod_start, *mod_end; + struct rsnd_priv *priv = rsnd_mod_to_priv(this); + struct device *dev = rsnd_priv_to_dev(priv); + int nr, i; + if (!ssi) + return; - for (i = 0; i < MOD_MAX; i++) + nr = 0; + for (i = 0; i < MOD_MAX; i++) { mod[i] = NULL; + nr += !!rsnd_io_to_mod(io, i); + } /* - * in play case... + * [S] -*-> [E] + * [S] -*-> SRC -o-> [E] + * [S] -*-> SRC -> DVC -o-> [E] + * [S] -*-> SRC -> CTU -> MIX -> DVC -o-> [E] + * + * playback [S] = mem + * [E] = SSI * - * src -> dst + * capture [S] = SSI + * [E] = mem * - * mem -> SSI - * mem -> SRC -> SSI - * mem -> SRC -> DVC -> SSI + * -*-> Audio DMAC + * -o-> Audio DMAC peri peri */ - mod[0] = NULL; /* for "mem" */ - index = 1; - for (i = 1; i < MOD_MAX; i++) { - if (!src) { - mod[i] = ssi; - } else if (!dvc) { - mod[i] = src; - src = NULL; - } else { - if ((!is_play) && (this == src)) - this = dvc; + mod_start = (is_play) ? NULL : ssi; + mod_end = (is_play) ? ssi : NULL; - mod[i] = (is_play) ? src : dvc; - i++; - mod[i] = (is_play) ? dvc : src; + mod[0] = mod_start; + for (i = 1; i < nr; i++) { + if (src) { + mod[i] = src; src = NULL; + } else if (dvc) { + mod[i] = dvc; dvc = NULL; } - - if (mod[i] == this) - index = i; - - if (mod[i] == ssi) - break; } + mod[i] = mod_end; - if (is_play) { - *mod_from = mod[index - 1]; - *mod_to = mod[index]; + /* + * | SSI | SRC | + * -------------+-----+-----+ + * is_play | o | * | + * !is_play | * | o | + */ + if ((this == ssi) == (is_play)) { + *mod_from = mod[nr - 1]; + *mod_to = mod[nr]; } else { - *mod_from = mod[index]; - *mod_to = mod[index - 1]; + *mod_from = mod[0]; + *mod_to = mod[1]; + } + + dev_dbg(dev, "module connection (this is %s[%d])\n", + rsnd_mod_name(this), rsnd_mod_id(this)); + for (i = 0; i <= nr; i++) { + dev_dbg(dev, " %s[%d]%s\n", + rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), + (mod[i] == *mod_from) ? " from" : + (mod[i] == *mod_to) ? " to" : ""); } } @@ -580,8 +598,8 @@ void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) { - struct rsnd_mod *mod_from; - struct rsnd_mod *mod_to; + struct rsnd_mod *mod_from = NULL; + struct rsnd_mod *mod_to = NULL; struct rsnd_priv *priv = rsnd_io_to_priv(io); struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); struct device *dev = rsnd_priv_to_dev(priv); -- GitLab From 9269e3c3cfac277a49b485e27ac6850f9a11a259 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:17:17 +0000 Subject: [PATCH 1141/7006] ASoC: rsnd: add CTU (Channel Transfer Unit) prototype support This patch adds CTU (Channel Transfer Unit) support for rsnd driver. But, it does nothing to data at this point, but is required for MIX support. CTU design is a little different from other IPs (CTU0 is including CTU00 - CTU03, and CTU1 is including CTU10 - CTU13, these have different register mapping) We need to care about it on this driver. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.txt | 14 ++ include/sound/rcar_snd.h | 7 + sound/soc/sh/rcar/Makefile | 2 +- sound/soc/sh/rcar/core.c | 12 +- sound/soc/sh/rcar/ctu.c | 171 ++++++++++++++++++ sound/soc/sh/rcar/dma.c | 13 +- sound/soc/sh/rcar/gen.c | 2 + sound/soc/sh/rcar/rsnd.h | 21 +++ 8 files changed, 236 insertions(+), 6 deletions(-) create mode 100644 sound/soc/sh/rcar/ctu.c diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index b6b3a786855f2..278607de05de6 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -18,6 +18,9 @@ Required properties: - rcar_sound,src : Should contain SRC feature. The number of SRC subnode should be same as HW. see below for detail. +- rcar_sound,ctu : Should contain CTU feature. + The number of CTU subnode should be same as HW. + see below for detail. - rcar_sound,dvc : Should contain DVC feature. The number of DVC subnode should be same as HW. see below for detail. @@ -90,6 +93,17 @@ rcar_sound: sound@ec500000 { }; }; + rcar_sound,ctu { + ctu00: ctu@0 { }; + ctu01: ctu@1 { }; + ctu02: ctu@2 { }; + ctu03: ctu@3 { }; + ctu10: ctu@4 { }; + ctu11: ctu@5 { }; + ctu12: ctu@6 { }; + ctu13: ctu@7 { }; + }; + rcar_sound,src { src0: src@0 { interrupts = <0 352 IRQ_TYPE_LEVEL_HIGH>; diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 4cecd0c175f60..8f9303093ab94 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -61,6 +61,10 @@ struct rsnd_src_platform_info { /* * flags */ +struct rsnd_ctu_platform_info { + u32 flags; +}; + struct rsnd_dvc_platform_info { u32 flags; }; @@ -68,6 +72,7 @@ struct rsnd_dvc_platform_info { struct rsnd_dai_path_info { struct rsnd_ssi_platform_info *ssi; struct rsnd_src_platform_info *src; + struct rsnd_ctu_platform_info *ctu; struct rsnd_dvc_platform_info *dvc; }; @@ -93,6 +98,8 @@ struct rcar_snd_info { int ssi_info_nr; struct rsnd_src_platform_info *src_info; int src_info_nr; + struct rsnd_ctu_platform_info *ctu_info; + int ctu_info_nr; struct rsnd_dvc_platform_info *dvc_info; int dvc_info_nr; struct rsnd_dai_platform_info *dai_info; diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 3a274fd3593c2..7c4730a81c4a8 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e20d8ea0aafe8..63ae7bbfd1dce 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -651,6 +651,11 @@ static int rsnd_path_init(struct rsnd_priv *priv, if (ret < 0) return ret; + /* CTU */ + ret = rsnd_path_add(priv, io, ctu); + if (ret < 0) + return ret; + /* DVC */ ret = rsnd_path_add(priv, io, dvc); if (ret < 0) @@ -666,13 +671,14 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, struct device_node *dai_node, *dai_np; struct device_node *ssi_node, *ssi_np; struct device_node *src_node, *src_np; + struct device_node *ctu_node, *ctu_np; struct device_node *dvc_node, *dvc_np; struct device_node *playback, *capture; struct rsnd_dai_platform_info *dai_info; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = &pdev->dev; int nr, i; - int dai_i, ssi_i, src_i, dvc_i; + int dai_i, ssi_i, src_i, ctu_i, dvc_i; if (!of_data) return; @@ -698,6 +704,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); + ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); #define mod_parse(name) \ @@ -734,6 +741,7 @@ if (name##_node) { \ mod_parse(ssi); mod_parse(src); + mod_parse(ctu); mod_parse(dvc); of_node_put(playback); @@ -1146,6 +1154,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_dma_probe, rsnd_ssi_probe, rsnd_src_probe, + rsnd_ctu_probe, rsnd_dvc_probe, rsnd_adg_probe, rsnd_dai_probe, @@ -1241,6 +1250,7 @@ static int rsnd_remove(struct platform_device *pdev) struct rsnd_priv *priv) = { rsnd_ssi_remove, rsnd_src_remove, + rsnd_ctu_remove, rsnd_dvc_remove, }; int ret = 0, i; diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c new file mode 100644 index 0000000000000..05edd2009b812 --- /dev/null +++ b/sound/soc/sh/rcar/ctu.c @@ -0,0 +1,171 @@ +/* + * ctu.c + * + * Copyright (c) 2015 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +#define CTU_NAME_SIZE 16 +#define CTU_NAME "ctu" + +struct rsnd_ctu { + struct rsnd_ctu_platform_info *info; /* rcar_snd.h */ + struct rsnd_mod mod; +}; + +#define rsnd_ctu_nr(priv) ((priv)->ctu_nr) +#define for_each_rsnd_ctu(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_ctu_nr(priv)) && \ + ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ + i++) + +#define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) +#define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) +static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, CTU_CTUIR, enable); +} + +static int rsnd_ctu_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_start(mod); + + rsnd_ctu_initialize_lock(mod); + + rsnd_mod_write(mod, CTU_ADINR, rsnd_get_adinr_chan(mod, io)); + + rsnd_ctu_initialize_unlock(mod); + + return 0; +} + +static int rsnd_ctu_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_stop(mod); + + return 0; +} + +static struct rsnd_mod_ops rsnd_ctu_ops = { + .name = CTU_NAME, + .init = rsnd_ctu_init, + .quit = rsnd_ctu_quit, +}; + +struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) + id = 0; + + return &((struct rsnd_ctu *)(priv->ctu) + id)->mod; +} + +void rsnd_of_parse_ctu(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *node; + struct rsnd_ctu_platform_info *ctu_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr; + + if (!of_data) + return; + + node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); + if (!node) + return; + + nr = of_get_child_count(node); + if (!nr) + goto rsnd_of_parse_ctu_end; + + ctu_info = devm_kzalloc(dev, + sizeof(struct rsnd_ctu_platform_info) * nr, + GFP_KERNEL); + if (!ctu_info) { + dev_err(dev, "ctu info allocation error\n"); + goto rsnd_of_parse_ctu_end; + } + + info->ctu_info = ctu_info; + info->ctu_info_nr = nr; + +rsnd_of_parse_ctu_end: + of_node_put(node); + +} + +int rsnd_ctu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_ctu *ctu; + struct clk *clk; + char name[CTU_NAME_SIZE]; + int i, nr, ret; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) { + dev_warn(dev, "CTU is not supported on Gen1\n"); + return -EINVAL; + } + + rsnd_of_parse_ctu(pdev, of_data, priv); + + nr = info->ctu_info_nr; + if (!nr) + return 0; + + ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL); + if (!ctu) + return -ENOMEM; + + priv->ctu_nr = nr; + priv->ctu = ctu; + + for_each_rsnd_ctu(ctu, priv, i) { + /* + * CTU00, CTU01, CTU02, CTU03 => CTU0 + * CTU10, CTU11, CTU12, CTU13 => CTU1 + */ + snprintf(name, CTU_NAME_SIZE, "%s.%d", + CTU_NAME, i / 4); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + ctu->info = &info->ctu_info[i]; + + ret = rsnd_mod_init(priv, &ctu->mod, &rsnd_ctu_ops, + clk, RSND_MOD_CTU, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_ctu_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_ctu *ctu; + int i; + + for_each_rsnd_ctu(ctu, priv, i) { + rsnd_mod_quit(&ctu->mod); + } +} diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 23282f48f71f1..229b68d2cf702 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -426,7 +426,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, phys_addr_t src_reg = rsnd_gen_get_phy_addr(priv, RSND_GEN2_SCU); int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); int use_src = !!rsnd_io_to_mod_src(io); - int use_dvc = !!rsnd_io_to_mod_dvc(io); + int use_cmd = !!rsnd_io_to_mod_dvc(io) || + !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); struct dma_addr { dma_addr_t out_addr; @@ -464,7 +465,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, }; /* it shouldn't happen */ - if (use_dvc && !use_src) + if (use_cmd && !use_src) dev_err(dev, "DVC is selected without SRC\n"); /* use SSIU or SSI ? */ @@ -472,8 +473,8 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, is_ssi++; return (is_from) ? - dma_addrs[is_ssi][is_play][use_src + use_dvc].out_addr : - dma_addrs[is_ssi][is_play][use_src + use_dvc].in_addr; + dma_addrs[is_ssi][is_play][use_src + use_cmd].out_addr : + dma_addrs[is_ssi][is_play][use_src + use_cmd].in_addr; } static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, @@ -504,6 +505,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *this = rsnd_dma_to_mod(dma); struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; struct rsnd_mod *mod_start, *mod_end; @@ -543,6 +545,9 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, if (src) { mod[i] = src; src = NULL; + } else if (ctu) { + mod[i] = ctu; + ctu = NULL; } else if (dvc) { mod[i] = dvc; dvc = NULL; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index a2d5df4d5d176..41b75cd4e09b3 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -240,6 +240,8 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), RSND_GEN_M_REG(SRC_BSDSR, 0x22c, 0x40), RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), + RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), + RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 7fee2079ba5ab..f2128a7cf259e 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -47,6 +47,8 @@ enum rsnd_reg { RSND_REG_SCU_SYS_STATUS0, RSND_REG_SCU_SYS_INT_EN0, RSND_REG_CMD_ROUTE_SLCT, + RSND_REG_CTU_CTUIR, + RSND_REG_CTU_ADINR, RSND_REG_DVC_SWRSR, RSND_REG_DVC_DVUIR, RSND_REG_DVC_ADINR, @@ -220,6 +222,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, */ enum rsnd_mod_type { RSND_MOD_DVC = 0, + RSND_MOD_CTU, RSND_MOD_SRC, RSND_MOD_SSI, RSND_MOD_MAX, @@ -351,6 +354,7 @@ struct rsnd_dai_stream { #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) +#define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) @@ -462,6 +466,12 @@ struct rsnd_priv { void *src; int src_nr; + /* + * below value will be filled on rsnd_ctu_probe() + */ + void *ctu; + int ctu_nr; + /* * below value will be filled on rsnd_dvc_probe() */ @@ -567,6 +577,17 @@ int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); +/* + * R-Car CTU + */ +int rsnd_ctu_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); + +void rsnd_ctu_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); + /* * R-Car DVC */ -- GitLab From 70fb10529f61c31c26397a02091177bedd23217d Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 15 Jul 2015 07:17:36 +0000 Subject: [PATCH 1142/7006] ASoC: rsnd: add MIX (Mixer) support This patch adds MIX (Mixer) initial support for rsnd driver. It is assuming that this MIX is used via DPCM. This is sample code for playback. CPU0 : [MEM] -> [SRC1] -> [CTU02] -+ | +-> [MIX0] -> [DVC0] -> [SSI0] | CPU1 : [MEM] -> [SRC2] -> [CTU03] -+ sound { compatible = "renesas,rsrc-card"; ... cpu@0 { sound-dai = <&rcar_sound 0>; }; cpu@1 { sound-dai = <&rcar_sound 1>; }; codec { ... }; }; rcar_sound { ... rcar_sound,dai { dai0 { playback = <&src1 &ctu02 &mix0 &dvc0 &ssi0>; }; dai1 { playback = <&src2 &ctu03 &mix0 &dvc0 &ssi0>; }; }; }; Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi Signed-off-by: Mark Brown --- .../bindings/sound/renesas,rsnd.txt | 8 + include/sound/rcar_snd.h | 7 + sound/soc/sh/rcar/Makefile | 2 +- sound/soc/sh/rcar/core.c | 85 ++++++-- sound/soc/sh/rcar/dma.c | 5 + sound/soc/sh/rcar/gen.c | 10 + sound/soc/sh/rcar/mix.c | 200 ++++++++++++++++++ sound/soc/sh/rcar/rsnd.h | 29 +++ 8 files changed, 333 insertions(+), 13 deletions(-) create mode 100644 sound/soc/sh/rcar/mix.c diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index 278607de05de6..1173395b5e5c1 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt @@ -21,6 +21,9 @@ Required properties: - rcar_sound,ctu : Should contain CTU feature. The number of CTU subnode should be same as HW. see below for detail. +- rcar_sound,mix : Should contain MIX feature. + The number of MIX subnode should be same as HW. + see below for detail. - rcar_sound,dvc : Should contain DVC feature. The number of DVC subnode should be same as HW. see below for detail. @@ -93,6 +96,11 @@ rcar_sound: sound@ec500000 { }; }; + rcar_sound,mix { + mix0: mix@0 { }; + mix1: mix@1 { }; + }; + rcar_sound,ctu { ctu00: ctu@0 { }; ctu01: ctu@1 { }; diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h index 8f9303093ab94..bb7b2ebfee7b9 100644 --- a/include/sound/rcar_snd.h +++ b/include/sound/rcar_snd.h @@ -65,6 +65,10 @@ struct rsnd_ctu_platform_info { u32 flags; }; +struct rsnd_mix_platform_info { + u32 flags; +}; + struct rsnd_dvc_platform_info { u32 flags; }; @@ -73,6 +77,7 @@ struct rsnd_dai_path_info { struct rsnd_ssi_platform_info *ssi; struct rsnd_src_platform_info *src; struct rsnd_ctu_platform_info *ctu; + struct rsnd_mix_platform_info *mix; struct rsnd_dvc_platform_info *dvc; }; @@ -100,6 +105,8 @@ struct rcar_snd_info { int src_info_nr; struct rsnd_ctu_platform_info *ctu_info; int ctu_info_nr; + struct rsnd_mix_platform_info *mix_info; + int mix_info_nr; struct rsnd_dvc_platform_info *dvc_info; int dvc_info_nr; struct rsnd_dai_platform_info *dai_info; diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 7c4730a81c4a8..8b258501aa357 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile @@ -1,4 +1,4 @@ -snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o dvc.o +snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o snd-soc-rsrc-card-objs := rsrc-card.o diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 63ae7bbfd1dce..927a7b02123b3 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -605,23 +605,74 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { void rsnd_path_parse(struct rsnd_priv *priv, struct rsnd_dai_stream *io) { - struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); - int src_id = rsnd_mod_id(src); - u32 path[] = { - [0] = 0x30000, - [1] = 0x30001, - [2] = 0x40000, - [3] = 0x10000, - [4] = 0x20000, - [5] = 0x40100 - }; + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); + struct rsnd_mod *src = rsnd_io_to_mod_src(io); + struct rsnd_mod *cmd; + struct device *dev = rsnd_priv_to_dev(priv); + u32 data; /* Gen1 is not supported */ if (rsnd_is_gen1(priv)) return; - rsnd_mod_write(dvc, CMD_ROUTE_SLCT, path[src_id]); + if (!mix && !dvc) + return; + + if (mix) { + struct rsnd_dai *rdai; + int i; + u32 path[] = { + [0] = 0, + [1] = 1 << 0, + [2] = 0, + [3] = 0, + [4] = 0, + [5] = 1 << 8 + }; + + /* + * it is assuming that integrater is well understanding about + * data path. Here doesn't check impossible connection, + * like src2 + src5 + */ + data = 0; + for_each_rsnd_dai(rdai, priv, i) { + io = &rdai->playback; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + + io = &rdai->capture; + if (mix == rsnd_io_to_mod_mix(io)) + data |= path[rsnd_mod_id(src)]; + } + + /* + * We can't use ctu = rsnd_io_ctu() here. + * Since, ID of dvc/mix are 0 or 1 (= same as CMD number) + * but ctu IDs are 0 - 7 (= CTU00 - CTU13) + */ + cmd = mix; + } else { + u32 path[] = { + [0] = 0x30000, + [1] = 0x30001, + [2] = 0x40000, + [3] = 0x10000, + [4] = 0x20000, + [5] = 0x40100 + }; + + data = path[rsnd_mod_id(src)]; + + cmd = dvc; + } + + dev_dbg(dev, "ctu/mix path = 0x%08x", data); + + rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data); + + rsnd_mod_write(cmd, CMD_CTRL, 0x10); } static int rsnd_path_init(struct rsnd_priv *priv, @@ -656,6 +707,11 @@ static int rsnd_path_init(struct rsnd_priv *priv, if (ret < 0) return ret; + /* MIX */ + ret = rsnd_path_add(priv, io, mix); + if (ret < 0) + return ret; + /* DVC */ ret = rsnd_path_add(priv, io, dvc); if (ret < 0) @@ -672,13 +728,14 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, struct device_node *ssi_node, *ssi_np; struct device_node *src_node, *src_np; struct device_node *ctu_node, *ctu_np; + struct device_node *mix_node, *mix_np; struct device_node *dvc_node, *dvc_np; struct device_node *playback, *capture; struct rsnd_dai_platform_info *dai_info; struct rcar_snd_info *info = rsnd_priv_to_info(priv); struct device *dev = &pdev->dev; int nr, i; - int dai_i, ssi_i, src_i, ctu_i, dvc_i; + int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i; if (!of_data) return; @@ -705,6 +762,7 @@ static void rsnd_of_parse_dai(struct platform_device *pdev, ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); + mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); #define mod_parse(name) \ @@ -742,6 +800,7 @@ if (name##_node) { \ mod_parse(ssi); mod_parse(src); mod_parse(ctu); + mod_parse(mix); mod_parse(dvc); of_node_put(playback); @@ -1155,6 +1214,7 @@ static int rsnd_probe(struct platform_device *pdev) rsnd_ssi_probe, rsnd_src_probe, rsnd_ctu_probe, + rsnd_mix_probe, rsnd_dvc_probe, rsnd_adg_probe, rsnd_dai_probe, @@ -1251,6 +1311,7 @@ static int rsnd_remove(struct platform_device *pdev) rsnd_ssi_remove, rsnd_src_remove, rsnd_ctu_remove, + rsnd_mix_remove, rsnd_dvc_remove, }; int ret = 0, i; diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 229b68d2cf702..305b129298538 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c @@ -427,6 +427,7 @@ rsnd_gen2_dma_addr(struct rsnd_dai_stream *io, int is_ssi = !!(rsnd_io_to_mod_ssi(io) == mod); int use_src = !!rsnd_io_to_mod_src(io); int use_cmd = !!rsnd_io_to_mod_dvc(io) || + !!rsnd_io_to_mod_mix(io) || !!rsnd_io_to_mod_ctu(io); int id = rsnd_mod_id(mod); struct dma_addr { @@ -506,6 +507,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); struct rsnd_mod *src = rsnd_io_to_mod_src(io); struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); + struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); struct rsnd_mod *mod[MOD_MAX]; struct rsnd_mod *mod_start, *mod_end; @@ -548,6 +550,9 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, } else if (ctu) { mod[i] = ctu; ctu = NULL; + } else if (mix) { + mod[i] = mix; + mix = NULL; } else if (dvc) { mod[i] = dvc; dvc = NULL; diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index 41b75cd4e09b3..f04d17bc6e3de 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c @@ -242,6 +242,16 @@ static int rsnd_gen2_probe(struct platform_device *pdev, RSND_GEN_M_REG(SRC_BSISR, 0x238, 0x40), RSND_GEN_M_REG(CTU_CTUIR, 0x504, 0x100), RSND_GEN_M_REG(CTU_ADINR, 0x508, 0x100), + RSND_GEN_M_REG(MIX_SWRSR, 0xd00, 0x40), + RSND_GEN_M_REG(MIX_MIXIR, 0xd04, 0x40), + RSND_GEN_M_REG(MIX_ADINR, 0xd08, 0x40), + RSND_GEN_M_REG(MIX_MIXMR, 0xd10, 0x40), + RSND_GEN_M_REG(MIX_MVPDR, 0xd14, 0x40), + RSND_GEN_M_REG(MIX_MDBAR, 0xd18, 0x40), + RSND_GEN_M_REG(MIX_MDBBR, 0xd1c, 0x40), + RSND_GEN_M_REG(MIX_MDBCR, 0xd20, 0x40), + RSND_GEN_M_REG(MIX_MDBDR, 0xd24, 0x40), + RSND_GEN_M_REG(MIX_MDBER, 0xd28, 0x40), RSND_GEN_M_REG(DVC_SWRSR, 0xe00, 0x100), RSND_GEN_M_REG(DVC_DVUIR, 0xe04, 0x100), RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100), diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c new file mode 100644 index 0000000000000..0d5c102db6f5f --- /dev/null +++ b/sound/soc/sh/rcar/mix.c @@ -0,0 +1,200 @@ +/* + * mix.c + * + * Copyright (c) 2015 Kuninori Morimoto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include "rsnd.h" + +#define MIX_NAME_SIZE 16 +#define MIX_NAME "mix" + +struct rsnd_mix { + struct rsnd_mix_platform_info *info; /* rcar_snd.h */ + struct rsnd_mod mod; +}; + +#define rsnd_mix_nr(priv) ((priv)->mix_nr) +#define for_each_rsnd_mix(pos, priv, i) \ + for ((i) = 0; \ + ((i) < rsnd_mix_nr(priv)) && \ + ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ + i++) + + +static void rsnd_mix_soft_reset(struct rsnd_mod *mod) +{ + rsnd_mod_write(mod, MIX_SWRSR, 0); + rsnd_mod_write(mod, MIX_SWRSR, 1); +} + +#define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1) +#define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0) +static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable) +{ + rsnd_mod_write(mod, MIX_MIXIR, enable); +} + +static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, + struct rsnd_mod *mod) +{ + + /* Disable MIX dB setting */ + rsnd_mod_write(mod, MIX_MDBER, 0); + + rsnd_mod_write(mod, MIX_MDBAR, 0); + rsnd_mod_write(mod, MIX_MDBBR, 0); + rsnd_mod_write(mod, MIX_MDBCR, 0); + rsnd_mod_write(mod, MIX_MDBDR, 0); + + /* Enable MIX dB setting */ + rsnd_mod_write(mod, MIX_MDBER, 1); +} + +static int rsnd_mix_init(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_start(mod); + + rsnd_mix_soft_reset(mod); + + rsnd_mix_initialize_lock(mod); + + rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); + + rsnd_path_parse(priv, io); + + /* volume step */ + rsnd_mod_write(mod, MIX_MIXMR, 0); + rsnd_mod_write(mod, MIX_MVPDR, 0); + + rsnd_mix_volume_update(io, mod); + + rsnd_mix_initialize_unlock(mod); + + return 0; +} + +static int rsnd_mix_quit(struct rsnd_mod *mod, + struct rsnd_dai_stream *io, + struct rsnd_priv *priv) +{ + rsnd_mod_hw_stop(mod); + + return 0; +} + +static struct rsnd_mod_ops rsnd_mix_ops = { + .name = MIX_NAME, + .init = rsnd_mix_init, + .quit = rsnd_mix_quit, +}; + +struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) +{ + if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) + id = 0; + + return &((struct rsnd_mix *)(priv->mix) + id)->mod; +} + +static void rsnd_of_parse_mix(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct device_node *node; + struct rsnd_mix_platform_info *mix_info; + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = &pdev->dev; + int nr; + + if (!of_data) + return; + + node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); + if (!node) + return; + + nr = of_get_child_count(node); + if (!nr) + goto rsnd_of_parse_mix_end; + + mix_info = devm_kzalloc(dev, + sizeof(struct rsnd_mix_platform_info) * nr, + GFP_KERNEL); + if (!mix_info) { + dev_err(dev, "mix info allocation error\n"); + goto rsnd_of_parse_mix_end; + } + + info->mix_info = mix_info; + info->mix_info_nr = nr; + +rsnd_of_parse_mix_end: + of_node_put(node); + +} + +int rsnd_mix_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv) +{ + struct rcar_snd_info *info = rsnd_priv_to_info(priv); + struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_mix *mix; + struct clk *clk; + char name[MIX_NAME_SIZE]; + int i, nr, ret; + + /* This driver doesn't support Gen1 at this point */ + if (rsnd_is_gen1(priv)) { + dev_warn(dev, "MIX is not supported on Gen1\n"); + return -EINVAL; + } + + rsnd_of_parse_mix(pdev, of_data, priv); + + nr = info->mix_info_nr; + if (!nr) + return 0; + + mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL); + if (!mix) + return -ENOMEM; + + priv->mix_nr = nr; + priv->mix = mix; + + for_each_rsnd_mix(mix, priv, i) { + snprintf(name, MIX_NAME_SIZE, "%s.%d", + MIX_NAME, i); + + clk = devm_clk_get(dev, name); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + mix->info = &info->mix_info[i]; + + ret = rsnd_mod_init(priv, &mix->mod, &rsnd_mix_ops, + clk, RSND_MOD_MIX, i); + if (ret) + return ret; + } + + return 0; +} + +void rsnd_mix_remove(struct platform_device *pdev, + struct rsnd_priv *priv) +{ + struct rsnd_mix *mix; + int i; + + for_each_rsnd_mix(mix, priv, i) { + rsnd_mod_quit(&mix->mod); + } +} diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index f2128a7cf259e..7a0e52b4640a5 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h @@ -49,6 +49,16 @@ enum rsnd_reg { RSND_REG_CMD_ROUTE_SLCT, RSND_REG_CTU_CTUIR, RSND_REG_CTU_ADINR, + RSND_REG_MIX_SWRSR, + RSND_REG_MIX_MIXIR, + RSND_REG_MIX_ADINR, + RSND_REG_MIX_MIXMR, + RSND_REG_MIX_MVPDR, + RSND_REG_MIX_MDBAR, + RSND_REG_MIX_MDBBR, + RSND_REG_MIX_MDBCR, + RSND_REG_MIX_MDBDR, + RSND_REG_MIX_MDBER, RSND_REG_DVC_SWRSR, RSND_REG_DVC_DVUIR, RSND_REG_DVC_ADINR, @@ -222,6 +232,7 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, */ enum rsnd_mod_type { RSND_MOD_DVC = 0, + RSND_MOD_MIX, RSND_MOD_CTU, RSND_MOD_SRC, RSND_MOD_SSI, @@ -355,6 +366,7 @@ struct rsnd_dai_stream { #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) +#define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) #define rsnd_io_to_rdai(io) ((io)->rdai) #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) @@ -472,6 +484,12 @@ struct rsnd_priv { void *ctu; int ctu_nr; + /* + * below value will be filled on rsnd_mix_probe() + */ + void *mix; + int mix_nr; + /* * below value will be filled on rsnd_dvc_probe() */ @@ -588,6 +606,17 @@ void rsnd_ctu_remove(struct platform_device *pdev, struct rsnd_priv *priv); struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); +/* + * R-Car MIX + */ +int rsnd_mix_probe(struct platform_device *pdev, + const struct rsnd_of_data *of_data, + struct rsnd_priv *priv); + +void rsnd_mix_remove(struct platform_device *pdev, + struct rsnd_priv *priv); +struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); + /* * R-Car DVC */ -- GitLab From b4c45fe974bc5fa6240a729ea1f77db8b56d132a Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 14 Jul 2015 23:40:35 -0700 Subject: [PATCH 1143/7006] pinctrl: qcom: ssbi: Family A gpio & mpp drivers This introduces pinctrl drivers for gpio and mpp blocks found in family A PMICs. Tested-by: Srinivas Kandagatla Signed-off-by: Bjorn Andersson Signed-off-by: Linus Walleij --- .../bindings/pinctrl/qcom,pmic-mpp.txt | 5 + drivers/pinctrl/qcom/Kconfig | 12 + drivers/pinctrl/qcom/Makefile | 2 + drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c | 791 ++++++++++++++++ drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c | 882 ++++++++++++++++++ include/dt-bindings/pinctrl/qcom,pmic-mpp.h | 51 + 6 files changed, 1743 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c create mode 100644 drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt index b096d8351b8fc..d7803a2a94e9b 100644 --- a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt +++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt @@ -7,8 +7,13 @@ of PMIC's from Qualcomm. Usage: required Value type: Definition: Should contain one of: + "qcom,pm8018-mpp", + "qcom,pm8038-mpp", + "qcom,pm8821-mpp", "qcom,pm8841-mpp", "qcom,pm8916-mpp", + "qcom,pm8917-mpp", + "qcom,pm8921-mpp", "qcom,pm8941-mpp", "qcom,pma8084-mpp", diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 58f5632b27f45..8eef820b216e6 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -76,4 +76,16 @@ config PINCTRL_QCOM_SPMI_PMIC which are using SPMI for communication with SoC. Example PMIC's devices are pm8841, pm8941 and pma8084. +config PINCTRL_QCOM_SSBI_PMIC + tristate "Qualcomm SSBI PMIC pin controller driver" + depends on GPIOLIB && OF + select PINMUX + select PINCONF + select GENERIC_PINCONF + help + This is the pinctrl, pinmux, pinconf and gpiolib driver for the + Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, + which are using SSBI for communication with SoC. Example PMIC's + devices are pm8058 and pm8921. + endif diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index 3666c703ce889..e321f7ab325bd 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -9,3 +9,5 @@ obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o +obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o +obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-mpp.o diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c new file mode 100644 index 0000000000000..c978b311031b5 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-gpio.c @@ -0,0 +1,791 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinctrl-utils.h" + +/* mode */ +#define PM8XXX_GPIO_MODE_ENABLED BIT(0) +#define PM8XXX_GPIO_MODE_INPUT 0 +#define PM8XXX_GPIO_MODE_OUTPUT 2 + +/* output buffer */ +#define PM8XXX_GPIO_PUSH_PULL 0 +#define PM8XXX_GPIO_OPEN_DRAIN 1 + +/* bias */ +#define PM8XXX_GPIO_BIAS_PU_30 0 +#define PM8XXX_GPIO_BIAS_PU_1P5 1 +#define PM8XXX_GPIO_BIAS_PU_31P5 2 +#define PM8XXX_GPIO_BIAS_PU_1P5_30 3 +#define PM8XXX_GPIO_BIAS_PD 4 +#define PM8XXX_GPIO_BIAS_NP 5 + +/* GPIO registers */ +#define SSBI_REG_ADDR_GPIO_BASE 0x150 +#define SSBI_REG_ADDR_GPIO(n) (SSBI_REG_ADDR_GPIO_BASE + n) + +#define PM8XXX_BANK_WRITE BIT(7) + +#define PM8XXX_MAX_GPIOS 44 + +/* custom pinconf parameters */ +#define PM8XXX_QCOM_DRIVE_STRENGH (PIN_CONFIG_END + 1) +#define PM8XXX_QCOM_PULL_UP_STRENGTH (PIN_CONFIG_END + 2) + +/** + * struct pm8xxx_pin_data - dynamic configuration for a pin + * @reg: address of the control register + * @irq: IRQ from the PMIC interrupt controller + * @power_source: logical selected voltage source, mapping in static data + * is used translate to register values + * @mode: operating mode for the pin (input/output) + * @open_drain: output buffer configured as open-drain (vs push-pull) + * @output_value: configured output value + * @bias: register view of configured bias + * @pull_up_strength: placeholder for selected pull up strength + * only used to configure bias when pull up is selected + * @output_strength: selector of output-strength + * @disable: pin disabled / configured as tristate + * @function: pinmux selector + * @inverted: pin logic is inverted + */ +struct pm8xxx_pin_data { + unsigned reg; + int irq; + u8 power_source; + u8 mode; + bool open_drain; + bool output_value; + u8 bias; + u8 pull_up_strength; + u8 output_strength; + bool disable; + u8 function; + bool inverted; +}; + +struct pm8xxx_gpio { + struct device *dev; + struct regmap *regmap; + struct pinctrl_dev *pctrl; + struct gpio_chip chip; + + struct pinctrl_desc desc; + unsigned npins; +}; + +static const struct pinconf_generic_params pm8xxx_gpio_bindings[] = { + {"qcom,drive-strength", PM8XXX_QCOM_DRIVE_STRENGH, 0}, + {"qcom,pull-up-strength", PM8XXX_QCOM_PULL_UP_STRENGTH, 0}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pm8xxx_conf_items[ARRAY_SIZE(pm8xxx_gpio_bindings)] = { + PCONFDUMP(PM8XXX_QCOM_DRIVE_STRENGH, "drive-strength", NULL, true), + PCONFDUMP(PM8XXX_QCOM_PULL_UP_STRENGTH, "pull up strength", NULL, true), +}; +#endif + +static const char * const pm8xxx_groups[PM8XXX_MAX_GPIOS] = { + "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8", + "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15", + "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22", + "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29", + "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36", + "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", + "gpio44", +}; + +static const char * const pm8xxx_gpio_functions[] = { + PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED, + PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2, + PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2, + PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4, +}; + +static int pm8xxx_read_bank(struct pm8xxx_gpio *pctrl, + struct pm8xxx_pin_data *pin, int bank) +{ + unsigned int val = bank << 4; + int ret; + + ret = regmap_write(pctrl->regmap, pin->reg, val); + if (ret) { + dev_err(pctrl->dev, "failed to select bank %d\n", bank); + return ret; + } + + ret = regmap_read(pctrl->regmap, pin->reg, &val); + if (ret) { + dev_err(pctrl->dev, "failed to read register %d\n", bank); + return ret; + } + + return val; +} + +static int pm8xxx_write_bank(struct pm8xxx_gpio *pctrl, + struct pm8xxx_pin_data *pin, + int bank, + u8 val) +{ + int ret; + + val |= PM8XXX_BANK_WRITE; + val |= bank << 4; + + ret = regmap_write(pctrl->regmap, pin->reg, val); + if (ret) + dev_err(pctrl->dev, "failed to write register\n"); + + return ret; +} + +static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->npins; +} + +static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return pm8xxx_groups[group]; +} + + +static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pctrl->desc.pins[group].number; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops pm8xxx_pinctrl_ops = { + .get_groups_count = pm8xxx_get_groups_count, + .get_group_name = pm8xxx_get_group_name, + .get_group_pins = pm8xxx_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pm8xxx_gpio_functions); +} + +static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + return pm8xxx_gpio_functions[function]; +} + +static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pm8xxx_groups; + *num_groups = pctrl->npins; + return 0; +} + +static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data; + u8 val; + + pin->function = function; + val = pin->function << 1; + + pm8xxx_write_bank(pctrl, pin, 4, val); + + return 0; +} + +static const struct pinmux_ops pm8xxx_pinmux_ops = { + .get_functions_count = pm8xxx_get_functions_count, + .get_function_name = pm8xxx_get_function_name, + .get_function_groups = pm8xxx_get_function_groups, + .set_mux = pm8xxx_pinmux_set_mux, +}; + +static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *config) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param = pinconf_to_config_param(*config); + unsigned arg; + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + arg = pin->bias == PM8XXX_GPIO_BIAS_NP; + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + arg = pin->bias == PM8XXX_GPIO_BIAS_PD; + break; + case PIN_CONFIG_BIAS_PULL_UP: + arg = pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30; + break; + case PM8XXX_QCOM_PULL_UP_STRENGTH: + arg = pin->pull_up_strength; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = pin->disable; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pin->mode == PM8XXX_GPIO_MODE_INPUT; + break; + case PIN_CONFIG_OUTPUT: + if (pin->mode & PM8XXX_GPIO_MODE_OUTPUT) + arg = pin->output_value; + else + arg = 0; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = pin->power_source; + break; + case PM8XXX_QCOM_DRIVE_STRENGH: + arg = pin->output_strength; + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + arg = !pin->open_drain; + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + arg = pin->open_drain; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *configs, + unsigned num_configs) +{ + struct pm8xxx_gpio *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param; + unsigned arg; + unsigned i; + u8 banks = 0; + u8 val; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_DISABLE: + pin->bias = PM8XXX_GPIO_BIAS_NP; + banks |= BIT(2); + pin->disable = 0; + banks |= BIT(3); + break; + case PIN_CONFIG_BIAS_PULL_DOWN: + pin->bias = PM8XXX_GPIO_BIAS_PD; + banks |= BIT(2); + pin->disable = 0; + banks |= BIT(3); + break; + case PM8XXX_QCOM_PULL_UP_STRENGTH: + if (arg > PM8XXX_GPIO_BIAS_PU_1P5_30) { + dev_err(pctrl->dev, "invalid pull-up strength\n"); + return -EINVAL; + } + pin->pull_up_strength = arg; + /* FALLTHROUGH */ + case PIN_CONFIG_BIAS_PULL_UP: + pin->bias = pin->pull_up_strength; + banks |= BIT(2); + pin->disable = 0; + banks |= BIT(3); + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pin->disable = 1; + banks |= BIT(3); + break; + case PIN_CONFIG_INPUT_ENABLE: + pin->mode = PM8XXX_GPIO_MODE_INPUT; + banks |= BIT(0) | BIT(1); + break; + case PIN_CONFIG_OUTPUT: + pin->mode = PM8XXX_GPIO_MODE_OUTPUT; + pin->output_value = !!arg; + banks |= BIT(0) | BIT(1); + break; + case PIN_CONFIG_POWER_SOURCE: + pin->power_source = arg; + banks |= BIT(0); + break; + case PM8XXX_QCOM_DRIVE_STRENGH: + if (arg > PMIC_GPIO_STRENGTH_LOW) { + dev_err(pctrl->dev, "invalid drive strength\n"); + return -EINVAL; + } + pin->output_strength = arg; + banks |= BIT(3); + break; + case PIN_CONFIG_DRIVE_PUSH_PULL: + pin->open_drain = 0; + banks |= BIT(1); + break; + case PIN_CONFIG_DRIVE_OPEN_DRAIN: + pin->open_drain = 1; + banks |= BIT(1); + break; + default: + dev_err(pctrl->dev, + "unsupported config parameter: %x\n", + param); + return -EINVAL; + } + } + + if (banks & BIT(0)) { + val = pin->power_source << 1; + val |= PM8XXX_GPIO_MODE_ENABLED; + pm8xxx_write_bank(pctrl, pin, 0, val); + } + + if (banks & BIT(1)) { + val = pin->mode << 2; + val |= pin->open_drain << 1; + val |= pin->output_value; + pm8xxx_write_bank(pctrl, pin, 1, val); + } + + if (banks & BIT(2)) { + val = pin->bias << 1; + pm8xxx_write_bank(pctrl, pin, 2, val); + } + + if (banks & BIT(3)) { + val = pin->output_strength << 2; + val |= pin->disable; + pm8xxx_write_bank(pctrl, pin, 3, val); + } + + if (banks & BIT(4)) { + val = pin->function << 1; + pm8xxx_write_bank(pctrl, pin, 4, val); + } + + if (banks & BIT(5)) { + val = 0; + if (!pin->inverted) + val |= BIT(3); + pm8xxx_write_bank(pctrl, pin, 5, val); + } + + return 0; +} + +static const struct pinconf_ops pm8xxx_pinconf_ops = { + .is_generic = true, + .pin_config_group_get = pm8xxx_pin_config_get, + .pin_config_group_set = pm8xxx_pin_config_set, +}; + +static struct pinctrl_desc pm8xxx_pinctrl_desc = { + .name = "pm8xxx_gpio", + .pctlops = &pm8xxx_pinctrl_ops, + .pmxops = &pm8xxx_pinmux_ops, + .confops = &pm8xxx_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int pm8xxx_gpio_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + u8 val; + + pin->mode = PM8XXX_GPIO_MODE_INPUT; + val = pin->mode << 2; + + pm8xxx_write_bank(pctrl, pin, 1, val); + + return 0; +} + +static int pm8xxx_gpio_direction_output(struct gpio_chip *chip, + unsigned offset, + int value) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + u8 val; + + pin->mode = PM8XXX_GPIO_MODE_OUTPUT; + pin->output_value = !!value; + + val = pin->mode << 2; + val |= pin->open_drain << 1; + val |= pin->output_value; + + pm8xxx_write_bank(pctrl, pin, 1, val); + + return 0; +} + +static int pm8xxx_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + bool state; + int ret; + + if (pin->mode == PM8XXX_GPIO_MODE_OUTPUT) { + ret = pin->output_value; + } else { + ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); + if (!ret) + ret = !!state; + } + + return ret; +} + +static void pm8xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + u8 val; + + pin->output_value = !!value; + + val = pin->mode << 2; + val |= pin->open_drain << 1; + val |= pin->output_value; + + pm8xxx_write_bank(pctrl, pin, 1, val); +} + +static int pm8xxx_gpio_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) + return -EINVAL; + + if (flags) + *flags = gpio_desc->args[1]; + + return gpio_desc->args[0] - 1; +} + + +static int pm8xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + return pin->irq; +} + +#ifdef CONFIG_DEBUG_FS +#include + +static void pm8xxx_gpio_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, + unsigned gpio) +{ + struct pm8xxx_gpio *pctrl = container_of(chip, struct pm8xxx_gpio, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + static const char * const modes[] = { + "in", "both", "out", "off" + }; + static const char * const biases[] = { + "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA", + "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull" + }; + static const char * const buffer_types[] = { + "push-pull", "open-drain" + }; + static const char * const strengths[] = { + "no", "high", "medium", "low" + }; + + seq_printf(s, " gpio%-2d:", offset + 1); + if (pin->disable) { + seq_puts(s, " ---"); + } else { + seq_printf(s, " %-4s", modes[pin->mode]); + seq_printf(s, " %-7s", pm8xxx_gpio_functions[pin->function]); + seq_printf(s, " VIN%d", pin->power_source); + seq_printf(s, " %-27s", biases[pin->bias]); + seq_printf(s, " %-10s", buffer_types[pin->open_drain]); + seq_printf(s, " %-4s", pin->output_value ? "high" : "low"); + seq_printf(s, " %-7s", strengths[pin->output_strength]); + if (pin->inverted) + seq_puts(s, " inverted"); + } +} + +static void pm8xxx_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned gpio = chip->base; + unsigned i; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + pm8xxx_gpio_dbg_show_one(s, NULL, chip, i, gpio); + seq_puts(s, "\n"); + } +} + +#else +#define msm_gpio_dbg_show NULL +#endif + +static struct gpio_chip pm8xxx_gpio_template = { + .direction_input = pm8xxx_gpio_direction_input, + .direction_output = pm8xxx_gpio_direction_output, + .get = pm8xxx_gpio_get, + .set = pm8xxx_gpio_set, + .of_xlate = pm8xxx_gpio_of_xlate, + .to_irq = pm8xxx_gpio_to_irq, + .dbg_show = pm8xxx_gpio_dbg_show, + .owner = THIS_MODULE, +}; + +static int pm8xxx_pin_populate(struct pm8xxx_gpio *pctrl, + struct pm8xxx_pin_data *pin) +{ + int val; + + val = pm8xxx_read_bank(pctrl, pin, 0); + if (val < 0) + return val; + + pin->power_source = (val >> 1) & 0x7; + + val = pm8xxx_read_bank(pctrl, pin, 1); + if (val < 0) + return val; + + pin->mode = (val >> 2) & 0x3; + pin->open_drain = !!(val & BIT(1)); + pin->output_value = val & BIT(0); + + val = pm8xxx_read_bank(pctrl, pin, 2); + if (val < 0) + return val; + + pin->bias = (val >> 1) & 0x7; + if (pin->bias <= PM8XXX_GPIO_BIAS_PU_1P5_30) + pin->pull_up_strength = pin->bias; + else + pin->pull_up_strength = PM8XXX_GPIO_BIAS_PU_30; + + val = pm8xxx_read_bank(pctrl, pin, 3); + if (val < 0) + return val; + + pin->output_strength = (val >> 2) & 0x3; + pin->disable = val & BIT(0); + + val = pm8xxx_read_bank(pctrl, pin, 4); + if (val < 0) + return val; + + pin->function = (val >> 1) & 0x7; + + val = pm8xxx_read_bank(pctrl, pin, 5); + if (val < 0) + return val; + + pin->inverted = !(val & BIT(3)); + + return 0; +} + +static const struct of_device_id pm8xxx_gpio_of_match[] = { + { .compatible = "qcom,pm8018-gpio", .data = (void *)6 }, + { .compatible = "qcom,pm8038-gpio", .data = (void *)12 }, + { .compatible = "qcom,pm8058-gpio", .data = (void *)40 }, + { .compatible = "qcom,pm8917-gpio", .data = (void *)38 }, + { .compatible = "qcom,pm8921-gpio", .data = (void *)44 }, + { }, +}; +MODULE_DEVICE_TABLE(of, pm8xxx_gpio_of_match); + +static int pm8xxx_gpio_probe(struct platform_device *pdev) +{ + struct pm8xxx_pin_data *pin_data; + struct pinctrl_pin_desc *pins; + struct pm8xxx_gpio *pctrl; + int ret; + int i; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->dev = &pdev->dev; + pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev); + + pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!pctrl->regmap) { + dev_err(&pdev->dev, "parent regmap unavailable\n"); + return -ENXIO; + } + + pctrl->desc = pm8xxx_pinctrl_desc; + pctrl->desc.npins = pctrl->npins; + + pins = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + pin_data = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pm8xxx_pin_data), + GFP_KERNEL); + if (!pin_data) + return -ENOMEM; + + for (i = 0; i < pctrl->desc.npins; i++) { + pin_data[i].reg = SSBI_REG_ADDR_GPIO(i); + pin_data[i].irq = platform_get_irq(pdev, i); + if (pin_data[i].irq < 0) { + dev_err(&pdev->dev, + "missing interrupts for pin %d\n", i); + return pin_data[i].irq; + } + + ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); + if (ret) + return ret; + + pins[i].number = i; + pins[i].name = pm8xxx_groups[i]; + pins[i].drv_data = &pin_data[i]; + } + pctrl->desc.pins = pins; + + pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_gpio_bindings); + pctrl->desc.custom_params = pm8xxx_gpio_bindings; +#ifdef CONFIG_DEBUG_FS + pctrl->desc.custom_conf_items = pm8xxx_conf_items; +#endif + + pctrl->pctrl = pinctrl_register(&pctrl->desc, &pdev->dev, pctrl); + if (!pctrl->pctrl) { + dev_err(&pdev->dev, "couldn't register pm8xxx gpio driver\n"); + return -ENODEV; + } + + pctrl->chip = pm8xxx_gpio_template; + pctrl->chip.base = -1; + pctrl->chip.dev = &pdev->dev; + pctrl->chip.of_node = pdev->dev.of_node; + pctrl->chip.of_gpio_n_cells = 2; + pctrl->chip.label = dev_name(pctrl->dev); + pctrl->chip.ngpio = pctrl->npins; + ret = gpiochip_add(&pctrl->chip); + if (ret) { + dev_err(&pdev->dev, "failed register gpiochip\n"); + goto unregister_pinctrl; + } + + ret = gpiochip_add_pin_range(&pctrl->chip, + dev_name(pctrl->dev), + 0, 0, pctrl->chip.ngpio); + if (ret) { + dev_err(pctrl->dev, "failed to add pin range\n"); + goto unregister_gpiochip; + } + + platform_set_drvdata(pdev, pctrl); + + dev_dbg(&pdev->dev, "Qualcomm pm8xxx gpio driver probed\n"); + + return 0; + +unregister_gpiochip: + gpiochip_remove(&pctrl->chip); + +unregister_pinctrl: + pinctrl_unregister(pctrl->pctrl); + + return ret; +} + +static int pm8xxx_gpio_remove(struct platform_device *pdev) +{ + struct pm8xxx_gpio *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); + + pinctrl_unregister(pctrl->pctrl); + + return 0; +} + +static struct platform_driver pm8xxx_gpio_driver = { + .driver = { + .name = "qcom-ssbi-gpio", + .of_match_table = pm8xxx_gpio_of_match, + }, + .probe = pm8xxx_gpio_probe, + .remove = pm8xxx_gpio_remove, +}; + +module_platform_driver(pm8xxx_gpio_driver); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm PM8xxx GPIO driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c new file mode 100644 index 0000000000000..2d1b69f171be7 --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-ssbi-mpp.c @@ -0,0 +1,882 @@ +/* + * Copyright (c) 2015, Sony Mobile Communications AB. + * Copyright (c) 2013, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "../core.h" +#include "../pinctrl-utils.h" + +/* MPP registers */ +#define SSBI_REG_ADDR_MPP_BASE 0x50 +#define SSBI_REG_ADDR_MPP(n) (SSBI_REG_ADDR_MPP_BASE + n) + +/* MPP Type: type */ +#define PM8XXX_MPP_TYPE_D_INPUT 0 +#define PM8XXX_MPP_TYPE_D_OUTPUT 1 +#define PM8XXX_MPP_TYPE_D_BI_DIR 2 +#define PM8XXX_MPP_TYPE_A_INPUT 3 +#define PM8XXX_MPP_TYPE_A_OUTPUT 4 +#define PM8XXX_MPP_TYPE_SINK 5 +#define PM8XXX_MPP_TYPE_DTEST_SINK 6 +#define PM8XXX_MPP_TYPE_DTEST_OUTPUT 7 + +/* Digital Input: control */ +#define PM8XXX_MPP_DIN_TO_INT 0 +#define PM8XXX_MPP_DIN_TO_DBUS1 1 +#define PM8XXX_MPP_DIN_TO_DBUS2 2 +#define PM8XXX_MPP_DIN_TO_DBUS3 3 + +/* Digital Output: control */ +#define PM8XXX_MPP_DOUT_CTRL_LOW 0 +#define PM8XXX_MPP_DOUT_CTRL_HIGH 1 +#define PM8XXX_MPP_DOUT_CTRL_MPP 2 +#define PM8XXX_MPP_DOUT_CTRL_INV_MPP 3 + +/* Bidirectional: control */ +#define PM8XXX_MPP_BI_PULLUP_1KOHM 0 +#define PM8XXX_MPP_BI_PULLUP_OPEN 1 +#define PM8XXX_MPP_BI_PULLUP_10KOHM 2 +#define PM8XXX_MPP_BI_PULLUP_30KOHM 3 + +/* Analog Output: control */ +#define PM8XXX_MPP_AOUT_CTRL_DISABLE 0 +#define PM8XXX_MPP_AOUT_CTRL_ENABLE 1 +#define PM8XXX_MPP_AOUT_CTRL_MPP_HIGH_EN 2 +#define PM8XXX_MPP_AOUT_CTRL_MPP_LOW_EN 3 + +/* Current Sink: control */ +#define PM8XXX_MPP_CS_CTRL_DISABLE 0 +#define PM8XXX_MPP_CS_CTRL_ENABLE 1 +#define PM8XXX_MPP_CS_CTRL_MPP_HIGH_EN 2 +#define PM8XXX_MPP_CS_CTRL_MPP_LOW_EN 3 + +/* DTEST Current Sink: control */ +#define PM8XXX_MPP_DTEST_CS_CTRL_EN1 0 +#define PM8XXX_MPP_DTEST_CS_CTRL_EN2 1 +#define PM8XXX_MPP_DTEST_CS_CTRL_EN3 2 +#define PM8XXX_MPP_DTEST_CS_CTRL_EN4 3 + +/* DTEST Digital Output: control */ +#define PM8XXX_MPP_DTEST_DBUS1 0 +#define PM8XXX_MPP_DTEST_DBUS2 1 +#define PM8XXX_MPP_DTEST_DBUS3 2 +#define PM8XXX_MPP_DTEST_DBUS4 3 + +/* custom pinconf parameters */ +#define PM8XXX_CONFIG_AMUX (PIN_CONFIG_END + 1) +#define PM8XXX_CONFIG_DTEST_SELECTOR (PIN_CONFIG_END + 2) +#define PM8XXX_CONFIG_ALEVEL (PIN_CONFIG_END + 3) +#define PM8XXX_CONFIG_PAIRED (PIN_CONFIG_END + 4) + +/** + * struct pm8xxx_pin_data - dynamic configuration for a pin + * @reg: address of the control register + * @irq: IRQ from the PMIC interrupt controller + * @mode: operating mode for the pin (digital, analog or current sink) + * @input: pin is input + * @output: pin is output + * @high_z: pin is floating + * @paired: mpp operates in paired mode + * @output_value: logical output value of the mpp + * @power_source: selected power source + * @dtest: DTEST route selector + * @amux: input muxing in analog mode + * @aout_level: selector of the output in analog mode + * @drive_strength: drive strength of the current sink + * @pullup: pull up value, when in digital bidirectional mode + */ +struct pm8xxx_pin_data { + unsigned reg; + int irq; + + u8 mode; + + bool input; + bool output; + bool high_z; + bool paired; + bool output_value; + + u8 power_source; + u8 dtest; + u8 amux; + u8 aout_level; + u8 drive_strength; + unsigned pullup; +}; + +struct pm8xxx_mpp { + struct device *dev; + struct regmap *regmap; + struct pinctrl_dev *pctrl; + struct gpio_chip chip; + + struct pinctrl_desc desc; + unsigned npins; +}; + +static const struct pinconf_generic_params pm8xxx_mpp_bindings[] = { + {"qcom,amux-route", PM8XXX_CONFIG_AMUX, 0}, + {"qcom,analog-level", PM8XXX_CONFIG_ALEVEL, 0}, + {"qcom,dtest", PM8XXX_CONFIG_DTEST_SELECTOR, 0}, + {"qcom,paired", PM8XXX_CONFIG_PAIRED, 0}, +}; + +#ifdef CONFIG_DEBUG_FS +static const struct pin_config_item pm8xxx_conf_items[] = { + PCONFDUMP(PM8XXX_CONFIG_AMUX, "analog mux", NULL, true), + PCONFDUMP(PM8XXX_CONFIG_ALEVEL, "analog level", NULL, true), + PCONFDUMP(PM8XXX_CONFIG_DTEST_SELECTOR, "dtest", NULL, true), + PCONFDUMP(PM8XXX_CONFIG_PAIRED, "paired", NULL, false), +}; +#endif + +#define PM8XXX_MAX_MPPS 12 +static const char * const pm8xxx_groups[PM8XXX_MAX_MPPS] = { + "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8", + "mpp9", "mpp10", "mpp11", "mpp12", +}; + +#define PM8XXX_MPP_DIGITAL 0 +#define PM8XXX_MPP_ANALOG 1 +#define PM8XXX_MPP_SINK 2 + +static const char * const pm8xxx_mpp_functions[] = { + "digital", "analog", "sink", +}; + +static int pm8xxx_mpp_update(struct pm8xxx_mpp *pctrl, + struct pm8xxx_pin_data *pin) +{ + unsigned level; + unsigned ctrl; + unsigned type; + int ret; + u8 val; + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + if (pin->dtest) { + type = PM8XXX_MPP_TYPE_DTEST_OUTPUT; + ctrl = pin->dtest - 1; + } else if (pin->input && pin->output) { + type = PM8XXX_MPP_TYPE_D_BI_DIR; + if (pin->high_z) + ctrl = PM8XXX_MPP_BI_PULLUP_OPEN; + else if (pin->pullup == 600) + ctrl = PM8XXX_MPP_BI_PULLUP_1KOHM; + else if (pin->pullup == 10000) + ctrl = PM8XXX_MPP_BI_PULLUP_10KOHM; + else + ctrl = PM8XXX_MPP_BI_PULLUP_30KOHM; + } else if (pin->input) { + type = PM8XXX_MPP_TYPE_D_INPUT; + if (pin->dtest) + ctrl = pin->dtest; + else + ctrl = PM8XXX_MPP_DIN_TO_INT; + } else { + type = PM8XXX_MPP_TYPE_D_OUTPUT; + ctrl = !!pin->output_value; + if (pin->paired) + ctrl |= BIT(1); + } + + level = pin->power_source; + break; + case PM8XXX_MPP_ANALOG: + if (pin->output) { + type = PM8XXX_MPP_TYPE_A_OUTPUT; + level = pin->aout_level; + ctrl = pin->output_value; + if (pin->paired) + ctrl |= BIT(1); + } else { + type = PM8XXX_MPP_TYPE_A_INPUT; + level = pin->amux; + ctrl = 0; + } + break; + case PM8XXX_MPP_SINK: + level = (pin->drive_strength / 5) - 1; + if (pin->dtest) { + type = PM8XXX_MPP_TYPE_DTEST_SINK; + ctrl = pin->dtest - 1; + } else { + type = PM8XXX_MPP_TYPE_SINK; + ctrl = pin->output_value; + if (pin->paired) + ctrl |= BIT(1); + } + break; + default: + return -EINVAL; + } + + val = type << 5 | level << 2 | ctrl; + ret = regmap_write(pctrl->regmap, pin->reg, val); + if (ret) + dev_err(pctrl->dev, "failed to write register\n"); + + return ret; +} + +static int pm8xxx_get_groups_count(struct pinctrl_dev *pctldev) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + + return pctrl->npins; +} + +static const char *pm8xxx_get_group_name(struct pinctrl_dev *pctldev, + unsigned group) +{ + return pm8xxx_groups[group]; +} + + +static int pm8xxx_get_group_pins(struct pinctrl_dev *pctldev, + unsigned group, + const unsigned **pins, + unsigned *num_pins) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pctrl->desc.pins[group].number; + *num_pins = 1; + + return 0; +} + +static const struct pinctrl_ops pm8xxx_pinctrl_ops = { + .get_groups_count = pm8xxx_get_groups_count, + .get_group_name = pm8xxx_get_group_name, + .get_group_pins = pm8xxx_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static int pm8xxx_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(pm8xxx_mpp_functions); +} + +static const char *pm8xxx_get_function_name(struct pinctrl_dev *pctldev, + unsigned function) +{ + return pm8xxx_mpp_functions[function]; +} + +static int pm8xxx_get_function_groups(struct pinctrl_dev *pctldev, + unsigned function, + const char * const **groups, + unsigned * const num_groups) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + + *groups = pm8xxx_groups; + *num_groups = pctrl->npins; + return 0; +} + +static int pm8xxx_pinmux_set_mux(struct pinctrl_dev *pctldev, + unsigned function, + unsigned group) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[group].drv_data; + + pin->mode = function; + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static const struct pinmux_ops pm8xxx_pinmux_ops = { + .get_functions_count = pm8xxx_get_functions_count, + .get_function_name = pm8xxx_get_function_name, + .get_function_groups = pm8xxx_get_function_groups, + .set_mux = pm8xxx_pinmux_set_mux, +}; + +static int pm8xxx_pin_config_get(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *config) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param = pinconf_to_config_param(*config); + unsigned arg; + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + arg = pin->pullup; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + arg = pin->high_z; + break; + case PIN_CONFIG_INPUT_ENABLE: + arg = pin->input; + break; + case PIN_CONFIG_OUTPUT: + arg = pin->output_value; + break; + case PIN_CONFIG_POWER_SOURCE: + arg = pin->power_source; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + arg = pin->drive_strength; + break; + case PM8XXX_CONFIG_DTEST_SELECTOR: + arg = pin->dtest; + break; + case PM8XXX_CONFIG_AMUX: + arg = pin->amux; + break; + case PM8XXX_CONFIG_ALEVEL: + arg = pin->aout_level; + break; + case PM8XXX_CONFIG_PAIRED: + arg = pin->paired; + break; + default: + return -EINVAL; + } + + *config = pinconf_to_config_packed(param, arg); + + return 0; +} + +static int pm8xxx_pin_config_set(struct pinctrl_dev *pctldev, + unsigned int offset, + unsigned long *configs, + unsigned num_configs) +{ + struct pm8xxx_mpp *pctrl = pinctrl_dev_get_drvdata(pctldev); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + unsigned param; + unsigned arg; + unsigned i; + + for (i = 0; i < num_configs; i++) { + param = pinconf_to_config_param(configs[i]); + arg = pinconf_to_config_argument(configs[i]); + + switch (param) { + case PIN_CONFIG_BIAS_PULL_UP: + pin->pullup = arg; + break; + case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: + pin->high_z = true; + break; + case PIN_CONFIG_INPUT_ENABLE: + pin->input = true; + break; + case PIN_CONFIG_OUTPUT: + pin->output = true; + pin->output_value = !!arg; + break; + case PIN_CONFIG_POWER_SOURCE: + pin->power_source = arg; + break; + case PIN_CONFIG_DRIVE_STRENGTH: + pin->drive_strength = arg; + break; + case PM8XXX_CONFIG_DTEST_SELECTOR: + pin->dtest = arg; + break; + case PM8XXX_CONFIG_AMUX: + pin->amux = arg; + break; + case PM8XXX_CONFIG_ALEVEL: + pin->aout_level = arg; + break; + case PM8XXX_CONFIG_PAIRED: + pin->paired = !!arg; + break; + default: + dev_err(pctrl->dev, + "unsupported config parameter: %x\n", + param); + return -EINVAL; + } + } + + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static const struct pinconf_ops pm8xxx_pinconf_ops = { + .is_generic = true, + .pin_config_group_get = pm8xxx_pin_config_get, + .pin_config_group_set = pm8xxx_pin_config_set, +}; + +static struct pinctrl_desc pm8xxx_pinctrl_desc = { + .name = "pm8xxx_mpp", + .pctlops = &pm8xxx_pinctrl_ops, + .pmxops = &pm8xxx_pinmux_ops, + .confops = &pm8xxx_pinconf_ops, + .owner = THIS_MODULE, +}; + +static int pm8xxx_mpp_direction_input(struct gpio_chip *chip, + unsigned offset) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + pin->input = true; + break; + case PM8XXX_MPP_ANALOG: + pin->input = true; + pin->output = true; + break; + case PM8XXX_MPP_SINK: + return -EINVAL; + } + + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static int pm8xxx_mpp_direction_output(struct gpio_chip *chip, + unsigned offset, + int value) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + pin->output = true; + break; + case PM8XXX_MPP_ANALOG: + pin->input = false; + pin->output = true; + break; + case PM8XXX_MPP_SINK: + pin->input = false; + pin->output = true; + break; + } + + pm8xxx_mpp_update(pctrl, pin); + + return 0; +} + +static int pm8xxx_mpp_get(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + bool state; + int ret; + + if (!pin->input) + return pin->output_value; + + ret = irq_get_irqchip_state(pin->irq, IRQCHIP_STATE_LINE_LEVEL, &state); + if (!ret) + ret = !!state; + + return ret; +} + +static void pm8xxx_mpp_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + pin->output_value = !!value; + + pm8xxx_mpp_update(pctrl, pin); +} + +static int pm8xxx_mpp_of_xlate(struct gpio_chip *chip, + const struct of_phandle_args *gpio_desc, + u32 *flags) +{ + if (chip->of_gpio_n_cells < 2) + return -EINVAL; + + if (flags) + *flags = gpio_desc->args[1]; + + return gpio_desc->args[0] - 1; +} + + +static int pm8xxx_mpp_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + return pin->irq; +} + +#ifdef CONFIG_DEBUG_FS +#include + +static void pm8xxx_mpp_dbg_show_one(struct seq_file *s, + struct pinctrl_dev *pctldev, + struct gpio_chip *chip, + unsigned offset, + unsigned gpio) +{ + struct pm8xxx_mpp *pctrl = container_of(chip, struct pm8xxx_mpp, chip); + struct pm8xxx_pin_data *pin = pctrl->desc.pins[offset].drv_data; + + static const char * const aout_lvls[] = { + "1v25", "1v25_2", "0v625", "0v3125", "mpp", "abus1", "abus2", + "abus3" + }; + + static const char * const amuxs[] = { + "amux5", "amux6", "amux7", "amux8", "amux9", "abus1", "abus2", + "abus3", + }; + + seq_printf(s, " mpp%-2d:", offset + 1); + + switch (pin->mode) { + case PM8XXX_MPP_DIGITAL: + seq_puts(s, " digital "); + if (pin->dtest) { + seq_printf(s, "dtest%d\n", pin->dtest); + } else if (pin->input && pin->output) { + if (pin->high_z) + seq_puts(s, "bi-dir high-z"); + else + seq_printf(s, "bi-dir %dOhm", pin->pullup); + } else if (pin->input) { + if (pin->dtest) + seq_printf(s, "in dtest%d", pin->dtest); + else + seq_puts(s, "in gpio"); + } else if (pin->output) { + seq_puts(s, "out "); + + if (!pin->paired) { + seq_puts(s, pin->output_value ? + "high" : "low"); + } else { + seq_puts(s, pin->output_value ? + "inverted" : "follow"); + } + } + break; + case PM8XXX_MPP_ANALOG: + seq_puts(s, " analog "); + if (pin->output) { + seq_printf(s, "out %s ", aout_lvls[pin->aout_level]); + if (!pin->paired) { + seq_puts(s, pin->output_value ? + "high" : "low"); + } else { + seq_puts(s, pin->output_value ? + "inverted" : "follow"); + } + } else { + seq_printf(s, "input mux %s", amuxs[pin->amux]); + } + break; + case PM8XXX_MPP_SINK: + seq_printf(s, " sink %dmA ", pin->drive_strength); + if (pin->dtest) { + seq_printf(s, "dtest%d", pin->dtest); + } else { + if (!pin->paired) { + seq_puts(s, pin->output_value ? + "high" : "low"); + } else { + seq_puts(s, pin->output_value ? + "inverted" : "follow"); + } + } + break; + } + +} + +static void pm8xxx_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + unsigned gpio = chip->base; + unsigned i; + + for (i = 0; i < chip->ngpio; i++, gpio++) { + pm8xxx_mpp_dbg_show_one(s, NULL, chip, i, gpio); + seq_puts(s, "\n"); + } +} + +#else +#define msm_mpp_dbg_show NULL +#endif + +static struct gpio_chip pm8xxx_mpp_template = { + .direction_input = pm8xxx_mpp_direction_input, + .direction_output = pm8xxx_mpp_direction_output, + .get = pm8xxx_mpp_get, + .set = pm8xxx_mpp_set, + .of_xlate = pm8xxx_mpp_of_xlate, + .to_irq = pm8xxx_mpp_to_irq, + .dbg_show = pm8xxx_mpp_dbg_show, + .owner = THIS_MODULE, +}; + +static int pm8xxx_pin_populate(struct pm8xxx_mpp *pctrl, + struct pm8xxx_pin_data *pin) +{ + unsigned int val; + unsigned level; + unsigned ctrl; + unsigned type; + int ret; + + ret = regmap_read(pctrl->regmap, pin->reg, &val); + if (ret) { + dev_err(pctrl->dev, "failed to read register\n"); + return ret; + } + + type = (val >> 5) & 7; + level = (val >> 2) & 7; + ctrl = (val) & 3; + + switch (type) { + case PM8XXX_MPP_TYPE_D_INPUT: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->input = true; + pin->power_source = level; + pin->dtest = ctrl; + break; + case PM8XXX_MPP_TYPE_D_OUTPUT: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->output = true; + pin->power_source = level; + pin->output_value = !!(ctrl & BIT(0)); + pin->paired = !!(ctrl & BIT(1)); + break; + case PM8XXX_MPP_TYPE_D_BI_DIR: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->input = true; + pin->output = true; + pin->power_source = level; + switch (ctrl) { + case PM8XXX_MPP_BI_PULLUP_1KOHM: + pin->pullup = 600; + break; + case PM8XXX_MPP_BI_PULLUP_OPEN: + pin->high_z = true; + break; + case PM8XXX_MPP_BI_PULLUP_10KOHM: + pin->pullup = 10000; + break; + case PM8XXX_MPP_BI_PULLUP_30KOHM: + pin->pullup = 30000; + break; + } + break; + case PM8XXX_MPP_TYPE_A_INPUT: + pin->mode = PM8XXX_MPP_ANALOG; + pin->input = true; + pin->amux = level; + break; + case PM8XXX_MPP_TYPE_A_OUTPUT: + pin->mode = PM8XXX_MPP_ANALOG; + pin->output = true; + pin->aout_level = level; + pin->output_value = !!(ctrl & BIT(0)); + pin->paired = !!(ctrl & BIT(1)); + break; + case PM8XXX_MPP_TYPE_SINK: + pin->mode = PM8XXX_MPP_SINK; + pin->drive_strength = 5 * (level + 1); + pin->output_value = !!(ctrl & BIT(0)); + pin->paired = !!(ctrl & BIT(1)); + break; + case PM8XXX_MPP_TYPE_DTEST_SINK: + pin->mode = PM8XXX_MPP_SINK; + pin->dtest = ctrl + 1; + pin->drive_strength = 5 * (level + 1); + break; + case PM8XXX_MPP_TYPE_DTEST_OUTPUT: + pin->mode = PM8XXX_MPP_DIGITAL; + pin->power_source = level; + if (ctrl >= 1) + pin->dtest = ctrl; + break; + } + + return 0; +} + +static const struct of_device_id pm8xxx_mpp_of_match[] = { + { .compatible = "qcom,pm8018-mpp", .data = (void *)6 }, + { .compatible = "qcom,pm8038-mpp", .data = (void *)6 }, + { .compatible = "qcom,pm8917-mpp", .data = (void *)10 }, + { .compatible = "qcom,pm8821-mpp", .data = (void *)4 }, + { .compatible = "qcom,pm8921-mpp", .data = (void *)12 }, + { }, +}; +MODULE_DEVICE_TABLE(of, pm8xxx_mpp_of_match); + +static int pm8xxx_mpp_probe(struct platform_device *pdev) +{ + struct pm8xxx_pin_data *pin_data; + struct pinctrl_pin_desc *pins; + struct pm8xxx_mpp *pctrl; + int ret; + int i; + + pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); + if (!pctrl) + return -ENOMEM; + + pctrl->dev = &pdev->dev; + pctrl->npins = (unsigned)of_device_get_match_data(&pdev->dev); + + pctrl->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!pctrl->regmap) { + dev_err(&pdev->dev, "parent regmap unavailable\n"); + return -ENXIO; + } + + pctrl->desc = pm8xxx_pinctrl_desc; + pctrl->desc.npins = pctrl->npins; + + pins = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pinctrl_pin_desc), + GFP_KERNEL); + if (!pins) + return -ENOMEM; + + pin_data = devm_kcalloc(&pdev->dev, + pctrl->desc.npins, + sizeof(struct pm8xxx_pin_data), + GFP_KERNEL); + if (!pin_data) + return -ENOMEM; + + for (i = 0; i < pctrl->desc.npins; i++) { + pin_data[i].reg = SSBI_REG_ADDR_MPP(i); + pin_data[i].irq = platform_get_irq(pdev, i); + if (pin_data[i].irq < 0) { + dev_err(&pdev->dev, + "missing interrupts for pin %d\n", i); + return pin_data[i].irq; + } + + ret = pm8xxx_pin_populate(pctrl, &pin_data[i]); + if (ret) + return ret; + + pins[i].number = i; + pins[i].name = pm8xxx_groups[i]; + pins[i].drv_data = &pin_data[i]; + } + pctrl->desc.pins = pins; + + pctrl->desc.num_custom_params = ARRAY_SIZE(pm8xxx_mpp_bindings); + pctrl->desc.custom_params = pm8xxx_mpp_bindings; +#ifdef CONFIG_DEBUG_FS + pctrl->desc.custom_conf_items = pm8xxx_conf_items; +#endif + + pctrl->pctrl = pinctrl_register(&pctrl->desc, &pdev->dev, pctrl); + if (!pctrl->pctrl) { + dev_err(&pdev->dev, "couldn't register pm8xxx mpp driver\n"); + return -ENODEV; + } + + pctrl->chip = pm8xxx_mpp_template; + pctrl->chip.base = -1; + pctrl->chip.dev = &pdev->dev; + pctrl->chip.of_node = pdev->dev.of_node; + pctrl->chip.of_gpio_n_cells = 2; + pctrl->chip.label = dev_name(pctrl->dev); + pctrl->chip.ngpio = pctrl->npins; + ret = gpiochip_add(&pctrl->chip); + if (ret) { + dev_err(&pdev->dev, "failed register gpiochip\n"); + goto unregister_pinctrl; + } + + ret = gpiochip_add_pin_range(&pctrl->chip, + dev_name(pctrl->dev), + 0, 0, pctrl->chip.ngpio); + if (ret) { + dev_err(pctrl->dev, "failed to add pin range\n"); + goto unregister_gpiochip; + } + + platform_set_drvdata(pdev, pctrl); + + dev_dbg(&pdev->dev, "Qualcomm pm8xxx mpp driver probed\n"); + + return 0; + +unregister_gpiochip: + gpiochip_remove(&pctrl->chip); + +unregister_pinctrl: + pinctrl_unregister(pctrl->pctrl); + + return ret; +} + +static int pm8xxx_mpp_remove(struct platform_device *pdev) +{ + struct pm8xxx_mpp *pctrl = platform_get_drvdata(pdev); + + gpiochip_remove(&pctrl->chip); + + pinctrl_unregister(pctrl->pctrl); + + return 0; +} + +static struct platform_driver pm8xxx_mpp_driver = { + .driver = { + .name = "qcom-ssbi-mpp", + .of_match_table = pm8xxx_mpp_of_match, + }, + .probe = pm8xxx_mpp_probe, + .remove = pm8xxx_mpp_remove, +}; + +module_platform_driver(pm8xxx_mpp_driver); + +MODULE_AUTHOR("Bjorn Andersson "); +MODULE_DESCRIPTION("Qualcomm PM8xxx MPP driver"); +MODULE_LICENSE("GPL v2"); diff --git a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h index c10205491f8d6..a15c1704d0ec6 100644 --- a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h +++ b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h @@ -7,6 +7,47 @@ #define _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H /* power-source */ + +/* Digital Input/Output: level [PM8058] */ +#define PM8058_MPP_VPH 0 +#define PM8058_MPP_S3 1 +#define PM8058_MPP_L2 2 +#define PM8058_MPP_L3 3 + +/* Digital Input/Output: level [PM8901] */ +#define PM8901_MPP_MSMIO 0 +#define PM8901_MPP_DIG 1 +#define PM8901_MPP_L5 2 +#define PM8901_MPP_S4 3 +#define PM8901_MPP_VPH 4 + +/* Digital Input/Output: level [PM8921] */ +#define PM8921_MPP_S4 1 +#define PM8921_MPP_L15 3 +#define PM8921_MPP_L17 4 +#define PM8921_MPP_VPH 7 + +/* Digital Input/Output: level [PM8821] */ +#define PM8821_MPP_1P8 0 +#define PM8821_MPP_VPH 7 + +/* Digital Input/Output: level [PM8018] */ +#define PM8018_MPP_L4 0 +#define PM8018_MPP_L14 1 +#define PM8018_MPP_S3 2 +#define PM8018_MPP_L6 3 +#define PM8018_MPP_L2 4 +#define PM8018_MPP_L5 5 +#define PM8018_MPP_VPH 7 + +/* Digital Input/Output: level [PM8038] */ +#define PM8038_MPP_L20 0 +#define PM8038_MPP_L11 1 +#define PM8038_MPP_L5 2 +#define PM8038_MPP_L15 3 +#define PM8038_MPP_L17 4 +#define PM8038_MPP_VPH 7 + #define PM8841_MPP_VPH 0 #define PM8841_MPP_S3 2 @@ -37,6 +78,16 @@ #define PMIC_MPP_AMUX_ROUTE_ABUS3 6 #define PMIC_MPP_AMUX_ROUTE_ABUS4 7 +/* Analog Output: level */ +#define PMIC_MPP_AOUT_LVL_1V25 0 +#define PMIC_MPP_AOUT_LVL_1V25_2 1 +#define PMIC_MPP_AOUT_LVL_0V625 2 +#define PMIC_MPP_AOUT_LVL_0V3125 3 +#define PMIC_MPP_AOUT_LVL_MPP 4 +#define PMIC_MPP_AOUT_LVL_ABUS1 5 +#define PMIC_MPP_AOUT_LVL_ABUS2 6 +#define PMIC_MPP_AOUT_LVL_ABUS3 7 + /* To be used with "function" */ #define PMIC_MPP_FUNC_NORMAL "normal" #define PMIC_MPP_FUNC_PAIRED "paired" -- GitLab From 8f1338cd80648adf5434798f5393ad7c55d10848 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Wed, 15 Jul 2015 11:47:14 -0500 Subject: [PATCH 1144/7006] pinctrl: add support for Qualcomm Technologies QDF2xxx ARM64 SoCs Add the pinctrl driver for the Qualcomm Technologies QDF2xxx ARM64 SoCs, which uses the Qualcomm Technologies TLMM pinctrl/gpio device. This driver is probed via ACPI and uses the pinctrl-msm.c backend driver. This driver is intended to be used only an ACPI-enabled system. As such, UEFI will handle all pin control configuration, so this driver does not provide pin control functions. It is effectively a GPIO-only driver. Signed-off-by: Timur Tabi Reviewed-by: Bjorn Andersson Signed-off-by: Linus Walleij --- drivers/pinctrl/qcom/Kconfig | 8 ++ drivers/pinctrl/qcom/Makefile | 1 + drivers/pinctrl/qcom/pinctrl-qdf2xxx.c | 122 +++++++++++++++++++++++++ 3 files changed, 131 insertions(+) create mode 100644 drivers/pinctrl/qcom/pinctrl-qdf2xxx.c diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig index 8eef820b216e6..383263a92e59a 100644 --- a/drivers/pinctrl/qcom/Kconfig +++ b/drivers/pinctrl/qcom/Kconfig @@ -63,6 +63,14 @@ config PINCTRL_MSM8916 This is the pinctrl, pinmux, pinconf and gpiolib driver for the Qualcomm TLMM block found on the Qualcomm 8916 platform. +config PINCTRL_QDF2XXX + tristate "Qualcomm Technologies QDF2xxx pin controller driver" + depends on GPIOLIB && ACPI + select PINCTRL_MSM + help + This is the GPIO driver for the TLMM block found on the + Qualcomm Technologies QDF2xxx SOCs. + config PINCTRL_QCOM_SPMI_PMIC tristate "Qualcomm SPMI PMIC pin controller driver" depends on GPIOLIB && OF && SPMI diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile index e321f7ab325bd..13b190e72c219 100644 --- a/drivers/pinctrl/qcom/Makefile +++ b/drivers/pinctrl/qcom/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_MSM8660) += pinctrl-msm8660.o obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o obj-$(CONFIG_PINCTRL_MSM8916) += pinctrl-msm8916.o +obj-$(CONFIG_PINCTRL_QDF2XXX) += pinctrl-qdf2xxx.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o obj-$(CONFIG_PINCTRL_QCOM_SSBI_PMIC) += pinctrl-ssbi-gpio.o diff --git a/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c new file mode 100644 index 0000000000000..e9ff3bc150bbc --- /dev/null +++ b/drivers/pinctrl/qcom/pinctrl-qdf2xxx.c @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * GPIO and pin control functions on this SOC are handled by the "TLMM" + * device. The driver which controls this device is pinctrl-msm.c. Each + * SOC with a TLMM is expected to create a client driver that registers + * with pinctrl-msm.c. This means that all TLMM drivers are pin control + * drivers. + * + * This pin control driver is intended to be used only an ACPI-enabled + * system. As such, UEFI will handle all pin control configuration, so + * this driver does not provide pin control functions. It is effectively + * a GPIO-only driver. The alternative is to duplicate the GPIO code of + * pinctrl-msm.c into another driver. + */ + +#include +#include +#include +#include + +#include "pinctrl-msm.h" + +static struct msm_pinctrl_soc_data qdf2xxx_pinctrl; + +static int qdf2xxx_pinctrl_probe(struct platform_device *pdev) +{ + struct pinctrl_pin_desc *pins; + struct msm_pingroup *groups; + unsigned int i; + u32 num_gpios; + int ret; + + /* Query the number of GPIOs from ACPI */ + ret = device_property_read_u32(&pdev->dev, "num-gpios", &num_gpios); + if (ret < 0) + return ret; + + if (!num_gpios) { + dev_warn(&pdev->dev, "missing num-gpios property\n"); + return -ENODEV; + } + + pins = devm_kcalloc(&pdev->dev, num_gpios, + sizeof(struct pinctrl_pin_desc), GFP_KERNEL); + groups = devm_kcalloc(&pdev->dev, num_gpios, + sizeof(struct msm_pingroup), GFP_KERNEL); + + for (i = 0; i < num_gpios; i++) { + pins[i].number = i; + + groups[i].npins = 1, + groups[i].pins = &pins[i].number; + groups[i].ctl_reg = 0x10000 * i; + groups[i].io_reg = 0x04 + 0x10000 * i; + groups[i].intr_cfg_reg = 0x08 + 0x10000 * i; + groups[i].intr_status_reg = 0x0c + 0x10000 * i; + groups[i].intr_target_reg = 0x08 + 0x10000 * i; + + groups[i].mux_bit = 2; + groups[i].pull_bit = 0; + groups[i].drv_bit = 6; + groups[i].oe_bit = 9; + groups[i].in_bit = 0; + groups[i].out_bit = 1; + groups[i].intr_enable_bit = 0; + groups[i].intr_status_bit = 0; + groups[i].intr_target_bit = 5; + groups[i].intr_target_kpss_val = 1; + groups[i].intr_raw_status_bit = 4; + groups[i].intr_polarity_bit = 1; + groups[i].intr_detection_bit = 2; + groups[i].intr_detection_width = 2; + } + + qdf2xxx_pinctrl.pins = pins; + qdf2xxx_pinctrl.groups = groups; + qdf2xxx_pinctrl.npins = num_gpios; + qdf2xxx_pinctrl.ngroups = num_gpios; + qdf2xxx_pinctrl.ngpios = num_gpios; + + return msm_pinctrl_probe(pdev, &qdf2xxx_pinctrl); +} + +static const struct acpi_device_id qdf2xxx_acpi_ids[] = { + {"QCOM8001"}, + {}, +}; +MODULE_DEVICE_TABLE(acpi, qdf2xxx_acpi_ids); + +static struct platform_driver qdf2xxx_pinctrl_driver = { + .driver = { + .name = "qdf2xxx-pinctrl", + .acpi_match_table = ACPI_PTR(qdf2xxx_acpi_ids), + }, + .probe = qdf2xxx_pinctrl_probe, + .remove = msm_pinctrl_remove, +}; + +static int __init qdf2xxx_pinctrl_init(void) +{ + return platform_driver_register(&qdf2xxx_pinctrl_driver); +} +arch_initcall(qdf2xxx_pinctrl_init); + +static void __exit qdf2xxx_pinctrl_exit(void) +{ + platform_driver_unregister(&qdf2xxx_pinctrl_driver); +} +module_exit(qdf2xxx_pinctrl_exit); + +MODULE_DESCRIPTION("Qualcomm Technologies QDF2xxx pin control driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 03051bc242209f7130aec42d1a6ecb3be9f8f93b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:06 +0200 Subject: [PATCH 1145/7006] pinctrl/rockchip: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 9affcd7257764..626a4a6287e82 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1689,8 +1689,8 @@ static int rockchip_interrupts_register(struct platform_device *pdev, gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type; gc->wake_enabled = IRQ_MSK(bank->nr_pins); - irq_set_handler_data(bank->irq, bank); - irq_set_chained_handler(bank->irq, rockchip_irq_demux); + irq_set_chained_handler_and_data(bank->irq, + rockchip_irq_demux, bank); } return 0; -- GitLab From 20d5d142a645600f28cf42b8e3336f7309897b1e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:06 +0200 Subject: [PATCH 1146/7006] pinctrl: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-single.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 1cd085d921474..07661c86f7ef5 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1767,9 +1767,9 @@ static int pcs_irq_init_chained_handler(struct pcs_device *pcs, return res; } } else { - irq_set_handler_data(pcs_soc->irq, pcs_soc); - irq_set_chained_handler(pcs_soc->irq, - pcs_irq_chain_handler); + irq_set_chained_handler_and_data(pcs_soc->irq, + pcs_irq_chain_handler, + pcs_soc); } /* -- GitLab From c21f7849f126570c0bb1ececbb3ddba7b20cfc03 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 21 Jun 2015 21:11:07 +0200 Subject: [PATCH 1147/7006] pinctrl/exynos: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/samsung/pinctrl-exynos.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index b18dabba03a48..14b02fcedb4b8 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -542,8 +542,9 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d) } weint_data[idx].irq = idx; weint_data[idx].bank = bank; - irq_set_handler_data(irq, &weint_data[idx]); - irq_set_chained_handler(irq, exynos_irq_eint0_15); + irq_set_chained_handler_and_data(irq, + exynos_irq_eint0_15, + &weint_data[idx]); } } -- GitLab From 1aa74fd0bb2cc344c18a625fa1d8e75c00b9bbf8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:41 +0200 Subject: [PATCH 1148/7006] pinctrl/bcm2835: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index efcf2a2b3975c..104d8a63bbce7 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -584,9 +584,9 @@ static int bcm2835_gpio_irq_set_type(struct irq_data *data, unsigned int type) ret = __bcm2835_gpio_irq_set_type_disabled(pc, gpio, type); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(data->irq, handle_edge_irq); + irq_set_handler_locked(data, handle_edge_irq); else - __irq_set_handler_locked(data->irq, handle_level_irq); + irq_set_handler_locked(data, handle_level_irq); spin_unlock_irqrestore(&pc->irq_lock[bank], flags); -- GitLab From f3a085b4174e5806e2e6543323f9a70435ca0098 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:44 +0200 Subject: [PATCH 1149/7006] pinctrl/baytrail: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/intel/pinctrl-baytrail.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 2062c224e32fb..8834fa9df87f1 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -265,9 +265,9 @@ static int byt_irq_type(struct irq_data *d, unsigned type) writel(value, reg); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else if (type & IRQ_TYPE_LEVEL_MASK) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_unlock_irqrestore(&vg->lock, flags); -- GitLab From a4e3f7830fb742039c2c24535af931df3d6d2124 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:44 +0200 Subject: [PATCH 1150/7006] pinctrl/cherryview: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/intel/pinctrl-cherryview.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 3f737daa3fd26..ab87f5c5e9dfa 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1325,7 +1325,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) spin_lock_irqsave(&pctrl->lock, flags); if (!pctrl->intr_lines[intsel]) { - __irq_set_handler_locked(d->irq, handler); + irq_set_handler_locked(d, handler); pctrl->intr_lines[intsel] = offset; } spin_unlock_irqrestore(&pctrl->lock, flags); @@ -1389,9 +1389,9 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) pctrl->intr_lines[value] = offset; if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else if (type & IRQ_TYPE_LEVEL_MASK) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_unlock_irqrestore(&pctrl->lock, flags); -- GitLab From fc756bcd6aadbc59fa7142521729c8d38096ef9c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:45 +0200 Subject: [PATCH 1151/7006] pinctrl/intel: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/intel/pinctrl-intel.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index f9ee0d68b2888..27e4aa6971d16 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -758,9 +758,9 @@ static int intel_gpio_irq_type(struct irq_data *d, unsigned type) writel(value, reg); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else if (type & IRQ_TYPE_LEVEL_MASK) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_unlock_irqrestore(&pctrl->lock, flags); -- GitLab From e0d6a2c6cefc50f123a2386686738820d9a088c6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:47 +0200 Subject: [PATCH 1152/7006] pinctrl/adi2: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and update was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-adi2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-adi2.c b/drivers/pinctrl/pinctrl-adi2.c index c3c3d2345fc6b..a5976ebc44826 100644 --- a/drivers/pinctrl/pinctrl-adi2.c +++ b/drivers/pinctrl/pinctrl-adi2.c @@ -427,10 +427,10 @@ static int adi_gpio_irq_type(struct irq_data *d, unsigned int type) if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) { writel(pintmask, &pint_regs->edge_set); - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); } else { writel(pintmask, &pint_regs->edge_clear); - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); } out: -- GitLab From 9d8293147e8a09ac42018cfeb672cc0a3b90f65b Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:47 +0200 Subject: [PATCH 1153/7006] pinctrl/amd: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-amd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index d8e3f7c7fea35..ef72a8a8dc204 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -420,7 +420,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_EDGE_FALLING: @@ -428,7 +428,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_EDGE_BOTH: @@ -436,7 +436,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg &= ~(ACTIVE_LEVEL_MASK << ACTIVE_LEVEL_OFF); pin_reg |= BOTH_EADGE << ACTIVE_LEVEL_OFF; pin_reg |= DB_TYPE_REMOVE_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); break; case IRQ_TYPE_LEVEL_HIGH: @@ -445,7 +445,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg |= ACTIVE_HIGH << ACTIVE_LEVEL_OFF; pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); pin_reg |= DB_TYPE_PRESERVE_LOW_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); break; case IRQ_TYPE_LEVEL_LOW: @@ -454,7 +454,7 @@ static int amd_gpio_irq_set_type(struct irq_data *d, unsigned int type) pin_reg |= ACTIVE_LOW << ACTIVE_LEVEL_OFF; pin_reg &= ~(DB_CNTRl_MASK << DB_CNTRL_OFF); pin_reg |= DB_TYPE_PRESERVE_HIGH_GLITCH << DB_CNTRL_OFF; - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); break; case IRQ_TYPE_NONE: -- GitLab From c639845bcb87df4abffab94d72bd165d203c34a1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:49 +0200 Subject: [PATCH 1154/7006] pinctrl/at91: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-at91.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index a0824477072bd..6cec3861dff75 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1444,22 +1444,22 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type) switch (type) { case IRQ_TYPE_EDGE_RISING: - __irq_set_handler_locked(d->irq, handle_simple_irq); + irq_set_handler_locked(d, handle_simple_irq); writel_relaxed(mask, pio + PIO_ESR); writel_relaxed(mask, pio + PIO_REHLSR); break; case IRQ_TYPE_EDGE_FALLING: - __irq_set_handler_locked(d->irq, handle_simple_irq); + irq_set_handler_locked(d, handle_simple_irq); writel_relaxed(mask, pio + PIO_ESR); writel_relaxed(mask, pio + PIO_FELLSR); break; case IRQ_TYPE_LEVEL_LOW: - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); writel_relaxed(mask, pio + PIO_LSR); writel_relaxed(mask, pio + PIO_FELLSR); break; case IRQ_TYPE_LEVEL_HIGH: - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); writel_relaxed(mask, pio + PIO_LSR); writel_relaxed(mask, pio + PIO_REHLSR); break; @@ -1468,7 +1468,7 @@ static int alt_gpio_irq_type(struct irq_data *d, unsigned type) * disable additional interrupt modes: * fall back to default behavior */ - __irq_set_handler_locked(d->irq, handle_simple_irq); + irq_set_handler_locked(d, handle_simple_irq); writel_relaxed(mask, pio + PIO_AIMDR); return 0; case IRQ_TYPE_NONE: -- GitLab From 2dbf1bc5a29c5912679d687d2a826f201e75e89d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:50 +0200 Subject: [PATCH 1155/7006] pinctrl/rockchip: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 626a4a6287e82..6e56c962b6553 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1555,9 +1555,9 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type) spin_unlock_irqrestore(&bank->slock, flags); if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); spin_lock_irqsave(&bank->slock, flags); irq_gc_lock(gc); -- GitLab From 34c0ad84f316e19f06af3c2764fe20cac110d985 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:51 +0200 Subject: [PATCH 1156/7006] pinctrl/qcom: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/qcom/pinctrl-msm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 6242af8a42d5f..367ddbf518f76 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -734,9 +734,9 @@ static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) spin_unlock_irqrestore(&pctrl->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return 0; } -- GitLab From 40ec168ace3b963ddf768919ce96461ed885f9c8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:57 +0200 Subject: [PATCH 1157/7006] pinctrl/exynos: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/samsung/pinctrl-exynos.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 14b02fcedb4b8..f402eff2867ad 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -148,9 +148,9 @@ static int exynos_irq_set_type(struct irq_data *irqd, unsigned int type) } if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(irqd->irq, handle_edge_irq); + irq_set_handler_locked(irqd, handle_edge_irq); else - __irq_set_handler_locked(irqd->irq, handle_level_irq); + irq_set_handler_locked(irqd, handle_level_irq); con = readl(d->virt_base + reg_con); con &= ~(EXYNOS_EINT_CON_MASK << shift); -- GitLab From f66eb498ff131d52f9c7b73f0a25a5e3b9095528 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Tue, 23 Jun 2015 15:52:57 +0200 Subject: [PATCH 1158/7006] pinctrl/samsung: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 8 ++++---- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 01b43dbfb795b..7a77eae60b833 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -131,13 +131,13 @@ static int s3c24xx_eint_get_trigger(unsigned int type) } } -static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type) +static void s3c24xx_eint_set_handler(struct irq_data *d, unsigned int type) { /* Edge- and level-triggered interrupts need different handlers */ if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); } static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d, @@ -181,7 +181,7 @@ static int s3c24xx_eint_type(struct irq_data *data, unsigned int type) return -EINVAL; } - s3c24xx_eint_set_handler(data->irq, type); + s3c24xx_eint_set_handler(data, type); /* Set up interrupt trigger */ reg = d->virt_base + EINT_REG(index); diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index ec8cc3b476213..41050f4c67dc0 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -260,13 +260,13 @@ static int s3c64xx_irq_get_trigger(unsigned int type) return trigger; } -static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type) +static void s3c64xx_irq_set_handler(struct irq_data *d, unsigned int type) { /* Edge- and level-triggered interrupts need different handlers */ if (type & IRQ_TYPE_EDGE_BOTH) - __irq_set_handler_locked(irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); else - __irq_set_handler_locked(irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); } static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d, @@ -356,7 +356,7 @@ static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) return -EINVAL; } - s3c64xx_irq_set_handler(irqd->irq, type); + s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ reg = d->virt_base + EINTCON_REG(bank->eint_offset); @@ -567,7 +567,7 @@ static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type) return -EINVAL; } - s3c64xx_irq_set_handler(irqd->irq, type); + s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ reg = d->virt_base + EINT0CON0_REG; -- GitLab From 5663bb27dec1a2bfaf9d92e3685834b91a36a5a3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Thu, 4 Jun 2015 12:13:16 +0800 Subject: [PATCH 1159/7006] pinctrl: Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc Use irq_desc_get_xxx() to avoid redundant lookup of irq_desc while we already have a pointer to corresponding irq_desc. Signed-off-by: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org Signed-off-by: Thomas Gleixner --- drivers/pinctrl/intel/pinctrl-cherryview.c | 2 +- drivers/pinctrl/intel/pinctrl-intel.c | 2 +- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 4 ++-- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 12 +++++----- drivers/pinctrl/pinctrl-amd.c | 2 +- drivers/pinctrl/pinctrl-at91.c | 2 +- drivers/pinctrl/pinctrl-coh901.c | 4 ++-- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- drivers/pinctrl/pinctrl-single.c | 2 +- drivers/pinctrl/pinctrl-st.c | 6 ++--- drivers/pinctrl/qcom/pinctrl-msm.c | 2 +- drivers/pinctrl/samsung/pinctrl-exynos.c | 8 +++---- drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 18 +++++++-------- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 22 +++++++++---------- drivers/pinctrl/sirf/pinctrl-sirf.c | 2 +- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 4 ++-- 16 files changed, 46 insertions(+), 50 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index ab87f5c5e9dfa..f9a4767657367 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -1412,7 +1412,7 @@ static void chv_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); unsigned long pending; u32 intr_line; diff --git a/drivers/pinctrl/intel/pinctrl-intel.c b/drivers/pinctrl/intel/pinctrl-intel.c index 27e4aa6971d16..bb377c110541b 100644 --- a/drivers/pinctrl/intel/pinctrl-intel.c +++ b/drivers/pinctrl/intel/pinctrl-intel.c @@ -840,7 +840,7 @@ static void intel_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct intel_pinctrl *pctrl = gpiochip_to_pinctrl(gc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int i; chained_irq_enter(chip, desc); diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index ad1ea1695b4ae..4be0124e99361 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1118,8 +1118,8 @@ mtk_eint_debounce_process(struct mtk_pinctrl *pctl, int index) static void mtk_eint_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct mtk_pinctrl *pctl = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct mtk_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned int status, eint_num; int offset, index, virq; const struct mtk_eint_offsets *eint_offsets = diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 809d88445db5a..56e79c12562eb 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -843,10 +843,9 @@ static void nmk_gpio_irq_shutdown(struct irq_data *d) clk_disable(nmk_chip->clk); } -static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc, - u32 status) +static void __nmk_gpio_irq_handler(struct irq_desc *desc, u32 status) { - struct irq_chip *host_chip = irq_get_chip(irq); + struct irq_chip *host_chip = irq_desc_get_chip(desc); struct gpio_chip *chip = irq_desc_get_handler_data(desc); chained_irq_enter(host_chip, desc); @@ -871,17 +870,16 @@ static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) status = readl(nmk_chip->addr + NMK_GPIO_IS); clk_disable(nmk_chip->clk); - __nmk_gpio_irq_handler(irq, desc, status); + __nmk_gpio_irq_handler(desc, status); } -static void nmk_gpio_latent_irq_handler(unsigned int irq, - struct irq_desc *desc) +static void nmk_gpio_latent_irq_handler(unsigned int irq, struct irq_desc *desc) { struct gpio_chip *chip = irq_desc_get_handler_data(desc); struct nmk_gpio_chip *nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); u32 status = nmk_chip->get_latent_status(nmk_chip->bank); - __nmk_gpio_irq_handler(irq, desc, status); + __nmk_gpio_irq_handler(desc, status); } /* I/O Functions */ diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index ef72a8a8dc204..2663a055546ea 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -501,7 +501,7 @@ static void amd_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u64 reg64; int handled = 0; unsigned long flags; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct amd_gpio *gpio_dev = to_amd_gpio(gc); diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 6cec3861dff75..e1ab69928bba3 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1596,7 +1596,7 @@ static struct irq_chip gpio_irqchip = { static void gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); struct gpio_chip *gpio_chip = irq_desc_get_handler_data(desc); struct at91_gpio_chip *at91_gpio = container_of(gpio_chip, struct at91_gpio_chip, chip); diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 29cbbab8c3a67..9579442a221db 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -521,8 +521,8 @@ static struct irq_chip u300_gpio_irqchip = { static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *parent_chip = irq_get_chip(irq); - struct gpio_chip *chip = irq_get_handler_data(irq); + struct irq_chip *parent_chip = irq_desc_get_chip(desc); + struct gpio_chip *chip = irq_desc_get_handler_data(desc); struct u300_gpio *gpio = to_u300_gpio(chip); struct u300_gpio_port *port = &gpio->ports[irq - chip->base]; int pinoffset = port->number << 3; /* get the right stride */ diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 6e56c962b6553..28f9d08faf278 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1471,8 +1471,8 @@ static const struct gpio_chip rockchip_gpiolib_chip = { static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct rockchip_pin_bank *bank = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc); u32 pend; dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name); diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index 07661c86f7ef5..b8aaf9559dddb 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1684,7 +1684,7 @@ static void pcs_irq_chain_handler(unsigned int irq, struct irq_desc *desc) struct pcs_soc_data *pcs_soc = irq_desc_get_handler_data(desc); struct irq_chip *chip; - chip = irq_get_chip(irq); + chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); pcs_irq_handle(pcs_soc); /* REVISIT: export and add handle_bad_irq(irq, desc)? */ diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c index c262e5f35c280..f8338d2e6b6b9 100644 --- a/drivers/pinctrl/pinctrl-st.c +++ b/drivers/pinctrl/pinctrl-st.c @@ -1463,7 +1463,7 @@ static void __gpio_irq_handler(struct st_gpio_bank *bank) static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc) { /* interrupt dedicated per bank */ - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct st_gpio_bank *bank = gpio_chip_to_bank(gc); @@ -1474,8 +1474,8 @@ static void st_gpio_irq_handler(unsigned irq, struct irq_desc *desc) static void st_gpio_irqmux_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct st_pinctrl *info = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct st_pinctrl *info = irq_desc_get_handler_data(desc); unsigned long status; int n; diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 367ddbf518f76..3fd39921b3e86 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -770,7 +770,7 @@ static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) struct gpio_chip *gc = irq_desc_get_handler_data(desc); const struct msm_pingroup *g; struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int irq_pin; int handled = 0; u32 val; diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index f402eff2867ad..07773c70c12cf 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -422,9 +422,9 @@ static const struct of_device_id exynos_wkup_irq_ids[] = { /* interrupt handler for wakeup interrupts 0..15 */ static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc) { - struct exynos_weint_data *eintd = irq_get_handler_data(irq); + struct exynos_weint_data *eintd = irq_desc_get_handler_data(desc); struct samsung_pin_bank *bank = eintd->bank; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int eint_irq; chained_irq_enter(chip, desc); @@ -454,8 +454,8 @@ static inline void exynos_irq_demux_eint(unsigned long pend, /* interrupt handler for wakeup interrupt 16 */ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct exynos_muxed_weint_data *eintd = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct exynos_muxed_weint_data *eintd = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *d = eintd->banks[0]->drvdata; unsigned long pend; unsigned long mask; diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 7a77eae60b833..5d7b6112fc7e4 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -243,7 +243,7 @@ static struct irq_chip s3c2410_eint0_3_chip = { static void s3c2410_demux_eint0_3(unsigned int irq, struct irq_desc *desc) { struct irq_data *data = irq_desc_get_irq_data(desc); - struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq); + struct s3c24xx_eint_data *eint_data = irq_desc_get_handler_data(desc); unsigned int virq; /* the first 4 eints have a simple 1 to 1 mapping */ @@ -297,9 +297,9 @@ static struct irq_chip s3c2412_eint0_3_chip = { static void s3c2412_demux_eint0_3(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); + struct s3c24xx_eint_data *eint_data = irq_desc_get_handler_data(desc); struct irq_data *data = irq_desc_get_irq_data(desc); - struct s3c24xx_eint_data *eint_data = irq_get_handler_data(irq); + struct irq_chip *chip = irq_data_get_irq_chip(data); unsigned int virq; chained_irq_enter(chip, desc); @@ -357,11 +357,11 @@ static struct irq_chip s3c24xx_eint_chip = { .irq_set_type = s3c24xx_eint_type, }; -static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc, +static inline void s3c24xx_demux_eint(struct irq_desc *desc, u32 offset, u32 range) { - struct irq_chip *chip = irq_get_chip(irq); - struct s3c24xx_eint_data *data = irq_get_handler_data(irq); + struct s3c24xx_eint_data *data = irq_desc_get_handler_data(desc); + struct irq_chip *chip = irq_desc_get_irq_chip(desc); struct samsung_pinctrl_drv_data *d = data->drvdata; unsigned int pend, mask; @@ -374,7 +374,7 @@ static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc, pend &= range; while (pend) { - unsigned int virq; + unsigned int virq, irq; irq = __ffs(pend); pend &= ~(1 << irq); @@ -390,12 +390,12 @@ static inline void s3c24xx_demux_eint(unsigned int irq, struct irq_desc *desc, static void s3c24xx_demux_eint4_7(unsigned int irq, struct irq_desc *desc) { - s3c24xx_demux_eint(irq, desc, 0, 0xf0); + s3c24xx_demux_eint(desc, 0, 0xf0); } static void s3c24xx_demux_eint8_23(unsigned int irq, struct irq_desc *desc) { - s3c24xx_demux_eint(irq, desc, 8, 0xffff00); + s3c24xx_demux_eint(desc, 8, 0xffff00); } static irq_flow_handler_t s3c2410_eint_handlers[NUM_EINT_IRQ] = { diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 41050f4c67dc0..8700f0c9eee15 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -410,8 +410,8 @@ static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = { static void s3c64xx_eint_gpio_irq(unsigned int irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct s3c64xx_eint_gpio_data *data = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct s3c64xx_eint_gpio_data *data = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *drvdata = data->drvdata; chained_irq_enter(chip, desc); @@ -599,11 +599,10 @@ static struct irq_chip s3c64xx_eint0_irq_chip = { .irq_set_type = s3c64xx_eint0_irq_set_type, }; -static inline void s3c64xx_irq_demux_eint(unsigned int irq, - struct irq_desc *desc, u32 range) +static inline void s3c64xx_irq_demux_eint(struct irq_desc *desc, u32 range) { - struct irq_chip *chip = irq_get_chip(irq); - struct s3c64xx_eint0_data *data = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct s3c64xx_eint0_data *data = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *drvdata = data->drvdata; unsigned int pend, mask; @@ -616,11 +615,10 @@ static inline void s3c64xx_irq_demux_eint(unsigned int irq, pend &= range; while (pend) { - unsigned int virq; + unsigned int virq, irq; irq = fls(pend) - 1; pend &= ~(1 << irq); - virq = irq_linear_revmap(data->domains[irq], data->pins[irq]); /* * Something must be really wrong if an unmapped EINT @@ -636,22 +634,22 @@ static inline void s3c64xx_irq_demux_eint(unsigned int irq, static void s3c64xx_demux_eint0_3(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xf); + s3c64xx_irq_demux_eint(desc, 0xf); } static void s3c64xx_demux_eint4_11(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xff0); + s3c64xx_irq_demux_eint(desc, 0xff0); } static void s3c64xx_demux_eint12_19(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xff000); + s3c64xx_irq_demux_eint(desc, 0xff000); } static void s3c64xx_demux_eint20_27(unsigned int irq, struct irq_desc *desc) { - s3c64xx_irq_demux_eint(irq, desc, 0xff00000); + s3c64xx_irq_demux_eint(desc, 0xff00000); } static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = { diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 8ba26e45499a3..9455a2acf6c61 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -552,7 +552,7 @@ static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) struct sirfsoc_gpio_bank *bank; u32 status, ctrl; int idx = 0; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); int i; for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) { diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index f09573e132035..4b1a35cc5578e 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -711,8 +711,8 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) { - struct irq_chip *chip = irq_get_chip(irq); - struct sunxi_pinctrl *pctl = irq_get_handler_data(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned long bank, reg, val; for (bank = 0; bank < pctl->desc->irq_banks; bank++) -- GitLab From fa00fecc16acd80b455f14803ad35195cdcef65d Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:48:51 +0200 Subject: [PATCH 1160/7006] pinctrl/amd: Prepare amd_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij --- drivers/pinctrl/pinctrl-amd.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-amd.c b/drivers/pinctrl/pinctrl-amd.c index 2663a055546ea..5e86bb8ca80e6 100644 --- a/drivers/pinctrl/pinctrl-amd.c +++ b/drivers/pinctrl/pinctrl-amd.c @@ -492,8 +492,9 @@ static struct irq_chip amd_gpio_irqchip = { .irq_set_type = amd_gpio_irq_set_type, }; -static void amd_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void amd_gpio_irq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); u32 i; u32 off; u32 reg; -- GitLab From fc02a46938fa2dd2494e20ca7b81c687bd027df4 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:50:02 +0200 Subject: [PATCH 1161/7006] pinctrl/coh901: Prepare u300_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-coh901.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-coh901.c b/drivers/pinctrl/pinctrl-coh901.c index 9579442a221db..3731cc67a88bf 100644 --- a/drivers/pinctrl/pinctrl-coh901.c +++ b/drivers/pinctrl/pinctrl-coh901.c @@ -519,8 +519,9 @@ static struct irq_chip u300_gpio_irqchip = { .irq_set_type = u300_gpio_irq_type, }; -static void u300_gpio_irq_handler(unsigned irq, struct irq_desc *desc) +static void u300_gpio_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_chip *parent_chip = irq_desc_get_chip(desc); struct gpio_chip *chip = irq_desc_get_handler_data(desc); struct u300_gpio *gpio = to_u300_gpio(chip); -- GitLab From f43ebaf126d3f4b869ba5bcfb11a00f33f0892cf Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:50:50 +0200 Subject: [PATCH 1162/7006] pinctrl/pistachio: Prepare pistachio_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-pistachio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-pistachio.c b/drivers/pinctrl/pinctrl-pistachio.c index 63100be810152..3dc2ae15f3a10 100644 --- a/drivers/pinctrl/pinctrl-pistachio.c +++ b/drivers/pinctrl/pinctrl-pistachio.c @@ -1310,9 +1310,11 @@ static int pistachio_gpio_irq_set_type(struct irq_data *data, unsigned int type) return 0; } -static void pistachio_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void pistachio_gpio_irq_handler(unsigned int __irq, + struct irq_desc *desc) { - struct gpio_chip *gc = irq_get_handler_data(irq); + unsigned int irq = irq_desc_get_irq(desc); + struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct pistachio_gpio_bank *bank = gc_to_bank(gc); struct irq_chip *chip = irq_get_chip(irq); unsigned long pending; -- GitLab From 415f748c8658033d37af520dfa321a9413b7d665 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:52:00 +0200 Subject: [PATCH 1163/7006] pinctrl/rockchip: Prepare rockchip_irq_demux for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/pinctrl-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c index 28f9d08faf278..cc2843a1f38cd 100644 --- a/drivers/pinctrl/pinctrl-rockchip.c +++ b/drivers/pinctrl/pinctrl-rockchip.c @@ -1469,7 +1469,7 @@ static const struct gpio_chip rockchip_gpiolib_chip = { * Interrupt handling */ -static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) +static void rockchip_irq_demux(unsigned int __irq, struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct rockchip_pin_bank *bank = irq_desc_get_handler_data(desc); @@ -1482,7 +1482,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc) pend = readl_relaxed(bank->reg_base + GPIO_INT_STATUS); while (pend) { - unsigned int virq; + unsigned int irq, virq; irq = __ffs(pend); pend &= ~BIT(irq); -- GitLab From d1800c234703465b1f0b75aba51e27d7a3f47060 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:53:06 +0200 Subject: [PATCH 1164/7006] pinctrl/qcom/msm: Prepare msm_gpio_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/qcom/pinctrl-msm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 3fd39921b3e86..492cdd51dc5c7 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -765,8 +765,9 @@ static struct irq_chip msm_gpio_irq_chip = { .irq_set_wake = msm_gpio_irq_set_wake, }; -static void msm_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +static void msm_gpio_irq_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); const struct msm_pingroup *g; struct msm_pinctrl *pctrl = to_msm_pinctrl(gc); -- GitLab From 3b0d1561ea5787a40b2f014d4f3dc48a575c3675 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:54:35 +0200 Subject: [PATCH 1165/7006] pinctrl/sirf: Prepare xxx_gpio-handle_irq for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 5 +++-- drivers/pinctrl/sirf/pinctrl-sirf.c | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index d6e80fe1c7f79..0cd945c3af67d 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -4286,14 +4286,15 @@ static struct irq_chip atlas7_gpio_irq_chip = { .irq_set_type = atlas7_gpio_irq_type, }; -static void atlas7_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) +static void atlas7_gpio_handle_irq(unsigned int __irq, struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct atlas7_gpio_chip *a7gc = to_atlas7_gpio(gc); struct atlas7_gpio_bank *bank = NULL; u32 status, ctrl; int pin_in_bank = 0, idx; - struct irq_chip *chip = irq_get_chip(irq); + struct irq_chip *chip = irq_desc_get_chip(desc); + unsigned int irq = irq_desc_get_irq(desc); for (idx = 0; idx < a7gc->nbank; idx++) { bank = &a7gc->banks[idx]; diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c index 9455a2acf6c61..f8bd9fb52033d 100644 --- a/drivers/pinctrl/sirf/pinctrl-sirf.c +++ b/drivers/pinctrl/sirf/pinctrl-sirf.c @@ -545,8 +545,9 @@ static struct irq_chip sirfsoc_irq_chip = { .irq_set_type = sirfsoc_gpio_irq_type, }; -static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc) +static void sirfsoc_gpio_handle_irq(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct gpio_chip *gc = irq_desc_get_handler_data(desc); struct sirfsoc_gpio_chip *sgpio = to_sirfsoc_gpio(gc); struct sirfsoc_gpio_bank *bank; -- GitLab From eeef97b182fcbd4e32803be4f0b369d51e4c8535 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 01:55:27 +0200 Subject: [PATCH 1166/7006] pinctrl/sunxi: Prepare sunxi_pinctrl_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: Linus Walleij Cc: linux-gpio@vger.kernel.org --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 4b1a35cc5578e..3e905480ec56c 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -709,8 +709,9 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { IRQCHIP_EOI_IF_HANDLED, }; -static void sunxi_pinctrl_irq_handler(unsigned irq, struct irq_desc *desc) +static void sunxi_pinctrl_irq_handler(unsigned __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); struct irq_chip *chip = irq_desc_get_chip(desc); struct sunxi_pinctrl *pctl = irq_desc_get_handler_data(desc); unsigned long bank, reg, val; -- GitLab From 6de52c15132f6b86030bf3159020e3314ec14952 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 17 Jul 2015 21:37:09 +0800 Subject: [PATCH 1167/7006] pinctrl: pinconf: pinconf_show_config() can be static Signed-off-by: Fengguang Wu Signed-off-by: Linus Walleij --- drivers/pinctrl/pinconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c index cbf26a6992a03..078e58d74fc0a 100644 --- a/drivers/pinctrl/pinconf.c +++ b/drivers/pinctrl/pinconf.c @@ -202,7 +202,7 @@ int pinconf_apply_setting(struct pinctrl_setting const *setting) #ifdef CONFIG_DEBUG_FS -void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, +static void pinconf_show_config(struct seq_file *s, struct pinctrl_dev *pctldev, unsigned long *configs, unsigned num_configs) { const struct pinconf_ops *confops; -- GitLab From e0548f1979bfee900fb0671a5dd3a2f217dce5df Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 17 Jul 2015 22:24:32 +0200 Subject: [PATCH 1168/7006] drm/i915: Update DRIVER_DATE to 20150717 Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 01fbdc57462a2..23ce125e0298e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -56,7 +56,7 @@ #define DRIVER_NAME "i915" #define DRIVER_DESC "Intel Graphics" -#define DRIVER_DATE "20150703" +#define DRIVER_DATE "20150717" #undef WARN_ON /* Many gcc seem to no see through this and fall over :( */ -- GitLab From c2efefb33abfb245395199137ece3c1e3df47f51 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:53:43 +0200 Subject: [PATCH 1169/7006] ACPI / scan: Move sysfs-related device code to a separate file To reduce the size of scan.c and improve the readability of it, move all code related to device sysfs, modalias creation etc. to a new file called device_sysfs.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Makefile | 2 +- drivers/acpi/device_sysfs.c | 521 ++++++++++++++++++++++++++++++++++++ drivers/acpi/internal.h | 9 + drivers/acpi/scan.c | 483 +-------------------------------- 4 files changed, 532 insertions(+), 483 deletions(-) create mode 100644 drivers/acpi/device_sysfs.c diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8321430d7f24a..08ac1100e2dcc 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -24,7 +24,7 @@ acpi-y += nvs.o # Power management related files acpi-y += wakeup.o acpi-$(CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT) += sleep.o -acpi-y += device_pm.o +acpi-y += device_sysfs.o device_pm.o acpi-$(CONFIG_ACPI_SLEEP) += proc.o diff --git a/drivers/acpi/device_sysfs.c b/drivers/acpi/device_sysfs.c new file mode 100644 index 0000000000000..4ab4582e586b7 --- /dev/null +++ b/drivers/acpi/device_sysfs.c @@ -0,0 +1,521 @@ +/* + * drivers/acpi/device_sysfs.c - ACPI device sysfs attributes and modalias. + * + * Copyright (C) 2015, Intel Corp. + * Author: Mika Westerberg + * Author: Rafael J. Wysocki + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +#include +#include +#include +#include + +#include "internal.h" + +/** + * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent + * @acpi_dev: ACPI device object. + * @modalias: Buffer to print into. + * @size: Size of the buffer. + * + * Creates hid/cid(s) string needed for modalias and uevent + * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: + * char *modalias: "acpi:IBM0001:ACPI0001" + * Return: 0: no _HID and no _CID + * -EINVAL: output error + * -ENOMEM: output is truncated +*/ +static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, + int size) +{ + int len; + int count; + struct acpi_hardware_id *id; + + /* + * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should + * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the + * device's list. + */ + count = 0; + list_for_each_entry(id, &acpi_dev->pnp.ids, list) + if (strcmp(id->id, ACPI_DT_NAMESPACE_HID)) + count++; + + if (!count) + return 0; + + len = snprintf(modalias, size, "acpi:"); + if (len <= 0) + return len; + + size -= len; + + list_for_each_entry(id, &acpi_dev->pnp.ids, list) { + if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID)) + continue; + + count = snprintf(&modalias[len], size, "%s:", id->id); + if (count < 0) + return -EINVAL; + + if (count >= size) + return -ENOMEM; + + len += count; + size -= count; + } + modalias[len] = '\0'; + return len; +} + +/** + * create_of_modalias - Creates DT compatible string for modalias and uevent + * @acpi_dev: ACPI device object. + * @modalias: Buffer to print into. + * @size: Size of the buffer. + * + * Expose DT compatible modalias as of:NnameTCcompatible. This function should + * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of + * ACPI/PNP IDs. + */ +static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, + int size) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + const union acpi_object *of_compatible, *obj; + int len, count; + int i, nval; + char *c; + + acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); + /* DT strings are all in lower case */ + for (c = buf.pointer; *c != '\0'; c++) + *c = tolower(*c); + + len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); + ACPI_FREE(buf.pointer); + + if (len <= 0) + return len; + + of_compatible = acpi_dev->data.of_compatible; + if (of_compatible->type == ACPI_TYPE_PACKAGE) { + nval = of_compatible->package.count; + obj = of_compatible->package.elements; + } else { /* Must be ACPI_TYPE_STRING. */ + nval = 1; + obj = of_compatible; + } + for (i = 0; i < nval; i++, obj++) { + count = snprintf(&modalias[len], size, "C%s", + obj->string.pointer); + if (count < 0) + return -EINVAL; + + if (count >= size) + return -ENOMEM; + + len += count; + size -= count; + } + modalias[len] = '\0'; + return len; +} + +int __acpi_device_uevent_modalias(struct acpi_device *adev, + struct kobj_uevent_env *env) +{ + int len; + + if (!adev) + return -ENODEV; + + if (list_empty(&adev->pnp.ids)) + return 0; + + if (add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + len = create_pnp_modalias(adev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len < 0) + return len; + + env->buflen += len; + if (!adev->data.of_compatible) + return 0; + + if (len > 0 && add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + len = create_of_modalias(adev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len < 0) + return len; + + env->buflen += len; + + return 0; +} + +/** + * acpi_device_uevent_modalias - uevent modalias for ACPI-enumerated devices. + * + * Create the uevent modalias field for ACPI-enumerated devices. + * + * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with + * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001". + */ +int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +{ + return __acpi_device_uevent_modalias(acpi_companion_match(dev), env); +} +EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); + +static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size) +{ + int len, count; + + if (!adev) + return -ENODEV; + + if (list_empty(&adev->pnp.ids)) + return 0; + + len = create_pnp_modalias(adev, buf, size - 1); + if (len < 0) { + return len; + } else if (len > 0) { + buf[len++] = '\n'; + size -= len; + } + if (!adev->data.of_compatible) + return len; + + count = create_of_modalias(adev, buf + len, size - 1); + if (count < 0) { + return count; + } else if (count > 0) { + len += count; + buf[len++] = '\n'; + } + + return len; +} + +/** + * acpi_device_modalias - modalias sysfs attribute for ACPI-enumerated devices. + * + * Create the modalias sysfs attribute for ACPI-enumerated devices. + * + * Because other buses do not support ACPI HIDs & CIDs, e.g. for a device with + * hid:IBM0001 and cid:ACPI0001 you get: "acpi:IBM0001:ACPI0001". + */ +int acpi_device_modalias(struct device *dev, char *buf, int size) +{ + return __acpi_device_modalias(acpi_companion_match(dev), buf, size); +} +EXPORT_SYMBOL_GPL(acpi_device_modalias); + +static ssize_t +acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { + return __acpi_device_modalias(to_acpi_device(dev), buf, 1024); +} +static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); + +static ssize_t real_power_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *adev = to_acpi_device(dev); + int state; + int ret; + + ret = acpi_device_get_power(adev, &state); + if (ret) + return ret; + + return sprintf(buf, "%s\n", acpi_power_state_string(state)); +} + +static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL); + +static ssize_t power_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *adev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state)); +} + +static DEVICE_ATTR(power_state, 0444, power_state_show, NULL); + +static ssize_t +acpi_eject_store(struct device *d, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(d); + acpi_object_type not_used; + acpi_status status; + + if (!count || buf[0] != '1') + return -EINVAL; + + if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) + && !acpi_device->driver) + return -ENODEV; + + status = acpi_get_type(acpi_device->handle, ¬_used); + if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) + return -ENODEV; + + get_device(&acpi_device->dev); + status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT); + if (ACPI_SUCCESS(status)) + return count; + + put_device(&acpi_device->dev); + acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, + ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); + return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; +} + +static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); + +static ssize_t +acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev)); +} +static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); + +static ssize_t acpi_device_uid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); +} +static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); + +static ssize_t acpi_device_adr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + + return sprintf(buf, "0x%08x\n", + (unsigned int)(acpi_dev->pnp.bus_address)); +} +static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); + +static ssize_t +acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; + int result; + + result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); + if (result) + goto end; + + result = sprintf(buf, "%s\n", (char*)path.pointer); + kfree(path.pointer); +end: + return result; +} +static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); + +/* sysfs file that shows description text from the ACPI _STR method */ +static ssize_t description_show(struct device *dev, + struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + int result; + + if (acpi_dev->pnp.str_obj == NULL) + return 0; + + /* + * The _STR object contains a Unicode identifier for a device. + * We need to convert to utf-8 so it can be displayed. + */ + result = utf16s_to_utf8s( + (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer, + acpi_dev->pnp.str_obj->buffer.length, + UTF16_LITTLE_ENDIAN, buf, + PAGE_SIZE); + + buf[result++] = '\n'; + + return result; +} +static DEVICE_ATTR(description, 0444, description_show, NULL); + +static ssize_t +acpi_device_sun_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_status status; + unsigned long long sun; + + status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%llu\n", sun); +} +static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); + +static ssize_t status_show(struct device *dev, struct device_attribute *attr, + char *buf) { + struct acpi_device *acpi_dev = to_acpi_device(dev); + acpi_status status; + unsigned long long sta; + + status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta); + if (ACPI_FAILURE(status)) + return -ENODEV; + + return sprintf(buf, "%llu\n", sta); +} +static DEVICE_ATTR_RO(status); + +/** + * acpi_device_setup_files - Create sysfs attributes of an ACPI device. + * @dev: ACPI device object. + */ +int acpi_device_setup_files(struct acpi_device *dev) +{ + struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; + acpi_status status; + int result = 0; + + /* + * Devices gotten from FADT don't have a "path" attribute + */ + if (dev->handle) { + result = device_create_file(&dev->dev, &dev_attr_path); + if (result) + goto end; + } + + if (!list_empty(&dev->pnp.ids)) { + result = device_create_file(&dev->dev, &dev_attr_hid); + if (result) + goto end; + + result = device_create_file(&dev->dev, &dev_attr_modalias); + if (result) + goto end; + } + + /* + * If device has _STR, 'description' file is created + */ + if (acpi_has_method(dev->handle, "_STR")) { + status = acpi_evaluate_object(dev->handle, "_STR", + NULL, &buffer); + if (ACPI_FAILURE(status)) + buffer.pointer = NULL; + dev->pnp.str_obj = buffer.pointer; + result = device_create_file(&dev->dev, &dev_attr_description); + if (result) + goto end; + } + + if (dev->pnp.type.bus_address) + result = device_create_file(&dev->dev, &dev_attr_adr); + if (dev->pnp.unique_id) + result = device_create_file(&dev->dev, &dev_attr_uid); + + if (acpi_has_method(dev->handle, "_SUN")) { + result = device_create_file(&dev->dev, &dev_attr_sun); + if (result) + goto end; + } + + if (acpi_has_method(dev->handle, "_STA")) { + result = device_create_file(&dev->dev, &dev_attr_status); + if (result) + goto end; + } + + /* + * If device has _EJ0, 'eject' file is created that is used to trigger + * hot-removal function from userland. + */ + if (acpi_has_method(dev->handle, "_EJ0")) { + result = device_create_file(&dev->dev, &dev_attr_eject); + if (result) + return result; + } + + if (dev->flags.power_manageable) { + result = device_create_file(&dev->dev, &dev_attr_power_state); + if (result) + return result; + + if (dev->power.flags.power_resources) + result = device_create_file(&dev->dev, + &dev_attr_real_power_state); + } + +end: + return result; +} + +/** + * acpi_device_remove_files - Remove sysfs attributes of an ACPI device. + * @dev: ACPI device object. + */ +void acpi_device_remove_files(struct acpi_device *dev) +{ + if (dev->flags.power_manageable) { + device_remove_file(&dev->dev, &dev_attr_power_state); + if (dev->power.flags.power_resources) + device_remove_file(&dev->dev, + &dev_attr_real_power_state); + } + + /* + * If device has _STR, remove 'description' file + */ + if (acpi_has_method(dev->handle, "_STR")) { + kfree(dev->pnp.str_obj); + device_remove_file(&dev->dev, &dev_attr_description); + } + /* + * If device has _EJ0, remove 'eject' file. + */ + if (acpi_has_method(dev->handle, "_EJ0")) + device_remove_file(&dev->dev, &dev_attr_eject); + + if (acpi_has_method(dev->handle, "_SUN")) + device_remove_file(&dev->dev, &dev_attr_sun); + + if (dev->pnp.unique_id) + device_remove_file(&dev->dev, &dev_attr_uid); + if (dev->pnp.type.bus_address) + device_remove_file(&dev->dev, &dev_attr_adr); + device_remove_file(&dev->dev, &dev_attr_modalias); + device_remove_file(&dev->dev, &dev_attr_hid); + if (acpi_has_method(dev->handle, "_STA")) + device_remove_file(&dev->dev, &dev_attr_status); + if (dev->handle) + device_remove_file(&dev->dev, &dev_attr_path); +} diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4683a96932b91..c529454532dc7 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -93,11 +93,20 @@ int acpi_device_add(struct acpi_device *device, void (*release)(struct device *)); void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, int type, unsigned long long sta); +int acpi_device_setup_files(struct acpi_device *dev); +void acpi_device_remove_files(struct acpi_device *dev); void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); +/* -------------------------------------------------------------------------- + Device Matching and Notification + -------------------------------------------------------------------------- */ +struct acpi_device *acpi_companion_match(const struct device *dev); +int __acpi_device_uevent_modalias(struct acpi_device *adev, + struct kobj_uevent_env *env); + /* -------------------------------------------------------------------------- Power Resource -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ec256352f4236..099831fc8449b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -115,117 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, return 0; } -/** - * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent - * @acpi_dev: ACPI device object. - * @modalias: Buffer to print into. - * @size: Size of the buffer. - * - * Creates hid/cid(s) string needed for modalias and uevent - * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: - * char *modalias: "acpi:IBM0001:ACPI0001" - * Return: 0: no _HID and no _CID - * -EINVAL: output error - * -ENOMEM: output is truncated -*/ -static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, - int size) -{ - int len; - int count; - struct acpi_hardware_id *id; - - /* - * Since we skip ACPI_DT_NAMESPACE_HID from the modalias below, 0 should - * be returned if ACPI_DT_NAMESPACE_HID is the only ACPI/PNP ID in the - * device's list. - */ - count = 0; - list_for_each_entry(id, &acpi_dev->pnp.ids, list) - if (strcmp(id->id, ACPI_DT_NAMESPACE_HID)) - count++; - - if (!count) - return 0; - - len = snprintf(modalias, size, "acpi:"); - if (len <= 0) - return len; - - size -= len; - - list_for_each_entry(id, &acpi_dev->pnp.ids, list) { - if (!strcmp(id->id, ACPI_DT_NAMESPACE_HID)) - continue; - - count = snprintf(&modalias[len], size, "%s:", id->id); - if (count < 0) - return -EINVAL; - - if (count >= size) - return -ENOMEM; - - len += count; - size -= count; - } - modalias[len] = '\0'; - return len; -} - -/** - * create_of_modalias - Creates DT compatible string for modalias and uevent - * @acpi_dev: ACPI device object. - * @modalias: Buffer to print into. - * @size: Size of the buffer. - * - * Expose DT compatible modalias as of:NnameTCcompatible. This function should - * only be called for devices having ACPI_DT_NAMESPACE_HID in their list of - * ACPI/PNP IDs. - */ -static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, - int size) -{ - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; - const union acpi_object *of_compatible, *obj; - int len, count; - int i, nval; - char *c; - - acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); - /* DT strings are all in lower case */ - for (c = buf.pointer; *c != '\0'; c++) - *c = tolower(*c); - - len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); - ACPI_FREE(buf.pointer); - - if (len <= 0) - return len; - - of_compatible = acpi_dev->data.of_compatible; - if (of_compatible->type == ACPI_TYPE_PACKAGE) { - nval = of_compatible->package.count; - obj = of_compatible->package.elements; - } else { /* Must be ACPI_TYPE_STRING. */ - nval = 1; - obj = of_compatible; - } - for (i = 0; i < nval; i++, obj++) { - count = snprintf(&modalias[len], size, "C%s", - obj->string.pointer); - if (count < 0) - return -EINVAL; - - if (count >= size) - return -ENOMEM; - - len += count; - size -= count; - } - modalias[len] = '\0'; - return len; -} - /* * acpi_companion_match() - Can we match via ACPI companion device * @dev: Device in question @@ -247,7 +136,7 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, * resources available from it but they will be matched normally using functions * provided by their bus types (and analogously for their modalias). */ -static struct acpi_device *acpi_companion_match(const struct device *dev) +struct acpi_device *acpi_companion_match(const struct device *dev) { struct acpi_device *adev; struct mutex *physical_node_lock; @@ -276,103 +165,6 @@ static struct acpi_device *acpi_companion_match(const struct device *dev) return adev; } -static int __acpi_device_uevent_modalias(struct acpi_device *adev, - struct kobj_uevent_env *env) -{ - int len; - - if (!adev) - return -ENODEV; - - if (list_empty(&adev->pnp.ids)) - return 0; - - if (add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - - len = create_pnp_modalias(adev, &env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen); - if (len < 0) - return len; - - env->buflen += len; - if (!adev->data.of_compatible) - return 0; - - if (len > 0 && add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - - len = create_of_modalias(adev, &env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen); - if (len < 0) - return len; - - env->buflen += len; - - return 0; -} - -/* - * Creates uevent modalias field for ACPI enumerated devices. - * Because the other buses does not support ACPI HIDs & CIDs. - * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: - * "acpi:IBM0001:ACPI0001" - */ -int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) -{ - return __acpi_device_uevent_modalias(acpi_companion_match(dev), env); -} -EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); - -static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size) -{ - int len, count; - - if (!adev) - return -ENODEV; - - if (list_empty(&adev->pnp.ids)) - return 0; - - len = create_pnp_modalias(adev, buf, size - 1); - if (len < 0) { - return len; - } else if (len > 0) { - buf[len++] = '\n'; - size -= len; - } - if (!adev->data.of_compatible) - return len; - - count = create_of_modalias(adev, buf + len, size - 1); - if (count < 0) { - return count; - } else if (count > 0) { - len += count; - buf[len++] = '\n'; - } - - return len; -} - -/* - * Creates modalias sysfs attribute for ACPI enumerated devices. - * Because the other buses does not support ACPI HIDs & CIDs. - * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: - * "acpi:IBM0001:ACPI0001" - */ -int acpi_device_modalias(struct device *dev, char *buf, int size) -{ - return __acpi_device_modalias(acpi_companion_match(dev), buf, size); -} -EXPORT_SYMBOL_GPL(acpi_device_modalias); - -static ssize_t -acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - return __acpi_device_modalias(to_acpi_device(dev), buf, 1024); -} -static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); - bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) { struct acpi_device_physical_node *pn; @@ -701,279 +493,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) unlock_device_hotplug(); } -static ssize_t real_power_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *adev = to_acpi_device(dev); - int state; - int ret; - - ret = acpi_device_get_power(adev, &state); - if (ret) - return ret; - - return sprintf(buf, "%s\n", acpi_power_state_string(state)); -} - -static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL); - -static ssize_t power_state_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *adev = to_acpi_device(dev); - - return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state)); -} - -static DEVICE_ATTR(power_state, 0444, power_state_show, NULL); - -static ssize_t -acpi_eject_store(struct device *d, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct acpi_device *acpi_device = to_acpi_device(d); - acpi_object_type not_used; - acpi_status status; - - if (!count || buf[0] != '1') - return -EINVAL; - - if ((!acpi_device->handler || !acpi_device->handler->hotplug.enabled) - && !acpi_device->driver) - return -ENODEV; - - status = acpi_get_type(acpi_device->handle, ¬_used); - if (ACPI_FAILURE(status) || !acpi_device->flags.ejectable) - return -ENODEV; - - get_device(&acpi_device->dev); - status = acpi_hotplug_schedule(acpi_device, ACPI_OST_EC_OSPM_EJECT); - if (ACPI_SUCCESS(status)) - return count; - - put_device(&acpi_device->dev); - acpi_evaluate_ost(acpi_device->handle, ACPI_OST_EC_OSPM_EJECT, - ACPI_OST_SC_NON_SPECIFIC_FAILURE, NULL); - return status == AE_NO_MEMORY ? -ENOMEM : -EAGAIN; -} - -static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store); - -static ssize_t -acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - - return sprintf(buf, "%s\n", acpi_device_hid(acpi_dev)); -} -static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL); - -static ssize_t acpi_device_uid_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - - return sprintf(buf, "%s\n", acpi_dev->pnp.unique_id); -} -static DEVICE_ATTR(uid, 0444, acpi_device_uid_show, NULL); - -static ssize_t acpi_device_adr_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - - return sprintf(buf, "0x%08x\n", - (unsigned int)(acpi_dev->pnp.bus_address)); -} -static DEVICE_ATTR(adr, 0444, acpi_device_adr_show, NULL); - -static ssize_t -acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL}; - int result; - - result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path); - if (result) - goto end; - - result = sprintf(buf, "%s\n", (char*)path.pointer); - kfree(path.pointer); -end: - return result; -} -static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL); - -/* sysfs file that shows description text from the ACPI _STR method */ -static ssize_t description_show(struct device *dev, - struct device_attribute *attr, - char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - int result; - - if (acpi_dev->pnp.str_obj == NULL) - return 0; - - /* - * The _STR object contains a Unicode identifier for a device. - * We need to convert to utf-8 so it can be displayed. - */ - result = utf16s_to_utf8s( - (wchar_t *)acpi_dev->pnp.str_obj->buffer.pointer, - acpi_dev->pnp.str_obj->buffer.length, - UTF16_LITTLE_ENDIAN, buf, - PAGE_SIZE); - - buf[result++] = '\n'; - - return result; -} -static DEVICE_ATTR(description, 0444, description_show, NULL); - -static ssize_t -acpi_device_sun_show(struct device *dev, struct device_attribute *attr, - char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - acpi_status status; - unsigned long long sun; - - status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) - return -ENODEV; - - return sprintf(buf, "%llu\n", sun); -} -static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL); - -static ssize_t status_show(struct device *dev, struct device_attribute *attr, - char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - acpi_status status; - unsigned long long sta; - - status = acpi_evaluate_integer(acpi_dev->handle, "_STA", NULL, &sta); - if (ACPI_FAILURE(status)) - return -ENODEV; - - return sprintf(buf, "%llu\n", sta); -} -static DEVICE_ATTR_RO(status); - -static int acpi_device_setup_files(struct acpi_device *dev) -{ - struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; - acpi_status status; - int result = 0; - - /* - * Devices gotten from FADT don't have a "path" attribute - */ - if (dev->handle) { - result = device_create_file(&dev->dev, &dev_attr_path); - if (result) - goto end; - } - - if (!list_empty(&dev->pnp.ids)) { - result = device_create_file(&dev->dev, &dev_attr_hid); - if (result) - goto end; - - result = device_create_file(&dev->dev, &dev_attr_modalias); - if (result) - goto end; - } - - /* - * If device has _STR, 'description' file is created - */ - if (acpi_has_method(dev->handle, "_STR")) { - status = acpi_evaluate_object(dev->handle, "_STR", - NULL, &buffer); - if (ACPI_FAILURE(status)) - buffer.pointer = NULL; - dev->pnp.str_obj = buffer.pointer; - result = device_create_file(&dev->dev, &dev_attr_description); - if (result) - goto end; - } - - if (dev->pnp.type.bus_address) - result = device_create_file(&dev->dev, &dev_attr_adr); - if (dev->pnp.unique_id) - result = device_create_file(&dev->dev, &dev_attr_uid); - - if (acpi_has_method(dev->handle, "_SUN")) { - result = device_create_file(&dev->dev, &dev_attr_sun); - if (result) - goto end; - } - - if (acpi_has_method(dev->handle, "_STA")) { - result = device_create_file(&dev->dev, &dev_attr_status); - if (result) - goto end; - } - - /* - * If device has _EJ0, 'eject' file is created that is used to trigger - * hot-removal function from userland. - */ - if (acpi_has_method(dev->handle, "_EJ0")) { - result = device_create_file(&dev->dev, &dev_attr_eject); - if (result) - return result; - } - - if (dev->flags.power_manageable) { - result = device_create_file(&dev->dev, &dev_attr_power_state); - if (result) - return result; - - if (dev->power.flags.power_resources) - result = device_create_file(&dev->dev, - &dev_attr_real_power_state); - } - -end: - return result; -} - -static void acpi_device_remove_files(struct acpi_device *dev) -{ - if (dev->flags.power_manageable) { - device_remove_file(&dev->dev, &dev_attr_power_state); - if (dev->power.flags.power_resources) - device_remove_file(&dev->dev, - &dev_attr_real_power_state); - } - - /* - * If device has _STR, remove 'description' file - */ - if (acpi_has_method(dev->handle, "_STR")) { - kfree(dev->pnp.str_obj); - device_remove_file(&dev->dev, &dev_attr_description); - } - /* - * If device has _EJ0, remove 'eject' file. - */ - if (acpi_has_method(dev->handle, "_EJ0")) - device_remove_file(&dev->dev, &dev_attr_eject); - - if (acpi_has_method(dev->handle, "_SUN")) - device_remove_file(&dev->dev, &dev_attr_sun); - - if (dev->pnp.unique_id) - device_remove_file(&dev->dev, &dev_attr_uid); - if (dev->pnp.type.bus_address) - device_remove_file(&dev->dev, &dev_attr_adr); - device_remove_file(&dev->dev, &dev_attr_modalias); - device_remove_file(&dev->dev, &dev_attr_hid); - if (acpi_has_method(dev->handle, "_STA")) - device_remove_file(&dev->dev, &dev_attr_status); - if (dev->handle) - device_remove_file(&dev->dev, &dev_attr_path); -} /* -------------------------------------------------------------------------- ACPI Bus operations -------------------------------------------------------------------------- */ -- GitLab From 68c6b148daa6e45a85b31ef60ed9c9bfd556fff0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:53:52 +0200 Subject: [PATCH 1170/7006] ACPI / scan: Move device matching code to bus.c To reduce the size of scan.c and improve the readability of it, move code related device matching into drivers/acpi/bus.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 194 ++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 189 ------------------------------------------ 2 files changed, 194 insertions(+), 189 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 513e7230e3d04..ce805809b00bd 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -423,6 +423,200 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) acpi_evaluate_ost(handle, type, ost_code, NULL); } +/* -------------------------------------------------------------------------- + Device Matching + -------------------------------------------------------------------------- */ + +/* + * acpi_companion_match() - Can we match via ACPI companion device + * @dev: Device in question + * + * Check if the given device has an ACPI companion and if that companion has + * a valid list of PNP IDs, and if the device is the first (primary) physical + * device associated with it. Return the companion pointer if that's the case + * or NULL otherwise. + * + * If multiple physical devices are attached to a single ACPI companion, we need + * to be careful. The usage scenario for this kind of relationship is that all + * of the physical devices in question use resources provided by the ACPI + * companion. A typical case is an MFD device where all the sub-devices share + * the parent's ACPI companion. In such cases we can only allow the primary + * (first) physical device to be matched with the help of the companion's PNP + * IDs. + * + * Additional physical devices sharing the ACPI companion can still use + * resources available from it but they will be matched normally using functions + * provided by their bus types (and analogously for their modalias). + */ +struct acpi_device *acpi_companion_match(const struct device *dev) +{ + struct acpi_device *adev; + struct mutex *physical_node_lock; + + adev = ACPI_COMPANION(dev); + if (!adev) + return NULL; + + if (list_empty(&adev->pnp.ids)) + return NULL; + + physical_node_lock = &adev->physical_node_lock; + mutex_lock(physical_node_lock); + if (list_empty(&adev->physical_node_list)) { + adev = NULL; + } else { + const struct acpi_device_physical_node *node; + + node = list_first_entry(&adev->physical_node_list, + struct acpi_device_physical_node, node); + if (node->dev != dev) + adev = NULL; + } + mutex_unlock(physical_node_lock); + + return adev; +} + +/** + * acpi_of_match_device - Match device object using the "compatible" property. + * @adev: ACPI device object to match. + * @of_match_table: List of device IDs to match against. + * + * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of + * identifiers and a _DSD object with the "compatible" property, use that + * property to match against the given list of identifiers. + */ +static bool acpi_of_match_device(struct acpi_device *adev, + const struct of_device_id *of_match_table) +{ + const union acpi_object *of_compatible, *obj; + int i, nval; + + if (!adev) + return false; + + of_compatible = adev->data.of_compatible; + if (!of_match_table || !of_compatible) + return false; + + if (of_compatible->type == ACPI_TYPE_PACKAGE) { + nval = of_compatible->package.count; + obj = of_compatible->package.elements; + } else { /* Must be ACPI_TYPE_STRING. */ + nval = 1; + obj = of_compatible; + } + /* Now we can look for the driver DT compatible strings */ + for (i = 0; i < nval; i++, obj++) { + const struct of_device_id *id; + + for (id = of_match_table; id->compatible[0]; id++) + if (!strcasecmp(obj->string.pointer, id->compatible)) + return true; + } + + return false; +} + +static bool __acpi_match_device_cls(const struct acpi_device_id *id, + struct acpi_hardware_id *hwid) +{ + int i, msk, byte_shift; + char buf[3]; + + if (!id->cls) + return false; + + /* Apply class-code bitmask, before checking each class-code byte */ + for (i = 1; i <= 3; i++) { + byte_shift = 8 * (3 - i); + msk = (id->cls_msk >> byte_shift) & 0xFF; + if (!msk) + continue; + + sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); + if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) + return false; + } + return true; +} + +static const struct acpi_device_id *__acpi_match_device( + struct acpi_device *device, + const struct acpi_device_id *ids, + const struct of_device_id *of_ids) +{ + const struct acpi_device_id *id; + struct acpi_hardware_id *hwid; + + /* + * If the device is not present, it is unnecessary to load device + * driver for it. + */ + if (!device || !device->status.present) + return NULL; + + list_for_each_entry(hwid, &device->pnp.ids, list) { + /* First, check the ACPI/PNP IDs provided by the caller. */ + for (id = ids; id->id[0] || id->cls; id++) { + if (id->id[0] && !strcmp((char *) id->id, hwid->id)) + return id; + else if (id->cls && __acpi_match_device_cls(id, hwid)) + return id; + } + + /* + * Next, check ACPI_DT_NAMESPACE_HID and try to match the + * "compatible" property if found. + * + * The id returned by the below is not valid, but the only + * caller passing non-NULL of_ids here is only interested in + * whether or not the return value is NULL. + */ + if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id) + && acpi_of_match_device(device, of_ids)) + return id; + } + return NULL; +} + +/** + * acpi_match_device - Match a struct device against a given list of ACPI IDs + * @ids: Array of struct acpi_device_id object to match against. + * @dev: The device structure to match. + * + * Check if @dev has a valid ACPI handle and if there is a struct acpi_device + * object for that handle and use that object to match against a given list of + * device IDs. + * + * Return a pointer to the first matching ID on success or %NULL on failure. + */ +const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, + const struct device *dev) +{ + return __acpi_match_device(acpi_companion_match(dev), ids, NULL); +} +EXPORT_SYMBOL_GPL(acpi_match_device); + +int acpi_match_device_ids(struct acpi_device *device, + const struct acpi_device_id *ids) +{ + return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; +} +EXPORT_SYMBOL(acpi_match_device_ids); + +bool acpi_driver_match_device(struct device *dev, + const struct device_driver *drv) +{ + if (!drv->acpi_match_table) + return acpi_of_match_device(ACPI_COMPANION(dev), + drv->of_match_table); + + return !!__acpi_match_device(acpi_companion_match(dev), + drv->acpi_match_table, drv->of_match_table); +} +EXPORT_SYMBOL_GPL(acpi_driver_match_device); + /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 099831fc8449b..68877bc223572 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -115,55 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, return 0; } -/* - * acpi_companion_match() - Can we match via ACPI companion device - * @dev: Device in question - * - * Check if the given device has an ACPI companion and if that companion has - * a valid list of PNP IDs, and if the device is the first (primary) physical - * device associated with it. Return the companion pointer if that's the case - * or NULL otherwise. - * - * If multiple physical devices are attached to a single ACPI companion, we need - * to be careful. The usage scenario for this kind of relationship is that all - * of the physical devices in question use resources provided by the ACPI - * companion. A typical case is an MFD device where all the sub-devices share - * the parent's ACPI companion. In such cases we can only allow the primary - * (first) physical device to be matched with the help of the companion's PNP - * IDs. - * - * Additional physical devices sharing the ACPI companion can still use - * resources available from it but they will be matched normally using functions - * provided by their bus types (and analogously for their modalias). - */ -struct acpi_device *acpi_companion_match(const struct device *dev) -{ - struct acpi_device *adev; - struct mutex *physical_node_lock; - - adev = ACPI_COMPANION(dev); - if (!adev) - return NULL; - - if (list_empty(&adev->pnp.ids)) - return NULL; - - physical_node_lock = &adev->physical_node_lock; - mutex_lock(physical_node_lock); - if (list_empty(&adev->physical_node_list)) { - adev = NULL; - } else { - const struct acpi_device_physical_node *node; - - node = list_first_entry(&adev->physical_node_list, - struct acpi_device_physical_node, node); - if (node->dev != dev) - adev = NULL; - } - mutex_unlock(physical_node_lock); - - return adev; -} bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent) { @@ -497,146 +448,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) ACPI Bus operations -------------------------------------------------------------------------- */ -/** - * acpi_of_match_device - Match device object using the "compatible" property. - * @adev: ACPI device object to match. - * @of_match_table: List of device IDs to match against. - * - * If @dev has an ACPI companion which has ACPI_DT_NAMESPACE_HID in its list of - * identifiers and a _DSD object with the "compatible" property, use that - * property to match against the given list of identifiers. - */ -static bool acpi_of_match_device(struct acpi_device *adev, - const struct of_device_id *of_match_table) -{ - const union acpi_object *of_compatible, *obj; - int i, nval; - - if (!adev) - return false; - - of_compatible = adev->data.of_compatible; - if (!of_match_table || !of_compatible) - return false; - - if (of_compatible->type == ACPI_TYPE_PACKAGE) { - nval = of_compatible->package.count; - obj = of_compatible->package.elements; - } else { /* Must be ACPI_TYPE_STRING. */ - nval = 1; - obj = of_compatible; - } - /* Now we can look for the driver DT compatible strings */ - for (i = 0; i < nval; i++, obj++) { - const struct of_device_id *id; - - for (id = of_match_table; id->compatible[0]; id++) - if (!strcasecmp(obj->string.pointer, id->compatible)) - return true; - } - - return false; -} - -static bool __acpi_match_device_cls(const struct acpi_device_id *id, - struct acpi_hardware_id *hwid) -{ - int i, msk, byte_shift; - char buf[3]; - - if (!id->cls) - return false; - - /* Apply class-code bitmask, before checking each class-code byte */ - for (i = 1; i <= 3; i++) { - byte_shift = 8 * (3 - i); - msk = (id->cls_msk >> byte_shift) & 0xFF; - if (!msk) - continue; - - sprintf(buf, "%02x", (id->cls >> byte_shift) & msk); - if (strncmp(buf, &hwid->id[(i - 1) * 2], 2)) - return false; - } - return true; -} - -static const struct acpi_device_id *__acpi_match_device( - struct acpi_device *device, - const struct acpi_device_id *ids, - const struct of_device_id *of_ids) -{ - const struct acpi_device_id *id; - struct acpi_hardware_id *hwid; - - /* - * If the device is not present, it is unnecessary to load device - * driver for it. - */ - if (!device || !device->status.present) - return NULL; - - list_for_each_entry(hwid, &device->pnp.ids, list) { - /* First, check the ACPI/PNP IDs provided by the caller. */ - for (id = ids; id->id[0] || id->cls; id++) { - if (id->id[0] && !strcmp((char *) id->id, hwid->id)) - return id; - else if (id->cls && __acpi_match_device_cls(id, hwid)) - return id; - } - - /* - * Next, check ACPI_DT_NAMESPACE_HID and try to match the - * "compatible" property if found. - * - * The id returned by the below is not valid, but the only - * caller passing non-NULL of_ids here is only interested in - * whether or not the return value is NULL. - */ - if (!strcmp(ACPI_DT_NAMESPACE_HID, hwid->id) - && acpi_of_match_device(device, of_ids)) - return id; - } - return NULL; -} - -/** - * acpi_match_device - Match a struct device against a given list of ACPI IDs - * @ids: Array of struct acpi_device_id object to match against. - * @dev: The device structure to match. - * - * Check if @dev has a valid ACPI handle and if there is a struct acpi_device - * object for that handle and use that object to match against a given list of - * device IDs. - * - * Return a pointer to the first matching ID on success or %NULL on failure. - */ -const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, - const struct device *dev) -{ - return __acpi_match_device(acpi_companion_match(dev), ids, NULL); -} -EXPORT_SYMBOL_GPL(acpi_match_device); - -int acpi_match_device_ids(struct acpi_device *device, - const struct acpi_device_id *ids) -{ - return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; -} -EXPORT_SYMBOL(acpi_match_device_ids); - -bool acpi_driver_match_device(struct device *dev, - const struct device_driver *drv) -{ - if (!drv->acpi_match_table) - return acpi_of_match_device(ACPI_COMPANION(dev), - drv->of_match_table); - - return !!__acpi_match_device(acpi_companion_match(dev), - drv->acpi_match_table, drv->of_match_table); -} -EXPORT_SYMBOL_GPL(acpi_driver_match_device); - static void acpi_free_power_resources_lists(struct acpi_device *device) { int i; -- GitLab From 5894b0c46e49b5ecc25f22b2d1b8232aab00ce97 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:54:01 +0200 Subject: [PATCH 1171/7006] ACPI / scan: Move bus operations and notification routines to bus.c To reduce the size of scan.c and improve the readability of it, move code related to device notification, the definitions of the ACPI bus operations and the driver management code to drivers/acpi/bus.c. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 184 ++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 183 ------------------------------------------- 2 files changed, 184 insertions(+), 183 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index ce805809b00bd..2f50fc4be1d45 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -423,6 +423,65 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data) acpi_evaluate_ost(handle, type, ost_code, NULL); } +static void acpi_device_notify(acpi_handle handle, u32 event, void *data) +{ + struct acpi_device *device = data; + + device->driver->ops.notify(device, event); +} + +static void acpi_device_notify_fixed(void *data) +{ + struct acpi_device *device = data; + + /* Fixed hardware devices have no handles */ + acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); +} + +static u32 acpi_device_fixed_event(void *data) +{ + acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data); + return ACPI_INTERRUPT_HANDLED; +} + +static int acpi_device_install_notify_handler(struct acpi_device *device) +{ + acpi_status status; + + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + status = + acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_device_fixed_event, + device); + else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + status = + acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_device_fixed_event, + device); + else + status = acpi_install_notify_handler(device->handle, + ACPI_DEVICE_NOTIFY, + acpi_device_notify, + device); + + if (ACPI_FAILURE(status)) + return -EINVAL; + return 0; +} + +static void acpi_device_remove_notify_handler(struct acpi_device *device) +{ + if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) + acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, + acpi_device_fixed_event); + else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) + acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, + acpi_device_fixed_event); + else + acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_device_notify); +} + /* -------------------------------------------------------------------------- Device Matching -------------------------------------------------------------------------- */ @@ -617,6 +676,131 @@ bool acpi_driver_match_device(struct device *dev, } EXPORT_SYMBOL_GPL(acpi_driver_match_device); +/* -------------------------------------------------------------------------- + ACPI Driver Management + -------------------------------------------------------------------------- */ + +/** + * acpi_bus_register_driver - register a driver with the ACPI bus + * @driver: driver being registered + * + * Registers a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and binds. Returns zero for + * success or a negative error status for failure. + */ +int acpi_bus_register_driver(struct acpi_driver *driver) +{ + int ret; + + if (acpi_disabled) + return -ENODEV; + driver->drv.name = driver->name; + driver->drv.bus = &acpi_bus_type; + driver->drv.owner = driver->owner; + + ret = driver_register(&driver->drv); + return ret; +} + +EXPORT_SYMBOL(acpi_bus_register_driver); + +/** + * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus + * @driver: driver to unregister + * + * Unregisters a driver with the ACPI bus. Searches the namespace for all + * devices that match the driver's criteria and unbinds. + */ +void acpi_bus_unregister_driver(struct acpi_driver *driver) +{ + driver_unregister(&driver->drv); +} + +EXPORT_SYMBOL(acpi_bus_unregister_driver); + +/* -------------------------------------------------------------------------- + ACPI Bus operations + -------------------------------------------------------------------------- */ + +static int acpi_bus_match(struct device *dev, struct device_driver *drv) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(drv); + + return acpi_dev->flags.match_driver + && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); +} + +static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + return __acpi_device_uevent_modalias(to_acpi_device(dev), env); +} + +static int acpi_device_probe(struct device *dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); + int ret; + + if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev)) + return -EINVAL; + + if (!acpi_drv->ops.add) + return -ENOSYS; + + ret = acpi_drv->ops.add(acpi_dev); + if (ret) + return ret; + + acpi_dev->driver = acpi_drv; + ACPI_DEBUG_PRINT((ACPI_DB_INFO, + "Driver [%s] successfully bound to device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + + if (acpi_drv->ops.notify) { + ret = acpi_device_install_notify_handler(acpi_dev); + if (ret) { + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev); + + acpi_dev->driver = NULL; + acpi_dev->driver_data = NULL; + return ret; + } + } + + ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", + acpi_drv->name, acpi_dev->pnp.bus_id)); + get_device(dev); + return 0; +} + +static int acpi_device_remove(struct device * dev) +{ + struct acpi_device *acpi_dev = to_acpi_device(dev); + struct acpi_driver *acpi_drv = acpi_dev->driver; + + if (acpi_drv) { + if (acpi_drv->ops.notify) + acpi_device_remove_notify_handler(acpi_dev); + if (acpi_drv->ops.remove) + acpi_drv->ops.remove(acpi_dev); + } + acpi_dev->driver = NULL; + acpi_dev->driver_data = NULL; + + put_device(dev); + return 0; +} + +struct bus_type acpi_bus_type = { + .name = "acpi", + .match = acpi_bus_match, + .probe = acpi_device_probe, + .remove = acpi_device_remove, + .uevent = acpi_device_uevent, +}; + /* -------------------------------------------------------------------------- Initialization/Cleanup -------------------------------------------------------------------------- */ diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 68877bc223572..f541f689ae80b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -444,10 +444,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src) unlock_device_hotplug(); } -/* -------------------------------------------------------------------------- - ACPI Bus operations - -------------------------------------------------------------------------- */ - static void acpi_free_power_resources_lists(struct acpi_device *device) { int i; @@ -474,144 +470,6 @@ static void acpi_device_release(struct device *dev) kfree(acpi_dev); } -static int acpi_bus_match(struct device *dev, struct device_driver *drv) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = to_acpi_driver(drv); - - return acpi_dev->flags.match_driver - && !acpi_match_device_ids(acpi_dev, acpi_drv->ids); -} - -static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - return __acpi_device_uevent_modalias(to_acpi_device(dev), env); -} - -static void acpi_device_notify(acpi_handle handle, u32 event, void *data) -{ - struct acpi_device *device = data; - - device->driver->ops.notify(device, event); -} - -static void acpi_device_notify_fixed(void *data) -{ - struct acpi_device *device = data; - - /* Fixed hardware devices have no handles */ - acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); -} - -static u32 acpi_device_fixed_event(void *data) -{ - acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data); - return ACPI_INTERRUPT_HANDLED; -} - -static int acpi_device_install_notify_handler(struct acpi_device *device) -{ - acpi_status status; - - if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) - status = - acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_device_fixed_event, - device); - else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) - status = - acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_device_fixed_event, - device); - else - status = acpi_install_notify_handler(device->handle, - ACPI_DEVICE_NOTIFY, - acpi_device_notify, - device); - - if (ACPI_FAILURE(status)) - return -EINVAL; - return 0; -} - -static void acpi_device_remove_notify_handler(struct acpi_device *device) -{ - if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON) - acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON, - acpi_device_fixed_event); - else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON) - acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON, - acpi_device_fixed_event); - else - acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, - acpi_device_notify); -} - -static int acpi_device_probe(struct device *dev) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver); - int ret; - - if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev)) - return -EINVAL; - - if (!acpi_drv->ops.add) - return -ENOSYS; - - ret = acpi_drv->ops.add(acpi_dev); - if (ret) - return ret; - - acpi_dev->driver = acpi_drv; - ACPI_DEBUG_PRINT((ACPI_DB_INFO, - "Driver [%s] successfully bound to device [%s]\n", - acpi_drv->name, acpi_dev->pnp.bus_id)); - - if (acpi_drv->ops.notify) { - ret = acpi_device_install_notify_handler(acpi_dev); - if (ret) { - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - - acpi_dev->driver = NULL; - acpi_dev->driver_data = NULL; - return ret; - } - } - - ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", - acpi_drv->name, acpi_dev->pnp.bus_id)); - get_device(dev); - return 0; -} - -static int acpi_device_remove(struct device * dev) -{ - struct acpi_device *acpi_dev = to_acpi_device(dev); - struct acpi_driver *acpi_drv = acpi_dev->driver; - - if (acpi_drv) { - if (acpi_drv->ops.notify) - acpi_device_remove_notify_handler(acpi_dev); - if (acpi_drv->ops.remove) - acpi_drv->ops.remove(acpi_dev); - } - acpi_dev->driver = NULL; - acpi_dev->driver_data = NULL; - - put_device(dev); - return 0; -} - -struct bus_type acpi_bus_type = { - .name = "acpi", - .match = acpi_bus_match, - .probe = acpi_device_probe, - .remove = acpi_device_remove, - .uevent = acpi_device_uevent, -}; - static void acpi_device_del(struct acpi_device *device) { mutex_lock(&acpi_device_lock); @@ -858,47 +716,6 @@ struct acpi_device *acpi_get_next_child(struct device *dev, return next == head ? NULL : list_entry(next, struct acpi_device, node); } -/* -------------------------------------------------------------------------- - Driver Management - -------------------------------------------------------------------------- */ -/** - * acpi_bus_register_driver - register a driver with the ACPI bus - * @driver: driver being registered - * - * Registers a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and binds. Returns zero for - * success or a negative error status for failure. - */ -int acpi_bus_register_driver(struct acpi_driver *driver) -{ - int ret; - - if (acpi_disabled) - return -ENODEV; - driver->drv.name = driver->name; - driver->drv.bus = &acpi_bus_type; - driver->drv.owner = driver->owner; - - ret = driver_register(&driver->drv); - return ret; -} - -EXPORT_SYMBOL(acpi_bus_register_driver); - -/** - * acpi_bus_unregister_driver - unregisters a driver with the ACPI bus - * @driver: driver to unregister - * - * Unregisters a driver with the ACPI bus. Searches the namespace for all - * devices that match the driver's criteria and unbinds. - */ -void acpi_bus_unregister_driver(struct acpi_driver *driver) -{ - driver_unregister(&driver->drv); -} - -EXPORT_SYMBOL(acpi_bus_unregister_driver); - /* -------------------------------------------------------------------------- Device Enumeration -------------------------------------------------------------------------- */ -- GitLab From 1dcc3d3362b0c97e48290f7786be85b4cec2a147 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 17 Jul 2015 22:54:09 +0200 Subject: [PATCH 1172/7006] ACPI / bus: Move ACPI bus type registration Move the registration of the ACPI bus type to acpi_bus_init() and avoid using ACPI going forward if it fails (too many things depend on the presence of the ACPI bus type). Signed-off-by: Rafael J. Wysocki --- drivers/acpi/bus.c | 4 +++- drivers/acpi/scan.c | 6 ------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 2f50fc4be1d45..7a3ad929f0957 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -1039,7 +1039,9 @@ static int __init acpi_bus_init(void) */ acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL); - return 0; + result = bus_register(&acpi_bus_type); + if (!result) + return 0; /* Mimic structured exception handling */ error1: diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index f541f689ae80b..2fe5a37c385c3 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1891,12 +1891,6 @@ int __init acpi_scan_init(void) { int result; - result = bus_register(&acpi_bus_type); - if (result) { - /* We don't want to quit even if we failed to add suspend/resume */ - printk(KERN_ERR PREFIX "Could not register bus type\n"); - } - acpi_pci_root_init(); acpi_pci_link_init(); acpi_processor_init(); -- GitLab From f4745a92781b872455f32feb01d1dce92aefcb6c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 29 Jun 2015 22:13:38 +0100 Subject: [PATCH 1173/7006] PM / clk: don't return int on __pm_clk_enable() Static analysis by cppcheck found an issue that was recently introduced by commit 471f7707b6f0b1 ("PM / clock_ops: make __pm_clk_enable more generic") where a return status in ret was not being initialised and garbage being returned when ce->status >= PCE_STATUS_ERROR. The fact that ret is not being checked by the caller and that ret is only used internally __pm_clk_enable() to check if clk_enable() was OK means we can ignore returning it instead turn __pm_clk_enable() into function with a void return. Fixes: 471f7707b6f0b1 ("PM / clock_ops: make __pm_clk_enable more generic") Signed-off-by: Colin Ian King Signed-off-by: Rafael J. Wysocki --- drivers/base/power/clock_ops.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c index acef9f9f759a2..652b5a367c1f3 100644 --- a/drivers/base/power/clock_ops.c +++ b/drivers/base/power/clock_ops.c @@ -38,7 +38,7 @@ struct pm_clock_entry { * @dev: The device for the given clock * @ce: PM clock entry corresponding to the clock. */ -static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) +static inline void __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) { int ret; @@ -50,8 +50,6 @@ static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce) dev_err(dev, "%s: failed to enable clk %p, error %d\n", __func__, ce->clk, ret); } - - return ret; } /** -- GitLab From 386d46e6d5238c9648399eb1e0c418d06f4126a2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:01 +0530 Subject: [PATCH 1174/7006] cpufreq: governor: Name delayed-work as dwork Delayed work was named as 'work' and to access work within it we do work.work. Not much readable. Rename delayed_work as 'dwork'. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 2 +- drivers/cpufreq/cpufreq_governor.c | 6 +++--- drivers/cpufreq/cpufreq_governor.h | 2 +- drivers/cpufreq/cpufreq_ondemand.c | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index c86a10c309123..0e3ec1d968d90 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -105,7 +105,7 @@ static void cs_check_cpu(int cpu, unsigned int load) static void cs_dbs_timer(struct work_struct *work) { struct cs_cpu_dbs_info_s *dbs_info = container_of(work, - struct cs_cpu_dbs_info_s, cdbs.work.work); + struct cs_cpu_dbs_info_s, cdbs.dwork.work); unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 57a39f8a92b7f..6024bbc782c02 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -165,7 +165,7 @@ static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data, { struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); - mod_delayed_work_on(cpu, system_wq, &cdbs->work, delay); + mod_delayed_work_on(cpu, system_wq, &cdbs->dwork, delay); } void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, @@ -204,7 +204,7 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, for_each_cpu(i, policy->cpus) { cdbs = dbs_data->cdata->get_cpu_cdbs(i); - cancel_delayed_work_sync(&cdbs->work); + cancel_delayed_work_sync(&cdbs->dwork); } } @@ -367,7 +367,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; mutex_init(&j_cdbs->timer_mutex); - INIT_DEFERRABLE_WORK(&j_cdbs->work, cdata->gov_dbs_timer); + INIT_DEFERRABLE_WORK(&j_cdbs->dwork, cdata->gov_dbs_timer); } if (cdata->governor == GOV_CONSERVATIVE) { diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 34736f5e869d1..352eecaae789b 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -142,7 +142,7 @@ struct cpu_dbs_common_info { */ unsigned int prev_load; struct cpufreq_policy *cur_policy; - struct delayed_work work; + struct delayed_work dwork; /* * percpu mutex that serializes governor limit change with gov_dbs_timer * invocation. We do not want gov_dbs_timer to run when user is changing diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 3c1e10f2304cd..830aef1db8c3c 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -194,7 +194,7 @@ static void od_check_cpu(int cpu, unsigned int load) static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = - container_of(work, struct od_cpu_dbs_info_s, cdbs.work.work); + container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); @@ -275,18 +275,18 @@ static void update_sampling_rate(struct dbs_data *dbs_data, mutex_lock(&dbs_info->cdbs.timer_mutex); - if (!delayed_work_pending(&dbs_info->cdbs.work)) { + if (!delayed_work_pending(&dbs_info->cdbs.dwork)) { mutex_unlock(&dbs_info->cdbs.timer_mutex); continue; } next_sampling = jiffies + usecs_to_jiffies(new_rate); - appointed_at = dbs_info->cdbs.work.timer.expires; + appointed_at = dbs_info->cdbs.dwork.timer.expires; if (time_before(next_sampling, appointed_at)) { mutex_unlock(&dbs_info->cdbs.timer_mutex); - cancel_delayed_work_sync(&dbs_info->cdbs.work); + cancel_delayed_work_sync(&dbs_info->cdbs.dwork); mutex_lock(&dbs_info->cdbs.timer_mutex); gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, -- GitLab From d3574c851148266177ea9ecae10a317e6eae94de Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:02 +0530 Subject: [PATCH 1175/7006] cpufreq: governor: Drop unused field 'cpu' Its not used at all, drop it. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 1 - drivers/cpufreq/cpufreq_governor.h | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 6024bbc782c02..2149ba7d32a8a 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -353,7 +353,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, struct cpu_dbs_common_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; - j_cdbs->cpu = j; j_cdbs->cur_policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 352eecaae789b..1bbf8c87fdd5a 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -130,7 +130,6 @@ static void *get_cpu_dbs_info_s(int cpu) \ /* Per cpu structures */ struct cpu_dbs_common_info { - int cpu; u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; -- GitLab From 875b8508f9607b92e3ef4ece2fddf86d61351085 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:03 +0530 Subject: [PATCH 1176/7006] cpufreq: governor: Rename 'cpu_dbs_common_info' to 'cpu_dbs_info' Its not common info to all CPUs, but a structure representing common type of cpu info to both governor types. Lets drop 'common_' from its name. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 19 +++++++++---------- drivers/cpufreq/cpufreq_governor.h | 13 ++++++------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 2149ba7d32a8a..529f236f2d05b 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -32,7 +32,7 @@ static struct attribute_group *get_sysfs_attr(struct dbs_data *dbs_data) void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) { - struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; @@ -64,7 +64,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { - struct cpu_dbs_common_info *j_cdbs; + struct cpu_dbs_info *j_cdbs; u64 cur_wall_time, cur_idle_time; unsigned int idle_time, wall_time; unsigned int load; @@ -163,7 +163,7 @@ EXPORT_SYMBOL_GPL(dbs_check_cpu); static inline void __gov_queue_work(int cpu, struct dbs_data *dbs_data, unsigned int delay) { - struct cpu_dbs_common_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); mod_delayed_work_on(cpu, system_wq, &cdbs->dwork, delay); } @@ -199,7 +199,7 @@ EXPORT_SYMBOL_GPL(gov_queue_work); static inline void gov_cancel_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy) { - struct cpu_dbs_common_info *cdbs; + struct cpu_dbs_info *cdbs; int i; for_each_cpu(i, policy->cpus) { @@ -209,8 +209,7 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, } /* Will return if we need to evaluate cpu load again or not */ -bool need_load_eval(struct cpu_dbs_common_info *cdbs, - unsigned int sampling_rate) +bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate) { if (policy_is_shared(cdbs->cur_policy)) { ktime_t time_now = ktime_get(); @@ -330,7 +329,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu; - struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); int io_busy = 0; if (!policy->cur) @@ -350,7 +349,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, } for_each_cpu(j, policy->cpus) { - struct cpu_dbs_common_info *j_cdbs = cdata->get_cpu_cdbs(j); + struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; j_cdbs->cur_policy = policy; @@ -398,7 +397,7 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); if (cdata->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -418,7 +417,7 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_common_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); if (!cpu_cdbs->cur_policy) return; diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 1bbf8c87fdd5a..6b5e33f680641 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -109,7 +109,7 @@ store_one(_gov, file_name) /* create helper routines */ #define define_get_cpu_dbs_routines(_dbs_info) \ -static struct cpu_dbs_common_info *get_cpu_cdbs(int cpu) \ +static struct cpu_dbs_info *get_cpu_cdbs(int cpu) \ { \ return &per_cpu(_dbs_info, cpu).cdbs; \ } \ @@ -129,7 +129,7 @@ static void *get_cpu_dbs_info_s(int cpu) \ */ /* Per cpu structures */ -struct cpu_dbs_common_info { +struct cpu_dbs_info { u64 prev_cpu_idle; u64 prev_cpu_wall; u64 prev_cpu_nice; @@ -152,7 +152,7 @@ struct cpu_dbs_common_info { }; struct od_cpu_dbs_info_s { - struct cpu_dbs_common_info cdbs; + struct cpu_dbs_info cdbs; struct cpufreq_frequency_table *freq_table; unsigned int freq_lo; unsigned int freq_lo_jiffies; @@ -162,7 +162,7 @@ struct od_cpu_dbs_info_s { }; struct cs_cpu_dbs_info_s { - struct cpu_dbs_common_info cdbs; + struct cpu_dbs_info cdbs; unsigned int down_skip; unsigned int requested_freq; unsigned int enable:1; @@ -203,7 +203,7 @@ struct common_dbs_data { */ struct dbs_data *gdbs_data; - struct cpu_dbs_common_info *(*get_cpu_cdbs)(int cpu); + struct cpu_dbs_info *(*get_cpu_cdbs)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu); void (*gov_dbs_timer)(struct work_struct *work); void (*gov_check_cpu)(int cpu, unsigned int load); @@ -264,8 +264,7 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); -bool need_load_eval(struct cpu_dbs_common_info *cdbs, - unsigned int sampling_rate); +bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, -- GitLab From 49a9a40c1b48d24f0fd9a6b6be8a4038f47d13bf Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:04 +0530 Subject: [PATCH 1177/7006] cpufreq: governor: name pointer to cpu_dbs_info as 'cdbs' It is called as 'cdbs' at most of the places and 'cpu_dbs' at others. Lets use 'cdbs' consistently for better readability. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 529f236f2d05b..4ea13f1821546 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -329,7 +329,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu; - struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); int io_busy = 0; if (!policy->cur) @@ -385,7 +385,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, } /* Initiate timer time stamp */ - cpu_cdbs->time_stamp = ktime_get(); + cdbs->time_stamp = ktime_get(); gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate), true); @@ -397,7 +397,7 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); if (cdata->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -408,8 +408,8 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, gov_cancel_work(dbs_data, policy); - mutex_destroy(&cpu_cdbs->timer_mutex); - cpu_cdbs->cur_policy = NULL; + mutex_destroy(&cdbs->timer_mutex); + cdbs->cur_policy = NULL; } static void cpufreq_governor_limits(struct cpufreq_policy *policy, @@ -417,20 +417,20 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; - struct cpu_dbs_info *cpu_cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); - if (!cpu_cdbs->cur_policy) + if (!cdbs->cur_policy) return; - mutex_lock(&cpu_cdbs->timer_mutex); - if (policy->max < cpu_cdbs->cur_policy->cur) - __cpufreq_driver_target(cpu_cdbs->cur_policy, policy->max, + mutex_lock(&cdbs->timer_mutex); + if (policy->max < cdbs->cur_policy->cur) + __cpufreq_driver_target(cdbs->cur_policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > cpu_cdbs->cur_policy->cur) - __cpufreq_driver_target(cpu_cdbs->cur_policy, policy->min, + else if (policy->min > cdbs->cur_policy->cur) + __cpufreq_driver_target(cdbs->cur_policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); - mutex_unlock(&cpu_cdbs->timer_mutex); + mutex_unlock(&cdbs->timer_mutex); } int cpufreq_governor_dbs(struct cpufreq_policy *policy, -- GitLab From 42994af63cd1aafc9289035cf621e501b08732e9 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 19 Jun 2015 17:18:05 +0530 Subject: [PATCH 1178/7006] cpufreq: governor: rename cur_policy as policy Just call it 'policy', cur_policy is unnecessarily long and doesn't have any special meaning. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 10 +++++----- drivers/cpufreq/cpufreq_governor.c | 18 +++++++++--------- drivers/cpufreq/cpufreq_governor.h | 2 +- drivers/cpufreq/cpufreq_ondemand.c | 19 ++++++++++--------- 4 files changed, 25 insertions(+), 24 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 0e3ec1d968d90..af47d322679e5 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -47,7 +47,7 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners, static void cs_check_cpu(int cpu, unsigned int load) { struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + struct cpufreq_policy *policy = dbs_info->cdbs.policy; struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -106,10 +106,10 @@ static void cs_dbs_timer(struct work_struct *work) { struct cs_cpu_dbs_info_s *dbs_info = container_of(work, struct cs_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; + unsigned int cpu = dbs_info->cdbs.policy->cpu; struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data; + struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; int delay = delay_for_sampling_rate(cs_tuners->sampling_rate); bool modify_all = true; @@ -120,7 +120,7 @@ static void cs_dbs_timer(struct work_struct *work) else dbs_check_cpu(dbs_data, cpu); - gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all); + gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); mutex_unlock(&core_dbs_info->cdbs.timer_mutex); } @@ -135,7 +135,7 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!dbs_info->enable) return 0; - policy = dbs_info->cdbs.cur_policy; + policy = dbs_info->cdbs.policy; /* * we only care if our internally tracked freq moves outside the 'valid' diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 4ea13f1821546..c0566f86caed6 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -60,7 +60,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) ignore_nice = cs_tuners->ignore_nice_load; } - policy = cdbs->cur_policy; + policy = cdbs->policy; /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { @@ -211,7 +211,7 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, /* Will return if we need to evaluate cpu load again or not */ bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate) { - if (policy_is_shared(cdbs->cur_policy)) { + if (policy_is_shared(cdbs->policy)) { ktime_t time_now = ktime_get(); s64 delta_us = ktime_us_delta(time_now, cdbs->time_stamp); @@ -352,7 +352,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; - j_cdbs->cur_policy = policy; + j_cdbs->policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); @@ -409,7 +409,7 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, gov_cancel_work(dbs_data, policy); mutex_destroy(&cdbs->timer_mutex); - cdbs->cur_policy = NULL; + cdbs->policy = NULL; } static void cpufreq_governor_limits(struct cpufreq_policy *policy, @@ -419,15 +419,15 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); - if (!cdbs->cur_policy) + if (!cdbs->policy) return; mutex_lock(&cdbs->timer_mutex); - if (policy->max < cdbs->cur_policy->cur) - __cpufreq_driver_target(cdbs->cur_policy, policy->max, + if (policy->max < cdbs->policy->cur) + __cpufreq_driver_target(cdbs->policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > cdbs->cur_policy->cur) - __cpufreq_driver_target(cdbs->cur_policy, policy->min, + else if (policy->min > cdbs->policy->cur) + __cpufreq_driver_target(cdbs->policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cdbs->timer_mutex); diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 6b5e33f680641..a0f8eb79ee6d2 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -140,7 +140,7 @@ struct cpu_dbs_info { * wake-up from idle. */ unsigned int prev_load; - struct cpufreq_policy *cur_policy; + struct cpufreq_policy *policy; struct delayed_work dwork; /* * percpu mutex that serializes governor limit change with gov_dbs_timer diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 830aef1db8c3c..d29c6f9c6e3eb 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -155,7 +155,7 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) static void od_check_cpu(int cpu, unsigned int load) { struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.cur_policy; + struct cpufreq_policy *policy = dbs_info->cdbs.policy; struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; @@ -195,10 +195,10 @@ static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.cur_policy->cpu; + unsigned int cpu = dbs_info->cdbs.policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.cur_policy->governor_data; + struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; int delay = 0, sample_type = core_dbs_info->sample_type; bool modify_all = true; @@ -213,8 +213,9 @@ static void od_dbs_timer(struct work_struct *work) core_dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { delay = core_dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(core_dbs_info->cdbs.cur_policy, - core_dbs_info->freq_lo, CPUFREQ_RELATION_H); + __cpufreq_driver_target(core_dbs_info->cdbs.policy, + core_dbs_info->freq_lo, + CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); if (core_dbs_info->freq_lo) { @@ -229,7 +230,7 @@ max_delay: delay = delay_for_sampling_rate(od_tuners->sampling_rate * core_dbs_info->rate_mult); - gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, delay, modify_all); + gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); mutex_unlock(&core_dbs_info->cdbs.timer_mutex); } @@ -289,8 +290,8 @@ static void update_sampling_rate(struct dbs_data *dbs_data, cancel_delayed_work_sync(&dbs_info->cdbs.dwork); mutex_lock(&dbs_info->cdbs.timer_mutex); - gov_queue_work(dbs_data, dbs_info->cdbs.cur_policy, - usecs_to_jiffies(new_rate), true); + gov_queue_work(dbs_data, dbs_info->cdbs.policy, + usecs_to_jiffies(new_rate), true); } mutex_unlock(&dbs_info->cdbs.timer_mutex); @@ -559,7 +560,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias) if (cpumask_test_cpu(cpu, &done)) continue; - policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.cur_policy; + policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.policy; if (!policy) continue; -- GitLab From 800e3b9a68011c4124f380d50e2117523c41a843 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 17 Jul 2015 16:44:05 -0700 Subject: [PATCH 1179/7006] Input: drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/adp5589-keys.c | 1 - drivers/input/keyboard/cap11xx.c | 1 - drivers/input/keyboard/lm8333.c | 1 - drivers/input/keyboard/mcs_touchkey.c | 1 - drivers/input/keyboard/mpr121_touchkey.c | 1 - drivers/input/keyboard/qt1070.c | 1 - drivers/input/keyboard/qt2160.c | 1 - drivers/input/keyboard/tca8418_keypad.c | 1 - drivers/input/misc/adxl34x-i2c.c | 1 - drivers/input/misc/bma150.c | 1 - drivers/input/misc/cma3000_d0x_i2c.c | 1 - drivers/input/misc/drv260x.c | 1 - drivers/input/misc/drv2665.c | 1 - drivers/input/misc/drv2667.c | 1 - drivers/input/misc/gp2ap002a00f.c | 1 - drivers/input/misc/kxtj9.c | 1 - drivers/input/misc/mpu3050.c | 1 - drivers/input/misc/pcf8574_keypad.c | 1 - drivers/input/mouse/cyapa.c | 1 - drivers/input/mouse/elan_i2c_core.c | 1 - drivers/input/mouse/synaptics_i2c.c | 1 - drivers/input/touchscreen/ad7879-i2c.c | 1 - drivers/input/touchscreen/ar1021_i2c.c | 1 - drivers/input/touchscreen/atmel_mxt_ts.c | 1 - drivers/input/touchscreen/auo-pixcir-ts.c | 1 - drivers/input/touchscreen/bu21013_ts.c | 1 - drivers/input/touchscreen/chipone_icn8318.c | 1 - drivers/input/touchscreen/cy8ctmg110_ts.c | 1 - drivers/input/touchscreen/cyttsp4_i2c.c | 1 - drivers/input/touchscreen/cyttsp_i2c.c | 1 - drivers/input/touchscreen/edt-ft5x06.c | 1 - drivers/input/touchscreen/egalax_ts.c | 1 - drivers/input/touchscreen/elants_i2c.c | 1 - drivers/input/touchscreen/goodix.c | 1 - drivers/input/touchscreen/ili210x.c | 1 - drivers/input/touchscreen/max11801_ts.c | 1 - drivers/input/touchscreen/mms114.c | 1 - drivers/input/touchscreen/pixcir_i2c_ts.c | 1 - drivers/input/touchscreen/st1232.c | 1 - drivers/input/touchscreen/tsc2007.c | 1 - drivers/input/touchscreen/wacom_i2c.c | 1 - drivers/input/touchscreen/zforce_ts.c | 1 - 42 files changed, 42 deletions(-) diff --git a/drivers/input/keyboard/adp5589-keys.c b/drivers/input/keyboard/adp5589-keys.c index 6ed83cf8b74e9..4d446d5085aad 100644 --- a/drivers/input/keyboard/adp5589-keys.c +++ b/drivers/input/keyboard/adp5589-keys.c @@ -1097,7 +1097,6 @@ MODULE_DEVICE_TABLE(i2c, adp5589_id); static struct i2c_driver adp5589_driver = { .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, .pm = &adp5589_dev_pm_ops, }, .probe = adp5589_probe, diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c index f07461a64d85c..b58fd9d72d927 100644 --- a/drivers/input/keyboard/cap11xx.c +++ b/drivers/input/keyboard/cap11xx.c @@ -361,7 +361,6 @@ MODULE_DEVICE_TABLE(i2c, cap11xx_i2c_ids); static struct i2c_driver cap11xx_i2c_driver = { .driver = { .name = "cap11xx", - .owner = THIS_MODULE, .of_match_table = cap11xx_dt_ids, }, .id_table = cap11xx_i2c_ids, diff --git a/drivers/input/keyboard/lm8333.c b/drivers/input/keyboard/lm8333.c index 0ad422b8a2607..c717e8f3c964b 100644 --- a/drivers/input/keyboard/lm8333.c +++ b/drivers/input/keyboard/lm8333.c @@ -223,7 +223,6 @@ MODULE_DEVICE_TABLE(i2c, lm8333_id); static struct i2c_driver lm8333_driver = { .driver = { .name = "lm8333", - .owner = THIS_MODULE, }, .probe = lm8333_probe, .remove = lm8333_remove, diff --git a/drivers/input/keyboard/mcs_touchkey.c b/drivers/input/keyboard/mcs_touchkey.c index 375b05ca8e2a5..31090d71a685d 100644 --- a/drivers/input/keyboard/mcs_touchkey.c +++ b/drivers/input/keyboard/mcs_touchkey.c @@ -265,7 +265,6 @@ MODULE_DEVICE_TABLE(i2c, mcs_touchkey_id); static struct i2c_driver mcs_touchkey_driver = { .driver = { .name = "mcs_touchkey", - .owner = THIS_MODULE, .pm = &mcs_touchkey_pm_ops, }, .probe = mcs_touchkey_probe, diff --git a/drivers/input/keyboard/mpr121_touchkey.c b/drivers/input/keyboard/mpr121_touchkey.c index 3aa2ec45bcab4..0fd612dd76ede 100644 --- a/drivers/input/keyboard/mpr121_touchkey.c +++ b/drivers/input/keyboard/mpr121_touchkey.c @@ -305,7 +305,6 @@ MODULE_DEVICE_TABLE(i2c, mpr121_id); static struct i2c_driver mpr_touchkey_driver = { .driver = { .name = "mpr121", - .owner = THIS_MODULE, .pm = &mpr121_touchkey_pm_ops, }, .id_table = mpr121_id, diff --git a/drivers/input/keyboard/qt1070.c b/drivers/input/keyboard/qt1070.c index 52cd6e88acd70..5a5778729e370 100644 --- a/drivers/input/keyboard/qt1070.c +++ b/drivers/input/keyboard/qt1070.c @@ -277,7 +277,6 @@ MODULE_DEVICE_TABLE(i2c, qt1070_id); static struct i2c_driver qt1070_driver = { .driver = { .name = "qt1070", - .owner = THIS_MODULE, .pm = &qt1070_pm_ops, }, .id_table = qt1070_id, diff --git a/drivers/input/keyboard/qt2160.c b/drivers/input/keyboard/qt2160.c index 819b22897c137..43b86482dda01 100644 --- a/drivers/input/keyboard/qt2160.c +++ b/drivers/input/keyboard/qt2160.c @@ -497,7 +497,6 @@ MODULE_DEVICE_TABLE(i2c, qt2160_idtable); static struct i2c_driver qt2160_driver = { .driver = { .name = "qt2160", - .owner = THIS_MODULE, }, .id_table = qt2160_idtable, diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 4e491c1762cfe..9002298698fce 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -404,7 +404,6 @@ MODULE_ALIAS("i2c:tca8418"); static struct i2c_driver tca8418_keypad_driver = { .driver = { .name = TCA8418_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tca8418_dt_ids), }, .probe = tca8418_keypad_probe, diff --git a/drivers/input/misc/adxl34x-i2c.c b/drivers/input/misc/adxl34x-i2c.c index bdb5d03b296ec..a8b0a2eec344e 100644 --- a/drivers/input/misc/adxl34x-i2c.c +++ b/drivers/input/misc/adxl34x-i2c.c @@ -158,7 +158,6 @@ MODULE_DEVICE_TABLE(of, adxl34x_of_id); static struct i2c_driver adxl34x_driver = { .driver = { .name = "adxl34x", - .owner = THIS_MODULE, .pm = &adxl34x_i2c_pm, .of_match_table = of_match_ptr(adxl34x_of_id), }, diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index c2780493b0edb..1d0e61d7c1318 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -653,7 +653,6 @@ MODULE_DEVICE_TABLE(i2c, bma150_id); static struct i2c_driver bma150_driver = { .driver = { - .owner = THIS_MODULE, .name = BMA150_DRIVER, .pm = &bma150_pm, }, diff --git a/drivers/input/misc/cma3000_d0x_i2c.c b/drivers/input/misc/cma3000_d0x_i2c.c index 4fdef98ceb56f..c7021916b64b7 100644 --- a/drivers/input/misc/cma3000_d0x_i2c.c +++ b/drivers/input/misc/cma3000_d0x_i2c.c @@ -118,7 +118,6 @@ static struct i2c_driver cma3000_i2c_driver = { .id_table = cma3000_i2c_id, .driver = { .name = "cma3000_i2c_accl", - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &cma3000_i2c_pm_ops, #endif diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 0e3af55d9e257..e65496e6463d7 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -720,7 +720,6 @@ static struct i2c_driver drv260x_driver = { .probe = drv260x_probe, .driver = { .name = "drv260x-haptics", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(drv260x_of_match), .pm = &drv260x_pm_ops, }, diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index e9501fdca5ef6..327a63c2f07d0 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -309,7 +309,6 @@ static struct i2c_driver drv2665_driver = { .probe = drv2665_probe, .driver = { .name = "drv2665-haptics", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(drv2665_of_match), .pm = &drv2665_pm_ops, }, diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index a231342207f9c..46a4be4e9dc3f 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -484,7 +484,6 @@ static struct i2c_driver drv2667_driver = { .probe = drv2667_probe, .driver = { .name = "drv2667-haptics", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(drv2667_of_match), .pm = &drv2667_pm_ops, }, diff --git a/drivers/input/misc/gp2ap002a00f.c b/drivers/input/misc/gp2ap002a00f.c index 0ac176d66a6f0..ba301af91b95a 100644 --- a/drivers/input/misc/gp2ap002a00f.c +++ b/drivers/input/misc/gp2ap002a00f.c @@ -271,7 +271,6 @@ static const struct i2c_device_id gp2a_i2c_id[] = { static struct i2c_driver gp2a_i2c_driver = { .driver = { .name = GP2A_I2C_NAME, - .owner = THIS_MODULE, .pm = &gp2a_pm, }, .probe = gp2a_probe, diff --git a/drivers/input/misc/kxtj9.c b/drivers/input/misc/kxtj9.c index 6e29349da5379..e058d711256a2 100644 --- a/drivers/input/misc/kxtj9.c +++ b/drivers/input/misc/kxtj9.c @@ -658,7 +658,6 @@ MODULE_DEVICE_TABLE(i2c, kxtj9_id); static struct i2c_driver kxtj9_driver = { .driver = { .name = NAME, - .owner = THIS_MODULE, .pm = &kxtj9_pm_ops, }, .probe = kxtj9_probe, diff --git a/drivers/input/misc/mpu3050.c b/drivers/input/misc/mpu3050.c index 5e5051351c3a8..f088db31cfc7c 100644 --- a/drivers/input/misc/mpu3050.c +++ b/drivers/input/misc/mpu3050.c @@ -466,7 +466,6 @@ MODULE_DEVICE_TABLE(of, mpu3050_of_match); static struct i2c_driver mpu3050_i2c_driver = { .driver = { .name = "mpu3050", - .owner = THIS_MODULE, .pm = &mpu3050_pm, .of_match_table = mpu3050_of_match, }, diff --git a/drivers/input/misc/pcf8574_keypad.c b/drivers/input/misc/pcf8574_keypad.c index 97f711a7bd20d..4abdf1efb3e00 100644 --- a/drivers/input/misc/pcf8574_keypad.c +++ b/drivers/input/misc/pcf8574_keypad.c @@ -208,7 +208,6 @@ MODULE_DEVICE_TABLE(i2c, pcf8574_kp_id); static struct i2c_driver pcf8574_kp_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &pcf8574_kp_pm_ops, #endif diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index efe148474e7f6..dfbfd494bb1f4 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1382,7 +1382,6 @@ MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); static struct i2c_driver cyapa_driver = { .driver = { .name = "cyapa", - .owner = THIS_MODULE, .pm = &cyapa_pm_ops, .acpi_match_table = ACPI_PTR(cyapa_acpi_id), }, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 62641f2adaf74..e7ef4ab1b37d1 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1183,7 +1183,6 @@ MODULE_DEVICE_TABLE(of, elan_of_match); static struct i2c_driver elan_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &elan_pm_ops, .acpi_match_table = ACPI_PTR(elan_acpi_id), .of_match_table = of_match_ptr(elan_of_match), diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index ffceedcaf3c8c..aa7c5da608005 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -655,7 +655,6 @@ MODULE_DEVICE_TABLE(i2c, synaptics_i2c_id_table); static struct i2c_driver synaptics_i2c_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .pm = &synaptics_i2c_pm, }, diff --git a/drivers/input/touchscreen/ad7879-i2c.c b/drivers/input/touchscreen/ad7879-i2c.c index dcf390771549c..d66962c5b1c2c 100644 --- a/drivers/input/touchscreen/ad7879-i2c.c +++ b/drivers/input/touchscreen/ad7879-i2c.c @@ -94,7 +94,6 @@ MODULE_DEVICE_TABLE(i2c, ad7879_id); static struct i2c_driver ad7879_i2c_driver = { .driver = { .name = "ad7879", - .owner = THIS_MODULE, .pm = &ad7879_pm_ops, }, .probe = ad7879_i2c_probe, diff --git a/drivers/input/touchscreen/ar1021_i2c.c b/drivers/input/touchscreen/ar1021_i2c.c index f0b954d46a259..71b5a634cf6d5 100644 --- a/drivers/input/touchscreen/ar1021_i2c.c +++ b/drivers/input/touchscreen/ar1021_i2c.c @@ -166,7 +166,6 @@ MODULE_DEVICE_TABLE(of, ar1021_i2c_of_match); static struct i2c_driver ar1021_i2c_driver = { .driver = { .name = "ar1021_i2c", - .owner = THIS_MODULE, .pm = &ar1021_i2c_pm, .of_match_table = ar1021_i2c_of_match, }, diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c index dfc7309e3d389..8efe7a002f1e9 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c @@ -2666,7 +2666,6 @@ MODULE_DEVICE_TABLE(i2c, mxt_id); static struct i2c_driver mxt_driver = { .driver = { .name = "atmel_mxt_ts", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mxt_of_match), .acpi_match_table = ACPI_PTR(mxt_acpi_id), .pm = &mxt_pm_ops, diff --git a/drivers/input/touchscreen/auo-pixcir-ts.c b/drivers/input/touchscreen/auo-pixcir-ts.c index 40e02dd5b2f94..38c06f754acd6 100644 --- a/drivers/input/touchscreen/auo-pixcir-ts.c +++ b/drivers/input/touchscreen/auo-pixcir-ts.c @@ -686,7 +686,6 @@ MODULE_DEVICE_TABLE(of, auo_pixcir_ts_dt_idtable); static struct i2c_driver auo_pixcir_driver = { .driver = { - .owner = THIS_MODULE, .name = "auo_pixcir_ts", .pm = &auo_pixcir_pm_ops, .of_match_table = of_match_ptr(auo_pixcir_ts_dt_idtable), diff --git a/drivers/input/touchscreen/bu21013_ts.c b/drivers/input/touchscreen/bu21013_ts.c index b9b5ddad6658a..931417eb4f5a2 100644 --- a/drivers/input/touchscreen/bu21013_ts.c +++ b/drivers/input/touchscreen/bu21013_ts.c @@ -716,7 +716,6 @@ MODULE_DEVICE_TABLE(i2c, bu21013_id); static struct i2c_driver bu21013_driver = { .driver = { .name = DRIVER_TP, - .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &bu21013_dev_pm_ops, #endif diff --git a/drivers/input/touchscreen/chipone_icn8318.c b/drivers/input/touchscreen/chipone_icn8318.c index 32e9db0e04bfd..22a6fead8cfb3 100644 --- a/drivers/input/touchscreen/chipone_icn8318.c +++ b/drivers/input/touchscreen/chipone_icn8318.c @@ -300,7 +300,6 @@ MODULE_DEVICE_TABLE(i2c, icn8318_i2c_id); static struct i2c_driver icn8318_driver = { .driver = { - .owner = THIS_MODULE, .name = "chipone_icn8318", .pm = &icn8318_pm_ops, .of_match_table = icn8318_of_match, diff --git a/drivers/input/touchscreen/cy8ctmg110_ts.c b/drivers/input/touchscreen/cy8ctmg110_ts.c index f2119ee0e21be..cc1d1350074e3 100644 --- a/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -347,7 +347,6 @@ MODULE_DEVICE_TABLE(i2c, cy8ctmg110_idtable); static struct i2c_driver cy8ctmg110_driver = { .driver = { - .owner = THIS_MODULE, .name = CY8CTMG110_DRIVER_NAME, .pm = &cy8ctmg110_pm, }, diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index 8e2012c79058e..9a323dd915dea 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -74,7 +74,6 @@ MODULE_DEVICE_TABLE(i2c, cyttsp4_i2c_id); static struct i2c_driver cyttsp4_i2c_driver = { .driver = { .name = CYTTSP4_I2C_NAME, - .owner = THIS_MODULE, .pm = &cyttsp4_pm_ops, }, .probe = cyttsp4_i2c_probe, diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 63104a86a9bdf..519e2de2f8dfc 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -74,7 +74,6 @@ MODULE_DEVICE_TABLE(i2c, cyttsp_i2c_id); static struct i2c_driver cyttsp_i2c_driver = { .driver = { .name = CY_I2C_NAME, - .owner = THIS_MODULE, .pm = &cyttsp_pm_ops, }, .probe = cyttsp_i2c_probe, diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c index 8f8f3199be394..48de1e8b3c935 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -1134,7 +1134,6 @@ MODULE_DEVICE_TABLE(of, edt_ft5x06_of_match); static struct i2c_driver edt_ft5x06_ts_driver = { .driver = { - .owner = THIS_MODULE, .name = "edt_ft5x06", .of_match_table = of_match_ptr(edt_ft5x06_of_match), .pm = &edt_ft5x06_ts_pm_ops, diff --git a/drivers/input/touchscreen/egalax_ts.c b/drivers/input/touchscreen/egalax_ts.c index 4c56299284ef6..7bce2d90ec742 100644 --- a/drivers/input/touchscreen/egalax_ts.c +++ b/drivers/input/touchscreen/egalax_ts.c @@ -268,7 +268,6 @@ static const struct of_device_id egalax_ts_dt_ids[] = { static struct i2c_driver egalax_ts_driver = { .driver = { .name = "egalax_ts", - .owner = THIS_MODULE, .pm = &egalax_ts_pm_ops, .of_match_table = egalax_ts_dt_ids, }, diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index 0efd766a545bc..7461376941373 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -1261,7 +1261,6 @@ static struct i2c_driver elants_i2c_driver = { .id_table = elants_i2c_id, .driver = { .name = DEVICE_NAME, - .owner = THIS_MODULE, .pm = &elants_i2c_pm_ops, .acpi_match_table = ACPI_PTR(elants_acpi_id), .of_match_table = of_match_ptr(elants_of_match), diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c index b4d12e29abff7..ccd9dca61195f 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -412,7 +412,6 @@ static struct i2c_driver goodix_ts_driver = { .id_table = goodix_ts_id, .driver = { .name = "Goodix-TS", - .owner = THIS_MODULE, .acpi_match_table = ACPI_PTR(goodix_acpi_match), .of_match_table = of_match_ptr(goodix_of_match), }, diff --git a/drivers/input/touchscreen/ili210x.c b/drivers/input/touchscreen/ili210x.c index da6dc819c846e..cf0dc2f0b1bed 100644 --- a/drivers/input/touchscreen/ili210x.c +++ b/drivers/input/touchscreen/ili210x.c @@ -343,7 +343,6 @@ MODULE_DEVICE_TABLE(i2c, ili210x_i2c_id); static struct i2c_driver ili210x_ts_driver = { .driver = { .name = "ili210x_i2c", - .owner = THIS_MODULE, .pm = &ili210x_i2c_pm, }, .id_table = ili210x_i2c_id, diff --git a/drivers/input/touchscreen/max11801_ts.c b/drivers/input/touchscreen/max11801_ts.c index a68ec142ee9a5..82079cde849c8 100644 --- a/drivers/input/touchscreen/max11801_ts.c +++ b/drivers/input/touchscreen/max11801_ts.c @@ -229,7 +229,6 @@ MODULE_DEVICE_TABLE(i2c, max11801_ts_id); static struct i2c_driver max11801_ts_driver = { .driver = { .name = "max11801_ts", - .owner = THIS_MODULE, }, .id_table = max11801_ts_id, .probe = max11801_ts_probe, diff --git a/drivers/input/touchscreen/mms114.c b/drivers/input/touchscreen/mms114.c index 67c0d31613d87..6b69f461733c1 100644 --- a/drivers/input/touchscreen/mms114.c +++ b/drivers/input/touchscreen/mms114.c @@ -577,7 +577,6 @@ static const struct of_device_id mms114_dt_match[] = { static struct i2c_driver mms114_driver = { .driver = { .name = "mms114", - .owner = THIS_MODULE, .pm = &mms114_pm_ops, .of_match_table = of_match_ptr(mms114_dt_match), }, diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c index 68d0d549797c4..4c71d631cbae7 100644 --- a/drivers/input/touchscreen/pixcir_i2c_ts.c +++ b/drivers/input/touchscreen/pixcir_i2c_ts.c @@ -604,7 +604,6 @@ MODULE_DEVICE_TABLE(of, pixcir_of_match); static struct i2c_driver pixcir_i2c_ts_driver = { .driver = { - .owner = THIS_MODULE, .name = "pixcir_ts", .pm = &pixcir_dev_pm_ops, .of_match_table = of_match_ptr(pixcir_of_match), diff --git a/drivers/input/touchscreen/st1232.c b/drivers/input/touchscreen/st1232.c index 697e26e52d542..e943678ce54cd 100644 --- a/drivers/input/touchscreen/st1232.c +++ b/drivers/input/touchscreen/st1232.c @@ -296,7 +296,6 @@ static struct i2c_driver st1232_ts_driver = { .id_table = st1232_ts_id, .driver = { .name = ST1232_TS_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(st1232_ts_dt_ids), .pm = &st1232_ts_pm_ops, }, diff --git a/drivers/input/touchscreen/tsc2007.c b/drivers/input/touchscreen/tsc2007.c index ccc8aa6157096..5d0cd51c6f41d 100644 --- a/drivers/input/touchscreen/tsc2007.c +++ b/drivers/input/touchscreen/tsc2007.c @@ -482,7 +482,6 @@ MODULE_DEVICE_TABLE(of, tsc2007_of_match); static struct i2c_driver tsc2007_driver = { .driver = { - .owner = THIS_MODULE, .name = "tsc2007", .of_match_table = of_match_ptr(tsc2007_of_match), }, diff --git a/drivers/input/touchscreen/wacom_i2c.c b/drivers/input/touchscreen/wacom_i2c.c index 32f8ac0039367..8d7a2852caef9 100644 --- a/drivers/input/touchscreen/wacom_i2c.c +++ b/drivers/input/touchscreen/wacom_i2c.c @@ -271,7 +271,6 @@ MODULE_DEVICE_TABLE(i2c, wacom_i2c_id); static struct i2c_driver wacom_i2c_driver = { .driver = { .name = "wacom_i2c", - .owner = THIS_MODULE, .pm = &wacom_i2c_pm, }, diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index c4cffcfb03d38..d00e1e33b6576 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -919,7 +919,6 @@ MODULE_DEVICE_TABLE(of, zforce_dt_idtable); static struct i2c_driver zforce_driver = { .driver = { - .owner = THIS_MODULE, .name = "zforce-ts", .pm = &zforce_pm_ops, .of_match_table = of_match_ptr(zforce_dt_idtable), -- GitLab From eff3cddc222c88943ff515ae9335687c9e2cbaf6 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:30 -0700 Subject: [PATCH 1180/7006] clarify implementation of ethtool's get_ts_info op This patch adds some clarification about the intended way to implement both SIOCSHWTSTAMP and ethtool's get_ts_info. The HWTSTAMP API has several Rx filters which are very specific, as well as more general filters. The specific filters really only exist to support some broken hardware which can't fully implement the generic filters. This patch adds clarification that it is okay to support the specific filters in SIOCSHWTSTAMP by upscaling them to the generic filters. In addition, update the header for ethtool_ts_info to specify that drivers ought to only report the filters they support without upscaling in this manner. Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Phil Schmitt Reviewed-by: Aaron Brown Signed-off-by: Jeff Kirsher --- Documentation/networking/timestamping.txt | 7 +++++++ include/uapi/linux/ethtool.h | 5 +++++ 2 files changed, 12 insertions(+) diff --git a/Documentation/networking/timestamping.txt b/Documentation/networking/timestamping.txt index 5f0922613f1a8..a977339fbe0a5 100644 --- a/Documentation/networking/timestamping.txt +++ b/Documentation/networking/timestamping.txt @@ -359,6 +359,13 @@ the requested fine-grained filtering for incoming packets is not supported, the driver may time stamp more than just the requested types of packets. +Drivers are free to use a more permissive configuration than the requested +configuration. It is expected that drivers should only implement directly the +most generic mode that can be supported. For example if the hardware can +support HWTSTAMP_FILTER_V2_EVENT, then it should generally always upscale +HWTSTAMP_FILTER_V2_L2_SYNC_MESSAGE, and so forth, as HWTSTAMP_FILTER_V2_EVENT +is more generic (and more useful to applications). + A driver which supports hardware time stamping shall update the struct with the actual, possibly more permissive configuration. If the requested packets cannot be time stamped, then nothing should be diff --git a/include/uapi/linux/ethtool.h b/include/uapi/linux/ethtool.h index cd67aec187d9f..cd1629170103e 100644 --- a/include/uapi/linux/ethtool.h +++ b/include/uapi/linux/ethtool.h @@ -1093,6 +1093,11 @@ struct ethtool_sfeatures { * the 'hwtstamp_tx_types' and 'hwtstamp_rx_filters' enumeration values, * respectively. For example, if the device supports HWTSTAMP_TX_ON, * then (1 << HWTSTAMP_TX_ON) in 'tx_types' will be set. + * + * Drivers should only report the filters they actually support without + * upscaling in the SIOCSHWTSTAMP ioctl. If the SIOCSHWSTAMP request for + * HWTSTAMP_FILTER_V1_SYNC is supported by HWTSTAMP_FILTER_V1_EVENT, then the + * driver should only report HWTSTAMP_FILTER_V1_EVENT in this op. */ struct ethtool_ts_info { __u32 cmd; -- GitLab From 1c3b8c2fe71a5052270167a1c5786aaf0d86cf19 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:31 -0700 Subject: [PATCH 1181/7006] freescale: remove incorrect copied comment The comment in question is word-for-word copied from ixgbe, and clearly has no meaning in freescale's driver. (it even says 'return an error' when the code clearly does not). Remove the comment as it is obviously incorrect and not applicable to the code as it is today. CC: Pantelis Antoniou CC: Vitaly Bordug CC: Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/freescale/fec_ptp.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c index a15663ad7f5e9..7a8386a8244dd 100644 --- a/drivers/net/ethernet/freescale/fec_ptp.c +++ b/drivers/net/ethernet/freescale/fec_ptp.c @@ -506,12 +506,6 @@ int fec_ptp_set(struct net_device *ndev, struct ifreq *ifr) break; default: - /* - * register RXMTRL must be set in order to do V1 packets, - * therefore it is not possible to time stamp both V1 Sync and - * Delay_Req messages and hardware does not support - * timestamping all packets => return error - */ fep->hwts_rx_en = 1; config.rx_filter = HWTSTAMP_FILTER_ALL; break; -- GitLab From dd3950c6d7185fbf9ec78a451b18d8807f35c6f7 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:32 -0700 Subject: [PATCH 1182/7006] bnx2x: only report most generic filters in get_ts_info CC: Ariel Elior Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index 76b9052a961c5..c783b57b2c9b8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -3562,17 +3562,8 @@ static int bnx2x_get_ts_info(struct net_device *dev, info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); info->tx_types = (1 << HWTSTAMP_TX_OFF)|(1 << HWTSTAMP_TX_ON); -- GitLab From c583cc430cf6942548fe658aac5a39eb9f371faf Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:33 -0700 Subject: [PATCH 1183/7006] i40e: only report generic filters in get_ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 0b68f61eeb0c0..f2075d5b800c1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1467,17 +1467,8 @@ static int i40e_get_ts_info(struct net_device *dev, info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ); + (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } -- GitLab From 97aebc1b3cdfd445a0a051090f0dcc6018b6df2c Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:34 -0700 Subject: [PATCH 1184/7006] igb: only report generic filters in get_ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ethtool.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index d5673eb90c542..109cad928e71a 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2396,10 +2396,6 @@ static int igb_get_ts_info(struct net_device *dev, info->rx_filters |= (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; -- GitLab From 044651f58536f209f1efdcdd1ae20788cf6d05c2 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:35 -0700 Subject: [PATCH 1185/7006] ixgbe: only report generic filters in get_ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index ec7b2324b77b4..f7aeb560a504a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2938,14 +2938,6 @@ static int ixgbe_get_ts_info(struct net_device *dev, (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); break; default: -- GitLab From 7415991ead78de1d340fb55d5b94d5b3287ab785 Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:36 -0700 Subject: [PATCH 1186/7006] siena: only report generic filters in get_ts_info CC: Solarflare linux maintainers CC: Shradha Shah Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/sfc/siena.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index b323b9167526f..b2f886d904297 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -1042,9 +1042,5 @@ const struct efx_nic_type siena_a0_nic_type = { .max_rx_ip_filters = FR_BZ_RX_FILTER_TBL0_ROWS, .hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE | 1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT | - 1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC | - 1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ | - 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT | - 1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC | - 1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ), + 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT), }; -- GitLab From 11b1544b5cfcc8c1ff01d1757397a6ce3c8aa85e Mon Sep 17 00:00:00 2001 From: Jacob Keller Date: Wed, 22 Apr 2015 14:40:37 -0700 Subject: [PATCH 1187/7006] dp83640: only report generic filters in ts_info Signed-off-by: Jacob Keller Acked-by: Richard Cochran Signed-off-by: Jeff Kirsher --- drivers/net/phy/dp83640.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c index 00cb41e713123..185b03c08e16c 100644 --- a/drivers/net/phy/dp83640.c +++ b/drivers/net/phy/dp83640.c @@ -1449,17 +1449,9 @@ static int dp83640_ts_info(struct phy_device *dev, struct ethtool_ts_info *info) info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ) | (1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_SYNC) | - (1 << HWTSTAMP_FILTER_PTP_V2_DELAY_REQ); + (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } -- GitLab From f56e7bba22fad16c0d4fac996623ce1c13244f8f Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 22 Apr 2015 21:49:17 -0700 Subject: [PATCH 1188/7006] igb: Pull timestamp from fragment before adding it to skb This change makes it so that we pull the timestamp from the fragment before we add it to the skb. By doing this we can avoid a possible issue in which the fragment can possibly be less than IGB_RX_HDR_LEN due to the timestamp being pulled after the copybreak check. While making this change I realized we could also pull the rest of the igb_pull_tail function into igb_add_rx_frag since in the case of igb, unlike ixgbe, we are able to unmap the entire buffer before calling add_rx_frag so merging the two allows for sharing of code between the two merged functions. Reported-by: Cong Wang Signed-off-by: Alexander Duyck Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 94 ++++++----------------- 1 file changed, 25 insertions(+), 69 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 2f70a9b152bd1..fc7729e78f3de 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -6621,22 +6621,25 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, struct sk_buff *skb) { struct page *page = rx_buffer->page; + unsigned char *va = page_address(page) + rx_buffer->page_offset; unsigned int size = le16_to_cpu(rx_desc->wb.upper.length); #if (PAGE_SIZE < 8192) unsigned int truesize = IGB_RX_BUFSZ; #else - unsigned int truesize = ALIGN(size, L1_CACHE_BYTES); + unsigned int truesize = SKB_DATA_ALIGN(size); #endif + unsigned int pull_len; - if ((size <= IGB_RX_HDR_LEN) && !skb_is_nonlinear(skb)) { - unsigned char *va = page_address(page) + rx_buffer->page_offset; + if (unlikely(skb_is_nonlinear(skb))) + goto add_tail_frag; - if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) { - igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); - va += IGB_TS_HDR_LEN; - size -= IGB_TS_HDR_LEN; - } + if (unlikely(igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP))) { + igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); + va += IGB_TS_HDR_LEN; + size -= IGB_TS_HDR_LEN; + } + if (likely(size <= IGB_RX_HDR_LEN)) { memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); /* page is not reserved, we can reuse buffer as-is */ @@ -6648,8 +6651,21 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, return false; } + /* we need the header to contain the greater of either ETH_HLEN or + * 60 bytes if the skb->len is less than 60 for skb_pad. + */ + pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN); + + /* align pull length to size of long to optimize memcpy performance */ + memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long))); + + /* update all of the pointers */ + va += pull_len; + size -= pull_len; + +add_tail_frag: skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - rx_buffer->page_offset, size, truesize); + (unsigned long)va & ~PAGE_MASK, size, truesize); return igb_can_reuse_rx_page(rx_buffer, page, truesize); } @@ -6790,62 +6806,6 @@ static bool igb_is_non_eop(struct igb_ring *rx_ring, return true; } -/** - * igb_pull_tail - igb specific version of skb_pull_tail - * @rx_ring: rx descriptor ring packet is being transacted on - * @rx_desc: pointer to the EOP Rx descriptor - * @skb: pointer to current skb being adjusted - * - * This function is an igb specific version of __pskb_pull_tail. The - * main difference between this version and the original function is that - * this function can make several assumptions about the state of things - * that allow for significant optimizations versus the standard function. - * As a result we can do things like drop a frag and maintain an accurate - * truesize for the skb. - */ -static void igb_pull_tail(struct igb_ring *rx_ring, - union e1000_adv_rx_desc *rx_desc, - struct sk_buff *skb) -{ - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; - unsigned char *va; - unsigned int pull_len; - - /* it is valid to use page_address instead of kmap since we are - * working with pages allocated out of the lomem pool per - * alloc_page(GFP_ATOMIC) - */ - va = skb_frag_address(frag); - - if (igb_test_staterr(rx_desc, E1000_RXDADV_STAT_TSIP)) { - /* retrieve timestamp from buffer */ - igb_ptp_rx_pktstamp(rx_ring->q_vector, va, skb); - - /* update pointers to remove timestamp header */ - skb_frag_size_sub(frag, IGB_TS_HDR_LEN); - frag->page_offset += IGB_TS_HDR_LEN; - skb->data_len -= IGB_TS_HDR_LEN; - skb->len -= IGB_TS_HDR_LEN; - - /* move va to start of packet data */ - va += IGB_TS_HDR_LEN; - } - - /* we need the header to contain the greater of either ETH_HLEN or - * 60 bytes if the skb->len is less than 60 for skb_pad. - */ - pull_len = eth_get_headlen(va, IGB_RX_HDR_LEN); - - /* align pull length to size of long to optimize memcpy performance */ - skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long))); - - /* update all of the pointers */ - skb_frag_size_sub(frag, pull_len); - frag->page_offset += pull_len; - skb->data_len -= pull_len; - skb->tail += pull_len; -} - /** * igb_cleanup_headers - Correct corrupted or empty headers * @rx_ring: rx descriptor ring packet is being transacted on @@ -6873,10 +6833,6 @@ static bool igb_cleanup_headers(struct igb_ring *rx_ring, } } - /* place header in linear portion of buffer */ - if (skb_is_nonlinear(skb)) - igb_pull_tail(rx_ring, rx_desc, skb); - /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) return true; -- GitLab From 5505bdb54d92267a5b6f092c337bd84d247bcf49 Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 22 Apr 2015 21:49:32 -0700 Subject: [PATCH 1189/7006] ixgbevf: fold ixgbevf_pull_tail into ixgbevf_add_rx_frag This change folds the ixgbevf_pull_tail call into ixgbevf_add_rx_frag. The advantage to doing this is that the fragment doesn't have to be modified after it is added to the skb. Signed-off-by: Alexander Duyck Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 66 ++++++------------- 1 file changed, 19 insertions(+), 47 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index e71cdde9cb017..acfa05154436c 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -648,46 +648,6 @@ static void ixgbevf_alloc_rx_buffers(struct ixgbevf_ring *rx_ring, } } -/** - * ixgbevf_pull_tail - ixgbevf specific version of skb_pull_tail - * @rx_ring: rx descriptor ring packet is being transacted on - * @skb: pointer to current skb being adjusted - * - * This function is an ixgbevf specific version of __pskb_pull_tail. The - * main difference between this version and the original function is that - * this function can make several assumptions about the state of things - * that allow for significant optimizations versus the standard function. - * As a result we can do things like drop a frag and maintain an accurate - * truesize for the skb. - **/ -static void ixgbevf_pull_tail(struct ixgbevf_ring *rx_ring, - struct sk_buff *skb) -{ - struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0]; - unsigned char *va; - unsigned int pull_len; - - /* it is valid to use page_address instead of kmap since we are - * working with pages allocated out of the lomem pool per - * alloc_page(GFP_ATOMIC) - */ - va = skb_frag_address(frag); - - /* we need the header to contain the greater of either ETH_HLEN or - * 60 bytes if the skb->len is less than 60 for skb_pad. - */ - pull_len = eth_get_headlen(va, IXGBEVF_RX_HDR_SIZE); - - /* align pull length to size of long to optimize memcpy performance */ - skb_copy_to_linear_data(skb, va, ALIGN(pull_len, sizeof(long))); - - /* update all of the pointers */ - skb_frag_size_sub(frag, pull_len); - frag->page_offset += pull_len; - skb->data_len -= pull_len; - skb->tail += pull_len; -} - /** * ixgbevf_cleanup_headers - Correct corrupted or empty headers * @rx_ring: rx descriptor ring packet is being transacted on @@ -721,10 +681,6 @@ static bool ixgbevf_cleanup_headers(struct ixgbevf_ring *rx_ring, } } - /* place header in linear portion of buffer */ - if (skb_is_nonlinear(skb)) - ixgbevf_pull_tail(rx_ring, skb); - /* if eth_skb_pad returns an error the skb was freed */ if (eth_skb_pad(skb)) return true; @@ -789,16 +745,19 @@ static bool ixgbevf_add_rx_frag(struct ixgbevf_ring *rx_ring, struct sk_buff *skb) { struct page *page = rx_buffer->page; + unsigned char *va = page_address(page) + rx_buffer->page_offset; unsigned int size = le16_to_cpu(rx_desc->wb.upper.length); #if (PAGE_SIZE < 8192) unsigned int truesize = IXGBEVF_RX_BUFSZ; #else unsigned int truesize = ALIGN(size, L1_CACHE_BYTES); #endif + unsigned int pull_len; - if ((size <= IXGBEVF_RX_HDR_SIZE) && !skb_is_nonlinear(skb)) { - unsigned char *va = page_address(page) + rx_buffer->page_offset; + if (unlikely(skb_is_nonlinear(skb))) + goto add_tail_frag; + if (likely(size <= IXGBEVF_RX_HDR_SIZE)) { memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long))); /* page is not reserved, we can reuse buffer as is */ @@ -810,8 +769,21 @@ static bool ixgbevf_add_rx_frag(struct ixgbevf_ring *rx_ring, return false; } + /* we need the header to contain the greater of either ETH_HLEN or + * 60 bytes if the skb->len is less than 60 for skb_pad. + */ + pull_len = eth_get_headlen(va, IXGBEVF_RX_HDR_SIZE); + + /* align pull length to size of long to optimize memcpy performance */ + memcpy(__skb_put(skb, pull_len), va, ALIGN(pull_len, sizeof(long))); + + /* update all of the pointers */ + va += pull_len; + size -= pull_len; + +add_tail_frag: skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, - rx_buffer->page_offset, size, truesize); + (unsigned long)va & ~PAGE_MASK, size, truesize); /* avoid re-using remote pages */ if (unlikely(ixgbevf_page_is_reserved(page))) -- GitLab From 7edda4b8711d58dabb55e6afec03e8177647f266 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Wed, 29 Apr 2015 10:57:39 +0800 Subject: [PATCH 1190/7006] ixgbe: Specify Rx hash type WRT Rx desc RSS type RSS could be leveraged by taking account L4 src/dst ports as ingredients, thus ingress skb Rx hash type should honor such the real configuration. Signed-off-by: Fan Du Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 25 ++++++++++++++++--- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 9aa6104e34ea8..3e6a9319c7185 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1360,14 +1360,31 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) } #endif /* CONFIG_IXGBE_DCA */ + +#define IXGBE_RSS_L4_TYPES_MASK \ + ((1ul << IXGBE_RXDADV_RSSTYPE_IPV4_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV4_UDP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_UDP)) + static inline void ixgbe_rx_hash(struct ixgbe_ring *ring, union ixgbe_adv_rx_desc *rx_desc, struct sk_buff *skb) { - if (ring->netdev->features & NETIF_F_RXHASH) - skb_set_hash(skb, - le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), - PKT_HASH_TYPE_L3); + u16 rss_type; + + if (!(ring->netdev->features & NETIF_F_RXHASH)) + return; + + rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) & + IXGBE_RXDADV_RSSTYPE_MASK; + + if (!rss_type) + return; + + skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + (IXGBE_RSS_L4_TYPES_MASK & (1ul << rss_type)) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); } #ifdef IXGBE_FCOE -- GitLab From 1e1429d6ce6e6fe38e45c960133e9c9b3c62cbc6 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Wed, 29 Apr 2015 10:57:40 +0800 Subject: [PATCH 1191/7006] ixgbevf: Set Rx hash type for ingress packets Set hash type for ingress packets according to NIC advanced receive descriptors RSS type part. Signed-off-by: Fan Du Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/defines.h | 12 +++++++++ .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 27 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbevf/defines.h b/drivers/net/ethernet/intel/ixgbevf/defines.h index 770e21a643880..58434584b16d9 100644 --- a/drivers/net/ethernet/intel/ixgbevf/defines.h +++ b/drivers/net/ethernet/intel/ixgbevf/defines.h @@ -161,6 +161,18 @@ typedef u32 ixgbe_link_speed; #define IXGBE_RXDADV_SPLITHEADER_EN 0x00001000 #define IXGBE_RXDADV_SPH 0x8000 +/* RSS Hash results */ +#define IXGBE_RXDADV_RSSTYPE_NONE 0x00000000 +#define IXGBE_RXDADV_RSSTYPE_IPV4_TCP 0x00000001 +#define IXGBE_RXDADV_RSSTYPE_IPV4 0x00000002 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP 0x00000003 +#define IXGBE_RXDADV_RSSTYPE_IPV6_EX 0x00000004 +#define IXGBE_RXDADV_RSSTYPE_IPV6 0x00000005 +#define IXGBE_RXDADV_RSSTYPE_IPV6_TCP_EX 0x00000006 +#define IXGBE_RXDADV_RSSTYPE_IPV4_UDP 0x00000007 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP 0x00000008 +#define IXGBE_RXDADV_RSSTYPE_IPV6_UDP_EX 0x00000009 + #define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \ IXGBE_RXD_ERR_CE | \ IXGBE_RXD_ERR_LE | \ diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index acfa05154436c..b2c86f1b8a9fa 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -457,6 +457,32 @@ static void ixgbevf_rx_skb(struct ixgbevf_q_vector *q_vector, napi_gro_receive(&q_vector->napi, skb); } +#define IXGBE_RSS_L4_TYPES_MASK \ + ((1ul << IXGBE_RXDADV_RSSTYPE_IPV4_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV4_UDP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_TCP) | \ + (1ul << IXGBE_RXDADV_RSSTYPE_IPV6_UDP)) + +static inline void ixgbevf_rx_hash(struct ixgbevf_ring *ring, + union ixgbe_adv_rx_desc *rx_desc, + struct sk_buff *skb) +{ + u16 rss_type; + + if (!(ring->netdev->features & NETIF_F_RXHASH)) + return; + + rss_type = le16_to_cpu(rx_desc->wb.lower.lo_dword.hs_rss.pkt_info) & + IXGBE_RXDADV_RSSTYPE_MASK; + + if (!rss_type) + return; + + skb_set_hash(skb, le32_to_cpu(rx_desc->wb.lower.hi_dword.rss), + (IXGBE_RSS_L4_TYPES_MASK & (1ul << rss_type)) ? + PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3); +} + /** * ixgbevf_rx_checksum - indicate in skb if hw indicated a good cksum * @ring: structure containig ring specific data @@ -506,6 +532,7 @@ static void ixgbevf_process_skb_fields(struct ixgbevf_ring *rx_ring, union ixgbe_adv_rx_desc *rx_desc, struct sk_buff *skb) { + ixgbevf_rx_hash(rx_ring, rx_desc, skb); ixgbevf_rx_checksum(rx_ring, rx_desc, skb); if (ixgbevf_test_staterr(rx_desc, IXGBE_RXD_STAT_VP)) { -- GitLab From 3b7884f75f3d3f0a0191c00a083535a1dd01a5a4 Mon Sep 17 00:00:00 2001 From: Fan Du Date: Wed, 29 Apr 2015 10:57:41 +0800 Subject: [PATCH 1192/7006] ixgbe: Don't report flow director filter's status For two reasons I want to disable this: 1. Not any part actually check the report status(Alexander Duyck) 2. To report hash value of a packet to stack, RSS -> 32bits hash value Perfect match fdir filter -> 13bits hash value Hashed-based fdir filter -> 31bits hash value fdir filter might hash on masked tuples for IP address, so it's still not desirable for usage. So for now, just stick to RSS 32bits hash value. Signed-off-by: Fan Du Suggested-by: Alexander Duyck Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 6b87d96346146..b1e364d26aa73 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1394,14 +1394,12 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 fdirctrl) /* * Continue setup of fdirctrl register bits: * Turn perfect match filtering on - * Report hash in RSS field of Rx wb descriptor * Initialize the drop queue * Move the flexible bytes to use the ethertype - shift 6 words * Set the maximum length per hash bucket to 0xA filters * Send interrupt when 64 (0x4 * 16) filters are left */ fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH | - IXGBE_FDIRCTRL_REPORT_STATUS | (IXGBE_FDIR_DROP_QUEUE << IXGBE_FDIRCTRL_DROP_Q_SHIFT) | (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT) | (0xA << IXGBE_FDIRCTRL_MAX_LENGTH_SHIFT) | -- GitLab From 2ba6c0797c8b5a9f945345ef2b9193bd47e5f18e Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Wed, 29 Apr 2015 15:23:28 -0700 Subject: [PATCH 1193/7006] igb: Fix i354 88E1112 PHY on RCC boards using AutoMediaDetect e1000_check_for_link_media_swap() checks PHY page 0 for copper and PHY page 1 for "other" (fiber) link. The switch back from page 1 to page 0 happened too soon, before e1000_check_for_link_82575() is executed, and link on fiber (other) was never detected. Check for link while still on the proper PHY page. Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_82575.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_82575.c b/drivers/net/ethernet/intel/igb/e1000_82575.c index b0182dd313464..d19256994e5cf 100644 --- a/drivers/net/ethernet/intel/igb/e1000_82575.c +++ b/drivers/net/ethernet/intel/igb/e1000_82575.c @@ -139,10 +139,6 @@ static s32 igb_check_for_link_media_swap(struct e1000_hw *hw) if (ret_val) return ret_val; - /* reset page to 0 */ - ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); - if (ret_val) - return ret_val; if (data & E1000_M88E1112_STATUS_LINK) port = E1000_MEDIA_PORT_OTHER; @@ -151,8 +147,20 @@ static s32 igb_check_for_link_media_swap(struct e1000_hw *hw) if (port && (hw->dev_spec._82575.media_port != port)) { hw->dev_spec._82575.media_port = port; hw->dev_spec._82575.media_changed = true; + } + + if (port == E1000_MEDIA_PORT_COPPER) { + /* reset page to 0 */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; + igb_check_for_link_82575(hw); } else { - ret_val = igb_check_for_link_82575(hw); + igb_check_for_link_82575(hw); + /* reset page to 0 */ + ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0); + if (ret_val) + return ret_val; } return 0; -- GitLab From dd9283e23f674281c02cd8cbf894cb3132a4e3a6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jul 2015 23:38:34 +0800 Subject: [PATCH 1194/7006] ASoC: cs4349: Fix max_register setting for cs4349_regmap The max_register should be the maximum valid register index rather than number of registers. Also remove unused defines. Signed-off-by: Axel Lin Acked-by: Tim Howe Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 2 +- sound/soc/codecs/cs4349.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a8df8a7496071..9273b06e918b2 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -268,7 +268,7 @@ static struct regmap_config cs4349_regmap = { .reg_bits = 8, .val_bits = 8, - .max_register = CS4349_NUMREGS, + .max_register = CS4349_MISC, .reg_defaults = cs4349_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), .readable_reg = cs4349_readable_register, diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h index 3884a8907d23d..7effa0acec28e 100644 --- a/sound/soc/codecs/cs4349.h +++ b/sound/soc/codecs/cs4349.h @@ -36,9 +36,6 @@ struct cs4349_platform_data { #define CS4349_RMPFLT 0x07 /* Ramp and Filter Control */ #define CS4349_MISC 0x08 /* Power Down,Freeze Control,Pop Stop*/ -#define CS4349_FIRSTREG 0x01 -#define CS4349_LASTREG 0x08 -#define CS4349_NUMREGS (CS4349_LASTREG - CS4349_FIRSTREG + 1) #define CS4349_I2C_INCR 0x80 -- GitLab From b08b338253e917be45ee19924b58dd0b1265473f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 17 Jul 2015 23:43:02 +0800 Subject: [PATCH 1195/7006] ASoC: cs4349: Constify cs4349_regmap Signed-off-by: Axel Lin Acked-by: Tim Howe Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 9273b06e918b2..f4fccc621ceb0 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -264,7 +264,7 @@ static struct snd_soc_codec_driver soc_codec_dev_cs4349 = { .num_dapm_routes = ARRAY_SIZE(cs4349_routes), }; -static struct regmap_config cs4349_regmap = { +static const struct regmap_config cs4349_regmap = { .reg_bits = 8, .val_bits = 8, -- GitLab From 22801f76fa59870aed2c0b8a4eb6c8d6993347ae Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Mon, 19 Jan 2015 16:20:21 +0200 Subject: [PATCH 1196/7006] drm/radeon: Modify kgd_engine_type enum to match CZ This patch splits the KGD_ENGINE_SDMA to KGD_ENGINE_SDMA1 and KGD_ENGINE_SDMA2 to match CZ definitions. Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/include/kgd_kfd_interface.h | 3 ++- drivers/gpu/drm/radeon/radeon_kfd.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h index 9080daa116b60..888250b33ea89 100644 --- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h @@ -52,7 +52,8 @@ enum kgd_engine_type { KGD_ENGINE_MEC1, KGD_ENGINE_MEC2, KGD_ENGINE_RLC, - KGD_ENGINE_SDMA, + KGD_ENGINE_SDMA1, + KGD_ENGINE_SDMA2, KGD_ENGINE_MAX }; diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c index e476c331f3fa6..9a4d69e594015 100644 --- a/drivers/gpu/drm/radeon/radeon_kfd.c +++ b/drivers/gpu/drm/radeon/radeon_kfd.c @@ -845,7 +845,8 @@ static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) hdr = (const union radeon_firmware_header *) rdev->rlc_fw->data; break; - case KGD_ENGINE_SDMA: + case KGD_ENGINE_SDMA1: + case KGD_ENGINE_SDMA2: hdr = (const union radeon_firmware_header *) rdev->sdma_fw->data; break; -- GitLab From 130e0371b7d454bb4a861253c822b9f911ad5d19 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 12 Jun 2015 21:35:14 +0300 Subject: [PATCH 1197/7006] drm/amdgpu: Add H/W agnostic amdgpu <--> amdkfd interface This patch adds an interface file between amdgpu and amdkfd. This interface file is H/W agnostic, thus containing functions that operate the same for any AMD APU/GPU H/W generation. The functions in this interface mirror (some) of the functions in radeon_kfd.c (the radeon<-->amdkfd interface file). The main functions are: - amdgpu_amdkfd_init - initialize the amdkfd module - amdgpu_amdkfd_load_interface - load the H/W interface according to the currently probed device - amdgpu_amdkfd_device_probe - probe the device in amdkfd - amdgpu_amdkfd_device_init - initialize the device in amdkfd - amdgpu_amdkfd_interrupt - call the ISR of amdkfd - amdgpu_amdkfd_suspend - suspend callback from amdgpu - amdgpu_amdkfd_resume - resume callback from amdgpu This patch also modifies the relevant amdgpu files, to use this new interface. Signed-off-by: Oded Gabbay --- MAINTAINERS | 2 + drivers/gpu/drm/amd/amdgpu/Makefile | 4 + drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 262 +++++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 64 +++++ drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c | 5 + drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c | 7 + drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 7 + drivers/gpu/drm/amd/amdgpu/cik.c | 11 +- 9 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h diff --git a/MAINTAINERS b/MAINTAINERS index a2264167791ac..8012189d358fe 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -636,6 +636,8 @@ M: Oded Gabbay L: dri-devel@lists.freedesktop.org T: git git://people.freedesktop.org/~gabbayo/linux.git S: Supported +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 616dfd4a13981..891f02c21de60 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -71,6 +71,10 @@ amdgpu-y += \ amdgpu_vce.o \ vce_v3_0.o +# add amdkfd interfaces +amdgpu-y += \ + amdgpu_amdkfd.o + amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o amdgpu-$(CONFIG_ACPI) += amdgpu_acpi.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 01657830b470a..f3791e0d27d48 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -2011,6 +2011,9 @@ struct amdgpu_device { /* tracking pinned memory */ u64 vram_pin_size; u64 gart_pin_size; + + /* amdkfd interface */ + struct kfd_dev *kfd; }; bool amdgpu_device_is_px(struct drm_device *dev); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c new file mode 100644 index 0000000000000..2071a9b757f74 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -0,0 +1,262 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include "amdgpu_amdkfd.h" +#include "amdgpu_family.h" +#include +#include "amdgpu.h" +#include + +const struct kfd2kgd_calls *kfd2kgd; +const struct kgd2kfd_calls *kgd2kfd; +bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); + +bool amdgpu_amdkfd_init(void) +{ +#if defined(CONFIG_HSA_AMD_MODULE) + bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); + + kgd2kfd_init_p = symbol_request(kgd2kfd_init); + + if (kgd2kfd_init_p == NULL) + return false; +#endif + return true; +} + +bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) +{ +#if defined(CONFIG_HSA_AMD_MODULE) + bool (*kgd2kfd_init_p)(unsigned, const struct kgd2kfd_calls**); +#endif + + switch (rdev->asic_type) { + case CHIP_KAVERI: + default: + return false; + } + +#if defined(CONFIG_HSA_AMD_MODULE) + kgd2kfd_init_p = symbol_request(kgd2kfd_init); + + if (kgd2kfd_init_p == NULL) { + kfd2kgd = NULL; + return false; + } + + if (!kgd2kfd_init_p(KFD_INTERFACE_VERSION, &kgd2kfd)) { + symbol_put(kgd2kfd_init); + kfd2kgd = NULL; + kgd2kfd = NULL; + + return false; + } + + return true; +#elif defined(CONFIG_HSA_AMD) + if (!kgd2kfd_init(KFD_INTERFACE_VERSION, &kgd2kfd)) { + kfd2kgd = NULL; + kgd2kfd = NULL; + return false; + } + + return true; +#else + kfd2kgd = NULL; + return false; +#endif +} + +void amdgpu_amdkfd_fini(void) +{ + if (kgd2kfd) { + kgd2kfd->exit(); + symbol_put(kgd2kfd_init); + } +} + +void amdgpu_amdkfd_device_probe(struct amdgpu_device *rdev) +{ + if (kgd2kfd) + rdev->kfd = kgd2kfd->probe((struct kgd_dev *)rdev, + rdev->pdev, kfd2kgd); +} + +void amdgpu_amdkfd_device_init(struct amdgpu_device *rdev) +{ + if (rdev->kfd) { + struct kgd2kfd_shared_resources gpu_resources = { + .compute_vmid_bitmap = 0xFF00, + + .first_compute_pipe = 1, + .compute_pipe_count = 4 - 1, + }; + + amdgpu_doorbell_get_kfd_info(rdev, + &gpu_resources.doorbell_physical_address, + &gpu_resources.doorbell_aperture_size, + &gpu_resources.doorbell_start_offset); + + kgd2kfd->device_init(rdev->kfd, &gpu_resources); + } +} + +void amdgpu_amdkfd_device_fini(struct amdgpu_device *rdev) +{ + if (rdev->kfd) { + kgd2kfd->device_exit(rdev->kfd); + rdev->kfd = NULL; + } +} + +void amdgpu_amdkfd_interrupt(struct amdgpu_device *rdev, + const void *ih_ring_entry) +{ + if (rdev->kfd) + kgd2kfd->interrupt(rdev->kfd, ih_ring_entry); +} + +void amdgpu_amdkfd_suspend(struct amdgpu_device *rdev) +{ + if (rdev->kfd) + kgd2kfd->suspend(rdev->kfd); +} + +int amdgpu_amdkfd_resume(struct amdgpu_device *rdev) +{ + int r = 0; + + if (rdev->kfd) + r = kgd2kfd->resume(rdev->kfd); + + return r; +} + +u32 pool_to_domain(enum kgd_memory_pool p) +{ + switch (p) { + case KGD_POOL_FRAMEBUFFER: return AMDGPU_GEM_DOMAIN_VRAM; + default: return AMDGPU_GEM_DOMAIN_GTT; + } +} + +int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr) +{ + struct amdgpu_device *rdev = (struct amdgpu_device *)kgd; + struct kgd_mem **mem = (struct kgd_mem **) mem_obj; + int r; + + BUG_ON(kgd == NULL); + BUG_ON(gpu_addr == NULL); + BUG_ON(cpu_ptr == NULL); + + *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL); + if ((*mem) == NULL) + return -ENOMEM; + + r = amdgpu_bo_create(rdev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, + AMDGPU_GEM_CREATE_CPU_GTT_USWC, NULL, &(*mem)->bo); + if (r) { + dev_err(rdev->dev, + "failed to allocate BO for amdkfd (%d)\n", r); + return r; + } + + /* map the buffer */ + r = amdgpu_bo_reserve((*mem)->bo, true); + if (r) { + dev_err(rdev->dev, "(%d) failed to reserve bo for amdkfd\n", r); + goto allocate_mem_reserve_bo_failed; + } + + r = amdgpu_bo_pin((*mem)->bo, AMDGPU_GEM_DOMAIN_GTT, + &(*mem)->gpu_addr); + if (r) { + dev_err(rdev->dev, "(%d) failed to pin bo for amdkfd\n", r); + goto allocate_mem_pin_bo_failed; + } + *gpu_addr = (*mem)->gpu_addr; + + r = amdgpu_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr); + if (r) { + dev_err(rdev->dev, + "(%d) failed to map bo to kernel for amdkfd\n", r); + goto allocate_mem_kmap_bo_failed; + } + *cpu_ptr = (*mem)->cpu_ptr; + + amdgpu_bo_unreserve((*mem)->bo); + + return 0; + +allocate_mem_kmap_bo_failed: + amdgpu_bo_unpin((*mem)->bo); +allocate_mem_pin_bo_failed: + amdgpu_bo_unreserve((*mem)->bo); +allocate_mem_reserve_bo_failed: + amdgpu_bo_unref(&(*mem)->bo); + + return r; +} + +void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj) +{ + struct kgd_mem *mem = (struct kgd_mem *) mem_obj; + + BUG_ON(mem == NULL); + + amdgpu_bo_reserve(mem->bo, true); + amdgpu_bo_kunmap(mem->bo); + amdgpu_bo_unpin(mem->bo); + amdgpu_bo_unreserve(mem->bo); + amdgpu_bo_unref(&(mem->bo)); + kfree(mem); +} + +uint64_t get_vmem_size(struct kgd_dev *kgd) +{ + struct amdgpu_device *rdev = + (struct amdgpu_device *)kgd; + + BUG_ON(kgd == NULL); + + return rdev->mc.real_vram_size; +} + +uint64_t get_gpu_clock_counter(struct kgd_dev *kgd) +{ + struct amdgpu_device *rdev = (struct amdgpu_device *)kgd; + + if (rdev->asic_funcs->get_gpu_clock_counter) + return rdev->asic_funcs->get_gpu_clock_counter(rdev); + return 0; +} + +uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd) +{ + struct amdgpu_device *rdev = (struct amdgpu_device *)kgd; + + /* The sclk is in quantas of 10kHz */ + return rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk / 100; +} diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h new file mode 100644 index 0000000000000..c81242e84abab --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -0,0 +1,64 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +/* amdgpu_amdkfd.h defines the private interface between amdgpu and amdkfd. */ + +#ifndef AMDGPU_AMDKFD_H_INCLUDED +#define AMDGPU_AMDKFD_H_INCLUDED + +#include +#include + +struct amdgpu_device; + +struct kgd_mem { + struct amdgpu_bo *bo; + uint64_t gpu_addr; + void *cpu_ptr; +}; + +bool amdgpu_amdkfd_init(void); +void amdgpu_amdkfd_fini(void); + +bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev); + +void amdgpu_amdkfd_suspend(struct amdgpu_device *rdev); +int amdgpu_amdkfd_resume(struct amdgpu_device *rdev); +void amdgpu_amdkfd_interrupt(struct amdgpu_device *rdev, + const void *ih_ring_entry); +void amdgpu_amdkfd_device_probe(struct amdgpu_device *rdev); +void amdgpu_amdkfd_device_init(struct amdgpu_device *rdev); +void amdgpu_amdkfd_device_fini(struct amdgpu_device *rdev); + +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); + +/* Shared API */ +int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, + void **mem_obj, uint64_t *gpu_addr, + void **cpu_ptr); +void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj); +uint64_t get_vmem_size(struct kgd_dev *kgd); +uint64_t get_gpu_clock_counter(struct kgd_dev *kgd); + +uint32_t get_max_engine_clock_in_mhz(struct kgd_dev *kgd); + +#endif /* AMDGPU_AMDKFD_H_INCLUDED */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c index 56da962231fc7..115906f5fda0a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c @@ -44,6 +44,8 @@ #include "amdgpu.h" #include "amdgpu_irq.h" +#include "amdgpu_amdkfd.h" + /* * KMS wrapper. * - 3.0.0 - initial driver @@ -527,12 +529,15 @@ static int __init amdgpu_init(void) driver->num_ioctls = amdgpu_max_kms_ioctl; amdgpu_register_atpx_handler(); + amdgpu_amdkfd_init(); + /* let modprobe override vga console setting */ return drm_pci_init(driver, pdriver); } static void __exit amdgpu_exit(void) { + amdgpu_amdkfd_fini(); drm_pci_exit(driver, pdriver); amdgpu_unregister_atpx_handler(); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c index db5422e65ec5f..fb44dd2231b1c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c @@ -24,6 +24,7 @@ #include #include "amdgpu.h" #include "amdgpu_ih.h" +#include "amdgpu_amdkfd.h" /** * amdgpu_ih_ring_alloc - allocate memory for the IH ring @@ -199,6 +200,12 @@ restart_ih: rmb(); while (adev->irq.ih.rptr != wptr) { + u32 ring_index = adev->irq.ih.rptr >> 2; + + /* Before dispatching irq to IP blocks, send it to amdkfd */ + amdgpu_amdkfd_interrupt(adev, + (const void *) &adev->irq.ih.ring[ring_index]); + amdgpu_ih_decode_iv(adev, &entry); adev->irq.ih.rptr &= adev->irq.ih.ptr_mask; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 5533434c7a8fa..8c40a9671b9fb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -34,6 +34,7 @@ #include #include #include +#include "amdgpu_amdkfd.h" #if defined(CONFIG_VGA_SWITCHEROO) bool amdgpu_has_atpx(void); @@ -61,6 +62,8 @@ int amdgpu_driver_unload_kms(struct drm_device *dev) pm_runtime_get_sync(dev->dev); + amdgpu_amdkfd_device_fini(adev); + amdgpu_acpi_fini(adev); amdgpu_device_fini(adev); @@ -118,6 +121,10 @@ int amdgpu_driver_load_kms(struct drm_device *dev, unsigned long flags) "Error during ACPI methods call\n"); } + amdgpu_amdkfd_load_interface(adev); + amdgpu_amdkfd_device_probe(adev); + amdgpu_amdkfd_device_init(adev); + if (amdgpu_device_is_px(dev)) { pm_runtime_use_autosuspend(dev->dev); pm_runtime_set_autosuspend_delay(dev->dev, 5000); diff --git a/drivers/gpu/drm/amd/amdgpu/cik.c b/drivers/gpu/drm/amd/amdgpu/cik.c index 341c566818419..b3b66a0d5ff7c 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik.c +++ b/drivers/gpu/drm/amd/amdgpu/cik.c @@ -64,6 +64,8 @@ #include "oss/oss_2_0_d.h" #include "oss/oss_2_0_sh_mask.h" +#include "amdgpu_amdkfd.h" + /* * Indirect registers accessor */ @@ -2448,14 +2450,21 @@ static int cik_common_suspend(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + amdgpu_amdkfd_suspend(adev); + return cik_common_hw_fini(adev); } static int cik_common_resume(void *handle) { + int r; struct amdgpu_device *adev = (struct amdgpu_device *)handle; - return cik_common_hw_init(adev); + r = cik_common_hw_init(adev); + if (r) + return r; + + return amdgpu_amdkfd_resume(adev); } static bool cik_common_is_idle(void *handle) -- GitLab From 32c22e994f44e7e5cc54b52375012311d1693b0d Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 12 Jun 2015 21:38:22 +0300 Subject: [PATCH 1198/7006] drm/amdgpu: add amdgpu <--> amdkfd gfx7 interface This patch adds the gfx7 interface file between amdgpu and amdkfd. This interface file mirrors (some) of the functions in radeon_kfd.c (the interface file between radeon and amdkfd). The gfx7 interface is used when it is run on a Kaveri-based system. This interface file was used for bring-up of amdkfd on amdgpu and for debugging purposes. For users who would like to run HSA on Kaveri, please use the radeon graphic driver. Note: CONFIG_DRM_AMDGPU_CIK must be selected for amdgpu to handle Kaveri. v2: removed MTYPE_NONCACHED enum definition as it is defined in another patch Signed-off-by: Oded Gabbay --- MAINTAINERS | 1 + drivers/gpu/drm/amd/amdgpu/Makefile | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 2 + .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c | 670 ++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/cikd.h | 6 + 5 files changed, 681 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c diff --git a/MAINTAINERS b/MAINTAINERS index 8012189d358fe..5cc07349b5234 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -638,6 +638,7 @@ T: git git://people.freedesktop.org/~gabbayo/linux.git S: Supported F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index 891f02c21de60..af5397c40ea34 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -73,7 +73,8 @@ amdgpu-y += \ # add amdkfd interfaces amdgpu-y += \ - amdgpu_amdkfd.o + amdgpu_amdkfd.o \ + amdgpu_amdkfd_gfx_v7.o amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 2071a9b757f74..7aa5ab09ed099 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -51,6 +51,8 @@ bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) switch (rdev->asic_type) { case CHIP_KAVERI: + kfd2kgd = amdgpu_amdkfd_gfx_7_get_functions(); + break; default: return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c new file mode 100644 index 0000000000000..2daad335b8095 --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c @@ -0,0 +1,670 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include "amdgpu.h" +#include "amdgpu_amdkfd.h" +#include "cikd.h" +#include "cik_sdma.h" +#include "amdgpu_ucode.h" +#include "gca/gfx_7_2_d.h" +#include "gca/gfx_7_2_enum.h" +#include "gca/gfx_7_2_sh_mask.h" +#include "oss/oss_2_0_d.h" +#include "oss/oss_2_0_sh_mask.h" +#include "gmc/gmc_7_1_d.h" +#include "gmc/gmc_7_1_sh_mask.h" +#include "cik_structs.h" + +#define CIK_PIPE_PER_MEC (4) + +enum { + MAX_TRAPID = 8, /* 3 bits in the bitfield. */ + MAX_WATCH_ADDRESSES = 4 +}; + +enum { + ADDRESS_WATCH_REG_ADDR_HI = 0, + ADDRESS_WATCH_REG_ADDR_LO, + ADDRESS_WATCH_REG_CNTL, + ADDRESS_WATCH_REG_MAX +}; + +/* not defined in the CI/KV reg file */ +enum { + ADDRESS_WATCH_REG_CNTL_ATC_BIT = 0x10000000UL, + ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK = 0x00FFFFFF, + ADDRESS_WATCH_REG_ADDLOW_MASK_EXTENSION = 0x03000000, + /* extend the mask to 26 bits to match the low address field */ + ADDRESS_WATCH_REG_ADDLOW_SHIFT = 6, + ADDRESS_WATCH_REG_ADDHIGH_MASK = 0xFFFF +}; + +static const uint32_t watchRegs[MAX_WATCH_ADDRESSES * ADDRESS_WATCH_REG_MAX] = { + mmTCP_WATCH0_ADDR_H, mmTCP_WATCH0_ADDR_L, mmTCP_WATCH0_CNTL, + mmTCP_WATCH1_ADDR_H, mmTCP_WATCH1_ADDR_L, mmTCP_WATCH1_CNTL, + mmTCP_WATCH2_ADDR_H, mmTCP_WATCH2_ADDR_L, mmTCP_WATCH2_CNTL, + mmTCP_WATCH3_ADDR_H, mmTCP_WATCH3_ADDR_L, mmTCP_WATCH3_CNTL +}; + +union TCP_WATCH_CNTL_BITS { + struct { + uint32_t mask:24; + uint32_t vmid:4; + uint32_t atc:1; + uint32_t mode:2; + uint32_t valid:1; + } bitfields, bits; + uint32_t u32All; + signed int i32All; + float f32All; +}; + +/* + * Register access functions + */ + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, uint32_t sh_mem_ape1_base, + uint32_t sh_mem_ape1_limit, uint32_t sh_mem_bases); + +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid); + +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr); +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id); +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr); +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd); +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id); + +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id); +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd); +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout); +static int kgd_address_watch_disable(struct kgd_dev *kgd); +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo); +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd); +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset); + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, uint8_t vmid); +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid); +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); + +static const struct kfd2kgd_calls kfd2kgd = { + .init_gtt_mem_allocation = alloc_gtt_mem, + .free_gtt_mem = free_gtt_mem, + .get_vmem_size = get_vmem_size, + .get_gpu_clock_counter = get_gpu_clock_counter, + .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, + .program_sh_mem_settings = kgd_program_sh_mem_settings, + .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, + .init_pipeline = kgd_init_pipeline, + .init_interrupts = kgd_init_interrupts, + .hqd_load = kgd_hqd_load, + .hqd_sdma_load = kgd_hqd_sdma_load, + .hqd_is_occupied = kgd_hqd_is_occupied, + .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied, + .hqd_destroy = kgd_hqd_destroy, + .hqd_sdma_destroy = kgd_hqd_sdma_destroy, + .address_watch_disable = kgd_address_watch_disable, + .address_watch_execute = kgd_address_watch_execute, + .wave_control_execute = kgd_wave_control_execute, + .address_watch_get_offset = kgd_address_watch_get_offset, + .get_atc_vmid_pasid_mapping_pasid = get_atc_vmid_pasid_mapping_pasid, + .get_atc_vmid_pasid_mapping_valid = get_atc_vmid_pasid_mapping_valid, + .write_vmid_invalidate_request = write_vmid_invalidate_request, + .get_fw_version = get_fw_version +}; + +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions() +{ + return (struct kfd2kgd_calls *)&kfd2kgd; +} + +static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd) +{ + return (struct amdgpu_device *)kgd; +} + +static void lock_srbm(struct kgd_dev *kgd, uint32_t mec, uint32_t pipe, + uint32_t queue, uint32_t vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t value = PIPEID(pipe) | MEID(mec) | VMID(vmid) | QUEUEID(queue); + + mutex_lock(&adev->srbm_mutex); + WREG32(mmSRBM_GFX_CNTL, value); +} + +static void unlock_srbm(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + WREG32(mmSRBM_GFX_CNTL, 0); + mutex_unlock(&adev->srbm_mutex); +} + +static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t queue_id) +{ + uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1; + uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, queue_id, 0); +} + +static void release_queue(struct kgd_dev *kgd) +{ + unlock_srbm(kgd); +} + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, + uint32_t sh_mem_ape1_base, + uint32_t sh_mem_ape1_limit, + uint32_t sh_mem_bases) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + lock_srbm(kgd, 0, 0, 0, vmid); + + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, sh_mem_ape1_base); + WREG32(mmSH_MEM_APE1_LIMIT, sh_mem_ape1_limit); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + + unlock_srbm(kgd); +} + +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + /* + * We have to assume that there is no outstanding mapping. + * The ATC_VMID_PASID_MAPPING_UPDATE_STATUS bit could be 0 because + * a mapping is in progress or because a mapping finished and the + * SW cleared it. So the protocol is to always wait & clear. + */ + uint32_t pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid | + ATC_VMID0_PASID_MAPPING__VALID_MASK; + + WREG32(mmATC_VMID0_PASID_MAPPING + vmid, pasid_mapping); + + while (!(RREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS) & (1U << vmid))) + cpu_relax(); + WREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid); + + /* Mapping vmid to pasid also for IH block */ + WREG32(mmIH_VMID_0_LUT + vmid, pasid_mapping); + + return 0; +} + +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + uint32_t mec = (++pipe_id / CIK_PIPE_PER_MEC) + 1; + uint32_t pipe = (pipe_id % CIK_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, 0, 0); + WREG32(mmCP_HPD_EOP_BASE_ADDR, lower_32_bits(hpd_gpu_addr >> 8)); + WREG32(mmCP_HPD_EOP_BASE_ADDR_HI, upper_32_bits(hpd_gpu_addr >> 8)); + WREG32(mmCP_HPD_EOP_VMID, 0); + WREG32(mmCP_HPD_EOP_CONTROL, hpd_size); + unlock_srbm(kgd); + + return 0; +} + +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t mec; + uint32_t pipe; + + mec = (pipe_id / CIK_PIPE_PER_MEC) + 1; + pipe = (pipe_id % CIK_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, 0, 0); + + WREG32(mmCPC_INT_CNTL, CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK | + CP_INT_CNTL_RING0__OPCODE_ERROR_INT_ENABLE_MASK); + + unlock_srbm(kgd); + + return 0; +} + +static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m) +{ + uint32_t retval; + + retval = m->sdma_engine_id * SDMA1_REGISTER_OFFSET + + m->sdma_queue_id * KFD_CIK_SDMA_QUEUE_OFFSET; + + pr_debug("kfd: sdma base address: 0x%x\n", retval); + + return retval; +} + +static inline struct cik_mqd *get_mqd(void *mqd) +{ + return (struct cik_mqd *)mqd; +} + +static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) +{ + return (struct cik_sdma_rlc_registers *)mqd; +} + +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t wptr_shadow, is_wptr_shadow_valid; + struct cik_mqd *m; + + m = get_mqd(mqd); + + is_wptr_shadow_valid = !get_user(wptr_shadow, wptr); + + acquire_queue(kgd, pipe_id, queue_id); + WREG32(mmCP_MQD_BASE_ADDR, m->cp_mqd_base_addr_lo); + WREG32(mmCP_MQD_BASE_ADDR_HI, m->cp_mqd_base_addr_hi); + WREG32(mmCP_MQD_CONTROL, m->cp_mqd_control); + + WREG32(mmCP_HQD_PQ_BASE, m->cp_hqd_pq_base_lo); + WREG32(mmCP_HQD_PQ_BASE_HI, m->cp_hqd_pq_base_hi); + WREG32(mmCP_HQD_PQ_CONTROL, m->cp_hqd_pq_control); + + WREG32(mmCP_HQD_IB_CONTROL, m->cp_hqd_ib_control); + WREG32(mmCP_HQD_IB_BASE_ADDR, m->cp_hqd_ib_base_addr_lo); + WREG32(mmCP_HQD_IB_BASE_ADDR_HI, m->cp_hqd_ib_base_addr_hi); + + WREG32(mmCP_HQD_IB_RPTR, m->cp_hqd_ib_rptr); + + WREG32(mmCP_HQD_PERSISTENT_STATE, m->cp_hqd_persistent_state); + WREG32(mmCP_HQD_SEMA_CMD, m->cp_hqd_sema_cmd); + WREG32(mmCP_HQD_MSG_TYPE, m->cp_hqd_msg_type); + + WREG32(mmCP_HQD_ATOMIC0_PREOP_LO, m->cp_hqd_atomic0_preop_lo); + WREG32(mmCP_HQD_ATOMIC0_PREOP_HI, m->cp_hqd_atomic0_preop_hi); + WREG32(mmCP_HQD_ATOMIC1_PREOP_LO, m->cp_hqd_atomic1_preop_lo); + WREG32(mmCP_HQD_ATOMIC1_PREOP_HI, m->cp_hqd_atomic1_preop_hi); + + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR, m->cp_hqd_pq_rptr_report_addr_lo); + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR_HI, + m->cp_hqd_pq_rptr_report_addr_hi); + + WREG32(mmCP_HQD_PQ_RPTR, m->cp_hqd_pq_rptr); + + WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR, m->cp_hqd_pq_wptr_poll_addr_lo); + WREG32(mmCP_HQD_PQ_WPTR_POLL_ADDR_HI, m->cp_hqd_pq_wptr_poll_addr_hi); + + WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, m->cp_hqd_pq_doorbell_control); + + WREG32(mmCP_HQD_VMID, m->cp_hqd_vmid); + + WREG32(mmCP_HQD_QUANTUM, m->cp_hqd_quantum); + + WREG32(mmCP_HQD_PIPE_PRIORITY, m->cp_hqd_pipe_priority); + WREG32(mmCP_HQD_QUEUE_PRIORITY, m->cp_hqd_queue_priority); + + WREG32(mmCP_HQD_IQ_RPTR, m->cp_hqd_iq_rptr); + + if (is_wptr_shadow_valid) + WREG32(mmCP_HQD_PQ_WPTR, wptr_shadow); + + WREG32(mmCP_HQD_ACTIVE, m->cp_hqd_active); + release_queue(kgd); + + return 0; +} + +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_VIRTUAL_ADDR, + m->sdma_rlc_virtual_addr); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, + m->sdma_rlc_rb_base); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE_HI, + m->sdma_rlc_rb_base_hi); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_LO, + m->sdma_rlc_rb_rptr_addr_lo); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR_ADDR_HI, + m->sdma_rlc_rb_rptr_addr_hi); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, + m->sdma_rlc_doorbell); + + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, + m->sdma_rlc_rb_cntl); + + return 0; +} + +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t act; + bool retval = false; + uint32_t low, high; + + acquire_queue(kgd, pipe_id, queue_id); + act = RREG32(mmCP_HQD_ACTIVE); + if (act) { + low = lower_32_bits(queue_address >> 8); + high = upper_32_bits(queue_address >> 8); + + if (low == RREG32(mmCP_HQD_PQ_BASE) && + high == RREG32(mmCP_HQD_PQ_BASE_HI)) + retval = true; + } + release_queue(kgd); + return retval; +} + +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t sdma_rlc_rb_cntl; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + sdma_rlc_rb_cntl = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + + if (sdma_rlc_rb_cntl & SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK) + return true; + + return false; +} + +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t temp; + + acquire_queue(kgd, pipe_id, queue_id); + WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, 0); + + WREG32(mmCP_HQD_DEQUEUE_REQUEST, reset_type); + + while (true) { + temp = RREG32(mmCP_HQD_ACTIVE); + if (temp & CP_HQD_ACTIVE__ACTIVE__SHIFT) + break; + if (timeout == 0) { + pr_err("kfd: cp queue preemption time out (%dms)\n", + temp); + release_queue(kgd); + return -ETIME; + } + msleep(20); + timeout -= 20; + } + + release_queue(kgd); + return 0; +} + +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t temp; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + temp = temp & ~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK; + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, temp); + + while (true) { + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS); + if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT) + break; + if (timeout == 0) + return -ETIME; + msleep(20); + timeout -= 20; + } + + WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0); + + return 0; +} + +static int kgd_address_watch_disable(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + union TCP_WATCH_CNTL_BITS cntl; + unsigned int i; + + cntl.u32All = 0; + + cntl.bitfields.valid = 0; + cntl.bitfields.mask = ADDRESS_WATCH_REG_CNTL_DEFAULT_MASK; + cntl.bitfields.atc = 1; + + /* Turning off this address until we set all the registers */ + for (i = 0; i < MAX_WATCH_ADDRESSES; i++) + WREG32(watchRegs[i * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_CNTL], cntl.u32All); + + return 0; +} + +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + union TCP_WATCH_CNTL_BITS cntl; + + cntl.u32All = cntl_val; + + /* Turning off this watch point until we set all the registers */ + cntl.bitfields.valid = 0; + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_CNTL], cntl.u32All); + + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_ADDR_HI], addr_hi); + + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_ADDR_LO], addr_lo); + + /* Enable the watch point */ + cntl.bitfields.valid = 1; + + WREG32(watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + + ADDRESS_WATCH_REG_CNTL], cntl.u32All); + + return 0; +} + +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t data; + + mutex_lock(&adev->grbm_idx_mutex); + + WREG32(mmGRBM_GFX_INDEX, gfx_index_val); + WREG32(mmSQ_CMD, sq_cmd); + + /* Restore the GRBM_GFX_INDEX register */ + + data = GRBM_GFX_INDEX__INSTANCE_BROADCAST_WRITES_MASK | + GRBM_GFX_INDEX__SH_BROADCAST_WRITES_MASK | + GRBM_GFX_INDEX__SE_BROADCAST_WRITES_MASK; + + WREG32(mmGRBM_GFX_INDEX, data); + + mutex_unlock(&adev->grbm_idx_mutex); + + return 0; +} + +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset) +{ + return watchRegs[watch_point_id * ADDRESS_WATCH_REG_MAX + reg_offset]; +} + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); +} + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + const union amdgpu_firmware_header *hdr; + + BUG_ON(kgd == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.rlc_fw->data; + break; + + case KGD_ENGINE_SDMA1: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[0].fw->data; + break; + + case KGD_ENGINE_SDMA2: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[1].fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} + diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h index d19085a970648..a3e3dfaa01a43 100644 --- a/drivers/gpu/drm/amd/amdgpu/cikd.h +++ b/drivers/gpu/drm/amd/amdgpu/cikd.h @@ -552,6 +552,12 @@ #define VCE_CMD_IB_AUTO 0x00000005 #define VCE_CMD_SEMAPHORE 0x00000006 +/* if PTR32, these are the bases for scratch and lds */ +#define PRIVATE_BASE(x) ((x) << 0) /* scratch */ +#define SHARED_BASE(x) ((x) << 16) /* LDS */ + +#define KFD_CIK_SDMA_QUEUE_OFFSET 0x200 + /* valid for both DEFAULT_MTYPE and APE1_MTYPE */ enum { MTYPE_CACHED = 0, -- GitLab From ff758a12b45b0513dbe9905deba2a29b20412138 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 7 Oct 2014 14:43:07 +0300 Subject: [PATCH 1199/7006] drm/amdgpu: Add amdgpu <--> amdkfd gfx8 interface This patch adds the gfx8 interface file between amdgpu and amdkfd. This interface file is currently in use when running on a Carrizo-based system. The interface itself is represented by a pointer to struct kfd_dev. The pointer is located inside amdgpu_device structure. All the register accesses that amdkfd need are done using this interface. This allows us to avoid direct register accesses in amdkfd proper, while also allows us to avoid locking between amdkfd and amdgpu. The single exception is the doorbells that are used in both of the drivers. However, because they are located in separate pci bar pages, the danger of sharing registers between the drivers is minimal. Having said that, we are planning to move the doorbells as well to amdgpu. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- MAINTAINERS | 2 + drivers/gpu/drm/amd/amdgpu/Makefile | 3 +- drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 3 + drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 1 + .../gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c | 543 ++++++++++++++++++ drivers/gpu/drm/amd/amdgpu/vid.h | 5 + drivers/gpu/drm/amd/include/vi_structs.h | 417 ++++++++++++++ 7 files changed, 973 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c create mode 100644 drivers/gpu/drm/amd/include/vi_structs.h diff --git a/MAINTAINERS b/MAINTAINERS index 5cc07349b5234..9c9dd5fc7affd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -639,9 +639,11 @@ S: Supported F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v7.c +F: drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c F: drivers/gpu/drm/amd/amdkfd/ F: drivers/gpu/drm/amd/include/cik_structs.h F: drivers/gpu/drm/amd/include/kgd_kfd_interface.h +F: drivers/gpu/drm/amd/include/vi_structs.h F: drivers/gpu/drm/radeon/radeon_kfd.c F: drivers/gpu/drm/radeon/radeon_kfd.h F: include/uapi/linux/kfd_ioctl.h diff --git a/drivers/gpu/drm/amd/amdgpu/Makefile b/drivers/gpu/drm/amd/amdgpu/Makefile index af5397c40ea34..908360584e4dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/Makefile +++ b/drivers/gpu/drm/amd/amdgpu/Makefile @@ -74,7 +74,8 @@ amdgpu-y += \ # add amdkfd interfaces amdgpu-y += \ amdgpu_amdkfd.o \ - amdgpu_amdkfd_gfx_v7.o + amdgpu_amdkfd_gfx_v7.o \ + amdgpu_amdkfd_gfx_v8.o amdgpu-$(CONFIG_COMPAT) += amdgpu_ioc32.o amdgpu-$(CONFIG_VGA_SWITCHEROO) += amdgpu_atpx_handler.o diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c index 7aa5ab09ed099..bc763e0c8f4c9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c @@ -53,6 +53,9 @@ bool amdgpu_amdkfd_load_interface(struct amdgpu_device *rdev) case CHIP_KAVERI: kfd2kgd = amdgpu_amdkfd_gfx_7_get_functions(); break; + case CHIP_CARRIZO: + kfd2kgd = amdgpu_amdkfd_gfx_8_0_get_functions(); + break; default: return false; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h index c81242e84abab..a8be765542e64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h @@ -50,6 +50,7 @@ void amdgpu_amdkfd_device_init(struct amdgpu_device *rdev); void amdgpu_amdkfd_device_fini(struct amdgpu_device *rdev); struct kfd2kgd_calls *amdgpu_amdkfd_gfx_7_get_functions(void); +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions(void); /* Shared API */ int alloc_gtt_mem(struct kgd_dev *kgd, size_t size, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c new file mode 100644 index 0000000000000..dfd1d503bccfe --- /dev/null +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd_gfx_v8.c @@ -0,0 +1,543 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ + +#include +#include +#include +#include +#include +#include "amdgpu.h" +#include "amdgpu_amdkfd.h" +#include "amdgpu_ucode.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "gca/gfx_8_0_d.h" +#include "gca/gfx_8_0_enum.h" +#include "oss/oss_3_0_sh_mask.h" +#include "oss/oss_3_0_d.h" +#include "gmc/gmc_8_1_sh_mask.h" +#include "gmc/gmc_8_1_d.h" +#include "vi_structs.h" +#include "vid.h" + +#define VI_PIPE_PER_MEC (4) + +struct cik_sdma_rlc_registers; + +/* + * Register access functions + */ + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, + uint32_t sh_mem_ape1_base, uint32_t sh_mem_ape1_limit, + uint32_t sh_mem_bases); +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid); +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr); +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id); +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr); +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd); +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id); +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd); +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id); +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout); +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); +static int kgd_address_watch_disable(struct kgd_dev *kgd); +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo); +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd); +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset); + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, + uint8_t vmid); +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid); +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid); +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type); + +static const struct kfd2kgd_calls kfd2kgd = { + .init_gtt_mem_allocation = alloc_gtt_mem, + .free_gtt_mem = free_gtt_mem, + .get_vmem_size = get_vmem_size, + .get_gpu_clock_counter = get_gpu_clock_counter, + .get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz, + .program_sh_mem_settings = kgd_program_sh_mem_settings, + .set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping, + .init_pipeline = kgd_init_pipeline, + .init_interrupts = kgd_init_interrupts, + .hqd_load = kgd_hqd_load, + .hqd_sdma_load = kgd_hqd_sdma_load, + .hqd_is_occupied = kgd_hqd_is_occupied, + .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied, + .hqd_destroy = kgd_hqd_destroy, + .hqd_sdma_destroy = kgd_hqd_sdma_destroy, + .address_watch_disable = kgd_address_watch_disable, + .address_watch_execute = kgd_address_watch_execute, + .wave_control_execute = kgd_wave_control_execute, + .address_watch_get_offset = kgd_address_watch_get_offset, + .get_atc_vmid_pasid_mapping_pasid = + get_atc_vmid_pasid_mapping_pasid, + .get_atc_vmid_pasid_mapping_valid = + get_atc_vmid_pasid_mapping_valid, + .write_vmid_invalidate_request = write_vmid_invalidate_request, + .get_fw_version = get_fw_version +}; + +struct kfd2kgd_calls *amdgpu_amdkfd_gfx_8_0_get_functions() +{ + return (struct kfd2kgd_calls *)&kfd2kgd; +} + +static inline struct amdgpu_device *get_amdgpu_device(struct kgd_dev *kgd) +{ + return (struct amdgpu_device *)kgd; +} + +static void lock_srbm(struct kgd_dev *kgd, uint32_t mec, uint32_t pipe, + uint32_t queue, uint32_t vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t value = PIPEID(pipe) | MEID(mec) | VMID(vmid) | QUEUEID(queue); + + mutex_lock(&adev->srbm_mutex); + WREG32(mmSRBM_GFX_CNTL, value); +} + +static void unlock_srbm(struct kgd_dev *kgd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + WREG32(mmSRBM_GFX_CNTL, 0); + mutex_unlock(&adev->srbm_mutex); +} + +static void acquire_queue(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t queue_id) +{ + uint32_t mec = (++pipe_id / VI_PIPE_PER_MEC) + 1; + uint32_t pipe = (pipe_id % VI_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, queue_id, 0); +} + +static void release_queue(struct kgd_dev *kgd) +{ + unlock_srbm(kgd); +} + +static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid, + uint32_t sh_mem_config, + uint32_t sh_mem_ape1_base, + uint32_t sh_mem_ape1_limit, + uint32_t sh_mem_bases) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + lock_srbm(kgd, 0, 0, 0, vmid); + + WREG32(mmSH_MEM_CONFIG, sh_mem_config); + WREG32(mmSH_MEM_APE1_BASE, sh_mem_ape1_base); + WREG32(mmSH_MEM_APE1_LIMIT, sh_mem_ape1_limit); + WREG32(mmSH_MEM_BASES, sh_mem_bases); + + unlock_srbm(kgd); +} + +static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid, + unsigned int vmid) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + /* + * We have to assume that there is no outstanding mapping. + * The ATC_VMID_PASID_MAPPING_UPDATE_STATUS bit could be 0 because + * a mapping is in progress or because a mapping finished + * and the SW cleared it. + * So the protocol is to always wait & clear. + */ + uint32_t pasid_mapping = (pasid == 0) ? 0 : (uint32_t)pasid | + ATC_VMID0_PASID_MAPPING__VALID_MASK; + + WREG32(mmATC_VMID0_PASID_MAPPING + vmid, pasid_mapping); + + while (!(RREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS) & (1U << vmid))) + cpu_relax(); + WREG32(mmATC_VMID_PASID_MAPPING_UPDATE_STATUS, 1U << vmid); + + /* Mapping vmid to pasid also for IH block */ + WREG32(mmIH_VMID_0_LUT + vmid, pasid_mapping); + + return 0; +} + +static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id, + uint32_t hpd_size, uint64_t hpd_gpu_addr) +{ + return 0; +} + +static int kgd_init_interrupts(struct kgd_dev *kgd, uint32_t pipe_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t mec; + uint32_t pipe; + + mec = (++pipe_id / VI_PIPE_PER_MEC) + 1; + pipe = (pipe_id % VI_PIPE_PER_MEC); + + lock_srbm(kgd, mec, pipe, 0, 0); + + WREG32(mmCPC_INT_CNTL, CP_INT_CNTL_RING0__TIME_STAMP_INT_ENABLE_MASK); + + unlock_srbm(kgd); + + return 0; +} + +static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m) +{ + return 0; +} + +static inline struct vi_mqd *get_mqd(void *mqd) +{ + return (struct vi_mqd *)mqd; +} + +static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd) +{ + return (struct cik_sdma_rlc_registers *)mqd; +} + +static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id, + uint32_t queue_id, uint32_t __user *wptr) +{ + struct vi_mqd *m; + uint32_t shadow_wptr, valid_wptr; + struct amdgpu_device *adev = get_amdgpu_device(kgd); + + m = get_mqd(mqd); + + valid_wptr = copy_from_user(&shadow_wptr, wptr, sizeof(shadow_wptr)); + acquire_queue(kgd, pipe_id, queue_id); + + WREG32(mmCP_MQD_CONTROL, m->cp_mqd_control); + WREG32(mmCP_MQD_BASE_ADDR, m->cp_mqd_base_addr_lo); + WREG32(mmCP_MQD_BASE_ADDR_HI, m->cp_mqd_base_addr_hi); + + WREG32(mmCP_HQD_VMID, m->cp_hqd_vmid); + WREG32(mmCP_HQD_PERSISTENT_STATE, m->cp_hqd_persistent_state); + WREG32(mmCP_HQD_PIPE_PRIORITY, m->cp_hqd_pipe_priority); + WREG32(mmCP_HQD_QUEUE_PRIORITY, m->cp_hqd_queue_priority); + WREG32(mmCP_HQD_QUANTUM, m->cp_hqd_quantum); + WREG32(mmCP_HQD_PQ_BASE, m->cp_hqd_pq_base_lo); + WREG32(mmCP_HQD_PQ_BASE_HI, m->cp_hqd_pq_base_hi); + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR, m->cp_hqd_pq_rptr_report_addr_lo); + WREG32(mmCP_HQD_PQ_RPTR_REPORT_ADDR_HI, + m->cp_hqd_pq_rptr_report_addr_hi); + + if (valid_wptr > 0) + WREG32(mmCP_HQD_PQ_WPTR, shadow_wptr); + + WREG32(mmCP_HQD_PQ_CONTROL, m->cp_hqd_pq_control); + WREG32(mmCP_HQD_PQ_DOORBELL_CONTROL, m->cp_hqd_pq_doorbell_control); + + WREG32(mmCP_HQD_EOP_BASE_ADDR, m->cp_hqd_eop_base_addr_lo); + WREG32(mmCP_HQD_EOP_BASE_ADDR_HI, m->cp_hqd_eop_base_addr_hi); + WREG32(mmCP_HQD_EOP_CONTROL, m->cp_hqd_eop_control); + WREG32(mmCP_HQD_EOP_RPTR, m->cp_hqd_eop_rptr); + WREG32(mmCP_HQD_EOP_WPTR, m->cp_hqd_eop_wptr); + WREG32(mmCP_HQD_EOP_EVENTS, m->cp_hqd_eop_done_events); + + WREG32(mmCP_HQD_CTX_SAVE_BASE_ADDR_LO, m->cp_hqd_ctx_save_base_addr_lo); + WREG32(mmCP_HQD_CTX_SAVE_BASE_ADDR_HI, m->cp_hqd_ctx_save_base_addr_hi); + WREG32(mmCP_HQD_CTX_SAVE_CONTROL, m->cp_hqd_ctx_save_control); + WREG32(mmCP_HQD_CNTL_STACK_OFFSET, m->cp_hqd_cntl_stack_offset); + WREG32(mmCP_HQD_CNTL_STACK_SIZE, m->cp_hqd_cntl_stack_size); + WREG32(mmCP_HQD_WG_STATE_OFFSET, m->cp_hqd_wg_state_offset); + WREG32(mmCP_HQD_CTX_SAVE_SIZE, m->cp_hqd_ctx_save_size); + + WREG32(mmCP_HQD_IB_CONTROL, m->cp_hqd_ib_control); + + WREG32(mmCP_HQD_DEQUEUE_REQUEST, m->cp_hqd_dequeue_request); + WREG32(mmCP_HQD_ERROR, m->cp_hqd_error); + WREG32(mmCP_HQD_EOP_WPTR_MEM, m->cp_hqd_eop_wptr_mem); + WREG32(mmCP_HQD_EOP_DONES, m->cp_hqd_eop_dones); + + WREG32(mmCP_HQD_ACTIVE, m->cp_hqd_active); + + release_queue(kgd); + + return 0; +} + +static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd) +{ + return 0; +} + +static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address, + uint32_t pipe_id, uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t act; + bool retval = false; + uint32_t low, high; + + acquire_queue(kgd, pipe_id, queue_id); + act = RREG32(mmCP_HQD_ACTIVE); + if (act) { + low = lower_32_bits(queue_address >> 8); + high = upper_32_bits(queue_address >> 8); + + if (low == RREG32(mmCP_HQD_PQ_BASE) && + high == RREG32(mmCP_HQD_PQ_BASE_HI)) + retval = true; + } + release_queue(kgd); + return retval; +} + +static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t sdma_rlc_rb_cntl; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + sdma_rlc_rb_cntl = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + + if (sdma_rlc_rb_cntl & SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK) + return true; + + return false; +} + +static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t temp; + + acquire_queue(kgd, pipe_id, queue_id); + + WREG32(mmCP_HQD_DEQUEUE_REQUEST, reset_type); + + while (true) { + temp = RREG32(mmCP_HQD_ACTIVE); + if (temp & CP_HQD_ACTIVE__ACTIVE_MASK) + break; + if (timeout == 0) { + pr_err("kfd: cp queue preemption time out (%dms)\n", + temp); + release_queue(kgd); + return -ETIME; + } + msleep(20); + timeout -= 20; + } + + release_queue(kgd); + return 0; +} + +static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd, + unsigned int timeout) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + struct cik_sdma_rlc_registers *m; + uint32_t sdma_base_addr; + uint32_t temp; + + m = get_sdma_mqd(mqd); + sdma_base_addr = get_sdma_base_addr(m); + + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL); + temp = temp & ~SDMA0_RLC0_RB_CNTL__RB_ENABLE_MASK; + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_CNTL, temp); + + while (true) { + temp = RREG32(sdma_base_addr + mmSDMA0_RLC0_CONTEXT_STATUS); + if (temp & SDMA0_STATUS_REG__RB_CMD_IDLE__SHIFT) + break; + if (timeout == 0) + return -ETIME; + msleep(20); + timeout -= 20; + } + + WREG32(sdma_base_addr + mmSDMA0_RLC0_DOORBELL, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_RPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_WPTR, 0); + WREG32(sdma_base_addr + mmSDMA0_RLC0_RB_BASE, 0); + + return 0; +} + +static bool get_atc_vmid_pasid_mapping_valid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static uint16_t get_atc_vmid_pasid_mapping_pasid(struct kgd_dev *kgd, + uint8_t vmid) +{ + uint32_t reg; + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + reg = RREG32(mmATC_VMID0_PASID_MAPPING + vmid); + return reg & ATC_VMID0_PASID_MAPPING__VALID_MASK; +} + +static void write_vmid_invalidate_request(struct kgd_dev *kgd, uint8_t vmid) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + + WREG32(mmVM_INVALIDATE_REQUEST, 1 << vmid); +} + +static int kgd_address_watch_disable(struct kgd_dev *kgd) +{ + return 0; +} + +static int kgd_address_watch_execute(struct kgd_dev *kgd, + unsigned int watch_point_id, + uint32_t cntl_val, + uint32_t addr_hi, + uint32_t addr_lo) +{ + return 0; +} + +static int kgd_wave_control_execute(struct kgd_dev *kgd, + uint32_t gfx_index_val, + uint32_t sq_cmd) +{ + struct amdgpu_device *adev = get_amdgpu_device(kgd); + uint32_t data = 0; + + mutex_lock(&adev->grbm_idx_mutex); + + WREG32(mmGRBM_GFX_INDEX, gfx_index_val); + WREG32(mmSQ_CMD, sq_cmd); + + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + INSTANCE_BROADCAST_WRITES, 1); + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + SH_BROADCAST_WRITES, 1); + data = REG_SET_FIELD(data, GRBM_GFX_INDEX, + SE_BROADCAST_WRITES, 1); + + WREG32(mmGRBM_GFX_INDEX, data); + mutex_unlock(&adev->grbm_idx_mutex); + + return 0; +} + +static uint32_t kgd_address_watch_get_offset(struct kgd_dev *kgd, + unsigned int watch_point_id, + unsigned int reg_offset) +{ + return 0; +} + +static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type) +{ + struct amdgpu_device *adev = (struct amdgpu_device *) kgd; + const union amdgpu_firmware_header *hdr; + + BUG_ON(kgd == NULL); + + switch (type) { + case KGD_ENGINE_PFP: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.pfp_fw->data; + break; + + case KGD_ENGINE_ME: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.me_fw->data; + break; + + case KGD_ENGINE_CE: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.ce_fw->data; + break; + + case KGD_ENGINE_MEC1: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec_fw->data; + break; + + case KGD_ENGINE_MEC2: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.mec2_fw->data; + break; + + case KGD_ENGINE_RLC: + hdr = (const union amdgpu_firmware_header *) + adev->gfx.rlc_fw->data; + break; + + case KGD_ENGINE_SDMA1: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[0].fw->data; + break; + + case KGD_ENGINE_SDMA2: + hdr = (const union amdgpu_firmware_header *) + adev->sdma[1].fw->data; + break; + + default: + return 0; + } + + if (hdr == NULL) + return 0; + + /* Only 12 bit in use*/ + return hdr->common.ucode_version; +} diff --git a/drivers/gpu/drm/amd/amdgpu/vid.h b/drivers/gpu/drm/amd/amdgpu/vid.h index 31bb89452e124..d98aa9d82fa19 100644 --- a/drivers/gpu/drm/amd/amdgpu/vid.h +++ b/drivers/gpu/drm/amd/amdgpu/vid.h @@ -66,6 +66,11 @@ #define AMDGPU_NUM_OF_VMIDS 8 +#define PIPEID(x) ((x) << 0) +#define MEID(x) ((x) << 2) +#define VMID(x) ((x) << 4) +#define QUEUEID(x) ((x) << 8) + #define RB_BITMAP_WIDTH_PER_SH 2 #define MC_SEQ_MISC0__MT__MASK 0xf0000000 diff --git a/drivers/gpu/drm/amd/include/vi_structs.h b/drivers/gpu/drm/amd/include/vi_structs.h new file mode 100644 index 0000000000000..65cfacd7a66c0 --- /dev/null +++ b/drivers/gpu/drm/amd/include/vi_structs.h @@ -0,0 +1,417 @@ +/* + * Copyright 2012 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#ifndef VI_STRUCTS_H_ +#define VI_STRUCTS_H_ + +struct vi_sdma_mqd { + uint32_t sdmax_rlcx_rb_cntl; + uint32_t sdmax_rlcx_rb_base; + uint32_t sdmax_rlcx_rb_base_hi; + uint32_t sdmax_rlcx_rb_rptr; + uint32_t sdmax_rlcx_rb_wptr; + uint32_t sdmax_rlcx_rb_wptr_poll_cntl; + uint32_t sdmax_rlcx_rb_wptr_poll_addr_hi; + uint32_t sdmax_rlcx_rb_wptr_poll_addr_lo; + uint32_t sdmax_rlcx_rb_rptr_addr_hi; + uint32_t sdmax_rlcx_rb_rptr_addr_lo; + uint32_t sdmax_rlcx_ib_cntl; + uint32_t sdmax_rlcx_ib_rptr; + uint32_t sdmax_rlcx_ib_offset; + uint32_t sdmax_rlcx_ib_base_lo; + uint32_t sdmax_rlcx_ib_base_hi; + uint32_t sdmax_rlcx_ib_size; + uint32_t sdmax_rlcx_skip_cntl; + uint32_t sdmax_rlcx_context_status; + uint32_t sdmax_rlcx_doorbell; + uint32_t sdmax_rlcx_virtual_addr; + uint32_t sdmax_rlcx_ape1_cntl; + uint32_t sdmax_rlcx_doorbell_log; + uint32_t reserved_22; + uint32_t reserved_23; + uint32_t reserved_24; + uint32_t reserved_25; + uint32_t reserved_26; + uint32_t reserved_27; + uint32_t reserved_28; + uint32_t reserved_29; + uint32_t reserved_30; + uint32_t reserved_31; + uint32_t reserved_32; + uint32_t reserved_33; + uint32_t reserved_34; + uint32_t reserved_35; + uint32_t reserved_36; + uint32_t reserved_37; + uint32_t reserved_38; + uint32_t reserved_39; + uint32_t reserved_40; + uint32_t reserved_41; + uint32_t reserved_42; + uint32_t reserved_43; + uint32_t reserved_44; + uint32_t reserved_45; + uint32_t reserved_46; + uint32_t reserved_47; + uint32_t reserved_48; + uint32_t reserved_49; + uint32_t reserved_50; + uint32_t reserved_51; + uint32_t reserved_52; + uint32_t reserved_53; + uint32_t reserved_54; + uint32_t reserved_55; + uint32_t reserved_56; + uint32_t reserved_57; + uint32_t reserved_58; + uint32_t reserved_59; + uint32_t reserved_60; + uint32_t reserved_61; + uint32_t reserved_62; + uint32_t reserved_63; + uint32_t reserved_64; + uint32_t reserved_65; + uint32_t reserved_66; + uint32_t reserved_67; + uint32_t reserved_68; + uint32_t reserved_69; + uint32_t reserved_70; + uint32_t reserved_71; + uint32_t reserved_72; + uint32_t reserved_73; + uint32_t reserved_74; + uint32_t reserved_75; + uint32_t reserved_76; + uint32_t reserved_77; + uint32_t reserved_78; + uint32_t reserved_79; + uint32_t reserved_80; + uint32_t reserved_81; + uint32_t reserved_82; + uint32_t reserved_83; + uint32_t reserved_84; + uint32_t reserved_85; + uint32_t reserved_86; + uint32_t reserved_87; + uint32_t reserved_88; + uint32_t reserved_89; + uint32_t reserved_90; + uint32_t reserved_91; + uint32_t reserved_92; + uint32_t reserved_93; + uint32_t reserved_94; + uint32_t reserved_95; + uint32_t reserved_96; + uint32_t reserved_97; + uint32_t reserved_98; + uint32_t reserved_99; + uint32_t reserved_100; + uint32_t reserved_101; + uint32_t reserved_102; + uint32_t reserved_103; + uint32_t reserved_104; + uint32_t reserved_105; + uint32_t reserved_106; + uint32_t reserved_107; + uint32_t reserved_108; + uint32_t reserved_109; + uint32_t reserved_110; + uint32_t reserved_111; + uint32_t reserved_112; + uint32_t reserved_113; + uint32_t reserved_114; + uint32_t reserved_115; + uint32_t reserved_116; + uint32_t reserved_117; + uint32_t reserved_118; + uint32_t reserved_119; + uint32_t reserved_120; + uint32_t reserved_121; + uint32_t reserved_122; + uint32_t reserved_123; + uint32_t reserved_124; + uint32_t reserved_125; + uint32_t reserved_126; + uint32_t reserved_127; +}; + +struct vi_mqd { + uint32_t header; + uint32_t compute_dispatch_initiator; + uint32_t compute_dim_x; + uint32_t compute_dim_y; + uint32_t compute_dim_z; + uint32_t compute_start_x; + uint32_t compute_start_y; + uint32_t compute_start_z; + uint32_t compute_num_thread_x; + uint32_t compute_num_thread_y; + uint32_t compute_num_thread_z; + uint32_t compute_pipelinestat_enable; + uint32_t compute_perfcount_enable; + uint32_t compute_pgm_lo; + uint32_t compute_pgm_hi; + uint32_t compute_tba_lo; + uint32_t compute_tba_hi; + uint32_t compute_tma_lo; + uint32_t compute_tma_hi; + uint32_t compute_pgm_rsrc1; + uint32_t compute_pgm_rsrc2; + uint32_t compute_vmid; + uint32_t compute_resource_limits; + uint32_t compute_static_thread_mgmt_se0; + uint32_t compute_static_thread_mgmt_se1; + uint32_t compute_tmpring_size; + uint32_t compute_static_thread_mgmt_se2; + uint32_t compute_static_thread_mgmt_se3; + uint32_t compute_restart_x; + uint32_t compute_restart_y; + uint32_t compute_restart_z; + uint32_t compute_thread_trace_enable; + uint32_t compute_misc_reserved; + uint32_t compute_dispatch_id; + uint32_t compute_threadgroup_id; + uint32_t compute_relaunch; + uint32_t compute_wave_restore_addr_lo; + uint32_t compute_wave_restore_addr_hi; + uint32_t compute_wave_restore_control; + uint32_t reserved_39; + uint32_t reserved_40; + uint32_t reserved_41; + uint32_t reserved_42; + uint32_t reserved_43; + uint32_t reserved_44; + uint32_t reserved_45; + uint32_t reserved_46; + uint32_t reserved_47; + uint32_t reserved_48; + uint32_t reserved_49; + uint32_t reserved_50; + uint32_t reserved_51; + uint32_t reserved_52; + uint32_t reserved_53; + uint32_t reserved_54; + uint32_t reserved_55; + uint32_t reserved_56; + uint32_t reserved_57; + uint32_t reserved_58; + uint32_t reserved_59; + uint32_t reserved_60; + uint32_t reserved_61; + uint32_t reserved_62; + uint32_t reserved_63; + uint32_t reserved_64; + uint32_t compute_user_data_0; + uint32_t compute_user_data_1; + uint32_t compute_user_data_2; + uint32_t compute_user_data_3; + uint32_t compute_user_data_4; + uint32_t compute_user_data_5; + uint32_t compute_user_data_6; + uint32_t compute_user_data_7; + uint32_t compute_user_data_8; + uint32_t compute_user_data_9; + uint32_t compute_user_data_10; + uint32_t compute_user_data_11; + uint32_t compute_user_data_12; + uint32_t compute_user_data_13; + uint32_t compute_user_data_14; + uint32_t compute_user_data_15; + uint32_t cp_compute_csinvoc_count_lo; + uint32_t cp_compute_csinvoc_count_hi; + uint32_t reserved_83; + uint32_t reserved_84; + uint32_t reserved_85; + uint32_t cp_mqd_query_time_lo; + uint32_t cp_mqd_query_time_hi; + uint32_t cp_mqd_connect_start_time_lo; + uint32_t cp_mqd_connect_start_time_hi; + uint32_t cp_mqd_connect_end_time_lo; + uint32_t cp_mqd_connect_end_time_hi; + uint32_t cp_mqd_connect_end_wf_count; + uint32_t cp_mqd_connect_end_pq_rptr; + uint32_t cp_mqd_connect_end_pq_wptr; + uint32_t cp_mqd_connect_end_ib_rptr; + uint32_t reserved_96; + uint32_t reserved_97; + uint32_t cp_mqd_save_start_time_lo; + uint32_t cp_mqd_save_start_time_hi; + uint32_t cp_mqd_save_end_time_lo; + uint32_t cp_mqd_save_end_time_hi; + uint32_t cp_mqd_restore_start_time_lo; + uint32_t cp_mqd_restore_start_time_hi; + uint32_t cp_mqd_restore_end_time_lo; + uint32_t cp_mqd_restore_end_time_hi; + uint32_t reserved_106; + uint32_t reserved_107; + uint32_t gds_cs_ctxsw_cnt0; + uint32_t gds_cs_ctxsw_cnt1; + uint32_t gds_cs_ctxsw_cnt2; + uint32_t gds_cs_ctxsw_cnt3; + uint32_t reserved_112; + uint32_t reserved_113; + uint32_t cp_pq_exe_status_lo; + uint32_t cp_pq_exe_status_hi; + uint32_t cp_packet_id_lo; + uint32_t cp_packet_id_hi; + uint32_t cp_packet_exe_status_lo; + uint32_t cp_packet_exe_status_hi; + uint32_t gds_save_base_addr_lo; + uint32_t gds_save_base_addr_hi; + uint32_t gds_save_mask_lo; + uint32_t gds_save_mask_hi; + uint32_t ctx_save_base_addr_lo; + uint32_t ctx_save_base_addr_hi; + uint32_t reserved_126; + uint32_t reserved_127; + uint32_t cp_mqd_base_addr_lo; + uint32_t cp_mqd_base_addr_hi; + uint32_t cp_hqd_active; + uint32_t cp_hqd_vmid; + uint32_t cp_hqd_persistent_state; + uint32_t cp_hqd_pipe_priority; + uint32_t cp_hqd_queue_priority; + uint32_t cp_hqd_quantum; + uint32_t cp_hqd_pq_base_lo; + uint32_t cp_hqd_pq_base_hi; + uint32_t cp_hqd_pq_rptr; + uint32_t cp_hqd_pq_rptr_report_addr_lo; + uint32_t cp_hqd_pq_rptr_report_addr_hi; + uint32_t cp_hqd_pq_wptr_poll_addr_lo; + uint32_t cp_hqd_pq_wptr_poll_addr_hi; + uint32_t cp_hqd_pq_doorbell_control; + uint32_t cp_hqd_pq_wptr; + uint32_t cp_hqd_pq_control; + uint32_t cp_hqd_ib_base_addr_lo; + uint32_t cp_hqd_ib_base_addr_hi; + uint32_t cp_hqd_ib_rptr; + uint32_t cp_hqd_ib_control; + uint32_t cp_hqd_iq_timer; + uint32_t cp_hqd_iq_rptr; + uint32_t cp_hqd_dequeue_request; + uint32_t cp_hqd_dma_offload; + uint32_t cp_hqd_sema_cmd; + uint32_t cp_hqd_msg_type; + uint32_t cp_hqd_atomic0_preop_lo; + uint32_t cp_hqd_atomic0_preop_hi; + uint32_t cp_hqd_atomic1_preop_lo; + uint32_t cp_hqd_atomic1_preop_hi; + uint32_t cp_hqd_hq_status0; + uint32_t cp_hqd_hq_control0; + uint32_t cp_mqd_control; + uint32_t cp_hqd_hq_status1; + uint32_t cp_hqd_hq_control1; + uint32_t cp_hqd_eop_base_addr_lo; + uint32_t cp_hqd_eop_base_addr_hi; + uint32_t cp_hqd_eop_control; + uint32_t cp_hqd_eop_rptr; + uint32_t cp_hqd_eop_wptr; + uint32_t cp_hqd_eop_done_events; + uint32_t cp_hqd_ctx_save_base_addr_lo; + uint32_t cp_hqd_ctx_save_base_addr_hi; + uint32_t cp_hqd_ctx_save_control; + uint32_t cp_hqd_cntl_stack_offset; + uint32_t cp_hqd_cntl_stack_size; + uint32_t cp_hqd_wg_state_offset; + uint32_t cp_hqd_ctx_save_size; + uint32_t cp_hqd_gds_resource_state; + uint32_t cp_hqd_error; + uint32_t cp_hqd_eop_wptr_mem; + uint32_t cp_hqd_eop_dones; + uint32_t reserved_182; + uint32_t reserved_183; + uint32_t reserved_184; + uint32_t reserved_185; + uint32_t reserved_186; + uint32_t reserved_187; + uint32_t reserved_188; + uint32_t reserved_189; + uint32_t reserved_190; + uint32_t reserved_191; + uint32_t iqtimer_pkt_header; + uint32_t iqtimer_pkt_dw0; + uint32_t iqtimer_pkt_dw1; + uint32_t iqtimer_pkt_dw2; + uint32_t iqtimer_pkt_dw3; + uint32_t iqtimer_pkt_dw4; + uint32_t iqtimer_pkt_dw5; + uint32_t iqtimer_pkt_dw6; + uint32_t iqtimer_pkt_dw7; + uint32_t iqtimer_pkt_dw8; + uint32_t iqtimer_pkt_dw9; + uint32_t iqtimer_pkt_dw10; + uint32_t iqtimer_pkt_dw11; + uint32_t iqtimer_pkt_dw12; + uint32_t iqtimer_pkt_dw13; + uint32_t iqtimer_pkt_dw14; + uint32_t iqtimer_pkt_dw15; + uint32_t iqtimer_pkt_dw16; + uint32_t iqtimer_pkt_dw17; + uint32_t iqtimer_pkt_dw18; + uint32_t iqtimer_pkt_dw19; + uint32_t iqtimer_pkt_dw20; + uint32_t iqtimer_pkt_dw21; + uint32_t iqtimer_pkt_dw22; + uint32_t iqtimer_pkt_dw23; + uint32_t iqtimer_pkt_dw24; + uint32_t iqtimer_pkt_dw25; + uint32_t iqtimer_pkt_dw26; + uint32_t iqtimer_pkt_dw27; + uint32_t iqtimer_pkt_dw28; + uint32_t iqtimer_pkt_dw29; + uint32_t iqtimer_pkt_dw30; + uint32_t iqtimer_pkt_dw31; + uint32_t reserved_225; + uint32_t reserved_226; + uint32_t reserved_227; + uint32_t set_resources_header; + uint32_t set_resources_dw1; + uint32_t set_resources_dw2; + uint32_t set_resources_dw3; + uint32_t set_resources_dw4; + uint32_t set_resources_dw5; + uint32_t set_resources_dw6; + uint32_t set_resources_dw7; + uint32_t reserved_236; + uint32_t reserved_237; + uint32_t reserved_238; + uint32_t reserved_239; + uint32_t queue_doorbell_id0; + uint32_t queue_doorbell_id1; + uint32_t queue_doorbell_id2; + uint32_t queue_doorbell_id3; + uint32_t queue_doorbell_id4; + uint32_t queue_doorbell_id5; + uint32_t queue_doorbell_id6; + uint32_t queue_doorbell_id7; + uint32_t queue_doorbell_id8; + uint32_t queue_doorbell_id9; + uint32_t queue_doorbell_id10; + uint32_t queue_doorbell_id11; + uint32_t queue_doorbell_id12; + uint32_t queue_doorbell_id13; + uint32_t queue_doorbell_id14; + uint32_t queue_doorbell_id15; +}; + +#endif /* VI_STRUCTS_H_ */ -- GitLab From bd72a72c3a0d3e188b08cdbbc54eb083d860e365 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Fri, 21 Nov 2014 23:27:30 +0200 Subject: [PATCH 1200/7006] drm/amdkfd: Add dependency of DRM_AMDGPU to Kconfig Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/Kconfig b/drivers/gpu/drm/amd/amdkfd/Kconfig index 8dfac37ff3272..e13c67c8d2c0e 100644 --- a/drivers/gpu/drm/amd/amdkfd/Kconfig +++ b/drivers/gpu/drm/amd/amdkfd/Kconfig @@ -4,6 +4,6 @@ config HSA_AMD tristate "HSA kernel driver for AMD GPU devices" - depends on DRM_RADEON && AMD_IOMMU_V2 && X86_64 + depends on (DRM_RADEON || DRM_AMDGPU) && AMD_IOMMU_V2 && X86_64 help Enable this if you want to use HSA features on AMD GPU devices. -- GitLab From 123576d1440df7bfa6e2188784e8cd9dc01eea6b Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:37:24 +0200 Subject: [PATCH 1201/7006] drm/amdkfd: add supported CZ devices PCI IDs to amdkfd This patch adds the PCI IDs of supported CZ devices to the supported_devices structure in amdkfd. That structure is used during the amdkfd probing stage, to check if the currently probed device is eligible to be handled by amdkfd. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_device.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c index 75312c82969f3..3f95f7cb40194 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c @@ -80,7 +80,12 @@ static const struct kfd_deviceid supported_devices[] = { { 0x1318, &kaveri_device_info }, /* Kaveri */ { 0x131B, &kaveri_device_info }, /* Kaveri */ { 0x131C, &kaveri_device_info }, /* Kaveri */ - { 0x131D, &kaveri_device_info } /* Kaveri */ + { 0x131D, &kaveri_device_info }, /* Kaveri */ + { 0x9870, &carrizo_device_info }, /* Carrizo */ + { 0x9874, &carrizo_device_info }, /* Carrizo */ + { 0x9875, &carrizo_device_info }, /* Carrizo */ + { 0x9876, &carrizo_device_info }, /* Carrizo */ + { 0x9877, &carrizo_device_info } /* Carrizo */ }; static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size, -- GitLab From 2d8f1f330356f4e22cbf860af78d715715595041 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 4 Jan 2015 10:48:26 +0200 Subject: [PATCH 1202/7006] drm/amdkfd: add CP HWS packet headers for VI Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- .../gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h | 398 ++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h new file mode 100644 index 0000000000000..08c721922812b --- /dev/null +++ b/drivers/gpu/drm/amd/amdkfd/kfd_pm4_headers_vi.h @@ -0,0 +1,398 @@ +/* + * Copyright 2014 Advanced Micro Devices, Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + * + */ + +#ifndef F32_MES_PM4_PACKETS_H +#define F32_MES_PM4_PACKETS_H + +#ifndef PM4_MES_HEADER_DEFINED +#define PM4_MES_HEADER_DEFINED +union PM4_MES_TYPE_3_HEADER { + struct { + uint32_t reserved1 : 8; /* < reserved */ + uint32_t opcode : 8; /* < IT opcode */ + uint32_t count : 14;/* < number of DWORDs - 1 in the + information body. */ + uint32_t type : 2; /* < packet identifier. + It should be 3 for type 3 packets */ + }; + uint32_t u32All; +}; +#endif /* PM4_MES_HEADER_DEFINED */ + +/*--------------------MES_SET_RESOURCES--------------------*/ + +#ifndef PM4_MES_SET_RESOURCES_DEFINED +#define PM4_MES_SET_RESOURCES_DEFINED +enum mes_set_resources_queue_type_enum { + queue_type__mes_set_resources__kernel_interface_queue_kiq = 0, + queue_type__mes_set_resources__hsa_interface_queue_hiq = 1, + queue_type__mes_set_resources__hsa_debug_interface_queue = 4 +}; + + +struct pm4_mes_set_resources { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t vmid_mask:16; + uint32_t unmap_latency:8; + uint32_t reserved1:5; + enum mes_set_resources_queue_type_enum queue_type:3; + } bitfields2; + uint32_t ordinal2; + }; + + uint32_t queue_mask_lo; + uint32_t queue_mask_hi; + uint32_t gws_mask_lo; + uint32_t gws_mask_hi; + + union { + struct { + uint32_t oac_mask:16; + uint32_t reserved2:16; + } bitfields7; + uint32_t ordinal7; + }; + + union { + struct { + uint32_t gds_heap_base:6; + uint32_t reserved3:5; + uint32_t gds_heap_size:6; + uint32_t reserved4:15; + } bitfields8; + uint32_t ordinal8; + }; + +}; +#endif + +/*--------------------MES_RUN_LIST--------------------*/ + +#ifndef PM4_MES_RUN_LIST_DEFINED +#define PM4_MES_RUN_LIST_DEFINED + +struct pm4_mes_runlist { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t reserved1:2; + uint32_t ib_base_lo:30; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t ib_base_hi:16; + uint32_t reserved2:16; + } bitfields3; + uint32_t ordinal3; + }; + + union { + struct { + uint32_t ib_size:20; + uint32_t chain:1; + uint32_t offload_polling:1; + uint32_t reserved3:1; + uint32_t valid:1; + uint32_t reserved4:8; + } bitfields4; + uint32_t ordinal4; + }; + +}; +#endif + +/*--------------------MES_MAP_PROCESS--------------------*/ + +#ifndef PM4_MES_MAP_PROCESS_DEFINED +#define PM4_MES_MAP_PROCESS_DEFINED + +struct pm4_mes_map_process { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t pasid:16; + uint32_t reserved1:8; + uint32_t diq_enable:1; + uint32_t process_quantum:7; + } bitfields2; + uint32_t ordinal2; +}; + + union { + struct { + uint32_t page_table_base:28; + uint32_t reserved2:4; + } bitfields3; + uint32_t ordinal3; + }; + + uint32_t sh_mem_bases; + uint32_t sh_mem_ape1_base; + uint32_t sh_mem_ape1_limit; + uint32_t sh_mem_config; + uint32_t gds_addr_lo; + uint32_t gds_addr_hi; + + union { + struct { + uint32_t num_gws:6; + uint32_t reserved3:2; + uint32_t num_oac:4; + uint32_t reserved4:4; + uint32_t gds_size:6; + uint32_t num_queues:10; + } bitfields10; + uint32_t ordinal10; + }; + +}; +#endif + +/*--------------------MES_MAP_QUEUES--------------------*/ + +#ifndef PM4_MES_MAP_QUEUES_VI_DEFINED +#define PM4_MES_MAP_QUEUES_VI_DEFINED +enum mes_map_queues_queue_sel_vi_enum { + queue_sel__mes_map_queues__map_to_specified_queue_slots_vi = 0, +queue_sel__mes_map_queues__map_to_hws_determined_queue_slots_vi = 1 +}; + +enum mes_map_queues_queue_type_vi_enum { + queue_type__mes_map_queues__normal_compute_vi = 0, + queue_type__mes_map_queues__debug_interface_queue_vi = 1, + queue_type__mes_map_queues__normal_latency_static_queue_vi = 2, +queue_type__mes_map_queues__low_latency_static_queue_vi = 3 +}; + +enum mes_map_queues_alloc_format_vi_enum { + alloc_format__mes_map_queues__one_per_pipe_vi = 0, +alloc_format__mes_map_queues__all_on_one_pipe_vi = 1 +}; + +enum mes_map_queues_engine_sel_vi_enum { + engine_sel__mes_map_queues__compute_vi = 0, + engine_sel__mes_map_queues__sdma0_vi = 2, + engine_sel__mes_map_queues__sdma1_vi = 3 +}; + + +struct pm4_mes_map_queues { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t reserved1:4; + enum mes_map_queues_queue_sel_vi_enum queue_sel:2; + uint32_t reserved2:15; + enum mes_map_queues_queue_type_vi_enum queue_type:3; + enum mes_map_queues_alloc_format_vi_enum alloc_format:2; + enum mes_map_queues_engine_sel_vi_enum engine_sel:3; + uint32_t num_queues:3; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t reserved3:1; + uint32_t check_disable:1; + uint32_t doorbell_offset:21; + uint32_t reserved4:3; + uint32_t queue:6; + } bitfields3; + uint32_t ordinal3; + }; + + uint32_t mqd_addr_lo; + uint32_t mqd_addr_hi; + uint32_t wptr_addr_lo; + uint32_t wptr_addr_hi; +}; +#endif + +/*--------------------MES_QUERY_STATUS--------------------*/ + +#ifndef PM4_MES_QUERY_STATUS_DEFINED +#define PM4_MES_QUERY_STATUS_DEFINED +enum mes_query_status_interrupt_sel_enum { + interrupt_sel__mes_query_status__completion_status = 0, + interrupt_sel__mes_query_status__process_status = 1, + interrupt_sel__mes_query_status__queue_status = 2 +}; + +enum mes_query_status_command_enum { + command__mes_query_status__interrupt_only = 0, + command__mes_query_status__fence_only_immediate = 1, + command__mes_query_status__fence_only_after_write_ack = 2, + command__mes_query_status__fence_wait_for_write_ack_send_interrupt = 3 +}; + +enum mes_query_status_engine_sel_enum { + engine_sel__mes_query_status__compute = 0, + engine_sel__mes_query_status__sdma0_queue = 2, + engine_sel__mes_query_status__sdma1_queue = 3 +}; + +struct pm4_mes_query_status { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + uint32_t context_id:28; + enum mes_query_status_interrupt_sel_enum + interrupt_sel:2; + enum mes_query_status_command_enum command:2; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t pasid:16; + uint32_t reserved1:16; + } bitfields3a; + struct { + uint32_t reserved2:2; + uint32_t doorbell_offset:21; + uint32_t reserved3:2; + enum mes_query_status_engine_sel_enum engine_sel:3; + uint32_t reserved4:4; + } bitfields3b; + uint32_t ordinal3; + }; + + uint32_t addr_lo; + uint32_t addr_hi; + uint32_t data_lo; + uint32_t data_hi; +}; +#endif + +/*--------------------MES_UNMAP_QUEUES--------------------*/ + +#ifndef PM4_MES_UNMAP_QUEUES_DEFINED +#define PM4_MES_UNMAP_QUEUES_DEFINED +enum mes_unmap_queues_action_enum { + action__mes_unmap_queues__preempt_queues = 0, + action__mes_unmap_queues__reset_queues = 1, + action__mes_unmap_queues__disable_process_queues = 2, + action__mes_unmap_queues__reserved = 3 +}; + +enum mes_unmap_queues_queue_sel_enum { + queue_sel__mes_unmap_queues__perform_request_on_specified_queues = 0, + queue_sel__mes_unmap_queues__perform_request_on_pasid_queues = 1, + queue_sel__mes_unmap_queues__unmap_all_queues = 2, + queue_sel__mes_unmap_queues__unmap_all_non_static_queues = 3 +}; + +enum mes_unmap_queues_engine_sel_enum { + engine_sel__mes_unmap_queues__compute = 0, + engine_sel__mes_unmap_queues__sdma0 = 2, + engine_sel__mes_unmap_queues__sdmal = 3 +}; + +struct PM4_MES_UNMAP_QUEUES { + union { + union PM4_MES_TYPE_3_HEADER header; /* header */ + uint32_t ordinal1; + }; + + union { + struct { + enum mes_unmap_queues_action_enum action:2; + uint32_t reserved1:2; + enum mes_unmap_queues_queue_sel_enum queue_sel:2; + uint32_t reserved2:20; + enum mes_unmap_queues_engine_sel_enum engine_sel:3; + uint32_t num_queues:3; + } bitfields2; + uint32_t ordinal2; + }; + + union { + struct { + uint32_t pasid:16; + uint32_t reserved3:16; + } bitfields3a; + struct { + uint32_t reserved4:2; + uint32_t doorbell_offset0:21; + uint32_t reserved5:9; + } bitfields3b; + uint32_t ordinal3; + }; + + union { + struct { + uint32_t reserved6:2; + uint32_t doorbell_offset1:21; + uint32_t reserved7:9; + } bitfields4; + uint32_t ordinal4; + }; + + union { + struct { + uint32_t reserved8:2; + uint32_t doorbell_offset2:21; + uint32_t reserved9:9; + } bitfields5; + uint32_t ordinal5; + }; + + union { + struct { + uint32_t reserved10:2; + uint32_t doorbell_offset3:21; + uint32_t reserved11:9; + } bitfields6; + uint32_t ordinal6; + }; +}; +#endif + +#endif -- GitLab From d696d536f0a97ac779d6176107ac4e96d0a2f8b9 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:26:10 +0200 Subject: [PATCH 1203/7006] drm/amdkfd: add support for VI in MQD manager This patch implements all the VI MQD manager functions. This is done in a different file as the MQD format is different between CI and VI Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/Makefile | 3 +- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c | 249 +++++++++++++++++- 2 files changed, 248 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile index 28551153ec6d0..7fc9b0f444cbb 100644 --- a/drivers/gpu/drm/amd/amdkfd/Makefile +++ b/drivers/gpu/drm/amd/amdkfd/Makefile @@ -2,7 +2,8 @@ # Makefile for Heterogenous System Architecture support for AMD GPU devices # -ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/ +ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/ \ + -Idrivers/gpu/drm/amd/include/asic_reg amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \ kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \ diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c index b3a7e3ba1e380..fa32c32fa1c2b 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c @@ -22,12 +22,255 @@ */ #include +#include #include "kfd_priv.h" #include "kfd_mqd_manager.h" +#include "vi_structs.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "gca/gfx_8_0_enum.h" + +#define CP_MQD_CONTROL__PRIV_STATE__SHIFT 0x8 + +static inline struct vi_mqd *get_mqd(void *mqd) +{ + return (struct vi_mqd *)mqd; +} + +static int init_mqd(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + int retval; + uint64_t addr; + struct vi_mqd *m; + + retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct vi_mqd), + mqd_mem_obj); + if (retval != 0) + return -ENOMEM; + + m = (struct vi_mqd *) (*mqd_mem_obj)->cpu_ptr; + addr = (*mqd_mem_obj)->gpu_addr; + + memset(m, 0, sizeof(struct vi_mqd)); + + m->header = 0xC0310800; + m->compute_pipelinestat_enable = 1; + m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF; + m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF; + + m->cp_hqd_persistent_state = CP_HQD_PERSISTENT_STATE__PRELOAD_REQ_MASK | + 0x53 << CP_HQD_PERSISTENT_STATE__PRELOAD_SIZE__SHIFT; + + m->cp_mqd_control = 1 << CP_MQD_CONTROL__PRIV_STATE__SHIFT | + MTYPE_UC << CP_MQD_CONTROL__MTYPE__SHIFT; + + m->cp_mqd_base_addr_lo = lower_32_bits(addr); + m->cp_mqd_base_addr_hi = upper_32_bits(addr); + + m->cp_hqd_quantum = 1 << CP_HQD_QUANTUM__QUANTUM_EN__SHIFT | + 1 << CP_HQD_QUANTUM__QUANTUM_SCALE__SHIFT | + 10 << CP_HQD_QUANTUM__QUANTUM_DURATION__SHIFT; + + m->cp_hqd_pipe_priority = 1; + m->cp_hqd_queue_priority = 15; + + m->cp_hqd_eop_rptr = 1 << CP_HQD_EOP_RPTR__INIT_FETCHER__SHIFT; + + if (q->format == KFD_QUEUE_FORMAT_AQL) + m->cp_hqd_iq_rptr = 1; + + *mqd = m; + if (gart_addr != NULL) + *gart_addr = addr; + retval = mm->update_mqd(mm, m, q); + + return retval; +} + +static int load_mqd(struct mqd_manager *mm, void *mqd, + uint32_t pipe_id, uint32_t queue_id, + uint32_t __user *wptr) +{ + return mm->dev->kfd2kgd->hqd_load + (mm->dev->kgd, mqd, pipe_id, queue_id, wptr); +} + +static int __update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q, unsigned int mtype, + unsigned int atc_bit) +{ + struct vi_mqd *m; + + BUG_ON(!mm || !q || !mqd); + + pr_debug("kfd: In func %s\n", __func__); + + m = get_mqd(mqd); + + m->cp_hqd_pq_control = 5 << CP_HQD_PQ_CONTROL__RPTR_BLOCK_SIZE__SHIFT | + atc_bit << CP_HQD_PQ_CONTROL__PQ_ATC__SHIFT | + mtype << CP_HQD_PQ_CONTROL__MTYPE__SHIFT; + m->cp_hqd_pq_control |= + ffs(q->queue_size / sizeof(unsigned int)) - 1 - 1; + pr_debug("kfd: cp_hqd_pq_control 0x%x\n", m->cp_hqd_pq_control); + + m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8); + m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8); + + m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr); + m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr); + + m->cp_hqd_pq_doorbell_control = + 1 << CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_EN__SHIFT | + q->doorbell_off << + CP_HQD_PQ_DOORBELL_CONTROL__DOORBELL_OFFSET__SHIFT; + pr_debug("kfd: cp_hqd_pq_doorbell_control 0x%x\n", + m->cp_hqd_pq_doorbell_control); + + m->cp_hqd_eop_control = atc_bit << CP_HQD_EOP_CONTROL__EOP_ATC__SHIFT | + mtype << CP_HQD_EOP_CONTROL__MTYPE__SHIFT; + + m->cp_hqd_ib_control = atc_bit << CP_HQD_IB_CONTROL__IB_ATC__SHIFT | + 3 << CP_HQD_IB_CONTROL__MIN_IB_AVAIL_SIZE__SHIFT | + mtype << CP_HQD_IB_CONTROL__MTYPE__SHIFT; + + m->cp_hqd_eop_control |= + ffs(q->eop_ring_buffer_size / sizeof(unsigned int)) - 1 - 1; + m->cp_hqd_eop_base_addr_lo = + lower_32_bits(q->eop_ring_buffer_address >> 8); + m->cp_hqd_eop_base_addr_hi = + upper_32_bits(q->eop_ring_buffer_address >> 8); + + m->cp_hqd_iq_timer = atc_bit << CP_HQD_IQ_TIMER__IQ_ATC__SHIFT | + mtype << CP_HQD_IQ_TIMER__MTYPE__SHIFT; + + m->cp_hqd_vmid = q->vmid; + + if (q->format == KFD_QUEUE_FORMAT_AQL) { + m->cp_hqd_pq_control |= CP_HQD_PQ_CONTROL__NO_UPDATE_RPTR_MASK | + 2 << CP_HQD_PQ_CONTROL__SLOT_BASED_WPTR__SHIFT; + } + + m->cp_hqd_active = 0; + q->is_active = false; + if (q->queue_size > 0 && + q->queue_address != 0 && + q->queue_percent > 0) { + m->cp_hqd_active = 1; + q->is_active = true; + } + + return 0; +} + + +static int update_mqd(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + return __update_mqd(mm, mqd, q, MTYPE_CC, 1); +} + +static int destroy_mqd(struct mqd_manager *mm, void *mqd, + enum kfd_preempt_type type, + unsigned int timeout, uint32_t pipe_id, + uint32_t queue_id) +{ + return mm->dev->kfd2kgd->hqd_destroy + (mm->dev->kgd, type, timeout, + pipe_id, queue_id); +} + +static void uninit_mqd(struct mqd_manager *mm, void *mqd, + struct kfd_mem_obj *mqd_mem_obj) +{ + BUG_ON(!mm || !mqd); + kfd_gtt_sa_free(mm->dev, mqd_mem_obj); +} + +static bool is_occupied(struct mqd_manager *mm, void *mqd, + uint64_t queue_address, uint32_t pipe_id, + uint32_t queue_id) +{ + return mm->dev->kfd2kgd->hqd_is_occupied( + mm->dev->kgd, queue_address, + pipe_id, queue_id); +} + +static int init_mqd_hiq(struct mqd_manager *mm, void **mqd, + struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr, + struct queue_properties *q) +{ + struct vi_mqd *m; + int retval = init_mqd(mm, mqd, mqd_mem_obj, gart_addr, q); + + if (retval != 0) + return retval; + + m = get_mqd(*mqd); + + m->cp_hqd_pq_control |= 1 << CP_HQD_PQ_CONTROL__PRIV_STATE__SHIFT | + 1 << CP_HQD_PQ_CONTROL__KMD_QUEUE__SHIFT; + + return retval; +} + +static int update_mqd_hiq(struct mqd_manager *mm, void *mqd, + struct queue_properties *q) +{ + struct vi_mqd *m; + int retval = __update_mqd(mm, mqd, q, MTYPE_UC, 0); + + if (retval != 0) + return retval; + + m = get_mqd(mqd); + m->cp_hqd_vmid = q->vmid; + return retval; +} struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type, - struct kfd_dev *dev) + struct kfd_dev *dev) { - pr_warn("amdkfd: VI MQD is not currently supported\n"); - return NULL; + struct mqd_manager *mqd; + + BUG_ON(!dev); + BUG_ON(type >= KFD_MQD_TYPE_MAX); + + pr_debug("kfd: In func %s\n", __func__); + + mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL); + if (!mqd) + return NULL; + + mqd->dev = dev; + + switch (type) { + case KFD_MQD_TYPE_CP: + case KFD_MQD_TYPE_COMPUTE: + mqd->init_mqd = init_mqd; + mqd->uninit_mqd = uninit_mqd; + mqd->load_mqd = load_mqd; + mqd->update_mqd = update_mqd; + mqd->destroy_mqd = destroy_mqd; + mqd->is_occupied = is_occupied; + break; + case KFD_MQD_TYPE_HIQ: + mqd->init_mqd = init_mqd_hiq; + mqd->uninit_mqd = uninit_mqd; + mqd->load_mqd = load_mqd; + mqd->update_mqd = update_mqd_hiq; + mqd->destroy_mqd = destroy_mqd; + mqd->is_occupied = is_occupied; + break; + case KFD_MQD_TYPE_SDMA: + break; + default: + kfree(mqd); + return NULL; + } + + return mqd; } -- GitLab From 914bea6329b2cbbb3586a11f90ddf026bef44348 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Mon, 12 Jan 2015 14:28:46 +0200 Subject: [PATCH 1204/7006] drm/amdkfd: Add support for VI in DQM This patch adds support for the VI APU in the DQM module. Most of the functionality of DQM is shared between CI and VI. Therefore, only a handful of functions are required to be in the H/W-specific part of DQM. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- .../amd/amdkfd/kfd_device_queue_manager_vi.c | 103 +++++++++++++++++- 1 file changed, 99 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c index 4c15212a38996..44c38e8e54d30 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c @@ -22,6 +22,10 @@ */ #include "kfd_device_queue_manager.h" +#include "gca/gfx_8_0_enum.h" +#include "gca/gfx_8_0_sh_mask.h" +#include "gca/gfx_8_0_enum.h" +#include "oss/oss_3_0_sh_mask.h" static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd, @@ -37,14 +41,40 @@ static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, void device_queue_manager_init_vi(struct device_queue_manager_asic_ops *ops) { - pr_warn("amdkfd: VI DQM is not currently supported\n"); - ops->set_cache_memory_policy = set_cache_memory_policy_vi; ops->register_process = register_process_vi; ops->initialize = initialize_cpsch_vi; ops->init_sdma_vm = init_sdma_vm; } +static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble) +{ + /* In 64-bit mode, we can only control the top 3 bits of the LDS, + * scratch and GPUVM apertures. + * The hardware fills in the remaining 59 bits according to the + * following pattern: + * LDS: X0000000'00000000 - X0000001'00000000 (4GB) + * Scratch: X0000001'00000000 - X0000002'00000000 (4GB) + * GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB) + * + * (where X/Y is the configurable nybble with the low-bit 0) + * + * LDS and scratch will have the same top nybble programmed in the + * top 3 bits of SH_MEM_BASES.PRIVATE_BASE. + * GPUVM can have a different top nybble programmed in the + * top 3 bits of SH_MEM_BASES.SHARED_BASE. + * We don't bother to support different top nybbles + * for LDS/Scratch and GPUVM. + */ + + BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE || + top_address_nybble == 0); + + return top_address_nybble << 12 | + (top_address_nybble << 12) << + SH_MEM_BASES__SHARED_BASE__SHIFT; +} + static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd, enum cache_policy default_policy, @@ -52,18 +82,83 @@ static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm, void __user *alternate_aperture_base, uint64_t alternate_aperture_size) { - return false; + uint32_t default_mtype; + uint32_t ape1_mtype; + + default_mtype = (default_policy == cache_policy_coherent) ? + MTYPE_CC : + MTYPE_NC; + + ape1_mtype = (alternate_policy == cache_policy_coherent) ? + MTYPE_CC : + MTYPE_NC; + + qpd->sh_mem_config = (qpd->sh_mem_config & + SH_MEM_CONFIG__ADDRESS_MODE_MASK) | + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + default_mtype << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + ape1_mtype << SH_MEM_CONFIG__APE1_MTYPE__SHIFT | + SH_MEM_CONFIG__PRIVATE_ATC_MASK; + + return true; } static int register_process_vi(struct device_queue_manager *dqm, struct qcm_process_device *qpd) { - return -1; + struct kfd_process_device *pdd; + unsigned int temp; + + BUG_ON(!dqm || !qpd); + + pdd = qpd_to_pdd(qpd); + + /* check if sh_mem_config register already configured */ + if (qpd->sh_mem_config == 0) { + qpd->sh_mem_config = + SH_MEM_ALIGNMENT_MODE_UNALIGNED << + SH_MEM_CONFIG__ALIGNMENT_MODE__SHIFT | + MTYPE_CC << SH_MEM_CONFIG__DEFAULT_MTYPE__SHIFT | + MTYPE_CC << SH_MEM_CONFIG__APE1_MTYPE__SHIFT | + SH_MEM_CONFIG__PRIVATE_ATC_MASK; + + qpd->sh_mem_ape1_limit = 0; + qpd->sh_mem_ape1_base = 0; + } + + if (qpd->pqm->process->is_32bit_user_mode) { + temp = get_sh_mem_bases_32(pdd); + qpd->sh_mem_bases = temp << SH_MEM_BASES__SHARED_BASE__SHIFT; + qpd->sh_mem_config |= SH_MEM_ADDRESS_MODE_HSA32 << + SH_MEM_CONFIG__ADDRESS_MODE__SHIFT; + } else { + temp = get_sh_mem_bases_nybble_64(pdd); + qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp); + qpd->sh_mem_config |= SH_MEM_ADDRESS_MODE_HSA64 << + SH_MEM_CONFIG__ADDRESS_MODE__SHIFT; + } + + pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n", + qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases); + + return 0; } static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { + uint32_t value = (1 << SDMA0_RLC0_VIRTUAL_ADDR__ATC__SHIFT); + + if (q->process->is_32bit_user_mode) + value |= (1 << SDMA0_RLC0_VIRTUAL_ADDR__PTR32__SHIFT) | + get_sh_mem_bases_32(qpd_to_pdd(qpd)); + else + value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) && + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; + + q->properties.sdma_vm_addr = value; } static int initialize_cpsch_vi(struct device_queue_manager *dqm) -- GitLab From e1940fa4bfa32d86a771e300a3fd116c46878bf4 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 6 Jan 2015 11:32:13 +0200 Subject: [PATCH 1205/7006] drm/amdkfd: fix runlist length calculation The MAP_QUEUES packet length for Carrizo is different than for Kaveri. Therefore, we now need to calculate the runlist length with regard to the underlying H/W. Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index 99b6d28a11c3e..e3230ccc46c7d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -27,6 +27,7 @@ #include "kfd_kernel_queue.h" #include "kfd_priv.h" #include "kfd_pm4_headers.h" +#include "kfd_pm4_headers_vi.h" #include "kfd_pm4_opcodes.h" static inline void inc_wptr(unsigned int *wptr, unsigned int increment_bytes, @@ -55,6 +56,7 @@ static void pm_calc_rlib_size(struct packet_manager *pm, bool *over_subscription) { unsigned int process_count, queue_count; + unsigned int map_queue_size; BUG_ON(!pm || !rlib_size || !over_subscription); @@ -69,9 +71,13 @@ static void pm_calc_rlib_size(struct packet_manager *pm, pr_debug("kfd: over subscribed runlist\n"); } + map_queue_size = + (pm->dqm->dev->device_info->asic_family == CHIP_CARRIZO) ? + sizeof(struct pm4_mes_map_queues) : + sizeof(struct pm4_map_queues); /* calculate run list ib allocation size */ *rlib_size = process_count * sizeof(struct pm4_map_process) + - queue_count * sizeof(struct pm4_map_queues); + queue_count * map_queue_size; /* * Increase the allocation size in case we need a chained run list -- GitLab From d7b8f73ea03923dbf7c61093743b9eb1842fa8d7 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Tue, 6 Jan 2015 11:35:50 +0200 Subject: [PATCH 1206/7006] drm/amdkfd: Implement create_map_queues() for Carrizo Signed-off-by: Ben Goz Signed-off-by: Oded Gabbay --- .../gpu/drm/amd/amdkfd/kfd_packet_manager.c | 91 ++++++++++++++++++- 1 file changed, 87 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c index e3230ccc46c7d..90f391434fa39 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c @@ -182,6 +182,71 @@ static int pm_create_map_process(struct packet_manager *pm, uint32_t *buffer, return 0; } +static int pm_create_map_queue_vi(struct packet_manager *pm, uint32_t *buffer, + struct queue *q, bool is_static) +{ + struct pm4_mes_map_queues *packet; + bool use_static = is_static; + + BUG_ON(!pm || !buffer || !q); + + pr_debug("kfd: In func %s\n", __func__); + + packet = (struct pm4_mes_map_queues *)buffer; + memset(buffer, 0, sizeof(struct pm4_map_queues)); + + packet->header.u32all = build_pm4_header(IT_MAP_QUEUES, + sizeof(struct pm4_map_queues)); + packet->bitfields2.alloc_format = + alloc_format__mes_map_queues__one_per_pipe_vi; + packet->bitfields2.num_queues = 1; + packet->bitfields2.queue_sel = + queue_sel__mes_map_queues__map_to_hws_determined_queue_slots_vi; + + packet->bitfields2.engine_sel = + engine_sel__mes_map_queues__compute_vi; + packet->bitfields2.queue_type = + queue_type__mes_map_queues__normal_compute_vi; + + switch (q->properties.type) { + case KFD_QUEUE_TYPE_COMPUTE: + if (use_static) + packet->bitfields2.queue_type = + queue_type__mes_map_queues__normal_latency_static_queue_vi; + break; + case KFD_QUEUE_TYPE_DIQ: + packet->bitfields2.queue_type = + queue_type__mes_map_queues__debug_interface_queue_vi; + break; + case KFD_QUEUE_TYPE_SDMA: + packet->bitfields2.engine_sel = + engine_sel__mes_map_queues__sdma0_vi; + use_static = false; /* no static queues under SDMA */ + break; + default: + pr_err("kfd: in %s queue type %d\n", __func__, + q->properties.type); + BUG(); + break; + } + packet->bitfields3.doorbell_offset = + q->properties.doorbell_off; + + packet->mqd_addr_lo = + lower_32_bits(q->gart_mqd_addr); + + packet->mqd_addr_hi = + upper_32_bits(q->gart_mqd_addr); + + packet->wptr_addr_lo = + lower_32_bits((uint64_t)q->properties.write_ptr); + + packet->wptr_addr_hi = + upper_32_bits((uint64_t)q->properties.write_ptr); + + return 0; +} + static int pm_create_map_queue(struct packet_manager *pm, uint32_t *buffer, struct queue *q, bool is_static) { @@ -298,8 +363,17 @@ static int pm_create_runlist_ib(struct packet_manager *pm, pr_debug("kfd: static_queue, mapping kernel q %d, is debug status %d\n", kq->queue->queue, qpd->is_debug); - retval = pm_create_map_queue(pm, &rl_buffer[rl_wptr], - kq->queue, qpd->is_debug); + if (pm->dqm->dev->device_info->asic_family == + CHIP_CARRIZO) + retval = pm_create_map_queue_vi(pm, + &rl_buffer[rl_wptr], + kq->queue, + qpd->is_debug); + else + retval = pm_create_map_queue(pm, + &rl_buffer[rl_wptr], + kq->queue, + qpd->is_debug); if (retval != 0) return retval; @@ -315,8 +389,17 @@ static int pm_create_runlist_ib(struct packet_manager *pm, pr_debug("kfd: static_queue, mapping user queue %d, is debug status %d\n", q->queue, qpd->is_debug); - retval = pm_create_map_queue(pm, &rl_buffer[rl_wptr], - q, qpd->is_debug); + if (pm->dqm->dev->device_info->asic_family == + CHIP_CARRIZO) + retval = pm_create_map_queue_vi(pm, + &rl_buffer[rl_wptr], + q, + qpd->is_debug); + else + retval = pm_create_map_queue(pm, + &rl_buffer[rl_wptr], + q, + qpd->is_debug); if (retval != 0) return retval; -- GitLab From 3d30b28be811b0d7c0a113eab361d5e3029d6da4 Mon Sep 17 00:00:00 2001 From: Oded Gabbay Date: Sat, 6 Jun 2015 21:47:01 +0300 Subject: [PATCH 1207/7006] drm/amdkfd: Use generic defines in new amd headers This patch makes use of the new amd headers (that are part of the new amdgpu driver), instead of private defines. Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/cik_regs.h | 11 ---------- .../amd/amdkfd/kfd_device_queue_manager_cik.c | 12 +++++++---- .../gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c | 20 ++++++++++++------- 3 files changed, 21 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h index 183be5b8414fd..48769d12dd7be 100644 --- a/drivers/gpu/drm/amd/amdkfd/cik_regs.h +++ b/drivers/gpu/drm/amd/amdkfd/cik_regs.h @@ -65,17 +65,6 @@ #define AQL_ENABLE 1 -#define SDMA_RB_VMID(x) (x << 24) -#define SDMA_RB_ENABLE (1 << 0) -#define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */ -#define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12) -#define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */ -#define SDMA_OFFSET(x) (x << 0) -#define SDMA_DB_ENABLE (1 << 28) -#define SDMA_ATC (1 << 0) -#define SDMA_VA_PTR32 (1 << 4) -#define SDMA_VA_SHARED_BASE(x) (x << 8) - #define GRBM_GFX_INDEX 0x30800 #define ATC_VMID_PASID_MAPPING_VALID (1U << 31) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c index 9ce8a20a7aff0..23ce774ff09d3 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c @@ -23,6 +23,7 @@ #include "kfd_device_queue_manager.h" #include "cik_regs.h" +#include "oss/oss_2_4_sh_mask.h" static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm, struct qcm_process_device *qpd, @@ -135,13 +136,16 @@ static int register_process_cik(struct device_queue_manager *dqm, static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q, struct qcm_process_device *qpd) { - uint32_t value = SDMA_ATC; + uint32_t value = (1 << SDMA0_RLC0_VIRTUAL_ADDR__ATC__SHIFT); if (q->process->is_32bit_user_mode) - value |= SDMA_VA_PTR32 | get_sh_mem_bases_32(qpd_to_pdd(qpd)); + value |= (1 << SDMA0_RLC0_VIRTUAL_ADDR__PTR32__SHIFT) | + get_sh_mem_bases_32(qpd_to_pdd(qpd)); else - value |= SDMA_VA_SHARED_BASE(get_sh_mem_bases_nybble_64( - qpd_to_pdd(qpd))); + value |= ((get_sh_mem_bases_nybble_64(qpd_to_pdd(qpd))) << + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE__SHIFT) && + SDMA0_RLC0_VIRTUAL_ADDR__SHARED_BASE_MASK; + q->properties.sdma_vm_addr = value; } diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c index 434979428fc01..d83de985e88cf 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c @@ -27,6 +27,7 @@ #include "kfd_mqd_manager.h" #include "cik_regs.h" #include "cik_structs.h" +#include "oss/oss_2_4_sh_mask.h" static inline struct cik_mqd *get_mqd(void *mqd) { @@ -214,17 +215,20 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, BUG_ON(!mm || !mqd || !q); m = get_sdma_mqd(mqd); - m->sdma_rlc_rb_cntl = - SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) | - SDMA_RB_VMID(q->vmid) | - SDMA_RPTR_WRITEBACK_ENABLE | - SDMA_RPTR_WRITEBACK_TIMER(6); + m->sdma_rlc_rb_cntl = ffs(q->queue_size / sizeof(unsigned int)) << + SDMA0_RLC0_RB_CNTL__RB_SIZE__SHIFT | + q->vmid << SDMA0_RLC0_RB_CNTL__RB_VMID__SHIFT | + 1 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_ENABLE__SHIFT | + 6 << SDMA0_RLC0_RB_CNTL__RPTR_WRITEBACK_TIMER__SHIFT; m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8); m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8); m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr); m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr); - m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE; + m->sdma_rlc_doorbell = q->doorbell_off << + SDMA0_RLC0_DOORBELL__OFFSET__SHIFT | + 1 << SDMA0_RLC0_DOORBELL__ENABLE__SHIFT; + m->sdma_rlc_virtual_addr = q->sdma_vm_addr; m->sdma_engine_id = q->sdma_engine_id; @@ -234,7 +238,9 @@ static int update_mqd_sdma(struct mqd_manager *mm, void *mqd, if (q->queue_size > 0 && q->queue_address != 0 && q->queue_percent > 0) { - m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE; + m->sdma_rlc_rb_cntl |= + 1 << SDMA0_RLC0_RB_CNTL__RB_ENABLE__SHIFT; + q->is_active = true; } -- GitLab From 7639a8c420f04ca9be87974416efb2848b0962d9 Mon Sep 17 00:00:00 2001 From: Ben Goz Date: Sun, 7 Jun 2015 00:15:51 +0300 Subject: [PATCH 1208/7006] drm/amdkfd: Set correct doorbell packet type for Carrizo Signed-off-by: Ben Goz Reviewed-by: Yair Shachar Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_topology.c | 5 +++++ drivers/gpu/drm/amd/amdkfd/kfd_topology.h | 1 + 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c index c25728bc388a2..74909e72a0092 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c @@ -1186,6 +1186,11 @@ int kfd_topology_add_device(struct kfd_dev *gpu) * TODO: Retrieve max engine clock values from KGD */ + if (dev->gpu->device_info->asic_family == CHIP_CARRIZO) { + dev->node_props.capability |= HSA_CAP_DOORBELL_PACKET_TYPE; + pr_info("amdkfd: adding doorbell packet type capability\n"); + } + res = 0; err: diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h index 989624b3cd148..c3ddb9b95ff8d 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.h +++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.h @@ -40,6 +40,7 @@ #define HSA_CAP_WATCH_POINTS_TOTALBITS_MASK 0x00000f00 #define HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT 8 #define HSA_CAP_RESERVED 0xfffff000 +#define HSA_CAP_DOORBELL_PACKET_TYPE 0x00001000 struct kfd_node_properties { uint32_t cpu_cores_count; -- GitLab From e317fa505dcdfa25f0e4c888f991eb7fd1562e1e Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Sat, 18 Jul 2015 10:21:14 -0500 Subject: [PATCH 1209/7006] netfilter: Fix memory leak in nf_register_net_hook In the rare case that when it is a attempted to use a per network device netfilter hook and the network device does not exist the newly allocated structure can leak. Be a good citizen and free the newly allocated structure in the error handling code. Fixes: 085db2c04557 ("netfilter: Per network namespace netfilter hooks.") Reported-by: kbuild@01.org Reported-by: Dan Carpenter Signed-off-by: "Eric W. Biederman" Signed-off-by: Pablo Neira Ayuso --- net/netfilter/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 6896cee8b7334..87d237d20870f 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -96,8 +96,10 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) new->priority = reg->priority; nf_hook_list = find_nf_hook_list(net, reg); - if (!nf_hook_list) + if (!nf_hook_list) { + kfree(new); return -ENOENT; + } mutex_lock(&nf_hook_mutex); list_for_each_entry(elem, nf_hook_list, list) { -- GitLab From 5c31252c4a86dc591c23f1a951edd52ad791ef0e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Jul 2015 10:21:47 +0200 Subject: [PATCH 1210/7006] pwm: Add the pwm_is_enabled() helper Some PWM drivers are testing the PWMF_ENABLED flag. Create a helper function to hide the logic behind enabled test. This will allow us to smoothly move from the current approach to an atomic PWM update approach. Signed-off-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/core.c | 4 ++-- drivers/pwm/pwm-atmel-tcb.c | 2 +- drivers/pwm/pwm-atmel.c | 6 +++--- drivers/pwm/pwm-bcm-kona.c | 4 ++-- drivers/pwm/pwm-ep93xx.c | 4 ++-- drivers/pwm/pwm-imx.c | 2 +- drivers/pwm/pwm-mxs.c | 4 ++-- drivers/pwm/pwm-renesas-tpu.c | 2 +- drivers/pwm/pwm-tegra.c | 6 +++--- drivers/pwm/pwm-tiecap.c | 10 +++++----- drivers/pwm/pwm-tiehrpwm.c | 6 +++--- drivers/pwm/sysfs.c | 2 +- include/linux/pwm.h | 5 +++++ 13 files changed, 31 insertions(+), 26 deletions(-) diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c index 3a7769fe53dee..f7c11d2dec371 100644 --- a/drivers/pwm/core.c +++ b/drivers/pwm/core.c @@ -455,7 +455,7 @@ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity) if (!pwm->chip->ops->set_polarity) return -ENOSYS; - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) return -EBUSY; err = pwm->chip->ops->set_polarity(pwm->chip, pwm, polarity); @@ -853,7 +853,7 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s) if (test_bit(PWMF_REQUESTED, &pwm->flags)) seq_puts(s, " requested"); - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) seq_puts(s, " enabled"); seq_puts(s, "\n"); diff --git a/drivers/pwm/pwm-atmel-tcb.c b/drivers/pwm/pwm-atmel-tcb.c index d14e0677c92dd..6da01b3bf6f46 100644 --- a/drivers/pwm/pwm-atmel-tcb.c +++ b/drivers/pwm/pwm-atmel-tcb.c @@ -347,7 +347,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, tcbpwm->duty = duty; /* If the PWM is enabled, call enable to apply the new conf */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) atmel_tcb_pwm_enable(chip, pwm); return 0; diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index a947c9095d9d6..b3b294de88e0a 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -114,7 +114,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u32 val; int ret; - if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) { + if (pwm_is_enabled(pwm) && (period_ns != pwm->period)) { dev_err(chip->dev, "cannot change PWM period while enabled\n"); return -EBUSY; } @@ -176,7 +176,7 @@ static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM channel is enabled, only update CDTY by using the update * register, it needs to set bit 10 of CMR to 0 */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) return; /* * If the PWM channel is disabled, write value to duty and period @@ -191,7 +191,7 @@ static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm, { struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip); - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { /* * If the PWM channel is enabled, using the duty update register * to update the value. diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index 7af8fea2dc5b3..dfdcf88279ae1 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -134,7 +134,7 @@ static int kona_pwmc_config(struct pwm_chip *chip, struct pwm_device *pwm, } /* If the PWM channel is enabled, write the settings to the HW */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { value = readl(kp->base + PRESCALE_OFFSET); value &= ~PRESCALE_MASK(chan); value |= prescale << PRESCALE_SHIFT(chan); @@ -287,7 +287,7 @@ static int kona_pwmc_remove(struct platform_device *pdev) unsigned int chan; for (chan = 0; chan < kp->chip.npwm; chan++) - if (test_bit(PWMF_ENABLED, &kp->chip.pwms[chan].flags)) + if (pwm_is_enabled(&kp->chip.pwms[chan])) clk_disable_unprepare(kp->clk); return pwmchip_remove(&kp->chip); diff --git a/drivers/pwm/pwm-ep93xx.c b/drivers/pwm/pwm-ep93xx.c index e593e9c45c51c..bbf10ae02f0ec 100644 --- a/drivers/pwm/pwm-ep93xx.c +++ b/drivers/pwm/pwm-ep93xx.c @@ -82,7 +82,7 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * The clock needs to be enabled to access the PWM registers. * Configuration can be changed at any time. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { ret = clk_enable(ep93xx_pwm->clk); if (ret) return ret; @@ -113,7 +113,7 @@ static int ep93xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, ret = -EINVAL; } - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) clk_disable(ep93xx_pwm->clk); return ret; diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 66d6f0c5c421c..008dc646225e6 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -114,7 +114,7 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, unsigned long long c; unsigned long period_cycles, duty_cycles, prescale; unsigned int period_ms; - bool enable = test_bit(PWMF_ENABLED, &pwm->flags); + bool enable = pwm_is_enabled(pwm); int wait_count = 0, fifoav; u32 cr, sr; diff --git a/drivers/pwm/pwm-mxs.c b/drivers/pwm/pwm-mxs.c index b430811e14f58..9a596324ebef8 100644 --- a/drivers/pwm/pwm-mxs.c +++ b/drivers/pwm/pwm-mxs.c @@ -77,7 +77,7 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM channel is disabled, make sure to turn on the clock * before writing the register. Otherwise, keep it enabled. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { ret = clk_prepare_enable(mxs->clk); if (ret) return ret; @@ -92,7 +92,7 @@ static int mxs_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * If the PWM is not enabled, turn the clock off again to save power. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) clk_disable_unprepare(mxs->clk); return 0; diff --git a/drivers/pwm/pwm-renesas-tpu.c b/drivers/pwm/pwm-renesas-tpu.c index ee63f9e9d0fb7..075c1a764ba29 100644 --- a/drivers/pwm/pwm-renesas-tpu.c +++ b/drivers/pwm/pwm-renesas-tpu.c @@ -301,7 +301,7 @@ static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm, pwm->duty = duty; /* If the channel is disabled we're done. */ - if (!test_bit(PWMF_ENABLED, &_pwm->flags)) + if (!pwm_is_enabled(_pwm)) return 0; if (duty_only && pwm->timer_on) { diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c index cabd7d8e05cc0..d4de0607b502a 100644 --- a/drivers/pwm/pwm-tegra.c +++ b/drivers/pwm/pwm-tegra.c @@ -112,7 +112,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, * If the PWM channel is disabled, make sure to turn on the clock * before writing the register. Otherwise, keep it enabled. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { err = clk_prepare_enable(pc->clk); if (err < 0) return err; @@ -124,7 +124,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, /* * If the PWM is not enabled, turn the clock off again to save power. */ - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) clk_disable_unprepare(pc->clk); return 0; @@ -214,7 +214,7 @@ static int tegra_pwm_remove(struct platform_device *pdev) for (i = 0; i < NUM_PWM; i++) { struct pwm_device *pwm = &pc->chip.pwms[i]; - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) if (clk_prepare_enable(pc->clk) < 0) continue; diff --git a/drivers/pwm/pwm-tiecap.c b/drivers/pwm/pwm-tiecap.c index e557befdf4e65..616af764a2768 100644 --- a/drivers/pwm/pwm-tiecap.c +++ b/drivers/pwm/pwm-tiecap.c @@ -97,7 +97,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, writew(reg_val, pc->mmio_base + ECCTL2); - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { /* Update active registers if not running */ writel(duty_cycles, pc->mmio_base + CAP2); writel(period_cycles, pc->mmio_base + CAP1); @@ -111,7 +111,7 @@ static int ecap_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, writel(period_cycles, pc->mmio_base + CAP3); } - if (!test_bit(PWMF_ENABLED, &pwm->flags)) { + if (!pwm_is_enabled(pwm)) { reg_val = readw(pc->mmio_base + ECCTL2); /* Disable APWM mode to put APWM output Low */ reg_val &= ~ECCTL2_APWM_MODE; @@ -179,7 +179,7 @@ static void ecap_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) static void ecap_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { dev_warn(chip->dev, "Removing PWM device without disabling\n"); pm_runtime_put_sync(chip->dev); } @@ -306,7 +306,7 @@ static int ecap_pwm_suspend(struct device *dev) ecap_pwm_save_context(pc); /* Disable explicitly if PWM is running */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) pm_runtime_put_sync(dev); return 0; @@ -318,7 +318,7 @@ static int ecap_pwm_resume(struct device *dev) struct pwm_device *pwm = pc->chip.pwms; /* Enable explicitly if PWM was running */ - if (test_bit(PWMF_ENABLED, &pwm->flags)) + if (pwm_is_enabled(pwm)) pm_runtime_get_sync(dev); ecap_pwm_restore_context(pc); diff --git a/drivers/pwm/pwm-tiehrpwm.c b/drivers/pwm/pwm-tiehrpwm.c index 694b3cf7694be..6a41e66015b67 100644 --- a/drivers/pwm/pwm-tiehrpwm.c +++ b/drivers/pwm/pwm-tiehrpwm.c @@ -407,7 +407,7 @@ static void ehrpwm_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) { struct ehrpwm_pwm_chip *pc = to_ehrpwm_pwm_chip(chip); - if (test_bit(PWMF_ENABLED, &pwm->flags)) { + if (pwm_is_enabled(pwm)) { dev_warn(chip->dev, "Removing PWM device without disabling\n"); pm_runtime_put_sync(chip->dev); } @@ -565,7 +565,7 @@ static int ehrpwm_pwm_suspend(struct device *dev) for (i = 0; i < pc->chip.npwm; i++) { struct pwm_device *pwm = &pc->chip.pwms[i]; - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) continue; /* Disable explicitly if PWM is running */ @@ -582,7 +582,7 @@ static int ehrpwm_pwm_resume(struct device *dev) for (i = 0; i < pc->chip.npwm; i++) { struct pwm_device *pwm = &pc->chip.pwms[i]; - if (!test_bit(PWMF_ENABLED, &pwm->flags)) + if (!pwm_is_enabled(pwm)) continue; /* Enable explicitly if PWM was running */ diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index 4bd0c639e16da..eecf21d681082 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -97,7 +97,7 @@ static ssize_t pwm_enable_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); - int enabled = test_bit(PWMF_ENABLED, &pwm->flags); + int enabled = pwm_is_enabled(pwm); return sprintf(buf, "%d\n", enabled); } diff --git a/include/linux/pwm.h b/include/linux/pwm.h index 36262d08a9dad..ec34f4d9a9eec 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -92,6 +92,11 @@ struct pwm_device { enum pwm_polarity polarity; }; +static inline bool pwm_is_enabled(const struct pwm_device *pwm) +{ + return test_bit(PWMF_ENABLED, &pwm->flags); +} + static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period) { if (pwm) -- GitLab From a1cf42171a2e3c33cbc12bb037795caf0589149b Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Jul 2015 10:21:48 +0200 Subject: [PATCH 1211/7006] pwm: Constify PWM device where possible The PWM argument is not modified in PWM property accessors, make it a const argument so that the accessors can be used from sysfs. Signed-off-by: Boris Brezillon Signed-off-by: Thierry Reding --- include/linux/pwm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index ec34f4d9a9eec..d8f691339a450 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -103,7 +103,7 @@ static inline void pwm_set_period(struct pwm_device *pwm, unsigned int period) pwm->period = period; } -static inline unsigned int pwm_get_period(struct pwm_device *pwm) +static inline unsigned int pwm_get_period(const struct pwm_device *pwm) { return pwm ? pwm->period : 0; } @@ -114,7 +114,7 @@ static inline void pwm_set_duty_cycle(struct pwm_device *pwm, unsigned int duty) pwm->duty_cycle = duty; } -static inline unsigned int pwm_get_duty_cycle(struct pwm_device *pwm) +static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm) { return pwm ? pwm->duty_cycle : 0; } -- GitLab From 011e76314818b6a24d5347b2d83b8a577e6aaae6 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Jul 2015 10:21:49 +0200 Subject: [PATCH 1212/7006] pwm: Add pwm_get_polarity() helper function Some drivers are directly accessing the ->polarity field in pwm_device. Add a helper to retrieve the current polarity so that we can easily move this field elsewhere (required to support atomic update). Signed-off-by: Boris Brezillon Signed-off-by: Thierry Reding --- include/linux/pwm.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/pwm.h b/include/linux/pwm.h index d8f691339a450..6f286df300218 100644 --- a/include/linux/pwm.h +++ b/include/linux/pwm.h @@ -124,6 +124,11 @@ static inline unsigned int pwm_get_duty_cycle(const struct pwm_device *pwm) */ int pwm_set_polarity(struct pwm_device *pwm, enum pwm_polarity polarity); +static inline enum pwm_polarity pwm_get_polarity(const struct pwm_device *pwm) +{ + return pwm ? pwm->polarity : PWM_POLARITY_NORMAL; +} + /** * struct pwm_ops - PWM controller operations * @request: optional hook for requesting a PWM -- GitLab From 15da7b5001e498fa7dc619d4d7951f9665b071e4 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Wed, 1 Jul 2015 10:21:50 +0200 Subject: [PATCH 1213/7006] pwm: Make use of pwm_get_xxx() helpers where appropriate Use the pwm_get_xxx() helpers instead of directly accessing the fields in struct pwm_device. This will allow us to smoothly move to the atomic update approach. Signed-off-by: Boris Brezillon Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel.c | 2 +- drivers/pwm/pwm-bcm-kona.c | 3 ++- drivers/pwm/pwm-imx.c | 3 ++- drivers/pwm/pwm-rockchip.c | 2 +- drivers/pwm/sysfs.c | 11 ++++++----- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c index b3b294de88e0a..0e4bd4e8e5823 100644 --- a/drivers/pwm/pwm-atmel.c +++ b/drivers/pwm/pwm-atmel.c @@ -114,7 +114,7 @@ static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, u32 val; int ret; - if (pwm_is_enabled(pwm) && (period_ns != pwm->period)) { + if (pwm_is_enabled(pwm) && (period_ns != pwm_get_period(pwm))) { dev_err(chip->dev, "cannot change PWM period while enabled\n"); return -EBUSY; } diff --git a/drivers/pwm/pwm-bcm-kona.c b/drivers/pwm/pwm-bcm-kona.c index dfdcf88279ae1..920cd1b5aa9d6 100644 --- a/drivers/pwm/pwm-bcm-kona.c +++ b/drivers/pwm/pwm-bcm-kona.c @@ -194,7 +194,8 @@ static int kona_pwmc_enable(struct pwm_chip *chip, struct pwm_device *pwm) return ret; } - ret = kona_pwmc_config(chip, pwm, pwm->duty_cycle, pwm->period); + ret = kona_pwmc_config(chip, pwm, pwm_get_duty_cycle(pwm), + pwm_get_period(pwm)); if (ret < 0) { clk_disable_unprepare(kp->clk); return ret; diff --git a/drivers/pwm/pwm-imx.c b/drivers/pwm/pwm-imx.c index 008dc646225e6..d600fd5cd4bac 100644 --- a/drivers/pwm/pwm-imx.c +++ b/drivers/pwm/pwm-imx.c @@ -129,7 +129,8 @@ static int imx_pwm_config_v2(struct pwm_chip *chip, sr = readl(imx->mmio_base + MX3_PWMSR); fifoav = sr & MX3_PWMSR_FIFOAV_MASK; if (fifoav == MX3_PWMSR_FIFOAV_4WORDS) { - period_ms = DIV_ROUND_UP(pwm->period, NSEC_PER_MSEC); + period_ms = DIV_ROUND_UP(pwm_get_period(pwm), + NSEC_PER_MSEC); msleep(period_ms); sr = readl(imx->mmio_base + MX3_PWMSR); diff --git a/drivers/pwm/pwm-rockchip.c b/drivers/pwm/pwm-rockchip.c index 9442df2441017..7d9cc90495223 100644 --- a/drivers/pwm/pwm-rockchip.c +++ b/drivers/pwm/pwm-rockchip.c @@ -83,7 +83,7 @@ static void rockchip_pwm_set_enable_v2(struct pwm_chip *chip, PWM_CONTINUOUS; u32 val; - if (pwm->polarity == PWM_POLARITY_INVERSED) + if (pwm_get_polarity(pwm) == PWM_POLARITY_INVERSED) enable_conf |= PWM_DUTY_NEGATIVE | PWM_INACTIVE_POSITIVE; else enable_conf |= PWM_DUTY_POSITIVE | PWM_INACTIVE_NEGATIVE; diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index eecf21d681082..ac0abecfbaa01 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -46,7 +46,7 @@ static ssize_t pwm_period_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); - return sprintf(buf, "%u\n", pwm->period); + return sprintf(buf, "%u\n", pwm_get_period(pwm)); } static ssize_t pwm_period_store(struct device *child, @@ -61,7 +61,7 @@ static ssize_t pwm_period_store(struct device *child, if (ret) return ret; - ret = pwm_config(pwm, pwm->duty_cycle, val); + ret = pwm_config(pwm, pwm_get_duty_cycle(pwm), val); return ret ? : size; } @@ -72,7 +72,7 @@ static ssize_t pwm_duty_cycle_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); - return sprintf(buf, "%u\n", pwm->duty_cycle); + return sprintf(buf, "%u\n", pwm_get_duty_cycle(pwm)); } static ssize_t pwm_duty_cycle_store(struct device *child, @@ -87,7 +87,7 @@ static ssize_t pwm_duty_cycle_store(struct device *child, if (ret) return ret; - ret = pwm_config(pwm, val, pwm->period); + ret = pwm_config(pwm, val, pwm_get_period(pwm)); return ret ? : size; } @@ -134,7 +134,8 @@ static ssize_t pwm_polarity_show(struct device *child, { const struct pwm_device *pwm = child_to_pwm_device(child); - return sprintf(buf, "%s\n", pwm->polarity ? "inversed" : "normal"); + return sprintf(buf, "%s\n", + pwm_get_polarity(pwm) ? "inversed" : "normal"); } static ssize_t pwm_polarity_store(struct device *child, -- GitLab From dd92d8de833613993b337cb4ff853587e1600aef Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 20 Jul 2015 10:58:21 +0200 Subject: [PATCH 1214/7006] Partially revert "drm/i915: s/mdelay/msleep/" in ilk rps code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6adfb1ef106bfe4b5ecb8bd75c4d037741d28a48. Ironlake RPS code runs under an irqsave spinlock and hence sleeping isn't allowed. Not a this long delay while blocking irqs isn't great at all, but fixing the locking scheme is a lot more involved. So just revert for now. Cc: Ville Syrjälä Reported-by: kernel test robot Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0d3e01434860f..a1d92b7f3e356 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -4266,7 +4266,7 @@ static void ironlake_enable_drps(struct drm_device *dev) if (wait_for_atomic((I915_READ(MEMSWCTL) & MEMCTL_CMD_STS) == 0, 10)) DRM_ERROR("stuck trying to change perf mode\n"); - msleep(1); + mdelay(1); ironlake_set_drps(dev, fstart); @@ -4297,10 +4297,10 @@ static void ironlake_disable_drps(struct drm_device *dev) /* Go back to the starting frequency */ ironlake_set_drps(dev, dev_priv->ips.fstart); - msleep(1); + mdelay(1); rgvswctl |= MEMCTL_CMD_STS; I915_WRITE(MEMSWCTL, rgvswctl); - msleep(1); + mdelay(1); spin_unlock_irq(&mchdev_lock); } -- GitLab From 767f509ca11269c2bcd92e3972a93096f2173ac0 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Mon, 29 Jun 2015 23:26:01 -0700 Subject: [PATCH 1215/7006] futex: Enhance comments in futex_lock_pi() for blocking paths ... serves a bit better to clarify between blocking and non-blocking code paths. Signed-off-by: Davidlohr Bueso Cc: Peter Zijlstra Cc: Darren Hart Cc: Davidlohr Bueso Link: http://lkml.kernel.org/r/1435645562-975-2-git-send-email-dave@stgolabs.net Signed-off-by: Thomas Gleixner --- kernel/futex.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/kernel/futex.c b/kernel/futex.c index c4a182f5357eb..153eb22b0fc07 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -2268,8 +2268,11 @@ static long futex_wait_restart(struct restart_block *restart) /* * Userspace tried a 0 -> TID atomic transition of the futex value * and failed. The kernel side here does the whole locking operation: - * if there are waiters then it will block, it does PI, etc. (Due to - * races the kernel might see a 0 value of the futex too.) + * if there are waiters then it will block as a consequence of relying + * on rt-mutexes, it does PI, etc. (Due to races the kernel might see + * a 0 value of the futex too.). + * + * Also serves as futex trylock_pi()'ing, and due semantics. */ static int futex_lock_pi(u32 __user *uaddr, unsigned int flags, ktime_t *time, int trylock) @@ -2300,6 +2303,10 @@ retry_private: ret = futex_lock_pi_atomic(uaddr, hb, &q.key, &q.pi_state, current, 0); if (unlikely(ret)) { + /* + * Atomic work succeeded and we got the lock, + * or failed. Either way, we do _not_ block. + */ switch (ret) { case 1: /* We got the lock. */ -- GitLab From ab51fbab39d864f3223e44a2600fd951df261f0b Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Mon, 29 Jun 2015 23:26:02 -0700 Subject: [PATCH 1216/7006] futex: Fault/error injection capabilities Although futexes are well known for being a royal pita, we really have very little debugging capabilities - except for relying on tglx's eye half the time. By simply making use of the existing fault-injection machinery, we can improve this situation, allowing generating artificial uaddress faults and deadlock scenarios. Of course, when this is disabled in production systems, the overhead for failure checks is practically zero -- so this is very cheap at the same time. Future work would be nice to now enhance trinity to make use of this. There is a special tunable 'ignore-private', which can filter out private futexes. Given the tsk->make_it_fail filter and this option, pi futexes can be narrowed down pretty closely. Signed-off-by: Davidlohr Bueso Cc: Peter Zijlstra Cc: Darren Hart Cc: Davidlohr Bueso Link: http://lkml.kernel.org/r/1435645562-975-3-git-send-email-dave@stgolabs.net Signed-off-by: Thomas Gleixner --- .../fault-injection/fault-injection.txt | 11 +++ kernel/futex.c | 89 ++++++++++++++++++- lib/Kconfig.debug | 7 ++ 3 files changed, 105 insertions(+), 2 deletions(-) diff --git a/Documentation/fault-injection/fault-injection.txt b/Documentation/fault-injection/fault-injection.txt index 4cf1a2a6bd725..415484f3d59a2 100644 --- a/Documentation/fault-injection/fault-injection.txt +++ b/Documentation/fault-injection/fault-injection.txt @@ -15,6 +15,10 @@ o fail_page_alloc injects page allocation failures. (alloc_pages(), get_free_pages(), ...) +o fail_futex + + injects futex deadlock and uaddr fault errors. + o fail_make_request injects disk IO errors on devices permitted by setting @@ -113,6 +117,12 @@ configuration of fault-injection capabilities. specifies the minimum page allocation order to be injected failures. +- /sys/kernel/debug/fail_futex/ignore-private: + + Format: { 'Y' | 'N' } + default is 'N', setting it to 'Y' will disable failure injections + when dealing with private (address space) futexes. + o Boot option In order to inject faults while debugfs is not available (early boot time), @@ -121,6 +131,7 @@ use the boot option: failslab= fail_page_alloc= fail_make_request= + fail_futex= mmc_core.fail_request=,,, How to add new fault injection capability diff --git a/kernel/futex.c b/kernel/futex.c index 153eb22b0fc07..6ea31bb703c95 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -64,6 +64,7 @@ #include #include #include +#include #include @@ -258,6 +259,66 @@ static unsigned long __read_mostly futex_hashsize; static struct futex_hash_bucket *futex_queues; +/* + * Fault injections for futexes. + */ +#ifdef CONFIG_FAIL_FUTEX + +static struct { + struct fault_attr attr; + + u32 ignore_private; +} fail_futex = { + .attr = FAULT_ATTR_INITIALIZER, + .ignore_private = 0, +}; + +static int __init setup_fail_futex(char *str) +{ + return setup_fault_attr(&fail_futex.attr, str); +} +__setup("fail_futex=", setup_fail_futex); + +bool should_fail_futex(bool fshared) +{ + if (fail_futex.ignore_private && !fshared) + return false; + + return should_fail(&fail_futex.attr, 1); +} + +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + +static int __init fail_futex_debugfs(void) +{ + umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; + struct dentry *dir; + + dir = fault_create_debugfs_attr("fail_futex", NULL, + &fail_futex.attr); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + if (!debugfs_create_bool("ignore-private", mode, dir, + &fail_futex.ignore_private)) { + debugfs_remove_recursive(dir); + return -ENOMEM; + } + + return 0; +} + +late_initcall(fail_futex_debugfs); + +#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ + +#else +static inline bool should_fail_futex(bool fshared) +{ + return false; +} +#endif /* CONFIG_FAIL_FUTEX */ + static inline void futex_get_mm(union futex_key *key) { atomic_inc(&key->private.mm->mm_count); @@ -413,6 +474,9 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) if (unlikely(!access_ok(rw, uaddr, sizeof(u32)))) return -EFAULT; + if (unlikely(should_fail_futex(fshared))) + return -EFAULT; + /* * PROCESS_PRIVATE futexes are fast. * As the mm cannot disappear under us and the 'key' only needs @@ -428,6 +492,10 @@ get_futex_key(u32 __user *uaddr, int fshared, union futex_key *key, int rw) } again: + /* Ignore any VERIFY_READ mapping (futex common case) */ + if (unlikely(should_fail_futex(fshared))) + return -EFAULT; + err = get_user_pages_fast(address, 1, 1, &page); /* * If write access is not required (eg. FUTEX_WAIT), try @@ -516,7 +584,7 @@ again: * A RO anonymous page will never change and thus doesn't make * sense for futex operations. */ - if (ro) { + if (unlikely(should_fail_futex(fshared)) || ro) { err = -EFAULT; goto out; } @@ -974,6 +1042,9 @@ static int lock_pi_update_atomic(u32 __user *uaddr, u32 uval, u32 newval) { u32 uninitialized_var(curval); + if (unlikely(should_fail_futex(true))) + return -EFAULT; + if (unlikely(cmpxchg_futex_value_locked(&curval, uaddr, uval, newval))) return -EFAULT; @@ -1015,12 +1086,18 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb, if (get_futex_value_locked(&uval, uaddr)) return -EFAULT; + if (unlikely(should_fail_futex(true))) + return -EFAULT; + /* * Detect deadlocks. */ if ((unlikely((uval & FUTEX_TID_MASK) == vpid))) return -EDEADLK; + if ((unlikely(should_fail_futex(true)))) + return -EDEADLK; + /* * Lookup existing state first. If it exists, try to attach to * its pi_state. @@ -1155,6 +1232,9 @@ static int wake_futex_pi(u32 __user *uaddr, u32 uval, struct futex_q *this, */ newval = FUTEX_WAITERS | task_pid_vnr(new_owner); + if (unlikely(should_fail_futex(true))) + ret = -EFAULT; + if (cmpxchg_futex_value_locked(&curval, uaddr, uval, newval)) ret = -EFAULT; else if (curval != uval) @@ -1457,6 +1537,9 @@ static int futex_proxy_trylock_atomic(u32 __user *pifutex, if (get_futex_value_locked(&curval, pifutex)) return -EFAULT; + if (unlikely(should_fail_futex(true))) + return -EFAULT; + /* * Find the top_waiter and determine if there are additional waiters. * If the caller intends to requeue more than 1 waiter to pifutex, @@ -2537,7 +2620,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb, * futex_wait_requeue_pi() - Wait on uaddr and take uaddr2 * @uaddr: the futex we initially wait on (non-pi) * @flags: futex flags (FLAGS_SHARED, FLAGS_CLOCKRT, etc.), they must be - * the same type, no requeueing from private to shared, etc. + * the same type, no requeueing from private to shared, etc. * @val: the expected value of uaddr * @abs_time: absolute timeout * @bitset: 32 bit wakeup bitset set by userspace, defaults to all @@ -3012,6 +3095,8 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val, if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI || cmd == FUTEX_WAIT_BITSET || cmd == FUTEX_WAIT_REQUEUE_PI)) { + if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG)))) + return -EFAULT; if (copy_from_user(&ts, utime, sizeof(ts)) != 0) return -EFAULT; if (!timespec_valid(&ts)) diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index e2894b23efb60..22554d6f720f7 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1542,6 +1542,13 @@ config FAIL_MMC_REQUEST and to test how the mmc host driver handles retries from the block device. +config FAIL_FUTEX + bool "Fault-injection capability for futexes" + select DEBUG_FS + depends on FAULT_INJECTION && FUTEX + help + Provide fault-injection capability for futexes. + config FAULT_INJECTION_DEBUG_FS bool "Debugfs entries for fault-injection capabilities" depends on FAULT_INJECTION && SYSFS && DEBUG_FS -- GitLab From 1b0b7c1762679a2f8bc359da95649249dfcf4195 Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 1 Jul 2015 13:29:48 -0700 Subject: [PATCH 1217/7006] rtmutex: Delete scriptable tester No one uses this anymore, and this is not the first time the idea of replacing it with a (now possible) userspace side. Lock stealing logic was removed long ago in when the lock was granted to the highest prio. Signed-off-by: Davidlohr Bueso Cc: Darren Hart Cc: Steven Rostedt Cc: Mike Galbraith Cc: Paul E. McKenney Cc: Sebastian Andrzej Siewior Cc: Davidlohr Bueso Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1435782588-4177-2-git-send-email-dave@stgolabs.net Signed-off-by: Thomas Gleixner --- arch/parisc/configs/c8000_defconfig | 1 - arch/parisc/configs/generic-32bit_defconfig | 1 - arch/xtensa/configs/iss_defconfig | 1 - kernel/locking/Makefile | 1 - kernel/locking/rtmutex-tester.c | 420 ------------------ kernel/locking/rtmutex.c | 2 +- kernel/locking/rtmutex_common.h | 22 - lib/Kconfig.debug | 6 - scripts/rt-tester/check-all.sh | 21 - scripts/rt-tester/rt-tester.py | 218 --------- scripts/rt-tester/t2-l1-2rt-sameprio.tst | 94 ---- scripts/rt-tester/t2-l1-pi.tst | 77 ---- scripts/rt-tester/t2-l1-signal.tst | 72 --- scripts/rt-tester/t2-l2-2rt-deadlock.tst | 84 ---- scripts/rt-tester/t3-l1-pi-1rt.tst | 87 ---- scripts/rt-tester/t3-l1-pi-2rt.tst | 88 ---- scripts/rt-tester/t3-l1-pi-3rt.tst | 87 ---- scripts/rt-tester/t3-l1-pi-signal.tst | 93 ---- scripts/rt-tester/t3-l1-pi-steal.tst | 91 ---- scripts/rt-tester/t3-l2-pi.tst | 87 ---- scripts/rt-tester/t4-l2-pi-deboost.tst | 118 ----- .../t5-l4-pi-boost-deboost-setsched.tst | 178 -------- scripts/rt-tester/t5-l4-pi-boost-deboost.tst | 138 ------ 23 files changed, 1 insertion(+), 1986 deletions(-) delete mode 100644 kernel/locking/rtmutex-tester.c delete mode 100644 scripts/rt-tester/check-all.sh delete mode 100755 scripts/rt-tester/rt-tester.py delete mode 100644 scripts/rt-tester/t2-l1-2rt-sameprio.tst delete mode 100644 scripts/rt-tester/t2-l1-pi.tst delete mode 100644 scripts/rt-tester/t2-l1-signal.tst delete mode 100644 scripts/rt-tester/t2-l2-2rt-deadlock.tst delete mode 100644 scripts/rt-tester/t3-l1-pi-1rt.tst delete mode 100644 scripts/rt-tester/t3-l1-pi-2rt.tst delete mode 100644 scripts/rt-tester/t3-l1-pi-3rt.tst delete mode 100644 scripts/rt-tester/t3-l1-pi-signal.tst delete mode 100644 scripts/rt-tester/t3-l1-pi-steal.tst delete mode 100644 scripts/rt-tester/t3-l2-pi.tst delete mode 100644 scripts/rt-tester/t4-l2-pi-deboost.tst delete mode 100644 scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst delete mode 100644 scripts/rt-tester/t5-l4-pi-boost-deboost.tst diff --git a/arch/parisc/configs/c8000_defconfig b/arch/parisc/configs/c8000_defconfig index 269c23d23fcb6..1a8f6f95689e6 100644 --- a/arch/parisc/configs/c8000_defconfig +++ b/arch/parisc/configs/c8000_defconfig @@ -242,7 +242,6 @@ CONFIG_LOCKUP_DETECTOR=y CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC=y CONFIG_PANIC_ON_OOPS=y CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_RT_MUTEX_TESTER=y CONFIG_PROVE_RCU_DELAY=y CONFIG_DEBUG_BLOCK_EXT_DEVT=y CONFIG_LATENCYTOP=y diff --git a/arch/parisc/configs/generic-32bit_defconfig b/arch/parisc/configs/generic-32bit_defconfig index 33b148f825baa..0ffb08ff51252 100644 --- a/arch/parisc/configs/generic-32bit_defconfig +++ b/arch/parisc/configs/generic-32bit_defconfig @@ -295,7 +295,6 @@ CONFIG_DEBUG_SHIRQ=y CONFIG_DETECT_HUNG_TASK=y CONFIG_TIMER_STATS=y CONFIG_DEBUG_RT_MUTEXES=y -CONFIG_RT_MUTEX_TESTER=y CONFIG_DEBUG_SPINLOCK=y CONFIG_DEBUG_MUTEXES=y CONFIG_RCU_CPU_STALL_INFO=y diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig index e4d193e7a3008..f3dfe0d921c27 100644 --- a/arch/xtensa/configs/iss_defconfig +++ b/arch/xtensa/configs/iss_defconfig @@ -616,7 +616,6 @@ CONFIG_SCHED_DEBUG=y # CONFIG_SLUB_DEBUG_ON is not set # CONFIG_SLUB_STATS is not set # CONFIG_DEBUG_RT_MUTEXES is not set -# CONFIG_RT_MUTEX_TESTER is not set # CONFIG_DEBUG_SPINLOCK is not set # CONFIG_DEBUG_MUTEXES is not set # CONFIG_DEBUG_SPINLOCK_SLEEP is not set diff --git a/kernel/locking/Makefile b/kernel/locking/Makefile index 7dd5c9918e4c2..36942047ffc08 100644 --- a/kernel/locking/Makefile +++ b/kernel/locking/Makefile @@ -20,7 +20,6 @@ obj-$(CONFIG_PROVE_LOCKING) += spinlock.o obj-$(CONFIG_QUEUED_SPINLOCKS) += qspinlock.o obj-$(CONFIG_RT_MUTEXES) += rtmutex.o obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o -obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o diff --git a/kernel/locking/rtmutex-tester.c b/kernel/locking/rtmutex-tester.c deleted file mode 100644 index 1d96dd0d93c1a..0000000000000 --- a/kernel/locking/rtmutex-tester.c +++ /dev/null @@ -1,420 +0,0 @@ -/* - * RT-Mutex-tester: scriptable tester for rt mutexes - * - * started by Thomas Gleixner: - * - * Copyright (C) 2006, Timesys Corp., Thomas Gleixner - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rtmutex.h" - -#define MAX_RT_TEST_THREADS 8 -#define MAX_RT_TEST_MUTEXES 8 - -static spinlock_t rttest_lock; -static atomic_t rttest_event; - -struct test_thread_data { - int opcode; - int opdata; - int mutexes[MAX_RT_TEST_MUTEXES]; - int event; - struct device dev; -}; - -static struct test_thread_data thread_data[MAX_RT_TEST_THREADS]; -static struct task_struct *threads[MAX_RT_TEST_THREADS]; -static struct rt_mutex mutexes[MAX_RT_TEST_MUTEXES]; - -enum test_opcodes { - RTTEST_NOP = 0, - RTTEST_SCHEDOT, /* 1 Sched other, data = nice */ - RTTEST_SCHEDRT, /* 2 Sched fifo, data = prio */ - RTTEST_LOCK, /* 3 Lock uninterruptible, data = lockindex */ - RTTEST_LOCKNOWAIT, /* 4 Lock uninterruptible no wait in wakeup, data = lockindex */ - RTTEST_LOCKINT, /* 5 Lock interruptible, data = lockindex */ - RTTEST_LOCKINTNOWAIT, /* 6 Lock interruptible no wait in wakeup, data = lockindex */ - RTTEST_LOCKCONT, /* 7 Continue locking after the wakeup delay */ - RTTEST_UNLOCK, /* 8 Unlock, data = lockindex */ - /* 9, 10 - reserved for BKL commemoration */ - RTTEST_SIGNAL = 11, /* 11 Signal other test thread, data = thread id */ - RTTEST_RESETEVENT = 98, /* 98 Reset event counter */ - RTTEST_RESET = 99, /* 99 Reset all pending operations */ -}; - -static int handle_op(struct test_thread_data *td, int lockwakeup) -{ - int i, id, ret = -EINVAL; - - switch(td->opcode) { - - case RTTEST_NOP: - return 0; - - case RTTEST_LOCKCONT: - td->mutexes[td->opdata] = 1; - td->event = atomic_add_return(1, &rttest_event); - return 0; - - case RTTEST_RESET: - for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) { - if (td->mutexes[i] == 4) { - rt_mutex_unlock(&mutexes[i]); - td->mutexes[i] = 0; - } - } - return 0; - - case RTTEST_RESETEVENT: - atomic_set(&rttest_event, 0); - return 0; - - default: - if (lockwakeup) - return ret; - } - - switch(td->opcode) { - - case RTTEST_LOCK: - case RTTEST_LOCKNOWAIT: - id = td->opdata; - if (id < 0 || id >= MAX_RT_TEST_MUTEXES) - return ret; - - td->mutexes[id] = 1; - td->event = atomic_add_return(1, &rttest_event); - rt_mutex_lock(&mutexes[id]); - td->event = atomic_add_return(1, &rttest_event); - td->mutexes[id] = 4; - return 0; - - case RTTEST_LOCKINT: - case RTTEST_LOCKINTNOWAIT: - id = td->opdata; - if (id < 0 || id >= MAX_RT_TEST_MUTEXES) - return ret; - - td->mutexes[id] = 1; - td->event = atomic_add_return(1, &rttest_event); - ret = rt_mutex_lock_interruptible(&mutexes[id], 0); - td->event = atomic_add_return(1, &rttest_event); - td->mutexes[id] = ret ? 0 : 4; - return ret ? -EINTR : 0; - - case RTTEST_UNLOCK: - id = td->opdata; - if (id < 0 || id >= MAX_RT_TEST_MUTEXES || td->mutexes[id] != 4) - return ret; - - td->event = atomic_add_return(1, &rttest_event); - rt_mutex_unlock(&mutexes[id]); - td->event = atomic_add_return(1, &rttest_event); - td->mutexes[id] = 0; - return 0; - - default: - break; - } - return ret; -} - -/* - * Schedule replacement for rtsem_down(). Only called for threads with - * PF_MUTEX_TESTER set. - * - * This allows us to have finegrained control over the event flow. - * - */ -void schedule_rt_mutex_test(struct rt_mutex *mutex) -{ - int tid, op, dat; - struct test_thread_data *td; - - /* We have to lookup the task */ - for (tid = 0; tid < MAX_RT_TEST_THREADS; tid++) { - if (threads[tid] == current) - break; - } - - BUG_ON(tid == MAX_RT_TEST_THREADS); - - td = &thread_data[tid]; - - op = td->opcode; - dat = td->opdata; - - switch (op) { - case RTTEST_LOCK: - case RTTEST_LOCKINT: - case RTTEST_LOCKNOWAIT: - case RTTEST_LOCKINTNOWAIT: - if (mutex != &mutexes[dat]) - break; - - if (td->mutexes[dat] != 1) - break; - - td->mutexes[dat] = 2; - td->event = atomic_add_return(1, &rttest_event); - break; - - default: - break; - } - - schedule(); - - - switch (op) { - case RTTEST_LOCK: - case RTTEST_LOCKINT: - if (mutex != &mutexes[dat]) - return; - - if (td->mutexes[dat] != 2) - return; - - td->mutexes[dat] = 3; - td->event = atomic_add_return(1, &rttest_event); - break; - - case RTTEST_LOCKNOWAIT: - case RTTEST_LOCKINTNOWAIT: - if (mutex != &mutexes[dat]) - return; - - if (td->mutexes[dat] != 2) - return; - - td->mutexes[dat] = 1; - td->event = atomic_add_return(1, &rttest_event); - return; - - default: - return; - } - - td->opcode = 0; - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - - if (td->opcode > 0) { - int ret; - - set_current_state(TASK_RUNNING); - ret = handle_op(td, 1); - set_current_state(TASK_INTERRUPTIBLE); - if (td->opcode == RTTEST_LOCKCONT) - break; - td->opcode = ret; - } - - /* Wait for the next command to be executed */ - schedule(); - } - - /* Restore previous command and data */ - td->opcode = op; - td->opdata = dat; -} - -static int test_func(void *data) -{ - struct test_thread_data *td = data; - int ret; - - current->flags |= PF_MUTEX_TESTER; - set_freezable(); - allow_signal(SIGHUP); - - for(;;) { - - set_current_state(TASK_INTERRUPTIBLE); - - if (td->opcode > 0) { - set_current_state(TASK_RUNNING); - ret = handle_op(td, 0); - set_current_state(TASK_INTERRUPTIBLE); - td->opcode = ret; - } - - /* Wait for the next command to be executed */ - schedule(); - try_to_freeze(); - - if (signal_pending(current)) - flush_signals(current); - - if(kthread_should_stop()) - break; - } - return 0; -} - -/** - * sysfs_test_command - interface for test commands - * @dev: thread reference - * @buf: command for actual step - * @count: length of buffer - * - * command syntax: - * - * opcode:data - */ -static ssize_t sysfs_test_command(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct sched_param schedpar; - struct test_thread_data *td; - char cmdbuf[32]; - int op, dat, tid, ret; - - td = container_of(dev, struct test_thread_data, dev); - tid = td->dev.id; - - /* strings from sysfs write are not 0 terminated! */ - if (count >= sizeof(cmdbuf)) - return -EINVAL; - - /* strip of \n: */ - if (buf[count-1] == '\n') - count--; - if (count < 1) - return -EINVAL; - - memcpy(cmdbuf, buf, count); - cmdbuf[count] = 0; - - if (sscanf(cmdbuf, "%d:%d", &op, &dat) != 2) - return -EINVAL; - - switch (op) { - case RTTEST_SCHEDOT: - schedpar.sched_priority = 0; - ret = sched_setscheduler(threads[tid], SCHED_NORMAL, &schedpar); - if (ret) - return ret; - set_user_nice(current, 0); - break; - - case RTTEST_SCHEDRT: - schedpar.sched_priority = dat; - ret = sched_setscheduler(threads[tid], SCHED_FIFO, &schedpar); - if (ret) - return ret; - break; - - case RTTEST_SIGNAL: - send_sig(SIGHUP, threads[tid], 0); - break; - - default: - if (td->opcode > 0) - return -EBUSY; - td->opdata = dat; - td->opcode = op; - wake_up_process(threads[tid]); - } - - return count; -} - -/** - * sysfs_test_status - sysfs interface for rt tester - * @dev: thread to query - * @buf: char buffer to be filled with thread status info - */ -static ssize_t sysfs_test_status(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct test_thread_data *td; - struct task_struct *tsk; - char *curr = buf; - int i; - - td = container_of(dev, struct test_thread_data, dev); - tsk = threads[td->dev.id]; - - spin_lock(&rttest_lock); - - curr += sprintf(curr, - "O: %4d, E:%8d, S: 0x%08lx, P: %4d, N: %4d, B: %p, M:", - td->opcode, td->event, tsk->state, - (MAX_RT_PRIO - 1) - tsk->prio, - (MAX_RT_PRIO - 1) - tsk->normal_prio, - tsk->pi_blocked_on); - - for (i = MAX_RT_TEST_MUTEXES - 1; i >=0 ; i--) - curr += sprintf(curr, "%d", td->mutexes[i]); - - spin_unlock(&rttest_lock); - - curr += sprintf(curr, ", T: %p, R: %p\n", tsk, - mutexes[td->dev.id].owner); - - return curr - buf; -} - -static DEVICE_ATTR(status, S_IRUSR, sysfs_test_status, NULL); -static DEVICE_ATTR(command, S_IWUSR, NULL, sysfs_test_command); - -static struct bus_type rttest_subsys = { - .name = "rttest", - .dev_name = "rttest", -}; - -static int init_test_thread(int id) -{ - thread_data[id].dev.bus = &rttest_subsys; - thread_data[id].dev.id = id; - - threads[id] = kthread_run(test_func, &thread_data[id], "rt-test-%d", id); - if (IS_ERR(threads[id])) - return PTR_ERR(threads[id]); - - return device_register(&thread_data[id].dev); -} - -static int init_rttest(void) -{ - int ret, i; - - spin_lock_init(&rttest_lock); - - for (i = 0; i < MAX_RT_TEST_MUTEXES; i++) - rt_mutex_init(&mutexes[i]); - - ret = subsys_system_register(&rttest_subsys, NULL); - if (ret) - return ret; - - for (i = 0; i < MAX_RT_TEST_THREADS; i++) { - ret = init_test_thread(i); - if (ret) - break; - ret = device_create_file(&thread_data[i].dev, &dev_attr_status); - if (ret) - break; - ret = device_create_file(&thread_data[i].dev, &dev_attr_command); - if (ret) - break; - } - - printk("Initializing RT-Tester: %s\n", ret ? "Failed" : "OK" ); - - return ret; -} - -device_initcall(init_rttest); diff --git a/kernel/locking/rtmutex.c b/kernel/locking/rtmutex.c index 5674b073473c2..7781d801212fa 100644 --- a/kernel/locking/rtmutex.c +++ b/kernel/locking/rtmutex.c @@ -1120,7 +1120,7 @@ __rt_mutex_slowlock(struct rt_mutex *lock, int state, debug_rt_mutex_print_deadlock(waiter); - schedule_rt_mutex(lock); + schedule(); raw_spin_lock(&lock->wait_lock); set_current_state(state); diff --git a/kernel/locking/rtmutex_common.h b/kernel/locking/rtmutex_common.h index 7844f8f0e6391..4f5f83c7d2d35 100644 --- a/kernel/locking/rtmutex_common.h +++ b/kernel/locking/rtmutex_common.h @@ -14,28 +14,6 @@ #include -/* - * The rtmutex in kernel tester is independent of rtmutex debugging. We - * call schedule_rt_mutex_test() instead of schedule() for the tasks which - * belong to the tester. That way we can delay the wakeup path of those - * threads to provoke lock stealing and testing of complex boosting scenarios. - */ -#ifdef CONFIG_RT_MUTEX_TESTER - -extern void schedule_rt_mutex_test(struct rt_mutex *lock); - -#define schedule_rt_mutex(_lock) \ - do { \ - if (!(current->flags & PF_MUTEX_TESTER)) \ - schedule(); \ - else \ - schedule_rt_mutex_test(_lock); \ - } while (0) - -#else -# define schedule_rt_mutex(_lock) schedule() -#endif - /* * This is the control structure for tasks blocked on a rt_mutex, * which is allocated on the kernel stack on of the blocked task. diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 22554d6f720f7..e7b5b654ed8d8 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -916,12 +916,6 @@ config DEBUG_RT_MUTEXES This allows rt mutex semantics violations and rt mutex related deadlocks (lockups) to be detected and reported automatically. -config RT_MUTEX_TESTER - bool "Built-in scriptable tester for rt-mutexes" - depends on DEBUG_KERNEL && RT_MUTEXES && BROKEN - help - This option enables a rt-mutex tester. - config DEBUG_SPINLOCK bool "Spinlock and rw-lock debugging: basic checks" depends on DEBUG_KERNEL diff --git a/scripts/rt-tester/check-all.sh b/scripts/rt-tester/check-all.sh deleted file mode 100644 index 6b5c83baf1488..0000000000000 --- a/scripts/rt-tester/check-all.sh +++ /dev/null @@ -1,21 +0,0 @@ - - -function testit () -{ - printf "%-30s: " $1 - ./rt-tester.py $1 | grep Pass -} - -testit t2-l1-2rt-sameprio.tst -testit t2-l1-pi.tst -testit t2-l1-signal.tst -#testit t2-l2-2rt-deadlock.tst -testit t3-l1-pi-1rt.tst -testit t3-l1-pi-2rt.tst -testit t3-l1-pi-3rt.tst -testit t3-l1-pi-signal.tst -testit t3-l1-pi-steal.tst -testit t3-l2-pi.tst -testit t4-l2-pi-deboost.tst -testit t5-l4-pi-boost-deboost.tst -testit t5-l4-pi-boost-deboost-setsched.tst diff --git a/scripts/rt-tester/rt-tester.py b/scripts/rt-tester/rt-tester.py deleted file mode 100755 index 6d916c2a45a55..0000000000000 --- a/scripts/rt-tester/rt-tester.py +++ /dev/null @@ -1,218 +0,0 @@ -#!/usr/bin/python -# -# rt-mutex tester -# -# (C) 2006 Thomas Gleixner -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 as -# published by the Free Software Foundation. -# -import os -import sys -import getopt -import shutil -import string - -# Globals -quiet = 0 -test = 0 -comments = 0 - -sysfsprefix = "/sys/devices/system/rttest/rttest" -statusfile = "/status" -commandfile = "/command" - -# Command opcodes -cmd_opcodes = { - "schedother" : "1", - "schedfifo" : "2", - "lock" : "3", - "locknowait" : "4", - "lockint" : "5", - "lockintnowait" : "6", - "lockcont" : "7", - "unlock" : "8", - "signal" : "11", - "resetevent" : "98", - "reset" : "99", - } - -test_opcodes = { - "prioeq" : ["P" , "eq" , None], - "priolt" : ["P" , "lt" , None], - "priogt" : ["P" , "gt" , None], - "nprioeq" : ["N" , "eq" , None], - "npriolt" : ["N" , "lt" , None], - "npriogt" : ["N" , "gt" , None], - "unlocked" : ["M" , "eq" , 0], - "trylock" : ["M" , "eq" , 1], - "blocked" : ["M" , "eq" , 2], - "blockedwake" : ["M" , "eq" , 3], - "locked" : ["M" , "eq" , 4], - "opcodeeq" : ["O" , "eq" , None], - "opcodelt" : ["O" , "lt" , None], - "opcodegt" : ["O" , "gt" , None], - "eventeq" : ["E" , "eq" , None], - "eventlt" : ["E" , "lt" , None], - "eventgt" : ["E" , "gt" , None], - } - -# Print usage information -def usage(): - print "rt-tester.py <-c -h -q -t> " - print " -c display comments after first command" - print " -h help" - print " -q quiet mode" - print " -t test mode (syntax check)" - print " testfile: read test specification from testfile" - print " otherwise from stdin" - return - -# Print progress when not in quiet mode -def progress(str): - if not quiet: - print str - -# Analyse a status value -def analyse(val, top, arg): - - intval = int(val) - - if top[0] == "M": - intval = intval / (10 ** int(arg)) - intval = intval % 10 - argval = top[2] - elif top[0] == "O": - argval = int(cmd_opcodes.get(arg, arg)) - else: - argval = int(arg) - - # progress("%d %s %d" %(intval, top[1], argval)) - - if top[1] == "eq" and intval == argval: - return 1 - if top[1] == "lt" and intval < argval: - return 1 - if top[1] == "gt" and intval > argval: - return 1 - return 0 - -# Parse the commandline -try: - (options, arguments) = getopt.getopt(sys.argv[1:],'chqt') -except getopt.GetoptError, ex: - usage() - sys.exit(1) - -# Parse commandline options -for option, value in options: - if option == "-c": - comments = 1 - elif option == "-q": - quiet = 1 - elif option == "-t": - test = 1 - elif option == '-h': - usage() - sys.exit(0) - -# Select the input source -if arguments: - try: - fd = open(arguments[0]) - except Exception,ex: - sys.stderr.write("File not found %s\n" %(arguments[0])) - sys.exit(1) -else: - fd = sys.stdin - -linenr = 0 - -# Read the test patterns -while 1: - - linenr = linenr + 1 - line = fd.readline() - if not len(line): - break - - line = line.strip() - parts = line.split(":") - - if not parts or len(parts) < 1: - continue - - if len(parts[0]) == 0: - continue - - if parts[0].startswith("#"): - if comments > 1: - progress(line) - continue - - if comments == 1: - comments = 2 - - progress(line) - - cmd = parts[0].strip().lower() - opc = parts[1].strip().lower() - tid = parts[2].strip() - dat = parts[3].strip() - - try: - # Test or wait for a status value - if cmd == "t" or cmd == "w": - testop = test_opcodes[opc] - - fname = "%s%s%s" %(sysfsprefix, tid, statusfile) - if test: - print fname - continue - - while 1: - query = 1 - fsta = open(fname, 'r') - status = fsta.readline().strip() - fsta.close() - stat = status.split(",") - for s in stat: - s = s.strip() - if s.startswith(testop[0]): - # Separate status value - val = s[2:].strip() - query = analyse(val, testop, dat) - break - if query or cmd == "t": - break - - progress(" " + status) - - if not query: - sys.stderr.write("Test failed in line %d\n" %(linenr)) - sys.exit(1) - - # Issue a command to the tester - elif cmd == "c": - cmdnr = cmd_opcodes[opc] - # Build command string and sys filename - cmdstr = "%s:%s" %(cmdnr, dat) - fname = "%s%s%s" %(sysfsprefix, tid, commandfile) - if test: - print fname - continue - fcmd = open(fname, 'w') - fcmd.write(cmdstr) - fcmd.close() - - except Exception,ex: - sys.stderr.write(str(ex)) - sys.stderr.write("\nSyntax error in line %d\n" %(linenr)) - if not test: - fd.close() - sys.exit(1) - -# Normal exit pass -print "Pass" -sys.exit(0) diff --git a/scripts/rt-tester/t2-l1-2rt-sameprio.tst b/scripts/rt-tester/t2-l1-2rt-sameprio.tst deleted file mode 100644 index 3710c8b2090d5..0000000000000 --- a/scripts/rt-tester/t2-l1-2rt-sameprio.tst +++ /dev/null @@ -1,94 +0,0 @@ -# -# RT-Mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal 0 -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 2 threads 1 lock -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedfifo: 0: 80 -C: schedfifo: 1: 80 - -# T0 lock L0 -C: locknowait: 0: 0 -C: locknowait: 1: 0 -W: locked: 0: 0 -W: blocked: 1: 0 -T: prioeq: 0: 80 - -# T0 unlock L0 -C: unlock: 0: 0 -W: locked: 1: 0 - -# Verify T0 -W: unlocked: 0: 0 -T: prioeq: 0: 80 - -# Unlock -C: unlock: 1: 0 -W: unlocked: 1: 0 - -# T1,T0 lock L0 -C: locknowait: 1: 0 -C: locknowait: 0: 0 -W: locked: 1: 0 -W: blocked: 0: 0 -T: prioeq: 1: 80 - -# T1 unlock L0 -C: unlock: 1: 0 -W: locked: 0: 0 - -# Verify T1 -W: unlocked: 1: 0 -T: prioeq: 1: 80 - -# Unlock and exit -C: unlock: 0: 0 -W: unlocked: 0: 0 - diff --git a/scripts/rt-tester/t2-l1-pi.tst b/scripts/rt-tester/t2-l1-pi.tst deleted file mode 100644 index b4cc95975adbb..0000000000000 --- a/scripts/rt-tester/t2-l1-pi.tst +++ /dev/null @@ -1,77 +0,0 @@ -# -# RT-Mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal 0 -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 2 threads 1 lock with priority inversion -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedfifo: 1: 80 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: locknowait: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 80 - -# T0 unlock L0 -C: unlock: 0: 0 -W: locked: 1: 0 - -# Verify T1 -W: unlocked: 0: 0 -T: priolt: 0: 1 - -# Unlock and exit -C: unlock: 1: 0 -W: unlocked: 1: 0 - diff --git a/scripts/rt-tester/t2-l1-signal.tst b/scripts/rt-tester/t2-l1-signal.tst deleted file mode 100644 index 1b57376cc1f7c..0000000000000 --- a/scripts/rt-tester/t2-l1-signal.tst +++ /dev/null @@ -1,72 +0,0 @@ -# -# RT-Mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal 0 -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 2 threads 1 lock with priority inversion -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedother: 1: 0 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: lockintnowait: 1: 0 -W: blocked: 1: 0 - -# Interrupt T1 -C: signal: 1: 0 -W: unlocked: 1: 0 -T: opcodeeq: 1: -4 - -# Unlock and exit -C: unlock: 0: 0 -W: unlocked: 0: 0 diff --git a/scripts/rt-tester/t2-l2-2rt-deadlock.tst b/scripts/rt-tester/t2-l2-2rt-deadlock.tst deleted file mode 100644 index 68b10629b6f4d..0000000000000 --- a/scripts/rt-tester/t2-l2-2rt-deadlock.tst +++ /dev/null @@ -1,84 +0,0 @@ -# -# RT-Mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal 0 -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 2 threads 2 lock -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedfifo: 0: 80 -C: schedfifo: 1: 80 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L1 -C: locknowait: 1: 1 -W: locked: 1: 1 - -# T0 lock L1 -C: lockintnowait: 0: 1 -W: blocked: 0: 1 - -# T1 lock L0 -C: lockintnowait: 1: 0 -W: blocked: 1: 0 - -# Make deadlock go away -C: signal: 1: 0 -W: unlocked: 1: 0 -C: signal: 0: 0 -W: unlocked: 0: 1 - -# Unlock and exit -C: unlock: 0: 0 -W: unlocked: 0: 0 -C: unlock: 1: 1 -W: unlocked: 1: 1 - diff --git a/scripts/rt-tester/t3-l1-pi-1rt.tst b/scripts/rt-tester/t3-l1-pi-1rt.tst deleted file mode 100644 index 8e6c8b11ae563..0000000000000 --- a/scripts/rt-tester/t3-l1-pi-1rt.tst +++ /dev/null @@ -1,87 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 3 threads 1 lock PI -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedother: 1: 0 -C: schedfifo: 2: 82 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: locknowait: 1: 0 -W: blocked: 1: 0 -T: priolt: 0: 1 - -# T2 lock L0 -C: locknowait: 2: 0 -W: blocked: 2: 0 -T: prioeq: 0: 82 - -# T0 unlock L0 -C: unlock: 0: 0 - -# Wait until T2 got the lock -W: locked: 2: 0 -W: unlocked: 0: 0 -T: priolt: 0: 1 - -# T2 unlock L0 -C: unlock: 2: 0 - -W: unlocked: 2: 0 -W: locked: 1: 0 - -C: unlock: 1: 0 -W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l1-pi-2rt.tst b/scripts/rt-tester/t3-l1-pi-2rt.tst deleted file mode 100644 index 69c2212fc5208..0000000000000 --- a/scripts/rt-tester/t3-l1-pi-2rt.tst +++ /dev/null @@ -1,88 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 3 threads 1 lock PI -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedfifo: 1: 81 -C: schedfifo: 2: 82 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: locknowait: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 81 - -# T2 lock L0 -C: locknowait: 2: 0 -W: blocked: 2: 0 -T: prioeq: 0: 82 -T: prioeq: 1: 81 - -# T0 unlock L0 -C: unlock: 0: 0 - -# Wait until T2 got the lock -W: locked: 2: 0 -W: unlocked: 0: 0 -T: priolt: 0: 1 - -# T2 unlock L0 -C: unlock: 2: 0 - -W: unlocked: 2: 0 -W: locked: 1: 0 - -C: unlock: 1: 0 -W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l1-pi-3rt.tst b/scripts/rt-tester/t3-l1-pi-3rt.tst deleted file mode 100644 index 9b0f1eb26a88a..0000000000000 --- a/scripts/rt-tester/t3-l1-pi-3rt.tst +++ /dev/null @@ -1,87 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 3 threads 1 lock PI -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedfifo: 0: 80 -C: schedfifo: 1: 81 -C: schedfifo: 2: 82 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: locknowait: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 81 - -# T2 lock L0 -C: locknowait: 2: 0 -W: blocked: 2: 0 -T: prioeq: 0: 82 - -# T0 unlock L0 -C: unlock: 0: 0 - -# Wait until T2 got the lock -W: locked: 2: 0 -W: unlocked: 0: 0 -T: prioeq: 0: 80 - -# T2 unlock L0 -C: unlock: 2: 0 - -W: locked: 1: 0 -W: unlocked: 2: 0 - -C: unlock: 1: 0 -W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l1-pi-signal.tst b/scripts/rt-tester/t3-l1-pi-signal.tst deleted file mode 100644 index 39ec74ab06ee7..0000000000000 --- a/scripts/rt-tester/t3-l1-pi-signal.tst +++ /dev/null @@ -1,93 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# Reset event counter -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set priorities -C: schedother: 0: 0 -C: schedfifo: 1: 80 -C: schedfifo: 2: 81 - -# T0 lock L0 -C: lock: 0: 0 -W: locked: 0: 0 - -# T1 lock L0, no wait in the wakeup path -C: locknowait: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 80 -T: prioeq: 1: 80 - -# T2 lock L0 interruptible, no wait in the wakeup path -C: lockintnowait: 2: 0 -W: blocked: 2: 0 -T: prioeq: 0: 81 -T: prioeq: 1: 80 - -# Interrupt T2 -C: signal: 2: 2 -W: unlocked: 2: 0 -T: prioeq: 1: 80 -T: prioeq: 0: 80 - -T: locked: 0: 0 -T: blocked: 1: 0 - -# T0 unlock L0 -C: unlock: 0: 0 - -# Wait until T1 has locked L0 and exit -W: locked: 1: 0 -W: unlocked: 0: 0 -T: priolt: 0: 1 - -C: unlock: 1: 0 -W: unlocked: 1: 0 - - - diff --git a/scripts/rt-tester/t3-l1-pi-steal.tst b/scripts/rt-tester/t3-l1-pi-steal.tst deleted file mode 100644 index e03db7e010fa2..0000000000000 --- a/scripts/rt-tester/t3-l1-pi-steal.tst +++ /dev/null @@ -1,91 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 3 threads 1 lock PI steal pending ownership -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedfifo: 1: 80 -C: schedfifo: 2: 81 - -# T0 lock L0 -C: lock: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: lock: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 80 - -# T0 unlock L0 -C: unlock: 0: 0 - -# Wait until T1 is in the wakeup loop -W: blockedwake: 1: 0 -T: priolt: 0: 1 - -# T2 lock L0 -C: lock: 2: 0 -# T1 leave wakeup loop -C: lockcont: 1: 0 - -# T2 must have the lock and T1 must be blocked -W: locked: 2: 0 -W: blocked: 1: 0 - -# T2 unlock L0 -C: unlock: 2: 0 - -# Wait until T1 is in the wakeup loop and let it run -W: blockedwake: 1: 0 -C: lockcont: 1: 0 -W: locked: 1: 0 -C: unlock: 1: 0 -W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t3-l2-pi.tst b/scripts/rt-tester/t3-l2-pi.tst deleted file mode 100644 index 7b59100d3e48f..0000000000000 --- a/scripts/rt-tester/t3-l2-pi.tst +++ /dev/null @@ -1,87 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 3 threads 2 lock PI -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedother: 1: 0 -C: schedfifo: 2: 82 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L0 -C: locknowait: 1: 0 -W: blocked: 1: 0 -T: priolt: 0: 1 - -# T2 lock L0 -C: locknowait: 2: 0 -W: blocked: 2: 0 -T: prioeq: 0: 82 - -# T0 unlock L0 -C: unlock: 0: 0 - -# Wait until T2 got the lock -W: locked: 2: 0 -W: unlocked: 0: 0 -T: priolt: 0: 1 - -# T2 unlock L0 -C: unlock: 2: 0 - -W: unlocked: 2: 0 -W: locked: 1: 0 - -C: unlock: 1: 0 -W: unlocked: 1: 0 diff --git a/scripts/rt-tester/t4-l2-pi-deboost.tst b/scripts/rt-tester/t4-l2-pi-deboost.tst deleted file mode 100644 index 2f0e049d64438..0000000000000 --- a/scripts/rt-tester/t4-l2-pi-deboost.tst +++ /dev/null @@ -1,118 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 4 threads 2 lock PI -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedother: 1: 0 -C: schedfifo: 2: 82 -C: schedfifo: 3: 83 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L1 -C: locknowait: 1: 1 -W: locked: 1: 1 - -# T3 lock L0 -C: lockintnowait: 3: 0 -W: blocked: 3: 0 -T: prioeq: 0: 83 - -# T0 lock L1 -C: lock: 0: 1 -W: blocked: 0: 1 -T: prioeq: 1: 83 - -# T1 unlock L1 -C: unlock: 1: 1 - -# Wait until T0 is in the wakeup code -W: blockedwake: 0: 1 - -# Verify that T1 is unboosted -W: unlocked: 1: 1 -T: priolt: 1: 1 - -# T2 lock L1 (T0 is boosted and pending owner !) -C: locknowait: 2: 1 -W: blocked: 2: 1 -T: prioeq: 0: 83 - -# Interrupt T3 and wait until T3 returned -C: signal: 3: 0 -W: unlocked: 3: 0 - -# Verify prio of T0 (still pending owner, -# but T2 is enqueued due to the previous boost by T3 -T: prioeq: 0: 82 - -# Let T0 continue -C: lockcont: 0: 1 -W: locked: 0: 1 - -# Unlock L1 and let T2 get L1 -C: unlock: 0: 1 -W: locked: 2: 1 - -# Verify that T0 is unboosted -W: unlocked: 0: 1 -T: priolt: 0: 1 - -# Unlock everything and exit -C: unlock: 2: 1 -W: unlocked: 2: 1 - -C: unlock: 0: 0 -W: unlocked: 0: 0 - diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst deleted file mode 100644 index 04f4034ff895a..0000000000000 --- a/scripts/rt-tester/t5-l4-pi-boost-deboost-setsched.tst +++ /dev/null @@ -1,178 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 5 threads 4 lock PI - modify priority of blocked threads -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedfifo: 1: 81 -C: schedfifo: 2: 82 -C: schedfifo: 3: 83 -C: schedfifo: 4: 84 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L1 -C: locknowait: 1: 1 -W: locked: 1: 1 - -# T1 lock L0 -C: lockintnowait: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 81 - -# T2 lock L2 -C: locknowait: 2: 2 -W: locked: 2: 2 - -# T2 lock L1 -C: lockintnowait: 2: 1 -W: blocked: 2: 1 -T: prioeq: 0: 82 -T: prioeq: 1: 82 - -# T3 lock L3 -C: locknowait: 3: 3 -W: locked: 3: 3 - -# T3 lock L2 -C: lockintnowait: 3: 2 -W: blocked: 3: 2 -T: prioeq: 0: 83 -T: prioeq: 1: 83 -T: prioeq: 2: 83 - -# T4 lock L3 -C: lockintnowait: 4: 3 -W: blocked: 4: 3 -T: prioeq: 0: 84 -T: prioeq: 1: 84 -T: prioeq: 2: 84 -T: prioeq: 3: 84 - -# Reduce prio of T4 -C: schedfifo: 4: 80 -T: prioeq: 0: 83 -T: prioeq: 1: 83 -T: prioeq: 2: 83 -T: prioeq: 3: 83 -T: prioeq: 4: 80 - -# Increase prio of T4 -C: schedfifo: 4: 84 -T: prioeq: 0: 84 -T: prioeq: 1: 84 -T: prioeq: 2: 84 -T: prioeq: 3: 84 -T: prioeq: 4: 84 - -# Reduce prio of T3 -C: schedfifo: 3: 80 -T: prioeq: 0: 84 -T: prioeq: 1: 84 -T: prioeq: 2: 84 -T: prioeq: 3: 84 -T: prioeq: 4: 84 - -# Increase prio of T3 -C: schedfifo: 3: 85 -T: prioeq: 0: 85 -T: prioeq: 1: 85 -T: prioeq: 2: 85 -T: prioeq: 3: 85 -T: prioeq: 4: 84 - -# Reduce prio of T3 -C: schedfifo: 3: 83 -T: prioeq: 0: 84 -T: prioeq: 1: 84 -T: prioeq: 2: 84 -T: prioeq: 3: 84 -T: prioeq: 4: 84 - -# Signal T4 -C: signal: 4: 0 -W: unlocked: 4: 3 -T: prioeq: 0: 83 -T: prioeq: 1: 83 -T: prioeq: 2: 83 -T: prioeq: 3: 83 - -# Signal T3 -C: signal: 3: 0 -W: unlocked: 3: 2 -T: prioeq: 0: 82 -T: prioeq: 1: 82 -T: prioeq: 2: 82 - -# Signal T2 -C: signal: 2: 0 -W: unlocked: 2: 1 -T: prioeq: 0: 81 -T: prioeq: 1: 81 - -# Signal T1 -C: signal: 1: 0 -W: unlocked: 1: 0 -T: priolt: 0: 1 - -# Unlock and exit -C: unlock: 3: 3 -C: unlock: 2: 2 -C: unlock: 1: 1 -C: unlock: 0: 0 - -W: unlocked: 3: 3 -W: unlocked: 2: 2 -W: unlocked: 1: 1 -W: unlocked: 0: 0 - diff --git a/scripts/rt-tester/t5-l4-pi-boost-deboost.tst b/scripts/rt-tester/t5-l4-pi-boost-deboost.tst deleted file mode 100644 index a48a6ee29ddcf..0000000000000 --- a/scripts/rt-tester/t5-l4-pi-boost-deboost.tst +++ /dev/null @@ -1,138 +0,0 @@ -# -# rt-mutex test -# -# Op: C(ommand)/T(est)/W(ait) -# | opcode -# | | threadid: 0-7 -# | | | opcode argument -# | | | | -# C: lock: 0: 0 -# -# Commands -# -# opcode opcode argument -# schedother nice value -# schedfifo priority -# lock lock nr (0-7) -# locknowait lock nr (0-7) -# lockint lock nr (0-7) -# lockintnowait lock nr (0-7) -# lockcont lock nr (0-7) -# unlock lock nr (0-7) -# signal thread to signal (0-7) -# reset 0 -# resetevent 0 -# -# Tests / Wait -# -# opcode opcode argument -# -# prioeq priority -# priolt priority -# priogt priority -# nprioeq normal priority -# npriolt normal priority -# npriogt normal priority -# locked lock nr (0-7) -# blocked lock nr (0-7) -# blockedwake lock nr (0-7) -# unlocked lock nr (0-7) -# opcodeeq command opcode or number -# opcodelt number -# opcodegt number -# eventeq number -# eventgt number -# eventlt number - -# -# 5 threads 4 lock PI -# -C: resetevent: 0: 0 -W: opcodeeq: 0: 0 - -# Set schedulers -C: schedother: 0: 0 -C: schedfifo: 1: 81 -C: schedfifo: 2: 82 -C: schedfifo: 3: 83 -C: schedfifo: 4: 84 - -# T0 lock L0 -C: locknowait: 0: 0 -W: locked: 0: 0 - -# T1 lock L1 -C: locknowait: 1: 1 -W: locked: 1: 1 - -# T1 lock L0 -C: lockintnowait: 1: 0 -W: blocked: 1: 0 -T: prioeq: 0: 81 - -# T2 lock L2 -C: locknowait: 2: 2 -W: locked: 2: 2 - -# T2 lock L1 -C: lockintnowait: 2: 1 -W: blocked: 2: 1 -T: prioeq: 0: 82 -T: prioeq: 1: 82 - -# T3 lock L3 -C: locknowait: 3: 3 -W: locked: 3: 3 - -# T3 lock L2 -C: lockintnowait: 3: 2 -W: blocked: 3: 2 -T: prioeq: 0: 83 -T: prioeq: 1: 83 -T: prioeq: 2: 83 - -# T4 lock L3 -C: lockintnowait: 4: 3 -W: blocked: 4: 3 -T: prioeq: 0: 84 -T: prioeq: 1: 84 -T: prioeq: 2: 84 -T: prioeq: 3: 84 - -# Signal T4 -C: signal: 4: 0 -W: unlocked: 4: 3 -T: prioeq: 0: 83 -T: prioeq: 1: 83 -T: prioeq: 2: 83 -T: prioeq: 3: 83 - -# Signal T3 -C: signal: 3: 0 -W: unlocked: 3: 2 -T: prioeq: 0: 82 -T: prioeq: 1: 82 -T: prioeq: 2: 82 - -# Signal T2 -C: signal: 2: 0 -W: unlocked: 2: 1 -T: prioeq: 0: 81 -T: prioeq: 1: 81 - -# Signal T1 -C: signal: 1: 0 -W: unlocked: 1: 0 -T: priolt: 0: 1 - -# Unlock and exit -C: unlock: 3: 3 -C: unlock: 2: 2 -C: unlock: 1: 1 -C: unlock: 0: 0 - -W: unlocked: 3: 3 -W: unlocked: 2: 2 -W: unlocked: 1: 1 -W: unlocked: 0: 0 - -- GitLab From dd1b85dc446b7cfaeaa7e250d2ff2acc44a0d51d Mon Sep 17 00:00:00 2001 From: Dirk Behme Date: Mon, 20 Jul 2015 09:50:37 -0700 Subject: [PATCH 1218/7006] Input: zforce - don't invert the interrupt GPIO Commit 2d53809594af ("Input: zforce_ts - convert to use the gpiod interface") converted this driver to use the gpiod functions. These functions take the active low property into account, so we don't have to invert the result of gpiod_get_value_cansleep(). This has been missed in that commit. Fix it. Signed-off-by: Dirk Behme Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/zforce_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/zforce_ts.c b/drivers/input/touchscreen/zforce_ts.c index d00e1e33b6576..0aa934c3540ef 100644 --- a/drivers/input/touchscreen/zforce_ts.c +++ b/drivers/input/touchscreen/zforce_ts.c @@ -510,7 +510,7 @@ static irqreturn_t zforce_irq_thread(int irq, void *dev_id) if (!ts->suspending && device_may_wakeup(&client->dev)) pm_stay_awake(&client->dev); - while (!gpiod_get_value_cansleep(ts->gpio_int)) { + while (gpiod_get_value_cansleep(ts->gpio_int)) { ret = zforce_read_packet(ts, payload_buffer); if (ret < 0) { dev_err(&client->dev, -- GitLab From 6ccfe64c770139675a080ee5029ded7d89d9ea0d Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 20 Jul 2015 09:56:18 -0700 Subject: [PATCH 1219/7006] Input: elan_i2c - enable ELAN0600 acpi panels ELAN0600 seems to work just fine in mouse emulation mode through i2c-hid, but to have full raw touch support we need to register it in elan_i2c.ko Reported-and-tested-by: Alessio Treglia Signed-off-by: Benjamin Tissoires Acked-by: Jiri Kosina Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-core.c | 1 + drivers/input/mouse/elan_i2c_core.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 56ce8c2b5530d..f3133e49ba0cf 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2238,6 +2238,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index e7ef4ab1b37d1..4a5d6ee5caaf0 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1167,6 +1167,7 @@ MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0000", 0 }, + { "ELAN0600", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, elan_acpi_id); -- GitLab From a11244c0b25b79d2a3b07df429268d66736e5b45 Mon Sep 17 00:00:00 2001 From: Sandeep Paulraj Date: Tue, 19 Aug 2014 15:31:54 +0300 Subject: [PATCH 1220/7006] nand: davinci: add support for 4K page size nand devices It is needed for k2l keystone2 EVM which uses NAND flash with 4K page size, hence add support for 4K page size nand devices. [Brian: similar work submitted by Murali Karicheri and Hao Zhang ] Signed-off-by: Sandeep Paulraj Signed-off-by: Ivan Khoronzhuk Signed-off-by: Brian Norris --- drivers/mtd/nand/davinci_nand.c | 42 ++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/nand/davinci_nand.c b/drivers/mtd/nand/davinci_nand.c index feb6d18de78d5..b90801302df4e 100644 --- a/drivers/mtd/nand/davinci_nand.c +++ b/drivers/mtd/nand/davinci_nand.c @@ -520,6 +520,32 @@ static struct nand_ecclayout hwecc4_2048 = { }, }; +/* + * An ECC layout for using 4-bit ECC with large-page (4096bytes) flash, + * storing ten ECC bytes plus the manufacturer's bad block marker byte, + * and not overlapping the default BBT markers. + */ +static struct nand_ecclayout hwecc4_4096 = { + .eccbytes = 80, + .eccpos = { + /* at the end of spare sector */ + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, + 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, + 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, + 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, + 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, + }, + .oobfree = { + /* 2 bytes at offset 0 hold manufacturer badblock markers */ + {.offset = 2, .length = 46, }, + /* 5 bytes at offset 8 hold BBT markers */ + /* 8 bytes at offset 16 hold JFFS2 clean markers */ + }, +}; + #if defined(CONFIG_OF) static const struct of_device_id davinci_nand_of_match[] = { {.compatible = "ti,davinci-nand", }, @@ -796,18 +822,12 @@ static int nand_davinci_probe(struct platform_device *pdev) info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; goto syndrome_done; } + if (chunks == 8) { + info->ecclayout = hwecc4_4096; + info->chip.ecc.mode = NAND_ECC_HW_OOB_FIRST; + goto syndrome_done; + } - /* 4KiB page chips are not yet supported. The eccpos from - * nand_ecclayout cannot hold 80 bytes and change to eccpos[] - * breaks userspace ioctl interface with mtd-utils. Once we - * resolve this issue, NAND_ECC_HW_OOB_FIRST mode can be used - * for the 4KiB page chips. - * - * TODO: Note that nand_ecclayout has now been expanded and can - * hold plenty of OOB entries. - */ - dev_warn(&pdev->dev, "no 4-bit ECC support yet " - "for 4KiB-page NAND\n"); ret = -EIO; goto err; -- GitLab From f136dce45116027fec65c342fbcb5aaa900729c6 Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Mon, 20 Jul 2015 09:32:05 +0800 Subject: [PATCH 1221/7006] ASoC: rt5645: Remove return value in jack detect work "ASoC: rt5645: Check if codec is initialized in workqueue handler" adds a check if codec is NULL in rt5645_irq_detection, which returns an int. However, "ASoC: rt5645: Remove irq_jack_detection function" removes that function, and moves the code in jack_detect_work, which returns void. Remove the return value to fix compilation warning. Signed-off-by: Nicolas Boichat Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 19392b13bd5b5..2ee42781cc52f 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2928,7 +2928,7 @@ static void rt5645_jack_detect_work(struct work_struct *work) int val, btn_type, gpio_state = 0, report = 0; if (!rt5645->codec) - return -EINVAL; + return; switch (rt5645->pdata.jd_mode) { case 0: /* Not using rt5645 JD */ -- GitLab From 49bdb0440541ad1144ad08d5613f9a28bcd2a8dc Mon Sep 17 00:00:00 2001 From: zhengxing Date: Sun, 19 Jul 2015 19:33:48 +0800 Subject: [PATCH 1222/7006] ASoC: rockchip: Add machine driver for max98090 codec The driver is used for rockchip board using a max98090. Reviewed-by: Dylan Reid Signed-off-by: zhengxing Signed-off-by: Mark Brown --- .../bindings/sound/rockchip-max98090.txt | 19 ++ sound/soc/rockchip/Kconfig | 10 + sound/soc/rockchip/Makefile | 4 + sound/soc/rockchip/rockchip_max98090.c | 236 ++++++++++++++++++ 4 files changed, 269 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98090.txt create mode 100644 sound/soc/rockchip/rockchip_max98090.c diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98090.txt b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt new file mode 100644 index 0000000000000..a805aa99ad751 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip-max98090.txt @@ -0,0 +1,19 @@ +ROCKCHIP with MAX98090 CODEC + +Required properties: +- compatible: "rockchip,rockchip-audio-max98090" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the MAX98090 audio codec +- rockchip,headset-codec: The phandle of Ext chip for jack detection + +Example: + +sound { + compatible = "rockchip,rockchip-audio-max98090"; + rockchip,model = "ROCKCHIP-I2S"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&max98090>; + rockchip,headset-codec = <&headsetcodec>; +}; diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index e18182699d835..d12356617fc75 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -14,3 +14,13 @@ config SND_SOC_ROCKCHIP_I2S Say Y or M if you want to add support for I2S driver for Rockchip I2S device. The device supports upto maximum of 8 channels each for play and record. + +config SND_SOC_ROCKCHIP_MAX98090 + tristate "ASoC support for Rockchip boards using a MAX98090 codec" + depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB + select SND_SOC_ROCKCHIP_I2S + select SND_SOC_MAX98090 + select SND_SOC_TS3A227E + help + Say Y or M here if you want to add support for SoC audio on Rockchip + boards using the MAX98090 codec, such as Veyron. diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index b9219092b47fd..df3445b53806c 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -2,3 +2,7 @@ snd-soc-i2s-objs := rockchip_i2s.o obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o + +snd-soc-rockchip-max98090-objs := rockchip_max98090.o + +obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c new file mode 100644 index 0000000000000..acace20d4127d --- /dev/null +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -0,0 +1,236 @@ +/* + * Rockchip machine ASoC driver for boards using a MAX90809 CODEC. + * + * Copyright (c) 2014, ROCKCHIP CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rockchip_i2s.h" +#include "../codecs/ts3a227e.h" + +#define DRV_NAME "rockchip-snd-max98090" + +static struct snd_soc_jack headset_jack; +static struct snd_soc_jack_pin headset_jack_pins[] = { + { + .pin = "Headset Jack", + .mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + }, +}; + +static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphone", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), + SND_SOC_DAPM_SPK("Speaker", NULL), +}; + +static const struct snd_soc_dapm_route rk_audio_map[] = { + {"IN34", NULL, "Headset Mic"}, + {"IN34", NULL, "MICBIAS"}, + {"MICBIAS", NULL, "Headset Mic"}, + {"DMICL", NULL, "Int Mic"}, + {"Headphone", NULL, "HPL"}, + {"Headphone", NULL, "HPR"}, + {"Speaker", NULL, "SPKL"}, + {"Speaker", NULL, "SPKR"}, +}; + +static const struct snd_kcontrol_new rk_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphone"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), + SOC_DAPM_PIN_SWITCH("Speaker"), +}; + +static int rk_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int mclk; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + mclk = 12288000; + break; + case 44100: + mclk = 11289600; + break; + default: + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + return ret; +} + +static int rk_init(struct snd_soc_pcm_runtime *runtime) +{ + /* Enable Headset and 4 Buttons Jack detection */ + return snd_soc_card_jack_new(runtime->card, "Headset Jack", + SND_JACK_HEADSET | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, + headset_jack_pins, + ARRAY_SIZE(headset_jack_pins)); +} + +static int rk_98090_headset_init(struct snd_soc_component *component) +{ + return ts3a227e_enable_jack_detect(component, &headset_jack); +} + +static struct snd_soc_ops rk_aif1_ops = { + .hw_params = rk_aif1_hw_params, +}; + +static struct snd_soc_aux_dev rk_98090_headset_dev = { + .name = "Headset Chip", + .init = rk_98090_headset_init, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "max98090", + .stream_name = "Audio", + .codec_dai_name = "HiFi", + .init = rk_init, + .ops = &rk_aif1_ops, + /* set max98090 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_card_rk = { + .name = "ROCKCHIP-I2S", + .dai_link = &rk_dailink, + .num_links = 1, + .aux_dev = &rk_98090_headset_dev, + .num_aux_devs = 1, + .dapm_widgets = rk_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets), + .dapm_routes = rk_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_audio_map), + .controls = rk_mc_controls, + .num_controls = ARRAY_SIZE(rk_mc_controls), +}; + +static int snd_rk_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct snd_soc_card *card = &snd_soc_card_rk; + struct device_node *np = pdev->dev.of_node; + + /* register the soc card */ + card->dev = &pdev->dev; + + rk_dailink.codec_of_node = of_parse_phandle(np, + "rockchip,audio-codec", 0); + if (!rk_dailink.codec_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,audio-codec' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.cpu_of_node = of_parse_phandle(np, + "rockchip,i2s-controller", 0); + if (!rk_dailink.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,i2s-controller' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.platform_of_node = rk_dailink.cpu_of_node; + + rk_98090_headset_dev.codec_of_node = of_parse_phandle(np, + "rockchip,headset-codec", 0); + if (!rk_98090_headset_dev.codec_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,headset-codec' missing/invalid\n"); + return -EINVAL; + } + + ret = snd_soc_of_parse_card_name(card, "rockchip,model"); + if (ret) { + dev_err(&pdev->dev, + "Soc parse card name failed %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, + "Soc register card failed %d\n", ret); + return ret; + } + + return ret; +} + +static const struct of_device_id rockchip_max98090_of_match[] = { + { .compatible = "rockchip,rockchip-audio-max98090", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_max98090_of_match); + +static struct platform_driver snd_rk_mc_driver = { + .probe = snd_rk_mc_probe, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = rockchip_max98090_of_match, + }, +}; + +module_platform_driver(snd_rk_mc_driver); + +MODULE_AUTHOR("jianqun "); +MODULE_DESCRIPTION("Rockchip max98090 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- GitLab From 86059653ea7ca7b30ed25d6bec5807ba59a4f2e6 Mon Sep 17 00:00:00 2001 From: zhengxing Date: Sun, 19 Jul 2015 19:33:49 +0800 Subject: [PATCH 1223/7006] ASoC: rockchip: Add machine driver for rt5645/rt5650 codec The driver is used for rockchip board using a rt5645/rt5650. Reviewed-by: Dylan Reid Signed-off-by: zhengxing Signed-off-by: Mark Brown --- .../bindings/sound/rockchip-rt5645.txt | 17 ++ sound/soc/rockchip/Kconfig | 9 + sound/soc/rockchip/Makefile | 2 + sound/soc/rockchip/rockchip_rt5645.c | 225 ++++++++++++++++++ 4 files changed, 253 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/rockchip-rt5645.txt create mode 100644 sound/soc/rockchip/rockchip_rt5645.c diff --git a/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt b/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt new file mode 100644 index 0000000000000..411a62b3ff414 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip-rt5645.txt @@ -0,0 +1,17 @@ +ROCKCHIP with RT5645/RT5650 CODECS + +Required properties: +- compatible: "rockchip,rockchip-audio-rt5645" +- rockchip,model: The user-visible name of this sound complex +- rockchip,i2s-controller: The phandle of the Rockchip I2S controller that's + connected to the CODEC +- rockchip,audio-codec: The phandle of the RT5645/RT5650 audio codec + +Example: + +sound { + compatible = "rockchip,rockchip-audio-rt5645"; + rockchip,model = "ROCKCHIP-I2S"; + rockchip,i2s-controller = <&i2s>; + rockchip,audio-codec = <&rt5645>; +}; diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig index d12356617fc75..58bae8e2cf5ff 100644 --- a/sound/soc/rockchip/Kconfig +++ b/sound/soc/rockchip/Kconfig @@ -24,3 +24,12 @@ config SND_SOC_ROCKCHIP_MAX98090 help Say Y or M here if you want to add support for SoC audio on Rockchip boards using the MAX98090 codec, such as Veyron. + +config SND_SOC_ROCKCHIP_RT5645 + tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec" + depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB + select SND_SOC_ROCKCHIP_I2S + select SND_SOC_RT5645 + help + Say Y or M here if you want to add support for SoC audio on Rockchip + boards using the RT5645/RT5650 codec, such as Veyron. diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile index df3445b53806c..1bc1dc3c729a4 100644 --- a/sound/soc/rockchip/Makefile +++ b/sound/soc/rockchip/Makefile @@ -4,5 +4,7 @@ snd-soc-i2s-objs := rockchip_i2s.o obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-i2s.o snd-soc-rockchip-max98090-objs := rockchip_max98090.o +snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o +obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c new file mode 100644 index 0000000000000..3c6bb1ea06ece --- /dev/null +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -0,0 +1,225 @@ +/* + * Rockchip machine ASoC driver for boards using a RT5645/RT5650 CODEC. + * + * Copyright (c) 2015, ROCKCHIP CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "rockchip_i2s.h" + +#define DRV_NAME "rockchip-snd-rt5645" + +static struct snd_soc_jack headset_jack; + +/* Jack detect via rt5645 driver. */ +extern int rt5645_set_jack_detect(struct snd_soc_codec *codec, + struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack, + struct snd_soc_jack *btn_jack); + +static const struct snd_soc_dapm_widget rk_dapm_widgets[] = { + SND_SOC_DAPM_HP("Headphones", NULL), + SND_SOC_DAPM_SPK("Speakers", NULL), + SND_SOC_DAPM_MIC("Headset Mic", NULL), + SND_SOC_DAPM_MIC("Int Mic", NULL), +}; + +static const struct snd_soc_dapm_route rk_audio_map[] = { + /* Input Lines */ + {"DMIC L2", NULL, "Int Mic"}, + {"DMIC R2", NULL, "Int Mic"}, + {"RECMIXL", NULL, "Headset Mic"}, + {"RECMIXR", NULL, "Headset Mic"}, + + /* Output Lines */ + {"Headphones", NULL, "HPOR"}, + {"Headphones", NULL, "HPOL"}, + {"Speakers", NULL, "SPOL"}, + {"Speakers", NULL, "SPOR"}, +}; + +static const struct snd_kcontrol_new rk_mc_controls[] = { + SOC_DAPM_PIN_SWITCH("Headphones"), + SOC_DAPM_PIN_SWITCH("Speakers"), + SOC_DAPM_PIN_SWITCH("Headset Mic"), + SOC_DAPM_PIN_SWITCH("Int Mic"), +}; + +static int rk_aif1_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + int ret = 0; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_dai *cpu_dai = rtd->cpu_dai; + struct snd_soc_dai *codec_dai = rtd->codec_dai; + int mclk; + + switch (params_rate(params)) { + case 8000: + case 16000: + case 48000: + case 96000: + mclk = 12288000; + break; + case 44100: + mclk = 11289600; + break; + default: + return -EINVAL; + } + + ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, + SND_SOC_CLOCK_OUT); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, + SND_SOC_CLOCK_IN); + if (ret < 0) { + dev_err(codec_dai->dev, "Can't set codec clock %d\n", ret); + return ret; + } + + return ret; +} + +static int rk_init(struct snd_soc_pcm_runtime *runtime) +{ + struct snd_soc_card *card = runtime->card; + int ret; + + /* Enable Headset and 4 Buttons Jack detection */ + ret = snd_soc_card_jack_new(card, "Headset Jack", + SND_JACK_HEADPHONE | SND_JACK_MICROPHONE | + SND_JACK_BTN_0 | SND_JACK_BTN_1 | + SND_JACK_BTN_2 | SND_JACK_BTN_3, + &headset_jack, NULL, 0); + if (!ret) { + dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); + return ret; + } + + return rt5645_set_jack_detect(runtime->codec, + &headset_jack, + &headset_jack, + &headset_jack); +} + +static struct snd_soc_ops rk_aif1_ops = { + .hw_params = rk_aif1_hw_params, +}; + +static struct snd_soc_dai_link rk_dailink = { + .name = "rt5645", + .stream_name = "rt5645 PCM", + .codec_dai_name = "rt5645-aif1", + .init = rk_init, + .ops = &rk_aif1_ops, + /* set rt5645 as slave */ + .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS, +}; + +static struct snd_soc_card snd_soc_card_rk = { + .name = "I2S-RT5650", + .dai_link = &rk_dailink, + .num_links = 1, + .dapm_widgets = rk_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(rk_dapm_widgets), + .dapm_routes = rk_audio_map, + .num_dapm_routes = ARRAY_SIZE(rk_audio_map), + .controls = rk_mc_controls, + .num_controls = ARRAY_SIZE(rk_mc_controls), +}; + +static int snd_rk_mc_probe(struct platform_device *pdev) +{ + int ret = 0; + struct snd_soc_card *card = &snd_soc_card_rk; + struct device_node *np = pdev->dev.of_node; + + /* register the soc card */ + card->dev = &pdev->dev; + + rk_dailink.codec_of_node = of_parse_phandle(np, + "rockchip,audio-codec", 0); + if (!rk_dailink.codec_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,audio-codec' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.cpu_of_node = of_parse_phandle(np, + "rockchip,i2s-controller", 0); + if (!rk_dailink.cpu_of_node) { + dev_err(&pdev->dev, + "Property 'rockchip,i2s-controller' missing or invalid\n"); + return -EINVAL; + } + + rk_dailink.platform_of_node = rk_dailink.cpu_of_node; + + ret = snd_soc_of_parse_card_name(card, "rockchip,model"); + if (ret) { + dev_err(&pdev->dev, + "Soc parse card name failed %d\n", ret); + return ret; + } + + ret = devm_snd_soc_register_card(&pdev->dev, card); + if (ret) { + dev_err(&pdev->dev, + "Soc register card failed %d\n", ret); + return ret; + } + + return ret; +} + +static const struct of_device_id rockchip_rt5645_of_match[] = { + { .compatible = "rockchip,rockchip-audio-rt5645", }, + {}, +}; + +MODULE_DEVICE_TABLE(of, rockchip_rt5645_of_match); + +static struct platform_driver snd_rk_mc_driver = { + .probe = snd_rk_mc_probe, + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + .pm = &snd_soc_pm_ops, + .of_match_table = rockchip_rt5645_of_match, + }, +}; + +module_platform_driver(snd_rk_mc_driver); + +MODULE_AUTHOR("Xing Zheng "); +MODULE_DESCRIPTION("Rockchip rt5645 machine ASoC driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRV_NAME); -- GitLab From cb2510dac7e1c5ac77652bb31e8c39ce2eef8bbe Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 19 Jul 2015 12:15:17 +0200 Subject: [PATCH 1224/7006] ASoC: cs4349: Fix suspend/resume dev_get_drvdata() will not return the snd_soc_runtime to which this CODEC is attached, so the current code will result in undefined behavior. To fix this just use regmap_update_bits(cs4349->regmap, ...) directly instead of snd_soc_update_bits(rtd->codec, ...). Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index f4fccc621ceb0..13ccbf75207ea 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -328,10 +328,9 @@ static int cs4349_i2c_remove(struct i2c_client *client) static int cs4349_runtime_suspend(struct device *dev) { struct cs4349_private *cs4349 = dev_get_drvdata(dev); - struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); int ret; - ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 1); + ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 1); if (ret < 0) return ret; @@ -347,10 +346,9 @@ static int cs4349_runtime_suspend(struct device *dev) static int cs4349_runtime_resume(struct device *dev) { struct cs4349_private *cs4349 = dev_get_drvdata(dev); - struct snd_soc_pcm_runtime *rtd = dev_get_drvdata(dev); int ret; - ret = snd_soc_update_bits(rtd->codec, CS4349_MISC, PWR_DWN, 0); + ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 0); if (ret < 0) return ret; -- GitLab From dedae86d4da6c88ec2105e0bd038acc57c203bca Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sun, 19 Jul 2015 12:15:18 +0200 Subject: [PATCH 1225/7006] ASoC: cs4349: Don't use rtd->codec rtd->codec does not necessarily point to the CODEC instance for which the callback was called (e.g. for CODEC<->CODEC or multi-CODEC links). Use dai->codec instead. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 13ccbf75207ea..ab071675357ee 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -94,8 +94,7 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = substream->private_data; - struct snd_soc_codec *codec = rtd->codec; + struct snd_soc_codec *codec = dai->codec; struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); int mode, fmt, ret; -- GitLab From da304ac37efc1900892b5067c65f0ab8acfe3955 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 22:42:49 +0800 Subject: [PATCH 1226/7006] ASoC: cs4349: Fix setting digital interface format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mode Control - Register 02h Digital Interface Format (DIF[2:0]) Bits 6-4 DIF2 DIF1 DIF0 Description 0 0 0 Left-Justified, up to 24-bit data 0 0 1 I²S, up to 24-bit data 0 1 0 Right-Justified, 16-bit data 0 1 1 Right-Justified, 24-bit data 1 0 0 TDM slot 0 1 0 1 TDM slot 1 1 1 0 TDM slot 2 1 1 1 TDM slot 3 The DIF_MASK is 0x70, so current code does not correctly set the DIFx setting. Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index ab071675357ee..4885695e35a73 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -96,17 +96,16 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, { struct snd_soc_codec *codec = dai->codec; struct cs4349_private *cs4349 = snd_soc_codec_get_drvdata(codec); - int mode, fmt, ret; + int fmt, ret; - mode = snd_soc_read(codec, CS4349_MODE); cs4349->rate = params_rate(params); switch (cs4349->mode) { case SND_SOC_DAIFMT_I2S: - mode |= MODE_FORMAT(DIF_I2S); + fmt = DIF_I2S; break; case SND_SOC_DAIFMT_LEFT_J: - mode |= MODE_FORMAT(DIF_LEFT_JST); + fmt = DIF_LEFT_JST; break; case SND_SOC_DAIFMT_RIGHT_J: switch (params_width(params)) { @@ -119,13 +118,13 @@ static int cs4349_pcm_hw_params(struct snd_pcm_substream *substream, default: return -EINVAL; } - mode |= MODE_FORMAT(fmt); break; default: return -EINVAL; } - ret = snd_soc_write(codec, CS4349_MODE, mode); + ret = snd_soc_update_bits(codec, CS4349_MODE, DIF_MASK, + MODE_FORMAT(fmt)); if (ret < 0) return ret; -- GitLab From 4313489c25622b05adac55dbb9590fb5674c3f45 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 19 Jul 2015 21:12:16 +0200 Subject: [PATCH 1227/7006] ASoC: ux500: adjust devm usage The explicit call to devm_regulator_put in the probe and remove functions does not seem to be necessary. In particular, the functions prcmu_qos_remove_requirement and ux500_msp_i2s_cleanup_msp in the remove function seem to do nothing that can interfere with devm_regulator_put, making it safe to allow devm_regulator_put to occur after the end of the remove function. Convert the calls to clk_get to devm_clk_get, and remove the corresponding calls to clk_put in the probe and remove functions. Replace various gotos by direct returns, and drop unneeded labels. Signed-off-by: Julia Lawall Reviewed-by: Ulf Hansson Signed-off-by: Mark Brown --- sound/soc/ux500/ux500_msp_dai.c | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/sound/soc/ux500/ux500_msp_dai.c b/sound/soc/ux500/ux500_msp_dai.c index 978f2d7316b06..f5df08ded770e 100644 --- a/sound/soc/ux500/ux500_msp_dai.c +++ b/sound/soc/ux500/ux500_msp_dai.c @@ -773,20 +773,22 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) } prcmu_qos_add_requirement(PRCMU_QOS_APE_OPP, (char *)pdev->name, 50); - drvdata->pclk = clk_get(&pdev->dev, "apb_pclk"); + drvdata->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); if (IS_ERR(drvdata->pclk)) { ret = (int)PTR_ERR(drvdata->pclk); - dev_err(&pdev->dev, "%s: ERROR: clk_get of pclk failed (%d)!\n", + dev_err(&pdev->dev, + "%s: ERROR: devm_clk_get of pclk failed (%d)!\n", __func__, ret); - goto err_pclk; + return ret; } - drvdata->clk = clk_get(&pdev->dev, NULL); + drvdata->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(drvdata->clk)) { ret = (int)PTR_ERR(drvdata->clk); - dev_err(&pdev->dev, "%s: ERROR: clk_get failed (%d)!\n", + dev_err(&pdev->dev, + "%s: ERROR: devm_clk_get failed (%d)!\n", __func__, ret); - goto err_clk; + return ret; } ret = ux500_msp_i2s_init_msp(pdev, &drvdata->msp, @@ -795,7 +797,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) dev_err(&pdev->dev, "%s: ERROR: Failed to init MSP-struct (%d)!", __func__, ret); - goto err_init_msp; + return ret; } dev_set_drvdata(&pdev->dev, drvdata); @@ -804,7 +806,7 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Error: %s: Failed to register MSP%d!\n", __func__, drvdata->msp->id); - goto err_init_msp; + return ret; } ret = ux500_pcm_register_platform(pdev); @@ -819,13 +821,6 @@ static int ux500_msp_drv_probe(struct platform_device *pdev) err_reg_plat: snd_soc_unregister_component(&pdev->dev); -err_init_msp: - clk_put(drvdata->clk); -err_clk: - clk_put(drvdata->pclk); -err_pclk: - devm_regulator_put(drvdata->reg_vape); - return ret; } @@ -837,12 +832,8 @@ static int ux500_msp_drv_remove(struct platform_device *pdev) snd_soc_unregister_component(&pdev->dev); - devm_regulator_put(drvdata->reg_vape); prcmu_qos_remove_requirement(PRCMU_QOS_APE_OPP, "ux500_msp_i2s"); - clk_put(drvdata->clk); - clk_put(drvdata->pclk); - ux500_msp_i2s_cleanup_msp(pdev, drvdata->msp); return 0; -- GitLab From 0443de7e7e559eab7df2566d0e46940f753db51d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 09:14:23 +0800 Subject: [PATCH 1228/7006] ASoC: cs4349: Set .writeable_reg for cs4349_regmap The first valid register index is 1 rather than 0, and the CS4349_CHIPID is readonly. So set .writeable_reg to avoid writing to these registers. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 4885695e35a73..a6604a34db347 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -54,14 +54,17 @@ struct cs4349_private { static bool cs4349_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS4349_CHIPID: - case CS4349_MODE: - case CS4349_VMI: - case CS4349_MUTE: - case CS4349_VOLA: - case CS4349_VOLB: - case CS4349_RMPFLT: - case CS4349_MISC: + case CS4349_CHIPID ... CS4349_MISC: + return true; + default: + return false; + } +} + +static bool cs4349_writeable_register(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS4349_MODE ... CS4349_MISC: return true; default: return false; @@ -270,6 +273,7 @@ static const struct regmap_config cs4349_regmap = { .reg_defaults = cs4349_reg_defaults, .num_reg_defaults = ARRAY_SIZE(cs4349_reg_defaults), .readable_reg = cs4349_readable_register, + .writeable_reg = cs4349_writeable_register, .cache_type = REGCACHE_RBTREE, }; -- GitLab From 44251551dfca2117e42349136b871b33c8419a59 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 09:15:38 +0800 Subject: [PATCH 1229/7006] ASoC: cs4349: Drop platform data support The struct cs4349_platform_data should be defined in a public header in include/sound/ rather than in sound/soc/codecs folder. In additional, the platform data support is not properly handled in this driver so remove it now. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 7 +------ sound/soc/codecs/cs4349.h | 7 ------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a6604a34db347..2569010ee3962 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -45,7 +45,6 @@ static const struct reg_default cs4349_reg_defaults[] = { /* Private data for the CS4349 */ struct cs4349_private { struct regmap *regmap; - struct cs4349_platform_data pdata; struct gpio_desc *reset_gpio; unsigned int mode; int rate; @@ -281,8 +280,7 @@ static int cs4349_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct cs4349_private *cs4349; - struct cs4349_platform_data *pdata = dev_get_platdata(&client->dev); - int ret = 0; + int ret; cs4349 = devm_kzalloc(&client->dev, sizeof(*cs4349), GFP_KERNEL); if (!cs4349) @@ -295,9 +293,6 @@ static int cs4349_i2c_probe(struct i2c_client *client, return ret; } - if (pdata) - cs4349->pdata = *pdata; - /* Reset the Device */ cs4349->reset_gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW); diff --git a/sound/soc/codecs/cs4349.h b/sound/soc/codecs/cs4349.h index 7effa0acec28e..d58c06a25358e 100644 --- a/sound/soc/codecs/cs4349.h +++ b/sound/soc/codecs/cs4349.h @@ -19,13 +19,6 @@ #ifndef __CS4349_H__ #define __CS4349_H__ -struct cs4349_platform_data { - - /* GPIO for Reset */ - unsigned int gpio_nreset; - -}; - /* CS4349 registers addresses */ #define CS4349_CHIPID 0x01 /* Device and Rev ID, Read Only */ #define CS4349_MODE 0x02 /* Mode Control */ -- GitLab From 091571d071a435a517aec42c4f8c56883c5dc531 Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Fri, 17 Jul 2015 15:43:46 -0700 Subject: [PATCH 1230/7006] ASoC: cs4349: include gpio/consumer.h s390 allmodconfig: sound/soc/codecs/cs4349.c: In function 'cs4349_i2c_probe': sound/soc/codecs/cs4349.c:300: error: implicit declaration of function 'devm_gpiod_get_optional' sound/soc/codecs/cs4349.c:301: error: 'GPIOD_OUT_LOW' undeclared (first use in this function) sound/soc/codecs/cs4349.c:301: error: (Each undeclared identifier is reported only once sound/soc/codecs/cs4349.c:301: error: for each function it appears in.) sound/soc/codecs/cs4349.c:306: error: implicit declaration of function 'gpiod_set_value_cansleep' Signed-off-by: Andrew Morton Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 2569010ee3962..a7538aea7f993 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include -- GitLab From cef1ed9c6bcf69245c0b9eb89b3f3a45049ba10c Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sun, 5 Jul 2015 09:57:41 +0800 Subject: [PATCH 1231/7006] mtd: r852: make ecc_reg 32-bit in r852_ecc_correct r852_ecc_correct() reads a 32-bit register into a 16-bit variable, ecc_reg, but this variable is later used as if it was larger. This is reported by clang when building the kernel with many warnings: drivers/mtd/nand/r852.c:512:11: error: shift count >= width of type [-Werror,-Wshift-count-overflow] ecc_reg >>= 16; ^ ~~ Fix this by making ecc_reg 32-bit, like the return type of r852_read_reg_dword(). Signed-off-by: Nicolas Iooss Signed-off-by: Brian Norris --- drivers/mtd/nand/r852.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/r852.c b/drivers/mtd/nand/r852.c index 77e96d2df96ca..cc6bac537f5a2 100644 --- a/drivers/mtd/nand/r852.c +++ b/drivers/mtd/nand/r852.c @@ -466,7 +466,7 @@ static int r852_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat, static int r852_ecc_correct(struct mtd_info *mtd, uint8_t *dat, uint8_t *read_ecc, uint8_t *calc_ecc) { - uint16_t ecc_reg; + uint32_t ecc_reg; uint8_t ecc_status, err_byte; int i, error = 0; -- GitLab From 038761dfe4ce145f0f080cc08ee43f6e0ab3ae2f Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Thu, 2 Jul 2015 11:37:56 +0200 Subject: [PATCH 1232/7006] mtd: fsl-quadspi: Actually clear TX FIFO upon write QUADSPI_MCR_CLR_TXF_MASK is the correct mask for clearing the TX FIFO. Signed-off-by: Alexander Stein Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 4fe13dd535f8b..1946c6da76cd7 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -539,7 +539,7 @@ static int fsl_qspi_nor_write(struct fsl_qspi *q, struct spi_nor *nor, /* clear the TX FIFO. */ tmp = readl(q->iobase + QUADSPI_MCR); - writel(tmp | QUADSPI_MCR_CLR_RXF_MASK, q->iobase + QUADSPI_MCR); + writel(tmp | QUADSPI_MCR_CLR_TXF_MASK, q->iobase + QUADSPI_MCR); /* fill the TX data to the FIFO */ for (j = 0, i = ((count + 3) / 4); j < i; j++) { -- GitLab From 0db7fae2736d0db920905c1fb576ec7eab2660c8 Mon Sep 17 00:00:00 2001 From: Alexey Firago Date: Tue, 30 Jun 2015 12:53:46 +0300 Subject: [PATCH 1233/7006] mtd: spi-nor: set SECT_4K for n25q064 SPI flash Micron n25q064 flash supports 4 KiB erase sectors. Signed-off-by: Alexey Firago Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d78831b4422b4..b2e8c3b72ea13 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -589,7 +589,7 @@ static const struct spi_device_id spi_nor_ids[] = { /* Micron */ { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, - { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) }, + { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, -- GitLab From 0642ef6f2992eba46c41abb5ceb7d4fa14ba888e Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 23 Jun 2015 14:32:54 +0100 Subject: [PATCH 1234/7006] debugfs: Export bool read/write functions The file read/write functions for bools have no special dependencies on debugfs internals and are sufficiently non-trivial to be worth exporting so clients can re-use the implementation. Signed-off-by: Richard Fitzgerald Acked-by: Greg Kroah-Hartman Signed-off-by: Mark Brown --- fs/debugfs/file.c | 14 ++++++++------ include/linux/debugfs.h | 20 ++++++++++++++++++++ 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 284f9aa0028b8..6c55ade071c39 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -435,8 +435,8 @@ struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, } EXPORT_SYMBOL_GPL(debugfs_create_atomic_t); -static ssize_t read_file_bool(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) +ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) { char buf[3]; u32 *val = file->private_data; @@ -449,9 +449,10 @@ static ssize_t read_file_bool(struct file *file, char __user *user_buf, buf[2] = 0x00; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } +EXPORT_SYMBOL_GPL(debugfs_read_file_bool); -static ssize_t write_file_bool(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) +ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) { char buf[32]; size_t buf_size; @@ -468,10 +469,11 @@ static ssize_t write_file_bool(struct file *file, const char __user *user_buf, return count; } +EXPORT_SYMBOL_GPL(debugfs_write_file_bool); static const struct file_operations fops_bool = { - .read = read_file_bool, - .write = write_file_bool, + .read = debugfs_read_file_bool, + .write = debugfs_write_file_bool, .open = simple_open, .llseek = default_llseek, }; diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index 420311bcee38c..9beb636b97ebc 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h @@ -116,6 +116,12 @@ struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name, bool debugfs_initialized(void); +ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos); + +ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos); + #else #include @@ -282,6 +288,20 @@ static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev, return ERR_PTR(-ENODEV); } +static inline ssize_t debugfs_read_file_bool(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + return -ENODEV; +} + +static inline ssize_t debugfs_write_file_bool(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + return -ENODEV; +} + #endif #endif -- GitLab From d3dc5430d68fb91a62d971648170b34d46ab85bc Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 23 Jun 2015 14:32:55 +0100 Subject: [PATCH 1235/7006] regmap: debugfs: Allow writes to cache state settings Allow the user to write the cache_only and cache_bypass settings. This can be useful for debugging. Since this can lead to the hardware getting out-of-sync with the cache, at least for the period that the cache state is forced, the kernel is tainted and the action is recorded in the kernel log. When disabling cache_only through debugfs a cache sync will be performed. Signed-off-by: Richard Fitzgerald Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-debugfs.c | 90 ++++++++++++++++++++++++++-- 1 file changed, 86 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 5799a0b9e6cc4..6a61e4fa73a28 100644 --- a/drivers/base/regmap/regmap-debugfs.c +++ b/drivers/base/regmap/regmap-debugfs.c @@ -469,6 +469,87 @@ static const struct file_operations regmap_access_fops = { .llseek = default_llseek, }; +static ssize_t regmap_cache_only_write_file(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = container_of(file->private_data, + struct regmap, cache_only); + ssize_t result; + bool was_enabled, require_sync = false; + int err; + + map->lock(map->lock_arg); + + was_enabled = map->cache_only; + + result = debugfs_write_file_bool(file, user_buf, count, ppos); + if (result < 0) { + map->unlock(map->lock_arg); + return result; + } + + if (map->cache_only && !was_enabled) { + dev_warn(map->dev, "debugfs cache_only=Y forced\n"); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } else if (!map->cache_only && was_enabled) { + dev_warn(map->dev, "debugfs cache_only=N forced: syncing cache\n"); + require_sync = true; + } + + map->unlock(map->lock_arg); + + if (require_sync) { + err = regcache_sync(map); + if (err) + dev_err(map->dev, "Failed to sync cache %d\n", err); + } + + return result; +} + +static const struct file_operations regmap_cache_only_fops = { + .open = simple_open, + .read = debugfs_read_file_bool, + .write = regmap_cache_only_write_file, +}; + +static ssize_t regmap_cache_bypass_write_file(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct regmap *map = container_of(file->private_data, + struct regmap, cache_bypass); + ssize_t result; + bool was_enabled; + + map->lock(map->lock_arg); + + was_enabled = map->cache_bypass; + + result = debugfs_write_file_bool(file, user_buf, count, ppos); + if (result < 0) + goto out; + + if (map->cache_bypass && !was_enabled) { + dev_warn(map->dev, "debugfs cache_bypass=Y forced\n"); + add_taint(TAINT_USER, LOCKDEP_STILL_OK); + } else if (!map->cache_bypass && was_enabled) { + dev_warn(map->dev, "debugfs cache_bypass=N forced\n"); + } + +out: + map->unlock(map->lock_arg); + + return result; +} + +static const struct file_operations regmap_cache_bypass_fops = { + .open = simple_open, + .read = debugfs_read_file_bool, + .write = regmap_cache_bypass_write_file, +}; + void regmap_debugfs_init(struct regmap *map, const char *name) { struct rb_node *next; @@ -530,12 +611,13 @@ void regmap_debugfs_init(struct regmap *map, const char *name) } if (map->cache_type) { - debugfs_create_bool("cache_only", 0400, map->debugfs, - &map->cache_only); + debugfs_create_file("cache_only", 0600, map->debugfs, + &map->cache_only, ®map_cache_only_fops); debugfs_create_bool("cache_dirty", 0400, map->debugfs, &map->cache_dirty); - debugfs_create_bool("cache_bypass", 0400, map->debugfs, - &map->cache_bypass); + debugfs_create_file("cache_bypass", 0600, map->debugfs, + &map->cache_bypass, + ®map_cache_bypass_fops); } next = rb_first(&map->range_tree); -- GitLab From 9c618292dba6aa9b82e8a2e4e6fe70f54bd87a81 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 26 Jun 2015 11:00:10 +0200 Subject: [PATCH 1236/7006] mtd: nand: sunxi: Replace failsafe timing cfg with calculated value The TIMING_CFG register was previously statically set to a magic value (extracted from Allwinner's BSP) when initializing the NAND controller. Now that we have more details about the TIMING_CFG register layout (extracted from the A83 user manual) we can dynamically calculate the appropriate value for each NAND chip and set it when selecting the chip. Signed-off-by: Roy Spliet Acked-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/sunxi_nand.c | 73 ++++++++++++++++++++++++++++++++--- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 6f93b2990d250..663e3314bb83d 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -99,6 +99,12 @@ NFC_CMD_INT_ENABLE | \ NFC_DMA_INT_ENABLE) +/* define NFC_TIMING_CFG register layout */ +#define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ + (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ + (((tWHR) & 0x3) << 4) | (((tRHW) & 0x3) << 6) | \ + (((tCAD) & 0x7) << 8)) + /* define bit use in NFC_CMD */ #define NFC_CMD_LOW_BYTE GENMASK(7, 0) #define NFC_CMD_HIGH_BYTE GENMASK(15, 8) @@ -208,6 +214,7 @@ struct sunxi_nand_hw_ecc { * @nand: base NAND chip structure * @mtd: base MTD structure * @clk_rate: clk_rate required for this NAND chip + * @timing_cfg TIMING_CFG register value for this NAND chip * @selected: current active CS * @nsels: number of CS lines required by the NAND chip * @sels: array of CS lines descriptions @@ -217,6 +224,7 @@ struct sunxi_nand_chip { struct nand_chip nand; struct mtd_info mtd; unsigned long clk_rate; + u32 timing_cfg; int selected; int nsels; struct sunxi_nand_chip_sel sels[0]; @@ -403,6 +411,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) } } + writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); writel(ctl, nfc->regs + NFC_REG_CTL); sunxi_nand->selected = chip; @@ -807,10 +816,33 @@ static int sunxi_nfc_hw_syndrome_ecc_write_page(struct mtd_info *mtd, return 0; } +static const s32 tWB_lut[] = {6, 12, 16, 20}; +static const s32 tRHW_lut[] = {4, 8, 12, 20}; + +static int _sunxi_nand_lookup_timing(const s32 *lut, int lut_size, u32 duration, + u32 clk_period) +{ + u32 clk_cycles = DIV_ROUND_UP(duration, clk_period); + int i; + + for (i = 0; i < lut_size; i++) { + if (clk_cycles <= lut[i]) + return i; + } + + /* Doesn't fit */ + return -EINVAL; +} + +#define sunxi_nand_lookup_timing(l, p, c) \ + _sunxi_nand_lookup_timing(l, ARRAY_SIZE(l), p, c) + static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, const struct nand_sdr_timings *timings) { + struct sunxi_nfc *nfc = to_sunxi_nfc(chip->nand.controller); u32 min_clk_period = 0; + s32 tWB, tADL, tWHR, tRHW, tCAD; /* T1 <=> tCLS */ if (timings->tCLS_min > min_clk_period) @@ -872,6 +904,41 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, if (timings->tWC_min > (min_clk_period * 2)) min_clk_period = DIV_ROUND_UP(timings->tWC_min, 2); + /* T16 - T19 + tCAD */ + tWB = sunxi_nand_lookup_timing(tWB_lut, timings->tWB_max, + min_clk_period); + if (tWB < 0) { + dev_err(nfc->dev, "unsupported tWB\n"); + return tWB; + } + + tADL = DIV_ROUND_UP(timings->tADL_min, min_clk_period) >> 3; + if (tADL > 3) { + dev_err(nfc->dev, "unsupported tADL\n"); + return -EINVAL; + } + + tWHR = DIV_ROUND_UP(timings->tWHR_min, min_clk_period) >> 3; + if (tWHR > 3) { + dev_err(nfc->dev, "unsupported tWHR\n"); + return -EINVAL; + } + + tRHW = sunxi_nand_lookup_timing(tRHW_lut, timings->tRHW_min, + min_clk_period); + if (tRHW < 0) { + dev_err(nfc->dev, "unsupported tRHW\n"); + return tRHW; + } + + /* + * TODO: according to ONFI specs this value only applies for DDR NAND, + * but Allwinner seems to set this to 0x7. Mimic them for now. + */ + tCAD = 0x7; + + /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ + chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); /* Convert min_clk_period from picoseconds to nanoseconds */ min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); @@ -884,8 +951,6 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, */ chip->clk_rate = (2 * NSEC_PER_SEC) / min_clk_period; - /* TODO: configure T16-T19 */ - return 0; } @@ -1377,11 +1442,9 @@ static int sunxi_nfc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nfc); /* - * TODO: replace these magic values with proper flags as soon as we - * know what they are encoding. + * TODO: replace this magic value with EDO flag */ writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); - writel(0x7ff, nfc->regs + NFC_REG_TIMING_CFG); ret = sunxi_nand_chips_init(dev, nfc); if (ret) { -- GitLab From d052e508a4069f0711ea68156f4b1565bf14c41c Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Fri, 26 Jun 2015 11:00:11 +0200 Subject: [PATCH 1237/7006] mtd: nand: sunxi: Set serial access mode correctly Replaces the hard coded "always use EDO" policy with that prescribed by the ONFI 3.1 specification that EDO mode should always be used if tRC is below 30ns. Signed-off-by: Roy Spliet Acked-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/sunxi_nand.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 663e3314bb83d..f97a58d6aae1b 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -99,6 +99,9 @@ NFC_CMD_INT_ENABLE | \ NFC_DMA_INT_ENABLE) +/* define bit use in NFC_TIMING_CTL */ +#define NFC_TIMING_CTL_EDO BIT(8) + /* define NFC_TIMING_CFG register layout */ #define NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD) \ (((tWB) & 0x3) | (((tADL) & 0x3) << 2) | \ @@ -225,6 +228,7 @@ struct sunxi_nand_chip { struct mtd_info mtd; unsigned long clk_rate; u32 timing_cfg; + u32 timing_ctl; int selected; int nsels; struct sunxi_nand_chip_sel sels[0]; @@ -411,6 +415,7 @@ static void sunxi_nfc_select_chip(struct mtd_info *mtd, int chip) } } + writel(sunxi_nand->timing_ctl, nfc->regs + NFC_REG_TIMING_CTL); writel(sunxi_nand->timing_cfg, nfc->regs + NFC_REG_TIMING_CFG); writel(ctl, nfc->regs + NFC_REG_CTL); @@ -940,6 +945,13 @@ static int sunxi_nand_chip_set_timings(struct sunxi_nand_chip *chip, /* TODO: A83 has some more bits for CDQSS, CS, CLHZ, CCS, WC */ chip->timing_cfg = NFC_TIMING_CFG(tWB, tADL, tWHR, tRHW, tCAD); + /* + * ONFI specification 3.1, paragraph 4.15.2 dictates that EDO data + * output cycle timings shall be used if the host drives tRC less than + * 30 ns. + */ + chip->timing_ctl = (timings->tRC_min < 30000) ? NFC_TIMING_CTL_EDO : 0; + /* Convert min_clk_period from picoseconds to nanoseconds */ min_clk_period = DIV_ROUND_UP(min_clk_period, 1000); @@ -1441,11 +1453,6 @@ static int sunxi_nfc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, nfc); - /* - * TODO: replace this magic value with EDO flag - */ - writel(0x100, nfc->regs + NFC_REG_TIMING_CTL); - ret = sunxi_nand_chips_init(dev, nfc); if (ret) { dev_err(dev, "failed to init nand chips\n"); -- GitLab From bf9185dda829b2aaf73e1e869891a968ff85e2ae Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Mon, 20 Jul 2015 18:36:15 +0100 Subject: [PATCH 1238/7006] ASoC: sti-uniperf: Fix implicit inclusion of pinctrl Reported-by: Stephen Rothwell Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 83a301f2aa66f..51f745c56c7fd 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -6,6 +6,7 @@ */ #include +#include #include "uniperif.h" -- GitLab From 4691b271ac3a3bdc0d7d886e4715163eb4fb4bc7 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Tue, 7 Jul 2015 10:13:02 +0800 Subject: [PATCH 1239/7006] nfsd: Fix a memory leak in nfsd4_list_rec_dir() If lookup_one_len() failed, nfsd should free those memory allocated for fname. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4recover.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index d88ea7b9a85cb..591bfbdf0316d 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -272,6 +272,7 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) .ctx.actor = nfsd4_build_namelist, .names = LIST_HEAD_INIT(ctx.names) }; + struct name_list *entry, *tmp; int status; status = nfs4_save_creds(&original_cred); @@ -286,9 +287,8 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) status = iterate_dir(nn->rec_file, &ctx.ctx); mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT); - while (!list_empty(&ctx.names)) { - struct name_list *entry; - entry = list_entry(ctx.names.next, struct name_list, list); + + list_for_each_entry_safe(entry, tmp, &ctx.names, list) { if (!status) { struct dentry *dentry; dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1); @@ -304,6 +304,12 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn) } mutex_unlock(&d_inode(dir)->i_mutex); nfs4_reset_creds(original_cred); + + list_for_each_entry_safe(entry, tmp, &ctx.names, list) { + dprintk("NFSD: %s. Left entry %s\n", __func__, entry->name); + list_del(&entry->list); + kfree(entry); + } return status; } -- GitLab From 28e51af7c608f661a728db9d47b33c54096fdc59 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 8 Jul 2015 16:27:56 -0400 Subject: [PATCH 1240/7006] Revert "Documentation: NFS/RDMA: Document separate Kconfig symbols" This reverts commit 731d5cca82729c85ca3296902a64836619f4ba2d. Commit ffe1f0df5862 ("rpcrdma: Merge svcrdma and xprtrdma modules into one") forgot to update the corresponding documentation. Reported-by: Valentin Rothberg Signed-off-by: J. Bruce Fields --- Documentation/filesystems/nfs/nfs-rdma.txt | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Documentation/filesystems/nfs/nfs-rdma.txt b/Documentation/filesystems/nfs/nfs-rdma.txt index 95c13aa575ff3..906b6c233f62f 100644 --- a/Documentation/filesystems/nfs/nfs-rdma.txt +++ b/Documentation/filesystems/nfs/nfs-rdma.txt @@ -138,9 +138,9 @@ Installation - Build, install, reboot The NFS/RDMA code will be enabled automatically if NFS and RDMA - are turned on. The NFS/RDMA client and server are configured via the - SUNRPC_XPRT_RDMA_CLIENT and SUNRPC_XPRT_RDMA_SERVER config options that both - depend on SUNRPC and INFINIBAND. The default value of both options will be: + are turned on. The NFS/RDMA client and server are configured via the hidden + SUNRPC_XPRT_RDMA config option that depends on SUNRPC and INFINIBAND. The + value of SUNRPC_XPRT_RDMA will be: - N if either SUNRPC or INFINIBAND are N, in this case the NFS/RDMA client and server will not be built @@ -238,9 +238,8 @@ NFS/RDMA Setup - Start the NFS server - If the NFS/RDMA server was built as a module - (CONFIG_SUNRPC_XPRT_RDMA_SERVER=m in kernel config), load the RDMA - transport module: + If the NFS/RDMA server was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in + kernel config), load the RDMA transport module: $ modprobe svcrdma @@ -259,9 +258,8 @@ NFS/RDMA Setup - On the client system - If the NFS/RDMA client was built as a module - (CONFIG_SUNRPC_XPRT_RDMA_CLIENT=m in kernel config), load the RDMA client - module: + If the NFS/RDMA client was built as a module (CONFIG_SUNRPC_XPRT_RDMA=m in + kernel config), load the RDMA client module: $ modprobe xprtrdma.ko -- GitLab From d8398fc11762d162b2e7b0f368278449899cfbdf Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Tue, 7 Jul 2015 10:12:03 +0800 Subject: [PATCH 1241/7006] nfsd: Set lc_size_chg before ops->proc_layoutcommit After proc_layoutcommit success, i_size_read(inode) always >= new_size. Just set lc_size_chg before proc_layoutcommit, if proc_layoutcommit failed, nfsd will skip the lc_size_chg, so it's no harm. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index 90cfda75313c4..d112c8a322d9f 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -1364,10 +1364,6 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, goto out; } - nfserr = ops->proc_layoutcommit(inode, lcp); - if (nfserr) - goto out_put_stid; - if (new_size > i_size_read(inode)) { lcp->lc_size_chg = 1; lcp->lc_newsize = new_size; @@ -1375,7 +1371,7 @@ nfsd4_layoutcommit(struct svc_rqst *rqstp, lcp->lc_size_chg = 0; } -out_put_stid: + nfserr = ops->proc_layoutcommit(inode, lcp); nfs4_put_stid(&ls->ls_stid); out: return nfserr; -- GitLab From faf996a654ac60983a24a9cdc5e0f3324e8a2b32 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 3 Jul 2015 19:34:53 +0800 Subject: [PATCH 1242/7006] nfsd: Drop including client's header file nfs_fs.h nfs_fs.h is a client's header file. # ll fs/nfsd/nfs4acl.o fs/nfsd/nfsd.ko -rw-r--r--. 1 root root 328248 Jul 3 19:26 fs/nfsd/nfs4acl.o -rw-r--r--. 1 root root 7452016 Jul 3 19:26 fs/nfsd/nfsd.ko After this patch, # ll fs/nfsd/nfs4acl.o fs/nfsd/nfsd.ko -rw-r--r--. 1 root root 150872 Jul 3 19:15 fs/nfsd/nfs4acl.o -rw-r--r--. 1 root root 7273792 Jul 3 19:23 fs/nfsd/nfsd.ko Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4acl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c index eb5accf1b37f5..4b939b09f3d0b 100644 --- a/fs/nfsd/nfs4acl.c +++ b/fs/nfsd/nfs4acl.c @@ -34,8 +34,10 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include #include -#include +#include + #include "nfsfh.h" #include "nfsd.h" #include "acl.h" -- GitLab From e446d66dd77fa8fbb505a9940bf637649c9b45f2 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 3 Jul 2015 19:36:14 +0800 Subject: [PATCH 1243/7006] nfsd: Remove duplicate define of IDMAP_NAMESZ/IDMAP_TYPE_xx Just using the macro defined in nfs_idmap.h. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/idmap.h | 4 +--- fs/nfsd/nfs4idmap.c | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/fs/nfsd/idmap.h b/fs/nfsd/idmap.h index a3f34900091f4..23cc85d1efdd6 100644 --- a/fs/nfsd/idmap.h +++ b/fs/nfsd/idmap.h @@ -37,9 +37,7 @@ #include #include - -/* XXX from linux/nfs_idmap.h */ -#define IDMAP_NAMESZ 128 +#include #ifdef CONFIG_NFSD_V4 int nfsd_idmap_init(struct net *); diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index e1b3d3d472da7..5b20577dcdd23 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -59,9 +59,6 @@ MODULE_PARM_DESC(nfs4_disable_idmapping, * that. */ -#define IDMAP_TYPE_USER 0 -#define IDMAP_TYPE_GROUP 1 - struct ent { struct cache_head h; int type; /* User / Group */ -- GitLab From 7b8f4586532f36c5541a15d072576e7e89a5df75 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Fri, 3 Jul 2015 19:39:02 +0800 Subject: [PATCH 1244/7006] nfsd: Add macro NFS_ACL_MASK for ACL Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs2acl.c | 10 ++++------ fs/nfsd/nfs3acl.c | 4 ++-- include/uapi/linux/nfsacl.h | 1 + 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index d54701f6dc787..1580ea6fd64df 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -44,13 +44,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp, inode = d_inode(fh->fh_dentry); - if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + if (argp->mask & ~NFS_ACL_MASK) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; nfserr = fh_getattr(fh, &resp->stat); if (nfserr) - goto fail; + RETURN_STATUS(nfserr); if (resp->mask & (NFS_ACL|NFS_ACLCNT)) { acl = get_acl(inode, ACL_TYPE_ACCESS); @@ -202,7 +202,7 @@ static int nfsaclsvc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, if (!p) return 0; argp->mask = ntohl(*p++); - if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || + if (argp->mask & ~NFS_ACL_MASK || !xdr_argsize_check(rqstp, p)) return 0; @@ -293,9 +293,7 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p, resp->acl_default, resp->mask & NFS_DFACL, NFS_ACL_DEFAULT); - if (n <= 0) - return 0; - return 1; + return (n > 0); } static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p, diff --git a/fs/nfsd/nfs3acl.c b/fs/nfsd/nfs3acl.c index 882b1a14bc3e8..01df4cd7c753f 100644 --- a/fs/nfsd/nfs3acl.c +++ b/fs/nfsd/nfs3acl.c @@ -41,7 +41,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp, inode = d_inode(fh->fh_dentry); - if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT)) + if (argp->mask & ~NFS_ACL_MASK) RETURN_STATUS(nfserr_inval); resp->mask = argp->mask; @@ -148,7 +148,7 @@ static int nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, __be32 *p, if (!p) return 0; args->mask = ntohl(*p++); - if (args->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT) || + if (args->mask & ~NFS_ACL_MASK || !xdr_argsize_check(rqstp, p)) return 0; diff --git a/include/uapi/linux/nfsacl.h b/include/uapi/linux/nfsacl.h index 9bb9771a107f2..5527266311624 100644 --- a/include/uapi/linux/nfsacl.h +++ b/include/uapi/linux/nfsacl.h @@ -22,6 +22,7 @@ #define NFS_ACLCNT 0x0002 #define NFS_DFACL 0x0004 #define NFS_DFACLCNT 0x0008 +#define NFS_ACL_MASK 0x000f /* Flag for Default ACL entries */ #define NFS_ACL_DEFAULT 0x1000 -- GitLab From ff79c74dcace8fec62706d0bef00b6680b477fdb Mon Sep 17 00:00:00 2001 From: Shirley Ma Date: Thu, 9 Jul 2015 16:45:08 -0400 Subject: [PATCH 1245/7006] NFS/RDMA Release resources in svcrdma when device is removed When removing underlying RDMA device, the rmmod will hang forever if there are any outstanding NFS/RDMA client mounts. The outstanding NFS/RDMA counts could also prevent the server from shutting down. Further debugging shows that the existing connections are not teared down and resource are not released when receiving RDMA_CM_EVENT_DEVICE_REMOVAL event. It seems the original code missing svc_xprt_put() in RDMA_CM_EVENT_REMOVAL event handler thus svc_xprt_free is never invoked to release the existing connection resources. The patch has been passed removing, adding device back and forth without stopping NFS/RDMA service. This will also allow a device to be unplugged and swapped out without shutting down NFS service. BugLink: https://bugzilla.linux-nfs.org/show_bug.cgi?id=252 Signed-off-by: Shirley Ma Reviewed-by: Chuck Lever Signed-off-by: J. Bruce Fields --- net/sunrpc/xprtrdma/svc_rdma_transport.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 6b36279e42885..f4b9732339777 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -659,6 +659,7 @@ static int rdma_cma_handler(struct rdma_cm_id *cma_id, if (xprt) { set_bit(XPT_CLOSE, &xprt->xpt_flags); svc_xprt_enqueue(xprt); + svc_xprt_put(xprt); } break; default: -- GitLab From 9d11b51ce7c150a69e761e30518f294fc73d55ff Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 9 Jul 2015 16:45:18 -0400 Subject: [PATCH 1246/7006] svcrdma: Fix send_reply() scatter/gather set-up The Linux NFS server returns garbage in the data payload of inline NFS/RDMA READ replies. These are READs of under 1000 bytes or so where the client has not provided either a reply chunk or a write list. The NFS server delivers the data payload for an NFS READ reply to the transport in an xdr_buf page list. If the NFS client did not provide a reply chunk or a write list, send_reply() is supposed to set up a separate sge for the page containing the READ data, and another sge for XDR padding if needed, then post all of the sges via a single SEND Work Request. The problem is send_reply() does not advance through the xdr_buf when setting up scatter/gather entries for SEND WR. It always calls dma_map_xdr with xdr_off set to zero. When there's more than one sge, dma_map_xdr() sets up the SEND sge's so they all point to the xdr_buf's head. The current Linux NFS/RDMA client always provides a reply chunk or a write list when performing an NFS READ over RDMA. Therefore, it does not exercise this particular case. The Linux server has never had to use more than one extra sge for building RPC/RDMA replies with a Linux client. However, an NFS/RDMA client _is_ allowed to send small NFS READs without setting up a write list or reply chunk. The NFS READ reply fits entirely within the inline reply buffer in this case. This is perhaps a more efficient way of performing NFS READs that the Linux NFS/RDMA client may some day adopt. Fixes: b432e6b3d9c1 ('svcrdma: Change DMA mapping logic to . . .') BugLink: https://bugzilla.linux-nfs.org/show_bug.cgi?id=285 Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index d25cd430f9ffb..95412abc95b0b 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -384,6 +384,7 @@ static int send_reply(struct svcxprt_rdma *rdma, int byte_count) { struct ib_send_wr send_wr; + u32 xdr_off; int sge_no; int sge_bytes; int page_no; @@ -418,8 +419,8 @@ static int send_reply(struct svcxprt_rdma *rdma, ctxt->direction = DMA_TO_DEVICE; /* Map the payload indicated by 'byte_count' */ + xdr_off = 0; for (sge_no = 1; byte_count && sge_no < vec->count; sge_no++) { - int xdr_off = 0; sge_bytes = min_t(size_t, vec->sge[sge_no].iov_len, byte_count); byte_count -= sge_bytes; ctxt->sge[sge_no].addr = @@ -457,6 +458,13 @@ static int send_reply(struct svcxprt_rdma *rdma, } rqstp->rq_next_page = rqstp->rq_respages + 1; + /* The loop above bumps sc_dma_used for each sge. The + * xdr_buf.tail gets a separate sge, but resides in the + * same page as xdr_buf.head. Don't count it twice. + */ + if (sge_no > ctxt->count) + atomic_dec(&rdma->sc_dma_used); + if (sge_no > rdma->sc_max_sge) { pr_err("svcrdma: Too many sges (%d)\n", sge_no); goto err; -- GitLab From 10dc4512185741a298cd7bc87e9968944f31a50d Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 9 Jul 2015 16:45:28 -0400 Subject: [PATCH 1247/7006] svcrdma: Clean up svc_rdma_get_reply_array() Kernel coding conventions frown upon having large nontrivial functions in header files, and the preference these days is to allow the compiler to make inlining decisions if possible. As these functions are re-homed into a .c file, be sure that comparisons with fields in struct rpcrdma_msg are with be32 constants. This is a refactoring change; no behavior change is intended. Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_rdma.h | 81 +-------------------------- net/sunrpc/xprtrdma/svc_rdma_sendto.c | 73 ++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 79 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index cb94ee4181d49..ca4d86a6c947f 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -213,6 +213,8 @@ extern int rdma_read_chunk_frmr(struct svcxprt_rdma *, struct svc_rqst *, /* svc_rdma_sendto.c */ extern int svc_rdma_sendto(struct svc_rqst *); +extern struct rpcrdma_read_chunk * + svc_rdma_get_read_chunk(struct rpcrdma_msg *); /* svc_rdma_transport.c */ extern int svc_rdma_send(struct svcxprt_rdma *, struct ib_send_wr *); @@ -238,83 +240,4 @@ extern void svc_rdma_prep_reply_hdr(struct svc_rqst *); extern int svc_rdma_init(void); extern void svc_rdma_cleanup(void); -/* - * Returns the address of the first read chunk or if no read chunk is - * present - */ -static inline struct rpcrdma_read_chunk * -svc_rdma_get_read_chunk(struct rpcrdma_msg *rmsgp) -{ - struct rpcrdma_read_chunk *ch = - (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; - - if (ch->rc_discrim == 0) - return NULL; - - return ch; -} - -/* - * Returns the address of the first read write array element or if no - * write array list is present - */ -static inline struct rpcrdma_write_array * -svc_rdma_get_write_array(struct rpcrdma_msg *rmsgp) -{ - if (rmsgp->rm_body.rm_chunks[0] != 0 - || rmsgp->rm_body.rm_chunks[1] == 0) - return NULL; - - return (struct rpcrdma_write_array *)&rmsgp->rm_body.rm_chunks[1]; -} - -/* - * Returns the address of the first reply array element or if no - * reply array is present - */ -static inline struct rpcrdma_write_array * -svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp) -{ - struct rpcrdma_read_chunk *rch; - struct rpcrdma_write_array *wr_ary; - struct rpcrdma_write_array *rp_ary; - - /* XXX: Need to fix when reply list may occur with read-list and/or - * write list */ - if (rmsgp->rm_body.rm_chunks[0] != 0 || - rmsgp->rm_body.rm_chunks[1] != 0) - return NULL; - - rch = svc_rdma_get_read_chunk(rmsgp); - if (rch) { - while (rch->rc_discrim) - rch++; - - /* The reply list follows an empty write array located - * at 'rc_position' here. The reply array is at rc_target. - */ - rp_ary = (struct rpcrdma_write_array *)&rch->rc_target; - - goto found_it; - } - - wr_ary = svc_rdma_get_write_array(rmsgp); - if (wr_ary) { - rp_ary = (struct rpcrdma_write_array *) - &wr_ary-> - wc_array[ntohl(wr_ary->wc_nchunks)].wc_target.rs_length; - - goto found_it; - } - - /* No read list, no write list */ - rp_ary = (struct rpcrdma_write_array *) - &rmsgp->rm_body.rm_chunks[2]; - - found_it: - if (rp_ary->wc_discrim == 0) - return NULL; - - return rp_ary; -} #endif diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 95412abc95b0b..1dfae83170650 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -136,6 +136,79 @@ static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt, return dma_addr; } +/* Returns the address of the first read chunk or if no read chunk + * is present + */ +struct rpcrdma_read_chunk * +svc_rdma_get_read_chunk(struct rpcrdma_msg *rmsgp) +{ + struct rpcrdma_read_chunk *ch = + (struct rpcrdma_read_chunk *)&rmsgp->rm_body.rm_chunks[0]; + + if (ch->rc_discrim == xdr_zero) + return NULL; + return ch; +} + +/* Returns the address of the first read write array element or + * if no write array list is present + */ +static struct rpcrdma_write_array * +svc_rdma_get_write_array(struct rpcrdma_msg *rmsgp) +{ + if (rmsgp->rm_body.rm_chunks[0] != xdr_zero || + rmsgp->rm_body.rm_chunks[1] == xdr_zero) + return NULL; + return (struct rpcrdma_write_array *)&rmsgp->rm_body.rm_chunks[1]; +} + +/* Returns the address of the first reply array element or if no + * reply array is present + */ +static struct rpcrdma_write_array * +svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp) +{ + struct rpcrdma_read_chunk *rch; + struct rpcrdma_write_array *wr_ary; + struct rpcrdma_write_array *rp_ary; + + /* XXX: Need to fix when reply chunk may occur with read list + * and/or write list. + */ + if (rmsgp->rm_body.rm_chunks[0] != xdr_zero || + rmsgp->rm_body.rm_chunks[1] != xdr_zero) + return NULL; + + rch = svc_rdma_get_read_chunk(rmsgp); + if (rch) { + while (rch->rc_discrim != xdr_zero) + rch++; + + /* The reply chunk follows an empty write array located + * at 'rc_position' here. The reply array is at rc_target. + */ + rp_ary = (struct rpcrdma_write_array *)&rch->rc_target; + goto found_it; + } + + wr_ary = svc_rdma_get_write_array(rmsgp); + if (wr_ary) { + int chunk = be32_to_cpu(wr_ary->wc_nchunks); + + rp_ary = (struct rpcrdma_write_array *) + &wr_ary->wc_array[chunk].wc_target.rs_length; + goto found_it; + } + + /* No read list, no write list */ + rp_ary = (struct rpcrdma_write_array *)&rmsgp->rm_body.rm_chunks[2]; + + found_it: + if (rp_ary->wc_discrim == xdr_zero) + return NULL; + return rp_ary; +} + /* Assumptions: * - The specified write_len can be represented in sc_max_sge * PAGE_SIZE */ -- GitLab From 31193fe5f6fb616711323f5d74ee5bb92aacba4a Mon Sep 17 00:00:00 2001 From: Chuck Lever Date: Thu, 9 Jul 2015 16:45:37 -0400 Subject: [PATCH 1248/7006] svcrdma: Remove svc_rdma_fastreg() Commit 0bf4828983df ("svcrdma: refactor marshalling logic") removed the last call site for svc_rdma_fastreg(). Signed-off-by: Chuck Lever Signed-off-by: J. Bruce Fields --- include/linux/sunrpc/svc_rdma.h | 1 - net/sunrpc/xprtrdma/svc_rdma_transport.c | 34 ------------------------ 2 files changed, 35 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index ca4d86a6c947f..13af61b704174 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -227,7 +227,6 @@ extern void svc_rdma_put_context(struct svc_rdma_op_ctxt *, int); extern void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt); extern struct svc_rdma_req_map *svc_rdma_get_req_map(void); extern void svc_rdma_put_req_map(struct svc_rdma_req_map *); -extern int svc_rdma_fastreg(struct svcxprt_rdma *, struct svc_rdma_fastreg_mr *); extern struct svc_rdma_fastreg_mr *svc_rdma_get_frmr(struct svcxprt_rdma *); extern void svc_rdma_put_frmr(struct svcxprt_rdma *, struct svc_rdma_fastreg_mr *); diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index f4b9732339777..4054a9de6a912 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -1202,40 +1202,6 @@ static int svc_rdma_secure_port(struct svc_rqst *rqstp) return 1; } -/* - * Attempt to register the kvec representing the RPC memory with the - * device. - * - * Returns: - * NULL : The device does not support fastreg or there were no more - * fastreg mr. - * frmr : The kvec register request was successfully posted. - * <0 : An error was encountered attempting to register the kvec. - */ -int svc_rdma_fastreg(struct svcxprt_rdma *xprt, - struct svc_rdma_fastreg_mr *frmr) -{ - struct ib_send_wr fastreg_wr; - u8 key; - - /* Bump the key */ - key = (u8)(frmr->mr->lkey & 0x000000FF); - ib_update_fast_reg_key(frmr->mr, ++key); - - /* Prepare FASTREG WR */ - memset(&fastreg_wr, 0, sizeof fastreg_wr); - fastreg_wr.opcode = IB_WR_FAST_REG_MR; - fastreg_wr.send_flags = IB_SEND_SIGNALED; - fastreg_wr.wr.fast_reg.iova_start = (unsigned long)frmr->kva; - fastreg_wr.wr.fast_reg.page_list = frmr->page_list; - fastreg_wr.wr.fast_reg.page_list_len = frmr->page_list_len; - fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT; - fastreg_wr.wr.fast_reg.length = frmr->map_len; - fastreg_wr.wr.fast_reg.access_flags = frmr->access_flags; - fastreg_wr.wr.fast_reg.rkey = frmr->mr->lkey; - return svc_rdma_send(xprt, &fastreg_wr); -} - int svc_rdma_send(struct svcxprt_rdma *xprt, struct ib_send_wr *wr) { struct ib_send_wr *bad_wr, *n_wr; -- GitLab From fc865d6b4a6b58db8497ac2cf188ad20a5cec00c Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 15 Jul 2015 15:34:39 +0530 Subject: [PATCH 1249/7006] enic: add adaptive coalescing intr for intx and msi poll Adaptive interrupt coalescing is available for msix. This patch adds the support for msi poll. Interface for adaptive interrupt coalescing is already added in driver. We just did not enable it for legacy intr & msi. enic_calc_int_moderation() & enic_set_int_moderation() are defined as static after enic_poll. Since enic_poll needs it, move both of these function definitions above enic_poll. No change in functionality. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/enic_main.c | 135 ++++++++++---------- 1 file changed, 67 insertions(+), 68 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c index 918a8e42139b1..8f646e4e968b3 100644 --- a/drivers/net/ethernet/cisco/enic/enic_main.c +++ b/drivers/net/ethernet/cisco/enic/enic_main.c @@ -1149,6 +1149,64 @@ static int enic_rq_service(struct vnic_dev *vdev, struct cq_desc *cq_desc, return 0; } +static void enic_set_int_moderation(struct enic *enic, struct vnic_rq *rq) +{ + unsigned int intr = enic_msix_rq_intr(enic, rq->index); + struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; + u32 timer = cq->tobe_rx_coal_timeval; + + if (cq->tobe_rx_coal_timeval != cq->cur_rx_coal_timeval) { + vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); + cq->cur_rx_coal_timeval = cq->tobe_rx_coal_timeval; + } +} + +static void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq) +{ + struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; + struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; + struct vnic_rx_bytes_counter *pkt_size_counter = &cq->pkt_size_counter; + int index; + u32 timer; + u32 range_start; + u32 traffic; + u64 delta; + ktime_t now = ktime_get(); + + delta = ktime_us_delta(now, cq->prev_ts); + if (delta < ENIC_AIC_TS_BREAK) + return; + cq->prev_ts = now; + + traffic = pkt_size_counter->large_pkt_bytes_cnt + + pkt_size_counter->small_pkt_bytes_cnt; + /* The table takes Mbps + * traffic *= 8 => bits + * traffic *= (10^6 / delta) => bps + * traffic /= 10^6 => Mbps + * + * Combining, traffic *= (8 / delta) + */ + + traffic <<= 3; + traffic = delta > UINT_MAX ? 0 : traffic / (u32)delta; + + for (index = 0; index < ENIC_MAX_COALESCE_TIMERS; index++) + if (traffic < mod_table[index].rx_rate) + break; + range_start = (pkt_size_counter->small_pkt_bytes_cnt > + pkt_size_counter->large_pkt_bytes_cnt << 1) ? + rx_coal->small_pkt_range_start : + rx_coal->large_pkt_range_start; + timer = range_start + ((rx_coal->range_end - range_start) * + mod_table[index].range_percent / 100); + /* Damping */ + cq->tobe_rx_coal_timeval = (timer + cq->tobe_rx_coal_timeval) >> 1; + + pkt_size_counter->large_pkt_bytes_cnt = 0; + pkt_size_counter->small_pkt_bytes_cnt = 0; +} + static int enic_poll(struct napi_struct *napi, int budget) { struct net_device *netdev = napi->dev; @@ -1199,6 +1257,11 @@ static int enic_poll(struct napi_struct *napi, int budget) if (err) rq_work_done = rq_work_to_do; + if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) + /* Call the function which refreshes the intr coalescing timer + * value based on the traffic. + */ + enic_calc_int_moderation(enic, &enic->rq[0]); if (rq_work_done < rq_work_to_do) { @@ -1207,70 +1270,14 @@ static int enic_poll(struct napi_struct *napi, int budget) */ napi_complete(napi); + if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) + enic_set_int_moderation(enic, &enic->rq[0]); vnic_intr_unmask(&enic->intr[intr]); } return rq_work_done; } -static void enic_set_int_moderation(struct enic *enic, struct vnic_rq *rq) -{ - unsigned int intr = enic_msix_rq_intr(enic, rq->index); - struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; - u32 timer = cq->tobe_rx_coal_timeval; - - if (cq->tobe_rx_coal_timeval != cq->cur_rx_coal_timeval) { - vnic_intr_coalescing_timer_set(&enic->intr[intr], timer); - cq->cur_rx_coal_timeval = cq->tobe_rx_coal_timeval; - } -} - -static void enic_calc_int_moderation(struct enic *enic, struct vnic_rq *rq) -{ - struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; - struct vnic_cq *cq = &enic->cq[enic_cq_rq(enic, rq->index)]; - struct vnic_rx_bytes_counter *pkt_size_counter = &cq->pkt_size_counter; - int index; - u32 timer; - u32 range_start; - u32 traffic; - u64 delta; - ktime_t now = ktime_get(); - - delta = ktime_us_delta(now, cq->prev_ts); - if (delta < ENIC_AIC_TS_BREAK) - return; - cq->prev_ts = now; - - traffic = pkt_size_counter->large_pkt_bytes_cnt + - pkt_size_counter->small_pkt_bytes_cnt; - /* The table takes Mbps - * traffic *= 8 => bits - * traffic *= (10^6 / delta) => bps - * traffic /= 10^6 => Mbps - * - * Combining, traffic *= (8 / delta) - */ - - traffic <<= 3; - traffic = delta > UINT_MAX ? 0 : traffic / (u32)delta; - - for (index = 0; index < ENIC_MAX_COALESCE_TIMERS; index++) - if (traffic < mod_table[index].rx_rate) - break; - range_start = (pkt_size_counter->small_pkt_bytes_cnt > - pkt_size_counter->large_pkt_bytes_cnt << 1) ? - rx_coal->small_pkt_range_start : - rx_coal->large_pkt_range_start; - timer = range_start + ((rx_coal->range_end - range_start) * - mod_table[index].range_percent / 100); - /* Damping */ - cq->tobe_rx_coal_timeval = (timer + cq->tobe_rx_coal_timeval) >> 1; - - pkt_size_counter->large_pkt_bytes_cnt = 0; - pkt_size_counter->small_pkt_bytes_cnt = 0; -} - #ifdef CONFIG_RFS_ACCEL static void enic_free_rx_cpu_rmap(struct enic *enic) { @@ -1407,10 +1414,8 @@ static int enic_poll_msix_rq(struct napi_struct *napi, int budget) if (err) work_done = work_to_do; if (enic->rx_coalesce_setting.use_adaptive_rx_coalesce) - /* Call the function which refreshes - * the intr coalescing timer value based on - * the traffic. This is supported only in - * the case of MSI-x mode + /* Call the function which refreshes the intr coalescing timer + * value based on the traffic. */ enic_calc_int_moderation(enic, &enic->rq[rq]); @@ -1569,12 +1574,6 @@ static void enic_set_rx_coal_setting(struct enic *enic) int index = -1; struct enic_rx_coal *rx_coal = &enic->rx_coalesce_setting; - /* If intr mode is not MSIX, do not do adaptive coalescing */ - if (VNIC_DEV_INTR_MODE_MSIX != vnic_dev_get_intr_mode(enic->vdev)) { - netdev_info(enic->netdev, "INTR mode is not MSIX, Not initializing adaptive coalescing"); - return; - } - /* 1. Read the link speed from fw * 2. Pick the default range for the speed * 3. Update it in enic->rx_coalesce_setting -- GitLab From d9382bda4ef97d73c77ecaed7a8d5df20da8b8dd Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Wed, 15 Jul 2015 15:34:40 +0530 Subject: [PATCH 1250/7006] enic: allow adaptive coalesce setting for msi/legacy intr * Allow setting of adaptive coalescing setting for all types of interrupt. * In msi & legacy intr, we use single interrupt for rx & tx. In this case tx_coalesce_usecs is invalid. We should use only rx_coalesce_usecs. Do not display tx_coal values for msi/intx. And do not allow user to set this as well. * Driver supports only tx/rx_coalesce_usec and adaptive coalesce settings. For other values, driver does not return error. So ethtool succeeds for unsupported values. Introduce enic_coalesce_valid() function to validate the coalescing values. * If user requests for coalesce value greater than what adaptor supports, driver uses the max value. We should at least log this. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- .../net/ethernet/cisco/enic/enic_ethtool.c | 113 ++++++++++-------- 1 file changed, 65 insertions(+), 48 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c index f3f1601a76f37..f44a39c40642c 100644 --- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c +++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c @@ -224,7 +224,8 @@ static int enic_get_coalesce(struct net_device *netdev, struct enic *enic = netdev_priv(netdev); struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; - ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) + ecmd->tx_coalesce_usecs = enic->tx_coalesce_usecs; ecmd->rx_coalesce_usecs = enic->rx_coalesce_usecs; if (rxcoal->use_adaptive_rx_coalesce) ecmd->use_adaptive_rx_coalesce = 1; @@ -234,6 +235,53 @@ static int enic_get_coalesce(struct net_device *netdev, return 0; } +static int enic_coalesce_valid(struct enic *enic, + struct ethtool_coalesce *ec) +{ + u32 coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); + u32 rx_coalesce_usecs_high = min_t(u32, coalesce_usecs_max, + ec->rx_coalesce_usecs_high); + u32 rx_coalesce_usecs_low = min_t(u32, coalesce_usecs_max, + ec->rx_coalesce_usecs_low); + + if (ec->rx_max_coalesced_frames || + ec->rx_coalesce_usecs_irq || + ec->rx_max_coalesced_frames_irq || + ec->tx_max_coalesced_frames || + ec->tx_coalesce_usecs_irq || + ec->tx_max_coalesced_frames_irq || + ec->stats_block_coalesce_usecs || + ec->use_adaptive_tx_coalesce || + ec->pkt_rate_low || + ec->rx_max_coalesced_frames_low || + ec->tx_coalesce_usecs_low || + ec->tx_max_coalesced_frames_low || + ec->pkt_rate_high || + ec->rx_max_coalesced_frames_high || + ec->tx_coalesce_usecs_high || + ec->tx_max_coalesced_frames_high || + ec->rate_sample_interval) + return -EINVAL; + + if ((vnic_dev_get_intr_mode(enic->vdev) != VNIC_DEV_INTR_MODE_MSIX) && + ec->tx_coalesce_usecs) + return -EINVAL; + + if ((ec->tx_coalesce_usecs > coalesce_usecs_max) || + (ec->rx_coalesce_usecs > coalesce_usecs_max) || + (ec->rx_coalesce_usecs_low > coalesce_usecs_max) || + (ec->rx_coalesce_usecs_high > coalesce_usecs_max)) + netdev_info(enic->netdev, "ethtool_set_coalesce: adaptor supports max coalesce value of %d. Setting max value.\n", + coalesce_usecs_max); + + if (ec->rx_coalesce_usecs_high && + (rx_coalesce_usecs_high < + rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) + return -EINVAL; + + return 0; +} + static int enic_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecmd) { @@ -244,8 +292,12 @@ static int enic_set_coalesce(struct net_device *netdev, u32 rx_coalesce_usecs_high; u32 coalesce_usecs_max; unsigned int i, intr; + int ret; struct enic_rx_coal *rxcoal = &enic->rx_coalesce_setting; + ret = enic_coalesce_valid(enic, ecmd); + if (ret) + return ret; coalesce_usecs_max = vnic_dev_get_intr_coal_timer_max(enic->vdev); tx_coalesce_usecs = min_t(u32, ecmd->tx_coalesce_usecs, coalesce_usecs_max); @@ -257,59 +309,24 @@ static int enic_set_coalesce(struct net_device *netdev, rx_coalesce_usecs_high = min_t(u32, ecmd->rx_coalesce_usecs_high, coalesce_usecs_max); - switch (vnic_dev_get_intr_mode(enic->vdev)) { - case VNIC_DEV_INTR_MODE_INTX: - if (tx_coalesce_usecs != rx_coalesce_usecs) - return -EINVAL; - if (ecmd->use_adaptive_rx_coalesce || - ecmd->rx_coalesce_usecs_low || - ecmd->rx_coalesce_usecs_high) - return -EINVAL; - - intr = enic_legacy_io_intr(); - vnic_intr_coalescing_timer_set(&enic->intr[intr], - tx_coalesce_usecs); - break; - case VNIC_DEV_INTR_MODE_MSI: - if (tx_coalesce_usecs != rx_coalesce_usecs) - return -EINVAL; - if (ecmd->use_adaptive_rx_coalesce || - ecmd->rx_coalesce_usecs_low || - ecmd->rx_coalesce_usecs_high) - return -EINVAL; - - vnic_intr_coalescing_timer_set(&enic->intr[0], - tx_coalesce_usecs); - break; - case VNIC_DEV_INTR_MODE_MSIX: - if (ecmd->rx_coalesce_usecs_high && - (rx_coalesce_usecs_high < - rx_coalesce_usecs_low + ENIC_AIC_LARGE_PKT_DIFF)) - return -EINVAL; - + if (vnic_dev_get_intr_mode(enic->vdev) == VNIC_DEV_INTR_MODE_MSIX) { for (i = 0; i < enic->wq_count; i++) { intr = enic_msix_wq_intr(enic, i); vnic_intr_coalescing_timer_set(&enic->intr[intr], - tx_coalesce_usecs); - } - - rxcoal->use_adaptive_rx_coalesce = - !!ecmd->use_adaptive_rx_coalesce; - if (!rxcoal->use_adaptive_rx_coalesce) - enic_intr_coal_set_rx(enic, rx_coalesce_usecs); - - if (ecmd->rx_coalesce_usecs_high) { - rxcoal->range_end = rx_coalesce_usecs_high; - rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; - rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + - ENIC_AIC_LARGE_PKT_DIFF; + tx_coalesce_usecs); } - break; - default: - break; + enic->tx_coalesce_usecs = tx_coalesce_usecs; + } + rxcoal->use_adaptive_rx_coalesce = !!ecmd->use_adaptive_rx_coalesce; + if (!rxcoal->use_adaptive_rx_coalesce) + enic_intr_coal_set_rx(enic, rx_coalesce_usecs); + if (ecmd->rx_coalesce_usecs_high) { + rxcoal->range_end = rx_coalesce_usecs_high; + rxcoal->small_pkt_range_start = rx_coalesce_usecs_low; + rxcoal->large_pkt_range_start = rx_coalesce_usecs_low + + ENIC_AIC_LARGE_PKT_DIFF; } - enic->tx_coalesce_usecs = tx_coalesce_usecs; enic->rx_coalesce_usecs = rx_coalesce_usecs; return 0; -- GitLab From b87a173e25d6bf5c26f13d329cdddf57dbd4061a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 15 Jul 2015 14:21:41 +0200 Subject: [PATCH 1251/7006] cls_cgroup: factor out classid retrieval Split out retrieving the cgroups net_cls classid retrieval into its own function, so that it can be reused later on from other parts of the traffic control subsystem. If there's no skb->sk, then the small helper returns 0 as well, which in cls_cgroup terms means 'could not classify'. Signed-off-by: Daniel Borkmann Cc: Thomas Graf Signed-off-by: David S. Miller --- include/net/cls_cgroup.h | 29 +++++++++++++++++++++++++++++ net/sched/cls_cgroup.c | 23 ++--------------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/include/net/cls_cgroup.h b/include/net/cls_cgroup.h index c15d39456e146..ccd6d8bffa4d8 100644 --- a/include/net/cls_cgroup.h +++ b/include/net/cls_cgroup.h @@ -49,9 +49,38 @@ static inline void sock_update_classid(struct sock *sk) if (classid != sk->sk_classid) sk->sk_classid = classid; } + +static inline u32 task_get_classid(const struct sk_buff *skb) +{ + u32 classid = task_cls_state(current)->classid; + + /* Due to the nature of the classifier it is required to ignore all + * packets originating from softirq context as accessing `current' + * would lead to false results. + * + * This test assumes that all callers of dev_queue_xmit() explicitly + * disable bh. Knowing this, it is possible to detect softirq based + * calls by looking at the number of nested bh disable calls because + * softirqs always disables bh. + */ + if (in_serving_softirq()) { + /* If there is an sk_classid we'll use that. */ + if (!skb->sk) + return 0; + + classid = skb->sk->sk_classid; + } + + return classid; +} #else /* !CONFIG_CGROUP_NET_CLASSID */ static inline void sock_update_classid(struct sock *sk) { } + +static inline u32 task_get_classid(const struct sk_buff *skb) +{ + return 0; +} #endif /* CONFIG_CGROUP_NET_CLASSID */ #endif /* _NET_CLS_CGROUP_H */ diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c index ea611b2164124..4c85bd3a750cb 100644 --- a/net/sched/cls_cgroup.c +++ b/net/sched/cls_cgroup.c @@ -30,35 +30,16 @@ static int cls_cgroup_classify(struct sk_buff *skb, const struct tcf_proto *tp, struct tcf_result *res) { struct cls_cgroup_head *head = rcu_dereference_bh(tp->root); - u32 classid; - - classid = task_cls_state(current)->classid; - - /* - * Due to the nature of the classifier it is required to ignore all - * packets originating from softirq context as accessing `current' - * would lead to false results. - * - * This test assumes that all callers of dev_queue_xmit() explicitely - * disable bh. Knowing this, it is possible to detect softirq based - * calls by looking at the number of nested bh disable calls because - * softirqs always disables bh. - */ - if (in_serving_softirq()) { - /* If there is an sk_classid we'll use that. */ - if (!skb->sk) - return -1; - classid = skb->sk->sk_classid; - } + u32 classid = task_get_classid(skb); if (!classid) return -1; - if (!tcf_em_tree_match(skb, &head->ematches, NULL)) return -1; res->classid = classid; res->class = 0; + return tcf_exts_exec(skb, &head->exts, res); } -- GitLab From 8d20aabe1c76cccac544d9fcc3ad7823d9e98a2d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 15 Jul 2015 14:21:42 +0200 Subject: [PATCH 1252/7006] ebpf: add helper to retrieve net_cls's classid cookie It would be very useful to retrieve the net_cls's classid from an eBPF program to allow for a more fine-grained classification, it could be directly used or in conjunction with additional policies. I.e. docker, but also tooling such as cgexec, can easily run applications via net_cls cgroups: cgcreate -g net_cls:/foo echo 42 > foo/net_cls.classid cgexec -g net_cls:foo Thus, their respecitve classid cookie of foo can then be looked up on the egress path to apply further policies. The helper is desigend such that a non-zero value returns the cgroup id. Signed-off-by: Daniel Borkmann Cc: Thomas Graf Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/uapi/linux/bpf.h | 7 +++++++ net/core/filter.c | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 29ef6f99e43d1..2de87e58b12b0 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -249,6 +249,13 @@ enum bpf_func_id { * Return: 0 on success */ BPF_FUNC_get_current_comm, + + /** + * bpf_get_cgroup_classid(skb) - retrieve a proc's classid + * @skb: pointer to skb + * Return: classid if != 0 + */ + BPF_FUNC_get_cgroup_classid, __BPF_FUNC_MAX_ID, }; diff --git a/net/core/filter.c b/net/core/filter.c index be3098fb65e45..247450a5e3879 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -47,6 +47,7 @@ #include #include #include +#include /** * sk_filter - run a packet through a socket filter @@ -1424,6 +1425,18 @@ const struct bpf_func_proto bpf_clone_redirect_proto = { .arg3_type = ARG_ANYTHING, }; +static u64 bpf_get_cgroup_classid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + return task_get_classid((struct sk_buff *) (unsigned long) r1); +} + +static const struct bpf_func_proto bpf_get_cgroup_classid_proto = { + .func = bpf_get_cgroup_classid, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +}; + static const struct bpf_func_proto * sk_filter_func_proto(enum bpf_func_id func_id) { @@ -1461,6 +1474,8 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) return &bpf_l4_csum_replace_proto; case BPF_FUNC_clone_redirect: return &bpf_clone_redirect_proto; + case BPF_FUNC_get_cgroup_classid: + return &bpf_get_cgroup_classid_proto; default: return sk_filter_func_proto(func_id); } -- GitLab From 5d285a7f35b55c8fba346306ad3eb174c4f7eab1 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 21 Jul 2015 01:40:45 +0800 Subject: [PATCH 1253/7006] futex: Make should_fail_futex() static Signed-off-by: Fengguang Wu Cc: kbuild-all@01.org Cc: tipbuild@zytor.com Cc: Davidlohr Bueso Cc: Peter Zijlstra Cc: Darren Hart Cc: Oleg Nesterov Cc: Brian Silverman Cc: Andy Lutomirski Cc: Sebastian Andrzej Siewior Signed-off-by: Thomas Gleixner --- kernel/futex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/futex.c b/kernel/futex.c index 6ea31bb703c95..6e443efc65f41 100644 --- a/kernel/futex.c +++ b/kernel/futex.c @@ -279,7 +279,7 @@ static int __init setup_fail_futex(char *str) } __setup("fail_futex=", setup_fail_futex); -bool should_fail_futex(bool fshared) +static bool should_fail_futex(bool fshared) { if (fail_futex.ignore_private && !fshared) return false; -- GitLab From ef8299de7e2bf61ed24d1da699fa5ba13549d5f8 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 15 Jul 2015 07:16:50 -0700 Subject: [PATCH 1254/7006] bridge: multicast: notify on group delete Group notifications were not sent when a group expired or was deleted due to bridge/port device being deleted. So add br_mdb_notify() to br_multicast_del_pg(). Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_multicast.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 5a44cd9473f2e..55903d91d0a87 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -273,6 +273,8 @@ static void br_multicast_del_pg(struct net_bridge *br, rcu_assign_pointer(*pp, p->next); hlist_del_init(&p->mglist); del_timer(&p->timer); + br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB, + p->state); call_rcu_bh(&p->rcu, br_multicast_free_pg); if (!mp->ports && !mp->mglist && -- GitLab From e10177abf842d0c40dfecc43bd57a0a762a2fccf Mon Sep 17 00:00:00 2001 From: Satish Ashok Date: Wed, 15 Jul 2015 07:16:51 -0700 Subject: [PATCH 1255/7006] bridge: multicast: fix handling of temp and perm entries When the bridge (or port) is brought down/up flush only temp entries and leave the perm ones. Flush perm entries only when deleting the bridge device or the associated port. Signed-off-by: Satish Ashok Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_if.c | 1 + net/bridge/br_multicast.c | 27 ++++++++++++++++++++------- net/bridge/br_private.h | 1 + 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index a538cb1199a30..45e4757c6fd25 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -281,6 +281,7 @@ void br_dev_delete(struct net_device *dev, struct list_head *head) br_fdb_delete_by_port(br, NULL, 0, 1); br_vlan_flush(br); + br_multicast_dev_del(br); del_timer_sync(&br->gc_timer); br_sysfs_delbr(br->dev); diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 55903d91d0a87..0dd3cd90962c7 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -916,6 +916,15 @@ void br_multicast_add_port(struct net_bridge_port *port) void br_multicast_del_port(struct net_bridge_port *port) { + struct net_bridge *br = port->br; + struct net_bridge_port_group *pg; + struct hlist_node *n; + + /* Take care of the remaining groups, only perm ones should be left */ + spin_lock_bh(&br->multicast_lock); + hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) + br_multicast_del_pg(br, pg); + spin_unlock_bh(&br->multicast_lock); del_timer_sync(&port->multicast_router_timer); } @@ -955,7 +964,8 @@ void br_multicast_disable_port(struct net_bridge_port *port) spin_lock(&br->multicast_lock); hlist_for_each_entry_safe(pg, n, &port->mglist, mglist) - br_multicast_del_pg(br, pg); + if (pg->state == MDB_TEMPORARY) + br_multicast_del_pg(br, pg); if (!hlist_unhashed(&port->rlist)) hlist_del_init_rcu(&port->rlist); @@ -1732,12 +1742,6 @@ void br_multicast_open(struct net_bridge *br) void br_multicast_stop(struct net_bridge *br) { - struct net_bridge_mdb_htable *mdb; - struct net_bridge_mdb_entry *mp; - struct hlist_node *n; - u32 ver; - int i; - del_timer_sync(&br->multicast_router_timer); del_timer_sync(&br->ip4_other_query.timer); del_timer_sync(&br->ip4_own_query.timer); @@ -1745,6 +1749,15 @@ void br_multicast_stop(struct net_bridge *br) del_timer_sync(&br->ip6_other_query.timer); del_timer_sync(&br->ip6_own_query.timer); #endif +} + +void br_multicast_dev_del(struct net_bridge *br) +{ + struct net_bridge_mdb_htable *mdb; + struct net_bridge_mdb_entry *mp; + struct hlist_node *n; + u32 ver; + int i; spin_lock_bh(&br->multicast_lock); mdb = mlock_dereference(br->mdb, br); diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index c73fd785654da..2bada2279721a 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -466,6 +466,7 @@ void br_multicast_disable_port(struct net_bridge_port *port); void br_multicast_init(struct net_bridge *br); void br_multicast_open(struct net_bridge *br); void br_multicast_stop(struct net_bridge *br); +void br_multicast_dev_del(struct net_bridge *br); void br_multicast_deliver(struct net_bridge_mdb_entry *mdst, struct sk_buff *skb); void br_multicast_forward(struct net_bridge_mdb_entry *mdst, -- GitLab From 22f94e625635fb8555f5e7361745ea780a3853e4 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Wed, 15 Jul 2015 16:31:09 +0200 Subject: [PATCH 1256/7006] bonding: trivial: remove unused variables MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of these: drivers/net/bonding//bond_main.c: In function ‘bond_update_slave_arr’: drivers/net/bonding//bond_main.c:3754:6: warning: variable ‘slaves_in_agg’ set but not used [-Wunused-but-set-variable] int slaves_in_agg; ^ CC [M] drivers/net/bonding//bond_3ad.o drivers/net/bonding//bond_3ad.c: In function ‘ad_marker_response_received’: drivers/net/bonding//bond_3ad.c:1870:61: warning: parameter ‘marker’ set but not used [-Wunused-but-set-parameter] static void ad_marker_response_received(struct bond_marker *marker, ^ drivers/net/bonding//bond_3ad.c:1871:19: warning: parameter ‘port’ set but not used [-Wunused-but-set-parameter] struct port *port) ^ Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- drivers/net/bonding/bond_3ad.c | 2 -- drivers/net/bonding/bond_main.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 7fde4d5c2b28b..3c45358844eb9 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -1870,8 +1870,6 @@ static void ad_marker_info_received(struct bond_marker *marker_info, static void ad_marker_response_received(struct bond_marker *marker, struct port *port) { - marker = NULL; - port = NULL; /* DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW */ } diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 317a49480475d..1c6a773c87eac 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3751,7 +3751,6 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) struct slave *slave; struct list_head *iter; struct bond_up_slave *new_arr, *old_arr; - int slaves_in_agg; int agg_id = 0; int ret = 0; @@ -3782,7 +3781,6 @@ int bond_update_slave_arr(struct bonding *bond, struct slave *skipslave) } goto out; } - slaves_in_agg = ad_info.ports; agg_id = ad_info.aggregator_id; } bond_for_each_slave(bond, slave, iter) { -- GitLab From a0a9f33bdf8bf9061c31faab46d8eb46ff644622 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 15 Jul 2015 21:56:26 +0200 Subject: [PATCH 1257/7006] net/ipv6: update flowi6_oif in ip6_dst_lookup_flow if not set Newly created flows don't have flowi6_oif set (at least if the associated socket is not interface-bound). This leads to a mismatch in __xfrm6_selector_match() for policies which specify an interface in the selector (sel->ifindex != 0). Backtracing shows this happens in code-paths originating from e.g. ip6_datagram_connect(), rawv6_sendmsg() or tcp_v6_connect(). (UDP was not tested for.) In summary, this patch fixes policy matching on outgoing interface for locally generated packets. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- net/ipv6/ip6_output.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index d5f7716662dbc..c5fc85286ef64 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1023,6 +1023,8 @@ struct dst_entry *ip6_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, return ERR_PTR(err); if (final_dst) fl6->daddr = *final_dst; + if (!fl6->flowi6_oif) + fl6->flowi6_oif = dst->dev->ifindex; return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); } -- GitLab From 8ce344c66e3ce122585cfe68be1ef0ffd176380d Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 19 Jul 2015 18:50:38 +0200 Subject: [PATCH 1258/7006] ACPI / processor: remove leftover __refdata annotations The processor_handler structure does not reference any __init / __exit code or data. Therefore the __refdata annotation is not needed. It used to be prior to commit fe7bf106ebc2 ("acpi: delete __cpuinit usage from all acpi files") due to the __cpuinit annotation of acpi_processor_add(). But with that commit in place that requirement has gone. The same is true for the acpi_cpu_notifier notifier block. acpi_cpu_soft_notify() used to be marked __cpuinit but lost its annotation in the above mentioned commit as well. Therefore the __refdata annotation isn't needed there either. Just drop the unneded __refdata annotations to be able to catch future section mismatches. Signed-off-by: Mathias Krause Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_processor.c | 2 +- drivers/acpi/processor_driver.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c index 92a5f738e3707..985b8a83184e1 100644 --- a/drivers/acpi/acpi_processor.c +++ b/drivers/acpi/acpi_processor.c @@ -485,7 +485,7 @@ static const struct acpi_device_id processor_device_ids[] = { { } }; -static struct acpi_scan_handler __refdata processor_handler = { +static struct acpi_scan_handler processor_handler = { .ids = processor_device_ids, .attach = acpi_processor_add, #ifdef CONFIG_ACPI_HOTPLUG_CPU diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index d9f71581b79b2..cc820d840c61f 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -159,7 +159,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, return NOTIFY_OK; } -static struct notifier_block __refdata acpi_cpu_notifier = { +static struct notifier_block acpi_cpu_notifier = { .notifier_call = acpi_cpu_soft_notify, }; -- GitLab From 44152cb82d1ad6ae6f8b47c5437f6f1e65ca82c4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:30:59 +0530 Subject: [PATCH 1259/7006] cpufreq: governor: Keep single copy of information common to policy->cpus Some information is common to all CPUs belonging to a policy, but are kept on per-cpu basis. Lets keep that in another structure common to all policy->cpus. That will make updates/reads to that less complex and less error prone. The memory for cpu_common_dbs_info is allocated/freed at INIT/EXIT, so that it we don't reallocate it for STOP/START sequence. It will be also be used (in next patch) while the governor is stopped and so must not be freed that early. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 18 ++--- drivers/cpufreq/cpufreq_governor.c | 92 +++++++++++++++++++------- drivers/cpufreq/cpufreq_governor.h | 24 ++++--- drivers/cpufreq/cpufreq_ondemand.c | 38 ++++++----- 4 files changed, 114 insertions(+), 58 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index af47d322679e5..d21c3cff90569 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -47,7 +47,7 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners, static void cs_check_cpu(int cpu, unsigned int load) { struct cs_cpu_dbs_info_s *dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.policy; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -106,22 +106,24 @@ static void cs_dbs_timer(struct work_struct *work) { struct cs_cpu_dbs_info_s *dbs_info = container_of(work, struct cs_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.policy->cpu; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; + unsigned int cpu = policy->cpu; struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; + struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; int delay = delay_for_sampling_rate(cs_tuners->sampling_rate); bool modify_all = true; - mutex_lock(&core_dbs_info->cdbs.timer_mutex); - if (!need_load_eval(&core_dbs_info->cdbs, cs_tuners->sampling_rate)) + mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); + if (!need_load_eval(core_dbs_info->cdbs.shared, + cs_tuners->sampling_rate)) modify_all = false; else dbs_check_cpu(dbs_data, cpu); - gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.timer_mutex); + gov_queue_work(dbs_data, policy, delay, modify_all); + mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); } static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, @@ -135,7 +137,7 @@ static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, if (!dbs_info->enable) return 0; - policy = dbs_info->cdbs.policy; + policy = dbs_info->cdbs.shared->policy; /* * we only care if our internally tracked freq moves outside the 'valid' diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index c0566f86caed6..b01cb729104b1 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -35,7 +35,7 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct cpu_dbs_info *cdbs = dbs_data->cdata->get_cpu_cdbs(cpu); struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; - struct cpufreq_policy *policy; + struct cpufreq_policy *policy = cdbs->shared->policy; unsigned int sampling_rate; unsigned int max_load = 0; unsigned int ignore_nice; @@ -60,8 +60,6 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) ignore_nice = cs_tuners->ignore_nice_load; } - policy = cdbs->policy; - /* Get Absolute Load */ for_each_cpu(j, policy->cpus) { struct cpu_dbs_info *j_cdbs; @@ -209,17 +207,18 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, } /* Will return if we need to evaluate cpu load again or not */ -bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate) +bool need_load_eval(struct cpu_common_dbs_info *shared, + unsigned int sampling_rate) { - if (policy_is_shared(cdbs->policy)) { + if (policy_is_shared(shared->policy)) { ktime_t time_now = ktime_get(); - s64 delta_us = ktime_us_delta(time_now, cdbs->time_stamp); + s64 delta_us = ktime_us_delta(time_now, shared->time_stamp); /* Do nothing if we recently have sampled */ if (delta_us < (s64)(sampling_rate / 2)) return false; else - cdbs->time_stamp = time_now; + shared->time_stamp = time_now; } return true; @@ -238,6 +237,37 @@ static void set_sampling_rate(struct dbs_data *dbs_data, } } +static int alloc_common_dbs_info(struct cpufreq_policy *policy, + struct common_dbs_data *cdata) +{ + struct cpu_common_dbs_info *shared; + int j; + + /* Allocate memory for the common information for policy->cpus */ + shared = kzalloc(sizeof(*shared), GFP_KERNEL); + if (!shared) + return -ENOMEM; + + /* Set shared for all CPUs, online+offline */ + for_each_cpu(j, policy->related_cpus) + cdata->get_cpu_cdbs(j)->shared = shared; + + return 0; +} + +static void free_common_dbs_info(struct cpufreq_policy *policy, + struct common_dbs_data *cdata) +{ + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(policy->cpu); + struct cpu_common_dbs_info *shared = cdbs->shared; + int j; + + for_each_cpu(j, policy->cpus) + cdata->get_cpu_cdbs(j)->shared = NULL; + + kfree(shared); +} + static int cpufreq_governor_init(struct cpufreq_policy *policy, struct dbs_data *dbs_data, struct common_dbs_data *cdata) @@ -248,6 +278,11 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, if (dbs_data) { if (WARN_ON(have_governor_per_policy())) return -EINVAL; + + ret = alloc_common_dbs_info(policy, cdata); + if (ret) + return ret; + dbs_data->usage_count++; policy->governor_data = dbs_data; return 0; @@ -257,12 +292,16 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, if (!dbs_data) return -ENOMEM; + ret = alloc_common_dbs_info(policy, cdata); + if (ret) + goto free_dbs_data; + dbs_data->cdata = cdata; dbs_data->usage_count = 1; ret = cdata->init(dbs_data, !policy->governor->initialized); if (ret) - goto free_dbs_data; + goto free_common_dbs_info; /* policy latency is in ns. Convert it to us first */ latency = policy->cpuinfo.transition_latency / 1000; @@ -299,6 +338,8 @@ put_kobj: } cdata_exit: cdata->exit(dbs_data, !policy->governor->initialized); +free_common_dbs_info: + free_common_dbs_info(policy, cdata); free_dbs_data: kfree(dbs_data); return ret; @@ -322,6 +363,8 @@ static void cpufreq_governor_exit(struct cpufreq_policy *policy, cdata->exit(dbs_data, policy->governor->initialized == 1); kfree(dbs_data); } + + free_common_dbs_info(policy, cdata); } static int cpufreq_governor_start(struct cpufreq_policy *policy, @@ -330,6 +373,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, struct common_dbs_data *cdata = dbs_data->cdata; unsigned int sampling_rate, ignore_nice, j, cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_common_dbs_info *shared = cdbs->shared; int io_busy = 0; if (!policy->cur) @@ -348,11 +392,14 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, io_busy = od_tuners->io_is_busy; } + shared->policy = policy; + shared->time_stamp = ktime_get(); + mutex_init(&shared->timer_mutex); + for_each_cpu(j, policy->cpus) { struct cpu_dbs_info *j_cdbs = cdata->get_cpu_cdbs(j); unsigned int prev_load; - j_cdbs->policy = policy; j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_cpu_wall, io_busy); @@ -364,7 +411,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - mutex_init(&j_cdbs->timer_mutex); INIT_DEFERRABLE_WORK(&j_cdbs->dwork, cdata->gov_dbs_timer); } @@ -384,9 +430,6 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, od_ops->powersave_bias_init_cpu(cpu); } - /* Initiate timer time stamp */ - cdbs->time_stamp = ktime_get(); - gov_queue_work(dbs_data, policy, delay_for_sampling_rate(sampling_rate), true); return 0; @@ -398,6 +441,9 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); + struct cpu_common_dbs_info *shared = cdbs->shared; + + gov_cancel_work(dbs_data, policy); if (cdata->governor == GOV_CONSERVATIVE) { struct cs_cpu_dbs_info_s *cs_dbs_info = @@ -406,10 +452,8 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, cs_dbs_info->enable = 0; } - gov_cancel_work(dbs_data, policy); - - mutex_destroy(&cdbs->timer_mutex); - cdbs->policy = NULL; + shared->policy = NULL; + mutex_destroy(&shared->timer_mutex); } static void cpufreq_governor_limits(struct cpufreq_policy *policy, @@ -419,18 +463,18 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); - if (!cdbs->policy) + if (!cdbs->shared || !cdbs->shared->policy) return; - mutex_lock(&cdbs->timer_mutex); - if (policy->max < cdbs->policy->cur) - __cpufreq_driver_target(cdbs->policy, policy->max, + mutex_lock(&cdbs->shared->timer_mutex); + if (policy->max < cdbs->shared->policy->cur) + __cpufreq_driver_target(cdbs->shared->policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > cdbs->policy->cur) - __cpufreq_driver_target(cdbs->policy, policy->min, + else if (policy->min > cdbs->shared->policy->cur) + __cpufreq_driver_target(cdbs->shared->policy, policy->min, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); - mutex_unlock(&cdbs->timer_mutex); + mutex_unlock(&cdbs->shared->timer_mutex); } int cpufreq_governor_dbs(struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index a0f8eb79ee6d2..8e4a25f0730cd 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -128,6 +128,18 @@ static void *get_cpu_dbs_info_s(int cpu) \ * cs_*: Conservative governor */ +/* Common to all CPUs of a policy */ +struct cpu_common_dbs_info { + struct cpufreq_policy *policy; + /* + * percpu mutex that serializes governor limit change with gov_dbs_timer + * invocation. We do not want gov_dbs_timer to run when user is changing + * the governor or limits. + */ + struct mutex timer_mutex; + ktime_t time_stamp; +}; + /* Per cpu structures */ struct cpu_dbs_info { u64 prev_cpu_idle; @@ -140,15 +152,8 @@ struct cpu_dbs_info { * wake-up from idle. */ unsigned int prev_load; - struct cpufreq_policy *policy; struct delayed_work dwork; - /* - * percpu mutex that serializes governor limit change with gov_dbs_timer - * invocation. We do not want gov_dbs_timer to run when user is changing - * the governor or limits. - */ - struct mutex timer_mutex; - ktime_t time_stamp; + struct cpu_common_dbs_info *shared; }; struct od_cpu_dbs_info_s { @@ -264,7 +269,8 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); -bool need_load_eval(struct cpu_dbs_info *cdbs, unsigned int sampling_rate); +bool need_load_eval(struct cpu_common_dbs_info *shared, + unsigned int sampling_rate); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index d29c6f9c6e3eb..14d7e86e7f946 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -155,7 +155,7 @@ static void dbs_freq_increase(struct cpufreq_policy *policy, unsigned int freq) static void od_check_cpu(int cpu, unsigned int load) { struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct cpufreq_policy *policy = dbs_info->cdbs.policy; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; @@ -195,16 +195,18 @@ static void od_dbs_timer(struct work_struct *work) { struct od_cpu_dbs_info_s *dbs_info = container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); - unsigned int cpu = dbs_info->cdbs.policy->cpu; + struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; + unsigned int cpu = policy->cpu; struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = dbs_info->cdbs.policy->governor_data; + struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; int delay = 0, sample_type = core_dbs_info->sample_type; bool modify_all = true; - mutex_lock(&core_dbs_info->cdbs.timer_mutex); - if (!need_load_eval(&core_dbs_info->cdbs, od_tuners->sampling_rate)) { + mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); + if (!need_load_eval(core_dbs_info->cdbs.shared, + od_tuners->sampling_rate)) { modify_all = false; goto max_delay; } @@ -213,8 +215,7 @@ static void od_dbs_timer(struct work_struct *work) core_dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { delay = core_dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(core_dbs_info->cdbs.policy, - core_dbs_info->freq_lo, + __cpufreq_driver_target(policy, core_dbs_info->freq_lo, CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); @@ -230,8 +231,8 @@ max_delay: delay = delay_for_sampling_rate(od_tuners->sampling_rate * core_dbs_info->rate_mult); - gov_queue_work(dbs_data, dbs_info->cdbs.policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.timer_mutex); + gov_queue_work(dbs_data, policy, delay, modify_all); + mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); } /************************** sysfs interface ************************/ @@ -274,10 +275,10 @@ static void update_sampling_rate(struct dbs_data *dbs_data, dbs_info = &per_cpu(od_cpu_dbs_info, cpu); cpufreq_cpu_put(policy); - mutex_lock(&dbs_info->cdbs.timer_mutex); + mutex_lock(&dbs_info->cdbs.shared->timer_mutex); if (!delayed_work_pending(&dbs_info->cdbs.dwork)) { - mutex_unlock(&dbs_info->cdbs.timer_mutex); + mutex_unlock(&dbs_info->cdbs.shared->timer_mutex); continue; } @@ -286,15 +287,15 @@ static void update_sampling_rate(struct dbs_data *dbs_data, if (time_before(next_sampling, appointed_at)) { - mutex_unlock(&dbs_info->cdbs.timer_mutex); + mutex_unlock(&dbs_info->cdbs.shared->timer_mutex); cancel_delayed_work_sync(&dbs_info->cdbs.dwork); - mutex_lock(&dbs_info->cdbs.timer_mutex); + mutex_lock(&dbs_info->cdbs.shared->timer_mutex); - gov_queue_work(dbs_data, dbs_info->cdbs.policy, + gov_queue_work(dbs_data, policy, usecs_to_jiffies(new_rate), true); } - mutex_unlock(&dbs_info->cdbs.timer_mutex); + mutex_unlock(&dbs_info->cdbs.shared->timer_mutex); } } @@ -557,13 +558,16 @@ static void od_set_powersave_bias(unsigned int powersave_bias) get_online_cpus(); for_each_online_cpu(cpu) { + struct cpu_common_dbs_info *shared; + if (cpumask_test_cpu(cpu, &done)) continue; - policy = per_cpu(od_cpu_dbs_info, cpu).cdbs.policy; - if (!policy) + shared = per_cpu(od_cpu_dbs_info, cpu).cdbs.shared; + if (!shared) continue; + policy = shared->policy; cpumask_or(&done, &done, policy->cpus); if (policy->governor != &cpufreq_gov_ondemand) -- GitLab From 43e0ee361e96229959c2ce1eda1ad9d6b3c191b2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:00 +0530 Subject: [PATCH 1260/7006] cpufreq: governor: split out common part of {cs|od}_dbs_timer() Some part of cs_dbs_timer() and od_dbs_timer() is exactly same and is unnecessarily duplicated. Create the real work-handler in cpufreq_governor.c and put the common code in this routine (dbs_timer()). Shouldn't make any functional change. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_conservative.c | 27 +++++------------- drivers/cpufreq/cpufreq_governor.c | 38 +++++++++++++++++++++++--- drivers/cpufreq/cpufreq_governor.h | 10 +++---- drivers/cpufreq/cpufreq_ondemand.c | 36 ++++++++++-------------- 4 files changed, 60 insertions(+), 51 deletions(-) diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index d21c3cff90569..84a1506950a73 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c @@ -102,28 +102,15 @@ static void cs_check_cpu(int cpu, unsigned int load) } } -static void cs_dbs_timer(struct work_struct *work) +static unsigned int cs_dbs_timer(struct cpu_dbs_info *cdbs, + struct dbs_data *dbs_data, bool modify_all) { - struct cs_cpu_dbs_info_s *dbs_info = container_of(work, - struct cs_cpu_dbs_info_s, cdbs.dwork.work); - struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; - unsigned int cpu = policy->cpu; - struct cs_cpu_dbs_info_s *core_dbs_info = &per_cpu(cs_cpu_dbs_info, - cpu); - struct dbs_data *dbs_data = policy->governor_data; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; - int delay = delay_for_sampling_rate(cs_tuners->sampling_rate); - bool modify_all = true; - - mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); - if (!need_load_eval(core_dbs_info->cdbs.shared, - cs_tuners->sampling_rate)) - modify_all = false; - else - dbs_check_cpu(dbs_data, cpu); - - gov_queue_work(dbs_data, policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); + + if (modify_all) + dbs_check_cpu(dbs_data, cdbs->shared->policy->cpu); + + return delay_for_sampling_rate(cs_tuners->sampling_rate); } static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val, diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index b01cb729104b1..7ed0ec2ac853e 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -207,8 +207,8 @@ static inline void gov_cancel_work(struct dbs_data *dbs_data, } /* Will return if we need to evaluate cpu load again or not */ -bool need_load_eval(struct cpu_common_dbs_info *shared, - unsigned int sampling_rate) +static bool need_load_eval(struct cpu_common_dbs_info *shared, + unsigned int sampling_rate) { if (policy_is_shared(shared->policy)) { ktime_t time_now = ktime_get(); @@ -223,7 +223,37 @@ bool need_load_eval(struct cpu_common_dbs_info *shared, return true; } -EXPORT_SYMBOL_GPL(need_load_eval); + +static void dbs_timer(struct work_struct *work) +{ + struct cpu_dbs_info *cdbs = container_of(work, struct cpu_dbs_info, + dwork.work); + struct cpu_common_dbs_info *shared = cdbs->shared; + struct cpufreq_policy *policy = shared->policy; + struct dbs_data *dbs_data = policy->governor_data; + unsigned int sampling_rate, delay; + bool modify_all = true; + + mutex_lock(&shared->timer_mutex); + + if (dbs_data->cdata->governor == GOV_CONSERVATIVE) { + struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; + + sampling_rate = cs_tuners->sampling_rate; + } else { + struct od_dbs_tuners *od_tuners = dbs_data->tuners; + + sampling_rate = od_tuners->sampling_rate; + } + + if (!need_load_eval(cdbs->shared, sampling_rate)) + modify_all = false; + + delay = dbs_data->cdata->gov_dbs_timer(cdbs, dbs_data, modify_all); + gov_queue_work(dbs_data, policy, delay, modify_all); + + mutex_unlock(&shared->timer_mutex); +} static void set_sampling_rate(struct dbs_data *dbs_data, unsigned int sampling_rate) @@ -411,7 +441,7 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (ignore_nice) j_cdbs->prev_cpu_nice = kcpustat_cpu(j).cpustat[CPUTIME_NICE]; - INIT_DEFERRABLE_WORK(&j_cdbs->dwork, cdata->gov_dbs_timer); + INIT_DEFERRABLE_WORK(&j_cdbs->dwork, dbs_timer); } if (cdata->governor == GOV_CONSERVATIVE) { diff --git a/drivers/cpufreq/cpufreq_governor.h b/drivers/cpufreq/cpufreq_governor.h index 8e4a25f0730cd..50f1717966327 100644 --- a/drivers/cpufreq/cpufreq_governor.h +++ b/drivers/cpufreq/cpufreq_governor.h @@ -132,8 +132,8 @@ static void *get_cpu_dbs_info_s(int cpu) \ struct cpu_common_dbs_info { struct cpufreq_policy *policy; /* - * percpu mutex that serializes governor limit change with gov_dbs_timer - * invocation. We do not want gov_dbs_timer to run when user is changing + * percpu mutex that serializes governor limit change with dbs_timer + * invocation. We do not want dbs_timer to run when user is changing * the governor or limits. */ struct mutex timer_mutex; @@ -210,7 +210,9 @@ struct common_dbs_data { struct cpu_dbs_info *(*get_cpu_cdbs)(int cpu); void *(*get_cpu_dbs_info_s)(int cpu); - void (*gov_dbs_timer)(struct work_struct *work); + unsigned int (*gov_dbs_timer)(struct cpu_dbs_info *cdbs, + struct dbs_data *dbs_data, + bool modify_all); void (*gov_check_cpu)(int cpu, unsigned int load); int (*init)(struct dbs_data *dbs_data, bool notify); void (*exit)(struct dbs_data *dbs_data, bool notify); @@ -269,8 +271,6 @@ static ssize_t show_sampling_rate_min_gov_pol \ extern struct mutex cpufreq_governor_lock; void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); -bool need_load_eval(struct cpu_common_dbs_info *shared, - unsigned int sampling_rate); int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event); void gov_queue_work(struct dbs_data *dbs_data, struct cpufreq_policy *policy, diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 14d7e86e7f946..1fa9088c84a8d 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c @@ -191,48 +191,40 @@ static void od_check_cpu(int cpu, unsigned int load) } } -static void od_dbs_timer(struct work_struct *work) +static unsigned int od_dbs_timer(struct cpu_dbs_info *cdbs, + struct dbs_data *dbs_data, bool modify_all) { - struct od_cpu_dbs_info_s *dbs_info = - container_of(work, struct od_cpu_dbs_info_s, cdbs.dwork.work); - struct cpufreq_policy *policy = dbs_info->cdbs.shared->policy; + struct cpufreq_policy *policy = cdbs->shared->policy; unsigned int cpu = policy->cpu; - struct od_cpu_dbs_info_s *core_dbs_info = &per_cpu(od_cpu_dbs_info, + struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info, cpu); - struct dbs_data *dbs_data = policy->governor_data; struct od_dbs_tuners *od_tuners = dbs_data->tuners; - int delay = 0, sample_type = core_dbs_info->sample_type; - bool modify_all = true; + int delay = 0, sample_type = dbs_info->sample_type; - mutex_lock(&core_dbs_info->cdbs.shared->timer_mutex); - if (!need_load_eval(core_dbs_info->cdbs.shared, - od_tuners->sampling_rate)) { - modify_all = false; + if (!modify_all) goto max_delay; - } /* Common NORMAL_SAMPLE setup */ - core_dbs_info->sample_type = OD_NORMAL_SAMPLE; + dbs_info->sample_type = OD_NORMAL_SAMPLE; if (sample_type == OD_SUB_SAMPLE) { - delay = core_dbs_info->freq_lo_jiffies; - __cpufreq_driver_target(policy, core_dbs_info->freq_lo, + delay = dbs_info->freq_lo_jiffies; + __cpufreq_driver_target(policy, dbs_info->freq_lo, CPUFREQ_RELATION_H); } else { dbs_check_cpu(dbs_data, cpu); - if (core_dbs_info->freq_lo) { + if (dbs_info->freq_lo) { /* Setup timer for SUB_SAMPLE */ - core_dbs_info->sample_type = OD_SUB_SAMPLE; - delay = core_dbs_info->freq_hi_jiffies; + dbs_info->sample_type = OD_SUB_SAMPLE; + delay = dbs_info->freq_hi_jiffies; } } max_delay: if (!delay) delay = delay_for_sampling_rate(od_tuners->sampling_rate - * core_dbs_info->rate_mult); + * dbs_info->rate_mult); - gov_queue_work(dbs_data, policy, delay, modify_all); - mutex_unlock(&core_dbs_info->cdbs.shared->timer_mutex); + return delay; } /************************** sysfs interface ************************/ -- GitLab From a72c49590a1f9e5d26a71c3f807dbb8958c93513 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:01 +0530 Subject: [PATCH 1261/7006] cpufreq: governor: Avoid invalid states with additional checks There can be races where the request has come to a wrong state. For example INIT followed by STOP (instead of START) or START followed by EXIT (instead of STOP). Address these races by making sure the state-machine never gets into any invalid state. Also return an error if an invalid state-transition is requested. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 46 +++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index 7ed0ec2ac853e..f225dc9754158 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -305,6 +305,10 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy, unsigned int latency; int ret; + /* State should be equivalent to EXIT */ + if (policy->governor_data) + return -EBUSY; + if (dbs_data) { if (WARN_ON(have_governor_per_policy())) return -EINVAL; @@ -375,10 +379,15 @@ free_dbs_data: return ret; } -static void cpufreq_governor_exit(struct cpufreq_policy *policy, - struct dbs_data *dbs_data) +static int cpufreq_governor_exit(struct cpufreq_policy *policy, + struct dbs_data *dbs_data) { struct common_dbs_data *cdata = dbs_data->cdata; + struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(policy->cpu); + + /* State should be equivalent to INIT */ + if (!cdbs->shared || cdbs->shared->policy) + return -EBUSY; policy->governor_data = NULL; if (!--dbs_data->usage_count) { @@ -395,6 +404,7 @@ static void cpufreq_governor_exit(struct cpufreq_policy *policy, } free_common_dbs_info(policy, cdata); + return 0; } static int cpufreq_governor_start(struct cpufreq_policy *policy, @@ -409,6 +419,10 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, if (!policy->cur) return -EINVAL; + /* State should be equivalent to INIT */ + if (!shared || shared->policy) + return -EBUSY; + if (cdata->governor == GOV_CONSERVATIVE) { struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; @@ -465,14 +479,18 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy, return 0; } -static void cpufreq_governor_stop(struct cpufreq_policy *policy, - struct dbs_data *dbs_data) +static int cpufreq_governor_stop(struct cpufreq_policy *policy, + struct dbs_data *dbs_data) { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); struct cpu_common_dbs_info *shared = cdbs->shared; + /* State should be equivalent to START */ + if (!shared || !shared->policy) + return -EBUSY; + gov_cancel_work(dbs_data, policy); if (cdata->governor == GOV_CONSERVATIVE) { @@ -484,17 +502,19 @@ static void cpufreq_governor_stop(struct cpufreq_policy *policy, shared->policy = NULL; mutex_destroy(&shared->timer_mutex); + return 0; } -static void cpufreq_governor_limits(struct cpufreq_policy *policy, - struct dbs_data *dbs_data) +static int cpufreq_governor_limits(struct cpufreq_policy *policy, + struct dbs_data *dbs_data) { struct common_dbs_data *cdata = dbs_data->cdata; unsigned int cpu = policy->cpu; struct cpu_dbs_info *cdbs = cdata->get_cpu_cdbs(cpu); + /* State should be equivalent to START */ if (!cdbs->shared || !cdbs->shared->policy) - return; + return -EBUSY; mutex_lock(&cdbs->shared->timer_mutex); if (policy->max < cdbs->shared->policy->cur) @@ -505,13 +525,15 @@ static void cpufreq_governor_limits(struct cpufreq_policy *policy, CPUFREQ_RELATION_L); dbs_check_cpu(dbs_data, cpu); mutex_unlock(&cdbs->shared->timer_mutex); + + return 0; } int cpufreq_governor_dbs(struct cpufreq_policy *policy, struct common_dbs_data *cdata, unsigned int event) { struct dbs_data *dbs_data; - int ret = 0; + int ret; /* Lock governor to block concurrent initialization of governor */ mutex_lock(&cdata->mutex); @@ -531,17 +553,19 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, ret = cpufreq_governor_init(policy, dbs_data, cdata); break; case CPUFREQ_GOV_POLICY_EXIT: - cpufreq_governor_exit(policy, dbs_data); + ret = cpufreq_governor_exit(policy, dbs_data); break; case CPUFREQ_GOV_START: ret = cpufreq_governor_start(policy, dbs_data); break; case CPUFREQ_GOV_STOP: - cpufreq_governor_stop(policy, dbs_data); + ret = cpufreq_governor_stop(policy, dbs_data); break; case CPUFREQ_GOV_LIMITS: - cpufreq_governor_limits(policy, dbs_data); + ret = cpufreq_governor_limits(policy, dbs_data); break; + default: + ret = -EINVAL; } unlock: -- GitLab From 871ef3b53a2f4dd9be348c07b77df3c4bd74a37f Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:02 +0530 Subject: [PATCH 1262/7006] cpufreq: governor: Don't WARN on invalid states With previous commit, governors have started to return errors on invalid state-transition requests. We already have a WARN for an invalid state-transition request in cpufreq_governor_dbs(). This does trigger today, as the sequence of events isn't guaranteed by cpufreq core. Lets stop warning on that for now, and make sure we don't enter an invalid state. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq_governor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index f225dc9754158..939197ffa4ac0 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -543,7 +543,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, else dbs_data = cdata->gdbs_data; - if (WARN_ON(!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT))) { + if (!dbs_data && (event != CPUFREQ_GOV_POLICY_INIT)) { ret = -EINVAL; goto unlock; } -- GitLab From 4bc384ae6299d3f3a948efabda2a423e2a293ee0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Sat, 18 Jul 2015 11:31:03 +0530 Subject: [PATCH 1263/7006] cpufreq: propagate errors returned from __cpufreq_governor() Return codes aren't honored properly in cpufreq_set_policy(). This can lead to two problems: - wrong errors propagated to sysfs - we try to do next state-change even if the previous one failed cpufreq_governor_dbs() now returns proper errors on all invalid state-transition requests and this code should honor that. Reviewed-and-tested-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a7b6ac6e048e9..a3e8fb61cbccc 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2295,16 +2295,31 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, old_gov = policy->governor; /* end old governor */ if (old_gov) { - __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_STOP); + if (ret) { + /* This can happen due to race with other operations */ + pr_debug("%s: Failed to Stop Governor: %s (%d)\n", + __func__, old_gov->name, ret); + return ret; + } + up_write(&policy->rwsem); - __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); + ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT); down_write(&policy->rwsem); + + if (ret) { + pr_err("%s: Failed to Exit Governor: %s (%d)\n", + __func__, old_gov->name, ret); + return ret; + } } /* start new governor */ policy->governor = new_policy->governor; - if (!__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) { - if (!__cpufreq_governor(policy, CPUFREQ_GOV_START)) + ret = __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT); + if (!ret) { + ret = __cpufreq_governor(policy, CPUFREQ_GOV_START); + if (!ret) goto out; up_write(&policy->rwsem); @@ -2316,11 +2331,13 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, pr_debug("starting governor %s failed\n", policy->governor->name); if (old_gov) { policy->governor = old_gov; - __cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT); - __cpufreq_governor(policy, CPUFREQ_GOV_START); + if (__cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT)) + policy->governor = NULL; + else + __cpufreq_governor(policy, CPUFREQ_GOV_START); } - return -EINVAL; + return ret; out: pr_debug("governor: change or update limits\n"); -- GitLab From a7ce45a74bedd0ed80b956b3e14f8bc6dec85327 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 20 Jul 2015 23:03:45 +0200 Subject: [PATCH 1264/7006] bridge: mcast: fix br_multicast_dev_del warn when igmp snooping is not defined Fix: net/bridge/br_if.c: In function 'br_dev_delete': >> net/bridge/br_if.c:284:2: error: implicit declaration of function >> 'br_multicast_dev_del' [-Werror=implicit-function-declaration] br_multicast_dev_del(br); ^ cc1: some warnings being treated as errors when igmp snooping is not defined. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_private.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2bada2279721a..3ad1290528af5 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -566,6 +566,10 @@ static inline void br_multicast_stop(struct net_bridge *br) { } +static inline void br_multicast_dev_del(struct net_bridge *br) +{ +} + static inline void br_multicast_deliver(struct net_bridge_mdb_entry *mdst, struct sk_buff *skb) { -- GitLab From 8254973fa3459b512b6c0cd5b0e4641e4d7c048c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 16 Jul 2015 10:39:14 +0900 Subject: [PATCH 1265/7006] rocker: forward packets to CPU when port is joined to openvswitch Teach rocker to forward packets to CPU when a port is joined to Open vSwitch. There is scope to later refine what is passed up as per Open vSwitch flows on a port. This does not change the behaviour of rocker ports that are not joined to Open vSwitch. Signed-off-by: Simon Horman Acked-by: Scott Feldman Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 62 ++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 932428314b800..4ccde93cd07a0 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -202,6 +202,7 @@ enum { ROCKER_CTRL_IPV4_MCAST, ROCKER_CTRL_IPV6_MCAST, ROCKER_CTRL_DFLT_BRIDGING, + ROCKER_CTRL_DFLT_OVS, ROCKER_CTRL_MAX, }; @@ -321,9 +322,21 @@ static u16 rocker_port_vlan_to_vid(const struct rocker_port *rocker_port, return ntohs(vlan_id); } +static bool rocker_port_is_slave(const struct rocker_port *rocker_port, + const char *kind) +{ + return rocker_port->bridge_dev && + !strcmp(rocker_port->bridge_dev->rtnl_link_ops->kind, kind); +} + static bool rocker_port_is_bridged(const struct rocker_port *rocker_port) { - return !!rocker_port->bridge_dev; + return rocker_port_is_slave(rocker_port, "bridge"); +} + +static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port) +{ + return rocker_port_is_slave(rocker_port, "openvswitch"); } #define ROCKER_OP_FLAG_REMOVE BIT(0) @@ -3275,6 +3288,12 @@ static struct rocker_ctrl { .bridge = true, .copy_to_cpu = true, }, + [ROCKER_CTRL_DFLT_OVS] = { + /* pass all pkts up to CPU */ + .eth_dst = zero_mac, + .eth_dst_mask = zero_mac, + .acl = true, + }, }; static int rocker_port_ctrl_vlan_acl(struct rocker_port *rocker_port, @@ -3787,11 +3806,14 @@ static int rocker_port_stp_update(struct rocker_port *rocker_port, break; case BR_STATE_LEARNING: case BR_STATE_FORWARDING: - want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true; + if (!rocker_port_is_ovsed(rocker_port)) + want[ROCKER_CTRL_LINK_LOCAL_MCAST] = true; want[ROCKER_CTRL_IPV4_MCAST] = true; want[ROCKER_CTRL_IPV6_MCAST] = true; if (rocker_port_is_bridged(rocker_port)) want[ROCKER_CTRL_DFLT_BRIDGING] = true; + else if (rocker_port_is_ovsed(rocker_port)) + want[ROCKER_CTRL_DFLT_OVS] = true; else want[ROCKER_CTRL_LOCAL_ARP] = true; break; @@ -5264,23 +5286,39 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port) return err; } + +static int rocker_port_ovs_changed(struct rocker_port *rocker_port, + struct net_device *master) +{ + int err; + + rocker_port->bridge_dev = master; + + err = rocker_port_fwd_disable(rocker_port, SWITCHDEV_TRANS_NONE, 0); + if (err) + return err; + err = rocker_port_fwd_enable(rocker_port, SWITCHDEV_TRANS_NONE, 0); + + return err; +} + static int rocker_port_master_changed(struct net_device *dev) { struct rocker_port *rocker_port = netdev_priv(dev); struct net_device *master = netdev_master_upper_dev_get(dev); int err = 0; - /* There are currently three cases handled here: - * 1. Joining a bridge - * 2. Leaving a previously joined bridge - * 3. Other, e.g. being added to or removed from a bond or openvswitch, - * in which case nothing is done - */ - if (master && master->rtnl_link_ops && - !strcmp(master->rtnl_link_ops->kind, "bridge")) - err = rocker_port_bridge_join(rocker_port, master); - else if (rocker_port_is_bridged(rocker_port)) + /* N.B: Do nothing if the type of master is not supported */ + if (master && master->rtnl_link_ops) { + if (!strcmp(master->rtnl_link_ops->kind, "bridge")) + err = rocker_port_bridge_join(rocker_port, master); + else if (!strcmp(master->rtnl_link_ops->kind, "openvswitch")) + err = rocker_port_ovs_changed(rocker_port, master); + } else if (rocker_port_is_bridged(rocker_port)) { err = rocker_port_bridge_leave(rocker_port); + } else if (rocker_port_is_ovsed(rocker_port)) { + err = rocker_port_ovs_changed(rocker_port, NULL); + } return err; } -- GitLab From 0c4f691ff6791e55ac831666df0b49b1679c56e4 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 18 Jul 2015 18:24:48 -0700 Subject: [PATCH 1266/7006] net: don't reforward packets already forwarded by offload device Just before queuing skb for xmit on port, check if skb has been marked by switchdev port driver as already fordwarded by device. If so, drop skb. A non-zero skb->offload_fwd_mark field is set by the switchdev port driver/device on ingress to indicate the skb has already been forwarded by the device to egress ports with matching dev->skb_mark. The switchdev port driver would assign a non-zero dev->offload_skb_mark for each device port netdev during registration, for example. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Acked-by: Roopa Prabhu Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- include/linux/netdevice.h | 6 ++++++ include/linux/skbuff.h | 9 ++++++++- net/core/dev.c | 10 ++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 45cfd797eb77e..8364f29e08be2 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1456,6 +1456,8 @@ enum netdev_priv_flags { * * @xps_maps: XXX: need comments on this one * + * @offload_fwd_mark: Offload device fwding mark + * * @trans_start: Time (in jiffies) of last Tx * @watchdog_timeo: Represents the timeout that is used by * the watchdog ( see dev_watchdog() ) @@ -1697,6 +1699,10 @@ struct net_device { struct xps_dev_maps __rcu *xps_maps; #endif +#ifdef CONFIG_NET_SWITCHDEV + u32 offload_fwd_mark; +#endif + /* These may be needed for future network-power-down code. */ /* diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index d6cdd6e87d53b..af7a09650fa24 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -506,6 +506,7 @@ static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1, * @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS * @napi_id: id of the NAPI struct this skb came from * @secmark: security marking + * @offload_fwd_mark: fwding offload mark * @mark: Generic packet mark * @vlan_proto: vlan encapsulation protocol * @vlan_tci: vlan tag control information @@ -650,9 +651,15 @@ struct sk_buff { unsigned int sender_cpu; }; #endif + union { #ifdef CONFIG_NETWORK_SECMARK - __u32 secmark; + __u32 secmark; +#endif +#ifdef CONFIG_NET_SWITCHDEV + __u32 offload_fwd_mark; #endif + }; + union { __u32 mark; __u32 reserved_tailroom; diff --git a/net/core/dev.c b/net/core/dev.c index 8810b6bbebfea..2ee15afb412d7 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3061,6 +3061,16 @@ static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv) else skb_dst_force(skb); +#ifdef CONFIG_NET_SWITCHDEV + /* Don't forward if offload device already forwarded */ + if (skb->offload_fwd_mark && + skb->offload_fwd_mark == dev->offload_fwd_mark) { + consume_skb(skb); + rc = NET_XMIT_SUCCESS; + goto out; + } +#endif + txq = netdev_pick_tx(dev, skb, accel_priv); q = rcu_dereference_bh(txq->qdisc); -- GitLab From d754f98b502ad9a8c7570d494e1eaa0e6bc0350c Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 18 Jul 2015 18:24:49 -0700 Subject: [PATCH 1267/7006] net: add phys ID compare helper to test if two IDs are the same Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 7 +++++++ net/switchdev/switchdev.c | 8 ++------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 8364f29e08be2..607b5f41f46f9 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -766,6 +766,13 @@ struct netdev_phys_item_id { unsigned char id_len; }; +static inline bool netdev_phys_item_id_same(struct netdev_phys_item_id *a, + struct netdev_phys_item_id *b) +{ + return a->id_len == b->id_len && + memcmp(a->id, b->id, a->id_len) == 0; +} + typedef u16 (*select_queue_fallback_t)(struct net_device *dev, struct sk_buff *skb); diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 9f2add3cba26e..4e5bba50ccffa 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -910,13 +910,9 @@ static struct net_device *switchdev_get_dev_by_nhs(struct fib_info *fi) if (switchdev_port_attr_get(dev, &attr)) return NULL; - if (nhsel > 0) { - if (prev_attr.u.ppid.id_len != attr.u.ppid.id_len) + if (nhsel > 0 && + !netdev_phys_item_id_same(&prev_attr.u.ppid, &attr.u.ppid)) return NULL; - if (memcmp(prev_attr.u.ppid.id, attr.u.ppid.id, - attr.u.ppid.id_len)) - return NULL; - } prev_attr = attr; } -- GitLab From 1a3b2ec93d4277b121979321b4024b438cb09504 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 18 Jul 2015 18:24:50 -0700 Subject: [PATCH 1268/7006] switchdev: add offload_fwd_mark generator helper skb->offload_fwd_mark and dev->offload_fwd_mark are 32-bit and should be unique for device and may even be unique for a sub-set of ports within device, so add switchdev helper function to generate unique marks based on port's switch ID and group_ifindex. group_ifindex would typically be the container dev's ifindex, such as the bridge's ifindex. The generator uses a global hash table to store offload_fwd_marks hashed by {switch ID, group_ifindex} key. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- include/net/switchdev.h | 9 ++++ net/switchdev/switchdev.c | 103 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+) diff --git a/include/net/switchdev.h b/include/net/switchdev.h index d5671f118bfc5..89da8934519bb 100644 --- a/include/net/switchdev.h +++ b/include/net/switchdev.h @@ -157,6 +157,9 @@ int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, struct net_device *dev, struct net_device *filter_dev, int idx); +void switchdev_port_fwd_mark_set(struct net_device *dev, + struct net_device *group_dev, + bool joining); #else @@ -271,6 +274,12 @@ static inline int switchdev_port_fdb_dump(struct sk_buff *skb, return -EOPNOTSUPP; } +static inline void switchdev_port_fwd_mark_set(struct net_device *dev, + struct net_device *group_dev, + bool joining) +{ +} + #endif #endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 4e5bba50ccffa..33bafa2e703e2 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -1039,3 +1039,106 @@ void switchdev_fib_ipv4_abort(struct fib_info *fi) fi->fib_net->ipv4.fib_offload_disabled = true; } EXPORT_SYMBOL_GPL(switchdev_fib_ipv4_abort); + +static bool switchdev_port_same_parent_id(struct net_device *a, + struct net_device *b) +{ + struct switchdev_attr a_attr = { + .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .flags = SWITCHDEV_F_NO_RECURSE, + }; + struct switchdev_attr b_attr = { + .id = SWITCHDEV_ATTR_PORT_PARENT_ID, + .flags = SWITCHDEV_F_NO_RECURSE, + }; + + if (switchdev_port_attr_get(a, &a_attr) || + switchdev_port_attr_get(b, &b_attr)) + return false; + + return netdev_phys_item_id_same(&a_attr.u.ppid, &b_attr.u.ppid); +} + +static u32 switchdev_port_fwd_mark_get(struct net_device *dev, + struct net_device *group_dev) +{ + struct net_device *lower_dev; + struct list_head *iter; + + netdev_for_each_lower_dev(group_dev, lower_dev, iter) { + if (lower_dev == dev) + continue; + if (switchdev_port_same_parent_id(dev, lower_dev)) + return lower_dev->offload_fwd_mark; + return switchdev_port_fwd_mark_get(dev, lower_dev); + } + + return dev->ifindex; +} + +static void switchdev_port_fwd_mark_reset(struct net_device *group_dev, + u32 old_mark, u32 *reset_mark) +{ + struct net_device *lower_dev; + struct list_head *iter; + + netdev_for_each_lower_dev(group_dev, lower_dev, iter) { + if (lower_dev->offload_fwd_mark == old_mark) { + if (!*reset_mark) + *reset_mark = lower_dev->ifindex; + lower_dev->offload_fwd_mark = *reset_mark; + } + switchdev_port_fwd_mark_reset(lower_dev, old_mark, reset_mark); + } +} + +/** + * switchdev_port_fwd_mark_set - Set port offload forwarding mark + * + * @dev: port device + * @group_dev: containing device + * @joining: true if dev is joining group; false if leaving group + * + * An ungrouped port's offload mark is just its ifindex. A grouped + * port's (member of a bridge, for example) offload mark is the ifindex + * of one of the ports in the group with the same parent (switch) ID. + * Ports on the same device in the same group will have the same mark. + * + * Example: + * + * br0 ifindex=9 + * sw1p1 ifindex=2 mark=2 + * sw1p2 ifindex=3 mark=2 + * sw2p1 ifindex=4 mark=5 + * sw2p2 ifindex=5 mark=5 + * + * If sw2p2 leaves the bridge, we'll have: + * + * br0 ifindex=9 + * sw1p1 ifindex=2 mark=2 + * sw1p2 ifindex=3 mark=2 + * sw2p1 ifindex=4 mark=4 + * sw2p2 ifindex=5 mark=5 + */ +void switchdev_port_fwd_mark_set(struct net_device *dev, + struct net_device *group_dev, + bool joining) +{ + u32 mark = dev->ifindex; + u32 reset_mark = 0; + + if (group_dev && joining) { + mark = switchdev_port_fwd_mark_get(dev, group_dev); + } else if (group_dev && !joining) { + if (dev->offload_fwd_mark == mark) + /* Ohoh, this port was the mark reference port, + * but it's leaving the group, so reset the + * mark for the remaining ports in the group. + */ + switchdev_port_fwd_mark_reset(group_dev, mark, + &reset_mark); + } + + dev->offload_fwd_mark = mark; +} +EXPORT_SYMBOL_GPL(switchdev_port_fwd_mark_set); -- GitLab From 3f98a8e636757ce404f305d65dc93e9366112886 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 18 Jul 2015 18:24:51 -0700 Subject: [PATCH 1269/7006] rocker: add offload_fwd_mark support If device flags ingress packet as "fwd offload", mark the skb->offlaod_fwd_mark using the ingress port's dev->offlaod_fwd_mark. This will be the hint to the kernel that this packet has already been forwarded by device to egress ports matching skb->offlaod_fwd_mark. For rocker, derive port dev->offlaod_fwd_mark based on device switch ID and port ifindex. If port is bridged, use the bridge ifindex rather than the port ifindex. Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/rocker/rocker.c | 11 +++++++++++ drivers/net/ethernet/rocker/rocker.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 4ccde93cd07a0..7b4c3474acfe8 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -4822,6 +4822,7 @@ static int rocker_port_rx_proc(const struct rocker *rocker, const struct rocker_tlv *attrs[ROCKER_TLV_RX_MAX + 1]; struct sk_buff *skb = rocker_desc_cookie_ptr_get(desc_info); size_t rx_len; + u16 rx_flags = 0; if (!skb) return -ENOENT; @@ -4829,6 +4830,8 @@ static int rocker_port_rx_proc(const struct rocker *rocker, rocker_tlv_parse_desc(attrs, ROCKER_TLV_RX_MAX, desc_info); if (!attrs[ROCKER_TLV_RX_FRAG_LEN]) return -EINVAL; + if (attrs[ROCKER_TLV_RX_FLAGS]) + rx_flags = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FLAGS]); rocker_dma_rx_ring_skb_unmap(rocker, attrs); @@ -4836,6 +4839,9 @@ static int rocker_port_rx_proc(const struct rocker *rocker, skb_put(skb, rx_len); skb->protocol = eth_type_trans(skb, rocker_port->dev); + if (rx_flags & ROCKER_RX_FLAGS_FWD_OFFLOAD) + skb->offload_fwd_mark = rocker_port->dev->offload_fwd_mark; + rocker_port->dev->stats.rx_packets++; rocker_port->dev->stats.rx_bytes += skb->len; @@ -4973,6 +4979,8 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number) } rocker->ports[port_number] = rocker_port; + switchdev_port_fwd_mark_set(rocker_port->dev, NULL, false); + rocker_port_set_learning(rocker_port, SWITCHDEV_TRANS_NONE); err = rocker_port_ig_tbl(rocker_port, SWITCHDEV_TRANS_NONE, 0); @@ -5252,6 +5260,7 @@ static int rocker_port_bridge_join(struct rocker_port *rocker_port, rocker_port_internal_vlan_id_get(rocker_port, bridge->ifindex); rocker_port->bridge_dev = bridge; + switchdev_port_fwd_mark_set(rocker_port->dev, bridge, true); return rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, untagged_vid, 0); @@ -5272,6 +5281,8 @@ static int rocker_port_bridge_leave(struct rocker_port *rocker_port) rocker_port_internal_vlan_id_get(rocker_port, rocker_port->dev->ifindex); + switchdev_port_fwd_mark_set(rocker_port->dev, rocker_port->bridge_dev, + false); rocker_port->bridge_dev = NULL; err = rocker_port_vlan_add(rocker_port, SWITCHDEV_TRANS_NONE, diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h index 08b2c3d961887..12490b2f65040 100644 --- a/drivers/net/ethernet/rocker/rocker.h +++ b/drivers/net/ethernet/rocker/rocker.h @@ -246,6 +246,7 @@ enum { #define ROCKER_RX_FLAGS_TCP BIT(5) #define ROCKER_RX_FLAGS_UDP BIT(6) #define ROCKER_RX_FLAGS_TCP_UDP_CSUM_GOOD BIT(7) +#define ROCKER_RX_FLAGS_FWD_OFFLOAD BIT(8) enum { ROCKER_TLV_TX_UNSPEC, -- GitLab From a48037e7c6c25436912f78f48cdbb75a710b7aa9 Mon Sep 17 00:00:00 2001 From: Scott Feldman Date: Sat, 18 Jul 2015 18:24:52 -0700 Subject: [PATCH 1270/7006] switchdev: update documentation for offload_fwd_mark Signed-off-by: Scott Feldman Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- Documentation/networking/switchdev.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/networking/switchdev.txt b/Documentation/networking/switchdev.txt index c5d7ade10ff21..9825f32a86349 100644 --- a/Documentation/networking/switchdev.txt +++ b/Documentation/networking/switchdev.txt @@ -279,8 +279,18 @@ and unknown unicast packets to all ports in domain, if allowed by port's current STP state. The switch driver, knowing which ports are within which vlan L2 domain, can program the switch device for flooding. The packet should also be sent to the port netdev for processing by the bridge driver. The -bridge should not reflood the packet to the same ports the device flooded. -XXX: the mechanism to avoid duplicate flood packets is being discuseed. +bridge should not reflood the packet to the same ports the device flooded, +otherwise there will be duplicate packets on the wire. + +To avoid duplicate packets, the device/driver should mark a packet as already +forwarded using skb->offload_fwd_mark. The same mark is set on the device +ports in the domain using dev->offload_fwd_mark. If the skb->offload_fwd_mark +is non-zero and matches the forwarding egress port's dev->skb_mark, the kernel +will drop the skb right before transmit on the egress port, with the +understanding that the device already forwarded the packet on same egress port. +The driver can use switchdev_port_fwd_mark_set() to set a globally unique mark +for port's dev->offload_fwd_mark, based on the port's parent ID (switch ID) and +a group ifindex. It is possible for the switch device to not handle flooding and push the packets up to the bridge driver for flooding. This is not ideal as the number -- GitLab From 2476c09f391eddb546a73fef9f6ab86886a9f2b1 Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Mon, 20 Jul 2015 08:28:43 +0530 Subject: [PATCH 1271/7006] powerpc/signal: Add helper function to fetch quad word aligned pointer This patch adds one helper function 'sigcontext_vmx_regs' which computes quad word aligned pointer for 'vmx_reserve' array element in sigcontext structure making the code more readable. Signed-off-by: Anshuman Khandual [mpe: Reword comment and fix build for CONFIG_ALTIVEC=n] Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/signal_64.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index c7c24d2e2bdbc..20756dfb9f346 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -73,6 +73,19 @@ static const char fmt32[] = KERN_INFO \ static const char fmt64[] = KERN_INFO \ "%s[%d]: bad frame in %s: %016lx nip %016lx lr %016lx\n"; +/* + * This computes a quad word aligned pointer inside the vmx_reserve array + * element. For historical reasons sigcontext might not be quad word aligned, + * but the location we write the VMX regs to must be. See the comment in + * sigcontext for more detail. + */ +#ifdef CONFIG_ALTIVEC +static elf_vrreg_t __user *sigcontext_vmx_regs(struct sigcontext __user *sc) +{ + return (elf_vrreg_t __user *) (((unsigned long)sc->vmx_reserve + 15) & ~0xful); +} +#endif + /* * Set up the sigcontext for the signal frame. */ @@ -90,7 +103,7 @@ static long setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs, * v_regs pointer or not */ #ifdef CONFIG_ALTIVEC - elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *)(((unsigned long)sc->vmx_reserve + 15) & ~0xful); + elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc); #endif unsigned long msr = regs->msr; long err = 0; @@ -181,10 +194,8 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc, * v_regs pointer or not. */ #ifdef CONFIG_ALTIVEC - elf_vrreg_t __user *v_regs = (elf_vrreg_t __user *) - (((unsigned long)sc->vmx_reserve + 15) & ~0xful); - elf_vrreg_t __user *tm_v_regs = (elf_vrreg_t __user *) - (((unsigned long)tm_sc->vmx_reserve + 15) & ~0xful); + elf_vrreg_t __user *v_regs = sigcontext_vmx_regs(sc); + elf_vrreg_t __user *tm_v_regs = sigcontext_vmx_regs(tm_sc); #endif unsigned long msr = regs->msr; long err = 0; -- GitLab From 0f36db77643b6fb573313d97fa076903de6a34d6 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 12 May 2015 17:05:22 +1000 Subject: [PATCH 1272/7006] powerpc/eeh: Fix wrong printed PE number On LE kernel, the non-existing PE number in BE format derived from skiboot firmware isn't converted to LE format properly as following kernel log indicates: EEH: Clear non-existing PHB#4-PE#200000000000000 Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/eeh-powernv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index 5cf5e6ea213ba..b357cdc3f4726 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -1396,7 +1396,7 @@ static int pnv_eeh_next_error(struct eeh_pe **pe) be64_to_cpu(frozen_pe_no), pe)) { /* Try best to clear it */ pr_info("EEH: Clear non-existing PHB#%x-PE#%llx\n", - hose->global_number, frozen_pe_no); + hose->global_number, be64_to_cpu(frozen_pe_no)); pr_info("EEH: PHB location: %s\n", eeh_pe_loc_get(phb_pe)); opal_pci_eeh_freeze_clear(phb->opal_id, -- GitLab From 79cd95200035fb4b39b089dd01c13302eee6ee03 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Tue, 12 May 2015 17:05:32 +1000 Subject: [PATCH 1273/7006] powerpc/eeh: Dump PHB diag-data for non-existing PE When detecting EEH error on non-existing PE, including the reserved one, the PE is simply unfrozen without dumping the PHB diag-data, which is useful for locating the root cause of the EEH error. The patch dumps the PHB diag-data when non-existing PE reports error. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/eeh-powernv.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/platforms/powernv/eeh-powernv.c b/arch/powerpc/platforms/powernv/eeh-powernv.c index b357cdc3f4726..0fe2b0cb587a0 100644 --- a/arch/powerpc/platforms/powernv/eeh-powernv.c +++ b/arch/powerpc/platforms/powernv/eeh-powernv.c @@ -1394,11 +1394,19 @@ static int pnv_eeh_next_error(struct eeh_pe **pe) */ if (pnv_eeh_get_pe(hose, be64_to_cpu(frozen_pe_no), pe)) { - /* Try best to clear it */ pr_info("EEH: Clear non-existing PHB#%x-PE#%llx\n", hose->global_number, be64_to_cpu(frozen_pe_no)); pr_info("EEH: PHB location: %s\n", eeh_pe_loc_get(phb_pe)); + + /* Dump PHB diag-data */ + rc = opal_pci_get_phb_diag_data2(phb->opal_id, + phb->diag.blob, PNV_PCI_DIAG_BUF_SIZE); + if (rc == OPAL_SUCCESS) + pnv_pci_dump_phb_diag_data(hose, + phb->diag.blob); + + /* Try best to clear it */ opal_pci_eeh_freeze_clear(phb->opal_id, frozen_pe_no, OPAL_EEH_ACTION_CLEAR_FREEZE_ALL); -- GitLab From 9fe6b778ca93e6171dbb8e54df557a278a91abea Mon Sep 17 00:00:00 2001 From: Gil Fruchter Date: Tue, 9 Jun 2015 10:32:34 +0300 Subject: [PATCH 1274/7006] tracing: Prefer kcalloc over kzalloc with multiply Use kcalloc for allocating an array instead of kzalloc with multiply, as that is what kcalloc is used for. Found with checkpatch. Link: http://lkml.kernel.org/r/1433835155-6894-2-git-send-email-gilf@ezchip.com Signed-off-by: Gil Fruchter Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index abcbf7ff87436..5d219384b4d18 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3035,7 +3035,7 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) if (!iter) return ERR_PTR(-ENOMEM); - iter->buffer_iter = kzalloc(sizeof(*iter->buffer_iter) * num_possible_cpus(), + iter->buffer_iter = kcalloc(num_possible_cpus(), sizeof(*iter->buffer_iter), GFP_KERNEL); if (!iter->buffer_iter) goto release; -- GitLab From 72917235fd5f08638be1d52dcdb0fee3ce2cc95f Mon Sep 17 00:00:00 2001 From: Gil Fruchter Date: Tue, 9 Jun 2015 10:32:35 +0300 Subject: [PATCH 1275/7006] tracing: Fix for non-continuous cpu ids Currently exception occures due to access beyond buffer_iter range while using index of cpu bigger than num_possible_cpus(). Below there is an example for such exception when we use cpus 0,1,16,17. In order to fix buffer allocation size for non-continuous cpu ids we allocate according to the max cpu id and not according to the amount of possible cpus. Example: $ cat /sys/kernel/debug/tracing/per_cpu/cpu1/trace Path: /bin/busybox CPU: 0 PID: 82 Comm: cat Not tainted 4.0.0 #29 task: 80734c80 ti: 80012000 task.ti: 80012000 [ECR ]: 0x00220100 => Invalid Read @ 0x00000000 by insn @ 0x800abafc [EFA ]: 0x00000000 [BLINK ]: ring_buffer_read_finish+0x24/0x64 [ERET ]: rb_check_pages+0x20/0x188 [STAT32]: 0x00001a00 : BTA: 0x800abafc SP: 0x80013f0c FP: 0x57719cf8 LPS: 0x200036b4 LPE: 0x200036b8 LPC: 0x00000000 r00: 0x8002aca0 r01: 0x00001606 r02: 0x00000000 r03: 0x00000001 r04: 0x00000000 r05: 0x804b4954 r06: 0x00030003 r07: 0x8002a260 r08: 0x00000286 r09: 0x00080002 r10: 0x00001006 r11: 0x807351a4 r12: 0x00000001 Stack Trace: rb_check_pages+0x20/0x188 ring_buffer_read_finish+0x24/0x64 tracing_release+0x4e/0x170 __fput+0x62/0x158 task_work_run+0xa2/0xd4 do_notify_resume+0x52/0x7c resume_user_mode_begin+0xdc/0xe0 Link: http://lkml.kernel.org/r/1433835155-6894-3-git-send-email-gilf@ezchip.com Signed-off-by: Noam Camus Signed-off-by: Gil Fruchter Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 5d219384b4d18..59814adc39d6b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -3035,7 +3035,7 @@ __tracing_open(struct inode *inode, struct file *file, bool snapshot) if (!iter) return ERR_PTR(-ENOMEM); - iter->buffer_iter = kcalloc(num_possible_cpus(), sizeof(*iter->buffer_iter), + iter->buffer_iter = kcalloc(nr_cpu_ids, sizeof(*iter->buffer_iter), GFP_KERNEL); if (!iter->buffer_iter) goto release; -- GitLab From 5e2d5ef8ec1e3854daec41a3697a8d2ce05ff2ef Mon Sep 17 00:00:00 2001 From: Umesh Tiwari Date: Mon, 22 Jun 2015 16:55:06 +0530 Subject: [PATCH 1276/7006] ftrace: correct the counter increment for trace_buffer data In ftrace_dump, for disabling buffer, iter.tr->trace_buffer.data is used. But for enabling, iter.trace_buffer->data is used. Even though, both point to same buffer, for readability, same convention should be used. Link: http://lkml.kernel.org/r/1434972306-20043-1-git-send-email-umesh.t@samsung.com Signed-off-by: Umesh Tiwari Signed-off-by: Steven Rostedt --- kernel/trace/trace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 59814adc39d6b..6e79408674aaa 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6990,7 +6990,7 @@ void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) trace_init_global_iter(&iter); for_each_tracing_cpu(cpu) { - atomic_inc(&per_cpu_ptr(iter.tr->trace_buffer.data, cpu)->disabled); + atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled); } old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ; -- GitLab From fcc742eaad7cbcbbb2a96edc8f1d22adbaa804cb Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 28 May 2015 17:13:14 -0400 Subject: [PATCH 1277/7006] ring-buffer: Add event descriptor to simplify passing data Add rb_event_info descriptor to pass event info to functions a bit easier than using a bunch of parameters. This will also allow for changing the code around a bit to find better fast paths. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 91 ++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 6260717c18e3c..ba8f25ffcf6f1 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -399,6 +399,17 @@ struct rb_irq_work { bool wakeup_full; }; +/* + * Structure to hold event state and handle nested events. + */ +struct rb_event_info { + u64 ts; + u64 delta; + unsigned long length; + struct buffer_page *tail_page; + int add_timestamp; +}; + /* * Used for which event context the event is in. * NMI = 0 @@ -2000,9 +2011,12 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) */ static void rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event, unsigned length, - int add_timestamp, u64 delta) + struct ring_buffer_event *event, + struct rb_event_info *info) { + unsigned length = info->length; + u64 delta = info->delta; + /* Only a commit updates the timestamp */ if (unlikely(!rb_event_is_commit(cpu_buffer, event))) delta = 0; @@ -2011,7 +2025,7 @@ rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, * If we need to add a timestamp, then we * add it to the start of the resevered space. */ - if (unlikely(add_timestamp)) { + if (unlikely(info->add_timestamp)) { event = rb_add_time_stamp(event, delta); length -= RB_LEN_TIME_EXTEND; delta = 0; @@ -2203,10 +2217,11 @@ static unsigned rb_calculate_event_length(unsigned length) static inline void rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, - struct buffer_page *tail_page, - unsigned long tail, unsigned long length) + unsigned long tail, struct rb_event_info *info) { + struct buffer_page *tail_page = info->tail_page; struct ring_buffer_event *event; + unsigned long length = info->length; /* * Only the event that crossed the page boundary @@ -2276,13 +2291,14 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, */ static noinline struct ring_buffer_event * rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, - unsigned long length, unsigned long tail, - struct buffer_page *tail_page, u64 ts) + unsigned long tail, struct rb_event_info *info) { + struct buffer_page *tail_page = info->tail_page; struct buffer_page *commit_page = cpu_buffer->commit_page; struct ring_buffer *buffer = cpu_buffer->buffer; struct buffer_page *next_page; int ret; + u64 ts; next_page = tail_page; @@ -2368,25 +2384,24 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, out_again: - rb_reset_tail(cpu_buffer, tail_page, tail, length); + rb_reset_tail(cpu_buffer, tail, info); /* fail and let the caller try again */ return ERR_PTR(-EAGAIN); out_reset: /* reset write */ - rb_reset_tail(cpu_buffer, tail_page, tail, length); + rb_reset_tail(cpu_buffer, tail, info); return NULL; } static struct ring_buffer_event * __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, - unsigned long length, u64 ts, - u64 delta, int add_timestamp) + struct rb_event_info *info) { - struct buffer_page *tail_page; struct ring_buffer_event *event; + struct buffer_page *tail_page; unsigned long tail, write; /* @@ -2394,33 +2409,32 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, * hold in the time field of the event, then we append a * TIME EXTEND event ahead of the data event. */ - if (unlikely(add_timestamp)) - length += RB_LEN_TIME_EXTEND; + if (unlikely(info->add_timestamp)) + info->length += RB_LEN_TIME_EXTEND; - tail_page = cpu_buffer->tail_page; - write = local_add_return(length, &tail_page->write); + tail_page = info->tail_page = cpu_buffer->tail_page; + write = local_add_return(info->length, &tail_page->write); /* set write to only the index of the write */ write &= RB_WRITE_MASK; - tail = write - length; + tail = write - info->length; /* * If this is the first commit on the page, then it has the same * timestamp as the page itself. */ if (!tail) - delta = 0; + info->delta = 0; /* See if we shot pass the end of this buffer page */ if (unlikely(write > BUF_PAGE_SIZE)) - return rb_move_tail(cpu_buffer, length, tail, - tail_page, ts); + return rb_move_tail(cpu_buffer, tail, info); /* We reserved something on the buffer */ event = __rb_page_index(tail_page, tail); kmemcheck_annotate_bitfield(event, bitfield); - rb_update_event(cpu_buffer, event, length, add_timestamp, delta); + rb_update_event(cpu_buffer, event, info); local_inc(&tail_page->entries); @@ -2429,10 +2443,10 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, * its timestamp. */ if (!tail) - tail_page->page->time_stamp = ts; + tail_page->page->time_stamp = info->ts; /* account for these added bytes */ - local_add(length, &cpu_buffer->entries_bytes); + local_add(info->length, &cpu_buffer->entries_bytes); return event; } @@ -2521,9 +2535,8 @@ rb_reserve_next_event(struct ring_buffer *buffer, unsigned long length) { struct ring_buffer_event *event; - u64 ts, delta; + struct rb_event_info info; int nr_loops = 0; - int add_timestamp; u64 diff; rb_start_commit(cpu_buffer); @@ -2543,10 +2556,10 @@ rb_reserve_next_event(struct ring_buffer *buffer, } #endif - length = rb_calculate_event_length(length); + info.length = rb_calculate_event_length(length); again: - add_timestamp = 0; - delta = 0; + info.add_timestamp = 0; + info.delta = 0; /* * We allow for interrupts to reenter here and do a trace. @@ -2560,35 +2573,35 @@ rb_reserve_next_event(struct ring_buffer *buffer, if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000)) goto out_fail; - ts = rb_time_stamp(cpu_buffer->buffer); - diff = ts - cpu_buffer->write_stamp; + info.ts = rb_time_stamp(cpu_buffer->buffer); + diff = info.ts - cpu_buffer->write_stamp; /* make sure this diff is calculated here */ barrier(); /* Did the write stamp get updated already? */ - if (likely(ts >= cpu_buffer->write_stamp)) { - delta = diff; - if (unlikely(test_time_stamp(delta))) { + if (likely(info.ts >= cpu_buffer->write_stamp)) { + info.delta = diff; + if (unlikely(test_time_stamp(info.delta))) { int local_clock_stable = 1; #ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK local_clock_stable = sched_clock_stable(); #endif - WARN_ONCE(delta > (1ULL << 59), + WARN_ONCE(info.delta > (1ULL << 59), KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", - (unsigned long long)delta, - (unsigned long long)ts, + (unsigned long long)info.delta, + (unsigned long long)info.ts, (unsigned long long)cpu_buffer->write_stamp, local_clock_stable ? "" : "If you just came from a suspend/resume,\n" "please switch to the trace global clock:\n" " echo global > /sys/kernel/debug/tracing/trace_clock\n"); - add_timestamp = 1; + info.add_timestamp = 1; } } - event = __rb_reserve_next(cpu_buffer, length, ts, - delta, add_timestamp); + event = __rb_reserve_next(cpu_buffer, &info); + if (unlikely(PTR_ERR(event) == -EAGAIN)) goto again; -- GitLab From 9826b2733a4399149072058a11f611357479229d Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 28 May 2015 17:36:45 -0400 Subject: [PATCH 1278/7006] ring-buffer: Move the adding of the extended timestamp out of line Requiring a extended time stamp is an uncommon occurrence, and it is best to do it out of line when needed. Add a noinline function that handles the extended timestamp and have it called with an unlikely to completely move it out of the fast path. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 41 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index ba8f25ffcf6f1..a78d4ee4bc584 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2396,6 +2396,29 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, return NULL; } +#ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK +static inline bool sched_clock_stable(void) +{ + return true; +} +#endif + +static noinline void +rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, + struct rb_event_info *info) +{ + WARN_ONCE(info->delta > (1ULL << 59), + KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", + (unsigned long long)info->delta, + (unsigned long long)info->ts, + (unsigned long long)cpu_buffer->write_stamp, + sched_clock_stable() ? "" : + "If you just came from a suspend/resume,\n" + "please switch to the trace global clock:\n" + " echo global > /sys/kernel/debug/tracing/trace_clock\n"); + info->add_timestamp = 1; +} + static struct ring_buffer_event * __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, struct rb_event_info *info) @@ -2582,22 +2605,8 @@ rb_reserve_next_event(struct ring_buffer *buffer, /* Did the write stamp get updated already? */ if (likely(info.ts >= cpu_buffer->write_stamp)) { info.delta = diff; - if (unlikely(test_time_stamp(info.delta))) { - int local_clock_stable = 1; -#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK - local_clock_stable = sched_clock_stable(); -#endif - WARN_ONCE(info.delta > (1ULL << 59), - KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", - (unsigned long long)info.delta, - (unsigned long long)info.ts, - (unsigned long long)cpu_buffer->write_stamp, - local_clock_stable ? "" : - "If you just came from a suspend/resume,\n" - "please switch to the trace global clock:\n" - " echo global > /sys/kernel/debug/tracing/trace_clock\n"); - info.add_timestamp = 1; - } + if (unlikely(test_time_stamp(info.delta))) + rb_handle_timestamp(cpu_buffer, &info); } event = __rb_reserve_next(cpu_buffer, &info); -- GitLab From a4543a2fa9ef31d6d0f854a4e14f8f82e7996d8d Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 29 May 2015 09:40:18 -0400 Subject: [PATCH 1279/7006] ring-buffer: Get timestamp after event is allocated Move the capturing of the timestamp to after an event is allocated. If the event is not a commit (where it is an event that preempted another event), then no timestamp is needed, because the delta of nested events is always zero. If the event starts on a new page, no delta needs to be calculated as the full timestamp will be added to the page header, and the event will have a delta of zero. Now if the event requires a time extend (the delta does not fit in the 27 bit delta slot in the header), then the event is discarded, the length is extended to hold the TIME_EXTEND event that allows for a 59 bit delta, and the commit is tried again. If the event can't be discarded (another event came in after it), then the TIME_EXTEND is added directly to the allocated event and the rest of the event is given padding. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 161 ++++++++++++++++++++++++++----------- 1 file changed, 114 insertions(+), 47 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index a78d4ee4bc584..b5ed553e0a45f 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2009,7 +2009,7 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) * and with this, we can determine what to place into the * data field. */ -static void +static void __always_inline rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event, struct rb_event_info *info) @@ -2017,10 +2017,6 @@ rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, unsigned length = info->length; u64 delta = info->delta; - /* Only a commit updates the timestamp */ - if (unlikely(!rb_event_is_commit(cpu_buffer, event))) - delta = 0; - /* * If we need to add a timestamp, then we * add it to the start of the resevered space. @@ -2286,6 +2282,8 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, local_sub(length, &tail_page->write); } +static inline void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer); + /* * This is the slow path, force gcc not to inline it. */ @@ -2300,6 +2298,16 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, int ret; u64 ts; + /* + * If the event had a timestamp attached to it, remove it. + * The first event on a page (nested or not) always uses + * the full timestamp of the new page. + */ + if (info->add_timestamp) { + info->add_timestamp = 0; + info->length -= RB_LEN_TIME_EXTEND; + } + next_page = tail_page; rb_inc_page(cpu_buffer, &next_page); @@ -2386,6 +2394,11 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, rb_reset_tail(cpu_buffer, tail, info); + /* Commit what we have for now to update timestamps */ + rb_end_commit(cpu_buffer); + /* rb_end_commit() decs committing */ + local_inc(&cpu_buffer->committing); + /* fail and let the caller try again */ return ERR_PTR(-EAGAIN); @@ -2403,10 +2416,23 @@ static inline bool sched_clock_stable(void) } #endif +static inline int +rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event); +static inline void rb_event_discard(struct ring_buffer_event *event); +static void +rb_update_write_stamp(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event); + static noinline void rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event, struct rb_event_info *info) { + struct ring_buffer_event *padding; + int length; + int size; + WARN_ONCE(info->delta > (1ULL << 59), KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", (unsigned long long)info->delta, @@ -2416,7 +2442,61 @@ rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, "If you just came from a suspend/resume,\n" "please switch to the trace global clock:\n" " echo global > /sys/kernel/debug/tracing/trace_clock\n"); - info->add_timestamp = 1; + + /* + * Discarding this event to add a timestamp in front, but + * we still need to update the length of it to perform the discard. + */ + rb_update_event(cpu_buffer, event, info); + + if (rb_try_to_discard(cpu_buffer, event)) { + info->add_timestamp = 1; + /* + * The time delta since the last event is too big to + * hold in the time field of the event, then we append a + * TIME EXTEND event ahead of the data event. + */ + info->length += RB_LEN_TIME_EXTEND; + return; + } + + /* + * Humpf! An event came in after this one, and because it is not a + * commit, it will have a delta of zero, thus, it will take on + * the timestamp of the previous commit, which happened a long time + * ago (we need to add a timestamp, remember?). + * We need to add the timestamp here. A timestamp is a fixed size + * of 8 bytes. That means the rest of the event needs to be + * padding. + */ + size = info->length - RB_LEN_TIME_EXTEND; + + /* The padding will have a delta of 1 */ + if (size) + info->delta--; + + padding = rb_add_time_stamp(event, info->delta); + + if (size) { + length = info->length; + info->delta = 0; + info->length = size; + rb_update_event(cpu_buffer, padding, info); + + rb_event_discard(padding); + + /* Still visible, need to update write_stamp */ + rb_update_write_stamp(cpu_buffer, event); + + /* Still need to commit the padding. */ + rb_end_commit(cpu_buffer); + + /* rb_end_commit() decs committing */ + local_inc(&cpu_buffer->committing); + + /* The next iteration still uses the original length */ + info->length = length; + } } static struct ring_buffer_event * @@ -2426,14 +2506,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event; struct buffer_page *tail_page; unsigned long tail, write; - - /* - * If the time delta since the last event is too big to - * hold in the time field of the event, then we append a - * TIME EXTEND event ahead of the data event. - */ - if (unlikely(info->add_timestamp)) - info->length += RB_LEN_TIME_EXTEND; + bool is_commit; tail_page = info->tail_page = cpu_buffer->tail_page; write = local_add_return(info->length, &tail_page->write); @@ -2442,31 +2515,42 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, write &= RB_WRITE_MASK; tail = write - info->length; - /* - * If this is the first commit on the page, then it has the same - * timestamp as the page itself. - */ - if (!tail) - info->delta = 0; - /* See if we shot pass the end of this buffer page */ if (unlikely(write > BUF_PAGE_SIZE)) return rb_move_tail(cpu_buffer, tail, info); /* We reserved something on the buffer */ - event = __rb_page_index(tail_page, tail); - kmemcheck_annotate_bitfield(event, bitfield); - rb_update_event(cpu_buffer, event, info); - - local_inc(&tail_page->entries); /* - * If this is the first commit on the page, then update - * its timestamp. + * If this is the first commit on the page, then it has the same + * timestamp as the page itself, otherwise we need to figure out + * the delta. */ - if (!tail) + info->ts = rb_time_stamp(cpu_buffer->buffer); + is_commit = rb_event_is_commit(cpu_buffer, event); + + /* Commits are special (non nested events) */ + info->delta = is_commit ? info->ts - cpu_buffer->write_stamp : 0; + + if (!tail) { + /* + * If this is the first commit on the page, set the + * page to its timestamp. + */ tail_page->page->time_stamp = info->ts; + info->delta = 0; + + } else if (unlikely(test_time_stamp(info->delta)) && + !info->add_timestamp) { + rb_handle_timestamp(cpu_buffer, event, info); + return ERR_PTR(-EAGAIN); + } + + kmemcheck_annotate_bitfield(event, bitfield); + rb_update_event(cpu_buffer, event, info); + + local_inc(&tail_page->entries); /* account for these added bytes */ local_add(info->length, &cpu_buffer->entries_bytes); @@ -2560,7 +2644,6 @@ rb_reserve_next_event(struct ring_buffer *buffer, struct ring_buffer_event *event; struct rb_event_info info; int nr_loops = 0; - u64 diff; rb_start_commit(cpu_buffer); @@ -2578,12 +2661,9 @@ rb_reserve_next_event(struct ring_buffer *buffer, return NULL; } #endif - info.length = rb_calculate_event_length(length); - again: info.add_timestamp = 0; - info.delta = 0; - + again: /* * We allow for interrupts to reenter here and do a trace. * If one does, it will cause this original code to loop @@ -2596,19 +2676,6 @@ rb_reserve_next_event(struct ring_buffer *buffer, if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000)) goto out_fail; - info.ts = rb_time_stamp(cpu_buffer->buffer); - diff = info.ts - cpu_buffer->write_stamp; - - /* make sure this diff is calculated here */ - barrier(); - - /* Did the write stamp get updated already? */ - if (likely(info.ts >= cpu_buffer->write_stamp)) { - info.delta = diff; - if (unlikely(test_time_stamp(info.delta))) - rb_handle_timestamp(cpu_buffer, &info); - } - event = __rb_reserve_next(cpu_buffer, &info); if (unlikely(PTR_ERR(event) == -EAGAIN)) -- GitLab From 7d75e6833b579adb3de2c7b917de1204eeafea47 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 29 May 2015 10:29:10 -0400 Subject: [PATCH 1280/7006] ring-buffer: Make sure event has enough room for extend and padding Now that events only add time extends after it is committed, in case an event comes in before it can discard the allocated event, the time extend needs to be stored within the event. If the event is bigger than then size needed for the time extend, padding must be added. The minimum padding size is 8 bytes. Thus if the event is 12 bytes (size of time extend + 4), there will not be enough room to add both the time extend and padding. Make sure all events are either 8 bytes or 16 or more bytes. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index b5ed553e0a45f..781ce359976c9 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2208,6 +2208,21 @@ static unsigned rb_calculate_event_length(unsigned length) length += RB_EVNT_HDR_SIZE; length = ALIGN(length, RB_ARCH_ALIGNMENT); + /* + * In case the time delta is larger than the 27 bits for it + * in the header, we need to add a timestamp. If another + * event comes in when trying to discard this one to increase + * the length, then the timestamp will be added in the allocated + * space of this event. If length is bigger than the size needed + * for the TIME_EXTEND, then padding has to be used. The events + * length must be either RB_LEN_TIME_EXTEND, or greater than or equal + * to RB_LEN_TIME_EXTEND + 8, as 8 is the minimum size for padding. + * As length is a multiple of 4, we only need to worry if it + * is 12 (RB_LEN_TIME_EXTEND + 4). + */ + if (length == RB_LEN_TIME_EXTEND + RB_ALIGNMENT) + length += RB_ALIGNMENT; + return length; } -- GitLab From d90fd77402d3de56a9ca3df04e5d868d0979dc59 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Fri, 29 May 2015 12:12:27 -0400 Subject: [PATCH 1281/7006] ring-buffer: Reorganize function locations Functions in ring-buffer.c have gotten interleaved between different use cases. Move the functions around to get like functions closer together. This may or may not help gcc keep cache locality, but it makes it a little easier to work with the code. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 920 ++++++++++++++++++------------------- 1 file changed, 456 insertions(+), 464 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 781ce359976c9..1cce0fbf92cea 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -1887,73 +1887,6 @@ rb_event_index(struct ring_buffer_event *event) return (addr & ~PAGE_MASK) - BUF_PAGE_HDR_SIZE; } -static inline int -rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event) -{ - unsigned long addr = (unsigned long)event; - unsigned long index; - - index = rb_event_index(event); - addr &= PAGE_MASK; - - return cpu_buffer->commit_page->page == (void *)addr && - rb_commit_index(cpu_buffer) == index; -} - -static void -rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) -{ - unsigned long max_count; - - /* - * We only race with interrupts and NMIs on this CPU. - * If we own the commit event, then we can commit - * all others that interrupted us, since the interruptions - * are in stack format (they finish before they come - * back to us). This allows us to do a simple loop to - * assign the commit to the tail. - */ - again: - max_count = cpu_buffer->nr_pages * 100; - - while (cpu_buffer->commit_page != cpu_buffer->tail_page) { - if (RB_WARN_ON(cpu_buffer, !(--max_count))) - return; - if (RB_WARN_ON(cpu_buffer, - rb_is_reader_page(cpu_buffer->tail_page))) - return; - local_set(&cpu_buffer->commit_page->page->commit, - rb_page_write(cpu_buffer->commit_page)); - rb_inc_page(cpu_buffer, &cpu_buffer->commit_page); - cpu_buffer->write_stamp = - cpu_buffer->commit_page->page->time_stamp; - /* add barrier to keep gcc from optimizing too much */ - barrier(); - } - while (rb_commit_index(cpu_buffer) != - rb_page_write(cpu_buffer->commit_page)) { - - local_set(&cpu_buffer->commit_page->page->commit, - rb_page_write(cpu_buffer->commit_page)); - RB_WARN_ON(cpu_buffer, - local_read(&cpu_buffer->commit_page->page->commit) & - ~RB_WRITE_MASK); - barrier(); - } - - /* again, keep gcc from optimizing */ - barrier(); - - /* - * If an interrupt came in just after the first while loop - * and pushed the tail page forward, we will be left with - * a dangling commit that will never go forward. - */ - if (unlikely(cpu_buffer->commit_page != cpu_buffer->tail_page)) - goto again; -} - static void rb_reset_reader_page(struct ring_buffer_per_cpu *cpu_buffer) { cpu_buffer->read_stamp = cpu_buffer->reader_page->page->time_stamp; @@ -1979,63 +1912,6 @@ static void rb_inc_iter(struct ring_buffer_iter *iter) iter->head = 0; } -/* Slow path, do not inline */ -static noinline struct ring_buffer_event * -rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) -{ - event->type_len = RINGBUF_TYPE_TIME_EXTEND; - - /* Not the first event on the page? */ - if (rb_event_index(event)) { - event->time_delta = delta & TS_MASK; - event->array[0] = delta >> TS_SHIFT; - } else { - /* nope, just zero it */ - event->time_delta = 0; - event->array[0] = 0; - } - - return skip_time_extend(event); -} - -/** - * rb_update_event - update event type and data - * @event: the event to update - * @type: the type of event - * @length: the size of the event field in the ring buffer - * - * Update the type and data fields of the event. The length - * is the actual size that is written to the ring buffer, - * and with this, we can determine what to place into the - * data field. - */ -static void __always_inline -rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event, - struct rb_event_info *info) -{ - unsigned length = info->length; - u64 delta = info->delta; - - /* - * If we need to add a timestamp, then we - * add it to the start of the resevered space. - */ - if (unlikely(info->add_timestamp)) { - event = rb_add_time_stamp(event, delta); - length -= RB_LEN_TIME_EXTEND; - delta = 0; - } - - event->time_delta = delta; - length -= RB_EVNT_HDR_SIZE; - if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) { - event->type_len = 0; - event->array[0] = length; - } else - event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT); -} - /* * rb_handle_head_page - writer hit the head page * @@ -2194,38 +2070,6 @@ rb_handle_head_page(struct ring_buffer_per_cpu *cpu_buffer, return 0; } -static unsigned rb_calculate_event_length(unsigned length) -{ - struct ring_buffer_event event; /* Used only for sizeof array */ - - /* zero length can cause confusions */ - if (!length) - length++; - - if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) - length += sizeof(event.array[0]); - - length += RB_EVNT_HDR_SIZE; - length = ALIGN(length, RB_ARCH_ALIGNMENT); - - /* - * In case the time delta is larger than the 27 bits for it - * in the header, we need to add a timestamp. If another - * event comes in when trying to discard this one to increase - * the length, then the timestamp will be added in the allocated - * space of this event. If length is bigger than the size needed - * for the TIME_EXTEND, then padding has to be used. The events - * length must be either RB_LEN_TIME_EXTEND, or greater than or equal - * to RB_LEN_TIME_EXTEND + 8, as 8 is the minimum size for padding. - * As length is a multiple of 4, we only need to worry if it - * is 12 (RB_LEN_TIME_EXTEND + 4). - */ - if (length == RB_LEN_TIME_EXTEND + RB_ALIGNMENT) - length += RB_ALIGNMENT; - - return length; -} - static inline void rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, unsigned long tail, struct rb_event_info *info) @@ -2424,71 +2268,471 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, return NULL; } -#ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK -static inline bool sched_clock_stable(void) +/* Slow path, do not inline */ +static noinline struct ring_buffer_event * +rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) { - return true; -} -#endif + event->type_len = RINGBUF_TYPE_TIME_EXTEND; -static inline int -rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event); -static inline void rb_event_discard(struct ring_buffer_event *event); -static void -rb_update_write_stamp(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event); + /* Not the first event on the page? */ + if (rb_event_index(event)) { + event->time_delta = delta & TS_MASK; + event->array[0] = delta >> TS_SHIFT; + } else { + /* nope, just zero it */ + event->time_delta = 0; + event->array[0] = 0; + } -static noinline void -rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event, - struct rb_event_info *info) -{ - struct ring_buffer_event *padding; - int length; - int size; + return skip_time_extend(event); +} - WARN_ONCE(info->delta > (1ULL << 59), - KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", - (unsigned long long)info->delta, - (unsigned long long)info->ts, - (unsigned long long)cpu_buffer->write_stamp, - sched_clock_stable() ? "" : - "If you just came from a suspend/resume,\n" - "please switch to the trace global clock:\n" - " echo global > /sys/kernel/debug/tracing/trace_clock\n"); +/** + * rb_update_event - update event type and data + * @event: the event to update + * @type: the type of event + * @length: the size of the event field in the ring buffer + * + * Update the type and data fields of the event. The length + * is the actual size that is written to the ring buffer, + * and with this, we can determine what to place into the + * data field. + */ +static void __always_inline +rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event, + struct rb_event_info *info) +{ + unsigned length = info->length; + u64 delta = info->delta; /* - * Discarding this event to add a timestamp in front, but - * we still need to update the length of it to perform the discard. + * If we need to add a timestamp, then we + * add it to the start of the resevered space. */ - rb_update_event(cpu_buffer, event, info); - - if (rb_try_to_discard(cpu_buffer, event)) { - info->add_timestamp = 1; - /* - * The time delta since the last event is too big to - * hold in the time field of the event, then we append a - * TIME EXTEND event ahead of the data event. - */ - info->length += RB_LEN_TIME_EXTEND; - return; + if (unlikely(info->add_timestamp)) { + event = rb_add_time_stamp(event, delta); + length -= RB_LEN_TIME_EXTEND; + delta = 0; } - /* - * Humpf! An event came in after this one, and because it is not a - * commit, it will have a delta of zero, thus, it will take on - * the timestamp of the previous commit, which happened a long time - * ago (we need to add a timestamp, remember?). - * We need to add the timestamp here. A timestamp is a fixed size - * of 8 bytes. That means the rest of the event needs to be - * padding. - */ - size = info->length - RB_LEN_TIME_EXTEND; - - /* The padding will have a delta of 1 */ - if (size) - info->delta--; + event->time_delta = delta; + length -= RB_EVNT_HDR_SIZE; + if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) { + event->type_len = 0; + event->array[0] = length; + } else + event->type_len = DIV_ROUND_UP(length, RB_ALIGNMENT); +} + +static unsigned rb_calculate_event_length(unsigned length) +{ + struct ring_buffer_event event; /* Used only for sizeof array */ + + /* zero length can cause confusions */ + if (!length) + length++; + + if (length > RB_MAX_SMALL_DATA || RB_FORCE_8BYTE_ALIGNMENT) + length += sizeof(event.array[0]); + + length += RB_EVNT_HDR_SIZE; + length = ALIGN(length, RB_ARCH_ALIGNMENT); + + /* + * In case the time delta is larger than the 27 bits for it + * in the header, we need to add a timestamp. If another + * event comes in when trying to discard this one to increase + * the length, then the timestamp will be added in the allocated + * space of this event. If length is bigger than the size needed + * for the TIME_EXTEND, then padding has to be used. The events + * length must be either RB_LEN_TIME_EXTEND, or greater than or equal + * to RB_LEN_TIME_EXTEND + 8, as 8 is the minimum size for padding. + * As length is a multiple of 4, we only need to worry if it + * is 12 (RB_LEN_TIME_EXTEND + 4). + */ + if (length == RB_LEN_TIME_EXTEND + RB_ALIGNMENT) + length += RB_ALIGNMENT; + + return length; +} + +#ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK +static inline bool sched_clock_stable(void) +{ + return true; +} +#endif + +static inline int +rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + unsigned long new_index, old_index; + struct buffer_page *bpage; + unsigned long index; + unsigned long addr; + + new_index = rb_event_index(event); + old_index = new_index + rb_event_ts_length(event); + addr = (unsigned long)event; + addr &= PAGE_MASK; + + bpage = cpu_buffer->tail_page; + + if (bpage->page == (void *)addr && rb_page_write(bpage) == old_index) { + unsigned long write_mask = + local_read(&bpage->write) & ~RB_WRITE_MASK; + unsigned long event_length = rb_event_length(event); + /* + * This is on the tail page. It is possible that + * a write could come in and move the tail page + * and write to the next page. That is fine + * because we just shorten what is on this page. + */ + old_index += write_mask; + new_index += write_mask; + index = local_cmpxchg(&bpage->write, old_index, new_index); + if (index == old_index) { + /* update counters */ + local_sub(event_length, &cpu_buffer->entries_bytes); + return 1; + } + } + + /* could not discard */ + return 0; +} + +static void rb_start_commit(struct ring_buffer_per_cpu *cpu_buffer) +{ + local_inc(&cpu_buffer->committing); + local_inc(&cpu_buffer->commits); +} + +static void +rb_set_commit_to_write(struct ring_buffer_per_cpu *cpu_buffer) +{ + unsigned long max_count; + + /* + * We only race with interrupts and NMIs on this CPU. + * If we own the commit event, then we can commit + * all others that interrupted us, since the interruptions + * are in stack format (they finish before they come + * back to us). This allows us to do a simple loop to + * assign the commit to the tail. + */ + again: + max_count = cpu_buffer->nr_pages * 100; + + while (cpu_buffer->commit_page != cpu_buffer->tail_page) { + if (RB_WARN_ON(cpu_buffer, !(--max_count))) + return; + if (RB_WARN_ON(cpu_buffer, + rb_is_reader_page(cpu_buffer->tail_page))) + return; + local_set(&cpu_buffer->commit_page->page->commit, + rb_page_write(cpu_buffer->commit_page)); + rb_inc_page(cpu_buffer, &cpu_buffer->commit_page); + cpu_buffer->write_stamp = + cpu_buffer->commit_page->page->time_stamp; + /* add barrier to keep gcc from optimizing too much */ + barrier(); + } + while (rb_commit_index(cpu_buffer) != + rb_page_write(cpu_buffer->commit_page)) { + + local_set(&cpu_buffer->commit_page->page->commit, + rb_page_write(cpu_buffer->commit_page)); + RB_WARN_ON(cpu_buffer, + local_read(&cpu_buffer->commit_page->page->commit) & + ~RB_WRITE_MASK); + barrier(); + } + + /* again, keep gcc from optimizing */ + barrier(); + + /* + * If an interrupt came in just after the first while loop + * and pushed the tail page forward, we will be left with + * a dangling commit that will never go forward. + */ + if (unlikely(cpu_buffer->commit_page != cpu_buffer->tail_page)) + goto again; +} + +static inline void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer) +{ + unsigned long commits; + + if (RB_WARN_ON(cpu_buffer, + !local_read(&cpu_buffer->committing))) + return; + + again: + commits = local_read(&cpu_buffer->commits); + /* synchronize with interrupts */ + barrier(); + if (local_read(&cpu_buffer->committing) == 1) + rb_set_commit_to_write(cpu_buffer); + + local_dec(&cpu_buffer->committing); + + /* synchronize with interrupts */ + barrier(); + + /* + * Need to account for interrupts coming in between the + * updating of the commit page and the clearing of the + * committing counter. + */ + if (unlikely(local_read(&cpu_buffer->commits) != commits) && + !local_read(&cpu_buffer->committing)) { + local_inc(&cpu_buffer->committing); + goto again; + } +} + +static inline void rb_event_discard(struct ring_buffer_event *event) +{ + if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) + event = skip_time_extend(event); + + /* array[0] holds the actual length for the discarded event */ + event->array[0] = rb_event_data_length(event) - RB_EVNT_HDR_SIZE; + event->type_len = RINGBUF_TYPE_PADDING; + /* time delta must be non zero */ + if (!event->time_delta) + event->time_delta = 1; +} + +static inline int +rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + unsigned long addr = (unsigned long)event; + unsigned long index; + + index = rb_event_index(event); + addr &= PAGE_MASK; + + return cpu_buffer->commit_page->page == (void *)addr && + rb_commit_index(cpu_buffer) == index; +} + +static void +rb_update_write_stamp(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + u64 delta; + + /* + * The event first in the commit queue updates the + * time stamp. + */ + if (rb_event_is_commit(cpu_buffer, event)) { + /* + * A commit event that is first on a page + * updates the write timestamp with the page stamp + */ + if (!rb_event_index(event)) + cpu_buffer->write_stamp = + cpu_buffer->commit_page->page->time_stamp; + else if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) { + delta = event->array[0]; + delta <<= TS_SHIFT; + delta += event->time_delta; + cpu_buffer->write_stamp += delta; + } else + cpu_buffer->write_stamp += event->time_delta; + } +} + +static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event) +{ + local_inc(&cpu_buffer->entries); + rb_update_write_stamp(cpu_buffer, event); + rb_end_commit(cpu_buffer); +} + +static __always_inline void +rb_wakeups(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer) +{ + bool pagebusy; + + if (buffer->irq_work.waiters_pending) { + buffer->irq_work.waiters_pending = false; + /* irq_work_queue() supplies it's own memory barriers */ + irq_work_queue(&buffer->irq_work.work); + } + + if (cpu_buffer->irq_work.waiters_pending) { + cpu_buffer->irq_work.waiters_pending = false; + /* irq_work_queue() supplies it's own memory barriers */ + irq_work_queue(&cpu_buffer->irq_work.work); + } + + pagebusy = cpu_buffer->reader_page == cpu_buffer->commit_page; + + if (!pagebusy && cpu_buffer->irq_work.full_waiters_pending) { + cpu_buffer->irq_work.wakeup_full = true; + cpu_buffer->irq_work.full_waiters_pending = false; + /* irq_work_queue() supplies it's own memory barriers */ + irq_work_queue(&cpu_buffer->irq_work.work); + } +} + +/* + * The lock and unlock are done within a preempt disable section. + * The current_context per_cpu variable can only be modified + * by the current task between lock and unlock. But it can + * be modified more than once via an interrupt. To pass this + * information from the lock to the unlock without having to + * access the 'in_interrupt()' functions again (which do show + * a bit of overhead in something as critical as function tracing, + * we use a bitmask trick. + * + * bit 0 = NMI context + * bit 1 = IRQ context + * bit 2 = SoftIRQ context + * bit 3 = normal context. + * + * This works because this is the order of contexts that can + * preempt other contexts. A SoftIRQ never preempts an IRQ + * context. + * + * When the context is determined, the corresponding bit is + * checked and set (if it was set, then a recursion of that context + * happened). + * + * On unlock, we need to clear this bit. To do so, just subtract + * 1 from the current_context and AND it to itself. + * + * (binary) + * 101 - 1 = 100 + * 101 & 100 = 100 (clearing bit zero) + * + * 1010 - 1 = 1001 + * 1010 & 1001 = 1000 (clearing bit 1) + * + * The least significant bit can be cleared this way, and it + * just so happens that it is the same bit corresponding to + * the current context. + */ + +static __always_inline int +trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer) +{ + unsigned int val = cpu_buffer->current_context; + int bit; + + if (in_interrupt()) { + if (in_nmi()) + bit = RB_CTX_NMI; + else if (in_irq()) + bit = RB_CTX_IRQ; + else + bit = RB_CTX_SOFTIRQ; + } else + bit = RB_CTX_NORMAL; + + if (unlikely(val & (1 << bit))) + return 1; + + val |= (1 << bit); + cpu_buffer->current_context = val; + + return 0; +} + +static __always_inline void +trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer) +{ + cpu_buffer->current_context &= cpu_buffer->current_context - 1; +} + +/** + * ring_buffer_unlock_commit - commit a reserved + * @buffer: The buffer to commit to + * @event: The event pointer to commit. + * + * This commits the data to the ring buffer, and releases any locks held. + * + * Must be paired with ring_buffer_lock_reserve. + */ +int ring_buffer_unlock_commit(struct ring_buffer *buffer, + struct ring_buffer_event *event) +{ + struct ring_buffer_per_cpu *cpu_buffer; + int cpu = raw_smp_processor_id(); + + cpu_buffer = buffer->buffers[cpu]; + + rb_commit(cpu_buffer, event); + + rb_wakeups(buffer, cpu_buffer); + + trace_recursive_unlock(cpu_buffer); + + preempt_enable_notrace(); + + return 0; +} +EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit); + +static noinline void +rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event, + struct rb_event_info *info) +{ + struct ring_buffer_event *padding; + int length; + int size; + + WARN_ONCE(info->delta > (1ULL << 59), + KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", + (unsigned long long)info->delta, + (unsigned long long)info->ts, + (unsigned long long)cpu_buffer->write_stamp, + sched_clock_stable() ? "" : + "If you just came from a suspend/resume,\n" + "please switch to the trace global clock:\n" + " echo global > /sys/kernel/debug/tracing/trace_clock\n"); + + /* + * Discarding this event to add a timestamp in front, but + * we still need to update the length of it to perform the discard. + */ + rb_update_event(cpu_buffer, event, info); + + if (rb_try_to_discard(cpu_buffer, event)) { + info->add_timestamp = 1; + /* + * The time delta since the last event is too big to + * hold in the time field of the event, then we append a + * TIME EXTEND event ahead of the data event. + */ + info->length += RB_LEN_TIME_EXTEND; + return; + } + + /* + * Humpf! An event came in after this one, and because it is not a + * commit, it will have a delta of zero, thus, it will take on + * the timestamp of the previous commit, which happened a long time + * ago (we need to add a timestamp, remember?). + * We need to add the timestamp here. A timestamp is a fixed size + * of 8 bytes. That means the rest of the event needs to be + * padding. + */ + size = info->length - RB_LEN_TIME_EXTEND; + + /* The padding will have a delta of 1 */ + if (size) + info->delta--; padding = rb_add_time_stamp(event, info->delta); @@ -2573,84 +2817,6 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, return event; } -static inline int -rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event) -{ - unsigned long new_index, old_index; - struct buffer_page *bpage; - unsigned long index; - unsigned long addr; - - new_index = rb_event_index(event); - old_index = new_index + rb_event_ts_length(event); - addr = (unsigned long)event; - addr &= PAGE_MASK; - - bpage = cpu_buffer->tail_page; - - if (bpage->page == (void *)addr && rb_page_write(bpage) == old_index) { - unsigned long write_mask = - local_read(&bpage->write) & ~RB_WRITE_MASK; - unsigned long event_length = rb_event_length(event); - /* - * This is on the tail page. It is possible that - * a write could come in and move the tail page - * and write to the next page. That is fine - * because we just shorten what is on this page. - */ - old_index += write_mask; - new_index += write_mask; - index = local_cmpxchg(&bpage->write, old_index, new_index); - if (index == old_index) { - /* update counters */ - local_sub(event_length, &cpu_buffer->entries_bytes); - return 1; - } - } - - /* could not discard */ - return 0; -} - -static void rb_start_commit(struct ring_buffer_per_cpu *cpu_buffer) -{ - local_inc(&cpu_buffer->committing); - local_inc(&cpu_buffer->commits); -} - -static inline void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer) -{ - unsigned long commits; - - if (RB_WARN_ON(cpu_buffer, - !local_read(&cpu_buffer->committing))) - return; - - again: - commits = local_read(&cpu_buffer->commits); - /* synchronize with interrupts */ - barrier(); - if (local_read(&cpu_buffer->committing) == 1) - rb_set_commit_to_write(cpu_buffer); - - local_dec(&cpu_buffer->committing); - - /* synchronize with interrupts */ - barrier(); - - /* - * Need to account for interrupts coming in between the - * updating of the commit page and the clearing of the - * committing counter. - */ - if (unlikely(local_read(&cpu_buffer->commits) != commits) && - !local_read(&cpu_buffer->committing)) { - local_inc(&cpu_buffer->committing); - goto again; - } -} - static struct ring_buffer_event * rb_reserve_next_event(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer, @@ -2706,75 +2872,6 @@ rb_reserve_next_event(struct ring_buffer *buffer, return NULL; } -/* - * The lock and unlock are done within a preempt disable section. - * The current_context per_cpu variable can only be modified - * by the current task between lock and unlock. But it can - * be modified more than once via an interrupt. To pass this - * information from the lock to the unlock without having to - * access the 'in_interrupt()' functions again (which do show - * a bit of overhead in something as critical as function tracing, - * we use a bitmask trick. - * - * bit 0 = NMI context - * bit 1 = IRQ context - * bit 2 = SoftIRQ context - * bit 3 = normal context. - * - * This works because this is the order of contexts that can - * preempt other contexts. A SoftIRQ never preempts an IRQ - * context. - * - * When the context is determined, the corresponding bit is - * checked and set (if it was set, then a recursion of that context - * happened). - * - * On unlock, we need to clear this bit. To do so, just subtract - * 1 from the current_context and AND it to itself. - * - * (binary) - * 101 - 1 = 100 - * 101 & 100 = 100 (clearing bit zero) - * - * 1010 - 1 = 1001 - * 1010 & 1001 = 1000 (clearing bit 1) - * - * The least significant bit can be cleared this way, and it - * just so happens that it is the same bit corresponding to - * the current context. - */ - -static __always_inline int -trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer) -{ - unsigned int val = cpu_buffer->current_context; - int bit; - - if (in_interrupt()) { - if (in_nmi()) - bit = RB_CTX_NMI; - else if (in_irq()) - bit = RB_CTX_IRQ; - else - bit = RB_CTX_SOFTIRQ; - } else - bit = RB_CTX_NORMAL; - - if (unlikely(val & (1 << bit))) - return 1; - - val |= (1 << bit); - cpu_buffer->current_context = val; - - return 0; -} - -static __always_inline void -trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer) -{ - cpu_buffer->current_context &= cpu_buffer->current_context - 1; -} - /** * ring_buffer_lock_reserve - reserve a part of the buffer * @buffer: the ring buffer to reserve from @@ -2833,111 +2930,6 @@ ring_buffer_lock_reserve(struct ring_buffer *buffer, unsigned long length) } EXPORT_SYMBOL_GPL(ring_buffer_lock_reserve); -static void -rb_update_write_stamp(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event) -{ - u64 delta; - - /* - * The event first in the commit queue updates the - * time stamp. - */ - if (rb_event_is_commit(cpu_buffer, event)) { - /* - * A commit event that is first on a page - * updates the write timestamp with the page stamp - */ - if (!rb_event_index(event)) - cpu_buffer->write_stamp = - cpu_buffer->commit_page->page->time_stamp; - else if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) { - delta = event->array[0]; - delta <<= TS_SHIFT; - delta += event->time_delta; - cpu_buffer->write_stamp += delta; - } else - cpu_buffer->write_stamp += event->time_delta; - } -} - -static void rb_commit(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event) -{ - local_inc(&cpu_buffer->entries); - rb_update_write_stamp(cpu_buffer, event); - rb_end_commit(cpu_buffer); -} - -static __always_inline void -rb_wakeups(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer) -{ - bool pagebusy; - - if (buffer->irq_work.waiters_pending) { - buffer->irq_work.waiters_pending = false; - /* irq_work_queue() supplies it's own memory barriers */ - irq_work_queue(&buffer->irq_work.work); - } - - if (cpu_buffer->irq_work.waiters_pending) { - cpu_buffer->irq_work.waiters_pending = false; - /* irq_work_queue() supplies it's own memory barriers */ - irq_work_queue(&cpu_buffer->irq_work.work); - } - - pagebusy = cpu_buffer->reader_page == cpu_buffer->commit_page; - - if (!pagebusy && cpu_buffer->irq_work.full_waiters_pending) { - cpu_buffer->irq_work.wakeup_full = true; - cpu_buffer->irq_work.full_waiters_pending = false; - /* irq_work_queue() supplies it's own memory barriers */ - irq_work_queue(&cpu_buffer->irq_work.work); - } -} - -/** - * ring_buffer_unlock_commit - commit a reserved - * @buffer: The buffer to commit to - * @event: The event pointer to commit. - * - * This commits the data to the ring buffer, and releases any locks held. - * - * Must be paired with ring_buffer_lock_reserve. - */ -int ring_buffer_unlock_commit(struct ring_buffer *buffer, - struct ring_buffer_event *event) -{ - struct ring_buffer_per_cpu *cpu_buffer; - int cpu = raw_smp_processor_id(); - - cpu_buffer = buffer->buffers[cpu]; - - rb_commit(cpu_buffer, event); - - rb_wakeups(buffer, cpu_buffer); - - trace_recursive_unlock(cpu_buffer); - - preempt_enable_notrace(); - - return 0; -} -EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit); - -static inline void rb_event_discard(struct ring_buffer_event *event) -{ - if (event->type_len == RINGBUF_TYPE_TIME_EXTEND) - event = skip_time_extend(event); - - /* array[0] holds the actual length for the discarded event */ - event->array[0] = rb_event_data_length(event) - RB_EVNT_HDR_SIZE; - event->type_len = RINGBUF_TYPE_PADDING; - /* time delta must be non zero */ - if (!event->time_delta) - event->time_delta = 1; -} - /* * Decrement the entries to the page that an event is on. * The event does not even need to exist, only the pointer -- GitLab From 72ac426a5bb0cec572d26b4456f8c1e14601694e Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 16 Jul 2015 13:24:54 -0400 Subject: [PATCH 1282/7006] tracing: Clean up stack tracing and fix fentry updates Akashi Takahiro was porting the stack tracer to arm64 and found some issues with it. One was that it repeats the top function, due to the stack frame added by the mcount caller and added by itself. This was added when fentry came in, and before fentry created its own stack frame. But x86's fentry now creates its own stack frame, and there's no need to insert the function again. This also cleans up the code a bit, where it doesn't need to do something special for fentry, and doesn't include insertion of a duplicate entry for the called function being traced. Link: http://lkml.kernel.org/r/55A646EE.6030402@linaro.org Some-suggestions-by: Jungseok Lee Some-suggestions-by: Mark Rutland Reported-by: AKASHI Takahiro Signed-off-by: Steven Rostedt --- kernel/trace/trace_stack.c | 68 +++++++++++++------------------------- 1 file changed, 23 insertions(+), 45 deletions(-) diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 3f34496244e93..b746399ab59c0 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c @@ -18,12 +18,6 @@ #define STACK_TRACE_ENTRIES 500 -#ifdef CC_USING_FENTRY -# define fentry 1 -#else -# define fentry 0 -#endif - static unsigned long stack_dump_trace[STACK_TRACE_ENTRIES+1] = { [0 ... (STACK_TRACE_ENTRIES)] = ULONG_MAX }; static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; @@ -35,7 +29,7 @@ static unsigned stack_dump_index[STACK_TRACE_ENTRIES]; */ static struct stack_trace max_stack_trace = { .max_entries = STACK_TRACE_ENTRIES - 1, - .entries = &stack_dump_trace[1], + .entries = &stack_dump_trace[0], }; static unsigned long max_stack_size; @@ -55,7 +49,7 @@ static inline void print_max_stack(void) pr_emerg(" Depth Size Location (%d entries)\n" " ----- ---- --------\n", - max_stack_trace.nr_entries - 1); + max_stack_trace.nr_entries); for (i = 0; i < max_stack_trace.nr_entries; i++) { if (stack_dump_trace[i] == ULONG_MAX) @@ -77,7 +71,7 @@ check_stack(unsigned long ip, unsigned long *stack) unsigned long this_size, flags; unsigned long *p, *top, *start; static int tracer_frame; int frame_size = ACCESS_ONCE(tracer_frame); - int i; + int i, x; this_size = ((unsigned long)stack) & (THREAD_SIZE-1); this_size = THREAD_SIZE - this_size; @@ -105,26 +99,20 @@ check_stack(unsigned long ip, unsigned long *stack) max_stack_size = this_size; max_stack_trace.nr_entries = 0; - - if (using_ftrace_ops_list_func()) - max_stack_trace.skip = 4; - else - max_stack_trace.skip = 3; + max_stack_trace.skip = 3; save_stack_trace(&max_stack_trace); - /* - * Add the passed in ip from the function tracer. - * Searching for this on the stack will skip over - * most of the overhead from the stack tracer itself. - */ - stack_dump_trace[0] = ip; - max_stack_trace.nr_entries++; + /* Skip over the overhead of the stack tracer itself */ + for (i = 0; i < max_stack_trace.nr_entries; i++) { + if (stack_dump_trace[i] == ip) + break; + } /* * Now find where in the stack these are. */ - i = 0; + x = 0; start = stack; top = (unsigned long *) (((unsigned long)start & ~(THREAD_SIZE-1)) + THREAD_SIZE); @@ -139,12 +127,15 @@ check_stack(unsigned long ip, unsigned long *stack) while (i < max_stack_trace.nr_entries) { int found = 0; - stack_dump_index[i] = this_size; + stack_dump_index[x] = this_size; p = start; for (; p < top && i < max_stack_trace.nr_entries; p++) { + if (stack_dump_trace[i] == ULONG_MAX) + break; if (*p == stack_dump_trace[i]) { - this_size = stack_dump_index[i++] = + stack_dump_trace[x] = stack_dump_trace[i++]; + this_size = stack_dump_index[x++] = (top - p) * sizeof(unsigned long); found = 1; /* Start the search from here */ @@ -156,7 +147,7 @@ check_stack(unsigned long ip, unsigned long *stack) * out what that is, then figure it out * now. */ - if (unlikely(!tracer_frame) && i == 1) { + if (unlikely(!tracer_frame)) { tracer_frame = (p - stack) * sizeof(unsigned long); max_stack_size -= tracer_frame; @@ -168,6 +159,10 @@ check_stack(unsigned long ip, unsigned long *stack) i++; } + max_stack_trace.nr_entries = x; + for (; x < i; x++) + stack_dump_trace[x] = ULONG_MAX; + if (task_stack_end_corrupted(current)) { print_max_stack(); BUG(); @@ -192,24 +187,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip, if (per_cpu(trace_active, cpu)++ != 0) goto out; - /* - * When fentry is used, the traced function does not get - * its stack frame set up, and we lose the parent. - * The ip is pretty useless because the function tracer - * was called before that function set up its stack frame. - * In this case, we use the parent ip. - * - * By adding the return address of either the parent ip - * or the current ip we can disregard most of the stack usage - * caused by the stack tracer itself. - * - * The function tracer always reports the address of where the - * mcount call was, but the stack will hold the return address. - */ - if (fentry) - ip = parent_ip; - else - ip += MCOUNT_INSN_SIZE; + ip += MCOUNT_INSN_SIZE; check_stack(ip, &stack); @@ -284,7 +262,7 @@ __next(struct seq_file *m, loff_t *pos) { long n = *pos - 1; - if (n >= max_stack_trace.nr_entries || stack_dump_trace[n] == ULONG_MAX) + if (n > max_stack_trace.nr_entries || stack_dump_trace[n] == ULONG_MAX) return NULL; m->private = (void *)n; @@ -354,7 +332,7 @@ static int t_show(struct seq_file *m, void *v) seq_printf(m, " Depth Size Location" " (%d entries)\n" " ----- ---- --------\n", - max_stack_trace.nr_entries - 1); + max_stack_trace.nr_entries); if (!stack_tracer_enabled && !max_stack_size) print_disabled(m); -- GitLab From 8e436ca042d904533a1e14fdc85f0facdfca752f Mon Sep 17 00:00:00 2001 From: Umesh Tiwari Date: Mon, 22 Jun 2015 16:58:08 +0530 Subject: [PATCH 1283/7006] ftrace: add tracing_thresh to function profile This patch extends tracing_thresh functionality to function profile tracer. If tracing_thresh is set, print those entries only, whose average is > tracing thresh. Link: http://lkml.kernel.org/r/1434972488-8571-1-git-send-email-umesh.t@samsung.com Signed-off-by: Umesh Tiwari [ Removed unnecessary 'moved' comment ] Signed-off-by: Steven Rostedt --- kernel/trace/ftrace.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 02bece4a99ea3..f46dbb5cdf762 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -613,13 +613,18 @@ static int function_stat_show(struct seq_file *m, void *v) goto out; } +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + avg = rec->time; + do_div(avg, rec->counter); + if (tracing_thresh && (avg < tracing_thresh)) + goto out; +#endif + kallsyms_lookup(rec->ip, NULL, NULL, NULL, str); seq_printf(m, " %-30.30s %10lu", str, rec->counter); #ifdef CONFIG_FUNCTION_GRAPH_TRACER seq_puts(m, " "); - avg = rec->time; - do_div(avg, rec->counter); /* Sample standard deviation (s^2) */ if (rec->counter <= 1) -- GitLab From 82c355e81afbf16bc1ab379899a79eb66e2b7504 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 16 Jul 2015 21:58:52 -0400 Subject: [PATCH 1284/7006] ftrace: Fix function_graph duration spacing with 7-digits Jungseok Lee noticed the following: Currently, row's width of 7-digit duration numbers not aligned with other cases like the following example. 3) $ 3999884 us | } 3) | finish_task_switch() { 3) 0.365 us | _raw_spin_unlock_irq(); 3) 3.333 us | } 3) $ 3999976 us | } 3) $ 3999979 us | } /* schedule */ As adding a single white space in case of 7-digit numbers, the format could be unified easily as follows. 3) $ 2237472 us | } 3) | finish_task_switch() { 3) 0.364 us | _raw_spin_unlock_irq(); 3) 3.125 us | } 3) $ 2237556 us | } 3) $ 2237559 us | } /* schedule */ Instead of making a special case for 7-digit numbers, the logic of the len and the space loop is slightly modified to make the two cases have the same format. Link: http://lkml.kernel.org/r/1436626300-1679-2-git-send-email-jungseoklee85@gmail.com Reported-by: Jungseok Lee Signed-off-by: Steven Rostedt --- kernel/trace/trace_functions_graph.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 8968bf720c125..ca98445782aca 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -715,13 +715,13 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s) snprintf(nsecs_str, slen, "%03lu", nsecs_rem); trace_seq_printf(s, ".%s", nsecs_str); - len += strlen(nsecs_str); + len += strlen(nsecs_str) + 1; } trace_seq_puts(s, " us "); /* Print remaining spaces to fit the row's width */ - for (i = len; i < 7; i++) + for (i = len; i < 8; i++) trace_seq_putc(s, ' '); } -- GitLab From b838e1d96c613019095ba008afbee800977b0582 Mon Sep 17 00:00:00 2001 From: Jungseok Lee Date: Sat, 11 Jul 2015 14:51:40 +0000 Subject: [PATCH 1285/7006] tracing: Introduce two additional marks for delay A fine granulity support for delay would be very useful when profiling VM logics, such as page allocation including page reclaim and memory compaction with function graph. Thus, this patch adds two additional marks with two changes. - An equal sign in mark selection function is removed to align code behavior with comments and documentation. - The function graph example related to delay in ftrace.txt is updated to cover all supported marks. Link: http://lkml.kernel.org/r/1436626300-1679-3-git-send-email-jungseoklee85@gmail.com Cc: Byungchul Park Signed-off-by: Jungseok Lee Signed-off-by: Steven Rostedt --- Documentation/trace/ftrace.txt | 51 +++++++++++++++++++++++++--------- kernel/trace/trace_output.c | 4 ++- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index 7ddb1e319f84d..072d3c4d57539 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt @@ -686,6 +686,8 @@ The above is mostly meaningful for kernel developers. The marks are determined by the difference between this current trace and the next trace. '$' - greater than 1 second + '@' - greater than 100 milisecond + '*' - greater than 10 milisecond '#' - greater than 1000 microsecond '!' - greater than 100 microsecond '+' - greater than 10 microsecond @@ -1939,26 +1941,49 @@ want, depending on your needs. ie: - 0) | up_write() { - 0) 0.646 us | _spin_lock_irqsave(); - 0) 0.684 us | _spin_unlock_irqrestore(); - 0) 3.123 us | } - 0) 0.548 us | fput(); - 0) + 58.628 us | } + 3) # 1837.709 us | } /* __switch_to */ + 3) | finish_task_switch() { + 3) 0.313 us | _raw_spin_unlock_irq(); + 3) 3.177 us | } + 3) # 1889.063 us | } /* __schedule */ + 3) ! 140.417 us | } /* __schedule */ + 3) # 2034.948 us | } /* schedule */ + 3) * 33998.59 us | } /* schedule_preempt_disabled */ [...] - 0) | putname() { - 0) | kmem_cache_free() { - 0) 0.518 us | __phys_addr(); - 0) 1.757 us | } - 0) 2.861 us | } - 0) ! 115.305 us | } - 0) ! 116.402 us | } + 1) 0.260 us | msecs_to_jiffies(); + 1) 0.313 us | __rcu_read_unlock(); + 1) + 61.770 us | } + 1) + 64.479 us | } + 1) 0.313 us | rcu_bh_qs(); + 1) 0.313 us | __local_bh_enable(); + 1) ! 217.240 us | } + 1) 0.365 us | idle_cpu(); + 1) | rcu_irq_exit() { + 1) 0.417 us | rcu_eqs_enter_common.isra.47(); + 1) 3.125 us | } + 1) ! 227.812 us | } + 1) ! 457.395 us | } + 1) @ 119760.2 us | } + + [...] + + 2) | handle_IPI() { + 1) 6.979 us | } + 2) 0.417 us | scheduler_ipi(); + 1) 9.791 us | } + 1) + 12.917 us | } + 2) 3.490 us | } + 1) + 15.729 us | } + 1) + 18.542 us | } + 2) $ 3594274 us | } + means that the function exceeded 10 usecs. ! means that the function exceeded 100 usecs. # means that the function exceeded 1000 usecs. + * means that the function exceeded 10 msecs. + @ means that the function exceeded 100 msecs. $ means that the function exceeded 1 sec. diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index dfab253727dc9..8e481a84aeea7 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c @@ -496,6 +496,8 @@ static const struct trace_mark { char sym; } mark[] = { MARK(1000000000ULL , '$'), /* 1 sec */ + MARK(100000000ULL , '@'), /* 100 msec */ + MARK(10000000ULL , '*'), /* 10 msec */ MARK(1000000ULL , '#'), /* 1000 usecs */ MARK(100000ULL , '!'), /* 100 usecs */ MARK(10000ULL , '+'), /* 10 usecs */ @@ -508,7 +510,7 @@ char trace_find_mark(unsigned long long d) int size = ARRAY_SIZE(mark); for (i = 0; i < size; i++) { - if (d >= mark[i].val) + if (d > mark[i].val) break; } -- GitLab From c93bf928fea22c61f6b5c04786b325c9bfbc0462 Mon Sep 17 00:00:00 2001 From: Minfei Huang Date: Sun, 12 Jul 2015 17:52:24 +0800 Subject: [PATCH 1286/7006] ftrace: Format MCOUNT_ADDR address as type unsigned long Always we use type unsigned long to format the ip address, since the value of ip address is never the negative. This patch uses type unsigned long, instead of long, to format the ip address. The code is more clearly to be viewed by using type unsigned long, although it is correct by using either unsigned long or long. Link: http://lkml.kernel.org/r/1436694744-16747-1-git-send-email-mhuang@redhat.com Cc: Minfei Huang Cc: "H. Peter Anvin" Cc: James Hogan Cc: Michal Simek Cc: Benjamin Herrenschmidt Cc: "David S. Miller" Signed-off-by: Minfei Huang Signed-off-by: Steven Rostedt --- arch/metag/include/asm/ftrace.h | 2 +- arch/microblaze/include/asm/ftrace.h | 2 +- arch/powerpc/include/asm/ftrace.h | 2 +- arch/sh/include/asm/ftrace.h | 2 +- arch/sparc/include/asm/ftrace.h | 2 +- arch/x86/include/asm/ftrace.h | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/metag/include/asm/ftrace.h b/arch/metag/include/asm/ftrace.h index 2901f0f7d944e..a2269d60a945b 100644 --- a/arch/metag/include/asm/ftrace.h +++ b/arch/metag/include/asm/ftrace.h @@ -6,7 +6,7 @@ #ifndef __ASSEMBLY__ extern void mcount_wrapper(void); -#define MCOUNT_ADDR ((long)(mcount_wrapper)) +#define MCOUNT_ADDR ((unsigned long)(mcount_wrapper)) static inline unsigned long ftrace_call_adjust(unsigned long addr) { diff --git a/arch/microblaze/include/asm/ftrace.h b/arch/microblaze/include/asm/ftrace.h index fd2fa2eca62f1..da0144f40d99d 100644 --- a/arch/microblaze/include/asm/ftrace.h +++ b/arch/microblaze/include/asm/ftrace.h @@ -3,7 +3,7 @@ #ifdef CONFIG_FUNCTION_TRACER -#define MCOUNT_ADDR ((long)(_mcount)) +#define MCOUNT_ADDR ((unsigned long)(_mcount)) #define MCOUNT_INSN_SIZE 8 /* sizeof mcount call */ #ifndef __ASSEMBLY__ diff --git a/arch/powerpc/include/asm/ftrace.h b/arch/powerpc/include/asm/ftrace.h index e3661872fbea5..ef89b14655731 100644 --- a/arch/powerpc/include/asm/ftrace.h +++ b/arch/powerpc/include/asm/ftrace.h @@ -2,7 +2,7 @@ #define _ASM_POWERPC_FTRACE #ifdef CONFIG_FUNCTION_TRACER -#define MCOUNT_ADDR ((long)(_mcount)) +#define MCOUNT_ADDR ((unsigned long)(_mcount)) #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ #ifdef __ASSEMBLY__ diff --git a/arch/sh/include/asm/ftrace.h b/arch/sh/include/asm/ftrace.h index e79fb6ebaa423..1f157b86eaa7a 100644 --- a/arch/sh/include/asm/ftrace.h +++ b/arch/sh/include/asm/ftrace.h @@ -9,7 +9,7 @@ #ifndef __ASSEMBLY__ extern void mcount(void); -#define MCOUNT_ADDR ((long)(mcount)) +#define MCOUNT_ADDR ((unsigned long)(mcount)) #ifdef CONFIG_DYNAMIC_FTRACE #define CALL_ADDR ((long)(ftrace_call)) diff --git a/arch/sparc/include/asm/ftrace.h b/arch/sparc/include/asm/ftrace.h index 9ec94ad116fbd..3192a8e42fd62 100644 --- a/arch/sparc/include/asm/ftrace.h +++ b/arch/sparc/include/asm/ftrace.h @@ -2,7 +2,7 @@ #define _ASM_SPARC64_FTRACE #ifdef CONFIG_MCOUNT -#define MCOUNT_ADDR ((long)(_mcount)) +#define MCOUNT_ADDR ((unsigned long)(_mcount)) #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ #ifndef __ASSEMBLY__ diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h index f45acad3c4b67..24938852db301 100644 --- a/arch/x86/include/asm/ftrace.h +++ b/arch/x86/include/asm/ftrace.h @@ -3,9 +3,9 @@ #ifdef CONFIG_FUNCTION_TRACER #ifdef CC_USING_FENTRY -# define MCOUNT_ADDR ((long)(__fentry__)) +# define MCOUNT_ADDR ((unsigned long)(__fentry__)) #else -# define MCOUNT_ADDR ((long)(mcount)) +# define MCOUNT_ADDR ((unsigned long)(mcount)) #endif #define MCOUNT_INSN_SIZE 5 /* sizeof mcount call */ -- GitLab From 6acc23266054a9969737b435fa012f87465dbc50 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Thu, 16 Jul 2015 21:50:50 +0200 Subject: [PATCH 1287/7006] net: remove skb_frag_add_head It's not used anywhere. Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- include/linux/skbuff.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index af7a09650fa24..6bd96fe9416a2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -2678,12 +2678,6 @@ static inline void skb_frag_list_init(struct sk_buff *skb) skb_shinfo(skb)->frag_list = NULL; } -static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag) -{ - frag->next = skb_shinfo(skb)->frag_list; - skb_shinfo(skb)->frag_list = frag; -} - #define skb_walk_frags(skb, iter) \ for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) -- GitLab From 9d13ec65ede775f896c3da1cfa35283afe2f796c Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:19 -0400 Subject: [PATCH 1288/7006] tipc: introduce link entry structure to struct tipc_node struct 'tipc_node' currently contains two arrays for link attributes, one for the link pointers, and one for the usable link MTUs. We now group those into a new struct 'tipc_link_entry', and intoduce one single array consisting of such enties. Apart from being a cosmetic improvement, this is a starting point for the strict master-slave relation between node and link that we will introduce in the following commits. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 2 +- net/tipc/discover.c | 2 +- net/tipc/link.c | 60 ++++++++-------- net/tipc/name_distr.c | 2 +- net/tipc/node.c | 163 ++++++++++++++++++++---------------------- net/tipc/node.h | 50 +++++++------ 6 files changed, 143 insertions(+), 136 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index a816382fc8af1..59b2f2a538e11 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -413,7 +413,7 @@ static void bclink_accept_pkt(struct tipc_node *node, u32 seqno) * all nodes in the cluster don't ACK at the same time */ if (((seqno - tn->own_addr) % TIPC_MIN_LINK_WIN) == 0) { - tipc_link_proto_xmit(node->active_links[node->addr & 1], + tipc_link_proto_xmit(node_active_link(node, node->addr), STATE_MSG, 0, 0, 0, 0); tn->bcl->stats.sent_acks++; } diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 967e292f53c89..933445337fb40 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -170,7 +170,7 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, return; tipc_node_lock(node); node->capabilities = caps; - link = node->links[bearer->identity]; + link = node->links[bearer->identity].link; /* Prepare to validate requesting node's signature and media address */ sign_match = (signature == node->signature); diff --git a/net/tipc/link.c b/net/tipc/link.c index eaa9fe54b4aeb..03372a7e98df5 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -132,9 +132,11 @@ static void tipc_link_put(struct tipc_link *l_ptr) static struct tipc_link *tipc_parallel_link(struct tipc_link *l) { - if (l->owner->active_links[0] != l) - return l->owner->active_links[0]; - return l->owner->active_links[1]; + struct tipc_node *n = l->owner; + + if (node_active_link(n, 0) != l) + return node_active_link(n, 0); + return node_active_link(n, 1); } /* @@ -147,10 +149,11 @@ int tipc_link_is_up(struct tipc_link *l_ptr) return link_working_working(l_ptr) || link_working_unknown(l_ptr); } -int tipc_link_is_active(struct tipc_link *l_ptr) +int tipc_link_is_active(struct tipc_link *l) { - return (l_ptr->owner->active_links[0] == l_ptr) || - (l_ptr->owner->active_links[1] == l_ptr); + struct tipc_node *n = l->owner; + + return (node_active_link(n, 0) == l) || (node_active_link(n, 1) == l); } /** @@ -240,7 +243,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, return NULL; } - if (n_ptr->links[b_ptr->identity]) { + if (n_ptr->links[b_ptr->identity].link) { tipc_addr_string_fill(addr_string, n_ptr->addr); pr_err("Attempt to establish second link on <%s> to %s\n", b_ptr->name, addr_string); @@ -321,7 +324,7 @@ void tipc_link_delete_list(struct net *net, unsigned int bearer_id) rcu_read_lock(); list_for_each_entry_rcu(node, &tn->node_list, list) { tipc_node_lock(node); - link = node->links[bearer_id]; + link = node->links[bearer_id].link; if (link) tipc_link_delete(link); tipc_node_unlock(node); @@ -446,7 +449,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET)) return; - tipc_node_link_down(l_ptr->owner, l_ptr); + tipc_node_link_down(l_ptr->owner, l_ptr->bearer_id); tipc_bearer_remove_dest(owner->net, l_ptr->bearer_id, l_ptr->addr); if (was_active_link && tipc_node_is_up(l_ptr->owner) && (pl != l_ptr)) { @@ -482,7 +485,7 @@ static void link_activate(struct tipc_link *link) link->rcv_nxt = 1; link->stats.recv_info = 1; link->silent_intv_cnt = 0; - tipc_node_link_up(node, link); + tipc_node_link_up(node, link->bearer_id); tipc_bearer_add_dest(node->net, link->bearer_id, link->addr); } @@ -577,7 +580,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) case TRAFFIC_MSG_EVT: break; case ACTIVATE_MSG: - other = l_ptr->owner->active_links[0]; + other = node_active_link(l_ptr->owner, 0); if (other && link_working_unknown(other)) break; l_ptr->state = WORKING_WORKING; @@ -606,7 +609,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) switch (event) { case TRAFFIC_MSG_EVT: case ACTIVATE_MSG: - other = l_ptr->owner->active_links[0]; + other = node_active_link(l_ptr->owner, 0); if (other && link_working_unknown(other)) break; l_ptr->state = WORKING_WORKING; @@ -755,7 +758,7 @@ int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, node = tipc_node_find(net, dnode); if (node) { tipc_node_lock(node); - link = node->active_links[selector & 1]; + link = node_active_link(node, selector & 1); if (link) rc = __tipc_link_xmit(net, link, list); tipc_node_unlock(node); @@ -858,9 +861,9 @@ void tipc_link_reset_all(struct tipc_node *node) tipc_addr_string_fill(addr_string, node->addr)); for (i = 0; i < MAX_BEARERS; i++) { - if (node->links[i]) { - link_print(node->links[i], "Resetting link\n"); - tipc_link_reset(node->links[i]); + if (node->links[i].link) { + link_print(node->links[i].link, "Resetting link\n"); + tipc_link_reset(node->links[i].link); } } @@ -1029,7 +1032,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) tipc_node_lock(n_ptr); /* Locate unicast link endpoint that should handle message */ - l_ptr = n_ptr->links[b_ptr->identity]; + l_ptr = n_ptr->links[b_ptr->identity].link; if (unlikely(!l_ptr)) goto unlock; @@ -1496,7 +1499,7 @@ static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, struct sk_buff *skb; u32 length = msg_size(msg); - tunnel = l_ptr->owner->active_links[selector & 1]; + tunnel = node_active_link(l_ptr->owner, selector & 1); if (!tipc_link_is_up(tunnel)) { pr_warn("%stunnel link no longer available\n", link_co_err); return; @@ -1522,7 +1525,7 @@ static void tipc_link_tunnel_xmit(struct tipc_link *l_ptr, void tipc_link_failover_send_queue(struct tipc_link *l_ptr) { int msgcount; - struct tipc_link *tunnel = l_ptr->owner->active_links[0]; + struct tipc_link *tunnel = node_active_link(l_ptr->owner, 0); struct tipc_msg tunnel_hdr; struct sk_buff *skb; int split_bundles; @@ -1556,8 +1559,8 @@ void tipc_link_failover_send_queue(struct tipc_link *l_ptr) return; } - split_bundles = (l_ptr->owner->active_links[0] != - l_ptr->owner->active_links[1]); + split_bundles = (node_active_link(l_ptr->owner, 0) != + node_active_link(l_ptr->owner, 0)); skb_queue_walk(&l_ptr->transmq, skb) { struct tipc_msg *msg = buf_msg(skb); @@ -1660,7 +1663,7 @@ static bool tipc_link_failover_rcv(struct tipc_link *link, if (bearer_id == link->bearer_id) goto exit; - pl = link->owner->links[bearer_id]; + pl = link->owner->links[bearer_id].link; if (pl && tipc_link_is_up(pl)) tipc_link_reset(pl); @@ -1743,7 +1746,7 @@ static struct tipc_node *tipc_link_find_owner(struct net *net, list_for_each_entry_rcu(n_ptr, &tn->node_list, list) { tipc_node_lock(n_ptr); for (i = 0; i < MAX_BEARERS; i++) { - l_ptr = n_ptr->links[i]; + l_ptr = n_ptr->links[i].link; if (l_ptr && !strcmp(l_ptr->name, link_name)) { *bearer_id = i; found_node = n_ptr; @@ -1865,7 +1868,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info) tipc_node_lock(node); - link = node->links[bearer_id]; + link = node->links[bearer_id].link; if (!link) { res = -EINVAL; goto out; @@ -2055,10 +2058,11 @@ static int __tipc_nl_add_node_links(struct net *net, struct tipc_nl_msg *msg, for (i = *prev_link; i < MAX_BEARERS; i++) { *prev_link = i; - if (!node->links[i]) + if (!node->links[i].link) continue; - err = __tipc_nl_add_link(net, msg, node->links[i], NLM_F_MULTI); + err = __tipc_nl_add_link(net, msg, + node->links[i].link, NLM_F_MULTI); if (err) return err; } @@ -2172,7 +2176,7 @@ int tipc_nl_link_get(struct sk_buff *skb, struct genl_info *info) return -EINVAL; tipc_node_lock(node); - link = node->links[bearer_id]; + link = node->links[bearer_id].link; if (!link) { tipc_node_unlock(node); nlmsg_free(msg.skb); @@ -2227,7 +2231,7 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info) tipc_node_lock(node); - link = node->links[bearer_id]; + link = node->links[bearer_id].link; if (!link) { tipc_node_unlock(node); return -EINVAL; diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 41e7b7e4dda08..3a1539e962941 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -96,7 +96,7 @@ void named_cluster_distribute(struct net *net, struct sk_buff *skb) dnode = node->addr; if (in_own_node(net, dnode)) continue; - if (!tipc_node_active_links(node)) + if (!tipc_node_is_up(node)) continue; oskb = pskb_copy(skb, GFP_ATOMIC); if (!oskb) diff --git a/net/tipc/node.c b/net/tipc/node.c index 0b1d61a5f8533..db46e5d1d156f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -224,126 +224,119 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) * * Link becomes active (alone or shared) or standby, depending on its priority. */ -void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr) +void tipc_node_link_up(struct tipc_node *n, int bearer_id) { - struct tipc_link **active = &n_ptr->active_links[0]; + struct tipc_link_entry **actv = &n->active_links[0]; + struct tipc_link_entry *le = &n->links[bearer_id]; + struct tipc_link *l = le->link; - n_ptr->working_links++; - n_ptr->action_flags |= TIPC_NOTIFY_LINK_UP; - n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id; + /* Leave room for tunnel header when returning 'mtu' to users: */ + n->links[bearer_id].mtu = l->mtu - INT_H_SIZE; + + n->working_links++; + n->action_flags |= TIPC_NOTIFY_LINK_UP; + n->link_id = l->peer_bearer_id << 16 | l->bearer_id; pr_debug("Established link <%s> on network plane %c\n", - l_ptr->name, l_ptr->net_plane); + l->name, l->net_plane); - if (!active[0]) { - active[0] = active[1] = l_ptr; - node_established_contact(n_ptr); - goto exit; + /* No active links ? => take both active slots */ + if (!actv[0]) { + actv[0] = le; + actv[1] = le; + node_established_contact(n); + return; } - if (l_ptr->priority < active[0]->priority) { - pr_debug("New link <%s> becomes standby\n", l_ptr->name); - goto exit; + if (l->priority < actv[0]->link->priority) { + pr_debug("New link <%s> becomes standby\n", l->name); + return; } - tipc_link_dup_queue_xmit(active[0], l_ptr); - if (l_ptr->priority == active[0]->priority) { - active[0] = l_ptr; - goto exit; + tipc_link_dup_queue_xmit(actv[0]->link, l); + + /* Take one active slot if applicable */ + if (l->priority == actv[0]->link->priority) { + actv[0] = le; + return; } - pr_debug("Old link <%s> becomes standby\n", active[0]->name); - if (active[1] != active[0]) - pr_debug("Old link <%s> becomes standby\n", active[1]->name); - active[0] = active[1] = l_ptr; -exit: - /* Leave room for changeover header when returning 'mtu' to users: */ - n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE; - n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE; + /* Higher prio than current active? => take both active slots */ + pr_debug("Old l <%s> becomes standby\n", actv[0]->link->name); + if (actv[1] != actv[0]) + pr_debug("Old link <%s> now standby\n", actv[1]->link->name); + actv[0] = le; + actv[1] = le; } /** - * node_select_active_links - select active link + * node_select_active_links - select which working links should be active */ -static void node_select_active_links(struct tipc_node *n_ptr) +static void node_select_active_links(struct tipc_node *n) { - struct tipc_link **active = &n_ptr->active_links[0]; - u32 i; - u32 highest_prio = 0; + struct tipc_link_entry **actv = &n->active_links[0]; + struct tipc_link *l; + u32 b, highest = 0; - active[0] = active[1] = NULL; - - for (i = 0; i < MAX_BEARERS; i++) { - struct tipc_link *l_ptr = n_ptr->links[i]; + actv[0] = NULL; + actv[1] = NULL; - if (!l_ptr || !tipc_link_is_up(l_ptr) || - (l_ptr->priority < highest_prio)) + for (b = 0; b < MAX_BEARERS; b++) { + l = n->links[b].link; + if (!l || !tipc_link_is_up(l) || (l->priority < highest)) + continue; + if (l->priority > highest) { + highest = l->priority; + actv[0] = &n->links[b]; + actv[1] = &n->links[b]; continue; - - if (l_ptr->priority > highest_prio) { - highest_prio = l_ptr->priority; - active[0] = active[1] = l_ptr; - } else { - active[1] = l_ptr; } + actv[1] = &n->links[b]; } } /** * tipc_node_link_down - handle loss of link */ -void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr) +void tipc_node_link_down(struct tipc_node *n, int bearer_id) { - struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id); - struct tipc_link **active; + struct tipc_link_entry **actv = &n->active_links[0]; + struct tipc_link_entry *le = &n->links[bearer_id]; + struct tipc_link *l = le->link; - n_ptr->working_links--; - n_ptr->action_flags |= TIPC_NOTIFY_LINK_DOWN; - n_ptr->link_id = l_ptr->peer_bearer_id << 16 | l_ptr->bearer_id; + n->working_links--; + n->action_flags |= TIPC_NOTIFY_LINK_DOWN; + n->link_id = l->peer_bearer_id << 16 | l->bearer_id; - if (!tipc_link_is_active(l_ptr)) { + if (!tipc_link_is_active(l)) { pr_debug("Lost standby link <%s> on network plane %c\n", - l_ptr->name, l_ptr->net_plane); + l->name, l->net_plane); return; } pr_debug("Lost link <%s> on network plane %c\n", - l_ptr->name, l_ptr->net_plane); - - active = &n_ptr->active_links[0]; - if (active[0] == l_ptr) - active[0] = active[1]; - if (active[1] == l_ptr) - active[1] = active[0]; - if (active[0] == l_ptr) - node_select_active_links(n_ptr); - if (tipc_node_is_up(n_ptr)) - tipc_link_failover_send_queue(l_ptr); - else - node_lost_contact(n_ptr); + l->name, l->net_plane); - /* Leave room for changeover header when returning 'mtu' to users: */ - if (active[0]) { - n_ptr->act_mtus[0] = active[0]->mtu - INT_H_SIZE; - n_ptr->act_mtus[1] = active[1]->mtu - INT_H_SIZE; - return; - } - /* Loopback link went down? No fragmentation needed from now on. */ - if (n_ptr->addr == tn->own_addr) { - n_ptr->act_mtus[0] = MAX_MSG_SIZE; - n_ptr->act_mtus[1] = MAX_MSG_SIZE; - } -} + /* Resdistribute active slots if applicable */ + if (actv[0] == le) + actv[0] = actv[1]; + if (actv[1] == le) + actv[1] = actv[0]; -int tipc_node_active_links(struct tipc_node *n_ptr) -{ - return n_ptr->active_links[0] != NULL; + /* Last link of this priority? => select other ones if available */ + if (actv[0] == le) + node_select_active_links(n); + + if (tipc_node_is_up(n)) + tipc_link_failover_send_queue(l); + else + node_lost_contact(n); } -int tipc_node_is_up(struct tipc_node *n_ptr) +bool tipc_node_is_up(struct tipc_node *n) { - return tipc_node_active_links(n_ptr); + return n->active_links[0]; } void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { - n_ptr->links[l_ptr->bearer_id] = l_ptr; + n_ptr->links[l_ptr->bearer_id].link = l_ptr; n_ptr->link_cnt++; } @@ -352,9 +345,9 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) int i; for (i = 0; i < MAX_BEARERS; i++) { - if (l_ptr != n_ptr->links[i]) + if (l_ptr != n_ptr->links[i].link) continue; - n_ptr->links[i] = NULL; + n_ptr->links[i].link = NULL; n_ptr->link_cnt--; } } @@ -396,7 +389,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) /* Abort any ongoing link failover */ for (i = 0; i < MAX_BEARERS; i++) { - struct tipc_link *l_ptr = n_ptr->links[i]; + struct tipc_link *l_ptr = n_ptr->links[i].link; if (!l_ptr) continue; l_ptr->flags &= ~LINK_FAILINGOVER; @@ -453,7 +446,7 @@ int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 addr, goto exit; tipc_node_lock(node); - link = node->links[bearer_id]; + link = node->links[bearer_id].link; if (link) { strncpy(linkname, link->name, len); err = 0; diff --git a/net/tipc/node.h b/net/tipc/node.h index 5a834cf142c84..320cea313bdce 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -89,6 +89,11 @@ struct tipc_node_bclink { bool recv_permitted; }; +struct tipc_link_entry { + struct tipc_link *link; + u32 mtu; +}; + /** * struct tipc_node - TIPC node structure * @addr: network address of node @@ -98,9 +103,8 @@ struct tipc_node_bclink { * @hash: links to adjacent nodes in unsorted hash chain * @inputq: pointer to input queue containing messages for msg event * @namedq: pointer to name table input queue with name table messages - * @curr_link: the link holding the node lock, if any - * @active_links: pointers to active links to node - * @links: pointers to all links to node + * @active_links: pointer into links[] array, identifying which links are active + * @links: array containing references to all links to node * @action_flags: bit mask of different types of node actions * @bclink: broadcast-related info * @list: links to adjacent nodes in sorted list of cluster's nodes @@ -120,9 +124,8 @@ struct tipc_node { struct hlist_node hash; struct sk_buff_head *inputq; struct sk_buff_head *namedq; - struct tipc_link *active_links[2]; - u32 act_mtus[2]; - struct tipc_link *links[MAX_BEARERS]; + struct tipc_link_entry *active_links[2]; + struct tipc_link_entry links[MAX_BEARERS]; int action_flags; struct tipc_node_bclink bclink; struct list_head list; @@ -142,10 +145,9 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr); void tipc_node_stop(struct net *net); void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); -void tipc_node_link_down(struct tipc_node *n_ptr, struct tipc_link *l_ptr); -void tipc_node_link_up(struct tipc_node *n_ptr, struct tipc_link *l_ptr); -int tipc_node_active_links(struct tipc_node *n_ptr); -int tipc_node_is_up(struct tipc_node *n_ptr); +void tipc_node_link_down(struct tipc_node *n_ptr, int bearer_id); +void tipc_node_link_up(struct tipc_node *n_ptr, int bearer_id); +bool tipc_node_is_up(struct tipc_node *n); int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, char *linkname, size_t len); void tipc_node_unlock(struct tipc_node *node); @@ -165,20 +167,28 @@ static inline bool tipc_node_blocked(struct tipc_node *node) TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); } -static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector) +static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel) { - struct tipc_node *node; - u32 mtu; + struct tipc_link_entry *le = n->active_links[sel & 1]; - node = tipc_node_find(net, addr); + if (likely(le)) + return le->link; + return NULL; +} - if (likely(node)) { - mtu = node->act_mtus[selector & 1]; - tipc_node_put(node); - } else { - mtu = MAX_MSG_SIZE; - } +static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector) +{ + struct tipc_node *n; + struct tipc_link_entry *le; + unsigned int mtu = MAX_MSG_SIZE; + n = tipc_node_find(net, addr); + if (unlikely(!n)) + return mtu; + le = n->active_links[selector & 1]; + if (likely(le)) + mtu = le->mtu; + tipc_node_put(n); return mtu; } -- GitLab From d3a43b907ae688af6cb753c53cd7de05f3c1ba85 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:20 -0400 Subject: [PATCH 1289/7006] tipc: move link creation from neighbor discoverer to node As a step towards turning links into node internal entities, we move the creation of links from the neighbor discovery logics to the node's link control logics. We also create an additional entry for the link's media address in the newly introduced struct tipc_link_entry, since this is where it is needed in the upcoming commits. The current copy in struct tipc_link is kept for now, but will be removed later. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/discover.c | 20 ++++---------------- net/tipc/node.c | 27 +++++++++++++++++++++++++++ net/tipc/node.h | 6 ++++++ 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/net/tipc/discover.c b/net/tipc/discover.c index 933445337fb40..164d08907d6f6 100644 --- a/net/tipc/discover.c +++ b/net/tipc/discover.c @@ -35,7 +35,7 @@ */ #include "core.h" -#include "link.h" +#include "node.h" #include "discover.h" /* min delay during bearer start up */ @@ -125,7 +125,6 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, { struct tipc_net *tn = net_generic(net, tipc_net_id); struct tipc_node *node; - struct tipc_link *link; struct tipc_media_addr maddr; struct sk_buff *rbuf; struct tipc_msg *msg = buf_msg(buf); @@ -170,13 +169,10 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, return; tipc_node_lock(node); node->capabilities = caps; - link = node->links[bearer->identity].link; /* Prepare to validate requesting node's signature and media address */ sign_match = (signature == node->signature); - addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr)); - link_up = link && tipc_link_is_up(link); - + tipc_node_check_dest(node, bearer, &link_up, &addr_match, &maddr); /* These three flags give us eight permutations: */ @@ -239,16 +235,8 @@ void tipc_disc_rcv(struct net *net, struct sk_buff *buf, if (accept_sign) node->signature = signature; - if (accept_addr) { - if (!link) - link = tipc_link_create(node, bearer, &maddr); - if (link) { - memcpy(&link->media_addr, &maddr, sizeof(maddr)); - tipc_link_reset(link); - } else { - respond = false; - } - } + if (accept_addr && !tipc_node_update_dest(node, bearer, &maddr)) + respond = false; /* Send response, if necessary */ if (respond && (mtyp == DSC_REQ_MSG)) { diff --git a/net/tipc/node.c b/net/tipc/node.c index db46e5d1d156f..06f642abdf38f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -334,6 +334,33 @@ bool tipc_node_is_up(struct tipc_node *n) return n->active_links[0]; } +void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b, + bool *link_up, bool *addr_match, + struct tipc_media_addr *maddr) +{ + struct tipc_link *l = n->links[b->identity].link; + struct tipc_media_addr *curr = &n->links[b->identity].maddr; + + *link_up = l && tipc_link_is_up(l); + *addr_match = l && !memcmp(curr, maddr, sizeof(*maddr)); +} + +bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b, + struct tipc_media_addr *maddr) +{ + struct tipc_link *l = n->links[b->identity].link; + struct tipc_media_addr *curr = &n->links[b->identity].maddr; + + if (!l) + l = tipc_link_create(n, b, maddr); + if (!l) + return false; + memcpy(&l->media_addr, maddr, sizeof(*maddr)); + memcpy(curr, maddr, sizeof(*maddr)); + tipc_link_reset(l); + return true; +} + void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) { n_ptr->links[l_ptr->bearer_id].link = l_ptr; diff --git a/net/tipc/node.h b/net/tipc/node.h index 320cea313bdce..68579c70748ba 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -92,6 +92,7 @@ struct tipc_node_bclink { struct tipc_link_entry { struct tipc_link *link; u32 mtu; + struct tipc_media_addr maddr; }; /** @@ -143,6 +144,11 @@ struct tipc_node *tipc_node_find(struct net *net, u32 addr); void tipc_node_put(struct tipc_node *node); struct tipc_node *tipc_node_create(struct net *net, u32 addr); void tipc_node_stop(struct net *net); +void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *bearer, + bool *link_up, bool *addr_match, + struct tipc_media_addr *maddr); +bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *bearer, + struct tipc_media_addr *maddr); void tipc_node_attach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr); void tipc_node_link_down(struct tipc_node *n_ptr, int bearer_id); -- GitLab From d39bbd445dc44259c77bbbc8aadcce7dcdba39cc Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:21 -0400 Subject: [PATCH 1290/7006] tipc: move link input queue to tipc_node At present, the link input queue and the name distributor receive queues are fields aggregated in struct tipc_link. This is a hazard, because a link might be deleted while a receiving socket still keeps reference to one of the queues. This commit fixes this bug. However, rather than adding yet another reference counter to the critical data path, we move the two queues to safe ground inside struct tipc_node, which is already protected, and let the link code only handle references to the queues. This is also in line with planned later changes in this area. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 27 +++++++++++++++------------ net/tipc/link.h | 12 +++++++----- net/tipc/node.c | 4 +++- net/tipc/node.h | 3 ++- 4 files changed, 27 insertions(+), 19 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 03372a7e98df5..f8e0e2ceceb45 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -227,7 +227,9 @@ static void link_set_timer(struct tipc_link *link, unsigned long time) */ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, struct tipc_bearer *b_ptr, - const struct tipc_media_addr *media_addr) + const struct tipc_media_addr *media_addr, + struct sk_buff_head *inputq, + struct sk_buff_head *namedq) { struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id); struct tipc_link *l_ptr; @@ -289,8 +291,9 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, __skb_queue_head_init(&l_ptr->backlogq); __skb_queue_head_init(&l_ptr->deferdq); skb_queue_head_init(&l_ptr->wakeupq); - skb_queue_head_init(&l_ptr->inputq); - skb_queue_head_init(&l_ptr->namedq); + l_ptr->inputq = inputq; + l_ptr->namedq = namedq; + skb_queue_head_init(l_ptr->inputq); link_reset_statistics(l_ptr); tipc_node_attach_link(n_ptr, l_ptr); setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr); @@ -391,8 +394,8 @@ void link_prepare_wakeup(struct tipc_link *l) if ((pnd[imp] + l->backlog[imp].len) >= lim) break; skb_unlink(skb, &l->wakeupq); - skb_queue_tail(&l->inputq, skb); - l->owner->inputq = &l->inputq; + skb_queue_tail(l->inputq, skb); + l->owner->inputq = l->inputq; l->owner->action_flags |= TIPC_MSG_EVT; } } @@ -465,7 +468,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) __skb_queue_purge(&l_ptr->transmq); __skb_queue_purge(&l_ptr->deferdq); if (!owner->inputq) - owner->inputq = &l_ptr->inputq; + owner->inputq = l_ptr->inputq; skb_queue_splice_init(&l_ptr->wakeupq, owner->inputq); if (!skb_queue_empty(owner->inputq)) owner->action_flags |= TIPC_MSG_EVT; @@ -962,7 +965,7 @@ static bool link_synch(struct tipc_link *l) /* Is it still in the input queue ? */ post_synch = mod(pl->rcv_nxt - l->synch_point) - 1; - if (skb_queue_len(&pl->inputq) > post_synch) + if (skb_queue_len(pl->inputq) > post_synch) return false; synched: l->flags &= ~LINK_SYNCHING; @@ -1141,16 +1144,16 @@ static bool tipc_data_input(struct tipc_link *link, struct sk_buff *skb) case TIPC_HIGH_IMPORTANCE: case TIPC_CRITICAL_IMPORTANCE: case CONN_MANAGER: - if (tipc_skb_queue_tail(&link->inputq, skb, dport)) { - node->inputq = &link->inputq; + if (tipc_skb_queue_tail(link->inputq, skb, dport)) { + node->inputq = link->inputq; node->action_flags |= TIPC_MSG_EVT; } return true; case NAME_DISTRIBUTOR: node->bclink.recv_permitted = true; - node->namedq = &link->namedq; - skb_queue_tail(&link->namedq, skb); - if (skb_queue_len(&link->namedq) == 1) + node->namedq = link->namedq; + skb_queue_tail(link->namedq, skb); + if (skb_queue_len(link->namedq) == 1) node->action_flags |= TIPC_NAMED_MSG_EVT; return true; case MSG_BUNDLER: diff --git a/net/tipc/link.h b/net/tipc/link.h index ae0a0ea572f29..9c71d9e42e930 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -192,8 +192,8 @@ struct tipc_link { u16 rcv_nxt; u32 rcv_unacked; struct sk_buff_head deferdq; - struct sk_buff_head inputq; - struct sk_buff_head namedq; + struct sk_buff_head *inputq; + struct sk_buff_head *namedq; /* Congestion handling */ struct sk_buff_head wakeupq; @@ -207,9 +207,11 @@ struct tipc_link { struct tipc_port; -struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, - struct tipc_bearer *b_ptr, - const struct tipc_media_addr *media_addr); +struct tipc_link *tipc_link_create(struct tipc_node *n, + struct tipc_bearer *b, + const struct tipc_media_addr *maddr, + struct sk_buff_head *inputq, + struct sk_buff_head *namedq); void tipc_link_delete(struct tipc_link *link); void tipc_link_delete_list(struct net *net, unsigned int bearer_id); void tipc_link_failover_send_queue(struct tipc_link *l_ptr); diff --git a/net/tipc/node.c b/net/tipc/node.c index 06f642abdf38f..20ec61cefface 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -132,6 +132,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) INIT_LIST_HEAD(&n_ptr->list); INIT_LIST_HEAD(&n_ptr->publ_list); INIT_LIST_HEAD(&n_ptr->conn_sks); + skb_queue_head_init(&n_ptr->bclink.namedq); __skb_queue_head_init(&n_ptr->bclink.deferdq); hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); list_for_each_entry_rcu(temp_node, &tn->node_list, list) { @@ -350,9 +351,10 @@ bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b, { struct tipc_link *l = n->links[b->identity].link; struct tipc_media_addr *curr = &n->links[b->identity].maddr; + struct sk_buff_head *inputq = &n->links[b->identity].inputq; if (!l) - l = tipc_link_create(n, b, maddr); + l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq); if (!l) return false; memcpy(&l->media_addr, maddr, sizeof(*maddr)); diff --git a/net/tipc/node.h b/net/tipc/node.h index 68579c70748ba..0657cbf1f5cd5 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -85,13 +85,14 @@ struct tipc_node_bclink { u32 deferred_size; struct sk_buff_head deferdq; struct sk_buff *reasm_buf; - int inputq_map; + struct sk_buff_head namedq; bool recv_permitted; }; struct tipc_link_entry { struct tipc_link *link; u32 mtu; + struct sk_buff_head inputq; struct tipc_media_addr maddr; }; -- GitLab From 36e78a463b26c9b8017a2e11dcd6c4b8e34b4161 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:22 -0400 Subject: [PATCH 1291/7006] tipc: use bearer index when looking up active links struct tipc_node currently holds two arrays of link pointers; one, indexed by bearer identity, which contains all links irrespective of current state, and one two-slot array for the currently active link or links. The latter array contains direct pointers into the elements of the former. This has the effect that we cannot know the bearer id of a link when accessing it via the "active_links[]" array without actually dereferencing the pointer, something we want to avoid in some cases. In this commit, we do instead store the bearer identity in the "active_links" array, and use this as an index to find the right element in the overall link entry array. This change should be seen as a preparation for the later commits in this series. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/node.c | 106 ++++++++++++++++++++---------------------------- net/tipc/node.h | 26 +++++++----- 2 files changed, 59 insertions(+), 73 deletions(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 20ec61cefface..19729645d4947 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -142,6 +142,8 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) list_add_tail_rcu(&n_ptr->list, &temp_node->list); n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN; n_ptr->signature = INVALID_NODE_SIG; + n_ptr->active_links[0] = INVALID_BEARER_ID; + n_ptr->active_links[1] = INVALID_BEARER_ID; tipc_node_get(n_ptr); exit: spin_unlock_bh(&tn->node_list_lock); @@ -227,12 +229,13 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) */ void tipc_node_link_up(struct tipc_node *n, int bearer_id) { - struct tipc_link_entry **actv = &n->active_links[0]; - struct tipc_link_entry *le = &n->links[bearer_id]; - struct tipc_link *l = le->link; + int *slot0 = &n->active_links[0]; + int *slot1 = &n->active_links[1]; + struct tipc_link_entry *links = n->links; + struct tipc_link *l = n->links[bearer_id].link; /* Leave room for tunnel header when returning 'mtu' to users: */ - n->links[bearer_id].mtu = l->mtu - INT_H_SIZE; + links[bearer_id].mtu = l->mtu - INT_H_SIZE; n->working_links++; n->action_flags |= TIPC_NOTIFY_LINK_UP; @@ -242,55 +245,30 @@ void tipc_node_link_up(struct tipc_node *n, int bearer_id) l->name, l->net_plane); /* No active links ? => take both active slots */ - if (!actv[0]) { - actv[0] = le; - actv[1] = le; + if (*slot0 < 0) { + *slot0 = bearer_id; + *slot1 = bearer_id; node_established_contact(n); return; } - if (l->priority < actv[0]->link->priority) { + + /* Lower prio than current active ? => no slot */ + if (l->priority < links[*slot0].link->priority) { pr_debug("New link <%s> becomes standby\n", l->name); return; } - tipc_link_dup_queue_xmit(actv[0]->link, l); + tipc_link_dup_queue_xmit(links[*slot0].link, l); - /* Take one active slot if applicable */ - if (l->priority == actv[0]->link->priority) { - actv[0] = le; + /* Same prio as current active ? => take one slot */ + if (l->priority == links[*slot0].link->priority) { + *slot0 = bearer_id; return; } - /* Higher prio than current active? => take both active slots */ - pr_debug("Old l <%s> becomes standby\n", actv[0]->link->name); - if (actv[1] != actv[0]) - pr_debug("Old link <%s> now standby\n", actv[1]->link->name); - actv[0] = le; - actv[1] = le; -} - -/** - * node_select_active_links - select which working links should be active - */ -static void node_select_active_links(struct tipc_node *n) -{ - struct tipc_link_entry **actv = &n->active_links[0]; - struct tipc_link *l; - u32 b, highest = 0; - actv[0] = NULL; - actv[1] = NULL; - - for (b = 0; b < MAX_BEARERS; b++) { - l = n->links[b].link; - if (!l || !tipc_link_is_up(l) || (l->priority < highest)) - continue; - if (l->priority > highest) { - highest = l->priority; - actv[0] = &n->links[b]; - actv[1] = &n->links[b]; - continue; - } - actv[1] = &n->links[b]; - } + /* Higher prio than current active => take both active slots */ + pr_debug("Old link <%s> now standby\n", links[*slot0].link->name); + *slot0 = bearer_id; + *slot1 = bearer_id; } /** @@ -298,32 +276,36 @@ static void node_select_active_links(struct tipc_node *n) */ void tipc_node_link_down(struct tipc_node *n, int bearer_id) { - struct tipc_link_entry **actv = &n->active_links[0]; - struct tipc_link_entry *le = &n->links[bearer_id]; - struct tipc_link *l = le->link; + int *slot0 = &n->active_links[0]; + int *slot1 = &n->active_links[1]; + int i, highest = 0; + struct tipc_link *l, *_l; + l = n->links[bearer_id].link; n->working_links--; n->action_flags |= TIPC_NOTIFY_LINK_DOWN; n->link_id = l->peer_bearer_id << 16 | l->bearer_id; - if (!tipc_link_is_active(l)) { - pr_debug("Lost standby link <%s> on network plane %c\n", - l->name, l->net_plane); - return; - } pr_debug("Lost link <%s> on network plane %c\n", l->name, l->net_plane); - /* Resdistribute active slots if applicable */ - if (actv[0] == le) - actv[0] = actv[1]; - if (actv[1] == le) - actv[1] = actv[0]; - - /* Last link of this priority? => select other ones if available */ - if (actv[0] == le) - node_select_active_links(n); - + /* Select new active link if any available */ + *slot0 = INVALID_BEARER_ID; + *slot1 = INVALID_BEARER_ID; + for (i = 0; i < MAX_BEARERS; i++) { + _l = n->links[i].link; + if (!_l || !tipc_link_is_up(_l)) + continue; + if (_l->priority < highest) + continue; + if (_l->priority > highest) { + highest = _l->priority; + *slot0 = i; + *slot1 = i; + continue; + } + *slot1 = i; + } if (tipc_node_is_up(n)) tipc_link_failover_send_queue(l); else @@ -332,7 +314,7 @@ void tipc_node_link_down(struct tipc_node *n, int bearer_id) bool tipc_node_is_up(struct tipc_node *n) { - return n->active_links[0]; + return n->active_links[0] != INVALID_BEARER_ID; } void tipc_node_check_dest(struct tipc_node *n, struct tipc_bearer *b, diff --git a/net/tipc/node.h b/net/tipc/node.h index 0657cbf1f5cd5..74f278adada35 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -45,6 +45,8 @@ /* Out-of-range value for node signature */ #define INVALID_NODE_SIG 0x10000 +#define INVALID_BEARER_ID -1 + /* Flags used to take different actions according to flag type * TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down * TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down @@ -105,7 +107,7 @@ struct tipc_link_entry { * @hash: links to adjacent nodes in unsorted hash chain * @inputq: pointer to input queue containing messages for msg event * @namedq: pointer to name table input queue with name table messages - * @active_links: pointer into links[] array, identifying which links are active + * @active_links: bearer ids of active links, used as index into links[] array * @links: array containing references to all links to node * @action_flags: bit mask of different types of node actions * @bclink: broadcast-related info @@ -126,7 +128,7 @@ struct tipc_node { struct hlist_node hash; struct sk_buff_head *inputq; struct sk_buff_head *namedq; - struct tipc_link_entry *active_links[2]; + int active_links[2]; struct tipc_link_entry links[MAX_BEARERS]; int action_flags; struct tipc_node_bclink bclink; @@ -176,25 +178,27 @@ static inline bool tipc_node_blocked(struct tipc_node *node) static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel) { - struct tipc_link_entry *le = n->active_links[sel & 1]; + int bearer_id = n->active_links[sel & 1]; + + if (unlikely(bearer_id == INVALID_BEARER_ID)) + return NULL; - if (likely(le)) - return le->link; - return NULL; + return n->links[bearer_id].link; } -static inline uint tipc_node_get_mtu(struct net *net, u32 addr, u32 selector) +static inline unsigned int tipc_node_get_mtu(struct net *net, u32 addr, u32 sel) { struct tipc_node *n; - struct tipc_link_entry *le; + int bearer_id; unsigned int mtu = MAX_MSG_SIZE; n = tipc_node_find(net, addr); if (unlikely(!n)) return mtu; - le = n->active_links[selector & 1]; - if (likely(le)) - mtu = le->mtu; + + bearer_id = n->active_links[sel & 1]; + if (likely(bearer_id != INVALID_BEARER_ID)) + mtu = n->links[bearer_id].mtu; tipc_node_put(n); return mtu; } -- GitLab From 22d85c79428b8ca9a01623aa3e3a1fe29a30a119 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:23 -0400 Subject: [PATCH 1292/7006] tipc: change sk_buffer handling in tipc_link_xmit() When the function tipc_link_xmit() is given a buffer list for transmission, it currently consumes the list both when transmission is successful and when it fails, except for the special case when it encounters link congestion. This behavior is inconsistent, and needs to be corrected if we want to avoid problems in later commits in this series. In this commit, we change this to let the function consume the list only when transmission is successful, and leave the list with the sender in all other cases. We also modifiy the socket code so that it adapts to this change, i.e., purges the list when a non-congestion error code is returned. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 5 ++--- net/tipc/link.c | 23 +++++++++------------- net/tipc/socket.c | 49 +++++++++++++++++++++++++---------------------- 3 files changed, 37 insertions(+), 40 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 59b2f2a538e11..295bdc26f1037 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -358,10 +358,9 @@ int tipc_bclink_xmit(struct net *net, struct sk_buff_head *list) /* Prepare clone of message for local node */ skb = tipc_msg_reassemble(list); - if (unlikely(!skb)) { - __skb_queue_purge(list); + if (unlikely(!skb)) return -EHOSTUNREACH; - } + /* Broadcast to all nodes */ if (likely(bclink)) { tipc_bclink_lock(net); diff --git a/net/tipc/link.c b/net/tipc/link.c index f8e0e2ceceb45..ea32679b67379 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -340,7 +340,7 @@ void tipc_link_delete_list(struct net *net, unsigned int bearer_id) * @link: congested link * @list: message that was attempted sent * Create pseudo msg to send back to user when congestion abates - * Only consumes message if there is an error + * Does not consume buffer list */ static int link_schedule_user(struct tipc_link *link, struct sk_buff_head *list) { @@ -354,7 +354,7 @@ static int link_schedule_user(struct tipc_link *link, struct sk_buff_head *list) if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) { pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); tipc_link_reset(link); - goto err; + return -ENOBUFS; } /* Non-blocking sender: */ if (TIPC_SKB_CB(skb_peek(list))->wakeup_pending) @@ -364,15 +364,12 @@ static int link_schedule_user(struct tipc_link *link, struct sk_buff_head *list) skb = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, addr, addr, oport, 0, 0); if (!skb) - goto err; + return -ENOBUFS; TIPC_SKB_CB(skb)->chain_sz = skb_queue_len(list); TIPC_SKB_CB(skb)->chain_imp = imp; skb_queue_tail(&link->wakeupq, skb); link->stats.link_congs++; return -ELINKCONG; -err: - __skb_queue_purge(list); - return -ENOBUFS; } /** @@ -641,8 +638,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) * @link: link to use * @list: chain of buffers containing message * - * Consumes the buffer chain, except when returning -ELINKCONG, - * since the caller then may want to make more send attempts. + * Consumes the buffer chain, except when returning an error code, * Returns 0 if success, or errno: -ELINKCONG, -EMSGSIZE or -ENOBUFS * Messages at TIPC_SYSTEM_IMPORTANCE are always accepted */ @@ -666,10 +662,9 @@ int __tipc_link_xmit(struct net *net, struct tipc_link *link, if (unlikely(link->backlog[i].len >= link->backlog[i].limit)) return link_schedule_user(link, list); } - if (unlikely(msg_size(msg) > mtu)) { - __skb_queue_purge(list); + if (unlikely(msg_size(msg) > mtu)) return -EMSGSIZE; - } + /* Prepare each packet for sending, and add to relevant queue: */ while (skb_queue_len(list)) { skb = skb_peek(list); @@ -722,7 +717,7 @@ static int __tipc_link_xmit_skb(struct tipc_link *link, struct sk_buff *skb) /* tipc_link_xmit_skb(): send single buffer to destination * Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE - * messages, which will not be rejected + * messages, which will not cause link congestion * The only exception is datagram messages rerouted after secondary * lookup, which are rare and safe to dispose of anyway. * TODO: Return real return value, and let callers use @@ -736,7 +731,7 @@ int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, skb2list(skb, &head); rc = tipc_link_xmit(net, &head, dnode, selector); - if (rc == -ELINKCONG) + if (rc) kfree_skb(skb); return 0; } @@ -748,7 +743,7 @@ int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, * @dsz: amount of user data to be sent * @dnode: address of destination node * @selector: a number used for deterministic link selection - * Consumes the buffer chain, except when returning -ELINKCONG + * Consumes the buffer chain, except when returning error * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE */ int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 3a7567f690f35..87fef25f6519e 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -686,21 +686,22 @@ new_mtu: do { rc = tipc_bclink_xmit(net, pktchain); - if (likely(rc >= 0)) { - rc = dsz; - break; + if (likely(!rc)) + return dsz; + + if (rc == -ELINKCONG) { + tsk->link_cong = 1; + rc = tipc_wait_for_sndmsg(sock, &timeo); + if (!rc) + continue; } + __skb_queue_purge(pktchain); if (rc == -EMSGSIZE) { msg->msg_iter = save; goto new_mtu; } - if (rc != -ELINKCONG) - break; - tipc_sk(sk)->link_cong = 1; - rc = tipc_wait_for_sndmsg(sock, &timeo); - if (rc) - __skb_queue_purge(pktchain); - } while (!rc); + break; + } while (1); return rc; } @@ -925,23 +926,24 @@ new_mtu: skb = skb_peek(pktchain); TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong; rc = tipc_link_xmit(net, pktchain, dnode, tsk->portid); - if (likely(rc >= 0)) { + if (likely(!rc)) { if (sock->state != SS_READY) sock->state = SS_CONNECTING; - rc = dsz; - break; + return dsz; } + if (rc == -ELINKCONG) { + tsk->link_cong = 1; + rc = tipc_wait_for_sndmsg(sock, &timeo); + if (!rc) + continue; + } + __skb_queue_purge(pktchain); if (rc == -EMSGSIZE) { m->msg_iter = save; goto new_mtu; } - if (rc != -ELINKCONG) - break; - tsk->link_cong = 1; - rc = tipc_wait_for_sndmsg(sock, &timeo); - if (rc) - __skb_queue_purge(pktchain); - } while (!rc); + break; + } while (1); return rc; } @@ -1048,10 +1050,11 @@ next: tsk->sent_unacked++; sent += send; if (sent == dsz) - break; + return dsz; goto next; } if (rc == -EMSGSIZE) { + __skb_queue_purge(pktchain); tsk->max_pkt = tipc_node_get_mtu(net, dnode, portid); m->msg_iter = save; @@ -1059,13 +1062,13 @@ next: } if (rc != -ELINKCONG) break; + tsk->link_cong = 1; } rc = tipc_wait_for_sndpkt(sock, &timeo); - if (rc) - __skb_queue_purge(pktchain); } while (!rc); + __skb_queue_purge(pktchain); return sent ? sent : rc; } -- GitLab From af9b028e270fda6fb812d70d17d902297df1ceb5 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:24 -0400 Subject: [PATCH 1293/7006] tipc: make media xmit call outside node spinlock context Currently, message sending is performed through a deep call chain, where the node spinlock is grabbed and held during a significant part of the transmission time. This is clearly detrimental to overall throughput performance; it would be better if we could send the message after the spinlock has been released. In this commit, we do instead let the call revert on the stack after the buffer chain has been added to the transmission queue, whereafter clones of the buffers are transmitted to the device layer outside the spinlock scope. As a further step in our effort to separate the roles of the node and link entities we also move the function tipc_link_xmit() to node.c, and rename it to tipc_node_xmit(). Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bearer.c | 26 +++++++++ net/tipc/bearer.h | 3 + net/tipc/link.c | 132 +++++++++++++++++++++++------------------- net/tipc/link.h | 6 +- net/tipc/name_distr.c | 4 +- net/tipc/node.c | 78 +++++++++++++++++++++++++ net/tipc/node.h | 4 ++ net/tipc/socket.c | 22 +++---- 8 files changed, 198 insertions(+), 77 deletions(-) diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c index 00bc0e6205326..eae58a6b121cf 100644 --- a/net/tipc/bearer.c +++ b/net/tipc/bearer.c @@ -470,6 +470,32 @@ void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf, rcu_read_unlock(); } +/* tipc_bearer_xmit() -send buffer to destination over bearer + */ +void tipc_bearer_xmit(struct net *net, u32 bearer_id, + struct sk_buff_head *xmitq, + struct tipc_media_addr *dst) +{ + struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_bearer *b; + struct sk_buff *skb, *tmp; + + if (skb_queue_empty(xmitq)) + return; + + rcu_read_lock(); + b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]); + if (likely(b)) { + skb_queue_walk_safe(xmitq, skb, tmp) { + __skb_dequeue(xmitq); + b->media->send_msg(net, skb, b, dst); + /* Until we remove cloning in tipc_l2_send_msg(): */ + kfree_skb(skb); + } + } + rcu_read_unlock(); +} + /** * tipc_l2_rcv_msg - handle incoming TIPC message from an interface * @buf: the received packet diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h index dc714d977768c..6426f242f6262 100644 --- a/net/tipc/bearer.h +++ b/net/tipc/bearer.h @@ -217,5 +217,8 @@ void tipc_bearer_cleanup(void); void tipc_bearer_stop(struct net *net); void tipc_bearer_send(struct net *net, u32 bearer_id, struct sk_buff *buf, struct tipc_media_addr *dest); +void tipc_bearer_xmit(struct net *net, u32 bearer_id, + struct sk_buff_head *xmitq, + struct tipc_media_addr *dst); #endif /* _TIPC_BEARER_H */ diff --git a/net/tipc/link.c b/net/tipc/link.c index ea32679b67379..c052437a7cfad 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -353,7 +353,6 @@ static int link_schedule_user(struct tipc_link *link, struct sk_buff_head *list) /* This really cannot happen... */ if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) { pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); - tipc_link_reset(link); return -ENOBUFS; } /* Non-blocking sender: */ @@ -701,6 +700,78 @@ int __tipc_link_xmit(struct net *net, struct tipc_link *link, return 0; } +/** + * tipc_link_xmit(): enqueue buffer list according to queue situation + * @link: link to use + * @list: chain of buffers containing message + * @xmitq: returned list of packets to be sent by caller + * + * Consumes the buffer chain, except when returning -ELINKCONG, + * since the caller then may want to make more send attempts. + * Returns 0 if success, or errno: -ELINKCONG, -EMSGSIZE or -ENOBUFS + * Messages at TIPC_SYSTEM_IMPORTANCE are always accepted + */ +int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list, + struct sk_buff_head *xmitq) +{ + struct tipc_msg *hdr = buf_msg(skb_peek(list)); + unsigned int maxwin = l->window; + unsigned int i, imp = msg_importance(hdr); + unsigned int mtu = l->mtu; + u16 ack = l->rcv_nxt - 1; + u16 seqno = l->snd_nxt; + u16 bc_last_in = l->owner->bclink.last_in; + struct sk_buff_head *transmq = &l->transmq; + struct sk_buff_head *backlogq = &l->backlogq; + struct sk_buff *skb, *_skb, *bskb; + + /* Match msg importance against this and all higher backlog limits: */ + for (i = imp; i <= TIPC_SYSTEM_IMPORTANCE; i++) { + if (unlikely(l->backlog[i].len >= l->backlog[i].limit)) + return link_schedule_user(l, list); + } + if (unlikely(msg_size(hdr) > mtu)) + return -EMSGSIZE; + + /* Prepare each packet for sending, and add to relevant queue: */ + while (skb_queue_len(list)) { + skb = skb_peek(list); + hdr = buf_msg(skb); + msg_set_seqno(hdr, seqno); + msg_set_ack(hdr, ack); + msg_set_bcast_ack(hdr, bc_last_in); + + if (likely(skb_queue_len(transmq) < maxwin)) { + _skb = skb_clone(skb, GFP_ATOMIC); + if (!_skb) + return -ENOBUFS; + __skb_dequeue(list); + __skb_queue_tail(transmq, skb); + __skb_queue_tail(xmitq, _skb); + l->rcv_unacked = 0; + seqno++; + continue; + } + if (tipc_msg_bundle(skb_peek_tail(backlogq), hdr, mtu)) { + kfree_skb(__skb_dequeue(list)); + l->stats.sent_bundled++; + continue; + } + if (tipc_msg_make_bundle(&bskb, hdr, mtu, l->addr)) { + kfree_skb(__skb_dequeue(list)); + __skb_queue_tail(backlogq, bskb); + l->backlog[msg_importance(buf_msg(bskb))].len++; + l->stats.sent_bundled++; + l->stats.sent_bundles++; + continue; + } + l->backlog[imp].len += skb_queue_len(list); + skb_queue_splice_tail_init(list, backlogq); + } + l->snd_nxt = seqno; + return 0; +} + static void skb2list(struct sk_buff *skb, struct sk_buff_head *list) { skb_queue_head_init(list); @@ -715,65 +786,6 @@ static int __tipc_link_xmit_skb(struct tipc_link *link, struct sk_buff *skb) return __tipc_link_xmit(link->owner->net, link, &head); } -/* tipc_link_xmit_skb(): send single buffer to destination - * Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE - * messages, which will not cause link congestion - * The only exception is datagram messages rerouted after secondary - * lookup, which are rare and safe to dispose of anyway. - * TODO: Return real return value, and let callers use - * tipc_wait_for_sendpkt() where applicable - */ -int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, - u32 selector) -{ - struct sk_buff_head head; - int rc; - - skb2list(skb, &head); - rc = tipc_link_xmit(net, &head, dnode, selector); - if (rc) - kfree_skb(skb); - return 0; -} - -/** - * tipc_link_xmit() is the general link level function for message sending - * @net: the applicable net namespace - * @list: chain of buffers containing message - * @dsz: amount of user data to be sent - * @dnode: address of destination node - * @selector: a number used for deterministic link selection - * Consumes the buffer chain, except when returning error - * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE - */ -int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, - u32 selector) -{ - struct tipc_link *link = NULL; - struct tipc_node *node; - int rc = -EHOSTUNREACH; - - node = tipc_node_find(net, dnode); - if (node) { - tipc_node_lock(node); - link = node_active_link(node, selector & 1); - if (link) - rc = __tipc_link_xmit(net, link, list); - tipc_node_unlock(node); - tipc_node_put(node); - } - if (link) - return rc; - - if (likely(in_own_node(net, dnode))) { - tipc_sk_rcv(net, list); - return 0; - } - - __skb_queue_purge(list); - return rc; -} - /* * tipc_link_sync_xmit - synchronize broadcast link endpoints. * diff --git a/net/tipc/link.h b/net/tipc/link.h index 9c71d9e42e930..7add2b90361d8 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -223,12 +223,10 @@ void tipc_link_purge_queues(struct tipc_link *l_ptr); void tipc_link_purge_backlog(struct tipc_link *l); void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset(struct tipc_link *l_ptr); -int tipc_link_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest, - u32 selector); -int tipc_link_xmit(struct net *net, struct sk_buff_head *list, u32 dest, - u32 selector); int __tipc_link_xmit(struct net *net, struct tipc_link *link, struct sk_buff_head *list); +int tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list, + struct sk_buff_head *xmitq); void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, u32 gap, u32 tolerance, u32 priority); void tipc_link_push_packets(struct tipc_link *l_ptr); diff --git a/net/tipc/name_distr.c b/net/tipc/name_distr.c index 3a1539e962941..e6018b7eb1970 100644 --- a/net/tipc/name_distr.c +++ b/net/tipc/name_distr.c @@ -102,7 +102,7 @@ void named_cluster_distribute(struct net *net, struct sk_buff *skb) if (!oskb) break; msg_set_destnode(buf_msg(oskb), dnode); - tipc_link_xmit_skb(net, oskb, dnode, dnode); + tipc_node_xmit_skb(net, oskb, dnode, dnode); } rcu_read_unlock(); @@ -223,7 +223,7 @@ void tipc_named_node_up(struct net *net, u32 dnode) &tn->nametbl->publ_list[TIPC_ZONE_SCOPE]); rcu_read_unlock(); - tipc_link_xmit(net, &head, dnode, dnode); + tipc_node_xmit(net, &head, dnode, dnode); } static void tipc_publ_subscribe(struct net *net, struct publication *publ, diff --git a/net/tipc/node.c b/net/tipc/node.c index 19729645d4947..ad759bb034e7d 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -563,6 +563,84 @@ msg_full: return -EMSGSIZE; } +static struct tipc_link *tipc_node_select_link(struct tipc_node *n, int sel, + int *bearer_id, + struct tipc_media_addr **maddr) +{ + int id = n->active_links[sel & 1]; + + if (unlikely(id < 0)) + return NULL; + + *bearer_id = id; + *maddr = &n->links[id].maddr; + return n->links[id].link; +} + +/** + * tipc_node_xmit() is the general link level function for message sending + * @net: the applicable net namespace + * @list: chain of buffers containing message + * @dnode: address of destination node + * @selector: a number used for deterministic link selection + * Consumes the buffer chain, except when returning -ELINKCONG + * Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE + */ +int tipc_node_xmit(struct net *net, struct sk_buff_head *list, + u32 dnode, int selector) +{ + struct tipc_link *l = NULL; + struct tipc_node *n; + struct sk_buff_head xmitq; + struct tipc_media_addr *maddr; + int bearer_id; + int rc = -EHOSTUNREACH; + + __skb_queue_head_init(&xmitq); + n = tipc_node_find(net, dnode); + if (likely(n)) { + tipc_node_lock(n); + l = tipc_node_select_link(n, selector, &bearer_id, &maddr); + if (likely(l)) + rc = tipc_link_xmit(l, list, &xmitq); + if (unlikely(rc == -ENOBUFS)) + tipc_link_reset(l); + tipc_node_unlock(n); + tipc_node_put(n); + } + if (likely(!rc)) { + tipc_bearer_xmit(net, bearer_id, &xmitq, maddr); + return 0; + } + if (likely(in_own_node(net, dnode))) { + tipc_sk_rcv(net, list); + return 0; + } + return rc; +} + +/* tipc_node_xmit_skb(): send single buffer to destination + * Buffers sent via this functon are generally TIPC_SYSTEM_IMPORTANCE + * messages, which will not be rejected + * The only exception is datagram messages rerouted after secondary + * lookup, which are rare and safe to dispose of anyway. + * TODO: Return real return value, and let callers use + * tipc_wait_for_sendpkt() where applicable + */ +int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, + u32 selector) +{ + struct sk_buff_head head; + int rc; + + skb_queue_head_init(&head); + __skb_queue_tail(&head, skb); + rc = tipc_node_xmit(net, &head, dnode, selector); + if (rc == -ELINKCONG) + kfree_skb(skb); + return 0; +} + int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) { int err; diff --git a/net/tipc/node.h b/net/tipc/node.h index 74f278adada35..86b7c740cf849 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -160,6 +160,10 @@ bool tipc_node_is_up(struct tipc_node *n); int tipc_node_get_linkname(struct net *net, u32 bearer_id, u32 node, char *linkname, size_t len); void tipc_node_unlock(struct tipc_node *node); +int tipc_node_xmit(struct net *net, struct sk_buff_head *list, u32 dnode, + int selector); +int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest, + u32 selector); int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port); void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port); diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 87fef25f6519e..5b0b08d58fcc1 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -261,7 +261,7 @@ static void tsk_rej_rx_queue(struct sock *sk) while ((skb = __skb_dequeue(&sk->sk_receive_queue))) { if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_ERR_NO_PORT)) - tipc_link_xmit_skb(sock_net(sk), skb, dnode, 0); + tipc_node_xmit_skb(sock_net(sk), skb, dnode, 0); } } @@ -443,7 +443,7 @@ static int tipc_release(struct socket *sock) } if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, TIPC_ERR_NO_PORT)) - tipc_link_xmit_skb(net, skb, dnode, 0); + tipc_node_xmit_skb(net, skb, dnode, 0); } } @@ -456,7 +456,7 @@ static int tipc_release(struct socket *sock) tsk_own_node(tsk), tsk_peer_port(tsk), tsk->portid, TIPC_ERR_NO_PORT); if (skb) - tipc_link_xmit_skb(net, skb, dnode, tsk->portid); + tipc_node_xmit_skb(net, skb, dnode, tsk->portid); tipc_node_remove_conn(net, dnode, tsk->portid); } @@ -925,7 +925,7 @@ new_mtu: do { skb = skb_peek(pktchain); TIPC_SKB_CB(skb)->wakeup_pending = tsk->link_cong; - rc = tipc_link_xmit(net, pktchain, dnode, tsk->portid); + rc = tipc_node_xmit(net, pktchain, dnode, tsk->portid); if (likely(!rc)) { if (sock->state != SS_READY) sock->state = SS_CONNECTING; @@ -1045,7 +1045,7 @@ next: return rc; do { if (likely(!tsk_conn_cong(tsk))) { - rc = tipc_link_xmit(net, pktchain, dnode, portid); + rc = tipc_node_xmit(net, pktchain, dnode, portid); if (likely(!rc)) { tsk->sent_unacked++; sent += send; @@ -1224,7 +1224,7 @@ static void tipc_sk_send_ack(struct tipc_sock *tsk, uint ack) return; msg = buf_msg(skb); msg_set_msgcnt(msg, ack); - tipc_link_xmit_skb(net, skb, dnode, msg_link_selector(msg)); + tipc_node_xmit_skb(net, skb, dnode, msg_link_selector(msg)); } static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) @@ -1703,7 +1703,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) return 0; } if (!err || tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, -err)) - tipc_link_xmit_skb(net, skb, dnode, tsk->portid); + tipc_node_xmit_skb(net, skb, dnode, tsk->portid); return 0; } @@ -1799,7 +1799,7 @@ int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) if (!tipc_msg_reverse(tn->own_addr, skb, &dnode, -err)) continue; xmit: - tipc_link_xmit_skb(net, skb, dnode, dport); + tipc_node_xmit_skb(net, skb, dnode, dport); } return err ? -EHOSTUNREACH : 0; } @@ -2092,7 +2092,7 @@ restart: } if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, TIPC_CONN_SHUTDOWN)) - tipc_link_xmit_skb(net, skb, dnode, + tipc_node_xmit_skb(net, skb, dnode, tsk->portid); } else { dnode = tsk_peer_node(tsk); @@ -2102,7 +2102,7 @@ restart: 0, dnode, tsk_own_node(tsk), tsk_peer_port(tsk), tsk->portid, TIPC_CONN_SHUTDOWN); - tipc_link_xmit_skb(net, skb, dnode, tsk->portid); + tipc_node_xmit_skb(net, skb, dnode, tsk->portid); } tsk->connected = 0; sock->state = SS_DISCONNECTING; @@ -2164,7 +2164,7 @@ static void tipc_sk_timeout(unsigned long data) } bh_unlock_sock(sk); if (skb) - tipc_link_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid); + tipc_node_xmit_skb(sock_net(sk), skb, peer_node, tsk->portid); exit: sock_put(sk); } -- GitLab From d3504c3449fead545e5254bfb11da916f72c4734 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:25 -0400 Subject: [PATCH 1294/7006] tipc: clean up definitions and usage of link flags The status flag LINK_STOPPED is not needed any more, since the mechanism for delayed deletion of links has been removed. Likewise, LINK_STARTED and LINK_START_EVT are unnecessary, because we can just as well start the link timer directly from inside tipc_link_create(). We eliminate these flags in this commit. Instead of the above flags, we now introduce three new link modes, TIPC_LINK_OPEN, TIPC_LINK_BLOCKED and TIPC_LINK_TUNNEL. The values indicate whether, and in the case of TIPC_LINK_TUNNEL, which, messages the link is allowed to receive in this state. TIPC_LINK_BLOCKED also blocks timer-driven protocol messages to be sent out, and any change to the link FSM. Since the modes are mutually exclusive, we convert them to state values, and rename the 'flags' field in struct tipc_link to 'exec_mode'. Finally, we move the #defines for link FSM states and events from link.h into enums inside the file link.c, which is the real usage scope of these definitions. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 1 - net/tipc/link.c | 98 ++++++++++++++++++++++++++++-------------------- net/tipc/link.h | 44 ++++------------------ net/tipc/node.c | 2 +- 4 files changed, 67 insertions(+), 78 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 295bdc26f1037..aab4e8dd7b32d 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -924,7 +924,6 @@ int tipc_bclink_init(struct net *net) tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT); bcl->bearer_id = MAX_BEARERS; rcu_assign_pointer(tn->bearer_list[MAX_BEARERS], &bcbearer->bearer); - bcl->state = WORKING_WORKING; bcl->pmsg = (struct tipc_msg *)&bcl->proto_msg; msg_set_prevnode(bcl->pmsg, tn->own_addr); strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME); diff --git a/net/tipc/link.c b/net/tipc/link.c index c052437a7cfad..35a2da688db12 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -79,19 +79,49 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { /* * Out-of-range value for link session numbers */ -#define INVALID_SESSION 0x10000 +#define WILDCARD_SESSION 0x10000 -/* - * Link state events: +/* State value stored in 'failover_pkts' */ -#define STARTING_EVT 856384768 /* link processing trigger */ -#define TRAFFIC_MSG_EVT 560815u /* rx'd ??? */ -#define SILENCE_EVT 560817u /* timer dicovered silence from peer */ +#define FIRST_FAILOVER 0xffffu -/* - * State value stored in 'failover_pkts' +/* Link FSM states and events: */ -#define FIRST_FAILOVER 0xffffu +enum { + WORKING_WORKING, + WORKING_UNKNOWN, + RESET_RESET, + RESET_UNKNOWN +}; + +enum { + PEER_RESET_EVT = RESET_MSG, + ACTIVATE_EVT = ACTIVATE_MSG, + TRAFFIC_EVT, /* Any other valid msg from peer */ + SILENCE_EVT /* Peer was silent during last timer interval*/ +}; + +/* Link FSM state checking routines + */ +static int link_working_working(struct tipc_link *l) +{ + return l->state == WORKING_WORKING; +} + +static int link_working_unknown(struct tipc_link *l) +{ + return l->state == WORKING_UNKNOWN; +} + +static int link_reset_unknown(struct tipc_link *l) +{ + return l->state == RESET_UNKNOWN; +} + +static int link_reset_reset(struct tipc_link *l) +{ + return l->state == RESET_RESET; +} static void link_handle_out_of_seq_msg(struct tipc_link *link, struct sk_buff *skb); @@ -268,7 +298,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, /* note: peer i/f name is updated by reset/activate message */ memcpy(&l_ptr->media_addr, media_addr, sizeof(*media_addr)); l_ptr->owner = n_ptr; - l_ptr->peer_session = INVALID_SESSION; + l_ptr->peer_session = WILDCARD_SESSION; l_ptr->bearer_id = b_ptr->identity; link_set_supervision_props(l_ptr, b_ptr->tolerance); l_ptr->state = RESET_UNKNOWN; @@ -297,8 +327,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, link_reset_statistics(l_ptr); tipc_node_attach_link(n_ptr, l_ptr); setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr); - link_state_event(l_ptr, STARTING_EVT); - + link_set_timer(l_ptr, l_ptr->keepalive_intv); return l_ptr; } @@ -311,7 +340,6 @@ void tipc_link_delete(struct tipc_link *l) tipc_link_reset(l); if (del_timer(&l->timer)) tipc_link_put(l); - l->flags |= LINK_STOPPED; /* Delete link now, or when timer is finished: */ tipc_link_reset_fragments(l); tipc_node_detach_link(l->owner, l); @@ -438,7 +466,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); /* Link is down, accept any session */ - l_ptr->peer_session = INVALID_SESSION; + l_ptr->peer_session = WILDCARD_SESSION; /* Prepare for renewed mtu size negotiation */ l_ptr->mtu = l_ptr->advertised_mtu; @@ -452,7 +480,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) tipc_bearer_remove_dest(owner->net, l_ptr->bearer_id, l_ptr->addr); if (was_active_link && tipc_node_is_up(l_ptr->owner) && (pl != l_ptr)) { - l_ptr->flags |= LINK_FAILINGOVER; + l_ptr->exec_mode = TIPC_LINK_BLOCKED; l_ptr->failover_checkpt = l_ptr->rcv_nxt; pl->failover_pkts = FIRST_FAILOVER; pl->failover_checkpt = l_ptr->rcv_nxt; @@ -496,21 +524,14 @@ static void link_activate(struct tipc_link *link) static void link_state_event(struct tipc_link *l_ptr, unsigned int event) { struct tipc_link *other; - unsigned long timer_intv = l_ptr->keepalive_intv; - - if (l_ptr->flags & LINK_STOPPED) - return; - - if (!(l_ptr->flags & LINK_STARTED) && (event != STARTING_EVT)) - return; /* Not yet. */ - if (l_ptr->flags & LINK_FAILINGOVER) + if (l_ptr->exec_mode == TIPC_LINK_BLOCKED) return; switch (l_ptr->state) { case WORKING_WORKING: switch (event) { - case TRAFFIC_MSG_EVT: + case TRAFFIC_EVT: case ACTIVATE_MSG: l_ptr->silent_intv_cnt = 0; break; @@ -538,7 +559,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) break; case WORKING_UNKNOWN: switch (event) { - case TRAFFIC_MSG_EVT: + case TRAFFIC_EVT: case ACTIVATE_MSG: l_ptr->state = WORKING_WORKING; l_ptr->silent_intv_cnt = 0; @@ -576,7 +597,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) break; case RESET_UNKNOWN: switch (event) { - case TRAFFIC_MSG_EVT: + case TRAFFIC_EVT: break; case ACTIVATE_MSG: other = node_active_link(l_ptr->owner, 0); @@ -593,10 +614,6 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, 1, 0, 0, 0); break; - case STARTING_EVT: - l_ptr->flags |= LINK_STARTED; - link_set_timer(l_ptr, timer_intv); - break; case SILENCE_EVT: tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0); break; @@ -606,7 +623,7 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) break; case RESET_RESET: switch (event) { - case TRAFFIC_MSG_EVT: + case TRAFFIC_EVT: case ACTIVATE_MSG: other = node_active_link(l_ptr->owner, 0); if (other && link_working_unknown(other)) @@ -975,7 +992,7 @@ static bool link_synch(struct tipc_link *l) if (skb_queue_len(pl->inputq) > post_synch) return false; synched: - l->flags &= ~LINK_SYNCHING; + l->exec_mode = TIPC_LINK_OPEN; return true; } @@ -1091,7 +1108,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) } /* Traffic message. Conditionally activate link */ - link_state_event(l_ptr, TRAFFIC_MSG_EVT); + link_state_event(l_ptr, TRAFFIC_EVT); if (link_working_working(l_ptr)) { /* Re-insert buffer in front of queue */ @@ -1112,7 +1129,8 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) l_ptr->silent_intv_cnt = 0; /* Synchronize with parallel link if applicable */ - if (unlikely((l_ptr->flags & LINK_SYNCHING) && !msg_dup(msg))) { + if (unlikely((l_ptr->exec_mode == TIPC_LINK_TUNNEL) && + !msg_dup(msg))) { if (!link_synch(l_ptr)) goto unlock; } @@ -1193,7 +1211,7 @@ static void tipc_link_input(struct tipc_link *link, struct sk_buff *skb) switch (msg_user(msg)) { case TUNNEL_PROTOCOL: if (msg_dup(msg)) { - link->flags |= LINK_SYNCHING; + link->exec_mode = TIPC_LINK_TUNNEL; link->synch_point = msg_seqno(msg_get_wrapped(msg)); kfree_skb(skb); break; @@ -1315,7 +1333,7 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, u16 last_rcv; /* Don't send protocol message during link failover */ - if (l_ptr->flags & LINK_FAILINGOVER) + if (l_ptr->exec_mode == TIPC_LINK_BLOCKED) return; /* Abort non-RESET send if communication with node is prohibited */ @@ -1390,7 +1408,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, u32 msg_tol; struct tipc_msg *msg = buf_msg(buf); - if (l_ptr->flags & LINK_FAILINGOVER) + if (l_ptr->exec_mode == TIPC_LINK_BLOCKED) goto exit; if (l_ptr->net_plane != msg_net_plane(msg)) @@ -1401,7 +1419,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, case RESET_MSG: if (!link_working_unknown(l_ptr) && - (l_ptr->peer_session != INVALID_SESSION)) { + (l_ptr->peer_session != WILDCARD_SESSION)) { if (less_eq(msg_session(msg), l_ptr->peer_session)) break; /* duplicate or old reset: ignore */ } @@ -1465,7 +1483,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, /* Record reception; force mismatch at next timeout: */ l_ptr->silent_intv_cnt = 0; - link_state_event(l_ptr, TRAFFIC_MSG_EVT); + link_state_event(l_ptr, TRAFFIC_EVT); l_ptr->stats.recv_states++; if (link_reset_unknown(l_ptr)) break; @@ -1704,7 +1722,7 @@ static bool tipc_link_failover_rcv(struct tipc_link *link, } exit: if (!link->failover_pkts && pl) - pl->flags &= ~LINK_FAILINGOVER; + pl->exec_mode = TIPC_LINK_OPEN; kfree_skb(*skb); *skb = iskb; return *skb; diff --git a/net/tipc/link.h b/net/tipc/link.h index 7add2b90361d8..0509c6de03cd5 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -49,19 +49,14 @@ */ #define INVALID_LINK_SEQ 0x10000 -/* Link working states - */ -#define WORKING_WORKING 560810u -#define WORKING_UNKNOWN 560811u -#define RESET_UNKNOWN 560812u -#define RESET_RESET 560813u -/* Link endpoint execution states +/* Link endpoint receive states */ -#define LINK_STARTED 0x0001 -#define LINK_STOPPED 0x0002 -#define LINK_SYNCHING 0x0004 -#define LINK_FAILINGOVER 0x0008 +enum { + TIPC_LINK_OPEN, + TIPC_LINK_BLOCKED, + TIPC_LINK_TUNNEL +}; /* Starting value for maximum packet size negotiation on unicast links * (unless bearer MTU is less) @@ -106,7 +101,6 @@ struct tipc_stats { * @timer: link timer * @owner: pointer to peer node * @refcnt: reference counter for permanent references (owner node & timer) - * @flags: execution state flags for link endpoint instance * @peer_session: link session # being used by peer end of link * @peer_bearer_id: bearer id used by link's peer endpoint * @bearer_id: local bearer id used by link @@ -119,6 +113,7 @@ struct tipc_stats { * @pmsg: convenience pointer to "proto_msg" field * @priority: current link priority * @net_plane: current link network plane ('A' through 'H') + * @exec_mode: transmit/receive mode for link endpoint instance * @backlog_limit: backlog queue congestion thresholds (indexed by importance) * @exp_msg_count: # of tunnelled messages expected during link changeover * @reset_rcv_checkpt: seq # of last acknowledged message at time of link reset @@ -149,7 +144,6 @@ struct tipc_link { struct kref ref; /* Management and link supervision data */ - unsigned int flags; u32 peer_session; u32 peer_bearer_id; u32 bearer_id; @@ -165,6 +159,7 @@ struct tipc_link { struct tipc_msg *pmsg; u32 priority; char net_plane; + u8 exec_mode; u16 synch_point; /* Failover */ @@ -249,27 +244,4 @@ static inline u32 link_own_addr(struct tipc_link *l) return msg_prevnode(l->pmsg); } -/* - * Link status checking routines - */ -static inline int link_working_working(struct tipc_link *l_ptr) -{ - return l_ptr->state == WORKING_WORKING; -} - -static inline int link_working_unknown(struct tipc_link *l_ptr) -{ - return l_ptr->state == WORKING_UNKNOWN; -} - -static inline int link_reset_unknown(struct tipc_link *l_ptr) -{ - return l_ptr->state == RESET_UNKNOWN; -} - -static inline int link_reset_reset(struct tipc_link *l_ptr) -{ - return l_ptr->state == RESET_RESET; -} - #endif diff --git a/net/tipc/node.c b/net/tipc/node.c index ad759bb034e7d..b7a4457f653cd 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -403,7 +403,7 @@ static void node_lost_contact(struct tipc_node *n_ptr) struct tipc_link *l_ptr = n_ptr->links[i].link; if (!l_ptr) continue; - l_ptr->flags &= ~LINK_FAILINGOVER; + l_ptr->exec_mode = TIPC_LINK_OPEN; l_ptr->failover_checkpt = 0; l_ptr->failover_pkts = 0; kfree_skb(l_ptr->failover_skb); -- GitLab From 426cc2b86d1813959497d608dcb52c32df2d448a Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:26 -0400 Subject: [PATCH 1295/7006] tipc: introduce new link protocol msg create function As a preparation for later changes, we introduce a new function tipc_link_build_proto_msg(). Instead of actually sending the created protocol message, it only creates it and adds it to the head of a skb queue provided by the caller. Since we still need the existing function tipc_link_protocol_xmit() for a while, we redesign it to make use of the new function. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 144 ++++++++++++++++++++++++++---------------------- 1 file changed, 77 insertions(+), 67 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 35a2da688db12..657ba91fde413 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -129,6 +129,9 @@ static void tipc_link_proto_rcv(struct tipc_link *link, struct sk_buff *skb); static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol); static void link_state_event(struct tipc_link *l_ptr, u32 event); +static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, + u16 rcvgap, int tolerance, int priority, + struct sk_buff_head *xmitq); static void link_reset_statistics(struct tipc_link *l_ptr); static void link_print(struct tipc_link *l_ptr, const char *str); static void tipc_link_sync_xmit(struct tipc_link *l); @@ -1323,77 +1326,21 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, /* * Send protocol message to the other endpoint. */ -void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int probe_msg, +void tipc_link_proto_xmit(struct tipc_link *l, u32 msg_typ, int probe_msg, u32 gap, u32 tolerance, u32 priority) { - struct sk_buff *buf = NULL; - struct tipc_msg *msg = l_ptr->pmsg; - u32 msg_size = sizeof(l_ptr->proto_msg); - int r_flag; - u16 last_rcv; + struct sk_buff *skb = NULL; + struct sk_buff_head xmitq; - /* Don't send protocol message during link failover */ - if (l_ptr->exec_mode == TIPC_LINK_BLOCKED) - return; - - /* Abort non-RESET send if communication with node is prohibited */ - if ((tipc_node_blocked(l_ptr->owner)) && (msg_typ != RESET_MSG)) - return; - - /* Create protocol message with "out-of-sequence" sequence number */ - msg_set_type(msg, msg_typ); - msg_set_net_plane(msg, l_ptr->net_plane); - msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in); - msg_set_last_bcast(msg, tipc_bclink_get_last_sent(l_ptr->owner->net)); - - if (msg_typ == STATE_MSG) { - u16 next_sent = l_ptr->snd_nxt; - - if (!tipc_link_is_up(l_ptr)) - return; - msg_set_next_sent(msg, next_sent); - if (!skb_queue_empty(&l_ptr->deferdq)) { - last_rcv = buf_seqno(skb_peek(&l_ptr->deferdq)); - gap = mod(last_rcv - l_ptr->rcv_nxt); - } - msg_set_seq_gap(msg, gap); - if (gap) - l_ptr->stats.sent_nacks++; - msg_set_link_tolerance(msg, tolerance); - msg_set_linkprio(msg, priority); - msg_set_max_pkt(msg, l_ptr->mtu); - msg_set_ack(msg, mod(l_ptr->rcv_nxt - 1)); - msg_set_probe(msg, probe_msg != 0); - if (probe_msg) - l_ptr->stats.sent_probes++; - l_ptr->stats.sent_states++; - } else { /* RESET_MSG or ACTIVATE_MSG */ - msg_set_ack(msg, mod(l_ptr->failover_checkpt - 1)); - msg_set_seq_gap(msg, 0); - msg_set_next_sent(msg, 1); - msg_set_probe(msg, 0); - msg_set_link_tolerance(msg, l_ptr->tolerance); - msg_set_linkprio(msg, l_ptr->priority); - msg_set_max_pkt(msg, l_ptr->advertised_mtu); - } - - r_flag = (l_ptr->owner->working_links > tipc_link_is_up(l_ptr)); - msg_set_redundant_link(msg, r_flag); - msg_set_linkprio(msg, l_ptr->priority); - msg_set_size(msg, msg_size); - - msg_set_seqno(msg, mod(l_ptr->snd_nxt + (0xffff / 2))); - - buf = tipc_buf_acquire(msg_size); - if (!buf) + __skb_queue_head_init(&xmitq); + tipc_link_build_proto_msg(l, msg_typ, probe_msg, gap, + tolerance, priority, &xmitq); + skb = __skb_dequeue(&xmitq); + if (!skb) return; - - skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); - buf->priority = TC_PRIO_CONTROL; - tipc_bearer_send(l_ptr->owner->net, l_ptr->bearer_id, buf, - &l_ptr->media_addr); - l_ptr->rcv_unacked = 0; - kfree_skb(buf); + tipc_bearer_send(l->owner->net, l->bearer_id, skb, &l->media_addr); + l->rcv_unacked = 0; + kfree_skb(skb); } /* @@ -1514,6 +1461,69 @@ exit: kfree_skb(buf); } +/* tipc_link_build_proto_msg: prepare link protocol message for transmission + */ +static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, + u16 rcvgap, int tolerance, int priority, + struct sk_buff_head *xmitq) +{ + struct sk_buff *skb = NULL; + struct tipc_msg *hdr = l->pmsg; + u16 snd_nxt = l->snd_nxt; + u16 rcv_nxt = l->rcv_nxt; + u16 rcv_last = rcv_nxt - 1; + int node_up = l->owner->bclink.recv_permitted; + + /* Don't send protocol message during reset or link failover */ + if (l->exec_mode == TIPC_LINK_BLOCKED) + return; + + /* Abort non-RESET send if communication with node is prohibited */ + if ((tipc_node_blocked(l->owner)) && (mtyp != RESET_MSG)) + return; + + msg_set_type(hdr, mtyp); + msg_set_net_plane(hdr, l->net_plane); + msg_set_bcast_ack(hdr, l->owner->bclink.last_in); + msg_set_last_bcast(hdr, tipc_bclink_get_last_sent(l->owner->net)); + msg_set_link_tolerance(hdr, tolerance); + msg_set_linkprio(hdr, priority); + msg_set_redundant_link(hdr, node_up); + msg_set_seq_gap(hdr, 0); + + /* Compatibility: created msg must not be in sequence with pkt flow */ + msg_set_seqno(hdr, snd_nxt + U16_MAX / 2); + + if (mtyp == STATE_MSG) { + if (!tipc_link_is_up(l)) + return; + msg_set_next_sent(hdr, snd_nxt); + + /* Override rcvgap if there are packets in deferred queue */ + if (!skb_queue_empty(&l->deferdq)) + rcvgap = buf_seqno(skb_peek(&l->deferdq)) - rcv_nxt; + if (rcvgap) { + msg_set_seq_gap(hdr, rcvgap); + l->stats.sent_nacks++; + } + msg_set_ack(hdr, rcv_last); + msg_set_probe(hdr, probe); + if (probe) + l->stats.sent_probes++; + l->stats.sent_states++; + } else { + /* RESET_MSG or ACTIVATE_MSG */ + msg_set_max_pkt(hdr, l->advertised_mtu); + msg_set_ack(hdr, l->failover_checkpt - 1); + msg_set_next_sent(hdr, 1); + } + skb = tipc_buf_acquire(msg_size(hdr)); + if (!skb) + return; + skb_copy_to_linear_data(skb, hdr, msg_size(hdr)); + skb->priority = TC_PRIO_CONTROL; + __skb_queue_head(xmitq, skb); +} /* tipc_link_tunnel_xmit(): Tunnel one packet via a link belonging to * a different bearer. Owner node is locked. -- GitLab From 6ab30f9cbe134d19559f48dc748587d036529aaf Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:27 -0400 Subject: [PATCH 1296/7006] tipc: improve link FSM implementation The link FSM implementation is currently unnecessarily complex. It sometimes checks for conditional state outside the FSM data before deciding next state, and often performs actions directly inside the FSM logics. In this commit, we create a second, simpler FSM implementation, that as far as possible acts only on states and events that it is strictly defined for, and postpone any actions until it is finished with its decisions. It also returns an event flag field and an a buffer queue which may potentially contain a protocol message to be sent by the caller. Unfortunately, we cannot yet make the FSM "clean", in the sense that its decisions are only based on FSM state and event, and that state changes happen only here. That will have to wait until the activate/reset logics has been cleaned up in a future commit. We also rename the link states as follows: WORKING_WORKING -> TIPC_LINK_WORKING WORKING_UNKNOWN -> TIPC_LINK_PROBING RESET_UNKNOWN -> TIPC_LINK_RESETTING RESET_RESET -> TIPC_LINK_ESTABLISHING The existing FSM function, link_state_event(), is still needed for a while, so we redesign it to make use of the new function. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 344 ++++++++++++++++++++++++++---------------------- net/tipc/link.h | 7 + 2 files changed, 195 insertions(+), 156 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 657ba91fde413..5d2f9198c6bc1 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -88,10 +88,10 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { /* Link FSM states and events: */ enum { - WORKING_WORKING, - WORKING_UNKNOWN, - RESET_RESET, - RESET_UNKNOWN + TIPC_LINK_WORKING, + TIPC_LINK_PROBING, + TIPC_LINK_RESETTING, + TIPC_LINK_ESTABLISHING }; enum { @@ -103,24 +103,24 @@ enum { /* Link FSM state checking routines */ -static int link_working_working(struct tipc_link *l) +static int link_working(struct tipc_link *l) { - return l->state == WORKING_WORKING; + return l->state == TIPC_LINK_WORKING; } -static int link_working_unknown(struct tipc_link *l) +static int link_probing(struct tipc_link *l) { - return l->state == WORKING_UNKNOWN; + return l->state == TIPC_LINK_PROBING; } -static int link_reset_unknown(struct tipc_link *l) +static int link_resetting(struct tipc_link *l) { - return l->state == RESET_UNKNOWN; + return l->state == TIPC_LINK_RESETTING; } -static int link_reset_reset(struct tipc_link *l) +static int link_establishing(struct tipc_link *l) { - return l->state == RESET_RESET; + return l->state == TIPC_LINK_ESTABLISHING; } static void link_handle_out_of_seq_msg(struct tipc_link *link, @@ -140,6 +140,8 @@ static void tipc_link_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_link_failover_rcv(struct tipc_link *l, struct sk_buff **skb); static void link_set_timer(struct tipc_link *link, unsigned long time); +static void link_activate(struct tipc_link *link); + /* * Simple link routines */ @@ -179,7 +181,7 @@ int tipc_link_is_up(struct tipc_link *l_ptr) { if (!l_ptr) return 0; - return link_working_working(l_ptr) || link_working_unknown(l_ptr); + return link_working(l_ptr) || link_probing(l_ptr); } int tipc_link_is_active(struct tipc_link *l) @@ -234,8 +236,11 @@ static void link_timeout(unsigned long data) } /* do all other link processing performed on a periodic basis */ - if (l_ptr->silent_intv_cnt || tipc_bclink_acks_missing(l_ptr->owner)) + if (l_ptr->silent_intv_cnt) link_state_event(l_ptr, SILENCE_EVT); + else if (link_working(l_ptr) && tipc_bclink_acks_missing(l_ptr->owner)) + tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0); + l_ptr->silent_intv_cnt++; if (skb_queue_len(&l_ptr->backlogq)) tipc_link_push_packets(l_ptr); @@ -304,7 +309,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, l_ptr->peer_session = WILDCARD_SESSION; l_ptr->bearer_id = b_ptr->identity; link_set_supervision_props(l_ptr, b_ptr->tolerance); - l_ptr->state = RESET_UNKNOWN; + l_ptr->state = TIPC_LINK_RESETTING; l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg; msg = l_ptr->pmsg; @@ -366,6 +371,134 @@ void tipc_link_delete_list(struct net *net, unsigned int bearer_id) rcu_read_unlock(); } +/** + * tipc_link_fsm_evt - link finite state machine + * @l: pointer to link + * @evt: state machine event to be processed + * @xmitq: queue to prepend created protocol message, if any + */ +static int tipc_link_fsm_evt(struct tipc_link *l, int evt, + struct sk_buff_head *xmitq) +{ + int mtyp = 0, rc = 0; + struct tipc_link *pl; + enum { + LINK_RESET = 1, + LINK_ACTIVATE = (1 << 1), + SND_PROBE = (1 << 2), + SND_STATE = (1 << 3), + SND_RESET = (1 << 4), + SND_ACTIVATE = (1 << 5) + } actions = 0; + + if (l->exec_mode == TIPC_LINK_BLOCKED) + return rc; + + switch (l->state) { + case TIPC_LINK_WORKING: + switch (evt) { + case TRAFFIC_EVT: + case ACTIVATE_EVT: + break; + case SILENCE_EVT: + l->state = TIPC_LINK_PROBING; + actions |= SND_PROBE; + break; + case PEER_RESET_EVT: + actions |= LINK_RESET | SND_ACTIVATE; + break; + default: + pr_debug("%s%u WORKING\n", link_unk_evt, evt); + } + break; + case TIPC_LINK_PROBING: + switch (evt) { + case TRAFFIC_EVT: + case ACTIVATE_EVT: + l->state = TIPC_LINK_WORKING; + break; + case PEER_RESET_EVT: + actions |= LINK_RESET | SND_ACTIVATE; + break; + case SILENCE_EVT: + if (l->silent_intv_cnt <= l->abort_limit) { + actions |= SND_PROBE; + break; + } + actions |= LINK_RESET | SND_RESET; + break; + default: + pr_err("%s%u PROBING\n", link_unk_evt, evt); + } + break; + case TIPC_LINK_RESETTING: + switch (evt) { + case TRAFFIC_EVT: + break; + case ACTIVATE_EVT: + pl = node_active_link(l->owner, 0); + if (pl && link_probing(pl)) + break; + actions |= LINK_ACTIVATE; + if (l->owner->working_links == 1) + tipc_link_sync_xmit(l); + break; + case PEER_RESET_EVT: + l->state = TIPC_LINK_ESTABLISHING; + actions |= SND_ACTIVATE; + break; + case SILENCE_EVT: + actions |= SND_RESET; + break; + default: + pr_err("%s%u in RESETTING\n", link_unk_evt, evt); + } + break; + case TIPC_LINK_ESTABLISHING: + switch (evt) { + case TRAFFIC_EVT: + case ACTIVATE_EVT: + pl = node_active_link(l->owner, 0); + if (pl && link_probing(pl)) + break; + actions |= LINK_ACTIVATE; + if (l->owner->working_links == 1) + tipc_link_sync_xmit(l); + break; + case PEER_RESET_EVT: + break; + case SILENCE_EVT: + actions |= SND_ACTIVATE; + break; + default: + pr_err("%s%u ESTABLISHING\n", link_unk_evt, evt); + } + break; + default: + pr_err("Unknown link state %u/%u\n", l->state, evt); + } + + /* Perform actions as decided by FSM */ + if (actions & LINK_RESET) { + l->exec_mode = TIPC_LINK_BLOCKED; + rc |= TIPC_LINK_DOWN_EVT; + } + if (actions & LINK_ACTIVATE) { + l->exec_mode = TIPC_LINK_OPEN; + rc |= TIPC_LINK_UP_EVT; + } + if (actions & (SND_STATE | SND_PROBE)) + mtyp = STATE_MSG; + if (actions & SND_RESET) + mtyp = RESET_MSG; + if (actions & SND_ACTIVATE) + mtyp = ACTIVATE_MSG; + if (actions & (SND_PROBE | SND_STATE | SND_RESET | SND_ACTIVATE)) + tipc_link_build_proto_msg(l, mtyp, actions & SND_PROBE, + 0, 0, 0, xmitq); + return rc; +} + /** * link_schedule_user - schedule a message sender for wakeup after congestion * @link: congested link @@ -474,9 +607,10 @@ void tipc_link_reset(struct tipc_link *l_ptr) /* Prepare for renewed mtu size negotiation */ l_ptr->mtu = l_ptr->advertised_mtu; - l_ptr->state = RESET_UNKNOWN; + l_ptr->state = TIPC_LINK_RESETTING; - if ((prev_state == RESET_UNKNOWN) || (prev_state == RESET_RESET)) + if ((prev_state == TIPC_LINK_RESETTING) || + (prev_state == TIPC_LINK_ESTABLISHING)) return; tipc_node_link_down(l_ptr->owner, l_ptr->bearer_id); @@ -515,6 +649,8 @@ static void link_activate(struct tipc_link *link) link->rcv_nxt = 1; link->stats.recv_info = 1; link->silent_intv_cnt = 0; + link->state = TIPC_LINK_WORKING; + link->exec_mode = TIPC_LINK_OPEN; tipc_node_link_up(node, link->bearer_id); tipc_bearer_add_dest(node->net, link->bearer_id, link->addr); } @@ -524,132 +660,29 @@ static void link_activate(struct tipc_link *link) * @l_ptr: pointer to link * @event: state machine event to process */ -static void link_state_event(struct tipc_link *l_ptr, unsigned int event) +static void link_state_event(struct tipc_link *l, unsigned int evt) { - struct tipc_link *other; + int rc; + struct sk_buff_head xmitq; + struct sk_buff *skb; - if (l_ptr->exec_mode == TIPC_LINK_BLOCKED) + if (l->exec_mode == TIPC_LINK_BLOCKED) return; - switch (l_ptr->state) { - case WORKING_WORKING: - switch (event) { - case TRAFFIC_EVT: - case ACTIVATE_MSG: - l_ptr->silent_intv_cnt = 0; - break; - case SILENCE_EVT: - if (!l_ptr->silent_intv_cnt) { - if (tipc_bclink_acks_missing(l_ptr->owner)) - tipc_link_proto_xmit(l_ptr, STATE_MSG, - 0, 0, 0, 0); - break; - } - l_ptr->state = WORKING_UNKNOWN; - tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0); - break; - case RESET_MSG: - pr_debug("%s<%s>, requested by peer\n", - link_rst_msg, l_ptr->name); - tipc_link_reset(l_ptr); - l_ptr->state = RESET_RESET; - tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 0, 0, 0, 0); - break; - default: - pr_debug("%s%u in WW state\n", link_unk_evt, event); - } - break; - case WORKING_UNKNOWN: - switch (event) { - case TRAFFIC_EVT: - case ACTIVATE_MSG: - l_ptr->state = WORKING_WORKING; - l_ptr->silent_intv_cnt = 0; - break; - case RESET_MSG: - pr_debug("%s<%s>, requested by peer while probing\n", - link_rst_msg, l_ptr->name); - tipc_link_reset(l_ptr); - l_ptr->state = RESET_RESET; - tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 0, 0, 0, 0); - break; - case SILENCE_EVT: - if (!l_ptr->silent_intv_cnt) { - l_ptr->state = WORKING_WORKING; - if (tipc_bclink_acks_missing(l_ptr->owner)) - tipc_link_proto_xmit(l_ptr, STATE_MSG, - 0, 0, 0, 0); - } else if (l_ptr->silent_intv_cnt < - l_ptr->abort_limit) { - tipc_link_proto_xmit(l_ptr, STATE_MSG, - 1, 0, 0, 0); - } else { /* Link has failed */ - pr_debug("%s<%s>, peer not responding\n", - link_rst_msg, l_ptr->name); - tipc_link_reset(l_ptr); - l_ptr->state = RESET_UNKNOWN; - tipc_link_proto_xmit(l_ptr, RESET_MSG, - 0, 0, 0, 0); - } - break; - default: - pr_err("%s%u in WU state\n", link_unk_evt, event); - } - break; - case RESET_UNKNOWN: - switch (event) { - case TRAFFIC_EVT: - break; - case ACTIVATE_MSG: - other = node_active_link(l_ptr->owner, 0); - if (other && link_working_unknown(other)) - break; - l_ptr->state = WORKING_WORKING; - link_activate(l_ptr); - tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0); - if (l_ptr->owner->working_links == 1) - tipc_link_sync_xmit(l_ptr); - break; - case RESET_MSG: - l_ptr->state = RESET_RESET; - tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 1, 0, 0, 0); - break; - case SILENCE_EVT: - tipc_link_proto_xmit(l_ptr, RESET_MSG, 0, 0, 0, 0); - break; - default: - pr_err("%s%u in RU state\n", link_unk_evt, event); - } - break; - case RESET_RESET: - switch (event) { - case TRAFFIC_EVT: - case ACTIVATE_MSG: - other = node_active_link(l_ptr->owner, 0); - if (other && link_working_unknown(other)) - break; - l_ptr->state = WORKING_WORKING; - link_activate(l_ptr); - tipc_link_proto_xmit(l_ptr, STATE_MSG, 1, 0, 0, 0); - if (l_ptr->owner->working_links == 1) - tipc_link_sync_xmit(l_ptr); - break; - case RESET_MSG: - break; - case SILENCE_EVT: - tipc_link_proto_xmit(l_ptr, ACTIVATE_MSG, - 0, 0, 0, 0); - break; - default: - pr_err("%s%u in RR state\n", link_unk_evt, event); - } - break; - default: - pr_err("Unknown link state %u/%u\n", l_ptr->state, event); - } + __skb_queue_head_init(&xmitq); + + rc = tipc_link_fsm_evt(l, evt, &xmitq); + + if (rc & TIPC_LINK_UP_EVT) + link_activate(l); + + if (rc & TIPC_LINK_DOWN_EVT) + tipc_link_reset(l); + + skb = __skb_dequeue(&xmitq); + if (!skb) + return; + tipc_bearer_send(l->owner->net, l->bearer_id, skb, &l->media_addr); } /** @@ -1102,7 +1135,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) link_prepare_wakeup(l_ptr); /* Process the incoming packet */ - if (unlikely(!link_working_working(l_ptr))) { + if (unlikely(!link_working(l_ptr))) { if (msg_user(msg) == LINK_PROTOCOL) { tipc_link_proto_rcv(l_ptr, skb); link_retrieve_defq(l_ptr, &head); @@ -1113,7 +1146,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) /* Traffic message. Conditionally activate link */ link_state_event(l_ptr, TRAFFIC_EVT); - if (link_working_working(l_ptr)) { + if (link_working(l_ptr)) { /* Re-insert buffer in front of queue */ __skb_queue_head(&head, skb); skb = NULL; @@ -1122,7 +1155,7 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) goto unlock; } - /* Link is now in state WORKING_WORKING */ + /* Link is now in state TIPC_LINK_WORKING */ if (unlikely(seq_no != l_ptr->rcv_nxt)) { link_handle_out_of_seq_msg(l_ptr, skb); link_retrieve_defq(l_ptr, &head); @@ -1365,16 +1398,15 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, switch (msg_type(msg)) { case RESET_MSG: - if (!link_working_unknown(l_ptr) && + if (!link_probing(l_ptr) && (l_ptr->peer_session != WILDCARD_SESSION)) { if (less_eq(msg_session(msg), l_ptr->peer_session)) break; /* duplicate or old reset: ignore */ } - if (!msg_redundant_link(msg) && (link_working_working(l_ptr) || - link_working_unknown(l_ptr))) { - /* - * peer has lost contact -- don't allow peer's links + if (!msg_redundant_link(msg) && (link_working(l_ptr) || + link_probing(l_ptr))) { + /* peer has lost contact -- don't allow peer's links * to reactivate before we recognize loss & clean up */ l_ptr->owner->action_flags |= TIPC_WAIT_OWN_LINKS_DOWN; @@ -1432,7 +1464,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, link_state_event(l_ptr, TRAFFIC_EVT); l_ptr->stats.recv_states++; - if (link_reset_unknown(l_ptr)) + if (link_resetting(l_ptr)) break; if (less_eq(l_ptr->rcv_nxt, msg_next_sent(msg))) @@ -1822,14 +1854,14 @@ static void link_print(struct tipc_link *l_ptr, const char *str) pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name); rcu_read_unlock(); - if (link_working_unknown(l_ptr)) - pr_cont(":WU\n"); - else if (link_reset_reset(l_ptr)) - pr_cont(":RR\n"); - else if (link_reset_unknown(l_ptr)) - pr_cont(":RU\n"); - else if (link_working_working(l_ptr)) - pr_cont(":WW\n"); + if (link_probing(l_ptr)) + pr_cont(":P\n"); + else if (link_establishing(l_ptr)) + pr_cont(":E\n"); + else if (link_resetting(l_ptr)) + pr_cont(":R\n"); + else if (link_working(l_ptr)) + pr_cont(":W\n"); else pr_cont("\n"); } diff --git a/net/tipc/link.h b/net/tipc/link.h index 0509c6de03cd5..ef68424f492d0 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -58,6 +58,13 @@ enum { TIPC_LINK_TUNNEL }; +/* Events occurring at packet reception or at timeout + */ +enum { + TIPC_LINK_UP_EVT = 1, + TIPC_LINK_DOWN_EVT = (1 << 1) +}; + /* Starting value for maximum packet size negotiation on unicast links * (unless bearer MTU is less) */ -- GitLab From 333ef69ed2121f535e00ceb26e095d3745584c6e Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:28 -0400 Subject: [PATCH 1297/7006] tipc: simplify link timer implementation We create a second, simpler, link timer function, tipc_link_timeout(). The new function makes use of the new FSM function introduced in the previous commit, and just like it, takes a buffer queue as parameter. It returns an event bit field and potentially a link protocol packet to the caller. The existing timer function, link_timeout(), is still needed for a while, so we redesign it to become a wrapper around the new function. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 116 +++++++++++++++++++++++++++++------------------- net/tipc/link.h | 1 + 2 files changed, 72 insertions(+), 45 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 5d2f9198c6bc1..f58bb434d1c85 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -193,60 +193,30 @@ int tipc_link_is_active(struct tipc_link *l) /** * link_timeout - handle expiration of link timer - * @l_ptr: pointer to link */ static void link_timeout(unsigned long data) { - struct tipc_link *l_ptr = (struct tipc_link *)data; + struct tipc_link *l = (struct tipc_link *)data; + struct sk_buff_head xmitq; struct sk_buff *skb; + int rc; - tipc_node_lock(l_ptr->owner); + __skb_queue_head_init(&xmitq); - /* update counters used in statistical profiling of send traffic */ - l_ptr->stats.accu_queue_sz += skb_queue_len(&l_ptr->transmq); - l_ptr->stats.queue_sz_counts++; + tipc_node_lock(l->owner); - skb = skb_peek(&l_ptr->transmq); - if (skb) { - struct tipc_msg *msg = buf_msg(skb); - u32 length = msg_size(msg); - - if ((msg_user(msg) == MSG_FRAGMENTER) && - (msg_type(msg) == FIRST_FRAGMENT)) { - length = msg_size(msg_get_wrapped(msg)); - } - if (length) { - l_ptr->stats.msg_lengths_total += length; - l_ptr->stats.msg_length_counts++; - if (length <= 64) - l_ptr->stats.msg_length_profile[0]++; - else if (length <= 256) - l_ptr->stats.msg_length_profile[1]++; - else if (length <= 1024) - l_ptr->stats.msg_length_profile[2]++; - else if (length <= 4096) - l_ptr->stats.msg_length_profile[3]++; - else if (length <= 16384) - l_ptr->stats.msg_length_profile[4]++; - else if (length <= 32768) - l_ptr->stats.msg_length_profile[5]++; - else - l_ptr->stats.msg_length_profile[6]++; - } - } + rc = tipc_link_timeout(l, &xmitq); - /* do all other link processing performed on a periodic basis */ - if (l_ptr->silent_intv_cnt) - link_state_event(l_ptr, SILENCE_EVT); - else if (link_working(l_ptr) && tipc_bclink_acks_missing(l_ptr->owner)) - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0); + if (rc & TIPC_LINK_DOWN_EVT) + tipc_link_reset(l); - l_ptr->silent_intv_cnt++; - if (skb_queue_len(&l_ptr->backlogq)) - tipc_link_push_packets(l_ptr); - link_set_timer(l_ptr, l_ptr->keepalive_intv); - tipc_node_unlock(l_ptr->owner); - tipc_link_put(l_ptr); + skb = __skb_dequeue(&xmitq); + if (skb) + tipc_bearer_send(l->owner->net, l->bearer_id, + skb, &l->media_addr); + link_set_timer(l, l->keepalive_intv); + tipc_node_unlock(l->owner); + tipc_link_put(l); } static void link_set_timer(struct tipc_link *link, unsigned long time) @@ -499,6 +469,62 @@ static int tipc_link_fsm_evt(struct tipc_link *l, int evt, return rc; } +/* link_profile_stats - update statistical profiling of traffic + */ +static void link_profile_stats(struct tipc_link *l) +{ + struct sk_buff *skb; + struct tipc_msg *msg; + int length; + + /* Update counters used in statistical profiling of send traffic */ + l->stats.accu_queue_sz += skb_queue_len(&l->transmq); + l->stats.queue_sz_counts++; + + skb = skb_peek(&l->transmq); + if (!skb) + return; + msg = buf_msg(skb); + length = msg_size(msg); + + if (msg_user(msg) == MSG_FRAGMENTER) { + if (msg_type(msg) != FIRST_FRAGMENT) + return; + length = msg_size(msg_get_wrapped(msg)); + } + l->stats.msg_lengths_total += length; + l->stats.msg_length_counts++; + if (length <= 64) + l->stats.msg_length_profile[0]++; + else if (length <= 256) + l->stats.msg_length_profile[1]++; + else if (length <= 1024) + l->stats.msg_length_profile[2]++; + else if (length <= 4096) + l->stats.msg_length_profile[3]++; + else if (length <= 16384) + l->stats.msg_length_profile[4]++; + else if (length <= 32768) + l->stats.msg_length_profile[5]++; + else + l->stats.msg_length_profile[6]++; +} + +/* tipc_link_timeout - perform periodic task as instructed from node timeout + */ +int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq) +{ + int rc = 0; + + link_profile_stats(l); + if (l->silent_intv_cnt) + rc = tipc_link_fsm_evt(l, SILENCE_EVT, xmitq); + else if (link_working(l) && tipc_bclink_acks_missing(l->owner)) + tipc_link_build_proto_msg(l, STATE_MSG, 0, 0, 0, 0, xmitq); + l->silent_intv_cnt++; + return rc; +} + /** * link_schedule_user - schedule a message sender for wakeup after congestion * @link: congested link diff --git a/net/tipc/link.h b/net/tipc/link.h index ef68424f492d0..98507b0f008d4 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -245,6 +245,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info); int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info); int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]); void link_prepare_wakeup(struct tipc_link *l); +int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq); static inline u32 link_own_addr(struct tipc_link *l) { -- GitLab From 8a1577c96f122308ac9b5f195f9f9a7dd74ac541 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:29 -0400 Subject: [PATCH 1298/7006] tipc: move link supervision timer to node level In our effort to move control of the links to the link aggregation layer, we move the perodic link supervision timer to struct tipc_node. The new timer is shared between all links belonging to the node, thus saving resources, while still kicking the FSM on both its pertaining links at each expiration. The current link timer and corresponding functions are removed. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 78 +++---------------------------------------------- net/tipc/link.h | 2 -- net/tipc/node.c | 66 ++++++++++++++++++++++++++++++++++++++--- net/tipc/node.h | 2 ++ 4 files changed, 68 insertions(+), 80 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index f58bb434d1c85..5b4609bd0ddc1 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -127,7 +127,6 @@ static void link_handle_out_of_seq_msg(struct tipc_link *link, struct sk_buff *skb); static void tipc_link_proto_rcv(struct tipc_link *link, struct sk_buff *skb); -static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol); static void link_state_event(struct tipc_link *l_ptr, u32 event); static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, u16 rcvgap, int tolerance, int priority, @@ -139,7 +138,6 @@ static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); static void tipc_link_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_link_failover_rcv(struct tipc_link *l, struct sk_buff **skb); -static void link_set_timer(struct tipc_link *link, unsigned long time); static void link_activate(struct tipc_link *link); /* @@ -150,21 +148,6 @@ static unsigned int align(unsigned int i) return (i + 3) & ~3u; } -static void tipc_link_release(struct kref *kref) -{ - kfree(container_of(kref, struct tipc_link, ref)); -} - -static void tipc_link_get(struct tipc_link *l_ptr) -{ - kref_get(&l_ptr->ref); -} - -static void tipc_link_put(struct tipc_link *l_ptr) -{ - kref_put(&l_ptr->ref, tipc_link_release); -} - static struct tipc_link *tipc_parallel_link(struct tipc_link *l) { struct tipc_node *n = l->owner; @@ -191,40 +174,6 @@ int tipc_link_is_active(struct tipc_link *l) return (node_active_link(n, 0) == l) || (node_active_link(n, 1) == l); } -/** - * link_timeout - handle expiration of link timer - */ -static void link_timeout(unsigned long data) -{ - struct tipc_link *l = (struct tipc_link *)data; - struct sk_buff_head xmitq; - struct sk_buff *skb; - int rc; - - __skb_queue_head_init(&xmitq); - - tipc_node_lock(l->owner); - - rc = tipc_link_timeout(l, &xmitq); - - if (rc & TIPC_LINK_DOWN_EVT) - tipc_link_reset(l); - - skb = __skb_dequeue(&xmitq); - if (skb) - tipc_bearer_send(l->owner->net, l->bearer_id, - skb, &l->media_addr); - link_set_timer(l, l->keepalive_intv); - tipc_node_unlock(l->owner); - tipc_link_put(l); -} - -static void link_set_timer(struct tipc_link *link, unsigned long time) -{ - if (!mod_timer(&link->timer, jiffies + time)) - tipc_link_get(link); -} - /** * tipc_link_create - create a new link * @n_ptr: pointer to associated node @@ -265,7 +214,6 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, pr_warn("Link creation failed, no memory\n"); return NULL; } - kref_init(&l_ptr->ref); l_ptr->addr = peer; if_name = strchr(b_ptr->name, ':') + 1; sprintf(l_ptr->name, "%u.%u.%u:%s-%u.%u.%u:unknown", @@ -278,7 +226,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, l_ptr->owner = n_ptr; l_ptr->peer_session = WILDCARD_SESSION; l_ptr->bearer_id = b_ptr->identity; - link_set_supervision_props(l_ptr, b_ptr->tolerance); + l_ptr->tolerance = b_ptr->tolerance; l_ptr->state = TIPC_LINK_RESETTING; l_ptr->pmsg = (struct tipc_msg *)&l_ptr->proto_msg; @@ -304,8 +252,6 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, skb_queue_head_init(l_ptr->inputq); link_reset_statistics(l_ptr); tipc_node_attach_link(n_ptr, l_ptr); - setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr); - link_set_timer(l_ptr, l_ptr->keepalive_intv); return l_ptr; } @@ -316,12 +262,8 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, void tipc_link_delete(struct tipc_link *l) { tipc_link_reset(l); - if (del_timer(&l->timer)) - tipc_link_put(l); - /* Delete link now, or when timer is finished: */ tipc_link_reset_fragments(l); tipc_node_detach_link(l->owner, l); - tipc_link_put(l); } void tipc_link_delete_list(struct net *net, unsigned int bearer_id) @@ -1447,7 +1389,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, msg_tol = msg_link_tolerance(msg); if (msg_tol > l_ptr->tolerance) - link_set_supervision_props(l_ptr, msg_tol); + l_ptr->tolerance = msg_tol; if (msg_linkprio(msg) > l_ptr->priority) l_ptr->priority = msg_linkprio(msg); @@ -1473,7 +1415,7 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, msg_tol = msg_link_tolerance(msg); if (msg_tol) - link_set_supervision_props(l_ptr, msg_tol); + l_ptr->tolerance = msg_tol; if (msg_linkprio(msg) && (msg_linkprio(msg) != l_ptr->priority)) { @@ -1796,18 +1738,6 @@ exit: return *skb; } -static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tol) -{ - unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; - - if ((tol < TIPC_MIN_LINK_TOL) || (tol > TIPC_MAX_LINK_TOL)) - return; - - l_ptr->tolerance = tol; - l_ptr->keepalive_intv = msecs_to_jiffies(intv); - l_ptr->abort_limit = tol / (jiffies_to_msecs(l_ptr->keepalive_intv)); -} - void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) { int max_bulk = TIPC_MAX_PUBLICATIONS / (l->mtu / ITEM_SIZE); @@ -1984,7 +1914,7 @@ int tipc_nl_link_set(struct sk_buff *skb, struct genl_info *info) u32 tol; tol = nla_get_u32(props[TIPC_NLA_PROP_TOL]); - link_set_supervision_props(link, tol); + link->tolerance = tol; tipc_link_proto_xmit(link, STATE_MSG, 0, 0, tol, 0); } if (props[TIPC_NLA_PROP_PRIO]) { diff --git a/net/tipc/link.h b/net/tipc/link.h index 98507b0f008d4..0cf7d2b11803c 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -146,9 +146,7 @@ struct tipc_link { u32 addr; char name[TIPC_MAX_LINK_NAME]; struct tipc_media_addr media_addr; - struct timer_list timer; struct tipc_node *owner; - struct kref ref; /* Management and link supervision data */ u32 peer_session; diff --git a/net/tipc/node.c b/net/tipc/node.c index b7a4457f653cd..77effb233725d 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -44,6 +44,7 @@ static void node_lost_contact(struct tipc_node *n_ptr); static void node_established_contact(struct tipc_node *n_ptr); static void tipc_node_delete(struct tipc_node *node); +static void tipc_node_timeout(unsigned long data); struct tipc_sock_conn { u32 port; @@ -145,11 +146,27 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) n_ptr->active_links[0] = INVALID_BEARER_ID; n_ptr->active_links[1] = INVALID_BEARER_ID; tipc_node_get(n_ptr); + setup_timer(&n_ptr->timer, tipc_node_timeout, (unsigned long)n_ptr); + n_ptr->keepalive_intv = U32_MAX; exit: spin_unlock_bh(&tn->node_list_lock); return n_ptr; } +static void tipc_node_calculate_timer(struct tipc_node *n, struct tipc_link *l) +{ + unsigned long tol = l->tolerance; + unsigned long intv = ((tol / 4) > 500) ? 500 : tol / 4; + unsigned long keepalive_intv = msecs_to_jiffies(intv); + + /* Link with lowest tolerance determines timer interval */ + if (keepalive_intv < n->keepalive_intv) + n->keepalive_intv = keepalive_intv; + + /* Ensure link's abort limit corresponds to current interval */ + l->abort_limit = l->tolerance / jiffies_to_msecs(n->keepalive_intv); +} + static void tipc_node_delete(struct tipc_node *node) { list_del_rcu(&node->list); @@ -163,8 +180,11 @@ void tipc_node_stop(struct net *net) struct tipc_node *node, *t_node; spin_lock_bh(&tn->node_list_lock); - list_for_each_entry_safe(node, t_node, &tn->node_list, list) + list_for_each_entry_safe(node, t_node, &tn->node_list, list) { + if (del_timer(&node->timer)) + tipc_node_put(node); tipc_node_put(node); + } spin_unlock_bh(&tn->node_list_lock); } @@ -222,6 +242,38 @@ void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port) tipc_node_put(node); } +/* tipc_node_timeout - handle expiration of node timer + */ +static void tipc_node_timeout(unsigned long data) +{ + struct tipc_node *n = (struct tipc_node *)data; + struct sk_buff_head xmitq; + struct tipc_link *l; + struct tipc_media_addr *maddr; + int bearer_id; + int rc = 0; + + __skb_queue_head_init(&xmitq); + + for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { + tipc_node_lock(n); + l = n->links[bearer_id].link; + if (l) { + /* Link tolerance may change asynchronously: */ + tipc_node_calculate_timer(n, l); + rc = tipc_link_timeout(l, &xmitq); + if (rc & TIPC_LINK_DOWN_EVT) + tipc_link_reset(l); + } + tipc_node_unlock(n); + maddr = &n->links[bearer_id].maddr; + tipc_bearer_xmit(n->net, bearer_id, &xmitq, maddr); + } + if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) + tipc_node_get(n); + tipc_node_put(n); +} + /** * tipc_node_link_up - handle addition of link * @@ -335,10 +387,16 @@ bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b, struct tipc_media_addr *curr = &n->links[b->identity].maddr; struct sk_buff_head *inputq = &n->links[b->identity].inputq; - if (!l) + if (!l) { l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq); - if (!l) - return false; + if (!l) + return false; + tipc_node_calculate_timer(n, l); + if (n->link_cnt == 1) { + if (!mod_timer(&n->timer, jiffies + n->keepalive_intv)) + tipc_node_get(n); + } + } memcpy(&l->media_addr, maddr, sizeof(*maddr)); memcpy(curr, maddr, sizeof(*maddr)); tipc_link_reset(l); diff --git a/net/tipc/node.h b/net/tipc/node.h index 86b7c740cf849..2d56344962e77 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -140,6 +140,8 @@ struct tipc_node { u32 link_id; struct list_head publ_list; struct list_head conn_sks; + unsigned long keepalive_intv; + struct timer_list timer; struct rcu_head rcu; }; -- GitLab From 1a20cc254e60e79929ef7edb5cf784df86b46e42 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:30 -0400 Subject: [PATCH 1299/7006] tipc: introduce node contact FSM The logics for determining when a node is permitted to establish and maintain contact with its peer node becomes non-trivial in the presence of multiple parallel links that may come and go independently. A known failure scenario is that one endpoint registers both its links to the peer lost, cleans up it binding table, and prepares for a table update once contact is re-establihed, while the other endpoint may see its links reset and re-established one by one, hence seeing no need to re-synchronize the binding table. To avoid this, a node must not allow re-establishing contact until it has confirmation that even the peer has lost both links. Currently, the mechanism for handling this consists of setting and resetting two state flags from different locations in the code. This solution is hard to understand and maintain. A closer analysis even reveals that it is not completely safe. In this commit we do instead introduce an FSM that keeps track of the conditions for when the node can establish and maintain links. It has six states and four events, and is strictly based on explicit knowledge about the own node's and the peer node's contact states. Only events leading to state change are shown as edges in the figure below. +--------------+ | SELF_UP/ | +---------------->| PEER_COMING |-----------------+ SELF_ | +--------------+ |PEER_ ESTBL_ | | |ESTBL_ CONTACT| SELF_LOST_CONTACT | |CONTACT | v | | +--------------+ | | PEER_ | SELF_DOWN/ | SELF_ | | LOST_ +--| PEER_LEAVING |<--+ LOST_ v +-------------+ CONTACT | +--------------+ | CONTACT +-----------+ | SELF_DOWN/ |<----------+ +----------| SELF_UP/ | | PEER_DOWN |<----------+ +----------| PEER_UP | +-------------+ SELF_ | +--------------+ | PEER_ +-----------+ | LOST_ +--| SELF_LEAVING/|<--+ LOST_ A | CONTACT | PEER_DOWN | CONTACT | | +--------------+ | | A | PEER_ | PEER_LOST_CONTACT | |SELF_ ESTBL_ | | |ESTBL_ CONTACT| +--------------+ |CONTACT +---------------->| PEER_UP/ |-----------------+ | SELF_COMING | +--------------+ Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 74 ++++++++++++--------------- net/tipc/msg.h | 7 +++ net/tipc/node.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++-- net/tipc/node.h | 28 ++++++++--- 4 files changed, 185 insertions(+), 54 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 5b4609bd0ddc1..eaccf4552d15c 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -911,9 +911,13 @@ static void link_retransmit_failure(struct tipc_link *l_ptr, if (l_ptr->addr) { /* Handle failure on standard link */ - link_print(l_ptr, "Resetting link\n"); + link_print(l_ptr, "Resetting link "); + pr_info("Failed msg: usr %u, typ %u, len %u, err %u\n", + msg_user(msg), msg_type(msg), msg_size(msg), + msg_errcode(msg)); + pr_info("sqno %u, prev: %x, src: %x\n", + msg_seqno(msg), msg_prevnode(msg), msg_orignode(msg)); tipc_link_reset(l_ptr); - } else { /* Handle failure on broadcast link */ struct tipc_node *n_ptr; @@ -1067,15 +1071,8 @@ void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) if (unlikely(!l_ptr)) goto unlock; - /* Verify that communication with node is currently allowed */ - if ((n_ptr->action_flags & TIPC_WAIT_PEER_LINKS_DOWN) && - msg_user(msg) == LINK_PROTOCOL && - (msg_type(msg) == RESET_MSG || - msg_type(msg) == ACTIVATE_MSG) && - !msg_redundant_link(msg)) - n_ptr->action_flags &= ~TIPC_WAIT_PEER_LINKS_DOWN; - - if (tipc_node_blocked(n_ptr)) + /* Is reception of this pkt permitted at the moment ? */ + if (!tipc_node_filter_skb(n_ptr, msg)) goto unlock; /* Validate message sequence number info */ @@ -1371,15 +1368,6 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, if (less_eq(msg_session(msg), l_ptr->peer_session)) break; /* duplicate or old reset: ignore */ } - - if (!msg_redundant_link(msg) && (link_working(l_ptr) || - link_probing(l_ptr))) { - /* peer has lost contact -- don't allow peer's links - * to reactivate before we recognize loss & clean up - */ - l_ptr->owner->action_flags |= TIPC_WAIT_OWN_LINKS_DOWN; - } - link_state_event(l_ptr, RESET_MSG); /* fall thru' */ @@ -1408,6 +1396,8 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, l_ptr->peer_session = msg_session(msg); l_ptr->peer_bearer_id = msg_bearer_id(msg); + if (!msg_peer_is_up(msg)) + tipc_node_fsm_evt(l_ptr->owner, PEER_LOST_CONTACT_EVT); if (msg_type(msg) == ACTIVATE_MSG) link_state_event(l_ptr, ACTIVATE_MSG); break; @@ -1419,11 +1409,11 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, if (msg_linkprio(msg) && (msg_linkprio(msg) != l_ptr->priority)) { - pr_debug("%s<%s>, priority change %u->%u\n", - link_rst_msg, l_ptr->name, - l_ptr->priority, msg_linkprio(msg)); + pr_info("%s<%s>, priority change %u->%u\n", + link_rst_msg, l_ptr->name, + l_ptr->priority, msg_linkprio(msg)); l_ptr->priority = msg_linkprio(msg); - tipc_link_reset(l_ptr); /* Enforce change to take effect */ + tipc_link_reset(l_ptr); break; } @@ -1446,15 +1436,18 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, tipc_bclink_update_link_state(l_ptr->owner, msg_last_bcast(msg)); - if (rec_gap || (msg_probe(msg))) { + if (rec_gap || (msg_probe(msg))) tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, rec_gap, 0, 0); - } + if (msg_seq_gap(msg)) { l_ptr->stats.recv_nacks++; tipc_link_retransmit(l_ptr, skb_peek(&l_ptr->transmq), msg_seq_gap(msg)); } + if (tipc_link_is_up(l_ptr)) + tipc_node_fsm_evt(l_ptr->owner, + PEER_ESTABL_CONTACT_EVT); break; } exit: @@ -1478,10 +1471,6 @@ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, if (l->exec_mode == TIPC_LINK_BLOCKED) return; - /* Abort non-RESET send if communication with node is prohibited */ - if ((tipc_node_blocked(l->owner)) && (mtyp != RESET_MSG)) - return; - msg_set_type(hdr, mtyp); msg_set_net_plane(hdr, l->net_plane); msg_set_bcast_ack(hdr, l->owner->bclink.last_in); @@ -1799,27 +1788,28 @@ static void link_reset_statistics(struct tipc_link *l_ptr) l_ptr->stats.recv_info = l_ptr->rcv_nxt; } -static void link_print(struct tipc_link *l_ptr, const char *str) +static void link_print(struct tipc_link *l, const char *str) { - struct tipc_net *tn = net_generic(l_ptr->owner->net, tipc_net_id); - struct tipc_bearer *b_ptr; + struct sk_buff *hskb = skb_peek(&l->transmq); + u16 head = hskb ? msg_seqno(buf_msg(hskb)) : l->snd_nxt; + u16 tail = l->snd_nxt - 1; - rcu_read_lock(); - b_ptr = rcu_dereference_rtnl(tn->bearer_list[l_ptr->bearer_id]); - if (b_ptr) - pr_info("%s Link %x<%s>:", str, l_ptr->addr, b_ptr->name); - rcu_read_unlock(); + pr_info("%s Link <%s>:", str, l->name); - if (link_probing(l_ptr)) + if (link_probing(l)) pr_cont(":P\n"); - else if (link_establishing(l_ptr)) + else if (link_establishing(l)) pr_cont(":E\n"); - else if (link_resetting(l_ptr)) + else if (link_resetting(l)) pr_cont(":R\n"); - else if (link_working(l_ptr)) + else if (link_working(l)) pr_cont(":W\n"); else pr_cont("\n"); + + pr_info("XMTQ: %u [%u-%u], BKLGQ: %u, SNDNX: %u, RCVNX: %u\n", + skb_queue_len(&l->transmq), head, tail, + skb_queue_len(&l->backlogq), l->snd_nxt, l->rcv_nxt); } /* Parse and validate nested (link) properties valid for media, bearer and link diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 19c45fb662388..4dc66d9f69cc4 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -766,6 +766,13 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) msg_set_bits(m, 9, 0, 0xffff, n); } +static inline bool msg_peer_is_up(struct tipc_msg *m) +{ + if (likely(msg_user(m) != LINK_PROTOCOL) || (msg_type(m) == STATE_MSG)) + return true; + return msg_redundant_link(m); +} + struct sk_buff *tipc_buf_acquire(u32 size); bool tipc_msg_validate(struct sk_buff *skb); bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode, diff --git a/net/tipc/node.c b/net/tipc/node.c index 77effb233725d..9dbbb5de287b4 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -141,7 +141,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) break; } list_add_tail_rcu(&n_ptr->list, &temp_node->list); - n_ptr->action_flags = TIPC_WAIT_PEER_LINKS_DOWN; + n_ptr->state = SELF_DOWN_PEER_DOWN; n_ptr->signature = INVALID_NODE_SIG; n_ptr->active_links[0] = INVALID_BEARER_ID; n_ptr->active_links[1] = INVALID_BEARER_ID; @@ -421,8 +421,131 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) } } +/* tipc_node_fsm_evt - node finite state machine + * Determines when contact is allowed with peer node + */ +void tipc_node_fsm_evt(struct tipc_node *n, int evt) +{ + int state = n->state; + + switch (state) { + case SELF_DOWN_PEER_DOWN: + switch (evt) { + case SELF_ESTABL_CONTACT_EVT: + state = SELF_UP_PEER_COMING; + break; + case PEER_ESTABL_CONTACT_EVT: + state = SELF_COMING_PEER_UP; + break; + case SELF_LOST_CONTACT_EVT: + case PEER_LOST_CONTACT_EVT: + break; + default: + pr_err("Unknown node fsm evt %x/%x\n", state, evt); + } + break; + case SELF_UP_PEER_UP: + switch (evt) { + case SELF_LOST_CONTACT_EVT: + state = SELF_DOWN_PEER_LEAVING; + break; + case PEER_LOST_CONTACT_EVT: + state = SELF_LEAVING_PEER_DOWN; + break; + case SELF_ESTABL_CONTACT_EVT: + case PEER_ESTABL_CONTACT_EVT: + break; + default: + pr_err("Unknown node fsm evt %x/%x\n", state, evt); + } + break; + case SELF_DOWN_PEER_LEAVING: + switch (evt) { + case PEER_LOST_CONTACT_EVT: + state = SELF_DOWN_PEER_DOWN; + break; + case SELF_ESTABL_CONTACT_EVT: + case PEER_ESTABL_CONTACT_EVT: + case SELF_LOST_CONTACT_EVT: + break; + default: + pr_err("Unknown node fsm evt %x/%x\n", state, evt); + } + break; + case SELF_UP_PEER_COMING: + switch (evt) { + case PEER_ESTABL_CONTACT_EVT: + state = SELF_UP_PEER_UP; + break; + case SELF_LOST_CONTACT_EVT: + state = SELF_DOWN_PEER_LEAVING; + break; + case SELF_ESTABL_CONTACT_EVT: + case PEER_LOST_CONTACT_EVT: + break; + default: + pr_err("Unknown node fsm evt %x/%x\n", state, evt); + } + break; + case SELF_COMING_PEER_UP: + switch (evt) { + case SELF_ESTABL_CONTACT_EVT: + state = SELF_UP_PEER_UP; + break; + case PEER_LOST_CONTACT_EVT: + state = SELF_LEAVING_PEER_DOWN; + break; + case SELF_LOST_CONTACT_EVT: + case PEER_ESTABL_CONTACT_EVT: + break; + default: + pr_err("Unknown node fsm evt %x/%x\n", state, evt); + } + break; + case SELF_LEAVING_PEER_DOWN: + switch (evt) { + case SELF_LOST_CONTACT_EVT: + state = SELF_DOWN_PEER_DOWN; + break; + case SELF_ESTABL_CONTACT_EVT: + case PEER_ESTABL_CONTACT_EVT: + case PEER_LOST_CONTACT_EVT: + break; + default: + pr_err("Unknown node fsm evt %x/%x\n", state, evt); + } + break; + default: + pr_err("Unknown node fsm state %x\n", state); + break; + } + + n->state = state; +} + +bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_msg *hdr) +{ + int state = n->state; + + if (likely(state == SELF_UP_PEER_UP)) + return true; + if (state == SELF_DOWN_PEER_DOWN) + return true; + if (state == SELF_UP_PEER_COMING) + return true; + if (state == SELF_COMING_PEER_UP) + return true; + if (state == SELF_LEAVING_PEER_DOWN) + return false; + if (state == SELF_DOWN_PEER_LEAVING) + if (!msg_peer_is_up(hdr)) + return true; + return false; +} + static void node_established_contact(struct tipc_node *n_ptr) { + tipc_node_fsm_evt(n_ptr, SELF_ESTABL_CONTACT_EVT); n_ptr->action_flags |= TIPC_NOTIFY_NODE_UP; n_ptr->bclink.oos_state = 0; n_ptr->bclink.acked = tipc_bclink_get_last_sent(n_ptr->net); @@ -468,11 +591,8 @@ static void node_lost_contact(struct tipc_node *n_ptr) l_ptr->failover_skb = NULL; tipc_link_reset_fragments(l_ptr); } - - n_ptr->action_flags &= ~TIPC_WAIT_OWN_LINKS_DOWN; - /* Prevent re-contact with node until cleanup is done */ - n_ptr->action_flags |= TIPC_WAIT_PEER_LINKS_DOWN; + tipc_node_fsm_evt(n_ptr, SELF_LOST_CONTACT_EVT); /* Notify publications from this node */ n_ptr->action_flags |= TIPC_NOTIFY_NODE_DOWN; diff --git a/net/tipc/node.h b/net/tipc/node.h index 2d56344962e77..270256e09ee5d 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -47,6 +47,24 @@ #define INVALID_BEARER_ID -1 +/* Node FSM states and events: + */ +enum { + SELF_DOWN_PEER_DOWN = 0xdd, + SELF_UP_PEER_UP = 0xaa, + SELF_DOWN_PEER_LEAVING = 0xd1, + SELF_UP_PEER_COMING = 0xac, + SELF_COMING_PEER_UP = 0xca, + SELF_LEAVING_PEER_DOWN = 0x1d, +}; + +enum { + SELF_ESTABL_CONTACT_EVT = 0xec, + SELF_LOST_CONTACT_EVT = 0x1c, + PEER_ESTABL_CONTACT_EVT = 0xfec, + PEER_LOST_CONTACT_EVT = 0xf1c +}; + /* Flags used to take different actions according to flag type * TIPC_WAIT_PEER_LINKS_DOWN: wait to see that peer's links are down * TIPC_WAIT_OWN_LINKS_DOWN: wait until peer node is declared down @@ -56,8 +74,6 @@ */ enum { TIPC_MSG_EVT = 1, - TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1), - TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2), TIPC_NOTIFY_NODE_DOWN = (1 << 3), TIPC_NOTIFY_NODE_UP = (1 << 4), TIPC_WAKEUP_BCAST_USERS = (1 << 5), @@ -133,6 +149,7 @@ struct tipc_node { int action_flags; struct tipc_node_bclink bclink; struct list_head list; + int state; int link_cnt; u16 working_links; u16 capabilities; @@ -176,11 +193,8 @@ static inline void tipc_node_lock(struct tipc_node *node) spin_lock_bh(&node->lock); } -static inline bool tipc_node_blocked(struct tipc_node *node) -{ - return (node->action_flags & (TIPC_WAIT_PEER_LINKS_DOWN | - TIPC_NOTIFY_NODE_DOWN | TIPC_WAIT_OWN_LINKS_DOWN)); -} +void tipc_node_fsm_evt(struct tipc_node *n, int evt); +bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_msg *hdr); static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel) { -- GitLab From d999297c3dbbe7fdd832f7fa4ec84301e170b3e6 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 16 Jul 2015 16:54:31 -0400 Subject: [PATCH 1300/7006] tipc: reduce locking scope during packet reception We convert packet/message reception according to the same principle we have been using for message sending and timeout handling: We move the function tipc_rcv() to node.c, hence handling the initial packet reception at the link aggregation level. The function grabs the node lock, selects the receiving link, and accesses it via a new call tipc_link_rcv(). This function appends buffers to the input queue for delivery upwards, but it may also append outgoing packets to the xmit queue, just as we do during regular message sending. The latter will happen when buffers are forwarded from the link backlog, or when retransmission is requested. Upon return of this function, and after having released the node lock, tipc_rcv() delivers/tranmsits the contents of those queues, but it may also perform actions such as link activation or reset, as indicated by the return flags from the link. This reduces the number of cpu cycles spent inside the node spinlock, and reduces contention on that lock. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/bcast.c | 23 ++ net/tipc/bcast.h | 1 + net/tipc/core.h | 5 + net/tipc/link.c | 673 +++++++++++++++++++++-------------------------- net/tipc/link.h | 6 +- net/tipc/msg.h | 50 +++- net/tipc/node.c | 105 +++++++- net/tipc/node.h | 4 - 8 files changed, 478 insertions(+), 389 deletions(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index aab4e8dd7b32d..8b010c976b2f7 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -316,6 +316,29 @@ void tipc_bclink_update_link_state(struct tipc_node *n_ptr, } } +void tipc_bclink_sync_state(struct tipc_node *n, struct tipc_msg *hdr) +{ + u16 last = msg_last_bcast(hdr); + int mtyp = msg_type(hdr); + + if (unlikely(msg_user(hdr) != LINK_PROTOCOL)) + return; + if (mtyp == STATE_MSG) { + tipc_bclink_update_link_state(n, last); + return; + } + /* Compatibility: older nodes don't know BCAST_PROTOCOL synchronization, + * and transfer synch info in LINK_PROTOCOL messages. + */ + if (tipc_node_is_up(n)) + return; + if ((mtyp != RESET_MSG) && (mtyp != ACTIVATE_MSG)) + return; + n->bclink.last_sent = last; + n->bclink.last_in = last; + n->bclink.oos_state = 0; +} + /** * bclink_peek_nack - monitor retransmission requests sent by other nodes * diff --git a/net/tipc/bcast.h b/net/tipc/bcast.h index 3c290a48f7203..d74c69bcf60bd 100644 --- a/net/tipc/bcast.h +++ b/net/tipc/bcast.h @@ -133,5 +133,6 @@ void tipc_bclink_wakeup_users(struct net *net); int tipc_nl_add_bc_link(struct net *net, struct tipc_nl_msg *msg); int tipc_nl_bc_link_set(struct net *net, struct nlattr *attrs[]); void tipc_bclink_input(struct net *net); +void tipc_bclink_sync_state(struct tipc_node *n, struct tipc_msg *msg); #endif diff --git a/net/tipc/core.h b/net/tipc/core.h index 0fcf133d5cb7c..f4ed67778c542 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -129,6 +129,11 @@ static inline int less(u16 left, u16 right) return less_eq(left, right) && (mod(right) != mod(left)); } +static inline int in_range(u16 val, u16 min, u16 max) +{ + return !less(val, min) && !more(val, max); +} + #ifdef CONFIG_SYSCTL int tipc_register_sysctl(void); void tipc_unregister_sysctl(void); diff --git a/net/tipc/link.c b/net/tipc/link.c index eaccf4552d15c..55b675d20de83 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -76,6 +76,10 @@ static const struct nla_policy tipc_nl_prop_policy[TIPC_NLA_PROP_MAX + 1] = { [TIPC_NLA_PROP_WIN] = { .type = NLA_U32 } }; +/* + * Interval between NACKs when packets arrive out of order + */ +#define TIPC_NACK_INTV (TIPC_MIN_LINK_WIN * 2) /* * Out-of-range value for link session numbers */ @@ -123,22 +127,19 @@ static int link_establishing(struct tipc_link *l) return l->state == TIPC_LINK_ESTABLISHING; } -static void link_handle_out_of_seq_msg(struct tipc_link *link, - struct sk_buff *skb); -static void tipc_link_proto_rcv(struct tipc_link *link, - struct sk_buff *skb); -static void link_state_event(struct tipc_link *l_ptr, u32 event); +static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, + struct sk_buff_head *xmitq); static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, u16 rcvgap, int tolerance, int priority, struct sk_buff_head *xmitq); static void link_reset_statistics(struct tipc_link *l_ptr); static void link_print(struct tipc_link *l_ptr, const char *str); -static void tipc_link_sync_xmit(struct tipc_link *l); +static void tipc_link_build_bcast_sync_msg(struct tipc_link *l, + struct sk_buff_head *xmitq); static void tipc_link_sync_rcv(struct tipc_node *n, struct sk_buff *buf); static void tipc_link_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_data_input(struct tipc_link *l, struct sk_buff *skb); static bool tipc_link_failover_rcv(struct tipc_link *l, struct sk_buff **skb); -static void link_activate(struct tipc_link *link); /* * Simple link routines @@ -283,6 +284,26 @@ void tipc_link_delete_list(struct net *net, unsigned int bearer_id) rcu_read_unlock(); } +/* tipc_link_build_bcast_sync_msg() - synchronize broadcast link endpoints. + * + * Give a newly added peer node the sequence number where it should + * start receiving and acking broadcast packets. + */ +static void tipc_link_build_bcast_sync_msg(struct tipc_link *l, + struct sk_buff_head *xmitq) +{ + struct sk_buff *skb; + struct sk_buff_head list; + + skb = tipc_msg_create(BCAST_PROTOCOL, STATE_MSG, INT_H_SIZE, + 0, l->addr, link_own_addr(l), 0, 0, 0); + if (!skb) + return; + __skb_queue_head_init(&list); + __skb_queue_tail(&list, skb); + tipc_link_xmit(l, &list, xmitq); +} + /** * tipc_link_fsm_evt - link finite state machine * @l: pointer to link @@ -295,12 +316,13 @@ static int tipc_link_fsm_evt(struct tipc_link *l, int evt, int mtyp = 0, rc = 0; struct tipc_link *pl; enum { - LINK_RESET = 1, - LINK_ACTIVATE = (1 << 1), - SND_PROBE = (1 << 2), - SND_STATE = (1 << 3), - SND_RESET = (1 << 4), - SND_ACTIVATE = (1 << 5) + LINK_RESET = 1, + LINK_ACTIVATE = (1 << 1), + SND_PROBE = (1 << 2), + SND_STATE = (1 << 3), + SND_RESET = (1 << 4), + SND_ACTIVATE = (1 << 5), + SND_BCAST_SYNC = (1 << 6) } actions = 0; if (l->exec_mode == TIPC_LINK_BLOCKED) @@ -352,8 +374,8 @@ static int tipc_link_fsm_evt(struct tipc_link *l, int evt, if (pl && link_probing(pl)) break; actions |= LINK_ACTIVATE; - if (l->owner->working_links == 1) - tipc_link_sync_xmit(l); + if (!l->owner->working_links) + actions |= SND_BCAST_SYNC; break; case PEER_RESET_EVT: l->state = TIPC_LINK_ESTABLISHING; @@ -374,8 +396,8 @@ static int tipc_link_fsm_evt(struct tipc_link *l, int evt, if (pl && link_probing(pl)) break; actions |= LINK_ACTIVATE; - if (l->owner->working_links == 1) - tipc_link_sync_xmit(l); + if (!l->owner->working_links) + actions |= SND_BCAST_SYNC; break; case PEER_RESET_EVT: break; @@ -408,6 +430,8 @@ static int tipc_link_fsm_evt(struct tipc_link *l, int evt, if (actions & (SND_PROBE | SND_STATE | SND_RESET | SND_ACTIVATE)) tipc_link_build_proto_msg(l, mtyp, actions & SND_PROBE, 0, 0, 0, xmitq); + if (actions & SND_BCAST_SYNC) + tipc_link_build_bcast_sync_msg(l, xmitq); return rc; } @@ -605,12 +629,14 @@ void tipc_link_reset(struct tipc_link *l_ptr) l_ptr->reasm_buf = NULL; l_ptr->rcv_unacked = 0; l_ptr->snd_nxt = 1; + l_ptr->rcv_nxt = 1; l_ptr->silent_intv_cnt = 0; + l_ptr->stats.recv_info = 0; l_ptr->stale_count = 0; link_reset_statistics(l_ptr); } -static void link_activate(struct tipc_link *link) +void tipc_link_activate(struct tipc_link *link) { struct tipc_node *node = link->owner; @@ -623,36 +649,6 @@ static void link_activate(struct tipc_link *link) tipc_bearer_add_dest(node->net, link->bearer_id, link->addr); } -/** - * link_state_event - link finite state machine - * @l_ptr: pointer to link - * @event: state machine event to process - */ -static void link_state_event(struct tipc_link *l, unsigned int evt) -{ - int rc; - struct sk_buff_head xmitq; - struct sk_buff *skb; - - if (l->exec_mode == TIPC_LINK_BLOCKED) - return; - - __skb_queue_head_init(&xmitq); - - rc = tipc_link_fsm_evt(l, evt, &xmitq); - - if (rc & TIPC_LINK_UP_EVT) - link_activate(l); - - if (rc & TIPC_LINK_DOWN_EVT) - tipc_link_reset(l); - - skb = __skb_dequeue(&xmitq); - if (!skb) - return; - tipc_bearer_send(l->owner->net, l->bearer_id, skb, &l->media_addr); -} - /** * __tipc_link_xmit(): same as tipc_link_xmit, but destlink is known & locked * @link: link to use @@ -807,30 +803,6 @@ static int __tipc_link_xmit_skb(struct tipc_link *link, struct sk_buff *skb) return __tipc_link_xmit(link->owner->net, link, &head); } -/* - * tipc_link_sync_xmit - synchronize broadcast link endpoints. - * - * Give a newly added peer node the sequence number where it should - * start receiving and acking broadcast packets. - * - * Called with node locked - */ -static void tipc_link_sync_xmit(struct tipc_link *link) -{ - struct sk_buff *skb; - struct tipc_msg *msg; - - skb = tipc_buf_acquire(INT_H_SIZE); - if (!skb) - return; - - msg = buf_msg(skb); - tipc_msg_init(link_own_addr(link), msg, BCAST_PROTOCOL, STATE_MSG, - INT_H_SIZE, link->addr); - msg_set_last_bcast(msg, link->owner->bclink.acked); - __tipc_link_xmit_skb(link, skb); -} - /* * tipc_link_sync_rcv - synchronize broadcast link endpoints. * Receive the sequence number where we should start receiving and @@ -881,6 +853,34 @@ void tipc_link_push_packets(struct tipc_link *link) link->snd_nxt = seqno; } +void tipc_link_advance_backlog(struct tipc_link *l, struct sk_buff_head *xmitq) +{ + struct sk_buff *skb, *_skb; + struct tipc_msg *hdr; + u16 seqno = l->snd_nxt; + u16 ack = l->rcv_nxt - 1; + + while (skb_queue_len(&l->transmq) < l->window) { + skb = skb_peek(&l->backlogq); + if (!skb) + break; + _skb = skb_clone(skb, GFP_ATOMIC); + if (!_skb) + break; + __skb_dequeue(&l->backlogq); + hdr = buf_msg(skb); + l->backlog[msg_importance(hdr)].len--; + __skb_queue_tail(&l->transmq, skb); + __skb_queue_tail(xmitq, _skb); + msg_set_ack(hdr, ack); + msg_set_seqno(hdr, seqno); + msg_set_bcast_ack(hdr, l->owner->bclink.last_in); + l->rcv_unacked = 0; + seqno++; + } + l->snd_nxt = seqno; +} + void tipc_link_reset_all(struct tipc_node *node) { char addr_string[16]; @@ -978,6 +978,41 @@ void tipc_link_retransmit(struct tipc_link *l_ptr, struct sk_buff *skb, } } +static int tipc_link_retransm(struct tipc_link *l, int retransm, + struct sk_buff_head *xmitq) +{ + struct sk_buff *_skb, *skb = skb_peek(&l->transmq); + struct tipc_msg *hdr; + + if (!skb) + return 0; + + /* Detect repeated retransmit failures on same packet */ + if (likely(l->last_retransm != buf_seqno(skb))) { + l->last_retransm = buf_seqno(skb); + l->stale_count = 1; + } else if (++l->stale_count > 100) { + link_retransmit_failure(l, skb); + return TIPC_LINK_DOWN_EVT; + } + skb_queue_walk(&l->transmq, skb) { + if (!retransm) + return 0; + hdr = buf_msg(skb); + _skb = __pskb_copy(skb, MIN_H_SIZE, GFP_ATOMIC); + if (!_skb) + return 0; + hdr = buf_msg(_skb); + msg_set_ack(hdr, l->rcv_nxt - 1); + msg_set_bcast_ack(hdr, l->owner->bclink.last_in); + _skb->priority = TC_PRIO_CONTROL; + __skb_queue_tail(xmitq, _skb); + retransm--; + l->stats.retransmitted++; + } + return 0; +} + /* link_synch(): check if all packets arrived before the synch * point have been consumed * Returns true if the parallel links are synched, otherwise false @@ -1004,155 +1039,6 @@ synched: return true; } -static void link_retrieve_defq(struct tipc_link *link, - struct sk_buff_head *list) -{ - u16 seq_no; - - if (skb_queue_empty(&link->deferdq)) - return; - - seq_no = buf_seqno(skb_peek(&link->deferdq)); - if (seq_no == link->rcv_nxt) - skb_queue_splice_tail_init(&link->deferdq, list); -} - -/** - * tipc_rcv - process TIPC packets/messages arriving from off-node - * @net: the applicable net namespace - * @skb: TIPC packet - * @b_ptr: pointer to bearer message arrived on - * - * Invoked with no locks held. Bearer pointer must point to a valid bearer - * structure (i.e. cannot be NULL), but bearer can be inactive. - */ -void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b_ptr) -{ - struct tipc_net *tn = net_generic(net, tipc_net_id); - struct sk_buff_head head; - struct tipc_node *n_ptr; - struct tipc_link *l_ptr; - struct sk_buff *skb1, *tmp; - struct tipc_msg *msg; - u16 seq_no; - u16 ackd; - u32 released; - - skb2list(skb, &head); - - while ((skb = __skb_dequeue(&head))) { - /* Ensure message is well-formed */ - if (unlikely(!tipc_msg_validate(skb))) - goto discard; - - /* Handle arrival of a non-unicast link message */ - msg = buf_msg(skb); - if (unlikely(msg_non_seq(msg))) { - if (msg_user(msg) == LINK_CONFIG) - tipc_disc_rcv(net, skb, b_ptr); - else - tipc_bclink_rcv(net, skb); - continue; - } - - /* Discard unicast link messages destined for another node */ - if (unlikely(!msg_short(msg) && - (msg_destnode(msg) != tn->own_addr))) - goto discard; - - /* Locate neighboring node that sent message */ - n_ptr = tipc_node_find(net, msg_prevnode(msg)); - if (unlikely(!n_ptr)) - goto discard; - - tipc_node_lock(n_ptr); - /* Locate unicast link endpoint that should handle message */ - l_ptr = n_ptr->links[b_ptr->identity].link; - if (unlikely(!l_ptr)) - goto unlock; - - /* Is reception of this pkt permitted at the moment ? */ - if (!tipc_node_filter_skb(n_ptr, msg)) - goto unlock; - - /* Validate message sequence number info */ - seq_no = msg_seqno(msg); - ackd = msg_ack(msg); - - /* Release acked messages */ - if (unlikely(n_ptr->bclink.acked != msg_bcast_ack(msg))) - tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg)); - - released = 0; - skb_queue_walk_safe(&l_ptr->transmq, skb1, tmp) { - if (more(buf_seqno(skb1), ackd)) - break; - __skb_unlink(skb1, &l_ptr->transmq); - kfree_skb(skb1); - released = 1; - } - - /* Try sending any messages link endpoint has pending */ - if (unlikely(skb_queue_len(&l_ptr->backlogq))) - tipc_link_push_packets(l_ptr); - - if (released && !skb_queue_empty(&l_ptr->wakeupq)) - link_prepare_wakeup(l_ptr); - - /* Process the incoming packet */ - if (unlikely(!link_working(l_ptr))) { - if (msg_user(msg) == LINK_PROTOCOL) { - tipc_link_proto_rcv(l_ptr, skb); - link_retrieve_defq(l_ptr, &head); - skb = NULL; - goto unlock; - } - - /* Traffic message. Conditionally activate link */ - link_state_event(l_ptr, TRAFFIC_EVT); - - if (link_working(l_ptr)) { - /* Re-insert buffer in front of queue */ - __skb_queue_head(&head, skb); - skb = NULL; - goto unlock; - } - goto unlock; - } - - /* Link is now in state TIPC_LINK_WORKING */ - if (unlikely(seq_no != l_ptr->rcv_nxt)) { - link_handle_out_of_seq_msg(l_ptr, skb); - link_retrieve_defq(l_ptr, &head); - skb = NULL; - goto unlock; - } - l_ptr->silent_intv_cnt = 0; - - /* Synchronize with parallel link if applicable */ - if (unlikely((l_ptr->exec_mode == TIPC_LINK_TUNNEL) && - !msg_dup(msg))) { - if (!link_synch(l_ptr)) - goto unlock; - } - l_ptr->rcv_nxt++; - if (unlikely(!skb_queue_empty(&l_ptr->deferdq))) - link_retrieve_defq(l_ptr, &head); - if (unlikely(++l_ptr->rcv_unacked >= TIPC_MIN_LINK_WIN)) { - l_ptr->stats.sent_acks++; - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0); - } - tipc_link_input(l_ptr, skb); - skb = NULL; -unlock: - tipc_node_unlock(n_ptr); - tipc_node_put(n_ptr); -discard: - if (unlikely(skb)) - kfree_skb(skb); - } -} - /* tipc_data_input - deliver data and name distr msgs to upper layer * * Consumes buffer if message is of right type @@ -1206,9 +1092,6 @@ static void tipc_link_input(struct tipc_link *link, struct sk_buff *skb) struct sk_buff *iskb; int pos = 0; - if (likely(tipc_data_input(link, skb))) - return; - switch (msg_user(msg)) { case TUNNEL_PROTOCOL: if (msg_dup(msg)) { @@ -1247,6 +1130,110 @@ static void tipc_link_input(struct tipc_link *link, struct sk_buff *skb) }; } +static bool tipc_link_release_pkts(struct tipc_link *l, u16 acked) +{ + bool released = false; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&l->transmq, skb, tmp) { + if (more(buf_seqno(skb), acked)) + break; + __skb_unlink(skb, &l->transmq); + kfree_skb(skb); + released = true; + } + return released; +} + +/* tipc_link_rcv - process TIPC packets/messages arriving from off-node + * @link: the link that should handle the message + * @skb: TIPC packet + * @xmitq: queue to place packets to be sent after this call + */ +int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb, + struct sk_buff_head *xmitq) +{ + struct sk_buff_head *arrvq = &l->deferdq; + struct sk_buff *tmp; + struct tipc_msg *hdr; + u16 seqno, rcv_nxt; + int rc = 0; + + if (unlikely(!__tipc_skb_queue_sorted(arrvq, skb))) { + if (!(skb_queue_len(arrvq) % TIPC_NACK_INTV)) + tipc_link_build_proto_msg(l, STATE_MSG, 0, + 0, 0, 0, xmitq); + return rc; + } + + skb_queue_walk_safe(arrvq, skb, tmp) { + hdr = buf_msg(skb); + + /* Verify and update link state */ + if (unlikely(msg_user(hdr) == LINK_PROTOCOL)) { + __skb_dequeue(arrvq); + rc |= tipc_link_proto_rcv(l, skb, xmitq); + continue; + } + + if (unlikely(!link_working(l))) { + rc |= tipc_link_fsm_evt(l, TRAFFIC_EVT, xmitq); + if (!link_working(l)) { + kfree_skb(__skb_dequeue(arrvq)); + return rc; + } + } + + l->silent_intv_cnt = 0; + + /* Forward queues and wake up waiting users */ + if (likely(tipc_link_release_pkts(l, msg_ack(hdr)))) { + tipc_link_advance_backlog(l, xmitq); + if (unlikely(!skb_queue_empty(&l->wakeupq))) + link_prepare_wakeup(l); + } + + /* Defer reception if there is a gap in the sequence */ + seqno = msg_seqno(hdr); + rcv_nxt = l->rcv_nxt; + if (unlikely(less(rcv_nxt, seqno))) { + l->stats.deferred_recv++; + return rc; + } + + __skb_dequeue(arrvq); + + /* Drop if packet already received */ + if (unlikely(more(rcv_nxt, seqno))) { + l->stats.duplicates++; + kfree_skb(skb); + return rc; + } + + /* Synchronize with parallel link if applicable */ + if (unlikely(l->exec_mode == TIPC_LINK_TUNNEL)) + if (!msg_dup(hdr) && !link_synch(l)) { + kfree_skb(skb); + return rc; + } + + /* Packet can be delivered */ + l->rcv_nxt++; + l->stats.recv_info++; + if (unlikely(!tipc_data_input(l, skb))) + tipc_link_input(l, skb); + + /* Ack at regular intervals */ + if (unlikely(++l->rcv_unacked >= TIPC_MIN_LINK_WIN)) { + l->rcv_unacked = 0; + l->stats.sent_acks++; + tipc_link_build_proto_msg(l, STATE_MSG, + 0, 0, 0, 0, xmitq); + } + } + return rc; +} + /** * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue * @@ -1286,41 +1273,6 @@ u32 tipc_link_defer_pkt(struct sk_buff_head *list, struct sk_buff *skb) return 1; } -/* - * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet - */ -static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr, - struct sk_buff *buf) -{ - u32 seq_no = buf_seqno(buf); - - if (likely(msg_user(buf_msg(buf)) == LINK_PROTOCOL)) { - tipc_link_proto_rcv(l_ptr, buf); - return; - } - - /* Record OOS packet arrival */ - l_ptr->silent_intv_cnt = 0; - - /* - * Discard packet if a duplicate; otherwise add it to deferred queue - * and notify peer of gap as per protocol specification - */ - if (less(seq_no, l_ptr->rcv_nxt)) { - l_ptr->stats.duplicates++; - kfree_skb(buf); - return; - } - - if (tipc_link_defer_pkt(&l_ptr->deferdq, buf)) { - l_ptr->stats.deferred_recv++; - if ((skb_queue_len(&l_ptr->deferdq) % TIPC_MIN_LINK_WIN) == 1) - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, 0, 0, 0); - } else { - l_ptr->stats.duplicates++; - } -} - /* * Send protocol message to the other endpoint. */ @@ -1341,119 +1293,6 @@ void tipc_link_proto_xmit(struct tipc_link *l, u32 msg_typ, int probe_msg, kfree_skb(skb); } -/* - * Receive protocol message : - * Note that network plane id propagates through the network, and may - * change at any time. The node with lowest address rules - */ -static void tipc_link_proto_rcv(struct tipc_link *l_ptr, - struct sk_buff *buf) -{ - u32 rec_gap = 0; - u32 msg_tol; - struct tipc_msg *msg = buf_msg(buf); - - if (l_ptr->exec_mode == TIPC_LINK_BLOCKED) - goto exit; - - if (l_ptr->net_plane != msg_net_plane(msg)) - if (link_own_addr(l_ptr) > msg_prevnode(msg)) - l_ptr->net_plane = msg_net_plane(msg); - - switch (msg_type(msg)) { - - case RESET_MSG: - if (!link_probing(l_ptr) && - (l_ptr->peer_session != WILDCARD_SESSION)) { - if (less_eq(msg_session(msg), l_ptr->peer_session)) - break; /* duplicate or old reset: ignore */ - } - link_state_event(l_ptr, RESET_MSG); - - /* fall thru' */ - case ACTIVATE_MSG: - /* Update link settings according other endpoint's values */ - strcpy((strrchr(l_ptr->name, ':') + 1), (char *)msg_data(msg)); - - msg_tol = msg_link_tolerance(msg); - if (msg_tol > l_ptr->tolerance) - l_ptr->tolerance = msg_tol; - - if (msg_linkprio(msg) > l_ptr->priority) - l_ptr->priority = msg_linkprio(msg); - - if (l_ptr->mtu > msg_max_pkt(msg)) - l_ptr->mtu = msg_max_pkt(msg); - - /* Synchronize broadcast link info, if not done previously */ - if (!tipc_node_is_up(l_ptr->owner)) { - l_ptr->owner->bclink.last_sent = - l_ptr->owner->bclink.last_in = - msg_last_bcast(msg); - l_ptr->owner->bclink.oos_state = 0; - } - - l_ptr->peer_session = msg_session(msg); - l_ptr->peer_bearer_id = msg_bearer_id(msg); - - if (!msg_peer_is_up(msg)) - tipc_node_fsm_evt(l_ptr->owner, PEER_LOST_CONTACT_EVT); - if (msg_type(msg) == ACTIVATE_MSG) - link_state_event(l_ptr, ACTIVATE_MSG); - break; - case STATE_MSG: - - msg_tol = msg_link_tolerance(msg); - if (msg_tol) - l_ptr->tolerance = msg_tol; - - if (msg_linkprio(msg) && - (msg_linkprio(msg) != l_ptr->priority)) { - pr_info("%s<%s>, priority change %u->%u\n", - link_rst_msg, l_ptr->name, - l_ptr->priority, msg_linkprio(msg)); - l_ptr->priority = msg_linkprio(msg); - tipc_link_reset(l_ptr); - break; - } - - /* Record reception; force mismatch at next timeout: */ - l_ptr->silent_intv_cnt = 0; - - link_state_event(l_ptr, TRAFFIC_EVT); - l_ptr->stats.recv_states++; - if (link_resetting(l_ptr)) - break; - - if (less_eq(l_ptr->rcv_nxt, msg_next_sent(msg))) - rec_gap = mod(msg_next_sent(msg) - l_ptr->rcv_nxt); - - if (msg_probe(msg)) - l_ptr->stats.recv_probes++; - - /* Protocol message before retransmits, reduce loss risk */ - if (l_ptr->owner->bclink.recv_permitted) - tipc_bclink_update_link_state(l_ptr->owner, - msg_last_bcast(msg)); - - if (rec_gap || (msg_probe(msg))) - tipc_link_proto_xmit(l_ptr, STATE_MSG, 0, - rec_gap, 0, 0); - - if (msg_seq_gap(msg)) { - l_ptr->stats.recv_nacks++; - tipc_link_retransmit(l_ptr, skb_peek(&l_ptr->transmq), - msg_seq_gap(msg)); - } - if (tipc_link_is_up(l_ptr)) - tipc_node_fsm_evt(l_ptr->owner, - PEER_ESTABL_CONTACT_EVT); - break; - } -exit: - kfree_skb(buf); -} - /* tipc_link_build_proto_msg: prepare link protocol message for transmission */ static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe, @@ -1727,6 +1566,96 @@ exit: return *skb; } +/* tipc_link_proto_rcv(): receive link level protocol message : + * Note that network plane id propagates through the network, and may + * change at any time. The node with lowest numerical id determines + * network plane + */ +static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, + struct sk_buff_head *xmitq) +{ + struct tipc_msg *hdr = buf_msg(skb); + u16 rcvgap = 0; + u16 nacked_gap = msg_seq_gap(hdr); + u16 peers_snd_nxt = msg_next_sent(hdr); + u16 peers_tol = msg_link_tolerance(hdr); + u16 peers_prio = msg_linkprio(hdr); + char *if_name; + int rc = 0; + + if (l->exec_mode == TIPC_LINK_BLOCKED) + goto exit; + + if (link_own_addr(l) > msg_prevnode(hdr)) + l->net_plane = msg_net_plane(hdr); + + switch (msg_type(hdr)) { + case RESET_MSG: + + /* Ignore duplicate RESET with old session number */ + if ((less_eq(msg_session(hdr), l->peer_session)) && + (l->peer_session != WILDCARD_SESSION)) + break; + /* fall thru' */ + case ACTIVATE_MSG: + + /* Complete own link name with peer's interface name */ + if_name = strrchr(l->name, ':') + 1; + if (sizeof(l->name) - (if_name - l->name) <= TIPC_MAX_IF_NAME) + break; + if (msg_data_sz(hdr) < TIPC_MAX_IF_NAME) + break; + strncpy(if_name, msg_data(hdr), TIPC_MAX_IF_NAME); + + /* Update own tolerance if peer indicates a non-zero value */ + if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL)) + l->tolerance = peers_tol; + + /* Update own priority if peer's priority is higher */ + if (in_range(peers_prio, l->priority + 1, TIPC_MAX_LINK_PRI)) + l->priority = peers_prio; + + l->peer_session = msg_session(hdr); + l->peer_bearer_id = msg_bearer_id(hdr); + rc = tipc_link_fsm_evt(l, msg_type(hdr), xmitq); + if (l->mtu > msg_max_pkt(hdr)) + l->mtu = msg_max_pkt(hdr); + break; + case STATE_MSG: + /* Update own tolerance if peer indicates a non-zero value */ + if (in_range(peers_tol, TIPC_MIN_LINK_TOL, TIPC_MAX_LINK_TOL)) + l->tolerance = peers_tol; + + l->silent_intv_cnt = 0; + l->stats.recv_states++; + if (msg_probe(hdr)) + l->stats.recv_probes++; + rc = tipc_link_fsm_evt(l, TRAFFIC_EVT, xmitq); + if (!tipc_link_is_up(l)) + break; + + /* Has peer sent packets we haven't received yet ? */ + if (more(peers_snd_nxt, l->rcv_nxt)) + rcvgap = peers_snd_nxt - l->rcv_nxt; + if (rcvgap || (msg_probe(hdr))) + tipc_link_build_proto_msg(l, STATE_MSG, 0, rcvgap, + 0, l->mtu, xmitq); + tipc_link_release_pkts(l, msg_ack(hdr)); + + /* If NACK, retransmit will now start at right position */ + if (nacked_gap) { + rc |= tipc_link_retransm(l, nacked_gap, xmitq); + l->stats.recv_nacks++; + } + tipc_link_advance_backlog(l, xmitq); + if (unlikely(!skb_queue_empty(&l->wakeupq))) + link_prepare_wakeup(l); + } +exit: + kfree_skb(skb); + return rc; +} + void tipc_link_set_queue_limits(struct tipc_link *l, u32 win) { int max_bulk = TIPC_MAX_PUBLICATIONS / (l->mtu / ITEM_SIZE); diff --git a/net/tipc/link.h b/net/tipc/link.h index 0cf7d2b11803c..37cfd7d7bf7d5 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h @@ -58,7 +58,7 @@ enum { TIPC_LINK_TUNNEL }; -/* Events occurring at packet reception or at timeout +/* Events returned from link at packet reception or at timeout */ enum { TIPC_LINK_UP_EVT = 1, @@ -223,6 +223,7 @@ void tipc_link_purge_queues(struct tipc_link *l_ptr); void tipc_link_purge_backlog(struct tipc_link *l); void tipc_link_reset_all(struct tipc_node *node); void tipc_link_reset(struct tipc_link *l_ptr); +void tipc_link_activate(struct tipc_link *link); int __tipc_link_xmit(struct net *net, struct tipc_link *link, struct sk_buff_head *list); int tipc_link_xmit(struct tipc_link *link, struct sk_buff_head *list, @@ -244,7 +245,8 @@ int tipc_nl_link_reset_stats(struct sk_buff *skb, struct genl_info *info); int tipc_nl_parse_link_prop(struct nlattr *prop, struct nlattr *props[]); void link_prepare_wakeup(struct tipc_link *l); int tipc_link_timeout(struct tipc_link *l, struct sk_buff_head *xmitq); - +int tipc_link_rcv(struct tipc_link *l, struct sk_buff *skb, + struct sk_buff_head *xmitq); static inline u32 link_own_addr(struct tipc_link *l) { return msg_prevnode(l->pmsg); diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 4dc66d9f69cc4..2f1563b47e24f 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -38,6 +38,7 @@ #define _TIPC_MSG_H #include +#include "core.h" /* * Constants and routines used to read and write TIPC payload message headers @@ -658,12 +659,12 @@ static inline void msg_set_link_selector(struct tipc_msg *m, u32 n) /* * Word 5 */ -static inline u32 msg_session(struct tipc_msg *m) +static inline u16 msg_session(struct tipc_msg *m) { return msg_bits(m, 5, 16, 0xffff); } -static inline void msg_set_session(struct tipc_msg *m, u32 n) +static inline void msg_set_session(struct tipc_msg *m, u16 n) { msg_set_bits(m, 5, 16, 0xffff, n); } @@ -766,10 +767,19 @@ static inline void msg_set_link_tolerance(struct tipc_msg *m, u32 n) msg_set_bits(m, 9, 0, 0xffff, n); } -static inline bool msg_peer_is_up(struct tipc_msg *m) +static inline bool msg_is_traffic(struct tipc_msg *m) { - if (likely(msg_user(m) != LINK_PROTOCOL) || (msg_type(m) == STATE_MSG)) + if (likely(msg_user(m) != LINK_PROTOCOL)) return true; + if ((msg_type(m) == RESET_MSG) || (msg_type(m) == ACTIVATE_MSG)) + return false; + return true; +} + +static inline bool msg_peer_is_up(struct tipc_msg *m) +{ + if (likely(msg_is_traffic(m))) + return false; return msg_redundant_link(m); } @@ -886,4 +896,36 @@ static inline bool tipc_skb_queue_tail(struct sk_buff_head *list, return rv; } +/* tipc_skb_queue_sorted(); sort pkt into list according to sequence number + * @list: list to be appended to + * @skb: buffer to add + * Returns true if queue should treated further, otherwise false + */ +static inline bool __tipc_skb_queue_sorted(struct sk_buff_head *list, + struct sk_buff *skb) +{ + struct sk_buff *_skb, *tmp; + struct tipc_msg *hdr = buf_msg(skb); + u16 seqno = msg_seqno(hdr); + + if (skb_queue_empty(list) || (msg_user(hdr) == LINK_PROTOCOL)) { + __skb_queue_head(list, skb); + return true; + } + if (likely(less(seqno, buf_seqno(skb_peek(list))))) { + __skb_queue_head(list, skb); + return true; + } + if (!more(seqno, buf_seqno(skb_peek_tail(list)))) { + skb_queue_walk_safe(list, _skb, tmp) { + if (likely(less(seqno, buf_seqno(_skb)))) { + __skb_queue_before(list, _skb, skb); + return true; + } + } + } + __skb_queue_tail(list, skb); + return false; +} + #endif diff --git a/net/tipc/node.c b/net/tipc/node.c index 9dbbb5de287b4..e92f84afbf95f 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -40,11 +40,13 @@ #include "name_distr.h" #include "socket.h" #include "bcast.h" +#include "discover.h" static void node_lost_contact(struct tipc_node *n_ptr); static void node_established_contact(struct tipc_node *n_ptr); static void tipc_node_delete(struct tipc_node *node); static void tipc_node_timeout(unsigned long data); +static void tipc_node_fsm_evt(struct tipc_node *n, int evt); struct tipc_sock_conn { u32 port; @@ -141,7 +143,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr) break; } list_add_tail_rcu(&n_ptr->list, &temp_node->list); - n_ptr->state = SELF_DOWN_PEER_DOWN; + n_ptr->state = SELF_DOWN_PEER_LEAVING; n_ptr->signature = INVALID_NODE_SIG; n_ptr->active_links[0] = INVALID_BEARER_ID; n_ptr->active_links[1] = INVALID_BEARER_ID; @@ -424,7 +426,7 @@ void tipc_node_detach_link(struct tipc_node *n_ptr, struct tipc_link *l_ptr) /* tipc_node_fsm_evt - node finite state machine * Determines when contact is allowed with peer node */ -void tipc_node_fsm_evt(struct tipc_node *n, int evt) +static void tipc_node_fsm_evt(struct tipc_node *n, int evt) { int state = n->state; @@ -523,23 +525,36 @@ void tipc_node_fsm_evt(struct tipc_node *n, int evt) n->state = state; } -bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_msg *hdr) +bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_link *l, + struct tipc_msg *hdr) { int state = n->state; if (likely(state == SELF_UP_PEER_UP)) return true; + if (state == SELF_DOWN_PEER_DOWN) return true; - if (state == SELF_UP_PEER_COMING) + + if (state == SELF_UP_PEER_COMING) { + /* If not traffic msg, peer may still be ESTABLISHING */ + if (tipc_link_is_up(l) && msg_is_traffic(hdr)) + tipc_node_fsm_evt(n, PEER_ESTABL_CONTACT_EVT); return true; + } + if (state == SELF_COMING_PEER_UP) return true; + if (state == SELF_LEAVING_PEER_DOWN) return false; - if (state == SELF_DOWN_PEER_LEAVING) - if (!msg_peer_is_up(hdr)) - return true; + + if (state == SELF_DOWN_PEER_LEAVING) { + if (msg_peer_is_up(hdr)) + return false; + tipc_node_fsm_evt(n, PEER_LOST_CONTACT_EVT); + return true; + } return false; } @@ -819,6 +834,82 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dnode, return 0; } +/** + * tipc_rcv - process TIPC packets/messages arriving from off-node + * @net: the applicable net namespace + * @skb: TIPC packet + * @bearer: pointer to bearer message arrived on + * + * Invoked with no locks held. Bearer pointer must point to a valid bearer + * structure (i.e. cannot be NULL), but bearer can be inactive. + */ +void tipc_rcv(struct net *net, struct sk_buff *skb, struct tipc_bearer *b) +{ + struct sk_buff_head xmitq; + struct tipc_node *n; + struct tipc_link *l; + struct tipc_msg *hdr; + struct tipc_media_addr *maddr; + int bearer_id = b->identity; + int rc = 0; + + __skb_queue_head_init(&xmitq); + + /* Ensure message is well-formed */ + if (unlikely(!tipc_msg_validate(skb))) + goto discard; + + /* Handle arrival of a non-unicast link packet */ + hdr = buf_msg(skb); + if (unlikely(msg_non_seq(hdr))) { + if (msg_user(hdr) == LINK_CONFIG) + tipc_disc_rcv(net, skb, b); + else + tipc_bclink_rcv(net, skb); + return; + } + + /* Locate neighboring node that sent packet */ + n = tipc_node_find(net, msg_prevnode(hdr)); + if (unlikely(!n)) + goto discard; + tipc_node_lock(n); + + /* Locate link endpoint that should handle packet */ + l = n->links[bearer_id].link; + if (unlikely(!l)) + goto unlock; + + /* Is reception of this packet permitted at the moment ? */ + if (unlikely(n->state != SELF_UP_PEER_UP)) + if (!tipc_node_filter_skb(n, l, hdr)) + goto unlock; + + if (unlikely(msg_user(hdr) == LINK_PROTOCOL)) + tipc_bclink_sync_state(n, hdr); + + /* Release acked broadcast messages */ + if (unlikely(n->bclink.acked != msg_bcast_ack(hdr))) + tipc_bclink_acknowledge(n, msg_bcast_ack(hdr)); + + /* Check protocol and update link state */ + rc = tipc_link_rcv(l, skb, &xmitq); + + if (unlikely(rc & TIPC_LINK_UP_EVT)) + tipc_link_activate(l); + if (unlikely(rc & TIPC_LINK_DOWN_EVT)) + tipc_link_reset(l); + skb = NULL; +unlock: + tipc_node_unlock(n); + tipc_sk_rcv(net, &n->links[bearer_id].inputq); + maddr = &n->links[bearer_id].maddr; + tipc_bearer_xmit(net, bearer_id, &xmitq, maddr); + tipc_node_put(n); +discard: + kfree_skb(skb); +} + int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb) { int err; diff --git a/net/tipc/node.h b/net/tipc/node.h index 270256e09ee5d..5e7016802077c 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h @@ -185,7 +185,6 @@ int tipc_node_xmit_skb(struct net *net, struct sk_buff *skb, u32 dest, u32 selector); int tipc_node_add_conn(struct net *net, u32 dnode, u32 port, u32 peer_port); void tipc_node_remove_conn(struct net *net, u32 dnode, u32 port); - int tipc_nl_node_dump(struct sk_buff *skb, struct netlink_callback *cb); static inline void tipc_node_lock(struct tipc_node *node) @@ -193,9 +192,6 @@ static inline void tipc_node_lock(struct tipc_node *node) spin_lock_bh(&node->lock); } -void tipc_node_fsm_evt(struct tipc_node *n, int evt); -bool tipc_node_filter_skb(struct tipc_node *n, struct tipc_msg *hdr); - static inline struct tipc_link *node_active_link(struct tipc_node *n, int sel) { int bearer_id = n->active_links[sel & 1]; -- GitLab From 0dacf3f664818ab1e3e0af8ef22a86c89f34d125 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:05 +0200 Subject: [PATCH 1301/7006] stmmac: use of_device_get_match_data to retrieve of match data By using of_device_get_match_data() the code that retrieve match data can be simplified quite a bit. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index f3918c7e7eeb3..89e40ddc03918 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -109,13 +109,11 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; + const struct stmmac_of_data *data; struct stmmac_dma_cfg *dma_cfg; - const struct of_device_id *device; - struct device *dev = &pdev->dev; - device = of_match_device(dev->driver->of_match_table, dev); - if (device->data) { - const struct stmmac_of_data *data = device->data; + data = of_device_get_match_data(&pdev->dev); + if (data) { plat->has_gmac = data->has_gmac; plat->enh_desc = data->enh_desc; plat->tx_coe = data->tx_coe; -- GitLab From 4ed2d8fca7979ad82d56b67ac83a50bba2dd3419 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:06 +0200 Subject: [PATCH 1302/7006] stmmac: clean up platform/of_match data retrieval Refactor code to clearly separate probing non-dt versus dt. In the non-dt case platform data must be supplied to probe successfully. For dt the platform data structure is created and match data is copied into it. Note that support for supplying platform data in dt from AUXDATA is dropped as no users in mainline does this. This change will allow dt dwmac-* drivers to call the config_dt() function from probe to create the needed platform data struct and retrieve common dt properties. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../ethernet/stmicro/stmmac/stmmac_platform.c | 50 +++++++++++-------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 89e40ddc03918..6e6ef859f58ad 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -105,13 +105,20 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries) * set some private fields that will be used by the main at runtime. */ static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data *plat, + struct plat_stmmacenet_data **plat_dat, const char **mac) { struct device_node *np = pdev->dev.of_node; + struct plat_stmmacenet_data *plat; const struct stmmac_of_data *data; struct stmmac_dma_cfg *dma_cfg; + plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); + if (!plat) + return -ENOMEM; + + *plat_dat = plat; + data = of_device_get_match_data(&pdev->dev); if (data) { plat->has_gmac = data->has_gmac; @@ -180,6 +187,12 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, */ plat->maxmtu = JUMBO_LEN; + /* Set default value for multicast hash bins */ + plat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat->unicast_filter_entries = 1; + /* * Currently only the properties needed on SPEAr600 * are provided. All other properties should be added @@ -242,7 +255,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, } #else static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data *plat, + struct plat_stmmacenet_data **plat, const char **mac) { return -ENOSYS; @@ -301,29 +314,24 @@ int stmmac_pltfr_probe(struct platform_device *pdev) if (IS_ERR(stmmac_res.addr)) return PTR_ERR(stmmac_res.addr); - plat_dat = dev_get_platdata(&pdev->dev); - - if (!plat_dat) - plat_dat = devm_kzalloc(&pdev->dev, - sizeof(struct plat_stmmacenet_data), - GFP_KERNEL); - if (!plat_dat) { - pr_err("%s: ERROR: no memory", __func__); - return -ENOMEM; - } - - /* Set default value for multicast hash bins */ - plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; - - /* Set default value for unicast filter entries */ - plat_dat->unicast_filter_entries = 1; - if (pdev->dev.of_node) { - ret = stmmac_probe_config_dt(pdev, plat_dat, &stmmac_res.mac); + ret = stmmac_probe_config_dt(pdev, &plat_dat, &stmmac_res.mac); if (ret) { - pr_err("%s: main dt probe failed", __func__); + dev_err(&pdev->dev, "dt configuration failed\n"); return ret; } + } else { + plat_dat = dev_get_platdata(&pdev->dev); + if (!plat_dat) { + dev_err(&pdev->dev, "no platform data provided\n"); + return -EINVAL; + } + + /* Set default value for multicast hash bins */ + plat_dat->multicast_filter_bins = HASH_TABLE_SIZE; + + /* Set default value for unicast filter entries */ + plat_dat->unicast_filter_entries = 1; } /* Custom setup (if needed) */ -- GitLab From f396cb01210909ab2de0b50b76677892c1bfeb5a Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:07 +0200 Subject: [PATCH 1303/7006] stmmac: introduce stmmac_get_platform_resources() Refactor all code that deals with platform resources into it's own get function. This function will later be used in the probe function in dwmac-* drivers. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../ethernet/stmicro/stmmac/stmmac_platform.c | 64 +++++++++++-------- 1 file changed, 37 insertions(+), 27 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 6e6ef859f58ad..94962d75b99ac 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -262,33 +262,23 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, } #endif /* CONFIG_OF */ -/** - * stmmac_pltfr_probe - platform driver probe. - * @pdev: platform device pointer - * Description: platform_device probe function. It is to allocate - * the necessary platform resources, invoke custom helper (if required) and - * invoke the main probe function. - */ -int stmmac_pltfr_probe(struct platform_device *pdev) +static int stmmac_get_platform_resources(struct platform_device *pdev, + struct stmmac_resources *stmmac_res) { - struct stmmac_resources stmmac_res; - int ret = 0; struct resource *res; - struct device *dev = &pdev->dev; - struct plat_stmmacenet_data *plat_dat = NULL; - memset(&stmmac_res, 0, sizeof(stmmac_res)); + memset(stmmac_res, 0, sizeof(*stmmac_res)); /* Get IRQ information early to have an ability to ask for deferred * probe if needed before we went too far with resource allocation. */ - stmmac_res.irq = platform_get_irq_byname(pdev, "macirq"); - if (stmmac_res.irq < 0) { - if (stmmac_res.irq != -EPROBE_DEFER) { - dev_err(dev, + stmmac_res->irq = platform_get_irq_byname(pdev, "macirq"); + if (stmmac_res->irq < 0) { + if (stmmac_res->irq != -EPROBE_DEFER) { + dev_err(&pdev->dev, "MAC IRQ configuration information not found\n"); } - return stmmac_res.irq; + return stmmac_res->irq; } /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq @@ -298,21 +288,41 @@ int stmmac_pltfr_probe(struct platform_device *pdev) * In case the wake up interrupt is not passed from the platform * so the driver will continue to use the mac irq (ndev->irq) */ - stmmac_res.wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); - if (stmmac_res.wol_irq < 0) { - if (stmmac_res.wol_irq == -EPROBE_DEFER) + stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq"); + if (stmmac_res->wol_irq < 0) { + if (stmmac_res->wol_irq == -EPROBE_DEFER) return -EPROBE_DEFER; - stmmac_res.wol_irq = stmmac_res.irq; + stmmac_res->wol_irq = stmmac_res->irq; } - stmmac_res.lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); - if (stmmac_res.lpi_irq == -EPROBE_DEFER) + stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi"); + if (stmmac_res->lpi_irq == -EPROBE_DEFER) return -EPROBE_DEFER; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - stmmac_res.addr = devm_ioremap_resource(dev, res); - if (IS_ERR(stmmac_res.addr)) - return PTR_ERR(stmmac_res.addr); + stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(stmmac_res->addr)) + return PTR_ERR(stmmac_res->addr); + + return 0; +} + +/** + * stmmac_pltfr_probe - platform driver probe. + * @pdev: platform device pointer + * Description: platform_device probe function. It is to allocate + * the necessary platform resources, invoke custom helper (if required) and + * invoke the main probe function. + */ +int stmmac_pltfr_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; if (pdev->dev.of_node) { ret = stmmac_probe_config_dt(pdev, &plat_dat, &stmmac_res.mac); -- GitLab From b0003ead75f394f1c6f3b704be5da8e9eb029f8c Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:08 +0200 Subject: [PATCH 1304/7006] stmmac: make stmmac_probe_config_dt return the platform data struct Since stmmac_probe_config_dt() allocates the platform data structure it is cleaner if it just returned this structure directly. This function will later be used in the probe function in dwmac-* drivers. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../ethernet/stmicro/stmmac/stmmac_platform.c | 28 ++++++++----------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index 94962d75b99ac..ea467be936737 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -104,9 +104,8 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries) * this function is to read the driver parameters from device-tree and * set some private fields that will be used by the main at runtime. */ -static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data **plat_dat, - const char **mac) +static struct plat_stmmacenet_data * +stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; struct plat_stmmacenet_data *plat; @@ -115,9 +114,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL); if (!plat) - return -ENOMEM; - - *plat_dat = plat; + return ERR_PTR(-ENOMEM); data = of_device_get_match_data(&pdev->dev); if (data) { @@ -156,7 +153,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, /* If phy-handle is not specified, check if we have a fixed-phy */ if (!plat->phy_node && of_phy_is_fixed_link(np)) { if ((of_phy_register_fixed_link(np) < 0)) - return -ENODEV; + return ERR_PTR(-ENODEV); plat->phy_node = of_node_get(np); } @@ -233,7 +230,7 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, GFP_KERNEL); if (!dma_cfg) { of_node_put(np); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } plat->dma_cfg = dma_cfg; of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl); @@ -251,14 +248,13 @@ static int stmmac_probe_config_dt(struct platform_device *pdev, pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set."); } - return 0; + return plat; } #else -static int stmmac_probe_config_dt(struct platform_device *pdev, - struct plat_stmmacenet_data **plat, - const char **mac) +static struct plat_stmmacenet_data * +stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { - return -ENOSYS; + return ERR_PTR(-ENOSYS); } #endif /* CONFIG_OF */ @@ -325,10 +321,10 @@ int stmmac_pltfr_probe(struct platform_device *pdev) return ret; if (pdev->dev.of_node) { - ret = stmmac_probe_config_dt(pdev, &plat_dat, &stmmac_res.mac); - if (ret) { + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) { dev_err(&pdev->dev, "dt configuration failed\n"); - return ret; + return PTR_ERR(plat_dat); } } else { plat_dat = dev_get_platdata(&pdev->dev); -- GitLab From 402dae0bed98dd41c5d6ab321135e8568a54819e Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:09 +0200 Subject: [PATCH 1305/7006] stmmac: export probe_config_dt() and get_platform_resources() Export stmmac_probe_config_dt() and stmmac_get_platform_resources() so they can be used in the dwmac-* drivers themselves. This will allow us to build more flexible and standalone drivers which just use stmmac_platform as a library for setup functions. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 10 ++++++---- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h | 8 ++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c index ea467be936737..eca0eb8452419 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c @@ -104,7 +104,7 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries) * this function is to read the driver parameters from device-tree and * set some private fields that will be used by the main at runtime. */ -static struct plat_stmmacenet_data * +struct plat_stmmacenet_data * stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { struct device_node *np = pdev->dev.of_node; @@ -251,15 +251,16 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) return plat; } #else -static struct plat_stmmacenet_data * +struct plat_stmmacenet_data * stmmac_probe_config_dt(struct platform_device *pdev, const char **mac) { return ERR_PTR(-ENOSYS); } #endif /* CONFIG_OF */ +EXPORT_SYMBOL_GPL(stmmac_probe_config_dt); -static int stmmac_get_platform_resources(struct platform_device *pdev, - struct stmmac_resources *stmmac_res) +int stmmac_get_platform_resources(struct platform_device *pdev, + struct stmmac_resources *stmmac_res) { struct resource *res; @@ -302,6 +303,7 @@ static int stmmac_get_platform_resources(struct platform_device *pdev, return 0; } +EXPORT_SYMBOL_GPL(stmmac_get_platform_resources); /** * stmmac_pltfr_probe - platform driver probe. diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h index 71da86d7bd00d..84ceb5342686f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h @@ -19,6 +19,14 @@ #ifndef __STMMAC_PLATFORM_H__ #define __STMMAC_PLATFORM_H__ +#include "stmmac.h" + +struct plat_stmmacenet_data * +stmmac_probe_config_dt(struct platform_device *pdev, const char **mac); + +int stmmac_get_platform_resources(struct platform_device *pdev, + struct stmmac_resources *stmmac_res); + int stmmac_pltfr_probe(struct platform_device *pdev); int stmmac_pltfr_remove(struct platform_device *pdev); extern const struct dev_pm_ops stmmac_pltfr_pm_ops; -- GitLab From f4f8dfdedf1b1ff34a5e6ff71c9e80a1643a0622 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:10 +0200 Subject: [PATCH 1306/7006] stmmac: add proper probe function to dwmac-lpc18xx By using a few functions from stmmac_platform we can now create a proper probe function in this driver. By doing so we can drop the OF match data and simplify the overall driver. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../ethernet/stmicro/stmmac/dwmac-lpc18xx.c | 59 ++++++++----------- 1 file changed, 23 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c index cb888d3ebbdc3..78e9d18618963 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c @@ -25,66 +25,53 @@ # define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0 # define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4 -struct lpc18xx_dwmac_priv_data { +static int lpc18xx_dwmac_probe(struct platform_device *pdev) +{ + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct regmap *reg; - int interface; -}; + u8 ethmode; + int ret; -static void *lpc18xx_dwmac_setup(struct platform_device *pdev) -{ - struct lpc18xx_dwmac_priv_data *dwmac; + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; - dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); - if (!dwmac) - return ERR_PTR(-ENOMEM); + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); - dwmac->interface = of_get_phy_mode(pdev->dev.of_node); - if (dwmac->interface < 0) - return ERR_PTR(dwmac->interface); + plat_dat->has_gmac = true; - dwmac->reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); - if (IS_ERR(dwmac->reg)) { - dev_err(&pdev->dev, "Syscon lookup failed\n"); - return dwmac->reg; + reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg"); + if (IS_ERR(reg)) { + dev_err(&pdev->dev, "syscon lookup failed\n"); + return PTR_ERR(reg); } - return dwmac; -} - -static int lpc18xx_dwmac_init(struct platform_device *pdev, void *priv) -{ - struct lpc18xx_dwmac_priv_data *dwmac = priv; - u8 ethmode; - - if (dwmac->interface == PHY_INTERFACE_MODE_MII) { + if (plat_dat->interface == PHY_INTERFACE_MODE_MII) { ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII; - } else if (dwmac->interface == PHY_INTERFACE_MODE_RMII) { + } else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) { ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII; } else { dev_err(&pdev->dev, "Only MII and RMII mode supported\n"); return -EINVAL; } - regmap_update_bits(dwmac->reg, LPC18XX_CREG_CREG6, + regmap_update_bits(reg, LPC18XX_CREG_CREG6, LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode); - return 0; + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); } -static const struct stmmac_of_data lpc18xx_dwmac_data = { - .has_gmac = 1, - .setup = lpc18xx_dwmac_setup, - .init = lpc18xx_dwmac_init, -}; - static const struct of_device_id lpc18xx_dwmac_match[] = { - { .compatible = "nxp,lpc1850-dwmac", .data = &lpc18xx_dwmac_data }, + { .compatible = "nxp,lpc1850-dwmac" }, { } }; MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match); static struct platform_driver lpc18xx_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = lpc18xx_dwmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "lpc18xx-dwmac", -- GitLab From 1734befd0694c9e430d2c84445eceb6a7bbe1008 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:11 +0200 Subject: [PATCH 1307/7006] stmmac: add proper probe function to dwmac-meson By using a few functions from stmmac_platform we can now create a proper probe function in this driver. By doing so we can drop the OF match data and simplify the overall driver. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- .../net/ethernet/stmicro/stmmac/dwmac-meson.c | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c index 61a324a87d09e..c1bac1912b371 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c @@ -47,36 +47,45 @@ static void meson6_dwmac_fix_mac_speed(void *priv, unsigned int speed) writel(val, dwmac->reg); } -static void *meson6_dwmac_setup(struct platform_device *pdev) +static int meson6_dwmac_probe(struct platform_device *pdev) { + struct plat_stmmacenet_data *plat_dat; + struct stmmac_resources stmmac_res; struct meson_dwmac *dwmac; struct resource *res; + int ret; + + ret = stmmac_get_platform_resources(pdev, &stmmac_res); + if (ret) + return ret; + + plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); + if (IS_ERR(plat_dat)) + return PTR_ERR(plat_dat); dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL); if (!dwmac) - return ERR_PTR(-ENOMEM); + return -ENOMEM; res = platform_get_resource(pdev, IORESOURCE_MEM, 1); dwmac->reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(dwmac->reg)) - return ERR_CAST(dwmac->reg); + return PTR_ERR(dwmac->reg); - return dwmac; -} + plat_dat->bsp_priv = dwmac; + plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed; -static const struct stmmac_of_data meson6_dwmac_data = { - .setup = meson6_dwmac_setup, - .fix_mac_speed = meson6_dwmac_fix_mac_speed, -}; + return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res); +} static const struct of_device_id meson6_dwmac_match[] = { - { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data}, + { .compatible = "amlogic,meson6-dwmac" }, { } }; MODULE_DEVICE_TABLE(of, meson6_dwmac_match); static struct platform_driver meson6_dwmac_driver = { - .probe = stmmac_pltfr_probe, + .probe = meson6_dwmac_probe, .remove = stmmac_pltfr_remove, .driver = { .name = "meson6-dwmac", -- GitLab From f4c190eb8b4f80b12dc98ce7d54a3bea0e4e7e69 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 17 Jul 2015 00:26:12 +0200 Subject: [PATCH 1308/7006] stmmac: drop custom_* fields from plat_stmmacenet_data Both of these fields are unused and has been unused since they were added 3 and 5 years ago. Drop them since they are clearly not very useful. Signed-off-by: Joachim Eastwood Signed-off-by: David S. Miller --- Documentation/networking/stmmac.txt | 4 ---- include/linux/stmmac.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index e655e2453c984..5fddefa69baf2 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -139,8 +139,6 @@ struct plat_stmmacenet_data { void (*free)(struct platform_device *pdev, void *priv); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); - void *custom_cfg; - void *custom_data; void *bsp_priv; }; @@ -186,8 +184,6 @@ Where: which will be stored in bsp_priv, and then passed to init and exit callbacks. init/exit callbacks should not use or modify platform data. - o custom_cfg/custom_data: this is a custom configuration that can be passed - while initializing the resources. o bsp_priv: another private pointer. For MDIO bus The we have: diff --git a/include/linux/stmmac.h b/include/linux/stmmac.h index c735f5c91eead..c86a20047cb10 100644 --- a/include/linux/stmmac.h +++ b/include/linux/stmmac.h @@ -123,8 +123,6 @@ struct plat_stmmacenet_data { void (*free)(struct platform_device *pdev, void *priv); int (*init)(struct platform_device *pdev, void *priv); void (*exit)(struct platform_device *pdev, void *priv); - void *custom_cfg; - void *custom_data; void *bsp_priv; }; -- GitLab From 6ac3ce8295e6763b86e5a7bfd61275f51e0a3fd3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:14 -0700 Subject: [PATCH 1309/7006] net: bcmgenet: Remove excessive PHY reset We are currently issuing multiple PHY resets during a suspend/resume, first during bcmgenet_power_up() which does a hardware reset, then a software reset by calling bcmgenet_mii_reset(). This is both unnecessary and can take as long as 10ms per MDIO transactions while we re-apply workarounds because we do not yet have MDIO interrupts enabled. phy_resume() takes care of re-apply our workarounds in case we need any, and bcmgenet_power_up() does a PHY hardware reset, all of this is more than enough to guarantee that the PHY operates correctly. Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 3 --- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 1 - drivers/net/ethernet/broadcom/genet/bcmmii.c | 11 ----------- 3 files changed, 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 64c1e9db6b0b5..674f374dceee6 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -907,9 +907,6 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, } bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); - - if (mode == GENET_POWER_PASSIVE) - bcmgenet_mii_reset(priv->dev); } /* ioctl handle special commands that are not present in ethtool. */ diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 6159deab8c985..9f9ac0089d4d4 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -672,7 +672,6 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); int bcmgenet_mii_init(struct net_device *dev); int bcmgenet_mii_config(struct net_device *dev, bool init); void bcmgenet_mii_exit(struct net_device *dev); -void bcmgenet_mii_reset(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); void bcmgenet_mii_setup(struct net_device *dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index adf23d2ac4888..c5f9c7b5d9e7e 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -163,16 +163,6 @@ void bcmgenet_mii_setup(struct net_device *dev) phy_print_status(phydev); } -void bcmgenet_mii_reset(struct net_device *dev) -{ - struct bcmgenet_priv *priv = netdev_priv(dev); - - if (priv->phydev) { - phy_init_hw(priv->phydev); - phy_start_aneg(priv->phydev); - } -} - void bcmgenet_phy_power_set(struct net_device *dev, bool enable) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -215,7 +205,6 @@ static void bcmgenet_internal_phy_setup(struct net_device *dev) reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_PWR_DN_EN_LD; bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); - bcmgenet_mii_reset(dev); } static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) -- GitLab From 978ffac4189e8bb7e74bce6463e501a7b92555af Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:15 -0700 Subject: [PATCH 1310/7006] net: bcmgenet: Use correct dev_id for free_irq bcmgenet_open()'s error path call free_irq() with a dev_id argument different from the one we used to call request_irq() with, this will make us trip over the warning in kernel/irq/manage.c:__free_irq() Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 674f374dceee6..c634ddbbd21d1 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2695,7 +2695,7 @@ static int bcmgenet_open(struct net_device *dev) return 0; err_irq0: - free_irq(priv->irq0, dev); + free_irq(priv->irq0, priv); err_fini_dma: bcmgenet_fini_dma(priv); err_clk_disable: -- GitLab From bd4060a6108befd1110a4c6be5544c932895d18d Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:16 -0700 Subject: [PATCH 1311/7006] net: bcmgenet: Power on integrated GPHY in bcmgenet_power_up() We are currently disabling the GPHY interface during bcmgenet_close(), and attempting to power it back on during bcmgenet_open(). This works fine for the first time, because we called bcmgenet_mii_config() which took care of enabling the interface, however, bcmgenet_power_up() really needs to power on the GPHY for correctness. This will be particularly important as we want to move bcmgenet_mii_probe() down to bcmgenet_open() to avoid seeing the "PHY already attached" message. Fixes: a642c4f7906f36 ("net: bcmgenet: power up and down integrated GPHY when unused") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index c634ddbbd21d1..2efe72f94869b 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -907,6 +907,8 @@ static void bcmgenet_power_up(struct bcmgenet_priv *priv, } bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); + if (mode == GENET_POWER_PASSIVE) + bcmgenet_phy_power_set(priv->dev, true); } /* ioctl handle special commands that are not present in ethtool. */ -- GitLab From c624f89121020882b3db0a33cac8daf151d2930f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:17 -0700 Subject: [PATCH 1312/7006] net: bcmgenet: Determine PHY type before scanning MDIO bus Our internal GPHY might be powered off before we attempt scanning the MDIO bus and bind a driver to it. The way we are currently determining whether a PHY is internal or not is done *after* we have successfully matched its driver. If the PHY is powered down, it will not respond to the MDIO bus, so we will not be able to bind a driver to it. Our Device Tree for GENET interfaces specifies a "phy-mode" value: "internal" which tells if this internal uses an internal PHY or not. If of_get_phy_mode() fails to parse the 'phy-mode' property, do an additional manual lookup, and if we find "internal" set the corresponding internal variable accordingly. Replace all uses of phy_is_internal() with a check against priv->internal_phy to avoid having to rely on whether or not priv->phydev is set correctly. Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 14 ++++----- .../net/ethernet/broadcom/genet/bcmgenet.h | 1 + drivers/net/ethernet/broadcom/genet/bcmmii.c | 29 +++++++++++++++---- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 2efe72f94869b..0765654632262 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -1724,7 +1724,7 @@ static int init_umac(struct bcmgenet_priv *priv) int0_enable |= UMAC_IRQ_TXDMA_DONE; /* Monitor cable plug/unplugged event for internal PHY */ - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; } else if (priv->ext_phy) { int0_enable |= UMAC_IRQ_LINK_EVENT; @@ -2631,7 +2631,7 @@ static int bcmgenet_open(struct net_device *dev) /* If this is an internal GPHY, power it back on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed */ - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); /* take MAC out of reset */ @@ -2650,7 +2650,7 @@ static int bcmgenet_open(struct net_device *dev) bcmgenet_set_hw_addr(priv, dev->dev_addr); - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_ENERGY_DET_MASK; bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); @@ -2756,7 +2756,7 @@ static int bcmgenet_close(struct net_device *dev) free_irq(priv->irq0, priv); free_irq(priv->irq1, priv); - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); if (!IS_ERR(priv->clk)) @@ -3318,7 +3318,7 @@ static int bcmgenet_suspend(struct device *d) if (device_may_wakeup(d) && priv->wolopts) { ret = bcmgenet_power_down(priv, GENET_POWER_WOL_MAGIC); clk_prepare_enable(priv->clk_wol); - } else if (phy_is_internal(priv->phydev)) { + } else if (priv->internal_phy) { ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); } @@ -3347,7 +3347,7 @@ static int bcmgenet_resume(struct device *d) /* If this is an internal GPHY, power it back on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed */ - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) bcmgenet_power_up(priv, GENET_POWER_PASSIVE); bcmgenet_umac_reset(priv); @@ -3369,7 +3369,7 @@ static int bcmgenet_resume(struct device *d) bcmgenet_set_hw_addr(priv, dev->dev_addr); - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { reg = bcmgenet_ext_readl(priv, EXT_EXT_PWR_MGMT); reg |= EXT_ENERGY_DET_MASK; bcmgenet_ext_writel(priv, reg, EXT_EXT_PWR_MGMT); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 9f9ac0089d4d4..84274de836709 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -593,6 +593,7 @@ struct bcmgenet_priv { /* MDIO bus variables */ wait_queue_head_t wq; struct phy_device *phydev; + bool internal_phy; struct device_node *phy_dn; struct device_node *mdio_dn; struct mii_bus *mii_bus; diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index c5f9c7b5d9e7e..35df947e738c9 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -227,10 +227,10 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) u32 port_ctrl; u32 reg; - priv->ext_phy = !phy_is_internal(priv->phydev) && + priv->ext_phy = !priv->internal_phy && (priv->phy_interface != PHY_INTERFACE_MODE_MOCA); - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) priv->phy_interface = PHY_INTERFACE_MODE_NA; switch (priv->phy_interface) { @@ -248,7 +248,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) bcmgenet_sys_writel(priv, port_ctrl, SYS_PORT_CTRL); - if (phy_is_internal(priv->phydev)) { + if (priv->internal_phy) { phy_name = "internal PHY"; bcmgenet_internal_phy_setup(dev); } else if (priv->phy_interface == PHY_INTERFACE_MODE_MOCA) { @@ -386,7 +386,7 @@ static int bcmgenet_mii_probe(struct net_device *dev) /* The internal PHY has its link interrupts routed to the * Ethernet MAC ISRs */ - if (phy_is_internal(priv->phydev)) + if (priv->internal_phy) priv->mii_bus->irq[phydev->addr] = PHY_IGNORE_INTERRUPT; else priv->mii_bus->irq[phydev->addr] = PHY_POLL; @@ -479,7 +479,9 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) { struct device_node *dn = priv->pdev->dev.of_node; struct device *kdev = &priv->pdev->dev; + const char *phy_mode_str = NULL; char *compat; + int phy_mode; int ret; compat = kasprintf(GFP_KERNEL, "brcm,genet-mdio-v%d", priv->version); @@ -503,7 +505,24 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0); /* Get the link mode */ - priv->phy_interface = of_get_phy_mode(dn); + phy_mode = of_get_phy_mode(dn); + priv->phy_interface = phy_mode; + + /* We need to specifically look up whether this PHY interface is internal + * or not *before* we even try to probe the PHY driver over MDIO as we + * may have shut down the internal PHY for power saving purposes. + */ + if (phy_mode < 0) { + ret = of_property_read_string(dn, "phy-mode", &phy_mode_str); + if (ret < 0) { + dev_err(kdev, "invalid PHY mode property\n"); + return ret; + } + + priv->phy_interface = PHY_INTERFACE_MODE_NA; + if (!strcasecmp(phy_mode_str, "internal")) + priv->internal_phy = true; + } return 0; } -- GitLab From 6cc8e6d4dcb3651eea9b01db3e195fffb19fb24f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:18 -0700 Subject: [PATCH 1313/7006] net: bcmgenet: Delay PHY initialization to bcmgenet_open() We are currently doing a full PHY initialization and even starting the pHY state machine during bcmgenet_mii_init() which is executed in the driver's probe function. This is convenient to determine whether we can attach to a proper PHY device but comes at the expense of spending up to 10ms per MDIO transactions (to reach the waitqueue timeout), which slows things down. This also creates a sitaution where we end-up attaching twice to the PHY, which is not quite correct either. Fix this by moving bcmgenet_mii_probe() into bcmgenet_open() and update its error path accordingly. Avoid printing the message "attached PHY at address 1 [...]" every time we bring up/down the interface and remove this print since it duplicates what the PHY driver already does for us. Fixes: 1c1008c793fa4 ("net: bcmgenet: add main driver file") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 12 +++--- .../net/ethernet/broadcom/genet/bcmgenet.h | 1 + drivers/net/ethernet/broadcom/genet/bcmmii.c | 37 ++++++------------- 3 files changed, 20 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 0765654632262..fbab7757adfab 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2686,16 +2686,18 @@ static int bcmgenet_open(struct net_device *dev) goto err_irq0; } - /* Re-configure the port multiplexer towards the PHY device */ - bcmgenet_mii_config(priv->dev, false); - - phy_connect_direct(dev, priv->phydev, bcmgenet_mii_setup, - priv->phy_interface); + ret = bcmgenet_mii_probe(dev); + if (ret) { + netdev_err(dev, "failed to connect to PHY\n"); + goto err_irq1; + } bcmgenet_netif_start(dev); return 0; +err_irq1: + free_irq(priv->irq1, priv); err_irq0: free_irq(priv->irq0, priv); err_fini_dma: diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index 84274de836709..e25b5327cc40c 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -672,6 +672,7 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); /* MDIO routines */ int bcmgenet_mii_init(struct net_device *dev); int bcmgenet_mii_config(struct net_device *dev, bool init); +int bcmgenet_mii_probe(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); void bcmgenet_mii_setup(struct net_device *dev); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 35df947e738c9..b503897a0da33 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -316,7 +316,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) return 0; } -static int bcmgenet_mii_probe(struct net_device *dev) +int bcmgenet_mii_probe(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); struct device_node *dn = priv->pdev->dev.of_node; @@ -334,22 +334,6 @@ static int bcmgenet_mii_probe(struct net_device *dev) priv->old_pause = -1; if (dn) { - if (priv->phydev) { - pr_info("PHY already attached\n"); - return 0; - } - - /* In the case of a fixed PHY, the DT node associated - * to the PHY is the Ethernet MAC DT node. - */ - if (!priv->phy_dn && of_phy_is_fixed_link(dn)) { - ret = of_phy_register_fixed_link(dn); - if (ret) - return ret; - - priv->phy_dn = of_node_get(dn); - } - phydev = of_phy_connect(dev, priv->phy_dn, bcmgenet_mii_setup, phy_flags, priv->phy_interface); if (!phydev) { @@ -391,9 +375,6 @@ static int bcmgenet_mii_probe(struct net_device *dev) else priv->mii_bus->irq[phydev->addr] = PHY_POLL; - pr_info("attached PHY at address %d [%s]\n", - phydev->addr, phydev->drv->name); - return 0; } @@ -504,6 +485,17 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) /* Fetch the PHY phandle */ priv->phy_dn = of_parse_phandle(dn, "phy-handle", 0); + /* In the case of a fixed PHY, the DT node associated + * to the PHY is the Ethernet MAC DT node. + */ + if (!priv->phy_dn && of_phy_is_fixed_link(dn)) { + ret = of_phy_register_fixed_link(dn); + if (ret) + return ret; + + priv->phy_dn = of_node_get(dn); + } + /* Get the link mode */ phy_mode = of_get_phy_mode(dn); priv->phy_interface = phy_mode; @@ -622,10 +614,6 @@ int bcmgenet_mii_init(struct net_device *dev) return ret; ret = bcmgenet_mii_bus_init(priv); - if (ret) - goto out_free; - - ret = bcmgenet_mii_probe(dev); if (ret) goto out; @@ -634,7 +622,6 @@ int bcmgenet_mii_init(struct net_device *dev) out: of_node_put(priv->phy_dn); mdiobus_unregister(priv->mii_bus); -out_free: kfree(priv->mii_bus->irq); mdiobus_free(priv->mii_bus); return ret; -- GitLab From 28b45910ccda7b3e4de61b24a6f34d5fb1da90d2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Thu, 16 Jul 2015 15:51:19 -0700 Subject: [PATCH 1314/7006] net: bcmgenet: Remove init parameter from bcmgenet_mii_config Now that we have reworked the way we perform the PHY initialization, we no longer need to differentiate between init time vs. non-init time calls, just use a dev_info_once() print to print the PHY type. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmgenet.c | 2 +- drivers/net/ethernet/broadcom/genet/bcmgenet.h | 2 +- drivers/net/ethernet/broadcom/genet/bcmmii.c | 7 +++---- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index fbab7757adfab..5bf7ce0ae2215 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -3364,7 +3364,7 @@ static int bcmgenet_resume(struct device *d) phy_init_hw(priv->phydev); /* Speed settings must be restored */ - bcmgenet_mii_config(priv->dev, false); + bcmgenet_mii_config(priv->dev); /* disable ethernet MAC while updating its registers */ umac_enable_set(priv, CMD_TX_EN | CMD_RX_EN, false); diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.h b/drivers/net/ethernet/broadcom/genet/bcmgenet.h index e25b5327cc40c..7299d10754226 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.h +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.h @@ -671,7 +671,7 @@ GENET_IO_MACRO(rbuf, GENET_RBUF_OFF); /* MDIO routines */ int bcmgenet_mii_init(struct net_device *dev); -int bcmgenet_mii_config(struct net_device *dev, bool init); +int bcmgenet_mii_config(struct net_device *dev); int bcmgenet_mii_probe(struct net_device *dev); void bcmgenet_mii_exit(struct net_device *dev); void bcmgenet_phy_power_set(struct net_device *dev, bool enable); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index b503897a0da33..0802cd9d2424f 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -217,7 +217,7 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL); } -int bcmgenet_mii_config(struct net_device *dev, bool init) +int bcmgenet_mii_config(struct net_device *dev) { struct bcmgenet_priv *priv = netdev_priv(dev); struct phy_device *phydev = priv->phydev; @@ -310,8 +310,7 @@ int bcmgenet_mii_config(struct net_device *dev, bool init) bcmgenet_ext_writel(priv, reg, EXT_RGMII_OOB_CTRL); } - if (init) - dev_info(kdev, "configuring instance for %s\n", phy_name); + dev_info_once(kdev, "configuring instance for %s\n", phy_name); return 0; } @@ -359,7 +358,7 @@ int bcmgenet_mii_probe(struct net_device *dev) * PHY speed which is needed for bcmgenet_mii_config() to configure * things appropriately. */ - ret = bcmgenet_mii_config(dev, true); + ret = bcmgenet_mii_config(dev); if (ret) { phy_disconnect(priv->phydev); return ret; -- GitLab From 4e10df9a60d96ced321dd2af71da558c6b750078 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 20 Jul 2015 20:34:18 -0700 Subject: [PATCH 1315/7006] bpf: introduce bpf_skb_vlan_push/pop() helpers Allow eBPF programs attached to TC qdiscs call skb_vlan_push/pop via helper functions. These functions may change skb->data/hlen which are cached by some JITs to improve performance of ld_abs/ld_ind instructions. Therefore JITs need to recognize bpf_skb_vlan_push/pop() calls, re-compute header len and re-cache skb->data/hlen back into cpu registers. Note, skb->data/hlen are not directly accessible from the programs, so any changes to skb->data done either by these helpers or by other TC actions are safe. eBPF JIT supported by three architectures: - arm64 JIT is using bpf_load_pointer() without caching, so it's ok as-is. - x64 JIT re-caches skb->data/hlen unconditionally after vlan_push/pop calls (experiments showed that conditional re-caching is slower). - s390 JIT falls back to interpreter for now when bpf_skb_vlan_push() is present in the program (re-caching is tbd). These helpers allow more scalable handling of vlan from the programs. Instead of creating thousands of vlan netdevs on top of eth0 and attaching TC+ingress+bpf to all of them, the program can be attached to eth0 directly and manipulate vlans as necessary. Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- arch/s390/net/bpf_jit_comp.c | 4 ++ arch/x86/net/bpf_jit_comp.c | 80 +++++++++++++++++++----------------- include/linux/bpf.h | 2 + include/linux/filter.h | 1 + include/uapi/linux/bpf.h | 2 + net/core/filter.c | 48 ++++++++++++++++++++++ 6 files changed, 99 insertions(+), 38 deletions(-) diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c index fee782acc2ee5..79c731e8d1780 100644 --- a/arch/s390/net/bpf_jit_comp.c +++ b/arch/s390/net/bpf_jit_comp.c @@ -973,6 +973,10 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp, int i */ const u64 func = (u64)__bpf_call_base + imm; + if (bpf_helper_changes_skb_data((void *)func)) + /* TODO reload skb->data, hlen */ + return -1; + REG_SET_SEEN(BPF_REG_5); jit->seen |= SEEN_FUNC; /* lg %w1,(%l) */ diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 579a8fd74be07..6c335a8fc086b 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -315,6 +315,26 @@ static void emit_bpf_tail_call(u8 **pprog) *pprog = prog; } + +static void emit_load_skb_data_hlen(u8 **pprog) +{ + u8 *prog = *pprog; + int cnt = 0; + + /* r9d = skb->len - skb->data_len (headlen) + * r10 = skb->data + */ + /* mov %r9d, off32(%rdi) */ + EMIT3_off32(0x44, 0x8b, 0x8f, offsetof(struct sk_buff, len)); + + /* sub %r9d, off32(%rdi) */ + EMIT3_off32(0x44, 0x2b, 0x8f, offsetof(struct sk_buff, data_len)); + + /* mov %r10, off32(%rdi) */ + EMIT3_off32(0x4c, 0x8b, 0x97, offsetof(struct sk_buff, data)); + *pprog = prog; +} + static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, int oldproglen, struct jit_context *ctx) { @@ -329,36 +349,8 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, emit_prologue(&prog); - if (seen_ld_abs) { - /* r9d : skb->len - skb->data_len (headlen) - * r10 : skb->data - */ - if (is_imm8(offsetof(struct sk_buff, len))) - /* mov %r9d, off8(%rdi) */ - EMIT4(0x44, 0x8b, 0x4f, - offsetof(struct sk_buff, len)); - else - /* mov %r9d, off32(%rdi) */ - EMIT3_off32(0x44, 0x8b, 0x8f, - offsetof(struct sk_buff, len)); - - if (is_imm8(offsetof(struct sk_buff, data_len))) - /* sub %r9d, off8(%rdi) */ - EMIT4(0x44, 0x2b, 0x4f, - offsetof(struct sk_buff, data_len)); - else - EMIT3_off32(0x44, 0x2b, 0x8f, - offsetof(struct sk_buff, data_len)); - - if (is_imm8(offsetof(struct sk_buff, data))) - /* mov %r10, off8(%rdi) */ - EMIT4(0x4c, 0x8b, 0x57, - offsetof(struct sk_buff, data)); - else - /* mov %r10, off32(%rdi) */ - EMIT3_off32(0x4c, 0x8b, 0x97, - offsetof(struct sk_buff, data)); - } + if (seen_ld_abs) + emit_load_skb_data_hlen(&prog); for (i = 0; i < insn_cnt; i++, insn++) { const s32 imm32 = insn->imm; @@ -367,6 +359,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 b1 = 0, b2 = 0, b3 = 0; s64 jmp_offset; u8 jmp_cond; + bool reload_skb_data; int ilen; u8 *func; @@ -818,12 +811,18 @@ xadd: if (is_imm8(insn->off)) func = (u8 *) __bpf_call_base + imm32; jmp_offset = func - (image + addrs[i]); if (seen_ld_abs) { - EMIT2(0x41, 0x52); /* push %r10 */ - EMIT2(0x41, 0x51); /* push %r9 */ - /* need to adjust jmp offset, since - * pop %r9, pop %r10 take 4 bytes after call insn - */ - jmp_offset += 4; + reload_skb_data = bpf_helper_changes_skb_data(func); + if (reload_skb_data) { + EMIT1(0x57); /* push %rdi */ + jmp_offset += 22; /* pop, mov, sub, mov */ + } else { + EMIT2(0x41, 0x52); /* push %r10 */ + EMIT2(0x41, 0x51); /* push %r9 */ + /* need to adjust jmp offset, since + * pop %r9, pop %r10 take 4 bytes after call insn + */ + jmp_offset += 4; + } } if (!imm32 || !is_simm32(jmp_offset)) { pr_err("unsupported bpf func %d addr %p image %p\n", @@ -832,8 +831,13 @@ xadd: if (is_imm8(insn->off)) } EMIT1_off32(0xE8, jmp_offset); if (seen_ld_abs) { - EMIT2(0x41, 0x59); /* pop %r9 */ - EMIT2(0x41, 0x5A); /* pop %r10 */ + if (reload_skb_data) { + EMIT1(0x5F); /* pop %rdi */ + emit_load_skb_data_hlen(&prog); + } else { + EMIT2(0x41, 0x59); /* pop %r9 */ + EMIT2(0x41, 0x5A); /* pop %r10 */ + } } break; diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 4383476a0d481..139d6d2e123fb 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -192,5 +192,7 @@ extern const struct bpf_func_proto bpf_ktime_get_ns_proto; extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto; extern const struct bpf_func_proto bpf_get_current_uid_gid_proto; extern const struct bpf_func_proto bpf_get_current_comm_proto; +extern const struct bpf_func_proto bpf_skb_vlan_push_proto; +extern const struct bpf_func_proto bpf_skb_vlan_pop_proto; #endif /* _LINUX_BPF_H */ diff --git a/include/linux/filter.h b/include/linux/filter.h index 17724f6ea983c..69d00555ce352 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -411,6 +411,7 @@ void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp); u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); void bpf_int_jit_compile(struct bpf_prog *fp); +bool bpf_helper_changes_skb_data(void *func); #ifdef CONFIG_BPF_JIT typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 2de87e58b12b0..2f6c83d714e95 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -256,6 +256,8 @@ enum bpf_func_id { * Return: classid if != 0 */ BPF_FUNC_get_cgroup_classid, + BPF_FUNC_skb_vlan_push, /* bpf_skb_vlan_push(skb, vlan_proto, vlan_tci) */ + BPF_FUNC_skb_vlan_pop, /* bpf_skb_vlan_pop(skb) */ __BPF_FUNC_MAX_ID, }; diff --git a/net/core/filter.c b/net/core/filter.c index 247450a5e3879..50338071fac48 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1437,6 +1437,50 @@ static const struct bpf_func_proto bpf_get_cgroup_classid_proto = { .arg1_type = ARG_PTR_TO_CTX, }; +static u64 bpf_skb_vlan_push(u64 r1, u64 r2, u64 vlan_tci, u64 r4, u64 r5) +{ + struct sk_buff *skb = (struct sk_buff *) (long) r1; + __be16 vlan_proto = (__force __be16) r2; + + if (unlikely(vlan_proto != htons(ETH_P_8021Q) && + vlan_proto != htons(ETH_P_8021AD))) + vlan_proto = htons(ETH_P_8021Q); + + return skb_vlan_push(skb, vlan_proto, vlan_tci); +} + +const struct bpf_func_proto bpf_skb_vlan_push_proto = { + .func = bpf_skb_vlan_push, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, + .arg2_type = ARG_ANYTHING, + .arg3_type = ARG_ANYTHING, +}; + +static u64 bpf_skb_vlan_pop(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) +{ + struct sk_buff *skb = (struct sk_buff *) (long) r1; + + return skb_vlan_pop(skb); +} + +const struct bpf_func_proto bpf_skb_vlan_pop_proto = { + .func = bpf_skb_vlan_pop, + .gpl_only = false, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_CTX, +}; + +bool bpf_helper_changes_skb_data(void *func) +{ + if (func == bpf_skb_vlan_push) + return true; + if (func == bpf_skb_vlan_pop) + return true; + return false; +} + static const struct bpf_func_proto * sk_filter_func_proto(enum bpf_func_id func_id) { @@ -1476,6 +1520,10 @@ tc_cls_act_func_proto(enum bpf_func_id func_id) return &bpf_clone_redirect_proto; case BPF_FUNC_get_cgroup_classid: return &bpf_get_cgroup_classid_proto; + case BPF_FUNC_skb_vlan_push: + return &bpf_skb_vlan_push_proto; + case BPF_FUNC_skb_vlan_pop: + return &bpf_skb_vlan_pop_proto; default: return sk_filter_func_proto(func_id); } -- GitLab From 4d9c5c53ac99e4cb5d031897863203d7817b36e0 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 20 Jul 2015 20:34:19 -0700 Subject: [PATCH 1316/7006] test_bpf: add bpf_skb_vlan_push/pop() tests improve accuracy of timing in test_bpf and add two stress tests: - {skb->data[0], get_smp_processor_id} repeated 2k times - {skb->data[0], vlan_push} x 68 followed by {skb->data[0], vlan_pop} x 68 1st test is useful to test performance of JIT implementation of BPF_LD_ABS together with BPF_CALL instructions. 2nd test is stressing skb_vlan_push/pop logic together with skb->data access via BPF_LD_ABS insn which checks that re-caching of skb->data is done correctly. In order to call bpf_skb_vlan_push() from test_bpf.ko have to add three export_symbol_gpl. Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- kernel/bpf/core.c | 1 + lib/test_bpf.c | 98 +++++++++++++++++++++++++++++++++++++++++++++-- net/core/filter.c | 2 + 3 files changed, 98 insertions(+), 3 deletions(-) diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index bf38f5e8196c1..fafa741614453 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -177,6 +177,7 @@ noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) { return 0; } +EXPORT_SYMBOL_GPL(__bpf_call_base); /** * __bpf_prog_run - run eBPF program on a given context diff --git a/lib/test_bpf.c b/lib/test_bpf.c index 9198f28a5528f..8b5e66f008b0d 100644 --- a/lib/test_bpf.c +++ b/lib/test_bpf.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -355,6 +356,81 @@ static int bpf_fill_ja(struct bpf_test *self) return __bpf_fill_ja(self, 12, 9); } +static int bpf_fill_ld_abs_get_processor_id(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct sock_filter *insn; + int i; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + for (i = 0; i < len - 1; i += 2) { + insn[i] = __BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 0); + insn[i + 1] = __BPF_STMT(BPF_LD | BPF_W | BPF_ABS, + SKF_AD_OFF + SKF_AD_CPU); + } + + insn[len - 1] = __BPF_STMT(BPF_RET | BPF_K, 0xbee); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + +#define PUSH_CNT 68 +/* test: {skb->data[0], vlan_push} x 68 + {skb->data[0], vlan_pop} x 68 */ +static int bpf_fill_ld_abs_vlan_push_pop(struct bpf_test *self) +{ + unsigned int len = BPF_MAXINSNS; + struct bpf_insn *insn; + int i = 0, j, k = 0; + + insn = kmalloc_array(len, sizeof(*insn), GFP_KERNEL); + if (!insn) + return -ENOMEM; + + insn[i++] = BPF_MOV64_REG(R6, R1); +loop: + for (j = 0; j < PUSH_CNT; j++) { + insn[i++] = BPF_LD_ABS(BPF_B, 0); + insn[i] = BPF_JMP_IMM(BPF_JNE, R0, 0x34, len - i - 2); + i++; + insn[i++] = BPF_MOV64_REG(R1, R6); + insn[i++] = BPF_MOV64_IMM(R2, 1); + insn[i++] = BPF_MOV64_IMM(R3, 2); + insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + bpf_skb_vlan_push_proto.func - __bpf_call_base); + insn[i] = BPF_JMP_IMM(BPF_JNE, R0, 0, len - i - 2); + i++; + } + + for (j = 0; j < PUSH_CNT; j++) { + insn[i++] = BPF_LD_ABS(BPF_B, 0); + insn[i] = BPF_JMP_IMM(BPF_JNE, R0, 0x34, len - i - 2); + i++; + insn[i++] = BPF_MOV64_REG(R1, R6); + insn[i++] = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + bpf_skb_vlan_pop_proto.func - __bpf_call_base); + insn[i] = BPF_JMP_IMM(BPF_JNE, R0, 0, len - i - 2); + i++; + } + if (++k < 5) + goto loop; + + for (; i < len - 1; i++) + insn[i] = BPF_ALU32_IMM(BPF_MOV, R0, 0xbef); + + insn[len - 1] = BPF_EXIT_INSN(); + + self->u.ptr.insns = insn; + self->u.ptr.len = len; + + return 0; +} + static struct bpf_test tests[] = { { "TAX", @@ -4398,6 +4474,22 @@ static struct bpf_test tests[] = { { { 0, 0xababcbac } }, .fill_helper = bpf_fill_maxinsns11, }, + { + "BPF_MAXINSNS: ld_abs+get_processor_id", + { }, + CLASSIC, + { }, + { { 1, 0xbee } }, + .fill_helper = bpf_fill_ld_abs_get_processor_id, + }, + { + "BPF_MAXINSNS: ld_abs+vlan_push/pop", + { }, + INTERNAL, + { 0x34 }, + { { 1, 0xbef } }, + .fill_helper = bpf_fill_ld_abs_vlan_push_pop, + }, }; static struct net_device dev; @@ -4551,14 +4643,14 @@ static int __run_one(const struct bpf_prog *fp, const void *data, u64 start, finish; int ret = 0, i; - start = ktime_to_us(ktime_get()); + start = ktime_get_ns(); for (i = 0; i < runs; i++) ret = BPF_PROG_RUN(fp, data); - finish = ktime_to_us(ktime_get()); + finish = ktime_get_ns(); - *duration = (finish - start) * 1000ULL; + *duration = finish - start; do_div(*duration, runs); return ret; diff --git a/net/core/filter.c b/net/core/filter.c index 50338071fac48..786722a9c6f2b 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1457,6 +1457,7 @@ const struct bpf_func_proto bpf_skb_vlan_push_proto = { .arg2_type = ARG_ANYTHING, .arg3_type = ARG_ANYTHING, }; +EXPORT_SYMBOL_GPL(bpf_skb_vlan_push_proto); static u64 bpf_skb_vlan_pop(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) { @@ -1471,6 +1472,7 @@ const struct bpf_func_proto bpf_skb_vlan_pop_proto = { .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, }; +EXPORT_SYMBOL_GPL(bpf_skb_vlan_pop_proto); bool bpf_helper_changes_skb_data(void *func) { -- GitLab From ea70299d6e6961dd6adce2cbdf64e6e8a7ea97c0 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 9 Jul 2015 19:29:02 +0100 Subject: [PATCH 1317/7006] drm/i915: Add i915_gem_object_create_from_data() i915_gem_object_create_from_data() is a generic function to save data from a plain linear buffer in a new pageable gem object that can later be accessed by the CPU and/or GPU. We will need this for the microcontroller firmware loading support code. Derived from i915_gem_object_write(), originally by Alex Dai v2: Change of function: now allocates & fills a new object, rather than writing to an existing object New name courtesy of Chris Wilson Explicit domain-setting and other improvements per review comments by Chris Wilson & Daniel Vetter v4: Rebased Issue: VIZ-4884 Signed-off-by: Alex Dai Signed-off-by: Dave Gordon Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_gem.c | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 23ce125e0298e..77c23796f1199 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2758,6 +2758,8 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj, const struct drm_i915_gem_object_ops *ops); struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev, size_t size); +struct drm_i915_gem_object *i915_gem_object_create_from_data( + struct drm_device *dev, const void *data, size_t size); void i915_init_vm(struct drm_i915_private *dev_priv, struct i915_address_space *vm); void i915_gem_free_object(struct drm_gem_object *obj); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d9f2701b45932..322bbefafbc3a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5477,3 +5477,43 @@ bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) return false; } + +/* Allocate a new GEM object and fill it with the supplied data */ +struct drm_i915_gem_object * +i915_gem_object_create_from_data(struct drm_device *dev, + const void *data, size_t size) +{ + struct drm_i915_gem_object *obj; + struct sg_table *sg; + size_t bytes; + int ret; + + obj = i915_gem_alloc_object(dev, round_up(size, PAGE_SIZE)); + if (IS_ERR_OR_NULL(obj)) + return obj; + + ret = i915_gem_object_set_to_cpu_domain(obj, true); + if (ret) + goto fail; + + ret = i915_gem_object_get_pages(obj); + if (ret) + goto fail; + + i915_gem_object_pin_pages(obj); + sg = obj->pages; + bytes = sg_copy_from_buffer(sg->sgl, sg->nents, (void *)data, size); + i915_gem_object_unpin_pages(obj); + + if (WARN_ON(bytes != size)) { + DRM_ERROR("Incomplete copy, wrote %zu of %zu", bytes, size); + ret = -EFAULT; + goto fail; + } + + return obj; + +fail: + drm_gem_object_unreference(&obj->base); + return ERR_PTR(ret); +} -- GitLab From 63dc04498ace9cb657174e77373d6fcc85d6c492 Mon Sep 17 00:00:00 2001 From: Alex Dai Date: Thu, 9 Jul 2015 19:29:03 +0100 Subject: [PATCH 1318/7006] drm/i915: Add GuC-related module parameters Two new module parameters: "enable_guc_submission" which will turn on submission of batchbuffers via the GuC (when implemented), and "guc_log_level" which controls the level of debugging logged by the GuC and captured by the host. Signed-off-by: Alex Dai v4: Mark "enable_guc_submission" unsafe [Daniel Vetter] Signed-off-by: Dave Gordon Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/i915_params.c | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 77c23796f1199..b876e788e2f86 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2610,6 +2610,8 @@ struct i915_params { bool reset; bool disable_display; bool disable_vtd_wa; + bool enable_guc_submission; + int guc_log_level; int use_mmio_flip; int mmio_debug; bool verbose_state_checks; diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c index 5f4e7295295ff..5ae4b0aba5641 100644 --- a/drivers/gpu/drm/i915/i915_params.c +++ b/drivers/gpu/drm/i915/i915_params.c @@ -52,6 +52,8 @@ struct i915_params i915 __read_mostly = { .mmio_debug = 0, .verbose_state_checks = 1, .edp_vswing = 0, + .enable_guc_submission = false, + .guc_log_level = -1, }; module_param_named(modeset, i915.modeset, int, 0400); @@ -181,3 +183,10 @@ MODULE_PARM_DESC(edp_vswing, "Ignore/Override vswing pre-emph table selection from VBT " "(0=use value from vbt [default], 1=low power swing(200mV)," "2=default swing(400mV))"); + +module_param_named_unsafe(enable_guc_submission, i915.enable_guc_submission, bool, 0400); +MODULE_PARM_DESC(enable_guc_submission, "Enable GuC submission (default:false)"); + +module_param_named(guc_log_level, i915.guc_log_level, int, 0400); +MODULE_PARM_DESC(guc_log_level, + "GuC firmware logging level (-1:disabled (default), 0-3:enabled)"); -- GitLab From 2617268ff9d8f8b6901a07962c985d774b999e58 Mon Sep 17 00:00:00 2001 From: Dave Gordon Date: Thu, 9 Jul 2015 19:29:04 +0100 Subject: [PATCH 1319/7006] drm/i915: Add GuC-related header files intel_guc_fwif.h contains the subset of the GuC interface that we will need for submission of commands through the GuC. These MUST be kept in sync with the definitions used by the GuC firmware, and updates to this file will (or should) be autogenerated from the source files used to build the firmware. Editing this file is therefore not recommended. i915_guc_reg.h contains definitions of GuC-related hardware: registers, bitmasks, etc. These should match the BSpec. v2: Files renamed & resliced per review comments by Chris Wilson v4: Added DON'T-EDIT-ME warning [Tom O'Rourke] Issue: VIZ-4884 Signed-off-by: Alex Dai Signed-off-by: Dave Gordon Reviewed-by: Tom O'Rourke Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_guc_reg.h | 102 +++++++++++ drivers/gpu/drm/i915/intel_guc_fwif.h | 245 ++++++++++++++++++++++++++ 2 files changed, 347 insertions(+) create mode 100644 drivers/gpu/drm/i915/i915_guc_reg.h create mode 100644 drivers/gpu/drm/i915/intel_guc_fwif.h diff --git a/drivers/gpu/drm/i915/i915_guc_reg.h b/drivers/gpu/drm/i915/i915_guc_reg.h new file mode 100644 index 0000000000000..ccdc6c8ac20b0 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_guc_reg.h @@ -0,0 +1,102 @@ +/* + * Copyright © 2014 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. + * + */ +#ifndef _I915_GUC_REG_H_ +#define _I915_GUC_REG_H_ + +/* Definitions of GuC H/W registers, bits, etc */ + +#define GUC_STATUS 0xc000 +#define GS_BOOTROM_SHIFT 1 +#define GS_BOOTROM_MASK (0x7F << GS_BOOTROM_SHIFT) +#define GS_BOOTROM_RSA_FAILED (0x50 << GS_BOOTROM_SHIFT) +#define GS_UKERNEL_SHIFT 8 +#define GS_UKERNEL_MASK (0xFF << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_LAPIC_DONE (0x30 << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_DPC_ERROR (0x60 << GS_UKERNEL_SHIFT) +#define GS_UKERNEL_READY (0xF0 << GS_UKERNEL_SHIFT) +#define GS_MIA_SHIFT 16 +#define GS_MIA_MASK (0x07 << GS_MIA_SHIFT) + +#define GUC_WOPCM_SIZE 0xc050 +#define GUC_WOPCM_SIZE_VALUE (0x80 << 12) /* 512KB */ +#define GUC_WOPCM_OFFSET 0x80000 /* 512KB */ + +#define SOFT_SCRATCH(n) (0xc180 + ((n) * 4)) + +#define UOS_RSA_SCRATCH_0 0xc200 +#define DMA_ADDR_0_LOW 0xc300 +#define DMA_ADDR_0_HIGH 0xc304 +#define DMA_ADDR_1_LOW 0xc308 +#define DMA_ADDR_1_HIGH 0xc30c +#define DMA_ADDRESS_SPACE_WOPCM (7 << 16) +#define DMA_ADDRESS_SPACE_GTT (8 << 16) +#define DMA_COPY_SIZE 0xc310 +#define DMA_CTRL 0xc314 +#define UOS_MOVE (1<<4) +#define START_DMA (1<<0) +#define DMA_GUC_WOPCM_OFFSET 0xc340 + +#define GEN8_GT_PM_CONFIG 0x138140 +#define GEN9_GT_PM_CONFIG 0x13816c +#define GEN8_GT_DOORBELL_ENABLE (1<<0) + +#define GEN8_GTCR 0x4274 +#define GEN8_GTCR_INVALIDATE (1<<0) + +#define GUC_ARAT_C6DIS 0xA178 + +#define GUC_SHIM_CONTROL 0xc064 +#define GUC_DISABLE_SRAM_INIT_TO_ZEROES (1<<0) +#define GUC_ENABLE_READ_CACHE_LOGIC (1<<1) +#define GUC_ENABLE_MIA_CACHING (1<<2) +#define GUC_GEN10_MSGCH_ENABLE (1<<4) +#define GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA (1<<9) +#define GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA (1<<10) +#define GUC_ENABLE_MIA_CLOCK_GATING (1<<15) +#define GUC_GEN10_SHIM_WC_ENABLE (1<<21) + +#define GUC_SHIM_CONTROL_VALUE (GUC_DISABLE_SRAM_INIT_TO_ZEROES | \ + GUC_ENABLE_READ_CACHE_LOGIC | \ + GUC_ENABLE_MIA_CACHING | \ + GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA | \ + GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA) + +#define HOST2GUC_INTERRUPT 0xc4c8 +#define HOST2GUC_TRIGGER (1<<0) + +#define DRBMISC1 0x1984 +#define DOORBELL_ENABLE (1<<0) + +#define GEN8_DRBREGL(x) (0x1000 + (x) * 8) +#define GEN8_DRB_VALID (1<<0) +#define GEN8_DRBREGU(x) (GEN8_DRBREGL(x) + 4) + +#define DE_GUCRMR 0x44054 + +#define GUC_BCS_RCS_IER 0xC550 +#define GUC_VCS2_VCS1_IER 0xC554 +#define GUC_WD_VECS_IER 0xC558 +#define GUC_PM_P24C_IER 0xC55C + +#endif diff --git a/drivers/gpu/drm/i915/intel_guc_fwif.h b/drivers/gpu/drm/i915/intel_guc_fwif.h new file mode 100644 index 0000000000000..18d7f20936c8e --- /dev/null +++ b/drivers/gpu/drm/i915/intel_guc_fwif.h @@ -0,0 +1,245 @@ +/* + * Copyright © 2014 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. + */ +#ifndef _INTEL_GUC_FWIF_H +#define _INTEL_GUC_FWIF_H + +/* + * This file is partially autogenerated, although currently with some manual + * fixups afterwards. In future, it should be entirely autogenerated, in order + * to ensure that the definitions herein remain in sync with those used by the + * GuC's own firmware. + * + * EDITING THIS FILE IS THEREFORE NOT RECOMMENDED - YOUR CHANGES MAY BE LOST. + */ + +#define GFXCORE_FAMILY_GEN8 11 +#define GFXCORE_FAMILY_GEN9 12 +#define GFXCORE_FAMILY_FORCE_ULONG 0x7fffffff + +#define GUC_CTX_PRIORITY_CRITICAL 0 +#define GUC_CTX_PRIORITY_HIGH 1 +#define GUC_CTX_PRIORITY_NORMAL 2 +#define GUC_CTX_PRIORITY_LOW 3 + +#define GUC_MAX_GPU_CONTEXTS 1024 +#define GUC_INVALID_CTX_ID (GUC_MAX_GPU_CONTEXTS + 1) + +/* Work queue item header definitions */ +#define WQ_STATUS_ACTIVE 1 +#define WQ_STATUS_SUSPENDED 2 +#define WQ_STATUS_CMD_ERROR 3 +#define WQ_STATUS_ENGINE_ID_NOT_USED 4 +#define WQ_STATUS_SUSPENDED_FROM_RESET 5 +#define WQ_TYPE_SHIFT 0 +#define WQ_TYPE_BATCH_BUF (0x1 << WQ_TYPE_SHIFT) +#define WQ_TYPE_PSEUDO (0x2 << WQ_TYPE_SHIFT) +#define WQ_TYPE_INORDER (0x3 << WQ_TYPE_SHIFT) +#define WQ_TARGET_SHIFT 10 +#define WQ_LEN_SHIFT 16 +#define WQ_NO_WCFLUSH_WAIT (1 << 27) +#define WQ_PRESENT_WORKLOAD (1 << 28) +#define WQ_WORKLOAD_SHIFT 29 +#define WQ_WORKLOAD_GENERAL (0 << WQ_WORKLOAD_SHIFT) +#define WQ_WORKLOAD_GPGPU (1 << WQ_WORKLOAD_SHIFT) +#define WQ_WORKLOAD_TOUCH (2 << WQ_WORKLOAD_SHIFT) + +#define WQ_RING_TAIL_SHIFT 20 +#define WQ_RING_TAIL_MASK (0x7FF << WQ_RING_TAIL_SHIFT) + +#define GUC_DOORBELL_ENABLED 1 +#define GUC_DOORBELL_DISABLED 0 + +#define GUC_CTX_DESC_ATTR_ACTIVE (1 << 0) +#define GUC_CTX_DESC_ATTR_PENDING_DB (1 << 1) +#define GUC_CTX_DESC_ATTR_KERNEL (1 << 2) +#define GUC_CTX_DESC_ATTR_PREEMPT (1 << 3) +#define GUC_CTX_DESC_ATTR_RESET (1 << 4) +#define GUC_CTX_DESC_ATTR_WQLOCKED (1 << 5) +#define GUC_CTX_DESC_ATTR_PCH (1 << 6) + +/* The guc control data is 10 DWORDs */ +#define GUC_CTL_CTXINFO 0 +#define GUC_CTL_CTXNUM_IN16_SHIFT 0 +#define GUC_CTL_BASE_ADDR_SHIFT 12 +#define GUC_CTL_ARAT_HIGH 1 +#define GUC_CTL_ARAT_LOW 2 +#define GUC_CTL_DEVICE_INFO 3 +#define GUC_CTL_GTTYPE_SHIFT 0 +#define GUC_CTL_COREFAMILY_SHIFT 7 +#define GUC_CTL_LOG_PARAMS 4 +#define GUC_LOG_VALID (1 << 0) +#define GUC_LOG_NOTIFY_ON_HALF_FULL (1 << 1) +#define GUC_LOG_ALLOC_IN_MEGABYTE (1 << 3) +#define GUC_LOG_CRASH_PAGES 1 +#define GUC_LOG_CRASH_SHIFT 4 +#define GUC_LOG_DPC_PAGES 3 +#define GUC_LOG_DPC_SHIFT 6 +#define GUC_LOG_ISR_PAGES 3 +#define GUC_LOG_ISR_SHIFT 9 +#define GUC_LOG_BUF_ADDR_SHIFT 12 +#define GUC_CTL_PAGE_FAULT_CONTROL 5 +#define GUC_CTL_WA 6 +#define GUC_CTL_WA_UK_BY_DRIVER (1 << 3) +#define GUC_CTL_FEATURE 7 +#define GUC_CTL_VCS2_ENABLED (1 << 0) +#define GUC_CTL_KERNEL_SUBMISSIONS (1 << 1) +#define GUC_CTL_FEATURE2 (1 << 2) +#define GUC_CTL_POWER_GATING (1 << 3) +#define GUC_CTL_DISABLE_SCHEDULER (1 << 4) +#define GUC_CTL_PREEMPTION_LOG (1 << 5) +#define GUC_CTL_ENABLE_SLPC (1 << 7) +#define GUC_CTL_DEBUG 8 +#define GUC_LOG_VERBOSITY_SHIFT 0 +#define GUC_LOG_VERBOSITY_LOW (0 << GUC_LOG_VERBOSITY_SHIFT) +#define GUC_LOG_VERBOSITY_MED (1 << GUC_LOG_VERBOSITY_SHIFT) +#define GUC_LOG_VERBOSITY_HIGH (2 << GUC_LOG_VERBOSITY_SHIFT) +#define GUC_LOG_VERBOSITY_ULTRA (3 << GUC_LOG_VERBOSITY_SHIFT) +/* Verbosity range-check limits, without the shift */ +#define GUC_LOG_VERBOSITY_MIN 0 +#define GUC_LOG_VERBOSITY_MAX 3 + +#define GUC_CTL_MAX_DWORDS (GUC_CTL_DEBUG + 1) + +struct guc_doorbell_info { + u32 db_status; + u32 cookie; + u32 reserved[14]; +} __packed; + +union guc_doorbell_qw { + struct { + u32 db_status; + u32 cookie; + }; + u64 value_qw; +} __packed; + +#define GUC_MAX_DOORBELLS 256 +#define GUC_INVALID_DOORBELL_ID (GUC_MAX_DOORBELLS) + +#define GUC_DB_SIZE (PAGE_SIZE) +#define GUC_WQ_SIZE (PAGE_SIZE * 2) + +/* Work item for submitting workloads into work queue of GuC. */ +struct guc_wq_item { + u32 header; + u32 context_desc; + u32 ring_tail; + u32 fence_id; +} __packed; + +struct guc_process_desc { + u32 context_id; + u64 db_base_addr; + u32 head; + u32 tail; + u32 error_offset; + u64 wq_base_addr; + u32 wq_size_bytes; + u32 wq_status; + u32 engine_presence; + u32 priority; + u32 reserved[30]; +} __packed; + +/* engine id and context id is packed into guc_execlist_context.context_id*/ +#define GUC_ELC_CTXID_OFFSET 0 +#define GUC_ELC_ENGINE_OFFSET 29 + +/* The execlist context including software and HW information */ +struct guc_execlist_context { + u32 context_desc; + u32 context_id; + u32 ring_status; + u32 ring_lcra; + u32 ring_begin; + u32 ring_end; + u32 ring_next_free_location; + u32 ring_current_tail_pointer_value; + u8 engine_state_submit_value; + u8 engine_state_wait_value; + u16 pagefault_count; + u16 engine_submit_queue_count; +} __packed; + +/*Context descriptor for communicating between uKernel and Driver*/ +struct guc_context_desc { + u32 sched_common_area; + u32 context_id; + u32 pas_id; + u8 engines_used; + u64 db_trigger_cpu; + u32 db_trigger_uk; + u64 db_trigger_phy; + u16 db_id; + + struct guc_execlist_context lrc[I915_NUM_RINGS]; + + u8 attribute; + + u32 priority; + + u32 wq_sampled_tail_offset; + u32 wq_total_submit_enqueues; + + u32 process_desc; + u32 wq_addr; + u32 wq_size; + + u32 engine_presence; + + u32 reserved0[1]; + u64 reserved1[1]; + + u64 desc_private; +} __packed; + +/* This Action will be programmed in C180 - SOFT_SCRATCH_O_REG */ +enum host2guc_action { + HOST2GUC_ACTION_DEFAULT = 0x0, + HOST2GUC_ACTION_SAMPLE_FORCEWAKE = 0x6, + HOST2GUC_ACTION_ALLOCATE_DOORBELL = 0x10, + HOST2GUC_ACTION_DEALLOCATE_DOORBELL = 0x20, + HOST2GUC_ACTION_SLPC_REQUEST = 0x3003, + HOST2GUC_ACTION_LIMIT +}; + +/* + * The GuC sends its response to a command by overwriting the + * command in SS0. The response is distinguishable from a command + * by the fact that all the MASK bits are set. The remaining bits + * give more detail. + */ +#define GUC2HOST_RESPONSE_MASK ((u32)0xF0000000) +#define GUC2HOST_IS_RESPONSE(x) ((u32)(x) >= GUC2HOST_RESPONSE_MASK) +#define GUC2HOST_STATUS(x) (GUC2HOST_RESPONSE_MASK | (x)) + +/* GUC will return status back to SOFT_SCRATCH_O_REG */ +enum guc2host_status { + GUC2HOST_STATUS_SUCCESS = GUC2HOST_STATUS(0x0), + GUC2HOST_STATUS_ALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x10), + GUC2HOST_STATUS_DEALLOCATE_DOORBELL_FAIL = GUC2HOST_STATUS(0x20), + GUC2HOST_STATUS_GENERIC_FAIL = GUC2HOST_STATUS(0x0000F000) +}; + +#endif -- GitLab From f61687c01917946d2274dd8736bb8f9e2691ee5b Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 17 Jul 2015 11:19:46 +0800 Subject: [PATCH 1320/7006] phylib: add driver for Teranetics TN2020 Teranetics TN2020 is compliant with IEEE 802.3an 10 Gigabit. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/teranetics.c | 128 +++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+) create mode 100644 drivers/net/phy/teranetics.c diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index cb86d7a015422..d6aff873803cd 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -54,6 +54,11 @@ config VITESSE_PHY ---help--- Currently supports the vsc8244 +config TERANETICS_PHY + tristate "Drivers for the Teranetics PHYs" + ---help--- + Currently supports the Teranetics TN2020 + config SMSC_PHY tristate "Drivers for SMSC PHYs" ---help--- diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index fcc25a0c45cd0..16aac1c3e7036 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_CICADA_PHY) += cicada.o obj-$(CONFIG_LXT_PHY) += lxt.o obj-$(CONFIG_QSEMI_PHY) += qsemi.o obj-$(CONFIG_SMSC_PHY) += smsc.o +obj-$(CONFIG_TERANETICS_PHY) += teranetics.o obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c new file mode 100644 index 0000000000000..7dcb5aada1c41 --- /dev/null +++ b/drivers/net/phy/teranetics.c @@ -0,0 +1,128 @@ +/* + * Driver for Teranetics PHY + * + * Author: Shaohui Xie + * + * Copyright 2015 Freescale Semiconductor, Inc. + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Teranetics PHY driver"); +MODULE_AUTHOR("Shaohui Xie "); +MODULE_LICENSE("GPL v2"); + +#define PHY_ID_TN2020 0x00a19410 +#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 +#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 +#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004 +#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 +#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 + +#define MDIO_PHYXS_LANE_READY (MDIO_PHYXS_LNSTAT_SYNC0 | \ + MDIO_PHYXS_LNSTAT_SYNC1 | \ + MDIO_PHYXS_LNSTAT_SYNC2 | \ + MDIO_PHYXS_LNSTAT_SYNC3 | \ + MDIO_PHYXS_LNSTAT_ALIGN) + +static int teranetics_config_init(struct phy_device *phydev) +{ + phydev->supported = SUPPORTED_10000baseT_Full; + phydev->advertising = SUPPORTED_10000baseT_Full; + + return 0; +} + +static int teranetics_soft_reset(struct phy_device *phydev) +{ + return 0; +} + +static int teranetics_aneg_done(struct phy_device *phydev) +{ + int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); +} + +static int teranetics_config_aneg(struct phy_device *phydev) +{ + return 0; +} + +static int teranetics_read_status(struct phy_device *phydev) +{ + int reg; + + phydev->link = 1; + + phydev->speed = SPEED_10000; + phydev->duplex = DUPLEX_FULL; + + if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) { + reg = phy_read_mmd(phydev, MDIO_MMD_PHYXS, MDIO_PHYXS_LNSTAT); + if (reg < 0 || + !((reg & MDIO_PHYXS_LANE_READY) == MDIO_PHYXS_LANE_READY)) { + phydev->link = 0; + return 0; + } + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + if (reg < 0 || !(reg & MDIO_STAT1_LSTATUS)) + phydev->link = 0; + } + + return 0; +} + +static int teranetics_match_phy_device(struct phy_device *phydev) +{ + return phydev->c45_ids.device_ids[3] == PHY_ID_TN2020; +} + +static struct phy_driver teranetics_driver[] = { +{ + .phy_id = PHY_ID_TN2020, + .phy_id_mask = 0xffffffff, + .name = "Teranetics TN2020", + .soft_reset = teranetics_soft_reset, + .aneg_done = teranetics_aneg_done, + .config_init = teranetics_config_init, + .config_aneg = teranetics_config_aneg, + .read_status = teranetics_read_status, + .match_phy_device = teranetics_match_phy_device, + .driver = { .owner = THIS_MODULE,}, +}, +}; + +static int __init teranetics_init(void) +{ + return phy_drivers_register(teranetics_driver, + ARRAY_SIZE(teranetics_driver)); +} + +static void __exit teranetics_exit(void) +{ + return phy_drivers_unregister(teranetics_driver, + ARRAY_SIZE(teranetics_driver)); +} + +module_init(teranetics_init); +module_exit(teranetics_exit); + +static struct mdio_device_id __maybe_unused teranetics_tbl[] = { + { PHY_ID_TN2020, 0xffffffff }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, teranetics_tbl); -- GitLab From 685a015e44dcd4db50ada60a9a2806659c165d9e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 17 Jul 2015 10:52:48 +0200 Subject: [PATCH 1321/7006] rhashtable: Allow other tasks to be scheduled in large lookup loops Depending on system speed, the large lookup/insert/delete loops of the testsuite can take a considerable amount of time to complete causing watchdog warnings to appear. Allow other tasks to be scheduled throughout the loops. Reported-by: Meelis Roos Signed-off-by: Thomas Graf Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- lib/test_rhashtable.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/test_rhashtable.c b/lib/test_rhashtable.c index c90777eae1f83..9af7cefb195d3 100644 --- a/lib/test_rhashtable.c +++ b/lib/test_rhashtable.c @@ -20,6 +20,7 @@ #include #include #include +#include #define MAX_ENTRIES 1000000 #define TEST_INSERT_FAIL INT_MAX @@ -87,6 +88,8 @@ static int __init test_rht_lookup(struct rhashtable *ht) return -EINVAL; } } + + cond_resched_rcu(); } return 0; @@ -160,6 +163,8 @@ static s64 __init test_rhashtable(struct rhashtable *ht) } else if (err) { return err; } + + cond_resched(); } if (insert_fails) @@ -183,6 +188,8 @@ static s64 __init test_rhashtable(struct rhashtable *ht) rhashtable_remove_fast(ht, &obj->node, test_rht_params); } + + cond_resched(); } end = ktime_get_ns(); -- GitLab From 7177a3b037c7569c137c2703efe8187fdc4352b8 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Mon, 20 Jul 2015 09:54:50 +0200 Subject: [PATCH 1322/7006] net/vxlan: Fix kernel unaligned access in __vxlan_find_mac __vxlan_find_mac invokes ether_addr_equal on the eth_addr field, which triggers unaligned access messages, so rearrange vxlan_fdb to avoid this in the most non-intrusive way. Signed-off-by: Sowmini Varadhan Reviewed-by: Jiri Pirko Reviewed-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 34c519eb1db50..ec86a11743fdf 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -106,9 +106,9 @@ struct vxlan_fdb { unsigned long updated; /* jiffies */ unsigned long used; struct list_head remotes; + u8 eth_addr[ETH_ALEN]; u16 state; /* see ndm_state */ u8 flags; /* see ndm_flags */ - u8 eth_addr[ETH_ALEN]; }; /* Pseudo network device */ -- GitLab From 07868284e530d52f72b14b800398a8fefa7cf5d0 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Fri, 17 Jul 2015 12:34:17 -0300 Subject: [PATCH 1323/7006] sctp: reduce indent level on sctp_v4_get_dst Paves the day for the next patch. Functionality stays untouched. Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/protocol.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 59e80356672bd..fa80fe4f23629 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -489,21 +489,23 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, list_for_each_entry_rcu(laddr, &bp->address_list, list) { if (!laddr->valid) continue; - if ((laddr->state == SCTP_ADDR_SRC) && - (AF_INET == laddr->a.sa.sa_family)) { - fl4->fl4_sport = laddr->a.v4.sin_port; - flowi4_update_output(fl4, - asoc->base.sk->sk_bound_dev_if, - RT_CONN_FLAGS(asoc->base.sk), - daddr->v4.sin_addr.s_addr, - laddr->a.v4.sin_addr.s_addr); - - rt = ip_route_output_key(sock_net(sk), fl4); - if (!IS_ERR(rt)) { - dst = &rt->dst; - goto out_unlock; - } - } + if (laddr->state != SCTP_ADDR_SRC || + AF_INET != laddr->a.sa.sa_family) + continue; + + fl4->fl4_sport = laddr->a.v4.sin_port; + flowi4_update_output(fl4, + asoc->base.sk->sk_bound_dev_if, + RT_CONN_FLAGS(asoc->base.sk), + daddr->v4.sin_addr.s_addr, + laddr->a.v4.sin_addr.s_addr); + + rt = ip_route_output_key(sock_net(sk), fl4); + if (IS_ERR(rt)) + continue; + + dst = &rt->dst; + break; } out_unlock: -- GitLab From 0ca50d12fe46cdf3c0dc9ec5ca98607a52afdc62 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Fri, 17 Jul 2015 12:34:18 -0300 Subject: [PATCH 1324/7006] sctp: fix src address selection if using secondary addresses In short, sctp is likely to incorrectly choose src address if socket is bound to secondary addresses. This patch fixes it by adding a new check that checks if such src address belongs to the interface that routing identified as output. This is enough to avoid rp_filter drops on remote peer. Details: Currently, sctp will do a routing attempt without specifying the src address and compare the returned value (preferred source) with the addresses that the socket is bound to. When using secondary addresses, this will not match. Then it will try specifying each of the addresses that the socket is bound to and re-routing, checking if that address is valid as src for that dst. Thing is, this check alone is weak: # ip r l 192.168.100.0/24 dev eth1 proto kernel scope link src 192.168.100.149 192.168.122.0/24 dev eth0 proto kernel scope link src 192.168.122.147 # ip a l 1: lo: mtu 65536 qdisc noqueue state UNKNOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 52:54:00:15:18:6a brd ff:ff:ff:ff:ff:ff inet 192.168.122.147/24 brd 192.168.122.255 scope global dynamic eth0 valid_lft 2160sec preferred_lft 2160sec inet 192.168.122.148/24 scope global secondary eth0 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fe15:186a/64 scope link valid_lft forever preferred_lft forever 3: eth1: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 52:54:00:b3:91:46 brd ff:ff:ff:ff:ff:ff inet 192.168.100.149/24 brd 192.168.100.255 scope global dynamic eth1 valid_lft 2162sec preferred_lft 2162sec inet 192.168.100.148/24 scope global secondary eth1 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:feb3:9146/64 scope link valid_lft forever preferred_lft forever 4: ens9: mtu 1500 qdisc pfifo_fast state UP group default qlen 1000 link/ether 52:54:00:05:47:ee brd ff:ff:ff:ff:ff:ff inet6 fe80::5054:ff:fe05:47ee/64 scope link valid_lft forever preferred_lft forever # ip r g 192.168.100.193 from 192.168.122.148 192.168.100.193 from 192.168.122.148 dev eth1 cache Even if you specify an interface: # ip r g 192.168.100.193 from 192.168.122.148 oif eth1 192.168.100.193 from 192.168.122.148 dev eth1 cache Although this would be valid, peers using rp_filter will drop such packets as their src doesn't match the routes for that interface. Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/protocol.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index fa80fe4f23629..4345790ad3266 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -487,6 +487,8 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, */ rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { + struct net_device *odev; + if (!laddr->valid) continue; if (laddr->state != SCTP_ADDR_SRC || @@ -504,6 +506,14 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if (IS_ERR(rt)) continue; + /* Ensure the src address belongs to the output + * interface. + */ + odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, + false); + if (!odev || odev->ifindex != fl4->flowi4_oif) + continue; + dst = &rt->dst; break; } -- GitLab From b52effd263e0926cc52713703f53d0a6c77259a1 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Fri, 17 Jul 2015 13:50:21 -0300 Subject: [PATCH 1325/7006] sctp: fix cut and paste issue in comment Cookie ACK is always received by the association initiator, so fix the comment to avoid confusion. Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/sm_statefuns.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 3ee27b7704ffb..d7eaa7354cf76 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -853,7 +853,7 @@ nomem: /* * Respond to a normal COOKIE ACK chunk. - * We are the side that is being asked for an association. + * We are the side that is asking for an association. * * RFC 2960 5.1 Normal Establishment of an Association * -- GitLab From be9015abb8296d8dc72cef4da75fa30e88ab7c81 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:04 +0530 Subject: [PATCH 1326/7006] gpiolib: Add support for removing registered consumer lookup table MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In case we unload and load a driver module again that is registering a lookup table, without this it will result in multiple entries. Provide an option to remove the lookup table on driver unload Cc: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Reviewed-by: Alexandre Courbot Reviewed-by: Linus Walleij Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Acked-by: Lee Jones Signed-off-by: Daniel Vetter --- drivers/gpio/gpiolib.c | 13 +++++++++++++ include/linux/gpio/machine.h | 1 + 2 files changed, 14 insertions(+) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index bf4bd1d120c38..f25dc880b0073 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1672,6 +1672,19 @@ void gpiod_add_lookup_table(struct gpiod_lookup_table *table) mutex_unlock(&gpio_lookup_lock); } +/** + * gpiod_remove_lookup_table() - unregister GPIO device consumers + * @table: table of consumers to unregister + */ +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table) +{ + mutex_lock(&gpio_lookup_lock); + + list_del(&table->list); + + mutex_unlock(&gpio_lookup_lock); +} + static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id, unsigned int idx, enum gpio_lookup_flags *flags) diff --git a/include/linux/gpio/machine.h b/include/linux/gpio/machine.h index e2706140eafff..c0d712d22b079 100644 --- a/include/linux/gpio/machine.h +++ b/include/linux/gpio/machine.h @@ -57,5 +57,6 @@ struct gpiod_lookup_table { } void gpiod_add_lookup_table(struct gpiod_lookup_table *table); +void gpiod_remove_lookup_table(struct gpiod_lookup_table *table); #endif /* __LINUX_GPIO_MACHINE_H */ -- GitLab From 61dd2ca2d44e493b050adbbb75bc50db11c367dd Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:05 +0530 Subject: [PATCH 1327/7006] mfd: intel_soc_pmic_core: Add lookup table for Panel Control as GPIO signal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some Intel SoC platforms, the panel enable/disable signals are controlled by CRC PMIC. Add those control as a new GPIO in a lookup table for gpio-crystalcove chip during CRC driver load CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Lee Jones Acked-by: Linus Walleij Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/intel_soc_pmic_core.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index 7b50b6b208a5b..f3d918e9ca02e 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -24,8 +24,19 @@ #include #include #include +#include #include "intel_soc_pmic_core.h" +/* Lookup table for the Panel Enable/Disable line as GPIO signals */ +static struct gpiod_lookup_table panel_gpio_table = { + /* Intel GFX is consumer */ + .dev_id = "0000:00:02.0", + .table = { + /* Panel EN/DISABLE */ + GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH), + }, +}; + static int intel_soc_pmic_find_gpio_irq(struct device *dev) { struct gpio_desc *desc; @@ -85,6 +96,9 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, if (ret) dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret); + /* Add lookup table binding for Panel Control to the GPIO Chip */ + gpiod_add_lookup_table(&panel_gpio_table); + ret = mfd_add_devices(dev, -1, config->cell_dev, config->n_cell_devs, NULL, 0, regmap_irq_get_domain(pmic->irq_chip_data)); @@ -104,6 +118,9 @@ static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); + /* Remove lookup table for Panel Control from the GPIO Chip */ + gpiod_remove_lookup_table(&panel_gpio_table); + mfd_remove_devices(&i2c->dev); return 0; -- GitLab From 3d5e10ec50f80bc433916ee0cefbc8dfd16acb0c Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:06 +0530 Subject: [PATCH 1328/7006] mfd: intel_soc_pmic_crc: Add PWM cell device for Crystalcove PMIC MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needed for PWM control suuported by the PMIC CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Lee Jones Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/intel_soc_pmic_crc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c index 7436075e89832..4a7494872da24 100644 --- a/drivers/mfd/intel_soc_pmic_crc.c +++ b/drivers/mfd/intel_soc_pmic_crc.c @@ -109,6 +109,9 @@ static struct mfd_cell crystal_cove_dev[] = { { .name = "crystal_cove_pmic", }, + { + .name = "crystal_cove_pwm", + }, }; static const struct regmap_config crystal_cove_regmap_config = { -- GitLab From a3aa9a93df9fc8a0c54485e4144fdb81591e2175 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:07 +0530 Subject: [PATCH 1329/7006] mfd: intel_soc_pmic_core: ADD PWM lookup table for CRC PMIC based PWM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On some BYT PLatform the PWM is controlled using CRC PMIC. Add a lookup entry for the same to be used by the consumer (Intel GFX) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Lee Jones Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/intel_soc_pmic_core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c index f3d918e9ca02e..a00ddd93dc15f 100644 --- a/drivers/mfd/intel_soc_pmic_core.c +++ b/drivers/mfd/intel_soc_pmic_core.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "intel_soc_pmic_core.h" /* Lookup table for the Panel Enable/Disable line as GPIO signals */ @@ -37,6 +38,11 @@ static struct gpiod_lookup_table panel_gpio_table = { }, }; +/* PWM consumed by the Intel GFX */ +static struct pwm_lookup crc_pwm_lookup[] = { + PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_backlight", 0, PWM_POLARITY_NORMAL), +}; + static int intel_soc_pmic_find_gpio_irq(struct device *dev) { struct gpio_desc *desc; @@ -99,6 +105,9 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c, /* Add lookup table binding for Panel Control to the GPIO Chip */ gpiod_add_lookup_table(&panel_gpio_table); + /* Add lookup table for crc-pwm */ + pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + ret = mfd_add_devices(dev, -1, config->cell_dev, config->n_cell_devs, NULL, 0, regmap_irq_get_domain(pmic->irq_chip_data)); @@ -121,6 +130,9 @@ static int intel_soc_pmic_i2c_remove(struct i2c_client *i2c) /* Remove lookup table for Panel Control from the GPIO Chip */ gpiod_remove_lookup_table(&panel_gpio_table); + /* remove crc-pwm lookup table */ + pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); + mfd_remove_devices(&i2c->dev); return 0; -- GitLab From a3f37a104bc42f19ceb74e3e06752b6e3a269745 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:08 +0530 Subject: [PATCH 1330/7006] pwm: crc: Add Crystalcove (CRC) PWM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Crystalcove PMIC provides three PWM signals and this driver exports one of them on the BYT platform which is used to control backlight for DSI panel. This is platform device implementation of the drivers/mfd cell device for CRC PMIC. CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Cc: Paul Bolle Cc: Paul Gortmaker Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Reviewed-by: Varka Bhadram Signed-off-by: Daniel Vetter --- drivers/pwm/Kconfig | 7 +++ drivers/pwm/Makefile | 1 + drivers/pwm/pwm-crc.c | 143 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 drivers/pwm/pwm-crc.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index b1541f40fd8d1..948d9abd27f11 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -111,6 +111,13 @@ config PWM_CLPS711X To compile this driver as a module, choose M here: the module will be called pwm-clps711x. +config PWM_CRC + bool "Intel Crystalcove (CRC) PWM support" + depends on X86 && INTEL_SOC_PMIC + help + Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM + control. + config PWM_EP93XX tristate "Cirrus Logic EP93xx PWM support" depends on ARCH_EP93XX diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index ec50eb5b5a8fd..d186f35a65388 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o +obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o obj-$(CONFIG_PWM_IMG) += pwm-img.o diff --git a/drivers/pwm/pwm-crc.c b/drivers/pwm/pwm-crc.c new file mode 100644 index 0000000000000..7101c7020bf45 --- /dev/null +++ b/drivers/pwm/pwm-crc.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2015 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Author: Shobhit Kumar + */ + +#include +#include +#include +#include + +#define PWM0_CLK_DIV 0x4B +#define PWM_OUTPUT_ENABLE BIT(7) +#define PWM_DIV_CLK_0 0x00 /* DIVIDECLK = BASECLK */ +#define PWM_DIV_CLK_100 0x63 /* DIVIDECLK = BASECLK/100 */ +#define PWM_DIV_CLK_128 0x7F /* DIVIDECLK = BASECLK/128 */ + +#define PWM0_DUTY_CYCLE 0x4E +#define BACKLIGHT_EN 0x51 + +#define PWM_MAX_LEVEL 0xFF + +#define PWM_BASE_CLK 6000000 /* 6 MHz */ +#define PWM_MAX_PERIOD_NS 21333 /* 46.875KHz */ + +/** + * struct crystalcove_pwm - Crystal Cove PWM controller + * @chip: the abstract pwm_chip structure. + * @regmap: the regmap from the parent device. + */ +struct crystalcove_pwm { + struct pwm_chip chip; + struct regmap *regmap; +}; + +static inline struct crystalcove_pwm *to_crc_pwm(struct pwm_chip *pc) +{ + return container_of(pc, struct crystalcove_pwm, chip); +} + +static int crc_pwm_enable(struct pwm_chip *c, struct pwm_device *pwm) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + + regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 1); + + return 0; +} + +static void crc_pwm_disable(struct pwm_chip *c, struct pwm_device *pwm) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + + regmap_write(crc_pwm->regmap, BACKLIGHT_EN, 0); +} + +static int crc_pwm_config(struct pwm_chip *c, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct crystalcove_pwm *crc_pwm = to_crc_pwm(c); + struct device *dev = crc_pwm->chip.dev; + int level; + + if (period_ns > PWM_MAX_PERIOD_NS) { + dev_err(dev, "un-supported period_ns\n"); + return -EINVAL; + } + + if (pwm->period != period_ns) { + int clk_div; + + /* changing the clk divisor, need to disable fisrt */ + crc_pwm_disable(c, pwm); + clk_div = PWM_BASE_CLK * period_ns / NSEC_PER_SEC; + + regmap_write(crc_pwm->regmap, PWM0_CLK_DIV, + clk_div | PWM_OUTPUT_ENABLE); + + /* enable back */ + crc_pwm_enable(c, pwm); + } + + /* change the pwm duty cycle */ + level = duty_ns * PWM_MAX_LEVEL / period_ns; + regmap_write(crc_pwm->regmap, PWM0_DUTY_CYCLE, level); + + return 0; +} + +static const struct pwm_ops crc_pwm_ops = { + .config = crc_pwm_config, + .enable = crc_pwm_enable, + .disable = crc_pwm_disable, +}; + +static int crystalcove_pwm_probe(struct platform_device *pdev) +{ + struct crystalcove_pwm *pwm; + struct device *dev = pdev->dev.parent; + struct intel_soc_pmic *pmic = dev_get_drvdata(dev); + + pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL); + if (!pwm) + return -ENOMEM; + + pwm->chip.dev = &pdev->dev; + pwm->chip.ops = &crc_pwm_ops; + pwm->chip.base = -1; + pwm->chip.npwm = 1; + + /* get the PMIC regmap */ + pwm->regmap = pmic->regmap; + + platform_set_drvdata(pdev, pwm); + + return pwmchip_add(&pwm->chip); +} + +static int crystalcove_pwm_remove(struct platform_device *pdev) +{ + struct crystalcove_pwm *pwm = platform_get_drvdata(pdev); + + return pwmchip_remove(&pwm->chip); +} + +static struct platform_driver crystalcove_pwm_driver = { + .probe = crystalcove_pwm_probe, + .remove = crystalcove_pwm_remove, + .driver = { + .name = "crystal_cove_pwm", + }, +}; + +builtin_platform_driver(crystalcove_pwm_driver); -- GitLab From fc45e821990781c13dba10e3aef1c9f11af8af08 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:09 +0530 Subject: [PATCH 1331/7006] drm/i915: Use the CRC gpio for panel enable/disable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The CRC (Crystal Cove) PMIC, controls the panel enable and disable signals for BYT for dsi panels. This is indicated in the VBT fields. Use that to initialize and use GPIO based control for these signals. v2: Use the newer gpiod interface(Alexandre) v3: Remove the redundant checks and unused code (Ville) v4: Moved PWM vs SoC backlight #defines to intel_bios.h (Jani) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Acked-by: Linus Walleij Reviewed-by: Jani Nikula Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_bios.h | 7 +++++++ drivers/gpu/drm/i915/intel_dsi.c | 32 +++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_dsi.h | 3 +++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index af0b476527526..f7ad6a585129a 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -778,6 +778,13 @@ int intel_parse_bios(struct drm_device *dev); #define MIPI_DSI_UNDEFINED_PANEL_ID 0 #define MIPI_DSI_GENERIC_PANEL_ID 1 +/* + * PMIC vs SoC Backlight support specified in pwm_blc + * field in mipi_config block below. +*/ +#define PPS_BLC_PMIC 0 +#define PPS_BLC_SOC 1 + struct mipi_config { u16 panel_id; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index b5a5558ecd631..c4db74a5e4e7b 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "i915_drv.h" #include "intel_drv.h" #include "intel_dsi.h" @@ -415,6 +416,12 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + /* Panel Enable over CRC PMIC */ + if (intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1); + + msleep(intel_dsi->panel_on_delay); + /* Disable DPOunit clock gating, can stall pipe * and we need DPLL REFA always enabled */ tmp = I915_READ(DPLL(pipe)); @@ -432,8 +439,6 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder) /* put device in ready state */ intel_dsi_device_ready(encoder); - msleep(intel_dsi->panel_on_delay); - drm_panel_prepare(intel_dsi->panel); for_each_dsi_port(port, intel_dsi->ports) @@ -576,6 +581,10 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder) msleep(intel_dsi->panel_off_delay); msleep(intel_dsi->panel_pwr_cycle_delay); + + /* Panel Disable over CRC PMIC */ + if (intel_dsi->gpio_panel) + gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0); } static bool intel_dsi_get_hw_state(struct intel_encoder *encoder, @@ -955,6 +964,11 @@ static void intel_dsi_encoder_destroy(struct drm_encoder *encoder) /* XXX: Logically this call belongs in the panel driver. */ drm_panel_remove(intel_dsi->panel); } + + /* dispose of the gpios */ + if (intel_dsi->gpio_panel) + gpiod_put(intel_dsi->gpio_panel); + intel_encoder_destroy(encoder); } @@ -1071,6 +1085,20 @@ void intel_dsi_init(struct drm_device *dev) goto err; } + /* + * In case of BYT with CRC PMIC, we need to use GPIO for + * Panel control. + */ + if (dev_priv->vbt.dsi.config->pwm_blc == PPS_BLC_PMIC) { + intel_dsi->gpio_panel = + gpiod_get(dev->dev, "panel", GPIOD_OUT_HIGH); + + if (IS_ERR(intel_dsi->gpio_panel)) { + DRM_ERROR("Failed to own gpio for panel control\n"); + intel_dsi->gpio_panel = NULL; + } + } + intel_encoder->type = INTEL_OUTPUT_DSI; intel_encoder->cloneable = 0; drm_connector_init(dev, connector, &intel_dsi_connector_funcs, diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h index 2784ac442368a..42a68593e32aa 100644 --- a/drivers/gpu/drm/i915/intel_dsi.h +++ b/drivers/gpu/drm/i915/intel_dsi.h @@ -42,6 +42,9 @@ struct intel_dsi { struct drm_panel *panel; struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS]; + /* GPIO Desc for CRC based Panel control */ + struct gpio_desc *gpio_panel; + struct intel_connector *attached_connector; /* bit mask of ports being driven */ -- GitLab From b029e66fa8e39ba10dcc47b114be8da8b082493b Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Fri, 26 Jun 2015 14:32:10 +0530 Subject: [PATCH 1332/7006] drm/i915: Backlight control using CRC PMIC based PWM driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the CRC PWM device in intel_panel.c and add new MIPI backlight specififc callbacks v2: Modify to use pwm_config callback v3: Addressed Jani's comments - Renamed all function as pwm_* instead of vlv_* - Call intel_panel_actually_set_backlight in enable function - Return -ENODEV in case pwm_get fails - in case pwm_config error return error cdoe from pwm_config - Cleanup pwm in intel_panel_destroy_backlight v4: Removed unused #defines and initialized backlight with INVALID_PIPE (Ville) CC: Samuel Ortiz Cc: Linus Walleij Cc: Alexandre Courbot Cc: Thierry Reding Reviewed-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_drv.h | 4 ++ drivers/gpu/drm/i915/intel_dsi.c | 5 ++ drivers/gpu/drm/i915/intel_panel.c | 94 ++++++++++++++++++++++++++++-- 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 105928382e216..286127001c43c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -182,6 +182,10 @@ struct intel_panel { bool enabled; bool combination_mode; /* gen 2/4 only */ bool active_low_pwm; + + /* PWM chip */ + struct pwm_device *pwm; + struct backlight_device *device; } backlight; diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index c4db74a5e4e7b..892b936e14d43 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -402,6 +402,8 @@ static void intel_dsi_enable(struct intel_encoder *encoder) intel_dsi_port_enable(encoder); } + + intel_panel_enable_backlight(intel_dsi->attached_connector); } static void intel_dsi_pre_enable(struct intel_encoder *encoder) @@ -466,6 +468,8 @@ static void intel_dsi_pre_disable(struct intel_encoder *encoder) DRM_DEBUG_KMS("\n"); + intel_panel_disable_backlight(intel_dsi->attached_connector); + if (is_vid_mode(intel_dsi)) { /* Send Shutdown command to the panel in LP mode */ for_each_dsi_port(port, intel_dsi->ports) @@ -1132,6 +1136,7 @@ void intel_dsi_init(struct drm_device *dev) } intel_panel_init(&intel_connector->panel, fixed_mode, NULL); + intel_panel_setup_backlight(connector, INVALID_PIPE); return; diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c index 55aad2322e10e..e2ab3f6ed0222 100644 --- a/drivers/gpu/drm/i915/intel_panel.c +++ b/drivers/gpu/drm/i915/intel_panel.c @@ -32,8 +32,11 @@ #include #include +#include #include "intel_drv.h" +#define CRC_PMIC_PWM_PERIOD_NS 21333 + void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode, struct drm_display_mode *adjusted_mode) @@ -544,6 +547,15 @@ static u32 bxt_get_backlight(struct intel_connector *connector) return I915_READ(BXT_BLC_PWM_DUTY1); } +static u32 pwm_get_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + int duty_ns; + + duty_ns = pwm_get_duty_cycle(panel->backlight.pwm); + return DIV_ROUND_UP(duty_ns * 100, CRC_PMIC_PWM_PERIOD_NS); +} + static u32 intel_panel_get_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -632,6 +644,14 @@ static void bxt_set_backlight(struct intel_connector *connector, u32 level) I915_WRITE(BXT_BLC_PWM_DUTY1, level); } +static void pwm_set_backlight(struct intel_connector *connector, u32 level) +{ + struct intel_panel *panel = &connector->panel; + int duty_ns = DIV_ROUND_UP(level * CRC_PMIC_PWM_PERIOD_NS, 100); + + pwm_config(panel->backlight.pwm, duty_ns, CRC_PMIC_PWM_PERIOD_NS); +} + static void intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level) { @@ -769,6 +789,16 @@ static void bxt_disable_backlight(struct intel_connector *connector) I915_WRITE(BXT_BLC_PWM_CTL1, tmp & ~BXT_BLC_PWM_ENABLE); } +static void pwm_disable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + /* Disable the backlight */ + pwm_config(panel->backlight.pwm, 0, CRC_PMIC_PWM_PERIOD_NS); + usleep_range(2000, 3000); + pwm_disable(panel->backlight.pwm); +} + void intel_panel_disable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1010,6 +1040,14 @@ static void bxt_enable_backlight(struct intel_connector *connector) I915_WRITE(BXT_BLC_PWM_CTL1, pwm_ctl | BXT_BLC_PWM_ENABLE); } +static void pwm_enable_backlight(struct intel_connector *connector) +{ + struct intel_panel *panel = &connector->panel; + + pwm_enable(panel->backlight.pwm); + intel_panel_actually_set_backlight(connector, panel->backlight.level); +} + void intel_panel_enable_backlight(struct intel_connector *connector) { struct drm_device *dev = connector->base.dev; @@ -1386,6 +1424,40 @@ bxt_setup_backlight(struct intel_connector *connector, enum pipe unused) return 0; } +static int pwm_setup_backlight(struct intel_connector *connector, + enum pipe pipe) +{ + struct drm_device *dev = connector->base.dev; + struct intel_panel *panel = &connector->panel; + int retval; + + /* Get the PWM chip for backlight control */ + panel->backlight.pwm = pwm_get(dev->dev, "pwm_backlight"); + if (IS_ERR(panel->backlight.pwm)) { + DRM_ERROR("Failed to own the pwm chip\n"); + panel->backlight.pwm = NULL; + return -ENODEV; + } + + retval = pwm_config(panel->backlight.pwm, CRC_PMIC_PWM_PERIOD_NS, + CRC_PMIC_PWM_PERIOD_NS); + if (retval < 0) { + DRM_ERROR("Failed to configure the pwm chip\n"); + pwm_put(panel->backlight.pwm); + panel->backlight.pwm = NULL; + return retval; + } + + panel->backlight.min = 0; /* 0% */ + panel->backlight.max = 100; /* 100% */ + panel->backlight.level = DIV_ROUND_UP( + pwm_get_duty_cycle(panel->backlight.pwm) * 100, + CRC_PMIC_PWM_PERIOD_NS); + panel->backlight.enabled = panel->backlight.level != 0; + + return 0; +} + int intel_panel_setup_backlight(struct drm_connector *connector, enum pipe pipe) { struct drm_device *dev = connector->dev; @@ -1429,6 +1501,10 @@ void intel_panel_destroy_backlight(struct drm_connector *connector) struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_panel *panel = &intel_connector->panel; + /* dispose of the pwm */ + if (panel->backlight.pwm) + pwm_put(panel->backlight.pwm); + panel->backlight.present = false; } @@ -1456,11 +1532,19 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev) dev_priv->display.set_backlight = pch_set_backlight; dev_priv->display.get_backlight = pch_get_backlight; } else if (IS_VALLEYVIEW(dev)) { - dev_priv->display.setup_backlight = vlv_setup_backlight; - dev_priv->display.enable_backlight = vlv_enable_backlight; - dev_priv->display.disable_backlight = vlv_disable_backlight; - dev_priv->display.set_backlight = vlv_set_backlight; - dev_priv->display.get_backlight = vlv_get_backlight; + if (dev_priv->vbt.has_mipi) { + dev_priv->display.setup_backlight = pwm_setup_backlight; + dev_priv->display.enable_backlight = pwm_enable_backlight; + dev_priv->display.disable_backlight = pwm_disable_backlight; + dev_priv->display.set_backlight = pwm_set_backlight; + dev_priv->display.get_backlight = pwm_get_backlight; + } else { + dev_priv->display.setup_backlight = vlv_setup_backlight; + dev_priv->display.enable_backlight = vlv_enable_backlight; + dev_priv->display.disable_backlight = vlv_disable_backlight; + dev_priv->display.set_backlight = vlv_set_backlight; + dev_priv->display.get_backlight = vlv_get_backlight; + } } else if (IS_GEN4(dev)) { dev_priv->display.setup_backlight = i965_setup_backlight; dev_priv->display.enable_backlight = i965_enable_backlight; -- GitLab From a44e7b73118b21176bdf6376c620d778a0ff0ee2 Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:30 -0700 Subject: [PATCH 1333/7006] cxgb4 : Only pass app selector of 0 or 3 to firmware This keeps app format passed to firmware the same irrespective of DCBx version in use. Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 6074680bc9858..7f7c4ba0d4f47 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -794,7 +794,9 @@ static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id, */ static int cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id) { - return __cxgb4_getapp(dev, app_idtype, app_id, 0); + /* Convert app_idtype to firmware format before querying */ + return __cxgb4_getapp(dev, app_idtype == DCB_APP_IDTYPE_ETHTYPE ? + app_idtype : 3, app_id, 0); } /* Write a new Application User Priority Map for the specified Application ID @@ -1133,7 +1135,7 @@ static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table) if (!pcmd.u.dcb.app_priority.protocolid) break; - table[i].selector = pcmd.u.dcb.app_priority.sel_field; + table[i].selector = (pcmd.u.dcb.app_priority.sel_field + 1); table[i].protocol = be16_to_cpu(pcmd.u.dcb.app_priority.protocolid); table[i].priority = -- GitLab From a85c2eb3113299b8d55936a49e70c5b63c72617f Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:31 -0700 Subject: [PATCH 1334/7006] cxgb4 : Allow firmware DCB info to be queried in host state Since finally DCB traffic management is still handled by firmware, allow firmware to be fully programmed and queried even in host managed state for the cases where this was previously rejected. Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- .../net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 7f7c4ba0d4f47..56a81b8f7c54a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -31,6 +31,15 @@ static const char * const dcb_ver_array[] = { "Auto Negotiated" }; +static inline bool cxgb4_dcb_state_synced(enum cxgb4_dcb_state state) +{ + if (state == CXGB4_DCB_STATE_FW_ALLSYNCED || + state == CXGB4_DCB_STATE_HOST) + return true; + else + return false; +} + /* Initialize a port's Data Center Bridging state. Typically used after a * Link Down event. */ @@ -603,7 +612,7 @@ static void cxgb4_getpfccfg(struct net_device *dev, int priority, u8 *pfccfg) struct port_info *pi = netdev2pinfo(dev); struct port_dcb_info *dcb = &pi->dcb; - if (dcb->state != CXGB4_DCB_STATE_FW_ALLSYNCED || + if (!cxgb4_dcb_state_synced(dcb->state) || priority >= CXGB4_MAX_PRIORITY) *pfccfg = 0; else @@ -620,7 +629,7 @@ static void cxgb4_setpfccfg(struct net_device *dev, int priority, u8 pfccfg) struct adapter *adap = pi->adapter; int err; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED || + if (!cxgb4_dcb_state_synced(pi->dcb.state) || priority >= CXGB4_MAX_PRIORITY) return; @@ -732,7 +741,7 @@ static u8 cxgb4_getpfcstate(struct net_device *dev) { struct port_info *pi = netdev2pinfo(dev); - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return false; return pi->dcb.pfcen != 0; @@ -756,7 +765,7 @@ static int __cxgb4_getapp(struct net_device *dev, u8 app_idtype, u16 app_id, struct adapter *adap = pi->adapter; int i; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 0; for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { @@ -810,7 +819,7 @@ static int __cxgb4_setapp(struct net_device *dev, u8 app_idtype, u16 app_id, int i, err; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return -EINVAL; /* DCB info gets thrown away on link up */ @@ -898,10 +907,11 @@ cxgb4_ieee_negotiation_complete(struct net_device *dev, struct port_info *pi = netdev2pinfo(dev); struct port_dcb_info *dcb = &pi->dcb; - if (dcb_subtype && !(dcb->msgs & dcb_subtype)) - return 0; + if (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED) + if (dcb_subtype && !(dcb->msgs & dcb_subtype)) + return 0; - return (dcb->state == CXGB4_DCB_STATE_FW_ALLSYNCED && + return (cxgb4_dcb_state_synced(dcb->state) && (dcb->supported & DCB_CAP_DCBX_VER_IEEE)); } @@ -1059,7 +1069,7 @@ static u8 cxgb4_setdcbx(struct net_device *dev, u8 dcb_request) /* Can't enable DCB if we haven't successfully negotiated it. */ - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 1; /* There's currently no mechanism to allow for the firmware DCBX @@ -1082,7 +1092,7 @@ static int cxgb4_getpeer_app(struct net_device *dev, struct adapter *adap = pi->adapter; int i, err = 0; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 1; info->willing = 0; @@ -1116,7 +1126,7 @@ static int cxgb4_getpeerapp_tbl(struct net_device *dev, struct dcb_app *table) struct adapter *adap = pi->adapter; int i, err = 0; - if (pi->dcb.state != CXGB4_DCB_STATE_FW_ALLSYNCED) + if (!cxgb4_dcb_state_synced(pi->dcb.state)) return 1; for (i = 0; i < CXGB4_MAX_DCBX_APP_SUPPORTED; i++) { -- GitLab From 8d6541b7bc0a56020ffc9fab7d740e47addd609d Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:32 -0700 Subject: [PATCH 1335/7006] cxgb4 : Fill in number of DCB traffic classes supported Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c index 56a81b8f7c54a..052c660aca80a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c @@ -1193,6 +1193,8 @@ static int cxgb4_cee_peer_getpg(struct net_device *dev, struct cee_pg *pg) for (i = 0; i < CXGB4_MAX_PRIORITY; i++) pg->pg_bw[i] = pcmd.u.dcb.pgrate.pgrate[i]; + pg->tcs_supported = pcmd.u.dcb.pgrate.num_tcs_supported; + return 0; } @@ -1210,6 +1212,8 @@ static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc) */ pfc->pfc_en = bitswap_1(pi->dcb.pfcen); + pfc->tcs_supported = pi->dcb.pfc_num_tcs_supported; + return 0; } -- GitLab From 397665dab58415d648f03e2893627f4f7abf0fba Mon Sep 17 00:00:00 2001 From: Anish Bhatt Date: Fri, 17 Jul 2015 13:12:33 -0700 Subject: [PATCH 1336/7006] cxgb4 : Fill DCB priority in vlan control headers Signed-off-by: Anish Bhatt Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 14 ++++++++++---- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 3 +++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 942db078f33a6..d4248d74f5601 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -1137,7 +1137,7 @@ cxgb_fcoe_offload(struct sk_buff *skb, struct adapter *adap, */ netdev_tx_t t4_eth_xmit(struct sk_buff *skb, struct net_device *dev) { - u32 wr_mid; + u32 wr_mid, ctrl0; u64 cntrl, *end; int qidx, credits; unsigned int flits, ndesc; @@ -1274,9 +1274,15 @@ out_free: dev_kfree_skb_any(skb); #endif /* CONFIG_CHELSIO_T4_FCOE */ } - cpl->ctrl0 = htonl(TXPKT_OPCODE_V(CPL_TX_PKT_XT) | - TXPKT_INTF_V(pi->tx_chan) | - TXPKT_PF_V(adap->pf)); + ctrl0 = TXPKT_OPCODE_V(CPL_TX_PKT_XT) | TXPKT_INTF_V(pi->tx_chan) | + TXPKT_PF_V(adap->pf); +#ifdef CONFIG_CHELSIO_T4_DCB + if (is_t4(adap->params.chip)) + ctrl0 |= TXPKT_OVLAN_IDX_V(q->dcb_prio); + else + ctrl0 |= TXPKT_T5_OVLAN_IDX_V(q->dcb_prio); +#endif + cpl->ctrl0 = htonl(ctrl0); cpl->pack = htons(0); cpl->len = htons(skb->len); cpl->ctrl1 = cpu_to_be64(cntrl); diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index 132cb8fc0bf71..b99144afd4ecc 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -660,6 +660,9 @@ struct cpl_tx_pkt { #define TXPKT_OVLAN_IDX_S 12 #define TXPKT_OVLAN_IDX_V(x) ((x) << TXPKT_OVLAN_IDX_S) +#define TXPKT_T5_OVLAN_IDX_S 12 +#define TXPKT_T5_OVLAN_IDX_V(x) ((x) << TXPKT_T5_OVLAN_IDX_S) + #define TXPKT_INTF_S 16 #define TXPKT_INTF_V(x) ((x) << TXPKT_INTF_S) -- GitLab From dd72bde05de5d68d56e59698f7f2c102afce904b Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Fri, 17 Jul 2015 17:08:51 +0100 Subject: [PATCH 1337/7006] drm/i915: Do kunmap if renderstate parsing fails Kunmap the renderstate page on error path. Reviewed-by: Arun Siluvery Signed-off-by: Mika Kuoppala Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index a0201fc94d256..b6492fe3722b5 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -96,8 +96,10 @@ static int render_state_setup(struct render_state *so) s = lower_32_bits(r); if (so->gen >= 8) { if (i + 1 >= rodata->batch_items || - rodata->batch[i + 1] != 0) - return -EINVAL; + rodata->batch[i + 1] != 0) { + ret = -EINVAL; + goto err_out; + } d[i++] = s; s = upper_32_bits(r); @@ -120,6 +122,10 @@ static int render_state_setup(struct render_state *so) } return 0; + +err_out: + kunmap(page); + return ret; } void i915_gem_render_state_fini(struct render_state *so) -- GitLab From 0c199a903d1cbc67fd99a9b074aaff4f72fa84d0 Mon Sep 17 00:00:00 2001 From: Jakub Wilk Date: Sat, 18 Jul 2015 14:41:51 +0200 Subject: [PATCH 1338/7006] xfrm: Fix a typo Signed-off-by: Jakub Wilk Signed-off-by: David S. Miller --- net/xfrm/xfrm_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index bd16c6c7e1e76..0cebf1fc37a27 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -2048,7 +2048,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, xfrm_audit_policy_delete(xp, 1, true); } else { // reset the timers here? - WARN(1, "Dont know what to do with soft policy expire\n"); + WARN(1, "Don't know what to do with soft policy expire\n"); } km_policy_expired(xp, p->dir, up->hard, nlh->nlmsg_pid); -- GitLab From 84e81020ee237df8af359c552b503db476b776ea Mon Sep 17 00:00:00 2001 From: Arun Siluvery Date: Mon, 20 Jul 2015 10:46:10 +0100 Subject: [PATCH 1339/7006] drm/i915: Add provision to extend Golden context batch The Golden batch carries 3D state at the beginning so that HW starts with a known state. It is carried as a binary blob which is auto-generated from source. The idea was it would be easier to maintain and keep the complexity out of the kernel which makes sense as we don't really touch it. However if you really need to update it then you need to update generator source and keep the binary blob in sync with it. There is a need to patch this in bxt to send one additional command to enable a feature. A solution was to patch the binary data with some additional data structures (included as part of auto-generator source) but it was unnecessarily complicated. Chris suggested the idea of having a secondary batch and execute two batch buffers. It has clear advantages as we needn't touch the base golden batch, can customize secondary/auxiliary batch depending on Gen and can be carried in the driver with no dependencies. This patch adds support for this auxiliary batch which is inserted at the end of golden batch and is completely independent from it. Thanks to Mika for the preliminary review. v2: Strictly conform to the batch size requirements to cover Gen2 and add comments to clarify overflow check in macro (Chris, Mika). v3: aux_batch_offset was declared as u64, change it to u32 (Chris) Reviewed-by: Chris Wilson Cc: Mika Kuoppala Cc: Chris Wilson Cc: Armin Reese Signed-off-by: Arun Siluvery Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_gem_render_state.c | 45 ++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_render_state.h | 2 + drivers/gpu/drm/i915/intel_lrc.c | 6 +++ 3 files changed, 53 insertions(+) diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c index b6492fe3722b5..5026a6267a880 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.c +++ b/drivers/gpu/drm/i915/i915_gem_render_state.c @@ -73,6 +73,24 @@ free_gem: return ret; } +/* + * Macro to add commands to auxiliary batch. + * This macro only checks for page overflow before inserting the commands, + * this is sufficient as the null state generator makes the final batch + * with two passes to build command and state separately. At this point + * the size of both are known and it compacts them by relocating the state + * right after the commands taking care of aligment so we should sufficient + * space below them for adding new commands. + */ +#define OUT_BATCH(batch, i, val) \ + do { \ + if (WARN_ON((i) >= PAGE_SIZE / sizeof(u32))) { \ + ret = -ENOSPC; \ + goto err_out; \ + } \ + (batch)[(i)++] = (val); \ + } while(0) + static int render_state_setup(struct render_state *so) { const struct intel_renderstate_rodata *rodata = so->rodata; @@ -110,6 +128,21 @@ static int render_state_setup(struct render_state *so) d[i++] = s; } + + while (i % CACHELINE_DWORDS) + OUT_BATCH(d, i, MI_NOOP); + + so->aux_batch_offset = i * sizeof(u32); + + OUT_BATCH(d, i, MI_BATCH_BUFFER_END); + so->aux_batch_size = (i * sizeof(u32)) - so->aux_batch_offset; + + /* + * Since we are sending length, we need to strictly conform to + * all requirements. For Gen2 this must be a multiple of 8. + */ + so->aux_batch_size = ALIGN(so->aux_batch_size, 8); + kunmap(page); ret = i915_gem_object_set_to_gtt_domain(so->obj, false); @@ -128,6 +161,8 @@ err_out: return ret; } +#undef OUT_BATCH + void i915_gem_render_state_fini(struct render_state *so) { i915_gem_object_ggtt_unpin(so->obj); @@ -176,6 +211,16 @@ int i915_gem_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; + if (so.aux_batch_size > 8) { + ret = req->ring->dispatch_execbuffer(req, + (so.ggtt_offset + + so.aux_batch_offset), + so.aux_batch_size, + I915_DISPATCH_SECURE); + if (ret) + goto out; + } + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.h b/drivers/gpu/drm/i915/i915_gem_render_state.h index 7aa73728178ac..e641bb093a903 100644 --- a/drivers/gpu/drm/i915/i915_gem_render_state.h +++ b/drivers/gpu/drm/i915/i915_gem_render_state.h @@ -37,6 +37,8 @@ struct render_state { struct drm_i915_gem_object *obj; u64 ggtt_offset; int gen; + u32 aux_batch_size; + u32 aux_batch_offset; }; int i915_gem_render_state_init(struct drm_i915_gem_request *req); diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 9faad82c42ecd..99bba8ece464b 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1740,6 +1740,12 @@ static int intel_lr_context_render_state_init(struct drm_i915_gem_request *req) if (ret) goto out; + ret = req->ring->emit_bb_start(req, + (so.ggtt_offset + so.aux_batch_offset), + I915_DISPATCH_SECURE); + if (ret) + goto out; + i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), req); out: -- GitLab From 2070c48cf2b78af89ba529c00992eaaa18df8ef7 Mon Sep 17 00:00:00 2001 From: Pieter Hollants Date: Mon, 20 Jul 2015 10:14:13 +0200 Subject: [PATCH 1340/7006] qmi_wwan: Add support for Dell Wireless 5809e 4G Modem Added the USB IDs 0x413c:0x81b1 for the "Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card", a Dell-branded Sierra Wireless EM7305 LTE card in M.2 form factor, used eg. in Dell's Latitude E7540 Notebook series. Signed-off-by: Pieter Hollants Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index f603f362504bc..f06c687c5429a 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -784,6 +784,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x413c, 0x81a4, 8)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a8, 8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x413c, 0x81a9, 8)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ + {QMI_FIXED_INTF(0x413c, 0x81b1, 8)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ {QMI_FIXED_INTF(0x03f0, 0x581d, 4)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Module (Huawei me906e) */ /* 4. Gobi 1000 devices */ -- GitLab From c21cde6fe1ba08b357c96071c71af6543f2863ec Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Tue, 21 Jul 2015 11:36:57 +0200 Subject: [PATCH 1341/7006] gpio: document interaction with other subsystems Now I am very fed up with people reinventing kernel wheels in userspace "just because they can" (read, sysfs). Put in a angry blurb in sysfs doc and put in a new file with pointers to other subsystem drivers utilizing GPIOs. Signed-off-by: Linus Walleij --- Documentation/gpio/00-INDEX | 3 + Documentation/gpio/drivers-on-gpio.txt | 95 ++++++++++++++++++++++++++ Documentation/gpio/sysfs.txt | 9 ++- 3 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 Documentation/gpio/drivers-on-gpio.txt diff --git a/Documentation/gpio/00-INDEX b/Documentation/gpio/00-INDEX index 1de43ae46ae6b..179beb234f989 100644 --- a/Documentation/gpio/00-INDEX +++ b/Documentation/gpio/00-INDEX @@ -6,6 +6,9 @@ consumer.txt - How to obtain and use GPIOs in a driver driver.txt - How to write a GPIO driver +drivers-on-gpio.txt: + - Drivers in other subsystems that can use GPIO to provide more + complex functionality. board.txt - How to assign GPIOs to a consumer device and a function sysfs.txt diff --git a/Documentation/gpio/drivers-on-gpio.txt b/Documentation/gpio/drivers-on-gpio.txt new file mode 100644 index 0000000000000..f6121328630f5 --- /dev/null +++ b/Documentation/gpio/drivers-on-gpio.txt @@ -0,0 +1,95 @@ +Subsystem drivers using GPIO +============================ + +Note that standard kernel drivers exist for common GPIO tasks and will provide +the right in-kernel and userspace APIs/ABIs for the job, and that these +drivers can quite easily interconnect with other kernel subsystems using +hardware descriptions such as device tree or ACPI: + +- leds-gpio: drivers/leds/leds-gpio.c will handle LEDs connected to GPIO + lines, giving you the LED sysfs interface + +- ledtrig-gpio: drivers/leds/trigger/ledtrig-gpio.c will provide a LED trigger, + i.e. a LED will turn on/off in response to a GPIO line going high or low + (and that LED may in turn use the leds-gpio as per above). + +- gpio-keys: drivers/input/keyboard/gpio_keys.c is used when your GPIO line + can generate interrupts in response to a key press. Also supports debounce. + +- gpio-keys-polled: drivers/input/keyboard/gpio_keys_polled.c is used when your + GPIO line cannot generate interrupts, so it needs to be periodically polled + by a timer. + +- gpio_mouse: drivers/input/mouse/gpio_mouse.c is used to provide a mouse with + up to three buttons by simply using GPIOs and no mouse port. You can cut the + mouse cable and connect the wires to GPIO lines or solder a mouse connector + to the lines for a more permanent solution of this type. + +- gpio-beeper: drivers/input/misc/gpio-beeper.c is used to provide a beep from + an external speaker connected to a GPIO line. + +- gpio-tilt-polled: drivers/input/misc/gpio_tilt_polled.c provides tilt + detection switches using GPIO, which is useful for your homebrewn pinball + machine if for nothing else. It can detect different tilt angles of the + monitored object. + +- extcon-gpio: drivers/extcon/extcon-gpio.c is used when you need to read an + external connector status, such as a headset line for an audio driver or an + HDMI connector. It will provide a better userspace sysfs interface than GPIO. + +- restart-gpio: drivers/power/gpio-restart.c is used to restart/reboot the + system by pulling a GPIO line and will register a restart handler so + userspace can issue the right system call to restart the system. + +- poweroff-gpio: drivers/power/gpio-poweroff.c is used to power the system down + by pulling a GPIO line and will register a pm_power_off() callback so that + userspace can issue the right system call to power down the system. + +- gpio-gate-clock: drivers/clk/clk-gpio-gate.c is used to control a gated clock + (off/on) that uses a GPIO, and integrated with the clock subsystem. + +- i2c-gpio: drivers/i2c/busses/i2c-gpio.c is used to drive an I2C bus + (two wires, SDA and SCL lines) by hammering (bitbang) two GPIO lines. It will + appear as any other I2C bus to the system and makes it possible to connect + drivers for the I2C devices on the bus like any other I2C bus driver. + +- spi_gpio: drivers/spi/spi-gpio.c is used to drive an SPI bus (variable number + of wires, atleast SCK and optionally MISO, MOSI and chip select lines) using + GPIO hammering (bitbang). It will appear as any other SPI bus on the system + and makes it possible to connect drivers for SPI devices on the bus like + any other SPI bus driver. For example any MMC/SD card can then be connected + to this SPI by using the mmc_spi host from the MMC/SD card subsystem. + +- w1-gpio: drivers/w1/masters/w1-gpio.c is used to drive a one-wire bus using + a GPIO line, integrating with the W1 subsystem and handling devices on + the bus like any other W1 device. + +- gpio-fan: drivers/hwmon/gpio-fan.c is used to control a fan for cooling the + system, connected to a GPIO line (and optionally a GPIO alarm line), + presenting all the right in-kernel and sysfs interfaces to make your system + not overheat. + +- gpio-regulator: drivers/regulator/gpio-regulator.c is used to control a + regulator providing a certain voltage by pulling a GPIO line, integrating + with the regulator subsystem and giving you all the right interfaces. + +- gpio-wdt: drivers/watchdog/gpio_wdt.c is used to provide a watchdog timer + that will periodically "ping" a hardware connected to a GPIO line by toggling + it from 1-to-0-to-1. If that hardware does not recieve its "ping" + periodically, it will reset the system. + +- gpio-nand: drivers/mtd/nand/gpio.c is used to connect a NAND flash chip to + a set of simple GPIO lines: RDY, NCE, ALE, CLE, NWP. It interacts with the + NAND flash MTD subsystem and provides chip access and partition parsing like + any other NAND driving hardware. + +Apart from this there are special GPIO drivers in subsystems like MMC/SD to +read card detect and write protect GPIO lines, and in the TTY serial subsystem +to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The +MTD NOR flash has add-ons for extra GPIO lines too, though the address bus is +usually connected directly to the flash. + +Use those instead of talking directly to the GPIOs using sysfs; they integrate +with kernel frameworks better than your userspace code could. Needless to say, +just using the apropriate kernel drivers will simplify and speed up your +embedded hacking in particular by providing ready-made components. diff --git a/Documentation/gpio/sysfs.txt b/Documentation/gpio/sysfs.txt index 535b6a8a7a7cc..0700b55637f56 100644 --- a/Documentation/gpio/sysfs.txt +++ b/Documentation/gpio/sysfs.txt @@ -20,11 +20,10 @@ userspace GPIO can be used to determine system configuration data that standard kernels won't know about. And for some tasks, simple userspace GPIO drivers could be all that the system really needs. -Note that standard kernel drivers exist for common "LEDs and Buttons" -GPIO tasks: "leds-gpio" and "gpio_keys", respectively. Use those -instead of talking directly to the GPIOs; they integrate with kernel -frameworks better than your userspace code could. - +DO NOT ABUSE SYFS TO CONTROL HARDWARE THAT HAS PROPER KERNEL DRIVERS. +PLEASE READ THE DOCUMENT NAMED "drivers-on-gpio.txt" IN THIS DOCUMENTATION +DIRECTORY TO AVOID REINVENTING KERNEL WHEELS IN USERSPACE. I MEAN IT. +REALLY. Paths in Sysfs -------------- -- GitLab From 48725e9cc841da395bfd74e7691bba91613d3517 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 21 Jul 2015 00:03:35 +0000 Subject: [PATCH 1342/7006] ASoC: rsnd: tidyup parameter assignment position 84e95355602c("ASoC: rsnd: show debug message for SSI/SRC/DVC connection") added debug message on rsnd_dai_connect(), but the relationship of parameter check was absurdity. This patch tidyup it. It is reported via Smatch/Dan Reported-by: Dan Carpenter Signed-off-by: Kuninori Morimoto Signed-off-by: Mark Brown --- sound/soc/sh/rcar/core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index 927a7b02123b3..f3feed5ce9b65 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -332,12 +332,15 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) static int rsnd_dai_connect(struct rsnd_mod *mod, struct rsnd_dai_stream *io) { - struct rsnd_priv *priv = rsnd_mod_to_priv(mod); - struct device *dev = rsnd_priv_to_dev(priv); + struct rsnd_priv *priv; + struct device *dev; if (!mod) return -EIO; + priv = rsnd_mod_to_priv(mod); + dev = rsnd_priv_to_dev(priv); + io->mod[mod->type] = mod; dev_dbg(dev, "%s[%d] is connected to io (%s)\n", -- GitLab From 6eb1c2a63d0415bd66c9c866b7d405662f50d5e4 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 21 Jul 2015 11:55:27 +0300 Subject: [PATCH 1343/7006] ASoC: max98925: reading beyond the end of the array Debug prints are seldom useful and this one has an annoying thing where it reads one space beyond the end of the array on error. Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index eddf8bc073146..0883d87776b1e 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -271,8 +271,6 @@ static inline int max98925_rate_value(struct snd_soc_codec *codec, break; } } - dev_dbg(codec->dev, "%s: sample rate is %d, returning %d\n", - __func__, rate_table[i].rate, *value); return ret; } -- GitLab From a4642e99694a912b32952317e8f4c253ed6be4a9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 21 Jul 2015 11:57:36 +0300 Subject: [PATCH 1344/7006] ASoC: sti: error handling bug in sti_uniperiph_cpu_dai_of() There is a stray '!' which means the condition is never true. Fixes: f3bd847eb0a7 ('ASoC: sti: Add uniperipheral dai driver') Signed-off-by: Dan Carpenter Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index 51f745c56c7fd..dffabf3ba9fbc 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -175,7 +175,7 @@ static int sti_uniperiph_cpu_dai_of(struct device_node *node, UNIPERIF_FIFO_DATA_OFFSET(uni); uni->irq = platform_get_irq(priv->pdev, 0); - if (!uni->irq < 0) { + if (uni->irq < 0) { dev_err(dev, "Failed to get IRQ resource"); return -ENXIO; } -- GitLab From 8ab30c1538b14424015e45063c41d509b24c1dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:53 +0100 Subject: [PATCH 1345/7006] KVM: add comments for kvm_debug_exit_arch struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring into line with the comments for the other structures and their KVM_EXIT_* cases. Also update api.txt to reflect use in kvm_run documentation. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall Signed-off-by: Marc Zyngier --- Documentation/virtual/kvm/api.txt | 4 +++- include/uapi/linux/kvm.h | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index a7926a90156f6..9f746eab333d4 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -3111,11 +3111,13 @@ data_offset describes where the data is located (KVM_EXIT_IO_OUT) or where kvm expects application code to place the data for the next KVM_RUN invocation (KVM_EXIT_IO_IN). Data format is a packed array. + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; -Unused. +If the exit_reason is KVM_EXIT_DEBUG, then a vcpu is processing a debug event +for which architecture specific information is returned. /* KVM_EXIT_MMIO */ struct { diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 716ad4ae4d4b1..4ab3c6a8d5639 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -237,6 +237,7 @@ struct kvm_run { __u32 count; __u64 data_offset; /* relative to kvm_run start */ } io; + /* KVM_EXIT_DEBUG */ struct { struct kvm_debug_exit_arch arch; } debug; @@ -285,6 +286,7 @@ struct kvm_run { __u32 data; __u8 is_write; } dcr; + /* KVM_EXIT_INTERNAL_ERROR */ struct { __u32 suberror; /* Available with KVM_CAP_INTERNAL_ERROR_DATA: */ @@ -295,6 +297,7 @@ struct kvm_run { struct { __u64 gprs[32]; } osi; + /* KVM_EXIT_PAPR_HCALL */ struct { __u64 nr; __u64 ret; -- GitLab From 21b6f32f9471284f6d4621fc8be71719266db557 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:54 +0100 Subject: [PATCH 1346/7006] KVM: arm64: guest debug, define API headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit defines the API headers for guest debugging. There are two architecture specific debug structures: - kvm_guest_debug_arch, allows us to pass in HW debug registers - kvm_debug_exit_arch, signals exception and possible faulting address The type of debugging being used is controlled by the architecture specific control bits of the kvm_guest_debug->control flags in the ioctl structure. Signed-off-by: Alex Bennée Reviewed-by: David Hildenbrand Reviewed-by: Andrew Jones Acked-by: Christoffer Dall Signed-off-by: Marc Zyngier --- arch/arm64/include/uapi/asm/kvm.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h index d26832022127e..d82f3f316ba45 100644 --- a/arch/arm64/include/uapi/asm/kvm.h +++ b/arch/arm64/include/uapi/asm/kvm.h @@ -100,12 +100,39 @@ struct kvm_sregs { struct kvm_fpu { }; +/* + * See v8 ARM ARM D7.3: Debug Registers + * + * The architectural limit is 16 debug registers of each type although + * in practice there are usually less (see ID_AA64DFR0_EL1). + * + * Although the control registers are architecturally defined as 32 + * bits wide we use a 64 bit structure here to keep parity with + * KVM_GET/SET_ONE_REG behaviour which treats all system registers as + * 64 bit values. It also allows for the possibility of the + * architecture expanding the control registers without having to + * change the userspace ABI. + */ +#define KVM_ARM_MAX_DBG_REGS 16 struct kvm_guest_debug_arch { + __u64 dbg_bcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_bvr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wcr[KVM_ARM_MAX_DBG_REGS]; + __u64 dbg_wvr[KVM_ARM_MAX_DBG_REGS]; }; struct kvm_debug_exit_arch { + __u32 hsr; + __u64 far; /* used for watchpoints */ }; +/* + * Architecture specific defines for kvm_guest_debug->control + */ + +#define KVM_GUESTDBG_USE_SW_BP (1 << 16) +#define KVM_GUESTDBG_USE_HW (1 << 17) + struct kvm_sync_regs { }; -- GitLab From 0e6f07f29cfb8d79dbbdb12560a73f7121ba324e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:55 +0100 Subject: [PATCH 1347/7006] KVM: arm: guest debug, add stub KVM_SET_GUEST_DEBUG ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a stub function to support the KVM_SET_GUEST_DEBUG ioctl. Any unsupported flag will return -EINVAL. For now, only KVM_GUESTDBG_ENABLE is supported, although it won't have any effects. Signed-off-by: Alex Bennée . Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm/kvm/arm.c | 7 ------- arch/arm/kvm/guest.c | 6 ++++++ arch/arm64/kvm/guest.c | 27 +++++++++++++++++++++++++++ 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 9f746eab333d4..19adfd385882e 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2671,7 +2671,7 @@ handled. 4.87 KVM_SET_GUEST_DEBUG Capability: KVM_CAP_SET_GUEST_DEBUG -Architectures: x86, s390, ppc +Architectures: x86, s390, ppc, arm64 Type: vcpu ioctl Parameters: struct kvm_guest_debug (in) Returns: 0 on success; -1 on error diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index bc738d2b83929..1b693cb2d5b27 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -301,13 +301,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) kvm_arm_set_running_vcpu(NULL); } -int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, - struct kvm_guest_debug *dbg) -{ - return -EINVAL; -} - - int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, struct kvm_mp_state *mp_state) { diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index d503fbb787d36..96e935bbc38c8 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -290,3 +290,9 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, { return -EINVAL; } + +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + return -EINVAL; +} diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 9535bd555d1d4..0ba86775235d9 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -331,3 +331,30 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, { return -EINVAL; } + +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) + +/** + * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging + * @kvm: pointer to the KVM struct + * @kvm_guest_debug: the ioctl data buffer + * + * This sets up and enables the VM for guest debugging. Userspace + * passes in a control flag to enable different debug types and + * potentially other architecture specific information in the rest of + * the structure. + */ +int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, + struct kvm_guest_debug *dbg) +{ + if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) + return -EINVAL; + + if (dbg->control & KVM_GUESTDBG_ENABLE) { + vcpu->guest_debug = dbg->control; + } else { + /* If not enabled clear all flags */ + vcpu->guest_debug = 0; + } + return 0; +} -- GitLab From 56c7f5e77f797fd0dcf2376ce1496f4238e6be33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:56 +0100 Subject: [PATCH 1348/7006] KVM: arm: introduce kvm_arm_init/setup/clear_debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a precursor for later patches which will need to do more to setup debug state before entering the hyp.S switch code. The existing functionality for setting mdcr_el2 has been moved out of hyp.S and now uses the value kept in vcpu->arch.mdcr_el2. As the assembler used to previously mask and preserve MDCR_EL2.HPMN I've had to add a mechanism to save the value of mdcr_el2 as a per-cpu variable during the initialisation code. The kernel never sets this number so we are assuming the bootcode has set up the correct value here. This also moves the conditional setting of the TDA bit from the hyp code into the C code which is currently used for the lazy debug register context switch code. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_host.h | 4 ++ arch/arm/kvm/arm.c | 6 +++ arch/arm64/include/asm/kvm_asm.h | 2 + arch/arm64/include/asm/kvm_host.h | 5 ++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kvm/Makefile | 2 +- arch/arm64/kvm/debug.c | 81 +++++++++++++++++++++++++++++++ arch/arm64/kvm/hyp.S | 19 +++----- 8 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 arch/arm64/kvm/debug.c diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index e896d2c196e63..2b0bc8c575528 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -231,4 +231,8 @@ static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +static inline void kvm_arm_init_debug(void) {} +static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} + #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 1b693cb2d5b27..77151b111d32d 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -543,6 +543,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) continue; } + kvm_arm_setup_debug(vcpu); + /************************************************************** * Enter the guest */ @@ -557,6 +559,8 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) * Back from guest *************************************************************/ + kvm_arm_clear_debug(vcpu); + /* * We may have taken a host interrupt in HYP mode (ie * while executing the guest). This interrupt is still @@ -914,6 +918,8 @@ static void cpu_init_hyp_mode(void *dummy) vector_ptr = (unsigned long)__kvm_hyp_vector; __cpu_init_hyp_mode(boot_pgd_ptr, pgd_ptr, hyp_stack_ptr, vector_ptr); + + kvm_arm_init_debug(); } static int hyp_init_cpu_notify(struct notifier_block *self, diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index 3c5fe685a2d69..f5e40dae291ab 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -132,6 +132,8 @@ extern int __kvm_vcpu_run(struct kvm_vcpu *vcpu); extern u64 __vgic_v3_get_ich_vtr_el2(void); +extern u32 __kvm_get_mdcr_el2(void); + #endif #endif /* __ARM_KVM_ASM_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 2709db2a7eac7..c90c6a41c448c 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -103,6 +103,7 @@ struct kvm_vcpu_arch { /* HYP configuration */ u64 hcr_el2; + u32 mdcr_el2; /* Exception Information */ struct kvm_vcpu_fault_info fault; @@ -227,4 +228,8 @@ static inline void kvm_arch_sync_events(struct kvm *kvm) {} static inline void kvm_arch_vcpu_uninit(struct kvm_vcpu *vcpu) {} static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} +void kvm_arm_init_debug(void); +void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); +void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index c99701a34d7b3..5c900d49b9068 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -117,6 +117,7 @@ int main(void) DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); + DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context)); DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl)); diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile index f90f4aa7f88d9..1949fe5f54246 100644 --- a/arch/arm64/kvm/Makefile +++ b/arch/arm64/kvm/Makefile @@ -17,7 +17,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(ARM)/psci.o $(ARM)/perf.o kvm-$(CONFIG_KVM_ARM_HOST) += emulate.o inject_fault.o regmap.o kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o -kvm-$(CONFIG_KVM_ARM_HOST) += guest.o reset.o sys_regs.o sys_regs_generic_v8.o +kvm-$(CONFIG_KVM_ARM_HOST) += guest.o debug.o reset.o sys_regs.o sys_regs_generic_v8.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic.o kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/vgic-v2.o diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c new file mode 100644 index 0000000000000..faf0e1fdba9ee --- /dev/null +++ b/arch/arm64/kvm/debug.c @@ -0,0 +1,81 @@ +/* + * Debug and Guest Debug support + * + * Copyright (C) 2015 - Linaro Ltd + * Author: Alex Bennée + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +static DEFINE_PER_CPU(u32, mdcr_el2); + +/** + * kvm_arm_init_debug - grab what we need for debug + * + * Currently the sole task of this function is to retrieve the initial + * value of mdcr_el2 so we can preserve MDCR_EL2.HPMN which has + * presumably been set-up by some knowledgeable bootcode. + * + * It is called once per-cpu during CPU hyp initialisation. + */ + +void kvm_arm_init_debug(void) +{ + __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); +} + + +/** + * kvm_arm_setup_debug - set up debug related stuff + * + * @vcpu: the vcpu pointer + * + * This is called before each entry into the hypervisor to setup any + * debug related registers. Currently this just ensures we will trap + * access to: + * - Performance monitors (MDCR_EL2_TPM/MDCR_EL2_TPMCR) + * - Debug ROM Address (MDCR_EL2_TDRA) + * - OS related registers (MDCR_EL2_TDOSA) + * + * Additionally, KVM only traps guest accesses to the debug registers if + * the guest is not actively using them (see the KVM_ARM64_DEBUG_DIRTY + * flag on vcpu->arch.debug_flags). Since the guest must not interfere + * with the hardware state when debugging the guest, we must ensure that + * trapping is enabled whenever we are debugging the guest using the + * debug registers. + */ + +void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) +{ + bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY); + + vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; + vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | + MDCR_EL2_TPMCR | + MDCR_EL2_TDRA | + MDCR_EL2_TDOSA); + + /* Trap on access to debug registers? */ + if (trap_debug) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + +} + +void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) +{ + /* Nothing to do yet */ +} diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 17a8fb14f428d..b3176e6e51d15 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -770,17 +770,8 @@ mov x2, #(1 << 15) // Trap CP15 Cr=15 msr hstr_el2, x2 - mrs x2, mdcr_el2 - and x2, x2, #MDCR_EL2_HPMN_MASK - orr x2, x2, #(MDCR_EL2_TPM | MDCR_EL2_TPMCR) - orr x2, x2, #(MDCR_EL2_TDRA | MDCR_EL2_TDOSA) - - // Check for KVM_ARM64_DEBUG_DIRTY, and set debug to trap - // if not dirty. - ldr x3, [x0, #VCPU_DEBUG_FLAGS] - tbnz x3, #KVM_ARM64_DEBUG_DIRTY_SHIFT, 1f - orr x2, x2, #MDCR_EL2_TDA -1: + // Monitor Debug Config - see kvm_arm_setup_debug() + ldr x2, [x0, #VCPU_MDCR_EL2] msr mdcr_el2, x2 .endm @@ -1285,4 +1276,10 @@ ENTRY(__kvm_hyp_vector) ventry el1_error_invalid // Error 32-bit EL1 ENDPROC(__kvm_hyp_vector) + +ENTRY(__kvm_get_mdcr_el2) + mrs x0, mdcr_el2 + ret +ENDPROC(__kvm_get_mdcr_el2) + .popsection -- GitLab From 4bd611ca60afa155bca25b40312ed61c4d46237f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:57 +0100 Subject: [PATCH 1349/7006] KVM: arm64: guest debug, add SW break point support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for SW breakpoints inserted by userspace. We do this by trapping all guest software debug exceptions to the hypervisor (MDCR_EL2.TDE). The exit handler sets an exit reason of KVM_EXIT_DEBUG with the kvm_debug_exit_arch structure holding the exception syndrome information. It will be up to userspace to extract the PC (via GET_ONE_REG) and determine if the debug event was for a breakpoint it inserted. If not userspace will need to re-inject the correct exception restart the hypervisor to deliver the debug exception to the guest. Any other guest software debug exception (e.g. single step or HW assisted breakpoints) will cause an error and the VM to be killed. This is addressed by later patches which add support for the other debug types. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier --- Documentation/virtual/kvm/api.txt | 2 +- arch/arm64/kvm/debug.c | 3 +++ arch/arm64/kvm/guest.c | 2 +- arch/arm64/kvm/handle_exit.c | 36 +++++++++++++++++++++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 19adfd385882e..0f498da354f26 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2693,7 +2693,7 @@ when running. Common control bits are: The top 16 bits of the control field are architecture specific control flags which can include the following: - - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86] + - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index faf0e1fdba9ee..8d1bfa4383109 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -73,6 +73,9 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + /* Trap breakpoints? */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 0ba86775235d9..22d22c54fd8d1 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -332,7 +332,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, return -EINVAL; } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 524fa25671fc8..27f38a9f9ea27 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -82,6 +82,40 @@ static int kvm_handle_wfx(struct kvm_vcpu *vcpu, struct kvm_run *run) return 1; } +/** + * kvm_handle_guest_debug - handle a debug exception instruction + * + * @vcpu: the vcpu pointer + * @run: access to the kvm_run structure for results + * + * We route all debug exceptions through the same handler. If both the + * guest and host are using the same debug facilities it will be up to + * userspace to re-inject the correct exception for guest delivery. + * + * @return: 0 (while setting run->exit_reason), -1 for error + */ +static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) +{ + u32 hsr = kvm_vcpu_get_hsr(vcpu); + int ret = 0; + + run->exit_reason = KVM_EXIT_DEBUG; + run->debug.arch.hsr = hsr; + + switch (hsr >> ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_BKPT32: + case ESR_ELx_EC_BRK64: + break; + default: + kvm_err("%s: un-handled case hsr: %#08x\n", + __func__, (unsigned int) hsr); + ret = -1; + break; + } + + return ret; +} + static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_WFx] = kvm_handle_wfx, [ESR_ELx_EC_CP15_32] = kvm_handle_cp15_32, @@ -96,6 +130,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, + [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; static exit_handle_fn kvm_get_exit_handler(struct kvm_vcpu *vcpu) -- GitLab From 337b99bf7edfb2044781447e7ca386edb1fdba9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:58 +0100 Subject: [PATCH 1350/7006] KVM: arm64: guest debug, add support for single-step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for single-stepping the guest. To do this we need to manipulate the guests PSTATE.SS and MDSCR_EL1.SS bits to trigger stepping. We take care to preserve MDSCR_EL1 and trap access to it to ensure we don't affect the apparent state of the guest. As we have to enable trapping of all software debug exceptions we suppress the ability of the guest to single-step itself. If we didn't we would have to deal with the exception arriving while the guest was in kernelspace when the guest is expecting to single-step userspace. This is something we don't want to unwind in the kernel. Once the host is no longer debugging the guest its ability to single-step userspace is restored. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier --- arch/arm64/include/asm/kvm_host.h | 11 +++++ arch/arm64/kvm/debug.c | 68 +++++++++++++++++++++++++++++-- arch/arm64/kvm/guest.c | 4 +- arch/arm64/kvm/handle_exit.c | 2 + 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index c90c6a41c448c..cfb675466e86c 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -123,6 +123,17 @@ struct kvm_vcpu_arch { * here. */ + /* + * Guest registers we preserve during guest debugging. + * + * These shadow registers are updated by the kvm_handle_sys_reg + * trap handler if the guest accesses or updates them while we + * are using guest debug. + */ + struct { + u32 mdscr_el1; + } guest_debug_preserved; + /* Don't run the guest */ bool pause; diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 8d1bfa4383109..d439eb8f3239e 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -19,10 +19,38 @@ #include +#include +#include #include +#include + +/* These are the bits of MDSCR_EL1 we may manipulate */ +#define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ + DBG_MDSCR_KDE | \ + DBG_MDSCR_MDE) static DEFINE_PER_CPU(u32, mdcr_el2); +/** + * save/restore_guest_debug_regs + * + * For some debug operations we need to tweak some guest registers. As + * a result we need to save the state of those registers before we + * make those modifications. + * + * Guest access to MDSCR_EL1 is trapped by the hypervisor and handled + * after we have restored the preserved value to the main context. + */ +static void save_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); +} + +static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) +{ + vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; +} + /** * kvm_arm_init_debug - grab what we need for debug * @@ -38,7 +66,6 @@ void kvm_arm_init_debug(void) __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); } - /** * kvm_arm_setup_debug - set up debug related stuff * @@ -73,12 +100,45 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; - /* Trap breakpoints? */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_SW_BP) + /* Is Guest debugging in effect? */ + if (vcpu->guest_debug) { + /* Route all software debug exceptions to EL2 */ vcpu->arch.mdcr_el2 |= MDCR_EL2_TDE; + + /* Save guest debug state */ + save_guest_debug_regs(vcpu); + + /* + * Single Step (ARM ARM D2.12.3 The software step state + * machine) + * + * If we are doing Single Step we need to manipulate + * the guest's MDSCR_EL1.SS and PSTATE.SS. Once the + * step has occurred the hypervisor will trap the + * debug exception and we return to userspace. + * + * If the guest attempts to single step its userspace + * we would have to deal with a trapped exception + * while in the guest kernel. Because this would be + * hard to unwind we suppress the guest's ability to + * do so by masking MDSCR_EL.SS. + * + * This confuses guest debuggers which use + * single-step behind the scenes but everything + * returns to normal once the host is no longer + * debugging the system. + */ + if (vcpu->guest_debug & KVM_GUESTDBG_SINGLESTEP) { + *vcpu_cpsr(vcpu) |= DBG_SPSR_SS; + vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_SS; + } else { + vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; + } + } } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) { - /* Nothing to do yet */ + if (vcpu->guest_debug) + restore_guest_debug_regs(vcpu); } diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 22d22c54fd8d1..48de4f4aaa1a5 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -332,7 +332,9 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, return -EINVAL; } -#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | KVM_GUESTDBG_USE_SW_BP) +#define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ + KVM_GUESTDBG_USE_SW_BP | \ + KVM_GUESTDBG_SINGLESTEP) /** * kvm_arch_vcpu_ioctl_set_guest_debug - set up guest debugging diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index 27f38a9f9ea27..e9de13ed477e6 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -103,6 +103,7 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) run->debug.arch.hsr = hsr; switch (hsr >> ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_SOFTSTP_LOW: case ESR_ELx_EC_BKPT32: case ESR_ELx_EC_BRK64: break; @@ -130,6 +131,7 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_SYS64] = kvm_handle_sys_reg, [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, + [ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug, [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; -- GitLab From e0a1b9a937dc6df9eb402af8966b5d617c7c6b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:29:59 +0100 Subject: [PATCH 1351/7006] KVM: arm64: re-factor hyp.S debug register code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a pre-cursor to sharing the code with the guest debug support. This replaces the big macro that fishes data out of a fixed location with a more general helper macro to restore a set of debug registers. It uses macro substitution so it can be re-used for debug control and value registers. It does however rely on the debug registers being 64 bit aligned (as they happen to be in the hyp ABI). Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier --- arch/arm64/kvm/hyp.S | 517 ++++++++++++------------------------------- 1 file changed, 138 insertions(+), 379 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index b3176e6e51d15..8264f5b4817c6 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -230,199 +230,52 @@ stp x24, x25, [x3, #160] .endm -.macro save_debug - // x2: base address for cpu context - // x3: tmp register - - mrs x26, id_aa64dfr0_el1 - ubfx x24, x26, #12, #4 // Extract BRPs - ubfx x25, x26, #20, #4 // Extract WRPs - mov w26, #15 - sub w24, w26, w24 // How many BPs to skip - sub w25, w26, w25 // How many WPs to skip - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbcr15_el1 - mrs x19, dbgbcr14_el1 - mrs x18, dbgbcr13_el1 - mrs x17, dbgbcr12_el1 - mrs x16, dbgbcr11_el1 - mrs x15, dbgbcr10_el1 - mrs x14, dbgbcr9_el1 - mrs x13, dbgbcr8_el1 - mrs x12, dbgbcr7_el1 - mrs x11, dbgbcr6_el1 - mrs x10, dbgbcr5_el1 - mrs x9, dbgbcr4_el1 - mrs x8, dbgbcr3_el1 - mrs x7, dbgbcr2_el1 - mrs x6, dbgbcr1_el1 - mrs x5, dbgbcr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - mrs x20, dbgbvr15_el1 - mrs x19, dbgbvr14_el1 - mrs x18, dbgbvr13_el1 - mrs x17, dbgbvr12_el1 - mrs x16, dbgbvr11_el1 - mrs x15, dbgbvr10_el1 - mrs x14, dbgbvr9_el1 - mrs x13, dbgbvr8_el1 - mrs x12, dbgbvr7_el1 - mrs x11, dbgbvr6_el1 - mrs x10, dbgbvr5_el1 - mrs x9, dbgbvr4_el1 - mrs x8, dbgbvr3_el1 - mrs x7, dbgbvr2_el1 - mrs x6, dbgbvr1_el1 - mrs x5, dbgbvr0_el1 - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 +.macro save_debug type + // x4: pointer to register set + // x5: number of registers to skip + // x6..x22 trashed + + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - mrs x20, dbgwcr15_el1 - mrs x19, dbgwcr14_el1 - mrs x18, dbgwcr13_el1 - mrs x17, dbgwcr12_el1 - mrs x16, dbgwcr11_el1 - mrs x15, dbgwcr10_el1 - mrs x14, dbgwcr9_el1 - mrs x13, dbgwcr8_el1 - mrs x12, dbgwcr7_el1 - mrs x11, dbgwcr6_el1 - mrs x10, dbgwcr5_el1 - mrs x9, dbgwcr4_el1 - mrs x8, dbgwcr3_el1 - mrs x7, dbgwcr2_el1 - mrs x6, dbgwcr1_el1 - mrs x5, dbgwcr0_el1 - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 + mrs x21, \type\()15_el1 + mrs x20, \type\()14_el1 + mrs x19, \type\()13_el1 + mrs x18, \type\()12_el1 + mrs x17, \type\()11_el1 + mrs x16, \type\()10_el1 + mrs x15, \type\()9_el1 + mrs x14, \type\()8_el1 + mrs x13, \type\()7_el1 + mrs x12, \type\()6_el1 + mrs x11, \type\()5_el1 + mrs x10, \type\()4_el1 + mrs x9, \type\()3_el1 + mrs x8, \type\()2_el1 + mrs x7, \type\()1_el1 + mrs x6, \type\()0_el1 + + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - mrs x20, dbgwvr15_el1 - mrs x19, dbgwvr14_el1 - mrs x18, dbgwvr13_el1 - mrs x17, dbgwvr12_el1 - mrs x16, dbgwvr11_el1 - mrs x15, dbgwvr10_el1 - mrs x14, dbgwvr9_el1 - mrs x13, dbgwvr8_el1 - mrs x12, dbgwvr7_el1 - mrs x11, dbgwvr6_el1 - mrs x10, dbgwvr5_el1 - mrs x9, dbgwvr4_el1 - mrs x8, dbgwvr3_el1 - mrs x7, dbgwvr2_el1 - mrs x6, dbgwvr1_el1 - mrs x5, dbgwvr0_el1 - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 - -1: - str x20, [x3, #(15 * 8)] - str x19, [x3, #(14 * 8)] - str x18, [x3, #(13 * 8)] - str x17, [x3, #(12 * 8)] - str x16, [x3, #(11 * 8)] - str x15, [x3, #(10 * 8)] - str x14, [x3, #(9 * 8)] - str x13, [x3, #(8 * 8)] - str x12, [x3, #(7 * 8)] - str x11, [x3, #(6 * 8)] - str x10, [x3, #(5 * 8)] - str x9, [x3, #(4 * 8)] - str x8, [x3, #(3 * 8)] - str x7, [x3, #(2 * 8)] - str x6, [x3, #(1 * 8)] - str x5, [x3, #(0 * 8)] - - mrs x21, mdccint_el1 - str x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] + str x21, [x4, #(15 * 8)] + str x20, [x4, #(14 * 8)] + str x19, [x4, #(13 * 8)] + str x18, [x4, #(12 * 8)] + str x17, [x4, #(11 * 8)] + str x16, [x4, #(10 * 8)] + str x15, [x4, #(9 * 8)] + str x14, [x4, #(8 * 8)] + str x13, [x4, #(7 * 8)] + str x12, [x4, #(6 * 8)] + str x11, [x4, #(5 * 8)] + str x10, [x4, #(4 * 8)] + str x9, [x4, #(3 * 8)] + str x8, [x4, #(2 * 8)] + str x7, [x4, #(1 * 8)] + str x6, [x4, #(0 * 8)] .endm .macro restore_sysregs @@ -467,195 +320,52 @@ msr mdscr_el1, x25 .endm -.macro restore_debug - // x2: base address for cpu context - // x3: tmp register - - mrs x26, id_aa64dfr0_el1 - ubfx x24, x26, #12, #4 // Extract BRPs - ubfx x25, x26, #20, #4 // Extract WRPs - mov w26, #15 - sub w24, w26, w24 // How many BPs to skip - sub w25, w26, w25 // How many WPs to skip - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) +.macro restore_debug type + // x4: pointer to register set + // x5: number of registers to skip + // x6..x22 trashed - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - ldr x20, [x3, #(15 * 8)] - ldr x19, [x3, #(14 * 8)] - ldr x18, [x3, #(13 * 8)] - ldr x17, [x3, #(12 * 8)] - ldr x16, [x3, #(11 * 8)] - ldr x15, [x3, #(10 * 8)] - ldr x14, [x3, #(9 * 8)] - ldr x13, [x3, #(8 * 8)] - ldr x12, [x3, #(7 * 8)] - ldr x11, [x3, #(6 * 8)] - ldr x10, [x3, #(5 * 8)] - ldr x9, [x3, #(4 * 8)] - ldr x8, [x3, #(3 * 8)] - ldr x7, [x3, #(2 * 8)] - ldr x6, [x3, #(1 * 8)] - ldr x5, [x3, #(0 * 8)] - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 + ldr x21, [x4, #(15 * 8)] + ldr x20, [x4, #(14 * 8)] + ldr x19, [x4, #(13 * 8)] + ldr x18, [x4, #(12 * 8)] + ldr x17, [x4, #(11 * 8)] + ldr x16, [x4, #(10 * 8)] + ldr x15, [x4, #(9 * 8)] + ldr x14, [x4, #(8 * 8)] + ldr x13, [x4, #(7 * 8)] + ldr x12, [x4, #(6 * 8)] + ldr x11, [x4, #(5 * 8)] + ldr x10, [x4, #(4 * 8)] + ldr x9, [x4, #(3 * 8)] + ldr x8, [x4, #(2 * 8)] + ldr x7, [x4, #(1 * 8)] + ldr x6, [x4, #(0 * 8)] + + adr x22, 1f + add x22, x22, x5, lsl #2 + br x22 1: - msr dbgbcr15_el1, x20 - msr dbgbcr14_el1, x19 - msr dbgbcr13_el1, x18 - msr dbgbcr12_el1, x17 - msr dbgbcr11_el1, x16 - msr dbgbcr10_el1, x15 - msr dbgbcr9_el1, x14 - msr dbgbcr8_el1, x13 - msr dbgbcr7_el1, x12 - msr dbgbcr6_el1, x11 - msr dbgbcr5_el1, x10 - msr dbgbcr4_el1, x9 - msr dbgbcr3_el1, x8 - msr dbgbcr2_el1, x7 - msr dbgbcr1_el1, x6 - msr dbgbcr0_el1, x5 - - add x3, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - ldr x20, [x3, #(15 * 8)] - ldr x19, [x3, #(14 * 8)] - ldr x18, [x3, #(13 * 8)] - ldr x17, [x3, #(12 * 8)] - ldr x16, [x3, #(11 * 8)] - ldr x15, [x3, #(10 * 8)] - ldr x14, [x3, #(9 * 8)] - ldr x13, [x3, #(8 * 8)] - ldr x12, [x3, #(7 * 8)] - ldr x11, [x3, #(6 * 8)] - ldr x10, [x3, #(5 * 8)] - ldr x9, [x3, #(4 * 8)] - ldr x8, [x3, #(3 * 8)] - ldr x7, [x3, #(2 * 8)] - ldr x6, [x3, #(1 * 8)] - ldr x5, [x3, #(0 * 8)] - - adr x26, 1f - add x26, x26, x24, lsl #2 - br x26 -1: - msr dbgbvr15_el1, x20 - msr dbgbvr14_el1, x19 - msr dbgbvr13_el1, x18 - msr dbgbvr12_el1, x17 - msr dbgbvr11_el1, x16 - msr dbgbvr10_el1, x15 - msr dbgbvr9_el1, x14 - msr dbgbvr8_el1, x13 - msr dbgbvr7_el1, x12 - msr dbgbvr6_el1, x11 - msr dbgbvr5_el1, x10 - msr dbgbvr4_el1, x9 - msr dbgbvr3_el1, x8 - msr dbgbvr2_el1, x7 - msr dbgbvr1_el1, x6 - msr dbgbvr0_el1, x5 - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 -1: - ldr x20, [x3, #(15 * 8)] - ldr x19, [x3, #(14 * 8)] - ldr x18, [x3, #(13 * 8)] - ldr x17, [x3, #(12 * 8)] - ldr x16, [x3, #(11 * 8)] - ldr x15, [x3, #(10 * 8)] - ldr x14, [x3, #(9 * 8)] - ldr x13, [x3, #(8 * 8)] - ldr x12, [x3, #(7 * 8)] - ldr x11, [x3, #(6 * 8)] - ldr x10, [x3, #(5 * 8)] - ldr x9, [x3, #(4 * 8)] - ldr x8, [x3, #(3 * 8)] - ldr x7, [x3, #(2 * 8)] - ldr x6, [x3, #(1 * 8)] - ldr x5, [x3, #(0 * 8)] - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 -1: - msr dbgwcr15_el1, x20 - msr dbgwcr14_el1, x19 - msr dbgwcr13_el1, x18 - msr dbgwcr12_el1, x17 - msr dbgwcr11_el1, x16 - msr dbgwcr10_el1, x15 - msr dbgwcr9_el1, x14 - msr dbgwcr8_el1, x13 - msr dbgwcr7_el1, x12 - msr dbgwcr6_el1, x11 - msr dbgwcr5_el1, x10 - msr dbgwcr4_el1, x9 - msr dbgwcr3_el1, x8 - msr dbgwcr2_el1, x7 - msr dbgwcr1_el1, x6 - msr dbgwcr0_el1, x5 - - add x3, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 -1: - ldr x20, [x3, #(15 * 8)] - ldr x19, [x3, #(14 * 8)] - ldr x18, [x3, #(13 * 8)] - ldr x17, [x3, #(12 * 8)] - ldr x16, [x3, #(11 * 8)] - ldr x15, [x3, #(10 * 8)] - ldr x14, [x3, #(9 * 8)] - ldr x13, [x3, #(8 * 8)] - ldr x12, [x3, #(7 * 8)] - ldr x11, [x3, #(6 * 8)] - ldr x10, [x3, #(5 * 8)] - ldr x9, [x3, #(4 * 8)] - ldr x8, [x3, #(3 * 8)] - ldr x7, [x3, #(2 * 8)] - ldr x6, [x3, #(1 * 8)] - ldr x5, [x3, #(0 * 8)] - - adr x26, 1f - add x26, x26, x25, lsl #2 - br x26 -1: - msr dbgwvr15_el1, x20 - msr dbgwvr14_el1, x19 - msr dbgwvr13_el1, x18 - msr dbgwvr12_el1, x17 - msr dbgwvr11_el1, x16 - msr dbgwvr10_el1, x15 - msr dbgwvr9_el1, x14 - msr dbgwvr8_el1, x13 - msr dbgwvr7_el1, x12 - msr dbgwvr6_el1, x11 - msr dbgwvr5_el1, x10 - msr dbgwvr4_el1, x9 - msr dbgwvr3_el1, x8 - msr dbgwvr2_el1, x7 - msr dbgwvr1_el1, x6 - msr dbgwvr0_el1, x5 - - ldr x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] - msr mdccint_el1, x21 + msr \type\()15_el1, x21 + msr \type\()14_el1, x20 + msr \type\()13_el1, x19 + msr \type\()12_el1, x18 + msr \type\()11_el1, x17 + msr \type\()10_el1, x16 + msr \type\()9_el1, x15 + msr \type\()8_el1, x14 + msr \type\()7_el1, x13 + msr \type\()6_el1, x12 + msr \type\()5_el1, x11 + msr \type\()4_el1, x10 + msr \type\()3_el1, x9 + msr \type\()2_el1, x8 + msr \type\()1_el1, x7 + msr \type\()0_el1, x6 .endm .macro skip_32bit_state tmp, target @@ -883,12 +593,61 @@ __restore_sysregs: restore_sysregs ret +/* Save debug state */ __save_debug: - save_debug + // x2: ptr to CPU context + // x4/x5/x6-22/x24-26: trashed + + mrs x26, id_aa64dfr0_el1 + ubfx x24, x26, #12, #4 // Extract BRPs + ubfx x25, x26, #20, #4 // Extract WRPs + mov w26, #15 + sub w24, w26, w24 // How many BPs to skip + sub w25, w26, w25 // How many WPs to skip + + mov x5, x24 + add x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) + save_debug dbgbcr + add x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) + save_debug dbgbvr + + mov x5, x25 + add x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) + save_debug dbgwcr + add x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) + save_debug dbgwvr + + mrs x21, mdccint_el1 + str x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] ret +/* Restore debug state */ __restore_debug: - restore_debug + // x2: ptr to CPU context + // x4/x5/x6-22/x24-26: trashed + + mrs x26, id_aa64dfr0_el1 + ubfx x24, x26, #12, #4 // Extract BRPs + ubfx x25, x26, #20, #4 // Extract WRPs + mov w26, #15 + sub w24, w26, w24 // How many BPs to skip + sub w25, w26, w25 // How many WPs to skip + + mov x5, x24 + add x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) + restore_debug dbgbcr + add x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) + restore_debug dbgbvr + + mov x5, x25 + add x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) + restore_debug dbgwcr + add x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) + restore_debug dbgwvr + + ldr x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] + msr mdccint_el1, x21 + ret __save_fpsimd: -- GitLab From 84e690bfbed1d1ecb45d8eccd4c7b6c8e878da1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:30:00 +0100 Subject: [PATCH 1352/7006] KVM: arm64: introduce vcpu->arch.debug_ptr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces a level of indirection for the debug registers. Instead of using the sys_regs[] directly we store registers in a structure in the vcpu. The new kvm_arm_reset_debug_ptr() sets the debug ptr to the guest context. Because we no longer give the sys_regs offset for the sys_reg_desc->reg field, but instead the index into a debug-specific struct we need to add a number of additional trap functions for each register. Also as the generic generic user-space access code no longer works we have introduced a new pair of function pointers to the sys_reg_desc structure to override the generic code when needed. Reviewed-by: Christoffer Dall Signed-off-by: Alex Bennée Signed-off-by: Marc Zyngier --- arch/arm/include/asm/kvm_host.h | 1 + arch/arm/kvm/arm.c | 2 + arch/arm64/include/asm/kvm_asm.h | 24 +-- arch/arm64/include/asm/kvm_host.h | 17 +- arch/arm64/kernel/asm-offsets.c | 6 + arch/arm64/kvm/debug.c | 9 + arch/arm64/kvm/hyp.S | 24 ++- arch/arm64/kvm/sys_regs.c | 274 +++++++++++++++++++++++++++--- arch/arm64/kvm/sys_regs.h | 6 + 9 files changed, 316 insertions(+), 47 deletions(-) diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h index 2b0bc8c575528..dcba0fa5176e9 100644 --- a/arch/arm/include/asm/kvm_host.h +++ b/arch/arm/include/asm/kvm_host.h @@ -234,5 +234,6 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} static inline void kvm_arm_init_debug(void) {} static inline void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) {} static inline void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) {} +static inline void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) {} #endif /* __ARM_KVM_HOST_H__ */ diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 77151b111d32d..9ce5cf02ed178 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -278,6 +278,8 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) /* Set up the timer */ kvm_timer_vcpu_init(vcpu); + kvm_arm_reset_debug_ptr(vcpu); + return 0; } diff --git a/arch/arm64/include/asm/kvm_asm.h b/arch/arm64/include/asm/kvm_asm.h index f5e40dae291ab..67fa0de3d4832 100644 --- a/arch/arm64/include/asm/kvm_asm.h +++ b/arch/arm64/include/asm/kvm_asm.h @@ -46,24 +46,16 @@ #define CNTKCTL_EL1 20 /* Timer Control Register (EL1) */ #define PAR_EL1 21 /* Physical Address Register */ #define MDSCR_EL1 22 /* Monitor Debug System Control Register */ -#define DBGBCR0_EL1 23 /* Debug Breakpoint Control Registers (0-15) */ -#define DBGBCR15_EL1 38 -#define DBGBVR0_EL1 39 /* Debug Breakpoint Value Registers (0-15) */ -#define DBGBVR15_EL1 54 -#define DBGWCR0_EL1 55 /* Debug Watchpoint Control Registers (0-15) */ -#define DBGWCR15_EL1 70 -#define DBGWVR0_EL1 71 /* Debug Watchpoint Value Registers (0-15) */ -#define DBGWVR15_EL1 86 -#define MDCCINT_EL1 87 /* Monitor Debug Comms Channel Interrupt Enable Reg */ +#define MDCCINT_EL1 23 /* Monitor Debug Comms Channel Interrupt Enable Reg */ /* 32bit specific registers. Keep them at the end of the range */ -#define DACR32_EL2 88 /* Domain Access Control Register */ -#define IFSR32_EL2 89 /* Instruction Fault Status Register */ -#define FPEXC32_EL2 90 /* Floating-Point Exception Control Register */ -#define DBGVCR32_EL2 91 /* Debug Vector Catch Register */ -#define TEECR32_EL1 92 /* ThumbEE Configuration Register */ -#define TEEHBR32_EL1 93 /* ThumbEE Handler Base Register */ -#define NR_SYS_REGS 94 +#define DACR32_EL2 24 /* Domain Access Control Register */ +#define IFSR32_EL2 25 /* Instruction Fault Status Register */ +#define FPEXC32_EL2 26 /* Floating-Point Exception Control Register */ +#define DBGVCR32_EL2 27 /* Debug Vector Catch Register */ +#define TEECR32_EL1 28 /* ThumbEE Configuration Register */ +#define TEEHBR32_EL1 29 /* ThumbEE Handler Base Register */ +#define NR_SYS_REGS 30 /* 32bit mapping */ #define c0_MPIDR (MPIDR_EL1 * 2) /* MultiProcessor ID Register */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index cfb675466e86c..9b99402b14df0 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -108,11 +108,25 @@ struct kvm_vcpu_arch { /* Exception Information */ struct kvm_vcpu_fault_info fault; - /* Debug state */ + /* Guest debug state */ u64 debug_flags; + /* + * We maintain more than a single set of debug registers to support + * debugging the guest from the host and to maintain separate host and + * guest state during world switches. vcpu_debug_state are the debug + * registers of the vcpu as the guest sees them. host_debug_state are + * the host registers which are saved and restored during world switches. + * + * debug_ptr points to the set of debug registers that should be loaded + * onto the hardware when running the guest. + */ + struct kvm_guest_debug_arch *debug_ptr; + struct kvm_guest_debug_arch vcpu_debug_state; + /* Pointer to host CPU context */ kvm_cpu_context_t *host_cpu_context; + struct kvm_guest_debug_arch host_debug_state; /* VGIC state */ struct vgic_cpu vgic_cpu; @@ -242,5 +256,6 @@ static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} void kvm_arm_init_debug(void); void kvm_arm_setup_debug(struct kvm_vcpu *vcpu); void kvm_arm_clear_debug(struct kvm_vcpu *vcpu); +void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu); #endif /* __ARM64_KVM_HOST_H__ */ diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 5c900d49b9068..d88630899a242 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -116,10 +116,16 @@ int main(void) DEFINE(VCPU_FAR_EL2, offsetof(struct kvm_vcpu, arch.fault.far_el2)); DEFINE(VCPU_HPFAR_EL2, offsetof(struct kvm_vcpu, arch.fault.hpfar_el2)); DEFINE(VCPU_DEBUG_FLAGS, offsetof(struct kvm_vcpu, arch.debug_flags)); + DEFINE(VCPU_DEBUG_PTR, offsetof(struct kvm_vcpu, arch.debug_ptr)); + DEFINE(DEBUG_BCR, offsetof(struct kvm_guest_debug_arch, dbg_bcr)); + DEFINE(DEBUG_BVR, offsetof(struct kvm_guest_debug_arch, dbg_bvr)); + DEFINE(DEBUG_WCR, offsetof(struct kvm_guest_debug_arch, dbg_wcr)); + DEFINE(DEBUG_WVR, offsetof(struct kvm_guest_debug_arch, dbg_wvr)); DEFINE(VCPU_HCR_EL2, offsetof(struct kvm_vcpu, arch.hcr_el2)); DEFINE(VCPU_MDCR_EL2, offsetof(struct kvm_vcpu, arch.mdcr_el2)); DEFINE(VCPU_IRQ_LINES, offsetof(struct kvm_vcpu, arch.irq_lines)); DEFINE(VCPU_HOST_CONTEXT, offsetof(struct kvm_vcpu, arch.host_cpu_context)); + DEFINE(VCPU_HOST_DEBUG_STATE, offsetof(struct kvm_vcpu, arch.host_debug_state)); DEFINE(VCPU_TIMER_CNTV_CTL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_ctl)); DEFINE(VCPU_TIMER_CNTV_CVAL, offsetof(struct kvm_vcpu, arch.timer_cpu.cntv_cval)); DEFINE(KVM_TIMER_CNTVOFF, offsetof(struct kvm, arch.timer.cntvoff)); diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index d439eb8f3239e..e0947b77faaab 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -66,6 +66,15 @@ void kvm_arm_init_debug(void) __this_cpu_write(mdcr_el2, kvm_call_hyp(__kvm_get_mdcr_el2)); } +/** + * kvm_arm_reset_debug_ptr - reset the debug ptr to point to the vcpu state + */ + +void kvm_arm_reset_debug_ptr(struct kvm_vcpu *vcpu) +{ + vcpu->arch.debug_ptr = &vcpu->arch.vcpu_debug_state; +} + /** * kvm_arm_setup_debug - set up debug related stuff * diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 8264f5b4817c6..d93c0a23630e6 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -596,6 +596,7 @@ __restore_sysregs: /* Save debug state */ __save_debug: // x2: ptr to CPU context + // x3: ptr to debug reg struct // x4/x5/x6-22/x24-26: trashed mrs x26, id_aa64dfr0_el1 @@ -606,15 +607,15 @@ __save_debug: sub w25, w26, w25 // How many WPs to skip mov x5, x24 - add x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) + add x4, x3, #DEBUG_BCR save_debug dbgbcr - add x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) + add x4, x3, #DEBUG_BVR save_debug dbgbvr mov x5, x25 - add x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) + add x4, x3, #DEBUG_WCR save_debug dbgwcr - add x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) + add x4, x3, #DEBUG_WVR save_debug dbgwvr mrs x21, mdccint_el1 @@ -624,6 +625,7 @@ __save_debug: /* Restore debug state */ __restore_debug: // x2: ptr to CPU context + // x3: ptr to debug reg struct // x4/x5/x6-22/x24-26: trashed mrs x26, id_aa64dfr0_el1 @@ -634,15 +636,15 @@ __restore_debug: sub w25, w26, w25 // How many WPs to skip mov x5, x24 - add x4, x2, #CPU_SYSREG_OFFSET(DBGBCR0_EL1) + add x4, x3, #DEBUG_BCR restore_debug dbgbcr - add x4, x2, #CPU_SYSREG_OFFSET(DBGBVR0_EL1) + add x4, x3, #DEBUG_BVR restore_debug dbgbvr mov x5, x25 - add x4, x2, #CPU_SYSREG_OFFSET(DBGWCR0_EL1) + add x4, x3, #DEBUG_WCR restore_debug dbgwcr - add x4, x2, #CPU_SYSREG_OFFSET(DBGWVR0_EL1) + add x4, x3, #DEBUG_WVR restore_debug dbgwvr ldr x21, [x2, #CPU_SYSREG_OFFSET(MDCCINT_EL1)] @@ -682,6 +684,7 @@ ENTRY(__kvm_vcpu_run) bl __save_sysregs compute_debug_state 1f + add x3, x0, #VCPU_HOST_DEBUG_STATE bl __save_debug 1: activate_traps @@ -697,6 +700,8 @@ ENTRY(__kvm_vcpu_run) bl __restore_fpsimd skip_debug_state x3, 1f + ldr x3, [x0, #VCPU_DEBUG_PTR] + kern_hyp_va x3 bl __restore_debug 1: restore_guest_32bit_state @@ -717,6 +722,8 @@ __kvm_vcpu_return: bl __save_sysregs skip_debug_state x3, 1f + ldr x3, [x0, #VCPU_DEBUG_PTR] + kern_hyp_va x3 bl __save_debug 1: save_guest_32bit_state @@ -739,6 +746,7 @@ __kvm_vcpu_return: // already been saved. Note that we nuke the whole 64bit word. // If we ever add more flags, we'll have to be more careful... str xzr, [x0, #VCPU_DEBUG_FLAGS] + add x3, x0, #VCPU_HOST_DEBUG_STATE bl __restore_debug 1: restore_host_regs diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index c370b40147996..158bae7c52cc4 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -211,6 +211,203 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, return true; } +/* + * reg_to_dbg/dbg_to_reg + * + * A 32 bit write to a debug register leave top bits alone + * A 32 bit read from a debug register only returns the bottom bits + * + * All writes will set the KVM_ARM64_DEBUG_DIRTY flag to ensure the + * hyp.S code switches between host and guest values in future. + */ +static inline void reg_to_dbg(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + u64 *dbg_reg) +{ + u64 val = *vcpu_reg(vcpu, p->Rt); + + if (p->is_32bit) { + val &= 0xffffffffUL; + val |= ((*dbg_reg >> 32) << 32); + } + + *dbg_reg = val; + vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; +} + +static inline void dbg_to_reg(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + u64 *dbg_reg) +{ + u64 val = *dbg_reg; + + if (p->is_32bit) + val &= 0xffffffffUL; + + *vcpu_reg(vcpu, p->Rt) = val; +} + +static inline bool trap_bvr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; + + if (p->is_write) + reg_to_dbg(vcpu, p, dbg_reg); + else + dbg_to_reg(vcpu, p, dbg_reg); + + return true; +} + +static int set_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; + + if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static int get_bvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; + + if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static inline void reset_bvr(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg] = rd->val; +} + +static inline bool trap_bcr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg]; + + if (p->is_write) + reg_to_dbg(vcpu, p, dbg_reg); + else + dbg_to_reg(vcpu, p, dbg_reg); + + return true; +} + +static int set_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg]; + + if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + + return 0; +} + +static int get_bcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg]; + + if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static inline void reset_bcr(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + vcpu->arch.vcpu_debug_state.dbg_bcr[rd->reg] = rd->val; +} + +static inline bool trap_wvr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]; + + if (p->is_write) + reg_to_dbg(vcpu, p, dbg_reg); + else + dbg_to_reg(vcpu, p, dbg_reg); + + return true; +} + +static int set_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]; + + if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static int get_wvr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]; + + if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static inline void reset_wvr(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg] = rd->val; +} + +static inline bool trap_wcr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg]; + + if (p->is_write) + reg_to_dbg(vcpu, p, dbg_reg); + else + dbg_to_reg(vcpu, p, dbg_reg); + + return true; +} + +static int set_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg]; + + if (copy_from_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static int get_wcr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr) +{ + __u64 *r = &vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg]; + + if (copy_to_user(uaddr, r, KVM_REG_SIZE(reg->id)) != 0) + return -EFAULT; + return 0; +} + +static inline void reset_wcr(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd) +{ + vcpu->arch.vcpu_debug_state.dbg_wcr[rd->reg] = rd->val; +} + static void reset_amair_el1(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) { u64 amair; @@ -240,16 +437,16 @@ static void reset_mpidr(struct kvm_vcpu *vcpu, const struct sys_reg_desc *r) #define DBG_BCR_BVR_WCR_WVR_EL1(n) \ /* DBGBVRn_EL1 */ \ { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b100), \ - trap_debug_regs, reset_val, (DBGBVR0_EL1 + (n)), 0 }, \ + trap_bvr, reset_bvr, n, 0, get_bvr, set_bvr }, \ /* DBGBCRn_EL1 */ \ { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b101), \ - trap_debug_regs, reset_val, (DBGBCR0_EL1 + (n)), 0 }, \ + trap_bcr, reset_bcr, n, 0, get_bcr, set_bcr }, \ /* DBGWVRn_EL1 */ \ { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b110), \ - trap_debug_regs, reset_val, (DBGWVR0_EL1 + (n)), 0 }, \ + trap_wvr, reset_wvr, n, 0, get_wvr, set_wvr }, \ /* DBGWCRn_EL1 */ \ { Op0(0b10), Op1(0b000), CRn(0b0000), CRm((n)), Op2(0b111), \ - trap_debug_regs, reset_val, (DBGWCR0_EL1 + (n)), 0 } + trap_wcr, reset_wcr, n, 0, get_wcr, set_wcr } /* * Architected system registers. @@ -516,28 +713,55 @@ static bool trap_debug32(struct kvm_vcpu *vcpu, return true; } -#define DBG_BCR_BVR_WCR_WVR(n) \ - /* DBGBVRn */ \ - { Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_debug32, \ - NULL, (cp14_DBGBVR0 + (n) * 2) }, \ - /* DBGBCRn */ \ - { Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_debug32, \ - NULL, (cp14_DBGBCR0 + (n) * 2) }, \ - /* DBGWVRn */ \ - { Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_debug32, \ - NULL, (cp14_DBGWVR0 + (n) * 2) }, \ - /* DBGWCRn */ \ - { Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_debug32, \ - NULL, (cp14_DBGWCR0 + (n) * 2) } - -#define DBGBXVR(n) \ - { Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_debug32, \ - NULL, cp14_DBGBXVR0 + n * 2 } +/* AArch32 debug register mappings + * + * AArch32 DBGBVRn is mapped to DBGBVRn_EL1[31:0] + * AArch32 DBGBXVRn is mapped to DBGBVRn_EL1[63:32] + * + * All control registers and watchpoint value registers are mapped to + * the lower 32 bits of their AArch64 equivalents. We share the trap + * handlers with the above AArch64 code which checks what mode the + * system is in. + */ + +static inline bool trap_xvr(struct kvm_vcpu *vcpu, + const struct sys_reg_params *p, + const struct sys_reg_desc *rd) +{ + u64 *dbg_reg = &vcpu->arch.vcpu_debug_state.dbg_bvr[rd->reg]; + + if (p->is_write) { + u64 val = *dbg_reg; + + val &= 0xffffffffUL; + val |= *vcpu_reg(vcpu, p->Rt) << 32; + *dbg_reg = val; + + vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; + } else { + *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32; + } + + return true; +} + +#define DBG_BCR_BVR_WCR_WVR(n) \ + /* DBGBVRn */ \ + { Op1( 0), CRn( 0), CRm((n)), Op2( 4), trap_bvr, NULL, n }, \ + /* DBGBCRn */ \ + { Op1( 0), CRn( 0), CRm((n)), Op2( 5), trap_bcr, NULL, n }, \ + /* DBGWVRn */ \ + { Op1( 0), CRn( 0), CRm((n)), Op2( 6), trap_wvr, NULL, n }, \ + /* DBGWCRn */ \ + { Op1( 0), CRn( 0), CRm((n)), Op2( 7), trap_wcr, NULL, n } + +#define DBGBXVR(n) \ + { Op1( 0), CRn( 1), CRm((n)), Op2( 1), trap_xvr, NULL, n } /* * Trapped cp14 registers. We generally ignore most of the external * debug, on the principle that they don't really make sense to a - * guest. Revisit this one day, whould this principle change. + * guest. Revisit this one day, would this principle change. */ static const struct sys_reg_desc cp14_regs[] = { /* DBGIDR */ @@ -1303,6 +1527,9 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (!r) return get_invariant_sys_reg(reg->id, uaddr); + if (r->get_user) + return (r->get_user)(vcpu, r, reg, uaddr); + return reg_to_user(uaddr, &vcpu_sys_reg(vcpu, r->reg), reg->id); } @@ -1321,6 +1548,9 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (!r) return set_invariant_sys_reg(reg->id, uaddr); + if (r->set_user) + return (r->set_user)(vcpu, r, reg, uaddr); + return reg_from_user(&vcpu_sys_reg(vcpu, r->reg), uaddr, reg->id); } diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index d411e251412c3..eaa324e4db4da 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -55,6 +55,12 @@ struct sys_reg_desc { /* Value (usually reset value) */ u64 val; + + /* Custom get/set_user functions, fallback to generic if NULL */ + int (*get_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr); + int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr); }; static inline void print_sys_reg_instr(const struct sys_reg_params *p) -- GitLab From 5540546bc93b49f98a0466fe3f96615286c76574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:30:01 +0100 Subject: [PATCH 1353/7006] KVM: arm64: guest debug, HW assisted debug support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds support for userspace to control the HW debug registers for guest debug. In the debug ioctl we copy an IMPDEF registers into a new register set called host_debug_state. We use the recently introduced vcpu parameter debug_ptr to select which register set is copied into the real registers when world switch occurs. I've made some helper functions from hw_breakpoint.c more widely available for re-use. As with single step we need to tweak the guest registers to enable the exceptions so we need to save and restore those bits. Two new capabilities have been added to the KVM_EXTENSION ioctl to allow userspace to query the number of hardware break and watch points available on the host hardware. Signed-off-by: Alex Bennée Reviewed-by: Christoffer Dall Signed-off-by: Marc Zyngier --- include/uapi/linux/kvm.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 4ab3c6a8d5639..a1e08e7bbf20a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -820,6 +820,8 @@ struct kvm_ppc_smmu_info { #define KVM_CAP_DISABLE_QUIRKS 116 #define KVM_CAP_X86_SMM 117 #define KVM_CAP_MULTI_ADDRESS_SPACE 118 +#define KVM_CAP_GUEST_DEBUG_HW_BPS 119 +#define KVM_CAP_GUEST_DEBUG_HW_WPS 120 #ifdef KVM_CAP_IRQ_ROUTING -- GitLab From 834bf88726f0f11ddc7ff9679fc9458654c01a12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:30:02 +0100 Subject: [PATCH 1354/7006] KVM: arm64: enable KVM_CAP_SET_GUEST_DEBUG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Finally advertise the KVM capability for SET_GUEST_DEBUG. Once arm support is added this check can be moved to the common kvm_vm_ioctl_check_extension() code. Signed-off-by: Alex Bennée Acked-by: Christoffer Dall Signed-off-by: Marc Zyngier --- Documentation/virtual/kvm/api.txt | 7 ++++- arch/arm64/include/asm/hw_breakpoint.h | 14 +++++++++ arch/arm64/include/asm/kvm_host.h | 6 +++- arch/arm64/kernel/hw_breakpoint.c | 12 -------- arch/arm64/kvm/debug.c | 40 ++++++++++++++++++++++---- arch/arm64/kvm/guest.c | 7 +++++ arch/arm64/kvm/handle_exit.c | 6 ++++ arch/arm64/kvm/reset.c | 16 +++++++++++ 8 files changed, 89 insertions(+), 19 deletions(-) diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt index 0f498da354f26..35affb5d94561 100644 --- a/Documentation/virtual/kvm/api.txt +++ b/Documentation/virtual/kvm/api.txt @@ -2694,7 +2694,7 @@ The top 16 bits of the control field are architecture specific control flags which can include the following: - KVM_GUESTDBG_USE_SW_BP: using software breakpoints [x86, arm64] - - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390] + - KVM_GUESTDBG_USE_HW_BP: using hardware breakpoints [x86, s390, arm64] - KVM_GUESTDBG_INJECT_DB: inject DB type exception [x86] - KVM_GUESTDBG_INJECT_BP: inject BP type exception [x86] - KVM_GUESTDBG_EXIT_PENDING: trigger an immediate guest exit [s390] @@ -2709,6 +2709,11 @@ updated to the correct (supplied) values. The second part of the structure is architecture specific and typically contains a set of debug registers. +For arm64 the number of debug registers is implementation defined and +can be determined by querying the KVM_CAP_GUEST_DEBUG_HW_BPS and +KVM_CAP_GUEST_DEBUG_HW_WPS capabilities which return a positive number +indicating the number of supported registers. + When debug events exit the main run loop with the reason KVM_EXIT_DEBUG with the kvm_debug_exit_arch part of the kvm_run structure containing architecture specific debug information. diff --git a/arch/arm64/include/asm/hw_breakpoint.h b/arch/arm64/include/asm/hw_breakpoint.h index 52b484b6aa1a7..4c47cb2fbb526 100644 --- a/arch/arm64/include/asm/hw_breakpoint.h +++ b/arch/arm64/include/asm/hw_breakpoint.h @@ -16,6 +16,8 @@ #ifndef __ASM_HW_BREAKPOINT_H #define __ASM_HW_BREAKPOINT_H +#include + #ifdef __KERNEL__ struct arch_hw_breakpoint_ctrl { @@ -132,5 +134,17 @@ static inline void ptrace_hw_copy_thread(struct task_struct *task) extern struct pmu perf_ops_bp; +/* Determine number of BRP registers available. */ +static inline int get_num_brps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; +} + +/* Determine number of WRP registers available. */ +static inline int get_num_wrps(void) +{ + return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; +} + #endif /* __KERNEL__ */ #endif /* __ASM_BREAKPOINT_H */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 9b99402b14df0..409217f484567 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -116,13 +116,17 @@ struct kvm_vcpu_arch { * debugging the guest from the host and to maintain separate host and * guest state during world switches. vcpu_debug_state are the debug * registers of the vcpu as the guest sees them. host_debug_state are - * the host registers which are saved and restored during world switches. + * the host registers which are saved and restored during + * world switches. external_debug_state contains the debug + * values we want to debug the guest. This is set via the + * KVM_SET_GUEST_DEBUG ioctl. * * debug_ptr points to the set of debug registers that should be loaded * onto the hardware when running the guest. */ struct kvm_guest_debug_arch *debug_ptr; struct kvm_guest_debug_arch vcpu_debug_state; + struct kvm_guest_debug_arch external_debug_state; /* Pointer to host CPU context */ kvm_cpu_context_t *host_cpu_context; diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index 7a1a5da6c8c1b..77bee00bd7ea0 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -48,18 +48,6 @@ static DEFINE_PER_CPU(int, stepping_kernel_bp); static int core_num_brps; static int core_num_wrps; -/* Determine number of BRP registers available. */ -static int get_num_brps(void) -{ - return ((read_cpuid(ID_AA64DFR0_EL1) >> 12) & 0xf) + 1; -} - -/* Determine number of WRP registers available. */ -static int get_num_wrps(void) -{ - return ((read_cpuid(ID_AA64DFR0_EL1) >> 20) & 0xf) + 1; -} - int hw_breakpoint_slots(int type) { /* diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index e0947b77faaab..4a99e54d7f3db 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -105,10 +105,6 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) MDCR_EL2_TDRA | MDCR_EL2_TDOSA); - /* Trap on access to debug registers? */ - if (trap_debug) - vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; - /* Is Guest debugging in effect? */ if (vcpu->guest_debug) { /* Route all software debug exceptions to EL2 */ @@ -143,11 +139,45 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) } else { vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; } + + /* + * HW Breakpoints and watchpoints + * + * We simply switch the debug_ptr to point to our new + * external_debug_state which has been populated by the + * debug ioctl. The existing KVM_ARM64_DEBUG_DIRTY + * mechanism ensures the registers are updated on the + * world switch. + */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { + /* Enable breakpoints/watchpoints */ + vcpu_sys_reg(vcpu, MDSCR_EL1) |= DBG_MDSCR_MDE; + + vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; + vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; + trap_debug = true; + } } + + BUG_ON(!vcpu->guest_debug && + vcpu->arch.debug_ptr != &vcpu->arch.vcpu_debug_state); + + /* Trap debug register access */ + if (trap_debug) + vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) { - if (vcpu->guest_debug) + if (vcpu->guest_debug) { restore_guest_debug_regs(vcpu); + + /* + * If we were using HW debug we need to restore the + * debug_ptr to the guest debug state. + */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) + kvm_arm_reset_debug_ptr(vcpu); + + } } diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 48de4f4aaa1a5..6f1b249e05873 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -334,6 +334,7 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \ KVM_GUESTDBG_USE_SW_BP | \ + KVM_GUESTDBG_USE_HW | \ KVM_GUESTDBG_SINGLESTEP) /** @@ -354,6 +355,12 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, if (dbg->control & KVM_GUESTDBG_ENABLE) { vcpu->guest_debug = dbg->control; + + /* Hardware assisted Break and Watch points */ + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { + vcpu->arch.external_debug_state = dbg->arch; + } + } else { /* If not enabled clear all flags */ vcpu->guest_debug = 0; diff --git a/arch/arm64/kvm/handle_exit.c b/arch/arm64/kvm/handle_exit.c index e9de13ed477e6..68a0759b1375e 100644 --- a/arch/arm64/kvm/handle_exit.c +++ b/arch/arm64/kvm/handle_exit.c @@ -103,7 +103,11 @@ static int kvm_handle_guest_debug(struct kvm_vcpu *vcpu, struct kvm_run *run) run->debug.arch.hsr = hsr; switch (hsr >> ESR_ELx_EC_SHIFT) { + case ESR_ELx_EC_WATCHPT_LOW: + run->debug.arch.far = vcpu->arch.fault.far_el2; + /* fall through */ case ESR_ELx_EC_SOFTSTP_LOW: + case ESR_ELx_EC_BREAKPT_LOW: case ESR_ELx_EC_BKPT32: case ESR_ELx_EC_BRK64: break; @@ -132,6 +136,8 @@ static exit_handle_fn arm_exit_handlers[] = { [ESR_ELx_EC_IABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_DABT_LOW] = kvm_handle_guest_abort, [ESR_ELx_EC_SOFTSTP_LOW]= kvm_handle_guest_debug, + [ESR_ELx_EC_WATCHPT_LOW]= kvm_handle_guest_debug, + [ESR_ELx_EC_BREAKPT_LOW]= kvm_handle_guest_debug, [ESR_ELx_EC_BKPT32] = kvm_handle_guest_debug, [ESR_ELx_EC_BRK64] = kvm_handle_guest_debug, }; diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c index 0b43265789858..b4af6185713f6 100644 --- a/arch/arm64/kvm/reset.c +++ b/arch/arm64/kvm/reset.c @@ -22,6 +22,7 @@ #include #include #include +#include #include @@ -56,6 +57,12 @@ static bool cpu_has_32bit_el1(void) return !!(pfr0 & 0x20); } +/** + * kvm_arch_dev_ioctl_check_extension + * + * We currently assume that the number of HW registers is uniform + * across all CPUs (see cpuinfo_sanity_check). + */ int kvm_arch_dev_ioctl_check_extension(long ext) { int r; @@ -64,6 +71,15 @@ int kvm_arch_dev_ioctl_check_extension(long ext) case KVM_CAP_ARM_EL1_32BIT: r = cpu_has_32bit_el1(); break; + case KVM_CAP_GUEST_DEBUG_HW_BPS: + r = get_num_brps(); + break; + case KVM_CAP_GUEST_DEBUG_HW_WPS: + r = get_num_wrps(); + break; + case KVM_CAP_SET_GUEST_DEBUG: + r = 1; + break; default: r = 0; } -- GitLab From eef8c85a3b81301f912e8802a1dd9f42dd884947 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Benn=C3=A9e?= Date: Tue, 7 Jul 2015 17:30:03 +0100 Subject: [PATCH 1355/7006] KVM: arm64: add trace points for guest_debug debug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This includes trace points for: kvm_arch_setup_guest_debug kvm_arch_clear_guest_debug I've also added some generic register setting trace events and also a trace point to dump the array of hardware registers. Acked-by: Christoffer Dall Signed-off-by: Alex Bennée Signed-off-by: Marc Zyngier --- arch/arm64/kvm/debug.c | 36 ++++++++++- arch/arm64/kvm/guest.c | 4 ++ arch/arm64/kvm/sys_regs.c | 17 ++++++ arch/arm64/kvm/trace.h | 123 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 179 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/debug.c b/arch/arm64/kvm/debug.c index 4a99e54d7f3db..47e5f0feaee82 100644 --- a/arch/arm64/kvm/debug.c +++ b/arch/arm64/kvm/debug.c @@ -18,12 +18,15 @@ */ #include +#include #include #include #include #include +#include "trace.h" + /* These are the bits of MDSCR_EL1 we may manipulate */ #define MDSCR_EL1_DEBUG_MASK (DBG_MDSCR_SS | \ DBG_MDSCR_KDE | \ @@ -44,11 +47,17 @@ static DEFINE_PER_CPU(u32, mdcr_el2); static void save_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu->arch.guest_debug_preserved.mdscr_el1 = vcpu_sys_reg(vcpu, MDSCR_EL1); + + trace_kvm_arm_set_dreg32("Saved MDSCR_EL1", + vcpu->arch.guest_debug_preserved.mdscr_el1); } static void restore_guest_debug_regs(struct kvm_vcpu *vcpu) { vcpu_sys_reg(vcpu, MDSCR_EL1) = vcpu->arch.guest_debug_preserved.mdscr_el1; + + trace_kvm_arm_set_dreg32("Restored MDSCR_EL1", + vcpu_sys_reg(vcpu, MDSCR_EL1)); } /** @@ -99,6 +108,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) { bool trap_debug = !(vcpu->arch.debug_flags & KVM_ARM64_DEBUG_DIRTY); + trace_kvm_arm_setup_debug(vcpu, vcpu->guest_debug); + vcpu->arch.mdcr_el2 = __this_cpu_read(mdcr_el2) & MDCR_EL2_HPMN_MASK; vcpu->arch.mdcr_el2 |= (MDCR_EL2_TPM | MDCR_EL2_TPMCR | @@ -140,6 +151,8 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu_sys_reg(vcpu, MDSCR_EL1) &= ~DBG_MDSCR_SS; } + trace_kvm_arm_set_dreg32("SPSR_EL2", *vcpu_cpsr(vcpu)); + /* * HW Breakpoints and watchpoints * @@ -156,6 +169,14 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) vcpu->arch.debug_ptr = &vcpu->arch.external_debug_state; vcpu->arch.debug_flags |= KVM_ARM64_DEBUG_DIRTY; trap_debug = true; + + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), + &vcpu->arch.debug_ptr->dbg_bcr[0], + &vcpu->arch.debug_ptr->dbg_bvr[0]); + + trace_kvm_arm_set_regset("WAPTS", get_num_wrps(), + &vcpu->arch.debug_ptr->dbg_wcr[0], + &vcpu->arch.debug_ptr->dbg_wvr[0]); } } @@ -165,10 +186,15 @@ void kvm_arm_setup_debug(struct kvm_vcpu *vcpu) /* Trap debug register access */ if (trap_debug) vcpu->arch.mdcr_el2 |= MDCR_EL2_TDA; + + trace_kvm_arm_set_dreg32("MDCR_EL2", vcpu->arch.mdcr_el2); + trace_kvm_arm_set_dreg32("MDSCR_EL1", vcpu_sys_reg(vcpu, MDSCR_EL1)); } void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) { + trace_kvm_arm_clear_debug(vcpu->guest_debug); + if (vcpu->guest_debug) { restore_guest_debug_regs(vcpu); @@ -176,8 +202,16 @@ void kvm_arm_clear_debug(struct kvm_vcpu *vcpu) * If we were using HW debug we need to restore the * debug_ptr to the guest debug state. */ - if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) + if (vcpu->guest_debug & KVM_GUESTDBG_USE_HW) { kvm_arm_reset_debug_ptr(vcpu); + trace_kvm_arm_set_regset("BKPTS", get_num_brps(), + &vcpu->arch.debug_ptr->dbg_bcr[0], + &vcpu->arch.debug_ptr->dbg_bvr[0]); + + trace_kvm_arm_set_regset("WAPTS", get_num_wrps(), + &vcpu->arch.debug_ptr->dbg_wcr[0], + &vcpu->arch.debug_ptr->dbg_wvr[0]); + } } } diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 6f1b249e05873..48868d8938707 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -32,6 +32,8 @@ #include #include +#include "trace.h" + struct kvm_stats_debugfs_item debugfs_entries[] = { { NULL } }; @@ -350,6 +352,8 @@ int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, struct kvm_guest_debug *dbg) { + trace_kvm_set_guest_debug(vcpu, dbg->control); + if (dbg->control & ~KVM_GUESTDBG_VALID_MASK) return -EINVAL; diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 158bae7c52cc4..b41607d270ac8 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -38,6 +38,8 @@ #include "sys_regs.h" +#include "trace.h" + /* * All of this file is extremly similar to the ARM coproc.c, but the * types are different. My gut feeling is that it should be pretty @@ -208,6 +210,8 @@ static bool trap_debug_regs(struct kvm_vcpu *vcpu, *vcpu_reg(vcpu, p->Rt) = vcpu_sys_reg(vcpu, r->reg); } + trace_trap_reg(__func__, r->reg, p->is_write, *vcpu_reg(vcpu, p->Rt)); + return true; } @@ -258,6 +262,8 @@ static inline bool trap_bvr(struct kvm_vcpu *vcpu, else dbg_to_reg(vcpu, p, dbg_reg); + trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); + return true; } @@ -298,6 +304,8 @@ static inline bool trap_bcr(struct kvm_vcpu *vcpu, else dbg_to_reg(vcpu, p, dbg_reg); + trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); + return true; } @@ -339,6 +347,9 @@ static inline bool trap_wvr(struct kvm_vcpu *vcpu, else dbg_to_reg(vcpu, p, dbg_reg); + trace_trap_reg(__func__, rd->reg, p->is_write, + vcpu->arch.vcpu_debug_state.dbg_wvr[rd->reg]); + return true; } @@ -379,6 +390,8 @@ static inline bool trap_wcr(struct kvm_vcpu *vcpu, else dbg_to_reg(vcpu, p, dbg_reg); + trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); + return true; } @@ -742,6 +755,8 @@ static inline bool trap_xvr(struct kvm_vcpu *vcpu, *vcpu_reg(vcpu, p->Rt) = *dbg_reg >> 32; } + trace_trap_reg(__func__, rd->reg, p->is_write, *dbg_reg); + return true; } @@ -1223,6 +1238,8 @@ int kvm_handle_sys_reg(struct kvm_vcpu *vcpu, struct kvm_run *run) struct sys_reg_params params; unsigned long esr = kvm_vcpu_get_hsr(vcpu); + trace_kvm_handle_sys_reg(esr); + params.is_aarch32 = false; params.is_32bit = false; params.Op0 = (esr >> 20) & 3; diff --git a/arch/arm64/kvm/trace.h b/arch/arm64/kvm/trace.h index 157416e963f2f..7fb0008c4fa3d 100644 --- a/arch/arm64/kvm/trace.h +++ b/arch/arm64/kvm/trace.h @@ -44,6 +44,129 @@ TRACE_EVENT(kvm_hvc_arm64, __entry->vcpu_pc, __entry->r0, __entry->imm) ); +TRACE_EVENT(kvm_arm_setup_debug, + TP_PROTO(struct kvm_vcpu *vcpu, __u32 guest_debug), + TP_ARGS(vcpu, guest_debug), + + TP_STRUCT__entry( + __field(struct kvm_vcpu *, vcpu) + __field(__u32, guest_debug) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->guest_debug = guest_debug; + ), + + TP_printk("vcpu: %p, flags: 0x%08x", __entry->vcpu, __entry->guest_debug) +); + +TRACE_EVENT(kvm_arm_clear_debug, + TP_PROTO(__u32 guest_debug), + TP_ARGS(guest_debug), + + TP_STRUCT__entry( + __field(__u32, guest_debug) + ), + + TP_fast_assign( + __entry->guest_debug = guest_debug; + ), + + TP_printk("flags: 0x%08x", __entry->guest_debug) +); + +TRACE_EVENT(kvm_arm_set_dreg32, + TP_PROTO(const char *name, __u32 value), + TP_ARGS(name, value), + + TP_STRUCT__entry( + __field(const char *, name) + __field(__u32, value) + ), + + TP_fast_assign( + __entry->name = name; + __entry->value = value; + ), + + TP_printk("%s: 0x%08x", __entry->name, __entry->value) +); + +TRACE_EVENT(kvm_arm_set_regset, + TP_PROTO(const char *type, int len, __u64 *control, __u64 *value), + TP_ARGS(type, len, control, value), + TP_STRUCT__entry( + __field(const char *, name) + __field(int, len) + __array(u64, ctrls, 16) + __array(u64, values, 16) + ), + TP_fast_assign( + __entry->name = type; + __entry->len = len; + memcpy(__entry->ctrls, control, len << 3); + memcpy(__entry->values, value, len << 3); + ), + TP_printk("%d %s CTRL:%s VALUE:%s", __entry->len, __entry->name, + __print_array(__entry->ctrls, __entry->len, sizeof(__u64)), + __print_array(__entry->values, __entry->len, sizeof(__u64))) +); + +TRACE_EVENT(trap_reg, + TP_PROTO(const char *fn, int reg, bool is_write, u64 write_value), + TP_ARGS(fn, reg, is_write, write_value), + + TP_STRUCT__entry( + __field(const char *, fn) + __field(int, reg) + __field(bool, is_write) + __field(u64, write_value) + ), + + TP_fast_assign( + __entry->fn = fn; + __entry->reg = reg; + __entry->is_write = is_write; + __entry->write_value = write_value; + ), + + TP_printk("%s %s reg %d (0x%08llx)", __entry->fn, __entry->is_write?"write to":"read from", __entry->reg, __entry->write_value) +); + +TRACE_EVENT(kvm_handle_sys_reg, + TP_PROTO(unsigned long hsr), + TP_ARGS(hsr), + + TP_STRUCT__entry( + __field(unsigned long, hsr) + ), + + TP_fast_assign( + __entry->hsr = hsr; + ), + + TP_printk("HSR 0x%08lx", __entry->hsr) +); + +TRACE_EVENT(kvm_set_guest_debug, + TP_PROTO(struct kvm_vcpu *vcpu, __u32 guest_debug), + TP_ARGS(vcpu, guest_debug), + + TP_STRUCT__entry( + __field(struct kvm_vcpu *, vcpu) + __field(__u32, guest_debug) + ), + + TP_fast_assign( + __entry->vcpu = vcpu; + __entry->guest_debug = guest_debug; + ), + + TP_printk("vcpu: %p, flags: 0x%08x", __entry->vcpu, __entry->guest_debug) +); + + #endif /* _TRACE_ARM64_KVM_H */ #undef TRACE_INCLUDE_PATH -- GitLab From 80b2089b4a0b08ff34619a8e07fc74a63b4e2d24 Mon Sep 17 00:00:00 2001 From: Taehee Yoo Date: Sat, 20 Jun 2015 03:28:15 +0900 Subject: [PATCH 1356/7006] rtlwifi: rtl8192cu: Remove rtl8723 code In the rtlwifi/rtl8192cu, rtl8723 code is dead code. So I remove it. Signed-off-by: Taehee Yoo Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/def.h | 9 --------- drivers/net/wireless/rtlwifi/rtl8192cu/hw.c | 16 +--------------- drivers/net/wireless/rtlwifi/rtl8192cu/mac.c | 12 ------------ 3 files changed, 1 insertion(+), 36 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h index c940a87175ca1..74a479ac323d5 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/def.h +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/def.h @@ -32,24 +32,15 @@ /*------------------------------------------------------------------------- * Chip specific *-------------------------------------------------------------------------*/ -#define CHIP_8723 BIT(2) /* RTL8723 With BT feature */ -#define CHIP_8723_DRV_REV BIT(3) /* RTL8723 Driver Revised */ #define NORMAL_CHIP BIT(4) #define CHIP_VENDOR_UMC BIT(5) #define CHIP_VENDOR_UMC_B_CUT BIT(6) -#define IS_8723_SERIES(version) \ - (((version) & CHIP_8723) ? true : false) - #define IS_92C_1T2R(version) \ (((version) & CHIP_92C) && ((version) & CHIP_92C_1T2R)) #define IS_VENDOR_UMC(version) \ (((version) & CHIP_VENDOR_UMC) ? true : false) -#define IS_VENDOR_8723_A_CUT(version) \ - (((version) & CHIP_VENDOR_UMC) ? (((version) & (BIT(6))) ? \ - false : true) : false) - #define CHIP_BONDING_92C_1T2R 0x1 #define CHIP_BONDING_IDENTIFIER(_value) (((_value) >> 22) & 0x3) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c index 767358a553fb0..7cf36619f2500 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c @@ -2280,7 +2280,6 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) { struct rtl_priv *rtlpriv = rtl_priv(hw); struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw)); - struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate; u8 u1tmp = 0; bool actuallyset = false; @@ -2357,20 +2356,7 @@ bool rtl92cu_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 * valid) if (ppsc->pwrdown_mode && e_rfpowerstate_toset == ERFOFF) { /* Enable register area 0x0-0xc. */ rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0); - if (IS_HARDWARE_TYPE_8723U(rtlhal)) { - /* - * We should configure HW PDn source for WiFi - * ONLY, and then our HW will be set in - * power-down mode if PDn source from all - * functions are configured. - */ - u1tmp = rtl_read_byte(rtlpriv, - REG_MULTI_FUNC_CTRL); - rtl_write_byte(rtlpriv, REG_MULTI_FUNC_CTRL, - (u1tmp|WL_HWPDN_EN)); - } else { - rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); - } + rtl_write_word(rtlpriv, REG_APS_FSMCO, 0x8812); } if (e_rfpowerstate_toset == ERFOFF) { if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c index 490a7cf7c702f..1c55a002d4bd9 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c @@ -69,8 +69,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) chip_version = NORMAL_CHIP; chip_version |= ((value32 & TYPE_ID) ? CHIP_92C : 0); chip_version |= ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0); - /* RTL8723 with BT function. */ - chip_version |= ((value32 & BT_FUNC) ? CHIP_8723 : 0); if (IS_VENDOR_UMC(chip_version)) chip_version |= ((value32 & CHIP_VER_RTL_MASK) ? CHIP_VENDOR_UMC_B_CUT : 0); @@ -78,10 +76,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) value32 = rtl_read_dword(rtlpriv, REG_HPON_FSM); chip_version |= ((CHIP_BONDING_IDENTIFIER(value32) == CHIP_BONDING_92C_1T2R) ? CHIP_92C_1T2R : 0); - } else if (IS_8723_SERIES(chip_version)) { - value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS); - chip_version |= ((value32 & RF_RL_ID) ? - CHIP_8723_DRV_REV : 0); } } rtlhal->version = (enum version_8192c)chip_version; @@ -114,12 +108,6 @@ void rtl92c_read_chip_version(struct ieee80211_hw *hw) case VERSION_NORMAL_UMC_CHIP_88C_B_CUT: versionid = "NORMAL_UMC_CHIP_88C_B_CUT"; break; - case VERSION_NORMA_UMC_CHIP_8723_1T1R_A_CUT: - versionid = "NORMAL_UMC_CHIP_8723_1T1R_A_CUT"; - break; - case VERSION_NORMA_UMC_CHIP_8723_1T1R_B_CUT: - versionid = "NORMAL_UMC_CHIP_8723_1T1R_B_CUT"; - break; case VERSION_TEST_CHIP_92C: versionid = "TEST_CHIP_92C"; break; -- GitLab From 4e6ee91bb728a268b37c74e2dd083481bf5ebb98 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:07 +0530 Subject: [PATCH 1357/7006] mwifiex: add tx data pause support This patch adds support to enable TX data pause feature for mwifiex. Whenever FW TX buffers reach threshold, FW would send TX pause event to driver. Driver in turn would block data traffic to that particular receiver address. Signed-off-by: Avinash Patil Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 9 ++++ drivers/net/wireless/mwifiex/main.h | 3 ++ drivers/net/wireless/mwifiex/sta_event.c | 66 ++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 38 ++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 2 + 5 files changed, 118 insertions(+) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index cd09051710e6c..8ab0d81e6437c 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -169,6 +169,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_UAP_PS_AO_TIMER (PROPRIETARY_TLV_BASE_ID + 123) #define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) #define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) +#define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) @@ -509,6 +510,7 @@ enum P2P_MODES { #define EVENT_TDLS_GENERIC_EVENT 0x00000052 #define EVENT_RADAR_DETECTED 0x00000053 #define EVENT_CHANNEL_REPORT_RDY 0x00000054 +#define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f #define EVENT_TX_STATUS_REPORT 0x00000074 @@ -1131,6 +1133,13 @@ struct host_cmd_ds_tx_rate_query { u8 ht_info; } __packed; +struct mwifiex_tx_pause_tlv { + struct mwifiex_ie_types_header header; + u8 peermac[ETH_ALEN]; + u8 tx_pause; + u8 pkt_cnt; +} __packed; + enum Host_Sleep_Action { HS_CONFIGURE = 0x0001, HS_ACTIVATE = 0x0002, diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index ae98b5b83b1f0..2106a5c246920 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -281,6 +281,7 @@ struct mwifiex_ra_list_tbl { u8 amsdu_in_ampdu; u16 total_pkt_count; bool tdls_link; + bool tx_paused; }; struct mwifiex_tid_tbl { @@ -294,6 +295,7 @@ struct mwifiex_tid_tbl { struct mwifiex_wmm_desc { struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID]; u32 packets_out[MAX_NUM_TID]; + u32 pkts_paused[MAX_NUM_TID]; /* spin lock to protect ra_list */ spinlock_t ra_list_spinlock; struct mwifiex_wmm_ac_status ac_status[IEEE80211_NUM_ACS]; @@ -768,6 +770,7 @@ struct mwifiex_sta_node { u8 tdls_status; struct mwifiex_tdls_capab tdls_cap; struct mwifiex_station_stats stats; + u8 tx_pause; }; struct mwifiex_auto_tdls_peer { diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 848de2621958c..0a80814ddbb0e 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -182,6 +182,67 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } +static void +mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 tlv_type, tlv_len; + int tlv_buf_left, status; + + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + return; + + tlv_buf_left = event_skb->len - sizeof(u32); + tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { + tlv_type = le16_to_cpu(tlv->type); + tlv_len = le16_to_cpu(tlv->len); + if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > + tlv_buf_left) { + mwifiex_dbg(priv->adapter, ERROR, + "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", + tlv_len, tlv_buf_left); + break; + } + if (tlv_type == TLV_TYPE_TX_PAUSE) { + tp_tlv = (void *)tlv; + mwifiex_dbg(priv->adapter, ERROR, + "TxPause: %pM pause=%d, pkts=%d\n", + tp_tlv->peermac, tp_tlv->tx_pause, + tp_tlv->pkt_cnt); + status = mwifiex_get_tdls_link_status + (priv, tp_tlv->peermac); + if (status == TDLS_SETUP_COMPLETE) { + spin_lock_irqsave(&priv->sta_list_spinlock, + flags); + sta_ptr = mwifiex_get_sta_entry + (priv, tp_tlv->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, + flags); + if (sta_ptr && sta_ptr->tx_pause != + tp_tlv->tx_pause) { + sta_ptr->tx_pause = tp_tlv->tx_pause; + mwifiex_update_ralist_tx_pause + (priv, tp_tlv->peermac, + tp_tlv->tx_pause); + } + } + } + + tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + + tlv_len; + tlv = (void *)((u8 *)tlv + tlv_len + + sizeof(struct mwifiex_ie_types_header)); + } +} + /* * This function handles coex events generated by firmware */ @@ -573,6 +634,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) ret = mwifiex_parse_tdls_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index a8ea21c3340c7..bc920a5a947cf 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -160,6 +160,7 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->tdls_link = false; ra_list->ba_status = BA_SETUP_NONE; ra_list->amsdu_in_ampdu = false; + ra_list->tx_paused = false; if (!mwifiex_queuing_ra_based(priv)) { if (mwifiex_get_tdls_link_status(priv, ra) == TDLS_SETUP_COMPLETE) { @@ -603,6 +604,43 @@ mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, return NULL; } +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, + u8 tx_pause) +{ + struct mwifiex_ra_list_tbl *ra_list; + u32 pkt_cnt = 0, tx_pkts_queued; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; ++i) { + ra_list = mwifiex_wmm_get_ralist_node(priv, i, mac); + if (ra_list && ra_list->tx_paused != tx_pause) { + pkt_cnt += ra_list->total_pkt_count; + ra_list->tx_paused = tx_pause; + if (tx_pause) + priv->wmm.pkts_paused[i] += + ra_list->total_pkt_count; + else + priv->wmm.pkts_paused[i] -= + ra_list->total_pkt_count; + } + } + + if (pkt_cnt) { + tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); + if (tx_pause) + tx_pkts_queued -= pkt_cnt; + else + tx_pkts_queued += pkt_cnt; + + atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); + } + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + /* * This function retrieves an RA list node for a given TID and * RA address pair. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 48ece0b355919..90edb8fc337d5 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -126,6 +126,8 @@ struct mwifiex_ra_list_tbl * mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); +void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, + u8 tx_pause); struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); -- GitLab From b5b0f272d618a470c34619b25f15ca4aa9d3b395 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:08 +0530 Subject: [PATCH 1358/7006] mwifiex: block data traffic to tx paused receive address Data traffic to tx paused receive address should be blocked. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index bc920a5a947cf..8a4dd248ff01f 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -1025,7 +1025,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, list_for_each_entry(ptr, &tid_ptr->ra_list, list) { - if (!skb_queue_empty(&ptr->skb_head)) + if (!ptr->tx_paused && + !skb_queue_empty(&ptr->skb_head)) /* holds both locks */ goto found; } -- GitLab From 9186a1f37d190f433c64558a4efeac7ed776b571 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:09 +0530 Subject: [PATCH 1359/7006] mwifiex: do not increase tx_pkts_queued if receive address tx paused If tx_pkts_queued is increased for tx paused receive address, tx process will be triggered for this packet. But since RA list was tx paused, there will be an infinite loop in mwifiex_wmm_process_tx waiting for the event(tx pause, tdls cs) to cancel tx pause. This will be an dead loop, since main_process was locked at this time, there will be no opportunity to process event. So do not increase tx_pkts_queued if receive address tx paused, this will be restored RA list is unpaused. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/wmm.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8a4dd248ff01f..8e343b3f60e90 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -803,7 +803,10 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, atomic_set(&priv->wmm.highest_queued_prio, priv->tos_to_tid_inv[tid_down]); - atomic_inc(&priv->wmm.tx_pkts_queued); + if (ra_list->tx_paused) + priv->wmm.pkts_paused[tid_down]++; + else + atomic_inc(&priv->wmm.tx_pkts_queued); spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } -- GitLab From ba101ad50a5024978f3f5007b4a6c20b304cdcbe Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:10 +0530 Subject: [PATCH 1360/7006] mwifiex: add tdls channel switch status This patch add new tdls status used for tdls channel switch. Driver in turn would block cmd path and data path if tdls channel switching. Data path to non tdls peer should be blocked if tdls channel switch to off-channel. Signed-off-by: Xinming Hu Signed-off-by: Avinash Patil Signed-off-by: Cathy Luo Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/decl.h | 3 ++ drivers/net/wireless/mwifiex/main.c | 14 ++++++- drivers/net/wireless/mwifiex/main.h | 3 ++ drivers/net/wireless/mwifiex/util.c | 59 +++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index 51e344789ba21..098e1f14dc9a4 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -141,6 +141,9 @@ enum mwifiex_tdls_status { TDLS_SETUP_COMPLETE, TDLS_SETUP_FAILURE, TDLS_LINK_TEARDOWN, + TDLS_CHAN_SWITCHING, + TDLS_IN_BASE_CHAN, + TDLS_IN_OFF_CHAN, }; enum mwifiex_tdls_error_code { diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 3ba4e0e04223b..2a2e5dbab8ddd 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -299,9 +299,15 @@ process_start: if ((!adapter->scan_chan_gap_enabled && adapter->scan_processing) || adapter->data_sent || + mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA)) || (mwifiex_wmm_lists_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || + !mwifiex_is_send_cmd_allowed + (mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_STA)) || (!is_command_pending(adapter))) break; } @@ -342,7 +348,9 @@ process_start: continue; } - if (!adapter->cmd_sent && !adapter->curr_cmd) { + if (!adapter->cmd_sent && !adapter->curr_cmd && + mwifiex_is_send_cmd_allowed + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { if (mwifiex_exec_next_cmd(adapter) == -1) { ret = -1; break; @@ -365,7 +373,9 @@ process_start: if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && - !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter)) { + !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && + !mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { mwifiex_wmm_process_tx(adapter); if (adapter->hs_activated) { adapter->is_hs_configured = false; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 2106a5c246920..d27e6aa63446d 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1461,6 +1461,9 @@ struct mwifiex_sta_node * mwifiex_add_sta_entry(struct mwifiex_private *priv, const u8 *mac); struct mwifiex_sta_node * mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac); +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv); +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv); +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv); int mwifiex_send_tdls_data_frame(struct mwifiex_private *priv, const u8 *peer, u8 action_code, u8 dialog_token, u16 status_code, const u8 *extra_ies, diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c index 790e61953abff..2504e422364a5 100644 --- a/drivers/net/wireless/mwifiex/util.c +++ b/drivers/net/wireless/mwifiex/util.c @@ -531,6 +531,65 @@ mwifiex_get_sta_entry(struct mwifiex_private *priv, const u8 *mac) return NULL; } +static struct mwifiex_sta_node * +mwifiex_get_tdls_sta_entry(struct mwifiex_private *priv, u8 status) +{ + struct mwifiex_sta_node *node; + + list_for_each_entry(node, &priv->sta_list, list) { + if (node->tdls_status == status) + return node; + } + + return NULL; +} + +/* If tdls channel switching is on-going, tx data traffic should be + * blocked until the switching stage completed. + */ +u8 mwifiex_is_tdls_chan_switching(struct mwifiex_private *priv) +{ + struct mwifiex_sta_node *sta_ptr; + + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return false; + + sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_CHAN_SWITCHING); + if (sta_ptr) + return true; + + return false; +} + +u8 mwifiex_is_tdls_off_chan(struct mwifiex_private *priv) +{ + struct mwifiex_sta_node *sta_ptr; + + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return false; + + sta_ptr = mwifiex_get_tdls_sta_entry(priv, TDLS_IN_OFF_CHAN); + if (sta_ptr) + return true; + + return false; +} + +/* If tdls channel switching is on-going or tdls operate on off-channel, + * cmd path should be blocked until tdls switched to base-channel. + */ +u8 mwifiex_is_send_cmd_allowed(struct mwifiex_private *priv) +{ + if (!priv || !ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return true; + + if (mwifiex_is_tdls_chan_switching(priv) || + mwifiex_is_tdls_off_chan(priv)) + return false; + + return true; +} + /* This function will add a sta_node entry to associated station list * table with the given mac address. * If entry exist already, existing entry is returned. -- GitLab From f7669877e7ab1c5c7fddf268d57f016d97e48198 Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:11 +0530 Subject: [PATCH 1361/7006] mwifiex: process tdls channel switch event This patch add support for tdls channel switch event process. We block TX queues for particular RA list depending upon channel switch state. If channel switch state is moving to base channel, we unblock RA lists for AP. If channel switch state is moving to off channel, we unblock TDLS peer RA lists. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 17 +++++++- drivers/net/wireless/mwifiex/sta_event.c | 54 ++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.c | 45 ++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 2 + 4 files changed, 117 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 8ab0d81e6437c..0785e645341ff 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -547,7 +547,14 @@ enum P2P_MODES { #define ACT_TDLS_DELETE 0x00 #define ACT_TDLS_CREATE 0x01 #define ACT_TDLS_CONFIG 0x02 -#define TDLS_EVENT_LINK_TEAR_DOWN 3 + +#define TDLS_EVENT_LINK_TEAR_DOWN 3 +#define TDLS_EVENT_CHAN_SWITCH_RESULT 7 +#define TDLS_EVENT_START_CHAN_SWITCH 8 +#define TDLS_EVENT_CHAN_SWITCH_STOPPED 9 + +#define TDLS_BASE_CHANNEL 0 +#define TDLS_OFF_CHANNEL 1 #define MWIFIEX_FW_V15 15 @@ -1936,10 +1943,18 @@ struct host_cmd_ds_802_11_subsc_evt { __le16 events; } __packed; +struct chan_switch_result { + u8 cur_chan; + u8 status; + u8 reason; +} __packed; + struct mwifiex_tdls_generic_event { __le16 type; u8 peer_mac[ETH_ALEN]; union { + struct chan_switch_result switch_result; + u8 cs_stop_reason; __le16 reason_code; __le16 reserved; } u; diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0a80814ddbb0e..0529b9a602d8e 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -153,6 +153,7 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, struct mwifiex_sta_node *sta_ptr; struct mwifiex_tdls_generic_event *tdls_evt = (void *)event_skb->data + sizeof(adapter->event_cause); + u8 *mac = tdls_evt->peer_mac; /* reserved 2 bytes are not mandatory in tdls event */ if (event_skb->len < (sizeof(struct mwifiex_tdls_generic_event) - @@ -175,6 +176,59 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, le16_to_cpu(tdls_evt->u.reason_code), GFP_KERNEL); break; + case TDLS_EVENT_CHAN_SWITCH_RESULT: + mwifiex_dbg(adapter, EVENT, "tdls channel switch result :\n"); + mwifiex_dbg(adapter, EVENT, + "status=0x%x, reason=0x%x cur_chan=%d\n", + tdls_evt->u.switch_result.status, + tdls_evt->u.switch_result.reason, + tdls_evt->u.switch_result.cur_chan); + + /* tdls channel switch failed */ + if (tdls_evt->u.switch_result.status != 0) { + switch (tdls_evt->u.switch_result.cur_chan) { + case TDLS_BASE_CHANNEL: + sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; + break; + case TDLS_OFF_CHANNEL: + sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; + break; + default: + break; + } + return ret; + } + + /* tdls channel switch success */ + switch (tdls_evt->u.switch_result.cur_chan) { + case TDLS_BASE_CHANNEL: + if (sta_ptr->tdls_status == TDLS_IN_BASE_CHAN) + break; + mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, + false); + sta_ptr->tdls_status = TDLS_IN_BASE_CHAN; + break; + case TDLS_OFF_CHANNEL: + if (sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) + break; + mwifiex_update_ralist_tx_pause_in_tdls_cs(priv, mac, + true); + sta_ptr->tdls_status = TDLS_IN_OFF_CHAN; + break; + default: + break; + } + + break; + case TDLS_EVENT_START_CHAN_SWITCH: + mwifiex_dbg(adapter, EVENT, "tdls start channel switch...\n"); + sta_ptr->tdls_status = TDLS_CHAN_SWITCHING; + break; + case TDLS_EVENT_CHAN_SWITCH_STOPPED: + mwifiex_dbg(adapter, EVENT, + "tdls chan switch stopped, reason=%d\n", + tdls_evt->u.cs_stop_reason); + break; default: break; } diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 8e343b3f60e90..21712cdcd95ad 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -641,6 +641,51 @@ void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); } +/* This function update non-tdls peer ralist tx_pause while + * tdls channel swithing + */ +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, + u8 *mac, u8 tx_pause) +{ + struct mwifiex_ra_list_tbl *ra_list; + u32 pkt_cnt = 0, tx_pkts_queued; + unsigned long flags; + int i; + + spin_lock_irqsave(&priv->wmm.ra_list_spinlock, flags); + + for (i = 0; i < MAX_NUM_TID; ++i) { + list_for_each_entry(ra_list, &priv->wmm.tid_tbl_ptr[i].ra_list, + list) { + if (!memcmp(ra_list->ra, mac, ETH_ALEN)) + continue; + + if (ra_list && ra_list->tx_paused != tx_pause) { + pkt_cnt += ra_list->total_pkt_count; + ra_list->tx_paused = tx_pause; + if (tx_pause) + priv->wmm.pkts_paused[i] += + ra_list->total_pkt_count; + else + priv->wmm.pkts_paused[i] -= + ra_list->total_pkt_count; + } + } + } + + if (pkt_cnt) { + tx_pkts_queued = atomic_read(&priv->wmm.tx_pkts_queued); + if (tx_pause) + tx_pkts_queued -= pkt_cnt; + else + tx_pkts_queued += pkt_cnt; + + atomic_set(&priv->wmm.tx_pkts_queued, tx_pkts_queued); + atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); + } + spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags); +} + /* * This function retrieves an RA list node for a given TID and * RA address pair. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index 90edb8fc337d5..c12dd0e9f0087 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -128,6 +128,8 @@ mwifiex_wmm_get_queue_raptr(struct mwifiex_private *priv, u8 tid, u8 mwifiex_wmm_downgrade_tid(struct mwifiex_private *priv, u32 tid); void mwifiex_update_ralist_tx_pause(struct mwifiex_private *priv, u8 *mac, u8 tx_pause); +void mwifiex_update_ralist_tx_pause_in_tdls_cs(struct mwifiex_private *priv, + u8 *mac, u8 tx_pause); struct mwifiex_ra_list_tbl *mwifiex_wmm_get_ralist_node(struct mwifiex_private *priv, u8 tid, const u8 *ra_addr); -- GitLab From 449b8bbf45e636a684c287f3008d13939aeac58b Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:12 +0530 Subject: [PATCH 1362/7006] mwifiex: add tdls config command This patch add support for a new tdls configuration command which is used for configuration of tdls channel switch parameters. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 45 +++++++++++++++ drivers/net/wireless/mwifiex/main.h | 7 +++ drivers/net/wireless/mwifiex/sta_cmd.c | 48 ++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 + drivers/net/wireless/mwifiex/tdls.c | 64 ++++++++++++++++++++++ 5 files changed, 166 insertions(+) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 0785e645341ff..427e363575196 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -360,6 +360,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_MGMT_FRAME_REG 0x010c #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 +#define HostCmd_CMD_TDLS_CONFIG 0x0100 #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 @@ -556,6 +557,19 @@ enum P2P_MODES { #define TDLS_BASE_CHANNEL 0 #define TDLS_OFF_CHANNEL 1 +#define ACT_TDLS_CS_ENABLE_CONFIG 0x00 +#define ACT_TDLS_CS_INIT 0x06 +#define ACT_TDLS_CS_STOP 0x07 +#define ACT_TDLS_CS_PARAMS 0x08 + +#define MWIFIEX_DEF_CS_UNIT_TIME 2 +#define MWIFIEX_DEF_CS_THR_OTHERLINK 10 +#define MWIFIEX_DEF_THR_DIRECTLINK 0 +#define MWIFIEX_DEF_CS_TIME 10 +#define MWIFIEX_DEF_CS_TIMEOUT 16 +#define MWIFIEX_DEF_CS_REG_CLASS 12 +#define MWIFIEX_DEF_CS_PERIODICITY 1 + #define MWIFIEX_FW_V15 15 #define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1) @@ -1265,6 +1279,36 @@ struct host_cmd_ds_tdls_oper { u8 peer_mac[ETH_ALEN]; } __packed; +struct mwifiex_tdls_config { + __le16 enable; +}; + +struct mwifiex_tdls_config_cs_params { + u8 unit_time; + u8 thr_otherlink; + u8 thr_directlink; +}; + +struct mwifiex_tdls_init_cs_params { + u8 peer_mac[ETH_ALEN]; + u8 primary_chan; + u8 second_chan_offset; + u8 band; + __le16 switch_time; + __le16 switch_timeout; + u8 reg_class; + u8 periodicity; +} __packed; + +struct mwifiex_tdls_stop_cs_params { + u8 peer_mac[ETH_ALEN]; +}; + +struct host_cmd_ds_tdls_config { + __le16 tdls_action; + u8 tdls_data[1]; +} __packed; + struct mwifiex_chan_desc { __le16 start_freq; u8 chan_width; @@ -2059,6 +2103,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_sta_list sta_list; struct host_cmd_11ac_vht_cfg vht_cfg; struct host_cmd_ds_coalesce_cfg coalesce_cfg; + struct host_cmd_ds_tdls_config tdls_config; struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d27e6aa63446d..da2275221c037 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1494,6 +1494,13 @@ void mwifiex_check_auto_tdls(unsigned long context); void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac); void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv); void mwifiex_clean_auto_tdls(struct mwifiex_private *priv); +int mwifiex_config_tdls_enable(struct mwifiex_private *priv); +int mwifiex_config_tdls_disable(struct mwifiex_private *priv); +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv); +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac); +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, + u8 primary_chan, u8 second_chan_offset, u8 band); + int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, void *data_buf); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 037adcd1f484a..82e6c6ec0b730 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1575,6 +1575,50 @@ mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_tdls_config(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_tdls_config *tdls_config = &cmd->params.tdls_config; + struct mwifiex_tdls_init_cs_params *config; + struct mwifiex_tdls_config *init_config; + u16 len; + + cmd->command = cpu_to_le16(HostCmd_CMD_TDLS_CONFIG); + cmd->size = cpu_to_le16(S_DS_GEN); + tdls_config->tdls_action = cpu_to_le16(cmd_action); + le16_add_cpu(&cmd->size, sizeof(tdls_config->tdls_action)); + + switch (cmd_action) { + case ACT_TDLS_CS_ENABLE_CONFIG: + init_config = data_buf; + len = sizeof(*init_config); + memcpy(tdls_config->tdls_data, init_config, len); + break; + case ACT_TDLS_CS_INIT: + config = data_buf; + len = sizeof(*config); + memcpy(tdls_config->tdls_data, config, len); + break; + case ACT_TDLS_CS_STOP: + len = sizeof(struct mwifiex_tdls_stop_cs_params); + memcpy(tdls_config->tdls_data, data_buf, len); + break; + case ACT_TDLS_CS_PARAMS: + len = sizeof(struct mwifiex_tdls_config_cs_params); + memcpy(tdls_config->tdls_data, data_buf, len); + break; + default: + mwifiex_dbg(priv->adapter, ERROR, + "Unknown TDLS configuration\n"); + return -ENOTSUPP; + } + + le16_add_cpu(&cmd->size, len); + return 0; +} + static int mwifiex_cmd_tdls_oper(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -1958,6 +2002,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, case HostCmd_CMD_TDLS_OPER: ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf); break; + case HostCmd_CMD_TDLS_CONFIG: + ret = mwifiex_cmd_tdls_config(priv, cmd_ptr, cmd_action, + data_buf); + break; case HostCmd_CMD_CHAN_REPORT_REQUEST: ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr, data_buf); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index b645884b3b97a..6a85c774587a2 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1197,6 +1197,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG: ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp); break; + case HostCmd_CMD_TDLS_CONFIG: + break; default: mwifiex_dbg(adapter, ERROR, "CMD_RESP: unknown cmd response %#x\n", diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 2faa1bc42abee..03eabd705abeb 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -1416,3 +1416,67 @@ void mwifiex_clean_auto_tdls(struct mwifiex_private *priv) mwifiex_flush_auto_tdls_list(priv); } } + +static int mwifiex_config_tdls(struct mwifiex_private *priv, u8 enable) +{ + struct mwifiex_tdls_config config; + + config.enable = cpu_to_le16(enable); + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_ENABLE_CONFIG, 0, &config, true); +} + +int mwifiex_config_tdls_enable(struct mwifiex_private *priv) +{ + return mwifiex_config_tdls(priv, true); +} + +int mwifiex_config_tdls_disable(struct mwifiex_private *priv) +{ + return mwifiex_config_tdls(priv, false); +} + +int mwifiex_config_tdls_cs_params(struct mwifiex_private *priv) +{ + struct mwifiex_tdls_config_cs_params config_tdls_cs_params; + + config_tdls_cs_params.unit_time = MWIFIEX_DEF_CS_UNIT_TIME; + config_tdls_cs_params.thr_otherlink = MWIFIEX_DEF_CS_THR_OTHERLINK; + config_tdls_cs_params.thr_directlink = MWIFIEX_DEF_THR_DIRECTLINK; + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_PARAMS, 0, + &config_tdls_cs_params, true); +} + +int mwifiex_stop_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac) +{ + struct mwifiex_tdls_stop_cs_params stop_tdls_cs_params; + + ether_addr_copy(stop_tdls_cs_params.peer_mac, peer_mac); + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_STOP, 0, + &stop_tdls_cs_params, true); +} + +int mwifiex_start_tdls_cs(struct mwifiex_private *priv, const u8 *peer_mac, + u8 primary_chan, u8 second_chan_offset, u8 band) +{ + struct mwifiex_tdls_init_cs_params start_tdls_cs_params; + + ether_addr_copy(start_tdls_cs_params.peer_mac, peer_mac); + start_tdls_cs_params.primary_chan = primary_chan; + start_tdls_cs_params.second_chan_offset = second_chan_offset; + start_tdls_cs_params.band = band; + + start_tdls_cs_params.switch_time = cpu_to_le16(MWIFIEX_DEF_CS_TIME); + start_tdls_cs_params.switch_timeout = + cpu_to_le16(MWIFIEX_DEF_CS_TIMEOUT); + start_tdls_cs_params.reg_class = MWIFIEX_DEF_CS_REG_CLASS; + start_tdls_cs_params.periodicity = MWIFIEX_DEF_CS_PERIODICITY; + + return mwifiex_send_cmd(priv, HostCmd_CMD_TDLS_CONFIG, + ACT_TDLS_CS_INIT, 0, + &start_tdls_cs_params, true); +} -- GitLab From 20834343a8e6a9a1e90d47810f6fe991f1e3362a Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:13 +0530 Subject: [PATCH 1363/7006] mwifiex: enable tdls channel switch ext_cap This patch enable tdls channel switch ext capability in tdls action frame, and also configure basic tdls channel switch parameters while tdls setup completed and tdls link is enabled.. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/tdls.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index 03eabd705abeb..f862ca63506ce 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -355,6 +355,7 @@ static void mwifiex_tdls_add_ext_capab(struct mwifiex_private *priv, extcap->ieee_hdr.len = 8; memset(extcap->ext_capab, 0, 8); extcap->ext_capab[4] |= WLAN_EXT_CAPA5_TDLS_ENABLED; + extcap->ext_capab[3] |= WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH; if (priv->adapter->is_hw_11ac_capable) extcap->ext_capab[7] |= WLAN_EXT_CAPA8_TDLS_WIDE_BW_ENABLED; @@ -1071,6 +1072,11 @@ mwifiex_tdls_process_enable_link(struct mwifiex_private *priv, const u8 *peer) for (i = 0; i < MAX_NUM_TID; i++) sta_ptr->ampdu_sta[i] = BA_STREAM_NOT_ALLOWED; } + if (sta_ptr->tdls_cap.extcap.ext_capab[3] & + WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH) { + mwifiex_config_tdls_enable(priv); + mwifiex_config_tdls_cs_params(priv); + } memset(sta_ptr->rx_seq, 0xff, sizeof(sta_ptr->rx_seq)); mwifiex_restore_tdls_packets(priv, peer, TDLS_SETUP_COMPLETE); -- GitLab From 55a2c0770634a08009229aaf23cda885d2e4359e Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:14 +0530 Subject: [PATCH 1364/7006] mwifiex: enhance tdls link setup condition TDLS link status - channel switching, off channel or base channel itself indicates that TDLS link is setup. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 15 +++++++++++++++ drivers/net/wireless/mwifiex/sta_event.c | 2 +- drivers/net/wireless/mwifiex/tdls.c | 8 ++++---- drivers/net/wireless/mwifiex/wmm.c | 7 +++++-- 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index da2275221c037..0e6ebc9001c3b 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1333,6 +1333,21 @@ static inline u8 mwifiex_is_any_intf_active(struct mwifiex_private *priv) return 0; } +static inline u8 mwifiex_is_tdls_link_setup(u8 status) +{ + switch (status) { + case TDLS_SETUP_COMPLETE: + case TDLS_CHAN_SWITCHING: + case TDLS_IN_BASE_CHAN: + case TDLS_IN_OFF_CHAN: + return true; + default: + break; + } + + return false; +} + int mwifiex_init_shutdown_fw(struct mwifiex_private *priv, u32 func_init_shutdown); int mwifiex_add_card(void *, struct semaphore *, struct mwifiex_if_ops *, u8); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 0529b9a602d8e..f1045d41abee8 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -273,7 +273,7 @@ mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, tp_tlv->pkt_cnt); status = mwifiex_get_tdls_link_status (priv, tp_tlv->peermac); - if (status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(status)) { spin_lock_irqsave(&priv->sta_list_spinlock, flags); sta_ptr = mwifiex_get_sta_entry diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c index f862ca63506ce..aa3d3c5ed07b3 100644 --- a/drivers/net/wireless/mwifiex/tdls.c +++ b/drivers/net/wireless/mwifiex/tdls.c @@ -49,7 +49,7 @@ static void mwifiex_restore_tdls_packets(struct mwifiex_private *priv, tid = skb->priority; tid_down = mwifiex_wmm_downgrade_tid(priv, tid); - if (status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(status)) { ra_list = mwifiex_wmm_get_queue_raptr(priv, tid, mac); ra_list->tdls_link = true; tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; @@ -1147,7 +1147,7 @@ int mwifiex_get_tdls_list(struct mwifiex_private *priv, spin_lock_irqsave(&priv->sta_list_spinlock, flags); list_for_each_entry(sta_ptr, &priv->sta_list, list) { - if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup(sta_ptr->tdls_status)) { ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr); peer++; count++; @@ -1301,7 +1301,7 @@ void mwifiex_auto_tdls_update_peer_status(struct mwifiex_private *priv, if ((link_status == TDLS_NOT_SETUP) && (peer->tdls_status == TDLS_SETUP_INPROGRESS)) peer->failure_count++; - else if (link_status == TDLS_SETUP_COMPLETE) + else if (mwifiex_is_tdls_link_setup(link_status)) peer->failure_count = 0; peer->tdls_status = link_status; @@ -1373,7 +1373,7 @@ void mwifiex_check_auto_tdls(unsigned long context) if (((tdls_peer->rssi >= MWIFIEX_TDLS_RSSI_LOW) || !tdls_peer->rssi) && - tdls_peer->tdls_status == TDLS_SETUP_COMPLETE) { + mwifiex_is_tdls_link_setup(tdls_peer->tdls_status)) { tdls_peer->tdls_status = TDLS_LINK_TEARDOWN; mwifiex_dbg(priv->adapter, MSG, "teardown TDLS link,peer=%pM rssi=%d\n", diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 21712cdcd95ad..6196daad5a612 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -162,8 +162,8 @@ void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra) ra_list->amsdu_in_ampdu = false; ra_list->tx_paused = false; if (!mwifiex_queuing_ra_based(priv)) { - if (mwifiex_get_tdls_link_status(priv, ra) == - TDLS_SETUP_COMPLETE) { + if (mwifiex_is_tdls_link_setup + (mwifiex_get_tdls_link_status(priv, ra))) { ra_list->tdls_link = true; ra_list->is_11n_enabled = mwifiex_tdls_peer_11n_enabled(priv, ra); @@ -806,6 +806,9 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, !mwifiex_is_skb_mgmt_frame(skb)) { switch (tdls_status) { case TDLS_SETUP_COMPLETE: + case TDLS_CHAN_SWITCHING: + case TDLS_IN_BASE_CHAN: + case TDLS_IN_OFF_CHAN: ra_list = mwifiex_wmm_get_queue_raptr(priv, tid_down, ra); tx_info->flags |= MWIFIEX_BUF_FLAG_TDLS_PKT; -- GitLab From b04975970676d797dec434755a14285420a4189f Mon Sep 17 00:00:00 2001 From: Xinming Hu Date: Mon, 22 Jun 2015 19:06:15 +0530 Subject: [PATCH 1365/7006] mwifiex: add cfg80211 tdls channel switch handler This patch add cfg80211 tdls_chan_switch and tdls_cancel_chan_switch handler. With this handlers, mwifiex would support TDLS channel switch feature. Signed-off-by: Xinming Hu Signed-off-by: Cathy Luo Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 72 +++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index b15e4c7acbecd..ecc8278a8cfe7 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -19,6 +19,7 @@ #include "cfg80211.h" #include "main.h" +#include "11n.h" static char *reg_alpha2; module_param(reg_alpha2, charp, 0); @@ -3359,6 +3360,72 @@ mwifiex_cfg80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, return mwifiex_tdls_oper(priv, peer, action); } +static int +mwifiex_cfg80211_tdls_chan_switch(struct wiphy *wiphy, struct net_device *dev, + const u8 *addr, u8 oper_class, + struct cfg80211_chan_def *chandef) +{ + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + u16 chan; + u8 second_chan_offset, band; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, addr); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (!sta_ptr) { + wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", + __func__, addr); + return -ENOENT; + } + + if (!(sta_ptr->tdls_cap.extcap.ext_capab[3] & + WLAN_EXT_CAPA4_TDLS_CHAN_SWITCH)) { + wiphy_err(wiphy, "%pM do not support tdls cs\n", addr); + return -ENOENT; + } + + if (sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || + sta_ptr->tdls_status == TDLS_IN_OFF_CHAN) { + wiphy_err(wiphy, "channel switch is running, abort request\n"); + return -EALREADY; + } + + chan = chandef->chan->hw_value; + second_chan_offset = mwifiex_get_sec_chan_offset(chan); + band = chandef->chan->band; + mwifiex_start_tdls_cs(priv, addr, chan, second_chan_offset, band); + + return 0; +} + +static void +mwifiex_cfg80211_tdls_cancel_chan_switch(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr) +{ + struct mwifiex_sta_node *sta_ptr; + unsigned long flags; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, addr); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (!sta_ptr) { + wiphy_err(wiphy, "%s: Invalid TDLS peer %pM\n", + __func__, addr); + } else if (!(sta_ptr->tdls_status == TDLS_CHAN_SWITCHING || + sta_ptr->tdls_status == TDLS_IN_BASE_CHAN || + sta_ptr->tdls_status == TDLS_IN_OFF_CHAN)) { + wiphy_err(wiphy, "tdls chan switch not initialize by %pM\n", + addr); + } else + mwifiex_stop_tdls_cs(priv, addr); +} + static int mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev, const u8 *mac, struct station_parameters *params) @@ -3575,6 +3642,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_coalesce = mwifiex_cfg80211_set_coalesce, .tdls_mgmt = mwifiex_cfg80211_tdls_mgmt, .tdls_oper = mwifiex_cfg80211_tdls_oper, + .tdls_channel_switch = mwifiex_cfg80211_tdls_chan_switch, + .tdls_cancel_channel_switch = mwifiex_cfg80211_tdls_cancel_chan_switch, .add_station = mwifiex_cfg80211_add_station, .change_station = mwifiex_cfg80211_change_station, .get_channel = mwifiex_cfg80211_get_channel, @@ -3709,6 +3778,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) NL80211_FEATURE_INACTIVITY_TIMER | NL80211_FEATURE_NEED_OBSS_SCAN; + if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info)) + wiphy->features |= NL80211_FEATURE_TDLS_CHANNEL_SWITCH; + if (adapter->fw_api_ver == MWIFIEX_FW_V15) wiphy->features |= NL80211_FEATURE_SK_TX_STATUS; -- GitLab From 65d48e5971065ccb831a93232d60deb7caa9d7cb Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:16 +0530 Subject: [PATCH 1366/7006] mwifiex: update domain_info upon band change in start_ap It was observed that AP beacons would not reflect correct regulatory information upon starting AP in A band. This was because of missing AP config band update in set_channel of start_ap. Also we configure 11D settings info FW only for specific band. So we need to download domain info to FW even if domain remains unchanged but band is changed. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 2 +- drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/uap_cmd.c | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index ecc8278a8cfe7..1d445cbbb31b6 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -442,7 +442,7 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, * - Country codes * - Sub bands (first channel, number of channels, maximum Tx power) */ -static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) { u8 no_of_triplet = 0; struct ieee80211_country_ie_triplet *t; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 0e6ebc9001c3b..d74ef2dd21bc8 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1550,6 +1550,8 @@ void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags); void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); +int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); + #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); void mwifiex_debugfs_remove(void); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index b74930054b8c0..4d5a6e3b63617 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -808,7 +808,7 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_cfg, struct cfg80211_chan_def chandef) { - u8 config_bands = 0; + u8 config_bands = 0, old_bands = priv->adapter->config_bands; priv->bss_chandef = chandef; @@ -834,6 +834,11 @@ void mwifiex_uap_set_channel(struct mwifiex_private *priv, } priv->adapter->config_bands = config_bands; + + if (old_bands != config_bands) { + mwifiex_send_domain_info_cmd_fw(priv->adapter->wiphy); + mwifiex_dnld_txpwr_table(priv); + } } int mwifiex_config_start_uap(struct mwifiex_private *priv, -- GitLab From a1777327126e184518e17e3c571540be72c73dce Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:17 +0530 Subject: [PATCH 1367/7006] mwifiex: support for bypass tx queue This patch adds support for another TX queue in driver- bypass TX queue. This queue is used for sending data/mgmt packets while in disconnected state i.e. when port is yet not unblocked. TDLS setup packets would also be queued in this queue. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 ++ drivers/net/wireless/mwifiex/init.c | 1 + drivers/net/wireless/mwifiex/main.c | 49 ++++++++++++++++++++++- drivers/net/wireless/mwifiex/main.h | 2 + drivers/net/wireless/mwifiex/wmm.c | 53 +++++++++++++++++++++++++ drivers/net/wireless/mwifiex/wmm.h | 4 ++ 6 files changed, 111 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 1d445cbbb31b6..46f9dc2b17369 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2789,6 +2789,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); struct mwifiex_adapter *adapter = priv->adapter; + struct sk_buff *skb, *tmp; #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); @@ -2796,6 +2797,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) mwifiex_stop_net_dev_queue(priv->netdev, adapter); + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index df7fdc09d38c7..e1b62bf0f7b49 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -499,6 +499,7 @@ int mwifiex_init_lock_list(struct mwifiex_adapter *adapter) INIT_LIST_HEAD(&priv->sta_list); INIT_LIST_HEAD(&priv->auto_tdls_list); skb_queue_head_init(&priv->tdls_txq); + skb_queue_head_init(&priv->bypass_txq); spin_lock_init(&priv->tx_ba_stream_tbl_lock); spin_lock_init(&priv->rx_reorder_tbl_lock); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 2a2e5dbab8ddd..278dc94eaecbb 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -276,6 +276,7 @@ process_start: !adapter->pm_wakeup_fw_try) && (is_command_pending(adapter) || !skb_queue_empty(&adapter->tx_data_q) || + !mwifiex_bypass_txlist_empty(adapter) || !mwifiex_wmm_lists_empty(adapter))) { adapter->pm_wakeup_fw_try = true; mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3)); @@ -303,6 +304,7 @@ process_start: (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA)) || (mwifiex_wmm_lists_empty(adapter) && + mwifiex_bypass_txlist_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (adapter->cmd_sent || adapter->curr_cmd || !mwifiex_is_send_cmd_allowed @@ -371,6 +373,22 @@ process_start: } } + if ((adapter->scan_chan_gap_enabled || + !adapter->scan_processing) && + !adapter->data_sent && + !mwifiex_bypass_txlist_empty(adapter) && + !mwifiex_is_tdls_chan_switching + (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA))) { + mwifiex_process_bypass_tx(adapter); + if (adapter->hs_activated) { + adapter->is_hs_configured = false; + mwifiex_hs_activated_event + (mwifiex_get_priv + (adapter, MWIFIEX_BSS_ROLE_ANY), + false); + } + } + if ((adapter->scan_chan_gap_enabled || !adapter->scan_processing) && !adapter->data_sent && !mwifiex_wmm_lists_empty(adapter) && @@ -389,6 +407,7 @@ process_start: if (adapter->delay_null_pkt && !adapter->cmd_sent && !adapter->curr_cmd && !is_command_pending(adapter) && (mwifiex_wmm_lists_empty(adapter) && + mwifiex_bypass_txlist_empty(adapter) && skb_queue_empty(&adapter->tx_data_q))) { if (!mwifiex_send_null_packet (mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA), @@ -659,6 +678,26 @@ mwifiex_close(struct net_device *dev) return 0; } +static bool +mwifiex_bypass_tx_queue(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + struct ethhdr *eth_hdr = (struct ethhdr *)skb->data; + + if (ntohs(eth_hdr->h_proto) == ETH_P_PAE || + mwifiex_is_skb_mgmt_frame(skb) || + (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA && + ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info) && + (ntohs(eth_hdr->h_proto) == ETH_P_TDLS))) { + mwifiex_dbg(priv->adapter, DATA, + "bypass txqueue; eth type %#x, mgmt %d\n", + ntohs(eth_hdr->h_proto), + mwifiex_is_skb_mgmt_frame(skb)); + return true; + } + + return false; +} /* * Add buffer into wmm tx queue and queue work to transmit it. */ @@ -676,8 +715,14 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb) } } - atomic_inc(&priv->adapter->tx_pending); - mwifiex_wmm_add_buf_txqueue(priv, skb); + if (mwifiex_bypass_tx_queue(priv, skb)) { + atomic_inc(&priv->adapter->tx_pending); + atomic_inc(&priv->adapter->bypass_tx_pending); + mwifiex_wmm_add_buf_bypass_txqueue(priv, skb); + } else { + atomic_inc(&priv->adapter->tx_pending); + mwifiex_wmm_add_buf_txqueue(priv, skb); + } mwifiex_queue_main_work(priv->adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index d74ef2dd21bc8..c59430e906aea 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -664,6 +664,7 @@ struct mwifiex_private { struct cfg80211_beacon_data beacon_after; struct mwifiex_11h_intf_state state_11h; struct mwifiex_ds_mem_rw mem_rw; + struct sk_buff_head bypass_txq; }; @@ -834,6 +835,7 @@ struct mwifiex_adapter { wait_queue_head_t init_wait_q; void *card; struct mwifiex_if_ops if_ops; + atomic_t bypass_tx_pending; atomic_t rx_pending; atomic_t tx_pending; atomic_t cmd_pending; diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 6196daad5a612..7995f92bc2d41 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -449,6 +449,11 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) } } +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter) +{ + return atomic_read(&adapter->bypass_tx_pending) ? false : true; +} + /* * This function checks if WMM Tx queue is empty. */ @@ -581,6 +586,10 @@ mwifiex_clean_txrx(struct mwifiex_private *priv) skb_queue_walk_safe(&priv->tdls_txq, skb, tmp) mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + skb_queue_walk_safe(&priv->bypass_txq, skb, tmp) + mwifiex_write_data_complete(priv->adapter, skb, 0, -1); + atomic_set(&priv->adapter->bypass_tx_pending, 0); + idr_for_each(&priv->ack_status_frames, mwifiex_free_ack_frame, NULL); idr_destroy(&priv->ack_status_frames); } @@ -752,6 +761,18 @@ mwifiex_is_ralist_valid(struct mwifiex_private *priv, return false; } +/* + * This function adds a packet to bypass TX queue. + * This is special TX queue for packets which can be sent even when port_open + * is false. + */ +void +mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, + struct sk_buff *skb) +{ + skb_queue_tail(&priv->bypass_txq, skb); +} + /* * This function adds a packet to WMM queue. * @@ -1429,6 +1450,38 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) return 0; } +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter) +{ + struct mwifiex_tx_param tx_param; + struct sk_buff *skb; + struct mwifiex_txinfo *tx_info; + struct mwifiex_private *priv; + int i; + + if (adapter->data_sent || adapter->tx_lock_flag) + return; + + for (i = 0; i < adapter->priv_num; ++i) { + priv = adapter->priv[i]; + + if (skb_queue_empty(&priv->bypass_txq)) + continue; + + skb = skb_dequeue(&priv->bypass_txq); + tx_info = MWIFIEX_SKB_TXCB(skb); + + /* no aggregation for bypass packets */ + tx_param.next_pkt_len = 0; + + if (mwifiex_process_tx(priv, skb, &tx_param) == -EBUSY) { + skb_queue_head(&priv->bypass_txq, skb); + tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT; + } else { + atomic_dec(&adapter->bypass_tx_pending); + } + } +} + /* * This function transmits the highest priority packet awaiting in the * WMM Queues. diff --git a/drivers/net/wireless/mwifiex/wmm.h b/drivers/net/wireless/mwifiex/wmm.h index c12dd0e9f0087..38f09762bd2f9 100644 --- a/drivers/net/wireless/mwifiex/wmm.h +++ b/drivers/net/wireless/mwifiex/wmm.h @@ -99,12 +99,16 @@ mwifiex_wmm_is_ra_list_empty(struct list_head *ra_list_hhead) void mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv, struct sk_buff *skb); +void mwifiex_wmm_add_buf_bypass_txqueue(struct mwifiex_private *priv, + struct sk_buff *skb); void mwifiex_ralist_add(struct mwifiex_private *priv, const u8 *ra); void mwifiex_rotate_priolists(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra, int tid); int mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter); +int mwifiex_bypass_txlist_empty(struct mwifiex_adapter *adapter); void mwifiex_wmm_process_tx(struct mwifiex_adapter *adapter); +void mwifiex_process_bypass_tx(struct mwifiex_adapter *adapter); int mwifiex_is_ralist_valid(struct mwifiex_private *priv, struct mwifiex_ra_list_tbl *ra_list, int tid); -- GitLab From 5c8946330abfa4c0476b94070d8833cfbbca5b28 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:18 +0530 Subject: [PATCH 1368/7006] mwifiex: enable traffic only when port is open This patch adds support to enable data traffic only when port is open. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/init.c | 2 +- drivers/net/wireless/mwifiex/join.c | 2 ++ drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmdresp.c | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 4 +++- drivers/net/wireless/mwifiex/uap_event.c | 3 +++ drivers/net/wireless/mwifiex/wmm.c | 5 ++++- 7 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index e1b62bf0f7b49..8fa363add9706 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -77,7 +77,7 @@ int mwifiex_init_priv(struct mwifiex_private *priv) priv->media_connected = false; eth_broadcast_addr(priv->curr_addr); - + priv->port_open = false; priv->pkt_tx_ctrl = 0; priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; priv->data_rate = 0; /* Initially indicate the rate as auto */ diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 56b024a6aaa58..3cda1f956f0b1 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -783,6 +783,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv, if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) priv->scan_block = true; + else + priv->port_open = true; done: /* Need to indicate IOCTL complete */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index c59430e906aea..6f98d7ea93382 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -519,6 +519,7 @@ struct mwifiex_private { u8 frame_type; u8 curr_addr[ETH_ALEN]; u8 media_connected; + u8 port_open; u32 num_tx_timeout; /* track consecutive timeout */ u8 tx_timeout_cnt; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 6a85c774587a2..18f269eaed605 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -599,6 +599,7 @@ static int mwifiex_ret_802_11_key_material_v1(struct mwifiex_private *priv, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; + priv->port_open = true; } } @@ -629,6 +630,7 @@ static int mwifiex_ret_802_11_key_material_v2(struct mwifiex_private *priv, mwifiex_dbg(priv->adapter, INFO, "info: key: GTK is set\n"); priv->wpa_is_gtk_set = true; priv->scan_block = false; + priv->port_open = true; } } diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f1045d41abee8..72be16eca7584 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -54,6 +54,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code) priv->media_connected = false; priv->scan_block = false; + priv->port_open = false; if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) && ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) { @@ -474,7 +475,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PS_AWAKE: mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n"); - if (!adapter->pps_uapsd_mode && + if (!adapter->pps_uapsd_mode && priv->port_open && priv->media_connected && adapter->sleep_period.period) { adapter->pps_uapsd_mode = true; mwifiex_dbg(adapter, EVENT, @@ -553,6 +554,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_PORT_RELEASE: mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n"); + priv->port_open = true; break; case EVENT_EXT_SCAN_REPORT: diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index 7bc1f850e3b71..a412c3d4c3652 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -176,6 +176,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_IDLE: priv->media_connected = false; + priv->port_open = false; if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); mwifiex_stop_net_dev_queue(priv->netdev, adapter); @@ -185,6 +186,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) break; case EVENT_UAP_BSS_ACTIVE: priv->media_connected = true; + priv->port_open = true; if (!netif_carrier_ok(priv->netdev)) netif_carrier_on(priv->netdev); mwifiex_wake_up_net_dev_queue(priv->netdev, adapter); @@ -192,6 +194,7 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) case EVENT_UAP_BSS_START: mwifiex_dbg(adapter, EVENT, "AP EVENT: event id: %#x\n", eventcause); + priv->port_open = false; memcpy(priv->netdev->dev_addr, adapter->event_body + 2, ETH_ALEN); if (priv->hist_data) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 7995f92bc2d41..173d3663c2e04 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -465,6 +465,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter) for (i = 0; i < adapter->priv_num; ++i) { priv = adapter->priv[i]; + if (priv && !priv->port_open) + continue; if (priv && atomic_read(&priv->wmm.tx_pkts_queued)) return false; } @@ -1080,7 +1082,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv; - if (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0) + if (!priv_tmp->port_open || + (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0)) continue; /* iterate over the WMM queues of the BSS */ -- GitLab From ddd7ceb3f6dd9071fd0e2058252d1fc4645313db Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:19 +0530 Subject: [PATCH 1369/7006] mwifiex: extend tx_data pause to AP interface as well This patch adds support to extend TX Data pause for AP intefaces. Also for station role, support for pausing/unpausing all traffic when mac address parameter is BSSID is added. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/main.h | 2 + drivers/net/wireless/mwifiex/sta_event.c | 121 ++++++++++++++++------- drivers/net/wireless/mwifiex/uap_event.c | 4 + 3 files changed, 93 insertions(+), 34 deletions(-) diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6f98d7ea93382..6e82058c0eab1 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1554,6 +1554,8 @@ void mwifiex_queue_main_work(struct mwifiex_adapter *adapter); void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter); void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 72be16eca7584..a2777d16c98ff 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -237,58 +237,110 @@ static int mwifiex_parse_tdls_event(struct mwifiex_private *priv, return ret; } -static void -mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, - struct sk_buff *event_skb) +static void mwifiex_process_uap_tx_pause(struct mwifiex_private *priv, + struct mwifiex_ie_types_header *tlv) { - struct mwifiex_ie_types_header *tlv; - struct mwifiex_tx_pause_tlv *tp_tlv; + struct mwifiex_tx_pause_tlv *tp; struct mwifiex_sta_node *sta_ptr; unsigned long flags; - u16 tlv_type, tlv_len; - int tlv_buf_left, status; - if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) - return; + tp = (void *)tlv; + mwifiex_dbg(priv->adapter, EVENT, + "uap tx_pause: %pM pause=%d, pkts=%d\n", + tp->peermac, tp->tx_pause, + tp->pkt_cnt); + + if (ether_addr_equal(tp->peermac, priv->netdev->dev_addr)) { + if (tp->tx_pause) + priv->port_open = false; + else + priv->port_open = true; + } else if (is_multicast_ether_addr(tp->peermac)) { + mwifiex_update_ralist_tx_pause(priv, tp->peermac, tp->tx_pause); + } else { + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { + sta_ptr->tx_pause = tp->tx_pause; + mwifiex_update_ralist_tx_pause(priv, tp->peermac, + tp->tx_pause); + } + } +} + +static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, + struct mwifiex_ie_types_header *tlv) +{ + struct mwifiex_tx_pause_tlv *tp; + struct mwifiex_sta_node *sta_ptr; + int status; + unsigned long flags; + + tp = (void *)tlv; + mwifiex_dbg(priv->adapter, EVENT, + "sta tx_pause: %pM pause=%d, pkts=%d\n", + tp->peermac, tp->tx_pause, + tp->pkt_cnt); + + if (ether_addr_equal(tp->peermac, priv->cfg_bssid)) { + if (tp->tx_pause) + priv->port_open = false; + else + priv->port_open = true; + } else { + if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info)) + return; + + status = mwifiex_get_tdls_link_status(priv, tp->peermac); + if (mwifiex_is_tdls_link_setup(status)) { + spin_lock_irqsave(&priv->sta_list_spinlock, flags); + sta_ptr = mwifiex_get_sta_entry(priv, tp->peermac); + spin_unlock_irqrestore(&priv->sta_list_spinlock, flags); + + if (sta_ptr && sta_ptr->tx_pause != tp->tx_pause) { + sta_ptr->tx_pause = tp->tx_pause; + mwifiex_update_ralist_tx_pause(priv, + tp->peermac, + tp->tx_pause); + } + } + } +} + +void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_header *tlv; + u16 tlv_type, tlv_len; + int tlv_buf_left; - if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected)) + if (!priv->media_connected) { + mwifiex_dbg(priv->adapter, ERROR, + "tx_pause event while disconnected; bss_role=%d\n", + priv->bss_role); return; + } tlv_buf_left = event_skb->len - sizeof(u32); tlv = (void *)event_skb->data + sizeof(u32); + while (tlv_buf_left >= (int)sizeof(struct mwifiex_ie_types_header)) { tlv_type = le16_to_cpu(tlv->type); tlv_len = le16_to_cpu(tlv->len); if ((sizeof(struct mwifiex_ie_types_header) + tlv_len) > - tlv_buf_left) { + tlv_buf_left) { mwifiex_dbg(priv->adapter, ERROR, "wrong tlv: tlvLen=%d, tlvBufLeft=%d\n", tlv_len, tlv_buf_left); break; } if (tlv_type == TLV_TYPE_TX_PAUSE) { - tp_tlv = (void *)tlv; - mwifiex_dbg(priv->adapter, ERROR, - "TxPause: %pM pause=%d, pkts=%d\n", - tp_tlv->peermac, tp_tlv->tx_pause, - tp_tlv->pkt_cnt); - status = mwifiex_get_tdls_link_status - (priv, tp_tlv->peermac); - if (mwifiex_is_tdls_link_setup(status)) { - spin_lock_irqsave(&priv->sta_list_spinlock, - flags); - sta_ptr = mwifiex_get_sta_entry - (priv, tp_tlv->peermac); - spin_unlock_irqrestore(&priv->sta_list_spinlock, - flags); - if (sta_ptr && sta_ptr->tx_pause != - tp_tlv->tx_pause) { - sta_ptr->tx_pause = tp_tlv->tx_pause; - mwifiex_update_ralist_tx_pause - (priv, tp_tlv->peermac, - tp_tlv->tx_pause); - } - } + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA) + mwifiex_process_sta_tx_pause(priv, tlv); + else + mwifiex_process_uap_tx_pause(priv, tlv); } tlv_buf_left -= sizeof(struct mwifiex_ie_types_header) + @@ -296,6 +348,7 @@ mwifiex_process_sta_tx_pause_event(struct mwifiex_private *priv, tlv = (void *)((u8 *)tlv + tlv_len + sizeof(struct mwifiex_ie_types_header)); } + } /* @@ -691,8 +744,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_TX_DATA_PAUSE: - mwifiex_process_sta_tx_pause_event(priv, adapter->event_skb); mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; case EVENT_TX_STATUS_REPORT: diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a412c3d4c3652..a9d34c6191813 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -300,6 +300,10 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_bt_coex_wlan_param_update_event(priv, adapter->event_skb); break; + case EVENT_TX_DATA_PAUSE: + mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); + mwifiex_process_tx_pause_event(priv, adapter->event_skb); + break; default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- GitLab From d5b036c403f811c6d1856b8e6891a6438cf56f61 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:20 +0530 Subject: [PATCH 1370/7006] mwifiex: support to set multichannel policy to FW This patch adds support for setting multichannel policy as module parameter to FW. Value of 1 indicates Multichannel support is enabled and value of 0 disables it. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 8 ++++++ drivers/net/wireless/mwifiex/sta_cmd.c | 31 ++++++++++++++++++++++ drivers/net/wireless/mwifiex/sta_cmdresp.c | 1 + 3 files changed, 40 insertions(+) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 427e363575196..976b58587c27d 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -201,6 +201,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) #define ISSUPP_TDLS_ENABLED(FwCapInfo) (FwCapInfo & BIT(14)) +#define ISSUPP_DRCS_ENABLED(FwCapInfo) (FwCapInfo & BIT(15)) #define ISSUPP_SDIO_SPA_ENABLED(FwCapInfo) (FwCapInfo & BIT(16)) #define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ @@ -361,6 +362,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_REMAIN_ON_CHAN 0x010d #define HostCmd_CMD_11AC_CFG 0x0112 #define HostCmd_CMD_TDLS_CONFIG 0x0100 +#define HostCmd_CMD_MC_POLICY 0x0121 #define HostCmd_CMD_TDLS_OPER 0x0122 #define HostCmd_CMD_SDIO_SP_RX_AGGR_CFG 0x0223 @@ -2039,6 +2041,11 @@ struct host_cmd_ds_coalesce_cfg { struct coalesce_receive_filt_rule rule[0]; } __packed; +struct host_cmd_ds_multi_chan_policy { + __le16 action; + __le16 policy; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -2107,6 +2114,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_tdls_oper tdls_oper; struct host_cmd_ds_chan_rpt_req chan_rpt_req; struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg; + struct host_cmd_ds_multi_chan_policy mc_policy; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 82e6c6ec0b730..f250b61a9ff79 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -26,6 +26,10 @@ #include "11n.h" #include "11ac.h" +static bool drcs; +module_param(drcs, bool, 0644); +MODULE_PARM_DESC(drcs, "multi-channel operation:1, single-channel operation:0"); + static bool disable_auto_ds; module_param(disable_auto_ds, bool, 0); MODULE_PARM_DESC(disable_auto_ds, @@ -1511,6 +1515,22 @@ static int mwifiex_cmd_cfg_data(struct mwifiex_private *priv, return 0; } +static int +mwifiex_cmd_set_mc_policy(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_multi_chan_policy *mc_pol = &cmd->params.mc_policy; + const u16 *drcs_info = data_buf; + + mc_pol->action = cpu_to_le16(cmd_action); + mc_pol->policy = cpu_to_le16(*drcs_info); + cmd->command = cpu_to_le16(HostCmd_CMD_MC_POLICY); + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_multi_chan_policy) + + S_DS_GEN); + return 0; +} + static int mwifiex_cmd_coalesce_cfg(struct mwifiex_private *priv, struct host_cmd_ds_command *cmd, @@ -2014,6 +2034,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_MC_POLICY: + ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action, + data_buf); + break; default: mwifiex_dbg(priv->adapter, ERROR, "PREP_CMD: unknown cmd- %#x\n", cmd_no); @@ -2130,6 +2154,13 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) if (ret) return -1; } + + if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + ret = mwifiex_send_cmd(priv, HostCmd_CMD_MC_POLICY, + HostCmd_ACT_GEN_SET, 0, &drcs, + true); + if (ret) + return -1; } /* get tx rate */ diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 18f269eaed605..89e8dafb47387 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -1193,6 +1193,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, break; case HostCmd_CMD_TDLS_OPER: ret = mwifiex_ret_tdls_oper(priv, resp); + case HostCmd_CMD_MC_POLICY: break; case HostCmd_CMD_CHAN_REPORT_REQUEST: break; -- GitLab From de9e9932b76d5458edabd2692d8ad6504501edf1 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:21 +0530 Subject: [PATCH 1371/7006] mwifiex: advertise multichannel support to cfg80211 This patch adds support to advetise mwifiex multichannel support to cfg80211. If module parameter drcs is enabled and FW supports multichannel operation we advertise this support to cfg80211. As of now 2 simultaneous channels are supported. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 14 +++++++++++++- drivers/net/wireless/mwifiex/main.h | 1 + drivers/net/wireless/mwifiex/sta_cmd.c | 13 +++++++++---- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 46f9dc2b17369..bc863e9511406 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -43,6 +43,15 @@ static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { .beacon_int_infra_match = true, }; +static const struct +ieee80211_iface_combination mwifiex_drcs_iface_comb_ap_sta = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 2, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, +}; + /* * This function maps the nl802.11 channel type into driver channel type. * @@ -3745,7 +3754,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) else wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; + if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + wiphy->iface_combinations = &mwifiex_drcs_iface_comb_ap_sta; + else + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; /* Initialize cipher suits */ diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 6e82058c0eab1..f3264f2231d33 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -985,6 +985,7 @@ struct mwifiex_adapter { u8 coex_win_size; u8 coex_tx_win_size; u8 coex_rx_win_size; + bool drcs_enabled; }; void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index f250b61a9ff79..36cb6bdbe49bb 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -2155,12 +2155,17 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init) return -1; } - if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) - ret = mwifiex_send_cmd(priv, HostCmd_CMD_MC_POLICY, - HostCmd_ACT_GEN_SET, 0, &drcs, - true); + if (drcs) { + adapter->drcs_enabled = true; + if (ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) + ret = mwifiex_send_cmd(priv, + HostCmd_CMD_MC_POLICY, + HostCmd_ACT_GEN_SET, 0, + &adapter->drcs_enabled, + true); if (ret) return -1; + } } /* get tx rate */ -- GitLab From cc7359b5c82f67a1a19a0cf66f84f465403edb5d Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:22 +0530 Subject: [PATCH 1372/7006] mwifiex: separate interface combination for multichannel and DFS Multichannel and DFS cannot be supported at same time. So when multichannel operation is enabled by module parameter, we enable number of channel as 2 while registering wiphy. For all other cases we advertise DFS support to cfg80211. Patch also adds support for radar detect widths parameter. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index bc863e9511406..93e40d0e90860 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -35,16 +35,33 @@ static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { }, }; -static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta = { .limits = mwifiex_ap_sta_limits, .num_different_channels = 1, .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), .max_interfaces = MWIFIEX_MAX_BSS_NUM, .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40), +}; + +static const struct ieee80211_iface_combination +mwifiex_iface_comb_ap_sta_vht = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, + .radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) | + BIT(NL80211_CHAN_WIDTH_20) | + BIT(NL80211_CHAN_WIDTH_40) | + BIT(NL80211_CHAN_WIDTH_80), }; static const struct -ieee80211_iface_combination mwifiex_drcs_iface_comb_ap_sta = { +ieee80211_iface_combination mwifiex_iface_comb_ap_sta_drcs = { .limits = mwifiex_ap_sta_limits, .num_different_channels = 2, .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), @@ -3755,7 +3772,9 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; if (adapter->drcs_enabled && ISSUPP_DRCS_ENABLED(adapter->fw_cap_info)) - wiphy->iface_combinations = &mwifiex_drcs_iface_comb_ap_sta; + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_drcs; + else if (adapter->is_hw_11ac_capable) + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta_vht; else wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; wiphy->n_iface_combinations = 1; -- GitLab From 8d6b538a5eac1fec259d22ffa5b47ac585582432 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Mon, 22 Jun 2015 19:06:23 +0530 Subject: [PATCH 1373/7006] mwifiex: handle multichannel event This patch adds support to handle multichannel event from FW. Signed-off-by: Avinash Patil Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 8 +++++++ drivers/net/wireless/mwifiex/main.h | 2 ++ drivers/net/wireless/mwifiex/sta_event.c | 30 ++++++++++++++++++++++++ drivers/net/wireless/mwifiex/uap_event.c | 6 +++++ 4 files changed, 46 insertions(+) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 976b58587c27d..98269bfd2b31e 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -172,6 +172,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_TX_PAUSE (PROPRIETARY_TLV_BASE_ID + 148) #define TLV_TYPE_COALESCE_RULE (PROPRIETARY_TLV_BASE_ID + 154) #define TLV_TYPE_KEY_PARAM_V2 (PROPRIETARY_TLV_BASE_ID + 156) +#define TLV_TYPE_MULTI_CHAN_INFO (PROPRIETARY_TLV_BASE_ID + 183) #define TLV_TYPE_TDLS_IDLE_TIMEOUT (PROPRIETARY_TLV_BASE_ID + 194) #define TLV_TYPE_SCAN_CHANNEL_GAP (PROPRIETARY_TLV_BASE_ID + 197) #define TLV_TYPE_API_REV (PROPRIETARY_TLV_BASE_ID + 199) @@ -516,6 +517,7 @@ enum P2P_MODES { #define EVENT_TX_DATA_PAUSE 0x00000055 #define EVENT_EXT_SCAN_REPORT 0x00000058 #define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f +#define EVENT_MULTI_CHAN_INFO 0x0000006a #define EVENT_TX_STATUS_REPORT 0x00000074 #define EVENT_BT_COEX_WLAN_PARA_CHANGE 0X00000076 @@ -1970,6 +1972,12 @@ struct mwifiex_radar_det_event { __le32 passed; } __packed; +struct mwifiex_ie_types_multi_chan_info { + struct mwifiex_ie_types_header header; + __le16 status; + u8 tlv_buffer[0]; +} __packed; + struct meas_rpt_map { u8 rssi:3; u8 unmeasured:1; diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index f3264f2231d33..face7478937f6 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1557,6 +1557,8 @@ void mwifiex_11n_delba(struct mwifiex_private *priv, int tid); int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy); void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event); +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, + struct sk_buff *event_skb); #ifdef CONFIG_DEBUG_FS void mwifiex_debugfs_init(void); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index a2777d16c98ff..3d18c585e5436 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -309,6 +309,31 @@ static void mwifiex_process_sta_tx_pause(struct mwifiex_private *priv, } } +void mwifiex_process_multi_chan_event(struct mwifiex_private *priv, + struct sk_buff *event_skb) +{ + struct mwifiex_ie_types_multi_chan_info *chan_info; + u16 status; + + chan_info = (void *)event_skb->data + sizeof(u32); + + if (le16_to_cpu(chan_info->header.type) != TLV_TYPE_MULTI_CHAN_INFO) { + mwifiex_dbg(priv->adapter, ERROR, + "unknown TLV in chan_info event\n"); + return; + } + + status = le16_to_cpu(chan_info->status); + + if (status) { + mwifiex_dbg(priv->adapter, EVENT, + "multi-channel operation started\n"); + } else { + mwifiex_dbg(priv->adapter, EVENT, + "multi-channel operation over\n"); + } +} + void mwifiex_process_tx_pause_event(struct mwifiex_private *priv, struct sk_buff *event_skb) { @@ -748,6 +773,11 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; + case EVENT_MULTI_CHAN_INFO: + mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); + mwifiex_process_multi_chan_event(priv, adapter->event_skb); + break; + case EVENT_TX_STATUS_REPORT: mwifiex_dbg(adapter, EVENT, "event: TX_STATUS Report\n"); mwifiex_parse_tx_status_event(priv, adapter->event_body); diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c index a9d34c6191813..492a8b3c636e2 100644 --- a/drivers/net/wireless/mwifiex/uap_event.c +++ b/drivers/net/wireless/mwifiex/uap_event.c @@ -304,6 +304,12 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv) mwifiex_dbg(adapter, EVENT, "event: TX DATA PAUSE\n"); mwifiex_process_tx_pause_event(priv, adapter->event_skb); break; + + case EVENT_MULTI_CHAN_INFO: + mwifiex_dbg(adapter, EVENT, "event: multi-chan info\n"); + mwifiex_process_multi_chan_event(priv, adapter->event_skb); + break; + default: mwifiex_dbg(adapter, EVENT, "event: unknown event id: %#x\n", eventcause); -- GitLab From 9030d52cfb340f57d86e1b5d995a463eaddb977b Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:53:05 +0800 Subject: [PATCH 1374/7006] wireless: cw1200: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo To: Solomon Peachy To: Kalle Valo To: linux-wireless@vger.kernel.org To: netdev@vger.kernel.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Kalle Valo --- drivers/net/wireless/cw1200/cw1200_spi.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/wireless/cw1200/cw1200_spi.c b/drivers/net/wireless/cw1200/cw1200_spi.c index 7603546d2de32..29185aeccba8b 100644 --- a/drivers/net/wireless/cw1200/cw1200_spi.c +++ b/drivers/net/wireless/cw1200/cw1200_spi.c @@ -467,7 +467,6 @@ static struct spi_driver spi_driver = { .remove = cw1200_spi_disconnect, .driver = { .name = "cw1200_wlan_spi", - .bus = &spi_bus_type, .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &cw1200_pm_ops, -- GitLab From 722d26680af10bd128b5228ba23e5d11ef2256c4 Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 23 Jun 2015 14:45:45 -0400 Subject: [PATCH 1375/7006] mwifiex: avoid freeing improper pointer in mwifiex_set_wowlan_mef_entry mwifiex_set_wowlan_mef_entry attempts to free a passed-in pointer in case of an error. The only caller (mwifiex_set_mef_filter) passes that pointer as an offset into allocated memory, so any attempt to free that will not be the actual allocated pointer. Address this by changing mwifiex_set_wowlan_mef_entry to not do any free, and to cause mwifiex_set_mef_filter to do the appropriate free if the call to mwifiex_set_wowlan_mef_entry fails. Coverity CID #1295879 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 93e40d0e90860..69ee6dbafd617 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -2985,7 +2985,6 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv, MWIFIEX_MEF_MAX_BYTESEQ)) { mwifiex_dbg(priv->adapter, ERROR, "Pattern not supported\n"); - kfree(mef_entry); return -EOPNOTSUPP; } @@ -3067,9 +3066,12 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, mwifiex_set_auto_arp_mef_entry(priv, &mef_entry[0]); - if (wowlan->n_patterns || wowlan->magic_pkt) + if (wowlan->n_patterns || wowlan->magic_pkt) { ret = mwifiex_set_wowlan_mef_entry(priv, &mef_cfg, &mef_entry[1], wowlan); + if (ret) + goto err; + } if (!mef_cfg.criteria) mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST | @@ -3079,6 +3081,8 @@ static int mwifiex_set_mef_filter(struct mwifiex_private *priv, ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG, HostCmd_ACT_GEN_SET, 0, &mef_cfg, true); + +err: kfree(mef_entry); return ret; } -- GitLab From 8b2c621c9f6f6240edaf4359c3148068fff8b1c7 Mon Sep 17 00:00:00 2001 From: John Linville Date: Tue, 23 Jun 2015 15:04:03 -0400 Subject: [PATCH 1376/7006] mwifiex: do not short circuit exit from mwifiex_set_mgmt_ies Without this change, the code simply exits after calling mwifiex_uap_set_head_tail_ies, leving the call to mwifiex_set_mgmt_beacon_data_ies as dead code. Coverity CID #1271292 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 0ba8945094139..23e368c77c08b 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -409,6 +409,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, int ret; ret = mwifiex_uap_parse_tail_ies(priv, info); + + if (ret) return ret; return mwifiex_set_mgmt_beacon_data_ies(priv, info); -- GitLab From 550795fc68a4bfa699480b362648fef3d6c74c23 Mon Sep 17 00:00:00 2001 From: Avinash Patil Date: Wed, 24 Jun 2015 16:52:21 +0530 Subject: [PATCH 1377/7006] MAINTAINERS: update for mwifiex driver maintainers Amit & Nishant would be taking care of maintaining mwifiex driver here onwards on account of organizational changes. Signed-off-by: Avinash Patil Signed-off-by: Amitkumar Karwar Signed-off-by: Nishant Sarmukadam Signed-off-by: Cathy Luo Signed-off-by: Frank Huang Signed-off-by: Kalle Valo --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 993d4cfd5aa01..5249b108c6d2c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6483,7 +6483,7 @@ F: drivers/net/ethernet/marvell/mvneta.* MARVELL MWIFIEX WIRELESS DRIVER M: Amitkumar Karwar -M: Avinash Patil +M: Nishant Sarmukadam L: linux-wireless@vger.kernel.org S: Maintained F: drivers/net/wireless/mwifiex/ -- GitLab From b5c103f20f0fdd736c51c996b07a42594d683b1c Mon Sep 17 00:00:00 2001 From: John Linville Date: Fri, 26 Jun 2015 15:29:36 -0400 Subject: [PATCH 1378/7006] mwifiex: fix leak of gen_ie storage on exit from mwifiex_del_mgmt_ies Storage pointed to by gen_ie is allocated with kmalloc, but was never freed. Coverity CID #1271251 Signed-off-by: John W. Linville Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/ie.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index 23e368c77c08b..abf52d25b9815 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -479,6 +479,7 @@ int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) ar_ie, &priv->assocresp_idx); done: + kfree(gen_ie); kfree(beacon_ie); kfree(pr_ie); kfree(ar_ie); -- GitLab From 9aaffa340add31aeb4449667da8779df448b7987 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 17:36:45 +0530 Subject: [PATCH 1379/7006] drm/i915: remove unnecessary null test While creating the debugfs file we are setting the inode->i_private to dev. That same dev is passed to these functions as private of struct seq_file via single_open(). Moreover single_open is setting file->private_data->private to dev. So at this point it can never be NULL. This check was added by commit eb3394faeb97 ("drm/i915: Add debugfs test control files for Displayport compliance testing") Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc817da9fef7a..ffce62e33dc9f 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4028,24 +4028,14 @@ static ssize_t i915_displayport_test_active_write(struct file *file, { char *input_buffer; int status = 0; - struct seq_file *m; struct drm_device *dev; struct drm_connector *connector; struct list_head *connector_list; struct intel_dp *intel_dp; int val = 0; - m = file->private_data; - if (!m) { - status = -ENODEV; - return status; - } - dev = m->private; + dev = ((struct seq_file *)file->private_data)->private; - if (!dev) { - status = -ENODEV; - return status; - } connector_list = &dev->mode_config.connector_list; if (len == 0) @@ -4103,9 +4093,6 @@ static int i915_displayport_test_active_show(struct seq_file *m, void *data) struct list_head *connector_list = &dev->mode_config.connector_list; struct intel_dp *intel_dp; - if (!dev) - return -ENODEV; - list_for_each_entry(connector, connector_list, head) { if (connector->connector_type != @@ -4150,9 +4137,6 @@ static int i915_displayport_test_data_show(struct seq_file *m, void *data) struct list_head *connector_list = &dev->mode_config.connector_list; struct intel_dp *intel_dp; - if (!dev) - return -ENODEV; - list_for_each_entry(connector, connector_list, head) { if (connector->connector_type != @@ -4192,9 +4176,6 @@ static int i915_displayport_test_type_show(struct seq_file *m, void *data) struct list_head *connector_list = &dev->mode_config.connector_list; struct intel_dp *intel_dp; - if (!dev) - return -ENODEV; - list_for_each_entry(connector, connector_list, head) { if (connector->connector_type != -- GitLab From b8bb08ec48fb4eafefbc7899b50ec5c6216465b1 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Tue, 21 Jul 2015 17:36:46 +0530 Subject: [PATCH 1380/7006] drm/i915: remove redundant if check The extra check for connector_type is not required as we are already checking for connector_type != DRM_MODE_CONNECTOR_DisplayPort. The check was added by commit eb3394faeb97 ("drm/i915: Add debugfs test control files for Displayport compliance testing") Signed-off-by: Sudip Mukherjee Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index ffce62e33dc9f..caf1382116de0 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -4059,9 +4059,7 @@ static ssize_t i915_displayport_test_active_write(struct file *file, DRM_MODE_CONNECTOR_DisplayPort) continue; - if (connector->connector_type == - DRM_MODE_CONNECTOR_DisplayPort && - connector->status == connector_status_connected && + if (connector->status == connector_status_connected && connector->encoder != NULL) { intel_dp = enc_to_intel_dp(connector->encoder); status = kstrtoint(input_buffer, 10, &val); -- GitLab From 11bdc44093555829eb4a5d9318eece469e2873e8 Mon Sep 17 00:00:00 2001 From: Reyad Attiyat Date: Sun, 28 Jun 2015 20:07:38 -0500 Subject: [PATCH 1381/7006] mwifiex: usb: Fix double add error when submitting rx urb There is an error that can occur where the driver adds the same URB to USB submission list twice. This happens since mwifiex_usb_submit_rem_rx can submit packets at same time as an rx urb complete callback. This causes list corruption and is fixed by not setting the skb to NULL when submitting an rx packet. [ 84.461242] WARNING: CPU: 1 PID: 748 at lib/list_debug.c:36 __list_add+0xcb/0xd0() [ 84.461245] list_add double add: new=ffff8800c92b0c50, prev=ffff8800c92b0c50, next=ffff8800ced6c430. [ 84.461247] Modules linked in: rfcomm fuse cmac nf_conntrack_netbios_ns nf_conntrack_broadcast ip6t_rpfilter ip6t_REJECT nf_reject_ipv6 xt_conntrack ebtable_nat ebtable_broute bridge stp llc ebtable_filter ebtables ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw ip6table_filter ip6_tables iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack bnep iptable_mangle iptable_security iptable_raw btusb btintel bluetooth mwifiex_usb mwifiex x86_pkg_temp_thermal cfg80211 coretemp r8712u(C) kvm_intel kvm hid_sensor_als hid_sensor_incl_3d hid_sensor_rotation hid_sensor_magn_3d hid_sensor_accel_3d hid_sensor_gyro_3d hid_sensor_trigger hid_sensor_iio_common industrialio_triggered_buffer kfifo_buf rfkill iTCO_wdt industrialio iTCO_vendor_support [ 84.461316] crc32_pclmul crc32c_intel ghash_clmulni_intel microcode snd_hda_codec_realtek vfat snd_hda_codec_generic fat snd_hda_codec_hdmi snd_hda_intel snd_hda_controller uvcvideo snd_hda_codec videobuf2_vmalloc videobuf2_memops snd_hwdep videobuf2_core snd_hda_core joydev v4l2_common videodev hid_sensor_hub snd_seq hid_multitouch media snd_seq_device snd_pcm snd_timer mei_me snd i2c_i801 lpc_ich mei soundcore tpm_infineon tpm_tis tpm i2c_hid i2c_designware_platform i2c_designware_core nfsd auth_rpcgss nfs_acl lockd grace sunrpc sch_fq_codel i915 i2c_algo_bit drm_kms_helper drm xhci_pci xhci_hcd ehci_pci sd_mod ehci_hcd video [ 84.461383] CPU: 1 PID: 748 Comm: kworker/u9:0 Tainted: G C 4.1.0-rc5+ #163 [ 84.461386] Hardware name: Microsoft Corporation Surface Pro 2/Surface Pro 2, BIOS 2.05.0250 04/10/2015 [ 84.461396] Workqueue: MWIFIEX_RX_WORK_QUEUE mwifiex_rx_work_queue [mwifiex] [ 84.461399] ffffffff81a8150e ffff8801174cf8e8 ffffffff817df830 0000000000000000 [ 84.461405] ffff8801174cf938 ffff8801174cf928 ffffffff810a54ba ffff8800c86bd750 [ 84.461410] ffff8800c92b0c50 ffff8800c92b0c50 ffff8800ced6c430 ffff88010c057178 [ 84.461416] Call Trace: [ 84.461421] [] dump_stack+0x4f/0x7b [ 84.461428] [] warn_slowpath_common+0x8a/0xc0 [ 84.461432] [] warn_slowpath_fmt+0x46/0x50 [ 84.461436] [] __list_add+0xcb/0xd0 [ 84.461442] [] ? usb_hcd_link_urb_to_ep+0x2a/0xa0 [ 84.461446] [] usb_hcd_link_urb_to_ep+0x80/0xa0 [ 84.461459] [] prepare_transfer+0xaa/0x130 [xhci_hcd] [ 84.461470] [] xhci_queue_bulk_tx+0xb7/0x7a0 [xhci_hcd] [ 84.461480] [] ? xhci_urb_enqueue+0x50f/0x660 [xhci_hcd] [ 84.461489] [] ? xhci_urb_enqueue+0x50f/0x660 [xhci_hcd] [ 84.461498] [] xhci_urb_enqueue+0x5c5/0x660 [xhci_hcd] [ 84.461503] [] usb_hcd_submit_urb+0x93/0xa70 [ 84.461507] [] ? __alloc_skb+0x78/0x1f0 [ 84.461511] [] ? __kmalloc_reserve.isra.26+0x31/0x90 [ 84.461515] [] ? __alloc_skb+0x4c/0x1f0 [ 84.461519] [] ? __alloc_skb+0x8c/0x1f0 [ 84.461523] [] ? skb_dequeue+0x5d/0x80 [ 84.461527] [] usb_submit_urb+0x42e/0x5f0 [ 84.461531] [] ? __alloc_rx_skb+0x39/0x100 [ 84.461536] [] mwifiex_usb_submit_rx_urb+0xb2/0x170 [mwifiex_usb] [ 84.461542] [] mwifiex_usb_submit_rem_rx_urbs+0x45/0x50 [mwifiex_usb] [ 84.461550] [] mwifiex_rx_work_queue+0x10e/0x140 [mwifiex] [ 84.461556] [] process_one_work+0x229/0x890 [ 84.461559] [] ? process_one_work+0x18c/0x890 [ 84.461565] [] worker_thread+0x53/0x470 [ 84.461569] [] ? process_one_work+0x890/0x890 [ 84.461572] [] kthread+0xf2/0x110 [ 84.461577] [] ? trace_hardirqs_on+0xd/0x10 [ 84.461581] [] ? kthread_create_on_node+0x230/0x230 [ 84.461586] [] ret_from_fork+0x42/0x70 [ 84.461590] [] ? kthread_create_on_node+0x230/0x230 [ 84.461593] ---[ end trace 65103af5e6fb3444 ]--- Signed-off-by: Reyad Attiyat Acked-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/usb.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index aada93425f806..fbad99c503078 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -244,9 +244,11 @@ setup_for_next: if (card->rx_cmd_ep == context->ep) { mwifiex_usb_submit_rx_urb(context, size); } else { - context->skb = NULL; - if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING) + if (atomic_read(&adapter->rx_pending) <= HIGH_RX_PENDING){ mwifiex_usb_submit_rx_urb(context, size); + }else{ + context->skb = NULL; + } } return; -- GitLab From 33b8261e0e1c6d95901d62808d65141d4df525bd Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 20:17:55 -0400 Subject: [PATCH 1382/7006] rtlwifi: fix typo in comments This fixes a typo in two comments: "paht" -> "path". Signed-off-by: Nik Nyby Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192de/phy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 1961b8e28dc16..bb06fe836fe75 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3515,14 +3515,14 @@ void rtl92d_update_bbrf_configuration(struct ieee80211_hw *hw) for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath; rfpath++) { if (rtlhal->current_bandtype == BAND_ON_2_4G) { - /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + /* MOD_AG for RF path_A 0x18 BIT8,BIT16 */ rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | BIT(18), 0); /* RF0x0b[16:14] =3b'111 */ rtl_set_rfreg(hw, (enum radio_path)rfpath, 0x0B, 0x1c000, 0x07); } else { - /* MOD_AG for RF paht_A 0x18 BIT8,BIT16 */ + /* MOD_AG for RF path_A 0x18 BIT8,BIT16 */ rtl_set_rfreg(hw, rfpath, RF_CHNLBW, BIT(8) | BIT(16) | BIT(18), (BIT(16) | BIT(8)) >> 8); -- GitLab From 277bf09e8be9fa35d6bc0175c2c5a1e6bdb0626e Mon Sep 17 00:00:00 2001 From: Nik Nyby Date: Mon, 29 Jun 2015 20:45:47 -0400 Subject: [PATCH 1383/7006] b43: Fix typo in function name This fixes a typo in the "b43_lo_g_maintenance_work" function name. Signed-off-by: Nik Nyby Acked-by: Larry Finger Acked-by: Michael Buesch Signed-off-by: Kalle Valo --- drivers/net/wireless/b43/lo.c | 4 ++-- drivers/net/wireless/b43/lo.h | 2 +- drivers/net/wireless/b43/phy_g.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/b43/lo.c b/drivers/net/wireless/b43/lo.c index 916123a3d74e7..a335f94c72ff7 100644 --- a/drivers/net/wireless/b43/lo.c +++ b/drivers/net/wireless/b43/lo.c @@ -929,8 +929,8 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, b43_lo_write(dev, &cal->ctl); } -/* Periodic LO maintanance work */ -void b43_lo_g_maintanance_work(struct b43_wldev *dev) +/* Periodic LO maintenance work */ +void b43_lo_g_maintenance_work(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; diff --git a/drivers/net/wireless/b43/lo.h b/drivers/net/wireless/b43/lo.h index 3b27e20eff80f..7b4df3883bc24 100644 --- a/drivers/net/wireless/b43/lo.h +++ b/drivers/net/wireless/b43/lo.h @@ -80,7 +80,7 @@ void b43_lo_g_adjust_to(struct b43_wldev *dev, void b43_gphy_dc_lt_init(struct b43_wldev *dev, bool update_all); -void b43_lo_g_maintanance_work(struct b43_wldev *dev); +void b43_lo_g_maintenance_work(struct b43_wldev *dev); void b43_lo_g_cleanup(struct b43_wldev *dev); void b43_lo_g_init(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 727ce6edb4b38..462310e6e88fb 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -3004,7 +3004,7 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) phy->rev == 1) { //TODO: implement rev1 workaround } - b43_lo_g_maintanance_work(dev); + b43_lo_g_maintenance_work(dev); b43_mac_enable(dev); } -- GitLab From cf7d5a80201066daac467d57a47b0826c2e88354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Poggi?= Date: Thu, 2 Jul 2015 10:34:49 +0200 Subject: [PATCH 1384/7006] wlcore: sdio: return correct error code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When wlcore_probe_of failed, return the correct error code instead of ENOMEM Signed-off-by: Raphaël Poggi Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/sdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index ea7e07abca4eb..c172da56b550b 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -293,7 +293,8 @@ static int wl1271_probe(struct sdio_func *func, /* Use block mode for transferring over one block size of data */ func->card->quirks |= MMC_QUIRK_BLKSZ_FOR_BYTE_MODE; - if (wlcore_probe_of(&func->dev, &irq, &pdev_data)) + ret = wlcore_probe_of(&func->dev, &irq, &pdev_data); + if (ret) goto out_free_glue; /* if sdio can keep power while host is suspended, enable wow */ -- GitLab From e60ac9c7a4c8776b2503892dfd01f1b4d651245d Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 2 Jul 2015 13:40:29 +0200 Subject: [PATCH 1385/7006] ath9k: make DMA stop related messages debug-only A long time ago, ath9k had issues during reset where the DMA engine would stay active and could potentially corrupt memory. To debug those issues, the driver would print warnings whenever they occur. Nowadays, these issues are gone and the primary cause of these messages is if the MAC is stuck during reset or busy processing a long transmission. This is fairly harmless, yet these messages continue to worry users. To reduce the number of bogus bug reports, turn these messages into debug messages and count their occurence in the "reset" debugfs file. Signed-off-by: Felix Fietkau Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/debug.c | 2 ++ drivers/net/wireless/ath/ath9k/debug.h | 2 ++ drivers/net/wireless/ath/ath9k/recv.c | 7 +++---- drivers/net/wireless/ath/ath9k/xmit.c | 7 +++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index dbf8f49596421..da32c8faad94f 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -765,6 +765,8 @@ static int read_file_reset(struct seq_file *file, void *data) [RESET_TYPE_BEACON_STUCK] = "Stuck Beacon", [RESET_TYPE_MCI] = "MCI Reset", [RESET_TYPE_CALIBRATION] = "Calibration error", + [RESET_TX_DMA_ERROR] = "Tx DMA stop error", + [RESET_RX_DMA_ERROR] = "Rx DMA stop error", }; int i; diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index a8e9319958e6e..cd68c5f0e751a 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -50,6 +50,8 @@ enum ath_reset_type { RESET_TYPE_BEACON_STUCK, RESET_TYPE_MCI, RESET_TYPE_CALIBRATION, + RESET_TX_DMA_ERROR, + RESET_RX_DMA_ERROR, __RESET_TYPE_MAX }; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6c75fb1ab77d4..d3189daf99965 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -491,10 +491,9 @@ bool ath_stoprecv(struct ath_softc *sc) if (!(ah->ah_flags & AH_UNPLUGGED) && unlikely(!stopped)) { - ath_err(ath9k_hw_common(sc->sc_ah), - "Could not stop RX, we could be " - "confusing the DMA engine when we start RX up\n"); - ATH_DBG_WARN_ON_ONCE(!stopped); + ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, + "Failed to stop Rx DMA\n"); + RESET_STAT_INC(sc, RESET_RX_DMA_ERROR); } return stopped && !reset; } diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 3ad79bb4f2c21..2c627f1233da6 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -1883,8 +1883,11 @@ bool ath_drain_all_txq(struct ath_softc *sc) npend |= BIT(i); } - if (npend) - ath_err(common, "Failed to stop TX DMA, queues=0x%03x!\n", npend); + if (npend) { + RESET_STAT_INC(sc, RESET_TX_DMA_ERROR); + ath_dbg(common, RESET, + "Failed to stop TX DMA, queues=0x%03x!\n", npend); + } for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (!ATH_TXQ_SETUP(sc, i)) -- GitLab From ae86c587b5b53da4f7859f236f6c22ff9941cff9 Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 2 Jul 2015 06:07:02 -0700 Subject: [PATCH 1386/7006] mwifiex: fix for p2p broken link This patch fixes following issues in p2p code paths. 1) bss role, bss type and connection type was not set correctly for p2p GO and p2p client at couple of places. 2) Driver appends a proprietary header to management frames which will be parsed by our firmware. Later while informing TX status to cfg80211, modified frame buffer was passed to cfg80211_mgmt_tx_status() instead of original one. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 5 ++++- drivers/net/wireless/mwifiex/sta_cmd.c | 6 ++++-- drivers/net/wireless/mwifiex/txrx.c | 22 +++++++++++++++++++++- 3 files changed, 29 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 69ee6dbafd617..d4b327752a5e2 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -831,10 +831,13 @@ mwifiex_init_new_priv_params(struct mwifiex_private *priv, priv->bss_type = MWIFIEX_BSS_TYPE_STA; break; case NL80211_IFTYPE_P2P_CLIENT: - case NL80211_IFTYPE_P2P_GO: priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_type = MWIFIEX_BSS_TYPE_P2P; break; + case NL80211_IFTYPE_P2P_GO: + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + priv->bss_type = MWIFIEX_BSS_TYPE_P2P; + break; case NL80211_IFTYPE_AP: priv->bss_type = MWIFIEX_BSS_TYPE_UAP; priv->bss_role = MWIFIEX_BSS_ROLE_UAP; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 36cb6bdbe49bb..a49a80dd773ed 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -1997,10 +1997,12 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, if (priv->bss_mode == NL80211_IFTYPE_ADHOC) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_ADHOC; - else if (priv->bss_mode == NL80211_IFTYPE_STATION) + else if (priv->bss_mode == NL80211_IFTYPE_STATION || + priv->bss_mode == NL80211_IFTYPE_P2P_CLIENT) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_INFRA; - else if (priv->bss_mode == NL80211_IFTYPE_AP) + else if (priv->bss_mode == NL80211_IFTYPE_AP || + priv->bss_mode == NL80211_IFTYPE_P2P_GO) cmd_ptr->params.bss_mode.con_type = CONNECTION_TYPE_AP; cmd_ptr->size = cpu_to_le16(sizeof(struct host_cmd_ds_set_bss_mode) + S_DS_GEN); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index 5ed9b794053e7..8b1e5b5d47fee 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -370,8 +370,28 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv, /* consumes ack_skb */ skb_complete_wifi_ack(ack_skb, !tx_status->status); } else { + /* Remove broadcast address which was added by driver */ + memmove(ack_skb->data + + sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16), + ack_skb->data + + sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + + ETH_ALEN, ack_skb->len - + (sizeof(struct ieee80211_hdr_3addr) + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + sizeof(u16) + + ETH_ALEN)); + ack_skb->len = ack_skb->len - ETH_ALEN; + /* Remove driver's proprietary header including 2 bytes + * of packet length and pass actual management frame buffer + * to cfg80211. + */ cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie, - ack_skb->data, ack_skb->len, + ack_skb->data + + MWIFIEX_MGMT_FRAME_HEADER_SIZE + + sizeof(u16), ack_skb->len - + (MWIFIEX_MGMT_FRAME_HEADER_SIZE + + sizeof(u16)), !tx_status->status, GFP_ATOMIC); dev_kfree_skb_any(ack_skb); } -- GitLab From cae761b5a6bdc597ba476a040fdcd5b4bc559b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Sun, 28 Jun 2015 17:17:13 +0200 Subject: [PATCH 1387/7006] bcma: populate bus DT subnodes as platform_device-s MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Our bus should allow defining children nodes as we may want to specify devices attached to the bus. This is required e.g. to specify NAND or ChipCommon cores and use bus's address and IRQ mappings. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/bcma/main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 9635f1033ce5c..59128478a90fd 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -12,6 +12,7 @@ #include #include #include +#include MODULE_DESCRIPTION("Broadcom's specific AMBA driver"); MODULE_LICENSE("GPL"); @@ -409,6 +410,13 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_early_init(&bus->drv_pci[0]); } + if (bus->host_pdev) { + struct device *dev = &bus->host_pdev->dev; + + of_platform_populate(dev->of_node, of_default_bus_match_table, + NULL, dev); + } + /* Cores providing flash access go before SPROM init */ list_for_each_entry(core, &bus->cores, list) { if (bcma_is_core_needed_early(core->id.id)) -- GitLab From 251086f588720277a6f5782020a648ce32c4e00b Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Wed, 8 Jul 2015 10:18:50 -0500 Subject: [PATCH 1388/7006] rtlwifi: rtl8821ae: Fix an expression that is always false In routine _rtl8821ae_set_media_status(), an incorrect mask results in a test for AP status to always be false. Similar bugs were fixed in rtl8192cu and rtl8192de, but this instance was missed at that time. Reported-by: David Binderman Signed-off-by: Larry Finger Cc: Stable [3.18+] Cc: David Binderman Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | 2 +- drivers/net/wireless/rtlwifi/rtl8821ae/reg.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c index 3236d44b459df..b7f18e2155eb1 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c @@ -2180,7 +2180,7 @@ static int _rtl8821ae_set_media_status(struct ieee80211_hw *hw, rtl_write_byte(rtlpriv, MSR, bt_msr); rtlpriv->cfg->ops->led_control(hw, ledaction); - if ((bt_msr & 0xfc) == MSR_AP) + if ((bt_msr & MSR_MASK) == MSR_AP) rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00); else rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66); diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h index 53668fc8f23e2..1d6110f9c1fb6 100644 --- a/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/reg.h @@ -429,6 +429,7 @@ #define MSR_ADHOC 0x01 #define MSR_INFRA 0x02 #define MSR_AP 0x03 +#define MSR_MASK 0x03 #define RRSR_RSC_OFFSET 21 #define RRSR_SHORT_OFFSET 23 -- GitLab From 77661208a87b458f353fd0b7a4729cf2887449a6 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Wed, 8 Jul 2015 22:22:46 +0200 Subject: [PATCH 1389/7006] brcmsmac: Use kstrdup to simplify code Replace a kmalloc+strcpy by an equivalent kstrdup in order to improve readability. Signed-off-by: Christophe JAILLET Acked-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index ab775a5d5b331..d2c5747e3ac92 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -1472,9 +1472,7 @@ struct brcms_timer *brcms_init_timer(struct brcms_info *wl, wl->timers = t; #ifdef DEBUG - t->name = kmalloc(strlen(name) + 1, GFP_ATOMIC); - if (t->name) - strcpy(t->name, name); + t->name = kstrdup(name, GFP_ATOMIC); #endif return t; -- GitLab From 92cd40322848a12f1f3ef2d7804233b93030c532 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 9 Jul 2015 12:27:22 +0200 Subject: [PATCH 1390/7006] ath9k: fix moredata flag endianness in cabq tx While compiling ath9k with some extra flags I've found that: ath9k/xmit.c +2473 ## 16: warning: restricted __le16 degrades to integer ath9k/xmit.c +2474 ## 36: warning: invalid assignment: &= ath9k/xmit.c +2474 ## 36: left side has type restricted __le16 ath9k/xmit.c +2474 ## 36: right side has type int There's no way for frame ftype/stype to be mistreated as the offending 'moredata' flag when considering cab queue. This could've however theoretically led sometimes to increased power consumption on connected stations as they would keep their Rx active waiting for frames that would never come. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 2c627f1233da6..b766a7fc60aaa 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2473,8 +2473,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct ieee80211_vif *vif, bf = list_first_entry(&bf_q, struct ath_buf, list); hdr = (struct ieee80211_hdr *) bf->bf_mpdu->data; - if (hdr->frame_control & IEEE80211_FCTL_MOREDATA) { - hdr->frame_control &= ~IEEE80211_FCTL_MOREDATA; + if (hdr->frame_control & cpu_to_le16(IEEE80211_FCTL_MOREDATA)) { + hdr->frame_control &= ~cpu_to_le16(IEEE80211_FCTL_MOREDATA); dma_sync_single_for_device(sc->dev, bf->bf_buf_addr, sizeof(*hdr), DMA_TO_DEVICE); } -- GitLab From e3faa866d5e4d6199b45f821343ee24510881823 Mon Sep 17 00:00:00 2001 From: Rafa? Mi?ecki Date: Thu, 9 Jul 2015 17:07:08 +0200 Subject: [PATCH 1391/7006] brcmfmac: set wiphy's addresses to provide valid MACs Broadcom's firmware requires every BSS to use MAC address with unique last few bits. The amount of bits may depend on a particular firmware, it was verified to be 2 for BCM43602 one. If this condition won't be fulfilled firmware will reject such MAC: brcmfmac: _brcmf_set_mac_address: Setting cur_etheraddr failed, -52 We don't want to simply set addr_mask as it would also disallow using locally administrated bit. Instead let's build a list of addresses manually enabling 0x2 bit for extra interfaces. Signed-off-by: Rafa? Mi?ecki Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 14 ++++++++++++++ drivers/net/wireless/brcm80211/brcmfmac/core.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index d86d1f1f1c91d..ffe526070d6f1 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5785,6 +5785,7 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy) static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { + struct brcmf_pub *drvr = ifp->drvr; struct ieee80211_supported_band *band; __le32 bandlist[3]; u32 n_bands; @@ -5798,6 +5799,19 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) if (err) return err; + for (i = 0; i < wiphy->iface_combinations->max_interfaces && + i < ARRAY_SIZE(drvr->addresses); i++) { + u8 *addr = drvr->addresses[i].addr; + + memcpy(addr, drvr->mac, ETH_ALEN); + if (i) { + addr[0] |= BIT(1); + addr[ETH_ALEN - 1] ^= i; + } + } + wiphy->addresses = drvr->addresses; + wiphy->n_addresses = i; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = __wl_cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h index fd74a9c6e9ac6..746304121cdbf 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h @@ -21,6 +21,7 @@ #ifndef BRCMFMAC_CORE_H #define BRCMFMAC_CORE_H +#include #include "fweh.h" #define TOE_TX_CSUM_OL 0x00000001 @@ -118,6 +119,8 @@ struct brcmf_pub { /* Multicast data packets sent to dongle */ unsigned long tx_multicast; + struct mac_address addresses[BRCMF_MAX_IFS]; + struct brcmf_if *iflist[BRCMF_MAX_IFS]; struct mutex proto_block; -- GitLab From fa5b8c8a5ae4088a590d59fffb022da3ea17bd15 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 15 Jul 2015 15:54:06 +0800 Subject: [PATCH 1392/7006] ath9k: Fix register definitions for QCA956x Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 25 ++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index fc595b92ac560..c5f8bc4b5595e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -455,7 +455,7 @@ #define AR_PHY_MODE (AR_SM_BASE + 0x8) #define AR_PHY_ACTIVE (AR_SM_BASE + 0xc) #define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20)) -#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24) +#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x1c : 0x24)) #define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28) #define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c) #define AR_PHY_SEARCH_START_DELAY (AR_SM_BASE + 0x30) @@ -495,7 +495,7 @@ #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A 0x3FF #define AR_PHY_SPUR_MASK_A_CF_PUNC_MASK_A_S 0 -#define AR_PHY_TEST (AR_SM_BASE + 0x160) +#define AR_PHY_TEST (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x15c : 0x160)) #define AR_PHY_TEST_BBB_OBS_SEL 0x780000 #define AR_PHY_TEST_BBB_OBS_SEL_S 19 @@ -521,24 +521,29 @@ #define AR_PHY_TEST_CTL_DEBUGPORT_SEL_S 29 -#define AR_PHY_TSTDAC (AR_SM_BASE + 0x168) +#define AR_PHY_TSTDAC (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x164 : 0x168)) -#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c) +#define AR_PHY_CHAN_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x168 : 0x16c)) #define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170)) #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008 #define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3 -#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + 0x174) -#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + 0x178) -#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + 0x17c) -#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + 0x180) -#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190) -#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194) +#define AR_PHY_CHNINFO_NOISEPWR (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x170 : 0x174)) +#define AR_PHY_CHNINFO_GAINDIFF (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x174 : 0x178)) +#define AR_PHY_CHNINFO_FINETIM (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x178 : 0x17c)) +#define AR_PHY_CHAN_INFO_GAIN_0 (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x17c : 0x180)) +#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x184 : 0x190)) +#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x188 : 0x194)) #define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4)) #define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8) #define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac) +#define AR_PHY_HEAVYCLIP_1 (AR_SM_BASE + 0x19c) +#define AR_PHY_HEAVYCLIP_2 (AR_SM_BASE + 0x1a0) +#define AR_PHY_HEAVYCLIP_3 (AR_SM_BASE + 0x1a4) +#define AR_PHY_HEAVYCLIP_4 (AR_SM_BASE + 0x1a8) +#define AR_PHY_HEAVYCLIP_5 (AR_SM_BASE + 0x1ac) #define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0) #define AR_PHY_POWER_TX_RATE(_d) (AR_SM_BASE + 0x1c0 + ((_d) << 2)) -- GitLab From 6301566e0b2dafa7d6779598621bca867962a0a2 Mon Sep 17 00:00:00 2001 From: Miaoqing Pan Date: Wed, 15 Jul 2015 15:54:07 +0800 Subject: [PATCH 1393/7006] ath9k: export HW random number generator We measured the FFT-based entropy in 3 ways, Shannon entropy, collision entropy, and directly measured min-entropy. Just to be conservative, we recommend the estimated min-Entropy to be 10 bits per 16-bit value. Analysis was done by Jacobson,David(djacobso@qti.qualcomm.com). Signed-off-by: Miaoqing Pan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/Kconfig | 7 +++ drivers/net/wireless/ath/ath9k/Makefile | 1 + drivers/net/wireless/ath/ath9k/ath9k.h | 23 ++++++++ drivers/net/wireless/ath/ath9k/main.c | 4 ++ drivers/net/wireless/ath/ath9k/rng.c | 75 +++++++++++++++++++++++++ 5 files changed, 110 insertions(+) create mode 100644 drivers/net/wireless/ath/ath9k/rng.c diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index fee0cadb0f5ed..bde62ec98bc7f 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -176,3 +176,10 @@ config ATH9K_HTC_DEBUGFS depends on ATH9K_HTC && DEBUG_FS ---help--- Say Y, if you need access to ath9k_htc's statistics. + +config ATH9K_HWRNG + bool "Random number generator support" + depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K) + default y + ---help--- + Provides a hardware random number generator to the kernel. diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index ecda613c2d547..76f9dc37500b1 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -15,6 +15,7 @@ ath9k-$(CONFIG_ATH9K_DFS_DEBUGFS) += dfs_debug.o ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += dfs.o ath9k-$(CONFIG_ATH9K_TX99) += tx99.o ath9k-$(CONFIG_ATH9K_WOW) += wow.o +ath9k-$(CONFIG_ATH9K_HWRNG) += rng.o ath9k-$(CONFIG_ATH9K_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index a7a81b3969cec..45596e5ae4db3 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -23,6 +23,7 @@ #include #include #include +#include #include "common.h" #include "debug.h" @@ -1041,6 +1042,12 @@ struct ath_softc { u32 wow_intr_before_sleep; bool force_wow; #endif + +#ifdef CONFIG_ATH9K_HWRNG + struct hwrng rng; + bool rng_initialized; + u32 rng_last; +#endif }; /********/ @@ -1063,6 +1070,22 @@ static inline int ath9k_tx99_send(struct ath_softc *sc, } #endif /* CONFIG_ATH9K_TX99 */ +/***************************/ +/* Random Number Generator */ +/***************************/ +#ifdef CONFIG_ATH9K_HWRNG +void ath9k_rng_register(struct ath_softc *sc); +void ath9k_rng_unregister(struct ath_softc *sc); +#else +static inline void ath9k_rng_register(struct ath_softc *sc) +{ +} + +static inline void ath9k_rng_unregister(struct ath_softc *sc) +{ +} +#endif + static inline void ath_read_cachesize(struct ath_common *common, int *csz) { common->bus_ops->read_cachesize(common, csz); diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cfd45cb8ccfc1..5916ab2f4a3de 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -739,6 +739,8 @@ static int ath9k_start(struct ieee80211_hw *hw) ath9k_ps_restore(sc); + ath9k_rng_register(sc); + return 0; } @@ -828,6 +830,8 @@ static void ath9k_stop(struct ieee80211_hw *hw) ath9k_deinit_channel_context(sc); + ath9k_rng_unregister(sc); + mutex_lock(&sc->mutex); ath_cancel_work(sc); diff --git a/drivers/net/wireless/ath/ath9k/rng.c b/drivers/net/wireless/ath/ath9k/rng.c new file mode 100644 index 0000000000000..d8fa7a535ab8f --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/rng.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2015 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, 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 "ath9k.h" +#include "hw.h" +#include "ar9003_phy.h" + +static int ath9k_rng_data_read(struct hwrng *rng, u32 *data) +{ + u32 v1, v2; + struct ath_softc *sc = (struct ath_softc *)rng->priv; + struct ath_hw *ah = sc->sc_ah; + + ath9k_ps_wakeup(sc); + + REG_RMW_FIELD(ah, AR_PHY_TEST, AR_PHY_TEST_BBB_OBS_SEL, 5); + REG_CLR_BIT(ah, AR_PHY_TEST, AR_PHY_TEST_RX_OBS_SEL_BIT5); + REG_RMW_FIELD(ah, AR_PHY_TEST_CTL_STATUS, AR_PHY_TEST_CTL_RX_OBS_SEL, 0); + + v1 = REG_READ(ah, AR_PHY_TST_ADC); + v2 = REG_READ(ah, AR_PHY_TST_ADC); + + ath9k_ps_restore(sc); + + /* wait for data ready */ + if (v1 && v2 && sc->rng_last != v1 && v1 != v2) { + *data = (v1 & 0xffff) | (v2 << 16); + sc->rng_last = v2; + + return sizeof(u32); + } + + sc->rng_last = v2; + + return 0; +} + +void ath9k_rng_register(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + + if (WARN_ON(sc->rng_initialized)) + return; + + if (!AR_SREV_9300_20_OR_LATER(ah)) + return; + + sc->rng.name = "ath9k"; + sc->rng.data_read = ath9k_rng_data_read; + sc->rng.priv = (unsigned long)sc; + + if (!hwrng_register(&sc->rng)) + sc->rng_initialized = true; +} + +void ath9k_rng_unregister(struct ath_softc *sc) +{ + if (sc->rng_initialized) { + hwrng_unregister(&sc->rng); + sc->rng_initialized = false; + } +} -- GitLab From 5d6af28a2d240602a594cea236406a9d29bc719a Mon Sep 17 00:00:00 2001 From: Guy Mishol Date: Thu, 16 Jul 2015 11:22:47 +0300 Subject: [PATCH 1394/7006] wlcore: add antenna diversity reading update the rssi reading on rx_status to read both RSSI level (7 bits) and antenna diversity (msb) Signed-off-by: Guy Mishol Signed-off-by: Kalle Valo --- drivers/net/wireless/ti/wlcore/rx.c | 3 ++- drivers/net/wireless/ti/wlcore/rx.h | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index e125974285cc8..7df672a84530b 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -74,7 +74,8 @@ static void wl1271_rx_status(struct wl1271 *wl, if (desc->rate <= wl->hw_min_ht_rate) status->flag |= RX_FLAG_HT; - status->signal = desc->rssi; + status->signal = ((desc->rssi & RSSI_LEVEL_BITMASK) | BIT(7)); + status->antenna = ((desc->rssi & ANT_DIVERSITY_BITMASK) >> 7); /* * FIXME: In wl1251, the SNR should be divided by two. In wl1271 we diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index a3b1618db27c2..f5a7087cfb978 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -30,6 +30,9 @@ #define WL1271_RX_MAX_RSSI -30 #define WL1271_RX_MIN_RSSI -95 +#define RSSI_LEVEL_BITMASK 0x7F +#define ANT_DIVERSITY_BITMASK BIT(7) + #define SHORT_PREAMBLE_BIT BIT(0) #define OFDM_RATE_BIT BIT(6) #define PBCC_RATE_BIT BIT(7) -- GitLab From 8358491d893e08d4b82af0d6012e078158f57ed9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 16 Jul 2015 15:42:15 +0300 Subject: [PATCH 1395/7006] iwlegacy: convert hex_dump_to_buffer() to %*ph There is no need to use hex_dump_to_buffer() in the cases like this: hexdump_to_buffer(buf, len, 16, 1, outbuf, outlen, false); /* len <= 16 */ sprintf("%s\n", outbuf); since it maybe easily converted to simple: sprintf("%*ph\n", len, buf); Note: it seems in the case the output is groupped by 2 bytes and looks like a typo. Thus, patch changes that to plain byte stream. Signed-off-by: Andy Shevchenko Signed-off-by: Kalle Valo --- drivers/net/wireless/iwlegacy/3945-mac.c | 2 +- drivers/net/wireless/iwlegacy/debug.c | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c index 7f4cb692cc57e..af1b3e6839fa6 100644 --- a/drivers/net/wireless/iwlegacy/3945-mac.c +++ b/drivers/net/wireless/iwlegacy/3945-mac.c @@ -3259,7 +3259,7 @@ il3945_show_measurement(struct device *d, struct device_attribute *attr, while (size && PAGE_SIZE - len) { hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); + PAGE_SIZE - len, true); len = strlen(buf); if (PAGE_SIZE - len) buf[len++] = '\n'; diff --git a/drivers/net/wireless/iwlegacy/debug.c b/drivers/net/wireless/iwlegacy/debug.c index 3440101531963..908b9f4fef6f3 100644 --- a/drivers/net/wireless/iwlegacy/debug.c +++ b/drivers/net/wireless/iwlegacy/debug.c @@ -515,12 +515,8 @@ il_dbgfs_nvm_read(struct file *file, char __user *user_buf, size_t count, scnprintf(buf + pos, buf_size - pos, "EEPROM " "version: 0x%x\n", eeprom_ver); for (ofs = 0; ofs < eeprom_len; ofs += 16) { - pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs); - hex_dump_to_buffer(ptr + ofs, 16, 16, 2, buf + pos, - buf_size - pos, 0); - pos += strlen(buf + pos); - if (buf_size - pos > 0) - buf[pos++] = '\n'; + pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x %16ph\n", + ofs, ptr + ofs); } ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); -- GitLab From 40d7412b56f02160291a5153551c4ada8e76f6ed Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:05:21 -0700 Subject: [PATCH 1396/7006] mwifiex: add bss mode TLV to extended scan command We are setting BSS mode as ANY so that firmware will provide all types of scan entries. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/fw.h | 6 ++++++ drivers/net/wireless/mwifiex/scan.c | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 98269bfd2b31e..cff38ad129aad 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -179,6 +179,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_CHANNEL_STATS (PROPRIETARY_TLV_BASE_ID + 198) #define TLV_BTCOEX_WL_AGGR_WINSIZE (PROPRIETARY_TLV_BASE_ID + 202) #define TLV_BTCOEX_WL_SCANTIME (PROPRIETARY_TLV_BASE_ID + 203) +#define TLV_TYPE_BSS_MODE (PROPRIETARY_TLV_BASE_ID + 206) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -1434,6 +1435,11 @@ struct host_cmd_ds_802_11_scan_ext { u8 tlv_buffer[1]; } __packed; +struct mwifiex_ie_types_bss_mode { + struct mwifiex_ie_types_header header; + u8 bss_mode; +} __packed; + struct mwifiex_ie_types_bss_scan_rsp { struct mwifiex_ie_types_header header; u8 bssid[ETH_ALEN]; diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index baf9715ddc103..ef2bef8399c24 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -823,6 +823,7 @@ mwifiex_config_scan(struct mwifiex_private *priv, int i; u8 ssid_filter; struct mwifiex_ie_types_htcap *ht_cap; + struct mwifiex_ie_types_bss_mode *bss_mode; /* The tlv_buf_len is calculated for each scan command. The TLVs added in this routine will be preserved since the routine that sends the @@ -968,6 +969,15 @@ mwifiex_config_scan(struct mwifiex_private *priv, else *max_chan_per_scan = MWIFIEX_DEF_CHANNELS_PER_SCAN_CMD; + if (adapter->ext_scan) { + bss_mode = (struct mwifiex_ie_types_bss_mode *)tlv_pos; + bss_mode->header.type = cpu_to_le16(TLV_TYPE_BSS_MODE); + bss_mode->header.len = cpu_to_le16(sizeof(bss_mode->bss_mode)); + bss_mode->bss_mode = scan_cfg_out->bss_mode; + tlv_pos += sizeof(bss_mode->header) + + le16_to_cpu(bss_mode->header.len); + } + /* If the input config or adapter has the number of Probes set, add tlv */ if (num_probes) { -- GitLab From 0c6303cc06954c336a8221522e9ddf056125afab Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:05:22 -0700 Subject: [PATCH 1397/7006] mwifiex: use maximum ssid length as 0xfe for p2p 0xfe is basically a magic number used to ask firmware match provided string in a SSID. In this case, firmware will return scan results containing"DIRECT-" string. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/scan.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index ef2bef8399c24..ef8da8ebcbab4 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -909,6 +909,10 @@ mwifiex_config_scan(struct mwifiex_private *priv, wildcard_ssid_tlv->max_ssid_length = IEEE80211_MAX_SSID_LEN; + if (!memcmp(user_scan_in->ssid_list[i].ssid, + "DIRECT-", 7)) + wildcard_ssid_tlv->max_ssid_length = 0xfe; + memcpy(wildcard_ssid_tlv->ssid, user_scan_in->ssid_list[i].ssid, ssid_len); -- GitLab From e79801ffe9c862597750359b8c6825f3a3bfaa4f Mon Sep 17 00:00:00 2001 From: Aniket Nagarnaik Date: Thu, 16 Jul 2015 08:48:43 -0700 Subject: [PATCH 1398/7006] mwifiex: correct p2p and station interface counters While changing interface type from p2p client or p2p go to station, we should update counters for p2p interface and station interface. Also calling mwifiex_cfg80211_deinit_p2p method instead of mwifiex_cfg80211_init_p2p_client method to deinit p2p interface. Signed-off-by: Aniket Nagarnaik Signed-off-by: Amitkumar Karwar Signed-off-by: Kalle Valo --- drivers/net/wireless/mwifiex/cfg80211.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index d4b327752a5e2..ff63cb5632eb0 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -1145,8 +1145,10 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_P2P_GO: switch (type) { case NL80211_IFTYPE_STATION: - if (mwifiex_cfg80211_init_p2p_client(priv)) + if (mwifiex_cfg80211_deinit_p2p(priv)) return -EFAULT; + priv->adapter->curr_iface_comb.p2p_intf--; + priv->adapter->curr_iface_comb.sta_intf++; dev->ieee80211_ptr->iftype = type; break; case NL80211_IFTYPE_ADHOC: -- GitLab From 292c24a073ee34c629966eec8b48d54b0a206667 Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Mon, 20 Jul 2015 22:55:28 +0800 Subject: [PATCH 1399/7006] percpu: clean up of schunk->map[] assignment in pcpu_setup_first_chunk The original assignment is a little redundent. Signed-off-by: Baoquan He Acked-by: Christoph Lameter Signed-off-by: Tejun Heo --- mm/percpu.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm/percpu.c b/mm/percpu.c index 2dd74487a0aff..a63b4d82a1415 100644 --- a/mm/percpu.c +++ b/mm/percpu.c @@ -1668,9 +1668,8 @@ int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, schunk->map[1] = ai->static_size; schunk->map_used = 1; if (schunk->free_size) - schunk->map[++schunk->map_used] = 1 | (ai->static_size + schunk->free_size); - else - schunk->map[1] |= 1; + schunk->map[++schunk->map_used] = ai->static_size + schunk->free_size; + schunk->map[schunk->map_used] |= 1; /* init dynamic chunk if necessary */ if (dyn_size) { -- GitLab From 498c43949c7b8f57e0afb8195019cf5a7ba72de0 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Mon, 20 Jul 2015 10:14:08 -0600 Subject: [PATCH 1400/7006] NVMe: Unify SQ entry writing and doorbell ringing This patch changes sq_cmd writers to instead create their command on the stack. __nvme_submit_cmd copies the sq entry to the queue and writes the doorbell. Signed-off-by: Jon Derrick Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 80 +++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 45 deletions(-) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index d844ec4a2b85e..e09ad6cc6dec5 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -730,18 +730,16 @@ static int nvme_setup_prps(struct nvme_dev *dev, struct nvme_iod *iod, static void nvme_submit_priv(struct nvme_queue *nvmeq, struct request *req, struct nvme_iod *iod) { - struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + struct nvme_command cmnd; - memcpy(cmnd, req->cmd, sizeof(struct nvme_command)); - cmnd->rw.command_id = req->tag; + memcpy(&cmnd, req->cmd, sizeof(cmnd)); + cmnd.rw.command_id = req->tag; if (req->nr_phys_segments) { - cmnd->rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); - cmnd->rw.prp2 = cpu_to_le64(iod->first_dma); + cmnd.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); + cmnd.rw.prp2 = cpu_to_le64(iod->first_dma); } - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); } /* @@ -754,45 +752,41 @@ static void nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns, { struct nvme_dsm_range *range = (struct nvme_dsm_range *)iod_list(iod)[0]; - struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + struct nvme_command cmnd; range->cattr = cpu_to_le32(0); range->nlb = cpu_to_le32(blk_rq_bytes(req) >> ns->lba_shift); range->slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); - memset(cmnd, 0, sizeof(*cmnd)); - cmnd->dsm.opcode = nvme_cmd_dsm; - cmnd->dsm.command_id = req->tag; - cmnd->dsm.nsid = cpu_to_le32(ns->ns_id); - cmnd->dsm.prp1 = cpu_to_le64(iod->first_dma); - cmnd->dsm.nr = 0; - cmnd->dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); + memset(&cmnd, 0, sizeof(cmnd)); + cmnd.dsm.opcode = nvme_cmd_dsm; + cmnd.dsm.command_id = req->tag; + cmnd.dsm.nsid = cpu_to_le32(ns->ns_id); + cmnd.dsm.prp1 = cpu_to_le64(iod->first_dma); + cmnd.dsm.nr = 0; + cmnd.dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); } static void nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns, int cmdid) { - struct nvme_command *cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; + struct nvme_command cmnd; - memset(cmnd, 0, sizeof(*cmnd)); - cmnd->common.opcode = nvme_cmd_flush; - cmnd->common.command_id = cmdid; - cmnd->common.nsid = cpu_to_le32(ns->ns_id); + memset(&cmnd, 0, sizeof(cmnd)); + cmnd.common.opcode = nvme_cmd_flush; + cmnd.common.command_id = cmdid; + cmnd.common.nsid = cpu_to_le32(ns->ns_id); - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); } static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, struct nvme_ns *ns) { struct request *req = iod_get_private(iod); - struct nvme_command *cmnd; + struct nvme_command cmnd; u16 control = 0; u32 dsmgmt = 0; @@ -804,19 +798,17 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, if (req->cmd_flags & REQ_RAHEAD) dsmgmt |= NVME_RW_DSM_FREQ_PREFETCH; - cmnd = &nvmeq->sq_cmds[nvmeq->sq_tail]; - memset(cmnd, 0, sizeof(*cmnd)); - - cmnd->rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read); - cmnd->rw.command_id = req->tag; - cmnd->rw.nsid = cpu_to_le32(ns->ns_id); - cmnd->rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); - cmnd->rw.prp2 = cpu_to_le64(iod->first_dma); - cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); - cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); + memset(&cmnd, 0, sizeof(cmnd)); + cmnd.rw.opcode = (rq_data_dir(req) ? nvme_cmd_write : nvme_cmd_read); + cmnd.rw.command_id = req->tag; + cmnd.rw.nsid = cpu_to_le32(ns->ns_id); + cmnd.rw.prp1 = cpu_to_le64(sg_dma_address(iod->sg)); + cmnd.rw.prp2 = cpu_to_le64(iod->first_dma); + cmnd.rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); + cmnd.rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); if (blk_integrity_rq(req)) { - cmnd->rw.metadata = cpu_to_le64(sg_dma_address(iod->meta_sg)); + cmnd.rw.metadata = cpu_to_le64(sg_dma_address(iod->meta_sg)); switch (ns->pi_type) { case NVME_NS_DPS_PI_TYPE3: control |= NVME_RW_PRINFO_PRCHK_GUARD; @@ -825,19 +817,17 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, case NVME_NS_DPS_PI_TYPE2: control |= NVME_RW_PRINFO_PRCHK_GUARD | NVME_RW_PRINFO_PRCHK_REF; - cmnd->rw.reftag = cpu_to_le32( + cmnd.rw.reftag = cpu_to_le32( nvme_block_nr(ns, blk_rq_pos(req))); break; } } else if (ns->ms) control |= NVME_RW_PRINFO_PRACT; - cmnd->rw.control = cpu_to_le16(control); - cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt); + cmnd.rw.control = cpu_to_le16(control); + cmnd.rw.dsmgmt = cpu_to_le32(dsmgmt); - if (++nvmeq->sq_tail == nvmeq->q_depth) - nvmeq->sq_tail = 0; - writel(nvmeq->sq_tail, nvmeq->q_db); + __nvme_submit_cmd(nvmeq, &cmnd); return 0; } -- GitLab From 8ffaadf7429270914b8f146ec13cf305e01df20d Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Mon, 20 Jul 2015 10:14:09 -0600 Subject: [PATCH 1401/7006] NVMe: Use CMB for the IO SQes if available Some controllers have a controller-side memory buffer available for use for submissions, completions, lists, or data. If a CMB is available, the entire CMB will be ioremapped and it will attempt to map the IO SQes onto the CMB. The queues will be shrunk as needed. The CMB will not be used if the queue depth is shrunk below some threshold where it may have reduced performance over a larger queue in system memory. Signed-off-by: Jon Derrick Reviewed-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 122 ++++++++++++++++++++++++++++++++++++-- include/linux/nvme.h | 17 ++++++ 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index e09ad6cc6dec5..82b4ffb6eefa7 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -72,6 +72,10 @@ module_param(nvme_char_major, int, 0); static int use_threaded_interrupts; module_param(use_threaded_interrupts, int, 0); +static bool use_cmb_sqes = true; +module_param(use_cmb_sqes, bool, 0644); +MODULE_PARM_DESC(use_cmb_sqes, "use controller's memory buffer for I/O SQes"); + static DEFINE_SPINLOCK(dev_list_lock); static LIST_HEAD(dev_list); static struct task_struct *nvme_thread; @@ -103,6 +107,7 @@ struct nvme_queue { char irqname[24]; /* nvme4294967295-65535\0 */ spinlock_t q_lock; struct nvme_command *sq_cmds; + struct nvme_command __iomem *sq_cmds_io; volatile struct nvme_completion *cqes; struct blk_mq_tags **tags; dma_addr_t sq_dma_addr; @@ -383,7 +388,11 @@ static int __nvme_submit_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd) { u16 tail = nvmeq->sq_tail; - memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); + if (nvmeq->sq_cmds_io) + memcpy_toio(&nvmeq->sq_cmds_io[tail], cmd, sizeof(*cmd)); + else + memcpy(&nvmeq->sq_cmds[tail], cmd, sizeof(*cmd)); + if (++tail == nvmeq->q_depth) tail = 0; writel(tail, nvmeq->q_db); @@ -1364,7 +1373,8 @@ static void nvme_free_queue(struct nvme_queue *nvmeq) { dma_free_coherent(nvmeq->q_dmadev, CQ_SIZE(nvmeq->q_depth), (void *)nvmeq->cqes, nvmeq->cq_dma_addr); - dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), + if (nvmeq->sq_cmds) + dma_free_coherent(nvmeq->q_dmadev, SQ_SIZE(nvmeq->q_depth), nvmeq->sq_cmds, nvmeq->sq_dma_addr); kfree(nvmeq); } @@ -1437,6 +1447,46 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid) spin_unlock_irq(&nvmeq->q_lock); } +static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, + int entry_size) +{ + int q_depth = dev->q_depth; + unsigned q_size_aligned = roundup(q_depth * entry_size, dev->page_size); + + if (q_size_aligned * nr_io_queues > dev->cmb_size) { + q_depth = rounddown(dev->cmb_size / nr_io_queues, + dev->page_size) / entry_size; + + /* + * Ensure the reduced q_depth is above some threshold where it + * would be better to map queues in system memory with the + * original depth + */ + if (q_depth < 64) + return -ENOMEM; + } + + return q_depth; +} + +static int nvme_alloc_sq_cmds(struct nvme_dev *dev, struct nvme_queue *nvmeq, + int qid, int depth) +{ + if (qid && dev->cmb && use_cmb_sqes && NVME_CMB_SQS(dev->cmbsz)) { + unsigned offset = (qid - 1) * + roundup(SQ_SIZE(depth), dev->page_size); + nvmeq->sq_dma_addr = dev->cmb_dma_addr + offset; + nvmeq->sq_cmds_io = dev->cmb + offset; + } else { + nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), + &nvmeq->sq_dma_addr, GFP_KERNEL); + if (!nvmeq->sq_cmds) + return -ENOMEM; + } + + return 0; +} + static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, int depth) { @@ -1449,9 +1499,7 @@ static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid, if (!nvmeq->cqes) goto free_nvmeq; - nvmeq->sq_cmds = dma_alloc_coherent(dev->dev, SQ_SIZE(depth), - &nvmeq->sq_dma_addr, GFP_KERNEL); - if (!nvmeq->sq_cmds) + if (nvme_alloc_sq_cmds(dev, nvmeq, qid, depth)) goto free_cqdma; nvmeq->q_dmadev = dev->dev; @@ -2149,6 +2197,58 @@ static int set_queue_count(struct nvme_dev *dev, int count) return min(result & 0xffff, result >> 16) + 1; } +static void __iomem *nvme_map_cmb(struct nvme_dev *dev) +{ + u64 szu, size, offset; + u32 cmbloc; + resource_size_t bar_size; + struct pci_dev *pdev = to_pci_dev(dev->dev); + void __iomem *cmb; + dma_addr_t dma_addr; + + if (!use_cmb_sqes) + return NULL; + + dev->cmbsz = readl(&dev->bar->cmbsz); + if (!(NVME_CMB_SZ(dev->cmbsz))) + return NULL; + + cmbloc = readl(&dev->bar->cmbloc); + + szu = (u64)1 << (12 + 4 * NVME_CMB_SZU(dev->cmbsz)); + size = szu * NVME_CMB_SZ(dev->cmbsz); + offset = szu * NVME_CMB_OFST(cmbloc); + bar_size = pci_resource_len(pdev, NVME_CMB_BIR(cmbloc)); + + if (offset > bar_size) + return NULL; + + /* + * Controllers may support a CMB size larger than their BAR, + * for example, due to being behind a bridge. Reduce the CMB to + * the reported size of the BAR + */ + if (size > bar_size - offset) + size = bar_size - offset; + + dma_addr = pci_resource_start(pdev, NVME_CMB_BIR(cmbloc)) + offset; + cmb = ioremap_wc(dma_addr, size); + if (!cmb) + return NULL; + + dev->cmb_dma_addr = dma_addr; + dev->cmb_size = size; + return cmb; +} + +static inline void nvme_release_cmb(struct nvme_dev *dev) +{ + if (dev->cmb) { + iounmap(dev->cmb); + dev->cmb = NULL; + } +} + static size_t db_bar_size(struct nvme_dev *dev, unsigned nr_io_queues) { return 4096 + ((nr_io_queues + 1) * 8 * dev->db_stride); @@ -2167,6 +2267,15 @@ static int nvme_setup_io_queues(struct nvme_dev *dev) if (result < nr_io_queues) nr_io_queues = result; + if (dev->cmb && NVME_CMB_SQS(dev->cmbsz)) { + result = nvme_cmb_qdepth(dev, nr_io_queues, + sizeof(struct nvme_command)); + if (result > 0) + dev->q_depth = result; + else + nvme_release_cmb(dev); + } + size = db_bar_size(dev, nr_io_queues); if (size > 8192) { iounmap(dev->bar); @@ -2430,6 +2539,8 @@ static int nvme_dev_map(struct nvme_dev *dev) dev->q_depth = min_t(int, NVME_CAP_MQES(cap) + 1, NVME_Q_DEPTH); dev->db_stride = 1 << NVME_CAP_STRIDE(cap); dev->dbs = ((void __iomem *)dev->bar) + 4096; + if (readl(&dev->bar->vs) >= NVME_VS(1, 2)) + dev->cmb = nvme_map_cmb(dev); return 0; @@ -3135,6 +3246,7 @@ static void nvme_remove(struct pci_dev *pdev) nvme_dev_remove_admin(dev); device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance)); nvme_free_queues(dev, 0); + nvme_release_cmb(dev); nvme_release_prp_pools(dev); kref_put(&dev->kref, nvme_free_dev); } diff --git a/include/linux/nvme.h b/include/linux/nvme.h index c0d94ed8ce9aa..fa3fe160c6cbc 100644 --- a/include/linux/nvme.h +++ b/include/linux/nvme.h @@ -32,6 +32,8 @@ struct nvme_bar { __u32 aqa; /* Admin Queue Attributes */ __u64 asq; /* Admin SQ Base Address */ __u64 acq; /* Admin CQ Base Address */ + __u32 cmbloc; /* Controller Memory Buffer Location */ + __u32 cmbsz; /* Controller Memory Buffer Size */ }; #define NVME_CAP_MQES(cap) ((cap) & 0xffff) @@ -40,6 +42,17 @@ struct nvme_bar { #define NVME_CAP_MPSMIN(cap) (((cap) >> 48) & 0xf) #define NVME_CAP_MPSMAX(cap) (((cap) >> 52) & 0xf) +#define NVME_CMB_BIR(cmbloc) ((cmbloc) & 0x7) +#define NVME_CMB_OFST(cmbloc) (((cmbloc) >> 12) & 0xfffff) +#define NVME_CMB_SZ(cmbsz) (((cmbsz) >> 12) & 0xfffff) +#define NVME_CMB_SZU(cmbsz) (((cmbsz) >> 8) & 0xf) + +#define NVME_CMB_WDS(cmbsz) ((cmbsz) & 0x10) +#define NVME_CMB_RDS(cmbsz) ((cmbsz) & 0x8) +#define NVME_CMB_LISTS(cmbsz) ((cmbsz) & 0x4) +#define NVME_CMB_CQS(cmbsz) ((cmbsz) & 0x2) +#define NVME_CMB_SQS(cmbsz) ((cmbsz) & 0x1) + enum { NVME_CC_ENABLE = 1 << 0, NVME_CC_CSS_NVM = 0 << 4, @@ -100,6 +113,10 @@ struct nvme_dev { u32 max_hw_sectors; u32 stripe_size; u32 page_size; + void __iomem *cmb; + dma_addr_t cmb_dma_addr; + u64 cmb_size; + u32 cmbsz; u16 oncs; u16 abort_limit; u8 event_limit; -- GitLab From 43163022927b6e7d202a7e6f939c3f392465494d Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 19 May 2015 14:38:22 -0700 Subject: [PATCH 1402/7006] mtd: m25p80: allow arbitrary OF matching for "jedec,spi-nor" When we added the "jedec,spi-nor" compatible string for use in this driver, we added it as a modalias option. The modalias can be derived in different ways for platform devices vs. device tree (of_*) matching. But for device tree matching (the primary target of this identifier string), the modalias is determined from the first entry in the 'compatible' property. IOW, the following properties would bind to this driver: // Option (a), modalias = "spi-nor" compatible = "jedec,spi-nor"; // Option (b), modalias = "spi-nor" compatible = "idontknowwhatimdoing,spi-nor"; But the following would not: // Option (c), modalias = "shinynewdevice" compatible = "myvendor,shinynewdevice", "jedec,spi-nor"; So, we'd like to match (a) and (c) (even when we don't have an explicit entry for "shinynewdevice"), and we'd rather not allow (b). To do this, we (1) always (for devices without specific platform data) pass the modalias to the spi-nor library; (2) rework the spi-nor library to not reject "bad" names, and instead just fall back to autodetection; and (3) add the .of_match_table to properly catch all "jedec,spi-nor". This allows (a) and (c) without warnings, and rejects (b). Signed-off-by: Brian Norris --- drivers/mtd/devices/m25p80.c | 18 +++++++++++------- drivers/mtd/spi-nor/spi-nor.c | 8 ++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index d313f948b96c6..9cd3631170ef8 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -223,8 +223,6 @@ static int m25p_probe(struct spi_device *spi) */ if (data && data->type) flash_name = data->type; - else if (!strcmp(spi->modalias, "spi-nor")) - flash_name = NULL; /* auto-detect */ else flash_name = spi->modalias; @@ -289,19 +287,25 @@ static const struct spi_device_id m25p_ids[] = { {"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"}, {"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"}, - /* - * Generic support for SPI NOR that can be identified by the JEDEC READ - * ID opcode (0x9F). Use this, if possible. - */ - {"spi-nor"}, { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); +static const struct of_device_id m25p_of_table[] = { + /* + * Generic compatibility for SPI NOR that can be identified by the + * JEDEC READ ID opcode (0x9F). Use this, if possible. + */ + { .compatible = "jedec,spi-nor" }, + {} +}; +MODULE_DEVICE_TABLE(of, m25p_of_table); + static struct spi_driver m25p80_driver = { .driver = { .name = "m25p80", .owner = THIS_MODULE, + .of_match_table = m25p_of_table, }, .id_table = m25p_ids, .probe = m25p_probe, diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b2e8c3b72ea13..47516d3af0156 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1015,11 +1015,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) if (ret) return ret; - /* Try to auto-detect if chip name wasn't specified */ - if (!name) - id = spi_nor_read_id(nor); - else + if (name) id = spi_nor_match_id(name); + /* Try to auto-detect if chip name wasn't specified or not found */ + if (!id) + id = spi_nor_read_id(nor); if (IS_ERR_OR_NULL(id)) return -ENOENT; -- GitLab From c4a42915d84ad4b5b5e13aeed5da67f458e22399 Mon Sep 17 00:00:00 2001 From: Jean-Francois Moine Date: Tue, 21 Jul 2015 18:32:58 +0200 Subject: [PATCH 1403/7006] ASoC: kirkwood: prevent double streaming The kirkwood audio subsystem presents 2 PCM's for one source. Streaming on a second PCM while the first one is active cuts this last one. Then, ending the last stream gives a kernel trap in free_irq(). Signed-off-by: Jean-Francois Moine Signed-off-by: Mark Brown --- sound/soc/kirkwood/kirkwood-dma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sound/soc/kirkwood/kirkwood-dma.c b/sound/soc/kirkwood/kirkwood-dma.c index 4cf2245950d79..dbfdfe99c69df 100644 --- a/sound/soc/kirkwood/kirkwood-dma.c +++ b/sound/soc/kirkwood/kirkwood-dma.c @@ -148,10 +148,14 @@ static int kirkwood_dma_open(struct snd_pcm_substream *substream) dram = mv_mbus_dram_info(); addr = substream->dma_buffer.addr; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + if (priv->substream_play) + return -EBUSY; priv->substream_play = substream; kirkwood_dma_conf_mbus_windows(priv->io, KIRKWOOD_PLAYBACK_WIN, addr, dram); } else { + if (priv->substream_rec) + return -EBUSY; priv->substream_rec = substream; kirkwood_dma_conf_mbus_windows(priv->io, KIRKWOOD_RECORD_WIN, addr, dram); -- GitLab From b97e26980f6c13afad4c249b60a8dca7f5f86116 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 18:11:07 +0200 Subject: [PATCH 1404/7006] ASoC: dapm: Add helper function to free a widget snd_soc_tplg_widget_remove_all() has a verbatim copy of an older version of the widget freeing code from dapm_free_widgets(). Add a new helper function that takes care of freeing a widget and use it in both places. This removes the duplicated code and also makes sure that future changes to the widget freeing code only have to be made in one location. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + sound/soc/soc-dapm.c | 38 ++++++++++++++++++++++---------------- sound/soc/soc-topology.c | 25 +------------------------ 3 files changed, 24 insertions(+), 40 deletions(-) diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 37d95a8982759..cadc7fc5d7277 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -397,6 +397,7 @@ int snd_soc_dapm_del_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); int snd_soc_dapm_weak_routes(struct snd_soc_dapm_context *dapm, const struct snd_soc_dapm_route *route, int num); +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w); /* dapm events */ void snd_soc_dapm_stream_event(struct snd_soc_pcm_runtime *rtd, int stream, diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index e0de8072c5144..24ea692bd49ee 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2312,30 +2312,36 @@ static void dapm_free_path(struct snd_soc_dapm_path *path) kfree(path); } +void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_dapm_path *p, *next_p; + + list_del(&w->list); + /* + * remove source and sink paths associated to this widget. + * While removing the path, remove reference to it from both + * source and sink widgets so that path is removed only once. + */ + list_for_each_entry_safe(p, next_p, &w->sources, list_sink) + dapm_free_path(p); + + list_for_each_entry_safe(p, next_p, &w->sinks, list_source) + dapm_free_path(p); + + kfree(w->kcontrols); + kfree(w->name); + kfree(w); +} + /* free all dapm widgets and resources */ static void dapm_free_widgets(struct snd_soc_dapm_context *dapm) { struct snd_soc_dapm_widget *w, *next_w; - struct snd_soc_dapm_path *p, *next_p; list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { if (w->dapm != dapm) continue; - list_del(&w->list); - /* - * remove source and sink paths associated to this widget. - * While removing the path, remove reference to it from both - * source and sink widgets so that path is removed only once. - */ - list_for_each_entry_safe(p, next_p, &w->sources, list_sink) - dapm_free_path(p); - - list_for_each_entry_safe(p, next_p, &w->sinks, list_source) - dapm_free_path(p); - - kfree(w->kcontrols); - kfree(w->name); - kfree(w); + snd_soc_dapm_free_widget(w); } } diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c index d0960683c4093..56dd108d6f5fc 100644 --- a/sound/soc/soc-topology.c +++ b/sound/soc/soc-topology.c @@ -1734,7 +1734,6 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, u32 index) { struct snd_soc_dapm_widget *w, *next_w; - struct snd_soc_dapm_path *p, *next_p; list_for_each_entry_safe(w, next_w, &dapm->card->widgets, list) { @@ -1746,31 +1745,9 @@ void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm, if (w->dobj.index != index && w->dobj.index != SND_SOC_TPLG_INDEX_ALL) continue; - - list_del(&w->list); - - /* - * remove source and sink paths associated to this widget. - * While removing the path, remove reference to it from both - * source and sink widgets so that path is removed only once. - */ - list_for_each_entry_safe(p, next_p, &w->sources, list_sink) { - list_del(&p->list_sink); - list_del(&p->list_source); - list_del(&p->list); - kfree(p); - } - list_for_each_entry_safe(p, next_p, &w->sinks, list_source) { - list_del(&p->list_sink); - list_del(&p->list_source); - list_del(&p->list); - kfree(p); - } /* check and free and dynamic widget kcontrols */ snd_soc_tplg_widget_remove(w); - kfree(w->kcontrols); - kfree(w->name); - kfree(w); + snd_soc_dapm_free_widget(w); } } EXPORT_SYMBOL_GPL(snd_soc_tplg_widget_remove_all); -- GitLab From 480689617510381391b3d906549477b948d9c4bc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 18:11:08 +0200 Subject: [PATCH 1405/7006] ASoC: dapm: Avoid duplicating immutable strings When creating a new widget from a template the name string of the template is duplicated for the newly created widget. This is necessary because in some cases the string might be stored on the stack or other volatile memory locations. But most of the time the string is static const data, which means it is possible to use it directly without having to worry that it might get freed or changed. Use kstrdup_const() to handle duplicating the string. This function is capable of detecting whether a string is immutable and if it is returns the input without duplicating it. This will slightly reduce the runtime memory footprint of DAPM and also speed up initialization. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-dapm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index 24ea692bd49ee..cb4bc1cd50492 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2329,7 +2329,7 @@ void snd_soc_dapm_free_widget(struct snd_soc_dapm_widget *w) dapm_free_path(p); kfree(w->kcontrols); - kfree(w->name); + kfree_const(w->name); kfree(w); } @@ -3350,7 +3350,7 @@ snd_soc_dapm_new_control_unlocked(struct snd_soc_dapm_context *dapm, if (prefix) w->name = kasprintf(GFP_KERNEL, "%s %s", prefix, widget->name); else - w->name = kasprintf(GFP_KERNEL, "%s", widget->name); + w->name = kstrdup_const(widget->name, GFP_KERNEL); if (w->name == NULL) { kfree(w); return NULL; -- GitLab From a0d9a8604f29ee3340126ec3f90c9421f930aa50 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:45 +0200 Subject: [PATCH 1406/7006] rtnetlink: introduce new RTA_ENCAP_TYPE and RTA_ENCAP attributes This patch introduces two new RTA attributes to attach encap data to fib routes. Example iproute2 command to attach mpls encap data to ipv4 routes $ip route add 10.1.1.0/30 encap mpls 200 via inet 10.1.1.1 dev swp1 Signed-off-by: Roopa Prabhu Suggested-by: Eric W. Biederman Signed-off-by: David S. Miller --- include/uapi/linux/rtnetlink.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index fdd8f07f1d34b..0d3d3cc43356e 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -308,6 +308,8 @@ enum rtattr_type_t { RTA_VIA, RTA_NEWDST, RTA_PREF, + RTA_ENCAP_TYPE, + RTA_ENCAP, __RTA_MAX }; -- GitLab From 499a24256862714539e902c0499b67da2bb3ab72 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:46 +0200 Subject: [PATCH 1407/7006] lwtunnel: infrastructure for handling light weight tunnels like mpls Provides infrastructure to parse/dump/store encap information for light weight tunnels like mpls. Encap information for such tunnels is associated with fib routes. This infrastructure is based on previous suggestions from Eric Biederman to follow the xfrm infrastructure. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/linux/lwtunnel.h | 6 ++ include/net/lwtunnel.h | 132 +++++++++++++++++++++++++ include/uapi/linux/lwtunnel.h | 15 +++ net/Kconfig | 7 ++ net/core/Makefile | 1 + net/core/lwtunnel.c | 179 ++++++++++++++++++++++++++++++++++ 6 files changed, 340 insertions(+) create mode 100644 include/linux/lwtunnel.h create mode 100644 include/net/lwtunnel.h create mode 100644 include/uapi/linux/lwtunnel.h create mode 100644 net/core/lwtunnel.c diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h new file mode 100644 index 0000000000000..97f32f8b4ae13 --- /dev/null +++ b/include/linux/lwtunnel.h @@ -0,0 +1,6 @@ +#ifndef _LINUX_LWTUNNEL_H_ +#define _LINUX_LWTUNNEL_H_ + +#include + +#endif /* _LINUX_LWTUNNEL_H_ */ diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h new file mode 100644 index 0000000000000..df24b3611ff49 --- /dev/null +++ b/include/net/lwtunnel.h @@ -0,0 +1,132 @@ +#ifndef __NET_LWTUNNEL_H +#define __NET_LWTUNNEL_H 1 + +#include +#include +#include +#include +#include + +#define LWTUNNEL_HASH_BITS 7 +#define LWTUNNEL_HASH_SIZE (1 << LWTUNNEL_HASH_BITS) + +/* lw tunnel state flags */ +#define LWTUNNEL_STATE_OUTPUT_REDIRECT 0x1 + +struct lwtunnel_state { + __u16 type; + __u16 flags; + atomic_t refcnt; + int len; + __u8 data[0]; +}; + +struct lwtunnel_encap_ops { + int (*build_state)(struct net_device *dev, struct nlattr *encap, + struct lwtunnel_state **ts); + int (*output)(struct sock *sk, struct sk_buff *skb); + int (*fill_encap)(struct sk_buff *skb, + struct lwtunnel_state *lwtstate); + int (*get_encap_size)(struct lwtunnel_state *lwtstate); + int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b); +}; + +extern const struct lwtunnel_encap_ops __rcu * + lwtun_encaps[LWTUNNEL_ENCAP_MAX+1]; + +#ifdef CONFIG_LWTUNNEL +static inline void lwtunnel_state_get(struct lwtunnel_state *lws) +{ + atomic_inc(&lws->refcnt); +} + +static inline void lwtunnel_state_put(struct lwtunnel_state *lws) +{ + if (!lws) + return; + + if (atomic_dec_and_test(&lws->refcnt)) + kfree(lws); +} + +static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate) +{ + if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_OUTPUT_REDIRECT)) + return true; + + return false; +} + +int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, + unsigned int num); +int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, + unsigned int num); +int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, + struct lwtunnel_state **lws); +int lwtunnel_fill_encap(struct sk_buff *skb, + struct lwtunnel_state *lwtstate); +int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate); +struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len); +int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b); + +#else + +static inline void lwtunnel_state_get(struct lwtunnel_state *lws) +{ +} + +static inline void lwtunnel_state_put(struct lwtunnel_state *lws) +{ +} + +static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate) +{ + return false; +} + +static inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, + unsigned int num) +{ + return -EOPNOTSUPP; + +} + +static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, + unsigned int num) +{ + return -EOPNOTSUPP; +} + +static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, + struct lwtunnel_state **lws) +{ + return -EOPNOTSUPP; +} + +static inline int lwtunnel_fill_encap(struct sk_buff *skb, + struct lwtunnel_state *lwtstate) +{ + return 0; +} + +static inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate) +{ + return 0; +} + +static inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len) +{ + return NULL; +} + +static inline int lwtunnel_cmp_encap(struct lwtunnel_state *a, + struct lwtunnel_state *b) +{ + return 0; +} + +#endif + +#endif /* __NET_LWTUNNEL_H */ diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h new file mode 100644 index 0000000000000..aa611d931a313 --- /dev/null +++ b/include/uapi/linux/lwtunnel.h @@ -0,0 +1,15 @@ +#ifndef _UAPI_LWTUNNEL_H_ +#define _UAPI_LWTUNNEL_H_ + +#include + +enum lwtunnel_encap_types { + LWTUNNEL_ENCAP_NONE, + LWTUNNEL_ENCAP_MPLS, + __LWTUNNEL_ENCAP_MAX, +}; + +#define LWTUNNEL_ENCAP_MAX (__LWTUNNEL_ENCAP_MAX - 1) + + +#endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/net/Kconfig b/net/Kconfig index 57a7c5af3175d..7021c1bf44d6c 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -374,6 +374,13 @@ source "net/caif/Kconfig" source "net/ceph/Kconfig" source "net/nfc/Kconfig" +config LWTUNNEL + bool "Network light weight tunnels" + ---help--- + This feature provides an infrastructure to support light weight + tunnels like mpls. There is no netdevice associated with a light + weight tunnel endpoint. Tunnel encapsulation parameters are stored + with light weight tunnel state associated with fib routes. endif # if NET diff --git a/net/core/Makefile b/net/core/Makefile index fec0856dd6c03..086b01fbe1bd8 100644 --- a/net/core/Makefile +++ b/net/core/Makefile @@ -23,3 +23,4 @@ obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o +obj-$(CONFIG_LWTUNNEL) += lwtunnel.o diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c new file mode 100644 index 0000000000000..d7ae3a235b4b0 --- /dev/null +++ b/net/core/lwtunnel.c @@ -0,0 +1,179 @@ +/* + * lwtunnel Infrastructure for light weight tunnels like mpls + * + * Authors: Roopa Prabhu, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +struct lwtunnel_state *lwtunnel_state_alloc(int encap_len) +{ + struct lwtunnel_state *lws; + + lws = kzalloc(sizeof(*lws) + encap_len, GFP_ATOMIC); + + return lws; +} +EXPORT_SYMBOL(lwtunnel_state_alloc); + +const struct lwtunnel_encap_ops __rcu * + lwtun_encaps[LWTUNNEL_ENCAP_MAX + 1] __read_mostly; + +int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *ops, + unsigned int num) +{ + if (num > LWTUNNEL_ENCAP_MAX) + return -ERANGE; + + return !cmpxchg((const struct lwtunnel_encap_ops **) + &lwtun_encaps[num], + NULL, ops) ? 0 : -1; +} +EXPORT_SYMBOL(lwtunnel_encap_add_ops); + +int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops, + unsigned int encap_type) +{ + int ret; + + if (encap_type == LWTUNNEL_ENCAP_NONE || + encap_type > LWTUNNEL_ENCAP_MAX) + return -ERANGE; + + ret = (cmpxchg((const struct lwtunnel_encap_ops **) + &lwtun_encaps[encap_type], + ops, NULL) == ops) ? 0 : -1; + + synchronize_net(); + + return ret; +} +EXPORT_SYMBOL(lwtunnel_encap_del_ops); + +int lwtunnel_build_state(struct net_device *dev, u16 encap_type, + struct nlattr *encap, struct lwtunnel_state **lws) +{ + const struct lwtunnel_encap_ops *ops; + int ret = -EINVAL; + + if (encap_type == LWTUNNEL_ENCAP_NONE || + encap_type > LWTUNNEL_ENCAP_MAX) + return ret; + + ret = -EOPNOTSUPP; + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[encap_type]); + if (likely(ops && ops->build_state)) + ret = ops->build_state(dev, encap, lws); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(lwtunnel_build_state); + +int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate) +{ + const struct lwtunnel_encap_ops *ops; + struct nlattr *nest; + int ret = -EINVAL; + + if (!lwtstate) + return 0; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || + lwtstate->type > LWTUNNEL_ENCAP_MAX) + return 0; + + ret = -EOPNOTSUPP; + nest = nla_nest_start(skb, RTA_ENCAP); + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[lwtstate->type]); + if (likely(ops && ops->fill_encap)) + ret = ops->fill_encap(skb, lwtstate); + rcu_read_unlock(); + + if (ret) + goto nla_put_failure; + nla_nest_end(skb, nest); + ret = nla_put_u16(skb, RTA_ENCAP_TYPE, lwtstate->type); + if (ret) + goto nla_put_failure; + + return 0; + +nla_put_failure: + nla_nest_cancel(skb, nest); + + return (ret == -EOPNOTSUPP ? 0 : ret); +} +EXPORT_SYMBOL(lwtunnel_fill_encap); + +int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate) +{ + const struct lwtunnel_encap_ops *ops; + int ret = 0; + + if (!lwtstate) + return 0; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || + lwtstate->type > LWTUNNEL_ENCAP_MAX) + return 0; + + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[lwtstate->type]); + if (likely(ops && ops->get_encap_size)) + ret = nla_total_size(ops->get_encap_size(lwtstate)); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(lwtunnel_get_encap_size); + +int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) +{ + const struct lwtunnel_encap_ops *ops; + int ret = 0; + + if (!a && !b) + return 0; + + if (!a || !b) + return 1; + + if (a->type != b->type) + return 1; + + if (a->type == LWTUNNEL_ENCAP_NONE || + a->type > LWTUNNEL_ENCAP_MAX) + return 0; + + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[a->type]); + if (likely(ops && ops->cmp_encap)) + ret = ops->cmp_encap(a, b); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(lwtunnel_cmp_encap); -- GitLab From 571e722676fe386bb66f72a75b64a6ebf535c077 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:47 +0200 Subject: [PATCH 1408/7006] ipv4: support for fib route lwtunnel encap attributes This patch adds support in ipv4 fib functions to parse user provided encap attributes and attach encap state data to fib_nh and rtable. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/net/ip_fib.h | 5 ++- include/net/route.h | 1 + net/ipv4/fib_frontend.c | 8 ++++ net/ipv4/fib_semantics.c | 96 +++++++++++++++++++++++++++++++++++++++- net/ipv4/route.c | 16 ++++++- 5 files changed, 122 insertions(+), 4 deletions(-) diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h index 49c142bdf01e6..5e0196084f1e8 100644 --- a/include/net/ip_fib.h +++ b/include/net/ip_fib.h @@ -44,7 +44,9 @@ struct fib_config { u32 fc_flow; u32 fc_nlflags; struct nl_info fc_nlinfo; - }; + struct nlattr *fc_encap; + u16 fc_encap_type; +}; struct fib_info; struct rtable; @@ -89,6 +91,7 @@ struct fib_nh { struct rtable __rcu * __percpu *nh_pcpu_rth_output; struct rtable __rcu *nh_rth_input; struct fnhe_hash_bucket __rcu *nh_exceptions; + struct lwtunnel_state *nh_lwtstate; }; /* diff --git a/include/net/route.h b/include/net/route.h index fe22d03afb6a2..2d45f419477fe 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -66,6 +66,7 @@ struct rtable { struct list_head rt_uncached; struct uncached_list *rt_uncached_list; + struct lwtunnel_state *rt_lwtstate; }; static inline bool rt_is_input_route(const struct rtable *rt) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 6bbc54940eb4e..9b2019cc35860 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -591,6 +591,8 @@ const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = { [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, [RTA_FLOW] = { .type = NLA_U32 }, + [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, + [RTA_ENCAP] = { .type = NLA_NESTED }, }; static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, @@ -656,6 +658,12 @@ static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, case RTA_TABLE: cfg->fc_table = nla_get_u32(attr); break; + case RTA_ENCAP: + cfg->fc_encap = attr; + break; + case RTA_ENCAP_TYPE: + cfg->fc_encap_type = nla_get_u16(attr); + break; } } diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index c7358ea4ae935..6754c64b2fe00 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -42,6 +42,7 @@ #include #include #include +#include #include "fib_lookup.h" @@ -208,6 +209,7 @@ static void free_fib_info_rcu(struct rcu_head *head) change_nexthops(fi) { if (nexthop_nh->nh_dev) dev_put(nexthop_nh->nh_dev); + lwtunnel_state_put(nexthop_nh->nh_lwtstate); free_nh_exceptions(nexthop_nh); rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); rt_fibinfo_free(&nexthop_nh->nh_rth_input); @@ -266,6 +268,7 @@ static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi) #ifdef CONFIG_IP_ROUTE_CLASSID nh->nh_tclassid != onh->nh_tclassid || #endif + lwtunnel_cmp_encap(nh->nh_lwtstate, onh->nh_lwtstate) || ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK)) return -1; onh++; @@ -366,6 +369,7 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi) payload += nla_total_size((RTAX_MAX * nla_total_size(4))); if (fi->fib_nhs) { + size_t nh_encapsize = 0; /* Also handles the special case fib_nhs == 1 */ /* each nexthop is packed in an attribute */ @@ -374,8 +378,21 @@ static inline size_t fib_nlmsg_size(struct fib_info *fi) /* may contain flow and gateway attribute */ nhsize += 2 * nla_total_size(4); + /* grab encap info */ + for_nexthops(fi) { + if (nh->nh_lwtstate) { + /* RTA_ENCAP_TYPE */ + nh_encapsize += lwtunnel_get_encap_size( + nh->nh_lwtstate); + /* RTA_ENCAP */ + nh_encapsize += nla_total_size(2); + } + } endfor_nexthops(fi); + /* all nexthops are packed in a nested attribute */ - payload += nla_total_size(fi->fib_nhs * nhsize); + payload += nla_total_size((fi->fib_nhs * nhsize) + + nh_encapsize); + } return payload; @@ -452,6 +469,9 @@ static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining) static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, int remaining, struct fib_config *cfg) { + struct net *net = cfg->fc_nlinfo.nl_net; + int ret; + change_nexthops(fi) { int attrlen; @@ -475,18 +495,66 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, if (nexthop_nh->nh_tclassid) fi->fib_net->ipv4.fib_num_tclassid_users++; #endif + nla = nla_find(attrs, attrlen, RTA_ENCAP); + if (nla) { + struct lwtunnel_state *lwtstate; + struct net_device *dev = NULL; + struct nlattr *nla_entype; + + nla_entype = nla_find(attrs, attrlen, + RTA_ENCAP_TYPE); + if (!nla_entype) + goto err_inval; + if (cfg->fc_oif) + dev = __dev_get_by_index(net, cfg->fc_oif); + ret = lwtunnel_build_state(dev, nla_get_u16( + nla_entype), + nla, &lwtstate); + if (ret) + goto errout; + lwtunnel_state_get(lwtstate); + nexthop_nh->nh_lwtstate = lwtstate; + } } rtnh = rtnh_next(rtnh, &remaining); } endfor_nexthops(fi); return 0; + +err_inval: + ret = -EINVAL; + +errout: + return ret; } #endif +int fib_encap_match(struct net *net, u16 encap_type, + struct nlattr *encap, + int oif, const struct fib_nh *nh) +{ + struct lwtunnel_state *lwtstate; + struct net_device *dev = NULL; + int ret; + + if (encap_type == LWTUNNEL_ENCAP_NONE) + return 0; + + if (oif) + dev = __dev_get_by_index(net, oif); + ret = lwtunnel_build_state(dev, encap_type, + encap, &lwtstate); + if (!ret) + return lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate); + + return 0; +} + int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) { + struct net *net = cfg->fc_nlinfo.nl_net; #ifdef CONFIG_IP_ROUTE_MULTIPATH struct rtnexthop *rtnh; int remaining; @@ -496,6 +564,12 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) return 1; if (cfg->fc_oif || cfg->fc_gw) { + if (cfg->fc_encap) { + if (fib_encap_match(net, cfg->fc_encap_type, + cfg->fc_encap, cfg->fc_oif, + fi->fib_nh)) + return 1; + } if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) return 0; @@ -882,6 +956,22 @@ struct fib_info *fib_create_info(struct fib_config *cfg) } else { struct fib_nh *nh = fi->fib_nh; + if (cfg->fc_encap) { + struct lwtunnel_state *lwtstate; + struct net_device *dev = NULL; + + if (cfg->fc_encap_type == LWTUNNEL_ENCAP_NONE) + goto err_inval; + if (cfg->fc_oif) + dev = __dev_get_by_index(net, cfg->fc_oif); + err = lwtunnel_build_state(dev, cfg->fc_encap_type, + cfg->fc_encap, &lwtstate); + if (err) + goto failure; + + lwtunnel_state_get(lwtstate); + nh->nh_lwtstate = lwtstate; + } nh->nh_oif = cfg->fc_oif; nh->nh_gw = cfg->fc_gw; nh->nh_flags = cfg->fc_flags; @@ -1055,6 +1145,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) goto nla_put_failure; #endif + if (fi->fib_nh->nh_lwtstate) + lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate); } #ifdef CONFIG_IP_ROUTE_MULTIPATH if (fi->fib_nhs > 1) { @@ -1090,6 +1182,8 @@ int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) goto nla_put_failure; #endif + if (nh->nh_lwtstate) + lwtunnel_fill_encap(skb, nh->nh_lwtstate); /* length of rtnetlink header + attributes */ rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; } endfor_nexthops(fi); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 04c83de4f79e3..226570ba1cedb 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -102,6 +102,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_SYSCTL @@ -1355,6 +1356,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst) list_del(&rt->rt_uncached); spin_unlock_bh(&ul->lock); } + lwtunnel_state_put(rt->rt_lwtstate); } void rt_flush_dev(struct net_device *dev) @@ -1403,6 +1405,12 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr, #ifdef CONFIG_IP_ROUTE_CLASSID rt->dst.tclassid = nh->nh_tclassid; #endif + if (nh->nh_lwtstate) { + lwtunnel_state_get(nh->nh_lwtstate); + rt->rt_lwtstate = nh->nh_lwtstate; + } else { + rt->rt_lwtstate = NULL; + } if (unlikely(fnhe)) cached = rt_bind_exception(rt, fnhe, daddr); else if (!(rt->dst.flags & DST_NOCACHE)) @@ -1488,6 +1496,7 @@ static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, rth->rt_gateway = 0; rth->rt_uses_gateway = 0; INIT_LIST_HEAD(&rth->rt_uncached); + rth->rt_lwtstate = NULL; if (our) { rth->dst.input= ip_local_deliver; rth->rt_flags |= RTCF_LOCAL; @@ -1617,6 +1626,7 @@ static int __mkroute_input(struct sk_buff *skb, rth->rt_gateway = 0; rth->rt_uses_gateway = 0; INIT_LIST_HEAD(&rth->rt_uncached); + rth->rt_lwtstate = NULL; RT_CACHE_STAT_INC(in_slow_tot); rth->dst.input = ip_forward; @@ -1791,6 +1801,8 @@ local_input: rth->rt_gateway = 0; rth->rt_uses_gateway = 0; INIT_LIST_HEAD(&rth->rt_uncached); + rth->rt_lwtstate = NULL; + RT_CACHE_STAT_INC(in_slow_tot); if (res.type == RTN_UNREACHABLE) { rth->dst.input= ip_error; @@ -1980,7 +1992,7 @@ add: rth->rt_gateway = 0; rth->rt_uses_gateway = 0; INIT_LIST_HEAD(&rth->rt_uncached); - + rth->rt_lwtstate = NULL; RT_CACHE_STAT_INC(out_slow_tot); if (flags & RTCF_LOCAL) @@ -2260,7 +2272,7 @@ struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_or rt->rt_uses_gateway = ort->rt_uses_gateway; INIT_LIST_HEAD(&rt->rt_uncached); - + rt->rt_lwtstate = NULL; dst_free(new); } -- GitLab From 19e42e45150672124b6a4341e2bc7982d247f0ac Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:48 +0200 Subject: [PATCH 1409/7006] ipv6: support for fib route lwtunnel encap attributes This patch adds support in ipv6 fib functions to parse Netlink RTA encap attributes and attach encap state data to rt6_info. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/net/ip6_fib.h | 3 +++ net/ipv6/ip6_fib.c | 2 ++ net/ipv6/route.c | 33 ++++++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h index 3b76849c190fc..276328e3daa64 100644 --- a/include/net/ip6_fib.h +++ b/include/net/ip6_fib.h @@ -51,6 +51,8 @@ struct fib6_config { struct nlattr *fc_mp; struct nl_info fc_nlinfo; + struct nlattr *fc_encap; + u16 fc_encap_type; }; struct fib6_node { @@ -131,6 +133,7 @@ struct rt6_info { /* more non-fragment space at head required */ unsigned short rt6i_nfheader_len; u8 rt6i_protocol; + struct lwtunnel_state *rt6i_lwtstate; }; static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 55d19861ab20f..d715f2e0c4e71 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -177,6 +178,7 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) static void rt6_release(struct rt6_info *rt) { if (atomic_dec_and_test(&rt->rt6i_ref)) { + lwtunnel_state_put(rt->rt6i_lwtstate); rt6_free_pcpu(rt); dst_free(&rt->dst); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 6090969937f8b..b3431b79dfb1a 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -58,6 +58,7 @@ #include #include #include +#include #include @@ -1770,6 +1771,17 @@ int ip6_route_add(struct fib6_config *cfg) rt->dst.output = ip6_output; + if (cfg->fc_encap) { + struct lwtunnel_state *lwtstate; + + err = lwtunnel_build_state(dev, cfg->fc_encap_type, + cfg->fc_encap, &lwtstate); + if (err) + goto out; + lwtunnel_state_get(lwtstate); + rt->rt6i_lwtstate = lwtstate; + } + ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); rt->rt6i_dst.plen = cfg->fc_dst_len; if (rt->rt6i_dst.plen == 128) @@ -2595,6 +2607,8 @@ static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { [RTA_METRICS] = { .type = NLA_NESTED }, [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, [RTA_PREF] = { .type = NLA_U8 }, + [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, + [RTA_ENCAP] = { .type = NLA_NESTED }, }; static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, @@ -2689,6 +2703,12 @@ static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, cfg->fc_flags |= RTF_PREF(pref); } + if (tb[RTA_ENCAP]) + cfg->fc_encap = tb[RTA_ENCAP]; + + if (tb[RTA_ENCAP_TYPE]) + cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); + err = 0; errout: return err; @@ -2721,6 +2741,10 @@ beginning: r_cfg.fc_gateway = nla_get_in6_addr(nla); r_cfg.fc_flags |= RTF_GATEWAY; } + r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP); + nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE); + if (nla) + r_cfg.fc_encap_type = nla_get_u16(nla); } err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); if (err) { @@ -2783,7 +2807,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) return ip6_route_add(&cfg); } -static inline size_t rt6_nlmsg_size(void) +static inline size_t rt6_nlmsg_size(struct rt6_info *rt) { return NLMSG_ALIGN(sizeof(struct rtmsg)) + nla_total_size(16) /* RTA_SRC */ @@ -2797,7 +2821,8 @@ static inline size_t rt6_nlmsg_size(void) + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ + nla_total_size(sizeof(struct rta_cacheinfo)) + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */ - + nla_total_size(1); /* RTA_PREF */ + + nla_total_size(1) /* RTA_PREF */ + + lwtunnel_get_encap_size(rt->rt6i_lwtstate); } static int rt6_fill_node(struct net *net, @@ -2945,6 +2970,8 @@ static int rt6_fill_node(struct net *net, if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) goto nla_put_failure; + lwtunnel_fill_encap(skb, rt->rt6i_lwtstate); + nlmsg_end(skb, nlh); return 0; @@ -3071,7 +3098,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info) err = -ENOBUFS; seq = info->nlh ? info->nlh->nlmsg_seq : 0; - skb = nlmsg_new(rt6_nlmsg_size(), gfp_any()); + skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); if (!skb) goto errout; -- GitLab From ffce41962ef64b8e685e5b621caf24bf381addd9 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:49 +0200 Subject: [PATCH 1410/7006] lwtunnel: support dst output redirect function This patch introduces lwtunnel_output function to call corresponding lwtunnels output function to xmit the packet. It adds two variants lwtunnel_output and lwtunnel_output6 for ipv4 and ipv6 respectively today. But this is subject to change when lwtstate will reside in dst or dst_metadata (as per upstream discussions). Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/net/lwtunnel.h | 12 +++++++++ net/core/lwtunnel.c | 56 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h index df24b3611ff49..918e03c1dafa5 100644 --- a/include/net/lwtunnel.h +++ b/include/net/lwtunnel.h @@ -69,6 +69,8 @@ int lwtunnel_fill_encap(struct sk_buff *skb, int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate); struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len); int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b); +int lwtunnel_output(struct sock *sk, struct sk_buff *skb); +int lwtunnel_output6(struct sock *sk, struct sk_buff *skb); #else @@ -127,6 +129,16 @@ static inline int lwtunnel_cmp_encap(struct lwtunnel_state *a, return 0; } +static inline int lwtunnel_output(struct sock *sk, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + +static inline int lwtunnel_output6(struct sock *sk, struct sk_buff *skb) +{ + return -EOPNOTSUPP; +} + #endif #endif /* __NET_LWTUNNEL_H */ diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index d7ae3a235b4b0..bb58826c708d6 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -25,6 +25,7 @@ #include #include +#include struct lwtunnel_state *lwtunnel_state_alloc(int encap_len) { @@ -177,3 +178,58 @@ int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) return ret; } EXPORT_SYMBOL(lwtunnel_cmp_encap); + +int __lwtunnel_output(struct sock *sk, struct sk_buff *skb, + struct lwtunnel_state *lwtstate) +{ + const struct lwtunnel_encap_ops *ops; + int ret = -EINVAL; + + if (!lwtstate) + goto drop; + + if (lwtstate->type == LWTUNNEL_ENCAP_NONE || + lwtstate->type > LWTUNNEL_ENCAP_MAX) + return 0; + + ret = -EOPNOTSUPP; + rcu_read_lock(); + ops = rcu_dereference(lwtun_encaps[lwtstate->type]); + if (likely(ops && ops->output)) + ret = ops->output(sk, skb); + rcu_read_unlock(); + + if (ret == -EOPNOTSUPP) + goto drop; + + return ret; + +drop: + kfree(skb); + + return ret; +} + +int lwtunnel_output6(struct sock *sk, struct sk_buff *skb) +{ + struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); + struct lwtunnel_state *lwtstate = NULL; + + if (rt) + lwtstate = rt->rt6i_lwtstate; + + return __lwtunnel_output(sk, skb, lwtstate); +} +EXPORT_SYMBOL(lwtunnel_output6); + +int lwtunnel_output(struct sock *sk, struct sk_buff *skb) +{ + struct rtable *rt = (struct rtable *)skb_dst(skb); + struct lwtunnel_state *lwtstate = NULL; + + if (rt) + lwtstate = rt->rt_lwtstate; + + return __lwtunnel_output(sk, skb, lwtstate); +} +EXPORT_SYMBOL(lwtunnel_output); -- GitLab From 8602a625024737602630fe0dee423b3096d31524 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:50 +0200 Subject: [PATCH 1411/7006] ipv4: redirect dst output to lwtunnel output For input routes with tunnel encap state this patch redirects dst output functions to lwtunnel_output which later resolves to the corresponding lwtunnel output function. This has been tested to work with mpls ip tunnels. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/ipv4/route.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 226570ba1cedb..cd3157c464e60 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1633,6 +1633,8 @@ static int __mkroute_input(struct sk_buff *skb, rth->dst.output = ip_output; rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag); + if (lwtunnel_output_redirect(rth->rt_lwtstate)) + rth->dst.output = lwtunnel_output; skb_dst_set(skb, &rth->dst); out: err = 0; -- GitLab From 74a0f2fe8ed51e3adbb1c882be04672fe7bb6996 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:51 +0200 Subject: [PATCH 1412/7006] ipv6: rt6_info output redirect to tunnel output This is similar to ipv4 redirect of dst output to lwtunnel output function for encapsulation and xmit. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/ipv6/route.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b3431b79dfb1a..7f2214f8fde71 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1780,6 +1780,7 @@ int ip6_route_add(struct fib6_config *cfg) goto out; lwtunnel_state_get(lwtstate); rt->rt6i_lwtstate = lwtstate; + rt->dst.output = lwtunnel_output6; } ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); -- GitLab From face0188e31b3cfc598d8dc3470e28e00fb3b07c Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:52 +0200 Subject: [PATCH 1413/7006] mpls: export mpls functions for use by mpls iptunnels Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/mpls/af_mpls.c | 11 ++++++++--- net/mpls/internal.h | 9 +++++++-- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 1f93a5978f2ad..6e669114f829d 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -58,10 +58,11 @@ static inline struct mpls_dev *mpls_dev_get(const struct net_device *dev) return rcu_dereference_rtnl(dev->mpls_ptr); } -static bool mpls_output_possible(const struct net_device *dev) +bool mpls_output_possible(const struct net_device *dev) { return dev && (dev->flags & IFF_UP) && netif_carrier_ok(dev); } +EXPORT_SYMBOL_GPL(mpls_output_possible); static unsigned int mpls_rt_header_size(const struct mpls_route *rt) { @@ -69,13 +70,14 @@ static unsigned int mpls_rt_header_size(const struct mpls_route *rt) return rt->rt_labels * sizeof(struct mpls_shim_hdr); } -static unsigned int mpls_dev_mtu(const struct net_device *dev) +unsigned int mpls_dev_mtu(const struct net_device *dev) { /* The amount of data the layer 2 frame can hold */ return dev->mtu; } +EXPORT_SYMBOL_GPL(mpls_dev_mtu); -static bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) +bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) { if (skb->len <= mtu) return false; @@ -85,6 +87,7 @@ static bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) return true; } +EXPORT_SYMBOL_GPL(mpls_pkt_too_big); static bool mpls_egress(struct mpls_route *rt, struct sk_buff *skb, struct mpls_entry_decoded dec) @@ -626,6 +629,7 @@ int nla_put_labels(struct sk_buff *skb, int attrtype, return 0; } +EXPORT_SYMBOL_GPL(nla_put_labels); int nla_get_labels(const struct nlattr *nla, u32 max_labels, u32 *labels, u32 label[]) @@ -671,6 +675,7 @@ int nla_get_labels(const struct nlattr *nla, *labels = nla_labels; return 0; } +EXPORT_SYMBOL_GPL(nla_get_labels); static int rtm_to_route_config(struct sk_buff *skb, struct nlmsghdr *nlh, struct mpls_route_config *cfg) diff --git a/net/mpls/internal.h b/net/mpls/internal.h index 8cabeb5a1cb92..2681a4ba6c375 100644 --- a/net/mpls/internal.h +++ b/net/mpls/internal.h @@ -50,7 +50,12 @@ static inline struct mpls_entry_decoded mpls_entry_decode(struct mpls_shim_hdr * return result; } -int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels, const u32 label[]); -int nla_get_labels(const struct nlattr *nla, u32 max_labels, u32 *labels, u32 label[]); +int nla_put_labels(struct sk_buff *skb, int attrtype, u8 labels, + const u32 label[]); +int nla_get_labels(const struct nlattr *nla, u32 max_labels, u32 *labels, + u32 label[]); +bool mpls_output_possible(const struct net_device *dev); +unsigned int mpls_dev_mtu(const struct net_device *dev); +bool mpls_pkt_too_big(const struct sk_buff *skb, unsigned int mtu); #endif /* MPLS_INTERNAL_H */ -- GitLab From e3e4712ec0961ed586a8db340bd994c4ad7f5dba Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 10:43:53 +0200 Subject: [PATCH 1414/7006] mpls: ip tunnel support This implementation uses lwtunnel infrastructure to register hooks for mpls tunnel encaps. It picks cues from iptunnel_encaps infrastructure and previous mpls iptunnel RFC patches from Eric W. Biederman and Robert Shearman Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/linux/mpls_iptunnel.h | 6 + include/net/mpls_iptunnel.h | 29 ++++ include/uapi/linux/mpls_iptunnel.h | 28 ++++ net/mpls/Kconfig | 8 +- net/mpls/Makefile | 1 + net/mpls/mpls_iptunnel.c | 233 +++++++++++++++++++++++++++++ 6 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 include/linux/mpls_iptunnel.h create mode 100644 include/net/mpls_iptunnel.h create mode 100644 include/uapi/linux/mpls_iptunnel.h create mode 100644 net/mpls/mpls_iptunnel.c diff --git a/include/linux/mpls_iptunnel.h b/include/linux/mpls_iptunnel.h new file mode 100644 index 0000000000000..ef29eb2d6dfd6 --- /dev/null +++ b/include/linux/mpls_iptunnel.h @@ -0,0 +1,6 @@ +#ifndef _LINUX_MPLS_IPTUNNEL_H +#define _LINUX_MPLS_IPTUNNEL_H + +#include + +#endif /* _LINUX_MPLS_IPTUNNEL_H */ diff --git a/include/net/mpls_iptunnel.h b/include/net/mpls_iptunnel.h new file mode 100644 index 0000000000000..4757997f76edf --- /dev/null +++ b/include/net/mpls_iptunnel.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 Cumulus Networks, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef _NET_MPLS_IPTUNNEL_H +#define _NET_MPLS_IPTUNNEL_H 1 + +#define MAX_NEW_LABELS 2 + +struct mpls_iptunnel_encap { + u32 label[MAX_NEW_LABELS]; + u32 labels; +}; + +static inline struct mpls_iptunnel_encap *mpls_lwtunnel_encap(struct lwtunnel_state *lwtstate) +{ + return (struct mpls_iptunnel_encap *)lwtstate->data; +} + +#endif diff --git a/include/uapi/linux/mpls_iptunnel.h b/include/uapi/linux/mpls_iptunnel.h new file mode 100644 index 0000000000000..d80a0498f77ed --- /dev/null +++ b/include/uapi/linux/mpls_iptunnel.h @@ -0,0 +1,28 @@ +/* + * mpls tunnel api + * + * Authors: + * Roopa Prabhu + * + * 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 _UAPI_LINUX_MPLS_IPTUNNEL_H +#define _UAPI_LINUX_MPLS_IPTUNNEL_H + +/* MPLS tunnel attributes + * [RTA_ENCAP] = { + * [MPLS_IPTUNNEL_DST] + * } + */ +enum { + MPLS_IPTUNNEL_UNSPEC, + MPLS_IPTUNNEL_DST, + __MPLS_IPTUNNEL_MAX, +}; +#define MPLS_IPTUNNEL_MAX (__MPLS_IPTUNNEL_MAX - 1) + +#endif /* _UAPI_LINUX_MPLS_IPTUNNEL_H */ diff --git a/net/mpls/Kconfig b/net/mpls/Kconfig index 17bde799c8548..5c467ef973114 100644 --- a/net/mpls/Kconfig +++ b/net/mpls/Kconfig @@ -24,7 +24,13 @@ config NET_MPLS_GSO config MPLS_ROUTING tristate "MPLS: routing support" - help + ---help--- Add support for forwarding of mpls packets. +config MPLS_IPTUNNEL + tristate "MPLS: IP over MPLS tunnel support" + depends on LWTUNNEL && MPLS_ROUTING + ---help--- + mpls ip tunnel support. + endif # MPLS diff --git a/net/mpls/Makefile b/net/mpls/Makefile index 65bbe68c72e66..9ca9236250165 100644 --- a/net/mpls/Makefile +++ b/net/mpls/Makefile @@ -3,5 +3,6 @@ # obj-$(CONFIG_NET_MPLS_GSO) += mpls_gso.o obj-$(CONFIG_MPLS_ROUTING) += mpls_router.o +obj-$(CONFIG_MPLS_IPTUNNEL) += mpls_iptunnel.o mpls_router-y := af_mpls.o diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c new file mode 100644 index 0000000000000..eea096f21ba58 --- /dev/null +++ b/net/mpls/mpls_iptunnel.c @@ -0,0 +1,233 @@ +/* + * mpls tunnels An implementation mpls tunnels using the light weight tunnel + * infrastructure + * + * Authors: Roopa Prabhu, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +static const struct nla_policy mpls_iptunnel_policy[MPLS_IPTUNNEL_MAX + 1] = { + [MPLS_IPTUNNEL_DST] = { .type = NLA_U32 }, +}; + +static unsigned int mpls_encap_size(struct mpls_iptunnel_encap *en) +{ + /* The size of the layer 2.5 labels to be added for this route */ + return en->labels * sizeof(struct mpls_shim_hdr); +} + +int mpls_output(struct sock *sk, struct sk_buff *skb) +{ + struct mpls_iptunnel_encap *tun_encap_info; + struct mpls_shim_hdr *hdr; + struct net_device *out_dev; + unsigned int hh_len; + unsigned int new_header_size; + unsigned int mtu; + struct dst_entry *dst = skb_dst(skb); + struct rtable *rt = NULL; + struct rt6_info *rt6 = NULL; + struct lwtunnel_state *lwtstate = NULL; + int err = 0; + bool bos; + int i; + unsigned int ttl; + + /* Obtain the ttl */ + if (skb->protocol == htons(ETH_P_IP)) { + ttl = ip_hdr(skb)->ttl; + rt = (struct rtable *)dst; + lwtstate = rt->rt_lwtstate; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + ttl = ipv6_hdr(skb)->hop_limit; + rt6 = (struct rt6_info *)dst; + lwtstate = rt6->rt6i_lwtstate; + } else { + goto drop; + } + + skb_orphan(skb); + + /* Find the output device */ + out_dev = rcu_dereference(dst->dev); + if (!mpls_output_possible(out_dev) || + !lwtstate || skb_warn_if_lro(skb)) + goto drop; + + skb_forward_csum(skb); + + tun_encap_info = mpls_lwtunnel_encap(lwtstate); + + /* Verify the destination can hold the packet */ + new_header_size = mpls_encap_size(tun_encap_info); + mtu = mpls_dev_mtu(out_dev); + if (mpls_pkt_too_big(skb, mtu - new_header_size)) + goto drop; + + hh_len = LL_RESERVED_SPACE(out_dev); + if (!out_dev->header_ops) + hh_len = 0; + + /* Ensure there is enough space for the headers in the skb */ + if (skb_cow(skb, hh_len + new_header_size)) + goto drop; + + skb_push(skb, new_header_size); + skb_reset_network_header(skb); + + skb->dev = out_dev; + skb->protocol = htons(ETH_P_MPLS_UC); + + /* Push the new labels */ + hdr = mpls_hdr(skb); + bos = true; + for (i = tun_encap_info->labels - 1; i >= 0; i--) { + hdr[i] = mpls_entry_encode(tun_encap_info->label[i], + ttl, 0, bos); + bos = false; + } + + if (rt) + err = neigh_xmit(NEIGH_ARP_TABLE, out_dev, &rt->rt_gateway, + skb); + else if (rt6) + err = neigh_xmit(NEIGH_ND_TABLE, out_dev, &rt6->rt6i_gateway, + skb); + if (err) + net_dbg_ratelimited("%s: packet transmission failed: %d\n", + __func__, err); + + return 0; + +drop: + kfree_skb(skb); + return -EINVAL; +} + +static int mpls_build_state(struct net_device *dev, struct nlattr *nla, + struct lwtunnel_state **ts) +{ + struct mpls_iptunnel_encap *tun_encap_info; + struct nlattr *tb[MPLS_IPTUNNEL_MAX + 1]; + struct lwtunnel_state *newts; + int tun_encap_info_len; + int ret; + + ret = nla_parse_nested(tb, MPLS_IPTUNNEL_MAX, nla, + mpls_iptunnel_policy); + if (ret < 0) + return ret; + + if (!tb[MPLS_IPTUNNEL_DST]) + return -EINVAL; + + tun_encap_info_len = sizeof(*tun_encap_info); + + newts = lwtunnel_state_alloc(tun_encap_info_len); + if (!newts) + return -ENOMEM; + + newts->len = tun_encap_info_len; + tun_encap_info = mpls_lwtunnel_encap(newts); + ret = nla_get_labels(tb[MPLS_IPTUNNEL_DST], MAX_NEW_LABELS, + &tun_encap_info->labels, tun_encap_info->label); + if (ret) + goto errout; + newts->type = LWTUNNEL_ENCAP_MPLS; + newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT; + + *ts = newts; + + return 0; + +errout: + kfree(newts); + *ts = NULL; + + return ret; +} + +static int mpls_fill_encap_info(struct sk_buff *skb, + struct lwtunnel_state *lwtstate) +{ + struct mpls_iptunnel_encap *tun_encap_info; + + tun_encap_info = mpls_lwtunnel_encap(lwtstate); + + if (nla_put_labels(skb, MPLS_IPTUNNEL_DST, tun_encap_info->labels, + tun_encap_info->label)) + goto nla_put_failure; + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static int mpls_encap_nlsize(struct lwtunnel_state *lwtstate) +{ + struct mpls_iptunnel_encap *tun_encap_info; + + tun_encap_info = mpls_lwtunnel_encap(lwtstate); + + return nla_total_size(tun_encap_info->labels * 4); +} + +static int mpls_encap_cmp(struct lwtunnel_state *a, struct lwtunnel_state *b) +{ + struct mpls_iptunnel_encap *a_hdr = mpls_lwtunnel_encap(a); + struct mpls_iptunnel_encap *b_hdr = mpls_lwtunnel_encap(b); + int l; + + if (a_hdr->labels != b_hdr->labels) + return 1; + + for (l = 0; l < MAX_NEW_LABELS; l++) + if (a_hdr->label[l] != b_hdr->label[l]) + return 1; + return 0; +} + +static const struct lwtunnel_encap_ops mpls_iptun_ops = { + .build_state = mpls_build_state, + .output = mpls_output, + .fill_encap = mpls_fill_encap_info, + .get_encap_size = mpls_encap_nlsize, + .cmp_encap = mpls_encap_cmp, +}; + +static int __init mpls_iptunnel_init(void) +{ + return lwtunnel_encap_add_ops(&mpls_iptun_ops, LWTUNNEL_ENCAP_MPLS); +} +module_init(mpls_iptunnel_init); + +static void __exit mpls_iptunnel_exit(void) +{ + lwtunnel_encap_del_ops(&mpls_iptun_ops, LWTUNNEL_ENCAP_MPLS); +} +module_exit(mpls_iptunnel_exit); + +MODULE_DESCRIPTION("MultiProtocol Label Switching IP Tunnels"); +MODULE_LICENSE("GPL v2"); -- GitLab From 1d8fff907342d2339796dbd27ea47d0e76a6a2d0 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:43:54 +0200 Subject: [PATCH 1415/7006] ip_tunnel: Make ovs_tunnel_info and ovs_key_ipv4_tunnel generic Rename the tunnel metadata data structures currently internal to OVS and make them generic for use by all IP tunnels. Both structures are kernel internal and will stay that way. Their members are exposed to user space through individual Netlink attributes by OVS. It will therefore be possible to extend/modify these structures without affecting user ABI. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/ip_tunnels.h | 63 ++++++++++++++++++++++++++ include/uapi/linux/openvswitch.h | 2 +- net/openvswitch/actions.c | 2 +- net/openvswitch/datapath.h | 5 ++- net/openvswitch/flow.c | 4 +- net/openvswitch/flow.h | 76 ++------------------------------ net/openvswitch/flow_netlink.c | 16 +++---- net/openvswitch/flow_netlink.h | 2 +- net/openvswitch/vport-geneve.c | 17 ++++--- net/openvswitch/vport-gre.c | 16 +++---- net/openvswitch/vport-vxlan.c | 18 ++++---- net/openvswitch/vport.c | 30 ++++++------- net/openvswitch/vport.h | 12 ++--- 13 files changed, 128 insertions(+), 135 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index d8214cb88bbcf..6b9d559ce5f5b 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -22,6 +22,28 @@ /* Keep error state on tunnel for 30 sec */ #define IPTUNNEL_ERR_TIMEO (30*HZ) +/* Used to memset ip_tunnel padding. */ +#define IP_TUNNEL_KEY_SIZE \ + (offsetof(struct ip_tunnel_key, tp_dst) + \ + FIELD_SIZEOF(struct ip_tunnel_key, tp_dst)) + +struct ip_tunnel_key { + __be64 tun_id; + __be32 ipv4_src; + __be32 ipv4_dst; + __be16 tun_flags; + __u8 ipv4_tos; + __u8 ipv4_ttl; + __be16 tp_src; + __be16 tp_dst; +} __packed __aligned(4); /* Minimize padding. */ + +struct ip_tunnel_info { + struct ip_tunnel_key key; + const void *options; + u8 options_len; +}; + /* 6rd prefix/relay information */ #ifdef CONFIG_IPV6_SIT_6RD struct ip_tunnel_6rd_parm { @@ -136,6 +158,47 @@ int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *op, int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *op, unsigned int num); +static inline void __ip_tunnel_info_init(struct ip_tunnel_info *tun_info, + __be32 saddr, __be32 daddr, + u8 tos, u8 ttl, + __be16 tp_src, __be16 tp_dst, + __be64 tun_id, __be16 tun_flags, + const void *opts, u8 opts_len) +{ + tun_info->key.tun_id = tun_id; + tun_info->key.ipv4_src = saddr; + tun_info->key.ipv4_dst = daddr; + tun_info->key.ipv4_tos = tos; + tun_info->key.ipv4_ttl = ttl; + tun_info->key.tun_flags = tun_flags; + + /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of + * the upper tunnel are used. + * E.g: GRE over IPSEC, the tp_src and tp_port are zero. + */ + tun_info->key.tp_src = tp_src; + tun_info->key.tp_dst = tp_dst; + + /* Clear struct padding. */ + if (sizeof(tun_info->key) != IP_TUNNEL_KEY_SIZE) + memset((unsigned char *)&tun_info->key + IP_TUNNEL_KEY_SIZE, + 0, sizeof(tun_info->key) - IP_TUNNEL_KEY_SIZE); + + tun_info->options = opts; + tun_info->options_len = opts_len; +} + +static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info, + const struct iphdr *iph, + __be16 tp_src, __be16 tp_dst, + __be64 tun_id, __be16 tun_flags, + const void *opts, u8 opts_len) +{ + __ip_tunnel_info_init(tun_info, iph->saddr, iph->daddr, + iph->tos, iph->ttl, tp_src, tp_dst, + tun_id, tun_flags, opts, opts_len); +} + #ifdef CONFIG_INET int ip_tunnel_init(struct net_device *dev); diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 1dab77601c217..d6b8854601872 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -321,7 +321,7 @@ enum ovs_key_attr { * the accepted length of the array. */ #ifdef __KERNEL__ - OVS_KEY_ATTR_TUNNEL_INFO, /* struct ovs_tunnel_info */ + OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ #endif __OVS_KEY_ATTR_MAX }; diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 8a8c0b8b4f63a..27c1687cfd927 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -611,7 +611,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, struct sw_flow_key *key, const struct nlattr *attr, const struct nlattr *actions, int actions_len) { - struct ovs_tunnel_info info; + struct ip_tunnel_info info; struct dp_upcall_info upcall; const struct nlattr *a; int rem; diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index cd691e935e08c..6b28c5cedb238 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -25,6 +25,7 @@ #include #include #include +#include #include "flow.h" #include "flow_table.h" @@ -98,7 +99,7 @@ struct datapath { * when a packet is received by OVS. */ struct ovs_skb_cb { - struct ovs_tunnel_info *egress_tun_info; + struct ip_tunnel_info *egress_tun_info; struct vport *input_vport; }; #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) @@ -114,7 +115,7 @@ struct ovs_skb_cb { * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY. */ struct dp_upcall_info { - const struct ovs_tunnel_info *egress_tun_info; + const struct ip_tunnel_info *egress_tun_info; const struct nlattr *userdata; const struct nlattr *actions; int actions_len; diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index bc7b0aba994ad..8db22ef73626c 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -682,12 +682,12 @@ int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key) return key_extract(skb, key); } -int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, +int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, struct sk_buff *skb, struct sw_flow_key *key) { /* Extract metadata from packet. */ if (tun_info) { - memcpy(&key->tun_key, &tun_info->tunnel, sizeof(key->tun_key)); + memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key)); if (tun_info->options) { BUILD_BUG_ON((1 << (sizeof(tun_info->options_len) * diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index a076e445ccc2e..cadc6c5c35456 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -32,31 +32,10 @@ #include #include #include +#include struct sk_buff; -/* Used to memset ovs_key_ipv4_tunnel padding. */ -#define OVS_TUNNEL_KEY_SIZE \ - (offsetof(struct ovs_key_ipv4_tunnel, tp_dst) + \ - FIELD_SIZEOF(struct ovs_key_ipv4_tunnel, tp_dst)) - -struct ovs_key_ipv4_tunnel { - __be64 tun_id; - __be32 ipv4_src; - __be32 ipv4_dst; - __be16 tun_flags; - u8 ipv4_tos; - u8 ipv4_ttl; - __be16 tp_src; - __be16 tp_dst; -} __packed __aligned(4); /* Minimize padding. */ - -struct ovs_tunnel_info { - struct ovs_key_ipv4_tunnel tunnel; - const void *options; - u8 options_len; -}; - /* Store options at the end of the array if they are less than the * maximum size. This allows us to get the benefits of variable length * matching for small options. @@ -66,55 +45,6 @@ struct ovs_tunnel_info { #define TUN_METADATA_OPTS(flow_key, opt_len) \ ((void *)((flow_key)->tun_opts + TUN_METADATA_OFFSET(opt_len))) -static inline void __ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, - __be32 saddr, __be32 daddr, - u8 tos, u8 ttl, - __be16 tp_src, - __be16 tp_dst, - __be64 tun_id, - __be16 tun_flags, - const void *opts, - u8 opts_len) -{ - tun_info->tunnel.tun_id = tun_id; - tun_info->tunnel.ipv4_src = saddr; - tun_info->tunnel.ipv4_dst = daddr; - tun_info->tunnel.ipv4_tos = tos; - tun_info->tunnel.ipv4_ttl = ttl; - tun_info->tunnel.tun_flags = tun_flags; - - /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of - * the upper tunnel are used. - * E.g: GRE over IPSEC, the tp_src and tp_port are zero. - */ - tun_info->tunnel.tp_src = tp_src; - tun_info->tunnel.tp_dst = tp_dst; - - /* Clear struct padding. */ - if (sizeof(tun_info->tunnel) != OVS_TUNNEL_KEY_SIZE) - memset((unsigned char *)&tun_info->tunnel + OVS_TUNNEL_KEY_SIZE, - 0, sizeof(tun_info->tunnel) - OVS_TUNNEL_KEY_SIZE); - - tun_info->options = opts; - tun_info->options_len = opts_len; -} - -static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, - const struct iphdr *iph, - __be16 tp_src, - __be16 tp_dst, - __be64 tun_id, - __be16 tun_flags, - const void *opts, - u8 opts_len) -{ - __ovs_flow_tun_info_init(tun_info, iph->saddr, iph->daddr, - iph->tos, iph->ttl, - tp_src, tp_dst, - tun_id, tun_flags, - opts, opts_len); -} - #define OVS_SW_FLOW_KEY_METADATA_SIZE \ (offsetof(struct sw_flow_key, recirc_id) + \ FIELD_SIZEOF(struct sw_flow_key, recirc_id)) @@ -122,7 +52,7 @@ static inline void ovs_flow_tun_info_init(struct ovs_tunnel_info *tun_info, struct sw_flow_key { u8 tun_opts[255]; u8 tun_opts_len; - struct ovs_key_ipv4_tunnel tun_key; /* Encapsulating tunnel key. */ + struct ip_tunnel_key tun_key; /* Encapsulating tunnel key. */ struct { u32 priority; /* Packet QoS priority. */ u32 skb_mark; /* SKB mark. */ @@ -273,7 +203,7 @@ void ovs_flow_stats_clear(struct sw_flow *); u64 ovs_flow_used_time(unsigned long flow_jiffies); int ovs_flow_key_update(struct sk_buff *skb, struct sw_flow_key *key); -int ovs_flow_key_extract(const struct ovs_tunnel_info *tun_info, +int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, struct sk_buff *skb, struct sw_flow_key *key); /* Extract key from packet coming from userspace. */ diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 624e41c4267fe..ecfa530d3461f 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -641,7 +641,7 @@ static int vxlan_opt_to_nlattr(struct sk_buff *skb, } static int __ipv4_tun_to_nlattr(struct sk_buff *skb, - const struct ovs_key_ipv4_tunnel *output, + const struct ip_tunnel_key *output, const void *tun_opts, int swkey_tun_opts_len) { if (output->tun_flags & TUNNEL_KEY && @@ -689,7 +689,7 @@ static int __ipv4_tun_to_nlattr(struct sk_buff *skb, } static int ipv4_tun_to_nlattr(struct sk_buff *skb, - const struct ovs_key_ipv4_tunnel *output, + const struct ip_tunnel_key *output, const void *tun_opts, int swkey_tun_opts_len) { struct nlattr *nla; @@ -708,9 +708,9 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, } int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, - const struct ovs_tunnel_info *egress_tun_info) + const struct ip_tunnel_info *egress_tun_info) { - return __ipv4_tun_to_nlattr(skb, &egress_tun_info->tunnel, + return __ipv4_tun_to_nlattr(skb, &egress_tun_info->key, egress_tun_info->options, egress_tun_info->options_len); } @@ -1746,7 +1746,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, { struct sw_flow_match match; struct sw_flow_key key; - struct ovs_tunnel_info *tun_info; + struct ip_tunnel_info *tun_info; struct nlattr *a; int err = 0, start, opts_type; @@ -1777,7 +1777,7 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, return PTR_ERR(a); tun_info = nla_data(a); - tun_info->tunnel = key.tun_key; + tun_info->key = key.tun_key; tun_info->options_len = key.tun_opts_len; if (tun_info->options_len) { @@ -2227,13 +2227,13 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) switch (key_type) { case OVS_KEY_ATTR_TUNNEL_INFO: { - struct ovs_tunnel_info *tun_info = nla_data(ovs_key); + struct ip_tunnel_info *tun_info = nla_data(ovs_key); start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); if (!start) return -EMSGSIZE; - err = ipv4_tun_to_nlattr(skb, &tun_info->tunnel, + err = ipv4_tun_to_nlattr(skb, &tun_info->key, tun_info->options_len ? tun_info->options : NULL, tun_info->options_len); diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index 5c3d75bff3104..ec53eb6e632b9 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h @@ -55,7 +55,7 @@ int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb); int ovs_nla_get_match(struct sw_flow_match *, const struct nlattr *key, const struct nlattr *mask, bool log); int ovs_nla_put_egress_tunnel_key(struct sk_buff *, - const struct ovs_tunnel_info *); + const struct ip_tunnel_info *); bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log); int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index 208c576bd1b68..1da3a14d10101 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -77,7 +77,7 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb) struct vport *vport = gs->rcv_data; struct genevehdr *geneveh = geneve_hdr(skb); int opts_len; - struct ovs_tunnel_info tun_info; + struct ip_tunnel_info tun_info; __be64 key; __be16 flags; @@ -90,10 +90,9 @@ static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb) key = vni_to_tunnel_id(geneveh->vni); - ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), - udp_hdr(skb)->source, udp_hdr(skb)->dest, - key, flags, - geneveh->options, opts_len); + ip_tunnel_info_init(&tun_info, ip_hdr(skb), + udp_hdr(skb)->source, udp_hdr(skb)->dest, + key, flags, geneveh->options, opts_len); ovs_vport_receive(vport, skb, &tun_info); } @@ -165,8 +164,8 @@ error: static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb) { - const struct ovs_key_ipv4_tunnel *tun_key; - struct ovs_tunnel_info *tun_info; + const struct ip_tunnel_key *tun_key; + struct ip_tunnel_info *tun_info; struct net *net = ovs_dp_get_net(vport->dp); struct geneve_port *geneve_port = geneve_vport(vport); __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport; @@ -183,7 +182,7 @@ static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb) goto error; } - tun_key = &tun_info->tunnel; + tun_key = &tun_info->key; rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP); if (IS_ERR(rt)) { err = PTR_ERR(rt); @@ -225,7 +224,7 @@ static const char *geneve_get_name(const struct vport *vport) } static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ovs_tunnel_info *egress_tun_info) + struct ip_tunnel_info *egress_tun_info) { struct geneve_port *geneve_port = geneve_vport(vport); struct net *net = ovs_dp_get_net(vport->dp); diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index f17ac9642f4ee..b87656c66aaff 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -67,9 +67,9 @@ static struct sk_buff *__build_header(struct sk_buff *skb, int tunnel_hlen) { struct tnl_ptk_info tpi; - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ip_tunnel_key *tun_key; - tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; + tun_key = &OVS_CB(skb)->egress_tun_info->key; skb = gre_handle_offloads(skb, !!(tun_key->tun_flags & TUNNEL_CSUM)); if (IS_ERR(skb)) @@ -97,7 +97,7 @@ static __be64 key_to_tunnel_id(__be32 key, __be32 seq) static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) { - struct ovs_tunnel_info tun_info; + struct ip_tunnel_info tun_info; struct ovs_net *ovs_net; struct vport *vport; __be64 key; @@ -108,8 +108,8 @@ static int gre_rcv(struct sk_buff *skb, return PACKET_REJECT; key = key_to_tunnel_id(tpi->key, tpi->seq); - ovs_flow_tun_info_init(&tun_info, ip_hdr(skb), 0, 0, key, - filter_tnl_flags(tpi->flags), NULL, 0); + ip_tunnel_info_init(&tun_info, ip_hdr(skb), 0, 0, key, + filter_tnl_flags(tpi->flags), NULL, 0); ovs_vport_receive(vport, skb, &tun_info); return PACKET_RCVD; @@ -134,7 +134,7 @@ static int gre_err(struct sk_buff *skb, u32 info, static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) { struct net *net = ovs_dp_get_net(vport->dp); - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ip_tunnel_key *tun_key; struct flowi4 fl; struct rtable *rt; int min_headroom; @@ -147,7 +147,7 @@ static int gre_tnl_send(struct vport *vport, struct sk_buff *skb) goto err_free_skb; } - tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; + tun_key = &OVS_CB(skb)->egress_tun_info->key; rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_GRE); if (IS_ERR(rt)) { err = PTR_ERR(rt); @@ -277,7 +277,7 @@ static void gre_tnl_destroy(struct vport *vport) } static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ovs_tunnel_info *egress_tun_info) + struct ip_tunnel_info *egress_tun_info) { return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 6d39766e7828c..6f7986fabb70c 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -64,7 +64,7 @@ static inline struct vxlan_port *vxlan_vport(const struct vport *vport) static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, struct vxlan_metadata *md) { - struct ovs_tunnel_info tun_info; + struct ip_tunnel_info tun_info; struct vxlan_port *vxlan_port; struct vport *vport = vs->data; struct iphdr *iph; @@ -82,9 +82,9 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, /* Save outer tunnel values */ iph = ip_hdr(skb); key = cpu_to_be64(ntohl(md->vni) >> 8); - ovs_flow_tun_info_init(&tun_info, iph, - udp_hdr(skb)->source, udp_hdr(skb)->dest, - key, flags, &opts, sizeof(opts)); + ip_tunnel_info_init(&tun_info, iph, + udp_hdr(skb)->source, udp_hdr(skb)->dest, + key, flags, &opts, sizeof(opts)); ovs_vport_receive(vport, skb, &tun_info); } @@ -205,13 +205,13 @@ error: static int vxlan_ext_gbp(struct sk_buff *skb) { - const struct ovs_tunnel_info *tun_info; + const struct ip_tunnel_info *tun_info; const struct ovs_vxlan_opts *opts; tun_info = OVS_CB(skb)->egress_tun_info; opts = tun_info->options; - if (tun_info->tunnel.tun_flags & TUNNEL_VXLAN_OPT && + if (tun_info->key.tun_flags & TUNNEL_VXLAN_OPT && tun_info->options_len >= sizeof(*opts)) return opts->gbp; else @@ -224,7 +224,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) struct vxlan_port *vxlan_port = vxlan_vport(vport); struct sock *sk = vxlan_port->vs->sock->sk; __be16 dst_port = inet_sk(sk)->inet_sport; - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ip_tunnel_key *tun_key; struct vxlan_metadata md = {0}; struct rtable *rt; struct flowi4 fl; @@ -238,7 +238,7 @@ static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) goto error; } - tun_key = &OVS_CB(skb)->egress_tun_info->tunnel; + tun_key = &OVS_CB(skb)->egress_tun_info->key; rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP); if (IS_ERR(rt)) { err = PTR_ERR(rt); @@ -269,7 +269,7 @@ error: } static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ovs_tunnel_info *egress_tun_info) + struct ip_tunnel_info *egress_tun_info) { struct net *net = ovs_dp_get_net(vport->dp); struct vxlan_port *vxlan_port = vxlan_vport(vport); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 067a3fff1d2cb..af23ba077836e 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -469,7 +469,7 @@ u32 ovs_vport_find_upcall_portid(const struct vport *vport, struct sk_buff *skb) * skb->data should point to the Ethernet header. */ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, - const struct ovs_tunnel_info *tun_info) + const struct ip_tunnel_info *tun_info) { struct pcpu_sw_netstats *stats; struct sw_flow_key key; @@ -572,22 +572,22 @@ void ovs_vport_deferred_free(struct vport *vport) } EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); -int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, +int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, struct net *net, - const struct ovs_tunnel_info *tun_info, + const struct ip_tunnel_info *tun_info, u8 ipproto, u32 skb_mark, __be16 tp_src, __be16 tp_dst) { - const struct ovs_key_ipv4_tunnel *tun_key; + const struct ip_tunnel_key *tun_key; struct rtable *rt; struct flowi4 fl; if (unlikely(!tun_info)) return -EINVAL; - tun_key = &tun_info->tunnel; + tun_key = &tun_info->key; /* Route lookup to get srouce IP address. * The process may need to be changed if the corresponding process @@ -602,22 +602,22 @@ int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, /* Generate egress_tun_info based on tun_info, * saddr, tp_src and tp_dst */ - __ovs_flow_tun_info_init(egress_tun_info, - fl.saddr, tun_key->ipv4_dst, - tun_key->ipv4_tos, - tun_key->ipv4_ttl, - tp_src, tp_dst, - tun_key->tun_id, - tun_key->tun_flags, - tun_info->options, - tun_info->options_len); + __ip_tunnel_info_init(egress_tun_info, + fl.saddr, tun_key->ipv4_dst, + tun_key->ipv4_tos, + tun_key->ipv4_ttl, + tp_src, tp_dst, + tun_key->tun_id, + tun_key->tun_flags, + tun_info->options, + tun_info->options_len); return 0; } EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info); int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ovs_tunnel_info *info) + struct ip_tunnel_info *info) { /* get_egress_tun_info() is only implemented on tunnel ports. */ if (unlikely(!vport->ops->get_egress_tun_info)) diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index bc85331a6c60c..4750fb673a9fc 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -58,15 +58,15 @@ u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); int ovs_vport_send(struct vport *, struct sk_buff *); -int ovs_tunnel_get_egress_info(struct ovs_tunnel_info *egress_tun_info, +int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, struct net *net, - const struct ovs_tunnel_info *tun_info, + const struct ip_tunnel_info *tun_info, u8 ipproto, u32 skb_mark, __be16 tp_src, __be16 tp_dst); int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ovs_tunnel_info *info); + struct ip_tunnel_info *info); /* The following definitions are for implementers of vport devices: */ @@ -176,7 +176,7 @@ struct vport_ops { int (*send)(struct vport *, struct sk_buff *); int (*get_egress_tun_info)(struct vport *, struct sk_buff *, - struct ovs_tunnel_info *); + struct ip_tunnel_info *); struct module *owner; struct list_head list; @@ -226,7 +226,7 @@ static inline struct vport *vport_from_priv(void *priv) } void ovs_vport_receive(struct vport *, struct sk_buff *, - const struct ovs_tunnel_info *); + const struct ip_tunnel_info *); static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, const void *start, unsigned int len) @@ -239,7 +239,7 @@ int ovs_vport_ops_register(struct vport_ops *ops); void ovs_vport_ops_unregister(struct vport_ops *ops); static inline struct rtable *ovs_tunnel_route_lookup(struct net *net, - const struct ovs_key_ipv4_tunnel *key, + const struct ip_tunnel_key *key, u32 mark, struct flowi4 *fl, u8 protocol) -- GitLab From 773a69d64bf65eb6c212c97e9737963a2cf668fd Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:43:55 +0200 Subject: [PATCH 1416/7006] icmp: Don't leak original dst into ip_route_input() ip_route_input() unconditionally overwrites the dst. Hide the original dst attached to the skb by calling skb_dst_set(skb, NULL) prior to ip_route_input(). Reported-by: Julian Anastasov Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/icmp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index f5203fba62363..c0556f1e4bf09 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -496,6 +496,7 @@ static struct rtable *icmp_route_lookup(struct net *net, } /* Ugh! */ orefdst = skb_in->_skb_refdst; /* save old refdst */ + skb_dst_set(skb_in, NULL); err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, RT_TOS(tos), rt2->dst.dev); -- GitLab From f38a9eb1f77b296ff07e000823884a0f64d67b2a Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:43:56 +0200 Subject: [PATCH 1417/7006] dst: Metadata destinations Introduces a new dst_metadata which enables to carry per packet metadata between forwarding and processing elements via the skb->dst pointer. The structure is set up to be a union. Thus, each separate type of metadata requires its own dst instance. If demand arises to carry multiple types of metadata concurrently, metadata dst entries can be made stackable. The metadata dst entry is refcnt'ed as expected for now but a non reference counted use is possible if the reference is forced before queueing the skb. In order to allow allocating dsts with variable length, the existing dst_alloc() is split into a dst_alloc() and dst_init() function. The existing dst_init() function to initialize the subsystem is being renamed to dst_subsys_init() to make it clear what is what. The check before ip_route_input() is changed to ignore metadata dsts and drop the dst inside the routing function thus allowing to interpret metadata in a later commit. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/dst.h | 6 ++- include/net/dst_metadata.h | 32 +++++++++++++++ net/core/dev.c | 2 +- net/core/dst.c | 84 +++++++++++++++++++++++++++++++------- net/ipv4/ip_input.c | 3 +- net/ipv4/route.c | 2 + 6 files changed, 112 insertions(+), 17 deletions(-) create mode 100644 include/net/dst_metadata.h diff --git a/include/net/dst.h b/include/net/dst.h index 2bc73f8a00a9c..2578811cef516 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -57,6 +57,7 @@ struct dst_entry { #define DST_FAKE_RTABLE 0x0040 #define DST_XFRM_TUNNEL 0x0080 #define DST_XFRM_QUEUE 0x0100 +#define DST_METADATA 0x0200 unsigned short pending_confirm; @@ -356,6 +357,9 @@ static inline int dst_discard(struct sk_buff *skb) } void *dst_alloc(struct dst_ops *ops, struct net_device *dev, int initial_ref, int initial_obsolete, unsigned short flags); +void dst_init(struct dst_entry *dst, struct dst_ops *ops, + struct net_device *dev, int initial_ref, int initial_obsolete, + unsigned short flags); void __dst_free(struct dst_entry *dst); struct dst_entry *dst_destroy(struct dst_entry *dst); @@ -457,7 +461,7 @@ static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) return dst; } -void dst_init(void); +void dst_subsys_init(void); /* Flags for xfrm_lookup flags argument. */ enum { diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h new file mode 100644 index 0000000000000..4f7694f3c7d0b --- /dev/null +++ b/include/net/dst_metadata.h @@ -0,0 +1,32 @@ +#ifndef __NET_DST_METADATA_H +#define __NET_DST_METADATA_H 1 + +#include +#include +#include + +struct metadata_dst { + struct dst_entry dst; + size_t opts_len; +}; + +static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) +{ + struct metadata_dst *md_dst = (struct metadata_dst *) skb_dst(skb); + + if (md_dst && md_dst->dst.flags & DST_METADATA) + return md_dst; + + return NULL; +} + +static inline bool skb_valid_dst(const struct sk_buff *skb) +{ + struct dst_entry *dst = skb_dst(skb); + + return dst && !(dst->flags & DST_METADATA); +} + +struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags); + +#endif /* __NET_DST_METADATA_H */ diff --git a/net/core/dev.c b/net/core/dev.c index 2ee15afb412d7..cb52cba30ae8b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7669,7 +7669,7 @@ static int __init net_dev_init(void) open_softirq(NET_RX_SOFTIRQ, net_rx_action); hotcpu_notifier(dev_cpu_callback, 0); - dst_init(); + dst_subsys_init(); rc = 0; out: return rc; diff --git a/net/core/dst.c b/net/core/dst.c index e956ce6d13782..917364f0d0be0 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -22,6 +22,7 @@ #include #include +#include /* * Theory of operations: @@ -158,19 +159,10 @@ const u32 dst_default_metrics[RTAX_MAX + 1] = { [RTAX_MAX] = 0xdeadbeef, }; - -void *dst_alloc(struct dst_ops *ops, struct net_device *dev, - int initial_ref, int initial_obsolete, unsigned short flags) +void dst_init(struct dst_entry *dst, struct dst_ops *ops, + struct net_device *dev, int initial_ref, int initial_obsolete, + unsigned short flags) { - struct dst_entry *dst; - - if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) { - if (ops->gc(ops)) - return NULL; - } - dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); - if (!dst) - return NULL; dst->child = NULL; dst->dev = dev; if (dev) @@ -200,6 +192,25 @@ void *dst_alloc(struct dst_ops *ops, struct net_device *dev, dst->next = NULL; if (!(flags & DST_NOCOUNT)) dst_entries_add(ops, 1); +} +EXPORT_SYMBOL(dst_init); + +void *dst_alloc(struct dst_ops *ops, struct net_device *dev, + int initial_ref, int initial_obsolete, unsigned short flags) +{ + struct dst_entry *dst; + + if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) { + if (ops->gc(ops)) + return NULL; + } + + dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); + if (!dst) + return NULL; + + dst_init(dst, ops, dev, initial_ref, initial_obsolete, flags); + return dst; } EXPORT_SYMBOL(dst_alloc); @@ -248,7 +259,11 @@ again: dst->ops->destroy(dst); if (dst->dev) dev_put(dst->dev); - kmem_cache_free(dst->ops->kmem_cachep, dst); + + if (dst->flags & DST_METADATA) + kfree(dst); + else + kmem_cache_free(dst->ops->kmem_cachep, dst); dst = child; if (dst) { @@ -327,6 +342,47 @@ void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old) } EXPORT_SYMBOL(__dst_destroy_metrics_generic); +static struct dst_ops md_dst_ops = { + .family = AF_UNSPEC, +}; + +static int dst_md_discard_sk(struct sock *sk, struct sk_buff *skb) +{ + WARN_ONCE(1, "Attempting to call output on metadata dst\n"); + kfree_skb(skb); + return 0; +} + +static int dst_md_discard(struct sk_buff *skb) +{ + WARN_ONCE(1, "Attempting to call input on metadata dst\n"); + kfree_skb(skb); + return 0; +} + +struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags) +{ + struct metadata_dst *md_dst; + struct dst_entry *dst; + + md_dst = kmalloc(sizeof(*md_dst) + optslen, flags); + if (!md_dst) + return ERR_PTR(-ENOMEM); + + dst = &md_dst->dst; + dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE, + DST_METADATA | DST_NOCACHE | DST_NOCOUNT); + + dst->input = dst_md_discard; + dst->output = dst_md_discard_sk; + + memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst)); + md_dst->opts_len = optslen; + + return md_dst; +} +EXPORT_SYMBOL_GPL(metadata_dst_alloc); + /* Dirty hack. We did it in 2.2 (in __dst_free), * we have _very_ good reasons not to repeat * this mistake in 2.3, but we have no choice @@ -391,7 +447,7 @@ static struct notifier_block dst_dev_notifier = { .priority = -10, /* must be called after other network notifiers */ }; -void __init dst_init(void) +void __init dst_subsys_init(void) { register_netdevice_notifier(&dst_dev_notifier); } diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 2db4c8773c1b4..f4fc8a77aaa79 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -146,6 +146,7 @@ #include #include #include +#include /* * Process Router Attention IP option (RFC 2113) @@ -331,7 +332,7 @@ static int ip_rcv_finish(struct sock *sk, struct sk_buff *skb) * Initialise the virtual path cache for the packet. It describes * how the packet travels inside Linux networking. */ - if (!skb_dst(skb)) { + if (!skb_valid_dst(skb)) { int err = ip_route_input_noref(skb, iph->daddr, iph->saddr, iph->tos, skb->dev); if (unlikely(err)) { diff --git a/net/ipv4/route.c b/net/ipv4/route.c index cd3157c464e60..4c8e84e758711 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1690,6 +1690,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, by fib_lookup. */ + skb_dst_drop(skb); + if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) goto martian_source; -- GitLab From 0accfc268f4d3345693d3af3d5780aae3ad93d8d Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:43:57 +0200 Subject: [PATCH 1418/7006] arp: Inherit metadata dst when creating ARP requests If output device wants to see the dst, inherit the dst of the original skb and pass it on to generate the ARP request. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv4/arp.c | 65 ++++++++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 933a92820d265..1d59e50ce8b74 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -291,6 +291,40 @@ static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb) kfree_skb(skb); } +/* Create and send an arp packet. */ +static void arp_send_dst(int type, int ptype, __be32 dest_ip, + struct net_device *dev, __be32 src_ip, + const unsigned char *dest_hw, + const unsigned char *src_hw, + const unsigned char *target_hw, struct sk_buff *oskb) +{ + struct sk_buff *skb; + + /* arp on this interface. */ + if (dev->flags & IFF_NOARP) + return; + + skb = arp_create(type, ptype, dest_ip, dev, src_ip, + dest_hw, src_hw, target_hw); + if (!skb) + return; + + if (oskb) + skb_dst_copy(skb, oskb); + + arp_xmit(skb); +} + +void arp_send(int type, int ptype, __be32 dest_ip, + struct net_device *dev, __be32 src_ip, + const unsigned char *dest_hw, const unsigned char *src_hw, + const unsigned char *target_hw) +{ + arp_send_dst(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, + target_hw, NULL); +} +EXPORT_SYMBOL(arp_send); + static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) { __be32 saddr = 0; @@ -346,8 +380,9 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) } } - arp_send(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, - dst_hw, dev->dev_addr, NULL); + arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, + dst_hw, dev->dev_addr, NULL, + dev->priv_flags & IFF_XMIT_DST_RELEASE ? NULL : skb); } static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) @@ -596,32 +631,6 @@ void arp_xmit(struct sk_buff *skb) } EXPORT_SYMBOL(arp_xmit); -/* - * Create and send an arp packet. - */ -void arp_send(int type, int ptype, __be32 dest_ip, - struct net_device *dev, __be32 src_ip, - const unsigned char *dest_hw, const unsigned char *src_hw, - const unsigned char *target_hw) -{ - struct sk_buff *skb; - - /* - * No arp on this interface. - */ - - if (dev->flags&IFF_NOARP) - return; - - skb = arp_create(type, ptype, dest_ip, dev, src_ip, - dest_hw, src_hw, target_hw); - if (!skb) - return; - - arp_xmit(skb); -} -EXPORT_SYMBOL(arp_send); - /* * Process an arp request. */ -- GitLab From ee122c79d4227f6ec642157834b6a90fcffa4382 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:43:58 +0200 Subject: [PATCH 1419/7006] vxlan: Flow based tunneling Allows putting a VXLAN device into a new flow-based mode in which skbs with a ip_tunnel_info dst metadata attached will be encapsulated according to the instructions stored in there with the VXLAN device defaults taken into consideration. Similar on the receive side, if the VXLAN_F_COLLECT_METADATA flag is set, the packet processing will populate a ip_tunnel_info struct for each packet received and attach it to the skb using the new metadata dst. The metadata structure will contain the outer header and tunnel header fields which have been stripped off. Layers further up in the stack such as routing, tc or netfitler can later match on these fields and perform forwarding. It is the responsibility of upper layers to ensure that the flag is set if the metadata is needed. The flag limits the additional cost of metadata collecting based on demand. This prepares the VXLAN device to be steered by the routing and other subsystems which allows to support encapsulation for a large number of tunnel endpoints and tunnel ids through a single net_device which improves the scalability. It also allows for OVS to leverage this mode which in turn allows for the removal of the OVS specific VXLAN code. Because the skb is currently scrubed in vxlan_rcv(), the attachment of the new dst metadata is postponed until after scrubing which requires the temporary addition of a new member to vxlan_metadata. This member is removed again in a later commit after the indirect VXLAN receive API has been removed. Signed-off-by: Thomas Graf Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 149 +++++++++++++++++++++++++++++------ include/linux/skbuff.h | 1 + include/net/dst_metadata.h | 13 +++ include/net/ip_tunnels.h | 14 ++++ include/net/vxlan.h | 10 ++- include/uapi/linux/if_link.h | 1 + 6 files changed, 165 insertions(+), 23 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ec86a11743fdf..06c092b05a513 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -49,6 +49,7 @@ #include #include #endif +#include #define VXLAN_VERSION "0.1" @@ -140,6 +141,11 @@ struct vxlan_dev { static u32 vxlan_salt __read_mostly; static struct workqueue_struct *vxlan_wq; +static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) +{ + return vs->flags & VXLAN_F_COLLECT_METADATA; +} + #if IS_ENABLED(CONFIG_IPV6) static inline bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b) @@ -1164,10 +1170,13 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, /* Callback from net/ipv4/udp.c to receive packets */ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { + struct metadata_dst *tun_dst = NULL; + struct ip_tunnel_info *info; struct vxlan_sock *vs; struct vxlanhdr *vxh; u32 flags, vni; - struct vxlan_metadata md = {0}; + struct vxlan_metadata _md; + struct vxlan_metadata *md = &_md; /* Need Vxlan and inner Ethernet header to be present */ if (!pskb_may_pull(skb, VXLAN_HLEN)) @@ -1202,6 +1211,33 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) vni &= VXLAN_VNI_MASK; } + if (vxlan_collect_metadata(vs)) { + const struct iphdr *iph = ip_hdr(skb); + + tun_dst = metadata_dst_alloc(sizeof(*md), GFP_ATOMIC); + if (!tun_dst) + goto drop; + + info = &tun_dst->u.tun_info; + info->key.ipv4_src = iph->saddr; + info->key.ipv4_dst = iph->daddr; + info->key.ipv4_tos = iph->tos; + info->key.ipv4_ttl = iph->ttl; + info->key.tp_src = udp_hdr(skb)->source; + info->key.tp_dst = udp_hdr(skb)->dest; + + info->mode = IP_TUNNEL_INFO_RX; + info->key.tun_flags = TUNNEL_KEY; + info->key.tun_id = cpu_to_be64(vni >> 8); + if (udp_hdr(skb)->check != 0) + info->key.tun_flags |= TUNNEL_CSUM; + + md = ip_tunnel_info_opts(info, sizeof(*md)); + md->tun_dst = tun_dst; + } else { + memset(md, 0, sizeof(*md)); + } + /* For backwards compatibility, only allow reserved fields to be * used by VXLAN extensions if explicitly requested. */ @@ -1209,13 +1245,16 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) struct vxlanhdr_gbp *gbp; gbp = (struct vxlanhdr_gbp *)vxh; - md.gbp = ntohs(gbp->policy_id); + md->gbp = ntohs(gbp->policy_id); + + if (tun_dst) + info->key.tun_flags |= TUNNEL_VXLAN_OPT; if (gbp->dont_learn) - md.gbp |= VXLAN_GBP_DONT_LEARN; + md->gbp |= VXLAN_GBP_DONT_LEARN; if (gbp->policy_applied) - md.gbp |= VXLAN_GBP_POLICY_APPLIED; + md->gbp |= VXLAN_GBP_POLICY_APPLIED; flags &= ~VXLAN_GBP_USED_BITS; } @@ -1233,8 +1272,8 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto bad_flags; } - md.vni = vxh->vx_vni; - vs->rcv(vs, skb, &md); + md->vni = vxh->vx_vni; + vs->rcv(vs, skb, md); return 0; drop: @@ -1247,6 +1286,9 @@ bad_flags: ntohl(vxh->vx_flags), ntohl(vxh->vx_vni)); error: + if (tun_dst) + dst_release((struct dst_entry *)tun_dst); + /* Return non vxlan pkt */ return 1; } @@ -1263,7 +1305,12 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, int err = 0; union vxlan_addr *remote_ip; - vni = ntohl(md->vni) >> 8; + /* For flow based devices, map all packets to VNI 0 */ + if (vs->flags & VXLAN_F_FLOW_BASED) + vni = 0; + else + vni = ntohl(md->vni) >> 8; + /* Is this VNI defined? */ vxlan = vxlan_vs_find_vni(vs, vni); if (!vxlan) @@ -1292,12 +1339,19 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, #endif } + if (md->tun_dst) { + skb_dst_set(skb, (struct dst_entry *)md->tun_dst); + md->tun_dst = NULL; + } + if ((vxlan->flags & VXLAN_F_LEARN) && vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) goto drop; skb_reset_network_header(skb); - skb->mark = md->gbp; + /* In flow-based mode, GBP is carried in dst_metadata */ + if (!(vs->flags & VXLAN_F_FLOW_BASED)) + skb->mark = md->gbp; if (oip6) err = IP6_ECN_decapsulate(oip6, skb); @@ -1330,6 +1384,9 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, return; drop: + if (md->tun_dst) + dst_release((struct dst_entry *)md->tun_dst); + /* Consume bad packet */ kfree_skb(skb); } @@ -1878,22 +1935,40 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_rdst *rdst, bool did_rsc) { + struct ip_tunnel_info *info = skb_tunnel_info(skb); struct vxlan_dev *vxlan = netdev_priv(dev); struct sock *sk = vxlan->vn_sock->sock->sk; struct rtable *rt = NULL; const struct iphdr *old_iph; struct flowi4 fl4; union vxlan_addr *dst; - struct vxlan_metadata md; + union vxlan_addr remote_ip; + struct vxlan_metadata _md; + struct vxlan_metadata *md = &_md; __be16 src_port = 0, dst_port; u32 vni; __be16 df = 0; __u8 tos, ttl; int err; + u32 flags = vxlan->flags; - dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; - vni = rdst->remote_vni; - dst = &rdst->remote_ip; + if (rdst) { + dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; + vni = rdst->remote_vni; + dst = &rdst->remote_ip; + } else { + if (!info) { + WARN_ONCE(1, "%s: Missing encapsulation instructions\n", + dev->name); + goto drop; + } + + dst_port = info->key.tp_dst ? : vxlan->dst_port; + vni = be64_to_cpu(info->key.tun_id); + remote_ip.sin.sin_family = AF_INET; + remote_ip.sin.sin_addr.s_addr = info->key.ipv4_dst; + dst = &remote_ip; + } if (vxlan_addr_any(dst)) { if (did_rsc) { @@ -1918,8 +1993,25 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, vxlan->port_max, true); if (dst->sa.sa_family == AF_INET) { + if (info) { + if (info->key.tun_flags & TUNNEL_DONT_FRAGMENT) + df = htons(IP_DF); + if (info->key.tun_flags & TUNNEL_CSUM) + flags |= VXLAN_F_UDP_CSUM; + else + flags &= ~VXLAN_F_UDP_CSUM; + + ttl = info->key.ipv4_ttl; + tos = info->key.ipv4_tos; + + if (info->options_len) + md = ip_tunnel_info_opts(info, sizeof(*md)); + } else { + md->gbp = skb->mark; + } + memset(&fl4, 0, sizeof(fl4)); - fl4.flowi4_oif = rdst->remote_ifindex; + fl4.flowi4_oif = rdst ? rdst->remote_ifindex : 0; fl4.flowi4_tos = RT_TOS(tos); fl4.flowi4_mark = skb->mark; fl4.flowi4_proto = IPPROTO_UDP; @@ -1958,14 +2050,12 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - md.vni = htonl(vni << 8); - md.gbp = skb->mark; - + md->vni = htonl(vni << 8); err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, - src_port, dst_port, &md, + src_port, dst_port, md, !net_eq(vxlan->net, dev_net(vxlan->dev)), - vxlan->flags); + flags); if (err < 0) { /* skb is already freed. */ skb = NULL; @@ -1980,7 +2070,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, u32 flags; memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_oif = rdst->remote_ifindex; + fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0; fl6.daddr = dst->sin6.sin6_addr; fl6.saddr = vxlan->saddr.sin6.sin6_addr; fl6.flowi6_mark = skb->mark; @@ -2018,11 +2108,11 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? : ip6_dst_hoplimit(ndst); - md.vni = htonl(vni << 8); - md.gbp = skb->mark; + md->vni = htonl(vni << 8); + md->gbp = skb->mark; err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr, - 0, ttl, src_port, dst_port, &md, + 0, ttl, src_port, dst_port, md, !net_eq(vxlan->net, dev_net(vxlan->dev)), vxlan->flags); #endif @@ -2051,6 +2141,7 @@ tx_free: static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); + const struct ip_tunnel_info *info = skb_tunnel_info(skb); struct ethhdr *eth; bool did_rsc = false; struct vxlan_rdst *rdst, *fdst = NULL; @@ -2078,6 +2169,12 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) #endif } + if (vxlan->flags & VXLAN_F_FLOW_BASED && + info && info->mode == IP_TUNNEL_INFO_TX) { + vxlan_xmit_one(skb, dev, NULL, false); + return NETDEV_TX_OK; + } + f = vxlan_find_mac(vxlan, eth->h_dest); did_rsc = false; @@ -2405,6 +2502,7 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = { [IFLA_VXLAN_RSC] = { .type = NLA_U8 }, [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 }, [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 }, + [IFLA_VXLAN_FLOWBASED] = { .type = NLA_U8 }, [IFLA_VXLAN_PORT] = { .type = NLA_U16 }, [IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 }, [IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 }, @@ -2681,6 +2779,10 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, if (data[IFLA_VXLAN_LIMIT]) vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); + if (data[IFLA_VXLAN_FLOWBASED] && + nla_get_u8(data[IFLA_VXLAN_FLOWBASED])) + vxlan->flags |= VXLAN_F_FLOW_BASED; + if (data[IFLA_VXLAN_PORT_RANGE]) { const struct ifla_vxlan_port_range *p = nla_data(data[IFLA_VXLAN_PORT_RANGE]); @@ -2777,6 +2879,7 @@ static size_t vxlan_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_RSC */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L2MISS */ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_L3MISS */ + nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_FLOWBASED */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_AGEING */ nla_total_size(sizeof(__u32)) + /* IFLA_VXLAN_LIMIT */ nla_total_size(sizeof(struct ifla_vxlan_port_range)) + @@ -2843,6 +2946,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(vxlan->flags & VXLAN_F_L2MISS)) || nla_put_u8(skb, IFLA_VXLAN_L3MISS, !!(vxlan->flags & VXLAN_F_L3MISS)) || + nla_put_u8(skb, IFLA_VXLAN_FLOWBASED, + !!(vxlan->flags & VXLAN_F_FLOW_BASED)) || nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) || nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) || nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port) || diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6bd96fe9416a2..648a2c2419930 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -3469,5 +3469,6 @@ static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) skb_network_header(skb); return hdr_len + skb_gso_transport_seglen(skb); } + #endif /* __KERNEL__ */ #endif /* _LINUX_SKBUFF_H */ diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 4f7694f3c7d0b..e843937fb30ae 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -8,6 +8,9 @@ struct metadata_dst { struct dst_entry dst; size_t opts_len; + union { + struct ip_tunnel_info tun_info; + } u; }; static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) @@ -20,6 +23,16 @@ static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) return NULL; } +static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb) +{ + struct metadata_dst *md_dst = skb_metadata_dst(skb); + + if (md_dst) + return &md_dst->u.tun_info; + + return NULL; +} + static inline bool skb_valid_dst(const struct sk_buff *skb) { struct dst_entry *dst = skb_dst(skb); diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 6b9d559ce5f5b..d11530f1c1e21 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -38,10 +38,19 @@ struct ip_tunnel_key { __be16 tp_dst; } __packed __aligned(4); /* Minimize padding. */ +/* Indicates whether the tunnel info structure represents receive + * or transmit tunnel parameters. + */ +enum { + IP_TUNNEL_INFO_RX, + IP_TUNNEL_INFO_TX, +}; + struct ip_tunnel_info { struct ip_tunnel_key key; const void *options; u8 options_len; + u8 mode; }; /* 6rd prefix/relay information */ @@ -284,6 +293,11 @@ static inline void iptunnel_xmit_stats(int err, } } +static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info, size_t n) +{ + return info + 1; +} + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 0082b5d33d7d3..80a2da29e0883 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -7,6 +7,7 @@ #include #include #include +#include #define VNI_HASH_BITS 10 #define VNI_HASH_SIZE (1< Date: Tue, 21 Jul 2015 10:43:59 +0200 Subject: [PATCH 1420/7006] route: Extend flow representation with tunnel key Add a new flowi_tunnel structure which is a subset of ip_tunnel_key to allow routes to match on tunnel metadata. For now, the tunnel id is added to flowi_tunnel which allows for routes to be bound to specific virtual tunnels. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/flow.h | 8 ++++++++ net/ipv4/fib_frontend.c | 2 ++ net/ipv4/route.c | 8 ++++++++ 3 files changed, 18 insertions(+) diff --git a/include/net/flow.h b/include/net/flow.h index 8109a159d1b3b..3098ae33a1784 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -19,6 +19,10 @@ #define LOOPBACK_IFINDEX 1 +struct flowi_tunnel { + __be64 tun_id; +}; + struct flowi_common { int flowic_oif; int flowic_iif; @@ -30,6 +34,7 @@ struct flowi_common { #define FLOWI_FLAG_ANYSRC 0x01 #define FLOWI_FLAG_KNOWN_NH 0x02 __u32 flowic_secid; + struct flowi_tunnel flowic_tun_key; }; union flowi_uli { @@ -66,6 +71,7 @@ struct flowi4 { #define flowi4_proto __fl_common.flowic_proto #define flowi4_flags __fl_common.flowic_flags #define flowi4_secid __fl_common.flowic_secid +#define flowi4_tun_key __fl_common.flowic_tun_key /* (saddr,daddr) must be grouped, same order as in IP header */ __be32 saddr; @@ -95,6 +101,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, fl4->flowi4_proto = proto; fl4->flowi4_flags = flags; fl4->flowi4_secid = 0; + fl4->flowi4_tun_key.tun_id = 0; fl4->daddr = daddr; fl4->saddr = saddr; fl4->fl4_dport = dport; @@ -165,6 +172,7 @@ struct flowi { #define flowi_proto u.__fl_common.flowic_proto #define flowi_flags u.__fl_common.flowic_flags #define flowi_secid u.__fl_common.flowic_secid +#define flowi_tun_key u.__fl_common.flowic_tun_key } __attribute__((__aligned__(BITS_PER_LONG/8))); static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 9b2019cc35860..6b98de0d79498 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -280,6 +280,7 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); fl4.flowi4_scope = scope; fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; + fl4.flowi4_tun_key.tun_id = 0; if (!fib_lookup(net, &fl4, &res, 0)) return FIB_RES_PREFSRC(net, res); } else { @@ -313,6 +314,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, fl4.saddr = dst; fl4.flowi4_tos = tos; fl4.flowi4_scope = RT_SCOPE_UNIVERSE; + fl4.flowi4_tun_key.tun_id = 0; no_addr = idev->ifa_list == NULL; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 4c8e84e758711..91da18be0a71e 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -91,6 +91,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ #include #endif #include +#include #define RT_FL_TOS(oldflp4) \ ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) @@ -1673,6 +1675,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, { struct fib_result res; struct in_device *in_dev = __in_dev_get_rcu(dev); + struct ip_tunnel_info *tun_info; struct flowi4 fl4; unsigned int flags = 0; u32 itag = 0; @@ -1690,6 +1693,11 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, by fib_lookup. */ + tun_info = skb_tunnel_info(skb); + if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX) + fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id; + else + fl4.flowi4_tun_key.tun_id = 0; skb_dst_drop(skb); if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) -- GitLab From 3093fbe7ff4bc7d1571fc217dade1cf80330a714 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:00 +0200 Subject: [PATCH 1421/7006] route: Per route IP tunnel metadata via lightweight tunnel This introduces a new IP tunnel lightweight tunnel type which allows to specify IP tunnel instructions per route. Only IPv4 is supported at this point. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 10 ++- include/net/dst_metadata.h | 12 +++- include/net/ip_tunnels.h | 7 +- include/uapi/linux/lwtunnel.h | 1 + include/uapi/linux/rtnetlink.h | 15 +++++ net/ipv4/ip_tunnel_core.c | 114 +++++++++++++++++++++++++++++++++ net/ipv4/route.c | 2 +- net/openvswitch/vport.h | 1 + 8 files changed, 157 insertions(+), 5 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 06c092b05a513..9486d7ec128c1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1935,7 +1935,7 @@ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, struct vxlan_rdst *rdst, bool did_rsc) { - struct ip_tunnel_info *info = skb_tunnel_info(skb); + struct ip_tunnel_info *info; struct vxlan_dev *vxlan = netdev_priv(dev); struct sock *sk = vxlan->vn_sock->sock->sk; struct rtable *rt = NULL; @@ -1952,6 +1952,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, int err; u32 flags = vxlan->flags; + /* FIXME: Support IPv6 */ + info = skb_tunnel_info(skb, AF_INET); + if (rdst) { dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; vni = rdst->remote_vni; @@ -2141,12 +2144,15 @@ tx_free: static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) { struct vxlan_dev *vxlan = netdev_priv(dev); - const struct ip_tunnel_info *info = skb_tunnel_info(skb); + const struct ip_tunnel_info *info; struct ethhdr *eth; bool did_rsc = false; struct vxlan_rdst *rdst, *fdst = NULL; struct vxlan_fdb *f; + /* FIXME: Support IPv6 */ + info = skb_tunnel_info(skb, AF_INET); + skb_reset_mac_header(skb); eth = eth_hdr(skb); diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index e843937fb30ae..7b03068946634 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -23,13 +23,23 @@ static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) return NULL; } -static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb) +static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb, + int family) { struct metadata_dst *md_dst = skb_metadata_dst(skb); + struct rtable *rt; if (md_dst) return &md_dst->u.tun_info; + switch (family) { + case AF_INET: + rt = (struct rtable *)skb_dst(skb); + if (rt && rt->rt_lwtstate) + return lwt_tun_info(rt->rt_lwtstate); + break; + } + return NULL; } diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index d11530f1c1e21..0b7e18cfa0b47 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -9,9 +9,9 @@ #include #include #include -#include #include #include +#include #if IS_ENABLED(CONFIG_IPV6) #include @@ -298,6 +298,11 @@ static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info, size_t n) return info + 1; } +static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) +{ + return (struct ip_tunnel_info *)lwtstate->data; +} + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ diff --git a/include/uapi/linux/lwtunnel.h b/include/uapi/linux/lwtunnel.h index aa611d931a313..31377bbea3f8f 100644 --- a/include/uapi/linux/lwtunnel.h +++ b/include/uapi/linux/lwtunnel.h @@ -6,6 +6,7 @@ enum lwtunnel_encap_types { LWTUNNEL_ENCAP_NONE, LWTUNNEL_ENCAP_MPLS, + LWTUNNEL_ENCAP_IP, __LWTUNNEL_ENCAP_MAX, }; diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 0d3d3cc43356e..47d24cb3fbc1f 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -286,6 +286,21 @@ enum rt_class_t { /* Routing message attributes */ +enum ip_tunnel_t { + IP_TUN_UNSPEC, + IP_TUN_ID, + IP_TUN_DST, + IP_TUN_SRC, + IP_TUN_TTL, + IP_TUN_TOS, + IP_TUN_SPORT, + IP_TUN_DPORT, + IP_TUN_FLAGS, + __IP_TUN_MAX, +}; + +#define IP_TUN_MAX (__IP_TUN_MAX - 1) + enum rtattr_type_t { RTA_UNSPEC, RTA_DST, diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 6a51a71a6c67a..025b76e803fde 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -190,3 +190,117 @@ struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, return tot; } EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64); + +static const struct nla_policy ip_tun_policy[IP_TUN_MAX + 1] = { + [IP_TUN_ID] = { .type = NLA_U64 }, + [IP_TUN_DST] = { .type = NLA_U32 }, + [IP_TUN_SRC] = { .type = NLA_U32 }, + [IP_TUN_TTL] = { .type = NLA_U8 }, + [IP_TUN_TOS] = { .type = NLA_U8 }, + [IP_TUN_SPORT] = { .type = NLA_U16 }, + [IP_TUN_DPORT] = { .type = NLA_U16 }, + [IP_TUN_FLAGS] = { .type = NLA_U16 }, +}; + +static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr, + struct lwtunnel_state **ts) +{ + struct ip_tunnel_info *tun_info; + struct lwtunnel_state *new_state; + struct nlattr *tb[IP_TUN_MAX + 1]; + int err; + + err = nla_parse_nested(tb, IP_TUN_MAX, attr, ip_tun_policy); + if (err < 0) + return err; + + new_state = lwtunnel_state_alloc(sizeof(*tun_info)); + if (!new_state) + return -ENOMEM; + + new_state->type = LWTUNNEL_ENCAP_IP; + + tun_info = lwt_tun_info(new_state); + + if (tb[IP_TUN_ID]) + tun_info->key.tun_id = nla_get_u64(tb[IP_TUN_ID]); + + if (tb[IP_TUN_DST]) + tun_info->key.ipv4_dst = nla_get_be32(tb[IP_TUN_DST]); + + if (tb[IP_TUN_SRC]) + tun_info->key.ipv4_src = nla_get_be32(tb[IP_TUN_SRC]); + + if (tb[IP_TUN_TTL]) + tun_info->key.ipv4_ttl = nla_get_u8(tb[IP_TUN_TTL]); + + if (tb[IP_TUN_TOS]) + tun_info->key.ipv4_tos = nla_get_u8(tb[IP_TUN_TOS]); + + if (tb[IP_TUN_SPORT]) + tun_info->key.tp_src = nla_get_be16(tb[IP_TUN_SPORT]); + + if (tb[IP_TUN_DPORT]) + tun_info->key.tp_dst = nla_get_be16(tb[IP_TUN_DPORT]); + + if (tb[IP_TUN_FLAGS]) + tun_info->key.tun_flags = nla_get_u16(tb[IP_TUN_FLAGS]); + + tun_info->mode = IP_TUNNEL_INFO_TX; + tun_info->options = NULL; + tun_info->options_len = 0; + + *ts = new_state; + + return 0; +} + +static int ip_tun_fill_encap_info(struct sk_buff *skb, + struct lwtunnel_state *lwtstate) +{ + struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate); + + if (nla_put_u64(skb, IP_TUN_ID, tun_info->key.tun_id) || + nla_put_be32(skb, IP_TUN_DST, tun_info->key.ipv4_dst) || + nla_put_be32(skb, IP_TUN_SRC, tun_info->key.ipv4_src) || + nla_put_u8(skb, IP_TUN_TOS, tun_info->key.ipv4_tos) || + nla_put_u8(skb, IP_TUN_TTL, tun_info->key.ipv4_ttl) || + nla_put_u16(skb, IP_TUN_SPORT, tun_info->key.tp_src) || + nla_put_u16(skb, IP_TUN_DPORT, tun_info->key.tp_dst) || + nla_put_u16(skb, IP_TUN_FLAGS, tun_info->key.tun_flags)) + return -ENOMEM; + + return 0; +} + +static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate) +{ + return nla_total_size(8) /* IP_TUN_ID */ + + nla_total_size(4) /* IP_TUN_DST */ + + nla_total_size(4) /* IP_TUN_SRC */ + + nla_total_size(1) /* IP_TUN_TOS */ + + nla_total_size(1) /* IP_TUN_TTL */ + + nla_total_size(2) /* IP_TUN_SPORT */ + + nla_total_size(2) /* IP_TUN_DPORT */ + + nla_total_size(2); /* IP_TUN_FLAGS */ +} + +static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { + .build_state = ip_tun_build_state, + .fill_encap = ip_tun_fill_encap_info, + .get_encap_size = ip_tun_encap_nlsize, +}; + +static int __init ip_tunnel_core_init(void) +{ + lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); + + return 0; +} +module_init(ip_tunnel_core_init); + +static void __exit ip_tunnel_core_exit(void) +{ + lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); +} +module_exit(ip_tunnel_core_exit); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 91da18be0a71e..519ec232818d4 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1693,7 +1693,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, by fib_lookup. */ - tun_info = skb_tunnel_info(skb); + tun_info = skb_tunnel_info(skb, AF_INET); if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX) fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id; else diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 4750fb673a9fc..75d68248ba691 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "datapath.h" -- GitLab From e7030878fc8448492b6e5cecd574043f63271298 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:01 +0200 Subject: [PATCH 1422/7006] fib: Add fib rule match on tunnel id This add the ability to select a routing table based on the tunnel id which allows to maintain separate routing tables for each virtual tunnel network. ip rule add from all tunnel-id 100 lookup 100 ip rule add from all tunnel-id 200 lookup 200 A new static key controls the collection of metadata at tunnel level upon demand. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 3 ++- include/net/fib_rules.h | 1 + include/net/ip_tunnels.h | 11 +++++++++++ include/uapi/linux/fib_rules.h | 2 +- net/core/fib_rules.c | 24 ++++++++++++++++++++++-- net/ipv4/ip_tunnel_core.c | 16 ++++++++++++++++ 6 files changed, 53 insertions(+), 4 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 9486d7ec128c1..2587ac84f71a9 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -143,7 +143,8 @@ static struct workqueue_struct *vxlan_wq; static inline bool vxlan_collect_metadata(struct vxlan_sock *vs) { - return vs->flags & VXLAN_F_COLLECT_METADATA; + return vs->flags & VXLAN_F_COLLECT_METADATA || + ip_tunnel_collect_metadata(); } #if IS_ENABLED(CONFIG_IPV6) diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 903a55efbffe5..4e8f804f45898 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -19,6 +19,7 @@ struct fib_rule { u8 action; /* 3 bytes hole, try to use */ u32 target; + __be64 tun_id; struct fib_rule __rcu *ctarget; struct net *fr_net; diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 0b7e18cfa0b47..0a5a7763eec24 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -303,6 +303,17 @@ static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstat return (struct ip_tunnel_info *)lwtstate->data; } +extern struct static_key ip_tunnel_metadata_cnt; + +/* Returns > 0 if metadata should be collected */ +static inline int ip_tunnel_collect_metadata(void) +{ + return static_key_false(&ip_tunnel_metadata_cnt); +} + +void ip_tunnel_need_metadata(void); +void ip_tunnel_unneed_metadata(void); + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ diff --git a/include/uapi/linux/fib_rules.h b/include/uapi/linux/fib_rules.h index 2b82d7e30974f..96161b8202b5d 100644 --- a/include/uapi/linux/fib_rules.h +++ b/include/uapi/linux/fib_rules.h @@ -43,7 +43,7 @@ enum { FRA_UNUSED5, FRA_FWMARK, /* mark */ FRA_FLOW, /* flow/class id */ - FRA_UNUSED6, + FRA_TUN_ID, FRA_SUPPRESS_IFGROUP, FRA_SUPPRESS_PREFIXLEN, FRA_TABLE, /* Extended table id */ diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 9a12668f7d627..ae8306e7c56f9 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -16,6 +16,7 @@ #include #include #include +#include int fib_default_rule_add(struct fib_rules_ops *ops, u32 pref, u32 table, u32 flags) @@ -186,6 +187,9 @@ static int fib_rule_match(struct fib_rule *rule, struct fib_rules_ops *ops, if ((rule->mark ^ fl->flowi_mark) & rule->mark_mask) goto out; + if (rule->tun_id && (rule->tun_id != fl->flowi_tun_key.tun_id)) + goto out; + ret = ops->match(rule, fl, flags); out: return (rule->flags & FIB_RULE_INVERT) ? !ret : ret; @@ -330,6 +334,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) if (tb[FRA_FWMASK]) rule->mark_mask = nla_get_u32(tb[FRA_FWMASK]); + if (tb[FRA_TUN_ID]) + rule->tun_id = nla_get_be64(tb[FRA_TUN_ID]); + rule->action = frh->action; rule->flags = frh->flags; rule->table = frh_get_table(frh, tb); @@ -407,6 +414,9 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) if (unresolved) ops->unresolved_rules++; + if (rule->tun_id) + ip_tunnel_need_metadata(); + notify_rule_change(RTM_NEWRULE, rule, ops, nlh, NETLINK_CB(skb).portid); flush_route_cache(ops); rules_ops_put(ops); @@ -473,6 +483,10 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) (rule->mark_mask != nla_get_u32(tb[FRA_FWMASK]))) continue; + if (tb[FRA_TUN_ID] && + (rule->tun_id != nla_get_be64(tb[FRA_TUN_ID]))) + continue; + if (!ops->compare(rule, frh, tb)) continue; @@ -487,6 +501,9 @@ static int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh) goto errout; } + if (rule->tun_id) + ip_tunnel_unneed_metadata(); + list_del_rcu(&rule->list); if (rule->action == FR_ACT_GOTO) { @@ -535,7 +552,8 @@ static inline size_t fib_rule_nlmsg_size(struct fib_rules_ops *ops, + nla_total_size(4) /* FRA_SUPPRESS_PREFIXLEN */ + nla_total_size(4) /* FRA_SUPPRESS_IFGROUP */ + nla_total_size(4) /* FRA_FWMARK */ - + nla_total_size(4); /* FRA_FWMASK */ + + nla_total_size(4) /* FRA_FWMASK */ + + nla_total_size(8); /* FRA_TUN_ID */ if (ops->nlmsg_payload) payload += ops->nlmsg_payload(rule); @@ -591,7 +609,9 @@ static int fib_nl_fill_rule(struct sk_buff *skb, struct fib_rule *rule, ((rule->mark_mask || rule->mark) && nla_put_u32(skb, FRA_FWMASK, rule->mark_mask)) || (rule->target && - nla_put_u32(skb, FRA_GOTO, rule->target))) + nla_put_u32(skb, FRA_GOTO, rule->target)) || + (rule->tun_id && + nla_put_be64(skb, FRA_TUN_ID, rule->tun_id))) goto nla_put_failure; if (rule->suppress_ifgroup != -1) { diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 025b76e803fde..630e6d5712e8e 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -304,3 +305,18 @@ static void __exit ip_tunnel_core_exit(void) lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); } module_exit(ip_tunnel_core_exit); + +struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; +EXPORT_SYMBOL(ip_tunnel_metadata_cnt); + +void ip_tunnel_need_metadata(void) +{ + static_key_slow_inc(&ip_tunnel_metadata_cnt); +} +EXPORT_SYMBOL_GPL(ip_tunnel_need_metadata); + +void ip_tunnel_unneed_metadata(void) +{ + static_key_slow_dec(&ip_tunnel_metadata_cnt); +} +EXPORT_SYMBOL_GPL(ip_tunnel_unneed_metadata); -- GitLab From 0dfbdf4102b9303d3ddf2177c0220098ff99f6de Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:02 +0200 Subject: [PATCH 1423/7006] vxlan: Factor out device configuration This factors out the device configuration out of the RTNL newlink API which allows for in-kernel creation of VXLAN net_devices. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 332 +++++++++++++++++++++++--------------------- include/net/vxlan.h | 59 ++++++++ 2 files changed, 236 insertions(+), 155 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 2587ac84f71a9..30e1f215af736 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -55,10 +55,6 @@ #define PORT_HASH_BITS 8 #define PORT_HASH_SIZE (1<remote_ip)) goto nla_put_failure; - if (rdst->remote_port && rdst->remote_port != vxlan->dst_port && + if (rdst->remote_port && rdst->remote_port != vxlan->cfg.dst_port && nla_put_be16(skb, NDA_PORT, rdst->remote_port)) goto nla_put_failure; if (rdst->remote_vni != vxlan->default_dst.remote_vni && @@ -756,7 +713,8 @@ static int vxlan_fdb_create(struct vxlan_dev *vxlan, if (!(flags & NLM_F_CREATE)) return -ENOENT; - if (vxlan->addrmax && vxlan->addrcnt >= vxlan->addrmax) + if (vxlan->cfg.addrmax && + vxlan->addrcnt >= vxlan->cfg.addrmax) return -ENOSPC; /* Disallow replace to add a multicast entry */ @@ -842,7 +800,7 @@ static int vxlan_fdb_parse(struct nlattr *tb[], struct vxlan_dev *vxlan, return -EINVAL; *port = nla_get_be16(tb[NDA_PORT]); } else { - *port = vxlan->dst_port; + *port = vxlan->cfg.dst_port; } if (tb[NDA_VNI]) { @@ -1028,7 +986,7 @@ static bool vxlan_snoop(struct net_device *dev, vxlan_fdb_create(vxlan, src_mac, src_ip, NUD_REACHABLE, NLM_F_EXCL|NLM_F_CREATE, - vxlan->dst_port, + vxlan->cfg.dst_port, vxlan->default_dst.remote_vni, 0, NTF_SELF); spin_unlock(&vxlan->hash_lock); @@ -1957,7 +1915,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, info = skb_tunnel_info(skb, AF_INET); if (rdst) { - dst_port = rdst->remote_port ? rdst->remote_port : vxlan->dst_port; + dst_port = rdst->remote_port ? rdst->remote_port : vxlan->cfg.dst_port; vni = rdst->remote_vni; dst = &rdst->remote_ip; } else { @@ -1967,7 +1925,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, goto drop; } - dst_port = info->key.tp_dst ? : vxlan->dst_port; + dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; vni = be64_to_cpu(info->key.tun_id); remote_ip.sin.sin_family = AF_INET; remote_ip.sin.sin_addr.s_addr = info->key.ipv4_dst; @@ -1985,16 +1943,16 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, old_iph = ip_hdr(skb); - ttl = vxlan->ttl; + ttl = vxlan->cfg.ttl; if (!ttl && vxlan_addr_multicast(dst)) ttl = 1; - tos = vxlan->tos; + tos = vxlan->cfg.tos; if (tos == 1) tos = ip_tunnel_get_dsfield(old_iph, skb); - src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->port_min, - vxlan->port_max, true); + src_port = udp_flow_src_port(dev_net(dev), skb, vxlan->cfg.port_min, + vxlan->cfg.port_max, true); if (dst->sa.sa_family == AF_INET) { if (info) { @@ -2020,7 +1978,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, fl4.flowi4_mark = skb->mark; fl4.flowi4_proto = IPPROTO_UDP; fl4.daddr = dst->sin.sin_addr.s_addr; - fl4.saddr = vxlan->saddr.sin.sin_addr.s_addr; + fl4.saddr = vxlan->cfg.saddr.sin.sin_addr.s_addr; rt = ip_route_output_key(vxlan->net, &fl4); if (IS_ERR(rt)) { @@ -2076,7 +2034,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, memset(&fl6, 0, sizeof(fl6)); fl6.flowi6_oif = rdst ? rdst->remote_ifindex : 0; fl6.daddr = dst->sin6.sin6_addr; - fl6.saddr = vxlan->saddr.sin6.sin6_addr; + fl6.saddr = vxlan->cfg.saddr.sin6.sin6_addr; fl6.flowi6_mark = skb->mark; fl6.flowi6_proto = IPPROTO_UDP; @@ -2247,7 +2205,7 @@ static void vxlan_cleanup(unsigned long arg) if (f->state & NUD_PERMANENT) continue; - timeout = f->used + vxlan->age_interval * HZ; + timeout = f->used + vxlan->cfg.age_interval * HZ; if (time_before_eq(timeout, jiffies)) { netdev_dbg(vxlan->dev, "garbage collect %pM\n", @@ -2311,8 +2269,8 @@ static int vxlan_open(struct net_device *dev) struct vxlan_sock *vs; int ret = 0; - vs = vxlan_sock_add(vxlan->net, vxlan->dst_port, vxlan_rcv, NULL, - false, vxlan->flags); + vs = vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, vxlan_rcv, + NULL, vxlan->cfg.no_share, vxlan->flags); if (IS_ERR(vs)) return PTR_ERR(vs); @@ -2326,7 +2284,7 @@ static int vxlan_open(struct net_device *dev) } } - if (vxlan->age_interval) + if (vxlan->cfg.age_interval) mod_timer(&vxlan->age_timer, jiffies + FDB_AGE_INTERVAL); return ret; @@ -2484,7 +2442,7 @@ static void vxlan_setup(struct net_device *dev) vxlan->age_timer.function = vxlan_cleanup; vxlan->age_timer.data = (unsigned long) vxlan; - vxlan->dst_port = htons(vxlan_port); + vxlan->cfg.dst_port = htons(vxlan_port); vxlan->dev = dev; @@ -2684,54 +2642,35 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, } EXPORT_SYMBOL_GPL(vxlan_sock_add); -static int vxlan_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) +static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, + struct vxlan_config *conf) { struct vxlan_net *vn = net_generic(src_net, vxlan_net_id); struct vxlan_dev *vxlan = netdev_priv(dev); struct vxlan_rdst *dst = &vxlan->default_dst; - __u32 vni; int err; bool use_ipv6 = false; - - if (!data[IFLA_VXLAN_ID]) - return -EINVAL; + __be16 default_port = vxlan->cfg.dst_port; vxlan->net = src_net; - vni = nla_get_u32(data[IFLA_VXLAN_ID]); - dst->remote_vni = vni; + dst->remote_vni = conf->vni; - /* Unless IPv6 is explicitly requested, assume IPv4 */ - dst->remote_ip.sa.sa_family = AF_INET; - if (data[IFLA_VXLAN_GROUP]) { - dst->remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); - } else if (data[IFLA_VXLAN_GROUP6]) { - if (!IS_ENABLED(CONFIG_IPV6)) - return -EPFNOSUPPORT; - - dst->remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); - dst->remote_ip.sa.sa_family = AF_INET6; - use_ipv6 = true; - } + memcpy(&dst->remote_ip, &conf->remote_ip, sizeof(conf->remote_ip)); - if (data[IFLA_VXLAN_LOCAL]) { - vxlan->saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); - vxlan->saddr.sa.sa_family = AF_INET; - } else if (data[IFLA_VXLAN_LOCAL6]) { - if (!IS_ENABLED(CONFIG_IPV6)) - return -EPFNOSUPPORT; + /* Unless IPv6 is explicitly requested, assume IPv4 */ + if (!dst->remote_ip.sa.sa_family) + dst->remote_ip.sa.sa_family = AF_INET; - /* TODO: respect scope id */ - vxlan->saddr.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_LOCAL6]); - vxlan->saddr.sa.sa_family = AF_INET6; + if (dst->remote_ip.sa.sa_family == AF_INET6 || + vxlan->cfg.saddr.sa.sa_family == AF_INET6) use_ipv6 = true; - } - if (data[IFLA_VXLAN_LINK] && - (dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) { + if (conf->remote_ifindex) { struct net_device *lowerdev - = __dev_get_by_index(src_net, dst->remote_ifindex); + = __dev_get_by_index(src_net, conf->remote_ifindex); + + dst->remote_ifindex = conf->remote_ifindex; if (!lowerdev) { pr_info("ifindex %d does not exist\n", dst->remote_ifindex); @@ -2749,7 +2688,7 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, } #endif - if (!tb[IFLA_MTU]) + if (!conf->mtu) dev->mtu = lowerdev->mtu - (use_ipv6 ? VXLAN6_HEADROOM : VXLAN_HEADROOM); dev->needed_headroom = lowerdev->hard_header_len + @@ -2757,105 +2696,188 @@ static int vxlan_newlink(struct net *src_net, struct net_device *dev, } else if (use_ipv6) vxlan->flags |= VXLAN_F_IPV6; + memcpy(&vxlan->cfg, conf, sizeof(*conf)); + if (!vxlan->cfg.dst_port) + vxlan->cfg.dst_port = default_port; + vxlan->flags |= conf->flags; + + if (!vxlan->cfg.age_interval) + vxlan->cfg.age_interval = FDB_AGE_DEFAULT; + + if (vxlan_find_vni(src_net, conf->vni, use_ipv6 ? AF_INET6 : AF_INET, + vxlan->cfg.dst_port, vxlan->flags)) + return -EEXIST; + + dev->ethtool_ops = &vxlan_ethtool_ops; + + /* create an fdb entry for a valid default destination */ + if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { + err = vxlan_fdb_create(vxlan, all_zeros_mac, + &vxlan->default_dst.remote_ip, + NUD_REACHABLE|NUD_PERMANENT, + NLM_F_EXCL|NLM_F_CREATE, + vxlan->cfg.dst_port, + vxlan->default_dst.remote_vni, + vxlan->default_dst.remote_ifindex, + NTF_SELF); + if (err) + return err; + } + + err = register_netdevice(dev); + if (err) { + vxlan_fdb_delete_default(vxlan); + return err; + } + + list_add(&vxlan->next, &vn->vxlan_list); + + return 0; +} + +struct net_device *vxlan_dev_create(struct net *net, const char *name, + u8 name_assign_type, struct vxlan_config *conf) +{ + struct nlattr *tb[IFLA_MAX+1]; + struct net_device *dev; + int err; + + memset(&tb, 0, sizeof(tb)); + + dev = rtnl_create_link(net, name, name_assign_type, + &vxlan_link_ops, tb); + if (IS_ERR(dev)) + return dev; + + err = vxlan_dev_configure(net, dev, conf); + if (err < 0) { + free_netdev(dev); + return ERR_PTR(err); + } + + return dev; +} +EXPORT_SYMBOL_GPL(vxlan_dev_create); + +static int vxlan_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + struct vxlan_config conf; + int err; + + if (!data[IFLA_VXLAN_ID]) + return -EINVAL; + + memset(&conf, 0, sizeof(conf)); + conf.vni = nla_get_u32(data[IFLA_VXLAN_ID]); + + if (data[IFLA_VXLAN_GROUP]) { + conf.remote_ip.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_GROUP]); + } else if (data[IFLA_VXLAN_GROUP6]) { + if (!IS_ENABLED(CONFIG_IPV6)) + return -EPFNOSUPPORT; + + conf.remote_ip.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_GROUP6]); + conf.remote_ip.sa.sa_family = AF_INET6; + } + + if (data[IFLA_VXLAN_LOCAL]) { + conf.saddr.sin.sin_addr.s_addr = nla_get_in_addr(data[IFLA_VXLAN_LOCAL]); + conf.saddr.sa.sa_family = AF_INET; + } else if (data[IFLA_VXLAN_LOCAL6]) { + if (!IS_ENABLED(CONFIG_IPV6)) + return -EPFNOSUPPORT; + + /* TODO: respect scope id */ + conf.saddr.sin6.sin6_addr = nla_get_in6_addr(data[IFLA_VXLAN_LOCAL6]); + conf.saddr.sa.sa_family = AF_INET6; + } + + if (data[IFLA_VXLAN_LINK]) + conf.remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]); + if (data[IFLA_VXLAN_TOS]) - vxlan->tos = nla_get_u8(data[IFLA_VXLAN_TOS]); + conf.tos = nla_get_u8(data[IFLA_VXLAN_TOS]); if (data[IFLA_VXLAN_TTL]) - vxlan->ttl = nla_get_u8(data[IFLA_VXLAN_TTL]); + conf.ttl = nla_get_u8(data[IFLA_VXLAN_TTL]); if (!data[IFLA_VXLAN_LEARNING] || nla_get_u8(data[IFLA_VXLAN_LEARNING])) - vxlan->flags |= VXLAN_F_LEARN; + conf.flags |= VXLAN_F_LEARN; if (data[IFLA_VXLAN_AGEING]) - vxlan->age_interval = nla_get_u32(data[IFLA_VXLAN_AGEING]); - else - vxlan->age_interval = FDB_AGE_DEFAULT; + conf.age_interval = nla_get_u32(data[IFLA_VXLAN_AGEING]); if (data[IFLA_VXLAN_PROXY] && nla_get_u8(data[IFLA_VXLAN_PROXY])) - vxlan->flags |= VXLAN_F_PROXY; + conf.flags |= VXLAN_F_PROXY; if (data[IFLA_VXLAN_RSC] && nla_get_u8(data[IFLA_VXLAN_RSC])) - vxlan->flags |= VXLAN_F_RSC; + conf.flags |= VXLAN_F_RSC; if (data[IFLA_VXLAN_L2MISS] && nla_get_u8(data[IFLA_VXLAN_L2MISS])) - vxlan->flags |= VXLAN_F_L2MISS; + conf.flags |= VXLAN_F_L2MISS; if (data[IFLA_VXLAN_L3MISS] && nla_get_u8(data[IFLA_VXLAN_L3MISS])) - vxlan->flags |= VXLAN_F_L3MISS; + conf.flags |= VXLAN_F_L3MISS; if (data[IFLA_VXLAN_LIMIT]) - vxlan->addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); + conf.addrmax = nla_get_u32(data[IFLA_VXLAN_LIMIT]); if (data[IFLA_VXLAN_FLOWBASED] && nla_get_u8(data[IFLA_VXLAN_FLOWBASED])) - vxlan->flags |= VXLAN_F_FLOW_BASED; + conf.flags |= VXLAN_F_FLOW_BASED; if (data[IFLA_VXLAN_PORT_RANGE]) { const struct ifla_vxlan_port_range *p = nla_data(data[IFLA_VXLAN_PORT_RANGE]); - vxlan->port_min = ntohs(p->low); - vxlan->port_max = ntohs(p->high); + conf.port_min = ntohs(p->low); + conf.port_max = ntohs(p->high); } if (data[IFLA_VXLAN_PORT]) - vxlan->dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]); + conf.dst_port = nla_get_be16(data[IFLA_VXLAN_PORT]); if (data[IFLA_VXLAN_UDP_CSUM] && nla_get_u8(data[IFLA_VXLAN_UDP_CSUM])) - vxlan->flags |= VXLAN_F_UDP_CSUM; + conf.flags |= VXLAN_F_UDP_CSUM; if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] && nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_TX])) - vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; + conf.flags |= VXLAN_F_UDP_ZERO_CSUM6_TX; if (data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] && nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX])) - vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; + conf.flags |= VXLAN_F_UDP_ZERO_CSUM6_RX; if (data[IFLA_VXLAN_REMCSUM_TX] && nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX])) - vxlan->flags |= VXLAN_F_REMCSUM_TX; + conf.flags |= VXLAN_F_REMCSUM_TX; if (data[IFLA_VXLAN_REMCSUM_RX] && nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX])) - vxlan->flags |= VXLAN_F_REMCSUM_RX; + conf.flags |= VXLAN_F_REMCSUM_RX; if (data[IFLA_VXLAN_GBP]) - vxlan->flags |= VXLAN_F_GBP; + conf.flags |= VXLAN_F_GBP; if (data[IFLA_VXLAN_REMCSUM_NOPARTIAL]) - vxlan->flags |= VXLAN_F_REMCSUM_NOPARTIAL; + conf.flags |= VXLAN_F_REMCSUM_NOPARTIAL; - if (vxlan_find_vni(src_net, vni, use_ipv6 ? AF_INET6 : AF_INET, - vxlan->dst_port, vxlan->flags)) { - pr_info("duplicate VNI %u\n", vni); - return -EEXIST; - } - - dev->ethtool_ops = &vxlan_ethtool_ops; + err = vxlan_dev_configure(src_net, dev, &conf); + switch (err) { + case -ENODEV: + pr_info("ifindex %d does not exist\n", conf.remote_ifindex); + break; - /* create an fdb entry for a valid default destination */ - if (!vxlan_addr_any(&vxlan->default_dst.remote_ip)) { - err = vxlan_fdb_create(vxlan, all_zeros_mac, - &vxlan->default_dst.remote_ip, - NUD_REACHABLE|NUD_PERMANENT, - NLM_F_EXCL|NLM_F_CREATE, - vxlan->dst_port, - vxlan->default_dst.remote_vni, - vxlan->default_dst.remote_ifindex, - NTF_SELF); - if (err) - return err; - } + case -EPERM: + pr_info("IPv6 is disabled via sysctl\n"); + break; - err = register_netdevice(dev); - if (err) { - vxlan_fdb_delete_default(vxlan); - return err; + case -EEXIST: + pr_info("duplicate VNI %u\n", conf.vni); + break; } - list_add(&vxlan->next, &vn->vxlan_list); - - return 0; + return err; } static void vxlan_dellink(struct net_device *dev, struct list_head *head) @@ -2904,8 +2926,8 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) const struct vxlan_dev *vxlan = netdev_priv(dev); const struct vxlan_rdst *dst = &vxlan->default_dst; struct ifla_vxlan_port_range ports = { - .low = htons(vxlan->port_min), - .high = htons(vxlan->port_max), + .low = htons(vxlan->cfg.port_min), + .high = htons(vxlan->cfg.port_max), }; if (nla_put_u32(skb, IFLA_VXLAN_ID, dst->remote_vni)) @@ -2928,22 +2950,22 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) if (dst->remote_ifindex && nla_put_u32(skb, IFLA_VXLAN_LINK, dst->remote_ifindex)) goto nla_put_failure; - if (!vxlan_addr_any(&vxlan->saddr)) { - if (vxlan->saddr.sa.sa_family == AF_INET) { + if (!vxlan_addr_any(&vxlan->cfg.saddr)) { + if (vxlan->cfg.saddr.sa.sa_family == AF_INET) { if (nla_put_in_addr(skb, IFLA_VXLAN_LOCAL, - vxlan->saddr.sin.sin_addr.s_addr)) + vxlan->cfg.saddr.sin.sin_addr.s_addr)) goto nla_put_failure; #if IS_ENABLED(CONFIG_IPV6) } else { if (nla_put_in6_addr(skb, IFLA_VXLAN_LOCAL6, - &vxlan->saddr.sin6.sin6_addr)) + &vxlan->cfg.saddr.sin6.sin6_addr)) goto nla_put_failure; #endif } } - if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->ttl) || - nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->tos) || + if (nla_put_u8(skb, IFLA_VXLAN_TTL, vxlan->cfg.ttl) || + nla_put_u8(skb, IFLA_VXLAN_TOS, vxlan->cfg.tos) || nla_put_u8(skb, IFLA_VXLAN_LEARNING, !!(vxlan->flags & VXLAN_F_LEARN)) || nla_put_u8(skb, IFLA_VXLAN_PROXY, @@ -2955,9 +2977,9 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(vxlan->flags & VXLAN_F_L3MISS)) || nla_put_u8(skb, IFLA_VXLAN_FLOWBASED, !!(vxlan->flags & VXLAN_F_FLOW_BASED)) || - nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->age_interval) || - nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->addrmax) || - nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->dst_port) || + nla_put_u32(skb, IFLA_VXLAN_AGEING, vxlan->cfg.age_interval) || + nla_put_u32(skb, IFLA_VXLAN_LIMIT, vxlan->cfg.addrmax) || + nla_put_be16(skb, IFLA_VXLAN_PORT, vxlan->cfg.dst_port) || nla_put_u8(skb, IFLA_VXLAN_UDP_CSUM, !!(vxlan->flags & VXLAN_F_UDP_CSUM)) || nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX, diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 80a2da29e0883..19535f85eb2c9 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -95,6 +95,11 @@ struct vxlanhdr { #define VXLAN_VNI_MASK (VXLAN_VID_MASK << 8) #define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr)) +#define VNI_HASH_BITS 10 +#define VNI_HASH_SIZE (1< Date: Tue, 21 Jul 2015 10:44:03 +0200 Subject: [PATCH 1424/7006] openvswitch: Make tunnel set action attach a metadata dst Utilize the new metadata dst to attach encapsulation instructions to the skb. The existing egress_tun_info via the OVS_CB() is left in place until all tunnel vports have been converted to the new method. Signed-off-by: Thomas Graf Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/actions.c | 10 +++++- net/openvswitch/datapath.c | 8 ++--- net/openvswitch/flow.h | 5 +++ net/openvswitch/flow_netlink.c | 64 ++++++++++++++++++++++++++++++---- net/openvswitch/flow_netlink.h | 1 + net/openvswitch/flow_table.c | 4 ++- 6 files changed, 79 insertions(+), 13 deletions(-) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 27c1687cfd927..cf04c2f8b32a5 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -733,7 +733,15 @@ static int execute_set_action(struct sk_buff *skb, { /* Only tunnel set execution is supported without a mask. */ if (nla_type(a) == OVS_KEY_ATTR_TUNNEL_INFO) { - OVS_CB(skb)->egress_tun_info = nla_data(a); + struct ovs_tunnel_info *tun = nla_data(a); + + skb_dst_drop(skb); + dst_hold((struct dst_entry *)tun->tun_dst); + skb_dst_set(skb, (struct dst_entry *)tun->tun_dst); + + /* FIXME: Remove when all vports have been converted */ + OVS_CB(skb)->egress_tun_info = &tun->tun_dst->u.tun_info; + return 0; } diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index ff8c4a4c16098..02082107c74ce 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1018,7 +1018,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) } ovs_unlock(); - ovs_nla_free_flow_actions(old_acts); + ovs_nla_free_flow_actions_rcu(old_acts); ovs_flow_free(new_flow, false); } @@ -1030,7 +1030,7 @@ err_unlock_ovs: ovs_unlock(); kfree_skb(reply); err_kfree_acts: - kfree(acts); + ovs_nla_free_flow_actions(acts); err_kfree_flow: ovs_flow_free(new_flow, false); error: @@ -1157,7 +1157,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) if (reply) ovs_notify(&dp_flow_genl_family, reply, info); if (old_acts) - ovs_nla_free_flow_actions(old_acts); + ovs_nla_free_flow_actions_rcu(old_acts); return 0; @@ -1165,7 +1165,7 @@ err_unlock_ovs: ovs_unlock(); kfree_skb(reply); err_kfree_acts: - kfree(acts); + ovs_nla_free_flow_actions(acts); error: return error; } diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index cadc6c5c35456..b62cdb3e35892 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -33,6 +33,7 @@ #include #include #include +#include struct sk_buff; @@ -45,6 +46,10 @@ struct sk_buff; #define TUN_METADATA_OPTS(flow_key, opt_len) \ ((void *)((flow_key)->tun_opts + TUN_METADATA_OFFSET(opt_len))) +struct ovs_tunnel_info { + struct metadata_dst *tun_dst; +}; + #define OVS_SW_FLOW_KEY_METADATA_SIZE \ (offsetof(struct sw_flow_key, recirc_id) + \ FIELD_SIZEOF(struct sw_flow_key, recirc_id)) diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index ecfa530d3461f..e7906dfb8814f 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1548,11 +1548,48 @@ static struct sw_flow_actions *nla_alloc_flow_actions(int size, bool log) return sfa; } +static void ovs_nla_free_set_action(const struct nlattr *a) +{ + const struct nlattr *ovs_key = nla_data(a); + struct ovs_tunnel_info *ovs_tun; + + switch (nla_type(ovs_key)) { + case OVS_KEY_ATTR_TUNNEL_INFO: + ovs_tun = nla_data(ovs_key); + dst_release((struct dst_entry *)ovs_tun->tun_dst); + break; + } +} + +void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) +{ + const struct nlattr *a; + int rem; + + if (!sf_acts) + return; + + nla_for_each_attr(a, sf_acts->actions, sf_acts->actions_len, rem) { + switch (nla_type(a)) { + case OVS_ACTION_ATTR_SET: + ovs_nla_free_set_action(a); + break; + } + } + + kfree(sf_acts); +} + +static void __ovs_nla_free_flow_actions(struct rcu_head *head) +{ + ovs_nla_free_flow_actions(container_of(head, struct sw_flow_actions, rcu)); +} + /* Schedules 'sf_acts' to be freed after the next RCU grace period. * The caller must hold rcu_read_lock for this to be sensible. */ -void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) +void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *sf_acts) { - kfree_rcu(sf_acts, rcu); + call_rcu(&sf_acts->rcu, __ovs_nla_free_flow_actions); } static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, @@ -1746,7 +1783,9 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, { struct sw_flow_match match; struct sw_flow_key key; + struct metadata_dst *tun_dst; struct ip_tunnel_info *tun_info; + struct ovs_tunnel_info *ovs_tun; struct nlattr *a; int err = 0, start, opts_type; @@ -1771,12 +1810,22 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, if (start < 0) return start; + tun_dst = metadata_dst_alloc(key.tun_opts_len, GFP_KERNEL); + if (!tun_dst) + return -ENOMEM; + a = __add_action(sfa, OVS_KEY_ATTR_TUNNEL_INFO, NULL, - sizeof(*tun_info) + key.tun_opts_len, log); - if (IS_ERR(a)) + sizeof(*ovs_tun), log); + if (IS_ERR(a)) { + dst_release((struct dst_entry *)tun_dst); return PTR_ERR(a); + } + + ovs_tun = nla_data(a); + ovs_tun->tun_dst = tun_dst; - tun_info = nla_data(a); + tun_info = &tun_dst->u.tun_info; + tun_info->mode = IP_TUNNEL_INFO_TX; tun_info->key = key.tun_key; tun_info->options_len = key.tun_opts_len; @@ -2177,7 +2226,7 @@ int ovs_nla_copy_actions(const struct nlattr *attr, err = __ovs_nla_copy_actions(attr, key, 0, sfa, key->eth.type, key->eth.tci, log); if (err) - kfree(*sfa); + ovs_nla_free_flow_actions(*sfa); return err; } @@ -2227,7 +2276,8 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) switch (key_type) { case OVS_KEY_ATTR_TUNNEL_INFO: { - struct ip_tunnel_info *tun_info = nla_data(ovs_key); + struct ovs_tunnel_info *ovs_tun = nla_data(ovs_key); + struct ip_tunnel_info *tun_info = &ovs_tun->tun_dst->u.tun_info; start = nla_nest_start(skb, OVS_ACTION_ATTR_SET); if (!start) diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index ec53eb6e632b9..acd074408f0aa 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h @@ -69,5 +69,6 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb); void ovs_nla_free_flow_actions(struct sw_flow_actions *); +void ovs_nla_free_flow_actions_rcu(struct sw_flow_actions *); #endif /* flow_netlink.h */ diff --git a/net/openvswitch/flow_table.c b/net/openvswitch/flow_table.c index 4613df8c82900..b70d845e7efb8 100644 --- a/net/openvswitch/flow_table.c +++ b/net/openvswitch/flow_table.c @@ -18,6 +18,7 @@ #include "flow.h" #include "datapath.h" +#include "flow_netlink.h" #include #include #include @@ -143,7 +144,8 @@ static void flow_free(struct sw_flow *flow) if (ovs_identifier_is_key(&flow->id)) kfree(flow->id.unmasked_key); - kfree((struct sw_flow_actions __force *)flow->sf_acts); + if (flow->sf_acts) + ovs_nla_free_flow_actions((struct sw_flow_actions __force *)flow->sf_acts); for_each_node(node) if (flow->stats[node]) kmem_cache_free(flow_stats_cache, -- GitLab From be4ace6e6b1bc12e18b25fe764917e09a1f96d7b Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:04 +0200 Subject: [PATCH 1425/7006] openvswitch: Move dev pointer into vport itself This is the first step in representing all OVS vports as regular struct net_devices. Move the net_device pointer into the vport structure itself to get rid of struct vport_netdev. Signed-off-by: Thomas Graf Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 7 +-- net/openvswitch/dp_notify.c | 5 +- net/openvswitch/vport-internal_dev.c | 37 +++++------- net/openvswitch/vport-netdev.c | 86 +++++++++++++--------------- net/openvswitch/vport-netdev.h | 12 ---- net/openvswitch/vport.h | 3 +- 6 files changed, 59 insertions(+), 91 deletions(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 02082107c74ce..19df28ee50942 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -188,7 +188,7 @@ static int get_dpifindex(const struct datapath *dp) local = ovs_vport_rcu(dp, OVSP_LOCAL); if (local) - ifindex = netdev_vport_priv(local)->dev->ifindex; + ifindex = local->dev->ifindex; else ifindex = 0; @@ -2219,13 +2219,10 @@ static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, struct vport *vport; hlist_for_each_entry(vport, &dp->ports[i], dp_hash_node) { - struct netdev_vport *netdev_vport; - if (vport->ops->type != OVS_VPORT_TYPE_INTERNAL) continue; - netdev_vport = netdev_vport_priv(vport); - if (dev_net(netdev_vport->dev) == dnet) + if (dev_net(vport->dev) == dnet) list_add(&vport->detach_list, head); } } diff --git a/net/openvswitch/dp_notify.c b/net/openvswitch/dp_notify.c index 2c631fe76be19..a7a80a6b77b0a 100644 --- a/net/openvswitch/dp_notify.c +++ b/net/openvswitch/dp_notify.c @@ -58,13 +58,10 @@ void ovs_dp_notify_wq(struct work_struct *work) struct hlist_node *n; hlist_for_each_entry_safe(vport, n, &dp->ports[i], dp_hash_node) { - struct netdev_vport *netdev_vport; - if (vport->ops->type != OVS_VPORT_TYPE_NETDEV) continue; - netdev_vport = netdev_vport_priv(vport); - if (!(netdev_vport->dev->priv_flags & IFF_OVS_DATAPATH)) + if (!(vport->dev->priv_flags & IFF_OVS_DATAPATH)) dp_detach_port_notify(vport); } } diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 6a55f71055051..a2c205d9a8d5c 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -156,49 +156,44 @@ static void do_setup(struct net_device *netdev) static struct vport *internal_dev_create(const struct vport_parms *parms) { struct vport *vport; - struct netdev_vport *netdev_vport; struct internal_dev *internal_dev; int err; - vport = ovs_vport_alloc(sizeof(struct netdev_vport), - &ovs_internal_vport_ops, parms); + vport = ovs_vport_alloc(0, &ovs_internal_vport_ops, parms); if (IS_ERR(vport)) { err = PTR_ERR(vport); goto error; } - netdev_vport = netdev_vport_priv(vport); - - netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), - parms->name, NET_NAME_UNKNOWN, - do_setup); - if (!netdev_vport->dev) { + vport->dev = alloc_netdev(sizeof(struct internal_dev), + parms->name, NET_NAME_UNKNOWN, do_setup); + if (!vport->dev) { err = -ENOMEM; goto error_free_vport; } - dev_net_set(netdev_vport->dev, ovs_dp_get_net(vport->dp)); - internal_dev = internal_dev_priv(netdev_vport->dev); + dev_net_set(vport->dev, ovs_dp_get_net(vport->dp)); + internal_dev = internal_dev_priv(vport->dev); internal_dev->vport = vport; /* Restrict bridge port to current netns. */ if (vport->port_no == OVSP_LOCAL) - netdev_vport->dev->features |= NETIF_F_NETNS_LOCAL; + vport->dev->features |= NETIF_F_NETNS_LOCAL; rtnl_lock(); - err = register_netdevice(netdev_vport->dev); + err = register_netdevice(vport->dev); if (err) goto error_free_netdev; - dev_set_promiscuity(netdev_vport->dev, 1); + dev_set_promiscuity(vport->dev, 1); rtnl_unlock(); - netif_start_queue(netdev_vport->dev); + netif_start_queue(vport->dev); return vport; error_free_netdev: rtnl_unlock(); - free_netdev(netdev_vport->dev); + free_netdev(vport->dev); error_free_vport: ovs_vport_free(vport); error: @@ -207,21 +202,19 @@ error: static void internal_dev_destroy(struct vport *vport) { - struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - - netif_stop_queue(netdev_vport->dev); + netif_stop_queue(vport->dev); rtnl_lock(); - dev_set_promiscuity(netdev_vport->dev, -1); + dev_set_promiscuity(vport->dev, -1); /* unregister_netdevice() waits for an RCU grace period. */ - unregister_netdevice(netdev_vport->dev); + unregister_netdevice(vport->dev); rtnl_unlock(); } static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) { - struct net_device *netdev = netdev_vport_priv(vport)->dev; + struct net_device *netdev = vport->dev; int len; if (unlikely(!(netdev->flags & IFF_UP))) { diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 33e6d6e2908f5..1c9696693f662 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -83,104 +83,97 @@ static struct net_device *get_dpdev(const struct datapath *dp) local = ovs_vport_ovsl(dp, OVSP_LOCAL); BUG_ON(!local); - return netdev_vport_priv(local)->dev; + return local->dev; } -static struct vport *netdev_create(const struct vport_parms *parms) +static struct vport *netdev_link(struct vport *vport, const char *name) { - struct vport *vport; - struct netdev_vport *netdev_vport; int err; - vport = ovs_vport_alloc(sizeof(struct netdev_vport), - &ovs_netdev_vport_ops, parms); - if (IS_ERR(vport)) { - err = PTR_ERR(vport); - goto error; - } - - netdev_vport = netdev_vport_priv(vport); - - netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name); - if (!netdev_vport->dev) { + vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), name); + if (!vport->dev) { err = -ENODEV; goto error_free_vport; } - if (netdev_vport->dev->flags & IFF_LOOPBACK || - netdev_vport->dev->type != ARPHRD_ETHER || - ovs_is_internal_dev(netdev_vport->dev)) { + if (vport->dev->flags & IFF_LOOPBACK || + vport->dev->type != ARPHRD_ETHER || + ovs_is_internal_dev(vport->dev)) { err = -EINVAL; goto error_put; } rtnl_lock(); - err = netdev_master_upper_dev_link(netdev_vport->dev, + err = netdev_master_upper_dev_link(vport->dev, get_dpdev(vport->dp)); if (err) goto error_unlock; - err = netdev_rx_handler_register(netdev_vport->dev, netdev_frame_hook, + err = netdev_rx_handler_register(vport->dev, netdev_frame_hook, vport); if (err) goto error_master_upper_dev_unlink; - dev_disable_lro(netdev_vport->dev); - dev_set_promiscuity(netdev_vport->dev, 1); - netdev_vport->dev->priv_flags |= IFF_OVS_DATAPATH; + dev_disable_lro(vport->dev); + dev_set_promiscuity(vport->dev, 1); + vport->dev->priv_flags |= IFF_OVS_DATAPATH; rtnl_unlock(); return vport; error_master_upper_dev_unlink: - netdev_upper_dev_unlink(netdev_vport->dev, get_dpdev(vport->dp)); + netdev_upper_dev_unlink(vport->dev, get_dpdev(vport->dp)); error_unlock: rtnl_unlock(); error_put: - dev_put(netdev_vport->dev); + dev_put(vport->dev); error_free_vport: ovs_vport_free(vport); -error: return ERR_PTR(err); } +static struct vport *netdev_create(const struct vport_parms *parms) +{ + struct vport *vport; + + vport = ovs_vport_alloc(0, &ovs_netdev_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + return netdev_link(vport, parms->name); +} + static void free_port_rcu(struct rcu_head *rcu) { - struct netdev_vport *netdev_vport = container_of(rcu, - struct netdev_vport, rcu); + struct vport *vport = container_of(rcu, struct vport, rcu); - dev_put(netdev_vport->dev); - ovs_vport_free(vport_from_priv(netdev_vport)); + dev_put(vport->dev); + ovs_vport_free(vport); } void ovs_netdev_detach_dev(struct vport *vport) { - struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - ASSERT_RTNL(); - netdev_vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; - netdev_rx_handler_unregister(netdev_vport->dev); - netdev_upper_dev_unlink(netdev_vport->dev, - netdev_master_upper_dev_get(netdev_vport->dev)); - dev_set_promiscuity(netdev_vport->dev, -1); + vport->dev->priv_flags &= ~IFF_OVS_DATAPATH; + netdev_rx_handler_unregister(vport->dev); + netdev_upper_dev_unlink(vport->dev, + netdev_master_upper_dev_get(vport->dev)); + dev_set_promiscuity(vport->dev, -1); } static void netdev_destroy(struct vport *vport) { - struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - rtnl_lock(); - if (netdev_vport->dev->priv_flags & IFF_OVS_DATAPATH) + if (vport->dev->priv_flags & IFF_OVS_DATAPATH) ovs_netdev_detach_dev(vport); rtnl_unlock(); - call_rcu(&netdev_vport->rcu, free_port_rcu); + call_rcu(&vport->rcu, free_port_rcu); } const char *ovs_netdev_get_name(const struct vport *vport) { - const struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - return netdev_vport->dev->name; + return vport->dev->name; } static unsigned int packet_length(const struct sk_buff *skb) @@ -195,18 +188,17 @@ static unsigned int packet_length(const struct sk_buff *skb) static int netdev_send(struct vport *vport, struct sk_buff *skb) { - struct netdev_vport *netdev_vport = netdev_vport_priv(vport); - int mtu = netdev_vport->dev->mtu; + int mtu = vport->dev->mtu; int len; if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) { net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", - netdev_vport->dev->name, + vport->dev->name, packet_length(skb), mtu); goto drop; } - skb->dev = netdev_vport->dev; + skb->dev = vport->dev; len = skb->len; dev_queue_xmit(skb); diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h index 6f7038e79c524..1c52aed255c5e 100644 --- a/net/openvswitch/vport-netdev.h +++ b/net/openvswitch/vport-netdev.h @@ -26,18 +26,6 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev); -struct netdev_vport { - struct rcu_head rcu; - - struct net_device *dev; -}; - -static inline struct netdev_vport * -netdev_vport_priv(const struct vport *vport) -{ - return vport_priv(vport); -} - const char *ovs_netdev_get_name(const struct vport *); void ovs_netdev_detach_dev(struct vport *); diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 75d68248ba691..e05ec68439d1d 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -107,7 +107,7 @@ struct vport_portids { * @detach_list: list used for detaching vport in net-exit call. */ struct vport { - struct rcu_head rcu; + struct net_device *dev; struct datapath *dp; struct vport_portids __rcu *upcall_portids; u16 port_no; @@ -120,6 +120,7 @@ struct vport { struct vport_err_stats err_stats; struct list_head detach_list; + struct rcu_head rcu; }; /** -- GitLab From c9db965c524ea27451e60d5ddcd242f6c33a70fd Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:05 +0200 Subject: [PATCH 1426/7006] openvswitch: Abstract vport name through ovs_vport_name() This allows to get rid of the get_name() vport ops later on. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 4 ++-- net/openvswitch/vport-internal_dev.c | 1 - net/openvswitch/vport-netdev.c | 6 ------ net/openvswitch/vport-netdev.h | 1 - net/openvswitch/vport.c | 4 ++-- net/openvswitch/vport.h | 5 +++++ 6 files changed, 9 insertions(+), 12 deletions(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 19df28ee50942..ffe984f5b95ce 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -176,7 +176,7 @@ static inline struct datapath *get_dp(struct net *net, int dp_ifindex) const char *ovs_dp_name(const struct datapath *dp) { struct vport *vport = ovs_vport_ovsl_rcu(dp, OVSP_LOCAL); - return vport->ops->get_name(vport); + return ovs_vport_name(vport); } static int get_dpifindex(const struct datapath *dp) @@ -1800,7 +1800,7 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb, if (nla_put_u32(skb, OVS_VPORT_ATTR_PORT_NO, vport->port_no) || nla_put_u32(skb, OVS_VPORT_ATTR_TYPE, vport->ops->type) || nla_put_string(skb, OVS_VPORT_ATTR_NAME, - vport->ops->get_name(vport))) + ovs_vport_name(vport))) goto nla_put_failure; ovs_vport_get_stats(vport, &vport_stats); diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index a2c205d9a8d5c..c058bbf876c34 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -242,7 +242,6 @@ static struct vport_ops ovs_internal_vport_ops = { .type = OVS_VPORT_TYPE_INTERNAL, .create = internal_dev_create, .destroy = internal_dev_destroy, - .get_name = ovs_netdev_get_name, .send = internal_dev_recv, }; diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 1c9696693f662..e682bdc34a5c9 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -171,11 +171,6 @@ static void netdev_destroy(struct vport *vport) call_rcu(&vport->rcu, free_port_rcu); } -const char *ovs_netdev_get_name(const struct vport *vport) -{ - return vport->dev->name; -} - static unsigned int packet_length(const struct sk_buff *skb) { unsigned int length = skb->len - ETH_HLEN; @@ -223,7 +218,6 @@ static struct vport_ops ovs_netdev_vport_ops = { .type = OVS_VPORT_TYPE_NETDEV, .create = netdev_create, .destroy = netdev_destroy, - .get_name = ovs_netdev_get_name, .send = netdev_send, }; diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h index 1c52aed255c5e..684fb88723a4b 100644 --- a/net/openvswitch/vport-netdev.h +++ b/net/openvswitch/vport-netdev.h @@ -26,7 +26,6 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev); -const char *ovs_netdev_get_name(const struct vport *); void ovs_netdev_detach_dev(struct vport *); int __init ovs_netdev_init(void); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index af23ba077836e..d14f59403c5eb 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -113,7 +113,7 @@ struct vport *ovs_vport_locate(const struct net *net, const char *name) struct vport *vport; hlist_for_each_entry_rcu(vport, bucket, hash_node) - if (!strcmp(name, vport->ops->get_name(vport)) && + if (!strcmp(name, ovs_vport_name(vport)) && net_eq(ovs_dp_get_net(vport->dp), net)) return vport; @@ -226,7 +226,7 @@ struct vport *ovs_vport_add(const struct vport_parms *parms) } bucket = hash_bucket(ovs_dp_get_net(vport->dp), - vport->ops->get_name(vport)); + ovs_vport_name(vport)); hlist_add_head_rcu(&vport->hash_node, bucket); return vport; } diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index e05ec68439d1d..1a689c28b5a63 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -237,6 +237,11 @@ static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, skb->csum = csum_add(skb->csum, csum_partial(start, len, 0)); } +static inline const char *ovs_vport_name(struct vport *vport) +{ + return vport->dev ? vport->dev->name : vport->ops->get_name(vport); +} + int ovs_vport_ops_register(struct vport_ops *ops); void ovs_vport_ops_unregister(struct vport_ops *ops); -- GitLab From 614732eaa12dd462c0ab274700bed14f36afea5e Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Tue, 21 Jul 2015 10:44:06 +0200 Subject: [PATCH 1427/7006] openvswitch: Use regular VXLAN net_device device This gets rid of all OVS specific VXLAN code in the receive and transmit path by using a VXLAN net_device to represent the vport. Only a small shim layer remains which takes care of handling the VXLAN specific OVS Netlink configuration. Unexports vxlan_sock_add(), vxlan_sock_release(), vxlan_xmit_skb() since they are no longer needed. Signed-off-by: Thomas Graf Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 242 ++++++++++++------------- include/net/rtnetlink.h | 1 + include/net/vxlan.h | 24 +-- net/core/rtnetlink.c | 26 ++- net/openvswitch/Kconfig | 12 -- net/openvswitch/Makefile | 1 - net/openvswitch/flow_netlink.c | 6 +- net/openvswitch/vport-netdev.c | 201 +++++++++++++++++++- net/openvswitch/vport-vxlan.c | 322 --------------------------------- net/openvswitch/vport-vxlan.h | 11 -- 10 files changed, 339 insertions(+), 507 deletions(-) delete mode 100644 net/openvswitch/vport-vxlan.c delete mode 100644 net/openvswitch/vport-vxlan.h diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 30e1f215af736..e9feefb41f0b4 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -75,6 +75,9 @@ static struct rtnl_link_ops vxlan_link_ops; static const u8 all_zeros_mac[ETH_ALEN]; +static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, + bool no_share, u32 flags); + /* per-network namespace private data for this module */ struct vxlan_net { struct list_head vxlan_list; @@ -1027,7 +1030,7 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev) return false; } -void vxlan_sock_release(struct vxlan_sock *vs) +static void vxlan_sock_release(struct vxlan_sock *vs) { struct sock *sk = vs->sock->sk; struct net *net = sock_net(sk); @@ -1043,7 +1046,6 @@ void vxlan_sock_release(struct vxlan_sock *vs) queue_work(vxlan_wq, &vs->del_work); } -EXPORT_SYMBOL_GPL(vxlan_sock_release); /* Update multicast group membership when first VNI on * multicast address is brought up @@ -1126,6 +1128,102 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, return vh; } +static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, + struct vxlan_metadata *md, u32 vni, + struct metadata_dst *tun_dst) +{ + struct iphdr *oip = NULL; + struct ipv6hdr *oip6 = NULL; + struct vxlan_dev *vxlan; + struct pcpu_sw_netstats *stats; + union vxlan_addr saddr; + int err = 0; + union vxlan_addr *remote_ip; + + /* For flow based devices, map all packets to VNI 0 */ + if (vs->flags & VXLAN_F_FLOW_BASED) + vni = 0; + + /* Is this VNI defined? */ + vxlan = vxlan_vs_find_vni(vs, vni); + if (!vxlan) + goto drop; + + remote_ip = &vxlan->default_dst.remote_ip; + skb_reset_mac_header(skb); + skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); + skb->protocol = eth_type_trans(skb, vxlan->dev); + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + + /* Ignore packet loops (and multicast echo) */ + if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) + goto drop; + + /* Re-examine inner Ethernet packet */ + if (remote_ip->sa.sa_family == AF_INET) { + oip = ip_hdr(skb); + saddr.sin.sin_addr.s_addr = oip->saddr; + saddr.sa.sa_family = AF_INET; +#if IS_ENABLED(CONFIG_IPV6) + } else { + oip6 = ipv6_hdr(skb); + saddr.sin6.sin6_addr = oip6->saddr; + saddr.sa.sa_family = AF_INET6; +#endif + } + + if (tun_dst) { + skb_dst_set(skb, (struct dst_entry *)tun_dst); + tun_dst = NULL; + } + + if ((vxlan->flags & VXLAN_F_LEARN) && + vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) + goto drop; + + skb_reset_network_header(skb); + /* In flow-based mode, GBP is carried in dst_metadata */ + if (!(vs->flags & VXLAN_F_FLOW_BASED)) + skb->mark = md->gbp; + + if (oip6) + err = IP6_ECN_decapsulate(oip6, skb); + if (oip) + err = IP_ECN_decapsulate(oip, skb); + + if (unlikely(err)) { + if (log_ecn_error) { + if (oip6) + net_info_ratelimited("non-ECT from %pI6\n", + &oip6->saddr); + if (oip) + net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", + &oip->saddr, oip->tos); + } + if (err > 1) { + ++vxlan->dev->stats.rx_frame_errors; + ++vxlan->dev->stats.rx_errors; + goto drop; + } + } + + stats = this_cpu_ptr(vxlan->dev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); + + netif_rx(skb); + + return; +drop: + if (tun_dst) + dst_release((struct dst_entry *)tun_dst); + + /* Consume bad packet */ + kfree_skb(skb); +} + /* Callback from net/ipv4/udp.c to receive packets */ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { @@ -1192,7 +1290,6 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) info->key.tun_flags |= TUNNEL_CSUM; md = ip_tunnel_info_opts(info, sizeof(*md)); - md->tun_dst = tun_dst; } else { memset(md, 0, sizeof(*md)); } @@ -1231,8 +1328,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto bad_flags; } - md->vni = vxh->vx_vni; - vs->rcv(vs, skb, md); + vxlan_rcv(vs, skb, md, vni >> 8, tun_dst); return 0; drop: @@ -1252,104 +1348,6 @@ error: return 1; } -static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, - struct vxlan_metadata *md) -{ - struct iphdr *oip = NULL; - struct ipv6hdr *oip6 = NULL; - struct vxlan_dev *vxlan; - struct pcpu_sw_netstats *stats; - union vxlan_addr saddr; - __u32 vni; - int err = 0; - union vxlan_addr *remote_ip; - - /* For flow based devices, map all packets to VNI 0 */ - if (vs->flags & VXLAN_F_FLOW_BASED) - vni = 0; - else - vni = ntohl(md->vni) >> 8; - - /* Is this VNI defined? */ - vxlan = vxlan_vs_find_vni(vs, vni); - if (!vxlan) - goto drop; - - remote_ip = &vxlan->default_dst.remote_ip; - skb_reset_mac_header(skb); - skb_scrub_packet(skb, !net_eq(vxlan->net, dev_net(vxlan->dev))); - skb->protocol = eth_type_trans(skb, vxlan->dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); - - /* Ignore packet loops (and multicast echo) */ - if (ether_addr_equal(eth_hdr(skb)->h_source, vxlan->dev->dev_addr)) - goto drop; - - /* Re-examine inner Ethernet packet */ - if (remote_ip->sa.sa_family == AF_INET) { - oip = ip_hdr(skb); - saddr.sin.sin_addr.s_addr = oip->saddr; - saddr.sa.sa_family = AF_INET; -#if IS_ENABLED(CONFIG_IPV6) - } else { - oip6 = ipv6_hdr(skb); - saddr.sin6.sin6_addr = oip6->saddr; - saddr.sa.sa_family = AF_INET6; -#endif - } - - if (md->tun_dst) { - skb_dst_set(skb, (struct dst_entry *)md->tun_dst); - md->tun_dst = NULL; - } - - if ((vxlan->flags & VXLAN_F_LEARN) && - vxlan_snoop(skb->dev, &saddr, eth_hdr(skb)->h_source)) - goto drop; - - skb_reset_network_header(skb); - /* In flow-based mode, GBP is carried in dst_metadata */ - if (!(vs->flags & VXLAN_F_FLOW_BASED)) - skb->mark = md->gbp; - - if (oip6) - err = IP6_ECN_decapsulate(oip6, skb); - if (oip) - err = IP_ECN_decapsulate(oip, skb); - - if (unlikely(err)) { - if (log_ecn_error) { - if (oip6) - net_info_ratelimited("non-ECT from %pI6\n", - &oip6->saddr); - if (oip) - net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", - &oip->saddr, oip->tos); - } - if (err > 1) { - ++vxlan->dev->stats.rx_frame_errors; - ++vxlan->dev->stats.rx_errors; - goto drop; - } - } - - stats = this_cpu_ptr(vxlan->dev->tstats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len; - u64_stats_update_end(&stats->syncp); - - netif_rx(skb); - - return; -drop: - if (md->tun_dst) - dst_release((struct dst_entry *)md->tun_dst); - - /* Consume bad packet */ - kfree_skb(skb); -} - static int arp_reduce(struct net_device *dev, struct sk_buff *skb) { struct vxlan_dev *vxlan = netdev_priv(dev); @@ -1688,7 +1686,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, + __be16 src_port, __be16 dst_port, __u32 vni, struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; @@ -1738,7 +1736,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); - vxh->vx_vni = md->vni; + vxh->vx_vni = vni; if (type & SKB_GSO_TUNNEL_REMCSUM) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> @@ -1771,10 +1769,10 @@ err: } #endif -int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, - __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, - struct vxlan_metadata *md, bool xnet, u32 vxflags) +static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, + __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, + __be16 src_port, __be16 dst_port, __u32 vni, + struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; int min_headroom; @@ -1817,7 +1815,7 @@ int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh)); vxh->vx_flags = htonl(VXLAN_HF_VNI); - vxh->vx_vni = md->vni; + vxh->vx_vni = vni; if (type & SKB_GSO_TUNNEL_REMCSUM) { u32 data = (skb_checksum_start_offset(skb) - hdrlen) >> @@ -1844,7 +1842,6 @@ int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, ttl, df, src_port, dst_port, xnet, !(vxflags & VXLAN_F_UDP_CSUM)); } -EXPORT_SYMBOL_GPL(vxlan_xmit_skb); /* Bypass encapsulation if the destination is local */ static void vxlan_encap_bypass(struct sk_buff *skb, struct vxlan_dev *src_vxlan, @@ -2012,10 +2009,9 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = ip_tunnel_ecn_encap(tos, old_iph, skb); ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - md->vni = htonl(vni << 8); err = vxlan_xmit_skb(rt, sk, skb, fl4.saddr, dst->sin.sin_addr.s_addr, tos, ttl, df, - src_port, dst_port, md, + src_port, dst_port, htonl(vni << 8), md, !net_eq(vxlan->net, dev_net(vxlan->dev)), flags); if (err < 0) { @@ -2070,11 +2066,10 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, } ttl = ttl ? : ip6_dst_hoplimit(ndst); - md->vni = htonl(vni << 8); md->gbp = skb->mark; err = vxlan6_xmit_skb(ndst, sk, skb, dev, &fl6.saddr, &fl6.daddr, - 0, ttl, src_port, dst_port, md, + 0, ttl, src_port, dst_port, htonl(vni << 8), md, !net_eq(vxlan->net, dev_net(vxlan->dev)), vxlan->flags); #endif @@ -2269,8 +2264,8 @@ static int vxlan_open(struct net_device *dev) struct vxlan_sock *vs; int ret = 0; - vs = vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, vxlan_rcv, - NULL, vxlan->cfg.no_share, vxlan->flags); + vs = vxlan_sock_add(vxlan->net, vxlan->cfg.dst_port, + vxlan->cfg.no_share, vxlan->flags); if (IS_ERR(vs)) return PTR_ERR(vs); @@ -2563,7 +2558,6 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6, /* Create new listen socket if needed */ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, - vxlan_rcv_t *rcv, void *data, u32 flags) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); @@ -2592,8 +2586,6 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, vs->sock = sock; atomic_set(&vs->refcnt, 1); - vs->rcv = rcv; - vs->data = data; vs->flags = (flags & VXLAN_F_RCV_FLAGS); /* Initialize the vxlan udp offloads structure */ @@ -2617,9 +2609,8 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port, return vs; } -struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, - vxlan_rcv_t *rcv, void *data, - bool no_share, u32 flags) +static struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, + bool no_share, u32 flags) { struct vxlan_net *vn = net_generic(net, vxlan_net_id); struct vxlan_sock *vs; @@ -2629,7 +2620,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, spin_lock(&vn->sock_lock); vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags); - if (vs && vs->rcv == rcv) { + if (vs) { if (!atomic_add_unless(&vs->refcnt, 1, 0)) vs = ERR_PTR(-EBUSY); spin_unlock(&vn->sock_lock); @@ -2638,9 +2629,8 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port, spin_unlock(&vn->sock_lock); } - return vxlan_socket_create(net, port, rcv, data, flags); + return vxlan_socket_create(net, port, flags); } -EXPORT_SYMBOL_GPL(vxlan_sock_add); static int vxlan_dev_configure(struct net *src_net, struct net_device *dev, struct vxlan_config *conf) diff --git a/include/net/rtnetlink.h b/include/net/rtnetlink.h index 343d922d15c2c..18fdb98185ab3 100644 --- a/include/net/rtnetlink.h +++ b/include/net/rtnetlink.h @@ -141,6 +141,7 @@ struct net_device *rtnl_create_link(struct net *net, const char *ifname, unsigned char name_assign_type, const struct rtnl_link_ops *ops, struct nlattr *tb[]); +int rtnl_delete_link(struct net_device *dev); int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm); int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len); diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 19535f85eb2c9..eb8d721cdb676 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -101,22 +101,12 @@ struct vxlanhdr { #define FDB_HASH_SIZE (1<vn_sock->sock->sk)->inet_sport; +} static inline netdev_features_t vxlan_features_check(struct sk_buff *skb, netdev_features_t features) diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 03d61b54aac03..5fb4af20c6dd0 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -1960,16 +1960,30 @@ static int rtnl_group_dellink(const struct net *net, int group) return 0; } +int rtnl_delete_link(struct net_device *dev) +{ + const struct rtnl_link_ops *ops; + LIST_HEAD(list_kill); + + ops = dev->rtnl_link_ops; + if (!ops || !ops->dellink) + return -EOPNOTSUPP; + + ops->dellink(dev, &list_kill); + unregister_netdevice_many(&list_kill); + + return 0; +} +EXPORT_SYMBOL_GPL(rtnl_delete_link); + static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) { struct net *net = sock_net(skb->sk); - const struct rtnl_link_ops *ops; struct net_device *dev; struct ifinfomsg *ifm; char ifname[IFNAMSIZ]; struct nlattr *tb[IFLA_MAX+1]; int err; - LIST_HEAD(list_kill); err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); if (err < 0) @@ -1991,13 +2005,7 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) if (!dev) return -ENODEV; - ops = dev->rtnl_link_ops; - if (!ops || !ops->dellink) - return -EOPNOTSUPP; - - ops->dellink(dev, &list_kill); - unregister_netdevice_many(&list_kill); - return 0; + return rtnl_delete_link(dev); } int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 15840401a2ce5..1119f46b80b4f 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig @@ -44,18 +44,6 @@ config OPENVSWITCH_GRE If unsure, say Y. -config OPENVSWITCH_VXLAN - tristate "Open vSwitch VXLAN tunneling support" - depends on OPENVSWITCH - depends on VXLAN - default OPENVSWITCH - ---help--- - If you say Y here, then the Open vSwitch will be able create vxlan vport. - - Say N to exclude this support and reduce the binary size. - - If unsure, say Y. - config OPENVSWITCH_GENEVE tristate "Open vSwitch Geneve tunneling support" depends on OPENVSWITCH diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 91b9478413ef1..38e0e149c55e1 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile @@ -16,5 +16,4 @@ openvswitch-y := \ vport-netdev.o obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o -obj-$(CONFIG_OPENVSWITCH_VXLAN) += vport-vxlan.o obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index e7906dfb8814f..a6eb77ab1a645 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -47,9 +47,9 @@ #include #include #include +#include #include "flow_netlink.h" -#include "vport-vxlan.h" struct ovs_len_tbl { int len; @@ -475,7 +475,7 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *a, { struct nlattr *tb[OVS_VXLAN_EXT_MAX+1]; unsigned long opt_key_offset; - struct ovs_vxlan_opts opts; + struct vxlan_metadata opts; int err; BUILD_BUG_ON(sizeof(opts) > sizeof(match->key->tun_opts)); @@ -626,7 +626,7 @@ static int ipv4_tun_from_nlattr(const struct nlattr *attr, static int vxlan_opt_to_nlattr(struct sk_buff *skb, const void *tun_opts, int swkey_tun_opts_len) { - const struct ovs_vxlan_opts *opts = tun_opts; + const struct vxlan_metadata *opts = tun_opts; struct nlattr *nla; nla = nla_nest_start(skb, OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS); diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index e682bdc34a5c9..68d0582fc0016 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -27,9 +27,13 @@ #include #include -#include +#include +#include +#include +#include #include "datapath.h" +#include "vport.h" #include "vport-internal_dev.h" #include "vport-netdev.h" @@ -147,7 +151,8 @@ static void free_port_rcu(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); - dev_put(vport->dev); + if (vport->dev) + dev_put(vport->dev); ovs_vport_free(vport); } @@ -221,12 +226,202 @@ static struct vport_ops ovs_netdev_vport_ops = { .send = netdev_send, }; +/* Compat code for old userspace. */ +#if IS_ENABLED(CONFIG_VXLAN) +static struct vport_ops ovs_vxlan_netdev_vport_ops; + +static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) +{ + struct vxlan_dev *vxlan = netdev_priv(vport->dev); + __be16 dst_port = vxlan->cfg.dst_port; + + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) + return -EMSGSIZE; + + if (vxlan->flags & VXLAN_F_GBP) { + struct nlattr *exts; + + exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION); + if (!exts) + return -EMSGSIZE; + + if (vxlan->flags & VXLAN_F_GBP && + nla_put_flag(skb, OVS_VXLAN_EXT_GBP)) + return -EMSGSIZE; + + nla_nest_end(skb, exts); + } + + return 0; +} + +static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX + 1] = { + [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, }, +}; + +static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr, + struct vxlan_config *conf) +{ + struct nlattr *exts[OVS_VXLAN_EXT_MAX + 1]; + int err; + + if (nla_len(attr) < sizeof(struct nlattr)) + return -EINVAL; + + err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy); + if (err < 0) + return err; + + if (exts[OVS_VXLAN_EXT_GBP]) + conf->flags |= VXLAN_F_GBP; + + return 0; +} + +static struct vport *vxlan_tnl_create(const struct vport_parms *parms) +{ + struct net *net = ovs_dp_get_net(parms->dp); + struct nlattr *options = parms->options; + struct net_device *dev; + struct vport *vport; + struct nlattr *a; + int err; + struct vxlan_config conf = { + .no_share = true, + .flags = VXLAN_F_FLOW_BASED | VXLAN_F_COLLECT_METADATA, + }; + + if (!options) { + err = -EINVAL; + goto error; + } + + a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); + if (a && nla_len(a) == sizeof(u16)) { + conf.dst_port = htons(nla_get_u16(a)); + } else { + /* Require destination port from userspace. */ + err = -EINVAL; + goto error; + } + + vport = ovs_vport_alloc(0, &ovs_vxlan_netdev_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); + if (a) { + err = vxlan_configure_exts(vport, a, &conf); + if (err) { + ovs_vport_free(vport); + goto error; + } + } + + rtnl_lock(); + dev = vxlan_dev_create(net, parms->name, NET_NAME_USER, &conf); + if (IS_ERR(dev)) { + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_CAST(dev); + } + + dev_change_flags(dev, dev->flags | IFF_UP); + rtnl_unlock(); + return vport; +error: + return ERR_PTR(err); +} + +static struct vport *vxlan_create(const struct vport_parms *parms) +{ + struct vport *vport; + + vport = vxlan_tnl_create(parms); + if (IS_ERR(vport)) + return vport; + + return netdev_link(vport, parms->name); +} + +static void vxlan_destroy(struct vport *vport) +{ + rtnl_lock(); + if (vport->dev->priv_flags & IFF_OVS_DATAPATH) + ovs_netdev_detach_dev(vport); + + /* Early release so we can unregister the device */ + dev_put(vport->dev); + rtnl_delete_link(vport->dev); + vport->dev = NULL; + rtnl_unlock(); + + call_rcu(&vport->rcu, free_port_rcu); +} + +static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, + struct ip_tunnel_info *egress_tun_info) +{ + struct vxlan_dev *vxlan = netdev_priv(vport->dev); + struct net *net = ovs_dp_get_net(vport->dp); + __be16 dst_port = vxlan_dev_dst_port(vxlan); + __be16 src_port; + int port_min; + int port_max; + + inet_get_local_port_range(net, &port_min, &port_max); + src_port = udp_flow_src_port(net, skb, 0, 0, true); + + return ovs_tunnel_get_egress_info(egress_tun_info, net, + OVS_CB(skb)->egress_tun_info, + IPPROTO_UDP, skb->mark, + src_port, dst_port); +} + +static struct vport_ops ovs_vxlan_netdev_vport_ops = { + .type = OVS_VPORT_TYPE_VXLAN, + .create = vxlan_create, + .destroy = vxlan_destroy, + .get_options = vxlan_get_options, + .send = netdev_send, + .get_egress_tun_info = vxlan_get_egress_tun_info, +}; + +static int vxlan_compat_init(void) +{ + return ovs_vport_ops_register(&ovs_vxlan_netdev_vport_ops); +} + +static void vxlan_compat_exit(void) +{ + ovs_vport_ops_unregister(&ovs_vxlan_netdev_vport_ops); +} +#else +static int vxlan_compat_init(void) +{ + return 0; +} + +static void vxlan_compat_exit(void) +{ +} +#endif + int __init ovs_netdev_init(void) { - return ovs_vport_ops_register(&ovs_netdev_vport_ops); + int err; + + err = ovs_vport_ops_register(&ovs_netdev_vport_ops); + if (err) + return err; + err = vxlan_compat_init(); + if (err) + vxlan_compat_exit(); + return err; } void ovs_netdev_exit(void) { ovs_vport_ops_unregister(&ovs_netdev_vport_ops); + vxlan_compat_exit(); } diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c deleted file mode 100644 index 6f7986fabb70c..0000000000000 --- a/net/openvswitch/vport-vxlan.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2014 Nicira, Inc. - * Copyright (c) 2013 Cisco Systems, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "datapath.h" -#include "vport.h" -#include "vport-vxlan.h" - -/** - * struct vxlan_port - Keeps track of open UDP ports - * @vs: vxlan_sock created for the port. - * @name: vport name. - */ -struct vxlan_port { - struct vxlan_sock *vs; - char name[IFNAMSIZ]; - u32 exts; /* VXLAN_F_* in */ -}; - -static struct vport_ops ovs_vxlan_vport_ops; - -static inline struct vxlan_port *vxlan_vport(const struct vport *vport) -{ - return vport_priv(vport); -} - -/* Called with rcu_read_lock and BH disabled. */ -static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, - struct vxlan_metadata *md) -{ - struct ip_tunnel_info tun_info; - struct vxlan_port *vxlan_port; - struct vport *vport = vs->data; - struct iphdr *iph; - struct ovs_vxlan_opts opts = { - .gbp = md->gbp, - }; - __be64 key; - __be16 flags; - - flags = TUNNEL_KEY | (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0); - vxlan_port = vxlan_vport(vport); - if (vxlan_port->exts & VXLAN_F_GBP && md->gbp) - flags |= TUNNEL_VXLAN_OPT; - - /* Save outer tunnel values */ - iph = ip_hdr(skb); - key = cpu_to_be64(ntohl(md->vni) >> 8); - ip_tunnel_info_init(&tun_info, iph, - udp_hdr(skb)->source, udp_hdr(skb)->dest, - key, flags, &opts, sizeof(opts)); - - ovs_vport_receive(vport, skb, &tun_info); -} - -static int vxlan_get_options(const struct vport *vport, struct sk_buff *skb) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; - - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(dst_port))) - return -EMSGSIZE; - - if (vxlan_port->exts) { - struct nlattr *exts; - - exts = nla_nest_start(skb, OVS_TUNNEL_ATTR_EXTENSION); - if (!exts) - return -EMSGSIZE; - - if (vxlan_port->exts & VXLAN_F_GBP && - nla_put_flag(skb, OVS_VXLAN_EXT_GBP)) - return -EMSGSIZE; - - nla_nest_end(skb, exts); - } - - return 0; -} - -static void vxlan_tnl_destroy(struct vport *vport) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - - vxlan_sock_release(vxlan_port->vs); - - ovs_vport_deferred_free(vport); -} - -static const struct nla_policy exts_policy[OVS_VXLAN_EXT_MAX+1] = { - [OVS_VXLAN_EXT_GBP] = { .type = NLA_FLAG, }, -}; - -static int vxlan_configure_exts(struct vport *vport, struct nlattr *attr) -{ - struct nlattr *exts[OVS_VXLAN_EXT_MAX+1]; - struct vxlan_port *vxlan_port; - int err; - - if (nla_len(attr) < sizeof(struct nlattr)) - return -EINVAL; - - err = nla_parse_nested(exts, OVS_VXLAN_EXT_MAX, attr, exts_policy); - if (err < 0) - return err; - - vxlan_port = vxlan_vport(vport); - - if (exts[OVS_VXLAN_EXT_GBP]) - vxlan_port->exts |= VXLAN_F_GBP; - - return 0; -} - -static struct vport *vxlan_tnl_create(const struct vport_parms *parms) -{ - struct net *net = ovs_dp_get_net(parms->dp); - struct nlattr *options = parms->options; - struct vxlan_port *vxlan_port; - struct vxlan_sock *vs; - struct vport *vport; - struct nlattr *a; - u16 dst_port; - int err; - - if (!options) { - err = -EINVAL; - goto error; - } - a = nla_find_nested(options, OVS_TUNNEL_ATTR_DST_PORT); - if (a && nla_len(a) == sizeof(u16)) { - dst_port = nla_get_u16(a); - } else { - /* Require destination port from userspace. */ - err = -EINVAL; - goto error; - } - - vport = ovs_vport_alloc(sizeof(struct vxlan_port), - &ovs_vxlan_vport_ops, parms); - if (IS_ERR(vport)) - return vport; - - vxlan_port = vxlan_vport(vport); - strncpy(vxlan_port->name, parms->name, IFNAMSIZ); - - a = nla_find_nested(options, OVS_TUNNEL_ATTR_EXTENSION); - if (a) { - err = vxlan_configure_exts(vport, a); - if (err) { - ovs_vport_free(vport); - goto error; - } - } - - vs = vxlan_sock_add(net, htons(dst_port), vxlan_rcv, vport, true, - vxlan_port->exts); - if (IS_ERR(vs)) { - ovs_vport_free(vport); - return (void *)vs; - } - vxlan_port->vs = vs; - - return vport; - -error: - return ERR_PTR(err); -} - -static int vxlan_ext_gbp(struct sk_buff *skb) -{ - const struct ip_tunnel_info *tun_info; - const struct ovs_vxlan_opts *opts; - - tun_info = OVS_CB(skb)->egress_tun_info; - opts = tun_info->options; - - if (tun_info->key.tun_flags & TUNNEL_VXLAN_OPT && - tun_info->options_len >= sizeof(*opts)) - return opts->gbp; - else - return 0; -} - -static int vxlan_tnl_send(struct vport *vport, struct sk_buff *skb) -{ - struct net *net = ovs_dp_get_net(vport->dp); - struct vxlan_port *vxlan_port = vxlan_vport(vport); - struct sock *sk = vxlan_port->vs->sock->sk; - __be16 dst_port = inet_sk(sk)->inet_sport; - const struct ip_tunnel_key *tun_key; - struct vxlan_metadata md = {0}; - struct rtable *rt; - struct flowi4 fl; - __be16 src_port; - __be16 df; - int err; - u32 vxflags; - - if (unlikely(!OVS_CB(skb)->egress_tun_info)) { - err = -EINVAL; - goto error; - } - - tun_key = &OVS_CB(skb)->egress_tun_info->key; - rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto error; - } - - df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? - htons(IP_DF) : 0; - - skb->ignore_df = 1; - - src_port = udp_flow_src_port(net, skb, 0, 0, true); - md.vni = htonl(be64_to_cpu(tun_key->tun_id) << 8); - md.gbp = vxlan_ext_gbp(skb); - vxflags = vxlan_port->exts | - (tun_key->tun_flags & TUNNEL_CSUM ? VXLAN_F_UDP_CSUM : 0); - - err = vxlan_xmit_skb(rt, sk, skb, fl.saddr, tun_key->ipv4_dst, - tun_key->ipv4_tos, tun_key->ipv4_ttl, df, - src_port, dst_port, - &md, false, vxflags); - if (err < 0) - ip_rt_put(rt); - return err; -error: - kfree_skb(skb); - return err; -} - -static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *egress_tun_info) -{ - struct net *net = ovs_dp_get_net(vport->dp); - struct vxlan_port *vxlan_port = vxlan_vport(vport); - __be16 dst_port = inet_sk(vxlan_port->vs->sock->sk)->inet_sport; - __be16 src_port; - int port_min; - int port_max; - - inet_get_local_port_range(net, &port_min, &port_max); - src_port = udp_flow_src_port(net, skb, 0, 0, true); - - return ovs_tunnel_get_egress_info(egress_tun_info, net, - OVS_CB(skb)->egress_tun_info, - IPPROTO_UDP, skb->mark, - src_port, dst_port); -} - -static const char *vxlan_get_name(const struct vport *vport) -{ - struct vxlan_port *vxlan_port = vxlan_vport(vport); - return vxlan_port->name; -} - -static struct vport_ops ovs_vxlan_vport_ops = { - .type = OVS_VPORT_TYPE_VXLAN, - .create = vxlan_tnl_create, - .destroy = vxlan_tnl_destroy, - .get_name = vxlan_get_name, - .get_options = vxlan_get_options, - .send = vxlan_tnl_send, - .get_egress_tun_info = vxlan_get_egress_tun_info, - .owner = THIS_MODULE, -}; - -static int __init ovs_vxlan_tnl_init(void) -{ - return ovs_vport_ops_register(&ovs_vxlan_vport_ops); -} - -static void __exit ovs_vxlan_tnl_exit(void) -{ - ovs_vport_ops_unregister(&ovs_vxlan_vport_ops); -} - -module_init(ovs_vxlan_tnl_init); -module_exit(ovs_vxlan_tnl_exit); - -MODULE_DESCRIPTION("OVS: VXLAN switching port"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("vport-type-4"); diff --git a/net/openvswitch/vport-vxlan.h b/net/openvswitch/vport-vxlan.h deleted file mode 100644 index 4b08233e73d5c..0000000000000 --- a/net/openvswitch/vport-vxlan.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef VPORT_VXLAN_H -#define VPORT_VXLAN_H 1 - -#include -#include - -struct ovs_vxlan_opts { - __u32 gbp; -}; - -#endif -- GitLab From 019d8817b1b064c2bacfbcf40fc68184438ad05a Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 15 Jul 2015 14:40:06 +0200 Subject: [PATCH 1428/7006] PM / sleep: Allow devices without runtime PM to do direct-complete Don't unset the direct_complete flag on devices that have runtime PM disabled, if they are runtime suspended. This is needed because otherwise ancestor devices wouldn't be able to do direct_complete without adding runtime PM support to all its descendants. Also removes pm_runtime_suspended_if_enabled() because it's now unused. Signed-off-by: Tomeu Vizoso Signed-off-by: Alan Stern Signed-off-by: Rafael J. Wysocki --- Documentation/power/devices.txt | 7 +++++++ Documentation/power/runtime_pm.txt | 4 ---- drivers/base/power/main.c | 2 +- include/linux/pm_runtime.h | 6 ------ 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/Documentation/power/devices.txt b/Documentation/power/devices.txt index d172bce0fd498..8ba6625fdd63d 100644 --- a/Documentation/power/devices.txt +++ b/Documentation/power/devices.txt @@ -341,6 +341,13 @@ the phases are: and is entirely responsible for bringing the device back to the functional state as appropriate. + Note that this direct-complete procedure applies even if the device is + disabled for runtime PM; only the runtime-PM status matters. It follows + that if a device has system-sleep callbacks but does not support runtime + PM, then its prepare callback must never return a positive value. This + is because all devices are initially set to runtime-suspended with + runtime PM disabled. + 2. The suspend methods should quiesce the device to stop it from performing I/O. They also may save the device registers and put it into the appropriate low-power state, depending on the bus type the device is on, diff --git a/Documentation/power/runtime_pm.txt b/Documentation/power/runtime_pm.txt index e76dc0ad4d2b7..0784bc3a2ab51 100644 --- a/Documentation/power/runtime_pm.txt +++ b/Documentation/power/runtime_pm.txt @@ -445,10 +445,6 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h: bool pm_runtime_status_suspended(struct device *dev); - return true if the device's runtime PM status is 'suspended' - bool pm_runtime_suspended_if_enabled(struct device *dev); - - return true if the device's runtime PM status is 'suspended' and its - 'power.disable_depth' field is equal to 1 - void pm_runtime_allow(struct device *dev); - set the power.runtime_auto flag for the device and decrease its usage counter (used by the /sys/devices/.../power/control interface to diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 30b7bbfdc5588..1710c26ba097d 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1377,7 +1377,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async) if (dev->power.direct_complete) { if (pm_runtime_status_suspended(dev)) { pm_runtime_disable(dev); - if (pm_runtime_suspended_if_enabled(dev)) + if (pm_runtime_status_suspended(dev)) goto Complete; pm_runtime_enable(dev); diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h index 30e84d48bfeaa..3bdbb41897800 100644 --- a/include/linux/pm_runtime.h +++ b/include/linux/pm_runtime.h @@ -98,11 +98,6 @@ static inline bool pm_runtime_status_suspended(struct device *dev) return dev->power.runtime_status == RPM_SUSPENDED; } -static inline bool pm_runtime_suspended_if_enabled(struct device *dev) -{ - return pm_runtime_status_suspended(dev) && dev->power.disable_depth == 1; -} - static inline bool pm_runtime_enabled(struct device *dev) { return !dev->power.disable_depth; @@ -164,7 +159,6 @@ static inline void device_set_run_wake(struct device *dev, bool enable) {} static inline bool pm_runtime_suspended(struct device *dev) { return false; } static inline bool pm_runtime_active(struct device *dev) { return true; } static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } -static inline bool pm_runtime_suspended_if_enabled(struct device *dev) { return false; } static inline bool pm_runtime_enabled(struct device *dev) { return false; } static inline void pm_runtime_no_callbacks(struct device *dev) {} -- GitLab From c45f5c9943ce0b16b299b543c2aae12408039027 Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Tue, 21 Jul 2015 15:08:13 -0600 Subject: [PATCH 1429/7006] nvme: Fixes u64 division which breaks i386 builds Uses div_u64 for u64 division and round_down, a bitwise operation, instead of rounddown, which uses a modulus. Signed-off-by: Jon Derrick Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index 82b4ffb6eefa7..666e994fd622c 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -1454,8 +1454,9 @@ static int nvme_cmb_qdepth(struct nvme_dev *dev, int nr_io_queues, unsigned q_size_aligned = roundup(q_depth * entry_size, dev->page_size); if (q_size_aligned * nr_io_queues > dev->cmb_size) { - q_depth = rounddown(dev->cmb_size / nr_io_queues, - dev->page_size) / entry_size; + u64 mem_per_q = div_u64(dev->cmb_size, nr_io_queues); + mem_per_q = round_down(mem_per_q, dev->page_size); + q_depth = div_u64(mem_per_q, entry_size); /* * Ensure the reduced q_depth is above some threshold where it -- GitLab From e181a5430491f038c198f0eacc3142d6e871c2da Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sun, 19 Jul 2015 22:21:13 +0200 Subject: [PATCH 1430/7006] net: #ifdefify sk_classid member of struct sock The sk_classid member is only required when CONFIG_CGROUP_NET_CLASSID is enabled. #ifdefify it to reduce the size of struct sock on 32 bit systems, at least. Signed-off-by: Mathias Krause Signed-off-by: David S. Miller --- include/net/sock.h | 2 ++ net/netfilter/nft_meta.c | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/include/net/sock.h b/include/net/sock.h index 05a8c1aea2518..4353ef70bf482 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -429,7 +429,9 @@ struct sock { void *sk_security; #endif __u32 sk_mark; +#ifdef CONFIG_CGROUP_NET_CLASSID u32 sk_classid; +#endif struct cg_proto *sk_cgrp; void (*sk_state_change)(struct sock *sk); void (*sk_data_ready)(struct sock *sk); diff --git a/net/netfilter/nft_meta.c b/net/netfilter/nft_meta.c index 52561e1c31e26..cb2f13ebb5a66 100644 --- a/net/netfilter/nft_meta.c +++ b/net/netfilter/nft_meta.c @@ -166,11 +166,13 @@ void nft_meta_get_eval(const struct nft_expr *expr, goto err; *dest = out->group; break; +#ifdef CONFIG_CGROUP_NET_CLASSID case NFT_META_CGROUP: if (skb->sk == NULL || !sk_fullsock(skb->sk)) goto err; *dest = skb->sk->sk_classid; break; +#endif default: WARN_ON(1); goto err; @@ -246,7 +248,9 @@ int nft_meta_get_init(const struct nft_ctx *ctx, case NFT_META_CPU: case NFT_META_IIFGROUP: case NFT_META_OIFGROUP: +#ifdef CONFIG_CGROUP_NET_CLASSID case NFT_META_CGROUP: +#endif len = sizeof(u32); break; case NFT_META_IIFNAME: -- GitLab From d2eac98f7d1b950b762a7eca05a9ce0ea1d878d2 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 20 Jul 2015 17:49:55 -0700 Subject: [PATCH 1431/7006] net: dsa: bcm_sf2: Do not override speed settings The SF2 driver currently overrides speed settings for its port configured using a fixed PHY, this is both unnecessary and incorrect, because we keep feedback to the hardware parameters that we read from the PHY device, which in the case of a fixed PHY cannot possibly change speed. This is a required change to allow the fixed PHY code to allow registering a PHY with a link configured as DOWN by default and avoid some sort of circular dependency where we require the link_update callback to run to program the hardware, and we then utilize the fixed PHY parameters to program the hardware with the same settings. Fixes: 246d7f773c13 ("net: dsa: add Broadcom SF2 switch driver") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 972982f8bea7a..3297604f82162 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -890,15 +890,11 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, struct fixed_phy_status *status) { struct bcm_sf2_priv *priv = ds_to_priv(ds); - u32 duplex, pause, speed; + u32 duplex, pause; u32 reg; duplex = core_readl(priv, CORE_DUPSTS); pause = core_readl(priv, CORE_PAUSESTS); - speed = core_readl(priv, CORE_SPDSTS); - - speed >>= (port * SPDSTS_SHIFT); - speed &= SPDSTS_MASK; status->link = 0; @@ -933,18 +929,6 @@ static void bcm_sf2_sw_fixed_link_update(struct dsa_switch *ds, int port, reg &= ~LINK_STS; core_writel(priv, reg, CORE_STS_OVERRIDE_GMIIP_PORT(port)); - switch (speed) { - case SPDSTS_10: - status->speed = SPEED_10; - break; - case SPDSTS_100: - status->speed = SPEED_100; - break; - case SPDSTS_1000: - status->speed = SPEED_1000; - break; - } - if ((pause & (1 << port)) && (pause & (1 << (port + PAUSESTS_TX_PAUSE_SHIFT)))) { status->asym_pause = 1; -- GitLab From 868a4215be9a6d80548ccb74763b883dc99d32a2 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 20 Jul 2015 17:49:56 -0700 Subject: [PATCH 1432/7006] net: phy: fixed_phy: handle link-down case fixed_phy_register() currently hardcodes the fixed PHY link to 1, and expects to find a "speed" parameter to provide correct information towards the fixed PHY consumer. In a subsequent change, where we allow "managed" (e.g: (RS)GMII in-band status auto-negotiation) fixed PHYs, none of these parameters can be provided since they will be auto-negotiated, hence, we just provide a zero-initialized fixed_phy_status to fixed_phy_register() which makes it fail when we call fixed_phy_update_regs() since status.speed = 0 which makes us hit the "default" label and error out. Without this change, we would also see potentially inconsistent speed/duplex parameters for fixed PHYs when the link is DOWN. CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Stas Sergeev [florian: add more background to why this is correct and desirable] Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 1960b46add65b..479b93f9581c4 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -52,6 +52,10 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) u16 lpagb = 0; u16 lpa = 0; + if (!fp->status.link) + goto done; + bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; + if (fp->status.duplex) { bmcr |= BMCR_FULLDPLX; @@ -96,15 +100,13 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) } } - if (fp->status.link) - bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; - if (fp->status.pause) lpa |= LPA_PAUSE_CAP; if (fp->status.asym_pause) lpa |= LPA_PAUSE_ASYM; +done: fp->regs[MII_PHYSID1] = 0; fp->regs[MII_PHYSID2] = 0; -- GitLab From 4cba5c2103657d43d0886e4cff8004d95a3d0def Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 20 Jul 2015 17:49:57 -0700 Subject: [PATCH 1433/7006] of_mdio: add new DT property 'managed' to specify the PHY management type Currently the PHY management type is selected by the MAC driver arbitrary. The decision is based on the presence of the "fixed-link" node and on a will of the driver's authors. This caused a regression recently, when mvneta driver suddenly started to use the in-band status for auto-negotiation on fixed links. It appears the auto-negotiation may not work when expected by the MAC driver. Sebastien Rannou explains: << Yes, I confirm that my HW does not generate an in-band status. AFAIK, it's a PHY that aggregates 4xSGMIIs to 1xQSGMII ; the MAC side of the PHY (with inband status) is connected to the switch through QSGMII, and in this context we are on the media side of the PHY. >> https://lkml.org/lkml/2015/7/10/206 This patch introduces the new string property 'managed' that allows the user to set the management type explicitly. The supported values are: "auto" - default. Uses either MDIO or nothing, depending on the presence of the fixed-link node "in-band-status" - use in-band status Signed-off-by: Stas Sergeev CC: Rob Herring CC: Pawel Moll CC: Mark Rutland CC: Ian Campbell CC: Kumar Gala CC: Florian Fainelli CC: Grant Likely CC: devicetree@vger.kernel.org CC: linux-kernel@vger.kernel.org CC: netdev@vger.kernel.org Signed-off-by: David S. Miller --- .../devicetree/bindings/net/ethernet.txt | 4 ++++ drivers/of/of_mdio.c | 19 +++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/net/ethernet.txt b/Documentation/devicetree/bindings/net/ethernet.txt index 41b3f3f864e84..5d88f37480b6a 100644 --- a/Documentation/devicetree/bindings/net/ethernet.txt +++ b/Documentation/devicetree/bindings/net/ethernet.txt @@ -25,7 +25,11 @@ The following properties are common to the Ethernet controllers: flow control thresholds. - tx-fifo-depth: the size of the controller's transmit fifo in bytes. This is used for components that can have configurable fifo sizes. +- managed: string, specifies the PHY management type. Supported values are: + "auto", "in-band-status". "auto" is the default, it usess MDIO for + management if fixed-link is not specified. Child nodes of the Ethernet controller are typically the individual PHY devices connected via the MDIO bus (sometimes the MDIO bus controller is separate). They are described in the phy.txt file in this same directory. +For non-MDIO PHY management see fixed-link.txt. diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index fdc60db608291..7c8c23cc6896c 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -266,7 +266,8 @@ EXPORT_SYMBOL(of_phy_attach); bool of_phy_is_fixed_link(struct device_node *np) { struct device_node *dn; - int len; + int len, err; + const char *managed; /* New binding */ dn = of_get_child_by_name(np, "fixed-link"); @@ -275,6 +276,10 @@ bool of_phy_is_fixed_link(struct device_node *np) return true; } + err = of_property_read_string(np, "managed", &managed); + if (err == 0 && strcmp(managed, "auto") != 0) + return true; + /* Old binding */ if (of_get_property(np, "fixed-link", &len) && len == (5 * sizeof(__be32))) @@ -289,8 +294,18 @@ int of_phy_register_fixed_link(struct device_node *np) struct fixed_phy_status status = {}; struct device_node *fixed_link_node; const __be32 *fixed_link_prop; - int len; + int len, err; struct phy_device *phy; + const char *managed; + + err = of_property_read_string(np, "managed", &managed); + if (err == 0) { + if (strcmp(managed, "in-band-status") == 0) { + /* status is zeroed, namely its .link member */ + phy = fixed_phy_register(PHY_POLL, &status, np); + return IS_ERR(phy) ? PTR_ERR(phy) : 0; + } + } /* New binding */ fixed_link_node = of_get_child_by_name(np, "fixed-link"); -- GitLab From f8af8e6eb95093d5ce5ebcc52bd1929b0433e172 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Mon, 20 Jul 2015 17:49:58 -0700 Subject: [PATCH 1434/7006] mvneta: use inband status only when explicitly enabled The commit 898b2970e2c9 ("mvneta: implement SGMII-based in-band link state signaling") implemented the link parameters auto-negotiation unconditionally. Unfortunately it appears that some HW that implements SGMII protocol, doesn't generate the inband status, so it is not possible to auto-negotiate anything with such HW. This patch enables the auto-negotiation only if explicitly requested with the 'managed' DT property. This patch fixes the following regression: https://lkml.org/lkml/2015/7/8/865 Signed-off-by: Stas Sergeev CC: Thomas Petazzoni CC: netdev@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvneta.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c index 370e20ed224c5..e4fb172d91a65 100644 --- a/drivers/net/ethernet/marvell/mvneta.c +++ b/drivers/net/ethernet/marvell/mvneta.c @@ -3029,8 +3029,8 @@ static int mvneta_probe(struct platform_device *pdev) const char *dt_mac_addr; char hw_mac_addr[ETH_ALEN]; const char *mac_from; + const char *managed; int phy_mode; - int fixed_phy = 0; int err; /* Our multiqueue support is not complete, so for now, only @@ -3064,7 +3064,6 @@ static int mvneta_probe(struct platform_device *pdev) dev_err(&pdev->dev, "cannot register fixed PHY\n"); goto err_free_irq; } - fixed_phy = 1; /* In the case of a fixed PHY, the DT node associated * to the PHY is the Ethernet MAC DT node. @@ -3088,8 +3087,10 @@ static int mvneta_probe(struct platform_device *pdev) pp = netdev_priv(dev); pp->phy_node = phy_node; pp->phy_interface = phy_mode; - pp->use_inband_status = (phy_mode == PHY_INTERFACE_MODE_SGMII) && - fixed_phy; + + err = of_property_read_string(dn, "managed", &managed); + pp->use_inband_status = (err == 0 && + strcmp(managed, "in-band-status") == 0); pp->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(pp->clk)) { -- GitLab From 16040894b26af9f85d9395f072c53d76a44eba21 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Tue, 21 Jul 2015 06:42:28 -0400 Subject: [PATCH 1435/7006] tipc: fix compatibility bug In commit d999297c3dbbe7fdd832f7fa4ec84301e170b3e6 ("tipc: reduce locking scope during packet reception") we introduced a new function tipc_link_proto_rcv(). This function contains a bug, so that it sometimes by error sends out a non-zero link priority value in created protocol messages. The bug may lead to an extra link reset at initial link establising with older nodes. This will never happen more than once, whereafter the link will work as intended. We fix this bug in this commit. Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 55b675d20de83..b63d57390bb7c 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1639,7 +1639,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, rcvgap = peers_snd_nxt - l->rcv_nxt; if (rcvgap || (msg_probe(hdr))) tipc_link_build_proto_msg(l, STATE_MSG, 0, rcvgap, - 0, l->mtu, xmitq); + 0, 0, xmitq); tipc_link_release_pkts(l, msg_ack(hdr)); /* If NACK, retransmit will now start at right position */ -- GitLab From 5a33911fa5ecd7395115df2e27fbd22b73357ac5 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Jul 2015 23:50:24 -0400 Subject: [PATCH 1436/7006] ext4: replace ext4_io_submit->io_op with ->io_wbc ext4_io_submit_init() takes the pointer to writeback_control to test its sync_mode and determine between WRITE and WRITE_SYNC and records the result in ->io_op. This patch makes it record the pointer directly and moves the test to ext4_io_submit(). This doesn't cause any noticeable differences now but having writeback_control available throughout IO submission path will be depended upon by the planned cgroup writeback support. Signed-off-by: Tejun Heo Signed-off-by: Theodore Ts'o --- fs/ext4/ext4.h | 2 +- fs/ext4/page-io.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f5e9f04220c1d..32071f5c1c262 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -187,7 +187,7 @@ typedef struct ext4_io_end { } ext4_io_end_t; struct ext4_io_submit { - int io_op; + struct writeback_control *io_wbc; struct bio *io_bio; ext4_io_end_t *io_end; sector_t io_next_block; diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 5602450f03f64..a917bfe3e70c4 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -357,8 +357,10 @@ void ext4_io_submit(struct ext4_io_submit *io) struct bio *bio = io->io_bio; if (bio) { + int io_op = io->io_wbc->sync_mode == WB_SYNC_ALL ? + WRITE_SYNC : WRITE; bio_get(io->io_bio); - submit_bio(io->io_op, io->io_bio); + submit_bio(io_op, io->io_bio); bio_put(io->io_bio); } io->io_bio = NULL; @@ -367,7 +369,7 @@ void ext4_io_submit(struct ext4_io_submit *io) void ext4_io_submit_init(struct ext4_io_submit *io, struct writeback_control *wbc) { - io->io_op = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : WRITE); + io->io_wbc = wbc; io->io_bio = NULL; io->io_end = NULL; } -- GitLab From 001e4a8775f6e8ad52a89e0072f09aee47d5d252 Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 21 Jul 2015 23:51:26 -0400 Subject: [PATCH 1437/7006] ext4: implement cgroup writeback support For ordered and writeback data modes, all data IOs go through ext4_io_submit. This patch adds cgroup writeback support by invoking wbc_init_bio() from io_submit_init_bio() and wbc_account_io() in io_submit_add_bh(). Journal data which is written by jbd2 worker is left alone by this patch and will always be written out from the root cgroup. ext4_fill_super() is updated to set MS_CGROUPWB when data mode is either ordered or writeback. In journaled data mode, most IOs become synchronous through the journal and enabling cgroup writeback support doesn't make much sense or difference. Journaled data mode is left alone. Lightly tested with sequential data write workload. Behaves as expected. Signed-off-by: Tejun Heo Signed-off-by: Theodore Ts'o --- fs/ext4/page-io.c | 2 ++ fs/ext4/super.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index a917bfe3e70c4..58ab2e3dd1147 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -383,6 +383,7 @@ static int io_submit_init_bio(struct ext4_io_submit *io, bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES)); if (!bio) return -ENOMEM; + wbc_init_bio(io->io_wbc, bio); bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); bio->bi_bdev = bh->b_bdev; bio->bi_end_io = ext4_end_bio; @@ -411,6 +412,7 @@ submit_and_retry: ret = bio_add_page(io->io_bio, page, bh->b_size, bh_offset(bh)); if (ret != bh->b_size) goto submit_and_retry; + wbc_account_io(io->io_wbc, page, bh->b_size); io->io_next_block++; return 0; } diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 58987b5c514b2..d2c9a7985fd78 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -3643,6 +3643,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } if (test_opt(sb, DELALLOC)) clear_opt(sb, DELALLOC); + } else { + sb->s_iflags |= SB_I_CGROUPWB; } sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | -- GitLab From 5ba92bcf0dd63b35a85e90c3016989733b239bb5 Mon Sep 17 00:00:00 2001 From: Carlos Maiolino Date: Tue, 21 Jul 2015 23:57:59 -0400 Subject: [PATCH 1438/7006] ext4: reject journal options for ext2 mounts There is no reason to allow ext2 filesystems be mounted with journal mount options. So, this patch adds them to the MOPT_NO_EXT2 mount options list. Signed-off-by: Carlos Maiolino Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index d2c9a7985fd78..14909cd91515d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1394,9 +1394,9 @@ static const struct mount_opts { {Opt_stripe, 0, MOPT_GTE0}, {Opt_resuid, 0, MOPT_GTE0}, {Opt_resgid, 0, MOPT_GTE0}, - {Opt_journal_dev, 0, MOPT_GTE0}, - {Opt_journal_path, 0, MOPT_STRING}, - {Opt_journal_ioprio, 0, MOPT_GTE0}, + {Opt_journal_dev, 0, MOPT_NO_EXT2 | MOPT_GTE0}, + {Opt_journal_path, 0, MOPT_NO_EXT2 | MOPT_STRING}, + {Opt_journal_ioprio, 0, MOPT_NO_EXT2 | MOPT_GTE0}, {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, -- GitLab From d76d99b219e1a233a720775c0451c310d34594e8 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 22 Jul 2015 00:08:08 -0400 Subject: [PATCH 1439/7006] ext4 crypto: exit cleanly if ext4_derive_key_aes() fails Return value of ext4_derive_key_aes() is stored but not used. Add test to exit cleanly if ext4_derive_key_aes() fail. Also fix coverity CID 1309760. Signed-off-by: Laurent Navet Signed-off-by: Theodore Ts'o --- fs/ext4/crypto_key.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c index 442d24e8efc0c..ce75bc8b9aefe 100644 --- a/fs/ext4/crypto_key.c +++ b/fs/ext4/crypto_key.c @@ -220,6 +220,8 @@ retry: BUG_ON(master_key->size != EXT4_AES_256_XTS_KEY_SIZE); res = ext4_derive_key_aes(ctx.nonce, master_key->raw, raw_key); + if (res) + goto out; got_key: ctfm = crypto_alloc_ablkcipher(cipher_str, 0, 0); if (!ctfm || IS_ERR(ctfm)) { -- GitLab From bb9a4e7e824e998070c2a2d1d4c67bc971ab72b8 Mon Sep 17 00:00:00 2001 From: Laurent Navet Date: Wed, 22 Jul 2015 00:09:45 -0400 Subject: [PATCH 1440/7006] ext4 crypto: fix spelling typo in comment Signed-off-by: Laurent Navet Signed-off-by: Theodore Ts'o --- fs/ext4/crypto_key.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/crypto_key.c b/fs/ext4/crypto_key.c index ce75bc8b9aefe..1d510c11b100c 100644 --- a/fs/ext4/crypto_key.c +++ b/fs/ext4/crypto_key.c @@ -30,7 +30,7 @@ static void derive_crypt_complete(struct crypto_async_request *req, int rc) /** * ext4_derive_key_aes() - Derive a key using AES-128-ECB - * @deriving_key: Encryption key used for derivatio. + * @deriving_key: Encryption key used for derivation. * @source_key: Source key to which to apply derivation. * @derived_key: Derived key. * -- GitLab From a9196bb048a78936d097600fb47b0b5ab9cc00d5 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 21 Jul 2015 15:08:56 +0100 Subject: [PATCH 1441/7006] sfc: update MCDI protocol definitions Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/mcdi_pcol.h | 3463 +++++++++++++++++++------- 1 file changed, 2600 insertions(+), 863 deletions(-) diff --git a/drivers/net/ethernet/sfc/mcdi_pcol.h b/drivers/net/ethernet/sfc/mcdi_pcol.h index 45fca9fc66b7c..4cc772164a79b 100644 --- a/drivers/net/ethernet/sfc/mcdi_pcol.h +++ b/drivers/net/ethernet/sfc/mcdi_pcol.h @@ -26,6 +26,10 @@ * Unlike a warm boot, assume DMEM has been reloaded, so that * the MC persistent data must be reinitialised. */ #define MC_FW_TEPID_BOOT_OK (16) +/* We have entered the main firmware via recovery mode. This + * means that MC persistent data must be reinitialised, but that + * we shouldn't touch PCIe config. */ +#define MC_FW_RECOVERY_MODE_PCIE_INIT_OK (32) /* BIST state has been initialized */ #define MC_FW_BIST_INIT_OK (128) @@ -169,6 +173,8 @@ #define MC_CMD_ERR_EINTR 4 /* I/O failure */ #define MC_CMD_ERR_EIO 5 +/* Already exists */ +#define MC_CMD_ERR_EEXIST 6 /* Try again */ #define MC_CMD_ERR_EAGAIN 11 /* Out of memory */ @@ -181,6 +187,10 @@ #define MC_CMD_ERR_ENODEV 19 /* Invalid argument to target */ #define MC_CMD_ERR_EINVAL 22 +/* Broken pipe */ +#define MC_CMD_ERR_EPIPE 32 +/* Read-only */ +#define MC_CMD_ERR_EROFS 30 /* Out of range */ #define MC_CMD_ERR_ERANGE 34 /* Non-recursive resource is already acquired */ @@ -226,6 +236,43 @@ #define MC_CMD_ERR_SLAVE_NOT_PRESENT 0x100a /* The datapath is disabled. */ #define MC_CMD_ERR_DATAPATH_DISABLED 0x100b +/* The requesting client is not a function */ +#define MC_CMD_ERR_CLIENT_NOT_FN 0x100c +/* The requested operation might require the + command to be passed between MCs, and the + transport doesn't support that. Should + only ever been seen over the UART. */ +#define MC_CMD_ERR_TRANSPORT_NOPROXY 0x100d +/* VLAN tag(s) exists */ +#define MC_CMD_ERR_VLAN_EXIST 0x100e +/* No MAC address assigned to an EVB port */ +#define MC_CMD_ERR_NO_MAC_ADDR 0x100f +/* Notifies the driver that the request has been relayed + * to an admin function for authorization. The driver should + * wait for a PROXY_RESPONSE event and then resend its request. + * This error code is followed by a 32-bit handle that + * helps matching it with the respective PROXY_RESPONSE event. */ +#define MC_CMD_ERR_PROXY_PENDING 0x1010 +#define MC_CMD_ERR_PROXY_PENDING_HANDLE_OFST 4 +/* The request cannot be passed for authorization because + * another request from the same function is currently being + * authorized. The drvier should try again later. */ +#define MC_CMD_ERR_PROXY_INPROGRESS 0x1011 +/* Returned by MC_CMD_PROXY_COMPLETE if the caller is not the function + * that has enabled proxying or BLOCK_INDEX points to a function that + * doesn't await an authorization. */ +#define MC_CMD_ERR_PROXY_UNEXPECTED 0x1012 +/* This code is currently only used internally in FW. Its meaning is that + * an operation failed due to lack of SR-IOV privilege. + * Normally it is translated to EPERM by send_cmd_err(), + * but it may also be used to trigger some special mechanism + * for handling such case, e.g. to relay the failed request + * to a designated admin function for authorization. */ +#define MC_CMD_ERR_NO_PRIVILEGE 0x1013 +/* Workaround 26807 could not be turned on/off because some functions + * have already installed filters. See the comment at + * MC_CMD_WORKAROUND_BUG26807. */ +#define MC_CMD_ERR_FILTERS_PRESENT 0x1014 #define MC_CMD_ERR_CODE_OFST 0 @@ -275,6 +322,11 @@ MC_CMD_DBIWROP_TYPEDEF_VALUE_OFST + \ (n) * MC_CMD_DBIWROP_TYPEDEF_LEN) +/* This may be ORed with an EVB_PORT_ID_xxx constant to pass a non-default + * stack ID (which must be in the range 1-255) along with an EVB port ID. + */ +#define EVB_STACK_ID(n) (((n) & 0xff) << 16) + /* Version 2 adds an optional argument to error returns: the errno value * may be followed by the (0-based) number of the first argument that @@ -394,6 +446,8 @@ #define MCDI_EVENT_AOE_BYTEBLASTER 0x9 /* enum: DDR ECC status update */ #define MCDI_EVENT_AOE_DDR_ECC_STATUS 0xa +/* enum: PTP status update */ +#define MCDI_EVENT_AOE_PTP_STATUS 0xb #define MCDI_EVENT_AOE_ERR_DATA_LBN 8 #define MCDI_EVENT_AOE_ERR_DATA_WIDTH 8 #define MCDI_EVENT_RX_ERR_RXQ_LBN 0 @@ -408,6 +462,16 @@ #define MCDI_EVENT_RX_FLUSH_RXQ_WIDTH 12 #define MCDI_EVENT_MC_REBOOT_COUNT_LBN 0 #define MCDI_EVENT_MC_REBOOT_COUNT_WIDTH 16 +#define MCDI_EVENT_MUM_ERR_TYPE_LBN 0 +#define MCDI_EVENT_MUM_ERR_TYPE_WIDTH 8 +/* enum: MUM failed to load - no valid image? */ +#define MCDI_EVENT_MUM_NO_LOAD 0x1 +/* enum: MUM f/w reported an exception */ +#define MCDI_EVENT_MUM_ASSERT 0x2 +/* enum: MUM not kicking watchdog */ +#define MCDI_EVENT_MUM_WATCHDOG 0x3 +#define MCDI_EVENT_MUM_ERR_DATA_LBN 8 +#define MCDI_EVENT_MUM_ERR_DATA_WIDTH 8 #define MCDI_EVENT_DATA_LBN 0 #define MCDI_EVENT_DATA_WIDTH 32 #define MCDI_EVENT_SRC_LBN 36 @@ -416,6 +480,8 @@ #define MCDI_EVENT_EV_CODE_WIDTH 4 #define MCDI_EVENT_CODE_LBN 44 #define MCDI_EVENT_CODE_WIDTH 8 +/* enum: Event generated by host software */ +#define MCDI_EVENT_SW_EVENT 0x0 /* enum: Bad assert. */ #define MCDI_EVENT_CODE_BADSSERT 0x1 /* enum: PM Notice. */ @@ -470,6 +536,14 @@ #define MCDI_EVENT_CODE_MC_BIST 0x19 /* enum: PTP tick event providing current NIC time */ #define MCDI_EVENT_CODE_PTP_TIME 0x1a +/* enum: MUM fault */ +#define MCDI_EVENT_CODE_MUM 0x1b +/* enum: notify the designated PF of a new authorization request */ +#define MCDI_EVENT_CODE_PROXY_REQUEST 0x1c +/* enum: notify a function that awaits an authorization that its request has + * been processed and it may now resend the command + */ +#define MCDI_EVENT_CODE_PROXY_RESPONSE 0x1d /* enum: Artificial event generated by host and posted via MC for test * purposes. */ @@ -537,6 +611,33 @@ /* For CODE_PTP_TIME events, bits 19-26 of the minor value of the PTP clock */ #define MCDI_EVENT_PTP_TIME_MINOR_26_19_LBN 36 #define MCDI_EVENT_PTP_TIME_MINOR_26_19_WIDTH 8 +/* For CODE_PTP_TIME events where report sync status is enabled, indicates + * whether the NIC clock has ever been set + */ +#define MCDI_EVENT_PTP_TIME_NIC_CLOCK_VALID_LBN 36 +#define MCDI_EVENT_PTP_TIME_NIC_CLOCK_VALID_WIDTH 1 +/* For CODE_PTP_TIME events where report sync status is enabled, indicates + * whether the NIC and System clocks are in sync + */ +#define MCDI_EVENT_PTP_TIME_HOST_NIC_IN_SYNC_LBN 37 +#define MCDI_EVENT_PTP_TIME_HOST_NIC_IN_SYNC_WIDTH 1 +/* For CODE_PTP_TIME events where report sync status is enabled, bits 21-26 of + * the minor value of the PTP clock + */ +#define MCDI_EVENT_PTP_TIME_MINOR_26_21_LBN 38 +#define MCDI_EVENT_PTP_TIME_MINOR_26_21_WIDTH 6 +#define MCDI_EVENT_PROXY_REQUEST_BUFF_INDEX_OFST 0 +#define MCDI_EVENT_PROXY_REQUEST_BUFF_INDEX_LBN 0 +#define MCDI_EVENT_PROXY_REQUEST_BUFF_INDEX_WIDTH 32 +#define MCDI_EVENT_PROXY_RESPONSE_HANDLE_OFST 0 +#define MCDI_EVENT_PROXY_RESPONSE_HANDLE_LBN 0 +#define MCDI_EVENT_PROXY_RESPONSE_HANDLE_WIDTH 32 +/* Zero means that the request has been completed or authorized, and the driver + * should resend it. A non-zero value means that the authorization has been + * denied, and gives the reason. Typically it will be EPERM. + */ +#define MCDI_EVENT_PROXY_RESPONSE_RC_LBN 36 +#define MCDI_EVENT_PROXY_RESPONSE_RC_WIDTH 8 /* FCDI_EVENT structuredef */ #define FCDI_EVENT_LEN 8 @@ -581,6 +682,10 @@ #define FCDI_EVENT_CODE_PTP_TICK 0x7 /* enum: ECC error counters */ #define FCDI_EVENT_CODE_DDR_ECC_STATUS 0x8 +/* enum: Current status of PTP */ +#define FCDI_EVENT_CODE_PTP_STATUS 0x9 +/* enum: Port id config to map MC-FC port idx */ +#define FCDI_EVENT_CODE_PORT_CONFIG 0xa #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_OFST 0 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_LBN 0 #define FCDI_EVENT_ASSERT_INSTR_ADDRESS_WIDTH 32 @@ -594,11 +699,24 @@ #define FCDI_EVENT_LINK_STATE_DATA_OFST 0 #define FCDI_EVENT_LINK_STATE_DATA_LBN 0 #define FCDI_EVENT_LINK_STATE_DATA_WIDTH 32 +#define FCDI_EVENT_PTP_STATE_OFST 0 +#define FCDI_EVENT_PTP_UNDEFINED 0x0 /* enum */ +#define FCDI_EVENT_PTP_SETUP_FAILED 0x1 /* enum */ +#define FCDI_EVENT_PTP_OPERATIONAL 0x2 /* enum */ +#define FCDI_EVENT_PTP_STATE_LBN 0 +#define FCDI_EVENT_PTP_STATE_WIDTH 32 #define FCDI_EVENT_DDR_ECC_STATUS_BANK_ID_LBN 36 #define FCDI_EVENT_DDR_ECC_STATUS_BANK_ID_WIDTH 8 #define FCDI_EVENT_DDR_ECC_STATUS_STATUS_OFST 0 #define FCDI_EVENT_DDR_ECC_STATUS_STATUS_LBN 0 #define FCDI_EVENT_DDR_ECC_STATUS_STATUS_WIDTH 32 +/* Index of MC port being referred to */ +#define FCDI_EVENT_PORT_CONFIG_SRC_LBN 36 +#define FCDI_EVENT_PORT_CONFIG_SRC_WIDTH 8 +/* FC Port index that matches the MC port index in SRC */ +#define FCDI_EVENT_PORT_CONFIG_DATA_OFST 0 +#define FCDI_EVENT_PORT_CONFIG_DATA_LBN 0 +#define FCDI_EVENT_PORT_CONFIG_DATA_WIDTH 32 /* FCDI_EXTENDED_EVENT_PPS structuredef: Extended FCDI event to send PPS events * to the MC. Note that this structure | is overlayed over a normal FCDI event @@ -631,6 +749,90 @@ #define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_LBN 64 #define FCDI_EXTENDED_EVENT_PPS_TIMESTAMPS_WIDTH 64 +/* MUM_EVENT structuredef */ +#define MUM_EVENT_LEN 8 +#define MUM_EVENT_CONT_LBN 32 +#define MUM_EVENT_CONT_WIDTH 1 +#define MUM_EVENT_LEVEL_LBN 33 +#define MUM_EVENT_LEVEL_WIDTH 3 +/* enum: Info. */ +#define MUM_EVENT_LEVEL_INFO 0x0 +/* enum: Warning. */ +#define MUM_EVENT_LEVEL_WARN 0x1 +/* enum: Error. */ +#define MUM_EVENT_LEVEL_ERR 0x2 +/* enum: Fatal. */ +#define MUM_EVENT_LEVEL_FATAL 0x3 +#define MUM_EVENT_DATA_OFST 0 +#define MUM_EVENT_SENSOR_ID_LBN 0 +#define MUM_EVENT_SENSOR_ID_WIDTH 8 +/* Enum values, see field(s): */ +/* MC_CMD_SENSOR_INFO/MC_CMD_SENSOR_INFO_OUT/MASK */ +#define MUM_EVENT_SENSOR_STATE_LBN 8 +#define MUM_EVENT_SENSOR_STATE_WIDTH 8 +#define MUM_EVENT_PORT_PHY_READY_LBN 0 +#define MUM_EVENT_PORT_PHY_READY_WIDTH 1 +#define MUM_EVENT_PORT_PHY_LINK_UP_LBN 1 +#define MUM_EVENT_PORT_PHY_LINK_UP_WIDTH 1 +#define MUM_EVENT_PORT_PHY_TX_LOL_LBN 2 +#define MUM_EVENT_PORT_PHY_TX_LOL_WIDTH 1 +#define MUM_EVENT_PORT_PHY_RX_LOL_LBN 3 +#define MUM_EVENT_PORT_PHY_RX_LOL_WIDTH 1 +#define MUM_EVENT_PORT_PHY_TX_LOS_LBN 4 +#define MUM_EVENT_PORT_PHY_TX_LOS_WIDTH 1 +#define MUM_EVENT_PORT_PHY_RX_LOS_LBN 5 +#define MUM_EVENT_PORT_PHY_RX_LOS_WIDTH 1 +#define MUM_EVENT_PORT_PHY_TX_FAULT_LBN 6 +#define MUM_EVENT_PORT_PHY_TX_FAULT_WIDTH 1 +#define MUM_EVENT_DATA_LBN 0 +#define MUM_EVENT_DATA_WIDTH 32 +#define MUM_EVENT_SRC_LBN 36 +#define MUM_EVENT_SRC_WIDTH 8 +#define MUM_EVENT_EV_CODE_LBN 60 +#define MUM_EVENT_EV_CODE_WIDTH 4 +#define MUM_EVENT_CODE_LBN 44 +#define MUM_EVENT_CODE_WIDTH 8 +/* enum: The MUM was rebooted. */ +#define MUM_EVENT_CODE_REBOOT 0x1 +/* enum: Bad assert. */ +#define MUM_EVENT_CODE_ASSERT 0x2 +/* enum: Sensor failure. */ +#define MUM_EVENT_CODE_SENSOR 0x3 +/* enum: Link fault has been asserted, or has cleared. */ +#define MUM_EVENT_CODE_QSFP_LASI_INTERRUPT 0x4 +#define MUM_EVENT_SENSOR_DATA_OFST 0 +#define MUM_EVENT_SENSOR_DATA_LBN 0 +#define MUM_EVENT_SENSOR_DATA_WIDTH 32 +#define MUM_EVENT_PORT_PHY_FLAGS_OFST 0 +#define MUM_EVENT_PORT_PHY_FLAGS_LBN 0 +#define MUM_EVENT_PORT_PHY_FLAGS_WIDTH 32 +#define MUM_EVENT_PORT_PHY_COPPER_LEN_OFST 0 +#define MUM_EVENT_PORT_PHY_COPPER_LEN_LBN 0 +#define MUM_EVENT_PORT_PHY_COPPER_LEN_WIDTH 32 +#define MUM_EVENT_PORT_PHY_CAPS_OFST 0 +#define MUM_EVENT_PORT_PHY_CAPS_LBN 0 +#define MUM_EVENT_PORT_PHY_CAPS_WIDTH 32 +#define MUM_EVENT_PORT_PHY_TECH_OFST 0 +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_UNKNOWN 0x0 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_OPTICAL 0x1 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_PASSIVE 0x2 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_PASSIVE_EQUALIZED 0x3 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_ACTIVE_LIMITING 0x4 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_COPPER_ACTIVE_LINEAR 0x5 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_BASE_T 0x6 /* enum */ +#define MUM_EVENT_PORT_PHY_STATE_QSFP_MODULE_TECH_LOOPBACK_PASSIVE 0x7 /* enum */ +#define MUM_EVENT_PORT_PHY_TECH_LBN 0 +#define MUM_EVENT_PORT_PHY_TECH_WIDTH 32 +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_LBN 36 +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_WIDTH 4 +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_FLAGS 0x0 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_COPPER_LEN 0x1 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_CAPS 0x2 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_TECH 0x3 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_DATA_ID_MAX 0x4 /* enum */ +#define MUM_EVENT_PORT_PHY_SRC_PORT_NO_LBN 40 +#define MUM_EVENT_PORT_PHY_SRC_PORT_NO_WIDTH 4 + /***********************************/ /* MC_CMD_READ32 @@ -687,24 +889,34 @@ /* MC_CMD_COPYCODE_IN msgrequest */ #define MC_CMD_COPYCODE_IN_LEN 16 -/* Source address */ -#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 -/* enum: The main image should be entered via a copy of a single word from and - * to this address when none of the other magic behaviours are required. +/* Source address + * + * The main image should be entered via a copy of a single word from and to a + * magic address, which controls various aspects of the boot. The magic address + * is a bitfield, with each bit as documented below. */ +#define MC_CMD_COPYCODE_IN_SRC_ADDR_OFST 0 +/* enum: Deprecated; equivalent to setting BOOT_MAGIC_PRESENT (see below) */ #define MC_CMD_COPYCODE_HUNT_NO_MAGIC_ADDR 0x10000 -/* enum: Entering the main image via a copy of a single word from and to this - * address indicates that it should not attempt to start the datapath CPUs. - * This is useful for certain soft rebooting scenarios. (Huntington only) +/* enum: Deprecated; equivalent to setting BOOT_MAGIC_PRESENT and + * BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED (see below) */ #define MC_CMD_COPYCODE_HUNT_NO_DATAPATH_MAGIC_ADDR 0x1d0d0 -/* enum: Entering the main image via a copy of a single word from and to this - * address indicates that it should not attempt to parse any configuration from - * flash. (In addition, the datapath CPUs will not be started, as for - * MC_CMD_COPYCODE_HUNT_NO_DATAPATH_MAGIC_ADDR above.) This is useful for - * certain soft rebooting scenarios. (Huntington only) +/* enum: Deprecated; equivalent to setting BOOT_MAGIC_PRESENT, + * BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED and BOOT_MAGIC_IGNORE_CONFIG (see + * below) */ #define MC_CMD_COPYCODE_HUNT_IGNORE_CONFIG_MAGIC_ADDR 0x1badc +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_PRESENT_LBN 17 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_PRESENT_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED_LBN 2 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SATELLITE_CPUS_NOT_LOADED_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_IGNORE_CONFIG_LBN 3 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_IGNORE_CONFIG_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SKIP_BOOT_ICORE_SYNC_LBN 4 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_SKIP_BOOT_ICORE_SYNC_WIDTH 1 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_FORCE_STANDALONE_LBN 5 +#define MC_CMD_COPYCODE_IN_BOOT_MAGIC_FORCE_STANDALONE_WIDTH 1 /* Destination address */ #define MC_CMD_COPYCODE_IN_DEST_ADDR_OFST 4 #define MC_CMD_COPYCODE_IN_NUMWORDS_OFST 8 @@ -795,6 +1007,10 @@ #define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_OFST 8 #define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_LEN 4 #define MC_CMD_GET_ASSERTS_OUT_GP_REGS_OFFS_NUM 31 +/* enum: A magic value hinting that the value in this register at the time of + * the failure has likely been lost. + */ +#define MC_CMD_GET_ASSERTS_REG_NO_DATA 0xda7a1057 /* Failing thread address */ #define MC_CMD_GET_ASSERTS_OUT_THREAD_OFFS_OFST 132 #define MC_CMD_GET_ASSERTS_OUT_RESERVED_OFST 136 @@ -802,7 +1018,8 @@ /***********************************/ /* MC_CMD_LOG_CTRL - * Configure the output stream for various events and messages. + * Configure the output stream for log events such as link state changes, + * sensor notifications and MCDI completions */ #define MC_CMD_LOG_CTRL 0x7 @@ -816,6 +1033,7 @@ #define MC_CMD_LOG_CTRL_IN_LOG_DEST_UART 0x1 /* enum: Event queue. */ #define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ 0x2 +/* Legacy argument. Must be zero. */ #define MC_CMD_LOG_CTRL_IN_LOG_DEST_EVQ_OFST 4 /* MC_CMD_LOG_CTRL_OUT msgresponse */ @@ -955,8 +1173,12 @@ * input on the same NIC. */ #define MC_CMD_PTP_OP_MANFTEST_PPS 0x1a +/* enum: Set the PTP sync status. Status is used by firmware to report to event + * subscribers. + */ +#define MC_CMD_PTP_OP_SET_SYNC_STATUS 0x1b /* enum: Above this for future use. */ -#define MC_CMD_PTP_OP_MAX 0x1b +#define MC_CMD_PTP_OP_MAX 0x1c /* MC_CMD_PTP_IN_ENABLE msgrequest */ #define MC_CMD_PTP_IN_ENABLE_LEN 16 @@ -1191,8 +1413,12 @@ #define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_LEN 12 /* MC_CMD_PTP_IN_CMD_OFST 0 */ /* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ -/* Event queue to send PTP time events to */ +/* Original field containing queue ID. Now extended to include flags. */ #define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_OFST 8 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_ID_LBN 0 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_QUEUE_ID_WIDTH 16 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_REPORT_SYNC_STATUS_LBN 31 +#define MC_CMD_PTP_IN_TIME_EVENT_SUBSCRIBE_REPORT_SYNC_STATUS_WIDTH 1 /* MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE msgrequest */ #define MC_CMD_PTP_IN_TIME_EVENT_UNSUBSCRIBE_LEN 16 @@ -1214,6 +1440,23 @@ /* 1 to enable PPS test mode, 0 to disable and return result. */ #define MC_CMD_PTP_IN_MANFTEST_PPS_TEST_ENABLE_OFST 8 +/* MC_CMD_PTP_IN_SET_SYNC_STATUS msgrequest */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_LEN 24 +/* MC_CMD_PTP_IN_CMD_OFST 0 */ +/* MC_CMD_PTP_IN_PERIPH_ID_OFST 4 */ +/* NIC - Host System Clock Synchronization status */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_STATUS_OFST 8 +/* enum: Host System clock and NIC clock are not in sync */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_NOT_IN_SYNC 0x0 +/* enum: Host System clock and NIC clock are synchronized */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_IN_SYNC 0x1 +/* If synchronized, number of seconds until clocks should be considered to be + * no longer in sync. + */ +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_TIMEOUT_OFST 12 +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_RESERVED0_OFST 16 +#define MC_CMD_PTP_IN_SET_SYNC_STATUS_RESERVED1_OFST 20 + /* MC_CMD_PTP_OUT msgresponse */ #define MC_CMD_PTP_OUT_LEN 0 @@ -1375,7 +1618,7 @@ #define MC_CMD_PTP_OUT_GET_TIME_FORMAT_SECONDS_27FRACTION 0x2 /* MC_CMD_PTP_OUT_GET_ATTRIBUTES msgresponse */ -#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN 8 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_LEN 24 /* Time format required/used by for this NIC. Applies to all PTP MCDI * operations that pass times between the host and firmware. If this operation * is not supported (older firmware) a format of seconds and nanoseconds should @@ -1396,6 +1639,13 @@ * end and start times minus the time that the MC waited for host end. */ #define MC_CMD_PTP_OUT_GET_ATTRIBUTES_SYNC_WINDOW_MIN_OFST 4 +/* Various PTP capabilities */ +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_CAPABILITIES_OFST 8 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_REPORT_SYNC_STATUS_LBN 0 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_REPORT_SYNC_STATUS_WIDTH 1 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_RESERVED0_OFST 12 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_RESERVED1_OFST 16 +#define MC_CMD_PTP_OUT_GET_ATTRIBUTES_RESERVED2_OFST 20 /* MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS msgresponse */ #define MC_CMD_PTP_OUT_GET_TIMESTAMP_CORRECTIONS_LEN 16 @@ -1415,6 +1665,9 @@ /* Enum values, see field(s): */ /* MC_CMD_PTP_OUT_MANFTEST_BASIC/TEST_RESULT */ +/* MC_CMD_PTP_OUT_SET_SYNC_STATUS msgresponse */ +#define MC_CMD_PTP_OUT_SET_SYNC_STATUS_LEN 0 + /***********************************/ /* MC_CMD_CSR_READ32 @@ -1915,6 +2168,14 @@ #define MC_CMD_FW_FULL_FEATURED 0x0 /* enum: Prefer to use firmware with fewer features but lower latency */ #define MC_CMD_FW_LOW_LATENCY 0x1 +/* enum: Prefer to use firmware for SolarCapture packed stream mode */ +#define MC_CMD_FW_PACKED_STREAM 0x2 +/* enum: Prefer to use firmware with fewer features and simpler TX event + * batching but higher TX packet rate + */ +#define MC_CMD_FW_HIGH_TX_RATE 0x3 +/* enum: Reserved value */ +#define MC_CMD_FW_PACKED_STREAM_HASH_MODE_1 0x4 /* enum: Only this option is allowed for non-admin functions */ #define MC_CMD_FW_DONT_CARE 0xffffffff @@ -2481,6 +2742,12 @@ #define MC_CMD_LOOPBACK_SD_FES_WS 0x22 /* enum: Near side of AOE Siena side port */ #define MC_CMD_LOOPBACK_AOE_INT_NEAR 0x23 +/* enum: Medford Wireside datapath loopback */ +#define MC_CMD_LOOPBACK_DATA_WS 0x24 +/* enum: Force link up without setting up any physical loopback (snapper use + * only) + */ +#define MC_CMD_LOOPBACK_FORCE_EXT_LINK 0x25 /* Supported loopbacks. */ #define MC_CMD_GET_LOOPBACK_MODES_OUT_1G_OFST 8 #define MC_CMD_GET_LOOPBACK_MODES_OUT_1G_LEN 8 @@ -2552,12 +2819,8 @@ #define MC_CMD_GET_LINK_OUT_LINK_FAULT_TX_WIDTH 1 /* This returns the negotiated flow control value. */ #define MC_CMD_GET_LINK_OUT_FCNTL_OFST 20 -/* enum: Flow control is off. */ -#define MC_CMD_FCNTL_OFF 0x0 -/* enum: Respond to flow control. */ -#define MC_CMD_FCNTL_RESPOND 0x1 -/* enum: Respond to and Issue flow control. */ -#define MC_CMD_FCNTL_BIDIR 0x2 +/* Enum values, see field(s): */ +/* MC_CMD_SET_MAC/MC_CMD_SET_MAC_IN/FCNTL */ #define MC_CMD_GET_LINK_OUT_MAC_FAULT_OFST 24 #define MC_CMD_MAC_FAULT_XGMII_LOCAL_LBN 0 #define MC_CMD_MAC_FAULT_XGMII_LOCAL_WIDTH 1 @@ -2632,7 +2895,7 @@ #define MC_CMD_0x2c_PRIVILEGE_CTG SRIOV_CTG_LINK /* MC_CMD_SET_MAC_IN msgrequest */ -#define MC_CMD_SET_MAC_IN_LEN 24 +#define MC_CMD_SET_MAC_IN_LEN 28 /* The MTU is the MTU programmed directly into the XMAC/GMAC (inclusive of * EtherII, VLAN, bug16011 padding). */ @@ -2649,13 +2912,20 @@ #define MC_CMD_SET_MAC_IN_REJECT_BRDCST_WIDTH 1 #define MC_CMD_SET_MAC_IN_FCNTL_OFST 20 /* enum: Flow control is off. */ -/* MC_CMD_FCNTL_OFF 0x0 */ +#define MC_CMD_FCNTL_OFF 0x0 /* enum: Respond to flow control. */ -/* MC_CMD_FCNTL_RESPOND 0x1 */ +#define MC_CMD_FCNTL_RESPOND 0x1 /* enum: Respond to and Issue flow control. */ -/* MC_CMD_FCNTL_BIDIR 0x2 */ +#define MC_CMD_FCNTL_BIDIR 0x2 /* enum: Auto neg flow control. */ #define MC_CMD_FCNTL_AUTO 0x3 +/* enum: Priority flow control (eftest builds only). */ +#define MC_CMD_FCNTL_QBB 0x4 +/* enum: Issue flow control. */ +#define MC_CMD_FCNTL_GENERATE 0x5 +#define MC_CMD_SET_MAC_IN_FLAGS_OFST 24 +#define MC_CMD_SET_MAC_IN_FLAG_INCLUDE_FCS_LBN 0 +#define MC_CMD_SET_MAC_IN_FLAG_INCLUDE_FCS_WIDTH 1 /* MC_CMD_SET_MAC_OUT msgresponse */ #define MC_CMD_SET_MAC_OUT_LEN 0 @@ -2748,7 +3018,8 @@ * guarantee consistent results. If the DMA_ADDR is 0, then no DMA is * performed, and the statistics may be read from the message response. If * DMA_ADDR != 0, then the statistics are dmad to that (page-aligned location). - * Locks required: None. Returns: 0, ETIME + * Locks required: None. The PERIODIC_CLEAR option is not used and now has no + * effect. Returns: 0, ETIME */ #define MC_CMD_MAC_STATS 0x2e @@ -2791,6 +3062,7 @@ #define MC_CMD_MAC_STATS_OUT_NO_DMA_STATISTICS_HI_OFST 4 #define MC_CMD_MAC_STATS_OUT_NO_DMA_STATISTICS_NUM MC_CMD_MAC_NSTATS #define MC_CMD_MAC_GENERATION_START 0x0 /* enum */ +#define MC_CMD_MAC_DMABUF_START 0x1 /* enum */ #define MC_CMD_MAC_TX_PKTS 0x1 /* enum */ #define MC_CMD_MAC_TX_PAUSE_PKTS 0x2 /* enum */ #define MC_CMD_MAC_TX_CONTROL_PKTS 0x3 /* enum */ @@ -2890,8 +3162,8 @@ * PM_AND_RXDP_COUNTERS capability only. */ #define MC_CMD_MAC_RXDP_STREAMING_PKTS 0x46 -/* enum: RXDP counter: Number of times an emergency descriptor fetch was - * performed. Valid for EF10 with PM_AND_RXDP_COUNTERS capability only. +/* enum: RXDP counter: Number of times an hlb descriptor fetch was performed. + * Valid for EF10 with PM_AND_RXDP_COUNTERS capability only. */ #define MC_CMD_MAC_RXDP_HLB_FETCH_CONDITIONS 0x47 /* enum: RXDP counter: Number of times the DPCPU waited for an existing @@ -3213,6 +3485,8 @@ #define MC_CMD_NVRAM_TYPE_LICENSE 0x12 /* enum: FC Log. */ #define MC_CMD_NVRAM_TYPE_FC_LOG 0x13 +/* enum: Additional flash on FPGA. */ +#define MC_CMD_NVRAM_TYPE_FC_EXTRA 0x14 /***********************************/ @@ -3407,6 +3681,8 @@ */ #define MC_CMD_SCHEDINFO 0x3e +#define MC_CMD_0x3e_PRIVILEGE_CTG SRIOV_CTG_ADMIN + /* MC_CMD_SCHEDINFO_IN msgrequest */ #define MC_CMD_SCHEDINFO_IN_LEN 0 @@ -3593,6 +3869,68 @@ #define MC_CMD_SENSOR_VDD08D_VSS08D_CSR_EXTADC 0x2c /* enum: Hotpoint temperature: degC */ #define MC_CMD_SENSOR_HOTPOINT_TEMP 0x2d +/* enum: Port 0 PHY power switch over-current: bool */ +#define MC_CMD_SENSOR_PHY_POWER_PORT0 0x2e +/* enum: Port 1 PHY power switch over-current: bool */ +#define MC_CMD_SENSOR_PHY_POWER_PORT1 0x2f +/* enum: Mop-up microcontroller reference voltage (millivolts) */ +#define MC_CMD_SENSOR_MUM_VCC 0x30 +/* enum: 0.9v power phase A voltage: mV */ +#define MC_CMD_SENSOR_IN_0V9_A 0x31 +/* enum: 0.9v power phase A current: mA */ +#define MC_CMD_SENSOR_IN_I0V9_A 0x32 +/* enum: 0.9V voltage regulator phase A temperature: degC */ +#define MC_CMD_SENSOR_VREG_0V9_A_TEMP 0x33 +/* enum: 0.9v power phase B voltage: mV */ +#define MC_CMD_SENSOR_IN_0V9_B 0x34 +/* enum: 0.9v power phase B current: mA */ +#define MC_CMD_SENSOR_IN_I0V9_B 0x35 +/* enum: 0.9V voltage regulator phase B temperature: degC */ +#define MC_CMD_SENSOR_VREG_0V9_B_TEMP 0x36 +/* enum: CCOM AVREG 1v2 supply (interval ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V2_SUPPLY 0x37 +/* enum: CCOM AVREG 1v2 supply (external ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V2_SUPPLY_EXTADC 0x38 +/* enum: CCOM AVREG 1v8 supply (interval ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V8_SUPPLY 0x39 +/* enum: CCOM AVREG 1v8 supply (external ADC): mV */ +#define MC_CMD_SENSOR_CCOM_AVREG_1V8_SUPPLY_EXTADC 0x3a +/* enum: Not a sensor: reserved for the next page flag */ +#define MC_CMD_SENSOR_PAGE1_NEXT 0x3f +/* enum: controller internal temperature sensor voltage on master core + * (internal ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_VPTAT 0x40 +/* enum: controller internal temperature on master core (internal ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_INTERNAL_TEMP 0x41 +/* enum: controller internal temperature sensor voltage on master core + * (external ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_VPTAT_EXTADC 0x42 +/* enum: controller internal temperature on master core (external ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_MASTER_INTERNAL_TEMP_EXTADC 0x43 +/* enum: controller internal temperature on slave core sensor voltage (internal + * ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_VPTAT 0x44 +/* enum: controller internal temperature on slave core (internal ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_INTERNAL_TEMP 0x45 +/* enum: controller internal temperature on slave core sensor voltage (external + * ADC): mV + */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_VPTAT_EXTADC 0x46 +/* enum: controller internal temperature on slave core (external ADC): degC */ +#define MC_CMD_SENSOR_CONTROLLER_SLAVE_INTERNAL_TEMP_EXTADC 0x47 +/* enum: Voltage supplied to the SODIMMs from their power supply: mV */ +#define MC_CMD_SENSOR_SODIMM_VOUT 0x49 +/* enum: Temperature of SODIMM 0 (if installed): degC */ +#define MC_CMD_SENSOR_SODIMM_0_TEMP 0x4a +/* enum: Temperature of SODIMM 1 (if installed): degC */ +#define MC_CMD_SENSOR_SODIMM_1_TEMP 0x4b +/* enum: Voltage supplied to the QSFP #0 from their power supply: mV */ +#define MC_CMD_SENSOR_PHY0_VCC 0x4c +/* enum: Voltage supplied to the QSFP #1 from their power supply: mV */ +#define MC_CMD_SENSOR_PHY1_VCC 0x4d /* MC_CMD_SENSOR_INFO_ENTRY_TYPEDEF */ #define MC_CMD_SENSOR_ENTRY_OFST 4 #define MC_CMD_SENSOR_ENTRY_LEN 8 @@ -3701,6 +4039,8 @@ #define MC_CMD_SENSOR_STATE_BROKEN 0x3 /* enum: Sensor is working but does not currently have a reading. */ #define MC_CMD_SENSOR_STATE_NO_READING 0x4 +/* enum: Sensor initialisation failed. */ +#define MC_CMD_SENSOR_STATE_INIT_FAILED 0x5 #define MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE_LBN 16 #define MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_STATE_WIDTH 8 #define MC_CMD_SENSOR_VALUE_ENTRY_TYPEDEF_TYPE_OFST 3 @@ -3870,6 +4210,7 @@ /* MC_CMD_WORKAROUND_IN msgrequest */ #define MC_CMD_WORKAROUND_IN_LEN 8 +/* The enums here must correspond with those in MC_CMD_GET_WORKAROUND. */ #define MC_CMD_WORKAROUND_IN_TYPE_OFST 0 /* enum: Bug 17230 work around. */ #define MC_CMD_WORKAROUND_BUG17230 0x1 @@ -3877,11 +4218,38 @@ #define MC_CMD_WORKAROUND_BUG35388 0x2 /* enum: Bug35017 workaround (A64 tables must be identity map) */ #define MC_CMD_WORKAROUND_BUG35017 0x3 +/* enum: Bug 41750 present (MC_CMD_TRIGGER_INTERRUPT won't work) */ +#define MC_CMD_WORKAROUND_BUG41750 0x4 +/* enum: Bug 42008 present (Interrupts can overtake associated events). Caution + * - before adding code that queries this workaround, remember that there's + * released Monza firmware that doesn't understand MC_CMD_WORKAROUND_BUG42008, + * and will hence (incorrectly) report that the bug doesn't exist. + */ +#define MC_CMD_WORKAROUND_BUG42008 0x5 +/* enum: Bug 26807 features present in firmware (multicast filter chaining) + * This feature cannot be turned on/off while there are any filters already + * present. The behaviour in such case depends on the acting client's privilege + * level. If the client has the admin privilege, then all functions that have + * filters installed will be FLRed and the FLR_DONE flag will be set. Otherwise + * the command will fail with MC_CMD_ERR_FILTERS_PRESENT. + */ +#define MC_CMD_WORKAROUND_BUG26807 0x6 +/* 0 = disable the workaround indicated by TYPE; any non-zero value = enable + * the workaround + */ #define MC_CMD_WORKAROUND_IN_ENABLED_OFST 4 /* MC_CMD_WORKAROUND_OUT msgresponse */ #define MC_CMD_WORKAROUND_OUT_LEN 0 +/* MC_CMD_WORKAROUND_EXT_OUT msgresponse: This response format will be used + * when (TYPE == MC_CMD_WORKAROUND_BUG26807) + */ +#define MC_CMD_WORKAROUND_EXT_OUT_LEN 4 +#define MC_CMD_WORKAROUND_EXT_OUT_FLAGS_OFST 0 +#define MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN 0 +#define MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_WIDTH 1 + /***********************************/ /* MC_CMD_GET_PHY_MEDIA_INFO @@ -4093,7 +4461,7 @@ /***********************************/ /* MC_CMD_GET_MAC_ADDRESSES - * Returns the base MAC, count and stride for the requestiong function + * Returns the base MAC, count and stride for the requesting function */ #define MC_CMD_GET_MAC_ADDRESSES 0x55 @@ -4115,6 +4483,527 @@ /* Spacing of allocated MAC addresses */ #define MC_CMD_GET_MAC_ADDRESSES_OUT_MAC_STRIDE_OFST 12 + +/***********************************/ +/* MC_CMD_CLP + * Perform a CLP related operation + */ +#define MC_CMD_CLP 0x56 + +#define MC_CMD_0x56_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_CLP_IN msgrequest */ +#define MC_CMD_CLP_IN_LEN 4 +/* Sub operation */ +#define MC_CMD_CLP_IN_OP_OFST 0 +/* enum: Return to factory default settings */ +#define MC_CMD_CLP_OP_DEFAULT 0x1 +/* enum: Set MAC address */ +#define MC_CMD_CLP_OP_SET_MAC 0x2 +/* enum: Get MAC address */ +#define MC_CMD_CLP_OP_GET_MAC 0x3 +/* enum: Set UEFI/GPXE boot mode */ +#define MC_CMD_CLP_OP_SET_BOOT 0x4 +/* enum: Get UEFI/GPXE boot mode */ +#define MC_CMD_CLP_OP_GET_BOOT 0x5 + +/* MC_CMD_CLP_OUT msgresponse */ +#define MC_CMD_CLP_OUT_LEN 0 + +/* MC_CMD_CLP_IN_DEFAULT msgrequest */ +#define MC_CMD_CLP_IN_DEFAULT_LEN 4 +/* MC_CMD_CLP_IN_OP_OFST 0 */ + +/* MC_CMD_CLP_OUT_DEFAULT msgresponse */ +#define MC_CMD_CLP_OUT_DEFAULT_LEN 0 + +/* MC_CMD_CLP_IN_SET_MAC msgrequest */ +#define MC_CMD_CLP_IN_SET_MAC_LEN 12 +/* MC_CMD_CLP_IN_OP_OFST 0 */ +/* MAC address assigned to port */ +#define MC_CMD_CLP_IN_SET_MAC_ADDR_OFST 4 +#define MC_CMD_CLP_IN_SET_MAC_ADDR_LEN 6 +/* Padding */ +#define MC_CMD_CLP_IN_SET_MAC_RESERVED_OFST 10 +#define MC_CMD_CLP_IN_SET_MAC_RESERVED_LEN 2 + +/* MC_CMD_CLP_OUT_SET_MAC msgresponse */ +#define MC_CMD_CLP_OUT_SET_MAC_LEN 0 + +/* MC_CMD_CLP_IN_GET_MAC msgrequest */ +#define MC_CMD_CLP_IN_GET_MAC_LEN 4 +/* MC_CMD_CLP_IN_OP_OFST 0 */ + +/* MC_CMD_CLP_OUT_GET_MAC msgresponse */ +#define MC_CMD_CLP_OUT_GET_MAC_LEN 8 +/* MAC address assigned to port */ +#define MC_CMD_CLP_OUT_GET_MAC_ADDR_OFST 0 +#define MC_CMD_CLP_OUT_GET_MAC_ADDR_LEN 6 +/* Padding */ +#define MC_CMD_CLP_OUT_GET_MAC_RESERVED_OFST 6 +#define MC_CMD_CLP_OUT_GET_MAC_RESERVED_LEN 2 + +/* MC_CMD_CLP_IN_SET_BOOT msgrequest */ +#define MC_CMD_CLP_IN_SET_BOOT_LEN 5 +/* MC_CMD_CLP_IN_OP_OFST 0 */ +/* Boot flag */ +#define MC_CMD_CLP_IN_SET_BOOT_FLAG_OFST 4 +#define MC_CMD_CLP_IN_SET_BOOT_FLAG_LEN 1 + +/* MC_CMD_CLP_OUT_SET_BOOT msgresponse */ +#define MC_CMD_CLP_OUT_SET_BOOT_LEN 0 + +/* MC_CMD_CLP_IN_GET_BOOT msgrequest */ +#define MC_CMD_CLP_IN_GET_BOOT_LEN 4 +/* MC_CMD_CLP_IN_OP_OFST 0 */ + +/* MC_CMD_CLP_OUT_GET_BOOT msgresponse */ +#define MC_CMD_CLP_OUT_GET_BOOT_LEN 4 +/* Boot flag */ +#define MC_CMD_CLP_OUT_GET_BOOT_FLAG_OFST 0 +#define MC_CMD_CLP_OUT_GET_BOOT_FLAG_LEN 1 +/* Padding */ +#define MC_CMD_CLP_OUT_GET_BOOT_RESERVED_OFST 1 +#define MC_CMD_CLP_OUT_GET_BOOT_RESERVED_LEN 3 + + +/***********************************/ +/* MC_CMD_MUM + * Perform a MUM operation + */ +#define MC_CMD_MUM 0x57 + +#define MC_CMD_0x57_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_MUM_IN msgrequest */ +#define MC_CMD_MUM_IN_LEN 4 +#define MC_CMD_MUM_IN_OP_HDR_OFST 0 +#define MC_CMD_MUM_IN_OP_LBN 0 +#define MC_CMD_MUM_IN_OP_WIDTH 8 +/* enum: NULL MCDI command to MUM */ +#define MC_CMD_MUM_OP_NULL 0x1 +/* enum: Get MUM version */ +#define MC_CMD_MUM_OP_GET_VERSION 0x2 +/* enum: Issue raw I2C command to MUM */ +#define MC_CMD_MUM_OP_RAW_CMD 0x3 +/* enum: Read from registers on devices connected to MUM. */ +#define MC_CMD_MUM_OP_READ 0x4 +/* enum: Write to registers on devices connected to MUM. */ +#define MC_CMD_MUM_OP_WRITE 0x5 +/* enum: Control UART logging. */ +#define MC_CMD_MUM_OP_LOG 0x6 +/* enum: Operations on MUM GPIO lines */ +#define MC_CMD_MUM_OP_GPIO 0x7 +/* enum: Get sensor readings from MUM */ +#define MC_CMD_MUM_OP_READ_SENSORS 0x8 +/* enum: Initiate clock programming on the MUM */ +#define MC_CMD_MUM_OP_PROGRAM_CLOCKS 0x9 +/* enum: Initiate FPGA load from flash on the MUM */ +#define MC_CMD_MUM_OP_FPGA_LOAD 0xa +/* enum: Request sensor reading from MUM ADC resulting from earlier request via + * MUM ATB + */ +#define MC_CMD_MUM_OP_READ_ATB_SENSOR 0xb +/* enum: Send commands relating to the QSFP ports via the MUM for PHY + * operations + */ +#define MC_CMD_MUM_OP_QSFP 0xc + +/* MC_CMD_MUM_IN_NULL msgrequest */ +#define MC_CMD_MUM_IN_NULL_LEN 4 +/* MUM cmd header */ +#define MC_CMD_MUM_IN_CMD_OFST 0 + +/* MC_CMD_MUM_IN_GET_VERSION msgrequest */ +#define MC_CMD_MUM_IN_GET_VERSION_LEN 4 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ + +/* MC_CMD_MUM_IN_READ msgrequest */ +#define MC_CMD_MUM_IN_READ_LEN 16 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* ID of (device connected to MUM) to read from registers of */ +#define MC_CMD_MUM_IN_READ_DEVICE_OFST 4 +/* enum: Hittite HMC1035 clock generator on Sorrento board */ +#define MC_CMD_MUM_DEV_HITTITE 0x1 +/* enum: Hittite HMC1035 clock generator for NIC-side on Sorrento board */ +#define MC_CMD_MUM_DEV_HITTITE_NIC 0x2 +/* 32-bit address to read from */ +#define MC_CMD_MUM_IN_READ_ADDR_OFST 8 +/* Number of words to read. */ +#define MC_CMD_MUM_IN_READ_NUMWORDS_OFST 12 + +/* MC_CMD_MUM_IN_WRITE msgrequest */ +#define MC_CMD_MUM_IN_WRITE_LENMIN 16 +#define MC_CMD_MUM_IN_WRITE_LENMAX 252 +#define MC_CMD_MUM_IN_WRITE_LEN(num) (12+4*(num)) +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* ID of (device connected to MUM) to write to registers of */ +#define MC_CMD_MUM_IN_WRITE_DEVICE_OFST 4 +/* enum: Hittite HMC1035 clock generator on Sorrento board */ +/* MC_CMD_MUM_DEV_HITTITE 0x1 */ +/* 32-bit address to write to */ +#define MC_CMD_MUM_IN_WRITE_ADDR_OFST 8 +/* Words to write */ +#define MC_CMD_MUM_IN_WRITE_BUFFER_OFST 12 +#define MC_CMD_MUM_IN_WRITE_BUFFER_LEN 4 +#define MC_CMD_MUM_IN_WRITE_BUFFER_MINNUM 1 +#define MC_CMD_MUM_IN_WRITE_BUFFER_MAXNUM 60 + +/* MC_CMD_MUM_IN_RAW_CMD msgrequest */ +#define MC_CMD_MUM_IN_RAW_CMD_LENMIN 17 +#define MC_CMD_MUM_IN_RAW_CMD_LENMAX 252 +#define MC_CMD_MUM_IN_RAW_CMD_LEN(num) (16+1*(num)) +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* MUM I2C cmd code */ +#define MC_CMD_MUM_IN_RAW_CMD_CMD_CODE_OFST 4 +/* Number of bytes to write */ +#define MC_CMD_MUM_IN_RAW_CMD_NUM_WRITE_OFST 8 +/* Number of bytes to read */ +#define MC_CMD_MUM_IN_RAW_CMD_NUM_READ_OFST 12 +/* Bytes to write */ +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_OFST 16 +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_LEN 1 +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_MINNUM 1 +#define MC_CMD_MUM_IN_RAW_CMD_WRITE_DATA_MAXNUM 236 + +/* MC_CMD_MUM_IN_LOG msgrequest */ +#define MC_CMD_MUM_IN_LOG_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_LOG_OP_OFST 4 +#define MC_CMD_MUM_IN_LOG_OP_UART 0x1 /* enum */ + +/* MC_CMD_MUM_IN_LOG_OP_UART msgrequest */ +#define MC_CMD_MUM_IN_LOG_OP_UART_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* MC_CMD_MUM_IN_LOG_OP_OFST 4 */ +/* Enable/disable debug output to UART */ +#define MC_CMD_MUM_IN_LOG_OP_UART_ENABLE_OFST 8 + +/* MC_CMD_MUM_IN_GPIO msgrequest */ +#define MC_CMD_MUM_IN_GPIO_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OPCODE_LBN 0 +#define MC_CMD_MUM_IN_GPIO_OPCODE_WIDTH 8 +#define MC_CMD_MUM_IN_GPIO_IN_READ 0x0 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE 0x1 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_READ 0x2 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE 0x3 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ 0x4 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP 0x5 /* enum */ + +/* MC_CMD_MUM_IN_GPIO_IN_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_IN_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_IN_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OUT_WRITE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_HDR_OFST 4 +/* The first 32-bit word to be written to the GPIO OUT register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_GPIOMASK1_OFST 8 +/* The second 32-bit word to be written to the GPIO OUT register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_WRITE_GPIOMASK2_OFST 12 + +/* MC_CMD_MUM_IN_GPIO_OUT_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_HDR_OFST 4 +/* The first 32-bit word to be written to the GPIO OUT ENABLE register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_GPIOMASK1_OFST 8 +/* The second 32-bit word to be written to the GPIO OUT ENABLE register. */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_WRITE_GPIOMASK2_OFST 12 + +/* MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OUT_ENABLE_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OP msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_BITWISE_OP_LBN 8 +#define MC_CMD_MUM_IN_GPIO_OP_BITWISE_OP_WIDTH 8 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_READ 0x0 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE 0x1 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG 0x2 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE 0x3 /* enum */ +#define MC_CMD_MUM_IN_GPIO_OP_GPIO_NUMBER_LBN 16 +#define MC_CMD_MUM_IN_GPIO_OP_GPIO_NUMBER_WIDTH 8 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_READ msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_READ_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_READ_HDR_OFST 4 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_WRITEBIT_LBN 24 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_WRITE_WRITEBIT_WIDTH 8 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_CFG_LBN 24 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_CONFIG_CFG_WIDTH 8 + +/* MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE msgrequest */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_LEN 8 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_HDR_OFST 4 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_ENABLEBIT_LBN 24 +#define MC_CMD_MUM_IN_GPIO_OP_OUT_ENABLE_ENABLEBIT_WIDTH 8 + +/* MC_CMD_MUM_IN_READ_SENSORS msgrequest */ +#define MC_CMD_MUM_IN_READ_SENSORS_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_READ_SENSORS_PARAMS_OFST 4 +#define MC_CMD_MUM_IN_READ_SENSORS_SENSOR_ID_LBN 0 +#define MC_CMD_MUM_IN_READ_SENSORS_SENSOR_ID_WIDTH 8 +#define MC_CMD_MUM_IN_READ_SENSORS_NUM_SENSORS_LBN 8 +#define MC_CMD_MUM_IN_READ_SENSORS_NUM_SENSORS_WIDTH 8 + +/* MC_CMD_MUM_IN_PROGRAM_CLOCKS msgrequest */ +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_LEN 12 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* Bit-mask of clocks to be programmed */ +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_MASK_OFST 4 +#define MC_CMD_MUM_CLOCK_ID_FPGA 0x0 /* enum */ +#define MC_CMD_MUM_CLOCK_ID_DDR 0x1 /* enum */ +#define MC_CMD_MUM_CLOCK_ID_NIC 0x2 /* enum */ +/* Control flags for clock programming */ +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_FLAGS_OFST 8 +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_OVERCLOCK_110_LBN 0 +#define MC_CMD_MUM_IN_PROGRAM_CLOCKS_OVERCLOCK_110_WIDTH 1 + +/* MC_CMD_MUM_IN_FPGA_LOAD msgrequest */ +#define MC_CMD_MUM_IN_FPGA_LOAD_LEN 8 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +/* Enable/Disable FPGA config from flash */ +#define MC_CMD_MUM_IN_FPGA_LOAD_ENABLE_OFST 4 + +/* MC_CMD_MUM_IN_READ_ATB_SENSOR msgrequest */ +#define MC_CMD_MUM_IN_READ_ATB_SENSOR_LEN 4 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ + +/* MC_CMD_MUM_IN_QSFP msgrequest */ +#define MC_CMD_MUM_IN_QSFP_LEN 12 +/* MUM cmd header */ +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_OPCODE_LBN 0 +#define MC_CMD_MUM_IN_QSFP_OPCODE_WIDTH 4 +#define MC_CMD_MUM_IN_QSFP_INIT 0x0 /* enum */ +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE 0x1 /* enum */ +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP 0x2 /* enum */ +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO 0x3 /* enum */ +#define MC_CMD_MUM_IN_QSFP_FILL_STATS 0x4 /* enum */ +#define MC_CMD_MUM_IN_QSFP_POLL_BIST 0x5 /* enum */ +#define MC_CMD_MUM_IN_QSFP_IDX_OFST 8 + +/* MC_CMD_MUM_IN_QSFP_INIT msgrequest */ +#define MC_CMD_MUM_IN_QSFP_INIT_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_INIT_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_INIT_IDX_OFST 8 +#define MC_CMD_MUM_IN_QSFP_INIT_CAGE_OFST 12 + +/* MC_CMD_MUM_IN_QSFP_RECONFIGURE msgrequest */ +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_LEN 24 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_IDX_OFST 8 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_TX_DISABLE_OFST 12 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_PORT_LANES_OFST 16 +#define MC_CMD_MUM_IN_QSFP_RECONFIGURE_PORT_LINK_SPEED_OFST 20 + +/* MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP msgrequest */ +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_GET_SUPPORTED_CAP_IDX_OFST 8 + +/* MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO msgrequest */ +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_LEN 16 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_IDX_OFST 8 +#define MC_CMD_MUM_IN_QSFP_GET_MEDIA_INFO_PAGE_OFST 12 + +/* MC_CMD_MUM_IN_QSFP_FILL_STATS msgrequest */ +#define MC_CMD_MUM_IN_QSFP_FILL_STATS_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_FILL_STATS_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_FILL_STATS_IDX_OFST 8 + +/* MC_CMD_MUM_IN_QSFP_POLL_BIST msgrequest */ +#define MC_CMD_MUM_IN_QSFP_POLL_BIST_LEN 12 +/* MC_CMD_MUM_IN_CMD_OFST 0 */ +#define MC_CMD_MUM_IN_QSFP_POLL_BIST_HDR_OFST 4 +#define MC_CMD_MUM_IN_QSFP_POLL_BIST_IDX_OFST 8 + +/* MC_CMD_MUM_OUT msgresponse */ +#define MC_CMD_MUM_OUT_LEN 0 + +/* MC_CMD_MUM_OUT_NULL msgresponse */ +#define MC_CMD_MUM_OUT_NULL_LEN 0 + +/* MC_CMD_MUM_OUT_GET_VERSION msgresponse */ +#define MC_CMD_MUM_OUT_GET_VERSION_LEN 12 +#define MC_CMD_MUM_OUT_GET_VERSION_FIRMWARE_OFST 0 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_OFST 4 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_LEN 8 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_LO_OFST 4 +#define MC_CMD_MUM_OUT_GET_VERSION_VERSION_HI_OFST 8 + +/* MC_CMD_MUM_OUT_RAW_CMD msgresponse */ +#define MC_CMD_MUM_OUT_RAW_CMD_LENMIN 1 +#define MC_CMD_MUM_OUT_RAW_CMD_LENMAX 252 +#define MC_CMD_MUM_OUT_RAW_CMD_LEN(num) (0+1*(num)) +/* returned data */ +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_OFST 0 +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_LEN 1 +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_MINNUM 1 +#define MC_CMD_MUM_OUT_RAW_CMD_DATA_MAXNUM 252 + +/* MC_CMD_MUM_OUT_READ msgresponse */ +#define MC_CMD_MUM_OUT_READ_LENMIN 4 +#define MC_CMD_MUM_OUT_READ_LENMAX 252 +#define MC_CMD_MUM_OUT_READ_LEN(num) (0+4*(num)) +#define MC_CMD_MUM_OUT_READ_BUFFER_OFST 0 +#define MC_CMD_MUM_OUT_READ_BUFFER_LEN 4 +#define MC_CMD_MUM_OUT_READ_BUFFER_MINNUM 1 +#define MC_CMD_MUM_OUT_READ_BUFFER_MAXNUM 63 + +/* MC_CMD_MUM_OUT_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_LOG msgresponse */ +#define MC_CMD_MUM_OUT_LOG_LEN 0 + +/* MC_CMD_MUM_OUT_LOG_OP_UART msgresponse */ +#define MC_CMD_MUM_OUT_LOG_OP_UART_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_IN_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_IN_READ_LEN 8 +/* The first 32-bit word read from the GPIO IN register. */ +#define MC_CMD_MUM_OUT_GPIO_IN_READ_GPIOMASK1_OFST 0 +/* The second 32-bit word read from the GPIO IN register. */ +#define MC_CMD_MUM_OUT_GPIO_IN_READ_GPIOMASK2_OFST 4 + +/* MC_CMD_MUM_OUT_GPIO_OUT_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OUT_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_READ_LEN 8 +/* The first 32-bit word read from the GPIO OUT register. */ +#define MC_CMD_MUM_OUT_GPIO_OUT_READ_GPIOMASK1_OFST 0 +/* The second 32-bit word read from the GPIO OUT register. */ +#define MC_CMD_MUM_OUT_GPIO_OUT_READ_GPIOMASK2_OFST 4 + +/* MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ_LEN 8 +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ_GPIOMASK1_OFST 0 +#define MC_CMD_MUM_OUT_GPIO_OUT_ENABLE_READ_GPIOMASK2_OFST 4 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_READ msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_READ_LEN 4 +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_READ_BIT_READ_OFST 0 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_WRITE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_WRITE_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_CONFIG msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_CONFIG_LEN 0 + +/* MC_CMD_MUM_OUT_GPIO_OP_OUT_ENABLE msgresponse */ +#define MC_CMD_MUM_OUT_GPIO_OP_OUT_ENABLE_LEN 0 + +/* MC_CMD_MUM_OUT_READ_SENSORS msgresponse */ +#define MC_CMD_MUM_OUT_READ_SENSORS_LENMIN 4 +#define MC_CMD_MUM_OUT_READ_SENSORS_LENMAX 252 +#define MC_CMD_MUM_OUT_READ_SENSORS_LEN(num) (0+4*(num)) +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_OFST 0 +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_LEN 4 +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_MINNUM 1 +#define MC_CMD_MUM_OUT_READ_SENSORS_DATA_MAXNUM 63 +#define MC_CMD_MUM_OUT_READ_SENSORS_READING_LBN 0 +#define MC_CMD_MUM_OUT_READ_SENSORS_READING_WIDTH 16 +#define MC_CMD_MUM_OUT_READ_SENSORS_STATE_LBN 16 +#define MC_CMD_MUM_OUT_READ_SENSORS_STATE_WIDTH 8 +#define MC_CMD_MUM_OUT_READ_SENSORS_TYPE_LBN 24 +#define MC_CMD_MUM_OUT_READ_SENSORS_TYPE_WIDTH 8 + +/* MC_CMD_MUM_OUT_PROGRAM_CLOCKS msgresponse */ +#define MC_CMD_MUM_OUT_PROGRAM_CLOCKS_LEN 4 +#define MC_CMD_MUM_OUT_PROGRAM_CLOCKS_OK_MASK_OFST 0 + +/* MC_CMD_MUM_OUT_FPGA_LOAD msgresponse */ +#define MC_CMD_MUM_OUT_FPGA_LOAD_LEN 0 + +/* MC_CMD_MUM_OUT_READ_ATB_SENSOR msgresponse */ +#define MC_CMD_MUM_OUT_READ_ATB_SENSOR_LEN 4 +#define MC_CMD_MUM_OUT_READ_ATB_SENSOR_RESULT_OFST 0 + +/* MC_CMD_MUM_OUT_QSFP_INIT msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_INIT_LEN 0 + +/* MC_CMD_MUM_OUT_QSFP_RECONFIGURE msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_LEN 8 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_LP_CAP_OFST 0 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_FLAGS_OFST 4 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_READY_LBN 0 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_READY_WIDTH 1 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_LINK_UP_LBN 1 +#define MC_CMD_MUM_OUT_QSFP_RECONFIGURE_PORT_PHY_LINK_UP_WIDTH 1 + +/* MC_CMD_MUM_OUT_QSFP_GET_SUPPORTED_CAP msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_GET_SUPPORTED_CAP_LEN 4 +#define MC_CMD_MUM_OUT_QSFP_GET_SUPPORTED_CAP_PORT_PHY_LP_CAP_OFST 0 + +/* MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_LENMIN 5 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_LENMAX 252 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_LEN(num) (4+1*(num)) +/* in bytes */ +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATALEN_OFST 0 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_OFST 4 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_LEN 1 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_MINNUM 1 +#define MC_CMD_MUM_OUT_QSFP_GET_MEDIA_INFO_DATA_MAXNUM 248 + +/* MC_CMD_MUM_OUT_QSFP_FILL_STATS msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_FILL_STATS_LEN 8 +#define MC_CMD_MUM_OUT_QSFP_FILL_STATS_PORT_PHY_STATS_PMA_PMD_LINK_UP_OFST 0 +#define MC_CMD_MUM_OUT_QSFP_FILL_STATS_PORT_PHY_STATS_PCS_LINK_UP_OFST 4 + +/* MC_CMD_MUM_OUT_QSFP_POLL_BIST msgresponse */ +#define MC_CMD_MUM_OUT_QSFP_POLL_BIST_LEN 4 +#define MC_CMD_MUM_OUT_QSFP_POLL_BIST_TEST_OFST 0 + /* MC_CMD_RESOURCE_SPECIFIER enum */ /* enum: Any */ #define MC_CMD_RESOURCE_INSTANCE_ANY 0xffffffff @@ -4203,6 +5092,30 @@ #define NVRAM_PARTITION_TYPE_PHY_MIN 0xa00 /* enum: End of range used for PHY partitions (low 8 bits are the PHY ID) */ #define NVRAM_PARTITION_TYPE_PHY_MAX 0xaff +/* enum: Primary FPGA partition */ +#define NVRAM_PARTITION_TYPE_FPGA 0xb00 +/* enum: Secondary FPGA partition */ +#define NVRAM_PARTITION_TYPE_FPGA_BACKUP 0xb01 +/* enum: FC firmware partition */ +#define NVRAM_PARTITION_TYPE_FC_FIRMWARE 0xb02 +/* enum: FC License partition */ +#define NVRAM_PARTITION_TYPE_FC_LICENSE 0xb03 +/* enum: Non-volatile log output partition for FC */ +#define NVRAM_PARTITION_TYPE_FC_LOG 0xb04 +/* enum: MUM firmware partition */ +#define NVRAM_PARTITION_TYPE_MUM_FIRMWARE 0xc00 +/* enum: MUM Non-volatile log output partition. */ +#define NVRAM_PARTITION_TYPE_MUM_LOG 0xc01 +/* enum: MUM Application table partition. */ +#define NVRAM_PARTITION_TYPE_MUM_APPTABLE 0xc02 +/* enum: MUM boot rom partition. */ +#define NVRAM_PARTITION_TYPE_MUM_BOOT_ROM 0xc03 +/* enum: MUM production signatures & calibration rom partition. */ +#define NVRAM_PARTITION_TYPE_MUM_PROD_ROM 0xc04 +/* enum: MUM user signatures & calibration rom partition. */ +#define NVRAM_PARTITION_TYPE_MUM_USER_ROM 0xc05 +/* enum: MUM fuses and lockbits partition. */ +#define NVRAM_PARTITION_TYPE_MUM_FUSELOCK 0xc06 /* enum: Start of reserved value range (firmware may use for any purpose) */ #define NVRAM_PARTITION_TYPE_RESERVED_VALUES_MIN 0xff00 /* enum: End of reserved value range (firmware may use for any purpose) */ @@ -4218,66 +5131,69 @@ #define LICENSED_APP_ID_LEN 4 #define LICENSED_APP_ID_ID_OFST 0 /* enum: OpenOnload */ -#define LICENSED_APP_ID_ONLOAD 0x1 +#define LICENSED_APP_ID_ONLOAD 0x1 /* enum: PTP timestamping */ -#define LICENSED_APP_ID_PTP 0x2 +#define LICENSED_APP_ID_PTP 0x2 /* enum: SolarCapture Pro */ -#define LICENSED_APP_ID_SOLARCAPTURE_PRO 0x4 +#define LICENSED_APP_ID_SOLARCAPTURE_PRO 0x4 +/* enum: SolarSecure filter engine */ +#define LICENSED_APP_ID_SOLARSECURE 0x8 +/* enum: Performance monitor */ +#define LICENSED_APP_ID_PERF_MONITOR 0x10 +/* enum: SolarCapture Live */ +#define LICENSED_APP_ID_SOLARCAPTURE_LIVE 0x20 +/* enum: Capture SolarSystem */ +#define LICENSED_APP_ID_CAPTURE_SOLARSYSTEM 0x40 +/* enum: Network Access Control */ +#define LICENSED_APP_ID_NETWORK_ACCESS_CONTROL 0x80 #define LICENSED_APP_ID_ID_LBN 0 #define LICENSED_APP_ID_ID_WIDTH 32 - -/***********************************/ -/* MC_CMD_GET_WORKAROUNDS - * Read the list of all implemented and all currently enabled workarounds. The - * enums here must correspond with those in MC_CMD_WORKAROUND. - */ -#define MC_CMD_GET_WORKAROUNDS 0x59 - -/* MC_CMD_GET_WORKAROUNDS_OUT msgresponse */ -#define MC_CMD_GET_WORKAROUNDS_OUT_LEN 8 -/* Each workaround is represented by a single bit according to the enums below. - */ -#define MC_CMD_GET_WORKAROUNDS_OUT_IMPLEMENTED_OFST 0 -#define MC_CMD_GET_WORKAROUNDS_OUT_ENABLED_OFST 4 -/* enum: Bug 17230 work around. */ -#define MC_CMD_GET_WORKAROUNDS_OUT_BUG17230 0x2 -/* enum: Bug 35388 work around (unsafe EVQ writes). */ -#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35388 0x4 -/* enum: Bug35017 workaround (A64 tables must be identity map) */ -#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35017 0x8 - - -/***********************************/ -/* MC_CMD_LINK_STATE_MODE - * Read/set link state mode of a VF - */ -#define MC_CMD_LINK_STATE_MODE 0x5c - -#define MC_CMD_0x5c_PRIVILEGE_CTG SRIOV_CTG_GENERAL - -/* MC_CMD_LINK_STATE_MODE_IN msgrequest */ -#define MC_CMD_LINK_STATE_MODE_IN_LEN 8 -/* The target function to have its link state mode read or set, must be a VF - * e.g. VF 1,3 = 0x00030001 - */ -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_OFST 0 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_LBN 0 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_WIDTH 16 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_LBN 16 -#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_WIDTH 16 -/* New link state mode to be set */ -#define MC_CMD_LINK_STATE_MODE_IN_NEW_MODE_OFST 4 -#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO 0x0 /* enum */ -#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP 0x1 /* enum */ -#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN 0x2 /* enum */ -/* enum: Use this value to just read the existing setting without modifying it. - */ -#define MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE 0xffffffff - -/* MC_CMD_LINK_STATE_MODE_OUT msgresponse */ -#define MC_CMD_LINK_STATE_MODE_OUT_LEN 4 -#define MC_CMD_LINK_STATE_MODE_OUT_OLD_MODE_OFST 0 +/* TX_TIMESTAMP_EVENT structuredef */ +#define TX_TIMESTAMP_EVENT_LEN 6 +/* lower 16 bits of timestamp data */ +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_OFST 0 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_LEN 2 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_LBN 0 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_LO_WIDTH 16 +/* Type of TX event, ordinary TX completion, low or high part of TX timestamp + */ +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_OFST 3 +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_LEN 1 +/* enum: This is a TX completion event, not a timestamp */ +#define TX_TIMESTAMP_EVENT_TX_EV_COMPLETION 0x0 +/* enum: This is the low part of a TX timestamp event */ +#define TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_LO 0x51 +/* enum: This is the high part of a TX timestamp event */ +#define TX_TIMESTAMP_EVENT_TX_EV_TSTAMP_HI 0x52 +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_LBN 24 +#define TX_TIMESTAMP_EVENT_TX_EV_TYPE_WIDTH 8 +/* upper 16 bits of timestamp data */ +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_OFST 4 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_LEN 2 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_LBN 32 +#define TX_TIMESTAMP_EVENT_TSTAMP_DATA_HI_WIDTH 16 + +/* RSS_MODE structuredef */ +#define RSS_MODE_LEN 1 +/* The RSS mode for a particular packet type is a value from 0 - 15 which can + * be considered as 4 bits selecting which fields are included in the hash. (A + * value 0 effectively disables RSS spreading for the packet type.) The YAML + * generation tools require this structure to be a whole number of bytes wide, + * but only 4 bits are relevant. + */ +#define RSS_MODE_HASH_SELECTOR_OFST 0 +#define RSS_MODE_HASH_SELECTOR_LEN 1 +#define RSS_MODE_HASH_SRC_ADDR_LBN 0 +#define RSS_MODE_HASH_SRC_ADDR_WIDTH 1 +#define RSS_MODE_HASH_DST_ADDR_LBN 1 +#define RSS_MODE_HASH_DST_ADDR_WIDTH 1 +#define RSS_MODE_HASH_SRC_PORT_LBN 2 +#define RSS_MODE_HASH_SRC_PORT_WIDTH 1 +#define RSS_MODE_HASH_DST_PORT_LBN 3 +#define RSS_MODE_HASH_DST_PORT_WIDTH 1 +#define RSS_MODE_HASH_SELECTOR_LBN 0 +#define RSS_MODE_HASH_SELECTOR_WIDTH 8 /***********************************/ @@ -4413,7 +5329,9 @@ #define MC_CMD_0x81_PRIVILEGE_CTG SRIOV_CTG_GENERAL -/* MC_CMD_INIT_RXQ_IN msgrequest */ +/* MC_CMD_INIT_RXQ_IN msgrequest: Legacy RXQ_INIT request. Use extended version + * in new code. + */ #define MC_CMD_INIT_RXQ_IN_LENMIN 36 #define MC_CMD_INIT_RXQ_IN_LENMAX 252 #define MC_CMD_INIT_RXQ_IN_LEN(num) (28+8*(num)) @@ -4456,9 +5374,73 @@ #define MC_CMD_INIT_RXQ_IN_DMA_ADDR_MINNUM 1 #define MC_CMD_INIT_RXQ_IN_DMA_ADDR_MAXNUM 28 +/* MC_CMD_INIT_RXQ_EXT_IN msgrequest: Extended RXQ_INIT with additional mode + * flags + */ +#define MC_CMD_INIT_RXQ_EXT_IN_LEN 544 +/* Size, in entries */ +#define MC_CMD_INIT_RXQ_EXT_IN_SIZE_OFST 0 +/* The EVQ to send events to. This is an index originally specified to INIT_EVQ + */ +#define MC_CMD_INIT_RXQ_EXT_IN_TARGET_EVQ_OFST 4 +/* The value to put in the event data. Check hardware spec. for valid range. */ +#define MC_CMD_INIT_RXQ_EXT_IN_LABEL_OFST 8 +/* Desired instance. Must be set to a specific instance, which is a function + * local queue index. + */ +#define MC_CMD_INIT_RXQ_EXT_IN_INSTANCE_OFST 12 +/* There will be more flags here. */ +#define MC_CMD_INIT_RXQ_EXT_IN_FLAGS_OFST 16 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_BUFF_MODE_LBN 0 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_BUFF_MODE_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT_LBN 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_HDR_SPLIT_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_TIMESTAMP_LBN 2 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_TIMESTAMP_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_CRC_MODE_LBN 3 +#define MC_CMD_INIT_RXQ_EXT_IN_CRC_MODE_WIDTH 4 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_CHAIN_LBN 7 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_CHAIN_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_PREFIX_LBN 8 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_PREFIX_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER_LBN 9 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_DISABLE_SCATTER_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_MODE_LBN 10 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_MODE_WIDTH 4 +/* enum: One packet per descriptor (for normal networking) */ +#define MC_CMD_INIT_RXQ_EXT_IN_SINGLE_PACKET 0x0 +/* enum: Pack multiple packets into large descriptors (for SolarCapture) */ +#define MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM 0x1 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_SNAPSHOT_MODE_LBN 14 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_SNAPSHOT_MODE_WIDTH 1 +#define MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE_LBN 15 +#define MC_CMD_INIT_RXQ_EXT_IN_PACKED_STREAM_BUFF_SIZE_WIDTH 3 +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_1M 0x0 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_512K 0x1 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_256K 0x2 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_128K 0x3 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_PS_BUFF_64K 0x4 /* enum */ +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES_LBN 18 +#define MC_CMD_INIT_RXQ_EXT_IN_FLAG_WANT_OUTER_CLASSES_WIDTH 1 +/* Owner ID to use if in buffer mode (zero if physical) */ +#define MC_CMD_INIT_RXQ_EXT_IN_OWNER_ID_OFST 20 +/* The port ID associated with the v-adaptor which should contain this DMAQ. */ +#define MC_CMD_INIT_RXQ_EXT_IN_PORT_ID_OFST 24 +/* 64-bit address of 4k of 4k-aligned host memory buffer */ +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_OFST 28 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_LEN 8 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_LO_OFST 28 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_HI_OFST 32 +#define MC_CMD_INIT_RXQ_EXT_IN_DMA_ADDR_NUM 64 +/* Maximum length of packet to receive, if SNAPSHOT_MODE flag is set */ +#define MC_CMD_INIT_RXQ_EXT_IN_SNAPSHOT_LENGTH_OFST 540 + /* MC_CMD_INIT_RXQ_OUT msgresponse */ #define MC_CMD_INIT_RXQ_OUT_LEN 0 +/* MC_CMD_INIT_RXQ_EXT_OUT msgresponse */ +#define MC_CMD_INIT_RXQ_EXT_OUT_LEN 0 + /***********************************/ /* MC_CMD_INIT_TXQ @@ -4467,7 +5449,9 @@ #define MC_CMD_0x82_PRIVILEGE_CTG SRIOV_CTG_GENERAL -/* MC_CMD_INIT_TXQ_IN msgrequest */ +/* MC_CMD_INIT_TXQ_IN msgrequest: Legacy INIT_TXQ request. Use extended version + * in new code. + */ #define MC_CMD_INIT_TXQ_IN_LENMIN 36 #define MC_CMD_INIT_TXQ_IN_LENMAX 252 #define MC_CMD_INIT_TXQ_IN_LEN(num) (28+8*(num)) @@ -4499,6 +5483,10 @@ #define MC_CMD_INIT_TXQ_IN_FLAG_TIMESTAMP_WIDTH 1 #define MC_CMD_INIT_TXQ_IN_FLAG_PACER_BYPASS_LBN 9 #define MC_CMD_INIT_TXQ_IN_FLAG_PACER_BYPASS_WIDTH 1 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_IP_CSUM_EN_LBN 10 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_IP_CSUM_EN_WIDTH 1 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_TCP_CSUM_EN_LBN 11 +#define MC_CMD_INIT_TXQ_IN_FLAG_INNER_TCP_CSUM_EN_WIDTH 1 /* Owner ID to use if in buffer mode (zero if physical) */ #define MC_CMD_INIT_TXQ_IN_OWNER_ID_OFST 20 /* The port ID associated with the v-adaptor which should contain this DMAQ. */ @@ -4511,6 +5499,60 @@ #define MC_CMD_INIT_TXQ_IN_DMA_ADDR_MINNUM 1 #define MC_CMD_INIT_TXQ_IN_DMA_ADDR_MAXNUM 28 +/* MC_CMD_INIT_TXQ_EXT_IN msgrequest: Extended INIT_TXQ with additional mode + * flags + */ +#define MC_CMD_INIT_TXQ_EXT_IN_LEN 544 +/* Size, in entries */ +#define MC_CMD_INIT_TXQ_EXT_IN_SIZE_OFST 0 +/* The EVQ to send events to. This is an index originally specified to + * INIT_EVQ. + */ +#define MC_CMD_INIT_TXQ_EXT_IN_TARGET_EVQ_OFST 4 +/* The value to put in the event data. Check hardware spec. for valid range. */ +#define MC_CMD_INIT_TXQ_EXT_IN_LABEL_OFST 8 +/* Desired instance. Must be set to a specific instance, which is a function + * local queue index. + */ +#define MC_CMD_INIT_TXQ_EXT_IN_INSTANCE_OFST 12 +/* There will be more flags here. */ +#define MC_CMD_INIT_TXQ_EXT_IN_FLAGS_OFST 16 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_BUFF_MODE_LBN 0 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_BUFF_MODE_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_IP_CSUM_DIS_LBN 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_IP_CSUM_DIS_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_CSUM_DIS_LBN 2 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_CSUM_DIS_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_UDP_ONLY_LBN 3 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TCP_UDP_ONLY_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_CRC_MODE_LBN 4 +#define MC_CMD_INIT_TXQ_EXT_IN_CRC_MODE_WIDTH 4 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TIMESTAMP_LBN 8 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_TIMESTAMP_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_PACER_BYPASS_LBN 9 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_PACER_BYPASS_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN_LBN 10 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_IP_CSUM_EN_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN_LBN 11 +#define MC_CMD_INIT_TXQ_EXT_IN_FLAG_INNER_TCP_CSUM_EN_WIDTH 1 +/* Owner ID to use if in buffer mode (zero if physical) */ +#define MC_CMD_INIT_TXQ_EXT_IN_OWNER_ID_OFST 20 +/* The port ID associated with the v-adaptor which should contain this DMAQ. */ +#define MC_CMD_INIT_TXQ_EXT_IN_PORT_ID_OFST 24 +/* 64-bit address of 4k of 4k-aligned host memory buffer */ +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_OFST 28 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_LEN 8 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_LO_OFST 28 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_HI_OFST 32 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_MINNUM 1 +#define MC_CMD_INIT_TXQ_EXT_IN_DMA_ADDR_MAXNUM 64 +/* Flags related to Qbb flow control mode. */ +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_FLAGS_OFST 540 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_ENABLE_LBN 0 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_ENABLE_WIDTH 1 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_PRIORITY_LBN 1 +#define MC_CMD_INIT_TXQ_EXT_IN_QBB_PRIORITY_WIDTH 3 + /* MC_CMD_INIT_TXQ_OUT msgresponse */ #define MC_CMD_INIT_TXQ_OUT_LEN 0 @@ -4617,6 +5659,132 @@ /* MC_CMD_PROXY_CMD_OUT msgresponse */ #define MC_CMD_PROXY_CMD_OUT_LEN 0 +/* MC_PROXY_STATUS_BUFFER structuredef: Host memory status buffer used to + * manage proxied requests + */ +#define MC_PROXY_STATUS_BUFFER_LEN 16 +/* Handle allocated by the firmware for this proxy transaction */ +#define MC_PROXY_STATUS_BUFFER_HANDLE_OFST 0 +/* enum: An invalid handle. */ +#define MC_PROXY_STATUS_BUFFER_HANDLE_INVALID 0x0 +#define MC_PROXY_STATUS_BUFFER_HANDLE_LBN 0 +#define MC_PROXY_STATUS_BUFFER_HANDLE_WIDTH 32 +/* The requesting physical function number */ +#define MC_PROXY_STATUS_BUFFER_PF_OFST 4 +#define MC_PROXY_STATUS_BUFFER_PF_LEN 2 +#define MC_PROXY_STATUS_BUFFER_PF_LBN 32 +#define MC_PROXY_STATUS_BUFFER_PF_WIDTH 16 +/* The requesting virtual function number. Set to VF_NULL if the target is a + * PF. + */ +#define MC_PROXY_STATUS_BUFFER_VF_OFST 6 +#define MC_PROXY_STATUS_BUFFER_VF_LEN 2 +#define MC_PROXY_STATUS_BUFFER_VF_LBN 48 +#define MC_PROXY_STATUS_BUFFER_VF_WIDTH 16 +/* The target function RID. */ +#define MC_PROXY_STATUS_BUFFER_RID_OFST 8 +#define MC_PROXY_STATUS_BUFFER_RID_LEN 2 +#define MC_PROXY_STATUS_BUFFER_RID_LBN 64 +#define MC_PROXY_STATUS_BUFFER_RID_WIDTH 16 +/* The status of the proxy as described in MC_CMD_PROXY_COMPLETE. */ +#define MC_PROXY_STATUS_BUFFER_STATUS_OFST 10 +#define MC_PROXY_STATUS_BUFFER_STATUS_LEN 2 +#define MC_PROXY_STATUS_BUFFER_STATUS_LBN 80 +#define MC_PROXY_STATUS_BUFFER_STATUS_WIDTH 16 +/* If a request is authorized rather than carried out by the host, this is the + * elevated privilege mask granted to the requesting function. + */ +#define MC_PROXY_STATUS_BUFFER_GRANTED_PRIVILEGES_OFST 12 +#define MC_PROXY_STATUS_BUFFER_GRANTED_PRIVILEGES_LBN 96 +#define MC_PROXY_STATUS_BUFFER_GRANTED_PRIVILEGES_WIDTH 32 + + +/***********************************/ +/* MC_CMD_PROXY_CONFIGURE + * Enable/disable authorization of MCDI requests from unprivileged functions by + * a designated admin function + */ +#define MC_CMD_PROXY_CONFIGURE 0x58 + +#define MC_CMD_0x58_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_PROXY_CONFIGURE_IN msgrequest */ +#define MC_CMD_PROXY_CONFIGURE_IN_LEN 108 +#define MC_CMD_PROXY_CONFIGURE_IN_FLAGS_OFST 0 +#define MC_CMD_PROXY_CONFIGURE_IN_ENABLE_LBN 0 +#define MC_CMD_PROXY_CONFIGURE_IN_ENABLE_WIDTH 1 +/* Host provides a contiguous memory buffer that contains at least NUM_BLOCKS + * of blocks, each of the size REQUEST_BLOCK_SIZE. + */ +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_OFST 4 +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_LEN 8 +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_LO_OFST 4 +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BUFF_ADDR_HI_OFST 8 +/* Must be a power of 2 */ +#define MC_CMD_PROXY_CONFIGURE_IN_STATUS_BLOCK_SIZE_OFST 12 +/* Host provides a contiguous memory buffer that contains at least NUM_BLOCKS + * of blocks, each of the size REPLY_BLOCK_SIZE. + */ +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_OFST 16 +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_LEN 8 +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_LO_OFST 16 +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BUFF_ADDR_HI_OFST 20 +/* Must be a power of 2 */ +#define MC_CMD_PROXY_CONFIGURE_IN_REQUEST_BLOCK_SIZE_OFST 24 +/* Host provides a contiguous memory buffer that contains at least NUM_BLOCKS + * of blocks, each of the size STATUS_BLOCK_SIZE. This buffer is only needed if + * host intends to complete proxied operations by using MC_CMD_PROXY_CMD. + */ +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_OFST 28 +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_LEN 8 +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_LO_OFST 28 +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BUFF_ADDR_HI_OFST 32 +/* Must be a power of 2, or zero if this buffer is not provided */ +#define MC_CMD_PROXY_CONFIGURE_IN_REPLY_BLOCK_SIZE_OFST 36 +/* Applies to all three buffers */ +#define MC_CMD_PROXY_CONFIGURE_IN_NUM_BLOCKS_OFST 40 +/* A bit mask defining which MCDI operations may be proxied */ +#define MC_CMD_PROXY_CONFIGURE_IN_ALLOWED_MCDI_MASK_OFST 44 +#define MC_CMD_PROXY_CONFIGURE_IN_ALLOWED_MCDI_MASK_LEN 64 + +/* MC_CMD_PROXY_CONFIGURE_OUT msgresponse */ +#define MC_CMD_PROXY_CONFIGURE_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_PROXY_COMPLETE + * Tells FW that a requested proxy operation has either been completed (by + * using MC_CMD_PROXY_CMD) or authorized/declined. May only be sent by the + * function that enabled proxying/authorization (by using + * MC_CMD_PROXY_CONFIGURE). + */ +#define MC_CMD_PROXY_COMPLETE 0x5f + +#define MC_CMD_0x5f_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_PROXY_COMPLETE_IN msgrequest */ +#define MC_CMD_PROXY_COMPLETE_IN_LEN 12 +#define MC_CMD_PROXY_COMPLETE_IN_BLOCK_INDEX_OFST 0 +#define MC_CMD_PROXY_COMPLETE_IN_STATUS_OFST 4 +/* enum: The operation has been completed by using MC_CMD_PROXY_CMD, the reply + * is stored in the REPLY_BUFF. + */ +#define MC_CMD_PROXY_COMPLETE_IN_COMPLETE 0x0 +/* enum: The operation has been authorized. The originating function may now + * try again. + */ +#define MC_CMD_PROXY_COMPLETE_IN_AUTHORIZED 0x1 +/* enum: The operation has been declined. */ +#define MC_CMD_PROXY_COMPLETE_IN_DECLINED 0x2 +/* enum: The authorization failed because the relevant application did not + * respond in time. + */ +#define MC_CMD_PROXY_COMPLETE_IN_TIMEDOUT 0x3 +#define MC_CMD_PROXY_COMPLETE_IN_HANDLE_OFST 8 + +/* MC_CMD_PROXY_COMPLETE_OUT msgresponse */ +#define MC_CMD_PROXY_COMPLETE_OUT_LEN 0 + /***********************************/ /* MC_CMD_ALLOC_BUFTBL_CHUNK @@ -4688,6 +5856,44 @@ /* MC_CMD_FREE_BUFTBL_CHUNK_OUT msgresponse */ #define MC_CMD_FREE_BUFTBL_CHUNK_OUT_LEN 0 +/* PORT_CONFIG_ENTRY structuredef */ +#define PORT_CONFIG_ENTRY_LEN 16 +/* External port number (label) */ +#define PORT_CONFIG_ENTRY_EXT_NUMBER_OFST 0 +#define PORT_CONFIG_ENTRY_EXT_NUMBER_LEN 1 +#define PORT_CONFIG_ENTRY_EXT_NUMBER_LBN 0 +#define PORT_CONFIG_ENTRY_EXT_NUMBER_WIDTH 8 +/* Port core location */ +#define PORT_CONFIG_ENTRY_CORE_OFST 1 +#define PORT_CONFIG_ENTRY_CORE_LEN 1 +#define PORT_CONFIG_ENTRY_STANDALONE 0x0 /* enum */ +#define PORT_CONFIG_ENTRY_MASTER 0x1 /* enum */ +#define PORT_CONFIG_ENTRY_SLAVE 0x2 /* enum */ +#define PORT_CONFIG_ENTRY_CORE_LBN 8 +#define PORT_CONFIG_ENTRY_CORE_WIDTH 8 +/* Internal number (HW resource) relative to the core */ +#define PORT_CONFIG_ENTRY_INT_NUMBER_OFST 2 +#define PORT_CONFIG_ENTRY_INT_NUMBER_LEN 1 +#define PORT_CONFIG_ENTRY_INT_NUMBER_LBN 16 +#define PORT_CONFIG_ENTRY_INT_NUMBER_WIDTH 8 +/* Reserved */ +#define PORT_CONFIG_ENTRY_RSVD_OFST 3 +#define PORT_CONFIG_ENTRY_RSVD_LEN 1 +#define PORT_CONFIG_ENTRY_RSVD_LBN 24 +#define PORT_CONFIG_ENTRY_RSVD_WIDTH 8 +/* Bitmask of KR lanes used by the port */ +#define PORT_CONFIG_ENTRY_LANES_OFST 4 +#define PORT_CONFIG_ENTRY_LANES_LBN 32 +#define PORT_CONFIG_ENTRY_LANES_WIDTH 32 +/* Port capabilities (MC_CMD_PHY_CAP_*) */ +#define PORT_CONFIG_ENTRY_SUPPORTED_CAPS_OFST 8 +#define PORT_CONFIG_ENTRY_SUPPORTED_CAPS_LBN 64 +#define PORT_CONFIG_ENTRY_SUPPORTED_CAPS_WIDTH 32 +/* Reserved (align to 16 bytes) */ +#define PORT_CONFIG_ENTRY_RSVD2_OFST 12 +#define PORT_CONFIG_ENTRY_RSVD2_LBN 96 +#define PORT_CONFIG_ENTRY_RSVD2_WIDTH 32 + /***********************************/ /* MC_CMD_FILTER_OP @@ -4759,9 +5965,9 @@ #define MC_CMD_FILTER_OP_IN_RX_DEST_HOST 0x1 /* enum: receive to MC */ #define MC_CMD_FILTER_OP_IN_RX_DEST_MC 0x2 -/* enum: loop back to port 0 TX MAC */ +/* enum: loop back to TXDP 0 */ #define MC_CMD_FILTER_OP_IN_RX_DEST_TX0 0x3 -/* enum: loop back to port 1 TX MAC */ +/* enum: loop back to TXDP 1 */ #define MC_CMD_FILTER_OP_IN_RX_DEST_TX1 0x4 /* receive queue handle (for multiple queue modes, this is the base queue) */ #define MC_CMD_FILTER_OP_IN_RX_QUEUE_OFST 24 @@ -4778,9 +5984,7 @@ #define MC_CMD_FILTER_OP_IN_RX_MODE_TEST_NEVER_MATCH 0x80000000 /* RSS context (for RX_MODE_RSS) or .1p mapping handle (for * RX_MODE_DOT1P_MAPPING), as returned by MC_CMD_RSS_CONTEXT_ALLOC or - * MC_CMD_DOT1P_MAPPING_ALLOC. Note that these handles should be considered - * opaque to the host, although a value of 0xFFFFFFFF is guaranteed never to be - * a valid handle. + * MC_CMD_DOT1P_MAPPING_ALLOC. */ #define MC_CMD_FILTER_OP_IN_RX_CONTEXT_OFST 32 /* transmit domain (reserved; set to 0) */ @@ -4835,6 +6039,235 @@ #define MC_CMD_FILTER_OP_IN_DST_IP_OFST 92 #define MC_CMD_FILTER_OP_IN_DST_IP_LEN 16 +/* MC_CMD_FILTER_OP_EXT_IN msgrequest: Extension to MC_CMD_FILTER_OP_IN to + * include handling of VXLAN/NVGRE encapsulated frame filtering (which is + * supported on Medford only). + */ +#define MC_CMD_FILTER_OP_EXT_IN_LEN 172 +/* identifies the type of operation requested */ +#define MC_CMD_FILTER_OP_EXT_IN_OP_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_FILTER_OP_IN/OP */ +/* filter handle (for remove / unsubscribe operations) */ +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_OFST 4 +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_LEN 8 +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_LO_OFST 4 +#define MC_CMD_FILTER_OP_EXT_IN_HANDLE_HI_OFST 8 +/* The port ID associated with the v-adaptor which should contain this filter. + */ +#define MC_CMD_FILTER_OP_EXT_IN_PORT_ID_OFST 12 +/* fields to include in match criteria */ +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_FIELDS_OFST 16 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP_LBN 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC_LBN 2 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT_LBN 3 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC_LBN 4 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT_LBN 5 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE_LBN 6 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN_LBN 7 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN_LBN 8 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO_LBN 9 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_FWDEF0_LBN 10 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_FWDEF0_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID_LBN 11 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_IP_LBN 12 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_IP_LBN 13 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_IP_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_MAC_LBN 14 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_PORT_LBN 15 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_SRC_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC_LBN 16 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_PORT_LBN 17 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_PORT_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_ETHER_TYPE_LBN 18 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_ETHER_TYPE_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_INNER_VLAN_LBN 19 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_INNER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_OUTER_VLAN_LBN 20 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_OUTER_VLAN_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_IP_PROTO_LBN 21 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_IP_PROTO_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF0_LBN 22 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF0_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF1_LBN 23 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_FWDEF1_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST_LBN 24 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST_LBN 25 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST_LBN 30 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST_LBN 31 +#define MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST_WIDTH 1 +/* receive destination */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_OFST 20 +/* enum: drop packets */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_DROP 0x0 +/* enum: receive to host */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST 0x1 +/* enum: receive to MC */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_MC 0x2 +/* enum: loop back to TXDP 0 */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_TX0 0x3 +/* enum: loop back to TXDP 1 */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_DEST_TX1 0x4 +/* receive queue handle (for multiple queue modes, this is the base queue) */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_QUEUE_OFST 24 +/* receive mode */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_OFST 28 +/* enum: receive to just the specified queue */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE 0x0 +/* enum: receive to multiple queues using RSS context */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS 0x1 +/* enum: receive to multiple queues using .1p mapping */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_DOT1P_MAPPING 0x2 +/* enum: install a filter entry that will never match; for test purposes only + */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_MODE_TEST_NEVER_MATCH 0x80000000 +/* RSS context (for RX_MODE_RSS) or .1p mapping handle (for + * RX_MODE_DOT1P_MAPPING), as returned by MC_CMD_RSS_CONTEXT_ALLOC or + * MC_CMD_DOT1P_MAPPING_ALLOC. + */ +#define MC_CMD_FILTER_OP_EXT_IN_RX_CONTEXT_OFST 32 +/* transmit domain (reserved; set to 0) */ +#define MC_CMD_FILTER_OP_EXT_IN_TX_DOMAIN_OFST 36 +/* transmit destination (either set the MAC and/or PM bits for explicit + * control, or set this field to TX_DEST_DEFAULT for sensible default + * behaviour) + */ +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_OFST 40 +/* enum: request default behaviour (based on filter type) */ +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT 0xffffffff +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_MAC_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_MAC_WIDTH 1 +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_PM_LBN 1 +#define MC_CMD_FILTER_OP_EXT_IN_TX_DEST_PM_WIDTH 1 +/* source MAC address to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_SRC_MAC_OFST 44 +#define MC_CMD_FILTER_OP_EXT_IN_SRC_MAC_LEN 6 +/* source port to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_SRC_PORT_OFST 50 +#define MC_CMD_FILTER_OP_EXT_IN_SRC_PORT_LEN 2 +/* destination MAC address to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_DST_MAC_OFST 52 +#define MC_CMD_FILTER_OP_EXT_IN_DST_MAC_LEN 6 +/* destination port to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_DST_PORT_OFST 58 +#define MC_CMD_FILTER_OP_EXT_IN_DST_PORT_LEN 2 +/* Ethernet type to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_ETHER_TYPE_OFST 60 +#define MC_CMD_FILTER_OP_EXT_IN_ETHER_TYPE_LEN 2 +/* Inner VLAN tag to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_INNER_VLAN_OFST 62 +#define MC_CMD_FILTER_OP_EXT_IN_INNER_VLAN_LEN 2 +/* Outer VLAN tag to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_OUTER_VLAN_OFST 64 +#define MC_CMD_FILTER_OP_EXT_IN_OUTER_VLAN_LEN 2 +/* IP protocol to match (in low byte; set high byte to 0) */ +#define MC_CMD_FILTER_OP_EXT_IN_IP_PROTO_OFST 66 +#define MC_CMD_FILTER_OP_EXT_IN_IP_PROTO_LEN 2 +/* Firmware defined register 0 to match (reserved; set to 0) */ +#define MC_CMD_FILTER_OP_EXT_IN_FWDEF0_OFST 68 +/* VNI (for VXLAN/Geneve, when IP protocol is UDP) or VSID (for NVGRE, when IP + * protocol is GRE) to match (as bytes in network order; set last byte to 0 for + * VXLAN/NVGRE, or 1 for Geneve) + */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_OR_VSID_OFST 72 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_VALUE_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_VALUE_WIDTH 24 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_LBN 24 +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_WIDTH 8 +/* enum: Match VXLAN traffic with this VNI */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN 0x0 +/* enum: Match Geneve traffic with this VNI */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE 0x1 +/* enum: Reserved for experimental development use */ +#define MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_EXPERIMENTAL 0xfe +#define MC_CMD_FILTER_OP_EXT_IN_VSID_VALUE_LBN 0 +#define MC_CMD_FILTER_OP_EXT_IN_VSID_VALUE_WIDTH 24 +#define MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_LBN 24 +#define MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_WIDTH 8 +/* enum: Match NVGRE traffic with this VSID */ +#define MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE 0x0 +/* source IP address to match (as bytes in network order; set last 12 bytes to + * 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_SRC_IP_OFST 76 +#define MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN 16 +/* destination IP address to match (as bytes in network order; set last 12 + * bytes to 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_DST_IP_OFST 92 +#define MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN 16 +/* VXLAN/NVGRE inner frame source MAC address to match (as bytes in network + * order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_MAC_OFST 108 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_MAC_LEN 6 +/* VXLAN/NVGRE inner frame source port to match (as bytes in network order) */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_PORT_OFST 114 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_PORT_LEN 2 +/* VXLAN/NVGRE inner frame destination MAC address to match (as bytes in + * network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_MAC_OFST 116 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_MAC_LEN 6 +/* VXLAN/NVGRE inner frame destination port to match (as bytes in network + * order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_PORT_OFST 122 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_PORT_LEN 2 +/* VXLAN/NVGRE inner frame Ethernet type to match (as bytes in network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_ETHER_TYPE_OFST 124 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_ETHER_TYPE_LEN 2 +/* VXLAN/NVGRE inner frame Inner VLAN tag to match (as bytes in network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_INNER_VLAN_OFST 126 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_INNER_VLAN_LEN 2 +/* VXLAN/NVGRE inner frame Outer VLAN tag to match (as bytes in network order) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_OUTER_VLAN_OFST 128 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_OUTER_VLAN_LEN 2 +/* VXLAN/NVGRE inner frame IP protocol to match (in low byte; set high byte to + * 0) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_IP_PROTO_OFST 130 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_IP_PROTO_LEN 2 +/* VXLAN/NVGRE inner frame Firmware defined register 0 to match (reserved; set + * to 0) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_FWDEF0_OFST 132 +/* VXLAN/NVGRE inner frame Firmware defined register 1 to match (reserved; set + * to 0) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_FWDEF1_OFST 136 +/* VXLAN/NVGRE inner frame source IP address to match (as bytes in network + * order; set last 12 bytes to 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_IP_OFST 140 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_SRC_IP_LEN 16 +/* VXLAN/NVGRE inner frame destination IP address to match (as bytes in network + * order; set last 12 bytes to 0 for IPv4 address) + */ +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_IP_OFST 156 +#define MC_CMD_FILTER_OP_EXT_IN_IFRM_DST_IP_LEN 16 + /* MC_CMD_FILTER_OP_OUT msgresponse */ #define MC_CMD_FILTER_OP_OUT_LEN 12 /* identifies the type of operation requested */ @@ -4849,6 +6282,27 @@ #define MC_CMD_FILTER_OP_OUT_HANDLE_LEN 8 #define MC_CMD_FILTER_OP_OUT_HANDLE_LO_OFST 4 #define MC_CMD_FILTER_OP_OUT_HANDLE_HI_OFST 8 +/* enum: guaranteed invalid filter handle (low 32 bits) */ +#define MC_CMD_FILTER_OP_OUT_HANDLE_LO_INVALID 0xffffffff +/* enum: guaranteed invalid filter handle (high 32 bits) */ +#define MC_CMD_FILTER_OP_OUT_HANDLE_HI_INVALID 0xffffffff + +/* MC_CMD_FILTER_OP_EXT_OUT msgresponse */ +#define MC_CMD_FILTER_OP_EXT_OUT_LEN 12 +/* identifies the type of operation requested */ +#define MC_CMD_FILTER_OP_EXT_OUT_OP_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_FILTER_OP_EXT_IN/OP */ +/* Returned filter handle (for insert / subscribe operations). Note that these + * handles should be considered opaque to the host, although a value of + * 0xFFFFFFFF_FFFFFFFF is guaranteed never to be a valid handle. + */ +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_OFST 4 +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_LEN 8 +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_LO_OFST 4 +#define MC_CMD_FILTER_OP_EXT_OUT_HANDLE_HI_OFST 8 +/* Enum values, see field(s): */ +/* MC_CMD_FILTER_OP_OUT/HANDLE */ /***********************************/ @@ -4865,6 +6319,10 @@ #define MC_CMD_GET_PARSER_DISP_INFO_IN_OP_OFST 0 /* enum: read the list of supported RX filter matches */ #define MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES 0x1 +/* enum: read flags indicating restrictions on filter insertion for the calling + * client + */ +#define MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_RESTRICTIONS 0x2 /* MC_CMD_GET_PARSER_DISP_INFO_OUT msgresponse */ #define MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMIN 8 @@ -4884,6 +6342,17 @@ #define MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MINNUM 0 #define MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_MAXNUM 61 +/* MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT msgresponse */ +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_LEN 8 +/* identifies the type of operation requested */ +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_OP_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_GET_PARSER_DISP_INFO_IN/OP */ +/* bitfield of filter insertion restrictions */ +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_RESTRICTION_FLAGS_OFST 4 +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_DST_IP_MCAST_ONLY_LBN 0 +#define MC_CMD_GET_PARSER_DISP_RESTRICTIONS_OUT_DST_IP_MCAST_ONLY_WIDTH 1 + /***********************************/ /* MC_CMD_PARSER_DISP_RW @@ -4901,8 +6370,10 @@ #define MC_CMD_PARSER_DISP_RW_IN_RX_DICPU 0x0 /* enum: TX dispatcher CPU */ #define MC_CMD_PARSER_DISP_RW_IN_TX_DICPU 0x1 -/* enum: Lookup engine */ +/* enum: Lookup engine (with original metadata format) */ #define MC_CMD_PARSER_DISP_RW_IN_LUE 0x2 +/* enum: Lookup engine (with requested metadata format) */ +#define MC_CMD_PARSER_DISP_RW_IN_LUE_VERSIONED_METADATA 0x3 /* identifies the type of operation requested */ #define MC_CMD_PARSER_DISP_RW_IN_OP_OFST 4 /* enum: read a word of DICPU DMEM or a LUE entry */ @@ -4919,6 +6390,8 @@ #define MC_CMD_PARSER_DISP_RW_IN_DMEM_RMW_XOR_VALUE_OFST 12 /* AND mask (for DMEM read-modify-writes: new = (old & mask) ^ value) */ #define MC_CMD_PARSER_DISP_RW_IN_DMEM_RMW_AND_MASK_OFST 16 +/* metadata format (for LUE reads using LUE_VERSIONED_METADATA) */ +#define MC_CMD_PARSER_DISP_RW_IN_LUE_READ_METADATA_VERSION_OFST 12 /* value to write (for LUE writes) */ #define MC_CMD_PARSER_DISP_RW_IN_LUE_WRITE_VALUE_OFST 12 #define MC_CMD_PARSER_DISP_RW_IN_LUE_WRITE_VALUE_LEN 20 @@ -5019,7 +6492,9 @@ /* The maximum number of VIs that would be useful */ #define MC_CMD_ALLOC_VIS_IN_MAX_VI_COUNT_OFST 4 -/* MC_CMD_ALLOC_VIS_OUT msgresponse */ +/* MC_CMD_ALLOC_VIS_OUT msgresponse: Huntington-compatible VI_ALLOC request. + * Use extended version in new code. + */ #define MC_CMD_ALLOC_VIS_OUT_LEN 8 /* The number of VIs allocated on this function */ #define MC_CMD_ALLOC_VIS_OUT_VI_COUNT_OFST 0 @@ -5028,6 +6503,17 @@ */ #define MC_CMD_ALLOC_VIS_OUT_VI_BASE_OFST 4 +/* MC_CMD_ALLOC_VIS_EXT_OUT msgresponse */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_LEN 12 +/* The number of VIs allocated on this function */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_VI_COUNT_OFST 0 +/* The base absolute VI number allocated to this function. Required to + * correctly interpret wakeup events. + */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_VI_BASE_OFST 4 +/* Function's port vi_shift value (always 0 on Huntington) */ +#define MC_CMD_ALLOC_VIS_EXT_OUT_VI_SHIFT_OFST 8 + /***********************************/ /* MC_CMD_FREE_VIS @@ -5114,13 +6600,15 @@ #define MC_CMD_GET_VI_ALLOC_INFO_IN_LEN 0 /* MC_CMD_GET_VI_ALLOC_INFO_OUT msgresponse */ -#define MC_CMD_GET_VI_ALLOC_INFO_OUT_LEN 8 +#define MC_CMD_GET_VI_ALLOC_INFO_OUT_LEN 12 /* The number of VIs allocated on this function */ #define MC_CMD_GET_VI_ALLOC_INFO_OUT_VI_COUNT_OFST 0 /* The base absolute VI number allocated to this function. Required to * correctly interpret wakeup events. */ #define MC_CMD_GET_VI_ALLOC_INFO_OUT_VI_BASE_OFST 4 +/* Function's port vi_shift value (always 0 on Huntington) */ +#define MC_CMD_GET_VI_ALLOC_INFO_OUT_VI_SHIFT_OFST 8 /***********************************/ @@ -5575,6 +7063,7 @@ #define MC_CMD_GET_CAPABILITIES 0xbe #define MC_CMD_0xbe_PRIVILEGE_CTG SRIOV_CTG_GENERAL + /* MC_CMD_GET_CAPABILITIES_IN msgrequest */ #define MC_CMD_GET_CAPABILITIES_IN_LEN 0 @@ -5582,6 +7071,20 @@ #define MC_CMD_GET_CAPABILITIES_OUT_LEN 20 /* First word of flags. */ #define MC_CMD_GET_CAPABILITIES_OUT_FLAGS1_OFST 0 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_LBN 12 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MAC_SECURITY_FILTERING_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_ADDITIONAL_RSS_MODES_LBN 13 +#define MC_CMD_GET_CAPABILITIES_OUT_ADDITIONAL_RSS_MODES_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_QBB_LBN 14 +#define MC_CMD_GET_CAPABILITIES_OUT_QBB_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_VAR_BUFFERS_LBN 15 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_VAR_BUFFERS_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_RSS_LIMITED_LBN 16 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_RSS_LIMITED_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_LBN 17 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_PACKED_STREAM_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_INCLUDE_FCS_LBN 18 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_INCLUDE_FCS_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_TX_VLAN_INSERTION_LBN 19 #define MC_CMD_GET_CAPABILITIES_OUT_TX_VLAN_INSERTION_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_RX_VLAN_STRIPPING_LBN 20 @@ -5600,8 +7103,14 @@ #define MC_CMD_GET_CAPABILITIES_OUT_MCAST_FILTER_CHAINING_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_LBN 27 #define MC_CMD_GET_CAPABILITIES_OUT_PM_AND_RXDP_COUNTERS_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER_LBN 28 +#define MC_CMD_GET_CAPABILITIES_OUT_RX_DISABLE_SCATTER_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MCAST_UDP_LOOPBACK_LBN 29 +#define MC_CMD_GET_CAPABILITIES_OUT_TX_MCAST_UDP_LOOPBACK_WIDTH 1 #define MC_CMD_GET_CAPABILITIES_OUT_EVB_LBN 30 #define MC_CMD_GET_CAPABILITIES_OUT_EVB_WIDTH 1 +#define MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_LBN 31 +#define MC_CMD_GET_CAPABILITIES_OUT_VXLAN_NVGRE_WIDTH 1 /* RxDPCPU firmware id. */ #define MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_OFST 4 #define MC_CMD_GET_CAPABILITIES_OUT_RX_DPCPU_FW_ID_LEN 2 @@ -5609,6 +7118,10 @@ #define MC_CMD_GET_CAPABILITIES_OUT_RXDP 0x0 /* enum: Low latency RXDP firmware */ #define MC_CMD_GET_CAPABILITIES_OUT_RXDP_LOW_LATENCY 0x1 +/* enum: Packed stream RXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXDP_PACKED_STREAM 0x2 +/* enum: BIST RXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXDP_BIST 0x10a /* enum: RXDP Test firmware image 1 */ #define MC_CMD_GET_CAPABILITIES_OUT_RXDP_TEST_FW_TO_MC_CUT_THROUGH 0x101 /* enum: RXDP Test firmware image 2 */ @@ -5632,6 +7145,10 @@ #define MC_CMD_GET_CAPABILITIES_OUT_TXDP 0x0 /* enum: Low latency TXDP firmware */ #define MC_CMD_GET_CAPABILITIES_OUT_TXDP_LOW_LATENCY 0x1 +/* enum: High packet rate TXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXDP_HIGH_PACKET_RATE 0x3 +/* enum: BIST TXDP firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXDP_BIST 0x12d /* enum: TXDP Test firmware image 1 */ #define MC_CMD_GET_CAPABILITIES_OUT_TXDP_TEST_FW_TSO_EDIT 0x101 /* enum: TXDP Test firmware image 2 */ @@ -5642,22 +7159,69 @@ #define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_VERSION_REV_WIDTH 12 #define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_VERSION_TYPE_LBN 12 #define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_VERSION_TYPE_WIDTH 4 -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_FIRST_PKT 0x1 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT 0x2 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_VSWITCH 0x3 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_LOW_LATENCY 0x5 /* enum */ +/* enum: reserved value - do not use (may indicate alternative interpretation + * of REV field in future) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_RESERVED 0x0 +/* enum: Trivial RX PD firmware for early Huntington development (Huntington + * development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_FIRST_PKT 0x1 +/* enum: RX PD firmware with approximately Siena-compatible behaviour + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT 0x2 +/* enum: Virtual switching (full feature) RX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_VSWITCH 0x3 +/* enum: siena_compat variant RX PD firmware using PM rather than MAC + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 +/* enum: Low latency RX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_LOW_LATENCY 0x5 +/* enum: Packed stream RX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_PACKED_STREAM 0x6 +/* enum: RX PD firmware handling layer 2 only for high packet rate performance + * tests (Medford development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_LAYER2_PERF 0x7 +/* enum: RX PD firmware for GUE parsing prototype (Medford development only) */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_TESTFW_GUE_PROTOTYPE 0xe +/* enum: RX PD firmware parsing but not filtering network overlay tunnel + * encapsulations (Medford development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_RXPD_FW_TYPE_TESTFW_ENCAP_PARSING_ONLY 0xf #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_OFST 10 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_LEN 2 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_REV_LBN 0 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_REV_WIDTH 12 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_TYPE_LBN 12 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_VERSION_TYPE_WIDTH 4 -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_FIRST_PKT 0x1 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT 0x2 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_VSWITCH 0x3 /* enum */ -#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 /* enum */ +/* enum: reserved value - do not use (may indicate alternative interpretation + * of REV field in future) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_RESERVED 0x0 +/* enum: Trivial TX PD firmware for early Huntington development (Huntington + * development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_FIRST_PKT 0x1 +/* enum: TX PD firmware with approximately Siena-compatible behaviour + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT 0x2 +/* enum: Virtual switching (full feature) TX PD production firmware */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_VSWITCH 0x3 +/* enum: siena_compat variant TX PD firmware using PM rather than MAC + * (Huntington development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_SIENA_COMPAT_PM 0x4 #define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_LOW_LATENCY 0x5 /* enum */ +/* enum: TX PD firmware handling layer 2 only for high packet rate performance + * tests (Medford development only) + */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_LAYER2_PERF 0x7 +/* enum: RX PD firmware for GUE parsing prototype (Medford development only) */ +#define MC_CMD_GET_CAPABILITIES_OUT_TXPD_FW_TYPE_TESTFW_GUE_PROTOTYPE 0xe /* Hardware capabilities of NIC */ #define MC_CMD_GET_CAPABILITIES_OUT_HW_CAPABILITIES_OFST 12 /* Licensed capabilities */ @@ -5735,6 +7299,15 @@ /* the rate in mbps */ #define MC_CMD_TCM_BUCKET_INIT_IN_RATE_OFST 4 +/* MC_CMD_TCM_BUCKET_INIT_EXT_IN msgrequest */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_LEN 12 +/* the bucket id */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_BUCKET_OFST 0 +/* the rate in mbps */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_RATE_OFST 4 +/* the desired maximum fill level */ +#define MC_CMD_TCM_BUCKET_INIT_EXT_IN_MAX_FILL_OFST 8 + /* MC_CMD_TCM_BUCKET_INIT_OUT msgresponse */ #define MC_CMD_TCM_BUCKET_INIT_OUT_LEN 0 @@ -5753,8 +7326,14 @@ #define MC_CMD_TCM_TXQ_INIT_IN_QID_OFST 0 /* the static priority associated with the txq */ #define MC_CMD_TCM_TXQ_INIT_IN_LABEL_OFST 4 -/* bitmask of the priority queues this txq is inserted into */ +/* bitmask of the priority queues this txq is inserted into when inserted. */ #define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAGS_OFST 8 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_GUARANTEED_LBN 0 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_GUARANTEED_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_NORMAL_LBN 1 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_NORMAL_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_LOW_LBN 2 +#define MC_CMD_TCM_TXQ_INIT_IN_PQ_FLAG_LOW_WIDTH 1 /* the reaction point (RP) bucket */ #define MC_CMD_TCM_TXQ_INIT_IN_RP_BKT_OFST 12 /* an already reserved bucket (typically set to bucket associated with outer @@ -5768,6 +7347,35 @@ /* the min bucket (typically for ETS/minimum bandwidth) */ #define MC_CMD_TCM_TXQ_INIT_IN_MIN_BKT_OFST 24 +/* MC_CMD_TCM_TXQ_INIT_EXT_IN msgrequest */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_LEN 32 +/* the txq id */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_QID_OFST 0 +/* the static priority associated with the txq */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_LABEL_NORMAL_OFST 4 +/* bitmask of the priority queues this txq is inserted into when inserted. */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAGS_OFST 8 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_GUARANTEED_LBN 0 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_GUARANTEED_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_NORMAL_LBN 1 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_NORMAL_WIDTH 1 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_LOW_LBN 2 +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_PQ_FLAG_LOW_WIDTH 1 +/* the reaction point (RP) bucket */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_RP_BKT_OFST 12 +/* an already reserved bucket (typically set to bucket associated with outer + * vswitch) + */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_MAX_BKT1_OFST 16 +/* an already reserved bucket (typically set to bucket associated with inner + * vswitch) + */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_MAX_BKT2_OFST 20 +/* the min bucket (typically for ETS/minimum bandwidth) */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_MIN_BKT_OFST 24 +/* the static priority associated with the txq */ +#define MC_CMD_TCM_TXQ_INIT_EXT_IN_LABEL_GUARANTEED_OFST 28 + /* MC_CMD_TCM_TXQ_INIT_OUT msgresponse */ #define MC_CMD_TCM_TXQ_INIT_OUT_LEN 0 @@ -5826,13 +7434,23 @@ #define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VLAN 0x1 /* enum: VEB */ #define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEB 0x2 -/* enum: VEPA */ +/* enum: VEPA (obsolete) */ #define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_VEPA 0x3 +/* enum: MUX */ +#define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_MUX 0x4 +/* enum: Snapper specific; semantics TBD */ +#define MC_CMD_VSWITCH_ALLOC_IN_VSWITCH_TYPE_TEST 0x5 /* Flags controlling v-port creation */ #define MC_CMD_VSWITCH_ALLOC_IN_FLAGS_OFST 8 #define MC_CMD_VSWITCH_ALLOC_IN_FLAG_AUTO_PORT_LBN 0 #define MC_CMD_VSWITCH_ALLOC_IN_FLAG_AUTO_PORT_WIDTH 1 -/* The number of VLAN tags to support. */ +/* The number of VLAN tags to allow for attached v-ports. For VLAN aggregators, + * this must be one or greated, and the attached v-ports must have exactly this + * number of tags. For other v-switch types, this must be zero of greater, and + * is an upper limit on the number of VLAN tags for attached v-ports. An error + * will be returned if existing configuration means we can't support attached + * v-ports with this number of tags. + */ #define MC_CMD_VSWITCH_ALLOC_IN_NUM_VLAN_TAGS_OFST 12 /* MC_CMD_VSWITCH_ALLOC_OUT msgresponse */ @@ -5892,7 +7510,10 @@ #define MC_CMD_VPORT_ALLOC_IN_FLAGS_OFST 8 #define MC_CMD_VPORT_ALLOC_IN_FLAG_AUTO_PORT_LBN 0 #define MC_CMD_VPORT_ALLOC_IN_FLAG_AUTO_PORT_WIDTH 1 -/* The number of VLAN tags to insert/remove. */ +/* The number of VLAN tags to insert/remove. An error will be returned if + * incompatible with the number of VLAN tags specified for the upstream + * v-switch. + */ #define MC_CMD_VPORT_ALLOC_IN_NUM_VLAN_TAGS_OFST 12 /* The actual VLAN tags to insert/remove */ #define MC_CMD_VPORT_ALLOC_IN_VLAN_TAGS_OFST 16 @@ -6136,8 +7757,13 @@ /* MC_CMD_RSS_CONTEXT_ALLOC_OUT msgresponse */ #define MC_CMD_RSS_CONTEXT_ALLOC_OUT_LEN 4 -/* The handle of the new RSS context */ +/* The handle of the new RSS context. This should be considered opaque to the + * host, although a value of 0xFFFFFFFF is guaranteed never to be a valid + * handle. + */ #define MC_CMD_RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID_OFST 0 +/* enum: guaranteed invalid RSS context handle value */ +#define MC_CMD_RSS_CONTEXT_ALLOC_OUT_RSS_CONTEXT_ID_INVALID 0xffffffff /***********************************/ @@ -6249,7 +7875,11 @@ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN 8 /* The handle of the RSS context */ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_RSS_CONTEXT_ID_OFST 0 -/* Hash control flags */ +/* Hash control flags. The _EN bits are always supported. The _MODE bits only + * work when the firmware reports ADDITIONAL_RSS_MODES in + * MC_CMD_GET_CAPABILITIES and override the _EN bits if any of them are not 0. + * See the RSS_MODE structure for the meaning of the mode bits. + */ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_FLAGS_OFST 4 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN_LBN 0 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV4_EN_WIDTH 1 @@ -6259,6 +7889,20 @@ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_IPV6_EN_WIDTH 1 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN_LBN 3 #define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TOEPLITZ_TCPV6_EN_WIDTH 1 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_RESERVED_LBN 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_RESERVED_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_LBN 8 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV4_RSS_MODE_LBN 12 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_LBN 16 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_LBN 20 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_TCP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV6_RSS_MODE_LBN 24 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_UDP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_LBN 28 +#define MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_OTHER_IPV6_RSS_MODE_WIDTH 4 /* MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT msgresponse */ #define MC_CMD_RSS_CONTEXT_SET_FLAGS_OUT_LEN 0 @@ -6279,7 +7923,12 @@ /* MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT msgresponse */ #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_LEN 8 -/* Hash control flags */ +/* Hash control flags. If any _MODE bits are non-zero (which will only be true + * when the firmware reports ADDITIONAL_RSS_MODES) then the _EN bits should be + * disregarded (but are guaranteed to be consistent with the _MODE bits if + * RSS_CONTEXT_SET_FLAGS has never been called for this context since it was + * allocated). + */ #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_FLAGS_OFST 4 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV4_EN_LBN 0 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV4_EN_WIDTH 1 @@ -6289,6 +7938,20 @@ #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_IPV6_EN_WIDTH 1 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_TCPV6_EN_LBN 3 #define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TOEPLITZ_TCPV6_EN_WIDTH 1 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_RESERVED_LBN 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_RESERVED_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV4_RSS_MODE_LBN 8 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_LBN 12 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV4_RSS_MODE_LBN 16 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV4_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV6_RSS_MODE_LBN 20 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_TCP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN 24 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_WIDTH 4 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN 28 +#define MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_WIDTH 4 /***********************************/ @@ -6311,8 +7974,13 @@ /* MC_CMD_DOT1P_MAPPING_ALLOC_OUT msgresponse */ #define MC_CMD_DOT1P_MAPPING_ALLOC_OUT_LEN 4 -/* The handle of the new .1p mapping */ +/* The handle of the new .1p mapping. This should be considered opaque to the + * host, although a value of 0xFFFFFFFF is guaranteed never to be a valid + * handle. + */ #define MC_CMD_DOT1P_MAPPING_ALLOC_OUT_DOT1P_MAPPING_ID_OFST 0 +/* enum: guaranteed invalid .1p mapping handle value */ +#define MC_CMD_DOT1P_MAPPING_ALLOC_OUT_DOT1P_MAPPING_ID_INVALID 0xffffffff /***********************************/ @@ -6421,401 +8089,32 @@ /***********************************/ -/* MC_CMD_RMON_RX_CLASS_STATS - * Retrieve rmon rx class statistics +/* MC_CMD_VPORT_ADD_MAC_ADDRESS + * Add a MAC address to a v-port */ -#define MC_CMD_RMON_RX_CLASS_STATS 0xc3 - -/* MC_CMD_RMON_RX_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_RX_CLASS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_CLASS_STATS_OUT_BUFFER_MAXNUM 63 - +#define MC_CMD_VPORT_ADD_MAC_ADDRESS 0xa8 -/***********************************/ -/* MC_CMD_RMON_TX_CLASS_STATS - * Retrieve rmon tx class statistics - */ -#define MC_CMD_RMON_TX_CLASS_STATS 0xc4 +#define MC_CMD_0xa8_PRIVILEGE_CTG SRIOV_CTG_GENERAL -/* MC_CMD_RMON_TX_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_TX_CLASS_STATS_IN_RST_WIDTH 1 +/* MC_CMD_VPORT_ADD_MAC_ADDRESS_IN msgrequest */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN 10 +/* The handle of the v-port */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID_OFST 0 +/* MAC address to add */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_OFST 4 +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_LEN 6 -/* MC_CMD_RMON_TX_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_CLASS_STATS_OUT_BUFFER_MAXNUM 63 +/* MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT msgresponse */ +#define MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT_LEN 0 /***********************************/ -/* MC_CMD_RMON_RX_SUPER_CLASS_STATS - * Retrieve rmon rx super_class statistics +/* MC_CMD_VPORT_DEL_MAC_ADDRESS + * Delete a MAC address from a v-port */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS 0xc5 - -/* MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_RST_LBN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_SUPER_CLASS_STATS_OUT_BUFFER_MAXNUM 63 +#define MC_CMD_VPORT_DEL_MAC_ADDRESS 0xa9 - -/***********************************/ -/* MC_CMD_RMON_TX_SUPER_CLASS_STATS - * Retrieve rmon tx super_class statistics - */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS 0xc6 - -/* MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_RST_LBN 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_SUPER_CLASS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_ADD_QID_TO_CLASS - * Add qid to class for statistics collection - */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS 0xc7 - -/* MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN msgrequest */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_LEN 12 -/* class */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_CLASS_OFST 0 -/* qid */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_QID_OFST 4 -/* flags */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_FLAGS_OFST 8 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_PE_DELTA_LBN 4 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_PE_DELTA_WIDTH 4 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_MTU_LBN 8 -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_IN_MTU_WIDTH 14 - -/* MC_CMD_RMON_RX_ADD_QID_TO_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_RX_ADD_QID_TO_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_TX_ADD_QID_TO_CLASS - * Add qid to class for statistics collection - */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS 0xc8 - -/* MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN msgrequest */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_LEN 12 -/* class */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_CLASS_OFST 0 -/* qid */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_QID_OFST 4 -/* flags */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_FLAGS_OFST 8 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_PE_DELTA_LBN 4 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_PE_DELTA_WIDTH 4 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_MTU_LBN 8 -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_IN_MTU_WIDTH 14 - -/* MC_CMD_RMON_TX_ADD_QID_TO_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_TX_ADD_QID_TO_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_MC_ADD_QID_TO_CLASS - * Add qid to class for statistics collection - */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS 0xc9 - -/* MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN msgrequest */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_LEN 12 -/* class */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_CLASS_OFST 0 -/* qid */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_QID_OFST 4 -/* flags */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_FLAGS_OFST 8 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_PE_DELTA_LBN 4 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_PE_DELTA_WIDTH 4 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_MTU_LBN 8 -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_IN_MTU_WIDTH 14 - -/* MC_CMD_RMON_MC_ADD_QID_TO_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_MC_ADD_QID_TO_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_ALLOC_CLASS - * Allocate an rmon class - */ -#define MC_CMD_RMON_ALLOC_CLASS 0xca - -/* MC_CMD_RMON_ALLOC_CLASS_IN msgrequest */ -#define MC_CMD_RMON_ALLOC_CLASS_IN_LEN 0 - -/* MC_CMD_RMON_ALLOC_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_ALLOC_CLASS_OUT_LEN 4 -/* class */ -#define MC_CMD_RMON_ALLOC_CLASS_OUT_CLASS_OFST 0 - - -/***********************************/ -/* MC_CMD_RMON_DEALLOC_CLASS - * Deallocate an rmon class - */ -#define MC_CMD_RMON_DEALLOC_CLASS 0xcb - -/* MC_CMD_RMON_DEALLOC_CLASS_IN msgrequest */ -#define MC_CMD_RMON_DEALLOC_CLASS_IN_LEN 4 -/* class */ -#define MC_CMD_RMON_DEALLOC_CLASS_IN_CLASS_OFST 0 - -/* MC_CMD_RMON_DEALLOC_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_DEALLOC_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_ALLOC_SUPER_CLASS - * Allocate an rmon super_class - */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS 0xcc - -/* MC_CMD_RMON_ALLOC_SUPER_CLASS_IN msgrequest */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS_IN_LEN 0 - -/* MC_CMD_RMON_ALLOC_SUPER_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS_OUT_LEN 4 -/* super_class */ -#define MC_CMD_RMON_ALLOC_SUPER_CLASS_OUT_SUPER_CLASS_OFST 0 - - -/***********************************/ -/* MC_CMD_RMON_DEALLOC_SUPER_CLASS - * Deallocate an rmon tx super_class - */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS 0xcd - -/* MC_CMD_RMON_DEALLOC_SUPER_CLASS_IN msgrequest */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS_IN_LEN 4 -/* super_class */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS_IN_SUPER_CLASS_OFST 0 - -/* MC_CMD_RMON_DEALLOC_SUPER_CLASS_OUT msgresponse */ -#define MC_CMD_RMON_DEALLOC_SUPER_CLASS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_RMON_RX_UP_CONV_STATS - * Retrieve up converter statistics - */ -#define MC_CMD_RMON_RX_UP_CONV_STATS 0xce - -/* MC_CMD_RMON_RX_UP_CONV_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_RX_UP_CONV_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_UP_CONV_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_UP_CONV_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPI_STATS - * Retrieve rx ipi stats - */ -#define MC_CMD_RMON_RX_IPI_STATS 0xcf - -/* MC_CMD_RMON_RX_IPI_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPI_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPI_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPI_STATS_IN_VFIFO_LBN 0 -#define MC_CMD_RMON_RX_IPI_STATS_IN_VFIFO_WIDTH 5 -#define MC_CMD_RMON_RX_IPI_STATS_IN_RST_LBN 5 -#define MC_CMD_RMON_RX_IPI_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPI_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPI_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPI_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS - * Retrieve rx ipsec cntxt_ptr indexed stats - */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS 0xd0 - -/* MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_LBN 0 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_WIDTH 9 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_RST_LBN 9 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPSEC_PORT_STATS - * Retrieve rx ipsec port indexed stats - */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS 0xd1 - -/* MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPSEC_PORT_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_IPSEC_OFLOW_STATS - * Retrieve tx ipsec overflow - */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS 0xd2 - -/* MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_IPSEC_OFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_VPORT_ADD_MAC_ADDRESS - * Add a MAC address to a v-port - */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS 0xa8 - -#define MC_CMD_0xa8_PRIVILEGE_CTG SRIOV_CTG_GENERAL - -/* MC_CMD_VPORT_ADD_MAC_ADDRESS_IN msgrequest */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_LEN 10 -/* The handle of the v-port */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_VPORT_ID_OFST 0 -/* MAC address to add */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_OFST 4 -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_IN_MACADDR_LEN 6 - -/* MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT msgresponse */ -#define MC_CMD_VPORT_ADD_MAC_ADDRESS_OUT_LEN 0 - - -/***********************************/ -/* MC_CMD_VPORT_DEL_MAC_ADDRESS - * Delete a MAC address from a v-port - */ -#define MC_CMD_VPORT_DEL_MAC_ADDRESS 0xa9 - -#define MC_CMD_0xa9_PRIVILEGE_CTG SRIOV_CTG_GENERAL +#define MC_CMD_0xa9_PRIVILEGE_CTG SRIOV_CTG_GENERAL /* MC_CMD_VPORT_DEL_MAC_ADDRESS_IN msgrequest */ #define MC_CMD_VPORT_DEL_MAC_ADDRESS_IN_LEN 10 @@ -6877,7 +8176,7 @@ #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_LENMIN 12 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_LENMAX 252 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_LEN(num) (0+12*(num)) -/* Raw buffer table entries, laid out as BUFTBL_ENTRY. */ +/* Raw buffer table entries, layed out as BUFTBL_ENTRY. */ #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_ENTRY_OFST 0 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_ENTRY_LEN 12 #define MC_CMD_DUMP_BUFTBL_ENTRIES_OUT_ENTRY_MINNUM 1 @@ -6920,354 +8219,6 @@ #define MC_CMD_GET_RXDP_CONFIG_OUT_PAD_HOST_DMA_WIDTH 1 -/***********************************/ -/* MC_CMD_RMON_RX_CLASS_DROPS_STATS - * Retrieve rx class drop stats - */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS 0xd3 - -/* MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_CLASS_DROPS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS - * Retrieve rx super class drop stats - */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS 0xd4 - -/* MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_SUPER_CLASS_LBN 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_SUPER_CLASS_WIDTH 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_RST_LBN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_SUPER_CLASS_DROPS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_ERRORS_STATS - * Retrieve rxdp errors - */ -#define MC_CMD_RMON_RX_ERRORS_STATS 0xd5 - -/* MC_CMD_RMON_RX_ERRORS_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_QID_LBN 0 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_QID_WIDTH 11 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_RST_LBN 11 -#define MC_CMD_RMON_RX_ERRORS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_ERRORS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_ERRORS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_RX_OVERFLOW_STATS - * Retrieve rxdp overflow - */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS 0xd6 - -/* MC_CMD_RMON_RX_OVERFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_RX_OVERFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_RX_OVERFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPI_STATS - * Retrieve tx ipi stats - */ -#define MC_CMD_RMON_TX_IPI_STATS 0xd7 - -/* MC_CMD_RMON_TX_IPI_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPI_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPI_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPI_STATS_IN_VFIFO_LBN 0 -#define MC_CMD_RMON_TX_IPI_STATS_IN_VFIFO_WIDTH 5 -#define MC_CMD_RMON_TX_IPI_STATS_IN_RST_LBN 5 -#define MC_CMD_RMON_TX_IPI_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPI_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPI_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPI_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS - * Retrieve tx ipsec counters by cntxt_ptr - */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS 0xd8 - -/* MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_LBN 0 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_CNTXT_PTR_WIDTH 9 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_RST_LBN 9 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPSEC_CNTXT_PTR_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPSEC_PORT_STATS - * Retrieve tx ipsec counters by port - */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS 0xd9 - -/* MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPSEC_PORT_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_IPSEC_OFLOW_STATS - * Retrieve tx ipsec overflow - */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS 0xda - -/* MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_PORT_LBN 0 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_PORT_WIDTH 2 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_RST_LBN 2 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_IPSEC_OFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_NOWHERE_STATS - * Retrieve tx nowhere stats - */ -#define MC_CMD_RMON_TX_NOWHERE_STATS 0xdb - -/* MC_CMD_RMON_TX_NOWHERE_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_TX_NOWHERE_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_NOWHERE_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_NOWHERE_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_NOWHERE_QBB_STATS - * Retrieve tx nowhere qbb stats - */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS 0xdc - -/* MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_PRIORITY_LBN 0 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_PRIORITY_WIDTH 3 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_RST_LBN 3 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_NOWHERE_QBB_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_ERRORS_STATS - * Retrieve rxdp errors - */ -#define MC_CMD_RMON_TX_ERRORS_STATS 0xdd - -/* MC_CMD_RMON_TX_ERRORS_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_QID_LBN 0 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_QID_WIDTH 11 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_RST_LBN 11 -#define MC_CMD_RMON_TX_ERRORS_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_ERRORS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_ERRORS_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_TX_OVERFLOW_STATS - * Retrieve rxdp overflow - */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS 0xde - -/* MC_CMD_RMON_TX_OVERFLOW_STATS_IN msgrequest */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_LEN 4 -/* flags */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_FLAGS_OFST 0 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_CLASS_LBN 0 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_CLASS_WIDTH 8 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_RST_LBN 8 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_IN_RST_WIDTH 1 - -/* MC_CMD_RMON_TX_OVERFLOW_STATS_OUT msgresponse */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_LENMIN 4 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_LENMAX 252 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_LEN(num) (0+4*(num)) -/* Array of stats */ -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_OFST 0 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_LEN 4 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_MINNUM 1 -#define MC_CMD_RMON_TX_OVERFLOW_STATS_OUT_BUFFER_MAXNUM 63 - - -/***********************************/ -/* MC_CMD_RMON_COLLECT_CLASS_STATS - * Explicitly collect class stats at the specified evb port - */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS 0xdf - -/* MC_CMD_RMON_COLLECT_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_IN_LEN 4 -/* The port id associated with the vport/pport at which to collect class stats - */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_IN_PORT_ID_OFST 0 - -/* MC_CMD_RMON_COLLECT_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_OUT_LEN 4 -/* class */ -#define MC_CMD_RMON_COLLECT_CLASS_STATS_OUT_CLASS_OFST 0 - - -/***********************************/ -/* MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS - * Explicitly collect class stats at the specified evb port - */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS 0xe0 - -/* MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_IN msgrequest */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_IN_LEN 4 -/* The port id associated with the vport/pport at which to collect class stats - */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_IN_PORT_ID_OFST 0 - -/* MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_OUT msgresponse */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_OUT_LEN 4 -/* super_class */ -#define MC_CMD_RMON_COLLECT_SUPER_CLASS_STATS_OUT_SUPER_CLASS_OFST 0 - - /***********************************/ /* MC_CMD_GET_CLOCK * Return the system and PDCPU clock frequencies. @@ -7296,22 +8247,66 @@ #define MC_CMD_0xad_PRIVILEGE_CTG SRIOV_CTG_ADMIN /* MC_CMD_SET_CLOCK_IN msgrequest */ -#define MC_CMD_SET_CLOCK_IN_LEN 12 -/* Requested system frequency in MHz; 0 leaves unchanged. */ +#define MC_CMD_SET_CLOCK_IN_LEN 28 +/* Requested frequency in MHz for system clock domain */ #define MC_CMD_SET_CLOCK_IN_SYS_FREQ_OFST 0 -/* Requested inter-core frequency in MHz; 0 leaves unchanged. */ +/* enum: Leave the system clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_SYS_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for inter-core clock domain */ #define MC_CMD_SET_CLOCK_IN_ICORE_FREQ_OFST 4 -/* Request DPCPU frequency in MHz; 0 leaves unchanged. */ +/* enum: Leave the inter-core clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_ICORE_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for DPCPU clock domain */ #define MC_CMD_SET_CLOCK_IN_DPCPU_FREQ_OFST 8 +/* enum: Leave the DPCPU clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_DPCPU_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for PCS clock domain */ +#define MC_CMD_SET_CLOCK_IN_PCS_FREQ_OFST 12 +/* enum: Leave the PCS clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_PCS_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for MC clock domain */ +#define MC_CMD_SET_CLOCK_IN_MC_FREQ_OFST 16 +/* enum: Leave the MC clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_MC_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for rmon clock domain */ +#define MC_CMD_SET_CLOCK_IN_RMON_FREQ_OFST 20 +/* enum: Leave the rmon clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_RMON_DOMAIN_DONT_CHANGE 0x0 +/* Requested frequency in MHz for vswitch clock domain */ +#define MC_CMD_SET_CLOCK_IN_VSWITCH_FREQ_OFST 24 +/* enum: Leave the vswitch clock domain frequency unchanged */ +#define MC_CMD_SET_CLOCK_IN_VSWITCH_DOMAIN_DONT_CHANGE 0x0 /* MC_CMD_SET_CLOCK_OUT msgresponse */ -#define MC_CMD_SET_CLOCK_OUT_LEN 12 +#define MC_CMD_SET_CLOCK_OUT_LEN 28 /* Resulting system frequency in MHz */ #define MC_CMD_SET_CLOCK_OUT_SYS_FREQ_OFST 0 +/* enum: The system clock domain doesn't exist */ +#define MC_CMD_SET_CLOCK_OUT_SYS_DOMAIN_UNSUPPORTED 0x0 /* Resulting inter-core frequency in MHz */ #define MC_CMD_SET_CLOCK_OUT_ICORE_FREQ_OFST 4 +/* enum: The inter-core clock domain doesn't exist / isn't used */ +#define MC_CMD_SET_CLOCK_OUT_ICORE_DOMAIN_UNSUPPORTED 0x0 /* Resulting DPCPU frequency in MHz */ #define MC_CMD_SET_CLOCK_OUT_DPCPU_FREQ_OFST 8 +/* enum: The dpcpu clock domain doesn't exist */ +#define MC_CMD_SET_CLOCK_OUT_DPCPU_DOMAIN_UNSUPPORTED 0x0 +/* Resulting PCS frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_PCS_FREQ_OFST 12 +/* enum: The PCS clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_PCS_DOMAIN_UNSUPPORTED 0x0 +/* Resulting MC frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_MC_FREQ_OFST 16 +/* enum: The MC clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_MC_DOMAIN_UNSUPPORTED 0x0 +/* Resulting rmon frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_RMON_FREQ_OFST 20 +/* enum: The rmon clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_RMON_DOMAIN_UNSUPPORTED 0x0 +/* Resulting vswitch frequency in MHz */ +#define MC_CMD_SET_CLOCK_OUT_VSWITCH_FREQ_OFST 24 +/* enum: The vswitch clock domain doesn't exist / isn't controlled */ +#define MC_CMD_SET_CLOCK_OUT_VSWITCH_DOMAIN_UNSUPPORTED 0x0 /***********************************/ @@ -7325,12 +8320,22 @@ /* MC_CMD_DPCPU_RPC_IN msgrequest */ #define MC_CMD_DPCPU_RPC_IN_LEN 36 #define MC_CMD_DPCPU_RPC_IN_CPU_OFST 0 -/* enum: RxDPCPU */ -#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX 0x0 +/* enum: RxDPCPU0 */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX0 0x0 /* enum: TxDPCPU0 */ #define MC_CMD_DPCPU_RPC_IN_DPCPU_TX0 0x1 /* enum: TxDPCPU1 */ #define MC_CMD_DPCPU_RPC_IN_DPCPU_TX1 0x2 +/* enum: RxDPCPU1 (Medford only) */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX1 0x3 +/* enum: RxDPCPU (will be for the calling function; for now, just an alias of + * DPCPU_RX0) + */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_RX 0x80 +/* enum: TxDPCPU (will be for the calling function; for now, just an alias of + * DPCPU_TX0) + */ +#define MC_CMD_DPCPU_RPC_IN_DPCPU_TX 0x81 /* First 8 bits [39:32] of DATA are consumed by MC-DPCPU protocol and must be * initialised to zero */ @@ -7417,6 +8422,25 @@ #define MC_CMD_TRIGGER_INTERRUPT_OUT_LEN 0 +/***********************************/ +/* MC_CMD_SHMBOOT_OP + * Special operations to support (for now) shmboot. + */ +#define MC_CMD_SHMBOOT_OP 0xe6 + +#define MC_CMD_0xe6_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_SHMBOOT_OP_IN msgrequest */ +#define MC_CMD_SHMBOOT_OP_IN_LEN 4 +/* Identifies the operation to perform */ +#define MC_CMD_SHMBOOT_OP_IN_SHMBOOT_OP_OFST 0 +/* enum: Copy slave_data section to the slave core. (Greenport only) */ +#define MC_CMD_SHMBOOT_OP_IN_PUSH_SLAVE_DATA 0x0 + +/* MC_CMD_SHMBOOT_OP_OUT msgresponse */ +#define MC_CMD_SHMBOOT_OP_OUT_LEN 0 + + /***********************************/ /* MC_CMD_CAP_BLK_READ * Read multiple 64bit words from capture block memory @@ -7730,6 +8754,8 @@ * more data is returned. */ #define MC_CMD_KR_TUNE_IN_POLL_EYE_PLOT 0x6 +/* enum: Read Figure Of Merit (eye quality, higher is better). */ +#define MC_CMD_KR_TUNE_IN_READ_FOM 0x7 /* Align the arguments to 32 bits */ #define MC_CMD_KR_TUNE_IN_KR_TUNE_RSVD_OFST 1 #define MC_CMD_KR_TUNE_IN_KR_TUNE_RSVD_LEN 3 @@ -7762,20 +8788,32 @@ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_MAXNUM 63 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_ID_LBN 0 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_ID_WIDTH 8 -/* enum: Attenuation (0-15) */ +/* enum: Attenuation (0-15, TBD for Medford) */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_ATT 0x0 -/* enum: CTLE Boost (0-15) */ +/* enum: CTLE Boost (0-15, TBD for Medford) */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_BOOST 0x1 -/* enum: Edge DFE Tap1 (0 - max negative, 64 - zero, 127 - max positive) */ +/* enum: Edge DFE Tap1 (0 - max negative, 64 - zero, 127 - max positive, TBD + * for Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP1 0x2 -/* enum: Edge DFE Tap2 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap2 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP2 0x3 -/* enum: Edge DFE Tap3 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap3 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP3 0x4 -/* enum: Edge DFE Tap4 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap4 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP4 0x5 -/* enum: Edge DFE Tap5 (0 - max negative, 32 - zero, 63 - max positive) */ +/* enum: Edge DFE Tap5 (0 - max negative, 32 - zero, 63 - max positive, TBD for + * Medford) + */ #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_TAP5 0x6 +/* enum: Edge DFE DLEV (TBD for Medford) */ +#define MC_CMD_KR_TUNE_RXEQ_GET_OUT_EDFE_DLEV 0x7 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_LANE_LBN 8 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_PARAM_LANE_WIDTH 3 #define MC_CMD_KR_TUNE_RXEQ_GET_OUT_LANE_0 0x0 /* enum */ @@ -7865,6 +8903,8 @@ #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_PREDRV_DLY 0x7 /* enum: TX Slew Rate Fine control */ #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_SR_SET 0x8 +/* enum: TX Termination Impedance control */ +#define MC_CMD_KR_TUNE_TXEQ_GET_OUT_TX_RT_SET 0x9 #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LANE_LBN 8 #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_PARAM_LANE_WIDTH 3 #define MC_CMD_KR_TUNE_TXEQ_GET_OUT_LANE_0 0x0 /* enum */ @@ -7955,6 +8995,20 @@ #define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MINNUM 0 #define MC_CMD_KR_TUNE_POLL_EYE_PLOT_OUT_SAMPLES_MAXNUM 126 +/* MC_CMD_KR_TUNE_READ_FOM_IN msgrequest */ +#define MC_CMD_KR_TUNE_READ_FOM_IN_LEN 8 +/* Requested operation */ +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_OP_OFST 0 +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_OP_LEN 1 +/* Align the arguments to 32 bits */ +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_RSVD_OFST 1 +#define MC_CMD_KR_TUNE_READ_FOM_IN_KR_TUNE_RSVD_LEN 3 +#define MC_CMD_KR_TUNE_READ_FOM_IN_LANE_OFST 4 + +/* MC_CMD_KR_TUNE_READ_FOM_OUT msgresponse */ +#define MC_CMD_KR_TUNE_READ_FOM_OUT_LEN 4 +#define MC_CMD_KR_TUNE_READ_FOM_OUT_FOM_OFST 0 + /***********************************/ /* MC_CMD_PCIE_TUNE @@ -8224,6 +9278,8 @@ #define MC_CMD_LICENSED_APP_OP_IN_OP_OFST 4 /* enum: validate application */ #define MC_CMD_LICENSED_APP_OP_IN_OP_VALIDATE 0x0 +/* enum: mask application */ +#define MC_CMD_LICENSED_APP_OP_IN_OP_MASK 0x1 /* arguments specific to this particular operation */ #define MC_CMD_LICENSED_APP_OP_IN_ARGS_OFST 8 #define MC_CMD_LICENSED_APP_OP_IN_ARGS_LEN 4 @@ -8258,10 +9314,22 @@ #define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_RESPONSE_OFST 4 #define MC_CMD_LICENSED_APP_OP_VALIDATE_OUT_RESPONSE_LEN 64 +/* MC_CMD_LICENSED_APP_OP_MASK_IN msgrequest */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_LEN 12 +/* application ID */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_APP_ID_OFST 0 +/* the type of operation requested */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_OP_OFST 4 +/* flag */ +#define MC_CMD_LICENSED_APP_OP_MASK_IN_FLAG_OFST 8 + +/* MC_CMD_LICENSED_APP_OP_MASK_OUT msgresponse */ +#define MC_CMD_LICENSED_APP_OP_MASK_OUT_LEN 0 + /***********************************/ /* MC_CMD_SET_PORT_SNIFF_CONFIG - * Configure port sniffing for the physical port associated with the calling + * Configure RX port sniffing for the physical port associated with the calling * function. Only a privileged function may change the port sniffing * configuration. A copy of all traffic delivered to the host (non-promiscuous * mode) or all traffic arriving at the port (promiscuous mode) may be @@ -8299,7 +9367,7 @@ /***********************************/ /* MC_CMD_GET_PORT_SNIFF_CONFIG - * Obtain the current port sniffing configuration for the physical port + * Obtain the current RX port sniffing configuration for the physical port * associated with the calling function. Only a privileged function may read * the configuration. */ @@ -8330,4 +9398,673 @@ #define MC_CMD_GET_PORT_SNIFF_CONFIG_OUT_RX_CONTEXT_OFST 12 +/***********************************/ +/* MC_CMD_SET_PARSER_DISP_CONFIG + * Change configuration related to the parser-dispatcher subsystem. + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG 0xf9 + +#define MC_CMD_0xf9_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_SET_PARSER_DISP_CONFIG_IN msgrequest */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_LENMIN 12 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_LENMAX 252 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_LEN(num) (8+4*(num)) +/* the type of configuration setting to change */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_TYPE_OFST 0 +/* enum: Per-TXQ enable for multicast UDP destination lookup for possible + * internal loopback. (ENTITY is a queue handle, VALUE is a single boolean.) + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_TXQ_MCAST_UDP_DST_LOOKUP_EN 0x0 +/* enum: Per-v-adaptor enable for suppression of self-transmissions on the + * internal loopback path. (ENTITY is an EVB_PORT_ID, VALUE is a single + * boolean.) + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VADAPTOR_SUPPRESS_SELF_TX 0x1 +/* handle for the entity to update: queue handle, EVB port ID, etc. depending + * on the type of configuration setting being changed + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_ENTITY_OFST 4 +/* new value: the details depend on the type of configuration setting being + * changed + */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_OFST 8 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_LEN 4 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_MINNUM 1 +#define MC_CMD_SET_PARSER_DISP_CONFIG_IN_VALUE_MAXNUM 61 + +/* MC_CMD_SET_PARSER_DISP_CONFIG_OUT msgresponse */ +#define MC_CMD_SET_PARSER_DISP_CONFIG_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_GET_PARSER_DISP_CONFIG + * Read configuration related to the parser-dispatcher subsystem. + */ +#define MC_CMD_GET_PARSER_DISP_CONFIG 0xfa + +#define MC_CMD_0xfa_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_PARSER_DISP_CONFIG_IN msgrequest */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_IN_LEN 8 +/* the type of configuration setting to read */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_IN_TYPE_OFST 0 +/* Enum values, see field(s): */ +/* MC_CMD_SET_PARSER_DISP_CONFIG/MC_CMD_SET_PARSER_DISP_CONFIG_IN/TYPE */ +/* handle for the entity to query: queue handle, EVB port ID, etc. depending on + * the type of configuration setting being read + */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_IN_ENTITY_OFST 4 + +/* MC_CMD_GET_PARSER_DISP_CONFIG_OUT msgresponse */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_LENMIN 4 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_LENMAX 252 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_LEN(num) (0+4*(num)) +/* current value: the details depend on the type of configuration setting being + * read + */ +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_OFST 0 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_LEN 4 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_MINNUM 1 +#define MC_CMD_GET_PARSER_DISP_CONFIG_OUT_VALUE_MAXNUM 63 + + +/***********************************/ +/* MC_CMD_SET_TX_PORT_SNIFF_CONFIG + * Configure TX port sniffing for the physical port associated with the calling + * function. Only a privileged function may change the port sniffing + * configuration. A copy of all traffic transmitted through the port may be + * delivered to a specific queue, or a set of queues with RSS. Note that these + * packets are delivered with transmit timestamps in the packet prefix, not + * receive timestamps, so it is likely that the queue(s) will need to be + * dedicated as TX sniff receivers. + */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG 0xfb + +#define MC_CMD_0xfb_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN msgrequest */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_LEN 16 +/* configuration flags */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_FLAGS_OFST 0 +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_ENABLE_LBN 0 +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_ENABLE_WIDTH 1 +/* receive queue handle (for RSS mode, this is the base queue) */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_QUEUE_OFST 4 +/* receive mode */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_MODE_OFST 8 +/* enum: receive to just the specified queue */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_MODE_SIMPLE 0x0 +/* enum: receive to multiple queues using RSS context */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_MODE_RSS 0x1 +/* RSS context (for RX_MODE_RSS) as returned by MC_CMD_RSS_CONTEXT_ALLOC. Note + * that these handles should be considered opaque to the host, although a value + * of 0xFFFFFFFF is guaranteed never to be a valid handle. + */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_IN_RX_CONTEXT_OFST 12 + +/* MC_CMD_SET_TX_PORT_SNIFF_CONFIG_OUT msgresponse */ +#define MC_CMD_SET_TX_PORT_SNIFF_CONFIG_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_GET_TX_PORT_SNIFF_CONFIG + * Obtain the current TX port sniffing configuration for the physical port + * associated with the calling function. Only a privileged function may read + * the configuration. + */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG 0xfc + +#define MC_CMD_0xfc_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_GET_TX_PORT_SNIFF_CONFIG_IN msgrequest */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_IN_LEN 0 + +/* MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT msgresponse */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_LEN 16 +/* configuration flags */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_FLAGS_OFST 0 +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_ENABLE_LBN 0 +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_ENABLE_WIDTH 1 +/* receiving queue handle (for RSS mode, this is the base queue) */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_QUEUE_OFST 4 +/* receive mode */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_MODE_OFST 8 +/* enum: receiving to just the specified queue */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_MODE_SIMPLE 0x0 +/* enum: receiving to multiple queues using RSS context */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_MODE_RSS 0x1 +/* RSS context (for RX_MODE_RSS) */ +#define MC_CMD_GET_TX_PORT_SNIFF_CONFIG_OUT_RX_CONTEXT_OFST 12 + + +/***********************************/ +/* MC_CMD_RMON_STATS_RX_ERRORS + * Per queue rx error stats. + */ +#define MC_CMD_RMON_STATS_RX_ERRORS 0xfe + +#define MC_CMD_0xfe_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_RMON_STATS_RX_ERRORS_IN msgrequest */ +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_LEN 8 +/* The rx queue to get stats for. */ +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_RX_QUEUE_OFST 0 +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_FLAGS_OFST 4 +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_RST_LBN 0 +#define MC_CMD_RMON_STATS_RX_ERRORS_IN_RST_WIDTH 1 + +/* MC_CMD_RMON_STATS_RX_ERRORS_OUT msgresponse */ +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_LEN 16 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_CRC_ERRORS_OFST 0 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_TRUNC_ERRORS_OFST 4 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_RX_NO_DESC_DROPS_OFST 8 +#define MC_CMD_RMON_STATS_RX_ERRORS_OUT_RX_ABORT_OFST 12 + + +/***********************************/ +/* MC_CMD_GET_PCIE_RESOURCE_INFO + * Find out about available PCIE resources + */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO 0xfd + +/* MC_CMD_GET_PCIE_RESOURCE_INFO_IN msgrequest */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_IN_LEN 0 + +/* MC_CMD_GET_PCIE_RESOURCE_INFO_OUT msgresponse */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_LEN 28 +/* The maximum number of PFs the device can expose */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_PFS_OFST 0 +/* The maximum number of VFs the device can expose in total */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_VFS_OFST 4 +/* The maximum number of MSI-X vectors the device can provide in total */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_VECTORS_OFST 8 +/* the number of MSI-X vectors the device will allocate by default to each PF + */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_DEFAULT_PF_VECTORS_OFST 12 +/* the number of MSI-X vectors the device will allocate by default to each VF + */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_DEFAULT_VF_VECTORS_OFST 16 +/* the maximum number of MSI-X vectors the device can allocate to any one PF */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_PF_VECTORS_OFST 20 +/* the maximum number of MSI-X vectors the device can allocate to any one VF */ +#define MC_CMD_GET_PCIE_RESOURCE_INFO_OUT_MAX_VF_VECTORS_OFST 24 + + +/***********************************/ +/* MC_CMD_GET_PORT_MODES + * Find out about available port modes + */ +#define MC_CMD_GET_PORT_MODES 0xff + +#define MC_CMD_0xff_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_PORT_MODES_IN msgrequest */ +#define MC_CMD_GET_PORT_MODES_IN_LEN 0 + +/* MC_CMD_GET_PORT_MODES_OUT msgresponse */ +#define MC_CMD_GET_PORT_MODES_OUT_LEN 12 +/* Bitmask of port modes available on the board (indexed by TLV_PORT_MODE_*) */ +#define MC_CMD_GET_PORT_MODES_OUT_MODES_OFST 0 +/* Default (canonical) board mode */ +#define MC_CMD_GET_PORT_MODES_OUT_DEFAULT_MODE_OFST 4 +/* Current board mode */ +#define MC_CMD_GET_PORT_MODES_OUT_CURRENT_MODE_OFST 8 + + +/***********************************/ +/* MC_CMD_READ_ATB + * Sample voltages on the ATB + */ +#define MC_CMD_READ_ATB 0x100 + +#define MC_CMD_0x100_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_READ_ATB_IN msgrequest */ +#define MC_CMD_READ_ATB_IN_LEN 16 +#define MC_CMD_READ_ATB_IN_SIGNAL_BUS_OFST 0 +#define MC_CMD_READ_ATB_IN_BUS_CCOM 0x0 /* enum */ +#define MC_CMD_READ_ATB_IN_BUS_CKR 0x1 /* enum */ +#define MC_CMD_READ_ATB_IN_BUS_CPCIE 0x8 /* enum */ +#define MC_CMD_READ_ATB_IN_SIGNAL_EN_BITNO_OFST 4 +#define MC_CMD_READ_ATB_IN_SIGNAL_SEL_OFST 8 +#define MC_CMD_READ_ATB_IN_SETTLING_TIME_US_OFST 12 + +/* MC_CMD_READ_ATB_OUT msgresponse */ +#define MC_CMD_READ_ATB_OUT_LEN 4 +#define MC_CMD_READ_ATB_OUT_SAMPLE_MV_OFST 0 + + +/***********************************/ +/* MC_CMD_GET_WORKAROUNDS + * Read the list of all implemented and all currently enabled workarounds. The + * enums here must correspond with those in MC_CMD_WORKAROUND. + */ +#define MC_CMD_GET_WORKAROUNDS 0x59 + +#define MC_CMD_0x59_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_WORKAROUNDS_OUT msgresponse */ +#define MC_CMD_GET_WORKAROUNDS_OUT_LEN 8 +/* Each workaround is represented by a single bit according to the enums below. + */ +#define MC_CMD_GET_WORKAROUNDS_OUT_IMPLEMENTED_OFST 0 +#define MC_CMD_GET_WORKAROUNDS_OUT_ENABLED_OFST 4 +/* enum: Bug 17230 work around. */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG17230 0x2 +/* enum: Bug 35388 work around (unsafe EVQ writes). */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35388 0x4 +/* enum: Bug35017 workaround (A64 tables must be identity map) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG35017 0x8 +/* enum: Bug 41750 present (MC_CMD_TRIGGER_INTERRUPT won't work) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG41750 0x10 +/* enum: Bug 42008 present (Interrupts can overtake associated events). Caution + * - before adding code that queries this workaround, remember that there's + * released Monza firmware that doesn't understand MC_CMD_WORKAROUND_BUG42008, + * and will hence (incorrectly) report that the bug doesn't exist. + */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG42008 0x20 +/* enum: Bug 26807 features present in firmware (multicast filter chaining) */ +#define MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 0x40 + + +/***********************************/ +/* MC_CMD_PRIVILEGE_MASK + * Read/set privileges of an arbitrary PCIe function + */ +#define MC_CMD_PRIVILEGE_MASK 0x5a + +#define MC_CMD_0x5a_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_PRIVILEGE_MASK_IN msgrequest */ +#define MC_CMD_PRIVILEGE_MASK_IN_LEN 8 +/* The target function to have its mask read or set e.g. PF 0 = 0xFFFF0000, VF + * 1,3 = 0x00030001 + */ +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_OFST 0 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_PF_LBN 0 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_PF_WIDTH 16 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_VF_LBN 16 +#define MC_CMD_PRIVILEGE_MASK_IN_FUNCTION_VF_WIDTH 16 +#define MC_CMD_PRIVILEGE_MASK_IN_VF_NULL 0xffff /* enum */ +/* New privilege mask to be set. The mask will only be changed if the MSB is + * set to 1. + */ +#define MC_CMD_PRIVILEGE_MASK_IN_NEW_MASK_OFST 4 +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_ADMIN 0x1 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_LINK 0x2 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_ONLOAD 0x4 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_PTP 0x8 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_INSECURE_FILTERS 0x10 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_MAC_SPOOFING 0x20 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_UNICAST 0x40 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_MULTICAST 0x80 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_BROADCAST 0x100 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_ALL_MULTICAST 0x200 /* enum */ +#define MC_CMD_PRIVILEGE_MASK_IN_GRP_PROMISCUOUS 0x400 /* enum */ +/* enum: Set this bit to indicate that a new privilege mask is to be set, + * otherwise the command will only read the existing mask. + */ +#define MC_CMD_PRIVILEGE_MASK_IN_DO_CHANGE 0x80000000 + +/* MC_CMD_PRIVILEGE_MASK_OUT msgresponse */ +#define MC_CMD_PRIVILEGE_MASK_OUT_LEN 4 +/* For an admin function, always all the privileges are reported. */ +#define MC_CMD_PRIVILEGE_MASK_OUT_OLD_MASK_OFST 0 + + +/***********************************/ +/* MC_CMD_LINK_STATE_MODE + * Read/set link state mode of a VF + */ +#define MC_CMD_LINK_STATE_MODE 0x5c + +#define MC_CMD_0x5c_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_LINK_STATE_MODE_IN msgrequest */ +#define MC_CMD_LINK_STATE_MODE_IN_LEN 8 +/* The target function to have its link state mode read or set, must be a VF + * e.g. VF 1,3 = 0x00030001 + */ +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_OFST 0 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_LBN 0 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_PF_WIDTH 16 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_LBN 16 +#define MC_CMD_LINK_STATE_MODE_IN_FUNCTION_VF_WIDTH 16 +/* New link state mode to be set */ +#define MC_CMD_LINK_STATE_MODE_IN_NEW_MODE_OFST 4 +#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_AUTO 0x0 /* enum */ +#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_UP 0x1 /* enum */ +#define MC_CMD_LINK_STATE_MODE_IN_LINK_STATE_DOWN 0x2 /* enum */ +/* enum: Use this value to just read the existing setting without modifying it. + */ +#define MC_CMD_LINK_STATE_MODE_IN_DO_NOT_CHANGE 0xffffffff + +/* MC_CMD_LINK_STATE_MODE_OUT msgresponse */ +#define MC_CMD_LINK_STATE_MODE_OUT_LEN 4 +#define MC_CMD_LINK_STATE_MODE_OUT_OLD_MODE_OFST 0 + + +/***********************************/ +/* MC_CMD_GET_SNAPSHOT_LENGTH + * Obtain the curent range of allowable values for the SNAPSHOT_LENGTH + * parameter to MC_CMD_INIT_RXQ. + */ +#define MC_CMD_GET_SNAPSHOT_LENGTH 0x101 + +#define MC_CMD_0x101_PRIVILEGE_CTG SRIOV_CTG_GENERAL + +/* MC_CMD_GET_SNAPSHOT_LENGTH_IN msgrequest */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_IN_LEN 0 + +/* MC_CMD_GET_SNAPSHOT_LENGTH_OUT msgresponse */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_OUT_LEN 8 +/* Minimum acceptable snapshot length. */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_OUT_RX_SNAPLEN_MIN_OFST 0 +/* Maximum acceptable snapshot length. */ +#define MC_CMD_GET_SNAPSHOT_LENGTH_OUT_RX_SNAPLEN_MAX_OFST 4 + + +/***********************************/ +/* MC_CMD_FUSE_DIAGS + * Additional fuse diagnostics + */ +#define MC_CMD_FUSE_DIAGS 0x102 + +#define MC_CMD_0x102_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_FUSE_DIAGS_IN msgrequest */ +#define MC_CMD_FUSE_DIAGS_IN_LEN 0 + +/* MC_CMD_FUSE_DIAGS_OUT msgresponse */ +#define MC_CMD_FUSE_DIAGS_OUT_LEN 48 +/* Total number of mismatched bits between pairs in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_MISMATCH_BITS_OFST 0 +/* Total number of unexpectedly clear (set in B but not A) bits in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_PAIR_A_BAD_BITS_OFST 4 +/* Total number of unexpectedly clear (set in A but not B) bits in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_PAIR_B_BAD_BITS_OFST 8 +/* Checksum of data after logical OR of pairs in area 0 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA0_CHECKSUM_OFST 12 +/* Total number of mismatched bits between pairs in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_MISMATCH_BITS_OFST 16 +/* Total number of unexpectedly clear (set in B but not A) bits in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_PAIR_A_BAD_BITS_OFST 20 +/* Total number of unexpectedly clear (set in A but not B) bits in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_PAIR_B_BAD_BITS_OFST 24 +/* Checksum of data after logical OR of pairs in area 1 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA1_CHECKSUM_OFST 28 +/* Total number of mismatched bits between pairs in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_MISMATCH_BITS_OFST 32 +/* Total number of unexpectedly clear (set in B but not A) bits in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_PAIR_A_BAD_BITS_OFST 36 +/* Total number of unexpectedly clear (set in A but not B) bits in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_PAIR_B_BAD_BITS_OFST 40 +/* Checksum of data after logical OR of pairs in area 2 */ +#define MC_CMD_FUSE_DIAGS_OUT_AREA2_CHECKSUM_OFST 44 + + +/***********************************/ +/* MC_CMD_PRIVILEGE_MODIFY + * Modify the privileges of a set of PCIe functions. Note that this operation + * only effects non-admin functions unless the admin privilege itself is + * included in one of the masks provided. + */ +#define MC_CMD_PRIVILEGE_MODIFY 0x60 + +#define MC_CMD_0x60_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_PRIVILEGE_MODIFY_IN msgrequest */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_LEN 16 +/* The groups of functions to have their privilege masks modified. */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_FN_GROUP_OFST 0 +#define MC_CMD_PRIVILEGE_MODIFY_IN_NONE 0x0 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_ALL 0x1 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_PFS_ONLY 0x2 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_VFS_ONLY 0x3 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_VFS_OF_PF 0x4 /* enum */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_ONE 0x5 /* enum */ +/* For VFS_OF_PF specify the PF, for ONE specify the target function */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_OFST 4 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_PF_LBN 0 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_PF_WIDTH 16 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_VF_LBN 16 +#define MC_CMD_PRIVILEGE_MODIFY_IN_FUNCTION_VF_WIDTH 16 +/* Privileges to be added to the target functions. For privilege definitions + * refer to the command MC_CMD_PRIVILEGE_MASK + */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_ADD_MASK_OFST 8 +/* Privileges to be removed from the target functions. For privilege + * definitions refer to the command MC_CMD_PRIVILEGE_MASK + */ +#define MC_CMD_PRIVILEGE_MODIFY_IN_REMOVE_MASK_OFST 12 + +/* MC_CMD_PRIVILEGE_MODIFY_OUT msgresponse */ +#define MC_CMD_PRIVILEGE_MODIFY_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_READ_BYTES + * Read XPM memory + */ +#define MC_CMD_XPM_READ_BYTES 0x103 + +#define MC_CMD_0x103_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_READ_BYTES_IN msgrequest */ +#define MC_CMD_XPM_READ_BYTES_IN_LEN 8 +/* Start address (byte) */ +#define MC_CMD_XPM_READ_BYTES_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_READ_BYTES_IN_COUNT_OFST 4 + +/* MC_CMD_XPM_READ_BYTES_OUT msgresponse */ +#define MC_CMD_XPM_READ_BYTES_OUT_LENMIN 0 +#define MC_CMD_XPM_READ_BYTES_OUT_LENMAX 252 +#define MC_CMD_XPM_READ_BYTES_OUT_LEN(num) (0+1*(num)) +/* Data */ +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_OFST 0 +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_LEN 1 +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_MINNUM 0 +#define MC_CMD_XPM_READ_BYTES_OUT_DATA_MAXNUM 252 + + +/***********************************/ +/* MC_CMD_XPM_WRITE_BYTES + * Write XPM memory + */ +#define MC_CMD_XPM_WRITE_BYTES 0x104 + +#define MC_CMD_0x104_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_WRITE_BYTES_IN msgrequest */ +#define MC_CMD_XPM_WRITE_BYTES_IN_LENMIN 8 +#define MC_CMD_XPM_WRITE_BYTES_IN_LENMAX 252 +#define MC_CMD_XPM_WRITE_BYTES_IN_LEN(num) (8+1*(num)) +/* Start address (byte) */ +#define MC_CMD_XPM_WRITE_BYTES_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_WRITE_BYTES_IN_COUNT_OFST 4 +/* Data */ +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_OFST 8 +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_LEN 1 +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_MINNUM 0 +#define MC_CMD_XPM_WRITE_BYTES_IN_DATA_MAXNUM 244 + +/* MC_CMD_XPM_WRITE_BYTES_OUT msgresponse */ +#define MC_CMD_XPM_WRITE_BYTES_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_READ_SECTOR + * Read XPM sector + */ +#define MC_CMD_XPM_READ_SECTOR 0x105 + +#define MC_CMD_0x105_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_READ_SECTOR_IN msgrequest */ +#define MC_CMD_XPM_READ_SECTOR_IN_LEN 8 +/* Sector index */ +#define MC_CMD_XPM_READ_SECTOR_IN_INDEX_OFST 0 +/* Sector size */ +#define MC_CMD_XPM_READ_SECTOR_IN_SIZE_OFST 4 + +/* MC_CMD_XPM_READ_SECTOR_OUT msgresponse */ +#define MC_CMD_XPM_READ_SECTOR_OUT_LENMIN 4 +#define MC_CMD_XPM_READ_SECTOR_OUT_LENMAX 36 +#define MC_CMD_XPM_READ_SECTOR_OUT_LEN(num) (4+1*(num)) +/* Sector type */ +#define MC_CMD_XPM_READ_SECTOR_OUT_TYPE_OFST 0 +#define MC_CMD_XPM_READ_SECTOR_OUT_BLANK 0x0 /* enum */ +#define MC_CMD_XPM_READ_SECTOR_OUT_CRYPTO_KEY_128 0x1 /* enum */ +#define MC_CMD_XPM_READ_SECTOR_OUT_CRYPTO_KEY_256 0x2 /* enum */ +#define MC_CMD_XPM_READ_SECTOR_OUT_INVALID 0xff /* enum */ +/* Sector data */ +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_OFST 4 +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_LEN 1 +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_MINNUM 0 +#define MC_CMD_XPM_READ_SECTOR_OUT_DATA_MAXNUM 32 + + +/***********************************/ +/* MC_CMD_XPM_WRITE_SECTOR + * Write XPM sector + */ +#define MC_CMD_XPM_WRITE_SECTOR 0x106 + +#define MC_CMD_0x106_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_WRITE_SECTOR_IN msgrequest */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_LENMIN 12 +#define MC_CMD_XPM_WRITE_SECTOR_IN_LENMAX 44 +#define MC_CMD_XPM_WRITE_SECTOR_IN_LEN(num) (12+1*(num)) +/* If writing fails due to an uncorrectable error, try up to RETRIES following + * sectors (or until no more space available). If 0, only one write attempt is + * made. Note that uncorrectable errors are unlikely, thanks to XPM self-repair + * mechanism. + */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_RETRIES_OFST 0 +#define MC_CMD_XPM_WRITE_SECTOR_IN_RETRIES_LEN 1 +#define MC_CMD_XPM_WRITE_SECTOR_IN_RESERVED_OFST 1 +#define MC_CMD_XPM_WRITE_SECTOR_IN_RESERVED_LEN 3 +/* Sector type */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_TYPE_OFST 4 +/* Enum values, see field(s): */ +/* MC_CMD_XPM_READ_SECTOR_OUT/TYPE */ +/* Sector size */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_SIZE_OFST 8 +/* Sector data */ +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_OFST 12 +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_LEN 1 +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_MINNUM 0 +#define MC_CMD_XPM_WRITE_SECTOR_IN_DATA_MAXNUM 32 + +/* MC_CMD_XPM_WRITE_SECTOR_OUT msgresponse */ +#define MC_CMD_XPM_WRITE_SECTOR_OUT_LEN 4 +/* New sector index */ +#define MC_CMD_XPM_WRITE_SECTOR_OUT_INDEX_OFST 0 + + +/***********************************/ +/* MC_CMD_XPM_INVALIDATE_SECTOR + * Invalidate XPM sector + */ +#define MC_CMD_XPM_INVALIDATE_SECTOR 0x107 + +#define MC_CMD_0x107_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_INVALIDATE_SECTOR_IN msgrequest */ +#define MC_CMD_XPM_INVALIDATE_SECTOR_IN_LEN 4 +/* Sector index */ +#define MC_CMD_XPM_INVALIDATE_SECTOR_IN_INDEX_OFST 0 + +/* MC_CMD_XPM_INVALIDATE_SECTOR_OUT msgresponse */ +#define MC_CMD_XPM_INVALIDATE_SECTOR_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_BLANK_CHECK + * Blank-check XPM memory and report bad locations + */ +#define MC_CMD_XPM_BLANK_CHECK 0x108 + +#define MC_CMD_0x108_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_BLANK_CHECK_IN msgrequest */ +#define MC_CMD_XPM_BLANK_CHECK_IN_LEN 8 +/* Start address (byte) */ +#define MC_CMD_XPM_BLANK_CHECK_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_BLANK_CHECK_IN_COUNT_OFST 4 + +/* MC_CMD_XPM_BLANK_CHECK_OUT msgresponse */ +#define MC_CMD_XPM_BLANK_CHECK_OUT_LENMIN 4 +#define MC_CMD_XPM_BLANK_CHECK_OUT_LENMAX 252 +#define MC_CMD_XPM_BLANK_CHECK_OUT_LEN(num) (4+2*(num)) +/* Total number of bad (non-blank) locations */ +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_COUNT_OFST 0 +/* Addresses of bad locations (may be less than BAD_COUNT, if all cannot fit + * into MCDI response) + */ +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_OFST 4 +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_LEN 2 +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_MINNUM 0 +#define MC_CMD_XPM_BLANK_CHECK_OUT_BAD_ADDR_MAXNUM 124 + + +/***********************************/ +/* MC_CMD_XPM_REPAIR + * Blank-check and repair XPM memory + */ +#define MC_CMD_XPM_REPAIR 0x109 + +#define MC_CMD_0x109_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_REPAIR_IN msgrequest */ +#define MC_CMD_XPM_REPAIR_IN_LEN 8 +/* Start address (byte) */ +#define MC_CMD_XPM_REPAIR_IN_ADDR_OFST 0 +/* Count (bytes) */ +#define MC_CMD_XPM_REPAIR_IN_COUNT_OFST 4 + +/* MC_CMD_XPM_REPAIR_OUT msgresponse */ +#define MC_CMD_XPM_REPAIR_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_DECODER_TEST + * Test XPM memory address decoders for gross manufacturing defects. Can only + * be performed on an unprogrammed part. + */ +#define MC_CMD_XPM_DECODER_TEST 0x10a + +#define MC_CMD_0x10a_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_DECODER_TEST_IN msgrequest */ +#define MC_CMD_XPM_DECODER_TEST_IN_LEN 0 + +/* MC_CMD_XPM_DECODER_TEST_OUT msgresponse */ +#define MC_CMD_XPM_DECODER_TEST_OUT_LEN 0 + + +/***********************************/ +/* MC_CMD_XPM_WRITE_TEST + * XPM memory write test. Test XPM write logic for gross manufacturing defects + * by writing to a dedicated test row. There are 16 locations in the test row + * and the test can only be performed on locations that have not been + * previously used (i.e. can be run at most 16 times). The test will pick the + * first available location to use, or fail with ENOSPC if none left. + */ +#define MC_CMD_XPM_WRITE_TEST 0x10b + +#define MC_CMD_0x10b_PRIVILEGE_CTG SRIOV_CTG_ADMIN + +/* MC_CMD_XPM_WRITE_TEST_IN msgrequest */ +#define MC_CMD_XPM_WRITE_TEST_IN_LEN 0 + +/* MC_CMD_XPM_WRITE_TEST_OUT msgresponse */ +#define MC_CMD_XPM_WRITE_TEST_OUT_LEN 0 + + #endif /* MCDI_PCOL_H */ -- GitLab From 46e612b0fcefb7a3381933135f386523dedb4159 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:09:18 +0100 Subject: [PATCH 1442/7006] sfc: enable cascaded multicast filters in MCFW After creating event queue 0, check to see if the workaround is enabled, and enable it if necessary. This will be called during PCI probe and also when coming back up after a reset. The nic_data->workaround_26807 will be used in the future to control the filter insertion behaviour based on this workaround. Only the primary PF can enable this workaround, so tolerate an EPERM error and continue. Otherwise, if any step in the checking and enabling of the workaround fails, the event queue must be removed. We check that workaround is implemented before trying to enable it, and store the current workaround setting before trying to change it. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 63 +++++++++++++++++++++++---------- drivers/net/ethernet/sfc/nic.h | 2 ++ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 605cc89485946..119301769ddab 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2197,6 +2197,29 @@ static int efx_ef10_ev_probe(struct efx_channel *channel) GFP_KERNEL); } +static void efx_ef10_ev_fini(struct efx_channel *channel) +{ + MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_EVQ_IN_LEN); + MCDI_DECLARE_BUF_ERR(outbuf); + struct efx_nic *efx = channel->efx; + size_t outlen; + int rc; + + MCDI_SET_DWORD(inbuf, FINI_EVQ_IN_INSTANCE, channel->channel); + + rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + + if (rc && rc != -EALREADY) + goto fail; + + return; + +fail: + efx_mcdi_display_error(efx, MC_CMD_FINI_EVQ, MC_CMD_FINI_EVQ_IN_LEN, + outbuf, outlen, rc); +} + static int efx_ef10_ev_init(struct efx_channel *channel) { MCDI_DECLARE_BUF(inbuf, @@ -2208,6 +2231,7 @@ static int efx_ef10_ev_init(struct efx_channel *channel) struct efx_ef10_nic_data *nic_data; bool supports_rx_merge; size_t inlen, outlen; + unsigned int enabled, implemented; dma_addr_t dma_addr; int rc; int i; @@ -2248,30 +2272,33 @@ static int efx_ef10_ev_init(struct efx_channel *channel) rc = efx_mcdi_rpc(efx, MC_CMD_INIT_EVQ, inbuf, inlen, outbuf, sizeof(outbuf), &outlen); /* IRQ return is ignored */ - return rc; -} - -static void efx_ef10_ev_fini(struct efx_channel *channel) -{ - MCDI_DECLARE_BUF(inbuf, MC_CMD_FINI_EVQ_IN_LEN); - MCDI_DECLARE_BUF_ERR(outbuf); - struct efx_nic *efx = channel->efx; - size_t outlen; - int rc; + if (channel->channel || rc) + return rc; - MCDI_SET_DWORD(inbuf, FINI_EVQ_IN_INSTANCE, channel->channel); + /* Successfully created event queue on channel 0 */ + rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled); + if (rc) + goto fail; - rc = efx_mcdi_rpc_quiet(efx, MC_CMD_FINI_EVQ, inbuf, sizeof(inbuf), - outbuf, sizeof(outbuf), &outlen); + nic_data->workaround_26807 = + !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); - if (rc && rc != -EALREADY) - goto fail; + if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && + !nic_data->workaround_26807) { + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, + true); + if (!rc) + nic_data->workaround_26807 = true; + else if (rc == -EPERM) + rc = 0; + } - return; + if (!rc) + return 0; fail: - efx_mcdi_display_error(efx, MC_CMD_FINI_EVQ, MC_CMD_FINI_EVQ_IN_LEN, - outbuf, outlen, rc); + efx_ef10_ev_fini(channel); + return rc; } static void efx_ef10_ev_remove(struct efx_channel *channel) diff --git a/drivers/net/ethernet/sfc/nic.h b/drivers/net/ethernet/sfc/nic.h index 31ff9084d9a46..0b536e27d3b22 100644 --- a/drivers/net/ethernet/sfc/nic.h +++ b/drivers/net/ethernet/sfc/nic.h @@ -506,6 +506,7 @@ enum { * @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared * @stats: Hardware statistics * @workaround_35388: Flag: firmware supports workaround for bug 35388 + * @workaround_26807: Flag: firmware supports workaround for bug 26807 * @must_check_datapath_caps: Flag: @datapath_caps needs to be revalidated * after MC reboot * @datapath_caps: Capabilities of datapath firmware (FLAGS1 field of @@ -535,6 +536,7 @@ struct efx_ef10_nic_data { bool rx_rss_context_exclusive; u64 stats[EF10_STAT_COUNT]; bool workaround_35388; + bool workaround_26807; bool must_check_datapath_caps; u32 datapath_caps; unsigned int rx_dpcpu_fw_id; -- GitLab From 832dc9ed43da8eb2033d90b46c1041e1d6947907 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 21 Jul 2015 15:09:31 +0100 Subject: [PATCH 1443/7006] sfc: cope with ENOSYS from efx_mcdi_get_workarounds() GET_WORKAROUNDS was only introduced in May 2014, not all firmware will have it. So call sites need to handle ENOSYS. In this case we're probing the bug26807 workaround, which is not implemented in any firmware that doesn't have GET_WORKAROUNDS. So interpret ENOSYS as 'false'. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 33 ++++++++++++++++++++------------- drivers/net/ethernet/sfc/mcdi.c | 6 +++++- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 119301769ddab..44071176859d1 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2277,20 +2277,27 @@ static int efx_ef10_ev_init(struct efx_channel *channel) /* Successfully created event queue on channel 0 */ rc = efx_mcdi_get_workarounds(efx, &implemented, &enabled); - if (rc) + if (rc == -ENOSYS) { + /* GET_WORKAROUNDS was implemented before the bug26807 + * workaround, thus the latter must be unavailable in this fw + */ + nic_data->workaround_26807 = false; + rc = 0; + } else if (rc) { goto fail; - - nic_data->workaround_26807 = - !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); - - if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && - !nic_data->workaround_26807) { - rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, - true); - if (!rc) - nic_data->workaround_26807 = true; - else if (rc == -EPERM) - rc = 0; + } else { + nic_data->workaround_26807 = + !!(enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807); + + if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && + !nic_data->workaround_26807) { + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, + true); + if (!rc) + nic_data->workaround_26807 = true; + else if (rc == -EPERM) + rc = 0; + } } if (!rc) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 81640f8bb811b..58232e78feaae 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1816,7 +1816,11 @@ int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, return 0; fail: - netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); + /* Older firmware lacks GET_WORKAROUNDS and this isn't especially + * terrifying. The call site will have to deal with it though. + */ + netif_printk(efx, hw, rc == -ENOSYS ? KERN_DEBUG : KERN_ERR, + efx->net_dev, "%s: failed rc=%d\n", __func__, rc); return rc; } -- GitLab From 34ccfe6f8abd9ce7ea70e68f130cc6618737269f Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:09:43 +0100 Subject: [PATCH 1444/7006] sfc: add output flag decoding to efx_mcdi_set_workaround The initial use of this will be to check a flag reporting if an FLR was performed on other functions when enabling cascaded multicast filters. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 7 ++++--- drivers/net/ethernet/sfc/mcdi.c | 22 +++++++++++++++++++--- drivers/net/ethernet/sfc/mcdi.h | 3 ++- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 44071176859d1..2b93f63a04218 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -387,7 +387,7 @@ static int efx_ef10_probe(struct efx_nic *efx) * First try to enable it, then if we get EPERM, just * ask if it's already enabled */ - rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG35388, true); + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG35388, true, NULL); if (rc == 0) { nic_data->workaround_35388 = true; } else if (rc == -EPERM) { @@ -2291,8 +2291,9 @@ static int efx_ef10_ev_init(struct efx_channel *channel) if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && !nic_data->workaround_26807) { - rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, - true); + rc = efx_mcdi_set_workaround(efx, + MC_CMD_WORKAROUND_BUG26807, + true, NULL); if (!rc) nic_data->workaround_26807 = true; else if (rc == -EPERM) diff --git a/drivers/net/ethernet/sfc/mcdi.c b/drivers/net/ethernet/sfc/mcdi.c index 58232e78feaae..98d172b04f718 100644 --- a/drivers/net/ethernet/sfc/mcdi.c +++ b/drivers/net/ethernet/sfc/mcdi.c @@ -1779,15 +1779,31 @@ int efx_mcdi_wol_filter_reset(struct efx_nic *efx) return rc; } -int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled) +int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled, + unsigned int *flags) { MCDI_DECLARE_BUF(inbuf, MC_CMD_WORKAROUND_IN_LEN); + MCDI_DECLARE_BUF(outbuf, MC_CMD_WORKAROUND_EXT_OUT_LEN); + size_t outlen; + int rc; BUILD_BUG_ON(MC_CMD_WORKAROUND_OUT_LEN != 0); MCDI_SET_DWORD(inbuf, WORKAROUND_IN_TYPE, type); MCDI_SET_DWORD(inbuf, WORKAROUND_IN_ENABLED, enabled); - return efx_mcdi_rpc(efx, MC_CMD_WORKAROUND, inbuf, sizeof(inbuf), - NULL, 0, NULL); + rc = efx_mcdi_rpc(efx, MC_CMD_WORKAROUND, inbuf, sizeof(inbuf), + outbuf, sizeof(outbuf), &outlen); + if (rc) + return rc; + + if (!flags) + return 0; + + if (outlen >= MC_CMD_WORKAROUND_EXT_OUT_LEN) + *flags = MCDI_DWORD(outbuf, WORKAROUND_EXT_OUT_FLAGS); + else + *flags = 0; + + return 0; } int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, diff --git a/drivers/net/ethernet/sfc/mcdi.h b/drivers/net/ethernet/sfc/mcdi.h index 1838afe2da920..025d504c472b5 100644 --- a/drivers/net/ethernet/sfc/mcdi.h +++ b/drivers/net/ethernet/sfc/mcdi.h @@ -346,7 +346,8 @@ void efx_mcdi_mac_pull_stats(struct efx_nic *efx); bool efx_mcdi_mac_check_fault(struct efx_nic *efx); enum reset_type efx_mcdi_map_reset_reason(enum reset_type reason); int efx_mcdi_reset(struct efx_nic *efx, enum reset_type method); -int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled); +int efx_mcdi_set_workaround(struct efx_nic *efx, u32 type, bool enabled, + unsigned int *flags); int efx_mcdi_get_workarounds(struct efx_nic *efx, unsigned int *impl_out, unsigned int *enabled_out); -- GitLab From 5a55a72abe48e5d6c0ec86e7b06cd73ab7d517c8 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:10:02 +0100 Subject: [PATCH 1445/7006] sfc: warn if other functions have been reset by MCFW When enabling the workaround for cascaded multicast filters, the MC can reset other functions if they have already inserted filters. In that case, the workaround has been enabled, but print an info message in the log recording that other functions had to be reset. As other functions were reset, the MC will have incremented its boot count, so also increment the warm_boot_count on the function which enabled the workaround, as that function won't have received an MC reboot event and does not need to reset. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 2b93f63a04218..18d6388fb5da8 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -2291,13 +2291,24 @@ static int efx_ef10_ev_init(struct efx_channel *channel) if (implemented & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807 && !nic_data->workaround_26807) { + unsigned int flags; + rc = efx_mcdi_set_workaround(efx, MC_CMD_WORKAROUND_BUG26807, - true, NULL); - if (!rc) + true, &flags); + + if (!rc) { + if (flags & + 1 << MC_CMD_WORKAROUND_EXT_OUT_FLR_DONE_LBN) { + netif_info(efx, drv, efx->net_dev, + "other functions on NIC have been reset\n"); + /* MC's boot count has incremented */ + ++nic_data->warm_boot_count; + } nic_data->workaround_26807 = true; - else if (rc == -EPERM) + } else if (rc == -EPERM) { rc = 0; + } } } -- GitLab From b6f568e27b6b214beaa0d57ddb4fcc446fcd5555 Mon Sep 17 00:00:00 2001 From: Jon Cooper Date: Tue, 21 Jul 2015 15:10:15 +0100 Subject: [PATCH 1446/7006] sfc: Insert multicast filters as well as mismatch filters in promiscuous mode If a function is in promiscuous mode and another function has a broadcast or multicast filter inserted, the function in promiscuous mode won't see that broadcast or multicast traffic. Most notably this breaks broadcast, which means ARP doesn't work. Less show-stoppingly, a function listening on a multicast address that's also in promiscuous mode will not see that multicast traffic if another function is also listening on that multicast address. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 104 ++++++++++++++++---------------- 1 file changed, 53 insertions(+), 51 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 18d6388fb5da8..784b46fb039a3 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3758,7 +3758,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) struct netdev_hw_addr *uc; struct netdev_hw_addr *mc; unsigned int filter_idx; - int i, n, rc; + int i, rc; + bool uc_promisc = false, mc_promisc = false; if (!efx_dev_registered(efx)) return; @@ -3768,13 +3769,11 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) /* Mark old filters that may need to be removed */ spin_lock_bh(&efx->filter_lock); - n = table->dev_uc_count < 0 ? 1 : table->dev_uc_count; - for (i = 0; i < n; i++) { + for (i = 0; i < table->dev_uc_count; i++) { filter_idx = table->dev_uc_list[i].id % HUNT_FILTER_TBL_ROWS; table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; } - n = table->dev_mc_count < 0 ? 1 : table->dev_mc_count; - for (i = 0; i < n; i++) { + for (i = 0; i < table->dev_mc_count; i++) { filter_idx = table->dev_mc_list[i].id % HUNT_FILTER_TBL_ROWS; table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; } @@ -3786,7 +3785,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) netif_addr_lock_bh(net_dev); if (net_dev->flags & IFF_PROMISC || netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { - table->dev_uc_count = -1; + table->dev_uc_count = 0; + uc_promisc = true; } else { table->dev_uc_count = 1 + netdev_uc_count(net_dev); ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); @@ -3796,9 +3796,11 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) i++; } } - if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI) || - netdev_mc_count(net_dev) >= EFX_EF10_FILTER_DEV_MC_MAX) { - table->dev_mc_count = -1; + if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ + >= EFX_EF10_FILTER_DEV_MC_MAX) { + table->dev_mc_count = 1; + eth_broadcast_addr(table->dev_mc_list[0].addr); + mc_promisc = true; } else { table->dev_mc_count = 1 + netdev_mc_count(net_dev); eth_broadcast_addr(table->dev_mc_list[0].addr); @@ -3807,31 +3809,32 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); i++; } + if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) + mc_promisc = true; } netif_addr_unlock_bh(net_dev); /* Insert/renew unicast filters */ - if (table->dev_uc_count >= 0) { - for (i = 0; i < table->dev_uc_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_uc_list[i].addr); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - /* Fall back to unicast-promisc */ - while (i--) - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - table->dev_uc_list[i].id); - table->dev_uc_count = -1; - break; - } - table->dev_uc_list[i].id = rc; + for (i = 0; i < table->dev_uc_count; i++) { + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, + table->dev_uc_list[i].addr); + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + /* Fall back to unicast-promisc */ + while (i--) + efx_ef10_filter_remove_safe( + efx, EFX_FILTER_PRI_AUTO, + table->dev_uc_list[i].id); + table->dev_uc_count = 0; + uc_promisc = true; + break; } + table->dev_uc_list[i].id = rc; } - if (table->dev_uc_count < 0) { + if (uc_promisc) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); @@ -3839,34 +3842,34 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { WARN_ON(1); - table->dev_uc_count = 0; } else { - table->dev_uc_list[0].id = rc; + table->dev_uc_list[table->dev_uc_count++].id = rc; } } /* Insert/renew multicast filters */ - if (table->dev_mc_count >= 0) { - for (i = 0; i < table->dev_mc_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_mc_list[i].addr); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - /* Fall back to multicast-promisc */ - while (i--) - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - table->dev_mc_list[i].id); - table->dev_mc_count = -1; - break; - } - table->dev_mc_list[i].id = rc; + for (i = 0; i < table->dev_mc_count; i++) { + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, + table->dev_mc_list[i].addr); + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + /* Fall back to multicast-promisc. + * Leave the broadcast filter. + */ + while (i > 1) + efx_ef10_filter_remove_safe( + efx, EFX_FILTER_PRI_AUTO, + table->dev_mc_list[--i].id); + table->dev_mc_count = i; + mc_promisc = true; + break; } + table->dev_mc_list[i].id = rc; } - if (table->dev_mc_count < 0) { + if (mc_promisc) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); @@ -3874,9 +3877,8 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { WARN_ON(1); - table->dev_mc_count = 0; } else { - table->dev_mc_list[0].id = rc; + table->dev_mc_list[table->dev_mc_count++].id = rc; } } -- GitLab From 822b96f87f1b47ac0c73417284879ef610500173 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:10:27 +0100 Subject: [PATCH 1447/7006] sfc: re-factor efx_ef10_filter_sync_rx_mode() This change is only re-factoring; there are no changes to functionality except for a slight elaboration of an error message (on mismatch filter insertion failure). Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 217 ++++++++++++++++++-------------- 1 file changed, 126 insertions(+), 91 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 784b46fb039a3..1704f71c72500 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -49,6 +49,11 @@ enum { */ #define HUNT_FILTER_TBL_ROWS 8192 +struct efx_ef10_dev_addr { + u8 addr[ETH_ALEN]; + u16 id; +}; + struct efx_ef10_filter_table { /* The RX match field masks supported by this fw & hw, in order of priority */ enum efx_filter_match_flags rx_match_flags[ @@ -69,11 +74,8 @@ struct efx_ef10_filter_table { /* Shadow of net_device address lists, guarded by mac_lock */ #define EFX_EF10_FILTER_DEV_UC_MAX 32 #define EFX_EF10_FILTER_DEV_MC_MAX 256 - struct { - u8 addr[ETH_ALEN]; - u16 id; - } dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX], - dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX]; + struct efx_ef10_dev_addr dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX]; + struct efx_ef10_dev_addr dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX]; int dev_uc_count; /* negative for PROMISC */ int dev_mc_count; /* negative for PROMISC/ALLMULTI */ }; @@ -3746,23 +3748,10 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx) kfree(table); } -/* Caller must hold efx->filter_sem for read if race against - * efx_ef10_filter_table_remove() is possible - */ -static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) +static void efx_ef10_filter_mark_old(struct efx_nic *efx) { struct efx_ef10_filter_table *table = efx->filter_state; - struct net_device *net_dev = efx->net_dev; - struct efx_filter_spec spec; - bool remove_failed = false; - struct netdev_hw_addr *uc; - struct netdev_hw_addr *mc; - unsigned int filter_idx; - int i, rc; - bool uc_promisc = false, mc_promisc = false; - - if (!efx_dev_registered(efx)) - return; + unsigned int filter_idx, i; if (!table) return; @@ -3778,29 +3767,40 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; } spin_unlock_bh(&efx->filter_lock); +} + +static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct net_device *net_dev = efx->net_dev; + struct netdev_hw_addr *uc; + unsigned int i; - /* Copy/convert the address lists; add the primary station - * address and broadcast address - */ - netif_addr_lock_bh(net_dev); if (net_dev->flags & IFF_PROMISC || netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { - table->dev_uc_count = 0; - uc_promisc = true; - } else { - table->dev_uc_count = 1 + netdev_uc_count(net_dev); - ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); - i = 1; - netdev_for_each_uc_addr(uc, net_dev) { - ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); - i++; - } + *promisc = true; } + table->dev_uc_count = 1 + netdev_uc_count(net_dev); + ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); + i = 1; + netdev_for_each_uc_addr(uc, net_dev) { + ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); + i++; + } +} + +static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct net_device *net_dev = efx->net_dev; + struct netdev_hw_addr *mc; + unsigned int i; + if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ - >= EFX_EF10_FILTER_DEV_MC_MAX) { + >= EFX_EF10_FILTER_DEV_MC_MAX) { table->dev_mc_count = 1; eth_broadcast_addr(table->dev_mc_list[0].addr); - mc_promisc = true; + *promisc = true; } else { table->dev_mc_count = 1 + netdev_mc_count(net_dev); eth_broadcast_addr(table->dev_mc_list[0].addr); @@ -3809,84 +3809,87 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); i++; } + if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) - mc_promisc = true; + *promisc = true; } - netif_addr_unlock_bh(net_dev); +} - /* Insert/renew unicast filters */ - for (i = 0; i < table->dev_uc_count; i++) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_uc_list[i].addr); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - /* Fall back to unicast-promisc */ - while (i--) - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - table->dev_uc_list[i].id); - table->dev_uc_count = 0; - uc_promisc = true; - break; - } - table->dev_uc_list[i].id = rc; - } - if (uc_promisc) { - efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, - EFX_FILTER_FLAG_RX_RSS, - 0); - efx_filter_set_uc_def(&spec); - rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - WARN_ON(1); - } else { - table->dev_uc_list[table->dev_uc_count++].id = rc; - } +static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, + bool multicast, bool *promisc) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_dev_addr *addr_list; + struct efx_filter_spec spec; + int *addr_count; + unsigned int i; + int rc; + + if (multicast) { + addr_list = table->dev_mc_list; + addr_count = &table->dev_mc_count; + } else { + addr_list = table->dev_uc_list; + addr_count = &table->dev_uc_count; } - /* Insert/renew multicast filters */ - for (i = 0; i < table->dev_mc_count; i++) { + /* Insert/renew filters */ + for (i = 0; i < *addr_count; i++) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, - table->dev_mc_list[i].addr); + addr_list[i].addr); rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { - /* Fall back to multicast-promisc. - * Leave the broadcast filter. + /* Fall back to promiscuous, but leave the broadcast + * filter for multicast */ - while (i > 1) + while (i--) { + if (multicast && i == 1) + break; + efx_ef10_filter_remove_safe( efx, EFX_FILTER_PRI_AUTO, - table->dev_mc_list[--i].id); - table->dev_mc_count = i; - mc_promisc = true; + addr_list[i].id); + } + *addr_count = i; + *promisc = true; break; } - table->dev_mc_list[i].id = rc; + addr_list[i].id = rc; } - if (mc_promisc) { + + if (*promisc) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); - efx_filter_set_mc_def(&spec); + + if (multicast) + efx_filter_set_mc_def(&spec); + else + efx_filter_set_uc_def(&spec); + rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) { - WARN_ON(1); - } else { - table->dev_mc_list[table->dev_mc_count++].id = rc; - } + if (rc < 0) + netif_warn(efx, drv, efx->net_dev, + "%scast mismatch filter insert failed.", + multicast ? "Multi" : "Uni"); + else + addr_list[(*addr_count)++].id = rc; } +} + +/* Remove filters that weren't renewed. Since nothing else changes the AUTO_OLD + * flag or removes these filters, we don't need to hold the filter_lock while + * scanning for these filters. + */ +static void efx_ef10_filter_remove_old(struct efx_nic *efx) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + bool remove_failed = false; + int i; - /* Remove filters that weren't renewed. Since nothing else - * changes the AUTO_OLD flag or removes these filters, we - * don't need to hold the filter_lock while scanning for - * these filters. - */ for (i = 0; i < HUNT_FILTER_TBL_ROWS; i++) { if (ACCESS_ONCE(table->entry[i].spec) & EFX_EF10_FILTER_FLAG_AUTO_OLD) { @@ -3965,6 +3968,38 @@ reset_nic: return rc ? rc : rc2; } +/* Caller must hold efx->filter_sem for read if race against + * efx_ef10_filter_table_remove() is possible + */ +static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct net_device *net_dev = efx->net_dev; + bool uc_promisc = false, mc_promisc = false; + + if (!efx_dev_registered(efx)) + return; + + if (!table) + return; + + efx_ef10_filter_mark_old(efx); + + /* Copy/convert the address lists; add the primary station + * address and broadcast address + */ + netif_addr_lock_bh(net_dev); + efx_ef10_filter_uc_addr_list(efx, &uc_promisc); + efx_ef10_filter_mc_addr_list(efx, &mc_promisc); + netif_addr_unlock_bh(net_dev); + + /* Insert/renew filters */ + efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); + efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); + + efx_ef10_filter_remove_old(efx); +} + static int efx_ef10_set_mac_address(struct efx_nic *efx) { MCDI_DECLARE_BUF(inbuf, MC_CMD_VADAPTOR_SET_MAC_IN_LEN); -- GitLab From ab8b1f7cf83a3016dcdeae874a469e2c8894fcd9 Mon Sep 17 00:00:00 2001 From: Daniel Pieczko Date: Tue, 21 Jul 2015 15:10:44 +0100 Subject: [PATCH 1448/7006] sfc: support cascaded multicast filters If the workaround to support cascaded multicast filters ("workaround_26807") is enabled, the broadcast filter and individual multicast filters are not inserted when in promiscuous or allmulti mode. There is a race while inserting and removing filters when entering and leaving promiscuous mode. When changing promiscuous state with cascaded multicast filters, the old multicast filters are removed before inserting the new filters to avoid duplicating packets; this can lead to dropped packets until all filters have been inserted. The efx_nic:mc_promisc flag is added to record the presence of a multicast promiscuous filter; this gives a simple way to tell if the promiscuous state is changing. Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 56 ++++++++++++++++++++------- drivers/net/ethernet/sfc/net_driver.h | 2 + 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 1704f71c72500..0a7cf432adf35 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -3792,26 +3792,42 @@ static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) { struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; struct netdev_hw_addr *mc; - unsigned int i; + unsigned int i, addr_count; - if (netdev_mc_count(net_dev) + 2 /* room for broadcast and promisc */ - >= EFX_EF10_FILTER_DEV_MC_MAX) { - table->dev_mc_count = 1; - eth_broadcast_addr(table->dev_mc_list[0].addr); + if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) *promisc = true; + + if (nic_data->workaround_26807) { + if (*promisc) { + table->dev_mc_count = 0; + return; + } + addr_count = netdev_mc_count(net_dev); } else { - table->dev_mc_count = 1 + netdev_mc_count(net_dev); - eth_broadcast_addr(table->dev_mc_list[0].addr); - i = 1; - netdev_for_each_mc_addr(mc, net_dev) { - ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); - i++; + /* Allow room for broadcast and promiscuous */ + addr_count = netdev_mc_count(net_dev) + 2; + } + + if (addr_count >= EFX_EF10_FILTER_DEV_MC_MAX) { + if (nic_data->workaround_26807) { + table->dev_mc_count = 0; + } else { + table->dev_mc_count = 1; + eth_broadcast_addr(table->dev_mc_list[0].addr); } + *promisc = true; + return; + } - if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) - *promisc = true; + table->dev_mc_count = 1 + netdev_mc_count(net_dev); + eth_broadcast_addr(table->dev_mc_list[0].addr); + i = 1; + netdev_for_each_mc_addr(mc, net_dev) { + ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); + i++; } } @@ -3846,7 +3862,11 @@ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, * filter for multicast */ while (i--) { - if (multicast && i == 1) + struct efx_ef10_nic_data *nic_data = + efx->nic_data; + + if (multicast && i == 1 && + !nic_data->workaround_26807) break; efx_ef10_filter_remove_safe( @@ -3974,6 +3994,7 @@ reset_nic: static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) { struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; bool uc_promisc = false, mc_promisc = false; @@ -3995,9 +4016,16 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) /* Insert/renew filters */ efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); + + /* If changing promiscuous state with cascaded multicast filters, remove + * old filters first, so that packets are dropped rather than duplicated + */ + if (nic_data->workaround_26807 && efx->mc_promisc != mc_promisc) + efx_ef10_filter_remove_old(efx); efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); efx_ef10_filter_remove_old(efx); + efx->mc_promisc = mc_promisc; } static int efx_ef10_set_mac_address(struct efx_nic *efx) diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 47d1e3a965226..4d35313a239db 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -925,6 +925,7 @@ struct vfdi_status; * @stats_lock: Statistics update lock. Must be held when calling * efx_nic_type::{update,start,stop}_stats. * @n_rx_noskb_drops: Count of RX packets dropped due to failure to allocate an skb + * @mc_promisc: Whether in multicast promiscuous mode when last changed * * This is stored in the private area of the &struct net_device. */ @@ -1072,6 +1073,7 @@ struct efx_nic { int last_irq_cpu; spinlock_t stats_lock; atomic_t n_rx_noskb_drops; + bool mc_promisc; }; static inline int efx_dev_registered(struct efx_nic *efx) -- GitLab From 12fb0da45c9a077dd76d9848f791fbdd4b8d4050 Mon Sep 17 00:00:00 2001 From: Edward Cree Date: Tue, 21 Jul 2015 15:11:00 +0100 Subject: [PATCH 1449/7006] sfc: clean fallbacks between promisc/normal in efx_ef10_filter_sync_rx_mode Separate functions for inserting individual and promisc filters; explicit fallback logic in efx_ef10_filter_sync_rx_mode(), in order not to overload the 'promisc' flag as also meaning "fall back to promisc". Signed-off-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 288 +++++++++++++++++++++++--------- 1 file changed, 208 insertions(+), 80 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 0a7cf432adf35..8505d82290cb3 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -49,6 +49,7 @@ enum { */ #define HUNT_FILTER_TBL_ROWS 8192 +#define EFX_EF10_FILTER_ID_INVALID 0xffff struct efx_ef10_dev_addr { u8 addr[ETH_ALEN]; u16 id; @@ -76,8 +77,12 @@ struct efx_ef10_filter_table { #define EFX_EF10_FILTER_DEV_MC_MAX 256 struct efx_ef10_dev_addr dev_uc_list[EFX_EF10_FILTER_DEV_UC_MAX]; struct efx_ef10_dev_addr dev_mc_list[EFX_EF10_FILTER_DEV_MC_MAX]; - int dev_uc_count; /* negative for PROMISC */ - int dev_mc_count; /* negative for PROMISC/ALLMULTI */ + int dev_uc_count; + int dev_mc_count; +/* Indices (like efx_ef10_dev_addr.id) for promisc/allmulti filters */ + u16 ucdef_id; + u16 bcast_id; + u16 mcdef_id; }; /* An arbitrary search limit for the software hash table */ @@ -3273,6 +3278,19 @@ static int efx_ef10_filter_remove_safe(struct efx_nic *efx, filter_id, false); } +static u32 efx_ef10_filter_get_unsafe_id(struct efx_nic *efx, u32 filter_id) +{ + return filter_id % HUNT_FILTER_TBL_ROWS; +} + +static int efx_ef10_filter_remove_unsafe(struct efx_nic *efx, + enum efx_filter_priority priority, + u32 filter_id) +{ + return efx_ef10_filter_remove_internal(efx, 1U << priority, + filter_id, true); +} + static int efx_ef10_filter_get_safe(struct efx_nic *efx, enum efx_filter_priority priority, u32 filter_id, struct efx_filter_spec *spec) @@ -3646,6 +3664,10 @@ static int efx_ef10_filter_table_probe(struct efx_nic *efx) goto fail; } + table->ucdef_id = EFX_EF10_FILTER_ID_INVALID; + table->bcast_id = EFX_EF10_FILTER_ID_INVALID; + table->mcdef_id = EFX_EF10_FILTER_ID_INVALID; + efx->filter_state = table; init_waitqueue_head(&table->waitq); return 0; @@ -3748,6 +3770,12 @@ static void efx_ef10_filter_table_remove(struct efx_nic *efx) kfree(table); } +#define EFX_EF10_FILTER_DO_MARK_OLD(id) \ + if (id != EFX_EF10_FILTER_ID_INVALID) { \ + filter_idx = efx_ef10_filter_get_unsafe_id(efx, id); \ + WARN_ON(!table->entry[filter_idx].spec); \ + table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; \ + } static void efx_ef10_filter_mark_old(struct efx_nic *efx) { struct efx_ef10_filter_table *table = efx->filter_state; @@ -3758,33 +3786,39 @@ static void efx_ef10_filter_mark_old(struct efx_nic *efx) /* Mark old filters that may need to be removed */ spin_lock_bh(&efx->filter_lock); - for (i = 0; i < table->dev_uc_count; i++) { - filter_idx = table->dev_uc_list[i].id % HUNT_FILTER_TBL_ROWS; - table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; - } - for (i = 0; i < table->dev_mc_count; i++) { - filter_idx = table->dev_mc_list[i].id % HUNT_FILTER_TBL_ROWS; - table->entry[filter_idx].spec |= EFX_EF10_FILTER_FLAG_AUTO_OLD; - } + for (i = 0; i < table->dev_uc_count; i++) + EFX_EF10_FILTER_DO_MARK_OLD(table->dev_uc_list[i].id); + for (i = 0; i < table->dev_mc_count; i++) + EFX_EF10_FILTER_DO_MARK_OLD(table->dev_mc_list[i].id); + EFX_EF10_FILTER_DO_MARK_OLD(table->ucdef_id); + EFX_EF10_FILTER_DO_MARK_OLD(table->bcast_id); + EFX_EF10_FILTER_DO_MARK_OLD(table->mcdef_id); spin_unlock_bh(&efx->filter_lock); } +#undef EFX_EF10_FILTER_DO_MARK_OLD static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) { struct efx_ef10_filter_table *table = efx->filter_state; struct net_device *net_dev = efx->net_dev; struct netdev_hw_addr *uc; + int addr_count; unsigned int i; - if (net_dev->flags & IFF_PROMISC || - netdev_uc_count(net_dev) >= EFX_EF10_FILTER_DEV_UC_MAX) { + table->ucdef_id = EFX_EF10_FILTER_ID_INVALID; + addr_count = netdev_uc_count(net_dev); + if (net_dev->flags & IFF_PROMISC) *promisc = true; - } - table->dev_uc_count = 1 + netdev_uc_count(net_dev); + table->dev_uc_count = 1 + addr_count; ether_addr_copy(table->dev_uc_list[0].addr, net_dev->dev_addr); i = 1; netdev_for_each_uc_addr(uc, net_dev) { + if (i >= EFX_EF10_FILTER_DEV_UC_MAX) { + *promisc = true; + break; + } ether_addr_copy(table->dev_uc_list[i].addr, uc->addr); + table->dev_uc_list[i].id = EFX_EF10_FILTER_ID_INVALID; i++; } } @@ -3792,65 +3826,51 @@ static void efx_ef10_filter_uc_addr_list(struct efx_nic *efx, bool *promisc) static void efx_ef10_filter_mc_addr_list(struct efx_nic *efx, bool *promisc) { struct efx_ef10_filter_table *table = efx->filter_state; - struct efx_ef10_nic_data *nic_data = efx->nic_data; struct net_device *net_dev = efx->net_dev; struct netdev_hw_addr *mc; unsigned int i, addr_count; + table->mcdef_id = EFX_EF10_FILTER_ID_INVALID; + table->bcast_id = EFX_EF10_FILTER_ID_INVALID; if (net_dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) *promisc = true; - if (nic_data->workaround_26807) { - if (*promisc) { - table->dev_mc_count = 0; - return; - } - addr_count = netdev_mc_count(net_dev); - } else { - /* Allow room for broadcast and promiscuous */ - addr_count = netdev_mc_count(net_dev) + 2; - } - - if (addr_count >= EFX_EF10_FILTER_DEV_MC_MAX) { - if (nic_data->workaround_26807) { - table->dev_mc_count = 0; - } else { - table->dev_mc_count = 1; - eth_broadcast_addr(table->dev_mc_list[0].addr); - } - *promisc = true; - return; - } - - table->dev_mc_count = 1 + netdev_mc_count(net_dev); - eth_broadcast_addr(table->dev_mc_list[0].addr); - i = 1; + addr_count = netdev_mc_count(net_dev); + i = 0; netdev_for_each_mc_addr(mc, net_dev) { + if (i >= EFX_EF10_FILTER_DEV_MC_MAX) { + *promisc = true; + break; + } ether_addr_copy(table->dev_mc_list[i].addr, mc->addr); + table->dev_mc_list[i].id = EFX_EF10_FILTER_ID_INVALID; i++; } + + table->dev_mc_count = i; } -static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, - bool multicast, bool *promisc) +static int efx_ef10_filter_insert_addr_list(struct efx_nic *efx, + bool multicast, bool rollback) { struct efx_ef10_filter_table *table = efx->filter_state; struct efx_ef10_dev_addr *addr_list; struct efx_filter_spec spec; - int *addr_count; - unsigned int i; + u8 baddr[ETH_ALEN]; + unsigned int i, j; + int addr_count; int rc; if (multicast) { addr_list = table->dev_mc_list; - addr_count = &table->dev_mc_count; + addr_count = table->dev_mc_count; } else { addr_list = table->dev_uc_list; - addr_count = &table->dev_uc_count; + addr_count = table->dev_uc_count; } /* Insert/renew filters */ - for (i = 0; i < *addr_count; i++) { + for (i = 0; i < addr_count; i++) { efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); @@ -3858,46 +3878,113 @@ static void efx_ef10_filter_insert_addr_list(struct efx_nic *efx, addr_list[i].addr); rc = efx_ef10_filter_insert(efx, &spec, true); if (rc < 0) { - /* Fall back to promiscuous, but leave the broadcast - * filter for multicast - */ - while (i--) { - struct efx_ef10_nic_data *nic_data = - efx->nic_data; - - if (multicast && i == 1 && - !nic_data->workaround_26807) - break; - - efx_ef10_filter_remove_safe( - efx, EFX_FILTER_PRI_AUTO, - addr_list[i].id); + if (rollback) { + netif_info(efx, drv, efx->net_dev, + "efx_ef10_filter_insert failed rc=%d\n", + rc); + /* Fall back to promiscuous */ + for (j = 0; j < i; j++) { + if (addr_list[j].id == EFX_EF10_FILTER_ID_INVALID) + continue; + efx_ef10_filter_remove_unsafe( + efx, EFX_FILTER_PRI_AUTO, + addr_list[j].id); + addr_list[j].id = EFX_EF10_FILTER_ID_INVALID; + } + return rc; + } else { + /* mark as not inserted, and carry on */ + rc = EFX_EF10_FILTER_ID_INVALID; } - *addr_count = i; - *promisc = true; - break; } - addr_list[i].id = rc; + addr_list[i].id = efx_ef10_filter_get_unsafe_id(efx, rc); } - if (*promisc) { + if (multicast && rollback) { + /* Also need an Ethernet broadcast filter */ efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, EFX_FILTER_FLAG_RX_RSS, 0); - - if (multicast) - efx_filter_set_mc_def(&spec); - else - efx_filter_set_uc_def(&spec); - + eth_broadcast_addr(baddr); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, baddr); rc = efx_ef10_filter_insert(efx, &spec, true); - if (rc < 0) + if (rc < 0) { netif_warn(efx, drv, efx->net_dev, - "%scast mismatch filter insert failed.", - multicast ? "Multi" : "Uni"); - else - addr_list[(*addr_count)++].id = rc; + "Broadcast filter insert failed rc=%d\n", rc); + /* Fall back to promiscuous */ + for (j = 0; j < i; j++) { + if (addr_list[j].id == EFX_EF10_FILTER_ID_INVALID) + continue; + efx_ef10_filter_remove_unsafe( + efx, EFX_FILTER_PRI_AUTO, + addr_list[j].id); + addr_list[j].id = EFX_EF10_FILTER_ID_INVALID; + } + return rc; + } else { + table->bcast_id = efx_ef10_filter_get_unsafe_id(efx, rc); + } } + + return 0; +} + +static int efx_ef10_filter_insert_def(struct efx_nic *efx, bool multicast, + bool rollback) +{ + struct efx_ef10_filter_table *table = efx->filter_state; + struct efx_ef10_nic_data *nic_data = efx->nic_data; + struct efx_filter_spec spec; + u8 baddr[ETH_ALEN]; + int rc; + + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + + if (multicast) + efx_filter_set_mc_def(&spec); + else + efx_filter_set_uc_def(&spec); + + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + netif_warn(efx, drv, efx->net_dev, + "%scast mismatch filter insert failed rc=%d\n", + multicast ? "Multi" : "Uni", rc); + } else if (multicast) { + table->mcdef_id = efx_ef10_filter_get_unsafe_id(efx, rc); + if (!nic_data->workaround_26807) { + /* Also need an Ethernet broadcast filter */ + efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, + EFX_FILTER_FLAG_RX_RSS, + 0); + eth_broadcast_addr(baddr); + efx_filter_set_eth_local(&spec, EFX_FILTER_VID_UNSPEC, + baddr); + rc = efx_ef10_filter_insert(efx, &spec, true); + if (rc < 0) { + netif_warn(efx, drv, efx->net_dev, + "Broadcast filter insert failed rc=%d\n", + rc); + if (rollback) { + /* Roll back the mc_def filter */ + efx_ef10_filter_remove_unsafe( + efx, EFX_FILTER_PRI_AUTO, + table->mcdef_id); + table->mcdef_id = EFX_EF10_FILTER_ID_INVALID; + return rc; + } + } else { + table->bcast_id = efx_ef10_filter_get_unsafe_id(efx, rc); + } + } + rc = 0; + } else { + table->ucdef_id = rc; + rc = 0; + } + return rc; } /* Remove filters that weren't renewed. Since nothing else changes the AUTO_OLD @@ -4014,15 +4101,56 @@ static void efx_ef10_filter_sync_rx_mode(struct efx_nic *efx) efx_ef10_filter_mc_addr_list(efx, &mc_promisc); netif_addr_unlock_bh(net_dev); - /* Insert/renew filters */ - efx_ef10_filter_insert_addr_list(efx, false, &uc_promisc); + /* Insert/renew unicast filters */ + if (uc_promisc) { + efx_ef10_filter_insert_def(efx, false, false); + efx_ef10_filter_insert_addr_list(efx, false, false); + } else { + /* If any of the filters failed to insert, fall back to + * promiscuous mode - add in the uc_def filter. But keep + * our individual unicast filters. + */ + if (efx_ef10_filter_insert_addr_list(efx, false, false)) + efx_ef10_filter_insert_def(efx, false, false); + } + /* Insert/renew multicast filters */ /* If changing promiscuous state with cascaded multicast filters, remove * old filters first, so that packets are dropped rather than duplicated */ if (nic_data->workaround_26807 && efx->mc_promisc != mc_promisc) efx_ef10_filter_remove_old(efx); - efx_ef10_filter_insert_addr_list(efx, true, &mc_promisc); + if (mc_promisc) { + if (nic_data->workaround_26807) { + /* If we failed to insert promiscuous filters, rollback + * and fall back to individual multicast filters + */ + if (efx_ef10_filter_insert_def(efx, true, true)) { + /* Changing promisc state, so remove old filters */ + efx_ef10_filter_remove_old(efx); + efx_ef10_filter_insert_addr_list(efx, true, false); + } + } else { + /* If we failed to insert promiscuous filters, don't + * rollback. Regardless, also insert the mc_list + */ + efx_ef10_filter_insert_def(efx, true, false); + efx_ef10_filter_insert_addr_list(efx, true, false); + } + } else { + /* If any filters failed to insert, rollback and fall back to + * promiscuous mode - mc_def filter and maybe broadcast. If + * that fails, roll back again and insert as many of our + * individual multicast filters as we can. + */ + if (efx_ef10_filter_insert_addr_list(efx, true, true)) { + /* Changing promisc state, so remove old filters */ + if (nic_data->workaround_26807) + efx_ef10_filter_remove_old(efx); + if (efx_ef10_filter_insert_def(efx, true, true)) + efx_ef10_filter_insert_addr_list(efx, true, false); + } + } efx_ef10_filter_remove_old(efx); efx->mc_promisc = mc_promisc; -- GitLab From 01faef2cebae02685e2bcfc9bbee8416d5ec19fc Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 09:16:24 -0700 Subject: [PATCH 1450/7006] mpls: make RTA_OIF optional If user did not specify an oif, try and get it from the via address. If failed to get device, return with -ENODEV. Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/mpls/af_mpls.c | 67 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 6e669114f829d..49f1b0e41bdf6 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "internal.h" #define LABEL_NOT_SPECIFIED (1<<20) @@ -330,6 +331,70 @@ static unsigned find_free_label(struct net *net) return LABEL_NOT_SPECIFIED; } +static struct net_device *inet_fib_lookup_dev(struct net *net, void *addr) +{ + struct net_device *dev = NULL; + struct rtable *rt; + struct in_addr daddr; + + memcpy(&daddr, addr, sizeof(struct in_addr)); + rt = ip_route_output(net, daddr.s_addr, 0, 0, 0); + if (IS_ERR(rt)) + goto errout; + + dev = rt->dst.dev; + dev_hold(dev); + + ip_rt_put(rt); + +errout: + return dev; +} + +static struct net_device *inet6_fib_lookup_dev(struct net *net, void *addr) +{ + struct net_device *dev = NULL; + struct dst_entry *dst; + struct flowi6 fl6; + + memset(&fl6, 0, sizeof(fl6)); + memcpy(&fl6.daddr, addr, sizeof(struct in6_addr)); + dst = ip6_route_output(net, NULL, &fl6); + if (dst->error) + goto errout; + + dev = dst->dev; + dev_hold(dev); + +errout: + dst_release(dst); + + return dev; +} + +static struct net_device *find_outdev(struct net *net, + struct mpls_route_config *cfg) +{ + struct net_device *dev = NULL; + + if (!cfg->rc_ifindex) { + switch (cfg->rc_via_table) { + case NEIGH_ARP_TABLE: + dev = inet_fib_lookup_dev(net, cfg->rc_via); + break; + case NEIGH_ND_TABLE: + dev = inet6_fib_lookup_dev(net, cfg->rc_via); + break; + case NEIGH_LINK_TABLE: + break; + } + } else { + dev = dev_get_by_index(net, cfg->rc_ifindex); + } + + return dev; +} + static int mpls_route_add(struct mpls_route_config *cfg) { struct mpls_route __rcu **platform_label; @@ -361,7 +426,7 @@ static int mpls_route_add(struct mpls_route_config *cfg) goto errout; err = -ENODEV; - dev = dev_get_by_index(net, cfg->rc_ifindex); + dev = find_outdev(net, cfg); if (!dev) goto errout; -- GitLab From 0b2c2a931a051e75f9df429b520bb2c2f2bb056b Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 21 Jul 2015 22:39:40 +0530 Subject: [PATCH 1451/7006] cxgb4: Add debugfs entry to enable backdoor access Add debugfs entry 'use_backdoor' to enable backdoor access to read sge context. By default, we read sge context's via firmware. In case of FW issues, one can enable backdoor access via debugfs to dump sge context for debugging purpose. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + .../ethernet/chelsio/cxgb4/cxgb4_debugfs.c | 2 ++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 19 ++++++++++++------- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 629f75d703535..58de4443eac03 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -767,6 +767,7 @@ struct adapter { bool tid_release_task_busy; struct dentry *debugfs_root; + u32 use_bd; /* Use SGE Back Door intfc for reading SGE Contexts */ spinlock_t stats_lock; spinlock_t win0_lock ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c index b135d05c9984c..f701a6f20c6af 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c @@ -2388,6 +2388,8 @@ int t4_setup_debugfs(struct adapter *adap) de = debugfs_create_file_size("flash", S_IRUSR, adap->debugfs_root, adap, &flash_debugfs_fops, adap->params.sf_size); + debugfs_create_bool("use_backdoor", S_IWUSR | S_IRUSR, + adap->debugfs_root, &adap->use_bd); return 0; } diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index 1e6597dc87365..800bd489dd751 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -3689,6 +3689,11 @@ int t4_read_rss(struct adapter *adapter, u16 *map) return 0; } +static unsigned int t4_use_ldst(struct adapter *adap) +{ + return (adap->flags & FW_OK) || !adap->use_bd; +} + /** * t4_fw_tp_pio_rw - Access TP PIO through LDST * @adap: the adapter @@ -3732,7 +3737,7 @@ static void t4_fw_tp_pio_rw(struct adapter *adap, u32 *vals, unsigned int nregs, */ void t4_read_rss_key(struct adapter *adap, u32 *key) { - if (adap->flags & FW_OK) + if (t4_use_ldst(adap)) t4_fw_tp_pio_rw(adap, key, 10, TP_RSS_SECRET_KEY0_A, 1); else t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, @@ -3762,7 +3767,7 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) (vrt & KEYEXTEND_F) && (KEYMODE_G(vrt) == 3)) rss_key_addr_cnt = 32; - if (adap->flags & FW_OK) + if (t4_use_ldst(adap)) t4_fw_tp_pio_rw(adap, (void *)key, 10, TP_RSS_SECRET_KEY0_A, 0); else t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10, @@ -3791,7 +3796,7 @@ void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx) void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index, u32 *valp) { - if (adapter->flags & FW_OK) + if (t4_use_ldst(adapter)) t4_fw_tp_pio_rw(adapter, valp, 1, TP_RSS_PF0_CONFIG_A + index, 1); else @@ -3831,7 +3836,7 @@ void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index, /* Grab the VFL/VFH values ... */ - if (adapter->flags & FW_OK) { + if (t4_use_ldst(adapter)) { t4_fw_tp_pio_rw(adapter, vfl, 1, TP_RSS_VFL_CONFIG_A, 1); t4_fw_tp_pio_rw(adapter, vfh, 1, TP_RSS_VFH_CONFIG_A, 1); } else { @@ -3852,7 +3857,7 @@ u32 t4_read_rss_pf_map(struct adapter *adapter) { u32 pfmap; - if (adapter->flags & FW_OK) + if (t4_use_ldst(adapter)) t4_fw_tp_pio_rw(adapter, &pfmap, 1, TP_RSS_PF_MAP_A, 1); else t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, @@ -3870,7 +3875,7 @@ u32 t4_read_rss_pf_mask(struct adapter *adapter) { u32 pfmask; - if (adapter->flags & FW_OK) + if (t4_use_ldst(adapter)) t4_fw_tp_pio_rw(adapter, &pfmask, 1, TP_RSS_PF_MSK_A, 1); else t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A, @@ -6275,7 +6280,7 @@ int t4_init_tp_params(struct adapter *adap) /* Cache the adapter's Compressed Filter Mode and global Incress * Configuration. */ - if (adap->flags & FW_OK) { + if (t4_use_ldst(adap)) { t4_fw_tp_pio_rw(adap, &adap->params.tp.vlan_pri_map, 1, TP_VLAN_PRI_MAP_A, 1); t4_fw_tp_pio_rw(adap, &adap->params.tp.ingress_config, 1, -- GitLab From b56ea2985d389a3676638203323ebe22c261b7fe Mon Sep 17 00:00:00 2001 From: Rick Jones Date: Tue, 21 Jul 2015 16:14:13 -0700 Subject: [PATCH 1452/7006] net: track success and failure of TCP PMTU probing Track success and failure of TCP PMTU probing. Signed-off-by: Rick Jones Signed-off-by: David S. Miller --- include/uapi/linux/snmp.h | 2 ++ net/ipv4/proc.c | 2 ++ net/ipv4/tcp_input.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/include/uapi/linux/snmp.h b/include/uapi/linux/snmp.h index eee8968407f06..25a9ad8bcef12 100644 --- a/include/uapi/linux/snmp.h +++ b/include/uapi/linux/snmp.h @@ -278,6 +278,8 @@ enum LINUX_MIB_TCPACKSKIPPEDCHALLENGE, /* TCPACKSkippedChallenge */ LINUX_MIB_TCPWINPROBE, /* TCPWinProbe */ LINUX_MIB_TCPKEEPALIVE, /* TCPKeepAlive */ + LINUX_MIB_TCPMTUPFAIL, /* TCPMTUPFail */ + LINUX_MIB_TCPMTUPSUCCESS, /* TCPMTUPSuccess */ __LINUX_MIB_MAX }; diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index da5d483e236ac..3abd9d7a3adf3 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -300,6 +300,8 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPACKSkippedChallenge", LINUX_MIB_TCPACKSKIPPEDCHALLENGE), SNMP_MIB_ITEM("TCPWinProbe", LINUX_MIB_TCPWINPROBE), SNMP_MIB_ITEM("TCPKeepAlive", LINUX_MIB_TCPKEEPALIVE), + SNMP_MIB_ITEM("TCPMTUPFail", LINUX_MIB_TCPMTUPFAIL), + SNMP_MIB_ITEM("TCPMTUPSuccess", LINUX_MIB_TCPMTUPSUCCESS), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 1578fc2a6f39b..cda3ffedadb63 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -2593,6 +2593,7 @@ static void tcp_mtup_probe_failed(struct sock *sk) icsk->icsk_mtup.search_high = icsk->icsk_mtup.probe_size - 1; icsk->icsk_mtup.probe_size = 0; + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMTUPFAIL); } static void tcp_mtup_probe_success(struct sock *sk) @@ -2612,6 +2613,7 @@ static void tcp_mtup_probe_success(struct sock *sk) icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size; icsk->icsk_mtup.probe_size = 0; tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPMTUPSUCCESS); } /* Do a simple retransmit without using the backoff mechanisms in -- GitLab From fd63e2a972c670887e5e8a08440111d3812c0996 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Jul 2015 15:32:44 -0700 Subject: [PATCH 1453/7006] drm/i915: combine i9xx_get_hpd_pins and pch_get_hpd_pins These functions are quite similar, so combine them with the use of a new argument for a function that detects long pulses. This will be also needed by an upcoming patch adding support for BXT long pulse detection. No functional change. v2: - rebase on top -nightly (Daniel) Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 57 +++++++++++---------------------- 1 file changed, 19 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d87f173a0179a..9410aaba01d46 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1256,9 +1256,10 @@ static bool i9xx_port_hotplug_long_detect(enum port port, u32 val) } /* Get a bit mask of pins that have triggered, and which ones may be long. */ -static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, +static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, u32 hotplug_trigger, u32 dig_hotplug_reg, - const u32 hpd[HPD_NUM_PINS]) + const u32 hpd[HPD_NUM_PINS], + bool long_pulse_detect(enum port port, u32 val)) { enum port port; int i; @@ -1273,7 +1274,7 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask |= BIT(i); port = intel_hpd_pin_to_port(i); - if (pch_port_hotplug_long_detect(port, dig_hotplug_reg)) + if (long_pulse_detect(port, dig_hotplug_reg)) *long_mask |= BIT(i); } @@ -1282,34 +1283,6 @@ static void pch_get_hpd_pins(u32 *pin_mask, u32 *long_mask, } -/* Get a bit mask of pins that have triggered, and which ones may be long. */ -static void i9xx_get_hpd_pins(u32 *pin_mask, u32 *long_mask, - u32 hotplug_trigger, const u32 hpd[HPD_NUM_PINS]) -{ - enum port port; - int i; - - *pin_mask = 0; - *long_mask = 0; - - if (!hotplug_trigger) - return; - - for_each_hpd_pin(i) { - if ((hpd[i] & hotplug_trigger) == 0) - continue; - - *pin_mask |= BIT(i); - - port = intel_hpd_pin_to_port(i); - if (i9xx_port_hotplug_long_detect(port, hotplug_trigger)) - *long_mask |= BIT(i); - } - - DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x, pins 0x%08x\n", - hotplug_trigger, *pin_mask); -} - static void gmbus_irq_handler(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -1547,7 +1520,9 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_G4X; - i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_g4x); + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + hotplug_trigger, hpd_status_g4x, + i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X) @@ -1555,7 +1530,9 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) } else { u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; - i9xx_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, hpd_status_i915); + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + hotplug_trigger, hpd_status_g4x, + i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } } @@ -1662,8 +1639,9 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - dig_hotplug_reg, hpd_ibx); + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_ibx, + pch_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } @@ -1763,8 +1741,10 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - pch_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - dig_hotplug_reg, hpd_cpt); + + intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, + dig_hotplug_reg, hpd_cpt, + pch_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } @@ -1981,7 +1961,8 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) /* Clear sticky bits in hpd status */ I915_WRITE(BXT_HOTPLUG_CTL, hp_control); - pch_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, hpd_bxt); + intel_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, + hpd_bxt, pch_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } -- GitLab From cc24fcdcea74844145f0f7683d4626be27dec221 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 21 Jul 2015 15:32:45 -0700 Subject: [PATCH 1454/7006] drm/i915: don't use HPD_PORT_A as an alias for HPD_NONE Currently HPD_PORT_A is used as an alias for HPD_NONE to mean that the given port doesn't support long/short HPD pulse detection. SDVO and CRT ports are like this and for these ports we only want to know whether an hot plug event was detected on the corresponding pin. Since at least on BXT we need long/short pulse detection on PORT A as well (added by the next patch) remove this aliasing of HPD_PORT_A/HPD_NONE and let the return value of intel_hpd_pin_to_port() show whether long/short pulse detection is supported on the passed in pin. No functional change. v2: - rebase on top of -nightly (Daniel) - make the check for intel_hpd_pin_to_port() return value more readable (Sivakumar) Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 4 ++-- drivers/gpu/drm/i915/i915_irq.c | 4 +++- drivers/gpu/drm/i915/intel_hotplug.c | 20 +++++++++++++------- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b876e788e2f86..b94ada96b3482 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -206,11 +206,11 @@ enum intel_display_power_domain { enum hpd_pin { HPD_NONE = 0, - HPD_PORT_A = HPD_NONE, /* PORT_A is internal */ HPD_TV = HPD_NONE, /* TV is known to be unreliable */ HPD_CRT, HPD_SDVO_B, HPD_SDVO_C, + HPD_PORT_A, HPD_PORT_B, HPD_PORT_C, HPD_PORT_D, @@ -2648,7 +2648,7 @@ void intel_hpd_irq_handler(struct drm_device *dev, u32 pin_mask, u32 long_mask); void intel_hpd_init(struct drm_i915_private *dev_priv); void intel_hpd_init_work(struct drm_i915_private *dev_priv); void intel_hpd_cancel_work(struct drm_i915_private *dev_priv); -enum port intel_hpd_pin_to_port(enum hpd_pin pin); +bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port); /* i915_irq.c */ void i915_queue_hangcheck(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 9410aaba01d46..f08ec9cf46e65 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1273,7 +1273,9 @@ static void intel_get_hpd_pins(u32 *pin_mask, u32 *long_mask, *pin_mask |= BIT(i); - port = intel_hpd_pin_to_port(i); + if (!intel_hpd_pin_to_port(i, &port)) + continue; + if (long_pulse_detect(port, dig_hotplug_reg)) *long_mask |= BIT(i); } diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 3c9171f115310..032a0bf75f3b1 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -76,17 +76,23 @@ * it will use i915_hotplug_work_func where this logic is handled. */ -enum port intel_hpd_pin_to_port(enum hpd_pin pin) +bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port) { switch (pin) { + case HPD_PORT_A: + *port = PORT_A; + return true; case HPD_PORT_B: - return PORT_B; + *port = PORT_B; + return true; case HPD_PORT_C: - return PORT_C; + *port = PORT_C; + return true; case HPD_PORT_D: - return PORT_D; + *port = PORT_D; + return true; default: - return PORT_A; /* no hpd */ + return false; /* no hpd */ } } @@ -369,8 +375,8 @@ void intel_hpd_irq_handler(struct drm_device *dev, if (!(BIT(i) & pin_mask)) continue; - port = intel_hpd_pin_to_port(i); - is_dig_port = port && dev_priv->hotplug.irq_port[port]; + is_dig_port = intel_hpd_pin_to_port(i, &port) && + dev_priv->hotplug.irq_port[port]; if (is_dig_port) { bool long_hpd = long_mask & BIT(i); -- GitLab From 63c88d2204bb33d060e22318b3d50162b7019add Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 20 Jul 2015 14:43:39 -0700 Subject: [PATCH 1455/7006] drm/i915/bxt: add support for HPD long/short pulse detection on HPD_PORT_A pin This is a requirement for enabling display port HPD support on the port A HPD pin. This support is to be added by follow-up patches. Signed-off-by: Imre Deak Reviewed-by: Sonika Jindal Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_irq.c | 18 +++++++++++++++++- drivers/gpu/drm/i915/i915_reg.h | 5 +++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index f08ec9cf46e65..1118c39281f98 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1227,6 +1227,22 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_i915_private *dev_priv, return ret; } +static bool bxt_port_hotplug_long_detect(enum port port, u32 val) +{ + switch (port) { + case PORT_A: + return val & BXT_PORTA_HOTPLUG_LONG_DETECT; + case PORT_B: + return val & PORTB_HOTPLUG_LONG_DETECT; + case PORT_C: + return val & PORTC_HOTPLUG_LONG_DETECT; + case PORT_D: + return val & PORTD_HOTPLUG_LONG_DETECT; + default: + return false; + } +} + static bool pch_port_hotplug_long_detect(enum port port, u32 val) { switch (port) { @@ -1964,7 +1980,7 @@ static void bxt_hpd_handler(struct drm_device *dev, uint32_t iir_status) I915_WRITE(BXT_HOTPLUG_CTL, hp_control); intel_get_hpd_pins(&pin_mask, &long_mask, hp_trigger, hp_control, - hpd_bxt, pch_port_hotplug_long_detect); + hpd_bxt, bxt_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index e9a95df639f0e..8cf77568f7e14 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5985,6 +5985,11 @@ enum skl_disp_power_wells { /* digital port hotplug */ #define PCH_PORT_HOTPLUG 0xc4030 /* SHOTPLUG_CTL */ +#define BXT_PORTA_HOTPLUG_ENABLE (1 << 28) +#define BXT_PORTA_HOTPLUG_STATUS_MASK (0x3 << 24) +#define BXT_PORTA_HOTPLUG_NO_DETECT (0 << 24) +#define BXT_PORTA_HOTPLUG_SHORT_DETECT (1 << 24) +#define BXT_PORTA_HOTPLUG_LONG_DETECT (2 << 24) #define PORTD_HOTPLUG_ENABLE (1 << 20) #define PORTD_PULSE_DURATION_2ms (0) #define PORTD_PULSE_DURATION_4_5ms (1 << 18) -- GitLab From 04cbfe68c3190f23bcfec230bfd832b533f35554 Mon Sep 17 00:00:00 2001 From: Shobhit Kumar Date: Wed, 22 Jul 2015 14:01:44 +0530 Subject: [PATCH 1456/7006] mfd: Add GPIOLIB dependency if INTEL_SOC_PMIC is to be enabled This is needed as the CRC PMIC has support for Panel enable/diable as gpio which needs 'gpiod_add_lookup_table' and 'gpiod_remove_lookup_table' from gpiolib. This patch can be squashed with below commit in topic/crc-pmic branch commit 61dd2ca2d44e493b050adbbb75bc50db11c367dd Author: Shobhit Kumar Date: Fri Jun 26 14:32:05 2015 +0530 mfd: intel_soc_pmic_core: Add lookup table for Panel Control as GPIO signal On some Intel SoC platforms, the panel enable/disable signals are controlled by CRC PMIC. Add those control as a new GPIO in a lookup table for gpio-crystalcove chip during CRC driver load Cc: Lee Jones Cc: Linus Walleij Signed-off-by: Shobhit Kumar Signed-off-by: Daniel Vetter --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 653815950aa24..379a420245eac 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -318,6 +318,7 @@ config LPC_SCH config INTEL_SOC_PMIC bool "Support for Intel Atom SoC PMIC" + depends on GPIOLIB depends on I2C=y select MFD_CORE select REGMAP_I2C -- GitLab From 6a75c0b62b0981c3a34d3336725b0840747e7680 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 22 Jul 2015 09:59:47 +0800 Subject: [PATCH 1457/7006] ASoC: cs4349: Remove unneeded NULL test for cs4349->reset_gpio It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index a7538aea7f993..852be858bb9f5 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -300,8 +300,7 @@ static int cs4349_i2c_probe(struct i2c_client *client, if (IS_ERR(cs4349->reset_gpio)) return PTR_ERR(cs4349->reset_gpio); - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); i2c_set_clientdata(client, cs4349); @@ -316,8 +315,7 @@ static int cs4349_i2c_remove(struct i2c_client *client) snd_soc_unregister_codec(&client->dev); /* Hold down reset */ - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); return 0; } @@ -335,8 +333,7 @@ static int cs4349_runtime_suspend(struct device *dev) regcache_cache_only(cs4349->regmap, true); /* Hold down reset */ - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 0); + gpiod_set_value_cansleep(cs4349->reset_gpio, 0); return 0; } @@ -350,8 +347,7 @@ static int cs4349_runtime_resume(struct device *dev) if (ret < 0) return ret; - if (cs4349->reset_gpio) - gpiod_set_value_cansleep(cs4349->reset_gpio, 1); + gpiod_set_value_cansleep(cs4349->reset_gpio, 1); regcache_cache_only(cs4349->regmap, false); regcache_sync(cs4349->regmap); -- GitLab From ec12693e5d03c7e6399ba1e9150908527b809f33 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Wed, 22 Jul 2015 10:22:33 +0800 Subject: [PATCH 1458/7006] ASoC: cs4349: Fix up setting PWR_DWN bit The PWR_DWN is Bit 7, so current code does not set the PWR_DWN bit. Fix it. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 852be858bb9f5..0d010c2b60212 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -326,7 +326,7 @@ static int cs4349_runtime_suspend(struct device *dev) struct cs4349_private *cs4349 = dev_get_drvdata(dev); int ret; - ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, 1); + ret = regmap_update_bits(cs4349->regmap, CS4349_MISC, PWR_DWN, PWR_DWN); if (ret < 0) return ret; -- GitLab From 775b07de4fa470ac10cd74f1b1a8d441b4f5838d Mon Sep 17 00:00:00 2001 From: Koro Chen Date: Wed, 22 Jul 2015 17:39:35 +0800 Subject: [PATCH 1459/7006] ASoC: mediatek: Add suspend/resume callbacks This adds suspend/resume callbacks, which are common for each DAI. To be able to continue the last playback/capture after resume when suspend was done during a playback/capture, in the callbacks we do backup/restore of registers which were set before prepare stage. Registers to be backup/restore are defined in a backup list array. Signed-off-by: Koro Chen Signed-off-by: Mark Brown --- sound/soc/mediatek/mtk-afe-common.h | 8 --- sound/soc/mediatek/mtk-afe-pcm.c | 77 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 8 deletions(-) diff --git a/sound/soc/mediatek/mtk-afe-common.h b/sound/soc/mediatek/mtk-afe-common.h index a88b17511fdf1..cc4393cb1130f 100644 --- a/sound/soc/mediatek/mtk-afe-common.h +++ b/sound/soc/mediatek/mtk-afe-common.h @@ -98,12 +98,4 @@ struct mtk_afe_memif { const struct mtk_afe_irq_data *irqdata; }; -struct mtk_afe { - /* address for ioremap audio hardware register */ - void __iomem *base_addr; - struct device *dev; - struct regmap *regmap; - struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; - struct clk *clocks[MTK_CLK_NUM]; -}; #endif diff --git a/sound/soc/mediatek/mtk-afe-pcm.c b/sound/soc/mediatek/mtk-afe-pcm.c index 5b74afb59c5cf..ef252a64d80b8 100644 --- a/sound/soc/mediatek/mtk-afe-pcm.c +++ b/sound/soc/mediatek/mtk-afe-pcm.c @@ -45,18 +45,21 @@ /* Memory interface */ #define AFE_DL1_BASE 0x0040 #define AFE_DL1_CUR 0x0044 +#define AFE_DL1_END 0x0048 #define AFE_DL2_BASE 0x0050 #define AFE_DL2_CUR 0x0054 #define AFE_AWB_BASE 0x0070 #define AFE_AWB_CUR 0x007c #define AFE_VUL_BASE 0x0080 #define AFE_VUL_CUR 0x008c +#define AFE_VUL_END 0x0088 #define AFE_DAI_BASE 0x0090 #define AFE_DAI_CUR 0x009c #define AFE_MOD_PCM_BASE 0x0330 #define AFE_MOD_PCM_CUR 0x033c #define AFE_HDMI_OUT_BASE 0x0374 #define AFE_HDMI_OUT_CUR 0x0378 +#define AFE_HDMI_OUT_END 0x037c #define AFE_ADDA2_TOP_CON0 0x0600 @@ -127,6 +130,34 @@ enum afe_tdm_ch_start { AFE_TDM_CH_ZERO, }; +static const unsigned int mtk_afe_backup_list[] = { + AUDIO_TOP_CON0, + AFE_CONN1, + AFE_CONN2, + AFE_CONN7, + AFE_CONN8, + AFE_DAC_CON1, + AFE_DL1_BASE, + AFE_DL1_END, + AFE_VUL_BASE, + AFE_VUL_END, + AFE_HDMI_OUT_BASE, + AFE_HDMI_OUT_END, + AFE_HDMI_CONN0, + AFE_DAC_CON0, +}; + +struct mtk_afe { + /* address for ioremap audio hardware register */ + void __iomem *base_addr; + struct device *dev; + struct regmap *regmap; + struct mtk_afe_memif memif[MTK_AFE_MEMIF_NUM]; + struct clk *clocks[MTK_CLK_NUM]; + unsigned int backup_regs[ARRAY_SIZE(mtk_afe_backup_list)]; + bool suspended; +}; + static const struct snd_pcm_hardware mtk_afe_hardware = { .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP_VALID), @@ -722,11 +753,53 @@ static const struct snd_soc_dai_ops mtk_afe_hdmi_ops = { }; +static int mtk_afe_runtime_suspend(struct device *dev); +static int mtk_afe_runtime_resume(struct device *dev); + +static int mtk_afe_dai_suspend(struct snd_soc_dai *dai) +{ + struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); + int i; + + dev_dbg(afe->dev, "%s\n", __func__); + if (pm_runtime_status_suspended(afe->dev) || afe->suspended) + return 0; + + for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) + regmap_read(afe->regmap, mtk_afe_backup_list[i], + &afe->backup_regs[i]); + + afe->suspended = true; + mtk_afe_runtime_suspend(afe->dev); + return 0; +} + +static int mtk_afe_dai_resume(struct snd_soc_dai *dai) +{ + struct mtk_afe *afe = snd_soc_dai_get_drvdata(dai); + int i = 0; + + dev_dbg(afe->dev, "%s\n", __func__); + if (pm_runtime_status_suspended(afe->dev) || !afe->suspended) + return 0; + + mtk_afe_runtime_resume(afe->dev); + + for (i = 0; i < ARRAY_SIZE(mtk_afe_backup_list); i++) + regmap_write(afe->regmap, mtk_afe_backup_list[i], + afe->backup_regs[i]); + + afe->suspended = false; + return 0; +} + static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { /* FE DAIs: memory intefaces to CPU */ { .name = "DL1", /* downlink 1 */ .id = MTK_AFE_MEMIF_DL1, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, .playback = { .stream_name = "DL1", .channels_min = 1, @@ -738,6 +811,8 @@ static struct snd_soc_dai_driver mtk_afe_pcm_dais[] = { }, { .name = "VUL", /* voice uplink */ .id = MTK_AFE_MEMIF_VUL, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, .capture = { .stream_name = "VUL", .channels_min = 1, @@ -774,6 +849,8 @@ static struct snd_soc_dai_driver mtk_afe_hdmi_dais[] = { { .name = "HDMI", .id = MTK_AFE_MEMIF_HDMI, + .suspend = mtk_afe_dai_suspend, + .resume = mtk_afe_dai_resume, .playback = { .stream_name = "HDMI", .channels_min = 2, -- GitLab From c99235fa3ef833c3c23926085f2bb68851c8460a Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Wed, 15 Jul 2015 18:00:06 -0300 Subject: [PATCH 1460/7006] [media] media: am437x-vpfe: Fix a race condition during release There was a race condition where during cleanup/release operation on-going streaming would cause a kernel panic because the hardware module was disabled prematurely with IRQ still pending. Fixes: 417d2e507edc ("[media] media: platform: add VPFE capture driver support for AM437X") Cc: # v4.0+ Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/am437x/am437x-vpfe.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 1fed7a56c8ae4..c8447fa3fd91b 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1186,14 +1186,24 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe) static int vpfe_release(struct file *file) { struct vpfe_device *vpfe = video_drvdata(file); + bool fh_singular; int ret; mutex_lock(&vpfe->lock); - if (v4l2_fh_is_singular_file(file)) - vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); + /* Save the singular status before we call the clean-up helper */ + fh_singular = v4l2_fh_is_singular_file(file); + + /* the release helper will cleanup any on-going streaming */ ret = _vb2_fop_release(file, NULL); + /* + * If this was the last open file. + * Then de-initialize hw module. + */ + if (fh_singular) + vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev); + mutex_unlock(&vpfe->lock); return ret; -- GitLab From 810c168c233fc531ecd3e7a6d9e0b5a3ffe85da7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jul 2015 08:29:40 -0300 Subject: [PATCH 1461/7006] [media] cobalt: accept unchanged timings when vb2_is_busy() When vb2_is_busy() it should still be possible to call S_DV_TIMINGS provided the new timings are the same as the current timings. For input 1 (test generator) the size is always 1080p, so just return that. Fixes a v4l2-compliance issue. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-v4l2.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index b40c2d141b582..9756fd3e8af5e 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -641,13 +642,17 @@ static int cobalt_s_dv_timings(struct file *file, void *priv_fh, struct cobalt_stream *s = video_drvdata(file); int err; - if (vb2_is_busy(&s->q)) - return -EBUSY; - if (s->input == 1) { *timings = cea1080p60; return 0; } + + if (v4l2_match_dv_timings(timings, &s->timings, 0)) + return 0; + + if (vb2_is_busy(&s->q)) + return -EBUSY; + err = v4l2_subdev_call(s->sd, video, s_dv_timings, timings); if (!err) { -- GitLab From 55b858b4e5f46e71f9e5089cb63602697a49a211 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 17 Jul 2015 08:45:22 -0300 Subject: [PATCH 1462/7006] [media] cobalt: allow fewer than 8 PCIe lanes Currently the cobalt driver refuses to load if fewer than 8 PCIe lanes are assigned. This patch changes this and just issues a warning. The only time it will refuse to load is if the number of assigned lanes is less than what the PCIe host is capable of since this suggests that the card isn't seated correctly in the slot. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-driver.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c index b994b8efdc99a..8fed61ec712ef 100644 --- a/drivers/media/pci/cobalt/cobalt-driver.c +++ b/drivers/media/pci/cobalt/cobalt-driver.c @@ -339,15 +339,16 @@ static int cobalt_setup_pci(struct cobalt *cobalt, struct pci_dev *pci_dev, } if (pcie_link_get_lanes(cobalt) != 8) { - cobalt_err("PCI Express link width is not 8 lanes (%d)\n", + cobalt_warn("PCI Express link width is %d lanes.\n", pcie_link_get_lanes(cobalt)); if (pcie_bus_link_get_lanes(cobalt) < 8) - cobalt_err("The current slot only supports %d lanes, at least 8 are needed\n", + cobalt_warn("The current slot only supports %d lanes, for best performance 8 are needed\n", pcie_bus_link_get_lanes(cobalt)); - else + if (pcie_link_get_lanes(cobalt) != pcie_bus_link_get_lanes(cobalt)) { cobalt_err("The card is most likely not seated correctly in the PCIe slot\n"); - ret = -EIO; - goto err_disable; + ret = -EIO; + goto err_disable; + } } if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64))) { -- GitLab From 4c5211a100399c3823563193dd881dcb3b7d24fc Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:53 -0300 Subject: [PATCH 1463/7006] [media] tc358743: register v4l2 asynchronous subdevice Add support for registering the sensor subdevice using the v4l2-async API. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 4e8811c3e7710..7278435048edf 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1710,6 +1710,16 @@ static int tc358743_probe(struct i2c_client *client, goto err_hdl; } + state->pad.flags = MEDIA_PAD_FL_SOURCE; + err = media_entity_init(&sd->entity, 1, &state->pad, 0); + if (err < 0) + goto err_hdl; + + sd->dev = &client->dev; + err = v4l2_async_register_subdev(sd); + if (err < 0) + goto err_hdl; + mutex_init(&state->confctl_mutex); INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug, @@ -1740,6 +1750,7 @@ err_work_queues: destroy_workqueue(state->work_queues); mutex_destroy(&state->confctl_mutex); err_hdl: + media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); return err; } @@ -1751,8 +1762,10 @@ static int tc358743_remove(struct i2c_client *client) cancel_delayed_work(&state->delayed_work_enable_hotplug); destroy_workqueue(state->work_queues); + v4l2_async_unregister_subdev(sd); v4l2_device_unregister_subdev(sd); mutex_destroy(&state->confctl_mutex); + media_entity_cleanup(&sd->entity); v4l2_ctrl_handler_free(&state->hdl); return 0; -- GitLab From 8ec23da73599848a5a5ecbab50f17a570b60c096 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:54 -0300 Subject: [PATCH 1464/7006] [media] tc358743: enable v4l2 subdevice devnode Add V4L2_SUBDEV_FL_HAS_DEVNODE to subdev flags, in order to enable a subdev device node. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 7278435048edf..0ccae3308b68b 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1668,7 +1668,7 @@ static int tc358743_probe(struct i2c_client *client, state->i2c_client = client; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &tc358743_ops); - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; /* i2c access */ if ((i2c_rd16(sd, CHIPID) & MASK_CHIPID) != 0) { -- GitLab From 4ea50e99bd3501aea394aa7a9e9bd3115faabf37 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:24 +0200 Subject: [PATCH 1465/7006] drm: Simplify drm_for_each_legacy_plane arguments No need to pass the planelist when everyone just uses dev->mode_config.plane_list anyway. I want to add a pile more of iterators with unified (obj, dev) arguments. This is just prep. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_pm.c | 2 +- drivers/gpu/drm/shmobile/shmob_drm_crtc.c | 2 +- include/drm/drm_crtc.h | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 0d3e01434860f..5004c4a46a9e3 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2356,7 +2356,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc, p->pri.horiz_pixels = intel_crtc->config->pipe_src_w; p->cur.horiz_pixels = intel_crtc->base.cursor->state->crtc_w; - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { + drm_for_each_legacy_plane(plane, dev) { struct intel_plane *intel_plane = to_intel_plane(plane); if (intel_plane->pipe == pipe) { diff --git a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c index 859ccb658601e..e9272b0a85924 100644 --- a/drivers/gpu/drm/shmobile/shmob_drm_crtc.c +++ b/drivers/gpu/drm/shmobile/shmob_drm_crtc.c @@ -248,7 +248,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc) lcdc_write(sdev, LDDDSR, value); /* Setup planes. */ - drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) { + drm_for_each_legacy_plane(plane, dev) { if (plane->crtc == crtc) shmob_drm_plane_setup(plane); } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 57ca8cc383a61..5cf0e6c3fc41d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1579,8 +1579,8 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, } /* Plane list iterator for legacy (overlay only) planes. */ -#define drm_for_each_legacy_plane(plane, planelist) \ - list_for_each_entry(plane, planelist, head) \ +#define drm_for_each_legacy_plane(plane, dev) \ + list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ if (plane->type == DRM_PLANE_TYPE_OVERLAY) #endif /* __DRM_CRTC_H__ */ -- GitLab From 6295d607ad34ee4e43aab3f20714c2ef7a6adea1 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:25 +0200 Subject: [PATCH 1466/7006] drm: Add modeset object iterators And roll them out across drm_* files. The point here isn't code prettification (it helps with that too) but that some of these lists aren't static any more. And having macros will gives us a convenient place to put locking checks into. I didn't add an iterator for props since that's only used by a list_for_each_entry_safe in the driver teardown code. Search&replace was done with the below cocci spatch. Note that there's a bunch more places that didn't match and which would need some manual changes, but I've intentially left these out for this mostly automated patch. iterator name drm_for_each_crtc; struct drm_crtc *crtc; struct drm_device *dev; expression head; @@ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc (crtc, dev) { ... } @@ iterator name drm_for_each_encoder; struct drm_encoder *encoder; struct drm_device *dev; expression head; @@ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder (encoder, dev) { ... } @@ iterator name drm_for_each_fb; struct drm_framebuffer *fb; struct drm_device *dev; expression head; @@ - list_for_each_entry(fb, &dev->mode_config.fb_list, head) { + drm_for_each_fb (fb, dev) { ... } @@ iterator name drm_for_each_connector; struct drm_connector *connector; struct drm_device *dev; expression head; @@ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector (connector, dev) { ... } Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 21 +++++++----------- drivers/gpu/drm/drm_crtc_helper.c | 34 +++++++++++++++--------------- drivers/gpu/drm/drm_fb_helper.c | 10 ++++----- drivers/gpu/drm/drm_of.c | 2 +- drivers/gpu/drm/drm_probe_helper.c | 6 +++--- include/drm/drm_crtc.h | 15 +++++++++++++ 6 files changed, 49 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9c978d9de3b8e..9b05dc76379e3 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -615,7 +615,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) if (atomic_read(&fb->refcount.refcount) > 1) { drm_modeset_lock_all(dev); /* remove from any CRTC */ - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb == fb) { /* should turn off the crtc */ memset(&set, 0, sizeof(struct drm_mode_set)); @@ -627,7 +627,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb) } } - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_plane(plane, dev) { if (plane->fb == fb) drm_plane_force_disable(plane); } @@ -1305,7 +1305,7 @@ drm_plane_from_index(struct drm_device *dev, int idx) struct drm_plane *plane; unsigned int i = 0; - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_plane(plane, dev) { if (i == idx) return plane; i++; @@ -1838,8 +1838,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, copied = 0; crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; if (!mode_group) { - list_for_each_entry(crtc, &dev->mode_config.crtc_list, - head) { + drm_for_each_crtc(crtc, dev) { DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); if (put_user(crtc->base.id, crtc_id + copied)) { ret = -EFAULT; @@ -1865,9 +1864,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, copied = 0; encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; if (!mode_group) { - list_for_each_entry(encoder, - &dev->mode_config.encoder_list, - head) { + drm_for_each_encoder(encoder, dev) { DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, encoder->name); if (put_user(encoder->base.id, encoder_id + @@ -1896,9 +1893,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data, copied = 0; connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; if (!mode_group) { - list_for_each_entry(connector, - &dev->mode_config.connector_list, - head) { + drm_for_each_connector(connector, dev) { DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id, connector->name); @@ -2187,7 +2182,7 @@ static struct drm_crtc *drm_encoder_get_crtc(struct drm_encoder *encoder) /* For atomic drivers only state objects are synchronously updated and * protected by modeset locks, so check those first. */ - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (!connector->state) continue; @@ -5393,7 +5388,7 @@ void drm_mode_config_reset(struct drm_device *dev) if (encoder->funcs->reset) encoder->funcs->reset(encoder); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { connector->status = connector_status_unknown; if (connector->funcs->reset) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 393114df88a3d..30254fb249fed 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -180,7 +180,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) drm_warn_on_modeset_not_all_locked(dev); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (!drm_helper_encoder_in_use(encoder)) { drm_encoder_disable(encoder); /* disconnect encoder from any connector */ @@ -188,7 +188,7 @@ static void __drm_helper_disable_unused_functions(struct drm_device *dev) } } - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; crtc->enabled = drm_helper_crtc_in_use(crtc); if (!crtc->enabled) { @@ -230,7 +230,7 @@ drm_crtc_prepare_encoders(struct drm_device *dev) const struct drm_encoder_helper_funcs *encoder_funcs; struct drm_encoder *encoder; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { encoder_funcs = encoder->helper_private; /* Disable unused encoders */ if (encoder->crtc == NULL) @@ -305,7 +305,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, * adjust it according to limitations or connector properties, and also * a chance to reject the mode entirely. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -334,7 +334,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, crtc->hwmode = *adjusted_mode; /* Prepare the encoders and CRTCs before setting the mode. */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -359,7 +359,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, if (!ret) goto done; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -376,7 +376,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, /* Now enable the clocks, plane, pipe, and connectors that we set up. */ crtc_funcs->commit(crtc); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; @@ -418,11 +418,11 @@ drm_crtc_helper_disable(struct drm_crtc *crtc) struct drm_encoder *encoder; /* Decouple all encoders and their attached connectors from this crtc */ - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if (encoder->crtc != crtc) continue; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (connector->encoder != encoder) continue; @@ -519,12 +519,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) * restored, not the drivers personal bookkeeping. */ count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { save_encoders[count++] = *encoder; } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { save_connectors[count++] = *connector; } @@ -562,7 +562,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) /* a) traverse passed in connector list and get encoders for them */ count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { const struct drm_connector_helper_funcs *connector_funcs = connector->helper_private; new_encoder = connector->encoder; @@ -602,7 +602,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (!connector->encoder) continue; @@ -685,12 +685,12 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set) fail: /* Restore all previous data. */ count = 0; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { *encoder = save_encoders[count++]; } count = 0; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { *connector = save_connectors[count++]; } @@ -862,7 +862,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) bool ret; drm_modeset_lock_all(dev); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { if (!crtc->enabled) continue; @@ -876,7 +876,7 @@ void drm_helper_resume_force_mode(struct drm_device *dev) /* Turn off outputs that were already powered off */ if (drm_helper_choose_crtc_dpms(crtc)) { - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { + drm_for_each_encoder(encoder, dev) { if(encoder->crtc != crtc) continue; diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index cac422916c7af..3630d92c9738a 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -98,7 +98,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) struct drm_connector *connector; int i; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { struct drm_fb_helper_connector *fb_helper_connector; fb_helper_connector = kzalloc(sizeof(struct drm_fb_helper_connector), GFP_KERNEL); @@ -269,7 +269,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc) struct drm_device *dev = crtc->dev; struct drm_crtc *c; - list_for_each_entry(c, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(c, dev) { if (crtc->base.id == c->base.id) return c->primary->fb; } @@ -321,7 +321,7 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper) drm_warn_on_modeset_not_all_locked(dev); - list_for_each_entry(plane, &dev->mode_config.plane_list, head) { + drm_for_each_plane(plane, dev) { if (plane->type != DRM_PLANE_TYPE_PRIMARY) drm_plane_force_disable(plane); @@ -458,7 +458,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper) if (dev->primary->master) return false; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { if (crtc->primary->fb) crtcs_bound++; if (crtc->primary->fb == fb_helper->fb) @@ -655,7 +655,7 @@ int drm_fb_helper_init(struct drm_device *dev, } i = 0; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(crtc, dev) { fb_helper->crtc_info[i].mode_set.crtc = crtc; i++; } diff --git a/drivers/gpu/drm/drm_of.c b/drivers/gpu/drm/drm_of.c index aaa130736bf8d..be3884073ea4d 100644 --- a/drivers/gpu/drm/drm_of.c +++ b/drivers/gpu/drm/drm_of.c @@ -19,7 +19,7 @@ static uint32_t drm_crtc_port_mask(struct drm_device *dev, unsigned int index = 0; struct drm_crtc *tmp; - list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) { + drm_for_each_crtc(tmp, dev) { if (tmp->port == port) return 1 << index; diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 04203c0d2ecbe..64d85c1bd18bf 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -312,7 +312,7 @@ static void output_poll_execute(struct work_struct *work) goto out; mutex_lock(&dev->mode_config.mutex); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { /* Ignore forced connectors. */ if (connector->force) @@ -413,7 +413,7 @@ void drm_kms_helper_poll_enable(struct drm_device *dev) if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) return; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT)) poll = true; @@ -495,7 +495,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev) return false; mutex_lock(&dev->mode_config.mutex); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + drm_for_each_connector(connector, dev) { /* Only handle HPD capable connectors. */ if (!(connector->polled & DRM_CONNECTOR_POLL_HPD)) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 5cf0e6c3fc41d..7c95a7df60651 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1583,4 +1583,19 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) \ if (plane->type == DRM_PLANE_TYPE_OVERLAY) +#define drm_for_each_plane(plane, dev) \ + list_for_each_entry(plane, &(dev)->mode_config.plane_list, head) + +#define drm_for_each_crtc(crtc, dev) \ + list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) + +#define drm_for_each_connector(connector, dev) \ + list_for_each_entry(connector, &(dev)->mode_config.connector_list, head) + +#define drm_for_each_encoder(encoder, dev) \ + list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) + +#define drm_for_each_fb(fb, dev) \ + list_for_each_entry(fb, &(dev)->mode_config.fb_list, head) + #endif /* __DRM_CRTC_H__ */ -- GitLab From 8c4ccc4ab6f64e859d4ff8d7c02c2ed2e956e07f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:26 +0200 Subject: [PATCH 1467/7006] drm/probe-helper: Grab mode_config.mutex in poll_init/enable So on first looks this seems superflous since drivers should ensure correct ordering to not make this a problem. Otoh ordering constraints between hdp, fbdev load and enabling polling are already tricky on some hardware and it helps to be more robust. But the real goal is to just shut up a locking WARN_ON I'd like to add, which means init code gets some additional locks just for uniformity. v2: Also grab the lock for the public poll_enable, not just poll_init which is used for resume, with the same justification. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_probe_helper.c | 41 ++++++++++++++++++------------ 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c index 64d85c1bd18bf..d734780b31c0f 100644 --- a/drivers/gpu/drm/drm_probe_helper.c +++ b/drivers/gpu/drm/drm_probe_helper.c @@ -93,6 +93,27 @@ static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector) return 1; } +#define DRM_OUTPUT_POLL_PERIOD (10*HZ) +static void __drm_kms_helper_poll_enable(struct drm_device *dev) +{ + bool poll = false; + struct drm_connector *connector; + + WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); + + if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) + return; + + drm_for_each_connector(connector, dev) { + if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | + DRM_CONNECTOR_POLL_DISCONNECT)) + poll = true; + } + + if (poll) + schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); +} + static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connector *connector, uint32_t maxX, uint32_t maxY, bool merge_type_bits) { @@ -153,7 +174,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect /* Re-enable polling in case the global poll config changed. */ if (drm_kms_helper_poll != dev->mode_config.poll_running) - drm_kms_helper_poll_enable(dev); + __drm_kms_helper_poll_enable(dev); dev->mode_config.poll_running = drm_kms_helper_poll; @@ -295,7 +316,6 @@ void drm_kms_helper_hotplug_event(struct drm_device *dev) } EXPORT_SYMBOL(drm_kms_helper_hotplug_event); -#define DRM_OUTPUT_POLL_PERIOD (10*HZ) static void output_poll_execute(struct work_struct *work) { struct delayed_work *delayed_work = to_delayed_work(work); @@ -407,20 +427,9 @@ EXPORT_SYMBOL(drm_kms_helper_poll_disable); */ void drm_kms_helper_poll_enable(struct drm_device *dev) { - bool poll = false; - struct drm_connector *connector; - - if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll) - return; - - drm_for_each_connector(connector, dev) { - if (connector->polled & (DRM_CONNECTOR_POLL_CONNECT | - DRM_CONNECTOR_POLL_DISCONNECT)) - poll = true; - } - - if (poll) - schedule_delayed_work(&dev->mode_config.output_poll_work, DRM_OUTPUT_POLL_PERIOD); + mutex_lock(&dev->mode_config.mutex); + __drm_kms_helper_poll_enable(dev); + mutex_unlock(&dev->mode_config.mutex); } EXPORT_SYMBOL(drm_kms_helper_poll_enable); -- GitLab From 169faecadd2444fc295c724c0a2f622b99e6bf19 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:27 +0200 Subject: [PATCH 1468/7006] drm/fbdev-helper: Grab mode_config.mutex in drm_fb_helper_single_add_all_connectors This is now truly only duct-tape to keep locking checks happy since calling this function when hpd or polling are already enabled is a bug. The fbdev helper can't cope with hotplug changes yet at this point, only after that. Otoh a bit more robustness in this function can't hurt, and with this fbdev can actually cope with hotplug changes. And it's also more consistent with the connector hotadd/remove dp mst needs to do. Therefore document this as new official behavior. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_helper.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 3630d92c9738a..329d08167b77d 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -89,8 +89,9 @@ static LIST_HEAD(kernel_fb_helper_list); * connectors to the fbdev, e.g. if some are reserved for special purposes or * not adequate to be used for the fbcon. * - * Since this is part of the initial setup before the fbdev is published, no - * locking is required. + * This function is protected against concurrent connector hotadds/removals + * using drm_fb_helper_add_one_connector() and + * drm_fb_helper_remove_one_connector(). */ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) { @@ -98,6 +99,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) struct drm_connector *connector; int i; + mutex_lock(&dev->mode_config.mutex); drm_for_each_connector(connector, dev) { struct drm_fb_helper_connector *fb_helper_connector; @@ -108,6 +110,7 @@ int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper) fb_helper_connector->connector = connector; fb_helper->connector_info[fb_helper->connector_count++] = fb_helper_connector; } + mutex_unlock(&dev->mode_config.mutex); return 0; fail: for (i = 0; i < fb_helper->connector_count; i++) { @@ -115,6 +118,8 @@ fail: fb_helper->connector_info[i] = NULL; } fb_helper->connector_count = 0; + mutex_unlock(&dev->mode_config.mutex); + return -ENOMEM; } EXPORT_SYMBOL(drm_fb_helper_single_add_all_connectors); -- GitLab From 7a3f3d6667f5f9ffd1517f6b21d64bbf5312042c Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:28 +0200 Subject: [PATCH 1469/7006] drm: Check locking in drm_for_each_connector Because of DP MST connectors can now be hotplugged and we must hold the right lock when walking the connector lists. Enforce this by checking the locking in our shiny new list walking macros. v2: Extract the locking check into a small static inline helper to help readability. This will be more important when we make the read list access rules more complicated in later patches. Inspired by comments from Chris. Unfortunately, due to header loops around the definition of struct drm_device the function interface is a bit funny. v3: Encoders aren't hotadded/removed. For each dp mst encoder we statically create one fake encoder per pipe so that we can support as many mst sinks as the hw can (Dave). Cc: Chris Wilson Cc: Dave Airlie Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 7c95a7df60651..499562274353a 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1589,8 +1589,18 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, #define drm_for_each_crtc(crtc, dev) \ list_for_each_entry(crtc, &(dev)->mode_config.crtc_list, head) +static inline void +assert_drm_connector_list_read_locked(struct drm_mode_config *mode_config) +{ + WARN_ON(!mutex_is_locked(&mode_config->mutex)); +} + #define drm_for_each_connector(connector, dev) \ - list_for_each_entry(connector, &(dev)->mode_config.connector_list, head) + for (assert_drm_connector_list_read_locked(&(dev)->mode_config), \ + connector = list_first_entry(&(dev)->mode_config.connector_list, \ + struct drm_connector, head); \ + &connector->head != (&(dev)->mode_config.connector_list); \ + connector = list_next_entry(connector, head)) #define drm_for_each_encoder(encoder, dev) \ list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) -- GitLab From 3a58ee106529ebea5710087e9b77bc11365665ae Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 10 Jul 2015 19:02:51 +0200 Subject: [PATCH 1470/7006] drm/i915: Use drm_for_each_fb in i915_debugfs.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just so I have a user for this macro. v2: Use the right macro - somehow I thought gcc should scream at me, but list_for_each isn't really typesafe unfortunately. Spotted by Ville. Cc: Ville Syrjälä Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_debugfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index bc817da9fef7a..51580bdd587fd 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -1866,6 +1866,7 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) struct drm_device *dev = node->minor->dev; struct intel_fbdev *ifbdev = NULL; struct intel_framebuffer *fb; + struct drm_framebuffer *drm_fb; #ifdef CONFIG_DRM_I915_FBDEV struct drm_i915_private *dev_priv = dev->dev_private; @@ -1885,7 +1886,8 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data) #endif mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, base.head) { + drm_for_each_fb(drm_fb, dev) { + fb = to_intel_framebuffer(drm_fb); if (ifbdev && &fb->base == ifbdev->helper.fb) continue; -- GitLab From 4676ba0be756b2b02b9737147713d458042962f7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:30 +0200 Subject: [PATCH 1471/7006] drm: Check locking in drm_for_each_fb Ever since framebuffers are reference counted we have a special lock for the global fb list. Make sure users of that list do hold that lock when using the new iterators. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 499562274353a..10547be5684a4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1606,6 +1606,10 @@ assert_drm_connector_list_read_locked(struct drm_mode_config *mode_config) list_for_each_entry(encoder, &(dev)->mode_config.encoder_list, head) #define drm_for_each_fb(fb, dev) \ - list_for_each_entry(fb, &(dev)->mode_config.fb_list, head) + for (WARN_ON(!mutex_is_locked(&(dev)->mode_config.fb_lock)), \ + fb = list_first_entry(&(dev)->mode_config.fb_list, \ + struct drm_framebuffer, head); \ + &fb->head != (&(dev)->mode_config.fb_list); \ + fb = list_next_entry(fb, head)) #endif /* __DRM_CRTC_H__ */ -- GitLab From 8bb4da1df54a20d68c34427356e34315ba122c0f Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:31 +0200 Subject: [PATCH 1472/7006] drm/i915: Take all modeset locks for DP MST hotplug While auditing various users of the connector/encoder lists I realized that the atomic code is a very prolific user of them. And it only ever grabs the mode_config->connection_mutex, but not the mode_config->mutex like all the other code walking encoder/connector lists. The problem is that we can't grab the mode_config.mutex late in atomic code since that would lead to locking inversions. And we don't want to grab it unconditionally like the legacy set_config modeset path since that would render all the fine-grained locking moot. Instead just grab more locks in the dp mst hotplug code. Note that drm_connector_init (which is the one adding the connector to these lists) already uses drm_modeset_lock_all. The other reason for grabbing all locks is that the dpms off in the unplug function amounts to a modeset, so better to take all required locks for that. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/intel_dp_mst.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 6e4cc5334f47d..d0b2569c62412 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -442,9 +442,9 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_mode_connector_set_path_property(connector, pathprop); drm_reinit_primary_mode_group(dev); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_connector_add_to_fbdev(intel_connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_connector_register(&intel_connector->base); return connector; } @@ -455,16 +455,16 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; /* need to nuke the connector */ - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_connector_dpms(connector, DRM_MODE_DPMS_OFF); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); intel_connector->unregister(intel_connector); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); intel_connector_remove_from_fbdev(intel_connector); drm_connector_cleanup(connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_reinit_primary_mode_group(dev); -- GitLab From 2ee6bcdcfa4d8b56b20bc6308cd5f9bced5b5324 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:32 +0200 Subject: [PATCH 1473/7006] drm/radeon: Take all modeset locks for DP MST hotplug Similar with the i915 take all modeset locks for mst hotplug. This is needed to make sure radeon holds both mode_config.mutex and mode_config.connection_mutex when updating the connector_list, which is the new (interim) locking regime we want for that. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/radeon/radeon_dp_mst.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index 257b10be5cda9..e649c8ff20a0d 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -286,9 +286,9 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_mode_connector_set_path_property(connector, pathprop); drm_reinit_primary_mode_group(dev); - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); radeon_fb_add_connector(rdev, connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_connector_register(connector); return connector; @@ -303,12 +303,12 @@ static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_unregister(connector); /* need to nuke the connector */ - mutex_lock(&dev->mode_config.mutex); + drm_modeset_lock_all(dev); /* dpms off */ radeon_fb_remove_connector(rdev, connector); drm_connector_cleanup(connector); - mutex_unlock(&dev->mode_config.mutex); + drm_modeset_unlock_all(dev); drm_reinit_primary_mode_group(dev); -- GitLab From cff20ba2758d6b82978be5b1f40536bfc121af88 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:33 +0200 Subject: [PATCH 1474/7006] drm: Amend connector list locking rules Now that dp mst hotplug takes all locks we can amend the locking rules for the iterators. This is needed before we can roll these out in the atomic code to avoid getting burried in WARNINGs. v2: Rebase onto the extracted list locking assert and add a comment to explain the rules. v3: Fixup German->English translation fail in the comment. Cc: Chris Wilson Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- include/drm/drm_crtc.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 10547be5684a4..fe3100115a41d 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1592,7 +1592,15 @@ static inline struct drm_property *drm_property_find(struct drm_device *dev, static inline void assert_drm_connector_list_read_locked(struct drm_mode_config *mode_config) { - WARN_ON(!mutex_is_locked(&mode_config->mutex)); + /* + * The connector hotadd/remove code currently grabs both locks when + * updating lists. Hence readers need only hold either of them to be + * safe and the check amounts to + * + * WARN_ON(not_holding(A) && not_holding(B)). + */ + WARN_ON(!mutex_is_locked(&mode_config->mutex) && + !drm_modeset_is_locked(&mode_config->connection_mutex)); } #define drm_for_each_connector(connector, dev) \ -- GitLab From 9a9f5ce8db176499a7f3f93172bf34176aa460f5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:34 +0200 Subject: [PATCH 1475/7006] drm: Roll out drm_for_each_connector more Now that we also grab the connection_mutex and so fixed the race with atomic modeset we can use the iterator there too. The other special case is drm_connector_unplug_all which would have a locking inversion with the sysfs store/show functions if we'd grab the mode_config.mutex around the unplug. We could just grab connection_mutex instead, but that's a bit too much a dirty trick for my taste. Also it's only used by udl, which doesn't do any other kind of connector hotplugging, so should be race-free. Hence just stick with a comment for now. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic.c | 2 +- drivers/gpu/drm/drm_atomic_helper.c | 4 ++-- drivers/gpu/drm/drm_crtc.c | 9 +++++---- drivers/gpu/drm/drm_crtc_helper.c | 6 +++--- drivers/gpu/drm/drm_edid.c | 2 +- drivers/gpu/drm/drm_plane_helper.c | 3 ++- 6 files changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index f6f2fb58eb37f..dfc8aaa1457e4 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1063,7 +1063,7 @@ drm_atomic_add_affected_connectors(struct drm_atomic_state *state, * Changed connectors are already in @state, so only need to look at the * current configuration. */ - list_for_each_entry(connector, &config->connector_list, head) { + drm_for_each_connector(connector, state->dev) { if (connector->state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5b59d5ad7d1c2..4ff334ba0382f 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -89,7 +89,7 @@ get_current_crtc_for_encoder(struct drm_device *dev, WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - list_for_each_entry(connector, &config->connector_list, head) { + drm_for_each_connector(connector, dev) { if (connector->state->best_encoder != encoder) continue; @@ -1986,7 +1986,7 @@ retry: WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - list_for_each_entry(tmp_connector, &config->connector_list, head) { + drm_for_each_connector(tmp_connector, connector->dev) { if (tmp_connector->state->crtc != crtc) continue; diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 9b05dc76379e3..d928bf7ef2219 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -988,7 +988,7 @@ unsigned int drm_connector_index(struct drm_connector *connector) WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); - list_for_each_entry(tmp, &connector->dev->mode_config.connector_list, head) { + drm_for_each_connector(tmp, connector->dev) { if (tmp == connector) return index; @@ -1054,7 +1054,7 @@ void drm_connector_unplug_all(struct drm_device *dev) { struct drm_connector *connector; - /* taking the mode config mutex ends up in a clash with sysfs */ + /* FIXME: taking the mode config mutex ends up in a clash with sysfs */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) drm_connector_unregister(connector); @@ -1726,7 +1726,7 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, group->id_list[group->num_crtcs + group->num_encoders++] = encoder->base.id; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) group->id_list[group->num_crtcs + group->num_encoders + group->num_connectors++] = connector->base.id; @@ -1810,12 +1810,13 @@ int drm_mode_getresources(struct drm_device *dev, void *data, * connector hot-adding. CRTC/Plane lists are invariant. */ mutex_lock(&dev->mode_config.mutex); if (!drm_is_primary_client(file_priv)) { + struct drm_connector *connector; mode_group = NULL; list_for_each(lh, &dev->mode_config.crtc_list) crtc_count++; - list_for_each(lh, &dev->mode_config.connector_list) + drm_for_each_connector(connector, dev) connector_count++; list_for_each(lh, &dev->mode_config.encoder_list) diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 30254fb249fed..4a83c22f5e617 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -121,7 +121,7 @@ bool drm_helper_encoder_in_use(struct drm_encoder *encoder) WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); } - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder == encoder) return true; return false; @@ -712,7 +712,7 @@ static int drm_helper_choose_encoder_dpms(struct drm_encoder *encoder) struct drm_connector *connector; struct drm_device *dev = encoder->dev; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder == encoder) if (connector->dpms < dpms) dpms = connector->dpms; @@ -746,7 +746,7 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) struct drm_connector *connector; struct drm_device *dev = crtc->dev; - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder && connector->encoder->crtc == crtc) if (connector->dpms < dpms) dpms = connector->dpms; diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 7087da37dae0b..e6e05bb75a771 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -3413,7 +3413,7 @@ struct drm_connector *drm_select_eld(struct drm_encoder *encoder, WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) if (connector->encoder == encoder && connector->eld[0]) return connector; diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 2f0ed11024eb8..7e1cde803bf30 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -91,13 +91,14 @@ static int get_connectors_for_crtc(struct drm_crtc *crtc, */ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); - list_for_each_entry(connector, &dev->mode_config.connector_list, head) + drm_for_each_connector(connector, dev) { if (connector->encoder && connector->encoder->crtc == crtc) { if (connector_list != NULL && count < num_connectors) *(connector_list++) = connector; count++; } + } return count; } -- GitLab From be559daabfaac74a7acd8cb56fae86fca7349f10 Mon Sep 17 00:00:00 2001 From: Misael Lopez Cruz Date: Wed, 22 Jul 2015 11:48:09 +0300 Subject: [PATCH 1476/7006] dmaengine: ti-dma-crossbar: Make idr xbar instance-specific In preparation for supporting multiple DMA crossbar instances, make the idr xbar instance specific. Signed-off-by: Misael Lopez Cruz Signed-off-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/ti-dma-crossbar.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 24f5ca2356bfc..1fd3fb73d6e8f 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -20,12 +20,11 @@ #define TI_XBAR_OUTPUTS 127 #define TI_XBAR_INPUTS 256 -static DEFINE_IDR(map_idr); - struct ti_dma_xbar_data { void __iomem *iomem; struct dma_router dmarouter; + struct idr map_idr; u16 safe_val; /* Value to rest the crossbar lines */ u32 xbar_requests; /* number of DMA requests connected to XBAR */ @@ -51,7 +50,7 @@ static void ti_dma_xbar_free(struct device *dev, void *route_data) map->xbar_in, map->xbar_out); ti_dma_xbar_write(xbar->iomem, map->xbar_out, xbar->safe_val); - idr_remove(&map_idr, map->xbar_out); + idr_remove(&xbar->map_idr, map->xbar_out); kfree(map); } @@ -81,7 +80,7 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, return ERR_PTR(-ENOMEM); } - map->xbar_out = idr_alloc(&map_idr, NULL, 0, xbar->dma_requests, + map->xbar_out = idr_alloc(&xbar->map_idr, NULL, 0, xbar->dma_requests, GFP_KERNEL); map->xbar_in = (u16)dma_spec->args[0]; @@ -113,6 +112,8 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) if (!xbar) return -ENOMEM; + idr_init(&xbar->map_idr); + dma_node = of_parse_phandle(node, "dma-masters", 0); if (!dma_node) { dev_err(&pdev->dev, "Can't get DMA master node\n"); -- GitLab From 1eb995bbf7a85e18f54fb162eade381320a3fcea Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Wed, 22 Jul 2015 11:48:10 +0300 Subject: [PATCH 1477/7006] dmaengine: ti-dma-crossbar: Add support for eDMA The crossbar for eDMA works exactly the same way as sDMA, but sDMA requires an offset of 1, while no offset is needed for eDMA. Based on the patch from Misael Lopez Cruz Signed-off-by: Peter Ujfalusi CC: Misael Lopez Cruz Signed-off-by: Vinod Koul --- drivers/dma/ti-dma-crossbar.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ti-dma-crossbar.c b/drivers/dma/ti-dma-crossbar.c index 1fd3fb73d6e8f..10487d91e60d4 100644 --- a/drivers/dma/ti-dma-crossbar.c +++ b/drivers/dma/ti-dma-crossbar.c @@ -20,6 +20,9 @@ #define TI_XBAR_OUTPUTS 127 #define TI_XBAR_INPUTS 256 +#define TI_XBAR_EDMA_OFFSET 0 +#define TI_XBAR_SDMA_OFFSET 1 + struct ti_dma_xbar_data { void __iomem *iomem; @@ -29,6 +32,7 @@ struct ti_dma_xbar_data { u16 safe_val; /* Value to rest the crossbar lines */ u32 xbar_requests; /* number of DMA requests connected to XBAR */ u32 dma_requests; /* number of DMA requests forwarded to DMA */ + u32 dma_offset; }; struct ti_dma_xbar_map { @@ -84,8 +88,7 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, GFP_KERNEL); map->xbar_in = (u16)dma_spec->args[0]; - /* The DMA request is 1 based in sDMA */ - dma_spec->args[0] = map->xbar_out + 1; + dma_spec->args[0] = map->xbar_out + xbar->dma_offset; dev_dbg(&pdev->dev, "Mapping XBAR%u to DMA%d\n", map->xbar_in, map->xbar_out); @@ -95,9 +98,22 @@ static void *ti_dma_xbar_route_allocate(struct of_phandle_args *dma_spec, return map; } +static const struct of_device_id ti_dma_master_match[] = { + { + .compatible = "ti,omap4430-sdma", + .data = (void *)TI_XBAR_SDMA_OFFSET, + }, + { + .compatible = "ti,edma3", + .data = (void *)TI_XBAR_EDMA_OFFSET, + }, + {}, +}; + static int ti_dma_xbar_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; + const struct of_device_id *match; struct device_node *dma_node; struct ti_dma_xbar_data *xbar; struct resource *res; @@ -120,6 +136,12 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) return -ENODEV; } + match = of_match_node(ti_dma_master_match, dma_node); + if (!match) { + dev_err(&pdev->dev, "DMA master is not supported\n"); + return -EINVAL; + } + if (of_property_read_u32(dma_node, "dma-requests", &xbar->dma_requests)) { dev_info(&pdev->dev, @@ -151,6 +173,7 @@ static int ti_dma_xbar_probe(struct platform_device *pdev) xbar->dmarouter.dev = &pdev->dev; xbar->dmarouter.route_free = ti_dma_xbar_free; + xbar->dma_offset = (u32)match->data; platform_set_drvdata(pdev, xbar); -- GitLab From 25614824685247e00b786032a504f10bfab347b1 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:55 -0300 Subject: [PATCH 1478/7006] [media] tc358743: support probe from device tree Add support for probing the TC358743 subdevice from device tree. The reference clock must be supplied using the common clock bindings. MIPI CSI-2 specific properties are parsed from the OF graph endpoint node and support for a non-continuous MIPI CSI-2 clock is added. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- .../bindings/media/i2c/tc358743.txt | 48 ++++++ drivers/media/i2c/tc358743.c | 155 +++++++++++++++++- 2 files changed, 197 insertions(+), 6 deletions(-) create mode 100644 Documentation/devicetree/bindings/media/i2c/tc358743.txt diff --git a/Documentation/devicetree/bindings/media/i2c/tc358743.txt b/Documentation/devicetree/bindings/media/i2c/tc358743.txt new file mode 100644 index 0000000000000..5218921629ed4 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/tc358743.txt @@ -0,0 +1,48 @@ +* Toshiba TC358743 HDMI-RX to MIPI CSI2-TX Bridge + +The Toshiba TC358743 HDMI-RX to MIPI CSI2-TX (H2C) is a bridge that converts +a HDMI stream to MIPI CSI-2 TX. It is programmable through I2C. + +Required Properties: + +- compatible: value should be "toshiba,tc358743" +- clocks, clock-names: should contain a phandle link to the reference clock + source, the clock input is named "refclk". + +Optional Properties: + +- reset-gpios: gpio phandle GPIO connected to the reset pin +- interrupts, interrupt-parent: GPIO connected to the interrupt pin +- data-lanes: should be <1 2 3 4> for four-lane operation, + or <1 2> for two-lane operation +- clock-lanes: should be <0> +- clock-noncontinuous: Presence of this boolean property decides whether the + MIPI CSI-2 clock is continuous or non-continuous. +- link-frequencies: List of allowed link frequencies in Hz. Each frequency is + expressed as a 64-bit big-endian integer. The frequency + is half of the bps per lane due to DDR transmission. + +For further information on the MIPI CSI-2 endpoint node properties, see +Documentation/devicetree/bindings/media/video-interfaces.txt. + +Example: + + tc358743@0f { + compatible = "toshiba,tc358743"; + reg = <0x0f>; + clocks = <&hdmi_osc>; + clock-names = "refclk"; + reset-gpios = <&gpio6 9 GPIO_ACTIVE_LOW>; + interrupt-parent = <&gpio2>; + interrupts = <5 IRQ_TYPE_LEVEL_HIGH>; + + port { + tc358743_out: endpoint { + remote-endpoint = <&mipi_csi2_in>; + data-lanes = <1 2 3 4>; + clock-lanes = <0>; + clock-noncontinuous; + link-frequencies = /bits/ 64 <297000000>; + }; + }; + }; diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 0ccae3308b68b..76d0aaa194932 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -37,6 +39,7 @@ #include #include #include +#include #include #include "tc358743_regs.h" @@ -69,6 +72,7 @@ static const struct v4l2_dv_timings_cap tc358743_timings_cap = { struct tc358743_state { struct tc358743_platform_data pdata; + struct v4l2_of_bus_mipi_csi2 bus; struct v4l2_subdev sd; struct media_pad pad; struct v4l2_ctrl_handler hdl; @@ -90,6 +94,8 @@ struct tc358743_state { struct v4l2_dv_timings timings; u32 mbus_fmt_code; + + struct gpio_desc *reset_gpio; }; static void tc358743_enable_interrupts(struct v4l2_subdev *sd, @@ -700,7 +706,8 @@ static void tc358743_set_csi(struct v4l2_subdev *sd) ((lanes > 2) ? MASK_D2M_HSTXVREGEN : 0x0) | ((lanes > 3) ? MASK_D3M_HSTXVREGEN : 0x0)); - i2c_wr32(sd, TXOPTIONCNTRL, MASK_CONTCLKMODE); + i2c_wr32(sd, TXOPTIONCNTRL, (state->bus.flags & + V4L2_MBUS_CSI2_CONTINUOUS_CLOCK) ? MASK_CONTCLKMODE : 0); i2c_wr32(sd, STARTCNTRL, MASK_START); i2c_wr32(sd, CSI_START, MASK_STRT); @@ -1638,6 +1645,136 @@ static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { /* --------------- PROBE / REMOVE --------------- */ +#ifdef CONFIG_OF +static void tc358743_gpio_reset(struct tc358743_state *state) +{ + gpiod_set_value(state->reset_gpio, 0); + usleep_range(5000, 10000); + gpiod_set_value(state->reset_gpio, 1); + usleep_range(1000, 2000); + gpiod_set_value(state->reset_gpio, 0); + msleep(20); +} + +static int tc358743_probe_of(struct tc358743_state *state) +{ + struct device *dev = &state->i2c_client->dev; + struct v4l2_of_endpoint *endpoint; + struct device_node *ep; + struct clk *refclk; + u32 bps_pr_lane; + int ret = -EINVAL; + + refclk = devm_clk_get(dev, "refclk"); + if (IS_ERR(refclk)) { + if (PTR_ERR(refclk) != -EPROBE_DEFER) + dev_err(dev, "failed to get refclk: %ld\n", + PTR_ERR(refclk)); + return PTR_ERR(refclk); + } + + ep = of_graph_get_next_endpoint(dev->of_node, NULL); + if (!ep) { + dev_err(dev, "missing endpoint node\n"); + return -EINVAL; + } + + endpoint = v4l2_of_alloc_parse_endpoint(ep); + if (IS_ERR(endpoint)) { + dev_err(dev, "failed to parse endpoint\n"); + return PTR_ERR(endpoint); + } + + if (endpoint->bus_type != V4L2_MBUS_CSI2 || + endpoint->bus.mipi_csi2.num_data_lanes == 0 || + endpoint->nr_of_link_frequencies == 0) { + dev_err(dev, "missing CSI-2 properties in endpoint\n"); + goto free_endpoint; + } + + state->bus = endpoint->bus.mipi_csi2; + + clk_prepare_enable(refclk); + + state->pdata.refclk_hz = clk_get_rate(refclk); + state->pdata.ddc5v_delay = DDC5V_DELAY_100_MS; + state->pdata.enable_hdcp = false; + /* A FIFO level of 16 should be enough for 2-lane 720p60 at 594 MHz. */ + state->pdata.fifo_level = 16; + /* + * The PLL input clock is obtained by dividing refclk by pll_prd. + * It must be between 6 MHz and 40 MHz, lower frequency is better. + */ + switch (state->pdata.refclk_hz) { + case 26000000: + case 27000000: + case 42000000: + state->pdata.pll_prd = state->pdata.refclk_hz / 6000000; + break; + default: + dev_err(dev, "unsupported refclk rate: %u Hz\n", + state->pdata.refclk_hz); + goto disable_clk; + } + + /* + * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. + * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. + */ + bps_pr_lane = 2 * endpoint->link_frequencies[0]; + if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { + dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane); + goto disable_clk; + } + + /* The CSI speed per lane is refclk / pll_prd * pll_fbd */ + state->pdata.pll_fbd = bps_pr_lane / + state->pdata.refclk_hz * state->pdata.pll_prd; + + /* + * FIXME: These timings are from REF_02 for 594 Mbps per lane (297 MHz + * link frequency). In principle it should be possible to calculate + * them based on link frequency and resolution. + */ + if (bps_pr_lane != 594000000U) + dev_warn(dev, "untested bps per lane: %u bps\n", bps_pr_lane); + state->pdata.lineinitcnt = 0xe80; + state->pdata.lptxtimecnt = 0x003; + /* tclk-preparecnt: 3, tclk-zerocnt: 20 */ + state->pdata.tclk_headercnt = 0x1403; + state->pdata.tclk_trailcnt = 0x00; + /* ths-preparecnt: 3, ths-zerocnt: 1 */ + state->pdata.ths_headercnt = 0x0103; + state->pdata.twakeup = 0x4882; + state->pdata.tclk_postcnt = 0x008; + state->pdata.ths_trailcnt = 0x2; + state->pdata.hstxvregcnt = 0; + + state->reset_gpio = devm_gpiod_get(dev, "reset"); + if (IS_ERR(state->reset_gpio)) { + dev_err(dev, "failed to get reset gpio\n"); + ret = PTR_ERR(state->reset_gpio); + goto disable_clk; + } + + tc358743_gpio_reset(state); + + ret = 0; + goto free_endpoint; + +disable_clk: + clk_disable_unprepare(refclk); +free_endpoint: + v4l2_of_free_endpoint(endpoint); + return ret; +} +#else +static inline int tc358743_probe_of(struct tc358743_state *state) +{ + return -ENODEV; +} +#endif + static int tc358743_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -1658,14 +1795,20 @@ static int tc358743_probe(struct i2c_client *client, if (!state) return -ENOMEM; + state->i2c_client = client; + /* platform data */ - if (!pdata) { - v4l_err(client, "No platform data!\n"); - return -ENODEV; + if (pdata) { + state->pdata = *pdata; + state->bus.flags = V4L2_MBUS_CSI2_CONTINUOUS_CLOCK; + } else { + err = tc358743_probe_of(state); + if (err == -ENODEV) + v4l_err(client, "No platform data!\n"); + if (err) + return err; } - state->pdata = *pdata; - state->i2c_client = client; sd = &state->sd; v4l2_i2c_subdev_init(sd, client, &tc358743_ops); sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; -- GitLab From d747b806abf41f037f7d2a076131adf8c7971a89 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 11:02:56 -0300 Subject: [PATCH 1479/7006] [media] tc358743: add direct interrupt handling When probed from device tree, the i2c client driver can handle the interrupt on its own. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 76d0aaa194932..934f6e17e06d1 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1306,6 +1307,16 @@ static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled) return 0; } +static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) +{ + struct tc358743_state *state = dev_id; + bool handled; + + tc358743_isr(&state->sd, 0, &handled); + + return handled ? IRQ_HANDLED : IRQ_NONE; +} + /* --------------- VIDEO OPS --------------- */ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) @@ -1876,6 +1887,17 @@ static int tc358743_probe(struct i2c_client *client, tc358743_set_csi_color_space(sd); tc358743_init_interrupts(sd); + + if (state->i2c_client->irq) { + err = devm_request_threaded_irq(&client->dev, + state->i2c_client->irq, + NULL, tc358743_irq_handler, + IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + "tc358743", state); + if (err) + goto err_work_queues; + } + tc358743_enable_interrupts(sd, tx_5v_power_present(sd)); i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff); -- GitLab From 1140f919f807b6d5a259ecfca88022da0e5340cb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Fri, 17 Jul 2015 12:26:45 -0300 Subject: [PATCH 1480/7006] [media] tc358743: allow event subscription This is useful to subscribe to HDMI hotplug events via the V4L2_CID_DV_RX_POWER_PRESENT control. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 934f6e17e06d1..d0dd83d7a38ea 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -859,8 +860,7 @@ static void tc358743_format_change(struct v4l2_subdev *sd) &timings, false); } - v4l2_subdev_notify(sd, V4L2_DEVICE_NOTIFY_EVENT, - (void *)&tc358743_ev_fmt); + v4l2_subdev_notify_event(sd, &tc358743_ev_fmt); } static void tc358743_init_interrupts(struct v4l2_subdev *sd) @@ -1317,6 +1317,19 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id) return handled ? IRQ_HANDLED : IRQ_NONE; } +static int tc358743_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subdev_subscribe(sd, fh, sub); + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + /* --------------- VIDEO OPS --------------- */ static int tc358743_g_input_status(struct v4l2_subdev *sd, u32 *status) @@ -1604,6 +1617,8 @@ static const struct v4l2_subdev_core_ops tc358743_core_ops = { .s_register = tc358743_s_register, #endif .interrupt_service_routine = tc358743_isr, + .subscribe_event = tc358743_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, }; static const struct v4l2_subdev_video_ops tc358743_video_ops = { -- GitLab From 9e75c0ef1428ae8a6bfb340ba2402471752c4af5 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:32:34 +0200 Subject: [PATCH 1481/7006] drm/cma-helper: Fix locking in drm_fb_cma_debugfs_show This function takes two locks, both of them the wrong ones. This wasn't an oversight from my fb locking rework since both patches landed in parallel. We really only need fb_lock when walking that list, since everything we can reach from that is refcounted properly already. v2: Drop unused dev spotted by 0day. Cc: Rob Clark Cc: Laurent Pinchart Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_fb_cma_helper.c | 16 ++-------------- drivers/gpu/drm/drm_gem_cma_helper.c | 3 --- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 5c1aca443e54f..46c4e6ee1cb1a 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -209,23 +209,11 @@ int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg) struct drm_info_node *node = (struct drm_info_node *) m->private; struct drm_device *dev = node->minor->dev; struct drm_framebuffer *fb; - int ret; - - ret = mutex_lock_interruptible(&dev->mode_config.mutex); - if (ret) - return ret; - - ret = mutex_lock_interruptible(&dev->struct_mutex); - if (ret) { - mutex_unlock(&dev->mode_config.mutex); - return ret; - } + mutex_lock(&dev->mode_config.fb_lock); list_for_each_entry(fb, &dev->mode_config.fb_list, head) drm_fb_cma_describe(fb, m); - - mutex_unlock(&dev->struct_mutex); - mutex_unlock(&dev->mode_config.mutex); + mutex_unlock(&dev->mode_config.fb_lock); return 0; } diff --git a/drivers/gpu/drm/drm_gem_cma_helper.c b/drivers/gpu/drm/drm_gem_cma_helper.c index bd75f303da63d..9edad11dca985 100644 --- a/drivers/gpu/drm/drm_gem_cma_helper.c +++ b/drivers/gpu/drm/drm_gem_cma_helper.c @@ -381,11 +381,8 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m) { struct drm_gem_object *obj = &cma_obj->base; - struct drm_device *dev = obj->dev; uint64_t off; - WARN_ON(!mutex_is_locked(&dev->struct_mutex)); - off = drm_vma_node_start(&obj->vma_node); seq_printf(m, "%2d (%2d) %08llx %pad %p %zu", -- GitLab From e4f62546325724168e0b7ee7180762cb07859ca7 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:35 +0200 Subject: [PATCH 1482/7006] drm: Roll out drm_for_each_{plane,crtc,encoder} Remaining manual work in the drm core&helpers. Nothing special here, no surprises. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 26 ++++++++++++++------------ drivers/gpu/drm/drm_crtc_helper.c | 2 +- drivers/gpu/drm/drm_fb_cma_helper.c | 2 +- drivers/gpu/drm/drm_modeset_lock.c | 7 +++---- 4 files changed, 19 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index d928bf7ef2219..138ef22078d9f 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -736,7 +736,7 @@ unsigned int drm_crtc_index(struct drm_crtc *crtc) unsigned int index = 0; struct drm_crtc *tmp; - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + drm_for_each_crtc(tmp, crtc->dev) { if (tmp == crtc) return index; @@ -1280,7 +1280,7 @@ unsigned int drm_plane_index(struct drm_plane *plane) unsigned int index = 0; struct drm_plane *tmp; - list_for_each_entry(tmp, &plane->dev->mode_config.plane_list, head) { + drm_for_each_plane(tmp, plane->dev) { if (tmp == plane) return index; @@ -1719,10 +1719,10 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev, if (ret) return ret; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_for_each_crtc(crtc, dev) group->id_list[group->num_crtcs++] = crtc->base.id; - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + drm_for_each_encoder(encoder, dev) group->id_list[group->num_crtcs + group->num_encoders++] = encoder->base.id; @@ -1811,15 +1811,17 @@ int drm_mode_getresources(struct drm_device *dev, void *data, mutex_lock(&dev->mode_config.mutex); if (!drm_is_primary_client(file_priv)) { struct drm_connector *connector; + struct drm_encoder *encoder; + struct drm_crtc *crtc; mode_group = NULL; - list_for_each(lh, &dev->mode_config.crtc_list) + drm_for_each_crtc(crtc, dev) crtc_count++; drm_for_each_connector(connector, dev) connector_count++; - list_for_each(lh, &dev->mode_config.encoder_list) + drm_for_each_encoder(encoder, dev) encoder_count++; } else { @@ -2287,7 +2289,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data, plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr; /* Plane lists are invariant, no locking needed. */ - list_for_each_entry(plane, &config->plane_list, head) { + drm_for_each_plane(plane, dev) { /* * Unless userspace set the 'universal planes' * capability bit, only advertise overlays. @@ -2592,7 +2594,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) * connectors from it), hence we need to refcount the fbs across all * crtcs. Atomic modeset will have saner semantics ... */ - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) + drm_for_each_crtc(tmp, crtc->dev) tmp->primary->old_fb = tmp->primary->fb; fb = set->fb; @@ -2603,7 +2605,7 @@ int drm_mode_set_config_internal(struct drm_mode_set *set) crtc->primary->fb = fb; } - list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) { + drm_for_each_crtc(tmp, crtc->dev) { if (tmp->primary->fb) drm_framebuffer_reference(tmp->primary->fb); if (tmp->primary->old_fb) @@ -5377,15 +5379,15 @@ void drm_mode_config_reset(struct drm_device *dev) struct drm_encoder *encoder; struct drm_connector *connector; - list_for_each_entry(plane, &dev->mode_config.plane_list, head) + drm_for_each_plane(plane, dev) if (plane->funcs->reset) plane->funcs->reset(plane); - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_for_each_crtc(crtc, dev) if (crtc->funcs->reset) crtc->funcs->reset(crtc); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + drm_for_each_encoder(encoder, dev) if (encoder->funcs->reset) encoder->funcs->reset(encoder); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index 4a83c22f5e617..2e89d8b7de18c 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -151,7 +151,7 @@ bool drm_helper_crtc_in_use(struct drm_crtc *crtc) if (!oops_in_progress) WARN_ON(!mutex_is_locked(&dev->mode_config.mutex)); - list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) + drm_for_each_encoder(encoder, dev) if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder)) return true; return false; diff --git a/drivers/gpu/drm/drm_fb_cma_helper.c b/drivers/gpu/drm/drm_fb_cma_helper.c index 46c4e6ee1cb1a..f01dc25df2dcb 100644 --- a/drivers/gpu/drm/drm_fb_cma_helper.c +++ b/drivers/gpu/drm/drm_fb_cma_helper.c @@ -211,7 +211,7 @@ int drm_fb_cma_debugfs_show(struct seq_file *m, void *arg) struct drm_framebuffer *fb; mutex_lock(&dev->mode_config.fb_lock); - list_for_each_entry(fb, &dev->mode_config.fb_list, head) + drm_for_each_fb(fb, dev) drm_fb_cma_describe(fb, m); mutex_unlock(&dev->mode_config.fb_lock); diff --git a/drivers/gpu/drm/drm_modeset_lock.c b/drivers/gpu/drm/drm_modeset_lock.c index c0a5cd8c52621..744dfbc6a329a 100644 --- a/drivers/gpu/drm/drm_modeset_lock.c +++ b/drivers/gpu/drm/drm_modeset_lock.c @@ -276,7 +276,7 @@ void drm_warn_on_modeset_not_all_locked(struct drm_device *dev) if (oops_in_progress) return; - list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + drm_for_each_crtc(crtc, dev) WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); @@ -464,18 +464,17 @@ EXPORT_SYMBOL(drm_modeset_unlock); int drm_modeset_lock_all_crtcs(struct drm_device *dev, struct drm_modeset_acquire_ctx *ctx) { - struct drm_mode_config *config = &dev->mode_config; struct drm_crtc *crtc; struct drm_plane *plane; int ret = 0; - list_for_each_entry(crtc, &config->crtc_list, head) { + drm_for_each_crtc(crtc, dev) { ret = drm_modeset_lock(&crtc->mutex, ctx); if (ret) return ret; } - list_for_each_entry(plane, &config->plane_list, head) { + drm_for_each_plane(plane, dev) { ret = drm_modeset_lock(&plane->mutex, ctx); if (ret) return ret; -- GitLab From 9c7060f7e3b09837621f93bd8666cf4cfac45001 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:36 +0200 Subject: [PATCH 1483/7006] drm: Stop filtering according to mode_group in getresources It's been dead code since forever since mode groups haven't ever been implemented. On top of that it's also been non-functional since we only ever filtered the getresources ioctl and not any of the others nor the mode object lookup code. Given overwhelming evidence it looks like this isn't a feature we need, hence remove it. Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 110 ++++++++++--------------------------- 1 file changed, 30 insertions(+), 80 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 138ef22078d9f..805ef2f408a74 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1771,12 +1771,11 @@ int drm_mode_getresources(struct drm_device *dev, void *data, int crtc_count = 0; int fb_count = 0; int encoder_count = 0; - int copied = 0, i; + int copied = 0; uint32_t __user *fb_id; uint32_t __user *crtc_id; uint32_t __user *connector_id; uint32_t __user *encoder_id; - struct drm_mode_group *mode_group; if (!drm_core_check_feature(dev, DRIVER_MODESET)) return -EINVAL; @@ -1809,27 +1808,14 @@ int drm_mode_getresources(struct drm_device *dev, void *data, /* mode_config.mutex protects the connector list against e.g. DP MST * connector hot-adding. CRTC/Plane lists are invariant. */ mutex_lock(&dev->mode_config.mutex); - if (!drm_is_primary_client(file_priv)) { - struct drm_connector *connector; - struct drm_encoder *encoder; - struct drm_crtc *crtc; - - mode_group = NULL; - drm_for_each_crtc(crtc, dev) - crtc_count++; - - drm_for_each_connector(connector, dev) - connector_count++; + drm_for_each_crtc(crtc, dev) + crtc_count++; - drm_for_each_encoder(encoder, dev) - encoder_count++; - } else { + drm_for_each_connector(connector, dev) + connector_count++; - mode_group = &file_priv->master->minor->mode_group; - crtc_count = mode_group->num_crtcs; - connector_count = mode_group->num_connectors; - encoder_count = mode_group->num_encoders; - } + drm_for_each_encoder(encoder, dev) + encoder_count++; card_res->max_height = dev->mode_config.max_height; card_res->min_height = dev->mode_config.min_height; @@ -1840,24 +1826,13 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_crtcs >= crtc_count) { copied = 0; crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr; - if (!mode_group) { - drm_for_each_crtc(crtc, dev) { - DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); - if (put_user(crtc->base.id, crtc_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } else { - for (i = 0; i < mode_group->num_crtcs; i++) { - if (put_user(mode_group->id_list[i], - crtc_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + drm_for_each_crtc(crtc, dev) { + DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id); + if (put_user(crtc->base.id, crtc_id + copied)) { + ret = -EFAULT; + goto out; } + copied++; } } card_res->count_crtcs = crtc_count; @@ -1866,27 +1841,15 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_encoders >= encoder_count) { copied = 0; encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr; - if (!mode_group) { - drm_for_each_encoder(encoder, dev) { - DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, - encoder->name); - if (put_user(encoder->base.id, encoder_id + - copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } else { - for (i = mode_group->num_crtcs; i < mode_group->num_crtcs + mode_group->num_encoders; i++) { - if (put_user(mode_group->id_list[i], - encoder_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + drm_for_each_encoder(encoder, dev) { + DRM_DEBUG_KMS("[ENCODER:%d:%s]\n", encoder->base.id, + encoder->name); + if (put_user(encoder->base.id, encoder_id + + copied)) { + ret = -EFAULT; + goto out; } - + copied++; } } card_res->count_encoders = encoder_count; @@ -1895,29 +1858,16 @@ int drm_mode_getresources(struct drm_device *dev, void *data, if (card_res->count_connectors >= connector_count) { copied = 0; connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr; - if (!mode_group) { - drm_for_each_connector(connector, dev) { - DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", - connector->base.id, - connector->name); - if (put_user(connector->base.id, - connector_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; - } - } else { - int start = mode_group->num_crtcs + - mode_group->num_encoders; - for (i = start; i < start + mode_group->num_connectors; i++) { - if (put_user(mode_group->id_list[i], - connector_id + copied)) { - ret = -EFAULT; - goto out; - } - copied++; + drm_for_each_connector(connector, dev) { + DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", + connector->base.id, + connector->name); + if (put_user(connector->base.id, + connector_id + copied)) { + ret = -EFAULT; + goto out; } + copied++; } } card_res->count_connectors = connector_count; -- GitLab From 3fdefa399e4644399ce3e74e65a75122d52dba6a Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Thu, 9 Jul 2015 23:44:37 +0200 Subject: [PATCH 1484/7006] drm: gc now dead mode_group code Two nice things here: - drm_dev_register will truly register everything in the right order if the driver doesn't have a ->load callback. Before this we had to init the primary mode_group after the device nodes where already registered. - Less things to keep track of when reworking the connector locking, yay! Reviewed-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_crtc.c | 64 -------------------------- drivers/gpu/drm/drm_drv.c | 12 ----- drivers/gpu/drm/i915/intel_dp_mst.c | 3 -- drivers/gpu/drm/radeon/radeon_dp_mst.c | 3 -- include/drm/drmP.h | 1 - include/drm/drm_crtc.h | 26 ----------- 6 files changed, 109 deletions(-) diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 805ef2f408a74..e385014ed6160 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -1679,70 +1679,6 @@ int drm_mode_create_suggested_offset_properties(struct drm_device *dev) } EXPORT_SYMBOL(drm_mode_create_suggested_offset_properties); -static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *group) -{ - uint32_t total_objects = 0; - - total_objects += dev->mode_config.num_crtc; - total_objects += dev->mode_config.num_connector; - total_objects += dev->mode_config.num_encoder; - - group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL); - if (!group->id_list) - return -ENOMEM; - - group->num_crtcs = 0; - group->num_connectors = 0; - group->num_encoders = 0; - return 0; -} - -void drm_mode_group_destroy(struct drm_mode_group *group) -{ - kfree(group->id_list); - group->id_list = NULL; -} - -/* - * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is - * the drm core's responsibility to set up mode control groups. - */ -int drm_mode_group_init_legacy_group(struct drm_device *dev, - struct drm_mode_group *group) -{ - struct drm_crtc *crtc; - struct drm_encoder *encoder; - struct drm_connector *connector; - int ret; - - ret = drm_mode_group_init(dev, group); - if (ret) - return ret; - - drm_for_each_crtc(crtc, dev) - group->id_list[group->num_crtcs++] = crtc->base.id; - - drm_for_each_encoder(encoder, dev) - group->id_list[group->num_crtcs + group->num_encoders++] = - encoder->base.id; - - drm_for_each_connector(connector, dev) - group->id_list[group->num_crtcs + group->num_encoders + - group->num_connectors++] = connector->base.id; - - return 0; -} -EXPORT_SYMBOL(drm_mode_group_init_legacy_group); - -void drm_reinit_primary_mode_group(struct drm_device *dev) -{ - drm_modeset_lock_all(dev); - drm_mode_group_destroy(&dev->primary->mode_group); - drm_mode_group_init_legacy_group(dev, &dev->primary->mode_group); - drm_modeset_unlock_all(dev); -} -EXPORT_SYMBOL(drm_reinit_primary_mode_group); - /** * drm_mode_getresources - get graphics configuration * @dev: drm device for the ioctl diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c index b7bf4ce8c012b..f7798c3b543e1 100644 --- a/drivers/gpu/drm/drm_drv.c +++ b/drivers/gpu/drm/drm_drv.c @@ -285,7 +285,6 @@ static void drm_minor_free(struct drm_device *dev, unsigned int type) if (!minor) return; - drm_mode_group_destroy(&minor->mode_group); put_device(minor->kdev); spin_lock_irqsave(&drm_minor_lock, flags); @@ -705,20 +704,9 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags) goto err_minors; } - /* setup grouping for legacy outputs */ - if (drm_core_check_feature(dev, DRIVER_MODESET)) { - ret = drm_mode_group_init_legacy_group(dev, - &dev->primary->mode_group); - if (ret) - goto err_unload; - } - ret = 0; goto out_unlock; -err_unload: - if (dev->driver->unload) - dev->driver->unload(dev); err_minors: drm_minor_unregister(dev, DRM_MINOR_LEGACY); drm_minor_unregister(dev, DRM_MINOR_RENDER); diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index d0b2569c62412..585f0a45b3f1c 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -441,7 +441,6 @@ static struct drm_connector *intel_dp_add_mst_connector(struct drm_dp_mst_topolo drm_object_attach_property(&connector->base, dev->mode_config.tile_property, 0); drm_mode_connector_set_path_property(connector, pathprop); - drm_reinit_primary_mode_group(dev); drm_modeset_lock_all(dev); intel_connector_add_to_fbdev(intel_connector); drm_modeset_unlock_all(dev); @@ -466,8 +465,6 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); - drm_reinit_primary_mode_group(dev); - kfree(intel_connector); DRM_DEBUG_KMS("\n"); } diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index e649c8ff20a0d..e4fc8f3bf58b0 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -284,7 +284,6 @@ static struct drm_connector *radeon_dp_add_mst_connector(struct drm_dp_mst_topol drm_object_attach_property(&connector->base, dev->mode_config.path_property, 0); drm_mode_connector_set_path_property(connector, pathprop); - drm_reinit_primary_mode_group(dev); drm_modeset_lock_all(dev); radeon_fb_add_connector(rdev, connector); @@ -309,8 +308,6 @@ static void radeon_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); - drm_reinit_primary_mode_group(dev); - kfree(connector); DRM_DEBUG_KMS("\n"); diff --git a/include/drm/drmP.h b/include/drm/drmP.h index 48db6a56975f5..c89351ede92c4 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h @@ -675,7 +675,6 @@ struct drm_minor { /* currently active master for this node. Protected by master_mutex */ struct drm_master *master; - struct drm_mode_group mode_group; }; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index fe3100115a41d..3071319ea1940 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1017,29 +1017,6 @@ struct drm_mode_config_funcs { void (*atomic_state_free)(struct drm_atomic_state *state); }; -/** - * struct drm_mode_group - group of mode setting resources for potential sub-grouping - * @num_crtcs: CRTC count - * @num_encoders: encoder count - * @num_connectors: connector count - * @num_bridges: bridge count - * @id_list: list of KMS object IDs in this group - * - * Currently this simply tracks the global mode setting state. But in the - * future it could allow groups of objects to be set aside into independent - * control groups for use by different user level processes (e.g. two X servers - * running simultaneously on different heads, each with their own mode - * configuration and freedom of mode setting). - */ -struct drm_mode_group { - uint32_t num_crtcs; - uint32_t num_encoders; - uint32_t num_connectors; - - /* list of object IDs for this group */ - uint32_t *id_list; -}; - /** * struct drm_mode_config - Mode configuration control structure * @mutex: mutex protecting KMS related lists and structures @@ -1324,9 +1301,6 @@ extern const char *drm_get_tv_select_name(int val); extern void drm_fb_release(struct drm_file *file_priv); extern void drm_property_destroy_user_blobs(struct drm_device *dev, struct drm_file *file_priv); -extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group); -extern void drm_mode_group_destroy(struct drm_mode_group *group); -extern void drm_reinit_primary_mode_group(struct drm_device *dev); extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); -- GitLab From dd70b27eecdd4e13378a5e253dbd426058e164ef Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Sun, 14 Jun 2015 23:01:45 -0300 Subject: [PATCH 1485/7006] [media] media: ttpci: Use vsprintf %pM extension Format mac addresses with the normal kernel extension. Signed-off-by: Joe Perches Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/ttpci-eeprom.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c index 32d43156c5482..c6f31f2712bc6 100644 --- a/drivers/media/pci/ttpci/ttpci-eeprom.c +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -162,9 +162,7 @@ int ttpci_eeprom_parse_mac(struct i2c_adapter *adapter, u8 *proposed_mac) } memcpy(proposed_mac, decodedMAC, 6); - dprintk("adapter has MAC addr = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - decodedMAC[0], decodedMAC[1], decodedMAC[2], - decodedMAC[3], decodedMAC[4], decodedMAC[5]); + dprintk("adapter has MAC addr = %pM\n", decodedMAC); return 0; } -- GitLab From 17a705e4a99bc6d810f2d64efe9368e221302f7a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 15 Jun 2015 08:33:29 -0300 Subject: [PATCH 1486/7006] [media] sh-veu: don't use COLORSPACE_JPEG COLORSPACE_JPEG should only be used for JPEGs. Use SMPTE170M instead, which is how YCbCr images are usually encoded. Signed-off-by: Hans Verkuil Acked-by: Guennadi Liakhovetski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sh_veu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index 2554f3719b9e3..7bb249cd19b8c 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -211,7 +211,7 @@ static enum v4l2_colorspace sh_veu_4cc2cspace(u32 fourcc) case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV24: - return V4L2_COLORSPACE_JPEG; + return V4L2_COLORSPACE_SMPTE170M; case V4L2_PIX_FMT_RGB332: case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_RGB565: -- GitLab From a4c4f95eb64640ec31cf0661b1a863151c744827 Mon Sep 17 00:00:00 2001 From: Sunil Shahu Date: Sat, 20 Jun 2015 05:53:50 -0300 Subject: [PATCH 1487/7006] [media] staging: media: lirc: fix coding style error Fix code indentation error by replacing tab in place of spaces. Signed-off-by: Sunil Shahu Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_sasem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c index 9e5674341abe7..b247649a99eb4 100644 --- a/drivers/staging/media/lirc/lirc_sasem.c +++ b/drivers/staging/media/lirc/lirc_sasem.c @@ -184,7 +184,7 @@ static void deregister_from_lirc(struct sasem_context *context) __func__, retval); else dev_info(&context->dev->dev, - "Deregistered Sasem driver (minor:%d)\n", minor); + "Deregistered Sasem driver (minor:%d)\n", minor); } -- GitLab From 4dc102b2f53d63207fa12a6ad49c7b6448bc3301 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Fri, 19 Jun 2015 23:58:17 -0300 Subject: [PATCH 1488/7006] [media] dvb_core: Replace memset with eth_zero_addr Use eth_zero_addr to assign the zero address to the given address array instead of memset when second argument is address of zero. The Coccinelle semantic patch that makes this change is as follows: // @eth_zero_addr@ expression e; @@ -memset(e,0x00,ETH_ALEN); +eth_zero_addr(e); // Signed-off-by: Vaishali Thakkar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index a694fb1ea2287..b81e026edab30 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -709,7 +709,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (!priv->ule_dbit) { /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ memcpy(ethh->h_dest, dest_addr, ETH_ALEN); - memset(ethh->h_source, 0, ETH_ALEN); + eth_zero_addr(ethh->h_source); } else /* zeroize source and dest */ memset( ethh, 0, ETH_ALEN*2 ); -- GitLab From 28311f8e7c3f52a810c0e0d2aa62deb549c9687d Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:22 +0300 Subject: [PATCH 1489/7006] bnx2x: Utilize FW 7.12.30 This moves bnx2x into using 7.12.30 FW. Said firmware fixes the following: - Packets from a VF with pvid configured which were sent with a different vlan were transmitted instead of being discarded. - FCoE traffic might not recover after a failue while there's traffic to another function. In addition, this FW opens the door for the driver to implement several new features; Specifically, this enhances the device's support for encapsulated packets and will allow vxlan/geneve offloads to be added in the future, as well as vlan filtering offload. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 11 ++- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 2 + .../ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 2 +- .../net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 87 +++++++++++-------- .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 2 + .../net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 53 ++++++++--- .../net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 45 ++++++---- 8 files changed, 136 insertions(+), 70 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index a90d7364334f9..fc32821c2e4d4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2103,9 +2103,14 @@ int bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj, if (rss_obj->udp_rss_v6) __set_bit(BNX2X_RSS_IPV6_UDP, ¶ms.rss_flags); - if (!CHIP_IS_E1x(bp)) + if (!CHIP_IS_E1x(bp)) { + /* valid only for TUNN_MODE_VXLAN tunnel mode */ + __set_bit(BNX2X_RSS_IPV4_VXLAN, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_IPV6_VXLAN, ¶ms.rss_flags); + /* valid only for TUNN_MODE_GRE tunnel mode */ - __set_bit(BNX2X_RSS_GRE_INNER_HDRS, ¶ms.rss_flags); + __set_bit(BNX2X_RSS_TUNN_INNER_HDRS, ¶ms.rss_flags); + } } else { __set_bit(BNX2X_RSS_MODE_DISABLED, ¶ms.rss_flags); } @@ -3677,7 +3682,7 @@ static void bnx2x_update_pbds_gso_enc(struct sk_buff *skb, pbd2->fw_ip_hdr_to_payload_w = hlen_w - ((sizeof(struct ipv6hdr)) >> 1); pbd_e2->data.tunnel_data.flags |= - ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER; + ETH_TUNNEL_DATA_IPV6_OUTER; } pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 03b7404d5b9ba..ec50d12d3198e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -936,9 +936,7 @@ static inline int bnx2x_func_start(struct bnx2x *bp) else /* CHIP_IS_E1X */ start_params->network_cos_mode = FW_WRR; - start_params->tunnel_mode = TUNN_MODE_GRE; - start_params->gre_tunnel_type = IPGRE_TUNNEL; - start_params->inner_gre_rss_en = 1; + start_params->inner_rss = 1; if (IS_MF_UFP(bp) && BNX2X_IS_MF_SD_PROTOCOL_FCOE(bp)) { start_params->class_fail_ethtype = ETH_P_FIP; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index 6e4294ed1fc99..b50f15496427e 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -1850,6 +1850,8 @@ static void bnx2x_dcbx_fw_struct(struct bnx2x *bp, if (bp->dcbx_port_params.ets.cos_params[cos]. pri_bitmask & pri_bit) tt2cos[pri].cos = cos; + + pfc_fw_cfg->dcb_outer_pri[pri] = ttp[pri]; } /* we never want the FW to add a 0 vlan tag */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index 7636e3c18771d..bfda526ffeee6 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -372,7 +372,7 @@ #define MAX_COS_NUMBER 4 #define MAX_TRAFFIC_TYPES 8 #define MAX_PFC_PRIORITIES 8 - +#define MAX_VLAN_PRIORITIES 8 /* used by array traffic_type_to_priority[] to mark traffic type \ that is not mapped to priority*/ #define LLFC_TRAFFIC_TYPE_TO_PRIORITY_UNMAPPED 0xFF diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 058bc73282201..2b6f97bc780bd 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -2898,8 +2898,8 @@ struct afex_stats { }; #define BCM_5710_FW_MAJOR_VERSION 7 -#define BCM_5710_FW_MINOR_VERSION 10 -#define BCM_5710_FW_REVISION_VERSION 51 +#define BCM_5710_FW_MINOR_VERSION 12 +#define BCM_5710_FW_REVISION_VERSION 30 #define BCM_5710_FW_ENGINEERING_VERSION 0 #define BCM_5710_FW_COMPILE_FLAGS 1 @@ -3901,7 +3901,11 @@ struct eth_fast_path_rx_cqe { __le16 len_on_bd; struct parsing_flags pars_flags; union eth_sgl_or_raw_data sgl_or_raw_data; - __le32 reserved1[7]; + u8 tunn_type; + u8 tunn_inner_hdrs_offset; + __le16 reserved1; + __le32 tunn_tenant_id; + __le32 padding[5]; u32 marker; }; @@ -4012,8 +4016,8 @@ struct eth_tunnel_data { __le16 pseudo_csum; u8 ip_hdr_start_inner_w; u8 flags; -#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER (0x1<<0) -#define ETH_TUNNEL_DATA_IP_HDR_TYPE_OUTER_SHIFT 0 +#define ETH_TUNNEL_DATA_IPV6_OUTER (0x1<<0) +#define ETH_TUNNEL_DATA_IPV6_OUTER_SHIFT 0 #define ETH_TUNNEL_DATA_RESERVED (0x7F<<1) #define ETH_TUNNEL_DATA_RESERVED_SHIFT 1 }; @@ -4120,16 +4124,12 @@ struct eth_rss_update_ramrod_data { #define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY_SHIFT 6 #define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY (0x1<<7) #define ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY_SHIFT 7 -#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY (0x1<<8) -#define ETH_RSS_UPDATE_RAMROD_DATA_EN_5_TUPLE_CAPABILITY_SHIFT 8 -#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY (0x1<<9) -#define ETH_RSS_UPDATE_RAMROD_DATA_NVGRE_KEY_ENTROPY_CAPABILITY_SHIFT 9 -#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY (0x1<<10) -#define ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY_SHIFT 10 -#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<11) -#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 11 -#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED (0xF<<12) -#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED_SHIFT 12 +#define ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY (0x1<<8) +#define ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY_SHIFT 8 +#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY (0x1<<9) +#define ETH_RSS_UPDATE_RAMROD_DATA_UPDATE_RSS_KEY_SHIFT 9 +#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED (0x3F<<10) +#define ETH_RSS_UPDATE_RAMROD_DATA_RESERVED_SHIFT 10 u8 rss_result_mask; u8 reserved3; __le16 reserved4; @@ -4314,6 +4314,18 @@ enum eth_tunnel_non_lso_csum_location { MAX_ETH_TUNNEL_NON_LSO_CSUM_LOCATION }; +enum eth_tunn_type { + TUNN_TYPE_NONE, + TUNN_TYPE_VXLAN, + TUNN_TYPE_L2_GRE, + TUNN_TYPE_IPV4_GRE, + TUNN_TYPE_IPV6_GRE, + TUNN_TYPE_L2_GENEVE, + TUNN_TYPE_IPV4_GENEVE, + TUNN_TYPE_IPV6_GENEVE, + MAX_ETH_TUNN_TYPE +}; + /* * Tx regular BD structure */ @@ -4758,6 +4770,9 @@ struct afex_vif_list_ramrod_data { __le16 reserved1; }; +struct c2s_pri_trans_table_entry { + u8 val[MAX_VLAN_PRIORITIES]; +}; /* * cfc delete event data @@ -5246,6 +5261,7 @@ struct flow_control_configuration { u8 dont_add_pri_0_en; u8 reserved1; __le32 reserved2; + u8 dcb_outer_pri[MAX_TRAFFIC_TYPES]; }; @@ -5260,18 +5276,25 @@ struct function_start_data { u8 path_id; u8 network_cos_mode; u8 dmae_cmd_id; - u8 tunnel_mode; - u8 gre_tunnel_type; - u8 tunn_clss_en; - u8 inner_gre_rss_en; - u8 sd_accept_mf_clss_fail; + u8 no_added_tags; + __le16 reserved0; + __le32 reserved1; + u8 inner_clss_vxlan; + u8 inner_clss_l2gre; + u8 inner_clss_l2geneve; + u8 inner_rss; __le16 vxlan_dst_port; + __le16 geneve_dst_port; + u8 sd_accept_mf_clss_fail; + u8 sd_accept_mf_clss_fail_match_ethtype; __le16 sd_accept_mf_clss_fail_ethtype; __le16 sd_vlan_eth_type; u8 sd_vlan_force_pri_flg; u8 sd_vlan_force_pri_val; - u8 sd_accept_mf_clss_fail_match_ethtype; - u8 no_added_tags; + u8 c2s_pri_tt_valid; + u8 c2s_pri_default; + u8 reserved2[6]; + struct c2s_pri_trans_table_entry c2s_pri_trans_table; }; struct function_update_data { @@ -5289,11 +5312,12 @@ struct function_update_data { u8 tx_switch_suspend; u8 echo; u8 update_tunn_cfg_flg; - u8 tunnel_mode; - u8 gre_tunnel_type; - u8 tunn_clss_en; - u8 inner_gre_rss_en; + u8 inner_clss_vxlan; + u8 inner_clss_l2gre; + u8 inner_clss_l2geneve; + u8 inner_rss; __le16 vxlan_dst_port; + __le16 geneve_dst_port; u8 sd_vlan_force_pri_change_flg; u8 sd_vlan_force_pri_flg; u8 sd_vlan_force_pri_val; @@ -5302,6 +5326,8 @@ struct function_update_data { u8 reserved1; __le16 sd_vlan_tag; __le16 sd_vlan_eth_type; + __le16 reserved0; + __le32 reserved2; }; /* @@ -5330,15 +5356,6 @@ struct fw_version { #define __FW_VERSION_RESERVED_SHIFT 4 }; - -/* GRE Tunnel Mode */ -enum gre_tunnel_type { - NVGRE_TUNNEL, - L2GRE_TUNNEL, - IPGRE_TUNNEL, - MAX_GRE_TUNNEL_TYPE -}; - /* * Dynamic Host-Coalescing - Driver(host) counters */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index c27af12314ed2..845471b6093f4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -5568,6 +5568,8 @@ static void bnx2x_eq_int(struct bnx2x *bp) BNX2X_STATE_OPEN): case (EVENT_RING_OPCODE_RSS_UPDATE_RULES | BNX2X_STATE_OPENING_WAIT4_PORT): + case (EVENT_RING_OPCODE_RSS_UPDATE_RULES | + BNX2X_STATE_CLOSING_WAIT4_HALT): cid = elem->message.data.eth_event.echo & BNX2X_SWCID_MASK; DP(BNX2X_MSG_SP, "got RSS_UPDATE ramrod. CID %d\n", diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 4ad415ac8cfe4..7d3f85eee63f1 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -4060,8 +4060,14 @@ static int bnx2x_setup_rss(struct bnx2x *bp, if (test_bit(BNX2X_RSS_IPV6_UDP, &p->rss_flags)) caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_UDP_CAPABILITY; - if (test_bit(BNX2X_RSS_GRE_INNER_HDRS, &p->rss_flags)) - caps |= ETH_RSS_UPDATE_RAMROD_DATA_GRE_INNER_HDRS_CAPABILITY; + if (test_bit(BNX2X_RSS_IPV4_VXLAN, &p->rss_flags)) + caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV4_VXLAN_CAPABILITY; + + if (test_bit(BNX2X_RSS_IPV6_VXLAN, &p->rss_flags)) + caps |= ETH_RSS_UPDATE_RAMROD_DATA_IPV6_VXLAN_CAPABILITY; + + if (test_bit(BNX2X_RSS_TUNN_INNER_HDRS, &p->rss_flags)) + caps |= ETH_RSS_UPDATE_RAMROD_DATA_TUNN_INNER_HDRS_CAPABILITY; /* RSS keys */ if (test_bit(BNX2X_RSS_SET_SRCH, &p->rss_flags)) { @@ -5669,10 +5675,14 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp, rdata->sd_vlan_tag = cpu_to_le16(start_params->sd_vlan_tag); rdata->path_id = BP_PATH(bp); rdata->network_cos_mode = start_params->network_cos_mode; - rdata->tunnel_mode = start_params->tunnel_mode; - rdata->gre_tunnel_type = start_params->gre_tunnel_type; - rdata->inner_gre_rss_en = start_params->inner_gre_rss_en; - rdata->vxlan_dst_port = cpu_to_le16(4789); + + rdata->vxlan_dst_port = cpu_to_le16(start_params->vxlan_dst_port); + rdata->geneve_dst_port = cpu_to_le16(start_params->geneve_dst_port); + rdata->inner_clss_l2gre = start_params->inner_clss_l2gre; + rdata->inner_clss_l2geneve = start_params->inner_clss_l2geneve; + rdata->inner_clss_vxlan = start_params->inner_clss_vxlan; + rdata->inner_rss = start_params->inner_rss; + rdata->sd_accept_mf_clss_fail = start_params->class_fail; if (start_params->class_fail_ethtype) { rdata->sd_accept_mf_clss_fail_match_ethtype = 1; @@ -5690,6 +5700,14 @@ static inline int bnx2x_func_send_start(struct bnx2x *bp, cpu_to_le16(0x8100); rdata->no_added_tags = start_params->no_added_tags; + + rdata->c2s_pri_tt_valid = start_params->c2s_pri_valid; + if (rdata->c2s_pri_tt_valid) { + memcpy(rdata->c2s_pri_trans_table.val, + start_params->c2s_pri, + MAX_VLAN_PRIORITIES); + rdata->c2s_pri_default = start_params->c2s_pri_default; + } /* No need for an explicit memory barrier here as long we would * need to ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory @@ -5750,15 +5768,22 @@ static inline int bnx2x_func_send_switch_update(struct bnx2x *bp, if (test_bit(BNX2X_F_UPDATE_TUNNEL_CFG_CHNG, &switch_update_params->changes)) { rdata->update_tunn_cfg_flg = 1; - if (test_bit(BNX2X_F_UPDATE_TUNNEL_CLSS_EN, + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GRE, + &switch_update_params->changes)) + rdata->inner_clss_l2gre = 1; + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_VXLAN, + &switch_update_params->changes)) + rdata->inner_clss_vxlan = 1; + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GENEVE, &switch_update_params->changes)) - rdata->tunn_clss_en = 1; - if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN, + rdata->inner_clss_l2geneve = 1; + if (test_bit(BNX2X_F_UPDATE_TUNNEL_INNER_RSS, &switch_update_params->changes)) - rdata->inner_gre_rss_en = 1; - rdata->tunnel_mode = switch_update_params->tunnel_mode; - rdata->gre_tunnel_type = switch_update_params->gre_tunnel_type; - rdata->vxlan_dst_port = cpu_to_le16(4789); + rdata->inner_rss = 1; + rdata->vxlan_dst_port = + cpu_to_le16(switch_update_params->vxlan_dst_port); + rdata->geneve_dst_port = + cpu_to_le16(switch_update_params->geneve_dst_port); } rdata->echo = SWITCH_UPDATE; @@ -5885,6 +5910,8 @@ static inline int bnx2x_func_send_tx_start(struct bnx2x *bp, rdata->traffic_type_to_priority_cos[i] = tx_start_params->traffic_type_to_priority_cos[i]; + for (i = 0; i < MAX_TRAFFIC_TYPES; i++) + rdata->dcb_outer_pri[i] = tx_start_params->dcb_outer_pri[i]; /* No need for an explicit memory barrier here as long as we * ensure the ordering of writing to the SPQ element * and updating of the SPQ producer which involves a memory diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index 86baecb7c60c4..df27bb8dce182 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -711,7 +711,10 @@ enum { BNX2X_RSS_IPV6, BNX2X_RSS_IPV6_TCP, BNX2X_RSS_IPV6_UDP, - BNX2X_RSS_GRE_INNER_HDRS, + + BNX2X_RSS_IPV4_VXLAN, + BNX2X_RSS_IPV6_VXLAN, + BNX2X_RSS_TUNN_INNER_HDRS, }; struct bnx2x_config_rss_params { @@ -1105,8 +1108,10 @@ enum { BNX2X_F_UPDATE_VLAN_FORCE_PRIO_CHNG, BNX2X_F_UPDATE_VLAN_FORCE_PRIO_FLAG, BNX2X_F_UPDATE_TUNNEL_CFG_CHNG, - BNX2X_F_UPDATE_TUNNEL_CLSS_EN, - BNX2X_F_UPDATE_TUNNEL_INNER_GRE_RSS_EN, + BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GRE, + BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_VXLAN, + BNX2X_F_UPDATE_TUNNEL_INNER_CLSS_L2GENEVE, + BNX2X_F_UPDATE_TUNNEL_INNER_RSS, }; /* Allowed Function states */ @@ -1171,19 +1176,23 @@ struct bnx2x_func_start_params { /* Function cos mode */ u8 network_cos_mode; - /* TUNN_MODE_NONE/TUNN_MODE_VXLAN/TUNN_MODE_GRE */ - u8 tunnel_mode; + /* UDP dest port for VXLAN */ + u16 vxlan_dst_port; - /* tunneling classification enablement */ - u8 tunn_clss_en; + /* UDP dest port for Geneve */ + u16 geneve_dst_port; - /* NVGRE_TUNNEL/L2GRE_TUNNEL/IPGRE_TUNNEL */ - u8 gre_tunnel_type; + /* Enable inner Rx classifications for L2GRE packets */ + u8 inner_clss_l2gre; - /* Enables Inner GRE RSS on the function, depends on the client RSS - * capailities - */ - u8 inner_gre_rss_en; + /* Enable inner Rx classifications for L2-Geneve packets */ + u8 inner_clss_l2geneve; + + /* Enable inner Rx classification for vxlan packets */ + u8 inner_clss_vxlan; + + /* Enable RSS according to inner header */ + u8 inner_rss; /* Allows accepting of packets failing MF classification, possibly * only matching a given ethertype @@ -1200,6 +1209,11 @@ struct bnx2x_func_start_params { /* Prevent inner vlans from being added by FW */ u8 no_added_tags; + + /* Inner-to-Outer vlan priority mapping */ + u8 c2s_pri[MAX_VLAN_PRIORITIES]; + u8 c2s_pri_default; + u8 c2s_pri_valid; }; struct bnx2x_func_switch_update_params { @@ -1207,8 +1221,8 @@ struct bnx2x_func_switch_update_params { u16 vlan; u16 vlan_eth_type; u8 vlan_force_prio; - u8 tunnel_mode; - u8 gre_tunnel_type; + u16 vxlan_dst_port; + u16 geneve_dst_port; }; struct bnx2x_func_afex_update_params { @@ -1229,6 +1243,7 @@ struct bnx2x_func_tx_start_params { u8 dcb_enabled; u8 dcb_version; u8 dont_add_pri_0_en; + u8 dcb_outer_pri[MAX_TRAFFIC_TYPES]; }; struct bnx2x_func_set_timesync_params { -- GitLab From 4ad79e1301f48b8c4ed2cc71c85e9b224a16b3e3 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:23 +0300 Subject: [PATCH 1490/7006] bnx2x: Rebrand from 'broadcom' into 'qlogic' bnx2x still appears as a Broadcom driver even though the devices it utilizes belong to Qlogic for more than a year. This patch changes the various headers and the device strings to indicate the correct ownership of the device. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_dcb.c | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_dcb.h | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_dump.h | 10 ++-- .../ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 4 +- .../ethernet/broadcom/bnx2x/bnx2x_fw_defs.h | 4 +- .../broadcom/bnx2x/bnx2x_fw_file_hdr.h | 2 + .../net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_init.h | 4 +- .../ethernet/broadcom/bnx2x/bnx2x_init_ops.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_link.c | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_link.h | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 50 ++++++++++--------- .../ethernet/broadcom/bnx2x/bnx2x_mfw_req.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_sp.c | 14 +++--- .../net/ethernet/broadcom/bnx2x/bnx2x_sp.h | 14 +++--- .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.h | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_stats.c | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_stats.h | 4 +- .../net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c | 10 ++-- .../net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h | 22 +++++--- 25 files changed, 142 insertions(+), 88 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index cd4ae76bbff2f..a59f0b9520383 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1,6 +1,8 @@ -/* bnx2x.h: Broadcom Everest network driver. +/* bnx2x.h: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index fc32821c2e4d4..e395ae9943078 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -1,6 +1,8 @@ -/* bnx2x_cmn.c: Broadcom Everest network driver. +/* bnx2x_cmn.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index ec50d12d3198e..77693d34acc98 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -1,6 +1,8 @@ -/* bnx2x_cmn.h: Broadcom Everest network driver. +/* bnx2x_cmn.h: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c index b50f15496427e..7ccf6684e0a32 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.c @@ -1,15 +1,17 @@ -/* bnx2x_dcb.c: Broadcom Everest network driver. +/* bnx2x_dcb.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h index c6939ecb02c57..9a9517c0f703f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dcb.h @@ -1,15 +1,17 @@ -/* bnx2x_dcb.h: Broadcom Everest network driver. +/* bnx2x_dcb.h: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h index 741aa130c19f4..eccfa13b0f2d5 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_dump.h @@ -1,15 +1,17 @@ -/* bnx2x_dump.h: Broadcom Everest network driver. +/* bnx2x_dump.h: QLogic Everest network driver. * * Copyright (c) 2012-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index c783b57b2c9b8..fd3631b1a3781 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1,6 +1,8 @@ -/* bnx2x_ethtool.c: Broadcom Everest network driver. +/* bnx2x_ethtool.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h index bfda526ffeee6..226ab29f4cb6a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_defs.h @@ -1,6 +1,8 @@ -/* bnx2x_fw_defs.h: Broadcom Everest network driver. +/* bnx2x_fw_defs.h: Qlogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h index 8aafd9b5d6a2b..9e3b5a1e9f4f4 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_fw_file_hdr.h @@ -1,6 +1,8 @@ /* bnx2x_fw_file_hdr.h: FW binary file header structure. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 2b6f97bc780bd..a838b6e8f1591 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -1,6 +1,8 @@ -/* bnx2x_hsi.h: Broadcom Everest network driver. +/* bnx2x_hsi.h: Qlogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h index d6e1975b7b691..46ee2c01f4c51 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init.h @@ -1,7 +1,9 @@ -/* bnx2x_init.h: Broadcom Everest network driver. +/* bnx2x_init.h: Qlogic Everest network driver. * Structures and macroes needed during the initialization. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h index 5669ed2e87d00..1835d2e451c01 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_init_ops.h @@ -1,8 +1,10 @@ -/* bnx2x_init_ops.h: Broadcom Everest network driver. +/* bnx2x_init_ops.h: Qlogic Everest network driver. * Static functions needed during the initialization. * This file is "included" in bnx2x_main.c. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index a0b03c27e0a30..7f9ec51cfe69f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -1,13 +1,15 @@ /* Copyright 2008-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Written by Yaniv Rosner diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h index d9cce4c3899b7..b7d251108c19f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.h @@ -1,13 +1,15 @@ /* Copyright 2008-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Written by Yaniv Rosner diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 845471b6093f4..e85e6ffa4e61b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -1,6 +1,8 @@ -/* bnx2x_main.c: Broadcom Everest network driver. +/* bnx2x_main.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 @@ -81,11 +83,11 @@ #define TX_TIMEOUT (5*HZ) static char version[] = - "Broadcom NetXtreme II 5771x/578xx 10/20-Gigabit Ethernet Driver " + "QLogic 5771x/578xx 10/20-Gigabit Ethernet Driver " DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; MODULE_AUTHOR("Eliezer Tamir"); -MODULE_DESCRIPTION("Broadcom NetXtreme II " +MODULE_DESCRIPTION("QLogic " "BCM57710/57711/57711E/" "57712/57712_MF/57800/57800_MF/57810/57810_MF/" "57840/57840_MF Driver"); @@ -163,27 +165,27 @@ enum bnx2x_board_type { static struct { char *name; } board_info[] = { - [BCM57710] = { "Broadcom NetXtreme II BCM57710 10 Gigabit PCIe [Everest]" }, - [BCM57711] = { "Broadcom NetXtreme II BCM57711 10 Gigabit PCIe" }, - [BCM57711E] = { "Broadcom NetXtreme II BCM57711E 10 Gigabit PCIe" }, - [BCM57712] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet" }, - [BCM57712_MF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Multi Function" }, - [BCM57712_VF] = { "Broadcom NetXtreme II BCM57712 10 Gigabit Ethernet Virtual Function" }, - [BCM57800] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet" }, - [BCM57800_MF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Multi Function" }, - [BCM57800_VF] = { "Broadcom NetXtreme II BCM57800 10 Gigabit Ethernet Virtual Function" }, - [BCM57810] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet" }, - [BCM57810_MF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Multi Function" }, - [BCM57810_VF] = { "Broadcom NetXtreme II BCM57810 10 Gigabit Ethernet Virtual Function" }, - [BCM57840_4_10] = { "Broadcom NetXtreme II BCM57840 10 Gigabit Ethernet" }, - [BCM57840_2_20] = { "Broadcom NetXtreme II BCM57840 20 Gigabit Ethernet" }, - [BCM57840_MF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" }, - [BCM57840_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" }, - [BCM57811] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet" }, - [BCM57811_MF] = { "Broadcom NetXtreme II BCM57811 10 Gigabit Ethernet Multi Function" }, - [BCM57840_O] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet" }, - [BCM57840_MFO] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Multi Function" }, - [BCM57811_VF] = { "Broadcom NetXtreme II BCM57840 10/20 Gigabit Ethernet Virtual Function" } + [BCM57710] = { "QLogic BCM57710 10 Gigabit PCIe [Everest]" }, + [BCM57711] = { "QLogic BCM57711 10 Gigabit PCIe" }, + [BCM57711E] = { "QLogic BCM57711E 10 Gigabit PCIe" }, + [BCM57712] = { "QLogic BCM57712 10 Gigabit Ethernet" }, + [BCM57712_MF] = { "QLogic BCM57712 10 Gigabit Ethernet Multi Function" }, + [BCM57712_VF] = { "QLogic BCM57712 10 Gigabit Ethernet Virtual Function" }, + [BCM57800] = { "QLogic BCM57800 10 Gigabit Ethernet" }, + [BCM57800_MF] = { "QLogic BCM57800 10 Gigabit Ethernet Multi Function" }, + [BCM57800_VF] = { "QLogic BCM57800 10 Gigabit Ethernet Virtual Function" }, + [BCM57810] = { "QLogic BCM57810 10 Gigabit Ethernet" }, + [BCM57810_MF] = { "QLogic BCM57810 10 Gigabit Ethernet Multi Function" }, + [BCM57810_VF] = { "QLogic BCM57810 10 Gigabit Ethernet Virtual Function" }, + [BCM57840_4_10] = { "QLogic BCM57840 10 Gigabit Ethernet" }, + [BCM57840_2_20] = { "QLogic BCM57840 20 Gigabit Ethernet" }, + [BCM57840_MF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Multi Function" }, + [BCM57840_VF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Virtual Function" }, + [BCM57811] = { "QLogic BCM57811 10 Gigabit Ethernet" }, + [BCM57811_MF] = { "QLogic BCM57811 10 Gigabit Ethernet Multi Function" }, + [BCM57840_O] = { "QLogic BCM57840 10/20 Gigabit Ethernet" }, + [BCM57840_MFO] = { "QLogic BCM57840 10/20 Gigabit Ethernet Multi Function" }, + [BCM57811_VF] = { "QLogic BCM57840 10/20 Gigabit Ethernet Virtual Function" } }; #ifndef PCI_DEVICE_ID_NX2_57710 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h index caf1aef651eb0..a91ccbf363451 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_mfw_req.h @@ -1,6 +1,8 @@ -/* bnx2x_mfw_req.h: Broadcom Everest network driver. +/* bnx2x_mfw_req.h: Qlogic Everest network driver. * * Copyright (c) 2012-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index 49d511092c82f..b7d33a1deb77b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -1,6 +1,8 @@ -/* bnx2x_reg.h: Broadcom Everest network driver. +/* bnx2x_reg.h: Qlogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c index 7d3f85eee63f1..265fe0a90adc0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.c @@ -1,15 +1,17 @@ -/* bnx2x_sp.c: Broadcom Everest network driver. +/* bnx2x_sp.c: Qlogic Everest network driver. * - * Copyright (c) 2011-2013 Broadcom Corporation + * Copyright 2011-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and Qlogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h index df27bb8dce182..324e9f986314c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sp.h @@ -1,15 +1,17 @@ -/* bnx2x_sp.h: Broadcom Everest network driver. +/* bnx2x_sp.h: Qlogic Everest network driver. * - * Copyright (c) 2011-2013 Broadcom Corporation + * Copyright 2011-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and Qlogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * at http://www.gnu.org/licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other Qlogic software provided under a + * license other than the GPL, without Qlogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index f67348d169667..4d5c7b3d3a327 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1,15 +1,17 @@ -/* bnx2x_sriov.c: Broadcom Everest network driver. +/* bnx2x_sriov.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h index 66ee62a0401a8..2011205ec8d46 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.h @@ -1,15 +1,17 @@ -/* bnx2x_sriov.h: Broadcom Everest network driver. +/* bnx2x_sriov.h: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c index 69d699f0730a3..7e0919aa450e7 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.c @@ -1,6 +1,8 @@ -/* bnx2x_stats.c: Broadcom Everest network driver. +/* bnx2x_stats.c: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h index 965539a9dabe7..b2644ed13d064 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_stats.h @@ -1,6 +1,8 @@ -/* bnx2x_stats.h: Broadcom Everest network driver. +/* bnx2x_stats.h: QLogic Everest network driver. * * Copyright (c) 2007-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * * 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 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c index 06b8c0d8fd3b1..31b79bd13292d 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.c @@ -1,15 +1,17 @@ -/* bnx2x_vfpf.c: Broadcom Everest network driver. +/* bnx2x_vfpf.c: QLogic Everest network driver. * * Copyright 2009-2013 Broadcom Corporation + * Copyright 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and QLogic execute a separate written software license * agreement governing use of this software, this software is licensed to you * under the terms of the GNU General Public License version 2, available * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). * * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written + * software in any way with any other QLogic software provided under a + * license other than the GPL, without QLogic's express prior written * consent. * * Maintained by: Ariel Elior diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h index b86479fc0d2f8..f0110f4bd0a34 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_vfpf.h @@ -1,16 +1,22 @@ -/* bnx2x_vfpf.h: Broadcom Everest network driver. +/* bnx2x_vfpf.h: Qlogic Everest network driver. * * Copyright (c) 2011-2013 Broadcom Corporation + * Copyright (c) 2014 QLogic Corporation + * All rights reserved * - * Unless you and Broadcom execute a separate written software license + * Unless you and Qlogic execute a separate written software license * agreement governing use of this software, this software is licensed to you - * under the terms of the GNU General Public License version 2, available - * at http://www.gnu.org/licenses/old-licenses/gpl-2.0.html (the "GPL"). + * under the terms of the GNU General Public License version 2 (the “GPL”), + * available at http://www.gnu.org/licenses/gpl-2.0.html, with the following + * added to such license: * - * Notwithstanding the above, under no circumstances may you combine this - * software in any way with any other Broadcom software provided under a - * license other than the GPL, without Broadcom's express prior written - * consent. + * As a special exception, the copyright holders of this software give you + * permission to link this software with independent modules, and to copy and + * distribute the resulting executable under terms of your choice, provided that + * you also meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module which is + * not derived from this software. The special exception does not apply to any + * modifications of the software. * * Maintained by: Ariel Elior * Written by: Ariel Elior -- GitLab From 924c6216f88172050a519639722e949b838529cc Mon Sep 17 00:00:00 2001 From: Yaniv Rosner Date: Wed, 22 Jul 2015 09:16:24 +0300 Subject: [PATCH 1491/7006] bnx2x: Add 84858 phy support This adds support to a new copper phy. Signed-off-by: Yaniv Rosner Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 3 + .../net/ethernet/broadcom/bnx2x/bnx2x_link.c | 244 ++++++++++++++---- .../net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 58 +++-- 3 files changed, 232 insertions(+), 73 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index a838b6e8f1591..5425de059aae8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -731,6 +731,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8722 0x00000f00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54616 0x00001000 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84834 0x00001100 + #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84858 0x00001200 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN 0x0000ff00 @@ -788,6 +789,7 @@ struct port_hw_cfg { /* port 0: 0x12c port 1: 0x2bc */ #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722 0x00000f00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616 0x00001000 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834 0x00001100 + #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858 0x00001200 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT_WC 0x0000fc00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE 0x0000fd00 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN 0x0000ff00 @@ -2253,6 +2255,7 @@ struct shmem2_region { u32 reserved4; /* Offset 0x150 */ u32 link_attr_sync[PORT_MAX]; /* Offset 0x154 */ #define LINK_ATTR_SYNC_KR2_ENABLE 0x00000001 + #define LINK_ATTR_84858 0x00000002 #define LINK_SFP_EEPROM_COMP_CODE_MASK 0x0000ff00 #define LINK_SFP_EEPROM_COMP_CODE_SHIFT 8 #define LINK_SFP_EEPROM_COMP_CODE_SR 0x00001000 diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c index 7f9ec51cfe69f..d946bba43726f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_link.c @@ -9654,6 +9654,13 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy, /******************************************************************/ /* BCM8481/BCM84823/BCM84833 PHY SECTION */ /******************************************************************/ +static int bnx2x_is_8483x_8485x(struct bnx2x_phy *phy) +{ + return ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || + (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834) || + (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858)); +} + static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, struct bnx2x *bp, u8 port) @@ -9668,8 +9675,7 @@ static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy, }; u16 fw_ver1; - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (bnx2x_is_8483x_8485x(phy)) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, 0x400f, &fw_ver1); bnx2x_save_spirom_version(bp, port, fw_ver1 & 0xfff, phy->ver_addr); @@ -9751,8 +9757,7 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp, bnx2x_cl45_write(bp, phy, reg_set[i].devad, reg_set[i].reg, reg_set[i].val); - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) + if (bnx2x_is_8483x_8485x(phy)) offset = MDIO_PMA_REG_84833_CTL_LED_CTL_1; else offset = MDIO_PMA_REG_84823_CTL_LED_CTL_1; @@ -9770,8 +9775,7 @@ static void bnx2x_848xx_specific_func(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; switch (action) { case PHY_INIT: - if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) && - (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (!bnx2x_is_8483x_8485x(phy)) { /* Save spirom version */ bnx2x_save_848xx_spirom_version(phy, bp, params->port); } @@ -9903,8 +9907,7 @@ static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy, /* Always write this if this is not 84833/4. * For 84833/4, write it only when it's a forced speed. */ - if (((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) && - (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) || + if (!bnx2x_is_8483x_8485x(phy) || ((autoneg_val & (1<<12)) == 0)) bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, @@ -9951,8 +9954,86 @@ static int bnx2x_8481_config_init(struct bnx2x_phy *phy, return bnx2x_848xx_cmn_config_init(phy, params, vars); } -#define PHY84833_CMDHDLR_WAIT 300 -#define PHY84833_CMDHDLR_MAX_ARGS 5 +#define PHY848xx_CMDHDLR_WAIT 300 +#define PHY848xx_CMDHDLR_MAX_ARGS 5 + +static int bnx2x_84858_cmd_hdlr(struct bnx2x_phy *phy, + struct link_params *params, + u16 fw_cmd, + u16 cmd_args[], int argc) +{ + int idx; + u16 val; + struct bnx2x *bp = params->bp; + + /* Step 1: Poll the STATUS register to see whether the previous command + * is in progress or the system is busy (CMD_IN_PROGRESS or + * SYSTEM_BUSY). If previous command is in progress or system is busy, + * check again until the previous command finishes execution and the + * system is available for taking command + */ + + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_STATUS, &val); + if ((val != PHY84858_STATUS_CMD_IN_PROGRESS) && + (val != PHY84858_STATUS_CMD_SYSTEM_BUSY)) + break; + usleep_range(1000, 2000); + } + if (idx >= PHY848xx_CMDHDLR_WAIT) { + DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n"); + return -EINVAL; + } + + /* Step2: If any parameters are required for the function, write them + * to the required DATA registers + */ + + for (idx = 0; idx < argc; idx++) { + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_DATA1 + idx, + cmd_args[idx]); + } + + /* Step3: When the firmware is ready for commands, write the 'Command + * code' to the CMD register + */ + bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd); + + /* Step4: Once the command has been written, poll the STATUS register + * to check whether the command has completed (CMD_COMPLETED_PASS/ + * CMD_FOR_CMDS or CMD_COMPLETED_ERROR). + */ + + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_STATUS, &val); + if ((val == PHY84858_STATUS_CMD_COMPLETE_PASS) || + (val == PHY84858_STATUS_CMD_COMPLETE_ERROR)) + break; + usleep_range(1000, 2000); + } + if ((idx >= PHY848xx_CMDHDLR_WAIT) || + (val == PHY84858_STATUS_CMD_COMPLETE_ERROR)) { + DP(NETIF_MSG_LINK, "FW cmd failed.\n"); + return -EINVAL; + } + /* Step5: Once the command has completed, read the specficied DATA + * registers for any saved results for the command, if applicable + */ + + /* Gather returning data */ + for (idx = 0; idx < argc; idx++) { + bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, + MDIO_848xx_CMD_HDLR_DATA1 + idx, + &cmd_args[idx]); + } + + return 0; +} + static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy, struct link_params *params, u16 fw_cmd, u16 cmd_args[], int argc) @@ -9962,16 +10043,16 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; /* Write CMD_OPEN_OVERRIDE to STATUS reg */ bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, + MDIO_848xx_CMD_HDLR_STATUS, PHY84833_STATUS_CMD_OPEN_OVERRIDE); - for (idx = 0; idx < PHY84833_CMDHDLR_WAIT; idx++) { + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, &val); + MDIO_848xx_CMD_HDLR_STATUS, &val); if (val == PHY84833_STATUS_CMD_OPEN_FOR_CMDS) break; usleep_range(1000, 2000); } - if (idx >= PHY84833_CMDHDLR_WAIT) { + if (idx >= PHY848xx_CMDHDLR_WAIT) { DP(NETIF_MSG_LINK, "FW cmd: FW not ready.\n"); return -EINVAL; } @@ -9979,42 +10060,62 @@ static int bnx2x_84833_cmd_hdlr(struct bnx2x_phy *phy, /* Prepare argument(s) and issue command */ for (idx = 0; idx < argc; idx++) { bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_DATA1 + idx, + MDIO_848xx_CMD_HDLR_DATA1 + idx, cmd_args[idx]); } bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_COMMAND, fw_cmd); - for (idx = 0; idx < PHY84833_CMDHDLR_WAIT; idx++) { + MDIO_848xx_CMD_HDLR_COMMAND, fw_cmd); + for (idx = 0; idx < PHY848xx_CMDHDLR_WAIT; idx++) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, &val); + MDIO_848xx_CMD_HDLR_STATUS, &val); if ((val == PHY84833_STATUS_CMD_COMPLETE_PASS) || - (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) + (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) break; usleep_range(1000, 2000); } - if ((idx >= PHY84833_CMDHDLR_WAIT) || - (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) { + if ((idx >= PHY848xx_CMDHDLR_WAIT) || + (val == PHY84833_STATUS_CMD_COMPLETE_ERROR)) { DP(NETIF_MSG_LINK, "FW cmd failed.\n"); return -EINVAL; } /* Gather returning data */ for (idx = 0; idx < argc; idx++) { bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_DATA1 + idx, + MDIO_848xx_CMD_HDLR_DATA1 + idx, &cmd_args[idx]); } bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD, - MDIO_84833_CMD_HDLR_STATUS, + MDIO_848xx_CMD_HDLR_STATUS, PHY84833_STATUS_CMD_CLEAR_COMPLETE); return 0; } -static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy, - struct link_params *params, - struct link_vars *vars) +static int bnx2x_848xx_cmd_hdlr(struct bnx2x_phy *phy, + struct link_params *params, + u16 fw_cmd, + u16 cmd_args[], int argc) +{ + struct bnx2x *bp = params->bp; + + if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) || + (REG_RD(bp, params->shmem2_base + + offsetof(struct shmem2_region, + link_attr_sync[params->port])) & + LINK_ATTR_84858)) { + return bnx2x_84858_cmd_hdlr(phy, params, fw_cmd, cmd_args, + argc); + } else { + return bnx2x_84833_cmd_hdlr(phy, params, fw_cmd, cmd_args, + argc); + } +} + +static int bnx2x_848xx_pair_swap_cfg(struct bnx2x_phy *phy, + struct link_params *params, + struct link_vars *vars) { u32 pair_swap; - u16 data[PHY84833_CMDHDLR_MAX_ARGS]; + u16 data[PHY848xx_CMDHDLR_MAX_ARGS]; int status; struct bnx2x *bp = params->bp; @@ -10030,8 +10131,9 @@ static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy, /* Only the second argument is used for this command */ data[1] = (u16)pair_swap; - status = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_PAIR_SWAP, data, PHY84833_CMDHDLR_MAX_ARGS); + status = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_PAIR_SWAP, data, + PHY848xx_CMDHDLR_MAX_ARGS); if (status == 0) DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data[1]); @@ -10120,8 +10222,8 @@ static int bnx2x_8483x_disable_eee(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Don't Advertise 10GBase-T EEE\n"); /* Prevent Phy from working in EEE and advertising it */ - rc = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1); + rc = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1); if (rc) { DP(NETIF_MSG_LINK, "EEE disable failed.\n"); return rc; @@ -10138,8 +10240,8 @@ static int bnx2x_8483x_enable_eee(struct bnx2x_phy *phy, struct bnx2x *bp = params->bp; u16 cmd_args = 1; - rc = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_EEE_MODE, &cmd_args, 1); + rc = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_EEE_MODE, &cmd_args, 1); if (rc) { DP(NETIF_MSG_LINK, "EEE enable failed.\n"); return rc; @@ -10157,7 +10259,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, u8 port, initialize = 1; u16 val; u32 actual_phy_selection; - u16 cmd_args[PHY84833_CMDHDLR_MAX_ARGS]; + u16 cmd_args[PHY848xx_CMDHDLR_MAX_ARGS]; int rc = 0; usleep_range(1000, 2000); @@ -10182,8 +10284,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, /* Wait for GPHY to come out of reset */ msleep(50); - if ((phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) && - (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (!bnx2x_is_8483x_8485x(phy)) { /* BCM84823 requires that XGXS links up first @ 10G for normal * behavior. */ @@ -10194,7 +10295,19 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, bnx2x_program_serdes(¶ms->phy[INT_PHY], params, vars); vars->line_speed = temp; } + /* Check if this is actually BCM84858 */ + if (phy->type != PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858) { + u16 hw_rev; + bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, + MDIO_AN_REG_848xx_ID_MSB, &hw_rev); + if (hw_rev == BCM84858_PHY_ID) { + params->link_attr_sync |= LINK_ATTR_84858; + bnx2x_update_link_attr(params, params->link_attr_sync); + } + } + + /* Set dual-media configuration according to configuration */ bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD, MDIO_CTL_REG_84823_MEDIA, &val); val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK | @@ -10239,18 +10352,17 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n", params->multi_phy_config, val); - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { - bnx2x_84833_pair_swap_cfg(phy, params, vars); + if (bnx2x_is_8483x_8485x(phy)) { + bnx2x_848xx_pair_swap_cfg(phy, params, vars); /* Keep AutogrEEEn disabled. */ cmd_args[0] = 0x0; cmd_args[1] = 0x0; cmd_args[2] = PHY84833_CONSTANT_LATENCY + 1; cmd_args[3] = PHY84833_CONSTANT_LATENCY; - rc = bnx2x_84833_cmd_hdlr(phy, params, - PHY84833_CMD_SET_EEE_MODE, cmd_args, - PHY84833_CMDHDLR_MAX_ARGS); + rc = bnx2x_848xx_cmd_hdlr(phy, params, + PHY848xx_CMD_SET_EEE_MODE, cmd_args, + PHY848xx_CMDHDLR_MAX_ARGS); if (rc) DP(NETIF_MSG_LINK, "Cfg AutogrEEEn failed.\n"); } @@ -10304,8 +10416,7 @@ static int bnx2x_848x3_config_init(struct bnx2x_phy *phy, vars->eee_status &= ~SHMEM_EEE_SUPPORTED_MASK; } - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) { + if (bnx2x_is_8483x_8485x(phy)) { /* Bring PHY out of super isolate mode as the final step. */ bnx2x_cl45_read_and_write(bp, phy, MDIO_CTL_DEVAD, @@ -10437,8 +10548,7 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy, LINK_STATUS_LINK_PARTNER_10GXFD_CAPABLE; /* Determine if EEE was negotiated */ - if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) + if (bnx2x_is_8483x_8485x(phy)) bnx2x_eee_an_resolve(phy, params, vars); } @@ -11844,6 +11954,40 @@ static const struct bnx2x_phy phy_84834 = { .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func }; +static const struct bnx2x_phy phy_84858 = { + .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858, + .addr = 0xff, + .def_md_devad = 0, + .flags = FLAGS_FAN_FAILURE_DET_REQ | + FLAGS_REARM_LATCH_SIGNAL, + .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff}, + .mdio_ctrl = 0, + .supported = (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full | + SUPPORTED_10000baseT_Full | + SUPPORTED_TP | + SUPPORTED_Autoneg | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause), + .media_type = ETH_PHY_BASE_T, + .ver_addr = 0, + .req_flow_ctrl = 0, + .req_line_speed = 0, + .speed_cap_mask = 0, + .req_duplex = 0, + .rsrv = 0, + .config_init = (config_init_t)bnx2x_848x3_config_init, + .read_status = (read_status_t)bnx2x_848xx_read_status, + .link_reset = (link_reset_t)bnx2x_848x3_link_reset, + .config_loopback = (config_loopback_t)NULL, + .format_fw_ver = (format_fw_ver_t)bnx2x_848xx_format_ver, + .hw_reset = (hw_reset_t)bnx2x_84833_hw_reset_phy, + .set_link_led = (set_link_led_t)bnx2x_848xx_set_link_led, + .phy_specific_func = (phy_specific_func_t)bnx2x_848xx_specific_func +}; + static const struct bnx2x_phy phy_54618se = { .type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE, .addr = 0xff, @@ -12130,6 +12274,9 @@ static int bnx2x_populate_ext_phy(struct bnx2x *bp, case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834: *phy = phy_84834; break; + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858: + *phy = phy_84858; + break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54616: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM54618SE: *phy = phy_54618se; @@ -12186,9 +12333,7 @@ static int bnx2x_populate_ext_phy(struct bnx2x *bp, } phy->mdio_ctrl = bnx2x_get_emac_base(bp, mdc_mdio_access, port); - if (((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) || - (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834)) && - (phy->ver_addr)) { + if (bnx2x_is_8483x_8485x(phy) && (phy->ver_addr)) { /* Remove 100Mb link supported for BCM84833/4 when phy fw * version lower than or equal to 1.39 */ @@ -13283,6 +13428,7 @@ static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[], break; case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833: case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84834: + case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84858: /* GPIO3's are linked, and so both need to be toggled * to obtain required 2us pulse. */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index b7d33a1deb77b..f18bf511d854b 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -7242,6 +7242,9 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_AN_REG_8481_LEGACY_MII_CTRL 0xffe0 #define MDIO_AN_REG_8481_MII_CTRL_FORCE_1G 0x40 #define MDIO_AN_REG_8481_LEGACY_MII_STATUS 0xffe1 +#define MDIO_AN_REG_848xx_ID_MSB 0xffe2 +#define BCM84858_PHY_ID 0x600d +#define MDIO_AN_REG_848xx_ID_LSB 0xffe3 #define MDIO_AN_REG_8481_LEGACY_AN_ADV 0xffe4 #define MDIO_AN_REG_8481_LEGACY_AN_EXPANSION 0xffe6 #define MDIO_AN_REG_8481_1000T_CTRL 0xffe9 @@ -7285,31 +7288,31 @@ Theotherbitsarereservedandshouldbezero*/ #define MDIO_84833_TOP_CFG_FW_NO_EEE 0x1f81 #define MDIO_84833_TOP_CFG_XGPHY_STRAP1 0x401a #define MDIO_84833_SUPER_ISOLATE 0x8000 -/* These are mailbox register set used by 84833. */ -#define MDIO_84833_TOP_CFG_SCRATCH_REG0 0x4005 -#define MDIO_84833_TOP_CFG_SCRATCH_REG1 0x4006 -#define MDIO_84833_TOP_CFG_SCRATCH_REG2 0x4007 -#define MDIO_84833_TOP_CFG_SCRATCH_REG3 0x4008 -#define MDIO_84833_TOP_CFG_SCRATCH_REG4 0x4009 -#define MDIO_84833_TOP_CFG_SCRATCH_REG26 0x4037 -#define MDIO_84833_TOP_CFG_SCRATCH_REG27 0x4038 -#define MDIO_84833_TOP_CFG_SCRATCH_REG28 0x4039 -#define MDIO_84833_TOP_CFG_SCRATCH_REG29 0x403a -#define MDIO_84833_TOP_CFG_SCRATCH_REG30 0x403b -#define MDIO_84833_TOP_CFG_SCRATCH_REG31 0x403c -#define MDIO_84833_CMD_HDLR_COMMAND MDIO_84833_TOP_CFG_SCRATCH_REG0 -#define MDIO_84833_CMD_HDLR_STATUS MDIO_84833_TOP_CFG_SCRATCH_REG26 -#define MDIO_84833_CMD_HDLR_DATA1 MDIO_84833_TOP_CFG_SCRATCH_REG27 -#define MDIO_84833_CMD_HDLR_DATA2 MDIO_84833_TOP_CFG_SCRATCH_REG28 -#define MDIO_84833_CMD_HDLR_DATA3 MDIO_84833_TOP_CFG_SCRATCH_REG29 -#define MDIO_84833_CMD_HDLR_DATA4 MDIO_84833_TOP_CFG_SCRATCH_REG30 -#define MDIO_84833_CMD_HDLR_DATA5 MDIO_84833_TOP_CFG_SCRATCH_REG31 +/* These are mailbox register set used by 84833/84858. */ +#define MDIO_848xx_TOP_CFG_SCRATCH_REG0 0x4005 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG1 0x4006 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG2 0x4007 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG3 0x4008 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG4 0x4009 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG26 0x4037 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG27 0x4038 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG28 0x4039 +#define MDIO_848xx_TOP_CFG_SCRATCH_REG29 0x403a +#define MDIO_848xx_TOP_CFG_SCRATCH_REG30 0x403b +#define MDIO_848xx_TOP_CFG_SCRATCH_REG31 0x403c +#define MDIO_848xx_CMD_HDLR_COMMAND (MDIO_848xx_TOP_CFG_SCRATCH_REG0) +#define MDIO_848xx_CMD_HDLR_STATUS (MDIO_848xx_TOP_CFG_SCRATCH_REG26) +#define MDIO_848xx_CMD_HDLR_DATA1 (MDIO_848xx_TOP_CFG_SCRATCH_REG27) +#define MDIO_848xx_CMD_HDLR_DATA2 (MDIO_848xx_TOP_CFG_SCRATCH_REG28) +#define MDIO_848xx_CMD_HDLR_DATA3 (MDIO_848xx_TOP_CFG_SCRATCH_REG29) +#define MDIO_848xx_CMD_HDLR_DATA4 (MDIO_848xx_TOP_CFG_SCRATCH_REG30) +#define MDIO_848xx_CMD_HDLR_DATA5 (MDIO_848xx_TOP_CFG_SCRATCH_REG31) -/* Mailbox command set used by 84833. */ -#define PHY84833_CMD_SET_PAIR_SWAP 0x8001 -#define PHY84833_CMD_GET_EEE_MODE 0x8008 -#define PHY84833_CMD_SET_EEE_MODE 0x8009 -/* Mailbox status set used by 84833. */ +/* Mailbox command set used by 84833/84858 */ +#define PHY848xx_CMD_SET_PAIR_SWAP 0x8001 +#define PHY848xx_CMD_GET_EEE_MODE 0x8008 +#define PHY848xx_CMD_SET_EEE_MODE 0x8009 +/* Mailbox status set used by 84833 only */ #define PHY84833_STATUS_CMD_RECEIVED 0x0001 #define PHY84833_STATUS_CMD_IN_PROGRESS 0x0002 #define PHY84833_STATUS_CMD_COMPLETE_PASS 0x0004 @@ -7320,6 +7323,13 @@ Theotherbitsarereservedandshouldbezero*/ #define PHY84833_STATUS_CMD_CLEAR_COMPLETE 0x0080 #define PHY84833_STATUS_CMD_OPEN_OVERRIDE 0xa5a5 +/* Mailbox status set used by 84858 only */ +#define PHY84858_STATUS_CMD_RECEIVED 0x0001 +#define PHY84858_STATUS_CMD_IN_PROGRESS 0x0002 +#define PHY84858_STATUS_CMD_COMPLETE_PASS 0x0004 +#define PHY84858_STATUS_CMD_COMPLETE_ERROR 0x0008 +#define PHY84858_STATUS_CMD_SYSTEM_BUSY 0xbbbb + /* Warpcore clause 45 addressing */ #define MDIO_WC_DEVAD 0x3 -- GitLab From 230d00eb4bfe0ddc88b848fd953f7b871ee2ecd7 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:25 +0300 Subject: [PATCH 1492/7006] bnx2x: new Multi-function mode - BD This adds support to a new multi-function mode, enabling driver to initialize such devices and correctly interacting with management FW for fully utilizing their features. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 3 + .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 74 ++++++++++++++++++- .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.h | 36 +++++++++ .../ethernet/broadcom/bnx2x/bnx2x_ethtool.c | 3 + .../net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 74 +++++++++++++++++++ .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 56 +++++++++++--- .../net/ethernet/broadcom/bnx2x/bnx2x_reg.h | 17 ++++- .../net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 3 + 8 files changed, 251 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index a59f0b9520383..ecf1d7f6ab279 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -1424,6 +1424,7 @@ enum { SUB_MF_MODE_UNKNOWN = 0, SUB_MF_MODE_UFP, SUB_MF_MODE_NPAR1_DOT_5, + SUB_MF_MODE_BD, }; struct bnx2x { @@ -1638,6 +1639,8 @@ struct bnx2x { u8 mf_sub_mode; #define IS_MF_UFP(bp) (IS_MF_SD(bp) && \ bp->mf_sub_mode == SUB_MF_MODE_UFP) +#define IS_MF_BD(bp) (IS_MF_SD(bp) && \ + bp->mf_sub_mode == SUB_MF_MODE_BD) u8 wol; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index e395ae9943078..b1d16d34551df 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2517,6 +2517,20 @@ static void bnx2x_bz_fp(struct bnx2x *bp, int index) fp->mode = TPA_MODE_DISABLED; } +void bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state) +{ + u32 cur; + + if (!IS_MF_BD(bp) || !SHMEM2_HAS(bp, os_driver_state) || IS_VF(bp)) + return; + + cur = SHMEM2_RD(bp, os_driver_state[BP_FW_MB_IDX(bp)]); + DP(NETIF_MSG_IFUP, "Driver state %08x-->%08x\n", + cur, state); + + SHMEM2_WR(bp, os_driver_state[BP_FW_MB_IDX(bp)], state); +} + int bnx2x_load_cnic(struct bnx2x *bp) { int i, rc, port = BP_PORT(bp); @@ -2880,6 +2894,8 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) /* mark driver is loaded in shmem2 */ u32 val; val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]); + val &= ~DRV_FLAGS_MTU_MASK; + val |= (bp->dev->mtu << DRV_FLAGS_MTU_SHIFT); SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)], val | DRV_FLAGS_CAPABILITIES_LOADED_SUPPORTED | DRV_FLAGS_CAPABILITIES_LOADED_L2); @@ -2896,6 +2912,9 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG)) bnx2x_dcbx_init(bp, false); + if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_ACTIVE); + DP(NETIF_MSG_IFUP, "Ending successfully NIC load\n"); return 0; @@ -2963,6 +2982,9 @@ int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) DP(NETIF_MSG_IFUP, "Starting NIC unload\n"); + if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED); + /* mark driver is unloaded in shmem2 */ if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { u32 val; @@ -4191,6 +4213,41 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +void bnx2x_get_c2s_mapping(struct bnx2x *bp, u8 *c2s_map, u8 *c2s_default) +{ + int mfw_vn = BP_FW_MB_IDX(bp); + u32 tmp; + + /* If the shmem shouldn't affect configuration, reflect */ + if (!IS_MF_BD(bp)) { + int i; + + for (i = 0; i < BNX2X_MAX_PRIORITY; i++) + c2s_map[i] = i; + *c2s_default = 0; + + return; + } + + tmp = SHMEM2_RD(bp, c2s_pcp_map_lower[mfw_vn]); + tmp = (__force u32)be32_to_cpu((__force __be32)tmp); + c2s_map[0] = tmp & 0xff; + c2s_map[1] = (tmp >> 8) & 0xff; + c2s_map[2] = (tmp >> 16) & 0xff; + c2s_map[3] = (tmp >> 24) & 0xff; + + tmp = SHMEM2_RD(bp, c2s_pcp_map_upper[mfw_vn]); + tmp = (__force u32)be32_to_cpu((__force __be32)tmp); + c2s_map[4] = tmp & 0xff; + c2s_map[5] = (tmp >> 8) & 0xff; + c2s_map[6] = (tmp >> 16) & 0xff; + c2s_map[7] = (tmp >> 24) & 0xff; + + tmp = SHMEM2_RD(bp, c2s_pcp_map_default[mfw_vn]); + tmp = (__force u32)be32_to_cpu((__force __be32)tmp); + *c2s_default = (tmp >> (8 * mfw_vn)) & 0xff; +} + /** * bnx2x_setup_tc - routine to configure net_device for multi tc * @@ -4201,8 +4258,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) */ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc) { - int cos, prio, count, offset; struct bnx2x *bp = netdev_priv(dev); + u8 c2s_map[BNX2X_MAX_PRIORITY], c2s_def; + int cos, prio, count, offset; /* setup tc must be called under rtnl lock */ ASSERT_RTNL(); @@ -4226,12 +4284,16 @@ int bnx2x_setup_tc(struct net_device *dev, u8 num_tc) return -EINVAL; } + bnx2x_get_c2s_mapping(bp, c2s_map, &c2s_def); + /* configure priority to traffic class mapping */ for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) { - netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[prio]); + int outer_prio = c2s_map[prio]; + + netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[outer_prio]); DP(BNX2X_MSG_SP | NETIF_MSG_IFUP, "mapping priority %d to tc %d\n", - prio, bp->prio_to_cos[prio]); + outer_prio, bp->prio_to_cos[outer_prio]); } /* Use this configuration to differentiate tc0 from other COSes @@ -4285,6 +4347,9 @@ int bnx2x_change_mac_addr(struct net_device *dev, void *p) if (netif_running(dev)) rc = bnx2x_set_eth_mac(bp, true); + if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg)) + SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); + return rc; } @@ -4838,6 +4903,9 @@ int bnx2x_change_mtu(struct net_device *dev, int new_mtu) */ dev->mtu = new_mtu; + if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg)) + SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); + return bnx2x_reload_if_running(dev); } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h index 77693d34acc98..821346ce50eb8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h @@ -622,6 +622,14 @@ int bnx2x_set_features(struct net_device *dev, netdev_features_t features); */ void bnx2x_tx_timeout(struct net_device *dev); +/** bnx2x_get_c2s_mapping - read inner-to-outer vlan configuration + * c2s_map should have BNX2X_MAX_PRIORITY entries. + * @bp: driver handle + * @c2s_map: should have BNX2X_MAX_PRIORITY entries for mapping + * @c2s_default: entry for non-tagged configuration + */ +void bnx2x_get_c2s_mapping(struct bnx2x *bp, u8 *c2s_map, u8 *c2s_default); + /*********************** Inlines **********************************/ /*********************** Fast path ********************************/ static inline void bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp) @@ -933,6 +941,27 @@ static inline int bnx2x_func_start(struct bnx2x *bp) start_params->mf_mode = bp->mf_mode; start_params->sd_vlan_tag = bp->mf_ov; + /* Configure Ethertype for BD mode */ + if (IS_MF_BD(bp)) { + DP(NETIF_MSG_IFUP, "Configuring ethertype 0x88a8 for BD\n"); + start_params->sd_vlan_eth_type = ETH_P_8021AD; + REG_WR(bp, PRS_REG_VLAN_TYPE_0, ETH_P_8021AD); + REG_WR(bp, PBF_REG_VLAN_TYPE_0, ETH_P_8021AD); + REG_WR(bp, NIG_REG_LLH_E1HOV_TYPE_1, ETH_P_8021AD); + + bnx2x_get_c2s_mapping(bp, start_params->c2s_pri, + &start_params->c2s_pri_default); + start_params->c2s_pri_valid = 1; + + DP(NETIF_MSG_IFUP, + "Inner-to-Outer priority: %02x %02x %02x %02x %02x %02x %02x %02x [Default %02x]\n", + start_params->c2s_pri[0], start_params->c2s_pri[1], + start_params->c2s_pri[2], start_params->c2s_pri[3], + start_params->c2s_pri[4], start_params->c2s_pri[5], + start_params->c2s_pri[6], start_params->c2s_pri[7], + start_params->c2s_pri_default); + } + if (CHIP_IS_E2(bp) || CHIP_IS_E3(bp)) start_params->network_cos_mode = STATIC_COS; else /* CHIP_IS_E1X */ @@ -1339,4 +1368,11 @@ void bnx2x_squeeze_objects(struct bnx2x *bp); void bnx2x_schedule_sp_rtnl(struct bnx2x*, enum sp_rtnl_flag, u32 verbose); +/** + * bnx2x_set_os_driver_state - write driver state for management FW usage + * + * @bp: driver handle + * @state: OS_DRIVER_STATE_* value reflecting current driver state + */ +void bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state); #endif /* BNX2X_CMN_H */ diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c index fd3631b1a3781..6b2050a198df8 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c @@ -1131,6 +1131,9 @@ static int bnx2x_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } else bp->wol = 0; + if (SHMEM2_HAS(bp, curr_cfg)) + SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); + return 0; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 5425de059aae8..23960df7e595a 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -868,6 +868,7 @@ struct shared_feat_cfg { /* NVRAM Offset */ #define SHARED_FEAT_CFG_FORCE_SF_MODE_SPIO4 0x00000200 #define SHARED_FEAT_CFG_FORCE_SF_MODE_SWITCH_INDEPT 0x00000300 #define SHARED_FEAT_CFG_FORCE_SF_MODE_AFEX_MODE 0x00000400 + #define SHARED_FEAT_CFG_FORCE_SF_MODE_BD_MODE 0x00000500 #define SHARED_FEAT_CFG_FORCE_SF_MODE_UFP_MODE 0x00000600 #define SHARED_FEAT_CFG_FORCE_SF_MODE_EXTENDED_MODE 0x00000700 @@ -2068,6 +2069,12 @@ struct ncsi_oem_fcoe_features { #define FCOE_FEATURES4_FEATURE_SETTINGS_OFFSET 0 }; +enum curr_cfg_method_e { + CURR_CFG_MET_NONE = 0, /* default config */ + CURR_CFG_MET_OS = 1, + CURR_CFG_MET_VENDOR_SPEC = 2,/* e.g. Option ROM, NPAR, O/S Cfg Utils */ +}; + struct ncsi_oem_data { u32 driver_version[4]; struct ncsi_oem_fcoe_features ncsi_oem_fcoe_features; @@ -2191,6 +2198,8 @@ struct shmem2_region { #define DRV_FLAGS_CAPABILITIES_LOADED_L2 0x00000002 #define DRV_FLAGS_CAPABILITIES_LOADED_FCOE 0x00000004 #define DRV_FLAGS_CAPABILITIES_LOADED_ISCSI 0x00000008 +#define DRV_FLAGS_MTU_MASK 0xffff0000 +#define DRV_FLAGS_MTU_SHIFT 16 u32 extended_dev_info_shared_cfg_size; @@ -2273,6 +2282,71 @@ struct shmem2_region { /* We use indication for each PF (0..3) */ #define MFW_DRV_IND_READ_DONE_OFFSET(_pf_) (1 << (_pf_)) + union { /* For various OEMs */ /* Offset 0x1a0 */ + u8 storage_boot_prog[E2_FUNC_MAX]; + #define STORAGE_BOOT_PROG_MASK 0x000000FF + #define STORAGE_BOOT_PROG_NONE 0x00000000 + #define STORAGE_BOOT_PROG_ISCSI_IP_ACQUIRED 0x00000002 + #define STORAGE_BOOT_PROG_FCOE_FABRIC_LOGIN_SUCCESS 0x00000002 + #define STORAGE_BOOT_PROG_TARGET_FOUND 0x00000004 + #define STORAGE_BOOT_PROG_ISCSI_CHAP_SUCCESS 0x00000008 + #define STORAGE_BOOT_PROG_FCOE_LUN_FOUND 0x00000008 + #define STORAGE_BOOT_PROG_LOGGED_INTO_TGT 0x00000010 + #define STORAGE_BOOT_PROG_IMG_DOWNLOADED 0x00000020 + #define STORAGE_BOOT_PROG_OS_HANDOFF 0x00000040 + #define STORAGE_BOOT_PROG_COMPLETED 0x00000080 + + u32 oem_i2c_data_addr; + }; + + /* 9 entires for the C2S PCP map for each inner VLAN PCP + 1 default */ + /* For PCP values 0-3 use the map lower */ + /* 0xFF000000 - PCP 0, 0x00FF0000 - PCP 1, + * 0x0000FF00 - PCP 2, 0x000000FF PCP 3 + */ + u32 c2s_pcp_map_lower[E2_FUNC_MAX]; /* 0x1a4 */ + + /* For PCP values 4-7 use the map upper */ + /* 0xFF000000 - PCP 4, 0x00FF0000 - PCP 5, + * 0x0000FF00 - PCP 6, 0x000000FF PCP 7 + */ + u32 c2s_pcp_map_upper[E2_FUNC_MAX]; /* 0x1b4 */ + + /* For PCP default value get the MSB byte of the map default */ + u32 c2s_pcp_map_default[E2_FUNC_MAX]; /* 0x1c4 */ + + /* FC_NPIV table offset in NVRAM */ + u32 fc_npiv_nvram_tbl_addr[PORT_MAX]; /* 0x1d4 */ + + /* Shows last method that changed configuration of this device */ + enum curr_cfg_method_e curr_cfg; /* 0x1dc */ + + /* Storm FW version, shold be kept in the format 0xMMmmbbdd: + * MM - Major, mm - Minor, bb - Build ,dd - Drop + */ + u32 netproc_fw_ver; /* 0x1e0 */ + + /* Option ROM SMASH CLP version */ + u32 clp_ver; /* 0x1e4 */ + + u32 pcie_bus_num; /* 0x1e8 */ + + u32 sriov_switch_mode; /* 0x1ec */ + #define SRIOV_SWITCH_MODE_NONE 0x0 + #define SRIOV_SWITCH_MODE_VEB 0x1 + #define SRIOV_SWITCH_MODE_VEPA 0x2 + + u8 rsrv2[E2_FUNC_MAX]; /* 0x1f0 */ + + u32 img_inv_table_addr; /* Address to INV_TABLE_P */ /* 0x1f4 */ + + u32 mtu_size[E2_FUNC_MAX]; /* 0x1f8 */ + + u32 os_driver_state[E2_FUNC_MAX]; /* 0x208 */ + #define OS_DRIVER_STATE_NOT_LOADED 0 /* not installed */ + #define OS_DRIVER_STATE_LOADING 1 /* transition state */ + #define OS_DRIVER_STATE_DISABLED 2 /* installed but disabled */ + #define OS_DRIVER_STATE_ACTIVE 3 /* installed and active */ }; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index e85e6ffa4e61b..0a069fa8e1fb9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -2918,7 +2918,7 @@ static void bnx2x_handle_update_svid_cmd(struct bnx2x *bp) func_params.f_obj = &bp->func_obj; func_params.cmd = BNX2X_F_CMD_SWITCH_UPDATE; - if (IS_MF_UFP(bp)) { + if (IS_MF_UFP(bp) || IS_MF_BD(bp)) { int func = BP_ABS_FUNC(bp); u32 val; @@ -2945,16 +2945,16 @@ static void bnx2x_handle_update_svid_cmd(struct bnx2x *bp) BNX2X_ERR("Failed to configure FW of S-tag Change to %02x\n", bp->mf_ov); goto fail; + } else { + DP(BNX2X_MSG_MCP, "Configured S-tag %02x\n", + bp->mf_ov); } - - DP(BNX2X_MSG_MCP, "Configured S-tag %02x\n", bp->mf_ov); - - bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_OK, 0); - - return; + } else { + goto fail; } - /* not supported by SW yet */ + bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_OK, 0); + return; fail: bnx2x_fw_command(bp, DRV_MSG_CODE_OEM_UPDATE_SVID_FAILURE, 0); } @@ -7433,6 +7433,9 @@ static int bnx2x_init_hw_common(struct bnx2x *bp) } else BNX2X_ERR("Bootcode is missing - can not initialize link\n"); + if (SHMEM2_HAS(bp, netproc_fw_ver)) + SHMEM2_WR(bp, netproc_fw_ver, REG_RD(bp, XSEM_REG_PRAM)); + return 0; } @@ -11682,7 +11685,7 @@ static void validate_set_si_mode(struct bnx2x *bp) static int bnx2x_get_hwinfo(struct bnx2x *bp) { int /*abs*/func = BP_ABS_FUNC(bp); - int vn; + int vn, mfw_vn; u32 val = 0, val2 = 0; int rc = 0; @@ -11772,6 +11775,7 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp) bp->mf_mode = 0; bp->mf_sub_mode = 0; vn = BP_VN(bp); + mfw_vn = BP_FW_MB_IDX(bp); if (!CHIP_IS_E1(bp) && !BP_NOMCP(bp)) { BNX2X_DEV_INFO("shmem2base 0x%x, size %d, mfcfg offset %d\n", @@ -11828,6 +11832,31 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp) } else BNX2X_DEV_INFO("illegal OV for SD\n"); break; + case SHARED_FEAT_CFG_FORCE_SF_MODE_BD_MODE: + bp->mf_mode = MULTI_FUNCTION_SD; + bp->mf_sub_mode = SUB_MF_MODE_BD; + bp->mf_config[vn] = + MF_CFG_RD(bp, + func_mf_config[func].config); + + if (SHMEM2_HAS(bp, mtu_size)) { + int mtu_idx = BP_FW_MB_IDX(bp); + u16 mtu_size; + u32 mtu; + + mtu = SHMEM2_RD(bp, mtu_size[mtu_idx]); + mtu_size = (u16)mtu; + DP(NETIF_MSG_IFUP, "Read MTU size %04x [%08x]\n", + mtu_size, mtu); + + /* if valid: update device mtu */ + if (((mtu_size + ETH_HLEN) >= + ETH_MIN_PACKET_SIZE) && + (mtu_size <= + ETH_MAX_JUMBO_PACKET_SIZE)) + bp->dev->mtu = mtu_size; + } + break; case SHARED_FEAT_CFG_FORCE_SF_MODE_UFP_MODE: bp->mf_mode = MULTI_FUNCTION_SD; bp->mf_sub_mode = SUB_MF_MODE_UFP; @@ -11875,9 +11904,10 @@ static int bnx2x_get_hwinfo(struct bnx2x *bp) BNX2X_DEV_INFO("MF OV for func %d is %d (0x%04x)\n", func, bp->mf_ov, bp->mf_ov); - } else if (bp->mf_sub_mode == SUB_MF_MODE_UFP) { + } else if ((bp->mf_sub_mode == SUB_MF_MODE_UFP) || + (bp->mf_sub_mode == SUB_MF_MODE_BD)) { dev_err(&bp->pdev->dev, - "Unexpected - no valid MF OV for func %d in UFP mode\n", + "Unexpected - no valid MF OV for func %d in UFP/BD mode\n", func); bp->path_has_ovlan = true; } else { @@ -13565,6 +13595,9 @@ static int bnx2x_init_one(struct pci_dev *pdev, bnx2x_register_phc(bp); + if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED); + return 0; init_one_exit: @@ -13627,6 +13660,7 @@ static void __bnx2x_remove(struct pci_dev *pdev, /* Power on: we can't let PCI layer write to us while we are in D3 */ if (IS_PF(bp)) { bnx2x_set_power_state(bp, PCI_D0); + bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_NOT_LOADED); /* Set endianity registers to reset values in case next driver * boots in different endianty environment. diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h index f18bf511d854b..4dead49bd5cb0 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_reg.h @@ -2139,6 +2139,10 @@ /* [RW 1] When this bit is set; the LLH will expect all packets to be with e1hov */ #define NIG_REG_LLH_E1HOV_MODE 0x160d8 +/* [RW 16] Outer VLAN type identifier for multi-function mode. In non + * multi-function mode; it will hold the inner VLAN type. Typically 0x8100. + */ +#define NIG_REG_LLH_E1HOV_TYPE_1 0x16028 /* [RW 1] When this bit is set; the LLH will classify the packet before sending it to the BRB or calculating WoL on it. */ #define NIG_REG_LLH_MF_MODE 0x16024 @@ -2955,7 +2959,12 @@ #define PBF_REG_TQ_OCCUPANCY_Q0 0x1403ac /* [R 13] Number of 8 bytes lines occupied in the task queue of queue 1. */ #define PBF_REG_TQ_OCCUPANCY_Q1 0x1403b0 -#define PB_REG_CONTROL 0 +/* [RW 16] One of 8 values that should be compared to type in Ethernet + * parsing. If there is a match; the field after Ethernet is the first VLAN. + * Reset value is 0x8100 which is the standard VLAN type. Note that when + * checking second VLAN; type is compared only to 0x8100. + */ +#define PBF_REG_VLAN_TYPE_0 0x15c06c /* [RW 2] Interrupt mask register #0 read/write */ #define PB_REG_PB_INT_MASK 0x28 /* [R 2] Interrupt register #0 read */ @@ -3374,6 +3383,12 @@ #define PRS_REG_TCM_CURRENT_CREDIT 0x40160 /* [R 8] debug only: TSDM current credit. Transaction based. */ #define PRS_REG_TSDM_CURRENT_CREDIT 0x4015c +/* [RW 16] One of 8 values that should be compared to type in Ethernet + * parsing. If there is a match; the field after Ethernet is the first VLAN. + * Reset value is 0x8100 which is the standard VLAN type. Note that when + * checking second VLAN; type is compared only to 0x8100. + */ +#define PRS_REG_VLAN_TYPE_0 0x401a8 #define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_AFT (0x1<<19) #define PXP2_PXP2_INT_MASK_0_REG_PGL_CPL_OF (0x1<<20) #define PXP2_PXP2_INT_MASK_0_REG_PGL_PCIE_ATTN (0x1<<22) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 4d5c7b3d3a327..5b243bcec3faa 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -1340,6 +1340,9 @@ int bnx2x_iov_init_one(struct bnx2x *bp, int int_mode_param, mutex_init(&bp->vfdb->bulletin_mutex); + if (SHMEM2_HAS(bp, sriov_switch_mode)) + SHMEM2_WR(bp, sriov_switch_mode, SRIOV_SWITCH_MODE_VEB); + return 0; failed: DP(BNX2X_MSG_IOV, "Failed err=%d\n", err); -- GitLab From c48f350ff5e75abae2627c2531780264f9e49130 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:26 +0300 Subject: [PATCH 1493/7006] bnx2x: Add MFW dump support Devices with up-to-date management FW will be able to store register dumps on their persistent storage - in case management FW identifies a fatal error it would gather and store such dumps, which could later be retrieved using specific debug tools. This patch adds the necessary part in the driver in order to make the feature operational, as well as update users [under debug] during load in case their device contains a dump of a previous crash. Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 ++ .../net/ethernet/broadcom/bnx2x/bnx2x_cmn.c | 4 +++ .../net/ethernet/broadcom/bnx2x/bnx2x_hsi.h | 17 +++++++++++ .../net/ethernet/broadcom/bnx2x/bnx2x_main.c | 28 +++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index ecf1d7f6ab279..2fe3563d25286 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -2582,6 +2582,8 @@ void bnx2x_set_local_cmng(struct bnx2x *bp); void bnx2x_update_mng_version(struct bnx2x *bp); +void bnx2x_update_mfw_dump(struct bnx2x *bp); + #define MCPR_SCRATCH_BASE(bp) \ (CHIP_IS_E1x(bp) ? MCP_REG_MCPR_SCRATCH : MCP_A_REG_MCPR_SCRATCH) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c index b1d16d34551df..6088c86c48727 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c @@ -2908,6 +2908,10 @@ int bnx2x_nic_load(struct bnx2x *bp, int load_mode) return -EBUSY; } + /* Update driver data for On-Chip MFW dump. */ + if (IS_PF(bp)) + bnx2x_update_mfw_dump(bp); + /* If PMF - send ADMIN DCBX msg to MFW to initiate DCBX FSM */ if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG)) bnx2x_dcbx_init(bp, false); diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h index 23960df7e595a..08a08fa49caad 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_hsi.h @@ -2075,6 +2075,20 @@ enum curr_cfg_method_e { CURR_CFG_MET_VENDOR_SPEC = 2,/* e.g. Option ROM, NPAR, O/S Cfg Utils */ }; +struct mdump_driver_info { + u32 epoc; + u32 drv_ver; + u32 fw_ver; + + u32 valid_dump; + #define FIRST_DUMP_VALID (1 << 0) + #define SECOND_DUMP_VALID (1 << 1) + + u32 flags; + #define ENABLE_ALL_TRIGGERS (0x7fffffff) + #define TRIGGER_MDUMP_ONCE (1 << 31) +}; + struct ncsi_oem_data { u32 driver_version[4]; struct ncsi_oem_fcoe_features ncsi_oem_fcoe_features; @@ -2347,6 +2361,9 @@ struct shmem2_region { #define OS_DRIVER_STATE_LOADING 1 /* transition state */ #define OS_DRIVER_STATE_DISABLED 2 /* installed but disabled */ #define OS_DRIVER_STATE_ACTIVE 3 /* installed and active */ + + /* mini dump driver info */ + struct mdump_driver_info drv_info; /* 0x218 */ }; diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 0a069fa8e1fb9..78e55fe616e3c 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -3709,6 +3709,34 @@ out: ethver, iscsiver, fcoever); } +void bnx2x_update_mfw_dump(struct bnx2x *bp) +{ + struct timeval epoc; + u32 drv_ver; + u32 valid_dump; + + if (!SHMEM2_HAS(bp, drv_info)) + return; + + /* Update Driver load time */ + do_gettimeofday(&epoc); + SHMEM2_WR(bp, drv_info.epoc, epoc.tv_sec); + + drv_ver = bnx2x_update_mng_version_utility(DRV_MODULE_VERSION, true); + SHMEM2_WR(bp, drv_info.drv_ver, drv_ver); + + SHMEM2_WR(bp, drv_info.fw_ver, REG_RD(bp, XSEM_REG_PRAM)); + + /* Check & notify On-Chip dump. */ + valid_dump = SHMEM2_RD(bp, drv_info.valid_dump); + + if (valid_dump & FIRST_DUMP_VALID) + DP(NETIF_MSG_IFUP, "A valid On-Chip MFW dump found on 1st partition\n"); + + if (valid_dump & SECOND_DUMP_VALID) + DP(NETIF_MSG_IFUP, "A valid On-Chip MFW dump found on 2nd partition\n"); +} + static void bnx2x_oem_event(struct bnx2x *bp, u32 event) { u32 cmd_ok, cmd_fail; -- GitLab From 3a375e3caf2b424386f9e32d0c55f8907c52981d Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Wed, 22 Jul 2015 09:16:27 +0300 Subject: [PATCH 1494/7006] bnx2x: Bump up driver version to 1.712.30 Signed-off-by: Yuval Mintz Signed-off-by: Ariel Elior Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h index 2fe3563d25286..a1f9785f02094 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h @@ -32,7 +32,7 @@ * (you will need to reboot afterwards) */ /* #define BNX2X_STOP_ON_ERROR */ -#define DRV_MODULE_VERSION "1.710.51-0" +#define DRV_MODULE_VERSION "1.712.30-0" #define DRV_MODULE_RELDATE "2014/02/10" #define BNX2X_BC_VER 0x040200 -- GitLab From de18547d48c0e735309d6874852f048352e08a88 Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 21 Jul 2015 22:49:00 -0700 Subject: [PATCH 1495/7006] mpls_iptunnel: fix sparse warn: remove incorrect rcu_dereference fix for: net/mpls/mpls_iptunnel.c:73:19: sparse: incompatible types in comparison expression (different address spaces) remove incorrect rcu_dereference possibly left over from earlier revisions of the code. Reported-by: kbuild test robot Signed-off-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/mpls/mpls_iptunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c index eea096f21ba58..276f8c9922184 100644 --- a/net/mpls/mpls_iptunnel.c +++ b/net/mpls/mpls_iptunnel.c @@ -70,7 +70,7 @@ int mpls_output(struct sock *sk, struct sk_buff *skb) skb_orphan(skb); /* Find the output device */ - out_dev = rcu_dereference(dst->dev); + out_dev = dst->dev; if (!mpls_output_possible(out_dev) || !lwtstate || skb_warn_if_lro(skb)) goto drop; -- GitLab From fb02eb4a29303295f2fed8a69d9aa703792c834b Mon Sep 17 00:00:00 2001 From: hayeswang Date: Wed, 22 Jul 2015 15:27:41 +0800 Subject: [PATCH 1496/7006] r8152: support the new RTL8153 chip Support the new USB gigabit ethernet. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 7f6419ebb5e1c..57b72ecb5455e 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -622,6 +622,7 @@ enum rtl_version { RTL_VER_03, RTL_VER_04, RTL_VER_05, + RTL_VER_06, RTL_VER_MAX }; @@ -2560,7 +2561,10 @@ static void r8153_hw_phy_cfg(struct r8152 *tp) u32 ocp_data; u16 data; - ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); + if (tp->version == RTL_VER_03 || tp->version == RTL_VER_04 || + tp->version == RTL_VER_05) + ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); + data = r8152_mdio_read(tp, MII_BMCR); if (data & BMCR_PDOWN) { data &= ~BMCR_PDOWN; @@ -3268,6 +3272,13 @@ static void r8153_init(struct r8152 *tp) ocp_data &= ~ECM_ALDPS; ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data); + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); + if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) + ocp_data &= ~DYNAMIC_BURST; + else + ocp_data |= DYNAMIC_BURST; + ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data); + } else if (tp->version == RTL_VER_06) { ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1); if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0) ocp_data &= ~DYNAMIC_BURST; @@ -3908,6 +3919,10 @@ static void r8152b_get_version(struct r8152 *tp) tp->version = RTL_VER_05; tp->mii.supports_gmii = 1; break; + case 0x5c30: + tp->version = RTL_VER_06; + tp->mii.supports_gmii = 1; + break; default: netif_info(tp, probe, tp->netdev, "Unknown version 0x%04x\n", version); @@ -3953,6 +3968,7 @@ static int rtl_ops_init(struct r8152 *tp) case RTL_VER_03: case RTL_VER_04: case RTL_VER_05: + case RTL_VER_06: ops->init = r8153_init; ops->enable = rtl8153_enable; ops->disable = rtl8153_disable; -- GitLab From 3985e8a3611a93bb36789f65db862e5700aab65e Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Wed, 22 Jul 2015 16:38:25 +0900 Subject: [PATCH 1497/7006] ipv6: sysctl to restrict candidate source addresses Per RFC 6724, section 4, "Candidate Source Addresses": It is RECOMMENDED that the candidate source addresses be the set of unicast addresses assigned to the interface that will be used to send to the destination (the "outgoing" interface). Add a sysctl to enable this behaviour. Signed-off-by: Erik Kline Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 7 +++++++ include/linux/ipv6.h | 1 + include/uapi/linux/ipv6.h | 1 + net/ipv6/addrconf.c | 22 +++++++++++++++++++--- 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index f63aeefd2c240..1a5ab21bcca51 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1460,6 +1460,13 @@ router_solicitations - INTEGER routers are present. Default: 3 +use_oif_addrs_only - BOOLEAN + When enabled, the candidate source addresses for destinations + routed via this interface are restricted to the set of addresses + configured on this interface (vis. RFC 6724, section 4). + + Default: false + use_tempaddr - INTEGER Preference for Privacy Extensions (RFC3041). <= 0 : disable Privacy Extensions diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 1319a6bb6b82b..06ed637225b87 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -57,6 +57,7 @@ struct ipv6_devconf { bool initialized; struct in6_addr secret; } stable_secret; + __s32 use_oif_addrs_only; void *sysctl; }; diff --git a/include/uapi/linux/ipv6.h b/include/uapi/linux/ipv6.h index 5efa54ae567ca..641a146ead7d2 100644 --- a/include/uapi/linux/ipv6.h +++ b/include/uapi/linux/ipv6.h @@ -171,6 +171,7 @@ enum { DEVCONF_USE_OPTIMISTIC, DEVCONF_ACCEPT_RA_MTU, DEVCONF_STABLE_SECRET, + DEVCONF_USE_OIF_ADDRS_ONLY, DEVCONF_MAX }; diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 32153c248959c..eb0c6a3a8a002 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -211,7 +211,8 @@ static struct ipv6_devconf ipv6_devconf __read_mostly = { .accept_ra_mtu = 1, .stable_secret = { .initialized = false, - } + }, + .use_oif_addrs_only = 0, }; static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { @@ -253,6 +254,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { .stable_secret = { .initialized = false, }, + .use_oif_addrs_only = 0, }; /* Check if a valid qdisc is available */ @@ -1472,11 +1474,16 @@ int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, * include addresses assigned to interfaces * belonging to the same site as the outgoing * interface.) + * - "It is RECOMMENDED that the candidate source addresses + * be the set of unicast addresses assigned to the + * interface that will be used to send to the destination + * (the 'outgoing' interface)." (RFC 6724) */ if (dst_dev) { + idev = __in6_dev_get(dst_dev); if ((dst_type & IPV6_ADDR_MULTICAST) || - dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) { - idev = __in6_dev_get(dst_dev); + dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL || + (idev && idev->cnf.use_oif_addrs_only)) { use_oif_addr = true; } } @@ -4607,6 +4614,7 @@ static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; /* we omit DEVCONF_STABLE_SECRET for now */ + array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only; } static inline size_t inet6_ifla6_size(void) @@ -5605,6 +5613,14 @@ static struct addrconf_sysctl_table .mode = 0600, .proc_handler = addrconf_sysctl_stable_secret, }, + { + .procname = "use_oif_addrs_only", + .data = &ipv6_devconf.use_oif_addrs_only, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec, + + }, { /* sentinel */ } -- GitLab From 052831879945be0d9fad2216b127147c565ec1b1 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Jul 2015 14:43:58 +0200 Subject: [PATCH 1498/7006] ip_tunnel: Provide tunnel metadata API for CONFIG_INET=n Account for the configuration FIB_RULES=y && INET=n as FIB_RULES can be selected by IPV6 or DECNET without INET. Fixes: e7030878fc84 ("fib: Add fib rule match on tunnel id") Fixes: 3093fbe7ff4b ("route: Per route IP tunnel metadata via lightweight tunnel") Reported-by: kbuild test robot Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/ip_tunnels.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 0a5a7763eec24..d975b3ebd6c7c 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -314,6 +314,21 @@ static inline int ip_tunnel_collect_metadata(void) void ip_tunnel_need_metadata(void); void ip_tunnel_unneed_metadata(void); +#else /* CONFIG_INET */ + +static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) +{ + return NULL; +} + +static inline void ip_tunnel_need_metadata(void) +{ +} + +static inline void ip_tunnel_unneed_metadata(void) +{ +} + #endif /* CONFIG_INET */ #endif /* __NET_IP_TUNNELS_H */ -- GitLab From 3bf2789cad9e6573dc19a6c3d123c2c049f2d90f Mon Sep 17 00:00:00 2001 From: Vivek Trivedi Date: Mon, 22 Jun 2015 15:36:06 +0530 Subject: [PATCH 1499/7006] smack: allow mount opts setting over filesystems with binary mount data Add support for setting smack mount labels(using smackfsdef, smackfsroot, smackfshat, smackfsfloor, smackfstransmute) for filesystems with binary mount data like NFS. To achieve this, implement sb_parse_opts_str and sb_set_mnt_opts security operations in smack LSM similar to SELinux. Signed-off-by: Vivek Trivedi Signed-off-by: Amit Sahrawat Acked-by: Casey Schaufler --- security/smack/smack.h | 18 +++ security/smack/smack_lsm.c | 241 +++++++++++++++++++++++++++++++------ 2 files changed, 219 insertions(+), 40 deletions(-) diff --git a/security/smack/smack.h b/security/smack/smack.h index 244e035e5a99f..69ab9eb7d6d92 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -143,6 +143,24 @@ struct smack_onlycap { struct smack_known *smk_label; }; +/* Super block security struct flags for mount options */ +#define FSDEFAULT_MNT 0x01 +#define FSFLOOR_MNT 0x02 +#define FSHAT_MNT 0x04 +#define FSROOT_MNT 0x08 +#define FSTRANS_MNT 0x10 + +#define NUM_SMK_MNT_OPTS 5 + +enum { + Opt_error = -1, + Opt_fsdefault = 1, + Opt_fsfloor = 2, + Opt_fshat = 3, + Opt_fsroot = 4, + Opt_fstransmute = 5, +}; + /* * Mount options */ diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index a143328f75ebb..d962f887d3f44 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -41,6 +41,7 @@ #include #include #include +#include #include "smack.h" #define TRANS_TRUE "TRUE" @@ -64,6 +65,15 @@ static char *smk_bu_mess[] = { "Unconfined Object", /* SMACK_UNCONFINED_OBJECT */ }; +static const match_table_t tokens = { + {Opt_fsdefault, SMK_FSDEFAULT "%s"}, + {Opt_fsfloor, SMK_FSFLOOR "%s"}, + {Opt_fshat, SMK_FSHAT "%s"}, + {Opt_fsroot, SMK_FSROOT "%s"}, + {Opt_fstransmute, SMK_FSTRANS "%s"}, + {Opt_error, NULL}, +}; + static void smk_bu_mode(int mode, char *s) { int i = 0; @@ -577,76 +587,193 @@ static int smack_sb_copy_data(char *orig, char *smackopts) } /** - * smack_sb_kern_mount - Smack specific mount processing + * smack_parse_opts_str - parse Smack specific mount options + * @options: mount options string + * @opts: where to store converted mount opts + * + * Returns 0 on success or -ENOMEM on error. + * + * converts Smack specific mount options to generic security option format + */ +static int smack_parse_opts_str(char *options, + struct security_mnt_opts *opts) +{ + char *p; + char *fsdefault = NULL, *fsfloor = NULL; + char *fshat = NULL, *fsroot = NULL, *fstransmute = NULL; + int rc = -ENOMEM, num_mnt_opts = 0; + + opts->num_mnt_opts = 0; + + if (!options) + return 0; + + while ((p = strsep(&options, ",")) != NULL) { + int token; + substring_t args[MAX_OPT_ARGS]; + + if (!*p) + continue; + + token = match_token(p, tokens, args); + + switch (token) { + case Opt_fsdefault: + if (fsdefault) + goto out_opt_err; + fsdefault = match_strdup(&args[0]); + if (!fsdefault) + goto out_err; + break; + case Opt_fsfloor: + if (fsfloor) + goto out_opt_err; + fsfloor = match_strdup(&args[0]); + if (!fsfloor) + goto out_err; + break; + case Opt_fshat: + if (fshat) + goto out_opt_err; + fshat = match_strdup(&args[0]); + if (!fshat) + goto out_err; + break; + case Opt_fsroot: + if (fsroot) + goto out_opt_err; + fsroot = match_strdup(&args[0]); + if (!fsroot) + goto out_err; + break; + case Opt_fstransmute: + if (fstransmute) + goto out_opt_err; + fstransmute = match_strdup(&args[0]); + if (!fstransmute) + goto out_err; + break; + default: + rc = -EINVAL; + pr_warn("Smack: unknown mount option\n"); + goto out_err; + } + } + + opts->mnt_opts = kcalloc(NUM_SMK_MNT_OPTS, sizeof(char *), GFP_ATOMIC); + if (!opts->mnt_opts) + goto out_err; + + opts->mnt_opts_flags = kcalloc(NUM_SMK_MNT_OPTS, sizeof(int), + GFP_ATOMIC); + if (!opts->mnt_opts_flags) { + kfree(opts->mnt_opts); + goto out_err; + } + + if (fsdefault) { + opts->mnt_opts[num_mnt_opts] = fsdefault; + opts->mnt_opts_flags[num_mnt_opts++] = FSDEFAULT_MNT; + } + if (fsfloor) { + opts->mnt_opts[num_mnt_opts] = fsfloor; + opts->mnt_opts_flags[num_mnt_opts++] = FSFLOOR_MNT; + } + if (fshat) { + opts->mnt_opts[num_mnt_opts] = fshat; + opts->mnt_opts_flags[num_mnt_opts++] = FSHAT_MNT; + } + if (fsroot) { + opts->mnt_opts[num_mnt_opts] = fsroot; + opts->mnt_opts_flags[num_mnt_opts++] = FSROOT_MNT; + } + if (fstransmute) { + opts->mnt_opts[num_mnt_opts] = fstransmute; + opts->mnt_opts_flags[num_mnt_opts++] = FSTRANS_MNT; + } + + opts->num_mnt_opts = num_mnt_opts; + return 0; + +out_opt_err: + rc = -EINVAL; + pr_warn("Smack: duplicate mount options\n"); + +out_err: + kfree(fsdefault); + kfree(fsfloor); + kfree(fshat); + kfree(fsroot); + kfree(fstransmute); + return rc; +} + +/** + * smack_set_mnt_opts - set Smack specific mount options * @sb: the file system superblock - * @flags: the mount flags - * @data: the smack mount options + * @opts: Smack mount options + * @kern_flags: mount option from kernel space or user space + * @set_kern_flags: where to store converted mount opts * * Returns 0 on success, an error code on failure + * + * Allow filesystems with binary mount data to explicitly set Smack mount + * labels. */ -static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) +static int smack_set_mnt_opts(struct super_block *sb, + struct security_mnt_opts *opts, + unsigned long kern_flags, + unsigned long *set_kern_flags) { struct dentry *root = sb->s_root; struct inode *inode = d_backing_inode(root); struct superblock_smack *sp = sb->s_security; struct inode_smack *isp; struct smack_known *skp; - char *op; - char *commap; + int i; + int num_opts = opts->num_mnt_opts; int transmute = 0; - int specified = 0; if (sp->smk_initialized) return 0; sp->smk_initialized = 1; - for (op = data; op != NULL; op = commap) { - commap = strchr(op, ','); - if (commap != NULL) - *commap++ = '\0'; - - if (strncmp(op, SMK_FSHAT, strlen(SMK_FSHAT)) == 0) { - op += strlen(SMK_FSHAT); - skp = smk_import_entry(op, 0); + for (i = 0; i < num_opts; i++) { + switch (opts->mnt_opts_flags[i]) { + case FSDEFAULT_MNT: + skp = smk_import_entry(opts->mnt_opts[i], 0); if (IS_ERR(skp)) return PTR_ERR(skp); - sp->smk_hat = skp; - specified = 1; - - } else if (strncmp(op, SMK_FSFLOOR, strlen(SMK_FSFLOOR)) == 0) { - op += strlen(SMK_FSFLOOR); - skp = smk_import_entry(op, 0); + sp->smk_default = skp; + break; + case FSFLOOR_MNT: + skp = smk_import_entry(opts->mnt_opts[i], 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_floor = skp; - specified = 1; - - } else if (strncmp(op, SMK_FSDEFAULT, - strlen(SMK_FSDEFAULT)) == 0) { - op += strlen(SMK_FSDEFAULT); - skp = smk_import_entry(op, 0); + break; + case FSHAT_MNT: + skp = smk_import_entry(opts->mnt_opts[i], 0); if (IS_ERR(skp)) return PTR_ERR(skp); - sp->smk_default = skp; - specified = 1; - - } else if (strncmp(op, SMK_FSROOT, strlen(SMK_FSROOT)) == 0) { - op += strlen(SMK_FSROOT); - skp = smk_import_entry(op, 0); + sp->smk_hat = skp; + break; + case FSROOT_MNT: + skp = smk_import_entry(opts->mnt_opts[i], 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_root = skp; - specified = 1; - - } else if (strncmp(op, SMK_FSTRANS, strlen(SMK_FSTRANS)) == 0) { - op += strlen(SMK_FSTRANS); - skp = smk_import_entry(op, 0); + break; + case FSTRANS_MNT: + skp = smk_import_entry(opts->mnt_opts[i], 0); if (IS_ERR(skp)) return PTR_ERR(skp); sp->smk_root = skp; transmute = 1; - specified = 1; + break; + default: + break; } } @@ -654,7 +781,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) /* * Unprivileged mounts don't get to specify Smack values. */ - if (specified) + if (num_opts) return -EPERM; /* * Unprivileged mounts get root and default from the caller. @@ -663,6 +790,7 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) sp->smk_root = skp; sp->smk_default = skp; } + /* * Initialize the root inode. */ @@ -681,6 +809,37 @@ static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) return 0; } +/** + * smack_sb_kern_mount - Smack specific mount processing + * @sb: the file system superblock + * @flags: the mount flags + * @data: the smack mount options + * + * Returns 0 on success, an error code on failure + */ +static int smack_sb_kern_mount(struct super_block *sb, int flags, void *data) +{ + int rc = 0; + char *options = data; + struct security_mnt_opts opts; + + security_init_mnt_opts(&opts); + + if (!options) + goto out; + + rc = smack_parse_opts_str(options, &opts); + if (rc) + goto out_err; + +out: + rc = smack_set_mnt_opts(sb, &opts, 0, NULL); + +out_err: + security_free_mnt_opts(&opts); + return rc; +} + /** * smack_sb_statfs - Smack check on statfs * @dentry: identifies the file system in question @@ -4264,6 +4423,8 @@ struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(sb_copy_data, smack_sb_copy_data), LSM_HOOK_INIT(sb_kern_mount, smack_sb_kern_mount), LSM_HOOK_INIT(sb_statfs, smack_sb_statfs), + LSM_HOOK_INIT(sb_set_mnt_opts, smack_set_mnt_opts), + LSM_HOOK_INIT(sb_parse_opts_str, smack_parse_opts_str), LSM_HOOK_INIT(bprm_set_creds, smack_bprm_set_creds), LSM_HOOK_INIT(bprm_committing_creds, smack_bprm_committing_creds), -- GitLab From ca70d27e445fe721587598030b97357b35f61913 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 24 Jun 2015 07:41:07 +0800 Subject: [PATCH 1500/7006] sysfs: fix simple_return.cocci warnings security/smack/smackfs.c:2251:1-4: WARNING: end returns can be simpified and declaration on line 2250 can be dropped Simplify a trivial if-return sequence. Possibly combine with a preceding function call. Generated by: scripts/coccinelle/misc/simple_return.cocci Signed-off-by: Fengguang Wu Acked-by: Serge Hallyn Acked-by: Casey Schaufler --- security/smack/smackfs.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 2716d02119f3e..81a2888a99086 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -2320,11 +2320,7 @@ static const struct file_operations smk_revoke_subj_ops = { */ static int smk_init_sysfs(void) { - int err; - err = sysfs_create_mount_point(fs_kobj, "smackfs"); - if (err) - return err; - return 0; + return sysfs_create_mount_point(fs_kobj, "smackfs"); } /** -- GitLab From b2f8dc4ce6626e25b164e29cf72b70230a1f1711 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Jul 2015 22:11:16 +0200 Subject: [PATCH 1501/7006] ACPI / processor: Drop an unused argument of a cleanup routine acpi_processor_unregister_performance() actually doesn't use its first argument, so drop it and update the callers accordingly. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/acpi/processor_perflib.c | 4 +--- drivers/cpufreq/acpi-cpufreq.c | 5 ++--- drivers/cpufreq/e_powersaver.c | 2 +- drivers/cpufreq/ia64-acpi-cpufreq.c | 5 ++--- drivers/cpufreq/powernow-k7.c | 4 ++-- drivers/cpufreq/powernow-k8.c | 5 ++--- drivers/xen/xen-acpi-processor.c | 16 ++++++---------- include/acpi/processor.h | 5 +---- 8 files changed, 17 insertions(+), 29 deletions(-) diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index cfc8aba72f86d..36b6da2918a68 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -784,9 +784,7 @@ acpi_processor_register_performance(struct acpi_processor_performance EXPORT_SYMBOL(acpi_processor_register_performance); -void -acpi_processor_unregister_performance(struct acpi_processor_performance - *performance, unsigned int cpu) +void acpi_processor_unregister_performance(unsigned int cpu) { struct acpi_processor *pr; diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index de54ce14eb395..ca9d0f6edf08e 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -844,7 +844,7 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) err_freqfree: kfree(data->freq_table); err_unreg: - acpi_processor_unregister_performance(perf, cpu); + acpi_processor_unregister_performance(cpu); err_free_mask: free_cpumask_var(data->freqdomain_cpus); err_free: @@ -862,8 +862,7 @@ static int acpi_cpufreq_cpu_exit(struct cpufreq_policy *policy) if (data) { policy->driver_data = NULL; - acpi_processor_unregister_performance(data->acpi_data, - data->acpi_perf_cpu); + acpi_processor_unregister_performance(data->acpi_perf_cpu); free_cpumask_var(data->freqdomain_cpus); kfree(data->freq_table); kfree(data); diff --git a/drivers/cpufreq/e_powersaver.c b/drivers/cpufreq/e_powersaver.c index a0d2a423cea97..4085244c8a670 100644 --- a/drivers/cpufreq/e_powersaver.c +++ b/drivers/cpufreq/e_powersaver.c @@ -78,7 +78,7 @@ static int eps_acpi_init(void) static int eps_acpi_exit(struct cpufreq_policy *policy) { if (eps_acpi_cpu_perf) { - acpi_processor_unregister_performance(eps_acpi_cpu_perf, 0); + acpi_processor_unregister_performance(0); free_cpumask_var(eps_acpi_cpu_perf->shared_cpu_map); kfree(eps_acpi_cpu_perf); eps_acpi_cpu_perf = NULL; diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index c30aaa6a54e84..a9c193286ef47 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -313,7 +313,7 @@ acpi_cpufreq_cpu_init ( err_freqfree: kfree(data->freq_table); err_unreg: - acpi_processor_unregister_performance(&data->acpi_data, cpu); + acpi_processor_unregister_performance(cpu); err_free: kfree(data); acpi_io_data[cpu] = NULL; @@ -332,8 +332,7 @@ acpi_cpufreq_cpu_exit ( if (data) { acpi_io_data[policy->cpu] = NULL; - acpi_processor_unregister_performance(&data->acpi_data, - policy->cpu); + acpi_processor_unregister_performance(policy->cpu); kfree(data); } diff --git a/drivers/cpufreq/powernow-k7.c b/drivers/cpufreq/powernow-k7.c index 37c5742482d8c..c1ae1999770af 100644 --- a/drivers/cpufreq/powernow-k7.c +++ b/drivers/cpufreq/powernow-k7.c @@ -421,7 +421,7 @@ static int powernow_acpi_init(void) return 0; err2: - acpi_processor_unregister_performance(acpi_processor_perf, 0); + acpi_processor_unregister_performance(0); err1: free_cpumask_var(acpi_processor_perf->shared_cpu_map); err05: @@ -661,7 +661,7 @@ static int powernow_cpu_exit(struct cpufreq_policy *policy) { #ifdef CONFIG_X86_POWERNOW_K7_ACPI if (acpi_processor_perf) { - acpi_processor_unregister_performance(acpi_processor_perf, 0); + acpi_processor_unregister_performance(0); free_cpumask_var(acpi_processor_perf->shared_cpu_map); kfree(acpi_processor_perf); } diff --git a/drivers/cpufreq/powernow-k8.c b/drivers/cpufreq/powernow-k8.c index 5c035d04d8271..0b5bf135b0907 100644 --- a/drivers/cpufreq/powernow-k8.c +++ b/drivers/cpufreq/powernow-k8.c @@ -795,7 +795,7 @@ err_out_mem: kfree(powernow_table); err_out: - acpi_processor_unregister_performance(&data->acpi_data, data->cpu); + acpi_processor_unregister_performance(data->cpu); /* data->acpi_data.state_count informs us at ->exit() * whether ACPI was used */ @@ -863,8 +863,7 @@ static int fill_powernow_table_fidvid(struct powernow_k8_data *data, static void powernow_k8_cpu_exit_acpi(struct powernow_k8_data *data) { if (data->acpi_data.state_count) - acpi_processor_unregister_performance(&data->acpi_data, - data->cpu); + acpi_processor_unregister_performance(data->cpu); free_cpumask_var(data->acpi_data.shared_cpu_map); } diff --git a/drivers/xen/xen-acpi-processor.c b/drivers/xen/xen-acpi-processor.c index 59fc190f1e927..70fa438000afa 100644 --- a/drivers/xen/xen-acpi-processor.c +++ b/drivers/xen/xen-acpi-processor.c @@ -560,11 +560,9 @@ static int __init xen_acpi_processor_init(void) return 0; err_unregister: - for_each_possible_cpu(i) { - struct acpi_processor_performance *perf; - perf = per_cpu_ptr(acpi_perf_data, i); - acpi_processor_unregister_performance(perf, i); - } + for_each_possible_cpu(i) + acpi_processor_unregister_performance(i); + err_out: /* Freeing a NULL pointer is OK: alloc_percpu zeroes. */ free_acpi_perf_data(); @@ -579,11 +577,9 @@ static void __exit xen_acpi_processor_exit(void) kfree(acpi_ids_done); kfree(acpi_id_present); kfree(acpi_id_cst_present); - for_each_possible_cpu(i) { - struct acpi_processor_performance *perf; - perf = per_cpu_ptr(acpi_perf_data, i); - acpi_processor_unregister_performance(perf, i); - } + for_each_possible_cpu(i) + acpi_processor_unregister_performance(i); + free_acpi_perf_data(); } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 4188a4d3b597c..aad1f2a3cd2ba 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -228,10 +228,7 @@ extern int acpi_processor_preregister_performance(struct extern int acpi_processor_register_performance(struct acpi_processor_performance *performance, unsigned int cpu); -extern void acpi_processor_unregister_performance(struct - acpi_processor_performance - *performance, - unsigned int cpu); +extern void acpi_processor_unregister_performance(unsigned int cpu); /* note: this locks both the calling module and the processor module if a _PPC object exists, rmmod is disallowed then */ -- GitLab From 3427616b2a5aa7f34716278aa6a140378a00a36e Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Jul 2015 22:11:56 +0200 Subject: [PATCH 1502/7006] cpufreq: acpi-cpufreq: Drop acpi_data from struct acpi_cpufreq_data After commit 8cfcfd39000d (acpi-cpufreq: Fix an ACPI perf unregister issue) we store both a pointer to per-CPU data of the first policy CPU and the number of that CPU which are redundant. Since the CPU number has to be stored anyway for the unregistration, the pointer to the CPU's per-CPU data may be dropped and we can access the data in question via per_cpu_ptr(). Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/acpi-cpufreq.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index ca9d0f6edf08e..af2bb8883d960 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -65,7 +65,6 @@ enum { #define MSR_K7_HWCR_CPB_DIS (1ULL << 25) struct acpi_cpufreq_data { - struct acpi_processor_performance *acpi_data; struct cpufreq_frequency_table *freq_table; unsigned int resume; unsigned int cpu_feature; @@ -76,6 +75,11 @@ struct acpi_cpufreq_data { /* acpi_perf_data is a pointer to percpu data. */ static struct acpi_processor_performance __percpu *acpi_perf_data; +static inline struct acpi_processor_performance *to_perf_data(struct acpi_cpufreq_data *data) +{ + return per_cpu_ptr(acpi_perf_data, data->acpi_perf_cpu); +} + static struct cpufreq_driver acpi_cpufreq_driver; static unsigned int acpi_pstate_strict; @@ -201,7 +205,7 @@ static unsigned extract_io(u32 value, struct acpi_cpufreq_data *data) struct acpi_processor_performance *perf; int i; - perf = data->acpi_data; + perf = to_perf_data(data); for (i = 0; i < perf->state_count; i++) { if (value == perf->states[i].status) @@ -220,7 +224,7 @@ static unsigned extract_msr(u32 msr, struct acpi_cpufreq_data *data) else msr &= INTEL_MSR_RANGE; - perf = data->acpi_data; + perf = to_perf_data(data); cpufreq_for_each_entry(pos, data->freq_table) if (msr == perf->states[pos->driver_data].status) @@ -346,7 +350,7 @@ get_cur_val(const struct cpumask *mask, struct acpi_cpufreq_data *data) break; case SYSTEM_IO_CAPABLE: cmd.type = SYSTEM_IO_CAPABLE; - perf = data->acpi_data; + perf = to_perf_data(data); cmd.addr.io.port = perf->control_register.address; cmd.addr.io.bit_width = perf->control_register.bit_width; break; @@ -377,10 +381,10 @@ static unsigned int get_cur_freq_on_cpu(unsigned int cpu) data = policy->driver_data; cpufreq_cpu_put(policy); - if (unlikely(!data || !data->acpi_data || !data->freq_table)) + if (unlikely(!data || !data->freq_table)) return 0; - cached_freq = data->freq_table[data->acpi_data->state].frequency; + cached_freq = data->freq_table[to_perf_data(data)->state].frequency; freq = extract_freq(get_cur_val(cpumask_of(cpu), data), data); if (freq != cached_freq) { /* @@ -419,12 +423,11 @@ static int acpi_cpufreq_target(struct cpufreq_policy *policy, unsigned int next_perf_state = 0; /* Index into perf table */ int result = 0; - if (unlikely(data == NULL || - data->acpi_data == NULL || data->freq_table == NULL)) { + if (unlikely(data == NULL || data->freq_table == NULL)) { return -ENODEV; } - perf = data->acpi_data; + perf = to_perf_data(data); next_perf_state = data->freq_table[index].driver_data; if (perf->state == next_perf_state) { if (unlikely(data->resume)) { @@ -487,8 +490,9 @@ out: static unsigned long acpi_cpufreq_guess_freq(struct acpi_cpufreq_data *data, unsigned int cpu) { - struct acpi_processor_performance *perf = data->acpi_data; + struct acpi_processor_performance *perf; + perf = to_perf_data(data); if (cpu_khz) { /* search the closest match to cpu_khz */ unsigned int i; @@ -677,18 +681,17 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy) goto err_free; } - data->acpi_data = per_cpu_ptr(acpi_perf_data, cpu); + perf = per_cpu_ptr(acpi_perf_data, cpu); data->acpi_perf_cpu = cpu; policy->driver_data = data; if (cpu_has(c, X86_FEATURE_CONSTANT_TSC)) acpi_cpufreq_driver.flags |= CPUFREQ_CONST_LOOPS; - result = acpi_processor_register_performance(data->acpi_data, cpu); + result = acpi_processor_register_performance(perf, cpu); if (result) goto err_free_mask; - perf = data->acpi_data; policy->shared_type = perf->shared_type; /* -- GitLab From f56c50e322eed07526a08edefa29fc8bab1e93df Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 22 Jul 2015 22:12:10 +0200 Subject: [PATCH 1503/7006] cpufreq: acpi-cpufreq: Fix up the handling of cpb sysfs attribute The cpb sysfs attribute is only exposed by the ACPI cpufreq driver after a runtime check. For this purpose, the driver keeps a NULL placeholder in its table of sysfs attributes and replaces the NULL with a pointer to an attribute structure if it decides to expose cpb. That is confusing, so make the driver set the pointer to the cpb attribute structure upfront and replace it with NULL if the attribute should not be exposed instead. Signed-off-by: Rafael J. Wysocki Acked-by: Viresh Kumar --- drivers/cpufreq/acpi-cpufreq.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index af2bb8883d960..15b921a9248c8 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -888,7 +888,9 @@ static int acpi_cpufreq_resume(struct cpufreq_policy *policy) static struct freq_attr *acpi_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, &freqdomain_cpus, - NULL, /* this is a placeholder for cpb, do not remove */ +#ifdef CONFIG_X86_ACPI_CPUFREQ_CPB + &cpb, +#endif NULL, }; @@ -961,17 +963,16 @@ static int __init acpi_cpufreq_init(void) * only if configured. This is considered legacy code, which * will probably be removed at some point in the future. */ - if (check_amd_hwpstate_cpu(0)) { - struct freq_attr **iter; + if (!check_amd_hwpstate_cpu(0)) { + struct freq_attr **attr; - pr_debug("adding sysfs entry for cpb\n"); + pr_debug("CPB unsupported, do not expose it\n"); - for (iter = acpi_cpufreq_attr; *iter != NULL; iter++) - ; - - /* make sure there is a terminator behind it */ - if (iter[1] == NULL) - *iter = &cpb; + for (attr = acpi_cpufreq_attr; *attr; attr++) + if (*attr == &cpb) { + *attr = NULL; + break; + } } #endif acpi_cpufreq_boost_init(); -- GitLab From 946c14f812bfff18e6fd6357d06b6e8fa8793fec Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Mon, 20 Jul 2015 14:22:46 +0800 Subject: [PATCH 1504/7006] cpufreq: ia64: remove redundant freq_table of acpi_cpufreq_data freq_table is now stored as policy->freq_table, so drop the redundant freq_table from struct cpufreq_acpi_io. Signed-off-by: Pan Xinhui Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/ia64-acpi-cpufreq.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index a9c193286ef47..cab8ab675bbcf 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -29,7 +29,6 @@ MODULE_LICENSE("GPL"); struct cpufreq_acpi_io { struct acpi_processor_performance acpi_data; - struct cpufreq_frequency_table *freq_table; unsigned int resume; }; @@ -221,6 +220,7 @@ acpi_cpufreq_cpu_init ( unsigned int cpu = policy->cpu; struct cpufreq_acpi_io *data; unsigned int result = 0; + struct cpufreq_frequency_table *freq_table; pr_debug("acpi_cpufreq_cpu_init\n"); @@ -254,10 +254,10 @@ acpi_cpufreq_cpu_init ( } /* alloc freq_table */ - data->freq_table = kzalloc(sizeof(*data->freq_table) * + freq_table = kzalloc(sizeof(*freq_table) * (data->acpi_data.state_count + 1), GFP_KERNEL); - if (!data->freq_table) { + if (!freq_table) { result = -ENOMEM; goto err_unreg; } @@ -276,14 +276,14 @@ acpi_cpufreq_cpu_init ( for (i = 0; i <= data->acpi_data.state_count; i++) { if (i < data->acpi_data.state_count) { - data->freq_table[i].frequency = + freq_table[i].frequency = data->acpi_data.states[i].core_frequency * 1000; } else { - data->freq_table[i].frequency = CPUFREQ_TABLE_END; + freq_table[i].frequency = CPUFREQ_TABLE_END; } } - result = cpufreq_table_validate_and_show(policy, data->freq_table); + result = cpufreq_table_validate_and_show(policy, freq_table); if (result) { goto err_freqfree; } @@ -311,7 +311,7 @@ acpi_cpufreq_cpu_init ( return (result); err_freqfree: - kfree(data->freq_table); + kfree(freq_table); err_unreg: acpi_processor_unregister_performance(cpu); err_free: -- GitLab From 555f3fe957b5bd763d49719cc68c6435c9c8dcf1 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Mon, 20 Jul 2015 14:24:36 +0800 Subject: [PATCH 1505/7006] cpufreq: ia64: Fix a memory leak in acpi_cpufreq_cpu_exit() freq_table should be alloced in ->init and freed in ->exit, but it it is not freed. Fix this memory leak in acpi_cpufreq_cpu_exit(). Signed-off-by: Pan Xinhui Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/ia64-acpi-cpufreq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index cab8ab675bbcf..0202429f1c5bb 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -333,6 +333,7 @@ acpi_cpufreq_cpu_exit ( if (data) { acpi_io_data[policy->cpu] = NULL; acpi_processor_unregister_performance(policy->cpu); + kfree(policy->freq_table); kfree(data); } -- GitLab From 9ef03193a93553885b43731c47d3b6ae90e677c4 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 22 Jul 2015 18:56:47 +0200 Subject: [PATCH 1506/7006] powerpc/rtas: Replace magic values with defines rtas.h already has some nice #defines for RTAS return status codes - let's use them instead of hard-coded "magic" values! Signed-off-by: Thomas Huth Reviewed-by: Tyrel Datwyler Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/rtas.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 7a488c108410b..10fb4024a0ce9 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -478,8 +478,9 @@ unsigned int rtas_busy_delay_time(int status) if (status == RTAS_BUSY) { ms = 1; - } else if (status >= 9900 && status <= 9905) { - order = status - 9900; + } else if (status >= RTAS_EXTENDED_DELAY_MIN && + status <= RTAS_EXTENDED_DELAY_MAX) { + order = status - RTAS_EXTENDED_DELAY_MIN; for (ms = 1; order > 0; order--) ms *= 10; } @@ -641,7 +642,8 @@ int rtas_set_indicator_fast(int indicator, int index, int new_value) rc = rtas_call(token, 3, 1, NULL, indicator, index, new_value); - WARN_ON(rc == -2 || (rc >= 9900 && rc <= 9905)); + WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN && + rc <= RTAS_EXTENDED_DELAY_MAX)); if (rc < 0) return rtas_error_rc(rc); -- GitLab From bc222ef4f79fa0003ef5a0af8090372e3bd8a783 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Jun 2015 15:45:41 +0200 Subject: [PATCH 1507/7006] pinctrl: nomadik: break out state container allocator Break out the function that allocates the nomadik GPIO chip state container to its own function. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 106 +++++++++++++++------- 1 file changed, 71 insertions(+), 35 deletions(-) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 56e79c12562eb..ceed731d4a2d6 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -203,6 +203,7 @@ typedef unsigned long pin_cfg_t; #define GPIO_BLOCK_SHIFT 5 #define NMK_GPIO_PER_CHIP (1 << GPIO_BLOCK_SHIFT) +#define NMK_MAX_BANKS DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP) /* Register in the logic block */ #define NMK_GPIO_DAT 0x00 @@ -282,8 +283,7 @@ struct nmk_pinctrl { void __iomem *prcm_base; }; -static struct nmk_gpio_chip * -nmk_gpio_chips[DIV_ROUND_UP(ARCH_NR_GPIOS, NMK_GPIO_PER_CHIP)]; +static struct nmk_gpio_chip *nmk_gpio_chips[NMK_MAX_BANKS]; static DEFINE_SPINLOCK(nmk_gpio_slpm_lock); @@ -1160,29 +1160,90 @@ void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up) } } +/* + * We will allocate memory for the state container using devm* allocators + * binding to the first device reaching this point, it doesn't matter if + * it is the pin controller or GPIO driver. However we need to use the right + * platform device when looking up resources so pay attention to pdev. + */ +static struct nmk_gpio_chip *nmk_gpio_populate_chip(struct device_node *np, + struct platform_device *pdev) +{ + struct nmk_gpio_chip *nmk_chip; + struct platform_device *gpio_pdev; + struct gpio_chip *chip; + struct resource *res; + struct clk *clk; + void __iomem *base; + u32 id; + + gpio_pdev = of_find_device_by_node(np); + if (!gpio_pdev) { + pr_err("populate \"%s\": device not found\n", np->name); + return ERR_PTR(-ENODEV); + } + if (of_property_read_u32(np, "gpio-bank", &id)) { + dev_err(&pdev->dev, "populate: gpio-bank property not found\n"); + return ERR_PTR(-EINVAL); + } + + /* Already populated? */ + nmk_chip = nmk_gpio_chips[id]; + if (nmk_chip) + return nmk_chip; + + nmk_chip = devm_kzalloc(&pdev->dev, sizeof(*nmk_chip), GFP_KERNEL); + if (!nmk_chip) + return ERR_PTR(-ENOMEM); + + nmk_chip->bank = id; + chip = &nmk_chip->chip; + chip->base = id * NMK_GPIO_PER_CHIP; + chip->ngpio = NMK_GPIO_PER_CHIP; + chip->label = dev_name(&gpio_pdev->dev); + chip->dev = &gpio_pdev->dev; + + res = platform_get_resource(gpio_pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return base; + nmk_chip->addr = base; + + clk = clk_get(&gpio_pdev->dev, NULL); + if (IS_ERR(clk)) + return (void *) clk; + clk_prepare(clk); + nmk_chip->clk = clk; + + BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); + nmk_gpio_chips[id] = nmk_chip; + return nmk_chip; +} + static int nmk_gpio_probe(struct platform_device *dev) { struct device_node *np = dev->dev.of_node; struct nmk_gpio_chip *nmk_chip; struct gpio_chip *chip; struct irq_chip *irqchip; - struct resource *res; - struct clk *clk; int latent_irq; bool supports_sleepmode; - void __iomem *base; int irq; int ret; + nmk_chip = nmk_gpio_populate_chip(np, dev); + if (IS_ERR(nmk_chip)) { + dev_err(&dev->dev, "could not populate nmk chip struct\n"); + return PTR_ERR(nmk_chip); + } + if (of_get_property(np, "st,supports-sleepmode", NULL)) supports_sleepmode = true; else supports_sleepmode = false; - if (of_property_read_u32(np, "gpio-bank", &dev->id)) { - dev_err(&dev->dev, "gpio-bank property not found\n"); - return -EINVAL; - } + /* Correct platform device ID */ + dev->id = nmk_chip->bank; irq = platform_get_irq(dev, 0); if (irq < 0) @@ -1191,27 +1252,10 @@ static int nmk_gpio_probe(struct platform_device *dev) /* It's OK for this IRQ not to be present */ latent_irq = platform_get_irq(dev, 1); - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&dev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); - - clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - clk_prepare(clk); - - nmk_chip = devm_kzalloc(&dev->dev, sizeof(*nmk_chip), GFP_KERNEL); - if (!nmk_chip) - return -ENOMEM; - /* * The virt address in nmk_chip->addr is in the nomadik register space, * so we can simply convert the resource address, without remapping */ - nmk_chip->bank = dev->id; - nmk_chip->clk = clk; - nmk_chip->addr = base; nmk_chip->parent_irq = irq; nmk_chip->latent_parent_irq = latent_irq; nmk_chip->sleepmode = supports_sleepmode; @@ -1226,10 +1270,6 @@ static int nmk_gpio_probe(struct platform_device *dev) chip->set = nmk_gpio_set_output; chip->dbg_show = nmk_gpio_dbg_show; chip->can_sleep = false; - chip->base = dev->id * NMK_GPIO_PER_CHIP; - chip->ngpio = NMK_GPIO_PER_CHIP; - chip->label = dev_name(&dev->dev); - chip->dev = &dev->dev; chip->owner = THIS_MODULE; irqchip = &nmk_chip->irqchip; @@ -1251,14 +1291,10 @@ static int nmk_gpio_probe(struct platform_device *dev) clk_disable(nmk_chip->clk); chip->of_node = np; - ret = gpiochip_add(&nmk_chip->chip); + ret = gpiochip_add(chip); if (ret) return ret; - BUG_ON(nmk_chip->bank >= ARRAY_SIZE(nmk_gpio_chips)); - - nmk_gpio_chips[nmk_chip->bank] = nmk_chip; - platform_set_drvdata(dev, nmk_chip); /* -- GitLab From 6ca7d2e352545132923bfdfcd17a4ceee80f5ce9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Jun 2015 16:05:47 +0200 Subject: [PATCH 1508/7006] pinctrl: nomadik: find chip from local array Instead of indexing around the GPIO ranges to find a chip, look directly in the local array of state containers for nmk_gpio_chip:s. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 64 +++++++++-------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index ceed731d4a2d6..7b1160def2852 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -1354,35 +1354,40 @@ static int nmk_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, return 0; } -static struct pinctrl_gpio_range * -nmk_match_gpio_range(struct pinctrl_dev *pctldev, unsigned offset) +static struct nmk_gpio_chip *find_nmk_gpio_from_pin(unsigned pin) { - struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); int i; + struct nmk_gpio_chip *nmk_gpio; - for (i = 0; i < npct->soc->gpio_num_ranges; i++) { - struct pinctrl_gpio_range *range; - - range = &npct->soc->gpio_ranges[i]; - if (offset >= range->pin_base && - offset <= (range->pin_base + range->npins - 1)) - return range; + for(i = 0; i < NMK_MAX_BANKS; i++) { + nmk_gpio = nmk_gpio_chips[i]; + if (!nmk_gpio) + continue; + if (pin >= nmk_gpio->chip.base && + pin < nmk_gpio->chip.base + nmk_gpio->chip.ngpio) + return nmk_gpio; } return NULL; } +static struct gpio_chip *find_gc_from_pin(unsigned pin) +{ + struct nmk_gpio_chip *nmk_gpio = find_nmk_gpio_from_pin(pin); + + if (nmk_gpio) + return &nmk_gpio->chip; + return NULL; +} + static void nmk_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, unsigned offset) { - struct pinctrl_gpio_range *range; - struct gpio_chip *chip; + struct gpio_chip *chip = find_gc_from_pin(offset); - range = nmk_match_gpio_range(pctldev, offset); - if (!range || !range->gc) { + if (!chip) { seq_printf(s, "invalid pin offset"); return; } - chip = range->gc; nmk_gpio_dbg_show_one(s, pctldev, chip, offset - chip->base, offset); } @@ -1727,25 +1732,16 @@ static int nmk_pmx_set(struct pinctrl_dev *pctldev, unsigned function, } for (i = 0; i < g->npins; i++) { - struct pinctrl_gpio_range *range; struct nmk_gpio_chip *nmk_chip; - struct gpio_chip *chip; unsigned bit; - range = nmk_match_gpio_range(pctldev, g->pins[i]); - if (!range) { + nmk_chip = find_nmk_gpio_from_pin(g->pins[i]); + if (!nmk_chip) { dev_err(npct->dev, "invalid pin offset %d in group %s at index %d\n", g->pins[i], g->name, i); goto out_glitch; } - if (!range->gc) { - dev_err(npct->dev, "GPIO chip missing in range for pin offset %d in group %s at index %d\n", - g->pins[i], g->name, i); - goto out_glitch; - } - chip = range->gc; - nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); dev_dbg(npct->dev, "setting pin %d to altsetting %d\n", g->pins[i], g->altsetting); clk_enable(nmk_chip->clk); @@ -1861,25 +1857,17 @@ static int nmk_pin_config_set(struct pinctrl_dev *pctldev, unsigned pin, }; struct nmk_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev); struct nmk_gpio_chip *nmk_chip; - struct pinctrl_gpio_range *range; - struct gpio_chip *chip; unsigned bit; pin_cfg_t cfg; int pull, slpm, output, val, i; bool lowemi, gpiomode, sleep; - range = nmk_match_gpio_range(pctldev, pin); - if (!range) { - dev_err(npct->dev, "invalid pin offset %d\n", pin); + nmk_chip = find_nmk_gpio_from_pin(pin); + if (!nmk_chip) { + dev_err(npct->dev, + "invalid pin offset %d\n", pin); return -EINVAL; } - if (!range->gc) { - dev_err(npct->dev, "GPIO chip missing in range for pin %d\n", - pin); - return -EINVAL; - } - chip = range->gc; - nmk_chip = container_of(chip, struct nmk_gpio_chip, chip); for (i = 0; i < num_configs; i++) { /* -- GitLab From ab4a936247561cd998913bab5f15e3d3eaed1f9e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 17 Jun 2015 23:10:21 +0200 Subject: [PATCH 1509/7006] pinctrl: nomadik: assure GPIO chips are populated If the pin controller probes before the GPIO driver it needs to populate the GPIO driver state containers ahead of the actual driver probe as the addresses are used by both halves of the driver. Signed-off-by: Linus Walleij --- .../bindings/pinctrl/ste,nomadik.txt | 7 ++++-- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 25 +++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt index f63fcb3ed3528..2213802435e00 100644 --- a/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt +++ b/Documentation/devicetree/bindings/pinctrl/ste,nomadik.txt @@ -3,7 +3,9 @@ ST Ericsson Nomadik pinmux controller Required properties: - compatible: "stericsson,db8500-pinctrl", "stericsson,db8540-pinctrl", "stericsson,stn8815-pinctrl" -- reg: Should contain the register physical address and length of the PRCMU. +- nomadik-gpio-chips: array of phandles to the corresponding GPIO chips + (these have the register ranges used by the pin controller). +- prcm: phandle to the PRCMU managing the back end of this pin controller Please refer to pinctrl-bindings.txt in this directory for details of the common pinctrl bindings used by client devices, including the meaning of the @@ -74,7 +76,8 @@ Example board file extract: pinctrl@80157000 { compatible = "stericsson,db8500-pinctrl"; - reg = <0x80157000 0x2000>; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>; + prcm = <&prcmu>; pinctrl-names = "default"; diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 7b1160def2852..143d1c06078c9 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -2019,6 +2019,31 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) if (version == PINCTRL_NMK_DB8540) nmk_pinctrl_db8540_init(&npct->soc); + /* + * Since we depend on the GPIO chips to provide clock and register base + * for the pin control operations, make sure that we have these + * populated before we continue. Follow the phandles to instantiate + * them. The GPIO portion of the actual hardware may be probed before + * or after this point: it shouldn't matter as the APIs are orthogonal. + */ + for (i = 0; i < NMK_MAX_BANKS; i++) { + struct device_node *gpio_np; + struct nmk_gpio_chip *nmk_chip; + + gpio_np = of_parse_phandle(np, "nomadik-gpio-chips", i); + if (gpio_np) { + dev_info(&pdev->dev, + "populate NMK GPIO %d \"%s\"\n", + i, gpio_np->name); + nmk_chip = nmk_gpio_populate_chip(gpio_np, pdev); + if (IS_ERR(nmk_chip)) + dev_err(&pdev->dev, + "could not populate nmk chip struct " + "- continue anyway\n"); + of_node_put(gpio_np); + } + } + prcm_np = of_parse_phandle(np, "prcm", 0); if (prcm_np) npct->prcm_base = of_iomap(prcm_np, 0); -- GitLab From 045a0fa0c5f5ea0f16c009f924ea579634afbba8 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 23 Jul 2015 10:08:44 +0200 Subject: [PATCH 1510/7006] ip_tunnel: Call ip_tunnel_core_init() from inet_init() Convert the module_init() to a invocation from inet_init() since ip_tunnel_core is part of the INET built-in. Fixes: 3093fbe7ff4 ("route: Per route IP tunnel metadata via lightweight tunnel") Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/ip_tunnels.h | 2 ++ net/ipv4/af_inet.c | 3 +++ net/ipv4/ip_tunnel_core.c | 11 +---------- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index d975b3ebd6c7c..47984415f5d1e 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -311,6 +311,8 @@ static inline int ip_tunnel_collect_metadata(void) return static_key_false(&ip_tunnel_metadata_cnt); } +void __init ip_tunnel_core_init(void); + void ip_tunnel_need_metadata(void); void ip_tunnel_unneed_metadata(void); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 9532ee87151f5..cc4e498a0ccf3 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -112,6 +112,7 @@ #include #include #include +#include #include #include #include @@ -1780,6 +1781,8 @@ static int __init inet_init(void) dev_add_pack(&ip_packet_type); + ip_tunnel_core_init(); + rc = 0; out: return rc; diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 630e6d5712e8e..5512f4e4ec1b1 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -292,19 +292,10 @@ static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { .get_encap_size = ip_tun_encap_nlsize, }; -static int __init ip_tunnel_core_init(void) +void __init ip_tunnel_core_init(void) { lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); - - return 0; -} -module_init(ip_tunnel_core_init); - -static void __exit ip_tunnel_core_exit(void) -{ - lwtunnel_encap_del_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); } -module_exit(ip_tunnel_core_exit); struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; EXPORT_SYMBOL(ip_tunnel_metadata_cnt); -- GitLab From 1c2cb594441d02815d304cccec9742ff5c707495 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Fri, 17 Jul 2015 12:46:58 +0200 Subject: [PATCH 1511/7006] powerpc/rtas: Introduce rtas_get_sensor_fast() for IRQ handlers The EPOW interrupt handler uses rtas_get_sensor(), which in turn uses rtas_busy_delay() to wait for RTAS becoming ready in case it is necessary. But rtas_busy_delay() is annotated with might_sleep() and thus may not be used by interrupts handlers like the EPOW handler! This leads to the following BUG when CONFIG_DEBUG_ATOMIC_SLEEP is enabled: BUG: sleeping function called from invalid context at arch/powerpc/kernel/rtas.c:496 in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/1 CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.2.0-rc2-thuth #6 Call Trace: [c00000007ffe7b90] [c000000000807670] dump_stack+0xa0/0xdc (unreliable) [c00000007ffe7bc0] [c0000000000e1f14] ___might_sleep+0x134/0x180 [c00000007ffe7c20] [c00000000002aec0] rtas_busy_delay+0x30/0xd0 [c00000007ffe7c50] [c00000000002bde4] rtas_get_sensor+0x74/0xe0 [c00000007ffe7ce0] [c000000000083264] ras_epow_interrupt+0x44/0x450 [c00000007ffe7d90] [c000000000120260] handle_irq_event_percpu+0xa0/0x300 [c00000007ffe7e70] [c000000000120524] handle_irq_event+0x64/0xc0 [c00000007ffe7eb0] [c000000000124dbc] handle_fasteoi_irq+0xec/0x260 [c00000007ffe7ef0] [c00000000011f4f0] generic_handle_irq+0x50/0x80 [c00000007ffe7f20] [c000000000010f3c] __do_irq+0x8c/0x200 [c00000007ffe7f90] [c0000000000236cc] call_do_irq+0x14/0x24 [c00000007e6f39e0] [c000000000011144] do_IRQ+0x94/0x110 [c00000007e6f3a30] [c000000000002594] hardware_interrupt_common+0x114/0x180 Fix this issue by introducing a new rtas_get_sensor_fast() function that does not use rtas_busy_delay() - and thus can only be used for sensors that do not cause a BUSY condition - known as "fast" sensors. The EPOW sensor is defined to be "fast" in sPAPR - mpe. Fixes: 587f83e8dd50 ("powerpc/pseries: Use rtas_get_sensor in RAS code") Signed-off-by: Thomas Huth Reviewed-by: Nathan Fontenot Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/rtas.h | 1 + arch/powerpc/kernel/rtas.c | 17 +++++++++++++++++ arch/powerpc/platforms/pseries/ras.c | 3 ++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/rtas.h b/arch/powerpc/include/asm/rtas.h index 7a4ede16b2836..b77ef369c0f0e 100644 --- a/arch/powerpc/include/asm/rtas.h +++ b/arch/powerpc/include/asm/rtas.h @@ -343,6 +343,7 @@ extern void rtas_power_off(void); extern void rtas_halt(void); extern void rtas_os_term(char *str); extern int rtas_get_sensor(int sensor, int index, int *state); +extern int rtas_get_sensor_fast(int sensor, int index, int *state); extern int rtas_get_power_level(int powerdomain, int *level); extern int rtas_set_power_level(int powerdomain, int level, int *setlevel); extern bool rtas_indicator_present(int token, int *maxindex); diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 10fb4024a0ce9..84bf934cf7487 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -585,6 +585,23 @@ int rtas_get_sensor(int sensor, int index, int *state) } EXPORT_SYMBOL(rtas_get_sensor); +int rtas_get_sensor_fast(int sensor, int index, int *state) +{ + int token = rtas_token("get-sensor-state"); + int rc; + + if (token == RTAS_UNKNOWN_SERVICE) + return -ENOENT; + + rc = rtas_call(token, 2, 2, state, sensor, index); + WARN_ON(rc == RTAS_BUSY || (rc >= RTAS_EXTENDED_DELAY_MIN && + rc <= RTAS_EXTENDED_DELAY_MAX)); + + if (rc < 0) + return rtas_error_rc(rc); + return rc; +} + bool rtas_indicator_present(int token, int *maxindex) { int proplen, count, i; diff --git a/arch/powerpc/platforms/pseries/ras.c b/arch/powerpc/platforms/pseries/ras.c index 02e4a17455164..3b6647e574b6d 100644 --- a/arch/powerpc/platforms/pseries/ras.c +++ b/arch/powerpc/platforms/pseries/ras.c @@ -189,7 +189,8 @@ static irqreturn_t ras_epow_interrupt(int irq, void *dev_id) int state; int critical; - status = rtas_get_sensor(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, &state); + status = rtas_get_sensor_fast(EPOW_SENSOR_TOKEN, EPOW_SENSOR_INDEX, + &state); if (state > 3) critical = 1; /* Time Critical */ -- GitLab From 01c9348c7620ec650aaeb3ce339f614709b2fb5a Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Fri, 17 Jul 2015 20:11:43 +1000 Subject: [PATCH 1512/7006] powerpc: Use hardware RNG for arch_get_random_seed_* not arch_get_random_* The hardware RNG on POWER8 and POWER7+ can be relatively slow, since it can only supply one 64-bit value per microsecond. Currently we read it in arch_get_random_long(), but that slows down reading from /dev/urandom since the code in random.c calls arch_get_random_long() for every longword read from /dev/urandom. Since the hardware RNG supplies high-quality entropy on every read, it matches the semantics of arch_get_random_seed_long() better than those of arch_get_random_long(). Therefore this commit makes the code use the POWER8/7+ hardware RNG only for arch_get_random_seed_{long,int} and not for arch_get_random_{long,int}. This won't affect any other PowerPC-based platforms because none of them currently support a hardware RNG. To make it clear that the ppc_md function pointer is used for arch_get_random_seed_*, we rename it from get_random_long to get_random_seed. Signed-off-by: Paul Mackerras Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/archrandom.h | 28 +++++++++++++-------------- arch/powerpc/include/asm/machdep.h | 2 +- arch/powerpc/platforms/powernv/rng.c | 2 +- arch/powerpc/platforms/pseries/rng.c | 2 +- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/arch/powerpc/include/asm/archrandom.h b/arch/powerpc/include/asm/archrandom.h index 0cc6eedc47803..85e88f7a59c0a 100644 --- a/arch/powerpc/include/asm/archrandom.h +++ b/arch/powerpc/include/asm/archrandom.h @@ -7,13 +7,22 @@ static inline int arch_get_random_long(unsigned long *v) { - if (ppc_md.get_random_long) - return ppc_md.get_random_long(v); - return 0; } static inline int arch_get_random_int(unsigned int *v) +{ + return 0; +} + +static inline int arch_get_random_seed_long(unsigned long *v) +{ + if (ppc_md.get_random_seed) + return ppc_md.get_random_seed(v); + + return 0; +} +static inline int arch_get_random_seed_int(unsigned int *v) { unsigned long val; int rc; @@ -26,23 +35,14 @@ static inline int arch_get_random_int(unsigned int *v) } static inline int arch_has_random(void) -{ - return !!ppc_md.get_random_long; -} - -static inline int arch_get_random_seed_long(unsigned long *v) -{ - return 0; -} -static inline int arch_get_random_seed_int(unsigned int *v) { return 0; } + static inline int arch_has_random_seed(void) { - return 0; + return !!ppc_md.get_random_seed; } - #endif /* CONFIG_ARCH_RANDOM */ #ifdef CONFIG_PPC_POWERNV diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index 952579f5e79a9..cab6753f1be56 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -249,7 +249,7 @@ struct machdep_calls { #endif #ifdef CONFIG_ARCH_RANDOM - int (*get_random_long)(unsigned long *v); + int (*get_random_seed)(unsigned long *v); #endif }; diff --git a/arch/powerpc/platforms/powernv/rng.c b/arch/powerpc/platforms/powernv/rng.c index 6eb808ff637e7..5dcbdea1afac0 100644 --- a/arch/powerpc/platforms/powernv/rng.c +++ b/arch/powerpc/platforms/powernv/rng.c @@ -128,7 +128,7 @@ static __init int rng_create(struct device_node *dn) pr_info_once("Registering arch random hook.\n"); - ppc_md.get_random_long = powernv_get_random_long; + ppc_md.get_random_seed = powernv_get_random_long; return 0; } diff --git a/arch/powerpc/platforms/pseries/rng.c b/arch/powerpc/platforms/pseries/rng.c index e09608770909c..31ca557af60bc 100644 --- a/arch/powerpc/platforms/pseries/rng.c +++ b/arch/powerpc/platforms/pseries/rng.c @@ -38,7 +38,7 @@ static __init int rng_init(void) pr_info("Registering arch random hook.\n"); - ppc_md.get_random_long = pseries_get_random_long; + ppc_md.get_random_seed = pseries_get_random_long; return 0; } -- GitLab From 6f2536141ce12e405d70f868451e706216e7e52d Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:09 +0100 Subject: [PATCH 1513/7006] mfd: dt-bindings: Provide human readable define for Clocksource mode ST's Low Power Controller can now operate in three supported modes; Watchdog, Real Time Clock and most recently as a Clocksource. This new define will allow the LPC IP to be configured for Clocksource from DT. Signed-off-by: Lee Jones --- include/dt-bindings/mfd/st-lpc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/dt-bindings/mfd/st-lpc.h b/include/dt-bindings/mfd/st-lpc.h index e3e6c75d8822c..d05894afa7e72 100644 --- a/include/dt-bindings/mfd/st-lpc.h +++ b/include/dt-bindings/mfd/st-lpc.h @@ -11,5 +11,6 @@ #define ST_LPC_MODE_RTC 0 #define ST_LPC_MODE_WDT 1 +#define ST_LPC_MODE_CLKSRC 2 #endif /* __DT_BINDINGS_ST_LPC_H__ */ -- GitLab From 9cba434f630a972b47327ae3d014445033166206 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 30 Apr 2015 11:50:55 -0700 Subject: [PATCH 1514/7006] ixgbevf: add support for reporting RSS key and hash table for X550 This patch extends the reporting of the RSS key and hash table by adding support for X550 VFs. The difference is that X550 VFs have their own registers for RSS key and indirection table, so there is no need to query the PF. The RSS key and indirection table are stored in the adapter structure during the configuration of VFRSSRK and VFRETA which in turn can be used in ethtool for reporting. The logic for writing VFRETA is also changed to make sure that the indirection table is reported correctly. In addition this patch adds defines for the VFRETA entries and number of VFRSSRK registers as well as some whitespace cleanups. Reported-by: Vlad Zolotarov Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbevf/ethtool.c | 51 ++++++++++--------- drivers/net/ethernet/intel/ixgbevf/ixgbevf.h | 9 +++- .../net/ethernet/intel/ixgbevf/ixgbevf_main.c | 21 ++++---- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbevf/ethtool.c b/drivers/net/ethernet/intel/ixgbevf/ethtool.c index b2f5b161d792a..d3e5f5b37999a 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ethtool.c +++ b/drivers/net/ethernet/intel/ixgbevf/ethtool.c @@ -813,22 +813,15 @@ static u32 ixgbevf_get_rxfh_indir_size(struct net_device *netdev) { struct ixgbevf_adapter *adapter = netdev_priv(netdev); - /* We support this operation only for 82599 and x540 at the moment */ - if (adapter->hw.mac.type < ixgbe_mac_X550_vf) - return IXGBEVF_82599_RETA_SIZE; + if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) + return IXGBEVF_X550_VFRETA_SIZE; - return 0; + return IXGBEVF_82599_RETA_SIZE; } static u32 ixgbevf_get_rxfh_key_size(struct net_device *netdev) { - struct ixgbevf_adapter *adapter = netdev_priv(netdev); - - /* We support this operation only for 82599 and x540 at the moment */ - if (adapter->hw.mac.type < ixgbe_mac_X550_vf) - return IXGBEVF_RSS_HASH_KEY_SIZE; - - return 0; + return IXGBEVF_RSS_HASH_KEY_SIZE; } static int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, @@ -840,21 +833,33 @@ static int ixgbevf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, if (hfunc) *hfunc = ETH_RSS_HASH_TOP; - /* If neither indirection table nor hash key was requested - just - * return a success avoiding taking any locks. - */ - if (!indir && !key) - return 0; + if (adapter->hw.mac.type >= ixgbe_mac_X550_vf) { + if (key) + memcpy(key, adapter->rss_key, sizeof(adapter->rss_key)); - spin_lock_bh(&adapter->mbx_lock); - if (indir) - err = ixgbevf_get_reta_locked(&adapter->hw, indir, - adapter->num_rx_queues); + if (indir) { + int i; - if (!err && key) - err = ixgbevf_get_rss_key_locked(&adapter->hw, key); + for (i = 0; i < IXGBEVF_X550_VFRETA_SIZE; i++) + indir[i] = adapter->rss_indir_tbl[i]; + } + } else { + /* If neither indirection table nor hash key was requested + * - just return a success avoiding taking any locks. + */ + if (!indir && !key) + return 0; - spin_unlock_bh(&adapter->mbx_lock); + spin_lock_bh(&adapter->mbx_lock); + if (indir) + err = ixgbevf_get_reta_locked(&adapter->hw, indir, + adapter->num_rx_queues); + + if (!err && key) + err = ixgbevf_get_rss_key_locked(&adapter->hw, key); + + spin_unlock_bh(&adapter->mbx_lock); + } return err; } diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h index 775d089009499..04c7ec8446e03 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h @@ -144,9 +144,11 @@ struct ixgbevf_ring { #define MAX_RX_QUEUES IXGBE_VF_MAX_RX_QUEUES #define MAX_TX_QUEUES IXGBE_VF_MAX_TX_QUEUES -#define IXGBEVF_MAX_RSS_QUEUES 2 -#define IXGBEVF_82599_RETA_SIZE 128 +#define IXGBEVF_MAX_RSS_QUEUES 2 +#define IXGBEVF_82599_RETA_SIZE 128 /* 128 entries */ +#define IXGBEVF_X550_VFRETA_SIZE 64 /* 64 entries */ #define IXGBEVF_RSS_HASH_KEY_SIZE 40 +#define IXGBEVF_VFRSSRK_REGS 10 /* 10 registers for RSS key */ #define IXGBEVF_DEFAULT_TXD 1024 #define IXGBEVF_DEFAULT_RXD 512 @@ -447,6 +449,9 @@ struct ixgbevf_adapter { spinlock_t mbx_lock; unsigned long last_reset; + + u32 rss_key[IXGBEVF_VFRSSRK_REGS]; + u8 rss_indir_tbl[IXGBEVF_X550_VFRETA_SIZE]; }; enum ixbgevf_state_t { diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index b2c86f1b8a9fa..88298a3ef942e 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -1696,22 +1696,25 @@ static void ixgbevf_setup_vfmrqc(struct ixgbevf_adapter *adapter) { struct ixgbe_hw *hw = &adapter->hw; u32 vfmrqc = 0, vfreta = 0; - u32 rss_key[10]; u16 rss_i = adapter->num_rx_queues; - int i, j; + u8 i, j; /* Fill out hash function seeds */ - netdev_rss_key_fill(rss_key, sizeof(rss_key)); - for (i = 0; i < 10; i++) - IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]); + netdev_rss_key_fill(adapter->rss_key, sizeof(adapter->rss_key)); + for (i = 0; i < IXGBEVF_VFRSSRK_REGS; i++) + IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), adapter->rss_key[i]); - /* Fill out redirection table */ - for (i = 0, j = 0; i < 64; i++, j++) { + for (i = 0, j = 0; i < IXGBEVF_X550_VFRETA_SIZE; i++, j++) { if (j == rss_i) j = 0; - vfreta = (vfreta << 8) | (j * 0x1); - if ((i & 3) == 3) + + adapter->rss_indir_tbl[i] = j; + + vfreta |= j << (i & 0x3) * 8; + if ((i & 3) == 3) { IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), vfreta); + vfreta = 0; + } } /* Perform hash on these packet types */ -- GitLab From 06324e0cb28e06cd7cf609d7c3099b12841a5dd6 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Jul 2015 11:07:23 -0700 Subject: [PATCH 1515/7006] HID: wacom: Perform all event processing as part of report processing In some cases, we need access to information before it becomes available to the 'event' handler. In particular, for some devices we cannot properly process the finger data without first knowing the "contact count" at the very end of the report (e.g. the Cintiq 24HDT touch screen, when forced through the GENERIC codepath). Since the HID subsystem doesn't provide a way to take action before 'event' is called, we take a cue from hid-multitouch.c and add a pre-process step within the 'report' handler that performs the same function. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 1 - drivers/hid/wacom_wac.c | 39 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 2a221630d8dcc..d932349277cd1 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1690,7 +1690,6 @@ static struct hid_driver wacom_driver = { .id_table = wacom_ids, .probe = wacom_probe, .remove = wacom_remove, - .event = wacom_wac_event, .report = wacom_wac_report, #ifdef CONFIG_PM .resume = wacom_resume, diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index f5a0d3c64520d..1d9d5d1d800d4 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1437,6 +1437,12 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void wacom_wac_pen_pre_report(struct hid_device *hdev, + struct hid_report *report) +{ + return; +} + static void wacom_wac_pen_report(struct hid_device *hdev, struct hid_report *report) { @@ -1564,6 +1570,12 @@ static int wacom_wac_finger_event(struct hid_device *hdev, return 0; } +static void wacom_wac_finger_pre_report(struct hid_device *hdev, + struct hid_report *report) +{ + return; +} + static void wacom_wac_finger_report(struct hid_device *hdev, struct hid_report *report) { @@ -1615,6 +1627,25 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, return 0; } +static void wacom_report_events(struct hid_device *hdev, struct hid_report *report) +{ + int r; + + for (r = 0; r < report->maxfield; r++) { + struct hid_field *field; + unsigned count, n; + + field = report->field[r]; + count = field->report_count; + + if (!(HID_MAIN_ITEM_VARIABLE & field->flags)) + continue; + + for (n = 0; n < count; n++) + wacom_wac_event(hdev, field, &field->usage[n], field->value[n]); + } +} + void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) { struct wacom *wacom = hid_get_drvdata(hdev); @@ -1624,6 +1655,14 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) if (wacom_wac->features.type != HID_GENERIC) return; + if (WACOM_PEN_FIELD(field)) + wacom_wac_pen_pre_report(hdev, report); + + if (WACOM_FINGER_FIELD(field)) + wacom_wac_finger_pre_report(hdev, report); + + wacom_report_events(hdev, report); + if (WACOM_PEN_FIELD(field)) return wacom_wac_pen_report(hdev, report); -- GitLab From 1b5d514a3d24996ddbe7c75685af9dfdeff125b5 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Jul 2015 11:07:24 -0700 Subject: [PATCH 1516/7006] HID: wacom: Ignore contacts in excess of declared contact count The reports sent from some touch devices (e.g. the Cintiq 24HDT) contain junk data in the contact slots which follow the final "valid" contact. To avoid forwarding it to usrspace, we store the reported contact count during the pre-process phase and then only process that many contacts. If a device sends its contacts across multiple reports (what Microsoft refers to as "hybrid" mode) then the contact count will be zero for reports other than the first. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 30 +++++++++++++++++++++++++++++- drivers/hid/wacom_wac.h | 4 ++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 1d9d5d1d800d4..09fe5d604c97a 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1510,6 +1510,10 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, features->last_slot_field = usage->hid; wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); break; + case HID_DG_CONTACTCOUNT: + wacom_wac->hid_data.cc_index = field->index; + wacom_wac->hid_data.cc_value_index = usage->usage_index; + break; } } @@ -1521,6 +1525,10 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, bool prox = hid_data->tipswitch && !wacom_wac->shared->stylus_in_proximity; + wacom_wac->hid_data.num_received++; + if (wacom_wac->hid_data.num_received > wacom_wac->hid_data.num_expected) + return; + if (mt) { int slot; @@ -1573,7 +1581,19 @@ static int wacom_wac_finger_event(struct hid_device *hdev, static void wacom_wac_finger_pre_report(struct hid_device *hdev, struct hid_report *report) { - return; + struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct hid_data* hid_data = &wacom_wac->hid_data; + + if (hid_data->cc_index >= 0) { + struct hid_field *field = report->field[hid_data->cc_index]; + int value = field->value[hid_data->cc_value_index]; + if (value) + hid_data->num_expected = value; + } + else { + hid_data->num_expected = wacom_wac->features.touch_max; + } } static void wacom_wac_finger_report(struct hid_device *hdev, @@ -1584,10 +1604,18 @@ static void wacom_wac_finger_report(struct hid_device *hdev, struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; + /* If more packets of data are expected, give us a chance to + * process them rather than immediately syncing a partial + * update. + */ + if (wacom_wac->hid_data.num_received < wacom_wac->hid_data.num_expected) + return; + if (touch_max > 1) input_mt_sync_frame(input); input_sync(input); + wacom_wac->hid_data.num_received = 0; /* keep touch state for pen event */ wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(wacom_wac); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 2978c303909d3..c245a6628224c 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -193,6 +193,10 @@ struct hid_data { int width; int height; int id; + int cc_index; + int cc_value_index; + int num_expected; + int num_received; }; struct wacom_wac { -- GitLab From 488abb5c70c19fd37264101d2b6ebee507e1f265 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 21 Jul 2015 11:07:25 -0700 Subject: [PATCH 1517/7006] HID: wacom: Report touch width/height/orientation for GENERIC devices The HID_DG_WIDTH and HID_DG_HEIGHT usages report with width and height of contacts. From this information, a crude determination of orientation is also possible. This patch reports all three to userspace if a device reports this usage. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 09fe5d604c97a..280deb293ae20 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1497,6 +1497,13 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_POSITION_Y, 4); break; + case HID_DG_WIDTH: + case HID_DG_HEIGHT: + features->last_slot_field = usage->hid; + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MAJOR, 0); + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_TOUCH_MINOR, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + break; case HID_DG_CONTACTID: features->last_slot_field = usage->hid; break; @@ -1545,6 +1552,13 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, hid_data->x); input_report_abs(input, mt ? ABS_MT_POSITION_Y : ABS_Y, hid_data->y); + + if (test_bit(ABS_MT_TOUCH_MAJOR, input->absbit)) { + input_report_abs(input, ABS_MT_TOUCH_MAJOR, max(hid_data->width, hid_data->height)); + input_report_abs(input, ABS_MT_TOUCH_MINOR, min(hid_data->width, hid_data->height)); + if (hid_data->width != hid_data->height) + input_report_abs(input, ABS_MT_ORIENTATION, hid_data->width <= hid_data->height ? 0 : 1); + } } } @@ -1561,6 +1575,12 @@ static int wacom_wac_finger_event(struct hid_device *hdev, case HID_GD_Y: wacom_wac->hid_data.y = value; break; + case HID_DG_WIDTH: + wacom_wac->hid_data.width = value; + break; + case HID_DG_HEIGHT: + wacom_wac->hid_data.height = value; + break; case HID_DG_CONTACTID: wacom_wac->hid_data.id = value; break; -- GitLab From 7faae96421870ed990b0a84797c6b2377e81d079 Mon Sep 17 00:00:00 2001 From: Jia-Ju Bai Date: Thu, 4 Jun 2015 21:07:27 +0800 Subject: [PATCH 1518/7006] e1000e: Cleanup qos request in error handling of e1000_open The driver lacks pm_qos_remove_request in error handling (err_req_irq) of e1000_open, and qos request inserted by pm_qos_add_request is not removed. This patch add pm_qos_remove_request in error handling to fix it. Signed-off-by: Jia-Ju Bai Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/e1000e/netdev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 89d788d8f263e..fea1601f32a36 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -4588,6 +4588,7 @@ static int e1000_open(struct net_device *netdev) return 0; err_req_irq: + pm_qos_remove_request(&adapter->pm_qos_req); e1000e_release_hw_control(adapter); e1000_power_down_phy(adapter); e1000e_free_rx_resources(adapter->rx_ring); -- GitLab From 0c5bbeb8839172990e3b8aa82ae3c166e85a09bc Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Thu, 4 Jun 2015 14:26:56 -0700 Subject: [PATCH 1519/7006] igb: report unsupported ethtool settings in set_coalesce There are many settings possible using ethtool -C/--coalesce, but not all of them are supported in igb. Report failure when an unsupported option is set. Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_ethtool.c | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/net/ethernet/intel/igb/igb_ethtool.c b/drivers/net/ethernet/intel/igb/igb_ethtool.c index 109cad928e71a..b7b9c670bb3c7 100644 --- a/drivers/net/ethernet/intel/igb/igb_ethtool.c +++ b/drivers/net/ethernet/intel/igb/igb_ethtool.c @@ -2159,6 +2159,27 @@ static int igb_set_coalesce(struct net_device *netdev, struct igb_adapter *adapter = netdev_priv(netdev); int i; + if (ec->rx_max_coalesced_frames || + ec->rx_coalesce_usecs_irq || + ec->rx_max_coalesced_frames_irq || + ec->tx_max_coalesced_frames || + ec->tx_coalesce_usecs_irq || + ec->stats_block_coalesce_usecs || + ec->use_adaptive_rx_coalesce || + ec->use_adaptive_tx_coalesce || + ec->pkt_rate_low || + ec->rx_coalesce_usecs_low || + ec->rx_max_coalesced_frames_low || + ec->tx_coalesce_usecs_low || + ec->tx_max_coalesced_frames_low || + ec->pkt_rate_high || + ec->rx_coalesce_usecs_high || + ec->rx_max_coalesced_frames_high || + ec->tx_coalesce_usecs_high || + ec->tx_max_coalesced_frames_high || + ec->rate_sample_interval) + return -ENOTSUPP; + if ((ec->rx_coalesce_usecs > IGB_MAX_ITR_USECS) || ((ec->rx_coalesce_usecs > 3) && (ec->rx_coalesce_usecs < IGB_MIN_ITR_USECS)) || -- GitLab From 9fa0452b645efdff439948a5cf448b8e497340e9 Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Tue, 30 Jun 2015 15:16:55 -0700 Subject: [PATCH 1520/7006] igb: use ARRAY_SIZE to replace calculating sizeof(a)/sizeof(a[0]) Use the ARRAY_SIZE macro rather than calculating sizeof(a)/sizeof(a[0]). Also directly replace the code rather than using an unnecessary define. Reported-by: Maninder Singh Reported-by: Joe Perches Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/e1000_phy.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index c1bb64d8366fa..987c9de247645 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1,5 +1,5 @@ /* Intel(R) Gigabit Ethernet Linux driver - * Copyright(c) 2007-2014 Intel Corporation. + * Copyright(c) 2007-2015 Intel Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -36,9 +36,6 @@ static s32 igb_set_master_slave_mode(struct e1000_hw *hw); /* Cable length tables */ static const u16 e1000_m88_cable_length_table[] = { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED }; -#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_m88_cable_length_table) / \ - sizeof(e1000_m88_cable_length_table[0])) static const u16 e1000_igp_2_cable_length_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, @@ -49,9 +46,6 @@ static const u16 e1000_igp_2_cable_length_table[] = { 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, 124}; -#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ - (sizeof(e1000_igp_2_cable_length_table) / \ - sizeof(e1000_igp_2_cable_length_table[0])) /** * igb_check_reset_block - Check if PHY reset is blocked @@ -1700,7 +1694,7 @@ s32 igb_get_cable_length_m88(struct e1000_hw *hw) index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) { ret_val = -E1000_ERR_PHY; goto out; } @@ -1796,7 +1790,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) index = (phy_data & M88E1000_PSSR_CABLE_LENGTH) >> M88E1000_PSSR_CABLE_LENGTH_SHIFT; - if (index >= M88E1000_CABLE_LENGTH_TABLE_SIZE - 1) { + if (index >= ARRAY_SIZE(e1000_m88_cable_length_table) - 1) { ret_val = -E1000_ERR_PHY; goto out; } @@ -1840,7 +1834,7 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) s32 ret_val = 0; u16 phy_data, i, agc_value = 0; u16 cur_agc_index, max_agc_index = 0; - u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; + u16 min_agc_index = ARRAY_SIZE(e1000_igp_2_cable_length_table) - 1; static const u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = { IGP02E1000_PHY_AGC_A, IGP02E1000_PHY_AGC_B, @@ -1863,7 +1857,7 @@ s32 igb_get_cable_length_igp_2(struct e1000_hw *hw) IGP02E1000_AGC_LENGTH_MASK; /* Array index bound check. */ - if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || + if ((cur_agc_index >= ARRAY_SIZE(e1000_igp_2_cable_length_table)) || (cur_agc_index == 0)) { ret_val = -E1000_ERR_PHY; goto out; -- GitLab From 6fb469023cd995d7be5ab3bf12b79387710382ff Mon Sep 17 00:00:00 2001 From: Todd Fujinaka Date: Wed, 20 May 2015 15:40:20 -0700 Subject: [PATCH 1521/7006] igb: bump version to igb-5.3.0 Signed-off-by: Todd Fujinaka Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/igb/igb_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index fc7729e78f3de..41e2740468964 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -57,8 +57,8 @@ #include "igb.h" #define MAJ 5 -#define MIN 2 -#define BUILD 18 +#define MIN 3 +#define BUILD 0 #define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \ __stringify(BUILD) "-k" char igb_driver_name[] = "igb"; -- GitLab From de32e3efd58e9e6754e911618ac7941979ceb6b1 Mon Sep 17 00:00:00 2001 From: Carolyn Wyborny Date: Wed, 10 Jun 2015 13:42:07 -0400 Subject: [PATCH 1522/7006] i40e/i40evf: Fix and refactor dynamic ITR code This patch changes the switch statement for dynamic interrupt throttling and adds a default case. With this patch, we check the latency setting instead of the current ITR settings and the included refactor improves performance. Without this patch, the ITR setting would never change dynamically, and there was no default. Change-ID: Idb5a8a14c7109ec47c90f6e94bd43baa17d7ee37 Signed-off-by: Carolyn Wyborny Signed-off-by: Anjali Singhai Jain Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 146 +++++++++++------- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 113 +++++++++----- 2 files changed, 161 insertions(+), 98 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index 1fe230d2be5d6..a72278c265c2f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -892,7 +892,7 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) * 20-1249MB/s bulk (8000 ints/s) */ bytes_per_int = rc->total_bytes / rc->itr; - switch (rc->itr) { + switch (new_latency_range) { case I40E_LOWEST_LATENCY: if (bytes_per_int > 10) new_latency_range = I40E_LOW_LATENCY; @@ -905,9 +905,14 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; case I40E_BULK_LATENCY: if (bytes_per_int <= 20) - rc->latency_range = I40E_LOW_LATENCY; + new_latency_range = I40E_LOW_LATENCY; + break; + default: + if (bytes_per_int <= 20) + new_latency_range = I40E_LOW_LATENCY; break; } + rc->latency_range = new_latency_range; switch (new_latency_range) { case I40E_LOWEST_LATENCY: @@ -923,41 +928,13 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; } - if (new_itr != rc->itr) { - /* do an exponential smoothing */ - new_itr = (10 * new_itr * rc->itr) / - ((9 * new_itr) + rc->itr); - rc->itr = new_itr & I40E_MAX_ITR; - } + if (new_itr != rc->itr) + rc->itr = new_itr; rc->total_bytes = 0; rc->total_packets = 0; } -/** - * i40e_update_dynamic_itr - Adjust ITR based on bytes per int - * @q_vector: the vector to adjust - **/ -static void i40e_update_dynamic_itr(struct i40e_q_vector *q_vector) -{ - u16 vector = q_vector->vsi->base_vector + q_vector->v_idx; - struct i40e_hw *hw = &q_vector->vsi->back->hw; - u32 reg_addr; - u16 old_itr; - - reg_addr = I40E_PFINT_ITRN(I40E_RX_ITR, vector - 1); - old_itr = q_vector->rx.itr; - i40e_set_new_dynamic_itr(&q_vector->rx); - if (old_itr != q_vector->rx.itr) - wr32(hw, reg_addr, q_vector->rx.itr); - - reg_addr = I40E_PFINT_ITRN(I40E_TX_ITR, vector - 1); - old_itr = q_vector->tx.itr; - i40e_set_new_dynamic_itr(&q_vector->tx); - if (old_itr != q_vector->tx.itr) - wr32(hw, reg_addr, q_vector->tx.itr); -} - /** * i40e_clean_programming_status - clean the programming status descriptor * @rx_ring: the rx ring that has this descriptor @@ -1826,6 +1803,68 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) return total_rx_packets; } +/** + * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt + * @vsi: the VSI we care about + * @q_vector: q_vector for which itr is being updated and interrupt enabled + * + **/ +static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, + struct i40e_q_vector *q_vector) +{ + struct i40e_hw *hw = &vsi->back->hw; + u16 old_itr; + int vector; + u32 val; + + vector = (q_vector->v_idx + vsi->base_vector); + if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) { + old_itr = q_vector->rx.itr; + i40e_set_new_dynamic_itr(&q_vector->rx); + if (old_itr != q_vector->rx.itr) { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_RX_ITR << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->rx.itr << + I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT); + } else { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_PFINT_DYN_CTLN(vector - 1), val); + } else { + i40e_irq_dynamic_enable(vsi, + q_vector->v_idx + vsi->base_vector); + } + if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) { + old_itr = q_vector->tx.itr; + i40e_set_new_dynamic_itr(&q_vector->tx); + if (old_itr != q_vector->tx.itr) { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_TX_ITR << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->tx.itr << + I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT); + } else { + val = I40E_PFINT_DYN_CTLN_INTENA_MASK | + I40E_PFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_PFINT_DYN_CTLN(q_vector->v_idx + + vsi->base_vector - 1), val); + } else { + i40e_irq_dynamic_enable(vsi, + q_vector->v_idx + vsi->base_vector); + } +} + /** * i40e_napi_poll - NAPI polling Rx/Tx cleanup routine * @napi: napi struct with our devices info in it @@ -1882,33 +1921,24 @@ int i40e_napi_poll(struct napi_struct *napi, int budget) /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); - if (ITR_IS_DYNAMIC(vsi->rx_itr_setting) || - ITR_IS_DYNAMIC(vsi->tx_itr_setting)) - i40e_update_dynamic_itr(q_vector); - - if (!test_bit(__I40E_DOWN, &vsi->state)) { - if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { - i40e_irq_dynamic_enable(vsi, - q_vector->v_idx + vsi->base_vector); - } else { - struct i40e_hw *hw = &vsi->back->hw; - /* We re-enable the queue 0 cause, but - * don't worry about dynamic_enable - * because we left it on for the other - * possible interrupts during napi - */ - u32 qval = rd32(hw, I40E_QINT_RQCTL(0)); - qval |= I40E_QINT_RQCTL_CAUSE_ENA_MASK; - wr32(hw, I40E_QINT_RQCTL(0), qval); - - qval = rd32(hw, I40E_QINT_TQCTL(0)); - qval |= I40E_QINT_TQCTL_CAUSE_ENA_MASK; - wr32(hw, I40E_QINT_TQCTL(0), qval); - - i40e_irq_dynamic_enable_icr0(vsi->back); - } + if (vsi->back->flags & I40E_FLAG_MSIX_ENABLED) { + i40e_update_enable_itr(vsi, q_vector); + } else { /* Legacy mode */ + struct i40e_hw *hw = &vsi->back->hw; + /* We re-enable the queue 0 cause, but + * don't worry about dynamic_enable + * because we left it on for the other + * possible interrupts during napi + */ + u32 qval = rd32(hw, I40E_QINT_RQCTL(0)) | + I40E_QINT_RQCTL_CAUSE_ENA_MASK; + + wr32(hw, I40E_QINT_RQCTL(0), qval); + qval = rd32(hw, I40E_QINT_TQCTL(0)) | + I40E_QINT_TQCTL_CAUSE_ENA_MASK; + wr32(hw, I40E_QINT_TQCTL(0), qval); + i40e_irq_dynamic_enable_icr0(vsi->back); } - return 0; } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 0f0e185b5c66a..cf3530335c681 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -404,7 +404,7 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) * 20-1249MB/s bulk (8000 ints/s) */ bytes_per_int = rc->total_bytes / rc->itr; - switch (rc->itr) { + switch (new_latency_range) { case I40E_LOWEST_LATENCY: if (bytes_per_int > 10) new_latency_range = I40E_LOW_LATENCY; @@ -417,9 +417,14 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; case I40E_BULK_LATENCY: if (bytes_per_int <= 20) - rc->latency_range = I40E_LOW_LATENCY; + new_latency_range = I40E_LOW_LATENCY; + break; + default: + if (bytes_per_int <= 20) + new_latency_range = I40E_LOW_LATENCY; break; } + rc->latency_range = new_latency_range; switch (new_latency_range) { case I40E_LOWEST_LATENCY: @@ -435,42 +440,14 @@ static void i40e_set_new_dynamic_itr(struct i40e_ring_container *rc) break; } - if (new_itr != rc->itr) { - /* do an exponential smoothing */ - new_itr = (10 * new_itr * rc->itr) / - ((9 * new_itr) + rc->itr); - rc->itr = new_itr & I40E_MAX_ITR; - } + if (new_itr != rc->itr) + rc->itr = new_itr; rc->total_bytes = 0; rc->total_packets = 0; } -/** - * i40e_update_dynamic_itr - Adjust ITR based on bytes per int - * @q_vector: the vector to adjust - **/ -static void i40e_update_dynamic_itr(struct i40e_q_vector *q_vector) -{ - u16 vector = q_vector->vsi->base_vector + q_vector->v_idx; - struct i40e_hw *hw = &q_vector->vsi->back->hw; - u32 reg_addr; - u16 old_itr; - - reg_addr = I40E_VFINT_ITRN1(I40E_RX_ITR, vector - 1); - old_itr = q_vector->rx.itr; - i40e_set_new_dynamic_itr(&q_vector->rx); - if (old_itr != q_vector->rx.itr) - wr32(hw, reg_addr, q_vector->rx.itr); - - reg_addr = I40E_VFINT_ITRN1(I40E_TX_ITR, vector - 1); - old_itr = q_vector->tx.itr; - i40e_set_new_dynamic_itr(&q_vector->tx); - if (old_itr != q_vector->tx.itr) - wr32(hw, reg_addr, q_vector->tx.itr); -} - -/** +/* * i40evf_setup_tx_descriptors - Allocate the Tx descriptors * @tx_ring: the tx ring to set up * @@ -1280,6 +1257,68 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) return total_rx_packets; } +/** + * i40e_update_enable_itr - Update itr and re-enable MSIX interrupt + * @vsi: the VSI we care about + * @q_vector: q_vector for which itr is being updated and interrupt enabled + * + **/ +static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, + struct i40e_q_vector *q_vector) +{ + struct i40e_hw *hw = &vsi->back->hw; + u16 old_itr; + int vector; + u32 val; + + vector = (q_vector->v_idx + vsi->base_vector); + if (ITR_IS_DYNAMIC(vsi->rx_itr_setting)) { + old_itr = q_vector->rx.itr; + i40e_set_new_dynamic_itr(&q_vector->rx); + if (old_itr != q_vector->rx.itr) { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_RX_ITR << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->rx.itr << + I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT); + } else { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); + } else { + i40evf_irq_enable_queues(vsi->back, 1 + << q_vector->v_idx); + } + if (ITR_IS_DYNAMIC(vsi->tx_itr_setting)) { + old_itr = q_vector->tx.itr; + i40e_set_new_dynamic_itr(&q_vector->tx); + if (old_itr != q_vector->tx.itr) { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_TX_ITR << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) | + (q_vector->tx.itr << + I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT); + + } else { + val = I40E_VFINT_DYN_CTLN_INTENA_MASK | + I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + (I40E_ITR_NONE << + I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT); + } + if (!test_bit(__I40E_DOWN, &vsi->state)) + wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); + } else { + i40evf_irq_enable_queues(vsi->back, + 1 << q_vector->v_idx); + } +} + /** * i40evf_napi_poll - NAPI polling Rx/Tx cleanup routine * @napi: napi struct with our devices info in it @@ -1336,13 +1375,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget) /* Work is done so exit the polling mode and re-enable the interrupt */ napi_complete(napi); - if (ITR_IS_DYNAMIC(vsi->rx_itr_setting) || - ITR_IS_DYNAMIC(vsi->tx_itr_setting)) - i40e_update_dynamic_itr(q_vector); - - if (!test_bit(__I40E_DOWN, &vsi->state)) - i40evf_irq_enable_queues(vsi->back, 1 << q_vector->v_idx); - + i40e_update_enable_itr(vsi, q_vector); return 0; } -- GitLab From 3b104be39e4a9ed2c0f6be56ceed4235262369b6 Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Mon, 1 Jun 2015 19:33:03 +0000 Subject: [PATCH 1523/7006] i40e: clean up unneeded gotos With a little work we can clean up some unnecessary logic jumping and drop a variable. Signed-off-by: Shannon Nelson Cc: Laurent Navet Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_hmc.c | 37 +++++++--------------- 1 file changed, 12 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_hmc.c index b89856a5e313b..5ebe12d56ebf4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.c @@ -297,21 +297,15 @@ i40e_status i40e_remove_sd_bp_new(struct i40e_hw *hw, u32 idx, bool is_pf) { struct i40e_hmc_sd_entry *sd_entry; - i40e_status ret_code = 0; + + if (!is_pf) + return I40E_NOT_SUPPORTED; /* get the entry and decrease its ref counter */ sd_entry = &hmc_info->sd_table.sd_entry[idx]; - if (is_pf) { - I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); - } else { - ret_code = I40E_NOT_SUPPORTED; - goto exit; - } - ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.bp.addr)); - if (ret_code) - goto exit; -exit: - return ret_code; + I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_DIRECT); + + return i40e_free_dma_mem(hw, &sd_entry->u.bp.addr); } /** @@ -351,20 +345,13 @@ i40e_status i40e_remove_pd_page_new(struct i40e_hw *hw, struct i40e_hmc_info *hmc_info, u32 idx, bool is_pf) { - i40e_status ret_code = 0; struct i40e_hmc_sd_entry *sd_entry; + if (!is_pf) + return I40E_NOT_SUPPORTED; + sd_entry = &hmc_info->sd_table.sd_entry[idx]; - if (is_pf) { - I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); - } else { - ret_code = I40E_NOT_SUPPORTED; - goto exit; - } - /* free memory here */ - ret_code = i40e_free_dma_mem(hw, &(sd_entry->u.pd_table.pd_page_addr)); - if (ret_code) - goto exit; -exit: - return ret_code; + I40E_CLEAR_PF_SD_ENTRY(hw, idx, I40E_SD_TYPE_PAGED); + + return i40e_free_dma_mem(hw, &sd_entry->u.pd_table.pd_page_addr); } -- GitLab From 1b53c2fb43a0f03f7bb8a179d910e98a2fe68674 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:55 -0400 Subject: [PATCH 1524/7006] i40e: add VF capabilities to virtual channel interface To prepare for the changes coming up in the X722 device and future devices, the virtual channel interface has to change slightly. The VF driver can now report what its capable of supporting, which then informs the PF driver when it sends the configuration information back to the VF. A 1.1 VF driver on a 1.0 PF driver should not send its capabilities. Likewise, a 1.1 PF driver controlling a 1.0 VF driver should not expect or depend upon receiving the VF capabilities. All other aspects of the API are unchanged. Change-ID: I530cc55f107edd1ee8bdf95830aa90b87854058a Signed-off-by: Mitch Williams Acked-by: Shannon Nelson Acked-by: Anjali Singhai Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl.h | 16 +++++++++++----- .../net/ethernet/intel/i40evf/i40e_virtchnl.h | 16 +++++++++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h index 2d20af290fbf2..a7ab463b44746 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h @@ -110,7 +110,9 @@ struct i40e_virtchnl_msg { * error regardless of version mismatch. */ #define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 0 +#define I40E_VIRTCHNL_VERSION_MINOR 1 +#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 + struct i40e_virtchnl_version_info { u32 major; u32 minor; @@ -129,7 +131,8 @@ struct i40e_virtchnl_version_info { */ /* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * VF sends this request to PF with no parameters + * Version 1.0 VF sends this request to PF with no parameters + * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities * PF responds with an indirect message containing * i40e_virtchnl_vf_resource and one or more * i40e_virtchnl_vsi_resource structures. @@ -143,9 +146,12 @@ struct i40e_virtchnl_vsi_resource { u8 default_mac_addr[ETH_ALEN]; }; /* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 +#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 +#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 +#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 +#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 struct i40e_virtchnl_vf_resource { u16 num_vsis; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h index 59f62f0e65dd3..1e89dea0d5292 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h @@ -110,7 +110,9 @@ struct i40e_virtchnl_msg { * error regardless of version mismatch. */ #define I40E_VIRTCHNL_VERSION_MAJOR 1 -#define I40E_VIRTCHNL_VERSION_MINOR 0 +#define I40E_VIRTCHNL_VERSION_MINOR 1 +#define I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS 0 + struct i40e_virtchnl_version_info { u32 major; u32 minor; @@ -129,7 +131,8 @@ struct i40e_virtchnl_version_info { */ /* I40E_VIRTCHNL_OP_GET_VF_RESOURCES - * VF sends this request to PF with no parameters + * Version 1.0 VF sends this request to PF with no parameters + * Version 1.1 VF sends this request to PF with u32 bitmap of its capabilities * PF responds with an indirect message containing * i40e_virtchnl_vf_resource and one or more * i40e_virtchnl_vsi_resource structures. @@ -143,9 +146,12 @@ struct i40e_virtchnl_vsi_resource { u8 default_mac_addr[ETH_ALEN]; }; /* VF offload flags */ -#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 -#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 -#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 +#define I40E_VIRTCHNL_VF_OFFLOAD_L2 0x00000001 +#define I40E_VIRTCHNL_VF_OFFLOAD_IWARP 0x00000002 +#define I40E_VIRTCHNL_VF_OFFLOAD_FCOE 0x00000004 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 +#define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 +#define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 struct i40e_virtchnl_vf_resource { u16 num_vsis; -- GitLab From 17a65a7f8030c467193a6b774b6bbbbfc9d01f5c Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:56 -0400 Subject: [PATCH 1525/7006] i40e/i40evf: add macros for virtual channel API version and device capability Now that we've rolled the virtual channel API version to 1.1, add some macros to test what version is being used by our partner in crime. For the VF, add some macros to determine what our device capabilities are. Change-ID: I79f6683d4c23bd76a8ad9fd492776fcc1208e1dc Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h | 3 +++ drivers/net/ethernet/intel/i40evf/i40evf.h | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index 09043c1aae543..d254a5e4abf1c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -42,6 +42,9 @@ #define I40E_VLAN_MASK 0xFFF #define I40E_PRIORITY_MASK 0x7000 +#define VF_IS_V10(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 0)) +#define VF_IS_V11(_v) (((_v)->vf_ver.major == 1) && ((_v)->vf_ver.minor == 1)) + /* Various queue ctrls */ enum i40e_queue_ctrl { I40E_QUEUE_CTRL_UNKNOWN = 0, diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index fea3b75a9a35f..f3bcd05f7ecf8 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -249,8 +249,17 @@ struct i40evf_adapter { bool netdev_registered; bool link_up; enum i40e_virtchnl_ops current_op; +#define CLIENT_ENABLED(_a) ((_a)->vf_res->vf_offload_flags & \ + I40E_VIRTCHNL_VF_OFFLOAD_IWARP) +#define RSS_AQ(_a) ((_a)->vf_res->vf_offload_flags & \ + I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ) +#define VLAN_ALLOWED(_a) ((_a)->vf_res->vf_offload_flags & \ + I40E_VIRTCHNL_VF_OFFLOAD_VLAN) struct i40e_virtchnl_vf_resource *vf_res; /* incl. all VSIs */ struct i40e_virtchnl_vsi_resource *vsi_res; /* our LAN VSI */ + struct i40e_virtchnl_version_info pf_version; +#define PF_IS_V11(_a) (((_a)->pf_version.major == 1) && \ + ((_a)->pf_version.minor == 1)) u16 msg_enable; struct i40e_eth_stats current_stats; struct i40e_vsi vsi; -- GitLab From f4ca1a229535f1e7eb8253504c66e01e4623c278 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:57 -0400 Subject: [PATCH 1526/7006] i40e: support virtual channel API 1.1 Store off the VF API version for use when figuring out the VF driver capabilities. Add support for the VF driver handing its capabilities to the PF driver and then use this information when sending VF resource information back to the VF driver. Change-ID: Ic00d0eeeb5b8118085e12f068ef857089a8f7c2d Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 25 ++++++++++++++----- .../ethernet/intel/i40e/i40e_virtchnl_pf.h | 2 ++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index fdd7f5e3a66b1..176a2898f1ad1 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1121,12 +1121,13 @@ static int i40e_vc_send_resp_to_vf(struct i40e_vf *vf, * * called from the VF to request the API version used by the PF **/ -static int i40e_vc_get_version_msg(struct i40e_vf *vf) +static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) { struct i40e_virtchnl_version_info info = { I40E_VIRTCHNL_VERSION_MAJOR, I40E_VIRTCHNL_VERSION_MINOR }; + vf->vf_ver = *(struct i40e_virtchnl_version_info *)msg; return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, sizeof(struct @@ -1141,7 +1142,7 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf) * * called from the VF to request its resources **/ -static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf) +static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf, u8 *msg) { struct i40e_virtchnl_vf_resource *vfres = NULL; struct i40e_pf *pf = vf->pf; @@ -1165,11 +1166,18 @@ static int i40e_vc_get_vf_resources_msg(struct i40e_vf *vf) len = 0; goto err; } + if (VF_IS_V11(vf)) + vf->driver_caps = *(u32 *)msg; + else + vf->driver_caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | + I40E_VIRTCHNL_VF_OFFLOAD_VLAN; vfres->vf_offload_flags = I40E_VIRTCHNL_VF_OFFLOAD_L2; vsi = pf->vsi[vf->lan_vsi_idx]; if (!vsi->info.pvid) - vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + vfres->vf_offload_flags |= I40E_VIRTCHNL_VF_OFFLOAD_VLAN | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG; vfres->num_vsis = num_vsis; vfres->num_queue_pairs = vf->num_queue_pairs; @@ -1771,9 +1779,14 @@ static int i40e_vc_validate_vf_msg(struct i40e_vf *vf, u32 v_opcode, valid_len = sizeof(struct i40e_virtchnl_version_info); break; case I40E_VIRTCHNL_OP_RESET_VF: - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: valid_len = 0; break; + case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: + if (VF_IS_V11(vf)) + valid_len = sizeof(u32); + else + valid_len = 0; + break; case I40E_VIRTCHNL_OP_CONFIG_TX_QUEUE: valid_len = sizeof(struct i40e_virtchnl_txq_info); break; @@ -1886,10 +1899,10 @@ int i40e_vc_process_vf_msg(struct i40e_pf *pf, u16 vf_id, u32 v_opcode, switch (v_opcode) { case I40E_VIRTCHNL_OP_VERSION: - ret = i40e_vc_get_version_msg(vf); + ret = i40e_vc_get_version_msg(vf, msg); break; case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: - ret = i40e_vc_get_vf_resources_msg(vf); + ret = i40e_vc_get_vf_resources_msg(vf, msg); break; case I40E_VIRTCHNL_OP_RESET_VF: i40e_vc_reset_vf_msg(vf); diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h index d254a5e4abf1c..736f6f08b4f26 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.h @@ -78,6 +78,8 @@ struct i40e_vf { u16 vf_id; /* all VF vsis connect to the same parent */ enum i40e_switch_element_types parent_type; + struct i40e_virtchnl_version_info vf_ver; + u32 driver_caps; /* reported by VF driver */ /* VF Port Extender (PE) stag if used */ u16 stag; -- GitLab From e6d038de13c82f8446d9db5b3d9bb7788344b2bd Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:58 -0400 Subject: [PATCH 1527/7006] i40evf: handle big resets The most common type of reset that the VF will encounter is a PF reset that cascades down into a VF reset for each VF. In this case, the VF will always be assigned the same VSI and recovery is fairly simple. However, in the case of 'bigger' resets, such as a Core or EMP reset, when the device is reinitialized, it's probable that the VF will NOT get the same VSI. When this happens, the VF will not be able to recover, as it will continue to request resources for its original VSI. Add an extra state to the admin queue state machine so that the driver can re-request its configuration information at runtime. During reset recovery, set this bit in the aq_required field, and fetch the (possibly new) configuration information before attempting to bring the driver back up. Since the driver doesn't know what kind of reset it has encountered, this step is done even for a PF reset, but it doesn't hurt anything - it just gets the same VSI back. Change-ID: I915d59ffb40375215117362f4ac7a37811aba748 Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf.h | 2 + .../net/ethernet/intel/i40evf/i40evf_main.c | 109 +++++++++++------- .../ethernet/intel/i40evf/i40evf_virtchnl.c | 30 ++++- 3 files changed, 95 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index f3bcd05f7ecf8..dfc5bc5398900 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -234,6 +234,7 @@ struct i40evf_adapter { #define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) #define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) #define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) +#define I40EVF_FLAG_AQ_GET_CONFIG (u32)(1 << 10) /* OS defined structs */ struct net_device *netdev; @@ -273,6 +274,7 @@ extern const char i40evf_driver_version[]; int i40evf_up(struct i40evf_adapter *adapter); void i40evf_down(struct i40evf_adapter *adapter); +int i40evf_process_config(struct i40evf_adapter *adapter); void i40evf_reset(struct i40evf_adapter *adapter); void i40evf_set_ethtool_ops(struct net_device *netdev); void i40evf_update_stats(struct i40evf_adapter *adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index c698523923e4d..7b9037123fe76 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -1371,6 +1371,10 @@ static void i40evf_watchdog_task(struct work_struct *work) } goto watchdog_done; } + if (adapter->aq_required & I40EVF_FLAG_AQ_GET_CONFIG) { + i40evf_send_vf_config_msg(adapter); + goto watchdog_done; + } if (adapter->aq_required & I40EVF_FLAG_AQ_DISABLE_QUEUES) { i40evf_disable_queues(adapter); @@ -1606,7 +1610,8 @@ continue_reset: dev_info(&adapter->pdev->dev, "Failed to init adminq: %d\n", err); - i40evf_map_queues(adapter); + adapter->aq_required = I40EVF_FLAG_AQ_GET_CONFIG; + adapter->aq_required |= I40EVF_FLAG_AQ_MAP_VECTORS; /* re-add all MAC filters */ list_for_each_entry(f, &adapter->mac_filter_list, list) { @@ -1616,7 +1621,7 @@ continue_reset: list_for_each_entry(f, &adapter->vlan_filter_list, list) { f->add = true; } - adapter->aq_required = I40EVF_FLAG_AQ_ADD_MAC_FILTER; + adapter->aq_required |= I40EVF_FLAG_AQ_ADD_MAC_FILTER; adapter->aq_required |= I40EVF_FLAG_AQ_ADD_VLAN_FILTER; clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section); i40evf_misc_irq_enable(adapter); @@ -1981,6 +1986,62 @@ static int i40evf_check_reset_complete(struct i40e_hw *hw) return -EBUSY; } +/** + * i40evf_process_config - Process the config information we got from the PF + * @adapter: board private structure + * + * Verify that we have a valid config struct, and set up our netdev features + * and our VSI struct. + **/ +int i40evf_process_config(struct i40evf_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int i; + + /* got VF config message back from PF, now we can parse it */ + for (i = 0; i < adapter->vf_res->num_vsis; i++) { + if (adapter->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV) + adapter->vsi_res = &adapter->vf_res->vsi_res[i]; + } + if (!adapter->vsi_res) { + dev_err(&adapter->pdev->dev, "No LAN VSI found\n"); + return -ENODEV; + } + + if (adapter->vf_res->vf_offload_flags + & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) { + netdev->vlan_features = netdev->features; + netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | + NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_HW_VLAN_CTAG_FILTER; + } + netdev->features |= NETIF_F_HIGHDMA | + NETIF_F_SG | + NETIF_F_IP_CSUM | + NETIF_F_SCTP_CSUM | + NETIF_F_IPV6_CSUM | + NETIF_F_TSO | + NETIF_F_TSO6 | + NETIF_F_RXCSUM | + NETIF_F_GRO; + + /* copy netdev features into list of user selectable features */ + netdev->hw_features |= netdev->features; + netdev->hw_features &= ~NETIF_F_RXCSUM; + + adapter->vsi.id = adapter->vsi_res->vsi_id; + + adapter->vsi.back = adapter; + adapter->vsi.base_vector = 1; + adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; + adapter->vsi.rx_itr_setting = (I40E_ITR_DYNAMIC | + ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); + adapter->vsi.tx_itr_setting = (I40E_ITR_DYNAMIC | + ITR_REG_TO_USEC(I40E_ITR_TX_DEF)); + adapter->vsi.netdev = adapter->netdev; + return 0; +} + /** * i40evf_init_task - worker thread to perform delayed initialization * @work: pointer to work_struct containing our data @@ -2001,7 +2062,7 @@ static void i40evf_init_task(struct work_struct *work) struct net_device *netdev = adapter->netdev; struct i40e_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; - int i, err, bufsz; + int err, bufsz; switch (adapter->state) { case __I40EVF_STARTUP: @@ -2087,42 +2148,15 @@ static void i40evf_init_task(struct work_struct *work) default: goto err_alloc; } - /* got VF config message back from PF, now we can parse it */ - for (i = 0; i < adapter->vf_res->num_vsis; i++) { - if (adapter->vf_res->vsi_res[i].vsi_type == I40E_VSI_SRIOV) - adapter->vsi_res = &adapter->vf_res->vsi_res[i]; - } - if (!adapter->vsi_res) { - dev_err(&pdev->dev, "No LAN VSI found\n"); + if (i40evf_process_config(adapter)) goto err_alloc; - } + adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN; adapter->flags |= I40EVF_FLAG_RX_CSUM_ENABLED; netdev->netdev_ops = &i40evf_netdev_ops; i40evf_set_ethtool_ops(netdev); netdev->watchdog_timeo = 5 * HZ; - netdev->features |= NETIF_F_HIGHDMA | - NETIF_F_SG | - NETIF_F_IP_CSUM | - NETIF_F_SCTP_CSUM | - NETIF_F_IPV6_CSUM | - NETIF_F_TSO | - NETIF_F_TSO6 | - NETIF_F_RXCSUM | - NETIF_F_GRO; - - if (adapter->vf_res->vf_offload_flags - & I40E_VIRTCHNL_VF_OFFLOAD_VLAN) { - netdev->vlan_features = netdev->features; - netdev->features |= NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_CTAG_RX | - NETIF_F_HW_VLAN_CTAG_FILTER; - } - - /* copy netdev features into list of user selectable features */ - netdev->hw_features |= netdev->features; - netdev->hw_features &= ~NETIF_F_RXCSUM; if (!is_valid_ether_addr(adapter->hw.mac.addr)) { dev_info(&pdev->dev, "Invalid MAC address %pM, using random\n", @@ -2153,17 +2187,6 @@ static void i40evf_init_task(struct work_struct *work) netif_carrier_off(netdev); - adapter->vsi.id = adapter->vsi_res->vsi_id; - adapter->vsi.seid = adapter->vsi_res->vsi_id; /* dummy */ - adapter->vsi.back = adapter; - adapter->vsi.base_vector = 1; - adapter->vsi.work_limit = I40E_DEFAULT_IRQ_WORK; - adapter->vsi.rx_itr_setting = (I40E_ITR_DYNAMIC | - ITR_REG_TO_USEC(I40E_ITR_RX_DEF)); - adapter->vsi.tx_itr_setting = (I40E_ITR_DYNAMIC | - ITR_REG_TO_USEC(I40E_ITR_TX_DEF)); - adapter->vsi.netdev = adapter->netdev; - if (!adapter->netdev_registered) { err = register_netdev(netdev); if (err) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 61e090558f313..a37d56b275c10 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -145,8 +145,24 @@ out: **/ int i40evf_send_vf_config_msg(struct i40evf_adapter *adapter) { - return i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_GET_VF_RESOURCES, - NULL, 0); + u32 caps; + + adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; + adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; + caps = I40E_VIRTCHNL_VF_OFFLOAD_L2 | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ | + I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG | + I40E_VIRTCHNL_VF_OFFLOAD_VLAN; + adapter->current_op = I40E_VIRTCHNL_OP_GET_VF_RESOURCES; + adapter->aq_required &= ~I40EVF_FLAG_AQ_GET_CONFIG; + if (PF_IS_V11(adapter)) + return i40evf_send_pf_msg(adapter, + I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + (u8 *)&caps, sizeof(caps)); + else + return i40evf_send_pf_msg(adapter, + I40E_VIRTCHNL_OP_GET_VF_RESOURCES, + NULL, 0); } /** @@ -729,6 +745,15 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, adapter->current_stats = *stats; } break; + case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: { + u16 len = sizeof(struct i40e_virtchnl_vf_resource) + + I40E_MAX_VF_VSI * + sizeof(struct i40e_virtchnl_vsi_resource); + memcpy(adapter->vf_res, msg, min(msglen, len)); + i40e_vf_parse_hw_config(&adapter->hw, adapter->vf_res); + i40evf_process_config(adapter); + } + break; case I40E_VIRTCHNL_OP_ENABLE_QUEUES: /* enable transmits */ i40evf_irq_enable(adapter, true); @@ -740,7 +765,6 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, i40evf_free_all_rx_resources(adapter); break; case I40E_VIRTCHNL_OP_VERSION: - case I40E_VIRTCHNL_OP_GET_VF_RESOURCES: case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP: /* Don't display an error if we get these out of sequence. * If the firmware needed to get kicked, we'll get these and -- GitLab From ee1693e5a5ad6cfd701381a1d04cc1878bb90724 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:23:59 -0400 Subject: [PATCH 1528/7006] i40evf: support virtual channel API version 1.1 Store off the PF's API version, then use it to determine whether or not to send it our capabilities. Change the version checking to allow for PF drivers with lower API versions than our current version, so we can still talk to PF drivers over the 1.0 API. Change-ID: I8edc55d1229c7decf0ed3f285a63032694007c2e Signed-off-by: Mitch Williams Tested-by: Jim young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 6 ++++++ drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 7b9037123fe76..f43ac9c7e8269 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -2113,6 +2113,12 @@ static void i40evf_init_task(struct work_struct *work) if (err) { if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) err = i40evf_send_api_ver(adapter); + else + dev_err(&pdev->dev, "Unsupported PF API version %d.%d, expected %d.%d\n", + adapter->pf_version.major, + adapter->pf_version.minor, + I40E_VIRTCHNL_VERSION_MAJOR, + I40E_VIRTCHNL_VERSION_MINOR); goto err; } err = i40evf_send_vf_config_msg(adapter); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index a37d56b275c10..52c695939319f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -125,8 +125,11 @@ int i40evf_verify_api_ver(struct i40evf_adapter *adapter) } pf_vvi = (struct i40e_virtchnl_version_info *)event.msg_buf; - if ((pf_vvi->major != I40E_VIRTCHNL_VERSION_MAJOR) || - (pf_vvi->minor != I40E_VIRTCHNL_VERSION_MINOR)) + adapter->pf_version = *pf_vvi; + + if ((pf_vvi->major > I40E_VIRTCHNL_VERSION_MAJOR) || + ((pf_vvi->major == I40E_VIRTCHNL_VERSION_MAJOR) && + (pf_vvi->minor > I40E_VIRTCHNL_VERSION_MINOR))) err = -EIO; out_alloc: -- GitLab From 606a5488a18788c374e797643678a3c82621bf59 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Thu, 4 Jun 2015 16:24:00 -0400 Subject: [PATCH 1529/7006] i40e: provide correct API version to older VF drivers This driver fully supports VF drivers using both the 1.0 and 1.1 versions of the virtual channel API. However, VF drivers using version 1.0 get upset if we provide them with a version other than that, and refuse to play with us. Correct this by checking the VFs API version at the time that we store it off, and provide the correct version number back to the VF so we can all get along. Change-ID: I86dfe02e67b2bef336b4b49a1bb072f3e7229abc Signed-off-by: Mitch Williams Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 176a2898f1ad1..51aff70721956 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -1128,6 +1128,9 @@ static int i40e_vc_get_version_msg(struct i40e_vf *vf, u8 *msg) }; vf->vf_ver = *(struct i40e_virtchnl_version_info *)msg; + /* VFs running the 1.0 API expect to get 1.0 back or they will cry. */ + if (VF_IS_V10(vf)) + info.minor = I40E_VIRTCHNL_VERSION_MINOR_NO_VF_CAPS; return i40e_vc_send_msg_to_vf(vf, I40E_VIRTCHNL_OP_VERSION, I40E_SUCCESS, (u8 *)&info, sizeof(struct -- GitLab From f1c7e72e3903910d7cc25ed8f45b9ef42b96037d Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Thu, 4 Jun 2015 16:24:01 -0400 Subject: [PATCH 1530/7006] i40e: clean up error status messages Clean up a little confusion in reporting error status in phy and fcoe setup error reports by separating the return status from the AQ error. Add two decoder functions to make this easier. Change-ID: I960bcdeef3978a15fec1cdb5eff781d5cbae42fb Signed-off-by: Shannon Nelson Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_common.c | 206 +++++++++ .../net/ethernet/intel/i40e/i40e_ethtool.c | 30 +- drivers/net/ethernet/intel/i40e/i40e_main.c | 392 +++++++++++------- .../net/ethernet/intel/i40e/i40e_prototype.h | 2 + drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + .../net/ethernet/intel/i40evf/i40e_common.c | 206 +++++++++ .../ethernet/intel/i40evf/i40e_prototype.h | 2 + drivers/net/ethernet/intel/i40evf/i40e_type.h | 1 + .../ethernet/intel/i40evf/i40evf_virtchnl.c | 10 +- 9 files changed, 673 insertions(+), 177 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 07032229ee60f..8f2ecbe5e62cd 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -71,6 +71,212 @@ static i40e_status i40e_set_mac_type(struct i40e_hw *hw) return status; } +/** + * i40e_aq_str - convert AQ err code to a string + * @hw: pointer to the HW structure + * @aq_err: the AQ error code to convert + **/ +char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) +{ + switch (aq_err) { + case I40E_AQ_RC_OK: + return "OK"; + case I40E_AQ_RC_EPERM: + return "I40E_AQ_RC_EPERM"; + case I40E_AQ_RC_ENOENT: + return "I40E_AQ_RC_ENOENT"; + case I40E_AQ_RC_ESRCH: + return "I40E_AQ_RC_ESRCH"; + case I40E_AQ_RC_EINTR: + return "I40E_AQ_RC_EINTR"; + case I40E_AQ_RC_EIO: + return "I40E_AQ_RC_EIO"; + case I40E_AQ_RC_ENXIO: + return "I40E_AQ_RC_ENXIO"; + case I40E_AQ_RC_E2BIG: + return "I40E_AQ_RC_E2BIG"; + case I40E_AQ_RC_EAGAIN: + return "I40E_AQ_RC_EAGAIN"; + case I40E_AQ_RC_ENOMEM: + return "I40E_AQ_RC_ENOMEM"; + case I40E_AQ_RC_EACCES: + return "I40E_AQ_RC_EACCES"; + case I40E_AQ_RC_EFAULT: + return "I40E_AQ_RC_EFAULT"; + case I40E_AQ_RC_EBUSY: + return "I40E_AQ_RC_EBUSY"; + case I40E_AQ_RC_EEXIST: + return "I40E_AQ_RC_EEXIST"; + case I40E_AQ_RC_EINVAL: + return "I40E_AQ_RC_EINVAL"; + case I40E_AQ_RC_ENOTTY: + return "I40E_AQ_RC_ENOTTY"; + case I40E_AQ_RC_ENOSPC: + return "I40E_AQ_RC_ENOSPC"; + case I40E_AQ_RC_ENOSYS: + return "I40E_AQ_RC_ENOSYS"; + case I40E_AQ_RC_ERANGE: + return "I40E_AQ_RC_ERANGE"; + case I40E_AQ_RC_EFLUSHED: + return "I40E_AQ_RC_EFLUSHED"; + case I40E_AQ_RC_BAD_ADDR: + return "I40E_AQ_RC_BAD_ADDR"; + case I40E_AQ_RC_EMODE: + return "I40E_AQ_RC_EMODE"; + case I40E_AQ_RC_EFBIG: + return "I40E_AQ_RC_EFBIG"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err); + return hw->err_str; +} + +/** + * i40e_stat_str - convert status err code to a string + * @hw: pointer to the HW structure + * @stat_err: the status error code to convert + **/ +char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err) +{ + switch (stat_err) { + case 0: + return "OK"; + case I40E_ERR_NVM: + return "I40E_ERR_NVM"; + case I40E_ERR_NVM_CHECKSUM: + return "I40E_ERR_NVM_CHECKSUM"; + case I40E_ERR_PHY: + return "I40E_ERR_PHY"; + case I40E_ERR_CONFIG: + return "I40E_ERR_CONFIG"; + case I40E_ERR_PARAM: + return "I40E_ERR_PARAM"; + case I40E_ERR_MAC_TYPE: + return "I40E_ERR_MAC_TYPE"; + case I40E_ERR_UNKNOWN_PHY: + return "I40E_ERR_UNKNOWN_PHY"; + case I40E_ERR_LINK_SETUP: + return "I40E_ERR_LINK_SETUP"; + case I40E_ERR_ADAPTER_STOPPED: + return "I40E_ERR_ADAPTER_STOPPED"; + case I40E_ERR_INVALID_MAC_ADDR: + return "I40E_ERR_INVALID_MAC_ADDR"; + case I40E_ERR_DEVICE_NOT_SUPPORTED: + return "I40E_ERR_DEVICE_NOT_SUPPORTED"; + case I40E_ERR_MASTER_REQUESTS_PENDING: + return "I40E_ERR_MASTER_REQUESTS_PENDING"; + case I40E_ERR_INVALID_LINK_SETTINGS: + return "I40E_ERR_INVALID_LINK_SETTINGS"; + case I40E_ERR_AUTONEG_NOT_COMPLETE: + return "I40E_ERR_AUTONEG_NOT_COMPLETE"; + case I40E_ERR_RESET_FAILED: + return "I40E_ERR_RESET_FAILED"; + case I40E_ERR_SWFW_SYNC: + return "I40E_ERR_SWFW_SYNC"; + case I40E_ERR_NO_AVAILABLE_VSI: + return "I40E_ERR_NO_AVAILABLE_VSI"; + case I40E_ERR_NO_MEMORY: + return "I40E_ERR_NO_MEMORY"; + case I40E_ERR_BAD_PTR: + return "I40E_ERR_BAD_PTR"; + case I40E_ERR_RING_FULL: + return "I40E_ERR_RING_FULL"; + case I40E_ERR_INVALID_PD_ID: + return "I40E_ERR_INVALID_PD_ID"; + case I40E_ERR_INVALID_QP_ID: + return "I40E_ERR_INVALID_QP_ID"; + case I40E_ERR_INVALID_CQ_ID: + return "I40E_ERR_INVALID_CQ_ID"; + case I40E_ERR_INVALID_CEQ_ID: + return "I40E_ERR_INVALID_CEQ_ID"; + case I40E_ERR_INVALID_AEQ_ID: + return "I40E_ERR_INVALID_AEQ_ID"; + case I40E_ERR_INVALID_SIZE: + return "I40E_ERR_INVALID_SIZE"; + case I40E_ERR_INVALID_ARP_INDEX: + return "I40E_ERR_INVALID_ARP_INDEX"; + case I40E_ERR_INVALID_FPM_FUNC_ID: + return "I40E_ERR_INVALID_FPM_FUNC_ID"; + case I40E_ERR_QP_INVALID_MSG_SIZE: + return "I40E_ERR_QP_INVALID_MSG_SIZE"; + case I40E_ERR_QP_TOOMANY_WRS_POSTED: + return "I40E_ERR_QP_TOOMANY_WRS_POSTED"; + case I40E_ERR_INVALID_FRAG_COUNT: + return "I40E_ERR_INVALID_FRAG_COUNT"; + case I40E_ERR_QUEUE_EMPTY: + return "I40E_ERR_QUEUE_EMPTY"; + case I40E_ERR_INVALID_ALIGNMENT: + return "I40E_ERR_INVALID_ALIGNMENT"; + case I40E_ERR_FLUSHED_QUEUE: + return "I40E_ERR_FLUSHED_QUEUE"; + case I40E_ERR_INVALID_PUSH_PAGE_INDEX: + return "I40E_ERR_INVALID_PUSH_PAGE_INDEX"; + case I40E_ERR_INVALID_IMM_DATA_SIZE: + return "I40E_ERR_INVALID_IMM_DATA_SIZE"; + case I40E_ERR_TIMEOUT: + return "I40E_ERR_TIMEOUT"; + case I40E_ERR_OPCODE_MISMATCH: + return "I40E_ERR_OPCODE_MISMATCH"; + case I40E_ERR_CQP_COMPL_ERROR: + return "I40E_ERR_CQP_COMPL_ERROR"; + case I40E_ERR_INVALID_VF_ID: + return "I40E_ERR_INVALID_VF_ID"; + case I40E_ERR_INVALID_HMCFN_ID: + return "I40E_ERR_INVALID_HMCFN_ID"; + case I40E_ERR_BACKING_PAGE_ERROR: + return "I40E_ERR_BACKING_PAGE_ERROR"; + case I40E_ERR_NO_PBLCHUNKS_AVAILABLE: + return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE"; + case I40E_ERR_INVALID_PBLE_INDEX: + return "I40E_ERR_INVALID_PBLE_INDEX"; + case I40E_ERR_INVALID_SD_INDEX: + return "I40E_ERR_INVALID_SD_INDEX"; + case I40E_ERR_INVALID_PAGE_DESC_INDEX: + return "I40E_ERR_INVALID_PAGE_DESC_INDEX"; + case I40E_ERR_INVALID_SD_TYPE: + return "I40E_ERR_INVALID_SD_TYPE"; + case I40E_ERR_MEMCPY_FAILED: + return "I40E_ERR_MEMCPY_FAILED"; + case I40E_ERR_INVALID_HMC_OBJ_INDEX: + return "I40E_ERR_INVALID_HMC_OBJ_INDEX"; + case I40E_ERR_INVALID_HMC_OBJ_COUNT: + return "I40E_ERR_INVALID_HMC_OBJ_COUNT"; + case I40E_ERR_INVALID_SRQ_ARM_LIMIT: + return "I40E_ERR_INVALID_SRQ_ARM_LIMIT"; + case I40E_ERR_SRQ_ENABLED: + return "I40E_ERR_SRQ_ENABLED"; + case I40E_ERR_ADMIN_QUEUE_ERROR: + return "I40E_ERR_ADMIN_QUEUE_ERROR"; + case I40E_ERR_ADMIN_QUEUE_TIMEOUT: + return "I40E_ERR_ADMIN_QUEUE_TIMEOUT"; + case I40E_ERR_BUF_TOO_SHORT: + return "I40E_ERR_BUF_TOO_SHORT"; + case I40E_ERR_ADMIN_QUEUE_FULL: + return "I40E_ERR_ADMIN_QUEUE_FULL"; + case I40E_ERR_ADMIN_QUEUE_NO_WORK: + return "I40E_ERR_ADMIN_QUEUE_NO_WORK"; + case I40E_ERR_BAD_IWARP_CQE: + return "I40E_ERR_BAD_IWARP_CQE"; + case I40E_ERR_NVM_BLANK_MODE: + return "I40E_ERR_NVM_BLANK_MODE"; + case I40E_ERR_NOT_IMPLEMENTED: + return "I40E_ERR_NOT_IMPLEMENTED"; + case I40E_ERR_PE_DOORBELL_NOT_ENABLED: + return "I40E_ERR_PE_DOORBELL_NOT_ENABLED"; + case I40E_ERR_DIAG_TEST_FAILED: + return "I40E_ERR_DIAG_TEST_FAILED"; + case I40E_ERR_NOT_READY: + return "I40E_ERR_NOT_READY"; + case I40E_NOT_SUPPORTED: + return "I40E_NOT_SUPPORTED"; + case I40E_ERR_FIRMWARE_API_VERSION: + return "I40E_ERR_FIRMWARE_API_VERSION"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err); + return hw->err_str; +} + /** * i40e_debug_aq * @hw: debug mask related to admin queue diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index f2075d5b800c1..4b06a27ab7990 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -681,15 +681,17 @@ static int i40e_set_settings(struct net_device *netdev, /* make the aq call */ status = i40e_aq_set_phy_config(hw, &config, NULL); if (status) { - netdev_info(netdev, "Set phy config failed with error %d.\n", - status); + netdev_info(netdev, "Set phy config failed, err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); return -EAGAIN; } status = i40e_aq_get_link_info(hw, true, NULL, NULL); if (status) - netdev_info(netdev, "Updating link info failed with error %d\n", - status); + netdev_info(netdev, "Updating link info failed with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); } else { netdev_info(netdev, "Nothing changed, exiting without setting anything.\n"); @@ -709,8 +711,9 @@ static int i40e_nway_reset(struct net_device *netdev) ret = i40e_aq_set_link_restart_an(hw, link_up, NULL); if (ret) { - netdev_info(netdev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + netdev_info(netdev, "link restart failed, err %s aq_err %s\n", + i40e_stat_str(hw, ret), + i40e_aq_str(hw, hw->aq.asq_last_status)); return -EIO; } @@ -822,18 +825,21 @@ static int i40e_set_pauseparam(struct net_device *netdev, status = i40e_set_fc(hw, &aq_failures, link_up); if (aq_failures & I40E_SET_FC_AQ_FAIL_GET) { - netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with error %d and status %d\n", - status, hw->aq.asq_last_status); + netdev_info(netdev, "Set fc failed on the get_phy_capabilities call with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); err = -EAGAIN; } if (aq_failures & I40E_SET_FC_AQ_FAIL_SET) { - netdev_info(netdev, "Set fc failed on the set_phy_config call with error %d and status %d\n", - status, hw->aq.asq_last_status); + netdev_info(netdev, "Set fc failed on the set_phy_config call with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); err = -EAGAIN; } if (aq_failures & I40E_SET_FC_AQ_FAIL_UPDATE) { - netdev_info(netdev, "Set fc failed on the get_link_info call with error %d and status %d\n", - status, hw->aq.asq_last_status); + netdev_info(netdev, "Set fc failed on the get_link_info call with err %s aq_err %s\n", + i40e_stat_str(hw, status), + i40e_aq_str(hw, hw->aq.asq_last_status)); err = -EAGAIN; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 6ce9086e558a4..7646297e09816 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1276,7 +1276,7 @@ static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) { struct i40e_aqc_remove_macvlan_element_data element; struct i40e_pf *pf = vsi->back; - i40e_status aq_ret; + i40e_status ret; /* Only appropriate for the PF main VSI */ if (vsi->type != I40E_VSI_MAIN) @@ -1287,8 +1287,8 @@ static int i40e_rm_default_mac_filter(struct i40e_vsi *vsi, u8 *macaddr) element.vlan_tag = 0; element.flags = I40E_AQC_MACVLAN_DEL_PERFECT_MATCH | I40E_AQC_MACVLAN_DEL_IGNORE_VLAN; - aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); - if (aq_ret) + ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, &element, 1, NULL); + if (ret) return -ENOENT; return 0; @@ -1728,10 +1728,11 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) bool add_happened = false; int filter_list_len = 0; u32 changed_flags = 0; - i40e_status aq_ret = 0; + i40e_status ret = 0; struct i40e_pf *pf; int num_add = 0; int num_del = 0; + int aq_err = 0; u16 cmd_flags; /* empty array typed pointers, kcalloc later */ @@ -1783,31 +1784,31 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) /* flush a full buffer */ if (num_del == filter_list_len) { - aq_ret = i40e_aq_remove_macvlan(&pf->hw, - vsi->seid, del_list, num_del, - NULL); + ret = i40e_aq_remove_macvlan(&pf->hw, + vsi->seid, del_list, num_del, + NULL); + aq_err = pf->hw.aq.asq_last_status; num_del = 0; memset(del_list, 0, sizeof(*del_list)); - if (aq_ret && - pf->hw.aq.asq_last_status != - I40E_AQ_RC_ENOENT) + if (ret && aq_err != I40E_AQ_RC_ENOENT) dev_info(&pf->pdev->dev, - "ignoring delete macvlan error, err %d, aq_err %d while flushing a full buffer\n", - aq_ret, - pf->hw.aq.asq_last_status); + "ignoring delete macvlan error, err %s, aq_err %s while flushing a full buffer\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); } } if (num_del) { - aq_ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, + ret = i40e_aq_remove_macvlan(&pf->hw, vsi->seid, del_list, num_del, NULL); + aq_err = pf->hw.aq.asq_last_status; num_del = 0; - if (aq_ret && - pf->hw.aq.asq_last_status != I40E_AQ_RC_ENOENT) + if (ret && aq_err != I40E_AQ_RC_ENOENT) dev_info(&pf->pdev->dev, - "ignoring delete macvlan error, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "ignoring delete macvlan error, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); } kfree(del_list); @@ -1845,29 +1846,31 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) /* flush a full buffer */ if (num_add == filter_list_len) { - aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, - add_list, num_add, - NULL); + ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, + add_list, num_add, + NULL); + aq_err = pf->hw.aq.asq_last_status; num_add = 0; - if (aq_ret) + if (ret) break; memset(add_list, 0, sizeof(*add_list)); } } if (num_add) { - aq_ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, - add_list, num_add, NULL); + ret = i40e_aq_add_macvlan(&pf->hw, vsi->seid, + add_list, num_add, NULL); + aq_err = pf->hw.aq.asq_last_status; num_add = 0; } kfree(add_list); add_list = NULL; - if (add_happened && aq_ret && - pf->hw.aq.asq_last_status != I40E_AQ_RC_EINVAL) { + if (add_happened && ret && aq_err != I40E_AQ_RC_EINVAL) { dev_info(&pf->pdev->dev, - "add filter failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "add filter failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, aq_err)); if ((pf->hw.aq.asq_last_status == I40E_AQ_RC_ENOSPC) && !test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state)) { @@ -1883,34 +1886,40 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) if (changed_flags & IFF_ALLMULTI) { bool cur_multipromisc; cur_multipromisc = !!(vsi->current_netdev_flags & IFF_ALLMULTI); - aq_ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw, - vsi->seid, - cur_multipromisc, - NULL); - if (aq_ret) + ret = i40e_aq_set_vsi_multicast_promiscuous(&vsi->back->hw, + vsi->seid, + cur_multipromisc, + NULL); + if (ret) dev_info(&pf->pdev->dev, - "set multi promisc failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "set multi promisc failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } if ((changed_flags & IFF_PROMISC) || promisc_forced_on) { bool cur_promisc; cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) || test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state)); - aq_ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw, - vsi->seid, - cur_promisc, NULL); - if (aq_ret) + ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw, + vsi->seid, + cur_promisc, NULL); + if (ret) dev_info(&pf->pdev->dev, - "set uni promisc failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); - aq_ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw, - vsi->seid, - cur_promisc, NULL); - if (aq_ret) + "set uni promisc failed, err %s, aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); + ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw, + vsi->seid, + cur_promisc, NULL); + if (ret) dev_info(&pf->pdev->dev, - "set brdcast promisc failed, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "set brdcast promisc failed, err %s, aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } clear_bit(__I40E_CONFIG_BUSY, &vsi->state); @@ -2006,8 +2015,10 @@ void i40e_vlan_stripping_enable(struct i40e_vsi *vsi) ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "%s: update vsi failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vlan stripping failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); } } @@ -2035,8 +2046,10 @@ void i40e_vlan_stripping_disable(struct i40e_vsi *vsi) ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "%s: update vsi failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vlan stripping failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); } } @@ -2306,7 +2319,7 @@ static void i40e_restore_vlan(struct i40e_vsi *vsi) int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid) { struct i40e_vsi_context ctxt; - i40e_status aq_ret; + i40e_status ret; vsi->info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_VLAN_VALID); vsi->info.pvid = cpu_to_le16(vid); @@ -2316,11 +2329,13 @@ int i40e_vsi_add_pvid(struct i40e_vsi *vsi, u16 vid) ctxt.seid = vsi->seid; ctxt.info = vsi->info; - aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); + if (ret) { dev_info(&vsi->back->pdev->dev, - "%s: update vsi failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "add pvid failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); return -ENOENT; } @@ -4233,26 +4248,28 @@ static int i40e_vsi_get_bw_info(struct i40e_vsi *vsi) struct i40e_aqc_query_vsi_bw_config_resp bw_config = {0}; struct i40e_pf *pf = vsi->back; struct i40e_hw *hw = &pf->hw; - i40e_status aq_ret; + i40e_status ret; u32 tc_bw_max; int i; /* Get the VSI level BW configuration */ - aq_ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL); - if (aq_ret) { + ret = i40e_aq_query_vsi_bw_config(hw, vsi->seid, &bw_config, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "couldn't get PF vsi bw config, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi bw config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EINVAL; } /* Get the VSI level BW configuration per TC */ - aq_ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config, - NULL); - if (aq_ret) { + ret = i40e_aq_query_vsi_ets_sla_config(hw, vsi->seid, &bw_ets_config, + NULL); + if (ret) { dev_info(&pf->pdev->dev, - "couldn't get PF vsi ets bw config, err %d, aq_err %d\n", - aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi ets bw config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EINVAL; } @@ -4291,16 +4308,16 @@ static int i40e_vsi_configure_bw_alloc(struct i40e_vsi *vsi, u8 enabled_tc, u8 *bw_share) { struct i40e_aqc_configure_vsi_tc_bw_data bw_data; - i40e_status aq_ret; + i40e_status ret; int i; bw_data.tc_valid_bits = enabled_tc; for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) bw_data.tc_bw_credits[i] = bw_share[i]; - aq_ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data, - NULL); - if (aq_ret) { + ret = i40e_aq_config_vsi_tc_bw(&vsi->back->hw, vsi->seid, &bw_data, + NULL); + if (ret) { dev_info(&vsi->back->pdev->dev, "AQ command Config VSI BW allocation per TC failed = %d\n", vsi->back->hw.aq.asq_last_status); @@ -4435,8 +4452,10 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "update vsi failed, aq_err=%d\n", - vsi->back->hw.aq.asq_last_status); + "Update vsi tc config failed, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); goto out; } /* update the local VSI info with updated queue map */ @@ -4447,8 +4466,10 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) ret = i40e_vsi_get_bw_info(vsi); if (ret) { dev_info(&vsi->back->pdev->dev, - "Failed updating vsi bw info, aq_err=%d\n", - vsi->back->hw.aq.asq_last_status); + "Failed updating vsi bw info, err %s aq_err %s\n", + i40e_stat_str(&vsi->back->hw, ret), + i40e_aq_str(&vsi->back->hw, + vsi->back->hw.aq.asq_last_status)); goto out; } @@ -4489,8 +4510,9 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) &bw_data, NULL); if (ret) { dev_info(&pf->pdev->dev, - "veb bw config failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + "VEB bw config failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto out; } @@ -4498,8 +4520,9 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) ret = i40e_veb_get_bw_info(veb); if (ret) { dev_info(&pf->pdev->dev, - "Failed getting veb bw config, aq_err=%d\n", - pf->hw.aq.asq_last_status); + "Failed getting veb bw config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } out: @@ -4586,8 +4609,9 @@ static int i40e_resume_port_tx(struct i40e_pf *pf) ret = i40e_aq_resume_port_tx(hw, NULL); if (ret) { dev_info(&pf->pdev->dev, - "AQ command Resume Port Tx failed = %d\n", - pf->hw.aq.asq_last_status); + "Resume Port Tx failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* Schedule PF reset to recover */ set_bit(__I40E_PF_RESET_REQUESTED, &pf->state); i40e_service_event_schedule(pf); @@ -4639,8 +4663,9 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf) } } else { dev_info(&pf->pdev->dev, - "AQ Querying DCB configuration failed: aq_err %d\n", - pf->hw.aq.asq_last_status); + "Query for DCB configuration failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } out: @@ -5265,7 +5290,10 @@ static int i40e_handle_lldp_event(struct i40e_pf *pf, /* Get updated DCBX data from firmware */ ret = i40e_get_dcb_config(&pf->hw); if (ret) { - dev_info(&pf->pdev->dev, "Failed querying DCB configuration data from firmware.\n"); + dev_info(&pf->pdev->dev, + "Failed querying DCB configuration data from firmware, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto exit; } @@ -5995,27 +6023,29 @@ static void i40e_enable_pf_switch_lb(struct i40e_pf *pf) { struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_vsi_context ctxt; - int aq_ret; + int ret; ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; ctxt.vf_num = 0; - aq_ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s couldn't get PF vsi config, err %d, aq_err %d\n", - __func__, aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return; } ctxt.flags = I40E_AQ_VSI_TYPE_PF; ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); ctxt.info.switch_id |= cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); - aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s: update vsi switch failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vsi switch failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } } @@ -6029,27 +6059,29 @@ static void i40e_disable_pf_switch_lb(struct i40e_pf *pf) { struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi]; struct i40e_vsi_context ctxt; - int aq_ret; + int ret; ctxt.seid = pf->main_vsi_seid; ctxt.pf_num = pf->hw.pf_id; ctxt.vf_num = 0; - aq_ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_get_vsi_params(&pf->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s couldn't get PF vsi config, err %d, aq_err %d\n", - __func__, aq_ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return; } ctxt.flags = I40E_AQ_VSI_TYPE_PF; ctxt.info.valid_sections = cpu_to_le16(I40E_AQ_VSI_PROP_SWITCH_VALID); ctxt.info.switch_id &= ~cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB); - aq_ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); - if (aq_ret) { + ret = i40e_aq_update_vsi_params(&vsi->back->hw, &ctxt, NULL); + if (ret) { dev_info(&pf->pdev->dev, - "%s: update vsi switch failed, aq_err=%d\n", - __func__, vsi->back->hw.aq.asq_last_status); + "update vsi switch failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); } } @@ -6109,7 +6141,8 @@ static int i40e_reconstitute_veb(struct i40e_veb *veb) ret = i40e_add_vsi(ctl_vsi); if (ret) { dev_info(&pf->pdev->dev, - "rebuild of owner VSI failed: %d\n", ret); + "rebuild of veb_idx %d owner VSI failed: %d\n", + veb->idx, ret); goto end_reconstitute; } i40e_vsi_reset_stats(ctl_vsi); @@ -6188,8 +6221,10 @@ static int i40e_get_capabilities(struct i40e_pf *pf) buf_len = data_size; } else if (pf->hw.aq.asq_last_status != I40E_AQ_RC_OK) { dev_info(&pf->pdev->dev, - "capability discovery failed: aq=%d\n", - pf->hw.aq.asq_last_status); + "capability discovery failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); return -ENODEV; } } while (err); @@ -6375,7 +6410,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) /* rebuild the basics for the AdminQ, HMC, and initial HW switch */ ret = i40e_init_adminq(&pf->hw); if (ret) { - dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, %d\n", ret); + dev_info(&pf->pdev->dev, "Rebuild AdminQ failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); goto clear_recovery; } @@ -6385,11 +6422,8 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) i40e_clear_pxe_mode(hw); ret = i40e_get_capabilities(pf); - if (ret) { - dev_info(&pf->pdev->dev, "i40e_get_capabilities failed, %d\n", - ret); + if (ret) goto end_core_reset; - } ret = i40e_init_lan_hmc(hw, hw->func_caps.num_tx_qp, hw->func_caps.num_rx_qp, @@ -6430,12 +6464,16 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); if (ret) - dev_info(&pf->pdev->dev, "set phy mask fail, aq_err %d\n", ret); + dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* make sure our flow control settings are restored */ ret = i40e_set_fc(&pf->hw, &set_fc_aq_fail, true); if (ret) - dev_info(&pf->pdev->dev, "set fc fail, aq_err %d\n", ret); + dev_info(&pf->pdev->dev, "set fc fail, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* Rebuild the VSIs and VEBs that existed before reset. * They are still in our local switch element arrays, so only @@ -6496,8 +6534,10 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit) msleep(75); ret = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (ret) - dev_info(&pf->pdev->dev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, "link restart failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } /* reinit the misc interrupt */ if (pf->flags & I40E_FLAG_MSIX_ENABLED) @@ -6671,10 +6711,12 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) if (ret) { dev_info(&pf->pdev->dev, - "%s vxlan port %d, index %d failed, err %d, aq_err %d\n", + "%s vxlan port %d, index %d failed, err %s aq_err %s\n", port ? "add" : "delete", - ntohs(port), i, ret, - pf->hw.aq.asq_last_status); + ntohs(port), i, + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); pf->vxlan_ports[i] = 0; } } @@ -7579,8 +7621,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) last_aq_status = pf->hw.aq.asq_last_status; if (ret) { dev_info(&pf->pdev->dev, - "Cannot acquire NVM for read access, err %d: aq_err %d\n", - ret, last_aq_status); + "Cannot acquire NVM for read access, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); goto bw_commit_out; } @@ -7595,8 +7638,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) last_aq_status = pf->hw.aq.asq_last_status; i40e_release_nvm(&pf->hw); if (ret) { - dev_info(&pf->pdev->dev, "NVM read error, err %d aq_err %d\n", - ret, last_aq_status); + dev_info(&pf->pdev->dev, "NVM read error, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); goto bw_commit_out; } @@ -7608,8 +7652,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) last_aq_status = pf->hw.aq.asq_last_status; if (ret) { dev_info(&pf->pdev->dev, - "Cannot acquire NVM for write access, err %d: aq_err %d\n", - ret, last_aq_status); + "Cannot acquire NVM for write access, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); goto bw_commit_out; } /* Write it back out unchanged to initiate update NVM, @@ -7627,8 +7672,9 @@ i40e_status i40e_commit_npar_bw_setting(struct i40e_pf *pf) i40e_release_nvm(&pf->hw); if (ret) dev_info(&pf->pdev->dev, - "BW settings NOT SAVED, err %d aq_err %d\n", - ret, last_aq_status); + "BW settings NOT SAVED, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, last_aq_status)); bw_commit_out: return ret; @@ -8328,8 +8374,10 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ctxt.flags = I40E_AQ_VSI_TYPE_PF; if (ret) { dev_info(&pf->pdev->dev, - "couldn't get PF vsi config, err %d, aq_err %d\n", - ret, pf->hw.aq.asq_last_status); + "couldn't get PF vsi config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); return -ENOENT; } vsi->info = ctxt.info; @@ -8351,8 +8399,10 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_aq_update_vsi_params(hw, &ctxt, NULL); if (ret) { dev_info(&pf->pdev->dev, - "update vsi failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + "update vsi failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); ret = -ENOENT; goto err; } @@ -8369,9 +8419,11 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_vsi_config_tc(vsi, enabled_tc); if (ret) { dev_info(&pf->pdev->dev, - "failed to configure TCs for main VSI tc_map 0x%08x, err %d, aq_err %d\n", - enabled_tc, ret, - pf->hw.aq.asq_last_status); + "failed to configure TCs for main VSI tc_map 0x%08x, err %s aq_err %s\n", + enabled_tc, + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); ret = -ENOENT; } } @@ -8462,8 +8514,10 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_aq_add_vsi(hw, &ctxt, NULL); if (ret) { dev_info(&vsi->back->pdev->dev, - "add vsi failed, aq_err=%d\n", - vsi->back->hw.aq.asq_last_status); + "add vsi failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); ret = -ENOENT; goto err; } @@ -8508,8 +8562,9 @@ static int i40e_add_vsi(struct i40e_vsi *vsi) ret = i40e_vsi_get_bw_info(vsi); if (ret) { dev_info(&pf->pdev->dev, - "couldn't get vsi bw info, err %d, aq_err %d\n", - ret, pf->hw.aq.asq_last_status); + "couldn't get vsi bw info, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); /* VSI is already added so not tearing that up */ ret = 0; } @@ -8682,7 +8737,7 @@ static struct i40e_vsi *i40e_vsi_reinit_setup(struct i40e_vsi *vsi) ret = i40e_get_lump(pf, pf->qp_pile, vsi->alloc_queue_pairs, vsi->idx); if (ret < 0) { dev_info(&pf->pdev->dev, - "failed to get tracking for %d queues for VSI %d err=%d\n", + "failed to get tracking for %d queues for VSI %d err %d\n", vsi->alloc_queue_pairs, vsi->seid, ret); goto err_vsi; } @@ -8920,8 +8975,9 @@ static int i40e_veb_get_bw_info(struct i40e_veb *veb) &bw_data, NULL); if (ret) { dev_info(&pf->pdev->dev, - "query veb bw config failed, aq_err=%d\n", - hw->aq.asq_last_status); + "query veb bw config failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, hw->aq.asq_last_status)); goto out; } @@ -8929,8 +8985,9 @@ static int i40e_veb_get_bw_info(struct i40e_veb *veb) &ets_data, NULL); if (ret) { dev_info(&pf->pdev->dev, - "query veb bw ets config failed, aq_err=%d\n", - hw->aq.asq_last_status); + "query veb bw ets config failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, hw->aq.asq_last_status)); goto out; } @@ -9114,36 +9171,40 @@ void i40e_veb_release(struct i40e_veb *veb) **/ static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) { + struct i40e_pf *pf = veb->pf; bool is_default = false; bool is_cloud = false; int ret; /* get a VEB from the hardware */ - ret = i40e_aq_add_veb(&veb->pf->hw, veb->uplink_seid, vsi->seid, + ret = i40e_aq_add_veb(&pf->hw, veb->uplink_seid, vsi->seid, veb->enabled_tc, is_default, is_cloud, &veb->seid, NULL); if (ret) { - dev_info(&veb->pf->pdev->dev, - "couldn't add VEB, err %d, aq_err %d\n", - ret, veb->pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, + "couldn't add VEB, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EPERM; } /* get statistics counter */ - ret = i40e_aq_get_veb_parameters(&veb->pf->hw, veb->seid, NULL, NULL, + ret = i40e_aq_get_veb_parameters(&pf->hw, veb->seid, NULL, NULL, &veb->stats_idx, NULL, NULL, NULL); if (ret) { - dev_info(&veb->pf->pdev->dev, - "couldn't get VEB statistics idx, err %d, aq_err %d\n", - ret, veb->pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, + "couldn't get VEB statistics idx, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return -EPERM; } ret = i40e_veb_get_bw_info(veb); if (ret) { - dev_info(&veb->pf->pdev->dev, - "couldn't get VEB bw info, err %d, aq_err %d\n", - ret, veb->pf->hw.aq.asq_last_status); - i40e_aq_delete_element(&veb->pf->hw, veb->seid, NULL); + dev_info(&pf->pdev->dev, + "couldn't get VEB bw info, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); + i40e_aq_delete_element(&pf->hw, veb->seid, NULL); return -ENOENT; } @@ -9349,8 +9410,10 @@ int i40e_fetch_switch_configuration(struct i40e_pf *pf, bool printconfig) &next_seid, NULL); if (ret) { dev_info(&pf->pdev->dev, - "get switch config failed %d aq_err=%x\n", - ret, pf->hw.aq.asq_last_status); + "get switch config failed err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); kfree(aq_buf); return -ENOENT; } @@ -9391,8 +9454,9 @@ static int i40e_setup_pf_switch(struct i40e_pf *pf, bool reinit) ret = i40e_fetch_switch_configuration(pf, false); if (ret) { dev_info(&pf->pdev->dev, - "couldn't fetch switch config, err %d, aq_err %d\n", - ret, pf->hw.aq.asq_last_status); + "couldn't fetch switch config, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, ret), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); return ret; } i40e_pf_reset_stats(pf); @@ -9935,15 +9999,19 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) I40E_AQ_EVENT_LINK_UPDOWN | I40E_AQ_EVENT_MODULE_QUAL_FAIL, NULL); if (err) - dev_info(&pf->pdev->dev, "set phy mask fail, aq_err %d\n", err); + dev_info(&pf->pdev->dev, "set phy mask fail, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 33)) || (pf->hw.aq.fw_maj_ver < 4)) { msleep(75); err = i40e_aq_set_link_restart_an(&pf->hw, true, NULL); if (err) - dev_info(&pf->pdev->dev, "link restart failed, aq_err=%d\n", - pf->hw.aq.asq_last_status); + dev_info(&pf->pdev->dev, "link restart failed, err %s aq_err %s\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, + pf->hw.aq.asq_last_status)); } /* The main driver is (mostly) up and happy. We need to set this state * before setting up the misc vector or we get a race and the vector @@ -10031,8 +10099,10 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* get the requested speeds from the fw */ err = i40e_aq_get_phy_capabilities(hw, false, false, &abilities, NULL); if (err) - dev_info(&pf->pdev->dev, "get phy abilities failed, aq_err %d, advertised speed settings may not be correct\n", - err); + dev_info(&pf->pdev->dev, + "get phy capabilities failed, err %s aq_err %s, advertised speed settings may not be correct\n", + i40e_stat_str(&pf->hw, err), + i40e_aq_str(&pf->hw, pf->hw.aq.asq_last_status)); pf->hw.phy.link_info.requested_speeds = abilities.link_speed; /* print a string summarizing features */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h index 7b34f1e660eac..d52a9f7873b0c 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h @@ -58,6 +58,8 @@ void i40e_debug_aq(struct i40e_hw *hw, enum i40e_debug_mask mask, void i40e_idle_aq(struct i40e_hw *hw); bool i40e_check_asq_alive(struct i40e_hw *hw); i40e_status i40e_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); +char *i40e_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); +char *i40e_stat_str(struct i40e_hw *hw, i40e_status stat_err); u32 i40e_led_get(struct i40e_hw *hw); void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink); diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 220371ece7c43..0cabf04cf23b3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -497,6 +497,7 @@ struct i40e_hw { /* debug mask */ u32 debug_mask; + char err_str[16]; }; static inline bool i40e_is_vf(struct i40e_hw *hw) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 39fcb1dc4ea64..56c7e751149b0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -71,6 +71,212 @@ i40e_status i40e_set_mac_type(struct i40e_hw *hw) return status; } +/** + * i40evf_aq_str - convert AQ err code to a string + * @hw: pointer to the HW structure + * @aq_err: the AQ error code to convert + **/ +char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err) +{ + switch (aq_err) { + case I40E_AQ_RC_OK: + return "OK"; + case I40E_AQ_RC_EPERM: + return "I40E_AQ_RC_EPERM"; + case I40E_AQ_RC_ENOENT: + return "I40E_AQ_RC_ENOENT"; + case I40E_AQ_RC_ESRCH: + return "I40E_AQ_RC_ESRCH"; + case I40E_AQ_RC_EINTR: + return "I40E_AQ_RC_EINTR"; + case I40E_AQ_RC_EIO: + return "I40E_AQ_RC_EIO"; + case I40E_AQ_RC_ENXIO: + return "I40E_AQ_RC_ENXIO"; + case I40E_AQ_RC_E2BIG: + return "I40E_AQ_RC_E2BIG"; + case I40E_AQ_RC_EAGAIN: + return "I40E_AQ_RC_EAGAIN"; + case I40E_AQ_RC_ENOMEM: + return "I40E_AQ_RC_ENOMEM"; + case I40E_AQ_RC_EACCES: + return "I40E_AQ_RC_EACCES"; + case I40E_AQ_RC_EFAULT: + return "I40E_AQ_RC_EFAULT"; + case I40E_AQ_RC_EBUSY: + return "I40E_AQ_RC_EBUSY"; + case I40E_AQ_RC_EEXIST: + return "I40E_AQ_RC_EEXIST"; + case I40E_AQ_RC_EINVAL: + return "I40E_AQ_RC_EINVAL"; + case I40E_AQ_RC_ENOTTY: + return "I40E_AQ_RC_ENOTTY"; + case I40E_AQ_RC_ENOSPC: + return "I40E_AQ_RC_ENOSPC"; + case I40E_AQ_RC_ENOSYS: + return "I40E_AQ_RC_ENOSYS"; + case I40E_AQ_RC_ERANGE: + return "I40E_AQ_RC_ERANGE"; + case I40E_AQ_RC_EFLUSHED: + return "I40E_AQ_RC_EFLUSHED"; + case I40E_AQ_RC_BAD_ADDR: + return "I40E_AQ_RC_BAD_ADDR"; + case I40E_AQ_RC_EMODE: + return "I40E_AQ_RC_EMODE"; + case I40E_AQ_RC_EFBIG: + return "I40E_AQ_RC_EFBIG"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", aq_err); + return hw->err_str; +} + +/** + * i40evf_stat_str - convert status err code to a string + * @hw: pointer to the HW structure + * @stat_err: the status error code to convert + **/ +char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err) +{ + switch (stat_err) { + case 0: + return "OK"; + case I40E_ERR_NVM: + return "I40E_ERR_NVM"; + case I40E_ERR_NVM_CHECKSUM: + return "I40E_ERR_NVM_CHECKSUM"; + case I40E_ERR_PHY: + return "I40E_ERR_PHY"; + case I40E_ERR_CONFIG: + return "I40E_ERR_CONFIG"; + case I40E_ERR_PARAM: + return "I40E_ERR_PARAM"; + case I40E_ERR_MAC_TYPE: + return "I40E_ERR_MAC_TYPE"; + case I40E_ERR_UNKNOWN_PHY: + return "I40E_ERR_UNKNOWN_PHY"; + case I40E_ERR_LINK_SETUP: + return "I40E_ERR_LINK_SETUP"; + case I40E_ERR_ADAPTER_STOPPED: + return "I40E_ERR_ADAPTER_STOPPED"; + case I40E_ERR_INVALID_MAC_ADDR: + return "I40E_ERR_INVALID_MAC_ADDR"; + case I40E_ERR_DEVICE_NOT_SUPPORTED: + return "I40E_ERR_DEVICE_NOT_SUPPORTED"; + case I40E_ERR_MASTER_REQUESTS_PENDING: + return "I40E_ERR_MASTER_REQUESTS_PENDING"; + case I40E_ERR_INVALID_LINK_SETTINGS: + return "I40E_ERR_INVALID_LINK_SETTINGS"; + case I40E_ERR_AUTONEG_NOT_COMPLETE: + return "I40E_ERR_AUTONEG_NOT_COMPLETE"; + case I40E_ERR_RESET_FAILED: + return "I40E_ERR_RESET_FAILED"; + case I40E_ERR_SWFW_SYNC: + return "I40E_ERR_SWFW_SYNC"; + case I40E_ERR_NO_AVAILABLE_VSI: + return "I40E_ERR_NO_AVAILABLE_VSI"; + case I40E_ERR_NO_MEMORY: + return "I40E_ERR_NO_MEMORY"; + case I40E_ERR_BAD_PTR: + return "I40E_ERR_BAD_PTR"; + case I40E_ERR_RING_FULL: + return "I40E_ERR_RING_FULL"; + case I40E_ERR_INVALID_PD_ID: + return "I40E_ERR_INVALID_PD_ID"; + case I40E_ERR_INVALID_QP_ID: + return "I40E_ERR_INVALID_QP_ID"; + case I40E_ERR_INVALID_CQ_ID: + return "I40E_ERR_INVALID_CQ_ID"; + case I40E_ERR_INVALID_CEQ_ID: + return "I40E_ERR_INVALID_CEQ_ID"; + case I40E_ERR_INVALID_AEQ_ID: + return "I40E_ERR_INVALID_AEQ_ID"; + case I40E_ERR_INVALID_SIZE: + return "I40E_ERR_INVALID_SIZE"; + case I40E_ERR_INVALID_ARP_INDEX: + return "I40E_ERR_INVALID_ARP_INDEX"; + case I40E_ERR_INVALID_FPM_FUNC_ID: + return "I40E_ERR_INVALID_FPM_FUNC_ID"; + case I40E_ERR_QP_INVALID_MSG_SIZE: + return "I40E_ERR_QP_INVALID_MSG_SIZE"; + case I40E_ERR_QP_TOOMANY_WRS_POSTED: + return "I40E_ERR_QP_TOOMANY_WRS_POSTED"; + case I40E_ERR_INVALID_FRAG_COUNT: + return "I40E_ERR_INVALID_FRAG_COUNT"; + case I40E_ERR_QUEUE_EMPTY: + return "I40E_ERR_QUEUE_EMPTY"; + case I40E_ERR_INVALID_ALIGNMENT: + return "I40E_ERR_INVALID_ALIGNMENT"; + case I40E_ERR_FLUSHED_QUEUE: + return "I40E_ERR_FLUSHED_QUEUE"; + case I40E_ERR_INVALID_PUSH_PAGE_INDEX: + return "I40E_ERR_INVALID_PUSH_PAGE_INDEX"; + case I40E_ERR_INVALID_IMM_DATA_SIZE: + return "I40E_ERR_INVALID_IMM_DATA_SIZE"; + case I40E_ERR_TIMEOUT: + return "I40E_ERR_TIMEOUT"; + case I40E_ERR_OPCODE_MISMATCH: + return "I40E_ERR_OPCODE_MISMATCH"; + case I40E_ERR_CQP_COMPL_ERROR: + return "I40E_ERR_CQP_COMPL_ERROR"; + case I40E_ERR_INVALID_VF_ID: + return "I40E_ERR_INVALID_VF_ID"; + case I40E_ERR_INVALID_HMCFN_ID: + return "I40E_ERR_INVALID_HMCFN_ID"; + case I40E_ERR_BACKING_PAGE_ERROR: + return "I40E_ERR_BACKING_PAGE_ERROR"; + case I40E_ERR_NO_PBLCHUNKS_AVAILABLE: + return "I40E_ERR_NO_PBLCHUNKS_AVAILABLE"; + case I40E_ERR_INVALID_PBLE_INDEX: + return "I40E_ERR_INVALID_PBLE_INDEX"; + case I40E_ERR_INVALID_SD_INDEX: + return "I40E_ERR_INVALID_SD_INDEX"; + case I40E_ERR_INVALID_PAGE_DESC_INDEX: + return "I40E_ERR_INVALID_PAGE_DESC_INDEX"; + case I40E_ERR_INVALID_SD_TYPE: + return "I40E_ERR_INVALID_SD_TYPE"; + case I40E_ERR_MEMCPY_FAILED: + return "I40E_ERR_MEMCPY_FAILED"; + case I40E_ERR_INVALID_HMC_OBJ_INDEX: + return "I40E_ERR_INVALID_HMC_OBJ_INDEX"; + case I40E_ERR_INVALID_HMC_OBJ_COUNT: + return "I40E_ERR_INVALID_HMC_OBJ_COUNT"; + case I40E_ERR_INVALID_SRQ_ARM_LIMIT: + return "I40E_ERR_INVALID_SRQ_ARM_LIMIT"; + case I40E_ERR_SRQ_ENABLED: + return "I40E_ERR_SRQ_ENABLED"; + case I40E_ERR_ADMIN_QUEUE_ERROR: + return "I40E_ERR_ADMIN_QUEUE_ERROR"; + case I40E_ERR_ADMIN_QUEUE_TIMEOUT: + return "I40E_ERR_ADMIN_QUEUE_TIMEOUT"; + case I40E_ERR_BUF_TOO_SHORT: + return "I40E_ERR_BUF_TOO_SHORT"; + case I40E_ERR_ADMIN_QUEUE_FULL: + return "I40E_ERR_ADMIN_QUEUE_FULL"; + case I40E_ERR_ADMIN_QUEUE_NO_WORK: + return "I40E_ERR_ADMIN_QUEUE_NO_WORK"; + case I40E_ERR_BAD_IWARP_CQE: + return "I40E_ERR_BAD_IWARP_CQE"; + case I40E_ERR_NVM_BLANK_MODE: + return "I40E_ERR_NVM_BLANK_MODE"; + case I40E_ERR_NOT_IMPLEMENTED: + return "I40E_ERR_NOT_IMPLEMENTED"; + case I40E_ERR_PE_DOORBELL_NOT_ENABLED: + return "I40E_ERR_PE_DOORBELL_NOT_ENABLED"; + case I40E_ERR_DIAG_TEST_FAILED: + return "I40E_ERR_DIAG_TEST_FAILED"; + case I40E_ERR_NOT_READY: + return "I40E_ERR_NOT_READY"; + case I40E_NOT_SUPPORTED: + return "I40E_NOT_SUPPORTED"; + case I40E_ERR_FIRMWARE_API_VERSION: + return "I40E_ERR_FIRMWARE_API_VERSION"; + } + + snprintf(hw->err_str, sizeof(hw->err_str), "%d", stat_err); + return hw->err_str; +} + /** * i40evf_debug_aq * @hw: debug mask related to admin queue diff --git a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h index 58e37a44b80a1..856eb9d06595e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_prototype.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_prototype.h @@ -60,6 +60,8 @@ void i40e_idle_aq(struct i40e_hw *hw); void i40evf_resume_aq(struct i40e_hw *hw); bool i40evf_check_asq_alive(struct i40e_hw *hw); i40e_status i40evf_aq_queue_shutdown(struct i40e_hw *hw, bool unloading); +char *i40evf_aq_str(struct i40e_hw *hw, enum i40e_admin_queue_err aq_err); +char *i40evf_stat_str(struct i40e_hw *hw, i40e_status stat_err); i40e_status i40e_set_mac_type(struct i40e_hw *hw); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 3969c6548af05..cbf94bd4f2bfe 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -491,6 +491,7 @@ struct i40e_hw { /* debug mask */ u32 debug_mask; + char err_str[16]; }; static inline bool i40e_is_vf(struct i40e_hw *hw) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index 52c695939319f..becd300fca7c1 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -51,8 +51,9 @@ static int i40evf_send_pf_msg(struct i40evf_adapter *adapter, err = i40e_aq_send_msg_to_pf(hw, op, 0, msg, len, NULL); if (err) - dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, error %d, aq status %d\n", - op, err, hw->aq.asq_last_status); + dev_err(&adapter->pdev->dev, "Unable to send opcode %d to PF, err %s, aq_err %s\n", + op, i40evf_stat_str(hw, err), + i40evf_aq_str(hw, hw->aq.asq_last_status)); return err; } @@ -727,8 +728,9 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter, return; } if (v_retval) { - dev_err(&adapter->pdev->dev, "%s: PF returned error %d to our request %d\n", - __func__, v_retval, v_opcode); + dev_err(&adapter->pdev->dev, "%s: PF returned error %d (%s) to our request %d\n", + __func__, v_retval, + i40evf_stat_str(&adapter->hw, v_retval), v_opcode); } switch (v_opcode) { case I40E_VIRTCHNL_OP_GET_STATS: { -- GitLab From 41a1d04b9d2006fdac5cab7680cff89915610944 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 4 Jun 2015 16:24:02 -0400 Subject: [PATCH 1531/7006] i40e: use BIT and BIT_ULL macros Use macros for abstracting (1 << foo) to BIT(foo) and (1ULL << foo64) to BIT_ULL(foo64) in order to match better with kernel requirements. NOTE: the adminq_cmd.h file was not modified on purpose because of the dependency upon firmware for that file. Change-ID: I73ee2e48c880d671948aad19bd53ca6b2ac558fc Signed-off-by: Jesse Brandeburg Signed-off-by: Catherine Sullivan Tested-by: Jim Young Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 56 +++++++------- drivers/net/ethernet/intel/i40e/i40e_common.c | 4 +- drivers/net/ethernet/intel/i40e/i40e_dcb.h | 8 +- drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c | 2 +- .../net/ethernet/intel/i40e/i40e_debugfs.c | 10 +-- drivers/net/ethernet/intel/i40e/i40e_diag.c | 11 +-- .../net/ethernet/intel/i40e/i40e_ethtool.c | 54 +++++++------- drivers/net/ethernet/intel/i40e/i40e_fcoe.c | 12 +-- drivers/net/ethernet/intel/i40e/i40e_fcoe.h | 4 +- drivers/net/ethernet/intel/i40e/i40e_hmc.h | 6 +- .../net/ethernet/intel/i40e/i40e_lan_hmc.c | 16 ++-- drivers/net/ethernet/intel/i40e/i40e_main.c | 73 ++++++++++--------- drivers/net/ethernet/intel/i40e/i40e_nvm.c | 6 +- drivers/net/ethernet/intel/i40e/i40e_ptp.c | 7 +- drivers/net/ethernet/intel/i40e/i40e_txrx.c | 39 +++++----- drivers/net/ethernet/intel/i40e/i40e_txrx.h | 44 +++++------ drivers/net/ethernet/intel/i40e/i40e_type.h | 22 +++--- .../ethernet/intel/i40e/i40e_virtchnl_pf.c | 18 ++--- drivers/net/ethernet/intel/i40evf/i40e_hmc.h | 6 +- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 37 +++++----- drivers/net/ethernet/intel/i40evf/i40e_txrx.h | 42 +++++------ drivers/net/ethernet/intel/i40evf/i40e_type.h | 22 +++--- drivers/net/ethernet/intel/i40evf/i40evf.h | 42 +++++------ .../ethernet/intel/i40evf/i40evf_ethtool.c | 44 +++++------ .../net/ethernet/intel/i40evf/i40evf_main.c | 8 +- .../ethernet/intel/i40evf/i40evf_virtchnl.c | 4 +- 26 files changed, 293 insertions(+), 304 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index ec76c3fa3a041..281fd84561461 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -98,7 +98,7 @@ #define I40E_INT_NAME_STR_LEN (IFNAMSIZ + 9) /* Ethtool Private Flags */ -#define I40E_PRIV_FLAGS_NPAR_FLAG (1 << 0) +#define I40E_PRIV_FLAGS_NPAR_FLAG BIT(0) #define I40E_NVM_VERSION_LO_SHIFT 0 #define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT) @@ -289,35 +289,35 @@ struct i40e_pf { struct work_struct service_task; u64 flags; -#define I40E_FLAG_RX_CSUM_ENABLED (u64)(1 << 1) -#define I40E_FLAG_MSI_ENABLED (u64)(1 << 2) -#define I40E_FLAG_MSIX_ENABLED (u64)(1 << 3) -#define I40E_FLAG_RX_1BUF_ENABLED (u64)(1 << 4) -#define I40E_FLAG_RX_PS_ENABLED (u64)(1 << 5) -#define I40E_FLAG_RSS_ENABLED (u64)(1 << 6) -#define I40E_FLAG_VMDQ_ENABLED (u64)(1 << 7) -#define I40E_FLAG_FDIR_REQUIRES_REINIT (u64)(1 << 8) -#define I40E_FLAG_NEED_LINK_UPDATE (u64)(1 << 9) +#define I40E_FLAG_RX_CSUM_ENABLED BIT_ULL(1) +#define I40E_FLAG_MSI_ENABLED BIT_ULL(2) +#define I40E_FLAG_MSIX_ENABLED BIT_ULL(3) +#define I40E_FLAG_RX_1BUF_ENABLED BIT_ULL(4) +#define I40E_FLAG_RX_PS_ENABLED BIT_ULL(5) +#define I40E_FLAG_RSS_ENABLED BIT_ULL(6) +#define I40E_FLAG_VMDQ_ENABLED BIT_ULL(7) +#define I40E_FLAG_FDIR_REQUIRES_REINIT BIT_ULL(8) +#define I40E_FLAG_NEED_LINK_UPDATE BIT_ULL(9) #ifdef I40E_FCOE -#define I40E_FLAG_FCOE_ENABLED (u64)(1 << 11) +#define I40E_FLAG_FCOE_ENABLED BIT_ULL(11) #endif /* I40E_FCOE */ -#define I40E_FLAG_IN_NETPOLL (u64)(1 << 12) -#define I40E_FLAG_16BYTE_RX_DESC_ENABLED (u64)(1 << 13) -#define I40E_FLAG_CLEAN_ADMINQ (u64)(1 << 14) -#define I40E_FLAG_FILTER_SYNC (u64)(1 << 15) -#define I40E_FLAG_PROCESS_MDD_EVENT (u64)(1 << 17) -#define I40E_FLAG_PROCESS_VFLR_EVENT (u64)(1 << 18) -#define I40E_FLAG_SRIOV_ENABLED (u64)(1 << 19) -#define I40E_FLAG_DCB_ENABLED (u64)(1 << 20) -#define I40E_FLAG_FD_SB_ENABLED (u64)(1 << 21) -#define I40E_FLAG_FD_ATR_ENABLED (u64)(1 << 22) -#define I40E_FLAG_PTP (u64)(1 << 25) -#define I40E_FLAG_MFP_ENABLED (u64)(1 << 26) +#define I40E_FLAG_IN_NETPOLL BIT_ULL(12) +#define I40E_FLAG_16BYTE_RX_DESC_ENABLED BIT_ULL(13) +#define I40E_FLAG_CLEAN_ADMINQ BIT_ULL(14) +#define I40E_FLAG_FILTER_SYNC BIT_ULL(15) +#define I40E_FLAG_PROCESS_MDD_EVENT BIT_ULL(17) +#define I40E_FLAG_PROCESS_VFLR_EVENT BIT_ULL(18) +#define I40E_FLAG_SRIOV_ENABLED BIT_ULL(19) +#define I40E_FLAG_DCB_ENABLED BIT_ULL(20) +#define I40E_FLAG_FD_SB_ENABLED BIT_ULL(21) +#define I40E_FLAG_FD_ATR_ENABLED BIT_ULL(22) +#define I40E_FLAG_PTP BIT_ULL(25) +#define I40E_FLAG_MFP_ENABLED BIT_ULL(26) #ifdef CONFIG_I40E_VXLAN -#define I40E_FLAG_VXLAN_FILTER_SYNC (u64)(1 << 27) +#define I40E_FLAG_VXLAN_FILTER_SYNC BIT_ULL(27) #endif -#define I40E_FLAG_PORT_ID_VALID (u64)(1 << 28) -#define I40E_FLAG_DCB_CAPABLE (u64)(1 << 29) +#define I40E_FLAG_PORT_ID_VALID BIT_ULL(28) +#define I40E_FLAG_DCB_CAPABLE BIT_ULL(29) #define I40E_FLAG_VEB_MODE_ENABLED BIT_ULL(40) /* tracks features that get auto disabled by errors */ @@ -443,8 +443,8 @@ struct i40e_vsi { u32 current_netdev_flags; unsigned long state; -#define I40E_VSI_FLAG_FILTER_CHANGED (1<<0) -#define I40E_VSI_FLAG_VEB_OWNER (1<<1) +#define I40E_VSI_FLAG_FILTER_CHANGED BIT(0) +#define I40E_VSI_FLAG_VEB_OWNER BIT(1) unsigned long flags; struct list_head mac_filter_list; diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c index 8f2ecbe5e62cd..167ca0d752ea8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_common.c +++ b/drivers/net/ethernet/intel/i40e/i40e_common.c @@ -1393,9 +1393,9 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink) blink = false; if (blink) - gpio_val |= (1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); + gpio_val |= BIT(I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); else - gpio_val &= ~(1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); + gpio_val &= ~BIT(I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT); wr32(hw, I40E_GLGEN_GPIO_CTL(i), gpio_val); break; diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.h b/drivers/net/ethernet/intel/i40e/i40e_dcb.h index e137e3fac8ee2..50fc894a4cde3 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.h +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.h @@ -58,9 +58,9 @@ #define I40E_IEEE_ETS_MAXTC_SHIFT 0 #define I40E_IEEE_ETS_MAXTC_MASK (0x7 << I40E_IEEE_ETS_MAXTC_SHIFT) #define I40E_IEEE_ETS_CBS_SHIFT 6 -#define I40E_IEEE_ETS_CBS_MASK (0x1 << I40E_IEEE_ETS_CBS_SHIFT) +#define I40E_IEEE_ETS_CBS_MASK BIT(I40E_IEEE_ETS_CBS_SHIFT) #define I40E_IEEE_ETS_WILLING_SHIFT 7 -#define I40E_IEEE_ETS_WILLING_MASK (0x1 << I40E_IEEE_ETS_WILLING_SHIFT) +#define I40E_IEEE_ETS_WILLING_MASK BIT(I40E_IEEE_ETS_WILLING_SHIFT) #define I40E_IEEE_ETS_PRIO_0_SHIFT 0 #define I40E_IEEE_ETS_PRIO_0_MASK (0x7 << I40E_IEEE_ETS_PRIO_0_SHIFT) #define I40E_IEEE_ETS_PRIO_1_SHIFT 4 @@ -79,9 +79,9 @@ #define I40E_IEEE_PFC_CAP_SHIFT 0 #define I40E_IEEE_PFC_CAP_MASK (0xF << I40E_IEEE_PFC_CAP_SHIFT) #define I40E_IEEE_PFC_MBC_SHIFT 6 -#define I40E_IEEE_PFC_MBC_MASK (0x1 << I40E_IEEE_PFC_MBC_SHIFT) +#define I40E_IEEE_PFC_MBC_MASK BIT(I40E_IEEE_PFC_MBC_SHIFT) #define I40E_IEEE_PFC_WILLING_SHIFT 7 -#define I40E_IEEE_PFC_WILLING_MASK (0x1 << I40E_IEEE_PFC_WILLING_SHIFT) +#define I40E_IEEE_PFC_WILLING_MASK BIT(I40E_IEEE_PFC_WILLING_SHIFT) /* Defines for IEEE APP TLV */ #define I40E_IEEE_APP_SEL_SHIFT 0 diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c index bd5079d5c1b68..1c51f736a8d0a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb_nl.c @@ -187,7 +187,7 @@ void i40e_dcbnl_set_all(struct i40e_vsi *vsi) /* Set up all the App TLVs if DCBx is negotiated */ for (i = 0; i < dcbxcfg->numapps; i++) { prio = dcbxcfg->app[i].priority; - tc_map = (1 << dcbxcfg->etscfg.prioritytable[prio]); + tc_map = BIT(dcbxcfg->etscfg.prioritytable[prio]); /* Add APP only if the TC is enabled for this VSI */ if (tc_map & vsi->tc_config.enabled_tc) { diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c index da0faf478af07..d7c15d17faa63 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c +++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c @@ -964,7 +964,7 @@ static void i40e_dbg_cmd_fd_ctrl(struct i40e_pf *pf, u64 flag, bool enable) pf->auto_disable_flags |= flag; } dev_info(&pf->pdev->dev, "requesting a PF reset\n"); - i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_PF_RESET_REQUESTED)); } #define I40E_MAX_DEBUG_OUT_BUFFER (4096*4) @@ -1471,19 +1471,19 @@ static ssize_t i40e_dbg_command_write(struct file *filp, } } else if (strncmp(cmd_buf, "pfr", 3) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing PFR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_PF_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "corer", 5) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing CoreR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_CORE_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_CORE_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "globr", 5) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing GlobR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_GLOBAL_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_GLOBAL_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "empr", 4) == 0) { dev_info(&pf->pdev->dev, "debugfs: forcing EMPR\n"); - i40e_do_reset_safe(pf, (1 << __I40E_EMP_RESET_REQUESTED)); + i40e_do_reset_safe(pf, BIT(__I40E_EMP_RESET_REQUESTED)); } else if (strncmp(cmd_buf, "read", 4) == 0) { u32 address; diff --git a/drivers/net/ethernet/intel/i40e/i40e_diag.c b/drivers/net/ethernet/intel/i40e/i40e_diag.c index 56438bd579e61..f141e78d409e5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_diag.c +++ b/drivers/net/ethernet/intel/i40e/i40e_diag.c @@ -144,11 +144,8 @@ i40e_status i40e_diag_eeprom_test(struct i40e_hw *hw) ret_code = i40e_read_nvm_word(hw, I40E_SR_NVM_CONTROL_WORD, ®_val); if (!ret_code && ((reg_val & I40E_SR_CONTROL_WORD_1_MASK) == - (0x01 << I40E_SR_CONTROL_WORD_1_SHIFT))) { - ret_code = i40e_validate_nvm_checksum(hw, NULL); - } else { - ret_code = I40E_ERR_DIAG_TEST_FAILED; - } - - return ret_code; + BIT(I40E_SR_CONTROL_WORD_1_SHIFT))) + return i40e_validate_nvm_checksum(hw, NULL); + else + return I40E_ERR_DIAG_TEST_FAILED; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 4b06a27ab7990..83d41c2cb02d4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1017,7 +1017,7 @@ static int i40e_get_eeprom_len(struct net_device *netdev) & I40E_GLPCI_LBARCTRL_FL_SIZE_MASK) >> I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT; /* register returns value in power of 2, 64Kbyte chunks. */ - val = (64 * 1024) * (1 << val); + val = (64 * 1024) * BIT(val); return val; } @@ -1470,11 +1470,11 @@ static int i40e_get_ts_info(struct net_device *dev, else info->phc_index = -1; - info->tx_types = (1 << HWTSTAMP_TX_OFF) | (1 << HWTSTAMP_TX_ON); + info->tx_types = BIT(HWTSTAMP_TX_OFF) | BIT(HWTSTAMP_TX_ON); - info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) | - (1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | - (1 << HWTSTAMP_FILTER_PTP_V2_EVENT); + info->rx_filters = BIT(HWTSTAMP_FILTER_NONE) | + BIT(HWTSTAMP_FILTER_PTP_V1_L4_EVENT) | + BIT(HWTSTAMP_FILTER_PTP_V2_EVENT); return 0; } @@ -1590,7 +1590,7 @@ static void i40e_diag_test(struct net_device *netdev, /* indicate we're in test mode */ dev_close(netdev); else - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED)); /* Link test performed before hardware reset * so autoneg doesn't interfere with test result @@ -1612,7 +1612,7 @@ static void i40e_diag_test(struct net_device *netdev, eth_test->flags |= ETH_TEST_FL_FAILED; clear_bit(__I40E_TESTING, &pf->state); - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED)); if (if_running) dev_open(netdev); @@ -1645,7 +1645,7 @@ static void i40e_get_wol(struct net_device *netdev, /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); - if ((1 << hw->port) & wol_nvm_bits || hw->partition_id != 1) { + if ((BIT(hw->port) & wol_nvm_bits) || (hw->partition_id != 1)) { wol->supported = 0; wol->wolopts = 0; } else { @@ -1678,7 +1678,7 @@ static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) /* NVM bit on means WoL disabled for the port */ i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits); - if (((1 << hw->port) & wol_nvm_bits)) + if (BIT(hw->port) & wol_nvm_bits) return -EOPNOTSUPP; /* only magic packet is supported */ @@ -2024,10 +2024,10 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case TCP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; default: return -EINVAL; @@ -2036,10 +2036,10 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case TCP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; default: return -EINVAL; @@ -2048,12 +2048,12 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case UDP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; default: return -EINVAL; @@ -2062,12 +2062,12 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) case UDP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; default: return -EINVAL; @@ -2080,7 +2080,7 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); break; case AH_ESP_V6_FLOW: case AH_V6_FLOW: @@ -2089,15 +2089,15 @@ static int i40e_set_rss_hash_opt(struct i40e_pf *pf, struct ethtool_rxnfc *nfc) if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); break; case IPV4_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4); break; case IPV6_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6); break; default: return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c index c8b621e0e7cda..5ea75dd537d62 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c @@ -298,8 +298,8 @@ int i40e_init_pf_fcoe(struct i40e_pf *pf) /* enable FCoE hash filter */ val = rd32(hw, I40E_PFQF_HENA(1)); - val |= 1 << (I40E_FILTER_PCTYPE_FCOE_OX - 32); - val |= 1 << (I40E_FILTER_PCTYPE_FCOE_RX - 32); + val |= BIT(I40E_FILTER_PCTYPE_FCOE_OX - 32); + val |= BIT(I40E_FILTER_PCTYPE_FCOE_RX - 32); val &= I40E_PFQF_HENA_PTYPE_ENA_MASK; wr32(hw, I40E_PFQF_HENA(1), val); @@ -308,10 +308,10 @@ int i40e_init_pf_fcoe(struct i40e_pf *pf) pf->num_fcoe_qps = I40E_DEFAULT_FCOE; /* Reserve 4K DDP contexts and 20K filter size for FCoE */ - pf->fcoe_hmc_cntx_num = (1 << I40E_DMA_CNTX_SIZE_4K) * - I40E_DMA_CNTX_BASE_SIZE; + pf->fcoe_hmc_cntx_num = BIT(I40E_DMA_CNTX_SIZE_4K) * + I40E_DMA_CNTX_BASE_SIZE; pf->fcoe_hmc_filt_num = pf->fcoe_hmc_cntx_num + - (1 << I40E_HASH_FILTER_SIZE_16K) * + BIT(I40E_HASH_FILTER_SIZE_16K) * I40E_HASH_FILTER_BASE_SIZE; /* FCoE object: max 16K filter buckets and 4K DMA contexts */ @@ -348,7 +348,7 @@ u8 i40e_get_fcoe_tc_map(struct i40e_pf *pf) if (app.selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE && app.protocolid == ETH_P_FCOE) { tc = dcbcfg->etscfg.prioritytable[app.priority]; - enabled_tc |= (1 << tc); + enabled_tc |= BIT(tc); break; } } diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.h b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h index 0d49e2d15d408..a93174ddeaba7 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.h +++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.h @@ -59,9 +59,9 @@ (((e) >> I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) & 0x1) #define I40E_RX_PROG_FCOE_ERROR_TBL_FULL_BIT \ - (1 << I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) + BIT(I40E_RX_PROG_STATUS_DESC_FCOE_TBL_FULL_SHIFT) #define I40E_RX_PROG_FCOE_ERROR_CONFLICT_BIT \ - (1 << I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) + BIT(I40E_RX_PROG_STATUS_DESC_FCOE_CONFLICT_SHIFT) #define I40E_RX_PROG_FCOE_ERROR_INVLFAIL(e) \ I40E_RX_PROG_FCOE_ERROR_CONFLICT(e) diff --git a/drivers/net/ethernet/intel/i40e/i40e_hmc.h b/drivers/net/ethernet/intel/i40e/i40e_hmc.h index 386416bf72674..d906692113929 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40e/i40e_hmc.h @@ -127,8 +127,8 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ - (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -147,7 +147,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ diff --git a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c index d399eaf5aad5d..fa371a2a40c68 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c +++ b/drivers/net/ethernet/intel/i40e/i40e_lan_hmc.c @@ -129,7 +129,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, obj->cnt = txq_num; obj->base = 0; size_exp = rd32(hw, I40E_GLHMC_LANTXOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (txq_num > obj->max_cnt) { @@ -152,7 +152,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, hw->hmc.hmc_obj[I40E_HMC_LAN_TX].size); obj->base = i40e_align_l2obj_base(obj->base); size_exp = rd32(hw, I40E_GLHMC_LANRXOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (rxq_num > obj->max_cnt) { @@ -175,7 +175,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, hw->hmc.hmc_obj[I40E_HMC_LAN_RX].size); obj->base = i40e_align_l2obj_base(obj->base); size_exp = rd32(hw, I40E_GLHMC_FCOEDDPOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (fcoe_cntx_num > obj->max_cnt) { @@ -198,7 +198,7 @@ i40e_status i40e_init_lan_hmc(struct i40e_hw *hw, u32 txq_num, hw->hmc.hmc_obj[I40E_HMC_FCOE_CTX].size); obj->base = i40e_align_l2obj_base(obj->base); size_exp = rd32(hw, I40E_GLHMC_FCOEFOBJSZ); - obj->size = (u64)1 << size_exp; + obj->size = BIT_ULL(size_exp); /* validate values requested by driver don't exceed HMC capacity */ if (fcoe_filt_num > obj->max_cnt) { @@ -763,7 +763,7 @@ static void i40e_write_byte(u8 *hmc_bits, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - mask = ((u8)1 << ce_info->width) - 1; + mask = BIT(ce_info->width) - 1; src_byte = *from; src_byte &= mask; @@ -804,7 +804,7 @@ static void i40e_write_word(u8 *hmc_bits, /* prepare the bits and mask */ shift_width = ce_info->lsb % 8; - mask = ((u16)1 << ce_info->width) - 1; + mask = BIT(ce_info->width) - 1; /* don't swizzle the bits until after the mask because the mask bits * will be in a different bit position on big endian machines @@ -854,7 +854,7 @@ static void i40e_write_dword(u8 *hmc_bits, * to 5 bits so the shift will do nothing */ if (ce_info->width < 32) - mask = ((u32)1 << ce_info->width) - 1; + mask = BIT(ce_info->width) - 1; else mask = ~(u32)0; @@ -906,7 +906,7 @@ static void i40e_write_qword(u8 *hmc_bits, * to 6 bits so the shift will do nothing */ if (ce_info->width < 64) - mask = ((u64)1 << ce_info->width) - 1; + mask = BIT_ULL(ce_info->width) - 1; else mask = ~(u64)0; diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 7646297e09816..857d294d2a453 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -520,7 +520,7 @@ static void i40e_stat_update48(struct i40e_hw *hw, u32 hireg, u32 loreg, if (likely(new_data >= *offset)) *stat = new_data - *offset; else - *stat = (new_data + ((u64)1 << 48)) - *offset; + *stat = (new_data + BIT_ULL(48)) - *offset; *stat &= 0xFFFFFFFFFFFFULL; } @@ -543,7 +543,7 @@ static void i40e_stat_update32(struct i40e_hw *hw, u32 reg, if (likely(new_data >= *offset)) *stat = (u32)(new_data - *offset); else - *stat = (u32)((new_data + ((u64)1 << 32)) - *offset); + *stat = (u32)((new_data + BIT_ULL(32)) - *offset); } /** @@ -1526,7 +1526,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, if (enabled_tc && (vsi->back->flags & I40E_FLAG_DCB_ENABLED)) { /* Find numtc from enabled TC bitmap */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) /* TC is enabled */ + if (enabled_tc & BIT_ULL(i)) /* TC is enabled */ numtc++; } if (!numtc) { @@ -1552,7 +1552,8 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, /* Setup queue offset/count for all TCs for given VSI */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { /* See if the given TC is enabled for the given VSI */ - if (vsi->tc_config.enabled_tc & (1 << i)) { /* TC is enabled */ + if (vsi->tc_config.enabled_tc & BIT_ULL(i)) { + /* TC is enabled */ int pow, num_qps; switch (vsi->type) { @@ -1578,7 +1579,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, /* find the next higher power-of-2 of num queue pairs */ num_qps = qcount; pow = 0; - while (num_qps && ((1 << pow) < qcount)) { + while (num_qps && (BIT_ULL(pow) < qcount)) { pow++; num_qps >>= 1; } @@ -2723,9 +2724,9 @@ static int i40e_vsi_configure_rx(struct i40e_vsi *vsi) #endif /* I40E_FCOE */ /* round up for the chip's needs */ vsi->rx_hdr_len = ALIGN(vsi->rx_hdr_len, - (1 << I40E_RXQ_CTX_HBUFF_SHIFT)); + BIT_ULL(I40E_RXQ_CTX_HBUFF_SHIFT)); vsi->rx_buf_len = ALIGN(vsi->rx_buf_len, - (1 << I40E_RXQ_CTX_DBUFF_SHIFT)); + BIT_ULL(I40E_RXQ_CTX_DBUFF_SHIFT)); /* set up individual rings */ for (i = 0; i < vsi->num_queue_pairs && !err; i++) @@ -2755,7 +2756,7 @@ static void i40e_vsi_config_dcb_rings(struct i40e_vsi *vsi) } for (n = 0; n < I40E_MAX_TRAFFIC_CLASS; n++) { - if (!(vsi->tc_config.enabled_tc & (1 << n))) + if (!(vsi->tc_config.enabled_tc & BIT_ULL(n))) continue; qoffset = vsi->tc_config.tc_info[n].qoffset; @@ -4100,7 +4101,7 @@ static u8 i40e_get_iscsi_tc_map(struct i40e_pf *pf) if (app.selector == I40E_APP_SEL_TCPIP && app.protocolid == I40E_APP_PROTOID_ISCSI) { tc = dcbcfg->etscfg.prioritytable[app.priority]; - enabled_tc |= (1 << tc); + enabled_tc |= BIT_ULL(tc); break; } } @@ -4149,7 +4150,7 @@ static u8 i40e_dcb_get_enabled_tc(struct i40e_dcbx_config *dcbcfg) u8 i; for (i = 0; i < num_tc; i++) - enabled_tc |= 1 << i; + enabled_tc |= BIT(i); return enabled_tc; } @@ -4184,7 +4185,7 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf) /* At least have TC0 */ enabled_tc = (enabled_tc ? enabled_tc : 0x1); for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) num_tc++; } return num_tc; @@ -4206,11 +4207,11 @@ static u8 i40e_pf_get_default_tc(struct i40e_pf *pf) /* Find the first enabled TC */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) break; } - return 1 << i; + return BIT(i); } /** @@ -4366,7 +4367,7 @@ static void i40e_vsi_config_netdev_tc(struct i40e_vsi *vsi, u8 enabled_tc) * will set the numtc for netdev as 2 that will be * referenced by the netdev layer as TC 0 and 1. */ - if (vsi->tc_config.enabled_tc & (1 << i)) + if (vsi->tc_config.enabled_tc & BIT_ULL(i)) netdev_set_tc_queue(netdev, vsi->tc_config.tc_info[i].netdev_tc, vsi->tc_config.tc_info[i].qcount, @@ -4428,7 +4429,7 @@ static int i40e_vsi_config_tc(struct i40e_vsi *vsi, u8 enabled_tc) /* Enable ETS TCs with equal BW Share for now across all VSIs */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) bw_share[i] = 1; } @@ -4502,7 +4503,7 @@ int i40e_veb_config_tc(struct i40e_veb *veb, u8 enabled_tc) /* Enable ETS TCs with equal BW Share for now */ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { - if (enabled_tc & (1 << i)) + if (enabled_tc & BIT_ULL(i)) bw_data.tc_bw_share_credits[i] = 1; } @@ -4896,7 +4897,7 @@ static int i40e_setup_tc(struct net_device *netdev, u8 tc) /* Generate TC map for number of tc requested */ for (i = 0; i < tc; i++) - enabled_tc |= (1 << i); + enabled_tc |= BIT_ULL(i); /* Requesting same TC configuration as already enabled */ if (enabled_tc == vsi->tc_config.enabled_tc) @@ -5035,7 +5036,7 @@ err_setup_rx: err_setup_tx: i40e_vsi_free_tx_resources(vsi); if (vsi == pf->vsi[pf->lan_vsi]) - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED)); return err; } @@ -5103,7 +5104,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) i40e_vc_notify_reset(pf); /* do the biggest reset indicated */ - if (reset_flags & (1 << __I40E_GLOBAL_RESET_REQUESTED)) { + if (reset_flags & BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED)) { /* Request a Global Reset * @@ -5118,7 +5119,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) val |= I40E_GLGEN_RTRIG_GLOBR_MASK; wr32(&pf->hw, I40E_GLGEN_RTRIG, val); - } else if (reset_flags & (1 << __I40E_CORE_RESET_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_CORE_RESET_REQUESTED)) { /* Request a Core Reset * @@ -5130,7 +5131,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) wr32(&pf->hw, I40E_GLGEN_RTRIG, val); i40e_flush(&pf->hw); - } else if (reset_flags & (1 << __I40E_PF_RESET_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_PF_RESET_REQUESTED)) { /* Request a PF Reset * @@ -5143,7 +5144,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) dev_dbg(&pf->pdev->dev, "PFR requested\n"); i40e_handle_reset_warning(pf); - } else if (reset_flags & (1 << __I40E_REINIT_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_REINIT_REQUESTED)) { int v; /* Find the VSI(s) that requested a re-init */ @@ -5160,7 +5161,7 @@ void i40e_do_reset(struct i40e_pf *pf, u32 reset_flags) /* no further action needed, so return now */ return; - } else if (reset_flags & (1 << __I40E_DOWN_REQUESTED)) { + } else if (reset_flags & BIT_ULL(__I40E_DOWN_REQUESTED)) { int v; /* Find the VSI(s) that needs to be brought down */ @@ -5801,23 +5802,23 @@ static void i40e_reset_subtask(struct i40e_pf *pf) rtnl_lock(); if (test_bit(__I40E_REINIT_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_REINIT_REQUESTED); + reset_flags |= BIT_ULL(__I40E_REINIT_REQUESTED); clear_bit(__I40E_REINIT_REQUESTED, &pf->state); } if (test_bit(__I40E_PF_RESET_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_PF_RESET_REQUESTED); + reset_flags |= BIT_ULL(__I40E_PF_RESET_REQUESTED); clear_bit(__I40E_PF_RESET_REQUESTED, &pf->state); } if (test_bit(__I40E_CORE_RESET_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_CORE_RESET_REQUESTED); + reset_flags |= BIT_ULL(__I40E_CORE_RESET_REQUESTED); clear_bit(__I40E_CORE_RESET_REQUESTED, &pf->state); } if (test_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_GLOBAL_RESET_REQUESTED); + reset_flags |= BIT_ULL(__I40E_GLOBAL_RESET_REQUESTED); clear_bit(__I40E_GLOBAL_RESET_REQUESTED, &pf->state); } if (test_bit(__I40E_DOWN_REQUESTED, &pf->state)) { - reset_flags |= (1 << __I40E_DOWN_REQUESTED); + reset_flags |= BIT_ULL(__I40E_DOWN_REQUESTED); clear_bit(__I40E_DOWN_REQUESTED, &pf->state); } @@ -6699,8 +6700,8 @@ static void i40e_sync_vxlan_filters_subtask(struct i40e_pf *pf) pf->flags &= ~I40E_FLAG_VXLAN_FILTER_SYNC; for (i = 0; i < I40E_MAX_PF_UDP_OFFLOAD_PORTS; i++) { - if (pf->pending_vxlan_bitmap & (1 << i)) { - pf->pending_vxlan_bitmap &= ~(1 << i); + if (pf->pending_vxlan_bitmap & BIT_ULL(i)) { + pf->pending_vxlan_bitmap &= ~BIT_ULL(i); port = pf->vxlan_ports[i]; if (port) ret = i40e_aq_add_udp_tunnel(hw, ntohs(port), @@ -7513,7 +7514,7 @@ static int i40e_config_rss(struct i40e_pf *pf) j = 0; /* lut = 4-byte sliding window of 4 lut entries */ lut = (lut << 8) | (j & - ((0x1 << pf->hw.func_caps.rss_table_entry_width) - 1)); + (BIT(pf->hw.func_caps.rss_table_entry_width) - 1)); /* On i = 3, we have 4 entries in lut; write to the register */ if ((i & 3) == 3) wr32(hw, I40E_PFQF_HLUT(i >> 2), lut); @@ -7587,7 +7588,7 @@ i40e_status i40e_set_npar_bw_setting(struct i40e_pf *pf) i40e_status status; /* Set the valid bit for this PF */ - bw_data.pf_valid_bits = cpu_to_le16(1 << pf->hw.pf_id); + bw_data.pf_valid_bits = cpu_to_le16(BIT(pf->hw.pf_id)); bw_data.max_bw[pf->hw.pf_id] = pf->npar_max_bw & I40E_ALT_BW_VALUE_MASK; bw_data.min_bw[pf->hw.pf_id] = pf->npar_min_bw & I40E_ALT_BW_VALUE_MASK; @@ -7720,7 +7721,7 @@ static int i40e_sw_init(struct i40e_pf *pf) /* Depending on PF configurations, it is possible that the RSS * maximum might end up larger than the available queues */ - pf->rss_size_max = 0x1 << pf->hw.func_caps.rss_table_entry_width; + pf->rss_size_max = BIT(pf->hw.func_caps.rss_table_entry_width); pf->rss_size = 1; pf->rss_table_size = pf->hw.func_caps.rss_table_size; pf->rss_size_max = min_t(int, pf->rss_size_max, @@ -7870,7 +7871,7 @@ static int i40e_set_features(struct net_device *netdev, need_reset = i40e_set_ntuple(pf, features); if (need_reset) - i40e_do_reset(pf, (1 << __I40E_PF_RESET_REQUESTED)); + i40e_do_reset(pf, BIT_ULL(__I40E_PF_RESET_REQUESTED)); return 0; } @@ -7933,7 +7934,7 @@ static void i40e_add_vxlan_port(struct net_device *netdev, /* New port: add it and mark its index in the bitmap */ pf->vxlan_ports[next_idx] = port; - pf->pending_vxlan_bitmap |= (1 << next_idx); + pf->pending_vxlan_bitmap |= BIT_ULL(next_idx); pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; dev_info(&pf->pdev->dev, "adding vxlan port %d\n", ntohs(port)); @@ -7964,7 +7965,7 @@ static void i40e_del_vxlan_port(struct net_device *netdev, * and make it pending */ pf->vxlan_ports[idx] = 0; - pf->pending_vxlan_bitmap |= (1 << idx); + pf->pending_vxlan_bitmap |= BIT_ULL(idx); pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; dev_info(&pf->pdev->dev, "deleting vxlan port %d\n", diff --git a/drivers/net/ethernet/intel/i40e/i40e_nvm.c b/drivers/net/ethernet/intel/i40e/i40e_nvm.c index 554e49d02683c..ce986af213d28 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_nvm.c +++ b/drivers/net/ethernet/intel/i40e/i40e_nvm.c @@ -50,7 +50,7 @@ i40e_status i40e_init_nvm(struct i40e_hw *hw) sr_size = ((gens & I40E_GLNVM_GENS_SR_SIZE_MASK) >> I40E_GLNVM_GENS_SR_SIZE_SHIFT); /* Switching to words (sr_size contains power of 2KB) */ - nvm->sr_size = (1 << sr_size) * I40E_SR_WORDS_IN_1KB; + nvm->sr_size = BIT(sr_size) * I40E_SR_WORDS_IN_1KB; /* Check if we are in the normal or blank NVM programming mode */ fla = rd32(hw, I40E_GLNVM_FLA); @@ -189,8 +189,8 @@ static i40e_status i40e_read_nvm_word_srctl(struct i40e_hw *hw, u16 offset, ret_code = i40e_poll_sr_srctl_done_bit(hw); if (!ret_code) { /* Write the address and start reading */ - sr_reg = (u32)(offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | - (1 << I40E_GLNVM_SRCTL_START_SHIFT); + sr_reg = ((u32)offset << I40E_GLNVM_SRCTL_ADDR_SHIFT) | + BIT(I40E_GLNVM_SRCTL_START_SHIFT); wr32(hw, I40E_GLNVM_SRCTL, sr_reg); /* Poll I40E_GLNVM_SRCTL until the done bit is set */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index a92b7725dec39..8c40d6ea15fda 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -43,9 +43,8 @@ #define I40E_PTP_10GB_INCVAL 0x0333333333ULL #define I40E_PTP_1GB_INCVAL 0x2000000000ULL -#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 (0x1 << \ - I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) -#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (0x2 << \ +#define I40E_PRTTSYN_CTL1_TSYNTYPE_V1 BIT(I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) +#define I40E_PRTTSYN_CTL1_TSYNTYPE_V2 (2 << \ I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) /** @@ -357,7 +356,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1); - if (!(prttsyn_stat & (1 << index))) + if (!(prttsyn_stat & BIT(index))) return; lo = rd32(hw, I40E_PRTTSYN_RXTIME_L(index)); diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c index a72278c265c2f..330e4ef43cd8f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c @@ -464,7 +464,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, error = (qw & I40E_RX_PROG_STATUS_DESC_QW1_ERROR_MASK) >> I40E_RX_PROG_STATUS_DESC_QW1_ERROR_SHIFT; - if (error == (0x1 << I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { + if (error == BIT(I40E_RX_PROG_STATUS_DESC_FD_TBL_FULL_SHIFT)) { if ((rx_desc->wb.qword0.hi_dword.fd_id != 0) || (I40E_DEBUG_FD & pf->hw.debug_mask)) dev_warn(&pdev->dev, "ntuple filter loc = %d, could not be added\n", @@ -509,8 +509,7 @@ static void i40e_fd_handle_status(struct i40e_ring *rx_ring, dev_info(&pdev->dev, "FD filter programming failed due to incorrect filter parameters\n"); } - } else if (error == - (0x1 << I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { + } else if (error == BIT(I40E_RX_PROG_STATUS_DESC_NO_FD_ENTRY_SHIFT)) { if (I40E_DEBUG_FD & pf->hw.debug_mask) dev_info(&pdev->dev, "ntuple filter fd_id = %d, could not be removed\n", rx_desc->wb.qword0.hi_dword.fd_id); @@ -1363,7 +1362,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, return; /* did the hardware decode the packet and checksum? */ - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; /* both known and outer_ip must be set for the below code to work */ @@ -1378,25 +1377,25 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ipv6 = true; if (ipv4 && - (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | - (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))) + (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) | + BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT)))) goto checksum_fail; /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) + rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; /* there was some L4 error, count error and punt packet to the stack */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT)) goto checksum_fail; /* handle packets that were not able to be checksummed due * to arrival speed, in this case the stack can compute * the csum. */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) return; /* If VXLAN traffic has an outer UDPv4 checksum we need to check @@ -1520,7 +1519,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1561,8 +1560,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT); - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_hbo = rx_error & BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1614,7 +1613,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { struct i40e_rx_buffer *next_buffer; next_buffer = &rx_ring->rx_bi[i]; @@ -1624,7 +1623,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); continue; } @@ -1646,7 +1645,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; #ifdef I40E_FCOE @@ -1707,7 +1706,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1730,7 +1729,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1748,13 +1747,13 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { rx_ring->rx_stats.non_eop_descs++; continue; } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); /* TODO: shouldn't we increment a counter indicating the * drop? @@ -1779,7 +1778,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; #ifdef I40E_FCOE diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.h b/drivers/net/ethernet/intel/i40e/i40e_txrx.h index 0dc48dc9ca619..429833c47245f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.h @@ -66,17 +66,17 @@ enum i40e_dyn_idx_t { /* Supported RSS offloads */ #define I40E_DEFAULT_RSS_HENA ( \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | \ - ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD)) + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ + BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ @@ -129,17 +129,17 @@ enum i40e_dyn_idx_t { #define DESC_NEEDED (MAX_SKB_FRAGS + 4) #define I40E_MIN_DESC_PENDING 4 -#define I40E_TX_FLAGS_CSUM (u32)(1) -#define I40E_TX_FLAGS_HW_VLAN (u32)(1 << 1) -#define I40E_TX_FLAGS_SW_VLAN (u32)(1 << 2) -#define I40E_TX_FLAGS_TSO (u32)(1 << 3) -#define I40E_TX_FLAGS_IPV4 (u32)(1 << 4) -#define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) -#define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) -#define I40E_TX_FLAGS_FSO (u32)(1 << 7) -#define I40E_TX_FLAGS_TSYN (u32)(1 << 8) -#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) -#define I40E_TX_FLAGS_VXLAN_TUNNEL (u32)(1 << 10) +#define I40E_TX_FLAGS_CSUM BIT(0) +#define I40E_TX_FLAGS_HW_VLAN BIT(1) +#define I40E_TX_FLAGS_SW_VLAN BIT(2) +#define I40E_TX_FLAGS_TSO BIT(3) +#define I40E_TX_FLAGS_IPV4 BIT(4) +#define I40E_TX_FLAGS_IPV6 BIT(5) +#define I40E_TX_FLAGS_FCCRC BIT(6) +#define I40E_TX_FLAGS_FSO BIT(7) +#define I40E_TX_FLAGS_TSYN BIT(8) +#define I40E_TX_FLAGS_FD_SB BIT(9) +#define I40E_TX_FLAGS_VXLAN_TUNNEL BIT(10) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 0cabf04cf23b3..a20128b82b625 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -611,7 +611,7 @@ enum i40e_rx_desc_status_bits { }; #define I40E_RXD_QW1_STATUS_SHIFT 0 -#define I40E_RXD_QW1_STATUS_MASK (((1 << I40E_RX_DESC_STATUS_LAST) - 1) \ +#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT @@ -619,8 +619,8 @@ enum i40e_rx_desc_status_bits { I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK (0x1UL << \ - I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) +#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \ + BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) enum i40e_rx_desc_fltstat_values { I40E_RX_DESC_FLTSTAT_NO_DATA = 0, @@ -754,8 +754,7 @@ enum i40e_rx_ptype_payload_layer { I40E_RXD_QW1_LENGTH_HBUF_SHIFT) #define I40E_RXD_QW1_LENGTH_SPH_SHIFT 63 -#define I40E_RXD_QW1_LENGTH_SPH_MASK (0x1ULL << \ - I40E_RXD_QW1_LENGTH_SPH_SHIFT) +#define I40E_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(I40E_RXD_QW1_LENGTH_SPH_SHIFT) enum i40e_rx_desc_ext_status_bits { /* Note: These are predefined bit offsets */ @@ -931,12 +930,12 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_NATT_SHIFT 9 #define I40E_TXD_CTX_QW0_NATT_MASK (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) -#define I40E_TXD_CTX_UDP_TUNNELING (0x1ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) +#define I40E_TXD_CTX_UDP_TUNNELING BIT_ULL(I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_GRE_TUNNELING (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT 11 -#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK (0x1ULL << \ - I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) +#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK \ + BIT_ULL(I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) #define I40E_TXD_CTX_EIP_NOINC_IPID_CONST I40E_TXD_CTX_QW0_EIP_NOINC_MASK @@ -1001,8 +1000,8 @@ enum i40e_filter_program_desc_fd_status { }; #define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT 23 -#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK (0x1FFUL << \ - I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) +#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK \ + BIT_ULL(I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) #define I40E_TXD_FLTR_QW1_CMD_SHIFT 4 #define I40E_TXD_FLTR_QW1_CMD_MASK (0xFFFFULL << \ @@ -1020,8 +1019,7 @@ enum i40e_filter_program_desc_pcmd { #define I40E_TXD_FLTR_QW1_DEST_MASK (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT) #define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK (0x1ULL << \ - I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) +#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK BIT_ULL(I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) #define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT (0x9ULL + \ I40E_TXD_FLTR_QW1_CMD_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 51aff70721956..d29d4062addf5 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -277,16 +277,14 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, } tempmap = vecmap->rxq_map; for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) { - linklistmap |= (1 << - (I40E_VIRTCHNL_SUPPORTED_QTYPES * - vsi_queue_id)); + linklistmap |= (BIT(I40E_VIRTCHNL_SUPPORTED_QTYPES * + vsi_queue_id)); } tempmap = vecmap->txq_map; for_each_set_bit(vsi_queue_id, &tempmap, I40E_MAX_VSI_QP) { - linklistmap |= (1 << - (I40E_VIRTCHNL_SUPPORTED_QTYPES * vsi_queue_id - + 1)); + linklistmap |= (BIT(I40E_VIRTCHNL_SUPPORTED_QTYPES * + vsi_queue_id + 1)); } next_q = find_first_bit(&linklistmap, @@ -332,7 +330,7 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, reg = (vector_id) | (qtype << I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) | (pf_queue_id << I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) | - (1 << I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) | + BIT(I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) | (itr_idx << I40E_QINT_RQCTL_ITR_INDX_SHIFT); wr32(hw, reg_idx, reg); } @@ -897,7 +895,7 @@ void i40e_free_vfs(struct i40e_pf *pf) for (vf_id = 0; vf_id < tmp; vf_id++) { reg_idx = (hw->func_caps.vf_base_id + vf_id) / 32; bit_idx = (hw->func_caps.vf_base_id + vf_id) % 32; - wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); + wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx)); } } clear_bit(__I40E_VF_DISABLE, &pf->state); @@ -1983,9 +1981,9 @@ int i40e_vc_process_vflr_event(struct i40e_pf *pf) /* read GLGEN_VFLRSTAT register to find out the flr VFs */ vf = &pf->vf[vf_id]; reg = rd32(hw, I40E_GLGEN_VFLRSTAT(reg_idx)); - if (reg & (1 << bit_idx)) { + if (reg & BIT(bit_idx)) { /* clear the bit in GLGEN_VFLRSTAT */ - wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), (1 << bit_idx)); + wr32(hw, I40E_GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx)); if (!test_bit(__I40E_DOWN, &pf->state)) i40e_reset_vf(vf, true); diff --git a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h index adc6f71f40a8c..00ed24bfce134 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_hmc.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_hmc.h @@ -127,8 +127,8 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) | \ - (1 << I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + BIT(I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, val1); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ @@ -147,7 +147,7 @@ struct i40e_hmc_info { I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) | \ ((((type) == I40E_SD_TYPE_PAGED) ? 0 : 1) << \ I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT); \ - val3 = (sd_index) | (1u << I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ + val3 = (sd_index) | BIT_ULL(I40E_PFHMC_SDCMD_PMSDWR_SHIFT); \ wr32((hw), I40E_PFHMC_SDDATAHIGH, 0); \ wr32((hw), I40E_PFHMC_SDDATALOW, val2); \ wr32((hw), I40E_PFHMC_SDCMD, val3); \ diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index cf3530335c681..60f88e4ad065e 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -850,7 +850,7 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, return; /* did the hardware decode the packet and checksum? */ - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_L3L4P_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_L3L4P_SHIFT))) return; /* both known and outer_ip must be set for the below code to work */ @@ -865,25 +865,25 @@ static inline void i40e_rx_checksum(struct i40e_vsi *vsi, ipv6 = true; if (ipv4 && - (rx_error & ((1 << I40E_RX_DESC_ERROR_IPE_SHIFT) | - (1 << I40E_RX_DESC_ERROR_EIPE_SHIFT)))) + (rx_error & (BIT(I40E_RX_DESC_ERROR_IPE_SHIFT) | + BIT(I40E_RX_DESC_ERROR_EIPE_SHIFT)))) goto checksum_fail; /* likely incorrect csum if alternate IP extension headers found */ if (ipv6 && - rx_status & (1 << I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) + rx_status & BIT(I40E_RX_DESC_STATUS_IPV6EXADD_SHIFT)) /* don't increment checksum err here, non-fatal err */ return; /* there was some L4 error, count error and punt packet to the stack */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_L4E_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_L4E_SHIFT)) goto checksum_fail; /* handle packets that were not able to be checksummed due * to arrival speed, in this case the stack can compute * the csum. */ - if (rx_error & (1 << I40E_RX_DESC_ERROR_PPRS_SHIFT)) + if (rx_error & BIT(I40E_RX_DESC_ERROR_PPRS_SHIFT)) return; /* If VXLAN traffic has an outer UDPv4 checksum we need to check @@ -1004,7 +1004,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1040,8 +1040,8 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_hbo = rx_error & (1 << I40E_RX_DESC_ERROR_HBO_SHIFT); - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_hbo = rx_error & BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1093,7 +1093,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { struct i40e_rx_buffer *next_buffer; next_buffer = &rx_ring->rx_bi[i]; @@ -1103,7 +1103,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); continue; } @@ -1118,7 +1118,7 @@ static int i40e_clean_rx_irq_ps(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; #ifdef I40E_FCOE @@ -1179,7 +1179,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_status = (qword & I40E_RXD_QW1_STATUS_MASK) >> I40E_RXD_QW1_STATUS_SHIFT; - if (!(rx_status & (1 << I40E_RX_DESC_STATUS_DD_SHIFT))) + if (!(rx_status & BIT(I40E_RX_DESC_STATUS_DD_SHIFT))) break; /* This memory barrier is needed to keep us from reading @@ -1197,7 +1197,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) rx_error = (qword & I40E_RXD_QW1_ERROR_MASK) >> I40E_RXD_QW1_ERROR_SHIFT; - rx_error &= ~(1 << I40E_RX_DESC_ERROR_HBO_SHIFT); + rx_error &= ~BIT(I40E_RX_DESC_ERROR_HBO_SHIFT); rx_ptype = (qword & I40E_RXD_QW1_PTYPE_MASK) >> I40E_RXD_QW1_PTYPE_SHIFT; @@ -1215,13 +1215,13 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) I40E_RX_INCREMENT(rx_ring, i); if (unlikely( - !(rx_status & (1 << I40E_RX_DESC_STATUS_EOF_SHIFT)))) { + !(rx_status & BIT(I40E_RX_DESC_STATUS_EOF_SHIFT)))) { rx_ring->rx_stats.non_eop_descs++; continue; } /* ERR_MASK will only have valid bits if EOP set */ - if (unlikely(rx_error & (1 << I40E_RX_DESC_ERROR_RXE_SHIFT))) { + if (unlikely(rx_error & BIT(I40E_RX_DESC_ERROR_RXE_SHIFT))) { dev_kfree_skb_any(skb); /* TODO: shouldn't we increment a counter indicating the * drop? @@ -1239,7 +1239,7 @@ static int i40e_clean_rx_irq_1buf(struct i40e_ring *rx_ring, int budget) i40e_rx_checksum(vsi, skb, rx_status, rx_error, rx_ptype); - vlan_tag = rx_status & (1 << I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) + vlan_tag = rx_status & BIT(I40E_RX_DESC_STATUS_L2TAG1P_SHIFT) ? le16_to_cpu(rx_desc->wb.qword0.lo_dword.l2tag1) : 0; i40e_receive_skb(rx_ring, skb, vlan_tag); @@ -1314,8 +1314,7 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, if (!test_bit(__I40E_DOWN, &vsi->state)) wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); } else { - i40evf_irq_enable_queues(vsi->back, - 1 << q_vector->v_idx); + i40evf_irq_enable_queues(vsi->back, BIT(q_vector->v_idx)); } } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h index e7a34f899f2cb..6b47c818d1f08 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h @@ -66,17 +66,17 @@ enum i40e_dyn_idx_t { /* Supported RSS offloads */ #define I40E_DEFAULT_RSS_HENA ( \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ - ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6) | \ - ((u64)1 << I40E_FILTER_PCTYPE_L2_PAYLOAD)) + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_SCTP) | \ + BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | \ + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6) | \ + BIT_ULL(I40E_FILTER_PCTYPE_L2_PAYLOAD)) /* Supported Rx Buffer Sizes */ #define I40E_RXBUFFER_512 512 /* Used for packet split */ @@ -129,16 +129,16 @@ enum i40e_dyn_idx_t { #define DESC_NEEDED (MAX_SKB_FRAGS + 4) #define I40E_MIN_DESC_PENDING 4 -#define I40E_TX_FLAGS_CSUM (u32)(1) -#define I40E_TX_FLAGS_HW_VLAN (u32)(1 << 1) -#define I40E_TX_FLAGS_SW_VLAN (u32)(1 << 2) -#define I40E_TX_FLAGS_TSO (u32)(1 << 3) -#define I40E_TX_FLAGS_IPV4 (u32)(1 << 4) -#define I40E_TX_FLAGS_IPV6 (u32)(1 << 5) -#define I40E_TX_FLAGS_FCCRC (u32)(1 << 6) -#define I40E_TX_FLAGS_FSO (u32)(1 << 7) -#define I40E_TX_FLAGS_FD_SB (u32)(1 << 9) -#define I40E_TX_FLAGS_VXLAN_TUNNEL (u32)(1 << 10) +#define I40E_TX_FLAGS_CSUM BIT(0) +#define I40E_TX_FLAGS_HW_VLAN BIT(1) +#define I40E_TX_FLAGS_SW_VLAN BIT(2) +#define I40E_TX_FLAGS_TSO BIT(3) +#define I40E_TX_FLAGS_IPV4 BIT(4) +#define I40E_TX_FLAGS_IPV6 BIT(5) +#define I40E_TX_FLAGS_FCCRC BIT(6) +#define I40E_TX_FLAGS_FSO BIT(7) +#define I40E_TX_FLAGS_FD_SB BIT(9) +#define I40E_TX_FLAGS_VXLAN_TUNNEL BIT(10) #define I40E_TX_FLAGS_VLAN_MASK 0xffff0000 #define I40E_TX_FLAGS_VLAN_PRIO_MASK 0xe0000000 #define I40E_TX_FLAGS_VLAN_PRIO_SHIFT 29 diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index cbf94bd4f2bfe..4ba9a012dcbac 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -605,7 +605,7 @@ enum i40e_rx_desc_status_bits { }; #define I40E_RXD_QW1_STATUS_SHIFT 0 -#define I40E_RXD_QW1_STATUS_MASK (((1 << I40E_RX_DESC_STATUS_LAST) - 1) \ +#define I40E_RXD_QW1_STATUS_MASK ((BIT(I40E_RX_DESC_STATUS_LAST) - 1) \ << I40E_RXD_QW1_STATUS_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT I40E_RX_DESC_STATUS_TSYNINDX_SHIFT @@ -613,8 +613,8 @@ enum i40e_rx_desc_status_bits { I40E_RXD_QW1_STATUS_TSYNINDX_SHIFT) #define I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT I40E_RX_DESC_STATUS_TSYNVALID_SHIFT -#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK (0x1UL << \ - I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) +#define I40E_RXD_QW1_STATUS_TSYNVALID_MASK \ + BIT_ULL(I40E_RXD_QW1_STATUS_TSYNVALID_SHIFT) enum i40e_rx_desc_fltstat_values { I40E_RX_DESC_FLTSTAT_NO_DATA = 0, @@ -748,8 +748,7 @@ enum i40e_rx_ptype_payload_layer { I40E_RXD_QW1_LENGTH_HBUF_SHIFT) #define I40E_RXD_QW1_LENGTH_SPH_SHIFT 63 -#define I40E_RXD_QW1_LENGTH_SPH_MASK (0x1ULL << \ - I40E_RXD_QW1_LENGTH_SPH_SHIFT) +#define I40E_RXD_QW1_LENGTH_SPH_MASK BIT_ULL(I40E_RXD_QW1_LENGTH_SPH_SHIFT) enum i40e_rx_desc_ext_status_bits { /* Note: These are predefined bit offsets */ @@ -925,12 +924,12 @@ enum i40e_tx_ctx_desc_eipt_offload { #define I40E_TXD_CTX_QW0_NATT_SHIFT 9 #define I40E_TXD_CTX_QW0_NATT_MASK (0x3ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) -#define I40E_TXD_CTX_UDP_TUNNELING (0x1ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) +#define I40E_TXD_CTX_UDP_TUNNELING BIT_ULL(I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_GRE_TUNNELING (0x2ULL << I40E_TXD_CTX_QW0_NATT_SHIFT) #define I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT 11 -#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK (0x1ULL << \ - I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) +#define I40E_TXD_CTX_QW0_EIP_NOINC_MASK \ + BIT_ULL(I40E_TXD_CTX_QW0_EIP_NOINC_SHIFT) #define I40E_TXD_CTX_EIP_NOINC_IPID_CONST I40E_TXD_CTX_QW0_EIP_NOINC_MASK @@ -995,8 +994,8 @@ enum i40e_filter_program_desc_fd_status { }; #define I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT 23 -#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK (0x1FFUL << \ - I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) +#define I40E_TXD_FLTR_QW0_DEST_VSI_MASK \ + BIT_ULL(I40E_TXD_FLTR_QW0_DEST_VSI_SHIFT) #define I40E_TXD_FLTR_QW1_CMD_SHIFT 4 #define I40E_TXD_FLTR_QW1_CMD_MASK (0xFFFFULL << \ @@ -1014,8 +1013,7 @@ enum i40e_filter_program_desc_pcmd { #define I40E_TXD_FLTR_QW1_DEST_MASK (0x3ULL << I40E_TXD_FLTR_QW1_DEST_SHIFT) #define I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT (0x7ULL + I40E_TXD_FLTR_QW1_CMD_SHIFT) -#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK (0x1ULL << \ - I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) +#define I40E_TXD_FLTR_QW1_CNT_ENA_MASK BIT_ULL(I40E_TXD_FLTR_QW1_CNT_ENA_SHIFT) #define I40E_TXD_FLTR_QW1_FD_STATUS_SHIFT (0x9ULL + \ I40E_TXD_FLTR_QW1_CMD_SHIFT) diff --git a/drivers/net/ethernet/intel/i40evf/i40evf.h b/drivers/net/ethernet/intel/i40evf/i40evf.h index dfc5bc5398900..c33c7cce52fe2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf.h +++ b/drivers/net/ethernet/intel/i40evf/i40evf.h @@ -207,17 +207,17 @@ struct i40evf_adapter { struct msix_entry *msix_entries; u32 flags; -#define I40EVF_FLAG_RX_CSUM_ENABLED (u32)(1) -#define I40EVF_FLAG_RX_1BUF_CAPABLE (u32)(1 << 1) -#define I40EVF_FLAG_RX_PS_CAPABLE (u32)(1 << 2) -#define I40EVF_FLAG_RX_PS_ENABLED (u32)(1 << 3) -#define I40EVF_FLAG_IN_NETPOLL (u32)(1 << 4) -#define I40EVF_FLAG_IMIR_ENABLED (u32)(1 << 5) -#define I40EVF_FLAG_MQ_CAPABLE (u32)(1 << 6) -#define I40EVF_FLAG_NEED_LINK_UPDATE (u32)(1 << 7) -#define I40EVF_FLAG_PF_COMMS_FAILED (u32)(1 << 8) -#define I40EVF_FLAG_RESET_PENDING (u32)(1 << 9) -#define I40EVF_FLAG_RESET_NEEDED (u32)(1 << 10) +#define I40EVF_FLAG_RX_CSUM_ENABLED BIT(0) +#define I40EVF_FLAG_RX_1BUF_CAPABLE BIT(1) +#define I40EVF_FLAG_RX_PS_CAPABLE BIT(2) +#define I40EVF_FLAG_RX_PS_ENABLED BIT(3) +#define I40EVF_FLAG_IN_NETPOLL BIT(4) +#define I40EVF_FLAG_IMIR_ENABLED BIT(5) +#define I40EVF_FLAG_MQ_CAPABLE BIT(6) +#define I40EVF_FLAG_NEED_LINK_UPDATE BIT(7) +#define I40EVF_FLAG_PF_COMMS_FAILED BIT(8) +#define I40EVF_FLAG_RESET_PENDING BIT(9) +#define I40EVF_FLAG_RESET_NEEDED BIT(10) /* duplcates for common code */ #define I40E_FLAG_FDIR_ATR_ENABLED 0 #define I40E_FLAG_DCB_ENABLED 0 @@ -225,16 +225,16 @@ struct i40evf_adapter { #define I40E_FLAG_RX_CSUM_ENABLED I40EVF_FLAG_RX_CSUM_ENABLED /* flags for admin queue service task */ u32 aq_required; -#define I40EVF_FLAG_AQ_ENABLE_QUEUES (u32)(1) -#define I40EVF_FLAG_AQ_DISABLE_QUEUES (u32)(1 << 1) -#define I40EVF_FLAG_AQ_ADD_MAC_FILTER (u32)(1 << 2) -#define I40EVF_FLAG_AQ_ADD_VLAN_FILTER (u32)(1 << 3) -#define I40EVF_FLAG_AQ_DEL_MAC_FILTER (u32)(1 << 4) -#define I40EVF_FLAG_AQ_DEL_VLAN_FILTER (u32)(1 << 5) -#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6) -#define I40EVF_FLAG_AQ_MAP_VECTORS (u32)(1 << 7) -#define I40EVF_FLAG_AQ_HANDLE_RESET (u32)(1 << 8) -#define I40EVF_FLAG_AQ_GET_CONFIG (u32)(1 << 10) +#define I40EVF_FLAG_AQ_ENABLE_QUEUES BIT(0) +#define I40EVF_FLAG_AQ_DISABLE_QUEUES BIT(1) +#define I40EVF_FLAG_AQ_ADD_MAC_FILTER BIT(2) +#define I40EVF_FLAG_AQ_ADD_VLAN_FILTER BIT(3) +#define I40EVF_FLAG_AQ_DEL_MAC_FILTER BIT(4) +#define I40EVF_FLAG_AQ_DEL_VLAN_FILTER BIT(5) +#define I40EVF_FLAG_AQ_CONFIGURE_QUEUES BIT(6) +#define I40EVF_FLAG_AQ_MAP_VECTORS BIT(7) +#define I40EVF_FLAG_AQ_HANDLE_RESET BIT(8) +#define I40EVF_FLAG_AQ_GET_CONFIG BIT(10) /* OS defined structs */ struct net_device *netdev; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c index 2b53c870e7f11..4790437a50ac0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_ethtool.c @@ -381,11 +381,11 @@ static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, switch (cmd->flow_type) { case TCP_V4_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case UDP_V4_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; @@ -397,11 +397,11 @@ static int i40evf_get_rss_hash_opts(struct i40evf_adapter *adapter, break; case TCP_V6_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; case UDP_V6_FLOW: - if (hena & ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) + if (hena & BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP)) cmd->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3; break; @@ -479,10 +479,10 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case TCP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_TCP); break; default: return -EINVAL; @@ -491,10 +491,10 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case TCP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena &= ~BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_TCP); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_TCP); break; default: return -EINVAL; @@ -503,12 +503,12 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case UDP_V4_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; default: return -EINVAL; @@ -517,12 +517,12 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, case UDP_V6_FLOW: switch (nfc->data & (RXH_L4_B_0_1 | RXH_L4_B_2_3)) { case 0: - hena &= ~(((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena &= ~(BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; case (RXH_L4_B_0_1 | RXH_L4_B_2_3): - hena |= (((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6)); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_UDP) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; default: return -EINVAL; @@ -535,7 +535,7 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER); break; case AH_ESP_V6_FLOW: case AH_V6_FLOW: @@ -544,15 +544,15 @@ static int i40evf_set_rss_hash_opt(struct i40evf_adapter *adapter, if ((nfc->data & RXH_L4_B_0_1) || (nfc->data & RXH_L4_B_2_3)) return -EINVAL; - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); + hena |= BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER); break; case IPV4_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV4); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV4_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV4)); break; case IPV6_FLOW: - hena |= ((u64)1 << I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | - ((u64)1 << I40E_FILTER_PCTYPE_FRAG_IPV6); + hena |= (BIT_ULL(I40E_FILTER_PCTYPE_NONF_IPV6_OTHER) | + BIT_ULL(I40E_FILTER_PCTYPE_FRAG_IPV6)); break; default: return -EINVAL; diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index f43ac9c7e8269..1503cad918d88 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -240,7 +240,7 @@ void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask) int i; for (i = 1; i < adapter->num_msix_vectors; i++) { - if (mask & (1 << (i - 1))) { + if (mask & BIT(i - 1)) { wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), I40E_VFINT_DYN_CTLN1_INTENA_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | @@ -268,7 +268,7 @@ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, u32 mask) wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl); } for (i = 1; i < adapter->num_msix_vectors; i++) { - if (mask & (1 << i)) { + if (mask & BIT(i)) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1)); dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | @@ -377,7 +377,7 @@ i40evf_map_vector_to_txq(struct i40evf_adapter *adapter, int v_idx, int t_idx) q_vector->tx.count++; q_vector->tx.latency_range = I40E_LOW_LATENCY; q_vector->num_ringpairs++; - q_vector->ring_mask |= (1 << t_idx); + q_vector->ring_mask |= BIT(t_idx); } /** @@ -2320,7 +2320,7 @@ static int i40evf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) hw = &adapter->hw; hw->back = adapter; - adapter->msg_enable = (1 << DEFAULT_DEBUG_LEVEL_SHIFT) - 1; + adapter->msg_enable = BIT(DEFAULT_DEBUG_LEVEL_SHIFT) - 1; adapter->state = __I40EVF_STARTUP; /* Call save state here because it relies on the adapter struct. */ diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c index becd300fca7c1..d4eb1a5e7d42c 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c @@ -294,7 +294,7 @@ void i40evf_enable_queues(struct i40evf_adapter *adapter) } adapter->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; - vqs.tx_queues = (1 << adapter->num_active_queues) - 1; + vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_ENABLE_QUEUES; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_ENABLE_QUEUES, @@ -319,7 +319,7 @@ void i40evf_disable_queues(struct i40evf_adapter *adapter) } adapter->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES; vqs.vsi_id = adapter->vsi_res->vsi_id; - vqs.tx_queues = (1 << adapter->num_active_queues) - 1; + vqs.tx_queues = BIT(adapter->num_active_queues) - 1; vqs.rx_queues = vqs.tx_queues; adapter->aq_required &= ~I40EVF_FLAG_AQ_DISABLE_QUEUES; i40evf_send_pf_msg(adapter, I40E_VIRTCHNL_OP_DISABLE_QUEUES, -- GitLab From 564bc402526e437729ecafe3c3511f7cab9f0327 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Thu, 23 Jul 2015 09:46:11 -0400 Subject: [PATCH 1532/7006] ext4, jbd2: add REQ_FUA flag when recording an error in the superblock When an error condition is detected, an error status should be recorded into superblocks of EXT4 or JBD2. However, the write request is submitted now without REQ_FUA flag, even in "barrier=1" mode, which is followed by panic() function in "errors=panic" mode. On mobile devices which make whole system reset as soon as kernel panic occurs, this write request containing an error flag will disappear just from storage cache without written to the physical cells. Therefore, when next start, even forever, the error flag cannot be shown in both superblocks, and e2fsck cannot fix the filesystem problems automatically, unless e2fsck is executed in force checking mode. [ Changed use test_opt(sb, BARRIER) of checking the journal flags -- TYT ] Signed-off-by: Daeho Jeong Signed-off-by: Theodore Ts'o --- fs/ext4/super.c | 3 ++- fs/jbd2/journal.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 14909cd91515d..a51db9ca90fd5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4667,7 +4667,8 @@ static int ext4_commit_super(struct super_block *sb, int sync) ext4_superblock_csum_set(sb); mark_buffer_dirty(sbh); if (sync) { - error = sync_dirty_buffer(sbh); + error = __sync_dirty_buffer(sbh, + test_opt(sb, BARRIER) ? WRITE_FUA : WRITE_SYNC); if (error) return error; diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c index 4ff3fad4e9e3f..fe1b4bdecdfa5 100644 --- a/fs/jbd2/journal.c +++ b/fs/jbd2/journal.c @@ -1456,7 +1456,7 @@ void jbd2_journal_update_sb_errno(journal_t *journal) sb->s_errno = cpu_to_be32(journal->j_errno); read_unlock(&journal->j_state_lock); - jbd2_write_superblock(journal, WRITE_SYNC); + jbd2_write_superblock(journal, WRITE_FUA); } EXPORT_SYMBOL(jbd2_journal_update_sb_errno); -- GitLab From 2385eb0c5fbcb4316d3490b3affba8e15efc7eb8 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Jul 2015 12:55:02 +0200 Subject: [PATCH 1533/7006] netfilter: nf_queue: fix nf_queue_nf_hook_drop() This function reacquires the rtnl_lock() which is already held by nf_unregister_hook(). This can be triggered via: modprobe nf_conntrack_ipv4 && rmmod nf_conntrack_ipv4 [ 720.628746] INFO: task rmmod:3578 blocked for more than 120 seconds. [ 720.628749] Not tainted 4.2.0-rc2+ #113 [ 720.628752] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. [ 720.628754] rmmod D ffff8800ca46fd58 0 3578 3571 0x00000080 [...] [ 720.628783] Call Trace: [ 720.628790] [] schedule+0x6b/0x90 [ 720.628795] [] schedule_preempt_disabled+0x13/0x20 [ 720.628799] [] mutex_lock_nested+0x1f5/0x380 [ 720.628803] [] ? rtnl_lock+0x12/0x20 [ 720.628807] [] ? rtnl_lock+0x12/0x20 [ 720.628812] [] rtnl_lock+0x12/0x20 [ 720.628817] [] nf_queue_nf_hook_drop+0x15/0x160 [ 720.628825] [] nf_unregister_net_hook+0x168/0x190 [ 720.628831] [] nf_unregister_hook+0x64/0x80 [ 720.628837] [] nf_unregister_hooks+0x20/0x30 [...] Moreover, nf_unregister_net_hook() should only destroy the queue for this netns, not for every netns. Reported-by: Fengguang Wu Fixes: 085db2c04557 ("netfilter: Per network namespace netfilter hooks.") Signed-off-by: Pablo Neira Ayuso Acked-by: "Eric W. Biederman" --- net/netfilter/core.c | 2 +- net/netfilter/nf_internals.h | 2 +- net/netfilter/nf_queue.c | 12 +++--------- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 87d237d20870f..12504fbbeef76 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -154,7 +154,7 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif synchronize_net(); - nf_queue_nf_hook_drop(elem); + nf_queue_nf_hook_drop(net, elem); kfree(elem); } EXPORT_SYMBOL(nf_unregister_net_hook); diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h index 399210693c2a8..065522564ac6a 100644 --- a/net/netfilter/nf_internals.h +++ b/net/netfilter/nf_internals.h @@ -19,7 +19,7 @@ unsigned int nf_iterate(struct list_head *head, struct sk_buff *skb, /* nf_queue.c */ int nf_queue(struct sk_buff *skb, struct nf_hook_ops *elem, struct nf_hook_state *state, unsigned int queuenum); -void nf_queue_nf_hook_drop(struct nf_hook_ops *ops); +void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops); int __init netfilter_queue_init(void); /* nf_log.c */ diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c index 8a8b2abc35ffd..96777f9a9350b 100644 --- a/net/netfilter/nf_queue.c +++ b/net/netfilter/nf_queue.c @@ -105,21 +105,15 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry) } EXPORT_SYMBOL_GPL(nf_queue_entry_get_refs); -void nf_queue_nf_hook_drop(struct nf_hook_ops *ops) +void nf_queue_nf_hook_drop(struct net *net, struct nf_hook_ops *ops) { const struct nf_queue_handler *qh; - struct net *net; - rtnl_lock(); rcu_read_lock(); qh = rcu_dereference(queue_handler); - if (qh) { - for_each_net(net) { - qh->nf_hook_drop(net, ops); - } - } + if (qh) + qh->nf_hook_drop(net, ops); rcu_read_unlock(); - rtnl_unlock(); } /* -- GitLab From 7181ebafd4306c9328fa1cd0ead69afa397ffe75 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Jul 2015 09:31:25 +0200 Subject: [PATCH 1534/7006] netfilter: fix possible removal of wrong hook nf_unregister_net_hook() uses the nf_hook_ops fields as tuple to look up for the corresponding hook in the list. However, we may have two hooks with exactly the same configuration. This shouldn't be a problem for nftables since every new chain has an unique priv field set, but this may still cause us problems in the future, so better address this problem now by keeping a reference to the original nf_hook_ops structure to make sure we delete the right hook from nf_unregister_net_hook(). Fixes: 085db2c04557 ("netfilter: Per network namespace netfilter hooks.") Signed-off-by: Pablo Neira Ayuso Acked-by: "Eric W. Biederman" --- net/netfilter/core.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 12504fbbeef76..0ecb2b52f2766 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -78,26 +78,27 @@ static struct list_head *find_nf_hook_list(struct net *net, return nf_hook_list; } +struct nf_hook_entry { + const struct nf_hook_ops *orig_ops; + struct nf_hook_ops ops; +}; + int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) { struct list_head *nf_hook_list; - struct nf_hook_ops *elem, *new; + struct nf_hook_entry *entry; + struct nf_hook_ops *elem; - new = kzalloc(sizeof(*new), GFP_KERNEL); - if (!new) + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) return -ENOMEM; - new->hook = reg->hook; - new->dev = reg->dev; - new->owner = reg->owner; - new->priv = reg->priv; - new->pf = reg->pf; - new->hooknum = reg->hooknum; - new->priority = reg->priority; + entry->orig_ops = reg; + entry->ops = *reg; nf_hook_list = find_nf_hook_list(net, reg); if (!nf_hook_list) { - kfree(new); + kfree(entry); return -ENOENT; } @@ -106,7 +107,7 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) if (reg->priority < elem->priority) break; } - list_add_rcu(&new->list, elem->list.prev); + list_add_rcu(&entry->ops.list, elem->list.prev); mutex_unlock(&nf_hook_mutex); #ifdef CONFIG_NETFILTER_INGRESS if (reg->pf == NFPROTO_NETDEV && reg->hooknum == NF_NETDEV_INGRESS) @@ -122,6 +123,7 @@ EXPORT_SYMBOL(nf_register_net_hook); void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) { struct list_head *nf_hook_list; + struct nf_hook_entry *entry; struct nf_hook_ops *elem; nf_hook_list = find_nf_hook_list(net, reg); @@ -130,14 +132,9 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) mutex_lock(&nf_hook_mutex); list_for_each_entry(elem, nf_hook_list, list) { - if ((reg->hook == elem->hook) && - (reg->dev == elem->dev) && - (reg->owner == elem->owner) && - (reg->priv == elem->priv) && - (reg->pf == elem->pf) && - (reg->hooknum == elem->hooknum) && - (reg->priority == elem->priority)) { - list_del_rcu(&elem->list); + entry = container_of(elem, struct nf_hook_entry, ops); + if (entry->orig_ops == reg) { + list_del_rcu(&entry->ops.list); break; } } @@ -154,8 +151,8 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) static_key_slow_dec(&nf_hooks_needed[reg->pf][reg->hooknum]); #endif synchronize_net(); - nf_queue_nf_hook_drop(net, elem); - kfree(elem); + nf_queue_nf_hook_drop(net, &entry->ops); + kfree(entry); } EXPORT_SYMBOL(nf_unregister_net_hook); -- GitLab From 3bbd14e0a2e3a988b1b5fe702a2539bd8d0ec622 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Mon, 20 Jul 2015 13:32:52 +0200 Subject: [PATCH 1535/7006] netfilter: rename local nf_hook_list to hook_list 085db2c04557 ("netfilter: Per network namespace netfilter hooks.") introduced a new nf_hook_list that is global, so let's avoid this overlap. Signed-off-by: Pablo Neira Ayuso Acked-by: "Eric W. Biederman" --- include/linux/netfilter.h | 14 +++++++------- net/netfilter/core.c | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index e01da73ee6c4c..d788ce62d8264 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -140,20 +140,20 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg); #ifdef HAVE_JUMP_LABEL extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; -static inline bool nf_hook_list_active(struct list_head *nf_hook_list, +static inline bool nf_hook_list_active(struct list_head *hook_list, u_int8_t pf, unsigned int hook) { if (__builtin_constant_p(pf) && __builtin_constant_p(hook)) return static_key_false(&nf_hooks_needed[pf][hook]); - return !list_empty(nf_hook_list); + return !list_empty(hook_list); } #else -static inline bool nf_hook_list_active(struct list_head *nf_hook_list, +static inline bool nf_hook_list_active(struct list_head *hook_list, u_int8_t pf, unsigned int hook) { - return !list_empty(nf_hook_list); + return !list_empty(hook_list); } #endif @@ -175,12 +175,12 @@ static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, int thresh) { struct net *net = dev_net(indev ? indev : outdev); - struct list_head *nf_hook_list = &net->nf.hooks[pf][hook]; + struct list_head *hook_list = &net->nf.hooks[pf][hook]; - if (nf_hook_list_active(nf_hook_list, pf, hook)) { + if (nf_hook_list_active(hook_list, pf, hook)) { struct nf_hook_state state; - nf_hook_state_init(&state, nf_hook_list, hook, thresh, + nf_hook_state_init(&state, hook_list, hook, thresh, pf, indev, outdev, sk, okfn); return nf_hook_slow(skb, &state); } diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 0ecb2b52f2766..2a5a0704245cc 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -62,20 +62,20 @@ EXPORT_SYMBOL(nf_hooks_needed); static DEFINE_MUTEX(nf_hook_mutex); -static struct list_head *find_nf_hook_list(struct net *net, +static struct list_head *nf_find_hook_list(struct net *net, const struct nf_hook_ops *reg) { - struct list_head *nf_hook_list = NULL; + struct list_head *hook_list = NULL; if (reg->pf != NFPROTO_NETDEV) - nf_hook_list = &net->nf.hooks[reg->pf][reg->hooknum]; + hook_list = &net->nf.hooks[reg->pf][reg->hooknum]; else if (reg->hooknum == NF_NETDEV_INGRESS) { #ifdef CONFIG_NETFILTER_INGRESS if (reg->dev && dev_net(reg->dev) == net) - nf_hook_list = ®->dev->nf_hooks_ingress; + hook_list = ®->dev->nf_hooks_ingress; #endif } - return nf_hook_list; + return hook_list; } struct nf_hook_entry { @@ -85,7 +85,7 @@ struct nf_hook_entry { int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) { - struct list_head *nf_hook_list; + struct list_head *hook_list; struct nf_hook_entry *entry; struct nf_hook_ops *elem; @@ -96,14 +96,14 @@ int nf_register_net_hook(struct net *net, const struct nf_hook_ops *reg) entry->orig_ops = reg; entry->ops = *reg; - nf_hook_list = find_nf_hook_list(net, reg); - if (!nf_hook_list) { + hook_list = nf_find_hook_list(net, reg); + if (!hook_list) { kfree(entry); return -ENOENT; } mutex_lock(&nf_hook_mutex); - list_for_each_entry(elem, nf_hook_list, list) { + list_for_each_entry(elem, hook_list, list) { if (reg->priority < elem->priority) break; } @@ -122,16 +122,16 @@ EXPORT_SYMBOL(nf_register_net_hook); void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) { - struct list_head *nf_hook_list; + struct list_head *hook_list; struct nf_hook_entry *entry; struct nf_hook_ops *elem; - nf_hook_list = find_nf_hook_list(net, reg); - if (!nf_hook_list) + hook_list = nf_find_hook_list(net, reg); + if (!hook_list) return; mutex_lock(&nf_hook_mutex); - list_for_each_entry(elem, nf_hook_list, list) { + list_for_each_entry(elem, hook_list, list) { entry = container_of(elem, struct nf_hook_entry, ops); if (entry->orig_ops == reg) { list_del_rcu(&entry->ops.list); @@ -139,7 +139,7 @@ void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *reg) } } mutex_unlock(&nf_hook_mutex); - if (&elem->list == nf_hook_list) { + if (&elem->list == hook_list) { WARN(1, "nf_unregister_net_hook: hook not found!\n"); return; } -- GitLab From 4c38b9c30f78d44c576ca3049577fbd4d5c2acc6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 08:28:50 +0800 Subject: [PATCH 1536/7006] ASoC: cs35l32: Fix define for CS35L32_SDOUT_3ST According to the datasheet, the CS35L32_SDOUT_3ST is BIT(3). Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/cs35l32.h b/sound/soc/codecs/cs35l32.h index 31ab804a22bcc..1d6c2508cd411 100644 --- a/sound/soc/codecs/cs35l32.h +++ b/sound/soc/codecs/cs35l32.h @@ -80,7 +80,7 @@ struct cs35l32_platform_data { #define CS35L32_GAIN_MGR_MASK 0x08 #define CS35L32_ADSP_SHARE_MASK 0x08 #define CS35L32_ADSP_DATACFG_MASK 0x30 -#define CS35L32_SDOUT_3ST 0x80 +#define CS35L32_SDOUT_3ST 0x08 #define CS35L32_BATT_REC_MASK 0x0E #define CS35L32_BATT_THRESH_MASK 0x30 -- GitLab From d5a78c8ea050e9c81db1e25a4916d8d9168dfb2e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 08:29:57 +0800 Subject: [PATCH 1537/7006] ASoC: cs35l32: Remove unneeded NULL test for cs35l32->reset_gpio It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs35l32.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/cs35l32.c b/sound/soc/codecs/cs35l32.c index 8f40025b7e7ca..f5f86b2045218 100644 --- a/sound/soc/codecs/cs35l32.c +++ b/sound/soc/codecs/cs35l32.c @@ -441,8 +441,7 @@ static int cs35l32_i2c_probe(struct i2c_client *i2c_client, if (IS_ERR(cs35l32->reset_gpio)) return PTR_ERR(cs35l32->reset_gpio); - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); /* initialize codec */ ret = regmap_read(cs35l32->regmap, CS35L32_DEVID_AB, ®); @@ -536,8 +535,7 @@ static int cs35l32_i2c_remove(struct i2c_client *i2c_client) snd_soc_unregister_codec(&i2c_client->dev); /* Hold down reset */ - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); return 0; } @@ -551,8 +549,7 @@ static int cs35l32_runtime_suspend(struct device *dev) regcache_mark_dirty(cs35l32->regmap); /* Hold down reset */ - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 0); /* remove power */ regulator_bulk_disable(ARRAY_SIZE(cs35l32->supplies), @@ -575,8 +572,7 @@ static int cs35l32_runtime_resume(struct device *dev) return ret; } - if (cs35l32->reset_gpio) - gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); + gpiod_set_value_cansleep(cs35l32->reset_gpio, 1); regcache_cache_only(cs35l32->regmap, false); regcache_sync(cs35l32->regmap); -- GitLab From 8626e5eb6c33b78ba7a5eb7cfbc5109896f443ef Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 08:26:57 +0800 Subject: [PATCH 1538/7006] ASoC: cs42l73: Fix mask for setting CS42L73_SP_3ST bit CS42L73_SP_3ST is BIT(7), so the mask field is wrong. Fix it. Signed-off-by: Axel Lin Acked-by: Brian Austin Signed-off-by: Mark Brown --- sound/soc/codecs/cs42l73.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c index b7853b9d3a60b..efd924ae384c8 100644 --- a/sound/soc/codecs/cs42l73.c +++ b/sound/soc/codecs/cs42l73.c @@ -1236,8 +1236,8 @@ static int cs42l73_set_tristate(struct snd_soc_dai *dai, int tristate) struct snd_soc_codec *codec = dai->codec; int id = dai->id; - return snd_soc_update_bits(codec, CS42L73_SPC(id), - 0x7F, tristate << 7); + return snd_soc_update_bits(codec, CS42L73_SPC(id), CS42L73_SP_3ST, + tristate << 7); } static const struct snd_pcm_hw_constraint_list constraints_12_24 = { -- GitLab From fac5e5b912bd1b42bad292e0b03956967229b45b Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Fri, 19 Jun 2015 08:46:15 +0000 Subject: [PATCH 1539/7006] Bluetooth: dtl1_cs: Fix coding style -- clean up Braces {} are not necessary for single statement blocks reported by checkpatch Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 78e10f0c65b28..09c130d73ba35 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -182,9 +182,9 @@ static void dtl1_control(struct dtl1_info *info, struct sk_buff *skb) int i; printk(KERN_INFO "Bluetooth: Nokia control data ="); - for (i = 0; i < skb->len; i++) { + for (i = 0; i < skb->len; i++) printk(" %02x", skb->data[i]); - } + printk("\n"); /* transition to active state */ -- GitLab From d77b4852b4d3698a90eef219acf9cddc964b1f3a Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 21 Jun 2015 16:45:20 +0200 Subject: [PATCH 1540/7006] mac802154: add llsec address update workaround This patch adds a workaround for using the new nl802154 netlink interface with the old ieee802154 netlink interface togehter. The nl802154 currently supports no access for llsec layer, currently there are users outside which are using both interfaces at the same time. This patch adds a necessary call when addresses are updated. Reported-by: Simon Vincent Suggested-by: Phoebe Buckheister Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/cfg.c | 9 +++++++-- net/mac802154/ieee802154_i.h | 2 ++ net/mac802154/iface.c | 7 ++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 317c4662e5446..44db8613812e1 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -145,13 +145,18 @@ static int ieee802154_set_pan_id(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, __le16 pan_id) { + int ret; + ASSERT_RTNL(); if (wpan_dev->pan_id == pan_id) return 0; - wpan_dev->pan_id = pan_id; - return 0; + ret = mac802154_wpan_update_llsec(wpan_dev->netdev); + if (!ret) + wpan_dev->pan_id = pan_id; + + return ret; } static int diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 34755d5751a46..6d4f3ccc3c1c3 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -167,6 +167,8 @@ void mac802154_get_table(struct net_device *dev, struct ieee802154_llsec_table **t); void mac802154_unlock_table(struct net_device *dev); +int mac802154_wpan_update_llsec(struct net_device *dev); + /* interface handling */ int ieee802154_iface_init(void); void ieee802154_iface_exit(void); diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 8b698246a51b6..4760368a34937 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -30,7 +30,7 @@ #include "ieee802154_i.h" #include "driver-ops.h" -static int mac802154_wpan_update_llsec(struct net_device *dev) +int mac802154_wpan_update_llsec(struct net_device *dev) { struct ieee802154_sub_if_data *sdata = IEEE802154_DEV_TO_SUB_IF(dev); struct ieee802154_mlme_ops *ops = ieee802154_mlme_ops(dev); @@ -471,6 +471,7 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, enum nl802154_iftype type) { struct wpan_dev *wpan_dev = &sdata->wpan_dev; + int ret; u8 tmp; /* set some type-dependent values */ @@ -505,6 +506,10 @@ ieee802154_setup_sdata(struct ieee802154_sub_if_data *sdata, mutex_init(&sdata->sec_mtx); mac802154_llsec_init(&sdata->sec); + ret = mac802154_wpan_update_llsec(sdata->dev); + if (ret < 0) + return ret; + break; case NL802154_IFTYPE_MONITOR: sdata->dev->destructor = free_netdev; -- GitLab From 301d7d42a207e0d4f5bf11c7e2b6862ddebc8c36 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Sun, 21 Jun 2015 17:11:19 +0200 Subject: [PATCH 1541/7006] 6lowpan: add request for ipv6 module The iphc module depends on CONFIG_IPV6, because it's not very useful to build the module without IPv6 support. Recently an user reported about issues for setting an IPv6 address to a 6LoWPAN interface. The issues was solved by modprobe the ipv6 module before. To avoid such user issues we try to request the ipv6 module when the 6LoWPAN module is loaded. Signed-off-by: Alexander Aring Acked-by: Jukka Rissanen Signed-off-by: Marcel Holtmann --- net/6lowpan/iphc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 94a375c04f21c..9055d7b9d1129 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c @@ -613,6 +613,8 @@ EXPORT_SYMBOL_GPL(lowpan_header_compress); static int __init lowpan_module_init(void) { + request_module_nowait("ipv6"); + request_module_nowait("nhc_dest"); request_module_nowait("nhc_fragment"); request_module_nowait("nhc_hop"); -- GitLab From 8f451829dd97fb22f03844ca52a49828e2e1d666 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 23 Jun 2015 11:41:03 +0530 Subject: [PATCH 1542/7006] mac802154: use WARN_ON() macro This patch will generate the warning if the required driver ops were not defined. Also it removes unnecessary debug message. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/main.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 356b346e1ee86..4caf04b676d72 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -58,11 +58,9 @@ ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops) struct ieee802154_local *local; size_t priv_size; - if (!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed || - !ops->start || !ops->stop || !ops->set_channel) { - pr_err("undefined IEEE802.15.4 device operations\n"); + if (WARN_ON(!ops || !(ops->xmit_async || ops->xmit_sync) || !ops->ed || + !ops->start || !ops->stop || !ops->set_channel)) return NULL; - } /* Ensure 32-byte alignment of our private data and hw private data. * We use the wpan_phy priv data for both our ieee802154_local and for -- GitLab From 927e031c7cb266e5f7fd600899f1603813ee7439 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 23 Jun 2015 16:03:44 +0530 Subject: [PATCH 1543/7006] mac802154: remove unused macro This patch removes the unused macro which was removed with the rework of linux-wpan kernel. Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- net/mac802154/ieee802154_i.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 6d4f3ccc3c1c3..ed8746334befa 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -94,8 +94,6 @@ struct ieee802154_sub_if_data { struct mac802154_llsec sec; }; -#define MAC802154_CHAN_NONE 0xff /* No channel is assigned */ - /* utility functions/constants */ extern const void *const mac802154_wpan_phy_privid; /* for wpan_phy privid */ -- GitLab From c4227c8a6246b30793bd7360113ddc7b66d526dc Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 24 Jun 2015 11:36:34 +0200 Subject: [PATCH 1544/7006] mac802154: util: add stop_device utility function This patch adds ieee802154_stop_device for preparing a utility function to stop the ieee802154 device. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/ieee802154_i.h | 1 + net/mac802154/iface.c | 7 ++----- net/mac802154/util.c | 8 ++++++++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index ed8746334befa..04077830e88c0 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -176,5 +176,6 @@ ieee802154_if_add(struct ieee802154_local *local, const char *name, unsigned char name_assign_type, enum nl802154_iftype type, __le64 extended_addr); void ieee802154_remove_interfaces(struct ieee802154_local *local); +void ieee802154_stop_device(struct ieee802154_local *local); #endif /* __IEEE802154_I_H */ diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 4760368a34937..416de903e4675 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c @@ -314,11 +314,8 @@ static int mac802154_slave_close(struct net_device *dev) clear_bit(SDATA_STATE_RUNNING, &sdata->state); - if (!local->open_count) { - flush_workqueue(local->workqueue); - hrtimer_cancel(&local->ifs_timer); - drv_stop(local); - } + if (!local->open_count) + ieee802154_stop_device(local); return 0; } diff --git a/net/mac802154/util.c b/net/mac802154/util.c index 583435f389303..f9fd0957ab67f 100644 --- a/net/mac802154/util.c +++ b/net/mac802154/util.c @@ -14,6 +14,7 @@ */ #include "ieee802154_i.h" +#include "driver-ops.h" /* privid for wpan_phys to determine whether they belong to us or not */ const void *const mac802154_wpan_phy_privid = &mac802154_wpan_phy_privid; @@ -92,3 +93,10 @@ void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, dev_consume_skb_any(skb); } EXPORT_SYMBOL(ieee802154_xmit_complete); + +void ieee802154_stop_device(struct ieee802154_local *local) +{ + flush_workqueue(local->workqueue); + hrtimer_cancel(&local->ifs_timer); + drv_stop(local); +} -- GitLab From a6cb869b3b7c16fd7c3ee766dd9f9a4fdda7edf9 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Wed, 24 Jun 2015 11:36:35 +0200 Subject: [PATCH 1545/7006] cfg802154: add PM hooks This patch help to implement suspend/resume in mac802154, these hooks will be run before the device is suspended and after it resumes. Signed-off-by: Varka Bhadram Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/cfg802154.h | 2 ++ net/ieee802154/rdev-ops.h | 20 ++++++++++++++++++++ net/ieee802154/sysfs.c | 38 ++++++++++++++++++++++++++++++++++++++ net/ieee802154/trace.h | 22 ++++++++++++++++++++++ 4 files changed, 82 insertions(+) diff --git a/include/net/cfg802154.h b/include/net/cfg802154.h index 290a9a69af078..382f94b59f2f7 100644 --- a/include/net/cfg802154.h +++ b/include/net/cfg802154.h @@ -34,6 +34,8 @@ struct cfg802154_ops { int type); void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, struct net_device *dev); + int (*suspend)(struct wpan_phy *wpan_phy); + int (*resume)(struct wpan_phy *wpan_phy); int (*add_virtual_intf)(struct wpan_phy *wpan_phy, const char *name, unsigned char name_assign_type, diff --git a/net/ieee802154/rdev-ops.h b/net/ieee802154/rdev-ops.h index b2155a123f6c8..8d5960a371951 100644 --- a/net/ieee802154/rdev-ops.h +++ b/net/ieee802154/rdev-ops.h @@ -23,6 +23,26 @@ rdev_del_virtual_intf_deprecated(struct cfg802154_registered_device *rdev, rdev->ops->del_virtual_intf_deprecated(&rdev->wpan_phy, dev); } +static inline int +rdev_suspend(struct cfg802154_registered_device *rdev) +{ + int ret; + trace_802154_rdev_suspend(&rdev->wpan_phy); + ret = rdev->ops->suspend(&rdev->wpan_phy); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + +static inline int +rdev_resume(struct cfg802154_registered_device *rdev) +{ + int ret; + trace_802154_rdev_resume(&rdev->wpan_phy); + ret = rdev->ops->resume(&rdev->wpan_phy); + trace_802154_rdev_return_int(&rdev->wpan_phy, ret); + return ret; +} + static inline int rdev_add_virtual_intf(struct cfg802154_registered_device *rdev, char *name, unsigned char name_assign_type, diff --git a/net/ieee802154/sysfs.c b/net/ieee802154/sysfs.c index 133b4280660cf..bd88525b041e7 100644 --- a/net/ieee802154/sysfs.c +++ b/net/ieee802154/sysfs.c @@ -14,11 +14,13 @@ */ #include +#include #include #include "core.h" #include "sysfs.h" +#include "rdev-ops.h" static inline struct cfg802154_registered_device * dev_to_rdev(struct device *dev) @@ -62,10 +64,46 @@ static struct attribute *pmib_attrs[] = { }; ATTRIBUTE_GROUPS(pmib); +#ifdef CONFIG_PM_SLEEP +static int wpan_phy_suspend(struct device *dev) +{ + struct cfg802154_registered_device *rdev = dev_to_rdev(dev); + int ret = 0; + + if (rdev->ops->suspend) { + rtnl_lock(); + ret = rdev_suspend(rdev); + rtnl_unlock(); + } + + return ret; +} + +static int wpan_phy_resume(struct device *dev) +{ + struct cfg802154_registered_device *rdev = dev_to_rdev(dev); + int ret = 0; + + if (rdev->ops->resume) { + rtnl_lock(); + ret = rdev_resume(rdev); + rtnl_unlock(); + } + + return ret; +} + +static SIMPLE_DEV_PM_OPS(wpan_phy_pm_ops, wpan_phy_suspend, wpan_phy_resume); +#define WPAN_PHY_PM_OPS (&wpan_phy_pm_ops) +#else +#define WPAN_PHY_PM_OPS NULL +#endif + struct class wpan_phy_class = { .name = "ieee802154", .dev_release = wpan_phy_release, .dev_groups = pmib_groups, + .pm = WPAN_PHY_PM_OPS, }; int wpan_phy_sysfs_init(void) diff --git a/net/ieee802154/trace.h b/net/ieee802154/trace.h index 9b5f0eb366969..4399b7fbaa314 100644 --- a/net/ieee802154/trace.h +++ b/net/ieee802154/trace.h @@ -40,6 +40,28 @@ * rdev->ops traces * *************************************************************/ +DECLARE_EVENT_CLASS(wpan_phy_only_evt, + TP_PROTO(struct wpan_phy *wpan_phy), + TP_ARGS(wpan_phy), + TP_STRUCT__entry( + WPAN_PHY_ENTRY + ), + TP_fast_assign( + WPAN_PHY_ASSIGN; + ), + TP_printk(WPAN_PHY_PR_FMT, WPAN_PHY_PR_ARG) +); + +DEFINE_EVENT(wpan_phy_only_evt, 802154_rdev_suspend, + TP_PROTO(struct wpan_phy *wpan_phy), + TP_ARGS(wpan_phy) +); + +DEFINE_EVENT(wpan_phy_only_evt, 802154_rdev_resume, + TP_PROTO(struct wpan_phy *wpan_phy), + TP_ARGS(wpan_phy) +); + TRACE_EVENT(802154_rdev_add_virtual_intf, TP_PROTO(struct wpan_phy *wpan_phy, char *name, enum nl802154_iftype type, __le64 extended_addr), -- GitLab From 3cf24cf8c3c06f9a6cacc8fc2cad94661b6096b6 Mon Sep 17 00:00:00 2001 From: Alexander Aring Date: Wed, 24 Jun 2015 11:36:36 +0200 Subject: [PATCH 1546/7006] mac802154: cfg: add suspend and resume callbacks This patch introduces suspend and resume callbacks to mac802154. When doing suspend we calling the stop driver callback which should stop the receiving of frames. A transceiver should go into low-power mode then. Calling resume will call the start driver callback, which starts receiving again and allow to transmit frames. This was tested only with the fakelb driver and a qemu vm by doing the following commands: echo "devices" > /sys/power/pm_test echo "freeze" > /sys/power/state while doing some high traffic between two fakelb phys. Signed-off-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/cfg.c | 45 ++++++++++++++++++++++++++++++++++++ net/mac802154/ieee802154_i.h | 1 + net/mac802154/rx.c | 10 ++++++-- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/net/mac802154/cfg.c b/net/mac802154/cfg.c index 44db8613812e1..f7ba51e8b4caf 100644 --- a/net/mac802154/cfg.c +++ b/net/mac802154/cfg.c @@ -44,6 +44,49 @@ static void ieee802154_del_iface_deprecated(struct wpan_phy *wpan_phy, ieee802154_if_remove(sdata); } +#ifdef CONFIG_PM +static int ieee802154_suspend(struct wpan_phy *wpan_phy) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + + if (!local->open_count) + goto suspend; + + ieee802154_stop_queue(&local->hw); + synchronize_net(); + + /* stop hardware - this must stop RX */ + ieee802154_stop_device(local); + +suspend: + local->suspended = true; + return 0; +} + +static int ieee802154_resume(struct wpan_phy *wpan_phy) +{ + struct ieee802154_local *local = wpan_phy_priv(wpan_phy); + int ret; + + /* nothing to do if HW shouldn't run */ + if (!local->open_count) + goto wake_up; + + /* restart hardware */ + ret = drv_start(local); + if (ret) + return ret; + +wake_up: + ieee802154_wake_queue(&local->hw); + local->suspended = false; + return 0; +} +#else +#define ieee802154_suspend NULL +#define ieee802154_resume NULL +#endif + static int ieee802154_add_iface(struct wpan_phy *phy, const char *name, unsigned char name_assign_type, @@ -232,6 +275,8 @@ ieee802154_set_lbt_mode(struct wpan_phy *wpan_phy, struct wpan_dev *wpan_dev, const struct cfg802154_ops mac802154_config_ops = { .add_virtual_intf_deprecated = ieee802154_add_iface_deprecated, .del_virtual_intf_deprecated = ieee802154_del_iface_deprecated, + .suspend = ieee802154_suspend, + .resume = ieee802154_resume, .add_virtual_intf = ieee802154_add_iface, .del_virtual_intf = ieee802154_del_iface, .set_channel = ieee802154_set_channel, diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 04077830e88c0..0054f39d499b3 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -56,6 +56,7 @@ struct ieee802154_local { struct hrtimer ifs_timer; bool started; + bool suspended; struct tasklet_struct tasklet; struct sk_buff_head skb_queue; diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index d93ad2d4a4fc2..5a258c11ed3bc 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -253,6 +253,9 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) WARN_ON_ONCE(softirq_count() == 0); + if (local->suspended) + goto drop; + /* TODO: When a transceiver omits the checksum here, we * add an own calculated one. This is currently an ugly * solution because the monitor needs a crc here. @@ -273,8 +276,7 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) crc = crc_ccitt(0, skb->data, skb->len); if (crc) { rcu_read_unlock(); - kfree_skb(skb); - return; + goto drop; } } /* remove crc */ @@ -283,6 +285,10 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) __ieee802154_rx_handle_packet(local, skb); rcu_read_unlock(); + + return; +drop: + kfree_skb(skb); } EXPORT_SYMBOL(ieee802154_rx); -- GitLab From ca93cee5a56e5199622bea8bff24c0a96e70c8f1 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Wed, 1 Jul 2015 12:20:26 +0200 Subject: [PATCH 1547/7006] Bluetooth: hci_uart: Add basic support for Intel Lightning Peak devices The Intel Lightning Peak devices do not come with Bluetooth firmware loaded and thus require a full download of the operational Bluetooth firmware when the device is attached via the Bluetooth line discipline. Lightning Peak devices start with a bootloader mode that only accepts a very limited set of HCI commands. The supported commands are enough to identify the hardware and select the right firmware to load. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/hci_intel.c | 604 ++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 + drivers/bluetooth/hci_uart.h | 5 + 4 files changed, 616 insertions(+) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 2e777071e1dcb..79e8234b1aa59 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -132,6 +132,7 @@ config BT_HCIUART_3WIRE config BT_HCIUART_INTEL bool "Intel protocol support" depends on BT_HCIUART + select BT_HCIUART_H4 select BT_INTEL help The Intel protocol support enables Bluetooth HCI over serial diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 5dd07bf052360..ade19aaeb5c5e 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -24,8 +24,612 @@ #include #include #include +#include +#include #include #include #include "hci_uart.h" +#include "btintel.h" + +#define STATE_BOOTLOADER 0 +#define STATE_DOWNLOADING 1 +#define STATE_FIRMWARE_LOADED 2 +#define STATE_FIRMWARE_FAILED 3 +#define STATE_BOOTING 4 + +struct intel_data { + struct sk_buff *rx_skb; + struct sk_buff_head txq; + unsigned long flags; +}; + +static int intel_open(struct hci_uart *hu) +{ + struct intel_data *intel; + + BT_DBG("hu %p", hu); + + intel = kzalloc(sizeof(*intel), GFP_KERNEL); + if (!intel) + return -ENOMEM; + + skb_queue_head_init(&intel->txq); + + hu->priv = intel; + return 0; +} + +static int intel_close(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&intel->txq); + kfree_skb(intel->rx_skb); + kfree(intel); + + hu->priv = NULL; + return 0; +} + +static int intel_flush(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&intel->txq); + + return 0; +} + +static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) +{ + struct sk_buff *skb; + struct hci_event_hdr *hdr; + struct hci_ev_cmd_complete *evt; + + skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr)); + hdr->evt = HCI_EV_CMD_COMPLETE; + hdr->plen = sizeof(*evt) + 1; + + evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt)); + evt->ncmd = 0x01; + evt->opcode = cpu_to_le16(opcode); + + *skb_put(skb, 1) = 0x00; + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + + return hci_recv_frame(hdev, skb); +} + +static int intel_secure_send(struct hci_dev *hdev, u8 fragment_type, + u32 plen, const void *param) +{ + while (plen > 0) { + struct sk_buff *skb; + u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; + + cmd_param[0] = fragment_type; + memcpy(cmd_param + 1, param, fragment_len); + + skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, + cmd_param, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + plen -= fragment_len; + param += fragment_len; + } + + return 0; +} + +static void intel_version_info(struct hci_dev *hdev, + struct intel_version *ver) +{ + const char *variant; + + switch (ver->fw_variant) { + case 0x06: + variant = "Bootloader"; + break; + case 0x23: + variant = "Firmware"; + break; + default: + return; + } + + BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, + variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, + ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); +} + +static int intel_setup(struct hci_uart *hu) +{ + static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, + 0x00, 0x08, 0x04, 0x00 }; + struct intel_data *intel = hu->priv; + struct hci_dev *hdev = hu->hdev; + struct sk_buff *skb; + struct intel_version *ver; + struct intel_boot_params *params; + const struct firmware *fw; + const u8 *fw_ptr; + char fwname[64]; + u32 frag_len; + ktime_t calltime, delta, rettime; + unsigned long long duration; + int err; + + BT_DBG("%s", hdev->name); + + calltime = ktime_get(); + + set_bit(STATE_BOOTLOADER, &intel->flags); + + /* Read the Intel version information to determine if the device + * is in bootloader mode or if it already has operational firmware + * loaded. + */ + skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel version information failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: Intel version event size mismatch", hdev->name); + kfree_skb(skb); + return -EILSEQ; + } + + ver = (struct intel_version *)skb->data; + if (ver->status) { + BT_ERR("%s: Intel version command failure (%02x)", + hdev->name, ver->status); + err = -bt_to_errno(ver->status); + kfree_skb(skb); + return err; + } + + /* The hardware platform number has a fixed value of 0x37 and + * for now only accept this single value. + */ + if (ver->hw_platform != 0x37) { + BT_ERR("%s: Unsupported Intel hardware platform (%u)", + hdev->name, ver->hw_platform); + kfree_skb(skb); + return -EINVAL; + } + + /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is + * supported by this firmware loading method. This check has been + * put in place to ensure correct forward compatibility options + * when newer hardware variants come along. + */ + if (ver->hw_variant != 0x0b) { + BT_ERR("%s: Unsupported Intel hardware variant (%u)", + hdev->name, ver->hw_variant); + kfree_skb(skb); + return -EINVAL; + } + + intel_version_info(hdev, ver); + + /* The firmware variant determines if the device is in bootloader + * mode or is running operational firmware. The value 0x06 identifies + * the bootloader and the value 0x23 identifies the operational + * firmware. + * + * When the operational firmware is already present, then only + * the check for valid Bluetooth device address is needed. This + * determines if the device will be added as configured or + * unconfigured controller. + * + * It is not possible to use the Secure Boot Parameters in this + * case since that command is only available in bootloader mode. + */ + if (ver->fw_variant == 0x23) { + kfree_skb(skb); + clear_bit(STATE_BOOTLOADER, &intel->flags); + btintel_check_bdaddr(hdev); + return 0; + } + + /* If the device is not in bootloader mode, then the only possible + * choice is to return an error and abort the device initialization. + */ + if (ver->fw_variant != 0x06) { + BT_ERR("%s: Unsupported Intel firmware variant (%u)", + hdev->name, ver->fw_variant); + kfree_skb(skb); + return -ENODEV; + } + + kfree_skb(skb); + + /* Read the secure boot parameters to identify the operating + * details of the bootloader. + */ + skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel boot parameters failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + + if (skb->len != sizeof(*params)) { + BT_ERR("%s: Intel boot parameters size mismatch", hdev->name); + kfree_skb(skb); + return -EILSEQ; + } + + params = (struct intel_boot_params *)skb->data; + if (params->status) { + BT_ERR("%s: Intel boot parameters command failure (%02x)", + hdev->name, params->status); + err = -bt_to_errno(params->status); + kfree_skb(skb); + return err; + } + + BT_INFO("%s: Device revision is %u", hdev->name, + le16_to_cpu(params->dev_revid)); + + BT_INFO("%s: Secure boot is %s", hdev->name, + params->secure_boot ? "enabled" : "disabled"); + + BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name, + params->min_fw_build_nn, params->min_fw_build_cw, + 2000 + params->min_fw_build_yy); + + /* It is required that every single firmware fragment is acknowledged + * with a command complete event. If the boot parameters indicate + * that this bootloader does not send them, then abort the setup. + */ + if (params->limited_cce != 0x00) { + BT_ERR("%s: Unsupported Intel firmware loading method (%u)", + hdev->name, params->limited_cce); + kfree_skb(skb); + return -EINVAL; + } + + /* If the OTP has no valid Bluetooth device address, then there will + * also be no valid address for the operational firmware. + */ + if (!bacmp(¶ms->otp_bdaddr, BDADDR_ANY)) { + BT_INFO("%s: No device address configured", hdev->name); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + /* With this Intel bootloader only the hardware variant and device + * revision information are used to select the right firmware. + * + * Currently this bootloader support is limited to hardware variant + * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b). + */ + snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi", + le16_to_cpu(params->dev_revid)); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err < 0) { + BT_ERR("%s: Failed to load Intel firmware file (%d)", + hdev->name, err); + kfree_skb(skb); + return err; + } + + BT_INFO("%s: Found device firmware: %s", hdev->name, fwname); + + kfree_skb(skb); + + if (fw->size < 644) { + BT_ERR("%s: Invalid size of firmware file (%zu)", + hdev->name, fw->size); + err = -EBADF; + goto done; + } + + set_bit(STATE_DOWNLOADING, &intel->flags); + + /* Start the firmware download transaction with the Init fragment + * represented by the 128 bytes of CSS header. + */ + err = intel_secure_send(hdev, 0x00, 128, fw->data); + if (err < 0) { + BT_ERR("%s: Failed to send firmware header (%d)", + hdev->name, err); + goto done; + } + + /* Send the 256 bytes of public key information from the firmware + * as the PKey fragment. + */ + err = intel_secure_send(hdev, 0x03, 256, fw->data + 128); + if (err < 0) { + BT_ERR("%s: Failed to send firmware public key (%d)", + hdev->name, err); + goto done; + } + + /* Send the 256 bytes of signature information from the firmware + * as the Sign fragment. + */ + err = intel_secure_send(hdev, 0x02, 256, fw->data + 388); + if (err < 0) { + BT_ERR("%s: Failed to send firmware signature (%d)", + hdev->name, err); + goto done; + } + + fw_ptr = fw->data + 644; + frag_len = 0; + + while (fw_ptr - fw->data < fw->size) { + struct hci_command_hdr *cmd = (void *)(fw_ptr + frag_len); + + frag_len += sizeof(*cmd) + cmd->plen; + + BT_DBG("%s: patching %td/%zu", hdev->name, + (fw_ptr - fw->data), fw->size); + + /* The parameter length of the secure send command requires + * a 4 byte alignment. It happens so that the firmware file + * contains proper Intel_NOP commands to align the fragments + * as needed. + * + * Send set of commands with 4 byte alignment from the + * firmware data buffer as a single Data fragement. + */ + if (frag_len % 4) + continue; + + /* Send each command from the firmware data buffer as + * a single Data fragment. + */ + err = intel_secure_send(hdev, 0x01, frag_len, fw_ptr); + if (err < 0) { + BT_ERR("%s: Failed to send firmware data (%d)", + hdev->name, err); + goto done; + } + + fw_ptr += frag_len; + frag_len = 0; + } + + set_bit(STATE_FIRMWARE_LOADED, &intel->flags); + + BT_INFO("%s: Waiting for firmware download to complete", hdev->name); + + /* Before switching the device into operational mode and with that + * booting the loaded firmware, wait for the bootloader notification + * that all fragments have been successfully received. + * + * When the event processing receives the notification, then the + * STATE_DOWNLOADING flag will be cleared. + * + * The firmware loading should not take longer than 5 seconds + * and thus just timeout if that happens and fail the setup + * of this device. + */ + err = wait_on_bit_timeout(&intel->flags, STATE_DOWNLOADING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(5000)); + if (err == 1) { + BT_ERR("%s: Firmware loading interrupted", hdev->name); + err = -EINTR; + goto done; + } + + if (err) { + BT_ERR("%s: Firmware loading timeout", hdev->name); + err = -ETIMEDOUT; + goto done; + } + + if (test_bit(STATE_FIRMWARE_FAILED, &intel->flags)) { + BT_ERR("%s: Firmware loading failed", hdev->name); + err = -ENOEXEC; + goto done; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration); + +done: + release_firmware(fw); + + if (err < 0) + return err; + + calltime = ktime_get(); + + set_bit(STATE_BOOTING, &intel->flags); + + skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + /* The bootloader will not indicate when the device is ready. This + * is done by the operational firmware sending bootup notification. + * + * Booting into operational firmware should not take longer than + * 1 second. However if that happens, then just fail the setup + * since something went wrong. + */ + BT_INFO("%s: Waiting for device to boot", hdev->name); + + err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(1000)); + + if (err == 1) { + BT_ERR("%s: Device boot interrupted", hdev->name); + return -EINTR; + } + + if (err) { + BT_ERR("%s: Device boot timeout", hdev->name); + return -ETIMEDOUT; + } + + rettime = ktime_get(); + delta = ktime_sub(rettime, calltime); + duration = (unsigned long long) ktime_to_ns(delta) >> 10; + + BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration); + + clear_bit(STATE_BOOTLOADER, &intel->flags); + + return 0; +} + +static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) +{ + struct hci_uart *hu = hci_get_drvdata(hdev); + struct intel_data *intel = hu->priv; + struct hci_event_hdr *hdr; + + if (!test_bit(STATE_BOOTLOADER, &intel->flags)) + goto recv; + + hdr = (void *)skb->data; + + /* When the firmware loading completes the device sends + * out a vendor specific event indicating the result of + * the firmware loading. + */ + if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 && + skb->data[2] == 0x06) { + if (skb->data[3] != 0x00) + set_bit(STATE_FIRMWARE_FAILED, &intel->flags); + + if (test_and_clear_bit(STATE_DOWNLOADING, &intel->flags) && + test_bit(STATE_FIRMWARE_LOADED, &intel->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&intel->flags, STATE_DOWNLOADING); + } + + /* When switching to the operational firmware the device + * sends a vendor specific event indicating that the bootup + * completed. + */ + } else if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 && + skb->data[2] == 0x02) { + if (test_and_clear_bit(STATE_BOOTING, &intel->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&intel->flags, STATE_BOOTING); + } + } +recv: + return hci_recv_frame(hdev, skb); +} + +static const struct h4_recv_pkt intel_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = intel_recv_event }, +}; + +static int intel_recv(struct hci_uart *hu, const void *data, int count) +{ + struct intel_data *intel = hu->priv; + + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + + intel->rx_skb = h4_recv_buf(hu->hdev, intel->rx_skb, data, count, + intel_recv_pkts, + ARRAY_SIZE(intel_recv_pkts)); + if (IS_ERR(intel->rx_skb)) { + int err = PTR_ERR(intel->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + intel->rx_skb = NULL; + return err; + } + + return count; +} + +static int intel_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + struct intel_data *intel = hu->priv; + + BT_DBG("hu %p skb %p", hu, skb); + + skb_queue_tail(&intel->txq, skb); + + return 0; +} + +static struct sk_buff *intel_dequeue(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + struct sk_buff *skb; + + skb = skb_dequeue(&intel->txq); + if (!skb) + return skb; + + if (test_bit(STATE_BOOTLOADER, &intel->flags) && + (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT)) { + struct hci_command_hdr *cmd = (void *)skb->data; + __u16 opcode = le16_to_cpu(cmd->opcode); + + /* When the 0xfc01 command is issued to boot into + * the operational firmware, it will actually not + * send a command complete event. To keep the flow + * control working inject that event here. + */ + if (opcode == 0xfc01) + inject_cmd_complete(hu->hdev, opcode); + } + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); + + return skb; +} + +static const struct hci_uart_proto intel_proto = { + .id = HCI_UART_INTEL, + .name = "Intel", + .init_speed = 115200, + .open = intel_open, + .close = intel_close, + .flush = intel_flush, + .setup = intel_setup, + .recv = intel_recv, + .enqueue = intel_enqueue, + .dequeue = intel_dequeue, +}; + +int __init intel_init(void) +{ + return hci_uart_register_proto(&intel_proto); +} + +int __exit intel_deinit(void) +{ + return hci_uart_unregister_proto(&intel_proto); +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 177dd69fdd954..051f8213697da 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -804,6 +804,9 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_3WIRE h5_init(); #endif +#ifdef CONFIG_BT_HCIUART_INTEL + intel_init(); +#endif #ifdef CONFIG_BT_HCIUART_BCM bcm_init(); #endif @@ -830,6 +833,9 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_3WIRE h5_deinit(); #endif +#ifdef CONFIG_BT_HCIUART_INTEL + intel_deinit(); +#endif #ifdef CONFIG_BT_HCIUART_BCM bcm_deinit(); #endif diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index ce9c670956f54..496587a73a9da 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -167,6 +167,11 @@ int h5_init(void); int h5_deinit(void); #endif +#ifdef CONFIG_BT_HCIUART_INTEL +int intel_init(void); +int intel_deinit(void); +#endif + #ifdef CONFIG_BT_HCIUART_BCM int bcm_init(void); int bcm_deinit(void); -- GitLab From a03e33da5f1f10cc93bd5de140a131dac1db97f0 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Sun, 5 Jul 2015 09:49:27 +0000 Subject: [PATCH 1548/7006] Bluetooth: bfusb: Coding style fix reported by coccinelle Removed semicolon at the end of switch case statement Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bfusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index fcfb72e9e0ee5..a5c4d05843897 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -492,7 +492,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; - }; + } /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); -- GitLab From 20a7e25f4ee173785fded331d2af4b68b1ef5921 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Sun, 5 Jul 2015 09:56:36 +0000 Subject: [PATCH 1549/7006] Bluetooth: dtl1_cs: Fixed coding style Removed semicolon at end of switch statement,error reported by Coccinelle Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/dtl1_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 09c130d73ba35..84135c54ed2e4 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -406,7 +406,7 @@ static int dtl1_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) break; default: return -EILSEQ; - }; + } nsh.zero = 0; nsh.len = skb->len; -- GitLab From 973bb97e5aee56edddaae3d5c96877101ad509c0 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:37:38 +0200 Subject: [PATCH 1550/7006] Bluetooth: btintel: Add generic function for handling hardware errors The handling of hardware error has support for providing a vendor specific callback to deal with the error. Move the Intel specific function out of the USB driver into the generic module so that it can also be utilized by the UART driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 34 ++++++++++++++++++++++++++++++++++ drivers/bluetooth/btintel.h | 5 +++++ 2 files changed, 39 insertions(+) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 828f2f8d1568c..8b160858f7e8d 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -89,6 +89,40 @@ int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(btintel_set_bdaddr); +void btintel_hw_error(struct hci_dev *hdev, u8 code) +{ + struct sk_buff *skb; + u8 type = 0x00; + + BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); + + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reset after hardware error failed (%ld)", + hdev->name, PTR_ERR(skb)); + return; + } + kfree_skb(skb); + + skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Retrieving Intel exception info failed (%ld)", + hdev->name, PTR_ERR(skb)); + return; + } + + if (skb->len != 13) { + BT_ERR("%s: Exception info size mismatch", hdev->name); + kfree_skb(skb); + return; + } + + BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); + + kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(btintel_hw_error); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 4bda6ab34f602..c4680cd440114 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -73,6 +73,7 @@ struct intel_secure_send_result { int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +void btintel_hw_error(struct hci_dev *hdev, u8 code); #else @@ -86,4 +87,8 @@ static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdadd return -EOPNOTSUPP; } +static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) +{ +} + #endif -- GitLab From eeb6abe97390c579d9ed9da27bd98fbf07c641ed Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:37:39 +0200 Subject: [PATCH 1551/7006] Bluetooth: btusb: Use hardware error handler from Intel module The Intel specific Bluetooth module provides now an exported function for the hardware error. Use that instead of duplicating it inside the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 35 +---------------------------------- 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index b4cf8d9c9dac2..21bdb89da6ebf 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2291,39 +2291,6 @@ done: return 0; } -static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code) -{ - struct sk_buff *skb; - u8 type = 0x00; - - BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code); - - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: Reset after hardware error failed (%ld)", - hdev->name, PTR_ERR(skb)); - return; - } - kfree_skb(skb); - - skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s: Retrieving Intel exception info failed (%ld)", - hdev->name, PTR_ERR(skb)); - return; - } - - if (skb->len != 13) { - BT_ERR("%s: Exception info size mismatch", hdev->name); - kfree_skb(skb); - return; - } - - BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1)); - - kfree_skb(skb); -} - static int btusb_shutdown_intel(struct hci_dev *hdev) { struct sk_buff *skb; @@ -2783,7 +2750,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INTEL_NEW) { hdev->send = btusb_send_frame_intel; hdev->setup = btusb_setup_intel_new; - hdev->hw_error = btusb_hw_error_intel; + hdev->hw_error = btintel_hw_error; hdev->set_bdaddr = btintel_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } -- GitLab From 35ab8150ee9df8c8a47a57617d7ccbd74cb45bcf Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:37:40 +0200 Subject: [PATCH 1552/7006] Bluetooth: hci_uart: Add Intel address configuration support The Intel specific Bluetooth module provides support for pubic address configuration. So make sure that it is enabled for Intel UART devices. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_intel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index ade19aaeb5c5e..06398cc0d95cf 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -175,6 +175,8 @@ static int intel_setup(struct hci_uart *hu) BT_DBG("%s", hdev->name); + hu->hdev->set_bdaddr = btintel_set_bdaddr; + calltime = ktime_get(); set_bit(STATE_BOOTLOADER, &intel->flags); -- GitLab From 09df123d2d128c52987f11c85397cdbc9ffc89c6 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 14:55:36 +0200 Subject: [PATCH 1553/7006] Bluetooth: btintel: Create common Intel Secure Send function The Intel Secure Send command is used the same in USB and UART drivers and with that move a generic version into the Intel module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 25 +++++++++++++++++++++++++ drivers/bluetooth/btintel.h | 9 +++++++++ drivers/bluetooth/btusb.c | 33 ++++----------------------------- drivers/bluetooth/hci_intel.c | 32 ++++---------------------------- 4 files changed, 42 insertions(+), 57 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 8b160858f7e8d..d3b0fb55e340b 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -123,6 +123,31 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) } EXPORT_SYMBOL_GPL(btintel_hw_error); +int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, + const void *param) +{ + while (plen > 0) { + struct sk_buff *skb; + u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; + + cmd_param[0] = fragment_type; + memcpy(cmd_param + 1, param, fragment_len); + + skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, + cmd_param, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + kfree_skb(skb); + + plen -= fragment_len; + param += fragment_len; + } + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_secure_send); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index c4680cd440114..ec89e3cb645fb 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -75,6 +75,9 @@ int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); void btintel_hw_error(struct hci_dev *hdev, u8 code); +int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, + const void *param); + #else static inline int btintel_check_bdaddr(struct hci_dev *hdev) @@ -91,4 +94,10 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) { } +static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, + u32 plen, const void *param) +{ + return -EOPNOTSUPP; +} + #endif diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 21bdb89da6ebf..de7395fe938c7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1878,30 +1878,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) return -EILSEQ; } -static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type, - u32 plen, const void *param) -{ - while (plen > 0) { - struct sk_buff *skb; - u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; - - cmd_param[0] = fragment_type; - memcpy(cmd_param + 1, param, fragment_len); - - skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, - cmd_param, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); - - plen -= fragment_len; - param += fragment_len; - } - - return 0; -} - static void btusb_intel_version_info(struct hci_dev *hdev, struct intel_version *ver) { @@ -2104,7 +2080,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Start the firmware download transaction with the Init fragment * represented by the 128 bytes of CSS header. */ - err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data); + err = btintel_secure_send(hdev, 0x00, 128, fw->data); if (err < 0) { BT_ERR("%s: Failed to send firmware header (%d)", hdev->name, err); @@ -2114,7 +2090,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Send the 256 bytes of public key information from the firmware * as the PKey fragment. */ - err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128); + err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); if (err < 0) { BT_ERR("%s: Failed to send firmware public key (%d)", hdev->name, err); @@ -2124,7 +2100,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) /* Send the 256 bytes of signature information from the firmware * as the Sign fragment. */ - err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388); + err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); if (err < 0) { BT_ERR("%s: Failed to send firmware signature (%d)", hdev->name, err); @@ -2148,8 +2124,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) * firmware data buffer as a single Data fragement. */ if (!(frag_len % 4)) { - err = btusb_intel_secure_send(hdev, 0x01, frag_len, - fw_ptr); + err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); if (err < 0) { BT_ERR("%s: Failed to send firmware data (%d)", hdev->name, err); diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 06398cc0d95cf..bc66a9baf5329 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -111,30 +111,6 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) return hci_recv_frame(hdev, skb); } -static int intel_secure_send(struct hci_dev *hdev, u8 fragment_type, - u32 plen, const void *param) -{ - while (plen > 0) { - struct sk_buff *skb; - u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen; - - cmd_param[0] = fragment_type; - memcpy(cmd_param + 1, param, fragment_len); - - skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1, - cmd_param, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - kfree_skb(skb); - - plen -= fragment_len; - param += fragment_len; - } - - return 0; -} - static void intel_version_info(struct hci_dev *hdev, struct intel_version *ver) { @@ -350,7 +326,7 @@ static int intel_setup(struct hci_uart *hu) /* Start the firmware download transaction with the Init fragment * represented by the 128 bytes of CSS header. */ - err = intel_secure_send(hdev, 0x00, 128, fw->data); + err = btintel_secure_send(hdev, 0x00, 128, fw->data); if (err < 0) { BT_ERR("%s: Failed to send firmware header (%d)", hdev->name, err); @@ -360,7 +336,7 @@ static int intel_setup(struct hci_uart *hu) /* Send the 256 bytes of public key information from the firmware * as the PKey fragment. */ - err = intel_secure_send(hdev, 0x03, 256, fw->data + 128); + err = btintel_secure_send(hdev, 0x03, 256, fw->data + 128); if (err < 0) { BT_ERR("%s: Failed to send firmware public key (%d)", hdev->name, err); @@ -370,7 +346,7 @@ static int intel_setup(struct hci_uart *hu) /* Send the 256 bytes of signature information from the firmware * as the Sign fragment. */ - err = intel_secure_send(hdev, 0x02, 256, fw->data + 388); + err = btintel_secure_send(hdev, 0x02, 256, fw->data + 388); if (err < 0) { BT_ERR("%s: Failed to send firmware signature (%d)", hdev->name, err); @@ -402,7 +378,7 @@ static int intel_setup(struct hci_uart *hu) /* Send each command from the firmware data buffer as * a single Data fragment. */ - err = intel_secure_send(hdev, 0x01, frag_len, fw_ptr); + err = btintel_secure_send(hdev, 0x01, frag_len, fw_ptr); if (err < 0) { BT_ERR("%s: Failed to send firmware data (%d)", hdev->name, err); -- GitLab From 7feb99e1308204e4d849dada3443bc410ce5026b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Jul 2015 15:02:07 +0200 Subject: [PATCH 1554/7006] Bluetooth: btintel: Create common function for Intel version info The Intel version information is shared between USB and UART drivers and with that move it into a generic function of the Intel module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 21 +++++++++++++++++++++ drivers/bluetooth/btintel.h | 5 +++++ drivers/bluetooth/btusb.c | 23 +---------------------- drivers/bluetooth/hci_intel.c | 23 +---------------------- 4 files changed, 28 insertions(+), 44 deletions(-) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index d3b0fb55e340b..1ce4ac16c7fac 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -123,6 +123,27 @@ void btintel_hw_error(struct hci_dev *hdev, u8 code) } EXPORT_SYMBOL_GPL(btintel_hw_error); +void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) +{ + const char *variant; + + switch (ver->fw_variant) { + case 0x06: + variant = "Bootloader"; + break; + case 0x23: + variant = "Firmware"; + break; + default: + return; + } + + BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, + variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, + ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); +} +EXPORT_SYMBOL_GPL(btintel_version_info); + int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param) { diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index ec89e3cb645fb..b278d14758d59 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -75,6 +75,7 @@ int btintel_check_bdaddr(struct hci_dev *hdev); int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); void btintel_hw_error(struct hci_dev *hdev, u8 code); +void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver); int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param); @@ -94,6 +95,10 @@ static inline void btintel_hw_error(struct hci_dev *hdev, u8 code) { } +static void btintel_version_info(struct hci_dev *hdev, struct intel_version *ver) +{ +} + static inline int btintel_secure_send(struct hci_dev *hdev, u8 fragment_type, u32 plen, const void *param) { diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index de7395fe938c7..93339a4f25f1a 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1878,27 +1878,6 @@ static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb) return -EILSEQ; } -static void btusb_intel_version_info(struct hci_dev *hdev, - struct intel_version *ver) -{ - const char *variant; - - switch (ver->fw_variant) { - case 0x06: - variant = "Bootloader"; - break; - case 0x23: - variant = "Firmware"; - break; - default: - return; - } - - BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, - variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, - ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); -} - static int btusb_setup_intel_new(struct hci_dev *hdev) { static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, @@ -1960,7 +1939,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) return -EINVAL; } - btusb_intel_version_info(hdev, ver); + btintel_version_info(hdev, ver); /* The firmware variant determines if the device is in bootloader * mode or is running operational firmware. The value 0x06 identifies diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index bc66a9baf5329..21dfa89751dfe 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -111,27 +111,6 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) return hci_recv_frame(hdev, skb); } -static void intel_version_info(struct hci_dev *hdev, - struct intel_version *ver) -{ - const char *variant; - - switch (ver->fw_variant) { - case 0x06: - variant = "Bootloader"; - break; - case 0x23: - variant = "Firmware"; - break; - default: - return; - } - - BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name, - variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f, - ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy); -} - static int intel_setup(struct hci_uart *hu) { static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, @@ -205,7 +184,7 @@ static int intel_setup(struct hci_uart *hu) return -EINVAL; } - intel_version_info(hdev, ver); + btintel_version_info(hdev, ver); /* The firmware variant determines if the device is in bootloader * mode or is running operational firmware. The value 0x06 identifies -- GitLab From f104f06c1b0c93a7c087609e6ab0005e359afab9 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Mon, 6 Jul 2015 05:40:16 +0000 Subject: [PATCH 1555/7006] Bluetooth: bt3c_cs: Fix coding style Remove semicolon in switch statement, reported by coccinelle Signed-off-by: Prasanna Karthik Signed-off-by: Marcel Holtmann --- drivers/bluetooth/bt3c_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 7aab65427d388..a00bb82eb7c6d 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -427,7 +427,7 @@ static int bt3c_hci_send_frame(struct hci_dev *hdev, struct sk_buff *skb) case HCI_SCODATA_PKT: hdev->stat.sco_tx++; break; - }; + } /* Prepend skb with frame type */ memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); -- GitLab From 729a8989b3fa8ae7965c537dfccbd08512e84d3c Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 7 Jul 2015 10:50:42 +0530 Subject: [PATCH 1556/7006] mac802154: do not export ieee802154_rx() Right now there are no other users for ieee802154_rx() in kernel. So lets remove EXPORT_SYMBOL() for this. Also it moves the function prototype from global header file to local header file. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 17 ----------------- net/mac802154/ieee802154_i.h | 1 + net/mac802154/rx.c | 1 - 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/include/net/mac802154.h b/include/net/mac802154.h index f534a46911dc3..b7f99615224bd 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -320,23 +320,6 @@ int ieee802154_register_hw(struct ieee802154_hw *hw); */ void ieee802154_unregister_hw(struct ieee802154_hw *hw); -/** - * ieee802154_rx - receive frame - * - * Use this function to hand received frames to mac802154. The receive - * buffer in @skb must start with an IEEE 802.15.4 header. In case of a - * paged @skb is used, the driver is recommended to put the ieee802154 - * header of the frame on the linear part of the @skb to avoid memory - * allocation and/or memcpy by the stack. - * - * This function may not be called in IRQ context. Calls to this function - * for a single hardware must be synchronized against each other. - * - * @hw: the hardware this frame came in on - * @skb: the buffer to receive, owned by mac802154 after this call - */ -void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb); - /** * ieee802154_rx_irqsafe - receive frame * diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index 0054f39d499b3..eb8502a6e7198 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -124,6 +124,7 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) extern struct ieee802154_mlme_ops mac802154_mlme_wpan; +void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb); netdev_tx_t ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); netdev_tx_t diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index 5a258c11ed3bc..7791c9b8cb571 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -290,7 +290,6 @@ void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) drop: kfree_skb(skb); } -EXPORT_SYMBOL(ieee802154_rx); void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, u8 lqi) -- GitLab From d10270ce941ee89afd74076ea3ed8dbef8a0ff25 Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Tue, 7 Jul 2015 10:50:43 +0530 Subject: [PATCH 1557/7006] mac802154: fix ieee802154_rx handling Instead of passing ieee802154_hw pointer to ieee802154_rx, we can directly pass the ieee802154_local pointer. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/mac802154/ieee802154_i.h | 2 +- net/mac802154/main.c | 2 +- net/mac802154/rx.c | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/net/mac802154/ieee802154_i.h b/net/mac802154/ieee802154_i.h index eb8502a6e7198..6810d7a25aca0 100644 --- a/net/mac802154/ieee802154_i.h +++ b/net/mac802154/ieee802154_i.h @@ -124,7 +124,7 @@ ieee802154_sdata_running(struct ieee802154_sub_if_data *sdata) extern struct ieee802154_mlme_ops mac802154_mlme_wpan; -void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb); +void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb); netdev_tx_t ieee802154_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); netdev_tx_t diff --git a/net/mac802154/main.c b/net/mac802154/main.c index 4caf04b676d72..91f120845a455 100644 --- a/net/mac802154/main.c +++ b/net/mac802154/main.c @@ -40,7 +40,7 @@ static void ieee802154_tasklet_handler(unsigned long data) * netstack. */ skb->pkt_type = 0; - ieee802154_rx(&local->hw, skb); + ieee802154_rx(local, skb); break; default: WARN(1, "mac802154: Packet is of unknown type %d\n", diff --git a/net/mac802154/rx.c b/net/mac802154/rx.c index 7791c9b8cb571..d1c33c1d6b9b3 100644 --- a/net/mac802154/rx.c +++ b/net/mac802154/rx.c @@ -246,9 +246,8 @@ ieee802154_monitors_rx(struct ieee802154_local *local, struct sk_buff *skb) } } -void ieee802154_rx(struct ieee802154_hw *hw, struct sk_buff *skb) +void ieee802154_rx(struct ieee802154_local *local, struct sk_buff *skb) { - struct ieee802154_local *local = hw_to_local(hw); u16 crc; WARN_ON_ONCE(softirq_count() == 0); -- GitLab From 2baea85dec1aebe0b100d4836dee8bcf29a51e94 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Tue, 23 Jun 2015 17:59:32 +0100 Subject: [PATCH 1558/7006] Bluetooth: L2CAP ERTM shutdown protect sk and chan During execution of l2cap_sock_shutdown() which might sleep, the sk and chan structures can be in an unlocked condition which potentially allows the structures to be freed by other running threads. Therefore, there is a possibility of a malfunction or memory reuse after being freed. Keep the sk and chan structures alive during the execution of l2cap_sock_shutdown() by using their respective hold and put functions. This allows the structures to be freeable at the end of l2cap_sock_shutdown(). Signed-off-by: Kautuk Consul Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 244287706f910..3794c2386c211 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1098,7 +1098,12 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) if (!sk) return 0; + /* prevent sk structure from being freed whilst unlocked */ + sock_hold(sk); + chan = l2cap_pi(sk)->chan; + /* prevent chan structure from being freed whilst unlocked */ + l2cap_chan_hold(chan); conn = chan->conn; BT_DBG("chan %p state %s", chan, state_to_string(chan->state)); @@ -1134,6 +1139,9 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) if (conn) mutex_unlock(&conn->chan_lock); + l2cap_chan_put(chan); + sock_put(sk); + return err; } -- GitLab From f65468f6e26c3bd05e642e10e80a485b99b7de05 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Tue, 23 Jun 2015 17:59:33 +0100 Subject: [PATCH 1559/7006] Bluetooth: Make __l2cap_wait_ack more efficient Use chan->state instead of chan->conn because waiting for ACK's is only possible in the BT_CONNECTED state. Also avoids reference to the conn structure so makes locking easier. Only call __l2cap_wait_ack() when the needed condition of chan->unacked_frames > 0 && chan->state == BT_CONNECTED is true and convert the while loop to a do while loop. __l2cap_wait_ack() change the function prototype to pass in the chan variable as chan is already available in the calling function l2cap_sock_shutdown(). Avoids locking issues. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3794c2386c211..29042880c449d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1054,16 +1054,15 @@ static void l2cap_sock_kill(struct sock *sk) sock_put(sk); } -static int __l2cap_wait_ack(struct sock *sk) +static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; DECLARE_WAITQUEUE(wait, current); int err = 0; int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); set_current_state(TASK_INTERRUPTIBLE); - while (chan->unacked_frames > 0 && chan->conn) { + do { if (!timeo) timeo = HZ/5; @@ -1080,7 +1079,10 @@ static int __l2cap_wait_ack(struct sock *sk) err = sock_error(sk); if (err) break; - } + + } while (chan->unacked_frames > 0 && + chan->state == BT_CONNECTED); + set_current_state(TASK_RUNNING); remove_wait_queue(sk_sleep(sk), &wait); return err; @@ -1115,8 +1117,10 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { - if (chan->mode == L2CAP_MODE_ERTM) - err = __l2cap_wait_ack(sk); + if (chan->mode == L2CAP_MODE_ERTM && + chan->unacked_frames > 0 && + chan->state == BT_CONNECTED) + err = __l2cap_wait_ack(sk, chan); sk->sk_shutdown = SHUTDOWN_MASK; -- GitLab From 451e4c6c6b3fd1a9f446a10eb9f6d4c2c476043c Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Tue, 23 Jun 2015 17:59:37 +0100 Subject: [PATCH 1560/7006] Bluetooth: Add BT_DBG to l2cap_sock_shutdown() Add helpful BT_DBG debug to l2cap_sock_shutdown() and __l2cap_wait_ack() so that the code flow can be analysed. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann --- net/bluetooth/l2cap_sock.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 29042880c449d..d915e4a963131 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1063,6 +1063,8 @@ static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) add_wait_queue(sk_sleep(sk), &wait); set_current_state(TASK_INTERRUPTIBLE); do { + BT_DBG("Waiting for %d ACKs", chan->unacked_frames); + if (!timeo) timeo = HZ/5; @@ -1146,6 +1148,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) l2cap_chan_put(chan); sock_put(sk); + BT_DBG("err: %d", err); + return err; } -- GitLab From cb02a25583b59ce48267472cd092485d754964f9 Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Tue, 23 Jun 2015 17:59:38 +0100 Subject: [PATCH 1561/7006] Bluetooth: __l2cap_wait_ack() use msecs_to_jiffies() Use msecs_to_jiffies() instead of using HZ so that it is easier to specify the time in milliseconds. Also add a #define L2CAP_WAIT_ACK_POLL_PERIOD to specify the 200ms polling period so that it is defined in a single place. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 2239a37530922..3dcad4159b0b8 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -55,6 +55,7 @@ #define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000) #define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000) #define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000) +#define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200) #define L2CAP_A2MP_DEFAULT_MTU 670 diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d915e4a963131..f0b052a75e8aa 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1058,7 +1058,7 @@ static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) { DECLARE_WAITQUEUE(wait, current); int err = 0; - int timeo = HZ/5; + int timeo = L2CAP_WAIT_ACK_POLL_PERIOD; add_wait_queue(sk_sleep(sk), &wait); set_current_state(TASK_INTERRUPTIBLE); @@ -1066,7 +1066,7 @@ static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) BT_DBG("Waiting for %d ACKs", chan->unacked_frames); if (!timeo) - timeo = HZ/5; + timeo = L2CAP_WAIT_ACK_POLL_PERIOD; if (signal_pending(current)) { err = sock_intr_errno(timeo); -- GitLab From e432c72c464d2deb6c66d1e2a5f548dc1f0ef4dc Mon Sep 17 00:00:00 2001 From: Dean Jenkins Date: Tue, 23 Jun 2015 17:59:39 +0100 Subject: [PATCH 1562/7006] Bluetooth: __l2cap_wait_ack() add defensive timeout Add a timeout to prevent the do while loop running in an infinite loop. This ensures that the channel will be instructed to close within 10 seconds so prevents l2cap_sock_shutdown() getting stuck forever. Returns -ENOLINK when the timeout is reached. The channel will be subequently closed and not all data will be ACK'ed. Signed-off-by: Dean Jenkins Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_sock.c | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3dcad4159b0b8..c98afc08cc261 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -56,6 +56,7 @@ #define L2CAP_MOVE_TIMEOUT msecs_to_jiffies(4000) #define L2CAP_MOVE_ERTX_TIMEOUT msecs_to_jiffies(60000) #define L2CAP_WAIT_ACK_POLL_PERIOD msecs_to_jiffies(200) +#define L2CAP_WAIT_ACK_TIMEOUT msecs_to_jiffies(10000) #define L2CAP_A2MP_DEFAULT_MTU 670 diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f0b052a75e8aa..586b3d580cfcb 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1059,11 +1059,15 @@ static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) DECLARE_WAITQUEUE(wait, current); int err = 0; int timeo = L2CAP_WAIT_ACK_POLL_PERIOD; + /* Timeout to prevent infinite loop */ + unsigned long timeout = jiffies + L2CAP_WAIT_ACK_TIMEOUT; add_wait_queue(sk_sleep(sk), &wait); set_current_state(TASK_INTERRUPTIBLE); do { - BT_DBG("Waiting for %d ACKs", chan->unacked_frames); + BT_DBG("Waiting for %d ACKs, timeout %04d ms", + chan->unacked_frames, time_after(jiffies, timeout) ? 0 : + jiffies_to_msecs(timeout - jiffies)); if (!timeo) timeo = L2CAP_WAIT_ACK_POLL_PERIOD; @@ -1082,6 +1086,11 @@ static int __l2cap_wait_ack(struct sock *sk, struct l2cap_chan *chan) if (err) break; + if (time_after(jiffies, timeout)) { + err = -ENOLINK; + break; + } + } while (chan->unacked_frames > 0 && chan->state == BT_CONNECTED); -- GitLab From fc586c41117117baf22d1088dad3a771e51e35f7 Mon Sep 17 00:00:00 2001 From: Antonio Borneo Date: Tue, 23 Jun 2015 22:52:52 +0800 Subject: [PATCH 1563/7006] net: ieee802154: Remove redundant spi driver bus initialization In ancient times it was necessary to manually initialize the bus field of an spi_driver to spi_bus_type. These days this is done in spi_register_driver(), so we can drop the manual assignment. Signed-off-by: Antonio Borneo Acked-by: Varka Bhadram Acked-by: Alan Ott Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/cc2520.c | 1 - drivers/net/ieee802154/mrf24j40.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c index b6fc295796679..613dae559925f 100644 --- a/drivers/net/ieee802154/cc2520.c +++ b/drivers/net/ieee802154/cc2520.c @@ -1151,7 +1151,6 @@ MODULE_DEVICE_TABLE(of, cc2520_of_ids); static struct spi_driver cc2520_driver = { .driver = { .name = "cc2520", - .bus = &spi_bus_type, .owner = THIS_MODULE, .of_match_table = of_match_ptr(cc2520_of_ids), }, diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c index 2549760e039fd..997724b8e4343 100644 --- a/drivers/net/ieee802154/mrf24j40.c +++ b/drivers/net/ieee802154/mrf24j40.c @@ -812,7 +812,6 @@ MODULE_DEVICE_TABLE(spi, mrf24j40_ids); static struct spi_driver mrf24j40_driver = { .driver = { .name = "mrf24j40", - .bus = &spi_bus_type, .owner = THIS_MODULE, }, .id_table = mrf24j40_ids, -- GitLab From 8757825b128e71319150219b0745d3ecb87f34aa Mon Sep 17 00:00:00 2001 From: Seungyoun Ju Date: Mon, 13 Jul 2015 17:28:13 +0900 Subject: [PATCH 1564/7006] Bluetooth: hci_check_conn_params() check proper range Slave latency range has been changed in Core Spec. 4.2 by Erratum 5419 of ESR08_V1.0.0. And it should be applied to Core Spec. 4.0 and 4.1. Before: connSlaveLatency <= ((connSupervisionTimeout / connIntervalMax) - 1) After: connSlaveLatency <= ((connSupervisionTimeout / (connIntervalMax*2)) - 1) This patch makes hci_check_conn_params() check the allowable slave latency range using the changed way. Signed-off-by: Seungyoun Ju Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3bd618d3e55dc..2a6b0919e23f7 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1297,7 +1297,7 @@ static inline int hci_check_conn_params(u16 min, u16 max, u16 latency, if (max >= to_multiplier * 8) return -EINVAL; - max_latency = (to_multiplier * 8 / max) - 1; + max_latency = (to_multiplier * 4 / max) - 1; if (latency > 499 || latency > max_latency) return -EINVAL; -- GitLab From 9a0a8a8e852dabeda848baafac19627cb469d5e9 Mon Sep 17 00:00:00 2001 From: Jakub Pawlowski Date: Mon, 20 Jul 2015 13:12:49 +0200 Subject: [PATCH 1565/7006] Bluetooth: Move IRK checking logic in preparation to new connect method Move IRK checking logic in preparation to new connect method. Also make sure that MGMT_STATUS_INVALID_PARAMS is returned when non identity address is passed to ADD_DEVICE. Right now MGMT_STATUS_FAILED is returned, which might be misleading. Signed-off-by: Jakub Pawlowski Signed-off-by: Johan Hedberg --- net/bluetooth/hci_core.c | 11 ----------- net/bluetooth/mgmt.c | 23 +++++++++++++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2f8fb33067e1c..bc43b6490555c 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -2822,10 +2822,6 @@ struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev, { struct hci_conn_params *params; - /* The conn params list only contains identity addresses */ - if (!hci_is_identity_address(addr, addr_type)) - return NULL; - list_for_each_entry(params, &hdev->le_conn_params, list) { if (bacmp(¶ms->addr, addr) == 0 && params->addr_type == addr_type) { @@ -2842,10 +2838,6 @@ struct hci_conn_params *hci_pend_le_action_lookup(struct list_head *list, { struct hci_conn_params *param; - /* The list only contains identity addresses */ - if (!hci_is_identity_address(addr, addr_type)) - return NULL; - list_for_each_entry(param, list, action) { if (bacmp(¶m->addr, addr) == 0 && param->addr_type == addr_type) @@ -2861,9 +2853,6 @@ struct hci_conn_params *hci_conn_params_add(struct hci_dev *hdev, { struct hci_conn_params *params; - if (!hci_is_identity_address(addr, addr_type)) - return NULL; - params = hci_conn_params_lookup(hdev, addr, addr_type); if (params) return params; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 7998fb2791656..7ab191589541c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6226,6 +6226,17 @@ static int add_device(struct sock *sk, struct hci_dev *hdev, else auto_conn = HCI_AUTO_CONN_REPORT; + /* Kernel internally uses conn_params with resolvable private + * address, but Add Device allows only identity addresses. + * Make sure it is enforced before calling + * hci_conn_params_lookup. + */ + if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) { + err = cmd->cmd_complete(cmd, MGMT_STATUS_INVALID_PARAMS); + mgmt_pending_remove(cmd); + goto unlock; + } + /* If the connection parameters don't exist for this device, * they will be created and configured with defaults. */ @@ -6340,6 +6351,18 @@ static int remove_device(struct sock *sk, struct hci_dev *hdev, else addr_type = ADDR_LE_DEV_RANDOM; + /* Kernel internally uses conn_params with resolvable private + * address, but Remove Device allows only identity addresses. + * Make sure it is enforced before calling + * hci_conn_params_lookup. + */ + if (!hci_is_identity_address(&cp->addr.bdaddr, addr_type)) { + err = cmd->cmd_complete(cmd, + MGMT_STATUS_INVALID_PARAMS); + mgmt_pending_remove(cmd); + goto unlock; + } + params = hci_conn_params_lookup(hdev, &cp->addr.bdaddr, addr_type); if (!params) { -- GitLab From f285f1610341af4181791938777e0affb5531278 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:32:04 +0800 Subject: [PATCH 1566/7006] ASoC: rt5677: Remove NULL test for desc before gpiod_set_value_cansleep call It's safe to call gpiod_set_value_cansleep() with NULL desc. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 13b871f110230..62230e05eac1a 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -4763,10 +4763,8 @@ static int rt5677_remove(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec); - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); return 0; } @@ -4780,10 +4778,8 @@ static int rt5677_suspend(struct snd_soc_codec *codec) regcache_cache_only(rt5677->regmap, true); regcache_mark_dirty(rt5677->regmap); - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 0); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 0); + gpiod_set_value_cansleep(rt5677->reset_pin, 0); } return 0; @@ -4794,10 +4790,8 @@ static int rt5677_resume(struct snd_soc_codec *codec) struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec); if (!rt5677->dsp_vad_en) { - if (rt5677->pow_ldo2) - gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); - if (rt5677->reset_pin) - gpiod_set_value_cansleep(rt5677->reset_pin, 1); + gpiod_set_value_cansleep(rt5677->pow_ldo2, 1); + gpiod_set_value_cansleep(rt5677->reset_pin, 1); if (rt5677->pow_ldo2 || rt5677->reset_pin) msleep(10); -- GitLab From 95f1044f5674b53f67e0933abff228c594792f4c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 22:56:04 +0800 Subject: [PATCH 1567/7006] ASoC: tas2552: Fix off-by-one for max_register setting The latest valid register is TAS2552_VBAT_DATA. Signed-off-by: Axel Lin Acked-by: Dan Murphy Signed-off-by: Mark Brown --- sound/soc/codecs/tas2552.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/tas2552.h b/sound/soc/codecs/tas2552.h index 5746f8fd0afd5..e34752b8a2994 100644 --- a/sound/soc/codecs/tas2552.h +++ b/sound/soc/codecs/tas2552.h @@ -42,7 +42,7 @@ #define TAS2552_BOOST_APT_CTRL 0x14 #define TAS2552_VER_NUM 0x16 #define TAS2552_VBAT_DATA 0x19 -#define TAS2552_MAX_REG 0x20 +#define TAS2552_MAX_REG TAS2552_VBAT_DATA /* CFG1 Register Masks */ #define TAS2552_DEV_RESET (1 << 0) -- GitLab From 9425e9d8c77dd9f40c5f199127a63be2e2b7c1f4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:13:36 +0800 Subject: [PATCH 1568/7006] ASoC: tas5086: Improve the logic for de-emphasis sampling rate selection Slightly improve the logic for de-emphasis sampling rate selection by break out the loop if the rate is matched. Signed-off-by: Axel Lin Acked-by: Daniel Mack Signed-off-by: Mark Brown --- sound/soc/codecs/tas5086.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/sound/soc/codecs/tas5086.c b/sound/soc/codecs/tas5086.c index 32942bed34b1e..16a6c6443aa83 100644 --- a/sound/soc/codecs/tas5086.c +++ b/sound/soc/codecs/tas5086.c @@ -266,10 +266,14 @@ static int tas5086_set_deemph(struct snd_soc_codec *codec) struct tas5086_private *priv = snd_soc_codec_get_drvdata(codec); int i, val = 0; - if (priv->deemph) - for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) - if (tas5086_deemph[i] == priv->rate) + if (priv->deemph) { + for (i = 0; i < ARRAY_SIZE(tas5086_deemph); i++) { + if (tas5086_deemph[i] == priv->rate) { val = i; + break; + } + } + } return regmap_update_bits(priv->regmap, TAS5086_SYS_CONTROL_1, TAS5086_DEEMPH_MASK, val); -- GitLab From 70bef01c0f1c9a55b54b625be3f82ff7ee1e8c05 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 26 May 2015 13:39:43 +0100 Subject: [PATCH 1569/7006] clocksource: sti: Provide support for the ST LPC Clocksource IP This IP is shared with Watchdog and RTC functionality. All 3 of these devices are mutually exclusive from one another i.e. Only 1 IP can be used at any given time. We use the device-driver model combined with a DT 'mode' property to enforce this. The ST LPC Clocksource IP can be used as the system (tick) timer. Acked-by: Daniel Lezcano Signed-off-by: Lee Jones --- drivers/clocksource/Kconfig | 8 ++ drivers/clocksource/Makefile | 1 + drivers/clocksource/clksrc_st_lpc.c | 123 ++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+) create mode 100644 drivers/clocksource/clksrc_st_lpc.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4e57730e0be4e..ae3ec9da0d153 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -293,4 +293,12 @@ config CLKSRC_IMX_GPT depends on ARM && CLKDEV_LOOKUP select CLKSRC_MMIO +config CLKSRC_ST_LPC + bool + depends on ARCH_STI + select CLKSRC_OF if OF + help + Enable this option to use the Low Power controller timer + as clocksource. + endmenu diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index f228354961ca6..1c2c9d2cd8599 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o obj-$(CONFIG_H8300) += h8300_timer8.o obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o obj-$(CONFIG_H8300_TPU) += h8300_tpu.o +obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c new file mode 100644 index 0000000000000..f38cf33281a20 --- /dev/null +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -0,0 +1,123 @@ +/* + * Clocksource using the Low Power Timer found in the Low Power Controller (LPC) + * + * Copyright (C) 2015 STMicroelectronics – All Rights Reserved + * + * Author(s): Francesco Virlinzi + * Ajit Pal Singh + * + * 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 +#include +#include +#include +#include + +#include + +/* Low Power Timer */ +#define LPC_LPT_LSB_OFF 0x400 +#define LPC_LPT_MSB_OFF 0x404 +#define LPC_LPT_START_OFF 0x408 + +static struct st_clksrc_ddata { + struct clk *clk; + void __iomem *base; +} ddata; + +static void __init st_clksrc_reset(void) +{ + writel_relaxed(0, ddata.base + LPC_LPT_START_OFF); + writel_relaxed(0, ddata.base + LPC_LPT_MSB_OFF); + writel_relaxed(0, ddata.base + LPC_LPT_LSB_OFF); + writel_relaxed(1, ddata.base + LPC_LPT_START_OFF); +} + +static int __init st_clksrc_init(void) +{ + unsigned long rate; + int ret; + + st_clksrc_reset(); + + rate = clk_get_rate(ddata.clk); + + ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF, + "clksrc-st-lpc", rate, 300, 32, + clocksource_mmio_readl_up); + if (ret) { + pr_err("clksrc-st-lpc: Failed to register clocksource\n"); + return ret; + } + + return 0; +} + +static int __init st_clksrc_setup_clk(struct device_node *np) +{ + struct clk *clk; + + clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + pr_err("clksrc-st-lpc: Failed to get LPC clock\n"); + return PTR_ERR(clk); + } + + if (clk_prepare_enable(clk)) { + pr_err("clksrc-st-lpc: Failed to enable LPC clock\n"); + return -EINVAL; + } + + if (!clk_get_rate(clk)) { + pr_err("clksrc-st-lpc: Failed to get LPC clock rate\n"); + clk_disable_unprepare(clk); + return -EINVAL; + } + + ddata.clk = clk; + + return 0; +} + +static void __init st_clksrc_of_register(struct device_node *np) +{ + int ret; + uint32_t mode; + + ret = of_property_read_u32(np, "st,lpc-mode", &mode); + if (ret) { + pr_err("clksrc-st-lpc: An LPC mode must be provided\n"); + return; + } + + /* LPC can either run as a Clocksource or in RTC or WDT mode */ + if (mode != ST_LPC_MODE_CLKSRC) + return; + + ddata.base = of_iomap(np, 0); + if (!ddata.base) { + pr_err("clksrc-st-lpc: Unable to map iomem\n"); + return; + } + + if (st_clksrc_setup_clk(np)) { + iounmap(ddata.base); + return; + } + + if (st_clksrc_init()) { + clk_disable_unprepare(ddata.clk); + clk_put(ddata.clk); + iounmap(ddata.base); + return; + } + + pr_info("clksrc-st-lpc: clocksource initialised - running @ %luHz\n", + clk_get_rate(ddata.clk)); +} +CLOCKSOURCE_OF_DECLARE(ddata, "st,stih407-lpc", st_clksrc_of_register); -- GitLab From ff45d8dd84dbb6e674e3757a07ef9471568c2e94 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:11 +0100 Subject: [PATCH 1570/7006] clocksource: sti: Provide 'use timer as sched clock' capability Acked-by: Daniel Lezcano Signed-off-by: Lee Jones --- drivers/clocksource/clksrc_st_lpc.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/clocksource/clksrc_st_lpc.c b/drivers/clocksource/clksrc_st_lpc.c index f38cf33281a20..65ec4674416d0 100644 --- a/drivers/clocksource/clksrc_st_lpc.c +++ b/drivers/clocksource/clksrc_st_lpc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -38,6 +39,11 @@ static void __init st_clksrc_reset(void) writel_relaxed(1, ddata.base + LPC_LPT_START_OFF); } +static u64 notrace st_clksrc_sched_clock_read(void) +{ + return (u64)readl_relaxed(ddata.base + LPC_LPT_LSB_OFF); +} + static int __init st_clksrc_init(void) { unsigned long rate; @@ -47,6 +53,8 @@ static int __init st_clksrc_init(void) rate = clk_get_rate(ddata.clk); + sched_clock_register(st_clksrc_sched_clock_read, 32, rate); + ret = clocksource_mmio_init(ddata.base + LPC_LPT_LSB_OFF, "clksrc-st-lpc", rate, 300, 32, clocksource_mmio_readl_up); -- GitLab From bea6356c12600b683de55a70e6a4c6cc36fa640f Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:12 +0100 Subject: [PATCH 1571/7006] clocksource: bindings: Provide bindings for ST's LPC Clocksource device On current ST platforms the LPC controls a number of functions including Watchdog and Real Time Clock. This patch provides the bindings used to configure LPC in Clocksource mode. Signed-off-by: Lee Jones --- .../devicetree/bindings/timer/st,stih407-lpc | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/st,stih407-lpc diff --git a/Documentation/devicetree/bindings/timer/st,stih407-lpc b/Documentation/devicetree/bindings/timer/st,stih407-lpc new file mode 100644 index 0000000000000..72acb487b856d --- /dev/null +++ b/Documentation/devicetree/bindings/timer/st,stih407-lpc @@ -0,0 +1,28 @@ +STMicroelectronics Low Power Controller (LPC) - Clocksource +=========================================================== + +LPC currently supports Watchdog OR Real Time Clock OR Clocksource +functionality. + +[See: ../watchdog/st_lpc_wdt.txt for Watchdog options] +[See: ../rtc/rtc-st-lpc.txt for RTC options] + +Required properties + +- compatible : Must be: "st,stih407-lpc" +- reg : LPC registers base address + size +- interrupts : LPC interrupt line number and associated flags +- clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) +- st,lpc-mode : The LPC can run either one of three modes: + ST_LPC_MODE_RTC [0] + ST_LPC_MODE_WDT [1] + ST_LPC_MODE_CLKSRC [2] + One (and only one) mode must be selected. + +Example: + lpc@fde05000 { + compatible = "st,stih407-lpc"; + reg = <0xfde05000 0x1000>; + clocks = <&clk_s_d3_flexgen CLK_LPC_0>; + st,lpc-mode = ; + }; -- GitLab From 82c32c0326dc758bdf202c82cb05594ba0dd0d2e Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:14 +0100 Subject: [PATCH 1572/7006] watchdog: bindings: Supply knowledge of a third supported device - clocksource Signed-off-by: Lee Jones --- .../devicetree/bindings/watchdog/st_lpc_wdt.txt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt index 388c88a012224..039c5ca45577c 100644 --- a/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/st_lpc_wdt.txt @@ -1,9 +1,11 @@ STMicroelectronics Low Power Controller (LPC) - Watchdog ======================================================== -LPC currently supports Watchdog OR Real Time Clock functionality. +LPC currently supports Watchdog OR Real Time Clock OR Clocksource +functionality. [See: ../rtc/rtc-st-lpc.txt for RTC options] +[See: ../timer/st,stih407-lpc for Clocksource options] Required properties @@ -12,9 +14,11 @@ Required properties - reg : LPC registers base address + size - interrupts : LPC interrupt line number and associated flags - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) -- st,lpc-mode : The LPC can run either one of two modes ST_LPC_MODE_RTC [0] or - ST_LPC_MODE_WDT [1]. One (and only one) mode must be - selected. +- st,lpc-mode : The LPC can run either one of three modes: + ST_LPC_MODE_RTC [0] + ST_LPC_MODE_WDT [1] + ST_LPC_MODE_CLKSRC [2] + One (and only one) mode must be selected. Required properties [watchdog mode] -- GitLab From 742e40978ff79cc92ba982a27a55b957226f9dbe Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:15 +0100 Subject: [PATCH 1573/7006] rtc: st: Update IP layout information to include Clocksource Initial submission adding support for this IP only included Watchdog and the Real-Time Clock. Now the third (and final) device is enabled this trivial patch is required to update the comment in the RTC driver to encompass Clocksource. Acked-by: Alexandre Belloni Signed-off-by: Lee Jones --- drivers/rtc/rtc-st-lpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-st-lpc.c b/drivers/rtc/rtc-st-lpc.c index 3f9d0acb81c7a..74c0a336ceea0 100644 --- a/drivers/rtc/rtc-st-lpc.c +++ b/drivers/rtc/rtc-st-lpc.c @@ -208,7 +208,7 @@ static int st_rtc_probe(struct platform_device *pdev) return -EINVAL; } - /* LPC can either run in RTC or WDT mode */ + /* LPC can either run as a Clocksource or in RTC or WDT mode */ if (mode != ST_LPC_MODE_RTC) return -ENODEV; -- GitLab From c74a06dce5f82ea4e94a552d486293667c905267 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:16 +0100 Subject: [PATCH 1574/7006] rtc: bindings: Supply knowledge of a third supported device - clocksource Signed-off-by: Lee Jones --- .../devicetree/bindings/rtc/rtc-st-lpc.txt | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt b/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt index 73407f502e4e9..daf88265df323 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-st-lpc.txt @@ -1,20 +1,23 @@ STMicroelectronics Low Power Controller (LPC) - RTC =================================================== -LPC currently supports Watchdog OR Real Time Clock functionality. +LPC currently supports Watchdog OR Real Time Clock OR Clocksource +functionality. [See: ../watchdog/st_lpc_wdt.txt for Watchdog options] +[See: ../timer/st,stih407-lpc for Clocksource options] Required properties -- compatible : Must be one of: "st,stih407-lpc" "st,stih416-lpc" - "st,stih415-lpc" "st,stid127-lpc" +- compatible : Must be: "st,stih407-lpc" - reg : LPC registers base address + size - interrupts : LPC interrupt line number and associated flags - clocks : Clock used by LPC device (See: ../clock/clock-bindings.txt) -- st,lpc-mode : The LPC can run either one of two modes ST_LPC_MODE_RTC [0] or - ST_LPC_MODE_WDT [1]. One (and only one) mode must be - selected. +- st,lpc-mode : The LPC can run either one of three modes: + ST_LPC_MODE_RTC [0] + ST_LPC_MODE_WDT [1] + ST_LPC_MODE_CLKSRC [2] + One (and only one) mode must be selected. Example: lpc@fde05000 { -- GitLab From 82805d1b3ee0d93d08fe8957f253642a6f778f9a Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 12 May 2015 13:58:17 +0100 Subject: [PATCH 1575/7006] MAINTAINERS: Add the LPC Clocksource to STi maintained driver list Signed-off-by: Lee Jones --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index fd60784430838..64cf79158390b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1503,6 +1503,7 @@ S: Maintained F: arch/arm/mach-sti/ F: arch/arm/boot/dts/sti* F: drivers/clocksource/arm_global_timer.c +F: drivers/clocksource/clksrc_st_lpc.c F: drivers/i2c/busses/i2c-st.c F: drivers/media/rc/st_rc.c F: drivers/mmc/host/sdhci-st.c -- GitLab From 5f1d980ee9b6353f18765bfa6774a5a08d6cb944 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:00 +0200 Subject: [PATCH 1576/7006] ALSA: ac97: Add helper function to reset the AC97 device There is currently a lot of code duplication in ASoC drivers regarding the reset handling of devices. This patch introduces a new generic reset function in the generic AC'97 framework that can be used to replace most the custom reset functions. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/ac97_codec.h | 2 ++ sound/ac97_bus.c | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h index 0e9d75b49bede..74bc85473b58c 100644 --- a/include/sound/ac97_codec.h +++ b/include/sound/ac97_codec.h @@ -584,6 +584,8 @@ static inline int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, void snd_ac97_suspend(struct snd_ac97 *ac97); void snd_ac97_resume(struct snd_ac97 *ac97); #endif +int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id, + unsigned int id_mask); /* quirk types */ enum { diff --git a/sound/ac97_bus.c b/sound/ac97_bus.c index 2b50cbe6aca90..55791a0b3943c 100644 --- a/sound/ac97_bus.c +++ b/sound/ac97_bus.c @@ -17,6 +17,68 @@ #include #include +/* + * snd_ac97_check_id() - Reads and checks the vendor ID of the device + * @ac97: The AC97 device to check + * @id: The ID to compare to + * @id_mask: Mask that is applied to the device ID before comparing to @id + * + * If @id is 0 this function returns true if the read device vendor ID is + * a valid ID. If @id is non 0 this functions returns true if @id + * matches the read vendor ID. Otherwise the function returns false. + */ +static bool snd_ac97_check_id(struct snd_ac97 *ac97, unsigned int id, + unsigned int id_mask) +{ + ac97->id = ac97->bus->ops->read(ac97, AC97_VENDOR_ID1) << 16; + ac97->id |= ac97->bus->ops->read(ac97, AC97_VENDOR_ID2); + + if (ac97->id == 0x0 || ac97->id == 0xffffffff) + return false; + + if (id != 0 && id != (ac97->id & id_mask)) + return false; + + return true; +} + +/** + * snd_ac97_reset() - Reset AC'97 device + * @ac97: The AC'97 device to reset + * @try_warm: Try a warm reset first + * @id: Expected device vendor ID + * @id_mask: Mask that is applied to the device ID before comparing to @id + * + * This function resets the AC'97 device. If @try_warm is true the function + * first performs a warm reset. If the warm reset is successful the function + * returns 1. Otherwise or if @try_warm is false the function issues cold reset + * followed by a warm reset. If this is successful the function returns 0, + * otherwise a negative error code. If @id is 0 any valid device ID will be + * accepted, otherwise only the ID that matches @id and @id_mask is accepted. + */ +int snd_ac97_reset(struct snd_ac97 *ac97, bool try_warm, unsigned int id, + unsigned int id_mask) +{ + struct snd_ac97_bus_ops *ops = ac97->bus->ops; + + if (try_warm && ops->warm_reset) { + ops->warm_reset(ac97); + if (snd_ac97_check_id(ac97, id, id_mask)) + return 1; + } + + if (ops->reset) + ops->reset(ac97); + if (ops->warm_reset) + ops->warm_reset(ac97); + + if (snd_ac97_check_id(ac97, id, id_mask)) + return 0; + + return -ENODEV; +} +EXPORT_SYMBOL_GPL(snd_ac97_reset); + /* * Let drivers decide whether they want to support given codec from their * probe method. Drivers have direct access to the struct snd_ac97 -- GitLab From 7361fbeaeaab5282bbfc88f1f6fe4cf034f7623c Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:01 +0200 Subject: [PATCH 1577/7006] ASoC: ac97: Add support for resetting device before registration AC97 devices need to be initially reset before they can be used. Currently each driver does this on its own. Add support for resetting the device to core in snd_soc_new_ac97_codec(). If the caller supplies a device ID and device ID mask the function will reset the device and verify that it has the correct ID, if it does not a error is returned. This will allow to remove custom code with similar functionality from individual drivers. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- include/sound/soc.h | 3 ++- sound/soc/codecs/ad1980.c | 2 +- sound/soc/codecs/stac9766.c | 2 +- sound/soc/soc-ac97.c | 30 +++++++++++++++++++++++++----- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf9d54a9..42d144a4b7ba7 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -526,7 +526,8 @@ int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg, #ifdef CONFIG_SND_SOC_AC97_BUS struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec); -struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec); +struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec, + unsigned int id, unsigned int id_mask); void snd_soc_free_ac97_codec(struct snd_ac97 *ac97); int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops); diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index 3cc69a626454f..d9cb81dd64b55 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -240,7 +240,7 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) u16 vendor_id2; u16 ext_status; - ac97 = snd_soc_new_ac97_codec(codec); + ac97 = snd_soc_new_ac97_codec(codec, 0, 0); if (IS_ERR(ac97)) { ret = PTR_ERR(ac97); dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index ed4cca7f67799..c6028300c0ac4 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -332,7 +332,7 @@ static int stac9766_codec_probe(struct snd_soc_codec *codec) struct snd_ac97 *ac97; int ret = 0; - ac97 = snd_soc_new_ac97_codec(codec); + ac97 = snd_soc_new_ac97_codec(codec, 0, 0); if (IS_ERR(ac97)) return PTR_ERR(ac97); diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c index 08d7259bbaaba..d40efc9fe0a9b 100644 --- a/sound/soc/soc-ac97.c +++ b/sound/soc/soc-ac97.c @@ -85,10 +85,19 @@ EXPORT_SYMBOL(snd_soc_alloc_ac97_codec); /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec + * @id: The expected device ID + * @id_mask: Mask that is applied to the device ID before comparing with @id * * Initialises AC97 codec resources for use by ad-hoc devices only. + * + * If @id is not 0 this function will reset the device, then read the ID from + * the device and check if it matches the expected ID. If it doesn't match an + * error will be returned and device will not be registered. + * + * Returns: A PTR_ERR() on failure or a valid snd_ac97 struct on success. */ -struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) +struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec, + unsigned int id, unsigned int id_mask) { struct snd_ac97 *ac97; int ret; @@ -97,13 +106,24 @@ struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec) if (IS_ERR(ac97)) return ac97; - ret = device_add(&ac97->dev); - if (ret) { - put_device(&ac97->dev); - return ERR_PTR(ret); + if (id) { + ret = snd_ac97_reset(ac97, false, id, id_mask); + if (ret < 0) { + dev_err(codec->dev, "Failed to reset AC97 device: %d\n", + ret); + goto err_put_device; + } } + ret = device_add(&ac97->dev); + if (ret) + goto err_put_device; + return ac97; + +err_put_device: + put_device(&ac97->dev); + return ERR_PTR(ret); } EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); -- GitLab From 3ab3dbdfb91b70ef6bf4eb9b544bf54ff1dff51a Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:02 +0200 Subject: [PATCH 1578/7006] ASoC: ad1980: Use core AC'97 reset helper Use the new snd_ac97_reset() helper function to perform the reset and verify the device ID. Unfortunately the reset can't be done in snd_soc_new_ac97_codec() due to the special requirements in order to support the non-standard 16-bit slot mode of the ad1980. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/ad1980.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c index d9cb81dd64b55..9ef20dbccbe31 100644 --- a/sound/soc/codecs/ad1980.c +++ b/sound/soc/codecs/ad1980.c @@ -202,19 +202,21 @@ static struct snd_soc_dai_driver ad1980_dai = { .formats = SND_SOC_STD_AC97_FMTS, }, }; +#define AD1980_VENDOR_ID 0x41445300 +#define AD1980_VENDOR_MASK 0xffffff00 + static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); unsigned int retry_cnt = 0; + int ret; do { - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(ac97); - if (snd_soc_read(codec, AC97_RESET) == 0x0090) - return 1; - } + ret = snd_ac97_reset(ac97, true, AD1980_VENDOR_ID, + AD1980_VENDOR_MASK); + if (ret >= 0) + return 0; - soc_ac97_ops->reset(ac97); /* * Set bit 16slot in register 74h, then every slot will has only * 16 bits. This command is sent out in 20bit mode, in which @@ -223,8 +225,6 @@ static int ad1980_reset(struct snd_soc_codec *codec, int try_warm) */ snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900); - if (snd_soc_read(codec, AC97_RESET) == 0x0090) - return 0; } while (retry_cnt++ < 10); dev_err(codec->dev, "Failed to reset: AC97 link error\n"); @@ -260,22 +260,10 @@ static int ad1980_soc_probe(struct snd_soc_codec *codec) if (ret < 0) goto reset_err; - /* Read out vendor ID to make sure it is ad1980 */ - if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) { - ret = -ENODEV; - goto reset_err; - } - vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2); - - if (vendor_id2 != 0x5370) { - if (vendor_id2 != 0x5374) { - ret = -ENODEV; - goto reset_err; - } else { - dev_warn(codec->dev, - "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); - } + if (vendor_id2 == 0x5374) { + dev_warn(codec->dev, + "Found AD1981 - only 2/2 IN/OUT Channels supported\n"); } /* unmute captures and playbacks volume */ -- GitLab From 017e800af9f91861dcd6e4fd8a29418de86fd884 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:03 +0200 Subject: [PATCH 1579/7006] ASoC: stac9766: Use core reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/stac9766.c | 57 +++++-------------------------------- 1 file changed, 7 insertions(+), 50 deletions(-) diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c index c6028300c0ac4..0945c51df003d 100644 --- a/sound/soc/codecs/stac9766.c +++ b/sound/soc/codecs/stac9766.c @@ -28,6 +28,9 @@ #include "stac9766.h" +#define STAC9766_VENDOR_ID 0x83847666 +#define STAC9766_VENDOR_ID_MASK 0xffffffff + /* * STAC9766 register cache */ @@ -239,45 +242,12 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int stac9766_reset(struct snd_soc_codec *codec, int try_warm) -{ - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(ac97); - if (stac9766_ac97_read(codec, 0) == stac9766_reg[0]) - return 1; - } - - soc_ac97_ops->reset(ac97); - if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(ac97); - if (stac9766_ac97_read(codec, 0) != stac9766_reg[0]) - return -EIO; - return 0; -} - static int stac9766_codec_resume(struct snd_soc_codec *codec) { struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - u16 id, reset; - reset = 0; - /* give the codec an AC97 warm reset to start the link */ -reset: - if (reset > 5) { - dev_err(codec->dev, "Failed to resume\n"); - return -EIO; - } - ac97->bus->ops->warm_reset(ac97); - id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2); - if (id != 0x4c13) { - stac9766_reset(codec, 0); - reset++; - goto reset; - } - - return 0; + return snd_ac97_reset(ac97, true, STAC9766_VENDOR_ID, + STAC9766_VENDOR_ID_MASK); } static const struct snd_soc_dai_ops stac9766_dai_ops_analog = { @@ -330,28 +300,15 @@ static struct snd_soc_dai_driver stac9766_dai[] = { static int stac9766_codec_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; - int ret = 0; - ac97 = snd_soc_new_ac97_codec(codec, 0, 0); + ac97 = snd_soc_new_ac97_codec(codec, STAC9766_VENDOR_ID, + STAC9766_VENDOR_ID_MASK); if (IS_ERR(ac97)) return PTR_ERR(ac97); snd_soc_codec_set_drvdata(codec, ac97); - /* do a cold reset for the controller and then try - * a warm reset followed by an optional cold reset for codec */ - stac9766_reset(codec, 0); - ret = stac9766_reset(codec, 1); - if (ret < 0) { - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - goto codec_err; - } - return 0; - -codec_err: - snd_soc_free_ac97_codec(ac97); - return ret; } static int stac9766_codec_remove(struct snd_soc_codec *codec) -- GitLab From 6e0b73a0a172f4d881092e388b3a3ad57ca80107 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:04 +0200 Subject: [PATCH 1580/7006] ASoC: wm9705: Use core AC'97 reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/wm9705.c | 40 ++++++++------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c index 5cc457ef8894f..744842c76a60c 100644 --- a/sound/soc/codecs/wm9705.c +++ b/sound/soc/codecs/wm9705.c @@ -22,6 +22,9 @@ #include "wm9705.h" +#define WM9705_VENDOR_ID 0x574d4c05 +#define WM9705_VENDOR_ID_MASK 0xffffffff + /* * WM9705 register cache */ @@ -293,21 +296,6 @@ static struct snd_soc_dai_driver wm9705_dai[] = { } }; -static int wm9705_reset(struct snd_soc_codec *codec) -{ - struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec); - - if (soc_ac97_ops->reset) { - soc_ac97_ops->reset(ac97); - if (ac97_read(codec, 0) == wm9705_reg[0]) - return 0; /* Success */ - } - - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - - return -EIO; -} - #ifdef CONFIG_PM static int wm9705_soc_suspend(struct snd_soc_codec *codec) { @@ -324,7 +312,8 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) int i, ret; u16 *cache = codec->reg_cache; - ret = wm9705_reset(codec); + ret = snd_ac97_reset(ac97, true, WM9705_VENDOR_ID, + WM9705_VENDOR_ID_MASK); if (ret < 0) return ret; @@ -342,30 +331,17 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec) static int wm9705_soc_probe(struct snd_soc_codec *codec) { struct snd_ac97 *ac97; - int ret = 0; - ac97 = snd_soc_alloc_ac97_codec(codec); + ac97 = snd_soc_new_ac97_codec(codec, WM9705_VENDOR_ID, + WM9705_VENDOR_ID_MASK); if (IS_ERR(ac97)) { - ret = PTR_ERR(ac97); dev_err(codec->dev, "Failed to register AC97 codec\n"); - return ret; + return PTR_ERR(ac97); } - ret = wm9705_reset(codec); - if (ret) - goto err_put_device; - - ret = device_add(&ac97->dev); - if (ret) - goto err_put_device; - snd_soc_codec_set_drvdata(codec, ac97); return 0; - -err_put_device: - put_device(&ac97->dev); - return ret; } static int wm9705_soc_remove(struct snd_soc_codec *codec) -- GitLab From a575be4cbb951244f93342487c2537f729f2239d Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:05 +0200 Subject: [PATCH 1581/7006] ASoC: wm9712: Use core AC'97 reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/wm9712.c | 45 +++++++-------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c index 1fda104dfc455..488a92224249f 100644 --- a/sound/soc/codecs/wm9712.c +++ b/sound/soc/codecs/wm9712.c @@ -23,6 +23,9 @@ #include #include "wm9712.h" +#define WM9712_VENDOR_ID 0x574d4c12 +#define WM9712_VENDOR_ID_MASK 0xffffffff + struct wm9712_priv { struct snd_ac97 *ac97; unsigned int hp_mixer[2]; @@ -613,35 +616,14 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int wm9712_reset(struct snd_soc_codec *codec, int try_warm) -{ - struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(wm9712->ac97); - if (ac97_read(codec, 0) == wm9712_reg[0]) - return 1; - } - - soc_ac97_ops->reset(wm9712->ac97); - if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(wm9712->ac97); - if (ac97_read(codec, 0) != wm9712_reg[0]) - goto err; - return 0; - -err: - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - return -EIO; -} - static int wm9712_soc_resume(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); int i, ret; u16 *cache = codec->reg_cache; - ret = wm9712_reset(codec, 1); + ret = snd_ac97_reset(wm9712->ac97, true, WM9712_VENDOR_ID, + WM9712_VENDOR_ID_MASK); if (ret < 0) return ret; @@ -663,31 +645,20 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec) static int wm9712_soc_probe(struct snd_soc_codec *codec) { struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec); - int ret = 0; + int ret; - wm9712->ac97 = snd_soc_alloc_ac97_codec(codec); + wm9712->ac97 = snd_soc_new_ac97_codec(codec, WM9712_VENDOR_ID, + WM9712_VENDOR_ID_MASK); if (IS_ERR(wm9712->ac97)) { ret = PTR_ERR(wm9712->ac97); dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret); return ret; } - ret = wm9712_reset(codec, 0); - if (ret < 0) - goto err_put_device; - - ret = device_add(&wm9712->ac97->dev); - if (ret) - goto err_put_device; - /* set alc mux to none */ ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000); return 0; - -err_put_device: - put_device(&wm9712->ac97->dev); - return ret; } static int wm9712_soc_remove(struct snd_soc_codec *codec) -- GitLab From 310398f5e4618e9a0f6fd0c4b152401daf06c215 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 21 Jul 2015 21:53:06 +0200 Subject: [PATCH 1582/7006] ASoC: wm9713: Use core AC'97 reset helper Use the new snd_ac97_reset() helper and the reset functionality provided by snd_soc_new_ac97_codec() to perform the device reset rather than open-coding it. Signed-off-by: Lars-Peter Clausen Reviewed-by: Takashi Iwai Signed-off-by: Mark Brown --- sound/soc/codecs/wm9713.c | 48 +++++++-------------------------------- sound/soc/codecs/wm9713.h | 2 -- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index 89cd2d6f57c01..955e6511af56b 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -29,6 +29,9 @@ #include "wm9713.h" +#define WM9713_VENDOR_ID 0x574d4c13 +#define WM9713_VENDOR_ID_MASK 0xffffffff + struct wm9713_priv { struct snd_ac97 *ac97; u32 pll_in; /* PLL input frequency */ @@ -1123,28 +1126,6 @@ static struct snd_soc_dai_driver wm9713_dai[] = { }, }; -int wm9713_reset(struct snd_soc_codec *codec, int try_warm) -{ - struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - - if (try_warm && soc_ac97_ops->warm_reset) { - soc_ac97_ops->warm_reset(wm9713->ac97); - if (ac97_read(codec, 0) == wm9713_reg[0]) - return 1; - } - - soc_ac97_ops->reset(wm9713->ac97); - if (soc_ac97_ops->warm_reset) - soc_ac97_ops->warm_reset(wm9713->ac97); - if (ac97_read(codec, 0) != wm9713_reg[0]) { - dev_err(codec->dev, "Failed to reset: AC97 link error\n"); - return -EIO; - } - - return 0; -} -EXPORT_SYMBOL_GPL(wm9713_reset); - static int wm9713_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { @@ -1196,7 +1177,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) int i, ret; u16 *cache = codec->reg_cache; - ret = wm9713_reset(codec, 1); + ret = snd_ac97_reset(wm9713->ac97, true, WM9713_VENDOR_ID, + WM9713_VENDOR_ID_MASK); if (ret < 0) return ret; @@ -1222,32 +1204,18 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec) static int wm9713_soc_probe(struct snd_soc_codec *codec) { struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec); - int ret = 0, reg; + int reg; - wm9713->ac97 = snd_soc_alloc_ac97_codec(codec); + wm9713->ac97 = snd_soc_new_ac97_codec(codec, WM9713_VENDOR_ID, + WM9713_VENDOR_ID_MASK); if (IS_ERR(wm9713->ac97)) return PTR_ERR(wm9713->ac97); - /* do a cold reset for the controller and then try - * a warm reset followed by an optional cold reset for codec */ - wm9713_reset(codec, 0); - ret = wm9713_reset(codec, 1); - if (ret < 0) - goto err_put_device; - - ret = device_add(&wm9713->ac97->dev); - if (ret) - goto err_put_device; - /* unmute the adc - move to kcontrol */ reg = ac97_read(codec, AC97_CD) & 0x7fff; ac97_write(codec, AC97_CD, reg); return 0; - -err_put_device: - put_device(&wm9713->ac97->dev); - return ret; } static int wm9713_soc_remove(struct snd_soc_codec *codec) diff --git a/sound/soc/codecs/wm9713.h b/sound/soc/codecs/wm9713.h index 793da863a03d9..53df11b1f727f 100644 --- a/sound/soc/codecs/wm9713.h +++ b/sound/soc/codecs/wm9713.h @@ -45,6 +45,4 @@ #define WM9713_DAI_AC97_AUX 1 #define WM9713_DAI_PCM_VOICE 2 -int wm9713_reset(struct snd_soc_codec *codec, int try_warm); - #endif -- GitLab From 473eb87adcf69204cd7e8fb5b0e4956edd6feae3 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 21 Jul 2015 23:53:55 +0530 Subject: [PATCH 1583/7006] ASoC: Intel: Skylake: Add NHLT support to get BE config The Non-HD Audio Endpoint Description table contains the link configuration information for the DSP. This is specific to Non HDA links only, like I2s and PDM Skylake driver will use NHLT table to retrieve the configuration based on the link type, format, channel and rate. This configuration is passed to DSP FW Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/Makefile | 2 +- sound/soc/intel/skylake/skl-nhlt.c | 141 +++++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-nhlt.h | 116 ++++++++++++++++++++++++ sound/soc/intel/skylake/skl.h | 7 ++ 4 files changed, 265 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-nhlt.c create mode 100644 sound/soc/intel/skylake/skl-nhlt.h diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index 1fccb378e62ce..b35faef05779c 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,4 +1,4 @@ -snd-soc-skl-objs := skl.o skl-pcm.o +snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o diff --git a/sound/soc/intel/skylake/skl-nhlt.c b/sound/soc/intel/skylake/skl-nhlt.c new file mode 100644 index 0000000000000..5c0895eaa10aa --- /dev/null +++ b/sound/soc/intel/skylake/skl-nhlt.c @@ -0,0 +1,141 @@ +/* + * skl-nhlt.c - Intel SKL Platform NHLT parsing + * + * Copyright (C) 2015 Intel Corp + * Author: Sanjiv Kumar + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +#include +#include "skl.h" + +/* Unique identification for getting NHLT blobs */ +static u8 OSC_UUID[16] = {0x6E, 0x88, 0x9F, 0xA6, 0xEB, 0x6C, 0x94, 0x45, + 0xA4, 0x1F, 0x7B, 0x5D, 0xCE, 0x24, 0xC5, 0x53}; + +#define DSDT_NHLT_PATH "\\_SB.PCI0.HDAS" + +void __iomem *skl_nhlt_init(struct device *dev) +{ + acpi_handle handle; + union acpi_object *obj; + struct nhlt_resource_desc *nhlt_ptr = NULL; + + if (ACPI_FAILURE(acpi_get_handle(NULL, DSDT_NHLT_PATH, &handle))) { + dev_err(dev, "Requested NHLT device not found\n"); + return NULL; + } + + obj = acpi_evaluate_dsm(handle, OSC_UUID, 1, 1, NULL); + if (obj && obj->type == ACPI_TYPE_BUFFER) { + nhlt_ptr = (struct nhlt_resource_desc *)obj->buffer.pointer; + + return ioremap_cache(nhlt_ptr->min_addr, nhlt_ptr->length); + } + + dev_err(dev, "device specific method to extract NHLT blob failed\n"); + return NULL; +} + +void skl_nhlt_free(void __iomem *addr) +{ + iounmap(addr); + addr = NULL; +} + +static struct nhlt_specific_cfg *skl_get_specific_cfg( + struct device *dev, struct nhlt_fmt *fmt, + u8 no_ch, u8 rate, u16 bps) +{ + struct nhlt_specific_cfg *sp_config; + struct wav_fmt *wfmt; + struct nhlt_fmt_cfg *fmt_config = fmt->fmt_config; + int i; + + dev_dbg(dev, "Format count =%d\n", fmt->fmt_count); + + for (i = 0; i < fmt->fmt_count; i++) { + wfmt = &fmt_config->fmt_ext.fmt; + dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", wfmt->channels, + wfmt->bits_per_sample, wfmt->samples_per_sec); + if (wfmt->channels == no_ch && wfmt->samples_per_sec == rate && + wfmt->bits_per_sample == bps) { + sp_config = &fmt_config->config; + + return sp_config; + } + + fmt_config = (struct nhlt_fmt_cfg *)(fmt_config->config.caps + + fmt_config->config.size); + } + + return NULL; +} + +static void dump_config(struct device *dev, u32 instance_id, u8 linktype, + u8 s_fmt, u8 num_channels, u32 s_rate, u8 dirn, u16 bps) +{ + dev_dbg(dev, "Input configuration\n"); + dev_dbg(dev, "ch=%d fmt=%d s_rate=%d\n", num_channels, s_fmt, s_rate); + dev_dbg(dev, "vbus_id=%d link_type=%d\n", instance_id, linktype); + dev_dbg(dev, "bits_per_sample=%d\n", bps); +} + +static bool skl_check_ep_match(struct device *dev, struct nhlt_endpoint *epnt, + u32 instance_id, u8 link_type, u8 dirn) +{ + dev_dbg(dev, "vbus_id=%d link_type=%d dir=%d\n", + epnt->virtual_bus_id, epnt->linktype, epnt->direction); + + if ((epnt->virtual_bus_id == instance_id) && + (epnt->linktype == link_type) && + (epnt->direction == dirn)) + return true; + else + return false; +} + +struct nhlt_specific_cfg +*skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, + u8 s_fmt, u8 num_ch, u32 s_rate, u8 dirn) +{ + struct nhlt_fmt *fmt; + struct nhlt_endpoint *epnt; + struct hdac_bus *bus = ebus_to_hbus(&skl->ebus); + struct device *dev = bus->dev; + struct nhlt_specific_cfg *sp_config; + struct nhlt_acpi_table *nhlt = (struct nhlt_acpi_table *)skl->nhlt; + u16 bps = num_ch * s_fmt; + u8 j; + + dump_config(dev, instance, link_type, s_fmt, num_ch, s_rate, dirn, bps); + + epnt = (struct nhlt_endpoint *)nhlt->desc; + + dev_dbg(dev, "endpoint count =%d\n", nhlt->endpoint_count); + + for (j = 0; j < nhlt->endpoint_count; j++) { + if (skl_check_ep_match(dev, epnt, instance, link_type, dirn)) { + fmt = (struct nhlt_fmt *)(epnt->config.caps + + epnt->config.size); + sp_config = skl_get_specific_cfg(dev, fmt, num_ch, s_rate, bps); + if (sp_config) + return sp_config; + } + + epnt = (struct nhlt_endpoint *)((u8 *)epnt + epnt->length); + } + + return NULL; +} diff --git a/sound/soc/intel/skylake/skl-nhlt.h b/sound/soc/intel/skylake/skl-nhlt.h new file mode 100644 index 0000000000000..b0e2e4da42a1e --- /dev/null +++ b/sound/soc/intel/skylake/skl-nhlt.h @@ -0,0 +1,116 @@ +/* + * skl-nhlt.h - Intel HDA Platform NHLT header + * + * Copyright (C) 2015 Intel Corp + * Author: Sanjiv Kumar + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * 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; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + */ +#ifndef __SKL_NHLT_H__ +#define __SKL_NHLT_H__ + +struct acpi_desc_header { + u32 signature; + u32 length; + u8 revision; + u8 checksum; + u8 oem_id[6]; + u64 oem_table_id; + u32 oem_revision; + u32 creator_id; + u32 creator_revision; +} __packed; + +struct wav_fmt { + u16 fmt_tag; + u16 channels; + u32 samples_per_sec; + u32 avg_bytes_per_sec; + u16 block_align; + u16 bits_per_sample; + u16 cb_size; +} __packed; + +struct wav_fmt_ext { + struct wav_fmt fmt; + union samples { + u16 valid_bits_per_sample; + u16 samples_per_block; + u16 reserved; + } sample; + u32 channel_mask; + u8 sub_fmt[16]; +} __packed; + +enum nhlt_link_type { + NHLT_LINK_HDA = 0, + NHLT_LINK_DSP = 1, + NHLT_LINK_DMIC = 2, + NHLT_LINK_SSP = 3, + NHLT_LINK_INVALID +}; + +enum nhlt_device_type { + NHLT_DEVICE_BT = 0, + NHLT_DEVICE_DMIC = 1, + NHLT_DEVICE_I2S = 4, + NHLT_DEVICE_INVALID +}; + +struct nhlt_specific_cfg { + u32 size; + u8 caps[0]; +} __packed; + +struct nhlt_fmt_cfg { + struct wav_fmt_ext fmt_ext; + struct nhlt_specific_cfg config; +} __packed; + +struct nhlt_fmt { + u8 fmt_count; + struct nhlt_fmt_cfg fmt_config[0]; +} __packed; + +struct nhlt_endpoint { + u32 length; + u8 linktype; + u8 instance_id; + u16 vendor_id; + u16 device_id; + u16 revision_id; + u32 subsystem_id; + u8 device_type; + u8 direction; + u8 virtual_bus_id; + struct nhlt_specific_cfg config; +} __packed; + +struct nhlt_acpi_table { + struct acpi_desc_header header; + u8 endpoint_count; + struct nhlt_endpoint desc[0]; +} __packed; + +struct nhlt_resource_desc { + u32 extra; + u16 flags; + u64 addr_spc_gra; + u64 min_addr; + u64 max_addr; + u64 addr_trans_offset; + u64 length; +} __packed; + +#endif diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index cc0f3e263495f..31dafa8a05942 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -23,6 +23,7 @@ #include #include +#include "skl-nhlt.h" #define SKL_SUSPEND_DELAY 2000 @@ -53,6 +54,8 @@ struct skl { unsigned int init_failed:1; /* delayed init failed */ struct platform_device *dmic_dev; + + void __iomem *nhlt; /* nhlt ptr */ }; #define skl_to_ebus(s) (&(s)->ebus) @@ -68,4 +71,8 @@ struct skl_dma_params { int skl_platform_unregister(struct device *dev); int skl_platform_register(struct device *dev); +void __iomem *skl_nhlt_init(struct device *dev); +void skl_nhlt_free(void __iomem *addr); +struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, + u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); #endif /* __SOUND_SOC_SKL_H */ -- GitLab From d255b09555e8ea0e517a4d3368ec60097ac9cf96 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Tue, 21 Jul 2015 23:53:56 +0530 Subject: [PATCH 1584/7006] ASoC: Intel: Skylake: Add dsp and ipc init helpers This helper function will be used by the Skylake driver for dsp and ipc initialization if processing pipe capability is supported. Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Mark Brown --- sound/soc/intel/skylake/Makefile | 2 +- sound/soc/intel/skylake/skl-messages.c | 133 +++++++++++++++++++++++++ sound/soc/intel/skylake/skl.h | 6 ++ 3 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 sound/soc/intel/skylake/skl-messages.c diff --git a/sound/soc/intel/skylake/Makefile b/sound/soc/intel/skylake/Makefile index b35faef05779c..27db22178204b 100644 --- a/sound/soc/intel/skylake/Makefile +++ b/sound/soc/intel/skylake/Makefile @@ -1,4 +1,4 @@ -snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o +snd-soc-skl-objs := skl.o skl-pcm.o skl-nhlt.o skl-messages.o obj-$(CONFIG_SND_SOC_INTEL_SKYLAKE) += snd-soc-skl.o diff --git a/sound/soc/intel/skylake/skl-messages.c b/sound/soc/intel/skylake/skl-messages.c new file mode 100644 index 0000000000000..7c07b76bf0bf1 --- /dev/null +++ b/sound/soc/intel/skylake/skl-messages.c @@ -0,0 +1,133 @@ +/* + * skl-message.c - HDA DSP interface for FW registration, Pipe and Module + * configurations + * + * Copyright (C) 2015 Intel Corp + * Author:Rafal Redzimski + * Jeeja KP + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include "skl-sst-dsp.h" +#include "skl-sst-ipc.h" +#include "skl.h" +#include "../common/sst-dsp.h" +#include "../common/sst-dsp-priv.h" + +static int skl_alloc_dma_buf(struct device *dev, + struct snd_dma_buffer *dmab, size_t size) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + if (!bus) + return -ENODEV; + + return bus->io_ops->dma_alloc_pages(bus, SNDRV_DMA_TYPE_DEV, size, dmab); +} + +static int skl_free_dma_buf(struct device *dev, struct snd_dma_buffer *dmab) +{ + struct hdac_ext_bus *ebus = dev_get_drvdata(dev); + struct hdac_bus *bus = ebus_to_hbus(ebus); + + if (!bus) + return -ENODEV; + + bus->io_ops->dma_free_pages(bus, dmab); + + return 0; +} + +int skl_init_dsp(struct skl *skl) +{ + void __iomem *mmio_base; + struct hdac_ext_bus *ebus = &skl->ebus; + struct hdac_bus *bus = ebus_to_hbus(ebus); + int irq = bus->irq; + struct skl_dsp_loader_ops loader_ops; + int ret; + + loader_ops.alloc_dma_buf = skl_alloc_dma_buf; + loader_ops.free_dma_buf = skl_free_dma_buf; + + /* enable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); + + /* read the BAR of the ADSP MMIO */ + mmio_base = pci_ioremap_bar(skl->pci, 4); + if (mmio_base == NULL) { + dev_err(bus->dev, "ioremap error\n"); + return -ENXIO; + } + + ret = skl_sst_dsp_init(bus->dev, mmio_base, irq, + loader_ops, &skl->skl_sst); + + dev_dbg(bus->dev, "dsp registration status=%d\n", ret); + + return ret; +} + +void skl_free_dsp(struct skl *skl) +{ + struct hdac_ext_bus *ebus = &skl->ebus; + struct hdac_bus *bus = ebus_to_hbus(ebus); + struct skl_sst *ctx = skl->skl_sst; + + /* disable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); + + skl_sst_dsp_cleanup(bus->dev, ctx); + if (ctx->dsp->addr.lpe) + iounmap(ctx->dsp->addr.lpe); +} + +int skl_suspend_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + int ret; + + /* if ppcap is not supported return 0 */ + if (!skl->ebus.ppcap) + return 0; + + ret = skl_dsp_sleep(ctx->dsp); + if (ret < 0) + return ret; + + /* disable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, false); + snd_hdac_ext_bus_ppcap_enable(&skl->ebus, false); + + return 0; +} + +int skl_resume_dsp(struct skl *skl) +{ + struct skl_sst *ctx = skl->skl_sst; + + /* if ppcap is not supported return 0 */ + if (!skl->ebus.ppcap) + return 0; + + /* enable ppcap interrupt */ + snd_hdac_ext_bus_ppcap_enable(&skl->ebus, true); + snd_hdac_ext_bus_ppcap_int_enable(&skl->ebus, true); + + return skl_dsp_wake(ctx->dsp); +} diff --git a/sound/soc/intel/skylake/skl.h b/sound/soc/intel/skylake/skl.h index 31dafa8a05942..f7fdbb02947f7 100644 --- a/sound/soc/intel/skylake/skl.h +++ b/sound/soc/intel/skylake/skl.h @@ -56,6 +56,7 @@ struct skl { struct platform_device *dmic_dev; void __iomem *nhlt; /* nhlt ptr */ + struct skl_sst *skl_sst; /* sst skl ctx */ }; #define skl_to_ebus(s) (&(s)->ebus) @@ -75,4 +76,9 @@ void __iomem *skl_nhlt_init(struct device *dev); void skl_nhlt_free(void __iomem *addr); struct nhlt_specific_cfg *skl_get_ep_blob(struct skl *skl, u32 instance, u8 link_type, u8 s_fmt, u8 no_ch, u32 s_rate, u8 dirn); + +int skl_init_dsp(struct skl *skl); +void skl_free_dsp(struct skl *skl); +int skl_suspend_dsp(struct skl *skl); +int skl_resume_dsp(struct skl *skl); #endif /* __SOUND_SOC_SKL_H */ -- GitLab From 213213d9d68e5fcb81a513a7d07ed6ee01294dea Mon Sep 17 00:00:00 2001 From: Bard Liao Date: Wed, 22 Jul 2015 13:09:15 +0800 Subject: [PATCH 1585/7006] ASoC: rl6231: add pll preset table Currently, rl6231_pll_calc provide a working PLL parameters for given freq_in and freq_out. However, in some cases it is not the perfect parameter. For example if freq_in = 19200000 and freq_out = 24576000, the calculated parameter will gengrate 24.5647 MHz which is not exactly the same as what we need. But the PLL can output 24.576 MHz as exactly what we expect if we set the best PLL parameter. To improve it, we put the best match parameters in a preset table. We can search the preset table first, if there is no preset parameter for the given freq_in and freq_out, we can still calculate a working PLL parameter. Signed-off-by: Bard Liao Signed-off-by: Mark Brown --- sound/soc/codecs/rl6231.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 56650d6c2f537..96f3e906dfefe 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c @@ -43,6 +43,19 @@ int rl6231_calc_dmic_clk(int rate) } EXPORT_SYMBOL_GPL(rl6231_calc_dmic_clk); +struct pll_calc_map { + unsigned int pll_in; + unsigned int pll_out; + int k; + int n; + int m; + bool m_bp; +}; + +static const struct pll_calc_map pll_preset_table[] = { + {19200000, 24576000, 3, 30, 3, false}, +}; + /** * rl6231_pll_calc - Calcualte PLL M/N/K code. * @freq_in: external clock provided to codec. @@ -57,7 +70,7 @@ int rl6231_pll_calc(const unsigned int freq_in, const unsigned int freq_out, struct rl6231_pll_code *pll_code) { int max_n = RL6231_PLL_N_MAX, max_m = RL6231_PLL_M_MAX; - int k, red, n_t, pll_out, in_t, out_t; + int i, k, red, n_t, pll_out, in_t, out_t; int n = 0, m = 0, m_t = 0; int red_t = abs(freq_out - freq_in); bool bypass = false; @@ -65,6 +78,18 @@ int rl6231_pll_calc(const unsigned int freq_in, if (RL6231_PLL_INP_MAX < freq_in || RL6231_PLL_INP_MIN > freq_in) return -EINVAL; + for (i = 0; i < ARRAY_SIZE(pll_preset_table); i++) { + if (freq_in == pll_preset_table[i].pll_in && + freq_out == pll_preset_table[i].pll_out) { + k = pll_preset_table[i].k; + m = pll_preset_table[i].m; + n = pll_preset_table[i].n; + bypass = pll_preset_table[i].m_bp; + pr_debug("Use preset PLL parameter table\n"); + goto code_find; + } + } + k = 100000000 / freq_out - 2; if (k > RL6231_PLL_K_MAX) k = RL6231_PLL_K_MAX; -- GitLab From 36e914cc4bb5d1842e7c8a2e2b9b4f2935771c14 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Thu, 23 Jul 2015 22:09:15 +0530 Subject: [PATCH 1586/7006] ASoC: xtensa: Remove unnecessary snd_pcm_lib_preallocate_free_for_all() The ALSA core takes care that all preallocated memory is freed when the PCM itself is freed. There is no need to do this manually in the driver. Signed-off-by: Vaishali Thakkar Signed-off-by: Mark Brown --- sound/soc/xtensa/xtfpga-i2s.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sound/soc/xtensa/xtfpga-i2s.c b/sound/soc/xtensa/xtfpga-i2s.c index 1cfb19e12949e..039f65e36fa88 100644 --- a/sound/soc/xtensa/xtfpga-i2s.c +++ b/sound/soc/xtensa/xtfpga-i2s.c @@ -474,11 +474,6 @@ static int xtfpga_pcm_new(struct snd_soc_pcm_runtime *rtd) card->dev, size, size); } -static void xtfpga_pcm_free(struct snd_pcm *pcm) -{ - snd_pcm_lib_preallocate_free_for_all(pcm); -} - static const struct snd_pcm_ops xtfpga_pcm_ops = { .open = xtfpga_pcm_open, .close = xtfpga_pcm_close, @@ -490,7 +485,6 @@ static const struct snd_pcm_ops xtfpga_pcm_ops = { static const struct snd_soc_platform_driver xtfpga_soc_platform = { .pcm_new = xtfpga_pcm_new, - .pcm_free = xtfpga_pcm_free, .ops = &xtfpga_pcm_ops, }; -- GitLab From 2e5e8fd1ff9d802ab74df1ceaa5243da30491a45 Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 23 Jul 2015 12:20:27 +0530 Subject: [PATCH 1587/7006] cpupower: Do not change the frequency of offline cpu Check if the cpu is online before changing the frequency/governor of the cpu. Reported-by: Pavaman Subramaniyam Signed-off-by: Shilpasri G Bhat Reviewed-by: Gautham R. Shenoy Acked-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/cpufreq-set.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index f656e585ed45b..4e213576381ea 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c @@ -17,6 +17,7 @@ #include "cpufreq.h" #include "helpers/helpers.h" +#include "helpers/sysfs.h" #define NORM_FREQ_LEN 32 @@ -318,6 +319,9 @@ int cmd_freq_set(int argc, char **argv) cpufreq_cpu_exists(cpu)) continue; + if (sysfs_is_cpu_online(cpu) != 1) + continue; + printf(_("Setting cpu: %d\n"), cpu); ret = do_one_cpu(cpu, &new_pol, freq, policychange); if (ret) { -- GitLab From 6184fc0b8dd76c6aedc7a26e93254993e14e52de Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 24 Jun 2015 18:07:02 +0200 Subject: [PATCH 1588/7006] quota: Propagate error from ->acquire_dquot() Currently when some error happened in ->acquire_dquot(), dqget() just returned NULL. That was indistinguishable from a case when e.g. someone run quotaoff and so was generally silently ignored. However ->acquire_dquot() can fail because of ENOSPC or EIO in which case user should better know. So propagate error up from ->acquire_dquot properly. Signed-off-by: Jan Kara --- fs/ocfs2/file.c | 8 ++-- fs/ocfs2/quota_local.c | 4 +- fs/quota/dquot.c | 88 ++++++++++++++++++++++++++++------------ include/linux/quotaops.h | 5 ++- 4 files changed, 72 insertions(+), 33 deletions(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 719f7f4c7a37b..4d9e8275ed999 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1209,8 +1209,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) && OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(attr->ia_uid)); - if (!transfer_to[USRQUOTA]) { - status = -ESRCH; + if (IS_ERR(transfer_to[USRQUOTA])) { + status = PTR_ERR(transfer_to[USRQUOTA]); goto bail_unlock; } } @@ -1218,8 +1218,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) && OCFS2_HAS_RO_COMPAT_FEATURE(sb, OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(attr->ia_gid)); - if (!transfer_to[GRPQUOTA]) { - status = -ESRCH; + if (IS_ERR(transfer_to[GRPQUOTA])) { + status = PTR_ERR(transfer_to[GRPQUOTA]); goto bail_unlock; } } diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index 3d0b63d34225e..bb07004df72a3 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -499,8 +499,8 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode, dquot = dqget(sb, make_kqid(&init_user_ns, type, le64_to_cpu(dqblk->dqb_id))); - if (!dquot) { - status = -EIO; + if (IS_ERR(dquot)) { + status = PTR_ERR(dquot); mlog(ML_ERROR, "Failed to get quota structure " "for id %u, type %d. Cannot finish quota " "file recovery.\n", diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index 20d1f74561cf1..fed66e2c9fe84 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c @@ -247,7 +247,7 @@ struct dqstats dqstats; EXPORT_SYMBOL(dqstats); static qsize_t inode_get_rsv_space(struct inode *inode); -static void __dquot_initialize(struct inode *inode, int type); +static int __dquot_initialize(struct inode *inode, int type); static inline unsigned int hashfn(const struct super_block *sb, struct kqid qid) @@ -832,16 +832,17 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) struct dquot *dqget(struct super_block *sb, struct kqid qid) { unsigned int hashent = hashfn(sb, qid); - struct dquot *dquot = NULL, *empty = NULL; + struct dquot *dquot, *empty = NULL; if (!sb_has_quota_active(sb, qid.type)) - return NULL; + return ERR_PTR(-ESRCH); we_slept: spin_lock(&dq_list_lock); spin_lock(&dq_state_lock); if (!sb_has_quota_active(sb, qid.type)) { spin_unlock(&dq_state_lock); spin_unlock(&dq_list_lock); + dquot = ERR_PTR(-ESRCH); goto out; } spin_unlock(&dq_state_lock); @@ -876,11 +877,15 @@ we_slept: * already finished or it will be canceled due to dq_count > 1 test */ wait_on_dquot(dquot); /* Read the dquot / allocate space in quota file */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && - sb->dq_op->acquire_dquot(dquot) < 0) { - dqput(dquot); - dquot = NULL; - goto out; + if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { + int err; + + err = sb->dq_op->acquire_dquot(dquot); + if (err < 0) { + dqput(dquot); + dquot = ERR_PTR(err); + goto out; + } } #ifdef CONFIG_QUOTA_DEBUG BUG_ON(!dquot->dq_sb); /* Has somebody invalidated entry under us? */ @@ -1390,15 +1395,16 @@ static int dquot_active(const struct inode *inode) * It is better to call this function outside of any transaction as it * might need a lot of space in journal for dquot structure allocation. */ -static void __dquot_initialize(struct inode *inode, int type) +static int __dquot_initialize(struct inode *inode, int type) { int cnt, init_needed = 0; struct dquot **dquots, *got[MAXQUOTAS]; struct super_block *sb = inode->i_sb; qsize_t rsv; + int ret = 0; if (!dquot_active(inode)) - return; + return 0; dquots = i_dquot(inode); @@ -1407,6 +1413,7 @@ static void __dquot_initialize(struct inode *inode, int type) struct kqid qid; kprojid_t projid; int rc; + struct dquot *dquot; got[cnt] = NULL; if (type != -1 && cnt != type) @@ -1438,16 +1445,25 @@ static void __dquot_initialize(struct inode *inode, int type) qid = make_kqid_projid(projid); break; } - got[cnt] = dqget(sb, qid); + dquot = dqget(sb, qid); + if (IS_ERR(dquot)) { + /* We raced with somebody turning quotas off... */ + if (PTR_ERR(dquot) != -ESRCH) { + ret = PTR_ERR(dquot); + goto out_put; + } + dquot = NULL; + } + got[cnt] = dquot; } /* All required i_dquot has been initialized */ if (!init_needed) - return; + return 0; spin_lock(&dq_data_lock); if (IS_NOQUOTA(inode)) - goto out_err; + goto out_lock; for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; @@ -1469,15 +1485,18 @@ static void __dquot_initialize(struct inode *inode, int type) dquot_resv_space(dquots[cnt], rsv); } } -out_err: +out_lock: spin_unlock(&dq_data_lock); +out_put: /* Drop unused references */ dqput_all(got); + + return ret; } -void dquot_initialize(struct inode *inode) +int dquot_initialize(struct inode *inode) { - __dquot_initialize(inode, -1); + return __dquot_initialize(inode, -1); } EXPORT_SYMBOL(dquot_initialize); @@ -1961,18 +1980,37 @@ EXPORT_SYMBOL(__dquot_transfer); int dquot_transfer(struct inode *inode, struct iattr *iattr) { struct dquot *transfer_to[MAXQUOTAS] = {}; + struct dquot *dquot; struct super_block *sb = inode->i_sb; int ret; if (!dquot_active(inode)) return 0; - if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) - transfer_to[USRQUOTA] = dqget(sb, make_kqid_uid(iattr->ia_uid)); - if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)) - transfer_to[GRPQUOTA] = dqget(sb, make_kqid_gid(iattr->ia_gid)); - + if (iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)){ + dquot = dqget(sb, make_kqid_uid(iattr->ia_uid)); + if (IS_ERR(dquot)) { + if (PTR_ERR(dquot) != -ESRCH) { + ret = PTR_ERR(dquot); + goto out_put; + } + dquot = NULL; + } + transfer_to[USRQUOTA] = dquot; + } + if (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid)){ + dquot = dqget(sb, make_kqid_gid(iattr->ia_gid)); + if (IS_ERR(dquot)) { + if (PTR_ERR(dquot) != -ESRCH) { + ret = PTR_ERR(dquot); + goto out_put; + } + dquot = NULL; + } + transfer_to[GRPQUOTA] = dquot; + } ret = __dquot_transfer(inode, transfer_to); +out_put: dqput_all(transfer_to); return ret; } @@ -2518,8 +2556,8 @@ int dquot_get_dqblk(struct super_block *sb, struct kqid qid, struct dquot *dquot; dquot = dqget(sb, qid); - if (!dquot) - return -ESRCH; + if (IS_ERR(dquot)) + return PTR_ERR(dquot); do_get_dqblk(dquot, di); dqput(dquot); @@ -2631,8 +2669,8 @@ int dquot_set_dqblk(struct super_block *sb, struct kqid qid, int rc; dquot = dqget(sb, qid); - if (!dquot) { - rc = -ESRCH; + if (IS_ERR(dquot)) { + rc = PTR_ERR(dquot); goto out; } rc = do_set_dqblk(dquot, di); diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h index 77ca6601ff258..7a57c28eb5e70 100644 --- a/include/linux/quotaops.h +++ b/include/linux/quotaops.h @@ -43,7 +43,7 @@ void inode_claim_rsv_space(struct inode *inode, qsize_t number); void inode_sub_rsv_space(struct inode *inode, qsize_t number); void inode_reclaim_rsv_space(struct inode *inode, qsize_t number); -void dquot_initialize(struct inode *inode); +int dquot_initialize(struct inode *inode); void dquot_drop(struct inode *inode); struct dquot *dqget(struct super_block *sb, struct kqid qid); static inline struct dquot *dqgrab(struct dquot *dquot) @@ -200,8 +200,9 @@ static inline int sb_has_quota_active(struct super_block *sb, int type) return 0; } -static inline void dquot_initialize(struct inode *inode) +static inline int dquot_initialize(struct inode *inode) { + return 0; } static inline void dquot_drop(struct inode *inode) -- GitLab From c2edb305d6846ee8af7b5133845e23943d128e4c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 29 Jun 2015 16:08:45 +0200 Subject: [PATCH 1589/7006] ext2: Handle error from dquot_initalize() dquot_initialize() can now return error. Handle it where possible. Signed-off-by: Jan Kara --- fs/ext2/ialloc.c | 5 ++++- fs/ext2/inode.c | 7 +++++-- fs/ext2/namei.c | 46 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 43 insertions(+), 15 deletions(-) diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 5c04a0ddea804..efe5fb21c5332 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c @@ -577,7 +577,10 @@ got: goto fail; } - dquot_initialize(inode); + err = dquot_initialize(inode); + if (err) + goto fail_drop; + err = dquot_alloc_inode(inode); if (err) goto fail_drop; diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 5c09776d347fc..a3a404c5df2ed 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -1552,8 +1552,11 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) if (error) return error; - if (is_quota_modification(inode, iattr)) - dquot_initialize(inode); + if (is_quota_modification(inode, iattr)) { + error = dquot_initialize(inode); + if (error) + return error; + } if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) || (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) { error = dquot_transfer(inode, iattr); diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 13ec54a99c962..b4841e3066a5b 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -96,8 +96,11 @@ struct dentry *ext2_get_parent(struct dentry *child) static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl) { struct inode *inode; + int err; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; inode = ext2_new_inode(dir, mode, &dentry->d_name); if (IS_ERR(inode)) @@ -143,7 +146,9 @@ static int ext2_mknod (struct inode * dir, struct dentry *dentry, umode_t mode, if (!new_valid_dev(rdev)) return -EINVAL; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; inode = ext2_new_inode (dir, mode, &dentry->d_name); err = PTR_ERR(inode); @@ -169,7 +174,9 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry, if (l > sb->s_blocksize) goto out; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + goto out; inode = ext2_new_inode (dir, S_IFLNK | S_IRWXUGO, &dentry->d_name); err = PTR_ERR(inode); @@ -212,7 +219,9 @@ static int ext2_link (struct dentry * old_dentry, struct inode * dir, struct inode *inode = d_inode(old_dentry); int err; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; inode->i_ctime = CURRENT_TIME_SEC; inode_inc_link_count(inode); @@ -233,7 +242,9 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) struct inode * inode; int err; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; inode_inc_link_count(dir); @@ -279,13 +290,17 @@ static int ext2_unlink(struct inode * dir, struct dentry *dentry) struct inode * inode = d_inode(dentry); struct ext2_dir_entry_2 * de; struct page * page; - int err = -ENOENT; + int err; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + goto out; de = ext2_find_entry (dir, &dentry->d_name, &page); - if (!de) + if (!de) { + err = -ENOENT; goto out; + } err = ext2_delete_entry (de, page); if (err) @@ -323,14 +338,21 @@ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct ext2_dir_entry_2 * dir_de = NULL; struct page * old_page; struct ext2_dir_entry_2 * old_de; - int err = -ENOENT; + int err; + + err = dquot_initialize(old_dir); + if (err) + goto out; - dquot_initialize(old_dir); - dquot_initialize(new_dir); + err = dquot_initialize(new_dir); + if (err) + goto out; old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); - if (!old_de) + if (!old_de) { + err = -ENOENT; goto out; + } if (S_ISDIR(old_inode->i_mode)) { err = -EIO; -- GitLab From a7cdadee0e89486ad072be7b91e477105784e0bb Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 29 Jun 2015 16:22:54 +0200 Subject: [PATCH 1590/7006] ext4: Handle error from dquot_initialize() dquot_initialize() can now return error. Handle it where possible. Acked-by: Theodore Ts'o Signed-off-by: Jan Kara --- fs/ext4/ialloc.c | 6 +++-- fs/ext4/inode.c | 7 ++++-- fs/ext4/namei.c | 63 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 56 insertions(+), 20 deletions(-) diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index 173c1ae213955..619bfc1fda8cc 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c @@ -721,7 +721,7 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, struct ext4_group_desc *gdp = NULL; struct ext4_inode_info *ei; struct ext4_sb_info *sbi; - int ret2, err = 0; + int ret2, err; struct inode *ret; ext4_group_t i; ext4_group_t flex_group; @@ -769,7 +769,9 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, inode->i_gid = dir->i_gid; } else inode_init_owner(inode, dir, mode); - dquot_initialize(inode); + err = dquot_initialize(inode); + if (err) + goto out; if (!goal) goal = sbi->s_inode_goal; diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index cecf9aa108113..fed7ee7ea6e8c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4661,8 +4661,11 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) if (error) return error; - if (is_quota_modification(inode, attr)) - dquot_initialize(inode); + if (is_quota_modification(inode, attr)) { + error = dquot_initialize(inode); + if (error) + return error; + } if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { handle_t *handle; diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index 011dcfb5cce37..d3ff83742a337 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -2436,7 +2436,9 @@ static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode, struct inode *inode; int err, credits, retries = 0; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); @@ -2470,7 +2472,9 @@ static int ext4_mknod(struct inode *dir, struct dentry *dentry, if (!new_valid_dev(rdev)) return -EINVAL; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); @@ -2499,7 +2503,9 @@ static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) struct inode *inode; int err, retries = 0; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; retry: inode = ext4_new_inode_start_handle(dir, mode, @@ -2612,7 +2618,9 @@ static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) if (EXT4_DIR_LINK_MAX(dir)) return -EMLINK; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); @@ -2910,8 +2918,12 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry) /* Initialize quotas before so that eventual writes go in * separate transaction */ - dquot_initialize(dir); - dquot_initialize(d_inode(dentry)); + retval = dquot_initialize(dir); + if (retval) + return retval; + retval = dquot_initialize(d_inode(dentry)); + if (retval) + return retval; retval = -ENOENT; bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); @@ -2980,8 +2992,12 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry) trace_ext4_unlink_enter(dir, dentry); /* Initialize quotas before so that eventual writes go * in separate transaction */ - dquot_initialize(dir); - dquot_initialize(d_inode(dentry)); + retval = dquot_initialize(dir); + if (retval) + return retval; + retval = dquot_initialize(d_inode(dentry)); + if (retval) + return retval; retval = -ENOENT; bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); @@ -3066,7 +3082,9 @@ static int ext4_symlink(struct inode *dir, goto err_free_sd; } - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; if ((disk_link.len > EXT4_N_BLOCKS * 4)) { /* @@ -3197,7 +3215,9 @@ static int ext4_link(struct dentry *old_dentry, if (ext4_encrypted_inode(dir) && !ext4_is_child_context_consistent_with_parent(dir, inode)) return -EPERM; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) + return err; retry: handle = ext4_journal_start(dir, EXT4_HT_DIR, @@ -3476,13 +3496,20 @@ static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, int credits; u8 old_file_type; - dquot_initialize(old.dir); - dquot_initialize(new.dir); + retval = dquot_initialize(old.dir); + if (retval) + return retval; + retval = dquot_initialize(new.dir); + if (retval) + return retval; /* Initialize quotas before so that eventual writes go * in separate transaction */ - if (new.inode) - dquot_initialize(new.inode); + if (new.inode) { + retval = dquot_initialize(new.inode); + if (retval) + return retval; + } old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL); if (IS_ERR(old.bh)) @@ -3678,8 +3705,12 @@ static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, new.inode))) return -EPERM; - dquot_initialize(old.dir); - dquot_initialize(new.dir); + retval = dquot_initialize(old.dir); + if (retval) + return retval; + retval = dquot_initialize(new.dir); + if (retval) + return retval; old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, &old.inlined); -- GitLab From 9c89fe0af826bfff36d8019ea6fd78db09b3c478 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 14 Jul 2015 13:36:02 +0200 Subject: [PATCH 1591/7006] ocfs2: Handle error from dquot_initialize() dquot_initialize() can now return error. Handle it where possible. Reviewed-by: Junxiao Bi Signed-off-by: Jan Kara --- fs/ocfs2/file.c | 14 +++++++--- fs/ocfs2/namei.c | 59 +++++++++++++++++++++++++++++++---------- fs/ocfs2/refcounttree.c | 5 ++-- 3 files changed, 58 insertions(+), 20 deletions(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 4d9e8275ed999..7210583b472f5 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -105,8 +105,11 @@ static int ocfs2_file_open(struct inode *inode, struct file *file) file->f_path.dentry->d_name.len, file->f_path.dentry->d_name.name, mode); - if (file->f_mode & FMODE_WRITE) - dquot_initialize(inode); + if (file->f_mode & FMODE_WRITE) { + status = dquot_initialize(inode); + if (status) + goto leave; + } spin_lock(&oi->ip_lock); @@ -1155,8 +1158,11 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) if (status) return status; - if (is_quota_modification(inode, attr)) - dquot_initialize(inode); + if (is_quota_modification(inode, attr)) { + status = dquot_initialize(inode); + if (status) + return status; + } size_change = S_ISREG(inode->i_mode) && attr->ia_valid & ATTR_SIZE; if (size_change) { status = ocfs2_rw_lock(inode, 1); diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 6e6abb93fda59..948681e37cfdb 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -200,11 +200,12 @@ bail: static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode) { struct inode *inode; + int status; inode = new_inode(dir->i_sb); if (!inode) { mlog(ML_ERROR, "new_inode failed!\n"); - return NULL; + return ERR_PTR(-ENOMEM); } /* populate as many fields early on as possible - many of @@ -213,7 +214,10 @@ static struct inode *ocfs2_get_init_inode(struct inode *dir, umode_t mode) if (S_ISDIR(mode)) set_nlink(inode, 2); inode_init_owner(inode, dir, mode); - dquot_initialize(inode); + status = dquot_initialize(inode); + if (status) + return ERR_PTR(status); + return inode; } @@ -264,7 +268,11 @@ static int ocfs2_mknod(struct inode *dir, (unsigned long long)OCFS2_I(dir)->ip_blkno, (unsigned long)dev, mode); - dquot_initialize(dir); + status = dquot_initialize(dir); + if (status) { + mlog_errno(status); + return status; + } /* get our super block */ osb = OCFS2_SB(dir->i_sb); @@ -311,8 +319,9 @@ static int ocfs2_mknod(struct inode *dir, } inode = ocfs2_get_init_inode(dir, mode); - if (!inode) { - status = -ENOMEM; + if (IS_ERR(inode)) { + status = PTR_ERR(inode); + inode = NULL; mlog_errno(status); goto leave; } @@ -708,7 +717,11 @@ static int ocfs2_link(struct dentry *old_dentry, if (S_ISDIR(inode->i_mode)) return -EPERM; - dquot_initialize(dir); + err = dquot_initialize(dir); + if (err) { + mlog_errno(err); + return err; + } err = ocfs2_double_lock(osb, &old_dir_bh, old_dir, &parent_fe_bh, dir, 0); @@ -896,7 +909,11 @@ static int ocfs2_unlink(struct inode *dir, (unsigned long long)OCFS2_I(dir)->ip_blkno, (unsigned long long)OCFS2_I(inode)->ip_blkno); - dquot_initialize(dir); + status = dquot_initialize(dir); + if (status) { + mlog_errno(status); + return status; + } BUG_ON(d_inode(dentry->d_parent) != dir); @@ -1230,8 +1247,16 @@ static int ocfs2_rename(struct inode *old_dir, old_dentry->d_name.len, old_dentry->d_name.name, new_dentry->d_name.len, new_dentry->d_name.name); - dquot_initialize(old_dir); - dquot_initialize(new_dir); + status = dquot_initialize(old_dir); + if (status) { + mlog_errno(status); + goto bail; + } + status = dquot_initialize(new_dir); + if (status) { + mlog_errno(status); + goto bail; + } osb = OCFS2_SB(old_dir->i_sb); @@ -1786,7 +1811,11 @@ static int ocfs2_symlink(struct inode *dir, trace_ocfs2_symlink_begin(dir, dentry, symname, dentry->d_name.len, dentry->d_name.name); - dquot_initialize(dir); + status = dquot_initialize(dir); + if (status) { + mlog_errno(status); + goto bail; + } sb = dir->i_sb; osb = OCFS2_SB(sb); @@ -1831,8 +1860,9 @@ static int ocfs2_symlink(struct inode *dir, } inode = ocfs2_get_init_inode(dir, S_IFLNK | S_IRWXUGO); - if (!inode) { - status = -ENOMEM; + if (IS_ERR(inode)) { + status = PTR_ERR(inode); + inode = NULL; mlog_errno(status); goto bail; } @@ -2485,8 +2515,9 @@ int ocfs2_create_inode_in_orphan(struct inode *dir, } inode = ocfs2_get_init_inode(dir, mode); - if (!inode) { - status = -ENOMEM; + if (IS_ERR(inode)) { + status = PTR_ERR(inode); + inode = NULL; mlog_errno(status); goto leave; } diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index b69dd14c0b9ba..7dc818b87cd82 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -4419,8 +4419,9 @@ static int ocfs2_vfs_reflink(struct dentry *old_dentry, struct inode *dir, } mutex_lock(&inode->i_mutex); - dquot_initialize(dir); - error = ocfs2_reflink(old_dentry, dir, new_dentry, preserve); + error = dquot_initialize(dir); + if (!error) + error = ocfs2_reflink(old_dentry, dir, new_dentry, preserve); mutex_unlock(&inode->i_mutex); if (!error) fsnotify_create(dir, new_dentry); -- GitLab From 2e6c97ea4ce6a29941da46d03183c2c0e330fb2f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 14 Jul 2015 13:51:55 +0200 Subject: [PATCH 1592/7006] reiserfs: Handle error from dquot_initialize() dquot_initialize() can now return error. Handle it where possible. Signed-off-by: Jan Kara --- fs/reiserfs/inode.c | 7 +++-- fs/reiserfs/namei.c | 63 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 53 insertions(+), 17 deletions(-) diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index f6f2fbad9777d..3d8e7e671d5ba 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -3319,8 +3319,11 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) /* must be turned off for recursive notify_change calls */ ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); - if (is_quota_modification(inode, attr)) - dquot_initialize(inode); + if (is_quota_modification(inode, attr)) { + error = dquot_initialize(inode); + if (error) + return error; + } reiserfs_write_lock(inode->i_sb); if (attr->ia_valid & ATTR_SIZE) { /* diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index b55a074653d7a..5f1c9c29eb8c9 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -613,8 +613,7 @@ static int new_inode_init(struct inode *inode, struct inode *dir, umode_t mode) * we have to set uid and gid here */ inode_init_owner(inode, dir, mode); - dquot_initialize(inode); - return 0; + return dquot_initialize(inode); } static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, @@ -633,12 +632,18 @@ static int reiserfs_create(struct inode *dir, struct dentry *dentry, umode_t mod struct reiserfs_transaction_handle th; struct reiserfs_security_handle security; - dquot_initialize(dir); + retval = dquot_initialize(dir); + if (retval) + return retval; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } - new_inode_init(inode, dir, mode); + retval = new_inode_init(inode, dir, mode); + if (retval) { + drop_new_inode(inode); + return retval; + } jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); @@ -710,12 +715,18 @@ static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode if (!new_valid_dev(rdev)) return -EINVAL; - dquot_initialize(dir); + retval = dquot_initialize(dir); + if (retval) + return retval; if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } - new_inode_init(inode, dir, mode); + retval = new_inode_init(inode, dir, mode); + if (retval) { + drop_new_inode(inode); + return retval; + } jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); @@ -787,7 +798,9 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb)); - dquot_initialize(dir); + retval = dquot_initialize(dir); + if (retval) + return retval; #ifdef DISPLACE_NEW_PACKING_LOCALITIES /* @@ -800,7 +813,11 @@ static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode if (!(inode = new_inode(dir->i_sb))) { return -ENOMEM; } - new_inode_init(inode, dir, mode); + retval = new_inode_init(inode, dir, mode); + if (retval) { + drop_new_inode(inode); + return retval; + } jbegin_count += reiserfs_cache_default_acl(dir); retval = reiserfs_security_init(dir, inode, &dentry->d_name, &security); @@ -899,7 +916,9 @@ static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry) JOURNAL_PER_BALANCE_CNT * 2 + 2 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); - dquot_initialize(dir); + retval = dquot_initialize(dir); + if (retval) + return retval; reiserfs_write_lock(dir->i_sb); retval = journal_begin(&th, dir->i_sb, jbegin_count); @@ -985,7 +1004,9 @@ static int reiserfs_unlink(struct inode *dir, struct dentry *dentry) int jbegin_count; unsigned long savelink; - dquot_initialize(dir); + retval = dquot_initialize(dir); + if (retval) + return retval; inode = d_inode(dentry); @@ -1095,12 +1116,18 @@ static int reiserfs_symlink(struct inode *parent_dir, 2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb) + REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb)); - dquot_initialize(parent_dir); + retval = dquot_initialize(parent_dir); + if (retval) + return retval; if (!(inode = new_inode(parent_dir->i_sb))) { return -ENOMEM; } - new_inode_init(inode, parent_dir, mode); + retval = new_inode_init(inode, parent_dir, mode); + if (retval) { + drop_new_inode(inode); + return retval; + } retval = reiserfs_security_init(parent_dir, inode, &dentry->d_name, &security); @@ -1184,7 +1211,9 @@ static int reiserfs_link(struct dentry *old_dentry, struct inode *dir, JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb); - dquot_initialize(dir); + retval = dquot_initialize(dir); + if (retval) + return retval; reiserfs_write_lock(dir->i_sb); if (inode->i_nlink >= REISERFS_LINK_MAX) { @@ -1308,8 +1337,12 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb); - dquot_initialize(old_dir); - dquot_initialize(new_dir); + retval = dquot_initialize(old_dir); + if (retval) + return retval; + retval = dquot_initialize(new_dir); + if (retval) + return retval; old_inode = d_inode(old_dentry); new_dentry_inode = d_inode(new_dentry); -- GitLab From acc84b05b1f463952a638689335ca47e70d5ea30 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Wed, 15 Jul 2015 13:53:19 -0500 Subject: [PATCH 1593/7006] jfs: Handle error from dquot_initialize() dquot_initialize() can now return error. Handle it where possible Slightly modified by Dave Kleikamp due to needed jfs_rename() error path fix. Signed-off-by: Jan Kara Reviewed-by: Dave Kleikamp --- fs/jfs/file.c | 7 ++++-- fs/jfs/jfs_inode.c | 4 +++- fs/jfs/namei.c | 54 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/fs/jfs/file.c b/fs/jfs/file.c index b9dc23cd04f20..0e026a7bdcd4d 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -107,8 +107,11 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) if (rc) return rc; - if (is_quota_modification(inode, iattr)) - dquot_initialize(inode); + if (is_quota_modification(inode, iattr)) { + rc = dquot_initialize(inode); + if (rc) + return rc; + } if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) || (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) { rc = dquot_transfer(inode, iattr); diff --git a/fs/jfs/jfs_inode.c b/fs/jfs/jfs_inode.c index 6b0f816201a22..cf7936fe2e682 100644 --- a/fs/jfs/jfs_inode.c +++ b/fs/jfs/jfs_inode.c @@ -109,7 +109,9 @@ struct inode *ialloc(struct inode *parent, umode_t mode) /* * Allocate inode to quota. */ - dquot_initialize(inode); + rc = dquot_initialize(inode); + if (rc) + goto fail_drop; rc = dquot_alloc_inode(inode); if (rc) goto fail_drop; diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index a5ac97b9a933a..35976bdccafcf 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -86,7 +86,9 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode, jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry); - dquot_initialize(dip); + rc = dquot_initialize(dip); + if (rc) + goto out1; /* * search parent directory for entry/freespace @@ -218,7 +220,9 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode) jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry); - dquot_initialize(dip); + rc = dquot_initialize(dip); + if (rc) + goto out1; /* * search parent directory for entry/freespace @@ -355,8 +359,12 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry) jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry); /* Init inode for quota operations. */ - dquot_initialize(dip); - dquot_initialize(ip); + rc = dquot_initialize(dip); + if (rc) + goto out; + rc = dquot_initialize(ip); + if (rc) + goto out; /* directory must be empty to be removed */ if (!dtEmpty(ip)) { @@ -483,8 +491,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry) jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry); /* Init inode for quota operations. */ - dquot_initialize(dip); - dquot_initialize(ip); + rc = dquot_initialize(dip); + if (rc) + goto out; + rc = dquot_initialize(ip); + if (rc) + goto out; if ((rc = get_UCSname(&dname, dentry))) goto out; @@ -799,7 +811,9 @@ static int jfs_link(struct dentry *old_dentry, jfs_info("jfs_link: %pd %pd", old_dentry, dentry); - dquot_initialize(dir); + rc = dquot_initialize(dir); + if (rc) + goto out; tid = txBegin(ip->i_sb, 0); @@ -810,7 +824,7 @@ static int jfs_link(struct dentry *old_dentry, * scan parent directory for entry/freespace */ if ((rc = get_UCSname(&dname, dentry))) - goto out; + goto out_tx; if ((rc = dtSearch(dir, &dname, &ino, &btstack, JFS_CREATE))) goto free_dname; @@ -842,12 +856,13 @@ static int jfs_link(struct dentry *old_dentry, free_dname: free_UCSname(&dname); - out: + out_tx: txEnd(tid); mutex_unlock(&JFS_IP(ip)->commit_mutex); mutex_unlock(&JFS_IP(dir)->commit_mutex); + out: jfs_info("jfs_link: rc:%d", rc); return rc; } @@ -891,7 +906,9 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, jfs_info("jfs_symlink: dip:0x%p name:%s", dip, name); - dquot_initialize(dip); + rc = dquot_initialize(dip); + if (rc) + goto out1; ssize = strlen(name) + 1; @@ -1082,8 +1099,12 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry); - dquot_initialize(old_dir); - dquot_initialize(new_dir); + rc = dquot_initialize(old_dir); + if (rc) + goto out1; + rc = dquot_initialize(new_dir); + if (rc) + goto out1; old_ip = d_inode(old_dentry); new_ip = d_inode(new_dentry); @@ -1130,7 +1151,9 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, } else if (new_ip) { IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL); /* Init inode for quota operations. */ - dquot_initialize(new_ip); + rc = dquot_initialize(new_ip); + if (rc) + goto out_unlock; } /* @@ -1318,6 +1341,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry, clear_cflag(COMMIT_Stale, old_dir); } + out_unlock: if (new_ip && !S_ISDIR(new_ip->i_mode)) IWRITE_UNLOCK(new_ip); out3: @@ -1353,7 +1377,9 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry, jfs_info("jfs_mknod: %pd", dentry); - dquot_initialize(dir); + rc = dquot_initialize(dir); + if (rc) + goto out; if ((rc = get_UCSname(&dname, dentry))) goto out; -- GitLab From 82ff50b222d8ac645cdeba974c612c9eef01c3dd Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 14 Jul 2015 14:55:05 +0200 Subject: [PATCH 1594/7006] doc: Update doc about journalling layer Documentation of journalling layer in Documentation/DocBook/filesystems.tmpl speaks about JBD layer. Since that is going away, update the documentation to speak about JBD2. Also update the parts that have changed since someone last touched the document and remove some parts which are just misleading and outdated. Signed-off-by: Jan Kara --- Documentation/DocBook/filesystems.tmpl | 178 ++++++++++--------------- 1 file changed, 67 insertions(+), 111 deletions(-) diff --git a/Documentation/DocBook/filesystems.tmpl b/Documentation/DocBook/filesystems.tmpl index bcdfdb9a92770..6006b6358c867 100644 --- a/Documentation/DocBook/filesystems.tmpl +++ b/Documentation/DocBook/filesystems.tmpl @@ -146,36 +146,30 @@ The journalling layer is easy to use. You need to first of all create a journal_t data structure. There are two calls to do this dependent on how you decide to allocate the physical -media on which the journal resides. The journal_init_inode() call -is for journals stored in filesystem inodes, or the journal_init_dev() -call can be use for journal stored on a raw device (in a continuous range +media on which the journal resides. The jbd2_journal_init_inode() call +is for journals stored in filesystem inodes, or the jbd2_journal_init_dev() +call can be used for journal stored on a raw device (in a continuous range of blocks). A journal_t is a typedef for a struct pointer, so when -you are finally finished make sure you call journal_destroy() on it +you are finally finished make sure you call jbd2_journal_destroy() on it to free up any used kernel memory. Once you have got your journal_t object you need to 'mount' or load the journal -file, unless of course you haven't initialised it yet - in which case you -need to call journal_create(). +file. The journalling layer expects the space for the journal was already +allocated and initialized properly by the userspace tools. When loading the +journal you must call jbd2_journal_load() to process journal contents. If the +client file system detects the journal contents does not need to be processed +(or even need not have valid contents), it may call jbd2_journal_wipe() to +clear the journal contents before calling jbd2_journal_load(). -Most of the time however your journal file will already have been created, but -before you load it you must call journal_wipe() to empty the journal file. -Hang on, you say , what if the filesystem wasn't cleanly umount()'d . Well, it is the -job of the client file system to detect this and skip the call to journal_wipe(). - - - -In either case the next call should be to journal_load() which prepares the -journal file for use. Note that journal_wipe(..,0) calls journal_skip_recovery() -for you if it detects any outstanding transactions in the journal and similarly -journal_load() will call journal_recover() if necessary. -I would advise reading fs/ext3/super.c for examples on this stage. -[RGG: Why is the journal_wipe() call necessary - doesn't this needlessly -complicate the API. Or isn't a good idea for the journal layer to hide -dirty mounts from the client fs] +Note that jbd2_journal_wipe(..,0) calls jbd2_journal_skip_recovery() for you if +it detects any outstanding transactions in the journal and similarly +jbd2_journal_load() will call jbd2_journal_recover() if necessary. I would +advise reading ext4_load_journal() in fs/ext4/super.c for examples on this +stage. @@ -189,41 +183,41 @@ You still need to actually journal your filesystem changes, this is done by wrapping them into transactions. Additionally you also need to wrap the modification of each of the buffers with calls to the journal layer, so it knows what the modifications -you are actually making are. To do this use journal_start() which +you are actually making are. To do this use jbd2_journal_start() which returns a transaction handle. -journal_start() -and its counterpart journal_stop(), which indicates the end of a transaction -are nestable calls, so you can reenter a transaction if necessary, -but remember you must call journal_stop() the same number of times as -journal_start() before the transaction is completed (or more accurately -leaves the update phase). Ext3/VFS makes use of this feature to simplify -quota support. +jbd2_journal_start() +and its counterpart jbd2_journal_stop(), which indicates the end of a +transaction are nestable calls, so you can reenter a transaction if necessary, +but remember you must call jbd2_journal_stop() the same number of times as +jbd2_journal_start() before the transaction is completed (or more accurately +leaves the update phase). Ext4/VFS makes use of this feature to simplify +handling of inode dirtying, quota support, etc. Inside each transaction you need to wrap the modifications to the individual buffers (blocks). Before you start to modify a buffer you -need to call journal_get_{create,write,undo}_access() as appropriate, +need to call jbd2_journal_get_{create,write,undo}_access() as appropriate, this allows the journalling layer to copy the unmodified data if it needs to. After all the buffer may be part of a previously uncommitted transaction. At this point you are at last ready to modify a buffer, and once -you are have done so you need to call journal_dirty_{meta,}data(). +you are have done so you need to call jbd2_journal_dirty_{meta,}data(). Or if you've asked for access to a buffer you now know is now longer -required to be pushed back on the device you can call journal_forget() +required to be pushed back on the device you can call jbd2_journal_forget() in much the same way as you might have used bforget() in the past. -A journal_flush() may be called at any time to commit and checkpoint +A jbd2_journal_flush() may be called at any time to commit and checkpoint all your transactions. -Then at umount time , in your put_super() you can then call journal_destroy() +Then at umount time , in your put_super() you can then call jbd2_journal_destroy() to clean up your in-core journal object. @@ -231,82 +225,74 @@ to clean up your in-core journal object. Unfortunately there a couple of ways the journal layer can cause a deadlock. The first thing to note is that each task can only have a single outstanding transaction at any one time, remember nothing -commits until the outermost journal_stop(). This means +commits until the outermost jbd2_journal_stop(). This means you must complete the transaction at the end of each file/inode/address etc. operation you perform, so that the journalling system isn't re-entered on another journal. Since transactions can't be nested/batched across differing journals, and another filesystem other than -yours (say ext3) may be modified in a later syscall. +yours (say ext4) may be modified in a later syscall. -The second case to bear in mind is that journal_start() can +The second case to bear in mind is that jbd2_journal_start() can block if there isn't enough space in the journal for your transaction (based on the passed nblocks param) - when it blocks it merely(!) needs to wait for transactions to complete and be committed from other tasks, -so essentially we are waiting for journal_stop(). So to avoid -deadlocks you must treat journal_start/stop() as if they +so essentially we are waiting for jbd2_journal_stop(). So to avoid +deadlocks you must treat jbd2_journal_start/stop() as if they were semaphores and include them in your semaphore ordering rules to prevent -deadlocks. Note that journal_extend() has similar blocking behaviour to -journal_start() so you can deadlock here just as easily as on journal_start(). +deadlocks. Note that jbd2_journal_extend() has similar blocking behaviour to +jbd2_journal_start() so you can deadlock here just as easily as on +jbd2_journal_start(). Try to reserve the right number of blocks the first time. ;-). This will be the maximum number of blocks you are going to touch in this transaction. -I advise having a look at at least ext3_jbd.h to see the basis on which -ext3 uses to make these decisions. +I advise having a look at at least ext4_jbd.h to see the basis on which +ext4 uses to make these decisions. Another wriggle to watch out for is your on-disk block allocation strategy. -why? Because, if you undo a delete, you need to ensure you haven't reused any -of the freed blocks in a later transaction. One simple way of doing this -is make sure any blocks you allocate only have checkpointed transactions -listed against them. Ext3 does this in ext3_test_allocatable(). +Why? Because, if you do a delete, you need to ensure you haven't reused any +of the freed blocks until the transaction freeing these blocks commits. If you +reused these blocks and crash happens, there is no way to restore the contents +of the reallocated blocks at the end of the last fully committed transaction. + +One simple way of doing this is to mark blocks as free in internal in-memory +block allocation structures only after the transaction freeing them commits. +Ext4 uses journal commit callback for this purpose. + + + +With journal commit callbacks you can ask the journalling layer to call a +callback function when the transaction is finally committed to disk, so that +you can do some of your own management. You ask the journalling layer for +calling the callback by simply setting journal->j_commit_callback function +pointer and that function is called after each transaction commit. You can also +use transaction->t_private_list for attaching entries to a transaction that +need processing when the transaction commits. -Lock is also providing through journal_{un,}lock_updates(), -ext3 uses this when it wants a window with a clean and stable fs for a moment. -eg. +JBD2 also provides a way to block all transaction updates via +jbd2_journal_{un,}lock_updates(). Ext4 uses this when it wants a window with a +clean and stable fs for a moment. E.g. - journal_lock_updates() //stop new stuff happening.. - journal_flush() // checkpoint everything. + jbd2_journal_lock_updates() //stop new stuff happening.. + jbd2_journal_flush() // checkpoint everything. ..do stuff on stable fs - journal_unlock_updates() // carry on with filesystem use. + jbd2_journal_unlock_updates() // carry on with filesystem use. The opportunities for abuse and DOS attacks with this should be obvious, if you allow unprivileged userspace to trigger codepaths containing these calls. - - - -A new feature of jbd since 2.5.25 is commit callbacks with the new -journal_callback_set() function you can now ask the journalling layer -to call you back when the transaction is finally committed to disk, so that -you can do some of your own management. The key to this is the journal_callback -struct, this maintains the internal callback information but you can -extend it like this:- - - - struct myfs_callback_s { - //Data structure element required by jbd.. - struct journal_callback for_jbd; - // Stuff for myfs allocated together. - myfs_inode* i_commited; - - } - - - -this would be useful if you needed to know when data was committed to a -particular inode. @@ -319,36 +305,6 @@ being each mount, each modification (transaction) and each changed buffer to tell the journalling layer about them. - -Here is a some pseudo code to give you an idea of how it works, as -an example. - - - - journal_t* my_jnrl = journal_create(); - journal_init_{dev,inode}(jnrl,...) - if (clean) journal_wipe(); - journal_load(); - - foreach(transaction) { /*transactions must be - completed before - a syscall returns to - userspace*/ - - handle_t * xct=journal_start(my_jnrl); - foreach(bh) { - journal_get_{create,write,undo}_access(xact,bh); - if ( myfs_modify(bh) ) { /* returns true - if makes changes */ - journal_dirty_{meta,}data(xact,bh); - } else { - journal_forget(bh); - } - } - journal_stop(xct); - } - journal_destroy(my_jrnl); - @@ -357,13 +313,13 @@ an example. Data Types The journalling layer uses typedefs to 'hide' the concrete definitions - of the structures used. As a client of the JBD layer you can + of the structures used. As a client of the JBD2 layer you can just rely on the using the pointer as a magic cookie of some sort. Obviously the hiding is not enforced as this is 'C'. Structures -!Iinclude/linux/jbd.h +!Iinclude/linux/jbd2.h @@ -375,11 +331,11 @@ an example. manage transactions Journal Level -!Efs/jbd/journal.c -!Ifs/jbd/recovery.c +!Efs/jbd2/journal.c +!Ifs/jbd2/recovery.c Transasction Level -!Efs/jbd/transaction.c +!Efs/jbd2/transaction.c -- GitLab From c290ea01abb7907fde602f3ba55905ef10a37477 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 18 Jun 2015 16:52:29 +0200 Subject: [PATCH 1595/7006] fs: Remove ext3 filesystem driver The functionality of ext3 is fully supported by ext4 driver. Major distributions (SUSE, RedHat) already use ext4 driver to handle ext3 filesystems for quite some time. There is some ugliness in mm resulting from jbd cleaning buffers in a dirty page without cleaning page dirty bit and also support for buffer bouncing in the block layer when stable pages are required is there only because of jbd. So let's remove the ext3 driver. This saves us some 28k lines of duplicated code. Acked-by: Theodore Ts'o Signed-off-by: Jan Kara --- Documentation/filesystems/ext2.txt | 4 +- Documentation/filesystems/ext3.txt | 209 +- Documentation/filesystems/vfs.txt | 2 +- MAINTAINERS | 18 +- fs/Kconfig | 5 +- fs/Makefile | 2 - fs/ext3/Kconfig | 89 - fs/ext3/Makefile | 12 - fs/ext3/acl.c | 281 --- fs/ext3/acl.h | 72 - fs/ext3/balloc.c | 2158 ----------------- fs/ext3/bitmap.c | 20 - fs/ext3/dir.c | 537 ----- fs/ext3/ext3.h | 1332 ----------- fs/ext3/ext3_jbd.c | 59 - fs/ext3/file.c | 79 - fs/ext3/fsync.c | 109 - fs/ext3/hash.c | 206 -- fs/ext3/ialloc.c | 706 ------ fs/ext3/inode.c | 3574 ---------------------------- fs/ext3/ioctl.c | 327 --- fs/ext3/namei.c | 2586 -------------------- fs/ext3/namei.h | 27 - fs/ext3/resize.c | 1117 --------- fs/ext3/super.c | 3165 ------------------------ fs/ext3/symlink.c | 46 - fs/ext3/xattr.c | 1330 ----------- fs/ext3/xattr.h | 136 -- fs/ext3/xattr_security.c | 78 - fs/ext3/xattr_trusted.c | 54 - fs/ext3/xattr_user.c | 58 - fs/ext4/Kconfig | 41 +- fs/ext4/super.c | 14 +- fs/jbd/Kconfig | 30 - fs/jbd/Makefile | 7 - fs/jbd/checkpoint.c | 782 ------ fs/jbd/commit.c | 1021 -------- fs/jbd/journal.c | 2145 ----------------- fs/jbd/recovery.c | 594 ----- fs/jbd/revoke.c | 733 ------ fs/jbd/transaction.c | 2237 ----------------- include/linux/jbd.h | 1047 -------- include/linux/jbd2.h | 41 +- include/linux/jbd_common.h | 46 - include/trace/events/ext3.h | 866 ------- include/trace/events/jbd.h | 194 -- 46 files changed, 87 insertions(+), 28109 deletions(-) delete mode 100644 fs/ext3/Kconfig delete mode 100644 fs/ext3/Makefile delete mode 100644 fs/ext3/acl.c delete mode 100644 fs/ext3/acl.h delete mode 100644 fs/ext3/balloc.c delete mode 100644 fs/ext3/bitmap.c delete mode 100644 fs/ext3/dir.c delete mode 100644 fs/ext3/ext3.h delete mode 100644 fs/ext3/ext3_jbd.c delete mode 100644 fs/ext3/file.c delete mode 100644 fs/ext3/fsync.c delete mode 100644 fs/ext3/hash.c delete mode 100644 fs/ext3/ialloc.c delete mode 100644 fs/ext3/inode.c delete mode 100644 fs/ext3/ioctl.c delete mode 100644 fs/ext3/namei.c delete mode 100644 fs/ext3/namei.h delete mode 100644 fs/ext3/resize.c delete mode 100644 fs/ext3/super.c delete mode 100644 fs/ext3/symlink.c delete mode 100644 fs/ext3/xattr.c delete mode 100644 fs/ext3/xattr.h delete mode 100644 fs/ext3/xattr_security.c delete mode 100644 fs/ext3/xattr_trusted.c delete mode 100644 fs/ext3/xattr_user.c delete mode 100644 fs/jbd/Kconfig delete mode 100644 fs/jbd/Makefile delete mode 100644 fs/jbd/checkpoint.c delete mode 100644 fs/jbd/commit.c delete mode 100644 fs/jbd/journal.c delete mode 100644 fs/jbd/recovery.c delete mode 100644 fs/jbd/revoke.c delete mode 100644 fs/jbd/transaction.c delete mode 100644 include/linux/jbd.h delete mode 100644 include/linux/jbd_common.h delete mode 100644 include/trace/events/ext3.h delete mode 100644 include/trace/events/jbd.h diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt index b9714569e472b..55755395d3dc5 100644 --- a/Documentation/filesystems/ext2.txt +++ b/Documentation/filesystems/ext2.txt @@ -360,8 +360,8 @@ and are copied into the filesystem. If a transaction is incomplete at the time of the crash, then there is no guarantee of consistency for the blocks in that transaction so they are discarded (which means any filesystem changes they represent are also lost). -Check Documentation/filesystems/ext3.txt if you want to read more about -ext3 and journaling. +Check Documentation/filesystems/ext4.txt if you want to read more about +ext4 and journaling. References ========== diff --git a/Documentation/filesystems/ext3.txt b/Documentation/filesystems/ext3.txt index 7ed0d17d67218..58758fbef9e0d 100644 --- a/Documentation/filesystems/ext3.txt +++ b/Documentation/filesystems/ext3.txt @@ -6,210 +6,7 @@ Ext3 was originally released in September 1999. Written by Stephen Tweedie for the 2.2 branch, and ported to 2.4 kernels by Peter Braam, Andreas Dilger, Andrew Morton, Alexander Viro, Ted Ts'o and Stephen Tweedie. -Ext3 is the ext2 filesystem enhanced with journalling capabilities. +Ext3 is the ext2 filesystem enhanced with journalling capabilities. The +filesystem is a subset of ext4 filesystem so use ext4 driver for accessing +ext3 filesystems. -Options -======= - -When mounting an ext3 filesystem, the following option are accepted: -(*) == default - -ro Mount filesystem read only. Note that ext3 will replay - the journal (and thus write to the partition) even when - mounted "read only". Mount options "ro,noload" can be - used to prevent writes to the filesystem. - -journal=update Update the ext3 file system's journal to the current - format. - -journal=inum When a journal already exists, this option is ignored. - Otherwise, it specifies the number of the inode which - will represent the ext3 file system's journal file. - -journal_path=path -journal_dev=devnum When the external journal device's major/minor numbers - have changed, these options allow the user to specify - the new journal location. The journal device is - identified through either its new major/minor numbers - encoded in devnum, or via a path to the device. - -norecovery Don't load the journal on mounting. Note that this forces -noload mount of inconsistent filesystem, which can lead to - various problems. - -data=journal All data are committed into the journal prior to being - written into the main file system. - -data=ordered (*) All data are forced directly out to the main file - system prior to its metadata being committed to the - journal. - -data=writeback Data ordering is not preserved, data may be written - into the main file system after its metadata has been - committed to the journal. - -commit=nrsec (*) Ext3 can be told to sync all its data and metadata - every 'nrsec' seconds. The default value is 5 seconds. - This means that if you lose your power, you will lose - as much as the latest 5 seconds of work (your - filesystem will not be damaged though, thanks to the - journaling). This default value (or any low value) - will hurt performance, but it's good for data-safety. - Setting it to 0 will have the same effect as leaving - it at the default (5 seconds). - Setting it to very large values will improve - performance. - -barrier=<0|1(*)> This enables/disables the use of write barriers in -barrier (*) the jbd code. barrier=0 disables, barrier=1 enables. -nobarrier This also requires an IO stack which can support - barriers, and if jbd gets an error on a barrier - write, it will disable again with a warning. - Write barriers enforce proper on-disk ordering - of journal commits, making volatile disk write caches - safe to use, at some performance penalty. If - your disks are battery-backed in one way or another, - disabling barriers may safely improve performance. - The mount options "barrier" and "nobarrier" can - also be used to enable or disable barriers, for - consistency with other ext3 mount options. - -user_xattr Enables Extended User Attributes. Additionally, you - need to have extended attribute support enabled in the - kernel configuration (CONFIG_EXT3_FS_XATTR). See the - attr(5) manual page and http://acl.bestbits.at/ to - learn more about extended attributes. - -nouser_xattr Disables Extended User Attributes. - -acl Enables POSIX Access Control Lists support. - Additionally, you need to have ACL support enabled in - the kernel configuration (CONFIG_EXT3_FS_POSIX_ACL). - See the acl(5) manual page and http://acl.bestbits.at/ - for more information. - -noacl This option disables POSIX Access Control List - support. - -reservation - -noreservation - -bsddf (*) Make 'df' act like BSD. -minixdf Make 'df' act like Minix. - -check=none Don't do extra checking of bitmaps on mount. -nocheck - -debug Extra debugging information is sent to syslog. - -errors=remount-ro Remount the filesystem read-only on an error. -errors=continue Keep going on a filesystem error. -errors=panic Panic and halt the machine if an error occurs. - (These mount options override the errors behavior - specified in the superblock, which can be - configured using tune2fs.) - -data_err=ignore(*) Just print an error message if an error occurs - in a file data buffer in ordered mode. -data_err=abort Abort the journal if an error occurs in a file - data buffer in ordered mode. - -grpid Give objects the same group ID as their creator. -bsdgroups - -nogrpid (*) New objects have the group ID of their creator. -sysvgroups - -resgid=n The group ID which may use the reserved blocks. - -resuid=n The user ID which may use the reserved blocks. - -sb=n Use alternate superblock at this location. - -quota These options are ignored by the filesystem. They -noquota are used only by quota tools to recognize volumes -grpquota where quota should be turned on. See documentation -usrquota in the quota-tools package for more details - (http://sourceforge.net/projects/linuxquota). - -jqfmt= These options tell filesystem details about quota -usrjquota= so that quota information can be properly updated -grpjquota= during journal replay. They replace the above - quota options. See documentation in the quota-tools - package for more details - (http://sourceforge.net/projects/linuxquota). - -Specification -============= -Ext3 shares all disk implementation with the ext2 filesystem, and adds -transactions capabilities to ext2. Journaling is done by the Journaling Block -Device layer. - -Journaling Block Device layer ------------------------------ -The Journaling Block Device layer (JBD) isn't ext3 specific. It was designed -to add journaling capabilities to a block device. The ext3 filesystem code -will inform the JBD of modifications it is performing (called a transaction). -The journal supports the transactions start and stop, and in case of a crash, -the journal can replay the transactions to quickly put the partition back into -a consistent state. - -Handles represent a single atomic update to a filesystem. JBD can handle an -external journal on a block device. - -Data Mode ---------- -There are 3 different data modes: - -* writeback mode -In data=writeback mode, ext3 does not journal data at all. This mode provides -a similar level of journaling as that of XFS, JFS, and ReiserFS in its default -mode - metadata journaling. A crash+recovery can cause incorrect data to -appear in files which were written shortly before the crash. This mode will -typically provide the best ext3 performance. - -* ordered mode -In data=ordered mode, ext3 only officially journals metadata, but it logically -groups metadata and data blocks into a single unit called a transaction. When -it's time to write the new metadata out to disk, the associated data blocks -are written first. In general, this mode performs slightly slower than -writeback but significantly faster than journal mode. - -* journal mode -data=journal mode provides full data and metadata journaling. All new data is -written to the journal first, and then to its final location. -In the event of a crash, the journal can be replayed, bringing both data and -metadata into a consistent state. This mode is the slowest except when data -needs to be read from and written to disk at the same time where it -outperforms all other modes. - -Compatibility -------------- - -Ext2 partitions can be easily convert to ext3, with `tune2fs -j `. -Ext3 is fully compatible with Ext2. Ext3 partitions can easily be mounted as -Ext2. - - -External Tools -============== -See manual pages to learn more. - -tune2fs: create a ext3 journal on a ext2 partition with the -j flag. -mke2fs: create a ext3 partition with the -j flag. -debugfs: ext2 and ext3 file system debugger. -ext2online: online (mounted) ext2 and ext3 filesystem resizer - - -References -========== - -kernel source: - - -programs: http://e2fsprogs.sourceforge.net/ - http://ext2resize.sourceforge.net - -useful links: http://www.ibm.com/developerworks/library/l-fs7/index.html - http://www.ibm.com/developerworks/library/l-fs8/index.html diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 5eb8456fc41eb..8c6f07ad373aa 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt @@ -769,7 +769,7 @@ struct address_space_operations { to stall to allow flushers a chance to complete some IO. Ordinarily it can use PageDirty and PageWriteback but some filesystems have more complex state (unstable pages in NFS prevent reclaim) or - do not set those flags due to locking problems (jbd). This callback + do not set those flags due to locking problems. This callback allows a filesystem to indicate to the VM if a page should be treated as dirty or writeback for the purposes of stalling. diff --git a/MAINTAINERS b/MAINTAINERS index a2264167791ac..0555bdb72c0dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4059,15 +4059,6 @@ F: Documentation/filesystems/ext2.txt F: fs/ext2/ F: include/linux/ext2* -EXT3 FILE SYSTEM -M: Jan Kara -M: Andrew Morton -M: Andreas Dilger -L: linux-ext4@vger.kernel.org -S: Maintained -F: Documentation/filesystems/ext3.txt -F: fs/ext3/ - EXT4 FILE SYSTEM M: "Theodore Ts'o" M: Andreas Dilger @@ -5751,16 +5742,9 @@ S: Maintained F: fs/jffs2/ F: include/uapi/linux/jffs2.h -JOURNALLING LAYER FOR BLOCK DEVICES (JBD) -M: Andrew Morton -M: Jan Kara -L: linux-ext4@vger.kernel.org -S: Maintained -F: fs/jbd/ -F: include/linux/jbd.h - JOURNALLING LAYER FOR BLOCK DEVICES (JBD2) M: "Theodore Ts'o" +M: Jan Kara L: linux-ext4@vger.kernel.org S: Maintained F: fs/jbd2/ diff --git a/fs/Kconfig b/fs/Kconfig index 011f43365d7b1..da3f32f1a4e4b 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -11,18 +11,15 @@ config DCACHE_WORD_ACCESS if BLOCK source "fs/ext2/Kconfig" -source "fs/ext3/Kconfig" source "fs/ext4/Kconfig" -source "fs/jbd/Kconfig" source "fs/jbd2/Kconfig" config FS_MBCACHE # Meta block cache for Extended Attributes (ext2/ext3/ext4) tristate default y if EXT2_FS=y && EXT2_FS_XATTR - default y if EXT3_FS=y && EXT3_FS_XATTR default y if EXT4_FS=y - default m if EXT2_FS_XATTR || EXT3_FS_XATTR || EXT4_FS + default m if EXT2_FS_XATTR || EXT4_FS source "fs/reiserfs/Kconfig" source "fs/jfs/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index cb20e4bf23039..09e051fefc5b4 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -62,12 +62,10 @@ obj-$(CONFIG_DLM) += dlm/ # Do not add any filesystems before this line obj-$(CONFIG_FSCACHE) += fscache/ obj-$(CONFIG_REISERFS_FS) += reiserfs/ -obj-$(CONFIG_EXT3_FS) += ext3/ # Before ext2 so root fs can be ext3 obj-$(CONFIG_EXT2_FS) += ext2/ # We place ext4 after ext2 so plain ext2 root fs's are mounted using ext2 # unless explicitly requested by rootfstype obj-$(CONFIG_EXT4_FS) += ext4/ -obj-$(CONFIG_JBD) += jbd/ obj-$(CONFIG_JBD2) += jbd2/ obj-$(CONFIG_CRAMFS) += cramfs/ obj-$(CONFIG_SQUASHFS) += squashfs/ diff --git a/fs/ext3/Kconfig b/fs/ext3/Kconfig deleted file mode 100644 index e8c6ba0e4a3ea..0000000000000 --- a/fs/ext3/Kconfig +++ /dev/null @@ -1,89 +0,0 @@ -config EXT3_FS - tristate "Ext3 journalling file system support" - select JBD - help - This is the journalling version of the Second extended file system - (often called ext3), the de facto standard Linux file system - (method to organize files on a storage device) for hard disks. - - The journalling code included in this driver means you do not have - to run e2fsck (file system checker) on your file systems after a - crash. The journal keeps track of any changes that were being made - at the time the system crashed, and can ensure that your file system - is consistent without the need for a lengthy check. - - Other than adding the journal to the file system, the on-disk format - of ext3 is identical to ext2. It is possible to freely switch - between using the ext3 driver and the ext2 driver, as long as the - file system has been cleanly unmounted, or e2fsck is run on the file - system. - - To add a journal on an existing ext2 file system or change the - behavior of ext3 file systems, you can use the tune2fs utility ("man - tune2fs"). To modify attributes of files and directories on ext3 - file systems, use chattr ("man chattr"). You need to be using - e2fsprogs version 1.20 or later in order to create ext3 journals - (available at ). - - To compile this file system support as a module, choose M here: the - module will be called ext3. - -config EXT3_DEFAULTS_TO_ORDERED - bool "Default to 'data=ordered' in ext3" - depends on EXT3_FS - default y - help - The journal mode options for ext3 have different tradeoffs - between when data is guaranteed to be on disk and - performance. The use of "data=writeback" can cause - unwritten data to appear in files after an system crash or - power failure, which can be a security issue. However, - "data=ordered" mode can also result in major performance - problems, including seconds-long delays before an fsync() - call returns. For details, see: - - http://ext4.wiki.kernel.org/index.php/Ext3_data_mode_tradeoffs - - If you have been historically happy with ext3's performance, - data=ordered mode will be a safe choice and you should - answer 'y' here. If you understand the reliability and data - privacy issues of data=writeback and are willing to make - that trade off, answer 'n'. - -config EXT3_FS_XATTR - bool "Ext3 extended attributes" - depends on EXT3_FS - default y - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - If unsure, say N. - - You need this for POSIX ACL support on ext3. - -config EXT3_FS_POSIX_ACL - bool "Ext3 POSIX Access Control Lists" - depends on EXT3_FS_XATTR - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config EXT3_FS_SECURITY - bool "Ext3 Security Labels" - depends on EXT3_FS_XATTR - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the ext3 filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. diff --git a/fs/ext3/Makefile b/fs/ext3/Makefile deleted file mode 100644 index e77766a8b3f07..0000000000000 --- a/fs/ext3/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile for the linux ext3-filesystem routines. -# - -obj-$(CONFIG_EXT3_FS) += ext3.o - -ext3-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ - ioctl.o namei.o super.o symlink.o hash.o resize.o ext3_jbd.o - -ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o -ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o -ext3-$(CONFIG_EXT3_FS_SECURITY) += xattr_security.o diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c deleted file mode 100644 index 8bbaf5bcf9820..0000000000000 --- a/fs/ext3/acl.c +++ /dev/null @@ -1,281 +0,0 @@ -/* - * linux/fs/ext3/acl.c - * - * Copyright (C) 2001-2003 Andreas Gruenbacher, - */ - -#include "ext3.h" -#include "xattr.h" -#include "acl.h" - -/* - * Convert from filesystem to in-memory representation. - */ -static struct posix_acl * -ext3_acl_from_disk(const void *value, size_t size) -{ - const char *end = (char *)value + size; - int n, count; - struct posix_acl *acl; - - if (!value) - return NULL; - if (size < sizeof(ext3_acl_header)) - return ERR_PTR(-EINVAL); - if (((ext3_acl_header *)value)->a_version != - cpu_to_le32(EXT3_ACL_VERSION)) - return ERR_PTR(-EINVAL); - value = (char *)value + sizeof(ext3_acl_header); - count = ext3_acl_count(size); - if (count < 0) - return ERR_PTR(-EINVAL); - if (count == 0) - return NULL; - acl = posix_acl_alloc(count, GFP_NOFS); - if (!acl) - return ERR_PTR(-ENOMEM); - for (n=0; n < count; n++) { - ext3_acl_entry *entry = - (ext3_acl_entry *)value; - if ((char *)value + sizeof(ext3_acl_entry_short) > end) - goto fail; - acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); - acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); - switch(acl->a_entries[n].e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - value = (char *)value + - sizeof(ext3_acl_entry_short); - break; - - case ACL_USER: - value = (char *)value + sizeof(ext3_acl_entry); - if ((char *)value > end) - goto fail; - acl->a_entries[n].e_uid = - make_kuid(&init_user_ns, - le32_to_cpu(entry->e_id)); - break; - case ACL_GROUP: - value = (char *)value + sizeof(ext3_acl_entry); - if ((char *)value > end) - goto fail; - acl->a_entries[n].e_gid = - make_kgid(&init_user_ns, - le32_to_cpu(entry->e_id)); - break; - - default: - goto fail; - } - } - if (value != end) - goto fail; - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} - -/* - * Convert from in-memory to filesystem representation. - */ -static void * -ext3_acl_to_disk(const struct posix_acl *acl, size_t *size) -{ - ext3_acl_header *ext_acl; - char *e; - size_t n; - - *size = ext3_acl_size(acl->a_count); - ext_acl = kmalloc(sizeof(ext3_acl_header) + acl->a_count * - sizeof(ext3_acl_entry), GFP_NOFS); - if (!ext_acl) - return ERR_PTR(-ENOMEM); - ext_acl->a_version = cpu_to_le32(EXT3_ACL_VERSION); - e = (char *)ext_acl + sizeof(ext3_acl_header); - for (n=0; n < acl->a_count; n++) { - const struct posix_acl_entry *acl_e = &acl->a_entries[n]; - ext3_acl_entry *entry = (ext3_acl_entry *)e; - entry->e_tag = cpu_to_le16(acl_e->e_tag); - entry->e_perm = cpu_to_le16(acl_e->e_perm); - switch(acl_e->e_tag) { - case ACL_USER: - entry->e_id = cpu_to_le32( - from_kuid(&init_user_ns, acl_e->e_uid)); - e += sizeof(ext3_acl_entry); - break; - case ACL_GROUP: - entry->e_id = cpu_to_le32( - from_kgid(&init_user_ns, acl_e->e_gid)); - e += sizeof(ext3_acl_entry); - break; - - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - e += sizeof(ext3_acl_entry_short); - break; - - default: - goto fail; - } - } - return (char *)ext_acl; - -fail: - kfree(ext_acl); - return ERR_PTR(-EINVAL); -} - -/* - * Inode operation get_posix_acl(). - * - * inode->i_mutex: don't care - */ -struct posix_acl * -ext3_get_acl(struct inode *inode, int type) -{ - int name_index; - char *value = NULL; - struct posix_acl *acl; - int retval; - - switch (type) { - case ACL_TYPE_ACCESS: - name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; - break; - default: - BUG(); - } - - retval = ext3_xattr_get(inode, name_index, "", NULL, 0); - if (retval > 0) { - value = kmalloc(retval, GFP_NOFS); - if (!value) - return ERR_PTR(-ENOMEM); - retval = ext3_xattr_get(inode, name_index, "", value, retval); - } - if (retval > 0) - acl = ext3_acl_from_disk(value, retval); - else if (retval == -ENODATA || retval == -ENOSYS) - acl = NULL; - else - acl = ERR_PTR(retval); - kfree(value); - - if (!IS_ERR(acl)) - set_cached_acl(inode, type, acl); - - return acl; -} - -/* - * Set the access or default ACL of an inode. - * - * inode->i_mutex: down unless called from ext3_new_inode - */ -static int -__ext3_set_acl(handle_t *handle, struct inode *inode, int type, - struct posix_acl *acl) -{ - int name_index; - void *value = NULL; - size_t size = 0; - int error; - - switch(type) { - case ACL_TYPE_ACCESS: - name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS; - if (acl) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) - return error; - else { - inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); - if (error == 0) - acl = NULL; - } - } - break; - - case ACL_TYPE_DEFAULT: - name_index = EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT; - if (!S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - break; - - default: - return -EINVAL; - } - if (acl) { - value = ext3_acl_to_disk(acl, &size); - if (IS_ERR(value)) - return (int)PTR_ERR(value); - } - - error = ext3_xattr_set_handle(handle, inode, name_index, "", - value, size, 0); - - kfree(value); - - if (!error) - set_cached_acl(inode, type, acl); - - return error; -} - -int -ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type) -{ - handle_t *handle; - int error, retries = 0; - -retry: - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - error = __ext3_set_acl(handle, inode, type, acl); - ext3_journal_stop(handle); - if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - return error; -} - -/* - * Initialize the ACLs of a new inode. Called from ext3_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ -int -ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) -{ - struct posix_acl *default_acl, *acl; - int error; - - error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); - if (error) - return error; - - if (default_acl) { - error = __ext3_set_acl(handle, inode, ACL_TYPE_DEFAULT, - default_acl); - posix_acl_release(default_acl); - } - if (acl) { - if (!error) - error = __ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, - acl); - posix_acl_release(acl); - } - return error; -} diff --git a/fs/ext3/acl.h b/fs/ext3/acl.h deleted file mode 100644 index ea1c69edab9e1..0000000000000 --- a/fs/ext3/acl.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - File: fs/ext3/acl.h - - (C) 2001 Andreas Gruenbacher, -*/ - -#include - -#define EXT3_ACL_VERSION 0x0001 - -typedef struct { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -} ext3_acl_entry; - -typedef struct { - __le16 e_tag; - __le16 e_perm; -} ext3_acl_entry_short; - -typedef struct { - __le32 a_version; -} ext3_acl_header; - -static inline size_t ext3_acl_size(int count) -{ - if (count <= 4) { - return sizeof(ext3_acl_header) + - count * sizeof(ext3_acl_entry_short); - } else { - return sizeof(ext3_acl_header) + - 4 * sizeof(ext3_acl_entry_short) + - (count - 4) * sizeof(ext3_acl_entry); - } -} - -static inline int ext3_acl_count(size_t size) -{ - ssize_t s; - size -= sizeof(ext3_acl_header); - s = size - 4 * sizeof(ext3_acl_entry_short); - if (s < 0) { - if (size % sizeof(ext3_acl_entry_short)) - return -1; - return size / sizeof(ext3_acl_entry_short); - } else { - if (s % sizeof(ext3_acl_entry)) - return -1; - return s / sizeof(ext3_acl_entry) + 4; - } -} - -#ifdef CONFIG_EXT3_FS_POSIX_ACL - -/* acl.c */ -extern struct posix_acl *ext3_get_acl(struct inode *inode, int type); -extern int ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type); -extern int ext3_init_acl (handle_t *, struct inode *, struct inode *); - -#else /* CONFIG_EXT3_FS_POSIX_ACL */ -#include -#define ext3_get_acl NULL -#define ext3_set_acl NULL - -static inline int -ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) -{ - return 0; -} -#endif /* CONFIG_EXT3_FS_POSIX_ACL */ - diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c deleted file mode 100644 index 158b5d4ce0670..0000000000000 --- a/fs/ext3/balloc.c +++ /dev/null @@ -1,2158 +0,0 @@ -/* - * linux/fs/ext3/balloc.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include -#include -#include "ext3.h" - -/* - * balloc.c contains the blocks allocation and deallocation routines - */ - -/* - * The free blocks are managed by bitmaps. A file system contains several - * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap - * block for inodes, N blocks for the inode table and data blocks. - * - * The file system contains group descriptors which are located after the - * super block. Each descriptor contains the number of the bitmap block and - * the free blocks count in the block. The descriptors are loaded in memory - * when a file system is mounted (see ext3_fill_super). - */ - - -#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) - -/* - * Calculate the block group number and offset, given a block number - */ -static void ext3_get_group_no_and_offset(struct super_block *sb, - ext3_fsblk_t blocknr, unsigned long *blockgrpp, ext3_grpblk_t *offsetp) -{ - struct ext3_super_block *es = EXT3_SB(sb)->s_es; - - blocknr = blocknr - le32_to_cpu(es->s_first_data_block); - if (offsetp) - *offsetp = blocknr % EXT3_BLOCKS_PER_GROUP(sb); - if (blockgrpp) - *blockgrpp = blocknr / EXT3_BLOCKS_PER_GROUP(sb); -} - -/** - * ext3_get_group_desc() -- load group descriptor from disk - * @sb: super block - * @block_group: given block group - * @bh: pointer to the buffer head to store the block - * group descriptor - */ -struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, - unsigned int block_group, - struct buffer_head ** bh) -{ - unsigned long group_desc; - unsigned long offset; - struct ext3_group_desc * desc; - struct ext3_sb_info *sbi = EXT3_SB(sb); - - if (block_group >= sbi->s_groups_count) { - ext3_error (sb, "ext3_get_group_desc", - "block_group >= groups_count - " - "block_group = %d, groups_count = %lu", - block_group, sbi->s_groups_count); - - return NULL; - } - smp_rmb(); - - group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(sb); - offset = block_group & (EXT3_DESC_PER_BLOCK(sb) - 1); - if (!sbi->s_group_desc[group_desc]) { - ext3_error (sb, "ext3_get_group_desc", - "Group descriptor not loaded - " - "block_group = %d, group_desc = %lu, desc = %lu", - block_group, group_desc, offset); - return NULL; - } - - desc = (struct ext3_group_desc *) sbi->s_group_desc[group_desc]->b_data; - if (bh) - *bh = sbi->s_group_desc[group_desc]; - return desc + offset; -} - -static int ext3_valid_block_bitmap(struct super_block *sb, - struct ext3_group_desc *desc, - unsigned int block_group, - struct buffer_head *bh) -{ - ext3_grpblk_t offset; - ext3_grpblk_t next_zero_bit; - ext3_fsblk_t bitmap_blk; - ext3_fsblk_t group_first_block; - - group_first_block = ext3_group_first_block_no(sb, block_group); - - /* check whether block bitmap block number is set */ - bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); - offset = bitmap_blk - group_first_block; - if (!ext3_test_bit(offset, bh->b_data)) - /* bad block bitmap */ - goto err_out; - - /* check whether the inode bitmap block number is set */ - bitmap_blk = le32_to_cpu(desc->bg_inode_bitmap); - offset = bitmap_blk - group_first_block; - if (!ext3_test_bit(offset, bh->b_data)) - /* bad block bitmap */ - goto err_out; - - /* check whether the inode table block number is set */ - bitmap_blk = le32_to_cpu(desc->bg_inode_table); - offset = bitmap_blk - group_first_block; - next_zero_bit = ext3_find_next_zero_bit(bh->b_data, - offset + EXT3_SB(sb)->s_itb_per_group, - offset); - if (next_zero_bit >= offset + EXT3_SB(sb)->s_itb_per_group) - /* good bitmap for inode tables */ - return 1; - -err_out: - ext3_error(sb, __func__, - "Invalid block bitmap - " - "block_group = %d, block = %lu", - block_group, bitmap_blk); - return 0; -} - -/** - * read_block_bitmap() - * @sb: super block - * @block_group: given block group - * - * Read the bitmap for a given block_group,and validate the - * bits for block/inode/inode tables are set in the bitmaps - * - * Return buffer_head on success or NULL in case of failure. - */ -static struct buffer_head * -read_block_bitmap(struct super_block *sb, unsigned int block_group) -{ - struct ext3_group_desc * desc; - struct buffer_head * bh = NULL; - ext3_fsblk_t bitmap_blk; - - desc = ext3_get_group_desc(sb, block_group, NULL); - if (!desc) - return NULL; - trace_ext3_read_block_bitmap(sb, block_group); - bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); - bh = sb_getblk(sb, bitmap_blk); - if (unlikely(!bh)) { - ext3_error(sb, __func__, - "Cannot read block bitmap - " - "block_group = %d, block_bitmap = %u", - block_group, le32_to_cpu(desc->bg_block_bitmap)); - return NULL; - } - if (likely(bh_uptodate_or_lock(bh))) - return bh; - - if (bh_submit_read(bh) < 0) { - brelse(bh); - ext3_error(sb, __func__, - "Cannot read block bitmap - " - "block_group = %d, block_bitmap = %u", - block_group, le32_to_cpu(desc->bg_block_bitmap)); - return NULL; - } - ext3_valid_block_bitmap(sb, desc, block_group, bh); - /* - * file system mounted not to panic on error, continue with corrupt - * bitmap - */ - return bh; -} -/* - * The reservation window structure operations - * -------------------------------------------- - * Operations include: - * dump, find, add, remove, is_empty, find_next_reservable_window, etc. - * - * We use a red-black tree to represent per-filesystem reservation - * windows. - * - */ - -/** - * __rsv_window_dump() -- Dump the filesystem block allocation reservation map - * @rb_root: root of per-filesystem reservation rb tree - * @verbose: verbose mode - * @fn: function which wishes to dump the reservation map - * - * If verbose is turned on, it will print the whole block reservation - * windows(start, end). Otherwise, it will only print out the "bad" windows, - * those windows that overlap with their immediate neighbors. - */ -#if 1 -static void __rsv_window_dump(struct rb_root *root, int verbose, - const char *fn) -{ - struct rb_node *n; - struct ext3_reserve_window_node *rsv, *prev; - int bad; - -restart: - n = rb_first(root); - bad = 0; - prev = NULL; - - printk("Block Allocation Reservation Windows Map (%s):\n", fn); - while (n) { - rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); - if (verbose) - printk("reservation window 0x%p " - "start: %lu, end: %lu\n", - rsv, rsv->rsv_start, rsv->rsv_end); - if (rsv->rsv_start && rsv->rsv_start >= rsv->rsv_end) { - printk("Bad reservation %p (start >= end)\n", - rsv); - bad = 1; - } - if (prev && prev->rsv_end >= rsv->rsv_start) { - printk("Bad reservation %p (prev->end >= start)\n", - rsv); - bad = 1; - } - if (bad) { - if (!verbose) { - printk("Restarting reservation walk in verbose mode\n"); - verbose = 1; - goto restart; - } - } - n = rb_next(n); - prev = rsv; - } - printk("Window map complete.\n"); - BUG_ON(bad); -} -#define rsv_window_dump(root, verbose) \ - __rsv_window_dump((root), (verbose), __func__) -#else -#define rsv_window_dump(root, verbose) do {} while (0) -#endif - -/** - * goal_in_my_reservation() - * @rsv: inode's reservation window - * @grp_goal: given goal block relative to the allocation block group - * @group: the current allocation block group - * @sb: filesystem super block - * - * Test if the given goal block (group relative) is within the file's - * own block reservation window range. - * - * If the reservation window is outside the goal allocation group, return 0; - * grp_goal (given goal block) could be -1, which means no specific - * goal block. In this case, always return 1. - * If the goal block is within the reservation window, return 1; - * otherwise, return 0; - */ -static int -goal_in_my_reservation(struct ext3_reserve_window *rsv, ext3_grpblk_t grp_goal, - unsigned int group, struct super_block * sb) -{ - ext3_fsblk_t group_first_block, group_last_block; - - group_first_block = ext3_group_first_block_no(sb, group); - group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); - - if ((rsv->_rsv_start > group_last_block) || - (rsv->_rsv_end < group_first_block)) - return 0; - if ((grp_goal >= 0) && ((grp_goal + group_first_block < rsv->_rsv_start) - || (grp_goal + group_first_block > rsv->_rsv_end))) - return 0; - return 1; -} - -/** - * search_reserve_window() - * @rb_root: root of reservation tree - * @goal: target allocation block - * - * Find the reserved window which includes the goal, or the previous one - * if the goal is not in any window. - * Returns NULL if there are no windows or if all windows start after the goal. - */ -static struct ext3_reserve_window_node * -search_reserve_window(struct rb_root *root, ext3_fsblk_t goal) -{ - struct rb_node *n = root->rb_node; - struct ext3_reserve_window_node *rsv; - - if (!n) - return NULL; - - do { - rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); - - if (goal < rsv->rsv_start) - n = n->rb_left; - else if (goal > rsv->rsv_end) - n = n->rb_right; - else - return rsv; - } while (n); - /* - * We've fallen off the end of the tree: the goal wasn't inside - * any particular node. OK, the previous node must be to one - * side of the interval containing the goal. If it's the RHS, - * we need to back up one. - */ - if (rsv->rsv_start > goal) { - n = rb_prev(&rsv->rsv_node); - rsv = rb_entry(n, struct ext3_reserve_window_node, rsv_node); - } - return rsv; -} - -/** - * ext3_rsv_window_add() -- Insert a window to the block reservation rb tree. - * @sb: super block - * @rsv: reservation window to add - * - * Must be called with rsv_lock hold. - */ -void ext3_rsv_window_add(struct super_block *sb, - struct ext3_reserve_window_node *rsv) -{ - struct rb_root *root = &EXT3_SB(sb)->s_rsv_window_root; - struct rb_node *node = &rsv->rsv_node; - ext3_fsblk_t start = rsv->rsv_start; - - struct rb_node ** p = &root->rb_node; - struct rb_node * parent = NULL; - struct ext3_reserve_window_node *this; - - trace_ext3_rsv_window_add(sb, rsv); - while (*p) - { - parent = *p; - this = rb_entry(parent, struct ext3_reserve_window_node, rsv_node); - - if (start < this->rsv_start) - p = &(*p)->rb_left; - else if (start > this->rsv_end) - p = &(*p)->rb_right; - else { - rsv_window_dump(root, 1); - BUG(); - } - } - - rb_link_node(node, parent, p); - rb_insert_color(node, root); -} - -/** - * ext3_rsv_window_remove() -- unlink a window from the reservation rb tree - * @sb: super block - * @rsv: reservation window to remove - * - * Mark the block reservation window as not allocated, and unlink it - * from the filesystem reservation window rb tree. Must be called with - * rsv_lock hold. - */ -static void rsv_window_remove(struct super_block *sb, - struct ext3_reserve_window_node *rsv) -{ - rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_alloc_hit = 0; - rb_erase(&rsv->rsv_node, &EXT3_SB(sb)->s_rsv_window_root); -} - -/* - * rsv_is_empty() -- Check if the reservation window is allocated. - * @rsv: given reservation window to check - * - * returns 1 if the end block is EXT3_RESERVE_WINDOW_NOT_ALLOCATED. - */ -static inline int rsv_is_empty(struct ext3_reserve_window *rsv) -{ - /* a valid reservation end block could not be 0 */ - return rsv->_rsv_end == EXT3_RESERVE_WINDOW_NOT_ALLOCATED; -} - -/** - * ext3_init_block_alloc_info() - * @inode: file inode structure - * - * Allocate and initialize the reservation window structure, and - * link the window to the ext3 inode structure at last - * - * The reservation window structure is only dynamically allocated - * and linked to ext3 inode the first time the open file - * needs a new block. So, before every ext3_new_block(s) call, for - * regular files, we should check whether the reservation window - * structure exists or not. In the latter case, this function is called. - * Fail to do so will result in block reservation being turned off for that - * open file. - * - * This function is called from ext3_get_blocks_handle(), also called - * when setting the reservation window size through ioctl before the file - * is open for write (needs block allocation). - * - * Needs truncate_mutex protection prior to call this function. - */ -void ext3_init_block_alloc_info(struct inode *inode) -{ - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_block_alloc_info *block_i; - struct super_block *sb = inode->i_sb; - - block_i = kmalloc(sizeof(*block_i), GFP_NOFS); - if (block_i) { - struct ext3_reserve_window_node *rsv = &block_i->rsv_window_node; - - rsv->rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - rsv->rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - - /* - * if filesystem is mounted with NORESERVATION, the goal - * reservation window size is set to zero to indicate - * block reservation is off - */ - if (!test_opt(sb, RESERVATION)) - rsv->rsv_goal_size = 0; - else - rsv->rsv_goal_size = EXT3_DEFAULT_RESERVE_BLOCKS; - rsv->rsv_alloc_hit = 0; - block_i->last_alloc_logical_block = 0; - block_i->last_alloc_physical_block = 0; - } - ei->i_block_alloc_info = block_i; -} - -/** - * ext3_discard_reservation() - * @inode: inode - * - * Discard(free) block reservation window on last file close, or truncate - * or at last iput(). - * - * It is being called in three cases: - * ext3_release_file(): last writer close the file - * ext3_clear_inode(): last iput(), when nobody link to this file. - * ext3_truncate(): when the block indirect map is about to change. - * - */ -void ext3_discard_reservation(struct inode *inode) -{ - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_block_alloc_info *block_i = ei->i_block_alloc_info; - struct ext3_reserve_window_node *rsv; - spinlock_t *rsv_lock = &EXT3_SB(inode->i_sb)->s_rsv_window_lock; - - if (!block_i) - return; - - rsv = &block_i->rsv_window_node; - if (!rsv_is_empty(&rsv->rsv_window)) { - spin_lock(rsv_lock); - if (!rsv_is_empty(&rsv->rsv_window)) { - trace_ext3_discard_reservation(inode, rsv); - rsv_window_remove(inode->i_sb, rsv); - } - spin_unlock(rsv_lock); - } -} - -/** - * ext3_free_blocks_sb() -- Free given blocks and update quota - * @handle: handle to this transaction - * @sb: super block - * @block: start physical block to free - * @count: number of blocks to free - * @pdquot_freed_blocks: pointer to quota - */ -void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb, - ext3_fsblk_t block, unsigned long count, - unsigned long *pdquot_freed_blocks) -{ - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *gd_bh; - unsigned long block_group; - ext3_grpblk_t bit; - unsigned long i; - unsigned long overflow; - struct ext3_group_desc * desc; - struct ext3_super_block * es; - struct ext3_sb_info *sbi; - int err = 0, ret; - ext3_grpblk_t group_freed; - - *pdquot_freed_blocks = 0; - sbi = EXT3_SB(sb); - es = sbi->s_es; - if (block < le32_to_cpu(es->s_first_data_block) || - block + count < block || - block + count > le32_to_cpu(es->s_blocks_count)) { - ext3_error (sb, "ext3_free_blocks", - "Freeing blocks not in datazone - " - "block = "E3FSBLK", count = %lu", block, count); - goto error_return; - } - - ext3_debug ("freeing block(s) %lu-%lu\n", block, block + count - 1); - -do_more: - overflow = 0; - block_group = (block - le32_to_cpu(es->s_first_data_block)) / - EXT3_BLOCKS_PER_GROUP(sb); - bit = (block - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb); - /* - * Check to see if we are freeing blocks across a group - * boundary. - */ - if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) { - overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb); - count -= overflow; - } - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, block_group); - if (!bitmap_bh) - goto error_return; - desc = ext3_get_group_desc (sb, block_group, &gd_bh); - if (!desc) - goto error_return; - - if (in_range (le32_to_cpu(desc->bg_block_bitmap), block, count) || - in_range (le32_to_cpu(desc->bg_inode_bitmap), block, count) || - in_range (block, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group) || - in_range (block + count - 1, le32_to_cpu(desc->bg_inode_table), - sbi->s_itb_per_group)) { - ext3_error (sb, "ext3_free_blocks", - "Freeing blocks in system zones - " - "Block = "E3FSBLK", count = %lu", - block, count); - goto error_return; - } - - /* - * We are about to start releasing blocks in the bitmap, - * so we need undo access. - */ - /* @@@ check errors */ - BUFFER_TRACE(bitmap_bh, "getting undo access"); - err = ext3_journal_get_undo_access(handle, bitmap_bh); - if (err) - goto error_return; - - /* - * We are about to modify some metadata. Call the journal APIs - * to unshare ->b_data if a currently-committing transaction is - * using it - */ - BUFFER_TRACE(gd_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, gd_bh); - if (err) - goto error_return; - - jbd_lock_bh_state(bitmap_bh); - - for (i = 0, group_freed = 0; i < count; i++) { - /* - * An HJ special. This is expensive... - */ -#ifdef CONFIG_JBD_DEBUG - jbd_unlock_bh_state(bitmap_bh); - { - struct buffer_head *debug_bh; - debug_bh = sb_find_get_block(sb, block + i); - if (debug_bh) { - BUFFER_TRACE(debug_bh, "Deleted!"); - if (!bh2jh(bitmap_bh)->b_committed_data) - BUFFER_TRACE(debug_bh, - "No committed data in bitmap"); - BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap"); - __brelse(debug_bh); - } - } - jbd_lock_bh_state(bitmap_bh); -#endif - if (need_resched()) { - jbd_unlock_bh_state(bitmap_bh); - cond_resched(); - jbd_lock_bh_state(bitmap_bh); - } - /* @@@ This prevents newly-allocated data from being - * freed and then reallocated within the same - * transaction. - * - * Ideally we would want to allow that to happen, but to - * do so requires making journal_forget() capable of - * revoking the queued write of a data block, which - * implies blocking on the journal lock. *forget() - * cannot block due to truncate races. - * - * Eventually we can fix this by making journal_forget() - * return a status indicating whether or not it was able - * to revoke the buffer. On successful revoke, it is - * safe not to set the allocation bit in the committed - * bitmap, because we know that there is no outstanding - * activity on the buffer any more and so it is safe to - * reallocate it. - */ - BUFFER_TRACE(bitmap_bh, "set in b_committed_data"); - J_ASSERT_BH(bitmap_bh, - bh2jh(bitmap_bh)->b_committed_data != NULL); - ext3_set_bit_atomic(sb_bgl_lock(sbi, block_group), bit + i, - bh2jh(bitmap_bh)->b_committed_data); - - /* - * We clear the bit in the bitmap after setting the committed - * data bit, because this is the reverse order to that which - * the allocator uses. - */ - BUFFER_TRACE(bitmap_bh, "clear bit"); - if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), - bit + i, bitmap_bh->b_data)) { - jbd_unlock_bh_state(bitmap_bh); - ext3_error(sb, __func__, - "bit already cleared for block "E3FSBLK, - block + i); - jbd_lock_bh_state(bitmap_bh); - BUFFER_TRACE(bitmap_bh, "bit already cleared"); - } else { - group_freed++; - } - } - jbd_unlock_bh_state(bitmap_bh); - - spin_lock(sb_bgl_lock(sbi, block_group)); - le16_add_cpu(&desc->bg_free_blocks_count, group_freed); - spin_unlock(sb_bgl_lock(sbi, block_group)); - percpu_counter_add(&sbi->s_freeblocks_counter, count); - - /* We dirtied the bitmap block */ - BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); - - /* And the group descriptor block */ - BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); - ret = ext3_journal_dirty_metadata(handle, gd_bh); - if (!err) err = ret; - *pdquot_freed_blocks += group_freed; - - if (overflow && !err) { - block += count; - count = overflow; - goto do_more; - } - -error_return: - brelse(bitmap_bh); - ext3_std_error(sb, err); - return; -} - -/** - * ext3_free_blocks() -- Free given blocks and update quota - * @handle: handle for this transaction - * @inode: inode - * @block: start physical block to free - * @count: number of blocks to count - */ -void ext3_free_blocks(handle_t *handle, struct inode *inode, - ext3_fsblk_t block, unsigned long count) -{ - struct super_block *sb = inode->i_sb; - unsigned long dquot_freed_blocks; - - trace_ext3_free_blocks(inode, block, count); - ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); - if (dquot_freed_blocks) - dquot_free_block(inode, dquot_freed_blocks); - return; -} - -/** - * ext3_test_allocatable() - * @nr: given allocation block group - * @bh: bufferhead contains the bitmap of the given block group - * - * For ext3 allocations, we must not reuse any blocks which are - * allocated in the bitmap buffer's "last committed data" copy. This - * prevents deletes from freeing up the page for reuse until we have - * committed the delete transaction. - * - * If we didn't do this, then deleting something and reallocating it as - * data would allow the old block to be overwritten before the - * transaction committed (because we force data to disk before commit). - * This would lead to corruption if we crashed between overwriting the - * data and committing the delete. - * - * @@@ We may want to make this allocation behaviour conditional on - * data-writes at some point, and disable it for metadata allocations or - * sync-data inodes. - */ -static int ext3_test_allocatable(ext3_grpblk_t nr, struct buffer_head *bh) -{ - int ret; - struct journal_head *jh = bh2jh(bh); - - if (ext3_test_bit(nr, bh->b_data)) - return 0; - - jbd_lock_bh_state(bh); - if (!jh->b_committed_data) - ret = 1; - else - ret = !ext3_test_bit(nr, jh->b_committed_data); - jbd_unlock_bh_state(bh); - return ret; -} - -/** - * bitmap_search_next_usable_block() - * @start: the starting block (group relative) of the search - * @bh: bufferhead contains the block group bitmap - * @maxblocks: the ending block (group relative) of the reservation - * - * The bitmap search --- search forward alternately through the actual - * bitmap on disk and the last-committed copy in journal, until we find a - * bit free in both bitmaps. - */ -static ext3_grpblk_t -bitmap_search_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, - ext3_grpblk_t maxblocks) -{ - ext3_grpblk_t next; - struct journal_head *jh = bh2jh(bh); - - while (start < maxblocks) { - next = ext3_find_next_zero_bit(bh->b_data, maxblocks, start); - if (next >= maxblocks) - return -1; - if (ext3_test_allocatable(next, bh)) - return next; - jbd_lock_bh_state(bh); - if (jh->b_committed_data) - start = ext3_find_next_zero_bit(jh->b_committed_data, - maxblocks, next); - jbd_unlock_bh_state(bh); - } - return -1; -} - -/** - * find_next_usable_block() - * @start: the starting block (group relative) to find next - * allocatable block in bitmap. - * @bh: bufferhead contains the block group bitmap - * @maxblocks: the ending block (group relative) for the search - * - * Find an allocatable block in a bitmap. We honor both the bitmap and - * its last-committed copy (if that exists), and perform the "most - * appropriate allocation" algorithm of looking for a free block near - * the initial goal; then for a free byte somewhere in the bitmap; then - * for any free bit in the bitmap. - */ -static ext3_grpblk_t -find_next_usable_block(ext3_grpblk_t start, struct buffer_head *bh, - ext3_grpblk_t maxblocks) -{ - ext3_grpblk_t here, next; - char *p, *r; - - if (start > 0) { - /* - * The goal was occupied; search forward for a free - * block within the next XX blocks. - * - * end_goal is more or less random, but it has to be - * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the - * next 64-bit boundary is simple.. - */ - ext3_grpblk_t end_goal = (start + 63) & ~63; - if (end_goal > maxblocks) - end_goal = maxblocks; - here = ext3_find_next_zero_bit(bh->b_data, end_goal, start); - if (here < end_goal && ext3_test_allocatable(here, bh)) - return here; - ext3_debug("Bit not found near goal\n"); - } - - here = start; - if (here < 0) - here = 0; - - p = bh->b_data + (here >> 3); - r = memscan(p, 0, ((maxblocks + 7) >> 3) - (here >> 3)); - next = (r - bh->b_data) << 3; - - if (next < maxblocks && next >= start && ext3_test_allocatable(next, bh)) - return next; - - /* - * The bitmap search --- search forward alternately through the actual - * bitmap and the last-committed copy until we find a bit free in - * both - */ - here = bitmap_search_next_usable_block(here, bh, maxblocks); - return here; -} - -/** - * claim_block() - * @lock: the spin lock for this block group - * @block: the free block (group relative) to allocate - * @bh: the buffer_head contains the block group bitmap - * - * We think we can allocate this block in this bitmap. Try to set the bit. - * If that succeeds then check that nobody has allocated and then freed the - * block since we saw that is was not marked in b_committed_data. If it _was_ - * allocated and freed then clear the bit in the bitmap again and return - * zero (failure). - */ -static inline int -claim_block(spinlock_t *lock, ext3_grpblk_t block, struct buffer_head *bh) -{ - struct journal_head *jh = bh2jh(bh); - int ret; - - if (ext3_set_bit_atomic(lock, block, bh->b_data)) - return 0; - jbd_lock_bh_state(bh); - if (jh->b_committed_data && ext3_test_bit(block,jh->b_committed_data)) { - ext3_clear_bit_atomic(lock, block, bh->b_data); - ret = 0; - } else { - ret = 1; - } - jbd_unlock_bh_state(bh); - return ret; -} - -/** - * ext3_try_to_allocate() - * @sb: superblock - * @handle: handle to this transaction - * @group: given allocation block group - * @bitmap_bh: bufferhead holds the block bitmap - * @grp_goal: given target block within the group - * @count: target number of blocks to allocate - * @my_rsv: reservation window - * - * Attempt to allocate blocks within a give range. Set the range of allocation - * first, then find the first free bit(s) from the bitmap (within the range), - * and at last, allocate the blocks by claiming the found free bit as allocated. - * - * To set the range of this allocation: - * if there is a reservation window, only try to allocate block(s) from the - * file's own reservation window; - * Otherwise, the allocation range starts from the give goal block, ends at - * the block group's last block. - * - * If we failed to allocate the desired block then we may end up crossing to a - * new bitmap. In that case we must release write access to the old one via - * ext3_journal_release_buffer(), else we'll run out of credits. - */ -static ext3_grpblk_t -ext3_try_to_allocate(struct super_block *sb, handle_t *handle, int group, - struct buffer_head *bitmap_bh, ext3_grpblk_t grp_goal, - unsigned long *count, struct ext3_reserve_window *my_rsv) -{ - ext3_fsblk_t group_first_block; - ext3_grpblk_t start, end; - unsigned long num = 0; - - /* we do allocation within the reservation window if we have a window */ - if (my_rsv) { - group_first_block = ext3_group_first_block_no(sb, group); - if (my_rsv->_rsv_start >= group_first_block) - start = my_rsv->_rsv_start - group_first_block; - else - /* reservation window cross group boundary */ - start = 0; - end = my_rsv->_rsv_end - group_first_block + 1; - if (end > EXT3_BLOCKS_PER_GROUP(sb)) - /* reservation window crosses group boundary */ - end = EXT3_BLOCKS_PER_GROUP(sb); - if ((start <= grp_goal) && (grp_goal < end)) - start = grp_goal; - else - grp_goal = -1; - } else { - if (grp_goal > 0) - start = grp_goal; - else - start = 0; - end = EXT3_BLOCKS_PER_GROUP(sb); - } - - BUG_ON(start > EXT3_BLOCKS_PER_GROUP(sb)); - -repeat: - if (grp_goal < 0 || !ext3_test_allocatable(grp_goal, bitmap_bh)) { - grp_goal = find_next_usable_block(start, bitmap_bh, end); - if (grp_goal < 0) - goto fail_access; - if (!my_rsv) { - int i; - - for (i = 0; i < 7 && grp_goal > start && - ext3_test_allocatable(grp_goal - 1, - bitmap_bh); - i++, grp_goal--) - ; - } - } - start = grp_goal; - - if (!claim_block(sb_bgl_lock(EXT3_SB(sb), group), - grp_goal, bitmap_bh)) { - /* - * The block was allocated by another thread, or it was - * allocated and then freed by another thread - */ - start++; - grp_goal++; - if (start >= end) - goto fail_access; - goto repeat; - } - num++; - grp_goal++; - while (num < *count && grp_goal < end - && ext3_test_allocatable(grp_goal, bitmap_bh) - && claim_block(sb_bgl_lock(EXT3_SB(sb), group), - grp_goal, bitmap_bh)) { - num++; - grp_goal++; - } - *count = num; - return grp_goal - num; -fail_access: - *count = num; - return -1; -} - -/** - * find_next_reservable_window(): - * find a reservable space within the given range. - * It does not allocate the reservation window for now: - * alloc_new_reservation() will do the work later. - * - * @search_head: the head of the searching list; - * This is not necessarily the list head of the whole filesystem - * - * We have both head and start_block to assist the search - * for the reservable space. The list starts from head, - * but we will shift to the place where start_block is, - * then start from there, when looking for a reservable space. - * - * @my_rsv: the reservation window - * - * @sb: the super block - * - * @start_block: the first block we consider to start - * the real search from - * - * @last_block: - * the maximum block number that our goal reservable space - * could start from. This is normally the last block in this - * group. The search will end when we found the start of next - * possible reservable space is out of this boundary. - * This could handle the cross boundary reservation window - * request. - * - * basically we search from the given range, rather than the whole - * reservation double linked list, (start_block, last_block) - * to find a free region that is of my size and has not - * been reserved. - * - */ -static int find_next_reservable_window( - struct ext3_reserve_window_node *search_head, - struct ext3_reserve_window_node *my_rsv, - struct super_block * sb, - ext3_fsblk_t start_block, - ext3_fsblk_t last_block) -{ - struct rb_node *next; - struct ext3_reserve_window_node *rsv, *prev; - ext3_fsblk_t cur; - int size = my_rsv->rsv_goal_size; - - /* TODO: make the start of the reservation window byte-aligned */ - /* cur = *start_block & ~7;*/ - cur = start_block; - rsv = search_head; - if (!rsv) - return -1; - - while (1) { - if (cur <= rsv->rsv_end) - cur = rsv->rsv_end + 1; - - /* TODO? - * in the case we could not find a reservable space - * that is what is expected, during the re-search, we could - * remember what's the largest reservable space we could have - * and return that one. - * - * For now it will fail if we could not find the reservable - * space with expected-size (or more)... - */ - if (cur > last_block) - return -1; /* fail */ - - prev = rsv; - next = rb_next(&rsv->rsv_node); - rsv = rb_entry(next,struct ext3_reserve_window_node,rsv_node); - - /* - * Reached the last reservation, we can just append to the - * previous one. - */ - if (!next) - break; - - if (cur + size <= rsv->rsv_start) { - /* - * Found a reserveable space big enough. We could - * have a reservation across the group boundary here - */ - break; - } - } - /* - * we come here either : - * when we reach the end of the whole list, - * and there is empty reservable space after last entry in the list. - * append it to the end of the list. - * - * or we found one reservable space in the middle of the list, - * return the reservation window that we could append to. - * succeed. - */ - - if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window))) - rsv_window_remove(sb, my_rsv); - - /* - * Let's book the whole available window for now. We will check the - * disk bitmap later and then, if there are free blocks then we adjust - * the window size if it's larger than requested. - * Otherwise, we will remove this node from the tree next time - * call find_next_reservable_window. - */ - my_rsv->rsv_start = cur; - my_rsv->rsv_end = cur + size - 1; - my_rsv->rsv_alloc_hit = 0; - - if (prev != my_rsv) - ext3_rsv_window_add(sb, my_rsv); - - return 0; -} - -/** - * alloc_new_reservation()--allocate a new reservation window - * - * To make a new reservation, we search part of the filesystem - * reservation list (the list that inside the group). We try to - * allocate a new reservation window near the allocation goal, - * or the beginning of the group, if there is no goal. - * - * We first find a reservable space after the goal, then from - * there, we check the bitmap for the first free block after - * it. If there is no free block until the end of group, then the - * whole group is full, we failed. Otherwise, check if the free - * block is inside the expected reservable space, if so, we - * succeed. - * If the first free block is outside the reservable space, then - * start from the first free block, we search for next available - * space, and go on. - * - * on succeed, a new reservation will be found and inserted into the list - * It contains at least one free block, and it does not overlap with other - * reservation windows. - * - * failed: we failed to find a reservation window in this group - * - * @my_rsv: the reservation window - * - * @grp_goal: The goal (group-relative). It is where the search for a - * free reservable space should start from. - * if we have a grp_goal(grp_goal >0 ), then start from there, - * no grp_goal(grp_goal = -1), we start from the first block - * of the group. - * - * @sb: the super block - * @group: the group we are trying to allocate in - * @bitmap_bh: the block group block bitmap - * - */ -static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, - ext3_grpblk_t grp_goal, struct super_block *sb, - unsigned int group, struct buffer_head *bitmap_bh) -{ - struct ext3_reserve_window_node *search_head; - ext3_fsblk_t group_first_block, group_end_block, start_block; - ext3_grpblk_t first_free_block; - struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root; - unsigned long size; - int ret; - spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; - - group_first_block = ext3_group_first_block_no(sb, group); - group_end_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); - - if (grp_goal < 0) - start_block = group_first_block; - else - start_block = grp_goal + group_first_block; - - trace_ext3_alloc_new_reservation(sb, start_block); - size = my_rsv->rsv_goal_size; - - if (!rsv_is_empty(&my_rsv->rsv_window)) { - /* - * if the old reservation is cross group boundary - * and if the goal is inside the old reservation window, - * we will come here when we just failed to allocate from - * the first part of the window. We still have another part - * that belongs to the next group. In this case, there is no - * point to discard our window and try to allocate a new one - * in this group(which will fail). we should - * keep the reservation window, just simply move on. - * - * Maybe we could shift the start block of the reservation - * window to the first block of next group. - */ - - if ((my_rsv->rsv_start <= group_end_block) && - (my_rsv->rsv_end > group_end_block) && - (start_block >= my_rsv->rsv_start)) - return -1; - - if ((my_rsv->rsv_alloc_hit > - (my_rsv->rsv_end - my_rsv->rsv_start + 1) / 2)) { - /* - * if the previously allocation hit ratio is - * greater than 1/2, then we double the size of - * the reservation window the next time, - * otherwise we keep the same size window - */ - size = size * 2; - if (size > EXT3_MAX_RESERVE_BLOCKS) - size = EXT3_MAX_RESERVE_BLOCKS; - my_rsv->rsv_goal_size= size; - } - } - - spin_lock(rsv_lock); - /* - * shift the search start to the window near the goal block - */ - search_head = search_reserve_window(fs_rsv_root, start_block); - - /* - * find_next_reservable_window() simply finds a reservable window - * inside the given range(start_block, group_end_block). - * - * To make sure the reservation window has a free bit inside it, we - * need to check the bitmap after we found a reservable window. - */ -retry: - ret = find_next_reservable_window(search_head, my_rsv, sb, - start_block, group_end_block); - - if (ret == -1) { - if (!rsv_is_empty(&my_rsv->rsv_window)) - rsv_window_remove(sb, my_rsv); - spin_unlock(rsv_lock); - return -1; - } - - /* - * On success, find_next_reservable_window() returns the - * reservation window where there is a reservable space after it. - * Before we reserve this reservable space, we need - * to make sure there is at least a free block inside this region. - * - * searching the first free bit on the block bitmap and copy of - * last committed bitmap alternatively, until we found a allocatable - * block. Search start from the start block of the reservable space - * we just found. - */ - spin_unlock(rsv_lock); - first_free_block = bitmap_search_next_usable_block( - my_rsv->rsv_start - group_first_block, - bitmap_bh, group_end_block - group_first_block + 1); - - if (first_free_block < 0) { - /* - * no free block left on the bitmap, no point - * to reserve the space. return failed. - */ - spin_lock(rsv_lock); - if (!rsv_is_empty(&my_rsv->rsv_window)) - rsv_window_remove(sb, my_rsv); - spin_unlock(rsv_lock); - return -1; /* failed */ - } - - start_block = first_free_block + group_first_block; - /* - * check if the first free block is within the - * free space we just reserved - */ - if (start_block >= my_rsv->rsv_start && - start_block <= my_rsv->rsv_end) { - trace_ext3_reserved(sb, start_block, my_rsv); - return 0; /* success */ - } - /* - * if the first free bit we found is out of the reservable space - * continue search for next reservable space, - * start from where the free block is, - * we also shift the list head to where we stopped last time - */ - search_head = my_rsv; - spin_lock(rsv_lock); - goto retry; -} - -/** - * try_to_extend_reservation() - * @my_rsv: given reservation window - * @sb: super block - * @size: the delta to extend - * - * Attempt to expand the reservation window large enough to have - * required number of free blocks - * - * Since ext3_try_to_allocate() will always allocate blocks within - * the reservation window range, if the window size is too small, - * multiple blocks allocation has to stop at the end of the reservation - * window. To make this more efficient, given the total number of - * blocks needed and the current size of the window, we try to - * expand the reservation window size if necessary on a best-effort - * basis before ext3_new_blocks() tries to allocate blocks, - */ -static void try_to_extend_reservation(struct ext3_reserve_window_node *my_rsv, - struct super_block *sb, int size) -{ - struct ext3_reserve_window_node *next_rsv; - struct rb_node *next; - spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock; - - if (!spin_trylock(rsv_lock)) - return; - - next = rb_next(&my_rsv->rsv_node); - - if (!next) - my_rsv->rsv_end += size; - else { - next_rsv = rb_entry(next, struct ext3_reserve_window_node, rsv_node); - - if ((next_rsv->rsv_start - my_rsv->rsv_end - 1) >= size) - my_rsv->rsv_end += size; - else - my_rsv->rsv_end = next_rsv->rsv_start - 1; - } - spin_unlock(rsv_lock); -} - -/** - * ext3_try_to_allocate_with_rsv() - * @sb: superblock - * @handle: handle to this transaction - * @group: given allocation block group - * @bitmap_bh: bufferhead holds the block bitmap - * @grp_goal: given target block within the group - * @my_rsv: reservation window - * @count: target number of blocks to allocate - * @errp: pointer to store the error code - * - * This is the main function used to allocate a new block and its reservation - * window. - * - * Each time when a new block allocation is need, first try to allocate from - * its own reservation. If it does not have a reservation window, instead of - * looking for a free bit on bitmap first, then look up the reservation list to - * see if it is inside somebody else's reservation window, we try to allocate a - * reservation window for it starting from the goal first. Then do the block - * allocation within the reservation window. - * - * This will avoid keeping on searching the reservation list again and - * again when somebody is looking for a free block (without - * reservation), and there are lots of free blocks, but they are all - * being reserved. - * - * We use a red-black tree for the per-filesystem reservation list. - * - */ -static ext3_grpblk_t -ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle, - unsigned int group, struct buffer_head *bitmap_bh, - ext3_grpblk_t grp_goal, - struct ext3_reserve_window_node * my_rsv, - unsigned long *count, int *errp) -{ - ext3_fsblk_t group_first_block, group_last_block; - ext3_grpblk_t ret = 0; - int fatal; - unsigned long num = *count; - - *errp = 0; - - /* - * Make sure we use undo access for the bitmap, because it is critical - * that we do the frozen_data COW on bitmap buffers in all cases even - * if the buffer is in BJ_Forget state in the committing transaction. - */ - BUFFER_TRACE(bitmap_bh, "get undo access for new block"); - fatal = ext3_journal_get_undo_access(handle, bitmap_bh); - if (fatal) { - *errp = fatal; - return -1; - } - - /* - * we don't deal with reservation when - * filesystem is mounted without reservation - * or the file is not a regular file - * or last attempt to allocate a block with reservation turned on failed - */ - if (my_rsv == NULL ) { - ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, - grp_goal, count, NULL); - goto out; - } - /* - * grp_goal is a group relative block number (if there is a goal) - * 0 <= grp_goal < EXT3_BLOCKS_PER_GROUP(sb) - * first block is a filesystem wide block number - * first block is the block number of the first block in this group - */ - group_first_block = ext3_group_first_block_no(sb, group); - group_last_block = group_first_block + (EXT3_BLOCKS_PER_GROUP(sb) - 1); - - /* - * Basically we will allocate a new block from inode's reservation - * window. - * - * We need to allocate a new reservation window, if: - * a) inode does not have a reservation window; or - * b) last attempt to allocate a block from existing reservation - * failed; or - * c) we come here with a goal and with a reservation window - * - * We do not need to allocate a new reservation window if we come here - * at the beginning with a goal and the goal is inside the window, or - * we don't have a goal but already have a reservation window. - * then we could go to allocate from the reservation window directly. - */ - while (1) { - if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) || - !goal_in_my_reservation(&my_rsv->rsv_window, - grp_goal, group, sb)) { - if (my_rsv->rsv_goal_size < *count) - my_rsv->rsv_goal_size = *count; - ret = alloc_new_reservation(my_rsv, grp_goal, sb, - group, bitmap_bh); - if (ret < 0) - break; /* failed */ - - if (!goal_in_my_reservation(&my_rsv->rsv_window, - grp_goal, group, sb)) - grp_goal = -1; - } else if (grp_goal >= 0) { - int curr = my_rsv->rsv_end - - (grp_goal + group_first_block) + 1; - - if (curr < *count) - try_to_extend_reservation(my_rsv, sb, - *count - curr); - } - - if ((my_rsv->rsv_start > group_last_block) || - (my_rsv->rsv_end < group_first_block)) { - rsv_window_dump(&EXT3_SB(sb)->s_rsv_window_root, 1); - BUG(); - } - ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, - grp_goal, &num, &my_rsv->rsv_window); - if (ret >= 0) { - my_rsv->rsv_alloc_hit += num; - *count = num; - break; /* succeed */ - } - num = *count; - } -out: - if (ret >= 0) { - BUFFER_TRACE(bitmap_bh, "journal_dirty_metadata for " - "bitmap block"); - fatal = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (fatal) { - *errp = fatal; - return -1; - } - return ret; - } - - BUFFER_TRACE(bitmap_bh, "journal_release_buffer"); - ext3_journal_release_buffer(handle, bitmap_bh); - return ret; -} - -/** - * ext3_has_free_blocks() - * @sbi: in-core super block structure. - * - * Check if filesystem has at least 1 free block available for allocation. - */ -static int ext3_has_free_blocks(struct ext3_sb_info *sbi, int use_reservation) -{ - ext3_fsblk_t free_blocks, root_blocks; - - free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); - if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && - !use_reservation && !uid_eq(sbi->s_resuid, current_fsuid()) && - (gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) || - !in_group_p (sbi->s_resgid))) { - return 0; - } - return 1; -} - -/** - * ext3_should_retry_alloc() - * @sb: super block - * @retries number of attemps has been made - * - * ext3_should_retry_alloc() is called when ENOSPC is returned, and if - * it is profitable to retry the operation, this function will wait - * for the current or committing transaction to complete, and then - * return TRUE. - * - * if the total number of retries exceed three times, return FALSE. - */ -int ext3_should_retry_alloc(struct super_block *sb, int *retries) -{ - if (!ext3_has_free_blocks(EXT3_SB(sb), 0) || (*retries)++ > 3) - return 0; - - jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); - - return journal_force_commit_nested(EXT3_SB(sb)->s_journal); -} - -/** - * ext3_new_blocks() -- core block(s) allocation function - * @handle: handle to this transaction - * @inode: file inode - * @goal: given target block(filesystem wide) - * @count: target number of blocks to allocate - * @errp: error code - * - * ext3_new_blocks uses a goal block to assist allocation. It tries to - * allocate block(s) from the block group contains the goal block first. If that - * fails, it will try to allocate block(s) from other block groups without - * any specific goal block. - * - */ -ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, unsigned long *count, int *errp) -{ - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *gdp_bh; - int group_no; - int goal_group; - ext3_grpblk_t grp_target_blk; /* blockgroup relative goal block */ - ext3_grpblk_t grp_alloc_blk; /* blockgroup-relative allocated block*/ - ext3_fsblk_t ret_block; /* filesyetem-wide allocated block */ - int bgi; /* blockgroup iteration index */ - int fatal = 0, err; - int performed_allocation = 0; - ext3_grpblk_t free_blocks; /* number of free blocks in a group */ - struct super_block *sb; - struct ext3_group_desc *gdp; - struct ext3_super_block *es; - struct ext3_sb_info *sbi; - struct ext3_reserve_window_node *my_rsv = NULL; - struct ext3_block_alloc_info *block_i; - unsigned short windowsz = 0; -#ifdef EXT3FS_DEBUG - static int goal_hits, goal_attempts; -#endif - unsigned long ngroups; - unsigned long num = *count; - - *errp = -ENOSPC; - sb = inode->i_sb; - - /* - * Check quota for allocation of this block. - */ - err = dquot_alloc_block(inode, num); - if (err) { - *errp = err; - return 0; - } - - trace_ext3_request_blocks(inode, goal, num); - - sbi = EXT3_SB(sb); - es = sbi->s_es; - ext3_debug("goal=%lu.\n", goal); - /* - * Allocate a block from reservation only when - * filesystem is mounted with reservation(default,-o reservation), and - * it's a regular file, and - * the desired window size is greater than 0 (One could use ioctl - * command EXT3_IOC_SETRSVSZ to set the window size to 0 to turn off - * reservation on that particular file) - */ - block_i = EXT3_I(inode)->i_block_alloc_info; - if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) - my_rsv = &block_i->rsv_window_node; - - if (!ext3_has_free_blocks(sbi, IS_NOQUOTA(inode))) { - *errp = -ENOSPC; - goto out; - } - - /* - * First, test whether the goal block is free. - */ - if (goal < le32_to_cpu(es->s_first_data_block) || - goal >= le32_to_cpu(es->s_blocks_count)) - goal = le32_to_cpu(es->s_first_data_block); - group_no = (goal - le32_to_cpu(es->s_first_data_block)) / - EXT3_BLOCKS_PER_GROUP(sb); - goal_group = group_no; -retry_alloc: - gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); - if (!gdp) - goto io_error; - - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); - /* - * if there is not enough free blocks to make a new resevation - * turn off reservation for this allocation - */ - if (my_rsv && (free_blocks < windowsz) - && (free_blocks > 0) - && (rsv_is_empty(&my_rsv->rsv_window))) - my_rsv = NULL; - - if (free_blocks > 0) { - grp_target_blk = ((goal - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb)); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle, - group_no, bitmap_bh, grp_target_blk, - my_rsv, &num, &fatal); - if (fatal) - goto out; - if (grp_alloc_blk >= 0) - goto allocated; - } - - ngroups = EXT3_SB(sb)->s_groups_count; - smp_rmb(); - - /* - * Now search the rest of the groups. We assume that - * group_no and gdp correctly point to the last group visited. - */ - for (bgi = 0; bgi < ngroups; bgi++) { - group_no++; - if (group_no >= ngroups) - group_no = 0; - gdp = ext3_get_group_desc(sb, group_no, &gdp_bh); - if (!gdp) - goto io_error; - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); - /* - * skip this group (and avoid loading bitmap) if there - * are no free blocks - */ - if (!free_blocks) - continue; - /* - * skip this group if the number of - * free blocks is less than half of the reservation - * window size. - */ - if (my_rsv && (free_blocks <= (windowsz/2))) - continue; - - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, group_no); - if (!bitmap_bh) - goto io_error; - /* - * try to allocate block(s) from this group, without a goal(-1). - */ - grp_alloc_blk = ext3_try_to_allocate_with_rsv(sb, handle, - group_no, bitmap_bh, -1, my_rsv, - &num, &fatal); - if (fatal) - goto out; - if (grp_alloc_blk >= 0) - goto allocated; - } - /* - * We may end up a bogus earlier ENOSPC error due to - * filesystem is "full" of reservations, but - * there maybe indeed free blocks available on disk - * In this case, we just forget about the reservations - * just do block allocation as without reservations. - */ - if (my_rsv) { - my_rsv = NULL; - windowsz = 0; - group_no = goal_group; - goto retry_alloc; - } - /* No space left on the device */ - *errp = -ENOSPC; - goto out; - -allocated: - - ext3_debug("using block group %d(%d)\n", - group_no, gdp->bg_free_blocks_count); - - BUFFER_TRACE(gdp_bh, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, gdp_bh); - if (fatal) - goto out; - - ret_block = grp_alloc_blk + ext3_group_first_block_no(sb, group_no); - - if (in_range(le32_to_cpu(gdp->bg_block_bitmap), ret_block, num) || - in_range(le32_to_cpu(gdp->bg_inode_bitmap), ret_block, num) || - in_range(ret_block, le32_to_cpu(gdp->bg_inode_table), - EXT3_SB(sb)->s_itb_per_group) || - in_range(ret_block + num - 1, le32_to_cpu(gdp->bg_inode_table), - EXT3_SB(sb)->s_itb_per_group)) { - ext3_error(sb, "ext3_new_block", - "Allocating block in system zone - " - "blocks from "E3FSBLK", length %lu", - ret_block, num); - /* - * claim_block() marked the blocks we allocated as in use. So we - * may want to selectively mark some of the blocks as free. - */ - goto retry_alloc; - } - - performed_allocation = 1; - -#ifdef CONFIG_JBD_DEBUG - { - struct buffer_head *debug_bh; - - /* Record bitmap buffer state in the newly allocated block */ - debug_bh = sb_find_get_block(sb, ret_block); - if (debug_bh) { - BUFFER_TRACE(debug_bh, "state when allocated"); - BUFFER_TRACE2(debug_bh, bitmap_bh, "bitmap state"); - brelse(debug_bh); - } - } - jbd_lock_bh_state(bitmap_bh); - spin_lock(sb_bgl_lock(sbi, group_no)); - if (buffer_jbd(bitmap_bh) && bh2jh(bitmap_bh)->b_committed_data) { - int i; - - for (i = 0; i < num; i++) { - if (ext3_test_bit(grp_alloc_blk+i, - bh2jh(bitmap_bh)->b_committed_data)) { - printk("%s: block was unexpectedly set in " - "b_committed_data\n", __func__); - } - } - } - ext3_debug("found bit %d\n", grp_alloc_blk); - spin_unlock(sb_bgl_lock(sbi, group_no)); - jbd_unlock_bh_state(bitmap_bh); -#endif - - if (ret_block + num - 1 >= le32_to_cpu(es->s_blocks_count)) { - ext3_error(sb, "ext3_new_block", - "block("E3FSBLK") >= blocks count(%d) - " - "block_group = %d, es == %p ", ret_block, - le32_to_cpu(es->s_blocks_count), group_no, es); - goto out; - } - - /* - * It is up to the caller to add the new buffer to a journal - * list of some description. We don't know in advance whether - * the caller wants to use it as metadata or data. - */ - ext3_debug("allocating block %lu. Goal hits %d of %d.\n", - ret_block, goal_hits, goal_attempts); - - spin_lock(sb_bgl_lock(sbi, group_no)); - le16_add_cpu(&gdp->bg_free_blocks_count, -num); - spin_unlock(sb_bgl_lock(sbi, group_no)); - percpu_counter_sub(&sbi->s_freeblocks_counter, num); - - BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor"); - fatal = ext3_journal_dirty_metadata(handle, gdp_bh); - if (fatal) - goto out; - - *errp = 0; - brelse(bitmap_bh); - - if (num < *count) { - dquot_free_block(inode, *count-num); - *count = num; - } - - trace_ext3_allocate_blocks(inode, goal, num, - (unsigned long long)ret_block); - - return ret_block; - -io_error: - *errp = -EIO; -out: - if (fatal) { - *errp = fatal; - ext3_std_error(sb, fatal); - } - /* - * Undo the block allocation - */ - if (!performed_allocation) - dquot_free_block(inode, *count); - brelse(bitmap_bh); - return 0; -} - -ext3_fsblk_t ext3_new_block(handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, int *errp) -{ - unsigned long count = 1; - - return ext3_new_blocks(handle, inode, goal, &count, errp); -} - -/** - * ext3_count_free_blocks() -- count filesystem free blocks - * @sb: superblock - * - * Adds up the number of free blocks from each block group. - */ -ext3_fsblk_t ext3_count_free_blocks(struct super_block *sb) -{ - ext3_fsblk_t desc_count; - struct ext3_group_desc *gdp; - int i; - unsigned long ngroups = EXT3_SB(sb)->s_groups_count; -#ifdef EXT3FS_DEBUG - struct ext3_super_block *es; - ext3_fsblk_t bitmap_count; - unsigned long x; - struct buffer_head *bitmap_bh = NULL; - - es = EXT3_SB(sb)->s_es; - desc_count = 0; - bitmap_count = 0; - gdp = NULL; - - smp_rmb(); - for (i = 0; i < ngroups; i++) { - gdp = ext3_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - desc_count += le16_to_cpu(gdp->bg_free_blocks_count); - brelse(bitmap_bh); - bitmap_bh = read_block_bitmap(sb, i); - if (bitmap_bh == NULL) - continue; - - x = ext3_count_free(bitmap_bh, sb->s_blocksize); - printk("group %d: stored = %d, counted = %lu\n", - i, le16_to_cpu(gdp->bg_free_blocks_count), x); - bitmap_count += x; - } - brelse(bitmap_bh); - printk("ext3_count_free_blocks: stored = "E3FSBLK - ", computed = "E3FSBLK", "E3FSBLK"\n", - (ext3_fsblk_t)le32_to_cpu(es->s_free_blocks_count), - desc_count, bitmap_count); - return bitmap_count; -#else - desc_count = 0; - smp_rmb(); - for (i = 0; i < ngroups; i++) { - gdp = ext3_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - desc_count += le16_to_cpu(gdp->bg_free_blocks_count); - } - - return desc_count; -#endif -} - -static inline int test_root(int a, int b) -{ - int num = b; - - while (a > num) - num *= b; - return num == a; -} - -static int ext3_group_sparse(int group) -{ - if (group <= 1) - return 1; - if (!(group & 1)) - return 0; - return (test_root(group, 7) || test_root(group, 5) || - test_root(group, 3)); -} - -/** - * ext3_bg_has_super - number of blocks used by the superblock in group - * @sb: superblock for filesystem - * @group: group number to check - * - * Return the number of blocks used by the superblock (primary or backup) - * in this group. Currently this will be only 0 or 1. - */ -int ext3_bg_has_super(struct super_block *sb, int group) -{ - if (EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) && - !ext3_group_sparse(group)) - return 0; - return 1; -} - -static unsigned long ext3_bg_num_gdb_meta(struct super_block *sb, int group) -{ - unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb); - unsigned long first = metagroup * EXT3_DESC_PER_BLOCK(sb); - unsigned long last = first + EXT3_DESC_PER_BLOCK(sb) - 1; - - if (group == first || group == first + 1 || group == last) - return 1; - return 0; -} - -static unsigned long ext3_bg_num_gdb_nometa(struct super_block *sb, int group) -{ - return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0; -} - -/** - * ext3_bg_num_gdb - number of blocks used by the group table in group - * @sb: superblock for filesystem - * @group: group number to check - * - * Return the number of blocks used by the group descriptor table - * (primary or backup) in this group. In the future there may be a - * different number of descriptor blocks in each group. - */ -unsigned long ext3_bg_num_gdb(struct super_block *sb, int group) -{ - unsigned long first_meta_bg = - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg); - unsigned long metagroup = group / EXT3_DESC_PER_BLOCK(sb); - - if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT3_FEATURE_INCOMPAT_META_BG) || - metagroup < first_meta_bg) - return ext3_bg_num_gdb_nometa(sb,group); - - return ext3_bg_num_gdb_meta(sb,group); - -} - -/** - * ext3_trim_all_free -- function to trim all free space in alloc. group - * @sb: super block for file system - * @group: allocation group to trim - * @start: first group block to examine - * @max: last group block to examine - * @gdp: allocation group description structure - * @minblocks: minimum extent block count - * - * ext3_trim_all_free walks through group's block bitmap searching for free - * blocks. When the free block is found, it tries to allocate this block and - * consequent free block to get the biggest free extent possible, until it - * reaches any used block. Then issue a TRIM command on this extent and free - * the extent in the block bitmap. This is done until whole group is scanned. - */ -static ext3_grpblk_t ext3_trim_all_free(struct super_block *sb, - unsigned int group, - ext3_grpblk_t start, ext3_grpblk_t max, - ext3_grpblk_t minblocks) -{ - handle_t *handle; - ext3_grpblk_t next, free_blocks, bit, freed, count = 0; - ext3_fsblk_t discard_block; - struct ext3_sb_info *sbi; - struct buffer_head *gdp_bh, *bitmap_bh = NULL; - struct ext3_group_desc *gdp; - int err = 0, ret = 0; - - /* - * We will update one block bitmap, and one group descriptor - */ - handle = ext3_journal_start_sb(sb, 2); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - bitmap_bh = read_block_bitmap(sb, group); - if (!bitmap_bh) { - err = -EIO; - goto err_out; - } - - BUFFER_TRACE(bitmap_bh, "getting undo access"); - err = ext3_journal_get_undo_access(handle, bitmap_bh); - if (err) - goto err_out; - - gdp = ext3_get_group_desc(sb, group, &gdp_bh); - if (!gdp) { - err = -EIO; - goto err_out; - } - - BUFFER_TRACE(gdp_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, gdp_bh); - if (err) - goto err_out; - - free_blocks = le16_to_cpu(gdp->bg_free_blocks_count); - sbi = EXT3_SB(sb); - - /* Walk through the whole group */ - while (start <= max) { - start = bitmap_search_next_usable_block(start, bitmap_bh, max); - if (start < 0) - break; - next = start; - - /* - * Allocate contiguous free extents by setting bits in the - * block bitmap - */ - while (next <= max - && claim_block(sb_bgl_lock(sbi, group), - next, bitmap_bh)) { - next++; - } - - /* We did not claim any blocks */ - if (next == start) - continue; - - discard_block = (ext3_fsblk_t)start + - ext3_group_first_block_no(sb, group); - - /* Update counters */ - spin_lock(sb_bgl_lock(sbi, group)); - le16_add_cpu(&gdp->bg_free_blocks_count, start - next); - spin_unlock(sb_bgl_lock(sbi, group)); - percpu_counter_sub(&sbi->s_freeblocks_counter, next - start); - - free_blocks -= next - start; - /* Do not issue a TRIM on extents smaller than minblocks */ - if ((next - start) < minblocks) - goto free_extent; - - trace_ext3_discard_blocks(sb, discard_block, next - start); - /* Send the TRIM command down to the device */ - err = sb_issue_discard(sb, discard_block, next - start, - GFP_NOFS, 0); - count += (next - start); -free_extent: - freed = 0; - - /* - * Clear bits in the bitmap - */ - for (bit = start; bit < next; bit++) { - BUFFER_TRACE(bitmap_bh, "clear bit"); - if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, group), - bit, bitmap_bh->b_data)) { - ext3_error(sb, __func__, - "bit already cleared for block "E3FSBLK, - (unsigned long)bit); - BUFFER_TRACE(bitmap_bh, "bit already cleared"); - } else { - freed++; - } - } - - /* Update couters */ - spin_lock(sb_bgl_lock(sbi, group)); - le16_add_cpu(&gdp->bg_free_blocks_count, freed); - spin_unlock(sb_bgl_lock(sbi, group)); - percpu_counter_add(&sbi->s_freeblocks_counter, freed); - - start = next; - if (err < 0) { - if (err != -EOPNOTSUPP) - ext3_warning(sb, __func__, "Discard command " - "returned error %d\n", err); - break; - } - - if (fatal_signal_pending(current)) { - err = -ERESTARTSYS; - break; - } - - cond_resched(); - - /* No more suitable extents */ - if (free_blocks < minblocks) - break; - } - - /* We dirtied the bitmap block */ - BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); - ret = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (!err) - err = ret; - - /* And the group descriptor block */ - BUFFER_TRACE(gdp_bh, "dirtied group descriptor block"); - ret = ext3_journal_dirty_metadata(handle, gdp_bh); - if (!err) - err = ret; - - ext3_debug("trimmed %d blocks in the group %d\n", - count, group); - -err_out: - if (err) - count = err; - ext3_journal_stop(handle); - brelse(bitmap_bh); - - return count; -} - -/** - * ext3_trim_fs() -- trim ioctl handle function - * @sb: superblock for filesystem - * @start: First Byte to trim - * @len: number of Bytes to trim from start - * @minlen: minimum extent length in Bytes - * - * ext3_trim_fs goes through all allocation groups containing Bytes from - * start to start+len. For each such a group ext3_trim_all_free function - * is invoked to trim all free space. - */ -int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range) -{ - ext3_grpblk_t last_block, first_block; - unsigned long group, first_group, last_group; - struct ext3_group_desc *gdp; - struct ext3_super_block *es = EXT3_SB(sb)->s_es; - uint64_t start, minlen, end, trimmed = 0; - ext3_fsblk_t first_data_blk = - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block); - ext3_fsblk_t max_blks = le32_to_cpu(es->s_blocks_count); - int ret = 0; - - start = range->start >> sb->s_blocksize_bits; - end = start + (range->len >> sb->s_blocksize_bits) - 1; - minlen = range->minlen >> sb->s_blocksize_bits; - - if (minlen > EXT3_BLOCKS_PER_GROUP(sb) || - start >= max_blks || - range->len < sb->s_blocksize) - return -EINVAL; - if (end >= max_blks) - end = max_blks - 1; - if (end <= first_data_blk) - goto out; - if (start < first_data_blk) - start = first_data_blk; - - smp_rmb(); - - /* Determine first and last group to examine based on start and len */ - ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) start, - &first_group, &first_block); - ext3_get_group_no_and_offset(sb, (ext3_fsblk_t) end, - &last_group, &last_block); - - /* end now represents the last block to discard in this group */ - end = EXT3_BLOCKS_PER_GROUP(sb) - 1; - - for (group = first_group; group <= last_group; group++) { - gdp = ext3_get_group_desc(sb, group, NULL); - if (!gdp) - break; - - /* - * For all the groups except the last one, last block will - * always be EXT3_BLOCKS_PER_GROUP(sb)-1, so we only need to - * change it for the last group, note that last_block is - * already computed earlier by ext3_get_group_no_and_offset() - */ - if (group == last_group) - end = last_block; - - if (le16_to_cpu(gdp->bg_free_blocks_count) >= minlen) { - ret = ext3_trim_all_free(sb, group, first_block, - end, minlen); - if (ret < 0) - break; - trimmed += ret; - } - - /* - * For every group except the first one, we are sure - * that the first block to discard will be block #0. - */ - first_block = 0; - } - - if (ret > 0) - ret = 0; - -out: - range->len = trimmed * sb->s_blocksize; - return ret; -} diff --git a/fs/ext3/bitmap.c b/fs/ext3/bitmap.c deleted file mode 100644 index ef9c643e8e9d5..0000000000000 --- a/fs/ext3/bitmap.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * linux/fs/ext3/bitmap.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include "ext3.h" - -#ifdef EXT3FS_DEBUG - -unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars) -{ - return numchars * BITS_PER_BYTE - memweight(map->b_data, numchars); -} - -#endif /* EXT3FS_DEBUG */ - diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c deleted file mode 100644 index 17742eed2c16f..0000000000000 --- a/fs/ext3/dir.c +++ /dev/null @@ -1,537 +0,0 @@ -/* - * linux/fs/ext3/dir.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/dir.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext3 directory handling functions - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * - * Hash Tree Directory indexing (c) 2001 Daniel Phillips - * - */ - -#include -#include "ext3.h" - -static unsigned char ext3_filetype_table[] = { - DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK -}; - -static int ext3_dx_readdir(struct file *, struct dir_context *); - -static unsigned char get_dtype(struct super_block *sb, int filetype) -{ - if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE) || - (filetype >= EXT3_FT_MAX)) - return DT_UNKNOWN; - - return (ext3_filetype_table[filetype]); -} - -/** - * Check if the given dir-inode refers to an htree-indexed directory - * (or a directory which could potentially get converted to use htree - * indexing). - * - * Return 1 if it is a dx dir, 0 if not - */ -static int is_dx_dir(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - - if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb, - EXT3_FEATURE_COMPAT_DIR_INDEX) && - ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) || - ((inode->i_size >> sb->s_blocksize_bits) == 1))) - return 1; - - return 0; -} - -int ext3_check_dir_entry (const char * function, struct inode * dir, - struct ext3_dir_entry_2 * de, - struct buffer_head * bh, - unsigned long offset) -{ - const char * error_msg = NULL; - const int rlen = ext3_rec_len_from_disk(de->rec_len); - - if (unlikely(rlen < EXT3_DIR_REC_LEN(1))) - error_msg = "rec_len is smaller than minimal"; - else if (unlikely(rlen % 4 != 0)) - error_msg = "rec_len % 4 != 0"; - else if (unlikely(rlen < EXT3_DIR_REC_LEN(de->name_len))) - error_msg = "rec_len is too small for name_len"; - else if (unlikely((((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize))) - error_msg = "directory entry across blocks"; - else if (unlikely(le32_to_cpu(de->inode) > - le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))) - error_msg = "inode out of bounds"; - - if (unlikely(error_msg != NULL)) - ext3_error (dir->i_sb, function, - "bad entry in directory #%lu: %s - " - "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", - dir->i_ino, error_msg, offset, - (unsigned long) le32_to_cpu(de->inode), - rlen, de->name_len); - - return error_msg == NULL ? 1 : 0; -} - -static int ext3_readdir(struct file *file, struct dir_context *ctx) -{ - unsigned long offset; - int i; - struct ext3_dir_entry_2 *de; - int err; - struct inode *inode = file_inode(file); - struct super_block *sb = inode->i_sb; - int dir_has_error = 0; - - if (is_dx_dir(inode)) { - err = ext3_dx_readdir(file, ctx); - if (err != ERR_BAD_DX_DIR) - return err; - /* - * We don't set the inode dirty flag since it's not - * critical that it get flushed back to the disk. - */ - EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL; - } - offset = ctx->pos & (sb->s_blocksize - 1); - - while (ctx->pos < inode->i_size) { - unsigned long blk = ctx->pos >> EXT3_BLOCK_SIZE_BITS(sb); - struct buffer_head map_bh; - struct buffer_head *bh = NULL; - - map_bh.b_state = 0; - err = ext3_get_blocks_handle(NULL, inode, blk, 1, &map_bh, 0); - if (err > 0) { - pgoff_t index = map_bh.b_blocknr >> - (PAGE_CACHE_SHIFT - inode->i_blkbits); - if (!ra_has_index(&file->f_ra, index)) - page_cache_sync_readahead( - sb->s_bdev->bd_inode->i_mapping, - &file->f_ra, file, - index, 1); - file->f_ra.prev_pos = (loff_t)index << PAGE_CACHE_SHIFT; - bh = ext3_bread(NULL, inode, blk, 0, &err); - } - - /* - * We ignore I/O errors on directories so users have a chance - * of recovering data when there's a bad sector - */ - if (!bh) { - if (!dir_has_error) { - ext3_error(sb, __func__, "directory #%lu " - "contains a hole at offset %lld", - inode->i_ino, ctx->pos); - dir_has_error = 1; - } - /* corrupt size? Maybe no more blocks to read */ - if (ctx->pos > inode->i_blocks << 9) - break; - ctx->pos += sb->s_blocksize - offset; - continue; - } - - /* If the dir block has changed since the last call to - * readdir(2), then we might be pointing to an invalid - * dirent right now. Scan from the start of the block - * to make sure. */ - if (offset && file->f_version != inode->i_version) { - for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ext3_dir_entry_2 *) - (bh->b_data + i); - /* It's too expensive to do a full - * dirent test each time round this - * loop, but we do have to test at - * least that it is non-zero. A - * failure will be detected in the - * dirent test below. */ - if (ext3_rec_len_from_disk(de->rec_len) < - EXT3_DIR_REC_LEN(1)) - break; - i += ext3_rec_len_from_disk(de->rec_len); - } - offset = i; - ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1)) - | offset; - file->f_version = inode->i_version; - } - - while (ctx->pos < inode->i_size - && offset < sb->s_blocksize) { - de = (struct ext3_dir_entry_2 *) (bh->b_data + offset); - if (!ext3_check_dir_entry ("ext3_readdir", inode, de, - bh, offset)) { - /* On error, skip the to the - next block. */ - ctx->pos = (ctx->pos | - (sb->s_blocksize - 1)) + 1; - break; - } - offset += ext3_rec_len_from_disk(de->rec_len); - if (le32_to_cpu(de->inode)) { - if (!dir_emit(ctx, de->name, de->name_len, - le32_to_cpu(de->inode), - get_dtype(sb, de->file_type))) { - brelse(bh); - return 0; - } - } - ctx->pos += ext3_rec_len_from_disk(de->rec_len); - } - offset = 0; - brelse (bh); - if (ctx->pos < inode->i_size) - if (!dir_relax(inode)) - return 0; - } - return 0; -} - -static inline int is_32bit_api(void) -{ -#ifdef CONFIG_COMPAT - return is_compat_task(); -#else - return (BITS_PER_LONG == 32); -#endif -} - -/* - * These functions convert from the major/minor hash to an f_pos - * value for dx directories - * - * Upper layer (for example NFS) should specify FMODE_32BITHASH or - * FMODE_64BITHASH explicitly. On the other hand, we allow ext3 to be mounted - * directly on both 32-bit and 64-bit nodes, under such case, neither - * FMODE_32BITHASH nor FMODE_64BITHASH is specified. - */ -static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return major >> 1; - else - return ((__u64)(major >> 1) << 32) | (__u64)minor; -} - -static inline __u32 pos2maj_hash(struct file *filp, loff_t pos) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return (pos << 1) & 0xffffffff; - else - return ((pos >> 32) << 1) & 0xffffffff; -} - -static inline __u32 pos2min_hash(struct file *filp, loff_t pos) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return 0; - else - return pos & 0xffffffff; -} - -/* - * Return 32- or 64-bit end-of-file for dx directories - */ -static inline loff_t ext3_get_htree_eof(struct file *filp) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return EXT3_HTREE_EOF_32BIT; - else - return EXT3_HTREE_EOF_64BIT; -} - - -/* - * ext3_dir_llseek() calls generic_file_llseek[_size]() to handle both - * non-htree and htree directories, where the "offset" is in terms - * of the filename hash value instead of the byte offset. - * - * Because we may return a 64-bit hash that is well beyond s_maxbytes, - * we need to pass the max hash as the maximum allowable offset in - * the htree directory case. - * - * NOTE: offsets obtained *before* ext3_set_inode_flag(dir, EXT3_INODE_INDEX) - * will be invalid once the directory was converted into a dx directory - */ -static loff_t ext3_dir_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file->f_mapping->host; - int dx_dir = is_dx_dir(inode); - loff_t htree_max = ext3_get_htree_eof(file); - - if (likely(dx_dir)) - return generic_file_llseek_size(file, offset, whence, - htree_max, htree_max); - else - return generic_file_llseek(file, offset, whence); -} - -/* - * This structure holds the nodes of the red-black tree used to store - * the directory entry in hash order. - */ -struct fname { - __u32 hash; - __u32 minor_hash; - struct rb_node rb_hash; - struct fname *next; - __u32 inode; - __u8 name_len; - __u8 file_type; - char name[0]; -}; - -/* - * This functoin implements a non-recursive way of freeing all of the - * nodes in the red-black tree. - */ -static void free_rb_tree_fname(struct rb_root *root) -{ - struct fname *fname, *next; - - rbtree_postorder_for_each_entry_safe(fname, next, root, rb_hash) - do { - struct fname *old = fname; - fname = fname->next; - kfree(old); - } while (fname); - - *root = RB_ROOT; -} - -static struct dir_private_info *ext3_htree_create_dir_info(struct file *filp, - loff_t pos) -{ - struct dir_private_info *p; - - p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL); - if (!p) - return NULL; - p->curr_hash = pos2maj_hash(filp, pos); - p->curr_minor_hash = pos2min_hash(filp, pos); - return p; -} - -void ext3_htree_free_dir_info(struct dir_private_info *p) -{ - free_rb_tree_fname(&p->root); - kfree(p); -} - -/* - * Given a directory entry, enter it into the fname rb tree. - */ -int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, - __u32 minor_hash, - struct ext3_dir_entry_2 *dirent) -{ - struct rb_node **p, *parent = NULL; - struct fname * fname, *new_fn; - struct dir_private_info *info; - int len; - - info = (struct dir_private_info *) dir_file->private_data; - p = &info->root.rb_node; - - /* Create and allocate the fname structure */ - len = sizeof(struct fname) + dirent->name_len + 1; - new_fn = kzalloc(len, GFP_KERNEL); - if (!new_fn) - return -ENOMEM; - new_fn->hash = hash; - new_fn->minor_hash = minor_hash; - new_fn->inode = le32_to_cpu(dirent->inode); - new_fn->name_len = dirent->name_len; - new_fn->file_type = dirent->file_type; - memcpy(new_fn->name, dirent->name, dirent->name_len); - new_fn->name[dirent->name_len] = 0; - - while (*p) { - parent = *p; - fname = rb_entry(parent, struct fname, rb_hash); - - /* - * If the hash and minor hash match up, then we put - * them on a linked list. This rarely happens... - */ - if ((new_fn->hash == fname->hash) && - (new_fn->minor_hash == fname->minor_hash)) { - new_fn->next = fname->next; - fname->next = new_fn; - return 0; - } - - if (new_fn->hash < fname->hash) - p = &(*p)->rb_left; - else if (new_fn->hash > fname->hash) - p = &(*p)->rb_right; - else if (new_fn->minor_hash < fname->minor_hash) - p = &(*p)->rb_left; - else /* if (new_fn->minor_hash > fname->minor_hash) */ - p = &(*p)->rb_right; - } - - rb_link_node(&new_fn->rb_hash, parent, p); - rb_insert_color(&new_fn->rb_hash, &info->root); - return 0; -} - - - -/* - * This is a helper function for ext3_dx_readdir. It calls filldir - * for all entres on the fname linked list. (Normally there is only - * one entry on the linked list, unless there are 62 bit hash collisions.) - */ -static bool call_filldir(struct file *file, struct dir_context *ctx, - struct fname *fname) -{ - struct dir_private_info *info = file->private_data; - struct inode *inode = file_inode(file); - struct super_block *sb = inode->i_sb; - - if (!fname) { - printk("call_filldir: called with null fname?!?\n"); - return true; - } - ctx->pos = hash2pos(file, fname->hash, fname->minor_hash); - while (fname) { - if (!dir_emit(ctx, fname->name, fname->name_len, - fname->inode, - get_dtype(sb, fname->file_type))) { - info->extra_fname = fname; - return false; - } - fname = fname->next; - } - return true; -} - -static int ext3_dx_readdir(struct file *file, struct dir_context *ctx) -{ - struct dir_private_info *info = file->private_data; - struct inode *inode = file_inode(file); - struct fname *fname; - int ret; - - if (!info) { - info = ext3_htree_create_dir_info(file, ctx->pos); - if (!info) - return -ENOMEM; - file->private_data = info; - } - - if (ctx->pos == ext3_get_htree_eof(file)) - return 0; /* EOF */ - - /* Some one has messed with f_pos; reset the world */ - if (info->last_pos != ctx->pos) { - free_rb_tree_fname(&info->root); - info->curr_node = NULL; - info->extra_fname = NULL; - info->curr_hash = pos2maj_hash(file, ctx->pos); - info->curr_minor_hash = pos2min_hash(file, ctx->pos); - } - - /* - * If there are any leftover names on the hash collision - * chain, return them first. - */ - if (info->extra_fname) { - if (!call_filldir(file, ctx, info->extra_fname)) - goto finished; - info->extra_fname = NULL; - goto next_node; - } else if (!info->curr_node) - info->curr_node = rb_first(&info->root); - - while (1) { - /* - * Fill the rbtree if we have no more entries, - * or the inode has changed since we last read in the - * cached entries. - */ - if ((!info->curr_node) || - (file->f_version != inode->i_version)) { - info->curr_node = NULL; - free_rb_tree_fname(&info->root); - file->f_version = inode->i_version; - ret = ext3_htree_fill_tree(file, info->curr_hash, - info->curr_minor_hash, - &info->next_hash); - if (ret < 0) - return ret; - if (ret == 0) { - ctx->pos = ext3_get_htree_eof(file); - break; - } - info->curr_node = rb_first(&info->root); - } - - fname = rb_entry(info->curr_node, struct fname, rb_hash); - info->curr_hash = fname->hash; - info->curr_minor_hash = fname->minor_hash; - if (!call_filldir(file, ctx, fname)) - break; - next_node: - info->curr_node = rb_next(info->curr_node); - if (info->curr_node) { - fname = rb_entry(info->curr_node, struct fname, - rb_hash); - info->curr_hash = fname->hash; - info->curr_minor_hash = fname->minor_hash; - } else { - if (info->next_hash == ~0) { - ctx->pos = ext3_get_htree_eof(file); - break; - } - info->curr_hash = info->next_hash; - info->curr_minor_hash = 0; - } - } -finished: - info->last_pos = ctx->pos; - return 0; -} - -static int ext3_release_dir (struct inode * inode, struct file * filp) -{ - if (filp->private_data) - ext3_htree_free_dir_info(filp->private_data); - - return 0; -} - -const struct file_operations ext3_dir_operations = { - .llseek = ext3_dir_llseek, - .read = generic_read_dir, - .iterate = ext3_readdir, - .unlocked_ioctl = ext3_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext3_compat_ioctl, -#endif - .fsync = ext3_sync_file, - .release = ext3_release_dir, -}; diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h deleted file mode 100644 index f483a80b3fe78..0000000000000 --- a/fs/ext3/ext3.h +++ /dev/null @@ -1,1332 +0,0 @@ -/* - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1998--1999 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/include/linux/minix_fs.h - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include - -/* - * The second extended filesystem constants/structures - */ - -/* - * Define EXT3FS_DEBUG to produce debug messages - */ -#undef EXT3FS_DEBUG - -/* - * Define EXT3_RESERVATION to reserve data blocks for expanding files - */ -#define EXT3_DEFAULT_RESERVE_BLOCKS 8 -/*max window size: 1024(direct blocks) + 3([t,d]indirect blocks) */ -#define EXT3_MAX_RESERVE_BLOCKS 1027 -#define EXT3_RESERVE_WINDOW_NOT_ALLOCATED 0 - -/* - * Debug code - */ -#ifdef EXT3FS_DEBUG -#define ext3_debug(f, a...) \ - do { \ - printk (KERN_DEBUG "EXT3-fs DEBUG (%s, %d): %s:", \ - __FILE__, __LINE__, __func__); \ - printk (KERN_DEBUG f, ## a); \ - } while (0) -#else -#define ext3_debug(f, a...) do {} while (0) -#endif - -/* - * Special inodes numbers - */ -#define EXT3_BAD_INO 1 /* Bad blocks inode */ -#define EXT3_ROOT_INO 2 /* Root inode */ -#define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ -#define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ -#define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ -#define EXT3_JOURNAL_INO 8 /* Journal inode */ - -/* First non-reserved inode for old ext3 filesystems */ -#define EXT3_GOOD_OLD_FIRST_INO 11 - -/* - * Maximal count of links to a file - */ -#define EXT3_LINK_MAX 32000 - -/* - * Macro-instructions used to manage several block sizes - */ -#define EXT3_MIN_BLOCK_SIZE 1024 -#define EXT3_MAX_BLOCK_SIZE 65536 -#define EXT3_MIN_BLOCK_LOG_SIZE 10 -#define EXT3_BLOCK_SIZE(s) ((s)->s_blocksize) -#define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) -#define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) -#define EXT3_ADDR_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_addr_per_block_bits) -#define EXT3_INODE_SIZE(s) (EXT3_SB(s)->s_inode_size) -#define EXT3_FIRST_INO(s) (EXT3_SB(s)->s_first_ino) - -/* - * Macro-instructions used to manage fragments - */ -#define EXT3_MIN_FRAG_SIZE 1024 -#define EXT3_MAX_FRAG_SIZE 4096 -#define EXT3_MIN_FRAG_LOG_SIZE 10 -#define EXT3_FRAG_SIZE(s) (EXT3_SB(s)->s_frag_size) -#define EXT3_FRAGS_PER_BLOCK(s) (EXT3_SB(s)->s_frags_per_block) - -/* - * Structure of a blocks group descriptor - */ -struct ext3_group_desc -{ - __le32 bg_block_bitmap; /* Blocks bitmap block */ - __le32 bg_inode_bitmap; /* Inodes bitmap block */ - __le32 bg_inode_table; /* Inodes table block */ - __le16 bg_free_blocks_count; /* Free blocks count */ - __le16 bg_free_inodes_count; /* Free inodes count */ - __le16 bg_used_dirs_count; /* Directories count */ - __u16 bg_pad; - __le32 bg_reserved[3]; -}; - -/* - * Macro-instructions used to manage group descriptors - */ -#define EXT3_BLOCKS_PER_GROUP(s) (EXT3_SB(s)->s_blocks_per_group) -#define EXT3_DESC_PER_BLOCK(s) (EXT3_SB(s)->s_desc_per_block) -#define EXT3_INODES_PER_GROUP(s) (EXT3_SB(s)->s_inodes_per_group) -#define EXT3_DESC_PER_BLOCK_BITS(s) (EXT3_SB(s)->s_desc_per_block_bits) - -/* - * Constants relative to the data blocks - */ -#define EXT3_NDIR_BLOCKS 12 -#define EXT3_IND_BLOCK EXT3_NDIR_BLOCKS -#define EXT3_DIND_BLOCK (EXT3_IND_BLOCK + 1) -#define EXT3_TIND_BLOCK (EXT3_DIND_BLOCK + 1) -#define EXT3_N_BLOCKS (EXT3_TIND_BLOCK + 1) - -/* - * Inode flags - */ -#define EXT3_SECRM_FL 0x00000001 /* Secure deletion */ -#define EXT3_UNRM_FL 0x00000002 /* Undelete */ -#define EXT3_COMPR_FL 0x00000004 /* Compress file */ -#define EXT3_SYNC_FL 0x00000008 /* Synchronous updates */ -#define EXT3_IMMUTABLE_FL 0x00000010 /* Immutable file */ -#define EXT3_APPEND_FL 0x00000020 /* writes to file may only append */ -#define EXT3_NODUMP_FL 0x00000040 /* do not dump file */ -#define EXT3_NOATIME_FL 0x00000080 /* do not update atime */ -/* Reserved for compression usage... */ -#define EXT3_DIRTY_FL 0x00000100 -#define EXT3_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ -#define EXT3_NOCOMPR_FL 0x00000400 /* Don't compress */ -#define EXT3_ECOMPR_FL 0x00000800 /* Compression error */ -/* End compression flags --- maybe not all used */ -#define EXT3_INDEX_FL 0x00001000 /* hash-indexed directory */ -#define EXT3_IMAGIC_FL 0x00002000 /* AFS directory */ -#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ -#define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ -#define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ -#define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ -#define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ - -#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ -#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ - -/* Flags that should be inherited by new inodes from their parent. */ -#define EXT3_FL_INHERITED (EXT3_SECRM_FL | EXT3_UNRM_FL | EXT3_COMPR_FL |\ - EXT3_SYNC_FL | EXT3_NODUMP_FL |\ - EXT3_NOATIME_FL | EXT3_COMPRBLK_FL |\ - EXT3_NOCOMPR_FL | EXT3_JOURNAL_DATA_FL |\ - EXT3_NOTAIL_FL | EXT3_DIRSYNC_FL) - -/* Flags that are appropriate for regular files (all but dir-specific ones). */ -#define EXT3_REG_FLMASK (~(EXT3_DIRSYNC_FL | EXT3_TOPDIR_FL)) - -/* Flags that are appropriate for non-directories/regular files. */ -#define EXT3_OTHER_FLMASK (EXT3_NODUMP_FL | EXT3_NOATIME_FL) - -/* Mask out flags that are inappropriate for the given type of inode. */ -static inline __u32 ext3_mask_flags(umode_t mode, __u32 flags) -{ - if (S_ISDIR(mode)) - return flags; - else if (S_ISREG(mode)) - return flags & EXT3_REG_FLMASK; - else - return flags & EXT3_OTHER_FLMASK; -} - -/* Used to pass group descriptor data when online resize is done */ -struct ext3_new_group_input { - __u32 group; /* Group number for this data */ - __u32 block_bitmap; /* Absolute block number of block bitmap */ - __u32 inode_bitmap; /* Absolute block number of inode bitmap */ - __u32 inode_table; /* Absolute block number of inode table start */ - __u32 blocks_count; /* Total number of blocks in this group */ - __u16 reserved_blocks; /* Number of reserved blocks in this group */ - __u16 unused; -}; - -/* The struct ext3_new_group_input in kernel space, with free_blocks_count */ -struct ext3_new_group_data { - __u32 group; - __u32 block_bitmap; - __u32 inode_bitmap; - __u32 inode_table; - __u32 blocks_count; - __u16 reserved_blocks; - __u16 unused; - __u32 free_blocks_count; -}; - - -/* - * ioctl commands - */ -#define EXT3_IOC_GETFLAGS FS_IOC_GETFLAGS -#define EXT3_IOC_SETFLAGS FS_IOC_SETFLAGS -#define EXT3_IOC_GETVERSION _IOR('f', 3, long) -#define EXT3_IOC_SETVERSION _IOW('f', 4, long) -#define EXT3_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) -#define EXT3_IOC_GROUP_ADD _IOW('f', 8,struct ext3_new_group_input) -#define EXT3_IOC_GETVERSION_OLD FS_IOC_GETVERSION -#define EXT3_IOC_SETVERSION_OLD FS_IOC_SETVERSION -#ifdef CONFIG_JBD_DEBUG -#define EXT3_IOC_WAIT_FOR_READONLY _IOR('f', 99, long) -#endif -#define EXT3_IOC_GETRSVSZ _IOR('f', 5, long) -#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long) - -/* - * ioctl commands in 32 bit emulation - */ -#define EXT3_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define EXT3_IOC32_SETFLAGS FS_IOC32_SETFLAGS -#define EXT3_IOC32_GETVERSION _IOR('f', 3, int) -#define EXT3_IOC32_SETVERSION _IOW('f', 4, int) -#define EXT3_IOC32_GETRSVSZ _IOR('f', 5, int) -#define EXT3_IOC32_SETRSVSZ _IOW('f', 6, int) -#define EXT3_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) -#ifdef CONFIG_JBD_DEBUG -#define EXT3_IOC32_WAIT_FOR_READONLY _IOR('f', 99, int) -#endif -#define EXT3_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION -#define EXT3_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION - -/* Number of supported quota types */ -#define EXT3_MAXQUOTAS 2 - -/* - * Mount options - */ -struct ext3_mount_options { - unsigned long s_mount_opt; - kuid_t s_resuid; - kgid_t s_resgid; - unsigned long s_commit_interval; -#ifdef CONFIG_QUOTA - int s_jquota_fmt; - char *s_qf_names[EXT3_MAXQUOTAS]; -#endif -}; - -/* - * Structure of an inode on the disk - */ -struct ext3_inode { - __le16 i_mode; /* File mode */ - __le16 i_uid; /* Low 16 bits of Owner Uid */ - __le32 i_size; /* Size in bytes */ - __le32 i_atime; /* Access time */ - __le32 i_ctime; /* Creation time */ - __le32 i_mtime; /* Modification time */ - __le32 i_dtime; /* Deletion Time */ - __le16 i_gid; /* Low 16 bits of Group Id */ - __le16 i_links_count; /* Links count */ - __le32 i_blocks; /* Blocks count */ - __le32 i_flags; /* File flags */ - union { - struct { - __u32 l_i_reserved1; - } linux1; - struct { - __u32 h_i_translator; - } hurd1; - struct { - __u32 m_i_reserved1; - } masix1; - } osd1; /* OS dependent 1 */ - __le32 i_block[EXT3_N_BLOCKS];/* Pointers to blocks */ - __le32 i_generation; /* File version (for NFS) */ - __le32 i_file_acl; /* File ACL */ - __le32 i_dir_acl; /* Directory ACL */ - __le32 i_faddr; /* Fragment address */ - union { - struct { - __u8 l_i_frag; /* Fragment number */ - __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; - __le16 l_i_uid_high; /* these 2 fields */ - __le16 l_i_gid_high; /* were reserved2[0] */ - __u32 l_i_reserved2; - } linux2; - struct { - __u8 h_i_frag; /* Fragment number */ - __u8 h_i_fsize; /* Fragment size */ - __u16 h_i_mode_high; - __u16 h_i_uid_high; - __u16 h_i_gid_high; - __u32 h_i_author; - } hurd2; - struct { - __u8 m_i_frag; /* Fragment number */ - __u8 m_i_fsize; /* Fragment size */ - __u16 m_pad1; - __u32 m_i_reserved2[2]; - } masix2; - } osd2; /* OS dependent 2 */ - __le16 i_extra_isize; - __le16 i_pad1; -}; - -#define i_size_high i_dir_acl - -#define i_reserved1 osd1.linux1.l_i_reserved1 -#define i_frag osd2.linux2.l_i_frag -#define i_fsize osd2.linux2.l_i_fsize -#define i_uid_low i_uid -#define i_gid_low i_gid -#define i_uid_high osd2.linux2.l_i_uid_high -#define i_gid_high osd2.linux2.l_i_gid_high -#define i_reserved2 osd2.linux2.l_i_reserved2 - -/* - * File system states - */ -#define EXT3_VALID_FS 0x0001 /* Unmounted cleanly */ -#define EXT3_ERROR_FS 0x0002 /* Errors detected */ -#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */ - -/* - * Misc. filesystem flags - */ -#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */ -#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */ -#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */ - -/* - * Mount flags - */ -#define EXT3_MOUNT_CHECK 0x00001 /* Do mount-time checks */ -/* EXT3_MOUNT_OLDALLOC was there */ -#define EXT3_MOUNT_GRPID 0x00004 /* Create files with directory's group */ -#define EXT3_MOUNT_DEBUG 0x00008 /* Some debugging messages */ -#define EXT3_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ -#define EXT3_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ -#define EXT3_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ -#define EXT3_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ -#define EXT3_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ -#define EXT3_MOUNT_ABORT 0x00200 /* Fatal error detected */ -#define EXT3_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ -#define EXT3_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ -#define EXT3_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ -#define EXT3_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ -#define EXT3_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ -#define EXT3_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ -#define EXT3_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ -#define EXT3_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ -#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */ -#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */ -#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */ -#define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ -#define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ -#define EXT3_MOUNT_DATA_ERR_ABORT 0x400000 /* Abort on file data write - * error in ordered mode */ - -/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ -#ifndef _LINUX_EXT2_FS_H -#define clear_opt(o, opt) o &= ~EXT3_MOUNT_##opt -#define set_opt(o, opt) o |= EXT3_MOUNT_##opt -#define test_opt(sb, opt) (EXT3_SB(sb)->s_mount_opt & \ - EXT3_MOUNT_##opt) -#else -#define EXT2_MOUNT_NOLOAD EXT3_MOUNT_NOLOAD -#define EXT2_MOUNT_ABORT EXT3_MOUNT_ABORT -#define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS -#endif - -#define ext3_set_bit __set_bit_le -#define ext3_set_bit_atomic ext2_set_bit_atomic -#define ext3_clear_bit __clear_bit_le -#define ext3_clear_bit_atomic ext2_clear_bit_atomic -#define ext3_test_bit test_bit_le -#define ext3_find_next_zero_bit find_next_zero_bit_le - -/* - * Maximal mount counts between two filesystem checks - */ -#define EXT3_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ -#define EXT3_DFL_CHECKINTERVAL 0 /* Don't use interval check */ - -/* - * Behaviour when detecting errors - */ -#define EXT3_ERRORS_CONTINUE 1 /* Continue execution */ -#define EXT3_ERRORS_RO 2 /* Remount fs read-only */ -#define EXT3_ERRORS_PANIC 3 /* Panic */ -#define EXT3_ERRORS_DEFAULT EXT3_ERRORS_CONTINUE - -/* - * Structure of the super block - */ -struct ext3_super_block { -/*00*/ __le32 s_inodes_count; /* Inodes count */ - __le32 s_blocks_count; /* Blocks count */ - __le32 s_r_blocks_count; /* Reserved blocks count */ - __le32 s_free_blocks_count; /* Free blocks count */ -/*10*/ __le32 s_free_inodes_count; /* Free inodes count */ - __le32 s_first_data_block; /* First Data Block */ - __le32 s_log_block_size; /* Block size */ - __le32 s_log_frag_size; /* Fragment size */ -/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */ - __le32 s_frags_per_group; /* # Fragments per group */ - __le32 s_inodes_per_group; /* # Inodes per group */ - __le32 s_mtime; /* Mount time */ -/*30*/ __le32 s_wtime; /* Write time */ - __le16 s_mnt_count; /* Mount count */ - __le16 s_max_mnt_count; /* Maximal mount count */ - __le16 s_magic; /* Magic signature */ - __le16 s_state; /* File system state */ - __le16 s_errors; /* Behaviour when detecting errors */ - __le16 s_minor_rev_level; /* minor revision level */ -/*40*/ __le32 s_lastcheck; /* time of last check */ - __le32 s_checkinterval; /* max. time between checks */ - __le32 s_creator_os; /* OS */ - __le32 s_rev_level; /* Revision level */ -/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */ - __le16 s_def_resgid; /* Default gid for reserved blocks */ - /* - * These fields are for EXT3_DYNAMIC_REV superblocks only. - * - * Note: the difference between the compatible feature set and - * the incompatible feature set is that if there is a bit set - * in the incompatible feature set that the kernel doesn't - * know about, it should refuse to mount the filesystem. - * - * e2fsck's requirements are more strict; if it doesn't know - * about a feature in either the compatible or incompatible - * feature set, it must abort and not try to meddle with - * things it doesn't understand... - */ - __le32 s_first_ino; /* First non-reserved inode */ - __le16 s_inode_size; /* size of inode structure */ - __le16 s_block_group_nr; /* block group # of this superblock */ - __le32 s_feature_compat; /* compatible feature set */ -/*60*/ __le32 s_feature_incompat; /* incompatible feature set */ - __le32 s_feature_ro_compat; /* readonly-compatible feature set */ -/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ -/*78*/ char s_volume_name[16]; /* volume name */ -/*88*/ char s_last_mounted[64]; /* directory where last mounted */ -/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */ - /* - * Performance hints. Directory preallocation should only - * happen if the EXT3_FEATURE_COMPAT_DIR_PREALLOC flag is on. - */ - __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ - __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ - /* - * Journaling support valid if EXT3_FEATURE_COMPAT_HAS_JOURNAL set. - */ -/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ -/*E0*/ __le32 s_journal_inum; /* inode number of journal file */ - __le32 s_journal_dev; /* device number of journal file */ - __le32 s_last_orphan; /* start of list of inodes to delete */ - __le32 s_hash_seed[4]; /* HTREE hash seed */ - __u8 s_def_hash_version; /* Default hash version to use */ - __u8 s_reserved_char_pad; - __u16 s_reserved_word_pad; - __le32 s_default_mount_opts; - __le32 s_first_meta_bg; /* First metablock block group */ - __le32 s_mkfs_time; /* When the filesystem was created */ - __le32 s_jnl_blocks[17]; /* Backup of the journal inode */ - /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ -/*150*/ __le32 s_blocks_count_hi; /* Blocks count */ - __le32 s_r_blocks_count_hi; /* Reserved blocks count */ - __le32 s_free_blocks_count_hi; /* Free blocks count */ - __le16 s_min_extra_isize; /* All inodes have at least # bytes */ - __le16 s_want_extra_isize; /* New inodes should reserve # bytes */ - __le32 s_flags; /* Miscellaneous flags */ - __le16 s_raid_stride; /* RAID stride */ - __le16 s_mmp_interval; /* # seconds to wait in MMP checking */ - __le64 s_mmp_block; /* Block for multi-mount protection */ - __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ - __u8 s_log_groups_per_flex; /* FLEX_BG group size */ - __u8 s_reserved_char_pad2; - __le16 s_reserved_pad; - __u32 s_reserved[162]; /* Padding to the end of the block */ -}; - -/* data type for block offset of block group */ -typedef int ext3_grpblk_t; - -/* data type for filesystem-wide blocks number */ -typedef unsigned long ext3_fsblk_t; - -#define E3FSBLK "%lu" - -struct ext3_reserve_window { - ext3_fsblk_t _rsv_start; /* First byte reserved */ - ext3_fsblk_t _rsv_end; /* Last byte reserved or 0 */ -}; - -struct ext3_reserve_window_node { - struct rb_node rsv_node; - __u32 rsv_goal_size; - __u32 rsv_alloc_hit; - struct ext3_reserve_window rsv_window; -}; - -struct ext3_block_alloc_info { - /* information about reservation window */ - struct ext3_reserve_window_node rsv_window_node; - /* - * was i_next_alloc_block in ext3_inode_info - * is the logical (file-relative) number of the - * most-recently-allocated block in this file. - * We use this for detecting linearly ascending allocation requests. - */ - __u32 last_alloc_logical_block; - /* - * Was i_next_alloc_goal in ext3_inode_info - * is the *physical* companion to i_next_alloc_block. - * it the physical block number of the block which was most-recentl - * allocated to this file. This give us the goal (target) for the next - * allocation when we detect linearly ascending requests. - */ - ext3_fsblk_t last_alloc_physical_block; -}; - -#define rsv_start rsv_window._rsv_start -#define rsv_end rsv_window._rsv_end - -/* - * third extended file system inode data in memory - */ -struct ext3_inode_info { - __le32 i_data[15]; /* unconverted */ - __u32 i_flags; -#ifdef EXT3_FRAGMENTS - __u32 i_faddr; - __u8 i_frag_no; - __u8 i_frag_size; -#endif - ext3_fsblk_t i_file_acl; - __u32 i_dir_acl; - __u32 i_dtime; - - /* - * i_block_group is the number of the block group which contains - * this file's inode. Constant across the lifetime of the inode, - * it is ued for making block allocation decisions - we try to - * place a file's data blocks near its inode block, and new inodes - * near to their parent directory's inode. - */ - __u32 i_block_group; - unsigned long i_state_flags; /* Dynamic state flags for ext3 */ - - /* block reservation info */ - struct ext3_block_alloc_info *i_block_alloc_info; - - __u32 i_dir_start_lookup; -#ifdef CONFIG_EXT3_FS_XATTR - /* - * Extended attributes can be read independently of the main file - * data. Taking i_mutex even when reading would cause contention - * between readers of EAs and writers of regular file data, so - * instead we synchronize on xattr_sem when reading or changing - * EAs. - */ - struct rw_semaphore xattr_sem; -#endif - - struct list_head i_orphan; /* unlinked but open inodes */ - - /* - * i_disksize keeps track of what the inode size is ON DISK, not - * in memory. During truncate, i_size is set to the new size by - * the VFS prior to calling ext3_truncate(), but the filesystem won't - * set i_disksize to 0 until the truncate is actually under way. - * - * The intent is that i_disksize always represents the blocks which - * are used by this file. This allows recovery to restart truncate - * on orphans if we crash during truncate. We actually write i_disksize - * into the on-disk inode when writing inodes out, instead of i_size. - * - * The only time when i_disksize and i_size may be different is when - * a truncate is in progress. The only things which change i_disksize - * are ext3_get_block (growth) and ext3_truncate (shrinkth). - */ - loff_t i_disksize; - - /* on-disk additional length */ - __u16 i_extra_isize; - - /* - * truncate_mutex is for serialising ext3_truncate() against - * ext3_getblock(). In the 2.4 ext2 design, great chunks of inode's - * data tree are chopped off during truncate. We can't do that in - * ext3 because whenever we perform intermediate commits during - * truncate, the inode and all the metadata blocks *must* be in a - * consistent state which allows truncation of the orphans to restart - * during recovery. Hence we must fix the get_block-vs-truncate race - * by other means, so we have truncate_mutex. - */ - struct mutex truncate_mutex; - - /* - * Transactions that contain inode's metadata needed to complete - * fsync and fdatasync, respectively. - */ - atomic_t i_sync_tid; - atomic_t i_datasync_tid; - -#ifdef CONFIG_QUOTA - struct dquot *i_dquot[MAXQUOTAS]; -#endif - - struct inode vfs_inode; -}; - -/* - * third extended-fs super-block data in memory - */ -struct ext3_sb_info { - unsigned long s_frag_size; /* Size of a fragment in bytes */ - unsigned long s_frags_per_block;/* Number of fragments per block */ - unsigned long s_inodes_per_block;/* Number of inodes per block */ - unsigned long s_frags_per_group;/* Number of fragments in a group */ - unsigned long s_blocks_per_group;/* Number of blocks in a group */ - unsigned long s_inodes_per_group;/* Number of inodes in a group */ - unsigned long s_itb_per_group; /* Number of inode table blocks per group */ - unsigned long s_gdb_count; /* Number of group descriptor blocks */ - unsigned long s_desc_per_block; /* Number of group descriptors per block */ - unsigned long s_groups_count; /* Number of groups in the fs */ - unsigned long s_overhead_last; /* Last calculated overhead */ - unsigned long s_blocks_last; /* Last seen block count */ - struct buffer_head * s_sbh; /* Buffer containing the super block */ - struct ext3_super_block * s_es; /* Pointer to the super block in the buffer */ - struct buffer_head ** s_group_desc; - unsigned long s_mount_opt; - ext3_fsblk_t s_sb_block; - kuid_t s_resuid; - kgid_t s_resgid; - unsigned short s_mount_state; - unsigned short s_pad; - int s_addr_per_block_bits; - int s_desc_per_block_bits; - int s_inode_size; - int s_first_ino; - spinlock_t s_next_gen_lock; - u32 s_next_generation; - u32 s_hash_seed[4]; - int s_def_hash_version; - int s_hash_unsigned; /* 3 if hash should be signed, 0 if not */ - struct percpu_counter s_freeblocks_counter; - struct percpu_counter s_freeinodes_counter; - struct percpu_counter s_dirs_counter; - struct blockgroup_lock *s_blockgroup_lock; - - /* root of the per fs reservation window tree */ - spinlock_t s_rsv_window_lock; - struct rb_root s_rsv_window_root; - struct ext3_reserve_window_node s_rsv_window_head; - - /* Journaling */ - struct inode * s_journal_inode; - struct journal_s * s_journal; - struct list_head s_orphan; - struct mutex s_orphan_lock; - struct mutex s_resize_lock; - unsigned long s_commit_interval; - struct block_device *journal_bdev; -#ifdef CONFIG_QUOTA - char *s_qf_names[EXT3_MAXQUOTAS]; /* Names of quota files with journalled quota */ - int s_jquota_fmt; /* Format of quota to use */ -#endif -}; - -static inline spinlock_t * -sb_bgl_lock(struct ext3_sb_info *sbi, unsigned int block_group) -{ - return bgl_lock_ptr(sbi->s_blockgroup_lock, block_group); -} - -static inline struct ext3_sb_info * EXT3_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} -static inline struct ext3_inode_info *EXT3_I(struct inode *inode) -{ - return container_of(inode, struct ext3_inode_info, vfs_inode); -} - -static inline int ext3_valid_inum(struct super_block *sb, unsigned long ino) -{ - return ino == EXT3_ROOT_INO || - ino == EXT3_JOURNAL_INO || - ino == EXT3_RESIZE_INO || - (ino >= EXT3_FIRST_INO(sb) && - ino <= le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)); -} - -/* - * Inode dynamic state flags - */ -enum { - EXT3_STATE_JDATA, /* journaled data exists */ - EXT3_STATE_NEW, /* inode is newly created */ - EXT3_STATE_XATTR, /* has in-inode xattrs */ - EXT3_STATE_FLUSH_ON_CLOSE, /* flush dirty pages on close */ -}; - -static inline int ext3_test_inode_state(struct inode *inode, int bit) -{ - return test_bit(bit, &EXT3_I(inode)->i_state_flags); -} - -static inline void ext3_set_inode_state(struct inode *inode, int bit) -{ - set_bit(bit, &EXT3_I(inode)->i_state_flags); -} - -static inline void ext3_clear_inode_state(struct inode *inode, int bit) -{ - clear_bit(bit, &EXT3_I(inode)->i_state_flags); -} - -#define NEXT_ORPHAN(inode) EXT3_I(inode)->i_dtime - -/* - * Codes for operating systems - */ -#define EXT3_OS_LINUX 0 -#define EXT3_OS_HURD 1 -#define EXT3_OS_MASIX 2 -#define EXT3_OS_FREEBSD 3 -#define EXT3_OS_LITES 4 - -/* - * Revision levels - */ -#define EXT3_GOOD_OLD_REV 0 /* The good old (original) format */ -#define EXT3_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ - -#define EXT3_CURRENT_REV EXT3_GOOD_OLD_REV -#define EXT3_MAX_SUPP_REV EXT3_DYNAMIC_REV - -#define EXT3_GOOD_OLD_INODE_SIZE 128 - -/* - * Feature set definitions - */ - -#define EXT3_HAS_COMPAT_FEATURE(sb,mask) \ - ( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) ) -#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask) \ - ( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) ) -#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask) \ - ( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) ) -#define EXT3_SET_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask) -#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask) -#define EXT3_SET_INCOMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask) -#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask) -#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask) -#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask) \ - EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask) - -#define EXT3_FEATURE_COMPAT_DIR_PREALLOC 0x0001 -#define EXT3_FEATURE_COMPAT_IMAGIC_INODES 0x0002 -#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 -#define EXT3_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT3_FEATURE_COMPAT_RESIZE_INODE 0x0010 -#define EXT3_FEATURE_COMPAT_DIR_INDEX 0x0020 - -#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 - -#define EXT3_FEATURE_INCOMPAT_COMPRESSION 0x0001 -#define EXT3_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ -#define EXT3_FEATURE_INCOMPAT_META_BG 0x0010 - -#define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR -#define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ - EXT3_FEATURE_INCOMPAT_RECOVER| \ - EXT3_FEATURE_INCOMPAT_META_BG) -#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT3_FEATURE_RO_COMPAT_BTREE_DIR) - -/* - * Default values for user and/or group using reserved blocks - */ -#define EXT3_DEF_RESUID 0 -#define EXT3_DEF_RESGID 0 - -/* - * Default mount options - */ -#define EXT3_DEFM_DEBUG 0x0001 -#define EXT3_DEFM_BSDGROUPS 0x0002 -#define EXT3_DEFM_XATTR_USER 0x0004 -#define EXT3_DEFM_ACL 0x0008 -#define EXT3_DEFM_UID16 0x0010 -#define EXT3_DEFM_JMODE 0x0060 -#define EXT3_DEFM_JMODE_DATA 0x0020 -#define EXT3_DEFM_JMODE_ORDERED 0x0040 -#define EXT3_DEFM_JMODE_WBACK 0x0060 - -/* - * Structure of a directory entry - */ -#define EXT3_NAME_LEN 255 - -struct ext3_dir_entry { - __le32 inode; /* Inode number */ - __le16 rec_len; /* Directory entry length */ - __le16 name_len; /* Name length */ - char name[EXT3_NAME_LEN]; /* File name */ -}; - -/* - * The new version of the directory entry. Since EXT3 structures are - * stored in intel byte order, and the name_len field could never be - * bigger than 255 chars, it's safe to reclaim the extra byte for the - * file_type field. - */ -struct ext3_dir_entry_2 { - __le32 inode; /* Inode number */ - __le16 rec_len; /* Directory entry length */ - __u8 name_len; /* Name length */ - __u8 file_type; - char name[EXT3_NAME_LEN]; /* File name */ -}; - -/* - * Ext3 directory file types. Only the low 3 bits are used. The - * other bits are reserved for now. - */ -#define EXT3_FT_UNKNOWN 0 -#define EXT3_FT_REG_FILE 1 -#define EXT3_FT_DIR 2 -#define EXT3_FT_CHRDEV 3 -#define EXT3_FT_BLKDEV 4 -#define EXT3_FT_FIFO 5 -#define EXT3_FT_SOCK 6 -#define EXT3_FT_SYMLINK 7 - -#define EXT3_FT_MAX 8 - -/* - * EXT3_DIR_PAD defines the directory entries boundaries - * - * NOTE: It must be a multiple of 4 - */ -#define EXT3_DIR_PAD 4 -#define EXT3_DIR_ROUND (EXT3_DIR_PAD - 1) -#define EXT3_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT3_DIR_ROUND) & \ - ~EXT3_DIR_ROUND) -#define EXT3_MAX_REC_LEN ((1<<16)-1) - -/* - * Tests against MAX_REC_LEN etc were put in place for 64k block - * sizes; if that is not possible on this arch, we can skip - * those tests and speed things up. - */ -static inline unsigned ext3_rec_len_from_disk(__le16 dlen) -{ - unsigned len = le16_to_cpu(dlen); - -#if (PAGE_CACHE_SIZE >= 65536) - if (len == EXT3_MAX_REC_LEN) - return 1 << 16; -#endif - return len; -} - -static inline __le16 ext3_rec_len_to_disk(unsigned len) -{ -#if (PAGE_CACHE_SIZE >= 65536) - if (len == (1 << 16)) - return cpu_to_le16(EXT3_MAX_REC_LEN); - else if (len > (1 << 16)) - BUG(); -#endif - return cpu_to_le16(len); -} - -/* - * Hash Tree Directory indexing - * (c) Daniel Phillips, 2001 - */ - -#define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \ - EXT3_FEATURE_COMPAT_DIR_INDEX) && \ - (EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) -#define EXT3_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX) -#define EXT3_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1) - -/* Legal values for the dx_root hash_version field: */ - -#define DX_HASH_LEGACY 0 -#define DX_HASH_HALF_MD4 1 -#define DX_HASH_TEA 2 -#define DX_HASH_LEGACY_UNSIGNED 3 -#define DX_HASH_HALF_MD4_UNSIGNED 4 -#define DX_HASH_TEA_UNSIGNED 5 - -/* hash info structure used by the directory hash */ -struct dx_hash_info -{ - u32 hash; - u32 minor_hash; - int hash_version; - u32 *seed; -}; - - -/* 32 and 64 bit signed EOF for dx directories */ -#define EXT3_HTREE_EOF_32BIT ((1UL << (32 - 1)) - 1) -#define EXT3_HTREE_EOF_64BIT ((1ULL << (64 - 1)) - 1) - - -/* - * Control parameters used by ext3_htree_next_block - */ -#define HASH_NB_ALWAYS 1 - - -/* - * Describe an inode's exact location on disk and in memory - */ -struct ext3_iloc -{ - struct buffer_head *bh; - unsigned long offset; - unsigned long block_group; -}; - -static inline struct ext3_inode *ext3_raw_inode(struct ext3_iloc *iloc) -{ - return (struct ext3_inode *) (iloc->bh->b_data + iloc->offset); -} - -/* - * This structure is stuffed into the struct file's private_data field - * for directories. It is where we put information so that we can do - * readdir operations in hash tree order. - */ -struct dir_private_info { - struct rb_root root; - struct rb_node *curr_node; - struct fname *extra_fname; - loff_t last_pos; - __u32 curr_hash; - __u32 curr_minor_hash; - __u32 next_hash; -}; - -/* calculate the first block number of the group */ -static inline ext3_fsblk_t -ext3_group_first_block_no(struct super_block *sb, unsigned long group_no) -{ - return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) + - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block); -} - -/* - * Special error return code only used by dx_probe() and its callers. - */ -#define ERR_BAD_DX_DIR -75000 - -/* - * Function prototypes - */ - -/* - * Ok, these declarations are also in but none of the - * ext3 source programs needs to include it so they are duplicated here. - */ -# define NORET_TYPE /**/ -# define ATTRIB_NORET __attribute__((noreturn)) -# define NORET_AND noreturn, - -/* balloc.c */ -extern int ext3_bg_has_super(struct super_block *sb, int group); -extern unsigned long ext3_bg_num_gdb(struct super_block *sb, int group); -extern ext3_fsblk_t ext3_new_block (handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, int *errp); -extern ext3_fsblk_t ext3_new_blocks (handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, unsigned long *count, int *errp); -extern void ext3_free_blocks (handle_t *handle, struct inode *inode, - ext3_fsblk_t block, unsigned long count); -extern void ext3_free_blocks_sb (handle_t *handle, struct super_block *sb, - ext3_fsblk_t block, unsigned long count, - unsigned long *pdquot_freed_blocks); -extern ext3_fsblk_t ext3_count_free_blocks (struct super_block *); -extern void ext3_check_blocks_bitmap (struct super_block *); -extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb, - unsigned int block_group, - struct buffer_head ** bh); -extern int ext3_should_retry_alloc(struct super_block *sb, int *retries); -extern void ext3_init_block_alloc_info(struct inode *); -extern void ext3_rsv_window_add(struct super_block *sb, struct ext3_reserve_window_node *rsv); -extern int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range); - -/* dir.c */ -extern int ext3_check_dir_entry(const char *, struct inode *, - struct ext3_dir_entry_2 *, - struct buffer_head *, unsigned long); -extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash, - __u32 minor_hash, - struct ext3_dir_entry_2 *dirent); -extern void ext3_htree_free_dir_info(struct dir_private_info *p); - -/* fsync.c */ -extern int ext3_sync_file(struct file *, loff_t, loff_t, int); - -/* hash.c */ -extern int ext3fs_dirhash(const char *name, int len, struct - dx_hash_info *hinfo); - -/* ialloc.c */ -extern struct inode * ext3_new_inode (handle_t *, struct inode *, - const struct qstr *, umode_t); -extern void ext3_free_inode (handle_t *, struct inode *); -extern struct inode * ext3_orphan_get (struct super_block *, unsigned long); -extern unsigned long ext3_count_free_inodes (struct super_block *); -extern unsigned long ext3_count_dirs (struct super_block *); -extern void ext3_check_inodes_bitmap (struct super_block *); -extern unsigned long ext3_count_free (struct buffer_head *, unsigned); - - -/* inode.c */ -int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, - struct buffer_head *bh, ext3_fsblk_t blocknr); -struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); -struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); -int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, - sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result, - int create); - -extern struct inode *ext3_iget(struct super_block *, unsigned long); -extern int ext3_write_inode (struct inode *, struct writeback_control *); -extern int ext3_setattr (struct dentry *, struct iattr *); -extern void ext3_evict_inode (struct inode *); -extern int ext3_sync_inode (handle_t *, struct inode *); -extern void ext3_discard_reservation (struct inode *); -extern void ext3_dirty_inode(struct inode *, int); -extern int ext3_change_inode_journal_flag(struct inode *, int); -extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *); -extern int ext3_can_truncate(struct inode *inode); -extern void ext3_truncate(struct inode *inode); -extern void ext3_set_inode_flags(struct inode *); -extern void ext3_get_inode_flags(struct ext3_inode_info *); -extern void ext3_set_aops(struct inode *inode); -extern int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len); - -/* ioctl.c */ -extern long ext3_ioctl(struct file *, unsigned int, unsigned long); -extern long ext3_compat_ioctl(struct file *, unsigned int, unsigned long); - -/* namei.c */ -extern int ext3_orphan_add(handle_t *, struct inode *); -extern int ext3_orphan_del(handle_t *, struct inode *); -extern int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, - __u32 start_minor_hash, __u32 *next_hash); - -/* resize.c */ -extern int ext3_group_add(struct super_block *sb, - struct ext3_new_group_data *input); -extern int ext3_group_extend(struct super_block *sb, - struct ext3_super_block *es, - ext3_fsblk_t n_blocks_count); - -/* super.c */ -extern __printf(3, 4) -void ext3_error(struct super_block *, const char *, const char *, ...); -extern void __ext3_std_error (struct super_block *, const char *, int); -extern __printf(3, 4) -void ext3_abort(struct super_block *, const char *, const char *, ...); -extern __printf(3, 4) -void ext3_warning(struct super_block *, const char *, const char *, ...); -extern __printf(3, 4) -void ext3_msg(struct super_block *, const char *, const char *, ...); -extern void ext3_update_dynamic_rev (struct super_block *sb); - -#define ext3_std_error(sb, errno) \ -do { \ - if ((errno)) \ - __ext3_std_error((sb), __func__, (errno)); \ -} while (0) - -/* - * Inodes and files operations - */ - -/* dir.c */ -extern const struct file_operations ext3_dir_operations; - -/* file.c */ -extern const struct inode_operations ext3_file_inode_operations; -extern const struct file_operations ext3_file_operations; - -/* namei.c */ -extern const struct inode_operations ext3_dir_inode_operations; -extern const struct inode_operations ext3_special_inode_operations; - -/* symlink.c */ -extern const struct inode_operations ext3_symlink_inode_operations; -extern const struct inode_operations ext3_fast_symlink_inode_operations; - -#define EXT3_JOURNAL(inode) (EXT3_SB((inode)->i_sb)->s_journal) - -/* Define the number of blocks we need to account to a transaction to - * modify one block of data. - * - * We may have to touch one inode, one bitmap buffer, up to three - * indirection blocks, the group and superblock summaries, and the data - * block to complete the transaction. */ - -#define EXT3_SINGLEDATA_TRANS_BLOCKS 8U - -/* Extended attribute operations touch at most two data buffers, - * two bitmap buffers, and two group summaries, in addition to the inode - * and the superblock, which are already accounted for. */ - -#define EXT3_XATTR_TRANS_BLOCKS 6U - -/* Define the minimum size for a transaction which modifies data. This - * needs to take into account the fact that we may end up modifying two - * quota files too (one for the group, one for the user quota). The - * superblock only gets updated once, of course, so don't bother - * counting that again for the quota updates. */ - -#define EXT3_DATA_TRANS_BLOCKS(sb) (EXT3_SINGLEDATA_TRANS_BLOCKS + \ - EXT3_XATTR_TRANS_BLOCKS - 2 + \ - EXT3_MAXQUOTAS_TRANS_BLOCKS(sb)) - -/* Delete operations potentially hit one directory's namespace plus an - * entire inode, plus arbitrary amounts of bitmap/indirection data. Be - * generous. We can grow the delete transaction later if necessary. */ - -#define EXT3_DELETE_TRANS_BLOCKS(sb) (EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) + 64) - -/* Define an arbitrary limit for the amount of data we will anticipate - * writing to any given transaction. For unbounded transactions such as - * write(2) and truncate(2) we can write more than this, but we always - * start off at the maximum transaction size and grow the transaction - * optimistically as we go. */ - -#define EXT3_MAX_TRANS_DATA 64U - -/* We break up a large truncate or write transaction once the handle's - * buffer credits gets this low, we need either to extend the - * transaction or to start a new one. Reserve enough space here for - * inode, bitmap, superblock, group and indirection updates for at least - * one block, plus two quota updates. Quota allocations are not - * needed. */ - -#define EXT3_RESERVE_TRANS_BLOCKS 12U - -#define EXT3_INDEX_EXTRA_TRANS_BLOCKS 8 - -#ifdef CONFIG_QUOTA -/* Amount of blocks needed for quota update - we know that the structure was - * allocated so we need to update only inode+data */ -#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0) -/* Amount of blocks needed for quota insert/delete - we do some block writes - * but inode, sb and group updates are done only once */ -#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\ - (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0) -#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\ - (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0) -#else -#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0 -#define EXT3_QUOTA_INIT_BLOCKS(sb) 0 -#define EXT3_QUOTA_DEL_BLOCKS(sb) 0 -#endif -#define EXT3_MAXQUOTAS_TRANS_BLOCKS(sb) (EXT3_MAXQUOTAS*EXT3_QUOTA_TRANS_BLOCKS(sb)) -#define EXT3_MAXQUOTAS_INIT_BLOCKS(sb) (EXT3_MAXQUOTAS*EXT3_QUOTA_INIT_BLOCKS(sb)) -#define EXT3_MAXQUOTAS_DEL_BLOCKS(sb) (EXT3_MAXQUOTAS*EXT3_QUOTA_DEL_BLOCKS(sb)) - -int -ext3_mark_iloc_dirty(handle_t *handle, - struct inode *inode, - struct ext3_iloc *iloc); - -/* - * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. - */ - -int ext3_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext3_iloc *iloc); - -int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode); - -/* - * Wrapper functions with which ext3 calls into JBD. The intent here is - * to allow these to be turned into appropriate stubs so ext3 can control - * ext2 filesystems, so ext2+ext3 systems only nee one fs. This work hasn't - * been done yet. - */ - -static inline void ext3_journal_release_buffer(handle_t *handle, - struct buffer_head *bh) -{ - journal_release_buffer(handle, bh); -} - -void ext3_journal_abort_handle(const char *caller, const char *err_fn, - struct buffer_head *bh, handle_t *handle, int err); - -int __ext3_journal_get_undo_access(const char *where, handle_t *handle, - struct buffer_head *bh); - -int __ext3_journal_get_write_access(const char *where, handle_t *handle, - struct buffer_head *bh); - -int __ext3_journal_forget(const char *where, handle_t *handle, - struct buffer_head *bh); - -int __ext3_journal_revoke(const char *where, handle_t *handle, - unsigned long blocknr, struct buffer_head *bh); - -int __ext3_journal_get_create_access(const char *where, - handle_t *handle, struct buffer_head *bh); - -int __ext3_journal_dirty_metadata(const char *where, - handle_t *handle, struct buffer_head *bh); - -#define ext3_journal_get_undo_access(handle, bh) \ - __ext3_journal_get_undo_access(__func__, (handle), (bh)) -#define ext3_journal_get_write_access(handle, bh) \ - __ext3_journal_get_write_access(__func__, (handle), (bh)) -#define ext3_journal_revoke(handle, blocknr, bh) \ - __ext3_journal_revoke(__func__, (handle), (blocknr), (bh)) -#define ext3_journal_get_create_access(handle, bh) \ - __ext3_journal_get_create_access(__func__, (handle), (bh)) -#define ext3_journal_dirty_metadata(handle, bh) \ - __ext3_journal_dirty_metadata(__func__, (handle), (bh)) -#define ext3_journal_forget(handle, bh) \ - __ext3_journal_forget(__func__, (handle), (bh)) - -int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh); - -handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks); -int __ext3_journal_stop(const char *where, handle_t *handle); - -static inline handle_t *ext3_journal_start(struct inode *inode, int nblocks) -{ - return ext3_journal_start_sb(inode->i_sb, nblocks); -} - -#define ext3_journal_stop(handle) \ - __ext3_journal_stop(__func__, (handle)) - -static inline handle_t *ext3_journal_current_handle(void) -{ - return journal_current_handle(); -} - -static inline int ext3_journal_extend(handle_t *handle, int nblocks) -{ - return journal_extend(handle, nblocks); -} - -static inline int ext3_journal_restart(handle_t *handle, int nblocks) -{ - return journal_restart(handle, nblocks); -} - -static inline int ext3_journal_blocks_per_page(struct inode *inode) -{ - return journal_blocks_per_page(inode); -} - -static inline int ext3_journal_force_commit(journal_t *journal) -{ - return journal_force_commit(journal); -} - -/* super.c */ -int ext3_force_commit(struct super_block *sb); - -static inline int ext3_should_journal_data(struct inode *inode) -{ - if (!S_ISREG(inode->i_mode)) - return 1; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA) - return 1; - if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) - return 1; - return 0; -} - -static inline int ext3_should_order_data(struct inode *inode) -{ - if (!S_ISREG(inode->i_mode)) - return 0; - if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) - return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA) - return 1; - return 0; -} - -static inline int ext3_should_writeback_data(struct inode *inode) -{ - if (!S_ISREG(inode->i_mode)) - return 0; - if (EXT3_I(inode)->i_flags & EXT3_JOURNAL_DATA_FL) - return 0; - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_WRITEBACK_DATA) - return 1; - return 0; -} - -#include diff --git a/fs/ext3/ext3_jbd.c b/fs/ext3/ext3_jbd.c deleted file mode 100644 index 785a3261a26c6..0000000000000 --- a/fs/ext3/ext3_jbd.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Interface between ext3 and JBD - */ - -#include "ext3.h" - -int __ext3_journal_get_undo_access(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = journal_get_undo_access(handle, bh); - if (err) - ext3_journal_abort_handle(where, __func__, bh, handle,err); - return err; -} - -int __ext3_journal_get_write_access(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = journal_get_write_access(handle, bh); - if (err) - ext3_journal_abort_handle(where, __func__, bh, handle,err); - return err; -} - -int __ext3_journal_forget(const char *where, handle_t *handle, - struct buffer_head *bh) -{ - int err = journal_forget(handle, bh); - if (err) - ext3_journal_abort_handle(where, __func__, bh, handle,err); - return err; -} - -int __ext3_journal_revoke(const char *where, handle_t *handle, - unsigned long blocknr, struct buffer_head *bh) -{ - int err = journal_revoke(handle, blocknr, bh); - if (err) - ext3_journal_abort_handle(where, __func__, bh, handle,err); - return err; -} - -int __ext3_journal_get_create_access(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = journal_get_create_access(handle, bh); - if (err) - ext3_journal_abort_handle(where, __func__, bh, handle,err); - return err; -} - -int __ext3_journal_dirty_metadata(const char *where, - handle_t *handle, struct buffer_head *bh) -{ - int err = journal_dirty_metadata(handle, bh); - if (err) - ext3_journal_abort_handle(where, __func__, bh, handle,err); - return err; -} diff --git a/fs/ext3/file.c b/fs/ext3/file.c deleted file mode 100644 index 3b8f650de22ce..0000000000000 --- a/fs/ext3/file.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * linux/fs/ext3/file.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/file.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext3 fs regular file handling primitives - * - * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) - */ - -#include -#include "ext3.h" -#include "xattr.h" -#include "acl.h" - -/* - * Called when an inode is released. Note that this is different - * from ext3_file_open: open gets called at every open, but release - * gets called only when /all/ the files are closed. - */ -static int ext3_release_file (struct inode * inode, struct file * filp) -{ - if (ext3_test_inode_state(inode, EXT3_STATE_FLUSH_ON_CLOSE)) { - filemap_flush(inode->i_mapping); - ext3_clear_inode_state(inode, EXT3_STATE_FLUSH_ON_CLOSE); - } - /* if we are the last writer on the inode, drop the block reservation */ - if ((filp->f_mode & FMODE_WRITE) && - (atomic_read(&inode->i_writecount) == 1)) - { - mutex_lock(&EXT3_I(inode)->truncate_mutex); - ext3_discard_reservation(inode); - mutex_unlock(&EXT3_I(inode)->truncate_mutex); - } - if (is_dx(inode) && filp->private_data) - ext3_htree_free_dir_info(filp->private_data); - - return 0; -} - -const struct file_operations ext3_file_operations = { - .llseek = generic_file_llseek, - .read_iter = generic_file_read_iter, - .write_iter = generic_file_write_iter, - .unlocked_ioctl = ext3_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext3_compat_ioctl, -#endif - .mmap = generic_file_mmap, - .open = dquot_file_open, - .release = ext3_release_file, - .fsync = ext3_sync_file, - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, -}; - -const struct inode_operations ext3_file_inode_operations = { - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, - .removexattr = generic_removexattr, -#endif - .get_acl = ext3_get_acl, - .set_acl = ext3_set_acl, - .fiemap = ext3_fiemap, -}; - diff --git a/fs/ext3/fsync.c b/fs/ext3/fsync.c deleted file mode 100644 index 1cb9c7e10c6f2..0000000000000 --- a/fs/ext3/fsync.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * linux/fs/ext3/fsync.c - * - * Copyright (C) 1993 Stephen Tweedie (sct@redhat.com) - * from - * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * from - * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds - * - * ext3fs fsync primitive - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * - * Removed unnecessary code duplication for little endian machines - * and excessive __inline__s. - * Andi Kleen, 1997 - * - * Major simplications and cleanup - we only need to do the metadata, because - * we can depend on generic_block_fdatasync() to sync the data blocks. - */ - -#include -#include -#include "ext3.h" - -/* - * akpm: A new design for ext3_sync_file(). - * - * This is only called from sys_fsync(), sys_fdatasync() and sys_msync(). - * There cannot be a transaction open by this task. - * Another task could have dirtied this inode. Its data can be in any - * state in the journalling system. - * - * What we do is just kick off a commit and wait on it. This will snapshot the - * inode to disk. - */ - -int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) -{ - struct inode *inode = file->f_mapping->host; - struct ext3_inode_info *ei = EXT3_I(inode); - journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; - int ret, needs_barrier = 0; - tid_t commit_tid; - - trace_ext3_sync_file_enter(file, datasync); - - if (inode->i_sb->s_flags & MS_RDONLY) { - /* Make sure that we read updated state */ - smp_rmb(); - if (EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS) - return -EROFS; - return 0; - } - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - goto out; - - J_ASSERT(ext3_journal_current_handle() == NULL); - - /* - * data=writeback,ordered: - * The caller's filemap_fdatawrite()/wait will sync the data. - * Metadata is in the journal, we wait for a proper transaction - * to commit here. - * - * data=journal: - * filemap_fdatawrite won't do anything (the buffers are clean). - * ext3_force_commit will write the file data into the journal and - * will wait on that. - * filemap_fdatawait() will encounter a ton of newly-dirtied pages - * (they were dirtied by commit). But that's OK - the blocks are - * safe in-journal, which is all fsync() needs to ensure. - */ - if (ext3_should_journal_data(inode)) { - ret = ext3_force_commit(inode->i_sb); - goto out; - } - - if (datasync) - commit_tid = atomic_read(&ei->i_datasync_tid); - else - commit_tid = atomic_read(&ei->i_sync_tid); - - if (test_opt(inode->i_sb, BARRIER) && - !journal_trans_will_send_data_barrier(journal, commit_tid)) - needs_barrier = 1; - log_start_commit(journal, commit_tid); - ret = log_wait_commit(journal, commit_tid); - - /* - * In case we didn't commit a transaction, we have to flush - * disk caches manually so that data really is on persistent - * storage - */ - if (needs_barrier) { - int err; - - err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - if (!ret) - ret = err; - } -out: - trace_ext3_sync_file_exit(inode, ret); - return ret; -} diff --git a/fs/ext3/hash.c b/fs/ext3/hash.c deleted file mode 100644 index ede315cdf1261..0000000000000 --- a/fs/ext3/hash.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * linux/fs/ext3/hash.c - * - * Copyright (C) 2002 by Theodore Ts'o - * - * This file is released under the GPL v2. - * - * This file may be redistributed under the terms of the GNU Public - * License. - */ - -#include "ext3.h" -#include - -#define DELTA 0x9E3779B9 - -static void TEA_transform(__u32 buf[4], __u32 const in[]) -{ - __u32 sum = 0; - __u32 b0 = buf[0], b1 = buf[1]; - __u32 a = in[0], b = in[1], c = in[2], d = in[3]; - int n = 16; - - do { - sum += DELTA; - b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); - b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); - } while(--n); - - buf[0] += b0; - buf[1] += b1; -} - - -/* The old legacy hash */ -static __u32 dx_hack_hash_unsigned(const char *name, int len) -{ - __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; - const unsigned char *ucp = (const unsigned char *) name; - - while (len--) { - hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373)); - - if (hash & 0x80000000) - hash -= 0x7fffffff; - hash1 = hash0; - hash0 = hash; - } - return hash0 << 1; -} - -static __u32 dx_hack_hash_signed(const char *name, int len) -{ - __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; - const signed char *scp = (const signed char *) name; - - while (len--) { - hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); - - if (hash & 0x80000000) - hash -= 0x7fffffff; - hash1 = hash0; - hash0 = hash; - } - return hash0 << 1; -} - -static void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num) -{ - __u32 pad, val; - int i; - const signed char *scp = (const signed char *) msg; - - pad = (__u32)len | ((__u32)len << 8); - pad |= pad << 16; - - val = pad; - if (len > num*4) - len = num * 4; - for (i = 0; i < len; i++) { - if ((i % 4) == 0) - val = pad; - val = ((int) scp[i]) + (val << 8); - if ((i % 4) == 3) { - *buf++ = val; - val = pad; - num--; - } - } - if (--num >= 0) - *buf++ = val; - while (--num >= 0) - *buf++ = pad; -} - -static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) -{ - __u32 pad, val; - int i; - const unsigned char *ucp = (const unsigned char *) msg; - - pad = (__u32)len | ((__u32)len << 8); - pad |= pad << 16; - - val = pad; - if (len > num*4) - len = num * 4; - for (i=0; i < len; i++) { - if ((i % 4) == 0) - val = pad; - val = ((int) ucp[i]) + (val << 8); - if ((i % 4) == 3) { - *buf++ = val; - val = pad; - num--; - } - } - if (--num >= 0) - *buf++ = val; - while (--num >= 0) - *buf++ = pad; -} - -/* - * Returns the hash of a filename. If len is 0 and name is NULL, then - * this function can be used to test whether or not a hash version is - * supported. - * - * The seed is an 4 longword (32 bits) "secret" which can be used to - * uniquify a hash. If the seed is all zero's, then some default seed - * may be used. - * - * A particular hash version specifies whether or not the seed is - * represented, and whether or not the returned hash is 32 bits or 64 - * bits. 32 bit hashes will return 0 for the minor hash. - */ -int ext3fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) -{ - __u32 hash; - __u32 minor_hash = 0; - const char *p; - int i; - __u32 in[8], buf[4]; - void (*str2hashbuf)(const char *, int, __u32 *, int) = - str2hashbuf_signed; - - /* Initialize the default seed for the hash checksum functions */ - buf[0] = 0x67452301; - buf[1] = 0xefcdab89; - buf[2] = 0x98badcfe; - buf[3] = 0x10325476; - - /* Check to see if the seed is all zero's */ - if (hinfo->seed) { - for (i=0; i < 4; i++) { - if (hinfo->seed[i]) - break; - } - if (i < 4) - memcpy(buf, hinfo->seed, sizeof(buf)); - } - - switch (hinfo->hash_version) { - case DX_HASH_LEGACY_UNSIGNED: - hash = dx_hack_hash_unsigned(name, len); - break; - case DX_HASH_LEGACY: - hash = dx_hack_hash_signed(name, len); - break; - case DX_HASH_HALF_MD4_UNSIGNED: - str2hashbuf = str2hashbuf_unsigned; - case DX_HASH_HALF_MD4: - p = name; - while (len > 0) { - (*str2hashbuf)(p, len, in, 8); - half_md4_transform(buf, in); - len -= 32; - p += 32; - } - minor_hash = buf[2]; - hash = buf[1]; - break; - case DX_HASH_TEA_UNSIGNED: - str2hashbuf = str2hashbuf_unsigned; - case DX_HASH_TEA: - p = name; - while (len > 0) { - (*str2hashbuf)(p, len, in, 4); - TEA_transform(buf, in); - len -= 16; - p += 16; - } - hash = buf[0]; - minor_hash = buf[1]; - break; - default: - hinfo->hash = 0; - return -1; - } - hash = hash & ~1; - if (hash == (EXT3_HTREE_EOF_32BIT << 1)) - hash = (EXT3_HTREE_EOF_32BIT - 1) << 1; - hinfo->hash = hash; - hinfo->minor_hash = minor_hash; - return 0; -} diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c deleted file mode 100644 index 3ad242e5840e0..0000000000000 --- a/fs/ext3/ialloc.c +++ /dev/null @@ -1,706 +0,0 @@ -/* - * linux/fs/ext3/ialloc.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * BSD ufs-inspired inode and directory allocation by - * Stephen Tweedie (sct@redhat.com), 1993 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include -#include - -#include "ext3.h" -#include "xattr.h" -#include "acl.h" - -/* - * ialloc.c contains the inodes allocation and deallocation routines - */ - -/* - * The free inodes are managed by bitmaps. A file system contains several - * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap - * block for inodes, N blocks for the inode table and data blocks. - * - * The file system contains group descriptors which are located after the - * super block. Each descriptor contains the number of the bitmap block and - * the free blocks count in the block. - */ - - -/* - * Read the inode allocation bitmap for a given block_group, reading - * into the specified slot in the superblock's bitmap cache. - * - * Return buffer_head of bitmap on success or NULL. - */ -static struct buffer_head * -read_inode_bitmap(struct super_block * sb, unsigned long block_group) -{ - struct ext3_group_desc *desc; - struct buffer_head *bh = NULL; - - desc = ext3_get_group_desc(sb, block_group, NULL); - if (!desc) - goto error_out; - - bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap)); - if (!bh) - ext3_error(sb, "read_inode_bitmap", - "Cannot read inode bitmap - " - "block_group = %lu, inode_bitmap = %u", - block_group, le32_to_cpu(desc->bg_inode_bitmap)); -error_out: - return bh; -} - -/* - * NOTE! When we get the inode, we're the only people - * that have access to it, and as such there are no - * race conditions we have to worry about. The inode - * is not on the hash-lists, and it cannot be reached - * through the filesystem because the directory entry - * has been deleted earlier. - * - * HOWEVER: we must make sure that we get no aliases, - * which means that we have to call "clear_inode()" - * _before_ we mark the inode not in use in the inode - * bitmaps. Otherwise a newly created file might use - * the same inode number (not actually the same pointer - * though), and then we'd have two inodes sharing the - * same inode number and space on the harddisk. - */ -void ext3_free_inode (handle_t *handle, struct inode * inode) -{ - struct super_block * sb = inode->i_sb; - int is_directory; - unsigned long ino; - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *bh2; - unsigned long block_group; - unsigned long bit; - struct ext3_group_desc * gdp; - struct ext3_super_block * es; - struct ext3_sb_info *sbi; - int fatal = 0, err; - - if (atomic_read(&inode->i_count) > 1) { - printk ("ext3_free_inode: inode has count=%d\n", - atomic_read(&inode->i_count)); - return; - } - if (inode->i_nlink) { - printk ("ext3_free_inode: inode has nlink=%d\n", - inode->i_nlink); - return; - } - if (!sb) { - printk("ext3_free_inode: inode on nonexistent device\n"); - return; - } - sbi = EXT3_SB(sb); - - ino = inode->i_ino; - ext3_debug ("freeing inode %lu\n", ino); - trace_ext3_free_inode(inode); - - is_directory = S_ISDIR(inode->i_mode); - - es = EXT3_SB(sb)->s_es; - if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext3_error (sb, "ext3_free_inode", - "reserved or nonexistent inode %lu", ino); - goto error_return; - } - block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); - bitmap_bh = read_inode_bitmap(sb, block_group); - if (!bitmap_bh) - goto error_return; - - BUFFER_TRACE(bitmap_bh, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, bitmap_bh); - if (fatal) - goto error_return; - - /* Ok, now we can actually update the inode bitmaps.. */ - if (!ext3_clear_bit_atomic(sb_bgl_lock(sbi, block_group), - bit, bitmap_bh->b_data)) - ext3_error (sb, "ext3_free_inode", - "bit already cleared for inode %lu", ino); - else { - gdp = ext3_get_group_desc (sb, block_group, &bh2); - - BUFFER_TRACE(bh2, "get_write_access"); - fatal = ext3_journal_get_write_access(handle, bh2); - if (fatal) goto error_return; - - if (gdp) { - spin_lock(sb_bgl_lock(sbi, block_group)); - le16_add_cpu(&gdp->bg_free_inodes_count, 1); - if (is_directory) - le16_add_cpu(&gdp->bg_used_dirs_count, -1); - spin_unlock(sb_bgl_lock(sbi, block_group)); - percpu_counter_inc(&sbi->s_freeinodes_counter); - if (is_directory) - percpu_counter_dec(&sbi->s_dirs_counter); - - } - BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh2); - if (!fatal) fatal = err; - } - BUFFER_TRACE(bitmap_bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bitmap_bh); - if (!fatal) - fatal = err; - -error_return: - brelse(bitmap_bh); - ext3_std_error(sb, fatal); -} - -/* - * Orlov's allocator for directories. - * - * We always try to spread first-level directories. - * - * If there are blockgroups with both free inodes and free blocks counts - * not worse than average we return one with smallest directory count. - * Otherwise we simply return a random group. - * - * For the rest rules look so: - * - * It's OK to put directory into a group unless - * it has too many directories already (max_dirs) or - * it has too few free inodes left (min_inodes) or - * it has too few free blocks left (min_blocks). - * Parent's group is preferred, if it doesn't satisfy these - * conditions we search cyclically through the rest. If none - * of the groups look good we just look for a group with more - * free inodes than average (starting at parent's group). - * - * Debt is incremented each time we allocate a directory and decremented - * when we allocate an inode, within 0--255. - */ - -static int find_group_orlov(struct super_block *sb, struct inode *parent) -{ - int parent_group = EXT3_I(parent)->i_block_group; - struct ext3_sb_info *sbi = EXT3_SB(sb); - int ngroups = sbi->s_groups_count; - int inodes_per_group = EXT3_INODES_PER_GROUP(sb); - unsigned int freei, avefreei; - ext3_fsblk_t freeb, avefreeb; - unsigned int ndirs; - int max_dirs, min_inodes; - ext3_grpblk_t min_blocks; - int group = -1, i; - struct ext3_group_desc *desc; - - freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); - avefreei = freei / ngroups; - freeb = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - avefreeb = freeb / ngroups; - ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); - - if ((parent == d_inode(sb->s_root)) || - (EXT3_I(parent)->i_flags & EXT3_TOPDIR_FL)) { - int best_ndir = inodes_per_group; - int best_group = -1; - - group = prandom_u32(); - parent_group = (unsigned)group % ngroups; - for (i = 0; i < ngroups; i++) { - group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (le16_to_cpu(desc->bg_used_dirs_count) >= best_ndir) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < avefreei) - continue; - if (le16_to_cpu(desc->bg_free_blocks_count) < avefreeb) - continue; - best_group = group; - best_ndir = le16_to_cpu(desc->bg_used_dirs_count); - } - if (best_group >= 0) - return best_group; - goto fallback; - } - - max_dirs = ndirs / ngroups + inodes_per_group / 16; - min_inodes = avefreei - inodes_per_group / 4; - min_blocks = avefreeb - EXT3_BLOCKS_PER_GROUP(sb) / 4; - - for (i = 0; i < ngroups; i++) { - group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (le16_to_cpu(desc->bg_used_dirs_count) >= max_dirs) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) < min_inodes) - continue; - if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks) - continue; - return group; - } - -fallback: - for (i = 0; i < ngroups; i++) { - group = (parent_group + i) % ngroups; - desc = ext3_get_group_desc (sb, group, NULL); - if (!desc || !desc->bg_free_inodes_count) - continue; - if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei) - return group; - } - - if (avefreei) { - /* - * The free-inodes counter is approximate, and for really small - * filesystems the above test can fail to find any blockgroups - */ - avefreei = 0; - goto fallback; - } - - return -1; -} - -static int find_group_other(struct super_block *sb, struct inode *parent) -{ - int parent_group = EXT3_I(parent)->i_block_group; - int ngroups = EXT3_SB(sb)->s_groups_count; - struct ext3_group_desc *desc; - int group, i; - - /* - * Try to place the inode in its parent directory - */ - group = parent_group; - desc = ext3_get_group_desc (sb, group, NULL); - if (desc && le16_to_cpu(desc->bg_free_inodes_count) && - le16_to_cpu(desc->bg_free_blocks_count)) - return group; - - /* - * We're going to place this inode in a different blockgroup from its - * parent. We want to cause files in a common directory to all land in - * the same blockgroup. But we want files which are in a different - * directory which shares a blockgroup with our parent to land in a - * different blockgroup. - * - * So add our directory's i_ino into the starting point for the hash. - */ - group = (group + parent->i_ino) % ngroups; - - /* - * Use a quadratic hash to find a group with a free inode and some free - * blocks. - */ - for (i = 1; i < ngroups; i <<= 1) { - group += i; - if (group >= ngroups) - group -= ngroups; - desc = ext3_get_group_desc (sb, group, NULL); - if (desc && le16_to_cpu(desc->bg_free_inodes_count) && - le16_to_cpu(desc->bg_free_blocks_count)) - return group; - } - - /* - * That failed: try linear search for a free inode, even if that group - * has no free blocks. - */ - group = parent_group; - for (i = 0; i < ngroups; i++) { - if (++group >= ngroups) - group = 0; - desc = ext3_get_group_desc (sb, group, NULL); - if (desc && le16_to_cpu(desc->bg_free_inodes_count)) - return group; - } - - return -1; -} - -/* - * There are two policies for allocating an inode. If the new inode is - * a directory, then a forward search is made for a block group with both - * free space and a low directory-to-inode ratio; if that fails, then of - * the groups with above-average free space, that group with the fewest - * directories already is chosen. - * - * For other inodes, search forward from the parent directory's block - * group to find a free inode. - */ -struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, - const struct qstr *qstr, umode_t mode) -{ - struct super_block *sb; - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *bh2; - int group; - unsigned long ino = 0; - struct inode * inode; - struct ext3_group_desc * gdp = NULL; - struct ext3_super_block * es; - struct ext3_inode_info *ei; - struct ext3_sb_info *sbi; - int err = 0; - struct inode *ret; - int i; - - /* Cannot create files in a deleted directory */ - if (!dir || !dir->i_nlink) - return ERR_PTR(-EPERM); - - sb = dir->i_sb; - trace_ext3_request_inode(dir, mode); - inode = new_inode(sb); - if (!inode) - return ERR_PTR(-ENOMEM); - ei = EXT3_I(inode); - - sbi = EXT3_SB(sb); - es = sbi->s_es; - if (S_ISDIR(mode)) - group = find_group_orlov(sb, dir); - else - group = find_group_other(sb, dir); - - err = -ENOSPC; - if (group == -1) - goto out; - - for (i = 0; i < sbi->s_groups_count; i++) { - err = -EIO; - - gdp = ext3_get_group_desc(sb, group, &bh2); - if (!gdp) - goto fail; - - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, group); - if (!bitmap_bh) - goto fail; - - ino = 0; - -repeat_in_this_group: - ino = ext3_find_next_zero_bit((unsigned long *) - bitmap_bh->b_data, EXT3_INODES_PER_GROUP(sb), ino); - if (ino < EXT3_INODES_PER_GROUP(sb)) { - - BUFFER_TRACE(bitmap_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bitmap_bh); - if (err) - goto fail; - - if (!ext3_set_bit_atomic(sb_bgl_lock(sbi, group), - ino, bitmap_bh->b_data)) { - /* we won it */ - BUFFER_TRACE(bitmap_bh, - "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, - bitmap_bh); - if (err) - goto fail; - goto got; - } - /* we lost it */ - journal_release_buffer(handle, bitmap_bh); - - if (++ino < EXT3_INODES_PER_GROUP(sb)) - goto repeat_in_this_group; - } - - /* - * This case is possible in concurrent environment. It is very - * rare. We cannot repeat the find_group_xxx() call because - * that will simply return the same blockgroup, because the - * group descriptor metadata has not yet been updated. - * So we just go onto the next blockgroup. - */ - if (++group == sbi->s_groups_count) - group = 0; - } - err = -ENOSPC; - goto out; - -got: - ino += group * EXT3_INODES_PER_GROUP(sb) + 1; - if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext3_error (sb, "ext3_new_inode", - "reserved inode or inode > inodes count - " - "block_group = %d, inode=%lu", group, ino); - err = -EIO; - goto fail; - } - - BUFFER_TRACE(bh2, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh2); - if (err) goto fail; - spin_lock(sb_bgl_lock(sbi, group)); - le16_add_cpu(&gdp->bg_free_inodes_count, -1); - if (S_ISDIR(mode)) { - le16_add_cpu(&gdp->bg_used_dirs_count, 1); - } - spin_unlock(sb_bgl_lock(sbi, group)); - BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh2); - if (err) goto fail; - - percpu_counter_dec(&sbi->s_freeinodes_counter); - if (S_ISDIR(mode)) - percpu_counter_inc(&sbi->s_dirs_counter); - - - if (test_opt(sb, GRPID)) { - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = dir->i_gid; - } else - inode_init_owner(inode, dir, mode); - - inode->i_ino = ino; - /* This is the optimal IO size (for stat), not the fs block size */ - inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; - - memset(ei->i_data, 0, sizeof(ei->i_data)); - ei->i_dir_start_lookup = 0; - ei->i_disksize = 0; - - ei->i_flags = - ext3_mask_flags(mode, EXT3_I(dir)->i_flags & EXT3_FL_INHERITED); -#ifdef EXT3_FRAGMENTS - ei->i_faddr = 0; - ei->i_frag_no = 0; - ei->i_frag_size = 0; -#endif - ei->i_file_acl = 0; - ei->i_dir_acl = 0; - ei->i_dtime = 0; - ei->i_block_alloc_info = NULL; - ei->i_block_group = group; - - ext3_set_inode_flags(inode); - if (IS_DIRSYNC(inode)) - handle->h_sync = 1; - if (insert_inode_locked(inode) < 0) { - /* - * Likely a bitmap corruption causing inode to be allocated - * twice. - */ - err = -EIO; - goto fail; - } - spin_lock(&sbi->s_next_gen_lock); - inode->i_generation = sbi->s_next_generation++; - spin_unlock(&sbi->s_next_gen_lock); - - ei->i_state_flags = 0; - ext3_set_inode_state(inode, EXT3_STATE_NEW); - - /* See comment in ext3_iget for explanation */ - if (ino >= EXT3_FIRST_INO(sb) + 1 && - EXT3_INODE_SIZE(sb) > EXT3_GOOD_OLD_INODE_SIZE) { - ei->i_extra_isize = - sizeof(struct ext3_inode) - EXT3_GOOD_OLD_INODE_SIZE; - } else { - ei->i_extra_isize = 0; - } - - ret = inode; - dquot_initialize(inode); - err = dquot_alloc_inode(inode); - if (err) - goto fail_drop; - - err = ext3_init_acl(handle, inode, dir); - if (err) - goto fail_free_drop; - - err = ext3_init_security(handle, inode, dir, qstr); - if (err) - goto fail_free_drop; - - err = ext3_mark_inode_dirty(handle, inode); - if (err) { - ext3_std_error(sb, err); - goto fail_free_drop; - } - - ext3_debug("allocating inode %lu\n", inode->i_ino); - trace_ext3_allocate_inode(inode, dir, mode); - goto really_out; -fail: - ext3_std_error(sb, err); -out: - iput(inode); - ret = ERR_PTR(err); -really_out: - brelse(bitmap_bh); - return ret; - -fail_free_drop: - dquot_free_inode(inode); - -fail_drop: - dquot_drop(inode); - inode->i_flags |= S_NOQUOTA; - clear_nlink(inode); - unlock_new_inode(inode); - iput(inode); - brelse(bitmap_bh); - return ERR_PTR(err); -} - -/* Verify that we are loading a valid orphan from disk */ -struct inode *ext3_orphan_get(struct super_block *sb, unsigned long ino) -{ - unsigned long max_ino = le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count); - unsigned long block_group; - int bit; - struct buffer_head *bitmap_bh; - struct inode *inode = NULL; - long err = -EIO; - - /* Error cases - e2fsck has already cleaned up for us */ - if (ino > max_ino) { - ext3_warning(sb, __func__, - "bad orphan ino %lu! e2fsck was run?", ino); - goto error; - } - - block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb); - bitmap_bh = read_inode_bitmap(sb, block_group); - if (!bitmap_bh) { - ext3_warning(sb, __func__, - "inode bitmap error for orphan %lu", ino); - goto error; - } - - /* Having the inode bit set should be a 100% indicator that this - * is a valid orphan (no e2fsck run on fs). Orphans also include - * inodes that were being truncated, so we can't check i_nlink==0. - */ - if (!ext3_test_bit(bit, bitmap_bh->b_data)) - goto bad_orphan; - - inode = ext3_iget(sb, ino); - if (IS_ERR(inode)) - goto iget_failed; - - /* - * If the orphans has i_nlinks > 0 then it should be able to be - * truncated, otherwise it won't be removed from the orphan list - * during processing and an infinite loop will result. - */ - if (inode->i_nlink && !ext3_can_truncate(inode)) - goto bad_orphan; - - if (NEXT_ORPHAN(inode) > max_ino) - goto bad_orphan; - brelse(bitmap_bh); - return inode; - -iget_failed: - err = PTR_ERR(inode); - inode = NULL; -bad_orphan: - ext3_warning(sb, __func__, - "bad orphan inode %lu! e2fsck was run?", ino); - printk(KERN_NOTICE "ext3_test_bit(bit=%d, block=%llu) = %d\n", - bit, (unsigned long long)bitmap_bh->b_blocknr, - ext3_test_bit(bit, bitmap_bh->b_data)); - printk(KERN_NOTICE "inode=%p\n", inode); - if (inode) { - printk(KERN_NOTICE "is_bad_inode(inode)=%d\n", - is_bad_inode(inode)); - printk(KERN_NOTICE "NEXT_ORPHAN(inode)=%u\n", - NEXT_ORPHAN(inode)); - printk(KERN_NOTICE "max_ino=%lu\n", max_ino); - printk(KERN_NOTICE "i_nlink=%u\n", inode->i_nlink); - /* Avoid freeing blocks if we got a bad deleted inode */ - if (inode->i_nlink == 0) - inode->i_blocks = 0; - iput(inode); - } - brelse(bitmap_bh); -error: - return ERR_PTR(err); -} - -unsigned long ext3_count_free_inodes (struct super_block * sb) -{ - unsigned long desc_count; - struct ext3_group_desc *gdp; - int i; -#ifdef EXT3FS_DEBUG - struct ext3_super_block *es; - unsigned long bitmap_count, x; - struct buffer_head *bitmap_bh = NULL; - - es = EXT3_SB(sb)->s_es; - desc_count = 0; - bitmap_count = 0; - gdp = NULL; - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { - gdp = ext3_get_group_desc (sb, i, NULL); - if (!gdp) - continue; - desc_count += le16_to_cpu(gdp->bg_free_inodes_count); - brelse(bitmap_bh); - bitmap_bh = read_inode_bitmap(sb, i); - if (!bitmap_bh) - continue; - - x = ext3_count_free(bitmap_bh, EXT3_INODES_PER_GROUP(sb) / 8); - printk("group %d: stored = %d, counted = %lu\n", - i, le16_to_cpu(gdp->bg_free_inodes_count), x); - bitmap_count += x; - } - brelse(bitmap_bh); - printk("ext3_count_free_inodes: stored = %u, computed = %lu, %lu\n", - le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); - return desc_count; -#else - desc_count = 0; - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { - gdp = ext3_get_group_desc (sb, i, NULL); - if (!gdp) - continue; - desc_count += le16_to_cpu(gdp->bg_free_inodes_count); - cond_resched(); - } - return desc_count; -#endif -} - -/* Called at mount-time, super-block is locked */ -unsigned long ext3_count_dirs (struct super_block * sb) -{ - unsigned long count = 0; - int i; - - for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) { - struct ext3_group_desc *gdp = ext3_get_group_desc (sb, i, NULL); - if (!gdp) - continue; - count += le16_to_cpu(gdp->bg_used_dirs_count); - } - return count; -} - diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c deleted file mode 100644 index 6c7e5468a2f80..0000000000000 --- a/fs/ext3/inode.c +++ /dev/null @@ -1,3574 +0,0 @@ -/* - * linux/fs/ext3/inode.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Goal-directed block allocation by Stephen Tweedie - * (sct@redhat.com), 1993, 1998 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) - * - * Assorted race fixes, rewrite of ext3_get_block() by Al Viro, 2000 - */ - -#include -#include -#include -#include -#include -#include -#include "ext3.h" -#include "xattr.h" -#include "acl.h" - -static int ext3_writepage_trans_blocks(struct inode *inode); -static int ext3_block_truncate_page(struct inode *inode, loff_t from); - -/* - * Test whether an inode is a fast symlink. - */ -static int ext3_inode_is_fast_symlink(struct inode *inode) -{ - int ea_blocks = EXT3_I(inode)->i_file_acl ? - (inode->i_sb->s_blocksize >> 9) : 0; - - return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); -} - -/* - * The ext3 forget function must perform a revoke if we are freeing data - * which has been journaled. Metadata (eg. indirect blocks) must be - * revoked in all cases. - * - * "bh" may be NULL: a metadata block may have been freed from memory - * but there may still be a record of it in the journal, and that record - * still needs to be revoked. - */ -int ext3_forget(handle_t *handle, int is_metadata, struct inode *inode, - struct buffer_head *bh, ext3_fsblk_t blocknr) -{ - int err; - - might_sleep(); - - trace_ext3_forget(inode, is_metadata, blocknr); - BUFFER_TRACE(bh, "enter"); - - jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " - "data mode %lx\n", - bh, is_metadata, inode->i_mode, - test_opt(inode->i_sb, DATA_FLAGS)); - - /* Never use the revoke function if we are doing full data - * journaling: there is no need to, and a V1 superblock won't - * support it. Otherwise, only skip the revoke on un-journaled - * data blocks. */ - - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA || - (!is_metadata && !ext3_should_journal_data(inode))) { - if (bh) { - BUFFER_TRACE(bh, "call journal_forget"); - return ext3_journal_forget(handle, bh); - } - return 0; - } - - /* - * data!=journal && (is_metadata || should_journal_data(inode)) - */ - BUFFER_TRACE(bh, "call ext3_journal_revoke"); - err = ext3_journal_revoke(handle, blocknr, bh); - if (err) - ext3_abort(inode->i_sb, __func__, - "error %d when attempting revoke", err); - BUFFER_TRACE(bh, "exit"); - return err; -} - -/* - * Work out how many blocks we need to proceed with the next chunk of a - * truncate transaction. - */ -static unsigned long blocks_for_truncate(struct inode *inode) -{ - unsigned long needed; - - needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); - - /* Give ourselves just enough room to cope with inodes in which - * i_blocks is corrupt: we've seen disk corruptions in the past - * which resulted in random data in an inode which looked enough - * like a regular file for ext3 to try to delete it. Things - * will go a bit crazy if that happens, but at least we should - * try not to panic the whole kernel. */ - if (needed < 2) - needed = 2; - - /* But we need to bound the transaction so we don't overflow the - * journal. */ - if (needed > EXT3_MAX_TRANS_DATA) - needed = EXT3_MAX_TRANS_DATA; - - return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed; -} - -/* - * Truncate transactions can be complex and absolutely huge. So we need to - * be able to restart the transaction at a conventient checkpoint to make - * sure we don't overflow the journal. - * - * start_transaction gets us a new handle for a truncate transaction, - * and extend_transaction tries to extend the existing one a bit. If - * extend fails, we need to propagate the failure up and restart the - * transaction in the top-level truncate loop. --sct - */ -static handle_t *start_transaction(struct inode *inode) -{ - handle_t *result; - - result = ext3_journal_start(inode, blocks_for_truncate(inode)); - if (!IS_ERR(result)) - return result; - - ext3_std_error(inode->i_sb, PTR_ERR(result)); - return result; -} - -/* - * Try to extend this transaction for the purposes of truncation. - * - * Returns 0 if we managed to create more room. If we can't create more - * room, and the transaction must be restarted we return 1. - */ -static int try_to_extend_transaction(handle_t *handle, struct inode *inode) -{ - if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS) - return 0; - if (!ext3_journal_extend(handle, blocks_for_truncate(inode))) - return 0; - return 1; -} - -/* - * Restart the transaction associated with *handle. This does a commit, - * so before we call here everything must be consistently dirtied against - * this transaction. - */ -static int truncate_restart_transaction(handle_t *handle, struct inode *inode) -{ - int ret; - - jbd_debug(2, "restarting handle %p\n", handle); - /* - * Drop truncate_mutex to avoid deadlock with ext3_get_blocks_handle - * At this moment, get_block can be called only for blocks inside - * i_size since page cache has been already dropped and writes are - * blocked by i_mutex. So we can safely drop the truncate_mutex. - */ - mutex_unlock(&EXT3_I(inode)->truncate_mutex); - ret = ext3_journal_restart(handle, blocks_for_truncate(inode)); - mutex_lock(&EXT3_I(inode)->truncate_mutex); - return ret; -} - -/* - * Called at inode eviction from icache - */ -void ext3_evict_inode (struct inode *inode) -{ - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_block_alloc_info *rsv; - handle_t *handle; - int want_delete = 0; - - trace_ext3_evict_inode(inode); - if (!inode->i_nlink && !is_bad_inode(inode)) { - dquot_initialize(inode); - want_delete = 1; - } - - /* - * When journalling data dirty buffers are tracked only in the journal. - * So although mm thinks everything is clean and ready for reaping the - * inode might still have some pages to write in the running - * transaction or waiting to be checkpointed. Thus calling - * journal_invalidatepage() (via truncate_inode_pages()) to discard - * these buffers can cause data loss. Also even if we did not discard - * these buffers, we would have no way to find them after the inode - * is reaped and thus user could see stale data if he tries to read - * them before the transaction is checkpointed. So be careful and - * force everything to disk here... We use ei->i_datasync_tid to - * store the newest transaction containing inode's data. - * - * Note that directories do not have this problem because they don't - * use page cache. - * - * The s_journal check handles the case when ext3_get_journal() fails - * and puts the journal inode. - */ - if (inode->i_nlink && ext3_should_journal_data(inode) && - EXT3_SB(inode->i_sb)->s_journal && - (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode)) && - inode->i_ino != EXT3_JOURNAL_INO) { - tid_t commit_tid = atomic_read(&ei->i_datasync_tid); - journal_t *journal = EXT3_SB(inode->i_sb)->s_journal; - - log_start_commit(journal, commit_tid); - log_wait_commit(journal, commit_tid); - filemap_write_and_wait(&inode->i_data); - } - truncate_inode_pages_final(&inode->i_data); - - ext3_discard_reservation(inode); - rsv = ei->i_block_alloc_info; - ei->i_block_alloc_info = NULL; - if (unlikely(rsv)) - kfree(rsv); - - if (!want_delete) - goto no_delete; - - handle = start_transaction(inode); - if (IS_ERR(handle)) { - /* - * If we're going to skip the normal cleanup, we still need to - * make sure that the in-core orphan linked list is properly - * cleaned up. - */ - ext3_orphan_del(NULL, inode); - goto no_delete; - } - - if (IS_SYNC(inode)) - handle->h_sync = 1; - inode->i_size = 0; - if (inode->i_blocks) - ext3_truncate(inode); - /* - * Kill off the orphan record created when the inode lost the last - * link. Note that ext3_orphan_del() has to be able to cope with the - * deletion of a non-existent orphan - ext3_truncate() could - * have removed the record. - */ - ext3_orphan_del(handle, inode); - ei->i_dtime = get_seconds(); - - /* - * One subtle ordering requirement: if anything has gone wrong - * (transaction abort, IO errors, whatever), then we can still - * do these next steps (the fs will already have been marked as - * having errors), but we can't free the inode if the mark_dirty - * fails. - */ - if (ext3_mark_inode_dirty(handle, inode)) { - /* If that failed, just dquot_drop() and be done with that */ - dquot_drop(inode); - clear_inode(inode); - } else { - ext3_xattr_delete_inode(handle, inode); - dquot_free_inode(inode); - dquot_drop(inode); - clear_inode(inode); - ext3_free_inode(handle, inode); - } - ext3_journal_stop(handle); - return; -no_delete: - clear_inode(inode); - dquot_drop(inode); -} - -typedef struct { - __le32 *p; - __le32 key; - struct buffer_head *bh; -} Indirect; - -static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) -{ - p->key = *(p->p = v); - p->bh = bh; -} - -static int verify_chain(Indirect *from, Indirect *to) -{ - while (from <= to && from->key == *from->p) - from++; - return (from > to); -} - -/** - * ext3_block_to_path - parse the block number into array of offsets - * @inode: inode in question (we are only interested in its superblock) - * @i_block: block number to be parsed - * @offsets: array to store the offsets in - * @boundary: set this non-zero if the referred-to block is likely to be - * followed (on disk) by an indirect block. - * - * To store the locations of file's data ext3 uses a data structure common - * for UNIX filesystems - tree of pointers anchored in the inode, with - * data blocks at leaves and indirect blocks in intermediate nodes. - * This function translates the block number into path in that tree - - * return value is the path length and @offsets[n] is the offset of - * pointer to (n+1)th node in the nth one. If @block is out of range - * (negative or too large) warning is printed and zero returned. - * - * Note: function doesn't find node addresses, so no IO is needed. All - * we need to know is the capacity of indirect blocks (taken from the - * inode->i_sb). - */ - -/* - * Portability note: the last comparison (check that we fit into triple - * indirect block) is spelled differently, because otherwise on an - * architecture with 32-bit longs and 8Kb pages we might get into trouble - * if our filesystem had 8Kb blocks. We might use long long, but that would - * kill us on x86. Oh, well, at least the sign propagation does not matter - - * i_block would have to be negative in the very beginning, so we would not - * get there at all. - */ - -static int ext3_block_to_path(struct inode *inode, - long i_block, int offsets[4], int *boundary) -{ - int ptrs = EXT3_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb); - const long direct_blocks = EXT3_NDIR_BLOCKS, - indirect_blocks = ptrs, - double_blocks = (1 << (ptrs_bits * 2)); - int n = 0; - int final = 0; - - if (i_block < 0) { - ext3_warning (inode->i_sb, "ext3_block_to_path", "block < 0"); - } else if (i_block < direct_blocks) { - offsets[n++] = i_block; - final = direct_blocks; - } else if ( (i_block -= direct_blocks) < indirect_blocks) { - offsets[n++] = EXT3_IND_BLOCK; - offsets[n++] = i_block; - final = ptrs; - } else if ((i_block -= indirect_blocks) < double_blocks) { - offsets[n++] = EXT3_DIND_BLOCK; - offsets[n++] = i_block >> ptrs_bits; - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { - offsets[n++] = EXT3_TIND_BLOCK; - offsets[n++] = i_block >> (ptrs_bits * 2); - offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else { - ext3_warning(inode->i_sb, "ext3_block_to_path", "block > big"); - } - if (boundary) - *boundary = final - 1 - (i_block & (ptrs - 1)); - return n; -} - -/** - * ext3_get_branch - read the chain of indirect blocks leading to data - * @inode: inode in question - * @depth: depth of the chain (1 - direct pointer, etc.) - * @offsets: offsets of pointers in inode/indirect blocks - * @chain: place to store the result - * @err: here we store the error value - * - * Function fills the array of triples and returns %NULL - * if everything went OK or the pointer to the last filled triple - * (incomplete one) otherwise. Upon the return chain[i].key contains - * the number of (i+1)-th block in the chain (as it is stored in memory, - * i.e. little-endian 32-bit), chain[i].p contains the address of that - * number (it points into struct inode for i==0 and into the bh->b_data - * for i>0) and chain[i].bh points to the buffer_head of i-th indirect - * block for i>0 and NULL for i==0. In other words, it holds the block - * numbers of the chain, addresses they were taken from (and where we can - * verify that chain did not change) and buffer_heads hosting these - * numbers. - * - * Function stops when it stumbles upon zero pointer (absent block) - * (pointer to last triple returned, *@err == 0) - * or when it gets an IO error reading an indirect block - * (ditto, *@err == -EIO) - * or when it notices that chain had been changed while it was reading - * (ditto, *@err == -EAGAIN) - * or when it reads all @depth-1 indirect blocks successfully and finds - * the whole chain, all way to the data (returns %NULL, *err == 0). - */ -static Indirect *ext3_get_branch(struct inode *inode, int depth, int *offsets, - Indirect chain[4], int *err) -{ - struct super_block *sb = inode->i_sb; - Indirect *p = chain; - struct buffer_head *bh; - - *err = 0; - /* i_data is not going away, no lock needed */ - add_chain (chain, NULL, EXT3_I(inode)->i_data + *offsets); - if (!p->key) - goto no_block; - while (--depth) { - bh = sb_bread(sb, le32_to_cpu(p->key)); - if (!bh) - goto failure; - /* Reader: pointers */ - if (!verify_chain(chain, p)) - goto changed; - add_chain(++p, bh, (__le32*)bh->b_data + *++offsets); - /* Reader: end */ - if (!p->key) - goto no_block; - } - return NULL; - -changed: - brelse(bh); - *err = -EAGAIN; - goto no_block; -failure: - *err = -EIO; -no_block: - return p; -} - -/** - * ext3_find_near - find a place for allocation with sufficient locality - * @inode: owner - * @ind: descriptor of indirect block. - * - * This function returns the preferred place for block allocation. - * It is used when heuristic for sequential allocation fails. - * Rules are: - * + if there is a block to the left of our position - allocate near it. - * + if pointer will live in indirect block - allocate near that block. - * + if pointer will live in inode - allocate in the same - * cylinder group. - * - * In the latter case we colour the starting block by the callers PID to - * prevent it from clashing with concurrent allocations for a different inode - * in the same block group. The PID is used here so that functionally related - * files will be close-by on-disk. - * - * Caller must make sure that @ind is valid and will stay that way. - */ -static ext3_fsblk_t ext3_find_near(struct inode *inode, Indirect *ind) -{ - struct ext3_inode_info *ei = EXT3_I(inode); - __le32 *start = ind->bh ? (__le32*) ind->bh->b_data : ei->i_data; - __le32 *p; - ext3_fsblk_t bg_start; - ext3_grpblk_t colour; - - /* Try to find previous block */ - for (p = ind->p - 1; p >= start; p--) { - if (*p) - return le32_to_cpu(*p); - } - - /* No such thing, so let's try location of indirect block */ - if (ind->bh) - return ind->bh->b_blocknr; - - /* - * It is going to be referred to from the inode itself? OK, just put it - * into the same cylinder group then. - */ - bg_start = ext3_group_first_block_no(inode->i_sb, ei->i_block_group); - colour = (current->pid % 16) * - (EXT3_BLOCKS_PER_GROUP(inode->i_sb) / 16); - return bg_start + colour; -} - -/** - * ext3_find_goal - find a preferred place for allocation. - * @inode: owner - * @block: block we want - * @partial: pointer to the last triple within a chain - * - * Normally this function find the preferred place for block allocation, - * returns it. - */ - -static ext3_fsblk_t ext3_find_goal(struct inode *inode, long block, - Indirect *partial) -{ - struct ext3_block_alloc_info *block_i; - - block_i = EXT3_I(inode)->i_block_alloc_info; - - /* - * try the heuristic for sequential allocation, - * failing that at least try to get decent locality. - */ - if (block_i && (block == block_i->last_alloc_logical_block + 1) - && (block_i->last_alloc_physical_block != 0)) { - return block_i->last_alloc_physical_block + 1; - } - - return ext3_find_near(inode, partial); -} - -/** - * ext3_blks_to_allocate - Look up the block map and count the number - * of direct blocks need to be allocated for the given branch. - * - * @branch: chain of indirect blocks - * @k: number of blocks need for indirect blocks - * @blks: number of data blocks to be mapped. - * @blocks_to_boundary: the offset in the indirect block - * - * return the total number of blocks to be allocate, including the - * direct and indirect blocks. - */ -static int ext3_blks_to_allocate(Indirect *branch, int k, unsigned long blks, - int blocks_to_boundary) -{ - unsigned long count = 0; - - /* - * Simple case, [t,d]Indirect block(s) has not allocated yet - * then it's clear blocks on that path have not allocated - */ - if (k > 0) { - /* right now we don't handle cross boundary allocation */ - if (blks < blocks_to_boundary + 1) - count += blks; - else - count += blocks_to_boundary + 1; - return count; - } - - count++; - while (count < blks && count <= blocks_to_boundary && - le32_to_cpu(*(branch[0].p + count)) == 0) { - count++; - } - return count; -} - -/** - * ext3_alloc_blocks - multiple allocate blocks needed for a branch - * @handle: handle for this transaction - * @inode: owner - * @goal: preferred place for allocation - * @indirect_blks: the number of blocks need to allocate for indirect - * blocks - * @blks: number of blocks need to allocated for direct blocks - * @new_blocks: on return it will store the new block numbers for - * the indirect blocks(if needed) and the first direct block, - * @err: here we store the error value - * - * return the number of direct blocks allocated - */ -static int ext3_alloc_blocks(handle_t *handle, struct inode *inode, - ext3_fsblk_t goal, int indirect_blks, int blks, - ext3_fsblk_t new_blocks[4], int *err) -{ - int target, i; - unsigned long count = 0; - int index = 0; - ext3_fsblk_t current_block = 0; - int ret = 0; - - /* - * Here we try to allocate the requested multiple blocks at once, - * on a best-effort basis. - * To build a branch, we should allocate blocks for - * the indirect blocks(if not allocated yet), and at least - * the first direct block of this branch. That's the - * minimum number of blocks need to allocate(required) - */ - target = blks + indirect_blks; - - while (1) { - count = target; - /* allocating blocks for indirect blocks and direct blocks */ - current_block = ext3_new_blocks(handle,inode,goal,&count,err); - if (*err) - goto failed_out; - - target -= count; - /* allocate blocks for indirect blocks */ - while (index < indirect_blks && count) { - new_blocks[index++] = current_block++; - count--; - } - - if (count > 0) - break; - } - - /* save the new block number for the first direct block */ - new_blocks[index] = current_block; - - /* total number of blocks allocated for direct blocks */ - ret = count; - *err = 0; - return ret; -failed_out: - for (i = 0; i key). Upon the exit we have the same - * picture as after the successful ext3_get_block(), except that in one - * place chain is disconnected - *branch->p is still zero (we did not - * set the last link), but branch->key contains the number that should - * be placed into *branch->p to fill that gap. - * - * If allocation fails we free all blocks we've allocated (and forget - * their buffer_heads) and return the error value the from failed - * ext3_alloc_block() (normally -ENOSPC). Otherwise we set the chain - * as described above and return 0. - */ -static int ext3_alloc_branch(handle_t *handle, struct inode *inode, - int indirect_blks, int *blks, ext3_fsblk_t goal, - int *offsets, Indirect *branch) -{ - int blocksize = inode->i_sb->s_blocksize; - int i, n = 0; - int err = 0; - struct buffer_head *bh; - int num; - ext3_fsblk_t new_blocks[4]; - ext3_fsblk_t current_block; - - num = ext3_alloc_blocks(handle, inode, goal, indirect_blks, - *blks, new_blocks, &err); - if (err) - return err; - - branch[0].key = cpu_to_le32(new_blocks[0]); - /* - * metadata blocks and data blocks are allocated. - */ - for (n = 1; n <= indirect_blks; n++) { - /* - * Get buffer_head for parent block, zero it out - * and set the pointer to new one, then send - * parent to disk. - */ - bh = sb_getblk(inode->i_sb, new_blocks[n-1]); - if (unlikely(!bh)) { - err = -ENOMEM; - goto failed; - } - branch[n].bh = bh; - lock_buffer(bh); - BUFFER_TRACE(bh, "call get_create_access"); - err = ext3_journal_get_create_access(handle, bh); - if (err) { - unlock_buffer(bh); - brelse(bh); - goto failed; - } - - memset(bh->b_data, 0, blocksize); - branch[n].p = (__le32 *) bh->b_data + offsets[n]; - branch[n].key = cpu_to_le32(new_blocks[n]); - *branch[n].p = branch[n].key; - if ( n == indirect_blks) { - current_block = new_blocks[n]; - /* - * End of chain, update the last new metablock of - * the chain to point to the new allocated - * data blocks numbers - */ - for (i=1; i < num; i++) - *(branch[n].p + i) = cpu_to_le32(++current_block); - } - BUFFER_TRACE(bh, "marking uptodate"); - set_buffer_uptodate(bh); - unlock_buffer(bh); - - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); - if (err) - goto failed; - } - *blks = num; - return err; -failed: - /* Allocation failed, free what we already allocated */ - for (i = 1; i <= n ; i++) { - BUFFER_TRACE(branch[i].bh, "call journal_forget"); - ext3_journal_forget(handle, branch[i].bh); - } - for (i = 0; i < indirect_blks; i++) - ext3_free_blocks(handle, inode, new_blocks[i], 1); - - ext3_free_blocks(handle, inode, new_blocks[i], num); - - return err; -} - -/** - * ext3_splice_branch - splice the allocated branch onto inode. - * @handle: handle for this transaction - * @inode: owner - * @block: (logical) number of block we are adding - * @where: location of missing link - * @num: number of indirect blocks we are adding - * @blks: number of direct blocks we are adding - * - * This function fills the missing link and does all housekeeping needed in - * inode (->i_blocks, etc.). In case of success we end up with the full - * chain to new block and return 0. - */ -static int ext3_splice_branch(handle_t *handle, struct inode *inode, - long block, Indirect *where, int num, int blks) -{ - int i; - int err = 0; - struct ext3_block_alloc_info *block_i; - ext3_fsblk_t current_block; - struct ext3_inode_info *ei = EXT3_I(inode); - struct timespec now; - - block_i = ei->i_block_alloc_info; - /* - * If we're splicing into a [td]indirect block (as opposed to the - * inode) then we need to get write access to the [td]indirect block - * before the splice. - */ - if (where->bh) { - BUFFER_TRACE(where->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, where->bh); - if (err) - goto err_out; - } - /* That's it */ - - *where->p = where->key; - - /* - * Update the host buffer_head or inode to point to more just allocated - * direct blocks blocks - */ - if (num == 0 && blks > 1) { - current_block = le32_to_cpu(where->key) + 1; - for (i = 1; i < blks; i++) - *(where->p + i ) = cpu_to_le32(current_block++); - } - - /* - * update the most recently allocated logical & physical block - * in i_block_alloc_info, to assist find the proper goal block for next - * allocation - */ - if (block_i) { - block_i->last_alloc_logical_block = block + blks - 1; - block_i->last_alloc_physical_block = - le32_to_cpu(where[num].key) + blks - 1; - } - - /* We are done with atomic stuff, now do the rest of housekeeping */ - now = CURRENT_TIME_SEC; - if (!timespec_equal(&inode->i_ctime, &now) || !where->bh) { - inode->i_ctime = now; - ext3_mark_inode_dirty(handle, inode); - } - /* ext3_mark_inode_dirty already updated i_sync_tid */ - atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); - - /* had we spliced it onto indirect block? */ - if (where->bh) { - /* - * If we spliced it onto an indirect block, we haven't - * altered the inode. Note however that if it is being spliced - * onto an indirect block at the very end of the file (the - * file is growing) then we *will* alter the inode to reflect - * the new i_size. But that is not done here - it is done in - * generic_commit_write->__mark_inode_dirty->ext3_dirty_inode. - */ - jbd_debug(5, "splicing indirect only\n"); - BUFFER_TRACE(where->bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, where->bh); - if (err) - goto err_out; - } else { - /* - * OK, we spliced it into the inode itself on a direct block. - * Inode was dirtied above. - */ - jbd_debug(5, "splicing direct\n"); - } - return err; - -err_out: - for (i = 1; i <= num; i++) { - BUFFER_TRACE(where[i].bh, "call journal_forget"); - ext3_journal_forget(handle, where[i].bh); - ext3_free_blocks(handle,inode,le32_to_cpu(where[i-1].key),1); - } - ext3_free_blocks(handle, inode, le32_to_cpu(where[num].key), blks); - - return err; -} - -/* - * Allocation strategy is simple: if we have to allocate something, we will - * have to go the whole way to leaf. So let's do it before attaching anything - * to tree, set linkage between the newborn blocks, write them if sync is - * required, recheck the path, free and repeat if check fails, otherwise - * set the last missing link (that will protect us from any truncate-generated - * removals - all blocks on the path are immune now) and possibly force the - * write on the parent block. - * That has a nice additional property: no special recovery from the failed - * allocations is needed - we simply release blocks and do not touch anything - * reachable from inode. - * - * `handle' can be NULL if create == 0. - * - * The BKL may not be held on entry here. Be sure to take it early. - * return > 0, # of blocks mapped or allocated. - * return = 0, if plain lookup failed. - * return < 0, error case. - */ -int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, - sector_t iblock, unsigned long maxblocks, - struct buffer_head *bh_result, - int create) -{ - int err = -EIO; - int offsets[4]; - Indirect chain[4]; - Indirect *partial; - ext3_fsblk_t goal; - int indirect_blks; - int blocks_to_boundary = 0; - int depth; - struct ext3_inode_info *ei = EXT3_I(inode); - int count = 0; - ext3_fsblk_t first_block = 0; - - - trace_ext3_get_blocks_enter(inode, iblock, maxblocks, create); - J_ASSERT(handle != NULL || create == 0); - depth = ext3_block_to_path(inode,iblock,offsets,&blocks_to_boundary); - - if (depth == 0) - goto out; - - partial = ext3_get_branch(inode, depth, offsets, chain, &err); - - /* Simplest case - block found, no allocation needed */ - if (!partial) { - first_block = le32_to_cpu(chain[depth - 1].key); - clear_buffer_new(bh_result); - count++; - /*map more blocks*/ - while (count < maxblocks && count <= blocks_to_boundary) { - ext3_fsblk_t blk; - - if (!verify_chain(chain, chain + depth - 1)) { - /* - * Indirect block might be removed by - * truncate while we were reading it. - * Handling of that case: forget what we've - * got now. Flag the err as EAGAIN, so it - * will reread. - */ - err = -EAGAIN; - count = 0; - break; - } - blk = le32_to_cpu(*(chain[depth-1].p + count)); - - if (blk == first_block + count) - count++; - else - break; - } - if (err != -EAGAIN) - goto got_it; - } - - /* Next simple case - plain lookup or failed read of indirect block */ - if (!create || err == -EIO) - goto cleanup; - - /* - * Block out ext3_truncate while we alter the tree - */ - mutex_lock(&ei->truncate_mutex); - - /* - * If the indirect block is missing while we are reading - * the chain(ext3_get_branch() returns -EAGAIN err), or - * if the chain has been changed after we grab the semaphore, - * (either because another process truncated this branch, or - * another get_block allocated this branch) re-grab the chain to see if - * the request block has been allocated or not. - * - * Since we already block the truncate/other get_block - * at this point, we will have the current copy of the chain when we - * splice the branch into the tree. - */ - if (err == -EAGAIN || !verify_chain(chain, partial)) { - while (partial > chain) { - brelse(partial->bh); - partial--; - } - partial = ext3_get_branch(inode, depth, offsets, chain, &err); - if (!partial) { - count++; - mutex_unlock(&ei->truncate_mutex); - if (err) - goto cleanup; - clear_buffer_new(bh_result); - goto got_it; - } - } - - /* - * Okay, we need to do block allocation. Lazily initialize the block - * allocation info here if necessary - */ - if (S_ISREG(inode->i_mode) && (!ei->i_block_alloc_info)) - ext3_init_block_alloc_info(inode); - - goal = ext3_find_goal(inode, iblock, partial); - - /* the number of blocks need to allocate for [d,t]indirect blocks */ - indirect_blks = (chain + depth) - partial - 1; - - /* - * Next look up the indirect map to count the totoal number of - * direct blocks to allocate for this branch. - */ - count = ext3_blks_to_allocate(partial, indirect_blks, - maxblocks, blocks_to_boundary); - err = ext3_alloc_branch(handle, inode, indirect_blks, &count, goal, - offsets + (partial - chain), partial); - - /* - * The ext3_splice_branch call will free and forget any buffers - * on the new chain if there is a failure, but that risks using - * up transaction credits, especially for bitmaps where the - * credits cannot be returned. Can we handle this somehow? We - * may need to return -EAGAIN upwards in the worst case. --sct - */ - if (!err) - err = ext3_splice_branch(handle, inode, iblock, - partial, indirect_blks, count); - mutex_unlock(&ei->truncate_mutex); - if (err) - goto cleanup; - - set_buffer_new(bh_result); -got_it: - map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key)); - if (count > blocks_to_boundary) - set_buffer_boundary(bh_result); - err = count; - /* Clean up and exit */ - partial = chain + depth - 1; /* the whole chain */ -cleanup: - while (partial > chain) { - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } - BUFFER_TRACE(bh_result, "returned"); -out: - trace_ext3_get_blocks_exit(inode, iblock, - depth ? le32_to_cpu(chain[depth-1].key) : 0, - count, err); - return err; -} - -/* Maximum number of blocks we map for direct IO at once. */ -#define DIO_MAX_BLOCKS 4096 -/* - * Number of credits we need for writing DIO_MAX_BLOCKS: - * We need sb + group descriptor + bitmap + inode -> 4 - * For B blocks with A block pointers per block we need: - * 1 (triple ind.) + (B/A/A + 2) (doubly ind.) + (B/A + 2) (indirect). - * If we plug in 4096 for B and 256 for A (for 1KB block size), we get 25. - */ -#define DIO_CREDITS 25 - -static int ext3_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - handle_t *handle = ext3_journal_current_handle(); - int ret = 0, started = 0; - unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; - - if (create && !handle) { /* Direct IO write... */ - if (max_blocks > DIO_MAX_BLOCKS) - max_blocks = DIO_MAX_BLOCKS; - handle = ext3_journal_start(inode, DIO_CREDITS + - EXT3_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } - started = 1; - } - - ret = ext3_get_blocks_handle(handle, inode, iblock, - max_blocks, bh_result, create); - if (ret > 0) { - bh_result->b_size = (ret << inode->i_blkbits); - ret = 0; - } - if (started) - ext3_journal_stop(handle); -out: - return ret; -} - -int ext3_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - u64 start, u64 len) -{ - return generic_block_fiemap(inode, fieinfo, start, len, - ext3_get_block); -} - -/* - * `handle' can be NULL if create is zero - */ -struct buffer_head *ext3_getblk(handle_t *handle, struct inode *inode, - long block, int create, int *errp) -{ - struct buffer_head dummy; - int fatal = 0, err; - - J_ASSERT(handle != NULL || create == 0); - - dummy.b_state = 0; - dummy.b_blocknr = -1000; - buffer_trace_init(&dummy.b_history); - err = ext3_get_blocks_handle(handle, inode, block, 1, - &dummy, create); - /* - * ext3_get_blocks_handle() returns number of blocks - * mapped. 0 in case of a HOLE. - */ - if (err > 0) { - WARN_ON(err > 1); - err = 0; - } - *errp = err; - if (!err && buffer_mapped(&dummy)) { - struct buffer_head *bh; - bh = sb_getblk(inode->i_sb, dummy.b_blocknr); - if (unlikely(!bh)) { - *errp = -ENOMEM; - goto err; - } - if (buffer_new(&dummy)) { - J_ASSERT(create != 0); - J_ASSERT(handle != NULL); - - /* - * Now that we do not always journal data, we should - * keep in mind whether this should always journal the - * new buffer as metadata. For now, regular file - * writes use ext3_get_block instead, so it's not a - * problem. - */ - lock_buffer(bh); - BUFFER_TRACE(bh, "call get_create_access"); - fatal = ext3_journal_get_create_access(handle, bh); - if (!fatal && !buffer_uptodate(bh)) { - memset(bh->b_data,0,inode->i_sb->s_blocksize); - set_buffer_uptodate(bh); - } - unlock_buffer(bh); - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); - if (!fatal) - fatal = err; - } else { - BUFFER_TRACE(bh, "not a new buffer"); - } - if (fatal) { - *errp = fatal; - brelse(bh); - bh = NULL; - } - return bh; - } -err: - return NULL; -} - -struct buffer_head *ext3_bread(handle_t *handle, struct inode *inode, - int block, int create, int *err) -{ - struct buffer_head * bh; - - bh = ext3_getblk(handle, inode, block, create, err); - if (!bh) - return bh; - if (bh_uptodate_or_lock(bh)) - return bh; - get_bh(bh); - bh->b_end_io = end_buffer_read_sync; - submit_bh(READ | REQ_META | REQ_PRIO, bh); - wait_on_buffer(bh); - if (buffer_uptodate(bh)) - return bh; - put_bh(bh); - *err = -EIO; - return NULL; -} - -static int walk_page_buffers( handle_t *handle, - struct buffer_head *head, - unsigned from, - unsigned to, - int *partial, - int (*fn)( handle_t *handle, - struct buffer_head *bh)) -{ - struct buffer_head *bh; - unsigned block_start, block_end; - unsigned blocksize = head->b_size; - int err, ret = 0; - struct buffer_head *next; - - for ( bh = head, block_start = 0; - ret == 0 && (bh != head || !block_start); - block_start = block_end, bh = next) - { - next = bh->b_this_page; - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (partial && !buffer_uptodate(bh)) - *partial = 1; - continue; - } - err = (*fn)(handle, bh); - if (!ret) - ret = err; - } - return ret; -} - -/* - * To preserve ordering, it is essential that the hole instantiation and - * the data write be encapsulated in a single transaction. We cannot - * close off a transaction and start a new one between the ext3_get_block() - * and the commit_write(). So doing the journal_start at the start of - * prepare_write() is the right place. - * - * Also, this function can nest inside ext3_writepage() -> - * block_write_full_page(). In that case, we *know* that ext3_writepage() - * has generated enough buffer credits to do the whole page. So we won't - * block on the journal in that case, which is good, because the caller may - * be PF_MEMALLOC. - * - * By accident, ext3 can be reentered when a transaction is open via - * quota file writes. If we were to commit the transaction while thus - * reentered, there can be a deadlock - we would be holding a quota - * lock, and the commit would never complete if another thread had a - * transaction open and was blocking on the quota lock - a ranking - * violation. - * - * So what we do is to rely on the fact that journal_stop/journal_start - * will _not_ run commit under these circumstances because handle->h_ref - * is elevated. We'll still have enough credits for the tiny quotafile - * write. - */ -static int do_journal_get_write_access(handle_t *handle, - struct buffer_head *bh) -{ - int dirty = buffer_dirty(bh); - int ret; - - if (!buffer_mapped(bh) || buffer_freed(bh)) - return 0; - /* - * __block_prepare_write() could have dirtied some buffers. Clean - * the dirty bit as jbd2_journal_get_write_access() could complain - * otherwise about fs integrity issues. Setting of the dirty bit - * by __block_prepare_write() isn't a real problem here as we clear - * the bit before releasing a page lock and thus writeback cannot - * ever write the buffer. - */ - if (dirty) - clear_buffer_dirty(bh); - ret = ext3_journal_get_write_access(handle, bh); - if (!ret && dirty) - ret = ext3_journal_dirty_metadata(handle, bh); - return ret; -} - -/* - * Truncate blocks that were not used by write. We have to truncate the - * pagecache as well so that corresponding buffers get properly unmapped. - */ -static void ext3_truncate_failed_write(struct inode *inode) -{ - truncate_inode_pages(inode->i_mapping, inode->i_size); - ext3_truncate(inode); -} - -/* - * Truncate blocks that were not used by direct IO write. We have to zero out - * the last file block as well because direct IO might have written to it. - */ -static void ext3_truncate_failed_direct_write(struct inode *inode) -{ - ext3_block_truncate_page(inode, inode->i_size); - ext3_truncate(inode); -} - -static int ext3_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - struct inode *inode = mapping->host; - int ret; - handle_t *handle; - int retries = 0; - struct page *page; - pgoff_t index; - unsigned from, to; - /* Reserve one block more for addition to orphan list in case - * we allocate blocks but write fails for some reason */ - int needed_blocks = ext3_writepage_trans_blocks(inode) + 1; - - trace_ext3_write_begin(inode, pos, len, flags); - - index = pos >> PAGE_CACHE_SHIFT; - from = pos & (PAGE_CACHE_SIZE - 1); - to = from + len; - -retry: - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; - *pagep = page; - - handle = ext3_journal_start(inode, needed_blocks); - if (IS_ERR(handle)) { - unlock_page(page); - page_cache_release(page); - ret = PTR_ERR(handle); - goto out; - } - ret = __block_write_begin(page, pos, len, ext3_get_block); - if (ret) - goto write_begin_failed; - - if (ext3_should_journal_data(inode)) { - ret = walk_page_buffers(handle, page_buffers(page), - from, to, NULL, do_journal_get_write_access); - } -write_begin_failed: - if (ret) { - /* - * block_write_begin may have instantiated a few blocks - * outside i_size. Trim these off again. Don't need - * i_size_read because we hold i_mutex. - * - * Add inode to orphan list in case we crash before truncate - * finishes. Do this only if ext3_can_truncate() agrees so - * that orphan processing code is happy. - */ - if (pos + len > inode->i_size && ext3_can_truncate(inode)) - ext3_orphan_add(handle, inode); - ext3_journal_stop(handle); - unlock_page(page); - page_cache_release(page); - if (pos + len > inode->i_size) - ext3_truncate_failed_write(inode); - } - if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) - goto retry; -out: - return ret; -} - - -int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) -{ - int err = journal_dirty_data(handle, bh); - if (err) - ext3_journal_abort_handle(__func__, __func__, - bh, handle, err); - return err; -} - -/* For ordered writepage and write_end functions */ -static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) -{ - /* - * Write could have mapped the buffer but it didn't copy the data in - * yet. So avoid filing such buffer into a transaction. - */ - if (buffer_mapped(bh) && buffer_uptodate(bh)) - return ext3_journal_dirty_data(handle, bh); - return 0; -} - -/* For write_end() in data=journal mode */ -static int write_end_fn(handle_t *handle, struct buffer_head *bh) -{ - if (!buffer_mapped(bh) || buffer_freed(bh)) - return 0; - set_buffer_uptodate(bh); - return ext3_journal_dirty_metadata(handle, bh); -} - -/* - * This is nasty and subtle: ext3_write_begin() could have allocated blocks - * for the whole page but later we failed to copy the data in. Update inode - * size according to what we managed to copy. The rest is going to be - * truncated in write_end function. - */ -static void update_file_sizes(struct inode *inode, loff_t pos, unsigned copied) -{ - /* What matters to us is i_disksize. We don't write i_size anywhere */ - if (pos + copied > inode->i_size) - i_size_write(inode, pos + copied); - if (pos + copied > EXT3_I(inode)->i_disksize) { - EXT3_I(inode)->i_disksize = pos + copied; - mark_inode_dirty(inode); - } -} - -/* - * We need to pick up the new inode size which generic_commit_write gave us - * `file' can be NULL - eg, when called from page_symlink(). - * - * ext3 never places buffers on inode->i_mapping->private_list. metadata - * buffers are managed internally. - */ -static int ext3_ordered_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - handle_t *handle = ext3_journal_current_handle(); - struct inode *inode = file->f_mapping->host; - unsigned from, to; - int ret = 0, ret2; - - trace_ext3_ordered_write_end(inode, pos, len, copied); - copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); - - from = pos & (PAGE_CACHE_SIZE - 1); - to = from + copied; - ret = walk_page_buffers(handle, page_buffers(page), - from, to, NULL, journal_dirty_data_fn); - - if (ret == 0) - update_file_sizes(inode, pos, copied); - /* - * There may be allocated blocks outside of i_size because - * we failed to copy some data. Prepare for truncate. - */ - if (pos + len > inode->i_size && ext3_can_truncate(inode)) - ext3_orphan_add(handle, inode); - ret2 = ext3_journal_stop(handle); - if (!ret) - ret = ret2; - unlock_page(page); - page_cache_release(page); - - if (pos + len > inode->i_size) - ext3_truncate_failed_write(inode); - return ret ? ret : copied; -} - -static int ext3_writeback_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - handle_t *handle = ext3_journal_current_handle(); - struct inode *inode = file->f_mapping->host; - int ret; - - trace_ext3_writeback_write_end(inode, pos, len, copied); - copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); - update_file_sizes(inode, pos, copied); - /* - * There may be allocated blocks outside of i_size because - * we failed to copy some data. Prepare for truncate. - */ - if (pos + len > inode->i_size && ext3_can_truncate(inode)) - ext3_orphan_add(handle, inode); - ret = ext3_journal_stop(handle); - unlock_page(page); - page_cache_release(page); - - if (pos + len > inode->i_size) - ext3_truncate_failed_write(inode); - return ret ? ret : copied; -} - -static int ext3_journalled_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - handle_t *handle = ext3_journal_current_handle(); - struct inode *inode = mapping->host; - struct ext3_inode_info *ei = EXT3_I(inode); - int ret = 0, ret2; - int partial = 0; - unsigned from, to; - - trace_ext3_journalled_write_end(inode, pos, len, copied); - from = pos & (PAGE_CACHE_SIZE - 1); - to = from + len; - - if (copied < len) { - if (!PageUptodate(page)) - copied = 0; - page_zero_new_buffers(page, from + copied, to); - to = from + copied; - } - - ret = walk_page_buffers(handle, page_buffers(page), from, - to, &partial, write_end_fn); - if (!partial) - SetPageUptodate(page); - - if (pos + copied > inode->i_size) - i_size_write(inode, pos + copied); - /* - * There may be allocated blocks outside of i_size because - * we failed to copy some data. Prepare for truncate. - */ - if (pos + len > inode->i_size && ext3_can_truncate(inode)) - ext3_orphan_add(handle, inode); - ext3_set_inode_state(inode, EXT3_STATE_JDATA); - atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); - if (inode->i_size > ei->i_disksize) { - ei->i_disksize = inode->i_size; - ret2 = ext3_mark_inode_dirty(handle, inode); - if (!ret) - ret = ret2; - } - - ret2 = ext3_journal_stop(handle); - if (!ret) - ret = ret2; - unlock_page(page); - page_cache_release(page); - - if (pos + len > inode->i_size) - ext3_truncate_failed_write(inode); - return ret ? ret : copied; -} - -/* - * bmap() is special. It gets used by applications such as lilo and by - * the swapper to find the on-disk block of a specific piece of data. - * - * Naturally, this is dangerous if the block concerned is still in the - * journal. If somebody makes a swapfile on an ext3 data-journaling - * filesystem and enables swap, then they may get a nasty shock when the - * data getting swapped to that swapfile suddenly gets overwritten by - * the original zero's written out previously to the journal and - * awaiting writeback in the kernel's buffer cache. - * - * So, if we see any bmap calls here on a modified, data-journaled file, - * take extra steps to flush any blocks which might be in the cache. - */ -static sector_t ext3_bmap(struct address_space *mapping, sector_t block) -{ - struct inode *inode = mapping->host; - journal_t *journal; - int err; - - if (ext3_test_inode_state(inode, EXT3_STATE_JDATA)) { - /* - * This is a REALLY heavyweight approach, but the use of - * bmap on dirty files is expected to be extremely rare: - * only if we run lilo or swapon on a freshly made file - * do we expect this to happen. - * - * (bmap requires CAP_SYS_RAWIO so this does not - * represent an unprivileged user DOS attack --- we'd be - * in trouble if mortal users could trigger this path at - * will.) - * - * NB. EXT3_STATE_JDATA is not set on files other than - * regular files. If somebody wants to bmap a directory - * or symlink and gets confused because the buffer - * hasn't yet been flushed to disk, they deserve - * everything they get. - */ - - ext3_clear_inode_state(inode, EXT3_STATE_JDATA); - journal = EXT3_JOURNAL(inode); - journal_lock_updates(journal); - err = journal_flush(journal); - journal_unlock_updates(journal); - - if (err) - return 0; - } - - return generic_block_bmap(mapping,block,ext3_get_block); -} - -static int bget_one(handle_t *handle, struct buffer_head *bh) -{ - get_bh(bh); - return 0; -} - -static int bput_one(handle_t *handle, struct buffer_head *bh) -{ - put_bh(bh); - return 0; -} - -static int buffer_unmapped(handle_t *handle, struct buffer_head *bh) -{ - return !buffer_mapped(bh); -} - -/* - * Note that whenever we need to map blocks we start a transaction even if - * we're not journalling data. This is to preserve ordering: any hole - * instantiation within __block_write_full_page -> ext3_get_block() should be - * journalled along with the data so we don't crash and then get metadata which - * refers to old data. - * - * In all journalling modes block_write_full_page() will start the I/O. - * - * We don't honour synchronous mounts for writepage(). That would be - * disastrous. Any write() or metadata operation will sync the fs for - * us. - */ -static int ext3_ordered_writepage(struct page *page, - struct writeback_control *wbc) -{ - struct inode *inode = page->mapping->host; - struct buffer_head *page_bufs; - handle_t *handle = NULL; - int ret = 0; - int err; - - J_ASSERT(PageLocked(page)); - /* - * We don't want to warn for emergency remount. The condition is - * ordered to avoid dereferencing inode->i_sb in non-error case to - * avoid slow-downs. - */ - WARN_ON_ONCE(IS_RDONLY(inode) && - !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); - - /* - * We give up here if we're reentered, because it might be for a - * different filesystem. - */ - if (ext3_journal_current_handle()) - goto out_fail; - - trace_ext3_ordered_writepage(page); - if (!page_has_buffers(page)) { - create_empty_buffers(page, inode->i_sb->s_blocksize, - (1 << BH_Dirty)|(1 << BH_Uptodate)); - page_bufs = page_buffers(page); - } else { - page_bufs = page_buffers(page); - if (!walk_page_buffers(NULL, page_bufs, 0, PAGE_CACHE_SIZE, - NULL, buffer_unmapped)) { - /* Provide NULL get_block() to catch bugs if buffers - * weren't really mapped */ - return block_write_full_page(page, NULL, wbc); - } - } - handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); - - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out_fail; - } - - walk_page_buffers(handle, page_bufs, 0, - PAGE_CACHE_SIZE, NULL, bget_one); - - ret = block_write_full_page(page, ext3_get_block, wbc); - - /* - * The page can become unlocked at any point now, and - * truncate can then come in and change things. So we - * can't touch *page from now on. But *page_bufs is - * safe due to elevated refcount. - */ - - /* - * And attach them to the current transaction. But only if - * block_write_full_page() succeeded. Otherwise they are unmapped, - * and generally junk. - */ - if (ret == 0) - ret = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, - NULL, journal_dirty_data_fn); - walk_page_buffers(handle, page_bufs, 0, - PAGE_CACHE_SIZE, NULL, bput_one); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; - -out_fail: - redirty_page_for_writepage(wbc, page); - unlock_page(page); - return ret; -} - -static int ext3_writeback_writepage(struct page *page, - struct writeback_control *wbc) -{ - struct inode *inode = page->mapping->host; - handle_t *handle = NULL; - int ret = 0; - int err; - - J_ASSERT(PageLocked(page)); - /* - * We don't want to warn for emergency remount. The condition is - * ordered to avoid dereferencing inode->i_sb in non-error case to - * avoid slow-downs. - */ - WARN_ON_ONCE(IS_RDONLY(inode) && - !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); - - if (ext3_journal_current_handle()) - goto out_fail; - - trace_ext3_writeback_writepage(page); - if (page_has_buffers(page)) { - if (!walk_page_buffers(NULL, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, buffer_unmapped)) { - /* Provide NULL get_block() to catch bugs if buffers - * weren't really mapped */ - return block_write_full_page(page, NULL, wbc); - } - } - - handle = ext3_journal_start(inode, ext3_writepage_trans_blocks(inode)); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out_fail; - } - - ret = block_write_full_page(page, ext3_get_block, wbc); - - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; - -out_fail: - redirty_page_for_writepage(wbc, page); - unlock_page(page); - return ret; -} - -static int ext3_journalled_writepage(struct page *page, - struct writeback_control *wbc) -{ - struct inode *inode = page->mapping->host; - handle_t *handle = NULL; - int ret = 0; - int err; - - J_ASSERT(PageLocked(page)); - /* - * We don't want to warn for emergency remount. The condition is - * ordered to avoid dereferencing inode->i_sb in non-error case to - * avoid slow-downs. - */ - WARN_ON_ONCE(IS_RDONLY(inode) && - !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ERROR_FS)); - - trace_ext3_journalled_writepage(page); - if (!page_has_buffers(page) || PageChecked(page)) { - if (ext3_journal_current_handle()) - goto no_write; - - handle = ext3_journal_start(inode, - ext3_writepage_trans_blocks(inode)); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto no_write; - } - /* - * It's mmapped pagecache. Add buffers and journal it. There - * doesn't seem much point in redirtying the page here. - */ - ClearPageChecked(page); - ret = __block_write_begin(page, 0, PAGE_CACHE_SIZE, - ext3_get_block); - if (ret != 0) { - ext3_journal_stop(handle); - goto out_unlock; - } - ret = walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, do_journal_get_write_access); - - err = walk_page_buffers(handle, page_buffers(page), 0, - PAGE_CACHE_SIZE, NULL, write_end_fn); - if (ret == 0) - ret = err; - ext3_set_inode_state(inode, EXT3_STATE_JDATA); - atomic_set(&EXT3_I(inode)->i_datasync_tid, - handle->h_transaction->t_tid); - unlock_page(page); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - } else { - /* - * It is a page full of checkpoint-mode buffers. Go and write - * them. They should have been already mapped when they went - * to the journal so provide NULL get_block function to catch - * errors. - */ - ret = block_write_full_page(page, NULL, wbc); - } -out: - return ret; - -no_write: - redirty_page_for_writepage(wbc, page); -out_unlock: - unlock_page(page); - goto out; -} - -static int ext3_readpage(struct file *file, struct page *page) -{ - trace_ext3_readpage(page); - return mpage_readpage(page, ext3_get_block); -} - -static int -ext3_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, ext3_get_block); -} - -static void ext3_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - journal_t *journal = EXT3_JOURNAL(page->mapping->host); - - trace_ext3_invalidatepage(page, offset, length); - - /* - * If it's a full truncate we just forget about the pending dirtying - */ - if (offset == 0 && length == PAGE_CACHE_SIZE) - ClearPageChecked(page); - - journal_invalidatepage(journal, page, offset, length); -} - -static int ext3_releasepage(struct page *page, gfp_t wait) -{ - journal_t *journal = EXT3_JOURNAL(page->mapping->host); - - trace_ext3_releasepage(page); - WARN_ON(PageChecked(page)); - if (!page_has_buffers(page)) - return 0; - return journal_try_to_free_buffers(journal, page, wait); -} - -/* - * If the O_DIRECT write will extend the file then add this inode to the - * orphan list. So recovery will truncate it back to the original size - * if the machine crashes during the write. - * - * If the O_DIRECT write is intantiating holes inside i_size and the machine - * crashes then stale disk data _may_ be exposed inside the file. But current - * VFS code falls back into buffered path in that case so we are safe. - */ -static ssize_t ext3_direct_IO(struct kiocb *iocb, struct iov_iter *iter, - loff_t offset) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - struct ext3_inode_info *ei = EXT3_I(inode); - handle_t *handle; - ssize_t ret; - int orphan = 0; - size_t count = iov_iter_count(iter); - int retries = 0; - - trace_ext3_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); - - if (iov_iter_rw(iter) == WRITE) { - loff_t final_size = offset + count; - - if (final_size > inode->i_size) { - /* Credits for sb + inode write */ - handle = ext3_journal_start(inode, 2); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } - ret = ext3_orphan_add(handle, inode); - if (ret) { - ext3_journal_stop(handle); - goto out; - } - orphan = 1; - ei->i_disksize = inode->i_size; - ext3_journal_stop(handle); - } - } - -retry: - ret = blockdev_direct_IO(iocb, inode, iter, offset, ext3_get_block); - /* - * In case of error extending write may have instantiated a few - * blocks outside i_size. Trim these off again. - */ - if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { - loff_t isize = i_size_read(inode); - loff_t end = offset + count; - - if (end > isize) - ext3_truncate_failed_direct_write(inode); - } - if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - - if (orphan) { - int err; - - /* Credits for sb + inode write */ - handle = ext3_journal_start(inode, 2); - if (IS_ERR(handle)) { - /* This is really bad luck. We've written the data - * but cannot extend i_size. Truncate allocated blocks - * and pretend the write failed... */ - ext3_truncate_failed_direct_write(inode); - ret = PTR_ERR(handle); - if (inode->i_nlink) - ext3_orphan_del(NULL, inode); - goto out; - } - if (inode->i_nlink) - ext3_orphan_del(handle, inode); - if (ret > 0) { - loff_t end = offset + ret; - if (end > inode->i_size) { - ei->i_disksize = end; - i_size_write(inode, end); - /* - * We're going to return a positive `ret' - * here due to non-zero-length I/O, so there's - * no way of reporting error returns from - * ext3_mark_inode_dirty() to userspace. So - * ignore it. - */ - ext3_mark_inode_dirty(handle, inode); - } - } - err = ext3_journal_stop(handle); - if (ret == 0) - ret = err; - } -out: - trace_ext3_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret); - return ret; -} - -/* - * Pages can be marked dirty completely asynchronously from ext3's journalling - * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do - * much here because ->set_page_dirty is called under VFS locks. The page is - * not necessarily locked. - * - * We cannot just dirty the page and leave attached buffers clean, because the - * buffers' dirty state is "definitive". We cannot just set the buffers dirty - * or jbddirty because all the journalling code will explode. - * - * So what we do is to mark the page "pending dirty" and next time writepage - * is called, propagate that into the buffers appropriately. - */ -static int ext3_journalled_set_page_dirty(struct page *page) -{ - SetPageChecked(page); - return __set_page_dirty_nobuffers(page); -} - -static const struct address_space_operations ext3_ordered_aops = { - .readpage = ext3_readpage, - .readpages = ext3_readpages, - .writepage = ext3_ordered_writepage, - .write_begin = ext3_write_begin, - .write_end = ext3_ordered_write_end, - .bmap = ext3_bmap, - .invalidatepage = ext3_invalidatepage, - .releasepage = ext3_releasepage, - .direct_IO = ext3_direct_IO, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, - .is_dirty_writeback = buffer_check_dirty_writeback, - .error_remove_page = generic_error_remove_page, -}; - -static const struct address_space_operations ext3_writeback_aops = { - .readpage = ext3_readpage, - .readpages = ext3_readpages, - .writepage = ext3_writeback_writepage, - .write_begin = ext3_write_begin, - .write_end = ext3_writeback_write_end, - .bmap = ext3_bmap, - .invalidatepage = ext3_invalidatepage, - .releasepage = ext3_releasepage, - .direct_IO = ext3_direct_IO, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; - -static const struct address_space_operations ext3_journalled_aops = { - .readpage = ext3_readpage, - .readpages = ext3_readpages, - .writepage = ext3_journalled_writepage, - .write_begin = ext3_write_begin, - .write_end = ext3_journalled_write_end, - .set_page_dirty = ext3_journalled_set_page_dirty, - .bmap = ext3_bmap, - .invalidatepage = ext3_invalidatepage, - .releasepage = ext3_releasepage, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; - -void ext3_set_aops(struct inode *inode) -{ - if (ext3_should_order_data(inode)) - inode->i_mapping->a_ops = &ext3_ordered_aops; - else if (ext3_should_writeback_data(inode)) - inode->i_mapping->a_ops = &ext3_writeback_aops; - else - inode->i_mapping->a_ops = &ext3_journalled_aops; -} - -/* - * ext3_block_truncate_page() zeroes out a mapping from file offset `from' - * up to the end of the block which corresponds to `from'. - * This required during truncate. We need to physically zero the tail end - * of that block so it doesn't yield old data if the file is later grown. - */ -static int ext3_block_truncate_page(struct inode *inode, loff_t from) -{ - ext3_fsblk_t index = from >> PAGE_CACHE_SHIFT; - unsigned offset = from & (PAGE_CACHE_SIZE - 1); - unsigned blocksize, iblock, length, pos; - struct page *page; - handle_t *handle = NULL; - struct buffer_head *bh; - int err = 0; - - /* Truncated on block boundary - nothing to do */ - blocksize = inode->i_sb->s_blocksize; - if ((from & (blocksize - 1)) == 0) - return 0; - - page = grab_cache_page(inode->i_mapping, index); - if (!page) - return -ENOMEM; - length = blocksize - (offset & (blocksize - 1)); - iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); - - if (!page_has_buffers(page)) - create_empty_buffers(page, blocksize, 0); - - /* Find the buffer that contains "offset" */ - bh = page_buffers(page); - pos = blocksize; - while (offset >= pos) { - bh = bh->b_this_page; - iblock++; - pos += blocksize; - } - - err = 0; - if (buffer_freed(bh)) { - BUFFER_TRACE(bh, "freed: skip"); - goto unlock; - } - - if (!buffer_mapped(bh)) { - BUFFER_TRACE(bh, "unmapped"); - ext3_get_block(inode, iblock, bh, 0); - /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(bh)) { - BUFFER_TRACE(bh, "still unmapped"); - goto unlock; - } - } - - /* Ok, it's mapped. Make sure it's up-to-date */ - if (PageUptodate(page)) - set_buffer_uptodate(bh); - - if (!bh_uptodate_or_lock(bh)) { - err = bh_submit_read(bh); - /* Uhhuh. Read error. Complain and punt. */ - if (err) - goto unlock; - } - - /* data=writeback mode doesn't need transaction to zero-out data */ - if (!ext3_should_writeback_data(inode)) { - /* We journal at most one block */ - handle = ext3_journal_start(inode, 1); - if (IS_ERR(handle)) { - clear_highpage(page); - flush_dcache_page(page); - err = PTR_ERR(handle); - goto unlock; - } - } - - if (ext3_should_journal_data(inode)) { - BUFFER_TRACE(bh, "get write access"); - err = ext3_journal_get_write_access(handle, bh); - if (err) - goto stop; - } - - zero_user(page, offset, length); - BUFFER_TRACE(bh, "zeroed end of block"); - - err = 0; - if (ext3_should_journal_data(inode)) { - err = ext3_journal_dirty_metadata(handle, bh); - } else { - if (ext3_should_order_data(inode)) - err = ext3_journal_dirty_data(handle, bh); - mark_buffer_dirty(bh); - } -stop: - if (handle) - ext3_journal_stop(handle); - -unlock: - unlock_page(page); - page_cache_release(page); - return err; -} - -/* - * Probably it should be a library function... search for first non-zero word - * or memcmp with zero_page, whatever is better for particular architecture. - * Linus? - */ -static inline int all_zeroes(__le32 *p, __le32 *q) -{ - while (p < q) - if (*p++) - return 0; - return 1; -} - -/** - * ext3_find_shared - find the indirect blocks for partial truncation. - * @inode: inode in question - * @depth: depth of the affected branch - * @offsets: offsets of pointers in that branch (see ext3_block_to_path) - * @chain: place to store the pointers to partial indirect blocks - * @top: place to the (detached) top of branch - * - * This is a helper function used by ext3_truncate(). - * - * When we do truncate() we may have to clean the ends of several - * indirect blocks but leave the blocks themselves alive. Block is - * partially truncated if some data below the new i_size is referred - * from it (and it is on the path to the first completely truncated - * data block, indeed). We have to free the top of that path along - * with everything to the right of the path. Since no allocation - * past the truncation point is possible until ext3_truncate() - * finishes, we may safely do the latter, but top of branch may - * require special attention - pageout below the truncation point - * might try to populate it. - * - * We atomically detach the top of branch from the tree, store the - * block number of its root in *@top, pointers to buffer_heads of - * partially truncated blocks - in @chain[].bh and pointers to - * their last elements that should not be removed - in - * @chain[].p. Return value is the pointer to last filled element - * of @chain. - * - * The work left to caller to do the actual freeing of subtrees: - * a) free the subtree starting from *@top - * b) free the subtrees whose roots are stored in - * (@chain[i].p+1 .. end of @chain[i].bh->b_data) - * c) free the subtrees growing from the inode past the @chain[0]. - * (no partially truncated stuff there). */ - -static Indirect *ext3_find_shared(struct inode *inode, int depth, - int offsets[4], Indirect chain[4], __le32 *top) -{ - Indirect *partial, *p; - int k, err; - - *top = 0; - /* Make k index the deepest non-null offset + 1 */ - for (k = depth; k > 1 && !offsets[k-1]; k--) - ; - partial = ext3_get_branch(inode, k, offsets, chain, &err); - /* Writer: pointers */ - if (!partial) - partial = chain + k-1; - /* - * If the branch acquired continuation since we've looked at it - - * fine, it should all survive and (new) top doesn't belong to us. - */ - if (!partial->key && *partial->p) - /* Writer: end */ - goto no_top; - for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--) - ; - /* - * OK, we've found the last block that must survive. The rest of our - * branch should be detached before unlocking. However, if that rest - * of branch is all ours and does not grow immediately from the inode - * it's easier to cheat and just decrement partial->p. - */ - if (p == chain + k - 1 && p > chain) { - p->p--; - } else { - *top = *p->p; - /* Nope, don't do this in ext3. Must leave the tree intact */ -#if 0 - *p->p = 0; -#endif - } - /* Writer: end */ - - while(partial > p) { - brelse(partial->bh); - partial--; - } -no_top: - return partial; -} - -/* - * Zero a number of block pointers in either an inode or an indirect block. - * If we restart the transaction we must again get write access to the - * indirect block for further modification. - * - * We release `count' blocks on disk, but (last - first) may be greater - * than `count' because there can be holes in there. - */ -static void ext3_clear_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, ext3_fsblk_t block_to_free, - unsigned long count, __le32 *first, __le32 *last) -{ - __le32 *p; - if (try_to_extend_transaction(handle, inode)) { - if (bh) { - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - if (ext3_journal_dirty_metadata(handle, bh)) - return; - } - ext3_mark_inode_dirty(handle, inode); - truncate_restart_transaction(handle, inode); - if (bh) { - BUFFER_TRACE(bh, "retaking write access"); - if (ext3_journal_get_write_access(handle, bh)) - return; - } - } - - /* - * Any buffers which are on the journal will be in memory. We find - * them on the hash table so journal_revoke() will run journal_forget() - * on them. We've already detached each block from the file, so - * bforget() in journal_forget() should be safe. - * - * AKPM: turn on bforget in journal_forget()!!! - */ - for (p = first; p < last; p++) { - u32 nr = le32_to_cpu(*p); - if (nr) { - struct buffer_head *bh; - - *p = 0; - bh = sb_find_get_block(inode->i_sb, nr); - ext3_forget(handle, 0, inode, bh, nr); - } - } - - ext3_free_blocks(handle, inode, block_to_free, count); -} - -/** - * ext3_free_data - free a list of data blocks - * @handle: handle for this transaction - * @inode: inode we are dealing with - * @this_bh: indirect buffer_head which contains *@first and *@last - * @first: array of block numbers - * @last: points immediately past the end of array - * - * We are freeing all blocks referred from that array (numbers are stored as - * little-endian 32-bit) and updating @inode->i_blocks appropriately. - * - * We accumulate contiguous runs of blocks to free. Conveniently, if these - * blocks are contiguous then releasing them at one time will only affect one - * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't - * actually use a lot of journal space. - * - * @this_bh will be %NULL if @first and @last point into the inode's direct - * block pointers. - */ -static void ext3_free_data(handle_t *handle, struct inode *inode, - struct buffer_head *this_bh, - __le32 *first, __le32 *last) -{ - ext3_fsblk_t block_to_free = 0; /* Starting block # of a run */ - unsigned long count = 0; /* Number of blocks in the run */ - __le32 *block_to_free_p = NULL; /* Pointer into inode/ind - corresponding to - block_to_free */ - ext3_fsblk_t nr; /* Current block # */ - __le32 *p; /* Pointer into inode/ind - for current block */ - int err; - - if (this_bh) { /* For indirect block */ - BUFFER_TRACE(this_bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, this_bh); - /* Important: if we can't update the indirect pointers - * to the blocks, we can't free them. */ - if (err) - return; - } - - for (p = first; p < last; p++) { - nr = le32_to_cpu(*p); - if (nr) { - /* accumulate blocks to free if they're contiguous */ - if (count == 0) { - block_to_free = nr; - block_to_free_p = p; - count = 1; - } else if (nr == block_to_free + count) { - count++; - } else { - ext3_clear_blocks(handle, inode, this_bh, - block_to_free, - count, block_to_free_p, p); - block_to_free = nr; - block_to_free_p = p; - count = 1; - } - } - } - - if (count > 0) - ext3_clear_blocks(handle, inode, this_bh, block_to_free, - count, block_to_free_p, p); - - if (this_bh) { - BUFFER_TRACE(this_bh, "call ext3_journal_dirty_metadata"); - - /* - * The buffer head should have an attached journal head at this - * point. However, if the data is corrupted and an indirect - * block pointed to itself, it would have been detached when - * the block was cleared. Check for this instead of OOPSing. - */ - if (bh2jh(this_bh)) - ext3_journal_dirty_metadata(handle, this_bh); - else - ext3_error(inode->i_sb, "ext3_free_data", - "circular indirect block detected, " - "inode=%lu, block=%llu", - inode->i_ino, - (unsigned long long)this_bh->b_blocknr); - } -} - -/** - * ext3_free_branches - free an array of branches - * @handle: JBD handle for this transaction - * @inode: inode we are dealing with - * @parent_bh: the buffer_head which contains *@first and *@last - * @first: array of block numbers - * @last: pointer immediately past the end of array - * @depth: depth of the branches to free - * - * We are freeing all blocks referred from these branches (numbers are - * stored as little-endian 32-bit) and updating @inode->i_blocks - * appropriately. - */ -static void ext3_free_branches(handle_t *handle, struct inode *inode, - struct buffer_head *parent_bh, - __le32 *first, __le32 *last, int depth) -{ - ext3_fsblk_t nr; - __le32 *p; - - if (is_handle_aborted(handle)) - return; - - if (depth--) { - struct buffer_head *bh; - int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); - p = last; - while (--p >= first) { - nr = le32_to_cpu(*p); - if (!nr) - continue; /* A hole */ - - /* Go read the buffer for the next level down */ - bh = sb_bread(inode->i_sb, nr); - - /* - * A read failure? Report error and clear slot - * (should be rare). - */ - if (!bh) { - ext3_error(inode->i_sb, "ext3_free_branches", - "Read failure, inode=%lu, block="E3FSBLK, - inode->i_ino, nr); - continue; - } - - /* This zaps the entire block. Bottom up. */ - BUFFER_TRACE(bh, "free child branches"); - ext3_free_branches(handle, inode, bh, - (__le32*)bh->b_data, - (__le32*)bh->b_data + addr_per_block, - depth); - - /* - * Everything below this this pointer has been - * released. Now let this top-of-subtree go. - * - * We want the freeing of this indirect block to be - * atomic in the journal with the updating of the - * bitmap block which owns it. So make some room in - * the journal. - * - * We zero the parent pointer *after* freeing its - * pointee in the bitmaps, so if extend_transaction() - * for some reason fails to put the bitmap changes and - * the release into the same transaction, recovery - * will merely complain about releasing a free block, - * rather than leaking blocks. - */ - if (is_handle_aborted(handle)) - return; - if (try_to_extend_transaction(handle, inode)) { - ext3_mark_inode_dirty(handle, inode); - truncate_restart_transaction(handle, inode); - } - - /* - * We've probably journalled the indirect block several - * times during the truncate. But it's no longer - * needed and we now drop it from the transaction via - * journal_revoke(). - * - * That's easy if it's exclusively part of this - * transaction. But if it's part of the committing - * transaction then journal_forget() will simply - * brelse() it. That means that if the underlying - * block is reallocated in ext3_get_block(), - * unmap_underlying_metadata() will find this block - * and will try to get rid of it. damn, damn. Thus - * we don't allow a block to be reallocated until - * a transaction freeing it has fully committed. - * - * We also have to make sure journal replay after a - * crash does not overwrite non-journaled data blocks - * with old metadata when the block got reallocated for - * data. Thus we have to store a revoke record for a - * block in the same transaction in which we free the - * block. - */ - ext3_forget(handle, 1, inode, bh, bh->b_blocknr); - - ext3_free_blocks(handle, inode, nr, 1); - - if (parent_bh) { - /* - * The block which we have just freed is - * pointed to by an indirect block: journal it - */ - BUFFER_TRACE(parent_bh, "get_write_access"); - if (!ext3_journal_get_write_access(handle, - parent_bh)){ - *p = 0; - BUFFER_TRACE(parent_bh, - "call ext3_journal_dirty_metadata"); - ext3_journal_dirty_metadata(handle, - parent_bh); - } - } - } - } else { - /* We have reached the bottom of the tree. */ - BUFFER_TRACE(parent_bh, "free data blocks"); - ext3_free_data(handle, inode, parent_bh, first, last); - } -} - -int ext3_can_truncate(struct inode *inode) -{ - if (S_ISREG(inode->i_mode)) - return 1; - if (S_ISDIR(inode->i_mode)) - return 1; - if (S_ISLNK(inode->i_mode)) - return !ext3_inode_is_fast_symlink(inode); - return 0; -} - -/* - * ext3_truncate() - * - * We block out ext3_get_block() block instantiations across the entire - * transaction, and VFS/VM ensures that ext3_truncate() cannot run - * simultaneously on behalf of the same inode. - * - * As we work through the truncate and commit bits of it to the journal there - * is one core, guiding principle: the file's tree must always be consistent on - * disk. We must be able to restart the truncate after a crash. - * - * The file's tree may be transiently inconsistent in memory (although it - * probably isn't), but whenever we close off and commit a journal transaction, - * the contents of (the filesystem + the journal) must be consistent and - * restartable. It's pretty simple, really: bottom up, right to left (although - * left-to-right works OK too). - * - * Note that at recovery time, journal replay occurs *before* the restart of - * truncate against the orphan inode list. - * - * The committed inode has the new, desired i_size (which is the same as - * i_disksize in this case). After a crash, ext3_orphan_cleanup() will see - * that this inode's truncate did not complete and it will again call - * ext3_truncate() to have another go. So there will be instantiated blocks - * to the right of the truncation point in a crashed ext3 filesystem. But - * that's fine - as long as they are linked from the inode, the post-crash - * ext3_truncate() run will find them and release them. - */ -void ext3_truncate(struct inode *inode) -{ - handle_t *handle; - struct ext3_inode_info *ei = EXT3_I(inode); - __le32 *i_data = ei->i_data; - int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb); - int offsets[4]; - Indirect chain[4]; - Indirect *partial; - __le32 nr = 0; - int n; - long last_block; - unsigned blocksize = inode->i_sb->s_blocksize; - - trace_ext3_truncate_enter(inode); - - if (!ext3_can_truncate(inode)) - goto out_notrans; - - if (inode->i_size == 0 && ext3_should_writeback_data(inode)) - ext3_set_inode_state(inode, EXT3_STATE_FLUSH_ON_CLOSE); - - handle = start_transaction(inode); - if (IS_ERR(handle)) - goto out_notrans; - - last_block = (inode->i_size + blocksize-1) - >> EXT3_BLOCK_SIZE_BITS(inode->i_sb); - n = ext3_block_to_path(inode, last_block, offsets, NULL); - if (n == 0) - goto out_stop; /* error */ - - /* - * OK. This truncate is going to happen. We add the inode to the - * orphan list, so that if this truncate spans multiple transactions, - * and we crash, we will resume the truncate when the filesystem - * recovers. It also marks the inode dirty, to catch the new size. - * - * Implication: the file must always be in a sane, consistent - * truncatable state while each transaction commits. - */ - if (ext3_orphan_add(handle, inode)) - goto out_stop; - - /* - * The orphan list entry will now protect us from any crash which - * occurs before the truncate completes, so it is now safe to propagate - * the new, shorter inode size (held for now in i_size) into the - * on-disk inode. We do this via i_disksize, which is the value which - * ext3 *really* writes onto the disk inode. - */ - ei->i_disksize = inode->i_size; - - /* - * From here we block out all ext3_get_block() callers who want to - * modify the block allocation tree. - */ - mutex_lock(&ei->truncate_mutex); - - if (n == 1) { /* direct blocks */ - ext3_free_data(handle, inode, NULL, i_data+offsets[0], - i_data + EXT3_NDIR_BLOCKS); - goto do_indirects; - } - - partial = ext3_find_shared(inode, n, offsets, chain, &nr); - /* Kill the top of shared branch (not detached) */ - if (nr) { - if (partial == chain) { - /* Shared branch grows from the inode */ - ext3_free_branches(handle, inode, NULL, - &nr, &nr+1, (chain+n-1) - partial); - *partial->p = 0; - /* - * We mark the inode dirty prior to restart, - * and prior to stop. No need for it here. - */ - } else { - /* Shared branch grows from an indirect block */ - ext3_free_branches(handle, inode, partial->bh, - partial->p, - partial->p+1, (chain+n-1) - partial); - } - } - /* Clear the ends of indirect blocks on the shared branch */ - while (partial > chain) { - ext3_free_branches(handle, inode, partial->bh, partial->p + 1, - (__le32*)partial->bh->b_data+addr_per_block, - (chain+n-1) - partial); - BUFFER_TRACE(partial->bh, "call brelse"); - brelse (partial->bh); - partial--; - } -do_indirects: - /* Kill the remaining (whole) subtrees */ - switch (offsets[0]) { - default: - nr = i_data[EXT3_IND_BLOCK]; - if (nr) { - ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 1); - i_data[EXT3_IND_BLOCK] = 0; - } - case EXT3_IND_BLOCK: - nr = i_data[EXT3_DIND_BLOCK]; - if (nr) { - ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 2); - i_data[EXT3_DIND_BLOCK] = 0; - } - case EXT3_DIND_BLOCK: - nr = i_data[EXT3_TIND_BLOCK]; - if (nr) { - ext3_free_branches(handle, inode, NULL, &nr, &nr+1, 3); - i_data[EXT3_TIND_BLOCK] = 0; - } - case EXT3_TIND_BLOCK: - ; - } - - ext3_discard_reservation(inode); - - mutex_unlock(&ei->truncate_mutex); - inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); - - /* - * In a multi-transaction truncate, we only make the final transaction - * synchronous - */ - if (IS_SYNC(inode)) - handle->h_sync = 1; -out_stop: - /* - * If this was a simple ftruncate(), and the file will remain alive - * then we need to clear up the orphan record which we created above. - * However, if this was a real unlink then we were called by - * ext3_evict_inode(), and we allow that function to clean up the - * orphan info for us. - */ - if (inode->i_nlink) - ext3_orphan_del(handle, inode); - - ext3_journal_stop(handle); - trace_ext3_truncate_exit(inode); - return; -out_notrans: - /* - * Delete the inode from orphan list so that it doesn't stay there - * forever and trigger assertion on umount. - */ - if (inode->i_nlink) - ext3_orphan_del(NULL, inode); - trace_ext3_truncate_exit(inode); -} - -static ext3_fsblk_t ext3_get_inode_block(struct super_block *sb, - unsigned long ino, struct ext3_iloc *iloc) -{ - unsigned long block_group; - unsigned long offset; - ext3_fsblk_t block; - struct ext3_group_desc *gdp; - - if (!ext3_valid_inum(sb, ino)) { - /* - * This error is already checked for in namei.c unless we are - * looking at an NFS filehandle, in which case no error - * report is needed - */ - return 0; - } - - block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb); - gdp = ext3_get_group_desc(sb, block_group, NULL); - if (!gdp) - return 0; - /* - * Figure out the offset within the block group inode table - */ - offset = ((ino - 1) % EXT3_INODES_PER_GROUP(sb)) * - EXT3_INODE_SIZE(sb); - block = le32_to_cpu(gdp->bg_inode_table) + - (offset >> EXT3_BLOCK_SIZE_BITS(sb)); - - iloc->block_group = block_group; - iloc->offset = offset & (EXT3_BLOCK_SIZE(sb) - 1); - return block; -} - -/* - * ext3_get_inode_loc returns with an extra refcount against the inode's - * underlying buffer_head on success. If 'in_mem' is true, we have all - * data in memory that is needed to recreate the on-disk version of this - * inode. - */ -static int __ext3_get_inode_loc(struct inode *inode, - struct ext3_iloc *iloc, int in_mem) -{ - ext3_fsblk_t block; - struct buffer_head *bh; - - block = ext3_get_inode_block(inode->i_sb, inode->i_ino, iloc); - if (!block) - return -EIO; - - bh = sb_getblk(inode->i_sb, block); - if (unlikely(!bh)) { - ext3_error (inode->i_sb, "ext3_get_inode_loc", - "unable to read inode block - " - "inode=%lu, block="E3FSBLK, - inode->i_ino, block); - return -ENOMEM; - } - if (!buffer_uptodate(bh)) { - lock_buffer(bh); - - /* - * If the buffer has the write error flag, we have failed - * to write out another inode in the same block. In this - * case, we don't have to read the block because we may - * read the old inode data successfully. - */ - if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) - set_buffer_uptodate(bh); - - if (buffer_uptodate(bh)) { - /* someone brought it uptodate while we waited */ - unlock_buffer(bh); - goto has_buffer; - } - - /* - * If we have all information of the inode in memory and this - * is the only valid inode in the block, we need not read the - * block. - */ - if (in_mem) { - struct buffer_head *bitmap_bh; - struct ext3_group_desc *desc; - int inodes_per_buffer; - int inode_offset, i; - int block_group; - int start; - - block_group = (inode->i_ino - 1) / - EXT3_INODES_PER_GROUP(inode->i_sb); - inodes_per_buffer = bh->b_size / - EXT3_INODE_SIZE(inode->i_sb); - inode_offset = ((inode->i_ino - 1) % - EXT3_INODES_PER_GROUP(inode->i_sb)); - start = inode_offset & ~(inodes_per_buffer - 1); - - /* Is the inode bitmap in cache? */ - desc = ext3_get_group_desc(inode->i_sb, - block_group, NULL); - if (!desc) - goto make_io; - - bitmap_bh = sb_getblk(inode->i_sb, - le32_to_cpu(desc->bg_inode_bitmap)); - if (unlikely(!bitmap_bh)) - goto make_io; - - /* - * If the inode bitmap isn't in cache then the - * optimisation may end up performing two reads instead - * of one, so skip it. - */ - if (!buffer_uptodate(bitmap_bh)) { - brelse(bitmap_bh); - goto make_io; - } - for (i = start; i < start + inodes_per_buffer; i++) { - if (i == inode_offset) - continue; - if (ext3_test_bit(i, bitmap_bh->b_data)) - break; - } - brelse(bitmap_bh); - if (i == start + inodes_per_buffer) { - /* all other inodes are free, so skip I/O */ - memset(bh->b_data, 0, bh->b_size); - set_buffer_uptodate(bh); - unlock_buffer(bh); - goto has_buffer; - } - } - -make_io: - /* - * There are other valid inodes in the buffer, this inode - * has in-inode xattrs, or we don't have this inode in memory. - * Read the block from disk. - */ - trace_ext3_load_inode(inode); - get_bh(bh); - bh->b_end_io = end_buffer_read_sync; - submit_bh(READ | REQ_META | REQ_PRIO, bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - ext3_error(inode->i_sb, "ext3_get_inode_loc", - "unable to read inode block - " - "inode=%lu, block="E3FSBLK, - inode->i_ino, block); - brelse(bh); - return -EIO; - } - } -has_buffer: - iloc->bh = bh; - return 0; -} - -int ext3_get_inode_loc(struct inode *inode, struct ext3_iloc *iloc) -{ - /* We have all inode data except xattrs in memory here. */ - return __ext3_get_inode_loc(inode, iloc, - !ext3_test_inode_state(inode, EXT3_STATE_XATTR)); -} - -void ext3_set_inode_flags(struct inode *inode) -{ - unsigned int flags = EXT3_I(inode)->i_flags; - - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); - if (flags & EXT3_SYNC_FL) - inode->i_flags |= S_SYNC; - if (flags & EXT3_APPEND_FL) - inode->i_flags |= S_APPEND; - if (flags & EXT3_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; - if (flags & EXT3_NOATIME_FL) - inode->i_flags |= S_NOATIME; - if (flags & EXT3_DIRSYNC_FL) - inode->i_flags |= S_DIRSYNC; -} - -/* Propagate flags from i_flags to EXT3_I(inode)->i_flags */ -void ext3_get_inode_flags(struct ext3_inode_info *ei) -{ - unsigned int flags = ei->vfs_inode.i_flags; - - ei->i_flags &= ~(EXT3_SYNC_FL|EXT3_APPEND_FL| - EXT3_IMMUTABLE_FL|EXT3_NOATIME_FL|EXT3_DIRSYNC_FL); - if (flags & S_SYNC) - ei->i_flags |= EXT3_SYNC_FL; - if (flags & S_APPEND) - ei->i_flags |= EXT3_APPEND_FL; - if (flags & S_IMMUTABLE) - ei->i_flags |= EXT3_IMMUTABLE_FL; - if (flags & S_NOATIME) - ei->i_flags |= EXT3_NOATIME_FL; - if (flags & S_DIRSYNC) - ei->i_flags |= EXT3_DIRSYNC_FL; -} - -struct inode *ext3_iget(struct super_block *sb, unsigned long ino) -{ - struct ext3_iloc iloc; - struct ext3_inode *raw_inode; - struct ext3_inode_info *ei; - struct buffer_head *bh; - struct inode *inode; - journal_t *journal = EXT3_SB(sb)->s_journal; - transaction_t *transaction; - long ret; - int block; - uid_t i_uid; - gid_t i_gid; - - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - ei = EXT3_I(inode); - ei->i_block_alloc_info = NULL; - - ret = __ext3_get_inode_loc(inode, &iloc, 0); - if (ret < 0) - goto bad_inode; - bh = iloc.bh; - raw_inode = ext3_raw_inode(&iloc); - inode->i_mode = le16_to_cpu(raw_inode->i_mode); - i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); - if(!(test_opt (inode->i_sb, NO_UID32))) { - i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; - } - i_uid_write(inode, i_uid); - i_gid_write(inode, i_gid); - set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); - inode->i_size = le32_to_cpu(raw_inode->i_size); - inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime); - inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime); - inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime); - inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; - - ei->i_state_flags = 0; - ei->i_dir_start_lookup = 0; - ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); - /* We now have enough fields to check if the inode was active or not. - * This is needed because nfsd might try to access dead inodes - * the test is that same one that e2fsck uses - * NeilBrown 1999oct15 - */ - if (inode->i_nlink == 0) { - if (inode->i_mode == 0 || - !(EXT3_SB(inode->i_sb)->s_mount_state & EXT3_ORPHAN_FS)) { - /* this inode is deleted */ - brelse (bh); - ret = -ESTALE; - goto bad_inode; - } - /* The only unlinked inodes we let through here have - * valid i_mode and are being read by the orphan - * recovery code: that's fine, we're about to complete - * the process of deleting those. */ - } - inode->i_blocks = le32_to_cpu(raw_inode->i_blocks); - ei->i_flags = le32_to_cpu(raw_inode->i_flags); -#ifdef EXT3_FRAGMENTS - ei->i_faddr = le32_to_cpu(raw_inode->i_faddr); - ei->i_frag_no = raw_inode->i_frag; - ei->i_frag_size = raw_inode->i_fsize; -#endif - ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl); - if (!S_ISREG(inode->i_mode)) { - ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl); - } else { - inode->i_size |= - ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32; - } - ei->i_disksize = inode->i_size; - inode->i_generation = le32_to_cpu(raw_inode->i_generation); - ei->i_block_group = iloc.block_group; - /* - * NOTE! The in-memory inode i_data array is in little-endian order - * even on big-endian machines: we do NOT byteswap the block numbers! - */ - for (block = 0; block < EXT3_N_BLOCKS; block++) - ei->i_data[block] = raw_inode->i_block[block]; - INIT_LIST_HEAD(&ei->i_orphan); - - /* - * Set transaction id's of transactions that have to be committed - * to finish f[data]sync. We set them to currently running transaction - * as we cannot be sure that the inode or some of its metadata isn't - * part of the transaction - the inode could have been reclaimed and - * now it is reread from disk. - */ - if (journal) { - tid_t tid; - - spin_lock(&journal->j_state_lock); - if (journal->j_running_transaction) - transaction = journal->j_running_transaction; - else - transaction = journal->j_committing_transaction; - if (transaction) - tid = transaction->t_tid; - else - tid = journal->j_commit_sequence; - spin_unlock(&journal->j_state_lock); - atomic_set(&ei->i_sync_tid, tid); - atomic_set(&ei->i_datasync_tid, tid); - } - - if (inode->i_ino >= EXT3_FIRST_INO(inode->i_sb) + 1 && - EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE) { - /* - * When mke2fs creates big inodes it does not zero out - * the unused bytes above EXT3_GOOD_OLD_INODE_SIZE, - * so ignore those first few inodes. - */ - ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); - if (EXT3_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > - EXT3_INODE_SIZE(inode->i_sb)) { - brelse (bh); - ret = -EIO; - goto bad_inode; - } - if (ei->i_extra_isize == 0) { - /* The extra space is currently unused. Use it. */ - ei->i_extra_isize = sizeof(struct ext3_inode) - - EXT3_GOOD_OLD_INODE_SIZE; - } else { - __le32 *magic = (void *)raw_inode + - EXT3_GOOD_OLD_INODE_SIZE + - ei->i_extra_isize; - if (*magic == cpu_to_le32(EXT3_XATTR_MAGIC)) - ext3_set_inode_state(inode, EXT3_STATE_XATTR); - } - } else - ei->i_extra_isize = 0; - - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ext3_file_inode_operations; - inode->i_fop = &ext3_file_operations; - ext3_set_aops(inode); - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ext3_dir_inode_operations; - inode->i_fop = &ext3_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - if (ext3_inode_is_fast_symlink(inode)) { - inode->i_op = &ext3_fast_symlink_inode_operations; - nd_terminate_link(ei->i_data, inode->i_size, - sizeof(ei->i_data) - 1); - inode->i_link = (char *)ei->i_data; - } else { - inode->i_op = &ext3_symlink_inode_operations; - ext3_set_aops(inode); - } - } else { - inode->i_op = &ext3_special_inode_operations; - if (raw_inode->i_block[0]) - init_special_inode(inode, inode->i_mode, - old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); - else - init_special_inode(inode, inode->i_mode, - new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); - } - brelse (iloc.bh); - ext3_set_inode_flags(inode); - unlock_new_inode(inode); - return inode; - -bad_inode: - iget_failed(inode); - return ERR_PTR(ret); -} - -/* - * Post the struct inode info into an on-disk inode location in the - * buffer-cache. This gobbles the caller's reference to the - * buffer_head in the inode location struct. - * - * The caller must have write access to iloc->bh. - */ -static int ext3_do_update_inode(handle_t *handle, - struct inode *inode, - struct ext3_iloc *iloc) -{ - struct ext3_inode *raw_inode = ext3_raw_inode(iloc); - struct ext3_inode_info *ei = EXT3_I(inode); - struct buffer_head *bh = iloc->bh; - int err = 0, rc, block; - int need_datasync = 0; - __le32 disksize; - uid_t i_uid; - gid_t i_gid; - -again: - /* we can't allow multiple procs in here at once, its a bit racey */ - lock_buffer(bh); - - /* For fields not not tracking in the in-memory inode, - * initialise them to zero for new inodes. */ - if (ext3_test_inode_state(inode, EXT3_STATE_NEW)) - memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); - - ext3_get_inode_flags(ei); - raw_inode->i_mode = cpu_to_le16(inode->i_mode); - i_uid = i_uid_read(inode); - i_gid = i_gid_read(inode); - if(!(test_opt(inode->i_sb, NO_UID32))) { - raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid)); - raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid)); -/* - * Fix up interoperability with old kernels. Otherwise, old inodes get - * re-used with the upper 16 bits of the uid/gid intact - */ - if(!ei->i_dtime) { - raw_inode->i_uid_high = - cpu_to_le16(high_16_bits(i_uid)); - raw_inode->i_gid_high = - cpu_to_le16(high_16_bits(i_gid)); - } else { - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - } else { - raw_inode->i_uid_low = - cpu_to_le16(fs_high2lowuid(i_uid)); - raw_inode->i_gid_low = - cpu_to_le16(fs_high2lowgid(i_gid)); - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - disksize = cpu_to_le32(ei->i_disksize); - if (disksize != raw_inode->i_size) { - need_datasync = 1; - raw_inode->i_size = disksize; - } - raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); - raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec); - raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec); - raw_inode->i_blocks = cpu_to_le32(inode->i_blocks); - raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); - raw_inode->i_flags = cpu_to_le32(ei->i_flags); -#ifdef EXT3_FRAGMENTS - raw_inode->i_faddr = cpu_to_le32(ei->i_faddr); - raw_inode->i_frag = ei->i_frag_no; - raw_inode->i_fsize = ei->i_frag_size; -#endif - raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl); - if (!S_ISREG(inode->i_mode)) { - raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl); - } else { - disksize = cpu_to_le32(ei->i_disksize >> 32); - if (disksize != raw_inode->i_size_high) { - raw_inode->i_size_high = disksize; - need_datasync = 1; - } - if (ei->i_disksize > 0x7fffffffULL) { - struct super_block *sb = inode->i_sb; - if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_LARGE_FILE) || - EXT3_SB(sb)->s_es->s_rev_level == - cpu_to_le32(EXT3_GOOD_OLD_REV)) { - /* If this is the first large file - * created, add a flag to the superblock. - */ - unlock_buffer(bh); - err = ext3_journal_get_write_access(handle, - EXT3_SB(sb)->s_sbh); - if (err) - goto out_brelse; - - ext3_update_dynamic_rev(sb); - EXT3_SET_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_LARGE_FILE); - handle->h_sync = 1; - err = ext3_journal_dirty_metadata(handle, - EXT3_SB(sb)->s_sbh); - /* get our lock and start over */ - goto again; - } - } - } - raw_inode->i_generation = cpu_to_le32(inode->i_generation); - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - if (old_valid_dev(inode->i_rdev)) { - raw_inode->i_block[0] = - cpu_to_le32(old_encode_dev(inode->i_rdev)); - raw_inode->i_block[1] = 0; - } else { - raw_inode->i_block[0] = 0; - raw_inode->i_block[1] = - cpu_to_le32(new_encode_dev(inode->i_rdev)); - raw_inode->i_block[2] = 0; - } - } else for (block = 0; block < EXT3_N_BLOCKS; block++) - raw_inode->i_block[block] = ei->i_data[block]; - - if (ei->i_extra_isize) - raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize); - - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - unlock_buffer(bh); - rc = ext3_journal_dirty_metadata(handle, bh); - if (!err) - err = rc; - ext3_clear_inode_state(inode, EXT3_STATE_NEW); - - atomic_set(&ei->i_sync_tid, handle->h_transaction->t_tid); - if (need_datasync) - atomic_set(&ei->i_datasync_tid, handle->h_transaction->t_tid); -out_brelse: - brelse (bh); - ext3_std_error(inode->i_sb, err); - return err; -} - -/* - * ext3_write_inode() - * - * We are called from a few places: - * - * - Within generic_file_aio_write() -> generic_write_sync() for O_SYNC files. - * Here, there will be no transaction running. We wait for any running - * transaction to commit. - * - * - Within flush work (for sys_sync(), kupdate and such). - * We wait on commit, if told to. - * - * - Within iput_final() -> write_inode_now() - * We wait on commit, if told to. - * - * In all cases it is actually safe for us to return without doing anything, - * because the inode has been copied into a raw inode buffer in - * ext3_mark_inode_dirty(). This is a correctness thing for WB_SYNC_ALL - * writeback. - * - * Note that we are absolutely dependent upon all inode dirtiers doing the - * right thing: they *must* call mark_inode_dirty() after dirtying info in - * which we are interested. - * - * It would be a bug for them to not do this. The code: - * - * mark_inode_dirty(inode) - * stuff(); - * inode->i_size = expr; - * - * is in error because write_inode() could occur while `stuff()' is running, - * and the new i_size will be lost. Plus the inode will no longer be on the - * superblock's dirty inode list. - */ -int ext3_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - if (WARN_ON_ONCE(current->flags & PF_MEMALLOC)) - return 0; - - if (ext3_journal_current_handle()) { - jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); - dump_stack(); - return -EIO; - } - - /* - * No need to force transaction in WB_SYNC_NONE mode. Also - * ext3_sync_fs() will force the commit after everything is - * written. - */ - if (wbc->sync_mode != WB_SYNC_ALL || wbc->for_sync) - return 0; - - return ext3_force_commit(inode->i_sb); -} - -/* - * ext3_setattr() - * - * Called from notify_change. - * - * We want to trap VFS attempts to truncate the file as soon as - * possible. In particular, we want to make sure that when the VFS - * shrinks i_size, we put the inode on the orphan list and modify - * i_disksize immediately, so that during the subsequent flushing of - * dirty pages and freeing of disk blocks, we can guarantee that any - * commit will leave the blocks being flushed in an unused state on - * disk. (On recovery, the inode will get truncated and the blocks will - * be freed, so we have a strong guarantee that no future commit will - * leave these blocks visible to the user.) - * - * Called with inode->sem down. - */ -int ext3_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - int error, rc = 0; - const unsigned int ia_valid = attr->ia_valid; - - error = inode_change_ok(inode, attr); - if (error) - return error; - - if (is_quota_modification(inode, attr)) - dquot_initialize(inode); - if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || - (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { - handle_t *handle; - - /* (user+group)*(old+new) structure, inode write (sb, - * inode block, ? - but truncate inode update has it) */ - handle = ext3_journal_start(inode, EXT3_MAXQUOTAS_INIT_BLOCKS(inode->i_sb)+ - EXT3_MAXQUOTAS_DEL_BLOCKS(inode->i_sb)+3); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto err_out; - } - error = dquot_transfer(inode, attr); - if (error) { - ext3_journal_stop(handle); - return error; - } - /* Update corresponding info in inode so that everything is in - * one transaction */ - if (attr->ia_valid & ATTR_UID) - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; - error = ext3_mark_inode_dirty(handle, inode); - ext3_journal_stop(handle); - } - - if (attr->ia_valid & ATTR_SIZE) - inode_dio_wait(inode); - - if (S_ISREG(inode->i_mode) && - attr->ia_valid & ATTR_SIZE && attr->ia_size < inode->i_size) { - handle_t *handle; - - handle = ext3_journal_start(inode, 3); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto err_out; - } - - error = ext3_orphan_add(handle, inode); - if (error) { - ext3_journal_stop(handle); - goto err_out; - } - EXT3_I(inode)->i_disksize = attr->ia_size; - error = ext3_mark_inode_dirty(handle, inode); - ext3_journal_stop(handle); - if (error) { - /* Some hard fs error must have happened. Bail out. */ - ext3_orphan_del(NULL, inode); - goto err_out; - } - rc = ext3_block_truncate_page(inode, attr->ia_size); - if (rc) { - /* Cleanup orphan list and exit */ - handle = ext3_journal_start(inode, 3); - if (IS_ERR(handle)) { - ext3_orphan_del(NULL, inode); - goto err_out; - } - ext3_orphan_del(handle, inode); - ext3_journal_stop(handle); - goto err_out; - } - } - - if ((attr->ia_valid & ATTR_SIZE) && - attr->ia_size != i_size_read(inode)) { - truncate_setsize(inode, attr->ia_size); - ext3_truncate(inode); - } - - setattr_copy(inode, attr); - mark_inode_dirty(inode); - - if (ia_valid & ATTR_MODE) - rc = posix_acl_chmod(inode, inode->i_mode); - -err_out: - ext3_std_error(inode->i_sb, error); - if (!error) - error = rc; - return error; -} - - -/* - * How many blocks doth make a writepage()? - * - * With N blocks per page, it may be: - * N data blocks - * 2 indirect block - * 2 dindirect - * 1 tindirect - * N+5 bitmap blocks (from the above) - * N+5 group descriptor summary blocks - * 1 inode block - * 1 superblock. - * 2 * EXT3_SINGLEDATA_TRANS_BLOCKS for the quote files - * - * 3 * (N + 5) + 2 + 2 * EXT3_SINGLEDATA_TRANS_BLOCKS - * - * With ordered or writeback data it's the same, less the N data blocks. - * - * If the inode's direct blocks can hold an integral number of pages then a - * page cannot straddle two indirect blocks, and we can only touch one indirect - * and dindirect block, and the "5" above becomes "3". - * - * This still overestimates under most circumstances. If we were to pass the - * start and end offsets in here as well we could do block_to_path() on each - * block and work out the exact number of indirects which are touched. Pah. - */ - -static int ext3_writepage_trans_blocks(struct inode *inode) -{ - int bpp = ext3_journal_blocks_per_page(inode); - int indirects = (EXT3_NDIR_BLOCKS % bpp) ? 5 : 3; - int ret; - - if (ext3_should_journal_data(inode)) - ret = 3 * (bpp + indirects) + 2; - else - ret = 2 * (bpp + indirects) + indirects + 2; - -#ifdef CONFIG_QUOTA - /* We know that structure was already allocated during dquot_initialize so - * we will be updating only the data blocks + inodes */ - ret += EXT3_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); -#endif - - return ret; -} - -/* - * The caller must have previously called ext3_reserve_inode_write(). - * Give this, we know that the caller already has write access to iloc->bh. - */ -int ext3_mark_iloc_dirty(handle_t *handle, - struct inode *inode, struct ext3_iloc *iloc) -{ - int err = 0; - - /* the do_update_inode consumes one bh->b_count */ - get_bh(iloc->bh); - - /* ext3_do_update_inode() does journal_dirty_metadata */ - err = ext3_do_update_inode(handle, inode, iloc); - put_bh(iloc->bh); - return err; -} - -/* - * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. - */ - -int -ext3_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext3_iloc *iloc) -{ - int err = 0; - if (handle) { - err = ext3_get_inode_loc(inode, iloc); - if (!err) { - BUFFER_TRACE(iloc->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, iloc->bh); - if (err) { - brelse(iloc->bh); - iloc->bh = NULL; - } - } - } - ext3_std_error(inode->i_sb, err); - return err; -} - -/* - * What we do here is to mark the in-core inode as clean with respect to inode - * dirtiness (it may still be data-dirty). - * This means that the in-core inode may be reaped by prune_icache - * without having to perform any I/O. This is a very good thing, - * because *any* task may call prune_icache - even ones which - * have a transaction open against a different journal. - * - * Is this cheating? Not really. Sure, we haven't written the - * inode out, but prune_icache isn't a user-visible syncing function. - * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync) - * we start and wait on commits. - */ -int ext3_mark_inode_dirty(handle_t *handle, struct inode *inode) -{ - struct ext3_iloc iloc; - int err; - - might_sleep(); - trace_ext3_mark_inode_dirty(inode, _RET_IP_); - err = ext3_reserve_inode_write(handle, inode, &iloc); - if (!err) - err = ext3_mark_iloc_dirty(handle, inode, &iloc); - return err; -} - -/* - * ext3_dirty_inode() is called from __mark_inode_dirty() - * - * We're really interested in the case where a file is being extended. - * i_size has been changed by generic_commit_write() and we thus need - * to include the updated inode in the current transaction. - * - * Also, dquot_alloc_space() will always dirty the inode when blocks - * are allocated to the file. - * - * If the inode is marked synchronous, we don't honour that here - doing - * so would cause a commit on atime updates, which we don't bother doing. - * We handle synchronous inodes at the highest possible level. - */ -void ext3_dirty_inode(struct inode *inode, int flags) -{ - handle_t *current_handle = ext3_journal_current_handle(); - handle_t *handle; - - handle = ext3_journal_start(inode, 2); - if (IS_ERR(handle)) - goto out; - if (current_handle && - current_handle->h_transaction != handle->h_transaction) { - /* This task has a transaction open against a different fs */ - printk(KERN_EMERG "%s: transactions do not match!\n", - __func__); - } else { - jbd_debug(5, "marking dirty. outer handle=%p\n", - current_handle); - ext3_mark_inode_dirty(handle, inode); - } - ext3_journal_stop(handle); -out: - return; -} - -#if 0 -/* - * Bind an inode's backing buffer_head into this transaction, to prevent - * it from being flushed to disk early. Unlike - * ext3_reserve_inode_write, this leaves behind no bh reference and - * returns no iloc structure, so the caller needs to repeat the iloc - * lookup to mark the inode dirty later. - */ -static int ext3_pin_inode(handle_t *handle, struct inode *inode) -{ - struct ext3_iloc iloc; - - int err = 0; - if (handle) { - err = ext3_get_inode_loc(inode, &iloc); - if (!err) { - BUFFER_TRACE(iloc.bh, "get_write_access"); - err = journal_get_write_access(handle, iloc.bh); - if (!err) - err = ext3_journal_dirty_metadata(handle, - iloc.bh); - brelse(iloc.bh); - } - } - ext3_std_error(inode->i_sb, err); - return err; -} -#endif - -int ext3_change_inode_journal_flag(struct inode *inode, int val) -{ - journal_t *journal; - handle_t *handle; - int err; - - /* - * We have to be very careful here: changing a data block's - * journaling status dynamically is dangerous. If we write a - * data block to the journal, change the status and then delete - * that block, we risk forgetting to revoke the old log record - * from the journal and so a subsequent replay can corrupt data. - * So, first we make sure that the journal is empty and that - * nobody is changing anything. - */ - - journal = EXT3_JOURNAL(inode); - if (is_journal_aborted(journal)) - return -EROFS; - - journal_lock_updates(journal); - journal_flush(journal); - - /* - * OK, there are no updates running now, and all cached data is - * synced to disk. We are now in a completely consistent state - * which doesn't have anything in the journal, and we know that - * no filesystem updates are running, so it is safe to modify - * the inode's in-core data-journaling state flag now. - */ - - if (val) - EXT3_I(inode)->i_flags |= EXT3_JOURNAL_DATA_FL; - else - EXT3_I(inode)->i_flags &= ~EXT3_JOURNAL_DATA_FL; - ext3_set_aops(inode); - - journal_unlock_updates(journal); - - /* Finally we can mark the inode as dirty. */ - - handle = ext3_journal_start(inode, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - err = ext3_mark_inode_dirty(handle, inode); - handle->h_sync = 1; - ext3_journal_stop(handle); - ext3_std_error(inode->i_sb, err); - - return err; -} diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c deleted file mode 100644 index 4d96e9a645326..0000000000000 --- a/fs/ext3/ioctl.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * linux/fs/ext3/ioctl.c - * - * Copyright (C) 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include -#include -#include -#include "ext3.h" - -long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct ext3_inode_info *ei = EXT3_I(inode); - unsigned int flags; - unsigned short rsv_window_size; - - ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg); - - switch (cmd) { - case EXT3_IOC_GETFLAGS: - ext3_get_inode_flags(ei); - flags = ei->i_flags & EXT3_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); - case EXT3_IOC_SETFLAGS: { - handle_t *handle = NULL; - int err; - struct ext3_iloc iloc; - unsigned int oldflags; - unsigned int jflag; - - if (!inode_owner_or_capable(inode)) - return -EACCES; - - if (get_user(flags, (int __user *) arg)) - return -EFAULT; - - err = mnt_want_write_file(filp); - if (err) - return err; - - flags = ext3_mask_flags(inode->i_mode, flags); - - mutex_lock(&inode->i_mutex); - - /* Is it quota file? Do not allow user to mess with it */ - err = -EPERM; - if (IS_NOQUOTA(inode)) - goto flags_out; - - oldflags = ei->i_flags; - - /* The JOURNAL_DATA flag is modifiable only by root */ - jflag = flags & EXT3_JOURNAL_DATA_FL; - - /* - * The IMMUTABLE and APPEND_ONLY flags can only be changed by - * the relevant capability. - * - * This test looks nicer. Thanks to Pauline Middelink - */ - if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto flags_out; - } - - /* - * The JOURNAL_DATA flag can only be changed by - * the relevant capability. - */ - if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { - if (!capable(CAP_SYS_RESOURCE)) - goto flags_out; - } - - handle = ext3_journal_start(inode, 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto flags_out; - } - if (IS_SYNC(inode)) - handle->h_sync = 1; - err = ext3_reserve_inode_write(handle, inode, &iloc); - if (err) - goto flags_err; - - flags = flags & EXT3_FL_USER_MODIFIABLE; - flags |= oldflags & ~EXT3_FL_USER_MODIFIABLE; - ei->i_flags = flags; - - ext3_set_inode_flags(inode); - inode->i_ctime = CURRENT_TIME_SEC; - - err = ext3_mark_iloc_dirty(handle, inode, &iloc); -flags_err: - ext3_journal_stop(handle); - if (err) - goto flags_out; - - if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) - err = ext3_change_inode_journal_flag(inode, jflag); -flags_out: - mutex_unlock(&inode->i_mutex); - mnt_drop_write_file(filp); - return err; - } - case EXT3_IOC_GETVERSION: - case EXT3_IOC_GETVERSION_OLD: - return put_user(inode->i_generation, (int __user *) arg); - case EXT3_IOC_SETVERSION: - case EXT3_IOC_SETVERSION_OLD: { - handle_t *handle; - struct ext3_iloc iloc; - __u32 generation; - int err; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - err = mnt_want_write_file(filp); - if (err) - return err; - if (get_user(generation, (int __user *) arg)) { - err = -EFAULT; - goto setversion_out; - } - - mutex_lock(&inode->i_mutex); - handle = ext3_journal_start(inode, 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto unlock_out; - } - err = ext3_reserve_inode_write(handle, inode, &iloc); - if (err == 0) { - inode->i_ctime = CURRENT_TIME_SEC; - inode->i_generation = generation; - err = ext3_mark_iloc_dirty(handle, inode, &iloc); - } - ext3_journal_stop(handle); - -unlock_out: - mutex_unlock(&inode->i_mutex); -setversion_out: - mnt_drop_write_file(filp); - return err; - } - case EXT3_IOC_GETRSVSZ: - if (test_opt(inode->i_sb, RESERVATION) - && S_ISREG(inode->i_mode) - && ei->i_block_alloc_info) { - rsv_window_size = ei->i_block_alloc_info->rsv_window_node.rsv_goal_size; - return put_user(rsv_window_size, (int __user *)arg); - } - return -ENOTTY; - case EXT3_IOC_SETRSVSZ: { - int err; - - if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) - return -ENOTTY; - - err = mnt_want_write_file(filp); - if (err) - return err; - - if (!inode_owner_or_capable(inode)) { - err = -EACCES; - goto setrsvsz_out; - } - - if (get_user(rsv_window_size, (int __user *)arg)) { - err = -EFAULT; - goto setrsvsz_out; - } - - if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) - rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; - - /* - * need to allocate reservation structure for this inode - * before set the window size - */ - mutex_lock(&ei->truncate_mutex); - if (!ei->i_block_alloc_info) - ext3_init_block_alloc_info(inode); - - if (ei->i_block_alloc_info){ - struct ext3_reserve_window_node *rsv = &ei->i_block_alloc_info->rsv_window_node; - rsv->rsv_goal_size = rsv_window_size; - } - mutex_unlock(&ei->truncate_mutex); -setrsvsz_out: - mnt_drop_write_file(filp); - return err; - } - case EXT3_IOC_GROUP_EXTEND: { - ext3_fsblk_t n_blocks_count; - struct super_block *sb = inode->i_sb; - int err, err2; - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - err = mnt_want_write_file(filp); - if (err) - return err; - - if (get_user(n_blocks_count, (__u32 __user *)arg)) { - err = -EFAULT; - goto group_extend_out; - } - err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); - journal_lock_updates(EXT3_SB(sb)->s_journal); - err2 = journal_flush(EXT3_SB(sb)->s_journal); - journal_unlock_updates(EXT3_SB(sb)->s_journal); - if (err == 0) - err = err2; -group_extend_out: - mnt_drop_write_file(filp); - return err; - } - case EXT3_IOC_GROUP_ADD: { - struct ext3_new_group_data input; - struct super_block *sb = inode->i_sb; - int err, err2; - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - err = mnt_want_write_file(filp); - if (err) - return err; - - if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, - sizeof(input))) { - err = -EFAULT; - goto group_add_out; - } - - err = ext3_group_add(sb, &input); - journal_lock_updates(EXT3_SB(sb)->s_journal); - err2 = journal_flush(EXT3_SB(sb)->s_journal); - journal_unlock_updates(EXT3_SB(sb)->s_journal); - if (err == 0) - err = err2; -group_add_out: - mnt_drop_write_file(filp); - return err; - } - case FITRIM: { - - struct super_block *sb = inode->i_sb; - struct fstrim_range range; - int ret = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&range, (struct fstrim_range __user *)arg, - sizeof(range))) - return -EFAULT; - - ret = ext3_trim_fs(sb, &range); - if (ret < 0) - return ret; - - if (copy_to_user((struct fstrim_range __user *)arg, &range, - sizeof(range))) - return -EFAULT; - - return 0; - } - - default: - return -ENOTTY; - } -} - -#ifdef CONFIG_COMPAT -long ext3_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - /* These are just misnamed, they actually get/put from/to user an int */ - switch (cmd) { - case EXT3_IOC32_GETFLAGS: - cmd = EXT3_IOC_GETFLAGS; - break; - case EXT3_IOC32_SETFLAGS: - cmd = EXT3_IOC_SETFLAGS; - break; - case EXT3_IOC32_GETVERSION: - cmd = EXT3_IOC_GETVERSION; - break; - case EXT3_IOC32_SETVERSION: - cmd = EXT3_IOC_SETVERSION; - break; - case EXT3_IOC32_GROUP_EXTEND: - cmd = EXT3_IOC_GROUP_EXTEND; - break; - case EXT3_IOC32_GETVERSION_OLD: - cmd = EXT3_IOC_GETVERSION_OLD; - break; - case EXT3_IOC32_SETVERSION_OLD: - cmd = EXT3_IOC_SETVERSION_OLD; - break; -#ifdef CONFIG_JBD_DEBUG - case EXT3_IOC32_WAIT_FOR_READONLY: - cmd = EXT3_IOC_WAIT_FOR_READONLY; - break; -#endif - case EXT3_IOC32_GETRSVSZ: - cmd = EXT3_IOC_GETRSVSZ; - break; - case EXT3_IOC32_SETRSVSZ: - cmd = EXT3_IOC_SETRSVSZ; - break; - case EXT3_IOC_GROUP_ADD: - break; - default: - return -ENOIOCTLCMD; - } - return ext3_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); -} -#endif diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c deleted file mode 100644 index c9e767cd4b679..0000000000000 --- a/fs/ext3/namei.c +++ /dev/null @@ -1,2586 +0,0 @@ -/* - * linux/fs/ext3/namei.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/namei.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * Directory entry file type support and forward compatibility hooks - * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 - * Hash Tree Directory indexing (c) - * Daniel Phillips, 2001 - * Hash Tree Directory indexing porting - * Christopher Li, 2002 - * Hash Tree Directory indexing cleanup - * Theodore Ts'o, 2002 - */ - -#include -#include "ext3.h" -#include "namei.h" -#include "xattr.h" -#include "acl.h" - -/* - * define how far ahead to read directories while searching them. - */ -#define NAMEI_RA_CHUNKS 2 -#define NAMEI_RA_BLOCKS 4 -#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) - -static struct buffer_head *ext3_append(handle_t *handle, - struct inode *inode, - u32 *block, int *err) -{ - struct buffer_head *bh; - - *block = inode->i_size >> inode->i_sb->s_blocksize_bits; - - if ((bh = ext3_dir_bread(handle, inode, *block, 1, err))) { - inode->i_size += inode->i_sb->s_blocksize; - EXT3_I(inode)->i_disksize = inode->i_size; - *err = ext3_journal_get_write_access(handle, bh); - if (*err) { - brelse(bh); - bh = NULL; - } - } - return bh; -} - -#ifndef assert -#define assert(test) J_ASSERT(test) -#endif - -#ifdef DX_DEBUG -#define dxtrace(command) command -#else -#define dxtrace(command) -#endif - -struct fake_dirent -{ - __le32 inode; - __le16 rec_len; - u8 name_len; - u8 file_type; -}; - -struct dx_countlimit -{ - __le16 limit; - __le16 count; -}; - -struct dx_entry -{ - __le32 hash; - __le32 block; -}; - -/* - * dx_root_info is laid out so that if it should somehow get overlaid by a - * dirent the two low bits of the hash version will be zero. Therefore, the - * hash version mod 4 should never be 0. Sincerely, the paranoia department. - */ - -struct dx_root -{ - struct fake_dirent dot; - char dot_name[4]; - struct fake_dirent dotdot; - char dotdot_name[4]; - struct dx_root_info - { - __le32 reserved_zero; - u8 hash_version; - u8 info_length; /* 8 */ - u8 indirect_levels; - u8 unused_flags; - } - info; - struct dx_entry entries[0]; -}; - -struct dx_node -{ - struct fake_dirent fake; - struct dx_entry entries[0]; -}; - - -struct dx_frame -{ - struct buffer_head *bh; - struct dx_entry *entries; - struct dx_entry *at; -}; - -struct dx_map_entry -{ - u32 hash; - u16 offs; - u16 size; -}; - -static inline unsigned dx_get_block (struct dx_entry *entry); -static void dx_set_block (struct dx_entry *entry, unsigned value); -static inline unsigned dx_get_hash (struct dx_entry *entry); -static void dx_set_hash (struct dx_entry *entry, unsigned value); -static unsigned dx_get_count (struct dx_entry *entries); -static unsigned dx_get_limit (struct dx_entry *entries); -static void dx_set_count (struct dx_entry *entries, unsigned value); -static void dx_set_limit (struct dx_entry *entries, unsigned value); -static unsigned dx_root_limit (struct inode *dir, unsigned infosize); -static unsigned dx_node_limit (struct inode *dir); -static struct dx_frame *dx_probe(struct qstr *entry, - struct inode *dir, - struct dx_hash_info *hinfo, - struct dx_frame *frame, - int *err); -static void dx_release (struct dx_frame *frames); -static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize, - struct dx_hash_info *hinfo, struct dx_map_entry map[]); -static void dx_sort_map(struct dx_map_entry *map, unsigned count); -static struct ext3_dir_entry_2 *dx_move_dirents (char *from, char *to, - struct dx_map_entry *offsets, int count); -static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize); -static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block); -static int ext3_htree_next_block(struct inode *dir, __u32 hash, - struct dx_frame *frame, - struct dx_frame *frames, - __u32 *start_hash); -static struct buffer_head * ext3_dx_find_entry(struct inode *dir, - struct qstr *entry, struct ext3_dir_entry_2 **res_dir, - int *err); -static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, - struct inode *inode); - -/* - * p is at least 6 bytes before the end of page - */ -static inline struct ext3_dir_entry_2 * -ext3_next_entry(struct ext3_dir_entry_2 *p) -{ - return (struct ext3_dir_entry_2 *)((char *)p + - ext3_rec_len_from_disk(p->rec_len)); -} - -/* - * Future: use high four bits of block for coalesce-on-delete flags - * Mask them off for now. - */ - -static inline unsigned dx_get_block (struct dx_entry *entry) -{ - return le32_to_cpu(entry->block) & 0x00ffffff; -} - -static inline void dx_set_block (struct dx_entry *entry, unsigned value) -{ - entry->block = cpu_to_le32(value); -} - -static inline unsigned dx_get_hash (struct dx_entry *entry) -{ - return le32_to_cpu(entry->hash); -} - -static inline void dx_set_hash (struct dx_entry *entry, unsigned value) -{ - entry->hash = cpu_to_le32(value); -} - -static inline unsigned dx_get_count (struct dx_entry *entries) -{ - return le16_to_cpu(((struct dx_countlimit *) entries)->count); -} - -static inline unsigned dx_get_limit (struct dx_entry *entries) -{ - return le16_to_cpu(((struct dx_countlimit *) entries)->limit); -} - -static inline void dx_set_count (struct dx_entry *entries, unsigned value) -{ - ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); -} - -static inline void dx_set_limit (struct dx_entry *entries, unsigned value) -{ - ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); -} - -static inline unsigned dx_root_limit (struct inode *dir, unsigned infosize) -{ - unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1) - - EXT3_DIR_REC_LEN(2) - infosize; - return entry_space / sizeof(struct dx_entry); -} - -static inline unsigned dx_node_limit (struct inode *dir) -{ - unsigned entry_space = dir->i_sb->s_blocksize - EXT3_DIR_REC_LEN(0); - return entry_space / sizeof(struct dx_entry); -} - -/* - * Debug - */ -#ifdef DX_DEBUG -static void dx_show_index (char * label, struct dx_entry *entries) -{ - int i, n = dx_get_count (entries); - printk("%s index ", label); - for (i = 0; i < n; i++) - { - printk("%x->%u ", i? dx_get_hash(entries + i): 0, dx_get_block(entries + i)); - } - printk("\n"); -} - -struct stats -{ - unsigned names; - unsigned space; - unsigned bcount; -}; - -static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_entry_2 *de, - int size, int show_names) -{ - unsigned names = 0, space = 0; - char *base = (char *) de; - struct dx_hash_info h = *hinfo; - - printk("names: "); - while ((char *) de < base + size) - { - if (de->inode) - { - if (show_names) - { - int len = de->name_len; - char *name = de->name; - while (len--) printk("%c", *name++); - ext3fs_dirhash(de->name, de->name_len, &h); - printk(":%x.%u ", h.hash, - (unsigned) ((char *) de - base)); - } - space += EXT3_DIR_REC_LEN(de->name_len); - names++; - } - de = ext3_next_entry(de); - } - printk("(%i)\n", names); - return (struct stats) { names, space, 1 }; -} - -struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, - struct dx_entry *entries, int levels) -{ - unsigned blocksize = dir->i_sb->s_blocksize; - unsigned count = dx_get_count (entries), names = 0, space = 0, i; - unsigned bcount = 0; - struct buffer_head *bh; - int err; - printk("%i indexed blocks...\n", count); - for (i = 0; i < count; i++, entries++) - { - u32 block = dx_get_block(entries), hash = i? dx_get_hash(entries): 0; - u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; - struct stats stats; - printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); - if (!(bh = ext3_bread (NULL,dir, block, 0,&err))) continue; - stats = levels? - dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): - dx_show_leaf(hinfo, (struct ext3_dir_entry_2 *) bh->b_data, blocksize, 0); - names += stats.names; - space += stats.space; - bcount += stats.bcount; - brelse (bh); - } - if (bcount) - printk("%snames %u, fullness %u (%u%%)\n", levels?"":" ", - names, space/bcount,(space/bcount)*100/blocksize); - return (struct stats) { names, space, bcount}; -} -#endif /* DX_DEBUG */ - -/* - * Probe for a directory leaf block to search. - * - * dx_probe can return ERR_BAD_DX_DIR, which means there was a format - * error in the directory index, and the caller should fall back to - * searching the directory normally. The callers of dx_probe **MUST** - * check for this error code, and make sure it never gets reflected - * back to userspace. - */ -static struct dx_frame * -dx_probe(struct qstr *entry, struct inode *dir, - struct dx_hash_info *hinfo, struct dx_frame *frame_in, int *err) -{ - unsigned count, indirect; - struct dx_entry *at, *entries, *p, *q, *m; - struct dx_root *root; - struct buffer_head *bh; - struct dx_frame *frame = frame_in; - u32 hash; - - frame->bh = NULL; - if (!(bh = ext3_dir_bread(NULL, dir, 0, 0, err))) { - *err = ERR_BAD_DX_DIR; - goto fail; - } - root = (struct dx_root *) bh->b_data; - if (root->info.hash_version != DX_HASH_TEA && - root->info.hash_version != DX_HASH_HALF_MD4 && - root->info.hash_version != DX_HASH_LEGACY) { - ext3_warning(dir->i_sb, __func__, - "Unrecognised inode hash code %d", - root->info.hash_version); - brelse(bh); - *err = ERR_BAD_DX_DIR; - goto fail; - } - hinfo->hash_version = root->info.hash_version; - if (hinfo->hash_version <= DX_HASH_TEA) - hinfo->hash_version += EXT3_SB(dir->i_sb)->s_hash_unsigned; - hinfo->seed = EXT3_SB(dir->i_sb)->s_hash_seed; - if (entry) - ext3fs_dirhash(entry->name, entry->len, hinfo); - hash = hinfo->hash; - - if (root->info.unused_flags & 1) { - ext3_warning(dir->i_sb, __func__, - "Unimplemented inode hash flags: %#06x", - root->info.unused_flags); - brelse(bh); - *err = ERR_BAD_DX_DIR; - goto fail; - } - - if ((indirect = root->info.indirect_levels) > 1) { - ext3_warning(dir->i_sb, __func__, - "Unimplemented inode hash depth: %#06x", - root->info.indirect_levels); - brelse(bh); - *err = ERR_BAD_DX_DIR; - goto fail; - } - - entries = (struct dx_entry *) (((char *)&root->info) + - root->info.info_length); - - if (dx_get_limit(entries) != dx_root_limit(dir, - root->info.info_length)) { - ext3_warning(dir->i_sb, __func__, - "dx entry: limit != root limit"); - brelse(bh); - *err = ERR_BAD_DX_DIR; - goto fail; - } - - dxtrace (printk("Look up %x", hash)); - while (1) - { - count = dx_get_count(entries); - if (!count || count > dx_get_limit(entries)) { - ext3_warning(dir->i_sb, __func__, - "dx entry: no count or count > limit"); - brelse(bh); - *err = ERR_BAD_DX_DIR; - goto fail2; - } - - p = entries + 1; - q = entries + count - 1; - while (p <= q) - { - m = p + (q - p)/2; - dxtrace(printk(".")); - if (dx_get_hash(m) > hash) - q = m - 1; - else - p = m + 1; - } - - if (0) // linear search cross check - { - unsigned n = count - 1; - at = entries; - while (n--) - { - dxtrace(printk(",")); - if (dx_get_hash(++at) > hash) - { - at--; - break; - } - } - assert (at == p - 1); - } - - at = p - 1; - dxtrace(printk(" %x->%u\n", at == entries? 0: dx_get_hash(at), dx_get_block(at))); - frame->bh = bh; - frame->entries = entries; - frame->at = at; - if (!indirect--) return frame; - if (!(bh = ext3_dir_bread(NULL, dir, dx_get_block(at), 0, err))) { - *err = ERR_BAD_DX_DIR; - goto fail2; - } - at = entries = ((struct dx_node *) bh->b_data)->entries; - if (dx_get_limit(entries) != dx_node_limit (dir)) { - ext3_warning(dir->i_sb, __func__, - "dx entry: limit != node limit"); - brelse(bh); - *err = ERR_BAD_DX_DIR; - goto fail2; - } - frame++; - frame->bh = NULL; - } -fail2: - while (frame >= frame_in) { - brelse(frame->bh); - frame--; - } -fail: - if (*err == ERR_BAD_DX_DIR) - ext3_warning(dir->i_sb, __func__, - "Corrupt dir inode %ld, running e2fsck is " - "recommended.", dir->i_ino); - return NULL; -} - -static void dx_release (struct dx_frame *frames) -{ - if (frames[0].bh == NULL) - return; - - if (((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels) - brelse(frames[1].bh); - brelse(frames[0].bh); -} - -/* - * This function increments the frame pointer to search the next leaf - * block, and reads in the necessary intervening nodes if the search - * should be necessary. Whether or not the search is necessary is - * controlled by the hash parameter. If the hash value is even, then - * the search is only continued if the next block starts with that - * hash value. This is used if we are searching for a specific file. - * - * If the hash value is HASH_NB_ALWAYS, then always go to the next block. - * - * This function returns 1 if the caller should continue to search, - * or 0 if it should not. If there is an error reading one of the - * index blocks, it will a negative error code. - * - * If start_hash is non-null, it will be filled in with the starting - * hash of the next page. - */ -static int ext3_htree_next_block(struct inode *dir, __u32 hash, - struct dx_frame *frame, - struct dx_frame *frames, - __u32 *start_hash) -{ - struct dx_frame *p; - struct buffer_head *bh; - int err, num_frames = 0; - __u32 bhash; - - p = frame; - /* - * Find the next leaf page by incrementing the frame pointer. - * If we run out of entries in the interior node, loop around and - * increment pointer in the parent node. When we break out of - * this loop, num_frames indicates the number of interior - * nodes need to be read. - */ - while (1) { - if (++(p->at) < p->entries + dx_get_count(p->entries)) - break; - if (p == frames) - return 0; - num_frames++; - p--; - } - - /* - * If the hash is 1, then continue only if the next page has a - * continuation hash of any value. This is used for readdir - * handling. Otherwise, check to see if the hash matches the - * desired contiuation hash. If it doesn't, return since - * there's no point to read in the successive index pages. - */ - bhash = dx_get_hash(p->at); - if (start_hash) - *start_hash = bhash; - if ((hash & 1) == 0) { - if ((bhash & ~1) != hash) - return 0; - } - /* - * If the hash is HASH_NB_ALWAYS, we always go to the next - * block so no check is necessary - */ - while (num_frames--) { - if (!(bh = ext3_dir_bread(NULL, dir, dx_get_block(p->at), - 0, &err))) - return err; /* Failure */ - p++; - brelse (p->bh); - p->bh = bh; - p->at = p->entries = ((struct dx_node *) bh->b_data)->entries; - } - return 1; -} - - -/* - * This function fills a red-black tree with information from a - * directory block. It returns the number directory entries loaded - * into the tree. If there is an error it is returned in err. - */ -static int htree_dirblock_to_tree(struct file *dir_file, - struct inode *dir, int block, - struct dx_hash_info *hinfo, - __u32 start_hash, __u32 start_minor_hash) -{ - struct buffer_head *bh; - struct ext3_dir_entry_2 *de, *top; - int err = 0, count = 0; - - dxtrace(printk("In htree dirblock_to_tree: block %d\n", block)); - - if (!(bh = ext3_dir_bread(NULL, dir, block, 0, &err))) - return err; - - de = (struct ext3_dir_entry_2 *) bh->b_data; - top = (struct ext3_dir_entry_2 *) ((char *) de + - dir->i_sb->s_blocksize - - EXT3_DIR_REC_LEN(0)); - for (; de < top; de = ext3_next_entry(de)) { - if (!ext3_check_dir_entry("htree_dirblock_to_tree", dir, de, bh, - (block<i_sb)) - +((char *)de - bh->b_data))) { - /* silently ignore the rest of the block */ - break; - } - ext3fs_dirhash(de->name, de->name_len, hinfo); - if ((hinfo->hash < start_hash) || - ((hinfo->hash == start_hash) && - (hinfo->minor_hash < start_minor_hash))) - continue; - if (de->inode == 0) - continue; - if ((err = ext3_htree_store_dirent(dir_file, - hinfo->hash, hinfo->minor_hash, de)) != 0) { - brelse(bh); - return err; - } - count++; - } - brelse(bh); - return count; -} - - -/* - * This function fills a red-black tree with information from a - * directory. We start scanning the directory in hash order, starting - * at start_hash and start_minor_hash. - * - * This function returns the number of entries inserted into the tree, - * or a negative error code. - */ -int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, - __u32 start_minor_hash, __u32 *next_hash) -{ - struct dx_hash_info hinfo; - struct ext3_dir_entry_2 *de; - struct dx_frame frames[2], *frame; - struct inode *dir; - int block, err; - int count = 0; - int ret; - __u32 hashval; - - dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash, - start_minor_hash)); - dir = file_inode(dir_file); - if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) { - hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; - if (hinfo.hash_version <= DX_HASH_TEA) - hinfo.hash_version += - EXT3_SB(dir->i_sb)->s_hash_unsigned; - hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; - count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, - start_hash, start_minor_hash); - *next_hash = ~0; - return count; - } - hinfo.hash = start_hash; - hinfo.minor_hash = 0; - frame = dx_probe(NULL, file_inode(dir_file), &hinfo, frames, &err); - if (!frame) - return err; - - /* Add '.' and '..' from the htree header */ - if (!start_hash && !start_minor_hash) { - de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data; - if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0) - goto errout; - count++; - } - if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) { - de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data; - de = ext3_next_entry(de); - if ((err = ext3_htree_store_dirent(dir_file, 2, 0, de)) != 0) - goto errout; - count++; - } - - while (1) { - block = dx_get_block(frame->at); - ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo, - start_hash, start_minor_hash); - if (ret < 0) { - err = ret; - goto errout; - } - count += ret; - hashval = ~0; - ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, - frame, frames, &hashval); - *next_hash = hashval; - if (ret < 0) { - err = ret; - goto errout; - } - /* - * Stop if: (a) there are no more entries, or - * (b) we have inserted at least one entry and the - * next hash value is not a continuation - */ - if ((ret == 0) || - (count && ((hashval & 1) == 0))) - break; - } - dx_release(frames); - dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", - count, *next_hash)); - return count; -errout: - dx_release(frames); - return (err); -} - - -/* - * Directory block splitting, compacting - */ - -/* - * Create map of hash values, offsets, and sizes, stored at end of block. - * Returns number of entries mapped. - */ -static int dx_make_map(struct ext3_dir_entry_2 *de, unsigned blocksize, - struct dx_hash_info *hinfo, struct dx_map_entry *map_tail) -{ - int count = 0; - char *base = (char *) de; - struct dx_hash_info h = *hinfo; - - while ((char *) de < base + blocksize) - { - if (de->name_len && de->inode) { - ext3fs_dirhash(de->name, de->name_len, &h); - map_tail--; - map_tail->hash = h.hash; - map_tail->offs = (u16) ((char *) de - base); - map_tail->size = le16_to_cpu(de->rec_len); - count++; - cond_resched(); - } - /* XXX: do we need to check rec_len == 0 case? -Chris */ - de = ext3_next_entry(de); - } - return count; -} - -/* Sort map by hash value */ -static void dx_sort_map (struct dx_map_entry *map, unsigned count) -{ - struct dx_map_entry *p, *q, *top = map + count - 1; - int more; - /* Combsort until bubble sort doesn't suck */ - while (count > 2) - { - count = count*10/13; - if (count - 9 < 2) /* 9, 10 -> 11 */ - count = 11; - for (p = top, q = p - count; q >= map; p--, q--) - if (p->hash < q->hash) - swap(*p, *q); - } - /* Garden variety bubble sort */ - do { - more = 0; - q = top; - while (q-- > map) - { - if (q[1].hash >= q[0].hash) - continue; - swap(*(q+1), *q); - more = 1; - } - } while(more); -} - -static void dx_insert_block(struct dx_frame *frame, u32 hash, u32 block) -{ - struct dx_entry *entries = frame->entries; - struct dx_entry *old = frame->at, *new = old + 1; - int count = dx_get_count(entries); - - assert(count < dx_get_limit(entries)); - assert(old < entries + count); - memmove(new + 1, new, (char *)(entries + count) - (char *)(new)); - dx_set_hash(new, hash); - dx_set_block(new, block); - dx_set_count(entries, count + 1); -} - -static void ext3_update_dx_flag(struct inode *inode) -{ - if (!EXT3_HAS_COMPAT_FEATURE(inode->i_sb, - EXT3_FEATURE_COMPAT_DIR_INDEX)) - EXT3_I(inode)->i_flags &= ~EXT3_INDEX_FL; -} - -/* - * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure. - * - * `len <= EXT3_NAME_LEN' is guaranteed by caller. - * `de != NULL' is guaranteed by caller. - */ -static inline int ext3_match (int len, const char * const name, - struct ext3_dir_entry_2 * de) -{ - if (len != de->name_len) - return 0; - if (!de->inode) - return 0; - return !memcmp(name, de->name, len); -} - -/* - * Returns 0 if not found, -1 on failure, and 1 on success - */ -static inline int search_dirblock(struct buffer_head * bh, - struct inode *dir, - struct qstr *child, - unsigned long offset, - struct ext3_dir_entry_2 ** res_dir) -{ - struct ext3_dir_entry_2 * de; - char * dlimit; - int de_len; - const char *name = child->name; - int namelen = child->len; - - de = (struct ext3_dir_entry_2 *) bh->b_data; - dlimit = bh->b_data + dir->i_sb->s_blocksize; - while ((char *) de < dlimit) { - /* this code is executed quadratically often */ - /* do minimal checking `by hand' */ - - if ((char *) de + namelen <= dlimit && - ext3_match (namelen, name, de)) { - /* found a match - just to be sure, do a full check */ - if (!ext3_check_dir_entry("ext3_find_entry", - dir, de, bh, offset)) - return -1; - *res_dir = de; - return 1; - } - /* prevent looping on a bad block */ - de_len = ext3_rec_len_from_disk(de->rec_len); - if (de_len <= 0) - return -1; - offset += de_len; - de = (struct ext3_dir_entry_2 *) ((char *) de + de_len); - } - return 0; -} - - -/* - * ext3_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the cache buffer in which the entry was found, and the entry - * itself (as a parameter - res_dir). It does NOT read the inode of the - * entry - you'll have to do that yourself if you want to. - * - * The returned buffer_head has ->b_count elevated. The caller is expected - * to brelse() it when appropriate. - */ -static struct buffer_head *ext3_find_entry(struct inode *dir, - struct qstr *entry, - struct ext3_dir_entry_2 **res_dir) -{ - struct super_block * sb; - struct buffer_head * bh_use[NAMEI_RA_SIZE]; - struct buffer_head * bh, *ret = NULL; - unsigned long start, block, b; - const u8 *name = entry->name; - int ra_max = 0; /* Number of bh's in the readahead - buffer, bh_use[] */ - int ra_ptr = 0; /* Current index into readahead - buffer */ - int num = 0; - int nblocks, i, err; - int namelen; - - *res_dir = NULL; - sb = dir->i_sb; - namelen = entry->len; - if (namelen > EXT3_NAME_LEN) - return NULL; - if ((namelen <= 2) && (name[0] == '.') && - (name[1] == '.' || name[1] == 0)) { - /* - * "." or ".." will only be in the first block - * NFS may look up ".."; "." should be handled by the VFS - */ - block = start = 0; - nblocks = 1; - goto restart; - } - if (is_dx(dir)) { - bh = ext3_dx_find_entry(dir, entry, res_dir, &err); - /* - * On success, or if the error was file not found, - * return. Otherwise, fall back to doing a search the - * old fashioned way. - */ - if (bh || (err != ERR_BAD_DX_DIR)) - return bh; - dxtrace(printk("ext3_find_entry: dx failed, falling back\n")); - } - nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); - start = EXT3_I(dir)->i_dir_start_lookup; - if (start >= nblocks) - start = 0; - block = start; -restart: - do { - /* - * We deal with the read-ahead logic here. - */ - if (ra_ptr >= ra_max) { - /* Refill the readahead buffer */ - ra_ptr = 0; - b = block; - for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { - /* - * Terminate if we reach the end of the - * directory and must wrap, or if our - * search has finished at this block. - */ - if (b >= nblocks || (num && block == start)) { - bh_use[ra_max] = NULL; - break; - } - num++; - bh = ext3_getblk(NULL, dir, b++, 0, &err); - bh_use[ra_max] = bh; - if (bh && !bh_uptodate_or_lock(bh)) { - get_bh(bh); - bh->b_end_io = end_buffer_read_sync; - submit_bh(READ | REQ_META | REQ_PRIO, - bh); - } - } - } - if ((bh = bh_use[ra_ptr++]) == NULL) - goto next; - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - /* read error, skip block & hope for the best */ - ext3_error(sb, __func__, "reading directory #%lu " - "offset %lu", dir->i_ino, block); - brelse(bh); - goto next; - } - i = search_dirblock(bh, dir, entry, - block << EXT3_BLOCK_SIZE_BITS(sb), res_dir); - if (i == 1) { - EXT3_I(dir)->i_dir_start_lookup = block; - ret = bh; - goto cleanup_and_exit; - } else { - brelse(bh); - if (i < 0) - goto cleanup_and_exit; - } - next: - if (++block >= nblocks) - block = 0; - } while (block != start); - - /* - * If the directory has grown while we were searching, then - * search the last part of the directory before giving up. - */ - block = nblocks; - nblocks = dir->i_size >> EXT3_BLOCK_SIZE_BITS(sb); - if (block < nblocks) { - start = 0; - goto restart; - } - -cleanup_and_exit: - /* Clean up the read-ahead blocks */ - for (; ra_ptr < ra_max; ra_ptr++) - brelse (bh_use[ra_ptr]); - return ret; -} - -static struct buffer_head * ext3_dx_find_entry(struct inode *dir, - struct qstr *entry, struct ext3_dir_entry_2 **res_dir, - int *err) -{ - struct super_block *sb = dir->i_sb; - struct dx_hash_info hinfo; - struct dx_frame frames[2], *frame; - struct buffer_head *bh; - unsigned long block; - int retval; - - if (!(frame = dx_probe(entry, dir, &hinfo, frames, err))) - return NULL; - do { - block = dx_get_block(frame->at); - if (!(bh = ext3_dir_bread (NULL, dir, block, 0, err))) - goto errout; - - retval = search_dirblock(bh, dir, entry, - block << EXT3_BLOCK_SIZE_BITS(sb), - res_dir); - if (retval == 1) { - dx_release(frames); - return bh; - } - brelse(bh); - if (retval == -1) { - *err = ERR_BAD_DX_DIR; - goto errout; - } - - /* Check to see if we should continue to search */ - retval = ext3_htree_next_block(dir, hinfo.hash, frame, - frames, NULL); - if (retval < 0) { - ext3_warning(sb, __func__, - "error reading index page in directory #%lu", - dir->i_ino); - *err = retval; - goto errout; - } - } while (retval == 1); - - *err = -ENOENT; -errout: - dxtrace(printk("%s not found\n", entry->name)); - dx_release (frames); - return NULL; -} - -static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags) -{ - struct inode * inode; - struct ext3_dir_entry_2 * de; - struct buffer_head * bh; - - if (dentry->d_name.len > EXT3_NAME_LEN) - return ERR_PTR(-ENAMETOOLONG); - - bh = ext3_find_entry(dir, &dentry->d_name, &de); - inode = NULL; - if (bh) { - unsigned long ino = le32_to_cpu(de->inode); - brelse (bh); - if (!ext3_valid_inum(dir->i_sb, ino)) { - ext3_error(dir->i_sb, "ext3_lookup", - "bad inode number: %lu", ino); - return ERR_PTR(-EIO); - } - inode = ext3_iget(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - ext3_error(dir->i_sb, __func__, - "deleted inode referenced: %lu", - ino); - return ERR_PTR(-EIO); - } - } - return d_splice_alias(inode, dentry); -} - - -struct dentry *ext3_get_parent(struct dentry *child) -{ - unsigned long ino; - struct qstr dotdot = QSTR_INIT("..", 2); - struct ext3_dir_entry_2 * de; - struct buffer_head *bh; - - bh = ext3_find_entry(d_inode(child), &dotdot, &de); - if (!bh) - return ERR_PTR(-ENOENT); - ino = le32_to_cpu(de->inode); - brelse(bh); - - if (!ext3_valid_inum(d_inode(child)->i_sb, ino)) { - ext3_error(d_inode(child)->i_sb, "ext3_get_parent", - "bad inode number: %lu", ino); - return ERR_PTR(-EIO); - } - - return d_obtain_alias(ext3_iget(d_inode(child)->i_sb, ino)); -} - -#define S_SHIFT 12 -static unsigned char ext3_type_by_mode[S_IFMT >> S_SHIFT] = { - [S_IFREG >> S_SHIFT] = EXT3_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] = EXT3_FT_DIR, - [S_IFCHR >> S_SHIFT] = EXT3_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] = EXT3_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] = EXT3_FT_FIFO, - [S_IFSOCK >> S_SHIFT] = EXT3_FT_SOCK, - [S_IFLNK >> S_SHIFT] = EXT3_FT_SYMLINK, -}; - -static inline void ext3_set_de_type(struct super_block *sb, - struct ext3_dir_entry_2 *de, - umode_t mode) { - if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) - de->file_type = ext3_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; -} - -/* - * Move count entries from end of map between two memory locations. - * Returns pointer to last entry moved. - */ -static struct ext3_dir_entry_2 * -dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count) -{ - unsigned rec_len = 0; - - while (count--) { - struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *) (from + map->offs); - rec_len = EXT3_DIR_REC_LEN(de->name_len); - memcpy (to, de, rec_len); - ((struct ext3_dir_entry_2 *) to)->rec_len = - ext3_rec_len_to_disk(rec_len); - de->inode = 0; - map++; - to += rec_len; - } - return (struct ext3_dir_entry_2 *) (to - rec_len); -} - -/* - * Compact each dir entry in the range to the minimal rec_len. - * Returns pointer to last entry in range. - */ -static struct ext3_dir_entry_2 *dx_pack_dirents(char *base, unsigned blocksize) -{ - struct ext3_dir_entry_2 *next, *to, *prev; - struct ext3_dir_entry_2 *de = (struct ext3_dir_entry_2 *)base; - unsigned rec_len = 0; - - prev = to = de; - while ((char *)de < base + blocksize) { - next = ext3_next_entry(de); - if (de->inode && de->name_len) { - rec_len = EXT3_DIR_REC_LEN(de->name_len); - if (de > to) - memmove(to, de, rec_len); - to->rec_len = ext3_rec_len_to_disk(rec_len); - prev = to; - to = (struct ext3_dir_entry_2 *) (((char *) to) + rec_len); - } - de = next; - } - return prev; -} - -/* - * Split a full leaf block to make room for a new dir entry. - * Allocate a new block, and move entries so that they are approx. equally full. - * Returns pointer to de in block into which the new entry will be inserted. - */ -static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, - struct buffer_head **bh,struct dx_frame *frame, - struct dx_hash_info *hinfo, int *error) -{ - unsigned blocksize = dir->i_sb->s_blocksize; - unsigned count, continued; - struct buffer_head *bh2; - u32 newblock; - u32 hash2; - struct dx_map_entry *map; - char *data1 = (*bh)->b_data, *data2; - unsigned split, move, size; - struct ext3_dir_entry_2 *de = NULL, *de2; - int err = 0, i; - - bh2 = ext3_append (handle, dir, &newblock, &err); - if (!(bh2)) { - brelse(*bh); - *bh = NULL; - goto errout; - } - - BUFFER_TRACE(*bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, *bh); - if (err) - goto journal_error; - - BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, frame->bh); - if (err) - goto journal_error; - - data2 = bh2->b_data; - - /* create map in the end of data2 block */ - map = (struct dx_map_entry *) (data2 + blocksize); - count = dx_make_map ((struct ext3_dir_entry_2 *) data1, - blocksize, hinfo, map); - map -= count; - dx_sort_map (map, count); - /* Split the existing block in the middle, size-wise */ - size = 0; - move = 0; - for (i = count-1; i >= 0; i--) { - /* is more than half of this entry in 2nd half of the block? */ - if (size + map[i].size/2 > blocksize/2) - break; - size += map[i].size; - move++; - } - /* map index at which we will split */ - split = count - move; - hash2 = map[split].hash; - continued = hash2 == map[split - 1].hash; - dxtrace(printk("Split block %i at %x, %i/%i\n", - dx_get_block(frame->at), hash2, split, count-split)); - - /* Fancy dance to stay within two buffers */ - de2 = dx_move_dirents(data1, data2, map + split, count - split); - de = dx_pack_dirents(data1,blocksize); - de->rec_len = ext3_rec_len_to_disk(data1 + blocksize - (char *) de); - de2->rec_len = ext3_rec_len_to_disk(data2 + blocksize - (char *) de2); - dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data1, blocksize, 1)); - dxtrace(dx_show_leaf (hinfo, (struct ext3_dir_entry_2 *) data2, blocksize, 1)); - - /* Which block gets the new entry? */ - if (hinfo->hash >= hash2) - { - swap(*bh, bh2); - de = de2; - } - dx_insert_block (frame, hash2 + continued, newblock); - err = ext3_journal_dirty_metadata (handle, bh2); - if (err) - goto journal_error; - err = ext3_journal_dirty_metadata (handle, frame->bh); - if (err) - goto journal_error; - brelse (bh2); - dxtrace(dx_show_index ("frame", frame->entries)); - return de; - -journal_error: - brelse(*bh); - brelse(bh2); - *bh = NULL; - ext3_std_error(dir->i_sb, err); -errout: - *error = err; - return NULL; -} - - -/* - * Add a new entry into a directory (leaf) block. If de is non-NULL, - * it points to a directory entry which is guaranteed to be large - * enough for new directory entry. If de is NULL, then - * add_dirent_to_buf will attempt search the directory block for - * space. It will return -ENOSPC if no space is available, and -EIO - * and -EEXIST if directory entry already exists. - * - * NOTE! bh is NOT released in the case where ENOSPC is returned. In - * all other cases bh is released. - */ -static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, - struct inode *inode, struct ext3_dir_entry_2 *de, - struct buffer_head * bh) -{ - struct inode *dir = d_inode(dentry->d_parent); - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - unsigned long offset = 0; - unsigned short reclen; - int nlen, rlen, err; - char *top; - - reclen = EXT3_DIR_REC_LEN(namelen); - if (!de) { - de = (struct ext3_dir_entry_2 *)bh->b_data; - top = bh->b_data + dir->i_sb->s_blocksize - reclen; - while ((char *) de <= top) { - if (!ext3_check_dir_entry("ext3_add_entry", dir, de, - bh, offset)) { - brelse (bh); - return -EIO; - } - if (ext3_match (namelen, name, de)) { - brelse (bh); - return -EEXIST; - } - nlen = EXT3_DIR_REC_LEN(de->name_len); - rlen = ext3_rec_len_from_disk(de->rec_len); - if ((de->inode? rlen - nlen: rlen) >= reclen) - break; - de = (struct ext3_dir_entry_2 *)((char *)de + rlen); - offset += rlen; - } - if ((char *) de > top) - return -ENOSPC; - } - BUFFER_TRACE(bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh); - if (err) { - ext3_std_error(dir->i_sb, err); - brelse(bh); - return err; - } - - /* By now the buffer is marked for journaling */ - nlen = EXT3_DIR_REC_LEN(de->name_len); - rlen = ext3_rec_len_from_disk(de->rec_len); - if (de->inode) { - struct ext3_dir_entry_2 *de1 = (struct ext3_dir_entry_2 *)((char *)de + nlen); - de1->rec_len = ext3_rec_len_to_disk(rlen - nlen); - de->rec_len = ext3_rec_len_to_disk(nlen); - de = de1; - } - de->file_type = EXT3_FT_UNKNOWN; - if (inode) { - de->inode = cpu_to_le32(inode->i_ino); - ext3_set_de_type(dir->i_sb, de, inode->i_mode); - } else - de->inode = 0; - de->name_len = namelen; - memcpy (de->name, name, namelen); - /* - * XXX shouldn't update any times until successful - * completion of syscall, but too many callers depend - * on this. - * - * XXX similarly, too many callers depend on - * ext3_new_inode() setting the times, but error - * recovery deletes the inode, so the worst that can - * happen is that the times are slightly out of date - * and/or different from the directory change time. - */ - dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; - ext3_update_dx_flag(dir); - dir->i_version++; - ext3_mark_inode_dirty(handle, dir); - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); - if (err) - ext3_std_error(dir->i_sb, err); - brelse(bh); - return 0; -} - -/* - * This converts a one block unindexed directory to a 3 block indexed - * directory, and adds the dentry to the indexed directory. - */ -static int make_indexed_dir(handle_t *handle, struct dentry *dentry, - struct inode *inode, struct buffer_head *bh) -{ - struct inode *dir = d_inode(dentry->d_parent); - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - struct buffer_head *bh2; - struct dx_root *root; - struct dx_frame frames[2], *frame; - struct dx_entry *entries; - struct ext3_dir_entry_2 *de, *de2; - char *data1, *top; - unsigned len; - int retval; - unsigned blocksize; - struct dx_hash_info hinfo; - u32 block; - struct fake_dirent *fde; - - blocksize = dir->i_sb->s_blocksize; - dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); - retval = ext3_journal_get_write_access(handle, bh); - if (retval) { - ext3_std_error(dir->i_sb, retval); - brelse(bh); - return retval; - } - root = (struct dx_root *) bh->b_data; - - /* The 0th block becomes the root, move the dirents out */ - fde = &root->dotdot; - de = (struct ext3_dir_entry_2 *)((char *)fde + - ext3_rec_len_from_disk(fde->rec_len)); - if ((char *) de >= (((char *) root) + blocksize)) { - ext3_error(dir->i_sb, __func__, - "invalid rec_len for '..' in inode %lu", - dir->i_ino); - brelse(bh); - return -EIO; - } - len = ((char *) root) + blocksize - (char *) de; - - bh2 = ext3_append (handle, dir, &block, &retval); - if (!(bh2)) { - brelse(bh); - return retval; - } - EXT3_I(dir)->i_flags |= EXT3_INDEX_FL; - data1 = bh2->b_data; - - memcpy (data1, de, len); - de = (struct ext3_dir_entry_2 *) data1; - top = data1 + len; - while ((char *)(de2 = ext3_next_entry(de)) < top) - de = de2; - de->rec_len = ext3_rec_len_to_disk(data1 + blocksize - (char *) de); - /* Initialize the root; the dot dirents already exist */ - de = (struct ext3_dir_entry_2 *) (&root->dotdot); - de->rec_len = ext3_rec_len_to_disk(blocksize - EXT3_DIR_REC_LEN(2)); - memset (&root->info, 0, sizeof(root->info)); - root->info.info_length = sizeof(root->info); - root->info.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version; - entries = root->entries; - dx_set_block (entries, 1); - dx_set_count (entries, 1); - dx_set_limit (entries, dx_root_limit(dir, sizeof(root->info))); - - /* Initialize as for dx_probe */ - hinfo.hash_version = root->info.hash_version; - if (hinfo.hash_version <= DX_HASH_TEA) - hinfo.hash_version += EXT3_SB(dir->i_sb)->s_hash_unsigned; - hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed; - ext3fs_dirhash(name, namelen, &hinfo); - frame = frames; - frame->entries = entries; - frame->at = entries; - frame->bh = bh; - bh = bh2; - /* - * Mark buffers dirty here so that if do_split() fails we write a - * consistent set of buffers to disk. - */ - ext3_journal_dirty_metadata(handle, frame->bh); - ext3_journal_dirty_metadata(handle, bh); - de = do_split(handle,dir, &bh, frame, &hinfo, &retval); - if (!de) { - ext3_mark_inode_dirty(handle, dir); - dx_release(frames); - return retval; - } - dx_release(frames); - - return add_dirent_to_buf(handle, dentry, inode, de, bh); -} - -/* - * ext3_add_entry() - * - * adds a file entry to the specified directory, using the same - * semantics as ext3_find_entry(). It returns NULL if it failed. - * - * NOTE!! The inode part of 'de' is left at 0 - which means you - * may not sleep between calling this and putting something into - * the entry, as someone else might have used it while you slept. - */ -static int ext3_add_entry (handle_t *handle, struct dentry *dentry, - struct inode *inode) -{ - struct inode *dir = d_inode(dentry->d_parent); - struct buffer_head * bh; - struct ext3_dir_entry_2 *de; - struct super_block * sb; - int retval; - int dx_fallback=0; - unsigned blocksize; - u32 block, blocks; - - sb = dir->i_sb; - blocksize = sb->s_blocksize; - if (!dentry->d_name.len) - return -EINVAL; - if (is_dx(dir)) { - retval = ext3_dx_add_entry(handle, dentry, inode); - if (!retval || (retval != ERR_BAD_DX_DIR)) - return retval; - EXT3_I(dir)->i_flags &= ~EXT3_INDEX_FL; - dx_fallback++; - ext3_mark_inode_dirty(handle, dir); - } - blocks = dir->i_size >> sb->s_blocksize_bits; - for (block = 0; block < blocks; block++) { - if (!(bh = ext3_dir_bread(handle, dir, block, 0, &retval))) - return retval; - - retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); - if (retval != -ENOSPC) - return retval; - - if (blocks == 1 && !dx_fallback && - EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_DIR_INDEX)) - return make_indexed_dir(handle, dentry, inode, bh); - brelse(bh); - } - bh = ext3_append(handle, dir, &block, &retval); - if (!bh) - return retval; - de = (struct ext3_dir_entry_2 *) bh->b_data; - de->inode = 0; - de->rec_len = ext3_rec_len_to_disk(blocksize); - return add_dirent_to_buf(handle, dentry, inode, de, bh); -} - -/* - * Returns 0 for success, or a negative error value - */ -static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, - struct inode *inode) -{ - struct dx_frame frames[2], *frame; - struct dx_entry *entries, *at; - struct dx_hash_info hinfo; - struct buffer_head * bh; - struct inode *dir = d_inode(dentry->d_parent); - struct super_block * sb = dir->i_sb; - struct ext3_dir_entry_2 *de; - int err; - - frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err); - if (!frame) - return err; - entries = frame->entries; - at = frame->at; - - if (!(bh = ext3_dir_bread(handle, dir, dx_get_block(frame->at), 0, &err))) - goto cleanup; - - BUFFER_TRACE(bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh); - if (err) - goto journal_error; - - err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); - if (err != -ENOSPC) { - bh = NULL; - goto cleanup; - } - - /* Block full, should compress but for now just split */ - dxtrace(printk("using %u of %u node entries\n", - dx_get_count(entries), dx_get_limit(entries))); - /* Need to split index? */ - if (dx_get_count(entries) == dx_get_limit(entries)) { - u32 newblock; - unsigned icount = dx_get_count(entries); - int levels = frame - frames; - struct dx_entry *entries2; - struct dx_node *node2; - struct buffer_head *bh2; - - if (levels && (dx_get_count(frames->entries) == - dx_get_limit(frames->entries))) { - ext3_warning(sb, __func__, - "Directory index full!"); - err = -ENOSPC; - goto cleanup; - } - bh2 = ext3_append (handle, dir, &newblock, &err); - if (!(bh2)) - goto cleanup; - node2 = (struct dx_node *)(bh2->b_data); - entries2 = node2->entries; - memset(&node2->fake, 0, sizeof(struct fake_dirent)); - node2->fake.rec_len = ext3_rec_len_to_disk(sb->s_blocksize); - BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, frame->bh); - if (err) - goto journal_error; - if (levels) { - unsigned icount1 = icount/2, icount2 = icount - icount1; - unsigned hash2 = dx_get_hash(entries + icount1); - dxtrace(printk("Split index %i/%i\n", icount1, icount2)); - - BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ - err = ext3_journal_get_write_access(handle, - frames[0].bh); - if (err) - goto journal_error; - - memcpy ((char *) entries2, (char *) (entries + icount1), - icount2 * sizeof(struct dx_entry)); - dx_set_count (entries, icount1); - dx_set_count (entries2, icount2); - dx_set_limit (entries2, dx_node_limit(dir)); - - /* Which index block gets the new entry? */ - if (at - entries >= icount1) { - frame->at = at = at - entries - icount1 + entries2; - frame->entries = entries = entries2; - swap(frame->bh, bh2); - } - dx_insert_block (frames + 0, hash2, newblock); - dxtrace(dx_show_index ("node", frames[1].entries)); - dxtrace(dx_show_index ("node", - ((struct dx_node *) bh2->b_data)->entries)); - err = ext3_journal_dirty_metadata(handle, bh2); - if (err) - goto journal_error; - brelse (bh2); - } else { - dxtrace(printk("Creating second level index...\n")); - memcpy((char *) entries2, (char *) entries, - icount * sizeof(struct dx_entry)); - dx_set_limit(entries2, dx_node_limit(dir)); - - /* Set up root */ - dx_set_count(entries, 1); - dx_set_block(entries + 0, newblock); - ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1; - - /* Add new access path frame */ - frame = frames + 1; - frame->at = at = at - entries + entries2; - frame->entries = entries = entries2; - frame->bh = bh2; - err = ext3_journal_get_write_access(handle, - frame->bh); - if (err) - goto journal_error; - } - err = ext3_journal_dirty_metadata(handle, frames[0].bh); - if (err) - goto journal_error; - } - de = do_split(handle, dir, &bh, frame, &hinfo, &err); - if (!de) - goto cleanup; - err = add_dirent_to_buf(handle, dentry, inode, de, bh); - bh = NULL; - goto cleanup; - -journal_error: - ext3_std_error(dir->i_sb, err); -cleanup: - if (bh) - brelse(bh); - dx_release(frames); - return err; -} - -/* - * ext3_delete_entry deletes a directory entry by merging it with the - * previous entry - */ -static int ext3_delete_entry (handle_t *handle, - struct inode * dir, - struct ext3_dir_entry_2 * de_del, - struct buffer_head * bh) -{ - struct ext3_dir_entry_2 * de, * pde; - int i; - - i = 0; - pde = NULL; - de = (struct ext3_dir_entry_2 *) bh->b_data; - while (i < bh->b_size) { - if (!ext3_check_dir_entry("ext3_delete_entry", dir, de, bh, i)) - return -EIO; - if (de == de_del) { - int err; - - BUFFER_TRACE(bh, "get_write_access"); - err = ext3_journal_get_write_access(handle, bh); - if (err) - goto journal_error; - - if (pde) - pde->rec_len = ext3_rec_len_to_disk( - ext3_rec_len_from_disk(pde->rec_len) + - ext3_rec_len_from_disk(de->rec_len)); - else - de->inode = 0; - dir->i_version++; - BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, bh); - if (err) { -journal_error: - ext3_std_error(dir->i_sb, err); - return err; - } - return 0; - } - i += ext3_rec_len_from_disk(de->rec_len); - pde = de; - de = ext3_next_entry(de); - } - return -ENOENT; -} - -static int ext3_add_nondir(handle_t *handle, - struct dentry *dentry, struct inode *inode) -{ - int err = ext3_add_entry(handle, dentry, inode); - if (!err) { - ext3_mark_inode_dirty(handle, inode); - unlock_new_inode(inode); - d_instantiate(dentry, inode); - return 0; - } - drop_nlink(inode); - unlock_new_inode(inode); - iput(inode); - return err; -} - -/* - * By the time this is called, we already have created - * the directory cache entry for the new file, but it - * is so far negative - it has no inode. - * - * If the create succeeds, we fill in the inode information - * with d_instantiate(). - */ -static int ext3_create (struct inode * dir, struct dentry * dentry, umode_t mode, - bool excl) -{ - handle_t *handle; - struct inode * inode; - int err, retries = 0; - - dquot_initialize(dir); - -retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - inode = ext3_new_inode (handle, dir, &dentry->d_name, mode); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - inode->i_op = &ext3_file_inode_operations; - inode->i_fop = &ext3_file_operations; - ext3_set_aops(inode); - err = ext3_add_nondir(handle, dentry, inode); - } - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -static int ext3_mknod (struct inode * dir, struct dentry *dentry, - umode_t mode, dev_t rdev) -{ - handle_t *handle; - struct inode *inode; - int err, retries = 0; - - if (!new_valid_dev(rdev)) - return -EINVAL; - - dquot_initialize(dir); - -retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - inode = ext3_new_inode (handle, dir, &dentry->d_name, mode); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - init_special_inode(inode, inode->i_mode, rdev); -#ifdef CONFIG_EXT3_FS_XATTR - inode->i_op = &ext3_special_inode_operations; -#endif - err = ext3_add_nondir(handle, dentry, inode); - } - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -static int ext3_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - handle_t *handle; - struct inode *inode; - int err, retries = 0; - - dquot_initialize(dir); - -retry: - handle = ext3_journal_start(dir, EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + - 4 + EXT3_XATTR_TRANS_BLOCKS); - - if (IS_ERR(handle)) - return PTR_ERR(handle); - - inode = ext3_new_inode (handle, dir, NULL, mode); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - inode->i_op = &ext3_file_inode_operations; - inode->i_fop = &ext3_file_operations; - ext3_set_aops(inode); - d_tmpfile(dentry, inode); - err = ext3_orphan_add(handle, inode); - if (err) - goto err_unlock_inode; - mark_inode_dirty(inode); - unlock_new_inode(inode); - } - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -err_unlock_inode: - ext3_journal_stop(handle); - unlock_new_inode(inode); - return err; -} - -static int ext3_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) -{ - handle_t *handle; - struct inode * inode; - struct buffer_head * dir_block = NULL; - struct ext3_dir_entry_2 * de; - int err, retries = 0; - - if (dir->i_nlink >= EXT3_LINK_MAX) - return -EMLINK; - - dquot_initialize(dir); - -retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - inode = ext3_new_inode (handle, dir, &dentry->d_name, S_IFDIR | mode); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out_stop; - - inode->i_op = &ext3_dir_inode_operations; - inode->i_fop = &ext3_dir_operations; - inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; - if (!(dir_block = ext3_dir_bread(handle, inode, 0, 1, &err))) - goto out_clear_inode; - - BUFFER_TRACE(dir_block, "get_write_access"); - err = ext3_journal_get_write_access(handle, dir_block); - if (err) - goto out_clear_inode; - - de = (struct ext3_dir_entry_2 *) dir_block->b_data; - de->inode = cpu_to_le32(inode->i_ino); - de->name_len = 1; - de->rec_len = ext3_rec_len_to_disk(EXT3_DIR_REC_LEN(de->name_len)); - strcpy (de->name, "."); - ext3_set_de_type(dir->i_sb, de, S_IFDIR); - de = ext3_next_entry(de); - de->inode = cpu_to_le32(dir->i_ino); - de->rec_len = ext3_rec_len_to_disk(inode->i_sb->s_blocksize - - EXT3_DIR_REC_LEN(1)); - de->name_len = 2; - strcpy (de->name, ".."); - ext3_set_de_type(dir->i_sb, de, S_IFDIR); - set_nlink(inode, 2); - BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); - err = ext3_journal_dirty_metadata(handle, dir_block); - if (err) - goto out_clear_inode; - - err = ext3_mark_inode_dirty(handle, inode); - if (!err) - err = ext3_add_entry (handle, dentry, inode); - - if (err) { -out_clear_inode: - clear_nlink(inode); - unlock_new_inode(inode); - ext3_mark_inode_dirty(handle, inode); - iput (inode); - goto out_stop; - } - inc_nlink(dir); - ext3_update_dx_flag(dir); - err = ext3_mark_inode_dirty(handle, dir); - if (err) - goto out_clear_inode; - - unlock_new_inode(inode); - d_instantiate(dentry, inode); -out_stop: - brelse(dir_block); - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -/* - * routine to check that the specified directory is empty (for rmdir) - */ -static int empty_dir (struct inode * inode) -{ - unsigned long offset; - struct buffer_head * bh; - struct ext3_dir_entry_2 * de, * de1; - struct super_block * sb; - int err = 0; - - sb = inode->i_sb; - if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) || - !(bh = ext3_dir_bread(NULL, inode, 0, 0, &err))) { - if (err) - ext3_error(inode->i_sb, __func__, - "error %d reading directory #%lu offset 0", - err, inode->i_ino); - else - ext3_warning(inode->i_sb, __func__, - "bad directory (dir #%lu) - no data block", - inode->i_ino); - return 1; - } - de = (struct ext3_dir_entry_2 *) bh->b_data; - de1 = ext3_next_entry(de); - if (le32_to_cpu(de->inode) != inode->i_ino || - !le32_to_cpu(de1->inode) || - strcmp (".", de->name) || - strcmp ("..", de1->name)) { - ext3_warning (inode->i_sb, "empty_dir", - "bad directory (dir #%lu) - no `.' or `..'", - inode->i_ino); - brelse (bh); - return 1; - } - offset = ext3_rec_len_from_disk(de->rec_len) + - ext3_rec_len_from_disk(de1->rec_len); - de = ext3_next_entry(de1); - while (offset < inode->i_size ) { - if (!bh || - (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { - err = 0; - brelse (bh); - if (!(bh = ext3_dir_bread (NULL, inode, - offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err))) { - if (err) - ext3_error(sb, __func__, - "error %d reading directory" - " #%lu offset %lu", - err, inode->i_ino, offset); - offset += sb->s_blocksize; - continue; - } - de = (struct ext3_dir_entry_2 *) bh->b_data; - } - if (!ext3_check_dir_entry("empty_dir", inode, de, bh, offset)) { - de = (struct ext3_dir_entry_2 *)(bh->b_data + - sb->s_blocksize); - offset = (offset | (sb->s_blocksize - 1)) + 1; - continue; - } - if (le32_to_cpu(de->inode)) { - brelse (bh); - return 0; - } - offset += ext3_rec_len_from_disk(de->rec_len); - de = ext3_next_entry(de); - } - brelse (bh); - return 1; -} - -/* ext3_orphan_add() links an unlinked or truncated inode into a list of - * such inodes, starting at the superblock, in case we crash before the - * file is closed/deleted, or in case the inode truncate spans multiple - * transactions and the last transaction is not recovered after a crash. - * - * At filesystem recovery time, we walk this list deleting unlinked - * inodes and truncating linked inodes in ext3_orphan_cleanup(). - */ -int ext3_orphan_add(handle_t *handle, struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - struct ext3_iloc iloc; - int err = 0, rc; - - mutex_lock(&EXT3_SB(sb)->s_orphan_lock); - if (!list_empty(&EXT3_I(inode)->i_orphan)) - goto out_unlock; - - /* Orphan handling is only valid for files with data blocks - * being truncated, or files being unlinked. */ - - /* @@@ FIXME: Observation from aviro: - * I think I can trigger J_ASSERT in ext3_orphan_add(). We block - * here (on s_orphan_lock), so race with ext3_link() which might bump - * ->i_nlink. For, say it, character device. Not a regular file, - * not a directory, not a symlink and ->i_nlink > 0. - * - * tytso, 4/25/2009: I'm not sure how that could happen; - * shouldn't the fs core protect us from these sort of - * unlink()/link() races? - */ - J_ASSERT ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); - - BUFFER_TRACE(EXT3_SB(sb)->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); - if (err) - goto out_unlock; - - err = ext3_reserve_inode_write(handle, inode, &iloc); - if (err) - goto out_unlock; - - /* Insert this inode at the head of the on-disk orphan list... */ - NEXT_ORPHAN(inode) = le32_to_cpu(EXT3_SB(sb)->s_es->s_last_orphan); - EXT3_SB(sb)->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - rc = ext3_mark_iloc_dirty(handle, inode, &iloc); - if (!err) - err = rc; - - /* Only add to the head of the in-memory list if all the - * previous operations succeeded. If the orphan_add is going to - * fail (possibly taking the journal offline), we can't risk - * leaving the inode on the orphan list: stray orphan-list - * entries can cause panics at unmount time. - * - * This is safe: on error we're going to ignore the orphan list - * anyway on the next recovery. */ - if (!err) - list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); - - jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); - jbd_debug(4, "orphan inode %lu will point to %d\n", - inode->i_ino, NEXT_ORPHAN(inode)); -out_unlock: - mutex_unlock(&EXT3_SB(sb)->s_orphan_lock); - ext3_std_error(inode->i_sb, err); - return err; -} - -/* - * ext3_orphan_del() removes an unlinked or truncated inode from the list - * of such inodes stored on disk, because it is finally being cleaned up. - */ -int ext3_orphan_del(handle_t *handle, struct inode *inode) -{ - struct list_head *prev; - struct ext3_inode_info *ei = EXT3_I(inode); - struct ext3_sb_info *sbi; - unsigned long ino_next; - struct ext3_iloc iloc; - int err = 0; - - mutex_lock(&EXT3_SB(inode->i_sb)->s_orphan_lock); - if (list_empty(&ei->i_orphan)) - goto out; - - ino_next = NEXT_ORPHAN(inode); - prev = ei->i_orphan.prev; - sbi = EXT3_SB(inode->i_sb); - - jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); - - list_del_init(&ei->i_orphan); - - /* If we're on an error path, we may not have a valid - * transaction handle with which to update the orphan list on - * disk, but we still need to remove the inode from the linked - * list in memory. */ - if (!handle) - goto out; - - err = ext3_reserve_inode_write(handle, inode, &iloc); - if (err) - goto out_err; - - if (prev == &sbi->s_orphan) { - jbd_debug(4, "superblock will point to %lu\n", ino_next); - BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext3_journal_get_write_access(handle, sbi->s_sbh); - if (err) - goto out_brelse; - sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); - err = ext3_journal_dirty_metadata(handle, sbi->s_sbh); - } else { - struct ext3_iloc iloc2; - struct inode *i_prev = - &list_entry(prev, struct ext3_inode_info, i_orphan)->vfs_inode; - - jbd_debug(4, "orphan inode %lu will point to %lu\n", - i_prev->i_ino, ino_next); - err = ext3_reserve_inode_write(handle, i_prev, &iloc2); - if (err) - goto out_brelse; - NEXT_ORPHAN(i_prev) = ino_next; - err = ext3_mark_iloc_dirty(handle, i_prev, &iloc2); - } - if (err) - goto out_brelse; - NEXT_ORPHAN(inode) = 0; - err = ext3_mark_iloc_dirty(handle, inode, &iloc); - -out_err: - ext3_std_error(inode->i_sb, err); -out: - mutex_unlock(&EXT3_SB(inode->i_sb)->s_orphan_lock); - return err; - -out_brelse: - brelse(iloc.bh); - goto out_err; -} - -static int ext3_rmdir (struct inode * dir, struct dentry *dentry) -{ - int retval; - struct inode * inode; - struct buffer_head * bh; - struct ext3_dir_entry_2 * de; - handle_t *handle; - - /* Initialize quotas before so that eventual writes go in - * separate transaction */ - dquot_initialize(dir); - dquot_initialize(d_inode(dentry)); - - handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - retval = -ENOENT; - bh = ext3_find_entry(dir, &dentry->d_name, &de); - if (!bh) - goto end_rmdir; - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - inode = d_inode(dentry); - - retval = -EIO; - if (le32_to_cpu(de->inode) != inode->i_ino) - goto end_rmdir; - - retval = -ENOTEMPTY; - if (!empty_dir (inode)) - goto end_rmdir; - - retval = ext3_delete_entry(handle, dir, de, bh); - if (retval) - goto end_rmdir; - if (inode->i_nlink != 2) - ext3_warning (inode->i_sb, "ext3_rmdir", - "empty directory has nlink!=2 (%d)", - inode->i_nlink); - inode->i_version++; - clear_nlink(inode); - /* There's no need to set i_disksize: the fact that i_nlink is - * zero will ensure that the right thing happens during any - * recovery. */ - inode->i_size = 0; - ext3_orphan_add(handle, inode); - inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, inode); - drop_nlink(dir); - ext3_update_dx_flag(dir); - ext3_mark_inode_dirty(handle, dir); - -end_rmdir: - ext3_journal_stop(handle); - brelse (bh); - return retval; -} - -static int ext3_unlink(struct inode * dir, struct dentry *dentry) -{ - int retval; - struct inode * inode; - struct buffer_head * bh; - struct ext3_dir_entry_2 * de; - handle_t *handle; - - trace_ext3_unlink_enter(dir, dentry); - /* Initialize quotas before so that eventual writes go - * in separate transaction */ - dquot_initialize(dir); - dquot_initialize(d_inode(dentry)); - - handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - retval = -ENOENT; - bh = ext3_find_entry(dir, &dentry->d_name, &de); - if (!bh) - goto end_unlink; - - inode = d_inode(dentry); - - retval = -EIO; - if (le32_to_cpu(de->inode) != inode->i_ino) - goto end_unlink; - - if (!inode->i_nlink) { - ext3_warning (inode->i_sb, "ext3_unlink", - "Deleting nonexistent file (%lu), %d", - inode->i_ino, inode->i_nlink); - set_nlink(inode, 1); - } - retval = ext3_delete_entry(handle, dir, de, bh); - if (retval) - goto end_unlink; - dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC; - ext3_update_dx_flag(dir); - ext3_mark_inode_dirty(handle, dir); - drop_nlink(inode); - if (!inode->i_nlink) - ext3_orphan_add(handle, inode); - inode->i_ctime = dir->i_ctime; - ext3_mark_inode_dirty(handle, inode); - retval = 0; - -end_unlink: - ext3_journal_stop(handle); - brelse (bh); - trace_ext3_unlink_exit(dentry, retval); - return retval; -} - -static int ext3_symlink (struct inode * dir, - struct dentry *dentry, const char * symname) -{ - handle_t *handle; - struct inode * inode; - int l, err, retries = 0; - int credits; - - l = strlen(symname)+1; - if (l > dir->i_sb->s_blocksize) - return -ENAMETOOLONG; - - dquot_initialize(dir); - - if (l > EXT3_N_BLOCKS * 4) { - /* - * For non-fast symlinks, we just allocate inode and put it on - * orphan list in the first transaction => we need bitmap, - * group descriptor, sb, inode block, quota blocks, and - * possibly selinux xattr blocks. - */ - credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + - EXT3_XATTR_TRANS_BLOCKS; - } else { - /* - * Fast symlink. We have to add entry to directory - * (EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS), - * allocate new inode (bitmap, group descriptor, inode block, - * quota blocks, sb is already counted in previous macros). - */ - credits = EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + - EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb); - } -retry: - handle = ext3_journal_start(dir, credits); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - inode = ext3_new_inode (handle, dir, &dentry->d_name, S_IFLNK|S_IRWXUGO); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out_stop; - - if (l > EXT3_N_BLOCKS * 4) { - inode->i_op = &ext3_symlink_inode_operations; - ext3_set_aops(inode); - /* - * We cannot call page_symlink() with transaction started - * because it calls into ext3_write_begin() which acquires page - * lock which ranks below transaction start (and it can also - * wait for journal commit if we are running out of space). So - * we have to stop transaction now and restart it when symlink - * contents is written. - * - * To keep fs consistent in case of crash, we have to put inode - * to orphan list in the mean time. - */ - drop_nlink(inode); - err = ext3_orphan_add(handle, inode); - ext3_journal_stop(handle); - if (err) - goto err_drop_inode; - err = __page_symlink(inode, symname, l, 1); - if (err) - goto err_drop_inode; - /* - * Now inode is being linked into dir (EXT3_DATA_TRANS_BLOCKS - * + EXT3_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified - */ - handle = ext3_journal_start(dir, - EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto err_drop_inode; - } - set_nlink(inode, 1); - err = ext3_orphan_del(handle, inode); - if (err) { - ext3_journal_stop(handle); - drop_nlink(inode); - goto err_drop_inode; - } - } else { - inode->i_op = &ext3_fast_symlink_inode_operations; - inode->i_link = (char*)&EXT3_I(inode)->i_data; - memcpy(inode->i_link, symname, l); - inode->i_size = l-1; - } - EXT3_I(inode)->i_disksize = inode->i_size; - err = ext3_add_nondir(handle, dentry, inode); -out_stop: - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -err_drop_inode: - unlock_new_inode(inode); - iput(inode); - return err; -} - -static int ext3_link (struct dentry * old_dentry, - struct inode * dir, struct dentry *dentry) -{ - handle_t *handle; - struct inode *inode = d_inode(old_dentry); - int err, retries = 0; - - if (inode->i_nlink >= EXT3_LINK_MAX) - return -EMLINK; - - dquot_initialize(dir); - -retry: - handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - handle->h_sync = 1; - - inode->i_ctime = CURRENT_TIME_SEC; - inc_nlink(inode); - ihold(inode); - - err = ext3_add_entry(handle, dentry, inode); - if (!err) { - ext3_mark_inode_dirty(handle, inode); - /* this can happen only for tmpfile being - * linked the first time - */ - if (inode->i_nlink == 1) - ext3_orphan_del(handle, inode); - d_instantiate(dentry, inode); - } else { - drop_nlink(inode); - iput(inode); - } - ext3_journal_stop(handle); - if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -#define PARENT_INO(buffer) \ - (ext3_next_entry((struct ext3_dir_entry_2 *)(buffer))->inode) - -/* - * Anybody can rename anything with this: the permission checks are left to the - * higher-level routines. - */ -static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, - struct inode * new_dir,struct dentry *new_dentry) -{ - handle_t *handle; - struct inode * old_inode, * new_inode; - struct buffer_head * old_bh, * new_bh, * dir_bh; - struct ext3_dir_entry_2 * old_de, * new_de; - int retval, flush_file = 0; - - dquot_initialize(old_dir); - dquot_initialize(new_dir); - - old_bh = new_bh = dir_bh = NULL; - - /* Initialize quotas before so that eventual writes go - * in separate transaction */ - if (d_really_is_positive(new_dentry)) - dquot_initialize(d_inode(new_dentry)); - handle = ext3_journal_start(old_dir, 2 * - EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) + - EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir)) - handle->h_sync = 1; - - old_bh = ext3_find_entry(old_dir, &old_dentry->d_name, &old_de); - /* - * Check for inode number is _not_ due to possible IO errors. - * We might rmdir the source, keep it as pwd of some process - * and merrily kill the link to whatever was created under the - * same name. Goodbye sticky bit ;-< - */ - old_inode = d_inode(old_dentry); - retval = -ENOENT; - if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino) - goto end_rename; - - new_inode = d_inode(new_dentry); - new_bh = ext3_find_entry(new_dir, &new_dentry->d_name, &new_de); - if (new_bh) { - if (!new_inode) { - brelse (new_bh); - new_bh = NULL; - } - } - if (S_ISDIR(old_inode->i_mode)) { - if (new_inode) { - retval = -ENOTEMPTY; - if (!empty_dir (new_inode)) - goto end_rename; - } - retval = -EIO; - dir_bh = ext3_dir_bread(handle, old_inode, 0, 0, &retval); - if (!dir_bh) - goto end_rename; - if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino) - goto end_rename; - retval = -EMLINK; - if (!new_inode && new_dir!=old_dir && - new_dir->i_nlink >= EXT3_LINK_MAX) - goto end_rename; - } - if (!new_bh) { - retval = ext3_add_entry (handle, new_dentry, old_inode); - if (retval) - goto end_rename; - } else { - BUFFER_TRACE(new_bh, "get write access"); - retval = ext3_journal_get_write_access(handle, new_bh); - if (retval) - goto journal_error; - new_de->inode = cpu_to_le32(old_inode->i_ino); - if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb, - EXT3_FEATURE_INCOMPAT_FILETYPE)) - new_de->file_type = old_de->file_type; - new_dir->i_version++; - new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, new_dir); - BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata"); - retval = ext3_journal_dirty_metadata(handle, new_bh); - if (retval) - goto journal_error; - brelse(new_bh); - new_bh = NULL; - } - - /* - * Like most other Unix systems, set the ctime for inodes on a - * rename. - */ - old_inode->i_ctime = CURRENT_TIME_SEC; - ext3_mark_inode_dirty(handle, old_inode); - - /* - * ok, that's it - */ - if (le32_to_cpu(old_de->inode) != old_inode->i_ino || - old_de->name_len != old_dentry->d_name.len || - strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || - (retval = ext3_delete_entry(handle, old_dir, - old_de, old_bh)) == -ENOENT) { - /* old_de could have moved from under us during htree split, so - * make sure that we are deleting the right entry. We might - * also be pointing to a stale entry in the unused part of - * old_bh so just checking inum and the name isn't enough. */ - struct buffer_head *old_bh2; - struct ext3_dir_entry_2 *old_de2; - - old_bh2 = ext3_find_entry(old_dir, &old_dentry->d_name, - &old_de2); - if (old_bh2) { - retval = ext3_delete_entry(handle, old_dir, - old_de2, old_bh2); - brelse(old_bh2); - } - } - if (retval) { - ext3_warning(old_dir->i_sb, "ext3_rename", - "Deleting old file (%lu), %d, error=%d", - old_dir->i_ino, old_dir->i_nlink, retval); - } - - if (new_inode) { - drop_nlink(new_inode); - new_inode->i_ctime = CURRENT_TIME_SEC; - } - old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC; - ext3_update_dx_flag(old_dir); - if (dir_bh) { - BUFFER_TRACE(dir_bh, "get_write_access"); - retval = ext3_journal_get_write_access(handle, dir_bh); - if (retval) - goto journal_error; - PARENT_INO(dir_bh->b_data) = cpu_to_le32(new_dir->i_ino); - BUFFER_TRACE(dir_bh, "call ext3_journal_dirty_metadata"); - retval = ext3_journal_dirty_metadata(handle, dir_bh); - if (retval) { -journal_error: - ext3_std_error(new_dir->i_sb, retval); - goto end_rename; - } - drop_nlink(old_dir); - if (new_inode) { - drop_nlink(new_inode); - } else { - inc_nlink(new_dir); - ext3_update_dx_flag(new_dir); - ext3_mark_inode_dirty(handle, new_dir); - } - } - ext3_mark_inode_dirty(handle, old_dir); - if (new_inode) { - ext3_mark_inode_dirty(handle, new_inode); - if (!new_inode->i_nlink) - ext3_orphan_add(handle, new_inode); - if (ext3_should_writeback_data(new_inode)) - flush_file = 1; - } - retval = 0; - -end_rename: - brelse (dir_bh); - brelse (old_bh); - brelse (new_bh); - ext3_journal_stop(handle); - if (retval == 0 && flush_file) - filemap_flush(old_inode->i_mapping); - return retval; -} - -/* - * directories can handle most operations... - */ -const struct inode_operations ext3_dir_inode_operations = { - .create = ext3_create, - .lookup = ext3_lookup, - .link = ext3_link, - .unlink = ext3_unlink, - .symlink = ext3_symlink, - .mkdir = ext3_mkdir, - .rmdir = ext3_rmdir, - .mknod = ext3_mknod, - .tmpfile = ext3_tmpfile, - .rename = ext3_rename, - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, - .removexattr = generic_removexattr, -#endif - .get_acl = ext3_get_acl, - .set_acl = ext3_set_acl, -}; - -const struct inode_operations ext3_special_inode_operations = { - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, - .removexattr = generic_removexattr, -#endif - .get_acl = ext3_get_acl, - .set_acl = ext3_set_acl, -}; diff --git a/fs/ext3/namei.h b/fs/ext3/namei.h deleted file mode 100644 index 46304d8c9f0a0..0000000000000 --- a/fs/ext3/namei.h +++ /dev/null @@ -1,27 +0,0 @@ -/* linux/fs/ext3/namei.h - * - * Copyright (C) 2005 Simtec Electronics - * Ben Dooks - * -*/ - -extern struct dentry *ext3_get_parent(struct dentry *child); - -static inline struct buffer_head *ext3_dir_bread(handle_t *handle, - struct inode *inode, - int block, int create, - int *err) -{ - struct buffer_head *bh; - - bh = ext3_bread(handle, inode, block, create, err); - - if (!bh && !(*err)) { - *err = -EIO; - ext3_error(inode->i_sb, __func__, - "Directory hole detected on inode %lu\n", - inode->i_ino); - return NULL; - } - return bh; -} diff --git a/fs/ext3/resize.c b/fs/ext3/resize.c deleted file mode 100644 index 27105655502cf..0000000000000 --- a/fs/ext3/resize.c +++ /dev/null @@ -1,1117 +0,0 @@ -/* - * linux/fs/ext3/resize.c - * - * Support for resizing an ext3 filesystem while it is mounted. - * - * Copyright (C) 2001, 2002 Andreas Dilger - * - * This could probably be made into a module, because it is not often in use. - */ - - -#define EXT3FS_DEBUG - -#include "ext3.h" - - -#define outside(b, first, last) ((b) < (first) || (b) >= (last)) -#define inside(b, first, last) ((b) >= (first) && (b) < (last)) - -static int verify_group_input(struct super_block *sb, - struct ext3_new_group_data *input) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count); - ext3_fsblk_t end = start + input->blocks_count; - unsigned group = input->group; - ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; - unsigned overhead = ext3_bg_has_super(sb, group) ? - (1 + ext3_bg_num_gdb(sb, group) + - le16_to_cpu(es->s_reserved_gdt_blocks)) : 0; - ext3_fsblk_t metaend = start + overhead; - struct buffer_head *bh = NULL; - ext3_grpblk_t free_blocks_count; - int err = -EINVAL; - - input->free_blocks_count = free_blocks_count = - input->blocks_count - 2 - overhead - sbi->s_itb_per_group; - - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT3-fs: adding %s group %u: %u blocks " - "(%d free, %u reserved)\n", - ext3_bg_has_super(sb, input->group) ? "normal" : - "no-super", input->group, input->blocks_count, - free_blocks_count, input->reserved_blocks); - - if (group != sbi->s_groups_count) - ext3_warning(sb, __func__, - "Cannot add at group %u (only %lu groups)", - input->group, sbi->s_groups_count); - else if ((start - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb)) - ext3_warning(sb, __func__, "Last group not full"); - else if (input->reserved_blocks > input->blocks_count / 5) - ext3_warning(sb, __func__, "Reserved blocks too high (%u)", - input->reserved_blocks); - else if (free_blocks_count < 0) - ext3_warning(sb, __func__, "Bad blocks count %u", - input->blocks_count); - else if (!(bh = sb_bread(sb, end - 1))) - ext3_warning(sb, __func__, - "Cannot read last block ("E3FSBLK")", - end - 1); - else if (outside(input->block_bitmap, start, end)) - ext3_warning(sb, __func__, - "Block bitmap not in group (block %u)", - input->block_bitmap); - else if (outside(input->inode_bitmap, start, end)) - ext3_warning(sb, __func__, - "Inode bitmap not in group (block %u)", - input->inode_bitmap); - else if (outside(input->inode_table, start, end) || - outside(itend - 1, start, end)) - ext3_warning(sb, __func__, - "Inode table not in group (blocks %u-"E3FSBLK")", - input->inode_table, itend - 1); - else if (input->inode_bitmap == input->block_bitmap) - ext3_warning(sb, __func__, - "Block bitmap same as inode bitmap (%u)", - input->block_bitmap); - else if (inside(input->block_bitmap, input->inode_table, itend)) - ext3_warning(sb, __func__, - "Block bitmap (%u) in inode table (%u-"E3FSBLK")", - input->block_bitmap, input->inode_table, itend-1); - else if (inside(input->inode_bitmap, input->inode_table, itend)) - ext3_warning(sb, __func__, - "Inode bitmap (%u) in inode table (%u-"E3FSBLK")", - input->inode_bitmap, input->inode_table, itend-1); - else if (inside(input->block_bitmap, start, metaend)) - ext3_warning(sb, __func__, - "Block bitmap (%u) in GDT table" - " ("E3FSBLK"-"E3FSBLK")", - input->block_bitmap, start, metaend - 1); - else if (inside(input->inode_bitmap, start, metaend)) - ext3_warning(sb, __func__, - "Inode bitmap (%u) in GDT table" - " ("E3FSBLK"-"E3FSBLK")", - input->inode_bitmap, start, metaend - 1); - else if (inside(input->inode_table, start, metaend) || - inside(itend - 1, start, metaend)) - ext3_warning(sb, __func__, - "Inode table (%u-"E3FSBLK") overlaps" - "GDT table ("E3FSBLK"-"E3FSBLK")", - input->inode_table, itend - 1, start, metaend - 1); - else - err = 0; - brelse(bh); - - return err; -} - -static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, - ext3_fsblk_t blk) -{ - struct buffer_head *bh; - int err; - - bh = sb_getblk(sb, blk); - if (unlikely(!bh)) - return ERR_PTR(-ENOMEM); - if ((err = ext3_journal_get_write_access(handle, bh))) { - brelse(bh); - bh = ERR_PTR(err); - } else { - lock_buffer(bh); - memset(bh->b_data, 0, sb->s_blocksize); - set_buffer_uptodate(bh); - unlock_buffer(bh); - } - - return bh; -} - -/* - * To avoid calling the atomic setbit hundreds or thousands of times, we only - * need to use it within a single byte (to ensure we get endianness right). - * We can use memset for the rest of the bitmap as there are no other users. - */ -static void mark_bitmap_end(int start_bit, int end_bit, char *bitmap) -{ - int i; - - if (start_bit >= end_bit) - return; - - ext3_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); - for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) - ext3_set_bit(i, bitmap); - if (i < end_bit) - memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); -} - -/* - * If we have fewer than thresh credits, extend by EXT3_MAX_TRANS_DATA. - * If that fails, restart the transaction & regain write access for the - * buffer head which is used for block_bitmap modifications. - */ -static int extend_or_restart_transaction(handle_t *handle, int thresh, - struct buffer_head *bh) -{ - int err; - - if (handle->h_buffer_credits >= thresh) - return 0; - - err = ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA); - if (err < 0) - return err; - if (err) { - err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA); - if (err) - return err; - err = ext3_journal_get_write_access(handle, bh); - if (err) - return err; - } - - return 0; -} - -/* - * Set up the block and inode bitmaps, and the inode table for the new group. - * This doesn't need to be part of the main transaction, since we are only - * changing blocks outside the actual filesystem. We still do journaling to - * ensure the recovery is correct in case of a failure just after resize. - * If any part of this fails, we simply abort the resize. - */ -static int setup_new_group_blocks(struct super_block *sb, - struct ext3_new_group_data *input) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t start = ext3_group_first_block_no(sb, input->group); - int reserved_gdb = ext3_bg_has_super(sb, input->group) ? - le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) : 0; - unsigned long gdblocks = ext3_bg_num_gdb(sb, input->group); - struct buffer_head *bh; - handle_t *handle; - ext3_fsblk_t block; - ext3_grpblk_t bit; - int i; - int err = 0, err2; - - /* This transaction may be extended/restarted along the way */ - handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); - - if (IS_ERR(handle)) - return PTR_ERR(handle); - - mutex_lock(&sbi->s_resize_lock); - if (input->group != sbi->s_groups_count) { - err = -EBUSY; - goto exit_journal; - } - - if (IS_ERR(bh = bclean(handle, sb, input->block_bitmap))) { - err = PTR_ERR(bh); - goto exit_journal; - } - - if (ext3_bg_has_super(sb, input->group)) { - ext3_debug("mark backup superblock %#04lx (+0)\n", start); - ext3_set_bit(0, bh->b_data); - } - - /* Copy all of the GDT blocks into the backup in this group */ - for (i = 0, bit = 1, block = start + 1; - i < gdblocks; i++, block++, bit++) { - struct buffer_head *gdb; - - ext3_debug("update backup group %#04lx (+%d)\n", block, bit); - - err = extend_or_restart_transaction(handle, 1, bh); - if (err) - goto exit_bh; - - gdb = sb_getblk(sb, block); - if (unlikely(!gdb)) { - err = -ENOMEM; - goto exit_bh; - } - if ((err = ext3_journal_get_write_access(handle, gdb))) { - brelse(gdb); - goto exit_bh; - } - lock_buffer(gdb); - memcpy(gdb->b_data, sbi->s_group_desc[i]->b_data, gdb->b_size); - set_buffer_uptodate(gdb); - unlock_buffer(gdb); - err = ext3_journal_dirty_metadata(handle, gdb); - if (err) { - brelse(gdb); - goto exit_bh; - } - ext3_set_bit(bit, bh->b_data); - brelse(gdb); - } - - /* Zero out all of the reserved backup group descriptor table blocks */ - for (i = 0, bit = gdblocks + 1, block = start + bit; - i < reserved_gdb; i++, block++, bit++) { - struct buffer_head *gdb; - - ext3_debug("clear reserved block %#04lx (+%d)\n", block, bit); - - err = extend_or_restart_transaction(handle, 1, bh); - if (err) - goto exit_bh; - - if (IS_ERR(gdb = bclean(handle, sb, block))) { - err = PTR_ERR(gdb); - goto exit_bh; - } - err = ext3_journal_dirty_metadata(handle, gdb); - if (err) { - brelse(gdb); - goto exit_bh; - } - ext3_set_bit(bit, bh->b_data); - brelse(gdb); - } - ext3_debug("mark block bitmap %#04x (+%ld)\n", input->block_bitmap, - input->block_bitmap - start); - ext3_set_bit(input->block_bitmap - start, bh->b_data); - ext3_debug("mark inode bitmap %#04x (+%ld)\n", input->inode_bitmap, - input->inode_bitmap - start); - ext3_set_bit(input->inode_bitmap - start, bh->b_data); - - /* Zero out all of the inode table blocks */ - for (i = 0, block = input->inode_table, bit = block - start; - i < sbi->s_itb_per_group; i++, bit++, block++) { - struct buffer_head *it; - - ext3_debug("clear inode block %#04lx (+%d)\n", block, bit); - - err = extend_or_restart_transaction(handle, 1, bh); - if (err) - goto exit_bh; - - if (IS_ERR(it = bclean(handle, sb, block))) { - err = PTR_ERR(it); - goto exit_bh; - } - err = ext3_journal_dirty_metadata(handle, it); - if (err) { - brelse(it); - goto exit_bh; - } - brelse(it); - ext3_set_bit(bit, bh->b_data); - } - - err = extend_or_restart_transaction(handle, 2, bh); - if (err) - goto exit_bh; - - mark_bitmap_end(input->blocks_count, EXT3_BLOCKS_PER_GROUP(sb), - bh->b_data); - err = ext3_journal_dirty_metadata(handle, bh); - if (err) - goto exit_bh; - brelse(bh); - - /* Mark unused entries in inode bitmap used */ - ext3_debug("clear inode bitmap %#04x (+%ld)\n", - input->inode_bitmap, input->inode_bitmap - start); - if (IS_ERR(bh = bclean(handle, sb, input->inode_bitmap))) { - err = PTR_ERR(bh); - goto exit_journal; - } - - mark_bitmap_end(EXT3_INODES_PER_GROUP(sb), EXT3_BLOCKS_PER_GROUP(sb), - bh->b_data); - err = ext3_journal_dirty_metadata(handle, bh); -exit_bh: - brelse(bh); - -exit_journal: - mutex_unlock(&sbi->s_resize_lock); - if ((err2 = ext3_journal_stop(handle)) && !err) - err = err2; - - return err; -} - -/* - * Iterate through the groups which hold BACKUP superblock/GDT copies in an - * ext3 filesystem. The counters should be initialized to 1, 5, and 7 before - * calling this for the first time. In a sparse filesystem it will be the - * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... - * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... - */ -static unsigned ext3_list_backups(struct super_block *sb, unsigned *three, - unsigned *five, unsigned *seven) -{ - unsigned *min = three; - int mult = 3; - unsigned ret; - - if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { - ret = *min; - *min += 1; - return ret; - } - - if (*five < *min) { - min = five; - mult = 5; - } - if (*seven < *min) { - min = seven; - mult = 7; - } - - ret = *min; - *min *= mult; - - return ret; -} - -/* - * Check that all of the backup GDT blocks are held in the primary GDT block. - * It is assumed that they are stored in group order. Returns the number of - * groups in current filesystem that have BACKUPS, or -ve error code. - */ -static int verify_reserved_gdb(struct super_block *sb, - struct buffer_head *primary) -{ - const ext3_fsblk_t blk = primary->b_blocknr; - const unsigned long end = EXT3_SB(sb)->s_groups_count; - unsigned three = 1; - unsigned five = 5; - unsigned seven = 7; - unsigned grp; - __le32 *p = (__le32 *)primary->b_data; - int gdbackups = 0; - - while ((grp = ext3_list_backups(sb, &three, &five, &seven)) < end) { - if (le32_to_cpu(*p++) != grp * EXT3_BLOCKS_PER_GROUP(sb) + blk){ - ext3_warning(sb, __func__, - "reserved GDT "E3FSBLK - " missing grp %d ("E3FSBLK")", - blk, grp, - grp * EXT3_BLOCKS_PER_GROUP(sb) + blk); - return -EINVAL; - } - if (++gdbackups > EXT3_ADDR_PER_BLOCK(sb)) - return -EFBIG; - } - - return gdbackups; -} - -/* - * Called when we need to bring a reserved group descriptor table block into - * use from the resize inode. The primary copy of the new GDT block currently - * is an indirect block (under the double indirect block in the resize inode). - * The new backup GDT blocks will be stored as leaf blocks in this indirect - * block, in group order. Even though we know all the block numbers we need, - * we check to ensure that the resize inode has actually reserved these blocks. - * - * Don't need to update the block bitmaps because the blocks are still in use. - * - * We get all of the error cases out of the way, so that we are sure to not - * fail once we start modifying the data on disk, because JBD has no rollback. - */ -static int add_new_gdb(handle_t *handle, struct inode *inode, - struct ext3_new_group_data *input, - struct buffer_head **primary) -{ - struct super_block *sb = inode->i_sb; - struct ext3_super_block *es = EXT3_SB(sb)->s_es; - unsigned long gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); - ext3_fsblk_t gdblock = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; - struct buffer_head **o_group_desc, **n_group_desc; - struct buffer_head *dind; - int gdbackups; - struct ext3_iloc iloc; - __le32 *data; - int err; - - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG - "EXT3-fs: ext3_add_new_gdb: adding group block %lu\n", - gdb_num); - - /* - * If we are not using the primary superblock/GDT copy don't resize, - * because the user tools have no way of handling this. Probably a - * bad time to do it anyways. - */ - if (EXT3_SB(sb)->s_sbh->b_blocknr != - le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block)) { - ext3_warning(sb, __func__, - "won't resize using backup superblock at %llu", - (unsigned long long)EXT3_SB(sb)->s_sbh->b_blocknr); - return -EPERM; - } - - *primary = sb_bread(sb, gdblock); - if (!*primary) - return -EIO; - - if ((gdbackups = verify_reserved_gdb(sb, *primary)) < 0) { - err = gdbackups; - goto exit_bh; - } - - data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; - dind = sb_bread(sb, le32_to_cpu(*data)); - if (!dind) { - err = -EIO; - goto exit_bh; - } - - data = (__le32 *)dind->b_data; - if (le32_to_cpu(data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)]) != gdblock) { - ext3_warning(sb, __func__, - "new group %u GDT block "E3FSBLK" not reserved", - input->group, gdblock); - err = -EINVAL; - goto exit_dind; - } - - if ((err = ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh))) - goto exit_dind; - - if ((err = ext3_journal_get_write_access(handle, *primary))) - goto exit_sbh; - - if ((err = ext3_journal_get_write_access(handle, dind))) - goto exit_primary; - - /* ext3_reserve_inode_write() gets a reference on the iloc */ - if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) - goto exit_dindj; - - n_group_desc = kmalloc((gdb_num + 1) * sizeof(struct buffer_head *), - GFP_NOFS); - if (!n_group_desc) { - err = -ENOMEM; - ext3_warning (sb, __func__, - "not enough memory for %lu groups", gdb_num + 1); - goto exit_inode; - } - - /* - * Finally, we have all of the possible failures behind us... - * - * Remove new GDT block from inode double-indirect block and clear out - * the new GDT block for use (which also "frees" the backup GDT blocks - * from the reserved inode). We don't need to change the bitmaps for - * these blocks, because they are marked as in-use from being in the - * reserved inode, and will become GDT blocks (primary and backup). - */ - data[gdb_num % EXT3_ADDR_PER_BLOCK(sb)] = 0; - err = ext3_journal_dirty_metadata(handle, dind); - if (err) - goto exit_group_desc; - brelse(dind); - dind = NULL; - inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; - err = ext3_mark_iloc_dirty(handle, inode, &iloc); - if (err) - goto exit_group_desc; - memset((*primary)->b_data, 0, sb->s_blocksize); - err = ext3_journal_dirty_metadata(handle, *primary); - if (err) - goto exit_group_desc; - - o_group_desc = EXT3_SB(sb)->s_group_desc; - memcpy(n_group_desc, o_group_desc, - EXT3_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); - n_group_desc[gdb_num] = *primary; - EXT3_SB(sb)->s_group_desc = n_group_desc; - EXT3_SB(sb)->s_gdb_count++; - kfree(o_group_desc); - - le16_add_cpu(&es->s_reserved_gdt_blocks, -1); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - if (err) - goto exit_inode; - - return 0; - -exit_group_desc: - kfree(n_group_desc); -exit_inode: - //ext3_journal_release_buffer(handle, iloc.bh); - brelse(iloc.bh); -exit_dindj: - //ext3_journal_release_buffer(handle, dind); -exit_primary: - //ext3_journal_release_buffer(handle, *primary); -exit_sbh: - //ext3_journal_release_buffer(handle, *primary); -exit_dind: - brelse(dind); -exit_bh: - brelse(*primary); - - ext3_debug("leaving with error %d\n", err); - return err; -} - -/* - * Called when we are adding a new group which has a backup copy of each of - * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. - * We need to add these reserved backup GDT blocks to the resize inode, so - * that they are kept for future resizing and not allocated to files. - * - * Each reserved backup GDT block will go into a different indirect block. - * The indirect blocks are actually the primary reserved GDT blocks, - * so we know in advance what their block numbers are. We only get the - * double-indirect block to verify it is pointing to the primary reserved - * GDT blocks so we don't overwrite a data block by accident. The reserved - * backup GDT blocks are stored in their reserved primary GDT block. - */ -static int reserve_backup_gdb(handle_t *handle, struct inode *inode, - struct ext3_new_group_data *input) -{ - struct super_block *sb = inode->i_sb; - int reserved_gdb =le16_to_cpu(EXT3_SB(sb)->s_es->s_reserved_gdt_blocks); - struct buffer_head **primary; - struct buffer_head *dind; - struct ext3_iloc iloc; - ext3_fsblk_t blk; - __le32 *data, *end; - int gdbackups = 0; - int res, i; - int err; - - primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS); - if (!primary) - return -ENOMEM; - - data = EXT3_I(inode)->i_data + EXT3_DIND_BLOCK; - dind = sb_bread(sb, le32_to_cpu(*data)); - if (!dind) { - err = -EIO; - goto exit_free; - } - - blk = EXT3_SB(sb)->s_sbh->b_blocknr + 1 + EXT3_SB(sb)->s_gdb_count; - data = (__le32 *)dind->b_data + (EXT3_SB(sb)->s_gdb_count % - EXT3_ADDR_PER_BLOCK(sb)); - end = (__le32 *)dind->b_data + EXT3_ADDR_PER_BLOCK(sb); - - /* Get each reserved primary GDT block and verify it holds backups */ - for (res = 0; res < reserved_gdb; res++, blk++) { - if (le32_to_cpu(*data) != blk) { - ext3_warning(sb, __func__, - "reserved block "E3FSBLK - " not at offset %ld", - blk, - (long)(data - (__le32 *)dind->b_data)); - err = -EINVAL; - goto exit_bh; - } - primary[res] = sb_bread(sb, blk); - if (!primary[res]) { - err = -EIO; - goto exit_bh; - } - if ((gdbackups = verify_reserved_gdb(sb, primary[res])) < 0) { - brelse(primary[res]); - err = gdbackups; - goto exit_bh; - } - if (++data >= end) - data = (__le32 *)dind->b_data; - } - - for (i = 0; i < reserved_gdb; i++) { - if ((err = ext3_journal_get_write_access(handle, primary[i]))) { - /* - int j; - for (j = 0; j < i; j++) - ext3_journal_release_buffer(handle, primary[j]); - */ - goto exit_bh; - } - } - - if ((err = ext3_reserve_inode_write(handle, inode, &iloc))) - goto exit_bh; - - /* - * Finally we can add each of the reserved backup GDT blocks from - * the new group to its reserved primary GDT block. - */ - blk = input->group * EXT3_BLOCKS_PER_GROUP(sb); - for (i = 0; i < reserved_gdb; i++) { - int err2; - data = (__le32 *)primary[i]->b_data; - /* printk("reserving backup %lu[%u] = %lu\n", - primary[i]->b_blocknr, gdbackups, - blk + primary[i]->b_blocknr); */ - data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); - err2 = ext3_journal_dirty_metadata(handle, primary[i]); - if (!err) - err = err2; - } - inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; - ext3_mark_iloc_dirty(handle, inode, &iloc); - -exit_bh: - while (--res >= 0) - brelse(primary[res]); - brelse(dind); - -exit_free: - kfree(primary); - - return err; -} - -/* - * Update the backup copies of the ext3 metadata. These don't need to be part - * of the main resize transaction, because e2fsck will re-write them if there - * is a problem (basically only OOM will cause a problem). However, we - * _should_ update the backups if possible, in case the primary gets trashed - * for some reason and we need to run e2fsck from a backup superblock. The - * important part is that the new block and inode counts are in the backup - * superblocks, and the location of the new group metadata in the GDT backups. - * - * We do not need take the s_resize_lock for this, because these - * blocks are not otherwise touched by the filesystem code when it is - * mounted. We don't need to worry about last changing from - * sbi->s_groups_count, because the worst that can happen is that we - * do not copy the full number of backups at this time. The resize - * which changed s_groups_count will backup again. - */ -static void update_backups(struct super_block *sb, - int blk_off, char *data, int size) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - const unsigned long last = sbi->s_groups_count; - const int bpg = EXT3_BLOCKS_PER_GROUP(sb); - unsigned three = 1; - unsigned five = 5; - unsigned seven = 7; - unsigned group; - int rest = sb->s_blocksize - size; - handle_t *handle; - int err = 0, err2; - - handle = ext3_journal_start_sb(sb, EXT3_MAX_TRANS_DATA); - if (IS_ERR(handle)) { - group = 1; - err = PTR_ERR(handle); - goto exit_err; - } - - while ((group = ext3_list_backups(sb, &three, &five, &seven)) < last) { - struct buffer_head *bh; - - /* Out of journal space, and can't get more - abort - so sad */ - if (handle->h_buffer_credits == 0 && - ext3_journal_extend(handle, EXT3_MAX_TRANS_DATA) && - (err = ext3_journal_restart(handle, EXT3_MAX_TRANS_DATA))) - break; - - bh = sb_getblk(sb, group * bpg + blk_off); - if (unlikely(!bh)) { - err = -ENOMEM; - break; - } - ext3_debug("update metadata backup %#04lx\n", - (unsigned long)bh->b_blocknr); - if ((err = ext3_journal_get_write_access(handle, bh))) { - brelse(bh); - break; - } - lock_buffer(bh); - memcpy(bh->b_data, data, size); - if (rest) - memset(bh->b_data + size, 0, rest); - set_buffer_uptodate(bh); - unlock_buffer(bh); - err = ext3_journal_dirty_metadata(handle, bh); - brelse(bh); - if (err) - break; - } - if ((err2 = ext3_journal_stop(handle)) && !err) - err = err2; - - /* - * Ugh! Need to have e2fsck write the backup copies. It is too - * late to revert the resize, we shouldn't fail just because of - * the backup copies (they are only needed in case of corruption). - * - * However, if we got here we have a journal problem too, so we - * can't really start a transaction to mark the superblock. - * Chicken out and just set the flag on the hope it will be written - * to disk, and if not - we will simply wait until next fsck. - */ -exit_err: - if (err) { - ext3_warning(sb, __func__, - "can't update backup for group %d (err %d), " - "forcing fsck on next reboot", group, err); - sbi->s_mount_state &= ~EXT3_VALID_FS; - sbi->s_es->s_state &= cpu_to_le16(~EXT3_VALID_FS); - mark_buffer_dirty(sbi->s_sbh); - } -} - -/* Add group descriptor data to an existing or new group descriptor block. - * Ensure we handle all possible error conditions _before_ we start modifying - * the filesystem, because we cannot abort the transaction and not have it - * write the data to disk. - * - * If we are on a GDT block boundary, we need to get the reserved GDT block. - * Otherwise, we may need to add backup GDT blocks for a sparse group. - * - * We only need to hold the superblock lock while we are actually adding - * in the new group's counts to the superblock. Prior to that we have - * not really "added" the group at all. We re-check that we are still - * adding in the last group in case things have changed since verifying. - */ -int ext3_group_add(struct super_block *sb, struct ext3_new_group_data *input) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - int reserved_gdb = ext3_bg_has_super(sb, input->group) ? - le16_to_cpu(es->s_reserved_gdt_blocks) : 0; - struct buffer_head *primary = NULL; - struct ext3_group_desc *gdp; - struct inode *inode = NULL; - handle_t *handle; - int gdb_off, gdb_num; - int err, err2; - - gdb_num = input->group / EXT3_DESC_PER_BLOCK(sb); - gdb_off = input->group % EXT3_DESC_PER_BLOCK(sb); - - if (gdb_off == 0 && !EXT3_HAS_RO_COMPAT_FEATURE(sb, - EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER)) { - ext3_warning(sb, __func__, - "Can't resize non-sparse filesystem further"); - return -EPERM; - } - - if (le32_to_cpu(es->s_blocks_count) + input->blocks_count < - le32_to_cpu(es->s_blocks_count)) { - ext3_warning(sb, __func__, "blocks_count overflow\n"); - return -EINVAL; - } - - if (le32_to_cpu(es->s_inodes_count) + EXT3_INODES_PER_GROUP(sb) < - le32_to_cpu(es->s_inodes_count)) { - ext3_warning(sb, __func__, "inodes_count overflow\n"); - return -EINVAL; - } - - if (reserved_gdb || gdb_off == 0) { - if (!EXT3_HAS_COMPAT_FEATURE(sb, - EXT3_FEATURE_COMPAT_RESIZE_INODE) - || !le16_to_cpu(es->s_reserved_gdt_blocks)) { - ext3_warning(sb, __func__, - "No reserved GDT blocks, can't resize"); - return -EPERM; - } - inode = ext3_iget(sb, EXT3_RESIZE_INO); - if (IS_ERR(inode)) { - ext3_warning(sb, __func__, - "Error opening resize inode"); - return PTR_ERR(inode); - } - } - - if ((err = verify_group_input(sb, input))) - goto exit_put; - - if ((err = setup_new_group_blocks(sb, input))) - goto exit_put; - - /* - * We will always be modifying at least the superblock and a GDT - * block. If we are adding a group past the last current GDT block, - * we will also modify the inode and the dindirect block. If we - * are adding a group with superblock/GDT backups we will also - * modify each of the reserved GDT dindirect blocks. - */ - handle = ext3_journal_start_sb(sb, - ext3_bg_has_super(sb, input->group) ? - 3 + reserved_gdb : 4); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto exit_put; - } - - mutex_lock(&sbi->s_resize_lock); - if (input->group != sbi->s_groups_count) { - ext3_warning(sb, __func__, - "multiple resizers run on filesystem!"); - err = -EBUSY; - goto exit_journal; - } - - if ((err = ext3_journal_get_write_access(handle, sbi->s_sbh))) - goto exit_journal; - - /* - * We will only either add reserved group blocks to a backup group - * or remove reserved blocks for the first group in a new group block. - * Doing both would be mean more complex code, and sane people don't - * use non-sparse filesystems anymore. This is already checked above. - */ - if (gdb_off) { - primary = sbi->s_group_desc[gdb_num]; - if ((err = ext3_journal_get_write_access(handle, primary))) - goto exit_journal; - - if (reserved_gdb && ext3_bg_num_gdb(sb, input->group) && - (err = reserve_backup_gdb(handle, inode, input))) - goto exit_journal; - } else if ((err = add_new_gdb(handle, inode, input, &primary))) - goto exit_journal; - - /* - * OK, now we've set up the new group. Time to make it active. - * - * We do not lock all allocations via s_resize_lock - * so we have to be safe wrt. concurrent accesses the group - * data. So we need to be careful to set all of the relevant - * group descriptor data etc. *before* we enable the group. - * - * The key field here is sbi->s_groups_count: as long as - * that retains its old value, nobody is going to access the new - * group. - * - * So first we update all the descriptor metadata for the new - * group; then we update the total disk blocks count; then we - * update the groups count to enable the group; then finally we - * update the free space counts so that the system can start - * using the new disk blocks. - */ - - /* Update group descriptor block for new group */ - gdp = (struct ext3_group_desc *)primary->b_data + gdb_off; - - gdp->bg_block_bitmap = cpu_to_le32(input->block_bitmap); - gdp->bg_inode_bitmap = cpu_to_le32(input->inode_bitmap); - gdp->bg_inode_table = cpu_to_le32(input->inode_table); - gdp->bg_free_blocks_count = cpu_to_le16(input->free_blocks_count); - gdp->bg_free_inodes_count = cpu_to_le16(EXT3_INODES_PER_GROUP(sb)); - - /* - * Make the new blocks and inodes valid next. We do this before - * increasing the group count so that once the group is enabled, - * all of its blocks and inodes are already valid. - * - * We always allocate group-by-group, then block-by-block or - * inode-by-inode within a group, so enabling these - * blocks/inodes before the group is live won't actually let us - * allocate the new space yet. - */ - le32_add_cpu(&es->s_blocks_count, input->blocks_count); - le32_add_cpu(&es->s_inodes_count, EXT3_INODES_PER_GROUP(sb)); - - /* - * We need to protect s_groups_count against other CPUs seeing - * inconsistent state in the superblock. - * - * The precise rules we use are: - * - * * Writers of s_groups_count *must* hold s_resize_lock - * AND - * * Writers must perform a smp_wmb() after updating all dependent - * data and before modifying the groups count - * - * * Readers must hold s_resize_lock over the access - * OR - * * Readers must perform an smp_rmb() after reading the groups count - * and before reading any dependent data. - * - * NB. These rules can be relaxed when checking the group count - * while freeing data, as we can only allocate from a block - * group after serialising against the group count, and we can - * only then free after serialising in turn against that - * allocation. - */ - smp_wmb(); - - /* Update the global fs size fields */ - sbi->s_groups_count++; - - err = ext3_journal_dirty_metadata(handle, primary); - if (err) - goto exit_journal; - - /* Update the reserved block counts only once the new group is - * active. */ - le32_add_cpu(&es->s_r_blocks_count, input->reserved_blocks); - - /* Update the free space counts */ - percpu_counter_add(&sbi->s_freeblocks_counter, - input->free_blocks_count); - percpu_counter_add(&sbi->s_freeinodes_counter, - EXT3_INODES_PER_GROUP(sb)); - - err = ext3_journal_dirty_metadata(handle, sbi->s_sbh); - -exit_journal: - mutex_unlock(&sbi->s_resize_lock); - if ((err2 = ext3_journal_stop(handle)) && !err) - err = err2; - if (!err) { - update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, - sizeof(struct ext3_super_block)); - update_backups(sb, primary->b_blocknr, primary->b_data, - primary->b_size); - } -exit_put: - iput(inode); - return err; -} /* ext3_group_add */ - -/* Extend the filesystem to the new number of blocks specified. This entry - * point is only used to extend the current filesystem to the end of the last - * existing group. It can be accessed via ioctl, or by "remount,resize=" - * for emergencies (because it has no dependencies on reserved blocks). - * - * If we _really_ wanted, we could use default values to call ext3_group_add() - * allow the "remount" trick to work for arbitrary resizing, assuming enough - * GDT blocks are reserved to grow to the desired size. - */ -int ext3_group_extend(struct super_block *sb, struct ext3_super_block *es, - ext3_fsblk_t n_blocks_count) -{ - ext3_fsblk_t o_blocks_count; - ext3_grpblk_t last; - ext3_grpblk_t add; - struct buffer_head * bh; - handle_t *handle; - int err; - unsigned long freed_blocks; - - /* We don't need to worry about locking wrt other resizers just - * yet: we're going to revalidate es->s_blocks_count after - * taking the s_resize_lock below. */ - o_blocks_count = le32_to_cpu(es->s_blocks_count); - - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT3-fs: extending last group from "E3FSBLK - " up to "E3FSBLK" blocks\n", - o_blocks_count, n_blocks_count); - - if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) - return 0; - - if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { - printk(KERN_ERR "EXT3-fs: filesystem on %s:" - " too large to resize to "E3FSBLK" blocks safely\n", - sb->s_id, n_blocks_count); - if (sizeof(sector_t) < 8) - ext3_warning(sb, __func__, - "CONFIG_LBDAF not enabled\n"); - return -EINVAL; - } - - if (n_blocks_count < o_blocks_count) { - ext3_warning(sb, __func__, - "can't shrink FS - resize aborted"); - return -EBUSY; - } - - /* Handle the remaining blocks in the last group only. */ - last = (o_blocks_count - le32_to_cpu(es->s_first_data_block)) % - EXT3_BLOCKS_PER_GROUP(sb); - - if (last == 0) { - ext3_warning(sb, __func__, - "need to use ext2online to resize further"); - return -EPERM; - } - - add = EXT3_BLOCKS_PER_GROUP(sb) - last; - - if (o_blocks_count + add < o_blocks_count) { - ext3_warning(sb, __func__, "blocks_count overflow"); - return -EINVAL; - } - - if (o_blocks_count + add > n_blocks_count) - add = n_blocks_count - o_blocks_count; - - if (o_blocks_count + add < n_blocks_count) - ext3_warning(sb, __func__, - "will only finish group ("E3FSBLK - " blocks, %u new)", - o_blocks_count + add, add); - - /* See if the device is actually as big as what was requested */ - bh = sb_bread(sb, o_blocks_count + add -1); - if (!bh) { - ext3_warning(sb, __func__, - "can't read last block, resize aborted"); - return -ENOSPC; - } - brelse(bh); - - /* We will update the superblock, one block bitmap, and - * one group descriptor via ext3_free_blocks(). - */ - handle = ext3_journal_start_sb(sb, 3); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - ext3_warning(sb, __func__, "error %d on journal start",err); - goto exit_put; - } - - mutex_lock(&EXT3_SB(sb)->s_resize_lock); - if (o_blocks_count != le32_to_cpu(es->s_blocks_count)) { - ext3_warning(sb, __func__, - "multiple resizers run on filesystem!"); - mutex_unlock(&EXT3_SB(sb)->s_resize_lock); - ext3_journal_stop(handle); - err = -EBUSY; - goto exit_put; - } - - if ((err = ext3_journal_get_write_access(handle, - EXT3_SB(sb)->s_sbh))) { - ext3_warning(sb, __func__, - "error %d on journal write access", err); - mutex_unlock(&EXT3_SB(sb)->s_resize_lock); - ext3_journal_stop(handle); - goto exit_put; - } - es->s_blocks_count = cpu_to_le32(o_blocks_count + add); - err = ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - mutex_unlock(&EXT3_SB(sb)->s_resize_lock); - if (err) { - ext3_warning(sb, __func__, - "error %d on journal dirty metadata", err); - ext3_journal_stop(handle); - goto exit_put; - } - ext3_debug("freeing blocks "E3FSBLK" through "E3FSBLK"\n", - o_blocks_count, o_blocks_count + add); - ext3_free_blocks_sb(handle, sb, o_blocks_count, add, &freed_blocks); - ext3_debug("freed blocks "E3FSBLK" through "E3FSBLK"\n", - o_blocks_count, o_blocks_count + add); - if ((err = ext3_journal_stop(handle))) - goto exit_put; - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT3-fs: extended group to %u blocks\n", - le32_to_cpu(es->s_blocks_count)); - update_backups(sb, EXT3_SB(sb)->s_sbh->b_blocknr, (char *)es, - sizeof(struct ext3_super_block)); -exit_put: - return err; -} /* ext3_group_extend */ diff --git a/fs/ext3/super.c b/fs/ext3/super.c deleted file mode 100644 index 5ed0044fbb377..0000000000000 --- a/fs/ext3/super.c +++ /dev/null @@ -1,3165 +0,0 @@ -/* - * linux/fs/ext3/super.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define CREATE_TRACE_POINTS - -#include "ext3.h" -#include "xattr.h" -#include "acl.h" -#include "namei.h" - -#ifdef CONFIG_EXT3_DEFAULTS_TO_ORDERED - #define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_ORDERED_DATA -#else - #define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_WRITEBACK_DATA -#endif - -static int ext3_load_journal(struct super_block *, struct ext3_super_block *, - unsigned long journal_devnum); -static int ext3_create_journal(struct super_block *, struct ext3_super_block *, - unsigned int); -static int ext3_commit_super(struct super_block *sb, - struct ext3_super_block *es, - int sync); -static void ext3_mark_recovery_complete(struct super_block * sb, - struct ext3_super_block * es); -static void ext3_clear_journal_err(struct super_block * sb, - struct ext3_super_block * es); -static int ext3_sync_fs(struct super_block *sb, int wait); -static const char *ext3_decode_error(struct super_block * sb, int errno, - char nbuf[16]); -static int ext3_remount (struct super_block * sb, int * flags, char * data); -static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf); -static int ext3_unfreeze(struct super_block *sb); -static int ext3_freeze(struct super_block *sb); - -/* - * Wrappers for journal_start/end. - */ -handle_t *ext3_journal_start_sb(struct super_block *sb, int nblocks) -{ - journal_t *journal; - - if (sb->s_flags & MS_RDONLY) - return ERR_PTR(-EROFS); - - /* Special case here: if the journal has aborted behind our - * backs (eg. EIO in the commit thread), then we still need to - * take the FS itself readonly cleanly. */ - journal = EXT3_SB(sb)->s_journal; - if (is_journal_aborted(journal)) { - ext3_abort(sb, __func__, - "Detected aborted journal"); - return ERR_PTR(-EROFS); - } - - return journal_start(journal, nblocks); -} - -int __ext3_journal_stop(const char *where, handle_t *handle) -{ - struct super_block *sb; - int err; - int rc; - - sb = handle->h_transaction->t_journal->j_private; - err = handle->h_err; - rc = journal_stop(handle); - - if (!err) - err = rc; - if (err) - __ext3_std_error(sb, where, err); - return err; -} - -void ext3_journal_abort_handle(const char *caller, const char *err_fn, - struct buffer_head *bh, handle_t *handle, int err) -{ - char nbuf[16]; - const char *errstr = ext3_decode_error(NULL, err, nbuf); - - if (bh) - BUFFER_TRACE(bh, "abort"); - - if (!handle->h_err) - handle->h_err = err; - - if (is_handle_aborted(handle)) - return; - - printk(KERN_ERR "EXT3-fs: %s: aborting transaction: %s in %s\n", - caller, errstr, err_fn); - - journal_abort_handle(handle); -} - -void ext3_msg(struct super_block *sb, const char *prefix, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk("%sEXT3-fs (%s): %pV\n", prefix, sb->s_id, &vaf); - - va_end(args); -} - -/* Deal with the reporting of failure conditions on a filesystem such as - * inconsistencies detected or read IO failures. - * - * On ext2, we can store the error state of the filesystem in the - * superblock. That is not possible on ext3, because we may have other - * write ordering constraints on the superblock which prevent us from - * writing it out straight away; and given that the journal is about to - * be aborted, we can't rely on the current, or future, transactions to - * write out the superblock safely. - * - * We'll just use the journal_abort() error code to record an error in - * the journal instead. On recovery, the journal will complain about - * that error until we've noted it down and cleared it. - */ - -static void ext3_handle_error(struct super_block *sb) -{ - struct ext3_super_block *es = EXT3_SB(sb)->s_es; - - EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; - es->s_state |= cpu_to_le16(EXT3_ERROR_FS); - - if (sb->s_flags & MS_RDONLY) - return; - - if (!test_opt (sb, ERRORS_CONT)) { - journal_t *journal = EXT3_SB(sb)->s_journal; - - set_opt(EXT3_SB(sb)->s_mount_opt, ABORT); - if (journal) - journal_abort(journal, -EIO); - } - if (test_opt (sb, ERRORS_RO)) { - ext3_msg(sb, KERN_CRIT, - "error: remounting filesystem read-only"); - /* - * Make sure updated value of ->s_mount_state will be visible - * before ->s_flags update. - */ - smp_wmb(); - sb->s_flags |= MS_RDONLY; - } - ext3_commit_super(sb, es, 1); - if (test_opt(sb, ERRORS_PANIC)) - panic("EXT3-fs (%s): panic forced after error\n", - sb->s_id); -} - -void ext3_error(struct super_block *sb, const char *function, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk(KERN_CRIT "EXT3-fs error (device %s): %s: %pV\n", - sb->s_id, function, &vaf); - - va_end(args); - - ext3_handle_error(sb); -} - -static const char *ext3_decode_error(struct super_block * sb, int errno, - char nbuf[16]) -{ - char *errstr = NULL; - - switch (errno) { - case -EIO: - errstr = "IO failure"; - break; - case -ENOMEM: - errstr = "Out of memory"; - break; - case -EROFS: - if (!sb || EXT3_SB(sb)->s_journal->j_flags & JFS_ABORT) - errstr = "Journal has aborted"; - else - errstr = "Readonly filesystem"; - break; - default: - /* If the caller passed in an extra buffer for unknown - * errors, textualise them now. Else we just return - * NULL. */ - if (nbuf) { - /* Check for truncated error codes... */ - if (snprintf(nbuf, 16, "error %d", -errno) >= 0) - errstr = nbuf; - } - break; - } - - return errstr; -} - -/* __ext3_std_error decodes expected errors from journaling functions - * automatically and invokes the appropriate error response. */ - -void __ext3_std_error (struct super_block * sb, const char * function, - int errno) -{ - char nbuf[16]; - const char *errstr; - - /* Special case: if the error is EROFS, and we're not already - * inside a transaction, then there's really no point in logging - * an error. */ - if (errno == -EROFS && journal_current_handle() == NULL && - (sb->s_flags & MS_RDONLY)) - return; - - errstr = ext3_decode_error(sb, errno, nbuf); - ext3_msg(sb, KERN_CRIT, "error in %s: %s", function, errstr); - - ext3_handle_error(sb); -} - -/* - * ext3_abort is a much stronger failure handler than ext3_error. The - * abort function may be used to deal with unrecoverable failures such - * as journal IO errors or ENOMEM at a critical moment in log management. - * - * We unconditionally force the filesystem into an ABORT|READONLY state, - * unless the error response on the fs has been set to panic in which - * case we take the easy way out and panic immediately. - */ - -void ext3_abort(struct super_block *sb, const char *function, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk(KERN_CRIT "EXT3-fs (%s): error: %s: %pV\n", - sb->s_id, function, &vaf); - - va_end(args); - - if (test_opt(sb, ERRORS_PANIC)) - panic("EXT3-fs: panic from previous error\n"); - - if (sb->s_flags & MS_RDONLY) - return; - - ext3_msg(sb, KERN_CRIT, - "error: remounting filesystem read-only"); - EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; - set_opt(EXT3_SB(sb)->s_mount_opt, ABORT); - /* - * Make sure updated value of ->s_mount_state will be visible - * before ->s_flags update. - */ - smp_wmb(); - sb->s_flags |= MS_RDONLY; - - if (EXT3_SB(sb)->s_journal) - journal_abort(EXT3_SB(sb)->s_journal, -EIO); -} - -void ext3_warning(struct super_block *sb, const char *function, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - printk(KERN_WARNING "EXT3-fs (%s): warning: %s: %pV\n", - sb->s_id, function, &vaf); - - va_end(args); -} - -void ext3_update_dynamic_rev(struct super_block *sb) -{ - struct ext3_super_block *es = EXT3_SB(sb)->s_es; - - if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) - return; - - ext3_msg(sb, KERN_WARNING, - "warning: updating to rev %d because of " - "new feature flag, running e2fsck is recommended", - EXT3_DYNAMIC_REV); - - es->s_first_ino = cpu_to_le32(EXT3_GOOD_OLD_FIRST_INO); - es->s_inode_size = cpu_to_le16(EXT3_GOOD_OLD_INODE_SIZE); - es->s_rev_level = cpu_to_le32(EXT3_DYNAMIC_REV); - /* leave es->s_feature_*compat flags alone */ - /* es->s_uuid will be set by e2fsck if empty */ - - /* - * The rest of the superblock fields should be zero, and if not it - * means they are likely already in use, so leave them alone. We - * can leave it up to e2fsck to clean up any inconsistencies there. - */ -} - -/* - * Open the external journal device - */ -static struct block_device *ext3_blkdev_get(dev_t dev, struct super_block *sb) -{ - struct block_device *bdev; - char b[BDEVNAME_SIZE]; - - bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); - if (IS_ERR(bdev)) - goto fail; - return bdev; - -fail: - ext3_msg(sb, KERN_ERR, "error: failed to open journal device %s: %ld", - __bdevname(dev, b), PTR_ERR(bdev)); - - return NULL; -} - -/* - * Release the journal device - */ -static void ext3_blkdev_put(struct block_device *bdev) -{ - blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); -} - -static void ext3_blkdev_remove(struct ext3_sb_info *sbi) -{ - struct block_device *bdev; - bdev = sbi->journal_bdev; - if (bdev) { - ext3_blkdev_put(bdev); - sbi->journal_bdev = NULL; - } -} - -static inline struct inode *orphan_list_entry(struct list_head *l) -{ - return &list_entry(l, struct ext3_inode_info, i_orphan)->vfs_inode; -} - -static void dump_orphan_list(struct super_block *sb, struct ext3_sb_info *sbi) -{ - struct list_head *l; - - ext3_msg(sb, KERN_ERR, "error: sb orphan head is %d", - le32_to_cpu(sbi->s_es->s_last_orphan)); - - ext3_msg(sb, KERN_ERR, "sb_info orphan list:"); - list_for_each(l, &sbi->s_orphan) { - struct inode *inode = orphan_list_entry(l); - ext3_msg(sb, KERN_ERR, " " - "inode %s:%lu at %p: mode %o, nlink %d, next %d\n", - inode->i_sb->s_id, inode->i_ino, inode, - inode->i_mode, inode->i_nlink, - NEXT_ORPHAN(inode)); - } -} - -static void ext3_put_super (struct super_block * sb) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - int i, err; - - dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); - ext3_xattr_put_super(sb); - err = journal_destroy(sbi->s_journal); - sbi->s_journal = NULL; - if (err < 0) - ext3_abort(sb, __func__, "Couldn't clean up the journal"); - - if (!(sb->s_flags & MS_RDONLY)) { - EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - es->s_state = cpu_to_le16(sbi->s_mount_state); - BUFFER_TRACE(sbi->s_sbh, "marking dirty"); - mark_buffer_dirty(sbi->s_sbh); - ext3_commit_super(sb, es, 1); - } - - for (i = 0; i < sbi->s_gdb_count; i++) - brelse(sbi->s_group_desc[i]); - kfree(sbi->s_group_desc); - percpu_counter_destroy(&sbi->s_freeblocks_counter); - percpu_counter_destroy(&sbi->s_freeinodes_counter); - percpu_counter_destroy(&sbi->s_dirs_counter); - brelse(sbi->s_sbh); -#ifdef CONFIG_QUOTA - for (i = 0; i < EXT3_MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); -#endif - - /* Debugging code just in case the in-memory inode orphan list - * isn't empty. The on-disk one can be non-empty if we've - * detected an error and taken the fs readonly, but the - * in-memory list had better be clean by this point. */ - if (!list_empty(&sbi->s_orphan)) - dump_orphan_list(sb, sbi); - J_ASSERT(list_empty(&sbi->s_orphan)); - - invalidate_bdev(sb->s_bdev); - if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { - /* - * Invalidate the journal device's buffers. We don't want them - * floating about in memory - the physical journal device may - * hotswapped, and it breaks the `ro-after' testing code. - */ - sync_blockdev(sbi->journal_bdev); - invalidate_bdev(sbi->journal_bdev); - ext3_blkdev_remove(sbi); - } - sb->s_fs_info = NULL; - kfree(sbi->s_blockgroup_lock); - mutex_destroy(&sbi->s_orphan_lock); - mutex_destroy(&sbi->s_resize_lock); - kfree(sbi); -} - -static struct kmem_cache *ext3_inode_cachep; - -/* - * Called inside transaction, so use GFP_NOFS - */ -static struct inode *ext3_alloc_inode(struct super_block *sb) -{ - struct ext3_inode_info *ei; - - ei = kmem_cache_alloc(ext3_inode_cachep, GFP_NOFS); - if (!ei) - return NULL; - ei->i_block_alloc_info = NULL; - ei->vfs_inode.i_version = 1; - atomic_set(&ei->i_datasync_tid, 0); - atomic_set(&ei->i_sync_tid, 0); -#ifdef CONFIG_QUOTA - memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); -#endif - - return &ei->vfs_inode; -} - -static int ext3_drop_inode(struct inode *inode) -{ - int drop = generic_drop_inode(inode); - - trace_ext3_drop_inode(inode, drop); - return drop; -} - -static void ext3_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(ext3_inode_cachep, EXT3_I(inode)); -} - -static void ext3_destroy_inode(struct inode *inode) -{ - if (!list_empty(&(EXT3_I(inode)->i_orphan))) { - printk("EXT3 Inode %p: orphan list check failed!\n", - EXT3_I(inode)); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4, - EXT3_I(inode), sizeof(struct ext3_inode_info), - false); - dump_stack(); - } - call_rcu(&inode->i_rcu, ext3_i_callback); -} - -static void init_once(void *foo) -{ - struct ext3_inode_info *ei = (struct ext3_inode_info *) foo; - - INIT_LIST_HEAD(&ei->i_orphan); -#ifdef CONFIG_EXT3_FS_XATTR - init_rwsem(&ei->xattr_sem); -#endif - mutex_init(&ei->truncate_mutex); - inode_init_once(&ei->vfs_inode); -} - -static int __init init_inodecache(void) -{ - ext3_inode_cachep = kmem_cache_create("ext3_inode_cache", - sizeof(struct ext3_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD), - init_once); - if (ext3_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -static void destroy_inodecache(void) -{ - /* - * Make sure all delayed rcu free inodes are flushed before we - * destroy cache. - */ - rcu_barrier(); - kmem_cache_destroy(ext3_inode_cachep); -} - -static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb) -{ -#if defined(CONFIG_QUOTA) - struct ext3_sb_info *sbi = EXT3_SB(sb); - - if (sbi->s_jquota_fmt) { - char *fmtname = ""; - - switch (sbi->s_jquota_fmt) { - case QFMT_VFS_OLD: - fmtname = "vfsold"; - break; - case QFMT_VFS_V0: - fmtname = "vfsv0"; - break; - case QFMT_VFS_V1: - fmtname = "vfsv1"; - break; - } - seq_printf(seq, ",jqfmt=%s", fmtname); - } - - if (sbi->s_qf_names[USRQUOTA]) - seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); - - if (sbi->s_qf_names[GRPQUOTA]) - seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); - - if (test_opt(sb, USRQUOTA)) - seq_puts(seq, ",usrquota"); - - if (test_opt(sb, GRPQUOTA)) - seq_puts(seq, ",grpquota"); -#endif -} - -static char *data_mode_string(unsigned long mode) -{ - switch (mode) { - case EXT3_MOUNT_JOURNAL_DATA: - return "journal"; - case EXT3_MOUNT_ORDERED_DATA: - return "ordered"; - case EXT3_MOUNT_WRITEBACK_DATA: - return "writeback"; - } - return "unknown"; -} - -/* - * Show an option if - * - it's set to a non-default value OR - * - if the per-sb default is different from the global default - */ -static int ext3_show_options(struct seq_file *seq, struct dentry *root) -{ - struct super_block *sb = root->d_sb; - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - unsigned long def_mount_opts; - - def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - - if (sbi->s_sb_block != 1) - seq_printf(seq, ",sb=%lu", sbi->s_sb_block); - if (test_opt(sb, MINIX_DF)) - seq_puts(seq, ",minixdf"); - if (test_opt(sb, GRPID)) - seq_puts(seq, ",grpid"); - if (!test_opt(sb, GRPID) && (def_mount_opts & EXT3_DEFM_BSDGROUPS)) - seq_puts(seq, ",nogrpid"); - if (!uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT3_DEF_RESUID)) || - le16_to_cpu(es->s_def_resuid) != EXT3_DEF_RESUID) { - seq_printf(seq, ",resuid=%u", - from_kuid_munged(&init_user_ns, sbi->s_resuid)); - } - if (!gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT3_DEF_RESGID)) || - le16_to_cpu(es->s_def_resgid) != EXT3_DEF_RESGID) { - seq_printf(seq, ",resgid=%u", - from_kgid_munged(&init_user_ns, sbi->s_resgid)); - } - if (test_opt(sb, ERRORS_RO)) { - int def_errors = le16_to_cpu(es->s_errors); - - if (def_errors == EXT3_ERRORS_PANIC || - def_errors == EXT3_ERRORS_CONTINUE) { - seq_puts(seq, ",errors=remount-ro"); - } - } - if (test_opt(sb, ERRORS_CONT)) - seq_puts(seq, ",errors=continue"); - if (test_opt(sb, ERRORS_PANIC)) - seq_puts(seq, ",errors=panic"); - if (test_opt(sb, NO_UID32)) - seq_puts(seq, ",nouid32"); - if (test_opt(sb, DEBUG)) - seq_puts(seq, ",debug"); -#ifdef CONFIG_EXT3_FS_XATTR - if (test_opt(sb, XATTR_USER)) - seq_puts(seq, ",user_xattr"); - if (!test_opt(sb, XATTR_USER) && - (def_mount_opts & EXT3_DEFM_XATTR_USER)) { - seq_puts(seq, ",nouser_xattr"); - } -#endif -#ifdef CONFIG_EXT3_FS_POSIX_ACL - if (test_opt(sb, POSIX_ACL)) - seq_puts(seq, ",acl"); - if (!test_opt(sb, POSIX_ACL) && (def_mount_opts & EXT3_DEFM_ACL)) - seq_puts(seq, ",noacl"); -#endif - if (!test_opt(sb, RESERVATION)) - seq_puts(seq, ",noreservation"); - if (sbi->s_commit_interval) { - seq_printf(seq, ",commit=%u", - (unsigned) (sbi->s_commit_interval / HZ)); - } - - /* - * Always display barrier state so it's clear what the status is. - */ - seq_puts(seq, ",barrier="); - seq_puts(seq, test_opt(sb, BARRIER) ? "1" : "0"); - seq_printf(seq, ",data=%s", data_mode_string(test_opt(sb, DATA_FLAGS))); - if (test_opt(sb, DATA_ERR_ABORT)) - seq_puts(seq, ",data_err=abort"); - - if (test_opt(sb, NOLOAD)) - seq_puts(seq, ",norecovery"); - - ext3_show_quota_options(seq, sb); - - return 0; -} - - -static struct inode *ext3_nfs_get_inode(struct super_block *sb, - u64 ino, u32 generation) -{ - struct inode *inode; - - if (ino < EXT3_FIRST_INO(sb) && ino != EXT3_ROOT_INO) - return ERR_PTR(-ESTALE); - if (ino > le32_to_cpu(EXT3_SB(sb)->s_es->s_inodes_count)) - return ERR_PTR(-ESTALE); - - /* iget isn't really right if the inode is currently unallocated!! - * - * ext3_read_inode will return a bad_inode if the inode had been - * deleted, so we should be safe. - * - * Currently we don't know the generation for parent directory, so - * a generation of 0 means "accept any" - */ - inode = ext3_iget(sb, ino); - if (IS_ERR(inode)) - return ERR_CAST(inode); - if (generation && inode->i_generation != generation) { - iput(inode); - return ERR_PTR(-ESTALE); - } - - return inode; -} - -static struct dentry *ext3_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_dentry(sb, fid, fh_len, fh_type, - ext3_nfs_get_inode); -} - -static struct dentry *ext3_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type) -{ - return generic_fh_to_parent(sb, fid, fh_len, fh_type, - ext3_nfs_get_inode); -} - -/* - * Try to release metadata pages (indirect blocks, directories) which are - * mapped via the block device. Since these pages could have journal heads - * which would prevent try_to_free_buffers() from freeing them, we must use - * jbd layer's try_to_free_buffers() function to release them. - */ -static int bdev_try_to_free_page(struct super_block *sb, struct page *page, - gfp_t wait) -{ - journal_t *journal = EXT3_SB(sb)->s_journal; - - WARN_ON(PageChecked(page)); - if (!page_has_buffers(page)) - return 0; - if (journal) - return journal_try_to_free_buffers(journal, page, - wait & ~__GFP_WAIT); - return try_to_free_buffers(page); -} - -#ifdef CONFIG_QUOTA -#define QTYPE2NAME(t) ((t)==USRQUOTA?"user":"group") -#define QTYPE2MOPT(on, t) ((t)==USRQUOTA?((on)##USRJQUOTA):((on)##GRPJQUOTA)) - -static int ext3_write_dquot(struct dquot *dquot); -static int ext3_acquire_dquot(struct dquot *dquot); -static int ext3_release_dquot(struct dquot *dquot); -static int ext3_mark_dquot_dirty(struct dquot *dquot); -static int ext3_write_info(struct super_block *sb, int type); -static int ext3_quota_on(struct super_block *sb, int type, int format_id, - struct path *path); -static int ext3_quota_on_mount(struct super_block *sb, int type); -static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, - size_t len, loff_t off); -static ssize_t ext3_quota_write(struct super_block *sb, int type, - const char *data, size_t len, loff_t off); -static struct dquot **ext3_get_dquots(struct inode *inode) -{ - return EXT3_I(inode)->i_dquot; -} - -static const struct dquot_operations ext3_quota_operations = { - .write_dquot = ext3_write_dquot, - .acquire_dquot = ext3_acquire_dquot, - .release_dquot = ext3_release_dquot, - .mark_dirty = ext3_mark_dquot_dirty, - .write_info = ext3_write_info, - .alloc_dquot = dquot_alloc, - .destroy_dquot = dquot_destroy, -}; - -static const struct quotactl_ops ext3_qctl_operations = { - .quota_on = ext3_quota_on, - .quota_off = dquot_quota_off, - .quota_sync = dquot_quota_sync, - .get_state = dquot_get_state, - .set_info = dquot_set_dqinfo, - .get_dqblk = dquot_get_dqblk, - .set_dqblk = dquot_set_dqblk -}; -#endif - -static const struct super_operations ext3_sops = { - .alloc_inode = ext3_alloc_inode, - .destroy_inode = ext3_destroy_inode, - .write_inode = ext3_write_inode, - .dirty_inode = ext3_dirty_inode, - .drop_inode = ext3_drop_inode, - .evict_inode = ext3_evict_inode, - .put_super = ext3_put_super, - .sync_fs = ext3_sync_fs, - .freeze_fs = ext3_freeze, - .unfreeze_fs = ext3_unfreeze, - .statfs = ext3_statfs, - .remount_fs = ext3_remount, - .show_options = ext3_show_options, -#ifdef CONFIG_QUOTA - .quota_read = ext3_quota_read, - .quota_write = ext3_quota_write, - .get_dquots = ext3_get_dquots, -#endif - .bdev_try_to_free_page = bdev_try_to_free_page, -}; - -static const struct export_operations ext3_export_ops = { - .fh_to_dentry = ext3_fh_to_dentry, - .fh_to_parent = ext3_fh_to_parent, - .get_parent = ext3_get_parent, -}; - -enum { - Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, - Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, - Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, - Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh, - Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev, - Opt_journal_path, - Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, - Opt_data_err_abort, Opt_data_err_ignore, - Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, - Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, - Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, - Opt_resize, Opt_usrquota, Opt_grpquota -}; - -static const match_table_t tokens = { - {Opt_bsd_df, "bsddf"}, - {Opt_minix_df, "minixdf"}, - {Opt_grpid, "grpid"}, - {Opt_grpid, "bsdgroups"}, - {Opt_nogrpid, "nogrpid"}, - {Opt_nogrpid, "sysvgroups"}, - {Opt_resgid, "resgid=%u"}, - {Opt_resuid, "resuid=%u"}, - {Opt_sb, "sb=%u"}, - {Opt_err_cont, "errors=continue"}, - {Opt_err_panic, "errors=panic"}, - {Opt_err_ro, "errors=remount-ro"}, - {Opt_nouid32, "nouid32"}, - {Opt_nocheck, "nocheck"}, - {Opt_nocheck, "check=none"}, - {Opt_debug, "debug"}, - {Opt_oldalloc, "oldalloc"}, - {Opt_orlov, "orlov"}, - {Opt_user_xattr, "user_xattr"}, - {Opt_nouser_xattr, "nouser_xattr"}, - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, - {Opt_reservation, "reservation"}, - {Opt_noreservation, "noreservation"}, - {Opt_noload, "noload"}, - {Opt_noload, "norecovery"}, - {Opt_nobh, "nobh"}, - {Opt_bh, "bh"}, - {Opt_commit, "commit=%u"}, - {Opt_journal_update, "journal=update"}, - {Opt_journal_inum, "journal=%u"}, - {Opt_journal_dev, "journal_dev=%u"}, - {Opt_journal_path, "journal_path=%s"}, - {Opt_abort, "abort"}, - {Opt_data_journal, "data=journal"}, - {Opt_data_ordered, "data=ordered"}, - {Opt_data_writeback, "data=writeback"}, - {Opt_data_err_abort, "data_err=abort"}, - {Opt_data_err_ignore, "data_err=ignore"}, - {Opt_offusrjquota, "usrjquota="}, - {Opt_usrjquota, "usrjquota=%s"}, - {Opt_offgrpjquota, "grpjquota="}, - {Opt_grpjquota, "grpjquota=%s"}, - {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, - {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, - {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, - {Opt_grpquota, "grpquota"}, - {Opt_noquota, "noquota"}, - {Opt_quota, "quota"}, - {Opt_usrquota, "usrquota"}, - {Opt_barrier, "barrier=%u"}, - {Opt_barrier, "barrier"}, - {Opt_nobarrier, "nobarrier"}, - {Opt_resize, "resize"}, - {Opt_err, NULL}, -}; - -static ext3_fsblk_t get_sb_block(void **data, struct super_block *sb) -{ - ext3_fsblk_t sb_block; - char *options = (char *) *data; - - if (!options || strncmp(options, "sb=", 3) != 0) - return 1; /* Default location */ - options += 3; - /*todo: use simple_strtoll with >32bit ext3 */ - sb_block = simple_strtoul(options, &options, 0); - if (*options && *options != ',') { - ext3_msg(sb, KERN_ERR, "error: invalid sb specification: %s", - (char *) *data); - return 1; - } - if (*options == ',') - options++; - *data = (void *) options; - return sb_block; -} - -#ifdef CONFIG_QUOTA -static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - char *qname; - - if (sb_any_quota_loaded(sb) && - !sbi->s_qf_names[qtype]) { - ext3_msg(sb, KERN_ERR, - "Cannot change journaled " - "quota options when quota turned on"); - return 0; - } - qname = match_strdup(args); - if (!qname) { - ext3_msg(sb, KERN_ERR, - "Not enough memory for storing quotafile name"); - return 0; - } - if (sbi->s_qf_names[qtype]) { - int same = !strcmp(sbi->s_qf_names[qtype], qname); - - kfree(qname); - if (!same) { - ext3_msg(sb, KERN_ERR, - "%s quota file already specified", - QTYPE2NAME(qtype)); - } - return same; - } - if (strchr(qname, '/')) { - ext3_msg(sb, KERN_ERR, - "quotafile must be on filesystem root"); - kfree(qname); - return 0; - } - sbi->s_qf_names[qtype] = qname; - set_opt(sbi->s_mount_opt, QUOTA); - return 1; -} - -static int clear_qf_name(struct super_block *sb, int qtype) { - - struct ext3_sb_info *sbi = EXT3_SB(sb); - - if (sb_any_quota_loaded(sb) && - sbi->s_qf_names[qtype]) { - ext3_msg(sb, KERN_ERR, "Cannot change journaled quota options" - " when quota turned on"); - return 0; - } - if (sbi->s_qf_names[qtype]) { - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; - } - return 1; -} -#endif - -static int parse_options (char *options, struct super_block *sb, - unsigned int *inum, unsigned long *journal_devnum, - ext3_fsblk_t *n_blocks_count, int is_remount) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - char * p; - substring_t args[MAX_OPT_ARGS]; - int data_opt = 0; - int option; - kuid_t uid; - kgid_t gid; - char *journal_path; - struct inode *journal_inode; - struct path path; - int error; - -#ifdef CONFIG_QUOTA - int qfmt; -#endif - - if (!options) - return 1; - - while ((p = strsep (&options, ",")) != NULL) { - int token; - if (!*p) - continue; - /* - * Initialize args struct so we know whether arg was - * found; some options take optional arguments. - */ - args[0].to = args[0].from = NULL; - token = match_token(p, tokens, args); - switch (token) { - case Opt_bsd_df: - clear_opt (sbi->s_mount_opt, MINIX_DF); - break; - case Opt_minix_df: - set_opt (sbi->s_mount_opt, MINIX_DF); - break; - case Opt_grpid: - set_opt (sbi->s_mount_opt, GRPID); - break; - case Opt_nogrpid: - clear_opt (sbi->s_mount_opt, GRPID); - break; - case Opt_resuid: - if (match_int(&args[0], &option)) - return 0; - uid = make_kuid(current_user_ns(), option); - if (!uid_valid(uid)) { - ext3_msg(sb, KERN_ERR, "Invalid uid value %d", option); - return 0; - - } - sbi->s_resuid = uid; - break; - case Opt_resgid: - if (match_int(&args[0], &option)) - return 0; - gid = make_kgid(current_user_ns(), option); - if (!gid_valid(gid)) { - ext3_msg(sb, KERN_ERR, "Invalid gid value %d", option); - return 0; - } - sbi->s_resgid = gid; - break; - case Opt_sb: - /* handled by get_sb_block() instead of here */ - /* *sb_block = match_int(&args[0]); */ - break; - case Opt_err_panic: - clear_opt (sbi->s_mount_opt, ERRORS_CONT); - clear_opt (sbi->s_mount_opt, ERRORS_RO); - set_opt (sbi->s_mount_opt, ERRORS_PANIC); - break; - case Opt_err_ro: - clear_opt (sbi->s_mount_opt, ERRORS_CONT); - clear_opt (sbi->s_mount_opt, ERRORS_PANIC); - set_opt (sbi->s_mount_opt, ERRORS_RO); - break; - case Opt_err_cont: - clear_opt (sbi->s_mount_opt, ERRORS_RO); - clear_opt (sbi->s_mount_opt, ERRORS_PANIC); - set_opt (sbi->s_mount_opt, ERRORS_CONT); - break; - case Opt_nouid32: - set_opt (sbi->s_mount_opt, NO_UID32); - break; - case Opt_nocheck: - clear_opt (sbi->s_mount_opt, CHECK); - break; - case Opt_debug: - set_opt (sbi->s_mount_opt, DEBUG); - break; - case Opt_oldalloc: - ext3_msg(sb, KERN_WARNING, - "Ignoring deprecated oldalloc option"); - break; - case Opt_orlov: - ext3_msg(sb, KERN_WARNING, - "Ignoring deprecated orlov option"); - break; -#ifdef CONFIG_EXT3_FS_XATTR - case Opt_user_xattr: - set_opt (sbi->s_mount_opt, XATTR_USER); - break; - case Opt_nouser_xattr: - clear_opt (sbi->s_mount_opt, XATTR_USER); - break; -#else - case Opt_user_xattr: - case Opt_nouser_xattr: - ext3_msg(sb, KERN_INFO, - "(no)user_xattr options not supported"); - break; -#endif -#ifdef CONFIG_EXT3_FS_POSIX_ACL - case Opt_acl: - set_opt(sbi->s_mount_opt, POSIX_ACL); - break; - case Opt_noacl: - clear_opt(sbi->s_mount_opt, POSIX_ACL); - break; -#else - case Opt_acl: - case Opt_noacl: - ext3_msg(sb, KERN_INFO, - "(no)acl options not supported"); - break; -#endif - case Opt_reservation: - set_opt(sbi->s_mount_opt, RESERVATION); - break; - case Opt_noreservation: - clear_opt(sbi->s_mount_opt, RESERVATION); - break; - case Opt_journal_update: - /* @@@ FIXME */ - /* Eventually we will want to be able to create - a journal file here. For now, only allow the - user to specify an existing inode to be the - journal file. */ - if (is_remount) { - ext3_msg(sb, KERN_ERR, "error: cannot specify " - "journal on remount"); - return 0; - } - set_opt (sbi->s_mount_opt, UPDATE_JOURNAL); - break; - case Opt_journal_inum: - if (is_remount) { - ext3_msg(sb, KERN_ERR, "error: cannot specify " - "journal on remount"); - return 0; - } - if (match_int(&args[0], &option)) - return 0; - *inum = option; - break; - case Opt_journal_dev: - if (is_remount) { - ext3_msg(sb, KERN_ERR, "error: cannot specify " - "journal on remount"); - return 0; - } - if (match_int(&args[0], &option)) - return 0; - *journal_devnum = option; - break; - case Opt_journal_path: - if (is_remount) { - ext3_msg(sb, KERN_ERR, "error: cannot specify " - "journal on remount"); - return 0; - } - - journal_path = match_strdup(&args[0]); - if (!journal_path) { - ext3_msg(sb, KERN_ERR, "error: could not dup " - "journal device string"); - return 0; - } - - error = kern_path(journal_path, LOOKUP_FOLLOW, &path); - if (error) { - ext3_msg(sb, KERN_ERR, "error: could not find " - "journal device path: error %d", error); - kfree(journal_path); - return 0; - } - - journal_inode = d_inode(path.dentry); - if (!S_ISBLK(journal_inode->i_mode)) { - ext3_msg(sb, KERN_ERR, "error: journal path %s " - "is not a block device", journal_path); - path_put(&path); - kfree(journal_path); - return 0; - } - - *journal_devnum = new_encode_dev(journal_inode->i_rdev); - path_put(&path); - kfree(journal_path); - break; - case Opt_noload: - set_opt (sbi->s_mount_opt, NOLOAD); - break; - case Opt_commit: - if (match_int(&args[0], &option)) - return 0; - if (option < 0) - return 0; - if (option == 0) - option = JBD_DEFAULT_MAX_COMMIT_AGE; - sbi->s_commit_interval = HZ * option; - break; - case Opt_data_journal: - data_opt = EXT3_MOUNT_JOURNAL_DATA; - goto datacheck; - case Opt_data_ordered: - data_opt = EXT3_MOUNT_ORDERED_DATA; - goto datacheck; - case Opt_data_writeback: - data_opt = EXT3_MOUNT_WRITEBACK_DATA; - datacheck: - if (is_remount) { - if (test_opt(sb, DATA_FLAGS) == data_opt) - break; - ext3_msg(sb, KERN_ERR, - "error: cannot change " - "data mode on remount. The filesystem " - "is mounted in data=%s mode and you " - "try to remount it in data=%s mode.", - data_mode_string(test_opt(sb, - DATA_FLAGS)), - data_mode_string(data_opt)); - return 0; - } else { - clear_opt(sbi->s_mount_opt, DATA_FLAGS); - sbi->s_mount_opt |= data_opt; - } - break; - case Opt_data_err_abort: - set_opt(sbi->s_mount_opt, DATA_ERR_ABORT); - break; - case Opt_data_err_ignore: - clear_opt(sbi->s_mount_opt, DATA_ERR_ABORT); - break; -#ifdef CONFIG_QUOTA - case Opt_usrjquota: - if (!set_qf_name(sb, USRQUOTA, &args[0])) - return 0; - break; - case Opt_grpjquota: - if (!set_qf_name(sb, GRPQUOTA, &args[0])) - return 0; - break; - case Opt_offusrjquota: - if (!clear_qf_name(sb, USRQUOTA)) - return 0; - break; - case Opt_offgrpjquota: - if (!clear_qf_name(sb, GRPQUOTA)) - return 0; - break; - case Opt_jqfmt_vfsold: - qfmt = QFMT_VFS_OLD; - goto set_qf_format; - case Opt_jqfmt_vfsv0: - qfmt = QFMT_VFS_V0; - goto set_qf_format; - case Opt_jqfmt_vfsv1: - qfmt = QFMT_VFS_V1; -set_qf_format: - if (sb_any_quota_loaded(sb) && - sbi->s_jquota_fmt != qfmt) { - ext3_msg(sb, KERN_ERR, "error: cannot change " - "journaled quota options when " - "quota turned on."); - return 0; - } - sbi->s_jquota_fmt = qfmt; - break; - case Opt_quota: - case Opt_usrquota: - set_opt(sbi->s_mount_opt, QUOTA); - set_opt(sbi->s_mount_opt, USRQUOTA); - break; - case Opt_grpquota: - set_opt(sbi->s_mount_opt, QUOTA); - set_opt(sbi->s_mount_opt, GRPQUOTA); - break; - case Opt_noquota: - if (sb_any_quota_loaded(sb)) { - ext3_msg(sb, KERN_ERR, "error: cannot change " - "quota options when quota turned on."); - return 0; - } - clear_opt(sbi->s_mount_opt, QUOTA); - clear_opt(sbi->s_mount_opt, USRQUOTA); - clear_opt(sbi->s_mount_opt, GRPQUOTA); - break; -#else - case Opt_quota: - case Opt_usrquota: - case Opt_grpquota: - ext3_msg(sb, KERN_ERR, - "error: quota options not supported."); - break; - case Opt_usrjquota: - case Opt_grpjquota: - case Opt_offusrjquota: - case Opt_offgrpjquota: - case Opt_jqfmt_vfsold: - case Opt_jqfmt_vfsv0: - case Opt_jqfmt_vfsv1: - ext3_msg(sb, KERN_ERR, - "error: journaled quota options not " - "supported."); - break; - case Opt_noquota: - break; -#endif - case Opt_abort: - set_opt(sbi->s_mount_opt, ABORT); - break; - case Opt_nobarrier: - clear_opt(sbi->s_mount_opt, BARRIER); - break; - case Opt_barrier: - if (args[0].from) { - if (match_int(&args[0], &option)) - return 0; - } else - option = 1; /* No argument, default to 1 */ - if (option) - set_opt(sbi->s_mount_opt, BARRIER); - else - clear_opt(sbi->s_mount_opt, BARRIER); - break; - case Opt_ignore: - break; - case Opt_resize: - if (!is_remount) { - ext3_msg(sb, KERN_ERR, - "error: resize option only available " - "for remount"); - return 0; - } - if (match_int(&args[0], &option) != 0) - return 0; - *n_blocks_count = option; - break; - case Opt_nobh: - ext3_msg(sb, KERN_WARNING, - "warning: ignoring deprecated nobh option"); - break; - case Opt_bh: - ext3_msg(sb, KERN_WARNING, - "warning: ignoring deprecated bh option"); - break; - default: - ext3_msg(sb, KERN_ERR, - "error: unrecognized mount option \"%s\" " - "or missing value", p); - return 0; - } - } -#ifdef CONFIG_QUOTA - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { - if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA]) - clear_opt(sbi->s_mount_opt, USRQUOTA); - if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) - clear_opt(sbi->s_mount_opt, GRPQUOTA); - - if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) { - ext3_msg(sb, KERN_ERR, "error: old and new quota " - "format mixing."); - return 0; - } - - if (!sbi->s_jquota_fmt) { - ext3_msg(sb, KERN_ERR, "error: journaled quota format " - "not specified."); - return 0; - } - } -#endif - return 1; -} - -static int ext3_setup_super(struct super_block *sb, struct ext3_super_block *es, - int read_only) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - int res = 0; - - if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) { - ext3_msg(sb, KERN_ERR, - "error: revision level too high, " - "forcing read-only mode"); - res = MS_RDONLY; - } - if (read_only) - return res; - if (!(sbi->s_mount_state & EXT3_VALID_FS)) - ext3_msg(sb, KERN_WARNING, - "warning: mounting unchecked fs, " - "running e2fsck is recommended"); - else if ((sbi->s_mount_state & EXT3_ERROR_FS)) - ext3_msg(sb, KERN_WARNING, - "warning: mounting fs with errors, " - "running e2fsck is recommended"); - else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 && - le16_to_cpu(es->s_mnt_count) >= - le16_to_cpu(es->s_max_mnt_count)) - ext3_msg(sb, KERN_WARNING, - "warning: maximal mount count reached, " - "running e2fsck is recommended"); - else if (le32_to_cpu(es->s_checkinterval) && - (le32_to_cpu(es->s_lastcheck) + - le32_to_cpu(es->s_checkinterval) <= get_seconds())) - ext3_msg(sb, KERN_WARNING, - "warning: checktime reached, " - "running e2fsck is recommended"); -#if 0 - /* @@@ We _will_ want to clear the valid bit if we find - inconsistencies, to force a fsck at reboot. But for - a plain journaled filesystem we can keep it set as - valid forever! :) */ - es->s_state &= cpu_to_le16(~EXT3_VALID_FS); -#endif - if (!le16_to_cpu(es->s_max_mnt_count)) - es->s_max_mnt_count = cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT); - le16_add_cpu(&es->s_mnt_count, 1); - es->s_mtime = cpu_to_le32(get_seconds()); - ext3_update_dynamic_rev(sb); - EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - - ext3_commit_super(sb, es, 1); - if (test_opt(sb, DEBUG)) - ext3_msg(sb, KERN_INFO, "[bs=%lu, gc=%lu, " - "bpg=%lu, ipg=%lu, mo=%04lx]", - sb->s_blocksize, - sbi->s_groups_count, - EXT3_BLOCKS_PER_GROUP(sb), - EXT3_INODES_PER_GROUP(sb), - sbi->s_mount_opt); - - if (EXT3_SB(sb)->s_journal->j_inode == NULL) { - char b[BDEVNAME_SIZE]; - ext3_msg(sb, KERN_INFO, "using external journal on %s", - bdevname(EXT3_SB(sb)->s_journal->j_dev, b)); - } else { - ext3_msg(sb, KERN_INFO, "using internal journal"); - } - cleancache_init_fs(sb); - return res; -} - -/* Called at mount-time, super-block is locked */ -static int ext3_check_descriptors(struct super_block *sb) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - int i; - - ext3_debug ("Checking group descriptors"); - - for (i = 0; i < sbi->s_groups_count; i++) { - struct ext3_group_desc *gdp = ext3_get_group_desc(sb, i, NULL); - ext3_fsblk_t first_block = ext3_group_first_block_no(sb, i); - ext3_fsblk_t last_block; - - if (i == sbi->s_groups_count - 1) - last_block = le32_to_cpu(sbi->s_es->s_blocks_count) - 1; - else - last_block = first_block + - (EXT3_BLOCKS_PER_GROUP(sb) - 1); - - if (le32_to_cpu(gdp->bg_block_bitmap) < first_block || - le32_to_cpu(gdp->bg_block_bitmap) > last_block) - { - ext3_error (sb, "ext3_check_descriptors", - "Block bitmap for group %d" - " not in group (block %lu)!", - i, (unsigned long) - le32_to_cpu(gdp->bg_block_bitmap)); - return 0; - } - if (le32_to_cpu(gdp->bg_inode_bitmap) < first_block || - le32_to_cpu(gdp->bg_inode_bitmap) > last_block) - { - ext3_error (sb, "ext3_check_descriptors", - "Inode bitmap for group %d" - " not in group (block %lu)!", - i, (unsigned long) - le32_to_cpu(gdp->bg_inode_bitmap)); - return 0; - } - if (le32_to_cpu(gdp->bg_inode_table) < first_block || - le32_to_cpu(gdp->bg_inode_table) + sbi->s_itb_per_group - 1 > - last_block) - { - ext3_error (sb, "ext3_check_descriptors", - "Inode table for group %d" - " not in group (block %lu)!", - i, (unsigned long) - le32_to_cpu(gdp->bg_inode_table)); - return 0; - } - } - - sbi->s_es->s_free_blocks_count=cpu_to_le32(ext3_count_free_blocks(sb)); - sbi->s_es->s_free_inodes_count=cpu_to_le32(ext3_count_free_inodes(sb)); - return 1; -} - - -/* ext3_orphan_cleanup() walks a singly-linked list of inodes (starting at - * the superblock) which were deleted from all directories, but held open by - * a process at the time of a crash. We walk the list and try to delete these - * inodes at recovery time (only with a read-write filesystem). - * - * In order to keep the orphan inode chain consistent during traversal (in - * case of crash during recovery), we link each inode into the superblock - * orphan list_head and handle it the same way as an inode deletion during - * normal operation (which journals the operations for us). - * - * We only do an iget() and an iput() on each inode, which is very safe if we - * accidentally point at an in-use or already deleted inode. The worst that - * can happen in this case is that we get a "bit already cleared" message from - * ext3_free_inode(). The only reason we would point at a wrong inode is if - * e2fsck was run on this filesystem, and it must have already done the orphan - * inode cleanup for us, so we can safely abort without any further action. - */ -static void ext3_orphan_cleanup (struct super_block * sb, - struct ext3_super_block * es) -{ - unsigned int s_flags = sb->s_flags; - int nr_orphans = 0, nr_truncates = 0; -#ifdef CONFIG_QUOTA - int i; -#endif - if (!es->s_last_orphan) { - jbd_debug(4, "no orphan inodes to clean up\n"); - return; - } - - if (bdev_read_only(sb->s_bdev)) { - ext3_msg(sb, KERN_ERR, "error: write access " - "unavailable, skipping orphan cleanup."); - return; - } - - /* Check if feature set allows readwrite operations */ - if (EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP)) { - ext3_msg(sb, KERN_INFO, "Skipping orphan cleanup due to " - "unknown ROCOMPAT features"); - return; - } - - if (EXT3_SB(sb)->s_mount_state & EXT3_ERROR_FS) { - /* don't clear list on RO mount w/ errors */ - if (es->s_last_orphan && !(s_flags & MS_RDONLY)) { - jbd_debug(1, "Errors on filesystem, " - "clearing orphan list.\n"); - es->s_last_orphan = 0; - } - jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); - return; - } - - if (s_flags & MS_RDONLY) { - ext3_msg(sb, KERN_INFO, "orphan cleanup on readonly fs"); - sb->s_flags &= ~MS_RDONLY; - } -#ifdef CONFIG_QUOTA - /* Needed for iput() to work correctly and not trash data */ - sb->s_flags |= MS_ACTIVE; - /* Turn on quotas so that they are updated correctly */ - for (i = 0; i < EXT3_MAXQUOTAS; i++) { - if (EXT3_SB(sb)->s_qf_names[i]) { - int ret = ext3_quota_on_mount(sb, i); - if (ret < 0) - ext3_msg(sb, KERN_ERR, - "error: cannot turn on journaled " - "quota: %d", ret); - } - } -#endif - - while (es->s_last_orphan) { - struct inode *inode; - - inode = ext3_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); - if (IS_ERR(inode)) { - es->s_last_orphan = 0; - break; - } - - list_add(&EXT3_I(inode)->i_orphan, &EXT3_SB(sb)->s_orphan); - dquot_initialize(inode); - if (inode->i_nlink) { - printk(KERN_DEBUG - "%s: truncating inode %lu to %Ld bytes\n", - __func__, inode->i_ino, inode->i_size); - jbd_debug(2, "truncating inode %lu to %Ld bytes\n", - inode->i_ino, inode->i_size); - ext3_truncate(inode); - nr_truncates++; - } else { - printk(KERN_DEBUG - "%s: deleting unreferenced inode %lu\n", - __func__, inode->i_ino); - jbd_debug(2, "deleting unreferenced inode %lu\n", - inode->i_ino); - nr_orphans++; - } - iput(inode); /* The delete magic happens here! */ - } - -#define PLURAL(x) (x), ((x)==1) ? "" : "s" - - if (nr_orphans) - ext3_msg(sb, KERN_INFO, "%d orphan inode%s deleted", - PLURAL(nr_orphans)); - if (nr_truncates) - ext3_msg(sb, KERN_INFO, "%d truncate%s cleaned up", - PLURAL(nr_truncates)); -#ifdef CONFIG_QUOTA - /* Turn quotas off */ - for (i = 0; i < EXT3_MAXQUOTAS; i++) { - if (sb_dqopt(sb)->files[i]) - dquot_quota_off(sb, i); - } -#endif - sb->s_flags = s_flags; /* Restore MS_RDONLY status */ -} - -/* - * Maximal file size. There is a direct, and {,double-,triple-}indirect - * block limit, and also a limit of (2^32 - 1) 512-byte sectors in i_blocks. - * We need to be 1 filesystem block less than the 2^32 sector limit. - */ -static loff_t ext3_max_size(int bits) -{ - loff_t res = EXT3_NDIR_BLOCKS; - int meta_blocks; - loff_t upper_limit; - - /* This is calculated to be the largest file size for a - * dense, file such that the total number of - * sectors in the file, including data and all indirect blocks, - * does not exceed 2^32 -1 - * __u32 i_blocks representing the total number of - * 512 bytes blocks of the file - */ - upper_limit = (1LL << 32) - 1; - - /* total blocks in file system block size */ - upper_limit >>= (bits - 9); - - - /* indirect blocks */ - meta_blocks = 1; - /* double indirect blocks */ - meta_blocks += 1 + (1LL << (bits-2)); - /* tripple indirect blocks */ - meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); - - upper_limit -= meta_blocks; - upper_limit <<= bits; - - res += 1LL << (bits-2); - res += 1LL << (2*(bits-2)); - res += 1LL << (3*(bits-2)); - res <<= bits; - if (res > upper_limit) - res = upper_limit; - - if (res > MAX_LFS_FILESIZE) - res = MAX_LFS_FILESIZE; - - return res; -} - -static ext3_fsblk_t descriptor_loc(struct super_block *sb, - ext3_fsblk_t logic_sb_block, - int nr) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - unsigned long bg, first_meta_bg; - int has_super = 0; - - first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); - - if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_META_BG) || - nr < first_meta_bg) - return (logic_sb_block + nr + 1); - bg = sbi->s_desc_per_block * nr; - if (ext3_bg_has_super(sb, bg)) - has_super = 1; - return (has_super + ext3_group_first_block_no(sb, bg)); -} - - -static int ext3_fill_super (struct super_block *sb, void *data, int silent) -{ - struct buffer_head * bh; - struct ext3_super_block *es = NULL; - struct ext3_sb_info *sbi; - ext3_fsblk_t block; - ext3_fsblk_t sb_block = get_sb_block(&data, sb); - ext3_fsblk_t logic_sb_block; - unsigned long offset = 0; - unsigned int journal_inum = 0; - unsigned long journal_devnum = 0; - unsigned long def_mount_opts; - struct inode *root; - int blocksize; - int hblock; - int db_count; - int i; - int needs_recovery; - int ret = -EINVAL; - __le32 features; - int err; - - sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); - if (!sbi) - return -ENOMEM; - - sbi->s_blockgroup_lock = - kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); - if (!sbi->s_blockgroup_lock) { - kfree(sbi); - return -ENOMEM; - } - sb->s_fs_info = sbi; - sbi->s_sb_block = sb_block; - - blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE); - if (!blocksize) { - ext3_msg(sb, KERN_ERR, "error: unable to set blocksize"); - goto out_fail; - } - - /* - * The ext3 superblock will not be buffer aligned for other than 1kB - * block sizes. We need to calculate the offset from buffer start. - */ - if (blocksize != EXT3_MIN_BLOCK_SIZE) { - logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; - offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; - } else { - logic_sb_block = sb_block; - } - - if (!(bh = sb_bread(sb, logic_sb_block))) { - ext3_msg(sb, KERN_ERR, "error: unable to read superblock"); - goto out_fail; - } - /* - * Note: s_es must be initialized as soon as possible because - * some ext3 macro-instructions depend on its value - */ - es = (struct ext3_super_block *) (bh->b_data + offset); - sbi->s_es = es; - sb->s_magic = le16_to_cpu(es->s_magic); - if (sb->s_magic != EXT3_SUPER_MAGIC) - goto cantfind_ext3; - - /* Set defaults before we parse the mount options */ - def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - if (def_mount_opts & EXT3_DEFM_DEBUG) - set_opt(sbi->s_mount_opt, DEBUG); - if (def_mount_opts & EXT3_DEFM_BSDGROUPS) - set_opt(sbi->s_mount_opt, GRPID); - if (def_mount_opts & EXT3_DEFM_UID16) - set_opt(sbi->s_mount_opt, NO_UID32); -#ifdef CONFIG_EXT3_FS_XATTR - if (def_mount_opts & EXT3_DEFM_XATTR_USER) - set_opt(sbi->s_mount_opt, XATTR_USER); -#endif -#ifdef CONFIG_EXT3_FS_POSIX_ACL - if (def_mount_opts & EXT3_DEFM_ACL) - set_opt(sbi->s_mount_opt, POSIX_ACL); -#endif - if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA) - set_opt(sbi->s_mount_opt, JOURNAL_DATA); - else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED) - set_opt(sbi->s_mount_opt, ORDERED_DATA); - else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_WBACK) - set_opt(sbi->s_mount_opt, WRITEBACK_DATA); - - if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_PANIC) - set_opt(sbi->s_mount_opt, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT3_ERRORS_CONTINUE) - set_opt(sbi->s_mount_opt, ERRORS_CONT); - else - set_opt(sbi->s_mount_opt, ERRORS_RO); - - sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); - sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); - - /* enable barriers by default */ - set_opt(sbi->s_mount_opt, BARRIER); - set_opt(sbi->s_mount_opt, RESERVATION); - - if (!parse_options ((char *) data, sb, &journal_inum, &journal_devnum, - NULL, 0)) - goto failed_mount; - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0); - - if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV && - (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) || - EXT3_HAS_RO_COMPAT_FEATURE(sb, ~0U) || - EXT3_HAS_INCOMPAT_FEATURE(sb, ~0U))) - ext3_msg(sb, KERN_WARNING, - "warning: feature flags set on rev 0 fs, " - "running e2fsck is recommended"); - /* - * Check feature flags regardless of the revision level, since we - * previously didn't change the revision level when setting the flags, - * so there is a chance incompat flags are set on a rev 0 filesystem. - */ - features = EXT3_HAS_INCOMPAT_FEATURE(sb, ~EXT3_FEATURE_INCOMPAT_SUPP); - if (features) { - ext3_msg(sb, KERN_ERR, - "error: couldn't mount because of unsupported " - "optional features (%x)", le32_to_cpu(features)); - goto failed_mount; - } - features = EXT3_HAS_RO_COMPAT_FEATURE(sb, ~EXT3_FEATURE_RO_COMPAT_SUPP); - if (!(sb->s_flags & MS_RDONLY) && features) { - ext3_msg(sb, KERN_ERR, - "error: couldn't mount RDWR because of unsupported " - "optional features (%x)", le32_to_cpu(features)); - goto failed_mount; - } - blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); - - if (blocksize < EXT3_MIN_BLOCK_SIZE || - blocksize > EXT3_MAX_BLOCK_SIZE) { - ext3_msg(sb, KERN_ERR, - "error: couldn't mount because of unsupported " - "filesystem blocksize %d", blocksize); - goto failed_mount; - } - - hblock = bdev_logical_block_size(sb->s_bdev); - if (sb->s_blocksize != blocksize) { - /* - * Make sure the blocksize for the filesystem is larger - * than the hardware sectorsize for the machine. - */ - if (blocksize < hblock) { - ext3_msg(sb, KERN_ERR, - "error: fsblocksize %d too small for " - "hardware sectorsize %d", blocksize, hblock); - goto failed_mount; - } - - brelse (bh); - if (!sb_set_blocksize(sb, blocksize)) { - ext3_msg(sb, KERN_ERR, - "error: bad blocksize %d", blocksize); - goto out_fail; - } - logic_sb_block = (sb_block * EXT3_MIN_BLOCK_SIZE) / blocksize; - offset = (sb_block * EXT3_MIN_BLOCK_SIZE) % blocksize; - bh = sb_bread(sb, logic_sb_block); - if (!bh) { - ext3_msg(sb, KERN_ERR, - "error: can't read superblock on 2nd try"); - goto failed_mount; - } - es = (struct ext3_super_block *)(bh->b_data + offset); - sbi->s_es = es; - if (es->s_magic != cpu_to_le16(EXT3_SUPER_MAGIC)) { - ext3_msg(sb, KERN_ERR, - "error: magic mismatch"); - goto failed_mount; - } - } - - sb->s_maxbytes = ext3_max_size(sb->s_blocksize_bits); - - if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) { - sbi->s_inode_size = EXT3_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT3_GOOD_OLD_FIRST_INO; - } else { - sbi->s_inode_size = le16_to_cpu(es->s_inode_size); - sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if ((sbi->s_inode_size < EXT3_GOOD_OLD_INODE_SIZE) || - (!is_power_of_2(sbi->s_inode_size)) || - (sbi->s_inode_size > blocksize)) { - ext3_msg(sb, KERN_ERR, - "error: unsupported inode size: %d", - sbi->s_inode_size); - goto failed_mount; - } - } - sbi->s_frag_size = EXT3_MIN_FRAG_SIZE << - le32_to_cpu(es->s_log_frag_size); - if (blocksize != sbi->s_frag_size) { - ext3_msg(sb, KERN_ERR, - "error: fragsize %lu != blocksize %u (unsupported)", - sbi->s_frag_size, blocksize); - goto failed_mount; - } - sbi->s_frags_per_block = 1; - sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); - sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group); - sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); - if (EXT3_INODE_SIZE(sb) == 0 || EXT3_INODES_PER_GROUP(sb) == 0) - goto cantfind_ext3; - sbi->s_inodes_per_block = blocksize / EXT3_INODE_SIZE(sb); - if (sbi->s_inodes_per_block == 0) - goto cantfind_ext3; - sbi->s_itb_per_group = sbi->s_inodes_per_group / - sbi->s_inodes_per_block; - sbi->s_desc_per_block = blocksize / sizeof(struct ext3_group_desc); - sbi->s_sbh = bh; - sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = ilog2(EXT3_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = ilog2(EXT3_DESC_PER_BLOCK(sb)); - for (i = 0; i < 4; i++) - sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); - sbi->s_def_hash_version = es->s_def_hash_version; - i = le32_to_cpu(es->s_flags); - if (i & EXT2_FLAGS_UNSIGNED_HASH) - sbi->s_hash_unsigned = 3; - else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { -#ifdef __CHAR_UNSIGNED__ - es->s_flags |= cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); - sbi->s_hash_unsigned = 3; -#else - es->s_flags |= cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); -#endif - } - - if (sbi->s_blocks_per_group > blocksize * 8) { - ext3_msg(sb, KERN_ERR, - "#blocks per group too big: %lu", - sbi->s_blocks_per_group); - goto failed_mount; - } - if (sbi->s_frags_per_group > blocksize * 8) { - ext3_msg(sb, KERN_ERR, - "error: #fragments per group too big: %lu", - sbi->s_frags_per_group); - goto failed_mount; - } - if (sbi->s_inodes_per_group > blocksize * 8) { - ext3_msg(sb, KERN_ERR, - "error: #inodes per group too big: %lu", - sbi->s_inodes_per_group); - goto failed_mount; - } - - err = generic_check_addressable(sb->s_blocksize_bits, - le32_to_cpu(es->s_blocks_count)); - if (err) { - ext3_msg(sb, KERN_ERR, - "error: filesystem is too large to mount safely"); - if (sizeof(sector_t) < 8) - ext3_msg(sb, KERN_ERR, - "error: CONFIG_LBDAF not enabled"); - ret = err; - goto failed_mount; - } - - if (EXT3_BLOCKS_PER_GROUP(sb) == 0) - goto cantfind_ext3; - sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) - - le32_to_cpu(es->s_first_data_block) - 1) - / EXT3_BLOCKS_PER_GROUP(sb)) + 1; - db_count = DIV_ROUND_UP(sbi->s_groups_count, EXT3_DESC_PER_BLOCK(sb)); - sbi->s_group_desc = kmalloc(db_count * sizeof (struct buffer_head *), - GFP_KERNEL); - if (sbi->s_group_desc == NULL) { - ext3_msg(sb, KERN_ERR, - "error: not enough memory"); - ret = -ENOMEM; - goto failed_mount; - } - - bgl_lock_init(sbi->s_blockgroup_lock); - - for (i = 0; i < db_count; i++) { - block = descriptor_loc(sb, logic_sb_block, i); - sbi->s_group_desc[i] = sb_bread(sb, block); - if (!sbi->s_group_desc[i]) { - ext3_msg(sb, KERN_ERR, - "error: can't read group descriptor %d", i); - db_count = i; - goto failed_mount2; - } - } - if (!ext3_check_descriptors (sb)) { - ext3_msg(sb, KERN_ERR, - "error: group descriptors corrupted"); - goto failed_mount2; - } - sbi->s_gdb_count = db_count; - get_random_bytes(&sbi->s_next_generation, sizeof(u32)); - spin_lock_init(&sbi->s_next_gen_lock); - - /* per fileystem reservation list head & lock */ - spin_lock_init(&sbi->s_rsv_window_lock); - sbi->s_rsv_window_root = RB_ROOT; - /* Add a single, static dummy reservation to the start of the - * reservation window list --- it gives us a placeholder for - * append-at-start-of-list which makes the allocation logic - * _much_ simpler. */ - sbi->s_rsv_window_head.rsv_start = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_end = EXT3_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_alloc_hit = 0; - sbi->s_rsv_window_head.rsv_goal_size = 0; - ext3_rsv_window_add(sb, &sbi->s_rsv_window_head); - - /* - * set up enough so that it can read an inode - */ - sb->s_op = &ext3_sops; - sb->s_export_op = &ext3_export_ops; - sb->s_xattr = ext3_xattr_handlers; -#ifdef CONFIG_QUOTA - sb->s_qcop = &ext3_qctl_operations; - sb->dq_op = &ext3_quota_operations; - sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP; -#endif - memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); - INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ - mutex_init(&sbi->s_orphan_lock); - mutex_init(&sbi->s_resize_lock); - - sb->s_root = NULL; - - needs_recovery = (es->s_last_orphan != 0 || - EXT3_HAS_INCOMPAT_FEATURE(sb, - EXT3_FEATURE_INCOMPAT_RECOVER)); - - /* - * The first inode we look at is the journal inode. Don't try - * root first: it may be modified in the journal! - */ - if (!test_opt(sb, NOLOAD) && - EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { - if (ext3_load_journal(sb, es, journal_devnum)) - goto failed_mount2; - } else if (journal_inum) { - if (ext3_create_journal(sb, es, journal_inum)) - goto failed_mount2; - } else { - if (!silent) - ext3_msg(sb, KERN_ERR, - "error: no journal found. " - "mounting ext3 over ext2?"); - goto failed_mount2; - } - err = percpu_counter_init(&sbi->s_freeblocks_counter, - ext3_count_free_blocks(sb), GFP_KERNEL); - if (!err) { - err = percpu_counter_init(&sbi->s_freeinodes_counter, - ext3_count_free_inodes(sb), GFP_KERNEL); - } - if (!err) { - err = percpu_counter_init(&sbi->s_dirs_counter, - ext3_count_dirs(sb), GFP_KERNEL); - } - if (err) { - ext3_msg(sb, KERN_ERR, "error: insufficient memory"); - ret = err; - goto failed_mount3; - } - - /* We have now updated the journal if required, so we can - * validate the data journaling mode. */ - switch (test_opt(sb, DATA_FLAGS)) { - case 0: - /* No mode set, assume a default based on the journal - capabilities: ORDERED_DATA if the journal can - cope, else JOURNAL_DATA */ - if (journal_check_available_features - (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) - set_opt(sbi->s_mount_opt, DEFAULT_DATA_MODE); - else - set_opt(sbi->s_mount_opt, JOURNAL_DATA); - break; - - case EXT3_MOUNT_ORDERED_DATA: - case EXT3_MOUNT_WRITEBACK_DATA: - if (!journal_check_available_features - (sbi->s_journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)) { - ext3_msg(sb, KERN_ERR, - "error: journal does not support " - "requested data journaling mode"); - goto failed_mount3; - } - default: - break; - } - - /* - * The journal_load will have done any necessary log recovery, - * so we can safely mount the rest of the filesystem now. - */ - - root = ext3_iget(sb, EXT3_ROOT_INO); - if (IS_ERR(root)) { - ext3_msg(sb, KERN_ERR, "error: get root inode failed"); - ret = PTR_ERR(root); - goto failed_mount3; - } - if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { - iput(root); - ext3_msg(sb, KERN_ERR, "error: corrupt root inode, run e2fsck"); - goto failed_mount3; - } - sb->s_root = d_make_root(root); - if (!sb->s_root) { - ext3_msg(sb, KERN_ERR, "error: get root dentry failed"); - ret = -ENOMEM; - goto failed_mount3; - } - - if (ext3_setup_super(sb, es, sb->s_flags & MS_RDONLY)) - sb->s_flags |= MS_RDONLY; - - EXT3_SB(sb)->s_mount_state |= EXT3_ORPHAN_FS; - ext3_orphan_cleanup(sb, es); - EXT3_SB(sb)->s_mount_state &= ~EXT3_ORPHAN_FS; - if (needs_recovery) { - ext3_mark_recovery_complete(sb, es); - ext3_msg(sb, KERN_INFO, "recovery complete"); - } - ext3_msg(sb, KERN_INFO, "mounted filesystem with %s data mode", - test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_JOURNAL_DATA ? "journal": - test_opt(sb,DATA_FLAGS) == EXT3_MOUNT_ORDERED_DATA ? "ordered": - "writeback"); - - return 0; - -cantfind_ext3: - if (!silent) - ext3_msg(sb, KERN_INFO, - "error: can't find ext3 filesystem on dev %s.", - sb->s_id); - goto failed_mount; - -failed_mount3: - percpu_counter_destroy(&sbi->s_freeblocks_counter); - percpu_counter_destroy(&sbi->s_freeinodes_counter); - percpu_counter_destroy(&sbi->s_dirs_counter); - journal_destroy(sbi->s_journal); -failed_mount2: - for (i = 0; i < db_count; i++) - brelse(sbi->s_group_desc[i]); - kfree(sbi->s_group_desc); -failed_mount: -#ifdef CONFIG_QUOTA - for (i = 0; i < EXT3_MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); -#endif - ext3_blkdev_remove(sbi); - brelse(bh); -out_fail: - sb->s_fs_info = NULL; - kfree(sbi->s_blockgroup_lock); - kfree(sbi); - return ret; -} - -/* - * Setup any per-fs journal parameters now. We'll do this both on - * initial mount, once the journal has been initialised but before we've - * done any recovery; and again on any subsequent remount. - */ -static void ext3_init_journal_params(struct super_block *sb, journal_t *journal) -{ - struct ext3_sb_info *sbi = EXT3_SB(sb); - - if (sbi->s_commit_interval) - journal->j_commit_interval = sbi->s_commit_interval; - /* We could also set up an ext3-specific default for the commit - * interval here, but for now we'll just fall back to the jbd - * default. */ - - spin_lock(&journal->j_state_lock); - if (test_opt(sb, BARRIER)) - journal->j_flags |= JFS_BARRIER; - else - journal->j_flags &= ~JFS_BARRIER; - if (test_opt(sb, DATA_ERR_ABORT)) - journal->j_flags |= JFS_ABORT_ON_SYNCDATA_ERR; - else - journal->j_flags &= ~JFS_ABORT_ON_SYNCDATA_ERR; - spin_unlock(&journal->j_state_lock); -} - -static journal_t *ext3_get_journal(struct super_block *sb, - unsigned int journal_inum) -{ - struct inode *journal_inode; - journal_t *journal; - - /* First, test for the existence of a valid inode on disk. Bad - * things happen if we iget() an unused inode, as the subsequent - * iput() will try to delete it. */ - - journal_inode = ext3_iget(sb, journal_inum); - if (IS_ERR(journal_inode)) { - ext3_msg(sb, KERN_ERR, "error: no journal found"); - return NULL; - } - if (!journal_inode->i_nlink) { - make_bad_inode(journal_inode); - iput(journal_inode); - ext3_msg(sb, KERN_ERR, "error: journal inode is deleted"); - return NULL; - } - - jbd_debug(2, "Journal inode found at %p: %Ld bytes\n", - journal_inode, journal_inode->i_size); - if (!S_ISREG(journal_inode->i_mode)) { - ext3_msg(sb, KERN_ERR, "error: invalid journal inode"); - iput(journal_inode); - return NULL; - } - - journal = journal_init_inode(journal_inode); - if (!journal) { - ext3_msg(sb, KERN_ERR, "error: could not load journal inode"); - iput(journal_inode); - return NULL; - } - journal->j_private = sb; - ext3_init_journal_params(sb, journal); - return journal; -} - -static journal_t *ext3_get_dev_journal(struct super_block *sb, - dev_t j_dev) -{ - struct buffer_head * bh; - journal_t *journal; - ext3_fsblk_t start; - ext3_fsblk_t len; - int hblock, blocksize; - ext3_fsblk_t sb_block; - unsigned long offset; - struct ext3_super_block * es; - struct block_device *bdev; - - bdev = ext3_blkdev_get(j_dev, sb); - if (bdev == NULL) - return NULL; - - blocksize = sb->s_blocksize; - hblock = bdev_logical_block_size(bdev); - if (blocksize < hblock) { - ext3_msg(sb, KERN_ERR, - "error: blocksize too small for journal device"); - goto out_bdev; - } - - sb_block = EXT3_MIN_BLOCK_SIZE / blocksize; - offset = EXT3_MIN_BLOCK_SIZE % blocksize; - set_blocksize(bdev, blocksize); - if (!(bh = __bread(bdev, sb_block, blocksize))) { - ext3_msg(sb, KERN_ERR, "error: couldn't read superblock of " - "external journal"); - goto out_bdev; - } - - es = (struct ext3_super_block *) (bh->b_data + offset); - if ((le16_to_cpu(es->s_magic) != EXT3_SUPER_MAGIC) || - !(le32_to_cpu(es->s_feature_incompat) & - EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { - ext3_msg(sb, KERN_ERR, "error: external journal has " - "bad superblock"); - brelse(bh); - goto out_bdev; - } - - if (memcmp(EXT3_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { - ext3_msg(sb, KERN_ERR, "error: journal UUID does not match"); - brelse(bh); - goto out_bdev; - } - - len = le32_to_cpu(es->s_blocks_count); - start = sb_block + 1; - brelse(bh); /* we're done with the superblock */ - - journal = journal_init_dev(bdev, sb->s_bdev, - start, len, blocksize); - if (!journal) { - ext3_msg(sb, KERN_ERR, - "error: failed to create device journal"); - goto out_bdev; - } - journal->j_private = sb; - if (!bh_uptodate_or_lock(journal->j_sb_buffer)) { - if (bh_submit_read(journal->j_sb_buffer)) { - ext3_msg(sb, KERN_ERR, "I/O error on journal device"); - goto out_journal; - } - } - if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) { - ext3_msg(sb, KERN_ERR, - "error: external journal has more than one " - "user (unsupported) - %d", - be32_to_cpu(journal->j_superblock->s_nr_users)); - goto out_journal; - } - EXT3_SB(sb)->journal_bdev = bdev; - ext3_init_journal_params(sb, journal); - return journal; -out_journal: - journal_destroy(journal); -out_bdev: - ext3_blkdev_put(bdev); - return NULL; -} - -static int ext3_load_journal(struct super_block *sb, - struct ext3_super_block *es, - unsigned long journal_devnum) -{ - journal_t *journal; - unsigned int journal_inum = le32_to_cpu(es->s_journal_inum); - dev_t journal_dev; - int err = 0; - int really_read_only; - - if (journal_devnum && - journal_devnum != le32_to_cpu(es->s_journal_dev)) { - ext3_msg(sb, KERN_INFO, "external journal device major/minor " - "numbers have changed"); - journal_dev = new_decode_dev(journal_devnum); - } else - journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev)); - - really_read_only = bdev_read_only(sb->s_bdev); - - /* - * Are we loading a blank journal or performing recovery after a - * crash? For recovery, we need to check in advance whether we - * can get read-write access to the device. - */ - - if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) { - if (sb->s_flags & MS_RDONLY) { - ext3_msg(sb, KERN_INFO, - "recovery required on readonly filesystem"); - if (really_read_only) { - ext3_msg(sb, KERN_ERR, "error: write access " - "unavailable, cannot proceed"); - return -EROFS; - } - ext3_msg(sb, KERN_INFO, - "write access will be enabled during recovery"); - } - } - - if (journal_inum && journal_dev) { - ext3_msg(sb, KERN_ERR, "error: filesystem has both journal " - "and inode journals"); - return -EINVAL; - } - - if (journal_inum) { - if (!(journal = ext3_get_journal(sb, journal_inum))) - return -EINVAL; - } else { - if (!(journal = ext3_get_dev_journal(sb, journal_dev))) - return -EINVAL; - } - - if (!(journal->j_flags & JFS_BARRIER)) - printk(KERN_INFO "EXT3-fs: barriers not enabled\n"); - - if (!really_read_only && test_opt(sb, UPDATE_JOURNAL)) { - err = journal_update_format(journal); - if (err) { - ext3_msg(sb, KERN_ERR, "error updating journal"); - journal_destroy(journal); - return err; - } - } - - if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER)) - err = journal_wipe(journal, !really_read_only); - if (!err) - err = journal_load(journal); - - if (err) { - ext3_msg(sb, KERN_ERR, "error loading journal"); - journal_destroy(journal); - return err; - } - - EXT3_SB(sb)->s_journal = journal; - ext3_clear_journal_err(sb, es); - - if (!really_read_only && journal_devnum && - journal_devnum != le32_to_cpu(es->s_journal_dev)) { - es->s_journal_dev = cpu_to_le32(journal_devnum); - - /* Make sure we flush the recovery flag to disk. */ - ext3_commit_super(sb, es, 1); - } - - return 0; -} - -static int ext3_create_journal(struct super_block *sb, - struct ext3_super_block *es, - unsigned int journal_inum) -{ - journal_t *journal; - int err; - - if (sb->s_flags & MS_RDONLY) { - ext3_msg(sb, KERN_ERR, - "error: readonly filesystem when trying to " - "create journal"); - return -EROFS; - } - - journal = ext3_get_journal(sb, journal_inum); - if (!journal) - return -EINVAL; - - ext3_msg(sb, KERN_INFO, "creating new journal on inode %u", - journal_inum); - - err = journal_create(journal); - if (err) { - ext3_msg(sb, KERN_ERR, "error creating journal"); - journal_destroy(journal); - return -EIO; - } - - EXT3_SB(sb)->s_journal = journal; - - ext3_update_dynamic_rev(sb); - EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_HAS_JOURNAL); - - es->s_journal_inum = cpu_to_le32(journal_inum); - - /* Make sure we flush the recovery flag to disk. */ - ext3_commit_super(sb, es, 1); - - return 0; -} - -static int ext3_commit_super(struct super_block *sb, - struct ext3_super_block *es, - int sync) -{ - struct buffer_head *sbh = EXT3_SB(sb)->s_sbh; - int error = 0; - - if (!sbh) - return error; - - if (buffer_write_io_error(sbh)) { - /* - * Oh, dear. A previous attempt to write the - * superblock failed. This could happen because the - * USB device was yanked out. Or it could happen to - * be a transient write error and maybe the block will - * be remapped. Nothing we can do but to retry the - * write and hope for the best. - */ - ext3_msg(sb, KERN_ERR, "previous I/O error to " - "superblock detected"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } - /* - * If the file system is mounted read-only, don't update the - * superblock write time. This avoids updating the superblock - * write time when we are mounting the root file system - * read/only but we need to replay the journal; at that point, - * for people who are east of GMT and who make their clock - * tick in localtime for Windows bug-for-bug compatibility, - * the clock is set in the future, and this will cause e2fsck - * to complain and force a full file system check. - */ - if (!(sb->s_flags & MS_RDONLY)) - es->s_wtime = cpu_to_le32(get_seconds()); - es->s_free_blocks_count = cpu_to_le32(ext3_count_free_blocks(sb)); - es->s_free_inodes_count = cpu_to_le32(ext3_count_free_inodes(sb)); - BUFFER_TRACE(sbh, "marking dirty"); - mark_buffer_dirty(sbh); - if (sync) { - error = sync_dirty_buffer(sbh); - if (buffer_write_io_error(sbh)) { - ext3_msg(sb, KERN_ERR, "I/O error while writing " - "superblock"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } - } - return error; -} - - -/* - * Have we just finished recovery? If so, and if we are mounting (or - * remounting) the filesystem readonly, then we will end up with a - * consistent fs on disk. Record that fact. - */ -static void ext3_mark_recovery_complete(struct super_block * sb, - struct ext3_super_block * es) -{ - journal_t *journal = EXT3_SB(sb)->s_journal; - - journal_lock_updates(journal); - if (journal_flush(journal) < 0) - goto out; - - if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER) && - sb->s_flags & MS_RDONLY) { - EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - ext3_commit_super(sb, es, 1); - } - -out: - journal_unlock_updates(journal); -} - -/* - * If we are mounting (or read-write remounting) a filesystem whose journal - * has recorded an error from a previous lifetime, move that error to the - * main filesystem now. - */ -static void ext3_clear_journal_err(struct super_block *sb, - struct ext3_super_block *es) -{ - journal_t *journal; - int j_errno; - const char *errstr; - - journal = EXT3_SB(sb)->s_journal; - - /* - * Now check for any error status which may have been recorded in the - * journal by a prior ext3_error() or ext3_abort() - */ - - j_errno = journal_errno(journal); - if (j_errno) { - char nbuf[16]; - - errstr = ext3_decode_error(sb, j_errno, nbuf); - ext3_warning(sb, __func__, "Filesystem error recorded " - "from previous mount: %s", errstr); - ext3_warning(sb, __func__, "Marking fs in need of " - "filesystem check."); - - EXT3_SB(sb)->s_mount_state |= EXT3_ERROR_FS; - es->s_state |= cpu_to_le16(EXT3_ERROR_FS); - ext3_commit_super (sb, es, 1); - - journal_clear_err(journal); - } -} - -/* - * Force the running and committing transactions to commit, - * and wait on the commit. - */ -int ext3_force_commit(struct super_block *sb) -{ - journal_t *journal; - int ret; - - if (sb->s_flags & MS_RDONLY) - return 0; - - journal = EXT3_SB(sb)->s_journal; - ret = ext3_journal_force_commit(journal); - return ret; -} - -static int ext3_sync_fs(struct super_block *sb, int wait) -{ - tid_t target; - - trace_ext3_sync_fs(sb, wait); - /* - * Writeback quota in non-journalled quota case - journalled quota has - * no dirty dquots - */ - dquot_writeback_dquots(sb, -1); - if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { - if (wait) - log_wait_commit(EXT3_SB(sb)->s_journal, target); - } - return 0; -} - -/* - * LVM calls this function before a (read-only) snapshot is created. This - * gives us a chance to flush the journal completely and mark the fs clean. - */ -static int ext3_freeze(struct super_block *sb) -{ - int error = 0; - journal_t *journal; - - if (!(sb->s_flags & MS_RDONLY)) { - journal = EXT3_SB(sb)->s_journal; - - /* Now we set up the journal barrier. */ - journal_lock_updates(journal); - - /* - * We don't want to clear needs_recovery flag when we failed - * to flush the journal. - */ - error = journal_flush(journal); - if (error < 0) - goto out; - - /* Journal blocked and flushed, clear needs_recovery flag. */ - EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - error = ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); - if (error) - goto out; - } - return 0; - -out: - journal_unlock_updates(journal); - return error; -} - -/* - * Called by LVM after the snapshot is done. We need to reset the RECOVER - * flag here, even though the filesystem is not technically dirty yet. - */ -static int ext3_unfreeze(struct super_block *sb) -{ - if (!(sb->s_flags & MS_RDONLY)) { - /* Reser the needs_recovery flag before the fs is unlocked. */ - EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); - ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); - journal_unlock_updates(EXT3_SB(sb)->s_journal); - } - return 0; -} - -static int ext3_remount (struct super_block * sb, int * flags, char * data) -{ - struct ext3_super_block * es; - struct ext3_sb_info *sbi = EXT3_SB(sb); - ext3_fsblk_t n_blocks_count = 0; - unsigned long old_sb_flags; - struct ext3_mount_options old_opts; - int enable_quota = 0; - int err; -#ifdef CONFIG_QUOTA - int i; -#endif - - sync_filesystem(sb); - - /* Store the original options */ - old_sb_flags = sb->s_flags; - old_opts.s_mount_opt = sbi->s_mount_opt; - old_opts.s_resuid = sbi->s_resuid; - old_opts.s_resgid = sbi->s_resgid; - old_opts.s_commit_interval = sbi->s_commit_interval; -#ifdef CONFIG_QUOTA - old_opts.s_jquota_fmt = sbi->s_jquota_fmt; - for (i = 0; i < EXT3_MAXQUOTAS; i++) - if (sbi->s_qf_names[i]) { - old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], - GFP_KERNEL); - if (!old_opts.s_qf_names[i]) { - int j; - - for (j = 0; j < i; j++) - kfree(old_opts.s_qf_names[j]); - return -ENOMEM; - } - } else - old_opts.s_qf_names[i] = NULL; -#endif - - /* - * Allow the "check" option to be passed as a remount option. - */ - if (!parse_options(data, sb, NULL, NULL, &n_blocks_count, 1)) { - err = -EINVAL; - goto restore_opts; - } - - if (test_opt(sb, ABORT)) - ext3_abort(sb, __func__, "Abort forced by user"); - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0); - - es = sbi->s_es; - - ext3_init_journal_params(sb, sbi->s_journal); - - if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) || - n_blocks_count > le32_to_cpu(es->s_blocks_count)) { - if (test_opt(sb, ABORT)) { - err = -EROFS; - goto restore_opts; - } - - if (*flags & MS_RDONLY) { - err = dquot_suspend(sb, -1); - if (err < 0) - goto restore_opts; - - /* - * First of all, the unconditional stuff we have to do - * to disable replay of the journal when we next remount - */ - sb->s_flags |= MS_RDONLY; - - /* - * OK, test if we are remounting a valid rw partition - * readonly, and if so set the rdonly flag and then - * mark the partition as valid again. - */ - if (!(es->s_state & cpu_to_le16(EXT3_VALID_FS)) && - (sbi->s_mount_state & EXT3_VALID_FS)) - es->s_state = cpu_to_le16(sbi->s_mount_state); - - ext3_mark_recovery_complete(sb, es); - } else { - __le32 ret; - if ((ret = EXT3_HAS_RO_COMPAT_FEATURE(sb, - ~EXT3_FEATURE_RO_COMPAT_SUPP))) { - ext3_msg(sb, KERN_WARNING, - "warning: couldn't remount RDWR " - "because of unsupported optional " - "features (%x)", le32_to_cpu(ret)); - err = -EROFS; - goto restore_opts; - } - - /* - * If we have an unprocessed orphan list hanging - * around from a previously readonly bdev mount, - * require a full umount & mount for now. - */ - if (es->s_last_orphan) { - ext3_msg(sb, KERN_WARNING, "warning: couldn't " - "remount RDWR because of unprocessed " - "orphan inode list. Please " - "umount & mount instead."); - err = -EINVAL; - goto restore_opts; - } - - /* - * Mounting a RDONLY partition read-write, so reread - * and store the current valid flag. (It may have - * been changed by e2fsck since we originally mounted - * the partition.) - */ - ext3_clear_journal_err(sb, es); - sbi->s_mount_state = le16_to_cpu(es->s_state); - if ((err = ext3_group_extend(sb, es, n_blocks_count))) - goto restore_opts; - if (!ext3_setup_super (sb, es, 0)) - sb->s_flags &= ~MS_RDONLY; - enable_quota = 1; - } - } -#ifdef CONFIG_QUOTA - /* Release old quota file names */ - for (i = 0; i < EXT3_MAXQUOTAS; i++) - kfree(old_opts.s_qf_names[i]); -#endif - if (enable_quota) - dquot_resume(sb, -1); - return 0; -restore_opts: - sb->s_flags = old_sb_flags; - sbi->s_mount_opt = old_opts.s_mount_opt; - sbi->s_resuid = old_opts.s_resuid; - sbi->s_resgid = old_opts.s_resgid; - sbi->s_commit_interval = old_opts.s_commit_interval; -#ifdef CONFIG_QUOTA - sbi->s_jquota_fmt = old_opts.s_jquota_fmt; - for (i = 0; i < EXT3_MAXQUOTAS; i++) { - kfree(sbi->s_qf_names[i]); - sbi->s_qf_names[i] = old_opts.s_qf_names[i]; - } -#endif - return err; -} - -static int ext3_statfs (struct dentry * dentry, struct kstatfs * buf) -{ - struct super_block *sb = dentry->d_sb; - struct ext3_sb_info *sbi = EXT3_SB(sb); - struct ext3_super_block *es = sbi->s_es; - u64 fsid; - - if (test_opt(sb, MINIX_DF)) { - sbi->s_overhead_last = 0; - } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) { - unsigned long ngroups = sbi->s_groups_count, i; - ext3_fsblk_t overhead = 0; - smp_rmb(); - - /* - * Compute the overhead (FS structures). This is constant - * for a given filesystem unless the number of block groups - * changes so we cache the previous value until it does. - */ - - /* - * All of the blocks before first_data_block are - * overhead - */ - overhead = le32_to_cpu(es->s_first_data_block); - - /* - * Add the overhead attributed to the superblock and - * block group descriptors. If the sparse superblocks - * feature is turned on, then not all groups have this. - */ - for (i = 0; i < ngroups; i++) { - overhead += ext3_bg_has_super(sb, i) + - ext3_bg_num_gdb(sb, i); - cond_resched(); - } - - /* - * Every block group has an inode bitmap, a block - * bitmap, and an inode table. - */ - overhead += ngroups * (2 + sbi->s_itb_per_group); - - /* Add the internal journal blocks as well */ - if (sbi->s_journal && !sbi->journal_bdev) - overhead += sbi->s_journal->j_maxlen; - - sbi->s_overhead_last = overhead; - smp_wmb(); - sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count); - } - - buf->f_type = EXT3_SUPER_MAGIC; - buf->f_bsize = sb->s_blocksize; - buf->f_blocks = le32_to_cpu(es->s_blocks_count) - sbi->s_overhead_last; - buf->f_bfree = percpu_counter_sum_positive(&sbi->s_freeblocks_counter); - buf->f_bavail = buf->f_bfree - le32_to_cpu(es->s_r_blocks_count); - if (buf->f_bfree < le32_to_cpu(es->s_r_blocks_count)) - buf->f_bavail = 0; - buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); - buf->f_namelen = EXT3_NAME_LEN; - fsid = le64_to_cpup((void *)es->s_uuid) ^ - le64_to_cpup((void *)es->s_uuid + sizeof(u64)); - buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; - buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; - return 0; -} - -/* Helper function for writing quotas on sync - we need to start transaction before quota file - * is locked for write. Otherwise the are possible deadlocks: - * Process 1 Process 2 - * ext3_create() quota_sync() - * journal_start() write_dquot() - * dquot_initialize() down(dqio_mutex) - * down(dqio_mutex) journal_start() - * - */ - -#ifdef CONFIG_QUOTA - -static inline struct inode *dquot_to_inode(struct dquot *dquot) -{ - return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type]; -} - -static int ext3_write_dquot(struct dquot *dquot) -{ - int ret, err; - handle_t *handle; - struct inode *inode; - - inode = dquot_to_inode(dquot); - handle = ext3_journal_start(inode, - EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_commit(dquot); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext3_acquire_dquot(struct dquot *dquot) -{ - int ret, err; - handle_t *handle; - - handle = ext3_journal_start(dquot_to_inode(dquot), - EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_acquire(dquot); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext3_release_dquot(struct dquot *dquot) -{ - int ret, err; - handle_t *handle; - - handle = ext3_journal_start(dquot_to_inode(dquot), - EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) { - /* Release dquot anyway to avoid endless cycle in dqput() */ - dquot_release(dquot); - return PTR_ERR(handle); - } - ret = dquot_release(dquot); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext3_mark_dquot_dirty(struct dquot *dquot) -{ - /* Are we journaling quotas? */ - if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || - EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { - dquot_mark_dquot_dirty(dquot); - return ext3_write_dquot(dquot); - } else { - return dquot_mark_dquot_dirty(dquot); - } -} - -static int ext3_write_info(struct super_block *sb, int type) -{ - int ret, err; - handle_t *handle; - - /* Data block + inode block */ - handle = ext3_journal_start(d_inode(sb->s_root), 2); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_commit_info(sb, type); - err = ext3_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -/* - * Turn on quotas during mount time - we need to find - * the quota file and such... - */ -static int ext3_quota_on_mount(struct super_block *sb, int type) -{ - return dquot_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type], - EXT3_SB(sb)->s_jquota_fmt, type); -} - -/* - * Standard function to be called on quota_on - */ -static int ext3_quota_on(struct super_block *sb, int type, int format_id, - struct path *path) -{ - int err; - - if (!test_opt(sb, QUOTA)) - return -EINVAL; - - /* Quotafile not on the same filesystem? */ - if (path->dentry->d_sb != sb) - return -EXDEV; - /* Journaling quota? */ - if (EXT3_SB(sb)->s_qf_names[type]) { - /* Quotafile not of fs root? */ - if (path->dentry->d_parent != sb->s_root) - ext3_msg(sb, KERN_WARNING, - "warning: Quota file not on filesystem root. " - "Journaled quota will not work."); - } - - /* - * When we journal data on quota file, we have to flush journal to see - * all updates to the file when we bypass pagecache... - */ - if (ext3_should_journal_data(d_inode(path->dentry))) { - /* - * We don't need to lock updates but journal_flush() could - * otherwise be livelocked... - */ - journal_lock_updates(EXT3_SB(sb)->s_journal); - err = journal_flush(EXT3_SB(sb)->s_journal); - journal_unlock_updates(EXT3_SB(sb)->s_journal); - if (err) - return err; - } - - return dquot_quota_on(sb, type, format_id, path); -} - -/* Read data from quotafile - avoid pagecache and such because we cannot afford - * acquiring the locks... As quota files are never truncated and quota code - * itself serializes the operations (and no one else should touch the files) - * we don't have to be afraid of races */ -static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, - size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); - int err = 0; - int offset = off & (sb->s_blocksize - 1); - int tocopy; - size_t toread; - struct buffer_head *bh; - loff_t i_size = i_size_read(inode); - - if (off > i_size) - return 0; - if (off+len > i_size) - len = i_size-off; - toread = len; - while (toread > 0) { - tocopy = sb->s_blocksize - offset < toread ? - sb->s_blocksize - offset : toread; - bh = ext3_bread(NULL, inode, blk, 0, &err); - if (err) - return err; - if (!bh) /* A hole? */ - memset(data, 0, tocopy); - else - memcpy(data, bh->b_data+offset, tocopy); - brelse(bh); - offset = 0; - toread -= tocopy; - data += tocopy; - blk++; - } - return len; -} - -/* Write to quotafile (we know the transaction is already started and has - * enough credits) */ -static ssize_t ext3_quota_write(struct super_block *sb, int type, - const char *data, size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); - int err = 0; - int offset = off & (sb->s_blocksize - 1); - int journal_quota = EXT3_SB(sb)->s_qf_names[type] != NULL; - struct buffer_head *bh; - handle_t *handle = journal_current_handle(); - - if (!handle) { - ext3_msg(sb, KERN_WARNING, - "warning: quota write (off=%llu, len=%llu)" - " cancelled because transaction is not started.", - (unsigned long long)off, (unsigned long long)len); - return -EIO; - } - - /* - * Since we account only one data block in transaction credits, - * then it is impossible to cross a block boundary. - */ - if (sb->s_blocksize - offset < len) { - ext3_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)" - " cancelled because not block aligned", - (unsigned long long)off, (unsigned long long)len); - return -EIO; - } - bh = ext3_bread(handle, inode, blk, 1, &err); - if (!bh) - goto out; - if (journal_quota) { - err = ext3_journal_get_write_access(handle, bh); - if (err) { - brelse(bh); - goto out; - } - } - lock_buffer(bh); - memcpy(bh->b_data+offset, data, len); - flush_dcache_page(bh->b_page); - unlock_buffer(bh); - if (journal_quota) - err = ext3_journal_dirty_metadata(handle, bh); - else { - /* Always do at least ordered writes for quotas */ - err = ext3_journal_dirty_data(handle, bh); - mark_buffer_dirty(bh); - } - brelse(bh); -out: - if (err) - return err; - if (inode->i_size < off + len) { - i_size_write(inode, off + len); - EXT3_I(inode)->i_disksize = inode->i_size; - } - inode->i_version++; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - ext3_mark_inode_dirty(handle, inode); - return len; -} - -#endif - -static struct dentry *ext3_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_bdev(fs_type, flags, dev_name, data, ext3_fill_super); -} - -static struct file_system_type ext3_fs_type = { - .owner = THIS_MODULE, - .name = "ext3", - .mount = ext3_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -MODULE_ALIAS_FS("ext3"); - -static int __init init_ext3_fs(void) -{ - int err = init_ext3_xattr(); - if (err) - return err; - err = init_inodecache(); - if (err) - goto out1; - err = register_filesystem(&ext3_fs_type); - if (err) - goto out; - return 0; -out: - destroy_inodecache(); -out1: - exit_ext3_xattr(); - return err; -} - -static void __exit exit_ext3_fs(void) -{ - unregister_filesystem(&ext3_fs_type); - destroy_inodecache(); - exit_ext3_xattr(); -} - -MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); -MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); -MODULE_LICENSE("GPL"); -module_init(init_ext3_fs) -module_exit(exit_ext3_fs) diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c deleted file mode 100644 index c08c59094ae61..0000000000000 --- a/fs/ext3/symlink.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * linux/fs/ext3/symlink.c - * - * Only fast symlinks left here - the rest is done by generic code. AV, 1999 - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/symlink.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext3 symlink handling code - */ - -#include "ext3.h" -#include "xattr.h" - -const struct inode_operations ext3_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = page_follow_link_light, - .put_link = page_put_link, - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, - .removexattr = generic_removexattr, -#endif -}; - -const struct inode_operations ext3_fast_symlink_inode_operations = { - .readlink = generic_readlink, - .follow_link = simple_follow_link, - .setattr = ext3_setattr, -#ifdef CONFIG_EXT3_FS_XATTR - .setxattr = generic_setxattr, - .getxattr = generic_getxattr, - .listxattr = ext3_listxattr, - .removexattr = generic_removexattr, -#endif -}; diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c deleted file mode 100644 index 7cf36501ccf46..0000000000000 --- a/fs/ext3/xattr.c +++ /dev/null @@ -1,1330 +0,0 @@ -/* - * linux/fs/ext3/xattr.c - * - * Copyright (C) 2001-2003 Andreas Gruenbacher, - * - * Fix by Harrison Xing . - * Ext3 code with a lot of help from Eric Jarman . - * Extended attributes for symlinks and special files added per - * suggestion of Luka Renko . - * xattr consolidation Copyright (c) 2004 James Morris , - * Red Hat Inc. - * ea-in-inode support by Alex Tomas aka bzzz - * and Andreas Gruenbacher . - */ - -/* - * Extended attributes are stored directly in inodes (on file systems with - * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl - * field contains the block number if an inode uses an additional block. All - * attributes must fit in the inode and one additional block. Blocks that - * contain the identical set of attributes may be shared among several inodes. - * Identical blocks are detected by keeping a cache of blocks that have - * recently been accessed. - * - * The attributes in inodes and on blocks have a different header; the entries - * are stored in the same format: - * - * +------------------+ - * | header | - * | entry 1 | | - * | entry 2 | | growing downwards - * | entry 3 | v - * | four null bytes | - * | . . . | - * | value 1 | ^ - * | value 3 | | growing upwards - * | value 2 | | - * +------------------+ - * - * The header is followed by multiple entry descriptors. In disk blocks, the - * entry descriptors are kept sorted. In inodes, they are unsorted. The - * attribute values are aligned to the end of the block in no specific order. - * - * Locking strategy - * ---------------- - * EXT3_I(inode)->i_file_acl is protected by EXT3_I(inode)->xattr_sem. - * EA blocks are only changed if they are exclusive to an inode, so - * holding xattr_sem also means that nothing but the EA block's reference - * count can change. Multiple writers to the same block are synchronized - * by the buffer lock. - */ - -#include "ext3.h" -#include -#include -#include "xattr.h" -#include "acl.h" - -#define BHDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) -#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) -#define BFIRST(bh) ENTRY(BHDR(bh)+1) -#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) - -#define IHDR(inode, raw_inode) \ - ((struct ext3_xattr_ibody_header *) \ - ((void *)raw_inode + \ - EXT3_GOOD_OLD_INODE_SIZE + \ - EXT3_I(inode)->i_extra_isize)) -#define IFIRST(hdr) ((struct ext3_xattr_entry *)((hdr)+1)) - -#ifdef EXT3_XATTR_DEBUG -# define ea_idebug(inode, f...) do { \ - printk(KERN_DEBUG "inode %s:%lu: ", \ - inode->i_sb->s_id, inode->i_ino); \ - printk(f); \ - printk("\n"); \ - } while (0) -# define ea_bdebug(bh, f...) do { \ - char b[BDEVNAME_SIZE]; \ - printk(KERN_DEBUG "block %s:%lu: ", \ - bdevname(bh->b_bdev, b), \ - (unsigned long) bh->b_blocknr); \ - printk(f); \ - printk("\n"); \ - } while (0) -#else -# define ea_idebug(f...) -# define ea_bdebug(f...) -#endif - -static void ext3_xattr_cache_insert(struct buffer_head *); -static struct buffer_head *ext3_xattr_cache_find(struct inode *, - struct ext3_xattr_header *, - struct mb_cache_entry **); -static void ext3_xattr_rehash(struct ext3_xattr_header *, - struct ext3_xattr_entry *); -static int ext3_xattr_list(struct dentry *dentry, char *buffer, - size_t buffer_size); - -static struct mb_cache *ext3_xattr_cache; - -static const struct xattr_handler *ext3_xattr_handler_map[] = { - [EXT3_XATTR_INDEX_USER] = &ext3_xattr_user_handler, -#ifdef CONFIG_EXT3_FS_POSIX_ACL - [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, - [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, -#endif - [EXT3_XATTR_INDEX_TRUSTED] = &ext3_xattr_trusted_handler, -#ifdef CONFIG_EXT3_FS_SECURITY - [EXT3_XATTR_INDEX_SECURITY] = &ext3_xattr_security_handler, -#endif -}; - -const struct xattr_handler *ext3_xattr_handlers[] = { - &ext3_xattr_user_handler, - &ext3_xattr_trusted_handler, -#ifdef CONFIG_EXT3_FS_POSIX_ACL - &posix_acl_access_xattr_handler, - &posix_acl_default_xattr_handler, -#endif -#ifdef CONFIG_EXT3_FS_SECURITY - &ext3_xattr_security_handler, -#endif - NULL -}; - -static inline const struct xattr_handler * -ext3_xattr_handler(int name_index) -{ - const struct xattr_handler *handler = NULL; - - if (name_index > 0 && name_index < ARRAY_SIZE(ext3_xattr_handler_map)) - handler = ext3_xattr_handler_map[name_index]; - return handler; -} - -/* - * Inode operation listxattr() - * - * d_inode(dentry)->i_mutex: don't care - */ -ssize_t -ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - return ext3_xattr_list(dentry, buffer, size); -} - -static int -ext3_xattr_check_names(struct ext3_xattr_entry *entry, void *end) -{ - while (!IS_LAST_ENTRY(entry)) { - struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(entry); - if ((void *)next >= end) - return -EIO; - entry = next; - } - return 0; -} - -static inline int -ext3_xattr_check_block(struct buffer_head *bh) -{ - int error; - - if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || - BHDR(bh)->h_blocks != cpu_to_le32(1)) - return -EIO; - error = ext3_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size); - return error; -} - -static inline int -ext3_xattr_check_entry(struct ext3_xattr_entry *entry, size_t size) -{ - size_t value_size = le32_to_cpu(entry->e_value_size); - - if (entry->e_value_block != 0 || value_size > size || - le16_to_cpu(entry->e_value_offs) + value_size > size) - return -EIO; - return 0; -} - -static int -ext3_xattr_find_entry(struct ext3_xattr_entry **pentry, int name_index, - const char *name, size_t size, int sorted) -{ - struct ext3_xattr_entry *entry; - size_t name_len; - int cmp = 1; - - if (name == NULL) - return -EINVAL; - name_len = strlen(name); - entry = *pentry; - for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) { - cmp = name_index - entry->e_name_index; - if (!cmp) - cmp = name_len - entry->e_name_len; - if (!cmp) - cmp = memcmp(name, entry->e_name, name_len); - if (cmp <= 0 && (sorted || cmp == 0)) - break; - } - *pentry = entry; - if (!cmp && ext3_xattr_check_entry(entry, size)) - return -EIO; - return cmp ? -ENODATA : 0; -} - -static int -ext3_xattr_block_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - struct buffer_head *bh = NULL; - struct ext3_xattr_entry *entry; - size_t size; - int error; - - ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", - name_index, name, buffer, (long)buffer_size); - - error = -ENODATA; - if (!EXT3_I(inode)->i_file_acl) - goto cleanup; - ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext3_xattr_check_block(bh)) { -bad_block: ext3_error(inode->i_sb, __func__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); - error = -EIO; - goto cleanup; - } - ext3_xattr_cache_insert(bh); - entry = BFIRST(bh); - error = ext3_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); - if (error == -EIO) - goto bad_block; - if (error) - goto cleanup; - size = le32_to_cpu(entry->e_value_size); - if (buffer) { - error = -ERANGE; - if (size > buffer_size) - goto cleanup; - memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), - size); - } - error = size; - -cleanup: - brelse(bh); - return error; -} - -static int -ext3_xattr_ibody_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - struct ext3_xattr_ibody_header *header; - struct ext3_xattr_entry *entry; - struct ext3_inode *raw_inode; - struct ext3_iloc iloc; - size_t size; - void *end; - int error; - - if (!ext3_test_inode_state(inode, EXT3_STATE_XATTR)) - return -ENODATA; - error = ext3_get_inode_loc(inode, &iloc); - if (error) - return error; - raw_inode = ext3_raw_inode(&iloc); - header = IHDR(inode, raw_inode); - entry = IFIRST(header); - end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; - error = ext3_xattr_check_names(entry, end); - if (error) - goto cleanup; - error = ext3_xattr_find_entry(&entry, name_index, name, - end - (void *)entry, 0); - if (error) - goto cleanup; - size = le32_to_cpu(entry->e_value_size); - if (buffer) { - error = -ERANGE; - if (size > buffer_size) - goto cleanup; - memcpy(buffer, (void *)IFIRST(header) + - le16_to_cpu(entry->e_value_offs), size); - } - error = size; - -cleanup: - brelse(iloc.bh); - return error; -} - -/* - * ext3_xattr_get() - * - * Copy an extended attribute into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. - * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. - */ -int -ext3_xattr_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - int error; - - down_read(&EXT3_I(inode)->xattr_sem); - error = ext3_xattr_ibody_get(inode, name_index, name, buffer, - buffer_size); - if (error == -ENODATA) - error = ext3_xattr_block_get(inode, name_index, name, buffer, - buffer_size); - up_read(&EXT3_I(inode)->xattr_sem); - return error; -} - -static int -ext3_xattr_list_entries(struct dentry *dentry, struct ext3_xattr_entry *entry, - char *buffer, size_t buffer_size) -{ - size_t rest = buffer_size; - - for (; !IS_LAST_ENTRY(entry); entry = EXT3_XATTR_NEXT(entry)) { - const struct xattr_handler *handler = - ext3_xattr_handler(entry->e_name_index); - - if (handler) { - size_t size = handler->list(dentry, buffer, rest, - entry->e_name, - entry->e_name_len, - handler->flags); - if (buffer) { - if (size > rest) - return -ERANGE; - buffer += size; - } - rest -= size; - } - } - return buffer_size - rest; -} - -static int -ext3_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - struct inode *inode = d_inode(dentry); - struct buffer_head *bh = NULL; - int error; - - ea_idebug(inode, "buffer=%p, buffer_size=%ld", - buffer, (long)buffer_size); - - error = 0; - if (!EXT3_I(inode)->i_file_acl) - goto cleanup; - ea_idebug(inode, "reading block %u", EXT3_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); - error = -EIO; - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext3_xattr_check_block(bh)) { - ext3_error(inode->i_sb, __func__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); - error = -EIO; - goto cleanup; - } - ext3_xattr_cache_insert(bh); - error = ext3_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size); - -cleanup: - brelse(bh); - - return error; -} - -static int -ext3_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - struct inode *inode = d_inode(dentry); - struct ext3_xattr_ibody_header *header; - struct ext3_inode *raw_inode; - struct ext3_iloc iloc; - void *end; - int error; - - if (!ext3_test_inode_state(inode, EXT3_STATE_XATTR)) - return 0; - error = ext3_get_inode_loc(inode, &iloc); - if (error) - return error; - raw_inode = ext3_raw_inode(&iloc); - header = IHDR(inode, raw_inode); - end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; - error = ext3_xattr_check_names(IFIRST(header), end); - if (error) - goto cleanup; - error = ext3_xattr_list_entries(dentry, IFIRST(header), - buffer, buffer_size); - -cleanup: - brelse(iloc.bh); - return error; -} - -/* - * ext3_xattr_list() - * - * Copy a list of attribute names into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. - * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. - */ -static int -ext3_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - int i_error, b_error; - - down_read(&EXT3_I(d_inode(dentry))->xattr_sem); - i_error = ext3_xattr_ibody_list(dentry, buffer, buffer_size); - if (i_error < 0) { - b_error = 0; - } else { - if (buffer) { - buffer += i_error; - buffer_size -= i_error; - } - b_error = ext3_xattr_block_list(dentry, buffer, buffer_size); - if (b_error < 0) - i_error = 0; - } - up_read(&EXT3_I(d_inode(dentry))->xattr_sem); - return i_error + b_error; -} - -/* - * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is - * not set, set it. - */ -static void ext3_xattr_update_super_block(handle_t *handle, - struct super_block *sb) -{ - if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) - return; - - if (ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh) == 0) { - EXT3_SET_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR); - ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); - } -} - -/* - * Release the xattr block BH: If the reference count is > 1, decrement - * it; otherwise free the block. - */ -static void -ext3_xattr_release_block(handle_t *handle, struct inode *inode, - struct buffer_head *bh) -{ - struct mb_cache_entry *ce = NULL; - int error = 0; - - ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_bdev, bh->b_blocknr); - error = ext3_journal_get_write_access(handle, bh); - if (error) - goto out; - - lock_buffer(bh); - - if (BHDR(bh)->h_refcount == cpu_to_le32(1)) { - ea_bdebug(bh, "refcount now=0; freeing"); - if (ce) - mb_cache_entry_free(ce); - ext3_free_blocks(handle, inode, bh->b_blocknr, 1); - get_bh(bh); - ext3_forget(handle, 1, inode, bh, bh->b_blocknr); - } else { - le32_add_cpu(&BHDR(bh)->h_refcount, -1); - error = ext3_journal_dirty_metadata(handle, bh); - if (IS_SYNC(inode)) - handle->h_sync = 1; - dquot_free_block(inode, 1); - ea_bdebug(bh, "refcount now=%d; releasing", - le32_to_cpu(BHDR(bh)->h_refcount)); - if (ce) - mb_cache_entry_release(ce); - } - unlock_buffer(bh); -out: - ext3_std_error(inode->i_sb, error); - return; -} - -struct ext3_xattr_info { - int name_index; - const char *name; - const void *value; - size_t value_len; -}; - -struct ext3_xattr_search { - struct ext3_xattr_entry *first; - void *base; - void *end; - struct ext3_xattr_entry *here; - int not_found; -}; - -static int -ext3_xattr_set_entry(struct ext3_xattr_info *i, struct ext3_xattr_search *s) -{ - struct ext3_xattr_entry *last; - size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); - - /* Compute min_offs and last. */ - last = s->first; - for (; !IS_LAST_ENTRY(last); last = EXT3_XATTR_NEXT(last)) { - if (!last->e_value_block && last->e_value_size) { - size_t offs = le16_to_cpu(last->e_value_offs); - if (offs < min_offs) - min_offs = offs; - } - } - free = min_offs - ((void *)last - s->base) - sizeof(__u32); - if (!s->not_found) { - if (!s->here->e_value_block && s->here->e_value_size) { - size_t size = le32_to_cpu(s->here->e_value_size); - free += EXT3_XATTR_SIZE(size); - } - free += EXT3_XATTR_LEN(name_len); - } - if (i->value) { - if (free < EXT3_XATTR_LEN(name_len) + - EXT3_XATTR_SIZE(i->value_len)) - return -ENOSPC; - } - - if (i->value && s->not_found) { - /* Insert the new name. */ - size_t size = EXT3_XATTR_LEN(name_len); - size_t rest = (void *)last - (void *)s->here + sizeof(__u32); - memmove((void *)s->here + size, s->here, rest); - memset(s->here, 0, size); - s->here->e_name_index = i->name_index; - s->here->e_name_len = name_len; - memcpy(s->here->e_name, i->name, name_len); - } else { - if (!s->here->e_value_block && s->here->e_value_size) { - void *first_val = s->base + min_offs; - size_t offs = le16_to_cpu(s->here->e_value_offs); - void *val = s->base + offs; - size_t size = EXT3_XATTR_SIZE( - le32_to_cpu(s->here->e_value_size)); - - if (i->value && size == EXT3_XATTR_SIZE(i->value_len)) { - /* The old and the new value have the same - size. Just replace. */ - s->here->e_value_size = - cpu_to_le32(i->value_len); - memset(val + size - EXT3_XATTR_PAD, 0, - EXT3_XATTR_PAD); /* Clear pad bytes. */ - memcpy(val, i->value, i->value_len); - return 0; - } - - /* Remove the old value. */ - memmove(first_val + size, first_val, val - first_val); - memset(first_val, 0, size); - s->here->e_value_size = 0; - s->here->e_value_offs = 0; - min_offs += size; - - /* Adjust all value offsets. */ - last = s->first; - while (!IS_LAST_ENTRY(last)) { - size_t o = le16_to_cpu(last->e_value_offs); - if (!last->e_value_block && - last->e_value_size && o < offs) - last->e_value_offs = - cpu_to_le16(o + size); - last = EXT3_XATTR_NEXT(last); - } - } - if (!i->value) { - /* Remove the old name. */ - size_t size = EXT3_XATTR_LEN(name_len); - last = ENTRY((void *)last - size); - memmove(s->here, (void *)s->here + size, - (void *)last - (void *)s->here + sizeof(__u32)); - memset(last, 0, size); - } - } - - if (i->value) { - /* Insert the new value. */ - s->here->e_value_size = cpu_to_le32(i->value_len); - if (i->value_len) { - size_t size = EXT3_XATTR_SIZE(i->value_len); - void *val = s->base + min_offs - size; - s->here->e_value_offs = cpu_to_le16(min_offs - size); - memset(val + size - EXT3_XATTR_PAD, 0, - EXT3_XATTR_PAD); /* Clear the pad bytes. */ - memcpy(val, i->value, i->value_len); - } - } - return 0; -} - -struct ext3_xattr_block_find { - struct ext3_xattr_search s; - struct buffer_head *bh; -}; - -static int -ext3_xattr_block_find(struct inode *inode, struct ext3_xattr_info *i, - struct ext3_xattr_block_find *bs) -{ - struct super_block *sb = inode->i_sb; - int error; - - ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", - i->name_index, i->name, i->value, (long)i->value_len); - - if (EXT3_I(inode)->i_file_acl) { - /* The inode already has an extended attribute block. */ - bs->bh = sb_bread(sb, EXT3_I(inode)->i_file_acl); - error = -EIO; - if (!bs->bh) - goto cleanup; - ea_bdebug(bs->bh, "b_count=%d, refcount=%d", - atomic_read(&(bs->bh->b_count)), - le32_to_cpu(BHDR(bs->bh)->h_refcount)); - if (ext3_xattr_check_block(bs->bh)) { - ext3_error(sb, __func__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); - error = -EIO; - goto cleanup; - } - /* Find the named attribute. */ - bs->s.base = BHDR(bs->bh); - bs->s.first = BFIRST(bs->bh); - bs->s.end = bs->bh->b_data + bs->bh->b_size; - bs->s.here = bs->s.first; - error = ext3_xattr_find_entry(&bs->s.here, i->name_index, - i->name, bs->bh->b_size, 1); - if (error && error != -ENODATA) - goto cleanup; - bs->s.not_found = error; - } - error = 0; - -cleanup: - return error; -} - -static int -ext3_xattr_block_set(handle_t *handle, struct inode *inode, - struct ext3_xattr_info *i, - struct ext3_xattr_block_find *bs) -{ - struct super_block *sb = inode->i_sb; - struct buffer_head *new_bh = NULL; - struct ext3_xattr_search *s = &bs->s; - struct mb_cache_entry *ce = NULL; - int error = 0; - -#define header(x) ((struct ext3_xattr_header *)(x)) - - if (i->value && i->value_len > sb->s_blocksize) - return -ENOSPC; - if (s->base) { - ce = mb_cache_entry_get(ext3_xattr_cache, bs->bh->b_bdev, - bs->bh->b_blocknr); - error = ext3_journal_get_write_access(handle, bs->bh); - if (error) - goto cleanup; - lock_buffer(bs->bh); - - if (header(s->base)->h_refcount == cpu_to_le32(1)) { - if (ce) { - mb_cache_entry_free(ce); - ce = NULL; - } - ea_bdebug(bs->bh, "modifying in-place"); - error = ext3_xattr_set_entry(i, s); - if (!error) { - if (!IS_LAST_ENTRY(s->first)) - ext3_xattr_rehash(header(s->base), - s->here); - ext3_xattr_cache_insert(bs->bh); - } - unlock_buffer(bs->bh); - if (error == -EIO) - goto bad_block; - if (!error) - error = ext3_journal_dirty_metadata(handle, - bs->bh); - if (error) - goto cleanup; - goto inserted; - } else { - int offset = (char *)s->here - bs->bh->b_data; - - unlock_buffer(bs->bh); - journal_release_buffer(handle, bs->bh); - - if (ce) { - mb_cache_entry_release(ce); - ce = NULL; - } - ea_bdebug(bs->bh, "cloning"); - s->base = kmalloc(bs->bh->b_size, GFP_NOFS); - error = -ENOMEM; - if (s->base == NULL) - goto cleanup; - memcpy(s->base, BHDR(bs->bh), bs->bh->b_size); - s->first = ENTRY(header(s->base)+1); - header(s->base)->h_refcount = cpu_to_le32(1); - s->here = ENTRY(s->base + offset); - s->end = s->base + bs->bh->b_size; - } - } else { - /* Allocate a buffer where we construct the new block. */ - s->base = kzalloc(sb->s_blocksize, GFP_NOFS); - /* assert(header == s->base) */ - error = -ENOMEM; - if (s->base == NULL) - goto cleanup; - header(s->base)->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); - header(s->base)->h_blocks = cpu_to_le32(1); - header(s->base)->h_refcount = cpu_to_le32(1); - s->first = ENTRY(header(s->base)+1); - s->here = ENTRY(header(s->base)+1); - s->end = s->base + sb->s_blocksize; - } - - error = ext3_xattr_set_entry(i, s); - if (error == -EIO) - goto bad_block; - if (error) - goto cleanup; - if (!IS_LAST_ENTRY(s->first)) - ext3_xattr_rehash(header(s->base), s->here); - -inserted: - if (!IS_LAST_ENTRY(s->first)) { - new_bh = ext3_xattr_cache_find(inode, header(s->base), &ce); - if (new_bh) { - /* We found an identical block in the cache. */ - if (new_bh == bs->bh) - ea_bdebug(new_bh, "keeping"); - else { - /* The old block is released after updating - the inode. */ - error = dquot_alloc_block(inode, 1); - if (error) - goto cleanup; - error = ext3_journal_get_write_access(handle, - new_bh); - if (error) - goto cleanup_dquot; - lock_buffer(new_bh); - le32_add_cpu(&BHDR(new_bh)->h_refcount, 1); - ea_bdebug(new_bh, "reusing; refcount now=%d", - le32_to_cpu(BHDR(new_bh)->h_refcount)); - unlock_buffer(new_bh); - error = ext3_journal_dirty_metadata(handle, - new_bh); - if (error) - goto cleanup_dquot; - } - mb_cache_entry_release(ce); - ce = NULL; - } else if (bs->bh && s->base == bs->bh->b_data) { - /* We were modifying this block in-place. */ - ea_bdebug(bs->bh, "keeping this block"); - new_bh = bs->bh; - get_bh(new_bh); - } else { - /* We need to allocate a new block */ - ext3_fsblk_t goal = ext3_group_first_block_no(sb, - EXT3_I(inode)->i_block_group); - ext3_fsblk_t block; - - /* - * Protect us agaist concurrent allocations to the - * same inode from ext3_..._writepage(). Reservation - * code does not expect racing allocations. - */ - mutex_lock(&EXT3_I(inode)->truncate_mutex); - block = ext3_new_block(handle, inode, goal, &error); - mutex_unlock(&EXT3_I(inode)->truncate_mutex); - if (error) - goto cleanup; - ea_idebug(inode, "creating block %d", block); - - new_bh = sb_getblk(sb, block); - if (unlikely(!new_bh)) { -getblk_failed: - ext3_free_blocks(handle, inode, block, 1); - error = -ENOMEM; - goto cleanup; - } - lock_buffer(new_bh); - error = ext3_journal_get_create_access(handle, new_bh); - if (error) { - unlock_buffer(new_bh); - goto getblk_failed; - } - memcpy(new_bh->b_data, s->base, new_bh->b_size); - set_buffer_uptodate(new_bh); - unlock_buffer(new_bh); - ext3_xattr_cache_insert(new_bh); - error = ext3_journal_dirty_metadata(handle, new_bh); - if (error) - goto cleanup; - } - } - - /* Update the inode. */ - EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; - - /* Drop the previous xattr block. */ - if (bs->bh && bs->bh != new_bh) - ext3_xattr_release_block(handle, inode, bs->bh); - error = 0; - -cleanup: - if (ce) - mb_cache_entry_release(ce); - brelse(new_bh); - if (!(bs->bh && s->base == bs->bh->b_data)) - kfree(s->base); - - return error; - -cleanup_dquot: - dquot_free_block(inode, 1); - goto cleanup; - -bad_block: - ext3_error(inode->i_sb, __func__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); - goto cleanup; - -#undef header -} - -struct ext3_xattr_ibody_find { - struct ext3_xattr_search s; - struct ext3_iloc iloc; -}; - -static int -ext3_xattr_ibody_find(struct inode *inode, struct ext3_xattr_info *i, - struct ext3_xattr_ibody_find *is) -{ - struct ext3_xattr_ibody_header *header; - struct ext3_inode *raw_inode; - int error; - - if (EXT3_I(inode)->i_extra_isize == 0) - return 0; - raw_inode = ext3_raw_inode(&is->iloc); - header = IHDR(inode, raw_inode); - is->s.base = is->s.first = IFIRST(header); - is->s.here = is->s.first; - is->s.end = (void *)raw_inode + EXT3_SB(inode->i_sb)->s_inode_size; - if (ext3_test_inode_state(inode, EXT3_STATE_XATTR)) { - error = ext3_xattr_check_names(IFIRST(header), is->s.end); - if (error) - return error; - /* Find the named attribute. */ - error = ext3_xattr_find_entry(&is->s.here, i->name_index, - i->name, is->s.end - - (void *)is->s.base, 0); - if (error && error != -ENODATA) - return error; - is->s.not_found = error; - } - return 0; -} - -static int -ext3_xattr_ibody_set(handle_t *handle, struct inode *inode, - struct ext3_xattr_info *i, - struct ext3_xattr_ibody_find *is) -{ - struct ext3_xattr_ibody_header *header; - struct ext3_xattr_search *s = &is->s; - int error; - - if (EXT3_I(inode)->i_extra_isize == 0) - return -ENOSPC; - error = ext3_xattr_set_entry(i, s); - if (error) - return error; - header = IHDR(inode, ext3_raw_inode(&is->iloc)); - if (!IS_LAST_ENTRY(s->first)) { - header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); - ext3_set_inode_state(inode, EXT3_STATE_XATTR); - } else { - header->h_magic = cpu_to_le32(0); - ext3_clear_inode_state(inode, EXT3_STATE_XATTR); - } - return 0; -} - -/* - * ext3_xattr_set_handle() - * - * Create, replace or remove an extended attribute for this inode. Value - * is NULL to remove an existing extended attribute, and non-NULL to - * either replace an existing extended attribute, or create a new extended - * attribute. The flags XATTR_REPLACE and XATTR_CREATE - * specify that an extended attribute must exist and must not exist - * previous to the call, respectively. - * - * Returns 0, or a negative error number on failure. - */ -int -ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len, - int flags) -{ - struct ext3_xattr_info i = { - .name_index = name_index, - .name = name, - .value = value, - .value_len = value_len, - - }; - struct ext3_xattr_ibody_find is = { - .s = { .not_found = -ENODATA, }, - }; - struct ext3_xattr_block_find bs = { - .s = { .not_found = -ENODATA, }, - }; - int error; - - if (!name) - return -EINVAL; - if (strlen(name) > 255) - return -ERANGE; - down_write(&EXT3_I(inode)->xattr_sem); - error = ext3_get_inode_loc(inode, &is.iloc); - if (error) - goto cleanup; - - error = ext3_journal_get_write_access(handle, is.iloc.bh); - if (error) - goto cleanup; - - if (ext3_test_inode_state(inode, EXT3_STATE_NEW)) { - struct ext3_inode *raw_inode = ext3_raw_inode(&is.iloc); - memset(raw_inode, 0, EXT3_SB(inode->i_sb)->s_inode_size); - ext3_clear_inode_state(inode, EXT3_STATE_NEW); - } - - error = ext3_xattr_ibody_find(inode, &i, &is); - if (error) - goto cleanup; - if (is.s.not_found) - error = ext3_xattr_block_find(inode, &i, &bs); - if (error) - goto cleanup; - if (is.s.not_found && bs.s.not_found) { - error = -ENODATA; - if (flags & XATTR_REPLACE) - goto cleanup; - error = 0; - if (!value) - goto cleanup; - } else { - error = -EEXIST; - if (flags & XATTR_CREATE) - goto cleanup; - } - if (!value) { - if (!is.s.not_found) - error = ext3_xattr_ibody_set(handle, inode, &i, &is); - else if (!bs.s.not_found) - error = ext3_xattr_block_set(handle, inode, &i, &bs); - } else { - error = ext3_xattr_ibody_set(handle, inode, &i, &is); - if (!error && !bs.s.not_found) { - i.value = NULL; - error = ext3_xattr_block_set(handle, inode, &i, &bs); - } else if (error == -ENOSPC) { - if (EXT3_I(inode)->i_file_acl && !bs.s.base) { - error = ext3_xattr_block_find(inode, &i, &bs); - if (error) - goto cleanup; - } - error = ext3_xattr_block_set(handle, inode, &i, &bs); - if (error) - goto cleanup; - if (!is.s.not_found) { - i.value = NULL; - error = ext3_xattr_ibody_set(handle, inode, &i, - &is); - } - } - } - if (!error) { - ext3_xattr_update_super_block(handle, inode->i_sb); - inode->i_ctime = CURRENT_TIME_SEC; - error = ext3_mark_iloc_dirty(handle, inode, &is.iloc); - /* - * The bh is consumed by ext3_mark_iloc_dirty, even with - * error != 0. - */ - is.iloc.bh = NULL; - if (IS_SYNC(inode)) - handle->h_sync = 1; - } - -cleanup: - brelse(is.iloc.bh); - brelse(bs.bh); - up_write(&EXT3_I(inode)->xattr_sem); - return error; -} - -/* - * ext3_xattr_set() - * - * Like ext3_xattr_set_handle, but start from an inode. This extended - * attribute modification is a filesystem transaction by itself. - * - * Returns 0, or a negative error number on failure. - */ -int -ext3_xattr_set(struct inode *inode, int name_index, const char *name, - const void *value, size_t value_len, int flags) -{ - handle_t *handle; - int error, retries = 0; - -retry: - handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb)); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - } else { - int error2; - - error = ext3_xattr_set_handle(handle, inode, name_index, name, - value, value_len, flags); - error2 = ext3_journal_stop(handle); - if (error == -ENOSPC && - ext3_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - if (error == 0) - error = error2; - } - - return error; -} - -/* - * ext3_xattr_delete_inode() - * - * Free extended attribute resources associated with this inode. This - * is called immediately before an inode is freed. We have exclusive - * access to the inode. - */ -void -ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) -{ - struct buffer_head *bh = NULL; - - if (!EXT3_I(inode)->i_file_acl) - goto cleanup; - bh = sb_bread(inode->i_sb, EXT3_I(inode)->i_file_acl); - if (!bh) { - ext3_error(inode->i_sb, __func__, - "inode %lu: block "E3FSBLK" read error", inode->i_ino, - EXT3_I(inode)->i_file_acl); - goto cleanup; - } - if (BHDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || - BHDR(bh)->h_blocks != cpu_to_le32(1)) { - ext3_error(inode->i_sb, __func__, - "inode %lu: bad block "E3FSBLK, inode->i_ino, - EXT3_I(inode)->i_file_acl); - goto cleanup; - } - ext3_xattr_release_block(handle, inode, bh); - EXT3_I(inode)->i_file_acl = 0; - -cleanup: - brelse(bh); -} - -/* - * ext3_xattr_put_super() - * - * This is called when a file system is unmounted. - */ -void -ext3_xattr_put_super(struct super_block *sb) -{ - mb_cache_shrink(sb->s_bdev); -} - -/* - * ext3_xattr_cache_insert() - * - * Create a new entry in the extended attribute cache, and insert - * it unless such an entry is already in the cache. - * - * Returns 0, or a negative error number on failure. - */ -static void -ext3_xattr_cache_insert(struct buffer_head *bh) -{ - __u32 hash = le32_to_cpu(BHDR(bh)->h_hash); - struct mb_cache_entry *ce; - int error; - - ce = mb_cache_entry_alloc(ext3_xattr_cache, GFP_NOFS); - if (!ce) { - ea_bdebug(bh, "out of memory"); - return; - } - error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); - if (error) { - mb_cache_entry_free(ce); - if (error == -EBUSY) { - ea_bdebug(bh, "already in cache"); - error = 0; - } - } else { - ea_bdebug(bh, "inserting [%x]", (int)hash); - mb_cache_entry_release(ce); - } -} - -/* - * ext3_xattr_cmp() - * - * Compare two extended attribute blocks for equality. - * - * Returns 0 if the blocks are equal, 1 if they differ, and - * a negative error number on errors. - */ -static int -ext3_xattr_cmp(struct ext3_xattr_header *header1, - struct ext3_xattr_header *header2) -{ - struct ext3_xattr_entry *entry1, *entry2; - - entry1 = ENTRY(header1+1); - entry2 = ENTRY(header2+1); - while (!IS_LAST_ENTRY(entry1)) { - if (IS_LAST_ENTRY(entry2)) - return 1; - if (entry1->e_hash != entry2->e_hash || - entry1->e_name_index != entry2->e_name_index || - entry1->e_name_len != entry2->e_name_len || - entry1->e_value_size != entry2->e_value_size || - memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) - return 1; - if (entry1->e_value_block != 0 || entry2->e_value_block != 0) - return -EIO; - if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), - (char *)header2 + le16_to_cpu(entry2->e_value_offs), - le32_to_cpu(entry1->e_value_size))) - return 1; - - entry1 = EXT3_XATTR_NEXT(entry1); - entry2 = EXT3_XATTR_NEXT(entry2); - } - if (!IS_LAST_ENTRY(entry2)) - return 1; - return 0; -} - -/* - * ext3_xattr_cache_find() - * - * Find an identical extended attribute block. - * - * Returns a pointer to the block found, or NULL if such a block was - * not found or an error occurred. - */ -static struct buffer_head * -ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header, - struct mb_cache_entry **pce) -{ - __u32 hash = le32_to_cpu(header->h_hash); - struct mb_cache_entry *ce; - - if (!header->h_hash) - return NULL; /* never share */ - ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); -again: - ce = mb_cache_entry_find_first(ext3_xattr_cache, inode->i_sb->s_bdev, - hash); - while (ce) { - struct buffer_head *bh; - - if (IS_ERR(ce)) { - if (PTR_ERR(ce) == -EAGAIN) - goto again; - break; - } - bh = sb_bread(inode->i_sb, ce->e_block); - if (!bh) { - ext3_error(inode->i_sb, __func__, - "inode %lu: block %lu read error", - inode->i_ino, (unsigned long) ce->e_block); - } else if (le32_to_cpu(BHDR(bh)->h_refcount) >= - EXT3_XATTR_REFCOUNT_MAX) { - ea_idebug(inode, "block %lu refcount %d>=%d", - (unsigned long) ce->e_block, - le32_to_cpu(BHDR(bh)->h_refcount), - EXT3_XATTR_REFCOUNT_MAX); - } else if (ext3_xattr_cmp(header, BHDR(bh)) == 0) { - *pce = ce; - return bh; - } - brelse(bh); - ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); - } - return NULL; -} - -#define NAME_HASH_SHIFT 5 -#define VALUE_HASH_SHIFT 16 - -/* - * ext3_xattr_hash_entry() - * - * Compute the hash of an extended attribute. - */ -static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, - struct ext3_xattr_entry *entry) -{ - __u32 hash = 0; - char *name = entry->e_name; - int n; - - for (n=0; n < entry->e_name_len; n++) { - hash = (hash << NAME_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ - *name++; - } - - if (entry->e_value_block == 0 && entry->e_value_size != 0) { - __le32 *value = (__le32 *)((char *)header + - le16_to_cpu(entry->e_value_offs)); - for (n = (le32_to_cpu(entry->e_value_size) + - EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) { - hash = (hash << VALUE_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ - le32_to_cpu(*value++); - } - } - entry->e_hash = cpu_to_le32(hash); -} - -#undef NAME_HASH_SHIFT -#undef VALUE_HASH_SHIFT - -#define BLOCK_HASH_SHIFT 16 - -/* - * ext3_xattr_rehash() - * - * Re-compute the extended attribute hash value after an entry has changed. - */ -static void ext3_xattr_rehash(struct ext3_xattr_header *header, - struct ext3_xattr_entry *entry) -{ - struct ext3_xattr_entry *here; - __u32 hash = 0; - - ext3_xattr_hash_entry(header, entry); - here = ENTRY(header+1); - while (!IS_LAST_ENTRY(here)) { - if (!here->e_hash) { - /* Block is not shared if an entry's hash value == 0 */ - hash = 0; - break; - } - hash = (hash << BLOCK_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ - le32_to_cpu(here->e_hash); - here = EXT3_XATTR_NEXT(here); - } - header->h_hash = cpu_to_le32(hash); -} - -#undef BLOCK_HASH_SHIFT - -int __init -init_ext3_xattr(void) -{ - ext3_xattr_cache = mb_cache_create("ext3_xattr", 6); - if (!ext3_xattr_cache) - return -ENOMEM; - return 0; -} - -void -exit_ext3_xattr(void) -{ - if (ext3_xattr_cache) - mb_cache_destroy(ext3_xattr_cache); - ext3_xattr_cache = NULL; -} diff --git a/fs/ext3/xattr.h b/fs/ext3/xattr.h deleted file mode 100644 index 32e93ebf80315..0000000000000 --- a/fs/ext3/xattr.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - File: fs/ext3/xattr.h - - On-disk format of extended attributes for the ext3 filesystem. - - (C) 2001 Andreas Gruenbacher, -*/ - -#include - -/* Magic value in attribute blocks */ -#define EXT3_XATTR_MAGIC 0xEA020000 - -/* Maximum number of references to one attribute block */ -#define EXT3_XATTR_REFCOUNT_MAX 1024 - -/* Name indexes */ -#define EXT3_XATTR_INDEX_USER 1 -#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 -#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 -#define EXT3_XATTR_INDEX_TRUSTED 4 -#define EXT3_XATTR_INDEX_LUSTRE 5 -#define EXT3_XATTR_INDEX_SECURITY 6 - -struct ext3_xattr_header { - __le32 h_magic; /* magic number for identification */ - __le32 h_refcount; /* reference count */ - __le32 h_blocks; /* number of disk blocks used */ - __le32 h_hash; /* hash value of all attributes */ - __u32 h_reserved[4]; /* zero right now */ -}; - -struct ext3_xattr_ibody_header { - __le32 h_magic; /* magic number for identification */ -}; - -struct ext3_xattr_entry { - __u8 e_name_len; /* length of name */ - __u8 e_name_index; /* attribute name index */ - __le16 e_value_offs; /* offset in disk block of value */ - __le32 e_value_block; /* disk block attribute is stored on (n/i) */ - __le32 e_value_size; /* size of attribute value */ - __le32 e_hash; /* hash value of name and value */ - char e_name[0]; /* attribute name */ -}; - -#define EXT3_XATTR_PAD_BITS 2 -#define EXT3_XATTR_PAD (1<e_name_len)) ) -#define EXT3_XATTR_SIZE(size) \ - (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND) - -# ifdef CONFIG_EXT3_FS_XATTR - -extern const struct xattr_handler ext3_xattr_user_handler; -extern const struct xattr_handler ext3_xattr_trusted_handler; -extern const struct xattr_handler ext3_xattr_security_handler; - -extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); - -extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t); -extern int ext3_xattr_set(struct inode *, int, const char *, const void *, size_t, int); -extern int ext3_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); - -extern void ext3_xattr_delete_inode(handle_t *, struct inode *); -extern void ext3_xattr_put_super(struct super_block *); - -extern int init_ext3_xattr(void); -extern void exit_ext3_xattr(void); - -extern const struct xattr_handler *ext3_xattr_handlers[]; - -# else /* CONFIG_EXT3_FS_XATTR */ - -static inline int -ext3_xattr_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t size, int flags) -{ - return -EOPNOTSUPP; -} - -static inline int -ext3_xattr_set(struct inode *inode, int name_index, const char *name, - const void *value, size_t size, int flags) -{ - return -EOPNOTSUPP; -} - -static inline int -ext3_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, - const char *name, const void *value, size_t size, int flags) -{ - return -EOPNOTSUPP; -} - -static inline void -ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) -{ -} - -static inline void -ext3_xattr_put_super(struct super_block *sb) -{ -} - -static inline int -init_ext3_xattr(void) -{ - return 0; -} - -static inline void -exit_ext3_xattr(void) -{ -} - -#define ext3_xattr_handlers NULL - -# endif /* CONFIG_EXT3_FS_XATTR */ - -#ifdef CONFIG_EXT3_FS_SECURITY -extern int ext3_init_security(handle_t *handle, struct inode *inode, - struct inode *dir, const struct qstr *qstr); -#else -static inline int ext3_init_security(handle_t *handle, struct inode *inode, - struct inode *dir, const struct qstr *qstr) -{ - return 0; -} -#endif diff --git a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c deleted file mode 100644 index c9506d5e3b13b..0000000000000 --- a/fs/ext3/xattr_security.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * linux/fs/ext3/xattr_security.c - * Handler for storing security labels as extended attributes. - */ - -#include -#include "ext3.h" -#include "xattr.h" - -static size_t -ext3_xattr_security_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t prefix_len = XATTR_SECURITY_PREFIX_LEN; - const size_t total_len = prefix_len + name_len + 1; - - - if (list && total_len <= list_size) { - memcpy(list, XATTR_SECURITY_PREFIX, prefix_len); - memcpy(list+prefix_len, name, name_len); - list[prefix_len + name_len] = '\0'; - } - return total_len; -} - -static int -ext3_xattr_security_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext3_xattr_get(d_inode(dentry), EXT3_XATTR_INDEX_SECURITY, - name, buffer, size); -} - -static int -ext3_xattr_security_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext3_xattr_set(d_inode(dentry), EXT3_XATTR_INDEX_SECURITY, - name, value, size, flags); -} - -static int ext3_initxattrs(struct inode *inode, - const struct xattr *xattr_array, - void *fs_info) -{ - const struct xattr *xattr; - handle_t *handle = fs_info; - int err = 0; - - for (xattr = xattr_array; xattr->name != NULL; xattr++) { - err = ext3_xattr_set_handle(handle, inode, - EXT3_XATTR_INDEX_SECURITY, - xattr->name, xattr->value, - xattr->value_len, 0); - if (err < 0) - break; - } - return err; -} - -int -ext3_init_security(handle_t *handle, struct inode *inode, struct inode *dir, - const struct qstr *qstr) -{ - return security_inode_init_security(inode, dir, qstr, - &ext3_initxattrs, handle); -} - -const struct xattr_handler ext3_xattr_security_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .list = ext3_xattr_security_list, - .get = ext3_xattr_security_get, - .set = ext3_xattr_security_set, -}; diff --git a/fs/ext3/xattr_trusted.c b/fs/ext3/xattr_trusted.c deleted file mode 100644 index 206cc66dc2852..0000000000000 --- a/fs/ext3/xattr_trusted.c +++ /dev/null @@ -1,54 +0,0 @@ -/* - * linux/fs/ext3/xattr_trusted.c - * Handler for trusted extended attributes. - * - * Copyright (C) 2003 by Andreas Gruenbacher, - */ - -#include "ext3.h" -#include "xattr.h" - -static size_t -ext3_xattr_trusted_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; - const size_t total_len = prefix_len + name_len + 1; - - if (!capable(CAP_SYS_ADMIN)) - return 0; - - if (list && total_len <= list_size) { - memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); - memcpy(list+prefix_len, name, name_len); - list[prefix_len + name_len] = '\0'; - } - return total_len; -} - -static int -ext3_xattr_trusted_get(struct dentry *dentry, const char *name, - void *buffer, size_t size, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext3_xattr_get(d_inode(dentry), EXT3_XATTR_INDEX_TRUSTED, - name, buffer, size); -} - -static int -ext3_xattr_trusted_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - return ext3_xattr_set(d_inode(dentry), EXT3_XATTR_INDEX_TRUSTED, name, - value, size, flags); -} - -const struct xattr_handler ext3_xattr_trusted_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .list = ext3_xattr_trusted_list, - .get = ext3_xattr_trusted_get, - .set = ext3_xattr_trusted_set, -}; diff --git a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c deleted file mode 100644 index 021508ad16168..0000000000000 --- a/fs/ext3/xattr_user.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * linux/fs/ext3/xattr_user.c - * Handler for extended user attributes. - * - * Copyright (C) 2001 by Andreas Gruenbacher, - */ - -#include "ext3.h" -#include "xattr.h" - -static size_t -ext3_xattr_user_list(struct dentry *dentry, char *list, size_t list_size, - const char *name, size_t name_len, int type) -{ - const size_t prefix_len = XATTR_USER_PREFIX_LEN; - const size_t total_len = prefix_len + name_len + 1; - - if (!test_opt(dentry->d_sb, XATTR_USER)) - return 0; - - if (list && total_len <= list_size) { - memcpy(list, XATTR_USER_PREFIX, prefix_len); - memcpy(list+prefix_len, name, name_len); - list[prefix_len + name_len] = '\0'; - } - return total_len; -} - -static int -ext3_xattr_user_get(struct dentry *dentry, const char *name, void *buffer, - size_t size, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, XATTR_USER)) - return -EOPNOTSUPP; - return ext3_xattr_get(d_inode(dentry), EXT3_XATTR_INDEX_USER, - name, buffer, size); -} - -static int -ext3_xattr_user_set(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags, int type) -{ - if (strcmp(name, "") == 0) - return -EINVAL; - if (!test_opt(dentry->d_sb, XATTR_USER)) - return -EOPNOTSUPP; - return ext3_xattr_set(d_inode(dentry), EXT3_XATTR_INDEX_USER, - name, value, size, flags); -} - -const struct xattr_handler ext3_xattr_user_handler = { - .prefix = XATTR_USER_PREFIX, - .list = ext3_xattr_user_list, - .get = ext3_xattr_user_get, - .set = ext3_xattr_user_set, -}; diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index bf8bc8aba471c..219a190ccae95 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -1,5 +1,38 @@ +# Ext3 configs are here for backward compatibility with old configs which may +# have EXT3_FS set but not EXT4_FS set and thus would result in non-bootable +# kernels after the removal of ext3 driver. +config EXT3_FS + tristate "The Extended 3 (ext3) filesystem" + # These must match EXT4_FS selects... + select EXT4_FS + select JBD2 + select CRC16 + select CRYPTO + select CRYPTO_CRC32C + help + This config option is here only for backward compatibility. ext3 + filesystem is now handled by the ext4 driver. + +config EXT3_FS_POSIX_ACL + bool "Ext3 POSIX Access Control Lists" + depends on EXT3_FS + select EXT4_FS_POSIX_ACL + select FS_POSIX_ACL + help + This config option is here only for backward compatibility. ext3 + filesystem is now handled by the ext4 driver. + +config EXT3_FS_SECURITY + bool "Ext3 Security Labels" + depends on EXT3_FS + select EXT4_FS_SECURITY + help + This config option is here only for backward compatibility. ext3 + filesystem is now handled by the ext4 driver. + config EXT4_FS tristate "The Extended 4 (ext4) filesystem" + # Please update EXT3_FS selects when changing these select JBD2 select CRC16 select CRYPTO @@ -28,14 +61,14 @@ config EXT4_FS If unsure, say N. -config EXT4_USE_FOR_EXT23 +config EXT4_USE_FOR_EXT2 bool "Use ext4 for ext2/ext3 file systems" depends on EXT4_FS - depends on EXT3_FS=n || EXT2_FS=n + depends on EXT2_FS=n default y help - Allow the ext4 file system driver code to be used for ext2 or - ext3 file system mounts. This allows users to reduce their + Allow the ext4 file system driver code to be used for ext2 + file system mounts. This allows users to reduce their compiled kernel size by using one file system driver for ext2, ext3, and ext4 file systems. diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 58987b5c514b2..06b4b14e8aa02 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -84,7 +84,7 @@ static void ext4_unregister_li_request(struct super_block *sb); static void ext4_clear_request_list(void); static int ext4_reserve_clusters(struct ext4_sb_info *, ext4_fsblk_t); -#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) static struct file_system_type ext2_fs_type = { .owner = THIS_MODULE, .name = "ext2", @@ -100,7 +100,6 @@ MODULE_ALIAS("ext2"); #endif -#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static struct file_system_type ext3_fs_type = { .owner = THIS_MODULE, .name = "ext3", @@ -111,9 +110,6 @@ static struct file_system_type ext3_fs_type = { MODULE_ALIAS_FS("ext3"); MODULE_ALIAS("ext3"); #define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) -#else -#define IS_EXT3_SB(sb) (0) -#endif static int ext4_verify_csum_type(struct super_block *sb, struct ext4_super_block *es) @@ -5500,7 +5496,7 @@ static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); } -#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) +#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) static inline void register_as_ext2(void) { int err = register_filesystem(&ext2_fs_type); @@ -5530,7 +5526,6 @@ static inline void unregister_as_ext2(void) { } static inline int ext2_feature_set_ok(struct super_block *sb) { return 0; } #endif -#if !defined(CONFIG_EXT3_FS) && !defined(CONFIG_EXT3_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT23) static inline void register_as_ext3(void) { int err = register_filesystem(&ext3_fs_type); @@ -5556,11 +5551,6 @@ static inline int ext3_feature_set_ok(struct super_block *sb) return 0; return 1; } -#else -static inline void register_as_ext3(void) { } -static inline void unregister_as_ext3(void) { } -static inline int ext3_feature_set_ok(struct super_block *sb) { return 0; } -#endif static struct file_system_type ext4_fs_type = { .owner = THIS_MODULE, diff --git a/fs/jbd/Kconfig b/fs/jbd/Kconfig deleted file mode 100644 index 4e28beeed1572..0000000000000 --- a/fs/jbd/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config JBD - tristate - help - This is a generic journalling layer for block devices. It is - currently used by the ext3 file system, but it could also be - used to add journal support to other file systems or block - devices such as RAID or LVM. - - If you are using the ext3 file system, you need to say Y here. - If you are not using ext3 then you will probably want to say N. - - To compile this device as a module, choose M here: the module will be - called jbd. If you are compiling ext3 into the kernel, you - cannot compile this code as a module. - -config JBD_DEBUG - bool "JBD (ext3) debugging support" - depends on JBD && DEBUG_FS - help - If you are using the ext3 journaled file system (or potentially any - other file system/device using JBD), this option allows you to - enable debugging output while the system is running, in order to - help track down any problems you are having. By default the - debugging output will be turned off. - - If you select Y here, then you will be able to turn on debugging - with "echo N > /sys/kernel/debug/jbd/jbd-debug", where N is a - number between 1 and 5, the higher the number, the more debugging - output is generated. To turn debugging off again, do - "echo 0 > /sys/kernel/debug/jbd/jbd-debug". diff --git a/fs/jbd/Makefile b/fs/jbd/Makefile deleted file mode 100644 index 54aca4868a363..0000000000000 --- a/fs/jbd/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the linux journaling routines. -# - -obj-$(CONFIG_JBD) += jbd.o - -jbd-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o diff --git a/fs/jbd/checkpoint.c b/fs/jbd/checkpoint.c deleted file mode 100644 index 08c03044abddb..0000000000000 --- a/fs/jbd/checkpoint.c +++ /dev/null @@ -1,782 +0,0 @@ -/* - * linux/fs/jbd/checkpoint.c - * - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1999 Red Hat Software --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Checkpoint routines for the generic filesystem journaling code. - * Part of the ext2fs journaling system. - * - * Checkpointing is the process of ensuring that a section of the log is - * committed fully to disk, so that that portion of the log can be - * reused. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Unlink a buffer from a transaction checkpoint list. - * - * Called with j_list_lock held. - */ -static inline void __buffer_unlink_first(struct journal_head *jh) -{ - transaction_t *transaction = jh->b_cp_transaction; - - jh->b_cpnext->b_cpprev = jh->b_cpprev; - jh->b_cpprev->b_cpnext = jh->b_cpnext; - if (transaction->t_checkpoint_list == jh) { - transaction->t_checkpoint_list = jh->b_cpnext; - if (transaction->t_checkpoint_list == jh) - transaction->t_checkpoint_list = NULL; - } -} - -/* - * Unlink a buffer from a transaction checkpoint(io) list. - * - * Called with j_list_lock held. - */ -static inline void __buffer_unlink(struct journal_head *jh) -{ - transaction_t *transaction = jh->b_cp_transaction; - - __buffer_unlink_first(jh); - if (transaction->t_checkpoint_io_list == jh) { - transaction->t_checkpoint_io_list = jh->b_cpnext; - if (transaction->t_checkpoint_io_list == jh) - transaction->t_checkpoint_io_list = NULL; - } -} - -/* - * Move a buffer from the checkpoint list to the checkpoint io list - * - * Called with j_list_lock held - */ -static inline void __buffer_relink_io(struct journal_head *jh) -{ - transaction_t *transaction = jh->b_cp_transaction; - - __buffer_unlink_first(jh); - - if (!transaction->t_checkpoint_io_list) { - jh->b_cpnext = jh->b_cpprev = jh; - } else { - jh->b_cpnext = transaction->t_checkpoint_io_list; - jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev; - jh->b_cpprev->b_cpnext = jh; - jh->b_cpnext->b_cpprev = jh; - } - transaction->t_checkpoint_io_list = jh; -} - -/* - * Try to release a checkpointed buffer from its transaction. - * Returns 1 if we released it and 2 if we also released the - * whole transaction. - * - * Requires j_list_lock - * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it - */ -static int __try_to_free_cp_buf(struct journal_head *jh) -{ - int ret = 0; - struct buffer_head *bh = jh2bh(jh); - - if (jh->b_jlist == BJ_None && !buffer_locked(bh) && - !buffer_dirty(bh) && !buffer_write_io_error(bh)) { - /* - * Get our reference so that bh cannot be freed before - * we unlock it - */ - get_bh(bh); - JBUFFER_TRACE(jh, "remove from checkpoint list"); - ret = __journal_remove_checkpoint(jh) + 1; - jbd_unlock_bh_state(bh); - BUFFER_TRACE(bh, "release"); - __brelse(bh); - } else { - jbd_unlock_bh_state(bh); - } - return ret; -} - -/* - * __log_wait_for_space: wait until there is space in the journal. - * - * Called under j-state_lock *only*. It will be unlocked if we have to wait - * for a checkpoint to free up some space in the log. - */ -void __log_wait_for_space(journal_t *journal) -{ - int nblocks, space_left; - assert_spin_locked(&journal->j_state_lock); - - nblocks = jbd_space_needed(journal); - while (__log_space_left(journal) < nblocks) { - if (journal->j_flags & JFS_ABORT) - return; - spin_unlock(&journal->j_state_lock); - mutex_lock(&journal->j_checkpoint_mutex); - - /* - * Test again, another process may have checkpointed while we - * were waiting for the checkpoint lock. If there are no - * transactions ready to be checkpointed, try to recover - * journal space by calling cleanup_journal_tail(), and if - * that doesn't work, by waiting for the currently committing - * transaction to complete. If there is absolutely no way - * to make progress, this is either a BUG or corrupted - * filesystem, so abort the journal and leave a stack - * trace for forensic evidence. - */ - spin_lock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - nblocks = jbd_space_needed(journal); - space_left = __log_space_left(journal); - if (space_left < nblocks) { - int chkpt = journal->j_checkpoint_transactions != NULL; - tid_t tid = 0; - - if (journal->j_committing_transaction) - tid = journal->j_committing_transaction->t_tid; - spin_unlock(&journal->j_list_lock); - spin_unlock(&journal->j_state_lock); - if (chkpt) { - log_do_checkpoint(journal); - } else if (cleanup_journal_tail(journal) == 0) { - /* We were able to recover space; yay! */ - ; - } else if (tid) { - log_wait_commit(journal, tid); - } else { - printk(KERN_ERR "%s: needed %d blocks and " - "only had %d space available\n", - __func__, nblocks, space_left); - printk(KERN_ERR "%s: no way to get more " - "journal space\n", __func__); - WARN_ON(1); - journal_abort(journal, 0); - } - spin_lock(&journal->j_state_lock); - } else { - spin_unlock(&journal->j_list_lock); - } - mutex_unlock(&journal->j_checkpoint_mutex); - } -} - -/* - * We were unable to perform jbd_trylock_bh_state() inside j_list_lock. - * The caller must restart a list walk. Wait for someone else to run - * jbd_unlock_bh_state(). - */ -static void jbd_sync_bh(journal_t *journal, struct buffer_head *bh) - __releases(journal->j_list_lock) -{ - get_bh(bh); - spin_unlock(&journal->j_list_lock); - jbd_lock_bh_state(bh); - jbd_unlock_bh_state(bh); - put_bh(bh); -} - -/* - * Clean up transaction's list of buffers submitted for io. - * We wait for any pending IO to complete and remove any clean - * buffers. Note that we take the buffers in the opposite ordering - * from the one in which they were submitted for IO. - * - * Return 0 on success, and return <0 if some buffers have failed - * to be written out. - * - * Called with j_list_lock held. - */ -static int __wait_cp_io(journal_t *journal, transaction_t *transaction) -{ - struct journal_head *jh; - struct buffer_head *bh; - tid_t this_tid; - int released = 0; - int ret = 0; - - this_tid = transaction->t_tid; -restart: - /* Did somebody clean up the transaction in the meanwhile? */ - if (journal->j_checkpoint_transactions != transaction || - transaction->t_tid != this_tid) - return ret; - while (!released && transaction->t_checkpoint_io_list) { - jh = transaction->t_checkpoint_io_list; - bh = jh2bh(jh); - if (!jbd_trylock_bh_state(bh)) { - jbd_sync_bh(journal, bh); - spin_lock(&journal->j_list_lock); - goto restart; - } - get_bh(bh); - if (buffer_locked(bh)) { - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - wait_on_buffer(bh); - /* the journal_head may have gone by now */ - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - spin_lock(&journal->j_list_lock); - goto restart; - } - if (unlikely(buffer_write_io_error(bh))) - ret = -EIO; - - /* - * Now in whatever state the buffer currently is, we know that - * it has been written out and so we can drop it from the list - */ - released = __journal_remove_checkpoint(jh); - jbd_unlock_bh_state(bh); - __brelse(bh); - } - - return ret; -} - -#define NR_BATCH 64 - -static void -__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) -{ - int i; - struct blk_plug plug; - - blk_start_plug(&plug); - for (i = 0; i < *batch_count; i++) - write_dirty_buffer(bhs[i], WRITE_SYNC); - blk_finish_plug(&plug); - - for (i = 0; i < *batch_count; i++) { - struct buffer_head *bh = bhs[i]; - clear_buffer_jwrite(bh); - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - } - *batch_count = 0; -} - -/* - * Try to flush one buffer from the checkpoint list to disk. - * - * Return 1 if something happened which requires us to abort the current - * scan of the checkpoint list. Return <0 if the buffer has failed to - * be written out. - * - * Called with j_list_lock held and drops it if 1 is returned - * Called under jbd_lock_bh_state(jh2bh(jh)), and drops it - */ -static int __process_buffer(journal_t *journal, struct journal_head *jh, - struct buffer_head **bhs, int *batch_count) -{ - struct buffer_head *bh = jh2bh(jh); - int ret = 0; - - if (buffer_locked(bh)) { - get_bh(bh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - wait_on_buffer(bh); - /* the journal_head may have gone by now */ - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - ret = 1; - } else if (jh->b_transaction != NULL) { - transaction_t *t = jh->b_transaction; - tid_t tid = t->t_tid; - - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - log_start_commit(journal, tid); - log_wait_commit(journal, tid); - ret = 1; - } else if (!buffer_dirty(bh)) { - ret = 1; - if (unlikely(buffer_write_io_error(bh))) - ret = -EIO; - get_bh(bh); - J_ASSERT_JH(jh, !buffer_jbddirty(bh)); - BUFFER_TRACE(bh, "remove from checkpoint"); - __journal_remove_checkpoint(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - __brelse(bh); - } else { - /* - * Important: we are about to write the buffer, and - * possibly block, while still holding the journal lock. - * We cannot afford to let the transaction logic start - * messing around with this buffer before we write it to - * disk, as that would break recoverability. - */ - BUFFER_TRACE(bh, "queue"); - get_bh(bh); - J_ASSERT_BH(bh, !buffer_jwrite(bh)); - set_buffer_jwrite(bh); - bhs[*batch_count] = bh; - __buffer_relink_io(jh); - jbd_unlock_bh_state(bh); - (*batch_count)++; - if (*batch_count == NR_BATCH) { - spin_unlock(&journal->j_list_lock); - __flush_batch(journal, bhs, batch_count); - ret = 1; - } - } - return ret; -} - -/* - * Perform an actual checkpoint. We take the first transaction on the - * list of transactions to be checkpointed and send all its buffers - * to disk. We submit larger chunks of data at once. - * - * The journal should be locked before calling this function. - * Called with j_checkpoint_mutex held. - */ -int log_do_checkpoint(journal_t *journal) -{ - transaction_t *transaction; - tid_t this_tid; - int result; - - jbd_debug(1, "Start checkpoint\n"); - - /* - * First thing: if there are any transactions in the log which - * don't need checkpointing, just eliminate them from the - * journal straight away. - */ - result = cleanup_journal_tail(journal); - trace_jbd_checkpoint(journal, result); - jbd_debug(1, "cleanup_journal_tail returned %d\n", result); - if (result <= 0) - return result; - - /* - * OK, we need to start writing disk blocks. Take one transaction - * and write it. - */ - result = 0; - spin_lock(&journal->j_list_lock); - if (!journal->j_checkpoint_transactions) - goto out; - transaction = journal->j_checkpoint_transactions; - this_tid = transaction->t_tid; -restart: - /* - * If someone cleaned up this transaction while we slept, we're - * done (maybe it's a new transaction, but it fell at the same - * address). - */ - if (journal->j_checkpoint_transactions == transaction && - transaction->t_tid == this_tid) { - int batch_count = 0; - struct buffer_head *bhs[NR_BATCH]; - struct journal_head *jh; - int retry = 0, err; - - while (!retry && transaction->t_checkpoint_list) { - struct buffer_head *bh; - - jh = transaction->t_checkpoint_list; - bh = jh2bh(jh); - if (!jbd_trylock_bh_state(bh)) { - jbd_sync_bh(journal, bh); - retry = 1; - break; - } - retry = __process_buffer(journal, jh, bhs,&batch_count); - if (retry < 0 && !result) - result = retry; - if (!retry && (need_resched() || - spin_needbreak(&journal->j_list_lock))) { - spin_unlock(&journal->j_list_lock); - retry = 1; - break; - } - } - - if (batch_count) { - if (!retry) { - spin_unlock(&journal->j_list_lock); - retry = 1; - } - __flush_batch(journal, bhs, &batch_count); - } - - if (retry) { - spin_lock(&journal->j_list_lock); - goto restart; - } - /* - * Now we have cleaned up the first transaction's checkpoint - * list. Let's clean up the second one - */ - err = __wait_cp_io(journal, transaction); - if (!result) - result = err; - } -out: - spin_unlock(&journal->j_list_lock); - if (result < 0) - journal_abort(journal, result); - else - result = cleanup_journal_tail(journal); - - return (result < 0) ? result : 0; -} - -/* - * Check the list of checkpoint transactions for the journal to see if - * we have already got rid of any since the last update of the log tail - * in the journal superblock. If so, we can instantly roll the - * superblock forward to remove those transactions from the log. - * - * Return <0 on error, 0 on success, 1 if there was nothing to clean up. - * - * This is the only part of the journaling code which really needs to be - * aware of transaction aborts. Checkpointing involves writing to the - * main filesystem area rather than to the journal, so it can proceed - * even in abort state, but we must not update the super block if - * checkpointing may have failed. Otherwise, we would lose some metadata - * buffers which should be written-back to the filesystem. - */ - -int cleanup_journal_tail(journal_t *journal) -{ - transaction_t * transaction; - tid_t first_tid; - unsigned int blocknr, freed; - - if (is_journal_aborted(journal)) - return 1; - - /* - * OK, work out the oldest transaction remaining in the log, and - * the log block it starts at. - * - * If the log is now empty, we need to work out which is the - * next transaction ID we will write, and where it will - * start. - */ - spin_lock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - transaction = journal->j_checkpoint_transactions; - if (transaction) { - first_tid = transaction->t_tid; - blocknr = transaction->t_log_start; - } else if ((transaction = journal->j_committing_transaction) != NULL) { - first_tid = transaction->t_tid; - blocknr = transaction->t_log_start; - } else if ((transaction = journal->j_running_transaction) != NULL) { - first_tid = transaction->t_tid; - blocknr = journal->j_head; - } else { - first_tid = journal->j_transaction_sequence; - blocknr = journal->j_head; - } - spin_unlock(&journal->j_list_lock); - J_ASSERT(blocknr != 0); - - /* If the oldest pinned transaction is at the tail of the log - already then there's not much we can do right now. */ - if (journal->j_tail_sequence == first_tid) { - spin_unlock(&journal->j_state_lock); - return 1; - } - spin_unlock(&journal->j_state_lock); - - /* - * We need to make sure that any blocks that were recently written out - * --- perhaps by log_do_checkpoint() --- are flushed out before we - * drop the transactions from the journal. Similarly we need to be sure - * superblock makes it to disk before next transaction starts reusing - * freed space (otherwise we could replay some blocks of the new - * transaction thinking they belong to the old one). So we use - * WRITE_FLUSH_FUA. It's unlikely this will be necessary, especially - * with an appropriately sized journal, but we need this to guarantee - * correctness. Fortunately cleanup_journal_tail() doesn't get called - * all that often. - */ - journal_update_sb_log_tail(journal, first_tid, blocknr, - WRITE_FLUSH_FUA); - - spin_lock(&journal->j_state_lock); - /* OK, update the superblock to recover the freed space. - * Physical blocks come first: have we wrapped beyond the end of - * the log? */ - freed = blocknr - journal->j_tail; - if (blocknr < journal->j_tail) - freed = freed + journal->j_last - journal->j_first; - - trace_jbd_cleanup_journal_tail(journal, first_tid, blocknr, freed); - jbd_debug(1, - "Cleaning journal tail from %d to %d (offset %u), " - "freeing %u\n", - journal->j_tail_sequence, first_tid, blocknr, freed); - - journal->j_free += freed; - journal->j_tail_sequence = first_tid; - journal->j_tail = blocknr; - spin_unlock(&journal->j_state_lock); - return 0; -} - - -/* Checkpoint list management */ - -/* - * journal_clean_one_cp_list - * - * Find all the written-back checkpoint buffers in the given list and release - * them. - * - * Called with j_list_lock held. - * Returns number of buffers reaped (for debug) - */ - -static int journal_clean_one_cp_list(struct journal_head *jh, int *released) -{ - struct journal_head *last_jh; - struct journal_head *next_jh = jh; - int ret, freed = 0; - - *released = 0; - if (!jh) - return 0; - - last_jh = jh->b_cpprev; - do { - jh = next_jh; - next_jh = jh->b_cpnext; - /* Use trylock because of the ranking */ - if (jbd_trylock_bh_state(jh2bh(jh))) { - ret = __try_to_free_cp_buf(jh); - if (ret) { - freed++; - if (ret == 2) { - *released = 1; - return freed; - } - } - } - /* - * This function only frees up some memory - * if possible so we dont have an obligation - * to finish processing. Bail out if preemption - * requested: - */ - if (need_resched()) - return freed; - } while (jh != last_jh); - - return freed; -} - -/* - * journal_clean_checkpoint_list - * - * Find all the written-back checkpoint buffers in the journal and release them. - * - * Called with the journal locked. - * Called with j_list_lock held. - * Returns number of buffers reaped (for debug) - */ - -int __journal_clean_checkpoint_list(journal_t *journal) -{ - transaction_t *transaction, *last_transaction, *next_transaction; - int ret = 0; - int released; - - transaction = journal->j_checkpoint_transactions; - if (!transaction) - goto out; - - last_transaction = transaction->t_cpprev; - next_transaction = transaction; - do { - transaction = next_transaction; - next_transaction = transaction->t_cpnext; - ret += journal_clean_one_cp_list(transaction-> - t_checkpoint_list, &released); - /* - * This function only frees up some memory if possible so we - * dont have an obligation to finish processing. Bail out if - * preemption requested: - */ - if (need_resched()) - goto out; - if (released) - continue; - /* - * It is essential that we are as careful as in the case of - * t_checkpoint_list with removing the buffer from the list as - * we can possibly see not yet submitted buffers on io_list - */ - ret += journal_clean_one_cp_list(transaction-> - t_checkpoint_io_list, &released); - if (need_resched()) - goto out; - } while (transaction != last_transaction); -out: - return ret; -} - -/* - * journal_remove_checkpoint: called after a buffer has been committed - * to disk (either by being write-back flushed to disk, or being - * committed to the log). - * - * We cannot safely clean a transaction out of the log until all of the - * buffer updates committed in that transaction have safely been stored - * elsewhere on disk. To achieve this, all of the buffers in a - * transaction need to be maintained on the transaction's checkpoint - * lists until they have been rewritten, at which point this function is - * called to remove the buffer from the existing transaction's - * checkpoint lists. - * - * The function returns 1 if it frees the transaction, 0 otherwise. - * The function can free jh and bh. - * - * This function is called with j_list_lock held. - * This function is called with jbd_lock_bh_state(jh2bh(jh)) - */ - -int __journal_remove_checkpoint(struct journal_head *jh) -{ - transaction_t *transaction; - journal_t *journal; - int ret = 0; - - JBUFFER_TRACE(jh, "entry"); - - if ((transaction = jh->b_cp_transaction) == NULL) { - JBUFFER_TRACE(jh, "not on transaction"); - goto out; - } - journal = transaction->t_journal; - - JBUFFER_TRACE(jh, "removing from transaction"); - __buffer_unlink(jh); - jh->b_cp_transaction = NULL; - journal_put_journal_head(jh); - - if (transaction->t_checkpoint_list != NULL || - transaction->t_checkpoint_io_list != NULL) - goto out; - - /* - * There is one special case to worry about: if we have just pulled the - * buffer off a running or committing transaction's checkpoing list, - * then even if the checkpoint list is empty, the transaction obviously - * cannot be dropped! - * - * The locking here around t_state is a bit sleazy. - * See the comment at the end of journal_commit_transaction(). - */ - if (transaction->t_state != T_FINISHED) - goto out; - - /* OK, that was the last buffer for the transaction: we can now - safely remove this transaction from the log */ - - __journal_drop_transaction(journal, transaction); - - /* Just in case anybody was waiting for more transactions to be - checkpointed... */ - wake_up(&journal->j_wait_logspace); - ret = 1; -out: - return ret; -} - -/* - * journal_insert_checkpoint: put a committed buffer onto a checkpoint - * list so that we know when it is safe to clean the transaction out of - * the log. - * - * Called with the journal locked. - * Called with j_list_lock held. - */ -void __journal_insert_checkpoint(struct journal_head *jh, - transaction_t *transaction) -{ - JBUFFER_TRACE(jh, "entry"); - J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); - J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); - - /* Get reference for checkpointing transaction */ - journal_grab_journal_head(jh2bh(jh)); - jh->b_cp_transaction = transaction; - - if (!transaction->t_checkpoint_list) { - jh->b_cpnext = jh->b_cpprev = jh; - } else { - jh->b_cpnext = transaction->t_checkpoint_list; - jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev; - jh->b_cpprev->b_cpnext = jh; - jh->b_cpnext->b_cpprev = jh; - } - transaction->t_checkpoint_list = jh; -} - -/* - * We've finished with this transaction structure: adios... - * - * The transaction must have no links except for the checkpoint by this - * point. - * - * Called with the journal locked. - * Called with j_list_lock held. - */ - -void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) -{ - assert_spin_locked(&journal->j_list_lock); - if (transaction->t_cpnext) { - transaction->t_cpnext->t_cpprev = transaction->t_cpprev; - transaction->t_cpprev->t_cpnext = transaction->t_cpnext; - if (journal->j_checkpoint_transactions == transaction) - journal->j_checkpoint_transactions = - transaction->t_cpnext; - if (journal->j_checkpoint_transactions == transaction) - journal->j_checkpoint_transactions = NULL; - } - - J_ASSERT(transaction->t_state == T_FINISHED); - J_ASSERT(transaction->t_buffers == NULL); - J_ASSERT(transaction->t_sync_datalist == NULL); - J_ASSERT(transaction->t_forget == NULL); - J_ASSERT(transaction->t_iobuf_list == NULL); - J_ASSERT(transaction->t_shadow_list == NULL); - J_ASSERT(transaction->t_log_list == NULL); - J_ASSERT(transaction->t_checkpoint_list == NULL); - J_ASSERT(transaction->t_checkpoint_io_list == NULL); - J_ASSERT(transaction->t_updates == 0); - J_ASSERT(journal->j_committing_transaction != transaction); - J_ASSERT(journal->j_running_transaction != transaction); - - trace_jbd_drop_transaction(journal, transaction); - jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); - kfree(transaction); -} diff --git a/fs/jbd/commit.c b/fs/jbd/commit.c deleted file mode 100644 index bb217dcb41aff..0000000000000 --- a/fs/jbd/commit.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * linux/fs/jbd/commit.c - * - * Written by Stephen C. Tweedie , 1998 - * - * Copyright 1998 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Journal commit routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Default IO end handler for temporary BJ_IO buffer_heads. - */ -static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) -{ - BUFFER_TRACE(bh, ""); - if (uptodate) - set_buffer_uptodate(bh); - else - clear_buffer_uptodate(bh); - unlock_buffer(bh); -} - -/* - * When an ext3-ordered file is truncated, it is possible that many pages are - * not successfully freed, because they are attached to a committing transaction. - * After the transaction commits, these pages are left on the LRU, with no - * ->mapping, and with attached buffers. These pages are trivially reclaimable - * by the VM, but their apparent absence upsets the VM accounting, and it makes - * the numbers in /proc/meminfo look odd. - * - * So here, we have a buffer which has just come off the forget list. Look to - * see if we can strip all buffers from the backing page. - * - * Called under journal->j_list_lock. The caller provided us with a ref - * against the buffer, and we drop that here. - */ -static void release_buffer_page(struct buffer_head *bh) -{ - struct page *page; - - if (buffer_dirty(bh)) - goto nope; - if (atomic_read(&bh->b_count) != 1) - goto nope; - page = bh->b_page; - if (!page) - goto nope; - if (page->mapping) - goto nope; - - /* OK, it's a truncated page */ - if (!trylock_page(page)) - goto nope; - - page_cache_get(page); - __brelse(bh); - try_to_free_buffers(page); - unlock_page(page); - page_cache_release(page); - return; - -nope: - __brelse(bh); -} - -/* - * Decrement reference counter for data buffer. If it has been marked - * 'BH_Freed', release it and the page to which it belongs if possible. - */ -static void release_data_buffer(struct buffer_head *bh) -{ - if (buffer_freed(bh)) { - WARN_ON_ONCE(buffer_dirty(bh)); - clear_buffer_freed(bh); - clear_buffer_mapped(bh); - clear_buffer_new(bh); - clear_buffer_req(bh); - bh->b_bdev = NULL; - release_buffer_page(bh); - } else - put_bh(bh); -} - -/* - * Try to acquire jbd_lock_bh_state() against the buffer, when j_list_lock is - * held. For ranking reasons we must trylock. If we lose, schedule away and - * return 0. j_list_lock is dropped in this case. - */ -static int inverted_lock(journal_t *journal, struct buffer_head *bh) -{ - if (!jbd_trylock_bh_state(bh)) { - spin_unlock(&journal->j_list_lock); - schedule(); - return 0; - } - return 1; -} - -/* Done it all: now write the commit record. We should have - * cleaned up our previous buffers by now, so if we are in abort - * mode we can now just skip the rest of the journal write - * entirely. - * - * Returns 1 if the journal needs to be aborted or 0 on success - */ -static int journal_write_commit_record(journal_t *journal, - transaction_t *commit_transaction) -{ - struct journal_head *descriptor; - struct buffer_head *bh; - journal_header_t *header; - int ret; - - if (is_journal_aborted(journal)) - return 0; - - descriptor = journal_get_descriptor_buffer(journal); - if (!descriptor) - return 1; - - bh = jh2bh(descriptor); - - header = (journal_header_t *)(bh->b_data); - header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - header->h_blocktype = cpu_to_be32(JFS_COMMIT_BLOCK); - header->h_sequence = cpu_to_be32(commit_transaction->t_tid); - - JBUFFER_TRACE(descriptor, "write commit block"); - set_buffer_dirty(bh); - - if (journal->j_flags & JFS_BARRIER) - ret = __sync_dirty_buffer(bh, WRITE_SYNC | WRITE_FLUSH_FUA); - else - ret = sync_dirty_buffer(bh); - - put_bh(bh); /* One for getblk() */ - journal_put_journal_head(descriptor); - - return (ret == -EIO); -} - -static void journal_do_submit_data(struct buffer_head **wbuf, int bufs, - int write_op) -{ - int i; - - for (i = 0; i < bufs; i++) { - wbuf[i]->b_end_io = end_buffer_write_sync; - /* - * Here we write back pagecache data that may be mmaped. Since - * we cannot afford to clean the page and set PageWriteback - * here due to lock ordering (page lock ranks above transaction - * start), the data can change while IO is in flight. Tell the - * block layer it should bounce the bio pages if stable data - * during write is required. - * - * We use up our safety reference in submit_bh(). - */ - _submit_bh(write_op, wbuf[i], 1 << BIO_SNAP_STABLE); - } -} - -/* - * Submit all the data buffers to disk - */ -static int journal_submit_data_buffers(journal_t *journal, - transaction_t *commit_transaction, - int write_op) -{ - struct journal_head *jh; - struct buffer_head *bh; - int locked; - int bufs = 0; - struct buffer_head **wbuf = journal->j_wbuf; - int err = 0; - - /* - * Whenever we unlock the journal and sleep, things can get added - * onto ->t_sync_datalist, so we have to keep looping back to - * write_out_data until we *know* that the list is empty. - * - * Cleanup any flushed data buffers from the data list. Even in - * abort mode, we want to flush this out as soon as possible. - */ -write_out_data: - cond_resched(); - spin_lock(&journal->j_list_lock); - - while (commit_transaction->t_sync_datalist) { - jh = commit_transaction->t_sync_datalist; - bh = jh2bh(jh); - locked = 0; - - /* Get reference just to make sure buffer does not disappear - * when we are forced to drop various locks */ - get_bh(bh); - /* If the buffer is dirty, we need to submit IO and hence - * we need the buffer lock. We try to lock the buffer without - * blocking. If we fail, we need to drop j_list_lock and do - * blocking lock_buffer(). - */ - if (buffer_dirty(bh)) { - if (!trylock_buffer(bh)) { - BUFFER_TRACE(bh, "needs blocking lock"); - spin_unlock(&journal->j_list_lock); - trace_jbd_do_submit_data(journal, - commit_transaction); - /* Write out all data to prevent deadlocks */ - journal_do_submit_data(wbuf, bufs, write_op); - bufs = 0; - lock_buffer(bh); - spin_lock(&journal->j_list_lock); - } - locked = 1; - } - /* We have to get bh_state lock. Again out of order, sigh. */ - if (!inverted_lock(journal, bh)) { - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - } - /* Someone already cleaned up the buffer? */ - if (!buffer_jbd(bh) || bh2jh(bh) != jh - || jh->b_transaction != commit_transaction - || jh->b_jlist != BJ_SyncData) { - jbd_unlock_bh_state(bh); - if (locked) - unlock_buffer(bh); - BUFFER_TRACE(bh, "already cleaned up"); - release_data_buffer(bh); - continue; - } - if (locked && test_clear_buffer_dirty(bh)) { - BUFFER_TRACE(bh, "needs writeout, adding to array"); - wbuf[bufs++] = bh; - __journal_file_buffer(jh, commit_transaction, - BJ_Locked); - jbd_unlock_bh_state(bh); - if (bufs == journal->j_wbufsize) { - spin_unlock(&journal->j_list_lock); - trace_jbd_do_submit_data(journal, - commit_transaction); - journal_do_submit_data(wbuf, bufs, write_op); - bufs = 0; - goto write_out_data; - } - } else if (!locked && buffer_locked(bh)) { - __journal_file_buffer(jh, commit_transaction, - BJ_Locked); - jbd_unlock_bh_state(bh); - put_bh(bh); - } else { - BUFFER_TRACE(bh, "writeout complete: unfile"); - if (unlikely(!buffer_uptodate(bh))) - err = -EIO; - __journal_unfile_buffer(jh); - jbd_unlock_bh_state(bh); - if (locked) - unlock_buffer(bh); - release_data_buffer(bh); - } - - if (need_resched() || spin_needbreak(&journal->j_list_lock)) { - spin_unlock(&journal->j_list_lock); - goto write_out_data; - } - } - spin_unlock(&journal->j_list_lock); - trace_jbd_do_submit_data(journal, commit_transaction); - journal_do_submit_data(wbuf, bufs, write_op); - - return err; -} - -/* - * journal_commit_transaction - * - * The primary function for committing a transaction to the log. This - * function is called by the journal thread to begin a complete commit. - */ -void journal_commit_transaction(journal_t *journal) -{ - transaction_t *commit_transaction; - struct journal_head *jh, *new_jh, *descriptor; - struct buffer_head **wbuf = journal->j_wbuf; - int bufs; - int flags; - int err; - unsigned int blocknr; - ktime_t start_time; - u64 commit_time; - char *tagp = NULL; - journal_header_t *header; - journal_block_tag_t *tag = NULL; - int space_left = 0; - int first_tag = 0; - int tag_flag; - int i; - struct blk_plug plug; - int write_op = WRITE; - - /* - * First job: lock down the current transaction and wait for - * all outstanding updates to complete. - */ - - /* Do we need to erase the effects of a prior journal_flush? */ - if (journal->j_flags & JFS_FLUSHED) { - jbd_debug(3, "super block updated\n"); - mutex_lock(&journal->j_checkpoint_mutex); - /* - * We hold j_checkpoint_mutex so tail cannot change under us. - * We don't need any special data guarantees for writing sb - * since journal is empty and it is ok for write to be - * flushed only with transaction commit. - */ - journal_update_sb_log_tail(journal, journal->j_tail_sequence, - journal->j_tail, WRITE_SYNC); - mutex_unlock(&journal->j_checkpoint_mutex); - } else { - jbd_debug(3, "superblock not updated\n"); - } - - J_ASSERT(journal->j_running_transaction != NULL); - J_ASSERT(journal->j_committing_transaction == NULL); - - commit_transaction = journal->j_running_transaction; - - trace_jbd_start_commit(journal, commit_transaction); - jbd_debug(1, "JBD: starting commit of transaction %d\n", - commit_transaction->t_tid); - - spin_lock(&journal->j_state_lock); - J_ASSERT(commit_transaction->t_state == T_RUNNING); - commit_transaction->t_state = T_LOCKED; - - trace_jbd_commit_locking(journal, commit_transaction); - spin_lock(&commit_transaction->t_handle_lock); - while (commit_transaction->t_updates) { - DEFINE_WAIT(wait); - - prepare_to_wait(&journal->j_wait_updates, &wait, - TASK_UNINTERRUPTIBLE); - if (commit_transaction->t_updates) { - spin_unlock(&commit_transaction->t_handle_lock); - spin_unlock(&journal->j_state_lock); - schedule(); - spin_lock(&journal->j_state_lock); - spin_lock(&commit_transaction->t_handle_lock); - } - finish_wait(&journal->j_wait_updates, &wait); - } - spin_unlock(&commit_transaction->t_handle_lock); - - J_ASSERT (commit_transaction->t_outstanding_credits <= - journal->j_max_transaction_buffers); - - /* - * First thing we are allowed to do is to discard any remaining - * BJ_Reserved buffers. Note, it is _not_ permissible to assume - * that there are no such buffers: if a large filesystem - * operation like a truncate needs to split itself over multiple - * transactions, then it may try to do a journal_restart() while - * there are still BJ_Reserved buffers outstanding. These must - * be released cleanly from the current transaction. - * - * In this case, the filesystem must still reserve write access - * again before modifying the buffer in the new transaction, but - * we do not require it to remember exactly which old buffers it - * has reserved. This is consistent with the existing behaviour - * that multiple journal_get_write_access() calls to the same - * buffer are perfectly permissible. - */ - while (commit_transaction->t_reserved_list) { - jh = commit_transaction->t_reserved_list; - JBUFFER_TRACE(jh, "reserved, unused: refile"); - /* - * A journal_get_undo_access()+journal_release_buffer() may - * leave undo-committed data. - */ - if (jh->b_committed_data) { - struct buffer_head *bh = jh2bh(jh); - - jbd_lock_bh_state(bh); - jbd_free(jh->b_committed_data, bh->b_size); - jh->b_committed_data = NULL; - jbd_unlock_bh_state(bh); - } - journal_refile_buffer(journal, jh); - } - - /* - * Now try to drop any written-back buffers from the journal's - * checkpoint lists. We do this *before* commit because it potentially - * frees some memory - */ - spin_lock(&journal->j_list_lock); - __journal_clean_checkpoint_list(journal); - spin_unlock(&journal->j_list_lock); - - jbd_debug (3, "JBD: commit phase 1\n"); - - /* - * Clear revoked flag to reflect there is no revoked buffers - * in the next transaction which is going to be started. - */ - journal_clear_buffer_revoked_flags(journal); - - /* - * Switch to a new revoke table. - */ - journal_switch_revoke_table(journal); - - trace_jbd_commit_flushing(journal, commit_transaction); - commit_transaction->t_state = T_FLUSH; - journal->j_committing_transaction = commit_transaction; - journal->j_running_transaction = NULL; - start_time = ktime_get(); - commit_transaction->t_log_start = journal->j_head; - wake_up(&journal->j_wait_transaction_locked); - spin_unlock(&journal->j_state_lock); - - jbd_debug (3, "JBD: commit phase 2\n"); - - if (tid_geq(journal->j_commit_waited, commit_transaction->t_tid)) - write_op = WRITE_SYNC; - - /* - * Now start flushing things to disk, in the order they appear - * on the transaction lists. Data blocks go first. - */ - blk_start_plug(&plug); - err = journal_submit_data_buffers(journal, commit_transaction, - write_op); - blk_finish_plug(&plug); - - /* - * Wait for all previously submitted IO to complete. - */ - spin_lock(&journal->j_list_lock); - while (commit_transaction->t_locked_list) { - struct buffer_head *bh; - - jh = commit_transaction->t_locked_list->b_tprev; - bh = jh2bh(jh); - get_bh(bh); - if (buffer_locked(bh)) { - spin_unlock(&journal->j_list_lock); - wait_on_buffer(bh); - spin_lock(&journal->j_list_lock); - } - if (unlikely(!buffer_uptodate(bh))) { - if (!trylock_page(bh->b_page)) { - spin_unlock(&journal->j_list_lock); - lock_page(bh->b_page); - spin_lock(&journal->j_list_lock); - } - if (bh->b_page->mapping) - set_bit(AS_EIO, &bh->b_page->mapping->flags); - - unlock_page(bh->b_page); - SetPageError(bh->b_page); - err = -EIO; - } - if (!inverted_lock(journal, bh)) { - put_bh(bh); - spin_lock(&journal->j_list_lock); - continue; - } - if (buffer_jbd(bh) && bh2jh(bh) == jh && - jh->b_transaction == commit_transaction && - jh->b_jlist == BJ_Locked) - __journal_unfile_buffer(jh); - jbd_unlock_bh_state(bh); - release_data_buffer(bh); - cond_resched_lock(&journal->j_list_lock); - } - spin_unlock(&journal->j_list_lock); - - if (err) { - char b[BDEVNAME_SIZE]; - - printk(KERN_WARNING - "JBD: Detected IO errors while flushing file data " - "on %s\n", bdevname(journal->j_fs_dev, b)); - if (journal->j_flags & JFS_ABORT_ON_SYNCDATA_ERR) - journal_abort(journal, err); - err = 0; - } - - blk_start_plug(&plug); - - journal_write_revoke_records(journal, commit_transaction, write_op); - - /* - * If we found any dirty or locked buffers, then we should have - * looped back up to the write_out_data label. If there weren't - * any then journal_clean_data_list should have wiped the list - * clean by now, so check that it is in fact empty. - */ - J_ASSERT (commit_transaction->t_sync_datalist == NULL); - - jbd_debug (3, "JBD: commit phase 3\n"); - - /* - * Way to go: we have now written out all of the data for a - * transaction! Now comes the tricky part: we need to write out - * metadata. Loop over the transaction's entire buffer list: - */ - spin_lock(&journal->j_state_lock); - commit_transaction->t_state = T_COMMIT; - spin_unlock(&journal->j_state_lock); - - trace_jbd_commit_logging(journal, commit_transaction); - J_ASSERT(commit_transaction->t_nr_buffers <= - commit_transaction->t_outstanding_credits); - - descriptor = NULL; - bufs = 0; - while (commit_transaction->t_buffers) { - - /* Find the next buffer to be journaled... */ - - jh = commit_transaction->t_buffers; - - /* If we're in abort mode, we just un-journal the buffer and - release it. */ - - if (is_journal_aborted(journal)) { - clear_buffer_jbddirty(jh2bh(jh)); - JBUFFER_TRACE(jh, "journal is aborting: refile"); - journal_refile_buffer(journal, jh); - /* If that was the last one, we need to clean up - * any descriptor buffers which may have been - * already allocated, even if we are now - * aborting. */ - if (!commit_transaction->t_buffers) - goto start_journal_io; - continue; - } - - /* Make sure we have a descriptor block in which to - record the metadata buffer. */ - - if (!descriptor) { - struct buffer_head *bh; - - J_ASSERT (bufs == 0); - - jbd_debug(4, "JBD: get descriptor\n"); - - descriptor = journal_get_descriptor_buffer(journal); - if (!descriptor) { - journal_abort(journal, -EIO); - continue; - } - - bh = jh2bh(descriptor); - jbd_debug(4, "JBD: got buffer %llu (%p)\n", - (unsigned long long)bh->b_blocknr, bh->b_data); - header = (journal_header_t *)&bh->b_data[0]; - header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - header->h_blocktype = cpu_to_be32(JFS_DESCRIPTOR_BLOCK); - header->h_sequence = cpu_to_be32(commit_transaction->t_tid); - - tagp = &bh->b_data[sizeof(journal_header_t)]; - space_left = bh->b_size - sizeof(journal_header_t); - first_tag = 1; - set_buffer_jwrite(bh); - set_buffer_dirty(bh); - wbuf[bufs++] = bh; - - /* Record it so that we can wait for IO - completion later */ - BUFFER_TRACE(bh, "ph3: file as descriptor"); - journal_file_buffer(descriptor, commit_transaction, - BJ_LogCtl); - } - - /* Where is the buffer to be written? */ - - err = journal_next_log_block(journal, &blocknr); - /* If the block mapping failed, just abandon the buffer - and repeat this loop: we'll fall into the - refile-on-abort condition above. */ - if (err) { - journal_abort(journal, err); - continue; - } - - /* - * start_this_handle() uses t_outstanding_credits to determine - * the free space in the log, but this counter is changed - * by journal_next_log_block() also. - */ - commit_transaction->t_outstanding_credits--; - - /* Bump b_count to prevent truncate from stumbling over - the shadowed buffer! @@@ This can go if we ever get - rid of the BJ_IO/BJ_Shadow pairing of buffers. */ - get_bh(jh2bh(jh)); - - /* Make a temporary IO buffer with which to write it out - (this will requeue both the metadata buffer and the - temporary IO buffer). new_bh goes on BJ_IO*/ - - set_buffer_jwrite(jh2bh(jh)); - /* - * akpm: journal_write_metadata_buffer() sets - * new_bh->b_transaction to commit_transaction. - * We need to clean this up before we release new_bh - * (which is of type BJ_IO) - */ - JBUFFER_TRACE(jh, "ph3: write metadata"); - flags = journal_write_metadata_buffer(commit_transaction, - jh, &new_jh, blocknr); - set_buffer_jwrite(jh2bh(new_jh)); - wbuf[bufs++] = jh2bh(new_jh); - - /* Record the new block's tag in the current descriptor - buffer */ - - tag_flag = 0; - if (flags & 1) - tag_flag |= JFS_FLAG_ESCAPE; - if (!first_tag) - tag_flag |= JFS_FLAG_SAME_UUID; - - tag = (journal_block_tag_t *) tagp; - tag->t_blocknr = cpu_to_be32(jh2bh(jh)->b_blocknr); - tag->t_flags = cpu_to_be32(tag_flag); - tagp += sizeof(journal_block_tag_t); - space_left -= sizeof(journal_block_tag_t); - - if (first_tag) { - memcpy (tagp, journal->j_uuid, 16); - tagp += 16; - space_left -= 16; - first_tag = 0; - } - - /* If there's no more to do, or if the descriptor is full, - let the IO rip! */ - - if (bufs == journal->j_wbufsize || - commit_transaction->t_buffers == NULL || - space_left < sizeof(journal_block_tag_t) + 16) { - - jbd_debug(4, "JBD: Submit %d IOs\n", bufs); - - /* Write an end-of-descriptor marker before - submitting the IOs. "tag" still points to - the last tag we set up. */ - - tag->t_flags |= cpu_to_be32(JFS_FLAG_LAST_TAG); - -start_journal_io: - for (i = 0; i < bufs; i++) { - struct buffer_head *bh = wbuf[i]; - lock_buffer(bh); - clear_buffer_dirty(bh); - set_buffer_uptodate(bh); - bh->b_end_io = journal_end_buffer_io_sync; - /* - * In data=journal mode, here we can end up - * writing pagecache data that might be - * mmapped. Since we can't afford to clean the - * page and set PageWriteback (see the comment - * near the other use of _submit_bh()), the - * data can change while the write is in - * flight. Tell the block layer to bounce the - * bio pages if stable pages are required. - */ - _submit_bh(write_op, bh, 1 << BIO_SNAP_STABLE); - } - cond_resched(); - - /* Force a new descriptor to be generated next - time round the loop. */ - descriptor = NULL; - bufs = 0; - } - } - - blk_finish_plug(&plug); - - /* Lo and behold: we have just managed to send a transaction to - the log. Before we can commit it, wait for the IO so far to - complete. Control buffers being written are on the - transaction's t_log_list queue, and metadata buffers are on - the t_iobuf_list queue. - - Wait for the buffers in reverse order. That way we are - less likely to be woken up until all IOs have completed, and - so we incur less scheduling load. - */ - - jbd_debug(3, "JBD: commit phase 4\n"); - - /* - * akpm: these are BJ_IO, and j_list_lock is not needed. - * See __journal_try_to_free_buffer. - */ -wait_for_iobuf: - while (commit_transaction->t_iobuf_list != NULL) { - struct buffer_head *bh; - - jh = commit_transaction->t_iobuf_list->b_tprev; - bh = jh2bh(jh); - if (buffer_locked(bh)) { - wait_on_buffer(bh); - goto wait_for_iobuf; - } - if (cond_resched()) - goto wait_for_iobuf; - - if (unlikely(!buffer_uptodate(bh))) - err = -EIO; - - clear_buffer_jwrite(bh); - - JBUFFER_TRACE(jh, "ph4: unfile after journal write"); - journal_unfile_buffer(journal, jh); - - /* - * ->t_iobuf_list should contain only dummy buffer_heads - * which were created by journal_write_metadata_buffer(). - */ - BUFFER_TRACE(bh, "dumping temporary bh"); - journal_put_journal_head(jh); - __brelse(bh); - J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); - free_buffer_head(bh); - - /* We also have to unlock and free the corresponding - shadowed buffer */ - jh = commit_transaction->t_shadow_list->b_tprev; - bh = jh2bh(jh); - clear_buffer_jwrite(bh); - J_ASSERT_BH(bh, buffer_jbddirty(bh)); - - /* The metadata is now released for reuse, but we need - to remember it against this transaction so that when - we finally commit, we can do any checkpointing - required. */ - JBUFFER_TRACE(jh, "file as BJ_Forget"); - journal_file_buffer(jh, commit_transaction, BJ_Forget); - /* - * Wake up any transactions which were waiting for this - * IO to complete. The barrier must be here so that changes - * by journal_file_buffer() take effect before wake_up_bit() - * does the waitqueue check. - */ - smp_mb(); - wake_up_bit(&bh->b_state, BH_Unshadow); - JBUFFER_TRACE(jh, "brelse shadowed buffer"); - __brelse(bh); - } - - J_ASSERT (commit_transaction->t_shadow_list == NULL); - - jbd_debug(3, "JBD: commit phase 5\n"); - - /* Here we wait for the revoke record and descriptor record buffers */ - wait_for_ctlbuf: - while (commit_transaction->t_log_list != NULL) { - struct buffer_head *bh; - - jh = commit_transaction->t_log_list->b_tprev; - bh = jh2bh(jh); - if (buffer_locked(bh)) { - wait_on_buffer(bh); - goto wait_for_ctlbuf; - } - if (cond_resched()) - goto wait_for_ctlbuf; - - if (unlikely(!buffer_uptodate(bh))) - err = -EIO; - - BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); - clear_buffer_jwrite(bh); - journal_unfile_buffer(journal, jh); - journal_put_journal_head(jh); - __brelse(bh); /* One for getblk */ - /* AKPM: bforget here */ - } - - if (err) - journal_abort(journal, err); - - jbd_debug(3, "JBD: commit phase 6\n"); - - /* All metadata is written, now write commit record and do cleanup */ - spin_lock(&journal->j_state_lock); - J_ASSERT(commit_transaction->t_state == T_COMMIT); - commit_transaction->t_state = T_COMMIT_RECORD; - spin_unlock(&journal->j_state_lock); - - if (journal_write_commit_record(journal, commit_transaction)) - err = -EIO; - - if (err) - journal_abort(journal, err); - - /* End of a transaction! Finally, we can do checkpoint - processing: any buffers committed as a result of this - transaction can be removed from any checkpoint list it was on - before. */ - - jbd_debug(3, "JBD: commit phase 7\n"); - - J_ASSERT(commit_transaction->t_sync_datalist == NULL); - J_ASSERT(commit_transaction->t_buffers == NULL); - J_ASSERT(commit_transaction->t_checkpoint_list == NULL); - J_ASSERT(commit_transaction->t_iobuf_list == NULL); - J_ASSERT(commit_transaction->t_shadow_list == NULL); - J_ASSERT(commit_transaction->t_log_list == NULL); - -restart_loop: - /* - * As there are other places (journal_unmap_buffer()) adding buffers - * to this list we have to be careful and hold the j_list_lock. - */ - spin_lock(&journal->j_list_lock); - while (commit_transaction->t_forget) { - transaction_t *cp_transaction; - struct buffer_head *bh; - int try_to_free = 0; - - jh = commit_transaction->t_forget; - spin_unlock(&journal->j_list_lock); - bh = jh2bh(jh); - /* - * Get a reference so that bh cannot be freed before we are - * done with it. - */ - get_bh(bh); - jbd_lock_bh_state(bh); - J_ASSERT_JH(jh, jh->b_transaction == commit_transaction || - jh->b_transaction == journal->j_running_transaction); - - /* - * If there is undo-protected committed data against - * this buffer, then we can remove it now. If it is a - * buffer needing such protection, the old frozen_data - * field now points to a committed version of the - * buffer, so rotate that field to the new committed - * data. - * - * Otherwise, we can just throw away the frozen data now. - */ - if (jh->b_committed_data) { - jbd_free(jh->b_committed_data, bh->b_size); - jh->b_committed_data = NULL; - if (jh->b_frozen_data) { - jh->b_committed_data = jh->b_frozen_data; - jh->b_frozen_data = NULL; - } - } else if (jh->b_frozen_data) { - jbd_free(jh->b_frozen_data, bh->b_size); - jh->b_frozen_data = NULL; - } - - spin_lock(&journal->j_list_lock); - cp_transaction = jh->b_cp_transaction; - if (cp_transaction) { - JBUFFER_TRACE(jh, "remove from old cp transaction"); - __journal_remove_checkpoint(jh); - } - - /* Only re-checkpoint the buffer_head if it is marked - * dirty. If the buffer was added to the BJ_Forget list - * by journal_forget, it may no longer be dirty and - * there's no point in keeping a checkpoint record for - * it. */ - - /* - * A buffer which has been freed while still being journaled by - * a previous transaction. - */ - if (buffer_freed(bh)) { - /* - * If the running transaction is the one containing - * "add to orphan" operation (b_next_transaction != - * NULL), we have to wait for that transaction to - * commit before we can really get rid of the buffer. - * So just clear b_modified to not confuse transaction - * credit accounting and refile the buffer to - * BJ_Forget of the running transaction. If the just - * committed transaction contains "add to orphan" - * operation, we can completely invalidate the buffer - * now. We are rather throughout in that since the - * buffer may be still accessible when blocksize < - * pagesize and it is attached to the last partial - * page. - */ - jh->b_modified = 0; - if (!jh->b_next_transaction) { - clear_buffer_freed(bh); - clear_buffer_jbddirty(bh); - clear_buffer_mapped(bh); - clear_buffer_new(bh); - clear_buffer_req(bh); - bh->b_bdev = NULL; - } - } - - if (buffer_jbddirty(bh)) { - JBUFFER_TRACE(jh, "add to new checkpointing trans"); - __journal_insert_checkpoint(jh, commit_transaction); - if (is_journal_aborted(journal)) - clear_buffer_jbddirty(bh); - } else { - J_ASSERT_BH(bh, !buffer_dirty(bh)); - /* - * The buffer on BJ_Forget list and not jbddirty means - * it has been freed by this transaction and hence it - * could not have been reallocated until this - * transaction has committed. *BUT* it could be - * reallocated once we have written all the data to - * disk and before we process the buffer on BJ_Forget - * list. - */ - if (!jh->b_next_transaction) - try_to_free = 1; - } - JBUFFER_TRACE(jh, "refile or unfile freed buffer"); - __journal_refile_buffer(jh); - jbd_unlock_bh_state(bh); - if (try_to_free) - release_buffer_page(bh); - else - __brelse(bh); - cond_resched_lock(&journal->j_list_lock); - } - spin_unlock(&journal->j_list_lock); - /* - * This is a bit sleazy. We use j_list_lock to protect transition - * of a transaction into T_FINISHED state and calling - * __journal_drop_transaction(). Otherwise we could race with - * other checkpointing code processing the transaction... - */ - spin_lock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - /* - * Now recheck if some buffers did not get attached to the transaction - * while the lock was dropped... - */ - if (commit_transaction->t_forget) { - spin_unlock(&journal->j_list_lock); - spin_unlock(&journal->j_state_lock); - goto restart_loop; - } - - /* Done with this transaction! */ - - jbd_debug(3, "JBD: commit phase 8\n"); - - J_ASSERT(commit_transaction->t_state == T_COMMIT_RECORD); - - commit_transaction->t_state = T_FINISHED; - J_ASSERT(commit_transaction == journal->j_committing_transaction); - journal->j_commit_sequence = commit_transaction->t_tid; - journal->j_committing_transaction = NULL; - commit_time = ktime_to_ns(ktime_sub(ktime_get(), start_time)); - - /* - * weight the commit time higher than the average time so we don't - * react too strongly to vast changes in commit time - */ - if (likely(journal->j_average_commit_time)) - journal->j_average_commit_time = (commit_time*3 + - journal->j_average_commit_time) / 4; - else - journal->j_average_commit_time = commit_time; - - spin_unlock(&journal->j_state_lock); - - if (commit_transaction->t_checkpoint_list == NULL && - commit_transaction->t_checkpoint_io_list == NULL) { - __journal_drop_transaction(journal, commit_transaction); - } else { - if (journal->j_checkpoint_transactions == NULL) { - journal->j_checkpoint_transactions = commit_transaction; - commit_transaction->t_cpnext = commit_transaction; - commit_transaction->t_cpprev = commit_transaction; - } else { - commit_transaction->t_cpnext = - journal->j_checkpoint_transactions; - commit_transaction->t_cpprev = - commit_transaction->t_cpnext->t_cpprev; - commit_transaction->t_cpnext->t_cpprev = - commit_transaction; - commit_transaction->t_cpprev->t_cpnext = - commit_transaction; - } - } - spin_unlock(&journal->j_list_lock); - - trace_jbd_end_commit(journal, commit_transaction); - jbd_debug(1, "JBD: commit %d complete, head %d\n", - journal->j_commit_sequence, journal->j_tail_sequence); - - wake_up(&journal->j_wait_done_commit); -} diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c deleted file mode 100644 index c46a79adb6adf..0000000000000 --- a/fs/jbd/journal.c +++ /dev/null @@ -1,2145 +0,0 @@ -/* - * linux/fs/jbd/journal.c - * - * Written by Stephen C. Tweedie , 1998 - * - * Copyright 1998 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Generic filesystem journal-writing code; part of the ext2fs - * journaling system. - * - * This file manages journals: areas of disk reserved for logging - * transactional updates. This includes the kernel journaling thread - * which is responsible for scheduling updates to the log. - * - * We do not actually manage the physical storage of the journal in this - * file: that is left to a per-journal policy function, which allows us - * to store the journal within a filesystem-specified area for ext2 - * journaling (ext2 can use a reserved inode for storing the log). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -#include -#include - -EXPORT_SYMBOL(journal_start); -EXPORT_SYMBOL(journal_restart); -EXPORT_SYMBOL(journal_extend); -EXPORT_SYMBOL(journal_stop); -EXPORT_SYMBOL(journal_lock_updates); -EXPORT_SYMBOL(journal_unlock_updates); -EXPORT_SYMBOL(journal_get_write_access); -EXPORT_SYMBOL(journal_get_create_access); -EXPORT_SYMBOL(journal_get_undo_access); -EXPORT_SYMBOL(journal_dirty_data); -EXPORT_SYMBOL(journal_dirty_metadata); -EXPORT_SYMBOL(journal_release_buffer); -EXPORT_SYMBOL(journal_forget); -#if 0 -EXPORT_SYMBOL(journal_sync_buffer); -#endif -EXPORT_SYMBOL(journal_flush); -EXPORT_SYMBOL(journal_revoke); - -EXPORT_SYMBOL(journal_init_dev); -EXPORT_SYMBOL(journal_init_inode); -EXPORT_SYMBOL(journal_update_format); -EXPORT_SYMBOL(journal_check_used_features); -EXPORT_SYMBOL(journal_check_available_features); -EXPORT_SYMBOL(journal_set_features); -EXPORT_SYMBOL(journal_create); -EXPORT_SYMBOL(journal_load); -EXPORT_SYMBOL(journal_destroy); -EXPORT_SYMBOL(journal_abort); -EXPORT_SYMBOL(journal_errno); -EXPORT_SYMBOL(journal_ack_err); -EXPORT_SYMBOL(journal_clear_err); -EXPORT_SYMBOL(log_wait_commit); -EXPORT_SYMBOL(log_start_commit); -EXPORT_SYMBOL(journal_start_commit); -EXPORT_SYMBOL(journal_force_commit_nested); -EXPORT_SYMBOL(journal_wipe); -EXPORT_SYMBOL(journal_blocks_per_page); -EXPORT_SYMBOL(journal_invalidatepage); -EXPORT_SYMBOL(journal_try_to_free_buffers); -EXPORT_SYMBOL(journal_force_commit); - -static int journal_convert_superblock_v1(journal_t *, journal_superblock_t *); -static void __journal_abort_soft (journal_t *journal, int errno); -static const char *journal_dev_name(journal_t *journal, char *buffer); - -#ifdef CONFIG_JBD_DEBUG -void __jbd_debug(int level, const char *file, const char *func, - unsigned int line, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (level > journal_enable_debug) - return; - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_DEBUG "%s: (%s, %u): %pV\n", file, func, line, &vaf); - va_end(args); -} -EXPORT_SYMBOL(__jbd_debug); -#endif - -/* - * Helper function used to manage commit timeouts - */ - -static void commit_timeout(unsigned long __data) -{ - struct task_struct * p = (struct task_struct *) __data; - - wake_up_process(p); -} - -/* - * kjournald: The main thread function used to manage a logging device - * journal. - * - * This kernel thread is responsible for two things: - * - * 1) COMMIT: Every so often we need to commit the current state of the - * filesystem to disk. The journal thread is responsible for writing - * all of the metadata buffers to disk. - * - * 2) CHECKPOINT: We cannot reuse a used section of the log file until all - * of the data in that part of the log has been rewritten elsewhere on - * the disk. Flushing these old buffers to reclaim space in the log is - * known as checkpointing, and this thread is responsible for that job. - */ - -static int kjournald(void *arg) -{ - journal_t *journal = arg; - transaction_t *transaction; - - /* - * Set up an interval timer which can be used to trigger a commit wakeup - * after the commit interval expires - */ - setup_timer(&journal->j_commit_timer, commit_timeout, - (unsigned long)current); - - set_freezable(); - - /* Record that the journal thread is running */ - journal->j_task = current; - wake_up(&journal->j_wait_done_commit); - - printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", - journal->j_commit_interval / HZ); - - /* - * And now, wait forever for commit wakeup events. - */ - spin_lock(&journal->j_state_lock); - -loop: - if (journal->j_flags & JFS_UNMOUNT) - goto end_loop; - - jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", - journal->j_commit_sequence, journal->j_commit_request); - - if (journal->j_commit_sequence != journal->j_commit_request) { - jbd_debug(1, "OK, requests differ\n"); - spin_unlock(&journal->j_state_lock); - del_timer_sync(&journal->j_commit_timer); - journal_commit_transaction(journal); - spin_lock(&journal->j_state_lock); - goto loop; - } - - wake_up(&journal->j_wait_done_commit); - if (freezing(current)) { - /* - * The simpler the better. Flushing journal isn't a - * good idea, because that depends on threads that may - * be already stopped. - */ - jbd_debug(1, "Now suspending kjournald\n"); - spin_unlock(&journal->j_state_lock); - try_to_freeze(); - spin_lock(&journal->j_state_lock); - } else { - /* - * We assume on resume that commits are already there, - * so we don't sleep - */ - DEFINE_WAIT(wait); - int should_sleep = 1; - - prepare_to_wait(&journal->j_wait_commit, &wait, - TASK_INTERRUPTIBLE); - if (journal->j_commit_sequence != journal->j_commit_request) - should_sleep = 0; - transaction = journal->j_running_transaction; - if (transaction && time_after_eq(jiffies, - transaction->t_expires)) - should_sleep = 0; - if (journal->j_flags & JFS_UNMOUNT) - should_sleep = 0; - if (should_sleep) { - spin_unlock(&journal->j_state_lock); - schedule(); - spin_lock(&journal->j_state_lock); - } - finish_wait(&journal->j_wait_commit, &wait); - } - - jbd_debug(1, "kjournald wakes\n"); - - /* - * Were we woken up by a commit wakeup event? - */ - transaction = journal->j_running_transaction; - if (transaction && time_after_eq(jiffies, transaction->t_expires)) { - journal->j_commit_request = transaction->t_tid; - jbd_debug(1, "woke because of timeout\n"); - } - goto loop; - -end_loop: - spin_unlock(&journal->j_state_lock); - del_timer_sync(&journal->j_commit_timer); - journal->j_task = NULL; - wake_up(&journal->j_wait_done_commit); - jbd_debug(1, "Journal thread exiting.\n"); - return 0; -} - -static int journal_start_thread(journal_t *journal) -{ - struct task_struct *t; - - t = kthread_run(kjournald, journal, "kjournald"); - if (IS_ERR(t)) - return PTR_ERR(t); - - wait_event(journal->j_wait_done_commit, journal->j_task != NULL); - return 0; -} - -static void journal_kill_thread(journal_t *journal) -{ - spin_lock(&journal->j_state_lock); - journal->j_flags |= JFS_UNMOUNT; - - while (journal->j_task) { - wake_up(&journal->j_wait_commit); - spin_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_done_commit, - journal->j_task == NULL); - spin_lock(&journal->j_state_lock); - } - spin_unlock(&journal->j_state_lock); -} - -/* - * journal_write_metadata_buffer: write a metadata buffer to the journal. - * - * Writes a metadata buffer to a given disk block. The actual IO is not - * performed but a new buffer_head is constructed which labels the data - * to be written with the correct destination disk block. - * - * Any magic-number escaping which needs to be done will cause a - * copy-out here. If the buffer happens to start with the - * JFS_MAGIC_NUMBER, then we can't write it to the log directly: the - * magic number is only written to the log for descripter blocks. In - * this case, we copy the data and replace the first word with 0, and we - * return a result code which indicates that this buffer needs to be - * marked as an escaped buffer in the corresponding log descriptor - * block. The missing word can then be restored when the block is read - * during recovery. - * - * If the source buffer has already been modified by a new transaction - * since we took the last commit snapshot, we use the frozen copy of - * that data for IO. If we end up using the existing buffer_head's data - * for the write, then we *have* to lock the buffer to prevent anyone - * else from using and possibly modifying it while the IO is in - * progress. - * - * The function returns a pointer to the buffer_heads to be used for IO. - * - * We assume that the journal has already been locked in this function. - * - * Return value: - * <0: Error - * >=0: Finished OK - * - * On success: - * Bit 0 set == escape performed on the data - * Bit 1 set == buffer copy-out performed (kfree the data after IO) - */ - -int journal_write_metadata_buffer(transaction_t *transaction, - struct journal_head *jh_in, - struct journal_head **jh_out, - unsigned int blocknr) -{ - int need_copy_out = 0; - int done_copy_out = 0; - int do_escape = 0; - char *mapped_data; - struct buffer_head *new_bh; - struct journal_head *new_jh; - struct page *new_page; - unsigned int new_offset; - struct buffer_head *bh_in = jh2bh(jh_in); - journal_t *journal = transaction->t_journal; - - /* - * The buffer really shouldn't be locked: only the current committing - * transaction is allowed to write it, so nobody else is allowed - * to do any IO. - * - * akpm: except if we're journalling data, and write() output is - * also part of a shared mapping, and another thread has - * decided to launch a writepage() against this buffer. - */ - J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); - - new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); - /* keep subsequent assertions sane */ - atomic_set(&new_bh->b_count, 1); - new_jh = journal_add_journal_head(new_bh); /* This sleeps */ - - /* - * If a new transaction has already done a buffer copy-out, then - * we use that version of the data for the commit. - */ - jbd_lock_bh_state(bh_in); -repeat: - if (jh_in->b_frozen_data) { - done_copy_out = 1; - new_page = virt_to_page(jh_in->b_frozen_data); - new_offset = offset_in_page(jh_in->b_frozen_data); - } else { - new_page = jh2bh(jh_in)->b_page; - new_offset = offset_in_page(jh2bh(jh_in)->b_data); - } - - mapped_data = kmap_atomic(new_page); - /* - * Check for escaping - */ - if (*((__be32 *)(mapped_data + new_offset)) == - cpu_to_be32(JFS_MAGIC_NUMBER)) { - need_copy_out = 1; - do_escape = 1; - } - kunmap_atomic(mapped_data); - - /* - * Do we need to do a data copy? - */ - if (need_copy_out && !done_copy_out) { - char *tmp; - - jbd_unlock_bh_state(bh_in); - tmp = jbd_alloc(bh_in->b_size, GFP_NOFS); - jbd_lock_bh_state(bh_in); - if (jh_in->b_frozen_data) { - jbd_free(tmp, bh_in->b_size); - goto repeat; - } - - jh_in->b_frozen_data = tmp; - mapped_data = kmap_atomic(new_page); - memcpy(tmp, mapped_data + new_offset, jh2bh(jh_in)->b_size); - kunmap_atomic(mapped_data); - - new_page = virt_to_page(tmp); - new_offset = offset_in_page(tmp); - done_copy_out = 1; - } - - /* - * Did we need to do an escaping? Now we've done all the - * copying, we can finally do so. - */ - if (do_escape) { - mapped_data = kmap_atomic(new_page); - *((unsigned int *)(mapped_data + new_offset)) = 0; - kunmap_atomic(mapped_data); - } - - set_bh_page(new_bh, new_page, new_offset); - new_jh->b_transaction = NULL; - new_bh->b_size = jh2bh(jh_in)->b_size; - new_bh->b_bdev = transaction->t_journal->j_dev; - new_bh->b_blocknr = blocknr; - set_buffer_mapped(new_bh); - set_buffer_dirty(new_bh); - - *jh_out = new_jh; - - /* - * The to-be-written buffer needs to get moved to the io queue, - * and the original buffer whose contents we are shadowing or - * copying is moved to the transaction's shadow queue. - */ - JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); - spin_lock(&journal->j_list_lock); - __journal_file_buffer(jh_in, transaction, BJ_Shadow); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh_in); - - JBUFFER_TRACE(new_jh, "file as BJ_IO"); - journal_file_buffer(new_jh, transaction, BJ_IO); - - return do_escape | (done_copy_out << 1); -} - -/* - * Allocation code for the journal file. Manage the space left in the - * journal, so that we can begin checkpointing when appropriate. - */ - -/* - * __log_space_left: Return the number of free blocks left in the journal. - * - * Called with the journal already locked. - * - * Called under j_state_lock - */ - -int __log_space_left(journal_t *journal) -{ - int left = journal->j_free; - - assert_spin_locked(&journal->j_state_lock); - - /* - * Be pessimistic here about the number of those free blocks which - * might be required for log descriptor control blocks. - */ - -#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */ - - left -= MIN_LOG_RESERVED_BLOCKS; - - if (left <= 0) - return 0; - left -= (left >> 3); - return left; -} - -/* - * Called under j_state_lock. Returns true if a transaction commit was started. - */ -int __log_start_commit(journal_t *journal, tid_t target) -{ - /* - * The only transaction we can possibly wait upon is the - * currently running transaction (if it exists). Otherwise, - * the target tid must be an old one. - */ - if (journal->j_commit_request != target && - journal->j_running_transaction && - journal->j_running_transaction->t_tid == target) { - /* - * We want a new commit: OK, mark the request and wakeup the - * commit thread. We do _not_ do the commit ourselves. - */ - - journal->j_commit_request = target; - jbd_debug(1, "JBD: requesting commit %d/%d\n", - journal->j_commit_request, - journal->j_commit_sequence); - wake_up(&journal->j_wait_commit); - return 1; - } else if (!tid_geq(journal->j_commit_request, target)) - /* This should never happen, but if it does, preserve - the evidence before kjournald goes into a loop and - increments j_commit_sequence beyond all recognition. */ - WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n", - journal->j_commit_request, journal->j_commit_sequence, - target, journal->j_running_transaction ? - journal->j_running_transaction->t_tid : 0); - return 0; -} - -int log_start_commit(journal_t *journal, tid_t tid) -{ - int ret; - - spin_lock(&journal->j_state_lock); - ret = __log_start_commit(journal, tid); - spin_unlock(&journal->j_state_lock); - return ret; -} - -/* - * Force and wait upon a commit if the calling process is not within - * transaction. This is used for forcing out undo-protected data which contains - * bitmaps, when the fs is running out of space. - * - * We can only force the running transaction if we don't have an active handle; - * otherwise, we will deadlock. - * - * Returns true if a transaction was started. - */ -int journal_force_commit_nested(journal_t *journal) -{ - transaction_t *transaction = NULL; - tid_t tid; - - spin_lock(&journal->j_state_lock); - if (journal->j_running_transaction && !current->journal_info) { - transaction = journal->j_running_transaction; - __log_start_commit(journal, transaction->t_tid); - } else if (journal->j_committing_transaction) - transaction = journal->j_committing_transaction; - - if (!transaction) { - spin_unlock(&journal->j_state_lock); - return 0; /* Nothing to retry */ - } - - tid = transaction->t_tid; - spin_unlock(&journal->j_state_lock); - log_wait_commit(journal, tid); - return 1; -} - -/* - * Start a commit of the current running transaction (if any). Returns true - * if a transaction is going to be committed (or is currently already - * committing), and fills its tid in at *ptid - */ -int journal_start_commit(journal_t *journal, tid_t *ptid) -{ - int ret = 0; - - spin_lock(&journal->j_state_lock); - if (journal->j_running_transaction) { - tid_t tid = journal->j_running_transaction->t_tid; - - __log_start_commit(journal, tid); - /* There's a running transaction and we've just made sure - * it's commit has been scheduled. */ - if (ptid) - *ptid = tid; - ret = 1; - } else if (journal->j_committing_transaction) { - /* - * If commit has been started, then we have to wait for - * completion of that transaction. - */ - if (ptid) - *ptid = journal->j_committing_transaction->t_tid; - ret = 1; - } - spin_unlock(&journal->j_state_lock); - return ret; -} - -/* - * Wait for a specified commit to complete. - * The caller may not hold the journal lock. - */ -int log_wait_commit(journal_t *journal, tid_t tid) -{ - int err = 0; - -#ifdef CONFIG_JBD_DEBUG - spin_lock(&journal->j_state_lock); - if (!tid_geq(journal->j_commit_request, tid)) { - printk(KERN_ERR - "%s: error: j_commit_request=%d, tid=%d\n", - __func__, journal->j_commit_request, tid); - } - spin_unlock(&journal->j_state_lock); -#endif - spin_lock(&journal->j_state_lock); - /* - * Not running or committing trans? Must be already committed. This - * saves us from waiting for a *long* time when tid overflows. - */ - if (!((journal->j_running_transaction && - journal->j_running_transaction->t_tid == tid) || - (journal->j_committing_transaction && - journal->j_committing_transaction->t_tid == tid))) - goto out_unlock; - - if (!tid_geq(journal->j_commit_waited, tid)) - journal->j_commit_waited = tid; - while (tid_gt(tid, journal->j_commit_sequence)) { - jbd_debug(1, "JBD: want %d, j_commit_sequence=%d\n", - tid, journal->j_commit_sequence); - wake_up(&journal->j_wait_commit); - spin_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_done_commit, - !tid_gt(tid, journal->j_commit_sequence)); - spin_lock(&journal->j_state_lock); - } -out_unlock: - spin_unlock(&journal->j_state_lock); - - if (unlikely(is_journal_aborted(journal))) - err = -EIO; - return err; -} - -/* - * Return 1 if a given transaction has not yet sent barrier request - * connected with a transaction commit. If 0 is returned, transaction - * may or may not have sent the barrier. Used to avoid sending barrier - * twice in common cases. - */ -int journal_trans_will_send_data_barrier(journal_t *journal, tid_t tid) -{ - int ret = 0; - transaction_t *commit_trans; - - if (!(journal->j_flags & JFS_BARRIER)) - return 0; - spin_lock(&journal->j_state_lock); - /* Transaction already committed? */ - if (tid_geq(journal->j_commit_sequence, tid)) - goto out; - /* - * Transaction is being committed and we already proceeded to - * writing commit record? - */ - commit_trans = journal->j_committing_transaction; - if (commit_trans && commit_trans->t_tid == tid && - commit_trans->t_state >= T_COMMIT_RECORD) - goto out; - ret = 1; -out: - spin_unlock(&journal->j_state_lock); - return ret; -} -EXPORT_SYMBOL(journal_trans_will_send_data_barrier); - -/* - * Log buffer allocation routines: - */ - -int journal_next_log_block(journal_t *journal, unsigned int *retp) -{ - unsigned int blocknr; - - spin_lock(&journal->j_state_lock); - J_ASSERT(journal->j_free > 1); - - blocknr = journal->j_head; - journal->j_head++; - journal->j_free--; - if (journal->j_head == journal->j_last) - journal->j_head = journal->j_first; - spin_unlock(&journal->j_state_lock); - return journal_bmap(journal, blocknr, retp); -} - -/* - * Conversion of logical to physical block numbers for the journal - * - * On external journals the journal blocks are identity-mapped, so - * this is a no-op. If needed, we can use j_blk_offset - everything is - * ready. - */ -int journal_bmap(journal_t *journal, unsigned int blocknr, - unsigned int *retp) -{ - int err = 0; - unsigned int ret; - - if (journal->j_inode) { - ret = bmap(journal->j_inode, blocknr); - if (ret) - *retp = ret; - else { - char b[BDEVNAME_SIZE]; - - printk(KERN_ALERT "%s: journal block not found " - "at offset %u on %s\n", - __func__, - blocknr, - bdevname(journal->j_dev, b)); - err = -EIO; - __journal_abort_soft(journal, err); - } - } else { - *retp = blocknr; /* +journal->j_blk_offset */ - } - return err; -} - -/* - * We play buffer_head aliasing tricks to write data/metadata blocks to - * the journal without copying their contents, but for journal - * descriptor blocks we do need to generate bona fide buffers. - * - * After the caller of journal_get_descriptor_buffer() has finished modifying - * the buffer's contents they really should run flush_dcache_page(bh->b_page). - * But we don't bother doing that, so there will be coherency problems with - * mmaps of blockdevs which hold live JBD-controlled filesystems. - */ -struct journal_head *journal_get_descriptor_buffer(journal_t *journal) -{ - struct buffer_head *bh; - unsigned int blocknr; - int err; - - err = journal_next_log_block(journal, &blocknr); - - if (err) - return NULL; - - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) - return NULL; - lock_buffer(bh); - memset(bh->b_data, 0, journal->j_blocksize); - set_buffer_uptodate(bh); - unlock_buffer(bh); - BUFFER_TRACE(bh, "return this buffer"); - return journal_add_journal_head(bh); -} - -/* - * Management for journal control blocks: functions to create and - * destroy journal_t structures, and to initialise and read existing - * journal blocks from disk. */ - -/* First: create and setup a journal_t object in memory. We initialise - * very few fields yet: that has to wait until we have created the - * journal structures from from scratch, or loaded them from disk. */ - -static journal_t * journal_init_common (void) -{ - journal_t *journal; - int err; - - journal = kzalloc(sizeof(*journal), GFP_KERNEL); - if (!journal) - goto fail; - - init_waitqueue_head(&journal->j_wait_transaction_locked); - init_waitqueue_head(&journal->j_wait_logspace); - init_waitqueue_head(&journal->j_wait_done_commit); - init_waitqueue_head(&journal->j_wait_checkpoint); - init_waitqueue_head(&journal->j_wait_commit); - init_waitqueue_head(&journal->j_wait_updates); - mutex_init(&journal->j_checkpoint_mutex); - spin_lock_init(&journal->j_revoke_lock); - spin_lock_init(&journal->j_list_lock); - spin_lock_init(&journal->j_state_lock); - - journal->j_commit_interval = (HZ * JBD_DEFAULT_MAX_COMMIT_AGE); - - /* The journal is marked for error until we succeed with recovery! */ - journal->j_flags = JFS_ABORT; - - /* Set up a default-sized revoke table for the new mount. */ - err = journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); - if (err) { - kfree(journal); - goto fail; - } - return journal; -fail: - return NULL; -} - -/* journal_init_dev and journal_init_inode: - * - * Create a journal structure assigned some fixed set of disk blocks to - * the journal. We don't actually touch those disk blocks yet, but we - * need to set up all of the mapping information to tell the journaling - * system where the journal blocks are. - * - */ - -/** - * journal_t * journal_init_dev() - creates and initialises a journal structure - * @bdev: Block device on which to create the journal - * @fs_dev: Device which hold journalled filesystem for this journal. - * @start: Block nr Start of journal. - * @len: Length of the journal in blocks. - * @blocksize: blocksize of journalling device - * - * Returns: a newly created journal_t * - * - * journal_init_dev creates a journal which maps a fixed contiguous - * range of blocks on an arbitrary block device. - * - */ -journal_t * journal_init_dev(struct block_device *bdev, - struct block_device *fs_dev, - int start, int len, int blocksize) -{ - journal_t *journal = journal_init_common(); - struct buffer_head *bh; - int n; - - if (!journal) - return NULL; - - /* journal descriptor can store up to n blocks -bzzz */ - journal->j_blocksize = blocksize; - n = journal->j_blocksize / sizeof(journal_block_tag_t); - journal->j_wbufsize = n; - journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); - if (!journal->j_wbuf) { - printk(KERN_ERR "%s: Can't allocate bhs for commit thread\n", - __func__); - goto out_err; - } - journal->j_dev = bdev; - journal->j_fs_dev = fs_dev; - journal->j_blk_offset = start; - journal->j_maxlen = len; - - bh = __getblk(journal->j_dev, start, journal->j_blocksize); - if (!bh) { - printk(KERN_ERR - "%s: Cannot get buffer for journal superblock\n", - __func__); - goto out_err; - } - journal->j_sb_buffer = bh; - journal->j_superblock = (journal_superblock_t *)bh->b_data; - - return journal; -out_err: - kfree(journal->j_wbuf); - kfree(journal); - return NULL; -} - -/** - * journal_t * journal_init_inode () - creates a journal which maps to a inode. - * @inode: An inode to create the journal in - * - * journal_init_inode creates a journal which maps an on-disk inode as - * the journal. The inode must exist already, must support bmap() and - * must have all data blocks preallocated. - */ -journal_t * journal_init_inode (struct inode *inode) -{ - struct buffer_head *bh; - journal_t *journal = journal_init_common(); - int err; - int n; - unsigned int blocknr; - - if (!journal) - return NULL; - - journal->j_dev = journal->j_fs_dev = inode->i_sb->s_bdev; - journal->j_inode = inode; - jbd_debug(1, - "journal %p: inode %s/%ld, size %Ld, bits %d, blksize %ld\n", - journal, inode->i_sb->s_id, inode->i_ino, - (long long) inode->i_size, - inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); - - journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits; - journal->j_blocksize = inode->i_sb->s_blocksize; - - /* journal descriptor can store up to n blocks -bzzz */ - n = journal->j_blocksize / sizeof(journal_block_tag_t); - journal->j_wbufsize = n; - journal->j_wbuf = kmalloc(n * sizeof(struct buffer_head*), GFP_KERNEL); - if (!journal->j_wbuf) { - printk(KERN_ERR "%s: Can't allocate bhs for commit thread\n", - __func__); - goto out_err; - } - - err = journal_bmap(journal, 0, &blocknr); - /* If that failed, give up */ - if (err) { - printk(KERN_ERR "%s: Cannot locate journal superblock\n", - __func__); - goto out_err; - } - - bh = getblk_unmovable(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) { - printk(KERN_ERR - "%s: Cannot get buffer for journal superblock\n", - __func__); - goto out_err; - } - journal->j_sb_buffer = bh; - journal->j_superblock = (journal_superblock_t *)bh->b_data; - - return journal; -out_err: - kfree(journal->j_wbuf); - kfree(journal); - return NULL; -} - -/* - * If the journal init or create aborts, we need to mark the journal - * superblock as being NULL to prevent the journal destroy from writing - * back a bogus superblock. - */ -static void journal_fail_superblock (journal_t *journal) -{ - struct buffer_head *bh = journal->j_sb_buffer; - brelse(bh); - journal->j_sb_buffer = NULL; -} - -/* - * Given a journal_t structure, initialise the various fields for - * startup of a new journaling session. We use this both when creating - * a journal, and after recovering an old journal to reset it for - * subsequent use. - */ - -static int journal_reset(journal_t *journal) -{ - journal_superblock_t *sb = journal->j_superblock; - unsigned int first, last; - - first = be32_to_cpu(sb->s_first); - last = be32_to_cpu(sb->s_maxlen); - if (first + JFS_MIN_JOURNAL_BLOCKS > last + 1) { - printk(KERN_ERR "JBD: Journal too short (blocks %u-%u).\n", - first, last); - journal_fail_superblock(journal); - return -EINVAL; - } - - journal->j_first = first; - journal->j_last = last; - - journal->j_head = first; - journal->j_tail = first; - journal->j_free = last - first; - - journal->j_tail_sequence = journal->j_transaction_sequence; - journal->j_commit_sequence = journal->j_transaction_sequence - 1; - journal->j_commit_request = journal->j_commit_sequence; - - journal->j_max_transaction_buffers = journal->j_maxlen / 4; - - /* - * As a special case, if the on-disk copy is already marked as needing - * no recovery (s_start == 0), then we can safely defer the superblock - * update until the next commit by setting JFS_FLUSHED. This avoids - * attempting a write to a potential-readonly device. - */ - if (sb->s_start == 0) { - jbd_debug(1,"JBD: Skipping superblock update on recovered sb " - "(start %u, seq %d, errno %d)\n", - journal->j_tail, journal->j_tail_sequence, - journal->j_errno); - journal->j_flags |= JFS_FLUSHED; - } else { - /* Lock here to make assertions happy... */ - mutex_lock(&journal->j_checkpoint_mutex); - /* - * Update log tail information. We use WRITE_FUA since new - * transaction will start reusing journal space and so we - * must make sure information about current log tail is on - * disk before that. - */ - journal_update_sb_log_tail(journal, - journal->j_tail_sequence, - journal->j_tail, - WRITE_FUA); - mutex_unlock(&journal->j_checkpoint_mutex); - } - return journal_start_thread(journal); -} - -/** - * int journal_create() - Initialise the new journal file - * @journal: Journal to create. This structure must have been initialised - * - * Given a journal_t structure which tells us which disk blocks we can - * use, create a new journal superblock and initialise all of the - * journal fields from scratch. - **/ -int journal_create(journal_t *journal) -{ - unsigned int blocknr; - struct buffer_head *bh; - journal_superblock_t *sb; - int i, err; - - if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) { - printk (KERN_ERR "Journal length (%d blocks) too short.\n", - journal->j_maxlen); - journal_fail_superblock(journal); - return -EINVAL; - } - - if (journal->j_inode == NULL) { - /* - * We don't know what block to start at! - */ - printk(KERN_EMERG - "%s: creation of journal on external device!\n", - __func__); - BUG(); - } - - /* Zero out the entire journal on disk. We cannot afford to - have any blocks on disk beginning with JFS_MAGIC_NUMBER. */ - jbd_debug(1, "JBD: Zeroing out journal blocks...\n"); - for (i = 0; i < journal->j_maxlen; i++) { - err = journal_bmap(journal, i, &blocknr); - if (err) - return err; - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (unlikely(!bh)) - return -ENOMEM; - lock_buffer(bh); - memset (bh->b_data, 0, journal->j_blocksize); - BUFFER_TRACE(bh, "marking dirty"); - mark_buffer_dirty(bh); - BUFFER_TRACE(bh, "marking uptodate"); - set_buffer_uptodate(bh); - unlock_buffer(bh); - __brelse(bh); - } - - sync_blockdev(journal->j_dev); - jbd_debug(1, "JBD: journal cleared.\n"); - - /* OK, fill in the initial static fields in the new superblock */ - sb = journal->j_superblock; - - sb->s_header.h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); - - sb->s_blocksize = cpu_to_be32(journal->j_blocksize); - sb->s_maxlen = cpu_to_be32(journal->j_maxlen); - sb->s_first = cpu_to_be32(1); - - journal->j_transaction_sequence = 1; - - journal->j_flags &= ~JFS_ABORT; - journal->j_format_version = 2; - - return journal_reset(journal); -} - -static void journal_write_superblock(journal_t *journal, int write_op) -{ - struct buffer_head *bh = journal->j_sb_buffer; - int ret; - - trace_journal_write_superblock(journal, write_op); - if (!(journal->j_flags & JFS_BARRIER)) - write_op &= ~(REQ_FUA | REQ_FLUSH); - lock_buffer(bh); - if (buffer_write_io_error(bh)) { - char b[BDEVNAME_SIZE]; - /* - * Oh, dear. A previous attempt to write the journal - * superblock failed. This could happen because the - * USB device was yanked out. Or it could happen to - * be a transient write error and maybe the block will - * be remapped. Nothing we can do but to retry the - * write and hope for the best. - */ - printk(KERN_ERR "JBD: previous I/O error detected " - "for journal superblock update for %s.\n", - journal_dev_name(journal, b)); - clear_buffer_write_io_error(bh); - set_buffer_uptodate(bh); - } - - get_bh(bh); - bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(write_op, bh); - wait_on_buffer(bh); - if (buffer_write_io_error(bh)) { - clear_buffer_write_io_error(bh); - set_buffer_uptodate(bh); - ret = -EIO; - } - if (ret) { - char b[BDEVNAME_SIZE]; - printk(KERN_ERR "JBD: Error %d detected " - "when updating journal superblock for %s.\n", - ret, journal_dev_name(journal, b)); - } -} - -/** - * journal_update_sb_log_tail() - Update log tail in journal sb on disk. - * @journal: The journal to update. - * @tail_tid: TID of the new transaction at the tail of the log - * @tail_block: The first block of the transaction at the tail of the log - * @write_op: With which operation should we write the journal sb - * - * Update a journal's superblock information about log tail and write it to - * disk, waiting for the IO to complete. - */ -void journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, - unsigned int tail_block, int write_op) -{ - journal_superblock_t *sb = journal->j_superblock; - - BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); - jbd_debug(1,"JBD: updating superblock (start %u, seq %u)\n", - tail_block, tail_tid); - - sb->s_sequence = cpu_to_be32(tail_tid); - sb->s_start = cpu_to_be32(tail_block); - - journal_write_superblock(journal, write_op); - - /* Log is no longer empty */ - spin_lock(&journal->j_state_lock); - WARN_ON(!sb->s_sequence); - journal->j_flags &= ~JFS_FLUSHED; - spin_unlock(&journal->j_state_lock); -} - -/** - * mark_journal_empty() - Mark on disk journal as empty. - * @journal: The journal to update. - * - * Update a journal's dynamic superblock fields to show that journal is empty. - * Write updated superblock to disk waiting for IO to complete. - */ -static void mark_journal_empty(journal_t *journal) -{ - journal_superblock_t *sb = journal->j_superblock; - - BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); - spin_lock(&journal->j_state_lock); - /* Is it already empty? */ - if (sb->s_start == 0) { - spin_unlock(&journal->j_state_lock); - return; - } - jbd_debug(1, "JBD: Marking journal as empty (seq %d)\n", - journal->j_tail_sequence); - - sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); - sb->s_start = cpu_to_be32(0); - spin_unlock(&journal->j_state_lock); - - journal_write_superblock(journal, WRITE_FUA); - - spin_lock(&journal->j_state_lock); - /* Log is empty */ - journal->j_flags |= JFS_FLUSHED; - spin_unlock(&journal->j_state_lock); -} - -/** - * journal_update_sb_errno() - Update error in the journal. - * @journal: The journal to update. - * - * Update a journal's errno. Write updated superblock to disk waiting for IO - * to complete. - */ -static void journal_update_sb_errno(journal_t *journal) -{ - journal_superblock_t *sb = journal->j_superblock; - - spin_lock(&journal->j_state_lock); - jbd_debug(1, "JBD: updating superblock error (errno %d)\n", - journal->j_errno); - sb->s_errno = cpu_to_be32(journal->j_errno); - spin_unlock(&journal->j_state_lock); - - journal_write_superblock(journal, WRITE_SYNC); -} - -/* - * Read the superblock for a given journal, performing initial - * validation of the format. - */ - -static int journal_get_superblock(journal_t *journal) -{ - struct buffer_head *bh; - journal_superblock_t *sb; - int err = -EIO; - - bh = journal->j_sb_buffer; - - J_ASSERT(bh != NULL); - if (!buffer_uptodate(bh)) { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - printk (KERN_ERR - "JBD: IO error reading journal superblock\n"); - goto out; - } - } - - sb = journal->j_superblock; - - err = -EINVAL; - - if (sb->s_header.h_magic != cpu_to_be32(JFS_MAGIC_NUMBER) || - sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) { - printk(KERN_WARNING "JBD: no valid journal superblock found\n"); - goto out; - } - - switch(be32_to_cpu(sb->s_header.h_blocktype)) { - case JFS_SUPERBLOCK_V1: - journal->j_format_version = 1; - break; - case JFS_SUPERBLOCK_V2: - journal->j_format_version = 2; - break; - default: - printk(KERN_WARNING "JBD: unrecognised superblock format ID\n"); - goto out; - } - - if (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen) - journal->j_maxlen = be32_to_cpu(sb->s_maxlen); - else if (be32_to_cpu(sb->s_maxlen) > journal->j_maxlen) { - printk (KERN_WARNING "JBD: journal file too short\n"); - goto out; - } - - if (be32_to_cpu(sb->s_first) == 0 || - be32_to_cpu(sb->s_first) >= journal->j_maxlen) { - printk(KERN_WARNING - "JBD: Invalid start block of journal: %u\n", - be32_to_cpu(sb->s_first)); - goto out; - } - - return 0; - -out: - journal_fail_superblock(journal); - return err; -} - -/* - * Load the on-disk journal superblock and read the key fields into the - * journal_t. - */ - -static int load_superblock(journal_t *journal) -{ - int err; - journal_superblock_t *sb; - - err = journal_get_superblock(journal); - if (err) - return err; - - sb = journal->j_superblock; - - journal->j_tail_sequence = be32_to_cpu(sb->s_sequence); - journal->j_tail = be32_to_cpu(sb->s_start); - journal->j_first = be32_to_cpu(sb->s_first); - journal->j_last = be32_to_cpu(sb->s_maxlen); - journal->j_errno = be32_to_cpu(sb->s_errno); - - return 0; -} - - -/** - * int journal_load() - Read journal from disk. - * @journal: Journal to act on. - * - * Given a journal_t structure which tells us which disk blocks contain - * a journal, read the journal from disk to initialise the in-memory - * structures. - */ -int journal_load(journal_t *journal) -{ - int err; - journal_superblock_t *sb; - - err = load_superblock(journal); - if (err) - return err; - - sb = journal->j_superblock; - /* If this is a V2 superblock, then we have to check the - * features flags on it. */ - - if (journal->j_format_version >= 2) { - if ((sb->s_feature_ro_compat & - ~cpu_to_be32(JFS_KNOWN_ROCOMPAT_FEATURES)) || - (sb->s_feature_incompat & - ~cpu_to_be32(JFS_KNOWN_INCOMPAT_FEATURES))) { - printk (KERN_WARNING - "JBD: Unrecognised features on journal\n"); - return -EINVAL; - } - } - - /* Let the recovery code check whether it needs to recover any - * data from the journal. */ - if (journal_recover(journal)) - goto recovery_error; - - /* OK, we've finished with the dynamic journal bits: - * reinitialise the dynamic contents of the superblock in memory - * and reset them on disk. */ - if (journal_reset(journal)) - goto recovery_error; - - journal->j_flags &= ~JFS_ABORT; - journal->j_flags |= JFS_LOADED; - return 0; - -recovery_error: - printk (KERN_WARNING "JBD: recovery failed\n"); - return -EIO; -} - -/** - * void journal_destroy() - Release a journal_t structure. - * @journal: Journal to act on. - * - * Release a journal_t structure once it is no longer in use by the - * journaled object. - * Return <0 if we couldn't clean up the journal. - */ -int journal_destroy(journal_t *journal) -{ - int err = 0; - - - /* Wait for the commit thread to wake up and die. */ - journal_kill_thread(journal); - - /* Force a final log commit */ - if (journal->j_running_transaction) - journal_commit_transaction(journal); - - /* Force any old transactions to disk */ - - /* We cannot race with anybody but must keep assertions happy */ - mutex_lock(&journal->j_checkpoint_mutex); - /* Totally anal locking here... */ - spin_lock(&journal->j_list_lock); - while (journal->j_checkpoint_transactions != NULL) { - spin_unlock(&journal->j_list_lock); - log_do_checkpoint(journal); - spin_lock(&journal->j_list_lock); - } - - J_ASSERT(journal->j_running_transaction == NULL); - J_ASSERT(journal->j_committing_transaction == NULL); - J_ASSERT(journal->j_checkpoint_transactions == NULL); - spin_unlock(&journal->j_list_lock); - - if (journal->j_sb_buffer) { - if (!is_journal_aborted(journal)) { - journal->j_tail_sequence = - ++journal->j_transaction_sequence; - mark_journal_empty(journal); - } else - err = -EIO; - brelse(journal->j_sb_buffer); - } - mutex_unlock(&journal->j_checkpoint_mutex); - - iput(journal->j_inode); - if (journal->j_revoke) - journal_destroy_revoke(journal); - kfree(journal->j_wbuf); - kfree(journal); - - return err; -} - - -/** - *int journal_check_used_features () - Check if features specified are used. - * @journal: Journal to check. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Check whether the journal uses all of a given set of - * features. Return true (non-zero) if it does. - **/ - -int journal_check_used_features (journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ - journal_superblock_t *sb; - - if (!compat && !ro && !incompat) - return 1; - if (journal->j_format_version == 1) - return 0; - - sb = journal->j_superblock; - - if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) && - ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) && - ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat)) - return 1; - - return 0; -} - -/** - * int journal_check_available_features() - Check feature set in journalling layer - * @journal: Journal to check. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Check whether the journaling code supports the use of - * all of a given set of features on this journal. Return true - * (non-zero) if it can. */ - -int journal_check_available_features (journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ - if (!compat && !ro && !incompat) - return 1; - - /* We can support any known requested features iff the - * superblock is in version 2. Otherwise we fail to support any - * extended sb features. */ - - if (journal->j_format_version != 2) - return 0; - - if ((compat & JFS_KNOWN_COMPAT_FEATURES) == compat && - (ro & JFS_KNOWN_ROCOMPAT_FEATURES) == ro && - (incompat & JFS_KNOWN_INCOMPAT_FEATURES) == incompat) - return 1; - - return 0; -} - -/** - * int journal_set_features () - Mark a given journal feature in the superblock - * @journal: Journal to act on. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Mark a given journal feature as present on the - * superblock. Returns true if the requested features could be set. - * - */ - -int journal_set_features (journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ - journal_superblock_t *sb; - - if (journal_check_used_features(journal, compat, ro, incompat)) - return 1; - - if (!journal_check_available_features(journal, compat, ro, incompat)) - return 0; - - jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", - compat, ro, incompat); - - sb = journal->j_superblock; - - sb->s_feature_compat |= cpu_to_be32(compat); - sb->s_feature_ro_compat |= cpu_to_be32(ro); - sb->s_feature_incompat |= cpu_to_be32(incompat); - - return 1; -} - - -/** - * int journal_update_format () - Update on-disk journal structure. - * @journal: Journal to act on. - * - * Given an initialised but unloaded journal struct, poke about in the - * on-disk structure to update it to the most recent supported version. - */ -int journal_update_format (journal_t *journal) -{ - journal_superblock_t *sb; - int err; - - err = journal_get_superblock(journal); - if (err) - return err; - - sb = journal->j_superblock; - - switch (be32_to_cpu(sb->s_header.h_blocktype)) { - case JFS_SUPERBLOCK_V2: - return 0; - case JFS_SUPERBLOCK_V1: - return journal_convert_superblock_v1(journal, sb); - default: - break; - } - return -EINVAL; -} - -static int journal_convert_superblock_v1(journal_t *journal, - journal_superblock_t *sb) -{ - int offset, blocksize; - struct buffer_head *bh; - - printk(KERN_WARNING - "JBD: Converting superblock from version 1 to 2.\n"); - - /* Pre-initialise new fields to zero */ - offset = ((char *) &(sb->s_feature_compat)) - ((char *) sb); - blocksize = be32_to_cpu(sb->s_blocksize); - memset(&sb->s_feature_compat, 0, blocksize-offset); - - sb->s_nr_users = cpu_to_be32(1); - sb->s_header.h_blocktype = cpu_to_be32(JFS_SUPERBLOCK_V2); - journal->j_format_version = 2; - - bh = journal->j_sb_buffer; - BUFFER_TRACE(bh, "marking dirty"); - mark_buffer_dirty(bh); - sync_dirty_buffer(bh); - return 0; -} - - -/** - * int journal_flush () - Flush journal - * @journal: Journal to act on. - * - * Flush all data for a given journal to disk and empty the journal. - * Filesystems can use this when remounting readonly to ensure that - * recovery does not need to happen on remount. - */ - -int journal_flush(journal_t *journal) -{ - int err = 0; - transaction_t *transaction = NULL; - - spin_lock(&journal->j_state_lock); - - /* Force everything buffered to the log... */ - if (journal->j_running_transaction) { - transaction = journal->j_running_transaction; - __log_start_commit(journal, transaction->t_tid); - } else if (journal->j_committing_transaction) - transaction = journal->j_committing_transaction; - - /* Wait for the log commit to complete... */ - if (transaction) { - tid_t tid = transaction->t_tid; - - spin_unlock(&journal->j_state_lock); - log_wait_commit(journal, tid); - } else { - spin_unlock(&journal->j_state_lock); - } - - /* ...and flush everything in the log out to disk. */ - spin_lock(&journal->j_list_lock); - while (!err && journal->j_checkpoint_transactions != NULL) { - spin_unlock(&journal->j_list_lock); - mutex_lock(&journal->j_checkpoint_mutex); - err = log_do_checkpoint(journal); - mutex_unlock(&journal->j_checkpoint_mutex); - spin_lock(&journal->j_list_lock); - } - spin_unlock(&journal->j_list_lock); - - if (is_journal_aborted(journal)) - return -EIO; - - mutex_lock(&journal->j_checkpoint_mutex); - cleanup_journal_tail(journal); - - /* Finally, mark the journal as really needing no recovery. - * This sets s_start==0 in the underlying superblock, which is - * the magic code for a fully-recovered superblock. Any future - * commits of data to the journal will restore the current - * s_start value. */ - mark_journal_empty(journal); - mutex_unlock(&journal->j_checkpoint_mutex); - spin_lock(&journal->j_state_lock); - J_ASSERT(!journal->j_running_transaction); - J_ASSERT(!journal->j_committing_transaction); - J_ASSERT(!journal->j_checkpoint_transactions); - J_ASSERT(journal->j_head == journal->j_tail); - J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); - spin_unlock(&journal->j_state_lock); - return 0; -} - -/** - * int journal_wipe() - Wipe journal contents - * @journal: Journal to act on. - * @write: flag (see below) - * - * Wipe out all of the contents of a journal, safely. This will produce - * a warning if the journal contains any valid recovery information. - * Must be called between journal_init_*() and journal_load(). - * - * If 'write' is non-zero, then we wipe out the journal on disk; otherwise - * we merely suppress recovery. - */ - -int journal_wipe(journal_t *journal, int write) -{ - int err = 0; - - J_ASSERT (!(journal->j_flags & JFS_LOADED)); - - err = load_superblock(journal); - if (err) - return err; - - if (!journal->j_tail) - goto no_recovery; - - printk (KERN_WARNING "JBD: %s recovery information on journal\n", - write ? "Clearing" : "Ignoring"); - - err = journal_skip_recovery(journal); - if (write) { - /* Lock to make assertions happy... */ - mutex_lock(&journal->j_checkpoint_mutex); - mark_journal_empty(journal); - mutex_unlock(&journal->j_checkpoint_mutex); - } - - no_recovery: - return err; -} - -/* - * journal_dev_name: format a character string to describe on what - * device this journal is present. - */ - -static const char *journal_dev_name(journal_t *journal, char *buffer) -{ - struct block_device *bdev; - - if (journal->j_inode) - bdev = journal->j_inode->i_sb->s_bdev; - else - bdev = journal->j_dev; - - return bdevname(bdev, buffer); -} - -/* - * Journal abort has very specific semantics, which we describe - * for journal abort. - * - * Two internal function, which provide abort to te jbd layer - * itself are here. - */ - -/* - * Quick version for internal journal use (doesn't lock the journal). - * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, - * and don't attempt to make any other journal updates. - */ -static void __journal_abort_hard(journal_t *journal) -{ - transaction_t *transaction; - char b[BDEVNAME_SIZE]; - - if (journal->j_flags & JFS_ABORT) - return; - - printk(KERN_ERR "Aborting journal on device %s.\n", - journal_dev_name(journal, b)); - - spin_lock(&journal->j_state_lock); - journal->j_flags |= JFS_ABORT; - transaction = journal->j_running_transaction; - if (transaction) - __log_start_commit(journal, transaction->t_tid); - spin_unlock(&journal->j_state_lock); -} - -/* Soft abort: record the abort error status in the journal superblock, - * but don't do any other IO. */ -static void __journal_abort_soft (journal_t *journal, int errno) -{ - if (journal->j_flags & JFS_ABORT) - return; - - if (!journal->j_errno) - journal->j_errno = errno; - - __journal_abort_hard(journal); - - if (errno) - journal_update_sb_errno(journal); -} - -/** - * void journal_abort () - Shutdown the journal immediately. - * @journal: the journal to shutdown. - * @errno: an error number to record in the journal indicating - * the reason for the shutdown. - * - * Perform a complete, immediate shutdown of the ENTIRE - * journal (not of a single transaction). This operation cannot be - * undone without closing and reopening the journal. - * - * The journal_abort function is intended to support higher level error - * recovery mechanisms such as the ext2/ext3 remount-readonly error - * mode. - * - * Journal abort has very specific semantics. Any existing dirty, - * unjournaled buffers in the main filesystem will still be written to - * disk by bdflush, but the journaling mechanism will be suspended - * immediately and no further transaction commits will be honoured. - * - * Any dirty, journaled buffers will be written back to disk without - * hitting the journal. Atomicity cannot be guaranteed on an aborted - * filesystem, but we _do_ attempt to leave as much data as possible - * behind for fsck to use for cleanup. - * - * Any attempt to get a new transaction handle on a journal which is in - * ABORT state will just result in an -EROFS error return. A - * journal_stop on an existing handle will return -EIO if we have - * entered abort state during the update. - * - * Recursive transactions are not disturbed by journal abort until the - * final journal_stop, which will receive the -EIO error. - * - * Finally, the journal_abort call allows the caller to supply an errno - * which will be recorded (if possible) in the journal superblock. This - * allows a client to record failure conditions in the middle of a - * transaction without having to complete the transaction to record the - * failure to disk. ext3_error, for example, now uses this - * functionality. - * - * Errors which originate from within the journaling layer will NOT - * supply an errno; a null errno implies that absolutely no further - * writes are done to the journal (unless there are any already in - * progress). - * - */ - -void journal_abort(journal_t *journal, int errno) -{ - __journal_abort_soft(journal, errno); -} - -/** - * int journal_errno () - returns the journal's error state. - * @journal: journal to examine. - * - * This is the errno numbet set with journal_abort(), the last - * time the journal was mounted - if the journal was stopped - * without calling abort this will be 0. - * - * If the journal has been aborted on this mount time -EROFS will - * be returned. - */ -int journal_errno(journal_t *journal) -{ - int err; - - spin_lock(&journal->j_state_lock); - if (journal->j_flags & JFS_ABORT) - err = -EROFS; - else - err = journal->j_errno; - spin_unlock(&journal->j_state_lock); - return err; -} - -/** - * int journal_clear_err () - clears the journal's error state - * @journal: journal to act on. - * - * An error must be cleared or Acked to take a FS out of readonly - * mode. - */ -int journal_clear_err(journal_t *journal) -{ - int err = 0; - - spin_lock(&journal->j_state_lock); - if (journal->j_flags & JFS_ABORT) - err = -EROFS; - else - journal->j_errno = 0; - spin_unlock(&journal->j_state_lock); - return err; -} - -/** - * void journal_ack_err() - Ack journal err. - * @journal: journal to act on. - * - * An error must be cleared or Acked to take a FS out of readonly - * mode. - */ -void journal_ack_err(journal_t *journal) -{ - spin_lock(&journal->j_state_lock); - if (journal->j_errno) - journal->j_flags |= JFS_ACK_ERR; - spin_unlock(&journal->j_state_lock); -} - -int journal_blocks_per_page(struct inode *inode) -{ - return 1 << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); -} - -/* - * Journal_head storage management - */ -static struct kmem_cache *journal_head_cache; -#ifdef CONFIG_JBD_DEBUG -static atomic_t nr_journal_heads = ATOMIC_INIT(0); -#endif - -static int journal_init_journal_head_cache(void) -{ - int retval; - - J_ASSERT(journal_head_cache == NULL); - journal_head_cache = kmem_cache_create("journal_head", - sizeof(struct journal_head), - 0, /* offset */ - SLAB_TEMPORARY, /* flags */ - NULL); /* ctor */ - retval = 0; - if (!journal_head_cache) { - retval = -ENOMEM; - printk(KERN_EMERG "JBD: no memory for journal_head cache\n"); - } - return retval; -} - -static void journal_destroy_journal_head_cache(void) -{ - if (journal_head_cache) { - kmem_cache_destroy(journal_head_cache); - journal_head_cache = NULL; - } -} - -/* - * journal_head splicing and dicing - */ -static struct journal_head *journal_alloc_journal_head(void) -{ - struct journal_head *ret; - -#ifdef CONFIG_JBD_DEBUG - atomic_inc(&nr_journal_heads); -#endif - ret = kmem_cache_zalloc(journal_head_cache, GFP_NOFS); - if (ret == NULL) { - jbd_debug(1, "out of memory for journal_head\n"); - printk_ratelimited(KERN_NOTICE "ENOMEM in %s, retrying.\n", - __func__); - - while (ret == NULL) { - yield(); - ret = kmem_cache_zalloc(journal_head_cache, GFP_NOFS); - } - } - return ret; -} - -static void journal_free_journal_head(struct journal_head *jh) -{ -#ifdef CONFIG_JBD_DEBUG - atomic_dec(&nr_journal_heads); - memset(jh, JBD_POISON_FREE, sizeof(*jh)); -#endif - kmem_cache_free(journal_head_cache, jh); -} - -/* - * A journal_head is attached to a buffer_head whenever JBD has an - * interest in the buffer. - * - * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit - * is set. This bit is tested in core kernel code where we need to take - * JBD-specific actions. Testing the zeroness of ->b_private is not reliable - * there. - * - * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one. - * - * When a buffer has its BH_JBD bit set it is immune from being released by - * core kernel code, mainly via ->b_count. - * - * A journal_head is detached from its buffer_head when the journal_head's - * b_jcount reaches zero. Running transaction (b_transaction) and checkpoint - * transaction (b_cp_transaction) hold their references to b_jcount. - * - * Various places in the kernel want to attach a journal_head to a buffer_head - * _before_ attaching the journal_head to a transaction. To protect the - * journal_head in this situation, journal_add_journal_head elevates the - * journal_head's b_jcount refcount by one. The caller must call - * journal_put_journal_head() to undo this. - * - * So the typical usage would be: - * - * (Attach a journal_head if needed. Increments b_jcount) - * struct journal_head *jh = journal_add_journal_head(bh); - * ... - * (Get another reference for transaction) - * journal_grab_journal_head(bh); - * jh->b_transaction = xxx; - * (Put original reference) - * journal_put_journal_head(jh); - */ - -/* - * Give a buffer_head a journal_head. - * - * May sleep. - */ -struct journal_head *journal_add_journal_head(struct buffer_head *bh) -{ - struct journal_head *jh; - struct journal_head *new_jh = NULL; - -repeat: - if (!buffer_jbd(bh)) - new_jh = journal_alloc_journal_head(); - - jbd_lock_bh_journal_head(bh); - if (buffer_jbd(bh)) { - jh = bh2jh(bh); - } else { - J_ASSERT_BH(bh, - (atomic_read(&bh->b_count) > 0) || - (bh->b_page && bh->b_page->mapping)); - - if (!new_jh) { - jbd_unlock_bh_journal_head(bh); - goto repeat; - } - - jh = new_jh; - new_jh = NULL; /* We consumed it */ - set_buffer_jbd(bh); - bh->b_private = jh; - jh->b_bh = bh; - get_bh(bh); - BUFFER_TRACE(bh, "added journal_head"); - } - jh->b_jcount++; - jbd_unlock_bh_journal_head(bh); - if (new_jh) - journal_free_journal_head(new_jh); - return bh->b_private; -} - -/* - * Grab a ref against this buffer_head's journal_head. If it ended up not - * having a journal_head, return NULL - */ -struct journal_head *journal_grab_journal_head(struct buffer_head *bh) -{ - struct journal_head *jh = NULL; - - jbd_lock_bh_journal_head(bh); - if (buffer_jbd(bh)) { - jh = bh2jh(bh); - jh->b_jcount++; - } - jbd_unlock_bh_journal_head(bh); - return jh; -} - -static void __journal_remove_journal_head(struct buffer_head *bh) -{ - struct journal_head *jh = bh2jh(bh); - - J_ASSERT_JH(jh, jh->b_jcount >= 0); - J_ASSERT_JH(jh, jh->b_transaction == NULL); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); - J_ASSERT_JH(jh, jh->b_jlist == BJ_None); - J_ASSERT_BH(bh, buffer_jbd(bh)); - J_ASSERT_BH(bh, jh2bh(jh) == bh); - BUFFER_TRACE(bh, "remove journal_head"); - if (jh->b_frozen_data) { - printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__); - jbd_free(jh->b_frozen_data, bh->b_size); - } - if (jh->b_committed_data) { - printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__); - jbd_free(jh->b_committed_data, bh->b_size); - } - bh->b_private = NULL; - jh->b_bh = NULL; /* debug, really */ - clear_buffer_jbd(bh); - journal_free_journal_head(jh); -} - -/* - * Drop a reference on the passed journal_head. If it fell to zero then - * release the journal_head from the buffer_head. - */ -void journal_put_journal_head(struct journal_head *jh) -{ - struct buffer_head *bh = jh2bh(jh); - - jbd_lock_bh_journal_head(bh); - J_ASSERT_JH(jh, jh->b_jcount > 0); - --jh->b_jcount; - if (!jh->b_jcount) { - __journal_remove_journal_head(bh); - jbd_unlock_bh_journal_head(bh); - __brelse(bh); - } else - jbd_unlock_bh_journal_head(bh); -} - -/* - * debugfs tunables - */ -#ifdef CONFIG_JBD_DEBUG - -u8 journal_enable_debug __read_mostly; -EXPORT_SYMBOL(journal_enable_debug); - -static struct dentry *jbd_debugfs_dir; -static struct dentry *jbd_debug; - -static void __init jbd_create_debugfs_entry(void) -{ - jbd_debugfs_dir = debugfs_create_dir("jbd", NULL); - if (jbd_debugfs_dir) - jbd_debug = debugfs_create_u8("jbd-debug", S_IRUGO | S_IWUSR, - jbd_debugfs_dir, - &journal_enable_debug); -} - -static void __exit jbd_remove_debugfs_entry(void) -{ - debugfs_remove(jbd_debug); - debugfs_remove(jbd_debugfs_dir); -} - -#else - -static inline void jbd_create_debugfs_entry(void) -{ -} - -static inline void jbd_remove_debugfs_entry(void) -{ -} - -#endif - -struct kmem_cache *jbd_handle_cache; - -static int __init journal_init_handle_cache(void) -{ - jbd_handle_cache = kmem_cache_create("journal_handle", - sizeof(handle_t), - 0, /* offset */ - SLAB_TEMPORARY, /* flags */ - NULL); /* ctor */ - if (jbd_handle_cache == NULL) { - printk(KERN_EMERG "JBD: failed to create handle cache\n"); - return -ENOMEM; - } - return 0; -} - -static void journal_destroy_handle_cache(void) -{ - if (jbd_handle_cache) - kmem_cache_destroy(jbd_handle_cache); -} - -/* - * Module startup and shutdown - */ - -static int __init journal_init_caches(void) -{ - int ret; - - ret = journal_init_revoke_caches(); - if (ret == 0) - ret = journal_init_journal_head_cache(); - if (ret == 0) - ret = journal_init_handle_cache(); - return ret; -} - -static void journal_destroy_caches(void) -{ - journal_destroy_revoke_caches(); - journal_destroy_journal_head_cache(); - journal_destroy_handle_cache(); -} - -static int __init journal_init(void) -{ - int ret; - - BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024); - - ret = journal_init_caches(); - if (ret != 0) - journal_destroy_caches(); - jbd_create_debugfs_entry(); - return ret; -} - -static void __exit journal_exit(void) -{ -#ifdef CONFIG_JBD_DEBUG - int n = atomic_read(&nr_journal_heads); - if (n) - printk(KERN_ERR "JBD: leaked %d journal_heads!\n", n); -#endif - jbd_remove_debugfs_entry(); - journal_destroy_caches(); -} - -MODULE_LICENSE("GPL"); -module_init(journal_init); -module_exit(journal_exit); - diff --git a/fs/jbd/recovery.c b/fs/jbd/recovery.c deleted file mode 100644 index a748fe21465ab..0000000000000 --- a/fs/jbd/recovery.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * linux/fs/jbd/recovery.c - * - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1999-2000 Red Hat Software --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Journal recovery routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. - */ - -#ifndef __KERNEL__ -#include "jfs_user.h" -#else -#include -#include -#include -#include -#include -#endif - -/* - * Maintain information about the progress of the recovery job, so that - * the different passes can carry information between them. - */ -struct recovery_info -{ - tid_t start_transaction; - tid_t end_transaction; - - int nr_replays; - int nr_revokes; - int nr_revoke_hits; -}; - -enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY}; -static int do_one_pass(journal_t *journal, - struct recovery_info *info, enum passtype pass); -static int scan_revoke_records(journal_t *, struct buffer_head *, - tid_t, struct recovery_info *); - -#ifdef __KERNEL__ - -/* Release readahead buffers after use */ -static void journal_brelse_array(struct buffer_head *b[], int n) -{ - while (--n >= 0) - brelse (b[n]); -} - - -/* - * When reading from the journal, we are going through the block device - * layer directly and so there is no readahead being done for us. We - * need to implement any readahead ourselves if we want it to happen at - * all. Recovery is basically one long sequential read, so make sure we - * do the IO in reasonably large chunks. - * - * This is not so critical that we need to be enormously clever about - * the readahead size, though. 128K is a purely arbitrary, good-enough - * fixed value. - */ - -#define MAXBUF 8 -static int do_readahead(journal_t *journal, unsigned int start) -{ - int err; - unsigned int max, nbufs, next; - unsigned int blocknr; - struct buffer_head *bh; - - struct buffer_head * bufs[MAXBUF]; - - /* Do up to 128K of readahead */ - max = start + (128 * 1024 / journal->j_blocksize); - if (max > journal->j_maxlen) - max = journal->j_maxlen; - - /* Do the readahead itself. We'll submit MAXBUF buffer_heads at - * a time to the block device IO layer. */ - - nbufs = 0; - - for (next = start; next < max; next++) { - err = journal_bmap(journal, next, &blocknr); - - if (err) { - printk (KERN_ERR "JBD: bad block at offset %u\n", - next); - goto failed; - } - - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) { - err = -ENOMEM; - goto failed; - } - - if (!buffer_uptodate(bh) && !buffer_locked(bh)) { - bufs[nbufs++] = bh; - if (nbufs == MAXBUF) { - ll_rw_block(READ, nbufs, bufs); - journal_brelse_array(bufs, nbufs); - nbufs = 0; - } - } else - brelse(bh); - } - - if (nbufs) - ll_rw_block(READ, nbufs, bufs); - err = 0; - -failed: - if (nbufs) - journal_brelse_array(bufs, nbufs); - return err; -} - -#endif /* __KERNEL__ */ - - -/* - * Read a block from the journal - */ - -static int jread(struct buffer_head **bhp, journal_t *journal, - unsigned int offset) -{ - int err; - unsigned int blocknr; - struct buffer_head *bh; - - *bhp = NULL; - - if (offset >= journal->j_maxlen) { - printk(KERN_ERR "JBD: corrupted journal superblock\n"); - return -EIO; - } - - err = journal_bmap(journal, offset, &blocknr); - - if (err) { - printk (KERN_ERR "JBD: bad block at offset %u\n", - offset); - return err; - } - - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) - return -ENOMEM; - - if (!buffer_uptodate(bh)) { - /* If this is a brand new buffer, start readahead. - Otherwise, we assume we are already reading it. */ - if (!buffer_req(bh)) - do_readahead(journal, offset); - wait_on_buffer(bh); - } - - if (!buffer_uptodate(bh)) { - printk (KERN_ERR "JBD: Failed to read block at offset %u\n", - offset); - brelse(bh); - return -EIO; - } - - *bhp = bh; - return 0; -} - - -/* - * Count the number of in-use tags in a journal descriptor block. - */ - -static int count_tags(struct buffer_head *bh, int size) -{ - char * tagp; - journal_block_tag_t * tag; - int nr = 0; - - tagp = &bh->b_data[sizeof(journal_header_t)]; - - while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) { - tag = (journal_block_tag_t *) tagp; - - nr++; - tagp += sizeof(journal_block_tag_t); - if (!(tag->t_flags & cpu_to_be32(JFS_FLAG_SAME_UUID))) - tagp += 16; - - if (tag->t_flags & cpu_to_be32(JFS_FLAG_LAST_TAG)) - break; - } - - return nr; -} - - -/* Make sure we wrap around the log correctly! */ -#define wrap(journal, var) \ -do { \ - if (var >= (journal)->j_last) \ - var -= ((journal)->j_last - (journal)->j_first); \ -} while (0) - -/** - * journal_recover - recovers a on-disk journal - * @journal: the journal to recover - * - * The primary function for recovering the log contents when mounting a - * journaled device. - * - * Recovery is done in three passes. In the first pass, we look for the - * end of the log. In the second, we assemble the list of revoke - * blocks. In the third and final pass, we replay any un-revoked blocks - * in the log. - */ -int journal_recover(journal_t *journal) -{ - int err, err2; - journal_superblock_t * sb; - - struct recovery_info info; - - memset(&info, 0, sizeof(info)); - sb = journal->j_superblock; - - /* - * The journal superblock's s_start field (the current log head) - * is always zero if, and only if, the journal was cleanly - * unmounted. - */ - - if (!sb->s_start) { - jbd_debug(1, "No recovery required, last transaction %d\n", - be32_to_cpu(sb->s_sequence)); - journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; - return 0; - } - - err = do_one_pass(journal, &info, PASS_SCAN); - if (!err) - err = do_one_pass(journal, &info, PASS_REVOKE); - if (!err) - err = do_one_pass(journal, &info, PASS_REPLAY); - - jbd_debug(1, "JBD: recovery, exit status %d, " - "recovered transactions %u to %u\n", - err, info.start_transaction, info.end_transaction); - jbd_debug(1, "JBD: Replayed %d and revoked %d/%d blocks\n", - info.nr_replays, info.nr_revoke_hits, info.nr_revokes); - - /* Restart the log at the next transaction ID, thus invalidating - * any existing commit records in the log. */ - journal->j_transaction_sequence = ++info.end_transaction; - - journal_clear_revoke(journal); - err2 = sync_blockdev(journal->j_fs_dev); - if (!err) - err = err2; - /* Flush disk caches to get replayed data on the permanent storage */ - if (journal->j_flags & JFS_BARRIER) { - err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); - if (!err) - err = err2; - } - - return err; -} - -/** - * journal_skip_recovery - Start journal and wipe exiting records - * @journal: journal to startup - * - * Locate any valid recovery information from the journal and set up the - * journal structures in memory to ignore it (presumably because the - * caller has evidence that it is out of date). - * This function does'nt appear to be exorted.. - * - * We perform one pass over the journal to allow us to tell the user how - * much recovery information is being erased, and to let us initialise - * the journal transaction sequence numbers to the next unused ID. - */ -int journal_skip_recovery(journal_t *journal) -{ - int err; - struct recovery_info info; - - memset (&info, 0, sizeof(info)); - - err = do_one_pass(journal, &info, PASS_SCAN); - - if (err) { - printk(KERN_ERR "JBD: error %d scanning journal\n", err); - ++journal->j_transaction_sequence; - } else { -#ifdef CONFIG_JBD_DEBUG - int dropped = info.end_transaction - - be32_to_cpu(journal->j_superblock->s_sequence); - jbd_debug(1, - "JBD: ignoring %d transaction%s from the journal.\n", - dropped, (dropped == 1) ? "" : "s"); -#endif - journal->j_transaction_sequence = ++info.end_transaction; - } - - journal->j_tail = 0; - return err; -} - -static int do_one_pass(journal_t *journal, - struct recovery_info *info, enum passtype pass) -{ - unsigned int first_commit_ID, next_commit_ID; - unsigned int next_log_block; - int err, success = 0; - journal_superblock_t * sb; - journal_header_t * tmp; - struct buffer_head * bh; - unsigned int sequence; - int blocktype; - - /* - * First thing is to establish what we expect to find in the log - * (in terms of transaction IDs), and where (in terms of log - * block offsets): query the superblock. - */ - - sb = journal->j_superblock; - next_commit_ID = be32_to_cpu(sb->s_sequence); - next_log_block = be32_to_cpu(sb->s_start); - - first_commit_ID = next_commit_ID; - if (pass == PASS_SCAN) - info->start_transaction = first_commit_ID; - - jbd_debug(1, "Starting recovery pass %d\n", pass); - - /* - * Now we walk through the log, transaction by transaction, - * making sure that each transaction has a commit block in the - * expected place. Each complete transaction gets replayed back - * into the main filesystem. - */ - - while (1) { - int flags; - char * tagp; - journal_block_tag_t * tag; - struct buffer_head * obh; - struct buffer_head * nbh; - - cond_resched(); - - /* If we already know where to stop the log traversal, - * check right now that we haven't gone past the end of - * the log. */ - - if (pass != PASS_SCAN) - if (tid_geq(next_commit_ID, info->end_transaction)) - break; - - jbd_debug(2, "Scanning for sequence ID %u at %u/%u\n", - next_commit_ID, next_log_block, journal->j_last); - - /* Skip over each chunk of the transaction looking - * either the next descriptor block or the final commit - * record. */ - - jbd_debug(3, "JBD: checking block %u\n", next_log_block); - err = jread(&bh, journal, next_log_block); - if (err) - goto failed; - - next_log_block++; - wrap(journal, next_log_block); - - /* What kind of buffer is it? - * - * If it is a descriptor block, check that it has the - * expected sequence number. Otherwise, we're all done - * here. */ - - tmp = (journal_header_t *)bh->b_data; - - if (tmp->h_magic != cpu_to_be32(JFS_MAGIC_NUMBER)) { - brelse(bh); - break; - } - - blocktype = be32_to_cpu(tmp->h_blocktype); - sequence = be32_to_cpu(tmp->h_sequence); - jbd_debug(3, "Found magic %d, sequence %d\n", - blocktype, sequence); - - if (sequence != next_commit_ID) { - brelse(bh); - break; - } - - /* OK, we have a valid descriptor block which matches - * all of the sequence number checks. What are we going - * to do with it? That depends on the pass... */ - - switch(blocktype) { - case JFS_DESCRIPTOR_BLOCK: - /* If it is a valid descriptor block, replay it - * in pass REPLAY; otherwise, just skip over the - * blocks it describes. */ - if (pass != PASS_REPLAY) { - next_log_block += - count_tags(bh, journal->j_blocksize); - wrap(journal, next_log_block); - brelse(bh); - continue; - } - - /* A descriptor block: we can now write all of - * the data blocks. Yay, useful work is finally - * getting done here! */ - - tagp = &bh->b_data[sizeof(journal_header_t)]; - while ((tagp - bh->b_data +sizeof(journal_block_tag_t)) - <= journal->j_blocksize) { - unsigned int io_block; - - tag = (journal_block_tag_t *) tagp; - flags = be32_to_cpu(tag->t_flags); - - io_block = next_log_block++; - wrap(journal, next_log_block); - err = jread(&obh, journal, io_block); - if (err) { - /* Recover what we can, but - * report failure at the end. */ - success = err; - printk (KERN_ERR - "JBD: IO error %d recovering " - "block %u in log\n", - err, io_block); - } else { - unsigned int blocknr; - - J_ASSERT(obh != NULL); - blocknr = be32_to_cpu(tag->t_blocknr); - - /* If the block has been - * revoked, then we're all done - * here. */ - if (journal_test_revoke - (journal, blocknr, - next_commit_ID)) { - brelse(obh); - ++info->nr_revoke_hits; - goto skip_write; - } - - /* Find a buffer for the new - * data being restored */ - nbh = __getblk(journal->j_fs_dev, - blocknr, - journal->j_blocksize); - if (nbh == NULL) { - printk(KERN_ERR - "JBD: Out of memory " - "during recovery.\n"); - err = -ENOMEM; - brelse(bh); - brelse(obh); - goto failed; - } - - lock_buffer(nbh); - memcpy(nbh->b_data, obh->b_data, - journal->j_blocksize); - if (flags & JFS_FLAG_ESCAPE) { - *((__be32 *)nbh->b_data) = - cpu_to_be32(JFS_MAGIC_NUMBER); - } - - BUFFER_TRACE(nbh, "marking dirty"); - set_buffer_uptodate(nbh); - mark_buffer_dirty(nbh); - BUFFER_TRACE(nbh, "marking uptodate"); - ++info->nr_replays; - /* ll_rw_block(WRITE, 1, &nbh); */ - unlock_buffer(nbh); - brelse(obh); - brelse(nbh); - } - - skip_write: - tagp += sizeof(journal_block_tag_t); - if (!(flags & JFS_FLAG_SAME_UUID)) - tagp += 16; - - if (flags & JFS_FLAG_LAST_TAG) - break; - } - - brelse(bh); - continue; - - case JFS_COMMIT_BLOCK: - /* Found an expected commit block: not much to - * do other than move on to the next sequence - * number. */ - brelse(bh); - next_commit_ID++; - continue; - - case JFS_REVOKE_BLOCK: - /* If we aren't in the REVOKE pass, then we can - * just skip over this block. */ - if (pass != PASS_REVOKE) { - brelse(bh); - continue; - } - - err = scan_revoke_records(journal, bh, - next_commit_ID, info); - brelse(bh); - if (err) - goto failed; - continue; - - default: - jbd_debug(3, "Unrecognised magic %d, end of scan.\n", - blocktype); - brelse(bh); - goto done; - } - } - - done: - /* - * We broke out of the log scan loop: either we came to the - * known end of the log or we found an unexpected block in the - * log. If the latter happened, then we know that the "current" - * transaction marks the end of the valid log. - */ - - if (pass == PASS_SCAN) - info->end_transaction = next_commit_ID; - else { - /* It's really bad news if different passes end up at - * different places (but possible due to IO errors). */ - if (info->end_transaction != next_commit_ID) { - printk (KERN_ERR "JBD: recovery pass %d ended at " - "transaction %u, expected %u\n", - pass, next_commit_ID, info->end_transaction); - if (!success) - success = -EIO; - } - } - - return success; - - failed: - return err; -} - - -/* Scan a revoke record, marking all blocks mentioned as revoked. */ - -static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, - tid_t sequence, struct recovery_info *info) -{ - journal_revoke_header_t *header; - int offset, max; - - header = (journal_revoke_header_t *) bh->b_data; - offset = sizeof(journal_revoke_header_t); - max = be32_to_cpu(header->r_count); - - while (offset < max) { - unsigned int blocknr; - int err; - - blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); - offset += 4; - err = journal_set_revoke(journal, blocknr, sequence); - if (err) - return err; - ++info->nr_revokes; - } - return 0; -} diff --git a/fs/jbd/revoke.c b/fs/jbd/revoke.c deleted file mode 100644 index dcead636c33b5..0000000000000 --- a/fs/jbd/revoke.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * linux/fs/jbd/revoke.c - * - * Written by Stephen C. Tweedie , 2000 - * - * Copyright 2000 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Journal revoke routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. - * - * Revoke is the mechanism used to prevent old log records for deleted - * metadata from being replayed on top of newer data using the same - * blocks. The revoke mechanism is used in two separate places: - * - * + Commit: during commit we write the entire list of the current - * transaction's revoked blocks to the journal - * - * + Recovery: during recovery we record the transaction ID of all - * revoked blocks. If there are multiple revoke records in the log - * for a single block, only the last one counts, and if there is a log - * entry for a block beyond the last revoke, then that log entry still - * gets replayed. - * - * We can get interactions between revokes and new log data within a - * single transaction: - * - * Block is revoked and then journaled: - * The desired end result is the journaling of the new block, so we - * cancel the revoke before the transaction commits. - * - * Block is journaled and then revoked: - * The revoke must take precedence over the write of the block, so we - * need either to cancel the journal entry or to write the revoke - * later in the log than the log block. In this case, we choose the - * latter: journaling a block cancels any revoke record for that block - * in the current transaction, so any revoke for that block in the - * transaction must have happened after the block was journaled and so - * the revoke must take precedence. - * - * Block is revoked and then written as data: - * The data write is allowed to succeed, but the revoke is _not_ - * cancelled. We still need to prevent old log records from - * overwriting the new data. We don't even need to clear the revoke - * bit here. - * - * We cache revoke status of a buffer in the current transaction in b_states - * bits. As the name says, revokevalid flag indicates that the cached revoke - * status of a buffer is valid and we can rely on the cached status. - * - * Revoke information on buffers is a tri-state value: - * - * RevokeValid clear: no cached revoke status, need to look it up - * RevokeValid set, Revoked clear: - * buffer has not been revoked, and cancel_revoke - * need do nothing. - * RevokeValid set, Revoked set: - * buffer has been revoked. - * - * Locking rules: - * We keep two hash tables of revoke records. One hashtable belongs to the - * running transaction (is pointed to by journal->j_revoke), the other one - * belongs to the committing transaction. Accesses to the second hash table - * happen only from the kjournald and no other thread touches this table. Also - * journal_switch_revoke_table() which switches which hashtable belongs to the - * running and which to the committing transaction is called only from - * kjournald. Therefore we need no locks when accessing the hashtable belonging - * to the committing transaction. - * - * All users operating on the hash table belonging to the running transaction - * have a handle to the transaction. Therefore they are safe from kjournald - * switching hash tables under them. For operations on the lists of entries in - * the hash table j_revoke_lock is used. - * - * Finally, also replay code uses the hash tables but at this moment no one else - * can touch them (filesystem isn't mounted yet) and hence no locking is - * needed. - */ - -#ifndef __KERNEL__ -#include "jfs_user.h" -#else -#include -#include -#include -#include -#include -#include -#include -#include -#endif -#include -#include - -static struct kmem_cache *revoke_record_cache; -static struct kmem_cache *revoke_table_cache; - -/* Each revoke record represents one single revoked block. During - journal replay, this involves recording the transaction ID of the - last transaction to revoke this block. */ - -struct jbd_revoke_record_s -{ - struct list_head hash; - tid_t sequence; /* Used for recovery only */ - unsigned int blocknr; -}; - - -/* The revoke table is just a simple hash table of revoke records. */ -struct jbd_revoke_table_s -{ - /* It is conceivable that we might want a larger hash table - * for recovery. Must be a power of two. */ - int hash_size; - int hash_shift; - struct list_head *hash_table; -}; - - -#ifdef __KERNEL__ -static void write_one_revoke_record(journal_t *, transaction_t *, - struct journal_head **, int *, - struct jbd_revoke_record_s *, int); -static void flush_descriptor(journal_t *, struct journal_head *, int, int); -#endif - -/* Utility functions to maintain the revoke table */ - -static inline int hash(journal_t *journal, unsigned int block) -{ - struct jbd_revoke_table_s *table = journal->j_revoke; - - return hash_32(block, table->hash_shift); -} - -static int insert_revoke_hash(journal_t *journal, unsigned int blocknr, - tid_t seq) -{ - struct list_head *hash_list; - struct jbd_revoke_record_s *record; - -repeat: - record = kmem_cache_alloc(revoke_record_cache, GFP_NOFS); - if (!record) - goto oom; - - record->sequence = seq; - record->blocknr = blocknr; - hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; - spin_lock(&journal->j_revoke_lock); - list_add(&record->hash, hash_list); - spin_unlock(&journal->j_revoke_lock); - return 0; - -oom: - if (!journal_oom_retry) - return -ENOMEM; - jbd_debug(1, "ENOMEM in %s, retrying\n", __func__); - yield(); - goto repeat; -} - -/* Find a revoke record in the journal's hash table. */ - -static struct jbd_revoke_record_s *find_revoke_record(journal_t *journal, - unsigned int blocknr) -{ - struct list_head *hash_list; - struct jbd_revoke_record_s *record; - - hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; - - spin_lock(&journal->j_revoke_lock); - record = (struct jbd_revoke_record_s *) hash_list->next; - while (&(record->hash) != hash_list) { - if (record->blocknr == blocknr) { - spin_unlock(&journal->j_revoke_lock); - return record; - } - record = (struct jbd_revoke_record_s *) record->hash.next; - } - spin_unlock(&journal->j_revoke_lock); - return NULL; -} - -void journal_destroy_revoke_caches(void) -{ - if (revoke_record_cache) { - kmem_cache_destroy(revoke_record_cache); - revoke_record_cache = NULL; - } - if (revoke_table_cache) { - kmem_cache_destroy(revoke_table_cache); - revoke_table_cache = NULL; - } -} - -int __init journal_init_revoke_caches(void) -{ - J_ASSERT(!revoke_record_cache); - J_ASSERT(!revoke_table_cache); - - revoke_record_cache = kmem_cache_create("revoke_record", - sizeof(struct jbd_revoke_record_s), - 0, - SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, - NULL); - if (!revoke_record_cache) - goto record_cache_failure; - - revoke_table_cache = kmem_cache_create("revoke_table", - sizeof(struct jbd_revoke_table_s), - 0, SLAB_TEMPORARY, NULL); - if (!revoke_table_cache) - goto table_cache_failure; - - return 0; - -table_cache_failure: - journal_destroy_revoke_caches(); -record_cache_failure: - return -ENOMEM; -} - -static struct jbd_revoke_table_s *journal_init_revoke_table(int hash_size) -{ - int i; - struct jbd_revoke_table_s *table; - - table = kmem_cache_alloc(revoke_table_cache, GFP_KERNEL); - if (!table) - goto out; - - table->hash_size = hash_size; - table->hash_shift = ilog2(hash_size); - table->hash_table = - kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); - if (!table->hash_table) { - kmem_cache_free(revoke_table_cache, table); - table = NULL; - goto out; - } - - for (i = 0; i < hash_size; i++) - INIT_LIST_HEAD(&table->hash_table[i]); - -out: - return table; -} - -static void journal_destroy_revoke_table(struct jbd_revoke_table_s *table) -{ - int i; - struct list_head *hash_list; - - for (i = 0; i < table->hash_size; i++) { - hash_list = &table->hash_table[i]; - J_ASSERT(list_empty(hash_list)); - } - - kfree(table->hash_table); - kmem_cache_free(revoke_table_cache, table); -} - -/* Initialise the revoke table for a given journal to a given size. */ -int journal_init_revoke(journal_t *journal, int hash_size) -{ - J_ASSERT(journal->j_revoke_table[0] == NULL); - J_ASSERT(is_power_of_2(hash_size)); - - journal->j_revoke_table[0] = journal_init_revoke_table(hash_size); - if (!journal->j_revoke_table[0]) - goto fail0; - - journal->j_revoke_table[1] = journal_init_revoke_table(hash_size); - if (!journal->j_revoke_table[1]) - goto fail1; - - journal->j_revoke = journal->j_revoke_table[1]; - - spin_lock_init(&journal->j_revoke_lock); - - return 0; - -fail1: - journal_destroy_revoke_table(journal->j_revoke_table[0]); -fail0: - return -ENOMEM; -} - -/* Destroy a journal's revoke table. The table must already be empty! */ -void journal_destroy_revoke(journal_t *journal) -{ - journal->j_revoke = NULL; - if (journal->j_revoke_table[0]) - journal_destroy_revoke_table(journal->j_revoke_table[0]); - if (journal->j_revoke_table[1]) - journal_destroy_revoke_table(journal->j_revoke_table[1]); -} - - -#ifdef __KERNEL__ - -/* - * journal_revoke: revoke a given buffer_head from the journal. This - * prevents the block from being replayed during recovery if we take a - * crash after this current transaction commits. Any subsequent - * metadata writes of the buffer in this transaction cancel the - * revoke. - * - * Note that this call may block --- it is up to the caller to make - * sure that there are no further calls to journal_write_metadata - * before the revoke is complete. In ext3, this implies calling the - * revoke before clearing the block bitmap when we are deleting - * metadata. - * - * Revoke performs a journal_forget on any buffer_head passed in as a - * parameter, but does _not_ forget the buffer_head if the bh was only - * found implicitly. - * - * bh_in may not be a journalled buffer - it may have come off - * the hash tables without an attached journal_head. - * - * If bh_in is non-zero, journal_revoke() will decrement its b_count - * by one. - */ - -int journal_revoke(handle_t *handle, unsigned int blocknr, - struct buffer_head *bh_in) -{ - struct buffer_head *bh = NULL; - journal_t *journal; - struct block_device *bdev; - int err; - - might_sleep(); - if (bh_in) - BUFFER_TRACE(bh_in, "enter"); - - journal = handle->h_transaction->t_journal; - if (!journal_set_features(journal, 0, 0, JFS_FEATURE_INCOMPAT_REVOKE)){ - J_ASSERT (!"Cannot set revoke feature!"); - return -EINVAL; - } - - bdev = journal->j_fs_dev; - bh = bh_in; - - if (!bh) { - bh = __find_get_block(bdev, blocknr, journal->j_blocksize); - if (bh) - BUFFER_TRACE(bh, "found on hash"); - } -#ifdef JBD_EXPENSIVE_CHECKING - else { - struct buffer_head *bh2; - - /* If there is a different buffer_head lying around in - * memory anywhere... */ - bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize); - if (bh2) { - /* ... and it has RevokeValid status... */ - if (bh2 != bh && buffer_revokevalid(bh2)) - /* ...then it better be revoked too, - * since it's illegal to create a revoke - * record against a buffer_head which is - * not marked revoked --- that would - * risk missing a subsequent revoke - * cancel. */ - J_ASSERT_BH(bh2, buffer_revoked(bh2)); - put_bh(bh2); - } - } -#endif - - /* We really ought not ever to revoke twice in a row without - first having the revoke cancelled: it's illegal to free a - block twice without allocating it in between! */ - if (bh) { - if (!J_EXPECT_BH(bh, !buffer_revoked(bh), - "inconsistent data on disk")) { - if (!bh_in) - brelse(bh); - return -EIO; - } - set_buffer_revoked(bh); - set_buffer_revokevalid(bh); - if (bh_in) { - BUFFER_TRACE(bh_in, "call journal_forget"); - journal_forget(handle, bh_in); - } else { - BUFFER_TRACE(bh, "call brelse"); - __brelse(bh); - } - } - - jbd_debug(2, "insert revoke for block %u, bh_in=%p\n", blocknr, bh_in); - err = insert_revoke_hash(journal, blocknr, - handle->h_transaction->t_tid); - BUFFER_TRACE(bh_in, "exit"); - return err; -} - -/* - * Cancel an outstanding revoke. For use only internally by the - * journaling code (called from journal_get_write_access). - * - * We trust buffer_revoked() on the buffer if the buffer is already - * being journaled: if there is no revoke pending on the buffer, then we - * don't do anything here. - * - * This would break if it were possible for a buffer to be revoked and - * discarded, and then reallocated within the same transaction. In such - * a case we would have lost the revoked bit, but when we arrived here - * the second time we would still have a pending revoke to cancel. So, - * do not trust the Revoked bit on buffers unless RevokeValid is also - * set. - */ -int journal_cancel_revoke(handle_t *handle, struct journal_head *jh) -{ - struct jbd_revoke_record_s *record; - journal_t *journal = handle->h_transaction->t_journal; - int need_cancel; - int did_revoke = 0; /* akpm: debug */ - struct buffer_head *bh = jh2bh(jh); - - jbd_debug(4, "journal_head %p, cancelling revoke\n", jh); - - /* Is the existing Revoke bit valid? If so, we trust it, and - * only perform the full cancel if the revoke bit is set. If - * not, we can't trust the revoke bit, and we need to do the - * full search for a revoke record. */ - if (test_set_buffer_revokevalid(bh)) { - need_cancel = test_clear_buffer_revoked(bh); - } else { - need_cancel = 1; - clear_buffer_revoked(bh); - } - - if (need_cancel) { - record = find_revoke_record(journal, bh->b_blocknr); - if (record) { - jbd_debug(4, "cancelled existing revoke on " - "blocknr %llu\n", (unsigned long long)bh->b_blocknr); - spin_lock(&journal->j_revoke_lock); - list_del(&record->hash); - spin_unlock(&journal->j_revoke_lock); - kmem_cache_free(revoke_record_cache, record); - did_revoke = 1; - } - } - -#ifdef JBD_EXPENSIVE_CHECKING - /* There better not be one left behind by now! */ - record = find_revoke_record(journal, bh->b_blocknr); - J_ASSERT_JH(jh, record == NULL); -#endif - - /* Finally, have we just cleared revoke on an unhashed - * buffer_head? If so, we'd better make sure we clear the - * revoked status on any hashed alias too, otherwise the revoke - * state machine will get very upset later on. */ - if (need_cancel) { - struct buffer_head *bh2; - bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size); - if (bh2) { - if (bh2 != bh) - clear_buffer_revoked(bh2); - __brelse(bh2); - } - } - return did_revoke; -} - -/* - * journal_clear_revoked_flags clears revoked flag of buffers in - * revoke table to reflect there is no revoked buffer in the next - * transaction which is going to be started. - */ -void journal_clear_buffer_revoked_flags(journal_t *journal) -{ - struct jbd_revoke_table_s *revoke = journal->j_revoke; - int i = 0; - - for (i = 0; i < revoke->hash_size; i++) { - struct list_head *hash_list; - struct list_head *list_entry; - hash_list = &revoke->hash_table[i]; - - list_for_each(list_entry, hash_list) { - struct jbd_revoke_record_s *record; - struct buffer_head *bh; - record = (struct jbd_revoke_record_s *)list_entry; - bh = __find_get_block(journal->j_fs_dev, - record->blocknr, - journal->j_blocksize); - if (bh) { - clear_buffer_revoked(bh); - __brelse(bh); - } - } - } -} - -/* journal_switch_revoke table select j_revoke for next transaction - * we do not want to suspend any processing until all revokes are - * written -bzzz - */ -void journal_switch_revoke_table(journal_t *journal) -{ - int i; - - if (journal->j_revoke == journal->j_revoke_table[0]) - journal->j_revoke = journal->j_revoke_table[1]; - else - journal->j_revoke = journal->j_revoke_table[0]; - - for (i = 0; i < journal->j_revoke->hash_size; i++) - INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); -} - -/* - * Write revoke records to the journal for all entries in the current - * revoke hash, deleting the entries as we go. - */ -void journal_write_revoke_records(journal_t *journal, - transaction_t *transaction, int write_op) -{ - struct journal_head *descriptor; - struct jbd_revoke_record_s *record; - struct jbd_revoke_table_s *revoke; - struct list_head *hash_list; - int i, offset, count; - - descriptor = NULL; - offset = 0; - count = 0; - - /* select revoke table for committing transaction */ - revoke = journal->j_revoke == journal->j_revoke_table[0] ? - journal->j_revoke_table[1] : journal->j_revoke_table[0]; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - - while (!list_empty(hash_list)) { - record = (struct jbd_revoke_record_s *) - hash_list->next; - write_one_revoke_record(journal, transaction, - &descriptor, &offset, - record, write_op); - count++; - list_del(&record->hash); - kmem_cache_free(revoke_record_cache, record); - } - } - if (descriptor) - flush_descriptor(journal, descriptor, offset, write_op); - jbd_debug(1, "Wrote %d revoke records\n", count); -} - -/* - * Write out one revoke record. We need to create a new descriptor - * block if the old one is full or if we have not already created one. - */ - -static void write_one_revoke_record(journal_t *journal, - transaction_t *transaction, - struct journal_head **descriptorp, - int *offsetp, - struct jbd_revoke_record_s *record, - int write_op) -{ - struct journal_head *descriptor; - int offset; - journal_header_t *header; - - /* If we are already aborting, this all becomes a noop. We - still need to go round the loop in - journal_write_revoke_records in order to free all of the - revoke records: only the IO to the journal is omitted. */ - if (is_journal_aborted(journal)) - return; - - descriptor = *descriptorp; - offset = *offsetp; - - /* Make sure we have a descriptor with space left for the record */ - if (descriptor) { - if (offset == journal->j_blocksize) { - flush_descriptor(journal, descriptor, offset, write_op); - descriptor = NULL; - } - } - - if (!descriptor) { - descriptor = journal_get_descriptor_buffer(journal); - if (!descriptor) - return; - header = (journal_header_t *) &jh2bh(descriptor)->b_data[0]; - header->h_magic = cpu_to_be32(JFS_MAGIC_NUMBER); - header->h_blocktype = cpu_to_be32(JFS_REVOKE_BLOCK); - header->h_sequence = cpu_to_be32(transaction->t_tid); - - /* Record it so that we can wait for IO completion later */ - JBUFFER_TRACE(descriptor, "file as BJ_LogCtl"); - journal_file_buffer(descriptor, transaction, BJ_LogCtl); - - offset = sizeof(journal_revoke_header_t); - *descriptorp = descriptor; - } - - * ((__be32 *)(&jh2bh(descriptor)->b_data[offset])) = - cpu_to_be32(record->blocknr); - offset += 4; - *offsetp = offset; -} - -/* - * Flush a revoke descriptor out to the journal. If we are aborting, - * this is a noop; otherwise we are generating a buffer which needs to - * be waited for during commit, so it has to go onto the appropriate - * journal buffer list. - */ - -static void flush_descriptor(journal_t *journal, - struct journal_head *descriptor, - int offset, int write_op) -{ - journal_revoke_header_t *header; - struct buffer_head *bh = jh2bh(descriptor); - - if (is_journal_aborted(journal)) { - put_bh(bh); - return; - } - - header = (journal_revoke_header_t *) jh2bh(descriptor)->b_data; - header->r_count = cpu_to_be32(offset); - set_buffer_jwrite(bh); - BUFFER_TRACE(bh, "write"); - set_buffer_dirty(bh); - write_dirty_buffer(bh, write_op); -} -#endif - -/* - * Revoke support for recovery. - * - * Recovery needs to be able to: - * - * record all revoke records, including the tid of the latest instance - * of each revoke in the journal - * - * check whether a given block in a given transaction should be replayed - * (ie. has not been revoked by a revoke record in that or a subsequent - * transaction) - * - * empty the revoke table after recovery. - */ - -/* - * First, setting revoke records. We create a new revoke record for - * every block ever revoked in the log as we scan it for recovery, and - * we update the existing records if we find multiple revokes for a - * single block. - */ - -int journal_set_revoke(journal_t *journal, - unsigned int blocknr, - tid_t sequence) -{ - struct jbd_revoke_record_s *record; - - record = find_revoke_record(journal, blocknr); - if (record) { - /* If we have multiple occurrences, only record the - * latest sequence number in the hashed record */ - if (tid_gt(sequence, record->sequence)) - record->sequence = sequence; - return 0; - } - return insert_revoke_hash(journal, blocknr, sequence); -} - -/* - * Test revoke records. For a given block referenced in the log, has - * that block been revoked? A revoke record with a given transaction - * sequence number revokes all blocks in that transaction and earlier - * ones, but later transactions still need replayed. - */ - -int journal_test_revoke(journal_t *journal, - unsigned int blocknr, - tid_t sequence) -{ - struct jbd_revoke_record_s *record; - - record = find_revoke_record(journal, blocknr); - if (!record) - return 0; - if (tid_gt(sequence, record->sequence)) - return 0; - return 1; -} - -/* - * Finally, once recovery is over, we need to clear the revoke table so - * that it can be reused by the running filesystem. - */ - -void journal_clear_revoke(journal_t *journal) -{ - int i; - struct list_head *hash_list; - struct jbd_revoke_record_s *record; - struct jbd_revoke_table_s *revoke; - - revoke = journal->j_revoke; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - while (!list_empty(hash_list)) { - record = (struct jbd_revoke_record_s*) hash_list->next; - list_del(&record->hash); - kmem_cache_free(revoke_record_cache, record); - } - } -} diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c deleted file mode 100644 index 1695ba8334a2a..0000000000000 --- a/fs/jbd/transaction.c +++ /dev/null @@ -1,2237 +0,0 @@ -/* - * linux/fs/jbd/transaction.c - * - * Written by Stephen C. Tweedie , 1998 - * - * Copyright 1998 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Generic filesystem transaction handling code; part of the ext2fs - * journaling system. - * - * This file manages transactions (compound commits managed by the - * journaling code) and handles (individual atomic operations by the - * filesystem). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void __journal_temp_unlink_buffer(struct journal_head *jh); - -/* - * get_transaction: obtain a new transaction_t object. - * - * Simply allocate and initialise a new transaction. Create it in - * RUNNING state and add it to the current journal (which should not - * have an existing running transaction: we only make a new transaction - * once we have started to commit the old one). - * - * Preconditions: - * The journal MUST be locked. We don't perform atomic mallocs on the - * new transaction and we can't block without protecting against other - * processes trying to touch the journal while it is in transition. - * - * Called under j_state_lock - */ - -static transaction_t * -get_transaction(journal_t *journal, transaction_t *transaction) -{ - transaction->t_journal = journal; - transaction->t_state = T_RUNNING; - transaction->t_start_time = ktime_get(); - transaction->t_tid = journal->j_transaction_sequence++; - transaction->t_expires = jiffies + journal->j_commit_interval; - spin_lock_init(&transaction->t_handle_lock); - - /* Set up the commit timer for the new transaction. */ - journal->j_commit_timer.expires = - round_jiffies_up(transaction->t_expires); - add_timer(&journal->j_commit_timer); - - J_ASSERT(journal->j_running_transaction == NULL); - journal->j_running_transaction = transaction; - - return transaction; -} - -/* - * Handle management. - * - * A handle_t is an object which represents a single atomic update to a - * filesystem, and which tracks all of the modifications which form part - * of that one update. - */ - -/* - * start_this_handle: Given a handle, deal with any locking or stalling - * needed to make sure that there is enough journal space for the handle - * to begin. Attach the handle to a transaction and set up the - * transaction's buffer credits. - */ - -static int start_this_handle(journal_t *journal, handle_t *handle) -{ - transaction_t *transaction; - int needed; - int nblocks = handle->h_buffer_credits; - transaction_t *new_transaction = NULL; - int ret = 0; - - if (nblocks > journal->j_max_transaction_buffers) { - printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", - current->comm, nblocks, - journal->j_max_transaction_buffers); - ret = -ENOSPC; - goto out; - } - -alloc_transaction: - if (!journal->j_running_transaction) { - new_transaction = kzalloc(sizeof(*new_transaction), - GFP_NOFS|__GFP_NOFAIL); - if (!new_transaction) { - ret = -ENOMEM; - goto out; - } - } - - jbd_debug(3, "New handle %p going live.\n", handle); - -repeat: - - /* - * We need to hold j_state_lock until t_updates has been incremented, - * for proper journal barrier handling - */ - spin_lock(&journal->j_state_lock); -repeat_locked: - if (is_journal_aborted(journal) || - (journal->j_errno != 0 && !(journal->j_flags & JFS_ACK_ERR))) { - spin_unlock(&journal->j_state_lock); - ret = -EROFS; - goto out; - } - - /* Wait on the journal's transaction barrier if necessary */ - if (journal->j_barrier_count) { - spin_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_transaction_locked, - journal->j_barrier_count == 0); - goto repeat; - } - - if (!journal->j_running_transaction) { - if (!new_transaction) { - spin_unlock(&journal->j_state_lock); - goto alloc_transaction; - } - get_transaction(journal, new_transaction); - new_transaction = NULL; - } - - transaction = journal->j_running_transaction; - - /* - * If the current transaction is locked down for commit, wait for the - * lock to be released. - */ - if (transaction->t_state == T_LOCKED) { - DEFINE_WAIT(wait); - - prepare_to_wait(&journal->j_wait_transaction_locked, - &wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&journal->j_state_lock); - schedule(); - finish_wait(&journal->j_wait_transaction_locked, &wait); - goto repeat; - } - - /* - * If there is not enough space left in the log to write all potential - * buffers requested by this operation, we need to stall pending a log - * checkpoint to free some more log space. - */ - spin_lock(&transaction->t_handle_lock); - needed = transaction->t_outstanding_credits + nblocks; - - if (needed > journal->j_max_transaction_buffers) { - /* - * If the current transaction is already too large, then start - * to commit it: we can then go back and attach this handle to - * a new transaction. - */ - DEFINE_WAIT(wait); - - jbd_debug(2, "Handle %p starting new commit...\n", handle); - spin_unlock(&transaction->t_handle_lock); - prepare_to_wait(&journal->j_wait_transaction_locked, &wait, - TASK_UNINTERRUPTIBLE); - __log_start_commit(journal, transaction->t_tid); - spin_unlock(&journal->j_state_lock); - schedule(); - finish_wait(&journal->j_wait_transaction_locked, &wait); - goto repeat; - } - - /* - * The commit code assumes that it can get enough log space - * without forcing a checkpoint. This is *critical* for - * correctness: a checkpoint of a buffer which is also - * associated with a committing transaction creates a deadlock, - * so commit simply cannot force through checkpoints. - * - * We must therefore ensure the necessary space in the journal - * *before* starting to dirty potentially checkpointed buffers - * in the new transaction. - * - * The worst part is, any transaction currently committing can - * reduce the free space arbitrarily. Be careful to account for - * those buffers when checkpointing. - */ - - /* - * @@@ AKPM: This seems rather over-defensive. We're giving commit - * a _lot_ of headroom: 1/4 of the journal plus the size of - * the committing transaction. Really, we only need to give it - * committing_transaction->t_outstanding_credits plus "enough" for - * the log control blocks. - * Also, this test is inconsistent with the matching one in - * journal_extend(). - */ - if (__log_space_left(journal) < jbd_space_needed(journal)) { - jbd_debug(2, "Handle %p waiting for checkpoint...\n", handle); - spin_unlock(&transaction->t_handle_lock); - __log_wait_for_space(journal); - goto repeat_locked; - } - - /* OK, account for the buffers that this operation expects to - * use and add the handle to the running transaction. */ - - handle->h_transaction = transaction; - transaction->t_outstanding_credits += nblocks; - transaction->t_updates++; - transaction->t_handle_count++; - jbd_debug(4, "Handle %p given %d credits (total %d, free %d)\n", - handle, nblocks, transaction->t_outstanding_credits, - __log_space_left(journal)); - spin_unlock(&transaction->t_handle_lock); - spin_unlock(&journal->j_state_lock); - - lock_map_acquire(&handle->h_lockdep_map); -out: - if (unlikely(new_transaction)) /* It's usually NULL */ - kfree(new_transaction); - return ret; -} - -static struct lock_class_key jbd_handle_key; - -/* Allocate a new handle. This should probably be in a slab... */ -static handle_t *new_handle(int nblocks) -{ - handle_t *handle = jbd_alloc_handle(GFP_NOFS); - if (!handle) - return NULL; - handle->h_buffer_credits = nblocks; - handle->h_ref = 1; - - lockdep_init_map(&handle->h_lockdep_map, "jbd_handle", &jbd_handle_key, 0); - - return handle; -} - -/** - * handle_t *journal_start() - Obtain a new handle. - * @journal: Journal to start transaction on. - * @nblocks: number of block buffer we might modify - * - * We make sure that the transaction can guarantee at least nblocks of - * modified buffers in the log. We block until the log can guarantee - * that much space. - * - * This function is visible to journal users (like ext3fs), so is not - * called with the journal already locked. - * - * Return a pointer to a newly allocated handle, or an ERR_PTR() value - * on failure. - */ -handle_t *journal_start(journal_t *journal, int nblocks) -{ - handle_t *handle = journal_current_handle(); - int err; - - if (!journal) - return ERR_PTR(-EROFS); - - if (handle) { - J_ASSERT(handle->h_transaction->t_journal == journal); - handle->h_ref++; - return handle; - } - - handle = new_handle(nblocks); - if (!handle) - return ERR_PTR(-ENOMEM); - - current->journal_info = handle; - - err = start_this_handle(journal, handle); - if (err < 0) { - jbd_free_handle(handle); - current->journal_info = NULL; - handle = ERR_PTR(err); - } - return handle; -} - -/** - * int journal_extend() - extend buffer credits. - * @handle: handle to 'extend' - * @nblocks: nr blocks to try to extend by. - * - * Some transactions, such as large extends and truncates, can be done - * atomically all at once or in several stages. The operation requests - * a credit for a number of buffer modications in advance, but can - * extend its credit if it needs more. - * - * journal_extend tries to give the running handle more buffer credits. - * It does not guarantee that allocation - this is a best-effort only. - * The calling process MUST be able to deal cleanly with a failure to - * extend here. - * - * Return 0 on success, non-zero on failure. - * - * return code < 0 implies an error - * return code > 0 implies normal transaction-full status. - */ -int journal_extend(handle_t *handle, int nblocks) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - int result; - int wanted; - - result = -EIO; - if (is_handle_aborted(handle)) - goto out; - - result = 1; - - spin_lock(&journal->j_state_lock); - - /* Don't extend a locked-down transaction! */ - if (handle->h_transaction->t_state != T_RUNNING) { - jbd_debug(3, "denied handle %p %d blocks: " - "transaction not running\n", handle, nblocks); - goto error_out; - } - - spin_lock(&transaction->t_handle_lock); - wanted = transaction->t_outstanding_credits + nblocks; - - if (wanted > journal->j_max_transaction_buffers) { - jbd_debug(3, "denied handle %p %d blocks: " - "transaction too large\n", handle, nblocks); - goto unlock; - } - - if (wanted > __log_space_left(journal)) { - jbd_debug(3, "denied handle %p %d blocks: " - "insufficient log space\n", handle, nblocks); - goto unlock; - } - - handle->h_buffer_credits += nblocks; - transaction->t_outstanding_credits += nblocks; - result = 0; - - jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); -unlock: - spin_unlock(&transaction->t_handle_lock); -error_out: - spin_unlock(&journal->j_state_lock); -out: - return result; -} - - -/** - * int journal_restart() - restart a handle. - * @handle: handle to restart - * @nblocks: nr credits requested - * - * Restart a handle for a multi-transaction filesystem - * operation. - * - * If the journal_extend() call above fails to grant new buffer credits - * to a running handle, a call to journal_restart will commit the - * handle's transaction so far and reattach the handle to a new - * transaction capabable of guaranteeing the requested number of - * credits. - */ - -int journal_restart(handle_t *handle, int nblocks) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - int ret; - - /* If we've had an abort of any type, don't even think about - * actually doing the restart! */ - if (is_handle_aborted(handle)) - return 0; - - /* - * First unlink the handle from its current transaction, and start the - * commit on that. - */ - J_ASSERT(transaction->t_updates > 0); - J_ASSERT(journal_current_handle() == handle); - - spin_lock(&journal->j_state_lock); - spin_lock(&transaction->t_handle_lock); - transaction->t_outstanding_credits -= handle->h_buffer_credits; - transaction->t_updates--; - - if (!transaction->t_updates) - wake_up(&journal->j_wait_updates); - spin_unlock(&transaction->t_handle_lock); - - jbd_debug(2, "restarting handle %p\n", handle); - __log_start_commit(journal, transaction->t_tid); - spin_unlock(&journal->j_state_lock); - - lock_map_release(&handle->h_lockdep_map); - handle->h_buffer_credits = nblocks; - ret = start_this_handle(journal, handle); - return ret; -} - - -/** - * void journal_lock_updates () - establish a transaction barrier. - * @journal: Journal to establish a barrier on. - * - * This locks out any further updates from being started, and blocks until all - * existing updates have completed, returning only once the journal is in a - * quiescent state with no updates running. - * - * We do not use simple mutex for synchronization as there are syscalls which - * want to return with filesystem locked and that trips up lockdep. Also - * hibernate needs to lock filesystem but locked mutex then blocks hibernation. - * Since locking filesystem is rare operation, we use simple counter and - * waitqueue for locking. - */ -void journal_lock_updates(journal_t *journal) -{ - DEFINE_WAIT(wait); - -wait: - /* Wait for previous locked operation to finish */ - wait_event(journal->j_wait_transaction_locked, - journal->j_barrier_count == 0); - - spin_lock(&journal->j_state_lock); - /* - * Check reliably under the lock whether we are the ones winning the race - * and locking the journal - */ - if (journal->j_barrier_count > 0) { - spin_unlock(&journal->j_state_lock); - goto wait; - } - ++journal->j_barrier_count; - - /* Wait until there are no running updates */ - while (1) { - transaction_t *transaction = journal->j_running_transaction; - - if (!transaction) - break; - - spin_lock(&transaction->t_handle_lock); - if (!transaction->t_updates) { - spin_unlock(&transaction->t_handle_lock); - break; - } - prepare_to_wait(&journal->j_wait_updates, &wait, - TASK_UNINTERRUPTIBLE); - spin_unlock(&transaction->t_handle_lock); - spin_unlock(&journal->j_state_lock); - schedule(); - finish_wait(&journal->j_wait_updates, &wait); - spin_lock(&journal->j_state_lock); - } - spin_unlock(&journal->j_state_lock); -} - -/** - * void journal_unlock_updates (journal_t* journal) - release barrier - * @journal: Journal to release the barrier on. - * - * Release a transaction barrier obtained with journal_lock_updates(). - */ -void journal_unlock_updates (journal_t *journal) -{ - J_ASSERT(journal->j_barrier_count != 0); - - spin_lock(&journal->j_state_lock); - --journal->j_barrier_count; - spin_unlock(&journal->j_state_lock); - wake_up(&journal->j_wait_transaction_locked); -} - -static void warn_dirty_buffer(struct buffer_head *bh) -{ - char b[BDEVNAME_SIZE]; - - printk(KERN_WARNING - "JBD: Spotted dirty metadata buffer (dev = %s, blocknr = %llu). " - "There's a risk of filesystem corruption in case of system " - "crash.\n", - bdevname(bh->b_bdev, b), (unsigned long long)bh->b_blocknr); -} - -/* - * If the buffer is already part of the current transaction, then there - * is nothing we need to do. If it is already part of a prior - * transaction which we are still committing to disk, then we need to - * make sure that we do not overwrite the old copy: we do copy-out to - * preserve the copy going to disk. We also account the buffer against - * the handle's metadata buffer credits (unless the buffer is already - * part of the transaction, that is). - * - */ -static int -do_get_write_access(handle_t *handle, struct journal_head *jh, - int force_copy) -{ - struct buffer_head *bh; - transaction_t *transaction; - journal_t *journal; - int error; - char *frozen_buffer = NULL; - int need_copy = 0; - - if (is_handle_aborted(handle)) - return -EROFS; - - transaction = handle->h_transaction; - journal = transaction->t_journal; - - jbd_debug(5, "journal_head %p, force_copy %d\n", jh, force_copy); - - JBUFFER_TRACE(jh, "entry"); -repeat: - bh = jh2bh(jh); - - /* @@@ Need to check for errors here at some point. */ - - lock_buffer(bh); - jbd_lock_bh_state(bh); - - /* We now hold the buffer lock so it is safe to query the buffer - * state. Is the buffer dirty? - * - * If so, there are two possibilities. The buffer may be - * non-journaled, and undergoing a quite legitimate writeback. - * Otherwise, it is journaled, and we don't expect dirty buffers - * in that state (the buffers should be marked JBD_Dirty - * instead.) So either the IO is being done under our own - * control and this is a bug, or it's a third party IO such as - * dump(8) (which may leave the buffer scheduled for read --- - * ie. locked but not dirty) or tune2fs (which may actually have - * the buffer dirtied, ugh.) */ - - if (buffer_dirty(bh)) { - /* - * First question: is this buffer already part of the current - * transaction or the existing committing transaction? - */ - if (jh->b_transaction) { - J_ASSERT_JH(jh, - jh->b_transaction == transaction || - jh->b_transaction == - journal->j_committing_transaction); - if (jh->b_next_transaction) - J_ASSERT_JH(jh, jh->b_next_transaction == - transaction); - warn_dirty_buffer(bh); - } - /* - * In any case we need to clean the dirty flag and we must - * do it under the buffer lock to be sure we don't race - * with running write-out. - */ - JBUFFER_TRACE(jh, "Journalling dirty buffer"); - clear_buffer_dirty(bh); - set_buffer_jbddirty(bh); - } - - unlock_buffer(bh); - - error = -EROFS; - if (is_handle_aborted(handle)) { - jbd_unlock_bh_state(bh); - goto out; - } - error = 0; - - /* - * The buffer is already part of this transaction if b_transaction or - * b_next_transaction points to it - */ - if (jh->b_transaction == transaction || - jh->b_next_transaction == transaction) - goto done; - - /* - * this is the first time this transaction is touching this buffer, - * reset the modified flag - */ - jh->b_modified = 0; - - /* - * If there is already a copy-out version of this buffer, then we don't - * need to make another one - */ - if (jh->b_frozen_data) { - JBUFFER_TRACE(jh, "has frozen data"); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - jh->b_next_transaction = transaction; - goto done; - } - - /* Is there data here we need to preserve? */ - - if (jh->b_transaction && jh->b_transaction != transaction) { - JBUFFER_TRACE(jh, "owned by older transaction"); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, jh->b_transaction == - journal->j_committing_transaction); - - /* There is one case we have to be very careful about. - * If the committing transaction is currently writing - * this buffer out to disk and has NOT made a copy-out, - * then we cannot modify the buffer contents at all - * right now. The essence of copy-out is that it is the - * extra copy, not the primary copy, which gets - * journaled. If the primary copy is already going to - * disk then we cannot do copy-out here. */ - - if (jh->b_jlist == BJ_Shadow) { - DEFINE_WAIT_BIT(wait, &bh->b_state, BH_Unshadow); - wait_queue_head_t *wqh; - - wqh = bit_waitqueue(&bh->b_state, BH_Unshadow); - - JBUFFER_TRACE(jh, "on shadow: sleep"); - jbd_unlock_bh_state(bh); - /* commit wakes up all shadow buffers after IO */ - for ( ; ; ) { - prepare_to_wait(wqh, &wait.wait, - TASK_UNINTERRUPTIBLE); - if (jh->b_jlist != BJ_Shadow) - break; - schedule(); - } - finish_wait(wqh, &wait.wait); - goto repeat; - } - - /* Only do the copy if the currently-owning transaction - * still needs it. If it is on the Forget list, the - * committing transaction is past that stage. The - * buffer had better remain locked during the kmalloc, - * but that should be true --- we hold the journal lock - * still and the buffer is already on the BUF_JOURNAL - * list so won't be flushed. - * - * Subtle point, though: if this is a get_undo_access, - * then we will be relying on the frozen_data to contain - * the new value of the committed_data record after the - * transaction, so we HAVE to force the frozen_data copy - * in that case. */ - - if (jh->b_jlist != BJ_Forget || force_copy) { - JBUFFER_TRACE(jh, "generate frozen data"); - if (!frozen_buffer) { - JBUFFER_TRACE(jh, "allocate memory for buffer"); - jbd_unlock_bh_state(bh); - frozen_buffer = - jbd_alloc(jh2bh(jh)->b_size, - GFP_NOFS); - if (!frozen_buffer) { - printk(KERN_ERR - "%s: OOM for frozen_buffer\n", - __func__); - JBUFFER_TRACE(jh, "oom!"); - error = -ENOMEM; - jbd_lock_bh_state(bh); - goto done; - } - goto repeat; - } - jh->b_frozen_data = frozen_buffer; - frozen_buffer = NULL; - need_copy = 1; - } - jh->b_next_transaction = transaction; - } - - - /* - * Finally, if the buffer is not journaled right now, we need to make - * sure it doesn't get written to disk before the caller actually - * commits the new data - */ - if (!jh->b_transaction) { - JBUFFER_TRACE(jh, "no transaction"); - J_ASSERT_JH(jh, !jh->b_next_transaction); - JBUFFER_TRACE(jh, "file as BJ_Reserved"); - spin_lock(&journal->j_list_lock); - __journal_file_buffer(jh, transaction, BJ_Reserved); - spin_unlock(&journal->j_list_lock); - } - -done: - if (need_copy) { - struct page *page; - int offset; - char *source; - - J_EXPECT_JH(jh, buffer_uptodate(jh2bh(jh)), - "Possible IO failure.\n"); - page = jh2bh(jh)->b_page; - offset = offset_in_page(jh2bh(jh)->b_data); - source = kmap_atomic(page); - memcpy(jh->b_frozen_data, source+offset, jh2bh(jh)->b_size); - kunmap_atomic(source); - } - jbd_unlock_bh_state(bh); - - /* - * If we are about to journal a buffer, then any revoke pending on it is - * no longer valid - */ - journal_cancel_revoke(handle, jh); - -out: - if (unlikely(frozen_buffer)) /* It's usually NULL */ - jbd_free(frozen_buffer, bh->b_size); - - JBUFFER_TRACE(jh, "exit"); - return error; -} - -/** - * int journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. - * @handle: transaction to add buffer modifications to - * @bh: bh to be used for metadata writes - * - * Returns an error code or 0 on success. - * - * In full data journalling mode the buffer may be of type BJ_AsyncData, - * because we're write()ing a buffer which is also part of a shared mapping. - */ - -int journal_get_write_access(handle_t *handle, struct buffer_head *bh) -{ - struct journal_head *jh = journal_add_journal_head(bh); - int rc; - - /* We do not want to get caught playing with fields which the - * log thread also manipulates. Make sure that the buffer - * completes any outstanding IO before proceeding. */ - rc = do_get_write_access(handle, jh, 0); - journal_put_journal_head(jh); - return rc; -} - - -/* - * When the user wants to journal a newly created buffer_head - * (ie. getblk() returned a new buffer and we are going to populate it - * manually rather than reading off disk), then we need to keep the - * buffer_head locked until it has been completely filled with new - * data. In this case, we should be able to make the assertion that - * the bh is not already part of an existing transaction. - * - * The buffer should already be locked by the caller by this point. - * There is no lock ranking violation: it was a newly created, - * unlocked buffer beforehand. */ - -/** - * int journal_get_create_access () - notify intent to use newly created bh - * @handle: transaction to new buffer to - * @bh: new buffer. - * - * Call this if you create a new bh. - */ -int journal_get_create_access(handle_t *handle, struct buffer_head *bh) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - struct journal_head *jh = journal_add_journal_head(bh); - int err; - - jbd_debug(5, "journal_head %p\n", jh); - err = -EROFS; - if (is_handle_aborted(handle)) - goto out; - err = 0; - - JBUFFER_TRACE(jh, "entry"); - /* - * The buffer may already belong to this transaction due to pre-zeroing - * in the filesystem's new_block code. It may also be on the previous, - * committing transaction's lists, but it HAS to be in Forget state in - * that case: the transaction must have deleted the buffer for it to be - * reused here. - */ - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - J_ASSERT_JH(jh, (jh->b_transaction == transaction || - jh->b_transaction == NULL || - (jh->b_transaction == journal->j_committing_transaction && - jh->b_jlist == BJ_Forget))); - - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); - - if (jh->b_transaction == NULL) { - /* - * Previous journal_forget() could have left the buffer - * with jbddirty bit set because it was being committed. When - * the commit finished, we've filed the buffer for - * checkpointing and marked it dirty. Now we are reallocating - * the buffer so the transaction freeing it must have - * committed and so it's safe to clear the dirty bit. - */ - clear_buffer_dirty(jh2bh(jh)); - - /* first access by this transaction */ - jh->b_modified = 0; - - JBUFFER_TRACE(jh, "file as BJ_Reserved"); - __journal_file_buffer(jh, transaction, BJ_Reserved); - } else if (jh->b_transaction == journal->j_committing_transaction) { - /* first access by this transaction */ - jh->b_modified = 0; - - JBUFFER_TRACE(jh, "set next transaction"); - jh->b_next_transaction = transaction; - } - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - - /* - * akpm: I added this. ext3_alloc_branch can pick up new indirect - * blocks which contain freed but then revoked metadata. We need - * to cancel the revoke in case we end up freeing it yet again - * and the reallocating as data - this would cause a second revoke, - * which hits an assertion error. - */ - JBUFFER_TRACE(jh, "cancelling revoke"); - journal_cancel_revoke(handle, jh); -out: - journal_put_journal_head(jh); - return err; -} - -/** - * int journal_get_undo_access() - Notify intent to modify metadata with non-rewindable consequences - * @handle: transaction - * @bh: buffer to undo - * - * Sometimes there is a need to distinguish between metadata which has - * been committed to disk and that which has not. The ext3fs code uses - * this for freeing and allocating space, we have to make sure that we - * do not reuse freed space until the deallocation has been committed, - * since if we overwrote that space we would make the delete - * un-rewindable in case of a crash. - * - * To deal with that, journal_get_undo_access requests write access to a - * buffer for parts of non-rewindable operations such as delete - * operations on the bitmaps. The journaling code must keep a copy of - * the buffer's contents prior to the undo_access call until such time - * as we know that the buffer has definitely been committed to disk. - * - * We never need to know which transaction the committed data is part - * of, buffers touched here are guaranteed to be dirtied later and so - * will be committed to a new transaction in due course, at which point - * we can discard the old committed data pointer. - * - * Returns error number or 0 on success. - */ -int journal_get_undo_access(handle_t *handle, struct buffer_head *bh) -{ - int err; - struct journal_head *jh = journal_add_journal_head(bh); - char *committed_data = NULL; - - JBUFFER_TRACE(jh, "entry"); - - /* - * Do this first --- it can drop the journal lock, so we want to - * make sure that obtaining the committed_data is done - * atomically wrt. completion of any outstanding commits. - */ - err = do_get_write_access(handle, jh, 1); - if (err) - goto out; - -repeat: - if (!jh->b_committed_data) { - committed_data = jbd_alloc(jh2bh(jh)->b_size, GFP_NOFS); - if (!committed_data) { - printk(KERN_ERR "%s: No memory for committed data\n", - __func__); - err = -ENOMEM; - goto out; - } - } - - jbd_lock_bh_state(bh); - if (!jh->b_committed_data) { - /* Copy out the current buffer contents into the - * preserved, committed copy. */ - JBUFFER_TRACE(jh, "generate b_committed data"); - if (!committed_data) { - jbd_unlock_bh_state(bh); - goto repeat; - } - - jh->b_committed_data = committed_data; - committed_data = NULL; - memcpy(jh->b_committed_data, bh->b_data, bh->b_size); - } - jbd_unlock_bh_state(bh); -out: - journal_put_journal_head(jh); - if (unlikely(committed_data)) - jbd_free(committed_data, bh->b_size); - return err; -} - -/** - * int journal_dirty_data() - mark a buffer as containing dirty data to be flushed - * @handle: transaction - * @bh: bufferhead to mark - * - * Description: - * Mark a buffer as containing dirty data which needs to be flushed before - * we can commit the current transaction. - * - * The buffer is placed on the transaction's data list and is marked as - * belonging to the transaction. - * - * Returns error number or 0 on success. - * - * journal_dirty_data() can be called via page_launder->ext3_writepage - * by kswapd. - */ -int journal_dirty_data(handle_t *handle, struct buffer_head *bh) -{ - journal_t *journal = handle->h_transaction->t_journal; - int need_brelse = 0; - struct journal_head *jh; - int ret = 0; - - if (is_handle_aborted(handle)) - return ret; - - jh = journal_add_journal_head(bh); - JBUFFER_TRACE(jh, "entry"); - - /* - * The buffer could *already* be dirty. Writeout can start - * at any time. - */ - jbd_debug(4, "jh: %p, tid:%d\n", jh, handle->h_transaction->t_tid); - - /* - * What if the buffer is already part of a running transaction? - * - * There are two cases: - * 1) It is part of the current running transaction. Refile it, - * just in case we have allocated it as metadata, deallocated - * it, then reallocated it as data. - * 2) It is part of the previous, still-committing transaction. - * If all we want to do is to guarantee that the buffer will be - * written to disk before this new transaction commits, then - * being sure that the *previous* transaction has this same - * property is sufficient for us! Just leave it on its old - * transaction. - * - * In case (2), the buffer must not already exist as metadata - * --- that would violate write ordering (a transaction is free - * to write its data at any point, even before the previous - * committing transaction has committed). The caller must - * never, ever allow this to happen: there's nothing we can do - * about it in this layer. - */ - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - - /* Now that we have bh_state locked, are we really still mapped? */ - if (!buffer_mapped(bh)) { - JBUFFER_TRACE(jh, "unmapped buffer, bailing out"); - goto no_journal; - } - - if (jh->b_transaction) { - JBUFFER_TRACE(jh, "has transaction"); - if (jh->b_transaction != handle->h_transaction) { - JBUFFER_TRACE(jh, "belongs to older transaction"); - J_ASSERT_JH(jh, jh->b_transaction == - journal->j_committing_transaction); - - /* @@@ IS THIS TRUE ? */ - /* - * Not any more. Scenario: someone does a write() - * in data=journal mode. The buffer's transaction has - * moved into commit. Then someone does another - * write() to the file. We do the frozen data copyout - * and set b_next_transaction to point to j_running_t. - * And while we're in that state, someone does a - * writepage() in an attempt to pageout the same area - * of the file via a shared mapping. At present that - * calls journal_dirty_data(), and we get right here. - * It may be too late to journal the data. Simply - * falling through to the next test will suffice: the - * data will be dirty and wil be checkpointed. The - * ordering comments in the next comment block still - * apply. - */ - //J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - - /* - * If we're journalling data, and this buffer was - * subject to a write(), it could be metadata, forget - * or shadow against the committing transaction. Now, - * someone has dirtied the same darn page via a mapping - * and it is being writepage()'d. - * We *could* just steal the page from commit, with some - * fancy locking there. Instead, we just skip it - - * don't tie the page's buffers to the new transaction - * at all. - * Implication: if we crash before the writepage() data - * is written into the filesystem, recovery will replay - * the write() data. - */ - if (jh->b_jlist != BJ_None && - jh->b_jlist != BJ_SyncData && - jh->b_jlist != BJ_Locked) { - JBUFFER_TRACE(jh, "Not stealing"); - goto no_journal; - } - - /* - * This buffer may be undergoing writeout in commit. We - * can't return from here and let the caller dirty it - * again because that can cause the write-out loop in - * commit to never terminate. - */ - if (buffer_dirty(bh)) { - get_bh(bh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - need_brelse = 1; - sync_dirty_buffer(bh); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - /* Since we dropped the lock... */ - if (!buffer_mapped(bh)) { - JBUFFER_TRACE(jh, "buffer got unmapped"); - goto no_journal; - } - /* The buffer may become locked again at any - time if it is redirtied */ - } - - /* - * We cannot remove the buffer with io error from the - * committing transaction, because otherwise it would - * miss the error and the commit would not abort. - */ - if (unlikely(!buffer_uptodate(bh))) { - ret = -EIO; - goto no_journal; - } - /* We might have slept so buffer could be refiled now */ - if (jh->b_transaction != NULL && - jh->b_transaction != handle->h_transaction) { - JBUFFER_TRACE(jh, "unfile from commit"); - __journal_temp_unlink_buffer(jh); - /* It still points to the committing - * transaction; move it to this one so - * that the refile assert checks are - * happy. */ - jh->b_transaction = handle->h_transaction; - } - /* The buffer will be refiled below */ - - } - /* - * Special case --- the buffer might actually have been - * allocated and then immediately deallocated in the previous, - * committing transaction, so might still be left on that - * transaction's metadata lists. - */ - if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) { - JBUFFER_TRACE(jh, "not on correct data list: unfile"); - J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow); - JBUFFER_TRACE(jh, "file as data"); - __journal_file_buffer(jh, handle->h_transaction, - BJ_SyncData); - } - } else { - JBUFFER_TRACE(jh, "not on a transaction"); - __journal_file_buffer(jh, handle->h_transaction, BJ_SyncData); - } -no_journal: - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - if (need_brelse) { - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - } - JBUFFER_TRACE(jh, "exit"); - journal_put_journal_head(jh); - return ret; -} - -/** - * int journal_dirty_metadata() - mark a buffer as containing dirty metadata - * @handle: transaction to add buffer to. - * @bh: buffer to mark - * - * Mark dirty metadata which needs to be journaled as part of the current - * transaction. - * - * The buffer is placed on the transaction's metadata list and is marked - * as belonging to the transaction. - * - * Returns error number or 0 on success. - * - * Special care needs to be taken if the buffer already belongs to the - * current committing transaction (in which case we should have frozen - * data present for that commit). In that case, we don't relink the - * buffer: that only gets done when the old transaction finally - * completes its commit. - */ -int journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - struct journal_head *jh = bh2jh(bh); - - jbd_debug(5, "journal_head %p\n", jh); - JBUFFER_TRACE(jh, "entry"); - if (is_handle_aborted(handle)) - goto out; - - jbd_lock_bh_state(bh); - - if (jh->b_modified == 0) { - /* - * This buffer's got modified and becoming part - * of the transaction. This needs to be done - * once a transaction -bzzz - */ - jh->b_modified = 1; - J_ASSERT_JH(jh, handle->h_buffer_credits > 0); - handle->h_buffer_credits--; - } - - /* - * fastpath, to avoid expensive locking. If this buffer is already - * on the running transaction's metadata list there is nothing to do. - * Nobody can take it off again because there is a handle open. - * I _think_ we're OK here with SMP barriers - a mistaken decision will - * result in this test being false, so we go in and take the locks. - */ - if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) { - JBUFFER_TRACE(jh, "fastpath"); - J_ASSERT_JH(jh, jh->b_transaction == - journal->j_running_transaction); - goto out_unlock_bh; - } - - set_buffer_jbddirty(bh); - - /* - * Metadata already on the current transaction list doesn't - * need to be filed. Metadata on another transaction's list must - * be committing, and will be refiled once the commit completes: - * leave it alone for now. - */ - if (jh->b_transaction != transaction) { - JBUFFER_TRACE(jh, "already on other transaction"); - J_ASSERT_JH(jh, jh->b_transaction == - journal->j_committing_transaction); - J_ASSERT_JH(jh, jh->b_next_transaction == transaction); - /* And this case is illegal: we can't reuse another - * transaction's data buffer, ever. */ - goto out_unlock_bh; - } - - /* That test should have eliminated the following case: */ - J_ASSERT_JH(jh, jh->b_frozen_data == NULL); - - JBUFFER_TRACE(jh, "file as BJ_Metadata"); - spin_lock(&journal->j_list_lock); - __journal_file_buffer(jh, handle->h_transaction, BJ_Metadata); - spin_unlock(&journal->j_list_lock); -out_unlock_bh: - jbd_unlock_bh_state(bh); -out: - JBUFFER_TRACE(jh, "exit"); - return 0; -} - -/* - * journal_release_buffer: undo a get_write_access without any buffer - * updates, if the update decided in the end that it didn't need access. - * - */ -void -journal_release_buffer(handle_t *handle, struct buffer_head *bh) -{ - BUFFER_TRACE(bh, "entry"); -} - -/** - * void journal_forget() - bforget() for potentially-journaled buffers. - * @handle: transaction handle - * @bh: bh to 'forget' - * - * We can only do the bforget if there are no commits pending against the - * buffer. If the buffer is dirty in the current running transaction we - * can safely unlink it. - * - * bh may not be a journalled buffer at all - it may be a non-JBD - * buffer which came off the hashtable. Check for this. - * - * Decrements bh->b_count by one. - * - * Allow this call even if the handle has aborted --- it may be part of - * the caller's cleanup after an abort. - */ -int journal_forget (handle_t *handle, struct buffer_head *bh) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - struct journal_head *jh; - int drop_reserve = 0; - int err = 0; - int was_modified = 0; - - BUFFER_TRACE(bh, "entry"); - - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - - if (!buffer_jbd(bh)) - goto not_jbd; - jh = bh2jh(bh); - - /* Critical error: attempting to delete a bitmap buffer, maybe? - * Don't do any jbd operations, and return an error. */ - if (!J_EXPECT_JH(jh, !jh->b_committed_data, - "inconsistent data on disk")) { - err = -EIO; - goto not_jbd; - } - - /* keep track of whether or not this transaction modified us */ - was_modified = jh->b_modified; - - /* - * The buffer's going from the transaction, we must drop - * all references -bzzz - */ - jh->b_modified = 0; - - if (jh->b_transaction == handle->h_transaction) { - J_ASSERT_JH(jh, !jh->b_frozen_data); - - /* If we are forgetting a buffer which is already part - * of this transaction, then we can just drop it from - * the transaction immediately. */ - clear_buffer_dirty(bh); - clear_buffer_jbddirty(bh); - - JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); - - /* - * we only want to drop a reference if this transaction - * modified the buffer - */ - if (was_modified) - drop_reserve = 1; - - /* - * We are no longer going to journal this buffer. - * However, the commit of this transaction is still - * important to the buffer: the delete that we are now - * processing might obsolete an old log entry, so by - * committing, we can satisfy the buffer's checkpoint. - * - * So, if we have a checkpoint on the buffer, we should - * now refile the buffer on our BJ_Forget list so that - * we know to remove the checkpoint after we commit. - */ - - if (jh->b_cp_transaction) { - __journal_temp_unlink_buffer(jh); - __journal_file_buffer(jh, transaction, BJ_Forget); - } else { - __journal_unfile_buffer(jh); - if (!buffer_jbd(bh)) { - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - __bforget(bh); - goto drop; - } - } - } else if (jh->b_transaction) { - J_ASSERT_JH(jh, (jh->b_transaction == - journal->j_committing_transaction)); - /* However, if the buffer is still owned by a prior - * (committing) transaction, we can't drop it yet... */ - JBUFFER_TRACE(jh, "belongs to older transaction"); - /* ... but we CAN drop it from the new transaction if we - * have also modified it since the original commit. */ - - if (jh->b_next_transaction) { - J_ASSERT(jh->b_next_transaction == transaction); - jh->b_next_transaction = NULL; - - /* - * only drop a reference if this transaction modified - * the buffer - */ - if (was_modified) - drop_reserve = 1; - } - } - -not_jbd: - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - __brelse(bh); -drop: - if (drop_reserve) { - /* no need to reserve log space for this block -bzzz */ - handle->h_buffer_credits++; - } - return err; -} - -/** - * int journal_stop() - complete a transaction - * @handle: tranaction to complete. - * - * All done for a particular handle. - * - * There is not much action needed here. We just return any remaining - * buffer credits to the transaction and remove the handle. The only - * complication is that we need to start a commit operation if the - * filesystem is marked for synchronous update. - * - * journal_stop itself will not usually return an error, but it may - * do so in unusual circumstances. In particular, expect it to - * return -EIO if a journal_abort has been executed since the - * transaction began. - */ -int journal_stop(handle_t *handle) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal = transaction->t_journal; - int err; - pid_t pid; - - J_ASSERT(journal_current_handle() == handle); - - if (is_handle_aborted(handle)) - err = -EIO; - else { - J_ASSERT(transaction->t_updates > 0); - err = 0; - } - - if (--handle->h_ref > 0) { - jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, - handle->h_ref); - return err; - } - - jbd_debug(4, "Handle %p going down\n", handle); - - /* - * Implement synchronous transaction batching. If the handle - * was synchronous, don't force a commit immediately. Let's - * yield and let another thread piggyback onto this transaction. - * Keep doing that while new threads continue to arrive. - * It doesn't cost much - we're about to run a commit and sleep - * on IO anyway. Speeds up many-threaded, many-dir operations - * by 30x or more... - * - * We try and optimize the sleep time against what the underlying disk - * can do, instead of having a static sleep time. This is useful for - * the case where our storage is so fast that it is more optimal to go - * ahead and force a flush and wait for the transaction to be committed - * than it is to wait for an arbitrary amount of time for new writers to - * join the transaction. We achieve this by measuring how long it takes - * to commit a transaction, and compare it with how long this - * transaction has been running, and if run time < commit time then we - * sleep for the delta and commit. This greatly helps super fast disks - * that would see slowdowns as more threads started doing fsyncs. - * - * But don't do this if this process was the most recent one to - * perform a synchronous write. We do this to detect the case where a - * single process is doing a stream of sync writes. No point in waiting - * for joiners in that case. - */ - pid = current->pid; - if (handle->h_sync && journal->j_last_sync_writer != pid) { - u64 commit_time, trans_time; - - journal->j_last_sync_writer = pid; - - spin_lock(&journal->j_state_lock); - commit_time = journal->j_average_commit_time; - spin_unlock(&journal->j_state_lock); - - trans_time = ktime_to_ns(ktime_sub(ktime_get(), - transaction->t_start_time)); - - commit_time = min_t(u64, commit_time, - 1000*jiffies_to_usecs(1)); - - if (trans_time < commit_time) { - ktime_t expires = ktime_add_ns(ktime_get(), - commit_time); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_hrtimeout(&expires, HRTIMER_MODE_ABS); - } - } - - current->journal_info = NULL; - spin_lock(&journal->j_state_lock); - spin_lock(&transaction->t_handle_lock); - transaction->t_outstanding_credits -= handle->h_buffer_credits; - transaction->t_updates--; - if (!transaction->t_updates) { - wake_up(&journal->j_wait_updates); - if (journal->j_barrier_count) - wake_up(&journal->j_wait_transaction_locked); - } - - /* - * If the handle is marked SYNC, we need to set another commit - * going! We also want to force a commit if the current - * transaction is occupying too much of the log, or if the - * transaction is too old now. - */ - if (handle->h_sync || - transaction->t_outstanding_credits > - journal->j_max_transaction_buffers || - time_after_eq(jiffies, transaction->t_expires)) { - /* Do this even for aborted journals: an abort still - * completes the commit thread, it just doesn't write - * anything to disk. */ - tid_t tid = transaction->t_tid; - - spin_unlock(&transaction->t_handle_lock); - jbd_debug(2, "transaction too old, requesting commit for " - "handle %p\n", handle); - /* This is non-blocking */ - __log_start_commit(journal, transaction->t_tid); - spin_unlock(&journal->j_state_lock); - - /* - * Special case: JFS_SYNC synchronous updates require us - * to wait for the commit to complete. - */ - if (handle->h_sync && !(current->flags & PF_MEMALLOC)) - err = log_wait_commit(journal, tid); - } else { - spin_unlock(&transaction->t_handle_lock); - spin_unlock(&journal->j_state_lock); - } - - lock_map_release(&handle->h_lockdep_map); - - jbd_free_handle(handle); - return err; -} - -/** - * int journal_force_commit() - force any uncommitted transactions - * @journal: journal to force - * - * For synchronous operations: force any uncommitted transactions - * to disk. May seem kludgy, but it reuses all the handle batching - * code in a very simple manner. - */ -int journal_force_commit(journal_t *journal) -{ - handle_t *handle; - int ret; - - handle = journal_start(journal, 1); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - } else { - handle->h_sync = 1; - ret = journal_stop(handle); - } - return ret; -} - -/* - * - * List management code snippets: various functions for manipulating the - * transaction buffer lists. - * - */ - -/* - * Append a buffer to a transaction list, given the transaction's list head - * pointer. - * - * j_list_lock is held. - * - * jbd_lock_bh_state(jh2bh(jh)) is held. - */ - -static inline void -__blist_add_buffer(struct journal_head **list, struct journal_head *jh) -{ - if (!*list) { - jh->b_tnext = jh->b_tprev = jh; - *list = jh; - } else { - /* Insert at the tail of the list to preserve order */ - struct journal_head *first = *list, *last = first->b_tprev; - jh->b_tprev = last; - jh->b_tnext = first; - last->b_tnext = first->b_tprev = jh; - } -} - -/* - * Remove a buffer from a transaction list, given the transaction's list - * head pointer. - * - * Called with j_list_lock held, and the journal may not be locked. - * - * jbd_lock_bh_state(jh2bh(jh)) is held. - */ - -static inline void -__blist_del_buffer(struct journal_head **list, struct journal_head *jh) -{ - if (*list == jh) { - *list = jh->b_tnext; - if (*list == jh) - *list = NULL; - } - jh->b_tprev->b_tnext = jh->b_tnext; - jh->b_tnext->b_tprev = jh->b_tprev; -} - -/* - * Remove a buffer from the appropriate transaction list. - * - * Note that this function can *change* the value of - * bh->b_transaction->t_sync_datalist, t_buffers, t_forget, - * t_iobuf_list, t_shadow_list, t_log_list or t_reserved_list. If the caller - * is holding onto a copy of one of thee pointers, it could go bad. - * Generally the caller needs to re-read the pointer from the transaction_t. - * - * Called under j_list_lock. The journal may not be locked. - */ -static void __journal_temp_unlink_buffer(struct journal_head *jh) -{ - struct journal_head **list = NULL; - transaction_t *transaction; - struct buffer_head *bh = jh2bh(jh); - - J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); - transaction = jh->b_transaction; - if (transaction) - assert_spin_locked(&transaction->t_journal->j_list_lock); - - J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); - if (jh->b_jlist != BJ_None) - J_ASSERT_JH(jh, transaction != NULL); - - switch (jh->b_jlist) { - case BJ_None: - return; - case BJ_SyncData: - list = &transaction->t_sync_datalist; - break; - case BJ_Metadata: - transaction->t_nr_buffers--; - J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0); - list = &transaction->t_buffers; - break; - case BJ_Forget: - list = &transaction->t_forget; - break; - case BJ_IO: - list = &transaction->t_iobuf_list; - break; - case BJ_Shadow: - list = &transaction->t_shadow_list; - break; - case BJ_LogCtl: - list = &transaction->t_log_list; - break; - case BJ_Reserved: - list = &transaction->t_reserved_list; - break; - case BJ_Locked: - list = &transaction->t_locked_list; - break; - } - - __blist_del_buffer(list, jh); - jh->b_jlist = BJ_None; - if (test_clear_buffer_jbddirty(bh)) - mark_buffer_dirty(bh); /* Expose it to the VM */ -} - -/* - * Remove buffer from all transactions. - * - * Called with bh_state lock and j_list_lock - * - * jh and bh may be already freed when this function returns. - */ -void __journal_unfile_buffer(struct journal_head *jh) -{ - __journal_temp_unlink_buffer(jh); - jh->b_transaction = NULL; - journal_put_journal_head(jh); -} - -void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) -{ - struct buffer_head *bh = jh2bh(jh); - - /* Get reference so that buffer cannot be freed before we unlock it */ - get_bh(bh); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - __journal_unfile_buffer(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - __brelse(bh); -} - -/* - * Called from journal_try_to_free_buffers(). - * - * Called under jbd_lock_bh_state(bh) - */ -static void -__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) -{ - struct journal_head *jh; - - jh = bh2jh(bh); - - if (buffer_locked(bh) || buffer_dirty(bh)) - goto out; - - if (jh->b_next_transaction != NULL) - goto out; - - spin_lock(&journal->j_list_lock); - if (jh->b_transaction != NULL && jh->b_cp_transaction == NULL) { - if (jh->b_jlist == BJ_SyncData || jh->b_jlist == BJ_Locked) { - /* A written-back ordered data buffer */ - JBUFFER_TRACE(jh, "release data"); - __journal_unfile_buffer(jh); - } - } else if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) { - /* written-back checkpointed metadata buffer */ - if (jh->b_jlist == BJ_None) { - JBUFFER_TRACE(jh, "remove from checkpoint list"); - __journal_remove_checkpoint(jh); - } - } - spin_unlock(&journal->j_list_lock); -out: - return; -} - -/** - * int journal_try_to_free_buffers() - try to free page buffers. - * @journal: journal for operation - * @page: to try and free - * @gfp_mask: we use the mask to detect how hard should we try to release - * buffers. If __GFP_WAIT and __GFP_FS is set, we wait for commit code to - * release the buffers. - * - * - * For all the buffers on this page, - * if they are fully written out ordered data, move them onto BUF_CLEAN - * so try_to_free_buffers() can reap them. - * - * This function returns non-zero if we wish try_to_free_buffers() - * to be called. We do this if the page is releasable by try_to_free_buffers(). - * We also do it if the page has locked or dirty buffers and the caller wants - * us to perform sync or async writeout. - * - * This complicates JBD locking somewhat. We aren't protected by the - * BKL here. We wish to remove the buffer from its committing or - * running transaction's ->t_datalist via __journal_unfile_buffer. - * - * This may *change* the value of transaction_t->t_datalist, so anyone - * who looks at t_datalist needs to lock against this function. - * - * Even worse, someone may be doing a journal_dirty_data on this - * buffer. So we need to lock against that. journal_dirty_data() - * will come out of the lock with the buffer dirty, which makes it - * ineligible for release here. - * - * Who else is affected by this? hmm... Really the only contender - * is do_get_write_access() - it could be looking at the buffer while - * journal_try_to_free_buffer() is changing its state. But that - * cannot happen because we never reallocate freed data as metadata - * while the data is part of a transaction. Yes? - * - * Return 0 on failure, 1 on success - */ -int journal_try_to_free_buffers(journal_t *journal, - struct page *page, gfp_t gfp_mask) -{ - struct buffer_head *head; - struct buffer_head *bh; - int ret = 0; - - J_ASSERT(PageLocked(page)); - - head = page_buffers(page); - bh = head; - do { - struct journal_head *jh; - - /* - * We take our own ref against the journal_head here to avoid - * having to add tons of locking around each instance of - * journal_put_journal_head(). - */ - jh = journal_grab_journal_head(bh); - if (!jh) - continue; - - jbd_lock_bh_state(bh); - __journal_try_to_free_buffer(journal, bh); - journal_put_journal_head(jh); - jbd_unlock_bh_state(bh); - if (buffer_jbd(bh)) - goto busy; - } while ((bh = bh->b_this_page) != head); - - ret = try_to_free_buffers(page); - -busy: - return ret; -} - -/* - * This buffer is no longer needed. If it is on an older transaction's - * checkpoint list we need to record it on this transaction's forget list - * to pin this buffer (and hence its checkpointing transaction) down until - * this transaction commits. If the buffer isn't on a checkpoint list, we - * release it. - * Returns non-zero if JBD no longer has an interest in the buffer. - * - * Called under j_list_lock. - * - * Called under jbd_lock_bh_state(bh). - */ -static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) -{ - int may_free = 1; - struct buffer_head *bh = jh2bh(jh); - - if (jh->b_cp_transaction) { - JBUFFER_TRACE(jh, "on running+cp transaction"); - __journal_temp_unlink_buffer(jh); - /* - * We don't want to write the buffer anymore, clear the - * bit so that we don't confuse checks in - * __journal_file_buffer - */ - clear_buffer_dirty(bh); - __journal_file_buffer(jh, transaction, BJ_Forget); - may_free = 0; - } else { - JBUFFER_TRACE(jh, "on running transaction"); - __journal_unfile_buffer(jh); - } - return may_free; -} - -/* - * journal_invalidatepage - * - * This code is tricky. It has a number of cases to deal with. - * - * There are two invariants which this code relies on: - * - * i_size must be updated on disk before we start calling invalidatepage on the - * data. - * - * This is done in ext3 by defining an ext3_setattr method which - * updates i_size before truncate gets going. By maintaining this - * invariant, we can be sure that it is safe to throw away any buffers - * attached to the current transaction: once the transaction commits, - * we know that the data will not be needed. - * - * Note however that we can *not* throw away data belonging to the - * previous, committing transaction! - * - * Any disk blocks which *are* part of the previous, committing - * transaction (and which therefore cannot be discarded immediately) are - * not going to be reused in the new running transaction - * - * The bitmap committed_data images guarantee this: any block which is - * allocated in one transaction and removed in the next will be marked - * as in-use in the committed_data bitmap, so cannot be reused until - * the next transaction to delete the block commits. This means that - * leaving committing buffers dirty is quite safe: the disk blocks - * cannot be reallocated to a different file and so buffer aliasing is - * not possible. - * - * - * The above applies mainly to ordered data mode. In writeback mode we - * don't make guarantees about the order in which data hits disk --- in - * particular we don't guarantee that new dirty data is flushed before - * transaction commit --- so it is always safe just to discard data - * immediately in that mode. --sct - */ - -/* - * The journal_unmap_buffer helper function returns zero if the buffer - * concerned remains pinned as an anonymous buffer belonging to an older - * transaction. - * - * We're outside-transaction here. Either or both of j_running_transaction - * and j_committing_transaction may be NULL. - */ -static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, - int partial_page) -{ - transaction_t *transaction; - struct journal_head *jh; - int may_free = 1; - - BUFFER_TRACE(bh, "entry"); - -retry: - /* - * It is safe to proceed here without the j_list_lock because the - * buffers cannot be stolen by try_to_free_buffers as long as we are - * holding the page lock. --sct - */ - - if (!buffer_jbd(bh)) - goto zap_buffer_unlocked; - - spin_lock(&journal->j_state_lock); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - - jh = journal_grab_journal_head(bh); - if (!jh) - goto zap_buffer_no_jh; - - /* - * We cannot remove the buffer from checkpoint lists until the - * transaction adding inode to orphan list (let's call it T) - * is committed. Otherwise if the transaction changing the - * buffer would be cleaned from the journal before T is - * committed, a crash will cause that the correct contents of - * the buffer will be lost. On the other hand we have to - * clear the buffer dirty bit at latest at the moment when the - * transaction marking the buffer as freed in the filesystem - * structures is committed because from that moment on the - * block can be reallocated and used by a different page. - * Since the block hasn't been freed yet but the inode has - * already been added to orphan list, it is safe for us to add - * the buffer to BJ_Forget list of the newest transaction. - * - * Also we have to clear buffer_mapped flag of a truncated buffer - * because the buffer_head may be attached to the page straddling - * i_size (can happen only when blocksize < pagesize) and thus the - * buffer_head can be reused when the file is extended again. So we end - * up keeping around invalidated buffers attached to transactions' - * BJ_Forget list just to stop checkpointing code from cleaning up - * the transaction this buffer was modified in. - */ - transaction = jh->b_transaction; - if (transaction == NULL) { - /* First case: not on any transaction. If it - * has no checkpoint link, then we can zap it: - * it's a writeback-mode buffer so we don't care - * if it hits disk safely. */ - if (!jh->b_cp_transaction) { - JBUFFER_TRACE(jh, "not on any transaction: zap"); - goto zap_buffer; - } - - if (!buffer_dirty(bh)) { - /* bdflush has written it. We can drop it now */ - goto zap_buffer; - } - - /* OK, it must be in the journal but still not - * written fully to disk: it's metadata or - * journaled data... */ - - if (journal->j_running_transaction) { - /* ... and once the current transaction has - * committed, the buffer won't be needed any - * longer. */ - JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); - may_free = __dispose_buffer(jh, - journal->j_running_transaction); - goto zap_buffer; - } else { - /* There is no currently-running transaction. So the - * orphan record which we wrote for this file must have - * passed into commit. We must attach this buffer to - * the committing transaction, if it exists. */ - if (journal->j_committing_transaction) { - JBUFFER_TRACE(jh, "give to committing trans"); - may_free = __dispose_buffer(jh, - journal->j_committing_transaction); - goto zap_buffer; - } else { - /* The orphan record's transaction has - * committed. We can cleanse this buffer */ - clear_buffer_jbddirty(bh); - goto zap_buffer; - } - } - } else if (transaction == journal->j_committing_transaction) { - JBUFFER_TRACE(jh, "on committing transaction"); - if (jh->b_jlist == BJ_Locked) { - /* - * The buffer is on the committing transaction's locked - * list. We have the buffer locked, so I/O has - * completed. So we can nail the buffer now. - */ - may_free = __dispose_buffer(jh, transaction); - goto zap_buffer; - } - /* - * The buffer is committing, we simply cannot touch - * it. If the page is straddling i_size we have to wait - * for commit and try again. - */ - if (partial_page) { - tid_t tid = journal->j_committing_transaction->t_tid; - - journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); - unlock_buffer(bh); - log_wait_commit(journal, tid); - lock_buffer(bh); - goto retry; - } - /* - * OK, buffer won't be reachable after truncate. We just set - * j_next_transaction to the running transaction (if there is - * one) and mark buffer as freed so that commit code knows it - * should clear dirty bits when it is done with the buffer. - */ - set_buffer_freed(bh); - if (journal->j_running_transaction && buffer_jbddirty(bh)) - jh->b_next_transaction = journal->j_running_transaction; - journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); - return 0; - } else { - /* Good, the buffer belongs to the running transaction. - * We are writing our own transaction's data, not any - * previous one's, so it is safe to throw it away - * (remember that we expect the filesystem to have set - * i_size already for this truncate so recovery will not - * expose the disk blocks we are discarding here.) */ - J_ASSERT_JH(jh, transaction == journal->j_running_transaction); - JBUFFER_TRACE(jh, "on running transaction"); - may_free = __dispose_buffer(jh, transaction); - } - -zap_buffer: - /* - * This is tricky. Although the buffer is truncated, it may be reused - * if blocksize < pagesize and it is attached to the page straddling - * EOF. Since the buffer might have been added to BJ_Forget list of the - * running transaction, journal_get_write_access() won't clear - * b_modified and credit accounting gets confused. So clear b_modified - * here. */ - jh->b_modified = 0; - journal_put_journal_head(jh); -zap_buffer_no_jh: - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_state_lock); -zap_buffer_unlocked: - clear_buffer_dirty(bh); - J_ASSERT_BH(bh, !buffer_jbddirty(bh)); - clear_buffer_mapped(bh); - clear_buffer_req(bh); - clear_buffer_new(bh); - bh->b_bdev = NULL; - return may_free; -} - -/** - * void journal_invalidatepage() - invalidate a journal page - * @journal: journal to use for flush - * @page: page to flush - * @offset: offset of the range to invalidate - * @length: length of the range to invalidate - * - * Reap page buffers containing data in specified range in page. - */ -void journal_invalidatepage(journal_t *journal, - struct page *page, - unsigned int offset, - unsigned int length) -{ - struct buffer_head *head, *bh, *next; - unsigned int stop = offset + length; - unsigned int curr_off = 0; - int partial_page = (offset || length < PAGE_CACHE_SIZE); - int may_free = 1; - - if (!PageLocked(page)) - BUG(); - if (!page_has_buffers(page)) - return; - - BUG_ON(stop > PAGE_CACHE_SIZE || stop < length); - - /* We will potentially be playing with lists other than just the - * data lists (especially for journaled data mode), so be - * cautious in our locking. */ - - head = bh = page_buffers(page); - do { - unsigned int next_off = curr_off + bh->b_size; - next = bh->b_this_page; - - if (next_off > stop) - return; - - if (offset <= curr_off) { - /* This block is wholly outside the truncation point */ - lock_buffer(bh); - may_free &= journal_unmap_buffer(journal, bh, - partial_page); - unlock_buffer(bh); - } - curr_off = next_off; - bh = next; - - } while (bh != head); - - if (!partial_page) { - if (may_free && try_to_free_buffers(page)) - J_ASSERT(!page_has_buffers(page)); - } -} - -/* - * File a buffer on the given transaction list. - */ -void __journal_file_buffer(struct journal_head *jh, - transaction_t *transaction, int jlist) -{ - struct journal_head **list = NULL; - int was_dirty = 0; - struct buffer_head *bh = jh2bh(jh); - - J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); - assert_spin_locked(&transaction->t_journal->j_list_lock); - - J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); - J_ASSERT_JH(jh, jh->b_transaction == transaction || - jh->b_transaction == NULL); - - if (jh->b_transaction && jh->b_jlist == jlist) - return; - - if (jlist == BJ_Metadata || jlist == BJ_Reserved || - jlist == BJ_Shadow || jlist == BJ_Forget) { - /* - * For metadata buffers, we track dirty bit in buffer_jbddirty - * instead of buffer_dirty. We should not see a dirty bit set - * here because we clear it in do_get_write_access but e.g. - * tune2fs can modify the sb and set the dirty bit at any time - * so we try to gracefully handle that. - */ - if (buffer_dirty(bh)) - warn_dirty_buffer(bh); - if (test_clear_buffer_dirty(bh) || - test_clear_buffer_jbddirty(bh)) - was_dirty = 1; - } - - if (jh->b_transaction) - __journal_temp_unlink_buffer(jh); - else - journal_grab_journal_head(bh); - jh->b_transaction = transaction; - - switch (jlist) { - case BJ_None: - J_ASSERT_JH(jh, !jh->b_committed_data); - J_ASSERT_JH(jh, !jh->b_frozen_data); - return; - case BJ_SyncData: - list = &transaction->t_sync_datalist; - break; - case BJ_Metadata: - transaction->t_nr_buffers++; - list = &transaction->t_buffers; - break; - case BJ_Forget: - list = &transaction->t_forget; - break; - case BJ_IO: - list = &transaction->t_iobuf_list; - break; - case BJ_Shadow: - list = &transaction->t_shadow_list; - break; - case BJ_LogCtl: - list = &transaction->t_log_list; - break; - case BJ_Reserved: - list = &transaction->t_reserved_list; - break; - case BJ_Locked: - list = &transaction->t_locked_list; - break; - } - - __blist_add_buffer(list, jh); - jh->b_jlist = jlist; - - if (was_dirty) - set_buffer_jbddirty(bh); -} - -void journal_file_buffer(struct journal_head *jh, - transaction_t *transaction, int jlist) -{ - jbd_lock_bh_state(jh2bh(jh)); - spin_lock(&transaction->t_journal->j_list_lock); - __journal_file_buffer(jh, transaction, jlist); - spin_unlock(&transaction->t_journal->j_list_lock); - jbd_unlock_bh_state(jh2bh(jh)); -} - -/* - * Remove a buffer from its current buffer list in preparation for - * dropping it from its current transaction entirely. If the buffer has - * already started to be used by a subsequent transaction, refile the - * buffer on that transaction's metadata list. - * - * Called under j_list_lock - * Called under jbd_lock_bh_state(jh2bh(jh)) - * - * jh and bh may be already free when this function returns - */ -void __journal_refile_buffer(struct journal_head *jh) -{ - int was_dirty, jlist; - struct buffer_head *bh = jh2bh(jh); - - J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); - if (jh->b_transaction) - assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock); - - /* If the buffer is now unused, just drop it. */ - if (jh->b_next_transaction == NULL) { - __journal_unfile_buffer(jh); - return; - } - - /* - * It has been modified by a later transaction: add it to the new - * transaction's metadata list. - */ - - was_dirty = test_clear_buffer_jbddirty(bh); - __journal_temp_unlink_buffer(jh); - /* - * We set b_transaction here because b_next_transaction will inherit - * our jh reference and thus __journal_file_buffer() must not take a - * new one. - */ - jh->b_transaction = jh->b_next_transaction; - jh->b_next_transaction = NULL; - if (buffer_freed(bh)) - jlist = BJ_Forget; - else if (jh->b_modified) - jlist = BJ_Metadata; - else - jlist = BJ_Reserved; - __journal_file_buffer(jh, jh->b_transaction, jlist); - J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); - - if (was_dirty) - set_buffer_jbddirty(bh); -} - -/* - * __journal_refile_buffer() with necessary locking added. We take our bh - * reference so that we can safely unlock bh. - * - * The jh and bh may be freed by this call. - */ -void journal_refile_buffer(journal_t *journal, struct journal_head *jh) -{ - struct buffer_head *bh = jh2bh(jh); - - /* Get reference so that buffer cannot be freed before we unlock it */ - get_bh(bh); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - __journal_refile_buffer(jh); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_list_lock); - __brelse(bh); -} diff --git a/include/linux/jbd.h b/include/linux/jbd.h deleted file mode 100644 index d32615280be92..0000000000000 --- a/include/linux/jbd.h +++ /dev/null @@ -1,1047 +0,0 @@ -/* - * linux/include/linux/jbd.h - * - * Written by Stephen C. Tweedie - * - * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Definitions for transaction data structures for the buffer cache - * filesystem journaling support. - */ - -#ifndef _LINUX_JBD_H -#define _LINUX_JBD_H - -/* Allow this file to be included directly into e2fsprogs */ -#ifndef __KERNEL__ -#include "jfs_compat.h" -#define JFS_DEBUG -#define jfs_debug jbd_debug -#else - -#include -#include -#include -#include -#include -#include -#include -#include - -#define journal_oom_retry 1 - -/* - * Define JBD_PARANOID_IOFAIL to cause a kernel BUG() if ext3 finds - * certain classes of error which can occur due to failed IOs. Under - * normal use we want ext3 to continue after such errors, because - * hardware _can_ fail, but for debugging purposes when running tests on - * known-good hardware we may want to trap these errors. - */ -#undef JBD_PARANOID_IOFAIL - -/* - * The default maximum commit age, in seconds. - */ -#define JBD_DEFAULT_MAX_COMMIT_AGE 5 - -#ifdef CONFIG_JBD_DEBUG -/* - * Define JBD_EXPENSIVE_CHECKING to enable more expensive internal - * consistency checks. By default we don't do this unless - * CONFIG_JBD_DEBUG is on. - */ -#define JBD_EXPENSIVE_CHECKING -extern u8 journal_enable_debug; - -void __jbd_debug(int level, const char *file, const char *func, - unsigned int line, const char *fmt, ...); - -#define jbd_debug(n, fmt, a...) \ - __jbd_debug((n), __FILE__, __func__, __LINE__, (fmt), ##a) -#else -#define jbd_debug(n, fmt, a...) /**/ -#endif - -static inline void *jbd_alloc(size_t size, gfp_t flags) -{ - return (void *)__get_free_pages(flags, get_order(size)); -} - -static inline void jbd_free(void *ptr, size_t size) -{ - free_pages((unsigned long)ptr, get_order(size)); -} - -#define JFS_MIN_JOURNAL_BLOCKS 1024 - - -/** - * typedef handle_t - The handle_t type represents a single atomic update being performed by some process. - * - * All filesystem modifications made by the process go - * through this handle. Recursive operations (such as quota operations) - * are gathered into a single update. - * - * The buffer credits field is used to account for journaled buffers - * being modified by the running process. To ensure that there is - * enough log space for all outstanding operations, we need to limit the - * number of outstanding buffers possible at any time. When the - * operation completes, any buffer credits not used are credited back to - * the transaction, so that at all times we know how many buffers the - * outstanding updates on a transaction might possibly touch. - * - * This is an opaque datatype. - **/ -typedef struct handle_s handle_t; /* Atomic operation type */ - - -/** - * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem. - * - * journal_t is linked to from the fs superblock structure. - * - * We use the journal_t to keep track of all outstanding transaction - * activity on the filesystem, and to manage the state of the log - * writing process. - * - * This is an opaque datatype. - **/ -typedef struct journal_s journal_t; /* Journal control structure */ -#endif - -/* - * Internal structures used by the logging mechanism: - */ - -#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ - -/* - * On-disk structures - */ - -/* - * Descriptor block types: - */ - -#define JFS_DESCRIPTOR_BLOCK 1 -#define JFS_COMMIT_BLOCK 2 -#define JFS_SUPERBLOCK_V1 3 -#define JFS_SUPERBLOCK_V2 4 -#define JFS_REVOKE_BLOCK 5 - -/* - * Standard header for all descriptor blocks: - */ -typedef struct journal_header_s -{ - __be32 h_magic; - __be32 h_blocktype; - __be32 h_sequence; -} journal_header_t; - - -/* - * The block tag: used to describe a single buffer in the journal - */ -typedef struct journal_block_tag_s -{ - __be32 t_blocknr; /* The on-disk block number */ - __be32 t_flags; /* See below */ -} journal_block_tag_t; - -/* - * The revoke descriptor: used on disk to describe a series of blocks to - * be revoked from the log - */ -typedef struct journal_revoke_header_s -{ - journal_header_t r_header; - __be32 r_count; /* Count of bytes used in the block */ -} journal_revoke_header_t; - - -/* Definitions for the journal tag flags word: */ -#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ -#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ -#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ -#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ - - -/* - * The journal superblock. All fields are in big-endian byte order. - */ -typedef struct journal_superblock_s -{ -/* 0x0000 */ - journal_header_t s_header; - -/* 0x000C */ - /* Static information describing the journal */ - __be32 s_blocksize; /* journal device blocksize */ - __be32 s_maxlen; /* total blocks in journal file */ - __be32 s_first; /* first block of log information */ - -/* 0x0018 */ - /* Dynamic information describing the current state of the log */ - __be32 s_sequence; /* first commit ID expected in log */ - __be32 s_start; /* blocknr of start of log */ - -/* 0x0020 */ - /* Error value, as set by journal_abort(). */ - __be32 s_errno; - -/* 0x0024 */ - /* Remaining fields are only valid in a version-2 superblock */ - __be32 s_feature_compat; /* compatible feature set */ - __be32 s_feature_incompat; /* incompatible feature set */ - __be32 s_feature_ro_compat; /* readonly-compatible feature set */ -/* 0x0030 */ - __u8 s_uuid[16]; /* 128-bit uuid for journal */ - -/* 0x0040 */ - __be32 s_nr_users; /* Nr of filesystems sharing log */ - - __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ - -/* 0x0048 */ - __be32 s_max_transaction; /* Limit of journal blocks per trans.*/ - __be32 s_max_trans_data; /* Limit of data blocks per trans. */ - -/* 0x0050 */ - __u32 s_padding[44]; - -/* 0x0100 */ - __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ -/* 0x0400 */ -} journal_superblock_t; - -#define JFS_HAS_COMPAT_FEATURE(j,mask) \ - ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask)))) -#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \ - ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask)))) -#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \ - ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) - -#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001 - -/* Features known to this kernel version: */ -#define JFS_KNOWN_COMPAT_FEATURES 0 -#define JFS_KNOWN_ROCOMPAT_FEATURES 0 -#define JFS_KNOWN_INCOMPAT_FEATURES JFS_FEATURE_INCOMPAT_REVOKE - -#ifdef __KERNEL__ - -#include -#include - -enum jbd_state_bits { - BH_JBD /* Has an attached ext3 journal_head */ - = BH_PrivateStart, - BH_JWrite, /* Being written to log (@@@ DEBUGGING) */ - BH_Freed, /* Has been freed (truncated) */ - BH_Revoked, /* Has been revoked from the log */ - BH_RevokeValid, /* Revoked flag is valid */ - BH_JBDDirty, /* Is dirty but journaled */ - BH_State, /* Pins most journal_head state */ - BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ - BH_Unshadow, /* Dummy bit, for BJ_Shadow wakeup filtering */ - BH_JBDPrivateStart, /* First bit available for private use by FS */ -}; - -BUFFER_FNS(JBD, jbd) -BUFFER_FNS(JWrite, jwrite) -BUFFER_FNS(JBDDirty, jbddirty) -TAS_BUFFER_FNS(JBDDirty, jbddirty) -BUFFER_FNS(Revoked, revoked) -TAS_BUFFER_FNS(Revoked, revoked) -BUFFER_FNS(RevokeValid, revokevalid) -TAS_BUFFER_FNS(RevokeValid, revokevalid) -BUFFER_FNS(Freed, freed) - -#include - -#define J_ASSERT(assert) BUG_ON(!(assert)) - -#define J_ASSERT_BH(bh, expr) J_ASSERT(expr) -#define J_ASSERT_JH(jh, expr) J_ASSERT(expr) - -#if defined(JBD_PARANOID_IOFAIL) -#define J_EXPECT(expr, why...) J_ASSERT(expr) -#define J_EXPECT_BH(bh, expr, why...) J_ASSERT_BH(bh, expr) -#define J_EXPECT_JH(jh, expr, why...) J_ASSERT_JH(jh, expr) -#else -#define __journal_expect(expr, why...) \ - ({ \ - int val = (expr); \ - if (!val) { \ - printk(KERN_ERR \ - "EXT3-fs unexpected failure: %s;\n",# expr); \ - printk(KERN_ERR why "\n"); \ - } \ - val; \ - }) -#define J_EXPECT(expr, why...) __journal_expect(expr, ## why) -#define J_EXPECT_BH(bh, expr, why...) __journal_expect(expr, ## why) -#define J_EXPECT_JH(jh, expr, why...) __journal_expect(expr, ## why) -#endif - -struct jbd_revoke_table_s; - -/** - * struct handle_s - this is the concrete type associated with handle_t. - * @h_transaction: Which compound transaction is this update a part of? - * @h_buffer_credits: Number of remaining buffers we are allowed to dirty. - * @h_ref: Reference count on this handle - * @h_err: Field for caller's use to track errors through large fs operations - * @h_sync: flag for sync-on-close - * @h_jdata: flag to force data journaling - * @h_aborted: flag indicating fatal error on handle - * @h_lockdep_map: lockdep info for debugging lock problems - */ -struct handle_s -{ - /* Which compound transaction is this update a part of? */ - transaction_t *h_transaction; - - /* Number of remaining buffers we are allowed to dirty: */ - int h_buffer_credits; - - /* Reference count on this handle */ - int h_ref; - - /* Field for caller's use to track errors through large fs */ - /* operations */ - int h_err; - - /* Flags [no locking] */ - unsigned int h_sync: 1; /* sync-on-close */ - unsigned int h_jdata: 1; /* force data journaling */ - unsigned int h_aborted: 1; /* fatal error on handle */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map h_lockdep_map; -#endif -}; - - -/* The transaction_t type is the guts of the journaling mechanism. It - * tracks a compound transaction through its various states: - * - * RUNNING: accepting new updates - * LOCKED: Updates still running but we don't accept new ones - * RUNDOWN: Updates are tidying up but have finished requesting - * new buffers to modify (state not used for now) - * FLUSH: All updates complete, but we are still writing to disk - * COMMIT: All data on disk, writing commit record - * FINISHED: We still have to keep the transaction for checkpointing. - * - * The transaction keeps track of all of the buffers modified by a - * running transaction, and all of the buffers committed but not yet - * flushed to home for finished transactions. - */ - -/* - * Lock ranking: - * - * j_list_lock - * ->jbd_lock_bh_journal_head() (This is "innermost") - * - * j_state_lock - * ->jbd_lock_bh_state() - * - * jbd_lock_bh_state() - * ->j_list_lock - * - * j_state_lock - * ->t_handle_lock - * - * j_state_lock - * ->j_list_lock (journal_unmap_buffer) - * - */ - -struct transaction_s -{ - /* Pointer to the journal for this transaction. [no locking] */ - journal_t *t_journal; - - /* Sequence number for this transaction [no locking] */ - tid_t t_tid; - - /* - * Transaction's current state - * [no locking - only kjournald alters this] - * [j_list_lock] guards transition of a transaction into T_FINISHED - * state and subsequent call of __journal_drop_transaction() - * FIXME: needs barriers - * KLUDGE: [use j_state_lock] - */ - enum { - T_RUNNING, - T_LOCKED, - T_FLUSH, - T_COMMIT, - T_COMMIT_RECORD, - T_FINISHED - } t_state; - - /* - * Where in the log does this transaction's commit start? [no locking] - */ - unsigned int t_log_start; - - /* Number of buffers on the t_buffers list [j_list_lock] */ - int t_nr_buffers; - - /* - * Doubly-linked circular list of all buffers reserved but not yet - * modified by this transaction [j_list_lock] - */ - struct journal_head *t_reserved_list; - - /* - * Doubly-linked circular list of all buffers under writeout during - * commit [j_list_lock] - */ - struct journal_head *t_locked_list; - - /* - * Doubly-linked circular list of all metadata buffers owned by this - * transaction [j_list_lock] - */ - struct journal_head *t_buffers; - - /* - * Doubly-linked circular list of all data buffers still to be - * flushed before this transaction can be committed [j_list_lock] - */ - struct journal_head *t_sync_datalist; - - /* - * Doubly-linked circular list of all forget buffers (superseded - * buffers which we can un-checkpoint once this transaction commits) - * [j_list_lock] - */ - struct journal_head *t_forget; - - /* - * Doubly-linked circular list of all buffers still to be flushed before - * this transaction can be checkpointed. [j_list_lock] - */ - struct journal_head *t_checkpoint_list; - - /* - * Doubly-linked circular list of all buffers submitted for IO while - * checkpointing. [j_list_lock] - */ - struct journal_head *t_checkpoint_io_list; - - /* - * Doubly-linked circular list of temporary buffers currently undergoing - * IO in the log [j_list_lock] - */ - struct journal_head *t_iobuf_list; - - /* - * Doubly-linked circular list of metadata buffers being shadowed by log - * IO. The IO buffers on the iobuf list and the shadow buffers on this - * list match each other one for one at all times. [j_list_lock] - */ - struct journal_head *t_shadow_list; - - /* - * Doubly-linked circular list of control buffers being written to the - * log. [j_list_lock] - */ - struct journal_head *t_log_list; - - /* - * Protects info related to handles - */ - spinlock_t t_handle_lock; - - /* - * Number of outstanding updates running on this transaction - * [t_handle_lock] - */ - int t_updates; - - /* - * Number of buffers reserved for use by all handles in this transaction - * handle but not yet modified. [t_handle_lock] - */ - int t_outstanding_credits; - - /* - * Forward and backward links for the circular list of all transactions - * awaiting checkpoint. [j_list_lock] - */ - transaction_t *t_cpnext, *t_cpprev; - - /* - * When will the transaction expire (become due for commit), in jiffies? - * [no locking] - */ - unsigned long t_expires; - - /* - * When this transaction started, in nanoseconds [no locking] - */ - ktime_t t_start_time; - - /* - * How many handles used this transaction? [t_handle_lock] - */ - int t_handle_count; -}; - -/** - * struct journal_s - this is the concrete type associated with journal_t. - * @j_flags: General journaling state flags - * @j_errno: Is there an outstanding uncleared error on the journal (from a - * prior abort)? - * @j_sb_buffer: First part of superblock buffer - * @j_superblock: Second part of superblock buffer - * @j_format_version: Version of the superblock format - * @j_state_lock: Protect the various scalars in the journal - * @j_barrier_count: Number of processes waiting to create a barrier lock - * @j_running_transaction: The current running transaction.. - * @j_committing_transaction: the transaction we are pushing to disk - * @j_checkpoint_transactions: a linked circular list of all transactions - * waiting for checkpointing - * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction - * to start committing, or for a barrier lock to be released - * @j_wait_logspace: Wait queue for waiting for checkpointing to complete - * @j_wait_done_commit: Wait queue for waiting for commit to complete - * @j_wait_checkpoint: Wait queue to trigger checkpointing - * @j_wait_commit: Wait queue to trigger commit - * @j_wait_updates: Wait queue to wait for updates to complete - * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints - * @j_head: Journal head - identifies the first unused block in the journal - * @j_tail: Journal tail - identifies the oldest still-used block in the - * journal. - * @j_free: Journal free - how many free blocks are there in the journal? - * @j_first: The block number of the first usable block - * @j_last: The block number one beyond the last usable block - * @j_dev: Device where we store the journal - * @j_blocksize: blocksize for the location where we store the journal. - * @j_blk_offset: starting block offset for into the device where we store the - * journal - * @j_fs_dev: Device which holds the client fs. For internal journal this will - * be equal to j_dev - * @j_maxlen: Total maximum capacity of the journal region on disk. - * @j_list_lock: Protects the buffer lists and internal buffer state. - * @j_inode: Optional inode where we store the journal. If present, all journal - * block numbers are mapped into this inode via bmap(). - * @j_tail_sequence: Sequence number of the oldest transaction in the log - * @j_transaction_sequence: Sequence number of the next transaction to grant - * @j_commit_sequence: Sequence number of the most recently committed - * transaction - * @j_commit_request: Sequence number of the most recent transaction wanting - * commit - * @j_commit_waited: Sequence number of the most recent transaction someone - * is waiting for to commit. - * @j_uuid: Uuid of client object. - * @j_task: Pointer to the current commit thread for this journal - * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a - * single compound commit transaction - * @j_commit_interval: What is the maximum transaction lifetime before we begin - * a commit? - * @j_commit_timer: The timer used to wakeup the commit thread - * @j_revoke_lock: Protect the revoke table - * @j_revoke: The revoke table - maintains the list of revoked blocks in the - * current transaction. - * @j_revoke_table: alternate revoke tables for j_revoke - * @j_wbuf: array of buffer_heads for journal_commit_transaction - * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the - * number that will fit in j_blocksize - * @j_last_sync_writer: most recent pid which did a synchronous write - * @j_average_commit_time: the average amount of time in nanoseconds it - * takes to commit a transaction to the disk. - * @j_private: An opaque pointer to fs-private information. - */ - -struct journal_s -{ - /* General journaling state flags [j_state_lock] */ - unsigned long j_flags; - - /* - * Is there an outstanding uncleared error on the journal (from a prior - * abort)? [j_state_lock] - */ - int j_errno; - - /* The superblock buffer */ - struct buffer_head *j_sb_buffer; - journal_superblock_t *j_superblock; - - /* Version of the superblock format */ - int j_format_version; - - /* - * Protect the various scalars in the journal - */ - spinlock_t j_state_lock; - - /* - * Number of processes waiting to create a barrier lock [j_state_lock] - */ - int j_barrier_count; - - /* - * Transactions: The current running transaction... - * [j_state_lock] [caller holding open handle] - */ - transaction_t *j_running_transaction; - - /* - * the transaction we are pushing to disk - * [j_state_lock] [caller holding open handle] - */ - transaction_t *j_committing_transaction; - - /* - * ... and a linked circular list of all transactions waiting for - * checkpointing. [j_list_lock] - */ - transaction_t *j_checkpoint_transactions; - - /* - * Wait queue for waiting for a locked transaction to start committing, - * or for a barrier lock to be released - */ - wait_queue_head_t j_wait_transaction_locked; - - /* Wait queue for waiting for checkpointing to complete */ - wait_queue_head_t j_wait_logspace; - - /* Wait queue for waiting for commit to complete */ - wait_queue_head_t j_wait_done_commit; - - /* Wait queue to trigger checkpointing */ - wait_queue_head_t j_wait_checkpoint; - - /* Wait queue to trigger commit */ - wait_queue_head_t j_wait_commit; - - /* Wait queue to wait for updates to complete */ - wait_queue_head_t j_wait_updates; - - /* Semaphore for locking against concurrent checkpoints */ - struct mutex j_checkpoint_mutex; - - /* - * Journal head: identifies the first unused block in the journal. - * [j_state_lock] - */ - unsigned int j_head; - - /* - * Journal tail: identifies the oldest still-used block in the journal. - * [j_state_lock] - */ - unsigned int j_tail; - - /* - * Journal free: how many free blocks are there in the journal? - * [j_state_lock] - */ - unsigned int j_free; - - /* - * Journal start and end: the block numbers of the first usable block - * and one beyond the last usable block in the journal. [j_state_lock] - */ - unsigned int j_first; - unsigned int j_last; - - /* - * Device, blocksize and starting block offset for the location where we - * store the journal. - */ - struct block_device *j_dev; - int j_blocksize; - unsigned int j_blk_offset; - - /* - * Device which holds the client fs. For internal journal this will be - * equal to j_dev. - */ - struct block_device *j_fs_dev; - - /* Total maximum capacity of the journal region on disk. */ - unsigned int j_maxlen; - - /* - * Protects the buffer lists and internal buffer state. - */ - spinlock_t j_list_lock; - - /* Optional inode where we store the journal. If present, all */ - /* journal block numbers are mapped into this inode via */ - /* bmap(). */ - struct inode *j_inode; - - /* - * Sequence number of the oldest transaction in the log [j_state_lock] - */ - tid_t j_tail_sequence; - - /* - * Sequence number of the next transaction to grant [j_state_lock] - */ - tid_t j_transaction_sequence; - - /* - * Sequence number of the most recently committed transaction - * [j_state_lock]. - */ - tid_t j_commit_sequence; - - /* - * Sequence number of the most recent transaction wanting commit - * [j_state_lock] - */ - tid_t j_commit_request; - - /* - * Sequence number of the most recent transaction someone is waiting - * for to commit. - * [j_state_lock] - */ - tid_t j_commit_waited; - - /* - * Journal uuid: identifies the object (filesystem, LVM volume etc) - * backed by this journal. This will eventually be replaced by an array - * of uuids, allowing us to index multiple devices within a single - * journal and to perform atomic updates across them. - */ - __u8 j_uuid[16]; - - /* Pointer to the current commit thread for this journal */ - struct task_struct *j_task; - - /* - * Maximum number of metadata buffers to allow in a single compound - * commit transaction - */ - int j_max_transaction_buffers; - - /* - * What is the maximum transaction lifetime before we begin a commit? - */ - unsigned long j_commit_interval; - - /* The timer used to wakeup the commit thread: */ - struct timer_list j_commit_timer; - - /* - * The revoke table: maintains the list of revoked blocks in the - * current transaction. [j_revoke_lock] - */ - spinlock_t j_revoke_lock; - struct jbd_revoke_table_s *j_revoke; - struct jbd_revoke_table_s *j_revoke_table[2]; - - /* - * array of bhs for journal_commit_transaction - */ - struct buffer_head **j_wbuf; - int j_wbufsize; - - /* - * this is the pid of the last person to run a synchronous operation - * through the journal. - */ - pid_t j_last_sync_writer; - - /* - * the average amount of time in nanoseconds it takes to commit a - * transaction to the disk. [j_state_lock] - */ - u64 j_average_commit_time; - - /* - * An opaque pointer to fs-private information. ext3 puts its - * superblock pointer here - */ - void *j_private; -}; - -/* - * Journal flag definitions - */ -#define JFS_UNMOUNT 0x001 /* Journal thread is being destroyed */ -#define JFS_ABORT 0x002 /* Journaling has been aborted for errors. */ -#define JFS_ACK_ERR 0x004 /* The errno in the sb has been acked */ -#define JFS_FLUSHED 0x008 /* The journal superblock has been flushed */ -#define JFS_LOADED 0x010 /* The journal superblock has been loaded */ -#define JFS_BARRIER 0x020 /* Use IDE barriers */ -#define JFS_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file - * data write error in ordered - * mode */ - -/* - * Function declarations for the journaling transaction and buffer - * management - */ - -/* Filing buffers */ -extern void journal_unfile_buffer(journal_t *, struct journal_head *); -extern void __journal_unfile_buffer(struct journal_head *); -extern void __journal_refile_buffer(struct journal_head *); -extern void journal_refile_buffer(journal_t *, struct journal_head *); -extern void __journal_file_buffer(struct journal_head *, transaction_t *, int); -extern void __journal_free_buffer(struct journal_head *bh); -extern void journal_file_buffer(struct journal_head *, transaction_t *, int); -extern void __journal_clean_data_list(transaction_t *transaction); - -/* Log buffer allocation */ -extern struct journal_head * journal_get_descriptor_buffer(journal_t *); -int journal_next_log_block(journal_t *, unsigned int *); - -/* Commit management */ -extern void journal_commit_transaction(journal_t *); - -/* Checkpoint list management */ -int __journal_clean_checkpoint_list(journal_t *journal); -int __journal_remove_checkpoint(struct journal_head *); -void __journal_insert_checkpoint(struct journal_head *, transaction_t *); - -/* Buffer IO */ -extern int -journal_write_metadata_buffer(transaction_t *transaction, - struct journal_head *jh_in, - struct journal_head **jh_out, - unsigned int blocknr); - -/* Transaction locking */ -extern void __wait_on_journal (journal_t *); - -/* - * Journal locking. - * - * We need to lock the journal during transaction state changes so that nobody - * ever tries to take a handle on the running transaction while we are in the - * middle of moving it to the commit phase. j_state_lock does this. - * - * Note that the locking is completely interrupt unsafe. We never touch - * journal structures from interrupts. - */ - -static inline handle_t *journal_current_handle(void) -{ - return current->journal_info; -} - -/* The journaling code user interface: - * - * Create and destroy handles - * Register buffer modifications against the current transaction. - */ - -extern handle_t *journal_start(journal_t *, int nblocks); -extern int journal_restart (handle_t *, int nblocks); -extern int journal_extend (handle_t *, int nblocks); -extern int journal_get_write_access(handle_t *, struct buffer_head *); -extern int journal_get_create_access (handle_t *, struct buffer_head *); -extern int journal_get_undo_access(handle_t *, struct buffer_head *); -extern int journal_dirty_data (handle_t *, struct buffer_head *); -extern int journal_dirty_metadata (handle_t *, struct buffer_head *); -extern void journal_release_buffer (handle_t *, struct buffer_head *); -extern int journal_forget (handle_t *, struct buffer_head *); -extern void journal_sync_buffer (struct buffer_head *); -extern void journal_invalidatepage(journal_t *, - struct page *, unsigned int, unsigned int); -extern int journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); -extern int journal_stop(handle_t *); -extern int journal_flush (journal_t *); -extern void journal_lock_updates (journal_t *); -extern void journal_unlock_updates (journal_t *); - -extern journal_t * journal_init_dev(struct block_device *bdev, - struct block_device *fs_dev, - int start, int len, int bsize); -extern journal_t * journal_init_inode (struct inode *); -extern int journal_update_format (journal_t *); -extern int journal_check_used_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_check_available_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_set_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern int journal_create (journal_t *); -extern int journal_load (journal_t *journal); -extern int journal_destroy (journal_t *); -extern int journal_recover (journal_t *journal); -extern int journal_wipe (journal_t *, int); -extern int journal_skip_recovery (journal_t *); -extern void journal_update_sb_log_tail (journal_t *, tid_t, unsigned int, - int); -extern void journal_abort (journal_t *, int); -extern int journal_errno (journal_t *); -extern void journal_ack_err (journal_t *); -extern int journal_clear_err (journal_t *); -extern int journal_bmap(journal_t *, unsigned int, unsigned int *); -extern int journal_force_commit(journal_t *); - -/* - * journal_head management - */ -struct journal_head *journal_add_journal_head(struct buffer_head *bh); -struct journal_head *journal_grab_journal_head(struct buffer_head *bh); -void journal_put_journal_head(struct journal_head *jh); - -/* - * handle management - */ -extern struct kmem_cache *jbd_handle_cache; - -static inline handle_t *jbd_alloc_handle(gfp_t gfp_flags) -{ - return kmem_cache_zalloc(jbd_handle_cache, gfp_flags); -} - -static inline void jbd_free_handle(handle_t *handle) -{ - kmem_cache_free(jbd_handle_cache, handle); -} - -/* Primary revoke support */ -#define JOURNAL_REVOKE_DEFAULT_HASH 256 -extern int journal_init_revoke(journal_t *, int); -extern void journal_destroy_revoke_caches(void); -extern int journal_init_revoke_caches(void); - -extern void journal_destroy_revoke(journal_t *); -extern int journal_revoke (handle_t *, - unsigned int, struct buffer_head *); -extern int journal_cancel_revoke(handle_t *, struct journal_head *); -extern void journal_write_revoke_records(journal_t *, - transaction_t *, int); - -/* Recovery revoke support */ -extern int journal_set_revoke(journal_t *, unsigned int, tid_t); -extern int journal_test_revoke(journal_t *, unsigned int, tid_t); -extern void journal_clear_revoke(journal_t *); -extern void journal_switch_revoke_table(journal_t *journal); -extern void journal_clear_buffer_revoked_flags(journal_t *journal); - -/* - * The log thread user interface: - * - * Request space in the current transaction, and force transaction commit - * transitions on demand. - */ - -int __log_space_left(journal_t *); /* Called with journal locked */ -int log_start_commit(journal_t *journal, tid_t tid); -int __log_start_commit(journal_t *journal, tid_t tid); -int journal_start_commit(journal_t *journal, tid_t *tid); -int journal_force_commit_nested(journal_t *journal); -int log_wait_commit(journal_t *journal, tid_t tid); -int log_do_checkpoint(journal_t *journal); -int journal_trans_will_send_data_barrier(journal_t *journal, tid_t tid); - -void __log_wait_for_space(journal_t *journal); -extern void __journal_drop_transaction(journal_t *, transaction_t *); -extern int cleanup_journal_tail(journal_t *); - -/* - * is_journal_abort - * - * Simple test wrapper function to test the JFS_ABORT state flag. This - * bit, when set, indicates that we have had a fatal error somewhere, - * either inside the journaling layer or indicated to us by the client - * (eg. ext3), and that we and should not commit any further - * transactions. - */ - -static inline int is_journal_aborted(journal_t *journal) -{ - return journal->j_flags & JFS_ABORT; -} - -static inline int is_handle_aborted(handle_t *handle) -{ - if (handle->h_aborted) - return 1; - return is_journal_aborted(handle->h_transaction->t_journal); -} - -static inline void journal_abort_handle(handle_t *handle) -{ - handle->h_aborted = 1; -} - -#endif /* __KERNEL__ */ - -/* Comparison functions for transaction IDs: perform comparisons using - * modulo arithmetic so that they work over sequence number wraps. */ - -static inline int tid_gt(tid_t x, tid_t y) -{ - int difference = (x - y); - return (difference > 0); -} - -static inline int tid_geq(tid_t x, tid_t y) -{ - int difference = (x - y); - return (difference >= 0); -} - -extern int journal_blocks_per_page(struct inode *inode); - -/* - * Return the minimum number of blocks which must be free in the journal - * before a new transaction may be started. Must be called under j_state_lock. - */ -static inline int jbd_space_needed(journal_t *journal) -{ - int nblocks = journal->j_max_transaction_buffers; - if (journal->j_committing_transaction) - nblocks += journal->j_committing_transaction-> - t_outstanding_credits; - return nblocks; -} - -/* - * Definitions which augment the buffer_head layer - */ - -/* journaling buffer types */ -#define BJ_None 0 /* Not journaled */ -#define BJ_SyncData 1 /* Normal data: flush before commit */ -#define BJ_Metadata 2 /* Normal journaled metadata */ -#define BJ_Forget 3 /* Buffer superseded by this transaction */ -#define BJ_IO 4 /* Buffer is for temporary IO use */ -#define BJ_Shadow 5 /* Buffer contents being shadowed to the log */ -#define BJ_LogCtl 6 /* Buffer contains log descriptors */ -#define BJ_Reserved 7 /* Buffer is reserved for access by journal */ -#define BJ_Locked 8 /* Locked for I/O during commit */ -#define BJ_Types 9 - -extern int jbd_blocks_per_page(struct inode *inode); - -#ifdef __KERNEL__ - -#define buffer_trace_init(bh) do {} while (0) -#define print_buffer_fields(bh) do {} while (0) -#define print_buffer_trace(bh) do {} while (0) -#define BUFFER_TRACE(bh, info) do {} while (0) -#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) -#define JBUFFER_TRACE(jh, info) do {} while (0) - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_JBD_H */ diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h index edb640ae9a948..ad4b28647298a 100644 --- a/include/linux/jbd2.h +++ b/include/linux/jbd2.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #endif @@ -336,7 +337,45 @@ BUFFER_FNS(Freed, freed) BUFFER_FNS(Shadow, shadow) BUFFER_FNS(Verified, verified) -#include +static inline struct buffer_head *jh2bh(struct journal_head *jh) +{ + return jh->b_bh; +} + +static inline struct journal_head *bh2jh(struct buffer_head *bh) +{ + return bh->b_private; +} + +static inline void jbd_lock_bh_state(struct buffer_head *bh) +{ + bit_spin_lock(BH_State, &bh->b_state); +} + +static inline int jbd_trylock_bh_state(struct buffer_head *bh) +{ + return bit_spin_trylock(BH_State, &bh->b_state); +} + +static inline int jbd_is_locked_bh_state(struct buffer_head *bh) +{ + return bit_spin_is_locked(BH_State, &bh->b_state); +} + +static inline void jbd_unlock_bh_state(struct buffer_head *bh) +{ + bit_spin_unlock(BH_State, &bh->b_state); +} + +static inline void jbd_lock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_lock(BH_JournalHead, &bh->b_state); +} + +static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) +{ + bit_spin_unlock(BH_JournalHead, &bh->b_state); +} #define J_ASSERT(assert) BUG_ON(!(assert)) diff --git a/include/linux/jbd_common.h b/include/linux/jbd_common.h deleted file mode 100644 index 3dc53432355f5..0000000000000 --- a/include/linux/jbd_common.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _LINUX_JBD_STATE_H -#define _LINUX_JBD_STATE_H - -#include - -static inline struct buffer_head *jh2bh(struct journal_head *jh) -{ - return jh->b_bh; -} - -static inline struct journal_head *bh2jh(struct buffer_head *bh) -{ - return bh->b_private; -} - -static inline void jbd_lock_bh_state(struct buffer_head *bh) -{ - bit_spin_lock(BH_State, &bh->b_state); -} - -static inline int jbd_trylock_bh_state(struct buffer_head *bh) -{ - return bit_spin_trylock(BH_State, &bh->b_state); -} - -static inline int jbd_is_locked_bh_state(struct buffer_head *bh) -{ - return bit_spin_is_locked(BH_State, &bh->b_state); -} - -static inline void jbd_unlock_bh_state(struct buffer_head *bh) -{ - bit_spin_unlock(BH_State, &bh->b_state); -} - -static inline void jbd_lock_bh_journal_head(struct buffer_head *bh) -{ - bit_spin_lock(BH_JournalHead, &bh->b_state); -} - -static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) -{ - bit_spin_unlock(BH_JournalHead, &bh->b_state); -} - -#endif diff --git a/include/trace/events/ext3.h b/include/trace/events/ext3.h deleted file mode 100644 index fc733d28117a4..0000000000000 --- a/include/trace/events/ext3.h +++ /dev/null @@ -1,866 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM ext3 - -#if !defined(_TRACE_EXT3_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_EXT3_H - -#include - -TRACE_EVENT(ext3_free_inode, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( umode_t, mode ) - __field( uid_t, uid ) - __field( gid_t, gid ) - __field( blkcnt_t, blocks ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->mode = inode->i_mode; - __entry->uid = i_uid_read(inode); - __entry->gid = i_gid_read(inode); - __entry->blocks = inode->i_blocks; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->uid, __entry->gid, - (unsigned long) __entry->blocks) -); - -TRACE_EVENT(ext3_request_inode, - TP_PROTO(struct inode *dir, int mode), - - TP_ARGS(dir, mode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, dir ) - __field( umode_t, mode ) - ), - - TP_fast_assign( - __entry->dev = dir->i_sb->s_dev; - __entry->dir = dir->i_ino; - __entry->mode = mode; - ), - - TP_printk("dev %d,%d dir %lu mode 0%o", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->dir, __entry->mode) -); - -TRACE_EVENT(ext3_allocate_inode, - TP_PROTO(struct inode *inode, struct inode *dir, int mode), - - TP_ARGS(inode, dir, mode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ino_t, dir ) - __field( umode_t, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->dir = dir->i_ino; - __entry->mode = mode; - ), - - TP_printk("dev %d,%d ino %lu dir %lu mode 0%o", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long) __entry->dir, __entry->mode) -); - -TRACE_EVENT(ext3_evict_inode, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, nlink ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->nlink = inode->i_nlink; - ), - - TP_printk("dev %d,%d ino %lu nlink %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->nlink) -); - -TRACE_EVENT(ext3_drop_inode, - TP_PROTO(struct inode *inode, int drop), - - TP_ARGS(inode, drop), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, drop ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->drop = drop; - ), - - TP_printk("dev %d,%d ino %lu drop %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->drop) -); - -TRACE_EVENT(ext3_mark_inode_dirty, - TP_PROTO(struct inode *inode, unsigned long IP), - - TP_ARGS(inode, IP), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field(unsigned long, ip ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->ip = IP; - ), - - TP_printk("dev %d,%d ino %lu caller %pS", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, (void *)__entry->ip) -); - -TRACE_EVENT(ext3_write_begin, - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int flags), - - TP_ARGS(inode, pos, len, flags), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned int, len ) - __field( unsigned int, flags ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = pos; - __entry->len = len; - __entry->flags = flags; - ), - - TP_printk("dev %d,%d ino %lu pos %llu len %u flags %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long long) __entry->pos, __entry->len, - __entry->flags) -); - -DECLARE_EVENT_CLASS(ext3__write_end, - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned int, len ) - __field( unsigned int, copied ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = pos; - __entry->len = len; - __entry->copied = copied; - ), - - TP_printk("dev %d,%d ino %lu pos %llu len %u copied %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long long) __entry->pos, __entry->len, - __entry->copied) -); - -DEFINE_EVENT(ext3__write_end, ext3_ordered_write_end, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied) -); - -DEFINE_EVENT(ext3__write_end, ext3_writeback_write_end, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied) -); - -DEFINE_EVENT(ext3__write_end, ext3_journalled_write_end, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied) -); - -DECLARE_EVENT_CLASS(ext3__page_op, - TP_PROTO(struct page *page), - - TP_ARGS(page), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( pgoff_t, index ) - - ), - - TP_fast_assign( - __entry->index = page->index; - __entry->ino = page->mapping->host->i_ino; - __entry->dev = page->mapping->host->i_sb->s_dev; - ), - - TP_printk("dev %d,%d ino %lu page_index %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->index) -); - -DEFINE_EVENT(ext3__page_op, ext3_ordered_writepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DEFINE_EVENT(ext3__page_op, ext3_writeback_writepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DEFINE_EVENT(ext3__page_op, ext3_journalled_writepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DEFINE_EVENT(ext3__page_op, ext3_readpage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DEFINE_EVENT(ext3__page_op, ext3_releasepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -TRACE_EVENT(ext3_invalidatepage, - TP_PROTO(struct page *page, unsigned int offset, unsigned int length), - - TP_ARGS(page, offset, length), - - TP_STRUCT__entry( - __field( pgoff_t, index ) - __field( unsigned int, offset ) - __field( unsigned int, length ) - __field( ino_t, ino ) - __field( dev_t, dev ) - - ), - - TP_fast_assign( - __entry->index = page->index; - __entry->offset = offset; - __entry->length = length; - __entry->ino = page->mapping->host->i_ino; - __entry->dev = page->mapping->host->i_sb->s_dev; - ), - - TP_printk("dev %d,%d ino %lu page_index %lu offset %u length %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->index, __entry->offset, __entry->length) -); - -TRACE_EVENT(ext3_discard_blocks, - TP_PROTO(struct super_block *sb, unsigned long blk, - unsigned long count), - - TP_ARGS(sb, blk, count), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, blk ) - __field( unsigned long, count ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->blk = blk; - __entry->count = count; - ), - - TP_printk("dev %d,%d blk %lu count %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->blk, __entry->count) -); - -TRACE_EVENT(ext3_request_blocks, - TP_PROTO(struct inode *inode, unsigned long goal, - unsigned long count), - - TP_ARGS(inode, goal, count), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( unsigned long, count ) - __field( unsigned long, goal ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->count = count; - __entry->goal = goal; - ), - - TP_printk("dev %d,%d ino %lu count %lu goal %lu ", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->count, __entry->goal) -); - -TRACE_EVENT(ext3_allocate_blocks, - TP_PROTO(struct inode *inode, unsigned long goal, - unsigned long count, unsigned long block), - - TP_ARGS(inode, goal, count, block), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( unsigned long, block ) - __field( unsigned long, count ) - __field( unsigned long, goal ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->block = block; - __entry->count = count; - __entry->goal = goal; - ), - - TP_printk("dev %d,%d ino %lu count %lu block %lu goal %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->count, __entry->block, - __entry->goal) -); - -TRACE_EVENT(ext3_free_blocks, - TP_PROTO(struct inode *inode, unsigned long block, - unsigned long count), - - TP_ARGS(inode, block, count), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( umode_t, mode ) - __field( unsigned long, block ) - __field( unsigned long, count ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->mode = inode->i_mode; - __entry->block = block; - __entry->count = count; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o block %lu count %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->block, __entry->count) -); - -TRACE_EVENT(ext3_sync_file_enter, - TP_PROTO(struct file *file, int datasync), - - TP_ARGS(file, datasync), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ino_t, parent ) - __field( int, datasync ) - ), - - TP_fast_assign( - struct dentry *dentry = file->f_path.dentry; - - __entry->dev = d_inode(dentry)->i_sb->s_dev; - __entry->ino = d_inode(dentry)->i_ino; - __entry->datasync = datasync; - __entry->parent = d_inode(dentry->d_parent)->i_ino; - ), - - TP_printk("dev %d,%d ino %lu parent %ld datasync %d ", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long) __entry->parent, __entry->datasync) -); - -TRACE_EVENT(ext3_sync_file_exit, - TP_PROTO(struct inode *inode, int ret), - - TP_ARGS(inode, ret), - - TP_STRUCT__entry( - __field( int, ret ) - __field( ino_t, ino ) - __field( dev_t, dev ) - ), - - TP_fast_assign( - __entry->ret = ret; - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - ), - - TP_printk("dev %d,%d ino %lu ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->ret) -); - -TRACE_EVENT(ext3_sync_fs, - TP_PROTO(struct super_block *sb, int wait), - - TP_ARGS(sb, wait), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, wait ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->wait = wait; - ), - - TP_printk("dev %d,%d wait %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->wait) -); - -TRACE_EVENT(ext3_rsv_window_add, - TP_PROTO(struct super_block *sb, - struct ext3_reserve_window_node *rsv_node), - - TP_ARGS(sb, rsv_node), - - TP_STRUCT__entry( - __field( unsigned long, start ) - __field( unsigned long, end ) - __field( dev_t, dev ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->start = rsv_node->rsv_window._rsv_start; - __entry->end = rsv_node->rsv_window._rsv_end; - ), - - TP_printk("dev %d,%d start %lu end %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->start, __entry->end) -); - -TRACE_EVENT(ext3_discard_reservation, - TP_PROTO(struct inode *inode, - struct ext3_reserve_window_node *rsv_node), - - TP_ARGS(inode, rsv_node), - - TP_STRUCT__entry( - __field( unsigned long, start ) - __field( unsigned long, end ) - __field( ino_t, ino ) - __field( dev_t, dev ) - ), - - TP_fast_assign( - __entry->start = rsv_node->rsv_window._rsv_start; - __entry->end = rsv_node->rsv_window._rsv_end; - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - ), - - TP_printk("dev %d,%d ino %lu start %lu end %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long)__entry->ino, __entry->start, - __entry->end) -); - -TRACE_EVENT(ext3_alloc_new_reservation, - TP_PROTO(struct super_block *sb, unsigned long goal), - - TP_ARGS(sb, goal), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, goal ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->goal = goal; - ), - - TP_printk("dev %d,%d goal %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->goal) -); - -TRACE_EVENT(ext3_reserved, - TP_PROTO(struct super_block *sb, unsigned long block, - struct ext3_reserve_window_node *rsv_node), - - TP_ARGS(sb, block, rsv_node), - - TP_STRUCT__entry( - __field( unsigned long, block ) - __field( unsigned long, start ) - __field( unsigned long, end ) - __field( dev_t, dev ) - ), - - TP_fast_assign( - __entry->block = block; - __entry->start = rsv_node->rsv_window._rsv_start; - __entry->end = rsv_node->rsv_window._rsv_end; - __entry->dev = sb->s_dev; - ), - - TP_printk("dev %d,%d block %lu, start %lu end %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->block, __entry->start, __entry->end) -); - -TRACE_EVENT(ext3_forget, - TP_PROTO(struct inode *inode, int is_metadata, unsigned long block), - - TP_ARGS(inode, is_metadata, block), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( umode_t, mode ) - __field( int, is_metadata ) - __field( unsigned long, block ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->mode = inode->i_mode; - __entry->is_metadata = is_metadata; - __entry->block = block; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o is_metadata %d block %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->is_metadata, __entry->block) -); - -TRACE_EVENT(ext3_read_block_bitmap, - TP_PROTO(struct super_block *sb, unsigned int group), - - TP_ARGS(sb, group), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( __u32, group ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->group = group; - ), - - TP_printk("dev %d,%d group %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->group) -); - -TRACE_EVENT(ext3_direct_IO_enter, - TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw), - - TP_ARGS(inode, offset, len, rw), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - __field( loff_t, pos ) - __field( unsigned long, len ) - __field( int, rw ) - ), - - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - __entry->pos = offset; - __entry->len = len; - __entry->rw = rw; - ), - - TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long long) __entry->pos, __entry->len, - __entry->rw) -); - -TRACE_EVENT(ext3_direct_IO_exit, - TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, - int rw, int ret), - - TP_ARGS(inode, offset, len, rw, ret), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - __field( loff_t, pos ) - __field( unsigned long, len ) - __field( int, rw ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - __entry->pos = offset; - __entry->len = len; - __entry->rw = rw; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu pos %llu len %lu rw %d ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long long) __entry->pos, __entry->len, - __entry->rw, __entry->ret) -); - -TRACE_EVENT(ext3_unlink_enter, - TP_PROTO(struct inode *parent, struct dentry *dentry), - - TP_ARGS(parent, dentry), - - TP_STRUCT__entry( - __field( ino_t, parent ) - __field( ino_t, ino ) - __field( loff_t, size ) - __field( dev_t, dev ) - ), - - TP_fast_assign( - __entry->parent = parent->i_ino; - __entry->ino = d_inode(dentry)->i_ino; - __entry->size = d_inode(dentry)->i_size; - __entry->dev = d_inode(dentry)->i_sb->s_dev; - ), - - TP_printk("dev %d,%d ino %lu size %lld parent %ld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long long)__entry->size, - (unsigned long) __entry->parent) -); - -TRACE_EVENT(ext3_unlink_exit, - TP_PROTO(struct dentry *dentry, int ret), - - TP_ARGS(dentry, ret), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->ino = d_inode(dentry)->i_ino; - __entry->dev = d_inode(dentry)->i_sb->s_dev; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->ret) -); - -DECLARE_EVENT_CLASS(ext3__truncate, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - __field( blkcnt_t, blocks ) - ), - - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - __entry->blocks = inode->i_blocks; - ), - - TP_printk("dev %d,%d ino %lu blocks %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, (unsigned long) __entry->blocks) -); - -DEFINE_EVENT(ext3__truncate, ext3_truncate_enter, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -DEFINE_EVENT(ext3__truncate, ext3_truncate_exit, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -TRACE_EVENT(ext3_get_blocks_enter, - TP_PROTO(struct inode *inode, unsigned long lblk, - unsigned long len, int create), - - TP_ARGS(inode, lblk, len, create), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - __field( unsigned long, lblk ) - __field( unsigned long, len ) - __field( int, create ) - ), - - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - __entry->lblk = lblk; - __entry->len = len; - __entry->create = create; - ), - - TP_printk("dev %d,%d ino %lu lblk %lu len %lu create %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->len, __entry->create) -); - -TRACE_EVENT(ext3_get_blocks_exit, - TP_PROTO(struct inode *inode, unsigned long lblk, - unsigned long pblk, unsigned long len, int ret), - - TP_ARGS(inode, lblk, pblk, len, ret), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - __field( unsigned long, lblk ) - __field( unsigned long, pblk ) - __field( unsigned long, len ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - __entry->lblk = lblk; - __entry->pblk = pblk; - __entry->len = len; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu lblk %lu pblk %lu len %lu ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->pblk, - __entry->len, __entry->ret) -); - -TRACE_EVENT(ext3_load_inode, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( ino_t, ino ) - __field( dev_t, dev ) - ), - - TP_fast_assign( - __entry->ino = inode->i_ino; - __entry->dev = inode->i_sb->s_dev; - ), - - TP_printk("dev %d,%d ino %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino) -); - -#endif /* _TRACE_EXT3_H */ - -/* This part must be outside protection */ -#include diff --git a/include/trace/events/jbd.h b/include/trace/events/jbd.h deleted file mode 100644 index da6f2591c25e1..0000000000000 --- a/include/trace/events/jbd.h +++ /dev/null @@ -1,194 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM jbd - -#if !defined(_TRACE_JBD_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_JBD_H - -#include -#include - -TRACE_EVENT(jbd_checkpoint, - - TP_PROTO(journal_t *journal, int result), - - TP_ARGS(journal, result), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, result ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->result = result; - ), - - TP_printk("dev %d,%d result %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->result) -); - -DECLARE_EVENT_CLASS(jbd_commit, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, transaction ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->transaction = commit_transaction->t_tid; - ), - - TP_printk("dev %d,%d transaction %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction) -); - -DEFINE_EVENT(jbd_commit, jbd_start_commit, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd_commit, jbd_commit_locking, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd_commit, jbd_commit_flushing, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd_commit, jbd_commit_logging, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -TRACE_EVENT(jbd_drop_transaction, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, transaction ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->transaction = commit_transaction->t_tid; - ), - - TP_printk("dev %d,%d transaction %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction) -); - -TRACE_EVENT(jbd_end_commit, - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, transaction ) - __field( int, head ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->transaction = commit_transaction->t_tid; - __entry->head = journal->j_tail_sequence; - ), - - TP_printk("dev %d,%d transaction %d head %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction, __entry->head) -); - -TRACE_EVENT(jbd_do_submit_data, - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, transaction ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->transaction = commit_transaction->t_tid; - ), - - TP_printk("dev %d,%d transaction %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction) -); - -TRACE_EVENT(jbd_cleanup_journal_tail, - - TP_PROTO(journal_t *journal, tid_t first_tid, - unsigned long block_nr, unsigned long freed), - - TP_ARGS(journal, first_tid, block_nr, freed), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( tid_t, tail_sequence ) - __field( tid_t, first_tid ) - __field(unsigned long, block_nr ) - __field(unsigned long, freed ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->tail_sequence = journal->j_tail_sequence; - __entry->first_tid = first_tid; - __entry->block_nr = block_nr; - __entry->freed = freed; - ), - - TP_printk("dev %d,%d from %u to %u offset %lu freed %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->tail_sequence, __entry->first_tid, - __entry->block_nr, __entry->freed) -); - -TRACE_EVENT(journal_write_superblock, - TP_PROTO(journal_t *journal, int write_op), - - TP_ARGS(journal, write_op), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, write_op ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->write_op = write_op; - ), - - TP_printk("dev %d,%d write_op %x", MAJOR(__entry->dev), - MINOR(__entry->dev), __entry->write_op) -); - -#endif /* _TRACE_JBD_H */ - -/* This part must be outside protection */ -#include -- GitLab From a3ad0a9da863fa554fc17fa8345a07adcdd27d3c Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 18 Jun 2015 17:19:14 +0200 Subject: [PATCH 1596/7006] block: Remove forced page bouncing under IO JBD layer wrote back data buffers without setting PageWriteback bit. Thus standard mechanism for guaranteeing stable pages under IO did not work. Since JBD is gone now and there is no other user of the functionality, just remove it. Acked-by: Jens Axboe Signed-off-by: Jan Kara --- block/bounce.c | 31 ++++--------------------------- include/linux/blk_types.h | 5 ++--- 2 files changed, 6 insertions(+), 30 deletions(-) diff --git a/block/bounce.c b/block/bounce.c index b17311227c127..31cad13a0c9d3 100644 --- a/block/bounce.c +++ b/block/bounce.c @@ -176,26 +176,8 @@ static void bounce_end_io_read_isa(struct bio *bio, int err) __bounce_end_io_read(bio, isa_page_pool, err); } -#ifdef CONFIG_NEED_BOUNCE_POOL -static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) -{ - if (bio_data_dir(bio) != WRITE) - return 0; - - if (!bdi_cap_stable_pages_required(&q->backing_dev_info)) - return 0; - - return test_bit(BIO_SNAP_STABLE, &bio->bi_flags); -} -#else -static int must_snapshot_stable_pages(struct request_queue *q, struct bio *bio) -{ - return 0; -} -#endif /* CONFIG_NEED_BOUNCE_POOL */ - static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, - mempool_t *pool, int force) + mempool_t *pool) { struct bio *bio; int rw = bio_data_dir(*bio_orig); @@ -203,8 +185,6 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig, struct bvec_iter iter; unsigned i; - if (force) - goto bounce; bio_for_each_segment(from, *bio_orig, iter) if (page_to_pfn(from.bv_page) > queue_bounce_pfn(q)) goto bounce; @@ -216,7 +196,7 @@ bounce: bio_for_each_segment_all(to, bio, i) { struct page *page = to->bv_page; - if (page_to_pfn(page) <= queue_bounce_pfn(q) && !force) + if (page_to_pfn(page) <= queue_bounce_pfn(q)) continue; to->bv_page = mempool_alloc(pool, q->bounce_gfp); @@ -254,7 +234,6 @@ bounce: void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) { - int must_bounce; mempool_t *pool; /* @@ -263,15 +242,13 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) if (!bio_has_data(*bio_orig)) return; - must_bounce = must_snapshot_stable_pages(q, *bio_orig); - /* * for non-isa bounce case, just check if the bounce pfn is equal * to or bigger than the highest pfn in the system -- in that case, * don't waste time iterating over bio segments */ if (!(q->bounce_gfp & GFP_DMA)) { - if (queue_bounce_pfn(q) >= blk_max_pfn && !must_bounce) + if (queue_bounce_pfn(q) >= blk_max_pfn) return; pool = page_pool; } else { @@ -282,7 +259,7 @@ void blk_queue_bounce(struct request_queue *q, struct bio **bio_orig) /* * slow path */ - __blk_queue_bounce(q, bio_orig, pool, must_bounce); + __blk_queue_bounce(q, bio_orig, pool); } EXPORT_SYMBOL(blk_queue_bounce); diff --git a/include/linux/blk_types.h b/include/linux/blk_types.h index 7303b3405520b..89fd49184b482 100644 --- a/include/linux/blk_types.h +++ b/include/linux/blk_types.h @@ -118,9 +118,8 @@ struct bio { #define BIO_USER_MAPPED 4 /* contains user pages */ #define BIO_NULL_MAPPED 5 /* contains invalid user pages */ #define BIO_QUIET 6 /* Make BIO Quiet */ -#define BIO_SNAP_STABLE 7 /* bio data must be snapshotted during write */ -#define BIO_CHAIN 8 /* chained bio, ->bi_remaining in effect */ -#define BIO_REFFED 9 /* bio has elevated ->bi_cnt */ +#define BIO_CHAIN 7 /* chained bio, ->bi_remaining in effect */ +#define BIO_REFFED 8 /* bio has elevated ->bi_cnt */ /* * Flags starting here get preserved by bio_reset() - this includes -- GitLab From c8962f4be4b47c2ff3b052c76007c6bbcb999c53 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Thu, 16 Jul 2015 11:20:02 +0200 Subject: [PATCH 1597/7006] ext4: Improve ext4 Kconfig test Now that ext4 driver must be used to access ext3 filesystems, improve the Kconfig help text to better explain that using ext4 driver to access the filesystem is fully compatible with the old ext3 driver. Acked-by: Theodore Ts'o Signed-off-by: Jan Kara --- fs/ext4/Kconfig | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig index 219a190ccae95..47728da7702cd 100644 --- a/fs/ext4/Kconfig +++ b/fs/ext4/Kconfig @@ -49,12 +49,13 @@ config EXT4_FS up fsck time. For more information, please see the web pages at http://ext4.wiki.kernel.org. - The ext4 filesystem will support mounting an ext3 - filesystem; while there will be some performance gains from - the delayed allocation and inode table readahead, the best - performance gains will require enabling ext4 features in the - filesystem, or formatting a new filesystem as an ext4 - filesystem initially. + The ext4 filesystem supports mounting an ext3 filesystem; while there + are some performance gains from the delayed allocation and inode + table readahead, the best performance gains require enabling ext4 + features in the filesystem using tune2fs, or formatting a new + filesystem as an ext4 filesystem initially. Without explicit enabling + of ext4 features, the on disk filesystem format stays fully backward + compatible. To compile this file system support as a module, choose M here. The module will be called ext4. -- GitLab From debeb29792f9bbb6b72ea2fc82088dc0fd9ec224 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Thu, 23 Jul 2015 13:18:06 +0200 Subject: [PATCH 1598/7006] mm/Kconfig: NEED_BOUNCE_POOL: clean-up condition commit 106542e7987c ("fs: Remove ext3 filesystem driver") removed ext3 and JBD, hence remove the superfluous condition. Signed-off-by: Valentin Rothberg Signed-off-by: Jan Kara --- mm/Kconfig | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mm/Kconfig b/mm/Kconfig index e79de2bd12cd0..d4e6495a720f4 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -299,15 +299,9 @@ config BOUNCE # On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often # have more than 4GB of memory, but we don't currently use the IOTLB to present # a 32-bit address to OHCI. So we need to use a bounce pool instead. -# -# We also use the bounce pool to provide stable page writes for jbd. jbd -# initiates buffer writeback without locking the page or setting PG_writeback, -# and fixing that behavior (a second time; jbd2 doesn't have this problem) is -# a major rework effort. Instead, use the bounce buffer to snapshot pages -# (until jbd goes away). The only jbd user is ext3. config NEED_BOUNCE_POOL bool - default y if (TILE && USB_OHCI_HCD) || (BLK_DEV_INTEGRITY && JBD) + default y if TILE && USB_OHCI_HCD config NR_QUICK int -- GitLab From eb87a05223293a915dc97e6966cbbb1baa43cd5f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:05 +0800 Subject: [PATCH 1599/7006] ACPICA: Parser: Reduce parser/namespace divergences for tracer support This patch reduces divergences in parser/namespace components so that the follow-up linuxized ACPICA upstream commits can be directly merged. Including the fix to an indent issue reported and fixed by Zhouyi Zhou. Signed-off-by: Lv Zheng Signed-off-by: Zhouyi Zhou Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/nsnames.c | 2 +- drivers/acpi/acpica/nsparse.c | 6 +++--- drivers/acpi/acpica/psloop.c | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index d293d97480363..2e37888f6abef 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -108,7 +108,7 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, if (index != 0) { ACPI_ERROR((AE_INFO, "Could not construct external pathname; index=%u, size=%u, Path=%s", - (u32) index, (u32) size, &name_buffer[size])); + (u32)index, (u32)size, &name_buffer[size])); return (AE_BAD_PARAMETER); } diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 57a4cfe547e49..9926a67ca6d71 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -70,7 +70,7 @@ acpi_ns_one_complete_parse(u32 pass_number, { union acpi_parse_object *parse_root; acpi_status status; - u32 aml_length; + u32 aml_length; u8 *aml_start; struct acpi_walk_state *walk_state; struct acpi_table_header *table; @@ -110,11 +110,11 @@ acpi_ns_one_complete_parse(u32 pass_number, if (table->length < sizeof(struct acpi_table_header)) { status = AE_BAD_HEADER; } else { - aml_start = (u8 *) table + sizeof(struct acpi_table_header); + aml_start = (u8 *)table + sizeof(struct acpi_table_header); aml_length = table->length - sizeof(struct acpi_table_header); status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, aml_start, aml_length, NULL, - (u8) pass_number); + (u8)pass_number); } /* Found OSDT table, enable the namespace override feature */ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 90437227d7909..6136458d65d23 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -126,9 +126,9 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && !walk_state->arg_count) { walk_state->aml_offset = - (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml, - walk_state->parser_state. - aml_start); + (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml, + walk_state->parser_state. + aml_start); status = acpi_ps_get_next_arg(walk_state, @@ -499,7 +499,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", - (u32) op->common.aml_opcode, + (u32)op->common.aml_opcode, walk_state->op_info->name, op, parser_state->aml, op->common.aml_offset)); -- GitLab From 83482f758b0d2d6a20a10be88399da44aa186aed Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:11 +0800 Subject: [PATCH 1600/7006] ACPICA: Parser: Cleanup aml_offset in struct acpi_walk_state ACPICA commit d254405814495058276c0c2f9d96794d15a6c91c This patch converts aml_offset in struct acpi_walk_state to AML address. AML offset is actually only used by the debugger, using AML address is more direct and efficient during the parsing stage so that we don't need to calculate it during the parsing stage. On the other hand, we can see several issues in the current parser logic around the aml_offset: 1. union acpi_operand_object.Common.aml_offset is redundantly assigned in acpi_ps_parse_loop(). 2. aml_offset is not an indication of the offset from the table header but the offset from the entry of a list of objects. Sometimes, it indicates an entry for a Method/Package/Buffer, which makes it difficult to be reversely calculated to a table header offset. 3. When being used with method tracers (for example, Linux function trace), it's better to have AML address logged instead of the AML offset because the address is the only attribute that can uniquely identify the opcode. This patch is required to solve the above issues. Lv Zheng. Link: https://github.com/acpica/acpica/commit/d2544058 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acstruct.h | 2 +- drivers/acpi/acpica/dsmethod.c | 9 +++++++-- drivers/acpi/acpica/psloop.c | 15 +++++++++------ drivers/acpi/acpica/psobject.c | 15 +++++++++------ 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h index 44997ca02ae26..f9992dced1f98 100644 --- a/drivers/acpi/acpica/acstruct.h +++ b/drivers/acpi/acpica/acstruct.h @@ -85,7 +85,7 @@ struct acpi_walk_state { u8 namespace_override; /* Override existing objects */ u8 result_size; /* Total elements for the result stack */ u8 result_count; /* Current number of occupied elements of result stack */ - u32 aml_offset; + u8 *aml; u32 arg_types; u32 method_breakpoint; /* For single stepping */ u32 user_breakpoint; /* User AML breakpoint */ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 85bb951430d96..bf8c16e379fbd 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -214,6 +214,8 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, acpi_status acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) { + u32 aml_offset; + ACPI_FUNCTION_ENTRY(); /* Ignore AE_OK and control exception codes */ @@ -234,13 +236,16 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) * Handler can map the exception code to anything it wants, including * AE_OK, in which case the executing method will not be aborted. */ + aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state->parser_state. + aml_start); + status = acpi_gbl_exception_handler(status, walk_state->method_node ? walk_state->method_node-> name.integer : 0, walk_state->opcode, - walk_state->aml_offset, - NULL); + aml_offset, NULL); acpi_ex_enter_interpreter(); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 6136458d65d23..ce66e73f1f60b 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -125,10 +125,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, */ while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) && !walk_state->arg_count) { - walk_state->aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml, - walk_state->parser_state. - aml_start); + walk_state->aml = walk_state->parser_state.aml; status = acpi_ps_get_next_arg(walk_state, @@ -140,7 +137,10 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, } if (arg) { - arg->common.aml_offset = walk_state->aml_offset; + arg->common.aml_offset = + (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state->parser_state. + aml_start); acpi_ps_append_arg(op, arg); } @@ -494,7 +494,10 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - op->common.aml_offset = walk_state->aml_offset; + op->common.aml_offset = + (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state->parser_state. + aml_start); if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 2f5ddd806c58b..6ba3bb7402a95 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -66,12 +66,11 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state); static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) { + u32 aml_offset; ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state); - walk_state->aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->parser_state.aml, - walk_state->parser_state.aml_start); + walk_state->aml = walk_state->parser_state.aml; walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state)); /* @@ -98,10 +97,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) /* The opcode is unrecognized. Complain and skip unknown opcodes */ if (walk_state->pass_number == 2) { + aml_offset = (u32)ACPI_PTR_DIFF(walk_state->aml, + walk_state-> + parser_state.aml_start); + ACPI_ERROR((AE_INFO, "Unknown opcode 0x%.2X at table offset 0x%.4X, ignoring", walk_state->opcode, - (u32)(walk_state->aml_offset + + (u32)(aml_offset + sizeof(struct acpi_table_header)))); ACPI_DUMP_BUFFER((walk_state->parser_state.aml - 16), @@ -115,14 +118,14 @@ static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state) acpi_os_printf ("/*\nError: Unknown opcode 0x%.2X at table offset 0x%.4X, context:\n", walk_state->opcode, - (u32)(walk_state->aml_offset + + (u32)(aml_offset + sizeof(struct acpi_table_header))); /* Dump the context surrounding the invalid opcode */ acpi_ut_dump_buffer(((u8 *)walk_state->parser_state. aml - 16), 48, DB_BYTE_DISPLAY, - (walk_state->aml_offset + + (aml_offset + sizeof(struct acpi_table_header) - 16)); acpi_os_printf(" */\n"); -- GitLab From 950a429cd21638b0c076d135ed279518b21f452b Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:18 +0800 Subject: [PATCH 1601/7006] ACPICA: Parser: Cleanup aml_offset in union acpi_operand_object ACPICA commit 61b360074fde2bb8282722579410f5d1fb12f84d This patch converts aml_offset in union acpi_operand_object to AML address. AML offset is actually only used by the debugger, using AML address is more direct and efficient during the parsing stage so that we don't need to calculate the offset during the parsing stage and will not have difficulities in converting it into other offset attributes. Sometimes, aml_offset is not an indication of the offset from the table header but the offset from the entry of a list of terms, which requires additional efforts to convert it into an offset from the table header. By using AML address directly, there is no such difficulty. Thus this patch also deletes a logic in disassembler that is trying to convert the aml_offset from "offset from the start address of Method/Package/Buffer" into the "offset from the start address of the ACPI table" (Sample code deletion can be seen in acpi_dm_deferred_parse(), but the function is not in the Linux kernel). Lv Zheng. Link: https://github.com/acpica/acpica/commit/61b36007 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/psargs.c | 7 +++---- drivers/acpi/acpica/psloop.c | 15 ++++----------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index bc600969c6a15..607e62897aff3 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -726,7 +726,7 @@ union acpi_parse_value { u8 descriptor_type; /* To differentiate various internal objs */\ u8 flags; /* Type of Op */\ u16 aml_opcode; /* AML opcode */\ - u32 aml_offset; /* Offset of declaration in AML */\ + u8 *aml; /* Address of declaration in AML */\ union acpi_parse_object *next; /* Next op */\ struct acpi_namespace_node *node; /* For use by interpreter */\ union acpi_parse_value value; /* Value or args associated with the opcode */\ diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 6d038770577b3..0bee9466d1498 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -484,7 +484,7 @@ acpi_ps_get_next_simple_arg(struct acpi_parse_state *parser_state, static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state *parser_state) { - u32 aml_offset; + u8 *aml; union acpi_parse_object *field; union acpi_parse_object *arg = NULL; u16 opcode; @@ -498,8 +498,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state ACPI_FUNCTION_TRACE(ps_get_next_field); - aml_offset = - (u32)ACPI_PTR_DIFF(parser_state->aml, parser_state->aml_start); + aml = parser_state->aml; /* Determine field type */ @@ -541,7 +540,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state return_PTR(NULL); } - field->common.aml_offset = aml_offset; + field->common.aml = aml; /* Decode the field type */ diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index ce66e73f1f60b..d5843830fef80 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -137,10 +137,7 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, } if (arg) { - arg->common.aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->aml, - walk_state->parser_state. - aml_start); + arg->common.aml = walk_state->aml; acpi_ps_append_arg(op, arg); } @@ -494,18 +491,14 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - op->common.aml_offset = - (u32)ACPI_PTR_DIFF(walk_state->aml, - walk_state->parser_state. - aml_start); + op->common.aml = walk_state->aml; if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Opcode %4.4X [%s] Op %p Aml %p AmlOffset %5.5X\n", + "Opcode %4.4X [%s] Op %p Aml %p\n", (u32)op->common.aml_opcode, walk_state->op_info->name, op, - parser_state->aml, - op->common.aml_offset)); + op->common.aml)); } } -- GitLab From 62eb935b77818a5e4ff3c8d9b97036b59944f649 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:24 +0800 Subject: [PATCH 1602/7006] ACPICA: Dispatcher: Cleanup union acpi_operand_object's AML address assignments ACPICA commit afb52611dbe7403551f93504d3798534f5c343f4 This patch cleans up the code of assigning the AML address to the union acpi_operand_object. The idea behind this cleanup is: The AML address of the union acpi_operand_object should always be determined at the point where the object is encountered. It should be started from the first byte of the object. For example, the opcode of the object, the name string of the user_term object, or the first byte of the packaged object (where a pkg_length is prefixed). So it's not cleaner to have it assigned here and there in the entire ACPICA source tree. There are some special cases for the internal opcodes, before cleaning up the internal opcodes, we should also determine the rules for the AML addresses of the internal opcodes: 1. INT_NAMEPATH_OP: the address of the first byte for the name_string. 2. INT_METHODCALL_OP: the address of the first byte for the name_string. 3. INT_BYTELIST_OP: the address of the first byte for the byte_data list. 4. INT_EVAL_SUBTREE_OP: the address of the first byte for the Region/Package/Buffer/bank_field/Field arguments. 5. INT_NAMEDFIELD_OP: the address to the name_seg. 6. INT_RESERVEDFIELD_OP: the address to the 0x00 prefix. 7. INT_ACCESSFIELD_OP: the address to the 0x01 prefix. 8. INT_CONNECTION_OP: the address to the 0x02 prefix. 9: INT_EXTACCESSFIELD_OP: the address to the 0x03 prefix. 10.INT_RETURN_VALUE_OP: the address of the replaced operand. 11.computational_data: the address to the Byte/Word/Dword/Qword/string_prefix. Before cleaning up the internal root scope of the aml_walk, turning it into the term_list, we need to remember the aml_start address as the "Aml" attribute for the union acpi_operand_object created by acpi_ps_create_scope_op(). Finally, we can delete some redundant AML address assignment in psloop.c. Link: https://github.com/acpica/acpica/commit/afb52611 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acparser.h | 4 ++-- drivers/acpi/acpica/dsargs.c | 4 ++-- drivers/acpi/acpica/dsmethod.c | 2 +- drivers/acpi/acpica/dswload.c | 2 +- drivers/acpi/acpica/dswload2.c | 2 +- drivers/acpi/acpica/nsparse.c | 40 ++++++++++++++++------------------ drivers/acpi/acpica/psargs.c | 21 ++++++++++-------- drivers/acpi/acpica/psloop.c | 3 --- drivers/acpi/acpica/psobject.c | 2 +- drivers/acpi/acpica/psparse.c | 12 ++++++---- drivers/acpi/acpica/psutils.c | 8 ++++--- drivers/acpi/acpica/psxface.c | 2 +- 12 files changed, 53 insertions(+), 49 deletions(-) diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h index 0cdd2fce493a9..6021ccfb0b1c8 100644 --- a/drivers/acpi/acpica/acparser.h +++ b/drivers/acpi/acpica/acparser.h @@ -225,11 +225,11 @@ void acpi_ps_delete_parse_tree(union acpi_parse_object *root); /* * psutils - parser utilities */ -union acpi_parse_object *acpi_ps_create_scope_op(void); +union acpi_parse_object *acpi_ps_create_scope_op(u8 *aml); void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode); -union acpi_parse_object *acpi_ps_alloc_op(u16 opcode); +union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml); void acpi_ps_free_op(union acpi_parse_object *op); diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c index 3e6989738e85f..e2ab59e391627 100644 --- a/drivers/acpi/acpica/dsargs.c +++ b/drivers/acpi/acpica/dsargs.c @@ -86,7 +86,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, /* Allocate a new parser op to be the root of the parsed tree */ - op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); + op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP, aml_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -129,7 +129,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node, /* Evaluate the deferred arguments */ - op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP); + op = acpi_ps_alloc_op(AML_INT_EVAL_SUBTREE_OP, aml_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index bf8c16e379fbd..4abc2425de4ba 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -103,7 +103,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node, /* Create/Init a root op for the method parse tree */ - op = acpi_ps_alloc_op(AML_METHOD_OP); + op = acpi_ps_alloc_op(AML_METHOD_OP, obj_desc->method.aml_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 845ff44919c37..097188a6b1c1b 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c @@ -388,7 +388,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, /* Create a new op */ - op = acpi_ps_alloc_op(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode, walk_state->aml); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c index fcaa30c611fb1..e2c08cd79aca7 100644 --- a/drivers/acpi/acpica/dswload2.c +++ b/drivers/acpi/acpica/dswload2.c @@ -335,7 +335,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, /* Create a new op */ - op = acpi_ps_alloc_op(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode, walk_state->aml); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c index 9926a67ca6d71..3736d43b18b94 100644 --- a/drivers/acpi/acpica/nsparse.c +++ b/drivers/acpi/acpica/nsparse.c @@ -78,6 +78,20 @@ acpi_ns_one_complete_parse(u32 pass_number, ACPI_FUNCTION_TRACE(ns_one_complete_parse); + status = acpi_get_table_by_index(table_index, &table); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + + /* Table must consist of at least a complete header */ + + if (table->length < sizeof(struct acpi_table_header)) { + return_ACPI_STATUS(AE_BAD_HEADER); + } + + aml_start = (u8 *)table + sizeof(struct acpi_table_header); + aml_length = table->length - sizeof(struct acpi_table_header); + status = acpi_tb_get_owner_id(table_index, &owner_id); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); @@ -85,7 +99,7 @@ acpi_ns_one_complete_parse(u32 pass_number, /* Create and init a Root Node */ - parse_root = acpi_ps_create_scope_op(); + parse_root = acpi_ps_create_scope_op(aml_start); if (!parse_root) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -98,23 +112,12 @@ acpi_ns_one_complete_parse(u32 pass_number, return_ACPI_STATUS(AE_NO_MEMORY); } - status = acpi_get_table_by_index(table_index, &table); + status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, + aml_start, aml_length, NULL, + (u8)pass_number); if (ACPI_FAILURE(status)) { acpi_ds_delete_walk_state(walk_state); - acpi_ps_free_op(parse_root); - return_ACPI_STATUS(status); - } - - /* Table must consist of at least a complete header */ - - if (table->length < sizeof(struct acpi_table_header)) { - status = AE_BAD_HEADER; - } else { - aml_start = (u8 *)table + sizeof(struct acpi_table_header); - aml_length = table->length - sizeof(struct acpi_table_header); - status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL, - aml_start, aml_length, NULL, - (u8)pass_number); + goto cleanup; } /* Found OSDT table, enable the namespace override feature */ @@ -124,11 +127,6 @@ acpi_ns_one_complete_parse(u32 pass_number, walk_state->namespace_override = TRUE; } - if (ACPI_FAILURE(status)) { - acpi_ds_delete_walk_state(walk_state); - goto cleanup; - } - /* start_node is the default location to load the table */ if (start_node && start_node != acpi_gbl_root_node) { diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c index 0bee9466d1498..29d8b7b01dca7 100644 --- a/drivers/acpi/acpica/psargs.c +++ b/drivers/acpi/acpica/psargs.c @@ -287,7 +287,7 @@ acpi_ps_get_next_namepath(struct acpi_walk_state *walk_state, "Control Method - %p Desc %p Path=%p\n", node, method_desc, path)); - name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + name_op = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, start); if (!name_op) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -535,13 +535,11 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state /* Allocate a new field op */ - field = acpi_ps_alloc_op(opcode); + field = acpi_ps_alloc_op(opcode, aml); if (!field) { return_PTR(NULL); } - field->common.aml = aml; - /* Decode the field type */ switch (opcode) { @@ -603,6 +601,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state * Argument for Connection operator can be either a Buffer * (resource descriptor), or a name_string. */ + aml = parser_state->aml; if (ACPI_GET8(parser_state->aml) == AML_BUFFER_OP) { parser_state->aml++; @@ -615,7 +614,8 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state /* Non-empty list */ - arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); + arg = + acpi_ps_alloc_op(AML_INT_BYTELIST_OP, aml); if (!arg) { acpi_ps_free_op(field); return_PTR(NULL); @@ -664,7 +664,7 @@ static union acpi_parse_object *acpi_ps_get_next_field(struct acpi_parse_state parser_state->aml = pkg_end; } else { - arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, aml); if (!arg) { acpi_ps_free_op(field); return_PTR(NULL); @@ -729,7 +729,7 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* Constants, strings, and namestrings are all the same size */ - arg = acpi_ps_alloc_op(AML_BYTE_OP); + arg = acpi_ps_alloc_op(AML_BYTE_OP, parser_state->aml); if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -776,7 +776,8 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* Non-empty list */ - arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP); + arg = acpi_ps_alloc_op(AML_INT_BYTELIST_OP, + parser_state->aml); if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } @@ -806,7 +807,9 @@ acpi_ps_get_next_arg(struct acpi_walk_state *walk_state, /* null_name or name_string */ - arg = acpi_ps_alloc_op(AML_INT_NAMEPATH_OP); + arg = + acpi_ps_alloc_op(AML_INT_NAMEPATH_OP, + parser_state->aml); if (!arg) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index d5843830fef80..49c60c2671ef5 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -137,7 +137,6 @@ acpi_ps_get_arguments(struct acpi_walk_state *walk_state, } if (arg) { - arg->common.aml = walk_state->aml; acpi_ps_append_arg(op, arg); } @@ -491,8 +490,6 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - op->common.aml = walk_state->aml; - if (walk_state->op_info) { ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Opcode %4.4X [%s] Op %p Aml %p\n", diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c index 6ba3bb7402a95..e54bc2aa7a880 100644 --- a/drivers/acpi/acpica/psobject.c +++ b/drivers/acpi/acpica/psobject.c @@ -297,7 +297,7 @@ acpi_ps_create_op(struct acpi_walk_state *walk_state, /* Create Op structure and append to parent's argument list */ walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode); - op = acpi_ps_alloc_op(walk_state->opcode); + op = acpi_ps_alloc_op(walk_state->opcode, aml_op_start); if (!op) { return_ACPI_STATUS(AE_NO_MEMORY); } diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index a555f7f7b9a21..b857ad58022af 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -185,7 +185,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, * op must be replaced by a placeholder return op */ replacement_op = - acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); + acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } @@ -209,7 +210,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, || (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) { replacement_op = - acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); + acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } @@ -224,7 +226,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, AML_VAR_PACKAGE_OP)) { replacement_op = acpi_ps_alloc_op(op->common. - aml_opcode); + aml_opcode, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } else { @@ -240,7 +243,8 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, default: replacement_op = - acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP); + acpi_ps_alloc_op(AML_INT_RETURN_VALUE_OP, + op->common.aml); if (!replacement_op) { status = AE_NO_MEMORY; } diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c index 32440912023a7..183cc1efbc518 100644 --- a/drivers/acpi/acpica/psutils.c +++ b/drivers/acpi/acpica/psutils.c @@ -60,11 +60,11 @@ ACPI_MODULE_NAME("psutils") * DESCRIPTION: Create a Scope and associated namepath op with the root name * ******************************************************************************/ -union acpi_parse_object *acpi_ps_create_scope_op(void) +union acpi_parse_object *acpi_ps_create_scope_op(u8 *aml) { union acpi_parse_object *scope_op; - scope_op = acpi_ps_alloc_op(AML_SCOPE_OP); + scope_op = acpi_ps_alloc_op(AML_SCOPE_OP, aml); if (!scope_op) { return (NULL); } @@ -103,6 +103,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) * FUNCTION: acpi_ps_alloc_op * * PARAMETERS: opcode - Opcode that will be stored in the new Op + * aml - Address of the opcode * * RETURN: Pointer to the new Op, null on failure * @@ -112,7 +113,7 @@ void acpi_ps_init_op(union acpi_parse_object *op, u16 opcode) * ******************************************************************************/ -union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) +union acpi_parse_object *acpi_ps_alloc_op(u16 opcode, u8 *aml) { union acpi_parse_object *op; const struct acpi_opcode_info *op_info; @@ -149,6 +150,7 @@ union acpi_parse_object *acpi_ps_alloc_op(u16 opcode) if (op) { acpi_ps_init_op(op, opcode); + op->common.aml = aml; op->common.flags = flags; } diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 841a5ea060942..1f3f46d44312e 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -256,7 +256,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) /* Create and init a Root Node */ - op = acpi_ps_create_scope_op(); + op = acpi_ps_create_scope_op(info->obj_desc->method.aml_start); if (!op) { status = AE_NO_MEMORY; goto cleanup; -- GitLab From 07b9c91225055afeb2d75942fc36dd51c5553d90 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:31 +0800 Subject: [PATCH 1603/7006] ACPICA: Executer: Add back pointing reference of method operand ACPICA commit 9dcd124e914e87495fbd1786d9484b962e0823e0 This patch adds back pointing reference of the namespace node for a method operand. The namespace node then can be used in acpi_ds_terminate_control_method() to obtain method full path to be used by tracing facilities. Lv Zheng. Link: https://github.com/acpica/acpica/commit/9dcd124e Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acobject.h | 1 + drivers/acpi/acpica/excreate.c | 1 + drivers/acpi/acpica/utdelete.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index c81d98d09cace..0bd02c4a5f759 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h @@ -176,6 +176,7 @@ struct acpi_object_method { u8 param_count; u8 sync_level; union acpi_operand_object *mutex; + union acpi_operand_object *node; u8 *aml_start; union { acpi_internal_method implementation; diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c index aaeea4840aaa3..ccb7219bdcee2 100644 --- a/drivers/acpi/acpica/excreate.c +++ b/drivers/acpi/acpica/excreate.c @@ -486,6 +486,7 @@ acpi_ex_create_method(u8 * aml_start, obj_desc->method.aml_start = aml_start; obj_desc->method.aml_length = aml_length; + obj_desc->method.node = operand[0]; /* * Disassemble the method flags. Split off the arg_count, Serialized diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c index 71fce389fd484..1638312e3d8f9 100644 --- a/drivers/acpi/acpica/utdelete.c +++ b/drivers/acpi/acpica/utdelete.c @@ -209,6 +209,9 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object) acpi_ut_delete_object_desc(object->method.mutex); object->method.mutex = NULL; } + if (object->method.node) { + object->method.node = NULL; + } break; case ACPI_TYPE_REGION: -- GitLab From d1e7ffe50ba588ddf7de520990815c37f31776d8 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:39 +0800 Subject: [PATCH 1604/7006] ACPICA: Namespace: Add function to directly return normalized full path ACPICA commit 6e0229bb156d71675f2e07dc7960adb7ec0a60ea This patch adds functions to return normalized full path instead of "external path". The external path contains trailing "_" for each name segment while the normalized full path doesn't contain the trailing "_". Currently this function is used by the method tracing users to specify a none trailing "_" attached name path. Lv Zheng. Note that we need to validate and switch all Linux kernel acpi_get_name() users to use the new name type before removing the old name type from ACPICA. Link: https://github.com/acpica/acpica/commit/6e0229bb Signed-off-by: Lv Zheng Reviewed-by: Ruiyi Zhang Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acnamesp.h | 13 +- drivers/acpi/acpica/exdump.c | 5 +- drivers/acpi/acpica/nsnames.c | 275 +++++++++++++++++++-------------- drivers/acpi/acpica/nsutils.c | 2 +- drivers/acpi/acpica/nsxfname.c | 8 +- drivers/acpi/acpica/rscreate.c | 3 +- drivers/acpi/acpica/utmisc.c | 2 +- include/acpi/actypes.h | 3 +- 8 files changed, 178 insertions(+), 133 deletions(-) diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index 0dd088290d805..ea0d9076d4087 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h @@ -272,17 +272,20 @@ acpi_ns_check_package(struct acpi_evaluate_info *info, */ u32 acpi_ns_opens_scope(acpi_object_type type); -acpi_status -acpi_ns_build_external_path(struct acpi_namespace_node *node, - acpi_size size, char *name_buffer); - char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node); +u32 +acpi_ns_build_normalized_path(struct acpi_namespace_node *node, + char *full_path, u32 path_size, u8 no_trailing); + +char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, + u8 no_trailing); + char *acpi_ns_name_of_current_scope(struct acpi_walk_state *walk_state); acpi_status acpi_ns_handle_to_pathname(acpi_handle target_handle, - struct acpi_buffer *buffer); + struct acpi_buffer *buffer, u8 no_trailing); u8 acpi_ns_pattern_match(struct acpi_namespace_node *obj_node, char *search_for); diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index 401e7edcd4193..b6495fb552f0b 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -995,9 +995,8 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) if (obj_desc->reference.class == ACPI_REFCLASS_NAME) { acpi_os_printf(" %p ", obj_desc->reference.node); - status = - acpi_ns_handle_to_pathname(obj_desc->reference.node, - &ret_buf); + status = acpi_ns_handle_to_pathname(obj_desc->reference.node, + &ret_buf, FALSE); if (ACPI_FAILURE(status)) { acpi_os_printf(" Could not convert name to pathname\n"); } else { diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index 2e37888f6abef..8934b4eddb731 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c @@ -49,73 +49,6 @@ #define _COMPONENT ACPI_NAMESPACE ACPI_MODULE_NAME("nsnames") -/******************************************************************************* - * - * FUNCTION: acpi_ns_build_external_path - * - * PARAMETERS: node - NS node whose pathname is needed - * size - Size of the pathname - * *name_buffer - Where to return the pathname - * - * RETURN: Status - * Places the pathname into the name_buffer, in external format - * (name segments separated by path separators) - * - * DESCRIPTION: Generate a full pathaname - * - ******************************************************************************/ -acpi_status -acpi_ns_build_external_path(struct acpi_namespace_node *node, - acpi_size size, char *name_buffer) -{ - acpi_size index; - struct acpi_namespace_node *parent_node; - - ACPI_FUNCTION_ENTRY(); - - /* Special case for root */ - - index = size - 1; - if (index < ACPI_NAME_SIZE) { - name_buffer[0] = AML_ROOT_PREFIX; - name_buffer[1] = 0; - return (AE_OK); - } - - /* Store terminator byte, then build name backwards */ - - parent_node = node; - name_buffer[index] = 0; - - while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) { - index -= ACPI_NAME_SIZE; - - /* Put the name into the buffer */ - - ACPI_MOVE_32_TO_32((name_buffer + index), &parent_node->name); - parent_node = parent_node->parent; - - /* Prefix name with the path separator */ - - index--; - name_buffer[index] = ACPI_PATH_SEPARATOR; - } - - /* Overwrite final separator with the root prefix character */ - - name_buffer[index] = AML_ROOT_PREFIX; - - if (index != 0) { - ACPI_ERROR((AE_INFO, - "Could not construct external pathname; index=%u, size=%u, Path=%s", - (u32)index, (u32)size, &name_buffer[size])); - - return (AE_BAD_PARAMETER); - } - - return (AE_OK); -} - /******************************************************************************* * * FUNCTION: acpi_ns_get_external_pathname @@ -130,37 +63,13 @@ acpi_ns_build_external_path(struct acpi_namespace_node *node, * for error and debug statements. * ******************************************************************************/ - char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) { - acpi_status status; char *name_buffer; - acpi_size size; ACPI_FUNCTION_TRACE_PTR(ns_get_external_pathname, node); - /* Calculate required buffer size based on depth below root */ - - size = acpi_ns_get_pathname_length(node); - if (!size) { - return_PTR(NULL); - } - - /* Allocate a buffer to be returned to caller */ - - name_buffer = ACPI_ALLOCATE_ZEROED(size); - if (!name_buffer) { - ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); - return_PTR(NULL); - } - - /* Build the path in the allocated buffer */ - - status = acpi_ns_build_external_path(node, size, name_buffer); - if (ACPI_FAILURE(status)) { - ACPI_FREE(name_buffer); - return_PTR(NULL); - } + name_buffer = acpi_ns_get_normalized_pathname(node, FALSE); return_PTR(name_buffer); } @@ -180,33 +89,12 @@ char *acpi_ns_get_external_pathname(struct acpi_namespace_node *node) acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) { acpi_size size; - struct acpi_namespace_node *next_node; ACPI_FUNCTION_ENTRY(); - /* - * Compute length of pathname as 5 * number of name segments. - * Go back up the parent tree to the root - */ - size = 0; - next_node = node; + size = acpi_ns_build_normalized_path(node, NULL, 0, FALSE); - while (next_node && (next_node != acpi_gbl_root_node)) { - if (ACPI_GET_DESCRIPTOR_TYPE(next_node) != ACPI_DESC_TYPE_NAMED) { - ACPI_ERROR((AE_INFO, - "Invalid Namespace Node (%p) while traversing namespace", - next_node)); - return (0); - } - size += ACPI_PATH_SEGMENT_LENGTH; - next_node = next_node->parent; - } - - if (!size) { - size = 1; /* Root node case */ - } - - return (size + 1); /* +1 for null string terminator */ + return (size); } /******************************************************************************* @@ -216,6 +104,8 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) * PARAMETERS: target_handle - Handle of named object whose name is * to be found * buffer - Where the pathname is returned + * no_trailing - Remove trailing '_' for each name + * segment * * RETURN: Status, Buffer is filled with pathname if status is AE_OK * @@ -225,7 +115,7 @@ acpi_size acpi_ns_get_pathname_length(struct acpi_namespace_node *node) acpi_status acpi_ns_handle_to_pathname(acpi_handle target_handle, - struct acpi_buffer * buffer) + struct acpi_buffer * buffer, u8 no_trailing) { acpi_status status; struct acpi_namespace_node *node; @@ -240,7 +130,8 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, /* Determine size required for the caller buffer */ - required_size = acpi_ns_get_pathname_length(node); + required_size = + acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); if (!required_size) { return_ACPI_STATUS(AE_BAD_PARAMETER); } @@ -254,8 +145,8 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, /* Build the path in the caller buffer */ - status = - acpi_ns_build_external_path(node, required_size, buffer->pointer); + (void)acpi_ns_build_normalized_path(node, buffer->pointer, + required_size, no_trailing); if (ACPI_FAILURE(status)) { return_ACPI_STATUS(status); } @@ -264,3 +155,149 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, (char *)buffer->pointer, (u32) required_size)); return_ACPI_STATUS(AE_OK); } + +/******************************************************************************* + * + * FUNCTION: acpi_ns_build_normalized_path + * + * PARAMETERS: node - Namespace node + * full_path - Where the path name is returned + * path_size - Size of returned path name buffer + * no_trailing - Remove trailing '_' from each name segment + * + * RETURN: Return 1 if the AML path is empty, otherwise returning (length + * of pathname + 1) which means the 'FullPath' contains a trailing + * null. + * + * DESCRIPTION: Build and return a full namespace pathname. + * Note that if the size of 'FullPath' isn't large enough to + * contain the namespace node's path name, the actual required + * buffer length is returned, and it should be greater than + * 'PathSize'. So callers are able to check the returning value + * to determine the buffer size of 'FullPath'. + * + ******************************************************************************/ + +u32 +acpi_ns_build_normalized_path(struct acpi_namespace_node *node, + char *full_path, u32 path_size, u8 no_trailing) +{ + u32 length = 0, i; + char name[ACPI_NAME_SIZE]; + u8 do_no_trailing; + char c, *left, *right; + struct acpi_namespace_node *next_node; + + ACPI_FUNCTION_TRACE_PTR(ns_build_normalized_path, node); + +#define ACPI_PATH_PUT8(path, size, byte, length) \ + do { \ + if ((length) < (size)) \ + { \ + (path)[(length)] = (byte); \ + } \ + (length)++; \ + } while (0) + + /* + * Make sure the path_size is correct, so that we don't need to + * validate both full_path and path_size. + */ + if (!full_path) { + path_size = 0; + } + + if (!node) { + goto build_trailing_null; + } + + next_node = node; + while (next_node && next_node != acpi_gbl_root_node) { + if (next_node != node) { + ACPI_PATH_PUT8(full_path, path_size, + AML_DUAL_NAME_PREFIX, length); + } + ACPI_MOVE_32_TO_32(name, &next_node->name); + do_no_trailing = no_trailing; + for (i = 0; i < 4; i++) { + c = name[4 - i - 1]; + if (do_no_trailing && c != '_') { + do_no_trailing = FALSE; + } + if (!do_no_trailing) { + ACPI_PATH_PUT8(full_path, path_size, c, length); + } + } + next_node = next_node->parent; + } + ACPI_PATH_PUT8(full_path, path_size, AML_ROOT_PREFIX, length); + + /* Reverse the path string */ + + if (length <= path_size) { + left = full_path; + right = full_path + length - 1; + while (left < right) { + c = *left; + *left++ = *right; + *right-- = c; + } + } + + /* Append the trailing null */ + +build_trailing_null: + ACPI_PATH_PUT8(full_path, path_size, '\0', length); + +#undef ACPI_PATH_PUT8 + + return_UINT32(length); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ns_get_normalized_pathname + * + * PARAMETERS: node - Namespace node whose pathname is needed + * no_trailing - Remove trailing '_' from each name segment + * + * RETURN: Pointer to storage containing the fully qualified name of + * the node, In external format (name segments separated by path + * separators.) + * + * DESCRIPTION: Used to obtain the full pathname to a namespace node, usually + * for error and debug statements. All trailing '_' will be + * removed from the full pathname if 'NoTrailing' is specified.. + * + ******************************************************************************/ + +char *acpi_ns_get_normalized_pathname(struct acpi_namespace_node *node, + u8 no_trailing) +{ + char *name_buffer; + acpi_size size; + + ACPI_FUNCTION_TRACE_PTR(ns_get_normalized_pathname, node); + + /* Calculate required buffer size based on depth below root */ + + size = acpi_ns_build_normalized_path(node, NULL, 0, no_trailing); + if (!size) { + return_PTR(NULL); + } + + /* Allocate a buffer to be returned to caller */ + + name_buffer = ACPI_ALLOCATE_ZEROED(size); + if (!name_buffer) { + ACPI_ERROR((AE_INFO, "Could not allocate %u bytes", (u32)size)); + return_PTR(NULL); + } + + /* Build the path in the allocated buffer */ + + (void)acpi_ns_build_normalized_path(node, name_buffer, size, + no_trailing); + + return_PTR(name_buffer); +} diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 8d8104b8bd28a..9a34c5f040759 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -83,7 +83,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(node, &buffer); + status = acpi_ns_handle_to_pathname(node, &buffer, FALSE); if (ACPI_SUCCESS(status)) { if (message) { acpi_os_printf("%s ", message); diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index 9ff643b9553fe..4b4d2f43d406f 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c @@ -172,11 +172,15 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) return (status); } - if (name_type == ACPI_FULL_PATHNAME) { + if (name_type == ACPI_FULL_PATHNAME || + name_type == ACPI_FULL_PATHNAME_NO_TRAILING) { /* Get the full pathname (From the namespace root) */ - status = acpi_ns_handle_to_pathname(handle, buffer); + status = acpi_ns_handle_to_pathname(handle, buffer, + name_type == + ACPI_FULL_PATHNAME ? FALSE : + TRUE); return (status); } diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c index 3fa829e96c2a0..a5344428f3ae7 100644 --- a/drivers/acpi/acpica/rscreate.c +++ b/drivers/acpi/acpica/rscreate.c @@ -348,7 +348,8 @@ acpi_rs_create_pci_routing_table(union acpi_operand_object *package_object, status = acpi_ns_handle_to_pathname((acpi_handle) node, - &path_buffer); + &path_buffer, + FALSE); /* +1 to include null terminator */ diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 71b66537f8260..98087ea1cdb3e 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -376,7 +376,7 @@ acpi_ut_display_init_pathname(u8 type, /* Get the full pathname to the node */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(obj_handle, &buffer); + status = acpi_ns_handle_to_pathname(obj_handle, &buffer, FALSE); if (ACPI_FAILURE(status)) { return; } diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index c2a41d223162a..0f3913f9a377a 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -985,7 +985,8 @@ struct acpi_buffer { */ #define ACPI_FULL_PATHNAME 0 #define ACPI_SINGLE_NAME 1 -#define ACPI_NAME_TYPE_MAX 1 +#define ACPI_FULL_PATHNAME_NO_TRAILING 2 +#define ACPI_NAME_TYPE_MAX 2 /* * Predefined Namespace items -- GitLab From 0bac4295526c67e87ec24b29762140c38de7c86a Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:46 +0800 Subject: [PATCH 1605/7006] ACPICA: Dispatcher: Move stack traversal code to dispatcher ACPICA commit c8275e243b58fd4adfc0362bd704af41ed14bc75 This patch moves parts of acpi_dm_dump_method_info() to the dispatcher component. This patch also makes the new function dependent on ACPI_DEBUG_OUTPUT compile-stage definition so that it can be used by the trace facility. acpi_dm_dump_method_info() traverses method stack when an exception is encountered. Such traversal is needed to support method tracing for the exceptions. When an exception is encountered, the end indications of the aborted methods should be logged in order not to break the user space analysis tool. Lv Zheng. Link: https://github.com/acpica/acpica/commit/c8275e24 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 1 + drivers/acpi/acpica/acdispat.h | 8 ++ drivers/acpi/acpica/dsdebug.c | 222 +++++++++++++++++++++++++++++++++ drivers/acpi/acpica/dsmethod.c | 7 +- 4 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 drivers/acpi/acpica/dsdebug.c diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index c1a963581dc0f..9f30ed7b1a07c 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -11,6 +11,7 @@ obj-y += acpi.o acpi-y := \ dsargs.o \ dscontrol.o \ + dsdebug.o \ dsfield.o \ dsinit.o \ dsmethod.o \ diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h index 408f04bcaab44..7094dc89eb816 100644 --- a/drivers/acpi/acpica/acdispat.h +++ b/drivers/acpi/acpica/acdispat.h @@ -354,4 +354,12 @@ acpi_status acpi_ds_result_push(union acpi_operand_object *object, struct acpi_walk_state *walk_state); +/* + * dsdebug - parser debugging routines + */ +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op); + #endif /* _ACDISPAT_H_ */ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c new file mode 100644 index 0000000000000..21c6cefd267e7 --- /dev/null +++ b/drivers/acpi/acpica/dsdebug.c @@ -0,0 +1,222 @@ +/****************************************************************************** + * + * Module Name: dsdebug - Parser/Interpreter interface - debugging + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" +#include "acdispat.h" +#include "acnamesp.h" +#ifdef ACPI_DISASSEMBLER +#include "acdisasm.h" +#endif + +#define _COMPONENT ACPI_DISPATCHER +ACPI_MODULE_NAME("dsdebug") + +#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) +/* Local prototypes */ +static void +acpi_ds_print_node_pathname(struct acpi_namespace_node *node, + const char *message); + +/******************************************************************************* + * + * FUNCTION: acpi_ds_print_node_pathname + * + * PARAMETERS: node - Object + * message - Prefix message + * + * DESCRIPTION: Print an object's full namespace pathname + * Manages allocation/freeing of a pathname buffer + * + ******************************************************************************/ + +static void +acpi_ds_print_node_pathname(struct acpi_namespace_node *node, + const char *message) +{ + struct acpi_buffer buffer; + acpi_status status; + + ACPI_FUNCTION_TRACE(ds_print_node_pathname); + + if (!node) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[NULL NAME]")); + return_VOID; + } + + /* Convert handle to full pathname and print it (with supplied message) */ + + buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; + + status = acpi_ns_handle_to_pathname(node, &buffer, FALSE); + if (ACPI_SUCCESS(status)) { + if (message) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ", + message)); + } + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "[%s] (Node %p)", + (char *)buffer.pointer, node)); + ACPI_FREE(buffer.pointer); + } + + return_VOID; +} + +/******************************************************************************* + * + * FUNCTION: acpi_ds_dump_method_stack + * + * PARAMETERS: status - Method execution status + * walk_state - Current state of the parse tree walk + * op - Executing parse op + * + * RETURN: None + * + * DESCRIPTION: Called when a method has been aborted because of an error. + * Dumps the method execution stack. + * + ******************************************************************************/ + +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + union acpi_parse_object *next; + struct acpi_thread_state *thread; + struct acpi_walk_state *next_walk_state; + struct acpi_namespace_node *previous_method = NULL; + + ACPI_FUNCTION_TRACE(ds_dump_method_stack); + + /* Ignore control codes, they are not errors */ + + if ((status & AE_CODE_MASK) == AE_CODE_CONTROL) { + return_VOID; + } + + /* We may be executing a deferred opcode */ + + if (walk_state->deferred_node) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "Executing subtree for Buffer/Package/Region\n")); + return_VOID; + } + + /* + * If there is no Thread, we are not actually executing a method. + * This can happen when the iASL compiler calls the interpreter + * to perform constant folding. + */ + thread = walk_state->thread; + if (!thread) { + return_VOID; + } + + /* Display exception and method name */ + + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + "\n**** Exception %s during execution of method ", + acpi_format_exception(status))); + acpi_ds_print_node_pathname(walk_state->method_node, NULL); + + /* Display stack of executing methods */ + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, + "\n\nMethod Execution Stack:\n")); + next_walk_state = thread->walk_state_list; + + /* Walk list of linked walk states */ + + while (next_walk_state) { + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, + " Method [%4.4s] executing: ", + acpi_ut_get_node_name(next_walk_state-> + method_node))); + + /* First method is the currently executing method */ + + if (next_walk_state == walk_state) { + if (op) { + + /* Display currently executing ASL statement */ + + next = op->common.next; + op->common.next = NULL; + +#ifdef ACPI_DISASSEMBLER + acpi_dm_disassemble(next_walk_state, op, + ACPI_UINT32_MAX); +#endif + op->common.next = next; + } + } else { + /* + * This method has called another method + * NOTE: the method call parse subtree is already deleted at this + * point, so we cannot disassemble the method invocation. + */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, + "Call to method ")); + acpi_ds_print_node_pathname(previous_method, NULL); + } + + previous_method = next_walk_state->method_node; + next_walk_state = next_walk_state->next; + ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "\n")); + } + + return_VOID; +} + +#else +void +acpi_ds_dump_method_stack(acpi_status status, + struct acpi_walk_state *walk_state, + union acpi_parse_object *op) +{ + return; +} + +#endif diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 4abc2425de4ba..e0ae8f4e9b35c 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -251,14 +251,15 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) acpi_ds_clear_implicit_return(walk_state); -#ifdef ACPI_DISASSEMBLER if (ACPI_FAILURE(status)) { + acpi_ds_dump_method_stack(status, walk_state, walk_state->op); /* Display method locals/args if disassembler is present */ - acpi_dm_dump_method_info(status, walk_state, walk_state->op); - } +#ifdef ACPI_DISASSEMBLER + acpi_dm_dump_method_info(status, walk_state); #endif + } return (status); } -- GitLab From a616dc2fe50270f1fa5050fb9cd88a08531a3f25 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:53 +0800 Subject: [PATCH 1606/7006] ACPICA: Dispatcher: Add trace support for interpreter ACPICA commit 71299ec8b49054daace0df50268e8e055654ca37 This patch adds trace point at the following point: 1. Begin/end of a control method execution; 2. Begin/end of an opcode execution. The trace point feature can be enabled by defining ACPI_DEBUG_OUTPUT and specifying a debug level that includes ACPI_LV_TRACDE_POINT and the debug layers that include ACPI_PARSER and ACPI_DISPACTCHER. In order to make aml_op_name of union acpi_parse_object usable for tracer, it is enabled for ACPI_DEBUG_OUTPUT in this patch. Lv Zheng. Link: https://github.com/acpica/acpica/commit/71299ec8 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 2 +- drivers/acpi/acpica/dsdebug.c | 24 ++++++++++++++++++++++++ drivers/acpi/acpica/dsmethod.c | 31 +++++++++++++++++++++++++++++++ drivers/acpi/acpica/psloop.c | 15 +++++++++++++++ drivers/acpi/acpica/psparse.c | 4 ++++ include/acpi/acoutput.h | 4 +++- 6 files changed, 78 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 607e62897aff3..610d001fbb31d 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -715,7 +715,7 @@ union acpi_parse_value { union acpi_parse_object *arg; /* arguments and contained ops */ }; -#ifdef ACPI_DISASSEMBLER +#if defined(ACPI_DISASSEMBLER) || defined(ACPI_DEBUG_OUTPUT) #define ACPI_DISASM_ONLY_MEMBERS(a) a; #else #define ACPI_DISASM_ONLY_MEMBERS(a) diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 21c6cefd267e7..7df9b50e17a7d 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -127,6 +127,8 @@ acpi_ds_dump_method_stack(acpi_status status, struct acpi_thread_state *thread; struct acpi_walk_state *next_walk_state; struct acpi_namespace_node *previous_method = NULL; + union acpi_operand_object *method_desc; + char *pathname = NULL; ACPI_FUNCTION_TRACE(ds_dump_method_stack); @@ -170,6 +172,28 @@ acpi_ds_dump_method_stack(acpi_status status, /* Walk list of linked walk states */ while (next_walk_state) { + method_desc = next_walk_state->method_desc; + if (method_desc && method_desc->method.node) { + pathname = acpi_ns_get_normalized_pathname((struct + acpi_namespace_node + *) + method_desc-> + method.node, + TRUE); + } + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p:%s] execution.\n", + method_desc->method.aml_start, + pathname)); + ACPI_FREE(pathname); + pathname = NULL; + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p] execution.\n", + method_desc->method.aml_start)); + } + ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, " Method [%4.4s] executing: ", acpi_ut_get_node_name(next_walk_state-> diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index e0ae8f4e9b35c..0fa6f19aab3a8 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -327,6 +327,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; + char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); @@ -334,6 +335,18 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, return_ACPI_STATUS(AE_NULL_ENTRY); } + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p:%s] execution.\n", + obj_desc->method.aml_start, pathname)); + ACPI_FREE(pathname); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p] execution.\n", + obj_desc->method.aml_start)); + } + /* Prevent wraparound of thread count */ if (obj_desc->method.thread_count == ACPI_UINT8_MAX) { @@ -695,6 +708,7 @@ void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { + char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); @@ -832,5 +846,22 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } } + if (method_desc->method.node) { + pathname = acpi_ns_get_normalized_pathname((struct + acpi_namespace_node + *)method_desc-> + method.node, TRUE); + } + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p:%s] execution.\n", + method_desc->method.aml_start, pathname)); + ACPI_FREE(pathname); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p] execution.\n", + method_desc->method.aml_start)); + } + return_VOID; } diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 49c60c2671ef5..80339ba56cad0 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -497,6 +497,21 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) walk_state->op_info->name, op, op->common.aml)); } + + if (walk_state->op_info) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", + op->common.aml_op_name, + op->common.aml, + walk_state->op_info->class, + walk_state->op_info->type, + walk_state->op_info->flags)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p].\n", + op->common.aml_op_name, + op->common.aml)); + } } /* diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index b857ad58022af..97ea0e5360f16 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -147,6 +147,10 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, return_ACPI_STATUS(AE_OK); /* OK for now */ } + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End opcode: %s[0x%p].\n", + op->common.aml_op_name, op->common.aml)); + /* Delete this op and the subtree below it if asked to */ if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index f56de8c5d844d..8f89df9c7295b 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -88,7 +88,8 @@ #define ACPI_LV_DEBUG_OBJECT 0x00000002 #define ACPI_LV_INFO 0x00000004 #define ACPI_LV_REPAIR 0x00000008 -#define ACPI_LV_ALL_EXCEPTIONS 0x0000000F +#define ACPI_LV_TRACE_POINT 0x00000010 +#define ACPI_LV_ALL_EXCEPTIONS 0x0000001F /* Trace verbosity level 1 [Standard Trace Level] */ @@ -147,6 +148,7 @@ #define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) #define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) #define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR) +#define ACPI_DB_TRACE_POINT ACPI_DEBUG_LEVEL (ACPI_LV_TRACE_POINT) #define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) /* Trace level -- also used in the global "DebugLevel" */ -- GitLab From ab6c573320768c36ac629be3db79ad62445aae64 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:52:59 +0800 Subject: [PATCH 1607/7006] ACPICA: Executer: Add interpreter tracing mode for method tracing facility ACPICA commit 07fffd02607685b655ed92ee15c160e6a810b60b The acpi_debug_trace() is the mechanism known as ACPI method tracing that is used by Linux as ACPICA debugging message reducer. This facility can be controlled through Linux ACPI subsystem - /sys/module/acpi/parameters. This facility requires CONFIG_ACPI_DEBUG to be enabled to see ACPICA trace logs in the kernel dmesg output. This patch enhances acpi_debug_trace() to make it not only a message reducer, but a real tracer to trace AML interpreter execution. Note that in addition to the AML tracer enabling, this patch also updates the facility with the following enhancements: 1. Allow a full path to be specified by the acpi_debug_trace() API. 2. Allow any method rather than just the entrance of acpi_evaluate_object() to be traced. 3. All interpreter ACPI_LV_TRACE_POINT messages are collected for ACPI_EXECUTER layer. The Makefile of drivers/acpi/acpica is also updated to include exdebug.o and the duplicated stubs are removed after that. Note that since this patch has enhanced the method tracing facility, Linux need also be updated after applying this patch. Lv Zheng. Link: https://github.com/acpica/acpica/commit/07fffd02 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 2 + drivers/acpi/acpica/acglobal.h | 2 - drivers/acpi/acpica/acinterp.h | 18 +++ drivers/acpi/acpica/dsdebug.c | 25 +-- drivers/acpi/acpica/dsmethod.c | 32 +--- drivers/acpi/acpica/exdebug.c | 271 +++++++++++++++++++++++++++++++++ drivers/acpi/acpica/psloop.c | 16 +- drivers/acpi/acpica/psparse.c | 4 +- drivers/acpi/acpica/psxface.c | 121 +-------------- drivers/acpi/acpica/utinit.c | 2 - include/acpi/acoutput.h | 13 ++ include/acpi/acpixf.h | 6 +- 12 files changed, 327 insertions(+), 185 deletions(-) diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 43685dd36c77c..88482f75e9415 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -102,6 +102,8 @@ void acpi_db_display_interfaces(char *action_arg, char *interface_name_arg); acpi_status acpi_db_sleep(char *object_arg); +void acpi_db_trace(char *enable_arg, char *method_arg, char *once_arg); + void acpi_db_display_locks(void); void acpi_db_display_resources(char *object_arg); diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 53f96a3707624..5342300719ee7 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -290,8 +290,6 @@ ACPI_GLOBAL(u32, acpi_fixed_event_count[ACPI_NUM_FIXED_EVENTS]); ACPI_GLOBAL(u32, acpi_gbl_original_dbg_level); ACPI_GLOBAL(u32, acpi_gbl_original_dbg_layer); -ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_level); -ACPI_GLOBAL(u32, acpi_gbl_trace_dbg_layer); /***************************************************************************** * diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index 7ac98000b46b6..a3c6e2ab93bb4 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -131,6 +131,24 @@ void acpi_ex_do_debug_object(union acpi_operand_object *source_desc, u32 level, u32 index); +void +acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void +acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void +acpi_ex_start_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + +void +acpi_ex_stop_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state); + /* * exfield - ACPI AML (p-code) execution - field manipulation */ diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index 7df9b50e17a7d..a651d30133d03 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -48,6 +48,7 @@ #ifdef ACPI_DISASSEMBLER #include "acdisasm.h" #endif +#include "acinterp.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsdebug") @@ -128,7 +129,6 @@ acpi_ds_dump_method_stack(acpi_status status, struct acpi_walk_state *next_walk_state; struct acpi_namespace_node *previous_method = NULL; union acpi_operand_object *method_desc; - char *pathname = NULL; ACPI_FUNCTION_TRACE(ds_dump_method_stack); @@ -173,25 +173,10 @@ acpi_ds_dump_method_stack(acpi_status status, while (next_walk_state) { method_desc = next_walk_state->method_desc; - if (method_desc && method_desc->method.node) { - pathname = acpi_ns_get_normalized_pathname((struct - acpi_namespace_node - *) - method_desc-> - method.node, - TRUE); - } - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p:%s] execution.\n", - method_desc->method.aml_start, - pathname)); - ACPI_FREE(pathname); - pathname = NULL; - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p] execution.\n", - method_desc->method.aml_start)); + if (method_desc) { + acpi_ex_stop_trace_method((struct acpi_namespace_node *) + method_desc->method.node, + method_desc, walk_state); } ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH, diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 0fa6f19aab3a8..ea2bdde1227ef 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -327,7 +327,6 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, struct acpi_walk_state *walk_state) { acpi_status status = AE_OK; - char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_begin_method_execution, method_node); @@ -335,17 +334,7 @@ acpi_ds_begin_method_execution(struct acpi_namespace_node *method_node, return_ACPI_STATUS(AE_NULL_ENTRY); } - pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p:%s] execution.\n", - obj_desc->method.aml_start, pathname)); - ACPI_FREE(pathname); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p] execution.\n", - obj_desc->method.aml_start)); - } + acpi_ex_start_trace_method(method_node, obj_desc, walk_state); /* Prevent wraparound of thread count */ @@ -708,7 +697,6 @@ void acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, struct acpi_walk_state *walk_state) { - char *pathname = NULL; ACPI_FUNCTION_TRACE_PTR(ds_terminate_control_method, walk_state); @@ -846,22 +834,8 @@ acpi_ds_terminate_control_method(union acpi_operand_object *method_desc, } } - if (method_desc->method.node) { - pathname = acpi_ns_get_normalized_pathname((struct - acpi_namespace_node - *)method_desc-> - method.node, TRUE); - } - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p:%s] execution.\n", - method_desc->method.aml_start, pathname)); - ACPI_FREE(pathname); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p] execution.\n", - method_desc->method.aml_start)); - } + acpi_ex_stop_trace_method((struct acpi_namespace_node *)method_desc-> + method.node, method_desc, walk_state); return_VOID; } diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 815442bbd0518..00ba9fc85f473 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -43,11 +43,15 @@ #include #include "accommon.h" +#include "acnamesp.h" #include "acinterp.h" +#include "acparser.h" #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME("exdebug") +static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; + #ifndef ACPI_NO_ERROR_MESSAGES /******************************************************************************* * @@ -70,6 +74,7 @@ ACPI_MODULE_NAME("exdebug") * enabled if necessary. * ******************************************************************************/ + void acpi_ex_do_debug_object(union acpi_operand_object *source_desc, u32 level, u32 index) @@ -308,3 +313,269 @@ acpi_ex_do_debug_object(union acpi_operand_object *source_desc, return_VOID; } #endif + +/******************************************************************************* + * + * FUNCTION: acpi_ex_interpreter_trace_enabled + * + * PARAMETERS: name - Whether method name should be matched, + * this should be checked before starting + * the tracer + * + * RETURN: TRUE if interpreter trace is enabled. + * + * DESCRIPTION: Check whether interpreter trace is enabled + * + ******************************************************************************/ + +static u8 acpi_ex_interpreter_trace_enabled(char *name) +{ + + /* Check if tracing is enabled */ + + if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) { + return (FALSE); + } + + /* + * Check if tracing is filtered: + * + * 1. If the tracer is started, acpi_gbl_trace_method_object should have + * been filled by the trace starter + * 2. If the tracer is not started, acpi_gbl_trace_method_name should be + * matched if it is specified + * 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should + * not be cleared by the trace stopper during the first match + */ + if (acpi_gbl_trace_method_object) { + return (TRUE); + } + if (name && + (acpi_gbl_trace_method_name && + strcmp(acpi_gbl_trace_method_name, name))) { + return (FALSE); + } + if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) && + !acpi_gbl_trace_method_name) { + return (FALSE); + } + + return (TRUE); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_start_trace_method + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start control method execution trace + * + ******************************************************************************/ + +void +acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + char *pathname = NULL; + u8 enabled = FALSE; + + ACPI_FUNCTION_NAME(ex_start_trace_method); + + if (method_node) { + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit; + } + + enabled = acpi_ex_interpreter_trace_enabled(pathname); + if (enabled && !acpi_gbl_trace_method_object) { + acpi_gbl_trace_method_object = obj_desc; + acpi_gbl_original_dbg_level = acpi_dbg_level; + acpi_gbl_original_dbg_layer = acpi_dbg_layer; + acpi_dbg_level = ACPI_TRACE_LEVEL_ALL; + acpi_dbg_layer = ACPI_TRACE_LAYER_ALL; + + if (acpi_gbl_trace_dbg_level) { + acpi_dbg_level = acpi_gbl_trace_dbg_level; + } + if (acpi_gbl_trace_dbg_layer) { + acpi_dbg_layer = acpi_gbl_trace_dbg_layer; + } + } + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + +exit: + if (enabled) { + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p:%s] execution.\n", + obj_desc->method.aml_start, + pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin method [0x%p] execution.\n", + obj_desc->method.aml_start)); + } + } + if (pathname) { + ACPI_FREE(pathname); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_stop_trace_method + * + * PARAMETERS: method_node - Node of the method + * obj_desc - The method object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop control method execution trace + * + ******************************************************************************/ + +void +acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, + union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state) +{ + acpi_status status; + char *pathname = NULL; + u8 enabled; + + ACPI_FUNCTION_NAME(ex_stop_trace_method); + + if (method_node) { + pathname = acpi_ns_get_normalized_pathname(method_node, TRUE); + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit_path; + } + + enabled = acpi_ex_interpreter_trace_enabled(NULL); + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + + if (enabled) { + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p:%s] execution.\n", + obj_desc->method.aml_start, + pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End method [0x%p] execution.\n", + obj_desc->method.aml_start)); + } + } + + status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); + if (ACPI_FAILURE(status)) { + goto exit_path; + } + + /* Check whether the tracer should be stopped */ + + if (acpi_gbl_trace_method_object == obj_desc) { + + /* Disable further tracing if type is one-shot */ + + if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) { + acpi_gbl_trace_method_name = NULL; + } + + acpi_dbg_level = acpi_gbl_original_dbg_level; + acpi_dbg_layer = acpi_gbl_original_dbg_layer; + acpi_gbl_trace_method_object = NULL; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + +exit_path: + if (pathname) { + ACPI_FREE(pathname); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_start_trace_opcode + * + * PARAMETERS: op - The parser opcode object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Start opcode execution trace + * + ******************************************************************************/ + +void +acpi_ex_start_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_NAME(ex_start_trace_opcode); + + if (acpi_ex_interpreter_trace_enabled(NULL)) { + if (walk_state->op_info) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", + op->common.aml_op_name, + op->common.aml, + walk_state->op_info->class, + walk_state->op_info->type, + walk_state->op_info->flags)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "Begin opcode: %s[0x%p].\n", + op->common.aml_op_name, + op->common.aml)); + } + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ex_stop_trace_opcode + * + * PARAMETERS: op - The parser opcode object + * walk_state - current state, NULL if not yet executing + * a method. + * + * RETURN: None + * + * DESCRIPTION: Stop opcode execution trace + * + ******************************************************************************/ + +void +acpi_ex_stop_trace_opcode(union acpi_parse_object *op, + struct acpi_walk_state *walk_state) +{ + + ACPI_FUNCTION_NAME(ex_stop_trace_opcode); + + if (acpi_ex_interpreter_trace_enabled(NULL)) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "End opcode: %s[0x%p].\n", + op->common.aml_op_name, op->common.aml)); + } +} diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 80339ba56cad0..a7de52ee15383 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -51,6 +51,7 @@ #include #include "accommon.h" +#include "acinterp.h" #include "acparser.h" #include "acdispat.h" #include "amlcode.h" @@ -498,20 +499,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) op->common.aml)); } - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", - op->common.aml_op_name, - op->common.aml, - walk_state->op_info->class, - walk_state->op_info->type, - walk_state->op_info->flags)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p].\n", - op->common.aml_op_name, - op->common.aml)); - } + acpi_ex_start_trace_opcode(op, walk_state); } /* diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c index 97ea0e5360f16..98001d7f6f803 100644 --- a/drivers/acpi/acpica/psparse.c +++ b/drivers/acpi/acpica/psparse.c @@ -147,9 +147,7 @@ acpi_ps_complete_this_op(struct acpi_walk_state * walk_state, return_ACPI_STATUS(AE_OK); /* OK for now */ } - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End opcode: %s[0x%p].\n", - op->common.aml_op_name, op->common.aml)); + acpi_ex_stop_trace_opcode(op, walk_state); /* Delete this op and the subtree below it if asked to */ diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 1f3f46d44312e..4254805dd319a 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c @@ -47,15 +47,12 @@ #include "acdispat.h" #include "acinterp.h" #include "actables.h" +#include "acnamesp.h" #define _COMPONENT ACPI_PARSER ACPI_MODULE_NAME("psxface") /* Local Prototypes */ -static void acpi_ps_start_trace(struct acpi_evaluate_info *info); - -static void acpi_ps_stop_trace(struct acpi_evaluate_info *info); - static void acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); @@ -76,7 +73,7 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action); ******************************************************************************/ acpi_status -acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags) +acpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags) { acpi_status status; @@ -85,108 +82,14 @@ acpi_debug_trace(char *name, u32 debug_level, u32 debug_layer, u32 flags) return (status); } - /* TBDs: Validate name, allow full path or just nameseg */ - - acpi_gbl_trace_method_name = *ACPI_CAST_PTR(u32, name); + acpi_gbl_trace_method_name = name; acpi_gbl_trace_flags = flags; - - if (debug_level) { - acpi_gbl_trace_dbg_level = debug_level; - } - if (debug_layer) { - acpi_gbl_trace_dbg_layer = debug_layer; - } + acpi_gbl_trace_dbg_level = debug_level; + acpi_gbl_trace_dbg_layer = debug_layer; + status = AE_OK; (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); - return (AE_OK); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ps_start_trace - * - * PARAMETERS: info - Method info struct - * - * RETURN: None - * - * DESCRIPTION: Start control method execution trace - * - ******************************************************************************/ - -static void acpi_ps_start_trace(struct acpi_evaluate_info *info) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return; - } - - if ((!acpi_gbl_trace_method_name) || - (acpi_gbl_trace_method_name != info->node->name.integer)) { - goto exit; - } - - acpi_gbl_original_dbg_level = acpi_dbg_level; - acpi_gbl_original_dbg_layer = acpi_dbg_layer; - - acpi_dbg_level = 0x00FFFFFF; - acpi_dbg_layer = ACPI_UINT32_MAX; - - if (acpi_gbl_trace_dbg_level) { - acpi_dbg_level = acpi_gbl_trace_dbg_level; - } - if (acpi_gbl_trace_dbg_layer) { - acpi_dbg_layer = acpi_gbl_trace_dbg_layer; - } - -exit: - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); -} - -/******************************************************************************* - * - * FUNCTION: acpi_ps_stop_trace - * - * PARAMETERS: info - Method info struct - * - * RETURN: None - * - * DESCRIPTION: Stop control method execution trace - * - ******************************************************************************/ - -static void acpi_ps_stop_trace(struct acpi_evaluate_info *info) -{ - acpi_status status; - - ACPI_FUNCTION_ENTRY(); - - status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); - if (ACPI_FAILURE(status)) { - return; - } - - if ((!acpi_gbl_trace_method_name) || - (acpi_gbl_trace_method_name != info->node->name.integer)) { - goto exit; - } - - /* Disable further tracing if type is one-shot */ - - if (acpi_gbl_trace_flags & 1) { - acpi_gbl_trace_method_name = 0; - acpi_gbl_trace_dbg_level = 0; - acpi_gbl_trace_dbg_layer = 0; - } - - acpi_dbg_level = acpi_gbl_original_dbg_level; - acpi_dbg_layer = acpi_gbl_original_dbg_layer; - -exit: - (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + return (status); } /******************************************************************************* @@ -212,7 +115,7 @@ exit: * ******************************************************************************/ -acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) +acpi_status acpi_ps_execute_method(struct acpi_evaluate_info * info) { acpi_status status; union acpi_parse_object *op; @@ -243,10 +146,6 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) */ acpi_ps_update_parameter_list(info, REF_INCREMENT); - /* Begin tracing if requested */ - - acpi_ps_start_trace(info); - /* * Execute the method. Performs parse simultaneously */ @@ -326,10 +225,6 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) cleanup: acpi_ps_delete_parse_tree(op); - /* End optional tracing */ - - acpi_ps_stop_trace(info); - /* Take away the extra reference that we gave the parameters above */ acpi_ps_update_parameter_list(info, REF_DECREMENT); diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index e402e07b48466..7f897c63aa5be 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -204,8 +204,6 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_acpi_hardware_present = TRUE; acpi_gbl_last_owner_id_index = 0; acpi_gbl_next_owner_id_offset = 0; - acpi_gbl_trace_dbg_level = 0; - acpi_gbl_trace_dbg_layer = 0; acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_osi_mutex = NULL; acpi_gbl_reg_methods_executed = FALSE; diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 8f89df9c7295b..37f46d49a74a6 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -184,6 +184,19 @@ #define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) #define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) +/* + * Global trace flags + */ +#define ACPI_TRACE_ENABLED ((u32) 2) +#define ACPI_TRACE_ONESHOT ((u32) 1) + +/* Defaults for trace debugging level/layer */ + +#define ACPI_TRACE_LEVEL_ALL ACPI_LV_ALL +#define ACPI_TRACE_LAYER_ALL 0x000001FF +#define ACPI_TRACE_LEVEL_DEFAULT ACPI_LV_TRACE_POINT +#define ACPI_TRACE_LAYER_DEFAULT ACPI_EXECUTER + #if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) /* * The module name is used primarily for error and debug messages. diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index e8ec18a4a634d..9c362cf142641 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -251,7 +251,9 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_reduced_hardware, FALSE); * traced each time it is executed. */ ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_flags, 0); -ACPI_INIT_GLOBAL(acpi_name, acpi_gbl_trace_method_name, 0); +ACPI_INIT_GLOBAL(const char *, acpi_gbl_trace_method_name, NULL); +ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_level, ACPI_TRACE_LEVEL_DEFAULT); +ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_layer, ACPI_TRACE_LAYER_DEFAULT); /* * Runtime configuration of debug output control masks. We want the debug @@ -504,7 +506,7 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_object_handler handler, void **data)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_debug_trace(char *name, u32 debug_level, + acpi_debug_trace(const char *name, u32 debug_level, u32 debug_layer, u32 flags)) /* -- GitLab From bab0482418885627babfd1a6ca4e57a809712474 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:07 +0800 Subject: [PATCH 1608/7006] ACPICA: Executer: Add OSL trace hook support ACPICA commit e8e4a9b19d0b72a7b165398bdc961fc2f6f502ec This patch adds OSL trace hook support. OSPMs are encouraged to use acpi_os_trace_point() with ACPI_USE_SYSTEM_TRACER defined to implement platform specific trace facility. Lv Zheng. Link: https://github.com/acpica/acpica/commit/e8e4a9b1 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acinterp.h | 4 ++ drivers/acpi/acpica/exdebug.c | 125 +++++++++++++++++++++++---------- drivers/acpi/acpica/utdebug.c | 31 +++++++- include/acpi/acoutput.h | 3 + include/acpi/acpiosxf.h | 6 ++ include/acpi/acpixf.h | 5 ++ include/acpi/actypes.h | 8 +++ 7 files changed, 144 insertions(+), 38 deletions(-) diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h index a3c6e2ab93bb4..e820ed8f173f0 100644 --- a/drivers/acpi/acpica/acinterp.h +++ b/drivers/acpi/acpica/acinterp.h @@ -149,6 +149,10 @@ void acpi_ex_stop_trace_opcode(union acpi_parse_object *op, struct acpi_walk_state *walk_state); +void +acpi_ex_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname); + /* * exfield - ACPI AML (p-code) execution - field manipulation */ diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 00ba9fc85f473..708b2aed0145a 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -52,6 +52,12 @@ ACPI_MODULE_NAME("exdebug") static union acpi_operand_object *acpi_gbl_trace_method_object = NULL; +/* Local prototypes */ + +#ifdef ACPI_DEBUG_OUTPUT +static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type); +#endif + #ifndef ACPI_NO_ERROR_MESSAGES /******************************************************************************* * @@ -363,6 +369,78 @@ static u8 acpi_ex_interpreter_trace_enabled(char *name) return (TRUE); } +/******************************************************************************* + * + * FUNCTION: acpi_ex_get_trace_event_name + * + * PARAMETERS: type - Trace event type + * + * RETURN: Trace event name. + * + * DESCRIPTION: Used to obtain the full trace event name. + * + ******************************************************************************/ + +#ifdef ACPI_DEBUG_OUTPUT + +static const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type) +{ + switch (type) { + case ACPI_TRACE_AML_METHOD: + + return "Method"; + + case ACPI_TRACE_AML_OPCODE: + + return "Opcode"; + + case ACPI_TRACE_AML_REGION: + + return "Region"; + + default: + + return ""; + } +} + +#endif + +/******************************************************************************* + * + * FUNCTION: acpi_ex_trace_point + * + * PARAMETERS: type - Trace event type + * begin - TRUE if before execution + * aml - Executed AML address + * pathname - Object path + * + * RETURN: None + * + * DESCRIPTION: Internal interpreter execution trace. + * + ******************************************************************************/ + +void +acpi_ex_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname) +{ + + ACPI_FUNCTION_NAME(ex_trace_point); + + if (pathname) { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "%s %s [0x%p:%s] execution.\n", + acpi_ex_get_trace_event_name(type), + begin ? "Begin" : "End", aml, pathname)); + } else { + ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, + "%s %s [0x%p] execution.\n", + acpi_ex_get_trace_event_name(type), + begin ? "Begin" : "End", aml)); + } +} + /******************************************************************************* * * FUNCTION: acpi_ex_start_trace_method @@ -417,16 +495,9 @@ acpi_ex_start_trace_method(struct acpi_namespace_node *method_node, exit: if (enabled) { - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p:%s] execution.\n", - obj_desc->method.aml_start, - pathname)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin method [0x%p] execution.\n", - obj_desc->method.aml_start)); - } + ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE, + obj_desc ? obj_desc->method.aml_start : NULL, + pathname); } if (pathname) { ACPI_FREE(pathname); @@ -473,16 +544,9 @@ acpi_ex_stop_trace_method(struct acpi_namespace_node *method_node, (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); if (enabled) { - if (pathname) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p:%s] execution.\n", - obj_desc->method.aml_start, - pathname)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End method [0x%p] execution.\n", - obj_desc->method.aml_start)); - } + ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE, + obj_desc ? obj_desc->method.aml_start : NULL, + pathname); } status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); @@ -535,20 +599,8 @@ acpi_ex_start_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_start_trace_opcode); if (acpi_ex_interpreter_trace_enabled(NULL)) { - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p] Class=0x%02x, Type=0x%02x, Flags=0x%04x.\n", - op->common.aml_op_name, - op->common.aml, - walk_state->op_info->class, - walk_state->op_info->type, - walk_state->op_info->flags)); - } else { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "Begin opcode: %s[0x%p].\n", - op->common.aml_op_name, - op->common.aml)); - } + ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, + op->common.aml, op->common.aml_op_name); } } @@ -574,8 +626,7 @@ acpi_ex_stop_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_stop_trace_opcode); if (acpi_ex_interpreter_trace_enabled(NULL)) { - ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT, - "End opcode: %s[0x%p].\n", - op->common.aml_op_name, op->common.aml)); + ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, + op->common.aml, op->common.aml_op_name); } } diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c index cd02693841db0..4146229103c82 100644 --- a/drivers/acpi/acpica/utdebug.c +++ b/drivers/acpi/acpica/utdebug.c @@ -45,6 +45,7 @@ #include #include "accommon.h" +#include "acinterp.h" #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utdebug") @@ -560,8 +561,37 @@ acpi_ut_ptr_exit(u32 line_number, } } +/******************************************************************************* + * + * FUNCTION: acpi_trace_point + * + * PARAMETERS: type - Trace event type + * begin - TRUE if before execution + * aml - Executed AML address + * pathname - Object path + * pointer - Pointer to the related object + * + * RETURN: None + * + * DESCRIPTION: Interpreter execution trace. + * + ******************************************************************************/ + +void +acpi_trace_point(acpi_trace_event_type type, u8 begin, u8 *aml, char *pathname) +{ + + ACPI_FUNCTION_ENTRY(); + + acpi_ex_trace_point(type, begin, aml, pathname); + +#ifdef ACPI_USE_SYSTEM_TRACER + acpi_os_trace_point(type, begin, aml, pathname); #endif +} +ACPI_EXPORT_SYMBOL(acpi_trace_point) +#endif #ifdef ACPI_APPLICATION /******************************************************************************* * @@ -575,7 +605,6 @@ acpi_ut_ptr_exit(u32 line_number, * DESCRIPTION: Print error message to the console, used by applications. * ******************************************************************************/ - void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...) { va_list args; diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 37f46d49a74a6..c3f0ac135f682 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -447,6 +447,8 @@ #define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) #define ACPI_DUMP_BUFFER(a, b) acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) +#define ACPI_TRACE_POINT(a, b, c, d) acpi_trace_point (a, b, c, d) + #else /* ACPI_DEBUG_OUTPUT */ /* * This is the non-debug case -- make everything go away, @@ -468,6 +470,7 @@ #define ACPI_DUMP_PATHNAME(a, b, c, d) #define ACPI_DUMP_BUFFER(a, b) #define ACPI_IS_DEBUG_ENABLED(level, component) 0 +#define ACPI_TRACE_POINT(a, b, c, d) /* Return macros must have a return statement at the minimum */ diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h index d02df0a49d980..a54ad1cc990c6 100644 --- a/include/acpi/acpiosxf.h +++ b/include/acpi/acpiosxf.h @@ -430,4 +430,10 @@ long acpi_os_get_file_offset(ACPI_FILE file); acpi_status acpi_os_set_file_offset(ACPI_FILE file, long offset, u8 from); #endif +#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_trace_point +void +acpi_os_trace_point(acpi_trace_event_type type, + u8 begin, u8 *aml, char *pathname); +#endif + #endif /* __ACPIOSXF_H__ */ diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9c362cf142641..9aa27a3e3716d 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -909,6 +909,11 @@ ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) const char *module_name, u32 component_id, const char *format, ...)) + +ACPI_DBG_DEPENDENT_RETURN_VOID(void + acpi_trace_point(acpi_trace_event_type type, + u8 begin, + u8 *aml, char *pathname)) ACPI_APP_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(1) void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...)) diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 0f3913f9a377a..531eca49edd43 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -1247,6 +1247,14 @@ struct acpi_memory_list { #endif }; +/* Definitions of trace event types */ + +typedef enum { + ACPI_TRACE_AML_METHOD, + ACPI_TRACE_AML_OPCODE, + ACPI_TRACE_AML_REGION +} acpi_trace_event_type; + /* Definitions of _OSI support */ #define ACPI_VENDOR_STRINGS 0x01 -- GitLab From fb18e8fd08862f5509f3c79e168b24512c7065aa Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:15 +0800 Subject: [PATCH 1609/7006] ACPICA: Executer: Add option to bypass opcode tracing ACPICA commit 61e9e20aadfaa03184d0959fbdc1fa5cdfea2551 This patch adds option to bypass opcode tracing. The option can be used to reduce the trace message output. Lv Zheng. Link: https://github.com/acpica/acpica/commit/61e9e20a Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exdebug.c | 6 ++++-- include/acpi/acoutput.h | 5 +++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c index 708b2aed0145a..de92458236f56 100644 --- a/drivers/acpi/acpica/exdebug.c +++ b/drivers/acpi/acpica/exdebug.c @@ -598,7 +598,8 @@ acpi_ex_start_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_start_trace_opcode); - if (acpi_ex_interpreter_trace_enabled(NULL)) { + if (acpi_ex_interpreter_trace_enabled(NULL) && + (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE, op->common.aml, op->common.aml_op_name); } @@ -625,7 +626,8 @@ acpi_ex_stop_trace_opcode(union acpi_parse_object *op, ACPI_FUNCTION_NAME(ex_stop_trace_opcode); - if (acpi_ex_interpreter_trace_enabled(NULL)) { + if (acpi_ex_interpreter_trace_enabled(NULL) && + (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) { ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE, op->common.aml, op->common.aml_op_name); } diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index c3f0ac135f682..908d4f9c348cc 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h @@ -187,8 +187,9 @@ /* * Global trace flags */ -#define ACPI_TRACE_ENABLED ((u32) 2) -#define ACPI_TRACE_ONESHOT ((u32) 1) +#define ACPI_TRACE_ENABLED ((u32) 4) +#define ACPI_TRACE_ONESHOT ((u32) 2) +#define ACPI_TRACE_OPCODE ((u32) 1) /* Defaults for trace debugging level/layer */ -- GitLab From ec4252a66b1a2cd2fc6fbdbf3d3279640500fb75 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:22 +0800 Subject: [PATCH 1610/7006] ACPICA: Parser: Remove redundant opcode execution debugging output ACPICA commit c832b0a9263c560b3ae3ae31d7298ef33988f8d5 This patch removes one redundant debugging output of opcode execution which has already been covered by acpi_ex_start_trace_opcode(). Lv Zheng. Link: https://github.com/acpica/acpica/commit/c832b0a9 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/psloop.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index a7de52ee15383..6b11fd7a93dc2 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -491,14 +491,6 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state) continue; } - if (walk_state->op_info) { - ACPI_DEBUG_PRINT((ACPI_DB_PARSE, - "Opcode %4.4X [%s] Op %p Aml %p\n", - (u32)op->common.aml_opcode, - walk_state->op_info->name, op, - op->common.aml)); - } - acpi_ex_start_trace_opcode(op, walk_state); } -- GitLab From dc67d0fa8612ad49a8ec36040c5d22a9091bdbf6 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 23 Jul 2015 12:53:28 +0800 Subject: [PATCH 1611/7006] ACPICA: Remove extraneous check for null walk_state ACPICA commit f9fd6e8bad0f16ce2b436c5cda36ced0c2d85302 Reported by Markus Elfring. Link: https://github.com/acpica/acpica/commit/f9fd6e8b Signed-off-by: Markus Elfring Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsmethod.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index ea2bdde1227ef..cb53c44c9644c 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -582,9 +582,7 @@ cleanup: /* On error, we must terminate the method properly */ acpi_ds_terminate_control_method(obj_desc, next_walk_state); - if (next_walk_state) { - acpi_ds_delete_walk_state(next_walk_state); - } + acpi_ds_delete_walk_state(next_walk_state); return_ACPI_STATUS(status); } -- GitLab From 53d9edce56de3eb495a3eef77e973e3ea014d999 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:53:35 +0800 Subject: [PATCH 1612/7006] ACPICA: iASL: Add new warnings for method local_x and arg_x variables ACPICA commit eb9f8cb9fd65f1149dd335d05944c31cbca41af3 1) Warn if a Local is set but never used 2) Warn if a arg_x is never used (for non-predefined method names) 3) Warn if a arg_x that is used as a local is never used This patch only affects iASL which is not in the kernel source tree. Link: https://github.com/acpica/acpica/commit/eb9f8cb9 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 610d001fbb31d..4758185b2b0ba 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -174,8 +174,12 @@ struct acpi_namespace_node { */ #ifdef ACPI_LARGE_NAMESPACE_NODE union acpi_parse_object *op; + void *method_locals; + void *method_args; u32 value; u32 length; + u8 arg_count; + #endif }; -- GitLab From 5a4f0693a586d73a65ccc7959e81a5618de265fe Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:53:42 +0800 Subject: [PATCH 1613/7006] ACPICA: MSVC: Fix inclusion order issue of ACPICA commit 49c6a6517a906900e9baa51ad5859beeb8a3089f The following error logs can be seen for calloc/free/malloc/realloc that defined in the stdlib.h: ...\stdlib.h(281) : error C2059: syntax error : ',' ...\stdlib.h(281) : error C2143: syntax error : missing ')' before 'constant' ...\stdlib.h(281) : error C2143: syntax error : missing '{' before 'constant' ...\stdlib.h(281) : error C2059: syntax error : '' ...\stdlib.h(281) : error C2059: syntax error : ')' This is caused by the wrong inclusion order of stdlib.h/crtdbg.h introduced in acenv.h. This patch fixes this breakage. Lv Zheng. This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/49c6a651 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acenvex.h | 3 ++ include/acpi/platform/acmsvcex.h | 54 ++++++++++++++++++++++++++++++++ include/acpi/platform/acwinex.h | 49 +++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 include/acpi/platform/acmsvcex.h create mode 100644 include/acpi/platform/acwinex.h diff --git a/include/acpi/platform/acenvex.h b/include/acpi/platform/acenvex.h index 0a7dc8e583b1c..2f296cb5f7e2e 100644 --- a/include/acpi/platform/acenvex.h +++ b/include/acpi/platform/acenvex.h @@ -56,6 +56,9 @@ #if defined(_LINUX) || defined(__linux__) #include +#elif defined(WIN32) +#include "acwinex.h" + #elif defined(_AED_EFI) #include "acefiex.h" diff --git a/include/acpi/platform/acmsvcex.h b/include/acpi/platform/acmsvcex.h new file mode 100644 index 0000000000000..b64797488775b --- /dev/null +++ b/include/acpi/platform/acmsvcex.h @@ -0,0 +1,54 @@ +/****************************************************************************** + * + * Name: acmsvcex.h - Extra VC specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACMSVCEX_H__ +#define __ACMSVCEX_H__ + +/* Debug support. */ + +#ifdef _DEBUG +#define _CRTDBG_MAP_ALLOC /* Enables specific file/lineno for leaks */ +#include +#endif + +#endif /* __ACMSVCEX_H__ */ diff --git a/include/acpi/platform/acwinex.h b/include/acpi/platform/acwinex.h new file mode 100644 index 0000000000000..6ed1d713509b3 --- /dev/null +++ b/include/acpi/platform/acwinex.h @@ -0,0 +1,49 @@ +/****************************************************************************** + * + * Name: acwinex.h - Extra OS specific defines, etc. + * + *****************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#ifndef __ACWINEX_H__ +#define __ACWINEX_H__ + +/* Windows uses VC */ + +#endif /* __ACWINEX_H__ */ -- GitLab From 276291962ebf43abebb491ddcd922009de9fde4b Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:53:49 +0800 Subject: [PATCH 1614/7006] ACPICA: Cleanup use of all non-ANSI local C library functions ACPICA commit 7c490c28a18b435c543c6b410e7e7c2131fccc78 ACPICA implements all non-ANSI functions locally. However, there are sometimes two or more versions of the same function throughout the ACPICA code. This change fixes this. Adds a new file, utilities/utnonansi.c Link: https://github.com/acpica/acpica/commit/7c490c28 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/Makefile | 1 + drivers/acpi/acpica/acmacros.h | 4 + drivers/acpi/acpica/acutils.h | 23 +- drivers/acpi/acpica/utnonansi.c | 380 ++++++++++++++++++++++++++++++++ drivers/acpi/acpica/utstring.c | 342 ---------------------------- 5 files changed, 396 insertions(+), 354 deletions(-) create mode 100644 drivers/acpi/acpica/utnonansi.c diff --git a/drivers/acpi/acpica/Makefile b/drivers/acpi/acpica/Makefile index 9f30ed7b1a07c..fedcc16b56cc5 100644 --- a/drivers/acpi/acpica/Makefile +++ b/drivers/acpi/acpica/Makefile @@ -165,6 +165,7 @@ acpi-y += \ utmath.o \ utmisc.o \ utmutex.o \ + utnonansi.o \ utobject.o \ utosi.o \ utownerid.o \ diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index c240bdf824f26..19d40c6c1f326 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -220,6 +220,10 @@ #define ACPI_MUL_32(a) _ACPI_MUL(a, 5) #define ACPI_MOD_32(a) _ACPI_MOD(a, 32) +/* Test for ASCII character */ + +#define ACPI_IS_ASCII(c) ((c) < 0x80) + /* * Rounding macros (Power of two boundaries only) */ diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 6de0d3573037a..566ff4df02fd4 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -166,6 +166,17 @@ struct acpi_pkg_info { #define DB_DWORD_DISPLAY 4 #define DB_QWORD_DISPLAY 8 +/* + * utnonansi - Non-ANSI C library functions + */ +void acpi_ut_strupr(char *src_string); + +void acpi_ut_strlwr(char *src_string); + +int acpi_ut_stricmp(char *string1, char *string2); + +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); + /* * utglobal - Global data structures and procedures */ @@ -205,8 +216,6 @@ acpi_status acpi_ut_hardware_initialize(void); void acpi_ut_subsystem_shutdown(void); -#define ACPI_IS_ASCII(c) ((c) < 0x80) - /* * utcopy - Object construction and conversion interfaces */ @@ -567,16 +576,6 @@ acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag); /* * utstring - String and character utilities */ -void acpi_ut_strupr(char *src_string); - -#ifdef ACPI_ASL_COMPILER -void acpi_ut_strlwr(char *src_string); - -int acpi_ut_stricmp(char *string1, char *string2); -#endif - -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer); - void acpi_ut_print_string(char *string, u16 max_length); #if defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP diff --git a/drivers/acpi/acpica/utnonansi.c b/drivers/acpi/acpica/utnonansi.c new file mode 100644 index 0000000000000..1d5f6b17b7664 --- /dev/null +++ b/drivers/acpi/acpica/utnonansi.c @@ -0,0 +1,380 @@ +/******************************************************************************* + * + * Module Name: utnonansi - Non-ansi C library functions + * + ******************************************************************************/ + +/* + * Copyright (C) 2000 - 2015, Intel Corp. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * substantially similar to the "NO WARRANTY" disclaimer below + * ("Disclaimer") and any redistribution must be conditioned upon + * including a substantially similar Disclaimer requirement for further + * binary redistribution. + * 3. Neither the names of the above-listed copyright holders nor the names + * of any contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGES. + */ + +#include +#include "accommon.h" + +#define _COMPONENT ACPI_UTILITIES +ACPI_MODULE_NAME("utnonansi") + +/* + * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit + * version of strtoul. + */ +/******************************************************************************* + * + * FUNCTION: acpi_ut_strlwr (strlwr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert a string to lowercase + * + ******************************************************************************/ +void acpi_ut_strlwr(char *src_string) +{ + char *string; + + ACPI_FUNCTION_ENTRY(); + + if (!src_string) { + return; + } + + /* Walk entire string, lowercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char)tolower((int)*string); + } +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strupr (strupr) + * + * PARAMETERS: src_string - The source string to convert + * + * RETURN: None + * + * DESCRIPTION: Convert a string to uppercase + * + ******************************************************************************/ + +void acpi_ut_strupr(char *src_string) +{ + char *string; + + ACPI_FUNCTION_ENTRY(); + + if (!src_string) { + return; + } + + /* Walk entire string, uppercasing the letters */ + + for (string = src_string; *string; string++) { + *string = (char)toupper((int)*string); + } +} + +/****************************************************************************** + * + * FUNCTION: acpi_ut_stricmp (stricmp) + * + * PARAMETERS: string1 - first string to compare + * string2 - second string to compare + * + * RETURN: int that signifies string relationship. Zero means strings + * are equal. + * + * DESCRIPTION: Case-insensitive string compare. Implementation of the + * non-ANSI stricmp function. + * + ******************************************************************************/ + +int acpi_ut_stricmp(char *string1, char *string2) +{ + int c1; + int c2; + + do { + c1 = tolower((int)*string1); + c2 = tolower((int)*string2); + + string1++; + string2++; + } + while ((c1 == c2) && (c1)); + + return (c1 - c2); +} + +/******************************************************************************* + * + * FUNCTION: acpi_ut_strtoul64 + * + * PARAMETERS: string - Null terminated string + * base - Radix of the string: 16 or ACPI_ANY_BASE; + * ACPI_ANY_BASE means 'in behalf of to_integer' + * ret_integer - Where the converted integer is returned + * + * RETURN: Status and Converted value + * + * DESCRIPTION: Convert a string into an unsigned value. Performs either a + * 32-bit or 64-bit conversion, depending on the current mode + * of the interpreter. + * + * NOTE: Does not support Octal strings, not needed. + * + ******************************************************************************/ + +acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) +{ + u32 this_digit = 0; + u64 return_value = 0; + u64 quotient; + u64 dividend; + u32 to_integer_op = (base == ACPI_ANY_BASE); + u32 mode32 = (acpi_gbl_integer_byte_width == 4); + u8 valid_digits = 0; + u8 sign_of0x = 0; + u8 term = 0; + + ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); + + switch (base) { + case ACPI_ANY_BASE: + case 16: + + break; + + default: + + /* Invalid Base */ + + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + if (!string) { + goto error_exit; + } + + /* Skip over any white space in the buffer */ + + while ((*string) && (isspace((int)*string) || *string == '\t')) { + string++; + } + + if (to_integer_op) { + /* + * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. + * We need to determine if it is decimal or hexadecimal. + */ + if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { + sign_of0x = 1; + base = 16; + + /* Skip over the leading '0x' */ + string += 2; + } else { + base = 10; + } + } + + /* Any string left? Check that '0x' is not followed by white space. */ + + if (!(*string) || isspace((int)*string) || *string == '\t') { + if (to_integer_op) { + goto error_exit; + } else { + goto all_done; + } + } + + /* + * Perform a 32-bit or 64-bit conversion, depending upon the current + * execution mode of the interpreter + */ + dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; + + /* Main loop: convert the string to a 32- or 64-bit integer */ + + while (*string) { + if (isdigit((int)*string)) { + + /* Convert ASCII 0-9 to Decimal value */ + + this_digit = ((u8)*string) - '0'; + } else if (base == 10) { + + /* Digit is out of range; possible in to_integer case only */ + + term = 1; + } else { + this_digit = (u8)toupper((int)*string); + if (isxdigit((int)this_digit)) { + + /* Convert ASCII Hex char to value */ + + this_digit = this_digit - 'A' + 10; + } else { + term = 1; + } + } + + if (term) { + if (to_integer_op) { + goto error_exit; + } else { + break; + } + } else if ((valid_digits == 0) && (this_digit == 0) + && !sign_of0x) { + + /* Skip zeros */ + string++; + continue; + } + + valid_digits++; + + if (sign_of0x + && ((valid_digits > 16) + || ((valid_digits > 8) && mode32))) { + /* + * This is to_integer operation case. + * No any restrictions for string-to-integer conversion, + * see ACPI spec. + */ + goto error_exit; + } + + /* Divide the digit into the correct position */ + + (void)acpi_ut_short_divide((dividend - (u64)this_digit), + base, "ient, NULL); + + if (return_value > quotient) { + if (to_integer_op) { + goto error_exit; + } else { + break; + } + } + + return_value *= base; + return_value += this_digit; + string++; + } + + /* All done, normal exit */ + +all_done: + + ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", + ACPI_FORMAT_UINT64(return_value))); + + *ret_integer = return_value; + return_ACPI_STATUS(AE_OK); + +error_exit: + /* Base was set/validated above */ + + if (base == 10) { + return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT); + } else { + return_ACPI_STATUS(AE_BAD_HEX_CONSTANT); + } +} + +#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) +/******************************************************************************* + * + * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat + * + * PARAMETERS: Adds a "DestSize" parameter to each of the standard string + * functions. This is the size of the Destination buffer. + * + * RETURN: TRUE if the operation would overflow the destination buffer. + * + * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that + * the result of the operation will not overflow the output string + * buffer. + * + * NOTE: These functions are typically only helpful for processing + * user input and command lines. For most ACPICA code, the + * required buffer length is precisely calculated before buffer + * allocation, so the use of these functions is unnecessary. + * + ******************************************************************************/ + +u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) +{ + + if (strlen(source) >= dest_size) { + return (TRUE); + } + + strcpy(dest, source); + return (FALSE); +} + +u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) +{ + + if ((strlen(dest) + strlen(source)) >= dest_size) { + return (TRUE); + } + + strcat(dest, source); + return (FALSE); +} + +u8 +acpi_ut_safe_strncat(char *dest, + acpi_size dest_size, + char *source, acpi_size max_transfer_length) +{ + acpi_size actual_transfer_length; + + actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); + + if ((strlen(dest) + actual_transfer_length) >= dest_size) { + return (TRUE); + } + + strncat(dest, source, max_transfer_length); + return (FALSE); +} +#endif diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c index 8f3c883dfe0ec..4ddd105d9741c 100644 --- a/drivers/acpi/acpica/utstring.c +++ b/drivers/acpi/acpica/utstring.c @@ -48,286 +48,6 @@ #define _COMPONENT ACPI_UTILITIES ACPI_MODULE_NAME("utstring") -/* - * Non-ANSI C library functions - strlwr, strupr, stricmp, and a 64-bit - * version of strtoul. - */ -#ifdef ACPI_ASL_COMPILER -/******************************************************************************* - * - * FUNCTION: acpi_ut_strlwr (strlwr) - * - * PARAMETERS: src_string - The source string to convert - * - * RETURN: None - * - * DESCRIPTION: Convert string to lowercase - * - * NOTE: This is not a POSIX function, so it appears here, not in utclib.c - * - ******************************************************************************/ -void acpi_ut_strlwr(char *src_string) -{ - char *string; - - ACPI_FUNCTION_ENTRY(); - - if (!src_string) { - return; - } - - /* Walk entire string, lowercasing the letters */ - - for (string = src_string; *string; string++) { - *string = (char)tolower((int)*string); - } - - return; -} - -/****************************************************************************** - * - * FUNCTION: acpi_ut_stricmp (stricmp) - * - * PARAMETERS: string1 - first string to compare - * string2 - second string to compare - * - * RETURN: int that signifies string relationship. Zero means strings - * are equal. - * - * DESCRIPTION: Implementation of the non-ANSI stricmp function (compare - * strings with no case sensitivity) - * - ******************************************************************************/ - -int acpi_ut_stricmp(char *string1, char *string2) -{ - int c1; - int c2; - - do { - c1 = tolower((int)*string1); - c2 = tolower((int)*string2); - - string1++; - string2++; - } - while ((c1 == c2) && (c1)); - - return (c1 - c2); -} -#endif - -/******************************************************************************* - * - * FUNCTION: acpi_ut_strupr (strupr) - * - * PARAMETERS: src_string - The source string to convert - * - * RETURN: None - * - * DESCRIPTION: Convert string to uppercase - * - * NOTE: This is not a POSIX function, so it appears here, not in utclib.c - * - ******************************************************************************/ - -void acpi_ut_strupr(char *src_string) -{ - char *string; - - ACPI_FUNCTION_ENTRY(); - - if (!src_string) { - return; - } - - /* Walk entire string, uppercasing the letters */ - - for (string = src_string; *string; string++) { - *string = (char)toupper((int)*string); - } - - return; -} - -/******************************************************************************* - * - * FUNCTION: acpi_ut_strtoul64 - * - * PARAMETERS: string - Null terminated string - * base - Radix of the string: 16 or ACPI_ANY_BASE; - * ACPI_ANY_BASE means 'in behalf of to_integer' - * ret_integer - Where the converted integer is returned - * - * RETURN: Status and Converted value - * - * DESCRIPTION: Convert a string into an unsigned value. Performs either a - * 32-bit or 64-bit conversion, depending on the current mode - * of the interpreter. - * NOTE: Does not support Octal strings, not needed. - * - ******************************************************************************/ - -acpi_status acpi_ut_strtoul64(char *string, u32 base, u64 *ret_integer) -{ - u32 this_digit = 0; - u64 return_value = 0; - u64 quotient; - u64 dividend; - u32 to_integer_op = (base == ACPI_ANY_BASE); - u32 mode32 = (acpi_gbl_integer_byte_width == 4); - u8 valid_digits = 0; - u8 sign_of0x = 0; - u8 term = 0; - - ACPI_FUNCTION_TRACE_STR(ut_stroul64, string); - - switch (base) { - case ACPI_ANY_BASE: - case 16: - - break; - - default: - - /* Invalid Base */ - - return_ACPI_STATUS(AE_BAD_PARAMETER); - } - - if (!string) { - goto error_exit; - } - - /* Skip over any white space in the buffer */ - - while ((*string) && (isspace((int)*string) || *string == '\t')) { - string++; - } - - if (to_integer_op) { - /* - * Base equal to ACPI_ANY_BASE means 'ToInteger operation case'. - * We need to determine if it is decimal or hexadecimal. - */ - if ((*string == '0') && (tolower((int)*(string + 1)) == 'x')) { - sign_of0x = 1; - base = 16; - - /* Skip over the leading '0x' */ - string += 2; - } else { - base = 10; - } - } - - /* Any string left? Check that '0x' is not followed by white space. */ - - if (!(*string) || isspace((int)*string) || *string == '\t') { - if (to_integer_op) { - goto error_exit; - } else { - goto all_done; - } - } - - /* - * Perform a 32-bit or 64-bit conversion, depending upon the current - * execution mode of the interpreter - */ - dividend = (mode32) ? ACPI_UINT32_MAX : ACPI_UINT64_MAX; - - /* Main loop: convert the string to a 32- or 64-bit integer */ - - while (*string) { - if (isdigit((int)*string)) { - - /* Convert ASCII 0-9 to Decimal value */ - - this_digit = ((u8)*string) - '0'; - } else if (base == 10) { - - /* Digit is out of range; possible in to_integer case only */ - - term = 1; - } else { - this_digit = (u8)toupper((int)*string); - if (isxdigit((int)this_digit)) { - - /* Convert ASCII Hex char to value */ - - this_digit = this_digit - 'A' + 10; - } else { - term = 1; - } - } - - if (term) { - if (to_integer_op) { - goto error_exit; - } else { - break; - } - } else if ((valid_digits == 0) && (this_digit == 0) - && !sign_of0x) { - - /* Skip zeros */ - string++; - continue; - } - - valid_digits++; - - if (sign_of0x - && ((valid_digits > 16) - || ((valid_digits > 8) && mode32))) { - /* - * This is to_integer operation case. - * No any restrictions for string-to-integer conversion, - * see ACPI spec. - */ - goto error_exit; - } - - /* Divide the digit into the correct position */ - - (void)acpi_ut_short_divide((dividend - (u64)this_digit), - base, "ient, NULL); - - if (return_value > quotient) { - if (to_integer_op) { - goto error_exit; - } else { - break; - } - } - - return_value *= base; - return_value += this_digit; - string++; - } - - /* All done, normal exit */ - -all_done: - - ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n", - ACPI_FORMAT_UINT64(return_value))); - - *ret_integer = return_value; - return_ACPI_STATUS(AE_OK); - -error_exit: - /* Base was set/validated above */ - - if (base == 10) { - return_ACPI_STATUS(AE_BAD_DECIMAL_CONSTANT); - } else { - return_ACPI_STATUS(AE_BAD_HEX_CONSTANT); - } -} - /******************************************************************************* * * FUNCTION: acpi_ut_print_string @@ -342,7 +62,6 @@ error_exit: * sequences. * ******************************************************************************/ - void acpi_ut_print_string(char *string, u16 max_length) { u32 i; @@ -584,64 +303,3 @@ void ut_convert_backslashes(char *pathname) } } #endif - -#if defined (ACPI_DEBUGGER) || defined (ACPI_APPLICATION) -/******************************************************************************* - * - * FUNCTION: acpi_ut_safe_strcpy, acpi_ut_safe_strcat, acpi_ut_safe_strncat - * - * PARAMETERS: Adds a "DestSize" parameter to each of the standard string - * functions. This is the size of the Destination buffer. - * - * RETURN: TRUE if the operation would overflow the destination buffer. - * - * DESCRIPTION: Safe versions of standard Clib string functions. Ensure that - * the result of the operation will not overflow the output string - * buffer. - * - * NOTE: These functions are typically only helpful for processing - * user input and command lines. For most ACPICA code, the - * required buffer length is precisely calculated before buffer - * allocation, so the use of these functions is unnecessary. - * - ******************************************************************************/ - -u8 acpi_ut_safe_strcpy(char *dest, acpi_size dest_size, char *source) -{ - - if (strlen(source) >= dest_size) { - return (TRUE); - } - - strcpy(dest, source); - return (FALSE); -} - -u8 acpi_ut_safe_strcat(char *dest, acpi_size dest_size, char *source) -{ - - if ((strlen(dest) + strlen(source)) >= dest_size) { - return (TRUE); - } - - strcat(dest, source); - return (FALSE); -} - -u8 -acpi_ut_safe_strncat(char *dest, - acpi_size dest_size, - char *source, acpi_size max_transfer_length) -{ - acpi_size actual_transfer_length; - - actual_transfer_length = ACPI_MIN(max_transfer_length, strlen(source)); - - if ((strlen(dest) + actual_transfer_length) >= dest_size) { - return (TRUE); - } - - strncat(dest, source, max_transfer_length); - return (FALSE); -} -#endif -- GitLab From 88606a2b9020993a776df894941b3b07cc1374fe Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:53:57 +0800 Subject: [PATCH 1615/7006] ACPICA: Cleanup use of NEGATIVE and POSITIVE defines ACPICA commit f88814201e01043a4f8caa69a69b799af11c44a3 These were defined in two places. Changed to ACPI_SIGN* names and define them once in acmacros.h This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/f8881420 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acmacros.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h index 19d40c6c1f326..e85366ceb15a2 100644 --- a/drivers/acpi/acpica/acmacros.h +++ b/drivers/acpi/acpica/acmacros.h @@ -224,6 +224,11 @@ #define ACPI_IS_ASCII(c) ((c) < 0x80) +/* Signed integers */ + +#define ACPI_SIGN_POSITIVE 0 +#define ACPI_SIGN_NEGATIVE 1 + /* * Rounding macros (Power of two boundaries only) */ -- GitLab From 15a61aa19dad8dedb137c216c13ba18ad6f59674 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:54:04 +0800 Subject: [PATCH 1616/7006] ACPICA: iASL: Add support for TCPA Server Table ACPICA commit 55fa9555c71eaa99daebed4cd82cfde3875e8c45 In addition to the existing support for the client table. Link: https://github.com/acpica/acpica/commit/55fa9555 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/actbl2.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h index a948fc586b9b8..6e28f544b7b23 100644 --- a/include/acpi/actbl2.h +++ b/include/acpi/actbl2.h @@ -1186,20 +1186,29 @@ enum acpi_spmi_interface_types { * December 19, 2014 * * NOTE: There are two versions of the table with the same signature -- - * the client version and the server version. + * the client version and the server version. The common platform_class + * field is used to differentiate the two types of tables. * ******************************************************************************/ -struct acpi_table_tcpa_client { +struct acpi_table_tcpa_hdr { struct acpi_table_header header; /* Common ACPI table header */ u16 platform_class; +}; + +/* + * Values for platform_class above. + * This is how the client and server subtables are differentiated + */ +#define ACPI_TCPA_CLIENT_TABLE 0 +#define ACPI_TCPA_SERVER_TABLE 1 + +struct acpi_table_tcpa_client { u32 minimum_log_length; /* Minimum length for the event log area */ u64 log_address; /* Address of the event log area */ }; struct acpi_table_tcpa_server { - struct acpi_table_header header; /* Common ACPI table header */ - u16 platform_class; u16 reserved; u64 minimum_log_length; /* Minimum length for the event log area */ u64 log_address; /* Address of the event log area */ -- GitLab From 02ca26bef8f49a654026f56bedde2ab25e761380 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:54:11 +0800 Subject: [PATCH 1617/7006] ACPICA: Debugger: Reduce structure size for debugger ACPICA commit 310e0ae1c4730f4dadc80125125099ab76851499 arg_types in struct acpi_db_method_info is only referenced by ACPI_DEBUGGER. This patch only affects ACPICA debugger which is only used by a non-kernel tool - acpiexec, so Linux kernel is currently not affected by this patch. Link: https://github.com/acpica/acpica/commit/310e0ae1 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 4758185b2b0ba..a6b68878cdbe1 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1107,6 +1107,9 @@ struct acpi_db_method_info { * Index of current thread inside all them created. */ char init_args; +#ifdef ACPI_DEBUGGER + acpi_object_type arg_types[4]; +#endif char *arguments[4]; char num_threads_str[11]; char id_of_thread_str[11]; -- GitLab From fdd8d831cf43761712d28e5d1ad812eab7dc1480 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Thu, 23 Jul 2015 12:54:17 +0800 Subject: [PATCH 1618/7006] ACPICA: Debugger: Move debugger specific APIs to debugger component ACPICA commit 2164923d60429eea7cd5a4a8629b607af7325afa Some disassembler APIs should rather be debugger APIs. This patch moves them to the debugger folder to be ready for debugger porting. Since there is no in-kernel ACPICA debugger in the kernel source tree, this patch doesn't affect the Linux kernel. Link: https://github.com/acpica/acpica/commit/2164923d Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 17 +++++++++++++++++ drivers/acpi/acpica/dsmethod.c | 12 +++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 88482f75e9415..b5a9c5126209c 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -263,6 +263,23 @@ acpi_status acpi_db_user_commands(char prompt, union acpi_parse_object *op); char *acpi_db_get_next_token(char *string, char **next, acpi_object_type * return_type); +/* + * dbobject + */ +void acpi_db_decode_internal_object(union acpi_operand_object *obj_desc); + +void +acpi_db_display_internal_object(union acpi_operand_object *obj_desc, + struct acpi_walk_state *walk_state); + +void acpi_db_decode_arguments(struct acpi_walk_state *walk_state); + +void acpi_db_decode_locals(struct acpi_walk_state *walk_state); + +void +acpi_db_dump_method_info(acpi_status status, + struct acpi_walk_state *walk_state); + /* * dbstats - Generation and display of ACPI table statistics */ diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index cb53c44c9644c..bc32f3194afe1 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c @@ -46,11 +46,9 @@ #include "acdispat.h" #include "acinterp.h" #include "acnamesp.h" -#ifdef ACPI_DISASSEMBLER -#include "acdisasm.h" -#endif #include "acparser.h" #include "amlcode.h" +#include "acdebug.h" #define _COMPONENT ACPI_DISPATCHER ACPI_MODULE_NAME("dsmethod") @@ -205,7 +203,7 @@ acpi_ds_detect_named_opcodes(struct acpi_walk_state *walk_state, * RETURN: Status * * DESCRIPTION: Called on method error. Invoke the global exception handler if - * present, dump the method data if the disassembler is configured + * present, dump the method data if the debugger is configured * * Note: Allows the exception handler to change the status code * @@ -254,10 +252,10 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state * walk_state) if (ACPI_FAILURE(status)) { acpi_ds_dump_method_stack(status, walk_state, walk_state->op); - /* Display method locals/args if disassembler is present */ + /* Display method locals/args if debugger is present */ -#ifdef ACPI_DISASSEMBLER - acpi_dm_dump_method_info(status, walk_state); +#ifdef ACPI_DEBUGGER + acpi_db_dump_method_info(status, walk_state); #endif } -- GitLab From 6d9be0a5c459ac30a5b3e7fbe51c55f65a5f4c7c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:54:23 +0800 Subject: [PATCH 1619/7006] ACPICA: iASL/Disassembler: Add prototype verbose mode ACPICA commit add72dca18ab5d02f1bf9b08027570e58da520e8 This mode will emit AML byte code after each ASL statement. This is a prototype only and requires additional development. This patch only affects ACPICA disassembler which is not in the kernel source tree. Link: https://github.com/acpica/acpica/commit/add72dca Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 5342300719ee7..79eb35d080a02 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -307,6 +307,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); +ACPI_INIT_GLOBAL(union acpi_parse_object *, acpi_gbl_previous_op, NULL); ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose); -- GitLab From 40913fe6ea3b733564f0b580cf6c51f5d8fa8158 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Thu, 23 Jul 2015 12:54:30 +0800 Subject: [PATCH 1620/7006] ACPICA: Update version to 20150717 ACPICA commit 8580ce04c1b7aa415c364b06e79edb8aca77dded Version 20150717. Link: https://github.com/acpica/acpica/commit/8580ce04 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 9aa27a3e3716d..f2e232717770a 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20150619 +#define ACPI_CA_VERSION 0x20150717 #include #include -- GitLab From 02b0b79c30076aaa33ee9134546130eb62b88078 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:59:18 -0700 Subject: [PATCH 1621/7006] Input: pmic8xxx-pwrkey - support shutdown On pm8xxx PMICs, shutdown and restart are signaled to the PMIC via a pin called PS_HOLD. When this pin goes low, the PMIC performs a configurable power sequence. Add a .shutdown hook so that we can properly configure this power sequence for shutdown or restart depending on the system state. Signed-off-by: Stephen Boyd Reviewed-by: Bjorn Andersson Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pmic8xxx-pwrkey.c | 268 ++++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 2 deletions(-) diff --git a/drivers/input/misc/pmic8xxx-pwrkey.c b/drivers/input/misc/pmic8xxx-pwrkey.c index c4ca20e632217..3f02e0e03d128 100644 --- a/drivers/input/misc/pmic8xxx-pwrkey.c +++ b/drivers/input/misc/pmic8xxx-pwrkey.c @@ -20,17 +20,72 @@ #include #include #include +#include #define PON_CNTL_1 0x1C #define PON_CNTL_PULL_UP BIT(7) #define PON_CNTL_TRIG_DELAY_MASK (0x7) +#define PON_CNTL_1_PULL_UP_EN 0xe0 +#define PON_CNTL_1_USB_PWR_EN 0x10 +#define PON_CNTL_1_WD_EN_RESET 0x08 + +#define PM8058_SLEEP_CTRL 0x02b +#define PM8921_SLEEP_CTRL 0x10a + +#define SLEEP_CTRL_SMPL_EN_RESET 0x04 + +/* Regulator master enable addresses */ +#define REG_PM8058_VREG_EN_MSM 0x018 +#define REG_PM8058_VREG_EN_GRP_5_4 0x1c8 + +/* Regulator control registers for shutdown/reset */ +#define PM8058_S0_CTRL 0x004 +#define PM8058_S1_CTRL 0x005 +#define PM8058_S3_CTRL 0x111 +#define PM8058_L21_CTRL 0x120 +#define PM8058_L22_CTRL 0x121 + +#define PM8058_REGULATOR_ENABLE_MASK 0x80 +#define PM8058_REGULATOR_ENABLE 0x80 +#define PM8058_REGULATOR_DISABLE 0x00 +#define PM8058_REGULATOR_PULL_DOWN_MASK 0x40 +#define PM8058_REGULATOR_PULL_DOWN_EN 0x40 + +/* Buck CTRL register */ +#define PM8058_SMPS_LEGACY_VREF_SEL 0x20 +#define PM8058_SMPS_LEGACY_VPROG_MASK 0x1f +#define PM8058_SMPS_ADVANCED_BAND_MASK 0xC0 +#define PM8058_SMPS_ADVANCED_BAND_SHIFT 6 +#define PM8058_SMPS_ADVANCED_VPROG_MASK 0x3f + +/* Buck TEST2 registers for shutdown/reset */ +#define PM8058_S0_TEST2 0x084 +#define PM8058_S1_TEST2 0x085 +#define PM8058_S3_TEST2 0x11a + +#define PM8058_REGULATOR_BANK_WRITE 0x80 +#define PM8058_REGULATOR_BANK_MASK 0x70 +#define PM8058_REGULATOR_BANK_SHIFT 4 +#define PM8058_REGULATOR_BANK_SEL(n) ((n) << PM8058_REGULATOR_BANK_SHIFT) + +/* Buck TEST2 register bank 1 */ +#define PM8058_SMPS_LEGACY_VLOW_SEL 0x01 + +/* Buck TEST2 register bank 7 */ +#define PM8058_SMPS_ADVANCED_MODE_MASK 0x02 +#define PM8058_SMPS_ADVANCED_MODE 0x02 +#define PM8058_SMPS_LEGACY_MODE 0x00 /** * struct pmic8xxx_pwrkey - pmic8xxx pwrkey information * @key_press_irq: key press irq number + * @regmap: device regmap + * @shutdown_fn: shutdown configuration function */ struct pmic8xxx_pwrkey { int key_press_irq; + struct regmap *regmap; + int (*shutdown_fn)(struct pmic8xxx_pwrkey *, bool); }; static irqreturn_t pwrkey_press_irq(int irq, void *_pwr) @@ -76,6 +131,212 @@ static int __maybe_unused pmic8xxx_pwrkey_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pm8xxx_pwr_key_pm_ops, pmic8xxx_pwrkey_suspend, pmic8xxx_pwrkey_resume); +static void pmic8xxx_pwrkey_shutdown(struct platform_device *pdev) +{ + struct pmic8xxx_pwrkey *pwrkey = platform_get_drvdata(pdev); + int error; + u8 mask, val; + bool reset = system_state == SYSTEM_RESTART; + + if (pwrkey->shutdown_fn) { + error = pwrkey->shutdown_fn(pwrkey, reset); + if (error) + return; + } + + /* + * Select action to perform (reset or shutdown) when PS_HOLD goes low. + * Also ensure that KPD, CBL0, and CBL1 pull ups are enabled and that + * USB charging is enabled. + */ + mask = PON_CNTL_1_PULL_UP_EN | PON_CNTL_1_USB_PWR_EN; + mask |= PON_CNTL_1_WD_EN_RESET; + val = mask; + if (!reset) + val &= ~PON_CNTL_1_WD_EN_RESET; + + regmap_update_bits(pwrkey->regmap, PON_CNTL_1, mask, val); +} + +/* + * Set an SMPS regulator to be disabled in its CTRL register, but enabled + * in the master enable register. Also set it's pull down enable bit. + * Take care to make sure that the output voltage doesn't change if switching + * from advanced mode to legacy mode. + */ +static int pm8058_disable_smps_locally_set_pull_down(struct regmap *regmap, + u16 ctrl_addr, u16 test2_addr, u16 master_enable_addr, + u8 master_enable_bit) +{ + int error; + u8 vref_sel, vlow_sel, band, vprog, bank; + unsigned int reg; + + bank = PM8058_REGULATOR_BANK_SEL(7); + error = regmap_write(regmap, test2_addr, bank); + if (error) + return error; + + error = regmap_read(regmap, test2_addr, ®); + if (error) + return error; + + reg &= PM8058_SMPS_ADVANCED_MODE_MASK; + /* Check if in advanced mode. */ + if (reg == PM8058_SMPS_ADVANCED_MODE) { + /* Determine current output voltage. */ + error = regmap_read(regmap, ctrl_addr, ®); + if (error) + return error; + + band = reg & PM8058_SMPS_ADVANCED_BAND_MASK; + band >>= PM8058_SMPS_ADVANCED_BAND_SHIFT; + switch (band) { + case 3: + vref_sel = 0; + vlow_sel = 0; + break; + case 2: + vref_sel = PM8058_SMPS_LEGACY_VREF_SEL; + vlow_sel = 0; + break; + case 1: + vref_sel = PM8058_SMPS_LEGACY_VREF_SEL; + vlow_sel = PM8058_SMPS_LEGACY_VLOW_SEL; + break; + default: + pr_err("%s: regulator already disabled\n", __func__); + return -EPERM; + } + vprog = reg & PM8058_SMPS_ADVANCED_VPROG_MASK; + /* Round up if fine step is in use. */ + vprog = (vprog + 1) >> 1; + if (vprog > PM8058_SMPS_LEGACY_VPROG_MASK) + vprog = PM8058_SMPS_LEGACY_VPROG_MASK; + + /* Set VLOW_SEL bit. */ + bank = PM8058_REGULATOR_BANK_SEL(1); + error = regmap_write(regmap, test2_addr, bank); + if (error) + return error; + + error = regmap_update_bits(regmap, test2_addr, + PM8058_REGULATOR_BANK_WRITE | PM8058_REGULATOR_BANK_MASK + | PM8058_SMPS_LEGACY_VLOW_SEL, + PM8058_REGULATOR_BANK_WRITE | + PM8058_REGULATOR_BANK_SEL(1) | vlow_sel); + if (error) + return error; + + /* Switch to legacy mode */ + bank = PM8058_REGULATOR_BANK_SEL(7); + error = regmap_write(regmap, test2_addr, bank); + if (error) + return error; + + error = regmap_update_bits(regmap, test2_addr, + PM8058_REGULATOR_BANK_WRITE | + PM8058_REGULATOR_BANK_MASK | + PM8058_SMPS_ADVANCED_MODE_MASK, + PM8058_REGULATOR_BANK_WRITE | + PM8058_REGULATOR_BANK_SEL(7) | + PM8058_SMPS_LEGACY_MODE); + if (error) + return error; + + /* Enable locally, enable pull down, keep voltage the same. */ + error = regmap_update_bits(regmap, ctrl_addr, + PM8058_REGULATOR_ENABLE_MASK | + PM8058_REGULATOR_PULL_DOWN_MASK | + PM8058_SMPS_LEGACY_VREF_SEL | + PM8058_SMPS_LEGACY_VPROG_MASK, + PM8058_REGULATOR_ENABLE | PM8058_REGULATOR_PULL_DOWN_EN + | vref_sel | vprog); + if (error) + return error; + } + + /* Enable in master control register. */ + error = regmap_update_bits(regmap, master_enable_addr, + master_enable_bit, master_enable_bit); + if (error) + return error; + + /* Disable locally and enable pull down. */ + return regmap_update_bits(regmap, ctrl_addr, + PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK, + PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN); +} + +static int pm8058_disable_ldo_locally_set_pull_down(struct regmap *regmap, + u16 ctrl_addr, u16 master_enable_addr, u8 master_enable_bit) +{ + int error; + + /* Enable LDO in master control register. */ + error = regmap_update_bits(regmap, master_enable_addr, + master_enable_bit, master_enable_bit); + if (error) + return error; + + /* Disable LDO in CTRL register and set pull down */ + return regmap_update_bits(regmap, ctrl_addr, + PM8058_REGULATOR_ENABLE_MASK | PM8058_REGULATOR_PULL_DOWN_MASK, + PM8058_REGULATOR_DISABLE | PM8058_REGULATOR_PULL_DOWN_EN); +} + +static int pm8058_pwrkey_shutdown(struct pmic8xxx_pwrkey *pwrkey, bool reset) +{ + int error; + struct regmap *regmap = pwrkey->regmap; + u8 mask, val; + + /* When shutting down, enable active pulldowns on important rails. */ + if (!reset) { + /* Disable SMPS's 0,1,3 locally and set pulldown enable bits. */ + pm8058_disable_smps_locally_set_pull_down(regmap, + PM8058_S0_CTRL, PM8058_S0_TEST2, + REG_PM8058_VREG_EN_MSM, BIT(7)); + pm8058_disable_smps_locally_set_pull_down(regmap, + PM8058_S1_CTRL, PM8058_S1_TEST2, + REG_PM8058_VREG_EN_MSM, BIT(6)); + pm8058_disable_smps_locally_set_pull_down(regmap, + PM8058_S3_CTRL, PM8058_S3_TEST2, + REG_PM8058_VREG_EN_GRP_5_4, BIT(7) | BIT(4)); + /* Disable LDO 21 locally and set pulldown enable bit. */ + pm8058_disable_ldo_locally_set_pull_down(regmap, + PM8058_L21_CTRL, REG_PM8058_VREG_EN_GRP_5_4, + BIT(1)); + } + + /* + * Fix-up: Set regulator LDO22 to 1.225 V in high power mode. Leave its + * pull-down state intact. This ensures a safe shutdown. + */ + error = regmap_update_bits(regmap, PM8058_L22_CTRL, 0xbf, 0x93); + if (error) + return error; + + /* Enable SMPL if resetting is desired */ + mask = SLEEP_CTRL_SMPL_EN_RESET; + val = 0; + if (reset) + val = mask; + return regmap_update_bits(regmap, PM8058_SLEEP_CTRL, mask, val); +} + +static int pm8921_pwrkey_shutdown(struct pmic8xxx_pwrkey *pwrkey, bool reset) +{ + struct regmap *regmap = pwrkey->regmap; + u8 mask = SLEEP_CTRL_SMPL_EN_RESET; + u8 val = 0; + + /* Enable SMPL if resetting is desired */ + if (reset) + val = mask; + return regmap_update_bits(regmap, PM8921_SLEEP_CTRL, mask, val); +} + static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) { struct input_dev *pwr; @@ -109,6 +370,8 @@ static int pmic8xxx_pwrkey_probe(struct platform_device *pdev) if (!pwrkey) return -ENOMEM; + pwrkey->shutdown_fn = of_device_get_match_data(&pdev->dev); + pwrkey->regmap = regmap; pwrkey->key_press_irq = key_press_irq; pwr = devm_input_allocate_device(&pdev->dev); @@ -182,8 +445,8 @@ static int pmic8xxx_pwrkey_remove(struct platform_device *pdev) } static const struct of_device_id pm8xxx_pwr_key_id_table[] = { - { .compatible = "qcom,pm8058-pwrkey" }, - { .compatible = "qcom,pm8921-pwrkey" }, + { .compatible = "qcom,pm8058-pwrkey", .data = &pm8058_pwrkey_shutdown }, + { .compatible = "qcom,pm8921-pwrkey", .data = &pm8921_pwrkey_shutdown }, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table); @@ -191,6 +454,7 @@ MODULE_DEVICE_TABLE(of, pm8xxx_pwr_key_id_table); static struct platform_driver pmic8xxx_pwrkey_driver = { .probe = pmic8xxx_pwrkey_probe, .remove = pmic8xxx_pwrkey_remove, + .shutdown = pmic8xxx_pwrkey_shutdown, .driver = { .name = "pm8xxx-pwrkey", .pm = &pm8xxx_pwr_key_pm_ops, -- GitLab From aeda5003d0b987085acef6ad4844f8e34851bb10 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 11:54:14 -0700 Subject: [PATCH 1622/7006] Input: matrix_keypad - change name of wakeup property to "wakeup-source" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Cc: Lothar Waßmann Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/gpio-matrix-keypad.txt | 2 +- drivers/input/keyboard/matrix_keypad.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt index ead641c65e0a8..4d86059c370c4 100644 --- a/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt +++ b/Documentation/devicetree/bindings/input/gpio-matrix-keypad.txt @@ -19,7 +19,7 @@ Required Properties: Optional Properties: - linux,no-autorepeat: do no enable autorepeat feature. -- linux,wakeup: use any event on keypad as wakeup event. +- wakeup-source: use any event on keypad as wakeup event. - debounce-delay-ms: debounce interval in milliseconds - col-scan-delay-us: delay, measured in microseconds, that is needed before we can scan keypad after activating column gpio diff --git a/drivers/input/keyboard/matrix_keypad.c b/drivers/input/keyboard/matrix_keypad.c index b370a59cb7597..7f12b6579f822 100644 --- a/drivers/input/keyboard/matrix_keypad.c +++ b/drivers/input/keyboard/matrix_keypad.c @@ -425,8 +425,10 @@ matrix_keypad_parse_dt(struct device *dev) if (of_get_property(np, "linux,no-autorepeat", NULL)) pdata->no_autorepeat = true; - if (of_get_property(np, "linux,wakeup", NULL)) - pdata->wakeup = true; + + pdata->wakeup = of_property_read_bool(np, "wakeup-source") || + of_property_read_bool(np, "linux,wakeup"); /* legacy */ + if (of_get_property(np, "gpio-activelow", NULL)) pdata->active_low = true; -- GitLab From abf77a32288d4379dfede0b50be6a04be3cd1431 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 12:03:39 -0700 Subject: [PATCH 1623/7006] Input: ads7846 - change name of wakeup property to "wakeup-source" Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/ads7846.txt | 2 +- drivers/input/touchscreen/ads7846.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/input/ads7846.txt b/Documentation/devicetree/bindings/input/ads7846.txt index 5f7619c227438..df8b1279491d1 100644 --- a/Documentation/devicetree/bindings/input/ads7846.txt +++ b/Documentation/devicetree/bindings/input/ads7846.txt @@ -64,7 +64,7 @@ Optional properties: pendown-gpio (u32). pendown-gpio GPIO handle describing the pin the !PENIRQ line is connected to. - linux,wakeup use any event on touchscreen as wakeup event. + wakeup-source use any event on touchscreen as wakeup event. Example for a TSC2046 chip connected to an McSPI controller of an OMAP SoC:: diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index e4eb8a6c658f1..0f5f968592bd0 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -1234,7 +1234,8 @@ static const struct ads7846_platform_data *ads7846_probe_dt(struct device *dev) of_property_read_u32(node, "ti,pendown-gpio-debounce", &pdata->gpio_pendown_debounce); - pdata->wakeup = of_property_read_bool(node, "linux,wakeup"); + pdata->wakeup = of_property_read_bool(node, "wakeup-source") || + of_property_read_bool(node, "linux,wakeup"); pdata->gpio_pendown = of_get_named_gpio(dev->of_node, "pendown-gpio", 0); -- GitLab From 274696521254855ba03f2d4f4575ae048a409256 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 12:15:24 -0700 Subject: [PATCH 1624/7006] Input: pmic8xxx-keypad - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Acked-by: Stephen Boyd Signed-off-by: Dmitry Torokhov --- .../devicetree/bindings/input/qcom,pm8xxx-keypad.txt | 2 +- drivers/input/keyboard/pmic8xxx-keypad.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt index 7d8cb92831d7b..ee62156811828 100644 --- a/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt +++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt @@ -33,7 +33,7 @@ PROPERTIES Value type: Definition: don't enable autorepeat feature. -- linux,keypad-wakeup: +- wakeup-source: Usage: optional Value type: Definition: use any event on keypad as wakeup event. diff --git a/drivers/input/keyboard/pmic8xxx-keypad.c b/drivers/input/keyboard/pmic8xxx-keypad.c index 32580afecc266..5c68e3f096bc8 100644 --- a/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/drivers/input/keyboard/pmic8xxx-keypad.c @@ -507,6 +507,7 @@ static void pmic8xxx_kp_close(struct input_dev *dev) */ static int pmic8xxx_kp_probe(struct platform_device *pdev) { + struct device_node *np = pdev->dev.of_node; unsigned int rows, cols; bool repeat; bool wakeup; @@ -524,10 +525,11 @@ static int pmic8xxx_kp_probe(struct platform_device *pdev) return -EINVAL; } - repeat = !of_property_read_bool(pdev->dev.of_node, - "linux,input-no-autorepeat"); - wakeup = of_property_read_bool(pdev->dev.of_node, - "linux,keypad-wakeup"); + repeat = !of_property_read_bool(np, "linux,input-no-autorepeat"); + + wakeup = of_property_read_bool(np, "wakeup-source") || + /* legacy name */ + of_property_read_bool(np, "linux,keypad-wakeup"); kp = devm_kzalloc(&pdev->dev, sizeof(*kp), GFP_KERNEL); if (!kp) -- GitLab From 99b4ffbd84ea4191e0b8d1709230656a1c33b848 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 16 Jul 2015 12:10:05 -0700 Subject: [PATCH 1625/7006] Input: gpio_keys[_polled] - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/gpio-keys-polled.txt | 2 +- Documentation/devicetree/bindings/input/gpio-keys.txt | 2 +- drivers/input/keyboard/gpio_keys.c | 4 +++- drivers/input/keyboard/gpio_keys_polled.c | 5 ++++- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt index 313abefa37ccd..5b91f5a3bd5c6 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys-polled.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys-polled.txt @@ -20,7 +20,7 @@ Optional subnode-properties: If not specified defaults to <1> == EV_KEY. - debounce-interval: Debouncing interval time in milliseconds. If not specified defaults to 5. - - gpio-key,wakeup: Boolean, button can wake-up the system. + - wakeup-source: Boolean, button can wake-up the system. Example nodes: diff --git a/Documentation/devicetree/bindings/input/gpio-keys.txt b/Documentation/devicetree/bindings/input/gpio-keys.txt index 44b705767aca4..072bf7573c376 100644 --- a/Documentation/devicetree/bindings/input/gpio-keys.txt +++ b/Documentation/devicetree/bindings/input/gpio-keys.txt @@ -23,7 +23,7 @@ Optional subnode-properties: If not specified defaults to <1> == EV_KEY. - debounce-interval: Debouncing interval time in milliseconds. If not specified defaults to 5. - - gpio-key,wakeup: Boolean, button can wake-up the system. + - wakeup-source: Boolean, button can wake-up the system. - linux,can-disable: Boolean, indicates that button is connected to dedicated (not shared) interrupt which can be disabled to suppress events from the button. diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index ddf4045de0846..1df4507c4c0b7 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -655,7 +655,9 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (of_property_read_u32(pp, "linux,input-type", &button->type)) button->type = EV_KEY; - button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); + button->wakeup = of_property_read_bool(pp, "wakeup-source") || + /* legacy name */ + of_property_read_bool(pp, "gpio-key,wakeup"); button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 097d7216d98ee..5a0c999506598 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -152,7 +152,10 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct &button->type)) button->type = EV_KEY; - button->wakeup = fwnode_property_present(child, "gpio-key,wakeup"); + button->wakeup = + fwnode_property_read_bool(child, "wakeup-source") || + /* legacy name */ + fwnode_property_read_bool(child, "gpio-key,wakeup"); if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) -- GitLab From 43b7be3b8c0457c35a124d8538372f82f355bd29 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Jul 2015 17:04:10 -0700 Subject: [PATCH 1626/7006] Input: samsung-keypad - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/input/samsung-keypad.txt | 4 +++- drivers/input/keyboard/samsung-keypad.c | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/input/samsung-keypad.txt b/Documentation/devicetree/bindings/input/samsung-keypad.txt index 942d071baaa5d..863e77f619dc6 100644 --- a/Documentation/devicetree/bindings/input/samsung-keypad.txt +++ b/Documentation/devicetree/bindings/input/samsung-keypad.txt @@ -36,9 +36,11 @@ Required Board Specific Properties: - pinctrl-0: Should specify pin control groups used for this controller. - pinctrl-names: Should contain only one value - "default". +Optional Properties: +- wakeup-source: use any event on keypad as wakeup event. + Optional Properties specific to linux: - linux,keypad-no-autorepeat: do no enable autorepeat feature. -- linux,keypad-wakeup: use any event on keypad as wakeup event. Example: diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c index 43e48dac7687f..4e319eb9e19d9 100644 --- a/drivers/input/keyboard/samsung-keypad.c +++ b/drivers/input/keyboard/samsung-keypad.c @@ -299,8 +299,10 @@ samsung_keypad_parse_dt(struct device *dev) if (of_get_property(np, "linux,input-no-autorepeat", NULL)) pdata->no_autorepeat = true; - if (of_get_property(np, "linux,input-wakeup", NULL)) - pdata->wakeup = true; + pdata->wakeup = of_property_read_bool(np, "wakeup-source") || + /* legacy name */ + of_property_read_bool(np, "linux,input-wakeup"); + return pdata; } -- GitLab From e571c73ee4836640d3019ac68b008f3662087e80 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 17 Jul 2015 17:08:02 -0700 Subject: [PATCH 1627/7006] Input: tc3589x-keypad - change name of wakeup property Wakeup property of device is not Linux-specific, it describes intended system behavior regardless of the OS being used. Therefore let's drop "linux," prefix, and, while at it, use the same name as I2C bus does: "wakeup-source". We keep parsing old name to keep compatibility with old DTSes. Reviewed-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- Documentation/devicetree/bindings/mfd/tc3589x.txt | 4 ++-- drivers/input/keyboard/tc3589x-keypad.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/tc3589x.txt b/Documentation/devicetree/bindings/mfd/tc3589x.txt index 6fcedba46ae9b..37bf7f1aa70a2 100644 --- a/Documentation/devicetree/bindings/mfd/tc3589x.txt +++ b/Documentation/devicetree/bindings/mfd/tc3589x.txt @@ -55,7 +55,7 @@ Optional nodes: - linux,keymap: the definition can be found in bindings/input/matrix-keymap.txt - linux,no-autorepeat: do no enable autorepeat feature. - - linux,wakeup: use any event on keypad as wakeup event. + - wakeup-source: use any event on keypad as wakeup event. Example: @@ -84,7 +84,6 @@ tc35893@44 { keypad,num-columns = <8>; keypad,num-rows = <8>; linux,no-autorepeat; - linux,wakeup; linux,keymap = <0x0301006b 0x04010066 0x06040072 @@ -103,5 +102,6 @@ tc35893@44 { 0x01030039 0x07060069 0x050500d9>; + wakeup-source; }; }; diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 31c606a4dd310..565805e1ff94d 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -352,7 +352,10 @@ tc3589x_keypad_of_probe(struct device *dev) } plat->no_autorepeat = of_property_read_bool(np, "linux,no-autorepeat"); - plat->enable_wakeup = of_property_read_bool(np, "linux,wakeup"); + + plat->enable_wakeup = of_property_read_bool(np, "wakeup-source") || + /* legacy name */ + of_property_read_bool(np, "linux,wakeup"); /* The custom delay format is ms/16 */ of_property_read_u32(np, "debounce-delay-ms", &debounce_ms); -- GitLab From be972177797636a4c8958ff0a8feb314309850c3 Mon Sep 17 00:00:00 2001 From: Himangi Saraogi Date: Sun, 25 May 2014 22:33:13 -0700 Subject: [PATCH 1628/7006] Input: tc3589x-keypad - switch to using managed resources Let's switch the driver to use managed resources, this will simplify error handling and driver unbinding logic. Signed-off-by: Himangi Saraogi Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tc3589x-keypad.c | 58 +++++++++---------------- 1 file changed, 20 insertions(+), 38 deletions(-) diff --git a/drivers/input/keyboard/tc3589x-keypad.c b/drivers/input/keyboard/tc3589x-keypad.c index 565805e1ff94d..e92dfd8889c2d 100644 --- a/drivers/input/keyboard/tc3589x-keypad.c +++ b/drivers/input/keyboard/tc3589x-keypad.c @@ -17,6 +17,7 @@ #include #include #include +#include /* Maximum supported keypad matrix row/columns size */ #define TC3589x_MAX_KPROW 8 @@ -389,12 +390,15 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) if (irq < 0) return irq; - keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL); - input = input_allocate_device(); - if (!keypad || !input) { - dev_err(&pdev->dev, "failed to allocate keypad memory\n"); - error = -ENOMEM; - goto err_free_mem; + keypad = devm_kzalloc(&pdev->dev, sizeof(struct tc_keypad), + GFP_KERNEL); + if (!keypad) + return -ENOMEM; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) { + dev_err(&pdev->dev, "failed to allocate input device\n"); + return -ENOMEM; } keypad->board = plat; @@ -413,7 +417,7 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) NULL, input); if (error) { dev_err(&pdev->dev, "Failed to build keymap\n"); - goto err_free_mem; + return error; } keypad->keymap = input->keycode; @@ -424,20 +428,23 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) input_set_drvdata(input, keypad); - error = request_threaded_irq(irq, NULL, tc3589x_keypad_irq, - plat->irqtype | IRQF_ONESHOT, - "tc3589x-keypad", keypad); - if (error < 0) { + tc3589x_keypad_disable(keypad); + + error = devm_request_threaded_irq(&pdev->dev, irq, + NULL, tc3589x_keypad_irq, + plat->irqtype | IRQF_ONESHOT, + "tc3589x-keypad", keypad); + if (error) { dev_err(&pdev->dev, "Could not allocate irq %d,error %d\n", irq, error); - goto err_free_mem; + return error; } error = input_register_device(input); if (error) { dev_err(&pdev->dev, "Could not register input device\n"); - goto err_free_irq; + return error; } /* let platform decide if keypad is a wakeup source or not */ @@ -446,30 +453,6 @@ static int tc3589x_keypad_probe(struct platform_device *pdev) platform_set_drvdata(pdev, keypad); - return 0; - -err_free_irq: - free_irq(irq, keypad); -err_free_mem: - input_free_device(input); - kfree(keypad); - return error; -} - -static int tc3589x_keypad_remove(struct platform_device *pdev) -{ - struct tc_keypad *keypad = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - if (!keypad->keypad_stopped) - tc3589x_keypad_disable(keypad); - - free_irq(irq, keypad); - - input_unregister_device(keypad->input); - - kfree(keypad); - return 0; } @@ -521,7 +504,6 @@ static struct platform_driver tc3589x_keypad_driver = { .pm = &tc3589x_keypad_dev_pm_ops, }, .probe = tc3589x_keypad_probe, - .remove = tc3589x_keypad_remove, }; module_platform_driver(tc3589x_keypad_driver); -- GitLab From 94897619bf24aca6b37cfa847399a56cf40eab66 Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 16:49:06 -0700 Subject: [PATCH 1629/7006] Input: cyapa - rename 'gen5' to 'pip' for chared code Change 'gen5' to 'pip' for all macros, variables and functions that are shared between gen5 and gen6 modules to make naming more clear and readable. Also fix a few spelling errors. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 34 +- drivers/input/mouse/cyapa.h | 136 +++- drivers/input/mouse/cyapa_gen3.c | 4 +- drivers/input/mouse/cyapa_gen5.c | 1103 ++++++++++++++---------------- 4 files changed, 673 insertions(+), 604 deletions(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index dfbfd494bb1f4..4c4429598adbb 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -6,7 +6,7 @@ * Daniel Kurtz * Benson Leung * - * Copyright (C) 2011-2014 Cypress Semiconductor, Inc. + * Copyright (C) 2011-2015 Cypress Semiconductor, Inc. * Copyright (C) 2011-2012 Google, Inc. * * This file is subject to the terms and conditions of the GNU General Public @@ -39,11 +39,27 @@ const char product_id[] = "CYTRA"; static int cyapa_reinitialize(struct cyapa *cyapa); -static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa) +bool cyapa_is_pip_bl_mode(struct cyapa *cyapa) { if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL) return true; + return false; +} + +bool cyapa_is_pip_app_mode(struct cyapa *cyapa) +{ + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) + return true; + + return false; +} + +static bool cyapa_is_bootloader_mode(struct cyapa *cyapa) +{ + if (cyapa_is_pip_bl_mode(cyapa)) + return true; + if (cyapa->gen == CYAPA_GEN3 && cyapa->state >= CYAPA_STATE_BL_BUSY && cyapa->state <= CYAPA_STATE_BL_ACTIVE) @@ -54,7 +70,7 @@ static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa) static inline bool cyapa_is_operational_mode(struct cyapa *cyapa) { - if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) + if (cyapa_is_pip_app_mode(cyapa)) return true; if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP) @@ -306,7 +322,7 @@ static int cyapa_check_is_operational(struct cyapa *cyapa) /* * Returns 0 on device detected, negative errno on no device detected. - * And when the device is detected and opertaional, it will be reset to + * And when the device is detected and operational, it will be reset to * full power active mode automatically. */ static int cyapa_detect(struct cyapa *cyapa) @@ -629,15 +645,15 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) if (device_may_wakeup(dev)) pm_wakeup_event(dev, 0); - /* Interrupt event maybe cuased by host command to trackpad device. */ + /* Interrupt event can be caused by host command to trackpad device. */ if (cyapa->ops->irq_cmd_handler(cyapa)) { /* * Interrupt event maybe from trackpad device input reporting. */ if (!cyapa->input) { /* - * Still in probling or in firware image - * udpating or reading. + * Still in probing or in firmware image + * updating or reading. */ cyapa->ops->sort_empty_output_data(cyapa, NULL, NULL, NULL); @@ -1051,12 +1067,12 @@ static ssize_t cyapa_update_fw_store(struct device *dev, dev_dbg(dev, "firmware update successfully done.\n"); /* - * Redetect trackpad device states because firmware update process + * Re-detect trackpad device states because firmware update process * will reset trackpad device into bootloader mode. */ ret = cyapa_reinitialize(cyapa); if (ret) { - dev_err(dev, "failed to redetect after updated: %d\n", ret); + dev_err(dev, "failed to re-detect after updated: %d\n", ret); error = error ? error : ret; } diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index adc9ed5dcb0e4..d019d1d2d1e41 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -3,7 +3,7 @@ * * Author: Dudley Du * - * Copyright (C) 2014 Cypress Semiconductor, Inc. + * Copyright (C) 2014-2015 Cypress Semiconductor, Inc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -25,7 +25,7 @@ /* * Macros for SMBus communication */ -#define SMBUS_READ 0x01 +#define SMBUS_READ 0x01 #define SMBUS_WRITE 0x00 #define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1)) #define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01)) @@ -159,12 +159,86 @@ #define AUTOSUSPEND_DELAY 2000 /* unit : ms */ -#define UNINIT_SLEEP_TIME 0xFFFF -#define UNINIT_PWR_MODE 0xFF - #define BTN_ONLY_MODE_NAME "buttononly" #define OFF_MODE_NAME "off" +/* Common macros for PIP interface. */ +#define PIP_HID_DESCRIPTOR_ADDR 0x0001 +#define PIP_REPORT_DESCRIPTOR_ADDR 0x0002 +#define PIP_INPUT_REPORT_ADDR 0x0003 +#define PIP_OUTPUT_REPORT_ADDR 0x0004 +#define PIP_CMD_DATA_ADDR 0x0006 + +#define PIP_RETRIEVE_DATA_STRUCTURE 0x24 +#define PIP_CMD_CALIBRATE 0x28 +#define PIP_BL_CMD_VERIFY_APP_INTEGRITY 0x31 +#define PIP_BL_CMD_GET_BL_INFO 0x38 +#define PIP_BL_CMD_PROGRAM_VERIFY_ROW 0x39 +#define PIP_BL_CMD_LAUNCH_APP 0x3b +#define PIP_BL_CMD_INITIATE_BL 0x48 +#define PIP_INVALID_CMD 0xff + +#define PIP_HID_DESCRIPTOR_SIZE 32 +#define PIP_HID_APP_REPORT_ID 0xf7 +#define PIP_HID_BL_REPORT_ID 0xff + +#define PIP_BL_CMD_REPORT_ID 0x40 +#define PIP_BL_RESP_REPORT_ID 0x30 +#define PIP_APP_CMD_REPORT_ID 0x2f +#define PIP_APP_RESP_REPORT_ID 0x1f + +#define PIP_READ_SYS_INFO_CMD_LENGTH 7 +#define PIP_BL_READ_APP_INFO_CMD_LENGTH 13 +#define PIP_MIN_BL_CMD_LENGTH 13 +#define PIP_MIN_BL_RESP_LENGTH 11 +#define PIP_MIN_APP_CMD_LENGTH 7 +#define PIP_MIN_APP_RESP_LENGTH 5 +#define PIP_UNSUPPORTED_CMD_RESP_LENGTH 6 +#define PIP_READ_SYS_INFO_RESP_LENGTH 71 +#define PIP_BL_APP_INFO_RESP_LENGTH 30 +#define PIP_BL_GET_INFO_RESP_LENGTH 19 + +#define PIP_PRODUCT_FAMILY_MASK 0xf000 +#define PIP_PRODUCT_FAMILY_TRACKPAD 0x1000 + +#define PIP_DEEP_SLEEP_STATE_ON 0x00 +#define PIP_DEEP_SLEEP_STATE_OFF 0x01 +#define PIP_DEEP_SLEEP_STATE_MASK 0x03 +#define PIP_APP_DEEP_SLEEP_REPORT_ID 0xf0 +#define PIP_DEEP_SLEEP_RESP_LENGTH 5 +#define PIP_DEEP_SLEEP_OPCODE 0x08 +#define PIP_DEEP_SLEEP_OPCODE_MASK 0x0f + +#define PIP_RESP_LENGTH_OFFSET 0 +#define PIP_RESP_LENGTH_SIZE 2 +#define PIP_RESP_REPORT_ID_OFFSET 2 +#define PIP_RESP_RSVD_OFFSET 3 +#define PIP_RESP_RSVD_KEY 0x00 +#define PIP_RESP_BL_SOP_OFFSET 4 +#define PIP_SOP_KEY 0x01 /* Start of Packet */ +#define PIP_EOP_KEY 0x17 /* End of Packet */ +#define PIP_RESP_APP_CMD_OFFSET 4 +#define GET_PIP_CMD_CODE(reg) ((reg) & 0x7f) +#define PIP_RESP_STATUS_OFFSET 5 + +#define VALID_CMD_RESP_HEADER(resp, cmd) \ + (((resp)[PIP_RESP_REPORT_ID_OFFSET] == PIP_APP_RESP_REPORT_ID) && \ + ((resp)[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY) && \ + (GET_PIP_CMD_CODE((resp)[PIP_RESP_APP_CMD_OFFSET]) == (cmd))) + +#define PIP_CMD_COMPLETE_SUCCESS(resp_data) \ + ((resp_data)[PIP_RESP_STATUS_OFFSET] == 0x00) + +/* Variables to record latest gen5 trackpad power states. */ +#define UNINIT_SLEEP_TIME 0xffff +#define UNINIT_PWR_MODE 0xff +#define PIP_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) +#define PIP_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) +#define PIP_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) +#define PIP_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) +#define PIP_DEV_UNINIT_SLEEP_TIME(cyapa) \ + (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) + /* The touch.id is used as the MT slot id, thus max MT slot is 15 */ #define CYAPA_MAX_MT_SLOTS 15 @@ -198,7 +272,7 @@ struct cyapa_dev_ops { int (*set_power_mode)(struct cyapa *, u8, u16); }; -struct cyapa_gen5_cmd_states { +struct cyapa_pip_cmd_states { struct mutex cmd_lock; struct completion cmd_ready; atomic_t cmd_issued; @@ -214,7 +288,7 @@ struct cyapa_gen5_cmd_states { }; union cyapa_cmd_states { - struct cyapa_gen5_cmd_states gen5; + struct cyapa_pip_cmd_states pip; }; enum cyapa_state { @@ -259,7 +333,7 @@ struct cyapa { int physical_size_y; /* Used in ttsp and truetouch based trackpad devices. */ - u8 x_origin; /* X Axis Origin: 0 = left side; 1 = rigth side. */ + u8 x_origin; /* X Axis Origin: 0 = left side; 1 = right side. */ u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */ int electrodes_x; /* Number of electrodes on the X Axis*/ int electrodes_y; /* Number of electrodes on the Y Axis*/ @@ -282,9 +356,9 @@ struct cyapa { ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len, - u8 *values); + u8 *values); ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len, - u8 *values); + u8 *values); ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values); @@ -293,7 +367,47 @@ int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout); u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time); u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode); - +ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size); +ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size); +int cyapa_empty_pip_output_data(struct cyapa *cyapa, + u8 *buf, int *len, cb_sort func); +int cyapa_i2c_pip_cmd_irq_sync(struct cyapa *cyapa, + u8 *cmd, int cmd_len, + u8 *resp_data, int *resp_len, + unsigned long timeout, + cb_sort func, + bool irq_mode); +int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len); +bool cyapa_pip_sort_system_info_data(struct cyapa *cyapa, u8 *buf, int len); +bool cyapa_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, u8 *data, int len); +int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state); +bool cyapa_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, u8 *data, int len); +int cyapa_pip_bl_exit(struct cyapa *cyapa); +int cyapa_pip_bl_enter(struct cyapa *cyapa); + + +bool cyapa_is_pip_bl_mode(struct cyapa *cyapa); +bool cyapa_is_pip_app_mode(struct cyapa *cyapa); +int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa); + +int cyapa_pip_resume_scanning(struct cyapa *cyapa); +int cyapa_pip_suspend_scanning(struct cyapa *cyapa); + +int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw); +int cyapa_pip_bl_initiate(struct cyapa *cyapa, const struct firmware *fw); +int cyapa_pip_do_fw_update(struct cyapa *cyapa, const struct firmware *fw); +int cyapa_pip_bl_activate(struct cyapa *cyapa); +int cyapa_pip_bl_deactivate(struct cyapa *cyapa); +ssize_t cyapa_pip_do_calibrate(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa); +int cyapa_pip_irq_handler(struct cyapa *cyapa); + + +extern u8 pip_read_sys_info[]; +extern u8 pip_bl_read_app_info[]; extern const char product_id[]; extern const struct cyapa_dev_ops cyapa_gen3_ops; extern const struct cyapa_dev_ops cyapa_gen5_ops; diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index 3faf01c1b1911..3884311410f75 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -6,7 +6,7 @@ * Daniel Kurtz * Benson Leung * - * Copyright (C) 2011-2014 Cypress Semiconductor, Inc. + * Copyright (C) 2011-2015 Cypress Semiconductor, Inc. * Copyright (C) 2011-2012 Google, Inc. * * This file is subject to the terms and conditions of the GNU General Public @@ -1156,7 +1156,7 @@ static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa) * so, stop cyapa_gen3_irq_handler to continue process to * avoid unwanted to error detecting and processing. * - * And also, avoid the periodicly accerted interrupts to be processed + * And also, avoid the periodically asserted interrupts to be processed * as touch inputs when gen3 failed to launch into application mode, * which will cause gen3 stays in bootloader mode. */ diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index afc39e799da23..9d75c6f9f307d 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -3,7 +3,7 @@ * * Author: Dudley Du * - * Copyright (C) 2014 Cypress Semiconductor, Inc. + * Copyright (C) 2014-2015 Cypress Semiconductor, Inc. * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for @@ -22,12 +22,7 @@ #include "cyapa.h" -/* Macro of Gen5 */ -#define RECORD_EVENT_NONE 0 -#define RECORD_EVENT_TOUCHDOWN 1 -#define RECORD_EVENT_DISPLACE 2 -#define RECORD_EVENT_LIFTOFF 3 - +/* Macro of TSG firmware image */ #define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80 #define CYAPA_TSG_IMG_FW_HDR_SIZE 13 #define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE) @@ -44,43 +39,48 @@ #define CYAPA_TSG_MAX_CMD_SIZE 256 -#define GEN5_BL_CMD_VERIFY_APP_INTEGRITY 0x31 -#define GEN5_BL_CMD_GET_BL_INFO 0x38 -#define GEN5_BL_CMD_PROGRAM_VERIFY_ROW 0x39 -#define GEN5_BL_CMD_LAUNCH_APP 0x3b -#define GEN5_BL_CMD_INITIATE_BL 0x48 - -#define GEN5_HID_DESCRIPTOR_ADDR 0x0001 -#define GEN5_REPORT_DESCRIPTOR_ADDR 0x0002 -#define GEN5_INPUT_REPORT_ADDR 0x0003 -#define GEN5_OUTPUT_REPORT_ADDR 0x0004 -#define GEN5_CMD_DATA_ADDR 0x0006 - -#define GEN5_TOUCH_REPORT_HEAD_SIZE 7 -#define GEN5_TOUCH_REPORT_MAX_SIZE 127 -#define GEN5_BTN_REPORT_HEAD_SIZE 6 -#define GEN5_BTN_REPORT_MAX_SIZE 14 -#define GEN5_WAKEUP_EVENT_SIZE 4 -#define GEN5_RAW_DATA_HEAD_SIZE 24 - -#define GEN5_BL_CMD_REPORT_ID 0x40 -#define GEN5_BL_RESP_REPORT_ID 0x30 -#define GEN5_APP_CMD_REPORT_ID 0x2f -#define GEN5_APP_RESP_REPORT_ID 0x1f - -#define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0 -#define GEN5_DEEP_SLEEP_RESP_LENGTH 5 +/* Macro of PIP interface */ +#define PIP_BL_INITIATE_RESP_LEN 11 +#define PIP_BL_FAIL_EXIT_RESP_LEN 11 +#define PIP_BL_FAIL_EXIT_STATUS_CODE 0x0c +#define PIP_BL_VERIFY_INTEGRITY_RESP_LEN 12 +#define PIP_BL_INTEGRITY_CHEKC_PASS 0x00 +#define PIP_BL_BLOCK_WRITE_RESP_LEN 11 + +#define PIP_TOUCH_REPORT_ID 0x01 +#define PIP_BTN_REPORT_ID 0x03 +#define PIP_WAKEUP_EVENT_REPORT_ID 0x04 +#define PIP_PUSH_BTN_REPORT_ID 0x06 +#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */ + +#define PIP_TOUCH_REPORT_HEAD_SIZE 7 +#define PIP_TOUCH_REPORT_MAX_SIZE 127 +#define PIP_BTN_REPORT_HEAD_SIZE 6 +#define PIP_BTN_REPORT_MAX_SIZE 14 +#define PIP_WAKEUP_EVENT_SIZE 4 + +#define PIP_NUMBER_OF_TOUCH_OFFSET 5 +#define PIP_NUMBER_OF_TOUCH_MASK 0x1f +#define PIP_BUTTONS_OFFSET 5 +#define PIP_BUTTONS_MASK 0x0f +#define PIP_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) +#define PIP_GET_TOUCH_ID(reg) ((reg) & 0x1f) +#define PIP_TOUCH_TYPE_FINGER 0x00 +#define PIP_TOUCH_TYPE_PROXIMITY 0x01 +#define PIP_TOUCH_TYPE_HOVER 0x02 +#define PIP_GET_TOUCH_TYPE(reg) ((reg) & 0x07) -#define GEN5_CMD_GET_PARAMETER 0x05 -#define GEN5_CMD_SET_PARAMETER 0x06 -#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d -#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 -#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f -#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 -#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c -#define GEN5_PARAMETER_LP_INTRVL_SIZE 2 +#define RECORD_EVENT_NONE 0 +#define RECORD_EVENT_TOUCHDOWN 1 +#define RECORD_EVENT_DISPLACE 2 +#define RECORD_EVENT_LIFTOFF 3 -#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 +#define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00 +#define PIP_SENSING_MODE_SELF_CAP 0x02 + +/* Macro of Gen5 */ +#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 +#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe #define GEN5_POWER_STATE_ACTIVE 0x01 #define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02 @@ -89,46 +89,19 @@ #define GEN5_POWER_STATE_BTN_ONLY 0x05 #define GEN5_POWER_STATE_OFF 0x06 -#define GEN5_DEEP_SLEEP_STATE_MASK 0x03 -#define GEN5_DEEP_SLEEP_STATE_ON 0x00 -#define GEN5_DEEP_SLEEP_STATE_OFF 0x01 - -#define GEN5_DEEP_SLEEP_OPCODE 0x08 -#define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f - #define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */ #define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */ -#define GEN5_CMD_REPORT_ID_OFFSET 4 - -#define GEN5_RESP_REPORT_ID_OFFSET 2 -#define GEN5_RESP_RSVD_OFFSET 3 -#define GEN5_RESP_RSVD_KEY 0x00 -#define GEN5_RESP_BL_SOP_OFFSET 4 -#define GEN5_SOP_KEY 0x01 /* Start of Packet */ -#define GEN5_EOP_KEY 0x17 /* End of Packet */ -#define GEN5_RESP_APP_CMD_OFFSET 4 -#define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f) - -#define VALID_CMD_RESP_HEADER(resp, cmd) \ - (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \ - ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \ - (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd))) - -#define GEN5_MIN_BL_CMD_LENGTH 13 -#define GEN5_MIN_BL_RESP_LENGTH 11 -#define GEN5_MIN_APP_CMD_LENGTH 7 -#define GEN5_MIN_APP_RESP_LENGTH 5 -#define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6 - -#define GEN5_RESP_LENGTH_OFFSET 0x00 -#define GEN5_RESP_LENGTH_SIZE 2 - -#define GEN5_HID_DESCRIPTOR_SIZE 32 -#define GEN5_BL_HID_REPORT_ID 0xff -#define GEN5_APP_HID_REPORT_ID 0xf7 -#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 -#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe +#define GEN5_CMD_GET_PARAMETER 0x05 +#define GEN5_CMD_SET_PARAMETER 0x06 +#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d +#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1 +#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f +#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2 +#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c +#define GEN5_PARAMETER_LP_INTRVL_SIZE 2 + +#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08 #define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d #define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe @@ -136,26 +109,6 @@ #define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa #define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6 -#define GEN5_TOUCH_REPORT_ID 0x01 -#define GEN5_BTN_REPORT_ID 0x03 -#define GEN5_WAKEUP_EVENT_REPORT_ID 0x04 -#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 -#define GEN5_PUSH_BTN_REPORT_ID 0x06 - -#define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00) - -#define GEN5_BL_INITIATE_RESP_LEN 11 -#define GEN5_BL_FAIL_EXIT_RESP_LEN 11 -#define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c -#define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12 -#define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00 -#define GEN5_BL_BLOCK_WRITE_RESP_LEN 11 -#define GEN5_BL_READ_APP_INFO_RESP_LEN 31 -#define GEN5_CMD_CALIBRATE 0x28 -#define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00 -#define CYAPA_SENSING_MODE_SELF_CAP 0x02 - -#define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24 #define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00 #define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01 @@ -170,23 +123,12 @@ #define GEN5_PANEL_SCAN_SELF_BASELINE 0x04 #define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05 -/* The offset only valid for reterive PWC and panel scan commands */ +/* The offset only valid for retrieve PWC and panel scan commands */ #define GEN5_RESP_DATA_STRUCTURE_OFFSET 10 #define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07 -#define GEN5_NUMBER_OF_TOUCH_OFFSET 5 -#define GEN5_NUMBER_OF_TOUCH_MASK 0x1f -#define GEN5_BUTTONS_OFFSET 5 -#define GEN5_BUTTONS_MASK 0x0f -#define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03) -#define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f) - -#define GEN5_PRODUCT_FAMILY_MASK 0xf000 -#define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000 - -#define TSG_INVALID_CMD 0xff -struct cyapa_gen5_touch_record { +struct cyapa_pip_touch_record { /* * Bit 7 - 3: reserved * Bit 2 - 0: touch type; @@ -221,7 +163,11 @@ struct cyapa_gen5_touch_record { /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */ u8 y_hi; - /* Touch intensity in counts, pressure value. */ + /* + * The meaning of this value is different when touch_type is different. + * For standard finger type: + * Touch intensity in counts, pressure value. + **/ u8 z; /* @@ -260,9 +206,9 @@ struct cyapa_gen5_touch_record { u8 orientation; } __packed; -struct cyapa_gen5_report_data { - u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE]; - struct cyapa_gen5_touch_record touch_records[10]; +struct cyapa_pip_report_data { + u8 report_head[PIP_TOUCH_REPORT_HEAD_SIZE]; + struct cyapa_pip_touch_record touch_records[10]; } __packed; struct cyapa_tsg_bin_image_head { @@ -288,36 +234,36 @@ struct cyapa_tsg_bin_image { struct cyapa_tsg_bin_image_data_record records[0]; } __packed; -struct gen5_bl_packet_start { +struct pip_bl_packet_start { u8 sop; /* Start of packet, must be 01h */ u8 cmd_code; __le16 data_length; /* Size of data parameter start from data[0] */ } __packed; -struct gen5_bl_packet_end { +struct pip_bl_packet_end { __le16 crc; u8 eop; /* End of packet, must be 17h */ } __packed; -struct gen5_bl_cmd_head { +struct pip_bl_cmd_head { __le16 addr; /* Output report register address, must be 0004h */ /* Size of packet not including output report register address */ __le16 length; u8 report_id; /* Bootloader output report id, must be 40h */ u8 rsvd; /* Reserved, must be 0 */ - struct gen5_bl_packet_start packet_start; + struct pip_bl_packet_start packet_start; u8 data[0]; /* Command data variable based on commands */ } __packed; /* Initiate bootload command data structure. */ -struct gen5_bl_initiate_cmd_data { +struct pip_bl_initiate_cmd_data { /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */ u8 key[CYAPA_TSG_BL_KEY_SIZE]; u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE]; __le16 metadata_crc; } __packed; -struct gen5_bl_metadata_row_params { +struct tsg_bl_metadata_row_params { __le16 size; __le16 maximum_size; __le32 app_start; @@ -332,13 +278,13 @@ struct gen5_bl_metadata_row_params { } __packed; /* Bootload program and verify row command data structure */ -struct gen5_bl_flash_row_head { +struct tsg_bl_flash_row_head { u8 flash_array_id; __le16 flash_row_id; u8 flash_data[0]; } __packed; -struct gen5_app_cmd_head { +struct pip_app_cmd_head { __le16 addr; /* Output report register address, must be 0004h */ /* Size of packet not including output report register address */ __le16 length; @@ -369,30 +315,26 @@ struct gen5_retrieve_panel_scan_data { u8 data_id; } __packed; -/* Variables to record latest gen5 trackpad power states. */ -#define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s)) -#define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode) -#define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t)) -#define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time) -#define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \ - (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME) - +u8 pip_read_sys_info[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 }; +u8 pip_bl_read_app_info[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, + 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 + }; -static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, +static u8 cyapa_pip_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03, 0xff, 0xfe, 0xfd, 0x5a }; -static int cyapa_gen5_initialize(struct cyapa *cyapa) +int cyapa_pip_cmd_state_initialize(struct cyapa *cyapa) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; - init_completion(&gen5_pip->cmd_ready); - atomic_set(&gen5_pip->cmd_issued, 0); - mutex_init(&gen5_pip->cmd_lock); + init_completion(&pip->cmd_ready); + atomic_set(&pip->cmd_issued, 0); + mutex_init(&pip->cmd_lock); - gen5_pip->resp_sort_func = NULL; - gen5_pip->in_progress_cmd = TSG_INVALID_CMD; - gen5_pip->resp_data = NULL; - gen5_pip->resp_len = NULL; + pip->resp_sort_func = NULL; + pip->in_progress_cmd = PIP_INVALID_CMD; + pip->resp_data = NULL; + pip->resp_len = NULL; cyapa->dev_pwr_mode = UNINIT_PWR_MODE; cyapa->dev_sleep_time = UNINIT_SLEEP_TIME; @@ -401,7 +343,7 @@ static int cyapa_gen5_initialize(struct cyapa *cyapa) } /* Return negative errno, or else the number of bytes read. */ -static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) +ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) { int ret; @@ -415,14 +357,13 @@ static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size) if (ret != size) return (ret < 0) ? ret : -EIO; - return size; } /** * Return a negative errno code else zero on success. */ -static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) +ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) { int ret; @@ -441,10 +382,10 @@ static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size) * This function is aimed to dump all not read data in Gen5 trackpad * before send any command, otherwise, the interrupt line will be blocked. */ -static int cyapa_empty_pip_output_data(struct cyapa *cyapa, +int cyapa_empty_pip_output_data(struct cyapa *cyapa, u8 *buf, int *len, cb_sort func) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int length; int report_count; int empty_count; @@ -476,13 +417,13 @@ static int cyapa_empty_pip_output_data(struct cyapa *cyapa, if (empty_count > 5) return 0; - error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, - GEN5_RESP_LENGTH_SIZE); + error = cyapa_i2c_pip_read(cyapa, pip->empty_buf, + PIP_RESP_LENGTH_SIZE); if (error < 0) return error; - length = get_unaligned_le16(gen5_pip->empty_buf); - if (length == GEN5_RESP_LENGTH_SIZE) { + length = get_unaligned_le16(pip->empty_buf); + if (length == PIP_RESP_LENGTH_SIZE) { empty_count++; continue; } else if (length > CYAPA_REG_MAP_SIZE) { @@ -490,11 +431,11 @@ static int cyapa_empty_pip_output_data(struct cyapa *cyapa, return -EINVAL; } else if (length == 0) { /* Application or bootloader launch data polled out. */ - length = GEN5_RESP_LENGTH_SIZE; + length = PIP_RESP_LENGTH_SIZE; if (buf && buf_len && func && - func(cyapa, gen5_pip->empty_buf, length)) { + func(cyapa, pip->empty_buf, length)) { length = min(buf_len, length); - memcpy(buf, gen5_pip->empty_buf, length); + memcpy(buf, pip->empty_buf, length); *len = length; /* Response found, success. */ return 0; @@ -502,19 +443,19 @@ static int cyapa_empty_pip_output_data(struct cyapa *cyapa, continue; } - error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); + error = cyapa_i2c_pip_read(cyapa, pip->empty_buf, length); if (error < 0) return error; report_count--; empty_count = 0; - length = get_unaligned_le16(gen5_pip->empty_buf); - if (length <= GEN5_RESP_LENGTH_SIZE) { + length = get_unaligned_le16(pip->empty_buf); + if (length <= PIP_RESP_LENGTH_SIZE) { empty_count++; } else if (buf && buf_len && func && - func(cyapa, gen5_pip->empty_buf, length)) { + func(cyapa, pip->empty_buf, length)) { length = min(buf_len, length); - memcpy(buf, gen5_pip->empty_buf, length); + memcpy(buf, pip->empty_buf, length); *len = length; /* Response found, success. */ return 0; @@ -531,24 +472,24 @@ static int cyapa_do_i2c_pip_cmd_irq_sync( u8 *cmd, size_t cmd_len, unsigned long timeout) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int error; /* Wait for interrupt to set ready completion */ - init_completion(&gen5_pip->cmd_ready); + init_completion(&pip->cmd_ready); - atomic_inc(&gen5_pip->cmd_issued); + atomic_inc(&pip->cmd_issued); error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); if (error) { - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return (error < 0) ? error : -EIO; } /* Wait for interrupt to indicate command is completed. */ - timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready, + timeout = wait_for_completion_timeout(&pip->cmd_ready, msecs_to_jiffies(timeout)); if (timeout == 0) { - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return -ETIMEDOUT; } @@ -562,15 +503,15 @@ static int cyapa_do_i2c_pip_cmd_polling( unsigned long timeout, cb_sort func) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int tries; int length; int error; - atomic_inc(&gen5_pip->cmd_issued); + atomic_inc(&pip->cmd_issued); error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len); if (error) { - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return error < 0 ? error : -EIO; } @@ -591,11 +532,11 @@ static int cyapa_do_i2c_pip_cmd_polling( error = error ? error : -ETIMEDOUT; } - atomic_dec(&gen5_pip->cmd_issued); + atomic_dec(&pip->cmd_issued); return error; } -static int cyapa_i2c_pip_cmd_irq_sync( +int cyapa_i2c_pip_cmd_irq_sync( struct cyapa *cyapa, u8 *cmd, int cmd_len, u8 *resp_data, int *resp_len, @@ -603,34 +544,34 @@ static int cyapa_i2c_pip_cmd_irq_sync( cb_sort func, bool irq_mode) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int error; if (!cmd || !cmd_len) return -EINVAL; /* Commands must be serialized. */ - error = mutex_lock_interruptible(&gen5_pip->cmd_lock); + error = mutex_lock_interruptible(&pip->cmd_lock); if (error) return error; - gen5_pip->resp_sort_func = func; - gen5_pip->resp_data = resp_data; - gen5_pip->resp_len = resp_len; + pip->resp_sort_func = func; + pip->resp_data = resp_data; + pip->resp_len = resp_len; - if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH && - cmd[4] == GEN5_APP_CMD_REPORT_ID) { + if (cmd_len >= PIP_MIN_APP_CMD_LENGTH && + cmd[4] == PIP_APP_CMD_REPORT_ID) { /* Application command */ - gen5_pip->in_progress_cmd = cmd[6] & 0x7f; - } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH && - cmd[4] == GEN5_BL_CMD_REPORT_ID) { + pip->in_progress_cmd = cmd[6] & 0x7f; + } else if (cmd_len >= PIP_MIN_BL_CMD_LENGTH && + cmd[4] == PIP_BL_CMD_REPORT_ID) { /* Bootloader command */ - gen5_pip->in_progress_cmd = cmd[7]; + pip->in_progress_cmd = cmd[7]; } /* Send command data, wait and read output response data's length. */ if (irq_mode) { - gen5_pip->is_irq_mode = true; + pip->is_irq_mode = true; error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, timeout); if (error == -ETIMEDOUT && resp_data && @@ -646,54 +587,54 @@ static int cyapa_i2c_pip_cmd_irq_sync( error = error ? error : -ETIMEDOUT; } } else { - gen5_pip->is_irq_mode = false; + pip->is_irq_mode = false; error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len, resp_data, resp_len, timeout, func); } - gen5_pip->resp_sort_func = NULL; - gen5_pip->resp_data = NULL; - gen5_pip->resp_len = NULL; - gen5_pip->in_progress_cmd = TSG_INVALID_CMD; + pip->resp_sort_func = NULL; + pip->resp_data = NULL; + pip->resp_len = NULL; + pip->in_progress_cmd = PIP_INVALID_CMD; - mutex_unlock(&gen5_pip->cmd_lock); + mutex_unlock(&pip->cmd_lock); return error; } -static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, +bool cyapa_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa, u8 *data, int len) { - if (!data || len < GEN5_MIN_BL_RESP_LENGTH) + if (!data || len < PIP_MIN_BL_RESP_LENGTH) return false; /* Bootloader input report id 30h */ - if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID && - data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && - data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY) + if (data[PIP_RESP_REPORT_ID_OFFSET] == PIP_BL_RESP_REPORT_ID && + data[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY && + data[PIP_RESP_BL_SOP_OFFSET] == PIP_SOP_KEY) return true; return false; } -static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, +bool cyapa_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, u8 *data, int len) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int resp_len; - if (!data || len < GEN5_MIN_APP_RESP_LENGTH) + if (!data || len < PIP_MIN_APP_RESP_LENGTH) return false; - if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID && - data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) { - resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]); - if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 && - resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH && - data[5] == gen5_pip->in_progress_cmd) { + if (data[PIP_RESP_REPORT_ID_OFFSET] == PIP_APP_RESP_REPORT_ID && + data[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY) { + resp_len = get_unaligned_le16(&data[PIP_RESP_LENGTH_OFFSET]); + if (GET_PIP_CMD_CODE(data[PIP_RESP_APP_CMD_OFFSET]) == 0x00 && + resp_len == PIP_UNSUPPORTED_CMD_RESP_LENGTH && + data[5] == pip->in_progress_cmd) { /* Unsupported command code */ return false; - } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == - gen5_pip->in_progress_cmd) { + } else if (GET_PIP_CMD_CODE(data[PIP_RESP_APP_CMD_OFFSET]) == + pip->in_progress_cmd) { /* Correct command response received */ return true; } @@ -702,10 +643,10 @@ static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa, return false; } -static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa, +static bool cyapa_sort_pip_application_launch_data(struct cyapa *cyapa, u8 *buf, int len) { - if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) + if (buf == NULL || len < PIP_RESP_LENGTH_SIZE) return false; /* @@ -718,25 +659,25 @@ static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa, return false; } -static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, +static bool cyapa_sort_gen5_hid_descriptor_data(struct cyapa *cyapa, u8 *buf, int len) { int resp_len; int max_output_len; /* Check hid descriptor. */ - if (len != GEN5_HID_DESCRIPTOR_SIZE) + if (len != PIP_HID_DESCRIPTOR_SIZE) return false; - resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]); + resp_len = get_unaligned_le16(&buf[PIP_RESP_LENGTH_OFFSET]); max_output_len = get_unaligned_le16(&buf[16]); - if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) { - if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID && + if (resp_len == PIP_HID_DESCRIPTOR_SIZE) { + if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID && max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { /* BL mode HID Descriptor */ return true; - } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_HID_REPORT_ID) && + } else if ((buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_APP_REPORT_ID) && max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { /* APP mode HID Descriptor */ return true; @@ -746,21 +687,21 @@ static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa, return false; } -static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa, +static bool cyapa_sort_pip_deep_sleep_data(struct cyapa *cyapa, u8 *buf, int len) { - if (len == GEN5_DEEP_SLEEP_RESP_LENGTH && - buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_DEEP_SLEEP_REPORT_ID && - (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) == - GEN5_DEEP_SLEEP_OPCODE) + if (len == PIP_DEEP_SLEEP_RESP_LENGTH && + buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_APP_DEEP_SLEEP_REPORT_ID && + (buf[4] & PIP_DEEP_SLEEP_OPCODE_MASK) == + PIP_DEEP_SLEEP_OPCODE) return true; return false; } static int gen5_idle_state_parse(struct cyapa *cyapa) { - u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE]; + u8 resp_data[PIP_HID_DESCRIPTOR_SIZE]; int max_output_len; int length; u8 cmd[2]; @@ -778,9 +719,9 @@ static int gen5_idle_state_parse(struct cyapa *cyapa) if (ret != 3) return ret < 0 ? ret : -EIO; - length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); - if (length == GEN5_RESP_LENGTH_SIZE) { - /* Normal state of Gen5 with no data to respose */ + length = get_unaligned_le16(&resp_data[PIP_RESP_LENGTH_OFFSET]); + if (length == PIP_RESP_LENGTH_SIZE) { + /* Normal state of Gen5 with no data to response */ cyapa->gen = CYAPA_GEN5; cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); @@ -788,30 +729,30 @@ static int gen5_idle_state_parse(struct cyapa *cyapa) /* Read description from trackpad device */ cmd[0] = 0x01; cmd[1] = 0x00; - length = GEN5_HID_DESCRIPTOR_SIZE; + length = PIP_HID_DESCRIPTOR_SIZE; error = cyapa_i2c_pip_cmd_irq_sync(cyapa, - cmd, GEN5_RESP_LENGTH_SIZE, + cmd, PIP_RESP_LENGTH_SIZE, resp_data, &length, 300, - cyapa_gen5_sort_hid_descriptor_data, + cyapa_sort_gen5_hid_descriptor_data, false); if (error) return error; length = get_unaligned_le16( - &resp_data[GEN5_RESP_LENGTH_OFFSET]); + &resp_data[PIP_RESP_LENGTH_OFFSET]); max_output_len = get_unaligned_le16(&resp_data[16]); - if ((length == GEN5_HID_DESCRIPTOR_SIZE || - length == GEN5_RESP_LENGTH_SIZE) && - (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_HID_REPORT_ID) && + if ((length == PIP_HID_DESCRIPTOR_SIZE || + length == PIP_RESP_LENGTH_SIZE) && + (resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_BL_REPORT_ID) && max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { /* BL mode HID Description read */ cyapa->state = CYAPA_STATE_GEN5_BL; - } else if ((length == GEN5_HID_DESCRIPTOR_SIZE || - length == GEN5_RESP_LENGTH_SIZE) && - (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_HID_REPORT_ID) && + } else if ((length == PIP_HID_DESCRIPTOR_SIZE || + length == PIP_RESP_LENGTH_SIZE) && + (resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_APP_REPORT_ID) && max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { /* APP mode HID Description read */ cyapa->state = CYAPA_STATE_GEN5_APP; @@ -839,14 +780,14 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) * or report any touch or button data. */ ret = cyapa_i2c_pip_read(cyapa, resp_data, - GEN5_HID_DESCRIPTOR_SIZE); - if (ret != GEN5_HID_DESCRIPTOR_SIZE) + PIP_HID_DESCRIPTOR_SIZE); + if (ret != PIP_HID_DESCRIPTOR_SIZE) return ret < 0 ? ret : -EIO; - length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]); + length = get_unaligned_le16(&resp_data[PIP_RESP_LENGTH_OFFSET]); max_output_len = get_unaligned_le16(&resp_data[16]); - if (length == GEN5_RESP_LENGTH_SIZE) { - if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_HID_REPORT_ID) { + if (length == PIP_RESP_LENGTH_SIZE) { + if (reg_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_BL_REPORT_ID) { /* * BL mode HID Description has been previously * read out. @@ -861,15 +802,15 @@ static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data) cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_APP; } - } else if (length == GEN5_HID_DESCRIPTOR_SIZE && - resp_data[2] == GEN5_BL_HID_REPORT_ID && + } else if (length == PIP_HID_DESCRIPTOR_SIZE && + resp_data[2] == PIP_HID_BL_REPORT_ID && max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) { /* BL mode HID Description read. */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; - } else if (length == GEN5_HID_DESCRIPTOR_SIZE && - (resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_HID_REPORT_ID) && + } else if (length == PIP_HID_DESCRIPTOR_SIZE && + (resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_HID_APP_REPORT_ID) && max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) { /* APP mode HID Description read. */ cyapa->gen = CYAPA_GEN5; @@ -886,22 +827,22 @@ static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) { int length; - length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); - switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) { - case GEN5_TOUCH_REPORT_ID: - if (length < GEN5_TOUCH_REPORT_HEAD_SIZE || - length > GEN5_TOUCH_REPORT_MAX_SIZE) + length = get_unaligned_le16(®_data[PIP_RESP_LENGTH_OFFSET]); + switch (reg_data[PIP_RESP_REPORT_ID_OFFSET]) { + case PIP_TOUCH_REPORT_ID: + if (length < PIP_TOUCH_REPORT_HEAD_SIZE || + length > PIP_TOUCH_REPORT_MAX_SIZE) return -EINVAL; break; - case GEN5_BTN_REPORT_ID: + case PIP_BTN_REPORT_ID: case GEN5_OLD_PUSH_BTN_REPORT_ID: - case GEN5_PUSH_BTN_REPORT_ID: - if (length < GEN5_BTN_REPORT_HEAD_SIZE || - length > GEN5_BTN_REPORT_MAX_SIZE) + case PIP_PUSH_BTN_REPORT_ID: + if (length < PIP_BTN_REPORT_HEAD_SIZE || + length > PIP_BTN_REPORT_MAX_SIZE) return -EINVAL; break; - case GEN5_WAKEUP_EVENT_REPORT_ID: - if (length != GEN5_WAKEUP_EVENT_SIZE) + case PIP_WAKEUP_EVENT_REPORT_ID: + if (length != PIP_WAKEUP_EVENT_SIZE) return -EINVAL; break; default: @@ -915,7 +856,7 @@ static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data) static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int length; int ret; @@ -924,15 +865,15 @@ static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) * otherwise Gen5 trackpad cannot response next command * or report any touch or button data. */ - length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); - ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length); + length = get_unaligned_le16(®_data[PIP_RESP_LENGTH_OFFSET]); + ret = cyapa_i2c_pip_read(cyapa, pip->empty_buf, length); if (ret != length) return ret < 0 ? ret : -EIO; - if (length == GEN5_RESP_LENGTH_SIZE) { + if (length == PIP_RESP_LENGTH_SIZE) { /* Previous command has read the data through out. */ - if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID) { + if (reg_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID) { /* Gen5 BL command response data detected */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; @@ -941,21 +882,21 @@ static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data) cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_APP; } - } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID) && - (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == - GEN5_RESP_RSVD_KEY) && - (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] == - GEN5_SOP_KEY) && - (gen5_pip->empty_buf[length - 1] == - GEN5_EOP_KEY)) { + } else if ((pip->empty_buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID) && + (pip->empty_buf[PIP_RESP_RSVD_OFFSET] == + PIP_RESP_RSVD_KEY) && + (pip->empty_buf[PIP_RESP_BL_SOP_OFFSET] == + PIP_SOP_KEY) && + (pip->empty_buf[length - 1] == + PIP_EOP_KEY)) { /* Gen5 BL command response data detected */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; - } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_APP_RESP_REPORT_ID && - gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] == - GEN5_RESP_RSVD_KEY) { + } else if (pip->empty_buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_APP_RESP_REPORT_ID && + pip->empty_buf[PIP_RESP_RSVD_OFFSET] == + PIP_RESP_RSVD_KEY) { /* Gen5 APP command response data detected */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_APP; @@ -977,12 +918,12 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) cyapa->state = CYAPA_STATE_NO_DEVICE; /* Parse based on Gen5 characteristic registers and bits */ - length = get_unaligned_le16(®_data[GEN5_RESP_LENGTH_OFFSET]); - if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) { + length = get_unaligned_le16(®_data[PIP_RESP_LENGTH_OFFSET]); + if (length == 0 || length == PIP_RESP_LENGTH_SIZE) { gen5_idle_state_parse(cyapa); - } else if (length == GEN5_HID_DESCRIPTOR_SIZE && - (reg_data[2] == GEN5_BL_HID_REPORT_ID || - reg_data[2] == GEN5_APP_HID_REPORT_ID)) { + } else if (length == PIP_HID_DESCRIPTOR_SIZE && + (reg_data[2] == PIP_HID_BL_REPORT_ID || + reg_data[2] == PIP_HID_APP_REPORT_ID)) { gen5_hid_description_header_parse(cyapa, reg_data); } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE || length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) && @@ -992,17 +933,17 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) cyapa->state = CYAPA_STATE_GEN5_APP; } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE && reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) { - /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */ + /* 0x1D 0x00 0xFE is Gen5 BL report descriptor header. */ cyapa->gen = CYAPA_GEN5; cyapa->state = CYAPA_STATE_GEN5_BL; - } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID || - reg_data[2] == GEN5_BTN_REPORT_ID || + } else if (reg_data[2] == PIP_TOUCH_REPORT_ID || + reg_data[2] == PIP_BTN_REPORT_ID || reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID || - reg_data[2] == GEN5_PUSH_BTN_REPORT_ID || - reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) { + reg_data[2] == PIP_PUSH_BTN_REPORT_ID || + reg_data[2] == PIP_WAKEUP_EVENT_REPORT_ID) { gen5_report_data_header_parse(cyapa, reg_data); - } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID || - reg_data[2] == GEN5_APP_RESP_REPORT_ID) { + } else if (reg_data[2] == PIP_BL_RESP_REPORT_ID || + reg_data[2] == PIP_APP_RESP_REPORT_ID) { gen5_cmd_resp_header_parse(cyapa, reg_data); } @@ -1023,14 +964,25 @@ static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) return -EAGAIN; } -static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, - const struct firmware *fw) +static struct cyapa_tsg_bin_image_data_record * +cyapa_get_image_record_data_num(const struct firmware *fw, + int *record_num) +{ + int head_size; + + head_size = fw->data[0] + 1; + *record_num = (fw->size - head_size) / + sizeof(struct cyapa_tsg_bin_image_data_record); + return (struct cyapa_tsg_bin_image_data_record *)&fw->data[head_size]; +} + +int cyapa_pip_bl_initiate(struct cyapa *cyapa, const struct firmware *fw) { - struct cyapa_tsg_bin_image *image; - struct gen5_bl_cmd_head *bl_cmd_head; - struct gen5_bl_packet_start *bl_packet_start; - struct gen5_bl_initiate_cmd_data *cmd_data; - struct gen5_bl_packet_end *bl_packet_end; + struct cyapa_tsg_bin_image_data_record *image_records; + struct pip_bl_cmd_head *bl_cmd_head; + struct pip_bl_packet_start *bl_packet_start; + struct pip_bl_initiate_cmd_data *cmd_data; + struct pip_bl_packet_end *bl_packet_end; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; int cmd_len; u16 cmd_data_len; @@ -1046,30 +998,28 @@ static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; + bl_cmd_head = (struct pip_bl_cmd_head *)cmd; cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE; - cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len + - sizeof(struct gen5_bl_packet_end); + cmd_len = sizeof(struct pip_bl_cmd_head) + cmd_data_len + + sizeof(struct pip_bl_packet_end); - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); - bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; + bl_cmd_head->report_id = PIP_BL_CMD_REPORT_ID; bl_packet_start = &bl_cmd_head->packet_start; - bl_packet_start->sop = GEN5_SOP_KEY; - bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL; + bl_packet_start->sop = PIP_SOP_KEY; + bl_packet_start->cmd_code = PIP_BL_CMD_INITIATE_BL; /* 8 key bytes and 128 bytes block size */ put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length); - cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data; - memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE); + cmd_data = (struct pip_bl_initiate_cmd_data *)bl_cmd_head->data; + memcpy(cmd_data->key, cyapa_pip_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE); + + image_records = cyapa_get_image_record_data_num(fw, &records_num); - /* Copy 60 bytes Meta Data Row Parameters */ - image = (struct cyapa_tsg_bin_image *)fw->data; - records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / - sizeof(struct cyapa_tsg_bin_image_data_record); /* APP_INTEGRITY row is always the last row block */ - data = image->records[records_num - 1].record_data; + data = image_records[records_num - 1].record_data; memcpy(cmd_data->metadata_raw_parameter, data, CYAPA_TSG_FLASH_MAP_METADATA_SIZE); @@ -1077,47 +1027,47 @@ static int cyapa_gen5_bl_initiate(struct cyapa *cyapa, CYAPA_TSG_FLASH_MAP_METADATA_SIZE); put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc); - bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + + bl_packet_end = (struct pip_bl_packet_end *)(bl_cmd_head->data + cmd_data_len); cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, - sizeof(struct gen5_bl_packet_start) + cmd_data_len); + sizeof(struct pip_bl_packet_start) + cmd_data_len); put_unaligned_le16(cmd_crc, &bl_packet_end->crc); - bl_packet_end->eop = GEN5_EOP_KEY; + bl_packet_end->eop = PIP_EOP_KEY; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, 12000, - cyapa_gen5_sort_tsg_pip_bl_resp_data, true); - if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN || - resp_data[2] != GEN5_BL_RESP_REPORT_ID || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + cyapa_sort_tsg_pip_bl_resp_data, true); + if (error || resp_len != PIP_BL_INITIATE_RESP_LEN || + resp_data[2] != PIP_BL_RESP_REPORT_ID || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error ? error : -EAGAIN; return 0; } -static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) +static bool cyapa_sort_pip_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len) { - if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE) + if (buf == NULL || len < PIP_RESP_LENGTH_SIZE) return false; if (buf[0] == 0 && buf[1] == 0) return true; /* Exit bootloader failed for some reason. */ - if (len == GEN5_BL_FAIL_EXIT_RESP_LEN && - buf[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID && - buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY && - buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY && - buf[10] == GEN5_EOP_KEY) + if (len == PIP_BL_FAIL_EXIT_RESP_LEN && + buf[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID && + buf[PIP_RESP_RSVD_OFFSET] == PIP_RESP_RSVD_KEY && + buf[PIP_RESP_BL_SOP_OFFSET] == PIP_SOP_KEY && + buf[10] == PIP_EOP_KEY) return true; return false; } -static int cyapa_gen5_bl_exit(struct cyapa *cyapa) +int cyapa_pip_bl_exit(struct cyapa *cyapa) { u8 bl_gen5_bl_exit[] = { 0x04, 0x00, @@ -1132,13 +1082,13 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit), resp_data, &resp_len, - 5000, cyapa_gen5_sort_bl_exit_data, false); + 5000, cyapa_sort_pip_bl_exit_data, false); if (error) return error; - if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN || - resp_data[GEN5_RESP_REPORT_ID_OFFSET] == - GEN5_BL_RESP_REPORT_ID) + if (resp_len == PIP_BL_FAIL_EXIT_RESP_LEN || + resp_data[PIP_RESP_REPORT_ID_OFFSET] == + PIP_BL_RESP_REPORT_ID) return -EAGAIN; if (resp_data[0] == 0x00 && resp_data[1] == 0x00) @@ -1147,7 +1097,7 @@ static int cyapa_gen5_bl_exit(struct cyapa *cyapa) return -ENODEV; } -static int cyapa_gen5_bl_enter(struct cyapa *cyapa) +int cyapa_pip_bl_enter(struct cyapa *cyapa) { u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 }; u8 resp_data[2]; @@ -1157,15 +1107,12 @@ static int cyapa_gen5_bl_enter(struct cyapa *cyapa) error = cyapa_poll_state(cyapa, 500); if (error < 0) return error; - if (cyapa->gen != CYAPA_GEN5) - return -EINVAL; - /* Already in Gen5 BL. Skipping exit. */ - if (cyapa->state == CYAPA_STATE_GEN5_BL) + /* Already in bootloader mode, Skipping exit. */ + if (cyapa_is_pip_bl_mode(cyapa)) return 0; - - if (cyapa->state != CYAPA_STATE_GEN5_APP) - return -EAGAIN; + else if (!cyapa_is_pip_app_mode(cyapa)) + return -EINVAL; /* Try to dump all buffered report data before any send command. */ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); @@ -1179,39 +1126,38 @@ static int cyapa_gen5_bl_enter(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 5000, cyapa_gen5_sort_application_launch_data, + 5000, cyapa_sort_pip_application_launch_data, true); if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00) return error < 0 ? error : -EAGAIN; cyapa->operational = false; - cyapa->state = CYAPA_STATE_GEN5_BL; + if (cyapa->gen == CYAPA_GEN5) + cyapa->state = CYAPA_STATE_GEN5_BL; return 0; } -static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) +int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw) { struct device *dev = &cyapa->client->dev; - const struct cyapa_tsg_bin_image *image = (const void *)fw->data; + struct cyapa_tsg_bin_image_data_record *image_records; const struct cyapa_tsg_bin_image_data_record *app_integrity; - const struct gen5_bl_metadata_row_params *metadata; - size_t flash_records_count; + const struct tsg_bl_metadata_row_params *metadata; + int flash_records_count; u32 fw_app_start, fw_upgrade_start; u16 fw_app_len, fw_upgrade_len; u16 app_crc; u16 app_integrity_crc; - int record_index; int i; - flash_records_count = (fw->size - - sizeof(struct cyapa_tsg_bin_image_head)) / - sizeof(struct cyapa_tsg_bin_image_data_record); + image_records = + cyapa_get_image_record_data_num(fw, &flash_records_count); /* * APP_INTEGRITY row is always the last row block, * and the row id must be 0x01ff. */ - app_integrity = &image->records[flash_records_count - 1]; + app_integrity = &image_records[flash_records_count - 1]; if (app_integrity->flash_array_id != 0x00 || get_unaligned_be16(&app_integrity->row_number) != 0x01ff) { @@ -1242,14 +1188,11 @@ static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) return -EINVAL; } - /* - * Verify application image CRC - */ - record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE - - CYAPA_TSG_IMG_START_ROW_NUM; + /* Verify application image CRC. */ app_crc = 0xffffU; for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) { - const u8 *data = image->records[record_index + i].record_data; + const u8 *data = image_records[i].record_data; + app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE); } @@ -1261,13 +1204,13 @@ static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw) return 0; } -static int cyapa_gen5_write_fw_block(struct cyapa *cyapa, +static int cyapa_pip_write_fw_block(struct cyapa *cyapa, struct cyapa_tsg_bin_image_data_record *flash_record) { - struct gen5_bl_cmd_head *bl_cmd_head; - struct gen5_bl_packet_start *bl_packet_start; - struct gen5_bl_flash_row_head *flash_row_head; - struct gen5_bl_packet_end *bl_packet_end; + struct pip_bl_cmd_head *bl_cmd_head; + struct pip_bl_packet_start *bl_packet_start; + struct tsg_bl_flash_row_head *flash_row_head; + struct pip_bl_packet_end *bl_packet_end; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; u16 cmd_len; u8 flash_array_id; @@ -1286,71 +1229,68 @@ static int cyapa_gen5_write_fw_block(struct cyapa *cyapa, record_data = flash_record->record_data; memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - bl_cmd_head = (struct gen5_bl_cmd_head *)cmd; + bl_cmd_head = (struct pip_bl_cmd_head *)cmd; bl_packet_start = &bl_cmd_head->packet_start; - cmd_len = sizeof(struct gen5_bl_cmd_head) + - sizeof(struct gen5_bl_flash_row_head) + + cmd_len = sizeof(struct pip_bl_cmd_head) + + sizeof(struct tsg_bl_flash_row_head) + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE + - sizeof(struct gen5_bl_packet_end); + sizeof(struct pip_bl_packet_end); - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr); /* Don't include 2 bytes register address */ put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length); - bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID; - bl_packet_start->sop = GEN5_SOP_KEY; - bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW; + bl_cmd_head->report_id = PIP_BL_CMD_REPORT_ID; + bl_packet_start->sop = PIP_SOP_KEY; + bl_packet_start->cmd_code = PIP_BL_CMD_PROGRAM_VERIFY_ROW; /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */ - data_len = sizeof(struct gen5_bl_flash_row_head) + record_len; + data_len = sizeof(struct tsg_bl_flash_row_head) + record_len; put_unaligned_le16(data_len, &bl_packet_start->data_length); - flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data; + flash_row_head = (struct tsg_bl_flash_row_head *)bl_cmd_head->data; flash_row_head->flash_array_id = flash_array_id; put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id); memcpy(flash_row_head->flash_data, record_data, record_len); - bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data + + bl_packet_end = (struct pip_bl_packet_end *)(bl_cmd_head->data + data_len); crc = crc_itu_t(0xffff, (u8 *)bl_packet_start, - sizeof(struct gen5_bl_packet_start) + data_len); + sizeof(struct pip_bl_packet_start) + data_len); put_unaligned_le16(crc, &bl_packet_end->crc); - bl_packet_end->eop = GEN5_EOP_KEY; + bl_packet_end->eop = PIP_EOP_KEY; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true); - if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN || - resp_data[2] != GEN5_BL_RESP_REPORT_ID || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + 500, cyapa_sort_tsg_pip_bl_resp_data, true); + if (error || resp_len != PIP_BL_BLOCK_WRITE_RESP_LEN || + resp_data[2] != PIP_BL_RESP_REPORT_ID || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error < 0 ? error : -EAGAIN; return 0; } -static int cyapa_gen5_do_fw_update(struct cyapa *cyapa, +int cyapa_pip_do_fw_update(struct cyapa *cyapa, const struct firmware *fw) { struct device *dev = &cyapa->client->dev; - struct cyapa_tsg_bin_image_data_record *flash_record; - struct cyapa_tsg_bin_image *image = - (struct cyapa_tsg_bin_image *)fw->data; + struct cyapa_tsg_bin_image_data_record *image_records; int flash_records_count; int i; int error; cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - flash_records_count = - (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) / - sizeof(struct cyapa_tsg_bin_image_data_record); + image_records = + cyapa_get_image_record_data_num(fw, &flash_records_count); + /* * The last flash row 0x01ff has been written through bl_initiate * command, so DO NOT write flash 0x01ff to trackpad device. */ for (i = 0; i < (flash_records_count - 1); i++) { - flash_record = &image->records[i]; - error = cyapa_gen5_write_fw_block(cyapa, flash_record); + error = cyapa_pip_write_fw_block(cyapa, &image_records[i]); if (error) { dev_err(dev, "%s: Gen5 FW update aborted: %d\n", __func__, error); @@ -1372,9 +1312,9 @@ static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error < 0 ? error : -EINVAL; return 0; @@ -1383,7 +1323,7 @@ static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state) static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, u8 parameter_id, u16 interval_time) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; struct gen5_app_set_parameter_data *parameter_data; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; int cmd_len; @@ -1393,10 +1333,10 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, int error; memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; + app_cmd_head = (struct pip_app_cmd_head *)cmd; parameter_data = (struct gen5_app_set_parameter_data *) app_cmd_head->parameter_data; - cmd_len = sizeof(struct gen5_app_cmd_head) + + cmd_len = sizeof(struct pip_app_cmd_head) + sizeof(struct gen5_app_set_parameter_data); switch (parameter_id) { @@ -1413,14 +1353,14 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, return -EINVAL; } - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); /* * Don't include unused parameter value bytes and * 2 bytes register address. */ put_unaligned_le16(cmd_len - (4 - parameter_size) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; parameter_data->parameter_id = parameter_id; parameter_data->parameter_size = parameter_size; @@ -1428,7 +1368,7 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || resp_data[5] != parameter_id || resp_data[6] != parameter_size || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER)) @@ -1440,7 +1380,7 @@ static int cyapa_gen5_set_interval_time(struct cyapa *cyapa, static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, u8 parameter_id, u16 *interval_time) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; struct gen5_app_get_parameter_data *parameter_data; u8 cmd[CYAPA_TSG_MAX_CMD_SIZE]; int cmd_len; @@ -1451,10 +1391,10 @@ static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, int error; memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; + app_cmd_head = (struct pip_app_cmd_head *)cmd; parameter_data = (struct gen5_app_get_parameter_data *) app_cmd_head->parameter_data; - cmd_len = sizeof(struct gen5_app_cmd_head) + + cmd_len = sizeof(struct pip_app_cmd_head) + sizeof(struct gen5_app_get_parameter_data); *interval_time = 0; @@ -1472,17 +1412,17 @@ static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, return -EINVAL; } - put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); /* Don't include 2 bytes register address */ put_unaligned_le16(cmd_len - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER; parameter_data->parameter_id = parameter_id; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || resp_data[5] != parameter_id || resp_data[6] == 0 || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER)) return error < 0 ? error : -EINVAL; @@ -1497,18 +1437,18 @@ static int cyapa_gen5_get_interval_time(struct cyapa *cyapa, static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; u8 cmd[10]; u8 resp_data[7]; int resp_len; int error; memset(cmd, 0, sizeof(cmd)); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; + app_cmd_head = (struct pip_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER; app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT; app_cmd_head->parameter_data[1] = 0x01; @@ -1516,7 +1456,7 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false); + 500, cyapa_sort_tsg_pip_app_resp_data, false); if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) || resp_data[6] != 0x01) @@ -1525,19 +1465,19 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) return 0; } -static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state) +int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) { u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; u8 resp_data[5]; int resp_len; int error; - cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK; + cmd[2] = state & PIP_DEEP_SLEEP_STATE_MASK; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_deep_sleep_data, false); - if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state)) + 500, cyapa_sort_pip_deep_sleep_data, false); + if (error || ((resp_data[3] & PIP_DEEP_SLEEP_STATE_MASK) != state)) return -EINVAL; return 0; @@ -1556,40 +1496,40 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, /* Dump all the report data before do power mode commmands. */ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { + if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { /* * Assume TP in deep sleep mode when driver is loaded, * avoid driver unload and reload command IO issue caused by TP * has been set into deep sleep mode when unloading. */ - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); } - if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) && - GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) + if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) && + PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) if (cyapa_gen5_get_interval_time(cyapa, GEN5_PARAMETER_LP_INTRVL_ID, &cyapa->dev_sleep_time) != 0) - GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); + PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); - if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) { + if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) { if (power_mode == PWR_MODE_OFF || power_mode == PWR_MODE_FULL_ACTIVE || power_mode == PWR_MODE_BTN_ONLY || - GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { + PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { /* Has in correct power mode state, early return. */ return 0; } } if (power_mode == PWR_MODE_OFF) { - error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF); + error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); if (error) { dev_err(dev, "enter deep sleep fail: %d\n", error); return error; } - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); return 0; } @@ -1598,8 +1538,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, * state directly, must be wake up from sleep firstly, then * continue to do next power sate change. */ - if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { - error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON); + if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { + error = cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); if (error) { dev_err(dev, "deep sleep wake fail: %d\n", error); return error; @@ -1614,7 +1554,7 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, return error; } - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); } else if (power_mode == PWR_MODE_BTN_ONLY) { error = cyapa_gen5_change_power_state(cyapa, GEN5_POWER_STATE_BTN_ONLY); @@ -1623,19 +1563,19 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, return error; } - GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); } else { /* * Continue to change power mode even failed to set * interval time, it won't affect the power mode change. * except the sleep interval time is not correct. */ - if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) || - sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa)) + if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) || + sleep_time != PIP_DEV_GET_SLEEP_TIME(cyapa)) if (cyapa_gen5_set_interval_time(cyapa, GEN5_PARAMETER_LP_INTRVL_ID, sleep_time) == 0) - GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time); + PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time); if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME) power_state = GEN5_POWER_STATE_READY; @@ -1661,14 +1601,14 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); cyapa_gen5_disable_pip_report(cyapa); - GEN5_DEV_SET_PWR_STATE(cyapa, + PIP_DEV_SET_PWR_STATE(cyapa, cyapa_sleep_time_to_pwr_cmd(sleep_time)); } return 0; } -static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) +int cyapa_pip_resume_scanning(struct cyapa *cyapa) { u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 }; u8 resp_data[6]; @@ -1682,7 +1622,7 @@ static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04)) return -EINVAL; @@ -1692,7 +1632,7 @@ static int cyapa_gen5_resume_scanning(struct cyapa *cyapa) return 0; } -static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) +int cyapa_pip_suspend_scanning(struct cyapa *cyapa) { u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 }; u8 resp_data[6]; @@ -1706,7 +1646,7 @@ static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03)) return -EINVAL; @@ -1716,10 +1656,10 @@ static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa) return 0; } -static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa, +static int cyapa_pip_calibrate_pwcs(struct cyapa *cyapa, u8 calibrate_sensing_mode_type) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; u8 cmd[8]; u8 resp_data[6]; int resp_len; @@ -1729,25 +1669,25 @@ static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa, cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); memset(cmd, 0, sizeof(cmd)); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + app_cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; - app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; + app_cmd_head->cmd_code = PIP_CMD_CALIBRATE; app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true); - if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + 5000, cyapa_sort_tsg_pip_app_resp_data, true); + if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_CMD_CALIBRATE) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error < 0 ? error : -EAGAIN; return 0; } -static ssize_t cyapa_gen5_do_calibrate(struct device *dev, +ssize_t cyapa_pip_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -1755,25 +1695,25 @@ static ssize_t cyapa_gen5_do_calibrate(struct device *dev, int error, calibrate_error; /* 1. Suspend Scanning*/ - error = cyapa_gen5_suspend_scanning(cyapa); + error = cyapa_pip_suspend_scanning(cyapa); if (error) return error; /* 2. Do mutual capacitance fine calibrate. */ - calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, - CYAPA_SENSING_MODE_MUTUAL_CAP_FINE); + calibrate_error = cyapa_pip_calibrate_pwcs(cyapa, + PIP_SENSING_MODE_MUTUAL_CAP_FINE); if (calibrate_error) goto resume_scanning; /* 3. Do self capacitance calibrate. */ - calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa, - CYAPA_SENSING_MODE_SELF_CAP); + calibrate_error = cyapa_pip_calibrate_pwcs(cyapa, + PIP_SENSING_MODE_SELF_CAP); if (calibrate_error) goto resume_scanning; resume_scanning: /* 4. Resume Scanning*/ - error = cyapa_gen5_resume_scanning(cyapa); + error = cyapa_pip_resume_scanning(cyapa); if (error || calibrate_error) return error ? error : calibrate_error; @@ -1856,7 +1796,7 @@ static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa, * If the input value of @data_size is not 0, than means read the mutual or * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to * return the max, min and average value of the mutual or self local PWC data. - * Note, in order to raed mutual local PWC data, must read invoke this function + * Note, in order to read mutual local PWC data, must read invoke this function * to read the mutual global idac data firstly to set the correct Rx number * value, otherwise, the read mutual idac and PWC data may not correct. */ @@ -1864,7 +1804,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, u8 cmd_code, u8 idac_data_type, int *data_size, int *idac_max, int *idac_min, int *idac_ave) { - struct gen5_app_cmd_head *cmd_head; + struct pip_app_cmd_head *cmd_head; u8 cmd[12]; u8 resp_data[256]; int resp_len; @@ -1879,7 +1819,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, int i; int error; - if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE || + if (cmd_code != PIP_RETRIEVE_DATA_STRUCTURE || (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA && idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) || !data_size || !idac_max || !idac_min || !idac_ave) @@ -1935,10 +1875,10 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, } memset(cmd, 0, sizeof(cmd)); - cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr); + cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length); - cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + cmd_head->report_id = PIP_APP_CMD_REPORT_ID; cmd_head->cmd_code = cmd_code; do { read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / @@ -1953,11 +1893,11 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data) || resp_data[6] != idac_data_type) return (error < 0) ? error : -EAGAIN; read_len = get_unaligned_le16(&resp_data[7]); @@ -1997,7 +1937,7 @@ static int cyapa_gen5_read_idac_data(struct cyapa *cyapa, tmp_count < cyapa->aligned_electrodes_rx && read_global_idac) { /* - * The value gap betwen global and local mutual + * The value gap between global and local mutual * idac data must bigger than 50%. * Normally, global value bigger than 50, * local values less than 10. @@ -2061,7 +2001,7 @@ static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa, data_size = 0; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_MUTUAL_PWC_DATA, &data_size, gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave); @@ -2069,7 +2009,7 @@ static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa, return error; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_MUTUAL_PWC_DATA, &data_size, lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave); @@ -2088,7 +2028,7 @@ static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, data_size = 0; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_SELF_CAP_PWC_DATA, &data_size, lidac_self_max, lidac_self_min, lidac_self_ave); @@ -2098,7 +2038,7 @@ static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, *gidac_self_tx = *lidac_self_min; error = cyapa_gen5_read_idac_data(cyapa, - GEN5_CMD_RETRIEVE_DATA_STRUCTURE, + PIP_RETRIEVE_DATA_STRUCTURE, GEN5_RETRIEVE_SELF_CAP_PWC_DATA, &data_size, lidac_self_max, lidac_self_min, lidac_self_ave); @@ -2107,27 +2047,27 @@ static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa, static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; u8 cmd[7]; u8 resp_data[6]; int resp_len; int error; memset(cmd, 0, sizeof(cmd)); - app_cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + app_cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || resp_len != sizeof(resp_data) || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_EXECUTE_PANEL_SCAN) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error ? error : -EAGAIN; return 0; @@ -2138,7 +2078,7 @@ static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, int *raw_data_max, int *raw_data_min, int *raw_data_ave, u8 *buffer) { - struct gen5_app_cmd_head *app_cmd_head; + struct pip_app_cmd_head *app_cmd_head; struct gen5_retrieve_panel_scan_data *panel_sacn_data; u8 cmd[12]; u8 resp_data[256]; /* Max bytes can transfer one time. */ @@ -2166,10 +2106,10 @@ static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, /* Assume max element size is 4 currently. */ read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4; read_len = read_elements * 4; - app_cmd_head = (struct gen5_app_cmd_head *)cmd; - put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); + app_cmd_head = (struct pip_app_cmd_head *)cmd; + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &app_cmd_head->addr); put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length); - app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID; + app_cmd_head->report_id = PIP_APP_CMD_REPORT_ID; app_cmd_head->cmd_code = cmd_code; panel_sacn_data = (struct gen5_retrieve_panel_scan_data *) app_cmd_head->parameter_data; @@ -2183,10 +2123,10 @@ static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa, error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true); + 500, cyapa_sort_tsg_pip_app_resp_data, true); if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data) || resp_data[6] != raw_data_type) return error ? error : -EAGAIN; @@ -2245,11 +2185,11 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev, int error, resume_error; int size; - if (cyapa->state != CYAPA_STATE_GEN5_APP) + if (!cyapa_is_pip_app_mode(cyapa)) return -EBUSY; /* 1. Suspend Scanning*/ - error = cyapa_gen5_suspend_scanning(cyapa); + error = cyapa_pip_suspend_scanning(cyapa); if (error) return error; @@ -2270,7 +2210,7 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev, if (error) goto resume_scanning; - /* 4. Execuate panel scan. It must be executed before read data. */ + /* 4. Execute panel scan. It must be executed before read data. */ error = cyapa_gen5_execute_panel_scan(cyapa); if (error) goto resume_scanning; @@ -2343,7 +2283,7 @@ static ssize_t cyapa_gen5_show_baseline(struct device *dev, resume_scanning: /* 11. Resume Scanning*/ - resume_error = cyapa_gen5_resume_scanning(cyapa); + resume_error = cyapa_pip_resume_scanning(cyapa); if (resume_error || error) return resume_error ? resume_error : error; @@ -2364,7 +2304,7 @@ resume_scanning: return size; } -static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, +bool cyapa_pip_sort_system_info_data(struct cyapa *cyapa, u8 *buf, int len) { /* Check the report id and command code */ @@ -2376,20 +2316,17 @@ static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa, static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) { - u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00, - 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17 - }; - u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN]; + u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH]; int resp_len; int error; - resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN; + resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, - bl_query_data_cmd, sizeof(bl_query_data_cmd), + pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH, resp_data, &resp_len, - 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false); - if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN || - !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5])) + 500, cyapa_sort_tsg_pip_bl_resp_data, false); + if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) return error ? error : -EIO; memcpy(&cyapa->product_id[0], &resp_data[8], 5); @@ -2407,25 +2344,22 @@ static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) static int cyapa_gen5_get_query_data(struct cyapa *cyapa) { - u8 get_system_information[] = { - 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02 - }; - u8 resp_data[71]; + u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; int resp_len; u16 product_family; int error; resp_len = sizeof(resp_data); error = cyapa_i2c_pip_cmd_irq_sync(cyapa, - get_system_information, sizeof(get_system_information), + pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, resp_data, &resp_len, - 2000, cyapa_gen5_sort_system_info_data, false); + 2000, cyapa_pip_sort_system_info_data, false); if (error || resp_len < sizeof(resp_data)) return error ? error : -EIO; product_family = get_unaligned_le16(&resp_data[7]); - if ((product_family & GEN5_PRODUCT_FAMILY_MASK) != - GEN5_PRODUCT_FAMILY_TRACKPAD) + if ((product_family & PIP_PRODUCT_FAMILY_MASK) != + PIP_PRODUCT_FAMILY_TRACKPAD) return -EINVAL; cyapa->fw_maj_ver = resp_data[15]; @@ -2472,9 +2406,9 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) switch (cyapa->state) { case CYAPA_STATE_GEN5_BL: - error = cyapa_gen5_bl_exit(cyapa); + error = cyapa_pip_bl_exit(cyapa); if (error) { - /* Rry to update trackpad product information. */ + /* Try to update trackpad product information. */ cyapa_gen5_bl_query_data(cyapa); goto out; } @@ -2486,7 +2420,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) * If trackpad device in deep sleep mode, * the app command will fail. * So always try to reset trackpad device to full active when - * the device state is requeried. + * the device state is required. */ error = cyapa_gen5_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); @@ -2518,14 +2452,14 @@ out: * Return false, do not continue process * Return true, continue process. */ -static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) +bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa) { - struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5; + struct cyapa_pip_cmd_states *pip = &cyapa->cmd_states.pip; int length; - if (atomic_read(&gen5_pip->cmd_issued)) { + if (atomic_read(&pip->cmd_issued)) { /* Polling command response data. */ - if (gen5_pip->is_irq_mode == false) + if (pip->is_irq_mode == false) return false; /* @@ -2533,59 +2467,64 @@ static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa) * these output data may caused by user put finger on * trackpad when host waiting the command response. */ - cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf, - GEN5_RESP_LENGTH_SIZE); - length = get_unaligned_le16(gen5_pip->irq_cmd_buf); - length = (length <= GEN5_RESP_LENGTH_SIZE) ? - GEN5_RESP_LENGTH_SIZE : length; - if (length > GEN5_RESP_LENGTH_SIZE) + cyapa_i2c_pip_read(cyapa, pip->irq_cmd_buf, + PIP_RESP_LENGTH_SIZE); + length = get_unaligned_le16(pip->irq_cmd_buf); + length = (length <= PIP_RESP_LENGTH_SIZE) ? + PIP_RESP_LENGTH_SIZE : length; + if (length > PIP_RESP_LENGTH_SIZE) cyapa_i2c_pip_read(cyapa, - gen5_pip->irq_cmd_buf, length); - - if (!(gen5_pip->resp_sort_func && - gen5_pip->resp_sort_func(cyapa, - gen5_pip->irq_cmd_buf, length))) { + pip->irq_cmd_buf, length); + if (!(pip->resp_sort_func && + pip->resp_sort_func(cyapa, + pip->irq_cmd_buf, length))) { /* - * Work around the Gen5 V1 firmware - * that does not assert interrupt signalling - * that command response is ready if user - * keeps touching the trackpad while command - * is sent to the device. + * Cover the Gen5 V1 firmware issue. + * The issue is no interrupt would be asserted from + * trackpad device to host for the command response + * ready event. Because when there was a finger touch + * on trackpad device, and the firmware output queue + * won't be empty (always with touch report data), so + * the interrupt signal won't be asserted again until + * the output queue was previous emptied. + * This issue would happen in the scenario that + * user always has his/her fingers touched on the + * trackpad device during system booting/rebooting. */ length = 0; - if (gen5_pip->resp_len) - length = *gen5_pip->resp_len; + if (pip->resp_len) + length = *pip->resp_len; cyapa_empty_pip_output_data(cyapa, - gen5_pip->resp_data, + pip->resp_data, &length, - gen5_pip->resp_sort_func); - if (gen5_pip->resp_len && length != 0) { - *gen5_pip->resp_len = length; - atomic_dec(&gen5_pip->cmd_issued); - complete(&gen5_pip->cmd_ready); + pip->resp_sort_func); + if (pip->resp_len && length != 0) { + *pip->resp_len = length; + atomic_dec(&pip->cmd_issued); + complete(&pip->cmd_ready); } return false; } - if (gen5_pip->resp_data && gen5_pip->resp_len) { - *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ? - *gen5_pip->resp_len : length; - memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf, - *gen5_pip->resp_len); + if (pip->resp_data && pip->resp_len) { + *pip->resp_len = (*pip->resp_len < length) ? + *pip->resp_len : length; + memcpy(pip->resp_data, pip->irq_cmd_buf, + *pip->resp_len); } - atomic_dec(&gen5_pip->cmd_issued); - complete(&gen5_pip->cmd_ready); + atomic_dec(&pip->cmd_issued); + complete(&pip->cmd_ready); return false; } return true; } -static void cyapa_gen5_report_buttons(struct cyapa *cyapa, - const struct cyapa_gen5_report_data *report_data) +static void cyapa_pip_report_buttons(struct cyapa *cyapa, + const struct cyapa_pip_report_data *report_data) { struct input_dev *input = cyapa->input; - u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET]; + u8 buttons = report_data->report_head[PIP_BUTTONS_OFFSET]; buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK; @@ -2605,12 +2544,12 @@ static void cyapa_gen5_report_buttons(struct cyapa *cyapa, input_sync(input); } -static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, - const struct cyapa_gen5_touch_record *touch) +static void cyapa_pip_report_slot_data(struct cyapa *cyapa, + const struct cyapa_pip_touch_record *touch) { struct input_dev *input = cyapa->input; - u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id); - int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id); + u8 event_id = PIP_GET_EVENT_ID(touch->touch_tip_event_id); + int slot = PIP_GET_TOUCH_ID(touch->touch_tip_event_id); int x, y; if (event_id == RECORD_EVENT_LIFTOFF) @@ -2621,10 +2560,10 @@ static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, x = (touch->x_hi << 8) | touch->x_lo; if (cyapa->x_origin) x = cyapa->max_abs_x - x; - input_report_abs(input, ABS_MT_POSITION_X, x); y = (touch->y_hi << 8) | touch->y_lo; if (cyapa->y_origin) y = cyapa->max_abs_y - y; + input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); input_report_abs(input, ABS_MT_PRESSURE, touch->z); @@ -2642,50 +2581,49 @@ static void cyapa_gen5_report_slot_data(struct cyapa *cyapa, touch->orientation); } -static void cyapa_gen5_report_touches(struct cyapa *cyapa, - const struct cyapa_gen5_report_data *report_data) +static void cyapa_pip_report_touches(struct cyapa *cyapa, + const struct cyapa_pip_report_data *report_data) { struct input_dev *input = cyapa->input; unsigned int touch_num; int i; - touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] & - GEN5_NUMBER_OF_TOUCH_MASK; + touch_num = report_data->report_head[PIP_NUMBER_OF_TOUCH_OFFSET] & + PIP_NUMBER_OF_TOUCH_MASK; for (i = 0; i < touch_num; i++) - cyapa_gen5_report_slot_data(cyapa, + cyapa_pip_report_slot_data(cyapa, &report_data->touch_records[i]); input_mt_sync_frame(input); input_sync(input); } -static int cyapa_gen5_irq_handler(struct cyapa *cyapa) +int cyapa_pip_irq_handler(struct cyapa *cyapa) { struct device *dev = &cyapa->client->dev; - struct cyapa_gen5_report_data report_data; - int ret; - u8 report_id; + struct cyapa_pip_report_data report_data; unsigned int report_len; + u8 report_id; + int ret; - if (cyapa->gen != CYAPA_GEN5 || - cyapa->state != CYAPA_STATE_GEN5_APP) { + if (!cyapa_is_pip_app_mode(cyapa)) { dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n", cyapa->gen, cyapa->state); return -EINVAL; } ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, - GEN5_RESP_LENGTH_SIZE); - if (ret != GEN5_RESP_LENGTH_SIZE) { + PIP_RESP_LENGTH_SIZE); + if (ret != PIP_RESP_LENGTH_SIZE) { dev_err(dev, "failed to read length bytes, (%d)\n", ret); return -EINVAL; } report_len = get_unaligned_le16( - &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]); - if (report_len < GEN5_RESP_LENGTH_SIZE) { - /* Invliad length or internal reset happened. */ + &report_data.report_head[PIP_RESP_LENGTH_OFFSET]); + if (report_len < PIP_RESP_LENGTH_SIZE) { + /* Invalid length or internal reset happened. */ dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n", report_len, report_data.report_head[0], report_data.report_head[1]); @@ -2693,7 +2631,7 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa) } /* Idle, no data for report. */ - if (report_len == GEN5_RESP_LENGTH_SIZE) + if (report_len == PIP_RESP_LENGTH_SIZE) return 0; ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len); @@ -2703,70 +2641,71 @@ static int cyapa_gen5_irq_handler(struct cyapa *cyapa) return -EINVAL; } - report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET]; - if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID && - report_len == GEN5_WAKEUP_EVENT_SIZE) { + report_id = report_data.report_head[PIP_RESP_REPORT_ID_OFFSET]; + if (report_id == PIP_WAKEUP_EVENT_REPORT_ID && + report_len == PIP_WAKEUP_EVENT_SIZE) { /* * Device wake event from deep sleep mode for touch. * This interrupt event is used to wake system up. */ return 0; - } else if (report_id != GEN5_TOUCH_REPORT_ID && - report_id != GEN5_BTN_REPORT_ID && + } else if (report_id != PIP_TOUCH_REPORT_ID && + report_id != PIP_BTN_REPORT_ID && report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && - report_id != GEN5_PUSH_BTN_REPORT_ID) { + report_id != PIP_PUSH_BTN_REPORT_ID) { /* Running in BL mode or unknown response data read. */ dev_err(dev, "invalid report_id=0x%02x\n", report_id); return -EINVAL; } - if (report_id == GEN5_TOUCH_REPORT_ID && - (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE || - report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) { + if (report_id == PIP_TOUCH_REPORT_ID && + (report_len < PIP_TOUCH_REPORT_HEAD_SIZE || + report_len > PIP_TOUCH_REPORT_MAX_SIZE)) { /* Invalid report data length for finger packet. */ dev_err(dev, "invalid touch packet length=%d\n", report_len); return 0; } - if ((report_id == GEN5_BTN_REPORT_ID || + if ((report_id == PIP_BTN_REPORT_ID || report_id == GEN5_OLD_PUSH_BTN_REPORT_ID || - report_id == GEN5_PUSH_BTN_REPORT_ID) && - (report_len < GEN5_BTN_REPORT_HEAD_SIZE || - report_len > GEN5_BTN_REPORT_MAX_SIZE)) { + report_id == PIP_PUSH_BTN_REPORT_ID) && + (report_len < PIP_BTN_REPORT_HEAD_SIZE || + report_len > PIP_BTN_REPORT_MAX_SIZE)) { /* Invalid report data length of button packet. */ dev_err(dev, "invalid button packet length=%d\n", report_len); return 0; } - if (report_id == GEN5_TOUCH_REPORT_ID) - cyapa_gen5_report_touches(cyapa, &report_data); + if (report_id == PIP_TOUCH_REPORT_ID) + cyapa_pip_report_touches(cyapa, &report_data); else - cyapa_gen5_report_buttons(cyapa, &report_data); + cyapa_pip_report_buttons(cyapa, &report_data); return 0; } -static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; } -static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; } +int cyapa_pip_bl_activate(struct cyapa *cyapa) { return 0; } +int cyapa_pip_bl_deactivate(struct cyapa *cyapa) { return 0; } + const struct cyapa_dev_ops cyapa_gen5_ops = { - .check_fw = cyapa_gen5_check_fw, - .bl_enter = cyapa_gen5_bl_enter, - .bl_initiate = cyapa_gen5_bl_initiate, - .update_fw = cyapa_gen5_do_fw_update, - .bl_activate = cyapa_gen5_bl_activate, - .bl_deactivate = cyapa_gen5_bl_deactivate, + .check_fw = cyapa_pip_check_fw, + .bl_enter = cyapa_pip_bl_enter, + .bl_initiate = cyapa_pip_bl_initiate, + .update_fw = cyapa_pip_do_fw_update, + .bl_activate = cyapa_pip_bl_activate, + .bl_deactivate = cyapa_pip_bl_deactivate, .show_baseline = cyapa_gen5_show_baseline, - .calibrate_store = cyapa_gen5_do_calibrate, + .calibrate_store = cyapa_pip_do_calibrate, - .initialize = cyapa_gen5_initialize, + .initialize = cyapa_pip_cmd_state_initialize, .state_parse = cyapa_gen5_state_parse, .operational_check = cyapa_gen5_do_operational_check, - .irq_handler = cyapa_gen5_irq_handler, - .irq_cmd_handler = cyapa_gen5_irq_cmd_handler, + .irq_handler = cyapa_pip_irq_handler, + .irq_cmd_handler = cyapa_pip_irq_cmd_handler, .sort_empty_output_data = cyapa_empty_pip_output_data, .set_power_mode = cyapa_gen5_set_power_mode, }; -- GitLab From c2c06c41f700b544c9331caf71c67edb5d131257 Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 16:53:30 -0700 Subject: [PATCH 1630/7006] Input: cyapa - add gen6 device module support Based on the cyapa core, add support for basic functionality of the gen6 trackpad devices. The driver can automatically determine what protocol (gen3, gen5, or gen6) should be used with the attached trackpad device. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/Makefile | 2 +- drivers/input/mouse/cyapa.c | 22 + drivers/input/mouse/cyapa.h | 15 + drivers/input/mouse/cyapa_gen5.c | 69 ++- drivers/input/mouse/cyapa_gen6.c | 730 +++++++++++++++++++++++++++++++ 5 files changed, 834 insertions(+), 4 deletions(-) create mode 100644 drivers/input/mouse/cyapa_gen6.c diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile index 793300bfbddda..ee6a6e9563d48 100644 --- a/drivers/input/mouse/Makefile +++ b/drivers/input/mouse/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o -cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o +cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o psmouse-objs := psmouse-base.o synaptics.o focaltech.o psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 4c4429598adbb..6952ed1c92c7b 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -41,6 +41,9 @@ static int cyapa_reinitialize(struct cyapa *cyapa); bool cyapa_is_pip_bl_mode(struct cyapa *cyapa) { + if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_BL) + return true; + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL) return true; @@ -49,6 +52,9 @@ bool cyapa_is_pip_bl_mode(struct cyapa *cyapa) bool cyapa_is_pip_app_mode(struct cyapa *cyapa) { + if (cyapa->gen == CYAPA_GEN6 && cyapa->state == CYAPA_STATE_GEN6_APP) + return true; + if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP) return true; @@ -204,6 +210,15 @@ static int cyapa_get_state(struct cyapa *cyapa) if (!error) goto out_detected; } + if (cyapa->gen == CYAPA_GEN_UNKNOWN || + cyapa->gen == CYAPA_GEN6 || + cyapa->gen == CYAPA_GEN5) { + error = cyapa_pip_state_parse(cyapa, + status, BL_STATUS_SIZE); + if (!error) + goto out_detected; + } + /* For old Gen5 trackpads detecting. */ if ((cyapa->gen == CYAPA_GEN_UNKNOWN || cyapa->gen == CYAPA_GEN5) && !smbus && even_addr) { @@ -300,6 +315,9 @@ static int cyapa_check_is_operational(struct cyapa *cyapa) return error; switch (cyapa->gen) { + case CYAPA_GEN6: + cyapa->ops = &cyapa_gen6_ops; + break; case CYAPA_GEN5: cyapa->ops = &cyapa_gen5_ops; break; @@ -579,6 +597,8 @@ static int cyapa_initialize(struct cyapa *cyapa) error = cyapa_gen3_ops.initialize(cyapa); if (!error) error = cyapa_gen5_ops.initialize(cyapa); + if (!error) + error = cyapa_gen6_ops.initialize(cyapa); if (error) return error; @@ -1136,9 +1156,11 @@ static char *cyapa_state_to_string(struct cyapa *cyapa) case CYAPA_STATE_BL_ACTIVE: return "bootloader active"; case CYAPA_STATE_GEN5_BL: + case CYAPA_STATE_GEN6_BL: return "bootloader"; case CYAPA_STATE_OP: case CYAPA_STATE_GEN5_APP: + case CYAPA_STATE_GEN6_APP: return "operational"; /* Normal valid state. */ default: return "invalid mode"; diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index d019d1d2d1e41..3a211c0769e9c 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -19,6 +19,7 @@ #define CYAPA_GEN_UNKNOWN 0x00 /* unknown protocol. */ #define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */ #define CYAPA_GEN5 0x05 /* support TrueTouch GEN5 trackpad device. */ +#define CYAPA_GEN6 0x06 /* support TrueTouch GEN6 trackpad device. */ #define CYAPA_NAME "Cypress APA Trackpad (cyapa)" @@ -198,6 +199,9 @@ #define PIP_BL_APP_INFO_RESP_LENGTH 30 #define PIP_BL_GET_INFO_RESP_LENGTH 19 +#define PIP_BL_PLATFORM_VER_SHIFT 4 +#define PIP_BL_PLATFORM_VER_MASK 0x0f + #define PIP_PRODUCT_FAMILY_MASK 0xf000 #define PIP_PRODUCT_FAMILY_TRACKPAD 0x1000 @@ -299,6 +303,14 @@ enum cyapa_state { CYAPA_STATE_OP, CYAPA_STATE_GEN5_BL, CYAPA_STATE_GEN5_APP, + CYAPA_STATE_GEN6_BL, + CYAPA_STATE_GEN6_APP, +}; + +struct gen6_interval_setting { + u16 active_interval; + u16 lp1_interval; + u16 lp2_interval; }; /* The main device structure */ @@ -320,9 +332,11 @@ struct cyapa { u16 runtime_suspend_sleep_time; u8 dev_pwr_mode; u16 dev_sleep_time; + struct gen6_interval_setting gen6_interval_setting; /* Read from query data region. */ char product_id[16]; + u8 platform_ver; /* Platform version. */ u8 fw_maj_ver; /* Firmware major version. */ u8 fw_min_ver; /* Firmware minor version. */ u8 btn_capability; @@ -411,5 +425,6 @@ extern u8 pip_bl_read_app_info[]; extern const char product_id[]; extern const struct cyapa_dev_ops cyapa_gen3_ops; extern const struct cyapa_dev_ops cyapa_gen5_ops; +extern const struct cyapa_dev_ops cyapa_gen6_ops; #endif diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 9d75c6f9f307d..4e19dce1dd62d 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -133,7 +133,9 @@ struct cyapa_pip_touch_record { * Bit 7 - 3: reserved * Bit 2 - 0: touch type; * 0 : standard finger; - * 1 - 15 : reserved. + * 1 : proximity (Start supported in Gen5 TP). + * 2 : finger hover (defined, but not used yet.) + * 3 - 15 : reserved. */ u8 touch_type; @@ -167,6 +169,9 @@ struct cyapa_pip_touch_record { * The meaning of this value is different when touch_type is different. * For standard finger type: * Touch intensity in counts, pressure value. + * For proximity type (Start supported in Gen5 TP): + * The distance, in surface units, between the contact and + * the surface. **/ u8 z; @@ -218,6 +223,12 @@ struct cyapa_tsg_bin_image_head { u8 fw_major_version; u8 fw_minor_version; u8 fw_revision_control_number[8]; + u8 silicon_id_hi; + u8 silicon_id_lo; + u8 chip_revision; + u8 family_id; + u8 bl_ver_maj; + u8 bl_ver_min; } __packed; struct cyapa_tsg_bin_image_data_record { @@ -1134,6 +1145,39 @@ int cyapa_pip_bl_enter(struct cyapa *cyapa) cyapa->operational = false; if (cyapa->gen == CYAPA_GEN5) cyapa->state = CYAPA_STATE_GEN5_BL; + else if (cyapa->gen == CYAPA_GEN6) + cyapa->state = CYAPA_STATE_GEN6_BL; + return 0; +} + +static int cyapa_pip_fw_head_check(struct cyapa *cyapa, + struct cyapa_tsg_bin_image_head *image_head) +{ + if (image_head->head_size != 0x0C && image_head->head_size != 0x12) + return -EINVAL; + + switch (cyapa->gen) { + case CYAPA_GEN6: + if (image_head->family_id != 0x9B || + image_head->silicon_id_hi != 0x0B) + return -EINVAL; + break; + case CYAPA_GEN5: + /* Gen5 without proximity support. */ + if (cyapa->platform_ver < 2) { + if (image_head->head_size == 0x0C) + break; + return -EINVAL; + } + + if (image_head->family_id != 0x91 || + image_head->silicon_id_hi != 0x02) + return -EINVAL; + break; + default: + return -EINVAL; + } + return 0; } @@ -1150,6 +1194,14 @@ int cyapa_pip_check_fw(struct cyapa *cyapa, const struct firmware *fw) u16 app_integrity_crc; int i; + /* Verify the firmware image not miss-used for Gen5 and Gen6. */ + if (cyapa_pip_fw_head_check(cyapa, + (struct cyapa_tsg_bin_image_head *)fw->data)) { + dev_err(dev, "%s: firmware image not match TP device.\n", + __func__); + return -EINVAL; + } + image_records = cyapa_get_image_record_data_num(fw, &flash_records_count); @@ -2339,6 +2391,9 @@ static int cyapa_gen5_bl_query_data(struct cyapa *cyapa) cyapa->fw_maj_ver = resp_data[22]; cyapa->fw_min_ver = resp_data[23]; + cyapa->platform_ver = (resp_data[26] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + return 0; } @@ -2362,8 +2417,16 @@ static int cyapa_gen5_get_query_data(struct cyapa *cyapa) PIP_PRODUCT_FAMILY_TRACKPAD) return -EINVAL; - cyapa->fw_maj_ver = resp_data[15]; - cyapa->fw_min_ver = resp_data[16]; + cyapa->platform_ver = (resp_data[49] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + if (cyapa->gen == CYAPA_GEN5 && cyapa->platform_ver < 2) { + /* Gen5 firmware that does not support proximity. */ + cyapa->fw_maj_ver = resp_data[15]; + cyapa->fw_min_ver = resp_data[16]; + } else { + cyapa->fw_maj_ver = resp_data[9]; + cyapa->fw_min_ver = resp_data[10]; + } cyapa->electrodes_x = resp_data[52]; cyapa->electrodes_y = resp_data[53]; diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c new file mode 100644 index 0000000000000..8a6aa73b53733 --- /dev/null +++ b/drivers/input/mouse/cyapa_gen6.c @@ -0,0 +1,730 @@ +/* + * Cypress APA trackpad with I2C interface + * + * Author: Dudley Du + * + * Copyright (C) 2015 Cypress Semiconductor, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "cyapa.h" + + +#define GEN6_ENABLE_CMD_IRQ 0x41 +#define GEN6_DISABLE_CMD_IRQ 0x42 +#define GEN6_ENABLE_DEV_IRQ 0x43 +#define GEN6_DISABLE_DEV_IRQ 0x44 + +#define GEN6_POWER_MODE_ACTIVE 0x01 +#define GEN6_POWER_MODE_LP_MODE1 0x02 +#define GEN6_POWER_MODE_LP_MODE2 0x03 +#define GEN6_POWER_MODE_BTN_ONLY 0x04 + +#define GEN6_SET_POWER_MODE_INTERVAL 0x47 +#define GEN6_GET_POWER_MODE_INTERVAL 0x48 + +#define GEN6_MAX_RX_NUM 14 +#define GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC 0x00 +#define GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM 0x12 + + +struct pip_app_cmd_head { + __le16 addr; + __le16 length; + u8 report_id; + u8 resv; /* Reserved, must be 0 */ + u8 cmd_code; /* bit7: resv, set to 0; bit6~0: command code.*/ +} __packed; + +struct pip_app_resp_head { + __le16 length; + u8 report_id; + u8 resv; /* Reserved, must be 0 */ + u8 cmd_code; /* bit7: TGL; bit6~0: command code.*/ + /* + * The value of data_status can be the first byte of data or + * the command status or the unsupported command code depending on the + * requested command code. + */ + u8 data_status; +} __packed; + +struct pip_fixed_info { + u8 silicon_id_high; + u8 silicon_id_low; + u8 family_id; +}; + +static u8 pip_get_bl_info[] = { + 0x04, 0x00, 0x0B, 0x00, 0x40, 0x00, 0x01, 0x38, + 0x00, 0x00, 0x70, 0x9E, 0x17 +}; + +static bool cyapa_sort_pip_hid_descriptor_data(struct cyapa *cyapa, + u8 *buf, int len) +{ + if (len != PIP_HID_DESCRIPTOR_SIZE) + return false; + + if (buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID || + buf[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID) + return true; + + return false; +} + +static int cyapa_get_pip_fixed_info(struct cyapa *cyapa, + struct pip_fixed_info *pip_info, bool is_bootloader) +{ + u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; + int resp_len; + u16 product_family; + int error; + + if (is_bootloader) { + /* Read Bootloader Information to determine Gen5 or Gen6. */ + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_get_bl_info, sizeof(pip_get_bl_info), + resp_data, &resp_len, + 2000, cyapa_sort_tsg_pip_bl_resp_data, + false); + if (error || resp_len < PIP_BL_GET_INFO_RESP_LENGTH) + return error ? error : -EIO; + + pip_info->family_id = resp_data[8]; + pip_info->silicon_id_low = resp_data[10]; + pip_info->silicon_id_high = resp_data[11]; + + return 0; + } + + /* Get App System Information to determine Gen5 or Gen6. */ + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, + resp_data, &resp_len, + 2000, cyapa_pip_sort_system_info_data, false); + if (error || resp_len < PIP_READ_SYS_INFO_RESP_LENGTH) + return error ? error : -EIO; + + product_family = get_unaligned_le16(&resp_data[7]); + if ((product_family & PIP_PRODUCT_FAMILY_MASK) != + PIP_PRODUCT_FAMILY_TRACKPAD) + return -EINVAL; + + pip_info->family_id = resp_data[19]; + pip_info->silicon_id_low = resp_data[21]; + pip_info->silicon_id_high = resp_data[22]; + + return 0; + +} + +int cyapa_pip_state_parse(struct cyapa *cyapa, u8 *reg_data, int len) +{ + u8 cmd[] = { 0x01, 0x00}; + struct pip_fixed_info pip_info; + u8 resp_data[PIP_HID_DESCRIPTOR_SIZE]; + int resp_len; + bool is_bootloader; + int error; + + cyapa->state = CYAPA_STATE_NO_DEVICE; + + /* Try to wake from it deep sleep state if it is. */ + cyapa_pip_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); + + /* Empty the buffer queue to get fresh data with later commands. */ + cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); + + /* + * Read description info from trackpad device to determine running in + * APP mode or Bootloader mode. + */ + resp_len = PIP_HID_DESCRIPTOR_SIZE; + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + cmd, sizeof(cmd), + resp_data, &resp_len, + 300, + cyapa_sort_pip_hid_descriptor_data, + false); + if (error) + return error; + + if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_BL_REPORT_ID) + is_bootloader = true; + else if (resp_data[PIP_RESP_REPORT_ID_OFFSET] == PIP_HID_APP_REPORT_ID) + is_bootloader = false; + else + return -EAGAIN; + + /* Get PIP fixed information to determine Gen5 or Gen6. */ + memset(&pip_info, 0, sizeof(struct pip_fixed_info)); + error = cyapa_get_pip_fixed_info(cyapa, &pip_info, is_bootloader); + if (error) + return error; + + if (pip_info.family_id == 0x9B && pip_info.silicon_id_high == 0x0B) { + cyapa->gen = CYAPA_GEN6; + cyapa->state = is_bootloader ? CYAPA_STATE_GEN6_BL + : CYAPA_STATE_GEN6_APP; + } else if (pip_info.family_id == 0x91 && + pip_info.silicon_id_high == 0x02) { + cyapa->gen = CYAPA_GEN5; + cyapa->state = is_bootloader ? CYAPA_STATE_GEN5_BL + : CYAPA_STATE_GEN5_APP; + } + + return 0; +} + +static int cyapa_gen6_read_sys_info(struct cyapa *cyapa) +{ + u8 resp_data[PIP_READ_SYS_INFO_RESP_LENGTH]; + int resp_len; + u16 product_family; + u8 rotat_align; + int error; + + /* Get App System Information to determine Gen5 or Gen6. */ + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_read_sys_info, PIP_READ_SYS_INFO_CMD_LENGTH, + resp_data, &resp_len, + 2000, cyapa_pip_sort_system_info_data, false); + if (error || resp_len < sizeof(resp_data)) + return error ? error : -EIO; + + product_family = get_unaligned_le16(&resp_data[7]); + if ((product_family & PIP_PRODUCT_FAMILY_MASK) != + PIP_PRODUCT_FAMILY_TRACKPAD) + return -EINVAL; + + cyapa->platform_ver = (resp_data[67] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + cyapa->fw_maj_ver = resp_data[9]; + cyapa->fw_min_ver = resp_data[10]; + + cyapa->electrodes_x = resp_data[33]; + cyapa->electrodes_y = resp_data[34]; + + cyapa->physical_size_x = get_unaligned_le16(&resp_data[35]) / 100; + cyapa->physical_size_y = get_unaligned_le16(&resp_data[37]) / 100; + + cyapa->max_abs_x = get_unaligned_le16(&resp_data[39]); + cyapa->max_abs_y = get_unaligned_le16(&resp_data[41]); + + cyapa->max_z = get_unaligned_le16(&resp_data[43]); + + cyapa->x_origin = resp_data[45] & 0x01; + cyapa->y_origin = resp_data[46] & 0x01; + + cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK; + + memcpy(&cyapa->product_id[0], &resp_data[51], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &resp_data[56], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &resp_data[62], 2); + cyapa->product_id[15] = '\0'; + + rotat_align = resp_data[68]; + if (rotat_align) { + cyapa->electrodes_rx = cyapa->electrodes_y; + cyapa->electrodes_rx = cyapa->electrodes_y; + } else { + cyapa->electrodes_rx = cyapa->electrodes_x; + cyapa->electrodes_rx = cyapa->electrodes_y; + } + cyapa->aligned_electrodes_rx = (cyapa->electrodes_rx + 3) & ~3u; + + if (!cyapa->electrodes_x || !cyapa->electrodes_y || + !cyapa->physical_size_x || !cyapa->physical_size_y || + !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z) + return -EINVAL; + + return 0; +} + +static int cyapa_gen6_bl_read_app_info(struct cyapa *cyapa) +{ + u8 resp_data[PIP_BL_APP_INFO_RESP_LENGTH]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + pip_bl_read_app_info, PIP_BL_READ_APP_INFO_CMD_LENGTH, + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_bl_resp_data, false); + if (error || resp_len < PIP_BL_APP_INFO_RESP_LENGTH || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) + return error ? error : -EIO; + + cyapa->fw_maj_ver = resp_data[8]; + cyapa->fw_min_ver = resp_data[9]; + + cyapa->platform_ver = (resp_data[12] >> PIP_BL_PLATFORM_VER_SHIFT) & + PIP_BL_PLATFORM_VER_MASK; + + memcpy(&cyapa->product_id[0], &resp_data[13], 5); + cyapa->product_id[5] = '-'; + memcpy(&cyapa->product_id[6], &resp_data[18], 6); + cyapa->product_id[12] = '-'; + memcpy(&cyapa->product_id[13], &resp_data[24], 2); + cyapa->product_id[15] = '\0'; + + return 0; + +} + +static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, cmd_code }; + u8 resp_data[6]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, cmd_code) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data) + ) + return error < 0 ? error : -EINVAL; + + return 0; +} + +static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode) +{ + u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode }; + u8 resp_data[6]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x46)) + return error < 0 ? error : -EINVAL; + + /* New power state applied in device not match the set power state. */ + if (resp_data[5] != power_mode) + return -EAGAIN; + + return 0; +} + +static int cyapa_gen6_set_interval_setting(struct cyapa *cyapa, + struct gen6_interval_setting *interval_setting) +{ + struct gen6_set_interval_cmd { + __le16 addr; + __le16 length; + u8 report_id; + u8 rsvd; /* Reserved, must be 0 */ + u8 cmd_code; + __le16 active_interval; + __le16 lp1_interval; + __le16 lp2_interval; + } __packed set_interval_cmd; + u8 resp_data[11]; + int resp_len; + int error; + + memset(&set_interval_cmd, 0, sizeof(set_interval_cmd)); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &set_interval_cmd.addr); + put_unaligned_le16(sizeof(set_interval_cmd) - 2, + &set_interval_cmd.length); + set_interval_cmd.report_id = PIP_APP_CMD_REPORT_ID; + set_interval_cmd.cmd_code = GEN6_SET_POWER_MODE_INTERVAL; + put_unaligned_le16(interval_setting->active_interval, + &set_interval_cmd.active_interval); + put_unaligned_le16(interval_setting->lp1_interval, + &set_interval_cmd.lp1_interval); + put_unaligned_le16(interval_setting->lp2_interval, + &set_interval_cmd.lp2_interval); + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + (u8 *)&set_interval_cmd, sizeof(set_interval_cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || + !VALID_CMD_RESP_HEADER(resp_data, GEN6_SET_POWER_MODE_INTERVAL)) + return error < 0 ? error : -EINVAL; + + /* Get the real set intervals from response. */ + interval_setting->active_interval = get_unaligned_le16(&resp_data[5]); + interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]); + interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]); + + return 0; +} + +static int cyapa_gen6_get_interval_setting(struct cyapa *cyapa, + struct gen6_interval_setting *interval_setting) +{ + u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, + GEN6_GET_POWER_MODE_INTERVAL }; + u8 resp_data[11]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || + !VALID_CMD_RESP_HEADER(resp_data, GEN6_GET_POWER_MODE_INTERVAL)) + return error < 0 ? error : -EINVAL; + + interval_setting->active_interval = get_unaligned_le16(&resp_data[5]); + interval_setting->lp1_interval = get_unaligned_le16(&resp_data[7]); + interval_setting->lp2_interval = get_unaligned_le16(&resp_data[9]); + + return 0; +} + +static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state) +{ + u8 ping[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x00 }; + + if (state == PIP_DEEP_SLEEP_STATE_ON) + /* + * Send ping command to notify device prepare for wake up + * when it's in deep sleep mode. At this time, device will + * response nothing except an I2C NAK. + */ + cyapa_i2c_pip_write(cyapa, ping, sizeof(ping)); + + return cyapa_pip_deep_sleep(cyapa, state); +} + +static int cyapa_gen6_set_power_mode(struct cyapa *cyapa, + u8 power_mode, u16 sleep_time) +{ + struct device *dev = &cyapa->client->dev; + struct gen6_interval_setting *interval_setting = + &cyapa->gen6_interval_setting; + u8 lp_mode; + int error; + + if (cyapa->state != CYAPA_STATE_GEN6_APP) + return 0; + + if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { + /* + * Assume TP in deep sleep mode when driver is loaded, + * avoid driver unload and reload command IO issue caused by TP + * has been set into deep sleep mode when unloading. + */ + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + } + + if (PIP_DEV_UNINIT_SLEEP_TIME(cyapa) && + PIP_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF) + PIP_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME); + + if (PIP_DEV_GET_PWR_STATE(cyapa) == power_mode) { + if (power_mode == PWR_MODE_OFF || + power_mode == PWR_MODE_FULL_ACTIVE || + power_mode == PWR_MODE_BTN_ONLY || + PIP_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) { + /* Has in correct power mode state, early return. */ + return 0; + } + } + + if (power_mode == PWR_MODE_OFF) { + cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); + + error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_OFF); + if (error) { + dev_err(dev, "enter deep sleep fail: %d\n", error); + return error; + } + + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF); + return 0; + } + + /* + * When trackpad in power off mode, it cannot change to other power + * state directly, must be wake up from sleep firstly, then + * continue to do next power sate change. + */ + if (PIP_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) { + error = cyapa_gen6_deep_sleep(cyapa, PIP_DEEP_SLEEP_STATE_ON); + if (error) { + dev_err(dev, "deep sleep wake fail: %d\n", error); + return error; + } + } + + /* + * Disable device assert interrupts for command response to avoid + * disturbing system suspending or hibernating process. + */ + cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); + + if (power_mode == PWR_MODE_FULL_ACTIVE) { + error = cyapa_gen6_change_power_state(cyapa, + GEN6_POWER_MODE_ACTIVE); + if (error) { + dev_err(dev, "change to active fail: %d\n", error); + goto out; + } + + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE); + + /* Sync the interval setting from device. */ + cyapa_gen6_get_interval_setting(cyapa, interval_setting); + + } else if (power_mode == PWR_MODE_BTN_ONLY) { + error = cyapa_gen6_change_power_state(cyapa, + GEN6_POWER_MODE_BTN_ONLY); + if (error) { + dev_err(dev, "fail to button only mode: %d\n", error); + goto out; + } + + PIP_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY); + } else { + /* + * Gen6 internally supports to 2 low power scan interval time, + * so can help to switch power mode quickly. + * such as runtime suspend and system suspend. + */ + if (interval_setting->lp1_interval == sleep_time) { + lp_mode = GEN6_POWER_MODE_LP_MODE1; + } else if (interval_setting->lp2_interval == sleep_time) { + lp_mode = GEN6_POWER_MODE_LP_MODE2; + } else { + if (interval_setting->lp1_interval == 0) { + interval_setting->lp1_interval = sleep_time; + lp_mode = GEN6_POWER_MODE_LP_MODE1; + } else { + interval_setting->lp2_interval = sleep_time; + lp_mode = GEN6_POWER_MODE_LP_MODE2; + } + cyapa_gen6_set_interval_setting(cyapa, + interval_setting); + } + + error = cyapa_gen6_change_power_state(cyapa, lp_mode); + if (error) { + dev_err(dev, "set power state to 0x%02x failed: %d\n", + lp_mode, error); + goto out; + } + + PIP_DEV_SET_SLEEP_TIME(cyapa, sleep_time); + PIP_DEV_SET_PWR_STATE(cyapa, + cyapa_sleep_time_to_pwr_cmd(sleep_time)); + } + +out: + cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ); + return error; +} + +static int cyapa_gen6_initialize(struct cyapa *cyapa) +{ + return 0; +} + +static int cyapa_pip_retrieve_data_structure(struct cyapa *cyapa, + u16 read_offset, u16 read_len, u8 data_id, + u8 *data, int *data_buf_lens) +{ + struct retrieve_data_struct_cmd { + struct pip_app_cmd_head head; + __le16 read_offset; + __le16 read_length; + u8 data_id; + } __packed cmd; + u8 resp_data[GEN6_MAX_RX_NUM + 10]; + int resp_len; + int error; + + memset(&cmd, 0, sizeof(cmd)); + put_unaligned_le16(PIP_OUTPUT_REPORT_ADDR, &cmd.head.addr); + put_unaligned_le16(sizeof(cmd), &cmd.head.length - 2); + cmd.head.report_id = PIP_APP_CMD_REPORT_ID; + cmd.head.cmd_code = PIP_RETRIEVE_DATA_STRUCTURE; + put_unaligned_le16(read_offset, &cmd.read_offset); + put_unaligned_le16(read_len, &cmd.read_length); + cmd.data_id = data_id; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, + (u8 *)&cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, + true); + if (error || !PIP_CMD_COMPLETE_SUCCESS(resp_data) || + resp_data[6] != data_id || + !VALID_CMD_RESP_HEADER(resp_data, PIP_RETRIEVE_DATA_STRUCTURE)) + return (error < 0) ? error : -EAGAIN; + + read_len = get_unaligned_le16(&resp_data[7]); + if (*data_buf_lens < read_len) { + *data_buf_lens = read_len; + return -ENOBUFS; + } + + memcpy(data, &resp_data[10], read_len); + *data_buf_lens = read_len; + return 0; +} + +static ssize_t cyapa_gen6_show_baseline(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct cyapa *cyapa = dev_get_drvdata(dev); + u8 data[GEN6_MAX_RX_NUM]; + int data_len; + int size = 0; + int i; + int error; + int resume_error; + + if (!cyapa_is_pip_app_mode(cyapa)) + return -EBUSY; + + /* 1. Suspend Scanning*/ + error = cyapa_pip_suspend_scanning(cyapa); + if (error) + return error; + + /* 2. IDAC and RX Attenuator Calibration Data (Center Frequency). */ + data_len = sizeof(data); + error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len, + GEN6_RETRIEVE_DATA_ID_RX_ATTENURATOR_IDAC, + data, &data_len); + if (error) + goto resume_scanning; + + size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d ", + data[0], /* RX Attenuator Mutual */ + data[1], /* IDAC Mutual */ + data[2], /* RX Attenuator Self RX */ + data[3], /* IDAC Self RX */ + data[4], /* RX Attenuator Self TX */ + data[5] /* IDAC Self TX */ + ); + + /* 3. Read Attenuator Trim. */ + data_len = sizeof(data); + error = cyapa_pip_retrieve_data_structure(cyapa, 0, data_len, + GEN6_RETRIEVE_DATA_ID_ATTENURATOR_TRIM, + data, &data_len); + if (error) + goto resume_scanning; + + /* set attenuator trim values. */ + for (i = 0; i < data_len; i++) + size += scnprintf(buf + size, PAGE_SIZE - size, "%d ", data[i]); + size += scnprintf(buf + size, PAGE_SIZE - size, "\n"); + +resume_scanning: + /* 4. Resume Scanning*/ + resume_error = cyapa_pip_resume_scanning(cyapa); + if (resume_error || error) { + memset(buf, 0, PAGE_SIZE); + return resume_error ? resume_error : error; + } + + return size; +} + +static int cyapa_gen6_operational_check(struct cyapa *cyapa) +{ + struct device *dev = &cyapa->client->dev; + int error; + + if (cyapa->gen != CYAPA_GEN6) + return -ENODEV; + + switch (cyapa->state) { + case CYAPA_STATE_GEN6_BL: + error = cyapa_pip_bl_exit(cyapa); + if (error) { + /* Try to update trackpad product information. */ + cyapa_gen6_bl_read_app_info(cyapa); + goto out; + } + + cyapa->state = CYAPA_STATE_GEN6_APP; + + case CYAPA_STATE_GEN6_APP: + /* + * If trackpad device in deep sleep mode, + * the app command will fail. + * So always try to reset trackpad device to full active when + * the device state is required. + */ + error = cyapa_gen6_set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0); + if (error) + dev_warn(dev, "%s: failed to set power active mode.\n", + __func__); + + /* Get trackpad product information. */ + error = cyapa_gen6_read_sys_info(cyapa); + if (error) + goto out; + /* Only support product ID starting with CYTRA */ + if (memcmp(cyapa->product_id, product_id, + strlen(product_id)) != 0) { + dev_err(dev, "%s: unknown product ID (%s)\n", + __func__, cyapa->product_id); + error = -EINVAL; + } + break; + default: + error = -EINVAL; + } + +out: + return error; +} + +const struct cyapa_dev_ops cyapa_gen6_ops = { + .check_fw = cyapa_pip_check_fw, + .bl_enter = cyapa_pip_bl_enter, + .bl_initiate = cyapa_pip_bl_initiate, + .update_fw = cyapa_pip_do_fw_update, + .bl_activate = cyapa_pip_bl_activate, + .bl_deactivate = cyapa_pip_bl_deactivate, + + .show_baseline = cyapa_gen6_show_baseline, + .calibrate_store = cyapa_pip_do_calibrate, + + .initialize = cyapa_gen6_initialize, + + .state_parse = cyapa_pip_state_parse, + .operational_check = cyapa_gen6_operational_check, + + .irq_handler = cyapa_pip_irq_handler, + .irq_cmd_handler = cyapa_pip_irq_cmd_handler, + .sort_empty_output_data = cyapa_empty_pip_output_data, + .set_power_mode = cyapa_gen6_set_power_mode, +}; -- GitLab From 945525ee607471630d07c309e036ae4a53abe37f Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 16:57:53 -0700 Subject: [PATCH 1631/7006] Input: cyapa - add proximity support for gen5 and gen6 modules Gen5 and Gen6 trackpad devices are able to detect and report object proximity data/events, add this function support in the cyapa driver through the ABS_DISTANCE event. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 13 ++++++- drivers/input/mouse/cyapa.h | 3 ++ drivers/input/mouse/cyapa_gen3.c | 7 ++++ drivers/input/mouse/cyapa_gen5.c | 61 +++++++++++++++++++++++++++++++- drivers/input/mouse/cyapa_gen6.c | 19 ++++++++++ 5 files changed, 101 insertions(+), 2 deletions(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 6952ed1c92c7b..2541fbb435335 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -477,6 +477,7 @@ static int cyapa_create_input_dev(struct cyapa *cyapa) if (cyapa->gen >= CYAPA_GEN5) { input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0); + input_set_abs_params(input, ABS_DISTANCE, 0, 1, 0, 0); } input_abs_set_res(input, ABS_MT_POSITION_X, @@ -1340,6 +1341,13 @@ static int __maybe_unused cyapa_suspend(struct device *dev) error); } + /* + * Disable proximity interrupt when system idle, want true touch to + * wake the system. + */ + if (cyapa->dev_pwr_mode != PWR_MODE_OFF) + cyapa->ops->set_proximity(cyapa, false); + if (device_may_wakeup(dev)) cyapa->irq_wake = (enable_irq_wake(client->irq) == 0); @@ -1360,7 +1368,10 @@ static int __maybe_unused cyapa_resume(struct device *dev) cyapa->irq_wake = false; } - /* Update device states and runtime PM states. */ + /* + * Update device states and runtime PM states. + * Re-Enable proximity interrupt after enter operational mode. + */ error = cyapa_reinitialize(cyapa); if (error) dev_warn(dev, "failed to reinitialize TP device: %d\n", error); diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index 3a211c0769e9c..f51deb69c3705 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -274,6 +274,8 @@ struct cyapa_dev_ops { u8 *, int *, cb_sort); int (*set_power_mode)(struct cyapa *, u8, u16); + + int (*set_proximity)(struct cyapa *, bool); }; struct cyapa_pip_cmd_states { @@ -415,6 +417,7 @@ int cyapa_pip_bl_deactivate(struct cyapa *cyapa); ssize_t cyapa_pip_do_calibrate(struct device *dev, struct device_attribute *attr, const char *buf, size_t count); +int cyapa_pip_set_proximity(struct cyapa *cyapa, bool enable); bool cyapa_pip_irq_cmd_handler(struct cyapa *cyapa); int cyapa_pip_irq_handler(struct cyapa *cyapa); diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index 3884311410f75..e7bbfee8b5d63 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -999,6 +999,11 @@ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, return ret; } +static int cyapa_gen3_set_proximity(struct cyapa *cyapa, bool enable) +{ + return -EOPNOTSUPP; +} + static int cyapa_gen3_get_query_data(struct cyapa *cyapa) { u8 query_data[QUERY_DATA_SIZE]; @@ -1243,4 +1248,6 @@ const struct cyapa_dev_ops cyapa_gen3_ops = { .irq_cmd_handler = cyapa_gen3_irq_cmd_handler, .sort_empty_output_data = cyapa_gen3_empty_output_data, .set_power_mode = cyapa_gen3_set_power_mode, + + .set_proximity = cyapa_gen3_set_proximity, }; diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index 4e19dce1dd62d..fa135f855f348 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -52,6 +52,11 @@ #define PIP_WAKEUP_EVENT_REPORT_ID 0x04 #define PIP_PUSH_BTN_REPORT_ID 0x06 #define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05 /* Special for old Gen5 TP. */ +#define PIP_PROXIMITY_REPORT_ID 0x07 + +#define PIP_PROXIMITY_REPORT_SIZE 6 +#define PIP_PROXIMITY_DISTANCE_OFFSET 0x05 +#define PIP_PROXIMITY_DISTANCE_MASK 0x01 #define PIP_TOUCH_REPORT_HEAD_SIZE 7 #define PIP_TOUCH_REPORT_MAX_SIZE 127 @@ -78,6 +83,8 @@ #define PIP_SENSING_MODE_MUTUAL_CAP_FINE 0x00 #define PIP_SENSING_MODE_SELF_CAP 0x02 +#define PIP_SET_PROXIMITY 0x49 + /* Macro of Gen5 */ #define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100 #define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe @@ -1517,6 +1524,28 @@ static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa) return 0; } +int cyapa_pip_set_proximity(struct cyapa *cyapa, bool enable) +{ + u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, PIP_SET_PROXIMITY, + (u8)!!enable + }; + u8 resp_data[6]; + int resp_len; + int error; + + resp_len = sizeof(resp_data); + error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd), + resp_data, &resp_len, + 500, cyapa_sort_tsg_pip_app_resp_data, false); + if (error || !VALID_CMD_RESP_HEADER(resp_data, PIP_SET_PROXIMITY) || + !PIP_CMD_COMPLETE_SUCCESS(resp_data)) { + error = (error == -ETIMEDOUT) ? -EOPNOTSUPP : error; + return error < 0 ? error : -EINVAL; + } + + return 0; +} + int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) { u8 cmd[] = { 0x05, 0x00, 0x00, 0x08}; @@ -2491,6 +2520,12 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); + /* By default, the trackpad proximity function is enabled. */ + error = cyapa_pip_set_proximity(cyapa, true); + if (error) + dev_warn(dev, "%s: failed to enable proximity.\n", + __func__); + /* Get trackpad product information. */ error = cyapa_gen5_get_query_data(cyapa); if (error) @@ -2607,6 +2642,17 @@ static void cyapa_pip_report_buttons(struct cyapa *cyapa, input_sync(input); } +static void cyapa_pip_report_proximity(struct cyapa *cyapa, + const struct cyapa_pip_report_data *report_data) +{ + struct input_dev *input = cyapa->input; + u8 distance = report_data->report_head[PIP_PROXIMITY_DISTANCE_OFFSET] & + PIP_PROXIMITY_DISTANCE_MASK; + + input_report_abs(input, ABS_DISTANCE, distance); + input_sync(input); +} + static void cyapa_pip_report_slot_data(struct cyapa *cyapa, const struct cyapa_pip_touch_record *touch) { @@ -2628,6 +2674,7 @@ static void cyapa_pip_report_slot_data(struct cyapa *cyapa, y = cyapa->max_abs_y - y; input_report_abs(input, ABS_MT_POSITION_X, x); input_report_abs(input, ABS_MT_POSITION_Y, y); + input_report_abs(input, ABS_DISTANCE, 0); input_report_abs(input, ABS_MT_PRESSURE, touch->z); input_report_abs(input, ABS_MT_TOUCH_MAJOR, @@ -2715,7 +2762,8 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) } else if (report_id != PIP_TOUCH_REPORT_ID && report_id != PIP_BTN_REPORT_ID && report_id != GEN5_OLD_PUSH_BTN_REPORT_ID && - report_id != PIP_PUSH_BTN_REPORT_ID) { + report_id != PIP_PUSH_BTN_REPORT_ID && + report_id != PIP_PROXIMITY_REPORT_ID) { /* Running in BL mode or unknown response data read. */ dev_err(dev, "invalid report_id=0x%02x\n", report_id); return -EINVAL; @@ -2739,8 +2787,17 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) return 0; } + if (report_id == PIP_PROXIMITY_REPORT_ID && + report_len != PIP_PROXIMITY_REPORT_SIZE) { + /* Invalid report data length of proximity packet. */ + dev_err(dev, "invalid proximity data, length=%d\n", report_len); + return 0; + } + if (report_id == PIP_TOUCH_REPORT_ID) cyapa_pip_report_touches(cyapa, &report_data); + else if (report_id == PIP_PROXIMITY_REPORT_ID) + cyapa_pip_report_proximity(cyapa, &report_data); else cyapa_pip_report_buttons(cyapa, &report_data); @@ -2771,4 +2828,6 @@ const struct cyapa_dev_ops cyapa_gen5_ops = { .irq_cmd_handler = cyapa_pip_irq_cmd_handler, .sort_empty_output_data = cyapa_empty_pip_output_data, .set_power_mode = cyapa_gen5_set_power_mode, + + .set_proximity = cyapa_pip_set_proximity, }; diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c index 8a6aa73b53733..61f04132eb65f 100644 --- a/drivers/input/mouse/cyapa_gen6.c +++ b/drivers/input/mouse/cyapa_gen6.c @@ -310,6 +310,17 @@ static int cyapa_gen6_config_dev_irq(struct cyapa *cyapa, u8 cmd_code) return 0; } +static int cyapa_gen6_set_proximity(struct cyapa *cyapa, bool enable) +{ + int error; + + cyapa_gen6_config_dev_irq(cyapa, GEN6_DISABLE_CMD_IRQ); + error = cyapa_pip_set_proximity(cyapa, enable); + cyapa_gen6_config_dev_irq(cyapa, GEN6_ENABLE_CMD_IRQ); + + return error; +} + static int cyapa_gen6_change_power_state(struct cyapa *cyapa, u8 power_mode) { u8 cmd[] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x46, power_mode }; @@ -687,6 +698,12 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); + /* By default, the trackpad proximity function is enabled. */ + error = cyapa_pip_set_proximity(cyapa, true); + if (error) + dev_warn(dev, "%s: failed to enable proximity.\n", + __func__); + /* Get trackpad product information. */ error = cyapa_gen6_read_sys_info(cyapa); if (error) @@ -727,4 +744,6 @@ const struct cyapa_dev_ops cyapa_gen6_ops = { .irq_cmd_handler = cyapa_pip_irq_cmd_handler, .sort_empty_output_data = cyapa_empty_pip_output_data, .set_power_mode = cyapa_gen6_set_power_mode, + + .set_proximity = cyapa_gen6_set_proximity, }; -- GitLab From 757cae5a6f0ac1c61ce149a066377a15d1ed881f Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 17:09:59 -0700 Subject: [PATCH 1632/7006] Input: cyapa - fully support runtime suspend power management Fix the the runtime suspend power management not working issue when system starts up and before user touches the trackpad device. TEST=test on Chromebook. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 73 ++++++++++++++++++++++---------- drivers/input/mouse/cyapa.h | 2 +- drivers/input/mouse/cyapa_gen3.c | 4 +- drivers/input/mouse/cyapa_gen5.c | 21 ++++++--- drivers/input/mouse/cyapa_gen6.c | 4 +- 5 files changed, 70 insertions(+), 34 deletions(-) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 2541fbb435335..5c08eeba61621 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -367,6 +367,7 @@ static int cyapa_open(struct input_dev *input) { struct cyapa *cyapa = input_get_drvdata(input); struct i2c_client *client = cyapa->client; + struct device *dev = &client->dev; int error; error = mutex_lock_interruptible(&cyapa->state_sync_lock); @@ -380,10 +381,9 @@ static int cyapa_open(struct input_dev *input) * when in operational mode. */ error = cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) { - dev_warn(&client->dev, - "set active power failed: %d\n", error); + dev_warn(dev, "set active power failed: %d\n", error); goto out; } } else { @@ -395,10 +395,14 @@ static int cyapa_open(struct input_dev *input) } enable_irq(client->irq); - if (!pm_runtime_enabled(&client->dev)) { - pm_runtime_set_active(&client->dev); - pm_runtime_enable(&client->dev); + if (!pm_runtime_enabled(dev)) { + pm_runtime_set_active(dev); + pm_runtime_enable(dev); } + + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); out: mutex_unlock(&cyapa->state_sync_lock); return error; @@ -408,16 +412,17 @@ static void cyapa_close(struct input_dev *input) { struct cyapa *cyapa = input_get_drvdata(input); struct i2c_client *client = cyapa->client; + struct device *dev = &cyapa->client->dev; mutex_lock(&cyapa->state_sync_lock); disable_irq(client->irq); - if (pm_runtime_enabled(&client->dev)) - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); + if (pm_runtime_enabled(dev)) + pm_runtime_disable(dev); + pm_runtime_set_suspended(dev); if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false); mutex_unlock(&cyapa->state_sync_lock); } @@ -527,7 +532,7 @@ static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa) */ if (!input || cyapa->operational) cyapa->ops->set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); /* Gen3 always using polling mode for command. */ if (cyapa->gen >= CYAPA_GEN5) enable_irq(cyapa->client->irq); @@ -542,7 +547,8 @@ static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa) if (cyapa->gen >= CYAPA_GEN5) disable_irq(cyapa->client->irq); if (!input || cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_OFF, 0, false); } } @@ -609,7 +615,7 @@ static int cyapa_initialize(struct cyapa *cyapa) /* Power down the device until we need it. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0, false); return 0; } @@ -625,7 +631,8 @@ static int cyapa_reinitialize(struct cyapa *cyapa) /* Avoid command failures when TP was in OFF state. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0, false); error = cyapa_detect(cyapa); if (error) @@ -644,7 +651,8 @@ out: if (!input || !input->users) { /* Reset to power OFF state to save power when no user open. */ if (cyapa->operational) - cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0); + cyapa->ops->set_power_mode(cyapa, + PWR_MODE_OFF, 0, false); } else if (!error && cyapa->operational) { /* * Make sure only enable runtime PM when device is @@ -652,6 +660,10 @@ out: */ pm_runtime_set_active(dev); pm_runtime_enable(dev); + + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); } return error; @@ -661,8 +673,8 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) { struct cyapa *cyapa = dev_id; struct device *dev = &cyapa->client->dev; + int error; - pm_runtime_get_sync(dev); if (device_may_wakeup(dev)) pm_wakeup_event(dev, 0); @@ -681,7 +693,24 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) goto out; } - if (!cyapa->operational || cyapa->ops->irq_handler(cyapa)) { + if (cyapa->operational) { + error = cyapa->ops->irq_handler(cyapa); + + /* + * Apply runtime power management to touch report event + * except the events caused by the command responses. + * Note: + * It will introduce about 20~40 ms additional delay + * time in receiving for first valid touch report data. + * The time is used to execute device runtime resume + * process. + */ + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); + } + + if (!cyapa->operational || error) { if (!mutex_trylock(&cyapa->state_sync_lock)) { cyapa->ops->sort_empty_output_data(cyapa, NULL, NULL, NULL); @@ -693,8 +722,6 @@ static irqreturn_t cyapa_irq(int irq, void *dev_id) } out: - pm_runtime_mark_last_busy(dev); - pm_runtime_put_sync_autosuspend(dev); return IRQ_HANDLED; } @@ -1335,7 +1362,7 @@ static int __maybe_unused cyapa_suspend(struct device *dev) power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode : PWR_MODE_OFF; error = cyapa->ops->set_power_mode(cyapa, power_mode, - cyapa->suspend_sleep_time); + cyapa->suspend_sleep_time, true); if (error) dev_err(dev, "suspend set power mode failed: %d\n", error); @@ -1389,7 +1416,8 @@ static int __maybe_unused cyapa_runtime_suspend(struct device *dev) error = cyapa->ops->set_power_mode(cyapa, cyapa->runtime_suspend_power_mode, - cyapa->runtime_suspend_sleep_time); + cyapa->runtime_suspend_sleep_time, + false); if (error) dev_warn(dev, "runtime suspend failed: %d\n", error); @@ -1401,7 +1429,8 @@ static int __maybe_unused cyapa_runtime_resume(struct device *dev) struct cyapa *cyapa = dev_get_drvdata(dev); int error; - error = cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0); + error = cyapa->ops->set_power_mode(cyapa, + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_warn(dev, "runtime resume failed: %d\n", error); diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h index f51deb69c3705..af12536405901 100644 --- a/drivers/input/mouse/cyapa.h +++ b/drivers/input/mouse/cyapa.h @@ -273,7 +273,7 @@ struct cyapa_dev_ops { int (*sort_empty_output_data)(struct cyapa *, u8 *, int *, cb_sort); - int (*set_power_mode)(struct cyapa *, u8, u16); + int (*set_power_mode)(struct cyapa *, u8, u16, bool); int (*set_proximity)(struct cyapa *, bool); }; diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c index e7bbfee8b5d63..1a9d12ae75384 100644 --- a/drivers/input/mouse/cyapa_gen3.c +++ b/drivers/input/mouse/cyapa_gen3.c @@ -950,7 +950,7 @@ static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode) * Device power mode can only be set when device is in operational mode. */ static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode, - u16 always_unused) + u16 always_unused, bool is_suspend_unused) { int ret; u8 power; @@ -1112,7 +1112,7 @@ static int cyapa_gen3_do_operational_check(struct cyapa *cyapa) * may cause problems, so we set the power mode first here. */ error = cyapa_gen3_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_err(dev, "%s: set full power mode failed: %d\n", __func__, error); diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c index fa135f855f348..6d7abbed67e44 100644 --- a/drivers/input/mouse/cyapa_gen5.c +++ b/drivers/input/mouse/cyapa_gen5.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "cyapa.h" @@ -1565,7 +1566,7 @@ int cyapa_pip_deep_sleep(struct cyapa *cyapa, u8 state) } static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, - u8 power_mode, u16 sleep_time) + u8 power_mode, u16 sleep_time, bool is_suspend) { struct device *dev = &cyapa->client->dev; u8 power_state; @@ -1574,9 +1575,6 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, if (cyapa->state != CYAPA_STATE_GEN5_APP) return 0; - /* Dump all the report data before do power mode commmands. */ - cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - if (PIP_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) { /* * Assume TP in deep sleep mode when driver is loaded, @@ -1679,8 +1677,8 @@ static int cyapa_gen5_set_power_mode(struct cyapa *cyapa, * is suspending which may cause interrupt line unable to be * asserted again. */ - cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL); - cyapa_gen5_disable_pip_report(cyapa); + if (is_suspend) + cyapa_gen5_disable_pip_report(cyapa); PIP_DEV_SET_PWR_STATE(cyapa, cyapa_sleep_time_to_pwr_cmd(sleep_time)); @@ -2515,7 +2513,7 @@ static int cyapa_gen5_do_operational_check(struct cyapa *cyapa) * the device state is required. */ error = cyapa_gen5_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); @@ -2757,7 +2755,16 @@ int cyapa_pip_irq_handler(struct cyapa *cyapa) /* * Device wake event from deep sleep mode for touch. * This interrupt event is used to wake system up. + * + * Note: + * It will introduce about 20~40 ms additional delay + * time in receiving for first valid touch report data. + * The time is used to execute device runtime resume + * process. */ + pm_runtime_get_sync(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync_autosuspend(dev); return 0; } else if (report_id != PIP_TOUCH_REPORT_ID && report_id != PIP_BTN_REPORT_ID && diff --git a/drivers/input/mouse/cyapa_gen6.c b/drivers/input/mouse/cyapa_gen6.c index 61f04132eb65f..5f191071d44a0 100644 --- a/drivers/input/mouse/cyapa_gen6.c +++ b/drivers/input/mouse/cyapa_gen6.c @@ -429,7 +429,7 @@ static int cyapa_gen6_deep_sleep(struct cyapa *cyapa, u8 state) } static int cyapa_gen6_set_power_mode(struct cyapa *cyapa, - u8 power_mode, u16 sleep_time) + u8 power_mode, u16 sleep_time, bool is_suspend) { struct device *dev = &cyapa->client->dev; struct gen6_interval_setting *interval_setting = @@ -693,7 +693,7 @@ static int cyapa_gen6_operational_check(struct cyapa *cyapa) * the device state is required. */ error = cyapa_gen6_set_power_mode(cyapa, - PWR_MODE_FULL_ACTIVE, 0); + PWR_MODE_FULL_ACTIVE, 0, false); if (error) dev_warn(dev, "%s: failed to set power active mode.\n", __func__); -- GitLab From ce2ae9e3e6a152866a33972c966f8315aab2cb1d Mon Sep 17 00:00:00 2001 From: Dudley Du Date: Mon, 20 Jul 2015 17:15:46 -0700 Subject: [PATCH 1633/7006] Input: cyapa - add ACPI HID CYAP0002 for Gen6 devices Add CYTP0002 to the list of ACPI HIDs recognized by the driver. Signed-off-by: Dudley Du Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/cyapa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c index 5c08eeba61621..6195ccb3cfdee 100644 --- a/drivers/input/mouse/cyapa.c +++ b/drivers/input/mouse/cyapa.c @@ -1452,6 +1452,7 @@ MODULE_DEVICE_TABLE(i2c, cyapa_id_table); static const struct acpi_device_id cyapa_acpi_id[] = { { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */ { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */ + { "CYAP0002", 0 }, /* Gen6 trackpad with 0x24 I2C address. */ { } }; MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id); -- GitLab From e75ed3c47a2082fad87dd6d726ff7275d35e197c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 6 Jul 2015 10:32:27 -0700 Subject: [PATCH 1634/7006] Input: arizona-haptic - convert to use managed input devices Using managed input device (via devm_input_allocate_device) simplifies error handling and driver removal paths and also silences CID# 712569. Reviewed-by: Joshua Clayton Signed-off-by: Dmitry Torokhov --- drivers/input/misc/arizona-haptics.c | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 4dbbed74c9e47..4bf678541496e 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -170,8 +170,8 @@ static int arizona_haptics_probe(struct platform_device *pdev) INIT_WORK(&haptics->work, arizona_haptics_work); - haptics->input_dev = input_allocate_device(); - if (haptics->input_dev == NULL) { + haptics->input_dev = devm_input_allocate_device(&pdev->dev); + if (!haptics->input_dev) { dev_err(arizona->dev, "Failed to allocate input device\n"); return -ENOMEM; } @@ -188,41 +188,23 @@ static int arizona_haptics_probe(struct platform_device *pdev) if (ret < 0) { dev_err(arizona->dev, "input_ff_create_memless() failed: %d\n", ret); - goto err_ialloc; + return ret; } ret = input_register_device(haptics->input_dev); if (ret < 0) { dev_err(arizona->dev, "couldn't register input device: %d\n", ret); - goto err_iff; + return ret; } platform_set_drvdata(pdev, haptics); - return 0; - -err_iff: - if (haptics->input_dev) - input_ff_destroy(haptics->input_dev); -err_ialloc: - input_free_device(haptics->input_dev); - - return ret; -} - -static int arizona_haptics_remove(struct platform_device *pdev) -{ - struct arizona_haptics *haptics = platform_get_drvdata(pdev); - - input_unregister_device(haptics->input_dev); - return 0; } static struct platform_driver arizona_haptics_driver = { .probe = arizona_haptics_probe, - .remove = arizona_haptics_remove, .driver = { .name = "arizona-haptics", }, -- GitLab From ac4c90c82e4d38cee613f68d2fabd714338ecca7 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Wed, 1 Jul 2015 15:10:38 +0200 Subject: [PATCH 1635/7006] cpufreq: exynos: remove exynos5250 specific cpufreq driver support Exynos5250 based platforms have switched over to use generic cpufreq driver for cpufreq functionality. So the Exynos specific cpufreq support for these platforms can be removed. Cc: Thomas Abraham Signed-off-by: Bartlomiej Zolnierkiewicz Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Viresh Kumar [k.kozlowski: Rebased the patch around exynos-cpufreq.c] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Kukjin Kim --- drivers/cpufreq/Kconfig.arm | 11 -- drivers/cpufreq/Makefile | 1 - drivers/cpufreq/exynos-cpufreq.c | 3 - drivers/cpufreq/exynos-cpufreq.h | 17 --- drivers/cpufreq/exynos5250-cpufreq.c | 210 --------------------------- 5 files changed, 242 deletions(-) delete mode 100644 drivers/cpufreq/exynos5250-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index cc8a71c267b88..7a4c1820de8c5 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -47,17 +47,6 @@ config ARM_EXYNOS4X12_CPUFREQ If in doubt, say N. -config ARM_EXYNOS5250_CPUFREQ - bool "SAMSUNG EXYNOS5250" - depends on SOC_EXYNOS5250 - depends on ARM_EXYNOS_CPUFREQ - default y - help - This adds the CPUFreq driver for Samsung EXYNOS5250 - SoC. - - If in doubt, say N. - config ARM_EXYNOS_CPU_FREQ_BOOST_SW bool "EXYNOS Frequency Overclocking - Software" depends on ARM_EXYNOS_CPUFREQ && THERMAL diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 2169bf792db76..06286bbace215 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -55,7 +55,6 @@ obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += arm-exynos-cpufreq.o arm-exynos-cpufreq-y := exynos-cpufreq.o arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o -arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index ae5b2bd3a9785..71d8891612186 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c @@ -175,9 +175,6 @@ static int exynos_cpufreq_probe(struct platform_device *pdev) } else if (of_machine_is_compatible("samsung,exynos4412")) { exynos_info->type = EXYNOS_SOC_4412; ret = exynos4x12_cpufreq_init(exynos_info); - } else if (of_machine_is_compatible("samsung,exynos5250")) { - exynos_info->type = EXYNOS_SOC_5250; - ret = exynos5250_cpufreq_init(exynos_info); } else { pr_err("%s: Unknown SoC type\n", __func__); return -ENODEV; diff --git a/drivers/cpufreq/exynos-cpufreq.h b/drivers/cpufreq/exynos-cpufreq.h index a3855e4d913d6..a359db792ac8b 100644 --- a/drivers/cpufreq/exynos-cpufreq.h +++ b/drivers/cpufreq/exynos-cpufreq.h @@ -20,7 +20,6 @@ enum cpufreq_level_index { enum exynos_soc_type { EXYNOS_SOC_4212, EXYNOS_SOC_4412, - EXYNOS_SOC_5250, }; #define APLL_FREQ(f, a0, a1, a2, a3, a4, a5, a6, a7, b0, b1, b2, m, p, s) \ @@ -60,14 +59,6 @@ static inline int exynos4x12_cpufreq_init(struct exynos_dvfs_info *info) return -EOPNOTSUPP; } #endif -#ifdef CONFIG_ARM_EXYNOS5250_CPUFREQ -extern int exynos5250_cpufreq_init(struct exynos_dvfs_info *); -#else -static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) -{ - return -EOPNOTSUPP; -} -#endif #define EXYNOS4_CLKSRC_CPU 0x14200 #define EXYNOS4_CLKMUX_STATCPU 0x14400 @@ -79,11 +70,3 @@ static inline int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) #define EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT (16) #define EXYNOS4_CLKMUX_STATCPU_MUXCORE_MASK (0x7 << EXYNOS4_CLKSRC_CPU_MUXCORE_SHIFT) - -#define EXYNOS5_APLL_LOCK 0x00000 -#define EXYNOS5_APLL_CON0 0x00100 -#define EXYNOS5_CLKMUX_STATCPU 0x00400 -#define EXYNOS5_CLKDIV_CPU0 0x00500 -#define EXYNOS5_CLKDIV_CPU1 0x00504 -#define EXYNOS5_CLKDIV_STATCPU0 0x00600 -#define EXYNOS5_CLKDIV_STATCPU1 0x00604 diff --git a/drivers/cpufreq/exynos5250-cpufreq.c b/drivers/cpufreq/exynos5250-cpufreq.c deleted file mode 100644 index 3eafdc7ba7877..0000000000000 --- a/drivers/cpufreq/exynos5250-cpufreq.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2010-20122Samsung Electronics Co., Ltd. - * http://www.samsung.com - * - * EXYNOS5250 - CPU frequency scaling support - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "exynos-cpufreq.h" - -static struct clk *cpu_clk; -static struct clk *moutcore; -static struct clk *mout_mpll; -static struct clk *mout_apll; -static struct exynos_dvfs_info *cpufreq; - -static unsigned int exynos5250_volt_table[] = { - 1300000, 1250000, 1225000, 1200000, 1150000, - 1125000, 1100000, 1075000, 1050000, 1025000, - 1012500, 1000000, 975000, 950000, 937500, - 925000 -}; - -static struct cpufreq_frequency_table exynos5250_freq_table[] = { - {0, L0, 1700 * 1000}, - {0, L1, 1600 * 1000}, - {0, L2, 1500 * 1000}, - {0, L3, 1400 * 1000}, - {0, L4, 1300 * 1000}, - {0, L5, 1200 * 1000}, - {0, L6, 1100 * 1000}, - {0, L7, 1000 * 1000}, - {0, L8, 900 * 1000}, - {0, L9, 800 * 1000}, - {0, L10, 700 * 1000}, - {0, L11, 600 * 1000}, - {0, L12, 500 * 1000}, - {0, L13, 400 * 1000}, - {0, L14, 300 * 1000}, - {0, L15, 200 * 1000}, - {0, 0, CPUFREQ_TABLE_END}, -}; - -static struct apll_freq apll_freq_5250[] = { - /* - * values: - * freq - * clock divider for ARM, CPUD, ACP, PERIPH, ATB, PCLK_DBG, APLL, ARM2 - * clock divider for COPY, HPM, RESERVED - * PLL M, P, S - */ - APLL_FREQ(1700, 0, 3, 7, 7, 7, 3, 5, 0, 0, 2, 0, 425, 6, 0), - APLL_FREQ(1600, 0, 3, 7, 7, 7, 1, 4, 0, 0, 2, 0, 200, 3, 0), - APLL_FREQ(1500, 0, 2, 7, 7, 7, 1, 4, 0, 0, 2, 0, 250, 4, 0), - APLL_FREQ(1400, 0, 2, 7, 7, 6, 1, 4, 0, 0, 2, 0, 175, 3, 0), - APLL_FREQ(1300, 0, 2, 7, 7, 6, 1, 3, 0, 0, 2, 0, 325, 6, 0), - APLL_FREQ(1200, 0, 2, 7, 7, 5, 1, 3, 0, 0, 2, 0, 200, 4, 0), - APLL_FREQ(1100, 0, 3, 7, 7, 5, 1, 3, 0, 0, 2, 0, 275, 6, 0), - APLL_FREQ(1000, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 125, 3, 0), - APLL_FREQ(900, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 150, 4, 0), - APLL_FREQ(800, 0, 1, 7, 7, 4, 1, 2, 0, 0, 2, 0, 100, 3, 0), - APLL_FREQ(700, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 175, 3, 1), - APLL_FREQ(600, 0, 1, 7, 7, 3, 1, 1, 0, 0, 2, 0, 200, 4, 1), - APLL_FREQ(500, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 125, 3, 1), - APLL_FREQ(400, 0, 1, 7, 7, 2, 1, 1, 0, 0, 2, 0, 100, 3, 1), - APLL_FREQ(300, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 200, 4, 2), - APLL_FREQ(200, 0, 1, 7, 7, 1, 1, 1, 0, 0, 2, 0, 100, 3, 2), -}; - -static void set_clkdiv(unsigned int div_index) -{ - unsigned int tmp; - - /* Change Divider - CPU0 */ - - tmp = apll_freq_5250[div_index].clk_div_cpu0; - - __raw_writel(tmp, cpufreq->cmu_regs + EXYNOS5_CLKDIV_CPU0); - - while (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKDIV_STATCPU0) - & 0x11111111) - cpu_relax(); - - /* Change Divider - CPU1 */ - tmp = apll_freq_5250[div_index].clk_div_cpu1; - - __raw_writel(tmp, cpufreq->cmu_regs + EXYNOS5_CLKDIV_CPU1); - - while (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKDIV_STATCPU1) & 0x11) - cpu_relax(); -} - -static void set_apll(unsigned int index) -{ - unsigned int tmp; - unsigned int freq = apll_freq_5250[index].freq; - - /* MUX_CORE_SEL = MPLL, ARMCLK uses MPLL for lock time */ - clk_set_parent(moutcore, mout_mpll); - - do { - cpu_relax(); - tmp = (__raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKMUX_STATCPU) - >> 16); - tmp &= 0x7; - } while (tmp != 0x2); - - clk_set_rate(mout_apll, freq * 1000); - - /* MUX_CORE_SEL = APLL */ - clk_set_parent(moutcore, mout_apll); - - do { - cpu_relax(); - tmp = __raw_readl(cpufreq->cmu_regs + EXYNOS5_CLKMUX_STATCPU); - tmp &= (0x7 << 16); - } while (tmp != (0x1 << 16)); -} - -static void exynos5250_set_frequency(unsigned int old_index, - unsigned int new_index) -{ - if (old_index > new_index) { - set_clkdiv(new_index); - set_apll(new_index); - } else if (old_index < new_index) { - set_apll(new_index); - set_clkdiv(new_index); - } -} - -int exynos5250_cpufreq_init(struct exynos_dvfs_info *info) -{ - struct device_node *np; - unsigned long rate; - - /* - * HACK: This is a temporary workaround to get access to clock - * controller registers directly and remove static mappings and - * dependencies on platform headers. It is necessary to enable - * Exynos multi-platform support and will be removed together with - * this whole driver as soon as Exynos gets migrated to use - * cpufreq-dt driver. - */ - np = of_find_compatible_node(NULL, NULL, "samsung,exynos5250-clock"); - if (!np) { - pr_err("%s: failed to find clock controller DT node\n", - __func__); - return -ENODEV; - } - - info->cmu_regs = of_iomap(np, 0); - if (!info->cmu_regs) { - pr_err("%s: failed to map CMU registers\n", __func__); - return -EFAULT; - } - - cpu_clk = clk_get(NULL, "armclk"); - if (IS_ERR(cpu_clk)) - return PTR_ERR(cpu_clk); - - moutcore = clk_get(NULL, "mout_cpu"); - if (IS_ERR(moutcore)) - goto err_moutcore; - - mout_mpll = clk_get(NULL, "mout_mpll"); - if (IS_ERR(mout_mpll)) - goto err_mout_mpll; - - rate = clk_get_rate(mout_mpll) / 1000; - - mout_apll = clk_get(NULL, "mout_apll"); - if (IS_ERR(mout_apll)) - goto err_mout_apll; - - info->mpll_freq_khz = rate; - /* 800Mhz */ - info->pll_safe_idx = L9; - info->cpu_clk = cpu_clk; - info->volt_table = exynos5250_volt_table; - info->freq_table = exynos5250_freq_table; - info->set_freq = exynos5250_set_frequency; - - cpufreq = info; - - return 0; - -err_mout_apll: - clk_put(mout_mpll); -err_mout_mpll: - clk_put(moutcore); -err_moutcore: - clk_put(cpu_clk); - - pr_err("%s: failed initialization\n", __func__); - return -EINVAL; -} -- GitLab From b7446cacfb433f5e89ff94afecbc349e404aee21 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 18 Jun 2015 11:43:37 +0200 Subject: [PATCH 1636/7006] tcm_loop: Remove SAS vestigies tcm_loop is able to emulate several protocols, so remove last vestigies of the SAS protocol. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index a556bdebd775d..b179d934cee16 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -526,7 +526,7 @@ static inline struct tcm_loop_tpg *tl_tpg(struct se_portal_group *se_tpg) static char *tcm_loop_get_endpoint_wwn(struct se_portal_group *se_tpg) { /* - * Return the passed NAA identifier for the SAS Target Port + * Return the passed NAA identifier for the Target Port */ return &tl_tpg(se_tpg)->tl_hba->tl_wwn_address[0]; } @@ -845,7 +845,7 @@ static int tcm_loop_make_nexus( transport_free_session(tl_nexus->se_sess); goto out; } - /* Now, register the SAS I_T Nexus as active. */ + /* Now, register the I_T Nexus as active. */ transport_register_session(se_tpg, tl_nexus->se_sess->se_node_acl, tl_nexus->se_sess, tl_nexus); tl_tpg->tl_nexus = tl_nexus; @@ -884,7 +884,7 @@ static int tcm_loop_drop_nexus( " %s Initiator Port: %s\n", tcm_loop_dump_proto_id(tpg->tl_hba), tl_nexus->se_sess->se_node_acl->initiatorname); /* - * Release the SCSI I_T Nexus to the emulated SAS Target Port + * Release the SCSI I_T Nexus to the emulated Target Port */ transport_deregister_session(tl_nexus->se_sess); tpg->tl_nexus = NULL; @@ -1077,7 +1077,7 @@ static struct se_portal_group *tcm_loop_make_naa_tpg( tl_tpg->tl_hba = tl_hba; tl_tpg->tl_tpgt = tpgt; /* - * Register the tl_tpg as a emulated SAS TCM Target Endpoint + * Register the tl_tpg as a emulated TCM Target Endpoint */ ret = core_tpg_register(wwn, &tl_tpg->tl_se_tpg, tl_hba->tl_proto_id); if (ret < 0) @@ -1102,11 +1102,11 @@ static void tcm_loop_drop_naa_tpg( tl_hba = tl_tpg->tl_hba; tpgt = tl_tpg->tl_tpgt; /* - * Release the I_T Nexus for the Virtual SAS link if present + * Release the I_T Nexus for the Virtual target link if present */ tcm_loop_drop_nexus(tl_tpg); /* - * Deregister the tl_tpg as a emulated SAS TCM Target Endpoint + * Deregister the tl_tpg as a emulated TCM Target Endpoint */ core_tpg_deregister(se_tpg); @@ -1199,8 +1199,9 @@ static void tcm_loop_drop_scsi_hba( struct tcm_loop_hba, tl_hba_wwn); pr_debug("TCM_Loop_ConfigFS: Deallocating emulated Target" - " SAS Address: %s at Linux/SCSI Host ID: %d\n", - tl_hba->tl_wwn_address, tl_hba->sh->host_no); + " %s Address: %s at Linux/SCSI Host ID: %d\n", + tcm_loop_dump_proto_id(tl_hba), tl_hba->tl_wwn_address, + tl_hba->sh->host_no); /* * Call device_unregister() on the original tl_hba->dev. * tcm_loop_fabric_scsi.c:tcm_loop_release_adapter() will -- GitLab From e986a35aba67558381d5cec59a14c4d0b20f0d47 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 18 Jun 2015 11:43:38 +0200 Subject: [PATCH 1637/7006] tcm_loop: Send I_T_NEXUS_LOSS_OCCURRED UA If the virtual SAS link is set to 'offline' we should be queueing an I_T_NEXUS_LOSS_OCCURRED UA. Signed-off-by: Hannes Reinecke Signed-off-by: Nicholas Bellinger --- drivers/target/loopback/tcm_loop.c | 5 +++++ drivers/target/target_core_tpg.c | 17 +++++++++++++++++ include/target/target_core_fabric.h | 1 + 3 files changed, 23 insertions(+) diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index b179d934cee16..5bc85ffed7204 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c @@ -1034,6 +1034,11 @@ static ssize_t tcm_loop_tpg_store_transport_status( } if (!strncmp(page, "offline", 7)) { tl_tpg->tl_transport_status = TCM_TRANSPORT_OFFLINE; + if (tl_tpg->tl_nexus) { + struct se_session *tl_sess = tl_tpg->tl_nexus->se_sess; + + core_allocate_nexus_loss_ua(tl_sess->se_node_acl); + } return count; } return -EINVAL; diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index babde4ad841f1..2d0381dd105c4 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -41,6 +41,7 @@ #include "target_core_internal.h" #include "target_core_alua.h" #include "target_core_pr.h" +#include "target_core_ua.h" extern struct se_device *g_lun0_dev; @@ -83,6 +84,22 @@ struct se_node_acl *core_tpg_get_initiator_node_acl( } EXPORT_SYMBOL(core_tpg_get_initiator_node_acl); +void core_allocate_nexus_loss_ua( + struct se_node_acl *nacl) +{ + struct se_dev_entry *deve; + + if (!nacl) + return; + + rcu_read_lock(); + hlist_for_each_entry_rcu(deve, &nacl->lun_entry_hlist, link) + core_scsi3_ua_allocate(deve, 0x29, + ASCQ_29H_NEXUS_LOSS_OCCURRED); + rcu_read_unlock(); +} +EXPORT_SYMBOL(core_allocate_nexus_loss_ua); + /* core_tpg_add_node_to_devs(): * * diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 18afef91b447f..69355feabd1d5 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -152,6 +152,7 @@ int transport_generic_handle_tmr(struct se_cmd *); void transport_generic_request_failure(struct se_cmd *, sense_reason_t); void __target_execute_cmd(struct se_cmd *); int transport_lookup_tmr_lun(struct se_cmd *, u64); +void core_allocate_nexus_loss_ua(struct se_node_acl *acl); struct se_node_acl *core_tpg_get_initiator_node_acl(struct se_portal_group *tpg, unsigned char *); -- GitLab From 46d5bd62ef9e3d6e2018963cbb725c91f864922d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 8 Jul 2015 17:58:50 +0300 Subject: [PATCH 1638/7006] target: Inline transport_get_sense_codes() Inline this function in its call site since it performs a trivial task and since it is only called once. Signed-off-by: Bart Van Assche Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index ce8574b7220ce..b6708d1b69b80 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2615,17 +2615,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) } EXPORT_SYMBOL(transport_wait_for_tasks); -static int transport_get_sense_codes( - struct se_cmd *cmd, - u8 *asc, - u8 *ascq) -{ - *asc = cmd->scsi_asc; - *ascq = cmd->scsi_ascq; - - return 0; -} - static void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector) { @@ -2819,9 +2808,8 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; /* Not Ready */ buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - transport_get_sense_codes(cmd, &asc, &ascq); - buffer[SPC_ASC_KEY_OFFSET] = asc; - buffer[SPC_ASCQ_KEY_OFFSET] = ascq; + buffer[SPC_ASC_KEY_OFFSET] = cmd->scsi_asc; + buffer[SPC_ASCQ_KEY_OFFSET] = cmd->scsi_ascq; break; case TCM_MISCOMPARE_VERIFY: /* CURRENT ERROR */ -- GitLab From ab78fef4d5f79134042ae0e1e2c259e1226aa5bd Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 8 Jul 2015 17:58:51 +0300 Subject: [PATCH 1639/7006] target: Split transport_send_check_condition_and_sense() Move the code for translating a sense_reason_t code into a SCSI status ASC and ASCQ codes from transport_send_check_condition_and_sense() into the new function translate_sense_reason(). Convert the switch statement that performs the translation into table-driven code. Signed-off-by: Bart Van Assche Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 383 ++++++++++--------------- 1 file changed, 148 insertions(+), 235 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index b6708d1b69b80..6ef44c9db3813 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2628,13 +2628,155 @@ void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector) put_unaligned_be64(bad_sector, &buffer[12]); } +struct sense_info { + u8 key; + u8 asc; + u8 ascq; + bool add_sector_info; +}; + +static const struct sense_info sense_info_table[] = { + [TCM_NO_SENSE] = { + .key = NOT_READY + }, + [TCM_NON_EXISTENT_LUN] = { + .key = ILLEGAL_REQUEST, + .asc = 0x25 /* LOGICAL UNIT NOT SUPPORTED */ + }, + [TCM_UNSUPPORTED_SCSI_OPCODE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x20, /* INVALID COMMAND OPERATION CODE */ + }, + [TCM_SECTOR_COUNT_TOO_MANY] = { + .key = ILLEGAL_REQUEST, + .asc = 0x20, /* INVALID COMMAND OPERATION CODE */ + }, + [TCM_UNKNOWN_MODE_PAGE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x24, /* INVALID FIELD IN CDB */ + }, + [TCM_CHECK_CONDITION_ABORT_CMD] = { + .key = ABORTED_COMMAND, + .asc = 0x29, /* BUS DEVICE RESET FUNCTION OCCURRED */ + .ascq = 0x03, + }, + [TCM_INCORRECT_AMOUNT_OF_DATA] = { + .key = ABORTED_COMMAND, + .asc = 0x0c, /* WRITE ERROR */ + .ascq = 0x0d, /* NOT ENOUGH UNSOLICITED DATA */ + }, + [TCM_INVALID_CDB_FIELD] = { + .key = ILLEGAL_REQUEST, + .asc = 0x24, /* INVALID FIELD IN CDB */ + }, + [TCM_INVALID_PARAMETER_LIST] = { + .key = ILLEGAL_REQUEST, + .asc = 0x26, /* INVALID FIELD IN PARAMETER LIST */ + }, + [TCM_PARAMETER_LIST_LENGTH_ERROR] = { + .key = ILLEGAL_REQUEST, + .asc = 0x1a, /* PARAMETER LIST LENGTH ERROR */ + }, + [TCM_UNEXPECTED_UNSOLICITED_DATA] = { + .key = ILLEGAL_REQUEST, + .asc = 0x0c, /* WRITE ERROR */ + .ascq = 0x0c, /* UNEXPECTED_UNSOLICITED_DATA */ + }, + [TCM_SERVICE_CRC_ERROR] = { + .key = ABORTED_COMMAND, + .asc = 0x47, /* PROTOCOL SERVICE CRC ERROR */ + .ascq = 0x05, /* N/A */ + }, + [TCM_SNACK_REJECTED] = { + .key = ABORTED_COMMAND, + .asc = 0x11, /* READ ERROR */ + .ascq = 0x13, /* FAILED RETRANSMISSION REQUEST */ + }, + [TCM_WRITE_PROTECTED] = { + .key = DATA_PROTECT, + .asc = 0x27, /* WRITE PROTECTED */ + }, + [TCM_ADDRESS_OUT_OF_RANGE] = { + .key = ILLEGAL_REQUEST, + .asc = 0x21, /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ + }, + [TCM_CHECK_CONDITION_UNIT_ATTENTION] = { + .key = UNIT_ATTENTION, + }, + [TCM_CHECK_CONDITION_NOT_READY] = { + .key = NOT_READY, + }, + [TCM_MISCOMPARE_VERIFY] = { + .key = MISCOMPARE, + .asc = 0x1d, /* MISCOMPARE DURING VERIFY OPERATION */ + .ascq = 0x00, + }, + [TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = { + .key = ILLEGAL_REQUEST, + .asc = 0x10, + .ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */ + .add_sector_info = true, + }, + [TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = { + .key = ILLEGAL_REQUEST, + .asc = 0x10, + .ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ + .add_sector_info = true, + }, + [TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = { + .key = ILLEGAL_REQUEST, + .asc = 0x10, + .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ + .add_sector_info = true, + }, + [TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE] = { + /* + * Returning ILLEGAL REQUEST would cause immediate IO errors on + * Solaris initiators. Returning NOT READY instead means the + * operations will be retried a finite number of times and we + * can survive intermittent errors. + */ + .key = NOT_READY, + .asc = 0x08, /* LOGICAL UNIT COMMUNICATION FAILURE */ + }, +}; + +static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) +{ + const struct sense_info *si; + u8 *buffer = cmd->sense_buffer; + int r = (__force int)reason; + u8 asc, ascq; + + if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key) + si = &sense_info_table[r]; + else + si = &sense_info_table[(__force int) + TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE]; + + buffer[SPC_SENSE_KEY_OFFSET] = si->key; + if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) { + core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); + WARN_ON_ONCE(asc == 0); + } else if (si->asc == 0) { + WARN_ON_ONCE(cmd->scsi_asc == 0); + asc = cmd->scsi_asc; + ascq = cmd->scsi_ascq; + } else { + asc = si->asc; + ascq = si->ascq; + } + buffer[SPC_ASC_KEY_OFFSET] = asc; + buffer[SPC_ASCQ_KEY_OFFSET] = ascq; + if (si->add_sector_info) + transport_err_sector_info(cmd->sense_buffer, cmd->bad_sector); +} + int transport_send_check_condition_and_sense(struct se_cmd *cmd, sense_reason_t reason, int from_transport) { - unsigned char *buffer = cmd->sense_buffer; unsigned long flags; - u8 asc = 0, ascq = 0; spin_lock_irqsave(&cmd->t_state_lock, flags); if (cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { @@ -2644,242 +2786,13 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, cmd->se_cmd_flags |= SCF_SENT_CHECK_CONDITION; spin_unlock_irqrestore(&cmd->t_state_lock, flags); - if (!reason && from_transport) - goto after_reason; - - if (!from_transport) + if (!from_transport) { cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - - /* - * Actual SENSE DATA, see SPC-3 7.23.2 SPC_SENSE_KEY_OFFSET uses - * SENSE KEY values from include/scsi/scsi.h - */ - switch (reason) { - case TCM_NO_SENSE: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* Not Ready */ - buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - /* NO ADDITIONAL SENSE INFORMATION */ - buffer[SPC_ASC_KEY_OFFSET] = 0; - buffer[SPC_ASCQ_KEY_OFFSET] = 0; - break; - case TCM_NON_EXISTENT_LUN: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL UNIT NOT SUPPORTED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x25; - break; - case TCM_UNSUPPORTED_SCSI_OPCODE: - case TCM_SECTOR_COUNT_TOO_MANY: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID COMMAND OPERATION CODE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x20; - break; - case TCM_UNKNOWN_MODE_PAGE: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID FIELD IN CDB */ - buffer[SPC_ASC_KEY_OFFSET] = 0x24; - break; - case TCM_CHECK_CONDITION_ABORT_CMD: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* BUS DEVICE RESET FUNCTION OCCURRED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x29; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x03; - break; - case TCM_INCORRECT_AMOUNT_OF_DATA: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* WRITE ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x0c; - /* NOT ENOUGH UNSOLICITED DATA */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x0d; - break; - case TCM_INVALID_CDB_FIELD: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID FIELD IN CDB */ - buffer[SPC_ASC_KEY_OFFSET] = 0x24; - break; - case TCM_INVALID_PARAMETER_LIST: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* INVALID FIELD IN PARAMETER LIST */ - buffer[SPC_ASC_KEY_OFFSET] = 0x26; - break; - case TCM_PARAMETER_LIST_LENGTH_ERROR: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* PARAMETER LIST LENGTH ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x1a; - break; - case TCM_UNEXPECTED_UNSOLICITED_DATA: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* WRITE ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x0c; - /* UNEXPECTED_UNSOLICITED_DATA */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x0c; - break; - case TCM_SERVICE_CRC_ERROR: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* PROTOCOL SERVICE CRC ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x47; - /* N/A */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x05; - break; - case TCM_SNACK_REJECTED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ABORTED COMMAND */ - buffer[SPC_SENSE_KEY_OFFSET] = ABORTED_COMMAND; - /* READ ERROR */ - buffer[SPC_ASC_KEY_OFFSET] = 0x11; - /* FAILED RETRANSMISSION REQUEST */ - buffer[SPC_ASCQ_KEY_OFFSET] = 0x13; - break; - case TCM_WRITE_PROTECTED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* DATA PROTECT */ - buffer[SPC_SENSE_KEY_OFFSET] = DATA_PROTECT; - /* WRITE PROTECTED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x27; - break; - case TCM_ADDRESS_OUT_OF_RANGE: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK ADDRESS OUT OF RANGE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x21; - break; - case TCM_CHECK_CONDITION_UNIT_ATTENTION: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* UNIT ATTENTION */ - buffer[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; - core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); - buffer[SPC_ASC_KEY_OFFSET] = asc; - buffer[SPC_ASCQ_KEY_OFFSET] = ascq; - break; - case TCM_CHECK_CONDITION_NOT_READY: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* Not Ready */ - buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - buffer[SPC_ASC_KEY_OFFSET] = cmd->scsi_asc; - buffer[SPC_ASCQ_KEY_OFFSET] = cmd->scsi_ascq; - break; - case TCM_MISCOMPARE_VERIFY: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - buffer[SPC_SENSE_KEY_OFFSET] = MISCOMPARE; - /* MISCOMPARE DURING VERIFY OPERATION */ - buffer[SPC_ASC_KEY_OFFSET] = 0x1d; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x00; - break; - case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK GUARD CHECK FAILED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x10; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x01; - transport_err_sector_info(buffer, cmd->bad_sector); - break; - case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x10; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x02; - transport_err_sector_info(buffer, cmd->bad_sector); - break; - case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* ILLEGAL REQUEST */ - buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; - /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ - buffer[SPC_ASC_KEY_OFFSET] = 0x10; - buffer[SPC_ASCQ_KEY_OFFSET] = 0x03; - transport_err_sector_info(buffer, cmd->bad_sector); - break; - case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: - default: - /* CURRENT ERROR */ - buffer[0] = 0x70; - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; - /* - * Returning ILLEGAL REQUEST would cause immediate IO errors on - * Solaris initiators. Returning NOT READY instead means the - * operations will be retried a finite number of times and we - * can survive intermittent errors. - */ - buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; - /* LOGICAL UNIT COMMUNICATION FAILURE */ - buffer[SPC_ASC_KEY_OFFSET] = 0x08; - break; + translate_sense_reason(cmd, reason); + cmd->scsi_status = SAM_STAT_CHECK_CONDITION; + cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; } - /* - * This code uses linux/include/scsi/scsi.h SAM status codes! - */ - cmd->scsi_status = SAM_STAT_CHECK_CONDITION; - /* - * Automatically padded, this value is encoded in the fabric's - * data_length response PDU containing the SCSI defined sense data. - */ - cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; -after_reason: trace_target_cmd_complete(cmd); return cmd->se_tfo->queue_status(cmd); } -- GitLab From 7708c1656552ddd60b9b9df3a9ee156acd1801ba Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Jul 2015 17:58:52 +0300 Subject: [PATCH 1640/7006] scsi: Move sense handling routines to scsi_common Sense data handling is also done in the target stack. Hence, move sense handling routines to scsi_common so the target will be able to use them as well. Signed-off-by: Sagi Grimberg Reviewed-by: Bart Van Assche Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/scsi/scsi_common.c | 98 +++++++++++++++++++++++++++++++++++++ drivers/scsi/scsi_error.c | 99 +------------------------------------- include/scsi/scsi_common.h | 5 ++ include/scsi/scsi_eh.h | 7 +-- 4 files changed, 105 insertions(+), 104 deletions(-) diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c index 2ff092252b762..41432c10dda2f 100644 --- a/drivers/scsi/scsi_common.c +++ b/drivers/scsi/scsi_common.c @@ -5,6 +5,7 @@ #include #include #include +#include #include /* NB: These are exposed through /proc/scsi/scsi and form part of the ABI. @@ -176,3 +177,100 @@ bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, return true; } EXPORT_SYMBOL(scsi_normalize_sense); + +/** + * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. + * @sense_buffer: byte array of descriptor format sense data + * @sb_len: number of valid bytes in sense_buffer + * @desc_type: value of descriptor type to find + * (e.g. 0 -> information) + * + * Notes: + * only valid when sense data is in descriptor format + * + * Return value: + * pointer to start of (first) descriptor if found else NULL + */ +const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type) +{ + int add_sen_len, add_len, desc_len, k; + const u8 * descp; + + if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) + return NULL; + if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) + return NULL; + add_sen_len = (add_sen_len < (sb_len - 8)) ? + add_sen_len : (sb_len - 8); + descp = &sense_buffer[8]; + for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { + descp += desc_len; + add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; + desc_len = add_len + 2; + if (descp[0] == desc_type) + return descp; + if (add_len < 0) // short descriptor ?? + break; + } + return NULL; +} +EXPORT_SYMBOL(scsi_sense_desc_find); + +/** + * scsi_build_sense_buffer - build sense data in a buffer + * @desc: Sense format (non zero == descriptor format, + * 0 == fixed format) + * @buf: Where to build sense data + * @key: Sense key + * @asc: Additional sense code + * @ascq: Additional sense code qualifier + * + **/ +void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) +{ + if (desc) { + buf[0] = 0x72; /* descriptor, current */ + buf[1] = key; + buf[2] = asc; + buf[3] = ascq; + buf[7] = 0; + } else { + buf[0] = 0x70; /* fixed, current */ + buf[2] = key; + buf[7] = 0xa; + buf[12] = asc; + buf[13] = ascq; + } +} +EXPORT_SYMBOL(scsi_build_sense_buffer); + +/** + * scsi_set_sense_information - set the information field in a + * formatted sense data buffer + * @buf: Where to build sense data + * @info: 64-bit information value to be set + * + **/ +void scsi_set_sense_information(u8 *buf, u64 info) +{ + if ((buf[0] & 0x7f) == 0x72) { + u8 *ucp, len; + + len = buf[7]; + ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); + if (!ucp) { + buf[7] = len + 0xa; + ucp = buf + 8 + len; + } + ucp[0] = 0; + ucp[1] = 0xa; + ucp[2] = 0x80; /* Valid bit */ + ucp[3] = 0; + put_unaligned_be64(info, &ucp[4]); + } else if ((buf[0] & 0x7f) == 0x70) { + buf[0] |= 0x80; + put_unaligned_be64(info, &buf[3]); + } +} +EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 106884a5444e1..6e6b2d26d3ce4 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -34,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -2407,45 +2407,6 @@ bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd, } EXPORT_SYMBOL(scsi_command_normalize_sense); -/** - * scsi_sense_desc_find - search for a given descriptor type in descriptor sense data format. - * @sense_buffer: byte array of descriptor format sense data - * @sb_len: number of valid bytes in sense_buffer - * @desc_type: value of descriptor type to find - * (e.g. 0 -> information) - * - * Notes: - * only valid when sense data is in descriptor format - * - * Return value: - * pointer to start of (first) descriptor if found else NULL - */ -const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, - int desc_type) -{ - int add_sen_len, add_len, desc_len, k; - const u8 * descp; - - if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7]))) - return NULL; - if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73)) - return NULL; - add_sen_len = (add_sen_len < (sb_len - 8)) ? - add_sen_len : (sb_len - 8); - descp = &sense_buffer[8]; - for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) { - descp += desc_len; - add_len = (k < (add_sen_len - 1)) ? descp[1]: -1; - desc_len = add_len + 2; - if (descp[0] == desc_type) - return descp; - if (add_len < 0) // short descriptor ?? - break; - } - return NULL; -} -EXPORT_SYMBOL(scsi_sense_desc_find); - /** * scsi_get_sense_info_fld - get information field from sense data (either fixed or descriptor format) * @sense_buffer: byte array of sense data @@ -2495,61 +2456,3 @@ int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, } } EXPORT_SYMBOL(scsi_get_sense_info_fld); - -/** - * scsi_build_sense_buffer - build sense data in a buffer - * @desc: Sense format (non zero == descriptor format, - * 0 == fixed format) - * @buf: Where to build sense data - * @key: Sense key - * @asc: Additional sense code - * @ascq: Additional sense code qualifier - * - **/ -void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq) -{ - if (desc) { - buf[0] = 0x72; /* descriptor, current */ - buf[1] = key; - buf[2] = asc; - buf[3] = ascq; - buf[7] = 0; - } else { - buf[0] = 0x70; /* fixed, current */ - buf[2] = key; - buf[7] = 0xa; - buf[12] = asc; - buf[13] = ascq; - } -} -EXPORT_SYMBOL(scsi_build_sense_buffer); - -/** - * scsi_set_sense_information - set the information field in a - * formatted sense data buffer - * @buf: Where to build sense data - * @info: 64-bit information value to be set - * - **/ -void scsi_set_sense_information(u8 *buf, u64 info) -{ - if ((buf[0] & 0x7f) == 0x72) { - u8 *ucp, len; - - len = buf[7]; - ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); - if (!ucp) { - buf[7] = len + 0xa; - ucp = buf + 8 + len; - } - ucp[0] = 0; - ucp[1] = 0xa; - ucp[2] = 0x80; /* Valid bit */ - ucp[3] = 0; - put_unaligned_be64(info, &ucp[4]); - } else if ((buf[0] & 0x7f) == 0x70) { - buf[0] |= 0x80; - put_unaligned_be64(info, &buf[3]); - } -} -EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h index 676b03b78e573..156d673db900c 100644 --- a/include/scsi/scsi_common.h +++ b/include/scsi/scsi_common.h @@ -61,4 +61,9 @@ static inline bool scsi_sense_valid(const struct scsi_sense_hdr *sshdr) extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr); +extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); +extern void scsi_set_sense_information(u8 *buf, u64 info); +extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, + int desc_type); + #endif /* _SCSI_COMMON_H_ */ diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 4942710ef720e..dbb8c640e26fc 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -4,6 +4,7 @@ #include #include +#include struct scsi_device; struct Scsi_Host; @@ -21,15 +22,9 @@ static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr) return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1)); } -extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, - int desc_type); - extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len, u64 * info_out); -extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -extern void scsi_set_sense_information(u8 *buf, u64 info); - extern int scsi_ioctl_reset(struct scsi_device *, int __user *); struct scsi_eh_save { -- GitLab From 9ec1e1ce3a0f854b9150e7888a373392fbbe7442 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Jul 2015 17:58:53 +0300 Subject: [PATCH 1641/7006] target: Use scsi helpers to build the sense data correctly Instead of open coding the sense buffer construction, use scsi scsi_build_sense_buffer() and scsi_set_sense_information() helpers which moved to scsi_common. Signed-off-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_spc.c | 31 +++++--------------------- drivers/target/target_core_transport.c | 21 ++++------------- 2 files changed, 9 insertions(+), 43 deletions(-) diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index b0744433315a8..c43dcbf2d48e5 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -1157,32 +1157,11 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) if (!rbuf) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; - if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) { - /* - * CURRENT ERROR, UNIT ATTENTION - */ - buf[0] = 0x70; - buf[SPC_SENSE_KEY_OFFSET] = UNIT_ATTENTION; - - /* - * The Additional Sense Code (ASC) from the UNIT ATTENTION - */ - buf[SPC_ASC_KEY_OFFSET] = ua_asc; - buf[SPC_ASCQ_KEY_OFFSET] = ua_ascq; - buf[7] = 0x0A; - } else { - /* - * CURRENT ERROR, NO SENSE - */ - buf[0] = 0x70; - buf[SPC_SENSE_KEY_OFFSET] = NO_SENSE; - - /* - * NO ADDITIONAL SENSE INFORMATION - */ - buf[SPC_ASC_KEY_OFFSET] = 0x00; - buf[7] = 0x0A; - } + if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) + scsi_build_sense_buffer(0, buf, UNIT_ATTENTION, + ua_asc, ua_ascq); + else + scsi_build_sense_buffer(0, buf, NO_SENSE, 0x0, 0x0); memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); transport_kunmap_data_sg(cmd); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 6ef44c9db3813..f528a9def65a8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -2615,19 +2616,6 @@ bool transport_wait_for_tasks(struct se_cmd *cmd) } EXPORT_SYMBOL(transport_wait_for_tasks); -static -void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector) -{ - /* Place failed LBA in sense data information descriptor 0. */ - buffer[SPC_ADD_SENSE_LEN_OFFSET] = 0xc; - buffer[SPC_DESC_TYPE_OFFSET] = 0; /* Information */ - buffer[SPC_ADDITIONAL_DESC_LEN_OFFSET] = 0xa; - buffer[SPC_VALIDITY_OFFSET] = 0x80; - - /* Descriptor Information: failing sector */ - put_unaligned_be64(bad_sector, &buffer[12]); -} - struct sense_info { u8 key; u8 asc; @@ -2754,7 +2742,6 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) si = &sense_info_table[(__force int) TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE]; - buffer[SPC_SENSE_KEY_OFFSET] = si->key; if (reason == TCM_CHECK_CONDITION_UNIT_ATTENTION) { core_scsi3_ua_for_check_condition(cmd, &asc, &ascq); WARN_ON_ONCE(asc == 0); @@ -2766,10 +2753,10 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) asc = si->asc; ascq = si->ascq; } - buffer[SPC_ASC_KEY_OFFSET] = asc; - buffer[SPC_ASCQ_KEY_OFFSET] = ascq; + + scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); if (si->add_sector_info) - transport_err_sector_info(cmd->sense_buffer, cmd->bad_sector); + scsi_set_sense_information(buffer, cmd->bad_sector); } int -- GitLab From 734ca5c467842186bf836d0b33379a51cfe259da Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 8 Jul 2015 17:58:54 +0300 Subject: [PATCH 1642/7006] target: Return ABORTED_COMMAND sense key for PI errors PI errors were reported with ILLEGAL_REQUEST sense key but there was actually no problem with the request. Target detected PI errors should be reported with aborted command sense key. Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index f528a9def65a8..2bece607ca0f9 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2700,19 +2700,19 @@ static const struct sense_info sense_info_table[] = { .ascq = 0x00, }, [TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED] = { - .key = ILLEGAL_REQUEST, + .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x01, /* LOGICAL BLOCK GUARD CHECK FAILED */ .add_sector_info = true, }, [TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED] = { - .key = ILLEGAL_REQUEST, + .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x02, /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */ .add_sector_info = true, }, [TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED] = { - .key = ILLEGAL_REQUEST, + .key = ABORTED_COMMAND, .asc = 0x10, .ascq = 0x03, /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */ .add_sector_info = true, -- GitLab From 3e963b2d3c93e0546e911d681f37d35f0f79b54f Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:33:07 -0700 Subject: [PATCH 1643/7006] tcm_qla2xxx: Remove set-but-not-used variables Detected these by building with W=1. This patch does not change any functionality. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Cc: Quinn Tran Cc: Saurav Kashyap Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d9a8c60843467..474d0c0e6dbaf 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1367,9 +1367,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) struct qla_hw_data *ha = tgt->ha; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); struct se_session *se_sess; - struct se_node_acl *se_nacl; struct tcm_qla2xxx_lport *lport; - struct tcm_qla2xxx_nacl *nacl; BUG_ON(in_interrupt()); @@ -1379,8 +1377,6 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess) dump_stack(); return; } - se_nacl = se_sess->se_node_acl; - nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl); lport = vha->vha_tgt.target_lport_ptr; if (!lport) { @@ -1684,7 +1680,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, (struct tcm_qla2xxx_lport *)target_lport_ptr; struct tcm_qla2xxx_lport *base_lport = (struct tcm_qla2xxx_lport *)base_vha->vha_tgt.target_lport_ptr; - struct tcm_qla2xxx_tpg *base_tpg; struct fc_vport_identifiers vport_id; if (!qla_tgt_mode_enabled(base_vha)) { @@ -1697,7 +1692,6 @@ static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha, pr_err("qla2xxx base_lport or tpg_1 not available\n"); return -EPERM; } - base_tpg = base_lport->tpg_1; memset(&vport_id, 0, sizeof(vport_id)); vport_id.port_name = npiv_wwpn; -- GitLab From 12306b425d0dbab7b60f54e02d67cf3dfae494d1 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 15 Jul 2015 10:55:36 +0300 Subject: [PATCH 1644/7006] scsi: Fix wrong additional sense length in descriptor format The sense header additional sense length should be the accumulated size of all the descriptors. Information descriptor size is 12 bytes. When setting the additional sense length we should add 0xc instead of 0xa. Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/scsi/scsi_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c index 41432c10dda2f..ee6bdf43a8ea3 100644 --- a/drivers/scsi/scsi_common.c +++ b/drivers/scsi/scsi_common.c @@ -260,7 +260,7 @@ void scsi_set_sense_information(u8 *buf, u64 info) len = buf[7]; ucp = (char *)scsi_sense_desc_find(buf, len + 8, 0); if (!ucp) { - buf[7] = len + 0xa; + buf[7] = len + 0xc; ucp = buf + 8 + len; } ucp[0] = 0; -- GitLab From f5a8b3a796db01b639435515b3adc003b9f27387 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 15 Jul 2015 10:55:37 +0300 Subject: [PATCH 1645/7006] scsi: Protect against buffer possible overflow in scsi_set_sense_information Make sure that the input sense buffer has sufficient length to fit the information descriptor (12 additional bytes). Modify scsi_set_sense_information to receive the sense buffer length and adjust its callers scsi target and libata. (Fix patch fuzz in scsi_set_sense_information - nab) Reported-by: Hannes Reinecke Signed-off-by: Sagi Grimberg Reviewed-by: Martin K. Petersen Cc: Tejun Heo Reviewed-by: Christoph Hellwig Signed-off-by: Nicholas Bellinger --- drivers/ata/libata-scsi.c | 4 +++- drivers/scsi/scsi_common.c | 13 ++++++++++++- drivers/target/target_core_transport.c | 14 +++++++++++--- include/scsi/scsi_common.h | 2 +- 4 files changed, 27 insertions(+), 6 deletions(-) diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c index 3131adcc1f87e..2fb7c79e727f9 100644 --- a/drivers/ata/libata-scsi.c +++ b/drivers/ata/libata-scsi.c @@ -289,7 +289,9 @@ void ata_scsi_set_sense_information(struct scsi_cmnd *cmd, return; information = ata_tf_read_block(tf, NULL); - scsi_set_sense_information(cmd->sense_buffer, information); + scsi_set_sense_information(cmd->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + information); } static ssize_t diff --git a/drivers/scsi/scsi_common.c b/drivers/scsi/scsi_common.c index ee6bdf43a8ea3..c126966130ab7 100644 --- a/drivers/scsi/scsi_common.c +++ b/drivers/scsi/scsi_common.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -249,10 +250,13 @@ EXPORT_SYMBOL(scsi_build_sense_buffer); * scsi_set_sense_information - set the information field in a * formatted sense data buffer * @buf: Where to build sense data + * @buf_len: buffer length * @info: 64-bit information value to be set * + * Return value: + * 0 on success or EINVAL for invalid sense buffer length **/ -void scsi_set_sense_information(u8 *buf, u64 info) +int scsi_set_sense_information(u8 *buf, int buf_len, u64 info) { if ((buf[0] & 0x7f) == 0x72) { u8 *ucp, len; @@ -263,6 +267,11 @@ void scsi_set_sense_information(u8 *buf, u64 info) buf[7] = len + 0xc; ucp = buf + 8 + len; } + + if (buf_len < len + 0xc) + /* Not enough room for info */ + return -EINVAL; + ucp[0] = 0; ucp[1] = 0xa; ucp[2] = 0x80; /* Valid bit */ @@ -272,5 +281,7 @@ void scsi_set_sense_information(u8 *buf, u64 info) buf[0] |= 0x80; put_unaligned_be64(info, &buf[3]); } + + return 0; } EXPORT_SYMBOL(scsi_set_sense_information); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2bece607ca0f9..7fb031bbcc8d1 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2729,7 +2729,7 @@ static const struct sense_info sense_info_table[] = { }, }; -static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) +static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) { const struct sense_info *si; u8 *buffer = cmd->sense_buffer; @@ -2756,7 +2756,11 @@ static void translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); if (si->add_sector_info) - scsi_set_sense_information(buffer, cmd->bad_sector); + return scsi_set_sense_information(buffer, + cmd->scsi_sense_length, + cmd->bad_sector); + + return 0; } int @@ -2774,10 +2778,14 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, spin_unlock_irqrestore(&cmd->t_state_lock, flags); if (!from_transport) { + int rc; + cmd->se_cmd_flags |= SCF_EMULATED_TASK_SENSE; - translate_sense_reason(cmd, reason); cmd->scsi_status = SAM_STAT_CHECK_CONDITION; cmd->scsi_sense_length = TRANSPORT_SENSE_BUFFER; + rc = translate_sense_reason(cmd, reason); + if (rc) + return rc; } trace_target_cmd_complete(cmd); diff --git a/include/scsi/scsi_common.h b/include/scsi/scsi_common.h index 156d673db900c..11571b2a831e3 100644 --- a/include/scsi/scsi_common.h +++ b/include/scsi/scsi_common.h @@ -62,7 +62,7 @@ extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr); extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -extern void scsi_set_sense_information(u8 *buf, u64 info); +int scsi_set_sense_information(u8 *buf, int buf_len, u64 info); extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, int desc_type); -- GitLab From 4e4937e8aefde8d49340e803ebbedcdf4b43e5f0 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 16 Jul 2015 10:28:05 +0300 Subject: [PATCH 1646/7006] target: Return descriptor format sense data in case the LU spans 64bit sectors In case a LU spans 64bit sectors, fixed size sense data information field is only 32 bits which means the sector information will be truncated. Thus, if the LU spans 64bit sectors, use descriptor format sense data to correctly report sector information. Reported-by: Christoph Hellwig Reviewed-by: Christoph Hellwig Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Sagi Grimberg Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_hba.c | 5 +++++ drivers/target/target_core_spc.c | 12 +++++++++--- drivers/target/target_core_transport.c | 3 ++- include/target/target_core_backend.h | 2 ++ 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index 62ea4e8e70a89..d746a3a4a623c 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c @@ -176,3 +176,8 @@ core_delete_hba(struct se_hba *hba) kfree(hba); return 0; } + +bool target_sense_desc_format(struct se_device *dev) +{ + return dev->transport->get_blocks(dev) > U32_MAX; +} diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index c43dcbf2d48e5..b949d335a6ba8 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -761,7 +761,12 @@ static int spc_modesense_control(struct se_cmd *cmd, u8 pc, u8 *p) if (pc == 1) goto out; - p[2] = 2; + /* GLTSD: No implicit save of log parameters */ + p[2] = (1 << 1); + if (target_sense_desc_format(dev)) + /* D_SENSE: Descriptor format sense data for 64bit sectors */ + p[2] |= (1 << 2); + /* * From spc4r23, 7.4.7 Control mode page * @@ -1144,6 +1149,7 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) unsigned char *rbuf; u8 ua_asc = 0, ua_ascq = 0; unsigned char buf[SE_SENSE_BUF]; + bool desc_format = target_sense_desc_format(cmd->se_dev); memset(buf, 0, SE_SENSE_BUF); @@ -1158,10 +1164,10 @@ static sense_reason_t spc_emulate_request_sense(struct se_cmd *cmd) return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; if (!core_scsi3_ua_clear_for_request_sense(cmd, &ua_asc, &ua_ascq)) - scsi_build_sense_buffer(0, buf, UNIT_ATTENTION, + scsi_build_sense_buffer(desc_format, buf, UNIT_ATTENTION, ua_asc, ua_ascq); else - scsi_build_sense_buffer(0, buf, NO_SENSE, 0x0, 0x0); + scsi_build_sense_buffer(desc_format, buf, NO_SENSE, 0x0, 0x0); memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length)); transport_kunmap_data_sg(cmd); diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7fb031bbcc8d1..98155db28365b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -2735,6 +2735,7 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) u8 *buffer = cmd->sense_buffer; int r = (__force int)reason; u8 asc, ascq; + bool desc_format = target_sense_desc_format(cmd->se_dev); if (r < ARRAY_SIZE(sense_info_table) && sense_info_table[r].key) si = &sense_info_table[r]; @@ -2754,7 +2755,7 @@ static int translate_sense_reason(struct se_cmd *cmd, sense_reason_t reason) ascq = si->ascq; } - scsi_build_sense_buffer(0, buffer, si->key, asc, ascq); + scsi_build_sense_buffer(desc_format, buffer, si->key, asc, ascq); if (si->add_sector_info) return scsi_set_sense_information(buffer, cmd->scsi_sense_length, diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index 1e5c8f949bae4..56cf8e485ef22 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -93,4 +93,6 @@ bool target_lun_is_rdonly(struct se_cmd *); sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); +bool target_sense_desc_format(struct se_device *dev); + #endif /* TARGET_CORE_BACKEND_H */ -- GitLab From a73c2a2f9123605022bedbd2b59ca7e76036f0b3 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 15 Jul 2015 10:55:39 +0300 Subject: [PATCH 1647/7006] libiscsi: Use scsi helper to set information descriptor In case encountered a PI error, use scsi_set_sense_information instead of open coding information descriptor format. Signed-off-by: Sagi Grimberg Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/scsi/libiscsi.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c index 8053f24f03499..bb5ca7f3d16d1 100644 --- a/drivers/scsi/libiscsi.c +++ b/drivers/scsi/libiscsi.c @@ -853,12 +853,9 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, SAM_STAT_CHECK_CONDITION; scsi_build_sense_buffer(1, sc->sense_buffer, ILLEGAL_REQUEST, 0x10, ascq); - sc->sense_buffer[7] = 0xc; /* Additional sense length */ - sc->sense_buffer[8] = 0; /* Information desc type */ - sc->sense_buffer[9] = 0xa; /* Additional desc length */ - sc->sense_buffer[10] = 0x80; /* Validity bit */ - - put_unaligned_be64(sector, &sc->sense_buffer[12]); + scsi_set_sense_information(sc->sense_buffer, + SCSI_SENSE_BUFFERSIZE, + sector); goto out; } } -- GitLab From acd195800ffca556e9c78c51d1efe534d71dd236 Mon Sep 17 00:00:00 2001 From: Vasanthakumar Thiagarajan Date: Fri, 10 Jul 2015 14:31:20 +0530 Subject: [PATCH 1648/7006] ath10k: delay device access after cold reset It is observed that during cold reset pcie access right after a write operation to SOC_GLOBAL_RESET_ADDRESS causes Data Bus Error and system hard lockup. The reason for bus error is that pcie needs some time to get back to stable state for any transaction during cold reset. Add delay of 20 msecs after write of SOC_GLOBAL_RESET_ADDRESS to fix this issue. This patch is tested on QCA988X. This is also tested on QCA99X0 which is WIP. Signed-off-by: Vasanthakumar Thiagarajan Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/pci.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 5778e5277823c..a69bfa41c68b8 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2761,7 +2761,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar) static int ath10k_pci_cold_reset(struct ath10k *ar) { - int i; u32 val; ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset\n"); @@ -2777,23 +2776,18 @@ static int ath10k_pci_cold_reset(struct ath10k *ar) val |= 1; ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & - RTC_STATE_COLD_RESET_MASK) - break; - msleep(1); - } + /* After writing into SOC_GLOBAL_RESET to put device into + * reset and pulling out of reset pcie may not be stable + * for any immediate pcie register access and cause bus error, + * add delay before any pcie access request to fix this issue. + */ + msleep(20); /* Pull Target, including PCIe, out of RESET. */ val &= ~1; ath10k_pci_reg_write32(ar, SOC_GLOBAL_RESET_ADDRESS, val); - for (i = 0; i < ATH_PCI_RESET_WAIT_MAX; i++) { - if (!(ath10k_pci_reg_read32(ar, RTC_STATE_ADDRESS) & - RTC_STATE_COLD_RESET_MASK)) - break; - msleep(1); - } + msleep(20); ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot cold reset complete\n"); -- GitLab From fbc03a466fd48bc8be2e675be948001feea29e4d Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:19 -0700 Subject: [PATCH 1649/7006] ath10k: update tx path to support QCA99X0 Since QCA99X0 uses fragmentation descriptor differently from other ones on tx path, we need to handle it separately. QCA99X0 is using 48 bits for address and 16 bits for length out of 2 dword and each values have to be programmed by frag desc base addr + msdu id, so that hardware can retrieve corresponding frag data. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 13 +++++++-- drivers/net/wireless/ath/ath10k/htt_tx.c | 35 +++++++++++++++++------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 8bdf1e7dd1718..e31cd74dded6e 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -83,8 +83,17 @@ struct htt_ver_req { * around the mask + shift defs. */ struct htt_data_tx_desc_frag { - __le32 paddr; - __le32 len; + union { + struct double_word_addr { + __le32 paddr; + __le32 len; + } __packed dword_addr; + struct triple_word_addr { + __le32 paddr_lo; + __le16 paddr_hi; + __le16 len_16; + } __packed tword_addr; + } __packed; } __packed; struct htt_msdu_ext_desc { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 148d5b607c3cf..c49ecffc29055 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -63,7 +63,8 @@ int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb) lockdep_assert_held(&htt->tx_lock); - ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC); + ret = idr_alloc(&htt->pending_tx, skb, 0, + htt->max_num_pending_tx, GFP_ATOMIC); ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret); @@ -259,6 +260,7 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt) cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc); cmd->frag_desc_bank_cfg.bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr); + cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0; cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx - 1); @@ -537,16 +539,29 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) flags0 |= HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT; /* pass through */ case ATH10K_HW_TXRX_ETHERNET: - frags = skb_cb->htt.txbuf->frags; - - frags[0].paddr = __cpu_to_le32(skb_cb->paddr); - frags[0].len = __cpu_to_le32(msdu->len); - frags[1].paddr = 0; - frags[1].len = 0; - + if (ar->hw_params.continuous_frag_desc) { + frags = (struct htt_data_tx_desc_frag *) + &htt->frag_desc.vaddr[msdu_id].frags; + frags[0].tword_addr.paddr_lo = + __cpu_to_le32(skb_cb->paddr); + frags[0].tword_addr.paddr_hi = 0; + frags[0].tword_addr.len_16 = __cpu_to_le16(msdu->len); + frags[1].tword_addr.paddr_lo = 0; + frags[1].tword_addr.paddr_hi = 0; + + frags_paddr = htt->frag_desc.paddr + + (sizeof(struct htt_msdu_ext_desc) * msdu_id); + } else { + frags = skb_cb->htt.txbuf->frags; + frags[0].dword_addr.paddr = + __cpu_to_le32(skb_cb->paddr); + frags[0].dword_addr.len = __cpu_to_le32(msdu->len); + frags[1].dword_addr.paddr = 0; + frags[1].dword_addr.len = 0; + + frags_paddr = skb_cb->htt.txbuf_paddr; + } flags0 |= SM(skb_cb->txmode, HTT_DATA_TX_DESC_FLAGS0_PKT_TYPE); - - frags_paddr = skb_cb->htt.txbuf_paddr; break; case ATH10K_HW_TXRX_MGMT: flags0 |= SM(ATH10K_HW_TXRX_MGMT, -- GitLab From 05a2cb0daa49af4e240834ff3736fd35ba83320f Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:20 -0700 Subject: [PATCH 1650/7006] ath10k: redefine rx_ppdu_end_common structure to cover qca99x0 rx_ppdu_end_common structure is valid for both of qca998x and qca6174, but not for qca99x0 since it has new additional members. Hence update the common structure to cover qca99x0 as well. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/rx_desc.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 492b5a5af434d..6cb078d6c3cc2 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -891,13 +891,13 @@ struct rx_ppdu_end_common { __le32 evm_p15; __le32 tsf_timestamp; __le32 wb_timestamp; +} __packed; + +struct rx_ppdu_end_qca988x { u8 locationing_timestamp; u8 phy_err_code; __le16 flags; /* %RX_PPDU_END_FLAGS_ */ __le32 info0; /* %RX_PPDU_END_INFO0_ */ -} __packed; - -struct rx_ppdu_end_qca988x { __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; @@ -909,6 +909,10 @@ struct rx_ppdu_end_qca988x { #define RX_PPDU_END_RTT_NORMAL_MODE BIT(31) struct rx_ppdu_end_qca6174 { + u8 locationing_timestamp; + u8 phy_err_code; + __le16 flags; /* %RX_PPDU_END_FLAGS_ */ + __le32 info0; /* %RX_PPDU_END_INFO0_ */ __le32 rtt; /* %RX_PPDU_END_RTT_ */ __le16 bb_length; __le16 info1; /* %RX_PPDU_END_INFO1_ */ -- GitLab From 1f5dbfbb64c92e1c22305ac2b3951d6e3cf7a9a7 Mon Sep 17 00:00:00 2001 From: Peter Oh Date: Wed, 15 Jul 2015 19:01:21 -0700 Subject: [PATCH 1651/7006] ath10k: add support for qca99x0 Rx descriptors QCA99X0 chip has an extra 4 bytes in rx_msdu_start, 20 bytes in rx_msdu_end and 20 bytes in rx_ppdu_end structure which are used in htt_rx_desc and HTT Rx ring offset setup. This is necessary for correct Rx for QCA99X0 or Rx descriptors will be overwritten and corrupted. With this patch QCA988X and QCA6174 will have extra 44 bytes padding in Rx descriptor layout which is harmless. Signed-off-by: Peter Oh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt_rx.c | 24 ++-- drivers/net/wireless/ath/ath10k/rx_desc.h | 163 +++++++++++++++++++++- 2 files changed, 172 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c index d7d118328f31b..61a26264728aa 100644 --- a/drivers/net/wireless/ath/ath10k/htt_rx.c +++ b/drivers/net/wireless/ath/ath10k/htt_rx.c @@ -368,7 +368,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_len_invalid = !!(__le32_to_cpu(rx_desc->attention.flags) & (RX_ATTENTION_FLAGS_MPDU_LENGTH_ERR | RX_ATTENTION_FLAGS_MSDU_LENGTH_ERR)); - msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.info0), + msdu_len = MS(__le32_to_cpu(rx_desc->msdu_start.common.info0), RX_MSDU_START_INFO0_MSDU_LENGTH); msdu_chained = rx_desc->frag_info.ring2_more_count; @@ -394,7 +394,7 @@ static int ath10k_htt_rx_amsdu_pop(struct ath10k_htt *htt, msdu_chaining = 1; } - last_msdu = __le32_to_cpu(rx_desc->msdu_end.info0) & + last_msdu = __le32_to_cpu(rx_desc->msdu_end.common.info0) & RX_MSDU_END_INFO0_LAST_MSDU; trace_ath10k_htt_rx_desc(ar, &rx_desc->attention, @@ -740,7 +740,7 @@ ath10k_htt_rx_h_peer_channel(struct ath10k *ar, struct htt_rx_desc *rxd) __cpu_to_le32(RX_ATTENTION_FLAGS_PEER_IDX_INVALID)) return NULL; - if (!(rxd->msdu_end.info0 & + if (!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU))) return NULL; @@ -991,9 +991,9 @@ static void ath10k_htt_rx_h_undecap_raw(struct ath10k *ar, bool is_last; rxd = (void *)msdu->data - sizeof(*rxd); - is_first = !!(rxd->msdu_end.info0 & + is_first = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); - is_last = !!(rxd->msdu_end.info0 & + is_last = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); /* Delivered decapped frame: @@ -1104,9 +1104,9 @@ static void *ath10k_htt_rx_h_find_rfc1042(struct ath10k *ar, rxd = (void *)msdu->data - sizeof(*rxd); hdr = (void *)rxd->rx_hdr_status; - is_first = !!(rxd->msdu_end.info0 & + is_first = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_FIRST_MSDU)); - is_last = !!(rxd->msdu_end.info0 & + is_last = !!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)); is_amsdu = !(is_first && is_last); @@ -1214,7 +1214,7 @@ static void ath10k_htt_rx_h_undecap(struct ath10k *ar, */ rxd = (void *)msdu->data - sizeof(*rxd); - decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); switch (decap) { @@ -1244,7 +1244,7 @@ static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb) rxd = (void *)skb->data - sizeof(*rxd); flags = __le32_to_cpu(rxd->attention.flags); - info = __le32_to_cpu(rxd->msdu_start.info1); + info = __le32_to_cpu(rxd->msdu_start.common.info1); is_ip4 = !!(info & RX_MSDU_START_INFO1_IPV4_PROTO); is_ip6 = !!(info & RX_MSDU_START_INFO1_IPV6_PROTO); @@ -1437,7 +1437,7 @@ static void ath10k_htt_rx_h_unchain(struct ath10k *ar, first = skb_peek(amsdu); rxd = (void *)first->data - sizeof(*rxd); - decap = MS(__le32_to_cpu(rxd->msdu_start.info1), + decap = MS(__le32_to_cpu(rxd->msdu_start.common.info1), RX_MSDU_START_INFO1_DECAP_FORMAT); if (!chained) @@ -1757,14 +1757,14 @@ static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list, __skb_queue_tail(amsdu, msdu); rxd = (void *)msdu->data - sizeof(*rxd); - if (rxd->msdu_end.info0 & + if (rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU)) break; } msdu = skb_peek_tail(amsdu); rxd = (void *)msdu->data - sizeof(*rxd); - if (!(rxd->msdu_end.info0 & + if (!(rxd->msdu_end.common.info0 & __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) { skb_queue_splice_init(amsdu, list); return -EAGAIN; diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h index 6cb078d6c3cc2..ca8d16884af1d 100644 --- a/drivers/net/wireless/ath/ath10k/rx_desc.h +++ b/drivers/net/wireless/ath/ath10k/rx_desc.h @@ -422,6 +422,12 @@ struct rx_mpdu_end { #define RX_MSDU_START_INFO1_IP_FRAG (1 << 14) #define RX_MSDU_START_INFO1_TCP_ONLY_ACK (1 << 15) +#define RX_MSDU_START_INFO2_DA_IDX_MASK 0x000007ff +#define RX_MSDU_START_INFO2_DA_IDX_LSB 0 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_MASK 0x00ff0000 +#define RX_MSDU_START_INFO2_IP_PROTO_FIELD_LSB 16 +#define RX_MSDU_START_INFO2_DA_BCAST_MCAST BIT(11) + /* The decapped header (rx_hdr_status) contains the following: * a) 802.11 header * [padding to 4 bytes] @@ -449,12 +455,23 @@ enum rx_msdu_decap_format { RX_MSDU_DECAP_8023_SNAP_LLC = 3 }; -struct rx_msdu_start { +struct rx_msdu_start_common { __le32 info0; /* %RX_MSDU_START_INFO0_ */ __le32 flow_id_crc; __le32 info1; /* %RX_MSDU_START_INFO1_ */ } __packed; +struct rx_msdu_start_qca99x0 { + __le32 info2; /* %RX_MSDU_START_INFO2_ */ +} __packed; + +struct rx_msdu_start { + struct rx_msdu_start_common common; + union { + struct rx_msdu_start_qca99x0 qca99x0; + } __packed; +} __packed; + /* * msdu_length * MSDU length in bytes after decapsulation. This field is @@ -540,7 +557,7 @@ struct rx_msdu_start { #define RX_MSDU_END_INFO0_PRE_DELIM_ERR (1 << 30) #define RX_MSDU_END_INFO0_RESERVED_3B (1 << 31) -struct rx_msdu_end { +struct rx_msdu_end_common { __le16 ip_hdr_cksum; __le16 tcp_hdr_cksum; u8 key_id_octet; @@ -549,6 +566,36 @@ struct rx_msdu_end { __le32 info0; } __packed; +#define RX_MSDU_END_INFO1_TCP_FLAG_MASK 0x000001ff +#define RX_MSDU_END_INFO1_TCP_FLAG_LSB 0 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_MASK 0x00001c00 +#define RX_MSDU_END_INFO1_L3_HDR_PAD_LSB 10 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_MASK 0xffff0000 +#define RX_MSDU_END_INFO1_WINDOW_SIZE_LSB 16 +#define RX_MSDU_END_INFO1_IRO_ELIGIBLE BIT(9) + +#define RX_MSDU_END_INFO2_DA_OFFSET_MASK 0x0000003f +#define RX_MSDU_END_INFO2_DA_OFFSET_LSB 0 +#define RX_MSDU_END_INFO2_SA_OFFSET_MASK 0x00000fc0 +#define RX_MSDU_END_INFO2_SA_OFFSET_LSB 6 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_MASK 0x0003f000 +#define RX_MSDU_END_INFO2_TYPE_OFFSET_LSB 12 + +struct rx_msdu_end_qca99x0 { + __le32 ipv6_crc; + __le32 tcp_seq_no; + __le32 tcp_ack_no; + __le32 info1; + __le32 info2; +} __packed; + +struct rx_msdu_end { + struct rx_msdu_end_common common; + union { + struct rx_msdu_end_qca99x0 qca99x0; + } __packed; +} __packed; + /* *ip_hdr_chksum * This can include the IP header checksum or the pseudo header @@ -870,7 +917,11 @@ struct rx_ppdu_start { #define RX_PPDU_END_INFO0_FLAGS_TX_HT_VHT_ACK (1 << 24) #define RX_PPDU_END_INFO0_BB_CAPTURED_CHANNEL (1 << 25) -#define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15) +#define RX_PPDU_END_INFO1_PEER_IDX_MASK 0x1ffc +#define RX_PPDU_END_INFO1_PEER_IDX_LSB 2 +#define RX_PPDU_END_INFO1_BB_DATA BIT(0) +#define RX_PPDU_END_INFO1_PEER_IDX_VALID BIT(1) +#define RX_PPDU_END_INFO1_PPDU_DONE BIT(15) struct rx_ppdu_end_common { __le32 evm_p0; @@ -918,11 +969,117 @@ struct rx_ppdu_end_qca6174 { __le16 info1; /* %RX_PPDU_END_INFO1_ */ } __packed; +#define RX_PKT_END_INFO0_RX_SUCCESS BIT(0) +#define RX_PKT_END_INFO0_ERR_TX_INTERRUPT_RX BIT(3) +#define RX_PKT_END_INFO0_ERR_OFDM_POWER_DROP BIT(4) +#define RX_PKT_END_INFO0_ERR_OFDM_RESTART BIT(5) +#define RX_PKT_END_INFO0_ERR_CCK_POWER_DROP BIT(6) +#define RX_PKT_END_INFO0_ERR_CCK_RESTART BIT(7) + +#define RX_LOCATION_INFO_RTT_CORR_VAL_MASK 0x0001ffff +#define RX_LOCATION_INFO_RTT_CORR_VAL_LSB 0 +#define RX_LOCATION_INFO_FAC_STATUS_MASK 0x000c0000 +#define RX_LOCATION_INFO_FAC_STATUS_LSB 18 +#define RX_LOCATION_INFO_PKT_BW_MASK 0x00700000 +#define RX_LOCATION_INFO_PKT_BW_LSB 20 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_MASK 0x01800000 +#define RX_LOCATION_INFO_RTT_TX_FRAME_PHASE_LSB 23 +#define RX_LOCATION_INFO_CIR_STATUS BIT(17) +#define RX_LOCATION_INFO_RTT_MAC_PHY_PHASE BIT(25) +#define RX_LOCATION_INFO_RTT_TX_DATA_START_X BIT(26) +#define RX_LOCATION_INFO_HW_IFFT_MODE BIT(30) +#define RX_LOCATION_INFO_RX_LOCATION_VALID BIT(31) + +struct rx_pkt_end { + __le32 info0; /* %RX_PKT_END_INFO0_ */ + __le32 phy_timestamp_1; + __le32 phy_timestamp_2; + __le32 rx_location_info; /* %RX_LOCATION_INFO_ */ +} __packed; + +enum rx_phy_ppdu_end_info0 { + RX_PHY_PPDU_END_INFO0_ERR_RADAR = BIT(2), + RX_PHY_PPDU_END_INFO0_ERR_RX_ABORT = BIT(3), + RX_PHY_PPDU_END_INFO0_ERR_RX_NAP = BIT(4), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_TIMING = BIT(5), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_PARITY = BIT(6), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_RATE = BIT(7), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_LENGTH = BIT(8), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_RESTART = BIT(9), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_SERVICE = BIT(10), + RX_PHY_PPDU_END_INFO0_ERR_OFDM_POWER_DROP = BIT(11), + RX_PHY_PPDU_END_INFO0_ERR_CCK_BLOCKER = BIT(12), + RX_PHY_PPDU_END_INFO0_ERR_CCK_TIMING = BIT(13), + RX_PHY_PPDU_END_INFO0_ERR_CCK_HEADER_CRC = BIT(14), + RX_PHY_PPDU_END_INFO0_ERR_CCK_RATE = BIT(15), + RX_PHY_PPDU_END_INFO0_ERR_CCK_LENGTH = BIT(16), + RX_PHY_PPDU_END_INFO0_ERR_CCK_RESTART = BIT(17), + RX_PHY_PPDU_END_INFO0_ERR_CCK_SERVICE = BIT(18), + RX_PHY_PPDU_END_INFO0_ERR_CCK_POWER_DROP = BIT(19), + RX_PHY_PPDU_END_INFO0_ERR_HT_CRC = BIT(20), + RX_PHY_PPDU_END_INFO0_ERR_HT_LENGTH = BIT(21), + RX_PHY_PPDU_END_INFO0_ERR_HT_RATE = BIT(22), + RX_PHY_PPDU_END_INFO0_ERR_HT_ZLF = BIT(23), + RX_PHY_PPDU_END_INFO0_ERR_FALSE_RADAR_EXT = BIT(24), + RX_PHY_PPDU_END_INFO0_ERR_GREEN_FIELD = BIT(25), + RX_PHY_PPDU_END_INFO0_ERR_SPECTRAL_SCAN = BIT(26), + RX_PHY_PPDU_END_INFO0_ERR_RX_DYN_BW = BIT(27), + RX_PHY_PPDU_END_INFO0_ERR_LEG_HT_MISMATCH = BIT(28), + RX_PHY_PPDU_END_INFO0_ERR_VHT_CRC = BIT(29), + RX_PHY_PPDU_END_INFO0_ERR_VHT_SIGA = BIT(30), + RX_PHY_PPDU_END_INFO0_ERR_VHT_LSIG = BIT(31), +}; + +enum rx_phy_ppdu_end_info1 { + RX_PHY_PPDU_END_INFO1_ERR_VHT_NDP = BIT(0), + RX_PHY_PPDU_END_INFO1_ERR_VHT_NSYM = BIT(1), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_EXT_SYM = BIT(2), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID0 = BIT(3), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID1_62 = BIT(4), + RX_PHY_PPDU_END_INFO1_ERR_VHT_RX_SKIP_ID63 = BIT(5), + RX_PHY_PPDU_END_INFO1_ERR_OFDM_LDPC_DECODER = BIT(6), + RX_PHY_PPDU_END_INFO1_ERR_DEFER_NAP = BIT(7), + RX_PHY_PPDU_END_INFO1_ERR_FDOMAIN_TIMEOUT = BIT(8), + RX_PHY_PPDU_END_INFO1_ERR_LSIG_REL_CHECK = BIT(9), + RX_PHY_PPDU_END_INFO1_ERR_BT_COLLISION = BIT(10), + RX_PHY_PPDU_END_INFO1_ERR_MU_FEEDBACK = BIT(11), + RX_PHY_PPDU_END_INFO1_ERR_TX_INTERRUPT_RX = BIT(12), + RX_PHY_PPDU_END_INFO1_ERR_RX_CBF = BIT(13), +}; + +struct rx_phy_ppdu_end { + __le32 info0; /* %RX_PHY_PPDU_END_INFO0_ */ + __le32 info1; /* %RX_PHY_PPDU_END_INFO1_ */ +} __packed; + +#define RX_PPDU_END_RX_TIMING_OFFSET_MASK 0x00000fff +#define RX_PPDU_END_RX_TIMING_OFFSET_LSB 0 + +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_MASK 0x00ffffff +#define RX_PPDU_END_RX_INFO_RX_ANTENNA_LSB 0 +#define RX_PPDU_END_RX_INFO_TX_HT_VHT_ACK BIT(24) +#define RX_PPDU_END_RX_INFO_RX_PKT_END_VALID BIT(25) +#define RX_PPDU_END_RX_INFO_RX_PHY_PPDU_END_VALID BIT(26) +#define RX_PPDU_END_RX_INFO_RX_TIMING_OFFSET_VALID BIT(27) +#define RX_PPDU_END_RX_INFO_BB_CAPTURED_CHANNEL BIT(28) +#define RX_PPDU_END_RX_INFO_UNSUPPORTED_MU_NC BIT(29) +#define RX_PPDU_END_RX_INFO_OTP_TXBF_DISABLE BIT(30) + +struct rx_ppdu_end_qca99x0 { + struct rx_pkt_end rx_pkt_end; + struct rx_phy_ppdu_end rx_phy_ppdu_end; + __le32 rx_timing_offset; /* %RX_PPDU_END_RX_TIMING_OFFSET_ */ + __le32 rx_info; /* %RX_PPDU_END_RX_INFO_ */ + __le16 bb_length; + __le16 info1; /* %RX_PPDU_END_INFO1_ */ +} __packed; + struct rx_ppdu_end { struct rx_ppdu_end_common common; union { struct rx_ppdu_end_qca988x qca988x; struct rx_ppdu_end_qca6174 qca6174; + struct rx_ppdu_end_qca99x0 qca99x0; } __packed; } __packed; -- GitLab From 19be9e9a7ac7e6050eab426283d2a87593cf6e82 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Thu, 16 Jul 2015 09:25:33 +0530 Subject: [PATCH 1652/7006] ath10k: fix wrong initialization of struct channel chandef is initialized with NULL and on the very next line, we are using it to get channel, which is not correct. Channel should be initialized after obtaining chandef. Found by cppcheck: ath/ath10k/mac.c:839]: (error) Possible null pointer dereference: chandef Signed-off-by: Maninder Singh Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index c9a7d5b5dffc5..49a54a1f07a89 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -836,7 +836,7 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = NULL; - struct ieee80211_channel *channel = chandef->chan; + struct ieee80211_channel *channel = NULL; struct wmi_vdev_start_request_arg arg = {}; int ret = 0; -- GitLab From b963519509644f52eaaddcc1fa484e28ac74c750 Mon Sep 17 00:00:00 2001 From: Manikanta Pubbisetty Date: Mon, 20 Jul 2015 17:56:12 +0530 Subject: [PATCH 1653/7006] ath10k: add TCP/UDP Checksum offload support for QCA99x0 The patch adds support to offload TCP/UDP checksum calculations for QCA99x0. Signed-off-by: Manikanta Pubbisetty Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 17 ++++++++++++++++- drivers/net/wireless/ath/ath10k/htt_tx.c | 4 ++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index e31cd74dded6e..551f64bf64578 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -97,10 +97,25 @@ struct htt_data_tx_desc_frag { } __packed; struct htt_msdu_ext_desc { - __le32 tso_flag[4]; + __le32 tso_flag[3]; + __le16 ip_identification; + u8 flags; + u8 reserved; struct htt_data_tx_desc_frag frags[6]; }; +#define HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE BIT(0) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE BIT(1) +#define HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE BIT(2) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE BIT(3) +#define HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE BIT(4) + +#define HTT_MSDU_CHECKSUM_ENABLE (HTT_MSDU_EXT_DESC_FLAG_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_UDP_IPV6_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV4_CSUM_ENABLE \ + | HTT_MSDU_EXT_DESC_FLAG_TCP_IPV6_CSUM_ENABLE) + enum htt_data_tx_desc_flags0 { HTT_DATA_TX_DESC_FLAGS0_MAC_HDR_PRESENT = 1 << 0, HTT_DATA_TX_DESC_FLAGS0_NO_AGGR = 1 << 1, diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index c49ecffc29055..1b34c1350f637 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -496,6 +496,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) u16 msdu_id, flags1 = 0; dma_addr_t paddr = 0; u32 frags_paddr = 0; + struct htt_msdu_ext_desc *ext_desc = NULL; res = ath10k_htt_tx_inc_pending(htt); if (res) @@ -542,6 +543,7 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if (ar->hw_params.continuous_frag_desc) { frags = (struct htt_data_tx_desc_frag *) &htt->frag_desc.vaddr[msdu_id].frags; + ext_desc = &htt->frag_desc.vaddr[msdu_id]; frags[0].tword_addr.paddr_lo = __cpu_to_le32(skb_cb->paddr); frags[0].tword_addr.paddr_hi = 0; @@ -603,6 +605,8 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) if (msdu->ip_summed == CHECKSUM_PARTIAL) { flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD; flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD; + if (ar->hw_params.continuous_frag_desc) + ext_desc->flags |= HTT_MSDU_CHECKSUM_ENABLE; } /* Prevent firmware from sending up tx inspection requests. There's -- GitLab From 1d0088f8c1d8b9541ed01f2cc52606fbf8baf50c Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Tue, 21 Jul 2015 10:52:00 +0530 Subject: [PATCH 1654/7006] ath10k: extend struct htt_mgmt_tx_dec for qca99x0 HTT_H2T_MSG_TYPE_MGMT_TX msg in 10.4 firmware carries additional 4 byte in htt_mgmt_tx_desc where it tells to firmware that at what rate mgmt frame has to go out in the air. It's an optional parameter, setting this field to zero will force firmware to choose auto rate and send the frame out. Those 4 byte info is missed out in the current code and 10.4 firmware ended up reading some junk in those 4 byte and sometime malfunctioning. Fix it by adding 4 byte in struct htt_mgmt_tx_desc. Non 10.4 firmware will not process those four byte. So, adding 4 byte at the end of struct htt_mgmt_tx_desc will not create any impact on other chipset. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htt.h | 6 ++++++ drivers/net/wireless/ath/ath10k/htt_tx.c | 2 ++ 2 files changed, 8 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h index 551f64bf64578..7583a126e8795 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h @@ -284,6 +284,9 @@ struct htt_aggr_conf { } __packed; #define HTT_MGMT_FRM_HDR_DOWNLOAD_LEN 32 +struct htt_mgmt_tx_desc_qca99x0 { + __le32 rate; +} __packed; struct htt_mgmt_tx_desc { u8 pad[sizeof(u32) - sizeof(struct htt_cmd_hdr)]; @@ -292,6 +295,9 @@ struct htt_mgmt_tx_desc { __le32 len; __le32 vdev_id; u8 hdr[HTT_MGMT_FRM_HDR_DOWNLOAD_LEN]; + union { + struct htt_mgmt_tx_desc_qca99x0 qca99x0; + } __packed; } __packed; enum htt_mgmt_tx_status { diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 1b34c1350f637..a97dd9d4295ba 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -450,6 +450,8 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_put(txdesc, len); cmd = (struct htt_cmd *)txdesc->data; + memset(cmd, 0, len); + cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_MGMT_TX; cmd->mgmt_tx.msdu_paddr = __cpu_to_le32(ATH10K_SKB_CB(msdu)->paddr); cmd->mgmt_tx.len = __cpu_to_le32(msdu->len); -- GitLab From 48f403be3eb9b603cfaf946ca7a0c76272750469 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 23 Jul 2015 23:23:35 +0800 Subject: [PATCH 1655/7006] ASoC: pcm1681: Improve the logic for de-emphasis sampling rate selection Slightly improve the logic for de-emphasis sampling rate selection by break out the loop if the rate is matched. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/pcm1681.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/sound/soc/codecs/pcm1681.c b/sound/soc/codecs/pcm1681.c index e7ba557979cb2..490970e5ab8cc 100644 --- a/sound/soc/codecs/pcm1681.c +++ b/sound/soc/codecs/pcm1681.c @@ -95,17 +95,22 @@ static int pcm1681_set_deemph(struct snd_soc_codec *codec) struct pcm1681_private *priv = snd_soc_codec_get_drvdata(codec); int i = 0, val = -1, enable = 0; - if (priv->deemph) - for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) - if (pcm1681_deemph[i] == priv->rate) + if (priv->deemph) { + for (i = 0; i < ARRAY_SIZE(pcm1681_deemph); i++) { + if (pcm1681_deemph[i] == priv->rate) { val = i; + break; + } + } + } if (val != -1) { regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, PCM1681_DEEMPH_RATE_MASK, val << 3); enable = 1; - } else + } else { enable = 0; + } /* enable/disable deemphasis functionality */ return regmap_update_bits(priv->regmap, PCM1681_DEEMPH_CONTROL, -- GitLab From 97a747117d95b54fe3ce21d43e04499a1671fff6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 24 Jul 2015 11:17:28 +0800 Subject: [PATCH 1656/7006] ASoC: sta529: Remove redundant I2C_FUNC_SMBUS_BYTE_DATA functionality check This checking is done by regmap_get_i2c_bus() which is called in devm_regmap_init_i2c(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/sta529.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 4f70378b2cfb4..2519c7f1cad3d 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c @@ -339,9 +339,6 @@ static int sta529_i2c_probe(struct i2c_client *i2c, struct sta529 *sta529; int ret; - if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) - return -EINVAL; - sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL); if (!sta529) return -ENOMEM; -- GitLab From eeffd4b442eb2aa25257d8c6631b17cba685ccac Mon Sep 17 00:00:00 2001 From: Harsha Priya Date: Thu, 23 Jul 2015 19:11:54 +0000 Subject: [PATCH 1657/7006] ASoC: ssm4567: Added ACPI entry for SSM4567 codec Added INT343B ACPI ID for the SSM4567 codec Signed-off-by: Harsha Priya Signed-off-by: M Naveen Signed-off-by: M R Sathya Prakash Acked-by: Anatol Pomozov Acked-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/codecs/ssm4567.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c index 938d2cb6d78be..af536ae75df9d 100644 --- a/sound/soc/codecs/ssm4567.c +++ b/sound/soc/codecs/ssm4567.c @@ -10,6 +10,7 @@ * Licensed under the GPL-2. */ +#include #include #include #include @@ -450,10 +451,21 @@ static const struct i2c_device_id ssm4567_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, ssm4567_i2c_ids); +#ifdef CONFIG_ACPI + +static const struct acpi_device_id ssm4567_acpi_match[] = { + { "INT343B", 0 }, + {}, +}; +MODULE_DEVICE_TABLE(acpi, ssm4567_acpi_match); + +#endif + static struct i2c_driver ssm4567_driver = { .driver = { .name = "ssm4567", .owner = THIS_MODULE, + .acpi_match_table = ACPI_PTR(ssm4567_acpi_match), }, .probe = ssm4567_i2c_probe, .remove = ssm4567_i2c_remove, -- GitLab From 0439de75d32c249bd9f5824ffd5e40c4c2109d77 Mon Sep 17 00:00:00 2001 From: Stephen Just Date: Wed, 22 Jul 2015 20:11:40 -0700 Subject: [PATCH 1658/7006] HID: microsoft: Add Surface 3 type cover Adding support for the Microsoft Surface 3 (non-pro) Type Cover. The existing definitions and quirks are actually for the Surface Pro 3 type covers. I've renamed the old constants to reflect that they belong to the Surface Pro 3, and added a new constant and matching code for the Surface 3. Signed-off-by: Stephen Just Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 8 +++++--- drivers/hid/hid-ids.h | 5 +++-- drivers/hid/hid-microsoft.c | 6 ++++-- drivers/hid/usbhid/hid-quirks.c | 3 ++- 4 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 157c627750535..d9c7cd971a521 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -705,8 +705,9 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->group = HID_GROUP_SENSOR_HUB; if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP || + (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -1902,8 +1903,9 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d8163..8dab4b2e9dfe8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -663,8 +663,9 @@ #define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 #define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 -#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc -#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd +#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc +#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd +#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de #define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 32a596f554afe..9aa3515090a72 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -276,9 +276,11 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500), .driver_data = MS_DUPLICATE_USAGES }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3), + .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP), .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3), .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), .driver_data = MS_HIDINPUT }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 53e7de7cb9e25..198e2665de44a 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -87,8 +87,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C05A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOUSE_C06A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, -- GitLab From 070f63b46ac893a5debf68c5751101b6f5f77230 Mon Sep 17 00:00:00 2001 From: Yang Bo Date: Mon, 20 Jul 2015 09:40:28 -0700 Subject: [PATCH 1659/7006] HID: multitouch: Add support for CJTouch MultiTouch Add device IDs for CJTouch 0020 and 0040 panels. Signed-off-by: Yang Bo Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-ids.h | 4 ++++ drivers/hid/hid-multitouch.c | 8 ++++++++ 3 files changed, 13 insertions(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index cc4c6649d1950..57c94d7d5834b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -480,6 +480,7 @@ config HID_MULTITOUCH - Atmel panels - Cando dual touch panels - Chunghwa panels + - CJTouch panels - CVTouch panels - Cypress TrueTouch panels - Elan Microelectronics touch panels diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d8163..591b7d06f54d3 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -236,6 +236,10 @@ #define USB_VENDOR_ID_CIDC 0x1677 +#define USB_VENDOR_ID_CJTOUCH 0x24b8 +#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020 +#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040 + #define USB_VENDOR_ID_CMEDIA 0x0d8c #define USB_DEVICE_ID_CM109 0x000e diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6a9b05b328a9d..ab0434f86f49d 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1138,6 +1138,14 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) }, + /* CJTouch panels */ + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, + USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020) }, + { .driver_data = MT_CLS_NSMU, + MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH, + USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040) }, + /* CVTouch panels */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, -- GitLab From 8f5f0bc2766af7785161a4440bca1d0746eb3671 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Thu, 23 Jul 2015 19:01:16 -0400 Subject: [PATCH 1660/7006] HID: sony: Drop invalid Sixaxis input reports When connected via Bluetooth the sixaxis periodically sends reports with an ID of 1, the second byte 0xff and the rest zeroed. These reports are not related to the controller state and must be dropped to avoid generating false input events. Link: http://www.spinics.net/lists/linux-bluetooth/msg63028.html Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 69586b3164094..ed0496abf573a 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1277,6 +1277,17 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, * has to be BYTE_SWAPPED before passing up to joystick interface */ if ((sc->quirks & SIXAXIS_CONTROLLER) && rd[0] == 0x01 && size == 49) { + /* + * When connected via Bluetooth the Sixaxis occasionally sends + * a report with the second byte 0xff and the rest zeroed. + * + * This report does not reflect the actual state of the + * controller must be ignored to avoid generating false input + * events. + */ + if (rd[1] == 0xff) + return -EINVAL; + swap(rd[41], rd[42]); swap(rd[43], rd[44]); swap(rd[45], rd[46]); -- GitLab From bd6906ed3d7a00d55c9bd368a640ef83bb487d1d Mon Sep 17 00:00:00 2001 From: Len Brown Date: Fri, 24 Jul 2015 10:35:23 -0400 Subject: [PATCH 1661/7006] tools/power turbostat: fix typo on DRAM column in Joules-mode < RAM_W > RAM_J Reported-by: Hubert Chrzaniuk Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 915eb2846a2d6..9655cb49c7cb8 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -372,7 +372,7 @@ void print_header(void) if (do_rapl & RAPL_GFX) outp += sprintf(outp, " GFX_J"); if (do_rapl & RAPL_DRAM) - outp += sprintf(outp, " RAM_W"); + outp += sprintf(outp, " RAM_J"); if (do_rapl & RAPL_PKG_PERF_STATUS) outp += sprintf(outp, " PKG_%%"); if (do_rapl & RAPL_DRAM_PERF_STATUS) -- GitLab From 80deaf09cb3fb3939c1d2b84610ae411cd7c6001 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 19 Jul 2015 12:32:52 +0800 Subject: [PATCH 1662/7006] ASoC: cs4265: CS4265_INT_STATUS is readable register CS4265_INT_STATUS was missed in cs4265_readable_register, fix it. The register 0x01 ~ 0x12 are readable, use CS4265_CHIP_ID ... CS4265_SPDIF_CTL2 syntax for better readability. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/cs4265.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c index d7ec4756e45bf..688c5007d157c 100644 --- a/sound/soc/codecs/cs4265.c +++ b/sound/soc/codecs/cs4265.c @@ -60,23 +60,7 @@ static const struct reg_default cs4265_reg_defaults[] = { static bool cs4265_readable_register(struct device *dev, unsigned int reg) { switch (reg) { - case CS4265_PWRCTL: - case CS4265_DAC_CTL: - case CS4265_ADC_CTL: - case CS4265_MCLK_FREQ: - case CS4265_SIG_SEL: - case CS4265_CHB_PGA_CTL: - case CS4265_CHA_PGA_CTL: - case CS4265_ADC_CTL2: - case CS4265_DAC_CHA_VOL: - case CS4265_DAC_CHB_VOL: - case CS4265_DAC_CTL2: - case CS4265_SPDIF_CTL1: - case CS4265_SPDIF_CTL2: - case CS4265_INT_MASK: - case CS4265_STATUS_MODE_MSB: - case CS4265_STATUS_MODE_LSB: - case CS4265_CHIP_ID: + case CS4265_CHIP_ID ... CS4265_SPDIF_CTL2: return true; default: return false; -- GitLab From 0a3dcb509ae7701ba3eaf470cad91827821daf41 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 24 Jul 2015 16:11:25 +0800 Subject: [PATCH 1663/7006] ASoC: Use params_width() at appropriate places Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/max98925.c | 2 +- sound/soc/codecs/pcm512x.c | 4 ++-- sound/soc/codecs/wm2200.c | 2 +- sound/soc/codecs/wm5100.c | 2 +- sound/soc/codecs/wm8776.c | 4 ++-- sound/soc/codecs/wm8996.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/sound/soc/codecs/max98925.c b/sound/soc/codecs/max98925.c index aad664225dc3a..a29e499d2f652 100644 --- a/sound/soc/codecs/max98925.c +++ b/sound/soc/codecs/max98925.c @@ -432,7 +432,7 @@ static int max98925_dai_hw_params(struct snd_pcm_substream *substream, struct snd_soc_codec *codec = dai->codec; struct max98925_priv *max98925 = snd_soc_codec_get_drvdata(codec); - switch (snd_pcm_format_width(params_format(params))) { + switch (params_width(params)) { case 16: regmap_update_bits(max98925->regmap, MAX98925_FORMAT, diff --git a/sound/soc/codecs/pcm512x.c b/sound/soc/codecs/pcm512x.c index de16429f0a431..047c48953a20c 100644 --- a/sound/soc/codecs/pcm512x.c +++ b/sound/soc/codecs/pcm512x.c @@ -1117,7 +1117,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, params_rate(params), params_channels(params)); - switch (snd_pcm_format_width(params_format(params))) { + switch (params_width(params)) { case 16: alen = PCM512x_ALEN_16; break; @@ -1132,7 +1132,7 @@ static int pcm512x_hw_params(struct snd_pcm_substream *substream, break; default: dev_err(codec->dev, "Bad frame size: %d\n", - snd_pcm_format_width(params_format(params))); + params_width(params)); return -EINVAL; } diff --git a/sound/soc/codecs/wm2200.c b/sound/soc/codecs/wm2200.c index c83083285e532..c51bc18b22ea8 100644 --- a/sound/soc/codecs/wm2200.c +++ b/sound/soc/codecs/wm2200.c @@ -1702,7 +1702,7 @@ static int wm2200_hw_params(struct snd_pcm_substream *substream, int *bclk_rates; /* Data sizes if not using TDM */ - wl = snd_pcm_format_width(params_format(params)); + wl = params_width(params); if (wl < 0) return wl; fl = snd_soc_params_to_frame_size(params); diff --git a/sound/soc/codecs/wm5100.c b/sound/soc/codecs/wm5100.c index 4c10cd88c1af6..05d25a62e2673 100644 --- a/sound/soc/codecs/wm5100.c +++ b/sound/soc/codecs/wm5100.c @@ -1408,7 +1408,7 @@ static int wm5100_hw_params(struct snd_pcm_substream *substream, base = dai->driver->base; /* Data sizes if not using TDM */ - wl = snd_pcm_format_width(params_format(params)); + wl = params_width(params); if (wl < 0) return wl; fl = snd_soc_params_to_frame_size(params); diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c index ece9b44567676..501c3349c34d4 100644 --- a/sound/soc/codecs/wm8776.c +++ b/sound/soc/codecs/wm8776.c @@ -265,7 +265,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream, } /* Set word length */ - switch (snd_pcm_format_width(params_format(params))) { + switch (params_width(params)) { case 16: iface = 0; break; @@ -280,7 +280,7 @@ static int wm8776_hw_params(struct snd_pcm_substream *substream, break; default: dev_err(codec->dev, "Unsupported sample size: %i\n", - snd_pcm_format_width(params_format(params))); + params_width(params)); return -EINVAL; } diff --git a/sound/soc/codecs/wm8996.c b/sound/soc/codecs/wm8996.c index 3dd063f682b29..04b25cbdc6a6b 100644 --- a/sound/soc/codecs/wm8996.c +++ b/sound/soc/codecs/wm8996.c @@ -1780,7 +1780,7 @@ static int wm8996_hw_params(struct snd_pcm_substream *substream, wm8996->rx_rate[dai->id] = params_rate(params); /* Needs looking at for TDM */ - bits = snd_pcm_format_width(params_format(params)); + bits = params_width(params); if (bits < 0) return bits; aifdata |= (bits << WM8996_AIF1TX_WL_SHIFT) | bits; -- GitLab From 7deef550f3a7d44c1d52a6d54f824e7e180c08ae Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:10 -0600 Subject: [PATCH 1664/7006] toshiba_acpi: Adapt /proc/acpi/toshiba/keys to TOS1900 devices Since the introduction of TOS1900 devices support to the driver, the "keys" entry under the proc directory was broken, given that it only handled TOS620X devices accordingly. This patch adapts the code to show the hotkey values of TOS1900 devices too, and in case some programs are still using that interface, hotkeys reporting should now work on these devices. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 56 +++++++++++------------------ 1 file changed, 20 insertions(+), 36 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 3ad7b1fa24ce5..c3a0c4d0c1dc4 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1499,32 +1499,10 @@ static const struct file_operations fan_proc_fops = { static int keys_proc_show(struct seq_file *m, void *v) { struct toshiba_acpi_dev *dev = m->private; - u32 hci_result; - u32 value; - - if (!dev->key_event_valid && dev->system_event_supported) { - hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); - if (hci_result == TOS_SUCCESS) { - dev->key_event_valid = 1; - dev->last_key_event = value; - } else if (hci_result == TOS_FIFO_EMPTY) { - /* Better luck next time */ - } else if (hci_result == TOS_NOT_SUPPORTED) { - /* - * This is a workaround for an unresolved issue on - * some machines where system events sporadically - * become disabled. - */ - hci_result = hci_write(dev, HCI_SYSTEM_EVENT, 1); - pr_notice("Re-enabled hotkeys\n"); - } else { - pr_err("Error reading hotkey status\n"); - return -EIO; - } - } seq_printf(m, "hotkey_ready: %d\n", dev->key_event_valid); seq_printf(m, "hotkey: 0x%04x\n", dev->last_key_event); + return 0; } @@ -2361,22 +2339,28 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev, static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) { - u32 hci_result, value; - int retries = 3; - int scancode; - if (dev->info_supported) { - scancode = toshiba_acpi_query_hotkey(dev); - if (scancode < 0) + int scancode = toshiba_acpi_query_hotkey(dev); + + if (scancode < 0) { pr_err("Failed to query hotkey event\n"); - else if (scancode != 0) + } else if (scancode != 0) { toshiba_acpi_report_hotkey(dev, scancode); + dev->key_event_valid = 1; + dev->last_key_event = scancode; + } } else if (dev->system_event_supported) { + u32 result; + u32 value; + int retries = 3; + do { - hci_result = hci_read(dev, HCI_SYSTEM_EVENT, &value); - switch (hci_result) { + result = hci_read(dev, HCI_SYSTEM_EVENT, &value); + switch (result) { case TOS_SUCCESS: toshiba_acpi_report_hotkey(dev, (int)value); + dev->key_event_valid = 1; + dev->last_key_event = value; break; case TOS_NOT_SUPPORTED: /* @@ -2384,15 +2368,15 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev) * issue on some machines where system events * sporadically become disabled. */ - hci_result = - hci_write(dev, HCI_SYSTEM_EVENT, 1); - pr_notice("Re-enabled hotkeys\n"); + result = hci_write(dev, HCI_SYSTEM_EVENT, 1); + if (result == TOS_SUCCESS) + pr_notice("Re-enabled hotkeys\n"); /* Fall through */ default: retries--; break; } - } while (retries && hci_result != TOS_FIFO_EMPTY); + } while (retries && result != TOS_FIFO_EMPTY); } } -- GitLab From fc5462f8525b47fa219452289ecb22c921c16823 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:11 -0600 Subject: [PATCH 1665/7006] toshiba_acpi: Add /dev/toshiba_acpi device There were previous attempts to "merge" the toshiba SMM module to the toshiba_acpi one, they were trying to imitate what the old toshiba module does, however, some models (TOS1900 devices) come with a "crippled" implementation and do not provide all the "features" a "genuine" Toshiba BIOS does. This patch adds a new device called toshiba_acpi, which aim is to enable userspace to access the SMM on Toshiba laptops via ACPI calls. Creating a new convenience _IOWR command to access the SCI functions by opening/closing the SCI internally to avoid buggy BIOS, while at the same time providing backwards compatibility. Older programs (and new) who wish to access the SMM on newer models can do it by pointing their path to /dev/toshiba_acpi (instead of /dev/toshiba) as the toshiba.h header was modified to reflect these changes as well as adds all the toshiba_acpi paths and command, however, it is strongly recommended to use the new IOCTL for any SCI command to avoid any buggy BIOS. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- Documentation/ioctl/ioctl-number.txt | 2 +- drivers/platform/x86/toshiba_acpi.c | 91 ++++++++++++++++++++++++++++ include/uapi/linux/toshiba.h | 32 +++++++++- 3 files changed, 121 insertions(+), 4 deletions(-) diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 611c52267d248..21d2f27c886b4 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -263,7 +263,7 @@ Code Seq#(hex) Include File Comments 's' all linux/cdk.h 't' 00-7F linux/ppp-ioctl.h 't' 80-8F linux/isdn_ppp.h -'t' 90 linux/toshiba.h +'t' 90-91 linux/toshiba.h toshiba and toshiba_acpi SMM 'u' 00-1F linux/smb_fs.h gone 'u' 20-3F linux/uvcvideo.h USB video class host driver 'v' 00-1F linux/ext2_fs.h conflict! diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index c3a0c4d0c1dc4..802577f43a233 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -50,6 +50,8 @@ #include #include #include +#include +#include #include MODULE_AUTHOR("John Belmonte"); @@ -170,6 +172,7 @@ struct toshiba_acpi_dev { struct led_classdev led_dev; struct led_classdev kbd_led; struct led_classdev eco_led; + struct miscdevice miscdev; int force_fan; int last_key_event; @@ -2239,6 +2242,81 @@ static struct attribute_group toshiba_attr_group = { .attrs = toshiba_attributes, }; +/* + * Misc device + */ +static int toshiba_acpi_smm_bridge(SMMRegisters *regs) +{ + u32 in[TCI_WORDS] = { regs->eax, regs->ebx, regs->ecx, + regs->edx, regs->esi, regs->edi }; + u32 out[TCI_WORDS]; + acpi_status status; + + status = tci_raw(toshiba_acpi, in, out); + if (ACPI_FAILURE(status)) { + pr_err("ACPI call to query SMM registers failed\n"); + return -EIO; + } + + /* Fillout the SMM struct with the TCI call results */ + regs->eax = out[0]; + regs->ebx = out[1]; + regs->ecx = out[2]; + regs->edx = out[3]; + regs->esi = out[4]; + regs->edi = out[5]; + + return 0; +} + +static long toshiba_acpi_ioctl(struct file *fp, unsigned int cmd, + unsigned long arg) +{ + SMMRegisters __user *argp = (SMMRegisters __user *)arg; + SMMRegisters regs; + int ret; + + if (!argp) + return -EINVAL; + + switch (cmd) { + case TOSH_SMM: + if (copy_from_user(®s, argp, sizeof(SMMRegisters))) + return -EFAULT; + ret = toshiba_acpi_smm_bridge(®s); + if (ret) + return ret; + if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) + return -EFAULT; + break; + case TOSHIBA_ACPI_SCI: + if (copy_from_user(®s, argp, sizeof(SMMRegisters))) + return -EFAULT; + /* Ensure we are being called with a SCI_{GET, SET} register */ + if (regs.eax != SCI_GET && regs.eax != SCI_SET) + return -EINVAL; + if (!sci_open(toshiba_acpi)) + return -EIO; + ret = toshiba_acpi_smm_bridge(®s); + sci_close(toshiba_acpi); + if (ret) + return ret; + if (copy_to_user(argp, ®s, sizeof(SMMRegisters))) + return -EFAULT; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct file_operations toshiba_acpi_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = toshiba_acpi_ioctl, + .llseek = noop_llseek, +}; + /* * Hotkeys */ @@ -2540,6 +2618,8 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev) { struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); + misc_deregister(&dev->miscdev); + remove_toshiba_proc_entries(dev); if (dev->sysfs_created) @@ -2611,6 +2691,17 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) return -ENOMEM; dev->acpi_dev = acpi_dev; dev->method_hci = hci_method; + dev->miscdev.minor = MISC_DYNAMIC_MINOR; + dev->miscdev.name = "toshiba_acpi"; + dev->miscdev.fops = &toshiba_acpi_fops; + + ret = misc_register(&dev->miscdev); + if (ret) { + pr_err("Failed to register miscdevice\n"); + kfree(dev); + return ret; + } + acpi_dev->driver_data = dev; dev_set_drvdata(&acpi_dev->dev, dev); diff --git a/include/uapi/linux/toshiba.h b/include/uapi/linux/toshiba.h index e9bef5b2f91eb..c58bf4b5bb266 100644 --- a/include/uapi/linux/toshiba.h +++ b/include/uapi/linux/toshiba.h @@ -1,6 +1,7 @@ /* toshiba.h -- Linux driver for accessing the SMM on Toshiba laptops * * Copyright (c) 1996-2000 Jonathan A. Buzzard (jonathan@buzzard.org.uk) + * Copyright (c) 2015 Azael Avalos * * Thanks to Juergen Heinzl for the pointers * on making sure the structure is aligned and packed. @@ -20,9 +21,18 @@ #ifndef _UAPI_LINUX_TOSHIBA_H #define _UAPI_LINUX_TOSHIBA_H -#define TOSH_PROC "/proc/toshiba" -#define TOSH_DEVICE "/dev/toshiba" -#define TOSH_SMM _IOWR('t', 0x90, int) /* broken: meant 24 bytes */ +/* + * Toshiba modules paths + */ + +#define TOSH_PROC "/proc/toshiba" +#define TOSH_DEVICE "/dev/toshiba" +#define TOSHIBA_ACPI_PROC "/proc/acpi/toshiba" +#define TOSHIBA_ACPI_DEVICE "/dev/toshiba_acpi" + +/* + * Toshiba SMM structure + */ typedef struct { unsigned int eax; @@ -33,5 +43,21 @@ typedef struct { unsigned int edi __attribute__ ((packed)); } SMMRegisters; +/* + * IOCTLs (0x90 - 0x91) + */ + +#define TOSH_SMM _IOWR('t', 0x90, SMMRegisters) +/* + * Convenience toshiba_acpi command. + * + * The System Configuration Interface (SCI) is opened/closed internally + * to avoid userspace of buggy BIOSes. + * + * The toshiba_acpi module checks whether the eax register is set with + * SCI_GET (0xf300) or SCI_SET (0xf400), returning -EINVAL if not. + */ +#define TOSHIBA_ACPI_SCI _IOWR('t', 0x91, SMMRegisters) + #endif /* _UAPI_LINUX_TOSHIBA_H */ -- GitLab From a88bc06e5aec4984f5bf01c6d410a0939134f737 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:12 -0600 Subject: [PATCH 1666/7006] toshiba_acpi: Avoid registering input device on WMI event laptops Commit f11f999e9890 ("toshiba_acpi: Refuse to load on machines with buggy INFO implementations") denied loading on laptops with a WMI Event GUID given that such laptops manage the hotkeys via that interface, however, such laptops have a working Toshiba Configuration Interface (TCI), and thus, such commit denied several supported features. This patch avoids registering the input device and ignores all hotkey events on laptops with such WMI Event GUID, making the supported features found in those laptops to work. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 802577f43a233..48b16b323c890 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -2466,6 +2466,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) u32 hci_result; int error; + if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { + pr_info("WMI event detected, hotkeys will not be monitored\n"); + return 0; + } + error = toshiba_acpi_enable_hotkeys(dev); if (error) return error; @@ -2813,6 +2818,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) switch (event) { case 0x80: /* Hotkeys and some system events */ + /* + * Machines with this WMI GUID aren't supported due to bugs in + * their AML. + * + * Return silently to avoid triggering a netlink event. + */ + if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) + return; toshiba_acpi_process_hotkeys(dev); break; case 0x81: /* Dock events */ @@ -2899,14 +2912,6 @@ static int __init toshiba_acpi_init(void) { int ret; - /* - * Machines with this WMI guid aren't supported due to bugs in - * their AML. This check relies on wmi initializing before - * toshiba_acpi to guarantee guids have been identified. - */ - if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) - return -ENODEV; - toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); if (!toshiba_proc_dir) { pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); -- GitLab From 695f6060903cefa08ffb78433136f51ac0f94488 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 18:09:13 -0600 Subject: [PATCH 1667/7006] toshiba_acpi: Transflective backlight updates This patch changes the tr function second parameter from bool to u32, to be on par with the rest of the TCI functions of the driver, and the code was updated accordingly. Also, the check for translective support was moved to the *add function, as the {__get, set}_lcd_brightness functions make use of it. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 30 +++++++++++------------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 48b16b323c890..649786de4a79d 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1187,22 +1187,17 @@ static int toshiba_hotkey_event_type_get(struct toshiba_acpi_dev *dev, } /* Transflective Backlight */ -static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) +static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) { - u32 hci_result; - u32 status; + u32 hci_result = hci_read(dev, HCI_TR_BACKLIGHT, status); - hci_result = hci_read(dev, HCI_TR_BACKLIGHT, &status); - *enabled = !status; return hci_result == TOS_SUCCESS ? 0 : -EIO; } -static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) +static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 status) { - u32 hci_result; - u32 value = !enable; + u32 hci_result = hci_write(dev, HCI_TR_BACKLIGHT, !status); - hci_result = hci_write(dev, HCI_TR_BACKLIGHT, value); return hci_result == TOS_SUCCESS ? 0 : -EIO; } @@ -1216,12 +1211,11 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) int brightness = 0; if (dev->tr_backlight_supported) { - bool enabled; - int ret = get_tr_backlight_status(dev, &enabled); + int ret = get_tr_backlight_status(dev, &value); if (ret) return ret; - if (enabled) + if (value) return 0; brightness++; } @@ -1271,8 +1265,7 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) u32 hci_result; if (dev->tr_backlight_supported) { - bool enable = !value; - int ret = set_tr_backlight_status(dev, enable); + int ret = set_tr_backlight_status(dev, !value); if (ret) return ret; @@ -2563,7 +2556,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) struct backlight_properties props; int brightness; int ret; - bool enabled; /* * Some machines don't support the backlight methods at all, and @@ -2580,10 +2572,6 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) return 0; } - /* Determine whether or not BIOS supports transflective backlight */ - ret = get_tr_backlight_status(dev, &enabled); - dev->tr_backlight_supported = !ret; - /* * Tell acpi-video-detect code to prefer vendor backlight on all * systems with transflective backlight and on dmi matched systems. @@ -2723,6 +2711,10 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) if (toshiba_acpi_setup_keyboard(dev)) pr_info("Unable to activate hotkeys\n"); + /* Determine whether or not BIOS supports transflective backlight */ + ret = get_tr_backlight_status(dev, &dummy); + dev->tr_backlight_supported = !ret; + ret = toshiba_acpi_setup_backlight(dev); if (ret) goto error; -- GitLab From d7e4f2e2ca392bce468718bcbba808108d81d501 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 19:37:47 -0600 Subject: [PATCH 1668/7006] toshiba_acpi: Remove unused wireless defines Commit 2b74103547b4 ("toshiba_acpi: Remove bluetooth rfkill code") removed bluetooth related code, however, the wireless defines were not removed and are unused. This patch simply removes those defines as there is no code using them. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 649786de4a79d..90d8cb1c2e27a 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -113,7 +113,6 @@ MODULE_LICENSE("GPL"); #define HCI_VIDEO_OUT 0x001c #define HCI_HOTKEY_EVENT 0x001e #define HCI_LCD_BRIGHTNESS 0x002a -#define HCI_WIRELESS 0x0056 #define HCI_ACCELEROMETER 0x006d #define HCI_KBD_ILLUMINATION 0x0095 #define HCI_ECO_MODE 0x0097 @@ -142,10 +141,6 @@ MODULE_LICENSE("GPL"); #define HCI_VIDEO_OUT_LCD 0x1 #define HCI_VIDEO_OUT_CRT 0x2 #define HCI_VIDEO_OUT_TV 0x4 -#define HCI_WIRELESS_KILL_SWITCH 0x01 -#define HCI_WIRELESS_BT_PRESENT 0x0f -#define HCI_WIRELESS_BT_ATTACH 0x40 -#define HCI_WIRELESS_BT_POWER 0x80 #define SCI_KBD_MODE_MASK 0x1f #define SCI_KBD_MODE_FNZ 0x1 #define SCI_KBD_MODE_AUTO 0x2 -- GitLab From d50c9005d32b4eda6e11f7ec4f1b00a93088e0ca Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 19:37:46 -0600 Subject: [PATCH 1669/7006] toshiba_acpi: Reorder toshiba_acpi_alt_keymap entries This patch simply reorders the entries found in the new keymap by ascending order, this is simply a cosmetic change, no functionality was modified. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 90d8cb1c2e27a..6013a11caeea8 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -246,16 +246,16 @@ static const struct key_entry toshiba_acpi_keymap[] = { }; static const struct key_entry toshiba_acpi_alt_keymap[] = { - { KE_KEY, 0x157, { KEY_MUTE } }, { KE_KEY, 0x102, { KEY_ZOOMOUT } }, { KE_KEY, 0x103, { KEY_ZOOMIN } }, { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } }, { KE_KEY, 0x139, { KEY_ZOOMRESET } }, - { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x13c, { KEY_BRIGHTNESSDOWN } }, { KE_KEY, 0x13d, { KEY_BRIGHTNESSUP } }, - { KE_KEY, 0x158, { KEY_WLAN } }, + { KE_KEY, 0x13e, { KEY_SWITCHVIDEOMODE } }, { KE_KEY, 0x13f, { KEY_TOUCHPAD_TOGGLE } }, + { KE_KEY, 0x157, { KEY_MUTE } }, + { KE_KEY, 0x158, { KEY_WLAN } }, { KE_END, 0 }, }; -- GitLab From 1e574dbfadafd9fd1f2a414efb731d7538277e71 Mon Sep 17 00:00:00 2001 From: Azael Avalos Date: Wed, 22 Jul 2015 19:37:49 -0600 Subject: [PATCH 1670/7006] toshiba_acpi: Change some variables to avoid warnings from ninja-check This patch changes some variables to avoid warnings from ninja-check. We are basically moving some variables inside the conditionals where such variables are being used, and we are checking the returned values of some others. Signed-off-by: Azael Avalos Signed-off-by: Darren Hart --- drivers/platform/x86/toshiba_acpi.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 6013a11caeea8..3bfdfddc38ac3 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c @@ -1651,7 +1651,6 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, { struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); int mode; - int time; int ret; @@ -1682,7 +1681,7 @@ static ssize_t kbd_backlight_mode_store(struct device *dev, /* Only make a change if the actual mode has changed */ if (toshiba->kbd_mode != mode) { /* Shift the time to "base time" (0x3c0000 == 60 seconds) */ - time = toshiba->kbd_time << HCI_MISC_SHIFT; + int time = toshiba->kbd_time << HCI_MISC_SHIFT; /* OR the "base time" to the actual method format */ if (toshiba->kbd_type == 1) { @@ -2856,10 +2855,14 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event) static int toshiba_acpi_suspend(struct device *device) { struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); - u32 result; - if (dev->hotkey_dev) + if (dev->hotkey_dev) { + u32 result; + result = hci_write(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE); + if (result != TOS_SUCCESS) + pr_info("Unable to disable hotkeys\n"); + } return 0; } @@ -2867,10 +2870,10 @@ static int toshiba_acpi_suspend(struct device *device) static int toshiba_acpi_resume(struct device *device) { struct toshiba_acpi_dev *dev = acpi_driver_data(to_acpi_device(device)); - int error; if (dev->hotkey_dev) { - error = toshiba_acpi_enable_hotkeys(dev); + int error = toshiba_acpi_enable_hotkeys(dev); + if (error) pr_info("Unable to re-enable hotkeys\n"); } -- GitLab From 454d3a2500a4eb33be85dde3bfba9e5f6b5efadc Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 22 Jul 2015 17:59:11 +0200 Subject: [PATCH 1671/7006] cpufreq: Remove cpufreq_rwsem cpufreq_rwsem was introduced in commit 6eed9404ab3c4 ("cpufreq: Use rwsem for protecting critical sections) in order to replace try_module_get() on the cpu-freq driver. That try_module_get() worked well until the refcount was so heavily used that module removal became more or less impossible. Though when looking at the various (undocumented) protection mechanisms in that code, the randomly sprinkeled around cpufreq_rwsem locking sites are superfluous. The policy, which is acquired in cpufreq_cpu_get() and released in cpufreq_cpu_put() is sufficiently protected already. cpufreq_cpu_get(cpu) /* Protects against concurrent driver removal */ read_lock_irqsave(&cpufreq_driver_lock, flags); policy = per_cpu(cpufreq_cpu_data, cpu); kobject_get(&policy->kobj); read_unlock_irqrestore(&cpufreq_driver_lock, flags); The reference on the policy serializes versus module unload already: cpufreq_unregister_driver() subsys_interface_unregister() __cpufreq_remove_dev_finish() per_cpu(cpufreq_cpu_data) = NULL; cpufreq_policy_put_kobj() If there is a reference held on the policy, i.e. obtained prior to the unregister call, then cpufreq_policy_put_kobj() will wait until that reference is dropped. So once subsys_interface_unregister() returns there is no policy pointer in flight and no new reference can be obtained. So that rwsem protection is useless. The other usage of cpufreq_rwsem in show()/store() of the sysfs interface is redundant as well because sysfs already does the proper kobject_get()/put() pairs. That leaves CPU hotplug versus module removal. The current down_write() around the write_lock() in cpufreq_unregister_driver() is silly at best as it protects actually nothing. The trivial solution to this is to prevent hotplug across cpufreq_unregister_driver completely. Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 41 +++------------------------------------ 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a3e8fb61cbccc..febda462681c6 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -112,12 +112,6 @@ static inline bool has_target(void) return cpufreq_driver->target_index || cpufreq_driver->target; } -/* - * rwsem to guarantee that cpufreq driver module doesn't unload during critical - * sections - */ -static DECLARE_RWSEM(cpufreq_rwsem); - /* internal prototypes */ static int __cpufreq_governor(struct cpufreq_policy *policy, unsigned int event); @@ -277,10 +271,6 @@ EXPORT_SYMBOL_GPL(cpufreq_generic_get); * If corresponding call cpufreq_cpu_put() isn't made, the policy wouldn't be * freed as that depends on the kobj count. * - * It also takes a read-lock of 'cpufreq_rwsem' and doesn't put it back if a - * valid policy is found. This is done to make sure the driver doesn't get - * unregistered while the policy is being used. - * * Return: A valid policy on success, otherwise NULL on failure. */ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) @@ -291,9 +281,6 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) if (WARN_ON(cpu >= nr_cpu_ids)) return NULL; - if (!down_read_trylock(&cpufreq_rwsem)) - return NULL; - /* get the cpufreq driver */ read_lock_irqsave(&cpufreq_driver_lock, flags); @@ -306,9 +293,6 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu) read_unlock_irqrestore(&cpufreq_driver_lock, flags); - if (!policy) - up_read(&cpufreq_rwsem); - return policy; } EXPORT_SYMBOL_GPL(cpufreq_cpu_get); @@ -320,13 +304,10 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get); * * This decrements the kobject reference count incremented earlier by calling * cpufreq_cpu_get(). - * - * It also drops the read-lock of 'cpufreq_rwsem' taken at cpufreq_cpu_get(). */ void cpufreq_cpu_put(struct cpufreq_policy *policy) { kobject_put(&policy->kobj); - up_read(&cpufreq_rwsem); } EXPORT_SYMBOL_GPL(cpufreq_cpu_put); @@ -851,9 +832,6 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) struct freq_attr *fattr = to_attr(attr); ssize_t ret; - if (!down_read_trylock(&cpufreq_rwsem)) - return -EINVAL; - down_read(&policy->rwsem); if (fattr->show) @@ -862,7 +840,6 @@ static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf) ret = -EIO; up_read(&policy->rwsem); - up_read(&cpufreq_rwsem); return ret; } @@ -879,9 +856,6 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, if (!cpu_online(policy->cpu)) goto unlock; - if (!down_read_trylock(&cpufreq_rwsem)) - goto unlock; - down_write(&policy->rwsem); /* Updating inactive policies is invalid, so avoid doing that. */ @@ -897,8 +871,6 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, unlock_policy_rwsem: up_write(&policy->rwsem); - - up_read(&cpufreq_rwsem); unlock: put_online_cpus(); @@ -1261,15 +1233,11 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) if (cpu_is_offline(cpu)) return add_cpu_dev_symlink(per_cpu(cpufreq_cpu_data, cpu), cpu); - if (!down_read_trylock(&cpufreq_rwsem)) - return 0; - /* Check if this CPU already has a policy to manage it */ policy = per_cpu(cpufreq_cpu_data, cpu); if (policy && !policy_is_inactive(policy)) { WARN_ON(!cpumask_test_cpu(cpu, policy->related_cpus)); ret = cpufreq_add_policy_cpu(policy, cpu, dev); - up_read(&cpufreq_rwsem); return ret; } @@ -1395,8 +1363,6 @@ static int cpufreq_add_dev(struct device *dev, struct subsys_interface *sif) kobject_uevent(&policy->kobj, KOBJ_ADD); - up_read(&cpufreq_rwsem); - /* Callback for handling stuff after policy is ready */ if (cpufreq_driver->ready) cpufreq_driver->ready(policy); @@ -1416,8 +1382,6 @@ out_exit_policy: out_free_policy: cpufreq_policy_free(policy, recover_policy); out_release_rwsem: - up_read(&cpufreq_rwsem); - return ret; } @@ -2604,19 +2568,20 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver) pr_debug("unregistering driver %s\n", driver->name); + /* Protect against concurrent cpu hotplug */ + get_online_cpus(); subsys_interface_unregister(&cpufreq_interface); if (cpufreq_boost_supported()) cpufreq_sysfs_remove_file(&boost.attr); unregister_hotcpu_notifier(&cpufreq_cpu_notifier); - down_write(&cpufreq_rwsem); write_lock_irqsave(&cpufreq_driver_lock, flags); cpufreq_driver = NULL; write_unlock_irqrestore(&cpufreq_driver_lock, flags); - up_write(&cpufreq_rwsem); + put_online_cpus(); return 0; } -- GitLab From 40386217cd7bc38908d65852c0af5cffe04bf7f4 Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Tue, 14 Jul 2015 20:01:48 -0700 Subject: [PATCH 1672/7006] powerpc/perf/hv-24x7: Whitespace - fix parameter alignment Fix parameter alignment to be consistent with coding style. Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Michael Ellerman --- arch/powerpc/perf/hv-24x7.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index df956295c2a7a..9d73c693e7924 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -416,7 +416,7 @@ out_val: } static struct attribute *event_to_desc_attr(struct hv_24x7_event_data *event, - int nonce) + int nonce) { int nl, dl; char *name = event_name(event, &nl); @@ -444,7 +444,7 @@ event_to_long_desc_attr(struct hv_24x7_event_data *event, int nonce) } static ssize_t event_data_to_attrs(unsigned ix, struct attribute **attrs, - struct hv_24x7_event_data *event, int nonce) + struct hv_24x7_event_data *event, int nonce) { unsigned i; @@ -512,7 +512,7 @@ static int memord(const void *d1, size_t s1, const void *d2, size_t s2) } static int ev_uniq_ord(const void *v1, size_t s1, unsigned d1, const void *v2, - size_t s2, unsigned d2) + size_t s2, unsigned d2) { int r = memord(v1, s1, v2, s2); @@ -526,7 +526,7 @@ static int ev_uniq_ord(const void *v1, size_t s1, unsigned d1, const void *v2, } static int event_uniq_add(struct rb_root *root, const char *name, int nl, - unsigned domain) + unsigned domain) { struct rb_node **new = &(root->rb_node), *parent = NULL; struct event_uniq *data; @@ -650,8 +650,8 @@ static ssize_t catalog_event_len_validate(struct hv_24x7_event_data *event, #define MAX_4K (SIZE_MAX / 4096) static int create_events_from_catalog(struct attribute ***events_, - struct attribute ***event_descs_, - struct attribute ***event_long_descs_) + struct attribute ***event_descs_, + struct attribute ***event_long_descs_) { unsigned long hret; size_t catalog_len, catalog_page_len, event_entry_count, @@ -1008,8 +1008,8 @@ static const struct attribute_group *attr_groups[] = { }; static void log_24x7_hcall(struct hv_24x7_request_buffer *request_buffer, - struct hv_24x7_data_result_buffer *result_buffer, - unsigned long ret) + struct hv_24x7_data_result_buffer *result_buffer, + unsigned long ret) { struct hv_24x7_request *req; @@ -1026,7 +1026,7 @@ static void log_24x7_hcall(struct hv_24x7_request_buffer *request_buffer, * Start the process for a new H_GET_24x7_DATA hcall. */ static void init_24x7_request(struct hv_24x7_request_buffer *request_buffer, - struct hv_24x7_data_result_buffer *result_buffer) + struct hv_24x7_data_result_buffer *result_buffer) { memset(request_buffer, 0, 4096); @@ -1041,7 +1041,7 @@ static void init_24x7_request(struct hv_24x7_request_buffer *request_buffer, * by 'init_24x7_request()' and 'add_event_to_24x7_request()'. */ static int make_24x7_request(struct hv_24x7_request_buffer *request_buffer, - struct hv_24x7_data_result_buffer *result_buffer) + struct hv_24x7_data_result_buffer *result_buffer) { unsigned long ret; -- GitLab From 465345ca387ed491c467689ec2ac1ecbe1d84c3d Mon Sep 17 00:00:00 2001 From: Sukadev Bhattiprolu Date: Tue, 14 Jul 2015 20:01:49 -0700 Subject: [PATCH 1673/7006] powerpc/perf/hv-24x7: Simplify extracting counter from result buffer Simplify code that extracts a 24x7 counter from the HCALL's result buffer. Suggested-by: Joe Perches Signed-off-by: Sukadev Bhattiprolu Signed-off-by: Michael Ellerman --- arch/powerpc/perf/hv-24x7.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/powerpc/perf/hv-24x7.c b/arch/powerpc/perf/hv-24x7.c index 9d73c693e7924..527c8b98e97ee 100644 --- a/arch/powerpc/perf/hv-24x7.c +++ b/arch/powerpc/perf/hv-24x7.c @@ -1104,7 +1104,6 @@ static unsigned long single_24x7_request(struct perf_event *event, u64 *count) unsigned long ret; struct hv_24x7_request_buffer *request_buffer; struct hv_24x7_data_result_buffer *result_buffer; - struct hv_24x7_result *resb; BUILD_BUG_ON(sizeof(*request_buffer) > 4096); BUILD_BUG_ON(sizeof(*result_buffer) > 4096); @@ -1125,8 +1124,7 @@ static unsigned long single_24x7_request(struct perf_event *event, u64 *count) } /* process result from hcall */ - resb = &result_buffer->results[0]; - *count = be64_to_cpu(resb->elements[0].element_data[0]); + *count = be64_to_cpu(result_buffer->results[0].elements[0].element_data[0]); out: put_cpu_var(hv_24x7_reqb); -- GitLab From a155a5db9389c4088c0901e665002332f2503660 Mon Sep 17 00:00:00 2001 From: Sriharsha Basavapatna Date: Wed, 22 Jul 2015 11:15:12 +0530 Subject: [PATCH 1674/7006] be2net: support ndo_get_phys_port_id() Add be_get_phys_port_id() function to report physical port id. The port id should be unique across different be2net devices in the system. We use the chip serial number along with the physical port number for this. Signed-off-by: Sriharsha Basavapatna Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 3 +++ drivers/net/ethernet/emulex/benet/be_cmds.c | 7 ++++++- drivers/net/ethernet/emulex/benet/be_cmds.h | 8 +++++--- drivers/net/ethernet/emulex/benet/be_main.c | 22 +++++++++++++++++++++ 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index cb5777bb74292..8cd384d0e38ae 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -105,6 +105,8 @@ #define MAX_VFS 30 /* Max VFs supported by BE3 FW */ #define FW_VER_LEN 32 +#define CNTL_SERIAL_NUM_WORDS 8 /* Controller serial number words */ +#define CNTL_SERIAL_NUM_WORD_SZ (sizeof(u16)) /* Byte-sz of serial num word */ #define RSS_INDIR_TABLE_LEN 128 #define RSS_HASH_KEY_LEN 40 @@ -590,6 +592,7 @@ struct be_adapter { struct rss_info rss_info; /* Filters for packets that need to be sent to BMC */ u32 bmc_filt_mask; + u16 serial_num[CNTL_SERIAL_NUM_WORDS]; }; #define be_physfn(adapter) (!adapter->virtfn) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index ecad46f796539..3be1fbdcdd021 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -2852,10 +2852,11 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) struct be_mcc_wrb *wrb; struct be_cmd_req_cntl_attribs *req; struct be_cmd_resp_cntl_attribs *resp; - int status; + int status, i; int payload_len = max(sizeof(*req), sizeof(*resp)); struct mgmt_controller_attrib *attribs; struct be_dma_mem attribs_cmd; + u32 *serial_num; if (mutex_lock_interruptible(&adapter->mbox_lock)) return -1; @@ -2886,6 +2887,10 @@ int be_cmd_get_cntl_attributes(struct be_adapter *adapter) if (!status) { attribs = attribs_cmd.va + sizeof(struct be_cmd_resp_hdr); adapter->hba_port_num = attribs->hba_attribs.phy_port; + serial_num = attribs->hba_attribs.controller_serial_number; + for (i = 0; i < CNTL_SERIAL_NUM_WORDS; i++) + adapter->serial_num[i] = le32_to_cpu(serial_num[i]) & + (BIT_MASK(16) - 1); } err: diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h index a4479f7488d3c..36d835bd5f3c0 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.h +++ b/drivers/net/ethernet/emulex/benet/be_cmds.h @@ -1637,10 +1637,12 @@ struct be_cmd_req_set_qos { struct mgmt_hba_attribs { u32 rsvd0[24]; u8 controller_model_number[32]; - u32 rsvd1[79]; - u8 rsvd2[3]; + u32 rsvd1[16]; + u32 controller_serial_number[8]; + u32 rsvd2[55]; + u8 rsvd3[3]; u8 phy_port; - u32 rsvd3[13]; + u32 rsvd4[13]; } __packed; struct mgmt_controller_attrib { diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index c996dd76f5461..5e92db8947d99 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -5219,6 +5219,27 @@ static netdev_features_t be_features_check(struct sk_buff *skb, } #endif +static int be_get_phys_port_id(struct net_device *dev, + struct netdev_phys_item_id *ppid) +{ + int i, id_len = CNTL_SERIAL_NUM_WORDS * CNTL_SERIAL_NUM_WORD_SZ + 1; + struct be_adapter *adapter = netdev_priv(dev); + u8 *id; + + if (MAX_PHYS_ITEM_ID_LEN < id_len) + return -ENOSPC; + + ppid->id[0] = adapter->hba_port_num + 1; + id = &ppid->id[1]; + for (i = CNTL_SERIAL_NUM_WORDS - 1; i >= 0; + i--, id += CNTL_SERIAL_NUM_WORD_SZ) + memcpy(id, &adapter->serial_num[i], CNTL_SERIAL_NUM_WORD_SZ); + + ppid->id_len = id_len; + + return 0; +} + static const struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@ -5249,6 +5270,7 @@ static const struct net_device_ops be_netdev_ops = { .ndo_del_vxlan_port = be_del_vxlan_port, .ndo_features_check = be_features_check, #endif + .ndo_get_phys_port_id = be_get_phys_port_id, }; static void be_netdev_init(struct net_device *netdev) -- GitLab From 6ca91c604074788dfeb7dd714e74f0ad6bea8a77 Mon Sep 17 00:00:00 2001 From: "Rosen, Rami" Date: Wed, 22 Jul 2015 07:57:02 +0300 Subject: [PATCH 1675/7006] bridge: Fix setting a flag in br_fill_ifvlaninfo_range(). This patch fixes setting of vinfo.flags in the br_fill_ifvlaninfo_range() method. The assignment of vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN has no effect and is unneeded, as vinfo.flags value is overriden by the immediately following vinfo.flags = flags | BRIDGE_VLAN_INFO_RANGE_END assignement. Signed-off-by: Rami Rosen Acked-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/bridge/br_netlink.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index 364bdc98bd9be..793d247ac2ca2 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -164,8 +164,6 @@ static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start, sizeof(vinfo), &vinfo)) goto nla_put_failure; - vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN; - vinfo.vid = vid_end; vinfo.flags = flags | BRIDGE_VLAN_INFO_RANGE_END; if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO, -- GitLab From f81309067ff2d84788316c513a415f6bb8c9171f Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 1 Jun 2015 23:44:46 +0100 Subject: [PATCH 1676/7006] ARM: move heavy barrier support out of line The existing memory barrier macro causes a significant amount of code to be inserted inline at every call site. For example, in gpio_set_irq_type(), we have this for mb(): c0344c08: f57ff04e dsb st c0344c0c: e59f8190 ldr r8, [pc, #400] ; c0344da4 c0344c10: e3590004 cmp r9, #4 c0344c14: e5983014 ldr r3, [r8, #20] c0344c18: 0a000054 beq c0344d70 c0344c1c: e3530000 cmp r3, #0 c0344c20: 0a000004 beq c0344c38 c0344c24: e50b2030 str r2, [fp, #-48] ; 0xffffffd0 c0344c28: e50bc034 str ip, [fp, #-52] ; 0xffffffcc c0344c2c: e12fff33 blx r3 c0344c30: e51bc034 ldr ip, [fp, #-52] ; 0xffffffcc c0344c34: e51b2030 ldr r2, [fp, #-48] ; 0xffffffd0 c0344c38: e5963004 ldr r3, [r6, #4] Moving the outer_cache_sync() call out of line reduces the impact of the barrier: c0344968: f57ff04e dsb st c034496c: e35a0004 cmp sl, #4 c0344970: e50b2030 str r2, [fp, #-48] ; 0xffffffd0 c0344974: 0a000044 beq c0344a8c c0344978: ebf363dd bl c001d8f4 c034497c: e5953004 ldr r3, [r5, #4] This should reduce the cache footprint of this code. Overall, this results in a reduction of around 20K in the kernel size: text data bss dec hex filename 10773970 667392 10369656 21811018 14ccf4a ../build/imx6/vmlinux-old 10754219 667392 10369656 21791267 14c8223 ../build/imx6/vmlinux-new Another advantage to this approach is that we can finally resolve the issue of SoCs which have their own memory barrier requirements within multiplatform kernels (such as OMAP.) Here, the bus interconnects need additional handling to ensure that writes become visible in the correct order (eg, between dma_map() operations, writes to DMA coherent memory, and MMIO accesses.) Acked-by: Tony Lindgren Acked-by: Richard Woodruff Signed-off-by: Russell King --- arch/arm/include/asm/barrier.h | 12 +++++++++--- arch/arm/include/asm/outercache.h | 17 ----------------- arch/arm/kernel/irq.c | 1 + arch/arm/mach-mmp/pm-pxa910.c | 1 + arch/arm/mach-prima2/pm.c | 1 + arch/arm/mach-ux500/cache-l2x0.c | 1 + arch/arm/mm/Kconfig | 4 ++++ arch/arm/mm/flush.c | 11 +++++++++++ 8 files changed, 28 insertions(+), 20 deletions(-) diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h index 6c2327e1c7323..fea99b0e20878 100644 --- a/arch/arm/include/asm/barrier.h +++ b/arch/arm/include/asm/barrier.h @@ -2,7 +2,6 @@ #define __ASM_BARRIER_H #ifndef __ASSEMBLY__ -#include #define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); @@ -37,12 +36,19 @@ #define dmb(x) __asm__ __volatile__ ("" : : : "memory") #endif +#ifdef CONFIG_ARM_HEAVY_MB +extern void arm_heavy_mb(void); +#define __arm_heavy_mb(x...) do { dsb(x); arm_heavy_mb(); } while (0) +#else +#define __arm_heavy_mb(x...) dsb(x) +#endif + #ifdef CONFIG_ARCH_HAS_BARRIERS #include #elif defined(CONFIG_ARM_DMA_MEM_BUFFERABLE) || defined(CONFIG_SMP) -#define mb() do { dsb(); outer_sync(); } while (0) +#define mb() __arm_heavy_mb() #define rmb() dsb() -#define wmb() do { dsb(st); outer_sync(); } while (0) +#define wmb() __arm_heavy_mb(st) #define dma_rmb() dmb(osh) #define dma_wmb() dmb(oshst) #else diff --git a/arch/arm/include/asm/outercache.h b/arch/arm/include/asm/outercache.h index 563b92fc2f41c..c2bf24f40177d 100644 --- a/arch/arm/include/asm/outercache.h +++ b/arch/arm/include/asm/outercache.h @@ -129,21 +129,4 @@ static inline void outer_resume(void) { } #endif -#ifdef CONFIG_OUTER_CACHE_SYNC -/** - * outer_sync - perform a sync point for outer cache - * - * Ensure that all outer cache operations are complete and any store - * buffers are drained. - */ -static inline void outer_sync(void) -{ - if (outer_cache.sync) - outer_cache.sync(); -} -#else -static inline void outer_sync(void) -{ } -#endif - #endif /* __ASM_OUTERCACHE_H */ diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c index 350f188c92d29..b96c8ed1723ab 100644 --- a/arch/arm/kernel/irq.c +++ b/arch/arm/kernel/irq.c @@ -39,6 +39,7 @@ #include #include +#include #include #include #include diff --git a/arch/arm/mach-mmp/pm-pxa910.c b/arch/arm/mach-mmp/pm-pxa910.c index 04c9daf9f8d76..7db5870d127fc 100644 --- a/arch/arm/mach-mmp/pm-pxa910.c +++ b/arch/arm/mach-mmp/pm-pxa910.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/arm/mach-prima2/pm.c b/arch/arm/mach-prima2/pm.c index d99d08eeb9664..83e94c95e3144 100644 --- a/arch/arm/mach-prima2/pm.c +++ b/arch/arm/mach-prima2/pm.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/arch/arm/mach-ux500/cache-l2x0.c b/arch/arm/mach-ux500/cache-l2x0.c index 7557bede7ae67..780bd13cd7e3d 100644 --- a/arch/arm/mach-ux500/cache-l2x0.c +++ b/arch/arm/mach-ux500/cache-l2x0.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "db8500-regs.h" diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig index 7c6b976ab8d39..df7537f12469a 100644 --- a/arch/arm/mm/Kconfig +++ b/arch/arm/mm/Kconfig @@ -883,6 +883,7 @@ config OUTER_CACHE config OUTER_CACHE_SYNC bool + select ARM_HEAVY_MB help The outer cache has a outer_cache_fns.sync function pointer that can be used to drain the write buffer of the outer cache. @@ -1031,6 +1032,9 @@ config ARCH_HAS_BARRIERS This option allows the use of custom mandatory barriers included via the mach/barriers.h file. +config ARM_HEAVY_MB + bool + config ARCH_SUPPORTS_BIG_ENDIAN bool help diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index 34b66af516ea9..ce6c2960d5ace 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -21,6 +21,17 @@ #include "mm.h" +#ifdef CONFIG_ARM_HEAVY_MB +void arm_heavy_mb(void) +{ +#ifdef CONFIG_OUTER_CACHE_SYNC + if (outer_cache.sync) + outer_cache.sync(); +#endif +} +EXPORT_SYMBOL(arm_heavy_mb); +#endif + #ifdef CONFIG_CPU_CACHE_VIPT static void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) -- GitLab From 4e1f8a6f1d978f033f1751e2887b3a69fab3f878 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 3 Jun 2015 13:10:16 +0100 Subject: [PATCH 1677/7006] ARM: add soc memory barrier extension Add an extension to the heavy barrier code to allow a SoC specific memory barrier function to be provided. This is needed for platforms where the interconnect has weak ordering, and thus needs assistance to ensure that memory writes are properly visible in the correct order to other parts of the system. Acked-by: Tony Lindgren Acked-by: Richard Woodruff Signed-off-by: Russell King --- arch/arm/include/asm/barrier.h | 1 + arch/arm/mm/flush.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/arch/arm/include/asm/barrier.h b/arch/arm/include/asm/barrier.h index fea99b0e20878..3d8f1d3ad9a76 100644 --- a/arch/arm/include/asm/barrier.h +++ b/arch/arm/include/asm/barrier.h @@ -37,6 +37,7 @@ #endif #ifdef CONFIG_ARM_HEAVY_MB +extern void (*soc_mb)(void); extern void arm_heavy_mb(void); #define __arm_heavy_mb(x...) do { dsb(x); arm_heavy_mb(); } while (0) #else diff --git a/arch/arm/mm/flush.c b/arch/arm/mm/flush.c index ce6c2960d5ace..1ec8e7590fc68 100644 --- a/arch/arm/mm/flush.c +++ b/arch/arm/mm/flush.c @@ -22,12 +22,16 @@ #include "mm.h" #ifdef CONFIG_ARM_HEAVY_MB +void (*soc_mb)(void); + void arm_heavy_mb(void) { #ifdef CONFIG_OUTER_CACHE_SYNC if (outer_cache.sync) outer_cache.sync(); #endif + if (soc_mb) + soc_mb(); } EXPORT_SYMBOL(arm_heavy_mb); #endif -- GitLab From f746929ffdc8a83c0e6092343d4475f6485e13d3 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Jun 2015 00:13:40 +0100 Subject: [PATCH 1678/7006] Revert "ARM: OMAP4: remove dead kconfig option OMAP4_ERRATA_I688" This reverts commit 606da4826b89b044b51e3a84958b802204cfe4c7. We actually need this code for proper behaviour of OMAP4, and it needs fixing a different way other than just removing the code. Disabling code which is necessary in the hopes of persuing multiplatform kernels is a stupid approach. Acked-by: Tony Lindgren Acked-by: Richard Woodruff Signed-off-by: Russell King --- arch/arm/mach-omap2/Kconfig | 21 +++++++++ arch/arm/mach-omap2/common.c | 1 + arch/arm/mach-omap2/common.h | 3 ++ arch/arm/mach-omap2/io.c | 2 + arch/arm/mach-omap2/omap-secure.h | 7 +++ arch/arm/mach-omap2/omap4-common.c | 69 ++++++++++++++++++++++++++++++ arch/arm/mach-omap2/sleep44xx.S | 2 + 7 files changed, 105 insertions(+) diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index ecc04ff13e959..2128441430ad3 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -240,6 +240,27 @@ config OMAP3_SDRC_AC_TIMING wish to say no. Selecting yes without understanding what is going on could result in system crashes; +config OMAP4_ERRATA_I688 + bool "OMAP4 errata: Async Bridge Corruption" + depends on (ARCH_OMAP4 || SOC_OMAP5) && !ARCH_MULTIPLATFORM + select ARCH_HAS_BARRIERS + help + If a data is stalled inside asynchronous bridge because of back + pressure, it may be accepted multiple times, creating pointer + misalignment that will corrupt next transfers on that data path + until next reset of the system (No recovery procedure once the + issue is hit, the path remains consistently broken). Async bridge + can be found on path between MPU to EMIF and MPU to L3 interconnect. + This situation can happen only when the idle is initiated by a + Master Request Disconnection (which is trigged by software when + executing WFI on CPU). + The work-around for this errata needs all the initiators connected + through async bridge must ensure that data path is properly drained + before issuing WFI. This condition will be met if one Strongly ordered + access is performed to the target right before executing the WFI. + In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained. + IO barrier ensure that there is no synchronisation loss on initiators + operating on both interconnect port simultaneously. endmenu endif diff --git a/arch/arm/mach-omap2/common.c b/arch/arm/mach-omap2/common.c index eae6a0e87c90d..484cdadfb1878 100644 --- a/arch/arm/mach-omap2/common.c +++ b/arch/arm/mach-omap2/common.c @@ -30,4 +30,5 @@ int __weak omap_secure_ram_reserve_memblock(void) void __init omap_reserve(void) { omap_secure_ram_reserve_memblock(); + omap_barrier_reserve_memblock(); } diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index cf3cf22ecd426..46e24581d6245 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -200,6 +200,9 @@ void __init omap4_map_io(void); void __init omap5_map_io(void); void __init ti81xx_map_io(void); +/* omap_barriers_init() is OMAP4 only */ +void omap_barriers_init(void); + /** * omap_test_timeout - busy-loop, testing a condition * @cond: condition to test until it evaluates to true diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c index 820dde8b5b045..7743e3672f98b 100644 --- a/arch/arm/mach-omap2/io.c +++ b/arch/arm/mach-omap2/io.c @@ -306,6 +306,7 @@ void __init am33xx_map_io(void) void __init omap4_map_io(void) { iotable_init(omap44xx_io_desc, ARRAY_SIZE(omap44xx_io_desc)); + omap_barriers_init(); } #endif @@ -313,6 +314,7 @@ void __init omap4_map_io(void) void __init omap5_map_io(void) { iotable_init(omap54xx_io_desc, ARRAY_SIZE(omap54xx_io_desc)); + omap_barriers_init(); } #endif /* diff --git a/arch/arm/mach-omap2/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h index af2851fbcdf02..dec2b05d184bd 100644 --- a/arch/arm/mach-omap2/omap-secure.h +++ b/arch/arm/mach-omap2/omap-secure.h @@ -70,6 +70,13 @@ extern u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs, extern u32 rx51_secure_update_aux_cr(u32 set_bits, u32 clear_bits); extern u32 rx51_secure_rng_call(u32 ptr, u32 count, u32 flag); +#ifdef CONFIG_OMAP4_ERRATA_I688 +extern int omap_barrier_reserve_memblock(void); +#else +static inline void omap_barrier_reserve_memblock(void) +{ } +#endif + #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER void set_cntfreq(void); #else diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 16350eefa66c8..7bb116a6f86f5 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -51,6 +51,75 @@ static void __iomem *twd_base; #define IRQ_LOCALTIMER 29 +#ifdef CONFIG_OMAP4_ERRATA_I688 +/* Used to implement memory barrier on DRAM path */ +#define OMAP4_DRAM_BARRIER_VA 0xfe600000 + +void __iomem *dram_sync, *sram_sync; + +static phys_addr_t paddr; +static u32 size; + +void omap_bus_sync(void) +{ + if (dram_sync && sram_sync) { + writel_relaxed(readl_relaxed(dram_sync), dram_sync); + writel_relaxed(readl_relaxed(sram_sync), sram_sync); + isb(); + } +} +EXPORT_SYMBOL(omap_bus_sync); + +static int __init omap4_sram_init(void) +{ + struct device_node *np; + struct gen_pool *sram_pool; + + np = of_find_compatible_node(NULL, NULL, "ti,omap4-mpu"); + if (!np) + pr_warn("%s:Unable to allocate sram needed to handle errata I688\n", + __func__); + sram_pool = of_get_named_gen_pool(np, "sram", 0); + if (!sram_pool) + pr_warn("%s:Unable to get sram pool needed to handle errata I688\n", + __func__); + else + sram_sync = (void *)gen_pool_alloc(sram_pool, PAGE_SIZE); + + return 0; +} +omap_arch_initcall(omap4_sram_init); + +/* Steal one page physical memory for barrier implementation */ +int __init omap_barrier_reserve_memblock(void) +{ + + size = ALIGN(PAGE_SIZE, SZ_1M); + paddr = arm_memblock_steal(size, SZ_1M); + + return 0; +} + +void __init omap_barriers_init(void) +{ + struct map_desc dram_io_desc[1]; + + dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA; + dram_io_desc[0].pfn = __phys_to_pfn(paddr); + dram_io_desc[0].length = size; + dram_io_desc[0].type = MT_MEMORY_RW_SO; + iotable_init(dram_io_desc, ARRAY_SIZE(dram_io_desc)); + dram_sync = (void __iomem *) dram_io_desc[0].virtual; + + pr_info("OMAP4: Map 0x%08llx to 0x%08lx for dram barrier\n", + (long long) paddr, dram_io_desc[0].virtual); + +} +#else +void __init omap_barriers_init(void) +{} +#endif + void gic_dist_disable(void) { if (gic_dist_base_addr) diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S index ad1bb9431e941..b84a0122d823a 100644 --- a/arch/arm/mach-omap2/sleep44xx.S +++ b/arch/arm/mach-omap2/sleep44xx.S @@ -333,9 +333,11 @@ ENDPROC(omap4_cpu_resume) #endif /* defined(CONFIG_SMP) && defined(CONFIG_PM) */ +#ifndef CONFIG_OMAP4_ERRATA_I688 ENTRY(omap_bus_sync) ret lr ENDPROC(omap_bus_sync) +#endif ENTRY(omap_do_wfi) stmfd sp!, {lr} -- GitLab From 3fa609755c11fbe8770ede4d895ebb86fb7b9f1e Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 6 Jun 2015 00:38:08 +0100 Subject: [PATCH 1679/7006] ARM: omap2: restore OMAP4 barrier behaviour Restore the OMAP4 barrier behaviour using the new implementation which allows multiplatform systems to hook into the mb() and wmb() ARM implementations to perform any necessary additional barrier maintanence. Acked-by: Tony Lindgren Acked-by: Richard Woodruff Signed-off-by: Russell King --- arch/arm/mach-omap2/Kconfig | 28 ++----- arch/arm/mach-omap2/common.h | 12 ++- arch/arm/mach-omap2/include/mach/barriers.h | 33 -------- arch/arm/mach-omap2/omap-secure.h | 7 -- arch/arm/mach-omap2/omap4-common.c | 92 ++++++++++++++++----- arch/arm/mach-omap2/sleep44xx.S | 10 +-- 6 files changed, 91 insertions(+), 91 deletions(-) delete mode 100644 arch/arm/mach-omap2/include/mach/barriers.h diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 2128441430ad3..8427997e09c4b 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -29,6 +29,7 @@ config ARCH_OMAP4 select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP select OMAP_INTERCONNECT + select OMAP_INTERCONNECT_BARRIER select PL310_ERRATA_588369 if CACHE_L2X0 select PL310_ERRATA_727915 if CACHE_L2X0 select PM_OPP if PM @@ -46,6 +47,7 @@ config SOC_OMAP5 select HAVE_ARM_TWD if SMP select HAVE_ARM_ARCH_TIMER select ARM_ERRATA_798181 if SMP + select OMAP_INTERCONNECT_BARRIER config SOC_AM33XX bool "TI AM33XX" @@ -70,6 +72,7 @@ config SOC_DRA7XX select HAVE_ARM_ARCH_TIMER select IRQ_CROSSBAR select ARM_ERRATA_798181 if SMP + select OMAP_INTERCONNECT_BARRIER config ARCH_OMAP2PLUS bool @@ -91,6 +94,10 @@ config ARCH_OMAP2PLUS help Systems based on OMAP2, OMAP3, OMAP4 or OMAP5 +config OMAP_INTERCONNECT_BARRIER + bool + select ARM_HEAVY_MB + if ARCH_OMAP2PLUS @@ -240,27 +247,6 @@ config OMAP3_SDRC_AC_TIMING wish to say no. Selecting yes without understanding what is going on could result in system crashes; -config OMAP4_ERRATA_I688 - bool "OMAP4 errata: Async Bridge Corruption" - depends on (ARCH_OMAP4 || SOC_OMAP5) && !ARCH_MULTIPLATFORM - select ARCH_HAS_BARRIERS - help - If a data is stalled inside asynchronous bridge because of back - pressure, it may be accepted multiple times, creating pointer - misalignment that will corrupt next transfers on that data path - until next reset of the system (No recovery procedure once the - issue is hit, the path remains consistently broken). Async bridge - can be found on path between MPU to EMIF and MPU to L3 interconnect. - This situation can happen only when the idle is initiated by a - Master Request Disconnection (which is trigged by software when - executing WFI on CPU). - The work-around for this errata needs all the initiators connected - through async bridge must ensure that data path is properly drained - before issuing WFI. This condition will be met if one Strongly ordered - access is performed to the target right before executing the WFI. - In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained. - IO barrier ensure that there is no synchronisation loss on initiators - operating on both interconnect port simultaneously. endmenu endif diff --git a/arch/arm/mach-omap2/common.h b/arch/arm/mach-omap2/common.h index 46e24581d6245..82f88b4ec15f4 100644 --- a/arch/arm/mach-omap2/common.h +++ b/arch/arm/mach-omap2/common.h @@ -189,6 +189,15 @@ static inline void omap44xx_restart(enum reboot_mode mode, const char *cmd) } #endif +#ifdef CONFIG_OMAP_INTERCONNECT_BARRIER +void omap_barrier_reserve_memblock(void); +void omap_barriers_init(void); +#else +static inline void omap_barrier_reserve_memblock(void) +{ +} +#endif + /* This gets called from mach-omap2/io.c, do not call this */ void __init omap2_set_globals_tap(u32 class, void __iomem *tap); @@ -200,9 +209,6 @@ void __init omap4_map_io(void); void __init omap5_map_io(void); void __init ti81xx_map_io(void); -/* omap_barriers_init() is OMAP4 only */ -void omap_barriers_init(void); - /** * omap_test_timeout - busy-loop, testing a condition * @cond: condition to test until it evaluates to true diff --git a/arch/arm/mach-omap2/include/mach/barriers.h b/arch/arm/mach-omap2/include/mach/barriers.h deleted file mode 100644 index 1c582a8592b93..0000000000000 --- a/arch/arm/mach-omap2/include/mach/barriers.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * OMAP memory barrier header. - * - * Copyright (C) 2011 Texas Instruments, Inc. - * Santosh Shilimkar - * Richard Woodruff - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __MACH_BARRIERS_H -#define __MACH_BARRIERS_H - -#include - -extern void omap_bus_sync(void); - -#define rmb() dsb() -#define wmb() do { dsb(); outer_sync(); omap_bus_sync(); } while (0) -#define mb() wmb() - -#endif /* __MACH_BARRIERS_H */ diff --git a/arch/arm/mach-omap2/omap-secure.h b/arch/arm/mach-omap2/omap-secure.h index dec2b05d184bd..af2851fbcdf02 100644 --- a/arch/arm/mach-omap2/omap-secure.h +++ b/arch/arm/mach-omap2/omap-secure.h @@ -70,13 +70,6 @@ extern u32 rx51_secure_dispatcher(u32 idx, u32 process, u32 flag, u32 nargs, extern u32 rx51_secure_update_aux_cr(u32 set_bits, u32 clear_bits); extern u32 rx51_secure_rng_call(u32 ptr, u32 count, u32 flag); -#ifdef CONFIG_OMAP4_ERRATA_I688 -extern int omap_barrier_reserve_memblock(void); -#else -static inline void omap_barrier_reserve_memblock(void) -{ } -#endif - #ifdef CONFIG_SOC_HAS_REALTIME_COUNTER void set_cntfreq(void); #else diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c index 7bb116a6f86f5..949696b6f17b6 100644 --- a/arch/arm/mach-omap2/omap4-common.c +++ b/arch/arm/mach-omap2/omap4-common.c @@ -51,16 +51,73 @@ static void __iomem *twd_base; #define IRQ_LOCALTIMER 29 -#ifdef CONFIG_OMAP4_ERRATA_I688 +#ifdef CONFIG_OMAP_INTERCONNECT_BARRIER + /* Used to implement memory barrier on DRAM path */ #define OMAP4_DRAM_BARRIER_VA 0xfe600000 -void __iomem *dram_sync, *sram_sync; +static void __iomem *dram_sync, *sram_sync; +static phys_addr_t dram_sync_paddr; +static u32 dram_sync_size; + +/* + * The OMAP4 bus structure contains asynchrnous bridges which can buffer + * data writes from the MPU. These asynchronous bridges can be found on + * paths between the MPU to EMIF, and the MPU to L3 interconnects. + * + * We need to be careful about re-ordering which can happen as a result + * of different accesses being performed via different paths, and + * therefore different asynchronous bridges. + */ -static phys_addr_t paddr; -static u32 size; +/* + * OMAP4 interconnect barrier which is called for each mb() and wmb(). + * This is to ensure that normal paths to DRAM (normal memory, cacheable + * accesses) are properly synchronised with writes to DMA coherent memory + * (normal memory, uncacheable) and device writes. + * + * The mb() and wmb() barriers only operate only on the MPU->MA->EMIF + * path, as we need to ensure that data is visible to other system + * masters prior to writes to those system masters being seen. + * + * Note: the SRAM path is not synchronised via mb() and wmb(). + */ +static void omap4_mb(void) +{ + if (dram_sync) + writel_relaxed(0, dram_sync); +} -void omap_bus_sync(void) +/* + * OMAP4 Errata i688 - asynchronous bridge corruption when entering WFI. + * + * If a data is stalled inside asynchronous bridge because of back + * pressure, it may be accepted multiple times, creating pointer + * misalignment that will corrupt next transfers on that data path until + * next reset of the system. No recovery procedure once the issue is hit, + * the path remains consistently broken. + * + * Async bridges can be found on paths between MPU to EMIF and MPU to L3 + * interconnects. + * + * This situation can happen only when the idle is initiated by a Master + * Request Disconnection (which is trigged by software when executing WFI + * on the CPU). + * + * The work-around for this errata needs all the initiators connected + * through an async bridge to ensure that data path is properly drained + * before issuing WFI. This condition will be met if one Strongly ordered + * access is performed to the target right before executing the WFI. + * + * In MPU case, L3 T2ASYNC FIFO and DDR T2ASYNC FIFO needs to be drained. + * IO barrier ensure that there is no synchronisation loss on initiators + * operating on both interconnect port simultaneously. + * + * This is a stronger version of the OMAP4 memory barrier below, and + * operates on both the MPU->MA->EMIF path but also the MPU->OCP path + * as well, and is necessary prior to executing a WFI. + */ +void omap_interconnect_sync(void) { if (dram_sync && sram_sync) { writel_relaxed(readl_relaxed(dram_sync), dram_sync); @@ -68,7 +125,6 @@ void omap_bus_sync(void) isb(); } } -EXPORT_SYMBOL(omap_bus_sync); static int __init omap4_sram_init(void) { @@ -79,7 +135,7 @@ static int __init omap4_sram_init(void) if (!np) pr_warn("%s:Unable to allocate sram needed to handle errata I688\n", __func__); - sram_pool = of_get_named_gen_pool(np, "sram", 0); + sram_pool = of_gen_pool_get(np, "sram", 0); if (!sram_pool) pr_warn("%s:Unable to get sram pool needed to handle errata I688\n", __func__); @@ -91,13 +147,10 @@ static int __init omap4_sram_init(void) omap_arch_initcall(omap4_sram_init); /* Steal one page physical memory for barrier implementation */ -int __init omap_barrier_reserve_memblock(void) +void __init omap_barrier_reserve_memblock(void) { - - size = ALIGN(PAGE_SIZE, SZ_1M); - paddr = arm_memblock_steal(size, SZ_1M); - - return 0; + dram_sync_size = ALIGN(PAGE_SIZE, SZ_1M); + dram_sync_paddr = arm_memblock_steal(dram_sync_size, SZ_1M); } void __init omap_barriers_init(void) @@ -105,19 +158,18 @@ void __init omap_barriers_init(void) struct map_desc dram_io_desc[1]; dram_io_desc[0].virtual = OMAP4_DRAM_BARRIER_VA; - dram_io_desc[0].pfn = __phys_to_pfn(paddr); - dram_io_desc[0].length = size; + dram_io_desc[0].pfn = __phys_to_pfn(dram_sync_paddr); + dram_io_desc[0].length = dram_sync_size; dram_io_desc[0].type = MT_MEMORY_RW_SO; iotable_init(dram_io_desc, ARRAY_SIZE(dram_io_desc)); dram_sync = (void __iomem *) dram_io_desc[0].virtual; - pr_info("OMAP4: Map 0x%08llx to 0x%08lx for dram barrier\n", - (long long) paddr, dram_io_desc[0].virtual); + pr_info("OMAP4: Map %pa to %p for dram barrier\n", + &dram_sync_paddr, dram_sync); + soc_mb = omap4_mb; } -#else -void __init omap_barriers_init(void) -{} + #endif void gic_dist_disable(void) diff --git a/arch/arm/mach-omap2/sleep44xx.S b/arch/arm/mach-omap2/sleep44xx.S index b84a0122d823a..9b09d85d811a1 100644 --- a/arch/arm/mach-omap2/sleep44xx.S +++ b/arch/arm/mach-omap2/sleep44xx.S @@ -333,16 +333,12 @@ ENDPROC(omap4_cpu_resume) #endif /* defined(CONFIG_SMP) && defined(CONFIG_PM) */ -#ifndef CONFIG_OMAP4_ERRATA_I688 -ENTRY(omap_bus_sync) - ret lr -ENDPROC(omap_bus_sync) -#endif - ENTRY(omap_do_wfi) stmfd sp!, {lr} +#ifdef CONFIG_OMAP_INTERCONNECT_BARRIER /* Drain interconnect write buffers. */ - bl omap_bus_sync + bl omap_interconnect_sync +#endif /* * Execute an ISB instruction to ensure that all of the -- GitLab From 92ff7a698badec3938edd3ba6b3e3ae035555365 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 25 Jul 2015 21:10:27 +0200 Subject: [PATCH 1680/7006] bcma: fix build error when build as module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently of_default_bus_match_table is not exported so we can only use this feature when bcma is build into the kernel. This patch removes support for child buses when bcma is build as a module as a temporary fix for a build problem introduces in this commit: commit cae761b5a6bdc597ba476a040fdcd5b4bc559b85 Author: Rafał Miłecki Date: Sun Jun 28 17:17:13 2015 +0200 bcma: populate bus DT subnodes as platform_device-s Reported-by: Stephen Rothwell Fixes: cae761b5a6bd ("bcma: populate bus DT subnodes as platform_device-s") Signed-off-by: Hauke Mehrtens Signed-off-by: Kalle Valo --- drivers/bcma/main.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 59128478a90fd..8d973c4fc84e3 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -410,7 +410,11 @@ int bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_early_init(&bus->drv_pci[0]); } - if (bus->host_pdev) { + /* TODO: remove check for IS_BUILTIN(CONFIG_BCMA) check when + * of_default_bus_match_table is exported or in some other way + * accessible. This is just a temporary workaround. + */ + if (IS_BUILTIN(CONFIG_BCMA) && bus->host_pdev) { struct device *dev = &bus->host_pdev->dev; of_platform_populate(dev->of_node, of_default_bus_match_table, -- GitLab From 7dd0e0af64afe4aa08ccdd167f64bd007f09b515 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 27 May 2015 17:11:37 -0400 Subject: [PATCH 1681/7006] intel_idle: allow idle states to be freeze-mode specific intel_idle uses a NULL "enter" field in a cpuidle state to recognize the invalid entry terminating a variable-length array. Linux-4.0 added support for the system-wide "freeze" state in cpuidle drivers via the new "enter_freeze" field. The natural way to expose a deep idle state for freeze, but not for run-time idle is to supply "enter_freeze" without "enter"; so we update the driver to accept such states. Signed-off-by: Len Brown --- drivers/idle/intel_idle.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c index 2a36a95d95cfa..008e943d224df 100644 --- a/drivers/idle/intel_idle.c +++ b/drivers/idle/intel_idle.c @@ -965,7 +965,8 @@ static int __init intel_idle_cpuidle_driver_init(void) for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) { int num_substates, mwait_hint, mwait_cstate; - if (cpuidle_state_table[cstate].enter == NULL) + if ((cpuidle_state_table[cstate].enter == NULL) && + (cpuidle_state_table[cstate].enter_freeze == NULL)) break; if (cstate + 1 > max_cstate) { -- GitLab From 90a21700ed9635070fb04fe92fb50c5e3bc16605 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 23 Jul 2015 16:34:58 -0700 Subject: [PATCH 1682/7006] drm: Fix DP_TEST_COUNT_MASK By Vesa's DP 1.2 Spec this counter has 4 bits [3:0]. This mask is wrong since when the counter was introduced by myself on commit ad9dc91b6e21266bfc6f466db4b95e10211f31ee Author: Rodrigo Vivi Date: Tue Sep 16 19:18:12 2014 -0400 drm/i915: Fix Sink CRC Signed-off-by: Rodrigo Vivi Reviewed-by: Sivakumar Thulasimani Signed-off-by: Daniel Vetter --- include/drm/drm_dp_helper.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index 2e86f642fc339..94898f6ea02af 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -420,7 +420,7 @@ #define DP_TEST_SINK_MISC 0x246 # define DP_TEST_CRC_SUPPORTED (1 << 5) -# define DP_TEST_COUNT_MASK 0x7 +# define DP_TEST_COUNT_MASK 0xf #define DP_TEST_RESPONSE 0x260 # define DP_TEST_ACK (1 << 0) -- GitLab From 29042e19f2c602fabe4705b5b719550b4627639c Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 22 Jul 2015 10:11:18 -0400 Subject: [PATCH 1683/7006] tipc: let function tipc_msg_reverse() expand header when needed The shortest TIPC message header, for cluster local CONNECTED messages, is 24 bytes long. With this format, the fields "dest_node" and "orig_node" are optimized away, since they in reality are redundant in this particular case. However, the absence of these fields leads to code inconsistencies that are difficult to handle in some cases, especially when we need to reverse or reject messages at the socket layer. In this commit, we concentrate the handling of the absent fields to one place, by letting the function tipc_msg_reverse() reallocate the buffer and expand the header to 32 bytes when necessary. This means that the socket code now can assume that the two previously absent fields are present in the header when a message needs to be rejected. This opens up for some further simplifications of the socket code. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.c | 67 +++++++++++++++++++++++++++++------------------ net/tipc/msg.h | 3 +-- net/tipc/socket.c | 12 ++++----- 3 files changed, 48 insertions(+), 34 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 08b4cc7d496d9..4339aab930348 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -463,43 +463,58 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, struct tipc_msg *msg, /** * tipc_msg_reverse(): swap source and destination addresses and add error code - * @buf: buffer containing message to be reversed - * @dnode: return value: node where to send message after reversal - * @err: error code to be set in message - * Consumes buffer if failure + * @own_node: originating node id for reversed message + * @skb: buffer containing message to be reversed; may be replaced. + * @err: error code to be set in message, if any + * Consumes buffer at failure * Returns true if success, otherwise false */ -bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode, - int err) +bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, u32 *dnode, int err) { - struct tipc_msg *msg = buf_msg(buf); + struct sk_buff *_skb = *skb; + struct tipc_msg *hdr = buf_msg(_skb); struct tipc_msg ohdr; - uint rdsz = min_t(uint, msg_data_sz(msg), MAX_FORWARD_SIZE); + int dlen = min_t(uint, msg_data_sz(hdr), MAX_FORWARD_SIZE); - if (skb_linearize(buf)) + if (skb_linearize(_skb)) goto exit; - msg = buf_msg(buf); - if (msg_dest_droppable(msg)) + hdr = buf_msg(_skb); + if (msg_dest_droppable(hdr)) goto exit; - if (msg_errcode(msg)) + if (msg_errcode(hdr)) goto exit; - memcpy(&ohdr, msg, msg_hdr_sz(msg)); - msg_set_errcode(msg, err); - msg_set_origport(msg, msg_destport(&ohdr)); - msg_set_destport(msg, msg_origport(&ohdr)); - msg_set_prevnode(msg, own_addr); - if (!msg_short(msg)) { - msg_set_orignode(msg, msg_destnode(&ohdr)); - msg_set_destnode(msg, msg_orignode(&ohdr)); + + /* Take a copy of original header before altering message */ + memcpy(&ohdr, hdr, msg_hdr_sz(hdr)); + + /* Never return SHORT header; expand by replacing buffer if necessary */ + if (msg_short(hdr)) { + *skb = tipc_buf_acquire(BASIC_H_SIZE + dlen); + if (!*skb) + goto exit; + memcpy((*skb)->data + BASIC_H_SIZE, msg_data(hdr), dlen); + kfree_skb(_skb); + _skb = *skb; + hdr = buf_msg(_skb); + memcpy(hdr, &ohdr, BASIC_H_SIZE); + msg_set_hdr_sz(hdr, BASIC_H_SIZE); } - msg_set_size(msg, msg_hdr_sz(msg) + rdsz); - skb_trim(buf, msg_size(msg)); - skb_orphan(buf); - *dnode = msg_orignode(&ohdr); + + /* Now reverse the concerned fields */ + msg_set_errcode(hdr, err); + msg_set_origport(hdr, msg_destport(&ohdr)); + msg_set_destport(hdr, msg_origport(&ohdr)); + msg_set_destnode(hdr, msg_prevnode(&ohdr)); + msg_set_prevnode(hdr, own_node); + msg_set_orignode(hdr, own_node); + msg_set_size(hdr, msg_hdr_sz(hdr) + dlen); + *dnode = msg_destnode(hdr); + skb_trim(_skb, msg_size(hdr)); + skb_orphan(_skb); return true; exit: - kfree_skb(buf); - *dnode = 0; + kfree_skb(_skb); + *skb = NULL; return false; } diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 2f1563b47e24f..0e96f59e33157 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -785,8 +785,7 @@ static inline bool msg_peer_is_up(struct tipc_msg *m) struct sk_buff *tipc_buf_acquire(u32 size); bool tipc_msg_validate(struct sk_buff *skb); -bool tipc_msg_reverse(u32 own_addr, struct sk_buff *buf, u32 *dnode, - int err); +bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, u32 *dnode, int err); void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 5b0b08d58fcc1..e2d5b98314853 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -260,7 +260,7 @@ static void tsk_rej_rx_queue(struct sock *sk) u32 own_node = tsk_own_node(tipc_sk(sk)); while ((skb = __skb_dequeue(&sk->sk_receive_queue))) { - if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_ERR_NO_PORT)) + if (tipc_msg_reverse(own_node, &skb, &dnode, TIPC_ERR_NO_PORT)) tipc_node_xmit_skb(sock_net(sk), skb, dnode, 0); } } @@ -441,7 +441,7 @@ static int tipc_release(struct socket *sock) tsk->connected = 0; tipc_node_remove_conn(net, dnode, tsk->portid); } - if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, + if (tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, TIPC_ERR_NO_PORT)) tipc_node_xmit_skb(net, skb, dnode, 0); } @@ -784,7 +784,7 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff **skb) if (conn_cong) tsk->sk.sk_write_space(&tsk->sk); } else if (msg_type(msg) == CONN_PROBE) { - if (tipc_msg_reverse(own_node, *skb, &dnode, TIPC_OK)) { + if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_OK)) { msg_set_type(msg, CONN_PROBE_REPLY); return; } @@ -1702,7 +1702,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) atomic_add(truesize, dcnt); return 0; } - if (!err || tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, -err)) + if (!err || tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, -err)) tipc_node_xmit_skb(net, skb, dnode, tsk->portid); return 0; } @@ -1796,7 +1796,7 @@ int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) goto xmit; } tn = net_generic(net, tipc_net_id); - if (!tipc_msg_reverse(tn->own_addr, skb, &dnode, -err)) + if (!tipc_msg_reverse(tn->own_addr, &skb, &dnode, -err)) continue; xmit: tipc_node_xmit_skb(net, skb, dnode, dport); @@ -2090,7 +2090,7 @@ restart: kfree_skb(skb); goto restart; } - if (tipc_msg_reverse(tsk_own_node(tsk), skb, &dnode, + if (tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, TIPC_CONN_SHUTDOWN)) tipc_node_xmit_skb(net, skb, dnode, tsk->portid); -- GitLab From bcd3ffd4f6d7c994c93be2ab8598fdfb2952a1f1 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 22 Jul 2015 10:11:19 -0400 Subject: [PATCH 1684/7006] tipc: introduce new tipc_sk_respond() function Currently, we use the code sequence if (msg_reverse()) tipc_link_xmit_skb() at numerous locations in socket.c. The preparation of arguments for these calls, as well as the sequence itself, makes the code unecessarily complex. In this commit, we introduce a new function, tipc_sk_respond(), that performs this call combination. We also replace some, but not yet all, of these explicit call sequences with calls to the new function. Notably, we let the function tipc_sk_proto_rcv() use the new function to directly send out PROBE_REPLY messages, instead of deferring this to the calling tipc_sk_rcv() function, as we do now. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.c | 3 +- net/tipc/msg.h | 2 +- net/tipc/socket.c | 81 ++++++++++++++++++++++++++--------------------- 3 files changed, 47 insertions(+), 39 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 4339aab930348..b6cc58ec73464 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -469,7 +469,7 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, struct tipc_msg *msg, * Consumes buffer at failure * Returns true if success, otherwise false */ -bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, u32 *dnode, int err) +bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, int err) { struct sk_buff *_skb = *skb; struct tipc_msg *hdr = buf_msg(_skb); @@ -508,7 +508,6 @@ bool tipc_msg_reverse(u32 own_node, struct sk_buff **skb, u32 *dnode, int err) msg_set_prevnode(hdr, own_node); msg_set_orignode(hdr, own_node); msg_set_size(hdr, msg_hdr_sz(hdr) + dlen); - *dnode = msg_destnode(hdr); skb_trim(_skb, msg_size(hdr)); skb_orphan(_skb); return true; diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 0e96f59e33157..d0834bc519aac 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -785,7 +785,7 @@ static inline bool msg_peer_is_up(struct tipc_msg *m) struct sk_buff *tipc_buf_acquire(u32 size); bool tipc_msg_validate(struct sk_buff *skb); -bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, u32 *dnode, int err); +bool tipc_msg_reverse(u32 own_addr, struct sk_buff **skb, int err); void tipc_msg_init(u32 own_addr, struct tipc_msg *m, u32 user, u32 type, u32 hsize, u32 destnode); struct sk_buff *tipc_msg_create(uint user, uint type, uint hdr_sz, diff --git a/net/tipc/socket.c b/net/tipc/socket.c index e2d5b98314853..71d88adadb185 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -248,6 +248,22 @@ static void tsk_advance_rx_queue(struct sock *sk) kfree_skb(__skb_dequeue(&sk->sk_receive_queue)); } +/* tipc_sk_respond() : send response message back to sender + */ +static void tipc_sk_respond(struct sock *sk, struct sk_buff *skb, int err) +{ + u32 selector; + u32 dnode; + u32 onode = tipc_own_addr(sock_net(sk)); + + if (!tipc_msg_reverse(onode, &skb, err)) + return; + + dnode = msg_destnode(buf_msg(skb)); + selector = msg_origport(buf_msg(skb)); + tipc_node_xmit_skb(sock_net(sk), skb, dnode, selector); +} + /** * tsk_rej_rx_queue - reject all buffers in socket receive queue * @@ -256,13 +272,9 @@ static void tsk_advance_rx_queue(struct sock *sk) static void tsk_rej_rx_queue(struct sock *sk) { struct sk_buff *skb; - u32 dnode; - u32 own_node = tsk_own_node(tipc_sk(sk)); - while ((skb = __skb_dequeue(&sk->sk_receive_queue))) { - if (tipc_msg_reverse(own_node, &skb, &dnode, TIPC_ERR_NO_PORT)) - tipc_node_xmit_skb(sock_net(sk), skb, dnode, 0); - } + while ((skb = __skb_dequeue(&sk->sk_receive_queue))) + tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); } /* tsk_peer_msg - verify if message was sent by connected port's peer @@ -441,9 +453,7 @@ static int tipc_release(struct socket *sock) tsk->connected = 0; tipc_node_remove_conn(net, dnode, tsk->portid); } - if (tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, - TIPC_ERR_NO_PORT)) - tipc_node_xmit_skb(net, skb, dnode, 0); + tipc_sk_respond(sk, skb, TIPC_ERR_NO_PORT); } } @@ -764,35 +774,35 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, /** * tipc_sk_proto_rcv - receive a connection mng protocol message * @tsk: receiving socket - * @skb: pointer to message buffer. Set to NULL if buffer is consumed. + * @skb: pointer to message buffer. */ -static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff **skb) +static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb) { - struct tipc_msg *msg = buf_msg(*skb); + struct sock *sk = &tsk->sk; + struct tipc_msg *hdr = buf_msg(skb); + int mtyp = msg_type(hdr); int conn_cong; - u32 dnode; - u32 own_node = tsk_own_node(tsk); + /* Ignore if connection cannot be validated: */ - if (!tsk_peer_msg(tsk, msg)) + if (!tsk_peer_msg(tsk, hdr)) goto exit; tsk->probing_state = TIPC_CONN_OK; - if (msg_type(msg) == CONN_ACK) { + if (mtyp == CONN_PROBE) { + msg_set_type(hdr, CONN_PROBE_REPLY); + tipc_sk_respond(sk, skb, TIPC_OK); + return; + } else if (mtyp == CONN_ACK) { conn_cong = tsk_conn_cong(tsk); - tsk->sent_unacked -= msg_msgcnt(msg); + tsk->sent_unacked -= msg_msgcnt(hdr); if (conn_cong) - tsk->sk.sk_write_space(&tsk->sk); - } else if (msg_type(msg) == CONN_PROBE) { - if (tipc_msg_reverse(own_node, skb, &dnode, TIPC_OK)) { - msg_set_type(msg, CONN_PROBE_REPLY); - return; - } + sk->sk_write_space(sk); + } else if (mtyp != CONN_PROBE_REPLY) { + pr_warn("Received unknown CONN_PROTO msg\n"); } - /* Do nothing if msg_type() == CONN_PROBE_REPLY */ exit: - kfree_skb(*skb); - *skb = NULL; + kfree_skb(skb); } static int tipc_wait_for_sndmsg(struct socket *sock, long *timeo_p) @@ -1638,7 +1648,7 @@ static int filter_rcv(struct sock *sk, struct sk_buff **skb) int rc = TIPC_OK; if (unlikely(msg_user(msg) == CONN_MANAGER)) { - tipc_sk_proto_rcv(tsk, skb); + tipc_sk_proto_rcv(tsk, *skb); return TIPC_OK; } @@ -1690,7 +1700,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) { int err; atomic_t *dcnt; - u32 dnode; + u32 dnode = msg_prevnode(buf_msg(skb)); struct tipc_sock *tsk = tipc_sk(sk); struct net *net = sock_net(sk); uint truesize = skb->truesize; @@ -1702,7 +1712,7 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) atomic_add(truesize, dcnt); return 0; } - if (!err || tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, -err)) + if (!err || tipc_msg_reverse(tsk_own_node(tsk), &skb, -err)) tipc_node_xmit_skb(net, skb, dnode, tsk->portid); return 0; } @@ -1794,9 +1804,11 @@ int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) if (!err) { dnode = msg_destnode(buf_msg(skb)); goto xmit; + } else { + dnode = msg_prevnode(buf_msg(skb)); } tn = net_generic(net, tipc_net_id); - if (!tipc_msg_reverse(tn->own_addr, &skb, &dnode, -err)) + if (!tipc_msg_reverse(tn->own_addr, &skb, -err)) continue; xmit: tipc_node_xmit_skb(net, skb, dnode, dport); @@ -2083,6 +2095,8 @@ static int tipc_shutdown(struct socket *sock, int how) case SS_CONNECTED: restart: + dnode = tsk_peer_node(tsk); + /* Disconnect and send a 'FIN+' or 'FIN-' message to peer */ skb = __skb_dequeue(&sk->sk_receive_queue); if (skb) { @@ -2090,13 +2104,8 @@ restart: kfree_skb(skb); goto restart; } - if (tipc_msg_reverse(tsk_own_node(tsk), &skb, &dnode, - TIPC_CONN_SHUTDOWN)) - tipc_node_xmit_skb(net, skb, dnode, - tsk->portid); + tipc_sk_respond(sk, skb, TIPC_CONN_SHUTDOWN); } else { - dnode = tsk_peer_node(tsk); - skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, SHORT_H_SIZE, 0, dnode, tsk_own_node(tsk), -- GitLab From cda3696d3d26eb798c94de0dab5bd66ddb5627cb Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Wed, 22 Jul 2015 10:11:20 -0400 Subject: [PATCH 1685/7006] tipc: clean up socket layer message reception When a message is received in a socket, one of the call chains tipc_sk_rcv()->tipc_sk_enqueue()->filter_rcv()(->tipc_sk_proto_rcv()) or tipc_sk_backlog_rcv()->filter_rcv()(->tipc_sk_proto_rcv()) are followed. At each of these levels we may encounter situations where the message may need to be rejected, or a new message produced for transfer back to the sender. Despite recent improvements, the current code for doing this is perceived as awkward and hard to follow. Leveraging the two previous commits in this series, we now introduce a more uniform handling of such situations. We let each of the functions in the chain itself produce/reverse the message to be returned to the sender, but also perform the actual forwarding. This simplifies the necessary logics within each function. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/msg.c | 20 ++-- net/tipc/msg.h | 3 +- net/tipc/socket.c | 255 ++++++++++++++++++++++------------------------ net/tipc/socket.h | 2 +- 4 files changed, 134 insertions(+), 146 deletions(-) diff --git a/net/tipc/msg.c b/net/tipc/msg.c index b6cc58ec73464..562c926a51cc7 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -520,17 +520,15 @@ exit: /** * tipc_msg_lookup_dest(): try to find new destination for named message * @skb: the buffer containing the message. - * @dnode: return value: next-hop node, if destination found - * @err: return value: error code to use, if message to be rejected + * @err: error code to be used by caller if lookup fails * Does not consume buffer * Returns true if a destination is found, false otherwise */ -bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, - u32 *dnode, int *err) +bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err) { struct tipc_msg *msg = buf_msg(skb); - u32 dport; - u32 own_addr = tipc_own_addr(net); + u32 dport, dnode; + u32 onode = tipc_own_addr(net); if (!msg_isdata(msg)) return false; @@ -543,15 +541,15 @@ bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, return false; if (msg_reroute_cnt(msg)) return false; - *dnode = addr_domain(net, msg_lookup_scope(msg)); + dnode = addr_domain(net, msg_lookup_scope(msg)); dport = tipc_nametbl_translate(net, msg_nametype(msg), - msg_nameinst(msg), dnode); + msg_nameinst(msg), &dnode); if (!dport) return false; msg_incr_reroute_cnt(msg); - if (*dnode != own_addr) - msg_set_prevnode(msg, own_addr); - msg_set_destnode(msg, *dnode); + if (dnode != onode) + msg_set_prevnode(msg, onode); + msg_set_destnode(msg, dnode); msg_set_destport(msg, dport); *err = TIPC_OK; return true; diff --git a/net/tipc/msg.h b/net/tipc/msg.h index d0834bc519aac..234fb0531d1d8 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h @@ -798,8 +798,7 @@ bool tipc_msg_make_bundle(struct sk_buff **skb, struct tipc_msg *msg, bool tipc_msg_extract(struct sk_buff *skb, struct sk_buff **iskb, int *pos); int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, int offset, int dsz, int mtu, struct sk_buff_head *list); -bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, u32 *dnode, - int *err); +bool tipc_msg_lookup_dest(struct net *net, struct sk_buff *skb, int *err); struct sk_buff *tipc_msg_reassemble(struct sk_buff_head *list); static inline u16 buf_seqno(struct sk_buff *skb) diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 71d88adadb185..1060d52ff23eb 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1520,82 +1520,81 @@ static void tipc_data_ready(struct sock *sk) * @tsk: TIPC socket * @skb: pointer to message buffer. Set to NULL if buffer is consumed * - * Returns 0 (TIPC_OK) if everything ok, -TIPC_ERR_NO_PORT otherwise + * Returns true if everything ok, false otherwise */ -static int filter_connect(struct tipc_sock *tsk, struct sk_buff **skb) +static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) { struct sock *sk = &tsk->sk; struct net *net = sock_net(sk); struct socket *sock = sk->sk_socket; - struct tipc_msg *msg = buf_msg(*skb); - int retval = -TIPC_ERR_NO_PORT; + struct tipc_msg *hdr = buf_msg(skb); - if (msg_mcast(msg)) - return retval; + if (unlikely(msg_mcast(hdr))) + return false; switch ((int)sock->state) { case SS_CONNECTED: + /* Accept only connection-based messages sent by peer */ - if (tsk_peer_msg(tsk, msg)) { - if (unlikely(msg_errcode(msg))) { - sock->state = SS_DISCONNECTING; - tsk->connected = 0; - /* let timer expire on it's own */ - tipc_node_remove_conn(net, tsk_peer_node(tsk), - tsk->portid); - } - retval = TIPC_OK; + if (unlikely(!tsk_peer_msg(tsk, hdr))) + return false; + + if (unlikely(msg_errcode(hdr))) { + sock->state = SS_DISCONNECTING; + tsk->connected = 0; + /* Let timer expire on it's own */ + tipc_node_remove_conn(net, tsk_peer_node(tsk), + tsk->portid); } - break; + return true; + case SS_CONNECTING: - /* Accept only ACK or NACK message */ - if (unlikely(!msg_connected(msg))) - break; + /* Accept only ACK or NACK message */ + if (unlikely(!msg_connected(hdr))) + return false; - if (unlikely(msg_errcode(msg))) { + if (unlikely(msg_errcode(hdr))) { sock->state = SS_DISCONNECTING; sk->sk_err = ECONNREFUSED; - retval = TIPC_OK; - break; + return true; } - if (unlikely(msg_importance(msg) > TIPC_CRITICAL_IMPORTANCE)) { + if (unlikely(!msg_isdata(hdr))) { sock->state = SS_DISCONNECTING; sk->sk_err = EINVAL; - retval = TIPC_OK; - break; + return true; } - tipc_sk_finish_conn(tsk, msg_origport(msg), msg_orignode(msg)); - msg_set_importance(&tsk->phdr, msg_importance(msg)); + tipc_sk_finish_conn(tsk, msg_origport(hdr), msg_orignode(hdr)); + msg_set_importance(&tsk->phdr, msg_importance(hdr)); sock->state = SS_CONNECTED; - /* If an incoming message is an 'ACK-', it should be - * discarded here because it doesn't contain useful - * data. In addition, we should try to wake up - * connect() routine if sleeping. - */ - if (msg_data_sz(msg) == 0) { - kfree_skb(*skb); - *skb = NULL; - if (waitqueue_active(sk_sleep(sk))) - wake_up_interruptible(sk_sleep(sk)); - } - retval = TIPC_OK; - break; + /* If 'ACK+' message, add to socket receive queue */ + if (msg_data_sz(hdr)) + return true; + + /* If empty 'ACK-' message, wake up sleeping connect() */ + if (waitqueue_active(sk_sleep(sk))) + wake_up_interruptible(sk_sleep(sk)); + + /* 'ACK-' message is neither accepted nor rejected: */ + msg_set_dest_droppable(hdr, 1); + return false; + case SS_LISTENING: case SS_UNCONNECTED: + /* Accept only SYN message */ - if (!msg_connected(msg) && !(msg_errcode(msg))) - retval = TIPC_OK; + if (!msg_connected(hdr) && !(msg_errcode(hdr))) + return true; break; case SS_DISCONNECTING: break; default: pr_err("Unknown socket state %u\n", sock->state); } - return retval; + return false; } /** @@ -1630,61 +1629,70 @@ static unsigned int rcvbuf_limit(struct sock *sk, struct sk_buff *buf) /** * filter_rcv - validate incoming message * @sk: socket - * @skb: pointer to message. Set to NULL if buffer is consumed. + * @skb: pointer to message. * * Enqueues message on receive queue if acceptable; optionally handles * disconnect indication for a connected socket. * * Called with socket lock already taken * - * Returns 0 (TIPC_OK) if message was ok, -TIPC error code if rejected + * Returns true if message was added to socket receive queue, otherwise false */ -static int filter_rcv(struct sock *sk, struct sk_buff **skb) +static bool filter_rcv(struct sock *sk, struct sk_buff *skb) { struct socket *sock = sk->sk_socket; struct tipc_sock *tsk = tipc_sk(sk); - struct tipc_msg *msg = buf_msg(*skb); - unsigned int limit = rcvbuf_limit(sk, *skb); - int rc = TIPC_OK; + struct tipc_msg *hdr = buf_msg(skb); + unsigned int limit = rcvbuf_limit(sk, skb); + int err = TIPC_OK; + int usr = msg_user(hdr); - if (unlikely(msg_user(msg) == CONN_MANAGER)) { - tipc_sk_proto_rcv(tsk, *skb); - return TIPC_OK; + if (unlikely(msg_user(hdr) == CONN_MANAGER)) { + tipc_sk_proto_rcv(tsk, skb); + return false; } - if (unlikely(msg_user(msg) == SOCK_WAKEUP)) { - kfree_skb(*skb); + if (unlikely(usr == SOCK_WAKEUP)) { + kfree_skb(skb); tsk->link_cong = 0; sk->sk_write_space(sk); - *skb = NULL; - return TIPC_OK; + return false; } - /* Reject message if it is wrong sort of message for socket */ - if (msg_type(msg) > TIPC_DIRECT_MSG) - return -TIPC_ERR_NO_PORT; + /* Drop if illegal message type */ + if (unlikely(msg_type(hdr) > TIPC_DIRECT_MSG)) { + kfree_skb(skb); + return false; + } - if (sock->state == SS_READY) { - if (msg_connected(msg)) - return -TIPC_ERR_NO_PORT; - } else { - rc = filter_connect(tsk, skb); - if (rc != TIPC_OK || !*skb) - return rc; + /* Reject if wrong message type for current socket state */ + if (unlikely(sock->state == SS_READY)) { + if (msg_connected(hdr)) { + err = TIPC_ERR_NO_PORT; + goto reject; + } + } else if (unlikely(!filter_connect(tsk, skb))) { + err = TIPC_ERR_NO_PORT; + goto reject; } /* Reject message if there isn't room to queue it */ - if (sk_rmem_alloc_get(sk) + (*skb)->truesize >= limit) - return -TIPC_ERR_OVERLOAD; + if (unlikely(sk_rmem_alloc_get(sk) + skb->truesize >= limit)) { + err = TIPC_ERR_OVERLOAD; + goto reject; + } /* Enqueue message */ - TIPC_SKB_CB(*skb)->handle = NULL; - __skb_queue_tail(&sk->sk_receive_queue, *skb); - skb_set_owner_r(*skb, sk); + TIPC_SKB_CB(skb)->handle = NULL; + __skb_queue_tail(&sk->sk_receive_queue, skb); + skb_set_owner_r(skb, sk); sk->sk_data_ready(sk); - *skb = NULL; - return TIPC_OK; + return true; + +reject: + tipc_sk_respond(sk, skb, err); + return false; } /** @@ -1698,22 +1706,10 @@ static int filter_rcv(struct sock *sk, struct sk_buff **skb) */ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) { - int err; - atomic_t *dcnt; - u32 dnode = msg_prevnode(buf_msg(skb)); - struct tipc_sock *tsk = tipc_sk(sk); - struct net *net = sock_net(sk); - uint truesize = skb->truesize; + unsigned int truesize = skb->truesize; - err = filter_rcv(sk, &skb); - if (likely(!skb)) { - dcnt = &tsk->dupl_rcvcnt; - if (atomic_read(dcnt) < TIPC_CONN_OVERLOAD_LIMIT) - atomic_add(truesize, dcnt); - return 0; - } - if (!err || tipc_msg_reverse(tsk_own_node(tsk), &skb, -err)) - tipc_node_xmit_skb(net, skb, dnode, tsk->portid); + if (likely(filter_rcv(sk, skb))) + atomic_add(truesize, &tipc_sk(sk)->dupl_rcvcnt); return 0; } @@ -1723,45 +1719,43 @@ static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb) * @inputq: list of incoming buffers with potentially different destinations * @sk: socket where the buffers should be enqueued * @dport: port number for the socket - * @_skb: returned buffer to be forwarded or rejected, if applicable * * Caller must hold socket lock - * - * Returns TIPC_OK if all buffers enqueued, otherwise -TIPC_ERR_OVERLOAD - * or -TIPC_ERR_NO_PORT */ -static int tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, - u32 dport, struct sk_buff **_skb) +static void tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, + u32 dport) { unsigned int lim; atomic_t *dcnt; - int err; struct sk_buff *skb; unsigned long time_limit = jiffies + 2; while (skb_queue_len(inputq)) { if (unlikely(time_after_eq(jiffies, time_limit))) - return TIPC_OK; + return; + skb = tipc_skb_dequeue(inputq, dport); if (unlikely(!skb)) - return TIPC_OK; + return; + + /* Add message directly to receive queue if possible */ if (!sock_owned_by_user(sk)) { - err = filter_rcv(sk, &skb); - if (likely(!skb)) - continue; - *_skb = skb; - return err; + filter_rcv(sk, skb); + continue; } + + /* Try backlog, compensating for double-counted bytes */ dcnt = &tipc_sk(sk)->dupl_rcvcnt; if (sk->sk_backlog.len) atomic_set(dcnt, 0); lim = rcvbuf_limit(sk, skb) + atomic_read(dcnt); if (likely(!sk_add_backlog(sk, skb, lim))) continue; - *_skb = skb; - return -TIPC_ERR_OVERLOAD; + + /* Overload => reject message back to sender */ + tipc_sk_respond(sk, skb, TIPC_ERR_OVERLOAD); + break; } - return TIPC_OK; } /** @@ -1769,51 +1763,46 @@ static int tipc_sk_enqueue(struct sk_buff_head *inputq, struct sock *sk, * @inputq: buffer list containing the buffers * Consumes all buffers in list until inputq is empty * Note: may be called in multiple threads referring to the same queue - * Returns 0 if last buffer was accepted, otherwise -EHOSTUNREACH - * Only node local calls check the return value, sending single-buffer queues */ -int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) +void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq) { u32 dnode, dport = 0; int err; - struct sk_buff *skb; struct tipc_sock *tsk; - struct tipc_net *tn; struct sock *sk; + struct sk_buff *skb; while (skb_queue_len(inputq)) { - err = -TIPC_ERR_NO_PORT; - skb = NULL; dport = tipc_skb_peek_port(inputq, dport); tsk = tipc_sk_lookup(net, dport); + if (likely(tsk)) { sk = &tsk->sk; if (likely(spin_trylock_bh(&sk->sk_lock.slock))) { - err = tipc_sk_enqueue(inputq, sk, dport, &skb); + tipc_sk_enqueue(inputq, sk, dport); spin_unlock_bh(&sk->sk_lock.slock); - dport = 0; } sock_put(sk); - } else { - skb = tipc_skb_dequeue(inputq, dport); - } - if (likely(!skb)) continue; - if (tipc_msg_lookup_dest(net, skb, &dnode, &err)) - goto xmit; - if (!err) { - dnode = msg_destnode(buf_msg(skb)); - goto xmit; - } else { - dnode = msg_prevnode(buf_msg(skb)); } - tn = net_generic(net, tipc_net_id); - if (!tipc_msg_reverse(tn->own_addr, &skb, -err)) + + /* No destination socket => dequeue skb if still there */ + skb = tipc_skb_dequeue(inputq, dport); + if (!skb) + return; + + /* Try secondary lookup if unresolved named message */ + err = TIPC_ERR_NO_PORT; + if (tipc_msg_lookup_dest(net, skb, &err)) + goto xmit; + + /* Prepare for message rejection */ + if (!tipc_msg_reverse(tipc_own_addr(net), &skb, err)) continue; xmit: + dnode = msg_destnode(buf_msg(skb)); tipc_node_xmit_skb(net, skb, dnode, dport); } - return err ? -EHOSTUNREACH : 0; } static int tipc_wait_for_connect(struct socket *sock, long *timeo_p) @@ -2082,7 +2071,10 @@ static int tipc_shutdown(struct socket *sock, int how) struct net *net = sock_net(sk); struct tipc_sock *tsk = tipc_sk(sk); struct sk_buff *skb; - u32 dnode; + u32 dnode = tsk_peer_node(tsk); + u32 dport = tsk_peer_port(tsk); + u32 onode = tipc_own_addr(net); + u32 oport = tsk->portid; int res; if (how != SHUT_RDWR) @@ -2108,9 +2100,8 @@ restart: } else { skb = tipc_msg_create(TIPC_CRITICAL_IMPORTANCE, TIPC_CONN_MSG, SHORT_H_SIZE, - 0, dnode, tsk_own_node(tsk), - tsk_peer_port(tsk), - tsk->portid, TIPC_CONN_SHUTDOWN); + 0, dnode, onode, dport, oport, + TIPC_CONN_SHUTDOWN); tipc_node_xmit_skb(net, skb, dnode, tsk->portid); } tsk->connected = 0; diff --git a/net/tipc/socket.h b/net/tipc/socket.h index bf6551389522d..4241f22069dc9 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h @@ -44,7 +44,7 @@ SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE)) int tipc_socket_init(void); void tipc_socket_stop(void); -int tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); +void tipc_sk_rcv(struct net *net, struct sk_buff_head *inputq); void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, struct sk_buff_head *inputq); void tipc_sk_reinit(struct net *net); -- GitLab From 6b6948dda798637aea237df0d0c8bcba8fa653bc Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Wed, 22 Jul 2015 17:08:42 +0200 Subject: [PATCH 1686/7006] vxlan: Use proper endian type for vni in vxlan[6]_xmit_skb Silences the following sparse warnings: drivers/net/vxlan.c:1818:21: warning: incorrect type in assignment (different base types) drivers/net/vxlan.c:1818:21: expected restricted __be32 [usertype] vx_vni drivers/net/vxlan.c:1818:21: got unsigned int [unsigned] [usertype] vni drivers/net/vxlan.c:2014:58: warning: incorrect type in argument 11 (different base types) drivers/net/vxlan.c:2014:58: expected unsigned int [unsigned] [usertype] vni drivers/net/vxlan.c:2014:58: got restricted __be32 [usertype] Fixes: 614732eaa12d ("openvswitch: Use regular VXLAN net_device device") Reported-by: kbuild test robot Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e9feefb41f0b4..81f0f24b2cfb1 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1686,7 +1686,7 @@ static int vxlan6_xmit_skb(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb, struct net_device *dev, struct in6_addr *saddr, struct in6_addr *daddr, __u8 prio, __u8 ttl, - __be16 src_port, __be16 dst_port, __u32 vni, + __be16 src_port, __be16 dst_port, __be32 vni, struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; @@ -1771,7 +1771,7 @@ err: static int vxlan_xmit_skb(struct rtable *rt, struct sock *sk, struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df, - __be16 src_port, __be16 dst_port, __u32 vni, + __be16 src_port, __be16 dst_port, __be32 vni, struct vxlan_metadata *md, bool xnet, u32 vxflags) { struct vxlanhdr *vxh; -- GitLab From 402b764533e9d973952573df7ff96c41189e1a14 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Wed, 22 Jul 2015 22:54:50 +0530 Subject: [PATCH 1687/7006] cxgb4: Allow firmware flash, only if cxgb4 is the master driver Adapter can go for a toss, if cxgb4 is loaded as slave and we try to upgrade the firmware. So add a check for the same before flashing firmware using ethtool. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c index 687acf71fa15e..5eedb98ff581a 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_ethtool.c @@ -925,6 +925,20 @@ static int set_flash(struct net_device *netdev, struct ethtool_flash *ef) const struct firmware *fw; struct adapter *adap = netdev2adap(netdev); unsigned int mbox = PCIE_FW_MASTER_M + 1; + u32 pcie_fw; + unsigned int master; + u8 master_vld = 0; + + pcie_fw = t4_read_reg(adap, PCIE_FW_A); + master = PCIE_FW_MASTER_G(pcie_fw); + if (pcie_fw & PCIE_FW_MASTER_VLD_F) + master_vld = 1; + /* if csiostor is the master return */ + if (master_vld && (master != adap->pf)) { + dev_warn(adap->pdev_dev, + "cxgb4 driver needs to be loaded as MASTER to support FW flash\n"); + return -EOPNOTSUPP; + } ef->data[sizeof(ef->data) - 1] = '\0'; ret = request_firmware(&fw, ef->data, adap->pdev_dev); -- GitLab From b3e6b82a0099dfef038e40c630a554ed1e402504 Mon Sep 17 00:00:00 2001 From: KY Srinivasan Date: Wed, 22 Jul 2015 11:42:32 -0700 Subject: [PATCH 1688/7006] hv_netvsc: Wait for sub-channels to be processed during probe The current code returns from probe without waiting for the proper handling of subchannels that may be requested. If the netvsc driver were to be rapidly loaded/unloaded, we can trigger a panic as the unload will be tearing down state that may not have been fully setup yet. We fix this issue by making sure that we return from the probe call only after ensuring that the sub-channel offers in flight are properly handled. Reviewed-and-tested-by: Haiyang Zhang Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 2 ++ drivers/net/hyperv/rndis_filter.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 26cd14ccf4d56..925b75d4d9103 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -671,6 +671,8 @@ struct netvsc_device { u32 send_table[VRSS_SEND_TAB_SIZE]; u32 max_chn; u32 num_chn; + spinlock_t sc_lock; /* Protects num_sc_offered variable */ + u32 num_sc_offered; atomic_t queue_sends[NR_CPUS]; /* Holds rndis device info */ diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c index 2e40417a80878..9b8263db49cc3 100644 --- a/drivers/net/hyperv/rndis_filter.c +++ b/drivers/net/hyperv/rndis_filter.c @@ -984,9 +984,16 @@ static void netvsc_sc_open(struct vmbus_channel *new_sc) struct netvsc_device *nvscdev; u16 chn_index = new_sc->offermsg.offer.sub_channel_index; int ret; + unsigned long flags; nvscdev = hv_get_drvdata(new_sc->primary_channel->device_obj); + spin_lock_irqsave(&nvscdev->sc_lock, flags); + nvscdev->num_sc_offered--; + spin_unlock_irqrestore(&nvscdev->sc_lock, flags); + if (nvscdev->num_sc_offered == 0) + complete(&nvscdev->channel_init_wait); + if (chn_index >= nvscdev->num_chn) return; @@ -1015,8 +1022,10 @@ int rndis_filter_device_add(struct hv_device *dev, u32 rsscap_size = sizeof(struct ndis_recv_scale_cap); u32 mtu, size; u32 num_rss_qs; + u32 sc_delta; const struct cpumask *node_cpu_mask; u32 num_possible_rss_qs; + unsigned long flags; rndis_device = get_rndis_device(); if (!rndis_device) @@ -1039,6 +1048,8 @@ int rndis_filter_device_add(struct hv_device *dev, net_device->max_chn = 1; net_device->num_chn = 1; + spin_lock_init(&net_device->sc_lock); + net_device->extension = rndis_device; rndis_device->net_dev = net_device; @@ -1116,6 +1127,9 @@ int rndis_filter_device_add(struct hv_device *dev, num_possible_rss_qs = cpumask_weight(node_cpu_mask); net_device->num_chn = min(num_possible_rss_qs, num_rss_qs); + num_rss_qs = net_device->num_chn - 1; + net_device->num_sc_offered = num_rss_qs; + if (net_device->num_chn == 1) goto out; @@ -1157,11 +1171,25 @@ int rndis_filter_device_add(struct hv_device *dev, ret = rndis_filter_set_rss_param(rndis_device, net_device->num_chn); + /* + * Wait for the host to send us the sub-channel offers. + */ + spin_lock_irqsave(&net_device->sc_lock, flags); + sc_delta = num_rss_qs - (net_device->num_chn - 1); + net_device->num_sc_offered -= sc_delta; + spin_unlock_irqrestore(&net_device->sc_lock, flags); + + while (net_device->num_sc_offered != 0) { + t = wait_for_completion_timeout(&net_device->channel_init_wait, 10*HZ); + if (t == 0) + WARN(1, "Netvsc: Waiting for sub-channel processing"); + } out: if (ret) { net_device->max_chn = 1; net_device->num_chn = 1; } + return 0; /* return 0 because primary channel can be used alone */ err_dev_remv: -- GitLab From 7d5d3075b5910cff7b33a68d3b065566fece4ba1 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 22 Jul 2015 17:28:23 -0700 Subject: [PATCH 1689/7006] net: bcmgenet: Remove checks on clock handles Instead of multiplying the number of checks for IS_ERR(priv->clk), simply NULLify the 'struct clk' pointer which is something the Linux common clock framework perfectly deals with and does early return for each and every single clk_* API functions. Having every single function check for !IS_ERR(priv->clk) is both redundant and error prone, as it turns out, we were doing it for the main GENET clock: priv->clk, but not for the Wake-on-LAN or EEE clock, so let's just be consistent here. Signed-off-by: Florian Fainelli Acked-by: Petri Gynther Signed-off-by: David S. Miller --- .../net/ethernet/broadcom/genet/bcmgenet.c | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmgenet.c b/drivers/net/ethernet/broadcom/genet/bcmgenet.c index 5bf7ce0ae2215..c6f2d396edf0a 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmgenet.c +++ b/drivers/net/ethernet/broadcom/genet/bcmgenet.c @@ -2625,8 +2625,7 @@ static int bcmgenet_open(struct net_device *dev) netif_dbg(priv, ifup, dev, "bcmgenet_open\n"); /* Turn on the clock */ - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); + clk_prepare_enable(priv->clk); /* If this is an internal GPHY, power it back on now, before UniMAC is * brought out of reset as absolutely no UniMAC activity is allowed @@ -2703,8 +2702,7 @@ err_irq0: err_fini_dma: bcmgenet_fini_dma(priv); err_clk_disable: - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -2761,8 +2759,7 @@ static int bcmgenet_close(struct net_device *dev) if (priv->internal_phy) ret = bcmgenet_power_down(priv, GENET_POWER_PASSIVE); - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); return ret; } @@ -3215,11 +3212,12 @@ static int bcmgenet_probe(struct platform_device *pdev) priv->version = pd->genet_version; priv->clk = devm_clk_get(&priv->pdev->dev, "enet"); - if (IS_ERR(priv->clk)) + if (IS_ERR(priv->clk)) { dev_warn(&priv->pdev->dev, "failed to get enet clock\n"); + priv->clk = NULL; + } - if (!IS_ERR(priv->clk)) - clk_prepare_enable(priv->clk); + clk_prepare_enable(priv->clk); bcmgenet_set_hw_params(priv); @@ -3230,8 +3228,10 @@ static int bcmgenet_probe(struct platform_device *pdev) INIT_WORK(&priv->bcmgenet_irq_work, bcmgenet_irq_task); priv->clk_wol = devm_clk_get(&priv->pdev->dev, "enet-wol"); - if (IS_ERR(priv->clk_wol)) + if (IS_ERR(priv->clk_wol)) { dev_warn(&priv->pdev->dev, "failed to get enet-wol clock\n"); + priv->clk_wol = NULL; + } priv->clk_eee = devm_clk_get(&priv->pdev->dev, "enet-eee"); if (IS_ERR(priv->clk_eee)) { @@ -3257,8 +3257,7 @@ static int bcmgenet_probe(struct platform_device *pdev) netif_carrier_off(dev); /* Turn off the main clock, WOL clock is handled separately */ - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); err = register_netdev(dev); if (err) @@ -3267,8 +3266,7 @@ static int bcmgenet_probe(struct platform_device *pdev) return err; err_clk_disable: - if (!IS_ERR(priv->clk)) - clk_disable_unprepare(priv->clk); + clk_disable_unprepare(priv->clk); err: free_netdev(dev); return err; -- GitLab From 6ac9de5f656352b24ab2cb3e925f078c8c809a19 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Wed, 22 Jul 2015 17:29:53 -0700 Subject: [PATCH 1690/7006] net: bcmgenet: Register link_update callback for all MoCA PHYs Commit 8d88c6ebb34c ("net: bcmgenet: enable MoCA link state change detection") added a fixed PHY link_update callback for MoCA PHYs when registered using platform_data exclusively, this change is also applicable to systems using Device Tree as their primary configuration interface. In order for this to work, move the link_update assignment into bcmgenet_moca_phy_setup() where we know for sure that we are running on a MoCA GENET instance, and do not override phydev->link since this is: - properly taken care of by the PHY library by getting the link UP/DOWN interrupts - this now runs everytime we call bcmgenet_open(), so we need to preserve whatever we detected before we went administratively DOWN and then UP - we need to make sure that MoCA PHYs start with a link DOWN during probe in order to force a link transition to occur To avoid a forward declaration, move bcmgenet_fixed_phy_link_update() above its caller. Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/genet/bcmmii.c | 37 ++++++++++++-------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index 0802cd9d2424f..b3679ad1c1c73 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -163,6 +163,15 @@ void bcmgenet_mii_setup(struct net_device *dev) phy_print_status(phydev); } +static int bcmgenet_fixed_phy_link_update(struct net_device *dev, + struct fixed_phy_status *status) +{ + if (dev && dev->phydev && status) + status->link = dev->phydev->link; + + return 0; +} + void bcmgenet_phy_power_set(struct net_device *dev, bool enable) { struct bcmgenet_priv *priv = netdev_priv(dev); @@ -215,6 +224,10 @@ static void bcmgenet_moca_phy_setup(struct bcmgenet_priv *priv) reg = bcmgenet_sys_readl(priv, SYS_PORT_CTRL); reg |= LED_ACT_SOURCE_MAC; bcmgenet_sys_writel(priv, reg, SYS_PORT_CTRL); + + if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) + fixed_phy_set_link_update(priv->phydev, + bcmgenet_fixed_phy_link_update); } int bcmgenet_mii_config(struct net_device *dev) @@ -460,6 +473,7 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) struct device_node *dn = priv->pdev->dev.of_node; struct device *kdev = &priv->pdev->dev; const char *phy_mode_str = NULL; + struct phy_device *phydev = NULL; char *compat; int phy_mode; int ret; @@ -515,14 +529,12 @@ static int bcmgenet_mii_of_init(struct bcmgenet_priv *priv) priv->internal_phy = true; } - return 0; -} - -static int bcmgenet_fixed_phy_link_update(struct net_device *dev, - struct fixed_phy_status *status) -{ - if (dev && dev->phydev && status) - status->link = dev->phydev->link; + /* Make sure we initialize MoCA PHYs with a link down */ + if (phy_mode == PHY_INTERFACE_MODE_MOCA) { + phydev = of_phy_find_device(dn); + if (phydev) + phydev->link = 0; + } return 0; } @@ -579,12 +591,9 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) return -ENODEV; } - if (priv->hw_params->flags & GENET_HAS_MOCA_LINK_DET) { - ret = fixed_phy_set_link_update( - phydev, bcmgenet_fixed_phy_link_update); - if (!ret) - phydev->link = 0; - } + /* Make sure we initialize MoCA PHYs with a link down */ + phydev->link = 0; + } priv->phydev = phydev; -- GitLab From 48fb6b554501914b6befcf9b38292cbeb91de330 Mon Sep 17 00:00:00 2001 From: Wei-Chun Chao Date: Wed, 22 Jul 2015 18:13:12 -0700 Subject: [PATCH 1691/7006] ipv6: fix crash over flow-based vxlan device Similar check was added in ip_rcv but not in ipv6_rcv. BUG: unable to handle kernel NULL pointer dereference at (null) IP: [] ipv6_rcv+0xfa/0x500 Call Trace: [] ? ip_rcv+0x296/0x400 [] ? packet_rcv+0x52/0x410 [] __netif_receive_skb_core+0x63f/0x9a0 [] ? br_handle_frame_finish+0x580/0x580 [bridge] [] ? update_rq_clock.part.81+0x1c/0x40 [] __netif_receive_skb+0x18/0x60 [] process_backlog+0x9f/0x150 Fixes: ee122c79d422 (vxlan: Flow based tunneling) Signed-off-by: Wei-Chun Chao Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/ipv6/ip6_input.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 57990c929cd81..adba03ac7ce96 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -45,6 +45,7 @@ #include #include #include +#include int ip6_rcv_finish(struct sock *sk, struct sk_buff *skb) { @@ -55,7 +56,7 @@ int ip6_rcv_finish(struct sock *sk, struct sk_buff *skb) if (ipprot && ipprot->early_demux) ipprot->early_demux(skb); } - if (!skb_dst(skb)) + if (!skb_valid_dst(skb)) ip6_route_input(skb); return dst_input(skb); @@ -98,7 +99,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt * arrived via the sending interface (ethX), because of the * nature of scoping architecture. --yoshfuji */ - IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; + IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) goto err; -- GitLab From 88f643203668b95b884b60b45ff182289153843c Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Thu, 23 Jul 2015 10:39:35 +0300 Subject: [PATCH 1692/7006] ipv4: be more aggressive when probing alternative gateways Currently, we do not notice if new alternative gateways are added. We can do it by checking for present neigh entry. Also, gateways that are currently probed (NUD_INCOMPLETE) can be skipped from round-robin probing. Suggested-by: Florian Westphal Signed-off-by: Julian Anastasov Signed-off-by: David S. Miller --- net/ipv4/fib_semantics.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 6754c64b2fe00..d4c6732cfbfa6 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -438,13 +438,15 @@ static int fib_detect_death(struct fib_info *fi, int order, if (n) { state = n->nud_state; neigh_release(n); + } else { + return 0; } if (state == NUD_REACHABLE) return 0; if ((state & NUD_VALID) && order != dflt) return 0; if ((state & NUD_VALID) || - (*last_idx < 0 && order > dflt)) { + (*last_idx < 0 && order > dflt && state != NUD_INCOMPLETE)) { *last_resort = fi; *last_idx = order; } -- GitLab From 2661371ace963280f34fe583d4a6697afecd87d5 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 23 Jul 2015 11:29:07 +0200 Subject: [PATCH 1693/7006] openvswitch: fix compilation when vxlan is a module With CONFIG_VXLAN=m and CONFIG_OPENVSWITCH=y, there was the following compilation error: LD init/built-in.o net/built-in.o: In function `vxlan_tnl_create': .../net/openvswitch/vport-netdev.c:322: undefined reference to `vxlan_dev_create' make: *** [vmlinux] Error 1 CC: Thomas Graf Fixes: 614732eaa12d ("openvswitch: Use regular VXLAN net_device device") Signed-off-by: Nicolas Dichtel Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/openvswitch/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 1119f46b80b4f..6ed1d2da9fcd2 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig @@ -5,6 +5,7 @@ config OPENVSWITCH tristate "Open vSwitch" depends on INET + depends on VXLAN select LIBCRC32C select MPLS select NET_MPLS_GSO -- GitLab From 9ece39ab9a91aa37090c8fbfe64c240f27ad9f1a Mon Sep 17 00:00:00 2001 From: Harini Katakam Date: Thu, 23 Jul 2015 15:44:25 +0530 Subject: [PATCH 1694/7006] net: macb: Change capability mask for jumbo support JUMBO and NO_GIGABIT_HALF have the same capability masks. Change one of them. Signed-off-by: Harini Katakam Acked-by: Nicolas Ferre Acked-by: Alexandre Belloni Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/macb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h index d74655993d4bf..8fb80b2dcf826 100644 --- a/drivers/net/ethernet/cadence/macb.h +++ b/drivers/net/ethernet/cadence/macb.h @@ -399,7 +399,7 @@ #define MACB_CAPS_GIGABIT_MODE_AVAILABLE 0x20000000 #define MACB_CAPS_SG_DISABLED 0x40000000 #define MACB_CAPS_MACB_IS_GEM 0x80000000 -#define MACB_CAPS_JUMBO 0x00000008 +#define MACB_CAPS_JUMBO 0x00000010 /* Bit manipulation macros */ #define MACB_BIT(name) \ -- GitLab From 597798e438371128519fa94dacdc42311b4254a6 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Thu, 23 Jul 2015 13:04:44 +0200 Subject: [PATCH 1695/7006] openvswitch: Retrieve tunnel metadata when receiving from vport-netdev Retrieve the tunnel metadata for packets received by a net_device and provide it to ovs_vport_receive() for flow key extraction. [This hunk was in the GRE patch in the initial series and missed the cut for the initial submission for merging.] Fixes: 614732eaa12d ("openvswitch: Use regular VXLAN net_device device") Signed-off-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/vport-netdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index 68d0582fc0016..2254b742168f9 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -58,7 +58,7 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) skb_push(skb, ETH_HLEN); ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); - ovs_vport_receive(vport, skb, NULL); + ovs_vport_receive(vport, skb, skb_tunnel_info(skb, AF_INET)); return; error: -- GitLab From 949f1e39a6177503349ef8adeedd13fa1c89e5dd Mon Sep 17 00:00:00 2001 From: Satish Ashok Date: Thu, 23 Jul 2015 05:00:53 -0700 Subject: [PATCH 1696/7006] bridge: mdb: notify on router port add and del Send notifications on router port add and del/expire, re-use the already existing MDBA_ROUTER and send NEWMDB/DELMDB netlink notifications respectively. Signed-off-by: Satish Ashok Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_mdb.c | 67 +++++++++++++++++++++++++++++++++++++++ net/bridge/br_multicast.c | 10 ++++-- net/bridge/br_private.h | 2 ++ 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 6a591e6e2d04a..5e9d1c5e11948 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c @@ -247,6 +247,73 @@ void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, __br_mdb_notify(dev, &entry, type); } +static int nlmsg_populate_rtr_fill(struct sk_buff *skb, + struct net_device *dev, + int ifindex, u32 pid, + u32 seq, int type, unsigned int flags) +{ + struct br_port_msg *bpm; + struct nlmsghdr *nlh; + struct nlattr *nest; + + nlh = nlmsg_put(skb, pid, seq, type, sizeof(*bpm), NLM_F_MULTI); + if (!nlh) + return -EMSGSIZE; + + bpm = nlmsg_data(nlh); + memset(bpm, 0, sizeof(*bpm)); + bpm->family = AF_BRIDGE; + bpm->ifindex = dev->ifindex; + nest = nla_nest_start(skb, MDBA_ROUTER); + if (!nest) + goto cancel; + + if (nla_put_u32(skb, MDBA_ROUTER_PORT, ifindex)) + goto end; + + nla_nest_end(skb, nest); + nlmsg_end(skb, nlh); + return 0; + +end: + nla_nest_end(skb, nest); +cancel: + nlmsg_cancel(skb, nlh); + return -EMSGSIZE; +} + +static inline size_t rtnl_rtr_nlmsg_size(void) +{ + return NLMSG_ALIGN(sizeof(struct br_port_msg)) + + nla_total_size(sizeof(__u32)); +} + +void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port, + int type) +{ + struct net *net = dev_net(dev); + struct sk_buff *skb; + int err = -ENOBUFS; + int ifindex; + + ifindex = port ? port->dev->ifindex : 0; + skb = nlmsg_new(rtnl_rtr_nlmsg_size(), GFP_ATOMIC); + if (!skb) + goto errout; + + err = nlmsg_populate_rtr_fill(skb, dev, ifindex, 0, 0, type, NTF_SELF); + if (err < 0) { + kfree_skb(skb); + goto errout; + } + + rtnl_notify(skb, net, 0, RTNLGRP_MDB, NULL, GFP_ATOMIC); + return; + +errout: + rtnl_set_sk_err(net, RTNLGRP_MDB, err); +} + static bool is_valid_mdb_entry(struct br_mdb_entry *entry) { if (entry->ifindex == 0) diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index ed5dc684a4cef..fd238587e0329 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -766,6 +766,7 @@ static void br_multicast_router_expired(unsigned long data) goto out; hlist_del_init_rcu(&port->rlist); + br_rtr_notify(br->dev, port, RTM_DELMDB); out: spin_unlock(&br->multicast_lock); @@ -977,8 +978,10 @@ void br_multicast_disable_port(struct net_bridge_port *port) if (pg->state == MDB_TEMPORARY) br_multicast_del_pg(br, pg); - if (!hlist_unhashed(&port->rlist)) + if (!hlist_unhashed(&port->rlist)) { hlist_del_init_rcu(&port->rlist); + br_rtr_notify(br->dev, port, RTM_DELMDB); + } del_timer(&port->multicast_router_timer); del_timer(&port->ip4_own_query.timer); #if IS_ENABLED(CONFIG_IPV6) @@ -1216,6 +1219,7 @@ static void br_multicast_add_router(struct net_bridge *br, hlist_add_behind_rcu(&port->rlist, slot); else hlist_add_head_rcu(&port->rlist, &br->router_list); + br_rtr_notify(br->dev, port, RTM_NEWMDB); } static void br_multicast_mark_router(struct net_bridge *br, @@ -1848,8 +1852,10 @@ int br_multicast_set_port_router(struct net_bridge_port *p, unsigned long val) p->multicast_router = val; err = 0; - if (val < 2 && !hlist_unhashed(&p->rlist)) + if (val < 2 && !hlist_unhashed(&p->rlist)) { hlist_del_init_rcu(&p->rlist); + br_rtr_notify(br->dev, p, RTM_DELMDB); + } if (val == 1) break; diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 3ad1290528af5..e2cb359f9dd32 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -490,6 +490,8 @@ void br_mdb_init(void); void br_mdb_uninit(void); void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port, struct br_ip *group, int type, u8 state); +void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port, + int type); #define mlock_dereference(X, br) \ rcu_dereference_protected(X, lockdep_is_held(&br->multicast_lock)) -- GitLab From f0322f7f1e2165fbf83530a424ef6ebeacbf4bca Mon Sep 17 00:00:00 2001 From: Anshuman Khandual Date: Tue, 30 Jun 2015 13:50:28 +0530 Subject: [PATCH 1697/7006] powerpc/perf: Change type of the bhrb_users variable This patch just changes data type of bhrb_users variable from int to unsigned int because it never contains a negative value. Reported-by: Daniel Axtens Signed-off-by: Anshuman Khandual Signed-off-by: Michael Ellerman --- arch/powerpc/perf/core-book3s.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index d90893b76e7ce..b0382f3f10955 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -53,7 +53,7 @@ struct cpu_hw_events { /* BHRB bits */ u64 bhrb_filter; /* BHRB HW branch filter */ - int bhrb_users; + unsigned int bhrb_users; void *bhrb_context; struct perf_branch_stack bhrb_stack; struct perf_branch_entry bhrb_entries[BHRB_MAX_ENTRIES]; @@ -369,8 +369,8 @@ static void power_pmu_bhrb_disable(struct perf_event *event) if (!ppmu->bhrb_nr) return; + WARN_ON_ONCE(!cpuhw->bhrb_users); cpuhw->bhrb_users--; - WARN_ON_ONCE(cpuhw->bhrb_users < 0); perf_sched_cb_dec(event->ctx->pmu); if (!cpuhw->disabled && !cpuhw->bhrb_users) { -- GitLab From e0910bace663b78c026b73bbd711a24ccf410531 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Thu, 23 Jul 2015 15:43:56 +0200 Subject: [PATCH 1698/7006] lwtunnel: export linux/lwtunnel.h to userspace Note also that include/linux/lwtunnel.h is not needed. CC: Thomas Graf CC: Roopa Prabhu Fixes: 499a24256862 ("lwtunnel: infrastructure for handling light weight tunnels like mpls") Signed-off-by: Nicolas Dichtel Acked-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/linux/lwtunnel.h | 6 ------ include/uapi/linux/Kbuild | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 include/linux/lwtunnel.h diff --git a/include/linux/lwtunnel.h b/include/linux/lwtunnel.h deleted file mode 100644 index 97f32f8b4ae13..0000000000000 --- a/include/linux/lwtunnel.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_LWTUNNEL_H_ -#define _LINUX_LWTUNNEL_H_ - -#include - -#endif /* _LINUX_LWTUNNEL_H_ */ diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 1ff9942718fee..aafb9937b162b 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -243,6 +243,7 @@ header-y += limits.h header-y += llc.h header-y += loop.h header-y += lp.h +header-y += lwtunnel.h header-y += magic.h header-y += major.h header-y += map_to_7segment.h -- GitLab From ea6f82fe37319675e271dd6b55fb37731eef0e46 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 23 Jul 2015 22:41:14 +0530 Subject: [PATCH 1699/7006] cxgb4vf: Read correct FL congestion threshold for T5 and T6 VF driver was reading incorrect freelist congestion notification threshold for FLM queues when packing is enabled for T5 and T6 adapter. Fixing it now. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4_regs.h | 5 +++++ drivers/net/ethernet/chelsio/cxgb4vf/sge.c | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h index 375a825573b0e..ed8a8f3501139 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h @@ -338,6 +338,11 @@ #define EGRTHRESHOLDPACKING_G(x) \ (((x) >> EGRTHRESHOLDPACKING_S) & EGRTHRESHOLDPACKING_M) +#define T6_EGRTHRESHOLDPACKING_S 16 +#define T6_EGRTHRESHOLDPACKING_M 0xffU +#define T6_EGRTHRESHOLDPACKING_G(x) \ + (((x) >> T6_EGRTHRESHOLDPACKING_S) & T6_EGRTHRESHOLDPACKING_M) + #define SGE_TIMESTAMP_LO_A 0x1098 #define SGE_TIMESTAMP_HI_A 0x109c diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c index 1d5e77a566e16..fa3786a9d30ea 100644 --- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c @@ -2668,8 +2668,22 @@ int t4vf_sge_init(struct adapter *adapter) * give it more Free List entries. (Note that the SGE's Egress * Congestion Threshold is in units of 2 Free List pointers.) */ - s->fl_starve_thres - = EGRTHRESHOLD_G(sge_params->sge_congestion_control)*2 + 1; + switch (CHELSIO_CHIP_VERSION(adapter->params.chip)) { + case CHELSIO_T4: + s->fl_starve_thres = + EGRTHRESHOLD_G(sge_params->sge_congestion_control); + break; + case CHELSIO_T5: + s->fl_starve_thres = + EGRTHRESHOLDPACKING_G(sge_params->sge_congestion_control); + break; + case CHELSIO_T6: + default: + s->fl_starve_thres = + T6_EGRTHRESHOLDPACKING_G(sge_params->sge_congestion_control); + break; + } + s->fl_starve_thres = s->fl_starve_thres * 2 + 1; /* * Set up tasklet timers. -- GitLab From c0f54edbe26fbe8194d7e72c24c49f7b1c9c547f Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:19 -0400 Subject: [PATCH 1700/7006] net: netcp: Fixes the use of spin_lock_bh in timer function This patch fixes a bug in which the timer routine synchronized against the ethtool-triggered statistics updates with spin_lock_bh(). A timer function is itself a bottom-half, so this should be spin_lock(). Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 9b7e0a34c98b1..cabf97728b2dc 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2189,14 +2189,15 @@ static void netcp_ethss_timer(unsigned long arg) netcp_ethss_update_link_state(gbe_dev, slave, NULL); } - spin_lock_bh(&gbe_dev->hw_stats_lock); + /* A timer runs as a BH, no need to block them */ + spin_lock(&gbe_dev->hw_stats_lock); if (gbe_dev->ss_version == GBE_SS_VERSION_14) gbe_update_stats_ver14(gbe_dev, NULL); else gbe_update_stats(gbe_dev, NULL); - spin_unlock_bh(&gbe_dev->hw_stats_lock); + spin_unlock(&gbe_dev->hw_stats_lock); gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL; add_timer(&gbe_dev->timer); -- GitLab From a94bcd09c554e8df3a32ef3f25ecfd74e73b9651 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:20 -0400 Subject: [PATCH 1701/7006] net: netcp: Fixes hw statistics module base setting error This patch fixes error in the setting of the hw statistics module base for K2HK platform. In K2HK although there are 4 hw statistics modules, but only 2 are visible at a time. Thus when setting up the pointers to the base of the corresponding hw statistics modules, modules 0 and 2 should point to one base, while modules 1 and 3 should point to the other. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index cabf97728b2dc..b954856f11981 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -2675,10 +2675,14 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; + /* K2HK has only 2 hw stats modules visible at a time, so + * module 0 & 2 points to one base and + * module 1 & 3 points to the other base + */ for (i = 0; i < gbe_dev->max_num_slaves; i++) { gbe_dev->hw_stats_regs[i] = gbe_dev->switch_regs + GBE13_HW_STATS_OFFSET + - (GBE_HW_STATS_REG_MAP_SZ * i); + (GBE_HW_STATS_REG_MAP_SZ * (i & 0x1)); } gbe_dev->ale_reg = gbe_dev->switch_regs + GBE13_ALE_OFFSET; -- GitLab From 208c6b9a49df8b69ab698d9f53d40d25f143dbde Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:21 -0400 Subject: [PATCH 1702/7006] net: netcp: Fixes error in oversized memory allocation for statistics storage The CPSW driver keeps internally some, but not all, of the statistics available in the hw statistics modules. Furthermore, some of the locations in the hw statistics modules are reserved and contain no useful information. Prior to this patch, the driver allocates memory of the size of the the whole hw statistics modules, instead of the size of statistics-entries-interested-in (i.e. et_stats), for internal storage. This patch fixes that. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 46 ++++++++++++--------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index b954856f11981..3976516b9a5ff 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -295,8 +295,6 @@ struct xgbe_hw_stats { u32 rx_dma_overruns; }; -#define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32)) - struct gbenu_ss_regs { u32 id_ver; u32 synce_count; /* NU */ @@ -480,7 +478,6 @@ struct gbenu_hw_stats { u32 tx_pri7_drop_bcnt; }; -#define GBENU_NUM_HW_STAT_ENTRIES (sizeof(struct gbenu_hw_stats) / sizeof(u32)) #define GBENU_HW_STATS_REG_MAP_SZ 0x200 struct gbe_ss_regs { @@ -615,7 +612,6 @@ struct gbe_hw_stats { u32 rx_dma_overruns; }; -#define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32)) #define GBE_MAX_HW_STAT_MODS 9 #define GBE_HW_STATS_REG_MAP_SZ 0x100 @@ -2555,10 +2551,12 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, } gbe_dev->xgbe_serdes_regs = regs; + gbe_dev->et_stats = xgbe10_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - XGBE10_NUM_STAT_ENTRIES * - (gbe_dev->max_num_ports) * sizeof(u64), - GFP_KERNEL); + gbe_dev->num_et_stats * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -2577,8 +2575,6 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = XGBE10_HOST_PORT_NUM; gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES; - gbe_dev->et_stats = xgbe10_et_stats; - gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; /* Subsystem registers */ @@ -2663,10 +2659,12 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, } gbe_dev->switch_regs = regs; + gbe_dev->et_stats = gbe13_et_stats; + gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - GBE13_NUM_HW_STAT_ENTRIES * - gbe_dev->max_num_slaves * sizeof(u64), - GFP_KERNEL); + gbe_dev->num_et_stats * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -2689,8 +2687,6 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBE13_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; - gbe_dev->et_stats = gbe13_et_stats; - gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); gbe_dev->stats_en_mask = GBE13_REG_VAL_STAT_ENABLE_ALL; /* Subsystem registers */ @@ -2717,10 +2713,18 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, void __iomem *regs; int i, ret; + gbe_dev->et_stats = gbenu_et_stats; + + if (IS_SS_ID_NU(gbe_dev)) + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + (gbe_dev->max_num_slaves * GBENU_ET_STATS_PORT_SIZE); + else + gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + + GBENU_ET_STATS_PORT_SIZE; + gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev, - GBENU_NUM_HW_STAT_ENTRIES * - (gbe_dev->max_num_ports) * sizeof(u64), - GFP_KERNEL); + gbe_dev->num_et_stats * sizeof(u64), + GFP_KERNEL); if (!gbe_dev->hw_stats) { dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n"); return -ENOMEM; @@ -2753,16 +2757,8 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, gbe_dev->ale_ports = gbe_dev->max_num_ports; gbe_dev->host_port = GBENU_HOST_PORT_NUM; gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES; - gbe_dev->et_stats = gbenu_et_stats; gbe_dev->stats_en_mask = (1 << (gbe_dev->max_num_ports)) - 1; - if (IS_SS_ID_NU(gbe_dev)) - gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + - (gbe_dev->max_num_slaves * GBENU_ET_STATS_PORT_SIZE); - else - gbe_dev->num_et_stats = GBENU_ET_STATS_HOST_SIZE + - GBENU_ET_STATS_PORT_SIZE; - /* Subsystem registers */ GBENU_SET_REG_OFS(gbe_dev, ss_regs, id_ver); -- GitLab From fbf64c1915b964c05edd4434250fbbb31ded38c6 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:22 -0400 Subject: [PATCH 1703/7006] net: netcp: Consolidates statistics collection code Different Keystone2 platforms have different number and layouts of hw statistics modules. This patch consolidates the statistics processing of different Keystone2 platforms for easy maintenance. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 99 +++++++++++++++------------ 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index 3976516b9a5ff..b06f210c8adaf 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -1550,70 +1550,79 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset) } } -static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) +static inline void gbe_update_hw_stats_entry(struct gbe_priv *gbe_dev, + int et_stats_entry) { void __iomem *base = NULL; u32 __iomem *p; u32 tmp = 0; + + /* The hw_stats_regs pointers are already + * properly set to point to the right base: + */ + base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[et_stats_entry].type]; + p = base + gbe_dev->et_stats[et_stats_entry].offset; + tmp = readl(p); + gbe_dev->hw_stats[et_stats_entry] += tmp; + + /* write-to-decrement: + * new register value = old register value - write value + */ + writel(tmp, p); +} + +static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) +{ int i; for (i = 0; i < gbe_dev->num_et_stats; i++) { - base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[i].type]; - p = base + gbe_dev->et_stats[i].offset; - tmp = readl(p); - gbe_dev->hw_stats[i] = gbe_dev->hw_stats[i] + tmp; + gbe_update_hw_stats_entry(gbe_dev, i); + if (data) data[i] = gbe_dev->hw_stats[i]; - /* write-to-decrement: - * new register value = old register value - write value - */ - writel(tmp, p); } } -static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) +static inline void gbe_stats_mod_visible_ver14(struct gbe_priv *gbe_dev, + int stats_mod) { - void __iomem *gbe_statsa = gbe_dev->hw_stats_regs[0]; - void __iomem *gbe_statsb = gbe_dev->hw_stats_regs[1]; - u64 *hw_stats = &gbe_dev->hw_stats[0]; - void __iomem *base = NULL; - u32 __iomem *p; - u32 tmp = 0, val, pair_size = (gbe_dev->num_et_stats / 2); - int i, j, pair; + u32 val; - for (pair = 0; pair < 2; pair++) { - val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); + val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); - if (pair == 0) - val &= ~GBE_STATS_CD_SEL; - else - val |= GBE_STATS_CD_SEL; + switch (stats_mod) { + case GBE_STATSA_MODULE: + case GBE_STATSB_MODULE: + val &= ~GBE_STATS_CD_SEL; + break; + case GBE_STATSC_MODULE: + case GBE_STATSD_MODULE: + val |= GBE_STATS_CD_SEL; + break; + default: + return; + } + + /* make the stat module visible */ + writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); +} - /* make the stat modules visible */ - writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); +static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) +{ + u32 half_num_et_stats = (gbe_dev->num_et_stats / 2); + int et_entry, j, pair; - for (i = 0; i < pair_size; i++) { - j = pair * pair_size + i; - switch (gbe_dev->et_stats[j].type) { - case GBE_STATSA_MODULE: - case GBE_STATSC_MODULE: - base = gbe_statsa; - break; - case GBE_STATSB_MODULE: - case GBE_STATSD_MODULE: - base = gbe_statsb; - break; - } + for (pair = 0; pair < 2; pair++) { + gbe_stats_mod_visible_ver14(gbe_dev, (pair ? + GBE_STATSC_MODULE : + GBE_STATSA_MODULE)); + + for (j = 0; j < half_num_et_stats; j++) { + et_entry = pair * half_num_et_stats + j; + gbe_update_hw_stats_entry(gbe_dev, et_entry); - p = base + gbe_dev->et_stats[j].offset; - tmp = readl(p); - hw_stats[j] += tmp; if (data) - data[j] = hw_stats[j]; - /* write-to-decrement: - * new register value = old register value - write value - */ - writel(tmp, p); + data[et_entry] = gbe_dev->hw_stats[et_entry]; } } } -- GitLab From 489e8a2f09d772afc98a85ca477bb6bc52400c26 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:23 -0400 Subject: [PATCH 1704/7006] net: netcp: Fixes to CPSW statistics collection In certain applications it's beneficial to allow the CPSW h/w stats counters to continue to increment even while the kernel polls them. This patch implements this behavior for both 1G and 10G ethernet subsystem modules. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 86 +++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index b06f210c8adaf..aa330669aa080 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -642,6 +642,7 @@ struct gbe_priv { bool enable_ale; u8 max_num_slaves; u8 max_num_ports; /* max_num_slaves + 1 */ + u8 num_stats_mods; struct netcp_tx_pipe tx_pipe; int host_port; @@ -671,6 +672,7 @@ struct gbe_priv { struct net_device *dummy_ndev; u64 *hw_stats; + u32 *hw_stats_prev; const struct netcp_ethtool_stat *et_stats; int num_et_stats; /* Lock for updating the hwstats */ @@ -1550,25 +1552,37 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset) } } +static void gbe_reset_mod_stats(struct gbe_priv *gbe_dev, int stats_mod) +{ + void __iomem *base = gbe_dev->hw_stats_regs[stats_mod]; + u32 __iomem *p_stats_entry; + int i; + + for (i = 0; i < gbe_dev->num_et_stats; i++) { + if (gbe_dev->et_stats[i].type == stats_mod) { + p_stats_entry = base + gbe_dev->et_stats[i].offset; + gbe_dev->hw_stats[i] = 0; + gbe_dev->hw_stats_prev[i] = readl(p_stats_entry); + } + } +} + static inline void gbe_update_hw_stats_entry(struct gbe_priv *gbe_dev, int et_stats_entry) { void __iomem *base = NULL; - u32 __iomem *p; - u32 tmp = 0; + u32 __iomem *p_stats_entry; + u32 curr, delta; /* The hw_stats_regs pointers are already * properly set to point to the right base: */ base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[et_stats_entry].type]; - p = base + gbe_dev->et_stats[et_stats_entry].offset; - tmp = readl(p); - gbe_dev->hw_stats[et_stats_entry] += tmp; - - /* write-to-decrement: - * new register value = old register value - write value - */ - writel(tmp, p); + p_stats_entry = base + gbe_dev->et_stats[et_stats_entry].offset; + curr = readl(p_stats_entry); + delta = curr - gbe_dev->hw_stats_prev[et_stats_entry]; + gbe_dev->hw_stats_prev[et_stats_entry] = curr; + gbe_dev->hw_stats[et_stats_entry] += delta; } static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data) @@ -1607,6 +1621,12 @@ static inline void gbe_stats_mod_visible_ver14(struct gbe_priv *gbe_dev, writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en)); } +static void gbe_reset_mod_stats_ver14(struct gbe_priv *gbe_dev, int stats_mod) +{ + gbe_stats_mod_visible_ver14(gbe_dev, stats_mod); + gbe_reset_mod_stats(gbe_dev, stats_mod); +} + static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data) { u32 half_num_et_stats = (gbe_dev->num_et_stats / 2); @@ -2560,6 +2580,7 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, } gbe_dev->xgbe_serdes_regs = regs; + gbe_dev->num_stats_mods = gbe_dev->max_num_ports; gbe_dev->et_stats = xgbe10_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats); @@ -2571,6 +2592,16 @@ static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } + gbe_dev->hw_stats_prev = + devm_kzalloc(gbe_dev->dev, + gbe_dev->num_et_stats * sizeof(u32), + GFP_KERNEL); + if (!gbe_dev->hw_stats_prev) { + dev_err(gbe_dev->dev, + "hw_stats_prev memory allocation failed\n"); + return -ENOMEM; + } + gbe_dev->ss_version = XGBE_SS_VERSION_10; gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + XGBE10_SGMII_MODULE_OFFSET; @@ -2668,6 +2699,7 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, } gbe_dev->switch_regs = regs; + gbe_dev->num_stats_mods = gbe_dev->max_num_slaves; gbe_dev->et_stats = gbe13_et_stats; gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats); @@ -2679,6 +2711,16 @@ static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } + gbe_dev->hw_stats_prev = + devm_kzalloc(gbe_dev->dev, + gbe_dev->num_et_stats * sizeof(u32), + GFP_KERNEL); + if (!gbe_dev->hw_stats_prev) { + dev_err(gbe_dev->dev, + "hw_stats_prev memory allocation failed\n"); + return -ENOMEM; + } + gbe_dev->sgmii_port_regs = gbe_dev->ss_regs + GBE13_SGMII_MODULE_OFFSET; gbe_dev->host_port_regs = gbe_dev->switch_regs + GBE13_HOST_PORT_OFFSET; @@ -2722,6 +2764,7 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, void __iomem *regs; int i, ret; + gbe_dev->num_stats_mods = gbe_dev->max_num_ports; gbe_dev->et_stats = gbenu_et_stats; if (IS_SS_ID_NU(gbe_dev)) @@ -2739,6 +2782,16 @@ static int set_gbenu_ethss_priv(struct gbe_priv *gbe_dev, return -ENOMEM; } + gbe_dev->hw_stats_prev = + devm_kzalloc(gbe_dev->dev, + gbe_dev->num_et_stats * sizeof(u32), + GFP_KERNEL); + if (!gbe_dev->hw_stats_prev) { + dev_err(gbe_dev->dev, + "hw_stats_prev memory allocation failed\n"); + return -ENOMEM; + } + ret = of_address_to_resource(node, GBENU_SM_REG_INDEX, &res); if (ret) { dev_err(gbe_dev->dev, @@ -2797,7 +2850,7 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, struct cpsw_ale_params ale_params; struct gbe_priv *gbe_dev; u32 slave_num; - int ret = 0; + int i, ret = 0; if (!node) { dev_err(dev, "device tree info unavailable\n"); @@ -2945,6 +2998,15 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, /* initialize host port */ gbe_init_host_port(gbe_dev); + spin_lock_bh(&gbe_dev->hw_stats_lock); + for (i = 0; i < gbe_dev->num_stats_mods; i++) { + if (gbe_dev->ss_version == GBE_SS_VERSION_14) + gbe_reset_mod_stats_ver14(gbe_dev, i); + else + gbe_reset_mod_stats(gbe_dev, i); + } + spin_unlock_bh(&gbe_dev->hw_stats_lock); + init_timer(&gbe_dev->timer); gbe_dev->timer.data = (unsigned long)gbe_dev; gbe_dev->timer.function = netcp_ethss_timer; @@ -2956,6 +3018,8 @@ static int gbe_probe(struct netcp_device *netcp_device, struct device *dev, quit: if (gbe_dev->hw_stats) devm_kfree(dev, gbe_dev->hw_stats); + if (gbe_dev->hw_stats_prev) + devm_kfree(dev, gbe_dev->hw_stats_prev); cpsw_ale_destroy(gbe_dev->ale); if (gbe_dev->ss_regs) devm_iounmap(dev, gbe_dev->ss_regs); -- GitLab From 5be4001eccb954da7f8ae68248167d3dbb6e7177 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Thu, 23 Jul 2015 15:57:24 -0400 Subject: [PATCH 1705/7006] net: netcp: Adds missing statistics for K2L and K2E This patch adds the missing statistics for the host and slave ports of the CPSW on K2L and K2E platforms. Signed-off-by: WingMan Kwok Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 177 +++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index aa330669aa080..01a955cf56030 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -872,7 +872,7 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { }; /* This is the size of entries in GBENU_STATS_HOST */ -#define GBENU_ET_STATS_HOST_SIZE 33 +#define GBENU_ET_STATS_HOST_SIZE 52 #define GBENU_STATS_HOST(field) \ { \ @@ -881,8 +881,8 @@ static const struct netcp_ethtool_stat gbe13_et_stats[] = { offsetof(struct gbenu_hw_stats, field) \ } -/* This is the size of entries in GBENU_STATS_HOST */ -#define GBENU_ET_STATS_PORT_SIZE 46 +/* This is the size of entries in GBENU_STATS_PORT */ +#define GBENU_ET_STATS_PORT_SIZE 65 #define GBENU_STATS_P1(field) \ { \ @@ -974,7 +974,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_HOST(ale_unknown_mcast_bytes), GBENU_STATS_HOST(ale_unknown_bcast), GBENU_STATS_HOST(ale_unknown_bcast_bytes), + GBENU_STATS_HOST(ale_pol_match), + GBENU_STATS_HOST(ale_pol_match_red), + GBENU_STATS_HOST(ale_pol_match_yellow), GBENU_STATS_HOST(tx_mem_protect_err), + GBENU_STATS_HOST(tx_pri0_drop), + GBENU_STATS_HOST(tx_pri1_drop), + GBENU_STATS_HOST(tx_pri2_drop), + GBENU_STATS_HOST(tx_pri3_drop), + GBENU_STATS_HOST(tx_pri4_drop), + GBENU_STATS_HOST(tx_pri5_drop), + GBENU_STATS_HOST(tx_pri6_drop), + GBENU_STATS_HOST(tx_pri7_drop), + GBENU_STATS_HOST(tx_pri0_drop_bcnt), + GBENU_STATS_HOST(tx_pri1_drop_bcnt), + GBENU_STATS_HOST(tx_pri2_drop_bcnt), + GBENU_STATS_HOST(tx_pri3_drop_bcnt), + GBENU_STATS_HOST(tx_pri4_drop_bcnt), + GBENU_STATS_HOST(tx_pri5_drop_bcnt), + GBENU_STATS_HOST(tx_pri6_drop_bcnt), + GBENU_STATS_HOST(tx_pri7_drop_bcnt), /* GBENU Module 1 */ GBENU_STATS_P1(rx_good_frames), GBENU_STATS_P1(rx_broadcast_frames), @@ -1021,7 +1040,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P1(ale_unknown_mcast_bytes), GBENU_STATS_P1(ale_unknown_bcast), GBENU_STATS_P1(ale_unknown_bcast_bytes), + GBENU_STATS_P1(ale_pol_match), + GBENU_STATS_P1(ale_pol_match_red), + GBENU_STATS_P1(ale_pol_match_yellow), GBENU_STATS_P1(tx_mem_protect_err), + GBENU_STATS_P1(tx_pri0_drop), + GBENU_STATS_P1(tx_pri1_drop), + GBENU_STATS_P1(tx_pri2_drop), + GBENU_STATS_P1(tx_pri3_drop), + GBENU_STATS_P1(tx_pri4_drop), + GBENU_STATS_P1(tx_pri5_drop), + GBENU_STATS_P1(tx_pri6_drop), + GBENU_STATS_P1(tx_pri7_drop), + GBENU_STATS_P1(tx_pri0_drop_bcnt), + GBENU_STATS_P1(tx_pri1_drop_bcnt), + GBENU_STATS_P1(tx_pri2_drop_bcnt), + GBENU_STATS_P1(tx_pri3_drop_bcnt), + GBENU_STATS_P1(tx_pri4_drop_bcnt), + GBENU_STATS_P1(tx_pri5_drop_bcnt), + GBENU_STATS_P1(tx_pri6_drop_bcnt), + GBENU_STATS_P1(tx_pri7_drop_bcnt), /* GBENU Module 2 */ GBENU_STATS_P2(rx_good_frames), GBENU_STATS_P2(rx_broadcast_frames), @@ -1068,7 +1106,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P2(ale_unknown_mcast_bytes), GBENU_STATS_P2(ale_unknown_bcast), GBENU_STATS_P2(ale_unknown_bcast_bytes), + GBENU_STATS_P2(ale_pol_match), + GBENU_STATS_P2(ale_pol_match_red), + GBENU_STATS_P2(ale_pol_match_yellow), GBENU_STATS_P2(tx_mem_protect_err), + GBENU_STATS_P2(tx_pri0_drop), + GBENU_STATS_P2(tx_pri1_drop), + GBENU_STATS_P2(tx_pri2_drop), + GBENU_STATS_P2(tx_pri3_drop), + GBENU_STATS_P2(tx_pri4_drop), + GBENU_STATS_P2(tx_pri5_drop), + GBENU_STATS_P2(tx_pri6_drop), + GBENU_STATS_P2(tx_pri7_drop), + GBENU_STATS_P2(tx_pri0_drop_bcnt), + GBENU_STATS_P2(tx_pri1_drop_bcnt), + GBENU_STATS_P2(tx_pri2_drop_bcnt), + GBENU_STATS_P2(tx_pri3_drop_bcnt), + GBENU_STATS_P2(tx_pri4_drop_bcnt), + GBENU_STATS_P2(tx_pri5_drop_bcnt), + GBENU_STATS_P2(tx_pri6_drop_bcnt), + GBENU_STATS_P2(tx_pri7_drop_bcnt), /* GBENU Module 3 */ GBENU_STATS_P3(rx_good_frames), GBENU_STATS_P3(rx_broadcast_frames), @@ -1115,7 +1172,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P3(ale_unknown_mcast_bytes), GBENU_STATS_P3(ale_unknown_bcast), GBENU_STATS_P3(ale_unknown_bcast_bytes), + GBENU_STATS_P3(ale_pol_match), + GBENU_STATS_P3(ale_pol_match_red), + GBENU_STATS_P3(ale_pol_match_yellow), GBENU_STATS_P3(tx_mem_protect_err), + GBENU_STATS_P3(tx_pri0_drop), + GBENU_STATS_P3(tx_pri1_drop), + GBENU_STATS_P3(tx_pri2_drop), + GBENU_STATS_P3(tx_pri3_drop), + GBENU_STATS_P3(tx_pri4_drop), + GBENU_STATS_P3(tx_pri5_drop), + GBENU_STATS_P3(tx_pri6_drop), + GBENU_STATS_P3(tx_pri7_drop), + GBENU_STATS_P3(tx_pri0_drop_bcnt), + GBENU_STATS_P3(tx_pri1_drop_bcnt), + GBENU_STATS_P3(tx_pri2_drop_bcnt), + GBENU_STATS_P3(tx_pri3_drop_bcnt), + GBENU_STATS_P3(tx_pri4_drop_bcnt), + GBENU_STATS_P3(tx_pri5_drop_bcnt), + GBENU_STATS_P3(tx_pri6_drop_bcnt), + GBENU_STATS_P3(tx_pri7_drop_bcnt), /* GBENU Module 4 */ GBENU_STATS_P4(rx_good_frames), GBENU_STATS_P4(rx_broadcast_frames), @@ -1162,7 +1238,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P4(ale_unknown_mcast_bytes), GBENU_STATS_P4(ale_unknown_bcast), GBENU_STATS_P4(ale_unknown_bcast_bytes), + GBENU_STATS_P4(ale_pol_match), + GBENU_STATS_P4(ale_pol_match_red), + GBENU_STATS_P4(ale_pol_match_yellow), GBENU_STATS_P4(tx_mem_protect_err), + GBENU_STATS_P4(tx_pri0_drop), + GBENU_STATS_P4(tx_pri1_drop), + GBENU_STATS_P4(tx_pri2_drop), + GBENU_STATS_P4(tx_pri3_drop), + GBENU_STATS_P4(tx_pri4_drop), + GBENU_STATS_P4(tx_pri5_drop), + GBENU_STATS_P4(tx_pri6_drop), + GBENU_STATS_P4(tx_pri7_drop), + GBENU_STATS_P4(tx_pri0_drop_bcnt), + GBENU_STATS_P4(tx_pri1_drop_bcnt), + GBENU_STATS_P4(tx_pri2_drop_bcnt), + GBENU_STATS_P4(tx_pri3_drop_bcnt), + GBENU_STATS_P4(tx_pri4_drop_bcnt), + GBENU_STATS_P4(tx_pri5_drop_bcnt), + GBENU_STATS_P4(tx_pri6_drop_bcnt), + GBENU_STATS_P4(tx_pri7_drop_bcnt), /* GBENU Module 5 */ GBENU_STATS_P5(rx_good_frames), GBENU_STATS_P5(rx_broadcast_frames), @@ -1209,7 +1304,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P5(ale_unknown_mcast_bytes), GBENU_STATS_P5(ale_unknown_bcast), GBENU_STATS_P5(ale_unknown_bcast_bytes), + GBENU_STATS_P5(ale_pol_match), + GBENU_STATS_P5(ale_pol_match_red), + GBENU_STATS_P5(ale_pol_match_yellow), GBENU_STATS_P5(tx_mem_protect_err), + GBENU_STATS_P5(tx_pri0_drop), + GBENU_STATS_P5(tx_pri1_drop), + GBENU_STATS_P5(tx_pri2_drop), + GBENU_STATS_P5(tx_pri3_drop), + GBENU_STATS_P5(tx_pri4_drop), + GBENU_STATS_P5(tx_pri5_drop), + GBENU_STATS_P5(tx_pri6_drop), + GBENU_STATS_P5(tx_pri7_drop), + GBENU_STATS_P5(tx_pri0_drop_bcnt), + GBENU_STATS_P5(tx_pri1_drop_bcnt), + GBENU_STATS_P5(tx_pri2_drop_bcnt), + GBENU_STATS_P5(tx_pri3_drop_bcnt), + GBENU_STATS_P5(tx_pri4_drop_bcnt), + GBENU_STATS_P5(tx_pri5_drop_bcnt), + GBENU_STATS_P5(tx_pri6_drop_bcnt), + GBENU_STATS_P5(tx_pri7_drop_bcnt), /* GBENU Module 6 */ GBENU_STATS_P6(rx_good_frames), GBENU_STATS_P6(rx_broadcast_frames), @@ -1256,7 +1370,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P6(ale_unknown_mcast_bytes), GBENU_STATS_P6(ale_unknown_bcast), GBENU_STATS_P6(ale_unknown_bcast_bytes), + GBENU_STATS_P6(ale_pol_match), + GBENU_STATS_P6(ale_pol_match_red), + GBENU_STATS_P6(ale_pol_match_yellow), GBENU_STATS_P6(tx_mem_protect_err), + GBENU_STATS_P6(tx_pri0_drop), + GBENU_STATS_P6(tx_pri1_drop), + GBENU_STATS_P6(tx_pri2_drop), + GBENU_STATS_P6(tx_pri3_drop), + GBENU_STATS_P6(tx_pri4_drop), + GBENU_STATS_P6(tx_pri5_drop), + GBENU_STATS_P6(tx_pri6_drop), + GBENU_STATS_P6(tx_pri7_drop), + GBENU_STATS_P6(tx_pri0_drop_bcnt), + GBENU_STATS_P6(tx_pri1_drop_bcnt), + GBENU_STATS_P6(tx_pri2_drop_bcnt), + GBENU_STATS_P6(tx_pri3_drop_bcnt), + GBENU_STATS_P6(tx_pri4_drop_bcnt), + GBENU_STATS_P6(tx_pri5_drop_bcnt), + GBENU_STATS_P6(tx_pri6_drop_bcnt), + GBENU_STATS_P6(tx_pri7_drop_bcnt), /* GBENU Module 7 */ GBENU_STATS_P7(rx_good_frames), GBENU_STATS_P7(rx_broadcast_frames), @@ -1303,7 +1436,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P7(ale_unknown_mcast_bytes), GBENU_STATS_P7(ale_unknown_bcast), GBENU_STATS_P7(ale_unknown_bcast_bytes), + GBENU_STATS_P7(ale_pol_match), + GBENU_STATS_P7(ale_pol_match_red), + GBENU_STATS_P7(ale_pol_match_yellow), GBENU_STATS_P7(tx_mem_protect_err), + GBENU_STATS_P7(tx_pri0_drop), + GBENU_STATS_P7(tx_pri1_drop), + GBENU_STATS_P7(tx_pri2_drop), + GBENU_STATS_P7(tx_pri3_drop), + GBENU_STATS_P7(tx_pri4_drop), + GBENU_STATS_P7(tx_pri5_drop), + GBENU_STATS_P7(tx_pri6_drop), + GBENU_STATS_P7(tx_pri7_drop), + GBENU_STATS_P7(tx_pri0_drop_bcnt), + GBENU_STATS_P7(tx_pri1_drop_bcnt), + GBENU_STATS_P7(tx_pri2_drop_bcnt), + GBENU_STATS_P7(tx_pri3_drop_bcnt), + GBENU_STATS_P7(tx_pri4_drop_bcnt), + GBENU_STATS_P7(tx_pri5_drop_bcnt), + GBENU_STATS_P7(tx_pri6_drop_bcnt), + GBENU_STATS_P7(tx_pri7_drop_bcnt), /* GBENU Module 8 */ GBENU_STATS_P8(rx_good_frames), GBENU_STATS_P8(rx_broadcast_frames), @@ -1350,7 +1502,26 @@ static const struct netcp_ethtool_stat gbenu_et_stats[] = { GBENU_STATS_P8(ale_unknown_mcast_bytes), GBENU_STATS_P8(ale_unknown_bcast), GBENU_STATS_P8(ale_unknown_bcast_bytes), + GBENU_STATS_P8(ale_pol_match), + GBENU_STATS_P8(ale_pol_match_red), + GBENU_STATS_P8(ale_pol_match_yellow), GBENU_STATS_P8(tx_mem_protect_err), + GBENU_STATS_P8(tx_pri0_drop), + GBENU_STATS_P8(tx_pri1_drop), + GBENU_STATS_P8(tx_pri2_drop), + GBENU_STATS_P8(tx_pri3_drop), + GBENU_STATS_P8(tx_pri4_drop), + GBENU_STATS_P8(tx_pri5_drop), + GBENU_STATS_P8(tx_pri6_drop), + GBENU_STATS_P8(tx_pri7_drop), + GBENU_STATS_P8(tx_pri0_drop_bcnt), + GBENU_STATS_P8(tx_pri1_drop_bcnt), + GBENU_STATS_P8(tx_pri2_drop_bcnt), + GBENU_STATS_P8(tx_pri3_drop_bcnt), + GBENU_STATS_P8(tx_pri4_drop_bcnt), + GBENU_STATS_P8(tx_pri5_drop_bcnt), + GBENU_STATS_P8(tx_pri6_drop_bcnt), + GBENU_STATS_P8(tx_pri7_drop_bcnt), }; #define XGBE_STATS0_INFO(field) \ -- GitLab From 2be6967cdbc95a9960b620defedbf5e02e2af619 Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 23 Jul 2015 23:35:56 +0300 Subject: [PATCH 1706/7006] net/mlx5e: Support ETH_RSS_HASH_XOR The ConnectX-4 HW implements inverted XOR8. To make it act as XOR we re-order the HW RSS indirection table. Set XOR to be the default RSS hash function and add ethtool API to control it. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 1 + .../ethernet/mellanox/mlx5/core/en_ethtool.c | 39 ++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 46 +++++++++++++++---- include/linux/mlx5/mlx5_ifc.h | 6 +-- 4 files changed, 79 insertions(+), 13 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 3d23bd657e3c0..61d8433392aaa 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -195,6 +195,7 @@ struct mlx5e_params { u16 rx_hash_log_tbl_sz; bool lro_en; u32 lro_wqe_sz; + u8 rss_hfunc; }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index 388938482ff99..cb28535705041 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -662,6 +662,43 @@ out: return err; } +static int mlx5e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, + u8 *hfunc) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + + if (hfunc) + *hfunc = priv->params.rss_hfunc; + + return 0; +} + +static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct mlx5e_priv *priv = netdev_priv(netdev); + int err = 0; + + if (hfunc == ETH_RSS_HASH_NO_CHANGE) + return 0; + + if ((hfunc != ETH_RSS_HASH_XOR) && + (hfunc != ETH_RSS_HASH_TOP)) + return -EINVAL; + + mutex_lock(&priv->state_lock); + + priv->params.rss_hfunc = hfunc; + if (test_bit(MLX5E_STATE_OPENED, &priv->state)) { + mlx5e_close_locked(priv->netdev); + err = mlx5e_open_locked(priv->netdev); + } + + mutex_unlock(&priv->state_lock); + + return err; +} + const struct ethtool_ops mlx5e_ethtool_ops = { .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, @@ -676,4 +713,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .set_coalesce = mlx5e_set_coalesce, .get_settings = mlx5e_get_settings, .set_settings = mlx5e_set_settings, + .get_rxfh = mlx5e_get_rxfh, + .set_rxfh = mlx5e_set_rxfh, }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 40206da1f9d7b..07d36275021ee 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1158,6 +1158,24 @@ static void mlx5e_close_tises(struct mlx5e_priv *priv) mlx5e_close_tis(priv, tc); } +static int mlx5e_rx_hash_fn(int hfunc) +{ + return (hfunc == ETH_RSS_HASH_TOP) ? + MLX5_RX_HASH_FN_TOEPLITZ : + MLX5_RX_HASH_FN_INVERTED_XOR8; +} + +static int mlx5e_bits_invert(unsigned long a, int size) +{ + int inv = 0; + int i; + + for (i = 0; i < size; i++) + inv |= (test_bit(size - i - 1, &a) ? 1 : 0) << i; + + return inv; +} + static int mlx5e_open_rqt(struct mlx5e_priv *priv) { struct mlx5_core_dev *mdev = priv->mdev; @@ -1166,11 +1184,10 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) void *rqtc; int inlen; int err; - int sz; + int log_tbl_sz = priv->params.rx_hash_log_tbl_sz; + int sz = 1 << log_tbl_sz; int i; - sz = 1 << priv->params.rx_hash_log_tbl_sz; - inlen = MLX5_ST_SZ_BYTES(create_rqt_in) + sizeof(u32) * sz; in = mlx5_vzalloc(inlen); if (!in) @@ -1182,8 +1199,12 @@ static int mlx5e_open_rqt(struct mlx5e_priv *priv) MLX5_SET(rqtc, rqtc, rqt_max_size, sz); for (i = 0; i < sz; i++) { - int ix = i % priv->params.num_channels; + int ix = i; + + if (priv->params.rss_hfunc == ETH_RSS_HASH_XOR) + ix = mlx5e_bits_invert(i, log_tbl_sz); + ix = ix % priv->params.num_channels; MLX5_SET(rqtc, rqtc, rq_num[i], priv->channel[ix]->rq.rqn); } @@ -1254,12 +1275,16 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(tirc, tirc, indirect_table, priv->rqtn); MLX5_SET(tirc, tirc, rx_hash_fn, - MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ); - MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); - netdev_rss_key_fill(MLX5_ADDR_OF(tirc, tirc, - rx_hash_toeplitz_key), - MLX5_FLD_SZ_BYTES(tirc, - rx_hash_toeplitz_key)); + mlx5e_rx_hash_fn(priv->params.rss_hfunc)); + if (priv->params.rss_hfunc == ETH_RSS_HASH_TOP) { + void *rss_key = MLX5_ADDR_OF(tirc, tirc, + rx_hash_toeplitz_key); + size_t len = MLX5_FLD_SZ_BYTES(tirc, + rx_hash_toeplitz_key); + + MLX5_SET(tirc, tirc, rx_hash_symmetric, 1); + netdev_rss_key_fill(rss_key, len); + } break; } @@ -1700,6 +1725,7 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, MLX5E_PARAMS_DEFAULT_RX_HASH_LOG_TBL_SZ; priv->params.num_tc = 1; priv->params.default_vlan_prio = 0; + priv->params.rss_hfunc = ETH_RSS_HASH_XOR; priv->params.lro_en = false && !!MLX5_CAP_ETH(priv->mdev, lro_cap); priv->params.lro_wqe_sz = diff --git a/include/linux/mlx5/mlx5_ifc.h b/include/linux/mlx5/mlx5_ifc.h index 6d2f6fee041cd..c60a62bba652c 100644 --- a/include/linux/mlx5/mlx5_ifc.h +++ b/include/linux/mlx5/mlx5_ifc.h @@ -1936,9 +1936,9 @@ enum { }; enum { - MLX5_TIRC_RX_HASH_FN_HASH_NONE = 0x0, - MLX5_TIRC_RX_HASH_FN_HASH_INVERTED_XOR8 = 0x1, - MLX5_TIRC_RX_HASH_FN_HASH_TOEPLITZ = 0x2, + MLX5_RX_HASH_FN_NONE = 0x0, + MLX5_RX_HASH_FN_INVERTED_XOR8 = 0x1, + MLX5_RX_HASH_FN_TOEPLITZ = 0x2, }; enum { -- GitLab From 311c7c71c9bb8786c96fee353fe9886c08b017fe Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 23 Jul 2015 23:35:57 +0300 Subject: [PATCH 1707/7006] net/mlx5e: Allocate DMA coherent memory on reader NUMA node By affinity hints and XPS, each mlx5e channel is assigned a CPU core. Channel DMA coherent memory that is written by the NIC and read by SW (e.g CQ buffer) is allocated on the NUMA node of the CPU core assigned for the channel. Channel DMA coherent memory that is written by SW and read by the NIC (e.g SQ/RQ buffer) is allocated on the NUMA node of the NIC. Doorbell record (written by SW and read by the NIC) is an exception since it is accessed by SW more frequently. Signed-off-by: Saeed Mahameed Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx5/core/alloc.c | 48 +++++++++++++++---- .../net/ethernet/mellanox/mlx5/core/en_main.c | 11 +++-- .../net/ethernet/mellanox/mlx5/core/main.c | 6 ++- drivers/net/ethernet/mellanox/mlx5/core/wq.c | 12 +++-- drivers/net/ethernet/mellanox/mlx5/core/wq.h | 3 +- include/linux/mlx5/driver.h | 8 ++++ 6 files changed, 70 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c index 0715b497511f6..6cb38304669f6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c @@ -45,15 +45,34 @@ * register it in a memory region at HCA virtual address 0. */ -int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) +static void *mlx5_dma_zalloc_coherent_node(struct mlx5_core_dev *dev, + size_t size, dma_addr_t *dma_handle, + int node) +{ + struct mlx5_priv *priv = &dev->priv; + int original_node; + void *cpu_handle; + + mutex_lock(&priv->alloc_mutex); + original_node = dev_to_node(&dev->pdev->dev); + set_dev_node(&dev->pdev->dev, node); + cpu_handle = dma_zalloc_coherent(&dev->pdev->dev, size, + dma_handle, GFP_KERNEL); + set_dev_node(&dev->pdev->dev, original_node); + mutex_unlock(&priv->alloc_mutex); + return cpu_handle; +} + +int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, + struct mlx5_buf *buf, int node) { dma_addr_t t; buf->size = size; buf->npages = 1; buf->page_shift = (u8)get_order(size) + PAGE_SHIFT; - buf->direct.buf = dma_zalloc_coherent(&dev->pdev->dev, - size, &t, GFP_KERNEL); + buf->direct.buf = mlx5_dma_zalloc_coherent_node(dev, size, + &t, node); if (!buf->direct.buf) return -ENOMEM; @@ -66,6 +85,11 @@ int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) return 0; } + +int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf) +{ + return mlx5_buf_alloc_node(dev, size, buf, dev->priv.numa_node); +} EXPORT_SYMBOL_GPL(mlx5_buf_alloc); void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) @@ -75,7 +99,8 @@ void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf) } EXPORT_SYMBOL_GPL(mlx5_buf_free); -static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device) +static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct mlx5_core_dev *dev, + int node) { struct mlx5_db_pgdir *pgdir; @@ -84,8 +109,9 @@ static struct mlx5_db_pgdir *mlx5_alloc_db_pgdir(struct device *dma_device) return NULL; bitmap_fill(pgdir->bitmap, MLX5_DB_PER_PAGE); - pgdir->db_page = dma_alloc_coherent(dma_device, PAGE_SIZE, - &pgdir->db_dma, GFP_KERNEL); + + pgdir->db_page = mlx5_dma_zalloc_coherent_node(dev, PAGE_SIZE, + &pgdir->db_dma, node); if (!pgdir->db_page) { kfree(pgdir); return NULL; @@ -118,7 +144,7 @@ static int mlx5_alloc_db_from_pgdir(struct mlx5_db_pgdir *pgdir, return 0; } -int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) +int mlx5_db_alloc_node(struct mlx5_core_dev *dev, struct mlx5_db *db, int node) { struct mlx5_db_pgdir *pgdir; int ret = 0; @@ -129,7 +155,7 @@ int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) if (!mlx5_alloc_db_from_pgdir(pgdir, db)) goto out; - pgdir = mlx5_alloc_db_pgdir(&(dev->pdev->dev)); + pgdir = mlx5_alloc_db_pgdir(dev, node); if (!pgdir) { ret = -ENOMEM; goto out; @@ -145,6 +171,12 @@ out: return ret; } +EXPORT_SYMBOL_GPL(mlx5_db_alloc_node); + +int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db) +{ + return mlx5_db_alloc_node(dev, db, dev->priv.numa_node); +} EXPORT_SYMBOL_GPL(mlx5_db_alloc); void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 07d36275021ee..57cc8960b73bd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -272,6 +272,8 @@ static int mlx5e_create_rq(struct mlx5e_channel *c, int err; int i; + param->wq.db_numa_node = cpu_to_node(c->cpu); + err = mlx5_wq_ll_create(mdev, ¶m->wq, rqc_wq, &rq->wq, &rq->wq_ctrl); if (err) @@ -502,6 +504,8 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, if (err) return err; + param->wq.db_numa_node = cpu_to_node(c->cpu); + err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq, &sq->wq_ctrl); if (err) @@ -702,7 +706,8 @@ static int mlx5e_create_cq(struct mlx5e_channel *c, int err; u32 i; - param->wq.numa = cpu_to_node(c->cpu); + param->wq.buf_numa_node = cpu_to_node(c->cpu); + param->wq.db_numa_node = cpu_to_node(c->cpu); param->eq_ix = c->ix; err = mlx5_cqwq_create(mdev, ¶m->wq, param->cqc, &cq->wq, @@ -1000,7 +1005,7 @@ static void mlx5e_build_rq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, log_wq_sz, priv->params.log_rq_size); MLX5_SET(wq, wq, pd, priv->pdn); - param->wq.numa = dev_to_node(&priv->mdev->pdev->dev); + param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); param->wq.linear = 1; } @@ -1014,7 +1019,7 @@ static void mlx5e_build_sq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB)); MLX5_SET(wq, wq, pd, priv->pdn); - param->wq.numa = dev_to_node(&priv->mdev->pdev->dev); + param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); } static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index afad529838de7..c34eafbf1c042 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -455,7 +455,7 @@ static int mlx5_irq_set_affinity_hint(struct mlx5_core_dev *mdev, int i) struct mlx5_priv *priv = &mdev->priv; struct msix_entry *msix = priv->msix_arr; int irq = msix[i + MLX5_EQ_VEC_COMP_BASE].vector; - int numa_node = dev_to_node(&mdev->pdev->dev); + int numa_node = priv->numa_node; int err; if (!zalloc_cpumask_var(&priv->irq_info[i].mask, GFP_KERNEL)) { @@ -668,6 +668,10 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) INIT_LIST_HEAD(&priv->pgdir_list); spin_lock_init(&priv->mkey_lock); + mutex_init(&priv->alloc_mutex); + + priv->numa_node = dev_to_node(&dev->pdev->dev); + priv->dbg_root = debugfs_create_dir(dev_name(&pdev->dev), mlx5_debugfs_root); if (!priv->dbg_root) return -ENOMEM; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.c b/drivers/net/ethernet/mellanox/mlx5/core/wq.c index 8388411582cf8..ce21ee5b23577 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.c @@ -73,13 +73,14 @@ int mlx5_wq_cyc_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, wq->log_stride = MLX5_GET(wq, wqc, log_wq_stride); wq->sz_m1 = (1 << MLX5_GET(wq, wqc, log_wq_sz)) - 1; - err = mlx5_db_alloc(mdev, &wq_ctrl->db); + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err); return err; } - err = mlx5_buf_alloc(mdev, mlx5_wq_cyc_get_byte_size(wq), &wq_ctrl->buf); + err = mlx5_buf_alloc_node(mdev, mlx5_wq_cyc_get_byte_size(wq), + &wq_ctrl->buf, param->buf_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err); goto err_db_free; @@ -108,13 +109,14 @@ int mlx5_cqwq_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, wq->log_sz = MLX5_GET(cqc, cqc, log_cq_size); wq->sz_m1 = (1 << wq->log_sz) - 1; - err = mlx5_db_alloc(mdev, &wq_ctrl->db); + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err); return err; } - err = mlx5_buf_alloc(mdev, mlx5_cqwq_get_byte_size(wq), &wq_ctrl->buf); + err = mlx5_buf_alloc_node(mdev, mlx5_cqwq_get_byte_size(wq), + &wq_ctrl->buf, param->buf_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_buf_alloc() failed, %d\n", err); goto err_db_free; @@ -144,7 +146,7 @@ int mlx5_wq_ll_create(struct mlx5_core_dev *mdev, struct mlx5_wq_param *param, wq->log_stride = MLX5_GET(wq, wqc, log_wq_stride); wq->sz_m1 = (1 << MLX5_GET(wq, wqc, log_wq_sz)) - 1; - err = mlx5_db_alloc(mdev, &wq_ctrl->db); + err = mlx5_db_alloc_node(mdev, &wq_ctrl->db, param->db_numa_node); if (err) { mlx5_core_warn(mdev, "mlx5_db_alloc() failed, %d\n", err); return err; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/wq.h b/drivers/net/ethernet/mellanox/mlx5/core/wq.h index e0ddd69fb429f..6c2a8f95093c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/wq.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/wq.h @@ -37,7 +37,8 @@ struct mlx5_wq_param { int linear; - int numa; + int buf_numa_node; + int db_numa_node; }; struct mlx5_wq_ctrl { diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 5722d88c24290..1c0d5d062d7c9 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -463,6 +463,10 @@ struct mlx5_priv { /* end: mr staff */ /* start: alloc staff */ + /* protect buffer alocation according to numa node */ + struct mutex alloc_mutex; + int numa_node; + struct mutex pgdir_mutex; struct list_head pgdir_list; /* end: alloc staff */ @@ -672,6 +676,8 @@ void mlx5_health_cleanup(void); void __init mlx5_health_init(void); void mlx5_start_health_poll(struct mlx5_core_dev *dev); void mlx5_stop_health_poll(struct mlx5_core_dev *dev); +int mlx5_buf_alloc_node(struct mlx5_core_dev *dev, int size, + struct mlx5_buf *buf, int node); int mlx5_buf_alloc(struct mlx5_core_dev *dev, int size, struct mlx5_buf *buf); void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf); struct mlx5_cmd_mailbox *mlx5_alloc_cmd_mailbox_chain(struct mlx5_core_dev *dev, @@ -773,6 +779,8 @@ void mlx5_eq_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_cq_debugfs_init(struct mlx5_core_dev *dev); void mlx5_cq_debugfs_cleanup(struct mlx5_core_dev *dev); int mlx5_db_alloc(struct mlx5_core_dev *dev, struct mlx5_db *db); +int mlx5_db_alloc_node(struct mlx5_core_dev *dev, struct mlx5_db *db, + int node); void mlx5_db_free(struct mlx5_core_dev *dev, struct mlx5_db *db); const char *mlx5_command_str(int command); -- GitLab From 58d522912ac7d25b63f468fa4a4e8bb059c5144e Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:35:58 +0300 Subject: [PATCH 1708/7006] net/mlx5e: Support TX packet copy into WQE AKA inline WQE. A TX latency optimization to save data gather DMA reads. Controlled by ETHTOOL_TX_COPYBREAK. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 + .../ethernet/mellanox/mlx5/core/en_ethtool.c | 53 +++++++++++++++++++ .../net/ethernet/mellanox/mlx5/core/en_main.c | 13 +++++ .../net/ethernet/mellanox/mlx5/core/en_tx.c | 10 +++- 4 files changed, 77 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 61d8433392aaa..d9dc506188c82 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -196,6 +196,7 @@ struct mlx5e_params { bool lro_en; u32 lro_wqe_sz; u8 rss_hfunc; + u16 tx_max_inline; }; enum { @@ -520,3 +521,4 @@ static inline void mlx5e_cq_arm(struct mlx5e_cq *cq) } extern const struct ethtool_ops mlx5e_ethtool_ops; +u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c index cb28535705041..14fd82c0d18e3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c @@ -699,6 +699,57 @@ static int mlx5e_set_rxfh(struct net_device *netdev, const u32 *indir, return err; } +static int mlx5e_get_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, + void *data) +{ + const struct mlx5e_priv *priv = netdev_priv(dev); + int err = 0; + + switch (tuna->id) { + case ETHTOOL_TX_COPYBREAK: + *(u32 *)data = priv->params.tx_max_inline; + break; + default: + err = -EINVAL; + break; + } + + return err; +} + +static int mlx5e_set_tunable(struct net_device *dev, + const struct ethtool_tunable *tuna, + const void *data) +{ + struct mlx5e_priv *priv = netdev_priv(dev); + struct mlx5_core_dev *mdev = priv->mdev; + struct mlx5e_params new_params; + u32 val; + int err = 0; + + switch (tuna->id) { + case ETHTOOL_TX_COPYBREAK: + val = *(u32 *)data; + if (val > mlx5e_get_max_inline_cap(mdev)) { + err = -EINVAL; + break; + } + + mutex_lock(&priv->state_lock); + new_params = priv->params; + new_params.tx_max_inline = val; + err = mlx5e_update_priv_params(priv, &new_params); + mutex_unlock(&priv->state_lock); + break; + default: + err = -EINVAL; + break; + } + + return err; +} + const struct ethtool_ops mlx5e_ethtool_ops = { .get_drvinfo = mlx5e_get_drvinfo, .get_link = ethtool_op_get_link, @@ -715,4 +766,6 @@ const struct ethtool_ops mlx5e_ethtool_ops = { .set_settings = mlx5e_set_settings, .get_rxfh = mlx5e_get_rxfh, .set_rxfh = mlx5e_set_rxfh, + .get_tunable = mlx5e_get_tunable, + .set_tunable = mlx5e_set_tunable, }; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 57cc8960b73bd..c55fad431cbf2 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -41,6 +41,7 @@ struct mlx5e_rq_param { struct mlx5e_sq_param { u32 sqc[MLX5_ST_SZ_DW(sqc)]; struct mlx5_wq_param wq; + u16 max_inline; }; struct mlx5e_cq_param { @@ -514,6 +515,7 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; sq->uar_map = sq->uar.map; sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; + sq->max_inline = param->max_inline; err = mlx5e_alloc_sq_db(sq, cpu_to_node(c->cpu)); if (err) @@ -1020,6 +1022,7 @@ static void mlx5e_build_sq_param(struct mlx5e_priv *priv, MLX5_SET(wq, wq, pd, priv->pdn); param->wq.buf_numa_node = dev_to_node(&priv->mdev->pdev->dev); + param->max_inline = priv->params.tx_max_inline; } static void mlx5e_build_common_cq_param(struct mlx5e_priv *priv, @@ -1703,6 +1706,15 @@ static int mlx5e_check_required_hca_cap(struct mlx5_core_dev *mdev) return 0; } +u16 mlx5e_get_max_inline_cap(struct mlx5_core_dev *mdev) +{ + int bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; + + return bf_buf_size - + sizeof(struct mlx5e_tx_wqe) + + 2 /*sizeof(mlx5e_tx_wqe.inline_hdr_start)*/; +} + static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, struct net_device *netdev, int num_comp_vectors) @@ -1721,6 +1733,7 @@ static void mlx5e_build_netdev_priv(struct mlx5_core_dev *mdev, MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_USEC; priv->params.tx_cq_moderation_pkts = MLX5E_PARAMS_DEFAULT_TX_CQ_MODERATION_PKTS; + priv->params.tx_max_inline = mlx5e_get_max_inline_cap(mdev); priv->params.min_rx_wqes = MLX5E_PARAMS_DEFAULT_MIN_RX_WQES; priv->params.rx_hash_log_tbl_sz = diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 03f28f438e55a..351ac6982e226 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -112,7 +112,15 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, struct sk_buff *skb) { -#define MLX5E_MIN_INLINE 16 /* eth header with vlan (w/o next ethertype) */ + /* Some NIC TX decisions, e.g loopback, are based on the packet + * headers and occur before the data gather. + * Therefore these headers must be copied into the WQE + */ +#define MLX5E_MIN_INLINE (ETH_HLEN + 2/*vlan tag*/) + + if (skb_headlen(skb) <= sq->max_inline) + return skb_headlen(skb); + return MLX5E_MIN_INLINE; } -- GitLab From 88a85f99e51fb2373259ab83c8bb130a9bbf3804 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:35:59 +0300 Subject: [PATCH 1709/7006] net/mlx5e: TX latency optimization to save DMA reads A regular TX WQE execution involves two or more DMA reads - one to fetch the WQE, and another one per WQE gather entry. These DMA reads obviously increase the TX latency. There are two mlx5 mechanisms to bypass these DMA reads: 1) Inline WQE 2) Blue Flame (BF) An inline WQE contains a whole packet, thus saves the DMA read/s of the regular WQE gather entry/s. Inline WQE support was already added in the previous commit. A BF WQE is written directly to the device I/O mapped memory, thus enables saving the DMA read that fetches the WQE. The BF WQE I/O write must be in cache line granularity, thus uses the CPU write combining mechanism. A BF WQE I/O write acts also as a TX doorbell for notifying the device of new TX WQEs. A BF WQE is written to the same I/O mapped address as the regular TX doorbell, thus this address is being mapped twice - once by ioremap() and once by io_mapping_map_wc(). While both mechanisms reduce the TX latency, they both consume more CPU cycles than a regular WQE: - A BF WQE must still be written to host memory, in addition to being written directly to the device I/O mapped memory. - An inline WQE involves copying the SKB data into it. To handle this tradeoff, we introduce here a heuristic algorithm that strives to avoid using these two mechanisms in case the TX queue is being back-pressured by the device, and limit their usage rate otherwise. An inline WQE will always be "Blue Flamed" (written directly to the device I/O mapped memory) while a BF WQE may not be inlined (may contain gather entries). Preliminary testing using netperf UDP_RR shows that the latency goes down from 17.5us to 16.9us, while the message rate (tested with pktgen) stays the same. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 24 ++++++++++++----- .../net/ethernet/mellanox/mlx5/core/en_main.c | 12 +++++---- .../net/ethernet/mellanox/mlx5/core/en_tx.c | 26 +++++++++++++++---- .../net/ethernet/mellanox/mlx5/core/main.c | 26 +++++++++++++++++-- drivers/net/ethernet/mellanox/mlx5/core/uar.c | 6 +++++ include/linux/mlx5/driver.h | 4 ++- 6 files changed, 79 insertions(+), 19 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index d9dc506188c82..b66edd2c5a617 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -60,6 +60,7 @@ #define MLX5E_TX_CQ_POLL_BUDGET 128 #define MLX5E_UPDATE_STATS_INTERVAL 200 /* msecs */ +#define MLX5E_SQ_BF_BUDGET 16 static const char vport_strings[][ETH_GSTRING_LEN] = { /* vport statistics */ @@ -268,7 +269,9 @@ struct mlx5e_sq { /* dirtied @xmit */ u16 pc ____cacheline_aligned_in_smp; u32 dma_fifo_pc; - u32 bf_offset; + u16 bf_offset; + u16 prev_cc; + u8 bf_budget; struct mlx5e_sq_stats stats; struct mlx5e_cq cq; @@ -281,9 +284,10 @@ struct mlx5e_sq { struct mlx5_wq_cyc wq; u32 dma_fifo_mask; void __iomem *uar_map; + void __iomem *uar_bf_map; struct netdev_queue *txq; u32 sqn; - u32 bf_buf_size; + u16 bf_buf_size; u16 max_inline; u16 edge; struct device *pdev; @@ -493,8 +497,10 @@ int mlx5e_update_priv_params(struct mlx5e_priv *priv, struct mlx5e_params *new_params); static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq, - struct mlx5e_tx_wqe *wqe) + struct mlx5e_tx_wqe *wqe, int bf_sz) { + u16 ofst = MLX5_BF_OFFSET + sq->bf_offset; + /* ensure wqe is visible to device before updating doorbell record */ dma_wmb(); @@ -505,9 +511,15 @@ static inline void mlx5e_tx_notify_hw(struct mlx5e_sq *sq, */ wmb(); - mlx5_write64((__be32 *)&wqe->ctrl, - sq->uar_map + MLX5_BF_OFFSET + sq->bf_offset, - NULL); + if (bf_sz) { + __iowrite64_copy(sq->uar_bf_map + ofst, &wqe->ctrl, bf_sz); + + /* flush the write-combining mapped buffer */ + wmb(); + + } else { + mlx5_write64((__be32 *)&wqe->ctrl, sq->uar_map + ofst, NULL); + } sq->bf_offset ^= sq->bf_buf_size; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index c55fad431cbf2..4a87e9dcf52c3 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -514,6 +514,7 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, sq->wq.db = &sq->wq.db[MLX5_SND_DBR]; sq->uar_map = sq->uar.map; + sq->uar_bf_map = sq->uar.bf_map; sq->bf_buf_size = (1 << MLX5_CAP_GEN(mdev, log_bf_reg_size)) / 2; sq->max_inline = param->max_inline; @@ -524,11 +525,12 @@ static int mlx5e_create_sq(struct mlx5e_channel *c, txq_ix = c->ix + tc * priv->params.num_channels; sq->txq = netdev_get_tx_queue(priv->netdev, txq_ix); - sq->pdev = c->pdev; - sq->mkey_be = c->mkey_be; - sq->channel = c; - sq->tc = tc; - sq->edge = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS; + sq->pdev = c->pdev; + sq->mkey_be = c->mkey_be; + sq->channel = c; + sq->tc = tc; + sq->edge = (sq->wq.sz_m1 + 1) - MLX5_SEND_WQE_MAX_WQEBBS; + sq->bf_budget = MLX5E_SQ_BF_BUDGET; priv->txq_to_sq_map[txq_ix] = sq; return 0; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 351ac6982e226..64380bc0cd6a5 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -57,7 +57,7 @@ void mlx5e_send_nop(struct mlx5e_sq *sq, bool notify_hw) if (notify_hw) { cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; - mlx5e_tx_notify_hw(sq, wqe); + mlx5e_tx_notify_hw(sq, wqe, 0); } } @@ -110,7 +110,7 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, } static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, - struct sk_buff *skb) + struct sk_buff *skb, bool bf) { /* Some NIC TX decisions, e.g loopback, are based on the packet * headers and occur before the data gather. @@ -118,7 +118,7 @@ static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, */ #define MLX5E_MIN_INLINE (ETH_HLEN + 2/*vlan tag*/) - if (skb_headlen(skb) <= sq->max_inline) + if (bf && (skb_headlen(skb) <= sq->max_inline)) return skb_headlen(skb); return MLX5E_MIN_INLINE; @@ -137,6 +137,7 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) u8 opcode = MLX5_OPCODE_SEND; dma_addr_t dma_addr = 0; + bool bf = false; u16 headlen; u16 ds_cnt; u16 ihs; @@ -149,6 +150,11 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) else sq->stats.csum_offload_none++; + if (sq->cc != sq->prev_cc) { + sq->prev_cc = sq->cc; + sq->bf_budget = (sq->cc == sq->pc) ? MLX5E_SQ_BF_BUDGET : 0; + } + if (skb_is_gso(skb)) { u32 payload_len; @@ -161,7 +167,10 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) sq->stats.tso_packets++; sq->stats.tso_bytes += payload_len; } else { - ihs = mlx5e_get_inline_hdr_size(sq, skb); + bf = sq->bf_budget && + !skb->xmit_more && + !skb_shinfo(skb)->nr_frags; + ihs = mlx5e_get_inline_hdr_size(sq, skb, bf); MLX5E_TX_SKB_CB(skb)->num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); } @@ -233,14 +242,21 @@ static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) } if (!skb->xmit_more || netif_xmit_stopped(sq->txq)) { + int bf_sz = 0; + + if (bf && sq->uar_bf_map) + bf_sz = MLX5E_TX_SKB_CB(skb)->num_wqebbs << 3; + cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; - mlx5e_tx_notify_hw(sq, wqe); + mlx5e_tx_notify_hw(sq, wqe, bf_sz); } /* fill sq edge with nops to avoid wqe wrap around */ while ((sq->pc & wq->sz_m1) > sq->edge) mlx5e_send_nop(sq, false); + sq->bf_budget = bf ? sq->bf_budget - 1 : 0; + sq->stats.packets++; return NETDEV_TX_OK; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c index c34eafbf1c042..603a8b0908eea 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c @@ -654,6 +654,22 @@ static int mlx5_core_set_issi(struct mlx5_core_dev *dev) } #endif +static int map_bf_area(struct mlx5_core_dev *dev) +{ + resource_size_t bf_start = pci_resource_start(dev->pdev, 0); + resource_size_t bf_len = pci_resource_len(dev->pdev, 0); + + dev->priv.bf_mapping = io_mapping_create_wc(bf_start, bf_len); + + return dev->priv.bf_mapping ? 0 : -ENOMEM; +} + +static void unmap_bf_area(struct mlx5_core_dev *dev) +{ + if (dev->priv.bf_mapping) + io_mapping_free(dev->priv.bf_mapping); +} + static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) { struct mlx5_priv *priv = &dev->priv; @@ -808,10 +824,13 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) goto err_stop_eqs; } + if (map_bf_area(dev)) + dev_err(&pdev->dev, "Failed to map blue flame area\n"); + err = mlx5_irq_set_affinity_hints(dev); if (err) { dev_err(&pdev->dev, "Failed to alloc affinity hint cpumask\n"); - goto err_free_comp_eqs; + goto err_unmap_bf_area; } MLX5_INIT_DOORBELL_LOCK(&priv->cq_uar_lock); @@ -823,7 +842,9 @@ static int mlx5_dev_init(struct mlx5_core_dev *dev, struct pci_dev *pdev) return 0; -err_free_comp_eqs: +err_unmap_bf_area: + unmap_bf_area(dev); + free_comp_eqs(dev); err_stop_eqs: @@ -881,6 +902,7 @@ static void mlx5_dev_cleanup(struct mlx5_core_dev *dev) mlx5_cleanup_qp_table(dev); mlx5_cleanup_cq_table(dev); mlx5_irq_clear_affinity_hints(dev); + unmap_bf_area(dev); free_comp_eqs(dev); mlx5_stop_eqs(dev); mlx5_free_uuars(dev, &priv->uuari); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/uar.c b/drivers/net/ethernet/mellanox/mlx5/core/uar.c index 9ef85873ceea8..eb05c845ece92 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/uar.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/uar.c @@ -32,6 +32,7 @@ #include #include +#include #include #include #include "mlx5_core.h" @@ -246,6 +247,10 @@ int mlx5_alloc_map_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar) goto err_free_uar; } + if (mdev->priv.bf_mapping) + uar->bf_map = io_mapping_map_wc(mdev->priv.bf_mapping, + uar->index << PAGE_SHIFT); + return 0; err_free_uar: @@ -257,6 +262,7 @@ EXPORT_SYMBOL(mlx5_alloc_map_uar); void mlx5_unmap_free_uar(struct mlx5_core_dev *mdev, struct mlx5_uar *uar) { + io_mapping_unmap(uar->bf_map); iounmap(uar->map); mlx5_cmd_free_uar(mdev, uar->index); } diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 1c0d5d062d7c9..5fe0cae1a5155 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -380,7 +380,7 @@ struct mlx5_uar { u32 index; struct list_head bf_list; unsigned free_bf_bmap; - void __iomem *wc_map; + void __iomem *bf_map; void __iomem *map; }; @@ -435,6 +435,8 @@ struct mlx5_priv { struct mlx5_uuar_info uuari; MLX5_DECLARE_DOORBELL_LOCK(cq_uar_lock); + struct io_mapping *bf_mapping; + /* pages stuff */ struct workqueue_struct *pg_wq; struct rb_root page_root; -- GitLab From 5a6f8aef16c53ffeb9c1497f0b583269695c067d Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:36:00 +0300 Subject: [PATCH 1710/7006] net/mlx5e: Cosmetics: use BIT() instead of "1 <<", and others No logical change in this commit. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 16 +- .../mellanox/mlx5/core/en_flow_table.c | 166 +++++++++--------- .../net/ethernet/mellanox/mlx5/core/en_main.c | 20 +-- 3 files changed, 104 insertions(+), 98 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index b66edd2c5a617..39294f2fbaacd 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -330,14 +330,14 @@ struct mlx5e_channel { }; enum mlx5e_traffic_types { - MLX5E_TT_IPV4_TCP = 0, - MLX5E_TT_IPV6_TCP = 1, - MLX5E_TT_IPV4_UDP = 2, - MLX5E_TT_IPV6_UDP = 3, - MLX5E_TT_IPV4 = 4, - MLX5E_TT_IPV6 = 5, - MLX5E_TT_ANY = 6, - MLX5E_NUM_TT = 7, + MLX5E_TT_IPV4_TCP, + MLX5E_TT_IPV6_TCP, + MLX5E_TT_IPV4_UDP, + MLX5E_TT_IPV6_UDP, + MLX5E_TT_IPV4, + MLX5E_TT_IPV6, + MLX5E_TT_ANY, + MLX5E_NUM_TT, }; enum { diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c index 120db80c47aac..cca34f6fa5151 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -105,25 +105,25 @@ static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, { void *ft = priv->ft.main; - if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_TCP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_TCP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_UDP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_UDP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV6)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV6)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]); - if (ai->tt_vec & (1 << MLX5E_TT_IPV4)) + if (ai->tt_vec & BIT(MLX5E_TT_IPV4)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]); - if (ai->tt_vec & (1 << MLX5E_TT_ANY)) + if (ai->tt_vec & BIT(MLX5E_TT_ANY)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]); } @@ -156,33 +156,33 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) switch (eth_addr_type) { case MLX5E_UC: ret = - (1 << MLX5E_TT_IPV4_TCP) | - (1 << MLX5E_TT_IPV6_TCP) | - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV4) | - (1 << MLX5E_TT_IPV6) | - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_IPV4_TCP) | + BIT(MLX5E_TT_IPV6_TCP) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV6) | + BIT(MLX5E_TT_ANY) | 0; break; case MLX5E_MC_IPV4: ret = - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV4) | 0; break; case MLX5E_MC_IPV6: ret = - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV6) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV6) | 0; break; case MLX5E_MC_OTHER: ret = - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_ANY) | 0; break; } @@ -191,23 +191,23 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) case MLX5E_ALLMULTI: ret = - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV4) | - (1 << MLX5E_TT_IPV6) | - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV6) | + BIT(MLX5E_TT_ANY) | 0; break; default: /* MLX5E_PROMISC */ ret = - (1 << MLX5E_TT_IPV4_TCP) | - (1 << MLX5E_TT_IPV6_TCP) | - (1 << MLX5E_TT_IPV4_UDP) | - (1 << MLX5E_TT_IPV6_UDP) | - (1 << MLX5E_TT_IPV4) | - (1 << MLX5E_TT_IPV6) | - (1 << MLX5E_TT_ANY) | + BIT(MLX5E_TT_IPV4_TCP) | + BIT(MLX5E_TT_IPV6_TCP) | + BIT(MLX5E_TT_IPV4_UDP) | + BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4) | + BIT(MLX5E_TT_IPV6) | + BIT(MLX5E_TT_ANY) | 0; break; } @@ -226,6 +226,7 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, u8 *match_criteria_dmac; void *ft = priv->ft.main; u32 *tirn = priv->tirn; + u32 *ft_ix; u32 tt_vec; int err; @@ -261,51 +262,51 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, tt_vec = mlx5e_get_tt_vec(ai, type); - if (tt_vec & (1 << MLX5E_TT_ANY)) { + ft_ix = &ai->ft_ix[MLX5E_TT_ANY]; + if (tt_vec & BIT(MLX5E_TT_ANY)) { MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_ANY]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_ANY]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_ANY); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_ANY); } match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.ethertype); - if (tt_vec & (1 << MLX5E_TT_IPV4)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4]; + if (tt_vec & BIT(MLX5E_TT_IPV4)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IP); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV4]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV4]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV4); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4); } - if (tt_vec & (1 << MLX5E_TT_IPV6)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6]; + if (tt_vec & BIT(MLX5E_TT_IPV6)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IPV6); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV6]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV6]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV6); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6); } MLX5_SET_TO_ONES(fte_match_param, match_criteria, @@ -313,70 +314,75 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, IPPROTO_UDP); - if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_UDP]; + if (tt_vec & BIT(MLX5E_TT_IPV4_UDP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IP); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV4_UDP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV4_UDP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_UDP); } - if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_UDP]; + if (tt_vec & BIT(MLX5E_TT_IPV6_UDP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IPV6); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV6_UDP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV6_UDP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_UDP); } MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, IPPROTO_TCP); - if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_TCP]; + if (tt_vec & BIT(MLX5E_TT_IPV4_TCP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IP); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV4_TCP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV4_TCP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_TCP); } - if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) { + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_TCP]; + if (tt_vec & BIT(MLX5E_TT_IPV6_TCP)) { MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, ETH_P_IPV6); MLX5_SET(dest_format_struct, dest, destination_id, tirn[MLX5E_TT_IPV6_TCP]); err = mlx5_add_flow_table_entry(ft, match_criteria_enable, match_criteria, flow_context, - &ai->ft_ix[MLX5E_TT_IPV6_TCP]); - if (err) { - mlx5e_del_eth_addr_from_flow_table(priv, ai); - return err; - } - ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP); + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_TCP); } return 0; + +err_del_ai: + mlx5e_del_eth_addr_from_flow_table(priv, ai); + + return err; } static int mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 4a87e9dcf52c3..8194c32c74767 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1252,13 +1252,13 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) #define ROUGH_MAX_L2_L3_HDR_SZ 256 -#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP) +#define MLX5_HASH_IP (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP) -#define MLX5_HASH_ALL (MLX5_HASH_FIELD_SEL_SRC_IP |\ - MLX5_HASH_FIELD_SEL_DST_IP |\ - MLX5_HASH_FIELD_SEL_L4_SPORT |\ - MLX5_HASH_FIELD_SEL_L4_DPORT) +#define MLX5_HASH_IP_L4PORTS (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_L4_SPORT |\ + MLX5_HASH_FIELD_SEL_L4_DPORT) if (priv->params.lro_en) { MLX5_SET(tirc, tirc, lro_enable_mask, @@ -1305,7 +1305,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV6_TCP: @@ -1314,7 +1314,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_TCP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV4_UDP: @@ -1323,7 +1323,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_UDP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV6_UDP: @@ -1332,7 +1332,7 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_SET(rx_hash_field_select, hfso, l4_prot_type, MLX5_L4_PROT_TYPE_UDP); MLX5_SET(rx_hash_field_select, hfso, selected_fields, - MLX5_HASH_ALL); + MLX5_HASH_IP_L4PORTS); break; case MLX5E_TT_IPV4: -- GitLab From a741749f214afd05402aeed0ecdca90eeaffc303 Mon Sep 17 00:00:00 2001 From: Achiad Shochat Date: Thu, 23 Jul 2015 23:36:01 +0300 Subject: [PATCH 1711/7006] net/mlx5e: Input IPSEC.SPI into the RX RSS hash function In addition to the source/destination IP which are already hashed. Only for unicast traffic for now. Signed-off-by: Achiad Shochat Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 4 + .../mellanox/mlx5/core/en_flow_table.c | 92 ++++++++++++++++++- .../net/ethernet/mellanox/mlx5/core/en_main.c | 32 +++++++ 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 39294f2fbaacd..b710e9bade386 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -334,6 +334,10 @@ enum mlx5e_traffic_types { MLX5E_TT_IPV6_TCP, MLX5E_TT_IPV4_UDP, MLX5E_TT_IPV6_UDP, + MLX5E_TT_IPV4_IPSEC_AH, + MLX5E_TT_IPV6_IPSEC_AH, + MLX5E_TT_IPV4_IPSEC_ESP, + MLX5E_TT_IPV6_IPSEC_ESP, MLX5E_TT_IPV4, MLX5E_TT_IPV6, MLX5E_TT_ANY, diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c index cca34f6fa5151..70ec31b9e1e96 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_flow_table.c @@ -105,6 +105,22 @@ static void mlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv, { void *ft = priv->ft.main; + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_ESP)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV6_IPSEC_ESP]); + + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_ESP)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV4_IPSEC_ESP]); + + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_AH)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV6_IPSEC_AH]); + + if (ai->tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_AH)) + mlx5_del_flow_table_entry(ft, + ai->ft_ix[MLX5E_TT_IPV4_IPSEC_AH]); + if (ai->tt_vec & BIT(MLX5E_TT_IPV6_TCP)) mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]); @@ -160,6 +176,10 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) BIT(MLX5E_TT_IPV6_TCP) | BIT(MLX5E_TT_IPV4_UDP) | BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4_IPSEC_AH) | + BIT(MLX5E_TT_IPV6_IPSEC_AH) | + BIT(MLX5E_TT_IPV4_IPSEC_ESP) | + BIT(MLX5E_TT_IPV6_IPSEC_ESP) | BIT(MLX5E_TT_IPV4) | BIT(MLX5E_TT_IPV6) | BIT(MLX5E_TT_ANY) | @@ -205,6 +225,10 @@ static u32 mlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type) BIT(MLX5E_TT_IPV6_TCP) | BIT(MLX5E_TT_IPV4_UDP) | BIT(MLX5E_TT_IPV6_UDP) | + BIT(MLX5E_TT_IPV4_IPSEC_AH) | + BIT(MLX5E_TT_IPV6_IPSEC_AH) | + BIT(MLX5E_TT_IPV4_IPSEC_ESP) | + BIT(MLX5E_TT_IPV6_IPSEC_ESP) | BIT(MLX5E_TT_IPV4) | BIT(MLX5E_TT_IPV6) | BIT(MLX5E_TT_ANY) | @@ -377,6 +401,72 @@ static int __mlx5e_add_eth_addr_rule(struct mlx5e_priv *priv, ai->tt_vec |= BIT(MLX5E_TT_IPV6_TCP); } + MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, + IPPROTO_AH); + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_IPSEC_AH]; + if (tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_AH)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4_IPSEC_AH]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_IPSEC_AH); + } + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_IPSEC_AH]; + if (tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_AH)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6_IPSEC_AH]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_IPSEC_AH); + } + + MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol, + IPPROTO_ESP); + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV4_IPSEC_ESP]; + if (tt_vec & BIT(MLX5E_TT_IPV4_IPSEC_ESP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IP); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV4_IPSEC_ESP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV4_IPSEC_ESP); + } + + ft_ix = &ai->ft_ix[MLX5E_TT_IPV6_IPSEC_ESP]; + if (tt_vec & BIT(MLX5E_TT_IPV6_IPSEC_ESP)) { + MLX5_SET(fte_match_param, match_value, outer_headers.ethertype, + ETH_P_IPV6); + MLX5_SET(dest_format_struct, dest, destination_id, + tirn[MLX5E_TT_IPV6_IPSEC_ESP]); + err = mlx5_add_flow_table_entry(ft, match_criteria_enable, + match_criteria, flow_context, + ft_ix); + if (err) + goto err_del_ai; + + ai->tt_vec |= BIT(MLX5E_TT_IPV6_IPSEC_ESP); + } + return 0; err_del_ai: @@ -731,7 +821,7 @@ static int mlx5e_create_main_flow_table(struct mlx5e_priv *priv) if (!g) return -ENOMEM; - g[0].log_sz = 2; + g[0].log_sz = 3; g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS; MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria, outer_headers.ethertype); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 8194c32c74767..355a10abe667a 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -1260,6 +1260,10 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_HASH_FIELD_SEL_L4_SPORT |\ MLX5_HASH_FIELD_SEL_L4_DPORT) +#define MLX5_HASH_IP_IPSEC_SPI (MLX5_HASH_FIELD_SEL_SRC_IP |\ + MLX5_HASH_FIELD_SEL_DST_IP |\ + MLX5_HASH_FIELD_SEL_IPSEC_SPI) + if (priv->params.lro_en) { MLX5_SET(tirc, tirc, lro_enable_mask, MLX5_TIRC_LRO_ENABLE_MASK_IPV4_LRO | @@ -1335,6 +1339,34 @@ static void mlx5e_build_tir_ctx(struct mlx5e_priv *priv, u32 *tirc, int tt) MLX5_HASH_IP_L4PORTS); break; + case MLX5E_TT_IPV4_IPSEC_AH: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV6_IPSEC_AH: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV4_IPSEC_ESP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV4); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + + case MLX5E_TT_IPV6_IPSEC_ESP: + MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, + MLX5_L3_PROT_TYPE_IPV6); + MLX5_SET(rx_hash_field_select, hfso, selected_fields, + MLX5_HASH_IP_IPSEC_SPI); + break; + case MLX5E_TT_IPV4: MLX5_SET(rx_hash_field_select, hfso, l3_prot_type, MLX5_L3_PROT_TYPE_IPV4); -- GitLab From ba27b7ef4a72e0d4718a13bc93b769eec4567d2a Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Thu, 23 Jul 2015 10:38:47 +0000 Subject: [PATCH 1712/7006] Bluetooth: btmrvl: Coding style Fix for btmrvl header Fix for "Unnecessary space before function pointer arguments" reported by checkpatch. Signed-off-by: Prasanna Karthik Signed-off-by: Johan Hedberg --- drivers/bluetooth/btmrvl_drv.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 086f0ec895806..27a9aac255832 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -95,10 +95,10 @@ struct btmrvl_private { struct btmrvl_device btmrvl_dev; struct btmrvl_adapter *adapter; struct btmrvl_thread main_thread; - int (*hw_host_to_card) (struct btmrvl_private *priv, + int (*hw_host_to_card)(struct btmrvl_private *priv, u8 *payload, u16 nb); - int (*hw_wakeup_firmware) (struct btmrvl_private *priv); - int (*hw_process_int_status) (struct btmrvl_private *priv); + int (*hw_wakeup_firmware)(struct btmrvl_private *priv); + int (*hw_process_int_status)(struct btmrvl_private *priv); void (*firmware_dump)(struct btmrvl_private *priv); spinlock_t driver_lock; /* spinlock used by driver */ #ifdef CONFIG_DEBUG_FS -- GitLab From acf50c5fc6f3d1851d23c48737210b5f61f58e1f Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Thu, 23 Jul 2015 11:08:52 +0000 Subject: [PATCH 1713/7006] Bluetooth: hci_ldisc: Cleaned up coding style warnings Fix for Cleanpatch warning: Space prohibited between function name and open parenthesis '(' Signed-off-by: Prasanna Karthik Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 051f8213697da..20c2ac193ff97 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -770,7 +770,7 @@ static int __init hci_uart_init(void) /* Register the tty discipline */ - memset(&hci_uart_ldisc, 0, sizeof (hci_uart_ldisc)); + memset(&hci_uart_ldisc, 0, sizeof(hci_uart_ldisc)); hci_uart_ldisc.magic = TTY_LDISC_MAGIC; hci_uart_ldisc.name = "n_hci"; hci_uart_ldisc.open = hci_uart_tty_open; -- GitLab From fa4cf04e65cb7f75c147e2cc80f0f472b0d93534 Mon Sep 17 00:00:00 2001 From: Prasanna Karthik Date: Thu, 23 Jul 2015 11:22:56 +0000 Subject: [PATCH 1714/7006] Bluetooth: hci_h5: Cleaned up coding style warnings Cleanedup "Unnecessary space before function pointer arguments" warning reported by Checkpatch Signed-off-by: Prasanna Karthik Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_h5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 3455cecc9ecfe..b35b238a03801 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -75,7 +75,7 @@ struct h5 { size_t rx_pending; /* Expecting more bytes */ u8 rx_ack; /* Last ack number received */ - int (*rx_func) (struct hci_uart *hu, u8 c); + int (*rx_func)(struct hci_uart *hu, u8 c); struct timer_list timer; /* Retransmission timer */ -- GitLab From 24b4d2abd0bd628f396dada3e915d395cbf459eb Mon Sep 17 00:00:00 2001 From: Alex Gartrell Date: Thu, 23 Jul 2015 14:24:40 -0700 Subject: [PATCH 1715/7006] ebpf: Allow dereferences of PTR_TO_STACK registers mov %rsp, %r1 ; r1 = rsp add $-8, %r1 ; r1 = rsp - 8 store_q $123, -8(%rsp) ; *(u64*)r1 = 123 <- valid store_q $123, (%r1) ; *(u64*)r1 = 123 <- previously invalid mov $0, %r0 exit ; Always need to exit And we'd get the following error: 0: (bf) r1 = r10 1: (07) r1 += -8 2: (7a) *(u64 *)(r10 -8) = 999 3: (7a) *(u64 *)(r1 +0) = 999 R1 invalid mem access 'fp' Unable to load program We already know that a register is a stack address and the appropriate offset, so we should be able to validate those references as well. Signed-off-by: Alex Gartrell Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- kernel/bpf/verifier.c | 6 +++- samples/bpf/test_verifier.c | 59 +++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 039d866fd36ab..cd307df98cb33 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -648,6 +648,9 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off, struct verifier_state *state = &env->cur_state; int size, err = 0; + if (state->regs[regno].type == PTR_TO_STACK) + off += state->regs[regno].imm; + size = bpf_size_to_bytes(bpf_size); if (size < 0) return size; @@ -667,7 +670,8 @@ static int check_mem_access(struct verifier_env *env, u32 regno, int off, if (!err && t == BPF_READ && value_regno >= 0) mark_reg_unknown_value(state->regs, value_regno); - } else if (state->regs[regno].type == FRAME_PTR) { + } else if (state->regs[regno].type == FRAME_PTR || + state->regs[regno].type == PTR_TO_STACK) { if (off >= 0 || off < -MAX_BPF_STACK) { verbose("invalid stack off=%d size=%d\n", off, size); return -EACCES; diff --git a/samples/bpf/test_verifier.c b/samples/bpf/test_verifier.c index 693605997abcb..ee0f110c9c543 100644 --- a/samples/bpf/test_verifier.c +++ b/samples/bpf/test_verifier.c @@ -822,6 +822,65 @@ static struct bpf_test tests[] = { .result = ACCEPT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, + { + "PTR_TO_STACK store/load", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2), + BPF_EXIT_INSN(), + }, + .result = ACCEPT, + }, + { + "PTR_TO_STACK store/load - bad alignment on off", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 2, 0xfaceb00c), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 2), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "misaligned access off -6 size 8", + }, + { + "PTR_TO_STACK store/load - bad alignment on reg", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -10), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "misaligned access off -2 size 8", + }, + { + "PTR_TO_STACK store/load - out of bounds low", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -80000), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "invalid stack off=-79992 size=8", + }, + { + "PTR_TO_STACK store/load - out of bounds high", + .insns = { + BPF_MOV64_REG(BPF_REG_1, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -8), + BPF_ST_MEM(BPF_DW, BPF_REG_1, 8, 0xfaceb00c), + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_1, 8), + BPF_EXIT_INSN(), + }, + .result = REJECT, + .errstr = "invalid stack off=0 size=8", + }, }; static int probe_filter_length(struct bpf_insn *fp) -- GitLab From b469139e81ca8265fb4797c007f8d3338f4191a5 Mon Sep 17 00:00:00 2001 From: "subashab@codeaurora.org" Date: Fri, 24 Jul 2015 03:03:29 +0000 Subject: [PATCH 1716/7006] dev: Spelling fix in comments Fix the following typo - unchainged -> unchanged Signed-off-by: Subash Abhinov Kasiviswanathan Signed-off-by: David S. Miller --- net/core/dev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/dev.c b/net/core/dev.c index cb52cba30ae8b..4870c3556a5a6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4995,7 +4995,7 @@ EXPORT_SYMBOL(netdev_all_upper_get_next_dev_rcu); * Gets the next netdev_adjacent->private from the dev's lower neighbour * list, starting from iter position. The caller must hold either hold the * RTNL lock or its own locking that guarantees that the neighbour lower - * list will remain unchainged. + * list will remain unchanged. */ void *netdev_lower_get_next_private(struct net_device *dev, struct list_head **iter) @@ -5050,7 +5050,7 @@ EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); * Gets the next netdev_adjacent from the dev's lower neighbour * list, starting from iter position. The caller must hold RTNL lock or * its own locking that guarantees that the neighbour lower - * list will remain unchainged. + * list will remain unchanged. */ void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter) { -- GitLab From 9267135cca60674321139626f49077a4937d730e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 24 Jul 2015 14:16:10 +0800 Subject: [PATCH 1717/7006] net: phy: dp83867: fix simple_return.cocci warnings drivers/net/phy/dp83867.c:126:1-4: WARNING: end returns can be simpified drivers/net/phy/dp83867.c:74:5-8: WARNING: end returns can be simpified if tested value is negative or 0 Simplify a trivial if-return sequence. Possibly combine with a preceding function call. Generated by: scripts/coccinelle/misc/simple_return.cocci CC: Dan Murphy Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller --- drivers/net/phy/dp83867.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/net/phy/dp83867.c b/drivers/net/phy/dp83867.c index 8a3bf54698921..32f10662f4ac7 100644 --- a/drivers/net/phy/dp83867.c +++ b/drivers/net/phy/dp83867.c @@ -123,12 +123,8 @@ static int dp83867_of_init(struct phy_device *phydev) if (ret) return ret; - ret = of_property_read_u32(of_node, "ti,fifo-depth", + return of_property_read_u32(of_node, "ti,fifo-depth", &dp83867->fifo_depth); - if (ret) - return ret; - - return 0; } #else static int dp83867_of_init(struct phy_device *phydev) -- GitLab From 6673a9f4e35c1f0e9976cd4e88042f87674a6b02 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 24 Jul 2015 10:59:41 +0200 Subject: [PATCH 1718/7006] ipv6: use lwtunnel_output6() only if flag redirect is set This function make sense only when LWTUNNEL_STATE_OUTPUT_REDIRECT is set. The check is already done in IPv4. CC: Thomas Graf CC: Roopa Prabhu Fixes: 74a0f2fe8ed5 ("ipv6: rt6_info output redirect to tunnel output") Signed-off-by: Nicolas Dichtel Acked-by: Thomas Graf Acked-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/ipv6/route.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 7f2214f8fde71..f91d2637072bf 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1780,7 +1780,8 @@ int ip6_route_add(struct fib6_config *cfg) goto out; lwtunnel_state_get(lwtstate); rt->rt6i_lwtstate = lwtstate; - rt->dst.output = lwtunnel_output6; + if (lwtunnel_output_redirect(rt->rt6i_lwtstate)) + rt->dst.output = lwtunnel_output6; } ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); -- GitLab From d943659508a4fb883507fdd3f998329e70a8f922 Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 24 Jul 2015 12:28:35 +0200 Subject: [PATCH 1719/7006] ipv6: copy lwtstate in ip6_rt_copy_init() We need to copy this field (ip6_rt_cache_alloc() and ip6_rt_pcpu_alloc() use ip6_rt_copy_init() to build a dst). CC: Thomas Graf CC: Roopa Prabhu Fixes: 19e42e451506 ("ipv6: support for fib route lwtunnel encap attributes") Signed-off-by: Nicolas Dichtel Acked-by: Thomas Graf Acked-by: Roopa Prabhu Signed-off-by: David S. Miller --- net/ipv6/route.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f91d2637072bf..fbe27fb6bd3f0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2161,6 +2161,10 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) #endif rt->rt6i_prefsrc = ort->rt6i_prefsrc; rt->rt6i_table = ort->rt6i_table; + if (ort->rt6i_lwtstate) { + lwtunnel_state_get(ort->rt6i_lwtstate); + rt->rt6i_lwtstate = ort->rt6i_lwtstate; + } } #ifdef CONFIG_IPV6_ROUTE_INFO -- GitLab From 5a6228a0b472062646434cd2536d109c102b606e Mon Sep 17 00:00:00 2001 From: Nicolas Dichtel Date: Fri, 24 Jul 2015 12:28:36 +0200 Subject: [PATCH 1720/7006] lwtunnel: change prototype of lwtunnel_state_get() It saves some lines and simplify a bit the code when the state is returning by this function. It's also useful to handle a NULL entry. To avoid too long lines, I've also renamed lwtunnel_state_get() and lwtunnel_state_put() to lwtstate_get() and lwtstate_put(). CC: Thomas Graf CC: Roopa Prabhu Signed-off-by: Nicolas Dichtel Acked-by: Thomas Graf Acked-by: Roopa Prabhu Signed-off-by: David S. Miller --- include/net/lwtunnel.h | 16 +++++++++++----- net/ipv4/fib_semantics.c | 9 ++++----- net/ipv4/route.c | 9 ++------- net/ipv6/ip6_fib.c | 2 +- net/ipv6/route.c | 8 ++------ 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h index 918e03c1dafa5..b02039081b048 100644 --- a/include/net/lwtunnel.h +++ b/include/net/lwtunnel.h @@ -35,12 +35,16 @@ extern const struct lwtunnel_encap_ops __rcu * lwtun_encaps[LWTUNNEL_ENCAP_MAX+1]; #ifdef CONFIG_LWTUNNEL -static inline void lwtunnel_state_get(struct lwtunnel_state *lws) +static inline struct lwtunnel_state * +lwtstate_get(struct lwtunnel_state *lws) { - atomic_inc(&lws->refcnt); + if (lws) + atomic_inc(&lws->refcnt); + + return lws; } -static inline void lwtunnel_state_put(struct lwtunnel_state *lws) +static inline void lwtstate_put(struct lwtunnel_state *lws) { if (!lws) return; @@ -74,11 +78,13 @@ int lwtunnel_output6(struct sock *sk, struct sk_buff *skb); #else -static inline void lwtunnel_state_get(struct lwtunnel_state *lws) +static inline struct lwtunnel_state * +lwtstate_get(struct lwtunnel_state *lws) { + return lws; } -static inline void lwtunnel_state_put(struct lwtunnel_state *lws) +static inline void lwtstate_put(struct lwtunnel_state *lws) { } diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index d4c6732cfbfa6..65e00399a9a6f 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -209,7 +209,7 @@ static void free_fib_info_rcu(struct rcu_head *head) change_nexthops(fi) { if (nexthop_nh->nh_dev) dev_put(nexthop_nh->nh_dev); - lwtunnel_state_put(nexthop_nh->nh_lwtstate); + lwtstate_put(nexthop_nh->nh_lwtstate); free_nh_exceptions(nexthop_nh); rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); rt_fibinfo_free(&nexthop_nh->nh_rth_input); @@ -514,8 +514,8 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, nla, &lwtstate); if (ret) goto errout; - lwtunnel_state_get(lwtstate); - nexthop_nh->nh_lwtstate = lwtstate; + nexthop_nh->nh_lwtstate = + lwtstate_get(lwtstate); } } @@ -971,8 +971,7 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (err) goto failure; - lwtunnel_state_get(lwtstate); - nh->nh_lwtstate = lwtstate; + nh->nh_lwtstate = lwtstate_get(lwtstate); } nh->nh_oif = cfg->fc_oif; nh->nh_gw = cfg->fc_gw; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 519ec232818d4..11096396ef4ae 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1358,7 +1358,7 @@ static void ipv4_dst_destroy(struct dst_entry *dst) list_del(&rt->rt_uncached); spin_unlock_bh(&ul->lock); } - lwtunnel_state_put(rt->rt_lwtstate); + lwtstate_put(rt->rt_lwtstate); } void rt_flush_dev(struct net_device *dev) @@ -1407,12 +1407,7 @@ static void rt_set_nexthop(struct rtable *rt, __be32 daddr, #ifdef CONFIG_IP_ROUTE_CLASSID rt->dst.tclassid = nh->nh_tclassid; #endif - if (nh->nh_lwtstate) { - lwtunnel_state_get(nh->nh_lwtstate); - rt->rt_lwtstate = nh->nh_lwtstate; - } else { - rt->rt_lwtstate = NULL; - } + rt->rt_lwtstate = lwtstate_get(nh->nh_lwtstate); if (unlikely(fnhe)) cached = rt_bind_exception(rt, fnhe, daddr); else if (!(rt->dst.flags & DST_NOCACHE)) diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index d715f2e0c4e71..5693b5eb84820 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -178,7 +178,7 @@ static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) static void rt6_release(struct rt6_info *rt) { if (atomic_dec_and_test(&rt->rt6i_ref)) { - lwtunnel_state_put(rt->rt6i_lwtstate); + lwtstate_put(rt->rt6i_lwtstate); rt6_free_pcpu(rt); dst_free(&rt->dst); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index fbe27fb6bd3f0..c9b2b9fe83fc4 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1778,8 +1778,7 @@ int ip6_route_add(struct fib6_config *cfg) cfg->fc_encap, &lwtstate); if (err) goto out; - lwtunnel_state_get(lwtstate); - rt->rt6i_lwtstate = lwtstate; + rt->rt6i_lwtstate = lwtstate_get(lwtstate); if (lwtunnel_output_redirect(rt->rt6i_lwtstate)) rt->dst.output = lwtunnel_output6; } @@ -2161,10 +2160,7 @@ static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) #endif rt->rt6i_prefsrc = ort->rt6i_prefsrc; rt->rt6i_table = ort->rt6i_table; - if (ort->rt6i_lwtstate) { - lwtunnel_state_get(ort->rt6i_lwtstate); - rt->rt6i_lwtstate = ort->rt6i_lwtstate; - } + rt->rt6i_lwtstate = lwtstate_get(ort->rt6i_lwtstate); } #ifdef CONFIG_IPV6_ROUTE_INFO -- GitLab From 94724d102c829d9f2105b1cb6e831c99174cd49d Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 24 Jul 2015 19:26:02 +0800 Subject: [PATCH 1721/7006] net: phy: fix auto negotiation checking for teranetics When using fiber port, the phy cannot report it's auto negotiation state, driver should always report auto negotiation is done when using fiber port. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/teranetics.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/phy/teranetics.c b/drivers/net/phy/teranetics.c index 7dcb5aada1c41..91e1bec6079fa 100644 --- a/drivers/net/phy/teranetics.c +++ b/drivers/net/phy/teranetics.c @@ -51,8 +51,15 @@ static int teranetics_aneg_done(struct phy_device *phydev) { int reg; - reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); - return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); + /* auto negotiation state can only be checked when using copper + * port, if using fiber port, just lie it's done. + */ + if (!phy_read_mmd(phydev, MDIO_MMD_VEND1, 93)) { + reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1); + return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); + } + + return 1; } static int teranetics_config_aneg(struct phy_device *phydev) -- GitLab From 205845a34763432040496908c8f52f1f97e5ee62 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 24 Jul 2015 15:50:31 +0200 Subject: [PATCH 1722/7006] bonding: convert num_grat_arp to the new bonding option API num_grat_arp wasn't converted to the new bonding option API, so do this now and remove the specific sysfs store option in order to use the standard one. num_grat_arp is the same as num_unsol_na so add it as an alias with the same option settings. An important difference is the option name which is matched in bond_sysfs_store_option(). Signed-off-by: Nikolay Aleksandrov Acked-by: Veaceslav Falico Signed-off-by: David S. Miller --- drivers/net/bonding/bond_options.c | 7 +++++++ drivers/net/bonding/bond_sysfs.c | 20 +++----------------- include/net/bond_options.h | 1 + 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index e9c624d54dd4c..6dda57e2e724f 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -420,6 +420,13 @@ static const struct bond_option bond_opts[BOND_OPT_LAST] = { .flags = BOND_OPTFLAG_IFDOWN, .values = bond_ad_user_port_key_tbl, .set = bond_option_ad_user_port_key_set, + }, + [BOND_OPT_NUM_PEER_NOTIF_ALIAS] = { + .id = BOND_OPT_NUM_PEER_NOTIF_ALIAS, + .name = "num_grat_arp", + .desc = "Number of peer notifications to send on failover event", + .values = bond_num_peer_notif_tbl, + .set = bond_option_num_peer_notif_set } }; diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 31835a4dab578..f4ae720862158 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -380,7 +380,7 @@ static ssize_t bonding_show_ad_select(struct device *d, static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_sysfs_store_option); -/* Show and set the number of peer notifications to send after a failover event. */ +/* Show the number of peer notifications to send after a failover event. */ static ssize_t bonding_show_num_peer_notif(struct device *d, struct device_attribute *attr, char *buf) @@ -388,24 +388,10 @@ static ssize_t bonding_show_num_peer_notif(struct device *d, struct bonding *bond = to_bond(d); return sprintf(buf, "%d\n", bond->params.num_peer_notif); } - -static ssize_t bonding_store_num_peer_notif(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct bonding *bond = to_bond(d); - int ret; - - ret = bond_opt_tryset_rtnl(bond, BOND_OPT_NUM_PEER_NOTIF, (char *)buf); - if (!ret) - ret = count; - - return ret; -} static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, - bonding_show_num_peer_notif, bonding_store_num_peer_notif); + bonding_show_num_peer_notif, bonding_sysfs_store_option); static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, - bonding_show_num_peer_notif, bonding_store_num_peer_notif); + bonding_show_num_peer_notif, bonding_sysfs_store_option); /* Show the MII monitor interval. */ static ssize_t bonding_show_miimon(struct device *d, diff --git a/include/net/bond_options.h b/include/net/bond_options.h index c28aca25320eb..1797235cd590c 100644 --- a/include/net/bond_options.h +++ b/include/net/bond_options.h @@ -66,6 +66,7 @@ enum { BOND_OPT_AD_ACTOR_SYS_PRIO, BOND_OPT_AD_ACTOR_SYSTEM, BOND_OPT_AD_USER_PORT_KEY, + BOND_OPT_NUM_PEER_NOTIF_ALIAS, BOND_OPT_LAST }; -- GitLab From fc596660dd4e83f7f84e3cd7b25dc5e8e83000ef Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jul 2015 13:28:57 +0200 Subject: [PATCH 1723/7006] drm/atomic: add connectors_changed to separate it from mode_changed, v2 This can be a separate case from mode_changed, when connectors stay the same but only the mode is different. Drivers may choose to implement specific optimizations to prevent a full modeset for this case. Changes since v1: - Update kerneldocs slightly. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 39 +++++++++++++++++++++------- drivers/gpu/drm/i915/intel_display.c | 2 +- include/drm/drm_atomic.h | 3 ++- include/drm/drm_crtc.h | 8 +++--- 4 files changed, 38 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 99656815641da..10bcdd554501c 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -124,7 +124,7 @@ steal_encoder(struct drm_atomic_state *state, if (IS_ERR(crtc_state)) return PTR_ERR(crtc_state); - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; list_for_each_entry(connector, &config->connector_list, head) { if (connector->state->best_encoder != encoder) @@ -174,14 +174,14 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) idx = drm_crtc_index(connector->state->crtc); crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; } if (connector_state->crtc) { idx = drm_crtc_index(connector_state->crtc); crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; } } @@ -233,7 +233,7 @@ update_connector_routing(struct drm_atomic_state *state, int conn_idx) idx = drm_crtc_index(connector_state->crtc); crtc_state = state->crtc_states[idx]; - crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; DRM_DEBUG_ATOMIC("[CONNECTOR:%d:%s] using [ENCODER:%d:%s] on [CRTC:%d]\n", connector->base.id, @@ -256,7 +256,8 @@ mode_fixup(struct drm_atomic_state *state) bool ret; for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->mode_changed) + if (!crtc_state->mode_changed && + !crtc_state->connectors_changed) continue; drm_mode_copy(&crtc_state->adjusted_mode, &crtc_state->mode); @@ -312,7 +313,8 @@ mode_fixup(struct drm_atomic_state *state) for_each_crtc_in_state(state, crtc, crtc_state, i) { const struct drm_crtc_helper_funcs *funcs; - if (!crtc_state->mode_changed) + if (!crtc_state->mode_changed && + !crtc_state->connectors_changed) continue; funcs = crtc->helper_private; @@ -338,9 +340,14 @@ mode_fixup(struct drm_atomic_state *state) * * Check the state object to see if the requested state is physically possible. * This does all the crtc and connector related computations for an atomic - * update. It computes and updates crtc_state->mode_changed, adds any additional - * connectors needed for full modesets and calls down into ->mode_fixup - * functions of the driver backend. + * update and adds any additional connectors needed for full modesets and calls + * down into ->mode_fixup functions of the driver backend. + * + * crtc_state->mode_changed is set when the input mode is changed. + * crtc_state->connectors_changed is set when a connector is added or + * removed from the crtc. + * crtc_state->active_changed is set when crtc_state->active changes, + * which is used for dpms. * * IMPORTANT: * @@ -373,7 +380,17 @@ drm_atomic_helper_check_modeset(struct drm_device *dev, if (crtc->state->enable != crtc_state->enable) { DRM_DEBUG_ATOMIC("[CRTC:%d] enable changed\n", crtc->base.id); + + /* + * For clarity this assignment is done here, but + * enable == 0 is only true when there are no + * connectors and a NULL mode. + * + * The other way around is true as well. enable != 0 + * iff connectors are attached and a mode is set. + */ crtc_state->mode_changed = true; + crtc_state->connectors_changed = true; } } @@ -448,6 +465,9 @@ EXPORT_SYMBOL(drm_atomic_helper_check_modeset); * This does all the plane update related checks using by calling into the * ->atomic_check hooks provided by the driver. * + * It also sets crtc_state->planes_changed to indicate that a crtc has + * updated planes. + * * RETURNS * Zero for success or -errno */ @@ -2074,6 +2094,7 @@ void __drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc, state->mode_changed = false; state->active_changed = false; state->planes_changed = false; + state->connectors_changed = false; state->event = NULL; } EXPORT_SYMBOL(__drm_atomic_helper_crtc_duplicate_state); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index af0bcfee4771f..07cee59edece4 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -413,7 +413,7 @@ static const intel_limit_t intel_limits_bxt = { static bool needs_modeset(struct drm_crtc_state *state) { - return state->mode_changed || state->active_changed; + return drm_atomic_crtc_needs_modeset(state); } /** diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h index 8a3a913320ebb..e67aeac2aee05 100644 --- a/include/drm/drm_atomic.h +++ b/include/drm/drm_atomic.h @@ -166,7 +166,8 @@ int __must_check drm_atomic_async_commit(struct drm_atomic_state *state); static inline bool drm_atomic_crtc_needs_modeset(struct drm_crtc_state *state) { - return state->mode_changed || state->active_changed; + return state->mode_changed || state->active_changed || + state->connectors_changed; } diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 3071319ea1940..90a0ff70384a4 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -255,12 +255,13 @@ struct drm_atomic_state; * @crtc: backpointer to the CRTC * @enable: whether the CRTC should be enabled, gates all other state * @active: whether the CRTC is actively displaying (used for DPMS) - * @mode_changed: for use by helpers and drivers when computing state updates - * @active_changed: for use by helpers and drivers when computing state updates + * @planes_changed: planes on this crtc are updated + * @mode_changed: crtc_state->mode or crtc_state->enable has been changed + * @active_changed: crtc_state->active has been toggled. + * @connectors_changed: connectors to this crtc have been updated * @plane_mask: bitmask of (1 << drm_plane_index(plane)) of attached planes * @last_vblank_count: for helpers and drivers to capture the vblank of the * update to ensure framebuffer cleanup isn't done too early - * @planes_changed: for use by helpers and drivers when computing state updates * @adjusted_mode: for use by helpers and drivers to compute adjusted mode timings * @mode: current mode timings * @event: optional pointer to a DRM event to signal upon completion of the @@ -283,6 +284,7 @@ struct drm_crtc_state { bool planes_changed : 1; bool mode_changed : 1; bool active_changed : 1; + bool connectors_changed : 1; /* attached planes bitmask: * WARNING: transitional helpers do not maintain plane_mask so -- GitLab From 990edb428c2c85c22ca770330437db7183cbe8b5 Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 24 Jul 2015 09:57:42 -0700 Subject: [PATCH 1724/7006] ipv6: Re-arrange code in rt6_probe() It is a prep work for the next patch to remove write_lock from rt6_probe(). 1. Reduce the number of if(neigh) check. From 4 to 1. 2. Bring the write_(un)lock() closer to the operations that the lock is protecting. Hopefully, the above make rt6_probe() more readable. Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa Cc: Julian Anastasov Cc: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/route.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index c9b2b9fe83fc4..0ef52623fc777 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -545,6 +545,7 @@ static void rt6_probe_deferred(struct work_struct *w) static void rt6_probe(struct rt6_info *rt) { + struct __rt6_probe_work *work; struct neighbour *neigh; /* * Okay, this does not seem to be appropriate @@ -559,34 +560,29 @@ static void rt6_probe(struct rt6_info *rt) rcu_read_lock_bh(); neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); if (neigh) { + work = NULL; write_lock(&neigh->lock); - if (neigh->nud_state & NUD_VALID) - goto out; - } - - if (!neigh || - time_after(jiffies, neigh->updated + rt->rt6i_idev->cnf.rtr_probe_interval)) { - struct __rt6_probe_work *work; - - work = kmalloc(sizeof(*work), GFP_ATOMIC); - - if (neigh && work) - __neigh_set_probe_once(neigh); - - if (neigh) - write_unlock(&neigh->lock); - - if (work) { - INIT_WORK(&work->work, rt6_probe_deferred); - work->target = rt->rt6i_gateway; - dev_hold(rt->dst.dev); - work->dev = rt->dst.dev; - schedule_work(&work->work); + if (!(neigh->nud_state & NUD_VALID) && + time_after(jiffies, + neigh->updated + + rt->rt6i_idev->cnf.rtr_probe_interval)) { + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (work) + __neigh_set_probe_once(neigh); } - } else { -out: write_unlock(&neigh->lock); + } else { + work = kmalloc(sizeof(*work), GFP_ATOMIC); + } + + if (work) { + INIT_WORK(&work->work, rt6_probe_deferred); + work->target = rt->rt6i_gateway; + dev_hold(rt->dst.dev); + work->dev = rt->dst.dev; + schedule_work(&work->work); } + rcu_read_unlock_bh(); } #else -- GitLab From 8d6c31bf574177c8de48dd1387d96e1ec3a8b8bc Mon Sep 17 00:00:00 2001 From: Martin KaFai Lau Date: Fri, 24 Jul 2015 09:57:43 -0700 Subject: [PATCH 1725/7006] ipv6: Avoid rt6_probe() taking writer lock in the fast path The patch checks neigh->nud_state before acquiring the writer lock. Note that rt6_probe() is only used in CONFIG_IPV6_ROUTER_PREF. 40 udpflood processes and a /64 gateway route are used. The gateway has NUD_PERMANENT. Each of them is run for 30s. At the end, the total number of finished sendto(): Before: 55M After: 95M Signed-off-by: Martin KaFai Lau Cc: Hannes Frederic Sowa CC: Julian Anastasov CC: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/route.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0ef52623fc777..54fccf0d705dd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -560,6 +560,9 @@ static void rt6_probe(struct rt6_info *rt) rcu_read_lock_bh(); neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); if (neigh) { + if (neigh->nud_state & NUD_VALID) + goto out; + work = NULL; write_lock(&neigh->lock); if (!(neigh->nud_state & NUD_VALID) && @@ -583,6 +586,7 @@ static void rt6_probe(struct rt6_info *rt) schedule_work(&work->work); } +out: rcu_read_unlock_bh(); } #else -- GitLab From 71790a2792c8772e29bf5aa726215d9256ef93dc Mon Sep 17 00:00:00 2001 From: Haiyang Zhang Date: Fri, 24 Jul 2015 10:08:40 -0700 Subject: [PATCH 1726/7006] hv_netvsc: Add structs and handlers for VF messages This patch adds data structures and handlers for messages related to SRIOV Virtual Function. Signed-off-by: Haiyang Zhang Reviewed-by: K. Y. Srinivasan Signed-off-by: David S. Miller --- drivers/net/hyperv/hyperv_net.h | 29 ++++++++++++++++++++++ drivers/net/hyperv/netvsc.c | 43 +++++++++++++++++++++++++-------- 2 files changed, 62 insertions(+), 10 deletions(-) diff --git a/drivers/net/hyperv/hyperv_net.h b/drivers/net/hyperv/hyperv_net.h index 925b75d4d9103..5ce7020ca5300 100644 --- a/drivers/net/hyperv/hyperv_net.h +++ b/drivers/net/hyperv/hyperv_net.h @@ -541,6 +541,29 @@ union nvsp_2_message_uber { struct nvsp_2_free_rxbuf free_rxbuf; } __packed; +struct nvsp_4_send_vf_association { + /* 1: allocated, serial number is valid. 0: not allocated */ + u32 allocated; + + /* Serial number of the VF to team with */ + u32 serial; +} __packed; + +enum nvsp_vm_datapath { + NVSP_DATAPATH_SYNTHETIC = 0, + NVSP_DATAPATH_VF, + NVSP_DATAPATH_MAX +}; + +struct nvsp_4_sw_datapath { + u32 active_datapath; /* active data path in VM */ +} __packed; + +union nvsp_4_message_uber { + struct nvsp_4_send_vf_association vf_assoc; + struct nvsp_4_sw_datapath active_dp; +} __packed; + enum nvsp_subchannel_operation { NVSP_SUBCHANNEL_NONE = 0, NVSP_SUBCHANNEL_ALLOCATE, @@ -578,6 +601,7 @@ union nvsp_all_messages { union nvsp_message_init_uber init_msg; union nvsp_1_message_uber v1_msg; union nvsp_2_message_uber v2_msg; + union nvsp_4_message_uber v4_msg; union nvsp_5_message_uber v5_msg; } __packed; @@ -691,6 +715,11 @@ struct netvsc_device { /* The net device context */ struct net_device_context *nd_ctx; + + /* 1: allocated, serial number is valid. 0: not allocated */ + u32 vf_alloc; + /* Serial number of the VF to team with */ + u32 vf_serial; }; /* NdisInitialize message */ diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c index 23126a74f3577..51e4c0fd0a748 100644 --- a/drivers/net/hyperv/netvsc.c +++ b/drivers/net/hyperv/netvsc.c @@ -453,13 +453,16 @@ static int negotiate_nvsp_ver(struct hv_device *device, if (nvsp_ver == NVSP_PROTOCOL_VERSION_1) return 0; - /* NVSPv2 only: Send NDIS config */ + /* NVSPv2 or later: Send NDIS config */ memset(init_packet, 0, sizeof(struct nvsp_message)); init_packet->hdr.msg_type = NVSP_MSG2_TYPE_SEND_NDIS_CONFIG; init_packet->msg.v2_msg.send_ndis_config.mtu = net_device->ndev->mtu + ETH_HLEN; init_packet->msg.v2_msg.send_ndis_config.capability.ieee8021q = 1; + if (nvsp_ver >= NVSP_PROTOCOL_VERSION_5) + init_packet->msg.v2_msg.send_ndis_config.capability.sriov = 1; + ret = vmbus_sendpacket(device->channel, init_packet, sizeof(struct nvsp_message), (unsigned long)init_packet, @@ -1064,11 +1067,10 @@ static void netvsc_receive(struct netvsc_device *net_device, static void netvsc_send_table(struct hv_device *hdev, - struct vmpacket_descriptor *vmpkt) + struct nvsp_message *nvmsg) { struct netvsc_device *nvscdev; struct net_device *ndev; - struct nvsp_message *nvmsg; int i; u32 count, *tab; @@ -1077,12 +1079,6 @@ static void netvsc_send_table(struct hv_device *hdev, return; ndev = nvscdev->ndev; - nvmsg = (struct nvsp_message *)((unsigned long)vmpkt + - (vmpkt->offset8 << 3)); - - if (nvmsg->hdr.msg_type != NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE) - return; - count = nvmsg->msg.v5_msg.send_table.count; if (count != VRSS_SEND_TAB_SIZE) { netdev_err(ndev, "Received wrong send-table size:%u\n", count); @@ -1096,6 +1092,28 @@ static void netvsc_send_table(struct hv_device *hdev, nvscdev->send_table[i] = tab[i]; } +static void netvsc_send_vf(struct netvsc_device *nvdev, + struct nvsp_message *nvmsg) +{ + nvdev->vf_alloc = nvmsg->msg.v4_msg.vf_assoc.allocated; + nvdev->vf_serial = nvmsg->msg.v4_msg.vf_assoc.serial; +} + +static inline void netvsc_receive_inband(struct hv_device *hdev, + struct netvsc_device *nvdev, + struct nvsp_message *nvmsg) +{ + switch (nvmsg->hdr.msg_type) { + case NVSP_MSG5_TYPE_SEND_INDIRECTION_TABLE: + netvsc_send_table(hdev, nvmsg); + break; + + case NVSP_MSG4_TYPE_SEND_VF_ASSOCIATION: + netvsc_send_vf(nvdev, nvmsg); + break; + } +} + void netvsc_channel_cb(void *context) { int ret; @@ -1108,6 +1126,7 @@ void netvsc_channel_cb(void *context) unsigned char *buffer; int bufferlen = NETVSC_PACKET_SIZE; struct net_device *ndev; + struct nvsp_message *nvmsg; if (channel->primary_channel != NULL) device = channel->primary_channel->device_obj; @@ -1126,6 +1145,8 @@ void netvsc_channel_cb(void *context) if (ret == 0) { if (bytes_recvd > 0) { desc = (struct vmpacket_descriptor *)buffer; + nvmsg = (struct nvsp_message *)((unsigned long) + desc + (desc->offset8 << 3)); switch (desc->type) { case VM_PKT_COMP: netvsc_send_completion(net_device, @@ -1138,7 +1159,9 @@ void netvsc_channel_cb(void *context) break; case VM_PKT_DATA_INBAND: - netvsc_send_table(device, desc); + netvsc_receive_inband(device, + net_device, + nvmsg); break; default: -- GitLab From c22995c5488d7048554d85ee5ee8a269932b0aea Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 25 Jul 2015 09:42:28 -0700 Subject: [PATCH 1727/7006] dsa: mv88e6352/mv88e6xxx: Move temperature sensor code to mv88e6xxx.c Move the temperature sensing code for mv88e6352 and mv88e6320 families into mv88e6xxx.c to simplify adding support for additional chips. With this change, mv88e6xxx_6320_family() no longer needs to be a global function and is made static. Cc: Andrew Lunn Signed-off-by: Guenter Roeck Acked-by: Andrew Lunn Tested-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6352.c | 72 +-------------- drivers/net/dsa/mv88e6xxx.c | 176 ++++++++++++++++++++++++++---------- drivers/net/dsa/mv88e6xxx.h | 7 +- 3 files changed, 136 insertions(+), 119 deletions(-) diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index cfece5ae9d5fd..af210efecc554 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -92,70 +92,6 @@ static int mv88e6352_setup_global(struct dsa_switch *ds) return 0; } -#ifdef CONFIG_NET_DSA_HWMON - -static int mv88e6352_get_temp(struct dsa_switch *ds, int *temp) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - *temp = 0; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); - if (ret < 0) - return ret; - - *temp = (ret & 0xff) - 25; - - return 0; -} - -static int mv88e6352_get_temp_limit(struct dsa_switch *ds, int *temp) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - *temp = 0; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); - if (ret < 0) - return ret; - - *temp = (((ret >> 8) & 0x1f) * 5) - 25; - - return 0; -} - -static int mv88e6352_set_temp_limit(struct dsa_switch *ds, int temp) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); - if (ret < 0) - return ret; - temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); - return mv88e6xxx_phy_page_write(ds, phy, 6, 26, - (ret & 0xe0ff) | (temp << 8)); -} - -static int mv88e6352_get_temp_alarm(struct dsa_switch *ds, bool *alarm) -{ - int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; - int ret; - - *alarm = false; - - ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); - if (ret < 0) - return ret; - - *alarm = !!(ret & 0x40); - - return 0; -} -#endif /* CONFIG_NET_DSA_HWMON */ - static int mv88e6352_setup(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -393,10 +329,10 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, #ifdef CONFIG_NET_DSA_HWMON - .get_temp = mv88e6352_get_temp, - .get_temp_limit = mv88e6352_get_temp_limit, - .set_temp_limit = mv88e6352_set_temp_limit, - .get_temp_alarm = mv88e6352_get_temp_alarm, + .get_temp = mv88e6xxx_get_temp, + .get_temp_limit = mv88e6xxx_get_temp_limit, + .set_temp_limit = mv88e6xxx_set_temp_limit, + .get_temp_alarm = mv88e6xxx_get_temp_alarm, #endif .get_eeprom = mv88e6352_get_eeprom, .set_eeprom = mv88e6352_set_eeprom, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 5158375b7abd1..61ce4cf120a68 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -517,7 +517,7 @@ static bool mv88e6xxx_6185_family(struct dsa_switch *ds) return false; } -bool mv88e6xxx_6320_family(struct dsa_switch *ds) +static bool mv88e6xxx_6320_family(struct dsa_switch *ds) { struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); @@ -808,54 +808,6 @@ void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, } } -#ifdef CONFIG_NET_DSA_HWMON - -int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) -{ - struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); - int ret; - int val; - - *temp = 0; - - mutex_lock(&ps->smi_mutex); - - ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); - if (ret < 0) - goto error; - - /* Enable temperature sensor */ - ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); - if (ret < 0) - goto error; - - ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); - if (ret < 0) - goto error; - - /* Wait for temperature to stabilize */ - usleep_range(10000, 12000); - - val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); - if (val < 0) { - ret = val; - goto error; - } - - /* Disable temperature sensor */ - ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); - if (ret < 0) - goto error; - - *temp = ((val & 0x1f) - 5) * 5; - -error: - _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); - mutex_unlock(&ps->smi_mutex); - return ret; -} -#endif /* CONFIG_NET_DSA_HWMON */ - /* Must be called with SMI lock held */ static int _mv88e6xxx_wait(struct dsa_switch *ds, int reg, int offset, u16 mask) @@ -2180,6 +2132,132 @@ mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int port, int regnum, return ret; } +#ifdef CONFIG_NET_DSA_HWMON + +static int mv88e61xx_get_temp(struct dsa_switch *ds, int *temp) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + int ret; + int val; + + *temp = 0; + + mutex_lock(&ps->smi_mutex); + + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x6); + if (ret < 0) + goto error; + + /* Enable temperature sensor */ + ret = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); + if (ret < 0) + goto error; + + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret | (1 << 5)); + if (ret < 0) + goto error; + + /* Wait for temperature to stabilize */ + usleep_range(10000, 12000); + + val = _mv88e6xxx_phy_read(ds, 0x0, 0x1a); + if (val < 0) { + ret = val; + goto error; + } + + /* Disable temperature sensor */ + ret = _mv88e6xxx_phy_write(ds, 0x0, 0x1a, ret & ~(1 << 5)); + if (ret < 0) + goto error; + + *temp = ((val & 0x1f) - 5) * 5; + +error: + _mv88e6xxx_phy_write(ds, 0x0, 0x16, 0x0); + mutex_unlock(&ps->smi_mutex); + return ret; +} + +static int mv88e63xx_get_temp(struct dsa_switch *ds, int *temp) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + *temp = 0; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 27); + if (ret < 0) + return ret; + + *temp = (ret & 0xff) - 25; + + return 0; +} + +int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp) +{ + if (mv88e6xxx_6320_family(ds) || mv88e6xxx_6352_family(ds)) + return mv88e63xx_get_temp(ds, temp); + + return mv88e61xx_get_temp(ds, temp); +} + +int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) + return -EOPNOTSUPP; + + *temp = 0; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); + if (ret < 0) + return ret; + + *temp = (((ret >> 8) & 0x1f) * 5) - 25; + + return 0; +} + +int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) + return -EOPNOTSUPP; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); + if (ret < 0) + return ret; + temp = clamp_val(DIV_ROUND_CLOSEST(temp, 5) + 5, 0, 0x1f); + return mv88e6xxx_phy_page_write(ds, phy, 6, 26, + (ret & 0xe0ff) | (temp << 8)); +} + +int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm) +{ + int phy = mv88e6xxx_6320_family(ds) ? 3 : 0; + int ret; + + if (!mv88e6xxx_6320_family(ds) && !mv88e6xxx_6352_family(ds)) + return -EOPNOTSUPP; + + *alarm = false; + + ret = mv88e6xxx_phy_page_read(ds, phy, 6, 26); + if (ret < 0) + return ret; + + *alarm = !!(ret & 0x40); + + return 0; +} +#endif /* CONFIG_NET_DSA_HWMON */ + static int __init mv88e6xxx_init(void) { #if IS_ENABLED(CONFIG_NET_DSA_MV88E6131) diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 64786cb89a93b..78e37226a37d2 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -394,7 +394,10 @@ int mv88e6xxx_get_sset_count_basic(struct dsa_switch *ds); int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, struct ethtool_regs *regs, void *_p); -int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp); +int mv88e6xxx_get_temp(struct dsa_switch *ds, int *temp); +int mv88e6xxx_get_temp_limit(struct dsa_switch *ds, int *temp); +int mv88e6xxx_set_temp_limit(struct dsa_switch *ds, int temp); +int mv88e6xxx_get_temp_alarm(struct dsa_switch *ds, bool *alarm); int mv88e6xxx_eeprom_load_wait(struct dsa_switch *ds); int mv88e6xxx_eeprom_busy_wait(struct dsa_switch *ds); int mv88e6xxx_phy_read_indirect(struct dsa_switch *ds, int addr, int regnum); @@ -415,7 +418,7 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port, int mv88e6xxx_phy_page_read(struct dsa_switch *ds, int port, int page, int reg); int mv88e6xxx_phy_page_write(struct dsa_switch *ds, int port, int page, int reg, int val); -bool mv88e6xxx_6320_family(struct dsa_switch *ds); + extern struct dsa_switch_driver mv88e6131_switch_driver; extern struct dsa_switch_driver mv88e6123_61_65_switch_driver; extern struct dsa_switch_driver mv88e6352_switch_driver; -- GitLab From 2f45d1902acfc7e6680cfeeb38922dcc7e16deb6 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 25 Jul 2015 23:42:01 +0300 Subject: [PATCH 1728/7006] ravb: minimize TX data copying Renesas Ethernet AVB controller requires that all data are aligned on 4-byte boundary. While it's easily achievable for the RX data with the help of skb_reserve() (we even align on 128-byte boundary as recommended by the manual), we can't do the same with the TX data, and it always comes unaligned from the networking core. Originally we solved it an easy way, copying all packet to a preallocated aligned buffer; however, it's enough to copy only up to 3 first bytes from each packet, doing the transfer using 2 TX descriptors instead of just 1. Here's an implementation of the new TX algorithm that significantly reduces the driver's memory requirements. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb.h | 5 +- drivers/net/ethernet/renesas/ravb_main.c | 104 +++++++++++++---------- 2 files changed, 64 insertions(+), 45 deletions(-) diff --git a/drivers/net/ethernet/renesas/ravb.h b/drivers/net/ethernet/renesas/ravb.h index 8aa50ac4e2d61..a157aaaaff6a1 100644 --- a/drivers/net/ethernet/renesas/ravb.h +++ b/drivers/net/ethernet/renesas/ravb.h @@ -658,6 +658,8 @@ struct ravb_desc { __le32 dptr; /* Descriptor pointer */ }; +#define DPTR_ALIGN 4 /* Required descriptor pointer alignment */ + enum DIE_DT { /* Frame data */ DT_FMID = 0x40, @@ -739,6 +741,7 @@ enum RAVB_QUEUE { #define RX_QUEUE_OFFSET 4 #define NUM_RX_QUEUE 2 #define NUM_TX_QUEUE 2 +#define NUM_TX_DESC 2 /* TX descriptors per packet */ struct ravb_tstamp_skb { struct list_head list; @@ -777,9 +780,9 @@ struct ravb_private { dma_addr_t tx_desc_dma[NUM_TX_QUEUE]; struct ravb_ex_rx_desc *rx_ring[NUM_RX_QUEUE]; struct ravb_tx_desc *tx_ring[NUM_TX_QUEUE]; + void *tx_align[NUM_TX_QUEUE]; struct sk_buff **rx_skb[NUM_RX_QUEUE]; struct sk_buff **tx_skb[NUM_TX_QUEUE]; - void **tx_buffers[NUM_TX_QUEUE]; u32 rx_over_errors; u32 rx_fifo_errors; struct net_device_stats stats[NUM_RX_QUEUE]; diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 779bb58a068e8..3d972d8194200 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -195,12 +195,8 @@ static void ravb_ring_free(struct net_device *ndev, int q) priv->tx_skb[q] = NULL; /* Free aligned TX buffers */ - if (priv->tx_buffers[q]) { - for (i = 0; i < priv->num_tx_ring[q]; i++) - kfree(priv->tx_buffers[q][i]); - } - kfree(priv->tx_buffers[q]); - priv->tx_buffers[q] = NULL; + kfree(priv->tx_align[q]); + priv->tx_align[q] = NULL; if (priv->rx_ring[q]) { ring_size = sizeof(struct ravb_ex_rx_desc) * @@ -212,7 +208,7 @@ static void ravb_ring_free(struct net_device *ndev, int q) if (priv->tx_ring[q]) { ring_size = sizeof(struct ravb_tx_desc) * - (priv->num_tx_ring[q] + 1); + (priv->num_tx_ring[q] * NUM_TX_DESC + 1); dma_free_coherent(NULL, ring_size, priv->tx_ring[q], priv->tx_desc_dma[q]); priv->tx_ring[q] = NULL; @@ -227,7 +223,8 @@ static void ravb_ring_format(struct net_device *ndev, int q) struct ravb_tx_desc *tx_desc; struct ravb_desc *desc; int rx_ring_size = sizeof(*rx_desc) * priv->num_rx_ring[q]; - int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q]; + int tx_ring_size = sizeof(*tx_desc) * priv->num_tx_ring[q] * + NUM_TX_DESC; dma_addr_t dma_addr; int i; @@ -260,11 +257,12 @@ static void ravb_ring_format(struct net_device *ndev, int q) memset(priv->tx_ring[q], 0, tx_ring_size); /* Build TX ring buffer */ - for (i = 0; i < priv->num_tx_ring[q]; i++) { - tx_desc = &priv->tx_ring[q][i]; + for (i = 0, tx_desc = priv->tx_ring[q]; i < priv->num_tx_ring[q]; + i++, tx_desc++) { + tx_desc->die_dt = DT_EEMPTY; + tx_desc++; tx_desc->die_dt = DT_EEMPTY; } - tx_desc = &priv->tx_ring[q][i]; tx_desc->dptr = cpu_to_le32((u32)priv->tx_desc_dma[q]); tx_desc->die_dt = DT_LINKFIX; /* type */ @@ -285,7 +283,6 @@ static int ravb_ring_init(struct net_device *ndev, int q) struct ravb_private *priv = netdev_priv(ndev); struct sk_buff *skb; int ring_size; - void *buffer; int i; /* Allocate RX and TX skb rings */ @@ -305,19 +302,11 @@ static int ravb_ring_init(struct net_device *ndev, int q) } /* Allocate rings for the aligned buffers */ - priv->tx_buffers[q] = kcalloc(priv->num_tx_ring[q], - sizeof(*priv->tx_buffers[q]), GFP_KERNEL); - if (!priv->tx_buffers[q]) + priv->tx_align[q] = kmalloc(DPTR_ALIGN * priv->num_tx_ring[q] + + DPTR_ALIGN - 1, GFP_KERNEL); + if (!priv->tx_align[q]) goto error; - for (i = 0; i < priv->num_tx_ring[q]; i++) { - buffer = kmalloc(PKT_BUF_SZ + RAVB_ALIGN - 1, GFP_KERNEL); - if (!buffer) - goto error; - /* Aligned TX buffer */ - priv->tx_buffers[q][i] = buffer; - } - /* Allocate all RX descriptors. */ ring_size = sizeof(struct ravb_ex_rx_desc) * (priv->num_rx_ring[q] + 1); priv->rx_ring[q] = dma_alloc_coherent(NULL, ring_size, @@ -329,7 +318,8 @@ static int ravb_ring_init(struct net_device *ndev, int q) priv->dirty_rx[q] = 0; /* Allocate all TX descriptors. */ - ring_size = sizeof(struct ravb_tx_desc) * (priv->num_tx_ring[q] + 1); + ring_size = sizeof(struct ravb_tx_desc) * + (priv->num_tx_ring[q] * NUM_TX_DESC + 1); priv->tx_ring[q] = dma_alloc_coherent(NULL, ring_size, &priv->tx_desc_dma[q], GFP_KERNEL); @@ -443,7 +433,8 @@ static int ravb_tx_free(struct net_device *ndev, int q) u32 size; for (; priv->cur_tx[q] - priv->dirty_tx[q] > 0; priv->dirty_tx[q]++) { - entry = priv->dirty_tx[q] % priv->num_tx_ring[q]; + entry = priv->dirty_tx[q] % (priv->num_tx_ring[q] * + NUM_TX_DESC); desc = &priv->tx_ring[q][entry]; if (desc->die_dt != DT_FEMPTY) break; @@ -451,14 +442,18 @@ static int ravb_tx_free(struct net_device *ndev, int q) dma_rmb(); size = le16_to_cpu(desc->ds_tagl) & TX_DS; /* Free the original skb. */ - if (priv->tx_skb[q][entry]) { + if (priv->tx_skb[q][entry / NUM_TX_DESC]) { dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr), size, DMA_TO_DEVICE); - dev_kfree_skb_any(priv->tx_skb[q][entry]); - priv->tx_skb[q][entry] = NULL; + /* Last packet descriptor? */ + if (entry % NUM_TX_DESC == NUM_TX_DESC - 1) { + entry /= NUM_TX_DESC; + dev_kfree_skb_any(priv->tx_skb[q][entry]); + priv->tx_skb[q][entry] = NULL; + stats->tx_packets++; + } free_num++; } - stats->tx_packets++; stats->tx_bytes += size; desc->die_dt = DT_EEMPTY; } @@ -1284,37 +1279,53 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) u32 dma_addr; void *buffer; u32 entry; + u32 len; spin_lock_irqsave(&priv->lock, flags); - if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q]) { + if (priv->cur_tx[q] - priv->dirty_tx[q] > (priv->num_tx_ring[q] - 1) * + NUM_TX_DESC) { netif_err(priv, tx_queued, ndev, "still transmitting with the full ring!\n"); netif_stop_subqueue(ndev, q); spin_unlock_irqrestore(&priv->lock, flags); return NETDEV_TX_BUSY; } - entry = priv->cur_tx[q] % priv->num_tx_ring[q]; - priv->tx_skb[q][entry] = skb; + entry = priv->cur_tx[q] % (priv->num_tx_ring[q] * NUM_TX_DESC); + priv->tx_skb[q][entry / NUM_TX_DESC] = skb; if (skb_put_padto(skb, ETH_ZLEN)) goto drop; - buffer = PTR_ALIGN(priv->tx_buffers[q][entry], RAVB_ALIGN); - memcpy(buffer, skb->data, skb->len); - desc = &priv->tx_ring[q][entry]; - desc->ds_tagl = cpu_to_le16(skb->len); - dma_addr = dma_map_single(&ndev->dev, buffer, skb->len, DMA_TO_DEVICE); + buffer = PTR_ALIGN(priv->tx_align[q], DPTR_ALIGN) + + entry / NUM_TX_DESC * DPTR_ALIGN; + len = PTR_ALIGN(skb->data, DPTR_ALIGN) - skb->data; + memcpy(buffer, skb->data, len); + dma_addr = dma_map_single(&ndev->dev, buffer, len, DMA_TO_DEVICE); if (dma_mapping_error(&ndev->dev, dma_addr)) goto drop; + + desc = &priv->tx_ring[q][entry]; + desc->ds_tagl = cpu_to_le16(len); + desc->dptr = cpu_to_le32(dma_addr); + + buffer = skb->data + len; + len = skb->len - len; + dma_addr = dma_map_single(&ndev->dev, buffer, len, DMA_TO_DEVICE); + if (dma_mapping_error(&ndev->dev, dma_addr)) + goto unmap; + + desc++; + desc->ds_tagl = cpu_to_le16(len); desc->dptr = cpu_to_le32(dma_addr); /* TX timestamp required */ if (q == RAVB_NC) { ts_skb = kmalloc(sizeof(*ts_skb), GFP_ATOMIC); if (!ts_skb) { - dma_unmap_single(&ndev->dev, dma_addr, skb->len, + desc--; + dma_unmap_single(&ndev->dev, dma_addr, len, DMA_TO_DEVICE); - goto drop; + goto unmap; } ts_skb->skb = skb; ts_skb->tag = priv->ts_skb_tag++; @@ -1330,13 +1341,15 @@ static netdev_tx_t ravb_start_xmit(struct sk_buff *skb, struct net_device *ndev) /* Descriptor type must be set after all the above writes */ dma_wmb(); - desc->die_dt = DT_FSINGLE; + desc->die_dt = DT_FEND; + desc--; + desc->die_dt = DT_FSTART; ravb_write(ndev, ravb_read(ndev, TCCR) | (TCCR_TSRQ0 << q), TCCR); - priv->cur_tx[q]++; - if (priv->cur_tx[q] - priv->dirty_tx[q] >= priv->num_tx_ring[q] && - !ravb_tx_free(ndev, q)) + priv->cur_tx[q] += NUM_TX_DESC; + if (priv->cur_tx[q] - priv->dirty_tx[q] > + (priv->num_tx_ring[q] - 1) * NUM_TX_DESC && !ravb_tx_free(ndev, q)) netif_stop_subqueue(ndev, q); exit: @@ -1344,9 +1357,12 @@ exit: spin_unlock_irqrestore(&priv->lock, flags); return NETDEV_TX_OK; +unmap: + dma_unmap_single(&ndev->dev, le32_to_cpu(desc->dptr), + le16_to_cpu(desc->ds_tagl), DMA_TO_DEVICE); drop: dev_kfree_skb_any(skb); - priv->tx_skb[q][entry] = NULL; + priv->tx_skb[q][entry / NUM_TX_DESC] = NULL; goto exit; } -- GitLab From 99d7662a04c4f9822b042f22ae37f8c7355c2d5a Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Sun, 26 Jul 2015 09:45:24 +0200 Subject: [PATCH 1729/7006] tcp: tso: allow deferring under reordering state While doing experiments with reordering resilience, we found linux senders were not able to send at full speed under reordering, because every incoming SACK was releasing one MSS. This patch removes the limitation, as we did for CWR state in commit a0ea700e409 ("tcp: tso: allow CA_CWR state in tcp_tso_should_defer()") Neal Cardwell had a concern about limited transmit so Yuchung conducted experiments on GFE and found nothing worth adding an extra check on fast path : if (icsk->icsk_ca_state == TCP_CA_Disorder && tcp_sk(sk)->reordering == sysctl_tcp_reordering) goto send_now; Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Cc: Neal Cardwell Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 71057849593ac..7d1efa762b75b 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -1774,7 +1774,7 @@ static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb, if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) goto send_now; - if (!((1 << icsk->icsk_ca_state) & (TCPF_CA_Open | TCPF_CA_CWR))) + if (icsk->icsk_ca_state >= TCP_CA_Recovery) goto send_now; /* Avoid bursty behavior by allowing defer -- GitLab From 042794b1f4234de36ce2d6edae071054c6985a03 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 13:55:10 +0200 Subject: [PATCH 1730/7006] drm/i915: Clean up Makefile Sorting became confused and a few new files ended up in strange places. Also move i915_irq.c to core since with the recent-ish extraction of i915_gpu_error.c and intel_hotplug.c it's more and more really just basic irq handling code. When adding new files please don't put them somewhere randomly. Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index e52e012516445..bf91482e14a33 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -6,12 +6,13 @@ # core driver code i915-y := i915_drv.o \ + i915_irq.o \ i915_params.o \ i915_suspend.o \ i915_sysfs.o \ + intel_csr.o \ intel_pm.o \ - intel_runtime_pm.o \ - intel_csr.o + intel_runtime_pm.o i915-$(CONFIG_COMPAT) += i915_ioc32.o i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o @@ -20,21 +21,19 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o i915-y += i915_cmd_parser.o \ i915_gem_batch_pool.o \ i915_gem_context.o \ - i915_gem_render_state.o \ i915_gem_debug.o \ i915_gem_dmabuf.o \ i915_gem_evict.o \ i915_gem_execbuffer.o \ i915_gem_gtt.o \ i915_gem.o \ + i915_gem_render_state.o \ i915_gem_shrinker.o \ i915_gem_stolen.o \ i915_gem_tiling.o \ i915_gem_userptr.o \ i915_gpu_error.o \ - i915_irq.o \ i915_trace_points.o \ - intel_hotplug.o \ intel_lrc.o \ intel_mocs.o \ intel_ringbuffer.o \ @@ -48,11 +47,14 @@ i915-y += intel_renderstate_gen6.o \ # modesetting core code i915-y += intel_audio.o \ + intel_atomic.o \ + intel_atomic_plane.o \ intel_bios.o \ intel_display.o \ intel_fbc.o \ intel_fifo_underrun.o \ intel_frontbuffer.o \ + intel_hotplug.o \ intel_modes.o \ intel_overlay.o \ intel_psr.o \ @@ -68,15 +70,13 @@ i915-y += dvo_ch7017.o \ dvo_ns2501.o \ dvo_sil164.o \ dvo_tfp410.o \ - intel_atomic.o \ - intel_atomic_plane.o \ intel_crt.o \ intel_ddi.o \ - intel_dp.o \ intel_dp_mst.o \ + intel_dp.o \ intel_dsi.o \ - intel_dsi_pll.o \ intel_dsi_panel_vbt.o \ + intel_dsi_pll.o \ intel_dvo.o \ intel_hdmi.o \ intel_i2c.o \ -- GitLab From 41a36b739ae378043ecc3984bec3dba00353fa34 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 13:55:11 +0200 Subject: [PATCH 1731/7006] drm/i915: Extract i915_gem_fence.c No code changes, just moving all the fence related code into a separate file (and avoiding a bunch of forward declarations while at it). Acked-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/Makefile | 1 + drivers/gpu/drm/i915/i915_drv.h | 16 +- drivers/gpu/drm/i915/i915_gem.c | 401 ------------------------ drivers/gpu/drm/i915/i915_gem_fence.c | 422 ++++++++++++++++++++++++++ 4 files changed, 432 insertions(+), 408 deletions(-) create mode 100644 drivers/gpu/drm/i915/i915_gem_fence.c diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile index bf91482e14a33..41fb8a9c5bef4 100644 --- a/drivers/gpu/drm/i915/Makefile +++ b/drivers/gpu/drm/i915/Makefile @@ -25,6 +25,7 @@ i915-y += i915_cmd_parser.o \ i915_gem_dmabuf.o \ i915_gem_evict.o \ i915_gem_execbuffer.o \ + i915_gem_fence.o \ i915_gem_gtt.o \ i915_gem.o \ i915_gem_render_state.o \ diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index b94ada96b3482..d575029af5412 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2868,11 +2868,6 @@ static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req, int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno); int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno); -int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); -int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); - -bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj); -void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj); struct drm_i915_gem_request * i915_gem_find_active_request(struct intel_engine_cs *ring); @@ -2970,8 +2965,6 @@ struct drm_gem_object *i915_gem_prime_import(struct drm_device *dev, struct dma_buf *i915_gem_prime_export(struct drm_device *dev, struct drm_gem_object *gem_obj, int flags); -void i915_gem_restore_fences(struct drm_device *dev); - unsigned long i915_gem_obj_ggtt_offset_view(struct drm_i915_gem_object *o, const struct i915_ggtt_view *view); @@ -3066,6 +3059,15 @@ i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj) i915_gem_object_ggtt_unpin_view(obj, &i915_ggtt_view_normal); } +/* i915_gem_fence.c */ +int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj); +int __must_check i915_gem_object_put_fence(struct drm_i915_gem_object *obj); + +bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj); +void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj); + +void i915_gem_restore_fences(struct drm_device *dev); + /* i915_gem_context.c */ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 322bbefafbc3a..5d685789b1f99 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -46,11 +46,6 @@ static void i915_gem_object_retire__write(struct drm_i915_gem_object *obj); static void i915_gem_object_retire__read(struct drm_i915_gem_object *obj, int ring); -static void i915_gem_write_fence(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj); -static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, - struct drm_i915_fence_reg *fence, - bool enable); static bool cpu_cache_is_coherent(struct drm_device *dev, enum i915_cache_level level) @@ -66,18 +61,6 @@ static bool cpu_write_needs_clflush(struct drm_i915_gem_object *obj) return obj->pin_display; } -static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) -{ - if (obj->tiling_mode) - i915_gem_release_mmap(obj); - - /* As we do not have an associated fence register, we will force - * a tiling change if we ever need to acquire one. - */ - obj->fence_dirty = false; - obj->fence_reg = I915_FENCE_REG_NONE; -} - /* some bookkeeping */ static void i915_gem_info_add_obj(struct drm_i915_private *dev_priv, size_t size) @@ -2793,27 +2776,6 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv, } } -void i915_gem_restore_fences(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int i; - - for (i = 0; i < dev_priv->num_fence_regs; i++) { - struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; - - /* - * Commit delayed tiling changes if we have an object still - * attached to the fence, otherwise just clear the fence. - */ - if (reg->obj) { - i915_gem_object_update_fence(reg->obj, reg, - reg->obj->tiling_mode); - } else { - i915_gem_write_fence(dev, i, NULL); - } - } -} - void i915_gem_reset(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; @@ -3340,343 +3302,6 @@ int i915_gpu_idle(struct drm_device *dev) return 0; } -static void i965_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - int fence_reg; - int fence_pitch_shift; - - if (INTEL_INFO(dev)->gen >= 6) { - fence_reg = FENCE_REG_SANDYBRIDGE_0; - fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; - } else { - fence_reg = FENCE_REG_965_0; - fence_pitch_shift = I965_FENCE_PITCH_SHIFT; - } - - fence_reg += reg * 8; - - /* To w/a incoherency with non-atomic 64-bit register updates, - * we split the 64-bit update into two 32-bit writes. In order - * for a partial fence not to be evaluated between writes, we - * precede the update with write to turn off the fence register, - * and only enable the fence as the last step. - * - * For extra levels of paranoia, we make sure each step lands - * before applying the next step. - */ - I915_WRITE(fence_reg, 0); - POSTING_READ(fence_reg); - - if (obj) { - u32 size = i915_gem_obj_ggtt_size(obj); - uint64_t val; - - /* Adjust fence size to match tiled area */ - if (obj->tiling_mode != I915_TILING_NONE) { - uint32_t row_size = obj->stride * - (obj->tiling_mode == I915_TILING_Y ? 32 : 8); - size = (size / row_size) * row_size; - } - - val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & - 0xfffff000) << 32; - val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; - val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I965_FENCE_TILING_Y_SHIFT; - val |= I965_FENCE_REG_VALID; - - I915_WRITE(fence_reg + 4, val >> 32); - POSTING_READ(fence_reg + 4); - - I915_WRITE(fence_reg + 0, val); - POSTING_READ(fence_reg); - } else { - I915_WRITE(fence_reg + 4, 0); - POSTING_READ(fence_reg + 4); - } -} - -static void i915_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - u32 val; - - if (obj) { - u32 size = i915_gem_obj_ggtt_size(obj); - int pitch_val; - int tile_width; - - WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) || - (size & -size) != size || - (i915_gem_obj_ggtt_offset(obj) & (size - 1)), - "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", - i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size); - - if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) - tile_width = 128; - else - tile_width = 512; - - /* Note: pitch better be a power of two tile widths */ - pitch_val = obj->stride / tile_width; - pitch_val = ffs(pitch_val) - 1; - - val = i915_gem_obj_ggtt_offset(obj); - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I915_FENCE_SIZE_BITS(size); - val |= pitch_val << I830_FENCE_PITCH_SHIFT; - val |= I830_FENCE_REG_VALID; - } else - val = 0; - - if (reg < 8) - reg = FENCE_REG_830_0 + reg * 4; - else - reg = FENCE_REG_945_8 + (reg - 8) * 4; - - I915_WRITE(reg, val); - POSTING_READ(reg); -} - -static void i830_write_fence_reg(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t val; - - if (obj) { - u32 size = i915_gem_obj_ggtt_size(obj); - uint32_t pitch_val; - - WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) || - (size & -size) != size || - (i915_gem_obj_ggtt_offset(obj) & (size - 1)), - "object 0x%08lx not 512K or pot-size 0x%08x aligned\n", - i915_gem_obj_ggtt_offset(obj), size); - - pitch_val = obj->stride / 128; - pitch_val = ffs(pitch_val) - 1; - - val = i915_gem_obj_ggtt_offset(obj); - if (obj->tiling_mode == I915_TILING_Y) - val |= 1 << I830_FENCE_TILING_Y_SHIFT; - val |= I830_FENCE_SIZE_BITS(size); - val |= pitch_val << I830_FENCE_PITCH_SHIFT; - val |= I830_FENCE_REG_VALID; - } else - val = 0; - - I915_WRITE(FENCE_REG_830_0 + reg * 4, val); - POSTING_READ(FENCE_REG_830_0 + reg * 4); -} - -inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) -{ - return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; -} - -static void i915_gem_write_fence(struct drm_device *dev, int reg, - struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - - /* Ensure that all CPU reads are completed before installing a fence - * and all writes before removing the fence. - */ - if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) - mb(); - - WARN(obj && (!obj->stride || !obj->tiling_mode), - "bogus fence setup with stride: 0x%x, tiling mode: %i\n", - obj->stride, obj->tiling_mode); - - if (IS_GEN2(dev)) - i830_write_fence_reg(dev, reg, obj); - else if (IS_GEN3(dev)) - i915_write_fence_reg(dev, reg, obj); - else if (INTEL_INFO(dev)->gen >= 4) - i965_write_fence_reg(dev, reg, obj); - - /* And similarly be paranoid that no direct access to this region - * is reordered to before the fence is installed. - */ - if (i915_gem_object_needs_mb(obj)) - mb(); -} - -static inline int fence_number(struct drm_i915_private *dev_priv, - struct drm_i915_fence_reg *fence) -{ - return fence - dev_priv->fence_regs; -} - -static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, - struct drm_i915_fence_reg *fence, - bool enable) -{ - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - int reg = fence_number(dev_priv, fence); - - i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); - - if (enable) { - obj->fence_reg = reg; - fence->obj = obj; - list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); - } else { - obj->fence_reg = I915_FENCE_REG_NONE; - fence->obj = NULL; - list_del_init(&fence->lru_list); - } - obj->fence_dirty = false; -} - -static int -i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) -{ - if (obj->last_fenced_req) { - int ret = i915_wait_request(obj->last_fenced_req); - if (ret) - return ret; - - i915_gem_request_assign(&obj->last_fenced_req, NULL); - } - - return 0; -} - -int -i915_gem_object_put_fence(struct drm_i915_gem_object *obj) -{ - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct drm_i915_fence_reg *fence; - int ret; - - ret = i915_gem_object_wait_fence(obj); - if (ret) - return ret; - - if (obj->fence_reg == I915_FENCE_REG_NONE) - return 0; - - fence = &dev_priv->fence_regs[obj->fence_reg]; - - if (WARN_ON(fence->pin_count)) - return -EBUSY; - - i915_gem_object_fence_lost(obj); - i915_gem_object_update_fence(obj, fence, false); - - return 0; -} - -static struct drm_i915_fence_reg * -i915_find_fence_reg(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - struct drm_i915_fence_reg *reg, *avail; - int i; - - /* First try to find a free reg */ - avail = NULL; - for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { - reg = &dev_priv->fence_regs[i]; - if (!reg->obj) - return reg; - - if (!reg->pin_count) - avail = reg; - } - - if (avail == NULL) - goto deadlock; - - /* None available, try to steal one or wait for a user to finish */ - list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { - if (reg->pin_count) - continue; - - return reg; - } - -deadlock: - /* Wait for completion of pending flips which consume fences */ - if (intel_has_pending_fb_unpin(dev)) - return ERR_PTR(-EAGAIN); - - return ERR_PTR(-EDEADLK); -} - -/** - * i915_gem_object_get_fence - set up fencing for an object - * @obj: object to map through a fence reg - * - * When mapping objects through the GTT, userspace wants to be able to write - * to them without having to worry about swizzling if the object is tiled. - * This function walks the fence regs looking for a free one for @obj, - * stealing one if it can't find any. - * - * It then sets up the reg based on the object's properties: address, pitch - * and tiling format. - * - * For an untiled surface, this removes any existing fence. - */ -int -i915_gem_object_get_fence(struct drm_i915_gem_object *obj) -{ - struct drm_device *dev = obj->base.dev; - struct drm_i915_private *dev_priv = dev->dev_private; - bool enable = obj->tiling_mode != I915_TILING_NONE; - struct drm_i915_fence_reg *reg; - int ret; - - /* Have we updated the tiling parameters upon the object and so - * will need to serialise the write to the associated fence register? - */ - if (obj->fence_dirty) { - ret = i915_gem_object_wait_fence(obj); - if (ret) - return ret; - } - - /* Just update our place in the LRU if our fence is getting reused. */ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - reg = &dev_priv->fence_regs[obj->fence_reg]; - if (!obj->fence_dirty) { - list_move_tail(®->lru_list, - &dev_priv->mm.fence_list); - return 0; - } - } else if (enable) { - if (WARN_ON(!obj->map_and_fenceable)) - return -EINVAL; - - reg = i915_find_fence_reg(dev); - if (IS_ERR(reg)) - return PTR_ERR(reg); - - if (reg->obj) { - struct drm_i915_gem_object *old = reg->obj; - - ret = i915_gem_object_wait_fence(old); - if (ret) - return ret; - - i915_gem_object_fence_lost(old); - } - } else - return 0; - - i915_gem_object_update_fence(obj, reg, enable); - - return 0; -} - static bool i915_gem_valid_gtt_space(struct i915_vma *vma, unsigned long cache_level) { @@ -4476,32 +4101,6 @@ i915_gem_object_ggtt_unpin_view(struct drm_i915_gem_object *obj, --vma->pin_count; } -bool -i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) -{ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj); - - WARN_ON(!ggtt_vma || - dev_priv->fence_regs[obj->fence_reg].pin_count > - ggtt_vma->pin_count); - dev_priv->fence_regs[obj->fence_reg].pin_count++; - return true; - } else - return false; -} - -void -i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) -{ - if (obj->fence_reg != I915_FENCE_REG_NONE) { - struct drm_i915_private *dev_priv = obj->base.dev->dev_private; - WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0); - dev_priv->fence_regs[obj->fence_reg].pin_count--; - } -} - int i915_gem_busy_ioctl(struct drm_device *dev, void *data, struct drm_file *file) diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c new file mode 100644 index 0000000000000..d3284ee047940 --- /dev/null +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -0,0 +1,422 @@ +/* + * Copyright © 2008-2015 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. + */ + +#include +#include +#include "i915_drv.h" + +static void i965_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int fence_reg; + int fence_pitch_shift; + + if (INTEL_INFO(dev)->gen >= 6) { + fence_reg = FENCE_REG_SANDYBRIDGE_0; + fence_pitch_shift = SANDYBRIDGE_FENCE_PITCH_SHIFT; + } else { + fence_reg = FENCE_REG_965_0; + fence_pitch_shift = I965_FENCE_PITCH_SHIFT; + } + + fence_reg += reg * 8; + + /* To w/a incoherency with non-atomic 64-bit register updates, + * we split the 64-bit update into two 32-bit writes. In order + * for a partial fence not to be evaluated between writes, we + * precede the update with write to turn off the fence register, + * and only enable the fence as the last step. + * + * For extra levels of paranoia, we make sure each step lands + * before applying the next step. + */ + I915_WRITE(fence_reg, 0); + POSTING_READ(fence_reg); + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + uint64_t val; + + /* Adjust fence size to match tiled area */ + if (obj->tiling_mode != I915_TILING_NONE) { + uint32_t row_size = obj->stride * + (obj->tiling_mode == I915_TILING_Y ? 32 : 8); + size = (size / row_size) * row_size; + } + + val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) & + 0xfffff000) << 32; + val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000; + val |= (uint64_t)((obj->stride / 128) - 1) << fence_pitch_shift; + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I965_FENCE_TILING_Y_SHIFT; + val |= I965_FENCE_REG_VALID; + + I915_WRITE(fence_reg + 4, val >> 32); + POSTING_READ(fence_reg + 4); + + I915_WRITE(fence_reg + 0, val); + POSTING_READ(fence_reg); + } else { + I915_WRITE(fence_reg + 4, 0); + POSTING_READ(fence_reg + 4); + } +} + +static void i915_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + u32 val; + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + int pitch_val; + int tile_width; + + WARN((i915_gem_obj_ggtt_offset(obj) & ~I915_FENCE_START_MASK) || + (size & -size) != size || + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx [fenceable? %d] not 1M or pot-size (0x%08x) aligned\n", + i915_gem_obj_ggtt_offset(obj), obj->map_and_fenceable, size); + + if (obj->tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING(dev)) + tile_width = 128; + else + tile_width = 512; + + /* Note: pitch better be a power of two tile widths */ + pitch_val = obj->stride / tile_width; + pitch_val = ffs(pitch_val) - 1; + + val = i915_gem_obj_ggtt_offset(obj); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I915_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + if (reg < 8) + reg = FENCE_REG_830_0 + reg * 4; + else + reg = FENCE_REG_945_8 + (reg - 8) * 4; + + I915_WRITE(reg, val); + POSTING_READ(reg); +} + +static void i830_write_fence_reg(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t val; + + if (obj) { + u32 size = i915_gem_obj_ggtt_size(obj); + uint32_t pitch_val; + + WARN((i915_gem_obj_ggtt_offset(obj) & ~I830_FENCE_START_MASK) || + (size & -size) != size || + (i915_gem_obj_ggtt_offset(obj) & (size - 1)), + "object 0x%08lx not 512K or pot-size 0x%08x aligned\n", + i915_gem_obj_ggtt_offset(obj), size); + + pitch_val = obj->stride / 128; + pitch_val = ffs(pitch_val) - 1; + + val = i915_gem_obj_ggtt_offset(obj); + if (obj->tiling_mode == I915_TILING_Y) + val |= 1 << I830_FENCE_TILING_Y_SHIFT; + val |= I830_FENCE_SIZE_BITS(size); + val |= pitch_val << I830_FENCE_PITCH_SHIFT; + val |= I830_FENCE_REG_VALID; + } else + val = 0; + + I915_WRITE(FENCE_REG_830_0 + reg * 4, val); + POSTING_READ(FENCE_REG_830_0 + reg * 4); +} + +inline static bool i915_gem_object_needs_mb(struct drm_i915_gem_object *obj) +{ + return obj && obj->base.read_domains & I915_GEM_DOMAIN_GTT; +} + +static void i915_gem_write_fence(struct drm_device *dev, int reg, + struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + + /* Ensure that all CPU reads are completed before installing a fence + * and all writes before removing the fence. + */ + if (i915_gem_object_needs_mb(dev_priv->fence_regs[reg].obj)) + mb(); + + WARN(obj && (!obj->stride || !obj->tiling_mode), + "bogus fence setup with stride: 0x%x, tiling mode: %i\n", + obj->stride, obj->tiling_mode); + + if (IS_GEN2(dev)) + i830_write_fence_reg(dev, reg, obj); + else if (IS_GEN3(dev)) + i915_write_fence_reg(dev, reg, obj); + else if (INTEL_INFO(dev)->gen >= 4) + i965_write_fence_reg(dev, reg, obj); + + /* And similarly be paranoid that no direct access to this region + * is reordered to before the fence is installed. + */ + if (i915_gem_object_needs_mb(obj)) + mb(); +} + +static inline int fence_number(struct drm_i915_private *dev_priv, + struct drm_i915_fence_reg *fence) +{ + return fence - dev_priv->fence_regs; +} + +static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj, + struct drm_i915_fence_reg *fence, + bool enable) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + int reg = fence_number(dev_priv, fence); + + i915_gem_write_fence(obj->base.dev, reg, enable ? obj : NULL); + + if (enable) { + obj->fence_reg = reg; + fence->obj = obj; + list_move_tail(&fence->lru_list, &dev_priv->mm.fence_list); + } else { + obj->fence_reg = I915_FENCE_REG_NONE; + fence->obj = NULL; + list_del_init(&fence->lru_list); + } + obj->fence_dirty = false; +} + +static inline void i915_gem_object_fence_lost(struct drm_i915_gem_object *obj) +{ + if (obj->tiling_mode) + i915_gem_release_mmap(obj); + + /* As we do not have an associated fence register, we will force + * a tiling change if we ever need to acquire one. + */ + obj->fence_dirty = false; + obj->fence_reg = I915_FENCE_REG_NONE; +} + +static int +i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) +{ + if (obj->last_fenced_req) { + int ret = i915_wait_request(obj->last_fenced_req); + if (ret) + return ret; + + i915_gem_request_assign(&obj->last_fenced_req, NULL); + } + + return 0; +} + +int +i915_gem_object_put_fence(struct drm_i915_gem_object *obj) +{ + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct drm_i915_fence_reg *fence; + int ret; + + ret = i915_gem_object_wait_fence(obj); + if (ret) + return ret; + + if (obj->fence_reg == I915_FENCE_REG_NONE) + return 0; + + fence = &dev_priv->fence_regs[obj->fence_reg]; + + if (WARN_ON(fence->pin_count)) + return -EBUSY; + + i915_gem_object_fence_lost(obj); + i915_gem_object_update_fence(obj, fence, false); + + return 0; +} + +static struct drm_i915_fence_reg * +i915_find_fence_reg(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + struct drm_i915_fence_reg *reg, *avail; + int i; + + /* First try to find a free reg */ + avail = NULL; + for (i = dev_priv->fence_reg_start; i < dev_priv->num_fence_regs; i++) { + reg = &dev_priv->fence_regs[i]; + if (!reg->obj) + return reg; + + if (!reg->pin_count) + avail = reg; + } + + if (avail == NULL) + goto deadlock; + + /* None available, try to steal one or wait for a user to finish */ + list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) { + if (reg->pin_count) + continue; + + return reg; + } + +deadlock: + /* Wait for completion of pending flips which consume fences */ + if (intel_has_pending_fb_unpin(dev)) + return ERR_PTR(-EAGAIN); + + return ERR_PTR(-EDEADLK); +} + +/** + * i915_gem_object_get_fence - set up fencing for an object + * @obj: object to map through a fence reg + * + * When mapping objects through the GTT, userspace wants to be able to write + * to them without having to worry about swizzling if the object is tiled. + * This function walks the fence regs looking for a free one for @obj, + * stealing one if it can't find any. + * + * It then sets up the reg based on the object's properties: address, pitch + * and tiling format. + * + * For an untiled surface, this removes any existing fence. + */ +int +i915_gem_object_get_fence(struct drm_i915_gem_object *obj) +{ + struct drm_device *dev = obj->base.dev; + struct drm_i915_private *dev_priv = dev->dev_private; + bool enable = obj->tiling_mode != I915_TILING_NONE; + struct drm_i915_fence_reg *reg; + int ret; + + /* Have we updated the tiling parameters upon the object and so + * will need to serialise the write to the associated fence register? + */ + if (obj->fence_dirty) { + ret = i915_gem_object_wait_fence(obj); + if (ret) + return ret; + } + + /* Just update our place in the LRU if our fence is getting reused. */ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + reg = &dev_priv->fence_regs[obj->fence_reg]; + if (!obj->fence_dirty) { + list_move_tail(®->lru_list, + &dev_priv->mm.fence_list); + return 0; + } + } else if (enable) { + if (WARN_ON(!obj->map_and_fenceable)) + return -EINVAL; + + reg = i915_find_fence_reg(dev); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + if (reg->obj) { + struct drm_i915_gem_object *old = reg->obj; + + ret = i915_gem_object_wait_fence(old); + if (ret) + return ret; + + i915_gem_object_fence_lost(old); + } + } else + return 0; + + i915_gem_object_update_fence(obj, reg, enable); + + return 0; +} + +bool +i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) +{ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + struct i915_vma *ggtt_vma = i915_gem_obj_to_ggtt(obj); + + WARN_ON(!ggtt_vma || + dev_priv->fence_regs[obj->fence_reg].pin_count > + ggtt_vma->pin_count); + dev_priv->fence_regs[obj->fence_reg].pin_count++; + return true; + } else + return false; +} + +void +i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) +{ + if (obj->fence_reg != I915_FENCE_REG_NONE) { + struct drm_i915_private *dev_priv = obj->base.dev->dev_private; + WARN_ON(dev_priv->fence_regs[obj->fence_reg].pin_count <= 0); + dev_priv->fence_regs[obj->fence_reg].pin_count--; + } +} + +void i915_gem_restore_fences(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + int i; + + for (i = 0; i < dev_priv->num_fence_regs; i++) { + struct drm_i915_fence_reg *reg = &dev_priv->fence_regs[i]; + + /* + * Commit delayed tiling changes if we have an object still + * attached to the fence, otherwise just clear the fence. + */ + if (reg->obj) { + i915_gem_object_update_fence(reg->obj, reg, + reg->obj->tiling_mode); + } else { + i915_gem_write_fence(dev, i, NULL); + } + } +} -- GitLab From e11f40b9352f75d924cb216abcc5413b38d9288b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 27 Jul 2015 11:07:47 +0300 Subject: [PATCH 1732/7006] lwtunnel: use kfree_skb() instead of vanilla kfree() kfree_skb() is correct here. Fixes: ffce41962ef6 ('lwtunnel: support dst output redirect function') Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- net/core/lwtunnel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index bb58826c708d6..5f7fae70ef681 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -205,7 +205,7 @@ int __lwtunnel_output(struct sock *sk, struct sk_buff *skb, return ret; drop: - kfree(skb); + kfree_skb(skb); return ret; } -- GitLab From a794f62a300194dbc53165f10cc5ad236a6a43c2 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:12 +0200 Subject: [PATCH 1733/7006] drm/i915: kerneldoc for fences v2: Clarify that this is about fence _registers_. Also clarify that the fence code revokes cpu ptes and not gtt ptes. Both suggested by Chris. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 5 ++ drivers/gpu/drm/i915/i915_gem_fence.c | 75 +++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 1ca1171b16e51..ee2ed7ed27d1d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4197,6 +4197,11 @@ int num_ioctls; Global GTT views !Pdrivers/gpu/drm/i915/i915_gem_gtt.c Global GTT views !Idrivers/gpu/drm/i915/i915_gem_gtt.c + + + Global GTT Fence Handling +!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling +!Idrivers/gpu/drm/i915/i915_gem_fence.c Buffer Object Eviction diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index d3284ee047940..0434c42d8c11f 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -25,6 +25,36 @@ #include #include "i915_drv.h" +/** + * DOC: fence register handling + * + * Important to avoid confusions: "fences" in the i915 driver are not execution + * fences used to track command completion but hardware detiler objects which + * wrap a given range of the global GTT. Each platform has only a fairly limited + * set of these objects. + * + * Fences are used to detile GTT memory mappings. They're also connected to the + * hardware frontbuffer render tracking and hence interract with frontbuffer + * conmpression. Furthermore on older platforms fences are required for tiled + * objects used by the display engine. They can also be used by the render + * engine - they're required for blitter commands and are optional for render + * commands. But on gen4+ both display (with the exception of fbc) and rendering + * have their own tiling state bits and don't need fences. + * + * Also note that fences only support X and Y tiling and hence can't be used for + * the fancier new tiling formats like W, Ys and Yf. + * + * Finally note that because fences are such a restricted resource they're + * dynamically associated with objects. Furthermore fence state is committed to + * the hardware lazily to avoid unecessary stalls on gen2/3. Therefore code must + * explictly call i915_gem_object_get_fence() to synchronize fencing status + * for cpu access. Also note that some code wants an unfenced view, for those + * cases the fence can be removed forcefully with i915_gem_object_put_fence(). + * + * Internally these functions will synchronize with userspace access by removing + * CPU ptes into GTT mmaps (not the GTT ptes themselves) as needed. + */ + static void i965_write_fence_reg(struct drm_device *dev, int reg, struct drm_i915_gem_object *obj) { @@ -247,6 +277,17 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj) return 0; } +/** + * i915_gem_object_put_fence - force-remove fence for an object + * @obj: object to map through a fence reg + * + * This function force-removes any fence from the given object, which is useful + * if the kernel wants to do untiled GTT access. + * + * Returns: + * + * 0 on success, negative error code on failure. + */ int i915_gem_object_put_fence(struct drm_i915_gem_object *obj) { @@ -322,6 +363,10 @@ deadlock: * and tiling format. * * For an untiled surface, this removes any existing fence. + * + * Returns: + * + * 0 on success, negative error code on failure. */ int i915_gem_object_get_fence(struct drm_i915_gem_object *obj) @@ -374,6 +419,21 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj) return 0; } +/** + * i915_gem_object_pin_fence - pin fencing state + * @obj: object to pin fencing for + * + * This pins the fencing state (whether tiled or untiled) to make sure the + * object is ready to be used as a scanout target. Fencing status must be + * synchronize first by calling i915_gem_object_get_fence(): + * + * The resulting fence pin reference must be released again with + * i915_gem_object_unpin_fence(). + * + * Returns: + * + * True if the object has a fence, false otherwise. + */ bool i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) { @@ -390,6 +450,14 @@ i915_gem_object_pin_fence(struct drm_i915_gem_object *obj) return false; } +/** + * i915_gem_object_unpin_fence - unpin fencing state + * @obj: object to unpin fencing for + * + * This releases the fence pin reference acquired through + * i915_gem_object_pin_fence. It will handle both objects with and without an + * attached fence correctly, callers do not need to distinguish this. + */ void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) { @@ -400,6 +468,13 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj) } } +/** + * i915_gem_restore_fences - restore fence state + * @dev: DRM device + * + * Restore the hw fence state to match the software tracking again, to be called + * after a gpu reset and on resume. + */ void i915_gem_restore_fences(struct drm_device *dev) { struct drm_i915_private *dev_priv = dev->dev_private; -- GitLab From e562b9739eda7399d1ec6737bc5f8803f92569e3 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:13 +0200 Subject: [PATCH 1734/7006] drm/i915: Remove bogus kerneldoc include directive Afaict intel_irq_fini never existed. No idea how that one came about. Note: Chris thinks that an irq_fini would be nice and I agree, but this is just to remove some ugly from generated docs. Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 1 - 1 file changed, 1 deletion(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index ee2ed7ed27d1d..20c39b7e21ee8 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -3982,7 +3982,6 @@ int num_ioctls; Interrupt Handling !Pdrivers/gpu/drm/i915/i915_irq.c interrupt handling !Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_init intel_irq_init_hw intel_hpd_init -!Fdrivers/gpu/drm/i915/i915_irq.c intel_irq_fini !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_disable_interrupts !Fdrivers/gpu/drm/i915/i915_irq.c intel_runtime_pm_enable_interrupts -- GitLab From 7f96ecaf1ea26fd7041acc56379a5c4393ee51ad Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:14 +0200 Subject: [PATCH 1735/7006] drm/i915: Move low-level swizzling code to i915_gem_fence.c It fits more with the low-level fence code, and this move leaves only the userspace tiling ioctl handling in i915_gem_tiling.c. Suggested-by: Chris Wilson Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_drv.h | 8 +- drivers/gpu/drm/i915/i915_gem_fence.c | 268 +++++++++++++++++++++++++ drivers/gpu/drm/i915/i915_gem_tiling.c | 219 -------------------- 3 files changed, 272 insertions(+), 223 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index d575029af5412..40fea41affc9e 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3068,6 +3068,10 @@ void i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj); void i915_gem_restore_fences(struct drm_device *dev); +void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); +void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); +void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); + /* i915_gem_context.c */ int __must_check i915_gem_context_init(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev); @@ -3160,10 +3164,6 @@ static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_objec obj->tiling_mode != I915_TILING_NONE; } -void i915_gem_detect_bit_6_swizzle(struct drm_device *dev); -void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj); -void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj); - /* i915_gem_debug.c */ #if WATCH_LISTS int i915_verify_lists(struct drm_device *dev); diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index 0434c42d8c11f..c643260a90c51 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -495,3 +495,271 @@ void i915_gem_restore_fences(struct drm_device *dev) } } } + +/** + * + * Support for managing tiling state of buffer objects. + * + * The idea behind tiling is to increase cache hit rates by rearranging + * pixel data so that a group of pixel accesses are in the same cacheline. + * Performance improvement from doing this on the back/depth buffer are on + * the order of 30%. + * + * Intel architectures make this somewhat more complicated, though, by + * adjustments made to addressing of data when the memory is in interleaved + * mode (matched pairs of DIMMS) to improve memory bandwidth. + * For interleaved memory, the CPU sends every sequential 64 bytes + * to an alternate memory channel so it can get the bandwidth from both. + * + * The GPU also rearranges its accesses for increased bandwidth to interleaved + * memory, and it matches what the CPU does for non-tiled. However, when tiled + * it does it a little differently, since one walks addresses not just in the + * X direction but also Y. So, along with alternating channels when bit + * 6 of the address flips, it also alternates when other bits flip -- Bits 9 + * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines) + * are common to both the 915 and 965-class hardware. + * + * The CPU also sometimes XORs in higher bits as well, to improve + * bandwidth doing strided access like we do so frequently in graphics. This + * is called "Channel XOR Randomization" in the MCH documentation. The result + * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address + * decode. + * + * All of this bit 6 XORing has an effect on our memory management, + * as we need to make sure that the 3d driver can correctly address object + * contents. + * + * If we don't have interleaved memory, all tiling is safe and no swizzling is + * required. + * + * When bit 17 is XORed in, we simply refuse to tile at all. Bit + * 17 is not just a page offset, so as we page an objet out and back in, + * individual pages in it will have different bit 17 addresses, resulting in + * each 64 bytes being swapped with its neighbor! + * + * Otherwise, if interleaved, we have to tell the 3d driver what the address + * swizzling it needs to do is, since it's writing with the CPU to the pages + * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the + * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling + * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order + * to match what the GPU expects. + */ + +/** + * Detects bit 6 swizzling of address lookup between IGD access and CPU + * access through main memory. + */ +void +i915_gem_detect_bit_6_swizzle(struct drm_device *dev) +{ + struct drm_i915_private *dev_priv = dev->dev_private; + uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + + if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) { + /* + * On BDW+, swizzling is not used. We leave the CPU memory + * controller in charge of optimizing memory accesses without + * the extra address manipulation GPU side. + * + * VLV and CHV don't have GPU swizzling. + */ + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } else if (INTEL_INFO(dev)->gen >= 6) { + if (dev_priv->preserve_bios_swizzle) { + if (I915_READ(DISP_ARB_CTL) & + DISP_TILE_SURFACE_SWIZZLING) { + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else { + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } + } else { + uint32_t dimm_c0, dimm_c1; + dimm_c0 = I915_READ(MAD_DIMM_C0); + dimm_c1 = I915_READ(MAD_DIMM_C1); + dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; + dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; + /* Enable swizzling when the channels are populated + * with identically sized dimms. We don't need to check + * the 3rd channel because no cpu with gpu attached + * ships in that configuration. Also, swizzling only + * makes sense for 2 channels anyway. */ + if (dimm_c0 == dimm_c1) { + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else { + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } + } + } else if (IS_GEN5(dev)) { + /* On Ironlake whatever DRAM config, GPU always do + * same swizzling setup. + */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else if (IS_GEN2(dev)) { + /* As far as we know, the 865 doesn't have these bit 6 + * swizzling issues. + */ + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) { + uint32_t dcc; + + /* On 9xx chipsets, channel interleave by the CPU is + * determined by DCC. For single-channel, neither the CPU + * nor the GPU do swizzling. For dual channel interleaved, + * the GPU's interleave is bit 9 and 10 for X tiled, and bit + * 9 for Y tiled. The CPU's interleave is independent, and + * can be based on either bit 11 (haven't seen this yet) or + * bit 17 (common). + */ + dcc = I915_READ(DCC); + switch (dcc & DCC_ADDRESSING_MODE_MASK) { + case DCC_ADDRESSING_MODE_SINGLE_CHANNEL: + case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC: + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + break; + case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED: + if (dcc & DCC_CHANNEL_XOR_DISABLE) { + /* This is the base swizzling by the GPU for + * tiled buffers. + */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) { + /* Bit 11 swizzling by the CPU in addition. */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10_11; + swizzle_y = I915_BIT_6_SWIZZLE_9_11; + } else { + /* Bit 17 swizzling by the CPU in addition. */ + swizzle_x = I915_BIT_6_SWIZZLE_9_10_17; + swizzle_y = I915_BIT_6_SWIZZLE_9_17; + } + break; + } + + /* check for L-shaped memory aka modified enhanced addressing */ + if (IS_GEN4(dev)) { + uint32_t ddc2 = I915_READ(DCC2); + + if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) + dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; + } + + if (dcc == 0xffffffff) { + DRM_ERROR("Couldn't read from MCHBAR. " + "Disabling tiling.\n"); + swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; + swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; + } + } else { + /* The 965, G33, and newer, have a very flexible memory + * configuration. It will enable dual-channel mode + * (interleaving) on as much memory as it can, and the GPU + * will additionally sometimes enable different bit 6 + * swizzling for tiled objects from the CPU. + * + * Here's what I found on the G965: + * slot fill memory size swizzling + * 0A 0B 1A 1B 1-ch 2-ch + * 512 0 0 0 512 0 O + * 512 0 512 0 16 1008 X + * 512 0 0 512 16 1008 X + * 0 512 0 512 16 1008 X + * 1024 1024 1024 0 2048 1024 O + * + * We could probably detect this based on either the DRB + * matching, which was the case for the swizzling required in + * the table above, or from the 1-ch value being less than + * the minimum size of a rank. + */ + if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { + swizzle_x = I915_BIT_6_SWIZZLE_NONE; + swizzle_y = I915_BIT_6_SWIZZLE_NONE; + } else { + swizzle_x = I915_BIT_6_SWIZZLE_9_10; + swizzle_y = I915_BIT_6_SWIZZLE_9; + } + } + + dev_priv->mm.bit_6_swizzle_x = swizzle_x; + dev_priv->mm.bit_6_swizzle_y = swizzle_y; +} + +/** + * Swap every 64 bytes of this page around, to account for it having a new + * bit 17 of its physical address and therefore being interpreted differently + * by the GPU. + */ +static void +i915_gem_swizzle_page(struct page *page) +{ + char temp[64]; + char *vaddr; + int i; + + vaddr = kmap(page); + + for (i = 0; i < PAGE_SIZE; i += 128) { + memcpy(temp, &vaddr[i], 64); + memcpy(&vaddr[i], &vaddr[i + 64], 64); + memcpy(&vaddr[i + 64], temp, 64); + } + + kunmap(page); +} + +void +i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) +{ + struct sg_page_iter sg_iter; + int i; + + if (obj->bit_17 == NULL) + return; + + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + struct page *page = sg_page_iter_page(&sg_iter); + char new_bit_17 = page_to_phys(page) >> 17; + if ((new_bit_17 & 0x1) != + (test_bit(i, obj->bit_17) != 0)) { + i915_gem_swizzle_page(page); + set_page_dirty(page); + } + i++; + } +} + +void +i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) +{ + struct sg_page_iter sg_iter; + int page_count = obj->base.size >> PAGE_SHIFT; + int i; + + if (obj->bit_17 == NULL) { + obj->bit_17 = kcalloc(BITS_TO_LONGS(page_count), + sizeof(long), GFP_KERNEL); + if (obj->bit_17 == NULL) { + DRM_ERROR("Failed to allocate memory for bit 17 " + "record\n"); + return; + } + } + + i = 0; + for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { + if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) + __set_bit(i, obj->bit_17); + else + __clear_bit(i, obj->bit_17); + i++; + } +} diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index 633bd1fcab692..fa7a8d7a24e01 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -80,153 +80,6 @@ * to match what the GPU expects. */ -/** - * Detects bit 6 swizzling of address lookup between IGD access and CPU - * access through main memory. - */ -void -i915_gem_detect_bit_6_swizzle(struct drm_device *dev) -{ - struct drm_i915_private *dev_priv = dev->dev_private; - uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; - uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; - - if (INTEL_INFO(dev)->gen >= 8 || IS_VALLEYVIEW(dev)) { - /* - * On BDW+, swizzling is not used. We leave the CPU memory - * controller in charge of optimizing memory accesses without - * the extra address manipulation GPU side. - * - * VLV and CHV don't have GPU swizzling. - */ - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else if (INTEL_INFO(dev)->gen >= 6) { - if (dev_priv->preserve_bios_swizzle) { - if (I915_READ(DISP_ARB_CTL) & - DISP_TILE_SURFACE_SWIZZLING) { - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } - } else { - uint32_t dimm_c0, dimm_c1; - dimm_c0 = I915_READ(MAD_DIMM_C0); - dimm_c1 = I915_READ(MAD_DIMM_C1); - dimm_c0 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; - dimm_c1 &= MAD_DIMM_A_SIZE_MASK | MAD_DIMM_B_SIZE_MASK; - /* Enable swizzling when the channels are populated - * with identically sized dimms. We don't need to check - * the 3rd channel because no cpu with gpu attached - * ships in that configuration. Also, swizzling only - * makes sense for 2 channels anyway. */ - if (dimm_c0 == dimm_c1) { - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } - } - } else if (IS_GEN5(dev)) { - /* On Ironlake whatever DRAM config, GPU always do - * same swizzling setup. - */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else if (IS_GEN2(dev)) { - /* As far as we know, the 865 doesn't have these bit 6 - * swizzling issues. - */ - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else if (IS_MOBILE(dev) || (IS_GEN3(dev) && !IS_G33(dev))) { - uint32_t dcc; - - /* On 9xx chipsets, channel interleave by the CPU is - * determined by DCC. For single-channel, neither the CPU - * nor the GPU do swizzling. For dual channel interleaved, - * the GPU's interleave is bit 9 and 10 for X tiled, and bit - * 9 for Y tiled. The CPU's interleave is independent, and - * can be based on either bit 11 (haven't seen this yet) or - * bit 17 (common). - */ - dcc = I915_READ(DCC); - switch (dcc & DCC_ADDRESSING_MODE_MASK) { - case DCC_ADDRESSING_MODE_SINGLE_CHANNEL: - case DCC_ADDRESSING_MODE_DUAL_CHANNEL_ASYMMETRIC: - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - break; - case DCC_ADDRESSING_MODE_DUAL_CHANNEL_INTERLEAVED: - if (dcc & DCC_CHANNEL_XOR_DISABLE) { - /* This is the base swizzling by the GPU for - * tiled buffers. - */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } else if ((dcc & DCC_CHANNEL_XOR_BIT_17) == 0) { - /* Bit 11 swizzling by the CPU in addition. */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10_11; - swizzle_y = I915_BIT_6_SWIZZLE_9_11; - } else { - /* Bit 17 swizzling by the CPU in addition. */ - swizzle_x = I915_BIT_6_SWIZZLE_9_10_17; - swizzle_y = I915_BIT_6_SWIZZLE_9_17; - } - break; - } - - /* check for L-shaped memory aka modified enhanced addressing */ - if (IS_GEN4(dev)) { - uint32_t ddc2 = I915_READ(DCC2); - - if (!(ddc2 & DCC2_MODIFIED_ENHANCED_DISABLE)) - dev_priv->quirks |= QUIRK_PIN_SWIZZLED_PAGES; - } - - if (dcc == 0xffffffff) { - DRM_ERROR("Couldn't read from MCHBAR. " - "Disabling tiling.\n"); - swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN; - swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN; - } - } else { - /* The 965, G33, and newer, have a very flexible memory - * configuration. It will enable dual-channel mode - * (interleaving) on as much memory as it can, and the GPU - * will additionally sometimes enable different bit 6 - * swizzling for tiled objects from the CPU. - * - * Here's what I found on the G965: - * slot fill memory size swizzling - * 0A 0B 1A 1B 1-ch 2-ch - * 512 0 0 0 512 0 O - * 512 0 512 0 16 1008 X - * 512 0 0 512 16 1008 X - * 0 512 0 512 16 1008 X - * 1024 1024 1024 0 2048 1024 O - * - * We could probably detect this based on either the DRB - * matching, which was the case for the swizzling required in - * the table above, or from the 1-ch value being less than - * the minimum size of a rank. - */ - if (I915_READ16(C0DRB3) != I915_READ16(C1DRB3)) { - swizzle_x = I915_BIT_6_SWIZZLE_NONE; - swizzle_y = I915_BIT_6_SWIZZLE_NONE; - } else { - swizzle_x = I915_BIT_6_SWIZZLE_9_10; - swizzle_y = I915_BIT_6_SWIZZLE_9; - } - } - - dev_priv->mm.bit_6_swizzle_x = swizzle_x; - dev_priv->mm.bit_6_swizzle_y = swizzle_y; -} - /* Check pitch constriants for all chips & tiling formats */ static bool i915_tiling_ok(struct drm_device *dev, int stride, int size, int tiling_mode) @@ -475,75 +328,3 @@ i915_gem_get_tiling(struct drm_device *dev, void *data, return 0; } - -/** - * Swap every 64 bytes of this page around, to account for it having a new - * bit 17 of its physical address and therefore being interpreted differently - * by the GPU. - */ -static void -i915_gem_swizzle_page(struct page *page) -{ - char temp[64]; - char *vaddr; - int i; - - vaddr = kmap(page); - - for (i = 0; i < PAGE_SIZE; i += 128) { - memcpy(temp, &vaddr[i], 64); - memcpy(&vaddr[i], &vaddr[i + 64], 64); - memcpy(&vaddr[i + 64], temp, 64); - } - - kunmap(page); -} - -void -i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) -{ - struct sg_page_iter sg_iter; - int i; - - if (obj->bit_17 == NULL) - return; - - i = 0; - for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { - struct page *page = sg_page_iter_page(&sg_iter); - char new_bit_17 = page_to_phys(page) >> 17; - if ((new_bit_17 & 0x1) != - (test_bit(i, obj->bit_17) != 0)) { - i915_gem_swizzle_page(page); - set_page_dirty(page); - } - i++; - } -} - -void -i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) -{ - struct sg_page_iter sg_iter; - int page_count = obj->base.size >> PAGE_SHIFT; - int i; - - if (obj->bit_17 == NULL) { - obj->bit_17 = kcalloc(BITS_TO_LONGS(page_count), - sizeof(long), GFP_KERNEL); - if (obj->bit_17 == NULL) { - DRM_ERROR("Failed to allocate memory for bit 17 " - "record\n"); - return; - } - } - - i = 0; - for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) { - if (page_to_phys(sg_page_iter_page(&sg_iter)) & (1 << 17)) - __set_bit(i, obj->bit_17); - else - __clear_bit(i, obj->bit_17); - i++; - } -} -- GitLab From 3271dca483a48759cdbdb5f16a13125ab91f6c05 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Fri, 24 Jul 2015 17:40:15 +0200 Subject: [PATCH 1736/7006] drm/i915: kerneldoc for tiling IOCTL and swizzle functions Chris rightfully suggested that documenting fences without documenting the BO tiling tracking doesn't make much sense, so fix that. The important bit to stress here (since it lead to some confusion) is the GEM doesn't really care about tiling. Except for a few select cases where the kernel needs to manage something that userspace can't take care of: Namely the limited number of fences and fixing up swizzling, although we still fail at the later. v2: Move the low-level tiling/swizzling functions and kerneldoc to i915_gem_fence.c and leave only the userspace interface here. Suggested by Chris. Cc: Chris Wilson Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- Documentation/DocBook/drm.tmpl | 16 ++++- drivers/gpu/drm/i915/i915_gem_fence.c | 28 ++++++++- drivers/gpu/drm/i915/i915_gem_tiling.c | 84 +++++++++++++------------- 3 files changed, 80 insertions(+), 48 deletions(-) diff --git a/Documentation/DocBook/drm.tmpl b/Documentation/DocBook/drm.tmpl index 20c39b7e21ee8..43042739ae63d 100644 --- a/Documentation/DocBook/drm.tmpl +++ b/Documentation/DocBook/drm.tmpl @@ -4198,9 +4198,21 @@ int num_ioctls; !Idrivers/gpu/drm/i915/i915_gem_gtt.c - Global GTT Fence Handling -!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling + GTT Fences and Swizzling !Idrivers/gpu/drm/i915/i915_gem_fence.c + + Global GTT Fence Handling +!Pdrivers/gpu/drm/i915/i915_gem_fence.c fence register handling + + + Hardware Tiling and Swizzling Details +!Pdrivers/gpu/drm/i915/i915_gem_fence.c tiling swizzling details + + + + Object Tiling IOCTLs +!Idrivers/gpu/drm/i915/i915_gem_tiling.c +!Pdrivers/gpu/drm/i915/i915_gem_tiling.c buffer object tiling Buffer Object Eviction diff --git a/drivers/gpu/drm/i915/i915_gem_fence.c b/drivers/gpu/drm/i915/i915_gem_fence.c index c643260a90c51..af1f8c461060f 100644 --- a/drivers/gpu/drm/i915/i915_gem_fence.c +++ b/drivers/gpu/drm/i915/i915_gem_fence.c @@ -497,8 +497,7 @@ void i915_gem_restore_fences(struct drm_device *dev) } /** - * - * Support for managing tiling state of buffer objects. + * DOC: tiling swizzling details * * The idea behind tiling is to increase cache hit rates by rearranging * pixel data so that a group of pixel accesses are in the same cacheline. @@ -546,6 +545,9 @@ void i915_gem_restore_fences(struct drm_device *dev) */ /** + * i915_gem_detect_bit_6_swizzle - detect bit 6 swizzling pattern + * @dev: DRM device + * * Detects bit 6 swizzling of address lookup between IGD access and CPU * access through main memory. */ @@ -692,7 +694,7 @@ i915_gem_detect_bit_6_swizzle(struct drm_device *dev) dev_priv->mm.bit_6_swizzle_y = swizzle_y; } -/** +/* * Swap every 64 bytes of this page around, to account for it having a new * bit 17 of its physical address and therefore being interpreted differently * by the GPU. @@ -715,6 +717,18 @@ i915_gem_swizzle_page(struct page *page) kunmap(page); } +/** + * i915_gem_object_do_bit_17_swizzle - fixup bit 17 swizzling + * @obj: i915 GEM buffer object + * + * This function fixes up the swizzling in case any page frame number for this + * object has changed in bit 17 since that state has been saved with + * i915_gem_object_save_bit_17_swizzle(). + * + * This is called when pinning backing storage again, since the kernel is free + * to move unpinned backing storage around (either by directly moving pages or + * by swapping them out and back in again). + */ void i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) { @@ -737,6 +751,14 @@ i915_gem_object_do_bit_17_swizzle(struct drm_i915_gem_object *obj) } } +/** + * i915_gem_object_save_bit_17_swizzle - save bit 17 swizzling + * @obj: i915 GEM buffer object + * + * This function saves the bit 17 of each page frame number so that swizzling + * can be fixed up later on with i915_gem_object_do_bit_17_swizzle(). This must + * be called before the backing storage can be unpinned. + */ void i915_gem_object_save_bit_17_swizzle(struct drm_i915_gem_object *obj) { diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c index fa7a8d7a24e01..ac3eb566c9d25 100644 --- a/drivers/gpu/drm/i915/i915_gem_tiling.c +++ b/drivers/gpu/drm/i915/i915_gem_tiling.c @@ -31,53 +31,31 @@ #include #include "i915_drv.h" -/** @file i915_gem_tiling.c - * - * Support for managing tiling state of buffer objects. - * - * The idea behind tiling is to increase cache hit rates by rearranging - * pixel data so that a group of pixel accesses are in the same cacheline. - * Performance improvement from doing this on the back/depth buffer are on - * the order of 30%. - * - * Intel architectures make this somewhat more complicated, though, by - * adjustments made to addressing of data when the memory is in interleaved - * mode (matched pairs of DIMMS) to improve memory bandwidth. - * For interleaved memory, the CPU sends every sequential 64 bytes - * to an alternate memory channel so it can get the bandwidth from both. - * - * The GPU also rearranges its accesses for increased bandwidth to interleaved - * memory, and it matches what the CPU does for non-tiled. However, when tiled - * it does it a little differently, since one walks addresses not just in the - * X direction but also Y. So, along with alternating channels when bit - * 6 of the address flips, it also alternates when other bits flip -- Bits 9 - * (every 512 bytes, an X tile scanline) and 10 (every two X tile scanlines) - * are common to both the 915 and 965-class hardware. - * - * The CPU also sometimes XORs in higher bits as well, to improve - * bandwidth doing strided access like we do so frequently in graphics. This - * is called "Channel XOR Randomization" in the MCH documentation. The result - * is that the CPU is XORing in either bit 11 or bit 17 to bit 6 of its address - * decode. +/** + * DOC: buffer object tiling * - * All of this bit 6 XORing has an effect on our memory management, - * as we need to make sure that the 3d driver can correctly address object - * contents. + * i915_gem_set_tiling() and i915_gem_get_tiling() is the userspace interface to + * declare fence register requirements. * - * If we don't have interleaved memory, all tiling is safe and no swizzling is - * required. + * In principle GEM doesn't care at all about the internal data layout of an + * object, and hence it also doesn't care about tiling or swizzling. There's two + * exceptions: * - * When bit 17 is XORed in, we simply refuse to tile at all. Bit - * 17 is not just a page offset, so as we page an objet out and back in, - * individual pages in it will have different bit 17 addresses, resulting in - * each 64 bytes being swapped with its neighbor! + * - For X and Y tiling the hardware provides detilers for CPU access, so called + * fences. Since there's only a limited amount of them the kernel must manage + * these, and therefore userspace must tell the kernel the object tiling if it + * wants to use fences for detiling. + * - On gen3 and gen4 platforms have a swizzling pattern for tiled objects which + * depends upon the physical page frame number. When swapping such objects the + * page frame number might change and the kernel must be able to fix this up + * and hence now the tiling. Note that on a subset of platforms with + * asymmetric memory channel population the swizzling pattern changes in an + * unknown way, and for those the kernel simply forbids swapping completely. * - * Otherwise, if interleaved, we have to tell the 3d driver what the address - * swizzling it needs to do is, since it's writing with the CPU to the pages - * (bit 6 and potentially bit 11 XORed in), and the GPU is reading from the - * pages (bit 6, 9, and 10 XORed in), resulting in a cumulative bit swizzling - * required by the CPU of XORing in bit 6, 9, 10, and potentially 11, in order - * to match what the GPU expects. + * Since neither of this applies for new tiling layouts on modern platforms like + * W, Ys and Yf tiling GEM only allows object tiling to be set to X or Y tiled. + * Anything else can be handled in userspace entirely without the kernel's + * invovlement. */ /* Check pitch constriants for all chips & tiling formats */ @@ -166,8 +144,18 @@ i915_gem_object_fence_ok(struct drm_i915_gem_object *obj, int tiling_mode) } /** + * i915_gem_set_tiling - IOCTL handler to set tiling mode + * @dev: DRM device + * @data: data pointer for the ioctl + * @file: DRM file for the ioctl call + * * Sets the tiling mode of an object, returning the required swizzling of * bit 6 of addresses in the object. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. */ int i915_gem_set_tiling(struct drm_device *dev, void *data, @@ -285,7 +273,17 @@ err: } /** + * i915_gem_get_tiling - IOCTL handler to get tiling mode + * @dev: DRM device + * @data: data pointer for the ioctl + * @file: DRM file for the ioctl call + * * Returns the current tiling mode and required bit 6 swizzling for the object. + * + * Called by the user via ioctl. + * + * Returns: + * Zero on success, negative errno on failure. */ int i915_gem_get_tiling(struct drm_device *dev, void *data, -- GitLab From cbc59e26e90dab17e233c6cdf51235d5d25f5fba Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Tue, 5 May 2015 13:55:09 +0300 Subject: [PATCH 1737/7006] pinctrl: dt-binding: document Conexant CX92755 SoC Add pinctrl device tree binding documentation for the General Purpose Pin Mapping module of the Conexant CX92755 SoC. Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- .../bindings/pinctrl/cnxt,cx92755-pinctrl.txt | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 Documentation/devicetree/bindings/pinctrl/cnxt,cx92755-pinctrl.txt diff --git a/Documentation/devicetree/bindings/pinctrl/cnxt,cx92755-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/cnxt,cx92755-pinctrl.txt new file mode 100644 index 0000000000000..23ce8dc26990b --- /dev/null +++ b/Documentation/devicetree/bindings/pinctrl/cnxt,cx92755-pinctrl.txt @@ -0,0 +1,86 @@ +Conexant Digicolor CX92755 General Purpose Pin Mapping + +This document describes the device tree binding of the pin mapping hardware +modules in the Conexant Digicolor CX92755 SoCs. The CX92755 in one of the +Digicolor series of SoCs. + +=== Pin Controller Node === + +Required Properties: + +- compatible: Must be "cnxt,cx92755-pinctrl" +- reg: Base address of the General Purpose Pin Mapping register block and the + size of the block. +- gpio-controller: Marks the device node as a GPIO controller. +- #gpio-cells: Must be <2>. The first cell is the pin number and the + second cell is used to specify flags. See include/dt-bindings/gpio/gpio.h + for possible values. + +For example, the following is the bare minimum node: + + pinctrl: pinctrl@f0000e20 { + compatible = "cnxt,cx92755-pinctrl"; + reg = <0xf0000e20 0x100>; + gpio-controller; + #gpio-cells = <2>; + }; + +As a pin controller device, in addition to the required properties, this node +should also contain the pin configuration nodes that client devices reference, +if any. + +For a general description of GPIO bindings, please refer to ../gpio/gpio.txt. + +=== Pin Configuration Node === + +Each pin configuration node is a sub-node of the pin controller node and is a +container of an arbitrary number of subnodes, called pin group nodes in this +document. + +Please refer to the pinctrl-bindings.txt in this directory for details of the +common pinctrl bindings used by client devices, including the definition of a +"pin configuration node". + +=== Pin Group Node === + +A pin group node specifies the desired pin mux for an arbitrary number of +pins. The name of the pin group node is optional and not used. + +A pin group node only affects the properties specified in the node, and has no +effect on any properties that are omitted. + +The pin group node accepts a subset of the generic pin config properties. For +details generic pin config properties, please refer to pinctrl-bindings.txt +and . + +Required Pin Group Node Properties: + +- pins: Multiple strings. Specifies the name(s) of one or more pins to be + configured by this node. The format of a pin name string is "GP_xy", where x + is an uppercase character from 'A' to 'R', and y is a digit from 0 to 7. +- function: String. Specifies the pin mux selection. Values must be one of: + "gpio", "client_a", "client_b", "client_c" + +Example: + pinctrl: pinctrl@f0000e20 { + compatible = "cnxt,cx92755-pinctrl"; + reg = <0xf0000e20 0x100>; + + uart0_default: uart0_active { + data_signals { + pins = "GP_O0", "GP_O1"; + function = "client_b"; + }; + }; + }; + + uart0: uart@f0000740 { + compatible = "cnxt,cx92755-usart"; + ... + pinctrl-0 = <&uart0_default>; + pinctrl-names = "default"; + }; + +In the example above, a single pin group configuration node defines the +"client select" for the Rx and Tx signals of uart0. The uart0 node references +that pin configuration node using the &uart0_default phandle. -- GitLab From 38b0e5071eca4db618e796a2f1dbad3b20c01358 Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Tue, 5 May 2015 13:55:10 +0300 Subject: [PATCH 1738/7006] pinctrl: driver for Conexant Digicolor CX92755 pin mapping This adds pinctrl and gpio driver to the CX92755 SoC "General Purpose Pin Mapping" hardware block. The CX92755 is one SoC from the Conexant Digicolor series. Pin mapping hardware supports configuring pins as either GPIO, or up to 3 other "client select" functions. This driver adds support for pin muxing using the generic device tree binding, and a basic gpiolib driver for the GPIO functionality. This driver does not currently support GPIO interrupts, and pad configuration. v2: * Address review comments for Linus Walleij: - Add a pointer to pinctrl_desc in struct dc_pinmap - Drop the now redundant pinctrl_pin_desc field - Adapt dc_get_group_{name,pins} to these changes, and add a comment explaining the 1-to-1 pin-groups relation * Staticise dc_pmxops * Protect the GP_CLIENTSEL clct parameter with parenthesis Signed-off-by: Baruch Siach Signed-off-by: Linus Walleij --- drivers/pinctrl/Kconfig | 6 + drivers/pinctrl/Makefile | 1 + drivers/pinctrl/pinctrl-digicolor.c | 378 ++++++++++++++++++++++++++++ 3 files changed, 385 insertions(+) create mode 100644 drivers/pinctrl/pinctrl-digicolor.c diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index e6362c61b5604..84dd2ed47a928 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -82,6 +82,12 @@ config PINCTRL_AMD Requires ACPI/FDT device enumeration code to set up a platform device. +config PINCTRL_DIGICOLOR + bool + depends on OF && (ARCH_DIGICOLOR || COMPILE_TEST) + select PINMUX + select GENERIC_PINCONF + config PINCTRL_LANTIQ bool depends on LANTIQ diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index 76ba976cb9cad..cad077c43fb73 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o obj-$(CONFIG_PINCTRL_AMD) += pinctrl-amd.o +obj-$(CONFIG_PINCTRL_DIGICOLOR) += pinctrl-digicolor.o obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o obj-$(CONFIG_PINCTRL_MESON) += meson/ obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o diff --git a/drivers/pinctrl/pinctrl-digicolor.c b/drivers/pinctrl/pinctrl-digicolor.c new file mode 100644 index 0000000000000..461fffc4c62ae --- /dev/null +++ b/drivers/pinctrl/pinctrl-digicolor.c @@ -0,0 +1,378 @@ +/* + * Driver for Conexant Digicolor General Purpose Pin Mapping + * + * Author: Baruch Siach + * + * Copyright (C) 2015 Paradox Innovation Ltd. + * + * 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. + * + * TODO: + * - GPIO interrupt support + * - Pin pad configuration (pull up/down, strength) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pinctrl-utils.h" + +#define DRIVER_NAME "pinctrl-digicolor" + +#define GP_CLIENTSEL(clct) ((clct)*8 + 0x20) +#define GP_DRIVE0(clct) (GP_CLIENTSEL(clct) + 2) +#define GP_OUTPUT0(clct) (GP_CLIENTSEL(clct) + 3) +#define GP_INPUT(clct) (GP_CLIENTSEL(clct) + 6) + +#define PIN_COLLECTIONS ('R' - 'A' + 1) +#define PINS_PER_COLLECTION 8 +#define PINS_COUNT (PIN_COLLECTIONS * PINS_PER_COLLECTION) + +struct dc_pinmap { + void __iomem *regs; + struct device *dev; + struct pinctrl_dev *pctl; + + struct pinctrl_desc *desc; + const char *pin_names[PINS_COUNT]; + + struct gpio_chip chip; + spinlock_t lock; +}; + +static int dc_get_groups_count(struct pinctrl_dev *pctldev) +{ + return PINS_COUNT; +} + +static const char *dc_get_group_name(struct pinctrl_dev *pctldev, + unsigned selector) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + + /* Exactly one group per pin */ + return pmap->desc->pins[selector].name; +} + +static int dc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector, + const unsigned **pins, + unsigned *num_pins) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + + *pins = &pmap->desc->pins[selector].number; + *num_pins = 1; + + return 0; +} + +static struct pinctrl_ops dc_pinctrl_ops = { + .get_groups_count = dc_get_groups_count, + .get_group_name = dc_get_group_name, + .get_group_pins = dc_get_group_pins, + .dt_node_to_map = pinconf_generic_dt_node_to_map_pin, + .dt_free_map = pinctrl_utils_dt_free_map, +}; + +static const char *const dc_functions[] = { + "gpio", + "client_a", + "client_b", + "client_c", +}; + +static int dc_get_functions_count(struct pinctrl_dev *pctldev) +{ + return ARRAY_SIZE(dc_functions); +} + +static const char *dc_get_fname(struct pinctrl_dev *pctldev, unsigned selector) +{ + return dc_functions[selector]; +} + +static int dc_get_groups(struct pinctrl_dev *pctldev, unsigned selector, + const char * const **groups, + unsigned * const num_groups) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + + *groups = pmap->pin_names; + *num_groups = PINS_COUNT; + + return 0; +} + +static void dc_client_sel(int pin_num, int *reg, int *bit) +{ + *bit = (pin_num % PINS_PER_COLLECTION) * 2; + *reg = GP_CLIENTSEL(pin_num/PINS_PER_COLLECTION); + + if (*bit >= PINS_PER_COLLECTION) { + *bit -= PINS_PER_COLLECTION; + *reg += 1; + } +} + +static int dc_set_mux(struct pinctrl_dev *pctldev, unsigned selector, + unsigned group) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev); + int bit_off, reg_off; + u8 reg; + + dc_client_sel(group, ®_off, &bit_off); + + reg = readb_relaxed(pmap->regs + reg_off); + reg &= ~(3 << bit_off); + reg |= (selector << bit_off); + writeb_relaxed(reg, pmap->regs + reg_off); + + return 0; +} + +static int dc_pmx_request_gpio(struct pinctrl_dev *pcdev, + struct pinctrl_gpio_range *range, + unsigned offset) +{ + struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pcdev); + int bit_off, reg_off; + u8 reg; + + dc_client_sel(offset, ®_off, &bit_off); + + reg = readb_relaxed(pmap->regs + reg_off); + if ((reg & (3 << bit_off)) != 0) + return -EBUSY; + + return 0; +} + +static struct pinmux_ops dc_pmxops = { + .get_functions_count = dc_get_functions_count, + .get_function_name = dc_get_fname, + .get_function_groups = dc_get_groups, + .set_mux = dc_set_mux, + .gpio_request_enable = dc_pmx_request_gpio, +}; + +static int dc_gpio_request(struct gpio_chip *chip, unsigned gpio) +{ + return pinctrl_request_gpio(chip->base + gpio); +} + +static void dc_gpio_free(struct gpio_chip *chip, unsigned gpio) +{ + pinctrl_free_gpio(chip->base + gpio); +} + +static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 drive; + unsigned long flags; + + spin_lock_irqsave(&pmap->lock, flags); + drive = readb_relaxed(pmap->regs + reg_off); + drive &= ~BIT(bit_off); + writeb_relaxed(drive, pmap->regs + reg_off); + spin_unlock_irqrestore(&pmap->lock, flags); + + return 0; +} + +static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value); + +static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, + int value) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 drive; + unsigned long flags; + + dc_gpio_set(chip, gpio, value); + + spin_lock_irqsave(&pmap->lock, flags); + drive = readb_relaxed(pmap->regs + reg_off); + drive |= BIT(bit_off); + writeb_relaxed(drive, pmap->regs + reg_off); + spin_unlock_irqrestore(&pmap->lock, flags); + + return 0; +} + +static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_INPUT(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 input; + + input = readb_relaxed(pmap->regs + reg_off); + + return !!(input & BIT(bit_off)); +} + +static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value) +{ + struct dc_pinmap *pmap = container_of(chip, struct dc_pinmap, chip); + int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION); + int bit_off = gpio % PINS_PER_COLLECTION; + u8 output; + unsigned long flags; + + spin_lock_irqsave(&pmap->lock, flags); + output = readb_relaxed(pmap->regs + reg_off); + if (value) + output |= BIT(bit_off); + else + output &= ~BIT(bit_off); + writeb_relaxed(output, pmap->regs + reg_off); + spin_unlock_irqrestore(&pmap->lock, flags); +} + +static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np) +{ + struct gpio_chip *chip = &pmap->chip; + int ret; + + chip->label = DRIVER_NAME; + chip->dev = pmap->dev; + chip->request = dc_gpio_request; + chip->free = dc_gpio_free; + chip->direction_input = dc_gpio_direction_input; + chip->direction_output = dc_gpio_direction_output; + chip->get = dc_gpio_get; + chip->set = dc_gpio_set; + chip->base = -1; + chip->ngpio = PINS_COUNT; + chip->of_node = np; + chip->of_gpio_n_cells = 2; + + spin_lock_init(&pmap->lock); + + ret = gpiochip_add(chip); + if (ret < 0) + return ret; + + ret = gpiochip_add_pin_range(chip, dev_name(pmap->dev), 0, 0, + PINS_COUNT); + if (ret < 0) { + gpiochip_remove(chip); + return ret; + } + + return 0; +} + +static int dc_pinctrl_probe(struct platform_device *pdev) +{ + struct dc_pinmap *pmap; + struct resource *r; + struct pinctrl_pin_desc *pins; + struct pinctrl_desc *pctl_desc; + char *pin_names; + int name_len = strlen("GP_xx") + 1; + int i, j, ret; + + pmap = devm_kzalloc(&pdev->dev, sizeof(*pmap), GFP_KERNEL); + if (!pmap) + return -ENOMEM; + + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pmap->regs = devm_ioremap_resource(&pdev->dev, r); + if (IS_ERR(pmap->regs)) + return PTR_ERR(pmap->regs); + + pins = devm_kzalloc(&pdev->dev, sizeof(*pins)*PINS_COUNT, GFP_KERNEL); + if (!pins) + return -ENOMEM; + pin_names = devm_kzalloc(&pdev->dev, name_len * PINS_COUNT, + GFP_KERNEL); + if (!pin_names) + return -ENOMEM; + + for (i = 0; i < PIN_COLLECTIONS; i++) { + for (j = 0; j < PINS_PER_COLLECTION; j++) { + int pin_id = i*PINS_PER_COLLECTION + j; + char *name = &pin_names[pin_id * name_len]; + + snprintf(name, name_len, "GP_%c%c", 'A'+i, '0'+j); + + pins[pin_id].number = pin_id; + pins[pin_id].name = name; + pmap->pin_names[pin_id] = name; + } + } + + pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL); + if (!pctl_desc) + return -ENOMEM; + + pctl_desc->name = DRIVER_NAME, + pctl_desc->owner = THIS_MODULE, + pctl_desc->pctlops = &dc_pinctrl_ops, + pctl_desc->pmxops = &dc_pmxops, + pctl_desc->npins = PINS_COUNT; + pctl_desc->pins = pins; + pmap->desc = pctl_desc; + + pmap->dev = &pdev->dev; + + pmap->pctl = pinctrl_register(pctl_desc, &pdev->dev, pmap); + if (!pmap->pctl) { + dev_err(&pdev->dev, "pinctrl driver registration failed\n"); + return -EINVAL; + } + + ret = dc_gpiochip_add(pmap, pdev->dev.of_node); + if (ret < 0) { + pinctrl_unregister(pmap->pctl); + return ret; + } + + return 0; +} + +static int dc_pinctrl_remove(struct platform_device *pdev) +{ + struct dc_pinmap *pmap = platform_get_drvdata(pdev); + + pinctrl_unregister(pmap->pctl); + gpiochip_remove(&pmap->chip); + + return 0; +} + +static const struct of_device_id dc_pinctrl_ids[] = { + { .compatible = "cnxt,cx92755-pinctrl" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, dc_pinctrl_ids); + +static struct platform_driver dc_pinctrl_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = dc_pinctrl_ids, + }, + .probe = dc_pinctrl_probe, + .remove = dc_pinctrl_remove, +}; +module_platform_driver(dc_pinctrl_driver); -- GitLab From 5a063d87e97df28ca0b00807bc4d6fa11c5a5107 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Jul 2015 09:56:05 +0200 Subject: [PATCH 1739/7006] pwm: sysfs: Properly convert from enum to string The current code will check for polarity in a boolean way. While it is correct that polarity is either normal or inversed, make it more obvious that it's an enumeration by using a switch statement and explicit matches on the enumeration values. Signed-off-by: Thierry Reding --- drivers/pwm/sysfs.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index ac0abecfbaa01..fbfc9e903230c 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -133,9 +133,19 @@ static ssize_t pwm_polarity_show(struct device *child, char *buf) { const struct pwm_device *pwm = child_to_pwm_device(child); + const char *polarity = "unknown"; - return sprintf(buf, "%s\n", - pwm_get_polarity(pwm) ? "inversed" : "normal"); + switch (pwm_get_polarity(pwm)) { + case PWM_POLARITY_NORMAL: + polarity = "normal"; + break; + + case PWM_POLARITY_INVERSED: + polarity = "inversed"; + break; + } + + return sprintf(buf, "%s\n", polarity); } static ssize_t pwm_polarity_store(struct device *child, -- GitLab From 412820dd536fe2d01a35f0d68982ea225ec255b3 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 20 Jul 2015 09:58:09 +0200 Subject: [PATCH 1740/7006] pwm: sysfs: Remove unnecessary padding Padding initializers so that assignment operators align is bound to lead to inconsistencies or churn. Single spaces around the assignment is just fine. Signed-off-by: Thierry Reding --- drivers/pwm/sysfs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/pwm/sysfs.c b/drivers/pwm/sysfs.c index fbfc9e903230c..c472772f00a78 100644 --- a/drivers/pwm/sysfs.c +++ b/drivers/pwm/sysfs.c @@ -312,9 +312,9 @@ static struct attribute *pwm_chip_attrs[] = { ATTRIBUTE_GROUPS(pwm_chip); static struct class pwm_class = { - .name = "pwm", - .owner = THIS_MODULE, - .dev_groups = pwm_chip_groups, + .name = "pwm", + .owner = THIS_MODULE, + .dev_groups = pwm_chip_groups, }; static int pwmchip_sysfs_match(struct device *parent, const void *data) -- GitLab From 2d23ed04de933625bc777cc474d2cd9a2a3fa860 Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Fri, 12 Jun 2015 15:39:28 +0100 Subject: [PATCH 1741/7006] arm64: perf: Remove unnecessary printk ARM64 pmu prints an error message in event_init() when no hardware PMU is available. This is pretty annoying as it keeps printing the message for every single trial, flooding the kernel logs, unnecessarily. The return code is sufficient for the user to figure out the reason. Signed-off-by: Suzuki K. Poulose Signed-off-by: Will Deacon --- arch/arm64/kernel/perf_event.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index b31e9a4b62754..2cd580a1fa805 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -435,10 +435,8 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) unsigned int i, irqs; struct platform_device *pmu_device = armpmu->plat_device; - if (!pmu_device) { - pr_err("no PMU device registered\n"); + if (!pmu_device) return -ENODEV; - } irqs = min(pmu_device->num_resources, num_possible_cpus()); if (!irqs) { -- GitLab From d09ce834dfffd93aa4586b3e07faaf901ee8706f Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 30 Jun 2015 13:56:56 +0100 Subject: [PATCH 1742/7006] arm64: perf: replace arch_find_n_match_cpu_physical_id with of_cpu_device_node_get arch_find_n_match_cpu_physical_id parses the device tree to get the device node for a given logical cpu index. However, since ARM PMUs get probed after the CPU device nodes are stashed while registering the cpus, we can use of_cpu_device_node_get to avoid another DT parse. This patch replaces arch_find_n_match_cpu_physical_id with of_cpu_device_node_get to reuse the stashed value directly instead. Cc: Will Deacon Cc: Mark Rutland Signed-off-by: Sudeep Holla Signed-off-by: Will Deacon --- arch/arm64/kernel/perf_event.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 2cd580a1fa805..563f8ce8df68d 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -1335,7 +1335,7 @@ static int armpmu_device_probe(struct platform_device *pdev) } for_each_possible_cpu(cpu) - if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL)) + if (dn == of_cpu_device_node_get(cpu)) break; if (cpu >= nr_cpu_ids) { -- GitLab From e147ae6d7f908412a013c115e42c3e15dac33ccc Mon Sep 17 00:00:00 2001 From: Rohit Thapliyal Date: Fri, 10 Jul 2015 09:23:59 +0100 Subject: [PATCH 1743/7006] arm64: modify the dump mem for 64 bit addresses On 64bit kernel, the dump_mem gives 32 bit addresses on the stack dump. This gives unorganized information regarding the 64bit values on the stack. Hence, modified to get a complete 64bit memory dump. With patch: [ 93.534801] Process insmod (pid: 1587, stack limit = 0xffffffc976be4058) [ 93.541441] Stack: (0xffffffc976be7cf0 to 0xffffffc976be8000) [ 93.547136] 7ce0: ffffffc976be7d00 ffffffc00008163c [ 93.554898] 7d00: ffffffc976be7d40 ffffffc0000f8a44 ffffffc00098ef38 ffffffbffc000088 [ 93.562659] 7d20: ffffffc00098ef50 ffffffbffc0000c0 0000000000000001 ffffffbffc000070 [ 93.570419] 7d40: ffffffc976be7e40 ffffffc0000f935c 0000000000000000 000000002b424090 [ 93.578179] 7d60: 000000002b424010 0000007facc555f4 0000000080000000 0000000000000015 [ 93.585937] 7d80: 0000000000000116 0000000000000069 ffffffc00097b000 ffffffc976be4000 [ 93.593694] 7da0: 0000000000000064 0000000000000072 000000000000006e 000000000000003f [ 93.601453] 7dc0: 000000000000feff 000000000000fff1 ffffffbffc002028 0000000000000124 [ 93.609211] 7de0: ffffffc976be7e10 0000000000000001 ffffff8000000000 ffffffbbffff0000 [ 93.616969] 7e00: ffffffc976be7e60 0000000000000000 0000000000000000 0000000000000000 [ 93.624726] 7e20: 0000000000000000 0000000000000000 0000000000000000 0000000000000000 [ 93.632484] 7e40: 0000007fcc474550 ffffffc0000841ec 000000002b424010 0000007facda0710 [ 93.640241] 7e60: ffffffffffffffff ffffffc0000be6dc ffffff80007d2000 000000000001c010 [ 93.647999] 7e80: ffffff80007e0ae0 ffffff80007e09d0 ffffff80007edf70 0000000000000288 [ 93.655757] 7ea0: 00000000000002e8 0000000000000000 0000000000000000 0000001c0000001b [ 93.663514] 7ec0: 0000000000000009 0000000000000007 000000002b424090 000000000001c010 [ 93.671272] 7ee0: 000000002b424010 0000007faccd3a48 0000000000000000 0000000000000000 [ 93.679030] 7f00: 0000007fcc4743f8 0000007fcc4743f8 0000000000000069 0000000000000003 [ 93.686787] 7f20: 0101010101010101 0000000000000004 0000000000000020 00000000000003f3 [ 93.694544] 7f40: 0000007facb95664 0000007facda7030 0000007facc555d0 0000000000498378 [ 93.702301] 7f60: 0000000000000000 000000002b424010 0000007facda0710 000000002b424090 [ 93.710058] 7f80: 0000007fcc474698 0000000000498000 0000007fcc474ebb 0000000000474f58 [ 93.717815] 7fa0: 0000000000498000 0000000000000000 0000000000000000 0000007fcc474550 [ 93.725573] 7fc0: 00000000004104bc 0000007fcc474430 0000007facc555f4 0000000080000000 [ 93.733330] 7fe0: 000000002b424090 0000000000000069 0950020128000244 4104000008000004 [ 93.741084] Call trace: The above output makes a debugger life a lot more easier. Signed-off-by: Rohit Thapliyal Signed-off-by: Maninder Singh Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/kernel/traps.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 566bc4c350405..4db6a2574fec8 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -52,11 +52,12 @@ int show_unhandled_signals = 1; * Dump out the contents of some memory nicely... */ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, - unsigned long top) + unsigned long top, bool compat) { unsigned long first; mm_segment_t fs; int i; + unsigned int width = compat ? 4 : 8; /* * We need to switch to kernel mode so that we can use __get_user @@ -75,13 +76,22 @@ static void dump_mem(const char *lvl, const char *str, unsigned long bottom, memset(str, ' ', sizeof(str)); str[sizeof(str) - 1] = '\0'; - for (p = first, i = 0; i < 8 && p < top; i++, p += 4) { + for (p = first, i = 0; i < (32 / width) + && p < top; i++, p += width) { if (p >= bottom && p < top) { - unsigned int val; - if (__get_user(val, (unsigned int *)p) == 0) - sprintf(str + i * 9, " %08x", val); - else - sprintf(str + i * 9, " ????????"); + unsigned long val; + + if (width == 8) { + if (__get_user(val, (unsigned long *)p) == 0) + sprintf(str + i * 17, " %016lx", val); + else + sprintf(str + i * 17, " ????????????????"); + } else { + if (__get_user(val, (unsigned int *)p) == 0) + sprintf(str + i * 9, " %08lx", val); + else + sprintf(str + i * 9, " ????????"); + } } } printk("%s%04lx:%s\n", lvl, first & 0xffff, str); @@ -95,7 +105,7 @@ static void dump_backtrace_entry(unsigned long where, unsigned long stack) print_ip_sym(where); if (in_exception_text(where)) dump_mem("", "Exception stack", stack, - stack + sizeof(struct pt_regs)); + stack + sizeof(struct pt_regs), false); } static void dump_instr(const char *lvl, struct pt_regs *regs) @@ -207,7 +217,8 @@ static int __die(const char *str, int err, struct thread_info *thread, if (!user_mode(regs) || in_interrupt()) { dump_mem(KERN_EMERG, "Stack: ", regs->sp, - THREAD_SIZE + (unsigned long)task_stack_page(tsk)); + THREAD_SIZE + (unsigned long)task_stack_page(tsk), + compat_user_mode(regs)); dump_backtrace(regs, tsk); dump_instr(KERN_EMERG, regs); } -- GitLab From d3127afa712321a2b297cfee358be2cb223f933c Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Fri, 10 Jul 2015 14:58:00 +0100 Subject: [PATCH 1744/7006] arm64: Remove unused macros from assembler.h Commit 68234df4ea79 ("arm64: kill flush_cache_all()") removed the only users of these macros. Signed-off-by: Daniel Thompson Cc: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/include/asm/assembler.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index 144b64ad96c33..e10516bbe8339 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -49,18 +49,6 @@ msr daifclr, #2 .endm -/* - * Save/disable and restore interrupts. - */ - .macro save_and_disable_irqs, olddaif - mrs \olddaif, daif - disable_irq - .endm - - .macro restore_irqs, olddaif - msr daif, \olddaif - .endm - /* * Enable and disable debug exceptions. */ -- GitLab From aaf6f2f098f8ec22fa51ec15bd327b8acdfe5a78 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 10 Jul 2015 16:47:56 +0100 Subject: [PATCH 1745/7006] arm64: consolidate __swiotlb_mmap Since commit 9d3bfbb4df58 ("arm64: Combine coherent and non-coherent swiotlb dma_ops"), __dma_common_mmap is no longer shared between two callers, so roll it into the remaining one. Signed-off-by: Robin Murphy Signed-off-by: Will Deacon --- arch/arm64/mm/dma-mapping.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index d16a1cead23f1..63b2a117a03ca 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -303,9 +303,10 @@ static void __swiotlb_sync_sg_for_device(struct device *dev, sg->length, dir); } -/* vma->vm_page_prot must be set appropriately before calling this function */ -static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) +static int __swiotlb_mmap(struct device *dev, + struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) { int ret = -ENXIO; unsigned long nr_vma_pages = (vma->vm_end - vma->vm_start) >> @@ -314,6 +315,9 @@ static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma, unsigned long pfn = dma_to_phys(dev, dma_addr) >> PAGE_SHIFT; unsigned long off = vma->vm_pgoff; + vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, + is_device_dma_coherent(dev)); + if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) return ret; @@ -327,16 +331,6 @@ static int __dma_common_mmap(struct device *dev, struct vm_area_struct *vma, return ret; } -static int __swiotlb_mmap(struct device *dev, - struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size, - struct dma_attrs *attrs) -{ - vma->vm_page_prot = __get_dma_pgprot(attrs, vma->vm_page_prot, - is_device_dma_coherent(dev)); - return __dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); -} - static struct dma_map_ops swiotlb_dma_ops = { .alloc = __dma_alloc, .free = __dma_free, -- GitLab From cba3574fd56be8132a19e4aa6b1d41a12c56d990 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 16 Jul 2015 19:26:02 +0100 Subject: [PATCH 1746/7006] arm64: move update_mmu_cache() into asm/pgtable.h Mark Brown reported an allnoconfig build failure in -next: Today's linux-next fails to build an arm64 allnoconfig due to "mm: make GUP handle pfn mapping unless FOLL_GET is requested" which causes: > arm64-allnoconfig > ../mm/gup.c:51:4: error: implicit declaration of function 'update_mmu_cache' [-Werror=implicit-function-declaration] Fix the error by moving the function to asm/pgtable.h, as is the case for most other architectures. Reported-by: Mark Brown Signed-off-by: Will Deacon --- arch/arm64/include/asm/pgtable.h | 15 +++++++++++++++ arch/arm64/include/asm/tlbflush.h | 14 -------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 56283f8a675c5..4d5c812847e9f 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -505,6 +505,21 @@ extern int kern_addr_valid(unsigned long addr); #define pgtable_cache_init() do { } while (0) +/* + * On AArch64, the cache coherency is handled via the set_pte_at() function. + */ +static inline void update_mmu_cache(struct vm_area_struct *vma, + unsigned long addr, pte_t *ptep) +{ + /* + * set_pte() does not have a DSB for user mappings, so make sure that + * the page table write is visible. + */ + dsb(ishst); +} + +#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) + #endif /* !__ASSEMBLY__ */ #endif /* __ASM_PGTABLE_H */ diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index 934815d45eda0..7fedfa787a642 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -154,20 +154,6 @@ static inline void __flush_tlb_pgtable(struct mm_struct *mm, asm("tlbi vae1is, %0" : : "r" (addr)); dsb(ish); } -/* - * On AArch64, the cache coherency is handled via the set_pte_at() function. - */ -static inline void update_mmu_cache(struct vm_area_struct *vma, - unsigned long addr, pte_t *ptep) -{ - /* - * set_pte() does not have a DSB for user mappings, so make sure that - * the page table write is visible. - */ - dsb(ishst); -} - -#define update_mmu_cache_pmd(vma, address, pmd) do { } while (0) #endif -- GitLab From b08d4640a3dca68670fc5af2fe9205b395a02388 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Thu, 16 Jul 2015 18:58:53 +0100 Subject: [PATCH 1747/7006] arm64: remove dead code Commit 68234df4ea79 ("arm64: kill flush_cache_all()") removed soft_reset() from the kernel. This was the only caller of setup_mm_for_reboot(), so remove that also. Signed-off-by: Mark Salter Signed-off-by: Will Deacon --- arch/arm64/include/asm/mmu.h | 1 - arch/arm64/mm/mmu.c | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h index 79fcfb0488844..030208767185b 100644 --- a/arch/arm64/include/asm/mmu.h +++ b/arch/arm64/include/asm/mmu.h @@ -28,7 +28,6 @@ typedef struct { #define ASID(mm) ((mm)->context.id & 0xffff) extern void paging_init(void); -extern void setup_mm_for_reboot(void); extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt); extern void init_mem_pgprot(void); extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys, diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index a4ede4e2ddd1e..63012fed46fc0 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -460,17 +460,6 @@ void __init paging_init(void) cpu_set_default_tcr_t0sz(); } -/* - * Enable the identity mapping to allow the MMU disabling. - */ -void setup_mm_for_reboot(void) -{ - cpu_set_reserved_ttbr0(); - flush_tlb_all(); - cpu_set_idmap_tcr_t0sz(); - cpu_switch_mm(idmap_pg_dir, &init_mm); -} - /* * Check whether a kernel address is valid (derived from arch/x86/). */ -- GitLab From 2f4b829c625ec36c2d80bef6395c7b74cea8aac0 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Fri, 10 Jul 2015 17:24:28 +0100 Subject: [PATCH 1748/7006] arm64: Add support for hardware updates of the access and dirty pte bits The ARMv8.1 architecture extensions introduce support for hardware updates of the access and dirty information in page table entries. With TCR_EL1.HA enabled, when the CPU accesses an address with the PTE_AF bit cleared in the page table, instead of raising an access flag fault the CPU sets the actual page table entry bit. To ensure that kernel modifications to the page tables do not inadvertently revert a change introduced by hardware updates, the exclusive monitor (ldxr/stxr) is adopted in the pte accessors. When TCR_EL1.HD is enabled, a write access to a memory location with the DBM (Dirty Bit Management) bit set in the corresponding pte automatically clears the read-only bit (AP[2]). Such DBM bit maps onto the Linux PTE_WRITE bit and to check whether a writable (DBM set) page is dirty, the kernel tests the PTE_RDONLY bit. In order to allow read-only and dirty pages, the kernel needs to preserve the software dirty bit. The hardware dirty status is transferred to the software dirty bit in ptep_set_wrprotect() (using load/store exclusive loop) and pte_modify(). Signed-off-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 17 +++ arch/arm64/include/asm/pgtable-hwdef.h | 3 + arch/arm64/include/asm/pgtable.h | 147 ++++++++++++++++++++++++- arch/arm64/mm/proc.S | 13 +++ 4 files changed, 178 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 318175f62c24d..40f717f8820a6 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -469,6 +469,23 @@ config ARM64_VA_BITS default 42 if ARM64_VA_BITS_42 default 48 if ARM64_VA_BITS_48 +config ARM64_HW_AFDBM + bool "Support for hardware updates of the Access and Dirty page flags" + default y + help + The ARMv8.1 architecture extensions introduce support for + hardware updates of the access and dirty information in page + table entries. When enabled in TCR_EL1 (HA and HD bits) on + capable processors, accesses to pages with PTE_AF cleared will + set this bit instead of raising an access flag fault. + Similarly, writes to read-only pages with the DBM bit set will + clear the read-only bit (AP[2]) instead of raising a + permission fault. + + Kernels built with this configuration option enabled continue + to work on pre-ARMv8.1 hardware and the performance impact is + minimal. If unsure, say Y. + config CPU_BIG_ENDIAN bool "Build big-endian kernel" help diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h index 59bfae75dc980..24154b055835b 100644 --- a/arch/arm64/include/asm/pgtable-hwdef.h +++ b/arch/arm64/include/asm/pgtable-hwdef.h @@ -104,6 +104,7 @@ #define PTE_SHARED (_AT(pteval_t, 3) << 8) /* SH[1:0], inner shareable */ #define PTE_AF (_AT(pteval_t, 1) << 10) /* Access Flag */ #define PTE_NG (_AT(pteval_t, 1) << 11) /* nG */ +#define PTE_DBM (_AT(pteval_t, 1) << 51) /* Dirty Bit Management */ #define PTE_PXN (_AT(pteval_t, 1) << 53) /* Privileged XN */ #define PTE_UXN (_AT(pteval_t, 1) << 54) /* User XN */ @@ -168,5 +169,7 @@ #define TCR_TG1_64K (UL(3) << 30) #define TCR_ASID16 (UL(1) << 36) #define TCR_TBI0 (UL(1) << 37) +#define TCR_HA (UL(1) << 39) +#define TCR_HD (UL(1) << 40) #endif diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 4d5c812847e9f..8212e6aa0fb11 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -16,6 +16,7 @@ #ifndef __ASM_PGTABLE_H #define __ASM_PGTABLE_H +#include #include #include @@ -27,7 +28,11 @@ #define PTE_VALID (_AT(pteval_t, 1) << 0) #define PTE_DIRTY (_AT(pteval_t, 1) << 55) #define PTE_SPECIAL (_AT(pteval_t, 1) << 56) +#ifdef CONFIG_ARM64_HW_AFDBM +#define PTE_WRITE (PTE_DBM) /* same as DBM */ +#else #define PTE_WRITE (_AT(pteval_t, 1) << 57) +#endif #define PTE_PROT_NONE (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */ /* @@ -48,6 +53,9 @@ #define FIRST_USER_ADDRESS 0UL #ifndef __ASSEMBLY__ + +#include + extern void __pte_error(const char *file, int line, unsigned long val); extern void __pmd_error(const char *file, int line, unsigned long val); extern void __pud_error(const char *file, int line, unsigned long val); @@ -137,12 +145,20 @@ extern struct page *empty_zero_page; * The following only work if pte_present(). Undefined behaviour otherwise. */ #define pte_present(pte) (!!(pte_val(pte) & (PTE_VALID | PTE_PROT_NONE))) -#define pte_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY)) #define pte_young(pte) (!!(pte_val(pte) & PTE_AF)) #define pte_special(pte) (!!(pte_val(pte) & PTE_SPECIAL)) #define pte_write(pte) (!!(pte_val(pte) & PTE_WRITE)) #define pte_exec(pte) (!(pte_val(pte) & PTE_UXN)) +#ifdef CONFIG_ARM64_HW_AFDBM +#define pte_hw_dirty(pte) (!(pte_val(pte) & PTE_RDONLY)) +#else +#define pte_hw_dirty(pte) (0) +#endif +#define pte_sw_dirty(pte) (!!(pte_val(pte) & PTE_DIRTY)) +#define pte_dirty(pte) (pte_sw_dirty(pte) || pte_hw_dirty(pte)) + +#define pte_valid(pte) (!!(pte_val(pte) && PTE_VALID)) #define pte_valid_user(pte) \ ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER)) #define pte_valid_not_user(pte) \ @@ -209,20 +225,49 @@ static inline void set_pte(pte_t *ptep, pte_t pte) } } +struct mm_struct; +struct vm_area_struct; + extern void __sync_icache_dcache(pte_t pteval, unsigned long addr); +/* + * PTE bits configuration in the presence of hardware Dirty Bit Management + * (PTE_WRITE == PTE_DBM): + * + * Dirty Writable | PTE_RDONLY PTE_WRITE PTE_DIRTY (sw) + * 0 0 | 1 0 0 + * 0 1 | 1 1 0 + * 1 0 | 1 0 1 + * 1 1 | 0 1 x + * + * When hardware DBM is not present, the sofware PTE_DIRTY bit is updated via + * the page fault mechanism. Checking the dirty status of a pte becomes: + * + * PTE_DIRTY || !PTE_RDONLY + */ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pte) { if (pte_valid_user(pte)) { if (!pte_special(pte) && pte_exec(pte)) __sync_icache_dcache(pte, addr); - if (pte_dirty(pte) && pte_write(pte)) + if (pte_sw_dirty(pte) && pte_write(pte)) pte_val(pte) &= ~PTE_RDONLY; else pte_val(pte) |= PTE_RDONLY; } + /* + * If the existing pte is valid, check for potential race with + * hardware updates of the pte (ptep_set_access_flags safely changes + * valid ptes without going through an invalid entry). + */ + if (IS_ENABLED(CONFIG_DEBUG_VM) && IS_ENABLED(CONFIG_ARM64_HW_AFDBM) && + pte_valid(*ptep)) { + BUG_ON(!pte_young(pte)); + BUG_ON(pte_write(*ptep) && !pte_dirty(pte)); + } + set_pte(ptep, pte); } @@ -461,6 +506,9 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) { const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY | PTE_PROT_NONE | PTE_WRITE | PTE_TYPE_MASK; + /* preserve the hardware dirty information */ + if (pte_hw_dirty(pte)) + newprot |= PTE_DIRTY; pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask); return pte; } @@ -470,6 +518,101 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot) return pte_pmd(pte_modify(pmd_pte(pmd), newprot)); } +#ifdef CONFIG_ARM64_HW_AFDBM +/* + * Atomic pte/pmd modifications. + */ +#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG +static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, + pte_t *ptep) +{ + pteval_t pteval; + unsigned int tmp, res; + + asm volatile("// ptep_test_and_clear_young\n" + " prfm pstl1strm, %2\n" + "1: ldxr %0, %2\n" + " ubfx %w3, %w0, %5, #1 // extract PTE_AF (young)\n" + " and %0, %0, %4 // clear PTE_AF\n" + " stxr %w1, %0, %2\n" + " cbnz %w1, 1b\n" + : "=&r" (pteval), "=&r" (tmp), "+Q" (pte_val(*ptep)), "=&r" (res) + : "L" (~PTE_AF), "I" (ilog2(PTE_AF))); + + return res; +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG +static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, + unsigned long address, + pmd_t *pmdp) +{ + return ptep_test_and_clear_young(vma, address, (pte_t *)pmdp); +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +#define __HAVE_ARCH_PTEP_GET_AND_CLEAR +static inline pte_t ptep_get_and_clear(struct mm_struct *mm, + unsigned long address, pte_t *ptep) +{ + pteval_t old_pteval; + unsigned int tmp; + + asm volatile("// ptep_get_and_clear\n" + " prfm pstl1strm, %2\n" + "1: ldxr %0, %2\n" + " stxr %w1, xzr, %2\n" + " cbnz %w1, 1b\n" + : "=&r" (old_pteval), "=&r" (tmp), "+Q" (pte_val(*ptep))); + + return __pte(old_pteval); +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define __HAVE_ARCH_PMDP_GET_AND_CLEAR +static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm, + unsigned long address, pmd_t *pmdp) +{ + return pte_pmd(ptep_get_and_clear(mm, address, (pte_t *)pmdp)); +} +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ + +/* + * ptep_set_wrprotect - mark read-only while trasferring potential hardware + * dirty status (PTE_DBM && !PTE_RDONLY) to the software PTE_DIRTY bit. + */ +#define __HAVE_ARCH_PTEP_SET_WRPROTECT +static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) +{ + pteval_t pteval; + unsigned long tmp; + + asm volatile("// ptep_set_wrprotect\n" + " prfm pstl1strm, %2\n" + "1: ldxr %0, %2\n" + " tst %0, %4 // check for hw dirty (!PTE_RDONLY)\n" + " csel %1, %3, xzr, eq // set PTE_DIRTY|PTE_RDONLY if dirty\n" + " orr %0, %0, %1 // if !dirty, PTE_RDONLY is already set\n" + " and %0, %0, %5 // clear PTE_WRITE/PTE_DBM\n" + " stxr %w1, %0, %2\n" + " cbnz %w1, 1b\n" + : "=&r" (pteval), "=&r" (tmp), "+Q" (pte_val(*ptep)) + : "r" (PTE_DIRTY|PTE_RDONLY), "L" (PTE_RDONLY), "L" (~PTE_WRITE) + : "cc"); +} + +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +#define __HAVE_ARCH_PMDP_SET_WRPROTECT +static inline void pmdp_set_wrprotect(struct mm_struct *mm, + unsigned long address, pmd_t *pmdp) +{ + ptep_set_wrprotect(mm, address, (pte_t *)pmdp); +} +#endif +#endif /* CONFIG_ARM64_HW_AFDBM */ + extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern pgd_t idmap_pg_dir[PTRS_PER_PGD]; diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index 39139a3aa16d8..a8be513dff6f9 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -196,6 +196,19 @@ ENTRY(__cpu_setup) */ mrs x9, ID_AA64MMFR0_EL1 bfi x10, x9, #32, #3 +#ifdef CONFIG_ARM64_HW_AFDBM + /* + * Hardware update of the Access and Dirty bits. + */ + mrs x9, ID_AA64MMFR1_EL1 + and x9, x9, #0xf + cbz x9, 2f + cmp x9, #2 + b.lt 1f + orr x10, x10, #TCR_HD // hardware Dirty flag update +1: orr x10, x10, #TCR_HA // hardware Access flag update +2: +#endif /* CONFIG_ARM64_HW_AFDBM */ msr tcr_el1, x10 ret // return to head.S ENDPROC(__cpu_setup) -- GitLab From 0723c05fb75e4428b79b5cd657af7496b2604422 Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Thu, 16 Jul 2015 21:26:16 +0100 Subject: [PATCH 1749/7006] arm64: enable more compressed Image formats Plumb up Makefile arguments for the already supported formats in the kbuild system: lz4, bzip2, lzma, and lzo. Note that just as with Image.gz, these images are not self-decompressing and the booting firmware still needs to handle decompression before launching the kernel image. Signed-off-by: Olof Johansson Signed-off-by: Will Deacon --- arch/arm64/Makefile | 5 ++++- arch/arm64/boot/Makefile | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 4d2a925998f92..0953a97b51196 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -58,7 +58,10 @@ all: $(KBUILD_IMAGE) $(KBUILD_DTBS) boot := arch/arm64/boot -Image Image.gz: vmlinux +Image: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +Image.%: vmlinux $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ zinstall install: vmlinux diff --git a/arch/arm64/boot/Makefile b/arch/arm64/boot/Makefile index 5a0e3ab854a57..abcbba2f01baa 100644 --- a/arch/arm64/boot/Makefile +++ b/arch/arm64/boot/Makefile @@ -19,9 +19,21 @@ targets := Image Image.gz $(obj)/Image: vmlinux FORCE $(call if_changed,objcopy) +$(obj)/Image.bz2: $(obj)/Image FORCE + $(call if_changed,bzip2) + $(obj)/Image.gz: $(obj)/Image FORCE $(call if_changed,gzip) +$(obj)/Image.lz4: $(obj)/Image FORCE + $(call if_changed,lz4) + +$(obj)/Image.lzma: $(obj)/Image FORCE + $(call if_changed,lzma) + +$(obj)/Image.lzo: $(obj)/Image FORCE + $(call if_changed,lzo) + install: $(obj)/Image $(CONFIG_SHELL) $(srctree)/$(src)/install.sh $(KERNELRELEASE) \ $(obj)/Image System.map "$(INSTALL_PATH)" -- GitLab From 5d220ff9420f8b1689805ba2d938bedf9e0860a4 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Tue, 14 Jul 2015 16:20:17 +0100 Subject: [PATCH 1750/7006] arm64: Better native ptrace support for compat tasks The compat ptrace interface allows access to the TLS register, hardware breakpoints and watchpoints, syscall number. However, a native task using the native ptrace interface to debug compat tasks (e.g. multi-arch gdb) only has access to the general and VFP register sets. The compat ptrace interface cannot be accessed from a native task. This patch adds a new user_aarch32_ptrace_view which contains the TLS, hardware breakpoint/watchpoint and syscall number regsets in addition to the existing GPR and VFP regsets. This view is backwards compatible with the previous kernels. Core dumping of 32-bit tasks and compat ptrace are not affected since the original user_aarch32_view is preserved. Signed-off-by: Catalin Marinas Reported-by: Yao Qi Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/kernel/ptrace.c | 92 +++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index d882b833dbdb5..1971f491bb90c 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -826,6 +826,30 @@ static int compat_vfp_set(struct task_struct *target, return ret; } +static int compat_tls_get(struct task_struct *target, + const struct user_regset *regset, unsigned int pos, + unsigned int count, void *kbuf, void __user *ubuf) +{ + compat_ulong_t tls = (compat_ulong_t)target->thread.tp_value; + return user_regset_copyout(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); +} + +static int compat_tls_set(struct task_struct *target, + const struct user_regset *regset, unsigned int pos, + unsigned int count, const void *kbuf, + const void __user *ubuf) +{ + int ret; + compat_ulong_t tls; + + ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &tls, 0, -1); + if (ret) + return ret; + + target->thread.tp_value = tls; + return ret; +} + static const struct user_regset aarch32_regsets[] = { [REGSET_COMPAT_GPR] = { .core_note_type = NT_PRSTATUS, @@ -850,6 +874,64 @@ static const struct user_regset_view user_aarch32_view = { .regsets = aarch32_regsets, .n = ARRAY_SIZE(aarch32_regsets) }; +static const struct user_regset aarch32_ptrace_regsets[] = { + [REGSET_GPR] = { + .core_note_type = NT_PRSTATUS, + .n = COMPAT_ELF_NGREG, + .size = sizeof(compat_elf_greg_t), + .align = sizeof(compat_elf_greg_t), + .get = compat_gpr_get, + .set = compat_gpr_set + }, + [REGSET_FPR] = { + .core_note_type = NT_ARM_VFP, + .n = VFP_STATE_SIZE / sizeof(compat_ulong_t), + .size = sizeof(compat_ulong_t), + .align = sizeof(compat_ulong_t), + .get = compat_vfp_get, + .set = compat_vfp_set + }, + [REGSET_TLS] = { + .core_note_type = NT_ARM_TLS, + .n = 1, + .size = sizeof(compat_ulong_t), + .align = sizeof(compat_ulong_t), + .get = compat_tls_get, + .set = compat_tls_set, + }, +#ifdef CONFIG_HAVE_HW_BREAKPOINT + [REGSET_HW_BREAK] = { + .core_note_type = NT_ARM_HW_BREAK, + .n = sizeof(struct user_hwdebug_state) / sizeof(u32), + .size = sizeof(u32), + .align = sizeof(u32), + .get = hw_break_get, + .set = hw_break_set, + }, + [REGSET_HW_WATCH] = { + .core_note_type = NT_ARM_HW_WATCH, + .n = sizeof(struct user_hwdebug_state) / sizeof(u32), + .size = sizeof(u32), + .align = sizeof(u32), + .get = hw_break_get, + .set = hw_break_set, + }, +#endif + [REGSET_SYSTEM_CALL] = { + .core_note_type = NT_ARM_SYSTEM_CALL, + .n = 1, + .size = sizeof(int), + .align = sizeof(int), + .get = system_call_get, + .set = system_call_set, + }, +}; + +static const struct user_regset_view user_aarch32_ptrace_view = { + .name = "aarch32", .e_machine = EM_ARM, + .regsets = aarch32_ptrace_regsets, .n = ARRAY_SIZE(aarch32_ptrace_regsets) +}; + static int compat_ptrace_read_user(struct task_struct *tsk, compat_ulong_t off, compat_ulong_t __user *ret) { @@ -1109,8 +1191,16 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request, const struct user_regset_view *task_user_regset_view(struct task_struct *task) { #ifdef CONFIG_COMPAT - if (is_compat_thread(task_thread_info(task))) + /* + * Core dumping of 32-bit tasks or compat ptrace requests must use the + * user_aarch32_view compatible with arm32. Native ptrace requests on + * 32-bit children use an extended user_aarch32_ptrace_view to allow + * access to the TLS register. + */ + if (is_compat_task()) return &user_aarch32_view; + else if (is_compat_thread(task_thread_info(task))) + return &user_aarch32_ptrace_view; #endif return &user_aarch64_view; } -- GitLab From 23e94994464a7281838785675e09c8ed1055f62f Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 2 Jun 2015 15:18:38 +0100 Subject: [PATCH 1751/7006] arm64: lib: use pair accessors for copy_*_user routines The AArch64 instruction set contains load/store pair memory accessors, so use these in our copy_*_user routines to transfer 16 bytes per iteration. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/lib/copy_from_user.S | 17 +++++++++++------ arch/arm64/lib/copy_in_user.S | 17 +++++++++++------ arch/arm64/lib/copy_to_user.S | 17 +++++++++++------ 3 files changed, 33 insertions(+), 18 deletions(-) diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 5e27add9d3624..47c3fa5ae4ae6 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -28,14 +28,19 @@ * x0 - bytes not copied */ ENTRY(__copy_from_user) - add x4, x1, x2 // upper user buffer boundary - subs x2, x2, #8 + add x5, x1, x2 // upper user buffer boundary + subs x2, x2, #16 + b.mi 1f +0: +USER(9f, ldp x3, x4, [x1], #16) + subs x2, x2, #16 + stp x3, x4, [x0], #16 + b.pl 0b +1: adds x2, x2, #8 b.mi 2f -1: USER(9f, ldr x3, [x1], #8 ) - subs x2, x2, #8 + sub x2, x2, #8 str x3, [x0], #8 - b.pl 1b 2: adds x2, x2, #4 b.mi 3f USER(9f, ldr w3, [x1], #4 ) @@ -56,7 +61,7 @@ ENDPROC(__copy_from_user) .section .fixup,"ax" .align 2 -9: sub x2, x4, x1 +9: sub x2, x5, x1 mov x3, x2 10: strb wzr, [x0], #1 // zero remaining buffer space subs x3, x3, #1 diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index 84b6c9bb9b936..436bcc5d77b50 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -30,14 +30,19 @@ * x0 - bytes not copied */ ENTRY(__copy_in_user) - add x4, x0, x2 // upper user buffer boundary - subs x2, x2, #8 + add x5, x0, x2 // upper user buffer boundary + subs x2, x2, #16 + b.mi 1f +0: +USER(9f, ldp x3, x4, [x1], #16) + subs x2, x2, #16 +USER(9f, stp x3, x4, [x0], #16) + b.pl 0b +1: adds x2, x2, #8 b.mi 2f -1: USER(9f, ldr x3, [x1], #8 ) - subs x2, x2, #8 + sub x2, x2, #8 USER(9f, str x3, [x0], #8 ) - b.pl 1b 2: adds x2, x2, #4 b.mi 3f USER(9f, ldr w3, [x1], #4 ) @@ -58,6 +63,6 @@ ENDPROC(__copy_in_user) .section .fixup,"ax" .align 2 -9: sub x0, x4, x0 // bytes not copied +9: sub x0, x5, x0 // bytes not copied ret .previous diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index a0aeeb9b7a284..f5e1f526f408c 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -28,14 +28,19 @@ * x0 - bytes not copied */ ENTRY(__copy_to_user) - add x4, x0, x2 // upper user buffer boundary - subs x2, x2, #8 + add x5, x0, x2 // upper user buffer boundary + subs x2, x2, #16 + b.mi 1f +0: + ldp x3, x4, [x1], #16 + subs x2, x2, #16 +USER(9f, stp x3, x4, [x0], #16) + b.pl 0b +1: adds x2, x2, #8 b.mi 2f -1: ldr x3, [x1], #8 - subs x2, x2, #8 + sub x2, x2, #8 USER(9f, str x3, [x0], #8 ) - b.pl 1b 2: adds x2, x2, #4 b.mi 3f ldr w3, [x1], #4 @@ -56,6 +61,6 @@ ENDPROC(__copy_to_user) .section .fixup,"ax" .align 2 -9: sub x0, x4, x0 // bytes not copied +9: sub x0, x5, x0 // bytes not copied ret .previous -- GitLab From 52da443ec4d0a807b720527eb474f9c2878cd671 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Mon, 6 Jul 2015 12:23:54 +0100 Subject: [PATCH 1752/7006] arm64: perf: factor out callchain code We currently bundle the callchain handling code with the PMU code, despite the fact the two are distinct, and the former can be useful even in the absence of the latter. Follow the example of arch/arm and factor the callchain handling into its own file dependent on CONFIG_PERF_EVENTS rather than CONFIG_HW_PERF_EVENTS. Signed-off-by: Mark Rutland Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/include/asm/perf_event.h | 2 +- arch/arm64/kernel/Makefile | 2 +- arch/arm64/kernel/perf_callchain.c | 196 ++++++++++++++++++++++++++++ arch/arm64/kernel/perf_event.c | 178 ------------------------- 4 files changed, 198 insertions(+), 180 deletions(-) create mode 100644 arch/arm64/kernel/perf_callchain.c diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index 6471773db6fd8..7bd3cdb533ea8 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -17,7 +17,7 @@ #ifndef __ASM_PERF_EVENT_H #define __ASM_PERF_EVENT_H -#ifdef CONFIG_HW_PERF_EVENTS +#ifdef CONFIG_PERF_EVENTS struct pt_regs; extern unsigned long perf_instruction_pointer(struct pt_regs *regs); extern unsigned long perf_misc_flags(struct pt_regs *regs); diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 426d0763c81bf..e89063eff14f1 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -25,7 +25,7 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o -arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o +arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c new file mode 100644 index 0000000000000..3aa74830cc69a --- /dev/null +++ b/arch/arm64/kernel/perf_callchain.c @@ -0,0 +1,196 @@ +/* + * arm64 callchain support + * + * Copyright (C) 2015 ARM Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include + +#include + +struct frame_tail { + struct frame_tail __user *fp; + unsigned long lr; +} __attribute__((packed)); + +/* + * Get the return address for a single stackframe and return a pointer to the + * next frame tail. + */ +static struct frame_tail __user * +user_backtrace(struct frame_tail __user *tail, + struct perf_callchain_entry *entry) +{ + struct frame_tail buftail; + unsigned long err; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) + return NULL; + + pagefault_disable(); + err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); + pagefault_enable(); + + if (err) + return NULL; + + perf_callchain_store(entry, buftail.lr); + + /* + * Frame pointers should strictly progress back up the stack + * (towards higher addresses). + */ + if (tail >= buftail.fp) + return NULL; + + return buftail.fp; +} + +#ifdef CONFIG_COMPAT +/* + * The registers we're interested in are at the end of the variable + * length saved register structure. The fp points at the end of this + * structure so the address of this struct is: + * (struct compat_frame_tail *)(xxx->fp)-1 + * + * This code has been adapted from the ARM OProfile support. + */ +struct compat_frame_tail { + compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */ + u32 sp; + u32 lr; +} __attribute__((packed)); + +static struct compat_frame_tail __user * +compat_user_backtrace(struct compat_frame_tail __user *tail, + struct perf_callchain_entry *entry) +{ + struct compat_frame_tail buftail; + unsigned long err; + + /* Also check accessibility of one struct frame_tail beyond */ + if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) + return NULL; + + pagefault_disable(); + err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); + pagefault_enable(); + + if (err) + return NULL; + + perf_callchain_store(entry, buftail.lr); + + /* + * Frame pointers should strictly progress back up the stack + * (towards higher addresses). + */ + if (tail + 1 >= (struct compat_frame_tail __user *) + compat_ptr(buftail.fp)) + return NULL; + + return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1; +} +#endif /* CONFIG_COMPAT */ + +void perf_callchain_user(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + /* We don't support guest os callchain now */ + return; + } + + perf_callchain_store(entry, regs->pc); + + if (!compat_user_mode(regs)) { + /* AARCH64 mode */ + struct frame_tail __user *tail; + + tail = (struct frame_tail __user *)regs->regs[29]; + + while (entry->nr < PERF_MAX_STACK_DEPTH && + tail && !((unsigned long)tail & 0xf)) + tail = user_backtrace(tail, entry); + } else { +#ifdef CONFIG_COMPAT + /* AARCH32 compat mode */ + struct compat_frame_tail __user *tail; + + tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; + + while ((entry->nr < PERF_MAX_STACK_DEPTH) && + tail && !((unsigned long)tail & 0x3)) + tail = compat_user_backtrace(tail, entry); +#endif + } +} + +/* + * Gets called by walk_stackframe() for every stackframe. This will be called + * whist unwinding the stackframe and is like a subroutine return so we use + * the PC. + */ +static int callchain_trace(struct stackframe *frame, void *data) +{ + struct perf_callchain_entry *entry = data; + perf_callchain_store(entry, frame->pc); + return 0; +} + +void perf_callchain_kernel(struct perf_callchain_entry *entry, + struct pt_regs *regs) +{ + struct stackframe frame; + + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + /* We don't support guest os callchain now */ + return; + } + + frame.fp = regs->regs[29]; + frame.sp = regs->sp; + frame.pc = regs->pc; + + walk_stackframe(&frame, callchain_trace, entry); +} + +unsigned long perf_instruction_pointer(struct pt_regs *regs) +{ + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) + return perf_guest_cbs->get_guest_ip(); + + return instruction_pointer(regs); +} + +unsigned long perf_misc_flags(struct pt_regs *regs) +{ + int misc = 0; + + if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { + if (perf_guest_cbs->is_user_mode()) + misc |= PERF_RECORD_MISC_GUEST_USER; + else + misc |= PERF_RECORD_MISC_GUEST_KERNEL; + } else { + if (user_mode(regs)) + misc |= PERF_RECORD_MISC_USER; + else + misc |= PERF_RECORD_MISC_KERNEL; + } + + return misc; +} diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 563f8ce8df68d..1821405614164 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -36,7 +36,6 @@ #include #include #include -#include /* * ARMv8 supports a maximum of 32 events. @@ -1413,180 +1412,3 @@ static int __init init_hw_perf_events(void) } early_initcall(init_hw_perf_events); -/* - * Callchain handling code. - */ -struct frame_tail { - struct frame_tail __user *fp; - unsigned long lr; -} __attribute__((packed)); - -/* - * Get the return address for a single stackframe and return a pointer to the - * next frame tail. - */ -static struct frame_tail __user * -user_backtrace(struct frame_tail __user *tail, - struct perf_callchain_entry *entry) -{ - struct frame_tail buftail; - unsigned long err; - - /* Also check accessibility of one struct frame_tail beyond */ - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) - return NULL; - - pagefault_disable(); - err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); - pagefault_enable(); - - if (err) - return NULL; - - perf_callchain_store(entry, buftail.lr); - - /* - * Frame pointers should strictly progress back up the stack - * (towards higher addresses). - */ - if (tail >= buftail.fp) - return NULL; - - return buftail.fp; -} - -#ifdef CONFIG_COMPAT -/* - * The registers we're interested in are at the end of the variable - * length saved register structure. The fp points at the end of this - * structure so the address of this struct is: - * (struct compat_frame_tail *)(xxx->fp)-1 - * - * This code has been adapted from the ARM OProfile support. - */ -struct compat_frame_tail { - compat_uptr_t fp; /* a (struct compat_frame_tail *) in compat mode */ - u32 sp; - u32 lr; -} __attribute__((packed)); - -static struct compat_frame_tail __user * -compat_user_backtrace(struct compat_frame_tail __user *tail, - struct perf_callchain_entry *entry) -{ - struct compat_frame_tail buftail; - unsigned long err; - - /* Also check accessibility of one struct frame_tail beyond */ - if (!access_ok(VERIFY_READ, tail, sizeof(buftail))) - return NULL; - - pagefault_disable(); - err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail)); - pagefault_enable(); - - if (err) - return NULL; - - perf_callchain_store(entry, buftail.lr); - - /* - * Frame pointers should strictly progress back up the stack - * (towards higher addresses). - */ - if (tail + 1 >= (struct compat_frame_tail __user *) - compat_ptr(buftail.fp)) - return NULL; - - return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1; -} -#endif /* CONFIG_COMPAT */ - -void perf_callchain_user(struct perf_callchain_entry *entry, - struct pt_regs *regs) -{ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - /* We don't support guest os callchain now */ - return; - } - - perf_callchain_store(entry, regs->pc); - - if (!compat_user_mode(regs)) { - /* AARCH64 mode */ - struct frame_tail __user *tail; - - tail = (struct frame_tail __user *)regs->regs[29]; - - while (entry->nr < PERF_MAX_STACK_DEPTH && - tail && !((unsigned long)tail & 0xf)) - tail = user_backtrace(tail, entry); - } else { -#ifdef CONFIG_COMPAT - /* AARCH32 compat mode */ - struct compat_frame_tail __user *tail; - - tail = (struct compat_frame_tail __user *)regs->compat_fp - 1; - - while ((entry->nr < PERF_MAX_STACK_DEPTH) && - tail && !((unsigned long)tail & 0x3)) - tail = compat_user_backtrace(tail, entry); -#endif - } -} - -/* - * Gets called by walk_stackframe() for every stackframe. This will be called - * whist unwinding the stackframe and is like a subroutine return so we use - * the PC. - */ -static int callchain_trace(struct stackframe *frame, void *data) -{ - struct perf_callchain_entry *entry = data; - perf_callchain_store(entry, frame->pc); - return 0; -} - -void perf_callchain_kernel(struct perf_callchain_entry *entry, - struct pt_regs *regs) -{ - struct stackframe frame; - - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - /* We don't support guest os callchain now */ - return; - } - - frame.fp = regs->regs[29]; - frame.sp = regs->sp; - frame.pc = regs->pc; - - walk_stackframe(&frame, callchain_trace, entry); -} - -unsigned long perf_instruction_pointer(struct pt_regs *regs) -{ - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) - return perf_guest_cbs->get_guest_ip(); - - return instruction_pointer(regs); -} - -unsigned long perf_misc_flags(struct pt_regs *regs) -{ - int misc = 0; - - if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) { - if (perf_guest_cbs->is_user_mode()) - misc |= PERF_RECORD_MISC_GUEST_USER; - else - misc |= PERF_RECORD_MISC_GUEST_KERNEL; - } else { - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - } - - return misc; -} -- GitLab From 4b3dc9679cf779339d9049800803dfc3c83433d1 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 29 May 2015 18:28:44 +0100 Subject: [PATCH 1753/7006] arm64: force CONFIG_SMP=y and remove redundant #ifdefs Nobody seems to be producing !SMP systems anymore, so this is just becoming a source of kernel bugs, particularly if people want to use coherent DMA with non-shared pages. This patch forces CONFIG_SMP=y for arm64, removing a modest amount of code in the process. Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 26 ++++---------------------- arch/arm64/include/asm/assembler.h | 2 -- arch/arm64/include/asm/barrier.h | 24 ------------------------ arch/arm64/include/asm/hardirq.h | 4 ---- arch/arm64/include/asm/irq_work.h | 11 ----------- arch/arm64/include/asm/percpu.h | 8 -------- arch/arm64/include/asm/pgtable.h | 5 ----- arch/arm64/include/asm/ptrace.h | 4 ---- arch/arm64/include/asm/smp.h | 4 ---- arch/arm64/include/asm/topology.h | 9 --------- arch/arm64/kernel/Makefile | 7 ++++--- arch/arm64/kernel/cpu_ops.c | 2 -- arch/arm64/kernel/head.S | 7 ------- arch/arm64/kernel/irq.c | 2 -- arch/arm64/kernel/psci.c | 5 ----- arch/arm64/kernel/setup.c | 6 ------ arch/arm64/kernel/sleep.S | 5 ----- arch/arm64/kernel/time.c | 2 -- arch/arm64/kernel/traps.c | 4 ---- arch/arm64/mm/context.c | 16 ---------------- arch/arm64/mm/flush.c | 4 ---- arch/arm64/mm/proc.S | 4 ---- 22 files changed, 8 insertions(+), 153 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 40f717f8820a6..de8dee60fd825 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -28,7 +28,7 @@ config ARM64 select EDAC_SUPPORT select GENERIC_ALLOCATOR select GENERIC_CLOCKEVENTS - select GENERIC_CLOCKEVENTS_BROADCAST if SMP + select GENERIC_CLOCKEVENTS_BROADCAST select GENERIC_CPU_AUTOPROBE select GENERIC_EARLY_IOREMAP select GENERIC_IRQ_PROBE @@ -137,6 +137,9 @@ config NEED_DMA_MAP_STATE config NEED_SG_DMA_LENGTH def_bool y +config SMP + def_bool y + config SWIOTLB def_bool y @@ -491,22 +494,8 @@ config CPU_BIG_ENDIAN help Say Y if you plan on running a kernel in big-endian mode. -config SMP - bool "Symmetric Multi-Processing" - help - This enables support for systems with more than one CPU. If - you say N here, the kernel will run on single and - multiprocessor machines, but will use only one CPU of a - multiprocessor machine. If you say Y here, the kernel will run - on many, but not all, single processor machines. On a single - processor machine, the kernel will run faster if you say N - here. - - If you don't know what to do here, say N. - config SCHED_MC bool "Multi-core scheduler support" - depends on SMP help Multi-core scheduler support improves the CPU scheduler's decision making when dealing with multi-core CPU chips at a cost of slightly @@ -514,7 +503,6 @@ config SCHED_MC config SCHED_SMT bool "SMT scheduler support" - depends on SMP help Improves the CPU scheduler's decision making when dealing with MultiThreading at a cost of slightly increased overhead in some @@ -523,23 +511,17 @@ config SCHED_SMT config NR_CPUS int "Maximum number of CPUs (2-4096)" range 2 4096 - depends on SMP # These have to remain sorted largest to smallest default "64" config HOTPLUG_CPU bool "Support for hot-pluggable CPUs" - depends on SMP help Say Y here to experiment with turning CPUs off and on. CPUs can be controlled through /sys/devices/system/cpu. source kernel/Kconfig.preempt -config UP_LATE_INIT - def_bool y - depends on !SMP - config HZ int default 100 diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h index e10516bbe8339..b51f2cc22ca99 100644 --- a/arch/arm64/include/asm/assembler.h +++ b/arch/arm64/include/asm/assembler.h @@ -91,9 +91,7 @@ * SMP data memory barrier */ .macro smp_dmb, opt -#ifdef CONFIG_SMP dmb \opt -#endif .endm #define USER(l, x...) \ diff --git a/arch/arm64/include/asm/barrier.h b/arch/arm64/include/asm/barrier.h index 0fa47c4275cb5..624f9679f4b0a 100644 --- a/arch/arm64/include/asm/barrier.h +++ b/arch/arm64/include/asm/barrier.h @@ -35,28 +35,6 @@ #define dma_rmb() dmb(oshld) #define dma_wmb() dmb(oshst) -#ifndef CONFIG_SMP -#define smp_mb() barrier() -#define smp_rmb() barrier() -#define smp_wmb() barrier() - -#define smp_store_release(p, v) \ -do { \ - compiletime_assert_atomic_type(*p); \ - barrier(); \ - ACCESS_ONCE(*p) = (v); \ -} while (0) - -#define smp_load_acquire(p) \ -({ \ - typeof(*p) ___p1 = ACCESS_ONCE(*p); \ - compiletime_assert_atomic_type(*p); \ - barrier(); \ - ___p1; \ -}) - -#else - #define smp_mb() dmb(ish) #define smp_rmb() dmb(ishld) #define smp_wmb() dmb(ishst) @@ -109,8 +87,6 @@ do { \ ___p1; \ }) -#endif - #define read_barrier_depends() do { } while(0) #define smp_read_barrier_depends() do { } while(0) diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h index 6aae421f4d733..2bb7009bdac72 100644 --- a/arch/arm64/include/asm/hardirq.h +++ b/arch/arm64/include/asm/hardirq.h @@ -24,9 +24,7 @@ typedef struct { unsigned int __softirq_pending; -#ifdef CONFIG_SMP unsigned int ipi_irqs[NR_IPI]; -#endif } ____cacheline_aligned irq_cpustat_t; #include /* Standard mappings for irq_cpustat_t above */ @@ -34,10 +32,8 @@ typedef struct { #define __inc_irq_stat(cpu, member) __IRQ_STAT(cpu, member)++ #define __get_irq_stat(cpu, member) __IRQ_STAT(cpu, member) -#ifdef CONFIG_SMP u64 smp_irq_stat_cpu(unsigned int cpu); #define arch_irq_stat_cpu smp_irq_stat_cpu -#endif #define __ARCH_IRQ_EXIT_IRQS_DISABLED 1 diff --git a/arch/arm64/include/asm/irq_work.h b/arch/arm64/include/asm/irq_work.h index b4f6b19a8a685..8e24ef3f7c82c 100644 --- a/arch/arm64/include/asm/irq_work.h +++ b/arch/arm64/include/asm/irq_work.h @@ -1,8 +1,6 @@ #ifndef __ASM_IRQ_WORK_H #define __ASM_IRQ_WORK_H -#ifdef CONFIG_SMP - #include static inline bool arch_irq_work_has_interrupt(void) @@ -10,13 +8,4 @@ static inline bool arch_irq_work_has_interrupt(void) return !!__smp_cross_call; } -#else - -static inline bool arch_irq_work_has_interrupt(void) -{ - return false; -} - -#endif - #endif /* __ASM_IRQ_WORK_H */ diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h index 4fde8c1df97ff..0a456bef8c792 100644 --- a/arch/arm64/include/asm/percpu.h +++ b/arch/arm64/include/asm/percpu.h @@ -16,8 +16,6 @@ #ifndef __ASM_PERCPU_H #define __ASM_PERCPU_H -#ifdef CONFIG_SMP - static inline void set_my_cpu_offset(unsigned long off) { asm volatile("msr tpidr_el1, %0" :: "r" (off) : "memory"); @@ -38,12 +36,6 @@ static inline unsigned long __my_cpu_offset(void) } #define __my_cpu_offset __my_cpu_offset() -#else /* !CONFIG_SMP */ - -#define set_my_cpu_offset(x) do { } while (0) - -#endif /* CONFIG_SMP */ - #define PERCPU_OP(op, asm_op) \ static inline unsigned long __percpu_##op(void *ptr, \ unsigned long val, int size) \ diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h index 8212e6aa0fb11..d001846c13ac8 100644 --- a/arch/arm64/include/asm/pgtable.h +++ b/arch/arm64/include/asm/pgtable.h @@ -61,13 +61,8 @@ extern void __pmd_error(const char *file, int line, unsigned long val); extern void __pud_error(const char *file, int line, unsigned long val); extern void __pgd_error(const char *file, int line, unsigned long val); -#ifdef CONFIG_SMP #define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF | PTE_SHARED) #define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S) -#else -#define PROT_DEFAULT (PTE_TYPE_PAGE | PTE_AF) -#define PROT_SECT_DEFAULT (PMD_TYPE_SECT | PMD_SECT_AF) -#endif #define PROT_DEVICE_nGnRE (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_DEVICE_nGnRE)) #define PROT_NORMAL_NC (PROT_DEFAULT | PTE_PXN | PTE_UXN | PTE_ATTRINDX(MT_NORMAL_NC)) diff --git a/arch/arm64/include/asm/ptrace.h b/arch/arm64/include/asm/ptrace.h index d6dd9fdbc3bee..536274ed292ea 100644 --- a/arch/arm64/include/asm/ptrace.h +++ b/arch/arm64/include/asm/ptrace.h @@ -183,11 +183,7 @@ static inline int valid_user_regs(struct user_pt_regs *regs) #define instruction_pointer(regs) ((unsigned long)(regs)->pc) -#ifdef CONFIG_SMP extern unsigned long profile_pc(struct pt_regs *regs); -#else -#define profile_pc(regs) instruction_pointer(regs) -#endif #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index db02be81b90a1..d9c3d6a6100ac 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -20,10 +20,6 @@ #include #include -#ifndef CONFIG_SMP -# error " included in non-SMP build" -#endif - #define raw_smp_processor_id() (current_thread_info()->cpu) struct seq_file; diff --git a/arch/arm64/include/asm/topology.h b/arch/arm64/include/asm/topology.h index 225ec3524fbfc..a3e9d6fdbf213 100644 --- a/arch/arm64/include/asm/topology.h +++ b/arch/arm64/include/asm/topology.h @@ -1,8 +1,6 @@ #ifndef __ASM_TOPOLOGY_H #define __ASM_TOPOLOGY_H -#ifdef CONFIG_SMP - #include struct cpu_topology { @@ -24,13 +22,6 @@ void init_cpu_topology(void); void store_cpu_topology(unsigned int cpuid); const struct cpumask *cpu_coregroup_mask(int cpu); -#else - -static inline void init_cpu_topology(void) { } -static inline void store_cpu_topology(unsigned int cpuid) { } - -#endif - #include #endif /* _ASM_ARM_TOPOLOGY_H */ diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index e89063eff14f1..f126cfe990038 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -17,7 +17,8 @@ arm64-obj-y := debug-monitors.o entry.o irq.o fpsimd.o \ sys.o stacktrace.o time.o traps.o io.o vdso.o \ hyp-stub.o psci.o psci-call.o cpu_ops.o insn.o \ return_address.o cpuinfo.o cpu_errata.o \ - cpufeature.o alternative.o cacheinfo.o + cpufeature.o alternative.o cacheinfo.o \ + smp.o smp_spin_table.o topology.o arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ sys_compat.o entry32.o \ @@ -25,8 +26,8 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o -arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o -arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o +arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o +arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_callchain.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o diff --git a/arch/arm64/kernel/cpu_ops.c b/arch/arm64/kernel/cpu_ops.c index 5ea337dd2f15d..b6bd7d4477683 100644 --- a/arch/arm64/kernel/cpu_ops.c +++ b/arch/arm64/kernel/cpu_ops.c @@ -30,9 +30,7 @@ extern const struct cpu_operations cpu_psci_ops; const struct cpu_operations *cpu_ops[NR_CPUS]; static const struct cpu_operations *supported_cpu_ops[] __initconst = { -#ifdef CONFIG_SMP &smp_spin_table_ops, -#endif &cpu_psci_ops, NULL, }; diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S index c0ff3ce4299e9..3a06541739976 100644 --- a/arch/arm64/kernel/head.S +++ b/arch/arm64/kernel/head.S @@ -62,13 +62,8 @@ /* * Initial memory map attributes. */ -#ifndef CONFIG_SMP -#define PTE_FLAGS PTE_TYPE_PAGE | PTE_AF -#define PMD_FLAGS PMD_TYPE_SECT | PMD_SECT_AF -#else #define PTE_FLAGS PTE_TYPE_PAGE | PTE_AF | PTE_SHARED #define PMD_FLAGS PMD_TYPE_SECT | PMD_SECT_AF | PMD_SECT_S -#endif #ifdef CONFIG_ARM64_64K_PAGES #define MM_MMUFLAGS PTE_ATTRINDX(MT_NORMAL) | PTE_FLAGS @@ -574,7 +569,6 @@ ENTRY(__boot_cpu_mode) .long BOOT_CPU_MODE_EL1 .popsection -#ifdef CONFIG_SMP /* * This provides a "holding pen" for platforms to hold all secondary * cores are held until we're ready for them to initialise. @@ -622,7 +616,6 @@ ENTRY(__secondary_switched) mov x29, #0 b secondary_start_kernel ENDPROC(__secondary_switched) -#endif /* CONFIG_SMP */ /* * Enable the MMU. diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c index 463fa2e7e34c1..11dc3fd478537 100644 --- a/arch/arm64/kernel/irq.c +++ b/arch/arm64/kernel/irq.c @@ -33,9 +33,7 @@ unsigned long irq_err_count; int arch_show_interrupts(struct seq_file *p, int prec) { -#ifdef CONFIG_SMP show_ipi_list(p, prec); -#endif seq_printf(p, "%*s: %10lu\n", prec, "Err", irq_err_count); return 0; } diff --git a/arch/arm64/kernel/psci.c b/arch/arm64/kernel/psci.c index 869f202748e8e..ec30152090ae2 100644 --- a/arch/arm64/kernel/psci.c +++ b/arch/arm64/kernel/psci.c @@ -462,8 +462,6 @@ int __init psci_acpi_init(void) } #endif -#ifdef CONFIG_SMP - static int __init cpu_psci_cpu_init(unsigned int cpu) { return 0; @@ -550,7 +548,6 @@ static int cpu_psci_cpu_kill(unsigned int cpu) return -ETIMEDOUT; } #endif -#endif static int psci_suspend_finisher(unsigned long index) { @@ -585,7 +582,6 @@ const struct cpu_operations cpu_psci_ops = { .cpu_init_idle = cpu_psci_cpu_init_idle, .cpu_suspend = cpu_psci_cpu_suspend, #endif -#ifdef CONFIG_SMP .cpu_init = cpu_psci_cpu_init, .cpu_prepare = cpu_psci_cpu_prepare, .cpu_boot = cpu_psci_cpu_boot, @@ -594,6 +590,5 @@ const struct cpu_operations cpu_psci_ops = { .cpu_die = cpu_psci_cpu_die, .cpu_kill = cpu_psci_cpu_kill, #endif -#endif }; diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index f3067d4d4e357..cf609cf3fcb51 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -131,7 +131,6 @@ bool arch_match_cpu_phys_id(int cpu, u64 phys_id) } struct mpidr_hash mpidr_hash; -#ifdef CONFIG_SMP /** * smp_build_mpidr_hash - Pre-compute shifts required at each affinity * level in order to build a linear index from an @@ -197,7 +196,6 @@ static void __init smp_build_mpidr_hash(void) pr_warn("Large number of MPIDR hash buckets detected\n"); __flush_dcache_area(&mpidr_hash, sizeof(struct mpidr_hash)); } -#endif static void __init hyp_mode_check(void) { @@ -405,10 +403,8 @@ void __init setup_arch(char **cmdline_p) xen_early_init(); cpu_read_bootcpu_ops(); -#ifdef CONFIG_SMP smp_init_cpus(); smp_build_mpidr_hash(); -#endif #ifdef CONFIG_VT #if defined(CONFIG_VGA_CONSOLE) @@ -508,9 +504,7 @@ static int c_show(struct seq_file *m, void *v) * online processors, looking for lines beginning with * "processor". Give glibc what it expects. */ -#ifdef CONFIG_SMP seq_printf(m, "processor\t: %d\n", i); -#endif /* * Dump out the common processor features in a single line. diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S index 803cfea41962f..5686a3ae3940f 100644 --- a/arch/arm64/kernel/sleep.S +++ b/arch/arm64/kernel/sleep.S @@ -82,7 +82,6 @@ ENTRY(__cpu_suspend_enter) str x2, [x0, #CPU_CTX_SP] ldr x1, =sleep_save_sp ldr x1, [x1, #SLEEP_SAVE_SP_VIRT] -#ifdef CONFIG_SMP mrs x7, mpidr_el1 ldr x9, =mpidr_hash ldr x10, [x9, #MPIDR_HASH_MASK] @@ -94,7 +93,6 @@ ENTRY(__cpu_suspend_enter) ldp w5, w6, [x9, #(MPIDR_HASH_SHIFTS + 8)] compute_mpidr_hash x8, x3, x4, x5, x6, x7, x10 add x1, x1, x8, lsl #3 -#endif bl __cpu_suspend_save /* * Grab suspend finisher in x20 and its argument in x19 @@ -151,7 +149,6 @@ ENDPROC(cpu_resume_after_mmu) ENTRY(cpu_resume) bl el2_setup // if in EL2 drop to EL1 cleanly -#ifdef CONFIG_SMP mrs x1, mpidr_el1 adrp x8, mpidr_hash add x8, x8, #:lo12:mpidr_hash // x8 = struct mpidr_hash phys address @@ -161,9 +158,7 @@ ENTRY(cpu_resume) ldp w5, w6, [x8, #(MPIDR_HASH_SHIFTS + 8)] compute_mpidr_hash x7, x3, x4, x5, x6, x1, x2 /* x7 contains hash index, let's use it to grab context pointer */ -#else mov x7, xzr -#endif ldr_l x0, sleep_save_sp + SLEEP_SAVE_SP_PHYS ldr x0, [x0, x7, lsl #3] /* load sp from context */ diff --git a/arch/arm64/kernel/time.c b/arch/arm64/kernel/time.c index 42f9195cf2f8a..149151fb42bb1 100644 --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -42,7 +42,6 @@ #include #include -#ifdef CONFIG_SMP unsigned long profile_pc(struct pt_regs *regs) { struct stackframe frame; @@ -62,7 +61,6 @@ unsigned long profile_pc(struct pt_regs *regs) return frame.pc; } EXPORT_SYMBOL(profile_pc); -#endif void __init time_init(void) { diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 4db6a2574fec8..1ea920cbd66d2 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -189,11 +189,7 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) #else #define S_PREEMPT "" #endif -#ifdef CONFIG_SMP #define S_SMP " SMP" -#else -#define S_SMP "" -#endif static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c index 76c1e6cd36fc4..d70ff14dbdbdd 100644 --- a/arch/arm64/mm/context.c +++ b/arch/arm64/mm/context.c @@ -53,8 +53,6 @@ static void flush_context(void) __flush_icache_all(); } -#ifdef CONFIG_SMP - static void set_mm_context(struct mm_struct *mm, unsigned int asid) { unsigned long flags; @@ -110,23 +108,12 @@ static void reset_context(void *info) cpu_switch_mm(mm->pgd, mm); } -#else - -static inline void set_mm_context(struct mm_struct *mm, unsigned int asid) -{ - mm->context.id = asid; - cpumask_copy(mm_cpumask(mm), cpumask_of(smp_processor_id())); -} - -#endif - void __new_context(struct mm_struct *mm) { unsigned int asid; unsigned int bits = asid_bits(); raw_spin_lock(&cpu_asid_lock); -#ifdef CONFIG_SMP /* * Check the ASID again, in case the change was broadcast from another * CPU before we acquired the lock. @@ -136,7 +123,6 @@ void __new_context(struct mm_struct *mm) raw_spin_unlock(&cpu_asid_lock); return; } -#endif /* * At this point, it is guaranteed that the current mm (with an old * ASID) isn't active on any other CPU since the ASIDs are changed @@ -155,10 +141,8 @@ void __new_context(struct mm_struct *mm) cpu_last_asid = ASID_FIRST_VERSION; asid = cpu_last_asid + smp_processor_id(); flush_context(); -#ifdef CONFIG_SMP smp_wmb(); smp_call_function(reset_context, NULL, 1); -#endif cpu_last_asid += NR_CPUS - 1; } diff --git a/arch/arm64/mm/flush.c b/arch/arm64/mm/flush.c index 4dfa3975ce5be..c26b804015e80 100644 --- a/arch/arm64/mm/flush.c +++ b/arch/arm64/mm/flush.c @@ -60,14 +60,10 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page, unsigned long uaddr, void *dst, const void *src, unsigned long len) { -#ifdef CONFIG_SMP preempt_disable(); -#endif memcpy(dst, src, len); flush_ptrace_access(vma, page, uaddr, dst, len); -#ifdef CONFIG_SMP preempt_enable(); -#endif } void __sync_icache_dcache(pte_t pte, unsigned long addr) diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S index a8be513dff6f9..34da270f9e344 100644 --- a/arch/arm64/mm/proc.S +++ b/arch/arm64/mm/proc.S @@ -34,11 +34,7 @@ #define TCR_TG_FLAGS TCR_TG0_4K | TCR_TG1_4K #endif -#ifdef CONFIG_SMP #define TCR_SMP_FLAGS TCR_SHARED -#else -#define TCR_SMP_FLAGS 0 -#endif /* PTWs cacheable, inner/outer WBWA */ #define TCR_CACHE_FLAGS TCR_IRGN_WBWA | TCR_ORGN_WBWA -- GitLab From 1d1ddf67dc3bfd80f60b216fa1fedfb242bee299 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 17 Jul 2015 16:58:21 +0100 Subject: [PATCH 1754/7006] arm64: dma-mapping: implement dma_get_sgtable() The default dma_common_get_sgtable() implementation relies on the CPU address of the buffer being a regular lowmem address. This is not always the case on arm64, since allocations from the various DMA pools may have remapped vmalloc addresses, rendering the use of virt_to_page() invalid. Fix this by providing our own implementation based on the fact that we can safely derive a physical address from the DMA address in both cases. CC: Jon Medhurst Signed-off-by: Robin Murphy [will: made static] Signed-off-by: Will Deacon --- arch/arm64/mm/dma-mapping.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 63b2a117a03ca..e5d74cdfdb711 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -331,10 +331,24 @@ static int __swiotlb_mmap(struct device *dev, return ret; } +static int __swiotlb_get_sgtable(struct device *dev, struct sg_table *sgt, + void *cpu_addr, dma_addr_t handle, size_t size, + struct dma_attrs *attrs) +{ + int ret = sg_alloc_table(sgt, 1, GFP_KERNEL); + + if (!ret) + sg_set_page(sgt->sgl, phys_to_page(dma_to_phys(dev, handle)), + PAGE_ALIGN(size), 0); + + return ret; +} + static struct dma_map_ops swiotlb_dma_ops = { .alloc = __dma_alloc, .free = __dma_free, .mmap = __swiotlb_mmap, + .get_sgtable = __swiotlb_get_sgtable, .map_page = __swiotlb_map_page, .unmap_page = __swiotlb_unmap_page, .map_sg = __swiotlb_map_sg_attrs, -- GitLab From 0a570e7adeeae28892e60bc919c7dcf011815134 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 21 Jul 2015 15:43:58 +0100 Subject: [PATCH 1755/7006] arm64: hugetlb: remove paragraph about writing to FSF Remove paragraph about writing to the Free Software Foundation's mailing address from GPL notice. Signed-off-by: Jisheng Zhang Signed-off-by: Will Deacon --- arch/arm64/include/asm/hugetlb.h | 4 ---- arch/arm64/mm/hugetlbpage.c | 4 ---- 2 files changed, 8 deletions(-) diff --git a/arch/arm64/include/asm/hugetlb.h b/arch/arm64/include/asm/hugetlb.h index 2fd9b14ca2956..bb4052e85dbac 100644 --- a/arch/arm64/include/asm/hugetlb.h +++ b/arch/arm64/include/asm/hugetlb.h @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef __ASM_HUGETLB_H diff --git a/arch/arm64/mm/hugetlbpage.c b/arch/arm64/mm/hugetlbpage.c index 831ec534d449b..383b03ff38f85 100644 --- a/arch/arm64/mm/hugetlbpage.c +++ b/arch/arm64/mm/hugetlbpage.c @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include -- GitLab From ae2fb7ece973f0b285f41985f5de85c57df9bf5a Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 21 Jul 2015 11:36:39 +0100 Subject: [PATCH 1756/7006] arm64: perf: condense event number maps Most of the cache events an architecture might support do not map well to those provided by the ARM architecture, and as such most entries in the event number maps are *_UNSUPPORTED. Unfortuantely as 0 is a valid physical event identifier, the *_UNSUPPORTED macros expand to a non-zero value and thus each unsupported event must be explicitly initialised as such. This leads to large diffs when adding support for a new CPU, and makes it difficult to spot the important information. This patch follows arch/arm/ in making use of PERF_*_ALL_UNSUPPORTED macros to initialise all entries to *_UNSUPPORTED before overriding this for the specific events we actually support, resulting in a significant source code reduction. Signed-off-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/kernel/perf_event.c | 124 ++++++--------------------------- 1 file changed, 22 insertions(+), 102 deletions(-) diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 1821405614164..f9a74d4fff3b5 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -77,6 +77,16 @@ EXPORT_SYMBOL_GPL(perf_num_counters); #define CACHE_OP_UNSUPPORTED 0xFFFF +#define PERF_MAP_ALL_UNSUPPORTED \ + [0 ... PERF_COUNT_HW_MAX - 1] = HW_OP_UNSUPPORTED + +#define PERF_CACHE_MAP_ALL_UNSUPPORTED \ +[0 ... C(MAX) - 1] = { \ + [0 ... C(OP_MAX) - 1] = { \ + [0 ... C(RESULT_MAX) - 1] = CACHE_OP_UNSUPPORTED, \ + }, \ +} + static int armpmu_map_cache_event(const unsigned (*cache_map) [PERF_COUNT_HW_CACHE_MAX] @@ -700,118 +710,28 @@ enum armv8_pmuv3_perf_types { /* PMUv3 HW events mapping. */ static const unsigned armv8_pmuv3_perf_map[PERF_COUNT_HW_MAX] = { + PERF_MAP_ALL_UNSUPPORTED, [PERF_COUNT_HW_CPU_CYCLES] = ARMV8_PMUV3_PERFCTR_CLOCK_CYCLES, [PERF_COUNT_HW_INSTRUCTIONS] = ARMV8_PMUV3_PERFCTR_INSTR_EXECUTED, [PERF_COUNT_HW_CACHE_REFERENCES] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, [PERF_COUNT_HW_CACHE_MISSES] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, - [PERF_COUNT_HW_BRANCH_INSTRUCTIONS] = HW_OP_UNSUPPORTED, [PERF_COUNT_HW_BRANCH_MISSES] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, - [PERF_COUNT_HW_BUS_CYCLES] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_STALLED_CYCLES_FRONTEND] = HW_OP_UNSUPPORTED, - [PERF_COUNT_HW_STALLED_CYCLES_BACKEND] = HW_OP_UNSUPPORTED, }; static const unsigned armv8_pmuv3_perf_cache_map[PERF_COUNT_HW_CACHE_MAX] [PERF_COUNT_HW_CACHE_OP_MAX] [PERF_COUNT_HW_CACHE_RESULT_MAX] = { - [C(L1D)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, - [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, - [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(L1I)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(LL)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(DTLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(ITLB)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(BPU)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED, - [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED, - [C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, - [C(NODE)] = { - [C(OP_READ)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_WRITE)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - [C(OP_PREFETCH)] = { - [C(RESULT_ACCESS)] = CACHE_OP_UNSUPPORTED, - [C(RESULT_MISS)] = CACHE_OP_UNSUPPORTED, - }, - }, + PERF_CACHE_MAP_ALL_UNSUPPORTED, + + [C(L1D)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, + [C(L1D)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, + [C(L1D)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_ACCESS, + [C(L1D)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_L1_DCACHE_REFILL, + + [C(BPU)][C(OP_READ)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED, + [C(BPU)][C(OP_READ)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, + [C(BPU)][C(OP_WRITE)][C(RESULT_ACCESS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_PRED, + [C(BPU)][C(OP_WRITE)][C(RESULT_MISS)] = ARMV8_PMUV3_PERFCTR_PC_BRANCH_MIS_PRED, }; /* -- GitLab From 79b0e09a3c9bd74ee54582efdb351179d7c00351 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 21 Jul 2015 13:23:26 +0100 Subject: [PATCH 1757/7006] arm64: kernel: Add cpuid_feature_extract_field() for 4bit sign extension Based on arch/arm/include/asm/cputype.h, this function does the shifting and sign extension necessary when accessing cpu feature fields. Signed-off-by: James Morse Suggested-by: Russell King Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index c1044218a63a1..9fafa75379976 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -70,6 +70,13 @@ static inline void cpus_set_cap(unsigned int num) __set_bit(num, cpu_hwcaps); } +static inline int __attribute_const__ cpuid_feature_extract_field(u64 features, + int field) +{ + return (s64)(features << (64 - 4 - field)) >> (64 - 4); +} + + void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, const char *info); void check_local_cpu_errata(void); -- GitLab From 63e40815f02584ba8174e0f6af40924b2b335cae Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Wed, 22 Jul 2015 12:21:01 +0100 Subject: [PATCH 1758/7006] arm64: alternative: Provide if/else/endif assembler macros The existing alternative_insn macro has some limitations that make it hard to work with. In particular the fact it takes instructions from it own macro arguments means it doesn't play very nicely with C pre-processor macros because the macro arguments look like a string to the C pre-processor. Workarounds are (probably) possible but things start to look ugly. Introduce an alternative set of macros that allows instructions to be presented to the assembler as normal and switch everything over to the new macros. Signed-off-by: Daniel Thompson Signed-off-by: Will Deacon --- arch/arm64/include/asm/alternative.h | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index c385a0c4057f0..e86681ad0931d 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -77,6 +77,47 @@ void free_alternatives_memory(void); .org . - (662b-661b) + (664b-663b) .endm +/* + * Begin an alternative code sequence. + * + * The code that follows this macro will be assembled and linked as + * normal. There are no restrictions on this code. + */ +.macro alternative_if_not cap + .pushsection .altinstructions, "a" + altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f + .popsection +661: +.endm + +/* + * Provide the alternative code sequence. + * + * The code that follows this macro is assembled into a special + * section to be used for dynamic patching. Code that follows this + * macro must: + * + * 1. Be exactly the same length (in bytes) as the default code + * sequence. + * + * 2. Not contain a branch target that is used outside of the + * alternative sequence it is defined in (branches into an + * alternative sequence are not fixed up). + */ +.macro alternative_else +662: .pushsection .altinstr_replacement, "ax" +663: +.endm + +/* + * Complete an alternative code sequence. + */ +.macro alternative_endif +664: .popsection + .org . - (664b-663b) + (662b-661b) + .org . - (662b-661b) + (664b-663b) +.endm + #endif /* __ASSEMBLY__ */ #endif /* __ASM_ALTERNATIVE_H */ -- GitLab From 271d35eb77d0f53177b44968417b630d1fee8b99 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Wed, 22 Jul 2015 12:21:02 +0100 Subject: [PATCH 1759/7006] arm64: mm: Adopt new alternative assembler macros Convert the dynamic patching for ARM64_WORKAROUND_CLEAN_CACHE over to the newly added alternative assembler macros. Signed-off-by: Daniel Thompson Signed-off-by: Will Deacon --- arch/arm64/mm/cache.S | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index bdeb5d38c2dd7..eb48d5df4a0f7 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -143,7 +143,12 @@ __dma_clean_range: dcache_line_size x2, x3 sub x3, x2, #1 bic x0, x0, x3 -1: alternative_insn "dc cvac, x0", "dc civac, x0", ARM64_WORKAROUND_CLEAN_CACHE +1: +alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE + dc cvac, x0 +alternative_else + dc civac, x0 +alternative_endif add x0, x0, x2 cmp x0, x1 b.lo 1b -- GitLab From e28cabf12304717b1054d0a02f0850f91e8a2074 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Wed, 22 Jul 2015 12:21:03 +0100 Subject: [PATCH 1760/7006] arm64: kernel: Adopt new alternative assembler macros Convert the dynamic patching for ARM64_WORKAROUND_845719 over to the newly added alternative assembler macros. Signed-off-by: Daniel Thompson Signed-off-by: Will Deacon --- arch/arm64/kernel/entry.S | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index e16351819fed9..d8a523600a4c2 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -122,26 +122,23 @@ ct_user_enter ldr x23, [sp, #S_SP] // load return stack pointer msr sp_el0, x23 - #ifdef CONFIG_ARM64_ERRATUM_845719 - -#undef SEQUENCE_ORG -#undef SEQUENCE_ALT - +alternative_if_not ARM64_WORKAROUND_845719 + nop + nop #ifdef CONFIG_PID_IN_CONTEXTIDR - -#define SEQUENCE_ORG "nop ; nop ; nop" -#define SEQUENCE_ALT "tbz x22, #4, 1f ; mrs x29, contextidr_el1; msr contextidr_el1, x29; 1:" - + nop +#endif +alternative_else + tbz x22, #4, 1f +#ifdef CONFIG_PID_IN_CONTEXTIDR + mrs x29, contextidr_el1 + msr contextidr_el1, x29 #else - -#define SEQUENCE_ORG "nop ; nop" -#define SEQUENCE_ALT "tbz x22, #4, 1f ; msr contextidr_el1, xzr; 1:" - + msr contextidr_el1, xzr #endif - - alternative_insn SEQUENCE_ORG, SEQUENCE_ALT, ARM64_WORKAROUND_845719 - +1: +alternative_endif #endif .endif msr elr_el1, x21 // set up the return data -- GitLab From fc032421ef4a825660fcc4d11672bc2dea202893 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Wed, 22 Jul 2015 12:21:04 +0100 Subject: [PATCH 1761/7006] arm64: kvm: Adopt new alternative assembler macros Convert the dynamic patching for ARM64_HAS_SYSREG_GIC_CPUIF over to the newly added alternative assembler macros. Acked-by: Marc Zyngier Signed-off-by: Daniel Thompson Signed-off-by: Will Deacon --- arch/arm64/kvm/hyp.S | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S index 17a8fb14f428d..10915aaf0b015 100644 --- a/arch/arm64/kvm/hyp.S +++ b/arch/arm64/kvm/hyp.S @@ -810,7 +810,11 @@ * Call into the vgic backend for state saving */ .macro save_vgic_state - alternative_insn "bl __save_vgic_v2_state", "bl __save_vgic_v3_state", ARM64_HAS_SYSREG_GIC_CPUIF +alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF + bl __save_vgic_v2_state +alternative_else + bl __save_vgic_v3_state +alternative_endif mrs x24, hcr_el2 mov x25, #HCR_INT_OVERRIDE neg x25, x25 @@ -827,7 +831,11 @@ orr x24, x24, #HCR_INT_OVERRIDE orr x24, x24, x25 msr hcr_el2, x24 - alternative_insn "bl __restore_vgic_v2_state", "bl __restore_vgic_v3_state", ARM64_HAS_SYSREG_GIC_CPUIF +alternative_if_not ARM64_HAS_SYSREG_GIC_CPUIF + bl __restore_vgic_v2_state +alternative_else + bl __restore_vgic_v3_state +alternative_endif .endm .macro save_timer_state -- GitLab From 870828e57b141eff76a5325f20e4691dd2a599b1 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 21 Jul 2015 13:23:27 +0100 Subject: [PATCH 1762/7006] arm64: kernel: Move config_sctlr_el1 Later patches need config_sctlr_el1 to set/clear bits in the sctlr_el1 register. This patch moves this function into header a file. Acked-by: Catalin Marinas Signed-off-by: James Morse Signed-off-by: Will Deacon --- arch/arm64/include/asm/cputype.h | 3 --- arch/arm64/include/asm/sysreg.h | 12 ++++++++++++ arch/arm64/kernel/armv8_deprecated.c | 11 +---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h index a84ec605bed81..ee6403df9fe4c 100644 --- a/arch/arm64/include/asm/cputype.h +++ b/arch/arm64/include/asm/cputype.h @@ -81,9 +81,6 @@ #define ID_AA64MMFR0_BIGEND(mmfr0) \ (((mmfr0) & ID_AA64MMFR0_BIGEND_MASK) >> ID_AA64MMFR0_BIGEND_SHIFT) -#define SCTLR_EL1_CP15BEN (0x1 << 5) -#define SCTLR_EL1_SED (0x1 << 8) - #ifndef __ASSEMBLY__ /* diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 5c89df0acbcb2..56391fbae1e11 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -20,6 +20,9 @@ #ifndef __ASM_SYSREG_H #define __ASM_SYSREG_H +#define SCTLR_EL1_CP15BEN (0x1 << 5) +#define SCTLR_EL1_SED (0x1 << 8) + #define sys_reg(op0, op1, crn, crm, op2) \ ((((op0)-2)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) @@ -55,6 +58,15 @@ asm( " .endm\n" ); +static inline void config_sctlr_el1(u32 clear, u32 set) +{ + u32 val; + + asm volatile("mrs %0, sctlr_el1" : "=r" (val)); + val &= ~clear; + val |= set; + asm volatile("msr sctlr_el1, %0" : : "r" (val)); +} #endif #endif /* __ASM_SYSREG_H */ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 7922c2e710cad..78d56bff91fd2 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -504,16 +505,6 @@ ret: return 0; } -static inline void config_sctlr_el1(u32 clear, u32 set) -{ - u32 val; - - asm volatile("mrs %0, sctlr_el1" : "=r" (val)); - val &= ~clear; - val |= set; - asm volatile("msr sctlr_el1, %0" : : "r" (val)); -} - static int cp15_barrier_set_hw_mode(bool enable) { if (enable) -- GitLab From 1c0763037f1e1caef739e36e09c6d41ed7b61b2d Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 21 Jul 2015 13:23:28 +0100 Subject: [PATCH 1763/7006] arm64: kernel: Add cpufeature 'enable' callback This patch adds an 'enable()' callback to cpu capability/feature detection, allowing features that require some setup or configuration to get this opportunity once the feature has been detected. Acked-by: Catalin Marinas Signed-off-by: James Morse Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 1 + arch/arm64/kernel/cpufeature.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 9fafa75379976..484fa94253141 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -34,6 +34,7 @@ struct arm64_cpu_capabilities { const char *desc; u16 capability; bool (*matches)(const struct arm64_cpu_capabilities *); + void (*enable)(void); union { struct { /* To be used for erratum handling only */ u32 midr_model; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 5ad86ceac0101..650ffc28bedcf 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -55,6 +55,12 @@ void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, pr_info("%s %s\n", info, caps[i].desc); cpus_set_cap(caps[i].capability); } + + /* second pass allows enable() to consider interacting capabilities */ + for (i = 0; caps[i].desc; i++) { + if (cpus_have_cap(caps[i].capability) && caps[i].enable) + caps[i].enable(); + } } void check_local_cpu_features(void) -- GitLab From 18ffa046c509d0cd011eeea2c0418f2d014771fc Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 21 Jul 2015 13:23:29 +0100 Subject: [PATCH 1764/7006] arm64: kernel: Add min_field_value and use '>=' for feature detection When a new cpu feature is available, the cpu feature bits will have some initial value, which is incremented when the feature is updated. This patch changes 'register_value' to be 'min_field_value', and checks the feature bits value (interpreted as a signed int) is greater than this minimum. Acked-by: Catalin Marinas Signed-off-by: James Morse Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 4 ++-- arch/arm64/kernel/cpufeature.c | 14 +++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 484fa94253141..f595f7ddd43ba 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -42,8 +42,8 @@ struct arm64_cpu_capabilities { }; struct { /* Feature register checking */ - u64 register_mask; - u64 register_value; + int field_pos; + int min_field_value; }; }; }; diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 650ffc28bedcf..74fd0f74b0651 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -22,13 +22,21 @@ #include #include +static bool +feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) +{ + int val = cpuid_feature_extract_field(reg, entry->field_pos); + + return val >= entry->min_field_value; +} + static bool has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry) { u64 val; val = read_cpuid(id_aa64pfr0_el1); - return (val & entry->register_mask) == entry->register_value; + return feature_matches(val, entry); } static const struct arm64_cpu_capabilities arm64_features[] = { @@ -36,8 +44,8 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .desc = "GIC system register CPU interface", .capability = ARM64_HAS_SYSREG_GIC_CPUIF, .matches = has_id_aa64pfr0_feature, - .register_mask = (0xf << 24), - .register_value = (1 << 24), + .field_pos = 24, + .min_field_value = 1, }, {}, }; -- GitLab From 91a5cefa2f98bdd3404c2fba57048c4fa225cc37 Mon Sep 17 00:00:00 2001 From: James Morse Date: Tue, 21 Jul 2015 13:23:30 +0100 Subject: [PATCH 1765/7006] arm64: kernel: Add optional CONFIG_ parameter to ALTERNATIVE() Some uses of ALTERNATIVE() may depend on a feature that is disabled at compile time by a Kconfig option. In this case the unused alternative instructions waste space, and if the original instruction is a nop, it wastes time and space. This patch adds an optional 'config' option to ALTERNATIVE() and alternative_insn that allows the compiler to remove both the original and alternative instructions if the config option is not defined. Suggested-by: Catalin Marinas Acked-by: Catalin Marinas Signed-off-by: James Morse Signed-off-by: Will Deacon --- arch/arm64/include/asm/alternative.h | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index e86681ad0931d..20367882226cf 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -3,6 +3,7 @@ #ifndef __ASSEMBLY__ +#include #include #include #include @@ -40,7 +41,8 @@ void free_alternatives_memory(void); * be fixed in a binutils release posterior to 2.25.51.0.2 (anything * containing commit 4e4d08cf7399b606 or c1baaddf8861). */ -#define ALTERNATIVE(oldinstr, newinstr, feature) \ +#define __ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg_enabled) \ + ".if "__stringify(cfg_enabled)" == 1\n" \ "661:\n\t" \ oldinstr "\n" \ "662:\n" \ @@ -53,7 +55,11 @@ void free_alternatives_memory(void); "664:\n\t" \ ".popsection\n\t" \ ".org . - (664b-663b) + (662b-661b)\n\t" \ - ".org . - (662b-661b) + (664b-663b)\n" + ".org . - (662b-661b) + (664b-663b)\n" \ + ".endif\n" + +#define _ALTERNATIVE_CFG(oldinstr, newinstr, feature, cfg, ...) \ + __ALTERNATIVE_CFG(oldinstr, newinstr, feature, IS_ENABLED(cfg)) #else @@ -65,7 +71,8 @@ void free_alternatives_memory(void); .byte \alt_len .endm -.macro alternative_insn insn1 insn2 cap +.macro alternative_insn insn1, insn2, cap, enable = 1 + .if \enable 661: \insn1 662: .pushsection .altinstructions, "a" altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f @@ -75,6 +82,7 @@ void free_alternatives_memory(void); 664: .popsection .org . - (664b-663b) + (662b-661b) .org . - (662b-661b) + (664b-663b) + .endif .endm /* @@ -118,6 +126,20 @@ void free_alternatives_memory(void); .org . - (662b-661b) + (664b-663b) .endm +#define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...) \ + alternative_insn insn1, insn2, cap, IS_ENABLED(cfg) + + #endif /* __ASSEMBLY__ */ +/* + * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature)); + * + * Usage: asm(ALTERNATIVE(oldinstr, newinstr, feature, CONFIG_FOO)); + * N.B. If CONFIG_FOO is specified, but not selected, the whole block + * will be omitted, including oldinstr. + */ +#define ALTERNATIVE(oldinstr, newinstr, ...) \ + _ALTERNATIVE_CFG(oldinstr, newinstr, __VA_ARGS__, 1) + #endif /* __ASM_ALTERNATIVE_H */ -- GitLab From 9ded63aaf83eba76e1a54ac02581c2badc497f1a Mon Sep 17 00:00:00 2001 From: "Suzuki K. Poulose" Date: Wed, 22 Jul 2015 11:38:14 +0100 Subject: [PATCH 1766/7006] arm64: Generalise msr_s/mrs_s operations The system register encoding generated by sys_reg() works only for MRS/MSR(Register) operations, as we hardcode Bit20 to 1 in mrs_s/msr_s mask. This makes it unusable for generating instructions accessing registers with Op0 < 2(e.g, PSTATE.x with Op0=0). As per ARMv8 ARM, (Ref: ARMv8 ARM, Section: "System instruction class encoding overview", C5.2, version:ARM DDI 0487A.f), the instruction encoding reserves bits [20-19] for Op0. This patch generalises the sys_reg, mrs_s and msr_s macros, so that we could use them to access any of the supported system register. Cc: James Morse Cc: Catalin Marinas Signed-off-by: Suzuki K. Poulose Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/sysreg.h | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 56391fbae1e11..5295bcbcb3746 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -23,8 +23,18 @@ #define SCTLR_EL1_CP15BEN (0x1 << 5) #define SCTLR_EL1_SED (0x1 << 8) +/* + * ARMv8 ARM reserves the following encoding for system registers: + * (Ref: ARMv8 ARM, Section: "System instruction class encoding overview", + * C5.2, version:ARM DDI 0487A.f) + * [20-19] : Op0 + * [18-16] : Op1 + * [15-12] : CRn + * [11-8] : CRm + * [7-5] : Op2 + */ #define sys_reg(op0, op1, crn, crm, op2) \ - ((((op0)-2)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) + ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) #ifdef __ASSEMBLY__ @@ -34,11 +44,11 @@ .equ __reg_num_xzr, 31 .macro mrs_s, rt, sreg - .inst 0xd5300000|(\sreg)|(__reg_num_\rt) + .inst 0xd5200000|(\sreg)|(__reg_num_\rt) .endm .macro msr_s, sreg, rt - .inst 0xd5100000|(\sreg)|(__reg_num_\rt) + .inst 0xd5000000|(\sreg)|(__reg_num_\rt) .endm #else @@ -50,11 +60,11 @@ asm( " .equ __reg_num_xzr, 31\n" "\n" " .macro mrs_s, rt, sreg\n" -" .inst 0xd5300000|(\\sreg)|(__reg_num_\\rt)\n" +" .inst 0xd5200000|(\\sreg)|(__reg_num_\\rt)\n" " .endm\n" "\n" " .macro msr_s, sreg, rt\n" -" .inst 0xd5100000|(\\sreg)|(__reg_num_\\rt)\n" +" .inst 0xd5000000|(\\sreg)|(__reg_num_\\rt)\n" " .endm\n" ); -- GitLab From 338d4f49d6f7114a017d294ccf7374df4f998edc Mon Sep 17 00:00:00 2001 From: James Morse Date: Wed, 22 Jul 2015 19:05:54 +0100 Subject: [PATCH 1767/7006] arm64: kernel: Add support for Privileged Access Never 'Privileged Access Never' is a new arm8.1 feature which prevents privileged code from accessing any virtual address where read or write access is also permitted at EL0. This patch enables the PAN feature on all CPUs, and modifies {get,put}_user helpers temporarily to permit access. This will catch kernel bugs where user memory is accessed directly. 'Unprivileged loads and stores' using ldtrb et al are unaffected by PAN. Reviewed-by: Catalin Marinas Signed-off-by: James Morse [will: use ALTERNATIVE in asm and tidy up pan_enable check] Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 14 ++++++++++++++ arch/arm64/include/asm/cpufeature.h | 3 ++- arch/arm64/include/asm/futex.h | 8 ++++++++ arch/arm64/include/asm/processor.h | 2 ++ arch/arm64/include/asm/sysreg.h | 8 ++++++++ arch/arm64/include/asm/uaccess.h | 11 +++++++++++ arch/arm64/include/uapi/asm/ptrace.h | 1 + arch/arm64/kernel/armv8_deprecated.c | 8 +++++++- arch/arm64/kernel/cpufeature.c | 20 ++++++++++++++++++++ arch/arm64/lib/clear_user.S | 8 ++++++++ arch/arm64/lib/copy_from_user.S | 8 ++++++++ arch/arm64/lib/copy_in_user.S | 8 ++++++++ arch/arm64/lib/copy_to_user.S | 8 ++++++++ arch/arm64/mm/fault.c | 16 ++++++++++++++++ 14 files changed, 121 insertions(+), 2 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index de8dee60fd825..c2bd79a02a6ca 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -596,6 +596,20 @@ config FORCE_MAX_ZONEORDER default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE) default "11" +config ARM64_PAN + bool "Enable support for Privileged Access Never (PAN)" + default y + help + Privileged Access Never (PAN; part of the ARMv8.1 Extensions) + prevents the kernel or hypervisor from accessing user-space (EL0) + memory directly. + + Choosing this option will cause any unprotected (not using + copy_to_user et al) memory access to fail with a permission fault. + + The feature is detected at runtime, and will remain as a 'nop' + instruction if the cpu does not implement the feature. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index f595f7ddd43ba..d71140b76773b 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -25,8 +25,9 @@ #define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1 #define ARM64_WORKAROUND_845719 2 #define ARM64_HAS_SYSREG_GIC_CPUIF 3 +#define ARM64_HAS_PAN 4 -#define ARM64_NCAPS 4 +#define ARM64_NCAPS 5 #ifndef __ASSEMBLY__ diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 74069b3bd919c..775e85b9d1f25 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -20,10 +20,16 @@ #include #include + +#include +#include #include +#include #define __futex_atomic_op(insn, ret, oldval, uaddr, tmp, oparg) \ asm volatile( \ + ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ "1: ldxr %w1, %2\n" \ insn "\n" \ "2: stlxr %w3, %w0, %2\n" \ @@ -39,6 +45,8 @@ " .align 3\n" \ " .quad 1b, 4b, 2b, 4b\n" \ " .popsection\n" \ + ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp) \ : "r" (oparg), "Ir" (-EFAULT) \ : "memory") diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index e4c893e54f01a..98f32355dc972 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -186,4 +186,6 @@ static inline void spin_lock_prefetch(const void *x) #endif +void cpu_enable_pan(void); + #endif /* __ASM_PROCESSOR_H */ diff --git a/arch/arm64/include/asm/sysreg.h b/arch/arm64/include/asm/sysreg.h index 5295bcbcb3746..a7f3d4b2514d6 100644 --- a/arch/arm64/include/asm/sysreg.h +++ b/arch/arm64/include/asm/sysreg.h @@ -20,6 +20,8 @@ #ifndef __ASM_SYSREG_H #define __ASM_SYSREG_H +#include + #define SCTLR_EL1_CP15BEN (0x1 << 5) #define SCTLR_EL1_SED (0x1 << 8) @@ -36,6 +38,12 @@ #define sys_reg(op0, op1, crn, crm, op2) \ ((((op0)&3)<<19)|((op1)<<16)|((crn)<<12)|((crm)<<8)|((op2)<<5)) +#define REG_PSTATE_PAN_IMM sys_reg(0, 0, 4, 0, 4) +#define SCTLR_EL1_SPAN (1 << 23) + +#define SET_PSTATE_PAN(x) __inst_arm(0xd5000000 | REG_PSTATE_PAN_IMM |\ + (!!x)<<8 | 0x1f) + #ifdef __ASSEMBLY__ .irp num,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30 diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 07e1ba449bf1e..b2ede967fe7d4 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -24,7 +24,10 @@ #include #include +#include +#include #include +#include #include #include #include @@ -131,6 +134,8 @@ static inline void set_fs(mm_segment_t fs) do { \ unsigned long __gu_val; \ __chk_user_ptr(ptr); \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ switch (sizeof(*(ptr))) { \ case 1: \ __get_user_asm("ldrb", "%w", __gu_val, (ptr), (err)); \ @@ -148,6 +153,8 @@ do { \ BUILD_BUG(); \ } \ (x) = (__force __typeof__(*(ptr)))__gu_val; \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ } while (0) #define __get_user(x, ptr) \ @@ -194,6 +201,8 @@ do { \ do { \ __typeof__(*(ptr)) __pu_val = (x); \ __chk_user_ptr(ptr); \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ switch (sizeof(*(ptr))) { \ case 1: \ __put_user_asm("strb", "%w", __pu_val, (ptr), (err)); \ @@ -210,6 +219,8 @@ do { \ default: \ BUILD_BUG(); \ } \ + asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN)); \ } while (0) #define __put_user(x, ptr) \ diff --git a/arch/arm64/include/uapi/asm/ptrace.h b/arch/arm64/include/uapi/asm/ptrace.h index 6913643bbe54e..208db3df135a4 100644 --- a/arch/arm64/include/uapi/asm/ptrace.h +++ b/arch/arm64/include/uapi/asm/ptrace.h @@ -44,6 +44,7 @@ #define PSR_I_BIT 0x00000080 #define PSR_A_BIT 0x00000100 #define PSR_D_BIT 0x00000200 +#define PSR_PAN_BIT 0x00400000 #define PSR_Q_BIT 0x08000000 #define PSR_V_BIT 0x10000000 #define PSR_C_BIT 0x20000000 diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 78d56bff91fd2..bcee7abac68eb 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include #include @@ -280,6 +282,8 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) */ #define __user_swpX_asm(data, addr, res, temp, B) \ __asm__ __volatile__( \ + ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ " mov %w2, %w1\n" \ "0: ldxr"B" %w1, [%3]\n" \ "1: stxr"B" %w0, %w2, [%3]\n" \ @@ -295,7 +299,9 @@ static void register_insn_emulation_sysctl(struct ctl_table *table) " .align 3\n" \ " .quad 0b, 3b\n" \ " .quad 1b, 3b\n" \ - " .popsection" \ + " .popsection\n" \ + ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) \ : "=&r" (res), "+r" (data), "=&r" (temp) \ : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \ : "memory") diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 74fd0f74b0651..978fa169d3c31 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -21,6 +21,7 @@ #include #include #include +#include static bool feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) @@ -39,6 +40,15 @@ has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry) return feature_matches(val, entry); } +static bool __maybe_unused +has_id_aa64mmfr1_feature(const struct arm64_cpu_capabilities *entry) +{ + u64 val; + + val = read_cpuid(id_aa64mmfr1_el1); + return feature_matches(val, entry); +} + static const struct arm64_cpu_capabilities arm64_features[] = { { .desc = "GIC system register CPU interface", @@ -47,6 +57,16 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .field_pos = 24, .min_field_value = 1, }, +#ifdef CONFIG_ARM64_PAN + { + .desc = "Privileged Access Never", + .capability = ARM64_HAS_PAN, + .matches = has_id_aa64mmfr1_feature, + .field_pos = 20, + .min_field_value = 1, + .enable = cpu_enable_pan, + }, +#endif /* CONFIG_ARM64_PAN */ {}, }; diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index c17967fdf5f60..a9723c71c52b2 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -16,7 +16,11 @@ * along with this program. If not, see . */ #include + +#include #include +#include +#include .text @@ -29,6 +33,8 @@ * Alignment fixed up by hardware. */ ENTRY(__clear_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) mov x2, x1 // save the size for fixup return subs x1, x1, #8 b.mi 2f @@ -48,6 +54,8 @@ USER(9f, strh wzr, [x0], #2 ) b.mi 5f USER(9f, strb wzr, [x0] ) 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__clear_user) diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index 47c3fa5ae4ae6..1be9ef27be970 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -15,7 +15,11 @@ */ #include + +#include #include +#include +#include /* * Copy from user space to a kernel buffer (alignment handled by the hardware) @@ -28,6 +32,8 @@ * x0 - bytes not copied */ ENTRY(__copy_from_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) add x5, x1, x2 // upper user buffer boundary subs x2, x2, #16 b.mi 1f @@ -56,6 +62,8 @@ USER(9f, ldrh w3, [x1], #2 ) USER(9f, ldrb w3, [x1] ) strb w3, [x0] 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__copy_from_user) diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index 436bcc5d77b50..1b94661e22b3f 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -17,7 +17,11 @@ */ #include + +#include #include +#include +#include /* * Copy from user space to user space (alignment handled by the hardware) @@ -30,6 +34,8 @@ * x0 - bytes not copied */ ENTRY(__copy_in_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) add x5, x0, x2 // upper user buffer boundary subs x2, x2, #16 b.mi 1f @@ -58,6 +64,8 @@ USER(9f, strh w3, [x0], #2 ) USER(9f, ldrb w3, [x1] ) USER(9f, strb w3, [x0] ) 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__copy_in_user) diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index f5e1f526f408c..a257b47e2dc49 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -15,7 +15,11 @@ */ #include + +#include #include +#include +#include /* * Copy to user space from a kernel buffer (alignment handled by the hardware) @@ -28,6 +32,8 @@ * x0 - bytes not copied */ ENTRY(__copy_to_user) +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(0)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) add x5, x0, x2 // upper user buffer boundary subs x2, x2, #16 b.mi 1f @@ -56,6 +62,8 @@ USER(9f, strh w3, [x0], #2 ) ldrb w3, [x1] USER(9f, strb w3, [x0] ) 5: mov x0, #0 +ALTERNATIVE("nop", __stringify(SET_PSTATE_PAN(1)), ARM64_HAS_PAN, \ + CONFIG_ARM64_PAN) ret ENDPROC(__copy_to_user) diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index 94d98cd1aad8a..ce591211434e6 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -30,9 +30,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -223,6 +225,13 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr, mm_flags |= FAULT_FLAG_WRITE; } + /* + * PAN bit set implies the fault happened in kernel space, but not + * in the arch's user access functions. + */ + if (IS_ENABLED(CONFIG_ARM64_PAN) && (regs->pstate & PSR_PAN_BIT)) + goto no_context; + /* * As per x86, we may deadlock here. However, since the kernel only * validly references user space from well defined areas of the code, @@ -536,3 +545,10 @@ asmlinkage int __exception do_debug_exception(unsigned long addr, return 0; } + +#ifdef CONFIG_ARM64_PAN +void cpu_enable_pan(void) +{ + config_sctlr_el1(SCTLR_EL1_SPAN, 0); +} +#endif /* CONFIG_ARM64_PAN */ -- GitLab From 77ee306c0aea9a219daec256ad25982944affef8 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 23 Jul 2015 13:51:46 +0100 Subject: [PATCH 1768/7006] arm64: alternatives: add enable parameter to conditional asm macros There are cases where we want to compile out both versions of an alternative code block, so add an enable parameter to the new conditional alternative assembly macros in the same way as alternative_insn. Signed-off-by: Will Deacon --- arch/arm64/include/asm/alternative.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h index 20367882226cf..b474e9106bc27 100644 --- a/arch/arm64/include/asm/alternative.h +++ b/arch/arm64/include/asm/alternative.h @@ -91,11 +91,13 @@ void free_alternatives_memory(void); * The code that follows this macro will be assembled and linked as * normal. There are no restrictions on this code. */ -.macro alternative_if_not cap +.macro alternative_if_not cap, enable = 1 + .if \enable .pushsection .altinstructions, "a" altinstruction_entry 661f, 663f, \cap, 662f-661f, 664f-663f .popsection 661: + .endif .endm /* @@ -112,18 +114,22 @@ void free_alternatives_memory(void); * alternative sequence it is defined in (branches into an * alternative sequence are not fixed up). */ -.macro alternative_else +.macro alternative_else, enable = 1 + .if \enable 662: .pushsection .altinstr_replacement, "ax" 663: + .endif .endm /* * Complete an alternative code sequence. */ -.macro alternative_endif +.macro alternative_endif, enable = 1 + .if \enable 664: .popsection .org . - (664b-663b) + (662b-661b) .org . - (662b-661b) + (664b-663b) + .endif .endm #define _ALTERNATIVE_CFG(insn1, insn2, cap, cfg, ...) \ -- GitLab From e094d44568680d4e5e2722c4ad090ff0810719b9 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 23 Jul 2015 18:28:26 +0100 Subject: [PATCH 1769/7006] arm64: kernel: remove non-legit DT warnings when booting using ACPI Since both CONFIG_ACPI and CONFIG_OF are enabled when booting using ACPI tables on ARM64 platforms, we get few device tree warnings which are not valid for ACPI boot. We can use of_have_populated_dt to check if the device tree is populated or not before throwing out those errors. This patch uses of_have_populated_dt to remove non legitimate device tree warning when booting using ACPI tables. Cc: Lorenzo Pieralisi Acked-by: Catalin Marinas Acked-by: Mark Rutland Signed-off-by: Sudeep Holla Signed-off-by: Will Deacon --- arch/arm64/kernel/setup.c | 9 +++++++-- arch/arm64/kernel/topology.c | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index cf609cf3fcb51..e7a1e719f1272 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -423,8 +423,13 @@ void __init setup_arch(char **cmdline_p) static int __init arm64_device_init(void) { - of_iommu_init(); - of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); + if (of_have_populated_dt()) { + of_iommu_init(); + of_platform_populate(NULL, of_default_bus_match_table, + NULL, NULL); + } else if (acpi_disabled) { + pr_crit("Device tree not populated\n"); + } return 0; } arch_initcall_sync(arm64_device_init); diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c index fcb8f7b42271c..694f6deedbab8 100644 --- a/arch/arm64/kernel/topology.c +++ b/arch/arm64/kernel/topology.c @@ -300,6 +300,6 @@ void __init init_cpu_topology(void) * Discard anything that was parsed if we hit an error so we * don't use partial information. */ - if (parse_dt_topology()) + if (of_have_populated_dt() && parse_dt_topology()) reset_cpu_topology(); } -- GitLab From e38457c361b30c5a2379cc767877c3e5c2505dc6 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 24 Jul 2015 12:38:27 +0100 Subject: [PATCH 1770/7006] arm64: efi: prefer AllocatePages() over efi_low_alloc() for vmlinux When allocating memory for the kernel image, try the AllocatePages() boot service to obtain memory at the preferred offset of 'dram_base + TEXT_OFFSET', and only revert to efi_low_alloc() if that fails. This is the only way to allocate at the base of DRAM if DRAM starts at 0x0, since efi_low_alloc() refuses to allocate at 0x0. Tested-by: Haojian Zhuang Reviewed-by: Mark Rutland Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/kernel/efi-stub.c | 41 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/arch/arm64/kernel/efi-stub.c b/arch/arm64/kernel/efi-stub.c index f5374065ad535..816120ece6bce 100644 --- a/arch/arm64/kernel/efi-stub.c +++ b/arch/arm64/kernel/efi-stub.c @@ -13,7 +13,7 @@ #include #include -efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table, +efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table_arg, unsigned long *image_addr, unsigned long *image_size, unsigned long *reserve_addr, @@ -23,21 +23,44 @@ efi_status_t __init handle_kernel_image(efi_system_table_t *sys_table, { efi_status_t status; unsigned long kernel_size, kernel_memsize = 0; + unsigned long nr_pages; + void *old_image_addr = (void *)*image_addr; /* Relocate the image, if required. */ kernel_size = _edata - _text; if (*image_addr != (dram_base + TEXT_OFFSET)) { kernel_memsize = kernel_size + (_end - _edata); - status = efi_low_alloc(sys_table, kernel_memsize + TEXT_OFFSET, - SZ_2M, reserve_addr); + + /* + * First, try a straight allocation at the preferred offset. + * This will work around the issue where, if dram_base == 0x0, + * efi_low_alloc() refuses to allocate at 0x0 (to prevent the + * address of the allocation to be mistaken for a FAIL return + * value or a NULL pointer). It will also ensure that, on + * platforms where the [dram_base, dram_base + TEXT_OFFSET) + * interval is partially occupied by the firmware (like on APM + * Mustang), we can still place the kernel at the address + * 'dram_base + TEXT_OFFSET'. + */ + *image_addr = *reserve_addr = dram_base + TEXT_OFFSET; + nr_pages = round_up(kernel_memsize, EFI_ALLOC_ALIGN) / + EFI_PAGE_SIZE; + status = efi_call_early(allocate_pages, EFI_ALLOCATE_ADDRESS, + EFI_LOADER_DATA, nr_pages, + (efi_physical_addr_t *)reserve_addr); if (status != EFI_SUCCESS) { - pr_efi_err(sys_table, "Failed to relocate kernel\n"); - return status; + kernel_memsize += TEXT_OFFSET; + status = efi_low_alloc(sys_table_arg, kernel_memsize, + SZ_2M, reserve_addr); + + if (status != EFI_SUCCESS) { + pr_efi_err(sys_table_arg, "Failed to relocate kernel\n"); + return status; + } + *image_addr = *reserve_addr + TEXT_OFFSET; } - memcpy((void *)*reserve_addr + TEXT_OFFSET, (void *)*image_addr, - kernel_size); - *image_addr = *reserve_addr + TEXT_OFFSET; - *reserve_size = kernel_memsize + TEXT_OFFSET; + memcpy((void *)*image_addr, old_image_addr, kernel_size); + *reserve_size = kernel_memsize; } -- GitLab From 51650dc2a18b1c65026c3bb9e35da2750e985706 Mon Sep 17 00:00:00 2001 From: yalin wang Date: Fri, 24 Jul 2015 12:52:28 +0100 Subject: [PATCH 1771/7006] arm64: insn: use set_fixmap_offset to make it more clear A little change to patch_map() function, use set_fixmap_offset() to make code more clear. Signed-off-by: yalin wang Signed-off-by: Will Deacon --- arch/arm64/kernel/insn.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c index dd9671cd0bb25..f341866aa8103 100644 --- a/arch/arm64/kernel/insn.c +++ b/arch/arm64/kernel/insn.c @@ -101,9 +101,8 @@ static void __kprobes *patch_map(void *addr, int fixmap) return addr; BUG_ON(!page); - set_fixmap(fixmap, page_to_phys(page)); - - return (void *) (__fix_to_virt(fixmap) + (uintaddr & ~PAGE_MASK)); + return (void *)set_fixmap_offset(fixmap, page_to_phys(page) + + (uintaddr & ~PAGE_MASK)); } static void __kprobes patch_unmap(int fixmap) -- GitLab From 951757ae83ec611b1c4f1dcfda67246cf5157451 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:41 +0100 Subject: [PATCH 1772/7006] arm64/debug: Eliminate magic number for size of BRK instruction The size of an A64 BRK instruction is the same as the size of all other A64 instructions, because all A64 instructions are the same size. BREAK_INSTR_SIZE is retained for readibility, but it should not be an independent constant from AARCH64_INSN_SIZE. Signed-off-by: Dave Martin Acked-by: Mark Rutland Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 40ec68aa68701..f3d2dbd5f0a72 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -18,6 +18,8 @@ #ifdef __KERNEL__ +#include + /* Low-level stepping controls. */ #define DBG_MDSCR_SS (1 << 0) #define DBG_SPSR_SS (1 << 21) @@ -38,7 +40,7 @@ /* * Break point instruction encoding */ -#define BREAK_INSTR_SIZE 4 +#define BREAK_INSTR_SIZE AARCH64_INSN_SIZE /* * ESR values expected for dynamic and compile time BRK instruction -- GitLab From dfac68314c969481fcce3dd528728dfa9d85caf5 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:42 +0100 Subject: [PATCH 1773/7006] arm64/debug: Mask off all reserved bits from generated ESR values There are only 16 comment bits in a BRK instruction, which correspond to ESR bits 15:0. Bits 24:16 of the ESR are RES0, and might have weird meanings in the future. This code inserts 16 bits of comment in the ESR value instead of 20 (almost certainly a typo in the original code). Signed-off-by: Dave Martin Acked-by: Mark Rutland Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index f3d2dbd5f0a72..ab7d5a875f8db 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -45,7 +45,7 @@ /* * ESR values expected for dynamic and compile time BRK instruction */ -#define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xfffff)) +#define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xffff)) /* * #imm16 values used for BRK instruction generation -- GitLab From 03923696a966bd3eeb3a169d71b8a337aaa5ab76 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:43 +0100 Subject: [PATCH 1774/7006] arm64/debug: Eliminate magic number from ESR template definition has perfectly good constants for defining ESR values already. Let's use them. Signed-off-by: Dave Martin Acked-by: Mark Rutland Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index ab7d5a875f8db..ff09058587e30 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -18,6 +18,7 @@ #ifdef __KERNEL__ +#include #include /* Low-level stepping controls. */ @@ -45,7 +46,8 @@ /* * ESR values expected for dynamic and compile time BRK instruction */ -#define DBG_ESR_VAL_BRK(x) (0xf2000000 | ((x) & 0xffff)) +#define DBG_ESR_VAL_BRK(x) \ + ((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL | ((x) & 0xffff)) /* * #imm16 values used for BRK instruction generation -- GitLab From c172d994e1fd57e46e85424c23124756c66d4b62 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:44 +0100 Subject: [PATCH 1775/7006] arm64/debug: More consistent naming for the BRK ESR template macro The naming of DBG_ESR_VAL_BRK is inconsistent with the way other similar macros are named. This patch makes the naming more consistent, and appends "64" as a reminder that this ESR pattern only matches from AArch64 state. Signed-off-by: Dave Martin Acked-by: Mark Rutland Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 5 +++-- arch/arm64/kernel/kgdb.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index ff09058587e30..bb97e9d88d23a 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -46,8 +46,9 @@ /* * ESR values expected for dynamic and compile time BRK instruction */ -#define DBG_ESR_VAL_BRK(x) \ - ((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL | ((x) & 0xffff)) +#define ESR_ELx_VAL_BRK64(imm) \ + ((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL | \ + ((imm) & 0xffff)) /* * #imm16 values used for BRK instruction generation diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c index a0d10c55f307a..a5a838e72c5ea 100644 --- a/arch/arm64/kernel/kgdb.c +++ b/arch/arm64/kernel/kgdb.c @@ -235,13 +235,13 @@ static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr) static struct break_hook kgdb_brkpt_hook = { .esr_mask = 0xffffffff, - .esr_val = DBG_ESR_VAL_BRK(KGDB_DYN_DBG_BRK_IMM), + .esr_val = ESR_ELx_VAL_BRK64(KGDB_DYN_DBG_BRK_IMM), .fn = kgdb_brk_fn }; static struct break_hook kgdb_compiled_brkpt_hook = { .esr_mask = 0xffffffff, - .esr_val = DBG_ESR_VAL_BRK(KGDB_COMPILED_DBG_BRK_IMM), + .esr_val = ESR_ELx_VAL_BRK64(KGDB_COMPILED_DBG_BRK_IMM), .fn = kgdb_compiled_brk_fn }; -- GitLab From 72d033e80a6f25a7e2f79cacac202f19ede289e4 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:45 +0100 Subject: [PATCH 1776/7006] arm64/debug: Move BRK ESR template macro into It makes sense to keep all the architectural exception syndrome definitions in the same place. Signed-off-by: Dave Martin Acked-by: Mark Rutland Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 7 ------- arch/arm64/include/asm/esr.h | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index bb97e9d88d23a..e28b1ddf22b93 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -43,13 +43,6 @@ */ #define BREAK_INSTR_SIZE AARCH64_INSN_SIZE -/* - * ESR values expected for dynamic and compile time BRK instruction - */ -#define ESR_ELx_VAL_BRK64(imm) \ - ((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL | \ - ((imm) & 0xffff)) - /* * #imm16 values used for BRK instruction generation * Allowed values for kgbd are 0x400 - 0x7ff diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 70522450ca234..1b44cf6be4b57 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -99,6 +99,13 @@ #define ESR_ELx_WFx_ISS_WFE (UL(1) << 0) #define ESR_ELx_xVC_IMM_MASK ((1UL << 16) - 1) +/* ESR value templates for specific events */ + +/* BRK instruction trap from AArch64 state */ +#define ESR_ELx_VAL_BRK64(imm) \ + ((ESR_ELx_EC_BRK64 << ESR_ELx_EC_SHIFT) | ESR_ELx_IL | \ + ((imm) & 0xffff)) + #ifndef __ASSEMBLY__ #include -- GitLab From c696b93461f53db89d61450ace7c73babf920b99 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:46 +0100 Subject: [PATCH 1777/7006] arm64/debug: Simplify BRK insn opcode declarations The way the KGDB_DYN_BRK_INS_BYTEx macros are declared is more complex than it needs to be. Also, the macros are only used in one place, which is arch-specific anyway. This patch refactors the macros to simplify them, and exposes an argument so that we can have a single macro instead of 4. As a side effect, this patch also fixes some anomalous spellings of "KGDB". These changes alter the compile types of some integer constants that are harmless but trigger truncation warnings in gcc when assigning to 32-bit variables. This patch adds an explicit cast for the affected cases. Signed-off-by: Dave Martin Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 23 ++++------------------- arch/arm64/kernel/kgdb.c | 12 ++++++------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index e28b1ddf22b93..6a17fb8a16d1b 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -66,25 +66,10 @@ */ #define AARCH64_BREAK_FAULT (AARCH64_BREAK_MON | (FAULT_BRK_IMM << 5)) -/* - * Extract byte from BRK instruction - */ -#define KGDB_DYN_DBG_BRK_INS_BYTE(x) \ - ((((AARCH64_BREAK_MON) & 0xffe0001f) >> (x * 8)) & 0xff) - -/* - * Extract byte from BRK #imm16 - */ -#define KGBD_DYN_DBG_BRK_IMM_BYTE(x) \ - (((((KGDB_DYN_DBG_BRK_IMM) & 0xffff) << 5) >> (x * 8)) & 0xff) - -#define KGDB_DYN_DBG_BRK_BYTE(x) \ - (KGDB_DYN_DBG_BRK_INS_BYTE(x) | KGBD_DYN_DBG_BRK_IMM_BYTE(x)) - -#define KGDB_DYN_BRK_INS_BYTE0 KGDB_DYN_DBG_BRK_BYTE(0) -#define KGDB_DYN_BRK_INS_BYTE1 KGDB_DYN_DBG_BRK_BYTE(1) -#define KGDB_DYN_BRK_INS_BYTE2 KGDB_DYN_DBG_BRK_BYTE(2) -#define KGDB_DYN_BRK_INS_BYTE3 KGDB_DYN_DBG_BRK_BYTE(3) +#define AARCH64_BREAK_KGDB_DYN_DBG \ + (AARCH64_BREAK_MON | (KGDB_DYN_DBG_BRK_IMM << 5)) +#define KGDB_DYN_BRK_INS_BYTE(x) \ + ((AARCH64_BREAK_KGDB_DYN_DBG >> (8 * (x))) & 0xff) #define CACHE_FLUSH_IS_SAFE 1 diff --git a/arch/arm64/kernel/kgdb.c b/arch/arm64/kernel/kgdb.c index a5a838e72c5ea..bcac81e600b9a 100644 --- a/arch/arm64/kernel/kgdb.c +++ b/arch/arm64/kernel/kgdb.c @@ -235,13 +235,13 @@ static int kgdb_step_brk_fn(struct pt_regs *regs, unsigned int esr) static struct break_hook kgdb_brkpt_hook = { .esr_mask = 0xffffffff, - .esr_val = ESR_ELx_VAL_BRK64(KGDB_DYN_DBG_BRK_IMM), + .esr_val = (u32)ESR_ELx_VAL_BRK64(KGDB_DYN_DBG_BRK_IMM), .fn = kgdb_brk_fn }; static struct break_hook kgdb_compiled_brkpt_hook = { .esr_mask = 0xffffffff, - .esr_val = ESR_ELx_VAL_BRK64(KGDB_COMPILED_DBG_BRK_IMM), + .esr_val = (u32)ESR_ELx_VAL_BRK64(KGDB_COMPILED_DBG_BRK_IMM), .fn = kgdb_compiled_brk_fn }; @@ -328,9 +328,9 @@ void kgdb_arch_exit(void) */ struct kgdb_arch arch_kgdb_ops = { .gdb_bpt_instr = { - KGDB_DYN_BRK_INS_BYTE0, - KGDB_DYN_BRK_INS_BYTE1, - KGDB_DYN_BRK_INS_BYTE2, - KGDB_DYN_BRK_INS_BYTE3, + KGDB_DYN_BRK_INS_BYTE(0), + KGDB_DYN_BRK_INS_BYTE(1), + KGDB_DYN_BRK_INS_BYTE(2), + KGDB_DYN_BRK_INS_BYTE(3), } }; -- GitLab From d7a33f4fbd12ca0a32a24cc46c0d02b47f6b54d1 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:47 +0100 Subject: [PATCH 1778/7006] arm64/debug: Add missing #includes relies on , but doesn't declare this dependency. This becomes a problem once debug-monitors.h starts getting included all over the place to get the BRK immedates. The missing include of (for UL()) in is also added. The series no longer relies on this, but I spotted it during development and it may as well get fixed. No functional change. Signed-off-by: Dave Martin Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 3 +++ arch/arm64/include/asm/esr.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 6a17fb8a16d1b..777c36a1f645c 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -18,8 +18,11 @@ #ifdef __KERNEL__ +#include +#include #include #include +#include /* Low-level stepping controls. */ #define DBG_MDSCR_SS (1 << 0) diff --git a/arch/arm64/include/asm/esr.h b/arch/arm64/include/asm/esr.h index 1b44cf6be4b57..77eeb2cc648fd 100644 --- a/arch/arm64/include/asm/esr.h +++ b/arch/arm64/include/asm/esr.h @@ -18,6 +18,8 @@ #ifndef __ASM_ESR_H #define __ASM_ESR_H +#include + #define ESR_ELx_EC_UNKNOWN (0x00) #define ESR_ELx_EC_WFx (0x01) /* Unallocated EC: 0x02 */ -- GitLab From 9fb7410f955f7a62c1f882ca8f9ffd4525907e28 Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:48 +0100 Subject: [PATCH 1779/7006] arm64/BUG: Use BRK instruction for generic BUG traps Currently, the minimal default BUG() implementation from asm- generic is used for arm64. This patch uses the BRK software breakpoint instruction to generate a trap instead, similarly to most other arches, with the generic BUG code generating the dmesg boilerplate. This allows bug metadata to be moved to a separate table and reduces the amount of inline code at BUG and WARN sites. This also avoids clobbering any registers before they can be dumped. To mitigate the size of the bug table further, this patch makes use of the existing infrastructure for encoding addresses within the bug table as 32-bit offsets instead of absolute pointers. (Note that this limits the kernel size to 2GB.) Traps are registered at arch_initcall time for aarch64, but BUG has minimal real dependencies and it is desirable to be able to generate bug splats as early as possible. This patch redirects all debug exceptions caused by BRK directly to bug_handler() until the full debug exception support has been initialised. Signed-off-by: Dave Martin Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 8 ++++ arch/arm64/include/asm/bug.h | 64 +++++++++++++++++++++++++ arch/arm64/include/asm/debug-monitors.h | 2 + arch/arm64/kernel/traps.c | 59 ++++++++++++++++++++++- arch/arm64/mm/fault.c | 12 ++++- 5 files changed, 142 insertions(+), 3 deletions(-) create mode 100644 arch/arm64/include/asm/bug.h diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index c2bd79a02a6ca..5372e1e0c11c4 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -113,6 +113,14 @@ config TRACE_IRQFLAGS_SUPPORT config RWSEM_XCHGADD_ALGORITHM def_bool y +config GENERIC_BUG + def_bool y + depends on BUG + +config GENERIC_BUG_RELATIVE_POINTERS + def_bool y + depends on GENERIC_BUG + config GENERIC_HWEIGHT def_bool y diff --git a/arch/arm64/include/asm/bug.h b/arch/arm64/include/asm/bug.h new file mode 100644 index 0000000000000..4a748ce9ba1a7 --- /dev/null +++ b/arch/arm64/include/asm/bug.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2015 ARM Limited + * Author: Dave Martin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ARCH_ARM64_ASM_BUG_H +#define _ARCH_ARM64_ASM_BUG_H + +#include + +#ifdef CONFIG_GENERIC_BUG +#define HAVE_ARCH_BUG + +#ifdef CONFIG_DEBUG_BUGVERBOSE +#define _BUGVERBOSE_LOCATION(file, line) __BUGVERBOSE_LOCATION(file, line) +#define __BUGVERBOSE_LOCATION(file, line) \ + ".pushsection .rodata.str,\"aMS\",@progbits,1\n" \ + "2: .string \"" file "\"\n\t" \ + ".popsection\n\t" \ + \ + ".long 2b - 0b\n\t" \ + ".short " #line "\n\t" +#else +#define _BUGVERBOSE_LOCATION(file, line) +#endif + +#define _BUG_FLAGS(flags) __BUG_FLAGS(flags) + +#define __BUG_FLAGS(flags) asm volatile ( \ + ".pushsection __bug_table,\"a\"\n\t" \ + ".align 2\n\t" \ + "0: .long 1f - 0b\n\t" \ +_BUGVERBOSE_LOCATION(__FILE__, __LINE__) \ + ".short " #flags "\n\t" \ + ".popsection\n" \ + \ + "1: brk %[imm]" \ + :: [imm] "i" (BUG_BRK_IMM) \ +) + +#define BUG() do { \ + _BUG_FLAGS(0); \ + unreachable(); \ +} while (0) + +#define __WARN_TAINT(taint) _BUG_FLAGS(BUGFLAG_TAINT(taint)) + +#endif /* ! CONFIG_GENERIC_BUG */ + +#include + +#endif /* ! _ARCH_ARM64_ASM_BUG_H */ diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index 777c36a1f645c..e3f2bad788c9b 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -52,10 +52,12 @@ * 0x100: for triggering a fault on purpose (reserved) * 0x400: for dynamic BRK instruction * 0x401: for compile time BRK instruction + * 0x800: kernel-mode BUG() and WARN() traps */ #define FAULT_BRK_IMM 0x100 #define KGDB_DYN_DBG_BRK_IMM 0x400 #define KGDB_COMPILED_DBG_BRK_IMM 0x401 +#define BUG_BRK_IMM 0x800 /* * BRK instruction encoding diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 1ea920cbd66d2..824ba5ac63615 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -32,8 +33,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -466,7 +469,61 @@ void __pgd_error(const char *file, int line, unsigned long val) pr_crit("%s:%d: bad pgd %016lx.\n", file, line, val); } +/* GENERIC_BUG traps */ + +int is_valid_bugaddr(unsigned long addr) +{ + /* + * bug_handler() only called for BRK #BUG_BRK_IMM. + * So the answer is trivial -- any spurious instances with no + * bug table entry will be rejected by report_bug() and passed + * back to the debug-monitors code and handled as a fatal + * unexpected debug exception. + */ + return 1; +} + +static int bug_handler(struct pt_regs *regs, unsigned int esr) +{ + if (user_mode(regs)) + return DBG_HOOK_ERROR; + + switch (report_bug(regs->pc, regs)) { + case BUG_TRAP_TYPE_BUG: + die("Oops - BUG", regs, 0); + break; + + case BUG_TRAP_TYPE_WARN: + break; + + default: + /* unknown/unrecognised bug trap type */ + return DBG_HOOK_ERROR; + } + + /* If thread survives, skip over the BUG instruction and continue: */ + regs->pc += AARCH64_INSN_SIZE; /* skip BRK and resume */ + return DBG_HOOK_HANDLED; +} + +static struct break_hook bug_break_hook = { + .esr_val = 0xf2000000 | BUG_BRK_IMM, + .esr_mask = 0xffffffff, + .fn = bug_handler, +}; + +/* + * Initial handler for AArch64 BRK exceptions + * This handler only used until debug_traps_init(). + */ +int __init early_brk64(unsigned long addr, unsigned int esr, + struct pt_regs *regs) +{ + return bug_handler(regs, esr) != DBG_HOOK_HANDLED; +} + +/* This registration must happen early, before debug_traps_init(). */ void __init trap_init(void) { - return; + register_break_hook(&bug_break_hook); } diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c index ce591211434e6..aba9ead1384c0 100644 --- a/arch/arm64/mm/fault.c +++ b/arch/arm64/mm/fault.c @@ -501,14 +501,22 @@ asmlinkage void __exception do_sp_pc_abort(unsigned long addr, arm64_notify_die("Oops - SP/PC alignment exception", regs, &info, esr); } -static struct fault_info debug_fault_info[] = { +int __init early_brk64(unsigned long addr, unsigned int esr, + struct pt_regs *regs); + +/* + * __refdata because early_brk64 is __init, but the reference to it is + * clobbered at arch_initcall time. + * See traps.c and debug-monitors.c:debug_traps_init(). + */ +static struct fault_info __refdata debug_fault_info[] = { { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware breakpoint" }, { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware single-step" }, { do_bad, SIGTRAP, TRAP_HWBKPT, "hardware watchpoint" }, { do_bad, SIGBUS, 0, "unknown 3" }, { do_bad, SIGTRAP, TRAP_BRKPT, "aarch32 BKPT" }, { do_bad, SIGTRAP, 0, "aarch32 vector catch" }, - { do_bad, SIGTRAP, TRAP_BRKPT, "aarch64 BRK" }, + { early_brk64, SIGTRAP, TRAP_BRKPT, "aarch64 BRK" }, { do_bad, SIGBUS, 0, "unknown 7" }, }; -- GitLab From a4653228a0f8d0a4a76d03a2dd15beaf6e78c22b Mon Sep 17 00:00:00 2001 From: Dave P Martin Date: Fri, 24 Jul 2015 16:37:49 +0100 Subject: [PATCH 1780/7006] arm64/BUG: Show explicit backtrace for WARNs The generic slowpath WARN implementation prints a backtrace, but the report_bug() based implementation does not, opting to print the registers instead which is generally not as useful. Ideally, report_bug() should be fixed to make the behaviour more consistent, but in the meantime this patch generates a backtrace directly from the arm64 backend instead so that this functionality is not lost with the migration to report_bug(). As a side-effect, the backtrace will be outside the oops end marker, but that's hard to avoid without modifying generic code. This patch can go away if report_bug() grows the ability in the future to generate a backtrace directly or call an arch hook at the appropriate time. Signed-off-by: Dave Martin Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/kernel/traps.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c index 824ba5ac63615..f93aae5e43075 100644 --- a/arch/arm64/kernel/traps.c +++ b/arch/arm64/kernel/traps.c @@ -494,6 +494,8 @@ static int bug_handler(struct pt_regs *regs, unsigned int esr) break; case BUG_TRAP_TYPE_WARN: + /* Ideally, report_bug() should backtrace for us... but no. */ + dump_backtrace(regs, NULL); break; default: -- GitLab From 772d68355e2f65f71e0402e39aabfdea56f55083 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jul 2015 11:07:03 +0100 Subject: [PATCH 1781/7006] arm64: include linux/types.h in asm/spinlock_types.h Our ticket-based spinlock structures rely on a definition of u16, so include linux/types.h explicitly to ensure the thing compiles. Found by a module build failure in -next: arch/arm64/include/asm/spinlock_types.h:27:2: error: unknown type name 'u16' arch/arm64/include/asm/spinlock_types.h:28:2: error: unknown type name 'u16' arch/arm64/include/asm/spinlock_types.h:33:13: error: expected declaration specifiers or '...' before numeric constant include/linux/spinlock_types.h:21:2: error: unknown type name 'arch_spinlock_t' arch/arm64/include/asm/spinlock.h:34:35: error: unknown type name 'arch_spinlock_t' arch/arm64/include/asm/spinlock.h:65:37: error: unknown type name 'arch_spinlock_t' Reported-by: Russell King Signed-off-by: Will Deacon --- arch/arm64/include/asm/spinlock_types.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/spinlock_types.h b/arch/arm64/include/asm/spinlock_types.h index b8d383665f56b..55be59a35e3fe 100644 --- a/arch/arm64/include/asm/spinlock_types.h +++ b/arch/arm64/include/asm/spinlock_types.h @@ -20,6 +20,8 @@ # error "please don't include this file directly" #endif +#include + #define TICKET_SHIFT 16 typedef struct { -- GitLab From 4183afefd995e3472c10348998edd9f791eb523f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 16 Jul 2015 21:08:21 +0200 Subject: [PATCH 1782/7006] gpio: mpc8xxx: constify of_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This variable is not modified in the driver and all functions it it passed to don't change it either. So it can and should be marked const. Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index da8e89205f371..0e2dbbb1645b0 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -334,7 +334,7 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; -static struct of_device_id mpc8xxx_gpio_ids[] = { +static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8349-gpio", }, { .compatible = "fsl,mpc8572-gpio", }, { .compatible = "fsl,mpc8610-gpio", }, -- GitLab From 82e39b0d8566fa67077c6941f776d17833c80fea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 16 Jul 2015 21:08:22 +0200 Subject: [PATCH 1783/7006] gpio: mpc8xxx: handle differences between incarnations at a single place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpio controllers that are handled by the mpc8xxx driver differ slightly. Up to now some differences were handled by use of of_device_is_compatible, others by use of struct of_device_id's data. To make this consistent and easily extendable handle the differences at a single place. Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 49 ++++++++++++++++++++++++++++--------- 1 file changed, 38 insertions(+), 11 deletions(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 0e2dbbb1645b0..836494420a56e 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -312,17 +312,13 @@ static struct irq_chip mpc8xxx_irq_chip = { .irq_unmask = mpc8xxx_irq_unmask, .irq_mask = mpc8xxx_irq_mask, .irq_ack = mpc8xxx_irq_ack, + /* this might get overwritten in mpc8xxx_probe() */ .irq_set_type = mpc8xxx_irq_set_type, }; static int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq, irq_hw_number_t hwirq) { - struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data; - - if (mpc8xxx_gc->of_dev_id_data) - mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data; - irq_set_chip_data(irq, h->host_data); irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_level_irq); @@ -334,11 +330,32 @@ static const struct irq_domain_ops mpc8xxx_gpio_irq_ops = { .xlate = irq_domain_xlate_twocell, }; +struct mpc8xxx_gpio_devtype { + int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int); + int (*gpio_get)(struct gpio_chip *, unsigned int); + int (*irq_set_type)(struct irq_data *, unsigned int); +}; + +static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { + .gpio_dir_out = mpc5121_gpio_dir_out, + .irq_set_type = mpc512x_irq_set_type, +}; + +static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = { + .gpio_get = mpc8572_gpio_get, +}; + +static const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = { + .gpio_dir_out = mpc8xxx_gpio_dir_out, + .gpio_get = mpc8xxx_gpio_get, + .irq_set_type = mpc8xxx_irq_set_type, +}; + static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8349-gpio", }, - { .compatible = "fsl,mpc8572-gpio", }, + { .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, }, { .compatible = "fsl,mpc8610-gpio", }, - { .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, }, + { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, { .compatible = "fsl,qoriq-gpio", }, {} @@ -351,6 +368,8 @@ static int mpc8xxx_probe(struct platform_device *pdev) struct of_mm_gpio_chip *mm_gc; struct gpio_chip *gc; const struct of_device_id *id; + const struct mpc8xxx_gpio_devtype *devtype = + of_device_get_match_data(&pdev->dev); int ret; mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL); @@ -367,10 +386,18 @@ static int mpc8xxx_probe(struct platform_device *pdev) mm_gc->save_regs = mpc8xxx_gpio_save_regs; gc->ngpio = MPC8XXX_GPIO_PINS; gc->direction_input = mpc8xxx_gpio_dir_in; - gc->direction_output = of_device_is_compatible(np, "fsl,mpc5121-gpio") ? - mpc5121_gpio_dir_out : mpc8xxx_gpio_dir_out; - gc->get = of_device_is_compatible(np, "fsl,mpc8572-gpio") ? - mpc8572_gpio_get : mpc8xxx_gpio_get; + + if (!devtype) + devtype = &mpc8xxx_gpio_devtype_default; + + /* + * It's assumed that only a single type of gpio controller is available + * on the current machine, so overwriting global data is fine. + */ + mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type; + + gc->direction_output = devtype->gpio_dir_out ?: mpc8xxx_gpio_dir_out; + gc->get = devtype->gpio_get ?: mpc8xxx_gpio_get; gc->set = mpc8xxx_gpio_set; gc->set_multiple = mpc8xxx_gpio_set_multiple; gc->to_irq = mpc8xxx_gpio_to_irq; -- GitLab From 0ba69e089827c24f5a4b21124185914f9de4f466 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 16 Jul 2015 21:08:23 +0200 Subject: [PATCH 1784/7006] gpio: mpc8xxx: add support for MPC5125 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The gpio controller on MPC5125 is identical to the MPC5121 register wise, the only difference is that the lines 0..3 are input only instead of 28..31 on MPC5121. Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 836494420a56e..4c51377934317 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -174,6 +174,15 @@ static int mpc5121_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val return mpc8xxx_gpio_dir_out(gc, gpio, val); } +static int mpc5125_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) +{ + /* GPIO 0..3 are input only on MPC5125 */ + if (gpio <= 3) + return -EINVAL; + + return mpc8xxx_gpio_dir_out(gc, gpio, val); +} + static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset) { struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc); @@ -341,6 +350,11 @@ static const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = { .irq_set_type = mpc512x_irq_set_type, }; +static const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = { + .gpio_dir_out = mpc5125_gpio_dir_out, + .irq_set_type = mpc512x_irq_set_type, +}; + static const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = { .gpio_get = mpc8572_gpio_get, }; @@ -356,6 +370,7 @@ static const struct of_device_id mpc8xxx_gpio_ids[] = { { .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, }, { .compatible = "fsl,mpc8610-gpio", }, { .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, }, + { .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, }, { .compatible = "fsl,pq3-gpio", }, { .compatible = "fsl,qoriq-gpio", }, {} -- GitLab From bb379ceb8d9f3599ab9162ebf58d731350f4177a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 16 Jul 2015 21:08:24 +0200 Subject: [PATCH 1785/7006] dt-bindings: gpio: document bindings supported by gpio-mpc8xxx.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-mpc8xxx.txt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt diff --git a/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt new file mode 100644 index 0000000000000..805ddcd79a572 --- /dev/null +++ b/Documentation/devicetree/bindings/gpio/gpio-mpc8xxx.txt @@ -0,0 +1,22 @@ +* Freescale MPC512x/MPC8xxx GPIO controller + +Required properties: +- compatible : Should be "fsl,-gpio" + The following s are known to be supported: + mpc5121, mpc5125, mpc8349, mpc8572, mpc8610, pq3, qoriq +- reg : Address and length of the register set for the device +- interrupts : Should be the port interrupt shared by all 32 pins. +- #gpio-cells : Should be two. The first cell is the pin number and + the second cell is used to specify the gpio polarity: + 0 = active high + 1 = active low + +Example: + +gpio0: gpio@1100 { + compatible = "fsl,mpc5125-gpio"; + #gpio-cells = <2>; + reg = <0x1100 0x080>; + interrupts = <78 0x8>; + status = "okay"; +}; -- GitLab From a0d6de9bdf8d66be458fcda5898a799778169c60 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jul 2015 14:41:11 +0200 Subject: [PATCH 1786/7006] pinctrl: sunxi: Use common functions to change irq_chip and handler The current code uses some custom variable affectations, while we have common functions to do exactly that. Move to the common functions. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 3e905480ec56c..c804f38323320 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -588,7 +588,6 @@ static void sunxi_pinctrl_irq_release_resources(struct irq_data *d) static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) { struct sunxi_pinctrl *pctl = irq_data_get_irq_chip_data(d); - struct irq_desc *desc = container_of(d, struct irq_desc, irq_data); u32 reg = sunxi_irq_cfg_reg(d->hwirq); u8 index = sunxi_irq_cfg_offset(d->hwirq); unsigned long flags; @@ -615,16 +614,17 @@ static int sunxi_pinctrl_irq_set_type(struct irq_data *d, unsigned int type) return -EINVAL; } - if (type & IRQ_TYPE_LEVEL_MASK) { - d->chip = &sunxi_pinctrl_level_irq_chip; - desc->handle_irq = handle_fasteoi_irq; - } else { - d->chip = &sunxi_pinctrl_edge_irq_chip; - desc->handle_irq = handle_edge_irq; - } - spin_lock_irqsave(&pctl->lock, flags); + if (type & IRQ_TYPE_LEVEL_MASK) + __irq_set_chip_handler_name_locked(d->irq, + &sunxi_pinctrl_level_irq_chip, + handle_fasteoi_irq, NULL); + else + __irq_set_chip_handler_name_locked(d->irq, + &sunxi_pinctrl_edge_irq_chip, + handle_edge_irq, NULL); + regval = readl(pctl->membase + reg); regval &= ~(IRQ_CFG_IRQ_MASK << index); writel(regval | (mode << index), pctl->membase + reg); -- GitLab From fb5b778808a1e5d6874c17b2e670c76fab9a1300 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 20 Jul 2015 14:41:12 +0200 Subject: [PATCH 1787/7006] pinctrl: sunxi: Add irq_chip name In order to ease the debugging, add a name to the irq_chips. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index c804f38323320..7f7e7bb4f22cf 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -685,6 +685,7 @@ static void sunxi_pinctrl_irq_ack_unmask(struct irq_data *d) } static struct irq_chip sunxi_pinctrl_edge_irq_chip = { + .name = "sunxi_pio_edge", .irq_ack = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, @@ -695,6 +696,7 @@ static struct irq_chip sunxi_pinctrl_edge_irq_chip = { }; static struct irq_chip sunxi_pinctrl_level_irq_chip = { + .name = "sunxi_pio_level", .irq_eoi = sunxi_pinctrl_irq_ack, .irq_mask = sunxi_pinctrl_irq_mask, .irq_unmask = sunxi_pinctrl_irq_unmask, -- GitLab From 56d1defe0bbddaa97d6e74b51490904130fd4f1d Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 15 Jul 2015 15:47:25 +0200 Subject: [PATCH 1788/7006] atomic: Prepare generic atomic implementation for logic ops Clean up the #ifdef guards a bit to prepare for architectures to supply their own logic ops. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- include/asm-generic/atomic.h | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 1973ad2b13f4d..92947e0a532a3 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -98,14 +98,22 @@ ATOMIC_OP_RETURN(add, +) ATOMIC_OP_RETURN(sub, -) #endif -#ifndef atomic_clear_mask +#ifndef atomic_and ATOMIC_OP(and, &) +#endif + +#ifndef atomic_clear_mask #define atomic_clear_mask(i, v) atomic_and(~(i), (v)) #endif -#ifndef atomic_set_mask +#ifndef atomic_or +#ifndef CONFIG_ARCH_HAS_ATOMIC_OR #define CONFIG_ARCH_HAS_ATOMIC_OR +#endif ATOMIC_OP(or, |) +#endif + +#ifndef atomic_set_mask #define atomic_set_mask(i, v) atomic_or((i), (v)) #endif -- GitLab From 212d3be102d73dce70cc12f39dce4e0aed2c025b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:07:47 +0200 Subject: [PATCH 1789/7006] alpha: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/alpha/include/asm/atomic.h | 43 +++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 8f8eafbedd7c2..0eff853398d21 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -29,13 +29,13 @@ * branch back to restart the operation. */ -#define ATOMIC_OP(op) \ +#define ATOMIC_OP(op, asm_op) \ static __inline__ void atomic_##op(int i, atomic_t * v) \ { \ unsigned long temp; \ __asm__ __volatile__( \ "1: ldl_l %0,%1\n" \ - " " #op "l %0,%2,%0\n" \ + " " #asm_op " %0,%2,%0\n" \ " stl_c %0,%1\n" \ " beq %0,2f\n" \ ".subsection 2\n" \ @@ -45,15 +45,15 @@ static __inline__ void atomic_##op(int i, atomic_t * v) \ :"Ir" (i), "m" (v->counter)); \ } \ -#define ATOMIC_OP_RETURN(op) \ +#define ATOMIC_OP_RETURN(op, asm_op) \ static inline int atomic_##op##_return(int i, atomic_t *v) \ { \ long temp, result; \ smp_mb(); \ __asm__ __volatile__( \ "1: ldl_l %0,%1\n" \ - " " #op "l %0,%3,%2\n" \ - " " #op "l %0,%3,%0\n" \ + " " #asm_op " %0,%3,%2\n" \ + " " #asm_op " %0,%3,%0\n" \ " stl_c %0,%1\n" \ " beq %0,2f\n" \ ".subsection 2\n" \ @@ -65,13 +65,13 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ return result; \ } -#define ATOMIC64_OP(op) \ +#define ATOMIC64_OP(op, asm_op) \ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ { \ unsigned long temp; \ __asm__ __volatile__( \ "1: ldq_l %0,%1\n" \ - " " #op "q %0,%2,%0\n" \ + " " #asm_op " %0,%2,%0\n" \ " stq_c %0,%1\n" \ " beq %0,2f\n" \ ".subsection 2\n" \ @@ -81,15 +81,15 @@ static __inline__ void atomic64_##op(long i, atomic64_t * v) \ :"Ir" (i), "m" (v->counter)); \ } \ -#define ATOMIC64_OP_RETURN(op) \ +#define ATOMIC64_OP_RETURN(op, asm_op) \ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ { \ long temp, result; \ smp_mb(); \ __asm__ __volatile__( \ "1: ldq_l %0,%1\n" \ - " " #op "q %0,%3,%2\n" \ - " " #op "q %0,%3,%0\n" \ + " " #asm_op " %0,%3,%2\n" \ + " " #asm_op " %0,%3,%0\n" \ " stq_c %0,%1\n" \ " beq %0,2f\n" \ ".subsection 2\n" \ @@ -101,15 +101,28 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ return result; \ } -#define ATOMIC_OPS(opg) \ - ATOMIC_OP(opg) \ - ATOMIC_OP_RETURN(opg) \ - ATOMIC64_OP(opg) \ - ATOMIC64_OP_RETURN(opg) +#define ATOMIC_OPS(op) \ + ATOMIC_OP(op, op##l) \ + ATOMIC_OP_RETURN(op, op##l) \ + ATOMIC64_OP(op, op##q) \ + ATOMIC64_OP_RETURN(op, op##q) ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR +#define atomic_andnot atomic_andnot +#define atomic64_andnot atomic64_andnot + +ATOMIC_OP(and, and) +ATOMIC_OP(andnot, bic) +ATOMIC_OP(or, bis) +ATOMIC_OP(xor, xor) +ATOMIC64_OP(and, and) +ATOMIC64_OP(andnot, bic) +ATOMIC64_OP(or, bis) +ATOMIC64_OP(xor, xor) + #undef ATOMIC_OPS #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- GitLab From cda7e4137a4e39c7d877b6ed41da13a5b30dd2cf Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:06:20 +0200 Subject: [PATCH 1790/7006] arc: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Acked-by: Vineet Gupta Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/arc/include/asm/atomic.h | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 03484cb4d16d2..e90b701fc6a87 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -143,14 +143,29 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) -ATOMIC_OP(and, &=, and) -#define atomic_clear_mask(mask, v) atomic_and(~(mask), (v)) +#define CONFIG_ARCH_HAS_ATOMIC_OR +#define atomic_andnot atomic_andnot + +ATOMIC_OP(and, &=, and) +ATOMIC_OP(andnot, &= ~, bic) +ATOMIC_OP(or, |=, or) +ATOMIC_OP(xor, ^=, xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} + +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} + /** * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t -- GitLab From 125897908c718972351b589da89b7f990892d4df Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:04:39 +0200 Subject: [PATCH 1791/7006] arm: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/arm/include/asm/atomic.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index e22c11970b7bd..ff214bac9cb4c 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -194,6 +194,14 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR +#define atomic_andnot atomic_andnot + +ATOMIC_OP(and, &=, and) +ATOMIC_OP(andnot, &= ~, bic) +ATOMIC_OP(or, |=, orr) +ATOMIC_OP(xor, ^=, eor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -321,6 +329,13 @@ static inline long long atomic64_##op##_return(long long i, atomic64_t *v) \ ATOMIC64_OPS(add, adds, adc) ATOMIC64_OPS(sub, subs, sbc) +#define atomic64_andnot atomic64_andnot + +ATOMIC64_OP(and, and, and) +ATOMIC64_OP(andnot, bic, bic) +ATOMIC64_OP(or, orr, orr) +ATOMIC64_OP(xor, eor, eor) + #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- GitLab From 22288b40e2c7ab484a08a03df32782a67903912c Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:03:13 +0200 Subject: [PATCH 1792/7006] arm64: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/arm64/include/asm/atomic.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 7047051ded40e..2876173397b28 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -85,6 +85,14 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, add) ATOMIC_OPS(sub, sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR +#define atomic_andnot atomic_andnot + +ATOMIC_OP(and, and) +ATOMIC_OP(andnot, bic) +ATOMIC_OP(or, orr) +ATOMIC_OP(xor, eor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -183,6 +191,13 @@ static inline long atomic64_##op##_return(long i, atomic64_t *v) \ ATOMIC64_OPS(add, add) ATOMIC64_OPS(sub, sub) +#define atomic64_andnot atomic64_andnot + +ATOMIC64_OP(and, and) +ATOMIC64_OP(andnot, bic) +ATOMIC64_OP(or, orr) +ATOMIC64_OP(xor, eor) + #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -- GitLab From f8a570e270bf62363cd498ac2ac8ea07a76ad4d6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:02:20 +0200 Subject: [PATCH 1793/7006] avr32: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/avr32/include/asm/atomic.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index 2d07ce1c5327c..115d3005e4bc1 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -44,6 +44,20 @@ static inline int __atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OP_RETURN(sub, sub, rKs21) ATOMIC_OP_RETURN(add, add, r) +#define ATOMIC_OP(op, asm_op) \ +ATOMIC_OP_RETURN(op, asm_op, r) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + (void)__atomic_##op##_return(i, v); \ +} + +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and, and) +ATOMIC_OP(or, or) +ATOMIC_OP(xor, eor) + +#undef ATOMIC_OP #undef ATOMIC_OP_RETURN /* -- GitLab From d835b6c4cc02507b3bf3f8ee6c86857cf0ee67ab Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Thu, 23 Apr 2015 21:44:42 +0200 Subject: [PATCH 1794/7006] blackfin: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. TODO: use inline asm or at least asm macros to collapse the lot. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/blackfin/include/asm/atomic.h | 28 +++++++++++++++++++++------- arch/blackfin/kernel/bfin_ksyms.c | 7 ++++--- arch/blackfin/mach-bf561/atomic.S | 30 +++++++++++++++--------------- 3 files changed, 40 insertions(+), 25 deletions(-) diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index a107a98e99783..eafa55b81a7b6 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -16,19 +16,33 @@ #include asmlinkage int __raw_uncached_fetch_asm(const volatile int *ptr); -asmlinkage int __raw_atomic_update_asm(volatile int *ptr, int value); -asmlinkage int __raw_atomic_clear_asm(volatile int *ptr, int value); -asmlinkage int __raw_atomic_set_asm(volatile int *ptr, int value); +asmlinkage int __raw_atomic_add_asm(volatile int *ptr, int value); + +asmlinkage int __raw_atomic_and_asm(volatile int *ptr, int value); +asmlinkage int __raw_atomic_or_asm(volatile int *ptr, int value); asmlinkage int __raw_atomic_xor_asm(volatile int *ptr, int value); asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); #define atomic_read(v) __raw_uncached_fetch_asm(&(v)->counter) -#define atomic_add_return(i, v) __raw_atomic_update_asm(&(v)->counter, i) -#define atomic_sub_return(i, v) __raw_atomic_update_asm(&(v)->counter, -(i)) +#define atomic_add_return(i, v) __raw_atomic_add_asm(&(v)->counter, i) +#define atomic_sub_return(i, v) __raw_atomic_add_asm(&(v)->counter, -(i)) + +#define CONFIG_ARCH_HAS_ATOMIC_OR + +#define atomic_or(i, v) (void)__raw_atomic_or_asm(&(v)->counter, i) +#define atomic_and(i, v) (void)__raw_atomic_and_asm(&(v)->counter, i) +#define atomic_xor(i, v) (void)__raw_atomic_xor_asm(&(v)->counter, i) + +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} -#define atomic_clear_mask(m, v) __raw_atomic_clear_asm(&(v)->counter, m) -#define atomic_set_mask(m, v) __raw_atomic_set_asm(&(v)->counter, m) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} #endif diff --git a/arch/blackfin/kernel/bfin_ksyms.c b/arch/blackfin/kernel/bfin_ksyms.c index c446591b961dd..a401c27b69b4a 100644 --- a/arch/blackfin/kernel/bfin_ksyms.c +++ b/arch/blackfin/kernel/bfin_ksyms.c @@ -83,11 +83,12 @@ EXPORT_SYMBOL(insl); EXPORT_SYMBOL(insl_16); #ifdef CONFIG_SMP -EXPORT_SYMBOL(__raw_atomic_update_asm); -EXPORT_SYMBOL(__raw_atomic_clear_asm); -EXPORT_SYMBOL(__raw_atomic_set_asm); +EXPORT_SYMBOL(__raw_atomic_add_asm); +EXPORT_SYMBOL(__raw_atomic_and_asm); +EXPORT_SYMBOL(__raw_atomic_or_asm); EXPORT_SYMBOL(__raw_atomic_xor_asm); EXPORT_SYMBOL(__raw_atomic_test_asm); + EXPORT_SYMBOL(__raw_xchg_1_asm); EXPORT_SYMBOL(__raw_xchg_2_asm); EXPORT_SYMBOL(__raw_xchg_4_asm); diff --git a/arch/blackfin/mach-bf561/atomic.S b/arch/blackfin/mach-bf561/atomic.S index 2a08df8e8c4c7..26fccb5568b97 100644 --- a/arch/blackfin/mach-bf561/atomic.S +++ b/arch/blackfin/mach-bf561/atomic.S @@ -587,10 +587,10 @@ ENDPROC(___raw_write_unlock_asm) * r0 = ptr * r1 = value * - * Add a signed value to a 32bit word and return the new value atomically. + * ADD a signed value to a 32bit word and return the new value atomically. * Clobbers: r3:0, p1:0 */ -ENTRY(___raw_atomic_update_asm) +ENTRY(___raw_atomic_add_asm) p1 = r0; r3 = r1; [--sp] = rets; @@ -603,19 +603,19 @@ ENTRY(___raw_atomic_update_asm) r0 = r3; rets = [sp++]; rts; -ENDPROC(___raw_atomic_update_asm) +ENDPROC(___raw_atomic_add_asm) /* * r0 = ptr * r1 = mask * - * Clear the mask bits from a 32bit word and return the old 32bit value + * AND the mask bits from a 32bit word and return the old 32bit value * atomically. * Clobbers: r3:0, p1:0 */ -ENTRY(___raw_atomic_clear_asm) +ENTRY(___raw_atomic_and_asm) p1 = r0; - r3 = ~r1; + r3 = r1; [--sp] = rets; call _get_core_lock; r2 = [p1]; @@ -627,17 +627,17 @@ ENTRY(___raw_atomic_clear_asm) r0 = r3; rets = [sp++]; rts; -ENDPROC(___raw_atomic_clear_asm) +ENDPROC(___raw_atomic_and_asm) /* * r0 = ptr * r1 = mask * - * Set the mask bits into a 32bit word and return the old 32bit value + * OR the mask bits into a 32bit word and return the old 32bit value * atomically. * Clobbers: r3:0, p1:0 */ -ENTRY(___raw_atomic_set_asm) +ENTRY(___raw_atomic_or_asm) p1 = r0; r3 = r1; [--sp] = rets; @@ -651,7 +651,7 @@ ENTRY(___raw_atomic_set_asm) r0 = r3; rets = [sp++]; rts; -ENDPROC(___raw_atomic_set_asm) +ENDPROC(___raw_atomic_or_asm) /* * r0 = ptr @@ -787,7 +787,7 @@ ENTRY(___raw_bit_set_asm) r2 = r1; r1 = 1; r1 <<= r2; - jump ___raw_atomic_set_asm + jump ___raw_atomic_or_asm ENDPROC(___raw_bit_set_asm) /* @@ -798,10 +798,10 @@ ENDPROC(___raw_bit_set_asm) * Clobbers: r3:0, p1:0 */ ENTRY(___raw_bit_clear_asm) - r2 = r1; - r1 = 1; - r1 <<= r2; - jump ___raw_atomic_clear_asm + r2 = 1; + r2 <<= r1; + r1 = ~r2; + jump ___raw_atomic_and_asm ENDPROC(___raw_bit_clear_asm) /* -- GitLab From 610f7ba93b1e4cda7370f367a6042cbda61227bb Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:00:54 +0200 Subject: [PATCH 1795/7006] hexagon: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/hexagon/include/asm/atomic.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 93d07025f183d..4efe2c7c0dd86 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -132,6 +132,12 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -- GitLab From 70ed47390d10a7351e44c3a07c5de376780cb6c1 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:00:01 +0200 Subject: [PATCH 1796/7006] ia64: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/ia64/include/asm/atomic.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 0bf03501fe5ca..0809ef5d6b9a1 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -45,8 +45,6 @@ ia64_atomic_##op (int i, atomic_t *v) \ ATOMIC_OP(add, +) ATOMIC_OP(sub, -) -#undef ATOMIC_OP - #define atomic_add_return(i,v) \ ({ \ int __ia64_aar_i = (i); \ @@ -71,6 +69,18 @@ ATOMIC_OP(sub, -) : ia64_atomic_sub(__ia64_asr_i, v); \ }) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and, &) +ATOMIC_OP(or, |) +ATOMIC_OP(xor, ^) + +#define atomic_and(i,v) (void)ia64_atomic_and(i,v) +#define atomic_or(i,v) (void)ia64_atomic_or(i,v) +#define atomic_xor(i,v) (void)ia64_atomic_xor(i,v) + +#undef ATOMIC_OP + #define ATOMIC64_OP(op, c_op) \ static __inline__ long \ ia64_atomic64_##op (__s64 i, atomic64_t *v) \ @@ -89,8 +99,6 @@ ia64_atomic64_##op (__s64 i, atomic64_t *v) \ ATOMIC64_OP(add, +) ATOMIC64_OP(sub, -) -#undef ATOMIC64_OP - #define atomic64_add_return(i,v) \ ({ \ long __ia64_aar_i = (i); \ @@ -115,6 +123,16 @@ ATOMIC64_OP(sub, -) : ia64_atomic64_sub(__ia64_asr_i, v); \ }) +ATOMIC64_OP(and, &) +ATOMIC64_OP(or, |) +ATOMIC64_OP(xor, ^) + +#define atomic64_and(i,v) (void)ia64_atomic64_and(i,v) +#define atomic64_or(i,v) (void)ia64_atomic64_or(i,v) +#define atomic64_xor(i,v) (void)ia64_atomic64_xor(i,v) + +#undef ATOMIC64_OP + #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), old, new)) #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) -- GitLab From c66e45edef51e1f54297ddaf202fc2dd00852734 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:57:49 +0200 Subject: [PATCH 1797/7006] m32r: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/m32r/include/asm/atomic.h | 44 ++++++++-------------------------- 1 file changed, 10 insertions(+), 34 deletions(-) diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 31bb74adba082..7245463c1e98d 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -94,6 +94,12 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -240,44 +246,14 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) } -static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *addr) +static __inline__ __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { - unsigned long flags; - unsigned long tmp; - - local_irq_save(flags); - __asm__ __volatile__ ( - "# atomic_clear_mask \n\t" - DCACHE_CLEAR("%0", "r5", "%1") - M32R_LOCK" %0, @%1; \n\t" - "and %0, %2; \n\t" - M32R_UNLOCK" %0, @%1; \n\t" - : "=&r" (tmp) - : "r" (addr), "r" (~mask) - : "memory" - __ATOMIC_CLOBBER - ); - local_irq_restore(flags); + atomic_and(~mask, v); } -static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *addr) +static __inline__ __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { - unsigned long flags; - unsigned long tmp; - - local_irq_save(flags); - __asm__ __volatile__ ( - "# atomic_set_mask \n\t" - DCACHE_CLEAR("%0", "r5", "%1") - M32R_LOCK" %0, @%1; \n\t" - "or %0, %2; \n\t" - M32R_UNLOCK" %0, @%1; \n\t" - : "=&r" (tmp) - : "r" (addr), "r" (mask) - : "memory" - __ATOMIC_CLOBBER - ); - local_irq_restore(flags); + atomic_or(mask, v); } #endif /* _ASM_M32R_ATOMIC_H */ -- GitLab From 74b1bc505b058efdfef33e775df68d8324bbf8b8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:56:20 +0200 Subject: [PATCH 1798/7006] m68k: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Acked-by: Geert Uytterhoeven Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/m68k/include/asm/atomic.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index e85f047fb072e..c30e43ea49a3b 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -77,6 +77,12 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and, &=, and) +ATOMIC_OP(or, |=, or) +ATOMIC_OP(xor, ^=, eor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -170,14 +176,14 @@ static inline int atomic_add_negative(int i, atomic_t *v) return c != 0; } -static inline void atomic_clear_mask(unsigned long mask, unsigned long *v) +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { - __asm__ __volatile__("andl %1,%0" : "+m" (*v) : ASM_DI (~(mask))); + atomic_and(~mask, v); } -static inline void atomic_set_mask(unsigned long mask, unsigned long *v) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { - __asm__ __volatile__("orl %1,%0" : "+m" (*v) : ASM_DI (mask)); + atomic_or(mask, v); } static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) -- GitLab From 5b4a2f0f91fd4a635f380f847254d23121972e7b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:53:39 +0200 Subject: [PATCH 1799/7006] metag: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/metag/include/asm/atomic_lnkget.h | 38 +++++++------------------- arch/metag/include/asm/atomic_lock1.h | 21 +++++--------- 2 files changed, 17 insertions(+), 42 deletions(-) diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index 948d8688643c5..930c12cb8d378 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h @@ -74,42 +74,24 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { - int temp; - - asm volatile ( - "1: LNKGETD %0, [%1]\n" - " AND %0, %0, %2\n" - " LNKSETD [%1] %0\n" - " DEFR %0, TXSTAT\n" - " ANDT %0, %0, #HI(0x3f000000)\n" - " CMPT %0, #HI(0x02000000)\n" - " BNZ 1b\n" - : "=&d" (temp) - : "da" (&v->counter), "bd" (~mask) - : "cc"); + atomic_and(~mask, v); } -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { - int temp; - - asm volatile ( - "1: LNKGETD %0, [%1]\n" - " OR %0, %0, %2\n" - " LNKSETD [%1], %0\n" - " DEFR %0, TXSTAT\n" - " ANDT %0, %0, #HI(0x3f000000)\n" - " CMPT %0, #HI(0x02000000)\n" - " BNZ 1b\n" - : "=&d" (temp) - : "da" (&v->counter), "bd" (mask) - : "cc"); + atomic_or(mask, v); } static inline int atomic_cmpxchg(atomic_t *v, int old, int new) diff --git a/arch/metag/include/asm/atomic_lock1.h b/arch/metag/include/asm/atomic_lock1.h index f5d5898c10201..7d88725a85da4 100644 --- a/arch/metag/include/asm/atomic_lock1.h +++ b/arch/metag/include/asm/atomic_lock1.h @@ -68,29 +68,22 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) +ATOMIC_OP(and, &=) +ATOMIC_OP(or, |=) +ATOMIC_OP(xor, ^=) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { - unsigned long flags; - - __global_lock1(flags); - fence(); - v->counter &= ~mask; - __global_unlock1(flags); + atomic_and(~mask, v); } -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { - unsigned long flags; - - __global_lock1(flags); - fence(); - v->counter |= mask; - __global_unlock1(flags); + atomic_or(mask, v); } static inline int atomic_cmpxchg(atomic_t *v, int old, int new) -- GitLab From 27782f2752aca65a241f10fb2d4508c71bb2656b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:51:36 +0200 Subject: [PATCH 1800/7006] mips: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Acked-by: Ralf Baechle Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/mips/include/asm/atomic.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 26d436336f2e1..0430ba6ab7628 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -137,6 +137,12 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ ATOMIC_OPS(add, +=, addu) ATOMIC_OPS(sub, -=, subu) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and, &=, and) +ATOMIC_OP(or, |=, or) +ATOMIC_OP(xor, ^=, xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -416,6 +422,9 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ ATOMIC64_OPS(add, +=, daddu) ATOMIC64_OPS(sub, -=, dsubu) +ATOMIC64_OP(and, &=, and) +ATOMIC64_OP(or, |=, or) +ATOMIC64_OP(xor, ^=, xor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN -- GitLab From ddb7573ff68964e7b3b72eeb9cde1384c4c6ba83 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:50:20 +0200 Subject: [PATCH 1801/7006] mn10300: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/mn10300/include/asm/atomic.h | 57 ++++++------------------------- 1 file changed, 10 insertions(+), 47 deletions(-) diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index 5be655e83e709..03eea8158cf95 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -89,6 +89,12 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -134,31 +140,9 @@ static inline void atomic_dec(atomic_t *v) * * Atomically clears the bits set in mask from the memory word specified. */ -static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { -#ifdef CONFIG_SMP - int status; - - asm volatile( - "1: mov %3,(_AAR,%2) \n" - " mov (_ADR,%2),%0 \n" - " and %4,%0 \n" - " mov %0,(_ADR,%2) \n" - " mov (_ADR,%2),%0 \n" /* flush */ - " mov (_ASR,%2),%0 \n" - " or %0,%0 \n" - " bne 1b \n" - : "=&r"(status), "=m"(*addr) - : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(~mask) - : "memory", "cc"); -#else - unsigned long flags; - - mask = ~mask; - flags = arch_local_cli_save(); - *addr &= mask; - arch_local_irq_restore(flags); -#endif + atomic_and(~mask, v); } /** @@ -168,30 +152,9 @@ static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) * * Atomically sets the bits set in mask from the memory word specified. */ -static inline void atomic_set_mask(unsigned long mask, unsigned long *addr) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { -#ifdef CONFIG_SMP - int status; - - asm volatile( - "1: mov %3,(_AAR,%2) \n" - " mov (_ADR,%2),%0 \n" - " or %4,%0 \n" - " mov %0,(_ADR,%2) \n" - " mov (_ADR,%2),%0 \n" /* flush */ - " mov (_ASR,%2),%0 \n" - " or %0,%0 \n" - " bne 1b \n" - : "=&r"(status), "=m"(*addr) - : "a"(ATOMIC_OPS_BASE_ADDR), "r"(addr), "r"(mask) - : "memory", "cc"); -#else - unsigned long flags; - - flags = arch_local_cli_save(); - *addr |= mask; - arch_local_irq_restore(flags); -#endif + atomic_or(mask, v); } #endif /* __KERNEL__ */ -- GitLab From aebea9359623b58b54242e5daa24e09d6104977b Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:47:25 +0200 Subject: [PATCH 1802/7006] parisc: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/parisc/include/asm/atomic.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index 226f8ca993f69..be2c50ddebd61 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -126,6 +126,12 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and, &=) +ATOMIC_OP(or, |=) +ATOMIC_OP(xor, ^=) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -185,6 +191,9 @@ static __inline__ s64 atomic64_##op##_return(s64 i, atomic64_t *v) \ ATOMIC64_OPS(add, +=) ATOMIC64_OPS(sub, -=) +ATOMIC64_OP(and, &=) +ATOMIC64_OP(or, |=) +ATOMIC64_OP(xor, ^=) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN -- GitLab From d0b7eb6ff2985c9350fdb297fa5727c35324d4df Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:46:23 +0200 Subject: [PATCH 1803/7006] powerpc: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Acked-by: Benjamin Herrenschmidt Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/powerpc/include/asm/atomic.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 512d2782b043d..6ca89e2aca159 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -67,6 +67,12 @@ static __inline__ int atomic_##op##_return(int a, atomic_t *v) \ ATOMIC_OPS(add, add) ATOMIC_OPS(sub, subf) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and, and) +ATOMIC_OP(or, or) +ATOMIC_OP(xor, xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP @@ -304,6 +310,9 @@ static __inline__ long atomic64_##op##_return(long a, atomic64_t *v) \ ATOMIC64_OPS(add, add) ATOMIC64_OPS(sub, subf) +ATOMIC64_OP(and, and) +ATOMIC64_OP(or, or) +ATOMIC64_OP(xor, xor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN -- GitLab From 658aa51459c2f5284183d35b6dd0beca0e0bfe2f Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:44:20 +0200 Subject: [PATCH 1804/7006] sh: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/sh/include/asm/atomic-grb.h | 45 +++++-------------------------- arch/sh/include/asm/atomic-irq.h | 21 +++------------ arch/sh/include/asm/atomic-llsc.h | 31 +++------------------ arch/sh/include/asm/atomic.h | 10 +++++++ 4 files changed, 22 insertions(+), 85 deletions(-) diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h index 97a5fda83450e..4b03830d48c73 100644 --- a/arch/sh/include/asm/atomic-grb.h +++ b/arch/sh/include/asm/atomic-grb.h @@ -48,47 +48,14 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - int tmp; - unsigned int _mask = ~mask; - - __asm__ __volatile__ ( - " .align 2 \n\t" - " mova 1f, r0 \n\t" /* r0 = end point */ - " mov r15, r1 \n\t" /* r1 = saved sp */ - " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ - " mov.l @%1, %0 \n\t" /* load old value */ - " and %2, %0 \n\t" /* add */ - " mov.l %0, @%1 \n\t" /* store new value */ - "1: mov r1, r15 \n\t" /* LOGOUT */ - : "=&r" (tmp), - "+r" (v) - : "r" (_mask) - : "memory" , "r0", "r1"); -} - -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - int tmp; - - __asm__ __volatile__ ( - " .align 2 \n\t" - " mova 1f, r0 \n\t" /* r0 = end point */ - " mov r15, r1 \n\t" /* r1 = saved sp */ - " mov #-6, r15 \n\t" /* LOGIN: r15 = size */ - " mov.l @%1, %0 \n\t" /* load old value */ - " or %2, %0 \n\t" /* or */ - " mov.l %0, @%1 \n\t" /* store new value */ - "1: mov r1, r15 \n\t" /* LOGOUT */ - : "=&r" (tmp), - "+r" (v) - : "r" (mask) - : "memory" , "r0", "r1"); -} - #endif /* __ASM_SH_ATOMIC_GRB_H */ diff --git a/arch/sh/include/asm/atomic-irq.h b/arch/sh/include/asm/atomic-irq.h index 61d107523f064..23fcdad5773ee 100644 --- a/arch/sh/include/asm/atomic-irq.h +++ b/arch/sh/include/asm/atomic-irq.h @@ -37,27 +37,12 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) +ATOMIC_OP(and, &=) +ATOMIC_OP(or, |=) +ATOMIC_OP(xor, ^=) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - unsigned long flags; - - raw_local_irq_save(flags); - v->counter &= ~mask; - raw_local_irq_restore(flags); -} - -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - unsigned long flags; - - raw_local_irq_save(flags); - v->counter |= mask; - raw_local_irq_restore(flags); -} - #endif /* __ASM_SH_ATOMIC_IRQ_H */ diff --git a/arch/sh/include/asm/atomic-llsc.h b/arch/sh/include/asm/atomic-llsc.h index 8575dccb9ef78..33d34b16d4d67 100644 --- a/arch/sh/include/asm/atomic-llsc.h +++ b/arch/sh/include/asm/atomic-llsc.h @@ -52,37 +52,12 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - unsigned long tmp; - - __asm__ __volatile__ ( -"1: movli.l @%2, %0 ! atomic_clear_mask \n" -" and %1, %0 \n" -" movco.l %0, @%2 \n" -" bf 1b \n" - : "=&z" (tmp) - : "r" (~mask), "r" (&v->counter) - : "t"); -} - -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - unsigned long tmp; - - __asm__ __volatile__ ( -"1: movli.l @%2, %0 ! atomic_set_mask \n" -" or %1, %0 \n" -" movco.l %0, @%2 \n" -" bf 1b \n" - : "=&z" (tmp) - : "r" (mask), "r" (&v->counter) - : "t"); -} - #endif /* __ASM_SH_ATOMIC_LLSC_H */ diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index 05b9f74ce2d54..cee0245257e13 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -25,6 +25,16 @@ #include #endif +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} + +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} + #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) -- GitLab From 304a0d699a3c6103b61d5ea18d56820e7d8e3116 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:40:25 +0200 Subject: [PATCH 1805/7006] sparc: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Acked-by: David S. Miller Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/sparc/include/asm/atomic_32.h | 4 ++++ arch/sparc/include/asm/atomic_64.h | 6 ++++++ arch/sparc/lib/atomic32.c | 22 +++++++++++++++++++--- arch/sparc/lib/atomic_64.S | 6 ++++++ arch/sparc/lib/ksyms.c | 3 +++ 5 files changed, 38 insertions(+), 3 deletions(-) diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index 0e69b7e7a439c..e19d8880b1461 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -17,10 +17,14 @@ #include #include +#define CONFIG_ARCH_HAS_ATOMIC_OR #define ATOMIC_INIT(i) { (i) } int atomic_add_return(int, atomic_t *); +void atomic_and(int, atomic_t *); +void atomic_or(int, atomic_t *); +void atomic_xor(int, atomic_t *); int atomic_cmpxchg(atomic_t *, int, int); int atomic_xchg(atomic_t *, int); int __atomic_add_unless(atomic_t *, int, int); diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index 4082749913ce0..d6af27c934505 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -33,6 +33,12 @@ long atomic64_##op##_return(long, atomic64_t *); ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP diff --git a/arch/sparc/lib/atomic32.c b/arch/sparc/lib/atomic32.c index 71cd65ab200c8..b9d63c0a7aabc 100644 --- a/arch/sparc/lib/atomic32.c +++ b/arch/sparc/lib/atomic32.c @@ -27,22 +27,38 @@ static DEFINE_SPINLOCK(dummy); #endif /* SMP */ -#define ATOMIC_OP(op, cop) \ +#define ATOMIC_OP_RETURN(op, c_op) \ int atomic_##op##_return(int i, atomic_t *v) \ { \ int ret; \ unsigned long flags; \ spin_lock_irqsave(ATOMIC_HASH(v), flags); \ \ - ret = (v->counter cop i); \ + ret = (v->counter c_op i); \ \ spin_unlock_irqrestore(ATOMIC_HASH(v), flags); \ return ret; \ } \ EXPORT_SYMBOL(atomic_##op##_return); -ATOMIC_OP(add, +=) +#define ATOMIC_OP(op, c_op) \ +void atomic_##op(int i, atomic_t *v) \ +{ \ + unsigned long flags; \ + spin_lock_irqsave(ATOMIC_HASH(v), flags); \ + \ + v->counter c_op i; \ + \ + spin_unlock_irqrestore(ATOMIC_HASH(v), flags); \ +} \ +EXPORT_SYMBOL(atomic_##op); + +ATOMIC_OP_RETURN(add, +=) +ATOMIC_OP(and, &=) +ATOMIC_OP(or, |=) +ATOMIC_OP(xor, ^=) +#undef ATOMIC_OP_RETURN #undef ATOMIC_OP int atomic_xchg(atomic_t *v, int new) diff --git a/arch/sparc/lib/atomic_64.S b/arch/sparc/lib/atomic_64.S index 05dac43907d11..d6b0363f345bf 100644 --- a/arch/sparc/lib/atomic_64.S +++ b/arch/sparc/lib/atomic_64.S @@ -47,6 +47,9 @@ ENDPROC(atomic_##op##_return); ATOMIC_OPS(add) ATOMIC_OPS(sub) +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN @@ -84,6 +87,9 @@ ENDPROC(atomic64_##op##_return); ATOMIC64_OPS(add) ATOMIC64_OPS(sub) +ATOMIC64_OP(and) +ATOMIC64_OP(or) +ATOMIC64_OP(xor) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c index 1d649a95660c8..bb60059972683 100644 --- a/arch/sparc/lib/ksyms.c +++ b/arch/sparc/lib/ksyms.c @@ -111,6 +111,9 @@ EXPORT_SYMBOL(atomic64_##op##_return); ATOMIC_OPS(add) ATOMIC_OPS(sub) +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN -- GitLab From 2a3ed90f428cab65567c5421ebc0f6c8d02c1216 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:35:00 +0200 Subject: [PATCH 1806/7006] xtensa: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/xtensa/include/asm/atomic.h | 85 ++++++-------------------------- 1 file changed, 16 insertions(+), 69 deletions(-) diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index 00b7d46b35b84..4dd2450300a67 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -145,10 +145,26 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + #undef ATOMIC_OPS #undef ATOMIC_OP_RETURN #undef ATOMIC_OP +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} + +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} + /** * atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract @@ -250,75 +266,6 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return c; } - -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ -#if XCHAL_HAVE_S32C1I - unsigned long tmp; - int result; - - __asm__ __volatile__( - "1: l32i %1, %3, 0\n" - " wsr %1, scompare1\n" - " and %0, %1, %2\n" - " s32c1i %0, %3, 0\n" - " bne %0, %1, 1b\n" - : "=&a" (result), "=&a" (tmp) - : "a" (~mask), "a" (v) - : "memory" - ); -#else - unsigned int all_f = -1; - unsigned int vval; - - __asm__ __volatile__( - " rsil a15,"__stringify(LOCKLEVEL)"\n" - " l32i %0, %2, 0\n" - " xor %1, %4, %3\n" - " and %0, %0, %4\n" - " s32i %0, %2, 0\n" - " wsr a15, ps\n" - " rsync\n" - : "=&a" (vval), "=a" (mask) - : "a" (v), "a" (all_f), "1" (mask) - : "a15", "memory" - ); -#endif -} - -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) -{ -#if XCHAL_HAVE_S32C1I - unsigned long tmp; - int result; - - __asm__ __volatile__( - "1: l32i %1, %3, 0\n" - " wsr %1, scompare1\n" - " or %0, %1, %2\n" - " s32c1i %0, %3, 0\n" - " bne %0, %1, 1b\n" - : "=&a" (result), "=&a" (tmp) - : "a" (mask), "a" (v) - : "memory" - ); -#else - unsigned int vval; - - __asm__ __volatile__( - " rsil a15,"__stringify(LOCKLEVEL)"\n" - " l32i %0, %2, 0\n" - " or %0, %0, %1\n" - " s32i %0, %2, 0\n" - " wsr a15, ps\n" - " rsync\n" - : "=&a" (vval) - : "a" (mask), "a" (v) - : "a15", "memory" - ); -#endif -} - #endif /* __KERNEL__ */ #endif /* _XTENSA_ATOMIC_H */ -- GitLab From ae8c35c85be92b79c545c57c2a14c2f8136d3353 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:15:48 +0200 Subject: [PATCH 1807/7006] s390: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Acked-by: Heiko Carstens Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/s390/include/asm/atomic.h | 47 ++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index adbe3802e377b..b3859d8e001ff 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -27,6 +27,7 @@ #define __ATOMIC_OR "lao" #define __ATOMIC_AND "lan" #define __ATOMIC_ADD "laa" +#define __ATOMIC_XOR "lax" #define __ATOMIC_BARRIER "bcr 14,0\n" #define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier) \ @@ -49,6 +50,7 @@ #define __ATOMIC_OR "or" #define __ATOMIC_AND "nr" #define __ATOMIC_ADD "ar" +#define __ATOMIC_XOR "xr" #define __ATOMIC_BARRIER "\n" #define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier) \ @@ -118,14 +120,26 @@ static inline void atomic_add(int i, atomic_t *v) #define atomic_dec_return(_v) atomic_sub_return(1, _v) #define atomic_dec_and_test(_v) (atomic_sub_return(1, _v) == 0) -static inline void atomic_clear_mask(unsigned int mask, atomic_t *v) +#define ATOMIC_OP(op, OP) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + __ATOMIC_LOOP(v, i, __ATOMIC_##OP, __ATOMIC_NO_BARRIER); \ +} + +ATOMIC_OP(and, AND) +ATOMIC_OP(or, OR) +ATOMIC_OP(xor, XOR) + +#undef ATOMIC_OP + +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { - __ATOMIC_LOOP(v, ~mask, __ATOMIC_AND, __ATOMIC_NO_BARRIER); + atomic_and(~mask, v); } -static inline void atomic_set_mask(unsigned int mask, atomic_t *v) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { - __ATOMIC_LOOP(v, mask, __ATOMIC_OR, __ATOMIC_NO_BARRIER); + atomic_or(mask, v); } #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) @@ -167,6 +181,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define __ATOMIC64_OR "laog" #define __ATOMIC64_AND "lang" #define __ATOMIC64_ADD "laag" +#define __ATOMIC64_XOR "laxg" #define __ATOMIC64_BARRIER "bcr 14,0\n" #define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier) \ @@ -189,6 +204,7 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define __ATOMIC64_OR "ogr" #define __ATOMIC64_AND "ngr" #define __ATOMIC64_ADD "agr" +#define __ATOMIC64_XOR "xgr" #define __ATOMIC64_BARRIER "\n" #define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier) \ @@ -247,16 +263,6 @@ static inline void atomic64_add(long long i, atomic64_t *v) __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_NO_BARRIER); } -static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v) -{ - __ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND, __ATOMIC64_NO_BARRIER); -} - -static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v) -{ - __ATOMIC64_LOOP(v, mask, __ATOMIC64_OR, __ATOMIC64_NO_BARRIER); -} - #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) static inline long long atomic64_cmpxchg(atomic64_t *v, @@ -270,6 +276,19 @@ static inline long long atomic64_cmpxchg(atomic64_t *v, return old; } +#define ATOMIC64_OP(op, OP) \ +static inline void atomic64_##op(long i, atomic64_t *v) \ +{ \ + __ATOMIC64_LOOP(v, i, __ATOMIC64_##OP, __ATOMIC64_NO_BARRIER); \ +} + +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC64_OP(and, AND) +ATOMIC64_OP(or, OR) +ATOMIC64_OP(xor, XOR) + +#undef ATOMIC64_OP #undef __ATOMIC64_LOOP static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u) -- GitLab From 7fc1845dd45a825b3c2b760df342a94f61fb1113 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 20:28:37 +0200 Subject: [PATCH 1808/7006] x86: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/atomic.h | 33 ++++++++++++++++++++++-------- arch/x86/include/asm/atomic64_32.h | 14 +++++++++++++ arch/x86/include/asm/atomic64_64.h | 15 ++++++++++++++ 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index e9168955c42f4..f3a3ec0406946 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -182,6 +182,23 @@ static inline int atomic_xchg(atomic_t *v, int new) return xchg(&v->counter, new); } +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + asm volatile(LOCK_PREFIX #op"l %1,%0" \ + : "+m" (v->counter) \ + : "ir" (i) \ + : "memory"); \ +} + +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + +#undef ATOMIC_OP + /** * __atomic_add_unless - add unless the number is already a given value * @v: pointer of type atomic_t @@ -219,15 +236,15 @@ static __always_inline short int atomic_inc_short(short int *v) return *v; } -/* These are x86-specific, used by some header files */ -#define atomic_clear_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "andl %0,%1" \ - : : "r" (~(mask)), "m" (*(addr)) : "memory") +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} -#define atomic_set_mask(mask, addr) \ - asm volatile(LOCK_PREFIX "orl %0,%1" \ - : : "r" ((unsigned)(mask)), "m" (*(addr)) \ - : "memory") +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} #ifdef CONFIG_X86_32 # include diff --git a/arch/x86/include/asm/atomic64_32.h b/arch/x86/include/asm/atomic64_32.h index b154de75c90cb..a11c30b77fb57 100644 --- a/arch/x86/include/asm/atomic64_32.h +++ b/arch/x86/include/asm/atomic64_32.h @@ -313,4 +313,18 @@ static inline long long atomic64_dec_if_positive(atomic64_t *v) #undef alternative_atomic64 #undef __alternative_atomic64 +#define ATOMIC64_OP(op, c_op) \ +static inline void atomic64_##op(long long i, atomic64_t *v) \ +{ \ + long long old, c = 0; \ + while ((old = atomic64_cmpxchg(v, c, c c_op i)) != c) \ + c = old; \ +} + +ATOMIC64_OP(and, &) +ATOMIC64_OP(or, |) +ATOMIC64_OP(xor, ^) + +#undef ATOMIC64_OP + #endif /* _ASM_X86_ATOMIC64_32_H */ diff --git a/arch/x86/include/asm/atomic64_64.h b/arch/x86/include/asm/atomic64_64.h index b965f9e03f2a0..50e33eff58de7 100644 --- a/arch/x86/include/asm/atomic64_64.h +++ b/arch/x86/include/asm/atomic64_64.h @@ -220,4 +220,19 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) return dec; } +#define ATOMIC64_OP(op) \ +static inline void atomic64_##op(long i, atomic64_t *v) \ +{ \ + asm volatile(LOCK_PREFIX #op"q %1,%0" \ + : "+m" (v->counter) \ + : "er" (i) \ + : "memory"); \ +} + +ATOMIC64_OP(and) +ATOMIC64_OP(or) +ATOMIC64_OP(xor) + +#undef ATOMIC64_OP + #endif /* _ASM_X86_ATOMIC64_64_H */ -- GitLab From b0d8003ef405c4148b703cdaab1171045c6c3bbd Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Apr 2015 00:49:20 +0200 Subject: [PATCH 1809/7006] frv: Rewrite atomic implementation Mostly complete rewrite of the FRV atomic implementation, instead of using assembly files, use inline assembler. The out-of-line CONFIG option makes a bit of a mess of things, but a little CPP trickery gets that done too. FRV already had the atomic logic ops but under a non standard name, the reimplementation provides the generic names and provides the intermediate form required for the bitops implementation. The slightly inconsistent __atomic32_fetch_##op naming is because __atomic_fetch_##op conlicts with GCC builtin functions. The 64bit atomic ops use the inline assembly %Ln construct to access the low word register (r+1), afaik this construct was not previously used in the kernel and is completely undocumented, but I found it in the FRV GCC code and it seems to work. FRV had a non-standard definition of atomic_{clear,set}_mask() which would work types other than atomic_t, the one user relying on that (arch/frv/kernel/dma.c) got converted to use the new intermediate form. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/frv/include/asm/atomic.h | 119 +++++++++++--------- arch/frv/include/asm/atomic_defs.h | 172 +++++++++++++++++++++++++++++ arch/frv/include/asm/bitops.h | 99 ++--------------- arch/frv/kernel/dma.c | 6 +- arch/frv/kernel/frv_ksyms.c | 5 - arch/frv/lib/Makefile | 2 +- arch/frv/lib/atomic-lib.c | 7 ++ arch/frv/lib/atomic-ops.S | 110 ------------------ arch/frv/lib/atomic64-ops.S | 94 ---------------- 9 files changed, 259 insertions(+), 355 deletions(-) create mode 100644 arch/frv/include/asm/atomic_defs.h create mode 100644 arch/frv/lib/atomic-lib.c diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 102190a61d65a..74d22454d7c63 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -15,7 +15,6 @@ #define _ASM_ATOMIC_H #include -#include #include #include @@ -23,6 +22,8 @@ #error not SMP safe #endif +#include + /* * Atomic operations that C can't guarantee us. Useful for * resource counting etc.. @@ -34,56 +35,26 @@ #define atomic_read(v) ACCESS_ONCE((v)->counter) #define atomic_set(v, i) (((v)->counter) = (i)) -#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS -static inline int atomic_add_return(int i, atomic_t *v) +static inline int atomic_inc_return(atomic_t *v) { - unsigned long val; + return __atomic_add_return(1, &v->counter); +} - asm("0: \n" - " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ - " ckeq icc3,cc7 \n" - " ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ - " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ - " add%I2 %1,%2,%1 \n" - " cst.p %1,%M0 ,cc3,#1 \n" - " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ - " beq icc3,#0,0b \n" - : "+U"(v->counter), "=&r"(val) - : "NPr"(i) - : "memory", "cc7", "cc3", "icc3" - ); +static inline int atomic_dec_return(atomic_t *v) +{ + return __atomic_sub_return(1, &v->counter); +} - return val; +static inline int atomic_add_return(int i, atomic_t *v) +{ + return __atomic_add_return(i, &v->counter); } static inline int atomic_sub_return(int i, atomic_t *v) { - unsigned long val; - - asm("0: \n" - " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ - " ckeq icc3,cc7 \n" - " ld.p %M0,%1 \n" /* LD.P/ORCR must be atomic */ - " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ - " sub%I2 %1,%2,%1 \n" - " cst.p %1,%M0 ,cc3,#1 \n" - " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* clear ICC3.Z if store happens */ - " beq icc3,#0,0b \n" - : "+U"(v->counter), "=&r"(val) - : "NPr"(i) - : "memory", "cc7", "cc3", "icc3" - ); - - return val; + return __atomic_sub_return(i, &v->counter); } -#else - -extern int atomic_add_return(int i, atomic_t *v); -extern int atomic_sub_return(int i, atomic_t *v); - -#endif - static inline int atomic_add_negative(int i, atomic_t *v) { return atomic_add_return(i, v) < 0; @@ -101,17 +72,14 @@ static inline void atomic_sub(int i, atomic_t *v) static inline void atomic_inc(atomic_t *v) { - atomic_add_return(1, v); + atomic_inc_return(v); } static inline void atomic_dec(atomic_t *v) { - atomic_sub_return(1, v); + atomic_dec_return(v); } -#define atomic_dec_return(v) atomic_sub_return(1, (v)) -#define atomic_inc_return(v) atomic_add_return(1, (v)) - #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0) #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0) #define atomic_inc_and_test(v) (atomic_add_return(1, (v)) == 0) @@ -120,18 +88,19 @@ static inline void atomic_dec(atomic_t *v) * 64-bit atomic ops */ typedef struct { - volatile long long counter; + long long counter; } atomic64_t; #define ATOMIC64_INIT(i) { (i) } -static inline long long atomic64_read(atomic64_t *v) +static inline long long atomic64_read(const atomic64_t *v) { long long counter; asm("ldd%I1 %M1,%0" : "=e"(counter) : "m"(v->counter)); + return counter; } @@ -142,10 +111,25 @@ static inline void atomic64_set(atomic64_t *v, long long i) : "e"(i)); } -extern long long atomic64_inc_return(atomic64_t *v); -extern long long atomic64_dec_return(atomic64_t *v); -extern long long atomic64_add_return(long long i, atomic64_t *v); -extern long long atomic64_sub_return(long long i, atomic64_t *v); +static inline long long atomic64_inc_return(atomic64_t *v) +{ + return __atomic64_add_return(1, &v->counter); +} + +static inline long long atomic64_dec_return(atomic64_t *v) +{ + return __atomic64_sub_return(1, &v->counter); +} + +static inline long long atomic64_add_return(long long i, atomic64_t *v) +{ + return __atomic64_add_return(i, &v->counter); +} + +static inline long long atomic64_sub_return(long long i, atomic64_t *v) +{ + return __atomic64_sub_return(i, &v->counter); +} static inline long long atomic64_add_negative(long long i, atomic64_t *v) { @@ -176,6 +160,7 @@ static inline void atomic64_dec(atomic64_t *v) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_and_test(v) (atomic64_inc_return((v)) == 0) + #define atomic_cmpxchg(v, old, new) (cmpxchg(&(v)->counter, old, new)) #define atomic_xchg(v, new) (xchg(&(v)->counter, new)) #define atomic64_cmpxchg(v, old, new) (__cmpxchg_64(old, new, &(v)->counter)) @@ -196,5 +181,33 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return c; } +#define ATOMIC_OP(op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + (void)__atomic32_fetch_##op(i, &v->counter); \ +} \ + \ +static inline void atomic64_##op(long long i, atomic64_t *v) \ +{ \ + (void)__atomic64_fetch_##op(i, &v->counter); \ +} + +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(or) +ATOMIC_OP(and) +ATOMIC_OP(xor) + +#undef ATOMIC_OP + +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} + +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} #endif /* _ASM_ATOMIC_H */ diff --git a/arch/frv/include/asm/atomic_defs.h b/arch/frv/include/asm/atomic_defs.h new file mode 100644 index 0000000000000..36e126d2f801a --- /dev/null +++ b/arch/frv/include/asm/atomic_defs.h @@ -0,0 +1,172 @@ + +#include + +#ifdef __ATOMIC_LIB__ + +#ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS + +#define ATOMIC_QUALS +#define ATOMIC_EXPORT(x) EXPORT_SYMBOL(x) + +#else /* !OUTOFLINE && LIB */ + +#define ATOMIC_OP_RETURN(op) +#define ATOMIC_FETCH_OP(op) + +#endif /* OUTOFLINE */ + +#else /* !__ATOMIC_LIB__ */ + +#define ATOMIC_EXPORT(x) + +#ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS + +#define ATOMIC_OP_RETURN(op) \ +extern int __atomic_##op##_return(int i, int *v); \ +extern long long __atomic64_##op##_return(long long i, long long *v); + +#define ATOMIC_FETCH_OP(op) \ +extern int __atomic32_fetch_##op(int i, int *v); \ +extern long long __atomic64_fetch_##op(long long i, long long *v); + +#else /* !OUTOFLINE && !LIB */ + +#define ATOMIC_QUALS static inline + +#endif /* OUTOFLINE */ +#endif /* __ATOMIC_LIB__ */ + + +/* + * Note on the 64 bit inline asm variants... + * + * CSTD is a conditional instruction and needs a constrained memory reference. + * Normally 'U' provides the correct constraints for conditional instructions + * and this is used for the 32 bit version, however 'U' does not appear to work + * for 64 bit values (gcc-4.9) + * + * The exact constraint is that conditional instructions cannot deal with an + * immediate displacement in the memory reference, so what we do is we read the + * address through a volatile cast into a local variable in order to insure we + * _have_ to compute the correct address without displacement. This allows us + * to use the regular 'm' for the memory address. + * + * Furthermore, the %Ln operand, which prints the low word register (r+1), + * really only works for registers, this means we cannot allow immediate values + * for the 64 bit versions -- like we do for the 32 bit ones. + * + */ + +#ifndef ATOMIC_OP_RETURN +#define ATOMIC_OP_RETURN(op) \ +ATOMIC_QUALS int __atomic_##op##_return(int i, int *v) \ +{ \ + int val; \ + \ + asm volatile( \ + "0: \n" \ + " orcc gr0,gr0,gr0,icc3 \n" \ + " ckeq icc3,cc7 \n" \ + " ld.p %M0,%1 \n" \ + " orcr cc7,cc7,cc3 \n" \ + " "#op"%I2 %1,%2,%1 \n" \ + " cst.p %1,%M0 ,cc3,#1 \n" \ + " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ + " beq icc3,#0,0b \n" \ + : "+U"(*v), "=&r"(val) \ + : "NPr"(i) \ + : "memory", "cc7", "cc3", "icc3" \ + ); \ + \ + return val; \ +} \ +ATOMIC_EXPORT(__atomic_##op##_return); \ + \ +ATOMIC_QUALS long long __atomic64_##op##_return(long long i, long long *v) \ +{ \ + long long *__v = READ_ONCE(v); \ + long long val; \ + \ + asm volatile( \ + "0: \n" \ + " orcc gr0,gr0,gr0,icc3 \n" \ + " ckeq icc3,cc7 \n" \ + " ldd.p %M0,%1 \n" \ + " orcr cc7,cc7,cc3 \n" \ + " "#op"cc %L1,%L2,%L1,icc0 \n" \ + " "#op"x %1,%2,%1,icc0 \n" \ + " cstd.p %1,%M0 ,cc3,#1 \n" \ + " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ + " beq icc3,#0,0b \n" \ + : "+m"(*__v), "=&e"(val) \ + : "e"(i) \ + : "memory", "cc7", "cc3", "icc0", "icc3" \ + ); \ + \ + return val; \ +} \ +ATOMIC_EXPORT(__atomic64_##op##_return); +#endif + +#ifndef ATOMIC_FETCH_OP +#define ATOMIC_FETCH_OP(op) \ +ATOMIC_QUALS int __atomic32_fetch_##op(int i, int *v) \ +{ \ + int old, tmp; \ + \ + asm volatile( \ + "0: \n" \ + " orcc gr0,gr0,gr0,icc3 \n" \ + " ckeq icc3,cc7 \n" \ + " ld.p %M0,%1 \n" \ + " orcr cc7,cc7,cc3 \n" \ + " "#op"%I3 %1,%3,%2 \n" \ + " cst.p %2,%M0 ,cc3,#1 \n" \ + " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ + " beq icc3,#0,0b \n" \ + : "+U"(*v), "=&r"(old), "=r"(tmp) \ + : "NPr"(i) \ + : "memory", "cc7", "cc3", "icc3" \ + ); \ + \ + return old; \ +} \ +ATOMIC_EXPORT(__atomic32_fetch_##op); \ + \ +ATOMIC_QUALS long long __atomic64_fetch_##op(long long i, long long *v) \ +{ \ + long long *__v = READ_ONCE(v); \ + long long old, tmp; \ + \ + asm volatile( \ + "0: \n" \ + " orcc gr0,gr0,gr0,icc3 \n" \ + " ckeq icc3,cc7 \n" \ + " ldd.p %M0,%1 \n" \ + " orcr cc7,cc7,cc3 \n" \ + " "#op" %L1,%L3,%L2 \n" \ + " "#op" %1,%3,%2 \n" \ + " cstd.p %2,%M0 ,cc3,#1 \n" \ + " corcc gr29,gr29,gr0 ,cc3,#1 \n" \ + " beq icc3,#0,0b \n" \ + : "+m"(*__v), "=&e"(old), "=e"(tmp) \ + : "e"(i) \ + : "memory", "cc7", "cc3", "icc3" \ + ); \ + \ + return old; \ +} \ +ATOMIC_EXPORT(__atomic64_fetch_##op); +#endif + +ATOMIC_FETCH_OP(or) +ATOMIC_FETCH_OP(and) +ATOMIC_FETCH_OP(xor) + +ATOMIC_OP_RETURN(add) +ATOMIC_OP_RETURN(sub) + +#undef ATOMIC_FETCH_OP +#undef ATOMIC_OP_RETURN +#undef ATOMIC_QUALS +#undef ATOMIC_EXPORT diff --git a/arch/frv/include/asm/bitops.h b/arch/frv/include/asm/bitops.h index 96de220ef131e..0df8e95e37151 100644 --- a/arch/frv/include/asm/bitops.h +++ b/arch/frv/include/asm/bitops.h @@ -25,109 +25,30 @@ #include -#ifndef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS -static inline -unsigned long atomic_test_and_ANDNOT_mask(unsigned long mask, volatile unsigned long *v) -{ - unsigned long old, tmp; - - asm volatile( - "0: \n" - " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ - " ckeq icc3,cc7 \n" - " ld.p %M0,%1 \n" /* LD.P/ORCR are atomic */ - " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ - " and%I3 %1,%3,%2 \n" - " cst.p %2,%M0 ,cc3,#1 \n" /* if store happens... */ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* ... clear ICC3.Z */ - " beq icc3,#0,0b \n" - : "+U"(*v), "=&r"(old), "=r"(tmp) - : "NPr"(~mask) - : "memory", "cc7", "cc3", "icc3" - ); - - return old; -} - -static inline -unsigned long atomic_test_and_OR_mask(unsigned long mask, volatile unsigned long *v) -{ - unsigned long old, tmp; - - asm volatile( - "0: \n" - " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ - " ckeq icc3,cc7 \n" - " ld.p %M0,%1 \n" /* LD.P/ORCR are atomic */ - " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ - " or%I3 %1,%3,%2 \n" - " cst.p %2,%M0 ,cc3,#1 \n" /* if store happens... */ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* ... clear ICC3.Z */ - " beq icc3,#0,0b \n" - : "+U"(*v), "=&r"(old), "=r"(tmp) - : "NPr"(mask) - : "memory", "cc7", "cc3", "icc3" - ); - - return old; -} - -static inline -unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsigned long *v) -{ - unsigned long old, tmp; - - asm volatile( - "0: \n" - " orcc gr0,gr0,gr0,icc3 \n" /* set ICC3.Z */ - " ckeq icc3,cc7 \n" - " ld.p %M0,%1 \n" /* LD.P/ORCR are atomic */ - " orcr cc7,cc7,cc3 \n" /* set CC3 to true */ - " xor%I3 %1,%3,%2 \n" - " cst.p %2,%M0 ,cc3,#1 \n" /* if store happens... */ - " corcc gr29,gr29,gr0 ,cc3,#1 \n" /* ... clear ICC3.Z */ - " beq icc3,#0,0b \n" - : "+U"(*v), "=&r"(old), "=r"(tmp) - : "NPr"(mask) - : "memory", "cc7", "cc3", "icc3" - ); - - return old; -} - -#else - -extern unsigned long atomic_test_and_ANDNOT_mask(unsigned long mask, volatile unsigned long *v); -extern unsigned long atomic_test_and_OR_mask(unsigned long mask, volatile unsigned long *v); -extern unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsigned long *v); - -#endif - -#define atomic_clear_mask(mask, v) atomic_test_and_ANDNOT_mask((mask), (v)) -#define atomic_set_mask(mask, v) atomic_test_and_OR_mask((mask), (v)) +#include static inline int test_and_clear_bit(unsigned long nr, volatile void *addr) { - volatile unsigned long *ptr = addr; - unsigned long mask = 1UL << (nr & 31); + unsigned int *ptr = (void *)addr; + unsigned int mask = 1UL << (nr & 31); ptr += nr >> 5; - return (atomic_test_and_ANDNOT_mask(mask, ptr) & mask) != 0; + return (__atomic32_fetch_and(~mask, ptr) & mask) != 0; } static inline int test_and_set_bit(unsigned long nr, volatile void *addr) { - volatile unsigned long *ptr = addr; - unsigned long mask = 1UL << (nr & 31); + unsigned int *ptr = (void *)addr; + unsigned int mask = 1UL << (nr & 31); ptr += nr >> 5; - return (atomic_test_and_OR_mask(mask, ptr) & mask) != 0; + return (__atomic32_fetch_or(mask, ptr) & mask) != 0; } static inline int test_and_change_bit(unsigned long nr, volatile void *addr) { - volatile unsigned long *ptr = addr; - unsigned long mask = 1UL << (nr & 31); + unsigned int *ptr = (void *)addr; + unsigned int mask = 1UL << (nr & 31); ptr += nr >> 5; - return (atomic_test_and_XOR_mask(mask, ptr) & mask) != 0; + return (__atomic32_fetch_xor(mask, ptr) & mask) != 0; } static inline void clear_bit(unsigned long nr, volatile void *addr) diff --git a/arch/frv/kernel/dma.c b/arch/frv/kernel/dma.c index 156184e17e57d..370dc9fa0b119 100644 --- a/arch/frv/kernel/dma.c +++ b/arch/frv/kernel/dma.c @@ -109,13 +109,13 @@ static struct frv_dma_channel frv_dma_channels[FRV_DMA_NCHANS] = { static DEFINE_RWLOCK(frv_dma_channels_lock); -unsigned long frv_dma_inprogress; +unsigned int frv_dma_inprogress; #define frv_clear_dma_inprogress(channel) \ - atomic_clear_mask(1 << (channel), &frv_dma_inprogress); + (void)__atomic32_fetch_and(~(1 << (channel)), &frv_dma_inprogress); #define frv_set_dma_inprogress(channel) \ - atomic_set_mask(1 << (channel), &frv_dma_inprogress); + (void)__atomic32_fetch_or(1 << (channel), &frv_dma_inprogress); /*****************************************************************************/ /* diff --git a/arch/frv/kernel/frv_ksyms.c b/arch/frv/kernel/frv_ksyms.c index 86c516d96dcda..cdb4ce9960ebe 100644 --- a/arch/frv/kernel/frv_ksyms.c +++ b/arch/frv/kernel/frv_ksyms.c @@ -58,11 +58,6 @@ EXPORT_SYMBOL(__outsl_ns); EXPORT_SYMBOL(__insl_ns); #ifdef CONFIG_FRV_OUTOFLINE_ATOMIC_OPS -EXPORT_SYMBOL(atomic_test_and_ANDNOT_mask); -EXPORT_SYMBOL(atomic_test_and_OR_mask); -EXPORT_SYMBOL(atomic_test_and_XOR_mask); -EXPORT_SYMBOL(atomic_add_return); -EXPORT_SYMBOL(atomic_sub_return); EXPORT_SYMBOL(__xchg_32); EXPORT_SYMBOL(__cmpxchg_32); #endif diff --git a/arch/frv/lib/Makefile b/arch/frv/lib/Makefile index 4ff2fb1e6b169..970e8b4f1a026 100644 --- a/arch/frv/lib/Makefile +++ b/arch/frv/lib/Makefile @@ -5,4 +5,4 @@ lib-y := \ __ashldi3.o __lshrdi3.o __muldi3.o __ashrdi3.o __negdi2.o __ucmpdi2.o \ checksum.o memcpy.o memset.o atomic-ops.o atomic64-ops.o \ - outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o + outsl_ns.o outsl_sw.o insl_ns.o insl_sw.o cache.o atomic-lib.o diff --git a/arch/frv/lib/atomic-lib.c b/arch/frv/lib/atomic-lib.c new file mode 100644 index 0000000000000..4d1b887c248bd --- /dev/null +++ b/arch/frv/lib/atomic-lib.c @@ -0,0 +1,7 @@ + +#include +#include + +#define __ATOMIC_LIB__ + +#include diff --git a/arch/frv/lib/atomic-ops.S b/arch/frv/lib/atomic-ops.S index 5e9e6ab5dd0e8..b7439a960b5ba 100644 --- a/arch/frv/lib/atomic-ops.S +++ b/arch/frv/lib/atomic-ops.S @@ -17,116 +17,6 @@ .text .balign 4 -############################################################################### -# -# unsigned long atomic_test_and_ANDNOT_mask(unsigned long mask, volatile unsigned long *v); -# -############################################################################### - .globl atomic_test_and_ANDNOT_mask - .type atomic_test_and_ANDNOT_mask,@function -atomic_test_and_ANDNOT_mask: - not.p gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ld.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - and gr8,gr10,gr11 - cst.p gr11,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic_test_and_ANDNOT_mask, .-atomic_test_and_ANDNOT_mask - -############################################################################### -# -# unsigned long atomic_test_and_OR_mask(unsigned long mask, volatile unsigned long *v); -# -############################################################################### - .globl atomic_test_and_OR_mask - .type atomic_test_and_OR_mask,@function -atomic_test_and_OR_mask: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ld.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - or gr8,gr10,gr11 - cst.p gr11,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic_test_and_OR_mask, .-atomic_test_and_OR_mask - -############################################################################### -# -# unsigned long atomic_test_and_XOR_mask(unsigned long mask, volatile unsigned long *v); -# -############################################################################### - .globl atomic_test_and_XOR_mask - .type atomic_test_and_XOR_mask,@function -atomic_test_and_XOR_mask: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ld.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - xor gr8,gr10,gr11 - cst.p gr11,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic_test_and_XOR_mask, .-atomic_test_and_XOR_mask - -############################################################################### -# -# int atomic_add_return(int i, atomic_t *v) -# -############################################################################### - .globl atomic_add_return - .type atomic_add_return,@function -atomic_add_return: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ld.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - add gr8,gr10,gr8 - cst.p gr8,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic_add_return, .-atomic_add_return - -############################################################################### -# -# int atomic_sub_return(int i, atomic_t *v) -# -############################################################################### - .globl atomic_sub_return - .type atomic_sub_return,@function -atomic_sub_return: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ld.p @(gr9,gr0),gr8 /* LD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - sub gr8,gr10,gr8 - cst.p gr8,@(gr9,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic_sub_return, .-atomic_sub_return - ############################################################################### # # uint32_t __xchg_32(uint32_t i, uint32_t *v) diff --git a/arch/frv/lib/atomic64-ops.S b/arch/frv/lib/atomic64-ops.S index b6194eeac127e..c4c472308a33a 100644 --- a/arch/frv/lib/atomic64-ops.S +++ b/arch/frv/lib/atomic64-ops.S @@ -18,100 +18,6 @@ .balign 4 -############################################################################### -# -# long long atomic64_inc_return(atomic64_t *v) -# -############################################################################### - .globl atomic64_inc_return - .type atomic64_inc_return,@function -atomic64_inc_return: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ldd.p @(gr10,gr0),gr8 /* LDD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - addicc gr9,#1,gr9,icc0 - addxi gr8,#0,gr8,icc0 - cstd.p gr8,@(gr10,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic64_inc_return, .-atomic64_inc_return - -############################################################################### -# -# long long atomic64_dec_return(atomic64_t *v) -# -############################################################################### - .globl atomic64_dec_return - .type atomic64_dec_return,@function -atomic64_dec_return: - or.p gr8,gr8,gr10 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ldd.p @(gr10,gr0),gr8 /* LDD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - subicc gr9,#1,gr9,icc0 - subxi gr8,#0,gr8,icc0 - cstd.p gr8,@(gr10,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic64_dec_return, .-atomic64_dec_return - -############################################################################### -# -# long long atomic64_add_return(long long i, atomic64_t *v) -# -############################################################################### - .globl atomic64_add_return - .type atomic64_add_return,@function -atomic64_add_return: - or.p gr8,gr8,gr4 - or gr9,gr9,gr5 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ldd.p @(gr10,gr0),gr8 /* LDD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - addcc gr9,gr5,gr9,icc0 - addx gr8,gr4,gr8,icc0 - cstd.p gr8,@(gr10,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic64_add_return, .-atomic64_add_return - -############################################################################### -# -# long long atomic64_sub_return(long long i, atomic64_t *v) -# -############################################################################### - .globl atomic64_sub_return - .type atomic64_sub_return,@function -atomic64_sub_return: - or.p gr8,gr8,gr4 - or gr9,gr9,gr5 -0: - orcc gr0,gr0,gr0,icc3 /* set ICC3.Z */ - ckeq icc3,cc7 - ldd.p @(gr10,gr0),gr8 /* LDD.P/ORCR must be atomic */ - orcr cc7,cc7,cc3 /* set CC3 to true */ - subcc gr9,gr5,gr9,icc0 - subx gr8,gr4,gr8,icc0 - cstd.p gr8,@(gr10,gr0) ,cc3,#1 - corcc gr29,gr29,gr0 ,cc3,#1 /* clear ICC3.Z if store happens */ - beq icc3,#0,0b - bralr - - .size atomic64_sub_return, .-atomic64_sub_return - ############################################################################### # # uint64_t __xchg_64(uint64_t i, uint64_t *v) -- GitLab From 73ada3700bbb0a4c7cc06ea8d74e93c689f90cdb Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 10 Jul 2015 12:55:45 +0200 Subject: [PATCH 1810/7006] h8300: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and} These will replace the atomic_{set,clear}_mask functions that are available on some archs. Also rework the atomic implementation in terms of CPP macros to avoid the typical repetition -- I seem to have missed this arch the last time around when I did that. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/h8300/include/asm/atomic.h | 135 ++++++++++---------------------- 1 file changed, 40 insertions(+), 95 deletions(-) diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index 7ca73f8546cc8..f181f820be332 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -16,83 +16,54 @@ #include -static inline int atomic_add_return(int i, atomic_t *v) -{ - h8300flags flags; - int ret; - - flags = arch_local_irq_save(); - ret = v->counter += i; - arch_local_irq_restore(flags); - return ret; +#define ATOMIC_OP_RETURN(op, c_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + h8300flags flags; \ + int ret; \ + \ + flags = arch_local_irq_save(); \ + ret = v->counter c_op i; \ + arch_local_irq_restore(flags); \ + return ret; \ } -#define atomic_add(i, v) atomic_add_return(i, v) -#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) - -static inline int atomic_sub_return(int i, atomic_t *v) -{ - h8300flags flags; - int ret; - - flags = arch_local_irq_save(); - ret = v->counter -= i; - arch_local_irq_restore(flags); - return ret; +#define ATOMIC_OP(op, c_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + h8300flags flags; \ + \ + flags = arch_local_irq_save(); \ + v->counter c_op i; \ + arch_local_irq_restore(flags); \ } -#define atomic_sub(i, v) atomic_sub_return(i, v) -#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) +ATOMIC_OP_RETURN(add, +=) +ATOMIC_OP_RETURN(sub, -=) -static inline int atomic_inc_return(atomic_t *v) -{ - h8300flags flags; - int ret; - - flags = arch_local_irq_save(); - v->counter++; - ret = v->counter; - arch_local_irq_restore(flags); - return ret; -} +#define CONFIG_ARCH_HAS_ATOMIC_OR -#define atomic_inc(v) atomic_inc_return(v) +ATOMIC_OP(and, &=) +ATOMIC_OP(or, |=) +ATOMIC_OP(xor, ^=) -/* - * atomic_inc_and_test - increment and test - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1 - * and returns true if the result is zero, or false for all - * other cases. - */ -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP -static inline int atomic_dec_return(atomic_t *v) -{ - h8300flags flags; - int ret; +#define atomic_add(i, v) (void)atomic_add_return(i, v) +#define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) - flags = arch_local_irq_save(); - --v->counter; - ret = v->counter; - arch_local_irq_restore(flags); - return ret; -} +#define atomic_sub(i, v) (void)atomic_sub_return(i, v) +#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) -#define atomic_dec(v) atomic_dec_return(v) +#define atomic_inc_return(v) atomic_add_return(1, v) +#define atomic_dec_return(v) atomic_sub_return(1, v) -static inline int atomic_dec_and_test(atomic_t *v) -{ - h8300flags flags; - int ret; +#define atomic_inc(v) (void)atomic_inc_return(v) +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) - flags = arch_local_irq_save(); - --v->counter; - ret = v->counter; - arch_local_irq_restore(flags); - return ret == 0; -} +#define atomic_dec(v) (void)atomic_dec_return(v) +#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { @@ -120,40 +91,14 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return ret; } -static inline void atomic_clear_mask(unsigned long mask, unsigned long *v) +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) { - unsigned char ccr; - unsigned long tmp; - - __asm__ __volatile__("stc ccr,%w3\n\t" - "orc #0x80,ccr\n\t" - "mov.l %0,%1\n\t" - "and.l %2,%1\n\t" - "mov.l %1,%0\n\t" - "ldc %w3,ccr" - : "=m"(*v), "=r"(tmp) - : "g"(~(mask)), "r"(ccr)); + atomic_and(~mask, v); } -static inline void atomic_set_mask(unsigned long mask, unsigned long *v) +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) { - unsigned char ccr; - unsigned long tmp; - - __asm__ __volatile__("stc ccr,%w3\n\t" - "orc #0x80,ccr\n\t" - "mov.l %0,%1\n\t" - "or.l %2,%1\n\t" - "mov.l %1,%0\n\t" - "ldc %w3,ccr" - : "=m"(*v), "=r"(tmp) - : "g"(~(mask)), "r"(ccr)); + atomic_or(mask, v); } -/* Atomic operations are already serializing */ -#define smp_mb__before_atomic_dec() barrier() -#define smp_mb__after_atomic_dec() barrier() -#define smp_mb__before_atomic_inc() barrier() -#define smp_mb__after_atomic_inc() barrier() - #endif /* __ARCH_H8300_ATOMIC __ */ -- GitLab From 2957c035395e492463d7f589af9dd32388967bbb Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Thu, 9 Jul 2015 16:38:17 -0400 Subject: [PATCH 1811/7006] tile: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. For tilegx, these are relatively straightforward; the architecture provides atomic "or" and "and", both 32-bit and 64-bit. To support xor we provide a loop using "cmpexch". For the older 32-bit tilepro architecture, we have to extend the set of low-level assembly routines to include 32-bit "and", as well as all three 64-bit routines. Somewhat confusingly, some 32-bit versions are already used by the bitops inlines, with parameter types appropriate for bitops, so we have to do a bit of casting to match "int" to "unsigned long". Signed-off-by: Chris Metcalf Signed-off-by: Peter Zijlstra (Intel) Link: http://lkml.kernel.org/r/1436474297-32187-1-git-send-email-cmetcalf@ezchip.com Signed-off-by: Thomas Gleixner --- arch/tile/include/asm/atomic_32.h | 30 ++++++++++++++++++++++ arch/tile/include/asm/atomic_64.h | 42 +++++++++++++++++++++++++++++++ arch/tile/lib/atomic_32.c | 23 +++++++++++++++++ arch/tile/lib/atomic_asm_32.S | 4 +++ 4 files changed, 99 insertions(+) diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index 1b109fad9fff3..94237922f0dd3 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h @@ -34,6 +34,21 @@ static inline void atomic_add(int i, atomic_t *v) _atomic_xchg_add(&v->counter, i); } +#define ATOMIC_OP(op) \ +unsigned long _atomic_##op(volatile unsigned long *p, unsigned long mask); \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + _atomic_##op((unsigned long *)&v->counter, i); \ +} + +#define CONFIG_ARCH_HAS_ATOMIC_OR + +ATOMIC_OP(and) +ATOMIC_OP(or) +ATOMIC_OP(xor) + +#undef ATOMIC_OP + /** * atomic_add_return - add integer and return * @v: pointer of type atomic_t @@ -113,6 +128,17 @@ static inline void atomic64_add(long long i, atomic64_t *v) _atomic64_xchg_add(&v->counter, i); } +#define ATOMIC64_OP(op) \ +long long _atomic64_##op(long long *v, long long n); \ +static inline void atomic64_##op(long long i, atomic64_t *v) \ +{ \ + _atomic64_##op(&v->counter, i); \ +} + +ATOMIC64_OP(and) +ATOMIC64_OP(or) +ATOMIC64_OP(xor) + /** * atomic64_add_return - add integer and return * @v: pointer of type atomic64_t @@ -225,6 +251,7 @@ extern struct __get_user __atomic_xchg_add(volatile int *p, int *lock, int n); extern struct __get_user __atomic_xchg_add_unless(volatile int *p, int *lock, int o, int n); extern struct __get_user __atomic_or(volatile int *p, int *lock, int n); +extern struct __get_user __atomic_and(volatile int *p, int *lock, int n); extern struct __get_user __atomic_andn(volatile int *p, int *lock, int n); extern struct __get_user __atomic_xor(volatile int *p, int *lock, int n); extern long long __atomic64_cmpxchg(volatile long long *p, int *lock, @@ -234,6 +261,9 @@ extern long long __atomic64_xchg_add(volatile long long *p, int *lock, long long n); extern long long __atomic64_xchg_add_unless(volatile long long *p, int *lock, long long o, long long n); +extern long long __atomic64_and(volatile long long *p, int *lock, long long n); +extern long long __atomic64_or(volatile long long *p, int *lock, long long n); +extern long long __atomic64_xor(volatile long long *p, int *lock, long long n); /* Return failure from the atomic wrappers. */ struct __get_user __atomic_bad_address(int __user *addr); diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index 0496970cef829..d07d9fc6e2a16 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h @@ -58,6 +58,28 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return oldval; } +#define CONFIG_ARCH_HAS_ATOMIC_OR + +static inline void atomic_and(int i, atomic_t *v) +{ + __insn_fetchand4((void *)&v->counter, i); +} + +static inline void atomic_or(int i, atomic_t *v) +{ + __insn_fetchor4((void *)&v->counter, i); +} + +static inline void atomic_xor(int i, atomic_t *v) +{ + int guess, oldval = v->counter; + do { + guess = oldval; + __insn_mtspr(SPR_CMPEXCH_VALUE, guess); + oldval = __insn_cmpexch4(&v->counter, guess ^ i); + } while (guess != oldval); +} + /* Now the true 64-bit operations. */ #define ATOMIC64_INIT(i) { (i) } @@ -91,6 +113,26 @@ static inline long atomic64_add_unless(atomic64_t *v, long a, long u) return oldval != u; } +static inline void atomic64_and(long i, atomic64_t *v) +{ + __insn_fetchand((void *)&v->counter, i); +} + +static inline void atomic64_or(long i, atomic64_t *v) +{ + __insn_fetchor((void *)&v->counter, i); +} + +static inline void atomic64_xor(long i, atomic64_t *v) +{ + long guess, oldval = v->counter; + do { + guess = oldval; + __insn_mtspr(SPR_CMPEXCH_VALUE, guess); + oldval = __insn_cmpexch(&v->counter, guess ^ i); + } while (guess != oldval); +} + #define atomic64_sub_return(i, v) atomic64_add_return(-(i), (v)) #define atomic64_sub(i, v) atomic64_add(-(i), (v)) #define atomic64_inc_return(v) atomic64_add_return(1, (v)) diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c index c89b211fd9e7c..298df1e9912a1 100644 --- a/arch/tile/lib/atomic_32.c +++ b/arch/tile/lib/atomic_32.c @@ -94,6 +94,12 @@ unsigned long _atomic_or(volatile unsigned long *p, unsigned long mask) } EXPORT_SYMBOL(_atomic_or); +unsigned long _atomic_and(volatile unsigned long *p, unsigned long mask) +{ + return __atomic_and((int *)p, __atomic_setup(p), mask).val; +} +EXPORT_SYMBOL(_atomic_and); + unsigned long _atomic_andn(volatile unsigned long *p, unsigned long mask) { return __atomic_andn((int *)p, __atomic_setup(p), mask).val; @@ -136,6 +142,23 @@ long long _atomic64_cmpxchg(long long *v, long long o, long long n) } EXPORT_SYMBOL(_atomic64_cmpxchg); +long long _atomic64_and(long long *v, long long n) +{ + return __atomic64_and(v, __atomic_setup(v), n); +} +EXPORT_SYMBOL(_atomic64_and); + +long long _atomic64_or(long long *v, long long n) +{ + return __atomic64_or(v, __atomic_setup(v), n); +} +EXPORT_SYMBOL(_atomic64_or); + +long long _atomic64_xor(long long *v, long long n) +{ + return __atomic64_xor(v, __atomic_setup(v), n); +} +EXPORT_SYMBOL(_atomic64_xor); /* * If any of the atomic or futex routines hit a bad address (not in diff --git a/arch/tile/lib/atomic_asm_32.S b/arch/tile/lib/atomic_asm_32.S index 6bda3132cd619..f611265633d69 100644 --- a/arch/tile/lib/atomic_asm_32.S +++ b/arch/tile/lib/atomic_asm_32.S @@ -178,6 +178,7 @@ atomic_op _xchg_add, 32, "add r24, r22, r2" atomic_op _xchg_add_unless, 32, \ "sne r26, r22, r2; { bbns r26, 3f; add r24, r22, r3 }" atomic_op _or, 32, "or r24, r22, r2" +atomic_op _and, 32, "and r24, r22, r2" atomic_op _andn, 32, "nor r2, r2, zero; and r24, r22, r2" atomic_op _xor, 32, "xor r24, r22, r2" @@ -191,6 +192,9 @@ atomic_op 64_xchg_add_unless, 64, \ { bbns r26, 3f; add r24, r22, r4 }; \ { bbns r27, 3f; add r25, r23, r5 }; \ slt_u r26, r24, r22; add r25, r25, r26" +atomic_op 64_or, 64, "{ or r24, r22, r2; or r25, r23, r3 }" +atomic_op 64_and, 64, "{ and r24, r22, r2; and r25, r23, r3 }" +atomic_op 64_xor, 64, "{ xor r24, r22, r2; xor r25, r23, r3 }" jrp lr /* happy backtracer */ -- GitLab From e6942b7de2dfe44ebde9bae57dadece5abca9de8 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Wed, 23 Apr 2014 19:32:50 +0200 Subject: [PATCH 1812/7006] atomic: Provide atomic_{or,xor,and} Implement atomic logic ops -- atomic_{or,xor,and}. These will replace the atomic_{set,clear}_mask functions that are available on some archs. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/alpha/include/asm/atomic.h | 1 - arch/arc/include/asm/atomic.h | 1 - arch/arm/include/asm/atomic.h | 1 - arch/arm64/include/asm/atomic.h | 1 - arch/avr32/include/asm/atomic.h | 2 -- arch/blackfin/include/asm/atomic.h | 2 -- arch/frv/include/asm/atomic.h | 2 -- arch/h8300/include/asm/atomic.h | 2 -- arch/hexagon/include/asm/atomic.h | 2 -- arch/ia64/include/asm/atomic.h | 2 -- arch/m32r/include/asm/atomic.h | 2 -- arch/m68k/include/asm/atomic.h | 2 -- arch/metag/include/asm/atomic_lnkget.h | 2 -- arch/mips/include/asm/atomic.h | 2 -- arch/mn10300/include/asm/atomic.h | 2 -- arch/parisc/include/asm/atomic.h | 2 -- arch/powerpc/include/asm/atomic.h | 2 -- arch/s390/include/asm/atomic.h | 2 -- arch/sh/include/asm/atomic-grb.h | 2 -- arch/sparc/include/asm/atomic_32.h | 2 -- arch/sparc/include/asm/atomic_64.h | 2 -- arch/tile/include/asm/atomic_32.h | 2 -- arch/tile/include/asm/atomic_64.h | 2 -- arch/x86/include/asm/atomic.h | 2 -- arch/xtensa/include/asm/atomic.h | 2 -- include/asm-generic/atomic.h | 21 ++++++++++++--------- include/asm-generic/atomic64.h | 4 ++++ include/linux/atomic.h | 13 ------------- lib/atomic64.c | 3 +++ 29 files changed, 19 insertions(+), 68 deletions(-) diff --git a/arch/alpha/include/asm/atomic.h b/arch/alpha/include/asm/atomic.h index 0eff853398d21..e8c9560984243 100644 --- a/arch/alpha/include/asm/atomic.h +++ b/arch/alpha/include/asm/atomic.h @@ -110,7 +110,6 @@ static __inline__ long atomic64_##op##_return(long i, atomic64_t * v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR #define atomic_andnot atomic_andnot #define atomic64_andnot atomic64_andnot diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index e90b701fc6a87..2a847821dee1a 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -144,7 +144,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR #define atomic_andnot atomic_andnot ATOMIC_OP(and, &=, and) diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h index ff214bac9cb4c..82b75a7cb7627 100644 --- a/arch/arm/include/asm/atomic.h +++ b/arch/arm/include/asm/atomic.h @@ -194,7 +194,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR #define atomic_andnot atomic_andnot ATOMIC_OP(and, &=, and) diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 2876173397b28..866a71fca9a3c 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -85,7 +85,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, add) ATOMIC_OPS(sub, sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR #define atomic_andnot atomic_andnot ATOMIC_OP(and, and) diff --git a/arch/avr32/include/asm/atomic.h b/arch/avr32/include/asm/atomic.h index 115d3005e4bc1..97c9bdf834096 100644 --- a/arch/avr32/include/asm/atomic.h +++ b/arch/avr32/include/asm/atomic.h @@ -51,8 +51,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ (void)__atomic_##op##_return(i, v); \ } -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, and) ATOMIC_OP(or, or) ATOMIC_OP(xor, eor) diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index eafa55b81a7b6..2d6a7a3823c3c 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -28,8 +28,6 @@ asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); #define atomic_add_return(i, v) __raw_atomic_add_asm(&(v)->counter, i) #define atomic_sub_return(i, v) __raw_atomic_add_asm(&(v)->counter, -(i)) -#define CONFIG_ARCH_HAS_ATOMIC_OR - #define atomic_or(i, v) (void)__raw_atomic_or_asm(&(v)->counter, i) #define atomic_and(i, v) (void)__raw_atomic_and_asm(&(v)->counter, i) #define atomic_xor(i, v) (void)__raw_atomic_xor_asm(&(v)->counter, i) diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index 74d22454d7c63..fc48bea26b402 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -192,8 +192,6 @@ static inline void atomic64_##op(long long i, atomic64_t *v) \ (void)__atomic64_fetch_##op(i, &v->counter); \ } -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(or) ATOMIC_OP(and) ATOMIC_OP(xor) diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index f181f820be332..c4d061f09c44d 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -41,8 +41,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ ATOMIC_OP_RETURN(add, +=) ATOMIC_OP_RETURN(sub, -=) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, &=) ATOMIC_OP(or, |=) ATOMIC_OP(xor, ^=) diff --git a/arch/hexagon/include/asm/atomic.h b/arch/hexagon/include/asm/atomic.h index 4efe2c7c0dd86..811d61f6422da 100644 --- a/arch/hexagon/include/asm/atomic.h +++ b/arch/hexagon/include/asm/atomic.h @@ -132,8 +132,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/ia64/include/asm/atomic.h b/arch/ia64/include/asm/atomic.h index 0809ef5d6b9a1..be4beeb77d57c 100644 --- a/arch/ia64/include/asm/atomic.h +++ b/arch/ia64/include/asm/atomic.h @@ -69,8 +69,6 @@ ATOMIC_OP(sub, -) : ia64_atomic_sub(__ia64_asr_i, v); \ }) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, &) ATOMIC_OP(or, |) ATOMIC_OP(xor, ^) diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index 7245463c1e98d..b2a13fbd5be0e 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -94,8 +94,6 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index c30e43ea49a3b..93ebd96aa494b 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -77,8 +77,6 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ ATOMIC_OPS(add, +=, add) ATOMIC_OPS(sub, -=, sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, &=, and) ATOMIC_OP(or, |=, or) ATOMIC_OP(xor, ^=, eor) diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index 930c12cb8d378..0642606de9012 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h @@ -74,8 +74,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h index 0430ba6ab7628..4c42fd9af7778 100644 --- a/arch/mips/include/asm/atomic.h +++ b/arch/mips/include/asm/atomic.h @@ -137,8 +137,6 @@ static __inline__ int atomic_##op##_return(int i, atomic_t * v) \ ATOMIC_OPS(add, +=, addu) ATOMIC_OPS(sub, -=, subu) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, &=, and) ATOMIC_OP(or, |=, or) ATOMIC_OP(xor, ^=, xor) diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index 03eea8158cf95..f5a63f0bda462 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -89,8 +89,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/parisc/include/asm/atomic.h b/arch/parisc/include/asm/atomic.h index be2c50ddebd61..2536965d00eae 100644 --- a/arch/parisc/include/asm/atomic.h +++ b/arch/parisc/include/asm/atomic.h @@ -126,8 +126,6 @@ static __inline__ int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add, +=) ATOMIC_OPS(sub, -=) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, &=) ATOMIC_OP(or, |=) ATOMIC_OP(xor, ^=) diff --git a/arch/powerpc/include/asm/atomic.h b/arch/powerpc/include/asm/atomic.h index 6ca89e2aca159..55f106ed12bf2 100644 --- a/arch/powerpc/include/asm/atomic.h +++ b/arch/powerpc/include/asm/atomic.h @@ -67,8 +67,6 @@ static __inline__ int atomic_##op##_return(int a, atomic_t *v) \ ATOMIC_OPS(add, add) ATOMIC_OPS(sub, subf) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and, and) ATOMIC_OP(or, or) ATOMIC_OP(xor, xor) diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index b3859d8e001ff..d761aeff72da0 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -282,8 +282,6 @@ static inline void atomic64_##op(long i, atomic64_t *v) \ __ATOMIC64_LOOP(v, i, __ATOMIC64_##OP, __ATOMIC64_NO_BARRIER); \ } -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC64_OP(and, AND) ATOMIC64_OP(or, OR) ATOMIC64_OP(xor, XOR) diff --git a/arch/sh/include/asm/atomic-grb.h b/arch/sh/include/asm/atomic-grb.h index 4b03830d48c73..b94df40e5f2d2 100644 --- a/arch/sh/include/asm/atomic-grb.h +++ b/arch/sh/include/asm/atomic-grb.h @@ -48,8 +48,6 @@ static inline int atomic_##op##_return(int i, atomic_t *v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/sparc/include/asm/atomic_32.h b/arch/sparc/include/asm/atomic_32.h index e19d8880b1461..7dcbebbcaec6f 100644 --- a/arch/sparc/include/asm/atomic_32.h +++ b/arch/sparc/include/asm/atomic_32.h @@ -17,8 +17,6 @@ #include #include -#define CONFIG_ARCH_HAS_ATOMIC_OR - #define ATOMIC_INIT(i) { (i) } int atomic_add_return(int, atomic_t *); diff --git a/arch/sparc/include/asm/atomic_64.h b/arch/sparc/include/asm/atomic_64.h index d6af27c934505..917084ace49de 100644 --- a/arch/sparc/include/asm/atomic_64.h +++ b/arch/sparc/include/asm/atomic_64.h @@ -33,8 +33,6 @@ long atomic64_##op##_return(long, atomic64_t *); ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h index 94237922f0dd3..d320ce253d863 100644 --- a/arch/tile/include/asm/atomic_32.h +++ b/arch/tile/include/asm/atomic_32.h @@ -41,8 +41,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ _atomic_##op((unsigned long *)&v->counter, i); \ } -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/tile/include/asm/atomic_64.h b/arch/tile/include/asm/atomic_64.h index d07d9fc6e2a16..096a56d6ead42 100644 --- a/arch/tile/include/asm/atomic_64.h +++ b/arch/tile/include/asm/atomic_64.h @@ -58,8 +58,6 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return oldval; } -#define CONFIG_ARCH_HAS_ATOMIC_OR - static inline void atomic_and(int i, atomic_t *v) { __insn_fetchand4((void *)&v->counter, i); diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index f3a3ec0406946..b3493023efdae 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -191,8 +191,6 @@ static inline void atomic_##op(int i, atomic_t *v) \ : "memory"); \ } -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index 4dd2450300a67..31371f43c23bb 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -145,8 +145,6 @@ static inline int atomic_##op##_return(int i, atomic_t * v) \ ATOMIC_OPS(add) ATOMIC_OPS(sub) -#define CONFIG_ARCH_HAS_ATOMIC_OR - ATOMIC_OP(and) ATOMIC_OP(or) ATOMIC_OP(xor) diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index 92947e0a532a3..a41b0b8f74049 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -102,24 +102,27 @@ ATOMIC_OP_RETURN(sub, -) ATOMIC_OP(and, &) #endif -#ifndef atomic_clear_mask -#define atomic_clear_mask(i, v) atomic_and(~(i), (v)) -#endif - #ifndef atomic_or -#ifndef CONFIG_ARCH_HAS_ATOMIC_OR -#define CONFIG_ARCH_HAS_ATOMIC_OR -#endif ATOMIC_OP(or, |) #endif -#ifndef atomic_set_mask -#define atomic_set_mask(i, v) atomic_or((i), (v)) +#ifndef atomic_xor +ATOMIC_OP(xor, ^) #endif #undef ATOMIC_OP_RETURN #undef ATOMIC_OP +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_and(~mask, v); +} + +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} + /* * Atomic operations that C can't guarantee us. Useful for * resource counting etc.. diff --git a/include/asm-generic/atomic64.h b/include/asm-generic/atomic64.h index 30ad9c86cebb6..d48e78ccad3dd 100644 --- a/include/asm-generic/atomic64.h +++ b/include/asm-generic/atomic64.h @@ -32,6 +32,10 @@ extern long long atomic64_##op##_return(long long a, atomic64_t *v); ATOMIC64_OPS(add) ATOMIC64_OPS(sub) +ATOMIC64_OP(and) +ATOMIC64_OP(or) +ATOMIC64_OP(xor) + #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 5b08a8540ecfc..7d6279012a1fd 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -111,19 +111,6 @@ static inline int atomic_dec_if_positive(atomic_t *v) } #endif -#ifndef CONFIG_ARCH_HAS_ATOMIC_OR -static inline void atomic_or(int i, atomic_t *v) -{ - int old; - int new; - - do { - old = atomic_read(v); - new = old | i; - } while (atomic_cmpxchg(v, old, new) != old); -} -#endif /* #ifndef CONFIG_ARCH_HAS_ATOMIC_OR */ - #include #ifdef CONFIG_GENERIC_ATOMIC64 #include diff --git a/lib/atomic64.c b/lib/atomic64.c index 1298c05ef5284..2886ebac65677 100644 --- a/lib/atomic64.c +++ b/lib/atomic64.c @@ -102,6 +102,9 @@ EXPORT_SYMBOL(atomic64_##op##_return); ATOMIC64_OPS(add, +=) ATOMIC64_OPS(sub, -=) +ATOMIC64_OP(and, &=) +ATOMIC64_OP(or, |=) +ATOMIC64_OP(xor, ^=) #undef ATOMIC64_OPS #undef ATOMIC64_OP_RETURN -- GitLab From de9e432cb5de1bf2952919dc0b22e4bec0ed8d53 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Apr 2015 01:12:32 +0200 Subject: [PATCH 1813/7006] atomic: Collapse all atomic_{set,clear}_mask definitions Move the now generic definitions of atomic_{set,clear}_mask() into linux/atomic.h to avoid endless and pointless repetition. Also, provide an atomic_andnot() wrapper for those few archs that can implement that. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/arc/include/asm/atomic.h | 10 ---------- arch/blackfin/include/asm/atomic.h | 10 ---------- arch/frv/include/asm/atomic.h | 10 ---------- arch/h8300/include/asm/atomic.h | 10 ---------- arch/m32r/include/asm/atomic.h | 11 ----------- arch/m68k/include/asm/atomic.h | 10 ---------- arch/metag/include/asm/atomic_lnkget.h | 10 ---------- arch/metag/include/asm/atomic_lock1.h | 10 ---------- arch/mn10300/include/asm/atomic.h | 24 ------------------------ arch/powerpc/kernel/misc_32.S | 19 ------------------- arch/s390/include/asm/atomic.h | 10 ---------- arch/sh/include/asm/atomic.h | 10 ---------- arch/x86/include/asm/atomic.h | 10 ---------- arch/xtensa/include/asm/atomic.h | 10 ---------- include/asm-generic/atomic.h | 10 ---------- include/linux/atomic.h | 25 +++++++++++++++++++++++++ 16 files changed, 25 insertions(+), 174 deletions(-) diff --git a/arch/arc/include/asm/atomic.h b/arch/arc/include/asm/atomic.h index 2a847821dee1a..d8a85e706fba3 100644 --- a/arch/arc/include/asm/atomic.h +++ b/arch/arc/include/asm/atomic.h @@ -155,16 +155,6 @@ ATOMIC_OP(xor, ^=, xor) #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - /** * __atomic_add_unless - add unless the number is a given value * @v: pointer of type atomic_t diff --git a/arch/blackfin/include/asm/atomic.h b/arch/blackfin/include/asm/atomic.h index 2d6a7a3823c3c..1c1c42330c99c 100644 --- a/arch/blackfin/include/asm/atomic.h +++ b/arch/blackfin/include/asm/atomic.h @@ -32,16 +32,6 @@ asmlinkage int __raw_atomic_test_asm(const volatile int *ptr, int value); #define atomic_and(i, v) (void)__raw_atomic_and_asm(&(v)->counter, i) #define atomic_xor(i, v) (void)__raw_atomic_xor_asm(&(v)->counter, i) -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #endif #include diff --git a/arch/frv/include/asm/atomic.h b/arch/frv/include/asm/atomic.h index fc48bea26b402..0da689def4cc6 100644 --- a/arch/frv/include/asm/atomic.h +++ b/arch/frv/include/asm/atomic.h @@ -198,14 +198,4 @@ ATOMIC_OP(xor) #undef ATOMIC_OP -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #endif /* _ASM_ATOMIC_H */ diff --git a/arch/h8300/include/asm/atomic.h b/arch/h8300/include/asm/atomic.h index c4d061f09c44d..702ee539f87da 100644 --- a/arch/h8300/include/asm/atomic.h +++ b/arch/h8300/include/asm/atomic.h @@ -89,14 +89,4 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) return ret; } -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #endif /* __ARCH_H8300_ATOMIC __ */ diff --git a/arch/m32r/include/asm/atomic.h b/arch/m32r/include/asm/atomic.h index b2a13fbd5be0e..025e2a1704936 100644 --- a/arch/m32r/include/asm/atomic.h +++ b/arch/m32r/include/asm/atomic.h @@ -243,15 +243,4 @@ static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) return c; } - -static __inline__ __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static __inline__ __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #endif /* _ASM_M32R_ATOMIC_H */ diff --git a/arch/m68k/include/asm/atomic.h b/arch/m68k/include/asm/atomic.h index 93ebd96aa494b..039fac120cc0e 100644 --- a/arch/m68k/include/asm/atomic.h +++ b/arch/m68k/include/asm/atomic.h @@ -174,16 +174,6 @@ static inline int atomic_add_negative(int i, atomic_t *v) return c != 0; } -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - static __inline__ int __atomic_add_unless(atomic_t *v, int a, int u) { int c, old; diff --git a/arch/metag/include/asm/atomic_lnkget.h b/arch/metag/include/asm/atomic_lnkget.h index 0642606de9012..21c4c268b86c6 100644 --- a/arch/metag/include/asm/atomic_lnkget.h +++ b/arch/metag/include/asm/atomic_lnkget.h @@ -82,16 +82,6 @@ ATOMIC_OP(xor) #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { int result, temp; diff --git a/arch/metag/include/asm/atomic_lock1.h b/arch/metag/include/asm/atomic_lock1.h index 7d88725a85da4..f8efe380fe8b3 100644 --- a/arch/metag/include/asm/atomic_lock1.h +++ b/arch/metag/include/asm/atomic_lock1.h @@ -76,16 +76,6 @@ ATOMIC_OP(xor, ^=) #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - static inline int atomic_cmpxchg(atomic_t *v, int old, int new) { int ret; diff --git a/arch/mn10300/include/asm/atomic.h b/arch/mn10300/include/asm/atomic.h index f5a63f0bda462..375e59140c9ce 100644 --- a/arch/mn10300/include/asm/atomic.h +++ b/arch/mn10300/include/asm/atomic.h @@ -131,30 +131,6 @@ static inline void atomic_dec(atomic_t *v) #define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) #define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) -/** - * atomic_clear_mask - Atomically clear bits in memory - * @mask: Mask of the bits to be cleared - * @v: pointer to word in memory - * - * Atomically clears the bits set in mask from the memory word specified. - */ -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -/** - * atomic_set_mask - Atomically set bits in memory - * @mask: Mask of the bits to be set - * @v: pointer to word in memory - * - * Atomically sets the bits set in mask from the memory word specified. - */ -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #endif /* __KERNEL__ */ #endif /* CONFIG_SMP */ #endif /* _ASM_ATOMIC_H */ diff --git a/arch/powerpc/kernel/misc_32.S b/arch/powerpc/kernel/misc_32.S index 7c6bb4b17b496..ed3ab509facac 100644 --- a/arch/powerpc/kernel/misc_32.S +++ b/arch/powerpc/kernel/misc_32.S @@ -595,25 +595,6 @@ _GLOBAL(copy_page) li r11,4 b 2b -/* - * void atomic_clear_mask(atomic_t mask, atomic_t *addr) - * void atomic_set_mask(atomic_t mask, atomic_t *addr); - */ -_GLOBAL(atomic_clear_mask) -10: lwarx r5,0,r4 - andc r5,r5,r3 - PPC405_ERR77(0,r4) - stwcx. r5,0,r4 - bne- 10b - blr -_GLOBAL(atomic_set_mask) -10: lwarx r5,0,r4 - or r5,r5,r3 - PPC405_ERR77(0,r4) - stwcx. r5,0,r4 - bne- 10b - blr - /* * Extended precision shifts. * diff --git a/arch/s390/include/asm/atomic.h b/arch/s390/include/asm/atomic.h index d761aeff72da0..117fa5c921c1b 100644 --- a/arch/s390/include/asm/atomic.h +++ b/arch/s390/include/asm/atomic.h @@ -132,16 +132,6 @@ ATOMIC_OP(xor, XOR) #undef ATOMIC_OP -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) static inline int atomic_cmpxchg(atomic_t *v, int old, int new) diff --git a/arch/sh/include/asm/atomic.h b/arch/sh/include/asm/atomic.h index cee0245257e13..05b9f74ce2d54 100644 --- a/arch/sh/include/asm/atomic.h +++ b/arch/sh/include/asm/atomic.h @@ -25,16 +25,6 @@ #include #endif -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #define atomic_add_negative(a, v) (atomic_add_return((a), (v)) < 0) #define atomic_dec_return(v) atomic_sub_return(1, (v)) #define atomic_inc_return(v) atomic_add_return(1, (v)) diff --git a/arch/x86/include/asm/atomic.h b/arch/x86/include/asm/atomic.h index b3493023efdae..fb52aa644aabb 100644 --- a/arch/x86/include/asm/atomic.h +++ b/arch/x86/include/asm/atomic.h @@ -234,16 +234,6 @@ static __always_inline short int atomic_inc_short(short int *v) return *v; } -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - #ifdef CONFIG_X86_32 # include #else diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h index 31371f43c23bb..e0be679369902 100644 --- a/arch/xtensa/include/asm/atomic.h +++ b/arch/xtensa/include/asm/atomic.h @@ -153,16 +153,6 @@ ATOMIC_OP(xor) #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - /** * atomic_sub_and_test - subtract value from variable and test result * @i: integer value to subtract diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h index a41b0b8f74049..d4d7e337fdcb5 100644 --- a/include/asm-generic/atomic.h +++ b/include/asm-generic/atomic.h @@ -113,16 +113,6 @@ ATOMIC_OP(xor, ^) #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) -{ - atomic_and(~mask, v); -} - -static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) -{ - atomic_or(mask, v); -} - /* * Atomic operations that C can't guarantee us. Useful for * resource counting etc.. diff --git a/include/linux/atomic.h b/include/linux/atomic.h index 7d6279012a1fd..8b98b423388fa 100644 --- a/include/linux/atomic.h +++ b/include/linux/atomic.h @@ -28,6 +28,23 @@ static inline int atomic_add_unless(atomic_t *v, int a, int u) #define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) #endif +#ifndef atomic_andnot +static inline void atomic_andnot(int i, atomic_t *v) +{ + atomic_and(~i, v); +} +#endif + +static inline __deprecated void atomic_clear_mask(unsigned int mask, atomic_t *v) +{ + atomic_andnot(mask, v); +} + +static inline __deprecated void atomic_set_mask(unsigned int mask, atomic_t *v) +{ + atomic_or(mask, v); +} + /** * atomic_inc_not_zero_hint - increment if not null * @v: pointer of type atomic_t @@ -115,4 +132,12 @@ static inline int atomic_dec_if_positive(atomic_t *v) #ifdef CONFIG_GENERIC_ATOMIC64 #include #endif + +#ifndef atomic64_andnot +static inline void atomic64_andnot(long long i, atomic64_t *v) +{ + atomic64_and(~i, v); +} +#endif + #endif /* _LINUX_ATOMIC_H */ -- GitLab From 805de8f43c20ba8b479bb598b543fa86b20067f6 Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Fri, 24 Apr 2015 01:12:32 +0200 Subject: [PATCH 1814/7006] atomic: Replace atomic_{set,clear}_mask() usage Replace the deprecated atomic_{set,clear}_mask() usage with the now ubiquous atomic_{or,andnot}() functions. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- arch/blackfin/mach-common/smp.c | 2 +- arch/m32r/kernel/smp.c | 4 +-- arch/mn10300/mm/tlb-smp.c | 2 +- arch/s390/kernel/time.c | 4 +-- arch/s390/kvm/interrupt.c | 30 ++++++++-------- arch/s390/kvm/kvm-s390.c | 32 ++++++++--------- drivers/gpu/drm/i915/i915_drv.c | 2 +- drivers/gpu/drm/i915/i915_gem.c | 2 +- drivers/gpu/drm/i915/i915_irq.c | 4 +-- drivers/s390/scsi/zfcp_aux.c | 2 +- drivers/s390/scsi/zfcp_erp.c | 62 ++++++++++++++++----------------- drivers/s390/scsi/zfcp_fc.c | 8 ++--- drivers/s390/scsi/zfcp_fsf.c | 26 +++++++------- drivers/s390/scsi/zfcp_qdio.c | 14 ++++---- 14 files changed, 97 insertions(+), 97 deletions(-) diff --git a/arch/blackfin/mach-common/smp.c b/arch/blackfin/mach-common/smp.c index 1c7259597395e..0030e21cfceb3 100644 --- a/arch/blackfin/mach-common/smp.c +++ b/arch/blackfin/mach-common/smp.c @@ -195,7 +195,7 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg) local_irq_save(flags); for_each_cpu(cpu, cpumask) { bfin_ipi_data = &per_cpu(bfin_ipi, cpu); - atomic_set_mask((1 << msg), &bfin_ipi_data->bits); + atomic_or((1 << msg), &bfin_ipi_data->bits); atomic_inc(&bfin_ipi_data->count); } local_irq_restore(flags); diff --git a/arch/m32r/kernel/smp.c b/arch/m32r/kernel/smp.c index c18ddc74ef9a6..62d6961e7f2b6 100644 --- a/arch/m32r/kernel/smp.c +++ b/arch/m32r/kernel/smp.c @@ -156,7 +156,7 @@ void smp_flush_cache_all(void) cpumask_clear_cpu(smp_processor_id(), &cpumask); spin_lock(&flushcache_lock); mask=cpumask_bits(&cpumask); - atomic_set_mask(*mask, (atomic_t *)&flushcache_cpumask); + atomic_or(*mask, (atomic_t *)&flushcache_cpumask); send_IPI_mask(&cpumask, INVALIDATE_CACHE_IPI, 0); _flush_cache_copyback_all(); while (flushcache_cpumask) @@ -407,7 +407,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, flush_vma = vma; flush_va = va; mask=cpumask_bits(&cpumask); - atomic_set_mask(*mask, (atomic_t *)&flush_cpumask); + atomic_or(*mask, (atomic_t *)&flush_cpumask); /* * We have to send the IPI only to diff --git a/arch/mn10300/mm/tlb-smp.c b/arch/mn10300/mm/tlb-smp.c index e5d0ef722bfa8..9a39ea9031d4f 100644 --- a/arch/mn10300/mm/tlb-smp.c +++ b/arch/mn10300/mm/tlb-smp.c @@ -119,7 +119,7 @@ static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm, flush_mm = mm; flush_va = va; #if NR_CPUS <= BITS_PER_LONG - atomic_set_mask(cpumask.bits[0], &flush_cpumask.bits[0]); + atomic_or(cpumask.bits[0], (atomic_t *)&flush_cpumask.bits[0]); #else #error Not supported. #endif diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 9e733d965e088..f5a0bd778ace1 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -381,7 +381,7 @@ static void disable_sync_clock(void *dummy) * increase the "sequence" counter to avoid the race of an * etr event and the complete recovery against get_sync_clock. */ - atomic_clear_mask(0x80000000, sw_ptr); + atomic_andnot(0x80000000, sw_ptr); atomic_inc(sw_ptr); } @@ -392,7 +392,7 @@ static void disable_sync_clock(void *dummy) static void enable_sync_clock(void) { atomic_t *sw_ptr = this_cpu_ptr(&clock_sync_word); - atomic_set_mask(0x80000000, sw_ptr); + atomic_or(0x80000000, sw_ptr); } /* diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index c98d89708e99f..57309e9cdd807 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -170,20 +170,20 @@ static unsigned long deliverable_irqs(struct kvm_vcpu *vcpu) static void __set_cpu_idle(struct kvm_vcpu *vcpu) { - atomic_set_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); set_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); } static void __unset_cpu_idle(struct kvm_vcpu *vcpu) { - atomic_clear_mask(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_WAIT, &vcpu->arch.sie_block->cpuflags); clear_bit(vcpu->vcpu_id, vcpu->arch.local_int.float_int->idle_mask); } static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) { - atomic_clear_mask(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, - &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_IO_INT | CPUSTAT_EXT_INT | CPUSTAT_STOP_INT, + &vcpu->arch.sie_block->cpuflags); vcpu->arch.sie_block->lctl = 0x0000; vcpu->arch.sie_block->ictl &= ~(ICTL_LPSW | ICTL_STCTL | ICTL_PINT); @@ -196,7 +196,7 @@ static void __reset_intercept_indicators(struct kvm_vcpu *vcpu) static void __set_cpuflag(struct kvm_vcpu *vcpu, u32 flag) { - atomic_set_mask(flag, &vcpu->arch.sie_block->cpuflags); + atomic_or(flag, &vcpu->arch.sie_block->cpuflags); } static void set_intercept_indicators_io(struct kvm_vcpu *vcpu) @@ -919,7 +919,7 @@ void kvm_s390_clear_local_irqs(struct kvm_vcpu *vcpu) spin_unlock(&li->lock); /* clear pending external calls set by sigp interpretation facility */ - atomic_clear_mask(CPUSTAT_ECALL_PEND, li->cpuflags); + atomic_andnot(CPUSTAT_ECALL_PEND, li->cpuflags); vcpu->kvm->arch.sca->cpu[vcpu->vcpu_id].sigp_ctrl = 0; } @@ -1020,7 +1020,7 @@ static int __inject_pfault_init(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) li->irq.ext = irq->u.ext; set_bit(IRQ_PEND_PFAULT_INIT, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1035,7 +1035,7 @@ static int __inject_extcall_sigpif(struct kvm_vcpu *vcpu, uint16_t src_id) /* another external call is pending */ return -EBUSY; } - atomic_set_mask(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_ECALL_PEND, &vcpu->arch.sie_block->cpuflags); return 0; } @@ -1061,7 +1061,7 @@ static int __inject_extcall(struct kvm_vcpu *vcpu, struct kvm_s390_irq *irq) if (test_and_set_bit(IRQ_PEND_EXT_EXTERNAL, &li->pending_irqs)) return -EBUSY; *extcall = irq->u.extcall; - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1133,7 +1133,7 @@ static int __inject_sigp_emergency(struct kvm_vcpu *vcpu, set_bit(irq->u.emerg.code, li->sigp_emerg_pending); set_bit(IRQ_PEND_EXT_EMERGENCY, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1177,7 +1177,7 @@ static int __inject_ckc(struct kvm_vcpu *vcpu) 0, 0, 2); set_bit(IRQ_PEND_EXT_CLOCK_COMP, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1190,7 +1190,7 @@ static int __inject_cpu_timer(struct kvm_vcpu *vcpu) 0, 0, 2); set_bit(IRQ_PEND_EXT_CPU_TIMER, &li->pending_irqs); - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); return 0; } @@ -1369,13 +1369,13 @@ static void __floating_irq_kick(struct kvm *kvm, u64 type) spin_lock(&li->lock); switch (type) { case KVM_S390_MCHK: - atomic_set_mask(CPUSTAT_STOP_INT, li->cpuflags); + atomic_or(CPUSTAT_STOP_INT, li->cpuflags); break; case KVM_S390_INT_IO_MIN...KVM_S390_INT_IO_MAX: - atomic_set_mask(CPUSTAT_IO_INT, li->cpuflags); + atomic_or(CPUSTAT_IO_INT, li->cpuflags); break; default: - atomic_set_mask(CPUSTAT_EXT_INT, li->cpuflags); + atomic_or(CPUSTAT_EXT_INT, li->cpuflags); break; } spin_unlock(&li->lock); diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c index 2078f92d15ac9..b73302fb05079 100644 --- a/arch/s390/kvm/kvm-s390.c +++ b/arch/s390/kvm/kvm-s390.c @@ -1215,12 +1215,12 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) } restore_access_regs(vcpu->run->s.regs.acrs); gmap_enable(vcpu->arch.gmap); - atomic_set_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); } void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) { - atomic_clear_mask(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_RUNNING, &vcpu->arch.sie_block->cpuflags); gmap_disable(vcpu->arch.gmap); if (test_kvm_facility(vcpu->kvm, 129)) { save_fp_ctl(&vcpu->run->s.regs.fpc); @@ -1320,9 +1320,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) CPUSTAT_STOPPED); if (test_kvm_facility(vcpu->kvm, 78)) - atomic_set_mask(CPUSTAT_GED2, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_GED2, &vcpu->arch.sie_block->cpuflags); else if (test_kvm_facility(vcpu->kvm, 8)) - atomic_set_mask(CPUSTAT_GED, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_GED, &vcpu->arch.sie_block->cpuflags); kvm_s390_vcpu_setup_model(vcpu); @@ -1422,24 +1422,24 @@ int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) void kvm_s390_vcpu_block(struct kvm_vcpu *vcpu) { - atomic_set_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); + atomic_or(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); exit_sie(vcpu); } void kvm_s390_vcpu_unblock(struct kvm_vcpu *vcpu) { - atomic_clear_mask(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); + atomic_andnot(PROG_BLOCK_SIE, &vcpu->arch.sie_block->prog20); } static void kvm_s390_vcpu_request(struct kvm_vcpu *vcpu) { - atomic_set_mask(PROG_REQUEST, &vcpu->arch.sie_block->prog20); + atomic_or(PROG_REQUEST, &vcpu->arch.sie_block->prog20); exit_sie(vcpu); } static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) { - atomic_clear_mask(PROG_REQUEST, &vcpu->arch.sie_block->prog20); + atomic_or(PROG_REQUEST, &vcpu->arch.sie_block->prog20); } /* @@ -1448,7 +1448,7 @@ static void kvm_s390_vcpu_request_handled(struct kvm_vcpu *vcpu) * return immediately. */ void exit_sie(struct kvm_vcpu *vcpu) { - atomic_set_mask(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_STOP_INT, &vcpu->arch.sie_block->cpuflags); while (vcpu->arch.sie_block->prog0c & PROG_IN_SIE) cpu_relax(); } @@ -1672,19 +1672,19 @@ int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, if (dbg->control & KVM_GUESTDBG_ENABLE) { vcpu->guest_debug = dbg->control; /* enforce guest PER */ - atomic_set_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); if (dbg->control & KVM_GUESTDBG_USE_HW_BP) rc = kvm_s390_import_bp_data(vcpu, dbg); } else { - atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); vcpu->arch.guestdbg.last_bp = 0; } if (rc) { vcpu->guest_debug = 0; kvm_s390_clear_bp_data(vcpu); - atomic_clear_mask(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_P, &vcpu->arch.sie_block->cpuflags); } return rc; @@ -1771,7 +1771,7 @@ retry: if (kvm_check_request(KVM_REQ_ENABLE_IBS, vcpu)) { if (!ibs_enabled(vcpu)) { trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 1); - atomic_set_mask(CPUSTAT_IBS, + atomic_or(CPUSTAT_IBS, &vcpu->arch.sie_block->cpuflags); } goto retry; @@ -1780,7 +1780,7 @@ retry: if (kvm_check_request(KVM_REQ_DISABLE_IBS, vcpu)) { if (ibs_enabled(vcpu)) { trace_kvm_s390_enable_disable_ibs(vcpu->vcpu_id, 0); - atomic_clear_mask(CPUSTAT_IBS, + atomic_andnot(CPUSTAT_IBS, &vcpu->arch.sie_block->cpuflags); } goto retry; @@ -2280,7 +2280,7 @@ void kvm_s390_vcpu_start(struct kvm_vcpu *vcpu) __disable_ibs_on_all_vcpus(vcpu->kvm); } - atomic_clear_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + atomic_andnot(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); /* * Another VCPU might have used IBS while we were offline. * Let's play safe and flush the VCPU at startup. @@ -2306,7 +2306,7 @@ void kvm_s390_vcpu_stop(struct kvm_vcpu *vcpu) /* SIGP STOP and SIGP STOP AND STORE STATUS has been fully processed */ kvm_s390_clear_stop_irq(vcpu); - atomic_set_mask(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); + atomic_or(CPUSTAT_STOPPED, &vcpu->arch.sie_block->cpuflags); __disable_ibs_on_vcpu(vcpu); for (i = 0; i < online_vcpus; i++) { diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 884b4f9b81c4a..8917c98ff121c 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -748,7 +748,7 @@ static int i915_drm_resume(struct drm_device *dev) mutex_lock(&dev->struct_mutex); if (i915_gem_init_hw(dev)) { DRM_ERROR("failed to re-initialize GPU, declaring wedged!\n"); - atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); + atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter); } mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 52b446b27b4d0..7a918d1c12ba3 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -5091,7 +5091,7 @@ int i915_gem_init(struct drm_device *dev) * for all other failure, such as an allocation failure, bail. */ DRM_ERROR("Failed to initialize GPU, declaring it wedged\n"); - atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter); + atomic_or(I915_WEDGED, &dev_priv->gpu_error.reset_counter); ret = 0; } diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 984e2fe6688c4..449a95c6c2a1d 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -2446,7 +2446,7 @@ static void i915_reset_and_wakeup(struct drm_device *dev) kobject_uevent_env(&dev->primary->kdev->kobj, KOBJ_CHANGE, reset_done_event); } else { - atomic_set_mask(I915_WEDGED, &error->reset_counter); + atomic_or(I915_WEDGED, &error->reset_counter); } /* @@ -2574,7 +2574,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged, i915_report_and_clear_eir(dev); if (wedged) { - atomic_set_mask(I915_RESET_IN_PROGRESS_FLAG, + atomic_or(I915_RESET_IN_PROGRESS_FLAG, &dev_priv->gpu_error.reset_counter); /* diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index 01a73395a0171..c00ac4650dce2 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -529,7 +529,7 @@ struct zfcp_port *zfcp_port_enqueue(struct zfcp_adapter *adapter, u64 wwpn, list_add_tail(&port->list, &adapter->port_list); write_unlock_irq(&adapter->port_list_lock); - atomic_set_mask(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); + atomic_or(status | ZFCP_STATUS_COMMON_RUNNING, &port->status); return port; diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index acde3f5d6e9e7..3fb410977014f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -190,7 +190,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, if (!(act_status & ZFCP_STATUS_ERP_NO_REF)) if (scsi_device_get(sdev)) return NULL; - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); erp_action = &zfcp_sdev->erp_action; memset(erp_action, 0, sizeof(struct zfcp_erp_action)); @@ -206,7 +206,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, if (!get_device(&port->dev)) return NULL; zfcp_erp_action_dismiss_port(port); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &port->status); erp_action = &port->erp_action; memset(erp_action, 0, sizeof(struct zfcp_erp_action)); erp_action->port = port; @@ -217,7 +217,7 @@ static struct zfcp_erp_action *zfcp_erp_setup_act(int need, u32 act_status, case ZFCP_ERP_ACTION_REOPEN_ADAPTER: kref_get(&adapter->ref); zfcp_erp_action_dismiss_adapter(adapter); - atomic_set_mask(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); + atomic_or(ZFCP_STATUS_COMMON_ERP_INUSE, &adapter->status); erp_action = &adapter->erp_action; memset(erp_action, 0, sizeof(struct zfcp_erp_action)); if (!(atomic_read(&adapter->status) & @@ -254,7 +254,7 @@ static int zfcp_erp_action_enqueue(int want, struct zfcp_adapter *adapter, act = zfcp_erp_setup_act(need, act_status, adapter, port, sdev); if (!act) goto out; - atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); ++adapter->erp_total_count; list_add_tail(&act->list, &adapter->erp_ready_head); wake_up(&adapter->erp_ready_wq); @@ -486,14 +486,14 @@ static void zfcp_erp_adapter_unblock(struct zfcp_adapter *adapter) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status)) zfcp_dbf_rec_run("eraubl1", &adapter->erp_action); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); + atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &adapter->status); } static void zfcp_erp_port_unblock(struct zfcp_port *port) { if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status)) zfcp_dbf_rec_run("erpubl1", &port->erp_action); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); + atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &port->status); } static void zfcp_erp_lun_unblock(struct scsi_device *sdev) @@ -502,7 +502,7 @@ static void zfcp_erp_lun_unblock(struct scsi_device *sdev) if (status_change_set(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status)) zfcp_dbf_rec_run("erlubl1", &sdev_to_zfcp(sdev)->erp_action); - atomic_set_mask(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); + atomic_or(ZFCP_STATUS_COMMON_UNBLOCKED, &zfcp_sdev->status); } static void zfcp_erp_action_to_running(struct zfcp_erp_action *erp_action) @@ -642,7 +642,7 @@ static void zfcp_erp_wakeup(struct zfcp_adapter *adapter) read_lock_irqsave(&adapter->erp_lock, flags); if (list_empty(&adapter->erp_ready_head) && list_empty(&adapter->erp_running_head)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_PENDING, + atomic_andnot(ZFCP_STATUS_ADAPTER_ERP_PENDING, &adapter->status); wake_up(&adapter->erp_done_wqh); } @@ -665,16 +665,16 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) int sleep = 1; struct zfcp_adapter *adapter = erp_action->adapter; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); + atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); for (retries = 7; retries; retries--) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); write_lock_irq(&adapter->erp_lock); zfcp_erp_action_to_running(erp_action); write_unlock_irq(&adapter->erp_lock); if (zfcp_fsf_exchange_config_data(erp_action)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); return ZFCP_ERP_FAILED; } @@ -692,7 +692,7 @@ static int zfcp_erp_adapter_strat_fsf_xconf(struct zfcp_erp_action *erp_action) sleep *= 2; } - atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_andnot(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); if (!(atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_XCONFIG_OK)) @@ -764,7 +764,7 @@ static void zfcp_erp_adapter_strategy_close(struct zfcp_erp_action *act) /* all ports and LUNs are closed */ zfcp_erp_clear_adapter_status(adapter, ZFCP_STATUS_COMMON_OPEN); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | + atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); } @@ -773,7 +773,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) struct zfcp_adapter *adapter = act->adapter; if (zfcp_qdio_open(adapter->qdio)) { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK | + atomic_andnot(ZFCP_STATUS_ADAPTER_XCONFIG_OK | ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); return ZFCP_ERP_FAILED; @@ -784,7 +784,7 @@ static int zfcp_erp_adapter_strategy_open(struct zfcp_erp_action *act) return ZFCP_ERP_FAILED; } - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &adapter->status); + atomic_or(ZFCP_STATUS_COMMON_OPEN, &adapter->status); return ZFCP_ERP_SUCCEEDED; } @@ -948,7 +948,7 @@ static void zfcp_erp_lun_strategy_clearstati(struct scsi_device *sdev) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, + atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED, &zfcp_sdev->status); } @@ -1187,18 +1187,18 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) switch (erp_action->action) { case ZFCP_ERP_ACTION_REOPEN_LUN: zfcp_sdev = sdev_to_zfcp(erp_action->sdev); - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, &zfcp_sdev->status); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: case ZFCP_ERP_ACTION_REOPEN_PORT: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->port->status); break; case ZFCP_ERP_ACTION_REOPEN_ADAPTER: - atomic_clear_mask(ZFCP_STATUS_COMMON_ERP_INUSE, + atomic_andnot(ZFCP_STATUS_COMMON_ERP_INUSE, &erp_action->adapter->status); break; } @@ -1422,19 +1422,19 @@ void zfcp_erp_set_adapter_status(struct zfcp_adapter *adapter, u32 mask) unsigned long flags; u32 common_mask = mask & ZFCP_COMMON_FLAGS; - atomic_set_mask(mask, &adapter->status); + atomic_or(mask, &adapter->status); if (!common_mask) return; read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) - atomic_set_mask(common_mask, &port->status); + atomic_or(common_mask, &port->status); read_unlock_irqrestore(&adapter->port_list_lock, flags); spin_lock_irqsave(adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, adapter->scsi_host) - atomic_set_mask(common_mask, &sdev_to_zfcp(sdev)->status); + atomic_or(common_mask, &sdev_to_zfcp(sdev)->status); spin_unlock_irqrestore(adapter->scsi_host->host_lock, flags); } @@ -1453,7 +1453,7 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) u32 common_mask = mask & ZFCP_COMMON_FLAGS; u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; - atomic_clear_mask(mask, &adapter->status); + atomic_andnot(mask, &adapter->status); if (!common_mask) return; @@ -1463,7 +1463,7 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) read_lock_irqsave(&adapter->port_list_lock, flags); list_for_each_entry(port, &adapter->port_list, list) { - atomic_clear_mask(common_mask, &port->status); + atomic_andnot(common_mask, &port->status); if (clear_counter) atomic_set(&port->erp_counter, 0); } @@ -1471,7 +1471,7 @@ void zfcp_erp_clear_adapter_status(struct zfcp_adapter *adapter, u32 mask) spin_lock_irqsave(adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, adapter->scsi_host) { - atomic_clear_mask(common_mask, &sdev_to_zfcp(sdev)->status); + atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status); if (clear_counter) atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); } @@ -1491,7 +1491,7 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) u32 common_mask = mask & ZFCP_COMMON_FLAGS; unsigned long flags; - atomic_set_mask(mask, &port->status); + atomic_or(mask, &port->status); if (!common_mask) return; @@ -1499,7 +1499,7 @@ void zfcp_erp_set_port_status(struct zfcp_port *port, u32 mask) spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - atomic_set_mask(common_mask, + atomic_or(common_mask, &sdev_to_zfcp(sdev)->status); spin_unlock_irqrestore(port->adapter->scsi_host->host_lock, flags); } @@ -1518,7 +1518,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) u32 clear_counter = mask & ZFCP_STATUS_COMMON_ERP_FAILED; unsigned long flags; - atomic_clear_mask(mask, &port->status); + atomic_andnot(mask, &port->status); if (!common_mask) return; @@ -1529,7 +1529,7 @@ void zfcp_erp_clear_port_status(struct zfcp_port *port, u32 mask) spin_lock_irqsave(port->adapter->scsi_host->host_lock, flags); __shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) { - atomic_clear_mask(common_mask, + atomic_andnot(common_mask, &sdev_to_zfcp(sdev)->status); if (clear_counter) atomic_set(&sdev_to_zfcp(sdev)->erp_counter, 0); @@ -1546,7 +1546,7 @@ void zfcp_erp_set_lun_status(struct scsi_device *sdev, u32 mask) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - atomic_set_mask(mask, &zfcp_sdev->status); + atomic_or(mask, &zfcp_sdev->status); } /** @@ -1558,7 +1558,7 @@ void zfcp_erp_clear_lun_status(struct scsi_device *sdev, u32 mask) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); - atomic_clear_mask(mask, &zfcp_sdev->status); + atomic_andnot(mask, &zfcp_sdev->status); if (mask & ZFCP_STATUS_COMMON_ERP_FAILED) atomic_set(&zfcp_sdev->erp_counter, 0); diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 25d49f32ca638..237688af179b9 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -508,7 +508,7 @@ static void zfcp_fc_adisc_handler(void *data) /* port is good, unblock rport without going through erp */ zfcp_scsi_schedule_rport_register(port); out: - atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); put_device(&port->dev); kmem_cache_free(zfcp_fc_req_cache, fc_req); } @@ -564,14 +564,14 @@ void zfcp_fc_link_test_work(struct work_struct *work) if (atomic_read(&port->status) & ZFCP_STATUS_PORT_LINK_TEST) goto out; - atomic_set_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_or(ZFCP_STATUS_PORT_LINK_TEST, &port->status); retval = zfcp_fc_adisc(port); if (retval == 0) return; /* send of ADISC was not possible */ - atomic_clear_mask(ZFCP_STATUS_PORT_LINK_TEST, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_LINK_TEST, &port->status); zfcp_erp_port_forced_reopen(port, 0, "fcltwk1"); out: @@ -640,7 +640,7 @@ static void zfcp_fc_validate_port(struct zfcp_port *port, struct list_head *lh) if (!(atomic_read(&port->status) & ZFCP_STATUS_COMMON_NOESC)) return; - atomic_clear_mask(ZFCP_STATUS_COMMON_NOESC, &port->status); + atomic_andnot(ZFCP_STATUS_COMMON_NOESC, &port->status); if ((port->supported_classes != 0) || !list_empty(&port->unit_list)) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 21ec5e2f584ce..27b976aa1818f 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -114,7 +114,7 @@ static void zfcp_fsf_link_down_info_eval(struct zfcp_fsf_req *req, if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED) return; - atomic_set_mask(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_LINK_UNPLUGGED, &adapter->status); zfcp_scsi_schedule_rports_block(adapter); @@ -345,7 +345,7 @@ static void zfcp_fsf_protstatus_eval(struct zfcp_fsf_req *req) zfcp_erp_adapter_shutdown(adapter, 0, "fspse_3"); break; case FSF_PROT_HOST_CONNECTION_INITIALIZING: - atomic_set_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, + atomic_or(ZFCP_STATUS_ADAPTER_HOST_CON_INIT, &adapter->status); break; case FSF_PROT_DUPLICATE_REQUEST_ID: @@ -554,7 +554,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) zfcp_erp_adapter_shutdown(adapter, 0, "fsecdh1"); return; } - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: @@ -567,7 +567,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) /* avoids adapter shutdown to be able to recognize * events such as LINK UP */ - atomic_set_mask(ZFCP_STATUS_ADAPTER_XCONFIG_OK, + atomic_or(ZFCP_STATUS_ADAPTER_XCONFIG_OK, &adapter->status); zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); @@ -1394,9 +1394,9 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req) break; case FSF_GOOD: port->handle = header->port_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN | + atomic_or(ZFCP_STATUS_COMMON_OPEN | ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED, + atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_BOXED, &port->status); /* check whether D_ID has changed during open */ /* @@ -1677,10 +1677,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) case FSF_PORT_BOXED: /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ - atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &sdev_to_zfcp(sdev)->status); zfcp_erp_set_port_status(port, ZFCP_STATUS_COMMON_ACCESS_BOXED); zfcp_erp_port_reopen(port, ZFCP_STATUS_COMMON_ERP_FAILED, @@ -1700,10 +1700,10 @@ static void zfcp_fsf_close_physical_port_handler(struct zfcp_fsf_req *req) /* can't use generic zfcp_erp_modify_port_status because * ZFCP_STATUS_COMMON_OPEN must not be reset for the port */ - atomic_clear_mask(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); + atomic_andnot(ZFCP_STATUS_PORT_PHYS_OPEN, &port->status); shost_for_each_device(sdev, port->adapter->scsi_host) if (sdev_to_zfcp(sdev)->port == port) - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, + atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &sdev_to_zfcp(sdev)->status); break; } @@ -1766,7 +1766,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) zfcp_sdev = sdev_to_zfcp(sdev); - atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED | + atomic_andnot(ZFCP_STATUS_COMMON_ACCESS_DENIED | ZFCP_STATUS_COMMON_ACCESS_BOXED, &zfcp_sdev->status); @@ -1822,7 +1822,7 @@ static void zfcp_fsf_open_lun_handler(struct zfcp_fsf_req *req) case FSF_GOOD: zfcp_sdev->lun_handle = header->lun_handle; - atomic_set_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); + atomic_or(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } @@ -1913,7 +1913,7 @@ static void zfcp_fsf_close_lun_handler(struct zfcp_fsf_req *req) } break; case FSF_GOOD: - atomic_clear_mask(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); + atomic_andnot(ZFCP_STATUS_COMMON_OPEN, &zfcp_sdev->status); break; } } diff --git a/drivers/s390/scsi/zfcp_qdio.c b/drivers/s390/scsi/zfcp_qdio.c index 495e1cb3afa60..dbf2b54703f72 100644 --- a/drivers/s390/scsi/zfcp_qdio.c +++ b/drivers/s390/scsi/zfcp_qdio.c @@ -349,7 +349,7 @@ void zfcp_qdio_close(struct zfcp_qdio *qdio) /* clear QDIOUP flag, thus do_QDIO is not called during qdio_shutdown */ spin_lock_irq(&qdio->req_q_lock); - atomic_clear_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); + atomic_andnot(ZFCP_STATUS_ADAPTER_QDIOUP, &adapter->status); spin_unlock_irq(&qdio->req_q_lock); wake_up(&qdio->req_q_wq); @@ -384,7 +384,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) if (atomic_read(&adapter->status) & ZFCP_STATUS_ADAPTER_QDIOUP) return -EIO; - atomic_clear_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, + atomic_andnot(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, &qdio->adapter->status); zfcp_qdio_setup_init_data(&init_data, qdio); @@ -396,14 +396,14 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) goto failed_qdio; if (ssqd.qdioac2 & CHSC_AC2_DATA_DIV_ENABLED) - atomic_set_mask(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, + atomic_or(ZFCP_STATUS_ADAPTER_DATA_DIV_ENABLED, &qdio->adapter->status); if (ssqd.qdioac2 & CHSC_AC2_MULTI_BUFFER_ENABLED) { - atomic_set_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER; } else { - atomic_clear_mask(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); + atomic_andnot(ZFCP_STATUS_ADAPTER_MB_ACT, &adapter->status); qdio->max_sbale_per_sbal = QDIO_MAX_ELEMENTS_PER_BUFFER - 1; } @@ -427,7 +427,7 @@ int zfcp_qdio_open(struct zfcp_qdio *qdio) /* set index of first available SBALS / number of available SBALS */ qdio->req_q_idx = 0; atomic_set(&qdio->req_q_free, QDIO_MAX_BUFFERS_PER_Q); - atomic_set_mask(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); + atomic_or(ZFCP_STATUS_ADAPTER_QDIOUP, &qdio->adapter->status); if (adapter->scsi_host) { adapter->scsi_host->sg_tablesize = qdio->max_sbale_per_req; @@ -499,6 +499,6 @@ void zfcp_qdio_siosl(struct zfcp_adapter *adapter) rc = ccw_device_siosl(adapter->ccw_device); if (!rc) - atomic_set_mask(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, + atomic_or(ZFCP_STATUS_ADAPTER_SIOSL_ISSUED, &adapter->status); } -- GitLab From 41b9e9fcc1c44b84a785115058ce9c703e3fca6e Mon Sep 17 00:00:00 2001 From: Peter Zijlstra Date: Mon, 13 Jul 2015 12:55:58 +0200 Subject: [PATCH 1815/7006] atomic: Add simple atomic_t tests Add a few atomic_t tests, gets some compile coverage for the new operations. Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Thomas Gleixner --- lib/atomic64_test.c | 68 +++++++++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 21 deletions(-) diff --git a/lib/atomic64_test.c b/lib/atomic64_test.c index 0211d30d8c390..83c33a5bcffb1 100644 --- a/lib/atomic64_test.c +++ b/lib/atomic64_test.c @@ -16,8 +16,39 @@ #include #include +#define TEST(bit, op, c_op, val) \ +do { \ + atomic##bit##_set(&v, v0); \ + r = v0; \ + atomic##bit##_##op(val, &v); \ + r c_op val; \ + WARN(atomic##bit##_read(&v) != r, "%Lx != %Lx\n", \ + (unsigned long long)atomic##bit##_read(&v), \ + (unsigned long long)r); \ +} while (0) + +static __init void test_atomic(void) +{ + int v0 = 0xaaa31337; + int v1 = 0xdeadbeef; + int onestwos = 0x11112222; + int one = 1; + + atomic_t v; + int r; + + TEST(, add, +=, onestwos); + TEST(, add, +=, -one); + TEST(, sub, -=, onestwos); + TEST(, sub, -=, -one); + TEST(, or, |=, v1); + TEST(, and, &=, v1); + TEST(, xor, ^=, v1); + TEST(, andnot, &= ~, v1); +} + #define INIT(c) do { atomic64_set(&v, c); r = c; } while (0) -static __init int test_atomic64(void) +static __init void test_atomic64(void) { long long v0 = 0xaaa31337c001d00dLL; long long v1 = 0xdeadbeefdeafcafeLL; @@ -34,15 +65,14 @@ static __init int test_atomic64(void) BUG_ON(v.counter != r); BUG_ON(atomic64_read(&v) != r); - INIT(v0); - atomic64_add(onestwos, &v); - r += onestwos; - BUG_ON(v.counter != r); - - INIT(v0); - atomic64_add(-one, &v); - r += -one; - BUG_ON(v.counter != r); + TEST(64, add, +=, onestwos); + TEST(64, add, +=, -one); + TEST(64, sub, -=, onestwos); + TEST(64, sub, -=, -one); + TEST(64, or, |=, v1); + TEST(64, and, &=, v1); + TEST(64, xor, ^=, v1); + TEST(64, andnot, &= ~, v1); INIT(v0); r += onestwos; @@ -54,16 +84,6 @@ static __init int test_atomic64(void) BUG_ON(atomic64_add_return(-one, &v) != r); BUG_ON(v.counter != r); - INIT(v0); - atomic64_sub(onestwos, &v); - r -= onestwos; - BUG_ON(v.counter != r); - - INIT(v0); - atomic64_sub(-one, &v); - r -= -one; - BUG_ON(v.counter != r); - INIT(v0); r -= onestwos; BUG_ON(atomic64_sub_return(onestwos, &v) != r); @@ -147,6 +167,12 @@ static __init int test_atomic64(void) BUG_ON(!atomic64_inc_not_zero(&v)); r += one; BUG_ON(v.counter != r); +} + +static __init int test_atomics(void) +{ + test_atomic(); + test_atomic64(); #ifdef CONFIG_X86 pr_info("passed for %s platform %s CX8 and %s SSE\n", @@ -166,4 +192,4 @@ static __init int test_atomic64(void) return 0; } -core_initcall(test_atomic64); +core_initcall(test_atomics); -- GitLab From 926631c2012d22ab507ace95b3e5f5621f2c72b7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 24 Jul 2015 14:05:33 +0300 Subject: [PATCH 1816/7006] ext4: memory leak on error in ext4_symlink() We should release "sd" before returning. Fixes: 0fa12ad1b285 ('ext4: Handle error from dquot_initialize()') Signed-off-by: Dan Carpenter Signed-off-by: Jan Kara --- fs/ext4/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index d3ff83742a337..9f61e7679a6de 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -3084,7 +3084,7 @@ static int ext4_symlink(struct inode *dir, err = dquot_initialize(dir); if (err) - return err; + goto err_free_sd; if ((disk_link.len > EXT4_N_BLOCKS * 4)) { /* -- GitLab From d1aceb80c685b0735268fba296523f5d7264ff22 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 14:45:40 +0900 Subject: [PATCH 1817/7006] gpio: remove unneeded initializer in gpiochip_add_to_list() This variable is used as an iterator and initialized in the list_for_each() loop. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 6d60ec2c9a796..b7e24780683ab 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -190,7 +190,7 @@ EXPORT_SYMBOL_GPL(gpiod_get_direction); */ static int gpiochip_add_to_list(struct gpio_chip *chip) { - struct list_head *pos = &gpio_chips; + struct list_head *pos; struct gpio_chip *_chip; int err = 0; -- GitLab From ba53219809f4b3a08f21600a0f3b675620d518bc Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 24 Jul 2015 12:02:22 -0400 Subject: [PATCH 1818/7006] HID: core: do not reject devices when they declare too many usages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some device present proprietary collections with a usage min of 0x00 and a usage max of 0xffff. hid-core currently reject them while most of the time this is harmless. Let's ignore the exceeding usages, and hope for the best. Reported-by: Simon Wörner Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 157c627750535..b403fe2c5cbe1 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -427,6 +427,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) { __u32 data; unsigned n; + __u32 count; data = item_udata(item); @@ -490,6 +491,24 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) if (item->size <= 2) data = (parser->global.usage_page << 16) + data; + count = data - parser->local.usage_minimum; + if (count + parser->local.usage_index >= HID_MAX_USAGES) { + /* + * We do not warn if the name is not set, we are + * actually pre-scanning the device. + */ + if (dev_name(&parser->device->dev)) + hid_warn(parser->device, + "ignoring exceeding usage max\n"); + data = HID_MAX_USAGES - parser->local.usage_index + + parser->local.usage_minimum - 1; + if (data <= 0) { + hid_err(parser->device, + "no more usage index available\n"); + return -1; + } + } + for (n = parser->local.usage_minimum; n <= data; n++) if (hid_add_usage(parser, n)) { dbg_hid("hid_add_usage failed\n"); -- GitLab From 2b38ca6d1aaf9149f1286c93b131f3e62c3ac63b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 15:25:26 +0900 Subject: [PATCH 1819/7006] pinctrl: use dev_err() to show message in pinctrl_register_one_pin() Use dev_err() rather than pr_err() to display the error message. (Besides, dev_err() is already used 7 lines below in this function.) Also, drop the redundant information "on %s" because dev_err() shows which device the message is related to. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pinctrl/core.c b/drivers/pinctrl/core.c index 8b8f3a04c3537..69723e07036ba 100644 --- a/drivers/pinctrl/core.c +++ b/drivers/pinctrl/core.c @@ -231,8 +231,7 @@ static int pinctrl_register_one_pin(struct pinctrl_dev *pctldev, pindesc = pin_desc_get(pctldev, number); if (pindesc != NULL) { - pr_err("pin %d already registered on %s\n", number, - pctldev->desc->name); + dev_err(pctldev->dev, "pin %d already registered\n", number); return -EINVAL; } -- GitLab From e324957096dbf5bbf1491231c9912c3f5d0bc216 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 21 Jul 2015 15:25:27 +0900 Subject: [PATCH 1820/7006] pinctrl: use dev_err() to show message in pinmux_func_name_to_selector() Use dev_err() rather than pr_err() to display the error message. pinctrl_dev_get_name(pctldev) is no longer necessary because dev_err() shows which device the message is related to. Signed-off-by: Masahiro Yamada Signed-off-by: Linus Walleij --- drivers/pinctrl/pinmux.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinmux.c b/drivers/pinctrl/pinmux.c index e7ae890dcf1ae..67e08cb315c47 100644 --- a/drivers/pinctrl/pinmux.c +++ b/drivers/pinctrl/pinmux.c @@ -322,8 +322,7 @@ static int pinmux_func_name_to_selector(struct pinctrl_dev *pctldev, selector++; } - pr_err("%s does not support function %s\n", - pinctrl_dev_get_name(pctldev), function); + dev_err(pctldev->dev, "function '%s' not supported\n", function); return -EINVAL; } -- GitLab From 4dbada2be460dc5568fa27784ef626232c28061f Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Tue, 21 Jul 2015 18:26:51 +0200 Subject: [PATCH 1821/7006] gpio: omap: use raw locks for locking This patch converts gpio_bank.lock from a spin_lock into a raw_spin_lock. The call path is to access this lock is always under a raw_spin_lock, for instance - __setup_irq() holds &desc->lock with irq off + __irq_set_trigger() + omap_gpio_irq_type() - handle_level_irq() (runs with irqs off therefore raw locks) + mask_ack_irq() + omap_gpio_mask_irq() This fixes the obvious backtrace on -RT. However the locking vs context is not and this is not limited to -RT: - omap_gpio_irq_type() is called with IRQ off and has an conditional call to pm_runtime_get_sync() which may sleep. Either it may happen or it may not happen but pm_runtime_get_sync() should not be called with irqs off. - omap_gpio_debounce() is holding the lock with IRQs off. + omap2_set_gpio_debounce() + clk_prepare_enable() + clk_prepare() this one might sleep. The number of users of gpiod_set_debounce() / gpio_set_debounce() looks low but still this is not good. Acked-by: Javier Martinez Canillas Acked-by: Santosh Shilimkar Signed-off-by: Sebastian Andrzej Siewior Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 80 ++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 04ea23ba37ccd..a2ff0eec5b363 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -57,7 +57,7 @@ struct gpio_bank { u32 saved_datain; u32 level_mask; u32 toggle_mask; - spinlock_t lock; + raw_spinlock_t lock; struct gpio_chip chip; struct clk *dbck; u32 mod_usage; @@ -498,17 +498,17 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type) if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); retval = omap_set_gpio_triggering(bank, offset, type); if (retval) goto error; omap_gpio_init_irq(bank, offset); if (!omap_gpio_is_input(bank, offset)) { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); retval = -EINVAL; goto error; } - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); @@ -634,14 +634,14 @@ static int omap_set_gpio_wakeup(struct gpio_bank *bank, unsigned offset, return -EINVAL; } - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); if (enable) bank->context.wake_en |= gpio_bit; else bank->context.wake_en &= ~gpio_bit; writel_relaxed(bank->context.wake_en, bank->base + bank->regs->wkup_en); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -667,10 +667,10 @@ static int omap_gpio_request(struct gpio_chip *chip, unsigned offset) if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap_enable_gpio_module(bank, offset); bank->mod_usage |= BIT(offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -680,14 +680,14 @@ static void omap_gpio_free(struct gpio_chip *chip, unsigned offset) struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip); unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->mod_usage &= ~(BIT(offset)); if (!LINE_USED(bank->irq_usage, offset)) { omap_set_gpio_direction(bank, offset, 1); omap_clear_gpio_debounce(bank, offset); } omap_disable_gpio_module(bank, offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); /* * If this is the last gpio to be freed in the bank, @@ -789,7 +789,7 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) if (!BANK_USED(bank)) pm_runtime_get_sync(bank->dev); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); if (!LINE_USED(bank->mod_usage, offset)) omap_set_gpio_direction(bank, offset, 1); @@ -798,12 +798,12 @@ static unsigned int omap_gpio_irq_startup(struct irq_data *d) omap_enable_gpio_module(bank, offset); bank->irq_usage |= BIT(offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); omap_gpio_unmask_irq(d); return 0; err: - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); if (!BANK_USED(bank)) pm_runtime_put(bank->dev); return -EINVAL; @@ -815,7 +815,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) unsigned long flags; unsigned offset = d->hwirq; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->irq_usage &= ~(BIT(offset)); omap_set_gpio_irqenable(bank, offset, 0); omap_clear_gpio_irqstatus(bank, offset); @@ -823,7 +823,7 @@ static void omap_gpio_irq_shutdown(struct irq_data *d) if (!LINE_USED(bank->mod_usage, offset)) omap_clear_gpio_debounce(bank, offset); omap_disable_gpio_module(bank, offset); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); /* * If this is the last IRQ to be freed in the bank, @@ -847,10 +847,10 @@ static void omap_gpio_mask_irq(struct irq_data *d) unsigned offset = d->hwirq; unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap_set_gpio_irqenable(bank, offset, 0); omap_set_gpio_triggering(bank, offset, IRQ_TYPE_NONE); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); } static void omap_gpio_unmask_irq(struct irq_data *d) @@ -860,7 +860,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d) u32 trigger = irqd_get_trigger_type(d); unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); if (trigger) omap_set_gpio_triggering(bank, offset, trigger); @@ -872,7 +872,7 @@ static void omap_gpio_unmask_irq(struct irq_data *d) } omap_set_gpio_irqenable(bank, offset, 1); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); } /*---------------------------------------------------------------------*/ @@ -885,9 +885,9 @@ static int omap_mpuio_suspend_noirq(struct device *dev) OMAP_MPUIO_GPIO_MASKIT / bank->stride; unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); writel_relaxed(0xffff & ~bank->context.wake_en, mask_reg); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -900,9 +900,9 @@ static int omap_mpuio_resume_noirq(struct device *dev) OMAP_MPUIO_GPIO_MASKIT / bank->stride; unsigned long flags; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); writel_relaxed(bank->context.wake_en, mask_reg); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -948,9 +948,9 @@ static int omap_gpio_get_direction(struct gpio_chip *chip, unsigned offset) bank = container_of(chip, struct gpio_bank, chip); reg = bank->base + bank->regs->direction; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); dir = !!(readl_relaxed(reg) & BIT(offset)); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return dir; } @@ -960,9 +960,9 @@ static int omap_gpio_input(struct gpio_chip *chip, unsigned offset) unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap_set_gpio_direction(bank, offset, 1); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -984,10 +984,10 @@ static int omap_gpio_output(struct gpio_chip *chip, unsigned offset, int value) unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->set_dataout(bank, offset, value); omap_set_gpio_direction(bank, offset, 0); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -999,9 +999,9 @@ static int omap_gpio_debounce(struct gpio_chip *chip, unsigned offset, bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); omap2_set_gpio_debounce(bank, offset, debounce); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -1012,9 +1012,9 @@ static void omap_gpio_set(struct gpio_chip *chip, unsigned offset, int value) unsigned long flags; bank = container_of(chip, struct gpio_bank, chip); - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); bank->set_dataout(bank, offset, value); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); } /*---------------------------------------------------------------------*/ @@ -1210,7 +1210,7 @@ static int omap_gpio_probe(struct platform_device *pdev) else bank->set_dataout = omap_set_gpio_dataout_mask; - spin_lock_init(&bank->lock); + raw_spin_lock_init(&bank->lock); /* Static mapping, never released */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1268,7 +1268,7 @@ static int omap_gpio_runtime_suspend(struct device *dev) unsigned long flags; u32 wake_low, wake_hi; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); /* * Only edges can generate a wakeup event to the PRCM. @@ -1321,7 +1321,7 @@ update_gpio_context_count: bank->get_context_loss_count(bank->dev); omap_gpio_dbck_disable(bank); - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -1336,7 +1336,7 @@ static int omap_gpio_runtime_resume(struct device *dev) unsigned long flags; int c; - spin_lock_irqsave(&bank->lock, flags); + raw_spin_lock_irqsave(&bank->lock, flags); /* * On the first resume during the probe, the context has not @@ -1372,14 +1372,14 @@ static int omap_gpio_runtime_resume(struct device *dev) if (c != bank->context_loss_count) { omap_gpio_restore_context(bank); } else { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } } } if (!bank->workaround_enabled) { - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } @@ -1434,7 +1434,7 @@ static int omap_gpio_runtime_resume(struct device *dev) } bank->workaround_enabled = false; - spin_unlock_irqrestore(&bank->lock, flags); + raw_spin_unlock_irqrestore(&bank->lock, flags); return 0; } -- GitLab From 8cd14702be9bcb2ec45e1ec30af04aea9b965708 Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Tue, 21 Jul 2015 11:08:50 +0200 Subject: [PATCH 1822/7006] gpio: rcar: Add r8a7795 (R-Car H3) support R-Car Gen3's GPIO blocks are identical to Gen2's in every respect. Signed-off-by: Ulrich Hecht Acked-by: Simon Horman Acked-by: Kuninori Morimoto Signed-off-by: Linus Walleij --- Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt | 1 + drivers/gpio/gpio-rcar.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt index 38fb86f28ba2c..f60e2f477e93c 100644 --- a/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt +++ b/Documentation/devicetree/bindings/gpio/renesas,gpio-rcar.txt @@ -9,6 +9,7 @@ Required Properties: - "renesas,gpio-r8a7791": for R8A7791 (R-Car M2-W) compatible GPIO controller. - "renesas,gpio-r8a7793": for R8A7793 (R-Car M2-N) compatible GPIO controller. - "renesas,gpio-r8a7794": for R8A7794 (R-Car E2) compatible GPIO controller. + - "renesas,gpio-r8a7795": for R8A7795 (R-Car H3) compatible GPIO controller. - "renesas,gpio-rcar": for generic R-Car GPIO controller. - reg: Base address and length of each memory resource used by the GPIO diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c index 4fc13ce9c60ad..2a81224446145 100644 --- a/drivers/gpio/gpio-rcar.c +++ b/drivers/gpio/gpio-rcar.c @@ -341,6 +341,10 @@ static const struct of_device_id gpio_rcar_of_table[] = { }, { .compatible = "renesas,gpio-r8a7794", .data = &gpio_rcar_info_gen2, + }, { + .compatible = "renesas,gpio-r8a7795", + /* Gen3 GPIO is identical to Gen2. */ + .data = &gpio_rcar_info_gen2, }, { .compatible = "renesas,gpio-rcar", .data = &gpio_rcar_info_gen1, -- GitLab From d8323c6b03533ac870fb665277e6dad7ebf7e4d3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 27 Jul 2015 14:41:57 +0200 Subject: [PATCH 1823/7006] pinctrl: sunxi: Add custom irq_domain_ops The current interrupt parsing code was working by accident, because the default was actually parsing the first node of interrupts. While that was mostly working (and the flags were actually ignored), this binding has never been documented, and doesn't work with SoCs that have multiple interrupt banks anyway. Add a proper interrupt xlate function, that uses the same description than the GPIOs ( ), that will make things less confusing. The EINT number will still be used as the hwirq number, but won't be exposed through the DT. Signed-off-by: Maxime Ripard Reviewed-by: Hans de Goede Signed-off-by: Linus Walleij --- .../pinctrl/allwinner,sunxi-pinctrl.txt | 37 ++++++++++++++++++- drivers/pinctrl/sunxi/pinctrl-sunxi.c | 35 +++++++++++++++++- 2 files changed, 69 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt index 9462ab7ddd1f5..3c821cda1ad05 100644 --- a/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/allwinner,sunxi-pinctrl.txt @@ -48,7 +48,7 @@ Optional subnode-properties: Examples: -pinctrl@01c20800 { +pio: pinctrl@01c20800 { compatible = "allwinner,sun5i-a13-pinctrl"; reg = <0x01c20800 0x400>; #address-cells = <1>; @@ -68,3 +68,38 @@ pinctrl@01c20800 { allwinner,pull = <0>; }; }; + + +GPIO and interrupt controller +----------------------------- + +This hardware also acts as a GPIO controller and an interrupt +controller. + +Consumers that would want to refer to one or the other (or both) +should provide through the usual *-gpios and interrupts properties a +cell with 3 arguments, first the number of the bank, then the pin +inside that bank, and finally the flags for the GPIO/interrupts. + +Example: + +xio: gpio@38 { + compatible = "nxp,pcf8574a"; + reg = <0x38>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-parent = <&pio>; + interrupts = <6 0 IRQ_TYPE_EDGE_FALLING>; + interrupt-controller; + #interrupt-cells = <2>; +}; + +reg_usb1_vbus: usb1-vbus { + compatible = "regulator-fixed"; + regulator-name = "usb1-vbus"; + regulator-min-microvolt = <5000000>; + regulator-max-microvolt = <5000000>; + gpio = <&pio 7 6 GPIO_ACTIVE_HIGH>; +}; diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.c b/drivers/pinctrl/sunxi/pinctrl-sunxi.c index 7f7e7bb4f22cf..fb4669c0ce0e7 100644 --- a/drivers/pinctrl/sunxi/pinctrl-sunxi.c +++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.c @@ -711,6 +711,37 @@ static struct irq_chip sunxi_pinctrl_level_irq_chip = { IRQCHIP_EOI_IF_HANDLED, }; +static int sunxi_pinctrl_irq_of_xlate(struct irq_domain *d, + struct device_node *node, + const u32 *intspec, + unsigned int intsize, + unsigned long *out_hwirq, + unsigned int *out_type) +{ + struct sunxi_desc_function *desc; + int pin, base; + + if (intsize < 3) + return -EINVAL; + + base = PINS_PER_BANK * intspec[0]; + pin = base + intspec[1]; + + desc = sunxi_pinctrl_desc_find_function_by_pin(d->host_data, + pin, "irq"); + if (!desc) + return -EINVAL; + + *out_hwirq = desc->irqbank * PINS_PER_BANK + desc->irqnum; + *out_type = intspec[2]; + + return 0; +} + +static struct irq_domain_ops sunxi_pinctrl_irq_domain_ops = { + .xlate = sunxi_pinctrl_irq_of_xlate, +}; + static void sunxi_pinctrl_irq_handler(unsigned __irq, struct irq_desc *desc) { unsigned int irq = irq_desc_get_irq(desc); @@ -986,8 +1017,8 @@ int sunxi_pinctrl_init(struct platform_device *pdev, pctl->domain = irq_domain_add_linear(node, pctl->desc->irq_banks * IRQ_PER_BANK, - &irq_domain_simple_ops, - NULL); + &sunxi_pinctrl_irq_domain_ops, + pctl); if (!pctl->domain) { dev_err(&pdev->dev, "Couldn't register IRQ domain\n"); ret = -ENOMEM; -- GitLab From 1296fba1a397b173d45534885a0934a7c005d7e3 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 22 Jul 2015 15:05:17 +0200 Subject: [PATCH 1824/7006] gpio: etraxfs: fix set register flag BGPIO_F_UNREADABLE_REG_SET is incorrect, since the set register _is_ readable. What's really required is BGPIO_F_READ_OUTPUT_REG_SET: reading the set register reads the set output value. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/gpio-etraxfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 0e643140efdef..625a9ed411dac 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -140,7 +140,7 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) NULL, /* clr */ regs + port->oe, /* dirout */ NULL, /* dirin */ - BGPIOF_UNREADABLE_REG_SET); + BGPIOF_READ_OUTPUT_REG_SET); if (ret) return ret; -- GitLab From 91492a44b998cf762150de8f1b40bda1902e8ea7 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 22 Jul 2015 15:05:18 +0200 Subject: [PATCH 1825/7006] gpio: generic: support input-only chips Allow chips to indicates that they are input-only and thus cannot set the output value. This will be used by the gpio-etraxfs driver. Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- drivers/gpio/gpio-generic.c | 23 ++++++++++++++++++++--- include/linux/basic_mmio_gpio.h | 1 + 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c index 802e6d2c64e9e..a3f07537fe625 100644 --- a/drivers/gpio/gpio-generic.c +++ b/drivers/gpio/gpio-generic.c @@ -153,6 +153,10 @@ static int bgpio_get(struct gpio_chip *gc, unsigned int gpio) return !!(bgc->read_reg(bgc->reg_dat) & bgc->pin2mask(bgc, gpio)); } +static void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) +{ +} + static void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) { struct bgpio_chip *bgc = to_bgpio_chip(gc); @@ -279,6 +283,12 @@ static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) return 0; } +static int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, + int val) +{ + return -EINVAL; +} + static int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) { @@ -460,6 +470,9 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, bgc->reg_set = set; bgc->gc.set = bgpio_set_set; bgc->gc.set_multiple = bgpio_set_multiple_set; + } else if (flags & BGPIOF_NO_OUTPUT) { + bgc->gc.set = bgpio_set_none; + bgc->gc.set_multiple = NULL; } else { bgc->gc.set = bgpio_set; bgc->gc.set_multiple = bgpio_set_multiple; @@ -476,7 +489,8 @@ static int bgpio_setup_io(struct bgpio_chip *bgc, static int bgpio_setup_direction(struct bgpio_chip *bgc, void __iomem *dirout, - void __iomem *dirin) + void __iomem *dirin, + unsigned long flags) { if (dirout && dirin) { return -EINVAL; @@ -491,7 +505,10 @@ static int bgpio_setup_direction(struct bgpio_chip *bgc, bgc->gc.direction_input = bgpio_dir_in_inv; bgc->gc.get_direction = bgpio_get_dir_inv; } else { - bgc->gc.direction_output = bgpio_simple_dir_out; + if (flags & BGPIOF_NO_OUTPUT) + bgc->gc.direction_output = bgpio_dir_out_err; + else + bgc->gc.direction_output = bgpio_simple_dir_out; bgc->gc.direction_input = bgpio_simple_dir_in; } @@ -543,7 +560,7 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, if (ret) return ret; - ret = bgpio_setup_direction(bgc, dirout, dirin); + ret = bgpio_setup_direction(bgc, dirout, dirin, flags); if (ret) return ret; diff --git a/include/linux/basic_mmio_gpio.h b/include/linux/basic_mmio_gpio.h index 14eea946e6401..ed3768f4ecc70 100644 --- a/include/linux/basic_mmio_gpio.h +++ b/include/linux/basic_mmio_gpio.h @@ -75,5 +75,6 @@ int bgpio_init(struct bgpio_chip *bgc, struct device *dev, #define BGPIOF_UNREADABLE_REG_DIR BIT(2) /* reg_dir is unreadable */ #define BGPIOF_BIG_ENDIAN_BYTE_ORDER BIT(3) #define BGPIOF_READ_OUTPUT_REG_SET BIT(4) /* reg_set stores output value */ +#define BGPIOF_NO_OUTPUT BIT(5) /* only input */ #endif /* __BASIC_MMIO_GPIO_H */ -- GitLab From d705073cdafa75286970dd30f722d0df584bae54 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 22 Jul 2015 15:05:19 +0200 Subject: [PATCH 1826/7006] gpio: etraxfs: add support for ARTPEC-3 Add support for the GIO block in the ARTPEC-3 SoC. The basic functionality is essentialy the same as the version in the ETRAX FS, except for a different set of ports, including a read-only port. Cc: devicetree@vger.kernel.org Signed-off-by: Rabin Vincent Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-etraxfs.txt | 3 +- drivers/gpio/gpio-etraxfs.c | 66 +++++++++++++++++-- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt index abf4db736c6e3..170194af30270 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-etraxfs.txt @@ -2,8 +2,9 @@ Axis ETRAX FS General I/O controller bindings Required properties: -- compatible: +- compatible: one of: - "axis,etraxfs-gio" + - "axis,artpec3-gio" - reg: Physical base address and length of the controller's registers. - #gpio-cells: Should be 3 - The first cell is the gpio offset number. diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 625a9ed411dac..27e5d8855205f 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -26,6 +26,17 @@ #define ETRAX_FS_r_pe_din 84 #define ETRAX_FS_rw_pe_oe 88 +#define ARTPEC3_r_pa_din 0 +#define ARTPEC3_rw_pa_dout 4 +#define ARTPEC3_rw_pa_oe 8 +#define ARTPEC3_r_pb_din 44 +#define ARTPEC3_rw_pb_dout 48 +#define ARTPEC3_rw_pb_oe 52 +#define ARTPEC3_r_pc_din 88 +#define ARTPEC3_rw_pc_dout 92 +#define ARTPEC3_rw_pc_oe 96 +#define ARTPEC3_r_pd_din 116 + struct etraxfs_gpio_port { const char *label; unsigned int oe; @@ -82,6 +93,40 @@ static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = { .ports = etraxfs_gpio_etraxfs_ports, }; +static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = { + { + .label = "A", + .ngpio = 32, + .oe = ARTPEC3_rw_pa_oe, + .dout = ARTPEC3_rw_pa_dout, + .din = ARTPEC3_r_pa_din, + }, + { + .label = "B", + .ngpio = 32, + .oe = ARTPEC3_rw_pb_oe, + .dout = ARTPEC3_rw_pb_dout, + .din = ARTPEC3_r_pb_din, + }, + { + .label = "C", + .ngpio = 16, + .oe = ARTPEC3_rw_pc_oe, + .dout = ARTPEC3_rw_pc_dout, + .din = ARTPEC3_r_pc_din, + }, + { + .label = "D", + .ngpio = 32, + .din = ARTPEC3_r_pd_din, + }, +}; + +static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = { + .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports), + .ports = etraxfs_gpio_artpec3_ports, +}; + static int etraxfs_gpio_of_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, u32 *flags) @@ -101,6 +146,10 @@ static const struct of_device_id etraxfs_gpio_of_table[] = { .compatible = "axis,etraxfs-gio", .data = &etraxfs_gpio_etraxfs, }, + { + .compatible = "axis,artpec3-gio", + .data = &etraxfs_gpio_artpec3, + }, {}, }; @@ -133,14 +182,19 @@ static int etraxfs_gpio_probe(struct platform_device *pdev) for (i = 0; i < info->num_ports; i++) { struct bgpio_chip *bgc = &chips[i]; const struct etraxfs_gpio_port *port = &info->ports[i]; + unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET; + void __iomem *dat = regs + port->din; + void __iomem *set = regs + port->dout; + void __iomem *dirout = regs + port->oe; + + if (dirout == set) { + dirout = set = NULL; + flags = BGPIOF_NO_OUTPUT; + } ret = bgpio_init(bgc, dev, 4, - regs + port->din, /* dat */ - regs + port->dout, /* set */ - NULL, /* clr */ - regs + port->oe, /* dirout */ - NULL, /* dirin */ - BGPIOF_READ_OUTPUT_REG_SET); + dat, set, NULL, dirout, NULL, + flags); if (ret) return ret; -- GitLab From ee04139d916a61454850f3e3c687f50f891fc8bd Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 23 Jul 2015 09:09:49 +0200 Subject: [PATCH 1827/7006] pinctrl/ARM: move GPIO and pinctrl deps to device tree This gets the GPIO ranges out of the driver and into the device tree where they belong. Standard DT bindings already exist for this. Since no systems with this are deployed we can just augment all device trees and the drivers at the same time and simplify the world. This also defines the array of GPIO chips related to the pin controller. Cc: arm@kernel.org Acked-by: Olof Johansson Signed-off-by: Linus Walleij --- arch/arm/boot/dts/ste-dbx5x0.dtsi | 23 ++++++++++-------- arch/arm/boot/dts/ste-nomadik-stn8815.dtsi | 8 ++++++- .../pinctrl/nomadik/pinctrl-nomadik-db8500.c | 21 ---------------- .../pinctrl/nomadik/pinctrl-nomadik-db8540.c | 24 ------------------- .../pinctrl/nomadik/pinctrl-nomadik-stn8815.c | 16 ------------- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 17 ------------- drivers/pinctrl/nomadik/pinctrl-nomadik.h | 4 ---- 7 files changed, 20 insertions(+), 93 deletions(-) diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi index 853684ad77733..b8fadb1d86162 100644 --- a/arch/arm/boot/dts/ste-dbx5x0.dtsi +++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi @@ -286,7 +286,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <0>; - + gpio-ranges = <&pinctrl 0 0 32>; clocks = <&prcc_pclk 1 9>; }; @@ -301,7 +301,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <1>; - + gpio-ranges = <&pinctrl 0 32 5>; clocks = <&prcc_pclk 1 9>; }; @@ -316,7 +316,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <2>; - + gpio-ranges = <&pinctrl 0 64 32>; clocks = <&prcc_pclk 3 8>; }; @@ -331,7 +331,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <3>; - + gpio-ranges = <&pinctrl 0 96 2>; clocks = <&prcc_pclk 3 8>; }; @@ -346,7 +346,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <4>; - + gpio-ranges = <&pinctrl 0 128 32>; clocks = <&prcc_pclk 3 8>; }; @@ -361,7 +361,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <5>; - + gpio-ranges = <&pinctrl 0 160 12>; clocks = <&prcc_pclk 3 8>; }; @@ -376,7 +376,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <6>; - + gpio-ranges = <&pinctrl 0 192 32>; clocks = <&prcc_pclk 2 11>; }; @@ -391,7 +391,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <7>; - + gpio-ranges = <&pinctrl 0 224 7>; clocks = <&prcc_pclk 2 11>; }; @@ -406,12 +406,15 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <8>; - + gpio-ranges = <&pinctrl 0 256 12>; clocks = <&prcc_pclk 5 1>; }; - pinctrl { + pinctrl: pinctrl { compatible = "stericsson,db8500-pinctrl"; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>, + <&gpio4>, <&gpio5>, <&gpio6>, <&gpio7>, + <&gpio8>; prcm = <&prcmu>; }; diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi index 9a5f2ba139b73..6846e3eb027d0 100644 --- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi +++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi @@ -52,6 +52,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <0>; + gpio-ranges = <&pinctrl 0 0 32>; clocks = <&pclk>; }; @@ -65,6 +66,7 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <1>; + gpio-ranges = <&pinctrl 0 32 32>; clocks = <&pclk>; }; @@ -78,12 +80,14 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <2>; + gpio-ranges = <&pinctrl 0 64 32>; clocks = <&pclk>; }; gpio3: gpio@101e7000 { compatible = "st,nomadik-gpio"; reg = <0x101e7000 0x80>; + ngpio = <28>; interrupt-parent = <&vica>; interrupts = <9>; interrupt-controller; @@ -91,11 +95,13 @@ gpio-controller; #gpio-cells = <2>; gpio-bank = <3>; + gpio-ranges = <&pinctrl 0 96 28>; clocks = <&pclk>; }; - pinctrl { + pinctrl: pinctrl { compatible = "stericsson,stn8815-pinctrl"; + nomadik-gpio-chips = <&gpio0>, <&gpio1>, <&gpio2>, <&gpio3>; /* Pin configurations */ uart0 { uart0_default_mux: uart0_mux { diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c index c74840729648e..8392083514fb6 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8500.c @@ -355,25 +355,6 @@ static const struct pinctrl_pin_desc nmk_db8500_pins[] = { PINCTRL_PIN(DB8500_PIN_AC27, "GPIO267_AC27"), }; -#define DB8500_GPIO_RANGE(a, b, c) { .name = "DB8500", .id = a, .base = b, \ - .pin_base = b, .npins = c } - -/* - * This matches the 32-pin gpio chips registered by the GPIO portion. This - * cannot be const since we assign the struct gpio_chip * pointer at runtime. - */ -static struct pinctrl_gpio_range nmk_db8500_ranges[] = { - DB8500_GPIO_RANGE(0, 0, 32), - DB8500_GPIO_RANGE(1, 32, 5), - DB8500_GPIO_RANGE(2, 64, 32), - DB8500_GPIO_RANGE(3, 96, 2), - DB8500_GPIO_RANGE(4, 128, 32), - DB8500_GPIO_RANGE(5, 160, 12), - DB8500_GPIO_RANGE(6, 192, 32), - DB8500_GPIO_RANGE(7, 224, 7), - DB8500_GPIO_RANGE(8, 256, 12), -}; - /* * Read the pin group names like this: * u0_a_1 = first groups of pins for uart0 on alt function a @@ -1238,8 +1219,6 @@ static const u16 db8500_prcm_gpiocr_regs[] = { }; static const struct nmk_pinctrl_soc_data nmk_db8500_soc = { - .gpio_ranges = nmk_db8500_ranges, - .gpio_num_ranges = ARRAY_SIZE(nmk_db8500_ranges), .pins = nmk_db8500_pins, .npins = ARRAY_SIZE(nmk_db8500_pins), .functions = nmk_db8500_functions, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c index d7ba5443bae05..2860eafd1b420 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-db8540.c @@ -341,28 +341,6 @@ static const struct pinctrl_pin_desc nmk_db8540_pins[] = { PINCTRL_PIN(DB8540_PIN_D17, "GPIO267_D17"), }; -#define DB8540_GPIO_RANGE(a, b, c) { .name = "db8540", .id = a, .base = b, \ - .pin_base = b, .npins = c } - -/* - * This matches the 32-pin gpio chips registered by the GPIO portion. This - * cannot be const since we assign the struct gpio_chip * pointer at runtime. - */ -static struct pinctrl_gpio_range nmk_db8540_ranges[] = { - DB8540_GPIO_RANGE(0, 0, 18), - DB8540_GPIO_RANGE(0, 22, 7), - DB8540_GPIO_RANGE(1, 33, 6), - DB8540_GPIO_RANGE(2, 64, 4), - DB8540_GPIO_RANGE(2, 70, 18), - DB8540_GPIO_RANGE(3, 116, 12), - DB8540_GPIO_RANGE(4, 128, 32), - DB8540_GPIO_RANGE(5, 160, 9), - DB8540_GPIO_RANGE(6, 192, 23), - DB8540_GPIO_RANGE(6, 219, 5), - DB8540_GPIO_RANGE(7, 224, 9), - DB8540_GPIO_RANGE(8, 256, 12), -}; - /* * Read the pin group names like this: * u0_a_1 = first groups of pins for uart0 on alt function a @@ -1247,8 +1225,6 @@ static const u16 db8540_prcm_gpiocr_regs[] = { }; static const struct nmk_pinctrl_soc_data nmk_db8540_soc = { - .gpio_ranges = nmk_db8540_ranges, - .gpio_num_ranges = ARRAY_SIZE(nmk_db8540_ranges), .pins = nmk_db8540_pins, .npins = ARRAY_SIZE(nmk_db8540_pins), .functions = nmk_db8540_functions, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c index 2cd71470f2700..a2de3b7a57a07 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -264,20 +264,6 @@ static const struct pinctrl_pin_desc nmk_stn8815_pins[] = { PINCTRL_PIN(STN8815_PIN_J22, "GPIO123_J22"), }; -#define STN8815_GPIO_RANGE(a, b, c) { .name = "STN8815", .id = a, .base = b, \ - .pin_base = b, .npins = c } - -/* - * This matches the 32-pin gpio chips registered by the GPIO portion. This - * cannot be const since we assign the struct gpio_chip * pointer at runtime. - */ -static struct pinctrl_gpio_range nmk_stn8815_ranges[] = { - STN8815_GPIO_RANGE(0, 0, 32), - STN8815_GPIO_RANGE(1, 32, 32), - STN8815_GPIO_RANGE(2, 64, 32), - STN8815_GPIO_RANGE(3, 96, 28), -}; - /* * Read the pin group names like this: * u0_a_1 = first groups of pins for uart0 on alt function a @@ -342,8 +328,6 @@ static const struct nmk_function nmk_stn8815_functions[] = { }; static const struct nmk_pinctrl_soc_data nmk_stn8815_soc = { - .gpio_ranges = nmk_stn8815_ranges, - .gpio_num_ranges = ARRAY_SIZE(nmk_stn8815_ranges), .pins = nmk_stn8815_pins, .npins = ARRAY_SIZE(nmk_stn8815_pins), .functions = nmk_stn8815_functions, diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 143d1c06078c9..8c87b2ec29c1e 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -2058,19 +2058,6 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) } } - /* - * We need all the GPIO drivers to probe FIRST, or we will not be able - * to obtain references to the struct gpio_chip * for them, and we - * need this to proceed. - */ - for (i = 0; i < npct->soc->gpio_num_ranges; i++) { - if (!nmk_gpio_chips[npct->soc->gpio_ranges[i].id]) { - dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i); - return -EPROBE_DEFER; - } - npct->soc->gpio_ranges[i].gc = &nmk_gpio_chips[npct->soc->gpio_ranges[i].id]->chip; - } - nmk_pinctrl_desc.pins = npct->soc->pins; nmk_pinctrl_desc.npins = npct->soc->npins; npct->dev = &pdev->dev; @@ -2081,10 +2068,6 @@ static int nmk_pinctrl_probe(struct platform_device *pdev) return PTR_ERR(npct->pctl); } - /* We will handle a range of GPIO pins */ - for (i = 0; i < npct->soc->gpio_num_ranges; i++) - pinctrl_add_gpio_range(npct->pctl, &npct->soc->gpio_ranges[i]); - platform_set_drvdata(pdev, npct); dev_info(&pdev->dev, "initialized Nomadik pin control driver\n"); diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.h b/drivers/pinctrl/nomadik/pinctrl-nomadik.h index d8215f1e70c74..30bba2a75a58a 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.h +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.h @@ -121,8 +121,6 @@ struct nmk_pingroup { /** * struct nmk_pinctrl_soc_data - Nomadik pin controller per-SoC configuration - * @gpio_ranges: An array of GPIO ranges for this SoC - * @gpio_num_ranges: The number of GPIO ranges for this SoC * @pins: An array describing all pins the pin controller affects. * All pins which are also GPIOs must be listed first within the * array, and be numbered identically to the GPIO controller's @@ -137,8 +135,6 @@ struct nmk_pingroup { * @prcm_gpiocr_registers: The array of PRCM GPIOCR registers on this SoC */ struct nmk_pinctrl_soc_data { - struct pinctrl_gpio_range *gpio_ranges; - unsigned gpio_num_ranges; const struct pinctrl_pin_desc *pins; unsigned npins; const struct nmk_function *functions; -- GitLab From 802bb9b67de75ea75638b8b1ca4b21a76a03bebf Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 22 Jul 2015 19:21:13 +0200 Subject: [PATCH 1828/7006] pinctrl: nomadik: depromote GPIO to subsystem_init() We no longer have to do GPIO initialization before the pinctrl initialization, instead we can initialize the pinctrl portions of the driver first and then the GPIO. Thus we can move GPIO initialization to a subsystem_initcall(), but not yet to a device_initcall(). Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c index 8c87b2ec29c1e..181fa546b2987 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c @@ -2102,15 +2102,15 @@ static struct platform_driver nmk_pinctrl_driver = { static int __init nmk_gpio_init(void) { - int ret; + return platform_driver_register(&nmk_gpio_driver); +} +subsys_initcall(nmk_gpio_init); - ret = platform_driver_register(&nmk_gpio_driver); - if (ret) - return ret; +static int __init nmk_pinctrl_init(void) +{ return platform_driver_register(&nmk_pinctrl_driver); } - -core_initcall(nmk_gpio_init); +core_initcall(nmk_pinctrl_init); MODULE_AUTHOR("Prafulla WADASKAR and Alessandro Rubini"); MODULE_DESCRIPTION("Nomadik GPIO Driver"); -- GitLab From 9511ca19dafbd503fb467d451fe331a6008f08cf Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 22 Jul 2015 18:25:52 +0100 Subject: [PATCH 1829/7006] arm64: rwlocks: don't fail trylock purely due to contention STXR can fail for a number of reasons, so don't fail an rwlock trylock operation simply because the STXR reported failure. I'm not aware of any issues with the current code, but this makes it consistent with spin_trylock and also other architectures (e.g. arch/arm). Reported-by: Catalin Marinas Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/spinlock.h | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index cee128732435c..0f08ba5cfb330 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h @@ -140,10 +140,11 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) unsigned int tmp; asm volatile( - " ldaxr %w0, %1\n" - " cbnz %w0, 1f\n" + "1: ldaxr %w0, %1\n" + " cbnz %w0, 2f\n" " stxr %w0, %w2, %1\n" - "1:\n" + " cbnz %w0, 1b\n" + "2:\n" : "=&r" (tmp), "+Q" (rw->lock) : "r" (0x80000000) : "memory"); @@ -209,11 +210,12 @@ static inline int arch_read_trylock(arch_rwlock_t *rw) unsigned int tmp, tmp2 = 1; asm volatile( - " ldaxr %w0, %2\n" + "1: ldaxr %w0, %2\n" " add %w0, %w0, #1\n" - " tbnz %w0, #31, 1f\n" + " tbnz %w0, #31, 2f\n" " stxr %w1, %w0, %2\n" - "1:\n" + " cbnz %w1, 1b\n" + "2:\n" : "=&r" (tmp), "+r" (tmp2), "+Q" (rw->lock) : : "memory"); -- GitLab From 144e9697a9e70b5549fd52df90111f1410bcbfeb Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 30 Apr 2015 18:55:50 +0100 Subject: [PATCH 1830/7006] arm64: cpufeature.h: add missing #include of kernel.h cpufeature.h makes use of DECLARE_BITMAP, which in turn relies on the BITS_TO_LONGS and DIV_ROUND_UP macros. This patch includes kernel.h in cpufeature.h to prevent all users having to do the same thing. Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index d71140b76773b..40e106f81f27e 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -31,6 +31,8 @@ #ifndef __ASSEMBLY__ +#include + struct arm64_cpu_capabilities { const char *desc; u16 capability; -- GitLab From c275f76bb4ce16fd0205da1e15f31b875013678e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Feb 2015 11:26:53 +0000 Subject: [PATCH 1831/7006] arm64: atomics: move ll/sc atomics into separate header file In preparation for the Large System Extension (LSE) atomic instructions introduced by ARM v8.1, move the current exclusive load/store (LL/SC) atomics into their own header file. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic.h | 180 +-------------------- arch/arm64/include/asm/atomic_ll_sc.h | 215 ++++++++++++++++++++++++++ 2 files changed, 221 insertions(+), 174 deletions(-) create mode 100644 arch/arm64/include/asm/atomic_ll_sc.h diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 866a71fca9a3c..632c47064722d 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -30,6 +30,8 @@ #ifdef __KERNEL__ +#include + /* * On ARM, ordinary assignment (str instruction) doesn't clear the local * strex/ldrex monitor on some implementations. The reason we can use it for @@ -38,86 +40,6 @@ #define atomic_read(v) ACCESS_ONCE((v)->counter) #define atomic_set(v,i) (((v)->counter) = (i)) -/* - * AArch64 UP and SMP safe atomic ops. We use load exclusive and - * store exclusive to ensure that these are atomic. We may loop - * to ensure that the update happens. - */ - -#define ATOMIC_OP(op, asm_op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - unsigned long tmp; \ - int result; \ - \ - asm volatile("// atomic_" #op "\n" \ -"1: ldxr %w0, %2\n" \ -" " #asm_op " %w0, %w0, %w3\n" \ -" stxr %w1, %w0, %2\n" \ -" cbnz %w1, 1b" \ - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i)); \ -} \ - -#define ATOMIC_OP_RETURN(op, asm_op) \ -static inline int atomic_##op##_return(int i, atomic_t *v) \ -{ \ - unsigned long tmp; \ - int result; \ - \ - asm volatile("// atomic_" #op "_return\n" \ -"1: ldxr %w0, %2\n" \ -" " #asm_op " %w0, %w0, %w3\n" \ -" stlxr %w1, %w0, %2\n" \ -" cbnz %w1, 1b" \ - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i) \ - : "memory"); \ - \ - smp_mb(); \ - return result; \ -} - -#define ATOMIC_OPS(op, asm_op) \ - ATOMIC_OP(op, asm_op) \ - ATOMIC_OP_RETURN(op, asm_op) - -ATOMIC_OPS(add, add) -ATOMIC_OPS(sub, sub) - -#define atomic_andnot atomic_andnot - -ATOMIC_OP(and, and) -ATOMIC_OP(andnot, bic) -ATOMIC_OP(or, orr) -ATOMIC_OP(xor, eor) - -#undef ATOMIC_OPS -#undef ATOMIC_OP_RETURN -#undef ATOMIC_OP - -static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) -{ - unsigned long tmp; - int oldval; - - smp_mb(); - - asm volatile("// atomic_cmpxchg\n" -"1: ldxr %w1, %2\n" -" cmp %w1, %w3\n" -" b.ne 2f\n" -" stxr %w0, %w4, %2\n" -" cbnz %w0, 1b\n" -"2:" - : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) - : "Ir" (old), "r" (new) - : "cc"); - - smp_mb(); - return oldval; -} - #define atomic_xchg(v, new) (xchg(&((v)->counter), new)) static inline int __atomic_add_unless(atomic_t *v, int a, int u) @@ -141,6 +63,8 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) +#define atomic_andnot atomic_andnot + /* * 64-bit atomic operations. */ @@ -149,102 +73,8 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u) #define atomic64_read(v) ACCESS_ONCE((v)->counter) #define atomic64_set(v,i) (((v)->counter) = (i)) -#define ATOMIC64_OP(op, asm_op) \ -static inline void atomic64_##op(long i, atomic64_t *v) \ -{ \ - long result; \ - unsigned long tmp; \ - \ - asm volatile("// atomic64_" #op "\n" \ -"1: ldxr %0, %2\n" \ -" " #asm_op " %0, %0, %3\n" \ -" stxr %w1, %0, %2\n" \ -" cbnz %w1, 1b" \ - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i)); \ -} \ - -#define ATOMIC64_OP_RETURN(op, asm_op) \ -static inline long atomic64_##op##_return(long i, atomic64_t *v) \ -{ \ - long result; \ - unsigned long tmp; \ - \ - asm volatile("// atomic64_" #op "_return\n" \ -"1: ldxr %0, %2\n" \ -" " #asm_op " %0, %0, %3\n" \ -" stlxr %w1, %0, %2\n" \ -" cbnz %w1, 1b" \ - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ - : "Ir" (i) \ - : "memory"); \ - \ - smp_mb(); \ - return result; \ -} - -#define ATOMIC64_OPS(op, asm_op) \ - ATOMIC64_OP(op, asm_op) \ - ATOMIC64_OP_RETURN(op, asm_op) - -ATOMIC64_OPS(add, add) -ATOMIC64_OPS(sub, sub) - -#define atomic64_andnot atomic64_andnot - -ATOMIC64_OP(and, and) -ATOMIC64_OP(andnot, bic) -ATOMIC64_OP(or, orr) -ATOMIC64_OP(xor, eor) - -#undef ATOMIC64_OPS -#undef ATOMIC64_OP_RETURN -#undef ATOMIC64_OP - -static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) -{ - long oldval; - unsigned long res; - - smp_mb(); - - asm volatile("// atomic64_cmpxchg\n" -"1: ldxr %1, %2\n" -" cmp %1, %3\n" -" b.ne 2f\n" -" stxr %w0, %4, %2\n" -" cbnz %w0, 1b\n" -"2:" - : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) - : "Ir" (old), "r" (new) - : "cc"); - - smp_mb(); - return oldval; -} - #define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) -static inline long atomic64_dec_if_positive(atomic64_t *v) -{ - long result; - unsigned long tmp; - - asm volatile("// atomic64_dec_if_positive\n" -"1: ldxr %0, %2\n" -" subs %0, %0, #1\n" -" b.mi 2f\n" -" stlxr %w1, %0, %2\n" -" cbnz %w1, 1b\n" -" dmb ish\n" -"2:" - : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) - : - : "cc", "memory"); - - return result; -} - static inline int atomic64_add_unless(atomic64_t *v, long a, long u) { long c, old; @@ -266,5 +96,7 @@ static inline int atomic64_add_unless(atomic64_t *v, long a, long u) #define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) #define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) +#define atomic64_andnot atomic64_andnot + #endif #endif diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h new file mode 100644 index 0000000000000..66e992a58f6b9 --- /dev/null +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -0,0 +1,215 @@ +/* + * Based on arch/arm/include/asm/atomic.h + * + * Copyright (C) 1996 Russell King. + * Copyright (C) 2002 Deep Blue Solutions Ltd. + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ASM_ATOMIC_LL_SC_H +#define __ASM_ATOMIC_LL_SC_H + +/* + * AArch64 UP and SMP safe atomic ops. We use load exclusive and + * store exclusive to ensure that these are atomic. We may loop + * to ensure that the update happens. + * + * NOTE: these functions do *not* follow the PCS and must explicitly + * save any clobbered registers other than x0 (regardless of return + * value). This is achieved through -fcall-saved-* compiler flags for + * this file, which unfortunately don't work on a per-function basis + * (the optimize attribute silently ignores these options). + */ + +#ifndef __LL_SC_INLINE +#define __LL_SC_INLINE static inline +#endif + +#ifndef __LL_SC_PREFIX +#define __LL_SC_PREFIX(x) x +#endif + +#define ATOMIC_OP(op, asm_op) \ +__LL_SC_INLINE void \ +__LL_SC_PREFIX(atomic_##op(int i, atomic_t *v)) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + asm volatile("// atomic_" #op "\n" \ +"1: ldxr %w0, %2\n" \ +" " #asm_op " %w0, %w0, %w3\n" \ +" stxr %w1, %w0, %2\n" \ +" cbnz %w1, 1b" \ + : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ + : "Ir" (i)); \ +} \ + +#define ATOMIC_OP_RETURN(op, asm_op) \ +__LL_SC_INLINE int \ +__LL_SC_PREFIX(atomic_##op##_return(int i, atomic_t *v)) \ +{ \ + unsigned long tmp; \ + int result; \ + \ + asm volatile("// atomic_" #op "_return\n" \ +"1: ldxr %w0, %2\n" \ +" " #asm_op " %w0, %w0, %w3\n" \ +" stlxr %w1, %w0, %2\n" \ +" cbnz %w1, 1b" \ + : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ + : "Ir" (i) \ + : "memory"); \ + \ + smp_mb(); \ + return result; \ +} + +#define ATOMIC_OPS(op, asm_op) \ + ATOMIC_OP(op, asm_op) \ + ATOMIC_OP_RETURN(op, asm_op) + +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, sub) + +ATOMIC_OP(and, and) +ATOMIC_OP(andnot, bic) +ATOMIC_OP(or, orr) +ATOMIC_OP(xor, eor) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +__LL_SC_INLINE int +__LL_SC_PREFIX(atomic_cmpxchg(atomic_t *ptr, int old, int new)) +{ + unsigned long tmp; + int oldval; + + smp_mb(); + + asm volatile("// atomic_cmpxchg\n" +"1: ldxr %w1, %2\n" +" cmp %w1, %w3\n" +" b.ne 2f\n" +" stxr %w0, %w4, %2\n" +" cbnz %w0, 1b\n" +"2:" + : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) + : "Ir" (old), "r" (new) + : "cc"); + + smp_mb(); + return oldval; +} + +#define ATOMIC64_OP(op, asm_op) \ +__LL_SC_INLINE void \ +__LL_SC_PREFIX(atomic64_##op(long i, atomic64_t *v)) \ +{ \ + long result; \ + unsigned long tmp; \ + \ + asm volatile("// atomic64_" #op "\n" \ +"1: ldxr %0, %2\n" \ +" " #asm_op " %0, %0, %3\n" \ +" stxr %w1, %0, %2\n" \ +" cbnz %w1, 1b" \ + : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ + : "Ir" (i)); \ +} \ + +#define ATOMIC64_OP_RETURN(op, asm_op) \ +__LL_SC_INLINE long \ +__LL_SC_PREFIX(atomic64_##op##_return(long i, atomic64_t *v)) \ +{ \ + long result; \ + unsigned long tmp; \ + \ + asm volatile("// atomic64_" #op "_return\n" \ +"1: ldxr %0, %2\n" \ +" " #asm_op " %0, %0, %3\n" \ +" stlxr %w1, %0, %2\n" \ +" cbnz %w1, 1b" \ + : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ + : "Ir" (i) \ + : "memory"); \ + \ + smp_mb(); \ + return result; \ +} + +#define ATOMIC64_OPS(op, asm_op) \ + ATOMIC64_OP(op, asm_op) \ + ATOMIC64_OP_RETURN(op, asm_op) + +ATOMIC64_OPS(add, add) +ATOMIC64_OPS(sub, sub) + +ATOMIC64_OP(and, and) +ATOMIC64_OP(andnot, bic) +ATOMIC64_OP(or, orr) +ATOMIC64_OP(xor, eor) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP + +__LL_SC_INLINE long +__LL_SC_PREFIX(atomic64_cmpxchg(atomic64_t *ptr, long old, long new)) +{ + long oldval; + unsigned long res; + + smp_mb(); + + asm volatile("// atomic64_cmpxchg\n" +"1: ldxr %1, %2\n" +" cmp %1, %3\n" +" b.ne 2f\n" +" stxr %w0, %4, %2\n" +" cbnz %w0, 1b\n" +"2:" + : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) + : "Ir" (old), "r" (new) + : "cc"); + + smp_mb(); + return oldval; +} + +__LL_SC_INLINE long +__LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) +{ + long result; + unsigned long tmp; + + asm volatile("// atomic64_dec_if_positive\n" +"1: ldxr %0, %2\n" +" subs %0, %0, #1\n" +" b.mi 2f\n" +" stlxr %w1, %0, %2\n" +" cbnz %w1, 1b\n" +" dmb ish\n" +"2:" + : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) + : + : "cc", "memory"); + + return result; +} + +#endif /* __ASM_ATOMIC_LL_SC_H */ -- GitLab From 40a1db2434a1b62332b1af25cfa14d7b8c0301fe Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 26 Jan 2015 18:46:19 +0000 Subject: [PATCH 1832/7006] arm64: elf: advertise 8.1 atomic instructions as new hwcap The ARM v8.1 architecture introduces new atomic instructions to the A64 instruction set for things like cmpxchg, so advertise their availability to userspace using a hwcap. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/uapi/asm/hwcap.h | 1 + arch/arm64/kernel/setup.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h index 73cf0f54d57cc..361c8a8ef55f3 100644 --- a/arch/arm64/include/uapi/asm/hwcap.h +++ b/arch/arm64/include/uapi/asm/hwcap.h @@ -27,5 +27,6 @@ #define HWCAP_SHA1 (1 << 5) #define HWCAP_SHA2 (1 << 6) #define HWCAP_CRC32 (1 << 7) +#define HWCAP_ATOMICS (1 << 8) #endif /* _UAPI__ASM_HWCAP_H */ diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index e7a1e719f1272..b2f9895ecf7b5 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -278,6 +278,19 @@ static void __init setup_processor(void) if (block && !(block & 0x8)) elf_hwcap |= HWCAP_CRC32; + block = (features >> 20) & 0xf; + if (!(block & 0x8)) { + switch (block) { + default: + case 2: + elf_hwcap |= HWCAP_ATOMICS; + case 1: + /* RESERVED */ + case 0: + break; + } + } + #ifdef CONFIG_COMPAT /* * ID_ISAR5_EL1 carries similar information as above, but pertaining to @@ -457,6 +470,7 @@ static const char *hwcap_str[] = { "sha1", "sha2", "crc32", + "atomics", NULL }; -- GitLab From d964b7229e7f94428a1e8d26999adffbe8a69db2 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Wed, 4 Feb 2015 12:17:55 +0000 Subject: [PATCH 1833/7006] arm64: alternatives: add cpu feature for lse atomics Add a CPU feature for the LSE atomic instructions, so that they can be patched in at runtime when we detect that they are supported. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 3 ++- arch/arm64/kernel/setup.c | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 40e106f81f27e..d9262d4b4dcd8 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -26,8 +26,9 @@ #define ARM64_WORKAROUND_845719 2 #define ARM64_HAS_SYSREG_GIC_CPUIF 3 #define ARM64_HAS_PAN 4 +#define ARM64_CPU_FEAT_LSE_ATOMICS 5 -#define ARM64_NCAPS 5 +#define ARM64_NCAPS 6 #ifndef __ASSEMBLY__ diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index b2f9895ecf7b5..f4fbbc884893f 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -284,6 +284,7 @@ static void __init setup_processor(void) default: case 2: elf_hwcap |= HWCAP_ATOMICS; + cpus_set_cap(ARM64_CPU_FEAT_LSE_ATOMICS); case 1: /* RESERVED */ case 0: -- GitLab From 613d2b272177c61c7cdb83be75a6e4c378d50ff9 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jul 2015 13:28:58 +0200 Subject: [PATCH 1834/7006] drm/atomic: pass old crtc state to atomic_begin/flush. In intel it's useful to keep track of some state changes with old crtc state vs new state, for example to disable initial planes or when a modeset's prevented during fastboot. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira [danvet: squash in fixup for exynos provided by Maarten.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c | 6 ++++-- drivers/gpu/drm/drm_atomic_helper.c | 8 ++++---- drivers/gpu/drm/drm_plane_helper.c | 4 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ++++-- drivers/gpu/drm/i915/intel_display.c | 10 ++++++---- drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c | 6 ++++-- drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c | 6 ++++-- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 6 ++++-- drivers/gpu/drm/sti/sti_drm_crtc.c | 6 ++++-- drivers/gpu/drm/tegra/dc.c | 6 ++++-- include/drm/drm_crtc_helper.h | 6 ++++-- 11 files changed, 44 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c index f69b92535505b..8b8fe3762ca9d 100644 --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c @@ -239,7 +239,8 @@ static int atmel_hlcdc_crtc_atomic_check(struct drm_crtc *c, return atmel_hlcdc_plane_prepare_disc_area(s); } -static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c) +static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c, + struct drm_crtc_state *old_s) { struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c); @@ -253,7 +254,8 @@ static void atmel_hlcdc_crtc_atomic_begin(struct drm_crtc *c) } } -static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc) +static void atmel_hlcdc_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_s) { /* TODO: write common plane control register if available */ } diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 10bcdd554501c..5ec13c7cc832a 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1164,7 +1164,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, if (!funcs || !funcs->atomic_begin) continue; - funcs->atomic_begin(crtc); + funcs->atomic_begin(crtc, old_crtc_state); } for_each_plane_in_state(old_state, plane, old_plane_state, i) { @@ -1194,7 +1194,7 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev, if (!funcs || !funcs->atomic_flush) continue; - funcs->atomic_flush(crtc); + funcs->atomic_flush(crtc, old_crtc_state); } } EXPORT_SYMBOL(drm_atomic_helper_commit_planes); @@ -1230,7 +1230,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) crtc_funcs = crtc->helper_private; if (crtc_funcs && crtc_funcs->atomic_begin) - crtc_funcs->atomic_begin(crtc); + crtc_funcs->atomic_begin(crtc, old_crtc_state); drm_for_each_plane_mask(plane, crtc->dev, plane_mask) { struct drm_plane_state *old_plane_state = @@ -1253,7 +1253,7 @@ drm_atomic_helper_commit_planes_on_crtc(struct drm_crtc_state *old_crtc_state) } if (crtc_funcs && crtc_funcs->atomic_flush) - crtc_funcs->atomic_flush(crtc); + crtc_funcs->atomic_flush(crtc, old_crtc_state); } EXPORT_SYMBOL(drm_atomic_helper_commit_planes_on_crtc); diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c index 46c7045733061..5e5a07af02c85 100644 --- a/drivers/gpu/drm/drm_plane_helper.c +++ b/drivers/gpu/drm/drm_plane_helper.c @@ -437,7 +437,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, for (i = 0; i < 2; i++) { if (crtc_funcs[i] && crtc_funcs[i]->atomic_begin) - crtc_funcs[i]->atomic_begin(crtc[i]); + crtc_funcs[i]->atomic_begin(crtc[i], crtc[i]->state); } /* @@ -452,7 +452,7 @@ int drm_plane_helper_commit(struct drm_plane *plane, for (i = 0; i < 2; i++) { if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush) - crtc_funcs[i]->atomic_flush(crtc[i]); + crtc_funcs[i]->atomic_flush(crtc[i], crtc[i]->state); } /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 644b4b76e0717..1610757230a5f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -80,7 +80,8 @@ exynos_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) exynos_crtc->ops->commit(exynos_crtc); } -static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) +static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); @@ -90,7 +91,8 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void exynos_crtc_atomic_flush(struct drm_crtc *crtc) +static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { } diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 07cee59edece4..40c73da2abcfd 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -102,8 +102,8 @@ static void vlv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); static void chv_prepare_pll(struct intel_crtc *crtc, const struct intel_crtc_state *pipe_config); -static void intel_begin_crtc_commit(struct drm_crtc *crtc); -static void intel_finish_crtc_commit(struct drm_crtc *crtc); +static void intel_begin_crtc_commit(struct drm_crtc *, struct drm_crtc_state *); +static void intel_finish_crtc_commit(struct drm_crtc *, struct drm_crtc_state *); static void skl_init_scalers(struct drm_device *dev, struct intel_crtc *intel_crtc, struct intel_crtc_state *crtc_state); static int i9xx_get_refclk(const struct intel_crtc_state *crtc_state, @@ -13628,7 +13628,8 @@ intel_disable_primary_plane(struct drm_plane *plane, dev_priv->display.update_primary_plane(crtc, NULL, 0, 0); } -static void intel_begin_crtc_commit(struct drm_crtc *crtc) +static void intel_begin_crtc_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct drm_device *dev = crtc->dev; struct intel_crtc *intel_crtc = to_intel_crtc(crtc); @@ -13644,7 +13645,8 @@ static void intel_begin_crtc_commit(struct drm_crtc *crtc) skl_detach_scalers(intel_crtc); } -static void intel_finish_crtc_commit(struct drm_crtc *crtc) +static void intel_finish_crtc_commit(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct intel_crtc *intel_crtc = to_intel_crtc(crtc); diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c index c4bb9d9c7667e..4dc158ed2e954 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c @@ -334,13 +334,15 @@ static int mdp4_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc) +static void mdp4_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); DBG("%s: begin", mdp4_crtc->name); } -static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc) +static void mdp4_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c index dea3d2e559b1c..4c1df4e6e5bca 100644 --- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c +++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c @@ -388,13 +388,15 @@ static int mdp5_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc) +static void mdp5_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); DBG("%s: begin", mdp5_crtc->name); } -static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc) +static void mdp5_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); struct drm_device *dev = crtc->dev; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 65d6ba6621aca..48cb19949ca3f 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -496,7 +496,8 @@ static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc) +static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct drm_pending_vblank_event *event = crtc->state->event; struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); @@ -512,7 +513,8 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc) +static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c index 6b641c5a2ec7d..26e63bf14efe2 100644 --- a/drivers/gpu/drm/sti/sti_drm_crtc.c +++ b/drivers/gpu/drm/sti/sti_drm_crtc.c @@ -164,7 +164,8 @@ sti_drm_crtc_mode_set_nofb(struct drm_crtc *crtc) sti_drm_crtc_mode_set(crtc, &crtc->state->adjusted_mode); } -static void sti_drm_atomic_begin(struct drm_crtc *crtc) +static void sti_drm_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct sti_mixer *mixer = to_sti_mixer(crtc); @@ -178,7 +179,8 @@ static void sti_drm_atomic_begin(struct drm_crtc *crtc) } } -static void sti_drm_atomic_flush(struct drm_crtc *crtc) +static void sti_drm_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { } diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c index a287e4fec8653..bf8ef3133e5bb 100644 --- a/drivers/gpu/drm/tegra/dc.c +++ b/drivers/gpu/drm/tegra/dc.c @@ -1277,7 +1277,8 @@ static int tegra_crtc_atomic_check(struct drm_crtc *crtc, return 0; } -static void tegra_crtc_atomic_begin(struct drm_crtc *crtc) +static void tegra_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct tegra_dc *dc = to_tegra_dc(crtc); @@ -1291,7 +1292,8 @@ static void tegra_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void tegra_crtc_atomic_flush(struct drm_crtc *crtc) +static void tegra_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct tegra_dc_state *state = to_dc_state(crtc->state); struct tegra_dc *dc = to_tegra_dc(crtc); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index c8fc187061de5..01cafcbe7deb5 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -108,8 +108,10 @@ struct drm_crtc_helper_funcs { /* atomic helpers */ int (*atomic_check)(struct drm_crtc *crtc, struct drm_crtc_state *state); - void (*atomic_begin)(struct drm_crtc *crtc); - void (*atomic_flush)(struct drm_crtc *crtc); + void (*atomic_begin)(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state); + void (*atomic_flush)(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state); }; /** -- GitLab From 9a69a9ac20f7f3435dd18019f902351c61a9ad1d Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jul 2015 11:34:55 +0200 Subject: [PATCH 1835/7006] drm: Make the connector dpms callback return a value, v2. This is required to properly handle failing dpms calls. When making a wait in i915 interruptible, I've noticed that the dpms sequence could fail with -ERESTARTSYS because it was waiting interruptibly for flips. So from now on allow drivers to fail in their connector dpms callback. Encoder and crtc dpms callbacks are unaffected. Changes since v1: - Update kerneldoc for the drm helper functions. Signed-off-by: Maarten Lankhorst [danvet: Resolve conflicts due to different merge order.] Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 28 ++++++++++++--------- drivers/gpu/drm/drm_crtc.c | 4 +-- drivers/gpu/drm/drm_crtc_helper.c | 9 ++++--- drivers/gpu/drm/i915/intel_crt.c | 8 +++--- drivers/gpu/drm/i915/intel_display.c | 6 +++-- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_dvo.c | 8 +++--- drivers/gpu/drm/i915/intel_sdvo.c | 8 +++--- drivers/gpu/drm/nouveau/nouveau_connector.c | 4 +-- drivers/gpu/drm/radeon/radeon_dp_mst.c | 3 ++- drivers/gpu/drm/tegra/dsi.c | 3 ++- drivers/gpu/drm/tegra/hdmi.c | 5 ++-- drivers/gpu/drm/tegra/rgb.c | 5 ++-- drivers/gpu/drm/tegra/sor.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.c | 3 ++- drivers/gpu/drm/vmwgfx/vmwgfx_kms.h | 2 +- include/drm/drm_atomic_helper.h | 4 +-- include/drm/drm_crtc.h | 2 +- include/drm/drm_crtc_helper.h | 2 +- 19 files changed, 65 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 5ec13c7cc832a..57847ae8ce8ce 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -1974,9 +1974,12 @@ EXPORT_SYMBOL(drm_atomic_helper_page_flip); * implementing the legacy DPMS connector interface. It computes the new desired * ->active state for the corresponding CRTC (if the connector is enabled) and * updates it. + * + * Returns: + * Returns 0 on success, negative errno numbers on failure. */ -void drm_atomic_helper_connector_dpms(struct drm_connector *connector, - int mode) +int drm_atomic_helper_connector_dpms(struct drm_connector *connector, + int mode) { struct drm_mode_config *config = &connector->dev->mode_config; struct drm_atomic_state *state; @@ -1985,6 +1988,7 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector, struct drm_connector *tmp_connector; int ret; bool active = false; + int old_mode = connector->dpms; if (mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; @@ -1993,18 +1997,19 @@ void drm_atomic_helper_connector_dpms(struct drm_connector *connector, crtc = connector->state->crtc; if (!crtc) - return; + return 0; - /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */ state = drm_atomic_state_alloc(connector->dev); if (!state) - return; + return -ENOMEM; state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc); retry: crtc_state = drm_atomic_get_crtc_state(state, crtc); - if (IS_ERR(crtc_state)) - return; + if (IS_ERR(crtc_state)) { + ret = PTR_ERR(crtc_state); + goto fail; + } WARN_ON(!drm_modeset_is_locked(&config->connection_mutex)); @@ -2023,17 +2028,16 @@ retry: if (ret != 0) goto fail; - /* Driver takes ownership of state on successful async commit. */ - return; + /* Driver takes ownership of state on successful commit. */ + return 0; fail: if (ret == -EDEADLK) goto backoff; + connector->dpms = old_mode; drm_atomic_state_free(state); - WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret); - - return; + return ret; backoff: drm_atomic_state_clear(state); drm_atomic_legacy_backoff(state); diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c index 1f0da41ae2a15..dfac394d06020 100644 --- a/drivers/gpu/drm/drm_crtc.c +++ b/drivers/gpu/drm/drm_crtc.c @@ -4753,9 +4753,9 @@ static int drm_mode_connector_set_obj_prop(struct drm_mode_object *obj, /* Do DPMS ourselves */ if (property == connector->dev->mode_config.dpms_property) { - if (connector->funcs->dpms) - (*connector->funcs->dpms)(connector, (int)value); ret = 0; + if (connector->funcs->dpms) + ret = (*connector->funcs->dpms)(connector, (int)value); } else if (connector->funcs->set_property) ret = connector->funcs->set_property(connector, property, value); diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c index d3d038f05bf7f..ef534758a02c6 100644 --- a/drivers/gpu/drm/drm_crtc_helper.c +++ b/drivers/gpu/drm/drm_crtc_helper.c @@ -762,15 +762,18 @@ static int drm_helper_choose_crtc_dpms(struct drm_crtc *crtc) * implementing the DPMS connector attribute. It computes the new desired DPMS * state for all encoders and crtcs in the output mesh and calls the ->dpms() * callback provided by the driver appropriately. + * + * Returns: + * Always returns 0. */ -void drm_helper_connector_dpms(struct drm_connector *connector, int mode) +int drm_helper_connector_dpms(struct drm_connector *connector, int mode) { struct drm_encoder *encoder = connector->encoder; struct drm_crtc *crtc = encoder ? encoder->crtc : NULL; int old_dpms, encoder_dpms = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; old_dpms = connector->dpms; connector->dpms = mode; @@ -802,7 +805,7 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode) } } - return; + return 0; } EXPORT_SYMBOL(drm_helper_connector_dpms); diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 521af2c069cb6..5d78c1feec814 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c @@ -237,7 +237,7 @@ static void intel_enable_crt(struct intel_encoder *encoder) } /* Special dpms function to support cloning between dvo/sdvo/crt. */ -static void intel_crt_dpms(struct drm_connector *connector, int mode) +static int intel_crt_dpms(struct drm_connector *connector, int mode) { struct drm_device *dev = connector->dev; struct intel_encoder *encoder = intel_attached_encoder(connector); @@ -249,7 +249,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; old_dpms = connector->dpms; connector->dpms = mode; @@ -258,7 +258,7 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) crtc = encoder->base.crtc; if (!crtc) { encoder->connectors_active = false; - return; + return 0; } /* We need the pipe to run for anything but OFF. */ @@ -281,6 +281,8 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode) } intel_modeset_check_state(connector->dev); + + return 0; } static enum drm_mode_status diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 40c73da2abcfd..13a6608be6898 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6429,14 +6429,14 @@ struct intel_connector *intel_connector_alloc(void) /* Even simpler default implementation, if there's really no special case to * consider. */ -void intel_connector_dpms(struct drm_connector *connector, int mode) +int intel_connector_dpms(struct drm_connector *connector, int mode) { /* All the simple cases only support two dpms states. */ if (mode != DRM_MODE_DPMS_ON) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; connector->dpms = mode; @@ -6445,6 +6445,8 @@ void intel_connector_dpms(struct drm_connector *connector, int mode) intel_encoder_dpms(to_intel_encoder(connector->encoder), mode); intel_modeset_check_state(connector->dev); + + return 0; } /* Simple connector->get_hw_state implementation for encoders that support only diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 47cef0e6c79c9..320c9e6bd8484 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -997,7 +997,7 @@ void intel_crtc_update_dpms(struct drm_crtc *crtc); void intel_encoder_destroy(struct drm_encoder *encoder); int intel_connector_init(struct intel_connector *); struct intel_connector *intel_connector_alloc(void); -void intel_connector_dpms(struct drm_connector *, int mode); +int intel_connector_dpms(struct drm_connector *, int mode); bool intel_connector_get_hw_state(struct intel_connector *connector); void intel_modeset_check_state(struct drm_device *dev); bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c index ece5bd754f85f..fd5e522abebb0 100644 --- a/drivers/gpu/drm/i915/intel_dvo.c +++ b/drivers/gpu/drm/i915/intel_dvo.c @@ -197,7 +197,7 @@ static void intel_enable_dvo(struct intel_encoder *encoder) } /* Special dpms function to support cloning between dvo/sdvo/crt. */ -static void intel_dvo_dpms(struct drm_connector *connector, int mode) +static int intel_dvo_dpms(struct drm_connector *connector, int mode) { struct intel_dvo *intel_dvo = intel_attached_dvo(connector); struct drm_crtc *crtc; @@ -208,7 +208,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; connector->dpms = mode; @@ -216,7 +216,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) crtc = intel_dvo->base.base.crtc; if (!crtc) { intel_dvo->base.connectors_active = false; - return; + return 0; } /* We call connector dpms manually below in case pipe dpms doesn't @@ -238,6 +238,8 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode) } intel_modeset_check_state(connector->dev); + + return 0; } static enum drm_mode_status diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index aa2fd751609cf..2c435a79d4da3 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c @@ -1509,7 +1509,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder) } /* Special dpms function to support cloning between dvo/sdvo/crt. */ -static void intel_sdvo_dpms(struct drm_connector *connector, int mode) +static int intel_sdvo_dpms(struct drm_connector *connector, int mode) { struct drm_crtc *crtc; struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector); @@ -1519,7 +1519,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) mode = DRM_MODE_DPMS_OFF; if (mode == connector->dpms) - return; + return 0; connector->dpms = mode; @@ -1527,7 +1527,7 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) crtc = intel_sdvo->base.base.crtc; if (!crtc) { intel_sdvo->base.connectors_active = false; - return; + return 0; } /* We set active outputs manually below in case pipe dpms doesn't change @@ -1551,6 +1551,8 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode) } intel_modeset_check_state(connector->dev); + + return 0; } static enum drm_mode_status diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 3162040bc3148..1f26eba245d10 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -919,7 +919,7 @@ nouveau_connector_funcs_lvds = { .force = nouveau_connector_force }; -static void +static int nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) { struct nouveau_encoder *nv_encoder = NULL; @@ -938,7 +938,7 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) } } - drm_helper_connector_dpms(connector, mode); + return drm_helper_connector_dpms(connector, mode); } static const struct drm_connector_funcs diff --git a/drivers/gpu/drm/radeon/radeon_dp_mst.c b/drivers/gpu/drm/radeon/radeon_dp_mst.c index e4fc8f3bf58b0..5e09c061847f5 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_mst.c +++ b/drivers/gpu/drm/radeon/radeon_dp_mst.c @@ -246,9 +246,10 @@ radeon_dp_mst_connector_destroy(struct drm_connector *connector) kfree(radeon_connector); } -static void radeon_connector_dpms(struct drm_connector *connector, int mode) +static int radeon_connector_dpms(struct drm_connector *connector, int mode) { DRM_DEBUG_KMS("\n"); + return 0; } static const struct drm_connector_funcs radeon_dp_mst_connector_funcs = { diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c index ed970f6229030..dc97c0b3681d9 100644 --- a/drivers/gpu/drm/tegra/dsi.c +++ b/drivers/gpu/drm/tegra/dsi.c @@ -726,8 +726,9 @@ static void tegra_dsi_soft_reset(struct tegra_dsi *dsi) tegra_dsi_soft_reset(dsi->slave); } -static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode) +static int tegra_dsi_connector_dpms(struct drm_connector *connector, int mode) { + return 0; } static void tegra_dsi_connector_reset(struct drm_connector *connector) diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c index 06ab1783bba11..fe4008a7ddba5 100644 --- a/drivers/gpu/drm/tegra/hdmi.c +++ b/drivers/gpu/drm/tegra/hdmi.c @@ -772,9 +772,10 @@ static bool tegra_output_is_hdmi(struct tegra_output *output) return drm_detect_hdmi_monitor(edid); } -static void tegra_hdmi_connector_dpms(struct drm_connector *connector, - int mode) +static int tegra_hdmi_connector_dpms(struct drm_connector *connector, + int mode) { + return 0; } static const struct drm_connector_funcs tegra_hdmi_connector_funcs = { diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c index 7cd833f5b5b59..9a99d213e1b1e 100644 --- a/drivers/gpu/drm/tegra/rgb.c +++ b/drivers/gpu/drm/tegra/rgb.c @@ -88,9 +88,10 @@ static void tegra_dc_write_regs(struct tegra_dc *dc, tegra_dc_writel(dc, table[i].value, table[i].offset); } -static void tegra_rgb_connector_dpms(struct drm_connector *connector, - int mode) +static int tegra_rgb_connector_dpms(struct drm_connector *connector, + int mode) { + return 0; } static const struct drm_connector_funcs tegra_rgb_connector_funcs = { diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c index 7591d8901f9a2..ee8ad0d4a0f28 100644 --- a/drivers/gpu/drm/tegra/sor.c +++ b/drivers/gpu/drm/tegra/sor.c @@ -866,8 +866,9 @@ static void tegra_sor_debugfs_exit(struct tegra_sor *sor) sor->debugfs_files = NULL; } -static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode) +static int tegra_sor_connector_dpms(struct drm_connector *connector, int mode) { + return 0; } static enum drm_connector_status diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c index 07cda8cbbddbc..2adc11bc09209 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.c @@ -1808,8 +1808,9 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, } } -void vmw_du_connector_dpms(struct drm_connector *connector, int mode) +int vmw_du_connector_dpms(struct drm_connector *connector, int mode) { + return 0; } void vmw_du_connector_save(struct drm_connector *connector) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h index 8d038c36bd575..f1a324cfb4c30 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_kms.h @@ -133,7 +133,7 @@ void vmw_du_crtc_gamma_set(struct drm_crtc *crtc, int vmw_du_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height); int vmw_du_crtc_cursor_move(struct drm_crtc *crtc, int x, int y); -void vmw_du_connector_dpms(struct drm_connector *connector, int mode); +int vmw_du_connector_dpms(struct drm_connector *connector, int mode); void vmw_du_connector_save(struct drm_connector *connector); void vmw_du_connector_restore(struct drm_connector *connector); enum drm_connector_status diff --git a/include/drm/drm_atomic_helper.h b/include/drm/drm_atomic_helper.h index cc1fee8a12d0a..11266d147a294 100644 --- a/include/drm/drm_atomic_helper.h +++ b/include/drm/drm_atomic_helper.h @@ -87,8 +87,8 @@ int drm_atomic_helper_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, struct drm_pending_vblank_event *event, uint32_t flags); -void drm_atomic_helper_connector_dpms(struct drm_connector *connector, - int mode); +int drm_atomic_helper_connector_dpms(struct drm_connector *connector, + int mode); /* default implementations for state handling */ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc); diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index 90a0ff70384a4..5746569651263 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -527,7 +527,7 @@ struct drm_connector_state { * etc. */ struct drm_connector_funcs { - void (*dpms)(struct drm_connector *connector, int mode); + int (*dpms)(struct drm_connector *connector, int mode); void (*save)(struct drm_connector *connector); void (*restore)(struct drm_connector *connector); void (*reset)(struct drm_connector *connector); diff --git a/include/drm/drm_crtc_helper.h b/include/drm/drm_crtc_helper.h index 01cafcbe7deb5..800e0d1cf32c2 100644 --- a/include/drm/drm_crtc_helper.h +++ b/include/drm/drm_crtc_helper.h @@ -189,7 +189,7 @@ extern bool drm_crtc_helper_set_mode(struct drm_crtc *crtc, extern bool drm_helper_crtc_in_use(struct drm_crtc *crtc); extern bool drm_helper_encoder_in_use(struct drm_encoder *encoder); -extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode); +extern int drm_helper_connector_dpms(struct drm_connector *connector, int mode); extern void drm_helper_move_panel_connectors_to_head(struct drm_device *); -- GitLab From 8c10342cb48f3140d9abeadcfd2fa6625d447282 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 27 Jul 2015 13:24:29 +0200 Subject: [PATCH 1836/7006] drm/atomic: Update legacy DPMS state during modesets, v3. This is required for DPMS to work correctly, during a modeset the DPMS property should be turned off, unless the state is crtc is made active in which case it should be set to DPMS on. Changes since v1: - Set DPMS to off when a connector is removed from a crtc too. - Update the legacy dpms property too. - Add an exception for the legacy dpms paths, it updates its own state. Changes since v2: - Do not preserve dpms property. Cc: dri-devel@lists.freedesktop.org Signed-off-by: Maarten Lankhorst Signed-off-by: Daniel Vetter --- drivers/gpu/drm/drm_atomic_helper.c | 26 ++++++++++++++++++++------ drivers/gpu/drm/i915/intel_display.c | 9 +-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c index 57847ae8ce8ce..0b475fae067d1 100644 --- a/drivers/gpu/drm/drm_atomic_helper.c +++ b/drivers/gpu/drm/drm_atomic_helper.c @@ -660,15 +660,29 @@ drm_atomic_helper_update_legacy_modeset_state(struct drm_device *dev, struct drm_crtc_state *old_crtc_state; int i; - /* clear out existing links */ + /* clear out existing links and update dpms */ for_each_connector_in_state(old_state, connector, old_conn_state, i) { - if (!connector->encoder) - continue; + if (connector->encoder) { + WARN_ON(!connector->encoder->crtc); + + connector->encoder->crtc = NULL; + connector->encoder = NULL; + } - WARN_ON(!connector->encoder->crtc); + crtc = connector->state->crtc; + if ((!crtc && old_conn_state->crtc) || + (crtc && drm_atomic_crtc_needs_modeset(crtc->state))) { + struct drm_property *dpms_prop = + dev->mode_config.dpms_property; + int mode = DRM_MODE_DPMS_OFF; - connector->encoder->crtc = NULL; - connector->encoder = NULL; + if (crtc && crtc->state->active) + mode = DRM_MODE_DPMS_ON; + + connector->dpms = mode; + drm_object_property_set_value(&connector->base, + dpms_prop, mode); + } } /* set new links */ diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 13a6608be6898..43b0f17ad1fa5 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12349,16 +12349,9 @@ intel_modeset_update_state(struct drm_atomic_state *state) continue; if (crtc->state->active) { - struct drm_property *dpms_property = - dev->mode_config.dpms_property; - - connector->dpms = DRM_MODE_DPMS_ON; - drm_object_property_set_value(&connector->base, dpms_property, DRM_MODE_DPMS_ON); - intel_encoder = to_intel_encoder(connector->encoder); intel_encoder->connectors_active = true; - } else - connector->dpms = DRM_MODE_DPMS_OFF; + } } } -- GitLab From c0385b24af15020a1e505f2c984db0d7c0d017e1 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Feb 2015 12:39:03 +0000 Subject: [PATCH 1837/7006] arm64: introduce CONFIG_ARM64_LSE_ATOMICS as fallback to ll/sc atomics In order to patch in the new atomic instructions at runtime, we need to generate wrappers around the out-of-line exclusive load/store atomics. This patch adds a new Kconfig option, CONFIG_ARM64_LSE_ATOMICS. which causes our atomic functions to branch to the out-of-line ll/sc implementations. To avoid the register spill overhead of the PCS, the out-of-line functions are compiled with specific compiler flags to force out-of-line save/restore of any registers that are usually caller-saved. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 12 ++ arch/arm64/include/asm/atomic.h | 9 ++ arch/arm64/include/asm/atomic_ll_sc.h | 19 ++- arch/arm64/include/asm/atomic_lse.h | 170 ++++++++++++++++++++++++++ arch/arm64/lib/Makefile | 13 ++ arch/arm64/lib/atomic_ll_sc.c | 3 + 6 files changed, 224 insertions(+), 2 deletions(-) create mode 100644 arch/arm64/include/asm/atomic_lse.h create mode 100644 arch/arm64/lib/atomic_ll_sc.c diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 5372e1e0c11c4..8dabffa82ef81 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -618,6 +618,18 @@ config ARM64_PAN The feature is detected at runtime, and will remain as a 'nop' instruction if the cpu does not implement the feature. +config ARM64_LSE_ATOMICS + bool "ARMv8.1 atomic instructions" + help + As part of the Large System Extensions, ARMv8.1 introduces new + atomic instructions that are designed specifically to scale in + very large systems. + + Say Y here to make use of these instructions for the in-kernel + atomic routines. This incurs a small overhead on CPUs that do + not support these instructions and requires the kernel to be + built with binutils >= 2.25. + menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 632c47064722d..84635f2d3d0a8 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -21,6 +21,7 @@ #define __ASM_ATOMIC_H #include +#include #include #include @@ -30,7 +31,15 @@ #ifdef __KERNEL__ +#define __ARM64_IN_ATOMIC_IMPL + +#ifdef CONFIG_ARM64_LSE_ATOMICS +#include +#else #include +#endif + +#undef __ARM64_IN_ATOMIC_IMPL /* * On ARM, ordinary assignment (str instruction) doesn't clear the local diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index 66e992a58f6b9..c33fa2cd399e3 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -21,6 +21,10 @@ #ifndef __ASM_ATOMIC_LL_SC_H #define __ASM_ATOMIC_LL_SC_H +#ifndef __ARM64_IN_ATOMIC_IMPL +#error "please don't include this file directly" +#endif + /* * AArch64 UP and SMP safe atomic ops. We use load exclusive and * store exclusive to ensure that these are atomic. We may loop @@ -41,6 +45,10 @@ #define __LL_SC_PREFIX(x) x #endif +#ifndef __LL_SC_EXPORT +#define __LL_SC_EXPORT(x) +#endif + #define ATOMIC_OP(op, asm_op) \ __LL_SC_INLINE void \ __LL_SC_PREFIX(atomic_##op(int i, atomic_t *v)) \ @@ -56,6 +64,7 @@ __LL_SC_PREFIX(atomic_##op(int i, atomic_t *v)) \ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ : "Ir" (i)); \ } \ +__LL_SC_EXPORT(atomic_##op); #define ATOMIC_OP_RETURN(op, asm_op) \ __LL_SC_INLINE int \ @@ -75,7 +84,8 @@ __LL_SC_PREFIX(atomic_##op##_return(int i, atomic_t *v)) \ \ smp_mb(); \ return result; \ -} +} \ +__LL_SC_EXPORT(atomic_##op##_return); #define ATOMIC_OPS(op, asm_op) \ ATOMIC_OP(op, asm_op) \ @@ -115,6 +125,7 @@ __LL_SC_PREFIX(atomic_cmpxchg(atomic_t *ptr, int old, int new)) smp_mb(); return oldval; } +__LL_SC_EXPORT(atomic_cmpxchg); #define ATOMIC64_OP(op, asm_op) \ __LL_SC_INLINE void \ @@ -131,6 +142,7 @@ __LL_SC_PREFIX(atomic64_##op(long i, atomic64_t *v)) \ : "=&r" (result), "=&r" (tmp), "+Q" (v->counter) \ : "Ir" (i)); \ } \ +__LL_SC_EXPORT(atomic64_##op); #define ATOMIC64_OP_RETURN(op, asm_op) \ __LL_SC_INLINE long \ @@ -150,7 +162,8 @@ __LL_SC_PREFIX(atomic64_##op##_return(long i, atomic64_t *v)) \ \ smp_mb(); \ return result; \ -} +} \ +__LL_SC_EXPORT(atomic64_##op##_return); #define ATOMIC64_OPS(op, asm_op) \ ATOMIC64_OP(op, asm_op) \ @@ -190,6 +203,7 @@ __LL_SC_PREFIX(atomic64_cmpxchg(atomic64_t *ptr, long old, long new)) smp_mb(); return oldval; } +__LL_SC_EXPORT(atomic64_cmpxchg); __LL_SC_INLINE long __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) @@ -211,5 +225,6 @@ __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) return result; } +__LL_SC_EXPORT(atomic64_dec_if_positive); #endif /* __ASM_ATOMIC_LL_SC_H */ diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h new file mode 100644 index 0000000000000..dce6ede740e88 --- /dev/null +++ b/arch/arm64/include/asm/atomic_lse.h @@ -0,0 +1,170 @@ +/* + * Based on arch/arm/include/asm/atomic.h + * + * Copyright (C) 1996 Russell King. + * Copyright (C) 2002 Deep Blue Solutions Ltd. + * Copyright (C) 2012 ARM Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __ASM_ATOMIC_LSE_H +#define __ASM_ATOMIC_LSE_H + +#ifndef __ARM64_IN_ATOMIC_IMPL +#error "please don't include this file directly" +#endif + +/* Move the ll/sc atomics out-of-line */ +#define __LL_SC_INLINE +#define __LL_SC_PREFIX(x) __ll_sc_##x +#define __LL_SC_EXPORT(x) EXPORT_SYMBOL(__LL_SC_PREFIX(x)) + +/* Macros for constructing calls to out-of-line ll/sc atomics */ +#define __LL_SC_CALL(op) \ + "bl\t" __stringify(__LL_SC_PREFIX(atomic_##op)) "\n" +#define __LL_SC_CALL64(op) \ + "bl\t" __stringify(__LL_SC_PREFIX(atomic64_##op)) "\n" + +#define ATOMIC_OP(op, asm_op) \ +static inline void atomic_##op(int i, atomic_t *v) \ +{ \ + register int w0 asm ("w0") = i; \ + register atomic_t *x1 asm ("x1") = v; \ + \ + asm volatile( \ + __LL_SC_CALL(op) \ + : "+r" (w0), "+Q" (v->counter) \ + : "r" (x1) \ + : "x30"); \ +} \ + +#define ATOMIC_OP_RETURN(op, asm_op) \ +static inline int atomic_##op##_return(int i, atomic_t *v) \ +{ \ + register int w0 asm ("w0") = i; \ + register atomic_t *x1 asm ("x1") = v; \ + \ + asm volatile( \ + __LL_SC_CALL(op##_return) \ + : "+r" (w0) \ + : "r" (x1) \ + : "x30", "memory"); \ + \ + return w0; \ +} + +#define ATOMIC_OPS(op, asm_op) \ + ATOMIC_OP(op, asm_op) \ + ATOMIC_OP_RETURN(op, asm_op) + +ATOMIC_OPS(add, add) +ATOMIC_OPS(sub, sub) + +ATOMIC_OP(and, and) +ATOMIC_OP(andnot, bic) +ATOMIC_OP(or, orr) +ATOMIC_OP(xor, eor) + +#undef ATOMIC_OPS +#undef ATOMIC_OP_RETURN +#undef ATOMIC_OP + +static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) +{ + register unsigned long x0 asm ("x0") = (unsigned long)ptr; + register int w1 asm ("w1") = old; + register int w2 asm ("w2") = new; + + asm volatile( + __LL_SC_CALL(cmpxchg) + : "+r" (x0) + : "r" (w1), "r" (w2) + : "x30", "cc", "memory"); + + return x0; +} + +#define ATOMIC64_OP(op, asm_op) \ +static inline void atomic64_##op(long i, atomic64_t *v) \ +{ \ + register long x0 asm ("x0") = i; \ + register atomic64_t *x1 asm ("x1") = v; \ + \ + asm volatile( \ + __LL_SC_CALL64(op) \ + : "+r" (x0), "+Q" (v->counter) \ + : "r" (x1) \ + : "x30"); \ +} \ + +#define ATOMIC64_OP_RETURN(op, asm_op) \ +static inline long atomic64_##op##_return(long i, atomic64_t *v) \ +{ \ + register long x0 asm ("x0") = i; \ + register atomic64_t *x1 asm ("x1") = v; \ + \ + asm volatile( \ + __LL_SC_CALL64(op##_return) \ + : "+r" (x0) \ + : "r" (x1) \ + : "x30", "memory"); \ + \ + return x0; \ +} + +#define ATOMIC64_OPS(op, asm_op) \ + ATOMIC64_OP(op, asm_op) \ + ATOMIC64_OP_RETURN(op, asm_op) + +ATOMIC64_OPS(add, add) +ATOMIC64_OPS(sub, sub) + +ATOMIC64_OP(and, and) +ATOMIC64_OP(andnot, bic) +ATOMIC64_OP(or, orr) +ATOMIC64_OP(xor, eor) + +#undef ATOMIC64_OPS +#undef ATOMIC64_OP_RETURN +#undef ATOMIC64_OP + +static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) +{ + register unsigned long x0 asm ("x0") = (unsigned long)ptr; + register long x1 asm ("x1") = old; + register long x2 asm ("x2") = new; + + asm volatile( + __LL_SC_CALL64(cmpxchg) + : "+r" (x0) + : "r" (x1), "r" (x2) + : "x30", "cc", "memory"); + + return x0; +} + +static inline long atomic64_dec_if_positive(atomic64_t *v) +{ + register unsigned long x0 asm ("x0") = (unsigned long)v; + + asm volatile( + __LL_SC_CALL64(dec_if_positive) + : "+r" (x0) + : + : "x30", "cc", "memory"); + + return x0; +} + +#endif /* __ASM_ATOMIC_LSE_H */ diff --git a/arch/arm64/lib/Makefile b/arch/arm64/lib/Makefile index d98d3e39879eb..1a811ecf71da8 100644 --- a/arch/arm64/lib/Makefile +++ b/arch/arm64/lib/Makefile @@ -3,3 +3,16 @@ lib-y := bitops.o clear_user.o delay.o copy_from_user.o \ clear_page.o memchr.o memcpy.o memmove.o memset.o \ memcmp.o strcmp.o strncmp.o strlen.o strnlen.o \ strchr.o strrchr.o + +# Tell the compiler to treat all general purpose registers as +# callee-saved, which allows for efficient runtime patching of the bl +# instruction in the caller with an atomic instruction when supported by +# the CPU. Result and argument registers are handled correctly, based on +# the function prototype. +lib-$(CONFIG_ARM64_LSE_ATOMICS) += atomic_ll_sc.o +CFLAGS_atomic_ll_sc.o := -fcall-used-x0 -ffixed-x1 -ffixed-x2 \ + -ffixed-x3 -ffixed-x4 -ffixed-x5 -ffixed-x6 \ + -ffixed-x7 -fcall-saved-x8 -fcall-saved-x9 \ + -fcall-saved-x10 -fcall-saved-x11 -fcall-saved-x12 \ + -fcall-saved-x13 -fcall-saved-x14 -fcall-saved-x15 \ + -fcall-saved-x16 -fcall-saved-x17 -fcall-saved-x18 diff --git a/arch/arm64/lib/atomic_ll_sc.c b/arch/arm64/lib/atomic_ll_sc.c new file mode 100644 index 0000000000000..b0c538b0da28c --- /dev/null +++ b/arch/arm64/lib/atomic_ll_sc.c @@ -0,0 +1,3 @@ +#include +#define __ARM64_IN_ATOMIC_IMPL +#include -- GitLab From c09d6a04d17d730b0463207a26ece082772b59ee Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 3 Feb 2015 16:14:13 +0000 Subject: [PATCH 1838/7006] arm64: atomics: patch in lse instructions when supported by the CPU On CPUs which support the LSE atomic instructions introduced in ARMv8.1, it makes sense to use them in preference to ll/sc sequences. This patch introduces runtime patching of atomic_t and atomic64_t routines so that the call-site for the out-of-line ll/sc sequences is patched with an LSE atomic instruction when we detect that the CPU supports it. If binutils is not recent enough to assemble the LSE instructions, then the ll/sc sequences are inlined as though CONFIG_ARM64_LSE_ATOMICS=n. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/Makefile | 13 +- arch/arm64/include/asm/atomic.h | 4 +- arch/arm64/include/asm/atomic_ll_sc.h | 12 - arch/arm64/include/asm/atomic_lse.h | 400 +++++++++++++++++++------- arch/arm64/include/asm/lse.h | 34 +++ arch/arm64/kernel/setup.c | 3 + 6 files changed, 342 insertions(+), 124 deletions(-) create mode 100644 arch/arm64/include/asm/lse.h diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile index 0953a97b51196..15ff5b4156fd7 100644 --- a/arch/arm64/Makefile +++ b/arch/arm64/Makefile @@ -17,7 +17,18 @@ GZFLAGS :=-9 KBUILD_DEFCONFIG := defconfig -KBUILD_CFLAGS += -mgeneral-regs-only +# Check for binutils support for specific extensions +lseinstr := $(call as-instr,.arch_extension lse,-DCONFIG_AS_LSE=1) + +ifeq ($(CONFIG_ARM64_LSE_ATOMICS), y) + ifeq ($(lseinstr),) +$(warning LSE atomics not supported by binutils) + endif +endif + +KBUILD_CFLAGS += -mgeneral-regs-only $(lseinstr) +KBUILD_AFLAGS += $(lseinstr) + ifeq ($(CONFIG_CPU_BIG_ENDIAN), y) KBUILD_CPPFLAGS += -mbig-endian AS += -EB diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 84635f2d3d0a8..836226d5e12cd 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -21,11 +21,11 @@ #define __ASM_ATOMIC_H #include -#include #include #include #include +#include #define ATOMIC_INIT(i) { (i) } @@ -33,7 +33,7 @@ #define __ARM64_IN_ATOMIC_IMPL -#ifdef CONFIG_ARM64_LSE_ATOMICS +#if defined(CONFIG_ARM64_LSE_ATOMICS) && defined(CONFIG_AS_LSE) #include #else #include diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index c33fa2cd399e3..4b981ba57e788 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -37,18 +37,6 @@ * (the optimize attribute silently ignores these options). */ -#ifndef __LL_SC_INLINE -#define __LL_SC_INLINE static inline -#endif - -#ifndef __LL_SC_PREFIX -#define __LL_SC_PREFIX(x) x -#endif - -#ifndef __LL_SC_EXPORT -#define __LL_SC_EXPORT(x) -#endif - #define ATOMIC_OP(op, asm_op) \ __LL_SC_INLINE void \ __LL_SC_PREFIX(atomic_##op(int i, atomic_t *v)) \ diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index dce6ede740e88..6e21b5e0c9d62 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -25,60 +25,129 @@ #error "please don't include this file directly" #endif -/* Move the ll/sc atomics out-of-line */ -#define __LL_SC_INLINE -#define __LL_SC_PREFIX(x) __ll_sc_##x -#define __LL_SC_EXPORT(x) EXPORT_SYMBOL(__LL_SC_PREFIX(x)) - -/* Macros for constructing calls to out-of-line ll/sc atomics */ -#define __LL_SC_CALL(op) \ - "bl\t" __stringify(__LL_SC_PREFIX(atomic_##op)) "\n" -#define __LL_SC_CALL64(op) \ - "bl\t" __stringify(__LL_SC_PREFIX(atomic64_##op)) "\n" - -#define ATOMIC_OP(op, asm_op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ - \ - asm volatile( \ - __LL_SC_CALL(op) \ - : "+r" (w0), "+Q" (v->counter) \ - : "r" (x1) \ - : "x30"); \ -} \ - -#define ATOMIC_OP_RETURN(op, asm_op) \ -static inline int atomic_##op##_return(int i, atomic_t *v) \ -{ \ - register int w0 asm ("w0") = i; \ - register atomic_t *x1 asm ("x1") = v; \ - \ - asm volatile( \ - __LL_SC_CALL(op##_return) \ - : "+r" (w0) \ - : "r" (x1) \ - : "x30", "memory"); \ - \ - return w0; \ -} - -#define ATOMIC_OPS(op, asm_op) \ - ATOMIC_OP(op, asm_op) \ - ATOMIC_OP_RETURN(op, asm_op) - -ATOMIC_OPS(add, add) -ATOMIC_OPS(sub, sub) - -ATOMIC_OP(and, and) -ATOMIC_OP(andnot, bic) -ATOMIC_OP(or, orr) -ATOMIC_OP(xor, eor) - -#undef ATOMIC_OPS -#undef ATOMIC_OP_RETURN -#undef ATOMIC_OP +#define __LL_SC_ATOMIC(op) __LL_SC_CALL(atomic_##op) + +static inline void atomic_andnot(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(andnot), + " stclr %w[i], %[v]\n") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic_or(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(or), + " stset %w[i], %[v]\n") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic_xor(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(xor), + " steor %w[i], %[v]\n") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic_add(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC(add), + " stadd %w[i], %[v]\n") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline int atomic_add_return(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC(add_return), + /* LSE atomics */ + " ldaddal %w[i], w30, %[v]\n" + " add %w[i], %w[i], w30") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30", "memory"); + + return w0; +} + +static inline void atomic_and(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC(and), + /* LSE atomics */ + " mvn %w[i], %w[i]\n" + " stclr %w[i], %[v]") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic_sub(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC(sub), + /* LSE atomics */ + " neg %w[i], %w[i]\n" + " stadd %w[i], %[v]") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline int atomic_sub_return(int i, atomic_t *v) +{ + register int w0 asm ("w0") = i; + register atomic_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC(sub_return) + " nop", + /* LSE atomics */ + " neg %w[i], %w[i]\n" + " ldaddal %w[i], w30, %[v]\n" + " add %w[i], %w[i], w30") + : [i] "+r" (w0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30", "memory"); + + return w0; +} static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) { @@ -86,69 +155,164 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) register int w1 asm ("w1") = old; register int w2 asm ("w2") = new; - asm volatile( - __LL_SC_CALL(cmpxchg) - : "+r" (x0) - : "r" (w1), "r" (w2) + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC(cmpxchg) + " nop", + /* LSE atomics */ + " mov w30, %w[old]\n" + " casal w30, %w[new], %[v]\n" + " mov %w[ret], w30") + : [ret] "+r" (x0), [v] "+Q" (ptr->counter) + : [old] "r" (w1), [new] "r" (w2) : "x30", "cc", "memory"); return x0; } -#define ATOMIC64_OP(op, asm_op) \ -static inline void atomic64_##op(long i, atomic64_t *v) \ -{ \ - register long x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ - \ - asm volatile( \ - __LL_SC_CALL64(op) \ - : "+r" (x0), "+Q" (v->counter) \ - : "r" (x1) \ - : "x30"); \ -} \ - -#define ATOMIC64_OP_RETURN(op, asm_op) \ -static inline long atomic64_##op##_return(long i, atomic64_t *v) \ -{ \ - register long x0 asm ("x0") = i; \ - register atomic64_t *x1 asm ("x1") = v; \ - \ - asm volatile( \ - __LL_SC_CALL64(op##_return) \ - : "+r" (x0) \ - : "r" (x1) \ - : "x30", "memory"); \ - \ - return x0; \ -} - -#define ATOMIC64_OPS(op, asm_op) \ - ATOMIC64_OP(op, asm_op) \ - ATOMIC64_OP_RETURN(op, asm_op) - -ATOMIC64_OPS(add, add) -ATOMIC64_OPS(sub, sub) - -ATOMIC64_OP(and, and) -ATOMIC64_OP(andnot, bic) -ATOMIC64_OP(or, orr) -ATOMIC64_OP(xor, eor) - -#undef ATOMIC64_OPS -#undef ATOMIC64_OP_RETURN -#undef ATOMIC64_OP +#undef __LL_SC_ATOMIC +#define __LL_SC_ATOMIC64(op) __LL_SC_CALL(atomic64_##op) + +static inline void atomic64_andnot(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(andnot), + " stclr %[i], %[v]\n") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic64_or(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(or), + " stset %[i], %[v]\n") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic64_xor(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(xor), + " steor %[i], %[v]\n") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic64_add(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN(__LL_SC_ATOMIC64(add), + " stadd %[i], %[v]\n") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline long atomic64_add_return(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC64(add_return), + /* LSE atomics */ + " ldaddal %[i], x30, %[v]\n" + " add %[i], %[i], x30") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30", "memory"); + + return x0; +} + +static inline void atomic64_and(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC64(and), + /* LSE atomics */ + " mvn %[i], %[i]\n" + " stclr %[i], %[v]") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline void atomic64_sub(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC64(sub), + /* LSE atomics */ + " neg %[i], %[i]\n" + " stadd %[i], %[v]") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30"); +} + +static inline long atomic64_sub_return(long i, atomic64_t *v) +{ + register long x0 asm ("x0") = i; + register atomic64_t *x1 asm ("x1") = v; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC64(sub_return) + " nop", + /* LSE atomics */ + " neg %[i], %[i]\n" + " ldaddal %[i], x30, %[v]\n" + " add %[i], %[i], x30") + : [i] "+r" (x0), [v] "+Q" (v->counter) + : "r" (x1) + : "x30", "memory"); + + return x0; +} static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) { register unsigned long x0 asm ("x0") = (unsigned long)ptr; register long x1 asm ("x1") = old; register long x2 asm ("x2") = new; - asm volatile( - __LL_SC_CALL64(cmpxchg) - : "+r" (x0) - : "r" (x1), "r" (x2) + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC64(cmpxchg) + " nop", + /* LSE atomics */ + " mov x30, %[old]\n" + " casal x30, %[new], %[v]\n" + " mov %[ret], x30") + : [ret] "+r" (x0), [v] "+Q" (ptr->counter) + : [old] "r" (x1), [new] "r" (x2) : "x30", "cc", "memory"); return x0; @@ -156,15 +320,33 @@ static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) static inline long atomic64_dec_if_positive(atomic64_t *v) { - register unsigned long x0 asm ("x0") = (unsigned long)v; + register long x0 asm ("x0") = (long)v; - asm volatile( - __LL_SC_CALL64(dec_if_positive) - : "+r" (x0) + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " nop\n" + __LL_SC_ATOMIC64(dec_if_positive) + " nop\n" + " nop\n" + " nop\n" + " nop\n" + " nop", + /* LSE atomics */ + "1: ldr x30, %[v]\n" + " subs %[ret], x30, #1\n" + " b.mi 2f\n" + " casal x30, %[ret], %[v]\n" + " sub x30, x30, #1\n" + " sub x30, x30, %[ret]\n" + " cbnz x30, 1b\n" + "2:") + : [ret] "+&r" (x0), [v] "+Q" (v->counter) : : "x30", "cc", "memory"); return x0; } +#undef __LL_SC_ATOMIC64 + #endif /* __ASM_ATOMIC_LSE_H */ diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h new file mode 100644 index 0000000000000..d516624a461ed --- /dev/null +++ b/arch/arm64/include/asm/lse.h @@ -0,0 +1,34 @@ +#ifndef __ASM_LSE_H +#define __ASM_LSE_H + +#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) + +#include + +#include +#include + +__asm__(".arch_extension lse"); + +/* Move the ll/sc atomics out-of-line */ +#define __LL_SC_INLINE +#define __LL_SC_PREFIX(x) __ll_sc_##x +#define __LL_SC_EXPORT(x) EXPORT_SYMBOL(__LL_SC_PREFIX(x)) + +/* Macro for constructing calls to out-of-line ll/sc atomics */ +#define __LL_SC_CALL(op) "bl\t" __stringify(__LL_SC_PREFIX(op)) "\n" + +/* In-line patching at runtime */ +#define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ + ALTERNATIVE(llsc, lse, ARM64_CPU_FEAT_LSE_ATOMICS) + +#else + +#define __LL_SC_INLINE static inline +#define __LL_SC_PREFIX(x) x +#define __LL_SC_EXPORT(x) + +#define ARM64_LSE_ATOMIC_INSN(llsc, lse) llsc + +#endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ +#endif /* __ASM_LSE_H */ diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index f4fbbc884893f..97785c01acbfc 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -285,6 +285,9 @@ static void __init setup_processor(void) case 2: elf_hwcap |= HWCAP_ATOMICS; cpus_set_cap(ARM64_CPU_FEAT_LSE_ATOMICS); + if (IS_ENABLED(CONFIG_AS_LSE) && + IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS)) + pr_info("LSE atomics supported\n"); case 1: /* RESERVED */ case 0: -- GitLab From 81bb5c6420635dfd058c210bd342c29c95ccd145 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 10 Feb 2015 03:03:15 +0000 Subject: [PATCH 1839/7006] arm64: locks: patch in lse instructions when supported by the CPU On CPUs which support the LSE atomic instructions introduced in ARMv8.1, it makes sense to use them in preference to ll/sc sequences. This patch introduces runtime patching of our locking functions so that LSE atomic instructions are used for spinlocks and rwlocks. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/spinlock.h | 137 +++++++++++++++++++++++------- 1 file changed, 108 insertions(+), 29 deletions(-) diff --git a/arch/arm64/include/asm/spinlock.h b/arch/arm64/include/asm/spinlock.h index 0f08ba5cfb330..87ae7efa12118 100644 --- a/arch/arm64/include/asm/spinlock.h +++ b/arch/arm64/include/asm/spinlock.h @@ -16,6 +16,7 @@ #ifndef __ASM_SPINLOCK_H #define __ASM_SPINLOCK_H +#include #include #include @@ -38,11 +39,21 @@ static inline void arch_spin_lock(arch_spinlock_t *lock) asm volatile( /* Atomically increment the next ticket. */ + ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ " prfm pstl1strm, %3\n" "1: ldaxr %w0, %3\n" " add %w1, %w0, %w5\n" " stxr %w2, %w1, %3\n" -" cbnz %w2, 1b\n" +" cbnz %w2, 1b\n", + /* LSE atomics */ +" mov %w2, %w5\n" +" ldadda %w2, %w0, %3\n" +" nop\n" +" nop\n" +" nop\n" + ) + /* Did we get the lock? */ " eor %w1, %w0, %w0, ror #16\n" " cbz %w1, 3f\n" @@ -67,15 +78,25 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) unsigned int tmp; arch_spinlock_t lockval; - asm volatile( -" prfm pstl1strm, %2\n" -"1: ldaxr %w0, %2\n" -" eor %w1, %w0, %w0, ror #16\n" -" cbnz %w1, 2f\n" -" add %w0, %w0, %3\n" -" stxr %w1, %w0, %2\n" -" cbnz %w1, 1b\n" -"2:" + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " prfm pstl1strm, %2\n" + "1: ldaxr %w0, %2\n" + " eor %w1, %w0, %w0, ror #16\n" + " cbnz %w1, 2f\n" + " add %w0, %w0, %3\n" + " stxr %w1, %w0, %2\n" + " cbnz %w1, 1b\n" + "2:", + /* LSE atomics */ + " ldr %w0, %2\n" + " eor %w1, %w0, %w0, ror #16\n" + " cbnz %w1, 1f\n" + " add %w1, %w0, %3\n" + " casa %w0, %w1, %2\n" + " and %w1, %w1, #0xffff\n" + " eor %w1, %w1, %w0, lsr #16\n" + "1:") : "=&r" (lockval), "=&r" (tmp), "+Q" (*lock) : "I" (1 << TICKET_SHIFT) : "memory"); @@ -85,10 +106,19 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) static inline void arch_spin_unlock(arch_spinlock_t *lock) { - asm volatile( -" stlrh %w1, %0\n" - : "=Q" (lock->owner) - : "r" (lock->owner + 1) + unsigned long tmp; + + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " ldr %w1, %0\n" + " add %w1, %w1, #1\n" + " stlrh %w1, %0", + /* LSE atomics */ + " mov %w1, #1\n" + " nop\n" + " staddlh %w1, %0") + : "=Q" (lock->owner), "=&r" (tmp) + : : "memory"); } @@ -123,13 +153,24 @@ static inline void arch_write_lock(arch_rwlock_t *rw) { unsigned int tmp; - asm volatile( + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ " sevl\n" "1: wfe\n" "2: ldaxr %w0, %1\n" " cbnz %w0, 1b\n" " stxr %w0, %w2, %1\n" " cbnz %w0, 2b\n" + " nop", + /* LSE atomics */ + "1: mov %w0, wzr\n" + "2: casa %w0, %w2, %1\n" + " cbz %w0, 3f\n" + " ldxr %w0, %1\n" + " cbz %w0, 2b\n" + " wfe\n" + " b 1b\n" + "3:") : "=&r" (tmp), "+Q" (rw->lock) : "r" (0x80000000) : "memory"); @@ -139,12 +180,18 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) { unsigned int tmp; - asm volatile( + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: ldaxr %w0, %1\n" " cbnz %w0, 2f\n" " stxr %w0, %w2, %1\n" " cbnz %w0, 1b\n" - "2:\n" + "2:", + /* LSE atomics */ + " mov %w0, wzr\n" + " casa %w0, %w2, %1\n" + " nop\n" + " nop") : "=&r" (tmp), "+Q" (rw->lock) : "r" (0x80000000) : "memory"); @@ -154,9 +201,10 @@ static inline int arch_write_trylock(arch_rwlock_t *rw) static inline void arch_write_unlock(arch_rwlock_t *rw) { - asm volatile( - " stlr %w1, %0\n" - : "=Q" (rw->lock) : "r" (0) : "memory"); + asm volatile(ARM64_LSE_ATOMIC_INSN( + " stlr wzr, %0", + " swpl wzr, wzr, %0") + : "=Q" (rw->lock) :: "memory"); } /* write_can_lock - would write_trylock() succeed? */ @@ -173,6 +221,10 @@ static inline void arch_write_unlock(arch_rwlock_t *rw) * * The memory barriers are implicit with the load-acquire and store-release * instructions. + * + * Note that in UNDEFINED cases, such as unlocking a lock twice, the LL/SC + * and LSE implementations may exhibit different behaviour (although this + * will have no effect on lockdep). */ static inline void arch_read_lock(arch_rwlock_t *rw) { @@ -180,26 +232,43 @@ static inline void arch_read_lock(arch_rwlock_t *rw) asm volatile( " sevl\n" + ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: wfe\n" "2: ldaxr %w0, %2\n" " add %w0, %w0, #1\n" " tbnz %w0, #31, 1b\n" " stxr %w1, %w0, %2\n" - " cbnz %w1, 2b\n" + " nop\n" + " cbnz %w1, 2b", + /* LSE atomics */ + "1: wfe\n" + "2: ldxr %w0, %2\n" + " adds %w1, %w0, #1\n" + " tbnz %w1, #31, 1b\n" + " casa %w0, %w1, %2\n" + " sbc %w0, %w1, %w0\n" + " cbnz %w0, 2b") : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock) : - : "memory"); + : "cc", "memory"); } static inline void arch_read_unlock(arch_rwlock_t *rw) { unsigned int tmp, tmp2; - asm volatile( + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: ldxr %w0, %2\n" " sub %w0, %w0, #1\n" " stlxr %w1, %w0, %2\n" - " cbnz %w1, 1b\n" + " cbnz %w1, 1b", + /* LSE atomics */ + " movn %w0, #0\n" + " nop\n" + " nop\n" + " staddl %w0, %2") : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock) : : "memory"); @@ -207,18 +276,28 @@ static inline void arch_read_unlock(arch_rwlock_t *rw) static inline int arch_read_trylock(arch_rwlock_t *rw) { - unsigned int tmp, tmp2 = 1; + unsigned int tmp, tmp2; - asm volatile( + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ + " mov %w1, #1\n" "1: ldaxr %w0, %2\n" " add %w0, %w0, #1\n" " tbnz %w0, #31, 2f\n" " stxr %w1, %w0, %2\n" " cbnz %w1, 1b\n" - "2:\n" - : "=&r" (tmp), "+r" (tmp2), "+Q" (rw->lock) + "2:", + /* LSE atomics */ + " ldr %w0, %2\n" + " adds %w1, %w0, #1\n" + " tbnz %w1, #31, 1f\n" + " casa %w0, %w1, %2\n" + " sbc %w1, %w1, %w0\n" + " nop\n" + "1:") + : "=&r" (tmp), "=&r" (tmp2), "+Q" (rw->lock) : - : "memory"); + : "cc", "memory"); return !tmp2; } -- GitLab From 084f903727e1c3a61d6bcdaeeed30bddc6d7f65a Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 12 Feb 2015 04:17:37 +0000 Subject: [PATCH 1840/7006] arm64: bitops: patch in lse instructions when supported by the CPU On CPUs which support the LSE atomic instructions introduced in ARMv8.1, it makes sense to use them in preference to ll/sc sequences. This patch introduces runtime patching of our bitops functions so that LSE atomic instructions are used instead. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/lse.h | 23 +++++++++++++++++-- arch/arm64/lib/bitops.S | 43 ++++++++++++++++++++---------------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h index d516624a461ed..fb3ac56a2cc04 100644 --- a/arch/arm64/include/asm/lse.h +++ b/arch/arm64/include/asm/lse.h @@ -4,10 +4,19 @@ #if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) #include - #include #include +#ifdef __ASSEMBLER__ + +.arch_extension lse + +.macro alt_lse, llsc, lse + alternative_insn "\llsc", "\lse", ARM64_CPU_FEAT_LSE_ATOMICS +.endm + +#else /* __ASSEMBLER__ */ + __asm__(".arch_extension lse"); /* Move the ll/sc atomics out-of-line */ @@ -22,7 +31,16 @@ __asm__(".arch_extension lse"); #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ ALTERNATIVE(llsc, lse, ARM64_CPU_FEAT_LSE_ATOMICS) -#else +#endif /* __ASSEMBLER__ */ +#else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ + +#ifdef __ASSEMBLER__ + +.macro alt_lse, llsc, lse + \llsc +.endm + +#else /* __ASSEMBLER__ */ #define __LL_SC_INLINE static inline #define __LL_SC_PREFIX(x) x @@ -30,5 +48,6 @@ __asm__(".arch_extension lse"); #define ARM64_LSE_ATOMIC_INSN(llsc, lse) llsc +#endif /* __ASSEMBLER__ */ #endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ #endif /* __ASM_LSE_H */ diff --git a/arch/arm64/lib/bitops.S b/arch/arm64/lib/bitops.S index 7dac371cc9a2f..bc18457c2bba6 100644 --- a/arch/arm64/lib/bitops.S +++ b/arch/arm64/lib/bitops.S @@ -18,52 +18,57 @@ #include #include +#include /* * x0: bits 5:0 bit offset * bits 31:6 word offset * x1: address */ - .macro bitop, name, instr + .macro bitop, name, llsc, lse ENTRY( \name ) and w3, w0, #63 // Get bit offset eor w0, w0, w3 // Clear low bits mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset lsl x3, x2, x3 // Create mask -1: ldxr x2, [x1] - \instr x2, x2, x3 - stxr w0, x2, [x1] - cbnz w0, 1b + +alt_lse "1: ldxr x2, [x1]", "\lse x3, [x1]" +alt_lse " \llsc x2, x2, x3", "nop" +alt_lse " stxr w0, x2, [x1]", "nop" +alt_lse " cbnz w0, 1b", "nop" + ret ENDPROC(\name ) .endm - .macro testop, name, instr + .macro testop, name, llsc, lse ENTRY( \name ) and w3, w0, #63 // Get bit offset eor w0, w0, w3 // Clear low bits mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset lsl x4, x2, x3 // Create mask -1: ldxr x2, [x1] - lsr x0, x2, x3 // Save old value of bit - \instr x2, x2, x4 // toggle bit - stlxr w5, x2, [x1] - cbnz w5, 1b - dmb ish + +alt_lse "1: ldxr x2, [x1]", "\lse x4, x2, [x1]" + lsr x0, x2, x3 +alt_lse " \llsc x2, x2, x4", "nop" +alt_lse " stlxr w5, x2, [x1]", "nop" +alt_lse " cbnz w5, 1b", "nop" +alt_lse " dmb ish", "nop" + and x0, x0, #1 -3: ret + ret ENDPROC(\name ) .endm /* * Atomic bit operations. */ - bitop change_bit, eor - bitop clear_bit, bic - bitop set_bit, orr + bitop change_bit, eor, steor + bitop clear_bit, bic, stclr + bitop set_bit, orr, stset - testop test_and_change_bit, eor - testop test_and_clear_bit, bic - testop test_and_set_bit, orr + testop test_and_change_bit, eor, ldeoral + testop test_and_clear_bit, bic, ldclral + testop test_and_set_bit, orr, ldsetal -- GitLab From c8366ba0fb65063b6b4f69c7af1ea74152435590 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Tue, 31 Mar 2015 14:11:24 +0100 Subject: [PATCH 1841/7006] arm64: xchg: patch in lse instructions when supported by the CPU On CPUs which support the LSE atomic instructions introduced in ARMv8.1, it makes sense to use them in preference to ll/sc sequences. This patch introduces runtime patching of our xchg primitives so that the LSE swp instruction (yes, you read right!) is used instead. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/cmpxchg.h | 38 +++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index d8c25b7b18fbf..d0cce80689026 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -22,6 +22,7 @@ #include #include +#include static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) { @@ -29,37 +30,65 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size switch (size) { case 1: - asm volatile("// __xchg1\n" + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: ldxrb %w0, %2\n" " stlxrb %w1, %w3, %2\n" " cbnz %w1, 1b\n" + " dmb ish", + /* LSE atomics */ + " nop\n" + " swpalb %w3, %w0, %2\n" + " nop\n" + " nop") : "=&r" (ret), "=&r" (tmp), "+Q" (*(u8 *)ptr) : "r" (x) : "memory"); break; case 2: - asm volatile("// __xchg2\n" + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: ldxrh %w0, %2\n" " stlxrh %w1, %w3, %2\n" " cbnz %w1, 1b\n" + " dmb ish", + /* LSE atomics */ + " nop\n" + " swpalh %w3, %w0, %2\n" + " nop\n" + " nop") : "=&r" (ret), "=&r" (tmp), "+Q" (*(u16 *)ptr) : "r" (x) : "memory"); break; case 4: - asm volatile("// __xchg4\n" + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: ldxr %w0, %2\n" " stlxr %w1, %w3, %2\n" " cbnz %w1, 1b\n" + " dmb ish", + /* LSE atomics */ + " nop\n" + " swpal %w3, %w0, %2\n" + " nop\n" + " nop") : "=&r" (ret), "=&r" (tmp), "+Q" (*(u32 *)ptr) : "r" (x) : "memory"); break; case 8: - asm volatile("// __xchg8\n" + asm volatile(ARM64_LSE_ATOMIC_INSN( + /* LL/SC */ "1: ldxr %0, %2\n" " stlxr %w1, %3, %2\n" " cbnz %w1, 1b\n" + " dmb ish", + /* LSE atomics */ + " nop\n" + " swpal %3, %0, %2\n" + " nop\n" + " nop") : "=&r" (ret), "=&r" (tmp), "+Q" (*(u64 *)ptr) : "r" (x) : "memory"); @@ -68,7 +97,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size BUILD_BUG(); } - smp_mb(); return ret; } -- GitLab From c342f78217e822d2178265b0b1de232eeb717149 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 23 Apr 2015 20:08:49 +0100 Subject: [PATCH 1842/7006] arm64: cmpxchg: patch in lse instructions when supported by the CPU On CPUs which support the LSE atomic instructions introduced in ARMv8.1, it makes sense to use them in preference to ll/sc sequences. This patch introduces runtime patching of our cmpxchg primitives so that the LSE cas instruction is used instead. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic.h | 3 +- arch/arm64/include/asm/atomic_ll_sc.h | 38 ++++++++++++ arch/arm64/include/asm/atomic_lse.h | 39 +++++++++++++ arch/arm64/include/asm/cmpxchg.h | 84 ++++++--------------------- 4 files changed, 98 insertions(+), 66 deletions(-) diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 836226d5e12cd..1fe8f209aeb44 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -24,7 +24,6 @@ #include #include -#include #include #define ATOMIC_INIT(i) { (i) } @@ -41,6 +40,8 @@ #undef __ARM64_IN_ATOMIC_IMPL +#include + /* * On ARM, ordinary assignment (str instruction) doesn't clear the local * strex/ldrex monitor on some implementations. The reason we can use it for diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index 4b981ba57e788..4864158d486ee 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -215,4 +215,42 @@ __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) } __LL_SC_EXPORT(atomic64_dec_if_positive); +#define __CMPXCHG_CASE(w, sz, name, mb, cl) \ +__LL_SC_INLINE unsigned long \ +__LL_SC_PREFIX(__cmpxchg_case_##name(volatile void *ptr, \ + unsigned long old, \ + unsigned long new)) \ +{ \ + unsigned long tmp, oldval; \ + \ + asm volatile( \ + " " #mb "\n" \ + "1: ldxr" #sz "\t%" #w "[oldval], %[v]\n" \ + " eor %" #w "[tmp], %" #w "[oldval], %" #w "[old]\n" \ + " cbnz %" #w "[tmp], 2f\n" \ + " stxr" #sz "\t%w[tmp], %" #w "[new], %[v]\n" \ + " cbnz %w[tmp], 1b\n" \ + " " #mb "\n" \ + " mov %" #w "[oldval], %" #w "[old]\n" \ + "2:" \ + : [tmp] "=&r" (tmp), [oldval] "=&r" (oldval), \ + [v] "+Q" (*(unsigned long *)ptr) \ + : [old] "Lr" (old), [new] "r" (new) \ + : cl); \ + \ + return oldval; \ +} \ +__LL_SC_EXPORT(__cmpxchg_case_##name); + +__CMPXCHG_CASE(w, b, 1, , ) +__CMPXCHG_CASE(w, h, 2, , ) +__CMPXCHG_CASE(w, , 4, , ) +__CMPXCHG_CASE( , , 8, , ) +__CMPXCHG_CASE(w, b, mb_1, dmb ish, "memory") +__CMPXCHG_CASE(w, h, mb_2, dmb ish, "memory") +__CMPXCHG_CASE(w, , mb_4, dmb ish, "memory") +__CMPXCHG_CASE( , , mb_8, dmb ish, "memory") + +#undef __CMPXCHG_CASE + #endif /* __ASM_ATOMIC_LL_SC_H */ diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 6e21b5e0c9d62..b39ae4c1451ab 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -349,4 +349,43 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) #undef __LL_SC_ATOMIC64 +#define __LL_SC_CMPXCHG(op) __LL_SC_CALL(__cmpxchg_case_##op) + +#define __CMPXCHG_CASE(w, sz, name, mb, cl...) \ +static inline unsigned long __cmpxchg_case_##name(volatile void *ptr, \ + unsigned long old, \ + unsigned long new) \ +{ \ + register unsigned long x0 asm ("x0") = (unsigned long)ptr; \ + register unsigned long x1 asm ("x1") = old; \ + register unsigned long x2 asm ("x2") = new; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + "nop\n" \ + __LL_SC_CMPXCHG(name) \ + "nop", \ + /* LSE atomics */ \ + " mov " #w "30, %" #w "[old]\n" \ + " cas" #mb #sz "\t" #w "30, %" #w "[new], %[v]\n" \ + " mov %" #w "[ret], " #w "30") \ + : [ret] "+r" (x0), [v] "+Q" (*(unsigned long *)ptr) \ + : [old] "r" (x1), [new] "r" (x2) \ + : "x30" , ##cl); \ + \ + return x0; \ +} + +__CMPXCHG_CASE(w, b, 1, ) +__CMPXCHG_CASE(w, h, 2, ) +__CMPXCHG_CASE(w, , 4, ) +__CMPXCHG_CASE(x, , 8, ) +__CMPXCHG_CASE(w, b, mb_1, al, "memory") +__CMPXCHG_CASE(w, h, mb_2, al, "memory") +__CMPXCHG_CASE(w, , mb_4, al, "memory") +__CMPXCHG_CASE(x, , mb_8, al, "memory") + +#undef __LL_SC_CMPXCHG +#undef __CMPXCHG_CASE + #endif /* __ASM_ATOMIC_LSE_H */ diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index d0cce80689026..60a558127cefb 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -111,74 +112,20 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size) { - unsigned long oldval = 0, res; - switch (size) { case 1: - do { - asm volatile("// __cmpxchg1\n" - " ldxrb %w1, %2\n" - " mov %w0, #0\n" - " cmp %w1, %w3\n" - " b.ne 1f\n" - " stxrb %w0, %w4, %2\n" - "1:\n" - : "=&r" (res), "=&r" (oldval), "+Q" (*(u8 *)ptr) - : "Ir" (old), "r" (new) - : "cc"); - } while (res); - break; - + return __cmpxchg_case_1(ptr, old, new); case 2: - do { - asm volatile("// __cmpxchg2\n" - " ldxrh %w1, %2\n" - " mov %w0, #0\n" - " cmp %w1, %w3\n" - " b.ne 1f\n" - " stxrh %w0, %w4, %2\n" - "1:\n" - : "=&r" (res), "=&r" (oldval), "+Q" (*(u16 *)ptr) - : "Ir" (old), "r" (new) - : "cc"); - } while (res); - break; - + return __cmpxchg_case_2(ptr, old, new); case 4: - do { - asm volatile("// __cmpxchg4\n" - " ldxr %w1, %2\n" - " mov %w0, #0\n" - " cmp %w1, %w3\n" - " b.ne 1f\n" - " stxr %w0, %w4, %2\n" - "1:\n" - : "=&r" (res), "=&r" (oldval), "+Q" (*(u32 *)ptr) - : "Ir" (old), "r" (new) - : "cc"); - } while (res); - break; - + return __cmpxchg_case_4(ptr, old, new); case 8: - do { - asm volatile("// __cmpxchg8\n" - " ldxr %1, %2\n" - " mov %w0, #0\n" - " cmp %1, %3\n" - " b.ne 1f\n" - " stxr %w0, %4, %2\n" - "1:\n" - : "=&r" (res), "=&r" (oldval), "+Q" (*(u64 *)ptr) - : "Ir" (old), "r" (new) - : "cc"); - } while (res); - break; - + return __cmpxchg_case_8(ptr, old, new); default: BUILD_BUG(); } - return oldval; + unreachable(); } #define system_has_cmpxchg_double() 1 @@ -229,13 +176,20 @@ static inline int __cmpxchg_double_mb(volatile void *ptr1, volatile void *ptr2, static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, unsigned long new, int size) { - unsigned long ret; - - smp_mb(); - ret = __cmpxchg(ptr, old, new, size); - smp_mb(); + switch (size) { + case 1: + return __cmpxchg_case_mb_1(ptr, old, new); + case 2: + return __cmpxchg_case_mb_2(ptr, old, new); + case 4: + return __cmpxchg_case_mb_4(ptr, old, new); + case 8: + return __cmpxchg_case_mb_8(ptr, old, new); + default: + BUILD_BUG(); + } - return ret; + unreachable(); } #define cmpxchg(ptr, o, n) \ -- GitLab From e9a4b795652f654a7870727e5333c1b709b8736c Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 14 May 2015 18:05:50 +0100 Subject: [PATCH 1843/7006] arm64: cmpxchg_dbl: patch in lse instructions when supported by the CPU On CPUs which support the LSE atomic instructions introduced in ARMv8.1, it makes sense to use them in preference to ll/sc sequences. This patch introduces runtime patching of our cmpxchg_double primitives so that the LSE casp instruction is used instead. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic_ll_sc.h | 34 ++++++++++++++ arch/arm64/include/asm/atomic_lse.h | 43 +++++++++++++++++ arch/arm64/include/asm/cmpxchg.h | 68 +++++++-------------------- 3 files changed, 94 insertions(+), 51 deletions(-) diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index 4864158d486ee..f89f1e4ba5772 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -253,4 +253,38 @@ __CMPXCHG_CASE( , , mb_8, dmb ish, "memory") #undef __CMPXCHG_CASE +#define __CMPXCHG_DBL(name, mb, cl) \ +__LL_SC_INLINE int \ +__LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ + unsigned long old2, \ + unsigned long new1, \ + unsigned long new2, \ + volatile void *ptr)) \ +{ \ + unsigned long tmp, ret; \ + \ + asm volatile("// __cmpxchg_double" #name "\n" \ + " " #mb "\n" \ + "1: ldxp %0, %1, %2\n" \ + " eor %0, %0, %3\n" \ + " eor %1, %1, %4\n" \ + " orr %1, %0, %1\n" \ + " cbnz %1, 2f\n" \ + " stxp %w0, %5, %6, %2\n" \ + " cbnz %w0, 1b\n" \ + " " #mb "\n" \ + "2:" \ + : "=&r" (tmp), "=&r" (ret), "+Q" (*(unsigned long *)ptr) \ + : "r" (old1), "r" (old2), "r" (new1), "r" (new2) \ + : cl); \ + \ + return ret; \ +} \ +__LL_SC_EXPORT(__cmpxchg_double##name); + +__CMPXCHG_DBL( , , ) +__CMPXCHG_DBL(_mb, dmb ish, "memory") + +#undef __CMPXCHG_DBL + #endif /* __ASM_ATOMIC_LL_SC_H */ diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index b39ae4c1451ab..f3cb1052ab247 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -388,4 +388,47 @@ __CMPXCHG_CASE(x, , mb_8, al, "memory") #undef __LL_SC_CMPXCHG #undef __CMPXCHG_CASE +#define __LL_SC_CMPXCHG_DBL(op) __LL_SC_CALL(__cmpxchg_double##op) + +#define __CMPXCHG_DBL(name, mb, cl...) \ +static inline int __cmpxchg_double##name(unsigned long old1, \ + unsigned long old2, \ + unsigned long new1, \ + unsigned long new2, \ + volatile void *ptr) \ +{ \ + unsigned long oldval1 = old1; \ + unsigned long oldval2 = old2; \ + register unsigned long x0 asm ("x0") = old1; \ + register unsigned long x1 asm ("x1") = old2; \ + register unsigned long x2 asm ("x2") = new1; \ + register unsigned long x3 asm ("x3") = new2; \ + register unsigned long x4 asm ("x4") = (unsigned long)ptr; \ + \ + asm volatile(ARM64_LSE_ATOMIC_INSN( \ + /* LL/SC */ \ + " nop\n" \ + " nop\n" \ + " nop\n" \ + __LL_SC_CMPXCHG_DBL(name), \ + /* LSE atomics */ \ + " casp" #mb "\t%[old1], %[old2], %[new1], %[new2], %[v]\n"\ + " eor %[old1], %[old1], %[oldval1]\n" \ + " eor %[old2], %[old2], %[oldval2]\n" \ + " orr %[old1], %[old1], %[old2]") \ + : [old1] "+r" (x0), [old2] "+r" (x1), \ + [v] "+Q" (*(unsigned long *)ptr) \ + : [new1] "r" (x2), [new2] "r" (x3), [ptr] "r" (x4), \ + [oldval1] "r" (oldval1), [oldval2] "r" (oldval2) \ + : "x30" , ##cl); \ + \ + return x0; \ +} + +__CMPXCHG_DBL( , ) +__CMPXCHG_DBL(_mb, al, "memory") + +#undef __LL_SC_CMPXCHG_DBL +#undef __CMPXCHG_DBL + #endif /* __ASM_ATOMIC_LSE_H */ diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index 60a558127cefb..f70212629d02f 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -128,51 +128,6 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, unreachable(); } -#define system_has_cmpxchg_double() 1 - -static inline int __cmpxchg_double(volatile void *ptr1, volatile void *ptr2, - unsigned long old1, unsigned long old2, - unsigned long new1, unsigned long new2, int size) -{ - unsigned long loop, lost; - - switch (size) { - case 8: - VM_BUG_ON((unsigned long *)ptr2 - (unsigned long *)ptr1 != 1); - do { - asm volatile("// __cmpxchg_double8\n" - " ldxp %0, %1, %2\n" - " eor %0, %0, %3\n" - " eor %1, %1, %4\n" - " orr %1, %0, %1\n" - " mov %w0, #0\n" - " cbnz %1, 1f\n" - " stxp %w0, %5, %6, %2\n" - "1:\n" - : "=&r"(loop), "=&r"(lost), "+Q" (*(u64 *)ptr1) - : "r" (old1), "r"(old2), "r"(new1), "r"(new2)); - } while (loop); - break; - default: - BUILD_BUG(); - } - - return !lost; -} - -static inline int __cmpxchg_double_mb(volatile void *ptr1, volatile void *ptr2, - unsigned long old1, unsigned long old2, - unsigned long new1, unsigned long new2, int size) -{ - int ret; - - smp_mb(); - ret = __cmpxchg_double(ptr1, ptr2, old1, old2, new1, new2, size); - smp_mb(); - - return ret; -} - static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, unsigned long new, int size) { @@ -210,21 +165,32 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old, __ret; \ }) +#define system_has_cmpxchg_double() 1 + +#define __cmpxchg_double_check(ptr1, ptr2) \ +({ \ + if (sizeof(*(ptr1)) != 8) \ + BUILD_BUG(); \ + VM_BUG_ON((unsigned long *)(ptr2) - (unsigned long *)(ptr1) != 1); \ +}) + #define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \ ({\ int __ret;\ - __ret = __cmpxchg_double_mb((ptr1), (ptr2), (unsigned long)(o1), \ - (unsigned long)(o2), (unsigned long)(n1), \ - (unsigned long)(n2), sizeof(*(ptr1)));\ + __cmpxchg_double_check(ptr1, ptr2); \ + __ret = !__cmpxchg_double_mb((unsigned long)(o1), (unsigned long)(o2), \ + (unsigned long)(n1), (unsigned long)(n2), \ + ptr1); \ __ret; \ }) #define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \ ({\ int __ret;\ - __ret = __cmpxchg_double((ptr1), (ptr2), (unsigned long)(o1), \ - (unsigned long)(o2), (unsigned long)(n1), \ - (unsigned long)(n2), sizeof(*(ptr1)));\ + __cmpxchg_double_check(ptr1, ptr2); \ + __ret = !__cmpxchg_double((unsigned long)(o1), (unsigned long)(o2), \ + (unsigned long)(n1), (unsigned long)(n2), \ + ptr1); \ __ret; \ }) -- GitLab From 0bc671d3f4bee9c31110d096ada0de52380e693d Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 29 May 2015 14:26:59 +0100 Subject: [PATCH 1844/7006] arm64: cmpxchg: avoid "cc" clobber in ll/sc routines We can perform the cmpxchg comparison using eor and cbnz which avoids the "cc" clobber for the ll/sc case and consequently for the LSE case where we may have to fall-back on the ll/sc code at runtime. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic_ll_sc.h | 14 ++++++-------- arch/arm64/include/asm/atomic_lse.h | 4 ++-- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index f89f1e4ba5772..c02684d1eab35 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -101,14 +101,13 @@ __LL_SC_PREFIX(atomic_cmpxchg(atomic_t *ptr, int old, int new)) asm volatile("// atomic_cmpxchg\n" "1: ldxr %w1, %2\n" -" cmp %w1, %w3\n" -" b.ne 2f\n" +" eor %w0, %w1, %w3\n" +" cbnz %w0, 2f\n" " stxr %w0, %w4, %2\n" " cbnz %w0, 1b\n" "2:" : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) - : "Ir" (old), "r" (new) - : "cc"); + : "Lr" (old), "r" (new)); smp_mb(); return oldval; @@ -179,14 +178,13 @@ __LL_SC_PREFIX(atomic64_cmpxchg(atomic64_t *ptr, long old, long new)) asm volatile("// atomic64_cmpxchg\n" "1: ldxr %1, %2\n" -" cmp %1, %3\n" -" b.ne 2f\n" +" eor %0, %1, %3\n" +" cbnz %w0, 2f\n" " stxr %w0, %4, %2\n" " cbnz %w0, 1b\n" "2:" : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) - : "Ir" (old), "r" (new) - : "cc"); + : "Lr" (old), "r" (new)); smp_mb(); return oldval; diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index f3cb1052ab247..a3d21e7cee4f2 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -166,7 +166,7 @@ static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) " mov %w[ret], w30") : [ret] "+r" (x0), [v] "+Q" (ptr->counter) : [old] "r" (w1), [new] "r" (w2) - : "x30", "cc", "memory"); + : "x30", "memory"); return x0; } @@ -313,7 +313,7 @@ static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) " mov %[ret], x30") : [ret] "+r" (x0), [v] "+Q" (ptr->counter) : [old] "r" (x1), [new] "r" (x2) - : "x30", "cc", "memory"); + : "x30", "memory"); return x0; } -- GitLab From 4e39715f4b5cb3b44576fedb2d38aca87de3cf48 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 29 May 2015 14:47:59 +0100 Subject: [PATCH 1845/7006] arm64: cmpxchg: avoid memory barrier on comparison failure cmpxchg doesn't require memory barrier semantics when the value comparison fails, so make the barrier conditional on success. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic_ll_sc.h | 48 ++++++++++++--------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index c02684d1eab35..5a9fb37272d4c 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -97,19 +97,18 @@ __LL_SC_PREFIX(atomic_cmpxchg(atomic_t *ptr, int old, int new)) unsigned long tmp; int oldval; - smp_mb(); - asm volatile("// atomic_cmpxchg\n" "1: ldxr %w1, %2\n" " eor %w0, %w1, %w3\n" " cbnz %w0, 2f\n" -" stxr %w0, %w4, %2\n" +" stlxr %w0, %w4, %2\n" " cbnz %w0, 1b\n" +" dmb ish\n" "2:" : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) - : "Lr" (old), "r" (new)); + : "Lr" (old), "r" (new) + : "memory"); - smp_mb(); return oldval; } __LL_SC_EXPORT(atomic_cmpxchg); @@ -174,19 +173,18 @@ __LL_SC_PREFIX(atomic64_cmpxchg(atomic64_t *ptr, long old, long new)) long oldval; unsigned long res; - smp_mb(); - asm volatile("// atomic64_cmpxchg\n" "1: ldxr %1, %2\n" " eor %0, %1, %3\n" " cbnz %w0, 2f\n" -" stxr %w0, %4, %2\n" +" stlxr %w0, %4, %2\n" " cbnz %w0, 1b\n" +" dmb ish\n" "2:" : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) - : "Lr" (old), "r" (new)); + : "Lr" (old), "r" (new) + : "memory"); - smp_mb(); return oldval; } __LL_SC_EXPORT(atomic64_cmpxchg); @@ -213,7 +211,7 @@ __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) } __LL_SC_EXPORT(atomic64_dec_if_positive); -#define __CMPXCHG_CASE(w, sz, name, mb, cl) \ +#define __CMPXCHG_CASE(w, sz, name, mb, rel, cl) \ __LL_SC_INLINE unsigned long \ __LL_SC_PREFIX(__cmpxchg_case_##name(volatile void *ptr, \ unsigned long old, \ @@ -222,11 +220,10 @@ __LL_SC_PREFIX(__cmpxchg_case_##name(volatile void *ptr, \ unsigned long tmp, oldval; \ \ asm volatile( \ - " " #mb "\n" \ "1: ldxr" #sz "\t%" #w "[oldval], %[v]\n" \ " eor %" #w "[tmp], %" #w "[oldval], %" #w "[old]\n" \ " cbnz %" #w "[tmp], 2f\n" \ - " stxr" #sz "\t%w[tmp], %" #w "[new], %[v]\n" \ + " st" #rel "xr" #sz "\t%w[tmp], %" #w "[new], %[v]\n" \ " cbnz %w[tmp], 1b\n" \ " " #mb "\n" \ " mov %" #w "[oldval], %" #w "[old]\n" \ @@ -240,18 +237,18 @@ __LL_SC_PREFIX(__cmpxchg_case_##name(volatile void *ptr, \ } \ __LL_SC_EXPORT(__cmpxchg_case_##name); -__CMPXCHG_CASE(w, b, 1, , ) -__CMPXCHG_CASE(w, h, 2, , ) -__CMPXCHG_CASE(w, , 4, , ) -__CMPXCHG_CASE( , , 8, , ) -__CMPXCHG_CASE(w, b, mb_1, dmb ish, "memory") -__CMPXCHG_CASE(w, h, mb_2, dmb ish, "memory") -__CMPXCHG_CASE(w, , mb_4, dmb ish, "memory") -__CMPXCHG_CASE( , , mb_8, dmb ish, "memory") +__CMPXCHG_CASE(w, b, 1, , , ) +__CMPXCHG_CASE(w, h, 2, , , ) +__CMPXCHG_CASE(w, , 4, , , ) +__CMPXCHG_CASE( , , 8, , , ) +__CMPXCHG_CASE(w, b, mb_1, dmb ish, l, "memory") +__CMPXCHG_CASE(w, h, mb_2, dmb ish, l, "memory") +__CMPXCHG_CASE(w, , mb_4, dmb ish, l, "memory") +__CMPXCHG_CASE( , , mb_8, dmb ish, l, "memory") #undef __CMPXCHG_CASE -#define __CMPXCHG_DBL(name, mb, cl) \ +#define __CMPXCHG_DBL(name, mb, rel, cl) \ __LL_SC_INLINE int \ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ unsigned long old2, \ @@ -262,13 +259,12 @@ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ unsigned long tmp, ret; \ \ asm volatile("// __cmpxchg_double" #name "\n" \ - " " #mb "\n" \ "1: ldxp %0, %1, %2\n" \ " eor %0, %0, %3\n" \ " eor %1, %1, %4\n" \ " orr %1, %0, %1\n" \ " cbnz %1, 2f\n" \ - " stxp %w0, %5, %6, %2\n" \ + " st" #rel "xp %w0, %5, %6, %2\n" \ " cbnz %w0, 1b\n" \ " " #mb "\n" \ "2:" \ @@ -280,8 +276,8 @@ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ } \ __LL_SC_EXPORT(__cmpxchg_double##name); -__CMPXCHG_DBL( , , ) -__CMPXCHG_DBL(_mb, dmb ish, "memory") +__CMPXCHG_DBL( , , , ) +__CMPXCHG_DBL(_mb, dmb ish, l, "memory") #undef __CMPXCHG_DBL -- GitLab From a82e62382fcbbf5c3348e802af73583e0cac39c0 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 4 Jun 2015 16:41:36 +0100 Subject: [PATCH 1846/7006] arm64: atomics: tidy up common atomic{,64}_* macros The common (i.e. identical for ll/sc and lse) atomic macros in atomic.h are needlessley different for atomic_t and atomic64_t. This patch tidies up the definitions to make them consistent across the two atomic types and factors out common code such as the add_unless implementation based on cmpxchg. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic.h | 99 +++++++++++++-------------------- 1 file changed, 40 insertions(+), 59 deletions(-) diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 1fe8f209aeb44..0b26da365f3be 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -26,8 +26,6 @@ #include #include -#define ATOMIC_INIT(i) { (i) } - #ifdef __KERNEL__ #define __ARM64_IN_ATOMIC_IMPL @@ -42,71 +40,54 @@ #include -/* - * On ARM, ordinary assignment (str instruction) doesn't clear the local - * strex/ldrex monitor on some implementations. The reason we can use it for - * atomic_set() is the clrex or dummy strex done on every exception return. - */ -#define atomic_read(v) ACCESS_ONCE((v)->counter) -#define atomic_set(v,i) (((v)->counter) = (i)) - -#define atomic_xchg(v, new) (xchg(&((v)->counter), new)) - -static inline int __atomic_add_unless(atomic_t *v, int a, int u) -{ - int c, old; - - c = atomic_read(v); - while (c != u && (old = atomic_cmpxchg((v), c, c + a)) != c) - c = old; - return c; -} - -#define atomic_inc(v) atomic_add(1, v) -#define atomic_dec(v) atomic_sub(1, v) +#define ___atomic_add_unless(v, a, u, sfx) \ +({ \ + typeof((v)->counter) c, old; \ + \ + c = atomic##sfx##_read(v); \ + while (c != (u) && \ + (old = atomic##sfx##_cmpxchg((v), c, c + (a))) != c) \ + c = old; \ + c; \ + }) -#define atomic_inc_and_test(v) (atomic_add_return(1, v) == 0) -#define atomic_dec_and_test(v) (atomic_sub_return(1, v) == 0) -#define atomic_inc_return(v) (atomic_add_return(1, v)) -#define atomic_dec_return(v) (atomic_sub_return(1, v)) -#define atomic_sub_and_test(i, v) (atomic_sub_return(i, v) == 0) - -#define atomic_add_negative(i,v) (atomic_add_return(i, v) < 0) +#define ATOMIC_INIT(i) { (i) } -#define atomic_andnot atomic_andnot +#define atomic_read(v) READ_ONCE((v)->counter) +#define atomic_set(v, i) (((v)->counter) = (i)) +#define atomic_xchg(v, new) xchg(&((v)->counter), (new)) + +#define atomic_inc(v) atomic_add(1, (v)) +#define atomic_dec(v) atomic_sub(1, (v)) +#define atomic_inc_return(v) atomic_add_return(1, (v)) +#define atomic_dec_return(v) atomic_sub_return(1, (v)) +#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) +#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) +#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) +#define atomic_add_negative(i, v) (atomic_add_return((i), (v)) < 0) +#define __atomic_add_unless(v, a, u) ___atomic_add_unless(v, a, u,) +#define atomic_andnot atomic_andnot /* * 64-bit atomic operations. */ -#define ATOMIC64_INIT(i) { (i) } - -#define atomic64_read(v) ACCESS_ONCE((v)->counter) -#define atomic64_set(v,i) (((v)->counter) = (i)) - -#define atomic64_xchg(v, new) (xchg(&((v)->counter), new)) - -static inline int atomic64_add_unless(atomic64_t *v, long a, long u) -{ - long c, old; - - c = atomic64_read(v); - while (c != u && (old = atomic64_cmpxchg((v), c, c + a)) != c) - c = old; - - return c != u; -} - -#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) -#define atomic64_inc(v) atomic64_add(1LL, (v)) -#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) +#define ATOMIC64_INIT ATOMIC_INIT +#define atomic64_read atomic_read +#define atomic64_set atomic_set +#define atomic64_xchg atomic_xchg + +#define atomic64_inc(v) atomic64_add(1, (v)) +#define atomic64_dec(v) atomic64_sub(1, (v)) +#define atomic64_inc_return(v) atomic64_add_return(1, (v)) +#define atomic64_dec_return(v) atomic64_sub_return(1, (v)) #define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) -#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) -#define atomic64_dec(v) atomic64_sub(1LL, (v)) -#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) -#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) +#define atomic64_dec_and_test(v) (atomic64_dec_return(v) == 0) +#define atomic64_sub_and_test(i, v) (atomic64_sub_return((i), (v)) == 0) +#define atomic64_add_negative(i, v) (atomic64_add_return((i), (v)) < 0) +#define atomic64_add_unless(v, a, u) (___atomic_add_unless(v, a, u, 64) != u) +#define atomic64_andnot atomic64_andnot -#define atomic64_andnot atomic64_andnot +#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1, 0) #endif #endif -- GitLab From 0ea366f5e1b6413a6095dce60ea49ae51e468b61 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 29 May 2015 13:31:10 +0100 Subject: [PATCH 1847/7006] arm64: atomics: prefetch the destination word for write prior to stxr The cost of changing a cacheline from shared to exclusive state can be significant, especially when this is triggered by an exclusive store, since it may result in having to retry the transaction. This patch makes use of prfm to prefetch cachelines for write prior to ldxr/stxr loops when using the ll/sc atomic routines. Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic_ll_sc.h | 9 +++++++++ arch/arm64/include/asm/cmpxchg.h | 8 ++++++++ arch/arm64/include/asm/futex.h | 2 ++ arch/arm64/lib/bitops.S | 2 ++ 4 files changed, 21 insertions(+) diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index 5a9fb37272d4c..50d6abd3c4399 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -45,6 +45,7 @@ __LL_SC_PREFIX(atomic_##op(int i, atomic_t *v)) \ int result; \ \ asm volatile("// atomic_" #op "\n" \ +" prfm pstl1strm, %2\n" \ "1: ldxr %w0, %2\n" \ " " #asm_op " %w0, %w0, %w3\n" \ " stxr %w1, %w0, %2\n" \ @@ -62,6 +63,7 @@ __LL_SC_PREFIX(atomic_##op##_return(int i, atomic_t *v)) \ int result; \ \ asm volatile("// atomic_" #op "_return\n" \ +" prfm pstl1strm, %2\n" \ "1: ldxr %w0, %2\n" \ " " #asm_op " %w0, %w0, %w3\n" \ " stlxr %w1, %w0, %2\n" \ @@ -98,6 +100,7 @@ __LL_SC_PREFIX(atomic_cmpxchg(atomic_t *ptr, int old, int new)) int oldval; asm volatile("// atomic_cmpxchg\n" +" prfm pstl1strm, %2\n" "1: ldxr %w1, %2\n" " eor %w0, %w1, %w3\n" " cbnz %w0, 2f\n" @@ -121,6 +124,7 @@ __LL_SC_PREFIX(atomic64_##op(long i, atomic64_t *v)) \ unsigned long tmp; \ \ asm volatile("// atomic64_" #op "\n" \ +" prfm pstl1strm, %2\n" \ "1: ldxr %0, %2\n" \ " " #asm_op " %0, %0, %3\n" \ " stxr %w1, %0, %2\n" \ @@ -138,6 +142,7 @@ __LL_SC_PREFIX(atomic64_##op##_return(long i, atomic64_t *v)) \ unsigned long tmp; \ \ asm volatile("// atomic64_" #op "_return\n" \ +" prfm pstl1strm, %2\n" \ "1: ldxr %0, %2\n" \ " " #asm_op " %0, %0, %3\n" \ " stlxr %w1, %0, %2\n" \ @@ -174,6 +179,7 @@ __LL_SC_PREFIX(atomic64_cmpxchg(atomic64_t *ptr, long old, long new)) unsigned long res; asm volatile("// atomic64_cmpxchg\n" +" prfm pstl1strm, %2\n" "1: ldxr %1, %2\n" " eor %0, %1, %3\n" " cbnz %w0, 2f\n" @@ -196,6 +202,7 @@ __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) unsigned long tmp; asm volatile("// atomic64_dec_if_positive\n" +" prfm pstl1strm, %2\n" "1: ldxr %0, %2\n" " subs %0, %0, #1\n" " b.mi 2f\n" @@ -220,6 +227,7 @@ __LL_SC_PREFIX(__cmpxchg_case_##name(volatile void *ptr, \ unsigned long tmp, oldval; \ \ asm volatile( \ + " prfm pstl1strm, %2\n" \ "1: ldxr" #sz "\t%" #w "[oldval], %[v]\n" \ " eor %" #w "[tmp], %" #w "[oldval], %" #w "[old]\n" \ " cbnz %" #w "[tmp], 2f\n" \ @@ -259,6 +267,7 @@ __LL_SC_PREFIX(__cmpxchg_double##name(unsigned long old1, \ unsigned long tmp, ret; \ \ asm volatile("// __cmpxchg_double" #name "\n" \ + " prfm pstl1strm, %2\n" \ "1: ldxp %0, %1, %2\n" \ " eor %0, %0, %3\n" \ " eor %1, %1, %4\n" \ diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h index f70212629d02f..7bfda0944c9bb 100644 --- a/arch/arm64/include/asm/cmpxchg.h +++ b/arch/arm64/include/asm/cmpxchg.h @@ -33,12 +33,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size case 1: asm volatile(ARM64_LSE_ATOMIC_INSN( /* LL/SC */ + " prfm pstl1strm, %2\n" "1: ldxrb %w0, %2\n" " stlxrb %w1, %w3, %2\n" " cbnz %w1, 1b\n" " dmb ish", /* LSE atomics */ " nop\n" + " nop\n" " swpalb %w3, %w0, %2\n" " nop\n" " nop") @@ -49,12 +51,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size case 2: asm volatile(ARM64_LSE_ATOMIC_INSN( /* LL/SC */ + " prfm pstl1strm, %2\n" "1: ldxrh %w0, %2\n" " stlxrh %w1, %w3, %2\n" " cbnz %w1, 1b\n" " dmb ish", /* LSE atomics */ " nop\n" + " nop\n" " swpalh %w3, %w0, %2\n" " nop\n" " nop") @@ -65,12 +69,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size case 4: asm volatile(ARM64_LSE_ATOMIC_INSN( /* LL/SC */ + " prfm pstl1strm, %2\n" "1: ldxr %w0, %2\n" " stlxr %w1, %w3, %2\n" " cbnz %w1, 1b\n" " dmb ish", /* LSE atomics */ " nop\n" + " nop\n" " swpal %w3, %w0, %2\n" " nop\n" " nop") @@ -81,12 +87,14 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size case 8: asm volatile(ARM64_LSE_ATOMIC_INSN( /* LL/SC */ + " prfm pstl1strm, %2\n" "1: ldxr %0, %2\n" " stlxr %w1, %3, %2\n" " cbnz %w1, 1b\n" " dmb ish", /* LSE atomics */ " nop\n" + " nop\n" " swpal %3, %0, %2\n" " nop\n" " nop") diff --git a/arch/arm64/include/asm/futex.h b/arch/arm64/include/asm/futex.h index 775e85b9d1f25..007a69fc4f408 100644 --- a/arch/arm64/include/asm/futex.h +++ b/arch/arm64/include/asm/futex.h @@ -30,6 +30,7 @@ asm volatile( \ ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_HAS_PAN, \ CONFIG_ARM64_PAN) \ +" prfm pstl1strm, %2\n" \ "1: ldxr %w1, %2\n" \ insn "\n" \ "2: stlxr %w3, %w0, %2\n" \ @@ -120,6 +121,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; asm volatile("// futex_atomic_cmpxchg_inatomic\n" +" prfm pstl1strm, %2\n" "1: ldxr %w1, %2\n" " sub %w3, %w1, %w4\n" " cbnz %w3, 3f\n" diff --git a/arch/arm64/lib/bitops.S b/arch/arm64/lib/bitops.S index bc18457c2bba6..43ac736baa5bf 100644 --- a/arch/arm64/lib/bitops.S +++ b/arch/arm64/lib/bitops.S @@ -31,6 +31,7 @@ ENTRY( \name ) eor w0, w0, w3 // Clear low bits mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset +alt_lse " prfm pstl1strm, [x1]", "nop" lsl x3, x2, x3 // Create mask alt_lse "1: ldxr x2, [x1]", "\lse x3, [x1]" @@ -48,6 +49,7 @@ ENTRY( \name ) eor w0, w0, w3 // Clear low bits mov x2, #1 add x1, x1, x0, lsr #3 // Get word offset +alt_lse " prfm pstl1strm, [x1]", "nop" lsl x4, x2, x3 // Create mask alt_lse "1: ldxr x2, [x1]", "\lse x4, x2, [x1]" -- GitLab From 6059a7b6e818023436a9058170a4fea1c670dc98 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Thu, 4 Jun 2015 17:46:37 +0100 Subject: [PATCH 1848/7006] arm64: atomics: implement atomic{,64}_cmpxchg using cmpxchg We don't need duplicate cmpxchg implementations, so use cmpxchg to implement atomic{,64}_cmpxchg, like we do for xchg already. Reviewed-by: Steve Capper Reviewed-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic.h | 2 ++ arch/arm64/include/asm/atomic_ll_sc.h | 46 --------------------------- arch/arm64/include/asm/atomic_lse.h | 43 ------------------------- 3 files changed, 2 insertions(+), 89 deletions(-) diff --git a/arch/arm64/include/asm/atomic.h b/arch/arm64/include/asm/atomic.h index 0b26da365f3be..35a67783cfa08 100644 --- a/arch/arm64/include/asm/atomic.h +++ b/arch/arm64/include/asm/atomic.h @@ -56,6 +56,7 @@ #define atomic_read(v) READ_ONCE((v)->counter) #define atomic_set(v, i) (((v)->counter) = (i)) #define atomic_xchg(v, new) xchg(&((v)->counter), (new)) +#define atomic_cmpxchg(v, old, new) cmpxchg(&((v)->counter), (old), (new)) #define atomic_inc(v) atomic_add(1, (v)) #define atomic_dec(v) atomic_sub(1, (v)) @@ -75,6 +76,7 @@ #define atomic64_read atomic_read #define atomic64_set atomic_set #define atomic64_xchg atomic_xchg +#define atomic64_cmpxchg atomic_cmpxchg #define atomic64_inc(v) atomic64_add(1, (v)) #define atomic64_dec(v) atomic64_sub(1, (v)) diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index 50d6abd3c4399..5e2d1db3a1db5 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -93,29 +93,6 @@ ATOMIC_OP(xor, eor) #undef ATOMIC_OP_RETURN #undef ATOMIC_OP -__LL_SC_INLINE int -__LL_SC_PREFIX(atomic_cmpxchg(atomic_t *ptr, int old, int new)) -{ - unsigned long tmp; - int oldval; - - asm volatile("// atomic_cmpxchg\n" -" prfm pstl1strm, %2\n" -"1: ldxr %w1, %2\n" -" eor %w0, %w1, %w3\n" -" cbnz %w0, 2f\n" -" stlxr %w0, %w4, %2\n" -" cbnz %w0, 1b\n" -" dmb ish\n" -"2:" - : "=&r" (tmp), "=&r" (oldval), "+Q" (ptr->counter) - : "Lr" (old), "r" (new) - : "memory"); - - return oldval; -} -__LL_SC_EXPORT(atomic_cmpxchg); - #define ATOMIC64_OP(op, asm_op) \ __LL_SC_INLINE void \ __LL_SC_PREFIX(atomic64_##op(long i, atomic64_t *v)) \ @@ -172,29 +149,6 @@ ATOMIC64_OP(xor, eor) #undef ATOMIC64_OP_RETURN #undef ATOMIC64_OP -__LL_SC_INLINE long -__LL_SC_PREFIX(atomic64_cmpxchg(atomic64_t *ptr, long old, long new)) -{ - long oldval; - unsigned long res; - - asm volatile("// atomic64_cmpxchg\n" -" prfm pstl1strm, %2\n" -"1: ldxr %1, %2\n" -" eor %0, %1, %3\n" -" cbnz %w0, 2f\n" -" stlxr %w0, %4, %2\n" -" cbnz %w0, 1b\n" -" dmb ish\n" -"2:" - : "=&r" (res), "=&r" (oldval), "+Q" (ptr->counter) - : "Lr" (old), "r" (new) - : "memory"); - - return oldval; -} -__LL_SC_EXPORT(atomic64_cmpxchg); - __LL_SC_INLINE long __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) { diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index a3d21e7cee4f2..30e5cbcfc707c 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -149,28 +149,6 @@ static inline int atomic_sub_return(int i, atomic_t *v) return w0; } -static inline int atomic_cmpxchg(atomic_t *ptr, int old, int new) -{ - register unsigned long x0 asm ("x0") = (unsigned long)ptr; - register int w1 asm ("w1") = old; - register int w2 asm ("w2") = new; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - " nop\n" - __LL_SC_ATOMIC(cmpxchg) - " nop", - /* LSE atomics */ - " mov w30, %w[old]\n" - " casal w30, %w[new], %[v]\n" - " mov %w[ret], w30") - : [ret] "+r" (x0), [v] "+Q" (ptr->counter) - : [old] "r" (w1), [new] "r" (w2) - : "x30", "memory"); - - return x0; -} - #undef __LL_SC_ATOMIC #define __LL_SC_ATOMIC64(op) __LL_SC_CALL(atomic64_##op) @@ -296,27 +274,6 @@ static inline long atomic64_sub_return(long i, atomic64_t *v) return x0; } -static inline long atomic64_cmpxchg(atomic64_t *ptr, long old, long new) -{ - register unsigned long x0 asm ("x0") = (unsigned long)ptr; - register long x1 asm ("x1") = old; - register long x2 asm ("x2") = new; - - asm volatile(ARM64_LSE_ATOMIC_INSN( - /* LL/SC */ - " nop\n" - __LL_SC_ATOMIC64(cmpxchg) - " nop", - /* LSE atomics */ - " mov x30, %[old]\n" - " casal x30, %[new], %[v]\n" - " mov %[ret], x30") - : [ret] "+r" (x0), [v] "+Q" (ptr->counter) - : [old] "r" (x1), [new] "r" (x2) - : "x30", "memory"); - - return x0; -} static inline long atomic64_dec_if_positive(atomic64_t *v) { -- GitLab From db26217e6f54647b137a0fe1f2ab346de67d6f3e Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 29 May 2015 14:44:06 +0100 Subject: [PATCH 1849/7006] arm64: atomic64_dec_if_positive: fix incorrect branch condition If we attempt to atomic64_dec_if_positive on INT_MIN, we will underflow and incorrectly decide that the original parameter was positive. This patches fixes the broken condition code so that we handle this corner case correctly. Reviewed-by: Steve Capper Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/include/asm/atomic_ll_sc.h | 2 +- arch/arm64/include/asm/atomic_lse.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/include/asm/atomic_ll_sc.h b/arch/arm64/include/asm/atomic_ll_sc.h index 5e2d1db3a1db5..6671978e60fe5 100644 --- a/arch/arm64/include/asm/atomic_ll_sc.h +++ b/arch/arm64/include/asm/atomic_ll_sc.h @@ -159,7 +159,7 @@ __LL_SC_PREFIX(atomic64_dec_if_positive(atomic64_t *v)) " prfm pstl1strm, %2\n" "1: ldxr %0, %2\n" " subs %0, %0, #1\n" -" b.mi 2f\n" +" b.lt 2f\n" " stlxr %w1, %0, %2\n" " cbnz %w1, 1b\n" " dmb ish\n" diff --git a/arch/arm64/include/asm/atomic_lse.h b/arch/arm64/include/asm/atomic_lse.h index 30e5cbcfc707c..f873bf61e17b1 100644 --- a/arch/arm64/include/asm/atomic_lse.h +++ b/arch/arm64/include/asm/atomic_lse.h @@ -291,7 +291,7 @@ static inline long atomic64_dec_if_positive(atomic64_t *v) /* LSE atomics */ "1: ldr x30, %[v]\n" " subs %[ret], x30, #1\n" - " b.mi 2f\n" + " b.lt 2f\n" " casal x30, %[ret], %[v]\n" " sub x30, x30, #1\n" " sub x30, x30, %[ret]\n" -- GitLab From 95eff6b27c40c7205f72f354712c3687d808e7f6 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Fri, 29 May 2015 14:57:47 +0100 Subject: [PATCH 1850/7006] arm64: kconfig: select HAVE_CMPXCHG_LOCAL We implement an optimised cmpxchg_local macro, so let the kernel know. Reviewed-by: Steve Capper Acked-by: Catalin Marinas Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 8dabffa82ef81..e82b98dfc028b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -53,6 +53,7 @@ config ARM64 select HAVE_C_RECORDMCOUNT select HAVE_CC_STACKPROTECTOR select HAVE_CMPXCHG_DOUBLE + select HAVE_CMPXCHG_LOCAL select HAVE_DEBUG_BUGVERBOSE select HAVE_DEBUG_KMEMLEAK select HAVE_DMA_API_DEBUG -- GitLab From c739dc83a0b6db01abfbcc5246a30c7a575e4272 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jul 2015 14:11:55 +0100 Subject: [PATCH 1851/7006] arm64: lse: rename ARM64_CPU_FEAT_LSE_ATOMICS for consistency Other CPU features follow an 'ARM64_HAS_*' naming scheme, so do the same for the LSE atomics. Signed-off-by: Will Deacon --- arch/arm64/include/asm/cpufeature.h | 2 +- arch/arm64/include/asm/lse.h | 4 ++-- arch/arm64/kernel/setup.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index d9262d4b4dcd8..171570702bb80 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -26,7 +26,7 @@ #define ARM64_WORKAROUND_845719 2 #define ARM64_HAS_SYSREG_GIC_CPUIF 3 #define ARM64_HAS_PAN 4 -#define ARM64_CPU_FEAT_LSE_ATOMICS 5 +#define ARM64_HAS_LSE_ATOMICS 5 #define ARM64_NCAPS 6 diff --git a/arch/arm64/include/asm/lse.h b/arch/arm64/include/asm/lse.h index fb3ac56a2cc04..3de42d68611df 100644 --- a/arch/arm64/include/asm/lse.h +++ b/arch/arm64/include/asm/lse.h @@ -12,7 +12,7 @@ .arch_extension lse .macro alt_lse, llsc, lse - alternative_insn "\llsc", "\lse", ARM64_CPU_FEAT_LSE_ATOMICS + alternative_insn "\llsc", "\lse", ARM64_HAS_LSE_ATOMICS .endm #else /* __ASSEMBLER__ */ @@ -29,7 +29,7 @@ __asm__(".arch_extension lse"); /* In-line patching at runtime */ #define ARM64_LSE_ATOMIC_INSN(llsc, lse) \ - ALTERNATIVE(llsc, lse, ARM64_CPU_FEAT_LSE_ATOMICS) + ALTERNATIVE(llsc, lse, ARM64_HAS_LSE_ATOMICS) #endif /* __ASSEMBLER__ */ #else /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 97785c01acbfc..82ae8429baf21 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -284,7 +284,7 @@ static void __init setup_processor(void) default: case 2: elf_hwcap |= HWCAP_ATOMICS; - cpus_set_cap(ARM64_CPU_FEAT_LSE_ATOMICS); + cpus_set_cap(ARM64_HAS_LSE_ATOMICS); if (IS_ENABLED(CONFIG_AS_LSE) && IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS)) pr_info("LSE atomics supported\n"); -- GitLab From 0e4a07092fc833dc3d972a3394398aef68217c13 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jul 2015 15:54:13 +0100 Subject: [PATCH 1852/7006] arm64: kconfig: group the v8.1 features together ARMv8 CPUs do not support any of the v8.1 features, so group them together in Kconfig to make it clear that they're part of 8.1 and not relevant to older cores. Signed-off-by: Will Deacon --- arch/arm64/Kconfig | 90 ++++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 43 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index e82b98dfc028b..371a987b3c113 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -481,23 +481,6 @@ config ARM64_VA_BITS default 42 if ARM64_VA_BITS_42 default 48 if ARM64_VA_BITS_48 -config ARM64_HW_AFDBM - bool "Support for hardware updates of the Access and Dirty page flags" - default y - help - The ARMv8.1 architecture extensions introduce support for - hardware updates of the access and dirty information in page - table entries. When enabled in TCR_EL1 (HA and HD bits) on - capable processors, accesses to pages with PTE_AF cleared will - set this bit instead of raising an access flag fault. - Similarly, writes to read-only pages with the DBM bit set will - clear the read-only bit (AP[2]) instead of raising a - permission fault. - - Kernels built with this configuration option enabled continue - to work on pre-ARMv8.1 hardware and the performance impact is - minimal. If unsure, say Y. - config CPU_BIG_ENDIAN bool "Build big-endian kernel" help @@ -605,32 +588,6 @@ config FORCE_MAX_ZONEORDER default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE) default "11" -config ARM64_PAN - bool "Enable support for Privileged Access Never (PAN)" - default y - help - Privileged Access Never (PAN; part of the ARMv8.1 Extensions) - prevents the kernel or hypervisor from accessing user-space (EL0) - memory directly. - - Choosing this option will cause any unprotected (not using - copy_to_user et al) memory access to fail with a permission fault. - - The feature is detected at runtime, and will remain as a 'nop' - instruction if the cpu does not implement the feature. - -config ARM64_LSE_ATOMICS - bool "ARMv8.1 atomic instructions" - help - As part of the Large System Extensions, ARMv8.1 introduces new - atomic instructions that are designed specifically to scale in - very large systems. - - Say Y here to make use of these instructions for the in-kernel - atomic routines. This incurs a small overhead on CPUs that do - not support these instructions and requires the kernel to be - built with binutils >= 2.25. - menuconfig ARMV8_DEPRECATED bool "Emulate deprecated/obsolete ARMv8 instructions" depends on COMPAT @@ -698,6 +655,53 @@ config SETEND_EMULATION If unsure, say Y endif +menu "ARMv8.1 architectural features" + +config ARM64_HW_AFDBM + bool "Support for hardware updates of the Access and Dirty page flags" + default y + help + The ARMv8.1 architecture extensions introduce support for + hardware updates of the access and dirty information in page + table entries. When enabled in TCR_EL1 (HA and HD bits) on + capable processors, accesses to pages with PTE_AF cleared will + set this bit instead of raising an access flag fault. + Similarly, writes to read-only pages with the DBM bit set will + clear the read-only bit (AP[2]) instead of raising a + permission fault. + + Kernels built with this configuration option enabled continue + to work on pre-ARMv8.1 hardware and the performance impact is + minimal. If unsure, say Y. + +config ARM64_PAN + bool "Enable support for Privileged Access Never (PAN)" + default y + help + Privileged Access Never (PAN; part of the ARMv8.1 Extensions) + prevents the kernel or hypervisor from accessing user-space (EL0) + memory directly. + + Choosing this option will cause any unprotected (not using + copy_to_user et al) memory access to fail with a permission fault. + + The feature is detected at runtime, and will remain as a 'nop' + instruction if the cpu does not implement the feature. + +config ARM64_LSE_ATOMICS + bool "Atomic instructions" + help + As part of the Large System Extensions, ARMv8.1 introduces new + atomic instructions that are designed specifically to scale in + very large systems. + + Say Y here to make use of these instructions for the in-kernel + atomic routines. This incurs a small overhead on CPUs that do + not support these instructions and requires the kernel to be + built with binutils >= 2.25. + +endmenu + endmenu menu "Boot options" -- GitLab From 2e94da13790336eb3fd00fb5e97610dd9aebe213 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jul 2015 16:23:58 +0100 Subject: [PATCH 1853/7006] arm64: lse: use generic cpufeature detection for LSE atomics Rework the cpufeature detection to support ISAR0 and use that for detecting the presence of LSE atomics. Signed-off-by: Will Deacon --- arch/arm64/kernel/cpufeature.c | 37 +++++++++++++++++++--------------- arch/arm64/kernel/setup.c | 4 ---- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 978fa169d3c31..3c9aed32f70b2 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -31,23 +31,19 @@ feature_matches(u64 reg, const struct arm64_cpu_capabilities *entry) return val >= entry->min_field_value; } -static bool -has_id_aa64pfr0_feature(const struct arm64_cpu_capabilities *entry) -{ - u64 val; - - val = read_cpuid(id_aa64pfr0_el1); - return feature_matches(val, entry); +#define __ID_FEAT_CHK(reg) \ +static bool __maybe_unused \ +has_##reg##_feature(const struct arm64_cpu_capabilities *entry) \ +{ \ + u64 val; \ + \ + val = read_cpuid(reg##_el1); \ + return feature_matches(val, entry); \ } -static bool __maybe_unused -has_id_aa64mmfr1_feature(const struct arm64_cpu_capabilities *entry) -{ - u64 val; - - val = read_cpuid(id_aa64mmfr1_el1); - return feature_matches(val, entry); -} +__ID_FEAT_CHK(id_aa64pfr0); +__ID_FEAT_CHK(id_aa64mmfr1); +__ID_FEAT_CHK(id_aa64isar0); static const struct arm64_cpu_capabilities arm64_features[] = { { @@ -67,6 +63,15 @@ static const struct arm64_cpu_capabilities arm64_features[] = { .enable = cpu_enable_pan, }, #endif /* CONFIG_ARM64_PAN */ +#if defined(CONFIG_AS_LSE) && defined(CONFIG_ARM64_LSE_ATOMICS) + { + .desc = "LSE atomic instructions", + .capability = ARM64_HAS_LSE_ATOMICS, + .matches = has_id_aa64isar0_feature, + .field_pos = 20, + .min_field_value = 2, + }, +#endif /* CONFIG_AS_LSE && CONFIG_ARM64_LSE_ATOMICS */ {}, }; @@ -93,5 +98,5 @@ void check_cpu_capabilities(const struct arm64_cpu_capabilities *caps, void check_local_cpu_features(void) { - check_cpu_capabilities(arm64_features, "detected feature"); + check_cpu_capabilities(arm64_features, "detected feature:"); } diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 82ae8429baf21..b2f9895ecf7b5 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -284,10 +284,6 @@ static void __init setup_processor(void) default: case 2: elf_hwcap |= HWCAP_ATOMICS; - cpus_set_cap(ARM64_HAS_LSE_ATOMICS); - if (IS_ENABLED(CONFIG_AS_LSE) && - IS_ENABLED(CONFIG_ARM64_LSE_ATOMICS)) - pr_info("LSE atomics supported\n"); case 1: /* RESERVED */ case 0: -- GitLab From 309585b0b931b291d0525b2830161ee76a2f23ff Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jul 2015 16:55:32 +0100 Subject: [PATCH 1854/7006] arm64: elf: use cpuid_feature_extract_field for hwcap detection cpuid_feature_extract_field takes care of the fiddly ID register field sign-extension, so use that instead of rolling our own version. Signed-off-by: Will Deacon --- arch/arm64/kernel/setup.c | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index b2f9895ecf7b5..be65ecc89e82a 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -223,7 +223,8 @@ void __init up_late_init(void) static void __init setup_processor(void) { - u64 features, block; + u64 features; + s64 block; u32 cwg; int cls; @@ -253,8 +254,8 @@ static void __init setup_processor(void) * for non-negative values. Negative values are reserved. */ features = read_cpuid(ID_AA64ISAR0_EL1); - block = (features >> 4) & 0xf; - if (!(block & 0x8)) { + block = cpuid_feature_extract_field(features, 4); + if (block > 0) { switch (block) { default: case 2: @@ -266,20 +267,17 @@ static void __init setup_processor(void) } } - block = (features >> 8) & 0xf; - if (block && !(block & 0x8)) + if (cpuid_feature_extract_field(features, 8) > 0) elf_hwcap |= HWCAP_SHA1; - block = (features >> 12) & 0xf; - if (block && !(block & 0x8)) + if (cpuid_feature_extract_field(features, 12) > 0) elf_hwcap |= HWCAP_SHA2; - block = (features >> 16) & 0xf; - if (block && !(block & 0x8)) + if (cpuid_feature_extract_field(features, 16) > 0) elf_hwcap |= HWCAP_CRC32; - block = (features >> 20) & 0xf; - if (!(block & 0x8)) { + block = cpuid_feature_extract_field(features, 20); + if (block > 0) { switch (block) { default: case 2: @@ -294,11 +292,11 @@ static void __init setup_processor(void) #ifdef CONFIG_COMPAT /* * ID_ISAR5_EL1 carries similar information as above, but pertaining to - * the Aarch32 32-bit execution state. + * the AArch32 32-bit execution state. */ features = read_cpuid(ID_ISAR5_EL1); - block = (features >> 4) & 0xf; - if (!(block & 0x8)) { + block = cpuid_feature_extract_field(features, 4); + if (block > 0) { switch (block) { default: case 2: @@ -310,16 +308,13 @@ static void __init setup_processor(void) } } - block = (features >> 8) & 0xf; - if (block && !(block & 0x8)) + if (cpuid_feature_extract_field(features, 8) > 0) compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA1; - block = (features >> 12) & 0xf; - if (block && !(block & 0x8)) + if (cpuid_feature_extract_field(features, 12) > 0) compat_elf_hwcap2 |= COMPAT_HWCAP2_SHA2; - block = (features >> 16) & 0xf; - if (block && !(block & 0x8)) + if (cpuid_feature_extract_field(features, 16) > 0) compat_elf_hwcap2 |= COMPAT_HWCAP2_CRC32; #endif } -- GitLab From 662ba3dbceca3ca284885a464ecb8c936f417003 Mon Sep 17 00:00:00 2001 From: Wang Long Date: Mon, 27 Jul 2015 03:32:53 +0100 Subject: [PATCH 1855/7006] arm64: mm: add __init section marker to free_initrd_mem It is not needed after booting, this patch moves the free_initrd_mem() function to the __init section. This patch also make keep_initrd __initdata, to reduce kernel size. Signed-off-by: Wang Long Signed-off-by: Will Deacon --- arch/arm64/mm/init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index ad87ce826cce4..f5c0680d17d9e 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -358,9 +358,9 @@ void free_initmem(void) #ifdef CONFIG_BLK_DEV_INITRD -static int keep_initrd; +static int keep_initrd __initdata; -void free_initrd_mem(unsigned long start, unsigned long end) +void __init free_initrd_mem(unsigned long start, unsigned long end) { if (!keep_initrd) free_reserved_area((void *)start, (void *)end, 0, "initrd"); -- GitLab From 6f883d10a18b971a3646303d12ef75138dfd31f9 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 27 Jul 2015 18:36:54 +0100 Subject: [PATCH 1856/7006] arm64: debug: rename enum debug_el to avoid symbol collision lib/list_sort.c defines a 'struct debug_el', where "el" is assumedly a a contraction of "element". This conflicts with 'enum debug_el' in our asm/debug-monitors.h header file, where "el" stands for Exception Level. The result is build failure when targetting allmodconfig, so rename our enum to 'dbg_active_el' to be slightly more explicit about what it is. Signed-off-by: Will Deacon --- arch/arm64/include/asm/debug-monitors.h | 6 +++--- arch/arm64/kernel/debug-monitors.c | 4 ++-- arch/arm64/kernel/hw_breakpoint.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/arch/arm64/include/asm/debug-monitors.h b/arch/arm64/include/asm/debug-monitors.h index e3f2bad788c9b..279c85b5ec091 100644 --- a/arch/arm64/include/asm/debug-monitors.h +++ b/arch/arm64/include/asm/debug-monitors.h @@ -115,13 +115,13 @@ void unregister_break_hook(struct break_hook *hook); u8 debug_monitors_arch(void); -enum debug_el { +enum dbg_active_el { DBG_ACTIVE_EL0 = 0, DBG_ACTIVE_EL1, }; -void enable_debug_monitors(enum debug_el el); -void disable_debug_monitors(enum debug_el el); +void enable_debug_monitors(enum dbg_active_el el); +void disable_debug_monitors(enum dbg_active_el el); void user_rewind_single_step(struct task_struct *task); void user_fastforward_single_step(struct task_struct *task); diff --git a/arch/arm64/kernel/debug-monitors.c b/arch/arm64/kernel/debug-monitors.c index b056369fd47da..9b3b62ac9c244 100644 --- a/arch/arm64/kernel/debug-monitors.c +++ b/arch/arm64/kernel/debug-monitors.c @@ -82,7 +82,7 @@ early_param("nodebugmon", early_debug_disable); static DEFINE_PER_CPU(int, mde_ref_count); static DEFINE_PER_CPU(int, kde_ref_count); -void enable_debug_monitors(enum debug_el el) +void enable_debug_monitors(enum dbg_active_el el) { u32 mdscr, enable = 0; @@ -102,7 +102,7 @@ void enable_debug_monitors(enum debug_el el) } } -void disable_debug_monitors(enum debug_el el) +void disable_debug_monitors(enum dbg_active_el el) { u32 mdscr, disable = 0; diff --git a/arch/arm64/kernel/hw_breakpoint.c b/arch/arm64/kernel/hw_breakpoint.c index 7a1a5da6c8c1b..003bc3d50636f 100644 --- a/arch/arm64/kernel/hw_breakpoint.c +++ b/arch/arm64/kernel/hw_breakpoint.c @@ -156,7 +156,7 @@ static void write_wb_reg(int reg, int n, u64 val) * Convert a breakpoint privilege level to the corresponding exception * level. */ -static enum debug_el debug_exception_level(int privilege) +static enum dbg_active_el debug_exception_level(int privilege) { switch (privilege) { case AARCH64_BREAKPOINT_EL0: @@ -230,7 +230,7 @@ static int hw_breakpoint_control(struct perf_event *bp, struct perf_event **slots; struct debug_info *debug_info = ¤t->thread.debug; int i, max_slots, ctrl_reg, val_reg, reg_enable; - enum debug_el dbg_el = debug_exception_level(info->ctrl.privilege); + enum dbg_active_el dbg_el = debug_exception_level(info->ctrl.privilege); u32 ctrl; if (info->ctrl.type == ARM_BREAKPOINT_EXECUTE) { @@ -537,7 +537,7 @@ int arch_validate_hwbkpt_settings(struct perf_event *bp) * exception level at the register level. * This is used when single-stepping after a breakpoint exception. */ -static void toggle_bp_registers(int reg, enum debug_el el, int enable) +static void toggle_bp_registers(int reg, enum dbg_active_el el, int enable) { int i, max_slots, privilege; u32 ctrl; -- GitLab From 1447f93f22add339ee63d1a7015309d9fbfa47e8 Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Mon, 27 Jul 2015 15:06:49 +0200 Subject: [PATCH 1857/7006] ARM: net: add support for BPF_ANC | SKF_AD_PKTTYPE in ARM JIT. Signed-off-by: Nicolas Schichan Signed-off-by: David S. Miller --- arch/arm/net/bpf_jit_32.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index c011e2296cb1e..6ff248ca36d95 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -895,6 +895,17 @@ b_epilogue: OP_IMM3(ARM_AND, r_A, r_A, 0x1, ctx); } break; + case BPF_ANC | SKF_AD_PKTTYPE: + ctx->seen |= SEEN_SKB; + BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, + __pkt_type_offset[0]) != 1); + off = PKT_TYPE_OFFSET(); + emit(ARM_LDRB_I(r_A, r_skb, off), ctx); + emit(ARM_AND_I(r_A, r_A, PKT_TYPE_MAX), ctx); +#ifdef __BIG_ENDIAN_BITFIELD + emit(ARM_LSR_I(r_A, r_A, 5), ctx); +#endif + break; case BPF_ANC | SKF_AD_QUEUE: ctx->seen |= SEEN_SKB; BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, -- GitLab From 303249ab168f58ee52c502389b9a8046af78d142 Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Mon, 27 Jul 2015 15:06:50 +0200 Subject: [PATCH 1858/7006] ARM: net: add support for BPF_ANC | SKF_AD_PAY_OFFSET in ARM JIT. Signed-off-by: Nicolas Schichan Signed-off-by: David S. Miller --- arch/arm/net/bpf_jit_32.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 6ff248ca36d95..3c73caf6e09bb 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -915,6 +915,14 @@ b_epilogue: off = offsetof(struct sk_buff, queue_mapping); emit(ARM_LDRH_I(r_A, r_skb, off), ctx); break; + case BPF_ANC | SKF_AD_PAY_OFFSET: + ctx->seen |= SEEN_SKB | SEEN_CALL; + + emit(ARM_MOV_R(ARM_R0, r_skb), ctx); + emit_mov_i(ARM_R3, (unsigned int)skb_get_poff, ctx); + emit_blx_r(ARM_R3, ctx); + emit(ARM_MOV_R(r_A, ARM_R0), ctx); + break; case BPF_LDX | BPF_W | BPF_ABS: /* * load a 32bit word from struct seccomp_data. -- GitLab From 5bf705b43b7243c68e831ed3072db2ed00edc7fa Mon Sep 17 00:00:00 2001 From: Nicolas Schichan Date: Mon, 27 Jul 2015 15:06:51 +0200 Subject: [PATCH 1859/7006] ARM: net: add support for BPF_ANC | SKF_AD_HATYPE in ARM JIT. Signed-off-by: Nicolas Schichan Signed-off-by: David S. Miller --- arch/arm/net/bpf_jit_32.c | 22 ++++++++++++++++++++-- arch/arm/net/bpf_jit_32.h | 3 +++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index 3c73caf6e09bb..876060bcceeb3 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c @@ -857,7 +857,9 @@ b_epilogue: emit(ARM_LDR_I(r_A, r_scratch, off), ctx); break; case BPF_ANC | SKF_AD_IFINDEX: + case BPF_ANC | SKF_AD_HATYPE: /* A = skb->dev->ifindex */ + /* A = skb->dev->type */ ctx->seen |= SEEN_SKB; off = offsetof(struct sk_buff, dev); emit(ARM_LDR_I(r_scratch, r_skb, off), ctx); @@ -867,8 +869,24 @@ b_epilogue: BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); - off = offsetof(struct net_device, ifindex); - emit(ARM_LDR_I(r_A, r_scratch, off), ctx); + BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, + type) != 2); + + if (code == (BPF_ANC | SKF_AD_IFINDEX)) { + off = offsetof(struct net_device, ifindex); + emit(ARM_LDR_I(r_A, r_scratch, off), ctx); + } else { + /* + * offset of field "type" in "struct + * net_device" is above what can be + * used in the ldrh rd, [rn, #imm] + * instruction, so load the offset in + * a register and use ldrh rd, [rn, rm] + */ + off = offsetof(struct net_device, type); + emit_mov_i(ARM_R3, off, ctx); + emit(ARM_LDRH_R(r_A, r_scratch, ARM_R3), ctx); + } break; case BPF_ANC | SKF_AD_MARK: ctx->seen |= SEEN_SKB; diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h index b2d7d92859d37..4b17d5ab652a4 100644 --- a/arch/arm/net/bpf_jit_32.h +++ b/arch/arm/net/bpf_jit_32.h @@ -74,6 +74,7 @@ #define ARM_INST_LDRB_I 0x05d00000 #define ARM_INST_LDRB_R 0x07d00000 #define ARM_INST_LDRH_I 0x01d000b0 +#define ARM_INST_LDRH_R 0x019000b0 #define ARM_INST_LDR_I 0x05900000 #define ARM_INST_LDM 0x08900000 @@ -160,6 +161,8 @@ | (rm)) #define ARM_LDRH_I(rt, rn, off) (ARM_INST_LDRH_I | (rt) << 12 | (rn) << 16 \ | (((off) & 0xf0) << 4) | ((off) & 0xf)) +#define ARM_LDRH_R(rt, rn, rm) (ARM_INST_LDRH_R | (rt) << 12 | (rn) << 16 \ + | (rm)) #define ARM_LDM(rn, regs) (ARM_INST_LDM | (rn) << 16 | (regs)) -- GitLab From 77fc29c4bbbbd01ee22c50ce8260fd0f2e08c124 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:31 +0300 Subject: [PATCH 1860/7006] net/mlx4_core: Preparations for 802.1ad VLAN support mlx4_core preparation to support hardware accelerated 802.1ad VLAN device. To allow 802.1ad accelerated device, "packet has vlan" (phv) Firmware capability should be available. Firmware without the phv capability won't behave properly and can't support 802.1ad device acceleration. The driver checks the Firmware capability and sets the phv bit accordingly in SET_PORT command. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/fw.c | 82 +++++++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/fw.h | 1 + drivers/net/ethernet/mellanox/mlx4/main.c | 15 +++++ drivers/net/ethernet/mellanox/mlx4/mlx4.h | 3 + include/linux/mlx4/device.h | 5 ++ 5 files changed, 106 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c index e30bf57ad7a18..5a1c3d249530d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.c +++ b/drivers/net/ethernet/mellanox/mlx4/fw.c @@ -154,6 +154,7 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags) [26] = "Port ETS Scheduler support", [27] = "Port beacon support", [28] = "RX-ALL support", + [29] = "802.1ad offload support", }; int i; @@ -307,6 +308,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, #define QUERY_FUNC_CAP_FLAGS0_FORCE_PHY_WQE_GID 0x80 #define QUERY_FUNC_CAP_SUPPORTS_NON_POWER_OF_2_NUM_EQS (1 << 31) +#define QUERY_FUNC_CAP_PHV_BIT 0x40 if (vhcr->op_modifier == 1) { struct mlx4_active_ports actv_ports = @@ -351,6 +353,12 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave, MLX4_PUT(outbox->buf, dev->caps.phys_port_id[vhcr->in_modifier], QUERY_FUNC_CAP_PHYS_PORT_ID); + if (dev->caps.phv_bit[port]) { + field = QUERY_FUNC_CAP_PHV_BIT; + MLX4_PUT(outbox->buf, field, + QUERY_FUNC_CAP_FLAGS0_OFFSET); + } + } else if (vhcr->op_modifier == 0) { struct mlx4_active_ports actv_ports = mlx4_get_active_ports(dev, slave); @@ -600,6 +608,9 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port, MLX4_GET(func_cap->phys_port_id, outbox, QUERY_FUNC_CAP_PHYS_PORT_ID); + MLX4_GET(field, outbox, QUERY_FUNC_CAP_FLAGS0_OFFSET); + func_cap->flags |= (field & QUERY_FUNC_CAP_PHV_BIT); + /* All other resources are allocated by the master, but we still report * 'num' and 'reserved' capabilities as follows: * - num remains the maximum resource index @@ -700,6 +711,7 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) #define QUERY_DEV_CAP_D_MPT_ENTRY_SZ_OFFSET 0x92 #define QUERY_DEV_CAP_BMME_FLAGS_OFFSET 0x94 #define QUERY_DEV_CAP_CONFIG_DEV_OFFSET 0x94 +#define QUERY_DEV_CAP_PHV_EN_OFFSET 0x96 #define QUERY_DEV_CAP_RSVD_LKEY_OFFSET 0x98 #define QUERY_DEV_CAP_MAX_ICM_SZ_OFFSET 0xa0 #define QUERY_DEV_CAP_ETH_BACKPL_OFFSET 0x9c @@ -898,6 +910,12 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV; if (field & (1 << 2)) dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_IGNORE_FCS; + MLX4_GET(field, outbox, QUERY_DEV_CAP_PHV_EN_OFFSET); + if (field & 0x80) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PHV_EN; + if (field & 0x40) + dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN; + MLX4_GET(dev_cap->reserved_lkey, outbox, QUERY_DEV_CAP_RSVD_LKEY_OFFSET); MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET); @@ -1992,6 +2010,10 @@ int mlx4_QUERY_HCA(struct mlx4_dev *dev, MLX4_GET(param->uar_page_sz, outbox, INIT_HCA_UAR_PAGE_SZ_OFFSET); MLX4_GET(param->log_uar_sz, outbox, INIT_HCA_LOG_UAR_SZ_OFFSET); + /* phv_check enable */ + MLX4_GET(byte_field, outbox, INIT_HCA_CACHELINE_SZ_OFFSET); + if (byte_field & 0x2) + param->phv_check_en = 1; out: mlx4_free_cmd_mailbox(dev, mailbox); @@ -2758,3 +2780,63 @@ int mlx4_ACCESS_REG_wrapper(struct mlx4_dev *dev, int slave, 0, MLX4_CMD_ACCESS_REG, MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE); } + +static int mlx4_SET_PORT_phv_bit(struct mlx4_dev *dev, u8 port, u8 phv_bit) +{ +#define SET_PORT_GEN_PHV_VALID 0x10 +#define SET_PORT_GEN_PHV_EN 0x80 + + struct mlx4_cmd_mailbox *mailbox; + struct mlx4_set_port_general_context *context; + u32 in_mod; + int err; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return PTR_ERR(mailbox); + context = mailbox->buf; + + context->v_ignore_fcs |= SET_PORT_GEN_PHV_VALID; + if (phv_bit) + context->phv_en |= SET_PORT_GEN_PHV_EN; + + in_mod = MLX4_SET_PORT_GENERAL << 8 | port; + err = mlx4_cmd(dev, mailbox->dma, in_mod, MLX4_SET_PORT_ETH_OPCODE, + MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_NATIVE); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv) +{ + int err; + struct mlx4_func_cap func_cap; + + memset(&func_cap, 0, sizeof(func_cap)); + err = mlx4_QUERY_FUNC_CAP(dev, 1, &func_cap); + if (!err) + *phv = func_cap.flags & QUERY_FUNC_CAP_PHV_BIT; + return err; +} +EXPORT_SYMBOL(get_phv_bit); + +int set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val) +{ + int ret; + + if (mlx4_is_slave(dev)) + return -EPERM; + + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && + !(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { + ret = mlx4_SET_PORT_phv_bit(dev, port, new_val); + if (!ret) + dev->caps.phv_bit[port] = new_val; + return ret; + } + + return -EOPNOTSUPP; +} +EXPORT_SYMBOL(set_phv_bit); diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h index 07cb7c2461ada..08de5555c2f4d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/fw.h +++ b/drivers/net/ethernet/mellanox/mlx4/fw.h @@ -204,6 +204,7 @@ struct mlx4_init_hca_param { u16 cqe_size; /* For use only when CQE stride feature enabled */ u16 eqe_size; /* For use only when EQE stride feature enabled */ u8 rss_ip_frags; + u8 phv_check_en; /* for QUERY_HCA */ }; struct mlx4_init_ib_param { diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index d76f4257e305b..6f35b6c06193b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -405,6 +405,21 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap) dev->caps.max_gso_sz = dev_cap->max_gso_sz; dev->caps.max_rss_tbl_sz = dev_cap->max_rss_tbl_sz; + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN) { + struct mlx4_init_hca_param hca_param; + + memset(&hca_param, 0, sizeof(hca_param)); + err = mlx4_QUERY_HCA(dev, &hca_param); + /* Turn off PHV_EN flag in case phv_check_en is set. + * phv_check_en is a HW check that parse the packet and verify + * phv bit was reported correctly in the wqe. To allow QinQ + * PHV_EN flag should be set and phv_check_en must be cleared + * otherwise QinQ packets will be drop by the HW. + */ + if (err || hca_param.phv_check_en) + dev->caps.flags2 &= ~MLX4_DEV_CAP_FLAG2_PHV_EN; + } + /* Sense port always allowed on supported devices for ConnectX-1 and -2 */ if (mlx4_priv(dev)->pci_dev_data & MLX4_PCI_DEV_FORCE_SENSE_PORT) dev->caps.flags |= MLX4_DEV_CAP_FLAG_SENSE_SUPPORT; diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h index a092c5c34d437..232b2b55f23b9 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h @@ -787,6 +787,9 @@ struct mlx4_set_port_general_context { u8 pprx; u8 pfcrx; u16 reserved4; + u32 reserved5; + u8 phv_en; + u8 reserved6[3]; }; struct mlx4_set_port_rqp_calc_context { diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index fd13c1ce3b4ab..bcbf8c72a77be 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -211,6 +211,8 @@ enum { MLX4_DEV_CAP_FLAG2_ETS_CFG = 1LL << 26, MLX4_DEV_CAP_FLAG2_PORT_BEACON = 1LL << 27, MLX4_DEV_CAP_FLAG2_IGNORE_FCS = 1LL << 28, + MLX4_DEV_CAP_FLAG2_PHV_EN = 1LL << 29, + MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN = 1LL << 30, }; enum { @@ -581,6 +583,7 @@ struct mlx4_caps { u64 phys_port_id[MLX4_MAX_PORTS + 1]; int tunnel_offload_mode; u8 rx_checksum_flags_port[MLX4_MAX_PORTS + 1]; + u8 phv_bit[MLX4_MAX_PORTS + 1]; u8 alloc_res_qp_mask; u32 dmfs_high_rate_qpn_base; u32 dmfs_high_rate_qpn_range; @@ -1332,6 +1335,8 @@ int mlx4_SET_PORT_BEACON(struct mlx4_dev *dev, u8 port, u16 time); int mlx4_SET_PORT_fcs_check(struct mlx4_dev *dev, u8 port, u8 ignore_fcs_value); int mlx4_SET_PORT_VXLAN(struct mlx4_dev *dev, u8 port, u8 steering, int enable); +int set_phv_bit(struct mlx4_dev *dev, u8 port, int new_val); +int get_phv_bit(struct mlx4_dev *dev, u8 port, int *phv); int mlx4_find_cached_mac(struct mlx4_dev *dev, u8 port, u64 mac, int *idx); int mlx4_find_cached_vlan(struct mlx4_dev *dev, u8 port, u16 vid, int *idx); int mlx4_register_vlan(struct mlx4_dev *dev, u8 port, u16 vlan, int *index); -- GitLab From 7c509a48ff999463f698ed5082875a938094bfb3 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:32 +0300 Subject: [PATCH 1861/7006] net/mlx4_en: Prepare ethtool private flags to support more flags Currently we support only one ethtool private flag. Prepare mlx4_en_set_priv_flags function to support more than one private flag. Will be used in the next patch to support hardware accelerated 802.1ad vlan. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/en_ethtool.c | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 99ba1c50e5851..70f65534e7863 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -1801,30 +1801,29 @@ static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); int i; - if (bf_enabled_new == bf_enabled_old) - return 0; /* Nothing to do */ + if (bf_enabled_new != bf_enabled_old) { + if (bf_enabled_new) { + bool bf_supported = true; - if (bf_enabled_new) { - bool bf_supported = true; + for (i = 0; i < priv->tx_ring_num; i++) + bf_supported &= priv->tx_ring[i]->bf_alloced; - for (i = 0; i < priv->tx_ring_num; i++) - bf_supported &= priv->tx_ring[i]->bf_alloced; + if (!bf_supported) { + en_err(priv, "BlueFlame is not supported\n"); + return -EINVAL; + } - if (!bf_supported) { - en_err(priv, "BlueFlame is not supported\n"); - return -EINVAL; + priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME; + } else { + priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; } - priv->pflags |= MLX4_EN_PRIV_FLAGS_BLUEFLAME; - } else { - priv->pflags &= ~MLX4_EN_PRIV_FLAGS_BLUEFLAME; - } - - for (i = 0; i < priv->tx_ring_num; i++) - priv->tx_ring[i]->bf_enabled = bf_enabled_new; + for (i = 0; i < priv->tx_ring_num; i++) + priv->tx_ring[i]->bf_enabled = bf_enabled_new; - en_info(priv, "BlueFlame %s\n", - bf_enabled_new ? "Enabled" : "Disabled"); + en_info(priv, "BlueFlame %s\n", + bf_enabled_new ? "Enabled" : "Disabled"); + } return 0; } -- GitLab From e802f8e4c54e6adf4215ef9fa3d6eea8fcb10bf9 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:33 +0300 Subject: [PATCH 1862/7006] net/mlx4: Prepare VLAN macros for 802.1ad Hardware accelerated support To add Hardware accelerated support in 802.1ad vlan, replace Current VLAN macros to CVLAN. Replace: MLX4_WQE_CTRL_INS_VLAN MLX4_CQE_VLAN_PRESENT_MASK With: MLX4_WQE_CTRL_INS_CVLAN MLX4_CQE_CVLAN_PRESENT_MASK Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- drivers/infiniband/hw/mlx4/cq.c | 2 +- drivers/net/ethernet/mellanox/mlx4/en_rx.c | 6 +++--- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 2 +- include/linux/mlx4/cq.h | 2 +- include/linux/mlx4/qp.h | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 36eb3d012b6d3..180a8f7ec82de 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -871,7 +871,7 @@ repoll: if (is_eth) { wc->sl = be16_to_cpu(cqe->sl_vid) >> 13; if (be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) { + MLX4_CQE_CVLAN_PRESENT_MASK) { wc->vlan_id = be16_to_cpu(cqe->sl_vid) & MLX4_CQE_VID_MASK; } else { diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 12c65e1ad6a93..10f6c2f1d5a07 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -726,7 +726,7 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va, hw_checksum = csum_unfold((__force __sum16)cqe->checksum); - if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK) && + if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) && !(dev_features & NETIF_F_HW_VLAN_CTAG_RX)) { hw_checksum = get_fixed_vlan_csum(hw_checksum, hdr); hdr += sizeof(struct vlan_hdr); @@ -907,7 +907,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud gro_skb->csum_level = 1; if ((cqe->vlan_my_qpn & - cpu_to_be32(MLX4_CQE_VLAN_PRESENT_MASK)) && + cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK)) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) { u16 vid = be16_to_cpu(cqe->sl_vid); @@ -970,7 +970,7 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud PKT_HASH_TYPE_L3); if ((be32_to_cpu(cqe->vlan_my_qpn) & - MLX4_CQE_VLAN_PRESENT_MASK) && + MLX4_CQE_CVLAN_PRESENT_MASK) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index c10d98f6ad967..7c858f67ef28e 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -958,7 +958,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->bf.offset ^= ring->bf.buf_size; } else { tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); - tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN * + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN * !!skb_vlan_tag_present(skb); tx_desc->ctrl.fence_size = real_size; diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index e7ecc12a11636..899a97b20d27a 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -88,7 +88,7 @@ struct mlx4_ts_cqe { enum { MLX4_CQE_L2_TUNNEL_IPOK = 1 << 31, - MLX4_CQE_VLAN_PRESENT_MASK = 1 << 29, + MLX4_CQE_CVLAN_PRESENT_MASK = 1 << 29, MLX4_CQE_L2_TUNNEL = 1 << 27, MLX4_CQE_L2_TUNNEL_CSUM = 1 << 26, MLX4_CQE_L2_TUNNEL_IPV4 = 1 << 25, diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 6fed539e54569..6c619006c21f8 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -272,7 +272,7 @@ enum { MLX4_WQE_CTRL_SOLICITED = 1 << 1, MLX4_WQE_CTRL_IP_CSUM = 1 << 4, MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, - MLX4_WQE_CTRL_INS_VLAN = 1 << 6, + MLX4_WQE_CTRL_INS_CVLAN = 1 << 6, MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7, MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, }; -- GitLab From e38af4faf01d0b35df6995fb395e5fa4a4898289 Mon Sep 17 00:00:00 2001 From: Hadar Hen Zion Date: Mon, 27 Jul 2015 14:46:34 +0300 Subject: [PATCH 1863/7006] net/mlx4_en: Add support for hardware accelerated 802.1ad vlan To enable device support in accelerated 802.1ad vlan, the port capability "packet has vlan enable" (phv_en) should be set. Firmware won't work properly, in case phv_en is not set. The user can enable "phv_en" port capability with the new ethtool private flag phv-bit. The phv-bit private flag default value is OFF, users who are interested in 802.1ad hardware acceleration should turn ON the phv-bit private flag: $ ethtool --set-priv-flags eth1 phv-bit on Once the private flag is set, the device is ready for 802.1ad vlan acceleration. The user should also change the interface device features and turn on "tx-vlan-stag-hw-insert" which is off by default: $ ethtool -K eth1 tx-vlan-stag-hw-insert on "phv-bit" private flag setting is available only for Physical Functions(PF), the Virtual Function (VF) will be able to use the feature by setting "tx-vlan-stag-hw-insert" ethtool device feature only if the feature was enabled by the Hypervisor. Signed-off-by: Hadar Hen Zion Signed-off-by: Amir Vadai Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlx4/en_ethtool.c | 16 +++++++ .../net/ethernet/mellanox/mlx4/en_netdev.c | 46 +++++++++++++++++++ drivers/net/ethernet/mellanox/mlx4/en_rx.c | 16 ++++++- drivers/net/ethernet/mellanox/mlx4/en_tx.c | 13 ++++-- drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 1 + include/linux/mlx4/cq.h | 1 + include/linux/mlx4/qp.h | 1 + 7 files changed, 89 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c index 70f65534e7863..f79d8124321e5 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c @@ -102,6 +102,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo) static const char mlx4_en_priv_flags[][ETH_GSTRING_LEN] = { "blueflame", + "phv-bit" }; static const char main_strings[][ETH_GSTRING_LEN] = { @@ -1797,9 +1798,13 @@ static int mlx4_en_get_ts_info(struct net_device *dev, static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) { struct mlx4_en_priv *priv = netdev_priv(dev); + struct mlx4_en_dev *mdev = priv->mdev; bool bf_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); bool bf_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_BLUEFLAME); + bool phv_enabled_new = !!(flags & MLX4_EN_PRIV_FLAGS_PHV); + bool phv_enabled_old = !!(priv->pflags & MLX4_EN_PRIV_FLAGS_PHV); int i; + int ret = 0; if (bf_enabled_new != bf_enabled_old) { if (bf_enabled_new) { @@ -1825,6 +1830,17 @@ static int mlx4_en_set_priv_flags(struct net_device *dev, u32 flags) bf_enabled_new ? "Enabled" : "Disabled"); } + if (phv_enabled_new != phv_enabled_old) { + ret = set_phv_bit(mdev->dev, priv->port, (int)phv_enabled_new); + if (ret) + return ret; + else if (phv_enabled_new) + priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; + else + priv->pflags &= ~MLX4_EN_PRIV_FLAGS_PHV; + en_info(priv, "PHV bit %s\n", + phv_enabled_new ? "Enabled" : "Disabled"); + } return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index e0de2fd1ce124..4726122ea76b2 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -2184,6 +2184,25 @@ static int mlx4_en_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } } +static netdev_features_t mlx4_en_fix_features(struct net_device *netdev, + netdev_features_t features) +{ + struct mlx4_en_priv *en_priv = netdev_priv(netdev); + struct mlx4_en_dev *mdev = en_priv->mdev; + + /* Since there is no support for separate RX C-TAG/S-TAG vlan accel + * enable/disable make sure S-TAG flag is always in same state as + * C-TAG. + */ + if (features & NETIF_F_HW_VLAN_CTAG_RX && + !(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) + features |= NETIF_F_HW_VLAN_STAG_RX; + else + features &= ~NETIF_F_HW_VLAN_STAG_RX; + + return features; +} + static int mlx4_en_set_features(struct net_device *netdev, netdev_features_t features) { @@ -2218,6 +2237,10 @@ static int mlx4_en_set_features(struct net_device *netdev, en_info(priv, "Turn %s TX vlan strip offload\n", (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF"); + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_STAG_TX)) + en_info(priv, "Turn %s TX S-VLAN strip offload\n", + (features & NETIF_F_HW_VLAN_STAG_TX) ? "ON" : "OFF"); + if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_LOOPBACK)) { en_info(priv, "Turn %s loopback\n", (features & NETIF_F_LOOPBACK) ? "ON" : "OFF"); @@ -2460,6 +2483,7 @@ static const struct net_device_ops mlx4_netdev_ops = { .ndo_poll_controller = mlx4_en_netpoll, #endif .ndo_set_features = mlx4_en_set_features, + .ndo_fix_features = mlx4_en_fix_features, .ndo_setup_tc = mlx4_en_setup_tc, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx4_en_filter_rfs, @@ -2500,6 +2524,7 @@ static const struct net_device_ops mlx4_netdev_ops_master = { .ndo_poll_controller = mlx4_en_netpoll, #endif .ndo_set_features = mlx4_en_set_features, + .ndo_fix_features = mlx4_en_fix_features, .ndo_setup_tc = mlx4_en_setup_tc, #ifdef CONFIG_RFS_ACCEL .ndo_rx_flow_steer = mlx4_en_filter_rfs, @@ -2931,6 +2956,27 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, dev->hw_features |= NETIF_F_LOOPBACK | NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX; + if (!(mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) { + dev->features |= NETIF_F_HW_VLAN_STAG_RX | + NETIF_F_HW_VLAN_STAG_FILTER; + dev->hw_features |= NETIF_F_HW_VLAN_STAG_RX; + } + + if (mlx4_is_slave(mdev->dev)) { + int phv; + + err = get_phv_bit(mdev->dev, port, &phv); + if (!err && phv) { + dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; + priv->pflags |= MLX4_EN_PRIV_FLAGS_PHV; + } + } else { + if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PHV_EN && + !(mdev->dev->caps.flags2 & + MLX4_DEV_CAP_FLAG2_SKIP_OUTER_VLAN)) + dev->hw_features |= NETIF_F_HW_VLAN_STAG_TX; + } + if (mdev->dev->caps.flags & MLX4_DEV_CAP_FLAG_FCS_KEEP) dev->hw_features |= NETIF_F_RXFCS; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c index 10f6c2f1d5a07..a67fbb90d69e1 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c @@ -912,6 +912,12 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud u16 vid = be16_to_cpu(cqe->sl_vid); __vlan_hwaccel_put_tag(gro_skb, htons(ETH_P_8021Q), vid); + } else if ((be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_SVLAN_PRESENT_MASK) && + (dev->features & NETIF_F_HW_VLAN_STAG_RX)) { + __vlan_hwaccel_put_tag(gro_skb, + htons(ETH_P_8021AD), + be16_to_cpu(cqe->sl_vid)); } if (dev->features & NETIF_F_RXHASH) @@ -973,6 +979,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud MLX4_CQE_CVLAN_PRESENT_MASK) && (dev->features & NETIF_F_HW_VLAN_CTAG_RX)) __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), be16_to_cpu(cqe->sl_vid)); + else if ((be32_to_cpu(cqe->vlan_my_qpn) & + MLX4_CQE_SVLAN_PRESENT_MASK) && + (dev->features & NETIF_F_HW_VLAN_STAG_RX)) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021AD), + be16_to_cpu(cqe->sl_vid)); if (ring->hwtstamp_rx_filter == HWTSTAMP_FILTER_ALL) { timestamp = mlx4_en_get_cqe_ts(cqe); @@ -1070,7 +1081,10 @@ static const int frag_sizes[] = { void mlx4_en_calc_rx_buf(struct net_device *dev) { struct mlx4_en_priv *priv = netdev_priv(dev); - int eff_mtu = dev->mtu + ETH_HLEN + VLAN_HLEN; + /* VLAN_HLEN is added twice,to support skb vlan tagged with multiple + * headers. (For example: ETH_P_8021Q and ETH_P_8021AD). + */ + int eff_mtu = dev->mtu + ETH_HLEN + (2 * VLAN_HLEN); int buf_size = 0; int i = 0; diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c index 7c858f67ef28e..494e7762fdb19 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c @@ -718,6 +718,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) u32 index, bf_index; __be32 op_own; u16 vlan_tag = 0; + u16 vlan_proto = 0; int i_frag; int lso_header_size; void *fragptr = NULL; @@ -750,9 +751,10 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) goto tx_drop; } - if (skb_vlan_tag_present(skb)) + if (skb_vlan_tag_present(skb)) { vlan_tag = skb_vlan_tag_get(skb); - + vlan_proto = be16_to_cpu(skb->vlan_proto); + } netdev_txq_bql_enqueue_prefetchw(ring->tx_queue); @@ -958,8 +960,11 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev) ring->bf.offset ^= ring->bf.buf_size; } else { tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag); - tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN * - !!skb_vlan_tag_present(skb); + if (vlan_proto == ETH_P_8021AD) + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_SVLAN; + else if (vlan_proto == ETH_P_8021Q) + tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_CVLAN; + tx_desc->ctrl.fence_size = real_size; /* Ensure new descriptor hits memory diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h index 666d1669eb523..defcf8c395bfa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h +++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h @@ -95,6 +95,7 @@ */ #define MLX4_EN_PRIV_FLAGS_BLUEFLAME 1 +#define MLX4_EN_PRIV_FLAGS_PHV 2 #define MLX4_EN_WATCHDOG_TIMEOUT (15 * HZ) diff --git a/include/linux/mlx4/cq.h b/include/linux/mlx4/cq.h index 899a97b20d27a..09cebe528488e 100644 --- a/include/linux/mlx4/cq.h +++ b/include/linux/mlx4/cq.h @@ -89,6 +89,7 @@ struct mlx4_ts_cqe { enum { MLX4_CQE_L2_TUNNEL_IPOK = 1 << 31, MLX4_CQE_CVLAN_PRESENT_MASK = 1 << 29, + MLX4_CQE_SVLAN_PRESENT_MASK = 1 << 30, MLX4_CQE_L2_TUNNEL = 1 << 27, MLX4_CQE_L2_TUNNEL_CSUM = 1 << 26, MLX4_CQE_L2_TUNNEL_IPV4 = 1 << 25, diff --git a/include/linux/mlx4/qp.h b/include/linux/mlx4/qp.h index 6c619006c21f8..de45a51b3f041 100644 --- a/include/linux/mlx4/qp.h +++ b/include/linux/mlx4/qp.h @@ -273,6 +273,7 @@ enum { MLX4_WQE_CTRL_IP_CSUM = 1 << 4, MLX4_WQE_CTRL_TCP_UDP_CSUM = 1 << 5, MLX4_WQE_CTRL_INS_CVLAN = 1 << 6, + MLX4_WQE_CTRL_INS_SVLAN = 1 << 7, MLX4_WQE_CTRL_STRONG_ORDER = 1 << 7, MLX4_WQE_CTRL_FORCE_LOOPBACK = 1 << 0, }; -- GitLab From 5e32940621eb62064d98f42c9889db71b0368bde Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 11 Jul 2015 10:02:46 -0400 Subject: [PATCH 1864/7006] libnvdimm, btt: sparse fix Fix: drivers/nvdimm/btt.c:635:29: warning: restricted __le64 degrades to integer Signed-off-by: Dan Williams --- drivers/nvdimm/btt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 411c7b2bb37ae..552f1c4f4dc6c 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -632,8 +632,9 @@ static void parse_arena_meta(struct arena_info *arena, struct btt_sb *super, arena->logoff = arena_off + le64_to_cpu(super->logoff); arena->info2off = arena_off + le64_to_cpu(super->info2off); - arena->size = (super->nextoff > 0) ? (le64_to_cpu(super->nextoff)) : - (arena->info2off - arena->infooff + BTT_PG_SIZE); + arena->size = (le64_to_cpu(super->nextoff) > 0) + ? (le64_to_cpu(super->nextoff)) + : (arena->info2off - arena->infooff + BTT_PG_SIZE); arena->flags = le32_to_cpu(super->flags); } -- GitLab From ec92777f2ba93c00387b8fe53780c25adc57c744 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 9 Jul 2015 13:25:35 -0600 Subject: [PATCH 1865/7006] libnvdimm: Update name of the ars_status_record mask field The spec suggests that this is a simple 'length' field, not a mask. Update the name accordingly. Signed-off-by: Vishal Verma Signed-off-by: Dan Williams --- include/uapi/linux/ndctl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index 2b94ea2287bb9..e94bc20016b2d 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -87,7 +87,7 @@ struct nd_cmd_ars_status { __u32 handle; __u32 flags; __u64 err_address; - __u64 mask; + __u64 length; } __packed records[0]; } __packed; -- GitLab From 39c686b862cdb2049b90e095b6c6c727b2a7ab60 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 9 Jul 2015 13:25:36 -0600 Subject: [PATCH 1866/7006] libnvdimm: Add DSM support for Address Range Scrub commands Add support for the three ARS DSM commands: - Query ARS Capabilities - Queries the firmware to check if a given range supports scrub, and if so, which type (persistent vs. volatile) - Start ARS - Starts a scrub for a given range/type - Query ARS Status - Checks status of a previously started scrub, and provides the error logs if any. The commands are described by the example DSM spec at: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf Also add these commands to the nfit_test test framework, and return canned data. Signed-off-by: Vishal Verma Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 1 + drivers/acpi/nfit.h | 1 + include/uapi/linux/ndctl.h | 10 ++ tools/testing/nvdimm/test/nfit.c | 199 ++++++++++++++++++++++--------- 4 files changed, 152 insertions(+), 59 deletions(-) diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 628a42c41ab12..ef8a664db2541 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -868,6 +868,7 @@ static void acpi_nfit_init_dsms(struct acpi_nfit_desc *acpi_desc) struct acpi_device *adev; int i; + nd_desc->dsm_mask = acpi_desc->bus_dsm_force_en; adev = to_acpi_dev(acpi_desc); if (!adev) return; diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index 79b6d83875c1d..f2c2bb751882c 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -107,6 +107,7 @@ struct acpi_nfit_desc { struct nvdimm_bus *nvdimm_bus; struct device *dev; unsigned long dimm_dsm_force_en; + unsigned long bus_dsm_force_en; int (*blk_do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, void *iobuf, u64 len, int rw); }; diff --git a/include/uapi/linux/ndctl.h b/include/uapi/linux/ndctl.h index e94bc20016b2d..5b4a4be06e2b9 100644 --- a/include/uapi/linux/ndctl.h +++ b/include/uapi/linux/ndctl.h @@ -111,6 +111,11 @@ enum { ND_CMD_VENDOR = 9, }; +enum { + ND_ARS_VOLATILE = 1, + ND_ARS_PERSISTENT = 2, +}; + static inline const char *nvdimm_bus_cmd_name(unsigned cmd) { static const char * const names[] = { @@ -194,4 +199,9 @@ enum nd_driver_flags { enum { ND_MIN_NAMESPACE_SIZE = 0x00400000, }; + +enum ars_masks { + ARS_STATUS_MASK = 0x0000FFFF, + ARS_EXT_STATUS_SHIFT = 16, +}; #endif /* __NDCTL_H__ */ diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index d0bdae40ccc90..28dba918524e5 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -147,75 +147,153 @@ static struct nfit_test *to_nfit_test(struct device *dev) return container_of(pdev, struct nfit_test, pdev); } +static int nfit_test_cmd_get_config_size(struct nd_cmd_get_config_size *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->status = 0; + nd_cmd->config_size = LABEL_SIZE; + nd_cmd->max_xfer = SZ_4K; + + return 0; +} + +static int nfit_test_cmd_get_config_data(struct nd_cmd_get_config_data_hdr + *nd_cmd, unsigned int buf_len, void *label) +{ + unsigned int len, offset = nd_cmd->in_offset; + int rc; + + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + if (offset >= LABEL_SIZE) + return -EINVAL; + if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) + return -EINVAL; + + nd_cmd->status = 0; + len = min(nd_cmd->in_length, LABEL_SIZE - offset); + memcpy(nd_cmd->out_buf, label + offset, len); + rc = buf_len - sizeof(*nd_cmd) - len; + + return rc; +} + +static int nfit_test_cmd_set_config_data(struct nd_cmd_set_config_hdr *nd_cmd, + unsigned int buf_len, void *label) +{ + unsigned int len, offset = nd_cmd->in_offset; + u32 *status; + int rc; + + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + if (offset >= LABEL_SIZE) + return -EINVAL; + if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) + return -EINVAL; + + status = (void *)nd_cmd + nd_cmd->in_length + sizeof(*nd_cmd); + *status = 0; + len = min(nd_cmd->in_length, LABEL_SIZE - offset); + memcpy(label + offset, nd_cmd->in_buf, len); + rc = buf_len - sizeof(*nd_cmd) - (len + 4); + + return rc; +} + +static int nfit_test_cmd_ars_cap(struct nd_cmd_ars_cap *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->max_ars_out = 256; + nd_cmd->status = (ND_ARS_PERSISTENT | ND_ARS_VOLATILE) << 16; + + return 0; +} + +static int nfit_test_cmd_ars_start(struct nd_cmd_ars_start *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->status = 0; + + return 0; +} + +static int nfit_test_cmd_ars_status(struct nd_cmd_ars_status *nd_cmd, + unsigned int buf_len) +{ + if (buf_len < sizeof(*nd_cmd)) + return -EINVAL; + + nd_cmd->out_length = 256; + nd_cmd->num_records = 0; + nd_cmd->status = 0; + + return 0; +} + static int nfit_test_ctl(struct nvdimm_bus_descriptor *nd_desc, struct nvdimm *nvdimm, unsigned int cmd, void *buf, unsigned int buf_len) { struct acpi_nfit_desc *acpi_desc = to_acpi_desc(nd_desc); struct nfit_test *t = container_of(acpi_desc, typeof(*t), acpi_desc); - struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - int i, rc; + int i, rc = 0; + + if (nvdimm) { + struct nfit_mem *nfit_mem = nvdimm_provider_data(nvdimm); - if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) - return -ENOTTY; + if (!nfit_mem || !test_bit(cmd, &nfit_mem->dsm_mask)) + return -ENOTTY; - /* lookup label space for the given dimm */ - for (i = 0; i < ARRAY_SIZE(handle); i++) - if (__to_nfit_memdev(nfit_mem)->device_handle == handle[i]) + /* lookup label space for the given dimm */ + for (i = 0; i < ARRAY_SIZE(handle); i++) + if (__to_nfit_memdev(nfit_mem)->device_handle == + handle[i]) + break; + if (i >= ARRAY_SIZE(handle)) + return -ENXIO; + + switch (cmd) { + case ND_CMD_GET_CONFIG_SIZE: + rc = nfit_test_cmd_get_config_size(buf, buf_len); break; - if (i >= ARRAY_SIZE(handle)) - return -ENXIO; + case ND_CMD_GET_CONFIG_DATA: + rc = nfit_test_cmd_get_config_data(buf, buf_len, + t->label[i]); + break; + case ND_CMD_SET_CONFIG_DATA: + rc = nfit_test_cmd_set_config_data(buf, buf_len, + t->label[i]); + break; + default: + return -ENOTTY; + } + } else { + if (!nd_desc || !test_bit(cmd, &nd_desc->dsm_mask)) + return -ENOTTY; - switch (cmd) { - case ND_CMD_GET_CONFIG_SIZE: { - struct nd_cmd_get_config_size *nd_cmd = buf; - - if (buf_len < sizeof(*nd_cmd)) - return -EINVAL; - nd_cmd->status = 0; - nd_cmd->config_size = LABEL_SIZE; - nd_cmd->max_xfer = SZ_4K; - rc = 0; - break; - } - case ND_CMD_GET_CONFIG_DATA: { - struct nd_cmd_get_config_data_hdr *nd_cmd = buf; - unsigned int len, offset = nd_cmd->in_offset; - - if (buf_len < sizeof(*nd_cmd)) - return -EINVAL; - if (offset >= LABEL_SIZE) - return -EINVAL; - if (nd_cmd->in_length + sizeof(*nd_cmd) > buf_len) - return -EINVAL; - - nd_cmd->status = 0; - len = min(nd_cmd->in_length, LABEL_SIZE - offset); - memcpy(nd_cmd->out_buf, t->label[i] + offset, len); - rc = buf_len - sizeof(*nd_cmd) - len; - break; - } - case ND_CMD_SET_CONFIG_DATA: { - struct nd_cmd_set_config_hdr *nd_cmd = buf; - unsigned int len, offset = nd_cmd->in_offset; - u32 *status; - - if (buf_len < sizeof(*nd_cmd)) - return -EINVAL; - if (offset >= LABEL_SIZE) - return -EINVAL; - if (nd_cmd->in_length + sizeof(*nd_cmd) + 4 > buf_len) - return -EINVAL; - - status = buf + nd_cmd->in_length + sizeof(*nd_cmd); - *status = 0; - len = min(nd_cmd->in_length, LABEL_SIZE - offset); - memcpy(t->label[i] + offset, nd_cmd->in_buf, len); - rc = buf_len - sizeof(*nd_cmd) - (len + 4); - break; - } - default: - return -ENOTTY; + switch (cmd) { + case ND_CMD_ARS_CAP: + rc = nfit_test_cmd_ars_cap(buf, buf_len); + break; + case ND_CMD_ARS_START: + rc = nfit_test_cmd_ars_start(buf, buf_len); + break; + case ND_CMD_ARS_STATUS: + rc = nfit_test_cmd_ars_status(buf, buf_len); + break; + default: + return -ENOTTY; + } } return rc; @@ -876,6 +954,9 @@ static void nfit_test0_setup(struct nfit_test *t) set_bit(ND_CMD_GET_CONFIG_SIZE, &acpi_desc->dimm_dsm_force_en); set_bit(ND_CMD_GET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); set_bit(ND_CMD_SET_CONFIG_DATA, &acpi_desc->dimm_dsm_force_en); + set_bit(ND_CMD_ARS_CAP, &acpi_desc->bus_dsm_force_en); + set_bit(ND_CMD_ARS_START, &acpi_desc->bus_dsm_force_en); + set_bit(ND_CMD_ARS_STATUS, &acpi_desc->bus_dsm_force_en); nd_desc = &acpi_desc->nd_desc; nd_desc->ndctl = nfit_test_ctl; } -- GitLab From 6b47496a6fc81816e7edaf8224dfb88e402a05f5 Mon Sep 17 00:00:00 2001 From: Vishal Verma Date: Thu, 23 Jul 2015 11:58:48 -0600 Subject: [PATCH 1867/7006] libnvdimm, pmem: Change pmem physical sector size to PAGE_SIZE Based on a patch: c8fa317 brd: Request from fdisk 4k alignment by Boaz Harrosh, allow fdisk to create properly aligned partitions for DAX. This will also cause mkfs.ext4 to emit a warning if using a file system block size of less than PAGE_SIZE. Cc: Dan Williams Cc: Ross Zwisler Cc: Matthew Wilcox Cc: Christoph Hellwig Cc: Elliott, Robert Signed-off-by: Vishal Verma Acked-by: Boaz Harrosh Acked-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index ade9eb917a4d9..bcf48f1334431 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -162,6 +162,7 @@ static int pmem_attach_disk(struct nd_namespace_common *ndns, return -ENOMEM; blk_queue_make_request(pmem->pmem_queue, pmem_make_request); + blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE); blk_queue_max_hw_sectors(pmem->pmem_queue, UINT_MAX); blk_queue_bounce_limit(pmem->pmem_queue, BLK_BOUNCE_ANY); queue_flag_set_unlocked(QUEUE_FLAG_NONROT, pmem->pmem_queue); -- GitLab From 60e95f43fc8573e81f54b0c1e0bc542c2260d956 Mon Sep 17 00:00:00 2001 From: Linda Knippers Date: Wed, 22 Jul 2015 16:17:22 -0400 Subject: [PATCH 1868/7006] nfit: Don't check _STA on NVDIMM devices The _STA only applies to the root device, not the individual NVDIMMS, so don't check here. NVDIMM device state flags are checked elsewhere. Signed-off-by: Linda Knippers Signed-off-by: Dan Williams --- drivers/acpi/nfit.c | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index ef8a664db2541..7c2638f914a90 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -764,9 +764,7 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, struct acpi_device *adev, *adev_dimm; struct device *dev = acpi_desc->dev; const u8 *uuid = to_nfit_uuid(NFIT_DEV_DIMM); - unsigned long long sta; - int i, rc = -ENODEV; - acpi_status status; + int i; nfit_mem->dsm_mask = acpi_desc->dimm_dsm_force_en; adev = to_acpi_dev(acpi_desc); @@ -781,25 +779,11 @@ static int acpi_nfit_add_dimm(struct acpi_nfit_desc *acpi_desc, return force_enable_dimms ? 0 : -ENODEV; } - status = acpi_evaluate_integer(adev_dimm->handle, "_STA", NULL, &sta); - if (status == AE_NOT_FOUND) { - dev_dbg(dev, "%s missing _STA, assuming enabled...\n", - dev_name(&adev_dimm->dev)); - rc = 0; - } else if (ACPI_FAILURE(status)) - dev_err(dev, "%s failed to retrieve_STA, disabling...\n", - dev_name(&adev_dimm->dev)); - else if ((sta & ACPI_STA_DEVICE_ENABLED) == 0) - dev_info(dev, "%s disabled by firmware\n", - dev_name(&adev_dimm->dev)); - else - rc = 0; - for (i = ND_CMD_SMART; i <= ND_CMD_VENDOR; i++) if (acpi_check_dsm(adev_dimm->handle, uuid, 1, 1ULL << i)) set_bit(i, &nfit_mem->dsm_mask); - return force_enable_dimms ? 0 : rc; + return 0; } static int acpi_nfit_register_dimms(struct acpi_nfit_desc *acpi_desc) -- GitLab From 730daa164e7c7e31c08fab940549f4acc3329432 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Thu, 23 Jul 2015 18:02:48 -0700 Subject: [PATCH 1869/7006] Yama: remove needless CONFIG_SECURITY_YAMA_STACKED Now that minor LSMs can cleanly stack with major LSMs, remove the unneeded config for Yama to be made to explicitly stack. Just selecting the main Yama CONFIG will allow it to work, regardless of the major LSM. Since distros using Yama are already forcing it to stack, this is effectively a no-op change. Additionally add MAINTAINERS entry. Signed-off-by: Kees Cook Signed-off-by: James Morris --- Documentation/security/Yama.txt | 10 ++++----- MAINTAINERS | 6 +++++ arch/mips/configs/pistachio_defconfig | 1 - include/linux/lsm_hooks.h | 6 +++-- security/Kconfig | 5 ----- security/security.c | 11 +++------ security/yama/Kconfig | 9 +------- security/yama/yama_lsm.c | 32 +++++++++------------------ 8 files changed, 28 insertions(+), 52 deletions(-) diff --git a/Documentation/security/Yama.txt b/Documentation/security/Yama.txt index 227a63f018a27..d9ee7d7a6c7fd 100644 --- a/Documentation/security/Yama.txt +++ b/Documentation/security/Yama.txt @@ -1,9 +1,7 @@ -Yama is a Linux Security Module that collects a number of system-wide DAC -security protections that are not handled by the core kernel itself. To -select it at boot time, specify "security=yama" (though this will disable -any other LSM). - -Yama is controlled through sysctl in /proc/sys/kernel/yama: +Yama is a Linux Security Module that collects system-wide DAC security +protections that are not handled by the core kernel itself. This is +selectable at build-time with CONFIG_SECURITY_YAMA, and can be controlled +at run-time through sysctls in /proc/sys/kernel/yama: - ptrace_scope diff --git a/MAINTAINERS b/MAINTAINERS index a2264167791ac..f8be2f7971975 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9102,6 +9102,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/jj/apparmor-dev.git S: Supported F: security/apparmor/ +YAMA SECURITY MODULE +M: Kees Cook +T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git yama/tip +S: Supported +F: security/yama/ + SENSABLE PHANTOM M: Jiri Slaby S: Maintained diff --git a/arch/mips/configs/pistachio_defconfig b/arch/mips/configs/pistachio_defconfig index 1646cce032c34..642b50946943c 100644 --- a/arch/mips/configs/pistachio_defconfig +++ b/arch/mips/configs/pistachio_defconfig @@ -320,7 +320,6 @@ CONFIG_KEYS=y CONFIG_SECURITY=y CONFIG_SECURITY_NETWORK=y CONFIG_SECURITY_YAMA=y -CONFIG_SECURITY_YAMA_STACKED=y CONFIG_DEFAULT_SECURITY_DAC=y CONFIG_CRYPTO_AUTHENC=y CONFIG_CRYPTO_HMAC=y diff --git a/include/linux/lsm_hooks.h b/include/linux/lsm_hooks.h index 9429f054c3239..ec3a6bab29de3 100644 --- a/include/linux/lsm_hooks.h +++ b/include/linux/lsm_hooks.h @@ -1881,8 +1881,10 @@ static inline void security_delete_hooks(struct security_hook_list *hooks, extern int __init security_module_enable(const char *module); extern void __init capability_add_hooks(void); -#ifdef CONFIG_SECURITY_YAMA_STACKED -void __init yama_add_hooks(void); +#ifdef CONFIG_SECURITY_YAMA +extern void __init yama_add_hooks(void); +#else +static inline void __init yama_add_hooks(void) { } #endif #endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/security/Kconfig b/security/Kconfig index bf4ec46474b63..e45237897b435 100644 --- a/security/Kconfig +++ b/security/Kconfig @@ -132,7 +132,6 @@ choice default DEFAULT_SECURITY_SMACK if SECURITY_SMACK default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR - default DEFAULT_SECURITY_YAMA if SECURITY_YAMA default DEFAULT_SECURITY_DAC help @@ -151,9 +150,6 @@ choice config DEFAULT_SECURITY_APPARMOR bool "AppArmor" if SECURITY_APPARMOR=y - config DEFAULT_SECURITY_YAMA - bool "Yama" if SECURITY_YAMA=y - config DEFAULT_SECURITY_DAC bool "Unix Discretionary Access Controls" @@ -165,7 +161,6 @@ config DEFAULT_SECURITY default "smack" if DEFAULT_SECURITY_SMACK default "tomoyo" if DEFAULT_SECURITY_TOMOYO default "apparmor" if DEFAULT_SECURITY_APPARMOR - default "yama" if DEFAULT_SECURITY_YAMA default "" if DEFAULT_SECURITY_DAC endmenu diff --git a/security/security.c b/security/security.c index 595fffab48b0a..e693ffcf9266e 100644 --- a/security/security.c +++ b/security/security.c @@ -56,18 +56,13 @@ int __init security_init(void) pr_info("Security Framework initialized\n"); /* - * Always load the capability module. + * Load minor LSMs, with the capability module always first. */ capability_add_hooks(); -#ifdef CONFIG_SECURITY_YAMA_STACKED - /* - * If Yama is configured for stacking load it next. - */ yama_add_hooks(); -#endif + /* - * Load the chosen module if there is one. - * This will also find yama if it is stacking + * Load all the remaining security modules. */ do_security_initcalls(); diff --git a/security/yama/Kconfig b/security/yama/Kconfig index 3123e1da2fedb..90c605eea8921 100644 --- a/security/yama/Kconfig +++ b/security/yama/Kconfig @@ -6,14 +6,7 @@ config SECURITY_YAMA This selects Yama, which extends DAC support with additional system-wide security settings beyond regular Linux discretionary access controls. Currently available is ptrace scope restriction. + Like capabilities, this security module stacks with other LSMs. Further information can be found in Documentation/security/Yama.txt. If you are unsure how to answer this question, answer N. - -config SECURITY_YAMA_STACKED - bool "Yama stacked with other LSMs" - depends on SECURITY_YAMA - default n - help - When Yama is built into the kernel, force it to stack with the - selected primary LSM. diff --git a/security/yama/yama_lsm.c b/security/yama/yama_lsm.c index 9ed32502470e9..d3c19c970a06b 100644 --- a/security/yama/yama_lsm.c +++ b/security/yama/yama_lsm.c @@ -353,11 +353,6 @@ static struct security_hook_list yama_hooks[] = { LSM_HOOK_INIT(task_free, yama_task_free), }; -void __init yama_add_hooks(void) -{ - security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); -} - #ifdef CONFIG_SYSCTL static int yama_dointvec_minmax(struct ctl_table *table, int write, void __user *buffer, size_t *lenp, loff_t *ppos) @@ -396,25 +391,18 @@ static struct ctl_table yama_sysctl_table[] = { }, { } }; -#endif /* CONFIG_SYSCTL */ - -static __init int yama_init(void) +static void __init yama_init_sysctl(void) { -#ifndef CONFIG_SECURITY_YAMA_STACKED - /* - * If yama is being stacked this is already taken care of. - */ - if (!security_module_enable("yama")) - return 0; -#endif - pr_info("Yama: becoming mindful.\n"); - -#ifdef CONFIG_SYSCTL if (!register_sysctl_paths(yama_sysctl_path, yama_sysctl_table)) panic("Yama: sysctl registration failed.\n"); -#endif - - return 0; } +#else +static inline void yama_init_sysctl(void) { } +#endif /* CONFIG_SYSCTL */ -security_initcall(yama_init); +void __init yama_add_hooks(void) +{ + pr_info("Yama: becoming mindful.\n"); + security_add_hooks(yama_hooks, ARRAY_SIZE(yama_hooks)); + yama_init_sysctl(); +} -- GitLab From a636df9673e1e4627722777fe6075943372e76be Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:26:38 -0700 Subject: [PATCH 1870/7006] Input: tsc2005 - improve readability of register defines Improve defines for first control byte by removing 0x00 prefix (the defines are for 8 bit values and not for 16 bit values) and expose register structure by exposing the shift. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index aaf947525cd96..2a27a1f77bcba 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -61,16 +61,24 @@ #define TSC2005_CMD_12BIT 0x04 /* control byte 0 */ -#define TSC2005_REG_READ 0x0001 -#define TSC2005_REG_PND0 0x0002 -#define TSC2005_REG_X 0x0000 -#define TSC2005_REG_Y 0x0008 -#define TSC2005_REG_Z1 0x0010 -#define TSC2005_REG_Z2 0x0018 -#define TSC2005_REG_TEMP_HIGH 0x0050 -#define TSC2005_REG_CFR0 0x0060 -#define TSC2005_REG_CFR1 0x0068 -#define TSC2005_REG_CFR2 0x0070 +#define TSC2005_REG_READ 0x01 /* R/W access */ +#define TSC2005_REG_PND0 0x02 /* Power Not Down Control */ +#define TSC2005_REG_X (0x0 << 3) +#define TSC2005_REG_Y (0x1 << 3) +#define TSC2005_REG_Z1 (0x2 << 3) +#define TSC2005_REG_Z2 (0x3 << 3) +#define TSC2005_REG_AUX (0x4 << 3) +#define TSC2005_REG_TEMP1 (0x5 << 3) +#define TSC2005_REG_TEMP2 (0x6 << 3) +#define TSC2005_REG_STATUS (0x7 << 3) +#define TSC2005_REG_AUX_HIGH (0x8 << 3) +#define TSC2005_REG_AUX_LOW (0x9 << 3) +#define TSC2005_REG_TEMP_HIGH (0xA << 3) +#define TSC2005_REG_TEMP_LOW (0xB << 3) +#define TSC2005_REG_CFR0 (0xC << 3) +#define TSC2005_REG_CFR1 (0xD << 3) +#define TSC2005_REG_CFR2 (0xE << 3) +#define TSC2005_REG_CONV_FUNC (0xF << 3) /* configuration register 0 */ #define TSC2005_CFR0_PRECHARGE_276US 0x0040 -- GitLab From f00d1f8f1d9720dcf9ec7911916b685e6f92729f Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:27:09 -0700 Subject: [PATCH 1871/7006] Input: tsc2005 - fix Kconfig indentation Replace spaces with tab, so that the tsc2005 Kconfig entry matches the other entries in drivers/input/touchscreen/Kconfig. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 5b272ba091aba..cb8405d405069 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -915,10 +915,10 @@ config TOUCHSCREEN_TSC_SERIO module will be called tsc40. config TOUCHSCREEN_TSC2005 - tristate "TSC2005 based touchscreens" - depends on SPI_MASTER - help - Say Y here if you have a TSC2005 based touchscreen. + tristate "TSC2005 based touchscreens" + depends on SPI_MASTER + help + Say Y here if you have a TSC2005 based touchscreen. If unsure, say N. -- GitLab From 273cf48aa95a86ee368a10b9a2a6b0c62544ffe5 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:27:25 -0700 Subject: [PATCH 1872/7006] Input: tsc2005 - convert to regmap Convert driver so that it uses regmap instead of directly using spi_transfer for all register accesses. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/Kconfig | 1 + drivers/input/touchscreen/tsc2005.c | 171 ++++++++++------------------ 2 files changed, 60 insertions(+), 112 deletions(-) diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index cb8405d405069..860d426c480e2 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -917,6 +917,7 @@ config TOUCHSCREEN_TSC_SERIO config TOUCHSCREEN_TSC2005 tristate "TSC2005 based touchscreens" depends on SPI_MASTER + select REGMAP_SPI help Say Y here if you have a TSC2005 based touchscreen. diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 2a27a1f77bcba..b116ee9069ca7 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -34,6 +34,7 @@ #include #include #include +#include /* * The touchscreen interface operates as follows: @@ -120,20 +121,37 @@ #define TSC2005_SPI_MAX_SPEED_HZ 10000000 #define TSC2005_PENUP_TIME_MS 40 -struct tsc2005_spi_rd { - struct spi_transfer spi_xfer; - u32 spi_tx; - u32 spi_rx; +static const struct regmap_range tsc2005_writable_ranges[] = { + regmap_reg_range(TSC2005_REG_AUX_HIGH, TSC2005_REG_CFR2), }; +static const struct regmap_access_table tsc2005_writable_table = { + .yes_ranges = tsc2005_writable_ranges, + .n_yes_ranges = ARRAY_SIZE(tsc2005_writable_ranges), +}; + +static struct regmap_config tsc2005_regmap_config = { + .reg_bits = 8, + .val_bits = 16, + .reg_stride = 0x08, + .max_register = 0x78, + .read_flag_mask = TSC2005_REG_READ, + .write_flag_mask = TSC2005_REG_PND0, + .wr_table = &tsc2005_writable_table, + .use_single_rw = true, +}; + +struct tsc2005_data { + u16 x; + u16 y; + u16 z1; + u16 z2; +} __packed; +#define TSC2005_DATA_REGS 4 + struct tsc2005 { struct spi_device *spi; - - struct spi_message spi_read_msg; - struct tsc2005_spi_rd spi_x; - struct tsc2005_spi_rd spi_y; - struct tsc2005_spi_rd spi_z1; - struct tsc2005_spi_rd spi_z2; + struct regmap *regmap; struct input_dev *idev; char phys[32]; @@ -190,62 +208,6 @@ static int tsc2005_cmd(struct tsc2005 *ts, u8 cmd) return 0; } -static int tsc2005_write(struct tsc2005 *ts, u8 reg, u16 value) -{ - u32 tx = ((reg | TSC2005_REG_PND0) << 16) | value; - struct spi_transfer xfer = { - .tx_buf = &tx, - .len = 4, - .bits_per_word = 24, - }; - struct spi_message msg; - int error; - - spi_message_init(&msg); - spi_message_add_tail(&xfer, &msg); - - error = spi_sync(ts->spi, &msg); - if (error) { - dev_err(&ts->spi->dev, - "%s: failed, register: %x, value: %x, error: %d\n", - __func__, reg, value, error); - return error; - } - - return 0; -} - -static void tsc2005_setup_read(struct tsc2005_spi_rd *rd, u8 reg, bool last) -{ - memset(rd, 0, sizeof(*rd)); - - rd->spi_tx = (reg | TSC2005_REG_READ) << 16; - rd->spi_xfer.tx_buf = &rd->spi_tx; - rd->spi_xfer.rx_buf = &rd->spi_rx; - rd->spi_xfer.len = 4; - rd->spi_xfer.bits_per_word = 24; - rd->spi_xfer.cs_change = !last; -} - -static int tsc2005_read(struct tsc2005 *ts, u8 reg, u16 *value) -{ - struct tsc2005_spi_rd spi_rd; - struct spi_message msg; - int error; - - tsc2005_setup_read(&spi_rd, reg, true); - - spi_message_init(&msg); - spi_message_add_tail(&spi_rd.spi_xfer, &msg); - - error = spi_sync(ts->spi, &msg); - if (error) - return error; - - *value = spi_rd.spi_rx; - return 0; -} - static void tsc2005_update_pen_state(struct tsc2005 *ts, int x, int y, int pressure) { @@ -274,26 +236,23 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) struct tsc2005 *ts = _ts; unsigned long flags; unsigned int pressure; - u32 x, y; - u32 z1, z2; + struct tsc2005_data tsdata; int error; /* read the coordinates */ - error = spi_sync(ts->spi, &ts->spi_read_msg); + error = regmap_bulk_read(ts->regmap, TSC2005_REG_X, &tsdata, + TSC2005_DATA_REGS); if (unlikely(error)) goto out; - x = ts->spi_x.spi_rx; - y = ts->spi_y.spi_rx; - z1 = ts->spi_z1.spi_rx; - z2 = ts->spi_z2.spi_rx; - /* validate position */ - if (unlikely(x > MAX_12BIT || y > MAX_12BIT)) + if (unlikely(tsdata.x > MAX_12BIT || tsdata.y > MAX_12BIT)) goto out; /* Skip reading if the pressure components are out of range */ - if (unlikely(z1 == 0 || z2 > MAX_12BIT || z1 >= z2)) + if (unlikely(tsdata.z1 == 0 || tsdata.z2 > MAX_12BIT)) + goto out; + if (unlikely(tsdata.z1 >= tsdata.z2)) goto out; /* @@ -301,8 +260,8 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) * the value before pen-up - that implies SPI fed us stale data */ if (!ts->pen_down && - ts->in_x == x && ts->in_y == y && - ts->in_z1 == z1 && ts->in_z2 == z2) { + ts->in_x == tsdata.x && ts->in_y == tsdata.y && + ts->in_z1 == tsdata.z1 && ts->in_z2 == tsdata.z2) { goto out; } @@ -310,20 +269,20 @@ static irqreturn_t tsc2005_irq_thread(int irq, void *_ts) * At this point we are happy we have a valid and useful reading. * Remember it for later comparisons. We may now begin downsampling. */ - ts->in_x = x; - ts->in_y = y; - ts->in_z1 = z1; - ts->in_z2 = z2; + ts->in_x = tsdata.x; + ts->in_y = tsdata.y; + ts->in_z1 = tsdata.z1; + ts->in_z2 = tsdata.z2; /* Compute touch pressure resistance using equation #1 */ - pressure = x * (z2 - z1) / z1; + pressure = tsdata.x * (tsdata.z2 - tsdata.z1) / tsdata.z1; pressure = pressure * ts->x_plate_ohm / 4096; if (unlikely(pressure > MAX_12BIT)) goto out; spin_lock_irqsave(&ts->lock, flags); - tsc2005_update_pen_state(ts, x, y, pressure); + tsc2005_update_pen_state(ts, tsdata.x, tsdata.y, pressure); mod_timer(&ts->penup_timer, jiffies + msecs_to_jiffies(TSC2005_PENUP_TIME_MS)); @@ -346,9 +305,9 @@ static void tsc2005_penup_timer(unsigned long data) static void tsc2005_start_scan(struct tsc2005 *ts) { - tsc2005_write(ts, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); - tsc2005_write(ts, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); - tsc2005_write(ts, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR0, TSC2005_CFR0_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR1, TSC2005_CFR1_INITVALUE); + regmap_write(ts->regmap, TSC2005_REG_CFR2, TSC2005_CFR2_INITVALUE); tsc2005_cmd(ts, TSC2005_CMD_NORMAL); } @@ -398,9 +357,9 @@ static ssize_t tsc2005_selftest_show(struct device *dev, { struct spi_device *spi = to_spi_device(dev); struct tsc2005 *ts = spi_get_drvdata(spi); - u16 temp_high; - u16 temp_high_orig; - u16 temp_high_test; + unsigned int temp_high; + unsigned int temp_high_orig; + unsigned int temp_high_test; bool success = true; int error; @@ -411,7 +370,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, */ __tsc2005_disable(ts); - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high_orig); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high_orig); if (error) { dev_warn(dev, "selftest failed: read error %d\n", error); success = false; @@ -420,14 +379,14 @@ static ssize_t tsc2005_selftest_show(struct device *dev, temp_high_test = (temp_high_orig - 1) & MAX_12BIT; - error = tsc2005_write(ts, TSC2005_REG_TEMP_HIGH, temp_high_test); + error = regmap_write(ts->regmap, TSC2005_REG_TEMP_HIGH, temp_high_test); if (error) { dev_warn(dev, "selftest failed: write error %d\n", error); success = false; goto out; } - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); if (error) { dev_warn(dev, "selftest failed: read error %d after write\n", error); @@ -450,7 +409,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, goto out; /* test that the reset really happened */ - error = tsc2005_read(ts, TSC2005_REG_TEMP_HIGH, &temp_high); + error = regmap_read(ts->regmap, TSC2005_REG_TEMP_HIGH, &temp_high); if (error) { dev_warn(dev, "selftest failed: read error %d after reset\n", error); @@ -503,7 +462,7 @@ static void tsc2005_esd_work(struct work_struct *work) { struct tsc2005 *ts = container_of(work, struct tsc2005, esd_work.work); int error; - u16 r; + unsigned int r; if (!mutex_trylock(&ts->mutex)) { /* @@ -519,7 +478,7 @@ static void tsc2005_esd_work(struct work_struct *work) goto out; /* We should be able to read register without disabling interrupts. */ - error = tsc2005_read(ts, TSC2005_REG_CFR0, &r); + error = regmap_read(ts->regmap, TSC2005_REG_CFR0, &r); if (!error && !((r ^ TSC2005_CFR0_INITVALUE) & TSC2005_CFR0_RW_MASK)) { goto out; @@ -583,20 +542,6 @@ static void tsc2005_close(struct input_dev *input) mutex_unlock(&ts->mutex); } -static void tsc2005_setup_spi_xfer(struct tsc2005 *ts) -{ - tsc2005_setup_read(&ts->spi_x, TSC2005_REG_X, false); - tsc2005_setup_read(&ts->spi_y, TSC2005_REG_Y, false); - tsc2005_setup_read(&ts->spi_z1, TSC2005_REG_Z1, false); - tsc2005_setup_read(&ts->spi_z2, TSC2005_REG_Z2, true); - - spi_message_init(&ts->spi_read_msg); - spi_message_add_tail(&ts->spi_x.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_y.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_z1.spi_xfer, &ts->spi_read_msg); - spi_message_add_tail(&ts->spi_z2.spi_xfer, &ts->spi_read_msg); -} - static int tsc2005_probe(struct spi_device *spi) { const struct tsc2005_platform_data *pdata = dev_get_platdata(&spi->dev); @@ -661,6 +606,10 @@ static int tsc2005_probe(struct spi_device *spi) ts->spi = spi; ts->idev = input_dev; + ts->regmap = devm_regmap_init_spi(spi, &tsc2005_regmap_config); + if (IS_ERR(ts->regmap)) + return PTR_ERR(ts->regmap); + ts->x_plate_ohm = x_plate_ohm; ts->esd_timeout = esd_timeout; @@ -700,8 +649,6 @@ static int tsc2005_probe(struct spi_device *spi) INIT_DELAYED_WORK(&ts->esd_work, tsc2005_esd_work); - tsc2005_setup_spi_xfer(ts); - snprintf(ts->phys, sizeof(ts->phys), "%s/input-ts", dev_name(&spi->dev)); -- GitLab From 80b46aa69e543939e39eca5ae96fe508a1da2230 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:28:37 -0700 Subject: [PATCH 1873/7006] Input: tsc2005 - simplify drvdata acquisition Using dev_*_drvdata() instead of spi_*_drvdata() reduces lines of code and prepares the driver for possible tsc2004 support, which is i2c based. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index b116ee9069ca7..4d3f3ee37d6d5 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -355,8 +355,7 @@ static ssize_t tsc2005_selftest_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); unsigned int temp_high; unsigned int temp_high_orig; unsigned int temp_high_test; @@ -441,8 +440,7 @@ static umode_t tsc2005_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n) { struct device *dev = container_of(kobj, struct device, kobj); - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); umode_t mode = attr->mode; if (attr == &dev_attr_selftest.attr) { @@ -690,7 +688,7 @@ static int tsc2005_probe(struct spi_device *spi) return error; } - spi_set_drvdata(spi, ts); + dev_set_drvdata(&spi->dev, ts); error = sysfs_create_group(&spi->dev.kobj, &tsc2005_attr_group); if (error) { dev_err(&spi->dev, @@ -718,7 +716,7 @@ disable_regulator: static int tsc2005_remove(struct spi_device *spi) { - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(&spi->dev); sysfs_remove_group(&spi->dev.kobj, &tsc2005_attr_group); @@ -730,8 +728,7 @@ static int tsc2005_remove(struct spi_device *spi) static int __maybe_unused tsc2005_suspend(struct device *dev) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); mutex_lock(&ts->mutex); @@ -747,8 +744,7 @@ static int __maybe_unused tsc2005_suspend(struct device *dev) static int __maybe_unused tsc2005_resume(struct device *dev) { - struct spi_device *spi = to_spi_device(dev); - struct tsc2005 *ts = spi_get_drvdata(spi); + struct tsc2005 *ts = dev_get_drvdata(dev); mutex_lock(&ts->mutex); -- GitLab From d257f2980feb431ac7f0ffa1978fb694f56c7782 Mon Sep 17 00:00:00 2001 From: Sebastian Reichel Date: Mon, 27 Jul 2015 17:28:58 -0700 Subject: [PATCH 1874/7006] Input: tsc2005 - convert to gpiod The GPIOD API can be used from boardcode, so that the DT check can be removed. To avoid breaking existing boardcode, _optional() variant has been chosen. For completely removing the DT check, the regulator has also been made optional, so that it could be supplied from boardcode. As a side-effect the patch fixes the after-probe reset GPIO state, so that the device is not kept in reset state. Signed-off-by: Sebastian Reichel Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/tsc2005.c | 47 +++++++++++------------------ 1 file changed, 18 insertions(+), 29 deletions(-) diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c index 4d3f3ee37d6d5..0f65d02eeb26f 100644 --- a/drivers/input/touchscreen/tsc2005.c +++ b/drivers/input/touchscreen/tsc2005.c @@ -30,11 +30,11 @@ #include #include #include -#include #include #include #include #include +#include /* * The touchscreen interface operates as follows: @@ -180,7 +180,7 @@ struct tsc2005 { struct regulator *vio; - int reset_gpio; + struct gpio_desc *reset_gpio; void (*set_reset)(bool enable); }; @@ -318,8 +318,8 @@ static void tsc2005_stop_scan(struct tsc2005 *ts) static void tsc2005_set_reset(struct tsc2005 *ts, bool enable) { - if (ts->reset_gpio >= 0) - gpio_set_value(ts->reset_gpio, enable); + if (ts->reset_gpio) + gpiod_set_value_cansleep(ts->reset_gpio, enable); else if (ts->set_reset) ts->set_reset(enable); } @@ -611,34 +611,23 @@ static int tsc2005_probe(struct spi_device *spi) ts->x_plate_ohm = x_plate_ohm; ts->esd_timeout = esd_timeout; - if (np) { - ts->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0); - if (ts->reset_gpio == -EPROBE_DEFER) - return ts->reset_gpio; - if (ts->reset_gpio < 0) { - dev_err(&spi->dev, "error acquiring reset gpio: %d\n", - ts->reset_gpio); - return ts->reset_gpio; - } + ts->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ts->reset_gpio)) { + error = PTR_ERR(ts->reset_gpio); + dev_err(&spi->dev, "error acquiring reset gpio: %d\n", error); + return error; + } - error = devm_gpio_request_one(&spi->dev, ts->reset_gpio, 0, - "reset-gpios"); - if (error) { - dev_err(&spi->dev, "error requesting reset gpio: %d\n", - error); - return error; - } + ts->vio = devm_regulator_get_optional(&spi->dev, "vio"); + if (IS_ERR(ts->vio)) { + error = PTR_ERR(ts->vio); + dev_err(&spi->dev, "vio regulator missing (%d)", error); + return error; + } - ts->vio = devm_regulator_get(&spi->dev, "vio"); - if (IS_ERR(ts->vio)) { - error = PTR_ERR(ts->vio); - dev_err(&spi->dev, "vio regulator missing (%d)", error); - return error; - } - } else { - ts->reset_gpio = -1; + if (!ts->reset_gpio && pdata) ts->set_reset = pdata->set_reset; - } mutex_init(&ts->mutex); -- GitLab From 23393d49fb75ca97b179668aa86b7038c2dc0831 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jul 2015 15:55:16 -0500 Subject: [PATCH 1875/7006] gpio: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also modify IRQ_NOPROBE and this has been maintained although it is not clear that is really needed as most platforms don't use probing. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Cc: Michael Hennerich Acked-by: Linus Walleij Cc: Alexandre Courbot Cc: Ray Jui Cc: Stephen Warren Cc: Thierry Reding Cc: linux-gpio@vger.kernel.org Cc: bcm-kernel-feedback-list@broadcom.com Cc: linux-tegra@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/gpio/gpio-adp5588.c | 10 +--------- drivers/gpio/gpio-bcm-kona.c | 15 --------------- drivers/gpio/gpio-davinci.c | 1 - drivers/gpio/gpio-em.c | 1 - drivers/gpio/gpio-ep93xx.c | 2 +- drivers/gpio/gpio-grgpio.c | 8 -------- drivers/gpio/gpio-mcp23s08.c | 4 ---- drivers/gpio/gpio-msm-v2.c | 1 - drivers/gpio/gpio-pxa.c | 8 ++++---- drivers/gpio/gpio-sa1100.c | 2 +- drivers/gpio/gpio-sta2x11.c | 2 +- drivers/gpio/gpio-tegra.c | 1 - drivers/gpio/gpio-timberdale.c | 4 +--- drivers/gpio/gpiolib.c | 8 +------- 14 files changed, 10 insertions(+), 57 deletions(-) diff --git a/drivers/gpio/gpio-adp5588.c b/drivers/gpio/gpio-adp5588.c index d3fe6a6776daa..984186ee58a09 100644 --- a/drivers/gpio/gpio-adp5588.c +++ b/drivers/gpio/gpio-adp5588.c @@ -305,15 +305,7 @@ static int adp5588_irq_setup(struct adp5588_gpio *dev) irq_set_chip_and_handler(irq, &adp5588_irq_chip, handle_level_irq); irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - /* - * ARM needs us to explicitly flag the IRQ as VALID, - * once we do so, it will also set the noprobe. - */ - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif + irq_modify_status(irq, IRQ_NOREQUEST, IRQ_NOPROBE); } ret = request_threaded_irq(client->irq, diff --git a/drivers/gpio/gpio-bcm-kona.c b/drivers/gpio/gpio-bcm-kona.c index 109083f652486..31b90ac15204b 100644 --- a/drivers/gpio/gpio-bcm-kona.c +++ b/drivers/gpio/gpio-bcm-kona.c @@ -525,11 +525,7 @@ static int bcm_kona_gpio_irq_map(struct irq_domain *d, unsigned int irq, return ret; irq_set_lockdep_class(irq, &gpio_lock_class); irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, handle_simple_irq); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return 0; } @@ -644,17 +640,6 @@ static int bcm_kona_gpio_probe(struct platform_device *pdev) dev_err(dev, "Couldn't add GPIO chip -- %d\n", ret); goto err_irq_domain; } - for (i = 0; i < chip->ngpio; i++) { - int irq = bcm_kona_gpio_to_irq(chip, i); - irq_set_lockdep_class(irq, &gpio_lock_class); - irq_set_chip_and_handler(irq, &bcm_gpio_irq_chip, - handle_simple_irq); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else - irq_set_noprobe(irq); -#endif - } for (i = 0; i < kona_gpio->num_bank; i++) { bank = &kona_gpio->banks[i]; irq_set_chained_handler_and_data(bank->irq, diff --git a/drivers/gpio/gpio-davinci.c b/drivers/gpio/gpio-davinci.c index 7be269402bafe..94b0ab7097216 100644 --- a/drivers/gpio/gpio-davinci.c +++ b/drivers/gpio/gpio-davinci.c @@ -423,7 +423,6 @@ davinci_gpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_irq_type(irq, IRQ_TYPE_NONE); irq_set_chip_data(irq, (__force void *)g); irq_set_handler_data(irq, (void *)__gpio_mask(hw)); - set_irq_flags(irq, IRQF_VALID); return 0; } diff --git a/drivers/gpio/gpio-em.c b/drivers/gpio/gpio-em.c index a77f16c8d1422..6bca1e125e123 100644 --- a/drivers/gpio/gpio-em.c +++ b/drivers/gpio/gpio-em.c @@ -261,7 +261,6 @@ static int em_gio_irq_domain_map(struct irq_domain *h, unsigned int irq, irq_set_chip_data(irq, h->host_data); irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); /* kill me now */ return 0; } diff --git a/drivers/gpio/gpio-ep93xx.c b/drivers/gpio/gpio-ep93xx.c index dc0c409359404..9d90366ea2599 100644 --- a/drivers/gpio/gpio-ep93xx.c +++ b/drivers/gpio/gpio-ep93xx.c @@ -236,7 +236,7 @@ static void ep93xx_gpio_init_irq(void) gpio_irq <= gpio_to_irq(EP93XX_GPIO_LINE_MAX_IRQ); ++gpio_irq) { irq_set_chip_and_handler(gpio_irq, &ep93xx_gpio_irq_chip, handle_level_irq); - set_irq_flags(gpio_irq, IRQF_VALID); + irq_clear_status_flags(gpio_irq, IRQ_NOREQUEST); } irq_set_chained_handler(IRQ_EP93XX_GPIO_AB, diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c index 0a8f7617e72e9..77053d61466e7 100644 --- a/drivers/gpio/gpio-grgpio.c +++ b/drivers/gpio/gpio-grgpio.c @@ -281,12 +281,7 @@ static int grgpio_irq_map(struct irq_domain *d, unsigned int irq, irq_set_chip_data(irq, priv); irq_set_chip_and_handler(irq, &grgpio_irq_chip, handle_simple_irq); - irq_clear_status_flags(irq, IRQ_NOREQUEST); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return ret; } @@ -301,9 +296,6 @@ static void grgpio_irq_unmap(struct irq_domain *d, unsigned int irq) int ngpio = priv->bgc.gc.ngpio; int i; -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif irq_set_chip_and_handler(irq, NULL, NULL); irq_set_chip_data(irq, NULL); diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c index 2fc7ff852d167..73db7ecd7ffd9 100644 --- a/drivers/gpio/gpio-mcp23s08.c +++ b/drivers/gpio/gpio-mcp23s08.c @@ -507,11 +507,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp) irq_set_chip_data(irq, mcp); irq_set_chip(irq, &mcp23s08_irq_chip); irq_set_nested_thread(irq, true); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif } return 0; } diff --git a/drivers/gpio/gpio-msm-v2.c b/drivers/gpio/gpio-msm-v2.c index 1f0fb19209bf9..d2012cfb55718 100644 --- a/drivers/gpio/gpio-msm-v2.c +++ b/drivers/gpio/gpio-msm-v2.c @@ -355,7 +355,6 @@ static int msm_gpio_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_set_lockdep_class(irq, &msm_gpio_lock_class); irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_level_irq); - set_irq_flags(irq, IRQF_VALID); return 0; } diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c index cdbbcf0faf9da..55a11de3d5b74 100644 --- a/drivers/gpio/gpio-pxa.c +++ b/drivers/gpio/gpio-pxa.c @@ -524,7 +524,7 @@ static int pxa_irq_domain_map(struct irq_domain *d, unsigned int irq, { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_noprobe(irq); return 0; } @@ -643,20 +643,20 @@ static int pxa_gpio_probe(struct platform_device *pdev) irq = gpio_to_irq(0); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } if (irq1 > 0) { irq = gpio_to_irq(1); irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } for (irq = gpio_to_irq(gpio_offset); irq <= gpio_to_irq(pxa_last_gpio); irq++) { irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); } } diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c index e847a4cf93266..67bd2f5d89e8f 100644 --- a/drivers/gpio/gpio-sa1100.c +++ b/drivers/gpio/gpio-sa1100.c @@ -155,7 +155,7 @@ static int sa1100_gpio_irqdomain_map(struct irq_domain *d, { irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip, handle_edge_irq); - set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); + irq_set_noprobe(irq); return 0; } diff --git a/drivers/gpio/gpio-sta2x11.c b/drivers/gpio/gpio-sta2x11.c index 18579ac65b2b0..55e47828ddfcb 100644 --- a/drivers/gpio/gpio-sta2x11.c +++ b/drivers/gpio/gpio-sta2x11.c @@ -346,7 +346,7 @@ static void gsta_alloc_irq_chip(struct gsta_gpio *chip) i = chip->irq_base + j; irq_set_chip_and_handler(i, &ct->chip, ct->handler); irq_set_chip_data(i, gc); - irq_modify_status(i, IRQ_NOREQUEST | IRQ_NOPROBE, 0); + irq_clear_status_flags(i, IRQ_NOREQUEST | IRQ_NOPROBE); } gc->irq_cnt = i - gc->irq_base; } diff --git a/drivers/gpio/gpio-tegra.c b/drivers/gpio/gpio-tegra.c index 530b27f9d66f3..9b14aafb576da 100644 --- a/drivers/gpio/gpio-tegra.c +++ b/drivers/gpio/gpio-tegra.c @@ -507,7 +507,6 @@ static int tegra_gpio_probe(struct platform_device *pdev) irq_set_chip_data(irq, bank); irq_set_chip_and_handler(irq, &tegra_gpio_irq_chip, handle_simple_irq); - set_irq_flags(irq, IRQF_VALID); } for (i = 0; i < tegra_gpio_bank_count; i++) { diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c index ac53ff0a80866..5a492054589fa 100644 --- a/drivers/gpio/gpio-timberdale.c +++ b/drivers/gpio/gpio-timberdale.c @@ -295,9 +295,7 @@ static int timbgpio_probe(struct platform_device *pdev) irq_set_chip_and_handler(tgpio->irq_base + i, &timbgpio_irqchip, handle_simple_irq); irq_set_chip_data(tgpio->irq_base + i, tgpio); -#ifdef CONFIG_ARM - set_irq_flags(tgpio->irq_base + i, IRQF_VALID | IRQF_PROBE); -#endif + irq_clear_status_flags(tgpio->irq_base + i, IRQ_NOREQUEST | IRQ_NOPROBE); } irq_set_chained_handler_and_data(irq, timbgpio_irq, tgpio); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b7e24780683ab..9312bbcb19b99 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -486,11 +486,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq, /* Chips that can sleep need nested thread handlers */ if (chip->can_sleep && !chip->irq_not_threaded) irq_set_nested_thread(irq, 1); -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif + /* * No set-up of the hardware will happen if IRQ_TYPE_NONE * is passed as default type. @@ -505,9 +502,6 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq) { struct gpio_chip *chip = d->host_data; -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif if (chip->can_sleep) irq_set_nested_thread(irq, 0); irq_set_chip_and_handler(irq, NULL, NULL); -- GitLab From 13b2c4a0c3b1cd37ee6bcfbb5b6e2b94e9a75364 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Jul 2015 18:03:56 +0300 Subject: [PATCH 1876/7006] PM / QoS: Make it possible to expose device latency tolerance to userspace Typically when a device is created the bus core it belongs to (for example PCI) does not know if the device supports things like latency tolerance. This is left to the driver that binds to the device in question. However, at that time the device has already been created and there is no way to set its dev->power.set_latency_tolerance anymore. So follow what has been done for other PM QoS attributes as well and allow drivers to expose and hide latency tolerance from userspace, if the device supports it. Acked-by: Rafael J. Wysocki Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/base/power/power.h | 2 ++ drivers/base/power/qos.c | 37 +++++++++++++++++++++++++++++++++++++ drivers/base/power/sysfs.c | 11 +++++++++++ include/linux/pm_qos.h | 5 +++++ 4 files changed, 55 insertions(+) diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index f1a5d95e7b207..998fa6b230844 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -73,6 +73,8 @@ extern int pm_qos_sysfs_add_resume_latency(struct device *dev); extern void pm_qos_sysfs_remove_resume_latency(struct device *dev); extern int pm_qos_sysfs_add_flags(struct device *dev); extern void pm_qos_sysfs_remove_flags(struct device *dev); +extern int pm_qos_sysfs_add_latency_tolerance(struct device *dev); +extern void pm_qos_sysfs_remove_latency_tolerance(struct device *dev); #else /* CONFIG_PM */ diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c index e56d538d039e4..7f3646e459cba 100644 --- a/drivers/base/power/qos.c +++ b/drivers/base/power/qos.c @@ -883,3 +883,40 @@ int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val) mutex_unlock(&dev_pm_qos_mtx); return ret; } + +/** + * dev_pm_qos_expose_latency_tolerance - Expose latency tolerance to userspace + * @dev: Device whose latency tolerance to expose + */ +int dev_pm_qos_expose_latency_tolerance(struct device *dev) +{ + int ret; + + if (!dev->power.set_latency_tolerance) + return -EINVAL; + + mutex_lock(&dev_pm_qos_sysfs_mtx); + ret = pm_qos_sysfs_add_latency_tolerance(dev); + mutex_unlock(&dev_pm_qos_sysfs_mtx); + + return ret; +} +EXPORT_SYMBOL_GPL(dev_pm_qos_expose_latency_tolerance); + +/** + * dev_pm_qos_hide_latency_tolerance - Hide latency tolerance from userspace + * @dev: Device whose latency tolerance to hide + */ +void dev_pm_qos_hide_latency_tolerance(struct device *dev) +{ + mutex_lock(&dev_pm_qos_sysfs_mtx); + pm_qos_sysfs_remove_latency_tolerance(dev); + mutex_unlock(&dev_pm_qos_sysfs_mtx); + + /* Remove the request from user space now */ + pm_runtime_get_sync(dev); + dev_pm_qos_update_user_latency_tolerance(dev, + PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT); + pm_runtime_put(dev); +} +EXPORT_SYMBOL_GPL(dev_pm_qos_hide_latency_tolerance); diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c index d2be3f9c211cb..a7b46798c81d0 100644 --- a/drivers/base/power/sysfs.c +++ b/drivers/base/power/sysfs.c @@ -738,6 +738,17 @@ void pm_qos_sysfs_remove_flags(struct device *dev) sysfs_unmerge_group(&dev->kobj, &pm_qos_flags_attr_group); } +int pm_qos_sysfs_add_latency_tolerance(struct device *dev) +{ + return sysfs_merge_group(&dev->kobj, + &pm_qos_latency_tolerance_attr_group); +} + +void pm_qos_sysfs_remove_latency_tolerance(struct device *dev) +{ + sysfs_unmerge_group(&dev->kobj, &pm_qos_latency_tolerance_attr_group); +} + void rpm_sysfs_remove(struct device *dev) { sysfs_unmerge_group(&dev->kobj, &pm_runtime_attr_group); diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h index 7b3ae0cffc05b..0f65d36c2a751 100644 --- a/include/linux/pm_qos.h +++ b/include/linux/pm_qos.h @@ -161,6 +161,8 @@ void dev_pm_qos_hide_flags(struct device *dev); int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set); s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev); int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val); +int dev_pm_qos_expose_latency_tolerance(struct device *dev); +void dev_pm_qos_hide_latency_tolerance(struct device *dev); static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { @@ -229,6 +231,9 @@ static inline s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev) { return PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; } static inline int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val) { return 0; } +static inline int dev_pm_qos_expose_latency_tolerance(struct device *dev) + { return 0; } +static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {} static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; } static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; } -- GitLab From 712e960f0ee9337f3473ba3de2bcfc7e87b7c5a4 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 27 Jul 2015 18:03:57 +0300 Subject: [PATCH 1877/7006] ACPI / PM: Attach ACPI power domain only once Some devices, like MFD subdevices, share a single ACPI companion device so that they are able to access their resources and children. However, currently all these subdevices are attached to the ACPI power domain and this might cause that the power methods for the companion device get called more than once. In order to solve this we attach the ACPI power domain only to the first physical device that is bound to the ACPI companion device. In case of MFD devices, this is the parent MFD device itself. Acked-by: Rafael J. Wysocki Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/acpi/device_pm.c | 8 +++++++ drivers/acpi/internal.h | 2 ++ drivers/acpi/scan.c | 46 ++++++++++++++++++++++++++-------------- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 717afcdb5f4a9..08dc3ec7e8927 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -1123,6 +1123,14 @@ int acpi_dev_pm_attach(struct device *dev, bool power_on) if (dev->pm_domain) return -EEXIST; + /* + * Only attach the power domain to the first device if the + * companion is shared by multiple. This is to prevent doing power + * management twice. + */ + if (!acpi_device_is_first_physical_node(adev, dev)) + return -EBUSY; + acpi_add_pm_notifier(adev, dev, acpi_pm_notify_work_func); dev->pm_domain = &acpi_general_pm_domain; if (power_on) { diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index 4683a96932b91..f6aefe984941d 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -97,6 +97,8 @@ void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); bool acpi_device_is_present(struct acpi_device *adev); bool acpi_device_is_battery(struct acpi_device *adev); +bool acpi_device_is_first_physical_node(struct acpi_device *adev, + const struct device *dev); /* -------------------------------------------------------------------------- Power Resource diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ec256352f4236..89ff6d2eef8a0 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -226,6 +226,35 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, return len; } +/** + * acpi_device_is_first_physical_node - Is given dev first physical node + * @adev: ACPI companion device + * @dev: Physical device to check + * + * Function checks if given @dev is the first physical devices attached to + * the ACPI companion device. This distinction is needed in some cases + * where the same companion device is shared between many physical devices. + * + * Note that the caller have to provide valid @adev pointer. + */ +bool acpi_device_is_first_physical_node(struct acpi_device *adev, + const struct device *dev) +{ + bool ret = false; + + mutex_lock(&adev->physical_node_lock); + if (!list_empty(&adev->physical_node_list)) { + const struct acpi_device_physical_node *node; + + node = list_first_entry(&adev->physical_node_list, + struct acpi_device_physical_node, node); + ret = node->dev == dev; + } + mutex_unlock(&adev->physical_node_lock); + + return ret; +} + /* * acpi_companion_match() - Can we match via ACPI companion device * @dev: Device in question @@ -250,7 +279,6 @@ static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, static struct acpi_device *acpi_companion_match(const struct device *dev) { struct acpi_device *adev; - struct mutex *physical_node_lock; adev = ACPI_COMPANION(dev); if (!adev) @@ -259,21 +287,7 @@ static struct acpi_device *acpi_companion_match(const struct device *dev) if (list_empty(&adev->pnp.ids)) return NULL; - physical_node_lock = &adev->physical_node_lock; - mutex_lock(physical_node_lock); - if (list_empty(&adev->physical_node_list)) { - adev = NULL; - } else { - const struct acpi_device_physical_node *node; - - node = list_first_entry(&adev->physical_node_list, - struct acpi_device_physical_node, node); - if (node->dev != dev) - adev = NULL; - } - mutex_unlock(physical_node_lock); - - return adev; + return acpi_device_is_first_physical_node(adev, dev) ? adev : NULL; } static int __acpi_device_uevent_modalias(struct acpi_device *adev, -- GitLab From ddef08dd00f5548f943422c86e4ffe67dd040b6c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 27 Jul 2015 18:03:58 +0300 Subject: [PATCH 1878/7006] Driver core: wakeup the parent device before trying probe If the parent is still suspended when driver probe is attempted, the result may be failure. For example, if the parent is a PCI MFD device that has been suspended when we try to probe our device, any register reads will return 0xffffffff. To fix the problem, making sure the parent is always awake before attempting driver probe. Signed-off-by: Heikki Krogerus Signed-off-by: Rafael J. Wysocki Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/base/dd.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/base/dd.c b/drivers/base/dd.c index a638bbb1a27a5..2d6df1dd38525 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -399,6 +399,8 @@ EXPORT_SYMBOL_GPL(wait_for_device_probe); * * This function must be called with @dev lock held. When called for a * USB interface, @dev->parent lock must be held as well. + * + * If the device has a parent, runtime-resume the parent before driver probing. */ int driver_probe_device(struct device_driver *drv, struct device *dev) { @@ -410,10 +412,16 @@ int driver_probe_device(struct device_driver *drv, struct device *dev) pr_debug("bus: '%s': %s: matched device %s with driver %s\n", drv->bus->name, __func__, dev_name(dev), drv->name); + if (dev->parent) + pm_runtime_get_sync(dev->parent); + pm_runtime_barrier(dev); ret = really_probe(dev, drv); pm_request_idle(dev); + if (dev->parent) + pm_runtime_put(dev->parent); + return ret; } @@ -507,11 +515,17 @@ static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) device_lock(dev); + if (dev->parent) + pm_runtime_get_sync(dev->parent); + bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); dev_dbg(dev, "async probe completed\n"); pm_request_idle(dev); + if (dev->parent) + pm_runtime_put(dev->parent); + device_unlock(dev); put_device(dev); @@ -541,6 +555,9 @@ static int __device_attach(struct device *dev, bool allow_async) .want_async = false, }; + if (dev->parent) + pm_runtime_get_sync(dev->parent); + ret = bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); if (!ret && allow_async && data.have_async) { @@ -557,6 +574,9 @@ static int __device_attach(struct device *dev, bool allow_async) } else { pm_request_idle(dev); } + + if (dev->parent) + pm_runtime_put(dev->parent); } out_unlock: device_unlock(dev); -- GitLab From 2e0fed7f7cdc41679e209c5636ad7537dc6210a9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:03:59 +0300 Subject: [PATCH 1879/7006] klist: implement klist_prev() klist_prev() gets the previous element in the list. It is useful to traverse through the list in reverse order, for example, to provide LIFO (last in first out) variant of access. Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Lee Jones --- include/linux/klist.h | 1 + lib/klist.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/linux/klist.h b/include/linux/klist.h index 61e5b723ae73d..953f283f8451d 100644 --- a/include/linux/klist.h +++ b/include/linux/klist.h @@ -63,6 +63,7 @@ extern void klist_iter_init(struct klist *k, struct klist_iter *i); extern void klist_iter_init_node(struct klist *k, struct klist_iter *i, struct klist_node *n); extern void klist_iter_exit(struct klist_iter *i); +extern struct klist_node *klist_prev(struct klist_iter *i); extern struct klist_node *klist_next(struct klist_iter *i); #endif diff --git a/lib/klist.c b/lib/klist.c index 89b485a2a58d1..d74cf7a29afdb 100644 --- a/lib/klist.c +++ b/lib/klist.c @@ -323,6 +323,47 @@ static struct klist_node *to_klist_node(struct list_head *n) return container_of(n, struct klist_node, n_node); } +/** + * klist_prev - Ante up prev node in list. + * @i: Iterator structure. + * + * First grab list lock. Decrement the reference count of the previous + * node, if there was one. Grab the prev node, increment its reference + * count, drop the lock, and return that prev node. + */ +struct klist_node *klist_prev(struct klist_iter *i) +{ + void (*put)(struct klist_node *) = i->i_klist->put; + struct klist_node *last = i->i_cur; + struct klist_node *prev; + + spin_lock(&i->i_klist->k_lock); + + if (last) { + prev = to_klist_node(last->n_node.prev); + if (!klist_dec_and_del(last)) + put = NULL; + } else + prev = to_klist_node(i->i_klist->k_list.prev); + + i->i_cur = NULL; + while (prev != to_klist_node(&i->i_klist->k_list)) { + if (likely(!knode_dead(prev))) { + kref_get(&prev->n_ref); + i->i_cur = prev; + break; + } + prev = to_klist_node(prev->n_node.prev); + } + + spin_unlock(&i->i_klist->k_lock); + + if (put && last) + put(last); + return i->i_cur; +} +EXPORT_SYMBOL_GPL(klist_prev); + /** * klist_next - Ante up next node in list. * @i: Iterator structure. -- GitLab From 3d060aeb72113cda0acf906bfe26914fc689506a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:00 +0300 Subject: [PATCH 1880/7006] driver core: implement device_for_each_child_reverse() The new function device_for_each_child_reverse() is helpful to traverse the registered devices in a reversed order, e.g. in the case when an operation on each device should be done first on the last added device, then on one before last and so on. Signed-off-by: Andy Shevchenko Acked-by: Greg Kroah-Hartman Signed-off-by: Lee Jones --- drivers/base/core.c | 43 ++++++++++++++++++++++++++++++++++++++++++ include/linux/device.h | 2 ++ 2 files changed, 45 insertions(+) diff --git a/drivers/base/core.c b/drivers/base/core.c index dafae6d2f7ace..7d6279554afc7 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -1252,6 +1252,19 @@ void device_unregister(struct device *dev) } EXPORT_SYMBOL_GPL(device_unregister); +static struct device *prev_device(struct klist_iter *i) +{ + struct klist_node *n = klist_prev(i); + struct device *dev = NULL; + struct device_private *p; + + if (n) { + p = to_device_private_parent(n); + dev = p->device; + } + return dev; +} + static struct device *next_device(struct klist_iter *i) { struct klist_node *n = klist_next(i); @@ -1340,6 +1353,36 @@ int device_for_each_child(struct device *parent, void *data, } EXPORT_SYMBOL_GPL(device_for_each_child); +/** + * device_for_each_child_reverse - device child iterator in reversed order. + * @parent: parent struct device. + * @fn: function to be called for each device. + * @data: data for the callback. + * + * Iterate over @parent's child devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + */ +int device_for_each_child_reverse(struct device *parent, void *data, + int (*fn)(struct device *dev, void *data)) +{ + struct klist_iter i; + struct device *child; + int error = 0; + + if (!parent->p) + return 0; + + klist_iter_init(&parent->p->klist_children, &i); + while ((child = prev_device(&i)) && !error) + error = fn(child, data); + klist_iter_exit(&i); + return error; +} +EXPORT_SYMBOL_GPL(device_for_each_child_reverse); + /** * device_find_child - device iterator for locating a particular device. * @parent: parent struct device diff --git a/include/linux/device.h b/include/linux/device.h index 5a31bf3a40243..af6fbc35d8a6c 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -958,6 +958,8 @@ extern int __must_check device_add(struct device *dev); extern void device_del(struct device *dev); extern int device_for_each_child(struct device *dev, void *data, int (*fn)(struct device *dev, void *data)); +extern int device_for_each_child_reverse(struct device *dev, void *data, + int (*fn)(struct device *dev, void *data)); extern struct device *device_find_child(struct device *dev, void *data, int (*match)(struct device *dev, void *data)); extern int device_rename(struct device *dev, const char *new_name); -- GitLab From b9a8a271c38fcb1664fd6034fb9326cc9a0dec94 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:01 +0300 Subject: [PATCH 1881/7006] mfd: make mfd_remove_devices() iterate in reverse order The newly introduced device_for_each_child_reverse() would be used when MFD core removes the device. After this patch applied the devices will be removed in a reversed order. This behaviour is useful when devices have implicit dependency on order, i.e. consider MFD device with serial bus controller, such as SPI, and DMA IP that is attached to serial bus controller: before remove the DMA driver we have to be ensured that no DMA transfers is ongoing and the requested channel are unused. Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 14fd5cbcf0f2d..c17635d3e5048 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -302,7 +302,7 @@ void mfd_remove_devices(struct device *parent) { atomic_t *cnts = NULL; - device_for_each_child(parent, &cnts, mfd_remove_devices_fn); + device_for_each_child_reverse(parent, &cnts, mfd_remove_devices_fn); kfree(cnts); } EXPORT_SYMBOL(mfd_remove_devices); -- GitLab From 667dfed98615ae1fc4cc05b0763078435598c0f5 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:02 +0300 Subject: [PATCH 1882/7006] dmaengine: add a driver for Intel integrated DMA 64-bit Intel integrated DMA (iDMA) 64-bit is a specific IP that is used as a part of LPSS devices such as HSUART or SPI. The iDMA IP is attached for private usage on each host controller independently. While it has similarities with Synopsys DesignWare DMA, the following distinctions doesn't allow to use the existing driver: - 64-bit mode with corresponding changes in Hardware Linked List data structure - many slight differences in the channel registers Moreover this driver is based on the DMA virtual channels framework that helps to make the driver cleaner and easy to understand. Signed-off-by: Andy Shevchenko Acked-by: Vinod Koul Signed-off-by: Lee Jones --- drivers/dma/Kconfig | 8 + drivers/dma/Makefile | 1 + drivers/dma/idma64.c | 710 +++++++++++++++++++++++++++++++++++++++++++ drivers/dma/idma64.h | 233 ++++++++++++++ 4 files changed, 952 insertions(+) create mode 100644 drivers/dma/idma64.c create mode 100644 drivers/dma/idma64.h diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 88d474b780766..bdbbe5bcfb83e 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -85,6 +85,14 @@ config INTEL_IOP_ADMA help Enable support for the Intel(R) IOP Series RAID engines. +config IDMA64 + tristate "Intel integrated DMA 64-bit support" + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable DMA support for Intel Low Power Subsystem such as found on + Intel Skylake PCH. + source "drivers/dma/dw/Kconfig" config AT_HDMAC diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index 6a4d6f2827da4..56ff8c705c002 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_HSU_DMA) += hsu/ obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_MV_XOR) += mv_xor.o +obj-$(CONFIG_IDMA64) += idma64.o obj-$(CONFIG_DW_DMAC_CORE) += dw/ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_AT_XDMAC) += at_xdmac.o diff --git a/drivers/dma/idma64.c b/drivers/dma/idma64.c new file mode 100644 index 0000000000000..18c14e1f1414e --- /dev/null +++ b/drivers/dma/idma64.c @@ -0,0 +1,710 @@ +/* + * Core driver for the Intel integrated DMA 64-bit + * + * Copyright (C) 2015 Intel Corporation + * Author: Andy Shevchenko + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "idma64.h" + +/* Platform driver name */ +#define DRV_NAME "idma64" + +/* For now we support only two channels */ +#define IDMA64_NR_CHAN 2 + +/* ---------------------------------------------------------------------- */ + +static struct device *chan2dev(struct dma_chan *chan) +{ + return &chan->dev->device; +} + +/* ---------------------------------------------------------------------- */ + +static void idma64_off(struct idma64 *idma64) +{ + unsigned short count = 100; + + dma_writel(idma64, CFG, 0); + + channel_clear_bit(idma64, MASK(XFER), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(BLOCK), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(SRC_TRAN), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(DST_TRAN), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(ERROR), idma64->all_chan_mask); + + do { + cpu_relax(); + } while (dma_readl(idma64, CFG) & IDMA64_CFG_DMA_EN && --count); +} + +static void idma64_on(struct idma64 *idma64) +{ + dma_writel(idma64, CFG, IDMA64_CFG_DMA_EN); +} + +/* ---------------------------------------------------------------------- */ + +static void idma64_chan_init(struct idma64 *idma64, struct idma64_chan *idma64c) +{ + u32 cfghi = IDMA64C_CFGH_SRC_PER(1) | IDMA64C_CFGH_DST_PER(0); + u32 cfglo = 0; + + /* Enforce FIFO drain when channel is suspended */ + cfglo |= IDMA64C_CFGL_CH_DRAIN; + + /* Set default burst alignment */ + cfglo |= IDMA64C_CFGL_DST_BURST_ALIGN | IDMA64C_CFGL_SRC_BURST_ALIGN; + + channel_writel(idma64c, CFG_LO, cfglo); + channel_writel(idma64c, CFG_HI, cfghi); + + /* Enable interrupts */ + channel_set_bit(idma64, MASK(XFER), idma64c->mask); + channel_set_bit(idma64, MASK(ERROR), idma64c->mask); + + /* + * Enforce the controller to be turned on. + * + * The iDMA is turned off in ->probe() and looses context during system + * suspend / resume cycle. That's why we have to enable it each time we + * use it. + */ + idma64_on(idma64); +} + +static void idma64_chan_stop(struct idma64 *idma64, struct idma64_chan *idma64c) +{ + channel_clear_bit(idma64, CH_EN, idma64c->mask); +} + +static void idma64_chan_start(struct idma64 *idma64, struct idma64_chan *idma64c) +{ + struct idma64_desc *desc = idma64c->desc; + struct idma64_hw_desc *hw = &desc->hw[0]; + + channel_writeq(idma64c, SAR, 0); + channel_writeq(idma64c, DAR, 0); + + channel_writel(idma64c, CTL_HI, IDMA64C_CTLH_BLOCK_TS(~0UL)); + channel_writel(idma64c, CTL_LO, IDMA64C_CTLL_LLP_S_EN | IDMA64C_CTLL_LLP_D_EN); + + channel_writeq(idma64c, LLP, hw->llp); + + channel_set_bit(idma64, CH_EN, idma64c->mask); +} + +static void idma64_stop_transfer(struct idma64_chan *idma64c) +{ + struct idma64 *idma64 = to_idma64(idma64c->vchan.chan.device); + + idma64_chan_stop(idma64, idma64c); +} + +static void idma64_start_transfer(struct idma64_chan *idma64c) +{ + struct idma64 *idma64 = to_idma64(idma64c->vchan.chan.device); + struct virt_dma_desc *vdesc; + + /* Get the next descriptor */ + vdesc = vchan_next_desc(&idma64c->vchan); + if (!vdesc) { + idma64c->desc = NULL; + return; + } + + list_del(&vdesc->node); + idma64c->desc = to_idma64_desc(vdesc); + + /* Configure the channel */ + idma64_chan_init(idma64, idma64c); + + /* Start the channel with a new descriptor */ + idma64_chan_start(idma64, idma64c); +} + +/* ---------------------------------------------------------------------- */ + +static void idma64_chan_irq(struct idma64 *idma64, unsigned short c, + u32 status_err, u32 status_xfer) +{ + struct idma64_chan *idma64c = &idma64->chan[c]; + struct idma64_desc *desc; + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + desc = idma64c->desc; + if (desc) { + if (status_err & (1 << c)) { + dma_writel(idma64, CLEAR(ERROR), idma64c->mask); + desc->status = DMA_ERROR; + } else if (status_xfer & (1 << c)) { + dma_writel(idma64, CLEAR(XFER), idma64c->mask); + desc->status = DMA_COMPLETE; + vchan_cookie_complete(&desc->vdesc); + idma64_start_transfer(idma64c); + } + + /* idma64_start_transfer() updates idma64c->desc */ + if (idma64c->desc == NULL || desc->status == DMA_ERROR) + idma64_stop_transfer(idma64c); + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); +} + +static irqreturn_t idma64_irq(int irq, void *dev) +{ + struct idma64 *idma64 = dev; + u32 status = dma_readl(idma64, STATUS_INT); + u32 status_xfer; + u32 status_err; + unsigned short i; + + dev_vdbg(idma64->dma.dev, "%s: status=%#x\n", __func__, status); + + /* Check if we have any interrupt from the DMA controller */ + if (!status) + return IRQ_NONE; + + /* Disable interrupts */ + channel_clear_bit(idma64, MASK(XFER), idma64->all_chan_mask); + channel_clear_bit(idma64, MASK(ERROR), idma64->all_chan_mask); + + status_xfer = dma_readl(idma64, RAW(XFER)); + status_err = dma_readl(idma64, RAW(ERROR)); + + for (i = 0; i < idma64->dma.chancnt; i++) + idma64_chan_irq(idma64, i, status_err, status_xfer); + + /* Re-enable interrupts */ + channel_set_bit(idma64, MASK(XFER), idma64->all_chan_mask); + channel_set_bit(idma64, MASK(ERROR), idma64->all_chan_mask); + + return IRQ_HANDLED; +} + +/* ---------------------------------------------------------------------- */ + +static struct idma64_desc *idma64_alloc_desc(unsigned int ndesc) +{ + struct idma64_desc *desc; + + desc = kzalloc(sizeof(*desc), GFP_NOWAIT); + if (!desc) + return NULL; + + desc->hw = kcalloc(ndesc, sizeof(*desc->hw), GFP_NOWAIT); + if (!desc->hw) { + kfree(desc); + return NULL; + } + + return desc; +} + +static void idma64_desc_free(struct idma64_chan *idma64c, + struct idma64_desc *desc) +{ + struct idma64_hw_desc *hw; + + if (desc->ndesc) { + unsigned int i = desc->ndesc; + + do { + hw = &desc->hw[--i]; + dma_pool_free(idma64c->pool, hw->lli, hw->llp); + } while (i); + } + + kfree(desc->hw); + kfree(desc); +} + +static void idma64_vdesc_free(struct virt_dma_desc *vdesc) +{ + struct idma64_chan *idma64c = to_idma64_chan(vdesc->tx.chan); + + idma64_desc_free(idma64c, to_idma64_desc(vdesc)); +} + +static u64 idma64_hw_desc_fill(struct idma64_hw_desc *hw, + struct dma_slave_config *config, + enum dma_transfer_direction direction, u64 llp) +{ + struct idma64_lli *lli = hw->lli; + u64 sar, dar; + u32 ctlhi = IDMA64C_CTLH_BLOCK_TS(hw->len); + u32 ctllo = IDMA64C_CTLL_LLP_S_EN | IDMA64C_CTLL_LLP_D_EN; + u32 src_width, dst_width; + + if (direction == DMA_MEM_TO_DEV) { + sar = hw->phys; + dar = config->dst_addr; + ctllo |= IDMA64C_CTLL_DST_FIX | IDMA64C_CTLL_SRC_INC | + IDMA64C_CTLL_FC_M2P; + src_width = min_t(u32, 2, __fls(sar | hw->len)); + dst_width = __fls(config->dst_addr_width); + } else { /* DMA_DEV_TO_MEM */ + sar = config->src_addr; + dar = hw->phys; + ctllo |= IDMA64C_CTLL_DST_INC | IDMA64C_CTLL_SRC_FIX | + IDMA64C_CTLL_FC_P2M; + src_width = __fls(config->src_addr_width); + dst_width = min_t(u32, 2, __fls(dar | hw->len)); + } + + lli->sar = sar; + lli->dar = dar; + + lli->ctlhi = ctlhi; + lli->ctllo = ctllo | + IDMA64C_CTLL_SRC_MSIZE(config->src_maxburst) | + IDMA64C_CTLL_DST_MSIZE(config->dst_maxburst) | + IDMA64C_CTLL_DST_WIDTH(dst_width) | + IDMA64C_CTLL_SRC_WIDTH(src_width); + + lli->llp = llp; + return hw->llp; +} + +static void idma64_desc_fill(struct idma64_chan *idma64c, + struct idma64_desc *desc) +{ + struct dma_slave_config *config = &idma64c->config; + struct idma64_hw_desc *hw = &desc->hw[desc->ndesc - 1]; + struct idma64_lli *lli = hw->lli; + u64 llp = 0; + unsigned int i = desc->ndesc; + + /* Fill the hardware descriptors and link them to a list */ + do { + hw = &desc->hw[--i]; + llp = idma64_hw_desc_fill(hw, config, desc->direction, llp); + desc->length += hw->len; + } while (i); + + /* Trigger interrupt after last block */ + lli->ctllo |= IDMA64C_CTLL_INT_EN; +} + +static struct dma_async_tx_descriptor *idma64_prep_slave_sg( + struct dma_chan *chan, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + struct idma64_desc *desc; + struct scatterlist *sg; + unsigned int i; + + desc = idma64_alloc_desc(sg_len); + if (!desc) + return NULL; + + for_each_sg(sgl, sg, sg_len, i) { + struct idma64_hw_desc *hw = &desc->hw[i]; + + /* Allocate DMA capable memory for hardware descriptor */ + hw->lli = dma_pool_alloc(idma64c->pool, GFP_NOWAIT, &hw->llp); + if (!hw->lli) { + desc->ndesc = i; + idma64_desc_free(idma64c, desc); + return NULL; + } + + hw->phys = sg_dma_address(sg); + hw->len = sg_dma_len(sg); + } + + desc->ndesc = sg_len; + desc->direction = direction; + desc->status = DMA_IN_PROGRESS; + + idma64_desc_fill(idma64c, desc); + return vchan_tx_prep(&idma64c->vchan, &desc->vdesc, flags); +} + +static void idma64_issue_pending(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + if (vchan_issue_pending(&idma64c->vchan) && !idma64c->desc) + idma64_start_transfer(idma64c); + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); +} + +static size_t idma64_active_desc_size(struct idma64_chan *idma64c) +{ + struct idma64_desc *desc = idma64c->desc; + struct idma64_hw_desc *hw; + size_t bytes = desc->length; + u64 llp; + u32 ctlhi; + unsigned int i = 0; + + llp = channel_readq(idma64c, LLP); + do { + hw = &desc->hw[i]; + } while ((hw->llp != llp) && (++i < desc->ndesc)); + + if (!i) + return bytes; + + do { + bytes -= desc->hw[--i].len; + } while (i); + + ctlhi = channel_readl(idma64c, CTL_HI); + return bytes - IDMA64C_CTLH_BLOCK_TS(ctlhi); +} + +static enum dma_status idma64_tx_status(struct dma_chan *chan, + dma_cookie_t cookie, struct dma_tx_state *state) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + struct virt_dma_desc *vdesc; + enum dma_status status; + size_t bytes; + unsigned long flags; + + status = dma_cookie_status(chan, cookie, state); + if (status == DMA_COMPLETE) + return status; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + vdesc = vchan_find_desc(&idma64c->vchan, cookie); + if (idma64c->desc && cookie == idma64c->desc->vdesc.tx.cookie) { + bytes = idma64_active_desc_size(idma64c); + dma_set_residue(state, bytes); + status = idma64c->desc->status; + } else if (vdesc) { + bytes = to_idma64_desc(vdesc)->length; + dma_set_residue(state, bytes); + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + return status; +} + +static void convert_burst(u32 *maxburst) +{ + if (*maxburst) + *maxburst = __fls(*maxburst); + else + *maxburst = 0; +} + +static int idma64_slave_config(struct dma_chan *chan, + struct dma_slave_config *config) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + + /* Check if chan will be configured for slave transfers */ + if (!is_slave_direction(config->direction)) + return -EINVAL; + + memcpy(&idma64c->config, config, sizeof(idma64c->config)); + + convert_burst(&idma64c->config.src_maxburst); + convert_burst(&idma64c->config.dst_maxburst); + + return 0; +} + +static void idma64_chan_deactivate(struct idma64_chan *idma64c) +{ + unsigned short count = 100; + u32 cfglo; + + cfglo = channel_readl(idma64c, CFG_LO); + channel_writel(idma64c, CFG_LO, cfglo | IDMA64C_CFGL_CH_SUSP); + do { + udelay(1); + cfglo = channel_readl(idma64c, CFG_LO); + } while (!(cfglo & IDMA64C_CFGL_FIFO_EMPTY) && --count); +} + +static void idma64_chan_activate(struct idma64_chan *idma64c) +{ + u32 cfglo; + + cfglo = channel_readl(idma64c, CFG_LO); + channel_writel(idma64c, CFG_LO, cfglo & ~IDMA64C_CFGL_CH_SUSP); +} + +static int idma64_pause(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + if (idma64c->desc && idma64c->desc->status == DMA_IN_PROGRESS) { + idma64_chan_deactivate(idma64c); + idma64c->desc->status = DMA_PAUSED; + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + return 0; +} + +static int idma64_resume(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + if (idma64c->desc && idma64c->desc->status == DMA_PAUSED) { + idma64c->desc->status = DMA_IN_PROGRESS; + idma64_chan_activate(idma64c); + } + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + return 0; +} + +static int idma64_terminate_all(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&idma64c->vchan.lock, flags); + idma64_chan_deactivate(idma64c); + idma64_stop_transfer(idma64c); + if (idma64c->desc) { + idma64_vdesc_free(&idma64c->desc->vdesc); + idma64c->desc = NULL; + } + vchan_get_all_descriptors(&idma64c->vchan, &head); + spin_unlock_irqrestore(&idma64c->vchan.lock, flags); + + vchan_dma_desc_free_list(&idma64c->vchan, &head); + return 0; +} + +static int idma64_alloc_chan_resources(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + + /* Create a pool of consistent memory blocks for hardware descriptors */ + idma64c->pool = dma_pool_create(dev_name(chan2dev(chan)), + chan->device->dev, + sizeof(struct idma64_lli), 8, 0); + if (!idma64c->pool) { + dev_err(chan2dev(chan), "No memory for descriptors\n"); + return -ENOMEM; + } + + return 0; +} + +static void idma64_free_chan_resources(struct dma_chan *chan) +{ + struct idma64_chan *idma64c = to_idma64_chan(chan); + + vchan_free_chan_resources(to_virt_chan(chan)); + dma_pool_destroy(idma64c->pool); + idma64c->pool = NULL; +} + +/* ---------------------------------------------------------------------- */ + +#define IDMA64_BUSWIDTHS \ + BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ + BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ + BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) + +static int idma64_probe(struct idma64_chip *chip) +{ + struct idma64 *idma64; + unsigned short nr_chan = IDMA64_NR_CHAN; + unsigned short i; + int ret; + + idma64 = devm_kzalloc(chip->dev, sizeof(*idma64), GFP_KERNEL); + if (!idma64) + return -ENOMEM; + + idma64->regs = chip->regs; + chip->idma64 = idma64; + + idma64->chan = devm_kcalloc(chip->dev, nr_chan, sizeof(*idma64->chan), + GFP_KERNEL); + if (!idma64->chan) + return -ENOMEM; + + idma64->all_chan_mask = (1 << nr_chan) - 1; + + /* Turn off iDMA controller */ + idma64_off(idma64); + + ret = devm_request_irq(chip->dev, chip->irq, idma64_irq, IRQF_SHARED, + dev_name(chip->dev), idma64); + if (ret) + return ret; + + INIT_LIST_HEAD(&idma64->dma.channels); + for (i = 0; i < nr_chan; i++) { + struct idma64_chan *idma64c = &idma64->chan[i]; + + idma64c->vchan.desc_free = idma64_vdesc_free; + vchan_init(&idma64c->vchan, &idma64->dma); + + idma64c->regs = idma64->regs + i * IDMA64_CH_LENGTH; + idma64c->mask = BIT(i); + } + + dma_cap_set(DMA_SLAVE, idma64->dma.cap_mask); + dma_cap_set(DMA_PRIVATE, idma64->dma.cap_mask); + + idma64->dma.device_alloc_chan_resources = idma64_alloc_chan_resources; + idma64->dma.device_free_chan_resources = idma64_free_chan_resources; + + idma64->dma.device_prep_slave_sg = idma64_prep_slave_sg; + + idma64->dma.device_issue_pending = idma64_issue_pending; + idma64->dma.device_tx_status = idma64_tx_status; + + idma64->dma.device_config = idma64_slave_config; + idma64->dma.device_pause = idma64_pause; + idma64->dma.device_resume = idma64_resume; + idma64->dma.device_terminate_all = idma64_terminate_all; + + idma64->dma.src_addr_widths = IDMA64_BUSWIDTHS; + idma64->dma.dst_addr_widths = IDMA64_BUSWIDTHS; + idma64->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); + idma64->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; + + idma64->dma.dev = chip->dev; + + ret = dma_async_device_register(&idma64->dma); + if (ret) + return ret; + + dev_info(chip->dev, "Found Intel integrated DMA 64-bit\n"); + return 0; +} + +static int idma64_remove(struct idma64_chip *chip) +{ + struct idma64 *idma64 = chip->idma64; + unsigned short i; + + dma_async_device_unregister(&idma64->dma); + + /* + * Explicitly call devm_request_irq() to avoid the side effects with + * the scheduled tasklets. + */ + devm_free_irq(chip->dev, chip->irq, idma64); + + for (i = 0; i < idma64->dma.chancnt; i++) { + struct idma64_chan *idma64c = &idma64->chan[i]; + + tasklet_kill(&idma64c->vchan.task); + } + + return 0; +} + +/* ---------------------------------------------------------------------- */ + +static int idma64_platform_probe(struct platform_device *pdev) +{ + struct idma64_chip *chip; + struct device *dev = &pdev->dev; + struct resource *mem; + int ret; + + chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->irq = platform_get_irq(pdev, 0); + if (chip->irq < 0) + return chip->irq; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + chip->regs = devm_ioremap_resource(dev, mem); + if (IS_ERR(chip->regs)) + return PTR_ERR(chip->regs); + + ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + chip->dev = dev; + + ret = idma64_probe(chip); + if (ret) + return ret; + + platform_set_drvdata(pdev, chip); + return 0; +} + +static int idma64_platform_remove(struct platform_device *pdev) +{ + struct idma64_chip *chip = platform_get_drvdata(pdev); + + return idma64_remove(chip); +} + +#ifdef CONFIG_PM_SLEEP + +static int idma64_pm_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct idma64_chip *chip = platform_get_drvdata(pdev); + + idma64_off(chip->idma64); + return 0; +} + +static int idma64_pm_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct idma64_chip *chip = platform_get_drvdata(pdev); + + idma64_on(chip->idma64); + return 0; +} + +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops idma64_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(idma64_pm_suspend, idma64_pm_resume) +}; + +static struct platform_driver idma64_platform_driver = { + .probe = idma64_platform_probe, + .remove = idma64_platform_remove, + .driver = { + .name = DRV_NAME, + .pm = &idma64_dev_pm_ops, + }, +}; + +module_platform_driver(idma64_platform_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("iDMA64 core driver"); +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/dma/idma64.h b/drivers/dma/idma64.h new file mode 100644 index 0000000000000..a4d99685a7c40 --- /dev/null +++ b/drivers/dma/idma64.h @@ -0,0 +1,233 @@ +/* + * Driver for the Intel integrated DMA 64-bit + * + * Copyright (C) 2015 Intel Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __DMA_IDMA64_H__ +#define __DMA_IDMA64_H__ + +#include +#include +#include +#include + +#include "virt-dma.h" + +/* Channel registers */ + +#define IDMA64_CH_SAR 0x00 /* Source Address Register */ +#define IDMA64_CH_DAR 0x08 /* Destination Address Register */ +#define IDMA64_CH_LLP 0x10 /* Linked List Pointer */ +#define IDMA64_CH_CTL_LO 0x18 /* Control Register Low */ +#define IDMA64_CH_CTL_HI 0x1c /* Control Register High */ +#define IDMA64_CH_SSTAT 0x20 +#define IDMA64_CH_DSTAT 0x28 +#define IDMA64_CH_SSTATAR 0x30 +#define IDMA64_CH_DSTATAR 0x38 +#define IDMA64_CH_CFG_LO 0x40 /* Configuration Register Low */ +#define IDMA64_CH_CFG_HI 0x44 /* Configuration Register High */ +#define IDMA64_CH_SGR 0x48 +#define IDMA64_CH_DSR 0x50 + +#define IDMA64_CH_LENGTH 0x58 + +/* Bitfields in CTL_LO */ +#define IDMA64C_CTLL_INT_EN (1 << 0) /* irqs enabled? */ +#define IDMA64C_CTLL_DST_WIDTH(x) ((x) << 1) /* bytes per element */ +#define IDMA64C_CTLL_SRC_WIDTH(x) ((x) << 4) +#define IDMA64C_CTLL_DST_INC (0 << 8) /* DAR update/not */ +#define IDMA64C_CTLL_DST_FIX (1 << 8) +#define IDMA64C_CTLL_SRC_INC (0 << 10) /* SAR update/not */ +#define IDMA64C_CTLL_SRC_FIX (1 << 10) +#define IDMA64C_CTLL_DST_MSIZE(x) ((x) << 11) /* burst, #elements */ +#define IDMA64C_CTLL_SRC_MSIZE(x) ((x) << 14) +#define IDMA64C_CTLL_FC_M2P (1 << 20) /* mem-to-periph */ +#define IDMA64C_CTLL_FC_P2M (2 << 20) /* periph-to-mem */ +#define IDMA64C_CTLL_LLP_D_EN (1 << 27) /* dest block chain */ +#define IDMA64C_CTLL_LLP_S_EN (1 << 28) /* src block chain */ + +/* Bitfields in CTL_HI */ +#define IDMA64C_CTLH_BLOCK_TS(x) ((x) & ((1 << 17) - 1)) +#define IDMA64C_CTLH_DONE (1 << 17) + +/* Bitfields in CFG_LO */ +#define IDMA64C_CFGL_DST_BURST_ALIGN (1 << 0) /* dst burst align */ +#define IDMA64C_CFGL_SRC_BURST_ALIGN (1 << 1) /* src burst align */ +#define IDMA64C_CFGL_CH_SUSP (1 << 8) +#define IDMA64C_CFGL_FIFO_EMPTY (1 << 9) +#define IDMA64C_CFGL_CH_DRAIN (1 << 10) /* drain FIFO */ +#define IDMA64C_CFGL_DST_OPT_BL (1 << 20) /* optimize dst burst length */ +#define IDMA64C_CFGL_SRC_OPT_BL (1 << 21) /* optimize src burst length */ + +/* Bitfields in CFG_HI */ +#define IDMA64C_CFGH_SRC_PER(x) ((x) << 0) /* src peripheral */ +#define IDMA64C_CFGH_DST_PER(x) ((x) << 4) /* dst peripheral */ +#define IDMA64C_CFGH_RD_ISSUE_THD(x) ((x) << 8) +#define IDMA64C_CFGH_RW_ISSUE_THD(x) ((x) << 18) + +/* Interrupt registers */ + +#define IDMA64_INT_XFER 0x00 +#define IDMA64_INT_BLOCK 0x08 +#define IDMA64_INT_SRC_TRAN 0x10 +#define IDMA64_INT_DST_TRAN 0x18 +#define IDMA64_INT_ERROR 0x20 + +#define IDMA64_RAW(x) (0x2c0 + IDMA64_INT_##x) /* r */ +#define IDMA64_STATUS(x) (0x2e8 + IDMA64_INT_##x) /* r (raw & mask) */ +#define IDMA64_MASK(x) (0x310 + IDMA64_INT_##x) /* rw (set = irq enabled) */ +#define IDMA64_CLEAR(x) (0x338 + IDMA64_INT_##x) /* w (ack, affects "raw") */ + +/* Common registers */ + +#define IDMA64_STATUS_INT 0x360 /* r */ +#define IDMA64_CFG 0x398 +#define IDMA64_CH_EN 0x3a0 + +/* Bitfields in CFG */ +#define IDMA64_CFG_DMA_EN (1 << 0) + +/* Hardware descriptor for Linked LIst transfers */ +struct idma64_lli { + u64 sar; + u64 dar; + u64 llp; + u32 ctllo; + u32 ctlhi; + u32 sstat; + u32 dstat; +}; + +struct idma64_hw_desc { + struct idma64_lli *lli; + dma_addr_t llp; + dma_addr_t phys; + unsigned int len; +}; + +struct idma64_desc { + struct virt_dma_desc vdesc; + enum dma_transfer_direction direction; + struct idma64_hw_desc *hw; + unsigned int ndesc; + size_t length; + enum dma_status status; +}; + +static inline struct idma64_desc *to_idma64_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct idma64_desc, vdesc); +} + +struct idma64_chan { + struct virt_dma_chan vchan; + + void __iomem *regs; + + /* hardware configuration */ + enum dma_transfer_direction direction; + unsigned int mask; + struct dma_slave_config config; + + void *pool; + struct idma64_desc *desc; +}; + +static inline struct idma64_chan *to_idma64_chan(struct dma_chan *chan) +{ + return container_of(chan, struct idma64_chan, vchan.chan); +} + +#define channel_set_bit(idma64, reg, mask) \ + dma_writel(idma64, reg, ((mask) << 8) | (mask)) +#define channel_clear_bit(idma64, reg, mask) \ + dma_writel(idma64, reg, ((mask) << 8) | 0) + +static inline u32 idma64c_readl(struct idma64_chan *idma64c, int offset) +{ + return readl(idma64c->regs + offset); +} + +static inline void idma64c_writel(struct idma64_chan *idma64c, int offset, + u32 value) +{ + writel(value, idma64c->regs + offset); +} + +#define channel_readl(idma64c, reg) \ + idma64c_readl(idma64c, IDMA64_CH_##reg) +#define channel_writel(idma64c, reg, value) \ + idma64c_writel(idma64c, IDMA64_CH_##reg, (value)) + +static inline u64 idma64c_readq(struct idma64_chan *idma64c, int offset) +{ + u64 l, h; + + l = idma64c_readl(idma64c, offset); + h = idma64c_readl(idma64c, offset + 4); + + return l | (h << 32); +} + +static inline void idma64c_writeq(struct idma64_chan *idma64c, int offset, + u64 value) +{ + idma64c_writel(idma64c, offset, value); + idma64c_writel(idma64c, offset + 4, value >> 32); +} + +#define channel_readq(idma64c, reg) \ + idma64c_readq(idma64c, IDMA64_CH_##reg) +#define channel_writeq(idma64c, reg, value) \ + idma64c_writeq(idma64c, IDMA64_CH_##reg, (value)) + +struct idma64 { + struct dma_device dma; + + void __iomem *regs; + + /* channels */ + unsigned short all_chan_mask; + struct idma64_chan *chan; +}; + +static inline struct idma64 *to_idma64(struct dma_device *ddev) +{ + return container_of(ddev, struct idma64, dma); +} + +static inline u32 idma64_readl(struct idma64 *idma64, int offset) +{ + return readl(idma64->regs + offset); +} + +static inline void idma64_writel(struct idma64 *idma64, int offset, u32 value) +{ + writel(value, idma64->regs + offset); +} + +#define dma_readl(idma64, reg) \ + idma64_readl(idma64, IDMA64_##reg) +#define dma_writel(idma64, reg, value) \ + idma64_writel(idma64, IDMA64_##reg, (value)) + +/** + * struct idma64_chip - representation of DesignWare DMA controller hardware + * @dev: struct device of the DMA controller + * @irq: irq line + * @regs: memory mapped I/O space + * @idma64: struct idma64 that is filed by idma64_probe() + */ +struct idma64_chip { + struct device *dev; + int irq; + void __iomem *regs; + struct idma64 *idma64; +}; + +#endif /* __DMA_IDMA64_H__ */ -- GitLab From 4b45efe8526359a11ca60a299bef3aebf413fd77 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 27 Jul 2015 18:04:03 +0300 Subject: [PATCH 1883/7006] mfd: Add support for Intel Sunrisepoint LPSS devices The new coming Intel platforms such as Skylake will contain Sunrisepoint PCH. The main difference to the previous platforms is that the LPSS devices are compound devices where usually main (SPI, HSUART, or I2C) and DMA IPs are present. This patch brings the driver for such devices found on Sunrisepoint PCH. Signed-off-by: Mika Westerberg Signed-off-by: Andy Shevchenko Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 23 ++ drivers/mfd/Makefile | 3 + drivers/mfd/intel-lpss-acpi.c | 84 ++++++ drivers/mfd/intel-lpss-pci.c | 113 ++++++++ drivers/mfd/intel-lpss.c | 524 ++++++++++++++++++++++++++++++++++ drivers/mfd/intel-lpss.h | 62 ++++ 6 files changed, 809 insertions(+) create mode 100644 drivers/mfd/intel-lpss-acpi.c create mode 100644 drivers/mfd/intel-lpss-pci.c create mode 100644 drivers/mfd/intel-lpss.c create mode 100644 drivers/mfd/intel-lpss.h diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 653815950aa24..268b6dd79accb 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -328,6 +328,29 @@ config INTEL_SOC_PMIC thermal, charger and related power management functions on these systems. +config MFD_INTEL_LPSS + tristate + select COMMON_CLK + select MFD_CORE + +config MFD_INTEL_LPSS_ACPI + tristate "Intel Low Power Subsystem support in ACPI mode" + select MFD_INTEL_LPSS + depends on X86 && ACPI + help + This driver supports Intel Low Power Subsystem (LPSS) devices such as + I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake + PCH) in ACPI mode. + +config MFD_INTEL_LPSS_PCI + tristate "Intel Low Power Subsystem support in PCI mode" + select MFD_INTEL_LPSS + depends on X86 && PCI + help + This driver supports Intel Low Power Subsystem (LPSS) devices such as + I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake + PCH) in PCI mode. + config MFD_INTEL_MSIC bool "Intel MSIC" depends on INTEL_SCU_IPC diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index ea40e076cb61b..9d730a2d18781 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -161,6 +161,9 @@ obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o obj-$(CONFIG_MFD_TPS65090) += tps65090.o obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o +obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o +obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o +obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o obj-$(CONFIG_MFD_PALMAS) += palmas.o obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o diff --git a/drivers/mfd/intel-lpss-acpi.c b/drivers/mfd/intel-lpss-acpi.c new file mode 100644 index 0000000000000..0d92d73bfa0ea --- /dev/null +++ b/drivers/mfd/intel-lpss-acpi.c @@ -0,0 +1,84 @@ +/* + * Intel LPSS ACPI support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "intel-lpss.h" + +static const struct intel_lpss_platform_info spt_info = { + .clk_rate = 120000000, +}; + +static const struct acpi_device_id intel_lpss_acpi_ids[] = { + /* SPT */ + { "INT3446", (kernel_ulong_t)&spt_info }, + { "INT3447", (kernel_ulong_t)&spt_info }, + { } +}; +MODULE_DEVICE_TABLE(acpi, intel_lpss_acpi_ids); + +static int intel_lpss_acpi_probe(struct platform_device *pdev) +{ + struct intel_lpss_platform_info *info; + const struct acpi_device_id *id; + + id = acpi_match_device(intel_lpss_acpi_ids, &pdev->dev); + if (!id) + return -ENODEV; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + info->irq = platform_get_irq(pdev, 0); + + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); + + return intel_lpss_probe(&pdev->dev, info); +} + +static int intel_lpss_acpi_remove(struct platform_device *pdev) +{ + intel_lpss_remove(&pdev->dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static INTEL_LPSS_PM_OPS(intel_lpss_acpi_pm_ops); + +static struct platform_driver intel_lpss_acpi_driver = { + .probe = intel_lpss_acpi_probe, + .remove = intel_lpss_acpi_remove, + .driver = { + .name = "intel-lpss", + .acpi_match_table = intel_lpss_acpi_ids, + .pm = &intel_lpss_acpi_pm_ops, + }, +}; + +module_platform_driver(intel_lpss_acpi_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel LPSS ACPI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c new file mode 100644 index 0000000000000..9236dffeb4d6b --- /dev/null +++ b/drivers/mfd/intel-lpss-pci.c @@ -0,0 +1,113 @@ +/* + * Intel LPSS PCI support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "intel-lpss.h" + +static int intel_lpss_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct intel_lpss_platform_info *info; + int ret; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + info = devm_kmemdup(&pdev->dev, (void *)id->driver_data, sizeof(*info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->mem = &pdev->resource[0]; + info->irq = pdev->irq; + + /* Probably it is enough to set this for iDMA capable devices only */ + pci_set_master(pdev); + + ret = intel_lpss_probe(&pdev->dev, info); + if (ret) + return ret; + + pm_runtime_put(&pdev->dev); + pm_runtime_allow(&pdev->dev); + + return 0; +} + +static void intel_lpss_pci_remove(struct pci_dev *pdev) +{ + pm_runtime_forbid(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + intel_lpss_remove(&pdev->dev); +} + +static INTEL_LPSS_PM_OPS(intel_lpss_pci_pm_ops); + +static const struct intel_lpss_platform_info spt_info = { + .clk_rate = 120000000, +}; + +static const struct intel_lpss_platform_info spt_uart_info = { + .clk_rate = 120000000, + .clk_con_id = "baudclk", +}; + +static const struct pci_device_id intel_lpss_pci_ids[] = { + /* SPT-LP */ + { PCI_VDEVICE(INTEL, 0x9d27), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9d28), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0x9d29), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d2a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d60), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d61), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d62), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d63), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d64), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d65), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0x9d66), (kernel_ulong_t)&spt_uart_info }, + /* SPT-H */ + { PCI_VDEVICE(INTEL, 0xa127), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa128), (kernel_ulong_t)&spt_uart_info }, + { PCI_VDEVICE(INTEL, 0xa129), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa12a), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa160), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa161), (kernel_ulong_t)&spt_info }, + { PCI_VDEVICE(INTEL, 0xa166), (kernel_ulong_t)&spt_uart_info }, + { } +}; +MODULE_DEVICE_TABLE(pci, intel_lpss_pci_ids); + +static struct pci_driver intel_lpss_pci_driver = { + .name = "intel-lpss", + .id_table = intel_lpss_pci_ids, + .probe = intel_lpss_pci_probe, + .remove = intel_lpss_pci_remove, + .driver = { + .pm = &intel_lpss_pci_pm_ops, + }, +}; + +module_pci_driver(intel_lpss_pci_driver); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_DESCRIPTION("Intel LPSS PCI driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-lpss.c b/drivers/mfd/intel-lpss.c new file mode 100644 index 0000000000000..fdf4d5c1add24 --- /dev/null +++ b/drivers/mfd/intel-lpss.c @@ -0,0 +1,524 @@ +/* + * Intel Sunrisepoint LPSS core support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * Heikki Krogerus + * Jarkko Nikula + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "intel-lpss.h" + +#define LPSS_DEV_OFFSET 0x000 +#define LPSS_DEV_SIZE 0x200 +#define LPSS_PRIV_OFFSET 0x200 +#define LPSS_PRIV_SIZE 0x100 +#define LPSS_IDMA64_OFFSET 0x800 +#define LPSS_IDMA64_SIZE 0x800 + +/* Offsets from lpss->priv */ +#define LPSS_PRIV_RESETS 0x04 +#define LPSS_PRIV_RESETS_FUNC BIT(2) +#define LPSS_PRIV_RESETS_IDMA 0x3 + +#define LPSS_PRIV_ACTIVELTR 0x10 +#define LPSS_PRIV_IDLELTR 0x14 + +#define LPSS_PRIV_LTR_REQ BIT(15) +#define LPSS_PRIV_LTR_SCALE_MASK 0xc00 +#define LPSS_PRIV_LTR_SCALE_1US 0x800 +#define LPSS_PRIV_LTR_SCALE_32US 0xc00 +#define LPSS_PRIV_LTR_VALUE_MASK 0x3ff + +#define LPSS_PRIV_SSP_REG 0x20 +#define LPSS_PRIV_SSP_REG_DIS_DMA_FIN BIT(0) + +#define LPSS_PRIV_REMAP_ADDR_LO 0x40 +#define LPSS_PRIV_REMAP_ADDR_HI 0x44 + +#define LPSS_PRIV_CAPS 0xfc +#define LPSS_PRIV_CAPS_NO_IDMA BIT(8) +#define LPSS_PRIV_CAPS_TYPE_SHIFT 4 +#define LPSS_PRIV_CAPS_TYPE_MASK (0xf << LPSS_PRIV_CAPS_TYPE_SHIFT) + +/* This matches the type field in CAPS register */ +enum intel_lpss_dev_type { + LPSS_DEV_I2C = 0, + LPSS_DEV_UART, + LPSS_DEV_SPI, +}; + +struct intel_lpss { + const struct intel_lpss_platform_info *info; + enum intel_lpss_dev_type type; + struct clk *clk; + struct clk_lookup *clock; + const struct mfd_cell *cell; + struct device *dev; + void __iomem *priv; + int devid; + u32 caps; + u32 active_ltr; + u32 idle_ltr; + struct dentry *debugfs; +}; + +static const struct resource intel_lpss_dev_resources[] = { + DEFINE_RES_MEM_NAMED(LPSS_DEV_OFFSET, LPSS_DEV_SIZE, "lpss_dev"), + DEFINE_RES_MEM_NAMED(LPSS_PRIV_OFFSET, LPSS_PRIV_SIZE, "lpss_priv"), + DEFINE_RES_IRQ(0), +}; + +static const struct resource intel_lpss_idma64_resources[] = { + DEFINE_RES_MEM(LPSS_IDMA64_OFFSET, LPSS_IDMA64_SIZE), + DEFINE_RES_IRQ(0), +}; + +#define LPSS_IDMA64_DRIVER_NAME "idma64" + +/* + * Cells needs to be ordered so that the iDMA is created first. This is + * because we need to be sure the DMA is available when the host controller + * driver is probed. + */ +static const struct mfd_cell intel_lpss_idma64_cell = { + .name = LPSS_IDMA64_DRIVER_NAME, + .num_resources = ARRAY_SIZE(intel_lpss_idma64_resources), + .resources = intel_lpss_idma64_resources, +}; + +static const struct mfd_cell intel_lpss_i2c_cell = { + .name = "i2c_designware", + .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), + .resources = intel_lpss_dev_resources, +}; + +static const struct mfd_cell intel_lpss_uart_cell = { + .name = "dw-apb-uart", + .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), + .resources = intel_lpss_dev_resources, +}; + +static const struct mfd_cell intel_lpss_spi_cell = { + .name = "pxa2xx-spi", + .num_resources = ARRAY_SIZE(intel_lpss_dev_resources), + .resources = intel_lpss_dev_resources, +}; + +static DEFINE_IDA(intel_lpss_devid_ida); +static struct dentry *intel_lpss_debugfs; + +static int intel_lpss_request_dma_module(const char *name) +{ + static bool intel_lpss_dma_requested; + + if (intel_lpss_dma_requested) + return 0; + + intel_lpss_dma_requested = true; + return request_module("%s", name); +} + +static void intel_lpss_cache_ltr(struct intel_lpss *lpss) +{ + lpss->active_ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); + lpss->idle_ltr = readl(lpss->priv + LPSS_PRIV_IDLELTR); +} + +static int intel_lpss_debugfs_add(struct intel_lpss *lpss) +{ + struct dentry *dir; + + dir = debugfs_create_dir(dev_name(lpss->dev), intel_lpss_debugfs); + if (IS_ERR(dir)) + return PTR_ERR(dir); + + /* Cache the values into lpss structure */ + intel_lpss_cache_ltr(lpss); + + debugfs_create_x32("capabilities", S_IRUGO, dir, &lpss->caps); + debugfs_create_x32("active_ltr", S_IRUGO, dir, &lpss->active_ltr); + debugfs_create_x32("idle_ltr", S_IRUGO, dir, &lpss->idle_ltr); + + lpss->debugfs = dir; + return 0; +} + +static void intel_lpss_debugfs_remove(struct intel_lpss *lpss) +{ + debugfs_remove_recursive(lpss->debugfs); +} + +static void intel_lpss_ltr_set(struct device *dev, s32 val) +{ + struct intel_lpss *lpss = dev_get_drvdata(dev); + u32 ltr; + + /* + * Program latency tolerance (LTR) accordingly what has been asked + * by the PM QoS layer or disable it in case we were passed + * negative value or PM_QOS_LATENCY_ANY. + */ + ltr = readl(lpss->priv + LPSS_PRIV_ACTIVELTR); + + if (val == PM_QOS_LATENCY_ANY || val < 0) { + ltr &= ~LPSS_PRIV_LTR_REQ; + } else { + ltr |= LPSS_PRIV_LTR_REQ; + ltr &= ~LPSS_PRIV_LTR_SCALE_MASK; + ltr &= ~LPSS_PRIV_LTR_VALUE_MASK; + + if (val > LPSS_PRIV_LTR_VALUE_MASK) + ltr |= LPSS_PRIV_LTR_SCALE_32US | val >> 5; + else + ltr |= LPSS_PRIV_LTR_SCALE_1US | val; + } + + if (ltr == lpss->active_ltr) + return; + + writel(ltr, lpss->priv + LPSS_PRIV_ACTIVELTR); + writel(ltr, lpss->priv + LPSS_PRIV_IDLELTR); + + /* Cache the values into lpss structure */ + intel_lpss_cache_ltr(lpss); +} + +static void intel_lpss_ltr_expose(struct intel_lpss *lpss) +{ + lpss->dev->power.set_latency_tolerance = intel_lpss_ltr_set; + dev_pm_qos_expose_latency_tolerance(lpss->dev); +} + +static void intel_lpss_ltr_hide(struct intel_lpss *lpss) +{ + dev_pm_qos_hide_latency_tolerance(lpss->dev); + lpss->dev->power.set_latency_tolerance = NULL; +} + +static int intel_lpss_assign_devs(struct intel_lpss *lpss) +{ + unsigned int type; + + type = lpss->caps & LPSS_PRIV_CAPS_TYPE_MASK; + type >>= LPSS_PRIV_CAPS_TYPE_SHIFT; + + switch (type) { + case LPSS_DEV_I2C: + lpss->cell = &intel_lpss_i2c_cell; + break; + case LPSS_DEV_UART: + lpss->cell = &intel_lpss_uart_cell; + break; + case LPSS_DEV_SPI: + lpss->cell = &intel_lpss_spi_cell; + break; + default: + return -ENODEV; + } + + lpss->type = type; + + return 0; +} + +static bool intel_lpss_has_idma(const struct intel_lpss *lpss) +{ + return (lpss->caps & LPSS_PRIV_CAPS_NO_IDMA) == 0; +} + +static void intel_lpss_set_remap_addr(const struct intel_lpss *lpss) +{ + resource_size_t addr = lpss->info->mem->start; + + writel(addr, lpss->priv + LPSS_PRIV_REMAP_ADDR_LO); +#if BITS_PER_LONG > 32 + writel(addr >> 32, lpss->priv + LPSS_PRIV_REMAP_ADDR_HI); +#else + writel(0, lpss->priv + LPSS_PRIV_REMAP_ADDR_HI); +#endif +} + +static void intel_lpss_deassert_reset(const struct intel_lpss *lpss) +{ + u32 value = LPSS_PRIV_RESETS_FUNC | LPSS_PRIV_RESETS_IDMA; + + /* Bring out the device from reset */ + writel(value, lpss->priv + LPSS_PRIV_RESETS); +} + +static void intel_lpss_init_dev(const struct intel_lpss *lpss) +{ + u32 value = LPSS_PRIV_SSP_REG_DIS_DMA_FIN; + + intel_lpss_deassert_reset(lpss); + + if (!intel_lpss_has_idma(lpss)) + return; + + intel_lpss_set_remap_addr(lpss); + + /* Make sure that SPI multiblock DMA transfers are re-enabled */ + if (lpss->type == LPSS_DEV_SPI) + writel(value, lpss->priv + LPSS_PRIV_SSP_REG); +} + +static void intel_lpss_unregister_clock_tree(struct clk *clk) +{ + struct clk *parent; + + while (clk) { + parent = clk_get_parent(clk); + clk_unregister(clk); + clk = parent; + } +} + +static int intel_lpss_register_clock_divider(struct intel_lpss *lpss, + const char *devname, + struct clk **clk) +{ + char name[32]; + struct clk *tmp = *clk; + + snprintf(name, sizeof(name), "%s-enable", devname); + tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), 0, + lpss->priv, 0, 0, NULL); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + snprintf(name, sizeof(name), "%s-div", devname); + tmp = clk_register_fractional_divider(NULL, name, __clk_get_name(tmp), + 0, lpss->priv, 1, 15, 16, 15, 0, + NULL); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + *clk = tmp; + + snprintf(name, sizeof(name), "%s-update", devname); + tmp = clk_register_gate(NULL, name, __clk_get_name(tmp), + CLK_SET_RATE_PARENT, lpss->priv, 31, 0, NULL); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + *clk = tmp; + + return 0; +} + +static int intel_lpss_register_clock(struct intel_lpss *lpss) +{ + const struct mfd_cell *cell = lpss->cell; + struct clk *clk; + char devname[24]; + int ret; + + if (!lpss->info->clk_rate) + return 0; + + /* Root clock */ + clk = clk_register_fixed_rate(NULL, dev_name(lpss->dev), NULL, + CLK_IS_ROOT, lpss->info->clk_rate); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + snprintf(devname, sizeof(devname), "%s.%d", cell->name, lpss->devid); + + /* + * Support for clock divider only if it has some preset value. + * Otherwise we assume that the divider is not used. + */ + if (lpss->type != LPSS_DEV_I2C) { + ret = intel_lpss_register_clock_divider(lpss, devname, &clk); + if (ret) + goto err_clk_register; + } + + ret = -ENOMEM; + + /* Clock for the host controller */ + lpss->clock = clkdev_create(clk, lpss->info->clk_con_id, "%s", devname); + if (!lpss->clock) + goto err_clk_register; + + lpss->clk = clk; + + return 0; + +err_clk_register: + intel_lpss_unregister_clock_tree(clk); + + return ret; +} + +static void intel_lpss_unregister_clock(struct intel_lpss *lpss) +{ + if (IS_ERR_OR_NULL(lpss->clk)) + return; + + clkdev_drop(lpss->clock); + intel_lpss_unregister_clock_tree(lpss->clk); +} + +int intel_lpss_probe(struct device *dev, + const struct intel_lpss_platform_info *info) +{ + struct intel_lpss *lpss; + int ret; + + if (!info || !info->mem || info->irq <= 0) + return -EINVAL; + + lpss = devm_kzalloc(dev, sizeof(*lpss), GFP_KERNEL); + if (!lpss) + return -ENOMEM; + + lpss->priv = devm_ioremap(dev, info->mem->start + LPSS_PRIV_OFFSET, + LPSS_PRIV_SIZE); + if (!lpss->priv) + return -ENOMEM; + + lpss->info = info; + lpss->dev = dev; + lpss->caps = readl(lpss->priv + LPSS_PRIV_CAPS); + + dev_set_drvdata(dev, lpss); + + ret = intel_lpss_assign_devs(lpss); + if (ret) + return ret; + + intel_lpss_init_dev(lpss); + + lpss->devid = ida_simple_get(&intel_lpss_devid_ida, 0, 0, GFP_KERNEL); + if (lpss->devid < 0) + return lpss->devid; + + ret = intel_lpss_register_clock(lpss); + if (ret) + goto err_clk_register; + + intel_lpss_ltr_expose(lpss); + + ret = intel_lpss_debugfs_add(lpss); + if (ret) + dev_warn(dev, "Failed to create debugfs entries\n"); + + if (intel_lpss_has_idma(lpss)) { + /* + * Ensure the DMA driver is loaded before the host + * controller device appears, so that the host controller + * driver can request its DMA channels as early as + * possible. + * + * If the DMA module is not there that's OK as well. + */ + intel_lpss_request_dma_module(LPSS_IDMA64_DRIVER_NAME); + + ret = mfd_add_devices(dev, lpss->devid, &intel_lpss_idma64_cell, + 1, info->mem, info->irq, NULL); + if (ret) + dev_warn(dev, "Failed to add %s, fallback to PIO\n", + LPSS_IDMA64_DRIVER_NAME); + } + + ret = mfd_add_devices(dev, lpss->devid, lpss->cell, + 1, info->mem, info->irq, NULL); + if (ret) + goto err_remove_ltr; + + return 0; + +err_remove_ltr: + intel_lpss_debugfs_remove(lpss); + intel_lpss_ltr_hide(lpss); + +err_clk_register: + ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); + + return ret; +} +EXPORT_SYMBOL_GPL(intel_lpss_probe); + +void intel_lpss_remove(struct device *dev) +{ + struct intel_lpss *lpss = dev_get_drvdata(dev); + + mfd_remove_devices(dev); + intel_lpss_debugfs_remove(lpss); + intel_lpss_ltr_hide(lpss); + intel_lpss_unregister_clock(lpss); + ida_simple_remove(&intel_lpss_devid_ida, lpss->devid); +} +EXPORT_SYMBOL_GPL(intel_lpss_remove); + +static int resume_lpss_device(struct device *dev, void *data) +{ + pm_runtime_resume(dev); + return 0; +} + +int intel_lpss_prepare(struct device *dev) +{ + /* + * Resume both child devices before entering system sleep. This + * ensures that they are in proper state before they get suspended. + */ + device_for_each_child_reverse(dev, NULL, resume_lpss_device); + return 0; +} +EXPORT_SYMBOL_GPL(intel_lpss_prepare); + +int intel_lpss_suspend(struct device *dev) +{ + return 0; +} +EXPORT_SYMBOL_GPL(intel_lpss_suspend); + +int intel_lpss_resume(struct device *dev) +{ + struct intel_lpss *lpss = dev_get_drvdata(dev); + + intel_lpss_init_dev(lpss); + + return 0; +} +EXPORT_SYMBOL_GPL(intel_lpss_resume); + +static int __init intel_lpss_init(void) +{ + intel_lpss_debugfs = debugfs_create_dir("intel_lpss", NULL); + return 0; +} +module_init(intel_lpss_init); + +static void __exit intel_lpss_exit(void) +{ + debugfs_remove(intel_lpss_debugfs); +} +module_exit(intel_lpss_exit); + +MODULE_AUTHOR("Andy Shevchenko "); +MODULE_AUTHOR("Mika Westerberg "); +MODULE_AUTHOR("Heikki Krogerus "); +MODULE_AUTHOR("Jarkko Nikula "); +MODULE_DESCRIPTION("Intel LPSS core driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/mfd/intel-lpss.h b/drivers/mfd/intel-lpss.h new file mode 100644 index 0000000000000..f28cb28a62f87 --- /dev/null +++ b/drivers/mfd/intel-lpss.h @@ -0,0 +1,62 @@ +/* + * Intel LPSS core support. + * + * Copyright (C) 2015, Intel Corporation + * + * Authors: Andy Shevchenko + * Mika Westerberg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __MFD_INTEL_LPSS_H +#define __MFD_INTEL_LPSS_H + +struct device; +struct resource; + +struct intel_lpss_platform_info { + struct resource *mem; + int irq; + unsigned long clk_rate; + const char *clk_con_id; +}; + +int intel_lpss_probe(struct device *dev, + const struct intel_lpss_platform_info *info); +void intel_lpss_remove(struct device *dev); + +#ifdef CONFIG_PM +int intel_lpss_prepare(struct device *dev); +int intel_lpss_suspend(struct device *dev); +int intel_lpss_resume(struct device *dev); + +#ifdef CONFIG_PM_SLEEP +#define INTEL_LPSS_SLEEP_PM_OPS \ + .prepare = intel_lpss_prepare, \ + .suspend = intel_lpss_suspend, \ + .resume = intel_lpss_resume, \ + .freeze = intel_lpss_suspend, \ + .thaw = intel_lpss_resume, \ + .poweroff = intel_lpss_suspend, \ + .restore = intel_lpss_resume, +#endif + +#define INTEL_LPSS_RUNTIME_PM_OPS \ + .runtime_suspend = intel_lpss_suspend, \ + .runtime_resume = intel_lpss_resume, + +#else /* !CONFIG_PM */ +#define INTEL_LPSS_SLEEP_PM_OPS +#define INTEL_LPSS_RUNTIME_PM_OPS +#endif /* CONFIG_PM */ + +#define INTEL_LPSS_PM_OPS(name) \ +const struct dev_pm_ops name = { \ + INTEL_LPSS_SLEEP_PM_OPS \ + INTEL_LPSS_RUNTIME_PM_OPS \ +} + +#endif /* __MFD_INTEL_LPSS_H */ -- GitLab From 9458120ea112c06f56ea1b75a1511815d36aecc2 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 27 Jul 2015 15:55:22 -0500 Subject: [PATCH 1884/7006] pinctrl: kill off set_irq_flags usage set_irq_flags is ARM specific with custom flags which have genirq equivalents. Convert drivers to use the genirq interfaces directly, so we can kill off set_irq_flags. The translation of flags is as follows: IRQF_VALID -> !IRQ_NOREQUEST IRQF_PROBE -> !IRQ_NOPROBE IRQF_NOAUTOEN -> IRQ_NOAUTOEN For IRQs managed by an irqdomain, the irqdomain core code handles clearing and setting IRQ_NOREQUEST already, so there is no need to do this in .map() functions and we can simply remove the set_irq_flags calls. Some users also modify IRQ_NOPROBE and this has been maintained although it is not clear that is really needed. There appears to be a great deal of blind copy and paste of this code. Signed-off-by: Rob Herring Cc: Stephen Warren Cc: Lee Jones Cc: Matthias Brugger Cc: Tomasz Figa Cc: Thomas Abraham Cc: Kukjin Kim Cc: Krzysztof Kozlowski Cc: linux-gpio@vger.kernel.org Cc: linux-rpi-kernel@lists.infradead.org Cc: linux-arm-kernel@lists.infradead.org Cc: linux-mediatek@lists.infradead.org Cc: linux-samsung-soc@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 1 - drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 2 -- drivers/pinctrl/pinctrl-single.c | 5 ----- drivers/pinctrl/samsung/pinctrl-exynos.c | 1 - drivers/pinctrl/samsung/pinctrl-exynos5440.c | 1 - drivers/pinctrl/samsung/pinctrl-s3c24xx.c | 2 -- drivers/pinctrl/samsung/pinctrl-s3c64xx.c | 2 -- 7 files changed, 14 deletions(-) diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index 104d8a63bbce7..f4d0168d814e1 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -987,7 +987,6 @@ static int bcm2835_pinctrl_probe(struct platform_device *pdev) irq_set_chip_and_handler(irq, &bcm2835_gpio_irq_chip, handle_level_irq); irq_set_chip_data(irq, pc); - set_irq_flags(irq, IRQF_VALID); } for (i = 0; i < BCM2835_NUM_BANKS; i++) { diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 4be0124e99361..0350a807da1a8 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1348,11 +1348,9 @@ int mtk_pctrl_init(struct platform_device *pdev, irq_set_chip_and_handler(virq, &mtk_pinctrl_irq_chip, handle_level_irq); irq_set_chip_data(virq, pctl); - set_irq_flags(virq, IRQF_VALID); }; irq_set_chained_handler_and_data(irq, mtk_eint_irq_handler, pctl); - set_irq_flags(irq, IRQF_VALID); return 0; chip_error: diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index b8aaf9559dddb..e99cabe33696a 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -1716,12 +1716,7 @@ static int pcs_irqdomain_map(struct irq_domain *d, unsigned int irq, irq_set_chip_data(irq, pcs_soc); irq_set_chip_and_handler(irq, &pcs->chip, handle_level_irq); - -#ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); -#else irq_set_noprobe(irq); -#endif return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c index 07773c70c12cf..5f45caaef46d6 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos.c @@ -256,7 +256,6 @@ static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, b); irq_set_chip_and_handler(virq, &b->irq_chip->chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-exynos5440.c b/drivers/pinctrl/samsung/pinctrl-exynos5440.c index 5574b8ae59497..9ce0b8619d4c6 100644 --- a/drivers/pinctrl/samsung/pinctrl-exynos5440.c +++ b/drivers/pinctrl/samsung/pinctrl-exynos5440.c @@ -894,7 +894,6 @@ static int exynos5440_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_data(virq, d); irq_set_chip_and_handler(virq, &exynos5440_gpio_irq_chip, handle_level_irq); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c index 5d7b6112fc7e4..019844d479bb5 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c @@ -437,7 +437,6 @@ static int s3c24xx_gpf_irq_map(struct irq_domain *h, unsigned int virq, handle_edge_irq); } irq_set_chip_data(virq, bank); - set_irq_flags(virq, IRQF_VALID); return 0; } @@ -457,7 +456,6 @@ static int s3c24xx_gpg_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &s3c24xx_eint_chip, handle_edge_irq); irq_set_chip_data(virq, bank); - set_irq_flags(virq, IRQF_VALID); return 0; } diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c index 8700f0c9eee15..f5ea40a69711c 100644 --- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c +++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c @@ -395,7 +395,6 @@ static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &s3c64xx_gpio_irq_chip, handle_level_irq); irq_set_chip_data(virq, bank); - set_irq_flags(virq, IRQF_VALID); return 0; } @@ -671,7 +670,6 @@ static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq, irq_set_chip_and_handler(virq, &s3c64xx_eint0_irq_chip, handle_level_irq); irq_set_chip_data(virq, ddata); - set_irq_flags(virq, IRQF_VALID); return 0; } -- GitLab From dc9ab949950352d716a6608343d7076cc1589498 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 28 Jul 2015 17:21:47 +0900 Subject: [PATCH 1885/7006] MAINTAINERS: pinctrl: Move Thomas Abraham to CREDITS Thomas Abraham's Linaro email address bounces for several months. Also there were no replies for several emails sent on LKML to his Samsung address. Move his name to CREDITS. Signed-off-by: Krzysztof Kozlowski Cc: Tomasz Figa Cc: Thomas Abraham Cc: Linus Walleij Link: http://lkml.org/lkml/2015/6/15/15 Signed-off-by: Linus Walleij --- CREDITS | 4 ++++ MAINTAINERS | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CREDITS b/CREDITS index 1d616640bbf64..674e55bca4309 100644 --- a/CREDITS +++ b/CREDITS @@ -20,6 +20,10 @@ D: One of assisting postmasters for vger.kernel.org's lists S: (ask for current address) S: Finland +N: Thomas Abraham +E: thomas.ab@samsung.com +D: Samsung pin controller driver + N: Dragos Acostachioaie E: dragos@iname.com W: http://www.arbornet.org/~dragos diff --git a/MAINTAINERS b/MAINTAINERS index fd60784430838..e138a3620978d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7988,7 +7988,6 @@ F: drivers/pinctrl/sh-pfc/ PIN CONTROLLER - SAMSUNG M: Tomasz Figa -M: Thomas Abraham L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) S: Maintained -- GitLab From c53e0baa6f34b7051790e0fba9d782ec4efe58bd Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Tue, 28 Jul 2015 10:31:06 +0100 Subject: [PATCH 1886/7006] arm64: mm: mark create_mapping as __init Currently create_mapping is marked with __ref, apparently because it refers to early_alloc. However, create_mapping has no logic to prevent erroneous use of early_alloc after it has been freed, and is only ever called by __init functions anyway. Thus the __ref marker is misleading and unnecessary. Instead, this patch marks create_mapping as __init, resulting in warnings if it is used from a a non __init functions, and allowing its memory to be reclaimed. Signed-off-by: Mark Rutland Cc: Catalin Marinas Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/mm/mmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c index 63012fed46fc0..9211b8527f258 100644 --- a/arch/arm64/mm/mmu.c +++ b/arch/arm64/mm/mmu.c @@ -267,7 +267,7 @@ static void *late_alloc(unsigned long size) return ptr; } -static void __ref create_mapping(phys_addr_t phys, unsigned long virt, +static void __init create_mapping(phys_addr_t phys, unsigned long virt, phys_addr_t size, pgprot_t prot) { if (virt < VMALLOC_START) { -- GitLab From da4e73303e448aa23b36249a85e239ca118ce941 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Fri, 24 Jul 2015 09:59:55 +0100 Subject: [PATCH 1887/7006] arm64: Clean up __flush_tlb(_kernel)_range functions This patch moves the MAX_TLB_RANGE check into the flush_tlb(_kernel)_range functions directly to avoid the undescore-prefixed definitions (and for consistency with a subsequent patch). Signed-off-by: Catalin Marinas Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/include/asm/tlbflush.h | 47 ++++++++++++++----------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index 7fedfa787a642..e972bf4565580 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -91,11 +91,23 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, dsb(ish); } -static inline void __flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) +/* + * This is meant to avoid soft lock-ups on large TLB flushing ranges and not + * necessarily a performance improvement. + */ +#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT) + +static inline void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) { unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48; unsigned long addr; + + if ((end - start) > MAX_TLB_RANGE) { + flush_tlb_mm(vma->vm_mm); + return; + } + start = asid | (start >> 12); end = asid | (end >> 12); @@ -105,9 +117,15 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, dsb(ish); } -static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long end) +static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) { unsigned long addr; + + if ((end - start) > MAX_TLB_RANGE) { + flush_tlb_all(); + return; + } + start >>= 12; end >>= 12; @@ -118,29 +136,6 @@ static inline void __flush_tlb_kernel_range(unsigned long start, unsigned long e isb(); } -/* - * This is meant to avoid soft lock-ups on large TLB flushing ranges and not - * necessarily a performance improvement. - */ -#define MAX_TLB_RANGE (1024UL << PAGE_SHIFT) - -static inline void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ - if ((end - start) <= MAX_TLB_RANGE) - __flush_tlb_range(vma, start, end); - else - flush_tlb_mm(vma->vm_mm); -} - -static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) -{ - if ((end - start) <= MAX_TLB_RANGE) - __flush_tlb_kernel_range(start, end); - else - flush_tlb_all(); -} - /* * Used to invalidate the TLB (walk caches) corresponding to intermediate page * table levels (pgd/pud/pmd). -- GitLab From 4150e50bf5f2171fbe7dfdbc7f2cdf44676b79a4 Mon Sep 17 00:00:00 2001 From: Catalin Marinas Date: Wed, 18 Mar 2015 11:28:06 +0000 Subject: [PATCH 1888/7006] arm64: Use last level TLBI for user pte changes The flush_tlb_page() function is used on user address ranges when PTEs (or PMDs/PUDs for huge pages) were changed (attributes or clearing). For such cases, it is more efficient to invalidate only the last level of the TLB with the "tlbi vale1is" instruction. In the TLB shoot-down case, the TLB caching of the intermediate page table levels (pmd, pud, pgd) is handled by __flush_tlb_pgtable() via the __(pte|pmd|pud)_free_tlb() functions and it is not deferred to tlb_finish_mmu() (as of commit 285994a62c80 - "arm64: Invalidate the TLB corresponding to intermediate page table levels"). The tlb_flush() function only needs to invalidate the TLB for the last level of page tables; the __flush_tlb_range() function gains a fourth argument for last level TLBI. Signed-off-by: Catalin Marinas Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/include/asm/tlb.h | 7 ++++++- arch/arm64/include/asm/tlbflush.h | 21 ++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h index 3a0242c7eb8da..d6e6b66603803 100644 --- a/arch/arm64/include/asm/tlb.h +++ b/arch/arm64/include/asm/tlb.h @@ -41,7 +41,12 @@ static inline void tlb_flush(struct mmu_gather *tlb) flush_tlb_mm(tlb->mm); } else { struct vm_area_struct vma = { .vm_mm = tlb->mm, }; - flush_tlb_range(&vma, tlb->start, tlb->end); + /* + * The intermediate page table levels are already handled by + * the __(pte|pmd|pud)_free_tlb() functions, so last level + * TLBI is sufficient here. + */ + __flush_tlb_range(&vma, tlb->start, tlb->end, true); } } diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index e972bf4565580..7bd2da021658a 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -87,7 +87,7 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, ((unsigned long)ASID(vma->vm_mm) << 48); dsb(ishst); - asm("tlbi vae1is, %0" : : "r" (addr)); + asm("tlbi vale1is, %0" : : "r" (addr)); dsb(ish); } @@ -97,8 +97,9 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, */ #define MAX_TLB_RANGE (1024UL << PAGE_SHIFT) -static inline void flush_tlb_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end) +static inline void __flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end, + bool last_level) { unsigned long asid = (unsigned long)ASID(vma->vm_mm) << 48; unsigned long addr; @@ -112,11 +113,21 @@ static inline void flush_tlb_range(struct vm_area_struct *vma, end = asid | (end >> 12); dsb(ishst); - for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) - asm("tlbi vae1is, %0" : : "r"(addr)); + for (addr = start; addr < end; addr += 1 << (PAGE_SHIFT - 12)) { + if (last_level) + asm("tlbi vale1is, %0" : : "r"(addr)); + else + asm("tlbi vae1is, %0" : : "r"(addr)); + } dsb(ish); } +static inline void flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end) +{ + __flush_tlb_range(vma, start, end, false); +} + static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) { unsigned long addr; -- GitLab From 3b9a02e844948fc14cb32a06bc00e0e61bde3577 Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Mon, 27 Jul 2015 11:47:38 +0200 Subject: [PATCH 1889/7006] drm/i915: Fake AGP is dead Remove the leftovers, yay! AGP for i915 kms died long ago with commit 3bb6ce66866310f50d461b9eff949c1ce95560ce Author: Daniel Vetter Date: Wed Nov 13 22:14:16 2013 +0100 drm/i915: Kill legeacy AGP for gen3 kms and with ums now gone to there's really no users any more. Note that device_is_agp is only called when DRIVER_USE_AGP is set and since we've unconditionally cleared that since a while there are really no users left for i915_driver_device_is_agp. Reviewed-by: Chris Wilson Signed-off-by: Daniel Vetter --- drivers/gpu/drm/i915/i915_dma.c | 10 ---------- drivers/gpu/drm/i915/i915_drv.c | 4 ---- drivers/gpu/drm/i915/i915_drv.h | 1 - 3 files changed, 15 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c index b1f9e5561cf2c..ab37d1121be82 100644 --- a/drivers/gpu/drm/i915/i915_dma.c +++ b/drivers/gpu/drm/i915/i915_dma.c @@ -1274,13 +1274,3 @@ const struct drm_ioctl_desc i915_ioctls[] = { }; int i915_max_ioctl = ARRAY_SIZE(i915_ioctls); - -/* - * This is really ugly: Because old userspace abused the linux agp interface to - * manage the gtt, we need to claim that all intel devices are agp. For - * otherwise the drm core refuses to initialize the agp support code. - */ -int i915_driver_device_is_agp(struct drm_device *dev) -{ - return 1; -} diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 0d6775a3e88c3..151263b433e65 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -935,8 +935,6 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (PCI_FUNC(pdev->devfn)) return -ENODEV; - driver.driver_features &= ~(DRIVER_USE_AGP); - return drm_get_pci_dev(pdev, ent, &driver); } @@ -1649,7 +1647,6 @@ static struct drm_driver driver = { * deal with them for Intel hardware. */ .driver_features = - DRIVER_USE_AGP | DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME | DRIVER_RENDER, .load = i915_driver_load, @@ -1664,7 +1661,6 @@ static struct drm_driver driver = { .suspend = i915_suspend_legacy, .resume = i915_resume_legacy, - .device_is_agp = i915_driver_device_is_agp, #if defined(CONFIG_DEBUG_FS) .debugfs_init = i915_debugfs_init, .debugfs_cleanup = i915_debugfs_cleanup, diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 40fea41affc9e..abd1a8659d833 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2628,7 +2628,6 @@ extern void i915_driver_preclose(struct drm_device *dev, struct drm_file *file); extern void i915_driver_postclose(struct drm_device *dev, struct drm_file *file); -extern int i915_driver_device_is_agp(struct drm_device * dev); #ifdef CONFIG_COMPAT extern long i915_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); -- GitLab From 28355f81969962cf01aef5b13d7de5b4ab0c5f13 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Tue, 14 Jul 2015 10:29:54 +0200 Subject: [PATCH 1890/7006] gpio: defer probe if pinctrl cannot be found When an OF node has a pin range for its GPIOs, return -EPROBE_DEFER if the pin controller isn't available. Otherwise, the GPIO range wouldn't be set at all unless the pin controller probed always before the GPIO chip. With this change, the probe of the GPIO chip will be deferred and will be retried at a later point, hopefully once the pin controller has been registered and probed already. Signed-off-by: Tomeu Vizoso Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib-of.c | 27 ++++++++++++++++++--------- drivers/gpio/gpiolib.c | 5 ++++- include/linux/of_gpio.h | 4 ++-- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c index 1e36ec5e2e0c0..fa6e3c8823d61 100644 --- a/drivers/gpio/gpiolib-of.c +++ b/drivers/gpio/gpiolib-of.c @@ -335,7 +335,7 @@ void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc) EXPORT_SYMBOL(of_mm_gpiochip_remove); #ifdef CONFIG_PINCTRL -static void of_gpiochip_add_pin_range(struct gpio_chip *chip) +static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { struct device_node *np = chip->of_node; struct of_phandle_args pinspec; @@ -346,7 +346,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) struct property *group_names; if (!np) - return; + return 0; group_names = of_find_property(np, group_names_propname, NULL); @@ -358,7 +358,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) pctldev = of_pinctrl_get(pinspec.np); if (!pctldev) - break; + return -EPROBE_DEFER; if (pinspec.args[2]) { if (group_names) { @@ -378,7 +378,7 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) pinspec.args[1], pinspec.args[2]); if (ret) - break; + return ret; } else { /* npins == 0: special range */ if (pinspec.args[1]) { @@ -408,32 +408,41 @@ static void of_gpiochip_add_pin_range(struct gpio_chip *chip) ret = gpiochip_add_pingroup_range(chip, pctldev, pinspec.args[0], name); if (ret) - break; + return ret; } } + + return 0; } #else -static void of_gpiochip_add_pin_range(struct gpio_chip *chip) {} +static int of_gpiochip_add_pin_range(struct gpio_chip *chip) { return 0; } #endif -void of_gpiochip_add(struct gpio_chip *chip) +int of_gpiochip_add(struct gpio_chip *chip) { + int status; + if ((!chip->of_node) && (chip->dev)) chip->of_node = chip->dev->of_node; if (!chip->of_node) - return; + return 0; if (!chip->of_xlate) { chip->of_gpio_n_cells = 2; chip->of_xlate = of_gpio_simple_xlate; } - of_gpiochip_add_pin_range(chip); + status = of_gpiochip_add_pin_range(chip); + if (status) + return status; + of_node_get(chip->of_node); of_gpiochip_scan_hogs(chip); + + return 0; } void of_gpiochip_remove(struct gpio_chip *chip) diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 9312bbcb19b99..1b5b8da71154a 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -290,7 +290,10 @@ int gpiochip_add(struct gpio_chip *chip) if (!chip->owner && chip->dev && chip->dev->driver) chip->owner = chip->dev->driver->owner; - of_gpiochip_add(chip); + status = of_gpiochip_add(chip); + if (status) + goto err_remove_chip; + acpi_gpiochip_add(chip); status = gpiochip_sysfs_register(chip); diff --git a/include/linux/of_gpio.h b/include/linux/of_gpio.h index 69dbe312b11b2..f3191828f0373 100644 --- a/include/linux/of_gpio.h +++ b/include/linux/of_gpio.h @@ -54,7 +54,7 @@ extern int of_mm_gpiochip_add(struct device_node *np, struct of_mm_gpio_chip *mm_gc); extern void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc); -extern void of_gpiochip_add(struct gpio_chip *gc); +extern int of_gpiochip_add(struct gpio_chip *gc); extern void of_gpiochip_remove(struct gpio_chip *gc); extern int of_gpio_simple_xlate(struct gpio_chip *gc, const struct of_phandle_args *gpiospec, @@ -76,7 +76,7 @@ static inline int of_gpio_simple_xlate(struct gpio_chip *gc, return -ENOSYS; } -static inline void of_gpiochip_add(struct gpio_chip *gc) { } +static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; } static inline void of_gpiochip_remove(struct gpio_chip *gc) { } #endif /* CONFIG_OF_GPIO */ -- GitLab From 1051fade4b1fac0de19478b33383b25bd1d24d10 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 25 Jul 2015 11:23:12 +0200 Subject: [PATCH 1891/7006] pinctrl: nomadik: split stn8815 UART0 pin groups Split the UART pin groups so we can activate RX/TX, CTS/RTS and the modem pins (DCD, DSR, RI, DTR) as three different groups with function u0. Signed-off-by: Linus Walleij --- drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c index a2de3b7a57a07..587b222f12f3c 100644 --- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c +++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c @@ -271,9 +271,11 @@ static const struct pinctrl_pin_desc nmk_stn8815_pins[] = { */ /* Altfunction A */ -static const unsigned u0_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5, - STN8815_PIN_C5, STN8815_PIN_A4, STN8815_PIN_B5, STN8815_PIN_D6, - STN8815_PIN_C6, STN8815_PIN_B6 }; +static const unsigned u0txrx_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5 }; +static const unsigned u0ctsrts_a_1_pins[] = { STN8815_PIN_C5, STN8815_PIN_B6 }; +/* Modem pins: DCD, DSR, RI, DTR */ +static const unsigned u0modem_a_1_pins[] = { STN8815_PIN_A4, STN8815_PIN_B5, + STN8815_PIN_D6, STN8815_PIN_C6 }; static const unsigned mmcsd_a_1_pins[] = { STN8815_PIN_B10, STN8815_PIN_A10, STN8815_PIN_C11, STN8815_PIN_B11, STN8815_PIN_A11, STN8815_PIN_C12, STN8815_PIN_B12, STN8815_PIN_A12, STN8815_PIN_C13, STN8815_PIN_C15 }; @@ -290,7 +292,9 @@ static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 }; .npins = ARRAY_SIZE(a##_pins), .altsetting = b } static const struct nmk_pingroup nmk_stn8815_groups[] = { - STN8815_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0txrx_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0ctsrts_a_1, NMK_GPIO_ALT_A), + STN8815_PIN_GROUP(u0modem_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(mmcsd_a_1, NMK_GPIO_ALT_A), STN8815_PIN_GROUP(mmcsd_b_1, NMK_GPIO_ALT_B), STN8815_PIN_GROUP(u1_a_1, NMK_GPIO_ALT_A), @@ -304,7 +308,7 @@ static const struct nmk_pingroup nmk_stn8815_groups[] = { #define STN8815_FUNC_GROUPS(a, b...) \ static const char * const a##_groups[] = { b }; -STN8815_FUNC_GROUPS(u0, "u0_a_1"); +STN8815_FUNC_GROUPS(u0, "u0txrx_a_1", "u0ctsrts_a_1", "u0modem_a_1"); STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1", "mmcsd_b_1"); STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1"); STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1"); -- GitLab From 48356aa79ccb3df36f654d8f622256052bb2bb65 Mon Sep 17 00:00:00 2001 From: Wei Chen Date: Mon, 27 Jul 2015 11:57:25 +0000 Subject: [PATCH 1892/7006] pinctrl: sirf: add power management support for atlas7 We had not implemented the pm interface of atlas7 pinctrl and gpio drivers. So when system resumes from sleep, all pin configuration and gpio status will be lost. Now, we implement these interfaces to support pm. At the same time, this patch also drops a lot of if-else by look-up table for getting and setting pull. Signed-off-by: Wei Chen Signed-off-by: Barry Song Signed-off-by: Linus Walleij --- drivers/pinctrl/sirf/pinctrl-atlas7.c | 392 +++++++++++++++++++++----- 1 file changed, 325 insertions(+), 67 deletions(-) diff --git a/drivers/pinctrl/sirf/pinctrl-atlas7.c b/drivers/pinctrl/sirf/pinctrl-atlas7.c index 0cd945c3af67d..d16e62996e055 100644 --- a/drivers/pinctrl/sirf/pinctrl-atlas7.c +++ b/drivers/pinctrl/sirf/pinctrl-atlas7.c @@ -148,6 +148,19 @@ enum altas7_pad_type { #define DIV_DISABLE 0x1 #define DIV_ENABLE 0x0 +/* Number of Function input disable registers */ +#define NUM_OF_IN_DISABLE_REG 0x2 + +/* Offset of Function input disable registers */ +#define IN_DISABLE_0_REG_SET 0x0A00 +#define IN_DISABLE_0_REG_CLR 0x0A04 +#define IN_DISABLE_1_REG_SET 0x0A08 +#define IN_DISABLE_1_REG_CLR 0x0A0C +#define IN_DISABLE_VAL_0_REG_SET 0x0A80 +#define IN_DISABLE_VAL_0_REG_CLR 0x0A84 +#define IN_DISABLE_VAL_1_REG_SET 0x0A88 +#define IN_DISABLE_VAL_1_REG_CLR 0x0A8C + struct dt_params { const char *property; int value; @@ -196,6 +209,16 @@ struct atlas7_pad_config { .ad_ctrl_bit = adb, \ } +/** + * struct atlas7_pad_status - Atlas7 Pad status + */ +struct atlas7_pad_status { + u8 func; + u8 pull; + u8 dstr; + u8 reserved; +}; + /** * struct atlas7_pad_mux - Atlas7 mux * @bank: The bank of this pad's registers on. @@ -285,6 +308,9 @@ struct atlas7_pinctrl_data { /* Platform info of atlas7 pinctrl */ #define ATLAS7_PINCTRL_REG_BANKS 2 #define ATLAS7_PINCTRL_BANK_0_PINS 18 +#define ATLAS7_PINCTRL_BANK_1_PINS 141 +#define ATLAS7_PINCTRL_TOTAL_PINS \ + (ATLAS7_PINCTRL_BANK_0_PINS + ATLAS7_PINCTRL_BANK_1_PINS) /** * Atlas7 GPIO Chip @@ -316,6 +342,7 @@ struct atlas7_gpio_bank { unsigned int gpio_offset; unsigned int ngpio; const unsigned int *gpio_pins; + u32 sleep_data[NGPIO_OF_BANK]; }; struct atlas7_gpio_chip { @@ -343,6 +370,9 @@ struct atlas7_pmx { struct pinctrl_desc pctl_desc; struct atlas7_pinctrl_data *pctl_data; void __iomem *regs[ATLAS7_PINCTRL_REG_BANKS]; + u32 status_ds[NUM_OF_IN_DISABLE_REG]; + u32 status_dsv[NUM_OF_IN_DISABLE_REG]; + struct atlas7_pad_status sleep_data[ATLAS7_PINCTRL_TOTAL_PINS]; }; /* @@ -3480,6 +3510,93 @@ struct atlas7_pinctrl_data atlas7_ioc_data = { .confs_cnt = ARRAY_SIZE(atlas7_ioc_pad_confs), }; +struct map_data { + u8 idx; + u8 data; +}; + +struct atlas7_pull_info { + u8 pad_type; + u8 mask; + const struct map_data *v2s; + const struct map_data *s2v; +}; + +/* Pull Register value map to status */ +static const struct map_data p4we_pull_v2s[] = { + { P4WE_PULL_UP, PULL_UP }, + { P4WE_HIGH_HYSTERESIS, HIGH_HYSTERESIS }, + { P4WE_HIGH_Z, HIGH_Z }, + { P4WE_PULL_DOWN, PULL_DOWN }, +}; + +static const struct map_data p16st_pull_v2s[] = { + { P16ST_PULL_UP, PULL_UP }, + { PD, PULL_UNKNOWN }, + { P16ST_HIGH_Z, HIGH_Z }, + { P16ST_PULL_DOWN, PULL_DOWN }, +}; + +static const struct map_data pm31_pull_v2s[] = { + { PM31_PULL_DISABLED, PULL_DOWN }, + { PM31_PULL_ENABLED, PULL_UP }, +}; + +static const struct map_data pangd_pull_v2s[] = { + { PANGD_PULL_UP, PULL_UP }, + { PD, PULL_UNKNOWN }, + { PANGD_HIGH_Z, HIGH_Z }, + { PANGD_PULL_DOWN, PULL_DOWN }, +}; + +/* Pull status map to register value */ +static const struct map_data p4we_pull_s2v[] = { + { PULL_UP, P4WE_PULL_UP }, + { HIGH_HYSTERESIS, P4WE_HIGH_HYSTERESIS }, + { HIGH_Z, P4WE_HIGH_Z }, + { PULL_DOWN, P4WE_PULL_DOWN }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct map_data p16st_pull_s2v[] = { + { PULL_UP, P16ST_PULL_UP }, + { HIGH_HYSTERESIS, -1 }, + { HIGH_Z, P16ST_HIGH_Z }, + { PULL_DOWN, P16ST_PULL_DOWN }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct map_data pm31_pull_s2v[] = { + { PULL_UP, PM31_PULL_ENABLED }, + { HIGH_HYSTERESIS, -1 }, + { HIGH_Z, -1 }, + { PULL_DOWN, PM31_PULL_DISABLED }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct map_data pangd_pull_s2v[] = { + { PULL_UP, PANGD_PULL_UP }, + { HIGH_HYSTERESIS, -1 }, + { HIGH_Z, PANGD_HIGH_Z }, + { PULL_DOWN, PANGD_PULL_DOWN }, + { PULL_DISABLE, -1 }, + { PULL_ENABLE, -1 }, +}; + +static const struct atlas7_pull_info atlas7_pull_map[] = { + { PAD_T_4WE_PD, P4WE_PULL_MASK, p4we_pull_v2s, p4we_pull_s2v }, + { PAD_T_4WE_PU, P4WE_PULL_MASK, p4we_pull_v2s, p4we_pull_s2v }, + { PAD_T_16ST, P16ST_PULL_MASK, p16st_pull_v2s, p16st_pull_s2v }, + { PAD_T_M31_0204_PD, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_M31_0204_PU, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_M31_0610_PD, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_M31_0610_PU, PM31_PULL_MASK, pm31_pull_v2s, pm31_pull_s2v }, + { PAD_T_AD, PANGD_PULL_MASK, pangd_pull_v2s, pangd_pull_s2v }, +}; + static inline u32 atlas7_pin_to_bank(u32 pin) { return (pin >= ATLAS7_PINCTRL_BANK_0_PINS) ? 1 : 0; @@ -3730,83 +3847,44 @@ static u32 convert_current_to_drive_strength(u32 type, u32 ma) return DS_NULL; } +static u32 altas7_pinctrl_get_pull_sel(struct atlas7_pmx *pmx, u32 pin) +{ + struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin]; + const struct atlas7_pull_info *pull_info; + int bank; + unsigned long regv; + + bank = atlas7_pin_to_bank(pin); + pull_info = &atlas7_pull_map[conf->type]; + + regv = readl(pmx->regs[bank] + conf->pupd_reg); + regv = (regv >> conf->pupd_bit) & pull_info->mask; + + return pull_info->v2s[regv].data; +} + static int altas7_pinctrl_set_pull_sel(struct pinctrl_dev *pctldev, u32 pin, u32 sel) { struct atlas7_pmx *pmx = pinctrl_dev_get_drvdata(pctldev); struct atlas7_pad_config *conf = &pmx->pctl_data->confs[pin]; - u32 type = conf->type; - u32 shift = conf->pupd_bit; - u32 bank = atlas7_pin_to_bank(pin); + const struct atlas7_pull_info *pull_info; + u32 bank; + unsigned long regv; void __iomem *pull_sel_reg, *pull_clr_reg; + bank = atlas7_pin_to_bank(pin); + pull_info = &atlas7_pull_map[conf->type]; + pull_sel_reg = pmx->regs[bank] + conf->pupd_reg; pull_clr_reg = CLR_REG(pull_sel_reg); - if (type == PAD_T_4WE_PD || type == PAD_T_4WE_PU) { - writel(P4WE_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(P4WE_PULL_UP << shift, pull_sel_reg); - else if (sel == HIGH_HYSTERESIS) - writel(P4WE_HIGH_HYSTERESIS << shift, pull_sel_reg); - else if (sel == HIGH_Z) - writel(P4WE_HIGH_Z << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(P4WE_PULL_DOWN << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for 4WEPAD#%d\n", - pin); - return -ENOTSUPP; - } - } else if (type == PAD_T_16ST) { - writel(P16ST_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(P16ST_PULL_UP << shift, pull_sel_reg); - else if (sel == HIGH_Z) - writel(P16ST_HIGH_Z << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(P16ST_PULL_DOWN << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for 16STPAD#%d\n", - pin); - return -ENOTSUPP; - } - } else if (type == PAD_T_M31_0204_PD || - type == PAD_T_M31_0204_PU || - type == PAD_T_M31_0610_PD || - type == PAD_T_M31_0610_PU) { - writel(PM31_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(PM31_PULL_ENABLED << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(PM31_PULL_DISABLED << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for M31PAD#%d\n", - pin); - return -ENOTSUPP; - } - } else if (type == PAD_T_AD) { - writel(PANGD_PULL_MASK << shift, pull_clr_reg); - - if (sel == PULL_UP) - writel(PANGD_PULL_UP << shift, pull_sel_reg); - else if (sel == HIGH_Z) - writel(PANGD_HIGH_Z << shift, pull_sel_reg); - else if (sel == PULL_DOWN) - writel(PANGD_PULL_DOWN << shift, pull_sel_reg); - else { - pr_err("Unknown Pull select type for A/D PAD#%d\n", - pin); - return -ENOTSUPP; - } - } else { - pr_err("Unknown Pad type[%d] for pull select PAD#%d\n", - type, pin); - return -ENOTSUPP; - } + /* Retrieve correspond register value from table by sel */ + regv = pull_info->s2v[sel].data & pull_info->mask; + + /* Clear & Set new value to pull register */ + writel(pull_info->mask << conf->pupd_bit, pull_clr_reg); + writel(regv << conf->pupd_bit, pull_sel_reg); pr_debug("PIN_CFG ### SET PIN#%d PULL SELECTOR:%d == OK ####\n", pin, sel); @@ -4101,14 +4179,144 @@ unmap_io: return ret; } +#ifdef CONFIG_PM_SLEEP +static int atlas7_pinmux_suspend_noirq(struct device *dev) +{ + struct atlas7_pmx *pmx = dev_get_drvdata(dev); + struct atlas7_pad_status *status; + struct atlas7_pad_config *conf; + int idx; + u32 bank; + unsigned long regv; + + for (idx = 0; idx < pmx->pctl_desc.npins; idx++) { + /* Get this Pad's descriptor from PINCTRL */ + conf = &pmx->pctl_data->confs[idx]; + bank = atlas7_pin_to_bank(idx); + status = &pmx->sleep_data[idx]; + + /* Save Function selector */ + regv = readl(pmx->regs[bank] + conf->mux_reg); + status->func = (regv >> conf->mux_bit) & FUNC_CLEAR_MASK; + + /* Check if Pad is in Analogue selector */ + if (conf->ad_ctrl_reg == -1) + goto save_ds_sel; + + regv = readl(pmx->regs[bank] + conf->ad_ctrl_reg); + if (!(regv & (conf->ad_ctrl_bit << ANA_CLEAR_MASK))) + status->func = FUNC_ANALOGUE; + +save_ds_sel: + if (conf->drvstr_reg == -1) + goto save_pull_sel; + + /* Save Drive Strength selector */ + regv = readl(pmx->regs[bank] + conf->drvstr_reg); + if (PAD_T_4WE_PD == conf->type || PAD_T_4WE_PU == conf->type) + status->dstr = (regv >> conf->drvstr_bit) & + DS_2BIT_MASK; + else if (PAD_T_16ST == conf->type) + status->dstr = (regv >> conf->drvstr_bit) & + DS_4BIT_MASK; + else if (PAD_T_M31_0204_PD == conf->type || + PAD_T_M31_0204_PU == conf->type || + PAD_T_M31_0610_PD == conf->type || + PAD_T_M31_0610_PU == conf->type) + status->dstr = (regv >> conf->drvstr_bit) & + DS_1BIT_MASK; + +save_pull_sel: + /* Save Pull selector */ + regv = readl(pmx->regs[bank] + conf->pupd_reg); + status->pull = altas7_pinctrl_get_pull_sel(pmx, idx); + pr_debug("idx %d %p %x: %x %x %x\n", idx, + pmx->regs[bank], conf->mux_reg, + status->func, status->pull, status->dstr); + } + + /* + * Save disable input selector, this selector is not for Pin, + * but for Mux function. + */ + for (idx = 0; idx < NUM_OF_IN_DISABLE_REG; idx++) { + pmx->status_ds[idx] = readl(pmx->regs[BANK_DS] + + IN_DISABLE_0_REG_SET + 0x8 * idx); + pmx->status_dsv[idx] = readl(pmx->regs[BANK_DS] + + IN_DISABLE_VAL_0_REG_SET + 0x8 * idx); + } + + return 0; +} + +static int atlas7_pinmux_resume_noirq(struct device *dev) +{ + struct atlas7_pmx *pmx = dev_get_drvdata(dev); + struct atlas7_pad_status *status; + struct atlas7_pad_config *conf; + int idx; + u32 bank; + + for (idx = 0; idx < pmx->pctl_desc.npins; idx++) { + /* Get this Pad's descriptor from PINCTRL */ + conf = &pmx->pctl_data->confs[idx]; + bank = atlas7_pin_to_bank(idx); + status = &pmx->sleep_data[idx]; + + /* Restore Function selector */ + __atlas7_pmx_pin_enable(pmx, idx, (u32)status->func & 0xff); + + if (FUNC_ANALOGUE == status->func) + goto restore_pull_sel; + + /* Restore Drive Strength selector */ + __altas7_pinctrl_set_drive_strength_sel(pmx->pctl, idx, + (u32)status->dstr & 0xff); + +restore_pull_sel: + /* Restore Pull selector */ + altas7_pinctrl_set_pull_sel(pmx->pctl, idx, + (u32)status->pull & 0xff); + } + + /* + * Restore disable input selector, this selector is not for Pin, + * but for Mux function + */ + for (idx = 0; idx < NUM_OF_IN_DISABLE_REG; idx++) { + writel(~0, pmx->regs[BANK_DS] + + IN_DISABLE_0_REG_CLR + 0x8 * idx); + writel(pmx->status_ds[idx], pmx->regs[BANK_DS] + + IN_DISABLE_0_REG_SET + 0x8 * idx); + writel(~0, pmx->regs[BANK_DS] + + IN_DISABLE_VAL_0_REG_CLR + 0x8 * idx); + writel(pmx->status_dsv[idx], pmx->regs[BANK_DS] + + IN_DISABLE_VAL_0_REG_SET + 0x8 * idx); + } + + return 0; +} + +static const struct dev_pm_ops atlas7_pinmux_pm_ops = { + .suspend_noirq = atlas7_pinmux_suspend_noirq, + .resume_noirq = atlas7_pinmux_resume_noirq, + .freeze_noirq = atlas7_pinmux_suspend_noirq, + .restore_noirq = atlas7_pinmux_resume_noirq, +}; +#endif + static const struct of_device_id atlas7_pinmux_ids[] = { { .compatible = "sirf,atlas7-ioc",}, + {}, }; static struct platform_driver atlas7_pinmux_driver = { .driver = { .name = "atlas7-ioc", .of_match_table = atlas7_pinmux_ids, +#ifdef CONFIG_PM_SLEEP + .pm = &atlas7_pinmux_pm_ops, +#endif }, .probe = atlas7_pinmux_probe, }; @@ -4497,6 +4705,7 @@ static void atlas7_gpio_set_value(struct gpio_chip *chip, static const struct of_device_id atlas7_gpio_ids[] = { { .compatible = "sirf,atlas7-gpio", }, + {}, }; static int atlas7_gpio_probe(struct platform_device *pdev) @@ -4613,16 +4822,65 @@ static int atlas7_gpio_probe(struct platform_device *pdev) BUG_ON(!bank->pctldev); } + platform_set_drvdata(pdev, a7gc); dev_info(&pdev->dev, "add to system.\n"); return 0; failed: return ret; } +#ifdef CONFIG_PM_SLEEP +static int atlas7_gpio_suspend_noirq(struct device *dev) +{ + struct atlas7_gpio_chip *a7gc = dev_get_drvdata(dev); + struct atlas7_gpio_bank *bank; + void __iomem *ctrl_reg; + u32 idx, pin; + + for (idx = 0; idx < a7gc->nbank; idx++) { + bank = &a7gc->banks[idx]; + for (pin = 0; pin < bank->ngpio; pin++) { + ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin); + bank->sleep_data[pin] = readl(ctrl_reg); + } + } + + return 0; +} + +static int atlas7_gpio_resume_noirq(struct device *dev) +{ + struct atlas7_gpio_chip *a7gc = dev_get_drvdata(dev); + struct atlas7_gpio_bank *bank; + void __iomem *ctrl_reg; + u32 idx, pin; + + for (idx = 0; idx < a7gc->nbank; idx++) { + bank = &a7gc->banks[idx]; + for (pin = 0; pin < bank->ngpio; pin++) { + ctrl_reg = ATLAS7_GPIO_CTRL(bank, pin); + writel(bank->sleep_data[pin], ctrl_reg); + } + } + + return 0; +} + +static const struct dev_pm_ops atlas7_gpio_pm_ops = { + .suspend_noirq = atlas7_gpio_suspend_noirq, + .resume_noirq = atlas7_gpio_resume_noirq, + .freeze_noirq = atlas7_gpio_suspend_noirq, + .restore_noirq = atlas7_gpio_resume_noirq, +}; +#endif + static struct platform_driver atlas7_gpio_driver = { .driver = { .name = "atlas7-gpio", .of_match_table = atlas7_gpio_ids, +#ifdef CONFIG_PM_SLEEP + .pm = &atlas7_gpio_pm_ops, +#endif }, .probe = atlas7_gpio_probe, }; -- GitLab From 505936131ea71ec998344355f7e5e8af8d6b15dc Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Tue, 21 Jul 2015 15:54:30 +0200 Subject: [PATCH 1893/7006] gpio: mpc8xxx: Convert mpc8xxx_gpio_chip.lock to raw_spinlock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mpc8xxx_gpio_chip.lock needs to be a real spinlock in preempt-rt. Especially the interrupt related functions can not be converted to a sleeping lock. Signed-off-by: Alexander Stein Acked-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpio-mpc8xxx.c | 48 ++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c index 4c51377934317..8ef7a12de9837 100644 --- a/drivers/gpio/gpio-mpc8xxx.c +++ b/drivers/gpio/gpio-mpc8xxx.c @@ -32,7 +32,7 @@ struct mpc8xxx_gpio_chip { struct of_mm_gpio_chip mm_gc; - spinlock_t lock; + raw_spinlock_t lock; /* * shadowed data register to be able to clear/set output pins in @@ -95,7 +95,7 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); if (val) mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio); @@ -104,7 +104,7 @@ static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val) out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, @@ -115,7 +115,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, unsigned long flags; int i; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); for (i = 0; i < gc->ngpio; i++) { if (*mask == 0) @@ -130,7 +130,7 @@ static void mpc8xxx_gpio_set_multiple(struct gpio_chip *gc, out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) @@ -139,11 +139,11 @@ static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm); unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); return 0; } @@ -156,11 +156,11 @@ static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val mpc8xxx_gpio_set(gc, gpio, val); - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio)); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); return 0; } @@ -215,11 +215,11 @@ static void mpc8xxx_irq_unmask(struct irq_data *d) struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_irq_mask(struct irq_data *d) @@ -228,11 +228,11 @@ static void mpc8xxx_irq_mask(struct irq_data *d) struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc; unsigned long flags; - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); } static void mpc8xxx_irq_ack(struct irq_data *d) @@ -251,17 +251,17 @@ static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_EDGE_FALLING: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); setbits32(mm->regs + GPIO_ICR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(mm->regs + GPIO_ICR, mpc8xxx_gpio2mask(irqd_to_hwirq(d))); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; default: @@ -291,22 +291,22 @@ static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type) switch (flow_type) { case IRQ_TYPE_EDGE_FALLING: case IRQ_TYPE_LEVEL_LOW: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrsetbits_be32(reg, 3 << shift, 2 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_RISING: case IRQ_TYPE_LEVEL_HIGH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrsetbits_be32(reg, 3 << shift, 1 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; case IRQ_TYPE_EDGE_BOTH: - spin_lock_irqsave(&mpc8xxx_gc->lock, flags); + raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags); clrbits32(reg, 3 << shift); - spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); + raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags); break; default: @@ -393,7 +393,7 @@ static int mpc8xxx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mpc8xxx_gc); - spin_lock_init(&mpc8xxx_gc->lock); + raw_spin_lock_init(&mpc8xxx_gc->lock); mm_gc = &mpc8xxx_gc->mm_gc; gc = &mm_gc->gc; -- GitLab From 21abb1ec414c75abe32c3854848ff30e2b4a6113 Mon Sep 17 00:00:00 2001 From: Casey Schaufler Date: Wed, 22 Jul 2015 14:25:31 -0700 Subject: [PATCH 1894/7006] Smack: IPv6 host labeling IPv6 appears to be (finally) coming of age with the influx of autonomous devices. In support of this, add the ability to associate a Smack label with IPv6 addresses. This patch also cleans up some of the conditional compilation associated with the introduction of secmark processing. It's now more obvious which bit of code goes with which feature. Signed-off-by: Casey Schaufler --- Documentation/security/Smack.txt | 27 +- security/smack/smack.h | 48 +++- security/smack/smack_lsm.c | 262 +++++++++++++------ security/smack/smackfs.c | 428 +++++++++++++++++++++++++------ 4 files changed, 604 insertions(+), 161 deletions(-) diff --git a/Documentation/security/Smack.txt b/Documentation/security/Smack.txt index de5e1aeca7fb9..5e6d07fbed07c 100644 --- a/Documentation/security/Smack.txt +++ b/Documentation/security/Smack.txt @@ -28,6 +28,10 @@ Smack kernels use the CIPSO IP option. Some network configurations are intolerant of IP options and can impede access to systems that use them as Smack does. +Smack is used in the Tizen operating system. Please +go to http://wiki.tizen.org for information about how +Smack is used in Tizen. + The current git repository for Smack user space is: git://github.com/smack-team/smack.git @@ -108,6 +112,8 @@ in the smackfs filesystem. This pseudo-filesystem is mounted on /sys/fs/smackfs. access + Provided for backward compatibility. The access2 interface + is preferred and should be used instead. This interface reports whether a subject with the specified Smack label has a particular access to an object with a specified Smack label. Write a fixed format access rule to @@ -136,6 +142,8 @@ change-rule those in the fourth string. If there is no such rule it will be created using the access specified in the third and the fourth strings. cipso + Provided for backward compatibility. The cipso2 interface + is preferred and should be used instead. This interface allows a specific CIPSO header to be assigned to a Smack label. The format accepted on write is: "%24s%4d%4d"["%4d"]... @@ -157,7 +165,19 @@ direct doi This contains the CIPSO domain of interpretation used in network packets. +ipv6host + This interface allows specific IPv6 internet addresses to be + treated as single label hosts. Packets are sent to single + label hosts only from processes that have Smack write access + to the host label. All packets received from single label hosts + are given the specified label. The format accepted on write is: + "%h:%h:%h:%h:%h:%h:%h:%h label" or + "%h:%h:%h:%h:%h:%h:%h:%h/%d label". + The "::" address shortcut is not supported. + If label is "-DELETE" a matched entry will be deleted. load + Provided for backward compatibility. The load2 interface + is preferred and should be used instead. This interface allows access control rules in addition to the system defined rules to be specified. The format accepted on write is: @@ -181,6 +201,8 @@ load2 permissions that are not allowed. The string "r-x--" would specify read and execute access. load-self + Provided for backward compatibility. The load-self2 interface + is preferred and should be used instead. This interface allows process specific access rules to be defined. These rules are only consulted if access would otherwise be permitted, and are intended to provide additional @@ -205,6 +227,8 @@ netlabel received from single label hosts are given the specified label. The format accepted on write is: "%d.%d.%d.%d label" or "%d.%d.%d.%d/%d label". + If the label specified is "-CIPSO" the address is treated + as a host that supports CIPSO headers. onlycap This contains labels processes must have for CAP_MAC_ADMIN and CAP_MAC_OVERRIDE to be effective. If this file is empty @@ -232,7 +256,8 @@ unconfined is dangerous and can ruin the proper labeling of your system. It should never be used in production. -You can add access rules in /etc/smack/accesses. They take the form: +If you are using the smackload utility +you can add access rules in /etc/smack/accesses. They take the form: subjectlabel objectlabel access diff --git a/security/smack/smack.h b/security/smack/smack.h index 69ab9eb7d6d92..fff0c612bbb77 100644 --- a/security/smack/smack.h +++ b/security/smack/smack.h @@ -17,11 +17,26 @@ #include #include #include +#if IS_ENABLED(CONFIG_IPV6) +#include +#endif /* CONFIG_IPV6 */ #include #include #include #include +/* + * Use IPv6 port labeling if IPv6 is enabled and secmarks + * are not being used. + */ +#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) +#define SMACK_IPV6_PORT_LABELING 1 +#endif + +#if IS_ENABLED(CONFIG_IPV6) && defined(CONFIG_SECURITY_SMACK_NETFILTER) +#define SMACK_IPV6_SECMARK_LABELING 1 +#endif + /* * Smack labels were limited to 23 characters for a long time. */ @@ -118,15 +133,30 @@ struct smack_rule { }; /* - * An entry in the table identifying hosts. + * An entry in the table identifying IPv4 hosts. */ -struct smk_netlbladdr { +struct smk_net4addr { struct list_head list; - struct sockaddr_in smk_host; /* network address */ + struct in_addr smk_host; /* network address */ struct in_addr smk_mask; /* network mask */ + int smk_masks; /* mask size */ + struct smack_known *smk_label; /* label */ +}; + +#if IS_ENABLED(CONFIG_IPV6) +/* + * An entry in the table identifying IPv6 hosts. + */ +struct smk_net6addr { + struct list_head list; + struct in6_addr smk_host; /* network address */ + struct in6_addr smk_mask; /* network mask */ + int smk_masks; /* mask size */ struct smack_known *smk_label; /* label */ }; +#endif /* CONFIG_IPV6 */ +#ifdef SMACK_IPV6_PORT_LABELING /* * An entry in the table identifying ports. */ @@ -137,6 +167,7 @@ struct smk_port_label { struct smack_known *smk_in; /* inbound label */ struct smack_known *smk_out; /* outgoing label */ }; +#endif /* SMACK_IPV6_PORT_LABELING */ struct smack_onlycap { struct list_head list; @@ -170,6 +201,7 @@ enum { #define SMK_FSROOT "smackfsroot=" #define SMK_FSTRANS "smackfstransmute=" +#define SMACK_DELETE_OPTION "-DELETE" #define SMACK_CIPSO_OPTION "-CIPSO" /* @@ -252,10 +284,6 @@ struct smk_audit_info { struct smack_audit_data sad; #endif }; -/* - * These functions are in smack_lsm.c - */ -struct inode_smack *new_inode_smack(struct smack_known *); /* * These functions are in smack_access.c @@ -285,7 +313,6 @@ extern struct smack_known *smack_syslog_label; #ifdef CONFIG_SECURITY_SMACK_BRINGUP extern struct smack_known *smack_unconfined; #endif -extern struct smack_known smack_cipso_option; extern int smack_ptrace_rule; extern struct smack_known smack_known_floor; @@ -297,7 +324,10 @@ extern struct smack_known smack_known_web; extern struct mutex smack_known_lock; extern struct list_head smack_known_list; -extern struct list_head smk_netlbladdr_list; +extern struct list_head smk_net4addr_list; +#if IS_ENABLED(CONFIG_IPV6) +extern struct list_head smk_net6addr_list; +#endif /* CONFIG_IPV6 */ extern struct mutex smack_onlycap_lock; extern struct list_head smack_onlycap_list; diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index d962f887d3f44..cc390bccecd77 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -51,9 +51,9 @@ #define SMK_RECEIVING 1 #define SMK_SENDING 2 -#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) +#ifdef SMACK_IPV6_PORT_LABELING LIST_HEAD(smk_ipv6_port_list); -#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif static struct kmem_cache *smack_inode_cache; int smack_enabled; @@ -2272,7 +2272,7 @@ static void smack_sk_free_security(struct sock *sk) } /** -* smack_host_label - check host based restrictions +* smack_ipv4host_label - check host based restrictions * @sip: the object end * * looks for host based access restrictions @@ -2283,30 +2283,96 @@ static void smack_sk_free_security(struct sock *sk) * * Returns the label of the far end or NULL if it's not special. */ -static struct smack_known *smack_host_label(struct sockaddr_in *sip) +static struct smack_known *smack_ipv4host_label(struct sockaddr_in *sip) { - struct smk_netlbladdr *snp; + struct smk_net4addr *snp; struct in_addr *siap = &sip->sin_addr; if (siap->s_addr == 0) return NULL; - list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) + list_for_each_entry_rcu(snp, &smk_net4addr_list, list) + /* + * we break after finding the first match because + * the list is sorted from longest to shortest mask + * so we have found the most specific match + */ + if (snp->smk_host.s_addr == + (siap->s_addr & snp->smk_mask.s_addr)) + return snp->smk_label; + + return NULL; +} + +#if IS_ENABLED(CONFIG_IPV6) +/* + * smk_ipv6_localhost - Check for local ipv6 host address + * @sip: the address + * + * Returns boolean true if this is the localhost address + */ +static bool smk_ipv6_localhost(struct sockaddr_in6 *sip) +{ + __be16 *be16p = (__be16 *)&sip->sin6_addr; + __be32 *be32p = (__be32 *)&sip->sin6_addr; + + if (be32p[0] == 0 && be32p[1] == 0 && be32p[2] == 0 && be16p[6] == 0 && + ntohs(be16p[7]) == 1) + return true; + return false; +} + +/** +* smack_ipv6host_label - check host based restrictions +* @sip: the object end +* +* looks for host based access restrictions +* +* This version will only be appropriate for really small sets of single label +* hosts. The caller is responsible for ensuring that the RCU read lock is +* taken before calling this function. +* +* Returns the label of the far end or NULL if it's not special. +*/ +static struct smack_known *smack_ipv6host_label(struct sockaddr_in6 *sip) +{ + struct smk_net6addr *snp; + struct in6_addr *sap = &sip->sin6_addr; + int i; + int found = 0; + + /* + * It's local. Don't look for a host label. + */ + if (smk_ipv6_localhost(sip)) + return NULL; + + list_for_each_entry_rcu(snp, &smk_net6addr_list, list) { /* * we break after finding the first match because * the list is sorted from longest to shortest mask * so we have found the most specific match */ - if ((&snp->smk_host.sin_addr)->s_addr == - (siap->s_addr & (&snp->smk_mask)->s_addr)) { - /* we have found the special CIPSO option */ - if (snp->smk_label == &smack_cipso_option) - return NULL; - return snp->smk_label; + for (found = 1, i = 0; i < 8; i++) { + /* + * If the label is NULL the entry has + * been renounced. Ignore it. + */ + if (snp->smk_label == NULL) + continue; + if ((sap->s6_addr16[i] & snp->smk_mask.s6_addr16[i]) != + snp->smk_host.s6_addr16[i]) { + found = 0; + break; + } } + if (found) + return snp->smk_label; + } return NULL; } +#endif /* CONFIG_IPV6 */ /** * smack_netlabel - Set the secattr on a socket @@ -2370,7 +2436,7 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) struct smk_audit_info ad; rcu_read_lock(); - hkp = smack_host_label(sap); + hkp = smack_ipv4host_label(sap); if (hkp != NULL) { #ifdef CONFIG_AUDIT struct lsm_network_audit net; @@ -2395,7 +2461,42 @@ static int smack_netlabel_send(struct sock *sk, struct sockaddr_in *sap) return smack_netlabel(sk, sk_lbl); } -#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) +#if IS_ENABLED(CONFIG_IPV6) +/** + * smk_ipv6_check - check Smack access + * @subject: subject Smack label + * @object: object Smack label + * @address: address + * @act: the action being taken + * + * Check an IPv6 access + */ +static int smk_ipv6_check(struct smack_known *subject, + struct smack_known *object, + struct sockaddr_in6 *address, int act) +{ +#ifdef CONFIG_AUDIT + struct lsm_network_audit net; +#endif + struct smk_audit_info ad; + int rc; + +#ifdef CONFIG_AUDIT + smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); + ad.a.u.net->family = PF_INET6; + ad.a.u.net->dport = ntohs(address->sin6_port); + if (act == SMK_RECEIVING) + ad.a.u.net->v6info.saddr = address->sin6_addr; + else + ad.a.u.net->v6info.daddr = address->sin6_addr; +#endif + rc = smk_access(subject, object, MAY_WRITE, &ad); + rc = smk_bu_note("IPv6 check", subject, object, MAY_WRITE, rc); + return rc; +} +#endif /* CONFIG_IPV6 */ + +#ifdef SMACK_IPV6_PORT_LABELING /** * smk_ipv6_port_label - Smack port access table management * @sock: socket @@ -2479,48 +2580,43 @@ static void smk_ipv6_port_label(struct socket *sock, struct sockaddr *address) static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, int act) { - __be16 *bep; - __be32 *be32p; struct smk_port_label *spp; struct socket_smack *ssp = sk->sk_security; - struct smack_known *skp; - unsigned short port = 0; + struct smack_known *skp = NULL; + unsigned short port; struct smack_known *object; - struct smk_audit_info ad; - int rc; -#ifdef CONFIG_AUDIT - struct lsm_network_audit net; -#endif if (act == SMK_RECEIVING) { - skp = smack_net_ambient; + skp = smack_ipv6host_label(address); object = ssp->smk_in; } else { skp = ssp->smk_out; - object = smack_net_ambient; + object = smack_ipv6host_label(address); } /* - * Get the IP address and port from the address. + * The other end is a single label host. */ - port = ntohs(address->sin6_port); - bep = (__be16 *)(&address->sin6_addr); - be32p = (__be32 *)(&address->sin6_addr); + if (skp != NULL && object != NULL) + return smk_ipv6_check(skp, object, address, act); + if (skp == NULL) + skp = smack_net_ambient; + if (object == NULL) + object = smack_net_ambient; /* * It's remote, so port lookup does no good. */ - if (be32p[0] || be32p[1] || be32p[2] || bep[6] || ntohs(bep[7]) != 1) - goto auditout; + if (!smk_ipv6_localhost(address)) + return smk_ipv6_check(skp, object, address, act); /* * It's local so the send check has to have passed. */ - if (act == SMK_RECEIVING) { - skp = &smack_known_web; - goto auditout; - } + if (act == SMK_RECEIVING) + return 0; + port = ntohs(address->sin6_port); list_for_each_entry(spp, &smk_ipv6_port_list, list) { if (spp->smk_port != port) continue; @@ -2530,22 +2626,9 @@ static int smk_ipv6_port_check(struct sock *sk, struct sockaddr_in6 *address, break; } -auditout: - -#ifdef CONFIG_AUDIT - smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); - ad.a.u.net->family = sk->sk_family; - ad.a.u.net->dport = port; - if (act == SMK_RECEIVING) - ad.a.u.net->v6info.saddr = address->sin6_addr; - else - ad.a.u.net->v6info.daddr = address->sin6_addr; -#endif - rc = smk_access(skp, object, MAY_WRITE, &ad); - rc = smk_bu_note("IPv6 port check", skp, object, MAY_WRITE, rc); - return rc; + return smk_ipv6_check(skp, object, address, act); } -#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif /* SMACK_IPV6_PORT_LABELING */ /** * smack_inode_setsecurity - set smack xattrs @@ -2606,10 +2689,10 @@ static int smack_inode_setsecurity(struct inode *inode, const char *name, } else return -EOPNOTSUPP; -#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) +#ifdef SMACK_IPV6_PORT_LABELING if (sock->sk->sk_family == PF_INET6) smk_ipv6_port_label(sock, NULL); -#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif return 0; } @@ -2651,7 +2734,7 @@ static int smack_socket_post_create(struct socket *sock, int family, return smack_netlabel(sock->sk, SMACK_CIPSO_SOCKET); } -#ifndef CONFIG_SECURITY_SMACK_NETFILTER +#ifdef SMACK_IPV6_PORT_LABELING /** * smack_socket_bind - record port binding information. * @sock: the socket @@ -2665,14 +2748,11 @@ static int smack_socket_post_create(struct socket *sock, int family, static int smack_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen) { -#if IS_ENABLED(CONFIG_IPV6) if (sock->sk != NULL && sock->sk->sk_family == PF_INET6) smk_ipv6_port_label(sock, address); -#endif - return 0; } -#endif /* !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif /* SMACK_IPV6_PORT_LABELING */ /** * smack_socket_connect - connect access check @@ -2688,6 +2768,13 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, int addrlen) { int rc = 0; +#if IS_ENABLED(CONFIG_IPV6) + struct sockaddr_in6 *sip = (struct sockaddr_in6 *)sap; +#endif +#ifdef SMACK_IPV6_SECMARK_LABELING + struct smack_known *rsp; + struct socket_smack *ssp = sock->sk->sk_security; +#endif if (sock->sk == NULL) return 0; @@ -2701,10 +2788,15 @@ static int smack_socket_connect(struct socket *sock, struct sockaddr *sap, case PF_INET6: if (addrlen < sizeof(struct sockaddr_in6)) return -EINVAL; -#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) - rc = smk_ipv6_port_check(sock->sk, (struct sockaddr_in6 *)sap, +#ifdef SMACK_IPV6_SECMARK_LABELING + rsp = smack_ipv6host_label(sip); + if (rsp != NULL) + rc = smk_ipv6_check(ssp->smk_out, rsp, sip, SMK_CONNECTING); -#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif +#ifdef SMACK_IPV6_PORT_LABELING + rc = smk_ipv6_port_check(sock->sk, sip, SMK_CONNECTING); +#endif break; } return rc; @@ -3590,9 +3682,13 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size) { struct sockaddr_in *sip = (struct sockaddr_in *) msg->msg_name; -#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) +#if IS_ENABLED(CONFIG_IPV6) struct sockaddr_in6 *sap = (struct sockaddr_in6 *) msg->msg_name; -#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif +#ifdef SMACK_IPV6_SECMARK_LABELING + struct socket_smack *ssp = sock->sk->sk_security; + struct smack_known *rsp; +#endif int rc = 0; /* @@ -3606,9 +3702,15 @@ static int smack_socket_sendmsg(struct socket *sock, struct msghdr *msg, rc = smack_netlabel_send(sock->sk, sip); break; case AF_INET6: -#if IS_ENABLED(CONFIG_IPV6) && !defined(CONFIG_SECURITY_SMACK_NETFILTER) +#ifdef SMACK_IPV6_SECMARK_LABELING + rsp = smack_ipv6host_label(sap); + if (rsp != NULL) + rc = smk_ipv6_check(ssp->smk_out, rsp, sap, + SMK_CONNECTING); +#endif +#ifdef SMACK_IPV6_PORT_LABELING rc = smk_ipv6_port_check(sock->sk, sap, SMK_SENDING); -#endif /* CONFIG_IPV6 && !CONFIG_SECURITY_SMACK_NETFILTER */ +#endif break; } return rc; @@ -3822,10 +3924,12 @@ access_check: proto = smk_skb_to_addr_ipv6(skb, &sadd); if (proto != IPPROTO_UDP && proto != IPPROTO_TCP) break; -#ifdef CONFIG_SECURITY_SMACK_NETFILTER +#ifdef SMACK_IPV6_SECMARK_LABELING if (skb && skb->secmark != 0) skp = smack_from_secid(skb->secmark); else + skp = smack_ipv6host_label(&sadd); + if (skp == NULL) skp = smack_net_ambient; #ifdef CONFIG_AUDIT smk_ad_init_net(&ad, __func__, LSM_AUDIT_DATA_NET, &net); @@ -3836,9 +3940,10 @@ access_check: rc = smk_access(skp, ssp->smk_in, MAY_WRITE, &ad); rc = smk_bu_note("IPv6 delivery", skp, ssp->smk_in, MAY_WRITE, rc); -#else /* CONFIG_SECURITY_SMACK_NETFILTER */ +#endif /* SMACK_IPV6_SECMARK_LABELING */ +#ifdef SMACK_IPV6_PORT_LABELING rc = smk_ipv6_port_check(sk, &sadd, SMK_RECEIVING); -#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ +#endif /* SMACK_IPV6_PORT_LABELING */ break; #endif /* CONFIG_IPV6 */ } @@ -3936,13 +4041,11 @@ static int smack_socket_getpeersec_dgram(struct socket *sock, } netlbl_secattr_destroy(&secattr); break; -#if IS_ENABLED(CONFIG_IPV6) case PF_INET6: -#ifdef CONFIG_SECURITY_SMACK_NETFILTER +#ifdef SMACK_IPV6_SECMARK_LABELING s = skb->secmark; -#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ +#endif break; -#endif /* CONFIG_IPV6 */ } *secid = s; if (s == 0) @@ -4065,7 +4168,7 @@ access_check: hdr = ip_hdr(skb); addr.sin_addr.s_addr = hdr->saddr; rcu_read_lock(); - hskp = smack_host_label(&addr); + hskp = smack_ipv4host_label(&addr); rcu_read_unlock(); if (hskp == NULL) @@ -4517,9 +4620,9 @@ struct security_hook_list smack_hooks[] = { LSM_HOOK_INIT(unix_may_send, smack_unix_may_send), LSM_HOOK_INIT(socket_post_create, smack_socket_post_create), -#ifndef CONFIG_SECURITY_SMACK_NETFILTER +#ifdef SMACK_IPV6_PORT_LABELING LSM_HOOK_INIT(socket_bind, smack_socket_bind), -#endif /* CONFIG_SECURITY_SMACK_NETFILTER */ +#endif LSM_HOOK_INIT(socket_connect, smack_socket_connect), LSM_HOOK_INIT(socket_sendmsg, smack_socket_sendmsg), LSM_HOOK_INIT(socket_sock_rcv_skb, smack_socket_sock_rcv_skb), @@ -4614,7 +4717,16 @@ static __init int smack_init(void) return -ENOMEM; } - printk(KERN_INFO "Smack: Initializing.\n"); + pr_info("Smack: Initializing.\n"); +#ifdef CONFIG_SECURITY_SMACK_NETFILTER + pr_info("Smack: Netfilter enabled.\n"); +#endif +#ifdef SMACK_IPV6_PORT_LABELING + pr_info("Smack: IPv6 port labeling enabled.\n"); +#endif +#ifdef SMACK_IPV6_SECMARK_LABELING + pr_info("Smack: IPv6 Netfilter enabled.\n"); +#endif /* * Set the security state for the initial task. diff --git a/security/smack/smackfs.c b/security/smack/smackfs.c index 81a2888a99086..11b752b366eab 100644 --- a/security/smack/smackfs.c +++ b/security/smack/smackfs.c @@ -29,6 +29,7 @@ #include #include "smack.h" +#define BEBITS (sizeof(__be32) * 8) /* * smackfs pseudo filesystem. */ @@ -40,7 +41,7 @@ enum smk_inos { SMK_DOI = 5, /* CIPSO DOI */ SMK_DIRECT = 6, /* CIPSO level indicating direct label */ SMK_AMBIENT = 7, /* internet ambient label */ - SMK_NETLBLADDR = 8, /* single label hosts */ + SMK_NET4ADDR = 8, /* single label hosts */ SMK_ONLYCAP = 9, /* the only "capable" label */ SMK_LOGGING = 10, /* logging */ SMK_LOAD_SELF = 11, /* task specific rules */ @@ -57,6 +58,9 @@ enum smk_inos { #ifdef CONFIG_SECURITY_SMACK_BRINGUP SMK_UNCONFINED = 22, /* define an unconfined label */ #endif +#if IS_ENABLED(CONFIG_IPV6) + SMK_NET6ADDR = 23, /* single label IPv6 hosts */ +#endif /* CONFIG_IPV6 */ }; /* @@ -64,7 +68,10 @@ enum smk_inos { */ static DEFINE_MUTEX(smack_cipso_lock); static DEFINE_MUTEX(smack_ambient_lock); -static DEFINE_MUTEX(smk_netlbladdr_lock); +static DEFINE_MUTEX(smk_net4addr_lock); +#if IS_ENABLED(CONFIG_IPV6) +static DEFINE_MUTEX(smk_net6addr_lock); +#endif /* CONFIG_IPV6 */ /* * This is the "ambient" label for network traffic. @@ -118,7 +125,10 @@ int smack_ptrace_rule = SMACK_PTRACE_DEFAULT; * can write to the specified label. */ -LIST_HEAD(smk_netlbladdr_list); +LIST_HEAD(smk_net4addr_list); +#if IS_ENABLED(CONFIG_IPV6) +LIST_HEAD(smk_net6addr_list); +#endif /* CONFIG_IPV6 */ /* * Rule lists are maintained for each label. @@ -140,11 +150,6 @@ struct smack_parsed_rule { static int smk_cipso_doi_value = SMACK_CIPSO_DOI_DEFAULT; -struct smack_known smack_cipso_option = { - .smk_known = SMACK_CIPSO_OPTION, - .smk_secid = 0, -}; - /* * Values for parsing cipso rules * SMK_DIGITLEN: Length of a digit field in a rule. @@ -1047,92 +1052,90 @@ static const struct file_operations smk_cipso2_ops = { * Seq_file read operations for /smack/netlabel */ -static void *netlbladdr_seq_start(struct seq_file *s, loff_t *pos) +static void *net4addr_seq_start(struct seq_file *s, loff_t *pos) { - return smk_seq_start(s, pos, &smk_netlbladdr_list); + return smk_seq_start(s, pos, &smk_net4addr_list); } -static void *netlbladdr_seq_next(struct seq_file *s, void *v, loff_t *pos) +static void *net4addr_seq_next(struct seq_file *s, void *v, loff_t *pos) { - return smk_seq_next(s, v, pos, &smk_netlbladdr_list); + return smk_seq_next(s, v, pos, &smk_net4addr_list); } -#define BEBITS (sizeof(__be32) * 8) /* * Print host/label pairs */ -static int netlbladdr_seq_show(struct seq_file *s, void *v) +static int net4addr_seq_show(struct seq_file *s, void *v) { struct list_head *list = v; - struct smk_netlbladdr *skp = - list_entry_rcu(list, struct smk_netlbladdr, list); - unsigned char *hp = (char *) &skp->smk_host.sin_addr.s_addr; - int maskn; - u32 temp_mask = be32_to_cpu(skp->smk_mask.s_addr); - - for (maskn = 0; temp_mask; temp_mask <<= 1, maskn++); + struct smk_net4addr *skp = + list_entry_rcu(list, struct smk_net4addr, list); + char *kp = SMACK_CIPSO_OPTION; - seq_printf(s, "%u.%u.%u.%u/%d %s\n", - hp[0], hp[1], hp[2], hp[3], maskn, skp->smk_label->smk_known); + if (skp->smk_label != NULL) + kp = skp->smk_label->smk_known; + seq_printf(s, "%pI4/%d %s\n", &skp->smk_host.s_addr, + skp->smk_masks, kp); return 0; } -static const struct seq_operations netlbladdr_seq_ops = { - .start = netlbladdr_seq_start, - .next = netlbladdr_seq_next, - .show = netlbladdr_seq_show, +static const struct seq_operations net4addr_seq_ops = { + .start = net4addr_seq_start, + .next = net4addr_seq_next, + .show = net4addr_seq_show, .stop = smk_seq_stop, }; /** - * smk_open_netlbladdr - open() for /smack/netlabel + * smk_open_net4addr - open() for /smack/netlabel * @inode: inode structure representing file * @file: "netlabel" file pointer * - * Connect our netlbladdr_seq_* operations with /smack/netlabel + * Connect our net4addr_seq_* operations with /smack/netlabel * file_operations */ -static int smk_open_netlbladdr(struct inode *inode, struct file *file) +static int smk_open_net4addr(struct inode *inode, struct file *file) { - return seq_open(file, &netlbladdr_seq_ops); + return seq_open(file, &net4addr_seq_ops); } /** - * smk_netlbladdr_insert + * smk_net4addr_insert * @new : netlabel to insert * - * This helper insert netlabel in the smack_netlbladdrs list + * This helper insert netlabel in the smack_net4addrs list * sorted by netmask length (longest to smallest) - * locked by &smk_netlbladdr_lock in smk_write_netlbladdr + * locked by &smk_net4addr_lock in smk_write_net4addr * */ -static void smk_netlbladdr_insert(struct smk_netlbladdr *new) +static void smk_net4addr_insert(struct smk_net4addr *new) { - struct smk_netlbladdr *m, *m_next; + struct smk_net4addr *m; + struct smk_net4addr *m_next; - if (list_empty(&smk_netlbladdr_list)) { - list_add_rcu(&new->list, &smk_netlbladdr_list); + if (list_empty(&smk_net4addr_list)) { + list_add_rcu(&new->list, &smk_net4addr_list); return; } - m = list_entry_rcu(smk_netlbladdr_list.next, - struct smk_netlbladdr, list); + m = list_entry_rcu(smk_net4addr_list.next, + struct smk_net4addr, list); /* the comparison '>' is a bit hacky, but works */ - if (new->smk_mask.s_addr > m->smk_mask.s_addr) { - list_add_rcu(&new->list, &smk_netlbladdr_list); + if (new->smk_masks > m->smk_masks) { + list_add_rcu(&new->list, &smk_net4addr_list); return; } - list_for_each_entry_rcu(m, &smk_netlbladdr_list, list) { - if (list_is_last(&m->list, &smk_netlbladdr_list)) { + list_for_each_entry_rcu(m, &smk_net4addr_list, list) { + if (list_is_last(&m->list, &smk_net4addr_list)) { list_add_rcu(&new->list, &m->list); return; } m_next = list_entry_rcu(m->list.next, - struct smk_netlbladdr, list); - if (new->smk_mask.s_addr > m_next->smk_mask.s_addr) { + struct smk_net4addr, list); + if (new->smk_masks > m_next->smk_masks) { list_add_rcu(&new->list, &m->list); return; } @@ -1141,28 +1144,29 @@ static void smk_netlbladdr_insert(struct smk_netlbladdr *new) /** - * smk_write_netlbladdr - write() for /smack/netlabel + * smk_write_net4addr - write() for /smack/netlabel * @file: file pointer, not actually used * @buf: where to get the data from * @count: bytes sent * @ppos: where to start * - * Accepts only one netlbladdr per write call. + * Accepts only one net4addr per write call. * Returns number of bytes written or error code, as appropriate */ -static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, +static ssize_t smk_write_net4addr(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { - struct smk_netlbladdr *snp; + struct smk_net4addr *snp; struct sockaddr_in newname; char *smack; - struct smack_known *skp; + struct smack_known *skp = NULL; char *data; char *host = (char *)&newname.sin_addr.s_addr; int rc; struct netlbl_audit audit_info; struct in_addr mask; unsigned int m; + unsigned int masks; int found; u32 mask_bits = (1<<31); __be32 nsa; @@ -1200,7 +1204,7 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, data[count] = '\0'; rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd/%u %s", - &host[0], &host[1], &host[2], &host[3], &m, smack); + &host[0], &host[1], &host[2], &host[3], &masks, smack); if (rc != 6) { rc = sscanf(data, "%hhd.%hhd.%hhd.%hhd %s", &host[0], &host[1], &host[2], &host[3], smack); @@ -1209,8 +1213,9 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, goto free_out; } m = BEBITS; + masks = 32; } - if (m > BEBITS) { + if (masks > BEBITS) { rc = -EINVAL; goto free_out; } @@ -1225,16 +1230,16 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, goto free_out; } } else { - /* check known options */ - if (strcmp(smack, smack_cipso_option.smk_known) == 0) - skp = &smack_cipso_option; - else { + /* + * Only the -CIPSO option is supported for IPv4 + */ + if (strcmp(smack, SMACK_CIPSO_OPTION) != 0) { rc = -EINVAL; goto free_out; } } - for (temp_mask = 0; m > 0; m--) { + for (m = masks, temp_mask = 0; m > 0; m--) { temp_mask |= mask_bits; mask_bits >>= 1; } @@ -1245,14 +1250,13 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, * Only allow one writer at a time. Writes should be * quite rare and small in any case. */ - mutex_lock(&smk_netlbladdr_lock); + mutex_lock(&smk_net4addr_lock); nsa = newname.sin_addr.s_addr; /* try to find if the prefix is already in the list */ found = 0; - list_for_each_entry_rcu(snp, &smk_netlbladdr_list, list) { - if (snp->smk_host.sin_addr.s_addr == nsa && - snp->smk_mask.s_addr == mask.s_addr) { + list_for_each_entry_rcu(snp, &smk_net4addr_list, list) { + if (snp->smk_host.s_addr == nsa && snp->smk_masks == masks) { found = 1; break; } @@ -1265,17 +1269,20 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, rc = -ENOMEM; else { rc = 0; - snp->smk_host.sin_addr.s_addr = newname.sin_addr.s_addr; + snp->smk_host.s_addr = newname.sin_addr.s_addr; snp->smk_mask.s_addr = mask.s_addr; snp->smk_label = skp; - smk_netlbladdr_insert(snp); + snp->smk_masks = masks; + smk_net4addr_insert(snp); } } else { - /* we delete the unlabeled entry, only if the previous label - * wasn't the special CIPSO option */ - if (snp->smk_label != &smack_cipso_option) + /* + * Delete the unlabeled entry, only if the previous label + * wasn't the special CIPSO option + */ + if (snp->smk_label != NULL) rc = netlbl_cfg_unlbl_static_del(&init_net, NULL, - &snp->smk_host.sin_addr, &snp->smk_mask, + &snp->smk_host, &snp->smk_mask, PF_INET, &audit_info); else rc = 0; @@ -1287,15 +1294,279 @@ static ssize_t smk_write_netlbladdr(struct file *file, const char __user *buf, * this host so that incoming packets get labeled. * but only if we didn't get the special CIPSO option */ - if (rc == 0 && skp != &smack_cipso_option) + if (rc == 0 && skp != NULL) rc = netlbl_cfg_unlbl_static_add(&init_net, NULL, - &snp->smk_host.sin_addr, &snp->smk_mask, PF_INET, + &snp->smk_host, &snp->smk_mask, PF_INET, snp->smk_label->smk_secid, &audit_info); if (rc == 0) rc = count; - mutex_unlock(&smk_netlbladdr_lock); + mutex_unlock(&smk_net4addr_lock); + +free_out: + kfree(smack); +free_data_out: + kfree(data); + + return rc; +} + +static const struct file_operations smk_net4addr_ops = { + .open = smk_open_net4addr, + .read = seq_read, + .llseek = seq_lseek, + .write = smk_write_net4addr, + .release = seq_release, +}; + +#if IS_ENABLED(CONFIG_IPV6) +/* + * Seq_file read operations for /smack/netlabel6 + */ + +static void *net6addr_seq_start(struct seq_file *s, loff_t *pos) +{ + return smk_seq_start(s, pos, &smk_net6addr_list); +} + +static void *net6addr_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + return smk_seq_next(s, v, pos, &smk_net6addr_list); +} + +/* + * Print host/label pairs + */ +static int net6addr_seq_show(struct seq_file *s, void *v) +{ + struct list_head *list = v; + struct smk_net6addr *skp = + list_entry(list, struct smk_net6addr, list); + + if (skp->smk_label != NULL) + seq_printf(s, "%pI6/%d %s\n", &skp->smk_host, skp->smk_masks, + skp->smk_label->smk_known); + + return 0; +} + +static const struct seq_operations net6addr_seq_ops = { + .start = net6addr_seq_start, + .next = net6addr_seq_next, + .show = net6addr_seq_show, + .stop = smk_seq_stop, +}; + +/** + * smk_open_net6addr - open() for /smack/netlabel + * @inode: inode structure representing file + * @file: "netlabel" file pointer + * + * Connect our net6addr_seq_* operations with /smack/netlabel + * file_operations + */ +static int smk_open_net6addr(struct inode *inode, struct file *file) +{ + return seq_open(file, &net6addr_seq_ops); +} + +/** + * smk_net6addr_insert + * @new : entry to insert + * + * This inserts an entry in the smack_net6addrs list + * sorted by netmask length (longest to smallest) + * locked by &smk_net6addr_lock in smk_write_net6addr + * + */ +static void smk_net6addr_insert(struct smk_net6addr *new) +{ + struct smk_net6addr *m_next; + struct smk_net6addr *m; + + if (list_empty(&smk_net6addr_list)) { + list_add_rcu(&new->list, &smk_net6addr_list); + return; + } + + m = list_entry_rcu(smk_net6addr_list.next, + struct smk_net6addr, list); + + if (new->smk_masks > m->smk_masks) { + list_add_rcu(&new->list, &smk_net6addr_list); + return; + } + + list_for_each_entry_rcu(m, &smk_net6addr_list, list) { + if (list_is_last(&m->list, &smk_net6addr_list)) { + list_add_rcu(&new->list, &m->list); + return; + } + m_next = list_entry_rcu(m->list.next, + struct smk_net6addr, list); + if (new->smk_masks > m_next->smk_masks) { + list_add_rcu(&new->list, &m->list); + return; + } + } +} + + +/** + * smk_write_net6addr - write() for /smack/netlabel + * @file: file pointer, not actually used + * @buf: where to get the data from + * @count: bytes sent + * @ppos: where to start + * + * Accepts only one net6addr per write call. + * Returns number of bytes written or error code, as appropriate + */ +static ssize_t smk_write_net6addr(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct smk_net6addr *snp; + struct in6_addr newname; + struct in6_addr fullmask; + struct smack_known *skp = NULL; + char *smack; + char *data; + int rc = 0; + int found = 0; + int i; + unsigned int scanned[8]; + unsigned int m; + unsigned int mask = 128; + + /* + * Must have privilege. + * No partial writes. + * Enough data must be present. + * " Remote Controller devices !Iinclude/media/rc-core.h diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 12629b8ecb0cd..c61a4f03a66f9 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -57,6 +57,25 @@ struct dvb_frontend; +/** + * struct dvb_adapter - represents a Digital TV adapter using Linux DVB API + * + * @num: Number of the adapter + * @list_head: List with the DVB adapters + * @device_list: List with the DVB devices + * @name: Name of the adapter + * @proposed_mac: proposed MAC address for the adapter + * @priv: private data + * @device: pointer to struct device + * @module: pointer to struct module + * @mfe_shared: mfe shared: indicates mutually exclusive frontends + * Thie usage of this flag is currently deprecated + * @mfe_dvbdev: Frontend device in use, in the case of MFE + * @mfe_lock: Lock to prevent using the other frontends when MFE is + * used. + * @mdev: pointer to struct media_device, used when the media + * controller is used. + */ struct dvb_adapter { int num; struct list_head list_head; @@ -78,7 +97,34 @@ struct dvb_adapter { #endif }; - +/** + * struct dvb_device - represents a DVB device node + * + * @list_head: List head with all DVB devices + * @fops: pointer to struct file_operations + * @adapter: pointer to the adapter that holds this device node + * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND, + * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET + * @minor: devnode minor number. Major number is always DVB_MAJOR. + * @id: device ID number, inside the adapter + * @readers: Initialized by the caller. Each call to open() in Read Only mode + * decreases this counter by one. + * @writers: Initialized by the caller. Each call to open() in Read/Write + * mode decreases this counter by one. + * @users: Initialized by the caller. Each call to open() in any mode + * decreases this counter by one. + * @wait_queue: wait queue, used to wait for certain events inside one of + * the DVB API callers + * @kernel_ioctl: callback function used to handle ioctl calls from userspace. + * @name: Name to be used for the device at the Media Controller + * @entity: pointer to struct media_entity associated with the device node + * @pads: pointer to struct media_pad associated with @entity; + * @priv: private data + * + * This structure is used by the DVB core (frontend, CA, net, demux) in + * order to create the device nodes. Usually, driver should not initialize + * this struct diretly. + */ struct dvb_device { struct list_head list_head; const struct file_operations *fops; @@ -109,19 +155,55 @@ struct dvb_device { void *priv; }; +/** + * dvb_register_adapter - Registers a new DVB adapter + * + * @adap: pointer to struct dvb_adapter + * @name: Adapter's name + * @module: initialized with THIS_MODULE at the caller + * @device: pointer to struct device that corresponds to the device driver + * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter; + * to select among them. Typically, initialized with: + * DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums) + */ +int dvb_register_adapter(struct dvb_adapter *adap, const char *name, + struct module *module, struct device *device, + short *adapter_nums); -extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name, - struct module *module, struct device *device, - short *adapter_nums); -extern int dvb_unregister_adapter (struct dvb_adapter *adap); - -extern int dvb_register_device (struct dvb_adapter *adap, - struct dvb_device **pdvbdev, - const struct dvb_device *template, - void *priv, - int type); +/** + * dvb_unregister_adapter - Unregisters a DVB adapter + * + * @adap: pointer to struct dvb_adapter + */ +int dvb_unregister_adapter(struct dvb_adapter *adap); -extern void dvb_unregister_device (struct dvb_device *dvbdev); +/** + * dvb_register_device - Registers a new DVB device + * + * @adap: pointer to struct dvb_adapter + * @pdvbdev: pointer to the place where the new struct dvb_device will be + * stored + * @template: Template used to create &pdvbdev; + * @device: pointer to struct device that corresponds to the device driver + * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter; + * to select among them. Typically, initialized with: + * DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums) + * @priv: private data + * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND, + * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET + */ +int dvb_register_device(struct dvb_adapter *adap, + struct dvb_device **pdvbdev, + const struct dvb_device *template, + void *priv, + int type); + +/** + * dvb_unregister_device - Unregisters a DVB device + * + * @dvbdev: pointer to struct dvb_device + */ +void dvb_unregister_device(struct dvb_device *dvbdev); #ifdef CONFIG_MEDIA_CONTROLLER_DVB void dvb_create_media_graph(struct dvb_adapter *adap); @@ -136,17 +218,17 @@ static inline void dvb_create_media_graph(struct dvb_adapter *adap) {} #define dvb_register_media_controller(a, b) {} #endif -extern int dvb_generic_open (struct inode *inode, struct file *file); -extern int dvb_generic_release (struct inode *inode, struct file *file); -extern long dvb_generic_ioctl (struct file *file, +int dvb_generic_open (struct inode *inode, struct file *file); +int dvb_generic_release (struct inode *inode, struct file *file); +long dvb_generic_ioctl (struct file *file, unsigned int cmd, unsigned long arg); /* we don't mess with video_usercopy() any more, we simply define out own dvb_usercopy(), which will hopefully become generic_usercopy() someday... */ -extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, - int (*func)(struct file *file, unsigned int cmd, void *arg)); +int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, + int (*func)(struct file *file, unsigned int cmd, void *arg)); /** generic DVB attach function. */ #ifdef CONFIG_MEDIA_ATTACH -- GitLab From 8e8114dee2a9a767ca8abc1c2d6a94a3ca5d4c7f Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 21 Aug 2015 11:48:21 +0300 Subject: [PATCH 4612/7006] iwlwifi: mvm: catch underflow error earlier My static checker complains that we don't check for underflows in iwl_dbgfs_fw_dbg_conf_write(). This is harmless because we have a sanity check in iwl_mvm_start_fw_dbg_conf(), but we may as well make this unsigned and silence the underflow warning. Signed-off-by: Dan Carpenter Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/debugfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c index ca4a1f8f82a5d..7d69a556bcc82 100644 --- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c @@ -949,9 +949,10 @@ static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm, char *buf, size_t count, loff_t *ppos) { - int ret, conf_id; + unsigned int conf_id; + int ret; - ret = kstrtoint(buf, 0, &conf_id); + ret = kstrtouint(buf, 0, &conf_id); if (ret) return ret; -- GitLab From ba537f98b5296cdb08ea98c23963201b3db14ed9 Mon Sep 17 00:00:00 2001 From: Sara Sharon Date: Wed, 19 Aug 2015 16:29:31 +0300 Subject: [PATCH 4613/7006] iwlwifi: mvm: update wakeup reason enum when waking from d0i3 there is a wakeup reason. Enum in driver is not up to date with FW api - fix it. Signed-off-by: Sara Sharon Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h index d7658d16e965c..20521bebb0b15 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h @@ -339,8 +339,13 @@ enum iwl_wowlan_wakeup_reason { IWL_WOWLAN_WAKEUP_BY_FOUR_WAY_HANDSHAKE = BIT(8), IWL_WOWLAN_WAKEUP_BY_REM_WAKE_LINK_LOSS = BIT(9), IWL_WOWLAN_WAKEUP_BY_REM_WAKE_SIGNATURE_TABLE = BIT(10), - /* BIT(11) reserved */ + IWL_WOWLAN_WAKEUP_BY_REM_WAKE_TCP_EXTERNAL = BIT(11), IWL_WOWLAN_WAKEUP_BY_REM_WAKE_WAKEUP_PACKET = BIT(12), + IWL_WOWLAN_WAKEUP_BY_IOAC_MAGIC_PACKET = BIT(13), + IWL_WOWLAN_WAKEUP_BY_D3_WAKEUP_HOST_TIMER = BIT(14), + IWL_WOWLAN_WAKEUP_BY_RXFRAME_FILTERED_IN = BIT(15), + IWL_WOWLAN_WAKEUP_BY_BEACON_FILTERED_IN = BIT(16), + }; /* WOWLAN_WAKE_UP_REASON_API_E_VER_2 */ struct iwl_wowlan_gtk_status { -- GitLab From 32c93a7057d600a06f96ff8997da1fadca65795a Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Wed, 19 Aug 2015 16:51:33 +0200 Subject: [PATCH 4614/7006] iwlwifi: correctly size command string arrays The command string array is assumed to be indexable by a full u8, so it must have 256 entries (0-255), not just 255. A recent firmware change (apparently) started using the command 0xff for a notification to the host, causing the driver to crash in debug message/tracing code. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/dvm/agn.h | 2 +- drivers/net/wireless/iwlwifi/dvm/rx.c | 2 +- drivers/net/wireless/iwlwifi/mvm/ops.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h index edc3dd42f8f86..991def878881d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/agn.h +++ b/drivers/net/wireless/iwlwifi/dvm/agn.h @@ -473,7 +473,7 @@ do { \ } while (0) #endif /* CONFIG_IWLWIFI_DEBUG */ -extern const char *const iwl_dvm_cmd_strings[REPLY_MAX]; +extern const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1]; static inline const char *iwl_dvm_get_cmd_string(u8 cmd) { diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index 4785203ae203d..4a45b0b594c75 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -39,7 +39,7 @@ #define IWL_CMD_ENTRY(x) [x] = #x -const char *const iwl_dvm_cmd_strings[REPLY_MAX] = { +const char *const iwl_dvm_cmd_strings[REPLY_MAX + 1] = { IWL_CMD_ENTRY(REPLY_ALIVE), IWL_CMD_ENTRY(REPLY_ERROR), IWL_CMD_ENTRY(REPLY_ECHO), diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 07e68929b005e..a37de3f410a01 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c @@ -268,7 +268,7 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = { #undef RX_HANDLER_GRP #define CMD(x) [x] = #x -static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = { +static const char *const iwl_mvm_cmd_strings[REPLY_MAX + 1] = { CMD(MVM_ALIVE), CMD(REPLY_ERROR), CMD(INIT_COMPLETE_NOTIF), -- GitLab From a7b3bc91c5b0a6a7eecfd33ac71e266c6fe897f8 Mon Sep 17 00:00:00 2001 From: Ayala Beker Date: Thu, 20 Aug 2015 04:00:38 +0300 Subject: [PATCH 4615/7006] iwlwifi: mvm: split debug message to avoid exceeding 110 characters split long debug messages that may result warning in tracing. Fixes: 1a84e7716086 ("iwlwifi: mvm: add debug info to schedule scan complete message.") Signed-off-by: Ayala Beker Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/mvm/scan.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c index 15055462cd110..56559d4d34ad1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/scan.c +++ b/drivers/net/wireless/iwlwifi/mvm/scan.c @@ -349,10 +349,11 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, if (mvm->scan_status & IWL_MVM_SCAN_STOPPING_SCHED) { WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_STOPPING_REGULAR); - IWL_DEBUG_SCAN(mvm, - "Scheduled scan %s, EBS status %s, Last line %d, Last iteration %d, Time after last iteration %d\n", + IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", aborted ? "aborted" : "completed", - iwl_mvm_ebs_status_str(scan_notif->ebs_status), + iwl_mvm_ebs_status_str(scan_notif->ebs_status)); + IWL_DEBUG_SCAN(mvm, + "Last line %d, Last iteration %d, Time after last iteration %d\n", scan_notif->last_schedule_line, scan_notif->last_schedule_iteration, __le32_to_cpu(scan_notif->time_after_last_iter)); @@ -367,10 +368,11 @@ void iwl_mvm_rx_lmac_scan_complete_notif(struct iwl_mvm *mvm, } else if (mvm->scan_status & IWL_MVM_SCAN_SCHED) { WARN_ON_ONCE(mvm->scan_status & IWL_MVM_SCAN_REGULAR); - IWL_DEBUG_SCAN(mvm, - "Scheduled scan %s, EBS status %s, Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", + IWL_DEBUG_SCAN(mvm, "Scheduled scan %s, EBS status %s\n", aborted ? "aborted" : "completed", - iwl_mvm_ebs_status_str(scan_notif->ebs_status), + iwl_mvm_ebs_status_str(scan_notif->ebs_status)); + IWL_DEBUG_SCAN(mvm, + "Last line %d, Last iteration %d, Time after last iteration %d (FW)\n", scan_notif->last_schedule_line, scan_notif->last_schedule_iteration, __le32_to_cpu(scan_notif->time_after_last_iter)); @@ -1346,11 +1348,13 @@ void iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm, mvm->scan_status &= ~mvm->scan_uid_status[uid]; IWL_DEBUG_SCAN(mvm, - "Scan completed, uid %u type %u, status %s, EBS status %s, Last line %d, Last iteration %d, Time from last iteration %d\n", + "Scan completed, uid %u type %u, status %s, EBS status %s\n", uid, mvm->scan_uid_status[uid], notif->status == IWL_SCAN_OFFLOAD_COMPLETED ? "completed" : "aborted", - iwl_mvm_ebs_status_str(notif->ebs_status), + iwl_mvm_ebs_status_str(notif->ebs_status)); + IWL_DEBUG_SCAN(mvm, + "Last line %d, Last iteration %d, Time from last iteration %d\n", notif->last_schedule, notif->last_iter, __le32_to_cpu(notif->time_from_last_iter)); -- GitLab From da03f0296c0c122cb91ed3c87a7efa4ea5127f22 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Tue, 18 Aug 2015 15:15:36 +0200 Subject: [PATCH 4616/7006] iwlwifi: mvm: support new TX power command Add support for the new (bigger) TX power command. This doesn't actually take advantage of the new capabilities (to set per-chain TX power limits) but makes the code compatible with newer firmware images expecting the larger command. Signed-off-by: Johannes Berg Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-fw-file.h | 3 ++ .../net/wireless/iwlwifi/mvm/fw-api-power.h | 29 ++++++++++++++++--- drivers/net/wireless/iwlwifi/mvm/mac80211.c | 15 ++++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h index 75809abee7598..84653e3d02bab 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h @@ -259,6 +259,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format * @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority * instead of 3. + * @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size + * (command version 3) that supports per-chain limits */ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_BT_COEX_SPLIT = (__force iwl_ucode_tlv_api_t)3, @@ -274,6 +276,7 @@ enum iwl_ucode_tlv_api { IWL_UCODE_TLV_API_STATS_V10 = (__force iwl_ucode_tlv_api_t)19, IWL_UCODE_TLV_API_NEW_VERSION = (__force iwl_ucode_tlv_api_t)20, IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY = (__force iwl_ucode_tlv_api_t)24, + IWL_UCODE_TLV_API_TX_POWER_CHAIN = (__force iwl_ucode_tlv_api_t)27, }; typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h index b86b1697d56f6..7005fa4be74a1 100644 --- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h +++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h @@ -7,6 +7,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as @@ -33,6 +34,7 @@ * * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH + * Copyright(c) 2015 Intel Deutschland GmbH * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -310,17 +312,22 @@ struct iwl_reduce_tx_power_cmd { __le16 pwr_restriction; } __packed; /* TX_REDUCED_POWER_API_S_VER_1 */ +enum iwl_dev_tx_power_cmd_mode { + IWL_TX_POWER_MODE_SET_MAC = 0, + IWL_TX_POWER_MODE_SET_DEVICE = 1, + IWL_TX_POWER_MODE_SET_CHAINS = 2, +}; /* TX_POWER_REDUCED_FLAGS_TYPE_API_E_VER_2 */; + /** - * struct iwl_dev_tx_power_cmd - TX power reduction command - * REDUCE_TX_POWER_CMD = 0x9f - * @set_mode: 0 - MAC tx power, 1 - device tx power + * struct iwl_dev_tx_power_cmd_v2 - TX power reduction command + * @set_mode: see &enum iwl_dev_tx_power_cmd_mode * @mac_context_id: id of the mac ctx for which we are reducing TX power. * @pwr_restriction: TX power restriction in 1/8 dBms. * @dev_24: device TX power restriction in 1/8 dBms * @dev_52_low: device TX power restriction upper band - low * @dev_52_high: device TX power restriction upper band - high */ -struct iwl_dev_tx_power_cmd { +struct iwl_dev_tx_power_cmd_v2 { __le32 set_mode; __le32 mac_context_id; __le16 pwr_restriction; @@ -329,6 +336,20 @@ struct iwl_dev_tx_power_cmd { __le16 dev_52_high; } __packed; /* TX_REDUCED_POWER_API_S_VER_2 */ +#define IWL_NUM_CHAIN_LIMITS 2 +#define IWL_NUM_SUB_BANDS 5 + +/** + * struct iwl_dev_tx_power_cmd - TX power reduction command + * @v2: version 2 of the command, embedded here for easier software handling + * @per_chain_restriction: per chain restrictions + */ +struct iwl_dev_tx_power_cmd { + /* v3 is just an extension of v2 - keep this here */ + struct iwl_dev_tx_power_cmd_v2 v2; + __le16 per_chain_restriction[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS]; +} __packed; /* TX_REDUCED_POWER_API_S_VER_3 */ + #define IWL_DEV_MAX_TX_POWER 0x7FFF /** diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 537a15719d45f..aa8c2b7f23c73 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c @@ -1595,20 +1595,23 @@ static int iwl_mvm_set_tx_power(struct iwl_mvm *mvm, struct ieee80211_vif *vif, s16 tx_power) { struct iwl_dev_tx_power_cmd cmd = { - .set_mode = 0, - .mac_context_id = + .v2.set_mode = cpu_to_le32(IWL_TX_POWER_MODE_SET_MAC), + .v2.mac_context_id = cpu_to_le32(iwl_mvm_vif_from_mac80211(vif)->id), - .pwr_restriction = cpu_to_le16(8 * tx_power), + .v2.pwr_restriction = cpu_to_le16(8 * tx_power), }; + int len = sizeof(cmd); if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_DEV)) return iwl_mvm_set_tx_power_old(mvm, vif, tx_power); if (tx_power == IWL_DEFAULT_MAX_TX_POWER) - cmd.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); + cmd.v2.pwr_restriction = cpu_to_le16(IWL_DEV_MAX_TX_POWER); - return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, - sizeof(cmd), &cmd); + if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_TX_POWER_CHAIN)) + len = sizeof(cmd.v2); + + return iwl_mvm_send_cmd_pdu(mvm, REDUCE_TX_POWER_CMD, 0, len, &cmd); } static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw, -- GitLab From e57690b1aeb208642d00f9b378830b26c9585caf Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 23 Aug 2015 11:52:49 +0530 Subject: [PATCH 4617/7006] ALSA: hdac: Fix size allocation for ext device allocation While creating hdac_ext_device, we used hdev for sizeof insteadof edev, which resulted in eventual crash of the system Fix the size here Fixes: a512f5611646 ('ALSA: hdac: add hdac extended device') Reported-by: Subhransu S. Prusty Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- sound/hda/ext/hdac_ext_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/hda/ext/hdac_ext_bus.c b/sound/hda/ext/hdac_ext_bus.c index 8544e4fb1cd3b..4449d1a990893 100644 --- a/sound/hda/ext/hdac_ext_bus.c +++ b/sound/hda/ext/hdac_ext_bus.c @@ -139,7 +139,7 @@ int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *ebus, int addr) char name[15]; int ret; - edev = kzalloc(sizeof(*hdev), GFP_KERNEL); + edev = kzalloc(sizeof(*edev), GFP_KERNEL); if (!edev) return -ENOMEM; hdev = &edev->hdac; -- GitLab From 54d1d2f5f0886f7c31512c83a6ed87bbcd0d2b3a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Sun, 23 Aug 2015 11:52:50 +0530 Subject: [PATCH 4618/7006] ALSA: hdac: fix the spbmaxfifo API spbmaxfifo API is actually a query function not a set function so name it snd_hdac_ext_stream_get_spbmaxfifo() Reported-by: Pierre-Louis Bossart Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/hdaudio_ext.h | 2 +- sound/hda/ext/hdac_ext_stream.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/sound/hdaudio_ext.h b/include/sound/hdaudio_ext.h index 9385c99a65041..94210dcdb6eac 100644 --- a/include/sound/hdaudio_ext.h +++ b/include/sound/hdaudio_ext.h @@ -107,7 +107,7 @@ void snd_hdac_ext_stop_streams(struct hdac_ext_bus *sbus); int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream, u32 value); -int snd_hdac_ext_stream_set_spbmaxfifo(struct hdac_ext_bus *ebus, +int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream); void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream); diff --git a/sound/hda/ext/hdac_ext_stream.c b/sound/hda/ext/hdac_ext_stream.c index c978a9bb1db83..33ba77dd32f2f 100644 --- a/sound/hda/ext/hdac_ext_stream.c +++ b/sound/hda/ext/hdac_ext_stream.c @@ -461,13 +461,13 @@ int snd_hdac_ext_stream_set_spib(struct hdac_ext_bus *ebus, EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spib); /** - * snd_hdac_ext_stream_set_spbmaxfifo - sets the spib value of a stream + * snd_hdac_ext_stream_get_spbmaxfifo - gets the spib value of a stream * @ebus: HD-audio ext core bus * @stream: hdac_ext_stream * * Return maxfifo for the stream */ -int snd_hdac_ext_stream_set_spbmaxfifo(struct hdac_ext_bus *ebus, +int snd_hdac_ext_stream_get_spbmaxfifo(struct hdac_ext_bus *ebus, struct hdac_ext_stream *stream) { struct hdac_bus *bus = &ebus->bus; @@ -479,7 +479,7 @@ int snd_hdac_ext_stream_set_spbmaxfifo(struct hdac_ext_bus *ebus, return readl(stream->fifo_addr); } -EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_set_spbmaxfifo); +EXPORT_SYMBOL_GPL(snd_hdac_ext_stream_get_spbmaxfifo); /** -- GitLab From 4308c9b083fbab1a442e68a03de099841791df27 Mon Sep 17 00:00:00 2001 From: Jeeja KP Date: Sun, 23 Aug 2015 11:52:51 +0530 Subject: [PATCH 4619/7006] ALSA: hdac: Add snd_hdac_get_hdac_stream() Add a helper to find the stream using stream tag and direction. This is useful for drivers to query stream based on stream tag and direction, fox example while downloading FW thru DSP loader code Signed-off-by: Jeeja KP Signed-off-by: Vinod Koul Signed-off-by: Takashi Iwai --- include/sound/hdaudio.h | 2 ++ sound/hda/hdac_stream.c | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 23a44c39c51c3..49bc836fcd848 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h @@ -438,6 +438,8 @@ void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev, struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus, struct snd_pcm_substream *substream); void snd_hdac_stream_release(struct hdac_stream *azx_dev); +struct hdac_stream *snd_hdac_get_stream(struct hdac_bus *bus, + int dir, int stream_tag); int snd_hdac_stream_setup(struct hdac_stream *azx_dev); void snd_hdac_stream_cleanup(struct hdac_stream *azx_dev); diff --git a/sound/hda/hdac_stream.c b/sound/hda/hdac_stream.c index 4c15d0accc9e2..8981159813efb 100644 --- a/sound/hda/hdac_stream.c +++ b/sound/hda/hdac_stream.c @@ -286,6 +286,28 @@ void snd_hdac_stream_release(struct hdac_stream *azx_dev) } EXPORT_SYMBOL_GPL(snd_hdac_stream_release); +/** + * snd_hdac_get_stream - return hdac_stream based on stream_tag and + * direction + * + * @bus: HD-audio core bus + * @dir: direction for the stream to be found + * @stream_tag: stream tag for stream to be found + */ +struct hdac_stream *snd_hdac_get_stream(struct hdac_bus *bus, + int dir, int stream_tag) +{ + struct hdac_stream *s; + + list_for_each_entry(s, &bus->stream_list, list) { + if (s->direction == dir && s->stream_tag == stream_tag) + return s; + } + + return NULL; +} +EXPORT_SYMBOL_GPL(snd_hdac_get_stream); + /* * set up a BDL entry */ -- GitLab From 5865f3658ba37c54e346b0fdee08a1c7a152681b Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Sun, 23 Aug 2015 12:54:16 +0300 Subject: [PATCH 4620/7006] iwlwifi: mvm: bump firmware API to 17 The driver is now able to handle -17.ucode. Signed-off-by: Emmanuel Grumbach --- drivers/net/wireless/iwlwifi/iwl-7000.c | 2 +- drivers/net/wireless/iwlwifi/iwl-8000.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c index 413b63e09717a..6951aba620eb7 100644 --- a/drivers/net/wireless/iwlwifi/iwl-7000.c +++ b/drivers/net/wireless/iwlwifi/iwl-7000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL7260_UCODE_API_MAX 16 +#define IWL7260_UCODE_API_MAX 17 /* Oldest version we won't warn about */ #define IWL7260_UCODE_API_OK 12 diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c index 8324bc8987a94..197abe43ddc53 100644 --- a/drivers/net/wireless/iwlwifi/iwl-8000.c +++ b/drivers/net/wireless/iwlwifi/iwl-8000.c @@ -69,7 +69,7 @@ #include "iwl-agn-hw.h" /* Highest firmware API version supported */ -#define IWL8000_UCODE_API_MAX 16 +#define IWL8000_UCODE_API_MAX 17 /* Oldest version we won't warn about */ #define IWL8000_UCODE_API_OK 12 -- GitLab From 43bcad2bb485f053661e5cfe306c34178c6651c7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Aug 2015 17:39:12 +0200 Subject: [PATCH 4621/7006] devicetree: Add bindings documentation for Analog Devices AXI-DMAC Add the devicetree descriptor for the Analog Devices AXI-DMAC DMA controller. This is a soft peripheral used in FPGAs and the bindings describe how it is connected to the system (clock, interrupt, memory map) as well as the configuration options that were used when the peripheral was instantiated. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- .../devicetree/bindings/dma/adi,axi-dmac.txt | 61 +++++++++++++++++++ include/dt-bindings/dma/axi-dmac.h | 48 +++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 Documentation/devicetree/bindings/dma/adi,axi-dmac.txt create mode 100644 include/dt-bindings/dma/axi-dmac.h diff --git a/Documentation/devicetree/bindings/dma/adi,axi-dmac.txt b/Documentation/devicetree/bindings/dma/adi,axi-dmac.txt new file mode 100644 index 0000000000000..47cb1d14b690f --- /dev/null +++ b/Documentation/devicetree/bindings/dma/adi,axi-dmac.txt @@ -0,0 +1,61 @@ +Analog Device AXI-DMAC DMA controller + +Required properties: + - compatible: Must be "adi,axi-dmac-1.00.a". + - reg: Specification for the controllers memory mapped register map. + - interrupts: Specification for the controllers interrupt. + - clocks: Phandle and specifier to the controllers AXI interface clock + - #dma-cells: Must be 1. + +Required sub-nodes: + - adi,channels: This sub-node must contain a sub-node for each DMA channel. For + the channel sub-nodes the following bindings apply. They must match the + configuration options of the peripheral as it was instantiated. + +Required properties for adi,channels sub-node: + - #size-cells: Must be 0 + - #address-cells: Must be 1 + +Required channel sub-node properties: + - reg: Which channel this node refers to. + - adi,length-width: Width of the DMA transfer length register. + - adi,source-bus-width, + adi,destination-bus-width: Width of the source or destination bus in bits. + - adi,source-bus-type, + adi,destination-bus-type: Type of the source or destination bus. Must be one + of the following: + 0 (AXI_DMAC_TYPE_AXI_MM): Memory mapped AXI interface + 1 (AXI_DMAC_TYPE_AXI_STREAM): Streaming AXI interface + 2 (AXI_DMAC_TYPE_AXI_FIFO): FIFO interface + +Optional channel properties: + - adi,cyclic: Must be set if the channel supports hardware cyclic DMA + transfers. + - adi,2d: Must be set if the channel supports hardware 2D DMA transfers. + +DMA clients connected to the AXI-DMAC DMA controller must use the format +described in the dma.txt file using a one-cell specifier. The value of the +specifier refers to the DMA channel index. + +Example: + +dma: dma@7c420000 { + compatible = "adi,axi-dmac-1.00.a"; + reg = <0x7c420000 0x10000>; + interrupts = <0 57 0>; + clocks = <&clkc 16>; + #dma-cells = <1>; + + adi,channels { + #size-cells = <0>; + #address-cells = <1>; + + dma-channel@0 { + reg = <0>; + adi,source-bus-width = <32>; + adi,source-bus-type = ; + adi,destination-bus-width = <64>; + adi,destination-bus-type = ; + }; + }; +}; diff --git a/include/dt-bindings/dma/axi-dmac.h b/include/dt-bindings/dma/axi-dmac.h new file mode 100644 index 0000000000000..ad9e6ecb9c2f2 --- /dev/null +++ b/include/dt-bindings/dma/axi-dmac.h @@ -0,0 +1,48 @@ +/* + * This file is dual-licensed: you can use it either under the terms + * of the GPL or the X11 license, at your option. Note that this dual + * licensing only applies to this file, and not this project as a + * whole. + * + * a) This file 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. + * + * This file is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * Or, alternatively, + * + * b) 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 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. + */ + +#ifndef __DT_BINDINGS_DMA_AXI_DMAC_H__ +#define __DT_BINDINGS_DMA_AXI_DMAC_H__ + +#define AXI_DMAC_BUS_TYPE_AXI_MM 0 +#define AXI_DMAC_BUS_TYPE_AXI_STREAM 1 +#define AXI_DMAC_BUS_TYPE_FIFO 2 + +#endif -- GitLab From 0e3b67b348b838d519b5d9ff30261f471d6371f2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Thu, 20 Aug 2015 17:39:13 +0200 Subject: [PATCH 4622/7006] dmaengine: Add support for the Analog Devices AXI-DMAC DMA controller Add support for the Analog Devices AXI-DMAC DMA controller. This controller is a soft peripheral that can be instantiated in a FPGA and is often used in Analog Devices' reference designs for FPGA platforms. The peripheral has various configuration options that can be selected at synthesis time and influence the supported features of the instantiated peripheral, those options are represented as device-tree properties to allow the driver to behave accordingly. The peripheral has a zero latency architecture, which means it is possible to switch from one to the next descriptor without any delay. This is archived by having a internal queue which can hold multiple descriptors. The driver supports this, which means it will submit new descriptors directly to the hardware until the queue is full and not wait for a descriptor to complete before the next one is submitted. Interrupts are used for the descriptor queue flow control. Currently the driver supports SG, cyclic and interleaved slave DMA. Signed-off-by: Lars-Peter Clausen Signed-off-by: Vinod Koul --- MAINTAINERS | 6 + drivers/dma/Kconfig | 10 + drivers/dma/Makefile | 1 + drivers/dma/dma-axi-dmac.c | 691 +++++++++++++++++++++++++++++++++++++ 4 files changed, 708 insertions(+) create mode 100644 drivers/dma/dma-axi-dmac.c diff --git a/MAINTAINERS b/MAINTAINERS index 8133cefb6b6e2..9a5ef2b3e9ddb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -728,6 +728,12 @@ X: drivers/iio/*/adjd* F: drivers/staging/iio/*/ad* F: staging/iio/trigger/iio-trig-bfin-timer.c +ANALOG DEVICES INC DMA DRIVERS +M: Lars-Peter Clausen +W: http://ez.analog.com/community/linux-device-drivers +S: Supported +F: drivers/dma/dma-axi-dmac.c + ANDROID DRIVERS M: Greg Kroah-Hartman M: Arve Hjønnevåg diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 84682538610e1..81e1937fcd6de 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -534,4 +534,14 @@ config QCOM_BAM_DMA Enable support for the QCOM BAM DMA controller. This controller provides DMA capabilities for a variety of on-chip devices. +config AXI_DMAC + tristate "Analog Devices AXI-DMAC DMA support" + depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_SOCFPGA || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for the Analog Devices AXI-DMAC peripheral. This DMA + controller is often used in Analog Device's reference designs for FPGA + platforms. + endif diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index d056a8ad6ab17..a4809849b6c5e 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ZX_DMA) += zx296702_dma.o +obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o diff --git a/drivers/dma/dma-axi-dmac.c b/drivers/dma/dma-axi-dmac.c new file mode 100644 index 0000000000000..5b2395e7e04d8 --- /dev/null +++ b/drivers/dma/dma-axi-dmac.c @@ -0,0 +1,691 @@ +/* + * Driver for the Analog Devices AXI-DMAC core + * + * Copyright 2013-2015 Analog Devices Inc. + * Author: Lars-Peter Clausen + * + * Licensed under the GPL-2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "dmaengine.h" +#include "virt-dma.h" + +/* + * The AXI-DMAC is a soft IP core that is used in FPGA designs. The core has + * various instantiation parameters which decided the exact feature set support + * by the core. + * + * Each channel of the core has a source interface and a destination interface. + * The number of channels and the type of the channel interfaces is selected at + * configuration time. A interface can either be a connected to a central memory + * interconnect, which allows access to system memory, or it can be connected to + * a dedicated bus which is directly connected to a data port on a peripheral. + * Given that those are configuration options of the core that are selected when + * it is instantiated this means that they can not be changed by software at + * runtime. By extension this means that each channel is uni-directional. It can + * either be device to memory or memory to device, but not both. Also since the + * device side is a dedicated data bus only connected to a single peripheral + * there is no address than can or needs to be configured for the device side. + */ + +#define AXI_DMAC_REG_IRQ_MASK 0x80 +#define AXI_DMAC_REG_IRQ_PENDING 0x84 +#define AXI_DMAC_REG_IRQ_SOURCE 0x88 + +#define AXI_DMAC_REG_CTRL 0x400 +#define AXI_DMAC_REG_TRANSFER_ID 0x404 +#define AXI_DMAC_REG_START_TRANSFER 0x408 +#define AXI_DMAC_REG_FLAGS 0x40c +#define AXI_DMAC_REG_DEST_ADDRESS 0x410 +#define AXI_DMAC_REG_SRC_ADDRESS 0x414 +#define AXI_DMAC_REG_X_LENGTH 0x418 +#define AXI_DMAC_REG_Y_LENGTH 0x41c +#define AXI_DMAC_REG_DEST_STRIDE 0x420 +#define AXI_DMAC_REG_SRC_STRIDE 0x424 +#define AXI_DMAC_REG_TRANSFER_DONE 0x428 +#define AXI_DMAC_REG_ACTIVE_TRANSFER_ID 0x42c +#define AXI_DMAC_REG_STATUS 0x430 +#define AXI_DMAC_REG_CURRENT_SRC_ADDR 0x434 +#define AXI_DMAC_REG_CURRENT_DEST_ADDR 0x438 + +#define AXI_DMAC_CTRL_ENABLE BIT(0) +#define AXI_DMAC_CTRL_PAUSE BIT(1) + +#define AXI_DMAC_IRQ_SOT BIT(0) +#define AXI_DMAC_IRQ_EOT BIT(1) + +#define AXI_DMAC_FLAG_CYCLIC BIT(0) + +struct axi_dmac_sg { + dma_addr_t src_addr; + dma_addr_t dest_addr; + unsigned int x_len; + unsigned int y_len; + unsigned int dest_stride; + unsigned int src_stride; + unsigned int id; +}; + +struct axi_dmac_desc { + struct virt_dma_desc vdesc; + bool cyclic; + + unsigned int num_submitted; + unsigned int num_completed; + unsigned int num_sgs; + struct axi_dmac_sg sg[]; +}; + +struct axi_dmac_chan { + struct virt_dma_chan vchan; + + struct axi_dmac_desc *next_desc; + struct list_head active_descs; + enum dma_transfer_direction direction; + + unsigned int src_width; + unsigned int dest_width; + unsigned int src_type; + unsigned int dest_type; + + unsigned int max_length; + unsigned int align_mask; + + bool hw_cyclic; + bool hw_2d; +}; + +struct axi_dmac { + void __iomem *base; + int irq; + + struct clk *clk; + + struct dma_device dma_dev; + struct axi_dmac_chan chan; + + struct device_dma_parameters dma_parms; +}; + +static struct axi_dmac *chan_to_axi_dmac(struct axi_dmac_chan *chan) +{ + return container_of(chan->vchan.chan.device, struct axi_dmac, + dma_dev); +} + +static struct axi_dmac_chan *to_axi_dmac_chan(struct dma_chan *c) +{ + return container_of(c, struct axi_dmac_chan, vchan.chan); +} + +static struct axi_dmac_desc *to_axi_dmac_desc(struct virt_dma_desc *vdesc) +{ + return container_of(vdesc, struct axi_dmac_desc, vdesc); +} + +static void axi_dmac_write(struct axi_dmac *axi_dmac, unsigned int reg, + unsigned int val) +{ + writel(val, axi_dmac->base + reg); +} + +static int axi_dmac_read(struct axi_dmac *axi_dmac, unsigned int reg) +{ + return readl(axi_dmac->base + reg); +} + +static int axi_dmac_src_is_mem(struct axi_dmac_chan *chan) +{ + return chan->src_type == AXI_DMAC_BUS_TYPE_AXI_MM; +} + +static int axi_dmac_dest_is_mem(struct axi_dmac_chan *chan) +{ + return chan->dest_type == AXI_DMAC_BUS_TYPE_AXI_MM; +} + +static bool axi_dmac_check_len(struct axi_dmac_chan *chan, unsigned int len) +{ + if (len == 0 || len > chan->max_length) + return false; + if ((len & chan->align_mask) != 0) /* Not aligned */ + return false; + return true; +} + +static bool axi_dmac_check_addr(struct axi_dmac_chan *chan, dma_addr_t addr) +{ + if ((addr & chan->align_mask) != 0) /* Not aligned */ + return false; + return true; +} + +static void axi_dmac_start_transfer(struct axi_dmac_chan *chan) +{ + struct axi_dmac *dmac = chan_to_axi_dmac(chan); + struct virt_dma_desc *vdesc; + struct axi_dmac_desc *desc; + struct axi_dmac_sg *sg; + unsigned int flags = 0; + unsigned int val; + + val = axi_dmac_read(dmac, AXI_DMAC_REG_START_TRANSFER); + if (val) /* Queue is full, wait for the next SOT IRQ */ + return; + + desc = chan->next_desc; + + if (!desc) { + vdesc = vchan_next_desc(&chan->vchan); + if (!vdesc) + return; + list_move_tail(&vdesc->node, &chan->active_descs); + desc = to_axi_dmac_desc(vdesc); + } + sg = &desc->sg[desc->num_submitted]; + + desc->num_submitted++; + if (desc->num_submitted == desc->num_sgs) + chan->next_desc = NULL; + else + chan->next_desc = desc; + + sg->id = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_ID); + + if (axi_dmac_dest_is_mem(chan)) { + axi_dmac_write(dmac, AXI_DMAC_REG_DEST_ADDRESS, sg->dest_addr); + axi_dmac_write(dmac, AXI_DMAC_REG_DEST_STRIDE, sg->dest_stride); + } + + if (axi_dmac_src_is_mem(chan)) { + axi_dmac_write(dmac, AXI_DMAC_REG_SRC_ADDRESS, sg->src_addr); + axi_dmac_write(dmac, AXI_DMAC_REG_SRC_STRIDE, sg->src_stride); + } + + /* + * If the hardware supports cyclic transfers and there is no callback to + * call, enable hw cyclic mode to avoid unnecessary interrupts. + */ + if (chan->hw_cyclic && desc->cyclic && !desc->vdesc.tx.callback) + flags |= AXI_DMAC_FLAG_CYCLIC; + + axi_dmac_write(dmac, AXI_DMAC_REG_X_LENGTH, sg->x_len - 1); + axi_dmac_write(dmac, AXI_DMAC_REG_Y_LENGTH, sg->y_len - 1); + axi_dmac_write(dmac, AXI_DMAC_REG_FLAGS, flags); + axi_dmac_write(dmac, AXI_DMAC_REG_START_TRANSFER, 1); +} + +static struct axi_dmac_desc *axi_dmac_active_desc(struct axi_dmac_chan *chan) +{ + return list_first_entry_or_null(&chan->active_descs, + struct axi_dmac_desc, vdesc.node); +} + +static void axi_dmac_transfer_done(struct axi_dmac_chan *chan, + unsigned int completed_transfers) +{ + struct axi_dmac_desc *active; + struct axi_dmac_sg *sg; + + active = axi_dmac_active_desc(chan); + if (!active) + return; + + if (active->cyclic) { + vchan_cyclic_callback(&active->vdesc); + } else { + do { + sg = &active->sg[active->num_completed]; + if (!(BIT(sg->id) & completed_transfers)) + break; + active->num_completed++; + if (active->num_completed == active->num_sgs) { + list_del(&active->vdesc.node); + vchan_cookie_complete(&active->vdesc); + active = axi_dmac_active_desc(chan); + } + } while (active); + } +} + +static irqreturn_t axi_dmac_interrupt_handler(int irq, void *devid) +{ + struct axi_dmac *dmac = devid; + unsigned int pending; + + pending = axi_dmac_read(dmac, AXI_DMAC_REG_IRQ_PENDING); + axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_PENDING, pending); + + spin_lock(&dmac->chan.vchan.lock); + /* One or more transfers have finished */ + if (pending & AXI_DMAC_IRQ_EOT) { + unsigned int completed; + + completed = axi_dmac_read(dmac, AXI_DMAC_REG_TRANSFER_DONE); + axi_dmac_transfer_done(&dmac->chan, completed); + } + /* Space has become available in the descriptor queue */ + if (pending & AXI_DMAC_IRQ_SOT) + axi_dmac_start_transfer(&dmac->chan); + spin_unlock(&dmac->chan.vchan.lock); + + return IRQ_HANDLED; +} + +static int axi_dmac_terminate_all(struct dma_chan *c) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac *dmac = chan_to_axi_dmac(chan); + unsigned long flags; + LIST_HEAD(head); + + spin_lock_irqsave(&chan->vchan.lock, flags); + axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, 0); + chan->next_desc = NULL; + vchan_get_all_descriptors(&chan->vchan, &head); + list_splice_tail_init(&chan->active_descs, &head); + spin_unlock_irqrestore(&chan->vchan.lock, flags); + + vchan_dma_desc_free_list(&chan->vchan, &head); + + return 0; +} + +static void axi_dmac_issue_pending(struct dma_chan *c) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac *dmac = chan_to_axi_dmac(chan); + unsigned long flags; + + axi_dmac_write(dmac, AXI_DMAC_REG_CTRL, AXI_DMAC_CTRL_ENABLE); + + spin_lock_irqsave(&chan->vchan.lock, flags); + if (vchan_issue_pending(&chan->vchan)) + axi_dmac_start_transfer(chan); + spin_unlock_irqrestore(&chan->vchan.lock, flags); +} + +static struct axi_dmac_desc *axi_dmac_alloc_desc(unsigned int num_sgs) +{ + struct axi_dmac_desc *desc; + + desc = kzalloc(sizeof(struct axi_dmac_desc) + + sizeof(struct axi_dmac_sg) * num_sgs, GFP_NOWAIT); + if (!desc) + return NULL; + + desc->num_sgs = num_sgs; + + return desc; +} + +static struct dma_async_tx_descriptor *axi_dmac_prep_slave_sg( + struct dma_chan *c, struct scatterlist *sgl, + unsigned int sg_len, enum dma_transfer_direction direction, + unsigned long flags, void *context) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac_desc *desc; + struct scatterlist *sg; + unsigned int i; + + if (direction != chan->direction) + return NULL; + + desc = axi_dmac_alloc_desc(sg_len); + if (!desc) + return NULL; + + for_each_sg(sgl, sg, sg_len, i) { + if (!axi_dmac_check_addr(chan, sg_dma_address(sg)) || + !axi_dmac_check_len(chan, sg_dma_len(sg))) { + kfree(desc); + return NULL; + } + + if (direction == DMA_DEV_TO_MEM) + desc->sg[i].dest_addr = sg_dma_address(sg); + else + desc->sg[i].src_addr = sg_dma_address(sg); + desc->sg[i].x_len = sg_dma_len(sg); + desc->sg[i].y_len = 1; + } + + desc->cyclic = false; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static struct dma_async_tx_descriptor *axi_dmac_prep_dma_cyclic( + struct dma_chan *c, dma_addr_t buf_addr, size_t buf_len, + size_t period_len, enum dma_transfer_direction direction, + unsigned long flags) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac_desc *desc; + unsigned int num_periods, i; + + if (direction != chan->direction) + return NULL; + + if (!axi_dmac_check_len(chan, buf_len) || + !axi_dmac_check_addr(chan, buf_addr)) + return NULL; + + if (period_len == 0 || buf_len % period_len) + return NULL; + + num_periods = buf_len / period_len; + + desc = axi_dmac_alloc_desc(num_periods); + if (!desc) + return NULL; + + for (i = 0; i < num_periods; i++) { + if (direction == DMA_DEV_TO_MEM) + desc->sg[i].dest_addr = buf_addr; + else + desc->sg[i].src_addr = buf_addr; + desc->sg[i].x_len = period_len; + desc->sg[i].y_len = 1; + buf_addr += period_len; + } + + desc->cyclic = true; + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static struct dma_async_tx_descriptor *axi_dmac_prep_interleaved( + struct dma_chan *c, struct dma_interleaved_template *xt, + unsigned long flags) +{ + struct axi_dmac_chan *chan = to_axi_dmac_chan(c); + struct axi_dmac_desc *desc; + size_t dst_icg, src_icg; + + if (xt->frame_size != 1) + return NULL; + + if (xt->dir != chan->direction) + return NULL; + + if (axi_dmac_src_is_mem(chan)) { + if (!xt->src_inc || !axi_dmac_check_addr(chan, xt->src_start)) + return NULL; + } + + if (axi_dmac_dest_is_mem(chan)) { + if (!xt->dst_inc || !axi_dmac_check_addr(chan, xt->dst_start)) + return NULL; + } + + dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]); + src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]); + + if (chan->hw_2d) { + if (!axi_dmac_check_len(chan, xt->sgl[0].size) || + !axi_dmac_check_len(chan, xt->numf)) + return NULL; + if (xt->sgl[0].size + dst_icg > chan->max_length || + xt->sgl[0].size + src_icg > chan->max_length) + return NULL; + } else { + if (dst_icg != 0 || src_icg != 0) + return NULL; + if (chan->max_length / xt->sgl[0].size < xt->numf) + return NULL; + if (!axi_dmac_check_len(chan, xt->sgl[0].size * xt->numf)) + return NULL; + } + + desc = axi_dmac_alloc_desc(1); + if (!desc) + return NULL; + + if (axi_dmac_src_is_mem(chan)) { + desc->sg[0].src_addr = xt->src_start; + desc->sg[0].src_stride = xt->sgl[0].size + src_icg; + } + + if (axi_dmac_dest_is_mem(chan)) { + desc->sg[0].dest_addr = xt->dst_start; + desc->sg[0].dest_stride = xt->sgl[0].size + dst_icg; + } + + if (chan->hw_2d) { + desc->sg[0].x_len = xt->sgl[0].size; + desc->sg[0].y_len = xt->numf; + } else { + desc->sg[0].x_len = xt->sgl[0].size * xt->numf; + desc->sg[0].y_len = 1; + } + + return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); +} + +static void axi_dmac_free_chan_resources(struct dma_chan *c) +{ + vchan_free_chan_resources(to_virt_chan(c)); +} + +static void axi_dmac_desc_free(struct virt_dma_desc *vdesc) +{ + kfree(container_of(vdesc, struct axi_dmac_desc, vdesc)); +} + +/* + * The configuration stored in the devicetree matches the configuration + * parameters of the peripheral instance and allows the driver to know which + * features are implemented and how it should behave. + */ +static int axi_dmac_parse_chan_dt(struct device_node *of_chan, + struct axi_dmac_chan *chan) +{ + u32 val; + int ret; + + ret = of_property_read_u32(of_chan, "reg", &val); + if (ret) + return ret; + + /* We only support 1 channel for now */ + if (val != 0) + return -EINVAL; + + ret = of_property_read_u32(of_chan, "adi,source-bus-type", &val); + if (ret) + return ret; + if (val > AXI_DMAC_BUS_TYPE_FIFO) + return -EINVAL; + chan->src_type = val; + + ret = of_property_read_u32(of_chan, "adi,destination-bus-type", &val); + if (ret) + return ret; + if (val > AXI_DMAC_BUS_TYPE_FIFO) + return -EINVAL; + chan->dest_type = val; + + ret = of_property_read_u32(of_chan, "adi,source-bus-width", &val); + if (ret) + return ret; + chan->src_width = val / 8; + + ret = of_property_read_u32(of_chan, "adi,destination-bus-width", &val); + if (ret) + return ret; + chan->dest_width = val / 8; + + ret = of_property_read_u32(of_chan, "adi,length-width", &val); + if (ret) + return ret; + + if (val >= 32) + chan->max_length = UINT_MAX; + else + chan->max_length = (1ULL << val) - 1; + + chan->align_mask = max(chan->dest_width, chan->src_width) - 1; + + if (axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan)) + chan->direction = DMA_MEM_TO_MEM; + else if (!axi_dmac_dest_is_mem(chan) && axi_dmac_src_is_mem(chan)) + chan->direction = DMA_MEM_TO_DEV; + else if (axi_dmac_dest_is_mem(chan) && !axi_dmac_src_is_mem(chan)) + chan->direction = DMA_DEV_TO_MEM; + else + chan->direction = DMA_DEV_TO_DEV; + + chan->hw_cyclic = of_property_read_bool(of_chan, "adi,cyclic"); + chan->hw_2d = of_property_read_bool(of_chan, "adi,2d"); + + return 0; +} + +static int axi_dmac_probe(struct platform_device *pdev) +{ + struct device_node *of_channels, *of_chan; + struct dma_device *dma_dev; + struct axi_dmac *dmac; + struct resource *res; + int ret; + + dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL); + if (!dmac) + return -ENOMEM; + + dmac->irq = platform_get_irq(pdev, 0); + if (dmac->irq <= 0) + return -EINVAL; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dmac->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dmac->base)) + return PTR_ERR(dmac->base); + + dmac->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(dmac->clk)) + return PTR_ERR(dmac->clk); + + INIT_LIST_HEAD(&dmac->chan.active_descs); + + of_channels = of_get_child_by_name(pdev->dev.of_node, "adi,channels"); + if (of_channels == NULL) + return -ENODEV; + + for_each_child_of_node(of_channels, of_chan) { + ret = axi_dmac_parse_chan_dt(of_chan, &dmac->chan); + if (ret) { + of_node_put(of_chan); + of_node_put(of_channels); + return -EINVAL; + } + } + of_node_put(of_channels); + + pdev->dev.dma_parms = &dmac->dma_parms; + dma_set_max_seg_size(&pdev->dev, dmac->chan.max_length); + + dma_dev = &dmac->dma_dev; + dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); + dma_cap_set(DMA_CYCLIC, dma_dev->cap_mask); + dma_dev->device_free_chan_resources = axi_dmac_free_chan_resources; + dma_dev->device_tx_status = dma_cookie_status; + dma_dev->device_issue_pending = axi_dmac_issue_pending; + dma_dev->device_prep_slave_sg = axi_dmac_prep_slave_sg; + dma_dev->device_prep_dma_cyclic = axi_dmac_prep_dma_cyclic; + dma_dev->device_prep_interleaved_dma = axi_dmac_prep_interleaved; + dma_dev->device_terminate_all = axi_dmac_terminate_all; + dma_dev->dev = &pdev->dev; + dma_dev->chancnt = 1; + dma_dev->src_addr_widths = BIT(dmac->chan.src_width); + dma_dev->dst_addr_widths = BIT(dmac->chan.dest_width); + dma_dev->directions = BIT(dmac->chan.direction); + dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR; + INIT_LIST_HEAD(&dma_dev->channels); + + dmac->chan.vchan.desc_free = axi_dmac_desc_free; + vchan_init(&dmac->chan.vchan, dma_dev); + + ret = clk_prepare_enable(dmac->clk); + if (ret < 0) + return ret; + + axi_dmac_write(dmac, AXI_DMAC_REG_IRQ_MASK, 0x00); + + ret = dma_async_device_register(dma_dev); + if (ret) + goto err_clk_disable; + + ret = of_dma_controller_register(pdev->dev.of_node, + of_dma_xlate_by_chan_id, dma_dev); + if (ret) + goto err_unregister_device; + + ret = request_irq(dmac->irq, axi_dmac_interrupt_handler, 0, + dev_name(&pdev->dev), dmac); + if (ret) + goto err_unregister_of; + + platform_set_drvdata(pdev, dmac); + + return 0; + +err_unregister_of: + of_dma_controller_free(pdev->dev.of_node); +err_unregister_device: + dma_async_device_unregister(&dmac->dma_dev); +err_clk_disable: + clk_disable_unprepare(dmac->clk); + + return ret; +} + +static int axi_dmac_remove(struct platform_device *pdev) +{ + struct axi_dmac *dmac = platform_get_drvdata(pdev); + + of_dma_controller_free(pdev->dev.of_node); + free_irq(dmac->irq, dmac); + tasklet_kill(&dmac->chan.vchan.task); + dma_async_device_unregister(&dmac->dma_dev); + clk_disable_unprepare(dmac->clk); + + return 0; +} + +static const struct of_device_id axi_dmac_of_match_table[] = { + { .compatible = "adi,axi-dmac-1.00.a" }, + { }, +}; + +static struct platform_driver axi_dmac_driver = { + .driver = { + .name = "dma-axi-dmac", + .of_match_table = axi_dmac_of_match_table, + }, + .probe = axi_dmac_probe, + .remove = axi_dmac_remove, +}; +module_platform_driver(axi_dmac_driver); + +MODULE_AUTHOR("Lars-Peter Clausen "); +MODULE_DESCRIPTION("DMA controller driver for the AXI-DMAC controller"); +MODULE_LICENSE("GPL v2"); -- GitLab From 25cf68da08389bb107e5cba2cbfb3b6e4a246095 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Fri, 21 Aug 2015 16:27:49 -0400 Subject: [PATCH 4623/7006] drivers/dma: make mv_xor.c driver explicitly non-modular The Kconfig for this driver is currently: config MV_XOR bool "Marvell XOR engine support" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init translates to device_initcall in the non-modular case, the init ordering remains unchanged with this commit. We leave some tags like MODULE_AUTHOR for documentation purposes. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. Cc: Vinod Koul Cc: Dan Williams Cc: dmaengine@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Vinod Koul --- drivers/dma/mv_xor.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index a0e118725ae33..086104ee104d2 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -13,7 +13,6 @@ */ #include -#include #include #include #include @@ -1126,7 +1125,6 @@ static const struct of_device_id mv_xor_dt_ids[] = { { .compatible = "marvell,armada-380-xor", .data = (void *)XOR_MODE_IN_DESC }, {}, }; -MODULE_DEVICE_TABLE(of, mv_xor_dt_ids); static unsigned int mv_xor_engine_count; @@ -1281,27 +1279,8 @@ err_channel_add: return ret; } -static int mv_xor_remove(struct platform_device *pdev) -{ - struct mv_xor_device *xordev = platform_get_drvdata(pdev); - int i; - - for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) { - if (xordev->channels[i]) - mv_xor_channel_remove(xordev->channels[i]); - } - - if (!IS_ERR(xordev->clk)) { - clk_disable_unprepare(xordev->clk); - clk_put(xordev->clk); - } - - return 0; -} - static struct platform_driver mv_xor_driver = { .probe = mv_xor_probe, - .remove = mv_xor_remove, .driver = { .name = MV_XOR_NAME, .of_match_table = of_match_ptr(mv_xor_dt_ids), @@ -1313,19 +1292,10 @@ static int __init mv_xor_init(void) { return platform_driver_register(&mv_xor_driver); } -module_init(mv_xor_init); - -/* it's currently unsafe to unload this module */ -#if 0 -static void __exit mv_xor_exit(void) -{ - platform_driver_unregister(&mv_xor_driver); - return; -} - -module_exit(mv_xor_exit); -#endif +device_initcall(mv_xor_init); +/* MODULE_AUTHOR("Saeed Bishara "); MODULE_DESCRIPTION("DMA engine driver for Marvell's XOR engine"); MODULE_LICENSE("GPL"); +*/ -- GitLab From cb9af418598b8f388844e1849014c689a048ce54 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Fri, 5 Jun 2015 19:09:35 +0200 Subject: [PATCH 4624/7006] 9p: remove unused option Opt_trans Commit 8a0dc95fd976 ("9p: transport API reorganization") removed Opt_trans in tokens not in enum. Signed-off-by: Fabian Frederick Signed-off-by: Eric Van Hensbergen --- fs/9p/v9fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 8aa56bb6e8619..6caca025019d1 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -52,7 +52,7 @@ enum { /* Options that take integer arguments */ Opt_debug, Opt_dfltuid, Opt_dfltgid, Opt_afid, /* String options */ - Opt_uname, Opt_remotename, Opt_trans, Opt_cache, Opt_cachetag, + Opt_uname, Opt_remotename, Opt_cache, Opt_cachetag, /* Options that take no arguments */ Opt_nodevmap, /* Cache options */ -- GitLab From b5ac1fb2717e48177d3f73f9e4c9b556c0a24c6b Mon Sep 17 00:00:00 2001 From: Vincent Bernat Date: Sat, 15 Aug 2015 14:07:44 +0200 Subject: [PATCH 4625/7006] 9p: fix return code of read() when count is 0 When reading 0 bytes from an empty file on a 9P filesystem, the return code of read() was not 0 as expected due to an unitialized err variable. Tested with this simple program: #include #include #include #include #include int main(int argc, const char **argv) { assert(argc == 2); char buffer[256]; int fd = open(argv[1], O_RDONLY|O_NOCTTY); assert(fd >= 0); assert(read(fd, buffer, 0) == 0); return 0; } Signed-off-by: Vincent Bernat Signed-off-by: Eric Van Hensbergen --- fs/9p/vfs_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 1ef16bd8280b5..3abc447783aa8 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -381,7 +381,7 @@ static ssize_t v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) { struct p9_fid *fid = iocb->ki_filp->private_data; - int ret, err; + int ret, err = 0; p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", iov_iter_count(to), iocb->ki_pos); -- GitLab From f5117ce4f6a16fa2a02ceff9c337cfffca8b75f2 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Wed, 19 Aug 2015 18:54:55 -0400 Subject: [PATCH 4626/7006] net: dsa: mv88e6xxx: set 802.1Q mode to Fallback The current Secure port mode requires the port-based VLANs to also be valid in the 802.1Q VLAN Table Unit. The current hardware bridging support only configures the port-based VLANs, thus is broken. A new patchset is required to adapt the hardware bridging code to fully support the Secure port mode. In the meantime, change the 802.1Q mode of every ports to Fallback, which filtering is more permissive, and doesn't add this restriction to handle port-based and tagged-based VLANs. Fixes: 8efdda4a1b60 ("net: dsa: mv88e6xxx: use port 802.1Q mode Secure") Signed-off-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 2ab3f98105935..3774f53d28d78 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -2033,7 +2033,7 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port) reg |= PORT_CONTROL_2_FORWARD_UNKNOWN; } - reg |= PORT_CONTROL_2_8021Q_SECURE; + reg |= PORT_CONTROL_2_8021Q_FALLBACK; if (reg) { ret = _mv88e6xxx_reg_write(ds, REG_PORT(port), -- GitLab From 9a873c71e91cabf4c10fd9bbd8358c22deaf6c9e Mon Sep 17 00:00:00 2001 From: Chas Williams <3chas3@gmail.com> Date: Wed, 19 Aug 2015 19:14:20 -0400 Subject: [PATCH 4627/7006] net/xen-netfront: only clean up queues if present If you simply load and unload the module without starting the interfaces, the queues are never created and you get a bad pointer dereference. Signed-off-by: Chas Williams <3chas3@gmail.com> Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f948c46d51329..002062db2f1dc 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1336,7 +1336,7 @@ static void xennet_disconnect_backend(struct netfront_info *info) netif_carrier_off(info->netdev); - for (i = 0; i < num_queues; ++i) { + for (i = 0; i < num_queues && info->queues; ++i) { struct netfront_queue *queue = &info->queues[i]; if (queue->tx_irq && (queue->tx_irq == queue->rx_irq)) @@ -2101,7 +2101,8 @@ static int xennet_remove(struct xenbus_device *dev) unregister_netdev(info->netdev); - xennet_destroy_queues(info); + if (info->queues) + xennet_destroy_queues(info); xennet_free_netdev(info->netdev); return 0; -- GitLab From b7fe10e5ebac2a3f37e95535e616494b65fa020f Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 19 Aug 2015 17:07:32 -0700 Subject: [PATCH 4628/7006] gro: Fix remcsum offload to deal with frags in GRO The remote checksum offload GRO did not consider the case that frag0 might be in use. This patch fixes that by accessing headers using the skb_gro functions and not saving offsets relative to skb->head. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 23 ++++++++------------ include/linux/netdevice.h | 44 ++++++++++++++++++++++++++++----------- net/ipv4/fou.c | 28 +++++++++++-------------- 3 files changed, 53 insertions(+), 42 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 54615bb9d9163..64fcd2402562c 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -519,10 +519,10 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, u32 data, struct gro_remcsum *grc, bool nopartial) { - size_t start, offset, plen; + size_t start, offset; if (skb->remcsum_offload) - return NULL; + return vh; if (!NAPI_GRO_CB(skb)->csum_valid) return NULL; @@ -532,17 +532,8 @@ static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb, offsetof(struct udphdr, check) : offsetof(struct tcphdr, check)); - plen = hdrlen + offset + sizeof(u16); - - /* Pull checksum that will be written */ - if (skb_gro_header_hard(skb, off + plen)) { - vh = skb_gro_header_slow(skb, off + plen, off); - if (!vh) - return NULL; - } - - skb_gro_remcsum_process(skb, (void *)vh + hdrlen, - start, offset, grc, nopartial); + vh = skb_gro_remcsum_process(skb, (void *)vh, off, hdrlen, + start, offset, grc, nopartial); skb->remcsum_offload = 1; @@ -573,7 +564,6 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, goto out; } - skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr)); flags = ntohl(vh->vx_flags); @@ -588,6 +578,8 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, goto out; } + skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */ + flush = 0; for (p = *head; p; p = p->next) { @@ -1110,6 +1102,9 @@ static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh, { size_t start, offset, plen; + if (skb->remcsum_offload) + return vh; + start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT; offset = start + ((data & VXLAN_RCO_UDP) ? offsetof(struct udphdr, check) : diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 4bd177faa90ce..6abe0d6f1e1d4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2311,8 +2311,7 @@ __sum16 __skb_gro_checksum_complete(struct sk_buff *skb); static inline bool skb_at_gro_remcsum_start(struct sk_buff *skb) { - return (NAPI_GRO_CB(skb)->gro_remcsum_start - skb_headroom(skb) == - skb_gro_offset(skb)); + return (NAPI_GRO_CB(skb)->gro_remcsum_start == skb_gro_offset(skb)); } static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb, @@ -2408,37 +2407,58 @@ static inline void skb_gro_remcsum_init(struct gro_remcsum *grc) grc->delta = 0; } -static inline void skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, - int start, int offset, - struct gro_remcsum *grc, - bool nopartial) +static inline void *skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, + unsigned int off, size_t hdrlen, + int start, int offset, + struct gro_remcsum *grc, + bool nopartial) { __wsum delta; + size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); BUG_ON(!NAPI_GRO_CB(skb)->csum_valid); if (!nopartial) { - NAPI_GRO_CB(skb)->gro_remcsum_start = - ((unsigned char *)ptr + start) - skb->head; - return; + NAPI_GRO_CB(skb)->gro_remcsum_start = off + hdrlen + start; + return ptr; + } + + ptr = skb_gro_header_fast(skb, off); + if (skb_gro_header_hard(skb, off + plen)) { + ptr = skb_gro_header_slow(skb, off + plen, off); + if (!ptr) + return NULL; } - delta = remcsum_adjust(ptr, NAPI_GRO_CB(skb)->csum, start, offset); + delta = remcsum_adjust(ptr + hdrlen, NAPI_GRO_CB(skb)->csum, + start, offset); /* Adjust skb->csum since we changed the packet */ NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta); - grc->offset = (ptr + offset) - (void *)skb->head; + grc->offset = off + hdrlen + offset; grc->delta = delta; + + return ptr; } static inline void skb_gro_remcsum_cleanup(struct sk_buff *skb, struct gro_remcsum *grc) { + void *ptr; + size_t plen = grc->offset + sizeof(u16); + if (!grc->delta) return; - remcsum_unadjust((__sum16 *)(skb->head + grc->offset), grc->delta); + ptr = skb_gro_header_fast(skb, grc->offset); + if (skb_gro_header_hard(skb, grc->offset + sizeof(u16))) { + ptr = skb_gro_header_slow(skb, plen, grc->offset); + if (!ptr) + return; + } + + remcsum_unadjust((__sum16 *)ptr, grc->delta); } static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 34968cd5c1464..eb11f95068946 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -79,7 +79,11 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, __be16 *pd = data; size_t start = ntohs(pd[0]); size_t offset = ntohs(pd[1]); - size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); + size_t plen = sizeof(struct udphdr) + hdrlen + + max_t(size_t, offset + sizeof(u16), start); + + if (skb->remcsum_offload) + return guehdr; if (!pskb_may_pull(skb, plen)) return NULL; @@ -221,29 +225,21 @@ out_unlock: static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, struct guehdr *guehdr, void *data, - size_t hdrlen, u8 ipproto, - struct gro_remcsum *grc, bool nopartial) + size_t hdrlen, struct gro_remcsum *grc, + bool nopartial) { __be16 *pd = data; size_t start = ntohs(pd[0]); size_t offset = ntohs(pd[1]); - size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); if (skb->remcsum_offload) - return NULL; + return guehdr; if (!NAPI_GRO_CB(skb)->csum_valid) return NULL; - /* Pull checksum that will be written */ - if (skb_gro_header_hard(skb, off + plen)) { - guehdr = skb_gro_header_slow(skb, off + plen, off); - if (!guehdr) - return NULL; - } - - skb_gro_remcsum_process(skb, (void *)guehdr + hdrlen, - start, offset, grc, nopartial); + guehdr = skb_gro_remcsum_process(skb, (void *)guehdr, off, hdrlen, + start, offset, grc, nopartial); skb->remcsum_offload = 1; @@ -307,10 +303,10 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, if (flags & GUE_PFLAG_REMCSUM) { guehdr = gue_gro_remcsum(skb, off, guehdr, - data + doffset, hdrlen, - guehdr->proto_ctype, &grc, + data + doffset, hdrlen, &grc, !!(fou->flags & FOU_F_REMCSUM_NOPARTIAL)); + if (!guehdr) goto out; -- GitLab From 58ce31cca1ffe057f4744c3f671e3e84606d3d4a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 19 Aug 2015 17:07:33 -0700 Subject: [PATCH 4629/7006] vxlan: GRO support at tunnel layer Add calls to gro_cells infrastructure to do GRO when receiving on a tunnel. Testing: Ran 200 netperf TCP_STREAM instance - With fix (GRO enabled on VXLAN interface) Verify GRO is happening. 9084 MBps tput 3.44% CPU utilization - Without fix (GRO disabled on VXLAN interface) Verified no GRO is happening. 9084 MBps tput 5.54% CPU utilization Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 9 +++++++-- include/net/vxlan.h | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 64fcd2402562c..61b457b9ec005 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1208,7 +1208,7 @@ static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb, stats->rx_bytes += skb->len; u64_stats_update_end(&stats->syncp); - netif_rx(skb); + gro_cells_receive(&vxlan->gro_cells, skb); return; drop: @@ -2446,6 +2446,8 @@ static void vxlan_setup(struct net_device *dev) vxlan->dev = dev; + gro_cells_init(&vxlan->gro_cells, dev); + for (h = 0; h < FDB_HASH_SIZE; ++h) INIT_HLIST_HEAD(&vxlan->fdb_head[h]); } @@ -2885,6 +2887,7 @@ static void vxlan_dellink(struct net_device *dev, struct list_head *head) hlist_del_rcu(&vxlan->hlist); spin_unlock(&vn->sock_lock); + gro_cells_destroy(&vxlan->gro_cells); list_del(&vxlan->next); unregister_netdevice_queue(dev, head); } @@ -3093,8 +3096,10 @@ static void __net_exit vxlan_exit_net(struct net *net) /* If vxlan->dev is in the same netns, it has already been added * to the list by the previous loop. */ - if (!net_eq(dev_net(vxlan->dev), net)) + if (!net_eq(dev_net(vxlan->dev), net)) { + gro_cells_destroy(&vxlan->gro_cells); unregister_netdevice_queue(vxlan->dev, &list); + } } unregister_netdevice_many(&list); diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 43677e6b9c431..6b3234599a2c5 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -161,6 +161,7 @@ struct vxlan_dev { struct timer_list age_timer; spinlock_t hash_lock; unsigned int addrcnt; + struct gro_cells gro_cells; struct vxlan_config cfg; -- GitLab From 270136613bf7306e2b83457628e2b2f6c6be3989 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Wed, 19 Aug 2015 17:07:34 -0700 Subject: [PATCH 4630/7006] fou: Do WARN_ON_ONCE in gue_gro_receive for bad proto callbacks Do WARN_ON_ONCE instead of WARN_ON in gue_gro_receive when the offload callcaks are bad (either don't exist or gro_receive is not specified). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/ipv4/fou.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index eb11f95068946..2d1646cff0572 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -347,7 +347,7 @@ static struct sk_buff **gue_gro_receive(struct sk_buff **head, rcu_read_lock(); offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; ops = rcu_dereference(offloads[guehdr->proto_ctype]); - if (WARN_ON(!ops || !ops->callbacks.gro_receive)) + if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive)) goto out_unlock; pp = ops->callbacks.gro_receive(head, skb); -- GitLab From 0dd20f3ce04e75521bd3f9867ecbc852ab348912 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:01 +0300 Subject: [PATCH 4631/7006] NET: nps_enet: replace use of cause register When interrupt is received we read directly from control register for RX/TX instead of reading cause register since this register fails to indicate TX done when TX interrupt is "edge mode". Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 9 +++++---- drivers/net/ethernet/ezchip/nps_enet.h | 20 -------------------- 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 24a85b292007c..0e652b4fee8d6 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -211,12 +211,13 @@ static irqreturn_t nps_enet_irq_handler(s32 irq, void *dev_instance) { struct net_device *ndev = dev_instance; struct nps_enet_priv *priv = netdev_priv(ndev); - struct nps_enet_buf_int_cause buf_int_cause; + struct nps_enet_rx_ctl rx_ctrl; + struct nps_enet_tx_ctl tx_ctrl; - buf_int_cause.value = - nps_enet_reg_get(priv, NPS_ENET_REG_BUF_INT_CAUSE); + rx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_RX_CTL); + tx_ctrl.value = nps_enet_reg_get(priv, NPS_ENET_REG_TX_CTL); - if (buf_int_cause.tx_done || buf_int_cause.rx_rdy) + if ((!tx_ctrl.ct && priv->tx_packet_sent) || rx_ctrl.cr) if (likely(napi_schedule_prep(&priv->napi))) { nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, 0); __napi_schedule(&priv->napi); diff --git a/drivers/net/ethernet/ezchip/nps_enet.h b/drivers/net/ethernet/ezchip/nps_enet.h index fc45c9daa1c2d..6703674d679c9 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.h +++ b/drivers/net/ethernet/ezchip/nps_enet.h @@ -36,7 +36,6 @@ #define NPS_ENET_REG_RX_CTL 0x810 #define NPS_ENET_REG_RX_BUF 0x818 #define NPS_ENET_REG_BUF_INT_ENABLE 0x8C0 -#define NPS_ENET_REG_BUF_INT_CAUSE 0x8C4 #define NPS_ENET_REG_GE_MAC_CFG_0 0x1000 #define NPS_ENET_REG_GE_MAC_CFG_1 0x1004 #define NPS_ENET_REG_GE_MAC_CFG_2 0x1008 @@ -108,25 +107,6 @@ struct nps_enet_buf_int_enable { }; }; -/* Interrupt cause for data buffer events register */ -struct nps_enet_buf_int_cause { - union { - /* tx_done: Interrupt in the case when current frame was - * read from TX buffer. - * rx_rdy: Interrupt in the case when new frame is ready - * in RX buffer. - */ - struct { - u32 - __reserved:30, - tx_done:1, - rx_rdy:1; - }; - - u32 value; - }; -}; - /* Gbps Eth MAC Configuration 0 register */ struct nps_enet_ge_mac_cfg_0 { union { -- GitLab From 93fcf83eb953d9ca2d3c51ff7f87095f0dd43511 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:02 +0300 Subject: [PATCH 4632/7006] NET: nps_enet: TX done race condition We need to set tx_skb pointer before send frame. If we receive interrupt before we set pointer we will try to free SKB with wrong pointer. Now we are sure that SKB pointer will never be NULL during handling TX done and check is removed. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 0e652b4fee8d6..8b25f240943d9 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -158,11 +158,7 @@ static void nps_enet_tx_handler(struct net_device *ndev) ndev->stats.tx_bytes += tx_ctrl.nt; } - if (priv->tx_skb) { - dev_kfree_skb(priv->tx_skb); - priv->tx_skb = NULL; - } - + dev_kfree_skb(priv->tx_skb); priv->tx_packet_sent = false; if (netif_queue_stopped(ndev)) @@ -528,10 +524,10 @@ static netdev_tx_t nps_enet_start_xmit(struct sk_buff *skb, /* This driver handles one frame at a time */ netif_stop_queue(ndev); - nps_enet_send_frame(ndev, skb); - priv->tx_skb = skb; + nps_enet_send_frame(ndev, skb); + return NETDEV_TX_OK; } -- GitLab From de6715677aaa5e9ed27dab1f6ca6597b74a3f7bc Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:03 +0300 Subject: [PATCH 4633/7006] NET: nps_enet: drop control frames We set controller to drop control frames and not trying to pass them on. This is only needed for debug reasons. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 8b25f240943d9..e553e6aa0e744 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -304,11 +304,8 @@ static void nps_enet_hw_enable_control(struct net_device *ndev) /* Discard Packets bigger than max frame length */ max_frame_length = ETH_HLEN + ndev->mtu + ETH_FCS_LEN; - if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) { + if (max_frame_length <= NPS_ENET_MAX_FRAME_LENGTH) ge_mac_cfg_3->max_len = max_frame_length; - nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, - ge_mac_cfg_3->value); - } /* Enable interrupts */ buf_int_enable.rx_rdy = NPS_ENET_ENABLE; @@ -336,11 +333,14 @@ static void nps_enet_hw_enable_control(struct net_device *ndev) ge_mac_cfg_0.tx_fc_en = NPS_ENET_ENABLE; ge_mac_cfg_0.rx_fc_en = NPS_ENET_ENABLE; ge_mac_cfg_0.tx_fc_retr = NPS_ENET_GE_MAC_CFG_0_TX_FC_RETR; + ge_mac_cfg_3->cf_drop = NPS_ENET_ENABLE; /* Enable Rx and Tx */ ge_mac_cfg_0.rx_en = NPS_ENET_ENABLE; ge_mac_cfg_0.tx_en = NPS_ENET_ENABLE; + nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_3, + ge_mac_cfg_3->value); nps_enet_reg_set(priv, NPS_ENET_REG_GE_MAC_CFG_0, ge_mac_cfg_0.value); } -- GitLab From 3d99b74ab3c4b7e529d5820ccadabfb81085f020 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:04 +0300 Subject: [PATCH 4634/7006] NET: nps_enet: TX done acknowledge. This is needed for when TX done interrupt is in "level mode". For example it is true for some simulators of this device. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index e553e6aa0e744..69b9129357fd9 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -150,6 +150,9 @@ static void nps_enet_tx_handler(struct net_device *ndev) if (!priv->tx_packet_sent || tx_ctrl.ct) return; + /* Ack Tx ctrl register */ + nps_enet_reg_set(priv, NPS_ENET_REG_TX_CTL, 0); + /* Check Tx transmit error */ if (unlikely(tx_ctrl.et)) { ndev->stats.tx_errors++; -- GitLab From 41493795a4c18170fdf27c0373d386b4039b24df Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 20 Aug 2015 08:00:05 +0300 Subject: [PATCH 4635/7006] NET: nps_enet: minor namespace cleanup We define buf_int_enable in the minimal namespace it is used. Signed-off-by: Noam Camus Signed-off-by: David S. Miller --- drivers/net/ethernet/ezchip/nps_enet.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/ezchip/nps_enet.c b/drivers/net/ethernet/ezchip/nps_enet.c index 69b9129357fd9..63c2bcf8031a8 100644 --- a/drivers/net/ethernet/ezchip/nps_enet.c +++ b/drivers/net/ethernet/ezchip/nps_enet.c @@ -179,15 +179,16 @@ static int nps_enet_poll(struct napi_struct *napi, int budget) { struct net_device *ndev = napi->dev; struct nps_enet_priv *priv = netdev_priv(ndev); - struct nps_enet_buf_int_enable buf_int_enable; u32 work_done; - buf_int_enable.rx_rdy = NPS_ENET_ENABLE; - buf_int_enable.tx_done = NPS_ENET_ENABLE; nps_enet_tx_handler(ndev); work_done = nps_enet_rx_handler(ndev); if (work_done < budget) { + struct nps_enet_buf_int_enable buf_int_enable; + napi_complete(napi); + buf_int_enable.rx_rdy = NPS_ENET_ENABLE; + buf_int_enable.tx_done = NPS_ENET_ENABLE; nps_enet_reg_set(priv, NPS_ENET_REG_BUF_INT_ENABLE, buf_int_enable.value); } -- GitLab From 17b2063077a7478e5fd3c34b04a059dbb8474638 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 20 Aug 2015 02:12:54 -0400 Subject: [PATCH 4636/7006] tipc: eliminate risk of premature link setup during failover When a link goes down, and there is still a working link towards its destination node, a failover is initiated, and the failed link is not allowed to re-establish until that procedure is finished. To ensure this, the concerned link endpoints are set to state LINK_FAILINGOVER, and the node endpoints to NODE_FAILINGOVER during the failover period. However, if the link reset is due to a disabled bearer, the corres- ponding link endpoint is deleted, and only the node endpoint knows about the ongoing failover. Now, if the disabled bearer is re-enabled during the failover period, the discovery mechanism may create a new link endpoint that is ready to be established, despite that this is not permitted. This situation may cause both the ongoing failover and any subsequent link synchronization to fail. In this commit, we ensure that a newly created link goes directly to state LINK_FAILINGOVER if the corresponding node state is NODE_FAILINGOVER. This eliminates the problem described above. Furthermore, we tighten the criteria for which packets are allowed to end a failover state in the function tipc_node_check_state(). By checking that the receiving link is up and running, instead of just checking that it is not in failover mode, we eliminate the risk that protocol packets from the re-created link may cause the failover to be prematurely terminated. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/node.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/tipc/node.c b/net/tipc/node.c index 7c191641b44f6..004834bd16051 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -565,6 +565,8 @@ void tipc_node_check_dest(struct net *net, u32 onode, goto exit; } tipc_link_reset(l); + if (n->state == NODE_FAILINGOVER) + tipc_link_fsm_evt(l, LINK_FAILOVER_BEGIN_EVT); le->link = l; n->link_cnt++; tipc_node_calculate_timer(n, l); @@ -1129,7 +1131,7 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, } /* Open parallel link when tunnel link reaches synch point */ - if ((n->state == NODE_FAILINGOVER) && !tipc_link_is_failingover(l)) { + if ((n->state == NODE_FAILINGOVER) && tipc_link_is_up(l)) { if (!more(rcv_nxt, n->sync_point)) return true; tipc_node_fsm_evt(n, NODE_FAILOVER_END_EVT); -- GitLab From 5ae2f8e6857968d6dddbd3879ed0a32b860e02d1 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 20 Aug 2015 02:12:55 -0400 Subject: [PATCH 4637/7006] tipc: interrupt link synchronization when a link goes down When we introduced the new link failover/synch mechanism in commit 6e498158a827fd515b514842e9a06bdf0f75ab86 ("tipc: move link synch and failover to link aggregation level"), we missed the case when the non-tunnel link goes down during the link synchronization period. In this case the tunnel link will remain in state LINK_SYNCHING, something leading to unpredictable behavior when the failover procedure is initiated. In this commit, we ensure that the node and remaining link goes back to regular communication state (SELF_UP_PEER_UP/LINK_ESTABLISHED) when one of the parallel links goes down. We also ensure that we don't re-enter synch mode if subsequent SYNCH packets arrive on the remaining link. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 2 +- net/tipc/node.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index f067e5425560f..7058c86f5e48b 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -351,11 +351,11 @@ int tipc_link_fsm_evt(struct tipc_link *l, int evt) l->state = LINK_RESET; break; case LINK_ESTABLISH_EVT: + case LINK_SYNCH_END_EVT: break; case LINK_SYNCH_BEGIN_EVT: l->state = LINK_SYNCHING; break; - case LINK_SYNCH_END_EVT: case LINK_FAILOVER_BEGIN_EVT: case LINK_FAILOVER_END_EVT: default: diff --git a/net/tipc/node.c b/net/tipc/node.c index 004834bd16051..937cc6192bcfc 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -423,6 +423,8 @@ static void __tipc_node_link_down(struct tipc_node *n, int *bearer_id, /* There is still a working link => initiate failover */ tnl = node_active_link(n, 0); + tipc_link_fsm_evt(tnl, LINK_SYNCH_END_EVT); + tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); n->sync_point = tnl->rcv_nxt + (U16_MAX / 2 - 1); tipc_link_tnl_prepare(l, tnl, FAILOVER_MSG, xmitq); tipc_link_reset(l); @@ -1140,6 +1142,10 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, return true; } + /* No synching needed if only one link */ + if (!pl || !tipc_link_is_up(pl)) + return true; + /* Initiate or update synch mode if applicable */ if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) { syncpt = iseqno + exp_pkts - 1; @@ -1158,9 +1164,8 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, /* Open tunnel link when parallel link reaches synch point */ if ((n->state == NODE_SYNCHING) && tipc_link_is_synching(l)) { - if (pl) - dlv_nxt = mod(pl->rcv_nxt - skb_queue_len(pl->inputq)); - if (!pl || more(dlv_nxt, n->sync_point)) { + dlv_nxt = pl->rcv_nxt - mod(skb_queue_len(pl->inputq)); + if (more(dlv_nxt, n->sync_point)) { tipc_link_fsm_evt(l, LINK_SYNCH_END_EVT); tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); return true; -- GitLab From 2be80c2d87de789550982e74a11e9f9ff5940845 Mon Sep 17 00:00:00 2001 From: Jon Paul Maloy Date: Thu, 20 Aug 2015 02:12:56 -0400 Subject: [PATCH 4638/7006] tipc: fix stale link problem during synchronization Recent changes to the link synchronization means that we can now just drop packets arriving on the synchronizing link before the synch point is reached. This has lead to significant simplifications to the implementation, but also turns out to have a flip side that we need to consider. Under unlucky circumstances, the two endpoints may end up repeatedly dropping each other's packets, while immediately asking for retransmission of the same packets, just to drop them once more. This pattern will eventually be broken when the synch point is reached on the other link, but before that, the endpoints may have arrived at the retransmission limit (stale counter) that indicates that the link should be broken. We see this happen at rare occasions. The fix for this is to not ask for retransmissions when a link is in state LINK_SYNCHING. The fact that the link has reached this state means that it has already received the first SYNCH packet, and that it knows the synch point. Hence, it doesn't need any more packets until the other link has reached the synch point, whereafter it can go ahead and ask for the missing packets. However, because of the reduced traffic on the synching link that follows this change, it may now take longer to discover that the synch point has been reached. We compensate for this by letting all packets, on any of the links, trig a check for synchronization termination. This is possible because the packets themselves don't contain any information that is needed for discovering this condition. Reviewed-by: Ying Xue Signed-off-by: Jon Maloy Signed-off-by: David S. Miller --- net/tipc/link.c | 3 ++- net/tipc/node.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/net/tipc/link.c b/net/tipc/link.c index 7058c86f5e48b..75db07c78a690 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -1330,6 +1330,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, u16 peers_snd_nxt = msg_next_sent(hdr); u16 peers_tol = msg_link_tolerance(hdr); u16 peers_prio = msg_linkprio(hdr); + u16 rcv_nxt = l->rcv_nxt; char *if_name; int rc = 0; @@ -1393,7 +1394,7 @@ static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb, break; /* Send NACK if peer has sent pkts we haven't received yet */ - if (more(peers_snd_nxt, l->rcv_nxt)) + if (more(peers_snd_nxt, rcv_nxt) && !tipc_link_is_synching(l)) rcvgap = peers_snd_nxt - l->rcv_nxt; if (rcvgap || (msg_probe(hdr))) tipc_link_build_proto_msg(l, STATE_MSG, 0, rcvgap, diff --git a/net/tipc/node.c b/net/tipc/node.c index 937cc6192bcfc..703875fd6cde2 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c @@ -1079,7 +1079,7 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, u16 exp_pkts = msg_msgcnt(hdr); u16 rcv_nxt, syncpt, dlv_nxt; int state = n->state; - struct tipc_link *l, *pl = NULL; + struct tipc_link *l, *tnl, *pl = NULL; struct tipc_media_addr *maddr; int i, pb_id; @@ -1164,12 +1164,20 @@ static bool tipc_node_check_state(struct tipc_node *n, struct sk_buff *skb, /* Open tunnel link when parallel link reaches synch point */ if ((n->state == NODE_SYNCHING) && tipc_link_is_synching(l)) { + if (tipc_link_is_synching(l)) { + tnl = l; + } else { + tnl = pl; + pl = l; + } dlv_nxt = pl->rcv_nxt - mod(skb_queue_len(pl->inputq)); if (more(dlv_nxt, n->sync_point)) { - tipc_link_fsm_evt(l, LINK_SYNCH_END_EVT); + tipc_link_fsm_evt(tnl, LINK_SYNCH_END_EVT); tipc_node_fsm_evt(n, NODE_SYNCH_END_EVT); return true; } + if (l == pl) + return true; if ((usr == TUNNEL_PROTOCOL) && (mtyp == SYNCH_MSG)) return true; if (usr == LINK_PROTOCOL) -- GitLab From 751a587ac9f9a8bf314590fbac32d9e418060c5a Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 21 Aug 2015 12:41:14 +0200 Subject: [PATCH 4639/7006] route: fix breakage after moving lwtunnel state __recnt and related fields need to be in its own cacheline for performance reasons. Commit 61adedf3e3f1 ("route: move lwtunnel state to dst_entry") broke that on 32bit archs, causing BUILD_BUG_ON in dst_hold to be triggered. This patch fixes the breakage by moving the lwtunnel state to the end of dst_entry on 32bit archs. Unfortunately, this makes it share the cacheline with __refcnt and may affect performance, thus further patches may be needed. Reported-by: kbuild test robot Fixes: 61adedf3e3f1 ("route: move lwtunnel state to dst_entry") Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- include/net/dst.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 0a9a723f6c19b..ef8f1d43a2033 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -44,7 +44,6 @@ struct dst_entry { #else void *__pad1; #endif - struct lwtunnel_state *lwtstate; int (*input)(struct sk_buff *); int (*output)(struct sock *sk, struct sk_buff *skb); @@ -85,11 +84,12 @@ struct dst_entry { __u32 __pad2; #endif +#ifdef CONFIG_64BIT + struct lwtunnel_state *lwtstate; /* * Align __refcnt to a 64 bytes alignment * (L1_CACHE_SIZE would be too much) */ -#ifdef CONFIG_64BIT long __pad_to_align_refcnt[1]; #endif /* @@ -99,6 +99,9 @@ struct dst_entry { atomic_t __refcnt; /* client references */ int __use; unsigned long lastuse; +#ifndef CONFIG_64BIT + struct lwtunnel_state *lwtstate; +#endif union { struct dst_entry *next; struct rtable __rcu *rt_next; -- GitLab From 6d857c18aefdec782ba1db578a390fbac5145107 Mon Sep 17 00:00:00 2001 From: Mathieu Larouche Date: Fri, 21 Aug 2015 09:24:05 -0400 Subject: [PATCH 4640/7006] drm/mgag200: Add support for a new G200eW3 chipset - Added support for the new deviceID for G200eW3 - Added PLL algorithm for the G200eW3 - Added some initialization code for G200eW3 Signed-off-by: Mathieu Larouche Signed-off-by: Dave Airlie --- drivers/gpu/drm/mgag200/mgag200_drv.c | 1 + drivers/gpu/drm/mgag200/mgag200_drv.h | 1 + drivers/gpu/drm/mgag200/mgag200_i2c.c | 1 + drivers/gpu/drm/mgag200/mgag200_main.c | 9 ++- drivers/gpu/drm/mgag200/mgag200_mode.c | 100 ++++++++++++++++++------- 5 files changed, 85 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.c b/drivers/gpu/drm/mgag200/mgag200_drv.c index 97745991544dd..b0af77454d523 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.c +++ b/drivers/gpu/drm/mgag200/mgag200_drv.c @@ -35,6 +35,7 @@ static const struct pci_device_id pciidlist[] = { { PCI_VENDOR_ID_MATROX, 0x532, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_WB }, { PCI_VENDOR_ID_MATROX, 0x533, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EH }, { PCI_VENDOR_ID_MATROX, 0x534, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_ER }, + { PCI_VENDOR_ID_MATROX, 0x536, PCI_ANY_ID, PCI_ANY_ID, 0, 0, G200_EW3 }, {0,} }; diff --git a/drivers/gpu/drm/mgag200/mgag200_drv.h b/drivers/gpu/drm/mgag200/mgag200_drv.h index e9eea1d4e7c3b..912151c36d59e 100644 --- a/drivers/gpu/drm/mgag200/mgag200_drv.h +++ b/drivers/gpu/drm/mgag200/mgag200_drv.h @@ -180,6 +180,7 @@ enum mga_type { G200_EV, G200_EH, G200_ER, + G200_EW3, }; #define IS_G200_SE(mdev) (mdev->type == G200_SE_A || mdev->type == G200_SE_B) diff --git a/drivers/gpu/drm/mgag200/mgag200_i2c.c b/drivers/gpu/drm/mgag200/mgag200_i2c.c index d3dcf54e6233d..10535e3b75f2f 100644 --- a/drivers/gpu/drm/mgag200/mgag200_i2c.c +++ b/drivers/gpu/drm/mgag200/mgag200_i2c.c @@ -101,6 +101,7 @@ struct mga_i2c_chan *mgag200_i2c_create(struct drm_device *dev) case G200_SE_B: case G200_EV: case G200_WB: + case G200_EW3: data = 1; clock = 2; break; diff --git a/drivers/gpu/drm/mgag200/mgag200_main.c b/drivers/gpu/drm/mgag200/mgag200_main.c index c99c2cb289390..de06388069e7c 100644 --- a/drivers/gpu/drm/mgag200/mgag200_main.c +++ b/drivers/gpu/drm/mgag200/mgag200_main.c @@ -82,12 +82,19 @@ static int mga_probe_vram(struct mga_device *mdev, void __iomem *mem) int orig; int test1, test2; int orig1, orig2; + unsigned int vram_size; /* Probe */ orig = ioread16(mem); iowrite16(0, mem); - for (offset = 0x100000; offset < mdev->mc.vram_window; offset += 0x4000) { + vram_size = mdev->mc.vram_window; + + if ((mdev->type == G200_EW3) && (vram_size >= 0x1000000)) { + vram_size = vram_size - 0x400000; + } + + for (offset = 0x100000; offset < vram_size; offset += 0x4000) { orig1 = ioread8(mem + offset); orig2 = ioread8(mem + offset + 0x100); diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index cd75cff096e1c..8f7a3a16c92ab 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -159,7 +159,7 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; unsigned int delta, tmpdelta; - unsigned int testp, testm, testn; + unsigned int testp, testm, testn, testp2; unsigned int p, m, n; unsigned int computed; int i, j, tmpcount, vcount; @@ -167,31 +167,71 @@ static int mga_g200wb_set_plls(struct mga_device *mdev, long clock) u8 tmp; m = n = p = 0; - vcomax = 550000; - vcomin = 150000; - pllreffreq = 48000; delta = 0xffffffff; - for (testp = 1; testp < 9; testp++) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; + if (mdev->type == G200_EW3) { + + vcomax = 800000; + vcomin = 400000; + pllreffreq = 25000; + + for (testp = 1; testp < 8; testp++) { + for (testp2 = 1; testp2 < 8; testp2++) { + if (testp < testp2) + continue; + if ((clock * testp * testp2) > vcomax) + continue; + if ((clock * testp * testp2) < vcomin) + continue; + for (testm = 1; testm < 26; testm++) { + for (testn = 32; testn < 2048 ; testn++) { + computed = (pllreffreq * testn) / + (testm * testp * testp2); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = ((testn & 0x100) >> 1) | + (testm); + n = (testn & 0xFF); + p = ((testn & 0x600) >> 3) | + (testp2 << 3) | + (testp); + } + } + } + } + } + } else { - for (testm = 1; testm < 17; testm++) { - for (testn = 1; testn < 151; testn++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - n = testn - 1; - m = (testm - 1) | ((n >> 1) & 0x80); - p = testp - 1; + vcomax = 550000; + vcomin = 150000; + pllreffreq = 48000; + + for (testp = 1; testp < 9; testp++) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; + + for (testm = 1; testm < 17; testm++) { + for (testn = 1; testn < 151; testn++) { + computed = (pllreffreq * testn) / + (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + n = testn - 1; + m = (testm - 1) | + ((n >> 1) & 0x80); + p = testp - 1; + } } } } @@ -569,6 +609,7 @@ static int mga_crtc_set_plls(struct mga_device *mdev, long clock) return mga_g200se_set_plls(mdev, clock); break; case G200_WB: + case G200_EW3: return mga_g200wb_set_plls(mdev, clock); break; case G200_EV: @@ -820,6 +861,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, option2 = 0x00008000; break; case G200_WB: + case G200_EW3: dacvalue[MGA1064_VREF_CTL] = 0x07; option = 0x41049120; option2 = 0x0000b000; @@ -875,7 +917,10 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, if (IS_G200_SE(mdev) && ((i == 0x2c) || (i == 0x2d) || (i == 0x2e))) continue; - if ((mdev->type == G200_EV || mdev->type == G200_WB || mdev->type == G200_EH) && + if ((mdev->type == G200_EV || + mdev->type == G200_WB || + mdev->type == G200_EH || + mdev->type == G200_EW3) && (i >= 0x44) && (i <= 0x4e)) continue; @@ -977,7 +1022,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, else ext_vga[3] = ((1 << bppshift) - 1) | 0x80; ext_vga[4] = 0; - if (mdev->type == G200_WB) + if (mdev->type == G200_WB || mdev->type == G200_EW3) ext_vga[1] |= 0x88; /* Set pixel clocks */ @@ -993,6 +1038,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc, if (mdev->type == G200_ER) WREG_ECRT(0x24, 0x5); + if (mdev->type == G200_EW3) + WREG_ECRT(0x34, 0x5); + if (mdev->type == G200_EV) { WREG_ECRT(6, 0); } @@ -1205,7 +1253,7 @@ static void mga_crtc_prepare(struct drm_crtc *crtc) WREG_SEQ(1, tmp | 0x20); } - if (mdev->type == G200_WB) + if (mdev->type == G200_WB || mdev->type == G200_EW3) mga_g200wb_prepare(crtc); WREG_CRT(17, 0); @@ -1222,7 +1270,7 @@ static void mga_crtc_commit(struct drm_crtc *crtc) const struct drm_crtc_helper_funcs *crtc_funcs = crtc->helper_private; u8 tmp; - if (mdev->type == G200_WB) + if (mdev->type == G200_WB || mdev->type == G200_EW3) mga_g200wb_commit(crtc); if (mdev->type == G200_SE_A || mdev->type == G200_SE_B) { -- GitLab From e829d7ef9f17d7b84d4c3d110ecd4b7b2bcba865 Mon Sep 17 00:00:00 2001 From: Mathieu Larouche Date: Fri, 21 Aug 2015 09:24:13 -0400 Subject: [PATCH 4641/7006] drm/mgag200: Add support for a new rev of G200e - Added PLL algorithm for a new rev of G200e - Removed the bandwidth limitation for the new G200e Signed-off-by: Mathieu Larouche Signed-off-by: Dave Airlie --- drivers/gpu/drm/mgag200/mgag200_mode.c | 112 +++++++++++++++++++------ 1 file changed, 87 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/mgag200/mgag200_mode.c b/drivers/gpu/drm/mgag200/mgag200_mode.c index 8f7a3a16c92ab..c99d3fe12881d 100644 --- a/drivers/gpu/drm/mgag200/mgag200_mode.c +++ b/drivers/gpu/drm/mgag200/mgag200_mode.c @@ -104,6 +104,8 @@ static bool mga_crtc_mode_fixup(struct drm_crtc *crtc, return true; } +#define P_ARRAY_SIZE 9 + static int mga_g200se_set_plls(struct mga_device *mdev, long clock) { unsigned int vcomax, vcomin, pllreffreq; @@ -111,37 +113,97 @@ static int mga_g200se_set_plls(struct mga_device *mdev, long clock) unsigned int testp, testm, testn; unsigned int p, m, n; unsigned int computed; + unsigned int pvalues_e4[P_ARRAY_SIZE] = {16, 14, 12, 10, 8, 6, 4, 2, 1}; + unsigned int fvv; + unsigned int i; - m = n = p = 0; - vcomax = 320000; - vcomin = 160000; - pllreffreq = 25000; + if (mdev->unique_rev_id <= 0x03) { - delta = 0xffffffff; - permitteddelta = clock * 5 / 1000; + m = n = p = 0; + vcomax = 320000; + vcomin = 160000; + pllreffreq = 25000; - for (testp = 8; testp > 0; testp /= 2) { - if (clock * testp > vcomax) - continue; - if (clock * testp < vcomin) - continue; + delta = 0xffffffff; + permitteddelta = clock * 5 / 1000; - for (testn = 17; testn < 256; testn++) { - for (testm = 1; testm < 32; testm++) { - computed = (pllreffreq * testn) / - (testm * testp); - if (computed > clock) - tmpdelta = computed - clock; - else - tmpdelta = clock - computed; - if (tmpdelta < delta) { - delta = tmpdelta; - m = testm - 1; - n = testn - 1; - p = testp - 1; + for (testp = 8; testp > 0; testp /= 2) { + if (clock * testp > vcomax) + continue; + if (clock * testp < vcomin) + continue; + + for (testn = 17; testn < 256; testn++) { + for (testm = 1; testm < 32; testm++) { + computed = (pllreffreq * testn) / + (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm - 1; + n = testn - 1; + p = testp - 1; + } + } + } + } + } else { + + + m = n = p = 0; + vcomax = 1600000; + vcomin = 800000; + pllreffreq = 25000; + + if (clock < 25000) + clock = 25000; + + clock = clock * 2; + + delta = 0xFFFFFFFF; + /* Permited delta is 0.5% as VESA Specification */ + permitteddelta = clock * 5 / 1000; + + for (i = 0 ; i < P_ARRAY_SIZE ; i++) { + testp = pvalues_e4[i]; + + if ((clock * testp) > vcomax) + continue; + if ((clock * testp) < vcomin) + continue; + + for (testn = 50; testn <= 256; testn++) { + for (testm = 1; testm <= 32; testm++) { + computed = (pllreffreq * testn) / + (testm * testp); + if (computed > clock) + tmpdelta = computed - clock; + else + tmpdelta = clock - computed; + + if (tmpdelta < delta) { + delta = tmpdelta; + m = testm - 1; + n = testn - 1; + p = testp - 1; + } } } } + + fvv = pllreffreq * testn / testm; + fvv = (fvv - 800000) / 50000; + + if (fvv > 15) + fvv = 15; + + p |= (fvv << 4); + m |= 0x80; + + clock = clock / 2; } if (delta > permitteddelta) { @@ -1540,7 +1602,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector, if (mga_vga_calculate_mode_bandwidth(mode, bpp) > (24400 * 1024)) return MODE_BANDWIDTH; - } else if (mdev->unique_rev_id >= 0x02) { + } else if (mdev->unique_rev_id == 0x02) { if (mode->hdisplay > 1920) return MODE_VIRTUAL_X; if (mode->vdisplay > 1200) -- GitLab From 5bbc08fb0f1457ceef388739b48c72675246639c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 16 Jul 2015 16:56:20 +0530 Subject: [PATCH 4642/7006] m68k/coldfire/pit: Migrate to new 'set-state' interface Migrate m68k driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in ->set_mode(RESUME) and so tick_resume() isn't implemented. Cc: Greg Ungerer Cc: Geert Uytterhoeven Cc: linux-m68k@lists.linux-m68k.org Signed-off-by: Viresh Kumar Signed-off-by: Greg Ungerer --- arch/m68k/coldfire/pit.c | 66 ++++++++++++++++++---------------------- 1 file changed, 30 insertions(+), 36 deletions(-) diff --git a/arch/m68k/coldfire/pit.c b/arch/m68k/coldfire/pit.c index 493b3111d4c12..d86a9ffb3f13e 100644 --- a/arch/m68k/coldfire/pit.c +++ b/arch/m68k/coldfire/pit.c @@ -42,37 +42,28 @@ static u32 pit_cnt; * This is also called after resume to bring the PIT into operation again. */ -static void init_cf_pit_timer(enum clock_event_mode mode, - struct clock_event_device *evt) +static int cf_pit_set_periodic(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - - __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); - __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); - __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ - MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | \ - MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - - __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); - break; - - case CLOCK_EVT_MODE_ONESHOT: - - __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); - __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | \ - MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, \ - TA(MCFPIT_PCSR)); - break; - - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } + __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); + __raw_writew(PIT_CYCLES_PER_JIFFY, TA(MCFPIT_PMR)); + __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | + MCFPIT_PCSR_OVW | MCFPIT_PCSR_RLD | + MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); + return 0; +} + +static int cf_pit_set_oneshot(struct clock_event_device *evt) +{ + __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); + __raw_writew(MCFPIT_PCSR_EN | MCFPIT_PCSR_PIE | + MCFPIT_PCSR_OVW | MCFPIT_PCSR_CLK64, TA(MCFPIT_PCSR)); + return 0; +} + +static int cf_pit_shutdown(struct clock_event_device *evt) +{ + __raw_writew(MCFPIT_PCSR_DISABLE, TA(MCFPIT_PCSR)); + return 0; } /* @@ -88,12 +79,15 @@ static int cf_pit_next_event(unsigned long delta, } struct clock_event_device cf_pit_clockevent = { - .name = "pit", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .set_mode = init_cf_pit_timer, - .set_next_event = cf_pit_next_event, - .shift = 32, - .irq = MCF_IRQ_PIT1, + .name = "pit", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .set_state_shutdown = cf_pit_shutdown, + .set_state_periodic = cf_pit_set_periodic, + .set_state_oneshot = cf_pit_set_oneshot, + .set_next_event = cf_pit_next_event, + .shift = 32, + .irq = MCF_IRQ_PIT1, }; -- GitLab From 50e48bd0673180311874d0c1bd88505eefd75c4e Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Wed, 12 Aug 2015 13:14:59 +0600 Subject: [PATCH 4643/7006] m68k/coldfire: use PFN_DOWN macro Replace ((x) >> PAGE_SHIFT) with the predefined PFN_DOWN macro. Signed-off-by: Alexander Kuleshov Signed-off-by: Greg Ungerer --- arch/m68k/coldfire/m54xx.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/m68k/coldfire/m54xx.c b/arch/m68k/coldfire/m54xx.c index 075aaabd13602..f7836c6a6b60e 100644 --- a/arch/m68k/coldfire/m54xx.c +++ b/arch/m68k/coldfire/m54xx.c @@ -25,6 +25,7 @@ #include #ifdef CONFIG_MMU #include +#include #endif /***************************************************************************/ @@ -91,13 +92,13 @@ static void __init mcf54xx_bootmem_alloc(void) m68k_memory[0].size = _ramend - _rambase; /* compute total pages in system */ - num_pages = (_ramend - _rambase) >> PAGE_SHIFT; + num_pages = PFN_DOWN(_ramend - _rambase); /* page numbers */ memstart = PAGE_ALIGN(_ramstart); - min_low_pfn = _rambase >> PAGE_SHIFT; - start_pfn = memstart >> PAGE_SHIFT; - max_low_pfn = _ramend >> PAGE_SHIFT; + min_low_pfn = PFN_DOWN(_rambase); + start_pfn = PFN_DOWN(memstart); + max_low_pfn = PFN_DOWN(_ramend); high_memory = (void *)_ramend; m68k_virt_to_node_shift = fls(_ramend - _rambase - 1) - 6; -- GitLab From 54cf7be992fe86571a3f07b96446cd5334b014ab Mon Sep 17 00:00:00 2001 From: Shaohui Xie Date: Fri, 21 Aug 2015 15:29:29 +0800 Subject: [PATCH 4644/7006] net: phy: add interrupt support for aquantia phy By implementing config_intr & ack_interrupt, now the phy can support link connect/disconnect interrupt. Signed-off-by: Shaohui Xie Signed-off-by: David S. Miller --- drivers/net/phy/aquantia.c | 49 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/net/phy/aquantia.c b/drivers/net/phy/aquantia.c index 73d347d7cb04c..d6111affbcb6c 100644 --- a/drivers/net/phy/aquantia.c +++ b/drivers/net/phy/aquantia.c @@ -44,6 +44,43 @@ static int aquantia_aneg_done(struct phy_device *phydev) return (reg < 0) ? reg : (reg & BMSR_ANEGCOMPLETE); } +static int aquantia_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 1); + if (err < 0) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 1); + if (err < 0) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0x1001); + } else { + err = phy_write_mmd(phydev, MDIO_MMD_AN, 0xd401, 0); + if (err < 0) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff00, 0); + if (err < 0) + return err; + + err = phy_write_mmd(phydev, MDIO_MMD_VEND1, 0xff01, 0); + } + + return err; +} + +static int aquantia_ack_interrupt(struct phy_device *phydev) +{ + int reg; + + reg = phy_read_mmd(phydev, MDIO_MMD_AN, 0xcc01); + return (reg < 0) ? reg : 0; +} + static int aquantia_read_status(struct phy_device *phydev) { int reg; @@ -85,8 +122,11 @@ static struct phy_driver aquantia_driver[] = { .phy_id_mask = 0xfffffff0, .name = "Aquantia AQ1202", .features = PHY_AQUANTIA_FEATURES, + .flags = PHY_HAS_INTERRUPT, .aneg_done = aquantia_aneg_done, .config_aneg = aquantia_config_aneg, + .config_intr = aquantia_config_intr, + .ack_interrupt = aquantia_ack_interrupt, .read_status = aquantia_read_status, .driver = { .owner = THIS_MODULE,}, }, @@ -95,8 +135,11 @@ static struct phy_driver aquantia_driver[] = { .phy_id_mask = 0xfffffff0, .name = "Aquantia AQ2104", .features = PHY_AQUANTIA_FEATURES, + .flags = PHY_HAS_INTERRUPT, .aneg_done = aquantia_aneg_done, .config_aneg = aquantia_config_aneg, + .config_intr = aquantia_config_intr, + .ack_interrupt = aquantia_ack_interrupt, .read_status = aquantia_read_status, .driver = { .owner = THIS_MODULE,}, }, @@ -105,8 +148,11 @@ static struct phy_driver aquantia_driver[] = { .phy_id_mask = 0xfffffff0, .name = "Aquantia AQR105", .features = PHY_AQUANTIA_FEATURES, + .flags = PHY_HAS_INTERRUPT, .aneg_done = aquantia_aneg_done, .config_aneg = aquantia_config_aneg, + .config_intr = aquantia_config_intr, + .ack_interrupt = aquantia_ack_interrupt, .read_status = aquantia_read_status, .driver = { .owner = THIS_MODULE,}, }, @@ -115,8 +161,11 @@ static struct phy_driver aquantia_driver[] = { .phy_id_mask = 0xfffffff0, .name = "Aquantia AQR405", .features = PHY_AQUANTIA_FEATURES, + .flags = PHY_HAS_INTERRUPT, .aneg_done = aquantia_aneg_done, .config_aneg = aquantia_config_aneg, + .config_intr = aquantia_config_intr, + .ack_interrupt = aquantia_ack_interrupt, .read_status = aquantia_read_status, .driver = { .owner = THIS_MODULE,}, }, -- GitLab From 6cc38acaaa995ad229447d87a3c5a181ba0cc161 Mon Sep 17 00:00:00 2001 From: Jani Nikula Date: Tue, 18 Aug 2015 14:28:55 +0300 Subject: [PATCH 4645/7006] drm/i915: fix VBT parsing for SDVO child device mapping MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 75067ddecf21271631bc018d2fb23ddd09b66aae Author: Antti Koskipaa Date: Fri Jul 10 14:10:55 2015 +0300 drm/i915: Per-DDI I_boost override increased size of union child_device_config without taking into account the size check in parse_sdvo_device_mapping(). Switch the function over to using the legacy struct only. Fixes: 75067ddecf21 ("drm/i915: Per-DDI I_boost override") Cc: Antti Koskipaa Cc: David Weinehall Reviewed-by: Ville Syrjälä Tested-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_bios.c | 50 +++++++++++++++---------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index c5b82fed95be2..64e5b15ae0b6c 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -401,7 +401,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, { struct sdvo_device_mapping *p_mapping; const struct bdb_general_definitions *p_defs; - const union child_device_config *p_child; + const struct old_child_dev_config *child; /* legacy */ int i, child_device_num, count; u16 block_size; @@ -410,14 +410,14 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("No general definition block is found, unable to construct sdvo mapping.\n"); return; } - /* judge whether the size of child device meets the requirements. - * If the child device size obtained from general definition block - * is different with sizeof(struct child_device_config), skip the - * parsing of sdvo device info + + /* + * Only parse SDVO mappings when the general definitions block child + * device size matches that of the *legacy* child device config + * struct. Thus, SDVO mapping will be skipped for newer VBT. */ - if (p_defs->child_dev_size != sizeof(*p_child)) { - /* different child dev size . Ignore it */ - DRM_DEBUG_KMS("different child size is found. Invalid.\n"); + if (p_defs->child_dev_size != sizeof(*child)) { + DRM_DEBUG_KMS("Unsupported child device size for SDVO mapping.\n"); return; } /* get the block size of general definitions */ @@ -427,37 +427,37 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, p_defs->child_dev_size; count = 0; for (i = 0; i < child_device_num; i++) { - p_child = child_device_ptr(p_defs, i); - if (!p_child->old.device_type) { + child = &child_device_ptr(p_defs, i)->old; + if (!child->device_type) { /* skip the device block if device type is invalid */ continue; } - if (p_child->old.slave_addr != SLAVE_ADDR1 && - p_child->old.slave_addr != SLAVE_ADDR2) { + if (child->slave_addr != SLAVE_ADDR1 && + child->slave_addr != SLAVE_ADDR2) { /* * If the slave address is neither 0x70 nor 0x72, * it is not a SDVO device. Skip it. */ continue; } - if (p_child->old.dvo_port != DEVICE_PORT_DVOB && - p_child->old.dvo_port != DEVICE_PORT_DVOC) { + if (child->dvo_port != DEVICE_PORT_DVOB && + child->dvo_port != DEVICE_PORT_DVOC) { /* skip the incorrect SDVO port */ DRM_DEBUG_KMS("Incorrect SDVO port. Skip it\n"); continue; } DRM_DEBUG_KMS("the SDVO device with slave addr %2x is found on" - " %s port\n", - p_child->old.slave_addr, - (p_child->old.dvo_port == DEVICE_PORT_DVOB) ? - "SDVOB" : "SDVOC"); - p_mapping = &(dev_priv->sdvo_mappings[p_child->old.dvo_port - 1]); + " %s port\n", + child->slave_addr, + (child->dvo_port == DEVICE_PORT_DVOB) ? + "SDVOB" : "SDVOC"); + p_mapping = &(dev_priv->sdvo_mappings[child->dvo_port - 1]); if (!p_mapping->initialized) { - p_mapping->dvo_port = p_child->old.dvo_port; - p_mapping->slave_addr = p_child->old.slave_addr; - p_mapping->dvo_wiring = p_child->old.dvo_wiring; - p_mapping->ddc_pin = p_child->old.ddc_pin; - p_mapping->i2c_pin = p_child->old.i2c_pin; + p_mapping->dvo_port = child->dvo_port; + p_mapping->slave_addr = child->slave_addr; + p_mapping->dvo_wiring = child->dvo_wiring; + p_mapping->ddc_pin = child->ddc_pin; + p_mapping->i2c_pin = child->i2c_pin; p_mapping->initialized = 1; DRM_DEBUG_KMS("SDVO device: dvo=%x, addr=%x, wiring=%d, ddc_pin=%d, i2c_pin=%d\n", p_mapping->dvo_port, @@ -469,7 +469,7 @@ parse_sdvo_device_mapping(struct drm_i915_private *dev_priv, DRM_DEBUG_KMS("Maybe one SDVO port is shared by " "two SDVO device.\n"); } - if (p_child->old.slave2_addr) { + if (child->slave2_addr) { /* Maybe this is a SDVO device with multiple inputs */ /* And the mapping info is not added */ DRM_DEBUG_KMS("there exists the slave2_addr. Maybe this" -- GitLab From af7080f555e556094762c03c31cabdbe072b16b6 Mon Sep 17 00:00:00 2001 From: "Thulasimani,Sivakumar" Date: Tue, 18 Aug 2015 11:07:59 +0530 Subject: [PATCH 4646/7006] drm/i915: fix link rates reported for SKL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the bug that SKL SKUs before B0 might return HBR2 as supported even though it is not supposed to be enabled on such platforms. v2: optimize if else condition (Jani) Reviewed-by: Ville Syrjälä Signed-off-by: Sivakumar Thulasimani [Jani: minor whitespace fix.] Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index d0f4eb793cf56..260ff8b084377 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1223,21 +1223,24 @@ static bool intel_dp_source_supports_hbr2(struct drm_device *dev) static int intel_dp_source_rates(struct drm_device *dev, const int **source_rates) { + int size; + if (IS_BROXTON(dev)) { *source_rates = bxt_rates; - return ARRAY_SIZE(bxt_rates); + size = ARRAY_SIZE(bxt_rates); } else if (IS_SKYLAKE(dev)) { *source_rates = skl_rates; - return ARRAY_SIZE(skl_rates); + size = ARRAY_SIZE(skl_rates); + } else { + *source_rates = default_rates; + size = ARRAY_SIZE(default_rates); } - *source_rates = default_rates; - /* This depends on the fact that 5.4 is last value in the array */ - if (intel_dp_source_supports_hbr2(dev)) - return (DP_LINK_BW_5_4 >> 3) + 1; - else - return (DP_LINK_BW_2_7 >> 3) + 1; + if (!intel_dp_source_supports_hbr2(dev)) + size--; + + return size; } static void -- GitLab From e2d6cf7f3696c87546f7fefe9bac79ee09db4bef Mon Sep 17 00:00:00 2001 From: David Weinehall Date: Fri, 21 Aug 2015 16:52:01 +0300 Subject: [PATCH 4647/7006] drm/i915: Allow parsing of variable size child device entries from VBT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VBT version 196 increased the size of common_child_dev_config. The parser code assumed that the size of this structure would not change. The modified code now copies the amount needed based on the VBT version, and emits a debug message if the VBT version is unknown (too new); since the struct config block won't shrink in newer versions it should be harmless to copy the maximum known size in such cases, so that's what we do, but emitting the warning is probably sensible anyway. In the longer run it might make sense to modify the parser code to use a version/feature mapping, rather than hardcoding things like this, but for now the variants are fairly manageable. This fixes a regression introduced in commit 75067ddecf21271631bc018d2fb23ddd09b66aae Author: Antti Koskipaa Date: Fri Jul 10 14:10:55 2015 +0300 drm/i915: Per-DDI I_boost override since that commit changed the child device config size without updating the checks and memcpy. v2: Stricter size checks v3 by Jani: - Keep the checks strict, and warnigns verbose, but keep going anyway. - Take care to copy the max amount of child device config we can. - Fix the messages. Signed-off-by: David Weinehall Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_bios.c | 37 +++++++++++++++++++++++++++---- drivers/gpu/drm/i915/intel_bios.h | 6 +++-- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 64e5b15ae0b6c..be83b77aa018b 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -1051,17 +1051,39 @@ parse_device_mapping(struct drm_i915_private *dev_priv, const union child_device_config *p_child; union child_device_config *child_dev_ptr; int i, child_device_num, count; - u16 block_size; + u8 expected_size; + u16 block_size; p_defs = find_section(bdb, BDB_GENERAL_DEFINITIONS); if (!p_defs) { DRM_DEBUG_KMS("No general definition block is found, no devices defined.\n"); return; } - if (p_defs->child_dev_size < sizeof(*p_child)) { - DRM_ERROR("General definiton block child device size is too small.\n"); + if (bdb->version < 195) { + expected_size = sizeof(struct old_child_dev_config); + } else if (bdb->version == 195) { + expected_size = 37; + } else if (bdb->version <= 197) { + expected_size = 38; + } else { + expected_size = 38; + BUILD_BUG_ON(sizeof(*p_child) < 38); + DRM_DEBUG_DRIVER("Expected child device config size for VBT version %u not known; assuming %u\n", + bdb->version, expected_size); + } + + /* The legacy sized child device config is the minimum we need. */ + if (p_defs->child_dev_size < sizeof(struct old_child_dev_config)) { + DRM_ERROR("Child device config size %u is too small.\n", + p_defs->child_dev_size); return; } + + /* Flag an error for unexpected size, but continue anyway. */ + if (p_defs->child_dev_size != expected_size) + DRM_ERROR("Unexpected child device config size %u (expected %u for VBT version %u)\n", + p_defs->child_dev_size, expected_size, bdb->version); + /* get the block size of general definitions */ block_size = get_blocksize(p_defs); /* get the number of child device */ @@ -1106,7 +1128,14 @@ parse_device_mapping(struct drm_i915_private *dev_priv, child_dev_ptr = dev_priv->vbt.child_dev + count; count++; - memcpy(child_dev_ptr, p_child, sizeof(*p_child)); + + /* + * Copy as much as we know (sizeof) and is available + * (child_dev_size) of the child device. Accessing the data must + * depend on VBT version. + */ + memcpy(child_dev_ptr, p_child, + min_t(size_t, p_defs->child_dev_size, sizeof(*p_child))); } return; } diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 6d909efbf43f3..06d0dbde2be63 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -203,9 +203,11 @@ struct bdb_general_features { #define DEVICE_PORT_DVOB 0x01 #define DEVICE_PORT_DVOC 0x02 -/* We used to keep this struct but without any version control. We should avoid +/* + * We used to keep this struct but without any version control. We should avoid * using it in the future, but it should be safe to keep using it in the old - * code. */ + * code. Do not change; we rely on its size. + */ struct old_child_dev_config { u16 handle; u16 device_type; -- GitLab From 7e97229b3920568067feefc8b49a98534c1a908c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 24 Aug 2015 13:43:14 +0530 Subject: [PATCH 4648/7006] dmaengine: sort the makefile dmaengine makefile grew over the years, unfortunately without any order to it. So order by core, dmatest and driver sections and sort these sections alphabetically Signed-off-by: Vinod Koul --- drivers/dma/Makefile | 88 +++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 41 deletions(-) diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile index a4809849b6c5e..25e0705053e96 100644 --- a/drivers/dma/Makefile +++ b/drivers/dma/Makefile @@ -1,62 +1,68 @@ +#dmaengine debug flags subdir-ccflags-$(CONFIG_DMADEVICES_DEBUG) := -DDEBUG subdir-ccflags-$(CONFIG_DMADEVICES_VDEBUG) += -DVERBOSE_DEBUG +#core obj-$(CONFIG_DMA_ENGINE) += dmaengine.o obj-$(CONFIG_DMA_VIRTUAL_CHANNELS) += virt-dma.o obj-$(CONFIG_DMA_ACPI) += acpi-dma.o obj-$(CONFIG_DMA_OF) += of-dma.o +#dmatest obj-$(CONFIG_DMATEST) += dmatest.o -obj-$(CONFIG_INTEL_IOATDMA) += ioat/ -obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o -obj-$(CONFIG_FSL_DMA) += fsldma.o -obj-$(CONFIG_HSU_DMA) += hsu/ -obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o -obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ -obj-$(CONFIG_MV_XOR) += mv_xor.o -obj-$(CONFIG_DW_DMAC_CORE) += dw/ + +#devices +obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o +obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o obj-$(CONFIG_AT_XDMAC) += at_xdmac.o -obj-$(CONFIG_MX3_IPU) += ipu/ -obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o -obj-$(CONFIG_RENESAS_DMA) += sh/ +obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o -obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/ -obj-$(CONFIG_IMX_SDMA) += imx-sdma.o +obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o +obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o +obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o +obj-$(CONFIG_DMA_OMAP) += omap-dma.o +obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o +obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o +obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o +obj-$(CONFIG_DW_DMAC_CORE) += dw/ +obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o +obj-$(CONFIG_FSL_DMA) += fsldma.o +obj-$(CONFIG_FSL_EDMA) += fsl-edma.o +obj-$(CONFIG_FSL_RAID) += fsl_raid.o +obj-$(CONFIG_HSU_DMA) += hsu/ +obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o obj-$(CONFIG_IMX_DMA) += imx-dma.o +obj-$(CONFIG_IMX_SDMA) += imx-sdma.o +obj-$(CONFIG_INTEL_IOATDMA) += ioat/ +obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o +obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o +obj-$(CONFIG_K3_DMA) += k3dma.o +obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o +obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o +obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o +obj-$(CONFIG_MOXART_DMA) += moxart-dma.o +obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o +obj-$(CONFIG_MV_XOR) += mv_xor.o obj-$(CONFIG_MXS_DMA) += mxs-dma.o +obj-$(CONFIG_MX3_IPU) += ipu/ +obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o +obj-$(CONFIG_PCH_DMA) += pch_dma.o +obj-$(CONFIG_PL330_DMA) += pl330.o +obj-$(CONFIG_PPC_BESTCOMM) += bestcomm/ obj-$(CONFIG_PXA_DMA) += pxa_dma.o -obj-$(CONFIG_TIMB_DMA) += timb_dma.o +obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o +obj-$(CONFIG_RENESAS_DMA) += sh/ obj-$(CONFIG_SIRF_DMA) += sirf-dma.o -obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o -obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o obj-$(CONFIG_S3C24XX_DMAC) += s3c24xx-dma.o -obj-$(CONFIG_LPC18XX_DMAMUX) += lpc18xx-dmamux.o -obj-$(CONFIG_PL330_DMA) += pl330.o -obj-$(CONFIG_PCH_DMA) += pch_dma.o -obj-$(CONFIG_AMBA_PL08X) += amba-pl08x.o -obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o -obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o -obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o -obj-$(CONFIG_DMA_OMAP) += omap-dma.o -obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o -obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o -obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o -obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o -obj-$(CONFIG_DMA_JZ4780) += dma-jz4780.o +obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o +obj-$(CONFIG_TEGRA20_APB_DMA) += tegra20-apb-dma.o +obj-$(CONFIG_TIMB_DMA) += timb_dma.o obj-$(CONFIG_TI_CPPI41) += cppi41.o -obj-$(CONFIG_K3_DMA) += k3dma.o -obj-$(CONFIG_MOXART_DMA) += moxart-dma.o -obj-$(CONFIG_FSL_RAID) += fsl_raid.o -obj-$(CONFIG_FSL_EDMA) += fsl-edma.o -obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o -obj-y += xilinx/ -obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o -obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o -obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o -obj-$(CONFIG_DMA_SUN4I) += sun4i-dma.o -obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o +obj-$(CONFIG_TI_DMA_CROSSBAR) += ti-dma-crossbar.o +obj-$(CONFIG_TI_EDMA) += edma.o obj-$(CONFIG_XGENE_DMA) += xgene-dma.o obj-$(CONFIG_ZX_DMA) += zx296702_dma.o -obj-$(CONFIG_AXI_DMAC) += dma-axi-dmac.o + +obj-y += xilinx/ -- GitLab From 3c21619077beb40ae3e49eb868798377e69dd940 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 24 Aug 2015 13:43:14 +0530 Subject: [PATCH 4649/7006] dmaengine: sort the Kconfig dmaengine Kconfig grew over the years, unfortunately without any order to it. So order by core, driver and client sections, and sort these sections alphabetically Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 628 ++++++++++++++++++++++---------------------- 1 file changed, 317 insertions(+), 311 deletions(-) diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index 81e1937fcd6de..7ba2847a50774 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -33,27 +33,29 @@ if DMADEVICES comment "DMA Devices" -config INTEL_MIC_X100_DMA - tristate "Intel MIC X100 DMA Driver" - depends on 64BIT && X86 && INTEL_MIC_BUS - select DMA_ENGINE - help - This enables DMA support for the Intel Many Integrated Core - (MIC) family of PCIe form factor coprocessor X100 devices that - run a 64 bit Linux OS. This driver will be used by both MIC - host and card drivers. - - If you are building host kernel with a MIC device or a card - kernel for a MIC device, then say M (recommended) or Y, else - say N. If unsure say N. +#core +config ASYNC_TX_ENABLE_CHANNEL_SWITCH + bool - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . +config ARCH_HAS_ASYNC_TX_FIND_CHANNEL + bool -config ASYNC_TX_ENABLE_CHANNEL_SWITCH +config DMA_ENGINE bool +config DMA_VIRTUAL_CHANNELS + tristate + +config DMA_ACPI + def_bool y + depends on ACPI + +config DMA_OF + def_bool y + depends on OF + select DMA_ENGINE + +#devices config AMBA_PL08X bool "ARM PrimeCell PL080 or PL081 support" depends on ARM_AMBA @@ -63,38 +65,15 @@ config AMBA_PL08X Platform has a PL08x DMAC device which can provide DMA engine support -config LPC18XX_DMAMUX - bool "NXP LPC18xx/43xx DMA MUX for PL080" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on OF && AMBA_PL08X - select MFD_SYSCON - help - Enable support for DMA on NXP LPC18xx/43xx platforms - with PL080 and multiplexed DMA request lines. - -config INTEL_IOATDMA - tristate "Intel I/OAT DMA support" - depends on PCI && X86_64 +config AMCC_PPC440SPE_ADMA + tristate "AMCC PPC440SPe ADMA support" + depends on 440SPe || 440SP select DMA_ENGINE select DMA_ENGINE_RAID - select DCA - help - Enable support for the Intel(R) I/OAT DMA engine present - in recent Intel Xeon chipsets. - - Say Y here if you have such a chipset. - - If unsure, say N. - -config INTEL_IOP_ADMA - tristate "Intel IOP ADMA support" - depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX - select DMA_ENGINE + select ARCH_HAS_ASYNC_TX_FIND_CHANNEL select ASYNC_TX_ENABLE_CHANNEL_SWITCH help - Enable support for the Intel(R) IOP Series RAID engines. - -source "drivers/dma/dw/Kconfig" + Enable support for the AMCC PPC440SPe RAID engines. config AT_HDMAC tristate "Atmel AHB DMA support" @@ -110,6 +89,89 @@ config AT_XDMAC help Support the Atmel XDMA controller. +config AXI_DMAC + tristate "Analog Devices AXI-DMAC DMA support" + depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_SOCFPGA || COMPILE_TEST + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Enable support for the Analog Devices AXI-DMAC peripheral. This DMA + controller is often used in Analog Device's reference designs for FPGA + platforms. + +config COH901318 + bool "ST-Ericsson COH901318 DMA support" + select DMA_ENGINE + depends on ARCH_U300 + help + Enable support for ST-Ericsson COH 901 318 DMA. + +config DMA_BCM2835 + tristate "BCM2835 DMA engine support" + depends on ARCH_BCM2835 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + +config DMA_JZ4740 + tristate "JZ4740 DMA support" + depends on MACH_JZ4740 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + +config DMA_JZ4780 + tristate "JZ4780 DMA support" + depends on MACH_JZ4780 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + This selects support for the DMA controller in Ingenic JZ4780 SoCs. + If you have a board based on such a SoC and wish to use DMA for + devices which can use the DMA controller, say Y or M here. + +config DMA_OMAP + tristate "OMAP DMA support" + depends on ARCH_OMAP + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + select TI_DMA_CROSSBAR if SOC_DRA7XX + +config DMA_SA11X0 + tristate "SA-11x0 DMA support" + depends on ARCH_SA1100 + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support the DMA engine found on Intel StrongARM SA-1100 and + SA-1110 SoCs. This DMA engine can only be used with on-chip + devices. + +config DMA_SUN4I + tristate "Allwinner A10 DMA SoCs support" + depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || COMPILE_TEST + default (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I) + select DMA_ENGINE + select DMA_OF + select DMA_VIRTUAL_CHANNELS + help + Enable support for the DMA controller present in the sun4i, + sun5i and sun7i Allwinner ARM SoCs. + +config DMA_SUN6I + tristate "Allwinner A31 SoCs DMA support" + depends on MACH_SUN6I || MACH_SUN8I || COMPILE_TEST + depends on RESET_CONTROLLER + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support for the DMA engine first found in Allwinner A31 SoCs. + +config EP93XX_DMA + bool "Cirrus Logic EP93xx DMA support" + depends on ARCH_EP93XX + select DMA_ENGINE + help + Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller. + config FSL_DMA tristate "Freescale Elo series DMA support" depends on FSL_SOC @@ -121,6 +183,16 @@ config FSL_DMA EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is on some Txxx and Bxxx parts. +config FSL_EDMA + tristate "Freescale eDMA engine support" + depends on OF + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + help + Support the Freescale eDMA engine with programmable channel + multiplexing capability for DMA request sources(slot). + This module can be found on Freescale Vybrid and LS-1 SoCs. + config FSL_RAID tristate "Freescale RAID engine Support" depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH @@ -132,153 +204,167 @@ config FSL_RAID the capability to offload memcpy, xor and pq computation for raid5/6. -source "drivers/dma/hsu/Kconfig" - -config MPC512X_DMA - tristate "Freescale MPC512x built-in DMA engine support" - depends on PPC_MPC512x || PPC_MPC831x - select DMA_ENGINE - ---help--- - Enable support for the Freescale MPC512x built-in DMA engine. - -source "drivers/dma/bestcomm/Kconfig" - -config MV_XOR - bool "Marvell XOR engine support" - depends on PLAT_ORION +config IMG_MDC_DMA + tristate "IMG MDC support" + depends on MIPS || COMPILE_TEST + depends on MFD_SYSCON select DMA_ENGINE - select DMA_ENGINE_RAID - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - ---help--- - Enable support for the Marvell XOR engine. + select DMA_VIRTUAL_CHANNELS + help + Enable support for the IMG multi-threaded DMA controller (MDC). -config MX3_IPU - bool "MX3x Image Processing Unit support" +config IMX_DMA + tristate "i.MX DMA support" depends on ARCH_MXC select DMA_ENGINE - default y help - If you plan to use the Image Processing unit in the i.MX3x, say - Y here. If unsure, select Y. + Support the i.MX DMA engine. This engine is integrated into + Freescale i.MX1/21/27 chips. -config MX3_IPU_IRQS - int "Number of dynamically mapped interrupts for IPU" - depends on MX3_IPU - range 2 137 - default 4 +config IMX_SDMA + tristate "i.MX SDMA support" + depends on ARCH_MXC + select DMA_ENGINE help - Out of 137 interrupt sources on i.MX31 IPU only very few are used. - To avoid bloating the irq_desc[] array we allocate a sufficient - number of IRQ slots and map them dynamically to specific sources. + Support the i.MX SDMA engine. This engine is integrated into + Freescale i.MX25/31/35/51/53/6 chips. -config PXA_DMA - bool "PXA DMA support" - depends on (ARCH_MMP || ARCH_PXA) +config INTEL_IOATDMA + tristate "Intel I/OAT DMA support" + depends on PCI && X86_64 select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS + select DMA_ENGINE_RAID + select DCA help - Support the DMA engine for PXA. It is also compatible with MMP PDMA - platform. The internal DMA IP of all PXA variants is supported, with - 16 to 32 channels for peripheral to memory or memory to memory - transfers. + Enable support for the Intel(R) I/OAT DMA engine present + in recent Intel Xeon chipsets. -config TXX9_DMAC - tristate "Toshiba TXx9 SoC DMA support" - depends on MACH_TX49XX || MACH_TX39XX + Say Y here if you have such a chipset. + + If unsure, say N. + +config INTEL_IOP_ADMA + tristate "Intel IOP ADMA support" + depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX select DMA_ENGINE + select ASYNC_TX_ENABLE_CHANNEL_SWITCH help - Support the TXx9 SoC internal DMA controller. This can be - integrated in chips such as the Toshiba TX4927/38/39. + Enable support for the Intel(R) IOP Series RAID engines. -config TEGRA20_APB_DMA - bool "NVIDIA Tegra20 APB DMA support" - depends on ARCH_TEGRA +config INTEL_MIC_X100_DMA + tristate "Intel MIC X100 DMA Driver" + depends on 64BIT && X86 && INTEL_MIC_BUS select DMA_ENGINE help - Support for the NVIDIA Tegra20 APB DMA controller driver. The - DMA controller is having multiple DMA channel which can be - configured for different peripherals like audio, UART, SPI, - I2C etc which is in APB bus. - This DMA controller transfers data from memory to peripheral fifo - or vice versa. It does not support memory to memory data transfer. + This enables DMA support for the Intel Many Integrated Core + (MIC) family of PCIe form factor coprocessor X100 devices that + run a 64 bit Linux OS. This driver will be used by both MIC + host and card drivers. -config S3C24XX_DMAC - tristate "Samsung S3C24XX DMA support" - depends on ARCH_S3C24XX + If you are building host kernel with a MIC device or a card + kernel for a MIC device, then say M (recommended) or Y, else + say N. If unsure say N. + + More information about the Intel MIC family as well as the Linux + OS and tools for MIC to use with this driver are available from + . + +config K3_DMA + tristate "Hisilicon K3 DMA support" + depends on ARCH_HI3xxx select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help - Support for the Samsung S3C24XX DMA controller driver. The - DMA controller is having multiple DMA channels which can be - configured for different peripherals like audio, UART, SPI. - The DMA controller can transfer data from memory to peripheral, - periphal to memory, periphal to periphal and memory to memory. + Support the DMA engine for Hisilicon K3 platform + devices. -source "drivers/dma/sh/Kconfig" +config LPC18XX_DMAMUX + bool "NXP LPC18xx/43xx DMA MUX for PL080" + depends on ARCH_LPC18XX || COMPILE_TEST + depends on OF && AMBA_PL08X + select MFD_SYSCON + help + Enable support for DMA on NXP LPC18xx/43xx platforms + with PL080 and multiplexed DMA request lines. -config COH901318 - bool "ST-Ericsson COH901318 DMA support" +config MMP_PDMA + bool "MMP PDMA support" + depends on (ARCH_MMP || ARCH_PXA) select DMA_ENGINE - depends on ARCH_U300 help - Enable support for ST-Ericsson COH 901 318 DMA. + Support the MMP PDMA engine for PXA and MMP platform. -config STE_DMA40 - bool "ST-Ericsson DMA40 support" - depends on ARCH_U8500 +config MMP_TDMA + bool "MMP Two-Channel DMA support" + depends on ARCH_MMP select DMA_ENGINE + select MMP_SRAM help - Support for ST-Ericsson DMA40 controller + Support the MMP Two-Channel DMA engine. + This engine used for MMP Audio DMA and pxa910 SQU. + It needs sram driver under mach-mmp. -config AMCC_PPC440SPE_ADMA - tristate "AMCC PPC440SPe ADMA support" - depends on 440SPe || 440SP +config MOXART_DMA + tristate "MOXART DMA support" + depends on ARCH_MOXART select DMA_ENGINE - select DMA_ENGINE_RAID - select ARCH_HAS_ASYNC_TX_FIND_CHANNEL - select ASYNC_TX_ENABLE_CHANNEL_SWITCH + select DMA_OF + select DMA_VIRTUAL_CHANNELS help - Enable support for the AMCC PPC440SPe RAID engines. + Enable support for the MOXA ART SoC DMA controller. + + Say Y here if you enabled MMP ADMA, otherwise say N. -config TIMB_DMA - tristate "Timberdale FPGA DMA support" - depends on MFD_TIMBERDALE +config MPC512X_DMA + tristate "Freescale MPC512x built-in DMA engine support" + depends on PPC_MPC512x || PPC_MPC831x select DMA_ENGINE - help - Enable support for the Timberdale FPGA DMA engine. + ---help--- + Enable support for the Freescale MPC512x built-in DMA engine. -config SIRF_DMA - tristate "CSR SiRFprimaII/SiRFmarco DMA support" - depends on ARCH_SIRF +config MV_XOR + bool "Marvell XOR engine support" + depends on PLAT_ORION select DMA_ENGINE - help - Enable support for the CSR SiRFprimaII DMA engine. + select DMA_ENGINE_RAID + select ASYNC_TX_ENABLE_CHANNEL_SWITCH + ---help--- + Enable support for the Marvell XOR engine. -config TI_EDMA - bool "TI EDMA support" - depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE +config MXS_DMA + bool "MXS DMA support" + depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q + select STMP_DEVICE select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - select TI_PRIV_EDMA - default n help - Enable support for the TI EDMA controller. This DMA - engine is found on TI DaVinci and AM33xx parts. + Support the MXS DMA engine. This engine including APBH-DMA + and APBX-DMA is integrated into Freescale i.MX23/28/MX6Q/MX6DL chips. -config TI_DMA_CROSSBAR - bool +config MX3_IPU + bool "MX3x Image Processing Unit support" + depends on ARCH_MXC + select DMA_ENGINE + default y + help + If you plan to use the Image Processing unit in the i.MX3x, say + Y here. If unsure, select Y. -config ARCH_HAS_ASYNC_TX_FIND_CHANNEL - bool +config MX3_IPU_IRQS + int "Number of dynamically mapped interrupts for IPU" + depends on MX3_IPU + range 2 137 + default 4 + help + Out of 137 interrupt sources on i.MX31 IPU only very few are used. + To avoid bloating the irq_desc[] array we allocate a sufficient + number of IRQ slots and map them dynamically to specific sources. -config PL330_DMA - tristate "DMA API Driver for PL330" +config NBPFAXI_DMA + tristate "Renesas Type-AXI NBPF DMA support" select DMA_ENGINE - depends on ARM_AMBA + depends on ARM || COMPILE_TEST help - Select if your platform has one or more PL330 DMACs. - You need to provide platform specific settings via - platform_data for a dma-pl330 device. + Support for "Type-AXI" NBPF DMA IPs from Renesas config PCH_DMA tristate "Intel EG20T PCH / LAPIS Semicon IOH(ML7213/ML7223/ML7831) DMA" @@ -294,72 +380,87 @@ config PCH_DMA ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. -config IMX_SDMA - tristate "i.MX SDMA support" - depends on ARCH_MXC +config PL330_DMA + tristate "DMA API Driver for PL330" select DMA_ENGINE + depends on ARM_AMBA help - Support the i.MX SDMA engine. This engine is integrated into - Freescale i.MX25/31/35/51/53/6 chips. + Select if your platform has one or more PL330 DMACs. + You need to provide platform specific settings via + platform_data for a dma-pl330 device. -config IMX_DMA - tristate "i.MX DMA support" - depends on ARCH_MXC +config PXA_DMA + bool "PXA DMA support" + depends on (ARCH_MMP || ARCH_PXA) select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS help - Support the i.MX DMA engine. This engine is integrated into - Freescale i.MX1/21/27 chips. + Support the DMA engine for PXA. It is also compatible with MMP PDMA + platform. The internal DMA IP of all PXA variants is supported, with + 16 to 32 channels for peripheral to memory or memory to memory + transfers. -config MXS_DMA - bool "MXS DMA support" - depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q - select STMP_DEVICE +config QCOM_BAM_DMA + tristate "QCOM BAM DMA support" + depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) + select DMA_ENGINE + select DMA_VIRTUAL_CHANNELS + ---help--- + Enable support for the QCOM BAM DMA controller. This controller + provides DMA capabilities for a variety of on-chip devices. + +config SIRF_DMA + tristate "CSR SiRFprimaII/SiRFmarco DMA support" + depends on ARCH_SIRF select DMA_ENGINE help - Support the MXS DMA engine. This engine including APBH-DMA - and APBX-DMA is integrated into Freescale i.MX23/28/MX6Q/MX6DL chips. + Enable support for the CSR SiRFprimaII DMA engine. -config EP93XX_DMA - bool "Cirrus Logic EP93xx DMA support" - depends on ARCH_EP93XX +config STE_DMA40 + bool "ST-Ericsson DMA40 support" + depends on ARCH_U8500 select DMA_ENGINE help - Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller. + Support for ST-Ericsson DMA40 controller -config DMA_SA11X0 - tristate "SA-11x0 DMA support" - depends on ARCH_SA1100 +config S3C24XX_DMAC + tristate "Samsung S3C24XX DMA support" + depends on ARCH_S3C24XX select DMA_ENGINE select DMA_VIRTUAL_CHANNELS help - Support the DMA engine found on Intel StrongARM SA-1100 and - SA-1110 SoCs. This DMA engine can only be used with on-chip - devices. + Support for the Samsung S3C24XX DMA controller driver. The + DMA controller is having multiple DMA channels which can be + configured for different peripherals like audio, UART, SPI. + The DMA controller can transfer data from memory to peripheral, + periphal to memory, periphal to periphal and memory to memory. -config MMP_TDMA - bool "MMP Two-Channel DMA support" - depends on ARCH_MMP +config TXX9_DMAC + tristate "Toshiba TXx9 SoC DMA support" + depends on MACH_TX49XX || MACH_TX39XX select DMA_ENGINE - select MMP_SRAM help - Support the MMP Two-Channel DMA engine. - This engine used for MMP Audio DMA and pxa910 SQU. - It needs sram driver under mach-mmp. - - Say Y here if you enabled MMP ADMA, otherwise say N. + Support the TXx9 SoC internal DMA controller. This can be + integrated in chips such as the Toshiba TX4927/38/39. -config DMA_OMAP - tristate "OMAP DMA support" - depends on ARCH_OMAP +config TEGRA20_APB_DMA + bool "NVIDIA Tegra20 APB DMA support" + depends on ARCH_TEGRA select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - select TI_DMA_CROSSBAR if SOC_DRA7XX + help + Support for the NVIDIA Tegra20 APB DMA controller driver. The + DMA controller is having multiple DMA channel which can be + configured for different peripherals like audio, UART, SPI, + I2C etc which is in APB bus. + This DMA controller transfers data from memory to peripheral fifo + or vice versa. It does not support memory to memory data transfer. -config DMA_BCM2835 - tristate "BCM2835 DMA engine support" - depends on ARCH_BCM2835 +config TIMB_DMA + tristate "Timberdale FPGA DMA support" + depends on MFD_TIMBERDALE select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS + help + Enable support for the Timberdale FPGA DMA engine. config TI_CPPI41 tristate "AM33xx CPPI41 DMA support" @@ -369,56 +470,28 @@ config TI_CPPI41 The Communications Port Programming Interface (CPPI) 4.1 DMA engine is currently used by the USB driver on AM335x platforms. -config MMP_PDMA - bool "MMP PDMA support" - depends on (ARCH_MMP || ARCH_PXA) - select DMA_ENGINE - help - Support the MMP PDMA engine for PXA and MMP platform. - -config DMA_JZ4740 - tristate "JZ4740 DMA support" - depends on MACH_JZ4740 - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - -config DMA_JZ4780 - tristate "JZ4780 DMA support" - depends on MACH_JZ4780 - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - This selects support for the DMA controller in Ingenic JZ4780 SoCs. - If you have a board based on such a SoC and wish to use DMA for - devices which can use the DMA controller, say Y or M here. +config TI_DMA_CROSSBAR + bool -config K3_DMA - tristate "Hisilicon K3 DMA support" - depends on ARCH_HI3xxx +config TI_EDMA + bool "TI EDMA support" + depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE select DMA_ENGINE select DMA_VIRTUAL_CHANNELS + select TI_PRIV_EDMA + default n help - Support the DMA engine for Hisilicon K3 platform - devices. + Enable support for the TI EDMA controller. This DMA + engine is found on TI DaVinci and AM33xx parts. -config MOXART_DMA - tristate "MOXART DMA support" - depends on ARCH_MOXART - select DMA_ENGINE - select DMA_OF - select DMA_VIRTUAL_CHANNELS - help - Enable support for the MOXA ART SoC DMA controller. - -config FSL_EDMA - tristate "Freescale eDMA engine support" - depends on OF +config XGENE_DMA + tristate "APM X-Gene DMA support" + depends on ARCH_XGENE || COMPILE_TEST select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS + select DMA_ENGINE_RAID + select ASYNC_TX_ENABLE_CHANNEL_SWITCH help - Support the Freescale eDMA engine with programmable channel - multiplexing capability for DMA request sources(slot). - This module can be found on Freescale Vybrid and LS-1 SoCs. + Enable support for the APM X-Gene SoC DMA engine. config XILINX_VDMA tristate "Xilinx AXI VDMA Engine" @@ -434,50 +507,6 @@ config XILINX_VDMA channels, Memory Mapped to Stream (MM2S) and Stream to Memory Mapped (S2MM) for the data transfers. -config DMA_SUN4I - tristate "Allwinner A10 DMA SoCs support" - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I || COMPILE_TEST - default (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I) - select DMA_ENGINE - select DMA_OF - select DMA_VIRTUAL_CHANNELS - help - Enable support for the DMA controller present in the sun4i, - sun5i and sun7i Allwinner ARM SoCs. - -config DMA_SUN6I - tristate "Allwinner A31 SoCs DMA support" - depends on MACH_SUN6I || MACH_SUN8I || COMPILE_TEST - depends on RESET_CONTROLLER - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support for the DMA engine first found in Allwinner A31 SoCs. - -config NBPFAXI_DMA - tristate "Renesas Type-AXI NBPF DMA support" - select DMA_ENGINE - depends on ARM || COMPILE_TEST - help - Support for "Type-AXI" NBPF DMA IPs from Renesas - -config IMG_MDC_DMA - tristate "IMG MDC support" - depends on MIPS || COMPILE_TEST - depends on MFD_SYSCON - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the IMG multi-threaded DMA controller (MDC). - -config XGENE_DMA - tristate "APM X-Gene DMA support" - depends on ARCH_XGENE || COMPILE_TEST - select DMA_ENGINE - select DMA_ENGINE_RAID - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - help - Enable support for the APM X-Gene SoC DMA engine. config ZX_DMA tristate "ZTE ZX296702 DMA support" depends on ARCH_ZX @@ -486,21 +515,17 @@ config ZX_DMA help Support the DMA engine for ZTE ZX296702 platform devices. -config DMA_ENGINE - bool -config DMA_VIRTUAL_CHANNELS - tristate +# driver files +source "drivers/dma/bestcomm/Kconfig" -config DMA_ACPI - def_bool y - depends on ACPI +source "drivers/dma/dw/Kconfig" -config DMA_OF - def_bool y - depends on OF - select DMA_ENGINE +source "drivers/dma/hsu/Kconfig" + +source "drivers/dma/sh/Kconfig" +# clients comment "DMA Clients" depends on DMA_ENGINE @@ -525,23 +550,4 @@ config DMATEST config DMA_ENGINE_RAID bool -config QCOM_BAM_DMA - tristate "QCOM BAM DMA support" - depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - ---help--- - Enable support for the QCOM BAM DMA controller. This controller - provides DMA capabilities for a variety of on-chip devices. - -config AXI_DMAC - tristate "Analog Devices AXI-DMAC DMA support" - depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_SOCFPGA || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the Analog Devices AXI-DMAC peripheral. This DMA - controller is often used in Analog Device's reference designs for FPGA - platforms. - endif -- GitLab From 6c310c46efeae99a1569947b8c60d4aab36bd61c Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 24 Aug 2015 13:43:14 +0530 Subject: [PATCH 4650/7006] dmaengine: sort the dw Kconfig Signed-off-by: Vinod Koul --- drivers/dma/dw/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/dma/dw/Kconfig b/drivers/dma/dw/Kconfig index 36e02f0f645e3..e00c9b0229647 100644 --- a/drivers/dma/dw/Kconfig +++ b/drivers/dma/dw/Kconfig @@ -6,6 +6,9 @@ config DW_DMAC_CORE tristate select DMA_ENGINE +config DW_DMAC_BIG_ENDIAN_IO + bool + config DW_DMAC tristate "Synopsys DesignWare AHB DMA platform driver" select DW_DMAC_CORE @@ -23,6 +26,3 @@ config DW_DMAC_PCI Support the Synopsys DesignWare AHB DMA controller on the platfroms that enumerate it as a PCI device. For example, Intel Medfield has integrated this GPDMA controller. - -config DW_DMAC_BIG_ENDIAN_IO - bool -- GitLab From 5b9eaa5659b32cf6c85a492d2e3bfa7a3a413144 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Tue, 30 Jun 2015 17:53:59 +0100 Subject: [PATCH 4651/7006] pinctrl: sh-pfc: Implement pinconf power-source param for voltage switching The pfc in the R8A7790 (and probably others in the R-Car gen 2 family) supports switching SDHI signals between 3.3V and 1.8V nominal voltage, and the SD driver should do that when switching to and from UHS modes. Add a flag for pins that have configurable I/O voltage and SoC operations to get and set the nominal voltage. Implement the pinconf power-source parameter using these operations. Signed-off-by: Ben Hutchings Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- .../bindings/pinctrl/renesas,pfc-pinctrl.txt | 4 +- drivers/pinctrl/sh-pfc/pinctrl.c | 44 ++++++++++++++++++- drivers/pinctrl/sh-pfc/sh_pfc.h | 5 +++ 3 files changed, 50 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt index e089142cfb141..9496934528bde 100644 --- a/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt +++ b/Documentation/devicetree/bindings/pinctrl/renesas,pfc-pinctrl.txt @@ -71,7 +71,9 @@ Pin Configuration Node Properties: The pin configuration parameters use the generic pinconf bindings defined in pinctrl-bindings.txt in this directory. The supported parameters are -bias-disable, bias-pull-up and bias-pull-down. +bias-disable, bias-pull-up, bias-pull-down and power-source. For pins that +have a configurable I/O voltage, the power-source value should be the +nominal I/O voltage in millivolts. GPIO diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c index 6fe7459f0ccb8..863c3e30ce05f 100644 --- a/drivers/pinctrl/sh-pfc/pinctrl.c +++ b/drivers/pinctrl/sh-pfc/pinctrl.c @@ -491,6 +491,9 @@ static bool sh_pfc_pinconf_validate(struct sh_pfc *pfc, unsigned int _pin, case PIN_CONFIG_BIAS_PULL_DOWN: return pin->configs & SH_PFC_PIN_CFG_PULL_DOWN; + case PIN_CONFIG_POWER_SOURCE: + return pin->configs & SH_PFC_PIN_CFG_IO_VOLTAGE; + default: return false; } @@ -503,7 +506,6 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, struct sh_pfc *pfc = pmx->pfc; enum pin_config_param param = pinconf_to_config_param(*config); unsigned long flags; - unsigned int bias; if (!sh_pfc_pinconf_validate(pfc, _pin, param)) return -ENOTSUPP; @@ -511,7 +513,9 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_UP: - case PIN_CONFIG_BIAS_PULL_DOWN: + case PIN_CONFIG_BIAS_PULL_DOWN: { + unsigned int bias; + if (!pfc->info->ops || !pfc->info->ops->get_bias) return -ENOTSUPP; @@ -524,6 +528,24 @@ static int sh_pfc_pinconf_get(struct pinctrl_dev *pctldev, unsigned _pin, *config = 0; break; + } + + case PIN_CONFIG_POWER_SOURCE: { + int ret; + + if (!pfc->info->ops || !pfc->info->ops->get_io_voltage) + return -ENOTSUPP; + + spin_lock_irqsave(&pfc->lock, flags); + ret = pfc->info->ops->get_io_voltage(pfc, _pin); + spin_unlock_irqrestore(&pfc->lock, flags); + + if (ret < 0) + return ret; + + *config = ret; + break; + } default: return -ENOTSUPP; @@ -560,6 +582,24 @@ static int sh_pfc_pinconf_set(struct pinctrl_dev *pctldev, unsigned _pin, break; + case PIN_CONFIG_POWER_SOURCE: { + unsigned int arg = + pinconf_to_config_argument(configs[i]); + int ret; + + if (!pfc->info->ops || !pfc->info->ops->set_io_voltage) + return -ENOTSUPP; + + spin_lock_irqsave(&pfc->lock, flags); + ret = pfc->info->ops->set_io_voltage(pfc, _pin, arg); + spin_unlock_irqrestore(&pfc->lock, flags); + + if (ret) + return ret; + + break; + } + default: return -ENOTSUPP; } diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h index c7508d5f68861..734f7a92229c9 100644 --- a/drivers/pinctrl/sh-pfc/sh_pfc.h +++ b/drivers/pinctrl/sh-pfc/sh_pfc.h @@ -12,6 +12,7 @@ #define __SH_PFC_H #include +#include #include enum { @@ -26,6 +27,7 @@ enum { #define SH_PFC_PIN_CFG_OUTPUT (1 << 1) #define SH_PFC_PIN_CFG_PULL_UP (1 << 2) #define SH_PFC_PIN_CFG_PULL_DOWN (1 << 3) +#define SH_PFC_PIN_CFG_IO_VOLTAGE (1 << 4) #define SH_PFC_PIN_CFG_NO_GPIO (1 << 31) struct sh_pfc_pin { @@ -121,6 +123,9 @@ struct sh_pfc_soc_operations { unsigned int (*get_bias)(struct sh_pfc *pfc, unsigned int pin); void (*set_bias)(struct sh_pfc *pfc, unsigned int pin, unsigned int bias); + int (*get_io_voltage)(struct sh_pfc *pfc, unsigned int pin); + int (*set_io_voltage)(struct sh_pfc *pfc, unsigned int pin, + u16 voltage_mV); }; struct sh_pfc_soc_info { -- GitLab From 5d3c2c352998fdefdc62795249cfc7311cf36df9 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sun, 23 Aug 2015 14:24:44 +0100 Subject: [PATCH 4652/7006] arm64: Fix source code file path in comments Architecture specific code for i386 and x86_64 was unified and merged to the arch/x86. This patch fix old path of x86 architecture in a comment from the arch/arm64/include/asm/fixmap.h. Signed-off-by: Alexander Kuleshov Signed-off-by: Will Deacon --- arch/arm64/include/asm/fixmap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h index c0739187a9204..8b9884c726adc 100644 --- a/arch/arm64/include/asm/fixmap.h +++ b/arch/arm64/include/asm/fixmap.h @@ -8,7 +8,7 @@ * Copyright (C) 1998 Ingo Molnar * Copyright (C) 2013 Mark Salter * - * Adapted from arch/x86_64 version. + * Adapted from arch/x86 version. * */ -- GitLab From 8eafeb48022816513abc4f440bdad4c350fe81a3 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 18 Aug 2015 10:34:41 +0100 Subject: [PATCH 4653/7006] of/fdt: make memblock maximum physical address arch configurable When parsing the memory nodes to populate the memblock memory table, we check against high and low limits and clip any memory that exceeds either one of them. However, for arm64, the high limit of (phys_addr_t)~0 is not very meaningful, since phys_addr_t is 64 bits (i.e., no limit) but there may be other constraints that limit the memory ranges that we can support. So rename MAX_PHYS_ADDR to MAX_MEMBLOCK_ADDR (for clarity) and only define it if the arch does not supply a definition of its own. Acked-by: Rob Herring Reviewed-by: Catalin Marinas Tested-by: Stuart Yoder Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- drivers/of/fdt.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c index 07496560e5b9e..6e82bc42373ba 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c @@ -967,7 +967,9 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, } #ifdef CONFIG_HAVE_MEMBLOCK -#define MAX_PHYS_ADDR ((phys_addr_t)~0) +#ifndef MAX_MEMBLOCK_ADDR +#define MAX_MEMBLOCK_ADDR ((phys_addr_t)~0) +#endif void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) { @@ -984,16 +986,16 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) } size &= PAGE_MASK; - if (base > MAX_PHYS_ADDR) { + if (base > MAX_MEMBLOCK_ADDR) { pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", base, base + size); return; } - if (base + size - 1 > MAX_PHYS_ADDR) { + if (base + size - 1 > MAX_MEMBLOCK_ADDR) { pr_warning("Ignoring memory range 0x%llx - 0x%llx\n", - ((u64)MAX_PHYS_ADDR) + 1, base + size); - size = MAX_PHYS_ADDR - base + 1; + ((u64)MAX_MEMBLOCK_ADDR) + 1, base + size); + size = MAX_MEMBLOCK_ADDR - base + 1; } if (base + size < phys_offset) { -- GitLab From 34ba2c4247e5c4b1542b1106e156af324660c4f0 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Tue, 18 Aug 2015 10:34:42 +0100 Subject: [PATCH 4654/7006] arm64: set MAX_MEMBLOCK_ADDR according to linear region size The linear region size of a 39-bit VA kernel is only 256 GB, which may be insufficient to cover all of system RAM, even on platforms that have much less than 256 GB of memory but which is laid out very sparsely. So make sure we clip the memory we will not be able to map before installing it into the memblock memory table, by setting MAX_MEMBLOCK_ADDR accordingly. Reviewed-by: Catalin Marinas Tested-by: Stuart Yoder Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/include/asm/memory.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index f800d45ea2265..44a59c20e7735 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -113,6 +113,14 @@ extern phys_addr_t memstart_addr; /* PHYS_OFFSET - the physical address of the start of memory. */ #define PHYS_OFFSET ({ memstart_addr; }) +/* + * The maximum physical address that the linear direct mapping + * of system RAM can cover. (PAGE_OFFSET can be interpreted as + * a 2's complement signed quantity and negated to derive the + * maximum size of the linear mapping.) + */ +#define MAX_MEMBLOCK_ADDR ({ memstart_addr - PAGE_OFFSET - 1; }) + /* * PFNs are used to describe any physical page; this means * PFN 0 == physical address 0. -- GitLab From 5497159c460fadf0d8190b6ef144ec22fa26aa6b Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 29 Jul 2015 16:22:46 +0200 Subject: [PATCH 4655/7006] mmc: sdhci: switch from programmable clock mode to divided one if needed In programmable mode, if the clock frequency is too high, the divider can be too small to meet the clock frequency requirement especially to init the SD card. In this case, switch to the divided clock mode. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index c83d11080da0a..0f1a8876e3b10 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1151,6 +1151,7 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) int real_div = div, clk_mul = 1; u16 clk = 0; unsigned long timeout; + bool switch_base_clk = false; host->mmc->actual_clock = 0; @@ -1188,15 +1189,25 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) <= clock) break; } - /* - * Set Programmable Clock Mode in the Clock - * Control register. - */ - clk = SDHCI_PROG_CLOCK_MODE; - real_div = div; - clk_mul = host->clk_mul; - div--; - } else { + if ((host->max_clk * host->clk_mul / div) <= clock) { + /* + * Set Programmable Clock Mode in the Clock + * Control register. + */ + clk = SDHCI_PROG_CLOCK_MODE; + real_div = div; + clk_mul = host->clk_mul; + div--; + } else { + /* + * Divisor can be too small to reach clock + * speed requirement. Then use the base clock. + */ + switch_base_clk = true; + } + } + + if (!host->clk_mul || switch_base_clk) { /* Version 3.00 divisors must be a multiple of 2. */ if (host->max_clk <= clock) div = 1; -- GitLab From bb5f8ea4d5149f3dec6f7cd24c040c52bfc0cdbd Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 29 Jul 2015 16:22:47 +0200 Subject: [PATCH 4656/7006] mmc: sdhci-of-at91: introduce driver for the Atmel SDMMC Introduce driver for he Atmel SDMMC available on sama5d2. It is a sdhci compliant controller. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- .../devicetree/bindings/mmc/sdhci-atmel.txt | 21 ++ drivers/mmc/host/Kconfig | 8 + drivers/mmc/host/Makefile | 1 + drivers/mmc/host/sdhci-of-at91.c | 192 ++++++++++++++++++ 4 files changed, 222 insertions(+) create mode 100644 Documentation/devicetree/bindings/mmc/sdhci-atmel.txt create mode 100644 drivers/mmc/host/sdhci-of-at91.c diff --git a/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt b/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt new file mode 100644 index 0000000000000..1b662d7171a0f --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/sdhci-atmel.txt @@ -0,0 +1,21 @@ +* Atmel SDHCI controller + +This file documents the differences between the core properties in +Documentation/devicetree/bindings/mmc/mmc.txt and the properties used by the +sdhci-of-at91 driver. + +Required properties: +- compatible: Must be "atmel,sama5d2-sdhci". +- clocks: Phandlers to the clocks. +- clock-names: Must be "hclock", "multclk", "baseclk"; + + +Example: + +sdmmc0: sdio-host@a0000000 { + compatible = "atmel,sama5d2-sdhci"; + reg = <0xa0000000 0x300>; + interrupts = <31 IRQ_TYPE_LEVEL_HIGH 0>; + clocks = <&sdmmc0_hclk>, <&sdmmc0_gclk>, <&main>; + clock-names = "hclock", "multclk", "baseclk"; +}; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 6a0f9c79be265..8a1e3498261e9 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -129,6 +129,14 @@ config MMC_SDHCI_OF_ARASAN If unsure, say N. +config MMC_SDHCI_OF_AT91 + tristate "SDHCI OF support for the Atmel SDMMC controller" + depends on MMC_SDHCI_PLTFM + depends on OF + select MMC_SDHCI_IO_ACCESSORS + help + This selects the Atmel SDMMC driver + config MMC_SDHCI_OF_ESDHC tristate "SDHCI OF support for the Freescale eSDHC controller" depends on MMC_SDHCI_PLTFM diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index e928d61c5f4be..4f3452afa6ca3 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_MMC_SDHCI_ESDHC_IMX) += sdhci-esdhc-imx.o obj-$(CONFIG_MMC_SDHCI_DOVE) += sdhci-dove.o obj-$(CONFIG_MMC_SDHCI_TEGRA) += sdhci-tegra.o obj-$(CONFIG_MMC_SDHCI_OF_ARASAN) += sdhci-of-arasan.o +obj-$(CONFIG_MMC_SDHCI_OF_AT91) += sdhci-of-at91.o obj-$(CONFIG_MMC_SDHCI_OF_ESDHC) += sdhci-of-esdhc.o obj-$(CONFIG_MMC_SDHCI_OF_HLWD) += sdhci-of-hlwd.o obj-$(CONFIG_MMC_SDHCI_BCM_KONA) += sdhci-bcm-kona.o diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c new file mode 100644 index 0000000000000..7a9f4b19f9895 --- /dev/null +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -0,0 +1,192 @@ +/* + * Atmel SDMMC controller driver. + * + * Copyright (C) 2015 Atmel, + * 2015 Ludovic Desroches + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sdhci-pltfm.h" + +#define SDMMC_CACR 0x230 +#define SDMMC_CACR_CAPWREN BIT(0) +#define SDMMC_CACR_KEY (0x46 << 8) + +struct sdhci_at91_priv { + struct clk *hclock; + struct clk *gck; + struct clk *mainck; +}; + +static const struct sdhci_ops sdhci_at91_sama5d2_ops = { + .set_clock = sdhci_set_clock, + .set_bus_width = sdhci_set_bus_width, + .reset = sdhci_reset, + .set_uhs_signaling = sdhci_set_uhs_signaling, +}; + +static const struct sdhci_pltfm_data soc_data_sama5d2 = { + .ops = &sdhci_at91_sama5d2_ops, +}; + +static const struct of_device_id sdhci_at91_dt_match[] = { + { .compatible = "atmel,sama5d2-sdhci", .data = &soc_data_sama5d2 }, + {} +}; + +static int sdhci_at91_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct sdhci_pltfm_data *soc_data; + struct sdhci_host *host; + struct sdhci_pltfm_host *pltfm_host; + struct sdhci_at91_priv *priv; + unsigned int caps0, caps1; + unsigned int clk_base, clk_mul; + unsigned int gck_rate, real_gck_rate; + int ret; + + match = of_match_device(sdhci_at91_dt_match, &pdev->dev); + if (!match) + return -EINVAL; + soc_data = match->data; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(&pdev->dev, "unable to allocate private data\n"); + return -ENOMEM; + } + + priv->mainck = devm_clk_get(&pdev->dev, "baseclk"); + if (IS_ERR(priv->mainck)) { + dev_err(&pdev->dev, "failed to get baseclk\n"); + return PTR_ERR(priv->mainck); + } + + priv->hclock = devm_clk_get(&pdev->dev, "hclock"); + if (IS_ERR(priv->hclock)) { + dev_err(&pdev->dev, "failed to get hclock\n"); + return PTR_ERR(priv->hclock); + } + + priv->gck = devm_clk_get(&pdev->dev, "multclk"); + if (IS_ERR(priv->gck)) { + dev_err(&pdev->dev, "failed to get multclk\n"); + return PTR_ERR(priv->gck); + } + + host = sdhci_pltfm_init(pdev, soc_data, 0); + if (IS_ERR(host)) + return PTR_ERR(host); + + /* + * The mult clock is provided by as a generated clock by the PMC + * controller. In order to set the rate of gck, we have to get the + * base clock rate and the clock mult from capabilities. + */ + clk_prepare_enable(priv->hclock); + caps0 = readl(host->ioaddr + SDHCI_CAPABILITIES); + caps1 = readl(host->ioaddr + SDHCI_CAPABILITIES_1); + clk_base = (caps0 & SDHCI_CLOCK_V3_BASE_MASK) >> SDHCI_CLOCK_BASE_SHIFT; + clk_mul = (caps1 & SDHCI_CLOCK_MUL_MASK) >> SDHCI_CLOCK_MUL_SHIFT; + gck_rate = clk_base * 1000000 * (clk_mul + 1); + ret = clk_set_rate(priv->gck, gck_rate); + if (ret < 0) { + dev_err(&pdev->dev, "failed to set gck"); + goto hclock_disable_unprepare; + return -EINVAL; + } + /* + * We need to check if we have the requested rate for gck because in + * some cases this rate could be not supported. If it happens, the rate + * is the closest one gck can provide. We have to update the value + * of clk mul. + */ + real_gck_rate = clk_get_rate(priv->gck); + if (real_gck_rate != gck_rate) { + clk_mul = real_gck_rate / (clk_base * 1000000) - 1; + caps1 &= (~SDHCI_CLOCK_MUL_MASK); + caps1 |= ((clk_mul << SDHCI_CLOCK_MUL_SHIFT) & SDHCI_CLOCK_MUL_MASK); + /* Set capabilities in r/w mode. */ + writel(SDMMC_CACR_KEY | SDMMC_CACR_CAPWREN, host->ioaddr + SDMMC_CACR); + writel(caps1, host->ioaddr + SDHCI_CAPABILITIES_1); + /* Set capabilities in ro mode. */ + writel(0, host->ioaddr + SDMMC_CACR); + dev_info(&pdev->dev, "update clk mul to %u as gck rate is %u Hz\n", + clk_mul, real_gck_rate); + } + + clk_prepare_enable(priv->mainck); + clk_prepare_enable(priv->gck); + + pltfm_host = sdhci_priv(host); + pltfm_host->priv = priv; + + ret = mmc_of_parse(host->mmc); + if (ret) + goto clocks_disable_unprepare; + + sdhci_get_of_property(pdev); + + ret = sdhci_add_host(host); + if (ret) + goto clocks_disable_unprepare; + + return 0; + +clocks_disable_unprepare: + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->mainck); +hclock_disable_unprepare: + clk_disable_unprepare(priv->hclock); + sdhci_pltfm_free(pdev); + return ret; +} + +static int sdhci_at91_remove(struct platform_device *pdev) +{ + struct sdhci_host *host = platform_get_drvdata(pdev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_at91_priv *priv = pltfm_host->priv; + + sdhci_pltfm_unregister(pdev); + + clk_disable_unprepare(priv->gck); + clk_disable_unprepare(priv->hclock); + clk_disable_unprepare(priv->mainck); + + return 0; +} + +static struct platform_driver sdhci_at91_driver = { + .driver = { + .name = "sdhci-at91", + .owner = THIS_MODULE, + .of_match_table = sdhci_at91_dt_match, + .pm = SDHCI_PLTFM_PMOPS, + }, + .probe = sdhci_at91_probe, + .remove = sdhci_at91_remove, +}; + +module_platform_driver(sdhci_at91_driver); + +MODULE_DESCRIPTION("SDHCI driver for at91"); +MODULE_AUTHOR("Ludovic Desroches "); +MODULE_LICENSE("GPL v2"); -- GitLab From 05c441efcc9796dd27451b9d87f5b22b8ebcdb2b Mon Sep 17 00:00:00 2001 From: "ludovic.desroches@atmel.com" Date: Wed, 29 Jul 2015 16:22:48 +0200 Subject: [PATCH 4657/7006] MAINTAINERS: add entry for Atmel sdhci-of-at91 driver Add an entry for Atmel SDMMC device. Signed-off-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- MAINTAINERS | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 569568f6644f2..a9638eb1e4d3a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1882,6 +1882,12 @@ L: linux-mtd@lists.infradead.org S: Supported F: drivers/mtd/nand/atmel_nand* +ATMEL SDMMC DRIVER +M: Ludovic Desroches +L: linux-mmc@vger.kernel.org +S: Supported +F: drivers/mmc/host/sdhci-of-at91.c + ATMEL SPI DRIVER M: Nicolas Ferre S: Supported -- GitLab From 0df9d2eae5e1092b07eaab6b989c2ff14115cab5 Mon Sep 17 00:00:00 2001 From: Takeshi Kihara Date: Mon, 20 Jul 2015 01:39:59 +0900 Subject: [PATCH 4658/7006] mmc: tmio: Fix timeout value for command request Fix the problem which timeout occurs at the time of command request with several cards. The timeout value was insufficient as a verification of several cards, so it was changed 5 seconds from 2 seconds. Signed-off-by: Takeshi Kihara Signed-off-by: Yoshihiro Kaneko Signed-off-by: Ulf Hansson --- drivers/mmc/host/tmio_mmc_pio.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c index e3dcf31a8bd6a..a10fde40b6c3d 100644 --- a/drivers/mmc/host/tmio_mmc_pio.c +++ b/drivers/mmc/host/tmio_mmc_pio.c @@ -83,6 +83,8 @@ static int tmio_mmc_next_sg(struct tmio_mmc_host *host) return --host->sg_len; } +#define CMDREQ_TIMEOUT 5000 + #ifdef CONFIG_MMC_DEBUG #define STATUS_TO_TEXT(a, status, i) \ @@ -230,7 +232,7 @@ static void tmio_mmc_reset_work(struct work_struct *work) */ if (IS_ERR_OR_NULL(mrq) || time_is_after_jiffies(host->last_req_ts + - msecs_to_jiffies(2000))) { + msecs_to_jiffies(CMDREQ_TIMEOUT))) { spin_unlock_irqrestore(&host->lock, flags); return; } @@ -818,7 +820,7 @@ static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) ret = tmio_mmc_start_command(host, mrq->cmd); if (!ret) { schedule_delayed_work(&host->delayed_reset_work, - msecs_to_jiffies(2000)); + msecs_to_jiffies(CMDREQ_TIMEOUT)); return; } -- GitLab From c9b57724b38d4c1555ee49418be3d76801e3327c Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 21 Aug 2015 10:18:08 -0400 Subject: [PATCH 4659/7006] HID: quirks: add QUIRK_NOGET for an other TPV touchscreen Looks like 0x8882 needs the same quirk than 0x8883. Given that both devices claim they are "TPV OpticalTouchScreen" rename the 0x8883 to add its PID in the #define. Reported-by: Blaine Lee Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 ++- drivers/hid/usbhid/hid-quirks.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b04b0820d8163..0de3284a3e248 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -922,7 +922,8 @@ #define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 #define USB_VENDOR_ID_TPV 0x25aa -#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN 0x8883 +#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882 0x8882 +#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883 0x8883 #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 53e7de7cb9e25..a983418114bb9 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -114,7 +114,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_1, HID_QUIRK_NOGET }, { USB_VENDOR_ID_SYMBOL, USB_DEVICE_ID_SYMBOL_SCANNER_2, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883, HID_QUIRK_NOGET }, { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT }, -- GitLab From f5005f7835e0da9ea6f203f8acc356bef9b331da Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 May 2015 17:40:55 +0200 Subject: [PATCH 4660/7006] dt-bindings: add header for generic I2C flags in bindings Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- include/dt-bindings/i2c/i2c.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 include/dt-bindings/i2c/i2c.h diff --git a/include/dt-bindings/i2c/i2c.h b/include/dt-bindings/i2c/i2c.h new file mode 100644 index 0000000000000..1d5da81d90f14 --- /dev/null +++ b/include/dt-bindings/i2c/i2c.h @@ -0,0 +1,18 @@ +/* + * This header provides constants for I2C bindings + * + * Copyright (C) 2015 by Sang Engineering + * Copyright (C) 2015 by Renesas Electronics Corporation + * + * Wolfram Sang + * + * GPLv2 only + */ + +#ifndef _DT_BINDINGS_I2C_I2C_H +#define _DT_BINDINGS_I2C_I2C_H + +#define I2C_TEN_BIT_ADDRESS (1 << 31) +#define I2C_OWN_SLAVE_ADDRESS (1 << 30) + +#endif -- GitLab From c5ebb387f4e6b2dd7c74d71caf7b696834d0c887 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 May 2015 17:44:31 +0200 Subject: [PATCH 4661/7006] i2c: add a flag to mark clients as slaves And update indentation with one more tab, sigh... Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- include/linux/i2c.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/linux/i2c.h b/include/linux/i2c.h index e2c859b74f8b7..5aea071372185 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -550,11 +550,12 @@ void i2c_lock_adapter(struct i2c_adapter *); void i2c_unlock_adapter(struct i2c_adapter *); /*flags for the client struct: */ -#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ -#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ +#define I2C_CLIENT_PEC 0x04 /* Use Packet Error Checking */ +#define I2C_CLIENT_TEN 0x10 /* we have a ten bit chip address */ /* Must equal I2C_M_TEN below */ -#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */ -#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */ +#define I2C_CLIENT_SLAVE 0x20 /* we are the slave */ +#define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */ +#define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */ /* Must match I2C_M_STOP|IGNORE_NAK */ /* i2c adapter classes (bitmask) */ -- GitLab From da899f55b359225f85e154765baaddb13ec436ca Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 18 May 2015 21:09:12 +0200 Subject: [PATCH 4662/7006] i2c: apply address offset for slaves, too We want a separate address range for being an I2C slave. Add an offset of 0x1000, so it can be combined with ten bit addresses as well. Add a separate function to create the address value, we will need it later in other places. Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 07a83f34ed58e..47dbe25147414 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -57,6 +57,9 @@ #define CREATE_TRACE_POINTS #include +#define I2C_ADDR_OFFSET_TEN_BIT 0xa000 +#define I2C_ADDR_OFFSET_SLAVE 0x1000 + /* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter calls are serialized */ @@ -778,6 +781,21 @@ struct i2c_client *i2c_verify_client(struct device *dev) EXPORT_SYMBOL(i2c_verify_client); +/* Return a unique address which takes the flags of the client into account */ +static unsigned short i2c_encode_flags_to_addr(struct i2c_client *client) +{ + unsigned short addr = client->addr; + + /* For some client flags, add an arbitrary offset to avoid collisions */ + if (client->flags & I2C_CLIENT_TEN) + addr |= I2C_ADDR_OFFSET_TEN_BIT; + + if (client->flags & I2C_CLIENT_SLAVE) + addr |= I2C_ADDR_OFFSET_SLAVE; + + return addr; +} + /* This is a permissive address validity check, I2C address map constraints * are purposely not enforced, except for the general call address. */ static int i2c_check_client_addr_validity(const struct i2c_client *client) @@ -923,10 +941,8 @@ static void i2c_dev_set_name(struct i2c_adapter *adap, return; } - /* For 10-bit clients, add an arbitrary offset to avoid collisions */ dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), - client->addr | ((client->flags & I2C_CLIENT_TEN) - ? 0xa000 : 0)); + i2c_encode_flags_to_addr(client)); } /** -- GitLab From 66be6056eba80690bb7fa3d983c21494e1950bea Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jul 2015 12:43:22 +0200 Subject: [PATCH 4663/7006] i2c: rename address check functions The current naming is based on the arguments of the functions and not on what they do. Even I as the maintainer find this confusing, so let's rename them to something more descriptive. Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 47dbe25147414..fced494040a8b 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -798,7 +798,7 @@ static unsigned short i2c_encode_flags_to_addr(struct i2c_client *client) /* This is a permissive address validity check, I2C address map constraints * are purposely not enforced, except for the general call address. */ -static int i2c_check_client_addr_validity(const struct i2c_client *client) +static int i2c_check_addr_validity(const struct i2c_client *client) { if (client->flags & I2C_CLIENT_TEN) { /* 10-bit address, all values are valid */ @@ -816,7 +816,7 @@ static int i2c_check_client_addr_validity(const struct i2c_client *client) * device uses a reserved address, then it shouldn't be probed. 7-bit * addressing is assumed, 10-bit address devices are rare and should be * explicitly enumerated. */ -static int i2c_check_addr_validity(unsigned short addr) +static int i2c_check_7bit_addr_validity_strict(unsigned short addr) { /* * Reserved addresses per I2C specification: @@ -985,7 +985,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); /* Check for address validity */ - status = i2c_check_client_addr_validity(client); + status = i2c_check_addr_validity(client); if (status) { dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); @@ -2296,7 +2296,7 @@ static int i2c_detect_address(struct i2c_client *temp_client, int err; /* Make sure the address is valid */ - err = i2c_check_addr_validity(addr); + err = i2c_check_7bit_addr_validity_strict(addr); if (err) { dev_warn(&adapter->dev, "Invalid probe address 0x%02x\n", addr); @@ -2413,7 +2413,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ - if (i2c_check_addr_validity(addr_list[i]) < 0) { + if (i2c_check_7bit_addr_validity_strict(addr_list[i]) < 0) { dev_warn(&adap->dev, "Invalid 7-bit address " "0x%02x\n", addr_list[i]); continue; @@ -2997,7 +2997,7 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) if (!(client->flags & I2C_CLIENT_TEN)) { /* Enforce stricter address checking */ - ret = i2c_check_addr_validity(client->addr); + ret = i2c_check_7bit_addr_validity_strict(client->addr); if (ret) { dev_err(&client->dev, "%s: invalid address\n", __func__); return ret; -- GitLab From c4019b7040eaf88f440ce5212e055a4f19b1b541 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jul 2015 12:50:06 +0200 Subject: [PATCH 4664/7006] i2c: make address check indpendent from client struct We want to use this function with struct boardinfo soon, so let's just pass the parameters really needed. We also extend the type of addr, so more types can be input. Remove a superfluous dangling comment while here. Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index fced494040a8b..4ffe06451081e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -798,15 +798,15 @@ static unsigned short i2c_encode_flags_to_addr(struct i2c_client *client) /* This is a permissive address validity check, I2C address map constraints * are purposely not enforced, except for the general call address. */ -static int i2c_check_addr_validity(const struct i2c_client *client) +static int i2c_check_addr_validity(unsigned addr, unsigned short flags) { - if (client->flags & I2C_CLIENT_TEN) { + if (flags & I2C_CLIENT_TEN) { /* 10-bit address, all values are valid */ - if (client->addr > 0x3ff) + if (addr > 0x3ff) return -EINVAL; } else { /* 7-bit address, reject the general call address */ - if (client->addr == 0x00 || client->addr > 0x7f) + if (addr == 0x00 || addr > 0x7f) return -EINVAL; } return 0; @@ -984,8 +984,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) strlcpy(client->name, info->type, sizeof(client->name)); - /* Check for address validity */ - status = i2c_check_addr_validity(client); + status = i2c_check_addr_validity(client->addr, client->flags); if (status) { dev_err(&adap->dev, "Invalid %d-bit I2C address 0x%02hx\n", client->flags & I2C_CLIENT_TEN ? 10 : 7, client->addr); -- GitLab From b4e2f6ac1281cd3e066919cc762eef4924e9fcc5 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 19 May 2015 21:04:40 +0200 Subject: [PATCH 4665/7006] i2c: apply DT flags when probing Check for slave and 10-bit flags when probing and mark the client when found. Improve the address validity check, too Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 4ffe06451081e..7b18f31bf6c63 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,6 +27,7 @@ I2C slave support (c) 2014 by Wolfram Sang */ +#include #include #include #include @@ -1288,7 +1289,8 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, struct i2c_client *result; struct i2c_board_info info = {}; struct dev_archdata dev_ad = {}; - const __be32 *addr; + const __be32 *addr_be; + u32 addr; int len; dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name); @@ -1299,20 +1301,31 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, return ERR_PTR(-EINVAL); } - addr = of_get_property(node, "reg", &len); - if (!addr || (len < sizeof(*addr))) { + addr_be = of_get_property(node, "reg", &len); + if (!addr_be || (len < sizeof(*addr_be))) { dev_err(&adap->dev, "of_i2c: invalid reg on %s\n", node->full_name); return ERR_PTR(-EINVAL); } - info.addr = be32_to_cpup(addr); - if (info.addr > (1 << 10) - 1) { + addr = be32_to_cpup(addr_be); + if (addr & I2C_TEN_BIT_ADDRESS) { + addr &= ~I2C_TEN_BIT_ADDRESS; + info.flags |= I2C_CLIENT_TEN; + } + + if (addr & I2C_OWN_SLAVE_ADDRESS) { + addr &= ~I2C_OWN_SLAVE_ADDRESS; + info.flags |= I2C_CLIENT_SLAVE; + } + + if (i2c_check_addr_validity(addr, info.flags)) { dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n", info.addr, node->full_name); return ERR_PTR(-EINVAL); } + info.addr = addr; info.of_node = of_node_get(node); info.archdata = &dev_ad; -- GitLab From 9bccc70a127cfe2a13e34d6b6e7300caae113f8f Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 17 Jul 2015 14:48:56 +0200 Subject: [PATCH 4666/7006] i2c: take address space into account when checking for used addresses It is not enough to compare the plain address value, we also need to check the flags enabling a different address space. E.g. it is valid to have address 0x50 as a 7-bit address and 0x050 as 10-bit address on the same bus. Same for addresses when we are the slave. Tested-by: Andrey Danin Acked-by: Stephen Warren Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 7b18f31bf6c63..fc6d89316144c 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -839,7 +839,7 @@ static int __i2c_check_addr_busy(struct device *dev, void *addrp) struct i2c_client *client = i2c_verify_client(dev); int addr = *(int *)addrp; - if (client && client->addr == addr) + if (client && i2c_encode_flags_to_addr(client) == addr) return -EBUSY; return 0; } @@ -993,7 +993,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) } /* Check for address business */ - status = i2c_check_addr_busy(adap, client->addr); + status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client)); if (status) goto out_err; @@ -2315,7 +2315,7 @@ static int i2c_detect_address(struct i2c_client *temp_client, return err; } - /* Skip if already in use */ + /* Skip if already in use (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adapter, addr)) return 0; @@ -2431,7 +2431,7 @@ i2c_new_probed_device(struct i2c_adapter *adap, continue; } - /* Check address availability */ + /* Check address availability (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adap, addr_list[i])) { dev_dbg(&adap->dev, "Address 0x%02x already in " "use, not probing\n", addr_list[i]); -- GitLab From cfa0327b0d03091e0c47249c080e50e287be762d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Mon, 27 Jul 2015 14:03:38 +0200 Subject: [PATCH 4667/7006] i2c: support 10 bit and slave addresses in sysfs 'new_device' We now have seperate address spaces for 10 bit and we-are-slave clients. Update the sysfs device instantiation method to support these types by accepting the address offsets that are assigned to the extra address spaces. Update the documentation, too. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- Documentation/i2c/slave-interface | 9 ++++++--- Documentation/i2c/ten-bit-addresses | 4 ++++ drivers/i2c/i2c-core.c | 12 +++++++++++- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/Documentation/i2c/slave-interface b/Documentation/i2c/slave-interface index 2dee4e2d62df1..61ed05cd95317 100644 --- a/Documentation/i2c/slave-interface +++ b/Documentation/i2c/slave-interface @@ -31,10 +31,13 @@ User manual =========== I2C slave backends behave like standard I2C clients. So, you can instantiate -them as described in the document 'instantiating-devices'. A quick example for -instantiating the slave-eeprom driver from userspace at address 0x64 on bus 1: +them as described in the document 'instantiating-devices'. The only difference +is that i2c slave backends have their own address space. So, you have to add +0x1000 to the address you would originally request. An example for +instantiating the slave-eeprom driver from userspace at the 7 bit address 0x64 +on bus 1: - # echo slave-24c02 0x64 > /sys/bus/i2c/devices/i2c-1/new_device + # echo slave-24c02 0x1064 > /sys/bus/i2c/devices/i2c-1/new_device Each backend should come with separate documentation to describe its specific behaviour and setup. diff --git a/Documentation/i2c/ten-bit-addresses b/Documentation/i2c/ten-bit-addresses index cdfe13901b99c..7b2d11e53a49f 100644 --- a/Documentation/i2c/ten-bit-addresses +++ b/Documentation/i2c/ten-bit-addresses @@ -2,6 +2,10 @@ The I2C protocol knows about two kinds of device addresses: normal 7 bit addresses, and an extended set of 10 bit addresses. The sets of addresses do not intersect: the 7 bit address 0x10 is not the same as the 10 bit address 0x10 (though a single device could respond to both of them). +To avoid ambiguity, the user sees 10 bit addresses mapped to a different +address space, namely 0xa000-0xa3ff. The leading 0xa (= 10) represents the +10 bit mode. This is used for creating device names in sysfs. It is also +needed when instantiating 10 bit devices via the new_device file in sysfs. I2C messages to and from 10-bit address devices have a different format. See the I2C specification for the details. diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index fc6d89316144c..039817eaecb58 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1158,6 +1158,16 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr, return -EINVAL; } + if ((info.addr & I2C_ADDR_OFFSET_TEN_BIT) == I2C_ADDR_OFFSET_TEN_BIT) { + info.addr &= ~I2C_ADDR_OFFSET_TEN_BIT; + info.flags |= I2C_CLIENT_TEN; + } + + if (info.addr & I2C_ADDR_OFFSET_SLAVE) { + info.addr &= ~I2C_ADDR_OFFSET_SLAVE; + info.flags |= I2C_CLIENT_SLAVE; + } + client = i2c_new_device(adap, &info); if (!client) return -EINVAL; @@ -1209,7 +1219,7 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr, i2c_adapter_depth(adap)); list_for_each_entry_safe(client, next, &adap->userspace_clients, detected) { - if (client->addr == addr) { + if (i2c_encode_flags_to_addr(client) == addr) { dev_info(dev, "%s: Deleting device %s at 0x%02hx\n", "delete_device", client->name, client->addr); -- GitLab From c6909d6f6f1082b8bb4c1b0ef3460a005c9dcb4d Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Wed, 5 Aug 2015 21:12:54 +0200 Subject: [PATCH 4668/7006] i2c: slave: print warning if slave flag not set Address collisions will be rare, but we should let the user know that slaves have their own address space nonetheless. Signed-off-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 039817eaecb58..a6780289c61d2 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -3017,6 +3017,10 @@ int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) return -EINVAL; } + if (!(client->flags & I2C_CLIENT_SLAVE)) + dev_warn(&client->dev, "%s: client slave flag not set. You might see address collisions\n", + __func__); + if (!(client->flags & I2C_CLIENT_TEN)) { /* Enforce stricter address checking */ ret = i2c_check_7bit_addr_validity_strict(client->addr); -- GitLab From 7a59b00a0906945f7fe25a10332ac0820491a0c3 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Sat, 8 Aug 2015 13:35:18 +0200 Subject: [PATCH 4669/7006] i2c: dt: describe generic bindings Start a new file which describes the generic bindings used for I2C with device tree. So we have a central place to look for them, increase visibility of them, and hopefully reduce the amount of custom properties introduced. Signed-off-by: Wolfram Sang Reviewed-by: Vaibhav Hiremath Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c.txt | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt new file mode 100644 index 0000000000000..1175efed4a41b --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -0,0 +1,33 @@ +Generic device tree bindings for I2C busses +=========================================== + +This document describes generic bindings which can be used to describe I2C +busses in a device tree. + +Required properties +------------------- + +- #address-cells - should be <1>. Read more about addresses below. +- #size-cells - should be <0>. +- compatible - name of I2C bus controller following generic names + recommended practice. + +For other required properties e.g. to describe register sets, interrupts, +clocks, etc. check the binding documentation of the specific driver. + +The cells properties above define that an address of children of an I2C bus +are described by a single value. This is usually a 7 bit address. However, +flags can be attached to the address. I2C_TEN_BIT_ADDRESS is used to mark a 10 +bit address. It is needed to avoid the ambiguity between e.g. a 7 bit address +of 0x50 and a 10 bit address of 0x050 which, in theory, can be on the same bus. +Another flag is I2C_OWN_SLAVE_ADDRESS to mark addresses on which we listen to +be devices ourselves. + +Optional properties +------------------- + +These properties may not be supported by all drivers. However, if a driver +wants to support one of the below features, it should adapt the bindings below. + +- clock-frequency - frequency of bus clock in Hz +- wakeup-source - device can be used as a wakeup source. -- GitLab From b3fdd32799d834e2626fae087906e886037350c6 Mon Sep 17 00:00:00 2001 From: York Sun Date: Mon, 17 Aug 2015 11:53:48 -0700 Subject: [PATCH 4670/7006] i2c: mux: Add register-based mux i2c-mux-reg Based on i2c-mux-gpio driver, similarly the register-based mux switch from one bus to another by setting a single register. The register can be on PCIe bus, local bus, or any memory-mapped address. The endianness of such register can be specified in device tree if used, or in platform data. Signed-off-by: York Sun Acked-by: Alexander Sverdlin Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-mux-reg.txt | 74 +++++ drivers/i2c/muxes/Kconfig | 11 + drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/i2c-mux-reg.c | 294 ++++++++++++++++++ include/linux/platform_data/i2c-mux-reg.h | 44 +++ 5 files changed, 424 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-reg.txt create mode 100644 drivers/i2c/muxes/i2c-mux-reg.c create mode 100644 include/linux/platform_data/i2c-mux-reg.h diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-reg.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-reg.txt new file mode 100644 index 0000000000000..688783fbe696b --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-reg.txt @@ -0,0 +1,74 @@ +Register-based I2C Bus Mux + +This binding describes an I2C bus multiplexer that uses a single register +to route the I2C signals. + +Required properties: +- compatible: i2c-mux-reg +- i2c-parent: The phandle of the I2C bus that this multiplexer's master-side + port is connected to. +* Standard I2C mux properties. See mux.txt in this directory. +* I2C child bus nodes. See mux.txt in this directory. + +Optional properties: +- reg: this pair of specifies the register to control the mux. + The depends on its parent node. It can be any memory-mapped + address. The size must be either 1, 2, or 4 bytes. If reg is omitted, the + resource of this device will be used. +- little-endian: The existence indicates the register is in little endian. +- big-endian: The existence indicates the register is in big endian. + If both little-endian and big-endian are omitted, the endianness of the + CPU will be used. +- write-only: The existence indicates the register is write-only. +- idle-state: value to set the muxer to when idle. When no value is + given, it defaults to the last value used. + +Whenever an access is made to a device on a child bus, the value set +in the revelant node's reg property will be output to the register. + +If an idle state is defined, using the idle-state (optional) property, +whenever an access is not being made to a device on a child bus, the +register will be set according to the idle value. + +If an idle state is not defined, the most recently used value will be +left programmed into the register. + +Example of a mux on PCIe card, the host is a powerpc SoC (big endian): + + i2c-mux { + /* the depends on the address translation + * of the parent device. If omitted, device resource + * will be used instead. The size is to determine + * whether iowrite32, iowrite16, or iowrite8 will be used. + */ + reg = <0x6028 0x4>; + little-endian; /* little endian register on PCIe */ + compatible = "i2c-mux-reg"; + #address-cells = <1>; + #size-cells = <0>; + i2c-parent = <&i2c1>; + i2c@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <0>; + + si5338: clock-generator@70 { + compatible = "silabs,si5338"; + reg = <0x70>; + /* other stuff */ + }; + }; + + i2c@1 { + /* data is written using iowrite32 */ + reg = <1>; + #address-cells = <1>; + #size-cells = <0>; + + si5338: clock-generator@70 { + compatible = "silabs,si5338"; + reg = <0x70>; + /* other stuff */ + }; + }; + }; diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index fdd0769c84a31..f06b0e24673b8 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -61,4 +61,15 @@ config I2C_MUX_PINCTRL This driver can also be built as a module. If so, the module will be called pinctrl-i2cmux. +config I2C_MUX_REG + tristate "Register-based I2C multiplexer" + help + If you say yes to this option, support will be included for a + register based I2C multiplexer. This driver provides access to + I2C busses connected through a MUX, which is controlled + by a single register. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-reg. + endmenu diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 465778b5d5dc8..e89799b76a928 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -7,5 +7,6 @@ obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o +obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c new file mode 100644 index 0000000000000..86d41d36a7834 --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -0,0 +1,294 @@ +/* + * I2C multiplexer using a single register + * + * Copyright 2015 Freescale Semiconductor + * York Sun + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +struct regmux { + struct i2c_adapter *parent; + struct i2c_adapter **adap; /* child busses */ + struct i2c_mux_reg_platform_data data; +}; + +static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id) +{ + if (!mux->data.reg) + return -EINVAL; + + switch (mux->data.reg_size) { + case 4: + if (mux->data.little_endian) { + iowrite32(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread32(mux->data.reg); + } else { + iowrite32be(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread32(mux->data.reg); + } + break; + case 2: + if (mux->data.little_endian) { + iowrite16(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread16(mux->data.reg); + } else { + iowrite16be(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread16be(mux->data.reg); + } + break; + case 1: + iowrite8(chan_id, mux->data.reg); + if (!mux->data.write_only) + ioread8(mux->data.reg); + break; + default: + pr_err("Invalid register size\n"); + return -EINVAL; + } + + return 0; +} + +static int i2c_mux_reg_select(struct i2c_adapter *adap, void *data, + unsigned int chan) +{ + struct regmux *mux = data; + + return i2c_mux_reg_set(mux, chan); +} + +static int i2c_mux_reg_deselect(struct i2c_adapter *adap, void *data, + unsigned int chan) +{ + struct regmux *mux = data; + + if (mux->data.idle_in_use) + return i2c_mux_reg_set(mux, mux->data.idle); + + return 0; +} + +#ifdef CONFIG_OF +static int i2c_mux_reg_probe_dt(struct regmux *mux, + struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *adapter_np, *child; + struct i2c_adapter *adapter; + struct resource res; + unsigned *values; + int i = 0; + + if (!np) + return -ENODEV; + + adapter_np = of_parse_phandle(np, "i2c-parent", 0); + if (!adapter_np) { + dev_err(&pdev->dev, "Cannot parse i2c-parent\n"); + return -ENODEV; + } + adapter = of_find_i2c_adapter_by_node(adapter_np); + if (!adapter) + return -EPROBE_DEFER; + + mux->parent = adapter; + mux->data.parent = i2c_adapter_id(adapter); + put_device(&adapter->dev); + + mux->data.n_values = of_get_child_count(np); + if (of_find_property(np, "little-endian", NULL)) { + mux->data.little_endian = true; + } else if (of_find_property(np, "big-endian", NULL)) { + mux->data.little_endian = false; + } else { +#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : \ + defined(__LITTLE_ENDIAN) + mux->data.little_endian = true; +#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : \ + defined(__BIG_ENDIAN) + mux->data.little_endian = false; +#else +#error Endianness not defined? +#endif + } + if (of_find_property(np, "write-only", NULL)) + mux->data.write_only = true; + else + mux->data.write_only = false; + + values = devm_kzalloc(&pdev->dev, + sizeof(*mux->data.values) * mux->data.n_values, + GFP_KERNEL); + if (!values) { + dev_err(&pdev->dev, "Cannot allocate values array"); + return -ENOMEM; + } + + for_each_child_of_node(np, child) { + of_property_read_u32(child, "reg", values + i); + i++; + } + mux->data.values = values; + + if (!of_property_read_u32(np, "idle-state", &mux->data.idle)) + mux->data.idle_in_use = true; + + /* map address from "reg" if exists */ + if (of_address_to_resource(np, 0, &res)) { + mux->data.reg_size = resource_size(&res); + if (mux->data.reg_size > 4) { + dev_err(&pdev->dev, "Invalid address size\n"); + return -EINVAL; + } + mux->data.reg = devm_ioremap_resource(&pdev->dev, &res); + if (IS_ERR(mux->data.reg)) + return PTR_ERR(mux->data.reg); + } + + return 0; +} +#else +static int i2c_mux_reg_probe_dt(struct gpiomux *mux, + struct platform_device *pdev) +{ + return 0; +} +#endif + +static int i2c_mux_reg_probe(struct platform_device *pdev) +{ + struct regmux *mux; + struct i2c_adapter *parent; + struct resource *res; + int (*deselect)(struct i2c_adapter *, void *, u32); + unsigned int class; + int i, ret, nr; + + mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); + if (!mux) + return -ENOMEM; + + platform_set_drvdata(pdev, mux); + + if (dev_get_platdata(&pdev->dev)) { + memcpy(&mux->data, dev_get_platdata(&pdev->dev), + sizeof(mux->data)); + + parent = i2c_get_adapter(mux->data.parent); + if (!parent) + return -EPROBE_DEFER; + + mux->parent = parent; + } else { + ret = i2c_mux_reg_probe_dt(mux, pdev); + if (ret < 0) { + dev_err(&pdev->dev, "Error parsing device tree"); + return ret; + } + } + + if (!mux->data.reg) { + dev_info(&pdev->dev, + "Register not set, using platform resource\n"); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mux->data.reg_size = resource_size(res); + if (mux->data.reg_size > 4) { + dev_err(&pdev->dev, "Invalid resource size\n"); + return -EINVAL; + } + mux->data.reg = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mux->data.reg)) + return PTR_ERR(mux->data.reg); + } + + mux->adap = devm_kzalloc(&pdev->dev, + sizeof(*mux->adap) * mux->data.n_values, + GFP_KERNEL); + if (!mux->adap) { + dev_err(&pdev->dev, "Cannot allocate i2c_adapter structure"); + return -ENOMEM; + } + + if (mux->data.idle_in_use) + deselect = i2c_mux_reg_deselect; + else + deselect = NULL; + + for (i = 0; i < mux->data.n_values; i++) { + nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; + class = mux->data.classes ? mux->data.classes[i] : 0; + + mux->adap[i] = i2c_add_mux_adapter(mux->parent, &pdev->dev, mux, + nr, mux->data.values[i], + class, i2c_mux_reg_select, + deselect); + if (!mux->adap[i]) { + ret = -ENODEV; + dev_err(&pdev->dev, "Failed to add adapter %d\n", i); + goto add_adapter_failed; + } + } + + dev_dbg(&pdev->dev, "%d port mux on %s adapter\n", + mux->data.n_values, mux->parent->name); + + return 0; + +add_adapter_failed: + for (; i > 0; i--) + i2c_del_mux_adapter(mux->adap[i - 1]); + + return ret; +} + +static int i2c_mux_reg_remove(struct platform_device *pdev) +{ + struct regmux *mux = platform_get_drvdata(pdev); + int i; + + for (i = 0; i < mux->data.n_values; i++) + i2c_del_mux_adapter(mux->adap[i]); + + i2c_put_adapter(mux->parent); + + return 0; +} + +static const struct of_device_id i2c_mux_reg_of_match[] = { + { .compatible = "i2c-mux-reg", }, + {}, +}; +MODULE_DEVICE_TABLE(of, i2c_mux_reg_of_match); + +static struct platform_driver i2c_mux_reg_driver = { + .probe = i2c_mux_reg_probe, + .remove = i2c_mux_reg_remove, + .driver = { + .name = "i2c-mux-reg", + }, +}; + +module_platform_driver(i2c_mux_reg_driver); + +MODULE_DESCRIPTION("Register-based I2C multiplexer driver"); +MODULE_AUTHOR("York Sun "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:i2c-mux-reg"); diff --git a/include/linux/platform_data/i2c-mux-reg.h b/include/linux/platform_data/i2c-mux-reg.h new file mode 100644 index 0000000000000..c68712aadf43c --- /dev/null +++ b/include/linux/platform_data/i2c-mux-reg.h @@ -0,0 +1,44 @@ +/* + * I2C multiplexer using a single register + * + * Copyright 2015 Freescale Semiconductor + * York Sun + * + * 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_PLATFORM_DATA_I2C_MUX_REG_H +#define __LINUX_PLATFORM_DATA_I2C_MUX_REG_H + +/** + * struct i2c_mux_reg_platform_data - Platform-dependent data for i2c-mux-reg + * @parent: Parent I2C bus adapter number + * @base_nr: Base I2C bus number to number adapters from or zero for dynamic + * @values: Array of value for each channel + * @n_values: Number of multiplexer channels + * @little_endian: Indicating if the register is in little endian + * @write_only: Reading the register is not allowed by hardware + * @classes: Optional I2C auto-detection classes + * @idle: Value to write to mux when idle + * @idle_in_use: indicate if idle value is in use + * @reg: Virtual address of the register to switch channel + * @reg_size: register size in bytes + */ +struct i2c_mux_reg_platform_data { + int parent; + int base_nr; + const unsigned int *values; + int n_values; + bool little_endian; + bool write_only; + const unsigned int *classes; + u32 idle; + bool idle_in_use; + void __iomem *reg; + resource_size_t reg_size; +}; + +#endif /* __LINUX_PLATFORM_DATA_I2C_MUX_REG_H */ -- GitLab From 3f9c37a0c9a59db97ca5712eca7838b842949047 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sun, 16 Aug 2015 20:10:16 +0200 Subject: [PATCH 4671/7006] i2c: lpc2k: add driver Add support for the I2C controller found on several NXP devices including LPC2xxx, LPC178x/7x and LPC18xx/43xx. The controller is implemented as a state machine and the driver act upon the state changes when the bus is accessed. The I2C controller supports master/slave operation, bus arbitration, programmable clock rate, and speeds up to 1 Mbit/s. Signed-off-by: Joachim Eastwood Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-lpc2k.txt | 33 ++ drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-lpc2k.c | 513 ++++++++++++++++++ 4 files changed, 557 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-lpc2k.txt create mode 100644 drivers/i2c/busses/i2c-lpc2k.c diff --git a/Documentation/devicetree/bindings/i2c/i2c-lpc2k.txt b/Documentation/devicetree/bindings/i2c/i2c-lpc2k.txt new file mode 100644 index 0000000000000..4101aa621ad42 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-lpc2k.txt @@ -0,0 +1,33 @@ +NXP I2C controller for LPC2xxx/178x/18xx/43xx + +Required properties: + - compatible: must be "nxp,lpc1788-i2c" + - reg: physical address and length of the device registers + - interrupts: a single interrupt specifier + - clocks: clock for the device + - #address-cells: should be <1> + - #size-cells: should be <0> + +Optional properties: +- clock-frequency: the desired I2C bus clock frequency in Hz; in + absence of this property the default value is used (100 kHz). + +Example: +i2c0: i2c@400a1000 { + compatible = "nxp,lpc1788-i2c"; + reg = <0x400a1000 0x1000>; + interrupts = <18>; + clocks = <&ccu1 CLK_APB1_I2C0>; + #address-cells = <1>; + #size-cells = <0>; +}; + +&i2c0 { + clock-frequency = <400000>; + + lm75@48 { + compatible = "nxp,lm75"; + reg = <0x48>; + }; +}; + diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0b798ae708fe4..48f4b796003c2 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -619,6 +619,16 @@ config I2C_KEMPLD This driver can also be built as a module. If so, the module will be called i2c-kempld. +config I2C_LPC2K + tristate "I2C bus support for NXP LPC2K/LPC178x/18xx/43xx" + depends on OF && (ARCH_LPC18XX || COMPILE_TEST) + help + This driver supports the I2C interface found several NXP + devices including LPC2xxx, LPC178x/7x and LPC18xx/43xx. + + This driver can also be built as a module. If so, the module + will be called i2c-lpc2k. + config I2C_MESON tristate "Amlogic Meson I2C controller" depends on ARCH_MESON diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 50e8bbb65f1cd..6df3b303bd092 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -59,6 +59,7 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o +obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c new file mode 100644 index 0000000000000..8560a13bf1b30 --- /dev/null +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -0,0 +1,513 @@ +/* + * Copyright (C) 2011 NXP Semiconductors + * + * Code portions referenced from the i2x-pxa and i2c-pnx drivers + * + * Make SMBus byte and word transactions work on LPC178x/7x + * Copyright (c) 2012 + * Alexander Potashev, Emcraft Systems, aspotashev@emcraft.com + * Anton Protopopov, Emcraft Systems, antonp@emcraft.com + * + * Copyright (C) 2015 Joachim Eastwood + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* LPC24xx register offsets and bits */ +#define LPC24XX_I2CONSET 0x00 +#define LPC24XX_I2STAT 0x04 +#define LPC24XX_I2DAT 0x08 +#define LPC24XX_I2ADDR 0x0c +#define LPC24XX_I2SCLH 0x10 +#define LPC24XX_I2SCLL 0x14 +#define LPC24XX_I2CONCLR 0x18 + +#define LPC24XX_AA BIT(2) +#define LPC24XX_SI BIT(3) +#define LPC24XX_STO BIT(4) +#define LPC24XX_STA BIT(5) +#define LPC24XX_I2EN BIT(6) + +#define LPC24XX_STO_AA (LPC24XX_STO | LPC24XX_AA) +#define LPC24XX_CLEAR_ALL (LPC24XX_AA | LPC24XX_SI | LPC24XX_STO | \ + LPC24XX_STA | LPC24XX_I2EN) + +/* I2C SCL clock has different duty cycle depending on mode */ +#define I2C_STD_MODE_DUTY 46 +#define I2C_FAST_MODE_DUTY 36 +#define I2C_FAST_MODE_PLUS_DUTY 38 + +/* + * 26 possible I2C status codes, but codes applicable only + * to master are listed here and used in this driver + */ +enum { + M_BUS_ERROR = 0x00, + M_START = 0x08, + M_REPSTART = 0x10, + MX_ADDR_W_ACK = 0x18, + MX_ADDR_W_NACK = 0x20, + MX_DATA_W_ACK = 0x28, + MX_DATA_W_NACK = 0x30, + M_DATA_ARB_LOST = 0x38, + MR_ADDR_R_ACK = 0x40, + MR_ADDR_R_NACK = 0x48, + MR_DATA_R_ACK = 0x50, + MR_DATA_R_NACK = 0x58, + M_I2C_IDLE = 0xf8, +}; + +struct lpc2k_i2c { + void __iomem *base; + struct clk *clk; + int irq; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int msg_idx; + int msg_status; + int is_last; +}; + +static void i2c_lpc2k_reset(struct lpc2k_i2c *i2c) +{ + /* Will force clear all statuses */ + writel(LPC24XX_CLEAR_ALL, i2c->base + LPC24XX_I2CONCLR); + writel(0, i2c->base + LPC24XX_I2ADDR); + writel(LPC24XX_I2EN, i2c->base + LPC24XX_I2CONSET); +} + +static int i2c_lpc2k_clear_arb(struct lpc2k_i2c *i2c) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + /* + * If the transfer needs to abort for some reason, we'll try to + * force a stop condition to clear any pending bus conditions + */ + writel(LPC24XX_STO, i2c->base + LPC24XX_I2CONSET); + + /* Wait for status change */ + while (readl(i2c->base + LPC24XX_I2STAT) != M_I2C_IDLE) { + if (time_after(jiffies, timeout)) { + /* Bus was not idle, try to reset adapter */ + i2c_lpc2k_reset(i2c); + return -EBUSY; + } + + cpu_relax(); + } + + return 0; +} + +static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) +{ + unsigned char data; + u32 status; + + /* + * I2C in the LPC2xxx series is basically a state machine. + * Just run through the steps based on the current status. + */ + status = readl(i2c->base + LPC24XX_I2STAT); + + switch (status) { + case M_START: + case M_REPSTART: + /* Start bit was just sent out, send out addr and dir */ + data = i2c->msg->addr << 1; + if (i2c->msg->flags & I2C_M_RD) + data |= 1; + + writel(data, i2c->base + LPC24XX_I2DAT); + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); + break; + + case MX_ADDR_W_ACK: + case MX_DATA_W_ACK: + /* + * Address or data was sent out with an ACK. If there is more + * data to send, send it now + */ + if (i2c->msg_idx < i2c->msg->len) { + writel(i2c->msg->buf[i2c->msg_idx], + i2c->base + LPC24XX_I2DAT); + } else if (i2c->is_last) { + /* Last message, send stop */ + writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); + i2c->msg_status = 0; + disable_irq_nosync(i2c->irq); + } else { + i2c->msg_status = 0; + disable_irq_nosync(i2c->irq); + } + + i2c->msg_idx++; + break; + + case MR_ADDR_R_ACK: + /* Receive first byte from slave */ + if (i2c->msg->len == 1) { + /* Last byte, return NACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); + } else { + /* Not last byte, return ACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET); + } + + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); + break; + + case MR_DATA_R_NACK: + /* + * The I2C shows NACK status on reads, so we need to accept + * the NACK as an ACK here. This should be ok, as the real + * BACK would of been caught on the address write. + */ + case MR_DATA_R_ACK: + /* Data was received */ + if (i2c->msg_idx < i2c->msg->len) { + i2c->msg->buf[i2c->msg_idx] = + readl(i2c->base + LPC24XX_I2DAT); + } + + /* If transfer is done, send STOP */ + if (i2c->msg_idx >= i2c->msg->len - 1 && i2c->is_last) { + writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); + i2c->msg_status = 0; + } + + /* Message is done */ + if (i2c->msg_idx >= i2c->msg->len - 1) { + i2c->msg_status = 0; + disable_irq_nosync(i2c->irq); + } + + /* + * One pre-last data input, send NACK to tell the slave that + * this is going to be the last data byte to be transferred. + */ + if (i2c->msg_idx >= i2c->msg->len - 2) { + /* One byte left to receive - NACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); + } else { + /* More than one byte left to receive - ACK */ + writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONSET); + } + + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONCLR); + i2c->msg_idx++; + break; + + case MX_ADDR_W_NACK: + case MX_DATA_W_NACK: + case MR_ADDR_R_NACK: + /* NACK processing is done */ + writel(LPC24XX_STO_AA, i2c->base + LPC24XX_I2CONSET); + i2c->msg_status = -ENXIO; + disable_irq_nosync(i2c->irq); + break; + + case M_DATA_ARB_LOST: + /* Arbitration lost */ + i2c->msg_status = -EAGAIN; + + /* Release the I2C bus */ + writel(LPC24XX_STA | LPC24XX_STO, i2c->base + LPC24XX_I2CONCLR); + disable_irq_nosync(i2c->irq); + break; + + default: + /* Unexpected statuses */ + i2c->msg_status = -EIO; + disable_irq_nosync(i2c->irq); + break; + } + + /* Exit on failure or all bytes transferred */ + if (i2c->msg_status != -EBUSY) + wake_up(&i2c->wait); + + /* + * If `msg_status` is zero, then `lpc2k_process_msg()` + * is responsible for clearing the SI flag. + */ + if (i2c->msg_status != 0) + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); +} + +static int lpc2k_process_msg(struct lpc2k_i2c *i2c, int msgidx) +{ + /* A new transfer is kicked off by initiating a start condition */ + if (!msgidx) { + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET); + } else { + /* + * A multi-message I2C transfer continues where the + * previous I2C transfer left off and uses the + * current condition of the I2C adapter. + */ + if (unlikely(i2c->msg->flags & I2C_M_NOSTART)) { + WARN_ON(i2c->msg->len == 0); + + if (!(i2c->msg->flags & I2C_M_RD)) { + /* Start transmit of data */ + writel(i2c->msg->buf[0], + i2c->base + LPC24XX_I2DAT); + i2c->msg_idx++; + } + } else { + /* Start or repeated start */ + writel(LPC24XX_STA, i2c->base + LPC24XX_I2CONSET); + } + + writel(LPC24XX_SI, i2c->base + LPC24XX_I2CONCLR); + } + + enable_irq(i2c->irq); + + /* Wait for transfer completion */ + if (wait_event_timeout(i2c->wait, i2c->msg_status != -EBUSY, + msecs_to_jiffies(1000)) == 0) { + disable_irq_nosync(i2c->irq); + + return -ETIMEDOUT; + } + + return i2c->msg_status; +} + +static int i2c_lpc2k_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int msg_num) +{ + struct lpc2k_i2c *i2c = i2c_get_adapdata(adap); + int ret, i; + u32 stat; + + /* Check for bus idle condition */ + stat = readl(i2c->base + LPC24XX_I2STAT); + if (stat != M_I2C_IDLE) { + /* Something is holding the bus, try to clear it */ + return i2c_lpc2k_clear_arb(i2c); + } + + /* Process a single message at a time */ + for (i = 0; i < msg_num; i++) { + /* Save message pointer and current message data index */ + i2c->msg = &msgs[i]; + i2c->msg_idx = 0; + i2c->msg_status = -EBUSY; + i2c->is_last = (i == (msg_num - 1)); + + ret = lpc2k_process_msg(i2c, i); + if (ret) + return ret; + } + + return msg_num; +} + +static irqreturn_t i2c_lpc2k_handler(int irq, void *dev_id) +{ + struct lpc2k_i2c *i2c = dev_id; + + if (readl(i2c->base + LPC24XX_I2CONSET) & LPC24XX_SI) { + i2c_lpc2k_pump_msg(i2c); + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static u32 i2c_lpc2k_functionality(struct i2c_adapter *adap) +{ + /* Only emulated SMBus for now */ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm i2c_lpc2k_algorithm = { + .master_xfer = i2c_lpc2k_xfer, + .functionality = i2c_lpc2k_functionality, +}; + +static int i2c_lpc2k_probe(struct platform_device *pdev) +{ + struct lpc2k_i2c *i2c; + struct resource *res; + u32 bus_clk_rate; + u32 scl_high; + u32 clkrate; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) { + dev_err(&pdev->dev, "can't get interrupt resource\n"); + return i2c->irq; + } + + init_waitqueue_head(&i2c->wait); + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) { + dev_err(&pdev->dev, "error getting clock\n"); + return PTR_ERR(i2c->clk); + } + + ret = clk_prepare_enable(i2c->clk); + if (ret) { + dev_err(&pdev->dev, "unable to enable clock.\n"); + return ret; + } + + ret = devm_request_irq(&pdev->dev, i2c->irq, i2c_lpc2k_handler, 0, + dev_name(&pdev->dev), i2c); + if (ret < 0) { + dev_err(&pdev->dev, "can't request interrupt.\n"); + goto fail_clk; + } + + disable_irq_nosync(i2c->irq); + + /* Place controller is a known state */ + i2c_lpc2k_reset(i2c); + + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &bus_clk_rate); + if (ret) + bus_clk_rate = 100000; /* 100 kHz default clock rate */ + + clkrate = clk_get_rate(i2c->clk); + if (clkrate == 0) { + dev_err(&pdev->dev, "can't get I2C base clock\n"); + ret = -EINVAL; + goto fail_clk; + } + + /* Setup I2C dividers to generate clock with proper duty cycle */ + clkrate = clkrate / bus_clk_rate; + if (bus_clk_rate <= 100000) + scl_high = (clkrate * I2C_STD_MODE_DUTY) / 100; + else if (bus_clk_rate <= 400000) + scl_high = (clkrate * I2C_FAST_MODE_DUTY) / 100; + else + scl_high = (clkrate * I2C_FAST_MODE_PLUS_DUTY) / 100; + + writel(scl_high, i2c->base + LPC24XX_I2SCLH); + writel(clkrate - scl_high, i2c->base + LPC24XX_I2SCLL); + + platform_set_drvdata(pdev, i2c); + + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.owner = THIS_MODULE; + strlcpy(i2c->adap.name, "LPC2K I2C adapter", sizeof(i2c->adap.name)); + i2c->adap.algo = &i2c_lpc2k_algorithm; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + ret = i2c_add_adapter(&i2c->adap); + if (ret < 0) { + dev_err(&pdev->dev, "failed to add adapter!\n"); + goto fail_clk; + } + + dev_info(&pdev->dev, "LPC2K I2C adapter\n"); + + return 0; + +fail_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int i2c_lpc2k_remove(struct platform_device *dev) +{ + struct lpc2k_i2c *i2c = platform_get_drvdata(dev); + + i2c_del_adapter(&i2c->adap); + clk_disable_unprepare(i2c->clk); + + return 0; +} + +#ifdef CONFIG_PM +static int i2c_lpc2k_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc2k_i2c *i2c = platform_get_drvdata(pdev); + + clk_disable(i2c->clk); + + return 0; +} + +static int i2c_lpc2k_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct lpc2k_i2c *i2c = platform_get_drvdata(pdev); + + clk_enable(i2c->clk); + i2c_lpc2k_reset(i2c); + + return 0; +} + +static const struct dev_pm_ops i2c_lpc2k_dev_pm_ops = { + .suspend_noirq = i2c_lpc2k_suspend, + .resume_noirq = i2c_lpc2k_resume, +}; + +#define I2C_LPC2K_DEV_PM_OPS (&i2c_lpc2k_dev_pm_ops) +#else +#define I2C_LPC2K_DEV_PM_OPS NULL +#endif + +static const struct of_device_id lpc2k_i2c_match[] = { + { .compatible = "nxp,lpc1788-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, lpc2k_i2c_match); + +static struct platform_driver i2c_lpc2k_driver = { + .probe = i2c_lpc2k_probe, + .remove = i2c_lpc2k_remove, + .driver = { + .name = "lpc2k-i2c", + .pm = I2C_LPC2K_DEV_PM_OPS, + .of_match_table = lpc2k_i2c_match, + }, +}; +module_platform_driver(i2c_lpc2k_driver); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_DESCRIPTION("I2C driver for LPC2xxx devices"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lpc2k-i2c"); -- GitLab From 01eef96e37d77cd89156e5f51aab81a9d5c96539 Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Wed, 12 Aug 2015 17:31:33 +0300 Subject: [PATCH 4672/7006] i2c: core: Add support for best effort block read emulation There are devices that need to handle block transactions regardless of the capabilities exported by the adapter. For performance reasons, they need to use i2c read blocks if available, otherwise emulate the block transaction with word or byte transactions. Add support for a helper function that would read a data block using the best transfer available: I2C_FUNC_SMBUS_READ_I2C_BLOCK, I2C_FUNC_SMBUS_READ_WORD_DATA or I2C_FUNC_SMBUS_READ_BYTE_DATA. Signed-off-by: Irina Tirdea Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 57 ++++++++++++++++++++++++++++++++++++++++++ include/linux/i2c.h | 3 +++ 2 files changed, 60 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a6780289c61d2..98f6c75b1d18e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -3007,6 +3007,63 @@ trace: } EXPORT_SYMBOL(i2c_smbus_xfer); +/** + * i2c_smbus_read_i2c_block_data_or_emulated - read block or emulate + * @client: Handle to slave device + * @command: Byte interpreted by slave + * @length: Size of data block; SMBus allows at most I2C_SMBUS_BLOCK_MAX bytes + * @values: Byte array into which data will be read; big enough to hold + * the data returned by the slave. SMBus allows at most + * I2C_SMBUS_BLOCK_MAX bytes. + * + * This executes the SMBus "block read" protocol if supported by the adapter. + * If block read is not supported, it emulates it using either word or byte + * read protocols depending on availability. + * + * The addresses of the I2C slave device that are accessed with this function + * must be mapped to a linear region, so that a block read will have the same + * effect as a byte read. Before using this function you must double-check + * if the I2C slave does support exchanging a block transfer with a byte + * transfer. + */ +s32 i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, + u8 command, u8 length, u8 *values) +{ + u8 i = 0; + int status; + + if (length > I2C_SMBUS_BLOCK_MAX) + length = I2C_SMBUS_BLOCK_MAX; + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) + return i2c_smbus_read_i2c_block_data(client, command, length, values); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) + return -EOPNOTSUPP; + + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) { + while ((i + 2) <= length) { + status = i2c_smbus_read_word_data(client, command + i); + if (status < 0) + return status; + values[i] = status & 0xff; + values[i + 1] = status >> 8; + i += 2; + } + } + + while (i < length) { + status = i2c_smbus_read_byte_data(client, command + i); + if (status < 0) + return status; + values[i] = status; + i++; + } + + return i; +} +EXPORT_SYMBOL(i2c_smbus_read_i2c_block_data_or_emulated); + #if IS_ENABLED(CONFIG_I2C_SLAVE) int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 5aea071372185..768063baafbf5 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -121,6 +121,9 @@ extern s32 i2c_smbus_read_i2c_block_data(const struct i2c_client *client, extern s32 i2c_smbus_write_i2c_block_data(const struct i2c_client *client, u8 command, u8 length, const u8 *values); +extern s32 +i2c_smbus_read_i2c_block_data_or_emulated(const struct i2c_client *client, + u8 command, u8 length, u8 *values); #endif /* I2C */ /** -- GitLab From 2cd9fbd0ed5ef12bf550c06126ebbe720574fc0e Mon Sep 17 00:00:00 2001 From: Irina Tirdea Date: Wed, 12 Aug 2015 17:31:34 +0300 Subject: [PATCH 4673/7006] eeprom: at24: use i2c_smbus_read_i2c_block_data_or_emulated For i2c busses that support only SMBUS extensions, the eeprom at24 driver reads data from the device using the SMBus block, word or byte read protocols depending on availability. Replace the block read emulation from the driver with the i2c_smbus_read_i2c_block_data_or_emulated call from i2c core. Signed-off-by: Irina Tirdea Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 2b254f3a1154e..c6cb7f8f325e9 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -186,19 +186,11 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, if (count > io_limit) count = io_limit; - switch (at24->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: + if (at24->use_smbus) { /* Smaller eeproms can work given some SMBus extension calls */ if (count > I2C_SMBUS_BLOCK_MAX) count = I2C_SMBUS_BLOCK_MAX; - break; - case I2C_SMBUS_WORD_DATA: - count = 2; - break; - case I2C_SMBUS_BYTE_DATA: - count = 1; - break; - default: + } else { /* * When we have a better choice than SMBus calls, use a * combined I2C message. Write address; then read up to @@ -229,27 +221,10 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf, timeout = jiffies + msecs_to_jiffies(write_timeout); do { read_time = jiffies; - switch (at24->use_smbus) { - case I2C_SMBUS_I2C_BLOCK_DATA: - status = i2c_smbus_read_i2c_block_data(client, offset, - count, buf); - break; - case I2C_SMBUS_WORD_DATA: - status = i2c_smbus_read_word_data(client, offset); - if (status >= 0) { - buf[0] = status & 0xff; - buf[1] = status >> 8; - status = count; - } - break; - case I2C_SMBUS_BYTE_DATA: - status = i2c_smbus_read_byte_data(client, offset); - if (status >= 0) { - buf[0] = status; - status = count; - } - break; - default: + if (at24->use_smbus) { + status = i2c_smbus_read_i2c_block_data_or_emulated(client, offset, + count, buf); + } else { status = i2c_transfer(client->adapter, msg, 2); if (status == 2) status = count; -- GitLab From 480b141abf7ffe630016dd4ced0fc57f105a05a9 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Aug 2015 13:19:57 +0200 Subject: [PATCH 4674/7006] i2c: Replace I2C_CROS_EC_TUNNEL dependency The ChromeOS EC tunnel I2C bus driver depend on CROS_EC_PROTO but MFD_CROS_EC select CROS_EC_PROTO instead. Mixing select and depends on is bad practice as it may lead to circular Kconfig dependencies. Since the platform device that is matched with the I2C bus driver is registered by the ChromeOS EC mfd driver, I2C_CROS_EC_TUNNEL really depends on MFD_CROS_EC. And because this config option selects CROS_EC_PROTO, that dependency is met as well. So make the driver to depend on MFD_CROS_EC instead of CROS_EC_PROTO. Signed-off-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 48f4b796003c2..08b86178e8fba 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1140,7 +1140,7 @@ config I2C_SIBYTE config I2C_CROS_EC_TUNNEL tristate "ChromeOS EC tunnel I2C bus" - depends on CROS_EC_PROTO + depends on MFD_CROS_EC help If you say yes here you get an I2C bus that will tunnel i2c commands through to the other side of the ChromeOS EC to the i2c bus -- GitLab From a4a9a8cb3248b3b48a6049acaeaf23d4ad3712b9 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Aug 2015 12:12:19 +0300 Subject: [PATCH 4675/7006] i2c: xgene-slimpro: dma_mapping_error() doesn't return an error code The dma_mapping_error() function returns true if there is an error, it doesn't return an error code. We should return -ENOMEM. Signed-off-by: Dan Carpenter Reviewed-by: Axel Lin Signed-off-by: Wolfram Sang Cc: stable@kernel.org --- drivers/i2c/busses/i2c-xgene-slimpro.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 1c9cb65ac4cf8..4233f5695352f 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -198,10 +198,10 @@ static int slimpro_i2c_blkrd(struct slimpro_i2c_dev *ctx, u32 chip, u32 addr, int rc; paddr = dma_map_single(ctx->dev, ctx->dma_buffer, readlen, DMA_FROM_DEVICE); - rc = dma_mapping_error(ctx->dev, paddr); - if (rc) { + if (dma_mapping_error(ctx->dev, paddr)) { dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n", ctx->dma_buffer); + rc = -ENOMEM; goto err; } @@ -241,10 +241,10 @@ static int slimpro_i2c_blkwr(struct slimpro_i2c_dev *ctx, u32 chip, memcpy(ctx->dma_buffer, data, writelen); paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen, DMA_TO_DEVICE); - rc = dma_mapping_error(ctx->dev, paddr); - if (rc) { + if (dma_mapping_error(ctx->dev, paddr)) { dev_err(&ctx->adapter.dev, "Error in mapping dma buffer %p\n", ctx->dma_buffer); + rc = -ENOMEM; goto err; } -- GitLab From 5166c20ef95be89d10ffe0140e74df5cf26e9786 Mon Sep 17 00:00:00 2001 From: Will Deacon Date: Mon, 24 Aug 2015 13:35:51 +0100 Subject: [PATCH 4676/7006] arm64: makefile: fix perf_callchain.o kconfig dependency Commit 4b3dc9679cf7 ("arm64: force CONFIG_SMP=y and remove redundant #ifdefs") incorrectly resolved a conflict on arch/arm64/kernel/Makefile which resulted in a partial revert of 52da443ec4d0 ("arm64: perf: factor out callchain code"), leading to perf_callchain.o depending on CONFIG_HW_PERF_EVENTS instead of CONFIG_PERF_EVENTS. This patch restores the kconfig dependency for perf_callchain.o. Reported-by: Mark Rutland Signed-off-by: Will Deacon --- arch/arm64/kernel/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index c662197ee57c0..22dc9bc781be6 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -25,8 +25,8 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \ ../../arm/kernel/opcodes.o arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o -arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o -arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_callchain.o +arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o +arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o -- GitLab From da935c0b6eeeac16de0a82cc1152fb0a9b5a11ef Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Aug 2015 13:19:56 +0200 Subject: [PATCH 4677/7006] mfd: cros_ec: Remove CROS_EC_PROTO dependency for SPI and I2C drivers The ChromeOS EC SPI and I2C transport drivers depends on CROS_EC_PROTO but MFD_CROS_EC select CROS_EC_PROTO instead. Mixing select and depends on is bad practice as it may lead to circular Kconfig dependencies. Since these drivers already depend on MFD_CROS_EC and that config option already selects CROS_EC_PROTO, there is no need to make them explicitly depend on CROS_EC_PROTO since that dependency is already met. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 93837b4e80250..dd55c25fb656a 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -105,7 +105,7 @@ config MFD_CROS_EC config MFD_CROS_EC_I2C tristate "ChromeOS Embedded Controller (I2C)" - depends on MFD_CROS_EC && CROS_EC_PROTO && I2C + depends on MFD_CROS_EC && I2C help If you say Y here, you get support for talking to the ChromeOS @@ -115,7 +115,7 @@ config MFD_CROS_EC_I2C config MFD_CROS_EC_SPI tristate "ChromeOS Embedded Controller (SPI)" - depends on MFD_CROS_EC && CROS_EC_PROTO && SPI + depends on MFD_CROS_EC && SPI ---help--- If you say Y here, you get support for talking to the ChromeOS EC -- GitLab From b9124a523017a53cce071451f5c38a0b77761534 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Aug 2015 13:19:53 +0200 Subject: [PATCH 4678/7006] mfd: Add MFD_CROS_EC dependencies The MFD_CROS_EC symbol select CHROME_PLATFORMS and CROS_EC_PROTO but that caused a Kconfig unmet direct dependencies warning since these symbols could only be selected for X86 || ARM. The fix it, the CHROME_PLATFORMS dependencies were relexed on commit d12bbcd3ea44 ("platform/chrome: Don't make CHROME_PLATFORMS depends on X86 || ARM") but that was found to be wrong and the correct fix is to add the needed dependencies to the MFD_CROS_EC config symbol. There are only x86 and ARM based Chromebooks so to avoid showing up the config option on unsupported platforms, make the symbol depend on these architectures. Also add a || COMPILE_TEST so it can have build coverage on other platforms. Suggested-by: Geert Uytterhoeven Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index dd55c25fb656a..5fa21739c54f1 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -97,6 +97,7 @@ config MFD_CROS_EC select MFD_CORE select CHROME_PLATFORMS select CROS_EC_PROTO + depends on X86 || ARM || COMPILE_TEST help If you say Y here you get support for the ChromeOS Embedded Controller (EC) providing keyboard, battery and power services. -- GitLab From 89bd794cf60760ef053d3694c6749f651c034e02 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 24 Aug 2015 10:47:18 +0200 Subject: [PATCH 4679/7006] mfd: max77686: Don't suggest in binding to use a deprecated property The regulator-compatible property from the regulator DT binding was deprecated. But the max77686 DT binding doc still suggest to use it instead of the regulator node name's which is the correct approach. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/max77686.txt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index 163bd81a4607c..8221102d3fc25 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -26,7 +26,7 @@ Optional node: }; refer Documentation/devicetree/bindings/regulator/regulator.txt - The regulator-compatible property of regulator should initialized with string + The regulator node's name should be initialized with a string to get matched with their hardware counterparts as follow: -LDOn : for LDOs, where n can lie in range 1 to 26. @@ -55,16 +55,14 @@ Example: reg = <0x09>; voltage-regulators { - ldo11_reg { - regulator-compatible = "LDO11"; + ldo11_reg: LDO11 { regulator-name = "vdd_ldo11"; regulator-min-microvolt = <1900000>; regulator-max-microvolt = <1900000>; regulator-always-on; }; - buck1_reg { - regulator-compatible = "BUCK1"; + buck1_reg: BUCK1 { regulator-name = "vdd_mif"; regulator-min-microvolt = <950000>; regulator-max-microvolt = <1300000>; @@ -72,8 +70,7 @@ Example: regulator-boot-on; }; - buck9_reg { - regulator-compatible = "BUCK9"; + buck9_reg: BUCK9 { regulator-name = "CAM_ISP_CORE_1.2V"; regulator-min-microvolt = <1000000>; regulator-max-microvolt = <1200000>; -- GitLab From 00d689169dd088257de7ed218ff2c638bc5ad3b5 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 24 Aug 2015 10:47:19 +0200 Subject: [PATCH 4680/7006] mfd: max77686: Use a generic name for the PMIC node in the example The ePAPR standard says that: "the name of a node should be somewhat generic, reflecting the function of the device and not its precise programming model." So, change the max77686 binding document example to use a generic node name instead of using the chip's name. Suggested-by: Sergei Shtylyov Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/max77686.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index 8221102d3fc25..d2ed3c20a5c3f 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -48,7 +48,7 @@ to get matched with their hardware counterparts as follow: Example: - max77686@09 { + max77686: pmic@09 { compatible = "maxim,max77686"; interrupt-parent = <&wakeup_eint>; interrupts = <26 0>; -- GitLab From 00f1493e9e0c875f16623bdb088108ada6e7647e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 24 Aug 2015 10:47:20 +0200 Subject: [PATCH 4681/7006] mfd: Add DT binding for Maxim MAX77802 IC The MAX77802 is a chip that contains regulators, 2 32kHz clocks, a RTC and an I2C interface to program the individual components. The are already DT bindings for the regulators and clocks and these reference to a bindings/mfd/max77802.txt file, that didn't exist, for the details about the PMIC. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/max77802.txt | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/mfd/max77802.txt diff --git a/Documentation/devicetree/bindings/mfd/max77802.txt b/Documentation/devicetree/bindings/mfd/max77802.txt new file mode 100644 index 0000000000000..51fc1a60caa56 --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/max77802.txt @@ -0,0 +1,26 @@ +Maxim MAX77802 multi-function device + +The Maxim MAX77802 is a Power Management IC (PMIC) that contains 10 high +efficiency Buck regulators, 32 Low-DropOut (LDO) regulators used to power +up application processors and peripherals, a 2-channel 32kHz clock outputs, +a Real-Time-Clock (RTC) and a I2C interface to program the individual +regulators, clocks outputs and the RTC. + +Bindings for the built-in 32k clock generator block and +regulators are defined in ../clk/maxim,max77802.txt and +../regulator/max77802.txt respectively. + +Required properties: +- compatible : Must be "maxim,max77802" +- reg : Specifies the I2C slave address of PMIC block. +- interrupts : I2C device IRQ line connected to the main SoC. +- interrupt-parent : The parent interrupt controller. + +Example: + + max77802: pmic@09 { + compatible = "maxim,max77802"; + interrupt-parent = <&intc>; + interrupts = <26 IRQ_TYPE_NONE>; + reg = <0x09>; + }; -- GitLab From aa60a8391337aa0f14ed890b237f5b8e6cadfbbf Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 24 Aug 2015 10:47:21 +0200 Subject: [PATCH 4682/7006] mfd: max77686: Split out regulator part from the DT binding The Maxim MAX77686 PMIC is a multi-function device with regulators, clocks and a RTC. The DT bindings for the clocks are in a separate file but the bindings for the regulators are inside the mfd part. To make it consistent with the clocks portion of the binding and because is more natural to look for regulator bindings under the bindings/regulator sub-directory, split the regulator portion of the DT binding and add it as a separate file. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/max77686.txt | 60 ++-------------- .../bindings/regulator/max77686.txt | 71 +++++++++++++++++++ 2 files changed, 75 insertions(+), 56 deletions(-) create mode 100644 Documentation/devicetree/bindings/regulator/max77686.txt diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt index d2ed3c20a5c3f..741e76688cf2a 100644 --- a/Documentation/devicetree/bindings/mfd/max77686.txt +++ b/Documentation/devicetree/bindings/mfd/max77686.txt @@ -7,8 +7,9 @@ different i2c slave address,presently for which we are statically creating i2c client while probing.This document describes the binding for mfd device and PMIC submodule. -Binding for the built-in 32k clock generator block is defined separately -in bindings/clk/maxim,max77686.txt file. +Bindings for the built-in 32k clock generator block and +regulators are defined in ../clk/maxim,max77686.txt and +../regulator/max77686.txt respectively. Required properties: - compatible : Must be "maxim,max77686"; @@ -16,36 +17,6 @@ Required properties: - interrupts : This i2c device has an IRQ line connected to the main SoC. - interrupt-parent : The parent interrupt controller. -Optional node: -- voltage-regulators : The regulators of max77686 have to be instantiated - under subnode named "voltage-regulators" using the following format. - - regulator_name { - regulator-compatible = LDOn/BUCKn - standard regulator constraints.... - }; - refer Documentation/devicetree/bindings/regulator/regulator.txt - - The regulator node's name should be initialized with a string -to get matched with their hardware counterparts as follow: - - -LDOn : for LDOs, where n can lie in range 1 to 26. - example: LDO1, LDO2, LDO26. - -BUCKn : for BUCKs, where n can lie in range 1 to 9. - example: BUCK1, BUCK5, BUCK9. - - Regulators which can be turned off during system suspend: - -LDOn : 2, 6-8, 10-12, 14-16, - -BUCKn : 1-4. - Use standard regulator bindings for it ('regulator-off-in-suspend'). - - LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable - control. To turn this feature on this property must be added to the regulator - sub-node: - - maxim,ena-gpios : one GPIO specifier enable control (the gpio - flags are actually ignored and always - ACTIVE_HIGH is used) - Example: max77686: pmic@09 { @@ -53,27 +24,4 @@ Example: interrupt-parent = <&wakeup_eint>; interrupts = <26 0>; reg = <0x09>; - - voltage-regulators { - ldo11_reg: LDO11 { - regulator-name = "vdd_ldo11"; - regulator-min-microvolt = <1900000>; - regulator-max-microvolt = <1900000>; - regulator-always-on; - }; - - buck1_reg: BUCK1 { - regulator-name = "vdd_mif"; - regulator-min-microvolt = <950000>; - regulator-max-microvolt = <1300000>; - regulator-always-on; - regulator-boot-on; - }; - - buck9_reg: BUCK9 { - regulator-name = "CAM_ISP_CORE_1.2V"; - regulator-min-microvolt = <1000000>; - regulator-max-microvolt = <1200000>; - maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; - }; - } + }; diff --git a/Documentation/devicetree/bindings/regulator/max77686.txt b/Documentation/devicetree/bindings/regulator/max77686.txt new file mode 100644 index 0000000000000..0dded64d89d3b --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/max77686.txt @@ -0,0 +1,71 @@ +Binding for Maxim MAX77686 regulators + +This is a part of the device tree bindings of MAX77686 multi-function device. +More information can be found in ../mfd/max77686.txt file. + +The MAX77686 PMIC has 9 high-efficiency Buck and 26 Low-DropOut (LDO) +regulators that can be controlled over I2C. + +Following properties should be present in main device node of the MFD chip. + +Optional node: +- voltage-regulators : The regulators of max77686 have to be instantiated + under subnode named "voltage-regulators" using the following format. + + regulator_name { + regulator-compatible = LDOn/BUCKn + standard regulator constraints.... + }; + refer Documentation/devicetree/bindings/regulator/regulator.txt + + The regulator node's name should be initialized with a string +to get matched with their hardware counterparts as follow: + + -LDOn : for LDOs, where n can lie in range 1 to 26. + example: LDO1, LDO2, LDO26. + -BUCKn : for BUCKs, where n can lie in range 1 to 9. + example: BUCK1, BUCK5, BUCK9. + + Regulators which can be turned off during system suspend: + -LDOn : 2, 6-8, 10-12, 14-16, + -BUCKn : 1-4. + Use standard regulator bindings for it ('regulator-off-in-suspend'). + + LDO20, LDO21, LDO22, BUCK8 and BUCK9 can be configured to GPIO enable + control. To turn this feature on this property must be added to the regulator + sub-node: + - maxim,ena-gpios : one GPIO specifier enable control (the gpio + flags are actually ignored and always + ACTIVE_HIGH is used) + +Example: + + max77686: pmic@09 { + compatible = "maxim,max77686"; + interrupt-parent = <&wakeup_eint>; + interrupts = <26 IRQ_TYPE_NONE>; + reg = <0x09>; + + voltage-regulators { + ldo11_reg: LDO11 { + regulator-name = "vdd_ldo11"; + regulator-min-microvolt = <1900000>; + regulator-max-microvolt = <1900000>; + regulator-always-on; + }; + + buck1_reg: BUCK1 { + regulator-name = "vdd_mif"; + regulator-min-microvolt = <950000>; + regulator-max-microvolt = <1300000>; + regulator-always-on; + regulator-boot-on; + }; + + buck9_reg: BUCK9 { + regulator-name = "CAM_ISP_CORE_1.2V"; + regulator-min-microvolt = <1000000>; + regulator-max-microvolt = <1200000>; + maxim,ena-gpios = <&gpm0 3 GPIO_ACTIVE_HIGH>; + }; + }; -- GitLab From 1e955bece28f0f464c2db03c7e12951cea65fab6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 20 Aug 2015 09:07:25 +0200 Subject: [PATCH 4683/7006] mfd: stmpe: Add OF match table The Documentation/devicetree/bindings/mfd/stmpe.txt DT binding doc lists "st,stmpe[610|801|811|1601|2401|2403]" as valid compatible strings but the corresponding driver does not have an OF match table. Add the table to the driver so the SPI core can do an OF style match. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/stmpe-spi.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/mfd/stmpe-spi.c b/drivers/mfd/stmpe-spi.c index a81badbaa917d..84e2e419bf3bc 100644 --- a/drivers/mfd/stmpe-spi.c +++ b/drivers/mfd/stmpe-spi.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "stmpe.h" @@ -108,6 +109,17 @@ static int stmpe_spi_remove(struct spi_device *spi) return stmpe_remove(stmpe); } +static const struct of_device_id stmpe_spi_of_match[] = { + { .compatible = "st,stmpe610", }, + { .compatible = "st,stmpe801", }, + { .compatible = "st,stmpe811", }, + { .compatible = "st,stmpe1601", }, + { .compatible = "st,stmpe2401", }, + { .compatible = "st,stmpe2403", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, stmpe_spi_of_match); + static const struct spi_device_id stmpe_spi_id[] = { { "stmpe610", STMPE610 }, { "stmpe801", STMPE801 }, @@ -122,6 +134,7 @@ MODULE_DEVICE_TABLE(spi, stmpe_id); static struct spi_driver stmpe_spi_driver = { .driver = { .name = "stmpe-spi", + .of_match_table = of_match_ptr(stmpe_spi_of_match), .owner = THIS_MODULE, #ifdef CONFIG_PM .pm = &stmpe_dev_pm_ops, -- GitLab From a78ea195f77a8ed2c5f3108a8cdb9a26ebd474d8 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 20 Aug 2015 09:07:22 +0200 Subject: [PATCH 4684/7006] mfd: cros_ec: spi: Add OF match table The Documentation/devicetree/bindings/mfd/cros-ec.txt DT binding doc lists "google,cros-ec-spi" as a compatible string but the corresponding driver does not have an OF match table. Add the table to the driver so the SPI core can do an OF style match. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/cros_ec_spi.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/mfd/cros_ec_spi.c b/drivers/mfd/cros_ec_spi.c index 16f228dc243f3..30a296b4e748c 100644 --- a/drivers/mfd/cros_ec_spi.c +++ b/drivers/mfd/cros_ec_spi.c @@ -701,6 +701,12 @@ static int cros_ec_spi_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(cros_ec_spi_pm_ops, cros_ec_spi_suspend, cros_ec_spi_resume); +static const struct of_device_id cros_ec_spi_of_match[] = { + { .compatible = "google,cros-ec-spi", }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, cros_ec_spi_of_match); + static const struct spi_device_id cros_ec_spi_id[] = { { "cros-ec-spi", 0 }, { } @@ -710,6 +716,7 @@ MODULE_DEVICE_TABLE(spi, cros_ec_spi_id); static struct spi_driver cros_ec_driver_spi = { .driver = { .name = "cros-ec-spi", + .of_match_table = of_match_ptr(cros_ec_spi_of_match), .owner = THIS_MODULE, .pm = &cros_ec_spi_pm_ops, }, -- GitLab From 5a688c455066c21c133bc8ffa7b11f8c66b7fe0b Mon Sep 17 00:00:00 2001 From: Matt Redfearn Date: Thu, 20 Aug 2015 11:30:32 +0100 Subject: [PATCH 4685/7006] mfd: jz4740-adc: Init mask cache in generic IRQ chip The mask cache must be initialised in the generic IRQ chip, otherwise enabling one channel will actually enable all channels when the empty mask cache is written. Signed-off-by: Matt Redfearn Signed-off-by: Lee Jones --- drivers/mfd/jz4740-adc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index 408291ce8af2f..5bb49f08955d0 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -273,7 +273,8 @@ static int jz4740_adc_probe(struct platform_device *pdev) ct->chip.irq_unmask = irq_gc_mask_clr_bit; ct->chip.irq_ack = irq_gc_ack_set_bit; - irq_setup_generic_chip(gc, IRQ_MSK(5), 0, 0, IRQ_NOPROBE | IRQ_LEVEL); + irq_setup_generic_chip(gc, IRQ_MSK(5), IRQ_GC_INIT_MASK_CACHE, 0, + IRQ_NOPROBE | IRQ_LEVEL); adc->gc = gc; -- GitLab From d721109611fb94aff53c2397859046e5f92f55ae Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 24 Jul 2015 14:18:45 +0900 Subject: [PATCH 4686/7006] kbuild: fixdep: optimize code slightly If the target string matches "CONFIG_", move the pointer p forward. This saves several 7-chars adjustments. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index b30406860b739..46cc1b3e5de2f 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -251,7 +251,8 @@ static void parse_config_file(const char *map, size_t len) continue; if (memcmp(p, "CONFIG_", 7)) continue; - for (q = p + 7; q < map + len; q++) { + p += 7; + for (q = p; q < map + len; q++) { if (!(isalnum(*q) || *q == '_')) goto found; } @@ -260,9 +261,9 @@ static void parse_config_file(const char *map, size_t len) found: if (!memcmp(q - 7, "_MODULE", 7)) q -= 7; - if( (q-p-7) < 0 ) + if (q - p < 0) continue; - use_config(p+7, q-p-7); + use_config(p, q - p); } } -- GitLab From d179e22762fd38414c4108acedd5feca4cf7e0d8 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 24 Jul 2015 14:18:46 +0900 Subject: [PATCH 4687/7006] kbuild: fixdep: drop meaningless hash table initialization The clear_config() is called just once at the beginning of this program, but the global variable hashtab[] is already zero-filled at the start-up. Signed-off-by: Masahiro Yamada Signed-off-by: Michal Marek --- scripts/basic/fixdep.c | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 46cc1b3e5de2f..c68fd61fdc42e 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -191,23 +191,6 @@ static void define_config(const char *name, int len, unsigned int hash) hashtab[hash % HASHSZ] = aux; } -/* - * Clear the set of configuration strings. - */ -static void clear_config(void) -{ - struct item *aux, *next; - unsigned int i; - - for (i = 0; i < HASHSZ; i++) { - for (aux = hashtab[i]; aux; aux = next) { - next = aux->next; - free(aux); - } - hashtab[i] = NULL; - } -} - /* * Record the use of a CONFIG_* word. */ @@ -325,8 +308,6 @@ static void parse_dep_file(void *map, size_t len) int saw_any_target = 0; int is_first_dep = 0; - clear_config(); - while (m < end) { /* Skip any "white space" */ while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) -- GitLab From cebb053bd144d88a4c24b14dd8ac775d8e5972d5 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 1 Aug 2014 15:50:44 +0200 Subject: [PATCH 4688/7006] of: Add vendor prefix for Sharp Corporation Use "sharp" as the vendor prefix for Sharp Corporation in device tree compatible strings. Signed-off-by: Thierry Reding [robh: fix name to Sharp Corporation] Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9ec..9a4ac79038e9c 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -181,6 +181,7 @@ sbs Smart Battery System schindler Schindler seagate Seagate Technology PLC semtech Semtech Corporation +sharp Sharp Corporation sil Silicon Image silabs Silicon Laboratories siliconmitus Silicon Mitus, Inc. -- GitLab From 80c545055dc7c1f7f487176fe0aac17896a4b7af Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Thu, 20 Aug 2015 08:51:56 -0700 Subject: [PATCH 4689/7006] f2fs: use __GFP_NOFAIL to avoid infinite loop __GFP_NOFAIL can avoid retrying the whole path of kmem_cache_alloc and bio_alloc. And, it also fixes the use cases of GFP_ATOMIC correctly. Suggested-by: Chao Yu Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/checkpoint.c | 21 ++++++++------------- fs/f2fs/f2fs.h | 16 +++++----------- fs/f2fs/node.c | 4 ++-- fs/f2fs/segment.c | 2 +- 4 files changed, 16 insertions(+), 27 deletions(-) diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c index 890e4d4c39d75..c5a38e352a809 100644 --- a/fs/f2fs/checkpoint.c +++ b/fs/f2fs/checkpoint.c @@ -336,26 +336,18 @@ const struct address_space_operations f2fs_meta_aops = { static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) { struct inode_management *im = &sbi->im[type]; - struct ino_entry *e; + struct ino_entry *e, *tmp; + + tmp = f2fs_kmem_cache_alloc(ino_entry_slab, GFP_NOFS); retry: - if (radix_tree_preload(GFP_NOFS)) { - cond_resched(); - goto retry; - } + radix_tree_preload(GFP_NOFS | __GFP_NOFAIL); spin_lock(&im->ino_lock); - e = radix_tree_lookup(&im->ino_root, ino); if (!e) { - e = kmem_cache_alloc(ino_entry_slab, GFP_ATOMIC); - if (!e) { - spin_unlock(&im->ino_lock); - radix_tree_preload_end(); - goto retry; - } + e = tmp; if (radix_tree_insert(&im->ino_root, ino, e)) { spin_unlock(&im->ino_lock); - kmem_cache_free(ino_entry_slab, e); radix_tree_preload_end(); goto retry; } @@ -368,6 +360,9 @@ retry: } spin_unlock(&im->ino_lock); radix_tree_preload_end(); + + if (e != tmp) + kmem_cache_free(ino_entry_slab, tmp); } static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 66410178aba1c..ece5e704dfd00 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1252,13 +1252,10 @@ static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) { void *entry; -retry: - entry = kmem_cache_alloc(cachep, flags); - if (!entry) { - cond_resched(); - goto retry; - } + entry = kmem_cache_alloc(cachep, flags); + if (!entry) + entry = kmem_cache_alloc(cachep, flags | __GFP_NOFAIL); return entry; } @@ -1267,12 +1264,9 @@ static inline struct bio *f2fs_bio_alloc(int npages) struct bio *bio; /* No failure on bio allocation */ -retry: bio = bio_alloc(GFP_NOIO, npages); - if (!bio) { - cond_resched(); - goto retry; - } + if (!bio) + bio = bio_alloc(GFP_NOIO | __GFP_NOFAIL, npages); return bio; } diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 6bef5a2788b45..777066d29fa80 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -159,7 +159,7 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i, head = radix_tree_lookup(&nm_i->nat_set_root, set); if (!head) { - head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_ATOMIC); + head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_NOFS); INIT_LIST_HEAD(&head->entry_list); INIT_LIST_HEAD(&head->set_list); @@ -246,7 +246,7 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid) { struct nat_entry *new; - new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC); + new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_NOFS); f2fs_radix_tree_insert(&nm_i->nat_root, nid, new); memset(new, 0, sizeof(struct nat_entry)); nat_set_nid(new, nid); diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c index 6273e2cde93e7..78e6d06968477 100644 --- a/fs/f2fs/segment.c +++ b/fs/f2fs/segment.c @@ -1753,7 +1753,7 @@ static struct page *get_next_sit_page(struct f2fs_sb_info *sbi, static struct sit_entry_set *grab_sit_entry_set(void) { struct sit_entry_set *ses = - f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_ATOMIC); + f2fs_kmem_cache_alloc(sit_entry_set_slab, GFP_NOFS); ses->entry_cnt = 0; INIT_LIST_HEAD(&ses->set_list); -- GitLab From f7409d0fae7a02ea6c8195f75ad73866d5dea617 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Fri, 21 Aug 2015 23:37:18 -0700 Subject: [PATCH 4690/7006] f2fs: fix wrong pointer access during try_to_free_nids If we release the lock in list_for_each_entry_safe, we can lose the tmp pointer by alloc_nid. Signed-off-by: Jaegeuk Kim --- fs/f2fs/node.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 777066d29fa80..0867325e288fc 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -1664,11 +1664,9 @@ int try_to_free_nids(struct f2fs_sb_info *sbi, int nr_shrink) if (i->state == NID_ALLOC) continue; __del_from_free_nid_list(nm_i, i); - nm_i->fcnt--; - spin_unlock(&nm_i->free_nid_list_lock); kmem_cache_free(free_nid_slab, i); + nm_i->fcnt--; nr_shrink--; - spin_lock(&nm_i->free_nid_list_lock); } spin_unlock(&nm_i->free_nid_list_lock); mutex_unlock(&nm_i->build_lock); -- GitLab From 6a6788576dac56135bf98ad974a038b0afb1a499 Mon Sep 17 00:00:00 2001 From: Zhang Zhen Date: Mon, 24 Aug 2015 10:41:32 +0800 Subject: [PATCH 4691/7006] f2fs: atomically set inode->i_flags According to commit 5f16f3225b06 ("ext4: atomically set inode->i_flags in ext4_set_inode_flags()"). Signed-off-by: Zhang Zhen Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index 83354433d4d1b..d1b03d01b7e3d 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -12,7 +12,6 @@ #include #include #include -#include #include "f2fs.h" #include "node.h" @@ -34,8 +33,8 @@ void f2fs_set_inode_flags(struct inode *inode) new_fl |= S_NOATIME; if (flags & FS_DIRSYNC_FL) new_fl |= S_DIRSYNC; - set_mask_bits(&inode->i_flags, - S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC, new_fl); + inode_set_flags(inode, new_fl, + S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); } static void __get_inode_rdev(struct inode *inode, struct f2fs_inode *ri) -- GitLab From 4ec17d688d74b6b7cb10043c57ff4818cde2b0ca Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 24 Aug 2015 17:36:25 +0800 Subject: [PATCH 4692/7006] f2fs: avoid unneeded initializing when converting inline dentry When converting inline dentry, we will zero out target dentry page before duplicating data of inline dentry into target page, it become overhead since inline dentry size is not small. So this patch tries to remove unneeded initializing in the space of target dentry page. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/inline.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c index 79d18d5c1fae3..3d143be428959 100644 --- a/fs/f2fs/inline.c +++ b/fs/f2fs/inline.c @@ -384,13 +384,21 @@ static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage, goto out; f2fs_wait_on_page_writeback(page, DATA); - zero_user_segment(page, 0, PAGE_CACHE_SIZE); + zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE); dentry_blk = kmap_atomic(page); /* copy data from inline dentry block to new dentry block */ memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap, INLINE_DENTRY_BITMAP_SIZE); + memset(dentry_blk->dentry_bitmap + INLINE_DENTRY_BITMAP_SIZE, 0, + SIZE_OF_DENTRY_BITMAP - INLINE_DENTRY_BITMAP_SIZE); + /* + * we do not need to zero out remainder part of dentry and filename + * field, since we have used bitmap for marking the usage status of + * them, besides, we can also ignore copying/zeroing reserved space + * of dentry block, because them haven't been used so far. + */ memcpy(dentry_blk->dentry, inline_dentry->dentry, sizeof(struct f2fs_dir_entry) * NR_INLINE_DENTRY); memcpy(dentry_blk->filename, inline_dentry->filename, -- GitLab From b01548919c33767bc457390fa3c41aedc273bfff Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 24 Aug 2015 17:39:42 +0800 Subject: [PATCH 4693/7006] f2fs: handle f2fs_truncate error correctly This patch fixes to return error number of f2fs_truncate, so that we can handle the error correctly in callers. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 +- fs/f2fs/file.c | 26 +++++++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index ece5e704dfd00..806439f1c886a 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1595,7 +1595,7 @@ static inline bool f2fs_may_extent_tree(struct inode *inode) int f2fs_sync_file(struct file *, loff_t, loff_t, int); void truncate_data_blocks(struct dnode_of_data *); int truncate_blocks(struct inode *, u64, bool); -void f2fs_truncate(struct inode *, bool); +int f2fs_truncate(struct inode *, bool); int f2fs_getattr(struct vfsmount *, struct dentry *, struct kstat *); int f2fs_setattr(struct dentry *, struct iattr *); int truncate_hole(struct inode *, pgoff_t, pgoff_t); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 7faafb5043e0f..86a5c76eb106d 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -579,24 +579,30 @@ out: return err; } -void f2fs_truncate(struct inode *inode, bool lock) +int f2fs_truncate(struct inode *inode, bool lock) { + int err; + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) - return; + return 0; trace_f2fs_truncate(inode); /* we should check inline_data size */ if (f2fs_has_inline_data(inode) && !f2fs_may_inline_data(inode)) { - if (f2fs_convert_inline_inode(inode)) - return; + err = f2fs_convert_inline_inode(inode); + if (err) + return err; } - if (!truncate_blocks(inode, i_size_read(inode), lock)) { - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - mark_inode_dirty(inode); - } + err = truncate_blocks(inode, i_size_read(inode), lock); + if (err) + return err; + + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; } int f2fs_getattr(struct vfsmount *mnt, @@ -656,7 +662,9 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr) if (attr->ia_size <= i_size_read(inode)) { truncate_setsize(inode, attr->ia_size); - f2fs_truncate(inode, true); + err = f2fs_truncate(inode, true); + if (err) + return err; f2fs_balance_fs(F2FS_I_SB(inode)); } else { /* -- GitLab From 127eb7cd3c210afead788991a30950a9e36759ea Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 24 Aug 2015 09:45:41 -0700 Subject: [PATCH 4694/7006] lwt: Add cfg argument to build_state Add cfg and family arguments to lwt build state functions. cfg is a void pointer and will either be a pointer to a fib_config or fib6_config structure. The family parameter indicates which one (either AF_INET or AF_INET6). LWT encpasulation implementation may use the fib configuration to build the LWT state. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/lwtunnel.h | 3 +++ net/core/lwtunnel.c | 5 +++-- net/ipv4/fib_semantics.c | 17 ++++++++++------- net/ipv4/ip_tunnel_core.c | 2 ++ net/ipv6/ila.c | 1 + net/ipv6/route.c | 3 ++- net/mpls/mpls_iptunnel.c | 1 + 7 files changed, 22 insertions(+), 10 deletions(-) diff --git a/include/net/lwtunnel.h b/include/net/lwtunnel.h index 8434898844483..fce0e35e74d07 100644 --- a/include/net/lwtunnel.h +++ b/include/net/lwtunnel.h @@ -26,6 +26,7 @@ struct lwtunnel_state { struct lwtunnel_encap_ops { int (*build_state)(struct net_device *dev, struct nlattr *encap, + unsigned int family, const void *cfg, struct lwtunnel_state **ts); int (*output)(struct sock *sk, struct sk_buff *skb); int (*input)(struct sk_buff *skb); @@ -80,6 +81,7 @@ int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, unsigned int num); int lwtunnel_build_state(struct net_device *dev, u16 encap_type, struct nlattr *encap, + unsigned int family, const void *cfg, struct lwtunnel_state **lws); int lwtunnel_fill_encap(struct sk_buff *skb, struct lwtunnel_state *lwtstate); @@ -130,6 +132,7 @@ static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, struct nlattr *encap, + unsigned int family, const void *cfg, struct lwtunnel_state **lws) { return -EOPNOTSUPP; diff --git a/net/core/lwtunnel.c b/net/core/lwtunnel.c index e924c2e085540..dfb1a9ca08354 100644 --- a/net/core/lwtunnel.c +++ b/net/core/lwtunnel.c @@ -72,7 +72,8 @@ int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *ops, EXPORT_SYMBOL(lwtunnel_encap_del_ops); int lwtunnel_build_state(struct net_device *dev, u16 encap_type, - struct nlattr *encap, struct lwtunnel_state **lws) + struct nlattr *encap, unsigned int family, + const void *cfg, struct lwtunnel_state **lws) { const struct lwtunnel_encap_ops *ops; int ret = -EINVAL; @@ -85,7 +86,7 @@ int lwtunnel_build_state(struct net_device *dev, u16 encap_type, rcu_read_lock(); ops = rcu_dereference(lwtun_encaps[encap_type]); if (likely(ops && ops->build_state)) - ret = ops->build_state(dev, encap, lws); + ret = ops->build_state(dev, encap, family, cfg, lws); rcu_read_unlock(); return ret; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 01f1c7dcd329c..1b2d01170a4de 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -511,7 +511,8 @@ static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, dev = __dev_get_by_index(net, cfg->fc_oif); ret = lwtunnel_build_state(dev, nla_get_u16( nla_entype), - nla, &lwtstate); + nla, AF_INET, cfg, + &lwtstate); if (ret) goto errout; nexthop_nh->nh_lwtstate = @@ -535,7 +536,8 @@ errout: static int fib_encap_match(struct net *net, u16 encap_type, struct nlattr *encap, - int oif, const struct fib_nh *nh) + int oif, const struct fib_nh *nh, + const struct fib_config *cfg) { struct lwtunnel_state *lwtstate; struct net_device *dev = NULL; @@ -546,8 +548,8 @@ static int fib_encap_match(struct net *net, u16 encap_type, if (oif) dev = __dev_get_by_index(net, oif); - ret = lwtunnel_build_state(dev, encap_type, - encap, &lwtstate); + ret = lwtunnel_build_state(dev, encap_type, encap, + AF_INET, cfg, &lwtstate); if (!ret) { result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate); lwtstate_free(lwtstate); @@ -571,7 +573,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) if (cfg->fc_encap) { if (fib_encap_match(net, cfg->fc_encap_type, cfg->fc_encap, cfg->fc_oif, - fi->fib_nh)) + fi->fib_nh, cfg)) return 1; } if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && @@ -663,7 +665,7 @@ int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, struct fib_nh *nh) { - int err; + int err = 0; struct net *net; struct net_device *dev; @@ -1005,7 +1007,8 @@ struct fib_info *fib_create_info(struct fib_config *cfg) if (cfg->fc_oif) dev = __dev_get_by_index(net, cfg->fc_oif); err = lwtunnel_build_state(dev, cfg->fc_encap_type, - cfg->fc_encap, &lwtstate); + cfg->fc_encap, AF_INET, cfg, + &lwtstate); if (err) goto failure; diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 289b6c26ce377..934f2ac8ad610 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -204,6 +204,7 @@ static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = { }; static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr, + unsigned int family, const void *cfg, struct lwtunnel_state **ts) { struct ip_tunnel_info *tun_info; @@ -311,6 +312,7 @@ static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = { }; static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr, + unsigned int family, const void *cfg, struct lwtunnel_state **ts) { struct ip_tunnel_info *tun_info; diff --git a/net/ipv6/ila.c b/net/ipv6/ila.c index f011c3d5ca40c..ffe4dcad6088c 100644 --- a/net/ipv6/ila.c +++ b/net/ipv6/ila.c @@ -123,6 +123,7 @@ static struct nla_policy ila_nl_policy[ILA_ATTR_MAX + 1] = { }; static int ila_build_state(struct net_device *dev, struct nlattr *nla, + unsigned int family, const void *cfg, struct lwtunnel_state **ts) { struct ila_params *p; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index e476f01add87c..df3e353a012d0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1819,7 +1819,8 @@ int ip6_route_add(struct fib6_config *cfg) struct lwtunnel_state *lwtstate; err = lwtunnel_build_state(dev, cfg->fc_encap_type, - cfg->fc_encap, &lwtstate); + cfg->fc_encap, AF_INET6, cfg, + &lwtstate); if (err) goto out; rt->dst.lwtstate = lwtstate_get(lwtstate); diff --git a/net/mpls/mpls_iptunnel.c b/net/mpls/mpls_iptunnel.c index 3da5ca3ba5638..21e70bc9af989 100644 --- a/net/mpls/mpls_iptunnel.c +++ b/net/mpls/mpls_iptunnel.c @@ -123,6 +123,7 @@ drop: } static int mpls_build_state(struct net_device *dev, struct nlattr *nla, + unsigned int family, const void *cfg, struct lwtunnel_state **ts) { struct mpls_iptunnel_encap *tun_encap_info; -- GitLab From 92b78aff855a4815afe5311e3473ec829d3f2a9e Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Mon, 24 Aug 2015 09:45:42 -0700 Subject: [PATCH 4695/7006] ila: Precompute checksum difference for translations In the ILA build state for LWT compute the checksum difference to apply to transport checksums that include the IPv6 pseudo header. The difference is between the route destination (from fib6_config) and the locator to write. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/ipv6/ila.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/net/ipv6/ila.c b/net/ipv6/ila.c index ffe4dcad6088c..678d2df4b8d93 100644 --- a/net/ipv6/ila.c +++ b/net/ipv6/ila.c @@ -14,6 +14,8 @@ struct ila_params { __be64 locator; + __be64 locator_match; + __wsum csum_diff; }; static inline struct ila_params *ila_params_lwtunnel( @@ -33,6 +35,9 @@ static inline __wsum compute_csum_diff8(const __be32 *from, const __be32 *to) static inline __wsum get_csum_diff(struct ipv6hdr *ip6h, struct ila_params *p) { + if (*(__be64 *)&ip6h->daddr == p->locator_match) + return p->csum_diff; + else return compute_csum_diff8((__be32 *)&ip6h->daddr, (__be32 *)&p->locator); } @@ -130,8 +135,12 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla, struct nlattr *tb[ILA_ATTR_MAX + 1]; size_t encap_len = sizeof(*p); struct lwtunnel_state *newts; + const struct fib6_config *cfg6 = cfg; int ret; + if (family != AF_INET6) + return -EINVAL; + ret = nla_parse_nested(tb, ILA_ATTR_MAX, nla, ila_nl_policy); if (ret < 0) @@ -149,6 +158,15 @@ static int ila_build_state(struct net_device *dev, struct nlattr *nla, p->locator = (__force __be64)nla_get_u64(tb[ILA_ATTR_LOCATOR]); + if (cfg6->fc_dst_len > sizeof(__be64)) { + /* Precompute checksum difference for translation since we + * know both the old locator and the new one. + */ + p->locator_match = *(__be64 *)&cfg6->fc_dst; + p->csum_diff = compute_csum_diff8( + (__be32 *)&p->locator_match, (__be32 *)&p->locator); + } + newts->type = LWTUNNEL_ENCAP_ILA; newts->flags |= LWTUNNEL_STATE_OUTPUT_REDIRECT | LWTUNNEL_STATE_INPUT_REDIRECT; -- GitLab From ff89de6ba1d41ad4dea2c59531c5b4038ae43e8c Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Mon, 24 Aug 2015 10:51:04 -0700 Subject: [PATCH 4696/7006] Input: sur40 - fix error return code Propagate error code on failure, or upper layers will be confused by returned 0 (success) code. Signed-off-by: Julia Lawall Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/sur40.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c index 8be7b9b79f20b..3f117637e832d 100644 --- a/drivers/input/touchscreen/sur40.c +++ b/drivers/input/touchscreen/sur40.c @@ -581,6 +581,7 @@ static int sur40_probe(struct usb_interface *interface, sur40->alloc_ctx = vb2_dma_sg_init_ctx(sur40->dev); if (IS_ERR(sur40->alloc_ctx)) { dev_err(sur40->dev, "Can't allocate buffer context"); + error = PTR_ERR(sur40->alloc_ctx); goto err_unreg_v4l2; } -- GitLab From 4ea14a53d8f881034fa9e186653821c4e3d9a8fb Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 24 Aug 2015 10:42:25 -0700 Subject: [PATCH 4697/7006] Input: gpio-keys - report error when disabling unsupported key When trying to disable a key that is not supported by the device we should report error, not do nothing and report success: root@yocto:/sys/devices/soc0/gpio-keys# cat keys 114-116 root@yocto:/sys/devices/soc0/gpio-keys# echo 77 > keys root@yocto:/sys/devices/soc0/gpio-keys# We want 'echo 77 > keys' to report an error, but silence to give us an illusion that all is 'ok'. Signed-off-by: Peng Fan Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 1df4507c4c0b7..9d517ca7eb5aa 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -239,6 +239,11 @@ static ssize_t gpio_keys_attr_store_helper(struct gpio_keys_drvdata *ddata, } } + if (i == ddata->pdata->nbuttons) { + error = -EINVAL; + goto out; + } + mutex_lock(&ddata->disable_lock); for (i = 0; i < ddata->pdata->nbuttons; i++) { -- GitLab From 534fcb3bdaab801636d2146079462f7fdf52be0a Mon Sep 17 00:00:00 2001 From: Michele Curti Date: Mon, 24 Aug 2015 10:49:29 -0700 Subject: [PATCH 4698/7006] Input: elan_i2c - enable ELAN0100 acpi panels Enable ELAN0100 touchpad driver, found on a Asus X205TA laptop, to gai 2,3 fingers tap and 2 fingers scroll. Signed-off-by: Michele Curti Reviewed-by: Duson Lin Signed-off-by: Dmitry Torokhov --- drivers/hid/hid-core.c | 1 + drivers/input/mouse/elan_i2c_core.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 279898c0a1606..3028c1687a517 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2268,6 +2268,7 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) }, { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x000a) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) }, { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index 67388f42ed9a0..bbdaedc09261e 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -98,6 +98,9 @@ static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count, u16 *signature_address) { switch(ic_type) { + case 0x08: + *vaildpage_count = 512; + break; case 0x09: *vaildpage_count = 768; break; @@ -1165,6 +1168,7 @@ MODULE_DEVICE_TABLE(i2c, elan_id); #ifdef CONFIG_ACPI static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0000", 0 }, + { "ELAN0100", 0 }, { "ELAN0600", 0 }, { } }; -- GitLab From 4a89ba04ecc6377696e4e26c1abc1cb5764decb9 Mon Sep 17 00:00:00 2001 From: Loganaden Velvindron Date: Thu, 20 Aug 2015 19:22:18 -0700 Subject: [PATCH 4699/7006] 3c59x: Add BQL support for 3c59x ethernet driver. This BQL patch is based on work done by Tino Reichardt. Tested on 0000:05:00.0: 3Com PCI 3c905C Tornado at ffffc90000e6e000 by running Flent several times. Signed-off-by: Loganaden Velvindron Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/3c59x.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index 753887d02b46a..2839af00f20cd 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -1726,6 +1726,7 @@ vortex_up(struct net_device *dev) if (vp->cb_fn_base) /* The PCMCIA people are idiots. */ iowrite32(0x8000, vp->cb_fn_base + 4); netif_start_queue (dev); + netdev_reset_queue(dev); err_out: return err; } @@ -1935,16 +1936,18 @@ static void vortex_tx_timeout(struct net_device *dev) if (vp->cur_tx - vp->dirty_tx > 0 && ioread32(ioaddr + DownListPtr) == 0) iowrite32(vp->tx_ring_dma + (vp->dirty_tx % TX_RING_SIZE) * sizeof(struct boom_tx_desc), ioaddr + DownListPtr); - if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) + if (vp->cur_tx - vp->dirty_tx < TX_RING_SIZE) { netif_wake_queue (dev); + netdev_reset_queue (dev); + } if (vp->drv_flags & IS_BOOMERANG) iowrite8(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); iowrite16(DownUnstall, ioaddr + EL3_CMD); } else { dev->stats.tx_dropped++; netif_wake_queue(dev); + netdev_reset_queue(dev); } - /* Issue Tx Enable */ iowrite16(TxEnable, ioaddr + EL3_CMD); dev->trans_start = jiffies; /* prevent tx timeout */ @@ -2063,6 +2066,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; + int skblen = skb->len; /* Put out the doubleword header... */ iowrite32(skb->len, ioaddr + TX_FIFO); @@ -2094,6 +2098,7 @@ vortex_start_xmit(struct sk_buff *skb, struct net_device *dev) } } + netdev_sent_queue(dev, skblen); /* Clear the Tx status stack. */ { @@ -2125,6 +2130,7 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) void __iomem *ioaddr = vp->ioaddr; /* Calculate the next Tx descriptor entry. */ int entry = vp->cur_tx % TX_RING_SIZE; + int skblen = skb->len; struct boom_tx_desc *prev_entry = &vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE]; unsigned long flags; dma_addr_t dma_addr; @@ -2230,6 +2236,8 @@ boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev) } vp->cur_tx++; + netdev_sent_queue(dev, skblen); + if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1) { netif_stop_queue (dev); } else { /* Clear previous interrupt enable. */ @@ -2267,6 +2275,7 @@ vortex_interrupt(int irq, void *dev_id) int status; int work_done = max_interrupt_work; int handled = 0; + unsigned int bytes_compl = 0, pkts_compl = 0; ioaddr = vp->ioaddr; spin_lock(&vp->lock); @@ -2314,6 +2323,8 @@ vortex_interrupt(int irq, void *dev_id) if (ioread16(ioaddr + Wn7_MasterStatus) & 0x1000) { iowrite16(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */ pci_unmap_single(VORTEX_PCI(vp), vp->tx_skb_dma, (vp->tx_skb->len + 3) & ~3, PCI_DMA_TODEVICE); + pkts_compl++; + bytes_compl += vp->tx_skb->len; dev_kfree_skb_irq(vp->tx_skb); /* Release the transferred buffer */ if (ioread16(ioaddr + TxFree) > 1536) { /* @@ -2358,6 +2369,7 @@ vortex_interrupt(int irq, void *dev_id) iowrite16(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD); } while ((status = ioread16(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete)); + netdev_completed_queue(dev, pkts_compl, bytes_compl); spin_unlock(&vp->window_lock); if (vortex_debug > 4) @@ -2382,6 +2394,7 @@ boomerang_interrupt(int irq, void *dev_id) int status; int work_done = max_interrupt_work; int handled = 0; + unsigned int bytes_compl = 0, pkts_compl = 0; ioaddr = vp->ioaddr; @@ -2455,6 +2468,8 @@ boomerang_interrupt(int irq, void *dev_id) pci_unmap_single(VORTEX_PCI(vp), le32_to_cpu(vp->tx_ring[entry].addr), skb->len, PCI_DMA_TODEVICE); #endif + pkts_compl++; + bytes_compl += skb->len; dev_kfree_skb_irq(skb); vp->tx_skbuff[entry] = NULL; } else { @@ -2495,6 +2510,7 @@ boomerang_interrupt(int irq, void *dev_id) iowrite32(0x8000, vp->cb_fn_base + 4); } while ((status = ioread16(ioaddr + EL3_STATUS)) & IntLatch); + netdev_completed_queue(dev, pkts_compl, bytes_compl); if (vortex_debug > 4) pr_debug("%s: exiting interrupt, status %4.4x.\n", @@ -2696,7 +2712,8 @@ vortex_down(struct net_device *dev, int final_down) struct vortex_private *vp = netdev_priv(dev); void __iomem *ioaddr = vp->ioaddr; - netif_stop_queue (dev); + netdev_reset_queue(dev); + netif_stop_queue(dev); del_timer_sync(&vp->rx_oom_timer); del_timer_sync(&vp->timer); -- GitLab From f8bcbe62acd0e1ce9004b83e98a4af87ae385dcf Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sat, 8 Aug 2015 10:44:10 +0200 Subject: [PATCH 4700/7006] lib: scatterlist: add sg splitting function Sometimes a scatter-gather has to be split into several chunks, or sub scatter lists. This happens for example if a scatter list will be handled by multiple DMA channels, each one filling a part of it. A concrete example comes with the media V4L2 API, where the scatter list is allocated from userspace to hold an image, regardless of the knowledge of how many DMAs will fill it : - in a simple RGB565 case, one DMA will pump data from the camera ISP to memory - in the trickier YUV422 case, 3 DMAs will pump data from the camera ISP pipes, one for pipe Y, one for pipe U and one for pipe V For these cases, it is necessary to split the original scatter list into multiple scatter lists, which is the purpose of this patch. The guarantees that are required for this patch are : - the intersection of spans of any couple of resulting scatter lists is empty. - the union of spans of all resulting scatter lists is a subrange of the span of the original scatter list. - streaming DMA API operations (mapping, unmapping) should not happen both on both the resulting and the original scatter list. It's either the first or the later ones. - the caller is reponsible to call kfree() on the resulting scatterlists. Signed-off-by: Robert Jarzmik Signed-off-by: Jens Axboe --- include/linux/scatterlist.h | 5 + lib/Kconfig | 7 ++ lib/Makefile | 1 + lib/sg_split.c | 202 ++++++++++++++++++++++++++++++++++++ 4 files changed, 215 insertions(+) create mode 100644 lib/sg_split.c diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 698e906ca7307..556ec1ea25746 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -247,6 +247,11 @@ struct scatterlist *sg_next(struct scatterlist *); struct scatterlist *sg_last(struct scatterlist *s, unsigned int); void sg_init_table(struct scatterlist *, unsigned int); void sg_init_one(struct scatterlist *, const void *, unsigned int); +int sg_split(struct scatterlist *in, const int in_mapped_nents, + const off_t skip, const int nb_splits, + const size_t *split_sizes, + struct scatterlist **out, int *out_mapped_nents, + gfp_t gfp_mask); typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t); typedef void (sg_free_fn)(struct scatterlist *, unsigned int); diff --git a/lib/Kconfig b/lib/Kconfig index 3a2ef67db6c72..dc516164415a0 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -521,6 +521,13 @@ config UCS2_STRING source "lib/fonts/Kconfig" +config SG_SPLIT + def_bool n + help + Provides a heler to split scatterlists into chunks, each chunk being a + scatterlist. This should be selected by a driver or an API which + whishes to split a scatterlist amongst multiple DMA channel. + # # sg chaining option # diff --git a/lib/Makefile b/lib/Makefile index 6897b527581a8..2ee6ea2e9b08b 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -160,6 +160,7 @@ obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o obj-$(CONFIG_GENERIC_NET_UTILS) += net_utils.o +obj-$(CONFIG_SG_SPLIT) += sg_split.o obj-$(CONFIG_STMP_DEVICE) += stmp_device.o libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \ diff --git a/lib/sg_split.c b/lib/sg_split.c new file mode 100644 index 0000000000000..b063410c3593e --- /dev/null +++ b/lib/sg_split.c @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2015 Robert Jarzmik + * + * Scatterlist splitting helpers. + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include + +struct sg_splitter { + struct scatterlist *in_sg0; + int nents; + off_t skip_sg0; + unsigned int length_last_sg; + + struct scatterlist *out_sg; +}; + +static int sg_calculate_split(struct scatterlist *in, int nents, int nb_splits, + off_t skip, const size_t *sizes, + struct sg_splitter *splitters, bool mapped) +{ + int i; + unsigned int sglen; + size_t size = sizes[0], len; + struct sg_splitter *curr = splitters; + struct scatterlist *sg; + + for (i = 0; i < nb_splits; i++) { + splitters[i].in_sg0 = NULL; + splitters[i].nents = 0; + } + + for_each_sg(in, sg, nents, i) { + sglen = mapped ? sg_dma_len(sg) : sg->length; + if (skip > sglen) { + skip -= sglen; + continue; + } + + len = min_t(size_t, size, sglen - skip); + if (!curr->in_sg0) { + curr->in_sg0 = sg; + curr->skip_sg0 = skip; + } + size -= len; + curr->nents++; + curr->length_last_sg = len; + + while (!size && (skip + len < sglen) && (--nb_splits > 0)) { + curr++; + size = *(++sizes); + skip += len; + len = min_t(size_t, size, sglen - skip); + + curr->in_sg0 = sg; + curr->skip_sg0 = skip; + curr->nents = 1; + curr->length_last_sg = len; + size -= len; + } + skip = 0; + + if (!size && --nb_splits > 0) { + curr++; + size = *(++sizes); + } + + if (!nb_splits) + break; + } + + return (size || !splitters[0].in_sg0) ? -EINVAL : 0; +} + +static void sg_split_phys(struct sg_splitter *splitters, const int nb_splits) +{ + int i, j; + struct scatterlist *in_sg, *out_sg; + struct sg_splitter *split; + + for (i = 0, split = splitters; i < nb_splits; i++, split++) { + in_sg = split->in_sg0; + out_sg = split->out_sg; + for (j = 0; j < split->nents; j++, out_sg++) { + *out_sg = *in_sg; + if (!j) { + out_sg->offset += split->skip_sg0; + out_sg->length -= split->skip_sg0; + } else { + out_sg->offset = 0; + } + sg_dma_address(out_sg) = 0; + sg_dma_len(out_sg) = 0; + in_sg = sg_next(in_sg); + } + out_sg[-1].length = split->length_last_sg; + sg_mark_end(out_sg - 1); + } +} + +static void sg_split_mapped(struct sg_splitter *splitters, const int nb_splits) +{ + int i, j; + struct scatterlist *in_sg, *out_sg; + struct sg_splitter *split; + + for (i = 0, split = splitters; i < nb_splits; i++, split++) { + in_sg = split->in_sg0; + out_sg = split->out_sg; + for (j = 0; j < split->nents; j++, out_sg++) { + sg_dma_address(out_sg) = sg_dma_address(in_sg); + sg_dma_len(out_sg) = sg_dma_len(in_sg); + if (!j) { + sg_dma_address(out_sg) += split->skip_sg0; + sg_dma_len(out_sg) -= split->skip_sg0; + } + in_sg = sg_next(in_sg); + } + sg_dma_len(--out_sg) = split->length_last_sg; + } +} + +/** + * sg_split - split a scatterlist into several scatterlists + * @in: the input sg list + * @in_mapped_nents: the result of a dma_map_sg(in, ...), or 0 if not mapped. + * @skip: the number of bytes to skip in the input sg list + * @nb_splits: the number of desired sg outputs + * @split_sizes: the respective size of each output sg list in bytes + * @out: an array where to store the allocated output sg lists + * @out_mapped_nents: the resulting sg lists mapped number of sg entries. Might + * be NULL if sglist not already mapped (in_mapped_nents = 0) + * @gfp_mask: the allocation flag + * + * This function splits the input sg list into nb_splits sg lists, which are + * allocated and stored into out. + * The @in is split into : + * - @out[0], which covers bytes [@skip .. @skip + @split_sizes[0] - 1] of @in + * - @out[1], which covers bytes [@skip + split_sizes[0] .. + * @skip + @split_sizes[0] + @split_sizes[1] -1] + * etc ... + * It will be the caller's duty to kfree() out array members. + * + * Returns 0 upon success, or error code + */ +int sg_split(struct scatterlist *in, const int in_mapped_nents, + const off_t skip, const int nb_splits, + const size_t *split_sizes, + struct scatterlist **out, int *out_mapped_nents, + gfp_t gfp_mask) +{ + int i, ret; + struct sg_splitter *splitters; + + splitters = kcalloc(nb_splits, sizeof(*splitters), gfp_mask); + if (!splitters) + return -ENOMEM; + + ret = sg_calculate_split(in, sg_nents(in), nb_splits, skip, split_sizes, + splitters, false); + if (ret < 0) + goto err; + + ret = -ENOMEM; + for (i = 0; i < nb_splits; i++) { + splitters[i].out_sg = kmalloc_array(splitters[i].nents, + sizeof(struct scatterlist), + gfp_mask); + if (!splitters[i].out_sg) + goto err; + } + + /* + * The order of these 3 calls is important and should be kept. + */ + sg_split_phys(splitters, nb_splits); + ret = sg_calculate_split(in, in_mapped_nents, nb_splits, skip, + split_sizes, splitters, true); + if (ret < 0) + goto err; + sg_split_mapped(splitters, nb_splits); + + for (i = 0; i < nb_splits; i++) { + out[i] = splitters[i].out_sg; + if (out_mapped_nents) + out_mapped_nents[i] = splitters[i].nents; + } + + kfree(splitters); + return 0; + +err: + for (i = 0; i < nb_splits; i++) + kfree(splitters[i].out_sg); + kfree(splitters); + return ret; +} +EXPORT_SYMBOL(sg_split); -- GitLab From 658d439b22924796d00f03282135a356f47cc64e Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:17 +0900 Subject: [PATCH 4701/7006] fjes: Introduce FUJITSU Extended Socket Network Device driver This patch adds the basic code of FUJITSU Extended Socket Network Device driver. When "PNP0C02" is found in ACPI DSDT, it evaluates "_STR" to check if "PNP0C02" is for Extended Socket device driver and retrieves ACPI resource information. Then creates platform_device. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/Kconfig | 7 ++ drivers/net/Makefile | 2 + drivers/net/fjes/Makefile | 30 +++++ drivers/net/fjes/fjes.h | 32 ++++++ drivers/net/fjes/fjes_main.c | 213 +++++++++++++++++++++++++++++++++++ 5 files changed, 284 insertions(+) create mode 100644 drivers/net/fjes/Makefile create mode 100644 drivers/net/fjes/fjes.h create mode 100644 drivers/net/fjes/fjes_main.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index f50373645ab4a..770483b31d624 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -413,6 +413,13 @@ config VMXNET3 To compile this driver as a module, choose M here: the module will be called vmxnet3. +config FUJITSU_ES + tristate "FUJITSU Extended Socket Network Device driver" + depends on ACPI + help + This driver provides support for Extended Socket network device + on Extended Partitioning of FUJITSU PRIMEQUEST 2000 E2 series. + source "drivers/net/hyperv/Kconfig" endif # NETDEVICES diff --git a/drivers/net/Makefile b/drivers/net/Makefile index ca16dd689b36b..900b0c5320bb9 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -68,3 +68,5 @@ obj-$(CONFIG_USB_NET_DRIVERS) += usb/ obj-$(CONFIG_HYPERV_NET) += hyperv/ obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o + +obj-$(CONFIG_FUJITSU_ES) += fjes/ diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile new file mode 100644 index 0000000000000..34bccbafa6572 --- /dev/null +++ b/drivers/net/fjes/Makefile @@ -0,0 +1,30 @@ +################################################################################ +# +# FUJITSU Extended Socket Network Device driver +# Copyright (c) 2015 FUJITSU LIMITED +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# The full GNU General Public License is included in this distribution in +# the file called "COPYING". +# +################################################################################ + + +# +# Makefile for the FUJITSU Extended Socket network device driver +# + +obj-$(CONFIG_FUJITSU_ES) += fjes.o + +fjes-objs := fjes_main.o diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h new file mode 100644 index 0000000000000..52eb60b650574 --- /dev/null +++ b/drivers/net/fjes/fjes.h @@ -0,0 +1,32 @@ +/* + * FUJITSU Extended Socket Network Device driver + * Copyright (c) 2015 FUJITSU LIMITED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#ifndef FJES_H_ +#define FJES_H_ + +#include + +#define FJES_ACPI_SYMBOL "Extended Socket" + +extern char fjes_driver_name[]; +extern char fjes_driver_version[]; + +#endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c new file mode 100644 index 0000000000000..95176667131eb --- /dev/null +++ b/drivers/net/fjes/fjes_main.c @@ -0,0 +1,213 @@ +/* + * FUJITSU Extended Socket Network Device driver + * Copyright (c) 2015 FUJITSU LIMITED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#include +#include +#include +#include + +#include "fjes.h" + +#define MAJ 1 +#define MIN 0 +#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) +#define DRV_NAME "fjes" +char fjes_driver_name[] = DRV_NAME; +char fjes_driver_version[] = DRV_VERSION; +static const char fjes_driver_string[] = + "FUJITSU Extended Socket Network Device Driver"; +static const char fjes_copyright[] = + "Copyright (c) 2015 FUJITSU LIMITED"; + +MODULE_AUTHOR("Taku Izumi "); +MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +static int fjes_acpi_add(struct acpi_device *); +static int fjes_acpi_remove(struct acpi_device *); +static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); + +static int fjes_probe(struct platform_device *); +static int fjes_remove(struct platform_device *); + +static const struct acpi_device_id fjes_acpi_ids[] = { + {"PNP0C02", 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, fjes_acpi_ids); + +static struct acpi_driver fjes_acpi_driver = { + .name = DRV_NAME, + .class = DRV_NAME, + .owner = THIS_MODULE, + .ids = fjes_acpi_ids, + .ops = { + .add = fjes_acpi_add, + .remove = fjes_acpi_remove, + }, +}; + +static struct platform_driver fjes_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + .probe = fjes_probe, + .remove = fjes_remove, +}; + +static struct resource fjes_resource[] = { + { + .flags = IORESOURCE_MEM, + .start = 0, + .end = 0, + }, + { + .flags = IORESOURCE_IRQ, + .start = 0, + .end = 0, + }, +}; + +static int fjes_acpi_add(struct acpi_device *device) +{ + struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL}; + char str_buf[sizeof(FJES_ACPI_SYMBOL) + 1]; + struct platform_device *plat_dev; + union acpi_object *str; + acpi_status status; + int result; + + status = acpi_evaluate_object(device->handle, "_STR", NULL, &buffer); + if (ACPI_FAILURE(status)) + return -ENODEV; + + str = buffer.pointer; + result = utf16s_to_utf8s((wchar_t *)str->string.pointer, + str->string.length, UTF16_LITTLE_ENDIAN, + str_buf, sizeof(str_buf) - 1); + str_buf[result] = 0; + + if (strncmp(FJES_ACPI_SYMBOL, str_buf, strlen(FJES_ACPI_SYMBOL)) != 0) { + kfree(buffer.pointer); + return -ENODEV; + } + kfree(buffer.pointer); + + status = acpi_walk_resources(device->handle, METHOD_NAME__CRS, + fjes_get_acpi_resource, fjes_resource); + if (ACPI_FAILURE(status)) + return -ENODEV; + + /* create platform_device */ + plat_dev = platform_device_register_simple(DRV_NAME, 0, fjes_resource, + ARRAY_SIZE(fjes_resource)); + device->driver_data = plat_dev; + + return 0; +} + +static int fjes_acpi_remove(struct acpi_device *device) +{ + struct platform_device *plat_dev; + + plat_dev = (struct platform_device *)acpi_driver_data(device); + platform_device_unregister(plat_dev); + + return 0; +} + +static acpi_status +fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) +{ + struct acpi_resource_address32 *addr; + struct acpi_resource_irq *irq; + struct resource *res = data; + + switch (acpi_res->type) { + case ACPI_RESOURCE_TYPE_ADDRESS32: + addr = &acpi_res->data.address32; + res[0].start = addr->address.minimum; + res[0].end = addr->address.minimum + + addr->address.address_length - 1; + break; + + case ACPI_RESOURCE_TYPE_IRQ: + irq = &acpi_res->data.irq; + if (irq->interrupt_count != 1) + return AE_ERROR; + res[1].start = irq->interrupts[0]; + res[1].end = irq->interrupts[0]; + break; + + default: + break; + } + + return AE_OK; +} + +/* fjes_probe - Device Initialization Routine */ +static int fjes_probe(struct platform_device *plat_dev) +{ + return 0; +} + +/* fjes_remove - Device Removal Routine */ +static int fjes_remove(struct platform_device *plat_dev) +{ + return 0; +} + +/* fjes_init_module - Driver Registration Routine */ +static int __init fjes_init_module(void) +{ + int result; + + pr_info("%s - version %s - %s\n", + fjes_driver_string, fjes_driver_version, fjes_copyright); + + result = platform_driver_register(&fjes_driver); + if (result < 0) + return result; + + result = acpi_bus_register_driver(&fjes_acpi_driver); + if (result < 0) + goto fail_acpi_driver; + + return 0; + +fail_acpi_driver: + platform_driver_unregister(&fjes_driver); + return result; +} + +module_init(fjes_init_module); + +/* fjes_exit_module - Driver Exit Cleanup Routine */ +static void __exit fjes_exit_module(void) +{ + acpi_bus_unregister_driver(&fjes_acpi_driver); + platform_driver_unregister(&fjes_driver); +} + +module_exit(fjes_exit_module); -- GitLab From 8cdc3f6c5d22dd059fe8127be7b5cae113e79afb Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:18 +0900 Subject: [PATCH 4702/7006] fjes: Hardware initialization routine This patch adds hardware initialization routine to be invoked at driver's .probe routine. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/Makefile | 2 +- drivers/net/fjes/fjes.h | 1 + drivers/net/fjes/fjes_hw.c | 295 +++++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 251 +++++++++++++++++++++++++++++ drivers/net/fjes/fjes_regs.h | 102 ++++++++++++ 5 files changed, 650 insertions(+), 1 deletion(-) create mode 100644 drivers/net/fjes/fjes_hw.c create mode 100644 drivers/net/fjes/fjes_hw.h create mode 100644 drivers/net/fjes/fjes_regs.h diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile index 34bccbafa6572..753d52f1be332 100644 --- a/drivers/net/fjes/Makefile +++ b/drivers/net/fjes/Makefile @@ -27,4 +27,4 @@ obj-$(CONFIG_FUJITSU_ES) += fjes.o -fjes-objs := fjes_main.o +fjes-objs := fjes_main.o fjes_hw.o diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 52eb60b650574..15ded96421012 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -28,5 +28,6 @@ extern char fjes_driver_name[]; extern char fjes_driver_version[]; +extern const u32 fjes_support_mtu[]; #endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c new file mode 100644 index 0000000000000..ae2663876605e --- /dev/null +++ b/drivers/net/fjes/fjes_hw.c @@ -0,0 +1,295 @@ +/* + * FUJITSU Extended Socket Network Device driver + * Copyright (c) 2015 FUJITSU LIMITED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#include "fjes_hw.h" +#include "fjes.h" + +/* supported MTU list */ +const u32 fjes_support_mtu[] = { + FJES_MTU_DEFINE(8 * 1024), + FJES_MTU_DEFINE(16 * 1024), + FJES_MTU_DEFINE(32 * 1024), + FJES_MTU_DEFINE(64 * 1024), + 0 +}; + +u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg) +{ + u8 *base = hw->base; + u32 value = 0; + + value = readl(&base[reg]); + + return value; +} + +static u8 *fjes_hw_iomap(struct fjes_hw *hw) +{ + u8 *base; + + if (!request_mem_region(hw->hw_res.start, hw->hw_res.size, + fjes_driver_name)) { + pr_err("request_mem_region failed\n"); + return NULL; + } + + base = (u8 *)ioremap_nocache(hw->hw_res.start, hw->hw_res.size); + + return base; +} + +int fjes_hw_reset(struct fjes_hw *hw) +{ + union REG_DCTL dctl; + int timeout; + + dctl.reg = 0; + dctl.bits.reset = 1; + wr32(XSCT_DCTL, dctl.reg); + + timeout = FJES_DEVICE_RESET_TIMEOUT * 1000; + dctl.reg = rd32(XSCT_DCTL); + while ((dctl.bits.reset == 1) && (timeout > 0)) { + msleep(1000); + dctl.reg = rd32(XSCT_DCTL); + timeout -= 1000; + } + + return timeout > 0 ? 0 : -EIO; +} + +static int fjes_hw_get_max_epid(struct fjes_hw *hw) +{ + union REG_MAX_EP info; + + info.reg = rd32(XSCT_MAX_EP); + + return info.bits.maxep; +} + +static int fjes_hw_get_my_epid(struct fjes_hw *hw) +{ + union REG_OWNER_EPID info; + + info.reg = rd32(XSCT_OWNER_EPID); + + return info.bits.epid; +} + +static int fjes_hw_alloc_shared_status_region(struct fjes_hw *hw) +{ + size_t size; + + size = sizeof(struct fjes_device_shared_info) + + (sizeof(u8) * hw->max_epid); + hw->hw_info.share = kzalloc(size, GFP_KERNEL); + if (!hw->hw_info.share) + return -ENOMEM; + + hw->hw_info.share->epnum = hw->max_epid; + + return 0; +} + +static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh) +{ + void *mem; + + mem = vzalloc(EP_BUFFER_SIZE); + if (!mem) + return -ENOMEM; + + epbh->buffer = mem; + epbh->size = EP_BUFFER_SIZE; + + epbh->info = (union ep_buffer_info *)mem; + epbh->ring = (u8 *)(mem + sizeof(union ep_buffer_info)); + + return 0; +} + +void fjes_hw_setup_epbuf(struct epbuf_handler *epbh, u8 *mac_addr, u32 mtu) +{ + union ep_buffer_info *info = epbh->info; + u16 vlan_id[EP_BUFFER_SUPPORT_VLAN_MAX]; + int i; + + for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) + vlan_id[i] = info->v1i.vlan_id[i]; + + memset(info, 0, sizeof(union ep_buffer_info)); + + info->v1i.version = 0; /* version 0 */ + + for (i = 0; i < ETH_ALEN; i++) + info->v1i.mac_addr[i] = mac_addr[i]; + + info->v1i.head = 0; + info->v1i.tail = 1; + + info->v1i.info_size = sizeof(union ep_buffer_info); + info->v1i.buffer_size = epbh->size - info->v1i.info_size; + + info->v1i.frame_max = FJES_MTU_TO_FRAME_SIZE(mtu); + info->v1i.count_max = + EP_RING_NUM(info->v1i.buffer_size, info->v1i.frame_max); + + for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) + info->v1i.vlan_id[i] = vlan_id[i]; +} + +void +fjes_hw_init_command_registers(struct fjes_hw *hw, + struct fjes_device_command_param *param) +{ + /* Request Buffer length */ + wr32(XSCT_REQBL, (__le32)(param->req_len)); + /* Response Buffer Length */ + wr32(XSCT_RESPBL, (__le32)(param->res_len)); + + /* Request Buffer Address */ + wr32(XSCT_REQBAL, + (__le32)(param->req_start & GENMASK_ULL(31, 0))); + wr32(XSCT_REQBAH, + (__le32)((param->req_start & GENMASK_ULL(63, 32)) >> 32)); + + /* Response Buffer Address */ + wr32(XSCT_RESPBAL, + (__le32)(param->res_start & GENMASK_ULL(31, 0))); + wr32(XSCT_RESPBAH, + (__le32)((param->res_start & GENMASK_ULL(63, 32)) >> 32)); + + /* Share status address */ + wr32(XSCT_SHSTSAL, + (__le32)(param->share_start & GENMASK_ULL(31, 0))); + wr32(XSCT_SHSTSAH, + (__le32)((param->share_start & GENMASK_ULL(63, 32)) >> 32)); +} + +static int fjes_hw_setup(struct fjes_hw *hw) +{ + u8 mac[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + struct fjes_device_command_param param; + struct ep_share_mem_info *buf_pair; + size_t mem_size; + int result; + int epidx; + void *buf; + + hw->hw_info.max_epid = &hw->max_epid; + hw->hw_info.my_epid = &hw->my_epid; + + buf = kcalloc(hw->max_epid, sizeof(struct ep_share_mem_info), + GFP_KERNEL); + if (!buf) + return -ENOMEM; + + hw->ep_shm_info = (struct ep_share_mem_info *)buf; + + mem_size = FJES_DEV_REQ_BUF_SIZE(hw->max_epid); + hw->hw_info.req_buf = kzalloc(mem_size, GFP_KERNEL); + if (!(hw->hw_info.req_buf)) + return -ENOMEM; + + hw->hw_info.req_buf_size = mem_size; + + mem_size = FJES_DEV_RES_BUF_SIZE(hw->max_epid); + hw->hw_info.res_buf = kzalloc(mem_size, GFP_KERNEL); + if (!(hw->hw_info.res_buf)) + return -ENOMEM; + + hw->hw_info.res_buf_size = mem_size; + + result = fjes_hw_alloc_shared_status_region(hw); + if (result) + return result; + + hw->hw_info.buffer_share_bit = 0; + hw->hw_info.buffer_unshare_reserve_bit = 0; + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx != hw->my_epid) { + buf_pair = &hw->ep_shm_info[epidx]; + + result = fjes_hw_alloc_epbuf(&buf_pair->tx); + if (result) + return result; + + result = fjes_hw_alloc_epbuf(&buf_pair->rx); + if (result) + return result; + + fjes_hw_setup_epbuf(&buf_pair->tx, mac, + fjes_support_mtu[0]); + fjes_hw_setup_epbuf(&buf_pair->rx, mac, + fjes_support_mtu[0]); + } + } + + memset(¶m, 0, sizeof(param)); + + param.req_len = hw->hw_info.req_buf_size; + param.req_start = __pa(hw->hw_info.req_buf); + param.res_len = hw->hw_info.res_buf_size; + param.res_start = __pa(hw->hw_info.res_buf); + + param.share_start = __pa(hw->hw_info.share->ep_status); + + fjes_hw_init_command_registers(hw, ¶m); + + return 0; +} + +int fjes_hw_init(struct fjes_hw *hw) +{ + int ret; + + hw->base = fjes_hw_iomap(hw); + if (!hw->base) + return -EIO; + + ret = fjes_hw_reset(hw); + if (ret) + return ret; + + fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); + + mutex_init(&hw->hw_info.lock); + + hw->max_epid = fjes_hw_get_max_epid(hw); + hw->my_epid = fjes_hw_get_my_epid(hw); + + if ((hw->max_epid == 0) || (hw->my_epid >= hw->max_epid)) + return -ENXIO; + + ret = fjes_hw_setup(hw); + + return ret; +} + +void fjes_hw_set_irqmask(struct fjes_hw *hw, + enum REG_ICTL_MASK intr_mask, bool mask) +{ + if (mask) + wr32(XSCT_IMS, intr_mask); + else + wr32(XSCT_IMC, intr_mask); +} diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h new file mode 100644 index 0000000000000..836ebe28793cb --- /dev/null +++ b/drivers/net/fjes/fjes_hw.h @@ -0,0 +1,251 @@ +/* + * FUJITSU Extended Socket Network Device driver + * Copyright (c) 2015 FUJITSU LIMITED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#ifndef FJES_HW_H_ +#define FJES_HW_H_ + +#include +#include +#include + +#include "fjes_regs.h" + +struct fjes_hw; + +#define EP_BUFFER_SUPPORT_VLAN_MAX 4 +#define EP_BUFFER_INFO_SIZE 4096 + +#define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */ + +#define EP_BUFFER_SIZE \ + (((sizeof(union ep_buffer_info) + (128 * (64 * 1024))) \ + / EP_BUFFER_INFO_SIZE) * EP_BUFFER_INFO_SIZE) + +#define EP_RING_NUM(buffer_size, frame_size) \ + (u32)((buffer_size) / (frame_size)) + +#define FJES_MTU_TO_BUFFER_SIZE(mtu) \ + (ETH_HLEN + VLAN_HLEN + (mtu) + ETH_FCS_LEN) +#define FJES_MTU_TO_FRAME_SIZE(mtu) \ + (sizeof(struct esmem_frame) + FJES_MTU_TO_BUFFER_SIZE(mtu)) +#define FJES_MTU_DEFINE(size) \ + ((size) - sizeof(struct esmem_frame) - \ + (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)) + +#define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum)) +#define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \ + (24 + (8 * ((txb) / EP_BUFFER_INFO_SIZE + (rxb) / EP_BUFFER_INFO_SIZE))) + +#define FJES_DEV_REQ_BUF_SIZE(maxep) \ + FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(EP_BUFFER_SIZE, EP_BUFFER_SIZE) +#define FJES_DEV_RES_BUF_SIZE(maxep) \ + FJES_DEV_COMMAND_INFO_RES_LEN(maxep) + +/* Frame & MTU */ +struct esmem_frame { + __le32 frame_size; + u8 frame_data[]; +}; + +/* shared status region */ +struct fjes_device_shared_info { + int epnum; + u8 ep_status[]; +}; + +/* structures for command control request data*/ +union fjes_device_command_req { + struct { + __le32 length; + } info; + struct { + __le32 length; + __le32 epid; + __le64 buffer[]; + } share_buffer; + struct { + __le32 length; + __le32 epid; + } unshare_buffer; + struct { + __le32 length; + __le32 mode; + __le64 buffer_len; + __le64 buffer[]; + } start_trace; + struct { + __le32 length; + } stop_trace; +}; + +/* structures for command control response data */ +union fjes_device_command_res { + struct { + __le32 length; + __le32 code; + struct { + u8 es_status; + u8 zone; + } info[]; + } info; + struct { + __le32 length; + __le32 code; + } share_buffer; + struct { + __le32 length; + __le32 code; + } unshare_buffer; + struct { + __le32 length; + __le32 code; + } start_trace; + struct { + __le32 length; + __le32 code; + } stop_trace; +}; + +/* parameter for command control */ +struct fjes_device_command_param { + u32 req_len; + phys_addr_t req_start; + u32 res_len; + phys_addr_t res_start; + phys_addr_t share_start; +}; + +/* EP buffer information */ +union ep_buffer_info { + u8 raw[EP_BUFFER_INFO_SIZE]; + + struct _ep_buffer_info_common_t { + u32 version; + } common; + + struct _ep_buffer_info_v1_t { + u32 version; + u32 info_size; + + u32 buffer_size; + u16 count_max; + + u16 _rsv_1; + + u32 frame_max; + u8 mac_addr[ETH_ALEN]; + + u16 _rsv_2; + u32 _rsv_3; + + u16 tx_status; + u16 rx_status; + + u32 head; + u32 tail; + + u16 vlan_id[EP_BUFFER_SUPPORT_VLAN_MAX]; + + } v1i; + +}; + +/* buffer pair for Extended Partition */ +struct ep_share_mem_info { + struct epbuf_handler { + void *buffer; + size_t size; + union ep_buffer_info *info; + u8 *ring; + } tx, rx; + + struct rtnl_link_stats64 net_stats; + + u16 tx_status_work; + + u8 es_status; + u8 zone; +}; + +struct es_device_trace { + u32 record_num; + u32 current_record; + u32 status_flag; + u32 _rsv; + + struct { + u16 epid; + u16 dir_offset; + u32 data; + u64 tsc; + } record[]; +}; + +struct fjes_hw_info { + struct fjes_device_shared_info *share; + union fjes_device_command_req *req_buf; + u64 req_buf_size; + union fjes_device_command_res *res_buf; + u64 res_buf_size; + + int *my_epid; + int *max_epid; + + struct es_device_trace *trace; + u64 trace_size; + + struct mutex lock; /* buffer lock*/ + + unsigned long buffer_share_bit; + unsigned long buffer_unshare_reserve_bit; +}; + +struct fjes_hw { + void *back; + + unsigned long txrx_stop_req_bit; + unsigned long epstop_req_bit; + + int my_epid; + int max_epid; + + struct ep_share_mem_info *ep_shm_info; + + struct fjes_hw_resource { + u64 start; + u64 size; + int irq; + } hw_res; + + u8 *base; + + struct fjes_hw_info hw_info; +}; + +int fjes_hw_init(struct fjes_hw *); +int fjes_hw_reset(struct fjes_hw *); + +void fjes_hw_init_command_registers(struct fjes_hw *, + struct fjes_device_command_param *); +void fjes_hw_setup_epbuf(struct epbuf_handler *, u8 *, u32); +void fjes_hw_set_irqmask(struct fjes_hw *, enum REG_ICTL_MASK, bool); + +#endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h new file mode 100644 index 0000000000000..4d0e0719645ef --- /dev/null +++ b/drivers/net/fjes/fjes_regs.h @@ -0,0 +1,102 @@ +/* + * FUJITSU Extended Socket Network Device driver + * Copyright (c) 2015 FUJITSU LIMITED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +#ifndef FJES_REGS_H_ +#define FJES_REGS_H_ + +#include + +#define XSCT_DEVICE_REGISTER_SIZE 0x1000 + +/* register offset */ +/* Information registers */ +#define XSCT_OWNER_EPID 0x0000 /* Owner EPID */ +#define XSCT_MAX_EP 0x0004 /* Maximum EP */ + +/* Device Control registers */ +#define XSCT_DCTL 0x0010 /* Device Control */ + +/* Command Control registers */ +#define XSCT_SHSTSAL 0x0028 /* Share status address Low */ +#define XSCT_SHSTSAH 0x002C /* Share status address High */ + +#define XSCT_REQBL 0x0034 /* Request Buffer length */ +#define XSCT_REQBAL 0x0038 /* Request Buffer Address Low */ +#define XSCT_REQBAH 0x003C /* Request Buffer Address High */ + +#define XSCT_RESPBL 0x0044 /* Response Buffer Length */ +#define XSCT_RESPBAL 0x0048 /* Response Buffer Address Low */ +#define XSCT_RESPBAH 0x004C /* Response Buffer Address High */ + +/* Interrupt Control registers */ +#define XSCT_IMS 0x0084 /* Interrupt mask set */ +#define XSCT_IMC 0x0088 /* Interrupt mask clear */ + +/* register structure */ +/* Information registers */ +union REG_OWNER_EPID { + struct { + __le32 epid:16; + __le32:16; + } bits; + __le32 reg; +}; + +union REG_MAX_EP { + struct { + __le32 maxep:16; + __le32:16; + } bits; + __le32 reg; +}; + +/* Device Control registers */ +union REG_DCTL { + struct { + __le32 reset:1; + __le32 rsv0:15; + __le32 rsv1:16; + } bits; + __le32 reg; +}; + +enum REG_ICTL_MASK { + REG_ICTL_MASK_INFO_UPDATE = 1 << 20, + REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19, + REG_ICTL_MASK_TXRX_STOP_REQ = 1 << 18, + REG_ICTL_MASK_TXRX_STOP_DONE = 1 << 17, + REG_ICTL_MASK_RX_DATA = 1 << 16, + REG_ICTL_MASK_ALL = GENMASK(20, 16), +}; + +struct fjes_hw; + +u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg); + +#define wr32(reg, val) \ +do { \ + u8 *base = hw->base; \ + writel((val), &base[(reg)]); \ +} while (0) + +#define rd32(reg) (fjes_hw_rd32(hw, reg)) + +#endif /* FJES_REGS_H_ */ -- GitLab From a18aaec21ec8f4d2a4e09ad590437777a1ebf691 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:19 +0900 Subject: [PATCH 4703/7006] fjes: Hardware cleanup routine This patch adds hardware cleanup routine to be invoked at driver's .remove routine. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 66 ++++++++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 1 + 2 files changed, 67 insertions(+) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index ae2663876605e..757cece85387f 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -56,6 +56,12 @@ static u8 *fjes_hw_iomap(struct fjes_hw *hw) return base; } +static void fjes_hw_iounmap(struct fjes_hw *hw) +{ + iounmap(hw->base); + release_mem_region(hw->hw_res.start, hw->hw_res.size); +} + int fjes_hw_reset(struct fjes_hw *hw) { union REG_DCTL dctl; @@ -109,6 +115,12 @@ static int fjes_hw_alloc_shared_status_region(struct fjes_hw *hw) return 0; } +static void fjes_hw_free_shared_status_region(struct fjes_hw *hw) +{ + kfree(hw->hw_info.share); + hw->hw_info.share = NULL; +} + static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh) { void *mem; @@ -126,6 +138,18 @@ static int fjes_hw_alloc_epbuf(struct epbuf_handler *epbh) return 0; } +static void fjes_hw_free_epbuf(struct epbuf_handler *epbh) +{ + if (epbh->buffer) + vfree(epbh->buffer); + + epbh->buffer = NULL; + epbh->size = 0; + + epbh->info = NULL; + epbh->ring = NULL; +} + void fjes_hw_setup_epbuf(struct epbuf_handler *epbh, u8 *mac_addr, u32 mtu) { union ep_buffer_info *info = epbh->info; @@ -258,6 +282,32 @@ static int fjes_hw_setup(struct fjes_hw *hw) return 0; } +static void fjes_hw_cleanup(struct fjes_hw *hw) +{ + int epidx; + + if (!hw->ep_shm_info) + return; + + fjes_hw_free_shared_status_region(hw); + + kfree(hw->hw_info.req_buf); + hw->hw_info.req_buf = NULL; + + kfree(hw->hw_info.res_buf); + hw->hw_info.res_buf = NULL; + + for (epidx = 0; epidx < hw->max_epid ; epidx++) { + if (epidx == hw->my_epid) + continue; + fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].tx); + fjes_hw_free_epbuf(&hw->ep_shm_info[epidx].rx); + } + + kfree(hw->ep_shm_info); + hw->ep_shm_info = NULL; +} + int fjes_hw_init(struct fjes_hw *hw) { int ret; @@ -285,6 +335,22 @@ int fjes_hw_init(struct fjes_hw *hw) return ret; } +void fjes_hw_exit(struct fjes_hw *hw) +{ + int ret; + + if (hw->base) { + ret = fjes_hw_reset(hw); + if (ret) + pr_err("%s: reset error", __func__); + + fjes_hw_iounmap(hw); + hw->base = NULL; + } + + fjes_hw_cleanup(hw); +} + void fjes_hw_set_irqmask(struct fjes_hw *hw, enum REG_ICTL_MASK intr_mask, bool mask) { diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 836ebe28793cb..1b3e9cac2746c 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -241,6 +241,7 @@ struct fjes_hw { }; int fjes_hw_init(struct fjes_hw *); +void fjes_hw_exit(struct fjes_hw *); int fjes_hw_reset(struct fjes_hw *); void fjes_hw_init_command_registers(struct fjes_hw *, -- GitLab From 2fcbca687702163ae3a37ec4eac5905d6f119296 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:20 +0900 Subject: [PATCH 4704/7006] fjes: platform_driver's .probe and .remove routine This patch implements platform_driver's .probe and .remove routine, and also adds board specific private data structure. This driver registers net_device at platform_driver's .probe routine and unregisters net_device at its .remove routine. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 25 ++++++++++ drivers/net/fjes/fjes_main.c | 94 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 15ded96421012..54bc189a997c1 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -24,7 +24,32 @@ #include +#include "fjes_hw.h" + #define FJES_ACPI_SYMBOL "Extended Socket" +#define FJES_MAX_QUEUES 1 +#define FJES_TX_RETRY_INTERVAL (20 * HZ) + +/* board specific private data structure */ +struct fjes_adapter { + struct net_device *netdev; + struct platform_device *plat_dev; + + struct napi_struct napi; + struct rtnl_link_stats64 stats64; + + unsigned int tx_retry_count; + unsigned long tx_start_jiffies; + unsigned long rx_last_jiffies; + bool unset_rx_last; + + bool force_reset; + bool open_guard; + + bool irq_registered; + + struct fjes_hw hw; +}; extern char fjes_driver_name[]; extern char fjes_driver_version[]; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 95176667131eb..45a8b9c52ae52 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "fjes.h" @@ -49,6 +50,9 @@ static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); static int fjes_probe(struct platform_device *); static int fjes_remove(struct platform_device *); +static int fjes_sw_init(struct fjes_adapter *); +static void fjes_netdev_setup(struct net_device *); + static const struct acpi_device_id fjes_acpi_ids[] = { {"PNP0C02", 0}, {"", 0}, @@ -166,18 +170,108 @@ fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) return AE_OK; } +static const struct net_device_ops fjes_netdev_ops = { +}; + /* fjes_probe - Device Initialization Routine */ static int fjes_probe(struct platform_device *plat_dev) { + struct fjes_adapter *adapter; + struct net_device *netdev; + struct resource *res; + struct fjes_hw *hw; + int err; + + err = -ENOMEM; + netdev = alloc_netdev_mq(sizeof(struct fjes_adapter), "es%d", + NET_NAME_UNKNOWN, fjes_netdev_setup, + FJES_MAX_QUEUES); + + if (!netdev) + goto err_out; + + SET_NETDEV_DEV(netdev, &plat_dev->dev); + + dev_set_drvdata(&plat_dev->dev, netdev); + adapter = netdev_priv(netdev); + adapter->netdev = netdev; + adapter->plat_dev = plat_dev; + hw = &adapter->hw; + hw->back = adapter; + + /* setup the private structure */ + err = fjes_sw_init(adapter); + if (err) + goto err_free_netdev; + + adapter->force_reset = false; + adapter->open_guard = false; + + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); + hw->hw_res.start = res->start; + hw->hw_res.size = res->end - res->start + 1; + hw->hw_res.irq = platform_get_irq(plat_dev, 0); + err = fjes_hw_init(&adapter->hw); + if (err) + goto err_free_netdev; + + /* setup MAC address (02:00:00:00:00:[epid])*/ + netdev->dev_addr[0] = 2; + netdev->dev_addr[1] = 0; + netdev->dev_addr[2] = 0; + netdev->dev_addr[3] = 0; + netdev->dev_addr[4] = 0; + netdev->dev_addr[5] = hw->my_epid; /* EPID */ + + err = register_netdev(netdev); + if (err) + goto err_hw_exit; + + netif_carrier_off(netdev); + return 0; + +err_hw_exit: + fjes_hw_exit(&adapter->hw); +err_free_netdev: + free_netdev(netdev); +err_out: + return err; } /* fjes_remove - Device Removal Routine */ static int fjes_remove(struct platform_device *plat_dev) { + struct net_device *netdev = dev_get_drvdata(&plat_dev->dev); + struct fjes_adapter *adapter = netdev_priv(netdev); + struct fjes_hw *hw = &adapter->hw; + + unregister_netdev(netdev); + + fjes_hw_exit(hw); + + free_netdev(netdev); + return 0; } +static int fjes_sw_init(struct fjes_adapter *adapter) +{ + return 0; +} + +/* fjes_netdev_setup - netdevice initialization routine */ +static void fjes_netdev_setup(struct net_device *netdev) +{ + ether_setup(netdev); + + netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL; + netdev->netdev_ops = &fjes_netdev_ops; + netdev->mtu = fjes_support_mtu[0]; + netdev->flags |= IFF_BROADCAST; + netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER; +} + /* fjes_init_module - Driver Registration Routine */ static int __init fjes_init_module(void) { -- GitLab From 3bb025d4f756049d297f2bed605241d4d43a15fe Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:21 +0900 Subject: [PATCH 4705/7006] fjes: ES information acquisition routine This patch adds ES information acquisition routine. ES information can be retrieved issuing information request command. ES information includes which receiver is same zone. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 101 +++++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 24 +++++++++ drivers/net/fjes/fjes_regs.h | 23 ++++++++ 3 files changed, 148 insertions(+) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 757cece85387f..c31be7f52ab9a 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -351,6 +351,107 @@ void fjes_hw_exit(struct fjes_hw *hw) fjes_hw_cleanup(hw); } +static enum fjes_dev_command_response_e +fjes_hw_issue_request_command(struct fjes_hw *hw, + enum fjes_dev_command_request_type type) +{ + enum fjes_dev_command_response_e ret = FJES_CMD_STATUS_UNKNOWN; + union REG_CR cr; + union REG_CS cs; + int timeout; + + cr.reg = 0; + cr.bits.req_start = 1; + cr.bits.req_code = type; + wr32(XSCT_CR, cr.reg); + cr.reg = rd32(XSCT_CR); + + if (cr.bits.error == 0) { + timeout = FJES_COMMAND_REQ_TIMEOUT * 1000; + cs.reg = rd32(XSCT_CS); + + while ((cs.bits.complete != 1) && timeout > 0) { + msleep(1000); + cs.reg = rd32(XSCT_CS); + timeout -= 1000; + } + + if (cs.bits.complete == 1) + ret = FJES_CMD_STATUS_NORMAL; + else if (timeout <= 0) + ret = FJES_CMD_STATUS_TIMEOUT; + + } else { + switch (cr.bits.err_info) { + case FJES_CMD_REQ_ERR_INFO_PARAM: + ret = FJES_CMD_STATUS_ERROR_PARAM; + break; + case FJES_CMD_REQ_ERR_INFO_STATUS: + ret = FJES_CMD_STATUS_ERROR_STATUS; + break; + default: + ret = FJES_CMD_STATUS_UNKNOWN; + break; + } + } + + return ret; +} + +int fjes_hw_request_info(struct fjes_hw *hw) +{ + union fjes_device_command_req *req_buf = hw->hw_info.req_buf; + union fjes_device_command_res *res_buf = hw->hw_info.res_buf; + enum fjes_dev_command_response_e ret; + int result; + + memset(req_buf, 0, hw->hw_info.req_buf_size); + memset(res_buf, 0, hw->hw_info.res_buf_size); + + req_buf->info.length = FJES_DEV_COMMAND_INFO_REQ_LEN; + + res_buf->info.length = 0; + res_buf->info.code = 0; + + ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_INFO); + + result = 0; + + if (FJES_DEV_COMMAND_INFO_RES_LEN((*hw->hw_info.max_epid)) != + res_buf->info.length) { + result = -ENOMSG; + } else if (ret == FJES_CMD_STATUS_NORMAL) { + switch (res_buf->info.code) { + case FJES_CMD_REQ_RES_CODE_NORMAL: + result = 0; + break; + default: + result = -EPERM; + break; + } + } else { + switch (ret) { + case FJES_CMD_STATUS_UNKNOWN: + result = -EPERM; + break; + case FJES_CMD_STATUS_TIMEOUT: + result = -EBUSY; + break; + case FJES_CMD_STATUS_ERROR_PARAM: + result = -EPERM; + break; + case FJES_CMD_STATUS_ERROR_STATUS: + result = -EPERM; + break; + default: + result = -EPERM; + break; + } + } + + return result; +} + void fjes_hw_set_irqmask(struct fjes_hw *hw, enum REG_ICTL_MASK intr_mask, bool mask) { diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 1b3e9cac2746c..cc1ef2100dc43 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -34,6 +34,12 @@ struct fjes_hw; #define EP_BUFFER_INFO_SIZE 4096 #define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */ +#define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */ + +#define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001) +#define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002) + +#define FJES_CMD_REQ_RES_CODE_NORMAL (0) #define EP_BUFFER_SIZE \ (((sizeof(union ep_buffer_info) + (128 * (64 * 1024))) \ @@ -50,6 +56,7 @@ struct fjes_hw; ((size) - sizeof(struct esmem_frame) - \ (ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN)) +#define FJES_DEV_COMMAND_INFO_REQ_LEN (4) #define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum)) #define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \ (24 + (8 * ((txb) / EP_BUFFER_INFO_SIZE + (rxb) / EP_BUFFER_INFO_SIZE))) @@ -124,6 +131,13 @@ union fjes_device_command_res { } stop_trace; }; +/* request command type */ +enum fjes_dev_command_request_type { + FJES_CMD_REQ_INFO = 0x0001, + FJES_CMD_REQ_SHARE_BUFFER = 0x0002, + FJES_CMD_REQ_UNSHARE_BUFFER = 0x0004, +}; + /* parameter for command control */ struct fjes_device_command_param { u32 req_len; @@ -133,6 +147,15 @@ struct fjes_device_command_param { phys_addr_t share_start; }; +/* error code for command control */ +enum fjes_dev_command_response_e { + FJES_CMD_STATUS_UNKNOWN, + FJES_CMD_STATUS_NORMAL, + FJES_CMD_STATUS_TIMEOUT, + FJES_CMD_STATUS_ERROR_PARAM, + FJES_CMD_STATUS_ERROR_STATUS, +}; + /* EP buffer information */ union ep_buffer_info { u8 raw[EP_BUFFER_INFO_SIZE]; @@ -243,6 +266,7 @@ struct fjes_hw { int fjes_hw_init(struct fjes_hw *); void fjes_hw_exit(struct fjes_hw *); int fjes_hw_reset(struct fjes_hw *); +int fjes_hw_request_info(struct fjes_hw *); void fjes_hw_init_command_registers(struct fjes_hw *, struct fjes_device_command_param *); diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h index 4d0e0719645ef..cc975a0fd111a 100644 --- a/drivers/net/fjes/fjes_regs.h +++ b/drivers/net/fjes/fjes_regs.h @@ -35,6 +35,8 @@ #define XSCT_DCTL 0x0010 /* Device Control */ /* Command Control registers */ +#define XSCT_CR 0x0020 /* Command request */ +#define XSCT_CS 0x0024 /* Command status */ #define XSCT_SHSTSAL 0x0028 /* Share status address Low */ #define XSCT_SHSTSAH 0x002C /* Share status address High */ @@ -78,6 +80,27 @@ union REG_DCTL { __le32 reg; }; +/* Command Control registers */ +union REG_CR { + struct { + __le32 req_code:16; + __le32 err_info:14; + __le32 error:1; + __le32 req_start:1; + } bits; + __le32 reg; +}; + +union REG_CS { + struct { + __le32 req_code:16; + __le32 rsv0:14; + __le32 busy:1; + __le32 complete:1; + } bits; + __le32 reg; +}; + enum REG_ICTL_MASK { REG_ICTL_MASK_INFO_UPDATE = 1 << 20, REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19, -- GitLab From 7950e6c5da55715debef9fa06b5ac87fb3eb4355 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:22 +0900 Subject: [PATCH 4706/7006] fjes: buffer address regist/unregistration routine This patch adds buffer address regist/unregistration routine. This function is mainly invoked when network device's activation (open) and deactivation (close) in order to retist/unregist shared buffer address. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 186 +++++++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 9 +- 2 files changed, 194 insertions(+), 1 deletion(-) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index c31be7f52ab9a..1e807dfc548af 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -452,6 +452,192 @@ int fjes_hw_request_info(struct fjes_hw *hw) return result; } +int fjes_hw_register_buff_addr(struct fjes_hw *hw, int dest_epid, + struct ep_share_mem_info *buf_pair) +{ + union fjes_device_command_req *req_buf = hw->hw_info.req_buf; + union fjes_device_command_res *res_buf = hw->hw_info.res_buf; + enum fjes_dev_command_response_e ret; + int page_count; + int timeout; + int i, idx; + void *addr; + int result; + + if (test_bit(dest_epid, &hw->hw_info.buffer_share_bit)) + return 0; + + memset(req_buf, 0, hw->hw_info.req_buf_size); + memset(res_buf, 0, hw->hw_info.res_buf_size); + + req_buf->share_buffer.length = FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN( + buf_pair->tx.size, + buf_pair->rx.size); + req_buf->share_buffer.epid = dest_epid; + + idx = 0; + req_buf->share_buffer.buffer[idx++] = buf_pair->tx.size; + page_count = buf_pair->tx.size / EP_BUFFER_INFO_SIZE; + for (i = 0; i < page_count; i++) { + addr = ((u8 *)(buf_pair->tx.buffer)) + + (i * EP_BUFFER_INFO_SIZE); + req_buf->share_buffer.buffer[idx++] = + (__le64)(page_to_phys(vmalloc_to_page(addr)) + + offset_in_page(addr)); + } + + req_buf->share_buffer.buffer[idx++] = buf_pair->rx.size; + page_count = buf_pair->rx.size / EP_BUFFER_INFO_SIZE; + for (i = 0; i < page_count; i++) { + addr = ((u8 *)(buf_pair->rx.buffer)) + + (i * EP_BUFFER_INFO_SIZE); + req_buf->share_buffer.buffer[idx++] = + (__le64)(page_to_phys(vmalloc_to_page(addr)) + + offset_in_page(addr)); + } + + res_buf->share_buffer.length = 0; + res_buf->share_buffer.code = 0; + + ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_SHARE_BUFFER); + + timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000; + while ((ret == FJES_CMD_STATUS_NORMAL) && + (res_buf->share_buffer.length == + FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN) && + (res_buf->share_buffer.code == FJES_CMD_REQ_RES_CODE_BUSY) && + (timeout > 0)) { + msleep(200 + hw->my_epid * 20); + timeout -= (200 + hw->my_epid * 20); + + res_buf->share_buffer.length = 0; + res_buf->share_buffer.code = 0; + + ret = fjes_hw_issue_request_command( + hw, FJES_CMD_REQ_SHARE_BUFFER); + } + + result = 0; + + if (res_buf->share_buffer.length != + FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN) + result = -ENOMSG; + else if (ret == FJES_CMD_STATUS_NORMAL) { + switch (res_buf->share_buffer.code) { + case FJES_CMD_REQ_RES_CODE_NORMAL: + result = 0; + set_bit(dest_epid, &hw->hw_info.buffer_share_bit); + break; + case FJES_CMD_REQ_RES_CODE_BUSY: + result = -EBUSY; + break; + default: + result = -EPERM; + break; + } + } else { + switch (ret) { + case FJES_CMD_STATUS_UNKNOWN: + result = -EPERM; + break; + case FJES_CMD_STATUS_TIMEOUT: + result = -EBUSY; + break; + case FJES_CMD_STATUS_ERROR_PARAM: + case FJES_CMD_STATUS_ERROR_STATUS: + default: + result = -EPERM; + break; + } + } + + return result; +} + +int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid) +{ + union fjes_device_command_req *req_buf = hw->hw_info.req_buf; + union fjes_device_command_res *res_buf = hw->hw_info.res_buf; + struct fjes_device_shared_info *share = hw->hw_info.share; + enum fjes_dev_command_response_e ret; + int timeout; + int result; + + if (!hw->base) + return -EPERM; + + if (!req_buf || !res_buf || !share) + return -EPERM; + + if (!test_bit(dest_epid, &hw->hw_info.buffer_share_bit)) + return 0; + + memset(req_buf, 0, hw->hw_info.req_buf_size); + memset(res_buf, 0, hw->hw_info.res_buf_size); + + req_buf->unshare_buffer.length = + FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN; + req_buf->unshare_buffer.epid = dest_epid; + + res_buf->unshare_buffer.length = 0; + res_buf->unshare_buffer.code = 0; + + ret = fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER); + + timeout = FJES_COMMAND_REQ_BUFF_TIMEOUT * 1000; + while ((ret == FJES_CMD_STATUS_NORMAL) && + (res_buf->unshare_buffer.length == + FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) && + (res_buf->unshare_buffer.code == + FJES_CMD_REQ_RES_CODE_BUSY) && + (timeout > 0)) { + msleep(200 + hw->my_epid * 20); + timeout -= (200 + hw->my_epid * 20); + + res_buf->unshare_buffer.length = 0; + res_buf->unshare_buffer.code = 0; + + ret = + fjes_hw_issue_request_command(hw, FJES_CMD_REQ_UNSHARE_BUFFER); + } + + result = 0; + + if (res_buf->unshare_buffer.length != + FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN) { + result = -ENOMSG; + } else if (ret == FJES_CMD_STATUS_NORMAL) { + switch (res_buf->unshare_buffer.code) { + case FJES_CMD_REQ_RES_CODE_NORMAL: + result = 0; + clear_bit(dest_epid, &hw->hw_info.buffer_share_bit); + break; + case FJES_CMD_REQ_RES_CODE_BUSY: + result = -EBUSY; + break; + default: + result = -EPERM; + break; + } + } else { + switch (ret) { + case FJES_CMD_STATUS_UNKNOWN: + result = -EPERM; + break; + case FJES_CMD_STATUS_TIMEOUT: + result = -EBUSY; + break; + case FJES_CMD_STATUS_ERROR_PARAM: + case FJES_CMD_STATUS_ERROR_STATUS: + default: + result = -EPERM; + break; + } + } + + return result; +} + void fjes_hw_set_irqmask(struct fjes_hw *hw, enum REG_ICTL_MASK intr_mask, bool mask) { diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index cc1ef2100dc43..2e750e9655ef3 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -35,11 +35,13 @@ struct fjes_hw; #define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */ #define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */ +#define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */ #define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001) #define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002) #define FJES_CMD_REQ_RES_CODE_NORMAL (0) +#define FJES_CMD_REQ_RES_CODE_BUSY (1) #define EP_BUFFER_SIZE \ (((sizeof(union ep_buffer_info) + (128 * (64 * 1024))) \ @@ -60,6 +62,9 @@ struct fjes_hw; #define FJES_DEV_COMMAND_INFO_RES_LEN(epnum) (8 + 2 * (epnum)) #define FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(txb, rxb) \ (24 + (8 * ((txb) / EP_BUFFER_INFO_SIZE + (rxb) / EP_BUFFER_INFO_SIZE))) +#define FJES_DEV_COMMAND_SHARE_BUFFER_RES_LEN (8) +#define FJES_DEV_COMMAND_UNSHARE_BUFFER_REQ_LEN (8) +#define FJES_DEV_COMMAND_UNSHARE_BUFFER_RES_LEN (8) #define FJES_DEV_REQ_BUF_SIZE(maxep) \ FJES_DEV_COMMAND_SHARE_BUFFER_REQ_LEN(EP_BUFFER_SIZE, EP_BUFFER_SIZE) @@ -267,7 +272,9 @@ int fjes_hw_init(struct fjes_hw *); void fjes_hw_exit(struct fjes_hw *); int fjes_hw_reset(struct fjes_hw *); int fjes_hw_request_info(struct fjes_hw *); - +int fjes_hw_register_buff_addr(struct fjes_hw *, int, + struct ep_share_mem_info *); +int fjes_hw_unregister_buff_addr(struct fjes_hw *, int); void fjes_hw_init_command_registers(struct fjes_hw *, struct fjes_device_command_param *); void fjes_hw_setup_epbuf(struct epbuf_handler *, u8 *, u32); -- GitLab From e5d486dcaa45dd365970c09395ae24df5a0e3f77 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:23 +0900 Subject: [PATCH 4707/7006] fjes: net_device_ops.ndo_open and .ndo_stop This patch adds net_device_ops.ndo_open and .ndo_stop callback. These function is called when network device activation and deactivation. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 1 + drivers/net/fjes/fjes_hw.c | 145 +++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 30 +++++ drivers/net/fjes/fjes_main.c | 246 +++++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_regs.h | 17 +++ 5 files changed, 439 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 54bc189a997c1..f182ed3a4cd12 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -29,6 +29,7 @@ #define FJES_ACPI_SYMBOL "Extended Socket" #define FJES_MAX_QUEUES 1 #define FJES_TX_RETRY_INTERVAL (20 * HZ) +#define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */ /* board specific private data structure */ struct fjes_adapter { diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 1e807dfc548af..1935f48e9e43a 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -638,6 +638,25 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *hw, int dest_epid) return result; } +int fjes_hw_raise_interrupt(struct fjes_hw *hw, int dest_epid, + enum REG_ICTL_MASK mask) +{ + u32 ig = mask | dest_epid; + + wr32(XSCT_IG, cpu_to_le32(ig)); + + return 0; +} + +u32 fjes_hw_capture_interrupt_status(struct fjes_hw *hw) +{ + u32 cur_is; + + cur_is = rd32(XSCT_IS); + + return cur_is; +} + void fjes_hw_set_irqmask(struct fjes_hw *hw, enum REG_ICTL_MASK intr_mask, bool mask) { @@ -646,3 +665,129 @@ void fjes_hw_set_irqmask(struct fjes_hw *hw, else wr32(XSCT_IMC, intr_mask); } + +bool fjes_hw_epid_is_same_zone(struct fjes_hw *hw, int epid) +{ + if (epid >= hw->max_epid) + return false; + + if ((hw->ep_shm_info[epid].es_status != + FJES_ZONING_STATUS_ENABLE) || + (hw->ep_shm_info[hw->my_epid].zone == + FJES_ZONING_ZONE_TYPE_NONE)) + return false; + else + return (hw->ep_shm_info[epid].zone == + hw->ep_shm_info[hw->my_epid].zone); +} + +int fjes_hw_epid_is_shared(struct fjes_device_shared_info *share, + int dest_epid) +{ + int value = false; + + if (dest_epid < share->epnum) + value = share->ep_status[dest_epid]; + + return value; +} + +static bool fjes_hw_epid_is_stop_requested(struct fjes_hw *hw, int src_epid) +{ + return test_bit(src_epid, &hw->txrx_stop_req_bit); +} + +static bool fjes_hw_epid_is_stop_process_done(struct fjes_hw *hw, int src_epid) +{ + return (hw->ep_shm_info[src_epid].tx.info->v1i.rx_status & + FJES_RX_STOP_REQ_DONE); +} + +enum ep_partner_status +fjes_hw_get_partner_ep_status(struct fjes_hw *hw, int epid) +{ + enum ep_partner_status status; + + if (fjes_hw_epid_is_shared(hw->hw_info.share, epid)) { + if (fjes_hw_epid_is_stop_requested(hw, epid)) { + status = EP_PARTNER_WAITING; + } else { + if (fjes_hw_epid_is_stop_process_done(hw, epid)) + status = EP_PARTNER_COMPLETE; + else + status = EP_PARTNER_SHARED; + } + } else { + status = EP_PARTNER_UNSHARE; + } + + return status; +} + +void fjes_hw_raise_epstop(struct fjes_hw *hw) +{ + enum ep_partner_status status; + int epidx; + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + status = fjes_hw_get_partner_ep_status(hw, epidx); + switch (status) { + case EP_PARTNER_SHARED: + fjes_hw_raise_interrupt(hw, epidx, + REG_ICTL_MASK_TXRX_STOP_REQ); + break; + default: + break; + } + + set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit); + set_bit(epidx, &hw->txrx_stop_req_bit); + + hw->ep_shm_info[epidx].tx.info->v1i.rx_status |= + FJES_RX_STOP_REQ_REQUEST; + } +} + +int fjes_hw_wait_epstop(struct fjes_hw *hw) +{ + enum ep_partner_status status; + union ep_buffer_info *info; + int wait_time = 0; + int epidx; + + while (hw->hw_info.buffer_unshare_reserve_bit && + (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000)) { + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + status = fjes_hw_epid_is_shared(hw->hw_info.share, + epidx); + info = hw->ep_shm_info[epidx].rx.info; + if ((!status || + (info->v1i.rx_status & + FJES_RX_STOP_REQ_DONE)) && + test_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit)) { + clear_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit); + } + } + + msleep(100); + wait_time += 100; + } + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + if (test_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit)) + clear_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit); + } + + return (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000) + ? 0 : -EBUSY; +} diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 2e750e9655ef3..9b8df553f730d 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -36,6 +36,7 @@ struct fjes_hw; #define FJES_DEVICE_RESET_TIMEOUT ((17 + 1) * 3) /* sec */ #define FJES_COMMAND_REQ_TIMEOUT (5 + 1) /* sec */ #define FJES_COMMAND_REQ_BUFF_TIMEOUT (8 * 3) /* sec */ +#define FJES_COMMAND_EPSTOP_WAIT_TIMEOUT (1) /* sec */ #define FJES_CMD_REQ_ERR_INFO_PARAM (0x0001) #define FJES_CMD_REQ_ERR_INFO_STATUS (0x0002) @@ -43,6 +44,17 @@ struct fjes_hw; #define FJES_CMD_REQ_RES_CODE_NORMAL (0) #define FJES_CMD_REQ_RES_CODE_BUSY (1) +#define FJES_ZONING_STATUS_DISABLE (0x00) +#define FJES_ZONING_STATUS_ENABLE (0x01) +#define FJES_ZONING_STATUS_INVALID (0xFF) + +#define FJES_ZONING_ZONE_TYPE_NONE (0xFF) + +#define FJES_RX_STOP_REQ_NONE (0x0) +#define FJES_RX_STOP_REQ_DONE (0x1) +#define FJES_RX_STOP_REQ_REQUEST (0x2) +#define FJES_RX_POLL_WORK (0x4) + #define EP_BUFFER_SIZE \ (((sizeof(union ep_buffer_info) + (128 * (64 * 1024))) \ / EP_BUFFER_INFO_SIZE) * EP_BUFFER_INFO_SIZE) @@ -77,6 +89,15 @@ struct esmem_frame { u8 frame_data[]; }; +/* EP partner status */ +enum ep_partner_status { + EP_PARTNER_UNSHARE, + EP_PARTNER_SHARED, + EP_PARTNER_WAITING, + EP_PARTNER_COMPLETE, + EP_PARTNER_STATUS_MAX, +}; + /* shared status region */ struct fjes_device_shared_info { int epnum; @@ -278,6 +299,15 @@ int fjes_hw_unregister_buff_addr(struct fjes_hw *, int); void fjes_hw_init_command_registers(struct fjes_hw *, struct fjes_device_command_param *); void fjes_hw_setup_epbuf(struct epbuf_handler *, u8 *, u32); +int fjes_hw_raise_interrupt(struct fjes_hw *, int, enum REG_ICTL_MASK); void fjes_hw_set_irqmask(struct fjes_hw *, enum REG_ICTL_MASK, bool); +u32 fjes_hw_capture_interrupt_status(struct fjes_hw *); +void fjes_hw_raise_epstop(struct fjes_hw *); +int fjes_hw_wait_epstop(struct fjes_hw *); +enum ep_partner_status + fjes_hw_get_partner_ep_status(struct fjes_hw *, int); + +bool fjes_hw_epid_is_same_zone(struct fjes_hw *, int); +int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int); #endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 45a8b9c52ae52..bd50cbd6915fc 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "fjes.h" @@ -43,6 +44,15 @@ MODULE_DESCRIPTION("FUJITSU Extended Socket Network Device Driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); +static int fjes_request_irq(struct fjes_adapter *); +static void fjes_free_irq(struct fjes_adapter *); + +static int fjes_open(struct net_device *); +static int fjes_close(struct net_device *); +static int fjes_setup_resources(struct fjes_adapter *); +static void fjes_free_resources(struct fjes_adapter *); +static irqreturn_t fjes_intr(int, void*); + static int fjes_acpi_add(struct acpi_device *); static int fjes_acpi_remove(struct acpi_device *); static acpi_status fjes_get_acpi_resource(struct acpi_resource *, void*); @@ -170,9 +180,245 @@ fjes_get_acpi_resource(struct acpi_resource *acpi_res, void *data) return AE_OK; } +static int fjes_request_irq(struct fjes_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + int result = -1; + + if (!adapter->irq_registered) { + result = request_irq(adapter->hw.hw_res.irq, fjes_intr, + IRQF_SHARED, netdev->name, adapter); + if (result) + adapter->irq_registered = false; + else + adapter->irq_registered = true; + } + + return result; +} + +static void fjes_free_irq(struct fjes_adapter *adapter) +{ + struct fjes_hw *hw = &adapter->hw; + + fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); + + if (adapter->irq_registered) { + free_irq(adapter->hw.hw_res.irq, adapter); + adapter->irq_registered = false; + } +} + static const struct net_device_ops fjes_netdev_ops = { + .ndo_open = fjes_open, + .ndo_stop = fjes_close, }; +/* fjes_open - Called when a network interface is made active */ +static int fjes_open(struct net_device *netdev) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + struct fjes_hw *hw = &adapter->hw; + int result; + + if (adapter->open_guard) + return -ENXIO; + + result = fjes_setup_resources(adapter); + if (result) + goto err_setup_res; + + hw->txrx_stop_req_bit = 0; + hw->epstop_req_bit = 0; + + fjes_hw_capture_interrupt_status(hw); + + result = fjes_request_irq(adapter); + if (result) + goto err_req_irq; + + fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, false); + + netif_tx_start_all_queues(netdev); + netif_carrier_on(netdev); + + return 0; + +err_req_irq: + fjes_free_irq(adapter); + +err_setup_res: + fjes_free_resources(adapter); + return result; +} + +/* fjes_close - Disables a network interface */ +static int fjes_close(struct net_device *netdev) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + struct fjes_hw *hw = &adapter->hw; + int epidx; + + netif_tx_stop_all_queues(netdev); + netif_carrier_off(netdev); + + fjes_hw_raise_epstop(hw); + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status &= + ~FJES_RX_POLL_WORK; + } + + fjes_free_irq(adapter); + + fjes_hw_wait_epstop(hw); + + fjes_free_resources(adapter); + + return 0; +} + +static int fjes_setup_resources(struct fjes_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct ep_share_mem_info *buf_pair; + struct fjes_hw *hw = &adapter->hw; + int result; + int epidx; + + mutex_lock(&hw->hw_info.lock); + result = fjes_hw_request_info(hw); + switch (result) { + case 0: + for (epidx = 0; epidx < hw->max_epid; epidx++) { + hw->ep_shm_info[epidx].es_status = + hw->hw_info.res_buf->info.info[epidx].es_status; + hw->ep_shm_info[epidx].zone = + hw->hw_info.res_buf->info.info[epidx].zone; + } + break; + default: + case -ENOMSG: + case -EBUSY: + adapter->force_reset = true; + + mutex_unlock(&hw->hw_info.lock); + return result; + } + mutex_unlock(&hw->hw_info.lock); + + for (epidx = 0; epidx < (hw->max_epid); epidx++) { + if ((epidx != hw->my_epid) && + (hw->ep_shm_info[epidx].es_status == + FJES_ZONING_STATUS_ENABLE)) { + fjes_hw_raise_interrupt(hw, epidx, + REG_ICTL_MASK_INFO_UPDATE); + } + } + + msleep(FJES_OPEN_ZONE_UPDATE_WAIT * hw->max_epid); + + for (epidx = 0; epidx < (hw->max_epid); epidx++) { + if (epidx == hw->my_epid) + continue; + + buf_pair = &hw->ep_shm_info[epidx]; + + fjes_hw_setup_epbuf(&buf_pair->tx, netdev->dev_addr, + netdev->mtu); + + if (fjes_hw_epid_is_same_zone(hw, epidx)) { + mutex_lock(&hw->hw_info.lock); + result = + fjes_hw_register_buff_addr(hw, epidx, buf_pair); + mutex_unlock(&hw->hw_info.lock); + + switch (result) { + case 0: + break; + case -ENOMSG: + case -EBUSY: + default: + adapter->force_reset = true; + return result; + } + } + } + + return 0; +} + +static void fjes_free_resources(struct fjes_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; + struct fjes_device_command_param param; + struct ep_share_mem_info *buf_pair; + struct fjes_hw *hw = &adapter->hw; + bool reset_flag = false; + int result; + int epidx; + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + mutex_lock(&hw->hw_info.lock); + result = fjes_hw_unregister_buff_addr(hw, epidx); + mutex_unlock(&hw->hw_info.lock); + + if (result) + reset_flag = true; + + buf_pair = &hw->ep_shm_info[epidx]; + + fjes_hw_setup_epbuf(&buf_pair->tx, + netdev->dev_addr, netdev->mtu); + + clear_bit(epidx, &hw->txrx_stop_req_bit); + } + + if (reset_flag || adapter->force_reset) { + result = fjes_hw_reset(hw); + + adapter->force_reset = false; + + if (result) + adapter->open_guard = true; + + hw->hw_info.buffer_share_bit = 0; + + memset((void *)¶m, 0, sizeof(param)); + + param.req_len = hw->hw_info.req_buf_size; + param.req_start = __pa(hw->hw_info.req_buf); + param.res_len = hw->hw_info.res_buf_size; + param.res_start = __pa(hw->hw_info.res_buf); + param.share_start = __pa(hw->hw_info.share->ep_status); + + fjes_hw_init_command_registers(hw, ¶m); + } +} + +static irqreturn_t fjes_intr(int irq, void *data) +{ + struct fjes_adapter *adapter = data; + struct fjes_hw *hw = &adapter->hw; + irqreturn_t ret; + u32 icr; + + icr = fjes_hw_capture_interrupt_status(hw); + + if (icr & REG_IS_MASK_IS_ASSERT) + ret = IRQ_HANDLED; + else + ret = IRQ_NONE; + + return ret; +} + /* fjes_probe - Device Initialization Routine */ static int fjes_probe(struct platform_device *plat_dev) { diff --git a/drivers/net/fjes/fjes_regs.h b/drivers/net/fjes/fjes_regs.h index cc975a0fd111a..029c924dc1755 100644 --- a/drivers/net/fjes/fjes_regs.h +++ b/drivers/net/fjes/fjes_regs.h @@ -49,8 +49,11 @@ #define XSCT_RESPBAH 0x004C /* Response Buffer Address High */ /* Interrupt Control registers */ +#define XSCT_IS 0x0080 /* Interrupt status */ #define XSCT_IMS 0x0084 /* Interrupt mask set */ #define XSCT_IMC 0x0088 /* Interrupt mask clear */ +#define XSCT_IG 0x008C /* Interrupt generator */ +#define XSCT_ICTL 0x0090 /* Interrupt control */ /* register structure */ /* Information registers */ @@ -101,6 +104,15 @@ union REG_CS { __le32 reg; }; +/* Interrupt Control registers */ +union REG_ICTL { + struct { + __le32 automak:1; + __le32 rsv0:31; + } bits; + __le32 reg; +}; + enum REG_ICTL_MASK { REG_ICTL_MASK_INFO_UPDATE = 1 << 20, REG_ICTL_MASK_DEV_STOP_REQ = 1 << 19, @@ -110,6 +122,11 @@ enum REG_ICTL_MASK { REG_ICTL_MASK_ALL = GENMASK(20, 16), }; +enum REG_IS_MASK { + REG_IS_MASK_IS_ASSERT = 1 << 31, + REG_IS_MASK_EPID = GENMASK(15, 0), +}; + struct fjes_hw; u32 fjes_hw_rd32(struct fjes_hw *hw, u32 reg); -- GitLab From 9acf51cbf73de8952e3df75200d7a7755c16d0f6 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:24 +0900 Subject: [PATCH 4708/7006] fjes: net_device_ops.ndo_start_xmit This patch adds net_device_ops.ndo_start_xmit callback, which is called when sending packets. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 1 + drivers/net/fjes/fjes_hw.c | 55 +++++++++++ drivers/net/fjes/fjes_hw.h | 12 +++ drivers/net/fjes/fjes_main.c | 177 +++++++++++++++++++++++++++++++++++ 4 files changed, 245 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index f182ed3a4cd12..7af4304f54252 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -29,6 +29,7 @@ #define FJES_ACPI_SYMBOL "Extended Socket" #define FJES_MAX_QUEUES 1 #define FJES_TX_RETRY_INTERVAL (20 * HZ) +#define FJES_TX_RETRY_TIMEOUT (100) #define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */ /* board specific private data structure */ diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 1935f48e9e43a..487dbc6b7c439 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -791,3 +791,58 @@ int fjes_hw_wait_epstop(struct fjes_hw *hw) return (wait_time < FJES_COMMAND_EPSTOP_WAIT_TIMEOUT * 1000) ? 0 : -EBUSY; } + +bool fjes_hw_check_epbuf_version(struct epbuf_handler *epbh, u32 version) +{ + union ep_buffer_info *info = epbh->info; + + return (info->common.version == version); +} + +bool fjes_hw_check_mtu(struct epbuf_handler *epbh, u32 mtu) +{ + union ep_buffer_info *info = epbh->info; + + return (info->v1i.frame_max == FJES_MTU_TO_FRAME_SIZE(mtu)); +} + +bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id) +{ + union ep_buffer_info *info = epbh->info; + bool ret = false; + int i; + + if (vlan_id == 0) { + ret = true; + } else { + for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) { + if (vlan_id == info->v1i.vlan_id[i]) { + ret = true; + break; + } + } + } + return ret; +} + +int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh, + void *frame, size_t size) +{ + union ep_buffer_info *info = epbh->info; + struct esmem_frame *ring_frame; + + if (EP_RING_FULL(info->v1i.head, info->v1i.tail, info->v1i.count_max)) + return -ENOBUFS; + + ring_frame = (struct esmem_frame *)&(epbh->ring[EP_RING_INDEX + (info->v1i.tail - 1, + info->v1i.count_max) * + info->v1i.frame_max]); + + ring_frame->frame_size = size; + memcpy((void *)(ring_frame->frame_data), (void *)frame, size); + + EP_RING_INDEX_INC(epbh->info->v1i.tail, info->v1i.count_max); + + return 0; +} diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 9b8df553f730d..07e122614a766 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -50,6 +50,9 @@ struct fjes_hw; #define FJES_ZONING_ZONE_TYPE_NONE (0xFF) +#define FJES_TX_DELAY_SEND_NONE (0) +#define FJES_TX_DELAY_SEND_PENDING (1) + #define FJES_RX_STOP_REQ_NONE (0x0) #define FJES_RX_STOP_REQ_DONE (0x1) #define FJES_RX_STOP_REQ_REQUEST (0x2) @@ -61,6 +64,11 @@ struct fjes_hw; #define EP_RING_NUM(buffer_size, frame_size) \ (u32)((buffer_size) / (frame_size)) +#define EP_RING_INDEX(_num, _max) (((_num) + (_max)) % (_max)) +#define EP_RING_INDEX_INC(_num, _max) \ + ((_num) = EP_RING_INDEX((_num) + 1, (_max))) +#define EP_RING_FULL(_head, _tail, _max) \ + (0 == EP_RING_INDEX(((_tail) - (_head)), (_max))) #define FJES_MTU_TO_BUFFER_SIZE(mtu) \ (ETH_HLEN + VLAN_HLEN + (mtu) + ETH_FCS_LEN) @@ -309,5 +317,9 @@ enum ep_partner_status bool fjes_hw_epid_is_same_zone(struct fjes_hw *, int); int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int); +bool fjes_hw_check_epbuf_version(struct epbuf_handler *, u32); +bool fjes_hw_check_mtu(struct epbuf_handler *, u32); +bool fjes_hw_check_vlan_id(struct epbuf_handler *, u16); +int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *, void *, size_t); #endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index bd50cbd6915fc..220ff3da45212 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -51,6 +51,7 @@ static int fjes_open(struct net_device *); static int fjes_close(struct net_device *); static int fjes_setup_resources(struct fjes_adapter *); static void fjes_free_resources(struct fjes_adapter *); +static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *); static irqreturn_t fjes_intr(int, void*); static int fjes_acpi_add(struct acpi_device *); @@ -212,6 +213,7 @@ static void fjes_free_irq(struct fjes_adapter *adapter) static const struct net_device_ops fjes_netdev_ops = { .ndo_open = fjes_open, .ndo_stop = fjes_close, + .ndo_start_xmit = fjes_xmit_frame, }; /* fjes_open - Called when a network interface is made active */ @@ -402,6 +404,181 @@ static void fjes_free_resources(struct fjes_adapter *adapter) } } +static int fjes_tx_send(struct fjes_adapter *adapter, int dest, + void *data, size_t len) +{ + int retval; + + retval = fjes_hw_epbuf_tx_pkt_send(&adapter->hw.ep_shm_info[dest].tx, + data, len); + if (retval) + return retval; + + adapter->hw.ep_shm_info[dest].tx.info->v1i.tx_status = + FJES_TX_DELAY_SEND_PENDING; + + retval = 0; + return retval; +} + +static netdev_tx_t +fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + struct fjes_hw *hw = &adapter->hw; + + int max_epid, my_epid, dest_epid; + enum ep_partner_status pstatus; + struct netdev_queue *cur_queue; + char shortpkt[VLAN_ETH_HLEN]; + bool is_multi, vlan; + struct ethhdr *eth; + u16 queue_no = 0; + u16 vlan_id = 0; + netdev_tx_t ret; + char *data; + int len; + + ret = NETDEV_TX_OK; + is_multi = false; + cur_queue = netdev_get_tx_queue(netdev, queue_no); + + eth = (struct ethhdr *)skb->data; + my_epid = hw->my_epid; + + vlan = (vlan_get_tag(skb, &vlan_id) == 0) ? true : false; + + data = skb->data; + len = skb->len; + + if (is_multicast_ether_addr(eth->h_dest)) { + dest_epid = 0; + max_epid = hw->max_epid; + is_multi = true; + } else if (is_local_ether_addr(eth->h_dest)) { + dest_epid = eth->h_dest[ETH_ALEN - 1]; + max_epid = dest_epid + 1; + + if ((eth->h_dest[0] == 0x02) && + (0x00 == (eth->h_dest[1] | eth->h_dest[2] | + eth->h_dest[3] | eth->h_dest[4])) && + (dest_epid < hw->max_epid)) { + ; + } else { + dest_epid = 0; + max_epid = 0; + ret = NETDEV_TX_OK; + + adapter->stats64.tx_packets += 1; + hw->ep_shm_info[my_epid].net_stats.tx_packets += 1; + adapter->stats64.tx_bytes += len; + hw->ep_shm_info[my_epid].net_stats.tx_bytes += len; + } + } else { + dest_epid = 0; + max_epid = 0; + ret = NETDEV_TX_OK; + + adapter->stats64.tx_packets += 1; + hw->ep_shm_info[my_epid].net_stats.tx_packets += 1; + adapter->stats64.tx_bytes += len; + hw->ep_shm_info[my_epid].net_stats.tx_bytes += len; + } + + for (; dest_epid < max_epid; dest_epid++) { + if (my_epid == dest_epid) + continue; + + pstatus = fjes_hw_get_partner_ep_status(hw, dest_epid); + if (pstatus != EP_PARTNER_SHARED) { + ret = NETDEV_TX_OK; + } else if (!fjes_hw_check_epbuf_version( + &adapter->hw.ep_shm_info[dest_epid].rx, 0)) { + /* version is NOT 0 */ + adapter->stats64.tx_carrier_errors += 1; + hw->ep_shm_info[my_epid].net_stats + .tx_carrier_errors += 1; + + ret = NETDEV_TX_OK; + } else if (!fjes_hw_check_mtu( + &adapter->hw.ep_shm_info[dest_epid].rx, + netdev->mtu)) { + adapter->stats64.tx_dropped += 1; + hw->ep_shm_info[my_epid].net_stats.tx_dropped += 1; + adapter->stats64.tx_errors += 1; + hw->ep_shm_info[my_epid].net_stats.tx_errors += 1; + + ret = NETDEV_TX_OK; + } else if (vlan && + !fjes_hw_check_vlan_id( + &adapter->hw.ep_shm_info[dest_epid].rx, + vlan_id)) { + ret = NETDEV_TX_OK; + } else { + if (len < VLAN_ETH_HLEN) { + memset(shortpkt, 0, VLAN_ETH_HLEN); + memcpy(shortpkt, skb->data, skb->len); + len = VLAN_ETH_HLEN; + data = shortpkt; + } + + if (adapter->tx_retry_count == 0) { + adapter->tx_start_jiffies = jiffies; + adapter->tx_retry_count = 1; + } else { + adapter->tx_retry_count++; + } + + if (fjes_tx_send(adapter, dest_epid, data, len)) { + if (is_multi) { + ret = NETDEV_TX_OK; + } else if ( + ((long)jiffies - + (long)adapter->tx_start_jiffies) >= + FJES_TX_RETRY_TIMEOUT) { + adapter->stats64.tx_fifo_errors += 1; + hw->ep_shm_info[my_epid].net_stats + .tx_fifo_errors += 1; + adapter->stats64.tx_errors += 1; + hw->ep_shm_info[my_epid].net_stats + .tx_errors += 1; + + ret = NETDEV_TX_OK; + } else { + netdev->trans_start = jiffies; + netif_tx_stop_queue(cur_queue); + + ret = NETDEV_TX_BUSY; + } + } else { + if (!is_multi) { + adapter->stats64.tx_packets += 1; + hw->ep_shm_info[my_epid].net_stats + .tx_packets += 1; + adapter->stats64.tx_bytes += len; + hw->ep_shm_info[my_epid].net_stats + .tx_bytes += len; + } + + adapter->tx_retry_count = 0; + ret = NETDEV_TX_OK; + } + } + } + + if (ret == NETDEV_TX_OK) { + dev_kfree_skb(skb); + if (is_multi) { + adapter->stats64.tx_packets += 1; + hw->ep_shm_info[my_epid].net_stats.tx_packets += 1; + adapter->stats64.tx_bytes += 1; + hw->ep_shm_info[my_epid].net_stats.tx_bytes += len; + } + } + + return ret; +} + static irqreturn_t fjes_intr(int irq, void *data) { struct fjes_adapter *adapter = data; -- GitLab From b772b9dc63df0ca8a750ceac9ab356376022f0b6 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:25 +0900 Subject: [PATCH 4709/7006] fjes: raise_intr_rxdata_task This patch add raise_intr_rxdata_task. Extended Socket Network Device is shared memory based, so someone's transmission denotes other's reception. In order to notify receivers, sender has to raise interruption of receivers. raise_intr_rxdata_task does this work. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 4 +++ drivers/net/fjes/fjes_main.c | 63 ++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 7af4304f54252..8e9899ea19933 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -50,6 +50,10 @@ struct fjes_adapter { bool irq_registered; + struct workqueue_struct *txrx_wq; + + struct work_struct raise_intr_rxdata_task; + struct fjes_hw hw; }; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 220ff3da45212..80e180f163f54 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -52,6 +52,7 @@ static int fjes_close(struct net_device *); static int fjes_setup_resources(struct fjes_adapter *); static void fjes_free_resources(struct fjes_adapter *); static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *); +static void fjes_raise_intr_rxdata_task(struct work_struct *); static irqreturn_t fjes_intr(int, void*); static int fjes_acpi_add(struct acpi_device *); @@ -276,6 +277,8 @@ static int fjes_close(struct net_device *netdev) fjes_free_irq(adapter); + cancel_work_sync(&adapter->raise_intr_rxdata_task); + fjes_hw_wait_epstop(hw); fjes_free_resources(adapter); @@ -404,6 +407,54 @@ static void fjes_free_resources(struct fjes_adapter *adapter) } } +static void fjes_raise_intr_rxdata_task(struct work_struct *work) +{ + struct fjes_adapter *adapter = container_of(work, + struct fjes_adapter, raise_intr_rxdata_task); + struct fjes_hw *hw = &adapter->hw; + enum ep_partner_status pstatus; + int max_epid, my_epid, epid; + + my_epid = hw->my_epid; + max_epid = hw->max_epid; + + for (epid = 0; epid < max_epid; epid++) + hw->ep_shm_info[epid].tx_status_work = 0; + + for (epid = 0; epid < max_epid; epid++) { + if (epid == my_epid) + continue; + + pstatus = fjes_hw_get_partner_ep_status(hw, epid); + if (pstatus == EP_PARTNER_SHARED) { + hw->ep_shm_info[epid].tx_status_work = + hw->ep_shm_info[epid].tx.info->v1i.tx_status; + + if (hw->ep_shm_info[epid].tx_status_work == + FJES_TX_DELAY_SEND_PENDING) { + hw->ep_shm_info[epid].tx.info->v1i.tx_status = + FJES_TX_DELAY_SEND_NONE; + } + } + } + + for (epid = 0; epid < max_epid; epid++) { + if (epid == my_epid) + continue; + + pstatus = fjes_hw_get_partner_ep_status(hw, epid); + if ((hw->ep_shm_info[epid].tx_status_work == + FJES_TX_DELAY_SEND_PENDING) && + (pstatus == EP_PARTNER_SHARED) && + !(hw->ep_shm_info[epid].rx.info->v1i.rx_status)) { + fjes_hw_raise_interrupt(hw, epid, + REG_ICTL_MASK_RX_DATA); + } + } + + usleep_range(500, 1000); +} + static int fjes_tx_send(struct fjes_adapter *adapter, int dest, void *data, size_t len) { @@ -416,6 +467,9 @@ static int fjes_tx_send(struct fjes_adapter *adapter, int dest, adapter->hw.ep_shm_info[dest].tx.info->v1i.tx_status = FJES_TX_DELAY_SEND_PENDING; + if (!work_pending(&adapter->raise_intr_rxdata_task)) + queue_work(adapter->txrx_wq, + &adapter->raise_intr_rxdata_task); retval = 0; return retval; @@ -630,6 +684,11 @@ static int fjes_probe(struct platform_device *plat_dev) adapter->force_reset = false; adapter->open_guard = false; + adapter->txrx_wq = create_workqueue(DRV_NAME "/txrx"); + + INIT_WORK(&adapter->raise_intr_rxdata_task, + fjes_raise_intr_rxdata_task); + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); hw->hw_res.start = res->start; hw->hw_res.size = res->end - res->start + 1; @@ -669,6 +728,10 @@ static int fjes_remove(struct platform_device *plat_dev) struct fjes_adapter *adapter = netdev_priv(netdev); struct fjes_hw *hw = &adapter->hw; + cancel_work_sync(&adapter->raise_intr_rxdata_task); + if (adapter->txrx_wq) + destroy_workqueue(adapter->txrx_wq); + unregister_netdev(netdev); fjes_hw_exit(hw); -- GitLab From ac63b947085d8297bed10063cdf1ed6374d04b73 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:26 +0900 Subject: [PATCH 4710/7006] fjes: tx_stall_task This patch adds tx_stall_task. When receiver's buffer is full, sender stops its tx queue. This task is used to monitor receiver's status and when receiver's buffer is avairable, it resumes tx queue. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 2 ++ drivers/net/fjes/fjes_main.c | 61 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 8e9899ea19933..b04ea9dcab438 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -30,6 +30,7 @@ #define FJES_MAX_QUEUES 1 #define FJES_TX_RETRY_INTERVAL (20 * HZ) #define FJES_TX_RETRY_TIMEOUT (100) +#define FJES_TX_TX_STALL_TIMEOUT (FJES_TX_RETRY_INTERVAL / 2) #define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */ /* board specific private data structure */ @@ -52,6 +53,7 @@ struct fjes_adapter { struct workqueue_struct *txrx_wq; + struct work_struct tx_stall_task; struct work_struct raise_intr_rxdata_task; struct fjes_hw hw; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 80e180f163f54..ac1e076366621 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -53,6 +53,7 @@ static int fjes_setup_resources(struct fjes_adapter *); static void fjes_free_resources(struct fjes_adapter *); static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *); static void fjes_raise_intr_rxdata_task(struct work_struct *); +static void fjes_tx_stall_task(struct work_struct *); static irqreturn_t fjes_intr(int, void*); static int fjes_acpi_add(struct acpi_device *); @@ -278,6 +279,7 @@ static int fjes_close(struct net_device *netdev) fjes_free_irq(adapter); cancel_work_sync(&adapter->raise_intr_rxdata_task); + cancel_work_sync(&adapter->tx_stall_task); fjes_hw_wait_epstop(hw); @@ -407,6 +409,59 @@ static void fjes_free_resources(struct fjes_adapter *adapter) } } +static void fjes_tx_stall_task(struct work_struct *work) +{ + struct fjes_adapter *adapter = container_of(work, + struct fjes_adapter, tx_stall_task); + struct net_device *netdev = adapter->netdev; + struct fjes_hw *hw = &adapter->hw; + int all_queue_available, sendable; + enum ep_partner_status pstatus; + int max_epid, my_epid, epid; + union ep_buffer_info *info; + int i; + + if (((long)jiffies - + (long)(netdev->trans_start)) > FJES_TX_TX_STALL_TIMEOUT) { + netif_wake_queue(netdev); + return; + } + + my_epid = hw->my_epid; + max_epid = hw->max_epid; + + for (i = 0; i < 5; i++) { + all_queue_available = 1; + + for (epid = 0; epid < max_epid; epid++) { + if (my_epid == epid) + continue; + + pstatus = fjes_hw_get_partner_ep_status(hw, epid); + sendable = (pstatus == EP_PARTNER_SHARED); + if (!sendable) + continue; + + info = adapter->hw.ep_shm_info[epid].tx.info; + + if (EP_RING_FULL(info->v1i.head, info->v1i.tail, + info->v1i.count_max)) { + all_queue_available = 0; + break; + } + } + + if (all_queue_available) { + netif_wake_queue(netdev); + return; + } + } + + usleep_range(50, 100); + + queue_work(adapter->txrx_wq, &adapter->tx_stall_task); +} + static void fjes_raise_intr_rxdata_task(struct work_struct *work) { struct fjes_adapter *adapter = container_of(work, @@ -602,6 +657,10 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev) netdev->trans_start = jiffies; netif_tx_stop_queue(cur_queue); + if (!work_pending(&adapter->tx_stall_task)) + queue_work(adapter->txrx_wq, + &adapter->tx_stall_task); + ret = NETDEV_TX_BUSY; } } else { @@ -686,6 +745,7 @@ static int fjes_probe(struct platform_device *plat_dev) adapter->txrx_wq = create_workqueue(DRV_NAME "/txrx"); + INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task); INIT_WORK(&adapter->raise_intr_rxdata_task, fjes_raise_intr_rxdata_task); @@ -729,6 +789,7 @@ static int fjes_remove(struct platform_device *plat_dev) struct fjes_hw *hw = &adapter->hw; cancel_work_sync(&adapter->raise_intr_rxdata_task); + cancel_work_sync(&adapter->tx_stall_task); if (adapter->txrx_wq) destroy_workqueue(adapter->txrx_wq); -- GitLab From 265859309a761b4eec36620b324c9eb27a3cfee1 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:27 +0900 Subject: [PATCH 4711/7006] fjes: NAPI polling function This patch adds NAPI polling function and receive related work. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 40 ++++++++ drivers/net/fjes/fjes_hw.h | 5 + drivers/net/fjes/fjes_main.c | 171 ++++++++++++++++++++++++++++++++++- 3 files changed, 214 insertions(+), 2 deletions(-) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 487dbc6b7c439..3c96d06d15cfd 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -825,6 +825,46 @@ bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id) return ret; } +bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *epbh) +{ + union ep_buffer_info *info = epbh->info; + + if (info->v1i.count_max == 0) + return true; + + return EP_RING_EMPTY(info->v1i.head, info->v1i.tail, + info->v1i.count_max); +} + +void *fjes_hw_epbuf_rx_curpkt_get_addr(struct epbuf_handler *epbh, + size_t *psize) +{ + union ep_buffer_info *info = epbh->info; + struct esmem_frame *ring_frame; + void *frame; + + ring_frame = (struct esmem_frame *)&(epbh->ring[EP_RING_INDEX + (info->v1i.head, + info->v1i.count_max) * + info->v1i.frame_max]); + + *psize = (size_t)ring_frame->frame_size; + + frame = ring_frame->frame_data; + + return frame; +} + +void fjes_hw_epbuf_rx_curpkt_drop(struct epbuf_handler *epbh) +{ + union ep_buffer_info *info = epbh->info; + + if (fjes_hw_epbuf_rx_is_empty(epbh)) + return; + + EP_RING_INDEX_INC(epbh->info->v1i.head, info->v1i.count_max); +} + int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh, void *frame, size_t size) { diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 07e122614a766..3511db2f7eb07 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -69,6 +69,8 @@ struct fjes_hw; ((_num) = EP_RING_INDEX((_num) + 1, (_max))) #define EP_RING_FULL(_head, _tail, _max) \ (0 == EP_RING_INDEX(((_tail) - (_head)), (_max))) +#define EP_RING_EMPTY(_head, _tail, _max) \ + (1 == EP_RING_INDEX(((_tail) - (_head)), (_max))) #define FJES_MTU_TO_BUFFER_SIZE(mtu) \ (ETH_HLEN + VLAN_HLEN + (mtu) + ETH_FCS_LEN) @@ -320,6 +322,9 @@ int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int); bool fjes_hw_check_epbuf_version(struct epbuf_handler *, u32); bool fjes_hw_check_mtu(struct epbuf_handler *, u32); bool fjes_hw_check_vlan_id(struct epbuf_handler *, u16); +bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *); +void *fjes_hw_epbuf_rx_curpkt_get_addr(struct epbuf_handler *, size_t *); +void fjes_hw_epbuf_rx_curpkt_drop(struct epbuf_handler *); int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *, void *, size_t); #endif /* FJES_HW_H_ */ diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index ac1e076366621..61949625176cc 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -66,6 +66,9 @@ static int fjes_remove(struct platform_device *); static int fjes_sw_init(struct fjes_adapter *); static void fjes_netdev_setup(struct net_device *); +static void fjes_rx_irq(struct fjes_adapter *, int); +static int fjes_poll(struct napi_struct *, int); + static const struct acpi_device_id fjes_acpi_ids[] = { {"PNP0C02", 0}, {"", 0}, @@ -235,6 +238,8 @@ static int fjes_open(struct net_device *netdev) hw->txrx_stop_req_bit = 0; hw->epstop_req_bit = 0; + napi_enable(&adapter->napi); + fjes_hw_capture_interrupt_status(hw); result = fjes_request_irq(adapter); @@ -250,6 +255,7 @@ static int fjes_open(struct net_device *netdev) err_req_irq: fjes_free_irq(adapter); + napi_disable(&adapter->napi); err_setup_res: fjes_free_resources(adapter); @@ -268,6 +274,8 @@ static int fjes_close(struct net_device *netdev) fjes_hw_raise_epstop(hw); + napi_disable(&adapter->napi); + for (epidx = 0; epidx < hw->max_epid; epidx++) { if (epidx == hw->my_epid) continue; @@ -701,14 +709,167 @@ static irqreturn_t fjes_intr(int irq, void *data) icr = fjes_hw_capture_interrupt_status(hw); - if (icr & REG_IS_MASK_IS_ASSERT) + if (icr & REG_IS_MASK_IS_ASSERT) { + if (icr & REG_ICTL_MASK_RX_DATA) + fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID); + ret = IRQ_HANDLED; - else + } else { ret = IRQ_NONE; + } return ret; } +static int fjes_rxframe_search_exist(struct fjes_adapter *adapter, + int start_epid) +{ + struct fjes_hw *hw = &adapter->hw; + enum ep_partner_status pstatus; + int max_epid, cur_epid; + int i; + + max_epid = hw->max_epid; + start_epid = (start_epid + 1 + max_epid) % max_epid; + + for (i = 0; i < max_epid; i++) { + cur_epid = (start_epid + i) % max_epid; + if (cur_epid == hw->my_epid) + continue; + + pstatus = fjes_hw_get_partner_ep_status(hw, cur_epid); + if (pstatus == EP_PARTNER_SHARED) { + if (!fjes_hw_epbuf_rx_is_empty( + &hw->ep_shm_info[cur_epid].rx)) + return cur_epid; + } + } + return -1; +} + +static void *fjes_rxframe_get(struct fjes_adapter *adapter, size_t *psize, + int *cur_epid) +{ + void *frame; + + *cur_epid = fjes_rxframe_search_exist(adapter, *cur_epid); + if (*cur_epid < 0) + return NULL; + + frame = + fjes_hw_epbuf_rx_curpkt_get_addr( + &adapter->hw.ep_shm_info[*cur_epid].rx, psize); + + return frame; +} + +static void fjes_rxframe_release(struct fjes_adapter *adapter, int cur_epid) +{ + fjes_hw_epbuf_rx_curpkt_drop(&adapter->hw.ep_shm_info[cur_epid].rx); +} + +static void fjes_rx_irq(struct fjes_adapter *adapter, int src_epid) +{ + struct fjes_hw *hw = &adapter->hw; + + fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, true); + + adapter->unset_rx_last = true; + napi_schedule(&adapter->napi); +} + +static int fjes_poll(struct napi_struct *napi, int budget) +{ + struct fjes_adapter *adapter = + container_of(napi, struct fjes_adapter, napi); + struct net_device *netdev = napi->dev; + struct fjes_hw *hw = &adapter->hw; + struct sk_buff *skb; + int work_done = 0; + int cur_epid = 0; + int epidx; + size_t frame_len; + void *frame; + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + adapter->hw.ep_shm_info[epidx].tx.info->v1i.rx_status |= + FJES_RX_POLL_WORK; + } + + while (work_done < budget) { + prefetch(&adapter->hw); + frame = fjes_rxframe_get(adapter, &frame_len, &cur_epid); + + if (frame) { + skb = napi_alloc_skb(napi, frame_len); + if (!skb) { + adapter->stats64.rx_dropped += 1; + hw->ep_shm_info[cur_epid].net_stats + .rx_dropped += 1; + adapter->stats64.rx_errors += 1; + hw->ep_shm_info[cur_epid].net_stats + .rx_errors += 1; + } else { + memcpy(skb_put(skb, frame_len), + frame, frame_len); + skb->protocol = eth_type_trans(skb, netdev); + skb->ip_summed = CHECKSUM_UNNECESSARY; + + netif_receive_skb(skb); + + work_done++; + + adapter->stats64.rx_packets += 1; + hw->ep_shm_info[cur_epid].net_stats + .rx_packets += 1; + adapter->stats64.rx_bytes += frame_len; + hw->ep_shm_info[cur_epid].net_stats + .rx_bytes += frame_len; + + if (is_multicast_ether_addr( + ((struct ethhdr *)frame)->h_dest)) { + adapter->stats64.multicast += 1; + hw->ep_shm_info[cur_epid].net_stats + .multicast += 1; + } + } + + fjes_rxframe_release(adapter, cur_epid); + adapter->unset_rx_last = true; + } else { + break; + } + } + + if (work_done < budget) { + napi_complete(napi); + + if (adapter->unset_rx_last) { + adapter->rx_last_jiffies = jiffies; + adapter->unset_rx_last = false; + } + + if (((long)jiffies - (long)adapter->rx_last_jiffies) < 3) { + napi_reschedule(napi); + } else { + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + adapter->hw.ep_shm_info[epidx] + .tx.info->v1i.rx_status &= + ~FJES_RX_POLL_WORK; + } + + fjes_hw_set_irqmask(hw, REG_ICTL_MASK_RX_DATA, false); + } + } + + return work_done; +} + /* fjes_probe - Device Initialization Routine */ static int fjes_probe(struct platform_device *plat_dev) { @@ -797,6 +958,8 @@ static int fjes_remove(struct platform_device *plat_dev) fjes_hw_exit(hw); + netif_napi_del(&adapter->napi); + free_netdev(netdev); return 0; @@ -804,6 +967,10 @@ static int fjes_remove(struct platform_device *plat_dev) static int fjes_sw_init(struct fjes_adapter *adapter) { + struct net_device *netdev = adapter->netdev; + + netif_napi_add(netdev, &adapter->napi, fjes_poll, 64); + return 0; } -- GitLab From 879bc9a3ea3b9015833b53f6ec114bb602a663a8 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:28 +0900 Subject: [PATCH 4712/7006] fjes: net_device_ops.ndo_get_stats64 This patch adds net_device_ops.ndo_get_stats64 callback. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_main.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 61949625176cc..20feb3e0aa64a 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -55,6 +55,8 @@ static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *); static void fjes_raise_intr_rxdata_task(struct work_struct *); static void fjes_tx_stall_task(struct work_struct *); static irqreturn_t fjes_intr(int, void*); +static struct rtnl_link_stats64 * +fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); static int fjes_acpi_add(struct acpi_device *); static int fjes_acpi_remove(struct acpi_device *); @@ -219,6 +221,7 @@ static const struct net_device_ops fjes_netdev_ops = { .ndo_open = fjes_open, .ndo_stop = fjes_close, .ndo_start_xmit = fjes_xmit_frame, + .ndo_get_stats64 = fjes_get_stats64, }; /* fjes_open - Called when a network interface is made active */ @@ -700,6 +703,16 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return ret; } +static struct rtnl_link_stats64 * +fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + + memcpy(stats, &adapter->stats64, sizeof(struct rtnl_link_stats64)); + + return stats; +} + static irqreturn_t fjes_intr(int irq, void *data) { struct fjes_adapter *adapter = data; -- GitLab From b9e23a67d52f956d75e6327a7fccbb53fbdc540b Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:29 +0900 Subject: [PATCH 4713/7006] fjes: net_device_ops.ndo_change_mtu This patch adds net_device_ops.ndo_change_mtu. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_main.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 20feb3e0aa64a..519976cd4d9e9 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -57,6 +57,7 @@ static void fjes_tx_stall_task(struct work_struct *); static irqreturn_t fjes_intr(int, void*); static struct rtnl_link_stats64 * fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); +static int fjes_change_mtu(struct net_device *, int); static int fjes_acpi_add(struct acpi_device *); static int fjes_acpi_remove(struct acpi_device *); @@ -222,6 +223,7 @@ static const struct net_device_ops fjes_netdev_ops = { .ndo_stop = fjes_close, .ndo_start_xmit = fjes_xmit_frame, .ndo_get_stats64 = fjes_get_stats64, + .ndo_change_mtu = fjes_change_mtu, }; /* fjes_open - Called when a network interface is made active */ @@ -713,6 +715,33 @@ fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) return stats; } +static int fjes_change_mtu(struct net_device *netdev, int new_mtu) +{ + bool running = netif_running(netdev); + int ret = 0; + int idx; + + for (idx = 0; fjes_support_mtu[idx] != 0; idx++) { + if (new_mtu <= fjes_support_mtu[idx]) { + new_mtu = fjes_support_mtu[idx]; + if (new_mtu == netdev->mtu) + return 0; + + if (running) + fjes_close(netdev); + + netdev->mtu = new_mtu; + + if (running) + ret = fjes_open(netdev); + + return ret; + } + } + + return -EINVAL; +} + static irqreturn_t fjes_intr(int irq, void *data) { struct fjes_adapter *adapter = data; -- GitLab From 4393e767aee706944dbdf3aa91810a0c981b6710 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:30 +0900 Subject: [PATCH 4714/7006] fjes: net_device_ops.ndo_tx_timeout This patch adds net_device_ops.ndo_tx_timeout callback. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_main.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 519976cd4d9e9..94ccc115020b4 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -58,6 +58,7 @@ static irqreturn_t fjes_intr(int, void*); static struct rtnl_link_stats64 * fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); static int fjes_change_mtu(struct net_device *, int); +static void fjes_tx_retry(struct net_device *); static int fjes_acpi_add(struct acpi_device *); static int fjes_acpi_remove(struct acpi_device *); @@ -224,6 +225,7 @@ static const struct net_device_ops fjes_netdev_ops = { .ndo_start_xmit = fjes_xmit_frame, .ndo_get_stats64 = fjes_get_stats64, .ndo_change_mtu = fjes_change_mtu, + .ndo_tx_timeout = fjes_tx_retry, }; /* fjes_open - Called when a network interface is made active */ @@ -705,6 +707,13 @@ fjes_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return ret; } +static void fjes_tx_retry(struct net_device *netdev) +{ + struct netdev_queue *queue = netdev_get_tx_queue(netdev, 0); + + netif_tx_wake_queue(queue); +} + static struct rtnl_link_stats64 * fjes_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { -- GitLab From 3e3fedda31798cff2cb5358e15263b8799c1e72c Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:31 +0900 Subject: [PATCH 4715/7006] fjes: net_device_ops.ndo_vlan_rx_add/kill_vid This patch adds net_device_ops.ndo_vlan_rx_add_vid and net_device_ops.ndo_vlan_rx_kill_vid callback. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 27 ++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 2 ++ drivers/net/fjes/fjes_main.c | 40 ++++++++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 3c96d06d15cfd..4a4b750fdb9cc 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -825,6 +825,33 @@ bool fjes_hw_check_vlan_id(struct epbuf_handler *epbh, u16 vlan_id) return ret; } +bool fjes_hw_set_vlan_id(struct epbuf_handler *epbh, u16 vlan_id) +{ + union ep_buffer_info *info = epbh->info; + int i; + + for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) { + if (info->v1i.vlan_id[i] == 0) { + info->v1i.vlan_id[i] = vlan_id; + return true; + } + } + return false; +} + +void fjes_hw_del_vlan_id(struct epbuf_handler *epbh, u16 vlan_id) +{ + union ep_buffer_info *info = epbh->info; + int i; + + if (0 != vlan_id) { + for (i = 0; i < EP_BUFFER_SUPPORT_VLAN_MAX; i++) { + if (vlan_id == info->v1i.vlan_id[i]) + info->v1i.vlan_id[i] = 0; + } + } +} + bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *epbh) { union ep_buffer_info *info = epbh->info; diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 3511db2f7eb07..95e632b363c1a 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -322,6 +322,8 @@ int fjes_hw_epid_is_shared(struct fjes_device_shared_info *, int); bool fjes_hw_check_epbuf_version(struct epbuf_handler *, u32); bool fjes_hw_check_mtu(struct epbuf_handler *, u32); bool fjes_hw_check_vlan_id(struct epbuf_handler *, u16); +bool fjes_hw_set_vlan_id(struct epbuf_handler *, u16); +void fjes_hw_del_vlan_id(struct epbuf_handler *, u16); bool fjes_hw_epbuf_rx_is_empty(struct epbuf_handler *); void *fjes_hw_epbuf_rx_curpkt_get_addr(struct epbuf_handler *, size_t *); void fjes_hw_epbuf_rx_curpkt_drop(struct epbuf_handler *); diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 94ccc115020b4..4a4ce8144023d 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -58,6 +58,8 @@ static irqreturn_t fjes_intr(int, void*); static struct rtnl_link_stats64 * fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); static int fjes_change_mtu(struct net_device *, int); +static int fjes_vlan_rx_add_vid(struct net_device *, __be16 proto, u16); +static int fjes_vlan_rx_kill_vid(struct net_device *, __be16 proto, u16); static void fjes_tx_retry(struct net_device *); static int fjes_acpi_add(struct acpi_device *); @@ -226,6 +228,8 @@ static const struct net_device_ops fjes_netdev_ops = { .ndo_get_stats64 = fjes_get_stats64, .ndo_change_mtu = fjes_change_mtu, .ndo_tx_timeout = fjes_tx_retry, + .ndo_vlan_rx_add_vid = fjes_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = fjes_vlan_rx_kill_vid, }; /* fjes_open - Called when a network interface is made active */ @@ -751,6 +755,42 @@ static int fjes_change_mtu(struct net_device *netdev, int new_mtu) return -EINVAL; } +static int fjes_vlan_rx_add_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + bool ret = true; + int epid; + + for (epid = 0; epid < adapter->hw.max_epid; epid++) { + if (epid == adapter->hw.my_epid) + continue; + + if (!fjes_hw_check_vlan_id( + &adapter->hw.ep_shm_info[epid].tx, vid)) + ret = fjes_hw_set_vlan_id( + &adapter->hw.ep_shm_info[epid].tx, vid); + } + + return ret ? 0 : -ENOSPC; +} + +static int fjes_vlan_rx_kill_vid(struct net_device *netdev, + __be16 proto, u16 vid) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + int epid; + + for (epid = 0; epid < adapter->hw.max_epid; epid++) { + if (epid == adapter->hw.my_epid) + continue; + + fjes_hw_del_vlan_id(&adapter->hw.ep_shm_info[epid].tx, vid); + } + + return 0; +} + static irqreturn_t fjes_intr(int irq, void *data) { struct fjes_adapter *adapter = data; -- GitLab From 8edb62a8131ca5b5ecbb29e45d812d9583585afb Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:32 +0900 Subject: [PATCH 4716/7006] fjes: interrupt_watch_task This patch adds interrupt_watch_task. This task is used to prevent delay of interrupts. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 5 +++++ drivers/net/fjes/fjes_main.c | 40 +++++++++++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index b04ea9dcab438..1743dbb83e5bf 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -32,6 +32,7 @@ #define FJES_TX_RETRY_TIMEOUT (100) #define FJES_TX_TX_STALL_TIMEOUT (FJES_TX_RETRY_INTERVAL / 2) #define FJES_OPEN_ZONE_UPDATE_WAIT (300) /* msec */ +#define FJES_IRQ_WATCH_DELAY (HZ) /* board specific private data structure */ struct fjes_adapter { @@ -52,10 +53,14 @@ struct fjes_adapter { bool irq_registered; struct workqueue_struct *txrx_wq; + struct workqueue_struct *control_wq; struct work_struct tx_stall_task; struct work_struct raise_intr_rxdata_task; + struct delayed_work interrupt_watch_task; + bool interrupt_watch_enable; + struct fjes_hw hw; }; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 4a4ce8144023d..5fce33dec8207 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -71,7 +71,7 @@ static int fjes_remove(struct platform_device *); static int fjes_sw_init(struct fjes_adapter *); static void fjes_netdev_setup(struct net_device *); - +static void fjes_irq_watch_task(struct work_struct *); static void fjes_rx_irq(struct fjes_adapter *, int); static int fjes_poll(struct napi_struct *, int); @@ -197,6 +197,13 @@ static int fjes_request_irq(struct fjes_adapter *adapter) struct net_device *netdev = adapter->netdev; int result = -1; + adapter->interrupt_watch_enable = true; + if (!delayed_work_pending(&adapter->interrupt_watch_task)) { + queue_delayed_work(adapter->control_wq, + &adapter->interrupt_watch_task, + FJES_IRQ_WATCH_DELAY); + } + if (!adapter->irq_registered) { result = request_irq(adapter->hw.hw_res.irq, fjes_intr, IRQF_SHARED, netdev->name, adapter); @@ -213,6 +220,9 @@ static void fjes_free_irq(struct fjes_adapter *adapter) { struct fjes_hw *hw = &adapter->hw; + adapter->interrupt_watch_enable = false; + cancel_delayed_work_sync(&adapter->interrupt_watch_task); + fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); if (adapter->irq_registered) { @@ -297,6 +307,7 @@ static int fjes_close(struct net_device *netdev) fjes_free_irq(adapter); + cancel_delayed_work_sync(&adapter->interrupt_watch_task); cancel_work_sync(&adapter->raise_intr_rxdata_task); cancel_work_sync(&adapter->tx_stall_task); @@ -996,11 +1007,15 @@ static int fjes_probe(struct platform_device *plat_dev) adapter->open_guard = false; adapter->txrx_wq = create_workqueue(DRV_NAME "/txrx"); + adapter->control_wq = create_workqueue(DRV_NAME "/control"); INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task); INIT_WORK(&adapter->raise_intr_rxdata_task, fjes_raise_intr_rxdata_task); + INIT_DELAYED_WORK(&adapter->interrupt_watch_task, fjes_irq_watch_task); + adapter->interrupt_watch_enable = false; + res = platform_get_resource(plat_dev, IORESOURCE_MEM, 0); hw->hw_res.start = res->start; hw->hw_res.size = res->end - res->start + 1; @@ -1040,8 +1055,11 @@ static int fjes_remove(struct platform_device *plat_dev) struct fjes_adapter *adapter = netdev_priv(netdev); struct fjes_hw *hw = &adapter->hw; + cancel_delayed_work_sync(&adapter->interrupt_watch_task); cancel_work_sync(&adapter->raise_intr_rxdata_task); cancel_work_sync(&adapter->tx_stall_task); + if (adapter->control_wq) + destroy_workqueue(adapter->control_wq); if (adapter->txrx_wq) destroy_workqueue(adapter->txrx_wq); @@ -1077,6 +1095,26 @@ static void fjes_netdev_setup(struct net_device *netdev) netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER; } +static void fjes_irq_watch_task(struct work_struct *work) +{ + struct fjes_adapter *adapter = container_of(to_delayed_work(work), + struct fjes_adapter, interrupt_watch_task); + + local_irq_disable(); + fjes_intr(adapter->hw.hw_res.irq, adapter); + local_irq_enable(); + + if (fjes_rxframe_search_exist(adapter, 0) >= 0) + napi_schedule(&adapter->napi); + + if (adapter->interrupt_watch_enable) { + if (!delayed_work_pending(&adapter->interrupt_watch_task)) + queue_delayed_work(adapter->control_wq, + &adapter->interrupt_watch_task, + FJES_IRQ_WATCH_DELAY); + } +} + /* fjes_init_module - Driver Registration Routine */ static int __init fjes_init_module(void) { -- GitLab From ff5b42103227c01c4082f27b06a43758efbf5ab8 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:33 +0900 Subject: [PATCH 4717/7006] fjes: force_close_task This patch adds force_close_task. This task is used to close network device forcibly. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 1 + drivers/net/fjes/fjes_main.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 1743dbb83e5bf..d31d4c3be45ff 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -47,6 +47,7 @@ struct fjes_adapter { unsigned long rx_last_jiffies; bool unset_rx_last; + struct work_struct force_close_task; bool force_reset; bool open_guard; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 5fce33dec8207..caecfb39ecf99 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -54,6 +54,7 @@ static void fjes_free_resources(struct fjes_adapter *); static netdev_tx_t fjes_xmit_frame(struct sk_buff *, struct net_device *); static void fjes_raise_intr_rxdata_task(struct work_struct *); static void fjes_tx_stall_task(struct work_struct *); +static void fjes_force_close_task(struct work_struct *); static irqreturn_t fjes_intr(int, void*); static struct rtnl_link_stats64 * fjes_get_stats64(struct net_device *, struct rtnl_link_stats64 *); @@ -492,6 +493,17 @@ static void fjes_tx_stall_task(struct work_struct *work) queue_work(adapter->txrx_wq, &adapter->tx_stall_task); } +static void fjes_force_close_task(struct work_struct *work) +{ + struct fjes_adapter *adapter = container_of(work, + struct fjes_adapter, force_close_task); + struct net_device *netdev = adapter->netdev; + + rtnl_lock(); + dev_close(netdev); + rtnl_unlock(); +} + static void fjes_raise_intr_rxdata_task(struct work_struct *work) { struct fjes_adapter *adapter = container_of(work, @@ -1003,6 +1015,7 @@ static int fjes_probe(struct platform_device *plat_dev) if (err) goto err_free_netdev; + INIT_WORK(&adapter->force_close_task, fjes_force_close_task); adapter->force_reset = false; adapter->open_guard = false; -- GitLab From 8fc4cadb98c6a0f1eecde678271fcc957258af3e Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:34 +0900 Subject: [PATCH 4718/7006] fjes: unshare_watch_task This patch adds unshare_watch_task. Shared buffer's status can be changed into unshared. This task is used to monitor shared buffer's status. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes.h | 3 + drivers/net/fjes/fjes_main.c | 126 +++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+) diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index d31d4c3be45ff..57feee84332d8 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -59,6 +59,9 @@ struct fjes_adapter { struct work_struct tx_stall_task; struct work_struct raise_intr_rxdata_task; + struct work_struct unshare_watch_task; + unsigned long unshare_watch_bitmask; + struct delayed_work interrupt_watch_task; bool interrupt_watch_enable; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index caecfb39ecf99..c47ecf35d0058 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -73,6 +73,7 @@ static int fjes_remove(struct platform_device *); static int fjes_sw_init(struct fjes_adapter *); static void fjes_netdev_setup(struct net_device *); static void fjes_irq_watch_task(struct work_struct *); +static void fjes_watch_unshare_task(struct work_struct *); static void fjes_rx_irq(struct fjes_adapter *, int); static int fjes_poll(struct napi_struct *, int); @@ -309,6 +310,8 @@ static int fjes_close(struct net_device *netdev) fjes_free_irq(adapter); cancel_delayed_work_sync(&adapter->interrupt_watch_task); + cancel_work_sync(&adapter->unshare_watch_task); + adapter->unshare_watch_bitmask = 0; cancel_work_sync(&adapter->raise_intr_rxdata_task); cancel_work_sync(&adapter->tx_stall_task); @@ -1025,6 +1028,8 @@ static int fjes_probe(struct platform_device *plat_dev) INIT_WORK(&adapter->tx_stall_task, fjes_tx_stall_task); INIT_WORK(&adapter->raise_intr_rxdata_task, fjes_raise_intr_rxdata_task); + INIT_WORK(&adapter->unshare_watch_task, fjes_watch_unshare_task); + adapter->unshare_watch_bitmask = 0; INIT_DELAYED_WORK(&adapter->interrupt_watch_task, fjes_irq_watch_task); adapter->interrupt_watch_enable = false; @@ -1069,6 +1074,7 @@ static int fjes_remove(struct platform_device *plat_dev) struct fjes_hw *hw = &adapter->hw; cancel_delayed_work_sync(&adapter->interrupt_watch_task); + cancel_work_sync(&adapter->unshare_watch_task); cancel_work_sync(&adapter->raise_intr_rxdata_task); cancel_work_sync(&adapter->tx_stall_task); if (adapter->control_wq) @@ -1128,6 +1134,126 @@ static void fjes_irq_watch_task(struct work_struct *work) } } +static void fjes_watch_unshare_task(struct work_struct *work) +{ + struct fjes_adapter *adapter = + container_of(work, struct fjes_adapter, unshare_watch_task); + + struct net_device *netdev = adapter->netdev; + struct fjes_hw *hw = &adapter->hw; + + int unshare_watch, unshare_reserve; + int max_epid, my_epid, epidx; + int stop_req, stop_req_done; + ulong unshare_watch_bitmask; + int wait_time = 0; + int is_shared; + int ret; + + my_epid = hw->my_epid; + max_epid = hw->max_epid; + + unshare_watch_bitmask = adapter->unshare_watch_bitmask; + adapter->unshare_watch_bitmask = 0; + + while ((unshare_watch_bitmask || hw->txrx_stop_req_bit) && + (wait_time < 3000)) { + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + is_shared = fjes_hw_epid_is_shared(hw->hw_info.share, + epidx); + + stop_req = test_bit(epidx, &hw->txrx_stop_req_bit); + + stop_req_done = hw->ep_shm_info[epidx].rx.info->v1i.rx_status & + FJES_RX_STOP_REQ_DONE; + + unshare_watch = test_bit(epidx, &unshare_watch_bitmask); + + unshare_reserve = test_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit); + + if ((!stop_req || + (is_shared && (!is_shared || !stop_req_done))) && + (is_shared || !unshare_watch || !unshare_reserve)) + continue; + + mutex_lock(&hw->hw_info.lock); + ret = fjes_hw_unregister_buff_addr(hw, epidx); + switch (ret) { + case 0: + break; + case -ENOMSG: + case -EBUSY: + default: + if (!work_pending( + &adapter->force_close_task)) { + adapter->force_reset = true; + schedule_work( + &adapter->force_close_task); + } + break; + } + mutex_unlock(&hw->hw_info.lock); + + fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx, + netdev->dev_addr, netdev->mtu); + + clear_bit(epidx, &hw->txrx_stop_req_bit); + clear_bit(epidx, &unshare_watch_bitmask); + clear_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit); + } + + msleep(100); + wait_time += 100; + } + + if (hw->hw_info.buffer_unshare_reserve_bit) { + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + if (test_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit)) { + mutex_lock(&hw->hw_info.lock); + + ret = fjes_hw_unregister_buff_addr(hw, epidx); + switch (ret) { + case 0: + break; + case -ENOMSG: + case -EBUSY: + default: + if (!work_pending( + &adapter->force_close_task)) { + adapter->force_reset = true; + schedule_work( + &adapter->force_close_task); + } + break; + } + mutex_unlock(&hw->hw_info.lock); + + fjes_hw_setup_epbuf( + &hw->ep_shm_info[epidx].tx, + netdev->dev_addr, netdev->mtu); + + clear_bit(epidx, &hw->txrx_stop_req_bit); + clear_bit(epidx, &unshare_watch_bitmask); + clear_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit); + } + + if (test_bit(epidx, &unshare_watch_bitmask)) { + hw->ep_shm_info[epidx].tx.info->v1i.rx_status &= + ~FJES_RX_STOP_REQ_DONE; + } + } + } +} + /* fjes_init_module - Driver Registration Routine */ static int __init fjes_init_module(void) { -- GitLab From 785f28e061a870eba937cb2a860cbcf631f5ebb0 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:35 +0900 Subject: [PATCH 4719/7006] fjes: update_zone_task This patch adds update_zone_task. Zoning information can be changed by user. This task is used to monitor if zoning information is changed or not. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 179 +++++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 1 + drivers/net/fjes/fjes_main.c | 14 +++ 3 files changed, 194 insertions(+) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 4a4b750fdb9cc..4525d3664ccff 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -22,6 +22,8 @@ #include "fjes_hw.h" #include "fjes.h" +static void fjes_hw_update_zone_task(struct work_struct *); + /* supported MTU list */ const u32 fjes_support_mtu[] = { FJES_MTU_DEFINE(8 * 1024), @@ -322,6 +324,8 @@ int fjes_hw_init(struct fjes_hw *hw) fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); + INIT_WORK(&hw->update_zone_task, fjes_hw_update_zone_task); + mutex_init(&hw->hw_info.lock); hw->max_epid = fjes_hw_get_max_epid(hw); @@ -349,6 +353,8 @@ void fjes_hw_exit(struct fjes_hw *hw) } fjes_hw_cleanup(hw); + + cancel_work_sync(&hw->update_zone_task); } static enum fjes_dev_command_response_e @@ -913,3 +919,176 @@ int fjes_hw_epbuf_tx_pkt_send(struct epbuf_handler *epbh, return 0; } + +static void fjes_hw_update_zone_task(struct work_struct *work) +{ + struct fjes_hw *hw = container_of(work, + struct fjes_hw, update_zone_task); + + struct my_s {u8 es_status; u8 zone; } *info; + union fjes_device_command_res *res_buf; + enum ep_partner_status pstatus; + + struct fjes_adapter *adapter; + struct net_device *netdev; + + ulong unshare_bit = 0; + ulong share_bit = 0; + ulong irq_bit = 0; + + int epidx; + int ret; + + adapter = (struct fjes_adapter *)hw->back; + netdev = adapter->netdev; + res_buf = hw->hw_info.res_buf; + info = (struct my_s *)&res_buf->info.info; + + mutex_lock(&hw->hw_info.lock); + + ret = fjes_hw_request_info(hw); + switch (ret) { + case -ENOMSG: + case -EBUSY: + default: + if (!work_pending(&adapter->force_close_task)) { + adapter->force_reset = true; + schedule_work(&adapter->force_close_task); + } + break; + + case 0: + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) { + hw->ep_shm_info[epidx].es_status = + info[epidx].es_status; + hw->ep_shm_info[epidx].zone = + info[epidx].zone; + continue; + } + + pstatus = fjes_hw_get_partner_ep_status(hw, epidx); + switch (pstatus) { + case EP_PARTNER_UNSHARE: + default: + if ((info[epidx].zone != + FJES_ZONING_ZONE_TYPE_NONE) && + (info[epidx].es_status == + FJES_ZONING_STATUS_ENABLE) && + (info[epidx].zone == + info[hw->my_epid].zone)) + set_bit(epidx, &share_bit); + else + set_bit(epidx, &unshare_bit); + break; + + case EP_PARTNER_COMPLETE: + case EP_PARTNER_WAITING: + if ((info[epidx].zone == + FJES_ZONING_ZONE_TYPE_NONE) || + (info[epidx].es_status != + FJES_ZONING_STATUS_ENABLE) || + (info[epidx].zone != + info[hw->my_epid].zone)) { + set_bit(epidx, + &adapter->unshare_watch_bitmask); + set_bit(epidx, + &hw->hw_info.buffer_unshare_reserve_bit); + } + break; + + case EP_PARTNER_SHARED: + if ((info[epidx].zone == + FJES_ZONING_ZONE_TYPE_NONE) || + (info[epidx].es_status != + FJES_ZONING_STATUS_ENABLE) || + (info[epidx].zone != + info[hw->my_epid].zone)) + set_bit(epidx, &irq_bit); + break; + } + } + + hw->ep_shm_info[epidx].es_status = info[epidx].es_status; + hw->ep_shm_info[epidx].zone = info[epidx].zone; + + break; + } + + mutex_unlock(&hw->hw_info.lock); + + for (epidx = 0; epidx < hw->max_epid; epidx++) { + if (epidx == hw->my_epid) + continue; + + if (test_bit(epidx, &share_bit)) { + fjes_hw_setup_epbuf(&hw->ep_shm_info[epidx].tx, + netdev->dev_addr, netdev->mtu); + + mutex_lock(&hw->hw_info.lock); + + ret = fjes_hw_register_buff_addr( + hw, epidx, &hw->ep_shm_info[epidx]); + + switch (ret) { + case 0: + break; + case -ENOMSG: + case -EBUSY: + default: + if (!work_pending(&adapter->force_close_task)) { + adapter->force_reset = true; + schedule_work( + &adapter->force_close_task); + } + break; + } + mutex_unlock(&hw->hw_info.lock); + } + + if (test_bit(epidx, &unshare_bit)) { + mutex_lock(&hw->hw_info.lock); + + ret = fjes_hw_unregister_buff_addr(hw, epidx); + + switch (ret) { + case 0: + break; + case -ENOMSG: + case -EBUSY: + default: + if (!work_pending(&adapter->force_close_task)) { + adapter->force_reset = true; + schedule_work( + &adapter->force_close_task); + } + break; + } + + mutex_unlock(&hw->hw_info.lock); + + if (ret == 0) + fjes_hw_setup_epbuf( + &hw->ep_shm_info[epidx].tx, + netdev->dev_addr, netdev->mtu); + } + + if (test_bit(epidx, &irq_bit)) { + fjes_hw_raise_interrupt(hw, epidx, + REG_ICTL_MASK_TXRX_STOP_REQ); + + set_bit(epidx, &hw->txrx_stop_req_bit); + hw->ep_shm_info[epidx].tx. + info->v1i.rx_status |= + FJES_RX_STOP_REQ_REQUEST; + set_bit(epidx, &hw->hw_info.buffer_unshare_reserve_bit); + } + } + + if (irq_bit || adapter->unshare_watch_bitmask) { + if (!work_pending(&adapter->unshare_watch_task)) + queue_work(adapter->control_wq, + &adapter->unshare_watch_task); + } +} diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index 95e632b363c1a..e59b737b45e73 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -282,6 +282,7 @@ struct fjes_hw { unsigned long txrx_stop_req_bit; unsigned long epstop_req_bit; + struct work_struct update_zone_task; int my_epid; int max_epid; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index c47ecf35d0058..8e3a084277c00 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -315,6 +315,8 @@ static int fjes_close(struct net_device *netdev) cancel_work_sync(&adapter->raise_intr_rxdata_task); cancel_work_sync(&adapter->tx_stall_task); + cancel_work_sync(&hw->update_zone_task); + fjes_hw_wait_epstop(hw); fjes_free_resources(adapter); @@ -817,6 +819,15 @@ static int fjes_vlan_rx_kill_vid(struct net_device *netdev, return 0; } +static void fjes_update_zone_irq(struct fjes_adapter *adapter, + int src_epid) +{ + struct fjes_hw *hw = &adapter->hw; + + if (!work_pending(&hw->update_zone_task)) + queue_work(adapter->control_wq, &hw->update_zone_task); +} + static irqreturn_t fjes_intr(int irq, void *data) { struct fjes_adapter *adapter = data; @@ -830,6 +841,9 @@ static irqreturn_t fjes_intr(int irq, void *data) if (icr & REG_ICTL_MASK_RX_DATA) fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID); + if (icr & REG_ICTL_MASK_INFO_UPDATE) + fjes_update_zone_irq(adapter, icr & REG_IS_MASK_EPID); + ret = IRQ_HANDLED; } else { ret = IRQ_NONE; -- GitLab From b5a9152d993a4f08d6e08ac0dde3a09993dc9c45 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:36 +0900 Subject: [PATCH 4720/7006] fjes: epstop_task This patch adds epstop_task. This task is used to process other receiver's cancellation request. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_hw.c | 31 +++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_hw.h | 1 + drivers/net/fjes/fjes_main.c | 1 + 3 files changed, 33 insertions(+) diff --git a/drivers/net/fjes/fjes_hw.c b/drivers/net/fjes/fjes_hw.c index 4525d3664ccff..b5f4a78da8283 100644 --- a/drivers/net/fjes/fjes_hw.c +++ b/drivers/net/fjes/fjes_hw.c @@ -23,6 +23,7 @@ #include "fjes.h" static void fjes_hw_update_zone_task(struct work_struct *); +static void fjes_hw_epstop_task(struct work_struct *); /* supported MTU list */ const u32 fjes_support_mtu[] = { @@ -325,6 +326,7 @@ int fjes_hw_init(struct fjes_hw *hw) fjes_hw_set_irqmask(hw, REG_ICTL_MASK_ALL, true); INIT_WORK(&hw->update_zone_task, fjes_hw_update_zone_task); + INIT_WORK(&hw->epstop_task, fjes_hw_epstop_task); mutex_init(&hw->hw_info.lock); @@ -355,6 +357,7 @@ void fjes_hw_exit(struct fjes_hw *hw) fjes_hw_cleanup(hw); cancel_work_sync(&hw->update_zone_task); + cancel_work_sync(&hw->epstop_task); } static enum fjes_dev_command_response_e @@ -1092,3 +1095,31 @@ static void fjes_hw_update_zone_task(struct work_struct *work) &adapter->unshare_watch_task); } } + +static void fjes_hw_epstop_task(struct work_struct *work) +{ + struct fjes_hw *hw = container_of(work, struct fjes_hw, epstop_task); + struct fjes_adapter *adapter = (struct fjes_adapter *)hw->back; + + ulong remain_bit; + int epid_bit; + + while ((remain_bit = hw->epstop_req_bit)) { + for (epid_bit = 0; remain_bit; remain_bit >>= 1, epid_bit++) { + if (remain_bit & 1) { + hw->ep_shm_info[epid_bit]. + tx.info->v1i.rx_status |= + FJES_RX_STOP_REQ_DONE; + + clear_bit(epid_bit, &hw->epstop_req_bit); + set_bit(epid_bit, + &adapter->unshare_watch_bitmask); + + if (!work_pending(&adapter->unshare_watch_task)) + queue_work( + adapter->control_wq, + &adapter->unshare_watch_task); + } + } + } +} diff --git a/drivers/net/fjes/fjes_hw.h b/drivers/net/fjes/fjes_hw.h index e59b737b45e73..6d57b89a0ee84 100644 --- a/drivers/net/fjes/fjes_hw.h +++ b/drivers/net/fjes/fjes_hw.h @@ -283,6 +283,7 @@ struct fjes_hw { unsigned long txrx_stop_req_bit; unsigned long epstop_req_bit; struct work_struct update_zone_task; + struct work_struct epstop_task; int my_epid; int max_epid; diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 8e3a084277c00..5e77d0cda8250 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -316,6 +316,7 @@ static int fjes_close(struct net_device *netdev) cancel_work_sync(&adapter->tx_stall_task); cancel_work_sync(&hw->update_zone_task); + cancel_work_sync(&hw->epstop_task); fjes_hw_wait_epstop(hw); -- GitLab From cb79eaaec4c1046e4b3d55c27aee48774c5ff936 Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:37 +0900 Subject: [PATCH 4721/7006] fjes: handle receive cancellation request interrupt This patch adds implementation of handling IRQ of other receiver's receive cancellation request. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/fjes_main.c | 78 ++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 5e77d0cda8250..5f93e42f5cce3 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -820,6 +820,74 @@ static int fjes_vlan_rx_kill_vid(struct net_device *netdev, return 0; } +static void fjes_txrx_stop_req_irq(struct fjes_adapter *adapter, + int src_epid) +{ + struct fjes_hw *hw = &adapter->hw; + enum ep_partner_status status; + + status = fjes_hw_get_partner_ep_status(hw, src_epid); + switch (status) { + case EP_PARTNER_UNSHARE: + case EP_PARTNER_COMPLETE: + default: + break; + case EP_PARTNER_WAITING: + if (src_epid < hw->my_epid) { + hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |= + FJES_RX_STOP_REQ_DONE; + + clear_bit(src_epid, &hw->txrx_stop_req_bit); + set_bit(src_epid, &adapter->unshare_watch_bitmask); + + if (!work_pending(&adapter->unshare_watch_task)) + queue_work(adapter->control_wq, + &adapter->unshare_watch_task); + } + break; + case EP_PARTNER_SHARED: + if (hw->ep_shm_info[src_epid].rx.info->v1i.rx_status & + FJES_RX_STOP_REQ_REQUEST) { + set_bit(src_epid, &hw->epstop_req_bit); + if (!work_pending(&hw->epstop_task)) + queue_work(adapter->control_wq, + &hw->epstop_task); + } + break; + } +} + +static void fjes_stop_req_irq(struct fjes_adapter *adapter, int src_epid) +{ + struct fjes_hw *hw = &adapter->hw; + enum ep_partner_status status; + + set_bit(src_epid, &hw->hw_info.buffer_unshare_reserve_bit); + + status = fjes_hw_get_partner_ep_status(hw, src_epid); + switch (status) { + case EP_PARTNER_WAITING: + hw->ep_shm_info[src_epid].tx.info->v1i.rx_status |= + FJES_RX_STOP_REQ_DONE; + clear_bit(src_epid, &hw->txrx_stop_req_bit); + /* fall through */ + case EP_PARTNER_UNSHARE: + case EP_PARTNER_COMPLETE: + default: + set_bit(src_epid, &adapter->unshare_watch_bitmask); + if (!work_pending(&adapter->unshare_watch_task)) + queue_work(adapter->control_wq, + &adapter->unshare_watch_task); + break; + case EP_PARTNER_SHARED: + set_bit(src_epid, &hw->epstop_req_bit); + + if (!work_pending(&hw->epstop_task)) + queue_work(adapter->control_wq, &hw->epstop_task); + break; + } +} + static void fjes_update_zone_irq(struct fjes_adapter *adapter, int src_epid) { @@ -842,6 +910,16 @@ static irqreturn_t fjes_intr(int irq, void *data) if (icr & REG_ICTL_MASK_RX_DATA) fjes_rx_irq(adapter, icr & REG_IS_MASK_EPID); + if (icr & REG_ICTL_MASK_DEV_STOP_REQ) + fjes_stop_req_irq(adapter, icr & REG_IS_MASK_EPID); + + if (icr & REG_ICTL_MASK_TXRX_STOP_REQ) + fjes_txrx_stop_req_irq(adapter, icr & REG_IS_MASK_EPID); + + if (icr & REG_ICTL_MASK_TXRX_STOP_DONE) + fjes_hw_set_irqmask(hw, + REG_ICTL_MASK_TXRX_STOP_DONE, true); + if (icr & REG_ICTL_MASK_INFO_UPDATE) fjes_update_zone_irq(adapter, icr & REG_IS_MASK_EPID); -- GitLab From 786eec27cbb1713caf3b33538a877a21e779d3bc Mon Sep 17 00:00:00 2001 From: Taku Izumi Date: Fri, 21 Aug 2015 17:29:38 +0900 Subject: [PATCH 4722/7006] fjes: ethtool support This patch adds implementation for ethtool support. Signed-off-by: Taku Izumi Signed-off-by: David S. Miller --- drivers/net/fjes/Makefile | 2 +- drivers/net/fjes/fjes.h | 2 + drivers/net/fjes/fjes_ethtool.c | 137 ++++++++++++++++++++++++++++++++ drivers/net/fjes/fjes_main.c | 1 + 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 drivers/net/fjes/fjes_ethtool.c diff --git a/drivers/net/fjes/Makefile b/drivers/net/fjes/Makefile index 753d52f1be332..523e3d7cf7aa4 100644 --- a/drivers/net/fjes/Makefile +++ b/drivers/net/fjes/Makefile @@ -27,4 +27,4 @@ obj-$(CONFIG_FUJITSU_ES) += fjes.o -fjes-objs := fjes_main.o fjes_hw.o +fjes-objs := fjes_main.o fjes_hw.o fjes_ethtool.o diff --git a/drivers/net/fjes/fjes.h b/drivers/net/fjes/fjes.h index 57feee84332d8..a592fe21c698f 100644 --- a/drivers/net/fjes/fjes.h +++ b/drivers/net/fjes/fjes.h @@ -72,4 +72,6 @@ extern char fjes_driver_name[]; extern char fjes_driver_version[]; extern const u32 fjes_support_mtu[]; +void fjes_set_ethtool_ops(struct net_device *); + #endif /* FJES_H_ */ diff --git a/drivers/net/fjes/fjes_ethtool.c b/drivers/net/fjes/fjes_ethtool.c new file mode 100644 index 0000000000000..0119dd199276b --- /dev/null +++ b/drivers/net/fjes/fjes_ethtool.c @@ -0,0 +1,137 @@ +/* + * FUJITSU Extended Socket Network Device driver + * Copyright (c) 2015 FUJITSU LIMITED + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, see . + * + * The full GNU General Public License is included in this distribution in + * the file called "COPYING". + * + */ + +/* ethtool support for fjes */ + +#include +#include +#include +#include + +#include "fjes.h" + +struct fjes_stats { + char stat_string[ETH_GSTRING_LEN]; + int sizeof_stat; + int stat_offset; +}; + +#define FJES_STAT(name, stat) { \ + .stat_string = name, \ + .sizeof_stat = FIELD_SIZEOF(struct fjes_adapter, stat), \ + .stat_offset = offsetof(struct fjes_adapter, stat) \ +} + +static const struct fjes_stats fjes_gstrings_stats[] = { + FJES_STAT("rx_packets", stats64.rx_packets), + FJES_STAT("tx_packets", stats64.tx_packets), + FJES_STAT("rx_bytes", stats64.rx_bytes), + FJES_STAT("tx_bytes", stats64.rx_bytes), + FJES_STAT("rx_dropped", stats64.rx_dropped), + FJES_STAT("tx_dropped", stats64.tx_dropped), +}; + +static void fjes_get_ethtool_stats(struct net_device *netdev, + struct ethtool_stats *stats, u64 *data) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + char *p; + int i; + + for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) { + p = (char *)adapter + fjes_gstrings_stats[i].stat_offset; + data[i] = (fjes_gstrings_stats[i].sizeof_stat == sizeof(u64)) + ? *(u64 *)p : *(u32 *)p; + } +} + +static void fjes_get_strings(struct net_device *netdev, + u32 stringset, u8 *data) +{ + u8 *p = data; + int i; + + switch (stringset) { + case ETH_SS_STATS: + for (i = 0; i < ARRAY_SIZE(fjes_gstrings_stats); i++) { + memcpy(p, fjes_gstrings_stats[i].stat_string, + ETH_GSTRING_LEN); + p += ETH_GSTRING_LEN; + } + break; + } +} + +static int fjes_get_sset_count(struct net_device *netdev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return ARRAY_SIZE(fjes_gstrings_stats); + default: + return -EOPNOTSUPP; + } +} + +static void fjes_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct fjes_adapter *adapter = netdev_priv(netdev); + struct platform_device *plat_dev; + + plat_dev = adapter->plat_dev; + + strlcpy(drvinfo->driver, fjes_driver_name, sizeof(drvinfo->driver)); + strlcpy(drvinfo->version, fjes_driver_version, + sizeof(drvinfo->version)); + + strlcpy(drvinfo->fw_version, "none", sizeof(drvinfo->fw_version)); + snprintf(drvinfo->bus_info, sizeof(drvinfo->bus_info), + "platform:%s", plat_dev->name); + drvinfo->regdump_len = 0; + drvinfo->eedump_len = 0; +} + +static int fjes_get_settings(struct net_device *netdev, + struct ethtool_cmd *ecmd) +{ + ecmd->supported = 0; + ecmd->advertising = 0; + ecmd->duplex = DUPLEX_FULL; + ecmd->autoneg = AUTONEG_DISABLE; + ecmd->transceiver = XCVR_DUMMY1; + ecmd->port = PORT_NONE; + ethtool_cmd_speed_set(ecmd, 20000); /* 20Gb/s */ + + return 0; +} + +static const struct ethtool_ops fjes_ethtool_ops = { + .get_settings = fjes_get_settings, + .get_drvinfo = fjes_get_drvinfo, + .get_ethtool_stats = fjes_get_ethtool_stats, + .get_strings = fjes_get_strings, + .get_sset_count = fjes_get_sset_count, +}; + +void fjes_set_ethtool_ops(struct net_device *netdev) +{ + netdev->ethtool_ops = &fjes_ethtool_ops; +} diff --git a/drivers/net/fjes/fjes_main.c b/drivers/net/fjes/fjes_main.c index 5f93e42f5cce3..0ddb54fe3d91b 100644 --- a/drivers/net/fjes/fjes_main.c +++ b/drivers/net/fjes/fjes_main.c @@ -1202,6 +1202,7 @@ static void fjes_netdev_setup(struct net_device *netdev) netdev->watchdog_timeo = FJES_TX_RETRY_INTERVAL; netdev->netdev_ops = &fjes_netdev_ops; + fjes_set_ethtool_ops(netdev); netdev->mtu = fjes_support_mtu[0]; netdev->flags |= IFF_BROADCAST; netdev->features |= NETIF_F_HW_CSUM | NETIF_F_HW_VLAN_CTAG_FILTER; -- GitLab From 6b5e971a282c0e7b18b47823103d695352b5a3c2 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 26 May 2015 18:34:26 +0200 Subject: [PATCH 4723/7006] batman-adv: Replace C99 int types with kernel type (s|u)(8|16|32|64) are the preferred types in the kernel. The use of the standard C99 types u?int(8|16|32|64)_t are objected by some people and even checkpatch now warns about using them. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 94 +++++------ net/batman-adv/bitarray.c | 6 +- net/batman-adv/bitarray.h | 10 +- net/batman-adv/bridge_loop_avoidance.c | 72 ++++---- net/batman-adv/bridge_loop_avoidance.h | 5 +- net/batman-adv/distributed-arp-table.c | 59 ++++--- net/batman-adv/distributed-arp-table.h | 8 +- net/batman-adv/fragmentation.c | 10 +- net/batman-adv/gateway_client.c | 14 +- net/batman-adv/gateway_client.h | 2 +- net/batman-adv/gateway_common.c | 11 +- net/batman-adv/hash.c | 6 +- net/batman-adv/hash.h | 12 +- net/batman-adv/icmp_socket.c | 2 +- net/batman-adv/main.c | 69 ++++---- net/batman-adv/main.h | 48 +++--- net/batman-adv/multicast.c | 16 +- net/batman-adv/network-coding.c | 44 +++-- net/batman-adv/originator.c | 15 +- net/batman-adv/originator.h | 11 +- net/batman-adv/packet.h | 204 +++++++++++----------- net/batman-adv/routing.c | 24 +-- net/batman-adv/routing.h | 2 +- net/batman-adv/send.c | 8 +- net/batman-adv/send.h | 8 +- net/batman-adv/soft-interface.c | 26 ++- net/batman-adv/sysfs.c | 4 +- net/batman-adv/translation-table.c | 224 ++++++++++++------------- net/batman-adv/translation-table.h | 29 ++-- net/batman-adv/types.h | 105 ++++++------ 30 files changed, 563 insertions(+), 585 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 753383c2215c2..f550a6ab77bbf 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -77,8 +77,7 @@ enum batadv_dup_status { * @lq_index: index to store the value at * @value: value to store in the ring buffer */ -static void batadv_ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, - uint8_t value) +static void batadv_ring_buffer_set(u8 lq_recv[], u8 *lq_index, u8 value) { lq_recv[*lq_index] = value; *lq_index = (*lq_index + 1) % BATADV_TQ_GLOBAL_WINDOW_SIZE; @@ -91,12 +90,12 @@ static void batadv_ring_buffer_set(uint8_t lq_recv[], uint8_t *lq_index, * * Returns computed average value. */ -static uint8_t batadv_ring_buffer_avg(const uint8_t lq_recv[]) +static u8 batadv_ring_buffer_avg(const u8 lq_recv[]) { - const uint8_t *ptr; - uint16_t count = 0; - uint16_t i = 0; - uint16_t sum = 0; + const u8 *ptr; + u16 count = 0; + u16 i = 0; + u16 sum = 0; ptr = lq_recv; @@ -113,7 +112,7 @@ static uint8_t batadv_ring_buffer_avg(const uint8_t lq_recv[]) if (count == 0) return 0; - return (uint8_t)(sum / count); + return (u8)(sum / count); } /** @@ -155,14 +154,14 @@ static int batadv_iv_ogm_orig_add_if(struct batadv_orig_node *orig_node, kfree(orig_node->bat_iv.bcast_own); orig_node->bat_iv.bcast_own = data_ptr; - data_ptr = kmalloc_array(max_if_num, sizeof(uint8_t), GFP_ATOMIC); + data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC); if (!data_ptr) { kfree(orig_node->bat_iv.bcast_own); goto unlock; } memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum, - (max_if_num - 1) * sizeof(uint8_t)); + (max_if_num - 1) * sizeof(u8)); kfree(orig_node->bat_iv.bcast_own_sum); orig_node->bat_iv.bcast_own_sum = data_ptr; @@ -215,19 +214,19 @@ free_bcast_own: if (max_if_num == 0) goto free_own_sum; - data_ptr = kmalloc_array(max_if_num, sizeof(uint8_t), GFP_ATOMIC); + data_ptr = kmalloc_array(max_if_num, sizeof(u8), GFP_ATOMIC); if (!data_ptr) { kfree(orig_node->bat_iv.bcast_own); goto unlock; } memcpy(data_ptr, orig_node->bat_iv.bcast_own_sum, - del_if_num * sizeof(uint8_t)); + del_if_num * sizeof(u8)); - if_offset = (del_if_num + 1) * sizeof(uint8_t); - memcpy((char *)data_ptr + del_if_num * sizeof(uint8_t), + if_offset = (del_if_num + 1) * sizeof(u8); + memcpy((char *)data_ptr + del_if_num * sizeof(u8), orig_node->bat_iv.bcast_own_sum + if_offset, - (max_if_num - del_if_num) * sizeof(uint8_t)); + (max_if_num - del_if_num) * sizeof(u8)); free_own_sum: kfree(orig_node->bat_iv.bcast_own_sum); @@ -250,7 +249,7 @@ unlock: * If the object does not exists it is created an initialised. */ static struct batadv_orig_node * -batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr) +batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const u8 *addr) { struct batadv_orig_node *orig_node; int size, hash_added; @@ -270,7 +269,7 @@ batadv_iv_ogm_orig_get(struct batadv_priv *bat_priv, const uint8_t *addr) if (!orig_node->bat_iv.bcast_own) goto free_orig_node; - size = bat_priv->num_ifaces * sizeof(uint8_t); + size = bat_priv->num_ifaces * sizeof(u8); orig_node->bat_iv.bcast_own_sum = kzalloc(size, GFP_ATOMIC); if (!orig_node->bat_iv.bcast_own_sum) goto free_orig_node; @@ -293,7 +292,7 @@ free_orig_node: static struct batadv_neigh_node * batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, - const uint8_t *neigh_addr, + const u8 *neigh_addr, struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_neigh) { @@ -339,7 +338,7 @@ static int batadv_iv_ogm_iface_enable(struct batadv_hard_iface *hard_iface) { struct batadv_ogm_packet *batadv_ogm_packet; unsigned char *ogm_buff; - uint32_t random_seqno; + u32 random_seqno; /* randomize initial seqno to avoid collision */ get_random_bytes(&random_seqno, sizeof(random_seqno)); @@ -411,8 +410,7 @@ static unsigned long batadv_iv_ogm_fwd_send_time(void) } /* apply hop penalty for a normal link */ -static uint8_t batadv_hop_penalty(uint8_t tq, - const struct batadv_priv *bat_priv) +static u8 batadv_hop_penalty(u8 tq, const struct batadv_priv *bat_priv) { int hop_penalty = atomic_read(&bat_priv->hop_penalty); int new_tq; @@ -442,11 +440,11 @@ static void batadv_iv_ogm_send_to_if(struct batadv_forw_packet *forw_packet, { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); const char *fwd_str; - uint8_t packet_num; - int16_t buff_pos; + u8 packet_num; + s16 buff_pos; struct batadv_ogm_packet *batadv_ogm_packet; struct sk_buff *skb; - uint8_t *packet_pos; + u8 *packet_pos; if (hard_iface->if_status != BATADV_IF_ACTIVE) return; @@ -837,7 +835,7 @@ static void batadv_iv_ogm_forward(struct batadv_orig_node *orig_node, struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - uint16_t tvlv_len; + u16 tvlv_len; if (batadv_ogm_packet->ttl <= 1) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "ttl exceeded\n"); @@ -896,9 +894,9 @@ batadv_iv_ogm_slide_own_bcast_window(struct batadv_hard_iface *hard_iface) struct hlist_head *head; struct batadv_orig_node *orig_node; unsigned long *word; - uint32_t i; + u32 i; size_t word_index; - uint8_t *w; + u8 *w; int if_num; for (i = 0; i < hash->size; i++) { @@ -927,8 +925,8 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *primary_if, *tmp_hard_iface; int *ogm_buff_len = &hard_iface->bat_iv.ogm_buff_len; - uint32_t seqno; - uint16_t tvlv_len = 0; + u32 seqno; + u16 tvlv_len = 0; unsigned long send_time; primary_if = batadv_primary_if_get_selected(bat_priv); @@ -947,7 +945,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) batadv_ogm_packet->tvlv_len = htons(tvlv_len); /* change sequence number to network order */ - seqno = (uint32_t)atomic_read(&hard_iface->bat_iv.ogm_seqno); + seqno = (u32)atomic_read(&hard_iface->bat_iv.ogm_seqno); batadv_ogm_packet->seqno = htonl(seqno); atomic_inc(&hard_iface->bat_iv.ogm_seqno); @@ -1010,9 +1008,9 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_node_tmp; int if_num; - uint8_t sum_orig, sum_neigh; - uint8_t *neigh_addr; - uint8_t tq_avg; + u8 sum_orig, sum_neigh; + u8 *neigh_addr; + u8 tq_avg; batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "update_originator(): Searching and updating originator entry of received packet\n"); @@ -1164,8 +1162,8 @@ static int batadv_iv_ogm_calc_tq(struct batadv_orig_node *orig_node, struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node; struct batadv_neigh_ifinfo *neigh_ifinfo; - uint8_t total_count; - uint8_t orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; + u8 total_count; + u8 orig_eq_count, neigh_rq_count, neigh_rq_inv, tq_own; unsigned int neigh_rq_inv_cube, neigh_rq_max_cube; int tq_asym_penalty, inv_asym_penalty, if_num, ret = 0; unsigned int combined_tq; @@ -1311,13 +1309,13 @@ batadv_iv_ogm_update_seqnos(const struct ethhdr *ethhdr, struct batadv_neigh_node *neigh_node; struct batadv_neigh_ifinfo *neigh_ifinfo; int is_dup; - int32_t seq_diff; + s32 seq_diff; int need_update = 0; int set_mark; enum batadv_dup_status ret = BATADV_NO_DUP; - uint32_t seqno = ntohl(batadv_ogm_packet->seqno); - uint8_t *neigh_addr; - uint8_t packet_count; + u32 seqno = ntohl(batadv_ogm_packet->seqno); + u8 *neigh_addr; + u8 packet_count; unsigned long *bitmap; orig_node = batadv_iv_ogm_orig_get(bat_priv, batadv_ogm_packet->orig); @@ -1418,7 +1416,7 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, bool sameseq, similar_ttl; struct sk_buff *skb_priv; struct ethhdr *ethhdr; - uint8_t *prev_sender; + u8 *prev_sender; int is_bidirect; /* create a private copy of the skb, as some functions change tq value @@ -1600,7 +1598,7 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, struct batadv_orig_node *orig_neigh_node, *orig_node; struct batadv_hard_iface *hard_iface; struct batadv_ogm_packet *ogm_packet; - uint32_t if_incoming_seqno; + u32 if_incoming_seqno; bool has_directlink_flag; struct ethhdr *ethhdr; bool is_my_oldorig = false; @@ -1673,9 +1671,9 @@ static void batadv_iv_ogm_process(const struct sk_buff *skb, int ogm_offset, if (is_my_orig) { unsigned long *word; int offset; - int32_t bit_pos; - int16_t if_num; - uint8_t *weight; + s32 bit_pos; + s16 if_num; + u8 *weight; orig_neigh_node = batadv_iv_ogm_orig_get(bat_priv, ethhdr->h_source); @@ -1751,7 +1749,7 @@ static int batadv_iv_ogm_receive(struct sk_buff *skb, { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); struct batadv_ogm_packet *ogm_packet; - uint8_t *packet_pos; + u8 *packet_pos; int ogm_offset; bool ret; @@ -1835,7 +1833,7 @@ static void batadv_iv_ogm_orig_print(struct batadv_priv *bat_priv, unsigned long last_seen_jiffies; struct hlist_head *head; int batman_count = 0; - uint32_t i; + u32 i; seq_printf(seq, " %-15s %s (%s/%i) %17s [%10s]: %20s ...\n", "Originator", "last-seen", "#", BATADV_TQ_MAX_VALUE, @@ -1903,7 +1901,7 @@ static int batadv_iv_ogm_neigh_cmp(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing2) { struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; - uint8_t tq1, tq2; + u8 tq1, tq2; int diff; neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); @@ -1945,7 +1943,7 @@ batadv_iv_ogm_neigh_is_eob(struct batadv_neigh_node *neigh1, struct batadv_hard_iface *if_outgoing2) { struct batadv_neigh_ifinfo *neigh1_ifinfo, *neigh2_ifinfo; - uint8_t tq1, tq2; + u8 tq1, tq2; bool ret; neigh1_ifinfo = batadv_neigh_ifinfo_get(neigh1, if_outgoing1); diff --git a/net/batman-adv/bitarray.c b/net/batman-adv/bitarray.c index cf68c328345e5..25cbc36e997ad 100644 --- a/net/batman-adv/bitarray.c +++ b/net/batman-adv/bitarray.c @@ -21,7 +21,7 @@ #include /* shift the packet array by n places. */ -static void batadv_bitmap_shift_left(unsigned long *seq_bits, int32_t n) +static void batadv_bitmap_shift_left(unsigned long *seq_bits, s32 n) { if (n <= 0 || n >= BATADV_TQ_LOCAL_WINDOW_SIZE) return; @@ -35,8 +35,8 @@ static void batadv_bitmap_shift_left(unsigned long *seq_bits, int32_t n) * 1 if the window was moved (either new or very old) * 0 if the window was not moved/shifted. */ -int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, - int32_t seq_num_diff, int set_mark) +int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, + int set_mark) { struct batadv_priv *bat_priv = priv; diff --git a/net/batman-adv/bitarray.h b/net/batman-adv/bitarray.h index 0c2456225fae9..0226b220fe5b0 100644 --- a/net/batman-adv/bitarray.h +++ b/net/batman-adv/bitarray.h @@ -28,9 +28,9 @@ * and curr_seqno is within range of last_seqno. Otherwise returns 0. */ static inline int batadv_test_bit(const unsigned long *seq_bits, - uint32_t last_seqno, uint32_t curr_seqno) + u32 last_seqno, u32 curr_seqno) { - int32_t diff; + s32 diff; diff = last_seqno - curr_seqno; if (diff < 0 || diff >= BATADV_TQ_LOCAL_WINDOW_SIZE) @@ -39,7 +39,7 @@ static inline int batadv_test_bit(const unsigned long *seq_bits, } /* turn corresponding bit on, so we can remember that we got the packet */ -static inline void batadv_set_bit(unsigned long *seq_bits, int32_t n) +static inline void batadv_set_bit(unsigned long *seq_bits, s32 n) { /* if too old, just drop it */ if (n < 0 || n >= BATADV_TQ_LOCAL_WINDOW_SIZE) @@ -51,7 +51,7 @@ static inline void batadv_set_bit(unsigned long *seq_bits, int32_t n) /* receive and process one packet, returns 1 if received seq_num is considered * new, 0 if old */ -int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, - int32_t seq_num_diff, int set_mark); +int batadv_bit_get_packet(void *priv, unsigned long *seq_bits, s32 seq_num_diff, + int set_mark); #endif /* _NET_BATMAN_ADV_BITARRAY_H_ */ diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index ba0609292ae71..8f9059f15ebb9 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -51,7 +51,7 @@ #include "packet.h" #include "translation-table.h" -static const uint8_t batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05}; +static const u8 batadv_announce_mac[4] = {0x43, 0x05, 0x43, 0x05}; static void batadv_bla_periodic_work(struct work_struct *work); static void @@ -59,10 +59,10 @@ batadv_bla_send_announce(struct batadv_priv *bat_priv, struct batadv_bla_backbone_gw *backbone_gw); /* return the index of the claim */ -static inline uint32_t batadv_choose_claim(const void *data, uint32_t size) +static inline u32 batadv_choose_claim(const void *data, u32 size) { struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data; - uint32_t hash = 0; + u32 hash = 0; hash = jhash(&claim->addr, sizeof(claim->addr), hash); hash = jhash(&claim->vid, sizeof(claim->vid), hash); @@ -71,11 +71,10 @@ static inline uint32_t batadv_choose_claim(const void *data, uint32_t size) } /* return the index of the backbone gateway */ -static inline uint32_t batadv_choose_backbone_gw(const void *data, - uint32_t size) +static inline u32 batadv_choose_backbone_gw(const void *data, u32 size) { const struct batadv_bla_claim *claim = (struct batadv_bla_claim *)data; - uint32_t hash = 0; + u32 hash = 0; hash = jhash(&claim->addr, sizeof(claim->addr), hash); hash = jhash(&claim->vid, sizeof(claim->vid), hash); @@ -192,8 +191,8 @@ static struct batadv_bla_claim * Returns claim if found or NULL otherwise. */ static struct batadv_bla_backbone_gw * -batadv_backbone_hash_find(struct batadv_priv *bat_priv, - uint8_t *addr, unsigned short vid) +batadv_backbone_hash_find(struct batadv_priv *bat_priv, u8 *addr, + unsigned short vid) { struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; struct hlist_head *head; @@ -269,14 +268,14 @@ batadv_bla_del_backbone_claims(struct batadv_bla_backbone_gw *backbone_gw) * @vid: the VLAN ID * @claimtype: the type of the claim (CLAIM, UNCLAIM, ANNOUNCE, ...) */ -static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac, +static void batadv_bla_send_claim(struct batadv_priv *bat_priv, u8 *mac, unsigned short vid, int claimtype) { struct sk_buff *skb; struct ethhdr *ethhdr; struct batadv_hard_iface *primary_if; struct net_device *soft_iface; - uint8_t *hw_src; + u8 *hw_src; struct batadv_bla_claim_dst local_claim_dest; __be32 zeroip = 0; @@ -304,13 +303,13 @@ static void batadv_bla_send_claim(struct batadv_priv *bat_priv, uint8_t *mac, * with XX = claim type * and YY:YY = group id */ - (uint8_t *)&local_claim_dest); + (u8 *)&local_claim_dest); if (!skb) goto out; ethhdr = (struct ethhdr *)skb->data; - hw_src = (uint8_t *)ethhdr + ETH_HLEN + sizeof(struct arphdr); + hw_src = (u8 *)ethhdr + ETH_HLEN + sizeof(struct arphdr); /* now we pretend that the client would have sent this ... */ switch (claimtype) { @@ -383,7 +382,7 @@ out: * be found. */ static struct batadv_bla_backbone_gw * -batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, uint8_t *orig, +batadv_bla_get_backbone_gw(struct batadv_priv *bat_priv, u8 *orig, unsigned short vid, bool own_backbone) { struct batadv_bla_backbone_gw *entry; @@ -552,7 +551,7 @@ static void batadv_bla_send_request(struct batadv_bla_backbone_gw *backbone_gw) static void batadv_bla_send_announce(struct batadv_priv *bat_priv, struct batadv_bla_backbone_gw *backbone_gw) { - uint8_t mac[ETH_ALEN]; + u8 mac[ETH_ALEN]; __be16 crc; memcpy(mac, batadv_announce_mac, 4); @@ -571,7 +570,7 @@ static void batadv_bla_send_announce(struct batadv_priv *bat_priv, * @backbone_gw: the backbone gateway which claims it */ static void batadv_bla_add_claim(struct batadv_priv *bat_priv, - const uint8_t *mac, const unsigned short vid, + const u8 *mac, const unsigned short vid, struct batadv_bla_backbone_gw *backbone_gw) { struct batadv_bla_claim *claim; @@ -635,7 +634,7 @@ claim_free_ref: * given mac address and vid. */ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, - const uint8_t *mac, const unsigned short vid) + const u8 *mac, const unsigned short vid) { struct batadv_bla_claim search_claim, *claim; @@ -659,12 +658,11 @@ static void batadv_bla_del_claim(struct batadv_priv *bat_priv, } /* check for ANNOUNCE frame, return 1 if handled */ -static int batadv_handle_announce(struct batadv_priv *bat_priv, - uint8_t *an_addr, uint8_t *backbone_addr, - unsigned short vid) +static int batadv_handle_announce(struct batadv_priv *bat_priv, u8 *an_addr, + u8 *backbone_addr, unsigned short vid) { struct batadv_bla_backbone_gw *backbone_gw; - uint16_t crc; + u16 crc; if (memcmp(an_addr, batadv_announce_mac, 4) != 0) return 0; @@ -708,8 +706,8 @@ static int batadv_handle_announce(struct batadv_priv *bat_priv, /* check for REQUEST frame, return 1 if handled */ static int batadv_handle_request(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, - uint8_t *backbone_addr, - struct ethhdr *ethhdr, unsigned short vid) + u8 *backbone_addr, struct ethhdr *ethhdr, + unsigned short vid) { /* check for REQUEST frame */ if (!batadv_compare_eth(backbone_addr, ethhdr->h_dest)) @@ -732,8 +730,8 @@ static int batadv_handle_request(struct batadv_priv *bat_priv, /* check for UNCLAIM frame, return 1 if handled */ static int batadv_handle_unclaim(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, - uint8_t *backbone_addr, - uint8_t *claim_addr, unsigned short vid) + u8 *backbone_addr, u8 *claim_addr, + unsigned short vid) { struct batadv_bla_backbone_gw *backbone_gw; @@ -761,7 +759,7 @@ static int batadv_handle_unclaim(struct batadv_priv *bat_priv, /* check for CLAIM frame, return 1 if handled */ static int batadv_handle_claim(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, - uint8_t *backbone_addr, uint8_t *claim_addr, + u8 *backbone_addr, u8 *claim_addr, unsigned short vid) { struct batadv_bla_backbone_gw *backbone_gw; @@ -805,10 +803,10 @@ static int batadv_handle_claim(struct batadv_priv *bat_priv, */ static int batadv_check_claim_group(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if, - uint8_t *hw_src, uint8_t *hw_dst, + u8 *hw_src, u8 *hw_dst, struct ethhdr *ethhdr) { - uint8_t *backbone_addr; + u8 *backbone_addr; struct batadv_orig_node *orig_node; struct batadv_bla_claim_dst *bla_dst, *bla_dst_own; @@ -877,7 +875,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, struct sk_buff *skb) { struct batadv_bla_claim_dst *bla_dst, *bla_dst_own; - uint8_t *hw_src, *hw_dst; + u8 *hw_src, *hw_dst; struct vlan_hdr *vhdr, vhdr_buf; struct ethhdr *ethhdr; struct arphdr *arphdr; @@ -923,7 +921,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, /* pskb_may_pull() may have modified the pointers, get ethhdr again */ ethhdr = eth_hdr(skb); - arphdr = (struct arphdr *)((uint8_t *)ethhdr + headlen); + arphdr = (struct arphdr *)((u8 *)ethhdr + headlen); /* Check whether the ARP frame carries a valid * IP information @@ -937,7 +935,7 @@ static int batadv_bla_process_claim(struct batadv_priv *bat_priv, if (arphdr->ar_pln != 4) return 0; - hw_src = (uint8_t *)arphdr + sizeof(struct arphdr); + hw_src = (u8 *)arphdr + sizeof(struct arphdr); hw_dst = hw_src + ETH_ALEN + 4; bla_dst = (struct batadv_bla_claim_dst *)hw_dst; bla_dst_own = &bat_priv->bla.claim_dest; @@ -1238,9 +1236,9 @@ static struct lock_class_key batadv_backbone_hash_lock_class_key; int batadv_bla_init(struct batadv_priv *bat_priv) { int i; - uint8_t claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00}; + u8 claim_dest[ETH_ALEN] = {0xff, 0x43, 0x05, 0x00, 0x00, 0x00}; struct batadv_hard_iface *primary_if; - uint16_t crc; + u16 crc; unsigned long entrytime; spin_lock_init(&bat_priv->bla.bcast_duplist_lock); @@ -1368,7 +1366,7 @@ out: * * Returns true if orig is a backbone for this vid, false otherwise. */ -bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig, +bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, unsigned short vid) { struct batadv_hashtable *hash = bat_priv->bla.backbone_hash; @@ -1647,9 +1645,9 @@ int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset) struct batadv_bla_claim *claim; struct batadv_hard_iface *primary_if; struct hlist_head *head; - uint32_t i; + u32 i; bool is_own; - uint8_t *primary_addr; + u8 *primary_addr; primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) @@ -1692,9 +1690,9 @@ int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset) struct batadv_hard_iface *primary_if; struct hlist_head *head; int secs, msecs; - uint32_t i; + u32 i; bool is_own; - uint8_t *primary_addr; + u8 *primary_addr; primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index 0282690389ac3..449f2f1350a52 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h @@ -38,7 +38,7 @@ int batadv_bla_is_backbone_gw(struct sk_buff *skb, int batadv_bla_claim_table_seq_print_text(struct seq_file *seq, void *offset); int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, void *offset); -bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, uint8_t *orig, +bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, u8 *orig, unsigned short vid); int batadv_bla_check_bcast_duplist(struct batadv_priv *bat_priv, struct sk_buff *skb); @@ -84,8 +84,7 @@ static inline int batadv_bla_backbone_table_seq_print_text(struct seq_file *seq, } static inline bool batadv_bla_is_backbone_gw_orig(struct batadv_priv *bat_priv, - uint8_t *orig, - unsigned short vid) + u8 *orig, unsigned short vid) { return false; } diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index cc7d87d649878..a63ea27eca6c6 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -102,7 +102,7 @@ static void __batadv_dat_purge(struct batadv_priv *bat_priv, struct batadv_dat_entry *dat_entry; struct hlist_node *node_tmp; struct hlist_head *head; - uint32_t i; + u32 i; if (!bat_priv->dat.hash) return; @@ -168,11 +168,11 @@ static int batadv_compare_dat(const struct hlist_node *node, const void *data2) * * Returns the value of the hw_src field in the ARP packet. */ -static uint8_t *batadv_arp_hw_src(struct sk_buff *skb, int hdr_size) +static u8 *batadv_arp_hw_src(struct sk_buff *skb, int hdr_size) { - uint8_t *addr; + u8 *addr; - addr = (uint8_t *)(skb->data + hdr_size); + addr = (u8 *)(skb->data + hdr_size); addr += ETH_HLEN + sizeof(struct arphdr); return addr; @@ -197,7 +197,7 @@ static __be32 batadv_arp_ip_src(struct sk_buff *skb, int hdr_size) * * Returns the value of the hw_dst field in the ARP packet. */ -static uint8_t *batadv_arp_hw_dst(struct sk_buff *skb, int hdr_size) +static u8 *batadv_arp_hw_dst(struct sk_buff *skb, int hdr_size) { return batadv_arp_hw_src(skb, hdr_size) + ETH_ALEN + 4; } @@ -221,12 +221,12 @@ static __be32 batadv_arp_ip_dst(struct sk_buff *skb, int hdr_size) * * Returns the selected index in the hash table for the given data. */ -static uint32_t batadv_hash_dat(const void *data, uint32_t size) +static u32 batadv_hash_dat(const void *data, u32 size) { - uint32_t hash = 0; + u32 hash = 0; const struct batadv_dat_entry *dat = data; const unsigned char *key; - uint32_t i; + u32 i; key = (const unsigned char *)&dat->ip; for (i = 0; i < sizeof(dat->ip); i++) { @@ -265,7 +265,7 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, struct hlist_head *head; struct batadv_dat_entry to_find, *dat_entry, *dat_entry_tmp = NULL; struct batadv_hashtable *hash = bat_priv->dat.hash; - uint32_t index; + u32 index; if (!hash) return NULL; @@ -300,7 +300,7 @@ batadv_dat_entry_hash_find(struct batadv_priv *bat_priv, __be32 ip, * @vid: VLAN identifier */ static void batadv_dat_entry_add(struct batadv_priv *bat_priv, __be32 ip, - uint8_t *mac_addr, unsigned short vid) + u8 *mac_addr, unsigned short vid) { struct batadv_dat_entry *dat_entry; int hash_added; @@ -357,11 +357,11 @@ out: * @msg: message to print together with the debugging information */ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb, - uint16_t type, int hdr_size, char *msg) + u16 type, int hdr_size, char *msg) { struct batadv_unicast_4addr_packet *unicast_4addr_packet; struct batadv_bcast_packet *bcast_pkt; - uint8_t *orig_addr; + u8 *orig_addr; __be32 ip_src, ip_dst; if (msg) @@ -424,7 +424,7 @@ static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb, #else static void batadv_dbg_arp(struct batadv_priv *bat_priv, struct sk_buff *skb, - uint16_t type, int hdr_size, char *msg) + u16 type, int hdr_size, char *msg) { } @@ -709,9 +709,8 @@ void batadv_dat_status_update(struct net_device *net_dev) */ static void batadv_dat_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, - void *tvlv_value, - uint16_t tvlv_value_len) + u8 flags, + void *tvlv_value, u16 tvlv_value_len) { if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) clear_bit(BATADV_ORIG_CAPA_HAS_DAT, &orig->capabilities); @@ -787,7 +786,7 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset) struct hlist_head *head; unsigned long last_seen_jiffies; int last_seen_msecs, last_seen_secs, last_seen_mins; - uint32_t i; + u32 i; primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) @@ -830,14 +829,14 @@ out: * * Returns the ARP type if the skb contains a valid ARP packet, 0 otherwise. */ -static uint16_t batadv_arp_get_type(struct batadv_priv *bat_priv, - struct sk_buff *skb, int hdr_size) +static u16 batadv_arp_get_type(struct batadv_priv *bat_priv, + struct sk_buff *skb, int hdr_size) { struct arphdr *arphdr; struct ethhdr *ethhdr; __be32 ip_src, ip_dst; - uint8_t *hw_src, *hw_dst; - uint16_t type = 0; + u8 *hw_src, *hw_dst; + u16 type = 0; /* pull the ethernet header */ if (unlikely(!pskb_may_pull(skb, hdr_size + ETH_HLEN))) @@ -934,9 +933,9 @@ static unsigned short batadv_dat_get_vid(struct sk_buff *skb, int *hdr_size) bool batadv_dat_snoop_outgoing_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb) { - uint16_t type = 0; + u16 type = 0; __be32 ip_dst, ip_src; - uint8_t *hw_src; + u8 *hw_src; bool ret = false; struct batadv_dat_entry *dat_entry = NULL; struct sk_buff *skb_new; @@ -1022,9 +1021,9 @@ out: bool batadv_dat_snoop_incoming_arp_request(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_size) { - uint16_t type; + u16 type; __be32 ip_src, ip_dst; - uint8_t *hw_src; + u8 *hw_src; struct sk_buff *skb_new; struct batadv_dat_entry *dat_entry = NULL; bool ret = false; @@ -1100,9 +1099,9 @@ out: void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, struct sk_buff *skb) { - uint16_t type; + u16 type; __be32 ip_src, ip_dst; - uint8_t *hw_src, *hw_dst; + u8 *hw_src, *hw_dst; int hdr_size = 0; unsigned short vid; @@ -1146,9 +1145,9 @@ void batadv_dat_snoop_outgoing_arp_reply(struct batadv_priv *bat_priv, bool batadv_dat_snoop_incoming_arp_reply(struct batadv_priv *bat_priv, struct sk_buff *skb, int hdr_size) { - uint16_t type; + u16 type; __be32 ip_src, ip_dst; - uint8_t *hw_src, *hw_dst; + u8 *hw_src, *hw_dst; bool dropped = false; unsigned short vid; @@ -1202,7 +1201,7 @@ out: bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, struct batadv_forw_packet *forw_packet) { - uint16_t type; + u16 type; __be32 ip_dst; struct batadv_dat_entry *dat_entry = NULL; bool ret = false; diff --git a/net/batman-adv/distributed-arp-table.h b/net/batman-adv/distributed-arp-table.h index 3181507ebc140..26d4a525a798e 100644 --- a/net/batman-adv/distributed-arp-table.h +++ b/net/batman-adv/distributed-arp-table.h @@ -54,7 +54,7 @@ bool batadv_dat_drop_broadcast_packet(struct batadv_priv *bat_priv, static inline void batadv_dat_init_orig_node_addr(struct batadv_orig_node *orig_node) { - uint32_t addr; + u32 addr; addr = batadv_choose_orig(orig_node->orig, BATADV_DAT_ADDR_MAX); orig_node->dat_addr = (batadv_dat_addr_t)addr; @@ -69,7 +69,7 @@ static inline void batadv_dat_init_own_addr(struct batadv_priv *bat_priv, struct batadv_hard_iface *primary_if) { - uint32_t addr; + u32 addr; addr = batadv_choose_orig(primary_if->net_dev->dev_addr, BATADV_DAT_ADDR_MAX); @@ -89,7 +89,7 @@ int batadv_dat_cache_seq_print_text(struct seq_file *seq, void *offset); * Updates the ethtool statistics for the received packet if it is a DAT subtype */ static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv, - uint8_t subtype) + u8 subtype) { switch (subtype) { case BATADV_P_DAT_DHT_GET: @@ -169,7 +169,7 @@ static inline void batadv_dat_free(struct batadv_priv *bat_priv) } static inline void batadv_dat_inc_counter(struct batadv_priv *bat_priv, - uint8_t subtype) + u8 subtype) { } diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index c0f0d01ab244e..ec5f7bcad66ea 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -66,7 +66,7 @@ void batadv_frag_purge_orig(struct batadv_orig_node *orig_node, bool (*check_cb)(struct batadv_frag_table_entry *)) { struct batadv_frag_table_entry *chain; - uint8_t i; + u8 i; for (i = 0; i < BATADV_FRAG_BUFFER_COUNT; i++) { chain = &orig_node->fragments[i]; @@ -110,7 +110,7 @@ static int batadv_frag_size_limit(void) * without searching for the right position. */ static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain, - uint16_t seqno) + u16 seqno) { if (chain->seqno == seqno) return false; @@ -145,8 +145,8 @@ static bool batadv_frag_insert_packet(struct batadv_orig_node *orig_node, struct batadv_frag_list_entry *frag_entry_new = NULL, *frag_entry_curr; struct batadv_frag_list_entry *frag_entry_last = NULL; struct batadv_frag_packet *frag_packet; - uint8_t bucket; - uint16_t seqno, hdr_size = sizeof(struct batadv_frag_packet); + u8 bucket; + u16 seqno, hdr_size = sizeof(struct batadv_frag_packet); bool ret = false; /* Linearize packet to avoid linearizing 16 packets in a row when doing @@ -351,7 +351,7 @@ bool batadv_frag_skb_fwd(struct sk_buff *skb, struct batadv_orig_node *orig_node_dst = NULL; struct batadv_neigh_node *neigh_node = NULL; struct batadv_frag_packet *packet; - uint16_t total_size; + u16 total_size; bool ret = false; packet = (struct batadv_frag_packet *)skb->data; diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 6012e2b4af4f5..6269c75919bf5 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -153,9 +153,9 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) struct batadv_neigh_node *router; struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_gw_node *gw_node, *curr_gw = NULL; - uint64_t max_gw_factor = 0, tmp_gw_factor = 0; - uint8_t max_tq = 0; - uint8_t tq_avg; + u64 max_gw_factor = 0, tmp_gw_factor = 0; + u8 max_tq = 0; + u8 tq_avg; struct batadv_orig_node *orig_node; rcu_read_lock(); @@ -348,7 +348,7 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, struct batadv_neigh_ifinfo *router_gw_tq = NULL; struct batadv_orig_node *curr_gw_orig; struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; - uint8_t gw_tq_avg, orig_tq_avg; + u8 gw_tq_avg, orig_tq_avg; curr_gw_orig = batadv_gw_get_selected_orig(bat_priv); if (!curr_gw_orig) @@ -688,7 +688,7 @@ out: */ enum batadv_dhcp_recipient batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, - uint8_t *chaddr) + u8 *chaddr) { enum batadv_dhcp_recipient ret = BATADV_DHCP_NO; struct ethhdr *ethhdr; @@ -698,7 +698,7 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, struct vlan_ethhdr *vhdr; int chaddr_offset; __be16 proto; - uint8_t *p; + u8 *p; /* check for ethernet header */ if (!pskb_may_pull(skb, *header_len + ETH_HLEN)) @@ -814,7 +814,7 @@ bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; struct ethhdr *ethhdr = (struct ethhdr *)skb->data; bool out_of_range = false; - uint8_t curr_tq_avg; + u8 curr_tq_avg; unsigned short vid; vid = batadv_get_vid(skb, 0); diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index 89565b451c186..ef4d7e336651f 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -43,6 +43,6 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); enum batadv_dhcp_recipient batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, - uint8_t *chaddr); + u8 *chaddr); #endif /* _NET_BATMAN_ADV_GATEWAY_CLIENT_H_ */ diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 39cf44ccebd44..9e32c8ebc28fb 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -39,7 +39,7 @@ * Returns false on parse error and true otherwise. */ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, - uint32_t *down, uint32_t *up) + u32 *down, u32 *up) { enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; char *slash_ptr, *tmp_ptr; @@ -124,7 +124,7 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, void batadv_gw_tvlv_container_update(struct batadv_priv *bat_priv) { struct batadv_tvlv_gateway_data gw; - uint32_t down, up; + u32 down, up; char gw_mode; gw_mode = atomic_read(&bat_priv->gw_mode); @@ -149,7 +149,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) { struct batadv_priv *bat_priv = netdev_priv(net_dev); - uint32_t down_curr, up_curr, down_new = 0, up_new = 0; + u32 down_curr, up_curr, down_new = 0, up_new = 0; bool ret; down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down); @@ -195,9 +195,8 @@ end: */ static void batadv_gw_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, - void *tvlv_value, - uint16_t tvlv_value_len) + u8 flags, + void *tvlv_value, u16 tvlv_value_len) { struct batadv_tvlv_gateway_data gateway, *gateway_ptr; diff --git a/net/batman-adv/hash.c b/net/batman-adv/hash.c index e89f3146b0925..2ea6a18d793fe 100644 --- a/net/batman-adv/hash.c +++ b/net/batman-adv/hash.c @@ -25,7 +25,7 @@ /* clears the hash */ static void batadv_hash_init(struct batadv_hashtable *hash) { - uint32_t i; + u32 i; for (i = 0; i < hash->size; i++) { INIT_HLIST_HEAD(&hash->table[i]); @@ -42,7 +42,7 @@ void batadv_hash_destroy(struct batadv_hashtable *hash) } /* allocates and clears the hash */ -struct batadv_hashtable *batadv_hash_new(uint32_t size) +struct batadv_hashtable *batadv_hash_new(u32 size) { struct batadv_hashtable *hash; @@ -73,7 +73,7 @@ free_hash: void batadv_hash_set_lock_class(struct batadv_hashtable *hash, struct lock_class_key *key) { - uint32_t i; + u32 i; for (i = 0; i < hash->size; i++) lockdep_set_class(&hash->list_locks[i], key); diff --git a/net/batman-adv/hash.h b/net/batman-adv/hash.h index 5065f50c9c3c7..377626250ac71 100644 --- a/net/batman-adv/hash.h +++ b/net/batman-adv/hash.h @@ -39,17 +39,17 @@ typedef int (*batadv_hashdata_compare_cb)(const struct hlist_node *, * based on the key in the data of the first * argument and the size the second */ -typedef uint32_t (*batadv_hashdata_choose_cb)(const void *, uint32_t); +typedef u32 (*batadv_hashdata_choose_cb)(const void *, u32); typedef void (*batadv_hashdata_free_cb)(struct hlist_node *, void *); struct batadv_hashtable { struct hlist_head *table; /* the hashtable itself with the buckets */ spinlock_t *list_locks; /* spinlock for each hash list entry */ - uint32_t size; /* size of hashtable */ + u32 size; /* size of hashtable */ }; /* allocates and clears the hash */ -struct batadv_hashtable *batadv_hash_new(uint32_t size); +struct batadv_hashtable *batadv_hash_new(u32 size); /* set class key for all locks */ void batadv_hash_set_lock_class(struct batadv_hashtable *hash, @@ -69,7 +69,7 @@ static inline void batadv_hash_delete(struct batadv_hashtable *hash, struct hlist_head *head; struct hlist_node *node, *node_tmp; spinlock_t *list_lock; /* spinlock to protect write access */ - uint32_t i; + u32 i; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -105,7 +105,7 @@ static inline int batadv_hash_add(struct batadv_hashtable *hash, const void *data, struct hlist_node *data_node) { - uint32_t index; + u32 index; int ret = -1; struct hlist_head *head; struct hlist_node *node; @@ -149,7 +149,7 @@ static inline void *batadv_hash_remove(struct batadv_hashtable *hash, batadv_hashdata_choose_cb choose, void *data) { - uint32_t index; + u32 index; struct hlist_node *node; struct hlist_head *head; void *data_save = NULL; diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 07061bcbaa044..5a70b7ed25581 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -183,7 +183,7 @@ static ssize_t batadv_socket_write(struct file *file, const char __user *buff, struct batadv_orig_node *orig_node = NULL; struct batadv_neigh_node *neigh_node = NULL; size_t packet_len = sizeof(struct batadv_icmp_packet); - uint8_t *addr; + u8 *addr; if (len < sizeof(struct batadv_icmp_header)) { batadv_dbg(BATADV_DBG_BATMAN, bat_priv, diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 8457097f1643e..40750cbe4f4f3 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -234,7 +234,7 @@ void batadv_mesh_free(struct net_device *soft_iface) * * Returns 'true' if the mac address was found, false otherwise. */ -bool batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr) +bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr) { const struct batadv_hard_iface *hard_iface; bool is_my_mac = false; @@ -387,7 +387,7 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct batadv_priv *bat_priv; struct batadv_ogm_packet *batadv_ogm_packet; struct batadv_hard_iface *hard_iface; - uint8_t idx; + u8 idx; int ret; hard_iface = container_of(ptype, struct batadv_hard_iface, @@ -496,7 +496,7 @@ static void batadv_recv_handler_init(void) } int -batadv_recv_handler_register(uint8_t packet_type, +batadv_recv_handler_register(u8 packet_type, int (*recv_handler)(struct sk_buff *, struct batadv_hard_iface *)) { @@ -512,7 +512,7 @@ batadv_recv_handler_register(uint8_t packet_type, return 0; } -void batadv_recv_handler_unregister(uint8_t packet_type) +void batadv_recv_handler_unregister(u8 packet_type) { batadv_rx_handler[packet_type] = batadv_recv_unhandled_packet; } @@ -642,8 +642,7 @@ batadv_tvlv_handler_free_ref(struct batadv_tvlv_handler *tvlv_handler) * Returns tvlv handler if found or NULL otherwise. */ static struct batadv_tvlv_handler -*batadv_tvlv_handler_get(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version) +*batadv_tvlv_handler_get(struct batadv_priv *bat_priv, u8 type, u8 version) { struct batadv_tvlv_handler *tvlv_handler_tmp, *tvlv_handler = NULL; @@ -691,8 +690,7 @@ static void batadv_tvlv_container_free_ref(struct batadv_tvlv_container *tvlv) * Returns tvlv container if found or NULL otherwise. */ static struct batadv_tvlv_container -*batadv_tvlv_container_get(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version) +*batadv_tvlv_container_get(struct batadv_priv *bat_priv, u8 type, u8 version) { struct batadv_tvlv_container *tvlv_tmp, *tvlv = NULL; @@ -723,10 +721,10 @@ static struct batadv_tvlv_container * * Returns size of all currently registered tvlv containers in bytes. */ -static uint16_t batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) +static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) { struct batadv_tvlv_container *tvlv; - uint16_t tvlv_len = 0; + u16 tvlv_len = 0; hlist_for_each_entry(tvlv, &bat_priv->tvlv.container_list, list) { tvlv_len += sizeof(struct batadv_tvlv_hdr); @@ -764,7 +762,7 @@ static void batadv_tvlv_container_remove(struct batadv_tvlv_container *tvlv) * @version: tvlv container type to unregister */ void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version) + u8 type, u8 version) { struct batadv_tvlv_container *tvlv; @@ -787,8 +785,8 @@ void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, * content is going to replace the old one. */ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version, - void *tvlv_value, uint16_t tvlv_value_len) + u8 type, u8 version, + void *tvlv_value, u16 tvlv_value_len) { struct batadv_tvlv_container *tvlv_old, *tvlv_new; @@ -861,14 +859,13 @@ static bool batadv_tvlv_realloc_packet_buff(unsigned char **packet_buff, * * Returns size of all appended tvlv containers in bytes. */ -uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, - int packet_min_len) +u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, int packet_min_len) { struct batadv_tvlv_container *tvlv; struct batadv_tvlv_hdr *tvlv_hdr; - uint16_t tvlv_value_len; + u16 tvlv_value_len; void *tvlv_value; bool ret; @@ -893,7 +890,7 @@ uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, tvlv_hdr->len = tvlv->tvlv_hdr.len; tvlv_value = tvlv_hdr + 1; memcpy(tvlv_value, tvlv + 1, ntohs(tvlv->tvlv_hdr.len)); - tvlv_value = (uint8_t *)tvlv_value + ntohs(tvlv->tvlv_hdr.len); + tvlv_value = (u8 *)tvlv_value + ntohs(tvlv->tvlv_hdr.len); } end: @@ -920,8 +917,8 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, struct batadv_tvlv_handler *tvlv_handler, bool ogm_source, struct batadv_orig_node *orig_node, - uint8_t *src, uint8_t *dst, - void *tvlv_value, uint16_t tvlv_value_len) + u8 *src, u8 *dst, + void *tvlv_value, u16 tvlv_value_len) { if (!tvlv_handler) return NET_RX_SUCCESS; @@ -972,13 +969,13 @@ static int batadv_tvlv_call_handler(struct batadv_priv *bat_priv, int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, bool ogm_source, struct batadv_orig_node *orig_node, - uint8_t *src, uint8_t *dst, - void *tvlv_value, uint16_t tvlv_value_len) + u8 *src, u8 *dst, + void *tvlv_value, u16 tvlv_value_len) { struct batadv_tvlv_handler *tvlv_handler; struct batadv_tvlv_hdr *tvlv_hdr; - uint16_t tvlv_value_cont_len; - uint8_t cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; + u16 tvlv_value_cont_len; + u8 cifnotfound = BATADV_TVLV_HANDLER_OGM_CIFNOTFND; int ret = NET_RX_SUCCESS; while (tvlv_value_len >= sizeof(*tvlv_hdr)) { @@ -1000,7 +997,7 @@ int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, tvlv_value_cont_len); if (tvlv_handler) batadv_tvlv_handler_free_ref(tvlv_handler); - tvlv_value = (uint8_t *)tvlv_value + tvlv_value_cont_len; + tvlv_value = (u8 *)tvlv_value + tvlv_value_cont_len; tvlv_value_len -= tvlv_value_cont_len; } @@ -1034,7 +1031,7 @@ void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { void *tvlv_value; - uint16_t tvlv_value_len; + u16 tvlv_value_len; if (!batadv_ogm_packet) return; @@ -1066,14 +1063,14 @@ void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, void (*optr)(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, + u8 flags, void *tvlv_value, - uint16_t tvlv_value_len), + u16 tvlv_value_len), int (*uptr)(struct batadv_priv *bat_priv, - uint8_t *src, uint8_t *dst, + u8 *src, u8 *dst, void *tvlv_value, - uint16_t tvlv_value_len), - uint8_t type, uint8_t version, uint8_t flags) + u16 tvlv_value_len), + u8 type, u8 version, u8 flags) { struct batadv_tvlv_handler *tvlv_handler; @@ -1108,7 +1105,7 @@ void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, * @version: tvlv handler version to be unregistered */ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version) + u8 type, u8 version) { struct batadv_tvlv_handler *tvlv_handler; @@ -1134,9 +1131,9 @@ void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, * @tvlv_value: tvlv content * @tvlv_value_len: tvlv content length */ -void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, - uint8_t *dst, uint8_t type, uint8_t version, - void *tvlv_value, uint16_t tvlv_value_len) +void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, + u8 *dst, u8 type, u8 version, + void *tvlv_value, u16 tvlv_value_len) { struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; struct batadv_tvlv_hdr *tvlv_hdr; diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 41d27c7872b95..78500ac725d62 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -193,7 +193,7 @@ extern struct workqueue_struct *batadv_event_workqueue; int batadv_mesh_init(struct net_device *soft_iface); void batadv_mesh_free(struct net_device *soft_iface); -bool batadv_is_my_mac(struct batadv_priv *bat_priv, const uint8_t *addr); +bool batadv_is_my_mac(struct batadv_priv *bat_priv, const u8 *addr); struct batadv_hard_iface * batadv_seq_print_text_primary_if_get(struct seq_file *seq); int batadv_max_header_len(void); @@ -202,10 +202,10 @@ int batadv_batman_skb_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev); int -batadv_recv_handler_register(uint8_t packet_type, +batadv_recv_handler_register(u8 packet_type, int (*recv_handler)(struct sk_buff *, struct batadv_hard_iface *)); -void batadv_recv_handler_unregister(uint8_t packet_type); +void batadv_recv_handler_unregister(u8 packet_type); int batadv_algo_register(struct batadv_algo_ops *bat_algo_ops); int batadv_algo_select(struct batadv_priv *bat_priv, char *name); int batadv_algo_seq_print_text(struct seq_file *seq, void *offset); @@ -304,7 +304,7 @@ static inline bool batadv_has_timed_out(unsigned long timestamp, * they handle overflows/underflows and can correctly check for a * predecessor/successor unless the variable sequence number has grown by * more then 2**(bitwidth(x)-1)-1. - * This means that for a uint8_t with the maximum value 255, it would think: + * This means that for a u8 with the maximum value 255, it would think: * - when adding nothing - it is neither a predecessor nor a successor * - before adding more than 127 to the starting value - it is a predecessor, * - when adding 128 - it is neither a predecessor nor a successor, @@ -327,10 +327,9 @@ static inline void batadv_add_counter(struct batadv_priv *bat_priv, size_t idx, #define batadv_inc_counter(b, i) batadv_add_counter(b, i, 1) /* Sum and return the cpu-local counters for index 'idx' */ -static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv, - size_t idx) +static inline u64 batadv_sum_counter(struct batadv_priv *bat_priv, size_t idx) { - uint64_t *counters, sum = 0; + u64 *counters, sum = 0; int cpu; for_each_possible_cpu(cpu) { @@ -348,39 +347,38 @@ static inline uint64_t batadv_sum_counter(struct batadv_priv *bat_priv, #define BATADV_SKB_CB(__skb) ((struct batadv_skb_cb *)&((__skb)->cb[0])) void batadv_tvlv_container_register(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version, - void *tvlv_value, uint16_t tvlv_value_len); -uint16_t batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, - unsigned char **packet_buff, - int *packet_buff_len, - int packet_min_len); + u8 type, u8 version, + void *tvlv_value, u16 tvlv_value_len); +u16 batadv_tvlv_container_ogm_append(struct batadv_priv *bat_priv, + unsigned char **packet_buff, + int *packet_buff_len, int packet_min_len); void batadv_tvlv_ogm_receive(struct batadv_priv *bat_priv, struct batadv_ogm_packet *batadv_ogm_packet, struct batadv_orig_node *orig_node); void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version); + u8 type, u8 version); void batadv_tvlv_handler_register(struct batadv_priv *bat_priv, void (*optr)(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, + u8 flags, void *tvlv_value, - uint16_t tvlv_value_len), + u16 tvlv_value_len), int (*uptr)(struct batadv_priv *bat_priv, - uint8_t *src, uint8_t *dst, + u8 *src, u8 *dst, void *tvlv_value, - uint16_t tvlv_value_len), - uint8_t type, uint8_t version, uint8_t flags); + u16 tvlv_value_len), + u8 type, u8 version, u8 flags); void batadv_tvlv_handler_unregister(struct batadv_priv *bat_priv, - uint8_t type, uint8_t version); + u8 type, u8 version); int batadv_tvlv_containers_process(struct batadv_priv *bat_priv, bool ogm_source, struct batadv_orig_node *orig_node, - uint8_t *src, uint8_t *dst, - void *tvlv_buff, uint16_t tvlv_buff_len); -void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, uint8_t *src, - uint8_t *dst, uint8_t type, uint8_t version, - void *tvlv_value, uint16_t tvlv_value_len); + u8 *src, u8 *dst, + void *tvlv_buff, u16 tvlv_buff_len); +void batadv_tvlv_unicast_send(struct batadv_priv *bat_priv, u8 *src, + u8 *dst, u8 type, u8 version, + void *tvlv_value, u16 tvlv_value_len); unsigned short batadv_get_vid(struct sk_buff *skb, size_t header_len); bool batadv_vlan_ap_isola_get(struct batadv_priv *bat_priv, unsigned short vid); diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 68a9554961eb4..2593f0fe0bad6 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -89,7 +89,7 @@ static int batadv_mcast_mla_softif_get(struct net_device *dev, * Returns true if the given address is already in the given list. * Otherwise returns false. */ -static bool batadv_mcast_mla_is_duplicate(uint8_t *mcast_addr, +static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr, struct hlist_head *mcast_list) { struct batadv_hw_addr *mcast_entry; @@ -595,7 +595,7 @@ batadv_mcast_forw_mode(struct batadv_priv *bat_priv, struct sk_buff *skb, */ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t mcast_flags) + u8 mcast_flags) { struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node; struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list; @@ -638,7 +638,7 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, */ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t mcast_flags) + u8 mcast_flags) { struct hlist_node *node = &orig->mcast_want_all_ipv4_node; struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list; @@ -681,7 +681,7 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, */ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t mcast_flags) + u8 mcast_flags) { struct hlist_node *node = &orig->mcast_want_all_ipv6_node; struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list; @@ -721,17 +721,17 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, */ static void batadv_mcast_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, + u8 flags, void *tvlv_value, - uint16_t tvlv_value_len) + u16 tvlv_value_len) { bool orig_mcast_enabled = !(flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND); - uint8_t mcast_flags = BATADV_NO_FLAGS; + u8 mcast_flags = BATADV_NO_FLAGS; bool orig_initialized; if (orig_mcast_enabled && tvlv_value && (tvlv_value_len >= sizeof(mcast_flags))) - mcast_flags = *(uint8_t *)tvlv_value; + mcast_flags = *(u8 *)tvlv_value; spin_lock_bh(&orig->mcast_handler_lock); orig_initialized = test_bit(BATADV_ORIG_CAPA_HAS_MCAST, diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 46604010dcd42..60dc7a6910b1f 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -130,9 +130,8 @@ void batadv_nc_status_update(struct net_device *net_dev) */ static void batadv_nc_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, - void *tvlv_value, - uint16_t tvlv_value_len) + u8 flags, + void *tvlv_value, u16 tvlv_value_len) { if (flags & BATADV_TVLV_HANDLER_OGM_CIFNOTFND) clear_bit(BATADV_ORIG_CAPA_HAS_NC, &orig->capabilities); @@ -382,7 +381,7 @@ static void batadv_nc_purge_orig_hash(struct batadv_priv *bat_priv) struct batadv_hashtable *hash = bat_priv->orig_hash; struct hlist_head *head; struct batadv_orig_node *orig_node; - uint32_t i; + u32 i; if (!hash) return; @@ -418,7 +417,7 @@ static void batadv_nc_purge_paths(struct batadv_priv *bat_priv, struct hlist_node *node_tmp; struct batadv_nc_path *nc_path; spinlock_t *lock; /* Protects lists in hash */ - uint32_t i; + u32 i; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -478,10 +477,10 @@ static void batadv_nc_hash_key_gen(struct batadv_nc_path *key, const char *src, * * Returns the selected index in the hash table for the given data. */ -static uint32_t batadv_nc_hash_choose(const void *data, uint32_t size) +static u32 batadv_nc_hash_choose(const void *data, u32 size) { const struct batadv_nc_path *nc_path = data; - uint32_t hash = 0; + u32 hash = 0; hash = jhash(&nc_path->prev_hop, sizeof(nc_path->prev_hop), hash); hash = jhash(&nc_path->next_hop, sizeof(nc_path->next_hop), hash); @@ -744,8 +743,8 @@ static bool batadv_can_nc_with_orig(struct batadv_priv *bat_priv, struct batadv_ogm_packet *ogm_packet) { struct batadv_orig_ifinfo *orig_ifinfo; - uint32_t last_real_seqno; - uint8_t last_ttl; + u32 last_real_seqno; + u8 last_ttl; orig_ifinfo = batadv_orig_ifinfo_get(orig_node, BATADV_IF_DEFAULT); if (!orig_ifinfo) @@ -938,8 +937,8 @@ out: */ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv, struct batadv_hashtable *hash, - uint8_t *src, - uint8_t *dst) + u8 *src, + u8 *dst) { int hash_added; struct batadv_nc_path *nc_path, nc_path_key; @@ -991,9 +990,9 @@ static struct batadv_nc_path *batadv_nc_get_path(struct batadv_priv *bat_priv, * selection of a receiver with slightly lower TQ than the other * @tq: to be weighted tq value */ -static uint8_t batadv_nc_random_weight_tq(uint8_t tq) +static u8 batadv_nc_random_weight_tq(u8 tq) { - uint8_t rand_val, rand_tq; + u8 rand_val, rand_tq; get_random_bytes(&rand_val, sizeof(rand_val)); @@ -1038,7 +1037,7 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, struct batadv_nc_packet *nc_packet, struct batadv_neigh_node *neigh_node) { - uint8_t tq_weighted_neigh, tq_weighted_coding, tq_tmp; + u8 tq_weighted_neigh, tq_weighted_coding, tq_tmp; struct sk_buff *skb_dest, *skb_src; struct batadv_unicast_packet *packet1; struct batadv_unicast_packet *packet2; @@ -1047,7 +1046,7 @@ static bool batadv_nc_code_packets(struct batadv_priv *bat_priv, struct batadv_neigh_node *router_coding = NULL; struct batadv_neigh_ifinfo *router_neigh_ifinfo = NULL; struct batadv_neigh_ifinfo *router_coding_ifinfo = NULL; - uint8_t *first_source, *first_dest, *second_source, *second_dest; + u8 *first_source, *first_dest, *second_source, *second_dest; __be32 packet_id1, packet_id2; size_t count; bool res = false; @@ -1231,8 +1230,7 @@ out: * * Returns true if coding of a decoded packet is allowed. */ -static bool batadv_nc_skb_coding_possible(struct sk_buff *skb, - uint8_t *dst, uint8_t *src) +static bool batadv_nc_skb_coding_possible(struct sk_buff *skb, u8 *dst, u8 *src) { if (BATADV_SKB_CB(skb)->decoded && !batadv_compare_eth(dst, src)) return false; @@ -1255,7 +1253,7 @@ batadv_nc_path_search(struct batadv_priv *bat_priv, struct batadv_nc_node *in_nc_node, struct batadv_nc_node *out_nc_node, struct sk_buff *skb, - uint8_t *eth_dst) + u8 *eth_dst) { struct batadv_nc_path *nc_path, nc_path_key; struct batadv_nc_packet *nc_packet_out = NULL; @@ -1321,8 +1319,8 @@ batadv_nc_path_search(struct batadv_priv *bat_priv, static struct batadv_nc_packet * batadv_nc_skb_src_search(struct batadv_priv *bat_priv, struct sk_buff *skb, - uint8_t *eth_dst, - uint8_t *eth_src, + u8 *eth_dst, + u8 *eth_src, struct batadv_nc_node *in_nc_node) { struct batadv_orig_node *orig_node; @@ -1362,7 +1360,7 @@ batadv_nc_skb_src_search(struct batadv_priv *bat_priv, */ static void batadv_nc_skb_store_before_coding(struct batadv_priv *bat_priv, struct sk_buff *skb, - uint8_t *eth_dst_new) + u8 *eth_dst_new) { struct ethhdr *ethhdr; @@ -1638,7 +1636,7 @@ batadv_nc_skb_decode_packet(struct batadv_priv *bat_priv, struct sk_buff *skb, struct batadv_unicast_packet *unicast_packet; struct batadv_coded_packet coded_packet_tmp; struct ethhdr *ethhdr, ethhdr_tmp; - uint8_t *orig_dest, ttl, ttvn; + u8 *orig_dest, ttl, ttvn; unsigned int coding_len; int err; @@ -1730,7 +1728,7 @@ batadv_nc_find_decoding_packet(struct batadv_priv *bat_priv, struct batadv_hashtable *hash = bat_priv->nc.decoding_hash; struct batadv_nc_packet *tmp_nc_packet, *nc_packet = NULL; struct batadv_nc_path *nc_path, nc_path_key; - uint8_t *dest, *source; + u8 *dest, *source; __be32 packet_id; int index; diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 32a0fcfab36d9..4500e3a087191 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -452,8 +452,7 @@ out: */ struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, - const uint8_t *neigh_addr, - struct batadv_orig_node *orig_node) + const u8 *neigh_addr, struct batadv_orig_node *orig_node) { struct batadv_neigh_node *neigh_node; @@ -489,7 +488,7 @@ out: struct batadv_neigh_node * batadv_neigh_node_get(const struct batadv_orig_node *orig_node, const struct batadv_hard_iface *hard_iface, - const uint8_t *addr) + const u8 *addr) { struct batadv_neigh_node *tmp_neigh_node, *res = NULL; @@ -624,7 +623,7 @@ void batadv_originator_free(struct batadv_priv *bat_priv) struct hlist_head *head; spinlock_t *list_lock; /* spinlock to protect write access */ struct batadv_orig_node *orig_node; - uint32_t i; + u32 i; if (!hash) return; @@ -659,7 +658,7 @@ void batadv_originator_free(struct batadv_priv *bat_priv) * Returns the newly created object or NULL on failure. */ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, - const uint8_t *addr) + const u8 *addr) { struct batadv_orig_node *orig_node; struct batadv_orig_node_vlan *vlan; @@ -981,7 +980,7 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv) struct hlist_head *head; spinlock_t *list_lock; /* spinlock to protect write access */ struct batadv_orig_node *orig_node; - uint32_t i; + u32 i; if (!hash) return; @@ -1115,7 +1114,7 @@ int batadv_orig_hash_add_if(struct batadv_hard_iface *hard_iface, struct batadv_hashtable *hash = bat_priv->orig_hash; struct hlist_head *head; struct batadv_orig_node *orig_node; - uint32_t i; + u32 i; int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on @@ -1152,7 +1151,7 @@ int batadv_orig_hash_del_if(struct batadv_hard_iface *hard_iface, struct batadv_hard_iface *hard_iface_tmp; struct batadv_orig_node *orig_node; struct batadv_algo_ops *bao = bat_priv->bat_algo_ops; - uint32_t i; + u32 i; int ret; /* resize all orig nodes because orig_node->bcast_own(_sum) depend on diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 79734d3020102..3fc76f6f710c4 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -40,15 +40,14 @@ void batadv_purge_orig_ref(struct batadv_priv *bat_priv); void batadv_orig_node_free_ref(struct batadv_orig_node *orig_node); void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, - const uint8_t *addr); + const u8 *addr); struct batadv_neigh_node * batadv_neigh_node_get(const struct batadv_orig_node *orig_node, const struct batadv_hard_iface *hard_iface, - const uint8_t *addr); + const u8 *addr); struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, - const uint8_t *neigh_addr, - struct batadv_orig_node *orig_node); + const u8 *neigh_addr, struct batadv_orig_node *orig_node); void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, @@ -86,9 +85,9 @@ void batadv_orig_node_vlan_free_ref(struct batadv_orig_node_vlan *orig_vlan); /* hashfunction to choose an entry in a hash table of given size * hash algorithm from http://en.wikipedia.org/wiki/Hash_table */ -static inline uint32_t batadv_choose_orig(const void *data, uint32_t size) +static inline u32 batadv_choose_orig(const void *data, u32 size) { - uint32_t hash = 0; + u32 hash = 0; hash = jhash(data, ETH_ALEN, hash); return hash % size; diff --git a/net/batman-adv/packet.h b/net/batman-adv/packet.h index 9e747c08d0bcc..11f996b39fefa 100644 --- a/net/batman-adv/packet.h +++ b/net/batman-adv/packet.h @@ -197,8 +197,8 @@ enum batadv_tvlv_type { * transport the claim type and the group id */ struct batadv_bla_claim_dst { - uint8_t magic[3]; /* FF:43:05 */ - uint8_t type; /* bla_claimframe */ + u8 magic[3]; /* FF:43:05 */ + u8 type; /* bla_claimframe */ __be16 group; /* group id */ }; @@ -213,16 +213,16 @@ struct batadv_bla_claim_dst { * @tvlv_len: length of tvlv data following the ogm header */ struct batadv_ogm_packet { - uint8_t packet_type; - uint8_t version; - uint8_t ttl; - uint8_t flags; - __be32 seqno; - uint8_t orig[ETH_ALEN]; - uint8_t prev_sender[ETH_ALEN]; - uint8_t reserved; - uint8_t tq; - __be16 tvlv_len; + u8 packet_type; + u8 version; + u8 ttl; + u8 flags; + __be32 seqno; + u8 orig[ETH_ALEN]; + u8 prev_sender[ETH_ALEN]; + u8 reserved; + u8 tq; + __be16 tvlv_len; /* __packed is not needed as the struct size is divisible by 4, * and the largest data type in this struct has a size of 4. */ @@ -246,14 +246,14 @@ struct batadv_ogm_packet { * members are padded the same way as they are in real packets. */ struct batadv_icmp_header { - uint8_t packet_type; - uint8_t version; - uint8_t ttl; - uint8_t msg_type; /* see ICMP message types above */ - uint8_t dst[ETH_ALEN]; - uint8_t orig[ETH_ALEN]; - uint8_t uid; - uint8_t align[3]; + u8 packet_type; + u8 version; + u8 ttl; + u8 msg_type; /* see ICMP message types above */ + u8 dst[ETH_ALEN]; + u8 orig[ETH_ALEN]; + u8 uid; + u8 align[3]; }; /** @@ -269,15 +269,15 @@ struct batadv_icmp_header { * @seqno: ICMP sequence number */ struct batadv_icmp_packet { - uint8_t packet_type; - uint8_t version; - uint8_t ttl; - uint8_t msg_type; /* see ICMP message types above */ - uint8_t dst[ETH_ALEN]; - uint8_t orig[ETH_ALEN]; - uint8_t uid; - uint8_t reserved; - __be16 seqno; + u8 packet_type; + u8 version; + u8 ttl; + u8 msg_type; /* see ICMP message types above */ + u8 dst[ETH_ALEN]; + u8 orig[ETH_ALEN]; + u8 uid; + u8 reserved; + __be16 seqno; }; #define BATADV_RR_LEN 16 @@ -296,16 +296,16 @@ struct batadv_icmp_packet { * @rr: route record array */ struct batadv_icmp_packet_rr { - uint8_t packet_type; - uint8_t version; - uint8_t ttl; - uint8_t msg_type; /* see ICMP message types above */ - uint8_t dst[ETH_ALEN]; - uint8_t orig[ETH_ALEN]; - uint8_t uid; - uint8_t rr_cur; - __be16 seqno; - uint8_t rr[BATADV_RR_LEN][ETH_ALEN]; + u8 packet_type; + u8 version; + u8 ttl; + u8 msg_type; /* see ICMP message types above */ + u8 dst[ETH_ALEN]; + u8 orig[ETH_ALEN]; + u8 uid; + u8 rr_cur; + __be16 seqno; + u8 rr[BATADV_RR_LEN][ETH_ALEN]; }; #define BATADV_ICMP_MAX_PACKET_SIZE sizeof(struct batadv_icmp_packet_rr) @@ -331,11 +331,11 @@ struct batadv_icmp_packet_rr { * @dest: originator destination of the unicast packet */ struct batadv_unicast_packet { - uint8_t packet_type; - uint8_t version; - uint8_t ttl; - uint8_t ttvn; /* destination translation table version number */ - uint8_t dest[ETH_ALEN]; + u8 packet_type; + u8 version; + u8 ttl; + u8 ttvn; /* destination translation table version number */ + u8 dest[ETH_ALEN]; /* "4 bytes boundary + 2 bytes" long to make the payload after the * following ethernet header again 4 bytes boundary aligned */ @@ -349,9 +349,9 @@ struct batadv_unicast_packet { */ struct batadv_unicast_4addr_packet { struct batadv_unicast_packet u; - uint8_t src[ETH_ALEN]; - uint8_t subtype; - uint8_t reserved; + u8 src[ETH_ALEN]; + u8 subtype; + u8 reserved; /* "4 bytes boundary + 2 bytes" long to make the payload after the * following ethernet header again 4 bytes boundary aligned */ @@ -370,22 +370,22 @@ struct batadv_unicast_4addr_packet { * @total_size: size of the merged packet */ struct batadv_frag_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; + u8 packet_type; + u8 version; /* batman version field */ + u8 ttl; #if defined(__BIG_ENDIAN_BITFIELD) - uint8_t no:4; - uint8_t reserved:4; + u8 no:4; + u8 reserved:4; #elif defined(__LITTLE_ENDIAN_BITFIELD) - uint8_t reserved:4; - uint8_t no:4; + u8 reserved:4; + u8 no:4; #else #error "unknown bitfield endianness" #endif - uint8_t dest[ETH_ALEN]; - uint8_t orig[ETH_ALEN]; - __be16 seqno; - __be16 total_size; + u8 dest[ETH_ALEN]; + u8 orig[ETH_ALEN]; + __be16 seqno; + __be16 total_size; }; /** @@ -398,12 +398,12 @@ struct batadv_frag_packet { * @orig: originator of the broadcast packet */ struct batadv_bcast_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; - uint8_t reserved; - __be32 seqno; - uint8_t orig[ETH_ALEN]; + u8 packet_type; + u8 version; /* batman version field */ + u8 ttl; + u8 reserved; + __be32 seqno; + u8 orig[ETH_ALEN]; /* "4 bytes boundary + 2 bytes" long to make the payload after the * following ethernet header again 4 bytes boundary aligned */ @@ -428,21 +428,21 @@ struct batadv_bcast_packet { * @coded_len: length of network coded part of the payload */ struct batadv_coded_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; - uint8_t first_ttvn; - /* uint8_t first_dest[ETH_ALEN]; - saved in mac header destination */ - uint8_t first_source[ETH_ALEN]; - uint8_t first_orig_dest[ETH_ALEN]; - __be32 first_crc; - uint8_t second_ttl; - uint8_t second_ttvn; - uint8_t second_dest[ETH_ALEN]; - uint8_t second_source[ETH_ALEN]; - uint8_t second_orig_dest[ETH_ALEN]; - __be32 second_crc; - __be16 coded_len; + u8 packet_type; + u8 version; /* batman version field */ + u8 ttl; + u8 first_ttvn; + /* u8 first_dest[ETH_ALEN]; - saved in mac header destination */ + u8 first_source[ETH_ALEN]; + u8 first_orig_dest[ETH_ALEN]; + __be32 first_crc; + u8 second_ttl; + u8 second_ttvn; + u8 second_dest[ETH_ALEN]; + u8 second_source[ETH_ALEN]; + u8 second_orig_dest[ETH_ALEN]; + __be32 second_crc; + __be16 coded_len; }; #pragma pack() @@ -459,14 +459,14 @@ struct batadv_coded_packet { * @align: 2 bytes to align the header to a 4 byte boundary */ struct batadv_unicast_tvlv_packet { - uint8_t packet_type; - uint8_t version; /* batman version field */ - uint8_t ttl; - uint8_t reserved; - uint8_t dst[ETH_ALEN]; - uint8_t src[ETH_ALEN]; - __be16 tvlv_len; - uint16_t align; + u8 packet_type; + u8 version; /* batman version field */ + u8 ttl; + u8 reserved; + u8 dst[ETH_ALEN]; + u8 src[ETH_ALEN]; + __be16 tvlv_len; + u16 align; }; /** @@ -476,9 +476,9 @@ struct batadv_unicast_tvlv_packet { * @len: tvlv container length */ struct batadv_tvlv_hdr { - uint8_t type; - uint8_t version; - __be16 len; + u8 type; + u8 version; + __be16 len; }; /** @@ -500,9 +500,9 @@ struct batadv_tvlv_gateway_data { * one batadv_tvlv_tt_vlan_data object per announced vlan */ struct batadv_tvlv_tt_data { - uint8_t flags; - uint8_t ttvn; - __be16 num_vlan; + u8 flags; + u8 ttvn; + __be16 num_vlan; }; /** @@ -513,9 +513,9 @@ struct batadv_tvlv_tt_data { * @reserved: unused, useful for alignment purposes */ struct batadv_tvlv_tt_vlan_data { - __be32 crc; - __be16 vid; - uint16_t reserved; + __be32 crc; + __be16 vid; + u16 reserved; }; /** @@ -527,9 +527,9 @@ struct batadv_tvlv_tt_vlan_data { * @vid: VLAN identifier */ struct batadv_tvlv_tt_change { - uint8_t flags; - uint8_t reserved[3]; - uint8_t addr[ETH_ALEN]; + u8 flags; + u8 reserved[3]; + u8 addr[ETH_ALEN]; __be16 vid; }; @@ -539,7 +539,7 @@ struct batadv_tvlv_tt_change { * @vid: VLAN identifier */ struct batadv_tvlv_roam_adv { - uint8_t client[ETH_ALEN]; + u8 client[ETH_ALEN]; __be16 vid; }; @@ -549,8 +549,8 @@ struct batadv_tvlv_roam_adv { * @reserved: reserved field */ struct batadv_tvlv_mcast_data { - uint8_t flags; - uint8_t reserved[3]; + u8 flags; + u8 reserved[3]; }; #endif /* _NET_BATMAN_ADV_PACKET_H_ */ diff --git a/net/batman-adv/routing.c b/net/batman-adv/routing.c index c360c0cd19c2b..8d990b070a2e8 100644 --- a/net/batman-adv/routing.c +++ b/net/batman-adv/routing.c @@ -145,7 +145,7 @@ out: * 0 if the packet is to be accepted * 1 if the packet is to be ignored. */ -int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, +int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, unsigned long *last_reset) { if (seq_num_diff <= -BATADV_TQ_LOCAL_WINDOW_SIZE || @@ -653,19 +653,19 @@ out: static bool batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, struct batadv_unicast_packet *unicast_packet, - uint8_t *dst_addr, unsigned short vid) + u8 *dst_addr, unsigned short vid) { struct batadv_orig_node *orig_node = NULL; struct batadv_hard_iface *primary_if = NULL; bool ret = false; - uint8_t *orig_addr, orig_ttvn; + u8 *orig_addr, orig_ttvn; if (batadv_is_my_client(bat_priv, dst_addr, vid)) { primary_if = batadv_primary_if_get_selected(bat_priv); if (!primary_if) goto out; orig_addr = primary_if->net_dev->dev_addr; - orig_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); + orig_ttvn = (u8)atomic_read(&bat_priv->tt.vn); } else { orig_node = batadv_transtable_search(bat_priv, NULL, dst_addr, vid); @@ -676,7 +676,7 @@ batadv_reroute_unicast_packet(struct batadv_priv *bat_priv, goto out; orig_addr = orig_node->orig; - orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); + orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); } /* update the packet header */ @@ -698,7 +698,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, struct batadv_unicast_packet *unicast_packet; struct batadv_hard_iface *primary_if; struct batadv_orig_node *orig_node; - uint8_t curr_ttvn, old_ttvn; + u8 curr_ttvn, old_ttvn; struct ethhdr *ethhdr; unsigned short vid; int is_old_ttvn; @@ -740,7 +740,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, * value is used later to check if the node which sent (or re-routed * last time) the packet had an updated information or not */ - curr_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); + curr_ttvn = (u8)atomic_read(&bat_priv->tt.vn); if (!batadv_is_my_mac(bat_priv, unicast_packet->dest)) { orig_node = batadv_orig_hash_find(bat_priv, unicast_packet->dest); @@ -751,7 +751,7 @@ static int batadv_check_unicast_ttvn(struct batadv_priv *bat_priv, if (!orig_node) return 0; - curr_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); + curr_ttvn = (u8)atomic_read(&orig_node->last_ttvn); batadv_orig_node_free_ref(orig_node); } @@ -833,7 +833,7 @@ int batadv_recv_unicast_packet(struct sk_buff *skb, struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct batadv_unicast_packet *unicast_packet; struct batadv_unicast_4addr_packet *unicast_4addr_packet; - uint8_t *orig_addr; + u8 *orig_addr; struct batadv_orig_node *orig_node = NULL; int check, hdr_size = sizeof(*unicast_packet); bool is4addr; @@ -904,7 +904,7 @@ int batadv_recv_unicast_tvlv(struct sk_buff *skb, struct batadv_priv *bat_priv = netdev_priv(recv_if->soft_iface); struct batadv_unicast_tvlv_packet *unicast_tvlv_packet; unsigned char *tvlv_buff; - uint16_t tvlv_buff_len; + u16 tvlv_buff_len; int hdr_size = sizeof(*unicast_tvlv_packet); int ret = NET_RX_DROP; @@ -1007,8 +1007,8 @@ int batadv_recv_bcast_packet(struct sk_buff *skb, struct ethhdr *ethhdr; int hdr_size = sizeof(*bcast_packet); int ret = NET_RX_DROP; - int32_t seq_diff; - uint32_t seqno; + s32 seq_diff; + u32 seqno; /* drop packet if it has not necessary minimum size */ if (unlikely(!pskb_may_pull(skb, hdr_size))) diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index 6bc29d33abc18..3c185a1fb7a94 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h @@ -55,7 +55,7 @@ struct batadv_neigh_node * batadv_find_router(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, struct batadv_hard_iface *recv_if); -int batadv_window_protected(struct batadv_priv *bat_priv, int32_t seq_num_diff, +int batadv_window_protected(struct batadv_priv *bat_priv, s32 seq_num_diff, unsigned long *last_reset); #endif /* _NET_BATMAN_ADV_ROUTING_H_ */ diff --git a/net/batman-adv/send.c b/net/batman-adv/send.c index 191076ef1eca1..f664324805eba 100644 --- a/net/batman-adv/send.c +++ b/net/batman-adv/send.c @@ -54,7 +54,7 @@ static void batadv_send_outstanding_bcast_packet(struct work_struct *work); */ int batadv_send_skb_packet(struct sk_buff *skb, struct batadv_hard_iface *hard_iface, - const uint8_t *dst_addr) + const u8 *dst_addr) { struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); struct ethhdr *ethhdr; @@ -172,7 +172,7 @@ batadv_send_skb_push_fill_unicast(struct sk_buff *skb, int hdr_size, struct batadv_orig_node *orig_node) { struct batadv_unicast_packet *unicast_packet; - uint8_t ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); + u8 ttvn = (u8)atomic_read(&orig_node->last_ttvn); if (batadv_skb_head_push(skb, hdr_size) < 0) return false; @@ -343,12 +343,12 @@ out: */ int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, struct sk_buff *skb, int packet_type, - int packet_subtype, uint8_t *dst_hint, + int packet_subtype, u8 *dst_hint, unsigned short vid) { struct ethhdr *ethhdr = (struct ethhdr *)skb->data; struct batadv_orig_node *orig_node; - uint8_t *src, *dst; + u8 *src, *dst; src = ethhdr->h_source; dst = ethhdr->h_dest; diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index 0536835fe5034..33ef6fc1030d9 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h @@ -33,7 +33,7 @@ struct work_struct; int batadv_send_skb_packet(struct sk_buff *skb, struct batadv_hard_iface *hard_iface, - const uint8_t *dst_addr); + const u8 *dst_addr); int batadv_send_skb_to_orig(struct sk_buff *skb, struct batadv_orig_node *orig_node, struct batadv_hard_iface *recv_if); @@ -56,7 +56,7 @@ int batadv_send_skb_unicast(struct batadv_priv *bat_priv, unsigned short vid); int batadv_send_skb_via_tt_generic(struct batadv_priv *bat_priv, struct sk_buff *skb, int packet_type, - int packet_subtype, uint8_t *dst_hint, + int packet_subtype, u8 *dst_hint, unsigned short vid); int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, unsigned short vid); @@ -75,7 +75,7 @@ int batadv_send_skb_via_gw(struct batadv_priv *bat_priv, struct sk_buff *skb, * Returns NET_XMIT_DROP in case of error or NET_XMIT_SUCCESS otherwise. */ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, - struct sk_buff *skb, uint8_t *dst_hint, + struct sk_buff *skb, u8 *dst_hint, unsigned short vid) { return batadv_send_skb_via_tt_generic(bat_priv, skb, BATADV_UNICAST, 0, @@ -100,7 +100,7 @@ static inline int batadv_send_skb_via_tt(struct batadv_priv *bat_priv, static inline int batadv_send_skb_via_tt_4addr(struct batadv_priv *bat_priv, struct sk_buff *skb, int packet_subtype, - uint8_t *dst_hint, + u8 *dst_hint, unsigned short vid) { return batadv_send_skb_via_tt_generic(bat_priv, skb, diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index 49d3d3aa59cba..d5c5ad93a6116 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -131,7 +131,7 @@ static int batadv_interface_set_mac_addr(struct net_device *dev, void *p) struct batadv_priv *bat_priv = netdev_priv(dev); struct batadv_softif_vlan *vlan; struct sockaddr *addr = p; - uint8_t old_addr[ETH_ALEN]; + u8 old_addr[ETH_ALEN]; if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; @@ -186,19 +186,19 @@ static int batadv_interface_tx(struct sk_buff *skb, struct batadv_hard_iface *primary_if = NULL; struct batadv_bcast_packet *bcast_packet; __be16 ethertype = htons(ETH_P_BATMAN); - static const uint8_t stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, - 0x00, 0x00}; - static const uint8_t ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, - 0x00, 0x00}; + static const u8 stp_addr[ETH_ALEN] = {0x01, 0x80, 0xC2, 0x00, + 0x00, 0x00}; + static const u8 ectp_addr[ETH_ALEN] = {0xCF, 0x00, 0x00, 0x00, + 0x00, 0x00}; enum batadv_dhcp_recipient dhcp_rcp = BATADV_DHCP_NO; - uint8_t *dst_hint = NULL, chaddr[ETH_ALEN]; + u8 *dst_hint = NULL, chaddr[ETH_ALEN]; struct vlan_ethhdr *vhdr; unsigned int header_len = 0; int data_len = skb->len, ret; unsigned long brd_delay = 1; bool do_bcast = false, client_added; unsigned short vid; - uint32_t seqno; + u32 seqno; int gw_mode; enum batadv_forw_mode forw_mode; struct batadv_orig_node *mcast_single_orig = NULL; @@ -750,9 +750,9 @@ static void batadv_softif_destroy_finish(struct work_struct *work) static int batadv_softif_init_late(struct net_device *dev) { struct batadv_priv *bat_priv; - uint32_t random_seqno; + u32 random_seqno; int ret; - size_t cnt_len = sizeof(uint64_t) * BATADV_CNT_NUM; + size_t cnt_len = sizeof(u64) * BATADV_CNT_NUM; batadv_set_lockdep_class(dev); @@ -763,7 +763,7 @@ static int batadv_softif_init_late(struct net_device *dev) /* batadv_interface_stats() needs to be available as soon as * register_netdevice() has been called */ - bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(uint64_t)); + bat_priv->bat_counters = __alloc_percpu(cnt_len, __alignof__(u64)); if (!bat_priv->bat_counters) return -ENOMEM; @@ -1117,8 +1117,7 @@ static const struct { #endif }; -static void batadv_get_strings(struct net_device *dev, uint32_t stringset, - uint8_t *data) +static void batadv_get_strings(struct net_device *dev, u32 stringset, u8 *data) { if (stringset == ETH_SS_STATS) memcpy(data, batadv_counters_strings, @@ -1126,8 +1125,7 @@ static void batadv_get_strings(struct net_device *dev, uint32_t stringset, } static void batadv_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, - uint64_t *data) + struct ethtool_stats *stats, u64 *data) { struct batadv_priv *bat_priv = netdev_priv(dev); int i; diff --git a/net/batman-adv/sysfs.c b/net/batman-adv/sysfs.c index d6a312a82c03d..9de3c8804ff48 100644 --- a/net/batman-adv/sysfs.c +++ b/net/batman-adv/sysfs.c @@ -457,7 +457,7 @@ static ssize_t batadv_show_gw_bwidth(struct kobject *kobj, struct attribute *attr, char *buff) { struct batadv_priv *bat_priv = batadv_kobj_to_batpriv(kobj); - uint32_t down, up; + u32 down, up; down = atomic_read(&bat_priv->gw.bandwidth_down); up = atomic_read(&bat_priv->gw.bandwidth_up); @@ -512,7 +512,7 @@ static ssize_t batadv_store_isolation_mark(struct kobject *kobj, { struct net_device *net_dev = batadv_kobj_to_netdev(kobj); struct batadv_priv *bat_priv = netdev_priv(net_dev); - uint32_t mark, mask; + u32 mark, mask; char *mask_ptr; /* parse the mask if it has been specified, otherwise assume the mask is diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index c1eb7b72ab15f..f90898881eeec 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -56,7 +56,7 @@ static struct lock_class_key batadv_tt_local_hash_lock_class_key; static struct lock_class_key batadv_tt_global_hash_lock_class_key; -static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, +static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, unsigned short vid, struct batadv_orig_node *orig_node); static void batadv_tt_purge(struct work_struct *work); @@ -85,10 +85,10 @@ static int batadv_compare_tt(const struct hlist_node *node, const void *data2) * Returns the hash index where the object represented by 'data' should be * stored at. */ -static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) +static inline u32 batadv_choose_tt(const void *data, u32 size) { struct batadv_tt_common_entry *tt; - uint32_t hash = 0; + u32 hash = 0; tt = (struct batadv_tt_common_entry *)data; hash = jhash(&tt->addr, ETH_ALEN, hash); @@ -107,12 +107,12 @@ static inline uint32_t batadv_choose_tt(const void *data, uint32_t size) * found, NULL otherwise. */ static struct batadv_tt_common_entry * -batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, +batadv_tt_hash_find(struct batadv_hashtable *hash, const u8 *addr, unsigned short vid) { struct hlist_head *head; struct batadv_tt_common_entry to_search, *tt, *tt_tmp = NULL; - uint32_t index; + u32 index; if (!hash) return NULL; @@ -152,7 +152,7 @@ batadv_tt_hash_find(struct batadv_hashtable *hash, const uint8_t *addr, * found, NULL otherwise. */ static struct batadv_tt_local_entry * -batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, +batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { struct batadv_tt_common_entry *tt_common_entry; @@ -177,7 +177,7 @@ batadv_tt_local_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, * is found, NULL otherwise. */ static struct batadv_tt_global_entry * -batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const uint8_t *addr, +batadv_tt_global_hash_find(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { struct batadv_tt_common_entry *tt_common_entry; @@ -223,7 +223,7 @@ batadv_tt_global_entry_free_ref(struct batadv_tt_global_entry *tt_global_entry) * (excluding ourself). */ int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, - const uint8_t *addr, unsigned short vid) + const u8 *addr, unsigned short vid) { struct batadv_tt_global_entry *tt_global_entry; int count; @@ -364,11 +364,11 @@ batadv_tt_orig_list_entry_free_ref(struct batadv_tt_orig_list_entry *orig_entry) */ static void batadv_tt_local_event(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry, - uint8_t event_flags) + u8 event_flags) { struct batadv_tt_change_node *tt_change_node, *entry, *safe; struct batadv_tt_common_entry *common = &tt_local_entry->common; - uint8_t flags = common->flags | event_flags; + u8 flags = common->flags | event_flags; bool event_removed = false; bool del_op_requested, del_op_entry; @@ -448,7 +448,7 @@ static int batadv_tt_len(int changes_num) * * Returns the number of entries. */ -static uint16_t batadv_tt_entries(uint16_t tt_len) +static u16 batadv_tt_entries(u16 tt_len) { return tt_len / batadv_tt_len(1); } @@ -462,7 +462,7 @@ static uint16_t batadv_tt_entries(uint16_t tt_len) */ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) { - uint16_t num_vlan = 0, tt_local_entries = 0; + u16 num_vlan = 0, tt_local_entries = 0; struct batadv_softif_vlan *vlan; int hdr_size; @@ -525,8 +525,8 @@ static void batadv_tt_global_free(struct batadv_priv *bat_priv, * * Returns true if the client was successfully added, false otherwise. */ -bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, - unsigned short vid, int ifindex, uint32_t mark) +bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, + unsigned short vid, int ifindex, u32 mark) { struct batadv_priv *bat_priv = netdev_priv(soft_iface); struct batadv_tt_local_entry *tt_local; @@ -537,8 +537,8 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, struct batadv_tt_orig_list_entry *orig_entry; int hash_added, table_size, packet_size_max; bool ret = false, roamed_back = false; - uint8_t remote_flags; - uint32_t match_mark; + u8 remote_flags; + u32 match_mark; if (ifindex != BATADV_NULL_IFINDEX) in_dev = dev_get_by_index(&init_net, ifindex); @@ -605,7 +605,7 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, batadv_dbg(BATADV_DBG_TT, bat_priv, "Creating new local tt entry: %pM (vid: %d, ttvn: %d)\n", addr, BATADV_PRINT_VID(vid), - (uint8_t)atomic_read(&bat_priv->tt.vn)); + (u8)atomic_read(&bat_priv->tt.vn)); ether_addr_copy(tt_local->common.addr, addr); /* The local entry has to be marked as NEW to avoid to send it in @@ -724,16 +724,16 @@ out: * * Return the size of the allocated buffer or 0 in case of failure. */ -static uint16_t +static u16 batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_data **tt_data, struct batadv_tvlv_tt_change **tt_change, - int32_t *tt_len) + s32 *tt_len) { - uint16_t num_vlan = 0, num_entries = 0, change_offset, tvlv_len; + u16 num_vlan = 0, num_entries = 0, change_offset, tvlv_len; struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_orig_node_vlan *vlan; - uint8_t *tt_change_ptr; + u8 *tt_change_ptr; rcu_read_lock(); list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { @@ -769,7 +769,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, tt_vlan++; } - tt_change_ptr = (uint8_t *)*tt_data + change_offset; + tt_change_ptr = (u8 *)*tt_data + change_offset; *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; out: @@ -795,16 +795,16 @@ out: * * Return the size of the allocated buffer or 0 in case of failure. */ -static uint16_t +static u16 batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data **tt_data, struct batadv_tvlv_tt_change **tt_change, - int32_t *tt_len) + s32 *tt_len) { struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_softif_vlan *vlan; - uint16_t num_vlan = 0, num_entries = 0, tvlv_len; - uint8_t *tt_change_ptr; + u16 num_vlan = 0, num_entries = 0, tvlv_len; + u8 *tt_change_ptr; int change_offset; rcu_read_lock(); @@ -841,7 +841,7 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, tt_vlan++; } - tt_change_ptr = (uint8_t *)*tt_data + change_offset; + tt_change_ptr = (u8 *)*tt_data + change_offset; *tt_change = (struct batadv_tvlv_tt_change *)tt_change_ptr; out: @@ -861,7 +861,7 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) struct batadv_tvlv_tt_change *tt_change; int tt_diff_len, tt_change_len = 0; int tt_diff_entries_num = 0, tt_diff_entries_count = 0; - uint16_t tvlv_len; + u16 tvlv_len; tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); tt_diff_len = batadv_tt_len(tt_diff_entries_num); @@ -935,12 +935,12 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) struct batadv_softif_vlan *vlan; struct hlist_head *head; unsigned short vid; - uint32_t i; + u32 i; int last_seen_secs; int last_seen_msecs; unsigned long last_seen_jiffies; bool no_purge; - uint16_t np_flag = BATADV_TT_CLIENT_NOPURGE; + u16 np_flag = BATADV_TT_CLIENT_NOPURGE; primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) @@ -948,7 +948,7 @@ int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset) seq_printf(seq, "Locally retrieved addresses (from %s) announced via TT (TTVN: %u):\n", - net_dev->name, (uint8_t)atomic_read(&bat_priv->tt.vn)); + net_dev->name, (u8)atomic_read(&bat_priv->tt.vn)); seq_printf(seq, " %-13s %s %-8s %-9s (%-10s)\n", "Client", "VID", "Flags", "Last seen", "CRC"); @@ -1008,7 +1008,7 @@ out: static void batadv_tt_local_set_pending(struct batadv_priv *bat_priv, struct batadv_tt_local_entry *tt_local_entry, - uint16_t flags, const char *message) + u16 flags, const char *message) { batadv_tt_local_event(bat_priv, tt_local_entry, flags); @@ -1034,12 +1034,12 @@ batadv_tt_local_set_pending(struct batadv_priv *bat_priv, * * Returns the flags assigned to the local entry before being deleted */ -uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, - const uint8_t *addr, unsigned short vid, - const char *message, bool roaming) +u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, const u8 *addr, + unsigned short vid, const char *message, + bool roaming) { struct batadv_tt_local_entry *tt_local_entry; - uint16_t flags, curr_flags = BATADV_NO_FLAGS; + u16 flags, curr_flags = BATADV_NO_FLAGS; struct batadv_softif_vlan *vlan; void *tt_entry_exists; @@ -1142,7 +1142,7 @@ static void batadv_tt_local_purge(struct batadv_priv *bat_priv, struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct hlist_head *head; spinlock_t *list_lock; /* protects write access to the hash lists */ - uint32_t i; + u32 i; for (i = 0; i < hash->size; i++) { head = &hash->table[i]; @@ -1163,7 +1163,7 @@ static void batadv_tt_local_table_free(struct batadv_priv *bat_priv) struct batadv_softif_vlan *vlan; struct hlist_node *node_tmp; struct hlist_head *head; - uint32_t i; + u32 i; if (!bat_priv->tt.local_hash) return; @@ -1338,15 +1338,14 @@ out: static bool batadv_tt_global_add(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const unsigned char *tt_addr, - unsigned short vid, uint16_t flags, - uint8_t ttvn) + unsigned short vid, u16 flags, u8 ttvn) { struct batadv_tt_global_entry *tt_global_entry; struct batadv_tt_local_entry *tt_local_entry; bool ret = false; int hash_added; struct batadv_tt_common_entry *common; - uint16_t local_flags; + u16 local_flags; /* ignore global entries from backbone nodes */ if (batadv_bla_is_backbone_gw_orig(bat_priv, orig_node->orig, vid)) @@ -1543,8 +1542,8 @@ batadv_tt_global_print_entry(struct batadv_priv *bat_priv, struct batadv_tt_common_entry *tt_common_entry; struct batadv_orig_node_vlan *vlan; struct hlist_head *head; - uint8_t last_ttvn; - uint16_t flags; + u8 last_ttvn; + u16 flags; tt_common_entry = &tt_global_entry->common; flags = tt_common_entry->flags; @@ -1618,7 +1617,7 @@ int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset) struct batadv_tt_global_entry *tt_global; struct batadv_hard_iface *primary_if; struct hlist_head *head; - uint32_t i; + u32 i; primary_if = batadv_seq_print_text_primary_if_get(seq); if (!primary_if) @@ -1838,12 +1837,12 @@ out: */ void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - int32_t match_vid, + s32 match_vid, const char *message) { struct batadv_tt_global_entry *tt_global; struct batadv_tt_common_entry *tt_common_entry; - uint32_t i; + u32 i; struct batadv_hashtable *hash = bat_priv->tt.global_hash; struct hlist_node *safe; struct hlist_head *head; @@ -1914,7 +1913,7 @@ static void batadv_tt_global_purge(struct batadv_priv *bat_priv) struct hlist_head *head; struct hlist_node *node_tmp; spinlock_t *list_lock; /* protects write access to the hash lists */ - uint32_t i; + u32 i; char *msg = NULL; struct batadv_tt_common_entry *tt_common; struct batadv_tt_global_entry *tt_global; @@ -1955,7 +1954,7 @@ static void batadv_tt_global_table_free(struct batadv_priv *bat_priv) struct batadv_tt_global_entry *tt_global; struct hlist_node *node_tmp; struct hlist_head *head; - uint32_t i; + u32 i; if (!bat_priv->tt.global_hash) return; @@ -2016,8 +2015,8 @@ _batadv_is_ap_isolated(struct batadv_tt_local_entry *tt_local_entry, * If the two clients are AP isolated the function returns NULL. */ struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, - const uint8_t *src, - const uint8_t *addr, + const u8 *src, + const u8 *addr, unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry = NULL; @@ -2085,16 +2084,16 @@ out: * * Returns the checksum of the global table of a given originator. */ -static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, - struct batadv_orig_node *orig_node, - unsigned short vid) +static u32 batadv_tt_global_crc(struct batadv_priv *bat_priv, + struct batadv_orig_node *orig_node, + unsigned short vid) { struct batadv_hashtable *hash = bat_priv->tt.global_hash; struct batadv_tt_common_entry *tt_common; struct batadv_tt_global_entry *tt_global; struct hlist_head *head; - uint32_t i, crc_tmp, crc = 0; - uint8_t flags; + u32 i, crc_tmp, crc = 0; + u8 flags; __be16 tmp_vid; for (i = 0; i < hash->size; i++) { @@ -2162,14 +2161,14 @@ static uint32_t batadv_tt_global_crc(struct batadv_priv *bat_priv, * * Returns the checksum of the local table */ -static uint32_t batadv_tt_local_crc(struct batadv_priv *bat_priv, - unsigned short vid) +static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, + unsigned short vid) { struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct batadv_tt_common_entry *tt_common; struct hlist_head *head; - uint32_t i, crc_tmp, crc = 0; - uint8_t flags; + u32 i, crc_tmp, crc = 0; + u8 flags; __be16 tmp_vid; for (i = 0; i < hash->size; i++) { @@ -2226,7 +2225,7 @@ static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const void *tt_buff, - uint16_t tt_buff_len) + u16 tt_buff_len) { /* Replace the old buffer only if I received something in the * last OGM (the OGM could carry no changes) @@ -2335,15 +2334,15 @@ static int batadv_tt_global_valid(const void *entry_ptr, */ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, struct batadv_hashtable *hash, - void *tvlv_buff, uint16_t tt_len, + void *tvlv_buff, u16 tt_len, int (*valid_cb)(const void *, const void *), void *cb_data) { struct batadv_tt_common_entry *tt_common_entry; struct batadv_tvlv_tt_change *tt_change; struct hlist_head *head; - uint16_t tt_tot, tt_num_entries = 0; - uint32_t i; + u16 tt_tot, tt_num_entries = 0; + u32 i; tt_tot = batadv_tt_entries(tt_len); tt_change = (struct batadv_tvlv_tt_change *)tvlv_buff; @@ -2385,11 +2384,11 @@ static void batadv_tt_tvlv_generate(struct batadv_priv *bat_priv, */ static bool batadv_tt_global_check_crc(struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_vlan_data *tt_vlan, - uint16_t num_vlan) + u16 num_vlan) { struct batadv_tvlv_tt_vlan_data *tt_vlan_tmp; struct batadv_orig_node_vlan *vlan; - uint32_t crc; + u32 crc; int i; /* check if each received CRC matches the locally stored one */ @@ -2444,7 +2443,7 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { struct batadv_orig_node_vlan *vlan; - uint32_t crc; + u32 crc; /* recompute the global CRC for each VLAN */ rcu_read_lock(); @@ -2474,9 +2473,9 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, */ static int batadv_send_tt_request(struct batadv_priv *bat_priv, struct batadv_orig_node *dst_orig_node, - uint8_t ttvn, + u8 ttvn, struct batadv_tvlv_tt_vlan_data *tt_vlan, - uint16_t num_vlan, bool full_table) + u16 num_vlan, bool full_table) { struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; struct batadv_tt_req_node *tt_req_node = NULL; @@ -2555,7 +2554,7 @@ out: */ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, - uint8_t *req_src, uint8_t *req_dst) + u8 *req_src, u8 *req_dst) { struct batadv_orig_node *req_dst_orig_node; struct batadv_orig_node *res_dst_orig_node = NULL; @@ -2563,9 +2562,9 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; struct batadv_tvlv_tt_vlan_data *tt_vlan; bool ret = false, full_table; - uint8_t orig_ttvn, req_ttvn; - uint16_t tvlv_len; - int32_t tt_len; + u8 orig_ttvn, req_ttvn; + u16 tvlv_len; + s32 tt_len; batadv_dbg(BATADV_DBG_TT, bat_priv, "Received TT_REQUEST from %pM for ttvn: %u (%pM) [%c]\n", @@ -2581,7 +2580,7 @@ static bool batadv_send_other_tt_response(struct batadv_priv *bat_priv, if (!res_dst_orig_node) goto out; - orig_ttvn = (uint8_t)atomic_read(&req_dst_orig_node->last_ttvn); + orig_ttvn = (u8)atomic_read(&req_dst_orig_node->last_ttvn); req_ttvn = tt_data->ttvn; tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(tt_data + 1); @@ -2687,16 +2686,16 @@ out: */ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, - uint8_t *req_src) + u8 *req_src) { struct batadv_tvlv_tt_data *tvlv_tt_data = NULL; struct batadv_hard_iface *primary_if = NULL; struct batadv_tvlv_tt_change *tt_change; struct batadv_orig_node *orig_node; - uint8_t my_ttvn, req_ttvn; - uint16_t tvlv_len; + u8 my_ttvn, req_ttvn; + u16 tvlv_len; bool full_table; - int32_t tt_len; + s32 tt_len; batadv_dbg(BATADV_DBG_TT, bat_priv, "Received TT_REQUEST from %pM for ttvn: %u (me) [%c]\n", @@ -2705,7 +2704,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, spin_lock_bh(&bat_priv->tt.commit_lock); - my_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); + my_ttvn = (u8)atomic_read(&bat_priv->tt.vn); req_ttvn = tt_data->ttvn; orig_node = batadv_orig_hash_find(bat_priv, req_src); @@ -2744,7 +2743,7 @@ static bool batadv_send_my_tt_response(struct batadv_priv *bat_priv, bat_priv->tt.last_changeset_len); spin_unlock_bh(&bat_priv->tt.last_changeset_lock); } else { - req_ttvn = (uint8_t)atomic_read(&bat_priv->tt.vn); + req_ttvn = (u8)atomic_read(&bat_priv->tt.vn); /* allocate the tvlv, put the tt_data and all the tt_vlan_data * in the initial part @@ -2805,7 +2804,7 @@ out: */ static bool batadv_send_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, - uint8_t *req_src, uint8_t *req_dst) + u8 *req_src, u8 *req_dst) { if (batadv_is_my_mac(bat_priv, req_dst)) return batadv_send_my_tt_response(bat_priv, tt_data, req_src); @@ -2816,7 +2815,7 @@ static bool batadv_send_tt_response(struct batadv_priv *bat_priv, static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_change *tt_change, - uint16_t tt_num_changes, uint8_t ttvn) + u16 tt_num_changes, u8 ttvn) { int i; int roams; @@ -2848,8 +2847,8 @@ static void _batadv_tt_update_changes(struct batadv_priv *bat_priv, static void batadv_tt_fill_gtable(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_change *tt_change, - uint8_t ttvn, uint8_t *resp_src, - uint16_t num_entries) + u8 ttvn, u8 *resp_src, + u16 num_entries) { struct batadv_orig_node *orig_node; @@ -2879,7 +2878,7 @@ out: static void batadv_tt_update_changes(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - uint16_t tt_num_changes, uint8_t ttvn, + u16 tt_num_changes, u8 ttvn, struct batadv_tvlv_tt_change *tt_change) { _batadv_tt_update_changes(bat_priv, orig_node, tt_change, @@ -2898,7 +2897,7 @@ static void batadv_tt_update_changes(struct batadv_priv *bat_priv, * * Returns true if the client is served by this node, false otherwise. */ -bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, +bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry; @@ -2929,13 +2928,13 @@ out: */ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, - uint8_t *resp_src, uint16_t num_entries) + u8 *resp_src, u16 num_entries) { struct batadv_tt_req_node *node, *safe; struct batadv_orig_node *orig_node = NULL; struct batadv_tvlv_tt_change *tt_change; - uint8_t *tvlv_ptr = (uint8_t *)tt_data; - uint16_t change_offset; + u8 *tvlv_ptr = (u8 *)tt_data; + u16 change_offset; batadv_dbg(BATADV_DBG_TT, bat_priv, "Received TT_RESPONSE from %pM for ttvn %d t_size: %d [%c]\n", @@ -3018,8 +3017,7 @@ static void batadv_tt_roam_purge(struct batadv_priv *bat_priv) * * returns true if the ROAMING_ADV can be sent, false otherwise */ -static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, - uint8_t *client) +static bool batadv_tt_check_roam_count(struct batadv_priv *bat_priv, u8 *client) { struct batadv_tt_roam_node *tt_roam_node; bool ret = false; @@ -3074,7 +3072,7 @@ unlock: * for this particular roamed client has to be forwarded to the sender of the * roaming message. */ -static void batadv_send_roam_adv(struct batadv_priv *bat_priv, uint8_t *client, +static void batadv_send_roam_adv(struct batadv_priv *bat_priv, u8 *client, unsigned short vid, struct batadv_orig_node *orig_node) { @@ -3152,14 +3150,14 @@ void batadv_tt_free(struct batadv_priv *bat_priv) * @enable: whether to set or unset the flag * @count: whether to increase the TT size by the number of changed entries */ -static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, - uint16_t flags, bool enable, bool count) +static void batadv_tt_local_set_flags(struct batadv_priv *bat_priv, u16 flags, + bool enable, bool count) { struct batadv_hashtable *hash = bat_priv->tt.local_hash; struct batadv_tt_common_entry *tt_common_entry; - uint16_t changed_num = 0; + u16 changed_num = 0; struct hlist_head *head; - uint32_t i; + u32 i; if (!hash) return; @@ -3201,7 +3199,7 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) struct hlist_node *node_tmp; struct hlist_head *head; spinlock_t *list_lock; /* protects write access to the hash lists */ - uint32_t i; + u32 i; if (!hash) return; @@ -3267,7 +3265,7 @@ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) atomic_inc(&bat_priv->tt.vn); batadv_dbg(BATADV_DBG_TT, bat_priv, "Local changes committed, updating to ttvn %u\n", - (uint8_t)atomic_read(&bat_priv->tt.vn)); + (u8)atomic_read(&bat_priv->tt.vn)); /* reset the sending counter */ atomic_set(&bat_priv->tt.ogm_append_cnt, BATADV_TT_OGM_APPEND_MAX); @@ -3286,8 +3284,8 @@ void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv) spin_unlock_bh(&bat_priv->tt.commit_lock); } -bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, - uint8_t *dst, unsigned short vid) +bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, + unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry = NULL; struct batadv_tt_global_entry *tt_global_entry = NULL; @@ -3335,11 +3333,11 @@ out: */ static void batadv_tt_update_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - const void *tt_buff, uint16_t tt_num_vlan, + const void *tt_buff, u16 tt_num_vlan, struct batadv_tvlv_tt_change *tt_change, - uint16_t tt_num_changes, uint8_t ttvn) + u16 tt_num_changes, u8 ttvn) { - uint8_t orig_ttvn = (uint8_t)atomic_read(&orig_node->last_ttvn); + u8 orig_ttvn = (u8)atomic_read(&orig_node->last_ttvn); struct batadv_tvlv_tt_vlan_data *tt_vlan; bool full_table = true; bool has_tt_init; @@ -3418,7 +3416,7 @@ request_table: * deleted later by a DEL or because of timeout */ bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr, unsigned short vid) + u8 *addr, unsigned short vid) { struct batadv_tt_global_entry *tt_global_entry; bool ret = false; @@ -3444,7 +3442,7 @@ out: * to keep the latter consistent with the node TTVN */ bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr, unsigned short vid) + u8 *addr, unsigned short vid) { struct batadv_tt_local_entry *tt_local_entry; bool ret = false; @@ -3530,13 +3528,13 @@ void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface) */ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, void *tvlv_value, - uint16_t tvlv_value_len) + u8 flags, void *tvlv_value, + u16 tvlv_value_len) { struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_tvlv_tt_change *tt_change; struct batadv_tvlv_tt_data *tt_data; - uint16_t num_entries, num_vlan; + u16 num_entries, num_vlan; if (tvlv_value_len < sizeof(*tt_data)) return; @@ -3572,12 +3570,12 @@ static void batadv_tt_tvlv_ogm_handler_v1(struct batadv_priv *bat_priv, * otherwise. */ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, - uint8_t *src, uint8_t *dst, + u8 *src, u8 *dst, void *tvlv_value, - uint16_t tvlv_value_len) + u16 tvlv_value_len) { struct batadv_tvlv_tt_data *tt_data; - uint16_t tt_vlan_len, tt_num_entries; + u16 tt_vlan_len, tt_num_entries; char tt_flag; bool ret; @@ -3653,9 +3651,9 @@ static int batadv_tt_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, * otherwise. */ static int batadv_roam_tvlv_unicast_handler_v1(struct batadv_priv *bat_priv, - uint8_t *src, uint8_t *dst, + u8 *src, u8 *dst, void *tvlv_value, - uint16_t tvlv_value_len) + u16 tvlv_value_len) { struct batadv_tvlv_roam_adv *roaming_adv; struct batadv_orig_node *orig_node = NULL; @@ -3737,7 +3735,7 @@ int batadv_tt_init(struct batadv_priv *bat_priv) * otherwise */ bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, - const uint8_t *addr, unsigned short vid) + const u8 *addr, unsigned short vid) { struct batadv_tt_global_entry *tt; bool ret; diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 6acc25d3a925c..9b82d5dd56e04 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -28,38 +28,37 @@ struct net_device; struct seq_file; int batadv_tt_init(struct batadv_priv *bat_priv); -bool batadv_tt_local_add(struct net_device *soft_iface, const uint8_t *addr, - unsigned short vid, int ifindex, uint32_t mark); -uint16_t batadv_tt_local_remove(struct batadv_priv *bat_priv, - const uint8_t *addr, unsigned short vid, - const char *message, bool roaming); +bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, + unsigned short vid, int ifindex, u32 mark); +u16 batadv_tt_local_remove(struct batadv_priv *bat_priv, + const u8 *addr, unsigned short vid, + const char *message, bool roaming); int batadv_tt_local_seq_print_text(struct seq_file *seq, void *offset); int batadv_tt_global_seq_print_text(struct seq_file *seq, void *offset); void batadv_tt_global_del_orig(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, - int32_t match_vid, const char *message); + s32 match_vid, const char *message); int batadv_tt_global_hash_count(struct batadv_priv *bat_priv, - const uint8_t *addr, unsigned short vid); + const u8 *addr, unsigned short vid); struct batadv_orig_node *batadv_transtable_search(struct batadv_priv *bat_priv, - const uint8_t *src, - const uint8_t *addr, + const u8 *src, const u8 *addr, unsigned short vid); void batadv_tt_free(struct batadv_priv *bat_priv); -bool batadv_is_my_client(struct batadv_priv *bat_priv, const uint8_t *addr, +bool batadv_is_my_client(struct batadv_priv *bat_priv, const u8 *addr, unsigned short vid); -bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, uint8_t *src, - uint8_t *dst, unsigned short vid); +bool batadv_is_ap_isolated(struct batadv_priv *bat_priv, u8 *src, u8 *dst, + unsigned short vid); void batadv_tt_local_commit_changes(struct batadv_priv *bat_priv); bool batadv_tt_global_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr, unsigned short vid); + u8 *addr, unsigned short vid); bool batadv_tt_local_client_is_roaming(struct batadv_priv *bat_priv, - uint8_t *addr, unsigned short vid); + u8 *addr, unsigned short vid); void batadv_tt_local_resize_to_mtu(struct net_device *soft_iface); bool batadv_tt_add_temporary_global_entry(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node, const unsigned char *addr, unsigned short vid); bool batadv_tt_global_is_isolated(struct batadv_priv *bat_priv, - const uint8_t *addr, unsigned short vid); + const u8 *addr, unsigned short vid); #endif /* _NET_BATMAN_ADV_TRANSLATION_TABLE_H_ */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 55610a805b533..f2ebe33d9b59f 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -44,7 +44,7 @@ struct seq_file; * * *Please be careful: batadv_dat_addr_t must be UNSIGNED* */ -#define batadv_dat_addr_t uint16_t +#define batadv_dat_addr_t u16 #endif /* CONFIG_BATMAN_ADV_DAT */ @@ -103,10 +103,10 @@ struct batadv_hard_iface_bat_iv { */ struct batadv_hard_iface { struct list_head list; - int16_t if_num; + s16 if_num; char if_status; struct net_device *net_dev; - uint8_t num_bcasts; + u8 num_bcasts; struct kobject *hardif_obj; atomic_t refcount; struct packet_type batman_adv_ptype; @@ -132,8 +132,8 @@ struct batadv_orig_ifinfo { struct hlist_node list; struct batadv_hard_iface *if_outgoing; struct batadv_neigh_node __rcu *router; /* rcu protected pointer */ - uint32_t last_real_seqno; - uint8_t last_ttl; + u32 last_real_seqno; + u8 last_ttl; unsigned long batman_seqno_reset; atomic_t refcount; struct rcu_head rcu; @@ -152,9 +152,9 @@ struct batadv_frag_table_entry { struct hlist_head head; spinlock_t lock; /* protects head */ unsigned long timestamp; - uint16_t seqno; - uint16_t size; - uint16_t total_size; + u16 seqno; + u16 size; + u16 total_size; }; /** @@ -166,7 +166,7 @@ struct batadv_frag_table_entry { struct batadv_frag_list_entry { struct hlist_node list; struct sk_buff *skb; - uint8_t no; + u8 no; }; /** @@ -175,7 +175,7 @@ struct batadv_frag_list_entry { * @num_entries: number of TT entries for this VLAN */ struct batadv_vlan_tt { - uint32_t crc; + u32 crc; atomic_t num_entries; }; @@ -206,7 +206,7 @@ struct batadv_orig_node_vlan { */ struct batadv_orig_bat_iv { unsigned long *bcast_own; - uint8_t *bcast_own_sum; + u8 *bcast_own_sum; /* ogm_cnt_lock protects: bcast_own, bcast_own_sum, * neigh_node->bat_iv.real_bits & neigh_node->bat_iv.real_packet_count */ @@ -260,7 +260,7 @@ struct batadv_orig_bat_iv { * @bat_iv: B.A.T.M.A.N. IV private structure */ struct batadv_orig_node { - uint8_t orig[ETH_ALEN]; + u8 orig[ETH_ALEN]; struct hlist_head ifinfo_list; struct batadv_orig_ifinfo *last_bonding_candidate; #ifdef CONFIG_BATMAN_ADV_DAT @@ -271,7 +271,7 @@ struct batadv_orig_node { #ifdef CONFIG_BATMAN_ADV_MCAST /* synchronizes mcast tvlv specific orig changes */ spinlock_t mcast_handler_lock; - uint8_t mcast_flags; + u8 mcast_flags; struct hlist_node mcast_want_all_unsnoopables_node; struct hlist_node mcast_want_all_ipv4_node; struct hlist_node mcast_want_all_ipv6_node; @@ -280,12 +280,12 @@ struct batadv_orig_node { unsigned long capa_initialized; atomic_t last_ttvn; unsigned char *tt_buff; - int16_t tt_buff_len; + s16 tt_buff_len; spinlock_t tt_buff_lock; /* protects tt_buff & tt_buff_len */ /* prevents from changing the table while reading it */ spinlock_t tt_lock; DECLARE_BITMAP(bcast_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); - uint32_t last_bcast_seqno; + u32 last_bcast_seqno; struct hlist_head neigh_list; /* neigh_list_lock protects: neigh_list and router */ spinlock_t neigh_list_lock; @@ -335,8 +335,8 @@ enum batadv_orig_capabilities { struct batadv_gw_node { struct hlist_node list; struct batadv_orig_node *orig_node; - uint32_t bandwidth_down; - uint32_t bandwidth_up; + u32 bandwidth_down; + u32 bandwidth_up; unsigned long deleted; atomic_t refcount; struct rcu_head rcu; @@ -358,7 +358,7 @@ struct batadv_gw_node { struct batadv_neigh_node { struct hlist_node list; struct batadv_orig_node *orig_node; - uint8_t addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; struct hlist_head ifinfo_list; spinlock_t ifinfo_lock; /* protects ifinfo_list and its members */ struct batadv_hard_iface *if_incoming; @@ -378,11 +378,11 @@ struct batadv_neigh_node { * @real_packet_count: counted result of real_bits */ struct batadv_neigh_ifinfo_bat_iv { - uint8_t tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; - uint8_t tq_index; - uint8_t tq_avg; + u8 tq_recv[BATADV_TQ_GLOBAL_WINDOW_SIZE]; + u8 tq_index; + u8 tq_avg; DECLARE_BITMAP(real_bits, BATADV_TQ_LOCAL_WINDOW_SIZE); - uint8_t real_packet_count; + u8 real_packet_count; }; /** @@ -398,7 +398,7 @@ struct batadv_neigh_ifinfo { struct hlist_node list; struct batadv_hard_iface *if_outgoing; struct batadv_neigh_ifinfo_bat_iv bat_iv; - uint8_t last_ttl; + u8 last_ttl; atomic_t refcount; struct rcu_head rcu; }; @@ -411,7 +411,7 @@ struct batadv_neigh_ifinfo { */ #ifdef CONFIG_BATMAN_ADV_BLA struct batadv_bcast_duplist_entry { - uint8_t orig[ETH_ALEN]; + u8 orig[ETH_ALEN]; __be32 crc; unsigned long entrytime; }; @@ -543,7 +543,7 @@ struct batadv_priv_tt { spinlock_t req_list_lock; /* protects req_list */ spinlock_t roam_list_lock; /* protects roam_list */ unsigned char *last_changeset; - int16_t last_changeset_len; + s16 last_changeset_len; /* protects last_changeset & last_changeset_len */ spinlock_t last_changeset_lock; /* prevents from executing a commit while reading the table */ @@ -663,7 +663,7 @@ struct batadv_priv_mcast { struct hlist_head want_all_unsnoopables_list; struct hlist_head want_all_ipv4_list; struct hlist_head want_all_ipv6_list; - uint8_t flags; + u8 flags; bool enabled; atomic_t num_disabled; atomic_t num_want_all_unsnoopables; @@ -781,7 +781,7 @@ struct batadv_priv { atomic_t mesh_state; struct net_device *soft_iface; struct net_device_stats stats; - uint64_t __percpu *bat_counters; /* Per cpu counters */ + u64 __percpu *bat_counters; /* Per cpu counters */ atomic_t aggregated_ogms; atomic_t bonding; atomic_t fragmentation; @@ -803,8 +803,8 @@ struct batadv_priv { #ifdef CONFIG_BATMAN_ADV_DEBUG atomic_t log_level; #endif - uint32_t isolation_mark; - uint32_t isolation_mark_mask; + u32 isolation_mark; + u32 isolation_mark_mask; atomic_t bcast_seqno; atomic_t bcast_queue_left; atomic_t batman_queue_left; @@ -870,7 +870,7 @@ struct batadv_socket_client { struct batadv_socket_packet { struct list_head list; size_t icmp_len; - uint8_t icmp_packet[BATADV_ICMP_MAX_PACKET_SIZE]; + u8 icmp_packet[BATADV_ICMP_MAX_PACKET_SIZE]; }; /** @@ -891,14 +891,14 @@ struct batadv_socket_packet { */ #ifdef CONFIG_BATMAN_ADV_BLA struct batadv_bla_backbone_gw { - uint8_t orig[ETH_ALEN]; + u8 orig[ETH_ALEN]; unsigned short vid; struct hlist_node hash_entry; struct batadv_priv *bat_priv; unsigned long lasttime; atomic_t wait_periods; atomic_t request_sent; - uint16_t crc; + u16 crc; atomic_t refcount; struct rcu_head rcu; }; @@ -914,7 +914,7 @@ struct batadv_bla_backbone_gw { * @rcu: struct used for freeing in an RCU-safe manner */ struct batadv_bla_claim { - uint8_t addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; unsigned short vid; struct batadv_bla_backbone_gw *backbone_gw; unsigned long lasttime; @@ -936,10 +936,10 @@ struct batadv_bla_claim { * @rcu: struct used for freeing in an RCU-safe manner */ struct batadv_tt_common_entry { - uint8_t addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; unsigned short vid; struct hlist_node hash_entry; - uint16_t flags; + u16 flags; unsigned long added_at; atomic_t refcount; struct rcu_head rcu; @@ -981,7 +981,7 @@ struct batadv_tt_global_entry { */ struct batadv_tt_orig_list_entry { struct batadv_orig_node *orig_node; - uint8_t ttvn; + u8 ttvn; struct hlist_node list; atomic_t refcount; struct rcu_head rcu; @@ -1004,7 +1004,7 @@ struct batadv_tt_change_node { * @list: list node for batadv_priv_tt::req_list */ struct batadv_tt_req_node { - uint8_t addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; unsigned long issued_at; struct list_head list; }; @@ -1018,7 +1018,7 @@ struct batadv_tt_req_node { * @list: list node for batadv_priv_tt::roam_list */ struct batadv_tt_roam_node { - uint8_t addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; atomic_t counter; unsigned long first_time; struct list_head list; @@ -1035,7 +1035,7 @@ struct batadv_tt_roam_node { */ struct batadv_nc_node { struct list_head list; - uint8_t addr[ETH_ALEN]; + u8 addr[ETH_ALEN]; atomic_t refcount; struct rcu_head rcu; struct batadv_orig_node *orig_node; @@ -1059,8 +1059,8 @@ struct batadv_nc_path { atomic_t refcount; struct list_head packet_list; spinlock_t packet_list_lock; /* Protects packet_list */ - uint8_t next_hop[ETH_ALEN]; - uint8_t prev_hop[ETH_ALEN]; + u8 next_hop[ETH_ALEN]; + u8 prev_hop[ETH_ALEN]; unsigned long last_valid; }; @@ -1112,11 +1112,11 @@ struct batadv_skb_cb { struct batadv_forw_packet { struct hlist_node list; unsigned long send_time; - uint8_t own; + u8 own; struct sk_buff *skb; - uint16_t packet_len; - uint32_t direct_link_flags; - uint8_t num_packets; + u16 packet_len; + u32 direct_link_flags; + u8 num_packets; struct delayed_work delayed_work; struct batadv_hard_iface *if_incoming; struct batadv_hard_iface *if_outgoing; @@ -1191,7 +1191,7 @@ struct batadv_algo_ops { */ struct batadv_dat_entry { __be32 ip; - uint8_t mac_addr[ETH_ALEN]; + u8 mac_addr[ETH_ALEN]; unsigned short vid; unsigned long last_update; struct hlist_node hash_entry; @@ -1253,14 +1253,13 @@ struct batadv_tvlv_handler { struct hlist_node list; void (*ogm_handler)(struct batadv_priv *bat_priv, struct batadv_orig_node *orig, - uint8_t flags, - void *tvlv_value, uint16_t tvlv_value_len); + u8 flags, void *tvlv_value, u16 tvlv_value_len); int (*unicast_handler)(struct batadv_priv *bat_priv, - uint8_t *src, uint8_t *dst, - void *tvlv_value, uint16_t tvlv_value_len); - uint8_t type; - uint8_t version; - uint8_t flags; + u8 *src, u8 *dst, + void *tvlv_value, u16 tvlv_value_len); + u8 type; + u8 version; + u8 flags; atomic_t refcount; struct rcu_head rcu; }; -- GitLab From 34473822da06510d708087bb76d9ad757ac09567 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 31 May 2015 10:10:20 +0200 Subject: [PATCH 4724/7006] batman-adv: Fix kerneldoc over 80 column lines Kerneldoc required single line documentation in the past (before 2009). Therefore, the 80 columns limit per line check of checkpatch was disabled for kerneldoc. But kerneldoc is not excluded anymore from it and checkpatch now enabled the check again. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/icmp_socket.c | 4 ++-- net/batman-adv/network-coding.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/batman-adv/icmp_socket.c b/net/batman-adv/icmp_socket.c index 5a70b7ed25581..bcabb5e3f4d3a 100644 --- a/net/batman-adv/icmp_socket.c +++ b/net/batman-adv/icmp_socket.c @@ -337,8 +337,8 @@ err: } /** - * batadv_socket_receive_packet - schedule an icmp packet to be sent to userspace - * on an icmp socket. + * batadv_socket_receive_packet - schedule an icmp packet to be sent to + * userspace on an icmp socket. * @socket_client: the socket this packet belongs to * @icmph: pointer to the header of the icmp packet * @icmp_len: total length of the icmp packet diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 60dc7a6910b1f..5cab144000be8 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -872,8 +872,8 @@ free: } /** - * batadv_nc_update_nc_node - updates stored incoming and outgoing nc node structs - * (best called on incoming OGMs) + * batadv_nc_update_nc_node - updates stored incoming and outgoing nc node + * structs (best called on incoming OGMs) * @bat_priv: the bat priv with all the soft interface information * @orig_node: orig node originating the ogm packet * @orig_neigh_node: neighboring orig node from which we received the ogm packet -- GitLab From 4f248cff9e21720bd5f057661f752fba067f3779 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Tue, 9 Jun 2015 20:50:49 +0200 Subject: [PATCH 4725/7006] batman-adv: Remove multiple assignment per line The Linux CodingStyle disallows multiple assignments in a single line. (see chapter 1) Reported-by: Markus Pargmann Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 6 ++++-- net/batman-adv/bridge_loop_avoidance.c | 6 ++++-- net/batman-adv/distributed-arp-table.c | 3 ++- net/batman-adv/gateway_client.c | 15 ++++++++++----- net/batman-adv/gateway_common.c | 5 ++++- net/batman-adv/network-coding.c | 3 ++- net/batman-adv/translation-table.c | 18 +++++++++++++----- 7 files changed, 39 insertions(+), 17 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index f550a6ab77bbf..df5411845c7da 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -1004,7 +1004,8 @@ batadv_iv_ogm_orig_update(struct batadv_priv *bat_priv, { struct batadv_neigh_ifinfo *neigh_ifinfo = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL; - struct batadv_neigh_node *neigh_node = NULL, *tmp_neigh_node = NULL; + struct batadv_neigh_node *neigh_node = NULL; + struct batadv_neigh_node *tmp_neigh_node = NULL; struct batadv_neigh_node *router = NULL; struct batadv_orig_node *orig_node_tmp; int if_num; @@ -1404,7 +1405,8 @@ batadv_iv_ogm_process_per_outif(const struct sk_buff *skb, int ogm_offset, struct batadv_hard_iface *if_outgoing) { struct batadv_priv *bat_priv = netdev_priv(if_incoming->soft_iface); - struct batadv_neigh_node *router = NULL, *router_router = NULL; + struct batadv_neigh_node *router = NULL; + struct batadv_neigh_node *router_router = NULL; struct batadv_orig_node *orig_neigh_node; struct batadv_orig_ifinfo *orig_ifinfo; struct batadv_neigh_node *orig_neigh_router = NULL; diff --git a/net/batman-adv/bridge_loop_avoidance.c b/net/batman-adv/bridge_loop_avoidance.c index 8f9059f15ebb9..191a70290dca2 100644 --- a/net/batman-adv/bridge_loop_avoidance.c +++ b/net/batman-adv/bridge_loop_avoidance.c @@ -88,7 +88,8 @@ static int batadv_compare_backbone_gw(const struct hlist_node *node, { const void *data1 = container_of(node, struct batadv_bla_backbone_gw, hash_entry); - const struct batadv_bla_backbone_gw *gw1 = data1, *gw2 = data2; + const struct batadv_bla_backbone_gw *gw1 = data1; + const struct batadv_bla_backbone_gw *gw2 = data2; if (!batadv_compare_eth(gw1->orig, gw2->orig)) return 0; @@ -105,7 +106,8 @@ static int batadv_compare_claim(const struct hlist_node *node, { const void *data1 = container_of(node, struct batadv_bla_claim, hash_entry); - const struct batadv_bla_claim *cl1 = data1, *cl2 = data2; + const struct batadv_bla_claim *cl1 = data1; + const struct batadv_bla_claim *cl2 = data2; if (!batadv_compare_eth(cl1->addr, cl2->addr)) return 0; diff --git a/net/batman-adv/distributed-arp-table.c b/net/batman-adv/distributed-arp-table.c index a63ea27eca6c6..83bc1aaf5800c 100644 --- a/net/batman-adv/distributed-arp-table.c +++ b/net/batman-adv/distributed-arp-table.c @@ -497,7 +497,8 @@ static void batadv_choose_next_candidate(struct batadv_priv *bat_priv, int select, batadv_dat_addr_t ip_key, batadv_dat_addr_t *last_max) { - batadv_dat_addr_t max = 0, tmp_max = 0; + batadv_dat_addr_t max = 0; + batadv_dat_addr_t tmp_max = 0; struct batadv_orig_node *orig_node, *max_orig_node = NULL; struct batadv_hashtable *hash = bat_priv->orig_hash; struct hlist_head *head; diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 6269c75919bf5..d7ca2144e62c1 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -153,7 +153,8 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) struct batadv_neigh_node *router; struct batadv_neigh_ifinfo *router_ifinfo; struct batadv_gw_node *gw_node, *curr_gw = NULL; - u64 max_gw_factor = 0, tmp_gw_factor = 0; + u64 max_gw_factor = 0; + u64 tmp_gw_factor = 0; u8 max_tq = 0; u8 tq_avg; struct batadv_orig_node *orig_node; @@ -263,7 +264,8 @@ void batadv_gw_check_client_stop(struct batadv_priv *bat_priv) void batadv_gw_election(struct batadv_priv *bat_priv) { - struct batadv_gw_node *curr_gw = NULL, *next_gw = NULL; + struct batadv_gw_node *curr_gw = NULL; + struct batadv_gw_node *next_gw = NULL; struct batadv_neigh_node *router = NULL; struct batadv_neigh_ifinfo *router_ifinfo = NULL; char gw_addr[18] = { '\0' }; @@ -347,7 +349,8 @@ void batadv_gw_check_election(struct batadv_priv *bat_priv, struct batadv_neigh_ifinfo *router_orig_tq = NULL; struct batadv_neigh_ifinfo *router_gw_tq = NULL; struct batadv_orig_node *curr_gw_orig; - struct batadv_neigh_node *router_gw = NULL, *router_orig = NULL; + struct batadv_neigh_node *router_gw = NULL; + struct batadv_neigh_node *router_orig = NULL; u8 gw_tq_avg, orig_tq_avg; curr_gw_orig = batadv_gw_get_selected_orig(bat_priv); @@ -808,9 +811,11 @@ batadv_gw_dhcp_recipient_get(struct sk_buff *skb, unsigned int *header_len, bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb) { - struct batadv_neigh_node *neigh_curr = NULL, *neigh_old = NULL; + struct batadv_neigh_node *neigh_curr = NULL; + struct batadv_neigh_node *neigh_old = NULL; struct batadv_orig_node *orig_dst_node = NULL; - struct batadv_gw_node *gw_node = NULL, *curr_gw = NULL; + struct batadv_gw_node *gw_node = NULL; + struct batadv_gw_node *curr_gw = NULL; struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; struct ethhdr *ethhdr = (struct ethhdr *)skb->data; bool out_of_range = false; diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 9e32c8ebc28fb..c50931cbfbb51 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -149,7 +149,10 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, size_t count) { struct batadv_priv *bat_priv = netdev_priv(net_dev); - u32 down_curr, up_curr, down_new = 0, up_new = 0; + u32 down_curr; + u32 up_curr; + u32 down_new = 0; + u32 up_new = 0; bool ret; down_curr = (unsigned int)atomic_read(&bat_priv->gw.bandwidth_down); diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index 5cab144000be8..ccfe5d86b106b 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -887,7 +887,8 @@ void batadv_nc_update_nc_node(struct batadv_priv *bat_priv, struct batadv_ogm_packet *ogm_packet, int is_single_hop_neigh) { - struct batadv_nc_node *in_nc_node = NULL, *out_nc_node = NULL; + struct batadv_nc_node *in_nc_node = NULL; + struct batadv_nc_node *out_nc_node = NULL; /* Check if network coding is enabled */ if (!atomic_read(&bat_priv->network_coding)) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index f90898881eeec..7e34901e214c0 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -462,7 +462,8 @@ static u16 batadv_tt_entries(u16 tt_len) */ static int batadv_tt_local_table_transmit_size(struct batadv_priv *bat_priv) { - u16 num_vlan = 0, tt_local_entries = 0; + u16 num_vlan = 0; + u16 tt_local_entries = 0; struct batadv_softif_vlan *vlan; int hdr_size; @@ -536,7 +537,8 @@ bool batadv_tt_local_add(struct net_device *soft_iface, const u8 *addr, struct hlist_head *head; struct batadv_tt_orig_list_entry *orig_entry; int hash_added, table_size, packet_size_max; - bool ret = false, roamed_back = false; + bool ret = false; + bool roamed_back = false; u8 remote_flags; u32 match_mark; @@ -730,7 +732,10 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, struct batadv_tvlv_tt_change **tt_change, s32 *tt_len) { - u16 num_vlan = 0, num_entries = 0, change_offset, tvlv_len; + u16 num_vlan = 0; + u16 num_entries = 0; + u16 change_offset; + u16 tvlv_len; struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_orig_node_vlan *vlan; u8 *tt_change_ptr; @@ -803,7 +808,9 @@ batadv_tt_prepare_tvlv_local_data(struct batadv_priv *bat_priv, { struct batadv_tvlv_tt_vlan_data *tt_vlan; struct batadv_softif_vlan *vlan; - u16 num_vlan = 0, num_entries = 0, tvlv_len; + u16 num_vlan = 0; + u16 num_entries = 0; + u16 tvlv_len; u8 *tt_change_ptr; int change_offset; @@ -860,7 +867,8 @@ static void batadv_tt_tvlv_container_update(struct batadv_priv *bat_priv) struct batadv_tvlv_tt_data *tt_data; struct batadv_tvlv_tt_change *tt_change; int tt_diff_len, tt_change_len = 0; - int tt_diff_entries_num = 0, tt_diff_entries_count = 0; + int tt_diff_entries_num = 0; + int tt_diff_entries_count = 0; u16 tvlv_len; tt_diff_entries_num = atomic_read(&bat_priv->tt.local_changes); -- GitLab From 433ff98f3f1d6baa56e23f6b50370a5ab16c0e66 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Thu, 18 Jun 2015 16:11:07 +0800 Subject: [PATCH 4726/7006] batman-adv: update kernel doc of batadv_tt_global_del_orig_entry() The updated kernel doc & additional comment shall prevent accidental copy & paste errors or calling the function without the required precautions. Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/translation-table.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 7e34901e214c0..6b5f718f67059 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1658,20 +1658,26 @@ out: } /** - * batadv_tt_global_del_orig_entry - remove and free an orig_entry + * _batadv_tt_global_del_orig_entry - remove and free an orig_entry * @tt_global_entry: the global entry to remove the orig_entry from * @orig_entry: the orig entry to remove and free * * Remove an orig_entry from its list in the given tt_global_entry and * free this orig_entry afterwards. + * + * Caller must hold tt_global_entry->list_lock and ensure orig_entry->list is + * part of a list. */ static void -batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, - struct batadv_tt_orig_list_entry *orig_entry) +_batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, + struct batadv_tt_orig_list_entry *orig_entry) { batadv_tt_global_size_dec(orig_entry->orig_node, tt_global_entry->common.vid); atomic_dec(&tt_global_entry->orig_list_count); + /* requires holding tt_global_entry->list_lock and orig_entry->list + * being part of a list + */ hlist_del_rcu(&orig_entry->list); batadv_tt_orig_list_entry_free_ref(orig_entry); } @@ -1687,7 +1693,7 @@ batadv_tt_global_del_orig_list(struct batadv_tt_global_entry *tt_global_entry) spin_lock_bh(&tt_global_entry->list_lock); head = &tt_global_entry->orig_list; hlist_for_each_entry_safe(orig_entry, safe, head, list) - batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); + _batadv_tt_global_del_orig_entry(tt_global_entry, orig_entry); spin_unlock_bh(&tt_global_entry->list_lock); } @@ -1722,8 +1728,8 @@ batadv_tt_global_del_orig_node(struct batadv_priv *bat_priv, orig_node->orig, tt_global_entry->common.addr, BATADV_PRINT_VID(vid), message); - batadv_tt_global_del_orig_entry(tt_global_entry, - orig_entry); + _batadv_tt_global_del_orig_entry(tt_global_entry, + orig_entry); } } spin_unlock_bh(&tt_global_entry->list_lock); -- GitLab From 383b863620aa5127200bff591f7465d593290997 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Thu, 18 Jun 2015 16:24:24 +0800 Subject: [PATCH 4727/7006] batman-adv: rename batadv_new_tt_req_node to batadv_tt_req_node_new Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/translation-table.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 6b5f718f67059..3932df200db6d 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -2272,11 +2272,16 @@ static void batadv_tt_req_purge(struct batadv_priv *bat_priv) spin_unlock_bh(&bat_priv->tt.req_list_lock); } -/* returns the pointer to the new tt_req_node struct if no request - * has already been issued for this orig_node, NULL otherwise +/** + * batadv_tt_req_node_new - search and possibly create a tt_req_node object + * @bat_priv: the bat priv with all the soft interface information + * @orig_node: orig node this request is being issued for + * + * Returns the pointer to the new tt_req_node struct if no request + * has already been issued for this orig_node, NULL otherwise. */ static struct batadv_tt_req_node * -batadv_new_tt_req_node(struct batadv_priv *bat_priv, +batadv_tt_req_node_new(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node) { struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; @@ -2505,7 +2510,7 @@ static int batadv_send_tt_request(struct batadv_priv *bat_priv, /* The new tt_req will be issued only if I'm not waiting for a * reply from the same orig_node yet */ - tt_req_node = batadv_new_tt_req_node(bat_priv, dst_orig_node); + tt_req_node = batadv_tt_req_node_new(bat_priv, dst_orig_node); if (!tt_req_node) goto out; -- GitLab From 2bdd1888f147576fb870a926a4d015305b5bbeee Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Thu, 18 Jun 2015 18:53:19 +0200 Subject: [PATCH 4728/7006] batman-adv: Remove batadv_ types forward declarations main.h is included in every file and is the only way to access types.h. This makes forward declarations for all types defined in types.h unnecessary. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/bridge_loop_avoidance.h | 3 --- net/batman-adv/debugfs.h | 1 - net/batman-adv/gateway_common.h | 1 - net/batman-adv/icmp_socket.h | 1 - net/batman-adv/multicast.h | 2 -- net/batman-adv/network-coding.h | 4 ---- net/batman-adv/routing.h | 4 ---- net/batman-adv/send.h | 3 --- net/batman-adv/soft-interface.h | 4 ---- net/batman-adv/sysfs.h | 2 -- net/batman-adv/translation-table.h | 2 -- 11 files changed, 27 deletions(-) diff --git a/net/batman-adv/bridge_loop_avoidance.h b/net/batman-adv/bridge_loop_avoidance.h index 449f2f1350a52..025152b342823 100644 --- a/net/batman-adv/bridge_loop_avoidance.h +++ b/net/batman-adv/bridge_loop_avoidance.h @@ -22,9 +22,6 @@ #include -struct batadv_hard_iface; -struct batadv_orig_node; -struct batadv_priv; struct seq_file; struct sk_buff; diff --git a/net/batman-adv/debugfs.h b/net/batman-adv/debugfs.h index 187acdc85dfaf..80ab8d6f0ab3c 100644 --- a/net/batman-adv/debugfs.h +++ b/net/batman-adv/debugfs.h @@ -22,7 +22,6 @@ #include -struct batadv_hard_iface; struct net_device; #define BATADV_DEBUGFS_SUBDIR "batman_adv" diff --git a/net/batman-adv/gateway_common.h b/net/batman-adv/gateway_common.h index bd5c812cebf48..ab893e3182292 100644 --- a/net/batman-adv/gateway_common.h +++ b/net/batman-adv/gateway_common.h @@ -22,7 +22,6 @@ #include -struct batadv_priv; struct net_device; enum batadv_gw_modes { diff --git a/net/batman-adv/icmp_socket.h b/net/batman-adv/icmp_socket.h index 7de7fce4b48ca..e937143f0b102 100644 --- a/net/batman-adv/icmp_socket.h +++ b/net/batman-adv/icmp_socket.h @@ -23,7 +23,6 @@ #include struct batadv_icmp_header; -struct batadv_priv; #define BATADV_ICMP_SOCKET "socket" diff --git a/net/batman-adv/multicast.h b/net/batman-adv/multicast.h index beb6e56c624af..8f3cb04b9f13f 100644 --- a/net/batman-adv/multicast.h +++ b/net/batman-adv/multicast.h @@ -20,8 +20,6 @@ #include "main.h" -struct batadv_orig_node; -struct batadv_priv; struct sk_buff; /** diff --git a/net/batman-adv/network-coding.h b/net/batman-adv/network-coding.h index 5b79aa8c64c1f..8f6d4ad8778ad 100644 --- a/net/batman-adv/network-coding.h +++ b/net/batman-adv/network-coding.h @@ -22,11 +22,7 @@ #include -struct batadv_nc_node; -struct batadv_neigh_node; struct batadv_ogm_packet; -struct batadv_orig_node; -struct batadv_priv; struct net_device; struct seq_file; struct sk_buff; diff --git a/net/batman-adv/routing.h b/net/batman-adv/routing.h index 3c185a1fb7a94..204bbe4952a6d 100644 --- a/net/batman-adv/routing.h +++ b/net/batman-adv/routing.h @@ -22,10 +22,6 @@ #include -struct batadv_hard_iface; -struct batadv_neigh_node; -struct batadv_orig_node; -struct batadv_priv; struct sk_buff; bool batadv_check_management_packet(struct sk_buff *skb, diff --git a/net/batman-adv/send.h b/net/batman-adv/send.h index 33ef6fc1030d9..82059f259e468 100644 --- a/net/batman-adv/send.h +++ b/net/batman-adv/send.h @@ -25,9 +25,6 @@ #include "packet.h" -struct batadv_hard_iface; -struct batadv_orig_node; -struct batadv_priv; struct sk_buff; struct work_struct; diff --git a/net/batman-adv/soft-interface.h b/net/batman-adv/soft-interface.h index 578e8a663c302..8e82176f40b1f 100644 --- a/net/batman-adv/soft-interface.h +++ b/net/batman-adv/soft-interface.h @@ -22,10 +22,6 @@ #include -struct batadv_hard_iface; -struct batadv_orig_node; -struct batadv_priv; -struct batadv_softif_vlan; struct net_device; struct sk_buff; diff --git a/net/batman-adv/sysfs.h b/net/batman-adv/sysfs.h index 2294583f7cf98..61974428a7af3 100644 --- a/net/batman-adv/sysfs.h +++ b/net/batman-adv/sysfs.h @@ -23,8 +23,6 @@ #include #include -struct batadv_priv; -struct batadv_softif_vlan; struct kobject; struct net_device; diff --git a/net/batman-adv/translation-table.h b/net/batman-adv/translation-table.h index 9b82d5dd56e04..abd8e116e5fb0 100644 --- a/net/batman-adv/translation-table.h +++ b/net/batman-adv/translation-table.h @@ -22,8 +22,6 @@ #include -struct batadv_orig_node; -struct batadv_priv; struct net_device; struct seq_file; -- GitLab From d0fa4f3f5b0419a016ff27eea2fa615e4c0d1713 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Jun 2015 00:30:22 +0800 Subject: [PATCH 4729/7006] batman-adv: convert orig_node->vlan_list to hlist Since the list's tail is never accessed using a double linked list head wastes memory. Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/originator.c | 7 ++++--- net/batman-adv/translation-table.c | 8 ++++---- net/batman-adv/types.h | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 4500e3a087191..610620aa8d261 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ batadv_orig_node_vlan_get(struct batadv_orig_node *orig_node, struct batadv_orig_node_vlan *vlan = NULL, *tmp; rcu_read_lock(); - list_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) { + hlist_for_each_entry_rcu(tmp, &orig_node->vlan_list, list) { if (tmp->vid != vid) continue; @@ -118,7 +119,7 @@ batadv_orig_node_vlan_new(struct batadv_orig_node *orig_node, atomic_set(&vlan->refcount, 2); vlan->vid = vid; - list_add_rcu(&vlan->list, &orig_node->vlan_list); + hlist_add_head_rcu(&vlan->list, &orig_node->vlan_list); out: spin_unlock_bh(&orig_node->vlan_list_lock); @@ -673,7 +674,7 @@ struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, return NULL; INIT_HLIST_HEAD(&orig_node->neigh_list); - INIT_LIST_HEAD(&orig_node->vlan_list); + INIT_HLIST_HEAD(&orig_node->vlan_list); INIT_HLIST_HEAD(&orig_node->ifinfo_list); spin_lock_init(&orig_node->bcast_seqno_lock); spin_lock_init(&orig_node->neigh_list_lock); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 3932df200db6d..9e1f866a59f4f 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -315,7 +315,7 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { spin_lock_bh(&orig_node->vlan_list_lock); - list_del_rcu(&vlan->list); + hlist_del_rcu(&vlan->list); spin_unlock_bh(&orig_node->vlan_list_lock); batadv_orig_node_vlan_free_ref(vlan); } @@ -741,7 +741,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, u8 *tt_change_ptr; rcu_read_lock(); - list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { + hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { num_vlan++; num_entries += atomic_read(&vlan->tt.num_entries); } @@ -767,7 +767,7 @@ batadv_tt_prepare_tvlv_global_data(struct batadv_orig_node *orig_node, (*tt_data)->num_vlan = htons(num_vlan); tt_vlan = (struct batadv_tvlv_tt_vlan_data *)(*tt_data + 1); - list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { + hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { tt_vlan->vid = htons(vlan->vid); tt_vlan->crc = htonl(vlan->tt.crc); @@ -2466,7 +2466,7 @@ static void batadv_tt_global_update_crc(struct batadv_priv *bat_priv, /* recompute the global CRC for each VLAN */ rcu_read_lock(); - list_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { + hlist_for_each_entry_rcu(vlan, &orig_node->vlan_list, list) { /* if orig_node is a backbone node for this VLAN, don't compute * the CRC as we ignore all the global entries over it */ diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index f2ebe33d9b59f..fe3695cb1d40b 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -190,7 +190,7 @@ struct batadv_vlan_tt { struct batadv_orig_node_vlan { unsigned short vid; struct batadv_vlan_tt tt; - struct list_head list; + struct hlist_node list; atomic_t refcount; struct rcu_head rcu; }; @@ -302,7 +302,7 @@ struct batadv_orig_node { spinlock_t out_coding_list_lock; /* Protects out_coding_list */ #endif struct batadv_frag_table_entry fragments[BATADV_FRAG_BUFFER_COUNT]; - struct list_head vlan_list; + struct hlist_head vlan_list; spinlock_t vlan_list_lock; /* protects vlan_list */ struct batadv_orig_bat_iv bat_iv; }; -- GitLab From a121048a89f8186fa2c8388d5b41528466013857 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Mon, 22 Jun 2015 00:30:23 +0800 Subject: [PATCH 4730/7006] batman-adv: prevent potential hlist double deletion The hlist_del_rcu() call in batadv_tt_global_size_mod() does not check if the element still is part of the list prior to deletion. The atomic list counter should prevent the worst but converting to hlist_del_init_rcu() ensures the element can't be deleted more than once. Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/translation-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 9e1f866a59f4f..596e326b01d01 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -315,7 +315,7 @@ static void batadv_tt_global_size_mod(struct batadv_orig_node *orig_node, if (atomic_add_return(v, &vlan->tt.num_entries) == 0) { spin_lock_bh(&orig_node->vlan_list_lock); - hlist_del_rcu(&vlan->list); + hlist_del_init_rcu(&vlan->list); spin_unlock_bh(&orig_node->vlan_list_lock); batadv_orig_node_vlan_free_ref(vlan); } -- GitLab From 77927b7d9dd6c9c5f59f0f49c76cda54b908090e Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 21 Jun 2015 14:42:49 +0200 Subject: [PATCH 4731/7006] batman-adv: Return EINVAL on invalid gw_bandwidth change Invalid speed settings by the user are currently acknowledged as correct but not stored. Instead the return of the store operation of the file "gw_bandwidth" should indicate that the given value is not acceptable. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/gateway_common.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index c50931cbfbb51..6b930a651f382 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -19,6 +19,7 @@ #include "main.h" #include +#include #include #include #include @@ -160,7 +161,7 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, ret = batadv_parse_gw_bandwidth(net_dev, buff, &down_new, &up_new); if (!ret) - goto end; + return -EINVAL; if (!down_new) down_new = 1; @@ -184,7 +185,6 @@ ssize_t batadv_gw_bandwidth_set(struct net_device *net_dev, char *buff, atomic_set(&bat_priv->gw.bandwidth_up, up_new); batadv_gw_tvlv_container_update(bat_priv); -end: return count; } -- GitLab From 0b8336f5fc26f263821534d7a9a3633748692207 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 21 Jun 2015 19:40:09 +0200 Subject: [PATCH 4732/7006] batman-adv: Fix gw_bandwidth calculation on 32 bit systems The TVLV for the gw_bandwidth stores everything as u32. But the gw_bandwidth reads the signed long which limits the maximum value to (2 ** 31 - 1) on systems with 4 byte long. Also the input value is always converted from either Mibit/s or Kibit/s to 100Kibit/s. This reduces the values even further when the user sets it via the default unit Kibit/s. It may even cause an integer overflow and end up with a value the user never intended. Instead read the values as u64, check for possible overflows, do the unit adjustments and then reduce the size to u32. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/gateway_common.c | 49 ++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 7 deletions(-) diff --git a/net/batman-adv/gateway_common.c b/net/batman-adv/gateway_common.c index 6b930a651f382..0cb5e6b6f6d47 100644 --- a/net/batman-adv/gateway_common.c +++ b/net/batman-adv/gateway_common.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,7 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, { enum batadv_bandwidth_units bw_unit_type = BATADV_BW_UNIT_KBIT; char *slash_ptr, *tmp_ptr; - long ldown, lup; + u64 ldown, lup; int ret; slash_ptr = strchr(buff, '/'); @@ -62,7 +63,7 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, *tmp_ptr = '\0'; } - ret = kstrtol(buff, 10, &ldown); + ret = kstrtou64(buff, 10, &ldown); if (ret) { batadv_err(net_dev, "Download speed of gateway mode invalid: %s\n", @@ -72,14 +73,31 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, switch (bw_unit_type) { case BATADV_BW_UNIT_MBIT: - *down = ldown * 10; + /* prevent overflow */ + if (U64_MAX / 10 < ldown) { + batadv_err(net_dev, + "Download speed of gateway mode too large: %s\n", + buff); + return false; + } + + ldown *= 10; break; case BATADV_BW_UNIT_KBIT: default: - *down = ldown / 100; + ldown = div_u64(ldown, 100); break; } + if (U32_MAX < ldown) { + batadv_err(net_dev, + "Download speed of gateway mode too large: %s\n", + buff); + return false; + } + + *down = ldown; + /* we also got some upload info */ if (slash_ptr) { bw_unit_type = BATADV_BW_UNIT_KBIT; @@ -95,7 +113,7 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, *tmp_ptr = '\0'; } - ret = kstrtol(slash_ptr + 1, 10, &lup); + ret = kstrtou64(slash_ptr + 1, 10, &lup); if (ret) { batadv_err(net_dev, "Upload speed of gateway mode invalid: %s\n", @@ -105,13 +123,30 @@ static bool batadv_parse_gw_bandwidth(struct net_device *net_dev, char *buff, switch (bw_unit_type) { case BATADV_BW_UNIT_MBIT: - *up = lup * 10; + /* prevent overflow */ + if (U64_MAX / 10 < lup) { + batadv_err(net_dev, + "Upload speed of gateway mode too large: %s\n", + slash_ptr + 1); + return false; + } + + lup *= 10; break; case BATADV_BW_UNIT_KBIT: default: - *up = lup / 100; + lup = div_u64(lup, 100); break; } + + if (U32_MAX < lup) { + batadv_err(net_dev, + "Upload speed of gateway mode too large: %s\n", + slash_ptr + 1); + return false; + } + + *up = lup; } return true; -- GitLab From 7c26a53ba5e7e4bf2be3cb93f2fffaefccff2e3b Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sun, 28 Jun 2015 22:16:06 +0800 Subject: [PATCH 4733/7006] batman-adv: convert bat_priv->tt.req_list to hlist Since the list's tail is never accessed using a double linked list head wastes memory. Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/main.c | 2 +- net/batman-adv/translation-table.c | 29 ++++++++++++++++------------- net/batman-adv/types.h | 4 ++-- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 40750cbe4f4f3..d277ba724a863 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -148,7 +148,7 @@ int batadv_mesh_init(struct net_device *soft_iface) INIT_HLIST_HEAD(&bat_priv->mcast.want_all_ipv6_list); #endif INIT_LIST_HEAD(&bat_priv->tt.changes_list); - INIT_LIST_HEAD(&bat_priv->tt.req_list); + INIT_HLIST_HEAD(&bat_priv->tt.req_list); INIT_LIST_HEAD(&bat_priv->tt.roam_list); #ifdef CONFIG_BATMAN_ADV_MCAST INIT_HLIST_HEAD(&bat_priv->mcast.mla_list); diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 596e326b01d01..734b456efaf40 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -2224,12 +2224,13 @@ static u32 batadv_tt_local_crc(struct batadv_priv *bat_priv, static void batadv_tt_req_list_free(struct batadv_priv *bat_priv) { - struct batadv_tt_req_node *node, *safe; + struct batadv_tt_req_node *node; + struct hlist_node *safe; spin_lock_bh(&bat_priv->tt.req_list_lock); - list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { - list_del_init(&node->list); + hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { + hlist_del_init(&node->list); kfree(node); } @@ -2259,13 +2260,14 @@ static void batadv_tt_save_orig_buffer(struct batadv_priv *bat_priv, static void batadv_tt_req_purge(struct batadv_priv *bat_priv) { - struct batadv_tt_req_node *node, *safe; + struct batadv_tt_req_node *node; + struct hlist_node *safe; spin_lock_bh(&bat_priv->tt.req_list_lock); - list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { + hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { if (batadv_has_timed_out(node->issued_at, BATADV_TT_REQUEST_TIMEOUT)) { - list_del_init(&node->list); + hlist_del_init(&node->list); kfree(node); } } @@ -2287,7 +2289,7 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv, struct batadv_tt_req_node *tt_req_node_tmp, *tt_req_node = NULL; spin_lock_bh(&bat_priv->tt.req_list_lock); - list_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { + hlist_for_each_entry(tt_req_node_tmp, &bat_priv->tt.req_list, list) { if (batadv_compare_eth(tt_req_node_tmp, orig_node) && !batadv_has_timed_out(tt_req_node_tmp->issued_at, BATADV_TT_REQUEST_TIMEOUT)) @@ -2301,7 +2303,7 @@ batadv_tt_req_node_new(struct batadv_priv *bat_priv, ether_addr_copy(tt_req_node->addr, orig_node->orig); tt_req_node->issued_at = jiffies; - list_add(&tt_req_node->list, &bat_priv->tt.req_list); + hlist_add_head(&tt_req_node->list, &bat_priv->tt.req_list); unlock: spin_unlock_bh(&bat_priv->tt.req_list_lock); return tt_req_node; @@ -2552,8 +2554,8 @@ out: batadv_hardif_free_ref(primary_if); if (ret && tt_req_node) { spin_lock_bh(&bat_priv->tt.req_list_lock); - /* list_del_init() verifies tt_req_node still is in the list */ - list_del_init(&tt_req_node->list); + /* hlist_del_init() verifies tt_req_node still is in the list */ + hlist_del_init(&tt_req_node->list); spin_unlock_bh(&bat_priv->tt.req_list_lock); kfree(tt_req_node); } @@ -2949,7 +2951,8 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, struct batadv_tvlv_tt_data *tt_data, u8 *resp_src, u16 num_entries) { - struct batadv_tt_req_node *node, *safe; + struct batadv_tt_req_node *node; + struct hlist_node *safe; struct batadv_orig_node *orig_node = NULL; struct batadv_tvlv_tt_change *tt_change; u8 *tvlv_ptr = (u8 *)tt_data; @@ -2987,10 +2990,10 @@ static void batadv_handle_tt_response(struct batadv_priv *bat_priv, /* Delete the tt_req_node from pending tt_requests list */ spin_lock_bh(&bat_priv->tt.req_list_lock); - list_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { + hlist_for_each_entry_safe(node, safe, &bat_priv->tt.req_list, list) { if (!batadv_compare_eth(node->addr, resp_src)) continue; - list_del_init(&node->list); + hlist_del_init(&node->list); kfree(node); } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index fe3695cb1d40b..2f5e6c39f9135 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -537,7 +537,7 @@ struct batadv_priv_tt { struct list_head changes_list; struct batadv_hashtable *local_hash; struct batadv_hashtable *global_hash; - struct list_head req_list; + struct hlist_head req_list; struct list_head roam_list; spinlock_t changes_list_lock; /* protects changes */ spinlock_t req_list_lock; /* protects req_list */ @@ -1006,7 +1006,7 @@ struct batadv_tt_change_node { struct batadv_tt_req_node { u8 addr[ETH_ALEN]; unsigned long issued_at; - struct list_head list; + struct hlist_node list; }; /** -- GitLab From 2c72d655b04450056566bcbfe89c2427376b60b4 Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 21 Jun 2015 14:45:14 +0200 Subject: [PATCH 4734/7006] batman-adv: Annotate deleting functions with external lock via lockdep Functions which use (h)list_del* are requiring correct locking when they operate on global lists. Most of the time the search in the list and the delete are done in the same function. All other cases should have it visible that they require a special lock to avoid race conditions. Lockdep asserts can be used to check these problem during runtime when the lockdep functionality is enabled. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/main.c | 11 ++++++++--- net/batman-adv/multicast.c | 13 +++++++++++-- net/batman-adv/network-coding.c | 4 ++++ net/batman-adv/translation-table.c | 2 ++ 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index d277ba724a863..50fc07b9d353e 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -737,13 +738,17 @@ static u16 batadv_tvlv_container_list_size(struct batadv_priv *bat_priv) /** * batadv_tvlv_container_remove - remove tvlv container from the tvlv container * list + * @bat_priv: the bat priv with all the soft interface information * @tvlv: the to be removed tvlv container * * Has to be called with the appropriate locks being acquired * (tvlv.container_list_lock). */ -static void batadv_tvlv_container_remove(struct batadv_tvlv_container *tvlv) +static void batadv_tvlv_container_remove(struct batadv_priv *bat_priv, + struct batadv_tvlv_container *tvlv) { + lockdep_assert_held(&bat_priv->tvlv.handler_list_lock); + if (!tvlv) return; @@ -768,7 +773,7 @@ void batadv_tvlv_container_unregister(struct batadv_priv *bat_priv, spin_lock_bh(&bat_priv->tvlv.container_list_lock); tvlv = batadv_tvlv_container_get(bat_priv, type, version); - batadv_tvlv_container_remove(tvlv); + batadv_tvlv_container_remove(bat_priv, tvlv); spin_unlock_bh(&bat_priv->tvlv.container_list_lock); } @@ -807,7 +812,7 @@ void batadv_tvlv_container_register(struct batadv_priv *bat_priv, spin_lock_bh(&bat_priv->tvlv.container_list_lock); tvlv_old = batadv_tvlv_container_get(bat_priv, type, version); - batadv_tvlv_container_remove(tvlv_old); + batadv_tvlv_container_remove(bat_priv, tvlv_old); hlist_add_head(&tvlv_new->list, &bat_priv->tvlv.container_list); spin_unlock_bh(&bat_priv->tvlv.container_list_lock); } diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 2593f0fe0bad6..410f34cf85c25 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -103,15 +104,19 @@ static bool batadv_mcast_mla_is_duplicate(u8 *mcast_addr, /** * batadv_mcast_mla_list_free - free a list of multicast addresses + * @bat_priv: the bat priv with all the soft interface information * @mcast_list: the list to free * * Removes and frees all items in the given mcast_list. */ -static void batadv_mcast_mla_list_free(struct hlist_head *mcast_list) +static void batadv_mcast_mla_list_free(struct batadv_priv *bat_priv, + struct hlist_head *mcast_list) { struct batadv_hw_addr *mcast_entry; struct hlist_node *tmp; + lockdep_assert_held(&bat_priv->tt.commit_lock); + hlist_for_each_entry_safe(mcast_entry, tmp, mcast_list, list) { hlist_del(&mcast_entry->list); kfree(mcast_entry); @@ -134,6 +139,8 @@ static void batadv_mcast_mla_tt_retract(struct batadv_priv *bat_priv, struct batadv_hw_addr *mcast_entry; struct hlist_node *tmp; + lockdep_assert_held(&bat_priv->tt.commit_lock); + hlist_for_each_entry_safe(mcast_entry, tmp, &bat_priv->mcast.mla_list, list) { if (mcast_list && @@ -164,6 +171,8 @@ static void batadv_mcast_mla_tt_add(struct batadv_priv *bat_priv, struct batadv_hw_addr *mcast_entry; struct hlist_node *tmp; + lockdep_assert_held(&bat_priv->tt.commit_lock); + if (!mcast_list) return; @@ -268,7 +277,7 @@ update: batadv_mcast_mla_tt_add(bat_priv, &mcast_list); out: - batadv_mcast_mla_list_free(&mcast_list); + batadv_mcast_mla_list_free(bat_priv, &mcast_list); } /** diff --git a/net/batman-adv/network-coding.c b/net/batman-adv/network-coding.c index ccfe5d86b106b..f5276be2c77c8 100644 --- a/net/batman-adv/network-coding.c +++ b/net/batman-adv/network-coding.c @@ -586,6 +586,8 @@ static bool batadv_nc_sniffed_purge(struct batadv_priv *bat_priv, unsigned long timeout = bat_priv->nc.max_buffer_time; bool res = false; + lockdep_assert_held(&nc_path->packet_list_lock); + /* Packets are added to tail, so the remaining packets did not time * out and we can stop processing the current queue */ @@ -622,6 +624,8 @@ static bool batadv_nc_fwd_flush(struct batadv_priv *bat_priv, { unsigned long timeout = bat_priv->nc.max_fwd_delay; + lockdep_assert_held(&nc_path->packet_list_lock); + /* Packets are added to tail, so the remaining packets did not time * out and we can stop processing the current queue */ diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 734b456efaf40..79cee7b771dc9 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -1672,6 +1672,8 @@ static void _batadv_tt_global_del_orig_entry(struct batadv_tt_global_entry *tt_global_entry, struct batadv_tt_orig_list_entry *orig_entry) { + lockdep_assert_held(&tt_global_entry->list_lock); + batadv_tt_global_size_dec(orig_entry->orig_node, tt_global_entry->common.vid); atomic_dec(&tt_global_entry->orig_list_count); -- GitLab From 5274cd68d744b4bc59b32d87cbde70803130eb3f Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Sun, 21 Jun 2015 14:45:15 +0200 Subject: [PATCH 4735/7006] batman-adv: Add lockdep_asserts for documented external locks Some functions already have documentation about locks they require inside their kerneldoc header. These can be directly tested during runtime using the lockdep asserts. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/fragmentation.c | 3 +++ net/batman-adv/multicast.c | 6 ++++++ net/batman-adv/translation-table.c | 2 ++ 3 files changed, 11 insertions(+) diff --git a/net/batman-adv/fragmentation.c b/net/batman-adv/fragmentation.c index ec5f7bcad66ea..700c96c82a151 100644 --- a/net/batman-adv/fragmentation.c +++ b/net/batman-adv/fragmentation.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -112,6 +113,8 @@ static int batadv_frag_size_limit(void) static bool batadv_frag_init_chain(struct batadv_frag_table_entry *chain, u16 seqno) { + lockdep_assert_held(&chain->lock); + if (chain->seqno == seqno) return false; diff --git a/net/batman-adv/multicast.c b/net/batman-adv/multicast.c index 410f34cf85c25..eb76386f8d4b5 100644 --- a/net/batman-adv/multicast.c +++ b/net/batman-adv/multicast.c @@ -609,6 +609,8 @@ static void batadv_mcast_want_unsnoop_update(struct batadv_priv *bat_priv, struct hlist_node *node = &orig->mcast_want_all_unsnoopables_node; struct hlist_head *head = &bat_priv->mcast.want_all_unsnoopables_list; + lockdep_assert_held(&orig->mcast_handler_lock); + /* switched from flag unset to set */ if (mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES && !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_UNSNOOPABLES)) { @@ -652,6 +654,8 @@ static void batadv_mcast_want_ipv4_update(struct batadv_priv *bat_priv, struct hlist_node *node = &orig->mcast_want_all_ipv4_node; struct hlist_head *head = &bat_priv->mcast.want_all_ipv4_list; + lockdep_assert_held(&orig->mcast_handler_lock); + /* switched from flag unset to set */ if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV4 && !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV4)) { @@ -695,6 +699,8 @@ static void batadv_mcast_want_ipv6_update(struct batadv_priv *bat_priv, struct hlist_node *node = &orig->mcast_want_all_ipv6_node; struct hlist_head *head = &bat_priv->mcast.want_all_ipv6_list; + lockdep_assert_held(&orig->mcast_handler_lock); + /* switched from flag unset to set */ if (mcast_flags & BATADV_MCAST_WANT_ALL_IPV6 && !(orig->mcast_flags & BATADV_MCAST_WANT_ALL_IPV6)) { diff --git a/net/batman-adv/translation-table.c b/net/batman-adv/translation-table.c index 79cee7b771dc9..4228b10c47ead 100644 --- a/net/batman-adv/translation-table.c +++ b/net/batman-adv/translation-table.c @@ -3271,6 +3271,8 @@ static void batadv_tt_local_purge_pending_clients(struct batadv_priv *bat_priv) */ static void batadv_tt_local_commit_changes_nolock(struct batadv_priv *bat_priv) { + lockdep_assert_held(&bat_priv->tt.commit_lock); + /* Update multicast addresses in local translation table */ batadv_mcast_mla_update(bat_priv); -- GitLab From 87b40f534d2a266eec55a897e9a93f3b022c901d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 17 Jul 2015 10:03:42 +0200 Subject: [PATCH 4736/7006] batman-adv: Fix conditional statements indentation commit 29b9256e6631 ("batman-adv: consider outgoing interface in OGM sending") incorrectly indented the interface check code. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index df5411845c7da..5c122000688fb 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -968,7 +968,7 @@ static void batadv_iv_ogm_schedule(struct batadv_hard_iface *hard_iface) rcu_read_lock(); list_for_each_entry_rcu(tmp_hard_iface, &batadv_hardif_list, list) { if (tmp_hard_iface->soft_iface != hard_iface->soft_iface) - continue; + continue; batadv_iv_ogm_queue_add(bat_priv, *ogm_buff, *ogm_buff_len, hard_iface, tmp_hard_iface, 1, send_time); -- GitLab From 854d2a63de86a769db4dbed75b660f544b3c0c7a Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Fri, 17 Jul 2015 22:25:59 +0800 Subject: [PATCH 4737/7006] batman-adv: beautify supported routing algorithm list Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index 50fc07b9d353e..e61c5f3633d0e 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -584,7 +584,7 @@ int batadv_algo_seq_print_text(struct seq_file *seq, void *offset) seq_puts(seq, "Available routing algorithms:\n"); hlist_for_each_entry(bat_algo_ops, &batadv_algo_list, list) { - seq_printf(seq, "%s\n", bat_algo_ops->name); + seq_printf(seq, " * %s\n", bat_algo_ops->name); } return 0; -- GitLab From 13ec7297e5331f2754d7629a068c619c41f20e56 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Mon, 24 Aug 2015 17:40:45 +0800 Subject: [PATCH 4738/7006] f2fs: fix to release inode correctly In following call stack, if unfortunately we lose all chances to truncate inode page in remove_inode_page, eventually we will add the nid allocated previously into free nid cache, this nid is with NID_NEW status and with NEW_ADDR in its blkaddr pointer: - f2fs_create - f2fs_add_link - __f2fs_add_link - init_inode_metadata - new_inode_page - new_node_page - set_node_addr(, NEW_ADDR) - f2fs_init_acl failed - remove_inode_page failed - handle_failed_inode - remove_inode_page failed - iput - f2fs_evict_inode - remove_inode_page failed - alloc_nid_failed cache a nid with valid blkaddr: NEW_ADDR This may not only cause resource leak of previous inode, but also may cause incorrect use of the previous blkaddr which is located in NO.nid node entry when this nid is reused by others. This patch tries to add this inode to orphan list if we fail to truncate inode, so that we can obtain a second chance to release it in orphan recovery flow. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/f2fs.h | 2 +- fs/f2fs/inode.c | 53 ++++++++++++++++++++++++++++++++++++++++++------- fs/f2fs/node.c | 14 ++++++++----- 3 files changed, 56 insertions(+), 13 deletions(-) diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 806439f1c886a..69827ee8a0eef 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -1687,7 +1687,7 @@ int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int); int truncate_inode_blocks(struct inode *, pgoff_t); int truncate_xattr_node(struct inode *, struct page *); int wait_on_node_pages_writeback(struct f2fs_sb_info *, nid_t); -void remove_inode_page(struct inode *); +int remove_inode_page(struct inode *); struct page *new_inode_page(struct inode *); struct page *new_node_page(struct dnode_of_data *, unsigned int, struct page *); void ra_node_page(struct f2fs_sb_info *, nid_t); diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c index d1b03d01b7e3d..35aae65b3e5db 100644 --- a/fs/f2fs/inode.c +++ b/fs/f2fs/inode.c @@ -317,6 +317,7 @@ void f2fs_evict_inode(struct inode *inode) struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct f2fs_inode_info *fi = F2FS_I(inode); nid_t xnid = fi->i_xattr_nid; + int err = 0; /* some remained atomic pages should discarded */ if (f2fs_is_atomic_file(inode)) @@ -342,11 +343,13 @@ void f2fs_evict_inode(struct inode *inode) i_size_write(inode, 0); if (F2FS_HAS_BLOCKS(inode)) - f2fs_truncate(inode, true); + err = f2fs_truncate(inode, true); - f2fs_lock_op(sbi); - remove_inode_page(inode); - f2fs_unlock_op(sbi); + if (!err) { + f2fs_lock_op(sbi); + err = remove_inode_page(inode); + f2fs_unlock_op(sbi); + } sb_end_intwrite(inode->i_sb); no_delete: @@ -362,9 +365,26 @@ no_delete: if (is_inode_flag_set(fi, FI_UPDATE_WRITE)) add_dirty_inode(sbi, inode->i_ino, UPDATE_INO); if (is_inode_flag_set(fi, FI_FREE_NID)) { - alloc_nid_failed(sbi, inode->i_ino); + if (err && err != -ENOENT) + alloc_nid_done(sbi, inode->i_ino); + else + alloc_nid_failed(sbi, inode->i_ino); clear_inode_flag(fi, FI_FREE_NID); } + + if (err && err != -ENOENT) { + if (!exist_written_data(sbi, inode->i_ino, ORPHAN_INO)) { + /* + * get here because we failed to release resource + * of inode previously, reminder our user to run fsck + * for fixing. + */ + set_sbi_flag(sbi, SBI_NEED_FSCK); + f2fs_msg(sbi->sb, KERN_WARNING, + "inode (ino:%lu) resource leak, run fsck " + "to fix this issue!", inode->i_ino); + } + } out_clear: #ifdef CONFIG_F2FS_FS_ENCRYPTION if (fi->i_crypt_info) @@ -377,6 +397,7 @@ out_clear: void handle_failed_inode(struct inode *inode) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + int err = 0; clear_nlink(inode); make_bad_inode(inode); @@ -384,9 +405,27 @@ void handle_failed_inode(struct inode *inode) i_size_write(inode, 0); if (F2FS_HAS_BLOCKS(inode)) - f2fs_truncate(inode, false); + err = f2fs_truncate(inode, false); + + if (!err) + err = remove_inode_page(inode); - remove_inode_page(inode); + /* + * if we skip truncate_node in remove_inode_page bacause we failed + * before, it's better to find another way to release resource of + * this inode (e.g. valid block count, node block or nid). Here we + * choose to add this inode to orphan list, so that we can call iput + * for releasing in orphan recovery flow. + * + * Note: we should add inode to orphan list before f2fs_unlock_op() + * so we can prevent losing this orphan when encoutering checkpoint + * and following suddenly power-off. + */ + if (err && err != -ENOENT) { + err = acquire_orphan_inode(sbi); + if (!err) + add_orphan_inode(sbi, inode->i_ino); + } set_inode_flag(F2FS_I(inode), FI_FREE_NID); f2fs_unlock_op(sbi); diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c index 0867325e288fc..27d1a74dd6f34 100644 --- a/fs/f2fs/node.c +++ b/fs/f2fs/node.c @@ -902,17 +902,20 @@ int truncate_xattr_node(struct inode *inode, struct page *page) * Caller should grab and release a rwsem by calling f2fs_lock_op() and * f2fs_unlock_op(). */ -void remove_inode_page(struct inode *inode) +int remove_inode_page(struct inode *inode) { struct dnode_of_data dn; + int err; set_new_dnode(&dn, inode, NULL, NULL, inode->i_ino); - if (get_dnode_of_data(&dn, 0, LOOKUP_NODE)) - return; + err = get_dnode_of_data(&dn, 0, LOOKUP_NODE); + if (err) + return err; - if (truncate_xattr_node(inode, dn.inode_page)) { + err = truncate_xattr_node(inode, dn.inode_page); + if (err) { f2fs_put_dnode(&dn); - return; + return err; } /* remove potential inline_data blocks */ @@ -926,6 +929,7 @@ void remove_inode_page(struct inode *inode) /* will put inode & node pages */ truncate_node(&dn); + return 0; } struct page *new_inode_page(struct inode *inode) -- GitLab From c184f855c483428027d6ec937e4a9d5f15b2cbad Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 25 Aug 2015 10:05:13 +1000 Subject: [PATCH 4739/7006] xfs: Fix uninitialized return value in xfs_alloc_fix_freelist() xfs_alloc_fix_freelist() can sometimes jump to out_agbp_relse without ever setting value of 'error' variable which is then returned. This can happen e.g. when pag->pagf_init is set but AG is for metadata and we want to allocate user data. Fix the problem by initializing 'error' to 0, which is the desired return value when we decide to skip this group. CC: xfs@oss.sgi.com Coverity-id: 1309714 Signed-off-by: Jan Kara Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_alloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_alloc.c b/fs/xfs/libxfs/xfs_alloc.c index b7fc17ce8233a..ffad7f20342f6 100644 --- a/fs/xfs/libxfs/xfs_alloc.c +++ b/fs/xfs/libxfs/xfs_alloc.c @@ -1937,7 +1937,7 @@ xfs_alloc_fix_freelist( struct xfs_alloc_arg targs; /* local allocation arguments */ xfs_agblock_t bno; /* freelist block */ xfs_extlen_t need; /* total blocks needed in freelist */ - int error; + int error = 0; if (!pag->pagf_init) { error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); -- GitLab From b6a9947efdbe0c9135d94b26b2f912f5b0b9dc45 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 25 Aug 2015 10:05:13 +1000 Subject: [PATCH 4740/7006] xfs: lockdep annotations throw warnings on non-debug builds SO, now if we enable lockdep without enabling CONFIG_XFS_DEBUG, the lockdep annotations throw a warning because the assert that uses the lockdep define is not built in: fs/xfs/xfs_inode.c:367:1: warning: 'xfs_lockdep_subclass_ok' defined but not used [-Wunused-function] xfs_lockdep_subclass_ok( So now we need to create an ifdef mess to sort this all out, because we need to handle all the combinations of CONFIG_XFS_DEBUG=[y|n], CONFIG_XFS_WARNING=[y|n] and CONFIG_LOCKDEP=[y|n] appropriately. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_inode.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index aa00ccc0bd785..c59da0e88c5fc 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -362,7 +362,13 @@ int xfs_lots_retries; int xfs_lock_delays; #endif -#ifdef CONFIG_LOCKDEP +/* + * xfs_lockdep_subclass_ok() is only used in an ASSERT, so is only called when + * DEBUG or XFS_WARN is set. And MAX_LOCKDEP_SUBCLASSES is then only defined + * when CONFIG_LOCKDEP is set. Hence the complex define below to avoid build + * errors and warnings. + */ +#if (defined(DEBUG) || defined(XFS_WARN)) && defined(CONFIG_LOCKDEP) static bool xfs_lockdep_subclass_ok( int subclass) -- GitLab From 037542345a82aaaa228ec280fe6ddff1568d169f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Tue, 25 Aug 2015 10:05:13 +1000 Subject: [PATCH 4741/7006] xfs: Fix file type directory corruption for btree directories Users have occasionally reported that file type for some directory entries is wrong. This mostly happened after updating libraries some libraries. After some debugging the problem was traced down to xfs_dir2_node_replace(). The function uses args->filetype as a file type to store in the replaced directory entry however it also calls xfs_da3_node_lookup_int() which will store file type of the current directory entry in args->filetype. Thus we fail to change file type of a directory entry to a proper type. Fix the problem by storing new file type in a local variable before calling xfs_da3_node_lookup_int(). cc: # 3.16 - 4.x Reported-by: Giacomo Comes Signed-off-by: Jan Kara Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_dir2_node.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c index 527b7337a43be..9bd3d698ee774 100644 --- a/fs/xfs/libxfs/xfs_dir2_node.c +++ b/fs/xfs/libxfs/xfs_dir2_node.c @@ -2132,6 +2132,7 @@ xfs_dir2_node_replace( int error; /* error return value */ int i; /* btree level */ xfs_ino_t inum; /* new inode number */ + int ftype; /* new file type */ xfs_dir2_leaf_t *leaf; /* leaf structure */ xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ int rval; /* internal return value */ @@ -2145,7 +2146,14 @@ xfs_dir2_node_replace( state = xfs_da_state_alloc(); state->args = args; state->mp = args->dp->i_mount; + + /* + * We have to save new inode number and ftype since + * xfs_da3_node_lookup_int() is going to overwrite them + */ inum = args->inumber; + ftype = args->filetype; + /* * Lookup the entry to change in the btree. */ @@ -2183,7 +2191,7 @@ xfs_dir2_node_replace( * Fill in the new inode number and log the entry. */ dep->inumber = cpu_to_be64(inum); - args->dp->d_ops->data_put_ftype(dep, args->filetype); + args->dp->d_ops->data_put_ftype(dep, ftype); xfs_dir2_data_log_entry(args, state->extrablk.bp, dep); rval = 0; } -- GitLab From 2ccf4a9b18868b0900072e6d5d15a04254a07345 Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Tue, 25 Aug 2015 10:05:13 +1000 Subject: [PATCH 4742/7006] xfs: collapse allocsize and biosize mount option handling The allocsize and biosize mount options are handled identically, other than allocsize accepting suffixes. suffix_kstrtoint handles bare numbers just fine too, so these can be collapsed. Signed-off-by: Eric Sandeen Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_super.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index f98ce83b7bc4f..3bf503a3f57e0 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -261,16 +261,8 @@ xfs_parseargs( mp->m_rtname = kstrndup(value, MAXNAMELEN, GFP_KERNEL); if (!mp->m_rtname) return -ENOMEM; - } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { - if (!value || !*value) { - xfs_warn(mp, "%s option requires an argument", - this_char); - return -EINVAL; - } - if (kstrtoint(value, 10, &iosize)) - return -EINVAL; - iosizelog = ffs(iosize) - 1; - } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { + } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE) || + !strcmp(this_char, MNTOPT_BIOSIZE)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); -- GitLab From f79af0b9090895520c69fbe1939184c4f8ed8426 Mon Sep 17 00:00:00 2001 From: Dave Chinner Date: Tue, 25 Aug 2015 10:05:13 +1000 Subject: [PATCH 4743/7006] xfs: fix non-debug build warnings There seem to be a couple of new set-but-unused build warnings that gcc 4.9.3 is now warning about. These are not regressions, just the compiler being more picky. Signed-off-by: Dave Chinner Reviewed-by: Brian Foster Signed-off-by: Dave Chinner --- fs/xfs/xfs_buf.c | 4 +--- fs/xfs/xfs_buf_item.c | 20 +++++++++++++------- fs/xfs/xfs_buf_item.h | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/fs/xfs/xfs_buf.c b/fs/xfs/xfs_buf.c index a4b7d92e946c1..fbf4c269a7b77 100644 --- a/fs/xfs/xfs_buf.c +++ b/fs/xfs/xfs_buf.c @@ -438,7 +438,6 @@ _xfs_buf_find( xfs_buf_flags_t flags, xfs_buf_t *new_bp) { - size_t numbytes; struct xfs_perag *pag; struct rb_node **rbp; struct rb_node *parent; @@ -450,10 +449,9 @@ _xfs_buf_find( for (i = 0; i < nmaps; i++) numblks += map[i].bm_len; - numbytes = BBTOB(numblks); /* Check for IOs smaller than the sector size / not sector aligned */ - ASSERT(!(numbytes < btp->bt_meta_sectorsize)); + ASSERT(!(BBTOB(numblks) < btp->bt_meta_sectorsize)); ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_meta_sectormask)); /* diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 092d652bc03df..9cf3a86a22011 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -750,13 +750,13 @@ xfs_buf_item_free_format( * buffer (see xfs_buf_attach_iodone() below), then put the * buf log item at the front. */ -void +int xfs_buf_item_init( - xfs_buf_t *bp, - xfs_mount_t *mp) + struct xfs_buf *bp, + struct xfs_mount *mp) { - xfs_log_item_t *lip = bp->b_fspriv; - xfs_buf_log_item_t *bip; + struct xfs_log_item *lip = bp->b_fspriv; + struct xfs_buf_log_item *bip; int chunks; int map_size; int error; @@ -770,12 +770,11 @@ xfs_buf_item_init( */ ASSERT(bp->b_target->bt_mount == mp); if (lip != NULL && lip->li_type == XFS_LI_BUF) - return; + return 0; bip = kmem_zone_zalloc(xfs_buf_item_zone, KM_SLEEP); xfs_log_item_init(mp, &bip->bli_item, XFS_LI_BUF, &xfs_buf_item_ops); bip->bli_buf = bp; - xfs_buf_hold(bp); /* * chunks is the number of XFS_BLF_CHUNK size pieces the buffer @@ -788,6 +787,11 @@ xfs_buf_item_init( */ error = xfs_buf_item_get_format(bip, bp->b_map_count); ASSERT(error == 0); + if (error) { /* to stop gcc throwing set-but-unused warnings */ + kmem_zone_free(xfs_buf_item_zone, bip); + return error; + } + for (i = 0; i < bip->bli_format_count; i++) { chunks = DIV_ROUND_UP(BBTOB(bp->b_maps[i].bm_len), @@ -807,6 +811,8 @@ xfs_buf_item_init( if (bp->b_fspriv) bip->bli_item.li_bio_list = bp->b_fspriv; bp->b_fspriv = bip; + xfs_buf_hold(bp); + return 0; } diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 3f3455a415102..f7eba99d19dde 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -61,7 +61,7 @@ typedef struct xfs_buf_log_item { struct xfs_buf_log_format __bli_format; /* embedded in-log header */ } xfs_buf_log_item_t; -void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); +int xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); void xfs_buf_item_relse(struct xfs_buf *); void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint); uint xfs_buf_item_dirty(xfs_buf_log_item_t *); -- GitLab From 02b771b64b73226052d6e731a0987db3b47281e9 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 12 Aug 2015 11:12:02 +0800 Subject: [PATCH 4744/7006] ACPI / EC: Fix an issue caused by the serialized _Qxx evaluations It is proven that Windows evaluates _Qxx handlers in a parallel way. This patch follows this fact, splits _Qxx evaluations from the NOTIFY queue to form a separate queue, so that _Qxx evaluations can be queued up on different CPUs rather than being queued up on a CPU0 bound queue. Event handling related callbacks are also renamed and sorted in this patch. Link: https://bugzilla.kernel.org/show_bug.cgi?id=94411 Reported-and-tested-by: Gabriele Mazzotta Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/ec.c | 82 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c index 9d4761d2f6b77..3e57ee7c890f3 100644 --- a/drivers/acpi/ec.c +++ b/drivers/acpi/ec.c @@ -165,8 +165,16 @@ struct transaction { u8 flags; }; +struct acpi_ec_query { + struct transaction transaction; + struct work_struct work; + struct acpi_ec_query_handler *handler; +}; + static int acpi_ec_query(struct acpi_ec *ec, u8 *data); static void advance_transaction(struct acpi_ec *ec); +static void acpi_ec_event_handler(struct work_struct *work); +static void acpi_ec_event_processor(struct work_struct *work); struct acpi_ec *boot_ec, *first_ec; EXPORT_SYMBOL(first_ec); @@ -978,60 +986,90 @@ void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit) } EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler); -static void acpi_ec_run(void *cxt) +static struct acpi_ec_query *acpi_ec_create_query(u8 *pval) { - struct acpi_ec_query_handler *handler = cxt; + struct acpi_ec_query *q; + struct transaction *t; + + q = kzalloc(sizeof (struct acpi_ec_query), GFP_KERNEL); + if (!q) + return NULL; + INIT_WORK(&q->work, acpi_ec_event_processor); + t = &q->transaction; + t->command = ACPI_EC_COMMAND_QUERY; + t->rdata = pval; + t->rlen = 1; + return q; +} + +static void acpi_ec_delete_query(struct acpi_ec_query *q) +{ + if (q) { + if (q->handler) + acpi_ec_put_query_handler(q->handler); + kfree(q); + } +} + +static void acpi_ec_event_processor(struct work_struct *work) +{ + struct acpi_ec_query *q = container_of(work, struct acpi_ec_query, work); + struct acpi_ec_query_handler *handler = q->handler; - if (!handler) - return; ec_dbg_evt("Query(0x%02x) started", handler->query_bit); if (handler->func) handler->func(handler->data); else if (handler->handle) acpi_evaluate_object(handler->handle, NULL, NULL, NULL); ec_dbg_evt("Query(0x%02x) stopped", handler->query_bit); - acpi_ec_put_query_handler(handler); + acpi_ec_delete_query(q); } static int acpi_ec_query(struct acpi_ec *ec, u8 *data) { u8 value = 0; int result; - acpi_status status; struct acpi_ec_query_handler *handler; - struct transaction t = {.command = ACPI_EC_COMMAND_QUERY, - .wdata = NULL, .rdata = &value, - .wlen = 0, .rlen = 1}; + struct acpi_ec_query *q; + + q = acpi_ec_create_query(&value); + if (!q) + return -ENOMEM; /* * Query the EC to find out which _Qxx method we need to evaluate. * Note that successful completion of the query causes the ACPI_EC_SCI * bit to be cleared (and thus clearing the interrupt source). */ - result = acpi_ec_transaction(ec, &t); - if (result) - return result; - if (data) - *data = value; + result = acpi_ec_transaction(ec, &q->transaction); if (!value) - return -ENODATA; + result = -ENODATA; + if (result) + goto err_exit; mutex_lock(&ec->mutex); list_for_each_entry(handler, &ec->list, node) { if (value == handler->query_bit) { - /* have custom handler for this bit */ - handler = acpi_ec_get_query_handler(handler); + q->handler = acpi_ec_get_query_handler(handler); ec_dbg_evt("Query(0x%02x) scheduled", - handler->query_bit); - status = acpi_os_execute((handler->func) ? - OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER, - acpi_ec_run, handler); - if (ACPI_FAILURE(status)) + q->handler->query_bit); + /* + * It is reported that _Qxx are evaluated in a + * parallel way on Windows: + * https://bugzilla.kernel.org/show_bug.cgi?id=94411 + */ + if (!schedule_work(&q->work)) result = -EBUSY; break; } } mutex_unlock(&ec->mutex); + +err_exit: + if (result && q) + acpi_ec_delete_query(q); + if (data) + *data = value; return result; } -- GitLab From 3277b4ea216e5cd7d3f6095ff40f1a9e574f37b3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 17 Aug 2015 17:28:46 +0300 Subject: [PATCH 4745/7006] ACPI / osl: replace custom implementation of readq / writeq The readq() and writeq() helpers are available in the asm-generic/io-64-nonatomic-hi-lo.h and asm-generic/io-64-nonatomic-lo-hi.h headers. Replace custom implementation by the generic helpers. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/osl.c | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 3b8963f21b367..64077e87477a2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -47,6 +47,7 @@ #include #include +#include #include "internal.h" @@ -947,21 +948,6 @@ acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width) EXPORT_SYMBOL(acpi_os_write_port); -#ifdef readq -static inline u64 read64(const volatile void __iomem *addr) -{ - return readq(addr); -} -#else -static inline u64 read64(const volatile void __iomem *addr) -{ - u64 l, h; - l = readl(addr); - h = readl(addr+4); - return l | (h << 32); -} -#endif - acpi_status acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) { @@ -994,7 +980,7 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) *(u32 *) value = readl(virt_addr); break; case 64: - *(u64 *) value = read64(virt_addr); + *(u64 *) value = readq(virt_addr); break; default: BUG(); @@ -1008,19 +994,6 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) return AE_OK; } -#ifdef writeq -static inline void write64(u64 val, volatile void __iomem *addr) -{ - writeq(val, addr); -} -#else -static inline void write64(u64 val, volatile void __iomem *addr) -{ - writel(val, addr); - writel(val>>32, addr+4); -} -#endif - acpi_status acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) { @@ -1049,7 +1022,7 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) writel(value, virt_addr); break; case 64: - write64(value, virt_addr); + writeq(value, virt_addr); break; default: BUG(); -- GitLab From d3c68f218f927bd4b14b586ea2dcecee54cf09ad Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 5 Aug 2015 09:40:24 -0400 Subject: [PATCH 4746/7006] PCC: Initialize PCC Mailbox earlier at boot This change initializes the PCC Mailbox earlier than the ACPI processor driver. This enables drivers introduced in follow up patches (e.g. CPPC) to be probed via the ACPI processor driver interface. The CPPC probe requires the PCC channel to be initialized for it to query each CPUs performance capabilities. Signed-off-by: Ashwin Chaugule Reviewed-by: Al Stone Signed-off-by: Rafael J. Wysocki --- drivers/mailbox/pcc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 26d121d1d501b..68885a82e7046 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -352,4 +352,10 @@ static int __init pcc_init(void) return 0; } -device_initcall(pcc_init); + +/* + * Make PCC init postcore so that users of this mailbox + * such as the ACPI Processor driver have it available + * at their init. + */ +postcore_initcall(pcc_init); -- GitLab From 239708a3af44064366f1af0eea02dc1e8991c11b Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 5 Aug 2015 09:40:25 -0400 Subject: [PATCH 4747/7006] ACPI: Split out ACPI PSS from ACPI Processor driver The ACPI processor driver is currently tied too closely to the ACPI P-states (PSS) and other related constructs for controlling CPU performance. The newer ACPI specification (v5.1 onwards) introduces alternative methods to PSS. These new mechanisms are described within each ACPI Processor object and so they need to be scanned whenever a new Processor object is detected. This patch introduces a new Kconfig symbol to allow for finer configurability among the two options for controlling performance states. There is no change in functionality and the option is auto-selected by the architectures which support it. A future commit will introduce support for CPPC: A newer method of controlling CPU performance. The OS is not expected to support CPPC and PSS at the same time, so the Kconfig option lets us make the two mutually exclusive at compile time. Signed-off-by: Ashwin Chaugule [ rjw: Changelog ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 15 +++--- drivers/acpi/Makefile | 5 +- drivers/acpi/processor_driver.c | 86 ++++++++++++++++++++++----------- include/acpi/processor.h | 28 ++++++++++- 4 files changed, 96 insertions(+), 38 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 114cf48085abd..d6e2a869033c9 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -189,17 +189,20 @@ config ACPI_DOCK This driver supports ACPI-controlled docking stations and removable drive bays such as the IBM Ultrabay and the Dell Module Bay. +config ACPI_CPU_FREQ_PSS + bool + select THERMAL + config ACPI_PROCESSOR tristate "Processor" - select THERMAL - select CPU_IDLE depends on X86 || IA64 + select CPU_IDLE + select ACPI_CPU_FREQ_PSS default y help - This driver installs ACPI as the idle handler for Linux and uses - ACPI C2 and C3 processor states to save power on systems that - support it. It is required by several flavors of cpufreq - performance-state drivers. + This driver adds support for the ACPI Processor package. It is required + by several flavors of cpufreq performance-state, thermal, throttling and + idle drivers. To compile this driver as a module, choose M here: the module will be called processor. diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 8321430d7f24a..7e97aef373ae3 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -80,8 +80,9 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o # processor has its own "processor." module_param namespace -processor-y := processor_driver.o processor_throttling.o -processor-y += processor_idle.o processor_thermal.o +processor-y := processor_driver.o processor_idle.o +processor-$(CONFIG_ACPI_CPU_FREQ_PSS) += processor_throttling.o \ + processor_thermal.o processor-$(CONFIG_CPU_FREQ) += processor_perflib.o obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c index cc820d840c61f..3fea539aa43e6 100644 --- a/drivers/acpi/processor_driver.c +++ b/drivers/acpi/processor_driver.c @@ -163,34 +163,24 @@ static struct notifier_block acpi_cpu_notifier = { .notifier_call = acpi_cpu_soft_notify, }; -static int __acpi_processor_start(struct acpi_device *device) +#ifdef CONFIG_ACPI_CPU_FREQ_PSS +static int acpi_pss_perf_init(struct acpi_processor *pr, + struct acpi_device *device) { - struct acpi_processor *pr = acpi_driver_data(device); - acpi_status status; int result = 0; - if (!pr) - return -ENODEV; - - if (pr->flags.need_hotplug_init) - return 0; - -#ifdef CONFIG_CPU_FREQ acpi_processor_ppc_has_changed(pr, 0); -#endif + acpi_processor_get_throttling_info(pr); if (pr->flags.throttling) pr->flags.limit = 1; - if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) - acpi_processor_power_init(pr); - pr->cdev = thermal_cooling_device_register("Processor", device, &processor_cooling_ops); if (IS_ERR(pr->cdev)) { result = PTR_ERR(pr->cdev); - goto err_power_exit; + return result; } dev_dbg(&device->dev, "registered as cooling_device%d\n", @@ -204,6 +194,7 @@ static int __acpi_processor_start(struct acpi_device *device) "Failed to create sysfs link 'thermal_cooling'\n"); goto err_thermal_unregister; } + result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, "device"); @@ -213,17 +204,61 @@ static int __acpi_processor_start(struct acpi_device *device) goto err_remove_sysfs_thermal; } - status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, - acpi_processor_notify, device); - if (ACPI_SUCCESS(status)) - return 0; - sysfs_remove_link(&pr->cdev->device.kobj, "device"); err_remove_sysfs_thermal: sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); err_thermal_unregister: thermal_cooling_device_unregister(pr->cdev); - err_power_exit: + + return result; +} + +static void acpi_pss_perf_exit(struct acpi_processor *pr, + struct acpi_device *device) +{ + if (pr->cdev) { + sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); + sysfs_remove_link(&pr->cdev->device.kobj, "device"); + thermal_cooling_device_unregister(pr->cdev); + pr->cdev = NULL; + } +} +#else +static inline int acpi_pss_perf_init(struct acpi_processor *pr, + struct acpi_device *device) +{ + return 0; +} + +static inline void acpi_pss_perf_exit(struct acpi_processor *pr, + struct acpi_device *device) {} +#endif /* CONFIG_ACPI_CPU_FREQ_PSS */ + +static int __acpi_processor_start(struct acpi_device *device) +{ + struct acpi_processor *pr = acpi_driver_data(device); + acpi_status status; + int result = 0; + + if (!pr) + return -ENODEV; + + if (pr->flags.need_hotplug_init) + return 0; + + if (!cpuidle_get_driver() || cpuidle_get_driver() == &acpi_idle_driver) + acpi_processor_power_init(pr); + + result = acpi_pss_perf_init(pr, device); + if (result) + goto err_power_exit; + + status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY, + acpi_processor_notify, device); + if (ACPI_SUCCESS(status)) + return 0; + +err_power_exit: acpi_processor_power_exit(pr); return result; } @@ -252,15 +287,10 @@ static int acpi_processor_stop(struct device *dev) pr = acpi_driver_data(device); if (!pr) return 0; - acpi_processor_power_exit(pr); - if (pr->cdev) { - sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); - sysfs_remove_link(&pr->cdev->device.kobj, "device"); - thermal_cooling_device_unregister(pr->cdev); - pr->cdev = NULL; - } + acpi_pss_perf_exit(pr, device); + return 0; } diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 4188a4d3b597c..b6c917835805c 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -318,6 +318,7 @@ int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); void acpi_processor_set_pdc(acpi_handle handle); /* in processor_throttling.c */ +#ifdef CONFIG_ACPI_CPU_FREQ_PSS int acpi_processor_tstate_has_changed(struct acpi_processor *pr); int acpi_processor_get_throttling_info(struct acpi_processor *pr); extern int acpi_processor_set_throttling(struct acpi_processor *pr, @@ -330,6 +331,29 @@ extern void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, unsigned long action); extern const struct file_operations acpi_processor_throttling_fops; extern void acpi_processor_throttling_init(void); +#else +static inline int acpi_processor_tstate_has_changed(struct acpi_processor *pr) +{ + return 0; +} + +static inline int acpi_processor_get_throttling_info(struct acpi_processor *pr) +{ + return -ENODEV; +} + +static inline int acpi_processor_set_throttling(struct acpi_processor *pr, + int state, bool force) +{ + return -ENODEV; +} + +static inline void acpi_processor_reevaluate_tstate(struct acpi_processor *pr, + unsigned long action) {} + +static inline void acpi_processor_throttling_init(void) {} +#endif /* CONFIG_ACPI_CPU_FREQ_PSS */ + /* in processor_idle.c */ int acpi_processor_power_init(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr); @@ -348,7 +372,7 @@ static inline void acpi_processor_syscore_exit(void) {} /* in processor_thermal.c */ int acpi_processor_get_limit_info(struct acpi_processor *pr); extern const struct thermal_cooling_device_ops processor_cooling_ops; -#ifdef CONFIG_CPU_FREQ +#if defined(CONFIG_ACPI_CPU_FREQ_PSS) & defined(CONFIG_CPU_FREQ) void acpi_thermal_cpufreq_init(void); void acpi_thermal_cpufreq_exit(void); #else @@ -360,6 +384,6 @@ static inline void acpi_thermal_cpufreq_exit(void) { return; } -#endif +#endif /* CONFIG_ACPI_CPU_FREQ_PSS */ #endif -- GitLab From 5f05586c609dfc737e2e00c757a51c7dbb415e51 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 5 Aug 2015 09:40:26 -0400 Subject: [PATCH 4748/7006] ACPI: Decouple ACPI idle and ACPI processor drivers This patch introduces a new Kconfig symbol, ACPI_PROCESSOR_IDLE, which is auto selected by architectures which support the ACPI based C states for CPU Idle management. The processor_idle driver in its present form contains declarations specific to X86 and IA64. Since there are no reasonable defaults for other architectures e.g. ARM64, the driver is selected only for X86 or IA64. This helps in decoupling the ACPI processor_driver from the ACPI processor_idle driver which is useful for the upcoming alternative patchwork for controlling CPU Performance (CPPC) and CPU Idle (LPI). Signed-off-by: Ashwin Chaugule Signed-off-by: Rafael J. Wysocki --- drivers/acpi/Kconfig | 6 +++++- drivers/acpi/Makefile | 3 ++- include/acpi/processor.h | 26 ++++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index d6e2a869033c9..54e9729f9634d 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -193,10 +193,14 @@ config ACPI_CPU_FREQ_PSS bool select THERMAL +config ACPI_PROCESSOR_IDLE + bool + select CPU_IDLE + config ACPI_PROCESSOR tristate "Processor" depends on X86 || IA64 - select CPU_IDLE + select ACPI_PROCESSOR_IDLE select ACPI_CPU_FREQ_PSS default y help diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile index 7e97aef373ae3..3ea59ae85c19b 100644 --- a/drivers/acpi/Makefile +++ b/drivers/acpi/Makefile @@ -80,7 +80,8 @@ obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o obj-$(CONFIG_ACPI_BGRT) += bgrt.o # processor has its own "processor." module_param namespace -processor-y := processor_driver.o processor_idle.o +processor-y := processor_driver.o +processor-$(CONFIG_ACPI_PROCESSOR_IDLE) += processor_idle.o processor-$(CONFIG_ACPI_CPU_FREQ_PSS) += processor_throttling.o \ processor_thermal.o processor-$(CONFIG_CPU_FREQ) += processor_perflib.o diff --git a/include/acpi/processor.h b/include/acpi/processor.h index b6c917835805c..2c4e7a9c1725a 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -355,13 +355,35 @@ static inline void acpi_processor_throttling_init(void) {} #endif /* CONFIG_ACPI_CPU_FREQ_PSS */ /* in processor_idle.c */ +extern struct cpuidle_driver acpi_idle_driver; +#ifdef CONFIG_ACPI_PROCESSOR_IDLE int acpi_processor_power_init(struct acpi_processor *pr); int acpi_processor_power_exit(struct acpi_processor *pr); int acpi_processor_cst_has_changed(struct acpi_processor *pr); int acpi_processor_hotplug(struct acpi_processor *pr); -extern struct cpuidle_driver acpi_idle_driver; +#else +static inline int acpi_processor_power_init(struct acpi_processor *pr) +{ + return -ENODEV; +} + +static inline int acpi_processor_power_exit(struct acpi_processor *pr) +{ + return -ENODEV; +} + +static inline int acpi_processor_cst_has_changed(struct acpi_processor *pr) +{ + return -ENODEV; +} + +static inline int acpi_processor_hotplug(struct acpi_processor *pr) +{ + return -ENODEV; +} +#endif /* CONFIG_ACPI_PROCESSOR_IDLE */ -#ifdef CONFIG_PM_SLEEP +#if defined(CONFIG_PM_SLEEP) & defined(CONFIG_ACPI_PROCESSOR_IDLE) void acpi_processor_syscore_init(void); void acpi_processor_syscore_exit(void); #else -- GitLab From 9dcc144b1f91c4fe33422518e401e9c624e2c64f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2015 08:52:55 +0200 Subject: [PATCH 4749/7006] ALSA: hda - Refresh sysfs at snd_hda_codec_update_widgets() In the commit [fa4f18b4f402: ALSA: hda - Refresh widgets sysfs at probing Haswell+ HDMI codecs], snd_hdac_refresh_widget_sysfs() is explicitly called in the codec driver. But this results in refreshing twice, as snd_hdac_refresh_widget_sysfs() itself calls snd_hdac_refresh_widgets() function. Instead, we can replace the call in snd_hda_codec_update_widgets() with snd_hdac_refresh_widget_sysfs(). This also fixes the missing sysfs update for ca0132, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/patch_hdmi.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 792948418cf07..2c021911f88a9 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -955,7 +955,7 @@ int snd_hda_codec_update_widgets(struct hda_codec *codec) hda_nid_t fg; int err; - err = snd_hdac_refresh_widgets(&codec->core); + err = snd_hdac_refresh_widget_sysfs(&codec->core); if (err < 0) return err; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index df982fc6a872e..a97db5fc8a151 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2331,7 +2331,6 @@ static int patch_generic_hdmi(struct hda_codec *codec) if (is_haswell_plus(codec)) { intel_haswell_enable_all_pins(codec, true); intel_haswell_fixup_enable_dp12(codec); - snd_hdac_refresh_widget_sysfs(&codec->core); } /* For Valleyview/Cherryview, only the display codec is in the display -- GitLab From f755d114cba98708932cba89d8c98c4ab89a83b0 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 23 Aug 2015 00:30:19 +0800 Subject: [PATCH 4750/7006] ASoC: cs4349: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/cs4349.c:389:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Tim Howe Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/cs4349.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/cs4349.c b/sound/soc/codecs/cs4349.c index 0d010c2b60212..0ac8fc5ed4ae4 100644 --- a/sound/soc/codecs/cs4349.c +++ b/sound/soc/codecs/cs4349.c @@ -378,7 +378,6 @@ MODULE_DEVICE_TABLE(i2c, cs4349_i2c_id); static struct i2c_driver cs4349_i2c_driver = { .driver = { .name = "cs4349", - .owner = THIS_MODULE, .of_match_table = cs4349_of_match, }, .id_table = cs4349_i2c_id, -- GitLab From db56176025cee5e242dfeed5f4e304d095d29fa3 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Tue, 25 Aug 2015 17:23:36 +1000 Subject: [PATCH 4751/7006] Revert "drm/atomic: Call ww_acquire_done after check phase is complete" This reverts commit 992cbf19b32900efa17850b9fa0031fd623edd4d. Until we make fbdev layer atomic we can't call this. Requested-by: Maarten Lankhorst Signed-off-by: Dave Airlie --- drivers/gpu/drm/drm_atomic.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 1066e4b658cf9..434915448ea0b 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1230,9 +1230,6 @@ int drm_atomic_check_only(struct drm_atomic_state *state) } } - if (ret == 0) - ww_acquire_done(&state->acquire_ctx->ww_ctx); - return ret; } EXPORT_SYMBOL(drm_atomic_check_only); -- GitLab From fe009175ae3ec3724c1414440e22a1d32d806ec5 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Mon, 20 Jul 2015 15:45:38 +0900 Subject: [PATCH 4752/7006] backlight: lp855x: Use private data for regulator control LP855x backlight device can be enabled by external VDD input. The 'supply' data is used for this purpose. It's kind of private data which runs internally, so there is no reason to expose to the platform data. And devm_regulator_get() is moved from _parse_dt() to _probe(). Regulator consumer(lp855x) can control regulator not only from DT but also from platform data configuration in a source file such like board-*.c. Signed-off-by: Milo Kim Acked-by: Sean Paul Acked-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/lp855x_bl.c | 23 ++++++++++++----------- include/linux/platform_data/lp855x.h | 2 -- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c index 88116b493f3ba..f88df9ec08d04 100644 --- a/drivers/video/backlight/lp855x_bl.c +++ b/drivers/video/backlight/lp855x_bl.c @@ -73,6 +73,7 @@ struct lp855x { struct device *dev; struct lp855x_platform_data *pdata; struct pwm_device *pwm; + struct regulator *supply; /* regulator for VDD input */ }; static int lp855x_write_byte(struct lp855x *lp, u8 reg, u8 data) @@ -378,13 +379,6 @@ static int lp855x_parse_dt(struct lp855x *lp) pdata->rom_data = &rom[0]; } - pdata->supply = devm_regulator_get(dev, "power"); - if (IS_ERR(pdata->supply)) { - if (PTR_ERR(pdata->supply) == -EPROBE_DEFER) - return -EPROBE_DEFER; - pdata->supply = NULL; - } - lp->pdata = pdata; return 0; @@ -425,8 +419,15 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id) else lp->mode = REGISTER_BASED; - if (lp->pdata->supply) { - ret = regulator_enable(lp->pdata->supply); + lp->supply = devm_regulator_get(lp->dev, "power"); + if (IS_ERR(lp->supply)) { + if (PTR_ERR(lp->supply) == -EPROBE_DEFER) + return -EPROBE_DEFER; + lp->supply = NULL; + } + + if (lp->supply) { + ret = regulator_enable(lp->supply); if (ret < 0) { dev_err(&cl->dev, "failed to enable supply: %d\n", ret); return ret; @@ -464,8 +465,8 @@ static int lp855x_remove(struct i2c_client *cl) lp->bl->props.brightness = 0; backlight_update_status(lp->bl); - if (lp->pdata->supply) - regulator_disable(lp->pdata->supply); + if (lp->supply) + regulator_disable(lp->supply); sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group); return 0; diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h index 9c7fd1efe4952..1b2ba24e4e03b 100644 --- a/include/linux/platform_data/lp855x.h +++ b/include/linux/platform_data/lp855x.h @@ -136,7 +136,6 @@ struct lp855x_rom_data { Only valid when mode is PWM_BASED. * @size_program : total size of lp855x_rom_data * @rom_data : list of new eeprom/eprom registers - * @supply : regulator that supplies 3V input */ struct lp855x_platform_data { const char *name; @@ -145,7 +144,6 @@ struct lp855x_platform_data { unsigned int period_ns; int size_program; struct lp855x_rom_data *rom_data; - struct regulator *supply; }; #endif -- GitLab From 7ddbc2423c3301280b883bbb04b998203f30312c Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 21 Jul 2015 17:44:49 -0700 Subject: [PATCH 4753/7006] backlight: pm8941-wled: Move PM8941 WLED driver to backlight The Qualcomm PM8941 WLED block is used for backlight and should therefor be in the backlight framework and not in the LED framework. This moves the driver and adapts to the backlight api instead. Signed-off-by: Bjorn Andersson Tested-by: Rob Clark Acked-by: Jacek Anaszewski Acked-by: Jingoo Han Signed-off-by: Lee Jones --- .../backlight/pm8941-wled.txt} | 5 +- drivers/leds/Kconfig | 8 --- drivers/leds/Makefile | 1 - drivers/video/backlight/Kconfig | 7 +++ drivers/video/backlight/Makefile | 1 + .../backlight/pm8941-wled.c} | 60 ++++++++----------- 6 files changed, 35 insertions(+), 47 deletions(-) rename Documentation/devicetree/bindings/{leds/leds-pm8941-wled.txt => video/backlight/pm8941-wled.txt} (84%) rename drivers/{leds/leds-pm8941-wled.c => video/backlight/pm8941-wled.c} (90%) diff --git a/Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt b/Documentation/devicetree/bindings/video/backlight/pm8941-wled.txt similarity index 84% rename from Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt rename to Documentation/devicetree/bindings/video/backlight/pm8941-wled.txt index a85a964d61f5a..424f8444a6cd9 100644 --- a/Documentation/devicetree/bindings/leds/leds-pm8941-wled.txt +++ b/Documentation/devicetree/bindings/video/backlight/pm8941-wled.txt @@ -5,10 +5,7 @@ Required properties: - reg: slave address Optional properties: -- label: The label for this led - See Documentation/devicetree/bindings/leds/common.txt -- linux,default-trigger: Default trigger assigned to the LED - See Documentation/devicetree/bindings/leds/common.txt +- label: The name of the backlight device - qcom,cs-out: bool; enable current sink output - qcom,cabc: bool; enable content adaptive backlight control - qcom,ext-gen: bool; use externally generated modulator signal to dim diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9ad35f72ab4c0..b8d4b965ca2a3 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -578,14 +578,6 @@ config LEDS_VERSATILE This option enabled support for the LEDs on the ARM Versatile and RealView boards. Say Y to enabled these. -config LEDS_PM8941_WLED - tristate "LED support for the Qualcomm PM8941 WLED block" - depends on LEDS_CLASS - select REGMAP - help - This option enables support for the 'White' LED block - on Qualcomm PM8941 PMICs. - comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 8d6a24a2f5137..abe96d960ebed 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -63,7 +63,6 @@ obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o obj-$(CONFIG_LEDS_VERSATILE) += leds-versatile.o obj-$(CONFIG_LEDS_MENF21BMC) += leds-menf21bmc.o -obj-$(CONFIG_LEDS_PM8941_WLED) += leds-pm8941-wled.o obj-$(CONFIG_LEDS_KTD2692) += leds-ktd2692.o # LED SPI Drivers diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 0505b796d7432..5ffa4b4e26c0e 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -299,6 +299,13 @@ config BACKLIGHT_TOSA If you have an Sharp SL-6000 Zaurus say Y to enable a driver for its backlight +config BACKLIGHT_PM8941_WLED + tristate "Qualcomm PM8941 WLED Driver" + select REGMAP + help + If you have the Qualcomm PM8941, say Y to enable a driver for the + WLED block. + config BACKLIGHT_SAHARA tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" depends on X86 diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index d67073f9d421f..16ec534cff304 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o +obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o diff --git a/drivers/leds/leds-pm8941-wled.c b/drivers/video/backlight/pm8941-wled.c similarity index 90% rename from drivers/leds/leds-pm8941-wled.c rename to drivers/video/backlight/pm8941-wled.c index bf64a593fbf17..c704c3236034f 100644 --- a/drivers/leds/leds-pm8941-wled.c +++ b/drivers/video/backlight/pm8941-wled.c @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include @@ -76,30 +76,29 @@ struct pm8941_wled_config { }; struct pm8941_wled { + const char *name; struct regmap *regmap; u16 addr; - struct led_classdev cdev; - struct pm8941_wled_config cfg; }; -static int pm8941_wled_set(struct led_classdev *cdev, - enum led_brightness value) +static int pm8941_wled_update_status(struct backlight_device *bl) { - struct pm8941_wled *wled; + struct pm8941_wled *wled = bl_get_data(bl); + u16 val = bl->props.brightness; u8 ctrl = 0; - u16 val; int rc; int i; - wled = container_of(cdev, struct pm8941_wled, cdev); + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & BL_CORE_FBBLANK) + val = 0; - if (value != 0) + if (val != 0) ctrl = PM8941_WLED_REG_MOD_EN_BIT; - val = value * PM8941_WLED_REG_VAL_MAX / LED_FULL; - rc = regmap_update_bits(wled->regmap, wled->addr + PM8941_WLED_REG_MOD_EN, PM8941_WLED_REG_MOD_EN_MASK, ctrl); @@ -128,16 +127,6 @@ static int pm8941_wled_set(struct led_classdev *cdev, return rc; } -static void pm8941_wled_set_brightness(struct led_classdev *cdev, - enum led_brightness value) -{ - if (pm8941_wled_set(cdev, value)) { - dev_err(cdev->dev, "Unable to set brightness\n"); - return; - } - cdev->brightness = value; -} - static int pm8941_wled_setup(struct pm8941_wled *wled) { int rc; @@ -336,12 +325,9 @@ static int pm8941_wled_configure(struct pm8941_wled *wled, struct device *dev) } wled->addr = val; - rc = of_property_read_string(dev->of_node, "label", &wled->cdev.name); + rc = of_property_read_string(dev->of_node, "label", &wled->name); if (rc) - wled->cdev.name = dev->of_node->name; - - wled->cdev.default_trigger = of_get_property(dev->of_node, - "linux,default-trigger", NULL); + wled->name = dev->of_node->name; *cfg = pm8941_wled_config_defaults; for (i = 0; i < ARRAY_SIZE(u32_opts); ++i) { @@ -377,8 +363,14 @@ static int pm8941_wled_configure(struct pm8941_wled *wled, struct device *dev) return 0; } +static const struct backlight_ops pm8941_wled_ops = { + .update_status = pm8941_wled_update_status, +}; + static int pm8941_wled_probe(struct platform_device *pdev) { + struct backlight_properties props; + struct backlight_device *bl; struct pm8941_wled *wled; struct regmap *regmap; int rc; @@ -403,13 +395,14 @@ static int pm8941_wled_probe(struct platform_device *pdev) if (rc) return rc; - wled->cdev.brightness_set = pm8941_wled_set_brightness; - - rc = devm_led_classdev_register(&pdev->dev, &wled->cdev); - if (rc) - return rc; - - platform_set_drvdata(pdev, wled); + memset(&props, 0, sizeof(struct backlight_properties)); + props.type = BACKLIGHT_RAW; + props.max_brightness = PM8941_WLED_REG_VAL_MAX; + bl = devm_backlight_device_register(&pdev->dev, wled->name, + &pdev->dev, wled, + &pm8941_wled_ops, &props); + if (IS_ERR(bl)) + return PTR_ERR(bl); return 0; }; @@ -432,4 +425,3 @@ module_platform_driver(pm8941_wled_driver); MODULE_DESCRIPTION("pm8941 wled driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:pm8941-wled"); -- GitLab From 047ffbb27115b57759767145803b752518399d90 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 17 Aug 2015 15:59:17 +0800 Subject: [PATCH 4754/7006] backlight: sky81452: Remove unneeded use of IS_ERR_VALUE() macro IS_ERR_VALUE() makes sense only *if* there could be valid values in negative error range. Signed-off-by: Axel Lin Signed-off-by: Lee Jones --- drivers/video/backlight/sky81452-backlight.c | 26 ++++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/video/backlight/sky81452-backlight.c b/drivers/video/backlight/sky81452-backlight.c index 052fa1bac03de..d414c7a3acf5a 100644 --- a/drivers/video/backlight/sky81452-backlight.c +++ b/drivers/video/backlight/sky81452-backlight.c @@ -65,7 +65,7 @@ static int sky81452_bl_update_status(struct backlight_device *bd) if (brightness > 0) { ret = regmap_write(regmap, SKY81452_REG0, brightness - 1); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; return regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN, @@ -87,12 +87,12 @@ static ssize_t sky81452_bl_store_enable(struct device *dev, int ret; ret = kstrtoul(buf, 16, &value); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; ret = regmap_update_bits(regmap, SKY81452_REG1, SKY81452_EN, value << CTZ(SKY81452_EN)); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; return count; @@ -108,7 +108,7 @@ static ssize_t sky81452_bl_show_open_short(struct device *dev, reg = !strcmp(attr->attr.name, "open") ? SKY81452_REG5 : SKY81452_REG4; ret = regmap_read(regmap, reg, &value); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; if (value & SKY81452_SHRT) { @@ -136,7 +136,7 @@ static ssize_t sky81452_bl_show_fault(struct device *dev, int ret; ret = regmap_read(regmap, SKY81452_REG4, &value); - if (IS_ERR_VALUE(ret)) + if (ret < 0) return ret; *buf = 0; @@ -196,7 +196,7 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( pdata->gpio_enable = of_get_gpio(np, 0); ret = of_property_count_u32_elems(np, "led-sources"); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { pdata->enable = SKY81452_EN >> CTZ(SKY81452_EN); } else { num_entry = ret; @@ -205,7 +205,7 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( ret = of_property_read_u32_array(np, "led-sources", sources, num_entry); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { dev_err(dev, "led-sources node is invalid.\n"); return ERR_PTR(-EINVAL); } @@ -218,12 +218,12 @@ static struct sky81452_bl_platform_data *sky81452_bl_parse_dt( ret = of_property_read_u32(np, "skyworks,short-detection-threshold-volt", &pdata->short_detection_threshold); - if (IS_ERR_VALUE(ret)) + if (ret < 0) pdata->short_detection_threshold = 7; ret = of_property_read_u32(np, "skyworks,current-limit-mA", &pdata->boost_current_limit); - if (IS_ERR_VALUE(ret)) + if (ret < 0) pdata->boost_current_limit = 2750; of_node_put(np); @@ -278,14 +278,14 @@ static int sky81452_bl_probe(struct platform_device *pdev) if (gpio_is_valid(pdata->gpio_enable)) { ret = devm_gpio_request_one(dev, pdata->gpio_enable, GPIOF_OUT_INIT_HIGH, "sky81452-en"); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { dev_err(dev, "failed to request GPIO. err=%d\n", ret); return ret; } } ret = sky81452_bl_init_device(regmap, pdata); - if (IS_ERR_VALUE(ret)) { + if (ret < 0) { dev_err(dev, "failed to initialize. err=%d\n", ret); return ret; } @@ -302,8 +302,8 @@ static int sky81452_bl_probe(struct platform_device *pdev) platform_set_drvdata(pdev, bd); - ret = sysfs_create_group(&bd->dev.kobj, &sky81452_bl_attr_group); - if (IS_ERR_VALUE(ret)) { + ret = sysfs_create_group(&bd->dev.kobj, &sky81452_bl_attr_group); + if (ret < 0) { dev_err(dev, "failed to create attribute. err=%d\n", ret); return ret; } -- GitLab From 85463d8ed1ffae0eb0bd070e400f33918a6696ef Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 1 Jul 2015 12:08:31 +0200 Subject: [PATCH 4755/7006] backlight: lp8788_bl: Delete a check before backlight_device_unregister() The backlight_device_unregister() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Acked-by: Jingoo Han Signed-off-by: Lee Jones --- drivers/video/backlight/lp8788_bl.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/video/backlight/lp8788_bl.c b/drivers/video/backlight/lp8788_bl.c index e418d5b1aa55a..5d583d7a517bc 100644 --- a/drivers/video/backlight/lp8788_bl.c +++ b/drivers/video/backlight/lp8788_bl.c @@ -221,8 +221,7 @@ static void lp8788_backlight_unregister(struct lp8788_bl *bl) { struct backlight_device *bl_dev = bl->bl_dev; - if (bl_dev) - backlight_device_unregister(bl_dev); + backlight_device_unregister(bl_dev); } static ssize_t lp8788_get_bl_ctl_mode(struct device *dev, -- GitLab From 13d20b3b618adc43168b034792eec57063b5ec6f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 25 Aug 2015 08:31:12 +0200 Subject: [PATCH 4756/7006] backlight: tosa: Export I2C module alias information The I2C core always reports the MODALIAS uevent as "i2c:" regardless of the mechanism that was used to register the device (i.e: OF or board code) and the table that is used later to match the driver with the device (i.e: I2C id table or OF match table). So drivers needs to export the I2C id table and this be built into the module or udev won't have the necessary information to autoload the needed driver module when the device is added. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/video/backlight/tosa_bl.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c index 3ad676558c803..83742d8063918 100644 --- a/drivers/video/backlight/tosa_bl.c +++ b/drivers/video/backlight/tosa_bl.c @@ -158,6 +158,7 @@ static const struct i2c_device_id tosa_bl_id[] = { { "tosa-bl", 0 }, { }, }; +MODULE_DEVICE_TABLE(i2c, tosa_bl_id); static struct i2c_driver tosa_bl_driver = { .driver = { -- GitLab From ca30475698696af3a03f6eaee16472ae09d42269 Mon Sep 17 00:00:00 2001 From: "Xiao, Nan" Date: Mon, 24 Aug 2015 06:22:42 +0000 Subject: [PATCH 4757/7006] x86/vt-d: Fix documentation of DRHD According to "Intel Virtualization Technology for Directed I/O" specification, DRHD stands for "DMA Remapping Hardware Unit Definition" , not "DMA Engine Reporting Structure". Signed-off-by: Nan Xiao Signed-off-by: Joerg Roedel --- Documentation/Intel-IOMMU.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Intel-IOMMU.txt b/Documentation/Intel-IOMMU.txt index cf9431db87315..7b57fc087088f 100644 --- a/Documentation/Intel-IOMMU.txt +++ b/Documentation/Intel-IOMMU.txt @@ -10,7 +10,7 @@ This guide gives a quick cheat sheet for some basic understanding. Some Keywords DMAR - DMA remapping -DRHD - DMA Engine Reporting Structure +DRHD - DMA Remapping Hardware Unit Definition RMRR - Reserved memory Region Reporting Structure ZLR - Zero length reads from PCI devices IOVA - IO Virtual address. -- GitLab From 508a43fdd73072c959f849b4e9eb60a9b523396f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:47:36 +0800 Subject: [PATCH 4758/7006] ASoC: davinci: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/davinci/davinci-i2s.c | 25 ++++++------------------- sound/soc/davinci/davinci-mcasp.c | 18 ++++-------------- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/sound/soc/davinci/davinci-i2s.c b/sound/soc/davinci/davinci-i2s.c index 56cb4d95637dd..ec98548a5fc92 100644 --- a/sound/soc/davinci/davinci-i2s.c +++ b/sound/soc/davinci/davinci-i2s.c @@ -651,23 +651,15 @@ static const struct snd_soc_component_driver davinci_i2s_component = { static int davinci_i2s_probe(struct platform_device *pdev) { struct davinci_mcbsp_dev *dev; - struct resource *mem, *ioarea, *res; + struct resource *mem, *res; + void __iomem *io_base; int *dma; int ret; mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - - ioarea = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), - pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "McBSP region already claimed\n"); - return -EBUSY; - } + io_base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_mcbsp_dev), GFP_KERNEL); @@ -679,12 +671,7 @@ static int davinci_i2s_probe(struct platform_device *pdev) return -ENODEV; clk_enable(dev->clk); - dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!dev->base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err_release_clk; - } + dev->base = io_base; dev->dma_data[SNDRV_PCM_STREAM_PLAYBACK].addr = (dma_addr_t)(mem->start + DAVINCI_MCBSP_DXR_REG); diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c index b960e626dad90..add6bb99661da 100644 --- a/sound/soc/davinci/davinci-mcasp.c +++ b/sound/soc/davinci/davinci-mcasp.c @@ -1613,7 +1613,7 @@ static int davinci_mcasp_get_dma_type(struct davinci_mcasp *mcasp) static int davinci_mcasp_probe(struct platform_device *pdev) { struct snd_dmaengine_dai_dma_data *dma_data; - struct resource *mem, *ioarea, *res, *dat; + struct resource *mem, *res, *dat; struct davinci_mcasp_pdata *pdata; struct davinci_mcasp *mcasp; char *irq_name; @@ -1648,22 +1648,12 @@ static int davinci_mcasp_probe(struct platform_device *pdev) } } - ioarea = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), pdev->name); - if (!ioarea) { - dev_err(&pdev->dev, "Audio region already claimed\n"); - return -EBUSY; - } + mcasp->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(mcasp->base)) + return PTR_ERR(mcasp->base); pm_runtime_enable(&pdev->dev); - mcasp->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!mcasp->base) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; - goto err; - } - mcasp->op_mode = pdata->op_mode; /* sanity check for tdm slots parameter */ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) { -- GitLab From 5aec892a6ebe5a3e2a006d969b5fab59e6c79f63 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:49:05 +0800 Subject: [PATCH 4759/7006] ASoC: omap-mcbsp: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Acked-by: Peter Ujfalusi Signed-off-by: Mark Brown --- sound/soc/omap/mcbsp.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c index 68a1252053750..c7563e230c7dd 100644 --- a/sound/soc/omap/mcbsp.c +++ b/sound/soc/omap/mcbsp.c @@ -965,25 +965,15 @@ int omap_mcbsp_init(struct platform_device *pdev) mcbsp->free = true; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mpu"); - if (!res) { + if (!res) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(mcbsp->dev, "invalid memory resource\n"); - return -ENOMEM; - } - } - if (!devm_request_mem_region(&pdev->dev, res->start, resource_size(res), - dev_name(&pdev->dev))) { - dev_err(mcbsp->dev, "memory region already claimed\n"); - return -ENODEV; - } + + mcbsp->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(mcbsp->io_base)) + return PTR_ERR(mcbsp->io_base); mcbsp->phys_base = res->start; mcbsp->reg_cache_size = resource_size(res); - mcbsp->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!mcbsp->io_base) - return -ENOMEM; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dma"); if (!res) -- GitLab From 552ef80389ec2567566be1ccc0dd79f08ba32cce Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 24 Aug 2015 16:52:30 +0800 Subject: [PATCH 4760/7006] ASoC: SPEAr: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/spear/spdif_in.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/sound/soc/spear/spdif_in.c b/sound/soc/spear/spdif_in.c index a4028601da01c..977a078eb92f2 100644 --- a/sound/soc/spear/spdif_in.c +++ b/sound/soc/spear/spdif_in.c @@ -203,35 +203,25 @@ static int spdif_in_probe(struct platform_device *pdev) struct spdif_in_dev *host; struct spear_spdif_platform_data *pdata; struct resource *res, *res_fifo; + void __iomem *io_base; int ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -EINVAL; + io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(io_base)) + return PTR_ERR(io_base); res_fifo = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res_fifo) return -EINVAL; - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name)) { - dev_warn(&pdev->dev, "Failed to get memory resourse\n"); - return -ENOENT; - } - host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); if (!host) { dev_warn(&pdev->dev, "kzalloc fail\n"); return -ENOMEM; } - host->io_base = devm_ioremap(&pdev->dev, res->start, - resource_size(res)); - if (!host->io_base) { - dev_warn(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - + host->io_base = io_base; host->irq = platform_get_irq(pdev, 0); if (host->irq < 0) return -EINVAL; -- GitLab From b64d1f66517a89b9b0f6bd0bca86b05a55a5e742 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 18 Aug 2015 23:06:25 +0100 Subject: [PATCH 4761/7006] ARM: uaccess: simplify user access assembly The user assembly for byte and word accesses was virtually identical. Rather than duplicating this, use a macro instead. Acked-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/uaccess.h | 47 +++++++++------------------------- 1 file changed, 12 insertions(+), 35 deletions(-) diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 74b17d09ef7aa..4cf54ebe408af 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -311,9 +311,9 @@ do { \ (x) = (__typeof__(*(ptr)))__gu_val; \ } while (0) -#define __get_user_asm_byte(x, addr, err) \ +#define __get_user_asm(x, addr, err, instr) \ __asm__ __volatile__( \ - "1: " TUSER(ldrb) " %1,[%2],#0\n" \ + "1: " TUSER(instr) " %1, [%2], #0\n" \ "2:\n" \ " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ @@ -329,6 +329,9 @@ do { \ : "r" (addr), "i" (-EFAULT) \ : "cc") +#define __get_user_asm_byte(x, addr, err) \ + __get_user_asm(x, addr, err, ldrb) + #ifndef __ARMEB__ #define __get_user_asm_half(x, __gu_addr, err) \ ({ \ @@ -348,22 +351,7 @@ do { \ #endif #define __get_user_asm_word(x, addr, err) \ - __asm__ __volatile__( \ - "1: " TUSER(ldr) " %1,[%2],#0\n" \ - "2:\n" \ - " .pushsection .text.fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, %3\n" \ - " mov %1, #0\n" \ - " b 2b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .popsection" \ - : "+r" (err), "=&r" (x) \ - : "r" (addr), "i" (-EFAULT) \ - : "cc") + __get_user_asm(x, addr, err, ldr) #define __put_user(x, ptr) \ ({ \ @@ -393,9 +381,9 @@ do { \ } \ } while (0) -#define __put_user_asm_byte(x, __pu_addr, err) \ +#define __put_user_asm(x, __pu_addr, err, instr) \ __asm__ __volatile__( \ - "1: " TUSER(strb) " %1,[%2],#0\n" \ + "1: " TUSER(instr) " %1, [%2], #0\n" \ "2:\n" \ " .pushsection .text.fixup,\"ax\"\n" \ " .align 2\n" \ @@ -410,6 +398,9 @@ do { \ : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ : "cc") +#define __put_user_asm_byte(x, __pu_addr, err) \ + __put_user_asm(x, __pu_addr, err, strb) + #ifndef __ARMEB__ #define __put_user_asm_half(x, __pu_addr, err) \ ({ \ @@ -427,21 +418,7 @@ do { \ #endif #define __put_user_asm_word(x, __pu_addr, err) \ - __asm__ __volatile__( \ - "1: " TUSER(str) " %1,[%2],#0\n" \ - "2:\n" \ - " .pushsection .text.fixup,\"ax\"\n" \ - " .align 2\n" \ - "3: mov %0, %3\n" \ - " b 2b\n" \ - " .popsection\n" \ - " .pushsection __ex_table,\"a\"\n" \ - " .align 3\n" \ - " .long 1b, 3b\n" \ - " .popsection" \ - : "+r" (err) \ - : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ - : "cc") + __put_user_asm(x, __pu_addr, err, str) #ifndef __ARMEB__ #define __reg_oper0 "%R2" -- GitLab From 01e09a28167c338684606b70797422da3bbb6650 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 20 Aug 2015 14:22:48 +0100 Subject: [PATCH 4762/7006] ARM: entry: get rid of asm_trace_hardirqs_on_cond There's no need for this macro, it can use a default for the condition argument. Acked-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/assembler.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 4abe57279c66f..742495eb55262 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -116,7 +116,7 @@ #endif .endm - .macro asm_trace_hardirqs_on_cond, cond + .macro asm_trace_hardirqs_on, cond=al #if defined(CONFIG_TRACE_IRQFLAGS) /* * actually the registers should be pushed and pop'd conditionally, but @@ -128,10 +128,6 @@ #endif .endm - .macro asm_trace_hardirqs_on - asm_trace_hardirqs_on_cond al - .endm - .macro disable_irq disable_irq_notrace asm_trace_hardirqs_off @@ -173,7 +169,7 @@ .macro restore_irqs, oldcpsr tst \oldcpsr, #PSR_I_BIT - asm_trace_hardirqs_on_cond eq + asm_trace_hardirqs_on cond=eq restore_irqs_notrace \oldcpsr .endm -- GitLab From 3302caddf10ad50710dbb7a94ccbdb3ad5bf1412 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 20 Aug 2015 16:13:37 +0100 Subject: [PATCH 4763/7006] ARM: entry: efficiency cleanups Make the "fast" syscall return path fast again. The addition of IRQ tracing and context tracking has made this path grossly inefficient. We can do much better if these options are enabled if we save the syscall return code on the stack - we then don't need to save a bunch of registers around every single callout to C code. Acked-by: Will Deacon Signed-off-by: Russell King --- arch/arm/include/asm/assembler.h | 16 ++++++-- arch/arm/include/asm/thread_info.h | 20 ++++------ arch/arm/kernel/entry-common.S | 61 ++++++++++++++++++++++-------- arch/arm/kernel/signal.c | 6 +++ 4 files changed, 71 insertions(+), 32 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 742495eb55262..5a5504f90d5f3 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -108,29 +108,37 @@ .endm #endif - .macro asm_trace_hardirqs_off + .macro asm_trace_hardirqs_off, save=1 #if defined(CONFIG_TRACE_IRQFLAGS) + .if \save stmdb sp!, {r0-r3, ip, lr} + .endif bl trace_hardirqs_off + .if \save ldmia sp!, {r0-r3, ip, lr} + .endif #endif .endm - .macro asm_trace_hardirqs_on, cond=al + .macro asm_trace_hardirqs_on, cond=al, save=1 #if defined(CONFIG_TRACE_IRQFLAGS) /* * actually the registers should be pushed and pop'd conditionally, but * after bl the flags are certainly clobbered */ + .if \save stmdb sp!, {r0-r3, ip, lr} + .endif bl\cond trace_hardirqs_on + .if \save ldmia sp!, {r0-r3, ip, lr} + .endif #endif .endm - .macro disable_irq + .macro disable_irq, save=1 disable_irq_notrace - asm_trace_hardirqs_off + asm_trace_hardirqs_off \save .endm .macro enable_irq diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index bd32eded3e506..71e0ffcedf8e4 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -136,22 +136,18 @@ extern int vfp_restore_user_hwstate(struct user_vfp __user *, /* * thread information flags: - * TIF_SYSCALL_TRACE - syscall trace active - * TIF_SYSCAL_AUDIT - syscall auditing active - * TIF_SIGPENDING - signal pending - * TIF_NEED_RESCHED - rescheduling necessary - * TIF_NOTIFY_RESUME - callback before returning to user * TIF_USEDFPU - FPU was used by this task this quantum (SMP) * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED */ -#define TIF_SIGPENDING 0 -#define TIF_NEED_RESCHED 1 +#define TIF_SIGPENDING 0 /* signal pending */ +#define TIF_NEED_RESCHED 1 /* rescheduling necessary */ #define TIF_NOTIFY_RESUME 2 /* callback before returning to user */ -#define TIF_UPROBE 7 -#define TIF_SYSCALL_TRACE 8 -#define TIF_SYSCALL_AUDIT 9 -#define TIF_SYSCALL_TRACEPOINT 10 -#define TIF_SECCOMP 11 /* seccomp syscall filtering active */ +#define TIF_UPROBE 3 /* breakpointed or singlestepping */ +#define TIF_SYSCALL_TRACE 4 /* syscall trace active */ +#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */ +#define TIF_SYSCALL_TRACEPOINT 6 /* syscall tracepoint instrumentation */ +#define TIF_SECCOMP 7 /* seccomp syscall filtering active */ + #define TIF_NOHZ 12 /* in adaptive nohz mode */ #define TIF_USING_IWMMXT 17 #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 92828a1dec80c..dd3721d1185e3 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -24,35 +24,55 @@ .align 5 +#if !(IS_ENABLED(CONFIG_TRACE_IRQFLAGS) || IS_ENABLED(CONFIG_CONTEXT_TRACKING)) /* - * This is the fast syscall return path. We do as little as - * possible here, and this includes saving r0 back into the SVC - * stack. + * This is the fast syscall return path. We do as little as possible here, + * such as avoiding writing r0 to the stack. We only use this path if we + * have tracing and context tracking disabled - the overheads from those + * features make this path too inefficient. */ ret_fast_syscall: UNWIND(.fnstart ) UNWIND(.cantunwind ) - disable_irq @ disable interrupts + disable_irq_notrace @ disable interrupts ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing - tst r1, #_TIF_SYSCALL_WORK - bne __sys_trace_return - tst r1, #_TIF_WORK_MASK + tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK bne fast_work_pending - asm_trace_hardirqs_on /* perform architecture specific actions before user return */ arch_ret_to_user r1, lr - ct_user_enter restore_user_regs fast = 1, offset = S_OFF UNWIND(.fnend ) +ENDPROC(ret_fast_syscall) -/* - * Ok, we need to do extra processing, enter the slow path. - */ + /* Ok, we need to do extra processing, enter the slow path. */ fast_work_pending: str r0, [sp, #S_R0+S_OFF]! @ returned r0 -work_pending: + /* fall through to work_pending */ +#else +/* + * The "replacement" ret_fast_syscall for when tracing or context tracking + * is enabled. As we will need to call out to some C functions, we save + * r0 first to avoid needing to save registers around each C function call. + */ +ret_fast_syscall: + UNWIND(.fnstart ) + UNWIND(.cantunwind ) + str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 + disable_irq_notrace @ disable interrupts + ldr r1, [tsk, #TI_FLAGS] @ re-check for syscall tracing + tst r1, #_TIF_SYSCALL_WORK | _TIF_WORK_MASK + beq no_work_pending + UNWIND(.fnend ) +ENDPROC(ret_fast_syscall) + + /* Slower path - fall through to work_pending */ +#endif + + tst r1, #_TIF_SYSCALL_WORK + bne __sys_trace_return_nosave +slow_work_pending: mov r0, sp @ 'regs' mov r2, why @ 'syscall' bl do_work_pending @@ -64,16 +84,19 @@ work_pending: /* * "slow" syscall return path. "why" tells us if this was a real syscall. + * IRQs may be enabled here, so always disable them. Note that we use the + * "notrace" version to avoid calling into the tracing code unnecessarily. + * do_work_pending() will update this state if necessary. */ ENTRY(ret_to_user) ret_slow_syscall: - disable_irq @ disable interrupts + disable_irq_notrace @ disable interrupts ENTRY(ret_to_user_from_irq) ldr r1, [tsk, #TI_FLAGS] tst r1, #_TIF_WORK_MASK - bne work_pending + bne slow_work_pending no_work_pending: - asm_trace_hardirqs_on + asm_trace_hardirqs_on save = 0 /* perform architecture specific actions before user return */ arch_ret_to_user r1, lr @@ -251,6 +274,12 @@ __sys_trace_return: bl syscall_trace_exit b ret_slow_syscall +__sys_trace_return_nosave: + asm_trace_hardirqs_off save=0 + mov r0, sp + bl syscall_trace_exit + b ret_slow_syscall + .align 5 #ifdef CONFIG_ALIGNMENT_TRAP .type __cr_alignment, #object diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c index 423663e23791e..b6cda06b455fc 100644 --- a/arch/arm/kernel/signal.c +++ b/arch/arm/kernel/signal.c @@ -562,6 +562,12 @@ static int do_signal(struct pt_regs *regs, int syscall) asmlinkage int do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall) { + /* + * The assembly code enters us with IRQs off, but it hasn't + * informed the tracing code of that for efficiency reasons. + * Update the trace code with the current status. + */ + trace_hardirqs_off(); do { if (likely(thread_flags & _TIF_NEED_RESCHED)) { schedule(); -- GitLab From e0aa3a665782e29cec752ae667c51ed4ee75d11f Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 20 Aug 2015 17:39:32 +0100 Subject: [PATCH 4764/7006] ARM: entry: ensure that IRQs are enabled when calling syscall_trace_exit() The audit code looks like it's been written to cope with being called with IRQs enabled. However, it's unclear whether IRQs should be enabled or disabled when calling the syscall tracing infrastructure. Right now, sometimes we call this with IRQs enabled, and other times with IRQs disabled. Opt for IRQs being enabled for consistency. Acked-by: Will Deacon Signed-off-by: Russell King --- arch/arm/kernel/entry-common.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index dd3721d1185e3..d83a40d8e055f 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -275,7 +275,7 @@ __sys_trace_return: b ret_slow_syscall __sys_trace_return_nosave: - asm_trace_hardirqs_off save=0 + enable_irq_notrace mov r0, sp bl syscall_trace_exit b ret_slow_syscall -- GitLab From 5e9a3fcfa2ca10e3ff76938fe9a12515ffa41003 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 23 Aug 2015 10:07:13 +0800 Subject: [PATCH 4765/7006] ASoC: tegra: Fix unused variable 'spdif' warning Fix below build warning: CC [M] sound/soc/tegra/tegra20_spdif.o sound/soc/tegra/tegra20_spdif.c: In function 'tegra20_spdif_platform_remove': sound/soc/tegra/tegra20_spdif.c:361:24: warning: unused variable 'spdif' [-Wunused-variable] Signed-off-by: Axel Lin Reviewed-by: Vaishali Thakkar Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_spdif.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 66237bc440339..0809b1ec11710 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -358,8 +358,6 @@ err_pm_disable: static int tegra20_spdif_platform_remove(struct platform_device *pdev) { - struct tegra20_spdif *spdif = dev_get_drvdata(&pdev->dev); - pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) tegra20_spdif_runtime_suspend(&pdev->dev); -- GitLab From 4df4eab168c1c4058603be55a3169d4a45779cc0 Mon Sep 17 00:00:00 2001 From: Joerg Roedel Date: Tue, 25 Aug 2015 10:54:28 +0200 Subject: [PATCH 4766/7006] iommu/vt-d: Really use upper context table when necessary There is a bug in iommu_context_addr() which will always use the lower context table, even when the upper context table needs to be used. Fix this issue. Fixes: 03ecc32c5274 ("iommu/vt-d: support extended root and context entries") Reported-by: Xiao, Nan Signed-off-by: Joerg Roedel --- drivers/iommu/intel-iommu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c index a85077d4335b5..63daf1ba04b7e 100644 --- a/drivers/iommu/intel-iommu.c +++ b/drivers/iommu/intel-iommu.c @@ -803,6 +803,7 @@ static inline struct context_entry *iommu_context_addr(struct intel_iommu *iommu struct context_entry *context; u64 *entry; + entry = &root->lo; if (ecs_enabled(iommu)) { if (devfn >= 0x80) { devfn -= 0x80; @@ -810,7 +811,6 @@ static inline struct context_entry *iommu_context_addr(struct intel_iommu *iommu } devfn *= 2; } - entry = &root->lo; if (*entry & 1) context = phys_to_virt(*entry & VTD_PAGE_MASK); else { -- GitLab From a2bc2af66a5b656577fc2d71b6c277b73537777e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Tue, 25 Aug 2015 08:31:14 +0200 Subject: [PATCH 4767/7006] ALSA: ppc: keywest: Export I2C module alias information The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Takashi Iwai --- sound/ppc/keywest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index 6120a067494a4..f644a8c57e0ad 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -101,6 +101,7 @@ static const struct i2c_device_id keywest_i2c_id[] = { { "keywest", 0 }, /* instantiated by us if needed */ { } }; +MODULE_DEVICE_TABLE(i2c, keywest_i2c_id); static struct i2c_driver keywest_driver = { .driver = { -- GitLab From 14250640cd52bf12831799c35502184c4ae8963b Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Fri, 14 Aug 2015 07:16:39 +0200 Subject: [PATCH 4768/7006] ath9k_htc: do ani shortcalibratio if we got -ETIMEDOUT current code will handle -ETIMEDOUT as success which is probalbly wrong. According to this comment I assume it is safe to handle -ETIMEDOUT as false: drivers/net/wireless/ath/ath9k/calib.c 290 /* 291 * We timed out waiting for the noisefloor to load, probably due to an 292 * in-progress rx. Simply return here and allow the load plenty of time 293 * to complete before the next calibration interval. We need to avoid 294 * trying to load -50 (which happens below) while the previous load is 295 * still in progress as this can cause rx deafness. Instead by returning 296 * here, the baseband nf cal will just be capped by our present 297 * noisefloor until the next calibration timer. 298 */ Since no other error wariants are present, this patch is checking only for (ret <= 0). Reported-by: Dan Carpenter Signed-off-by: Oleksij Rempel Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/htc_drv_main.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index dab1323dfec76..172a9ff4aaabc 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -794,8 +794,11 @@ void ath9k_htc_ani_work(struct work_struct *work) common->ani.longcal_timer = timestamp; } - /* Short calibration applies only while caldone is false */ - if (!common->ani.caldone) { + /* + * Short calibration applies only while caldone + * is false or -ETIMEDOUT + */ + if (common->ani.caldone <= 0) { if ((timestamp - common->ani.shortcal_timer) >= short_cal_interval) { shortcal = true; @@ -844,7 +847,11 @@ set_timer: */ cal_interval = ATH_LONG_CALINTERVAL; cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); - if (!common->ani.caldone) + /* + * Short calibration applies only while caldone + * is false or -ETIMEDOUT + */ + if (common->ani.caldone <= 0) cal_interval = min(cal_interval, (u32)short_cal_interval); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, -- GitLab From 12ff7288bfed9d6d62186f0dd782b7b5a43670cd Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sat, 15 Aug 2015 18:36:37 +0800 Subject: [PATCH 4769/7006] rtlwifi: rtl8192ee: fix semicolon.cocci warnings drivers/net/wireless/rtlwifi/rtl8192ee/phy.c:856:2-3: Unneeded semicolon drivers/net/wireless/rtlwifi/rtl8192ee/phy.c:492:3-4: Unneeded semicolon drivers/net/wireless/rtlwifi/rtl8192ee/phy.c:452:3-4: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Larry Finger Signed-off-by: Fengguang Wu Signed-off-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192ee/phy.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c index a863a44f9e16a..018340aedf099 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192ee/phy.c @@ -449,7 +449,7 @@ static void _rtl92ee_phy_set_txpower_by_rate_base(struct ieee80211_hw *hw, "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n", rate_section, path, txnum); break; - }; + } } else { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Invalid Band %d\n", band); @@ -489,7 +489,7 @@ static u8 _rtl92ee_phy_get_txpower_by_rate_base(struct ieee80211_hw *hw, "Invalid RateSection %d in 2.4G,Rf %d,%dTx\n", rate_section, path, txnum); break; - }; + } } else { RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Invalid Band %d()\n", band); @@ -853,7 +853,7 @@ static u8 _rtl92ee_get_rate_section_index(u32 regaddr) else if (regaddr >= 0xE20 && regaddr <= 0xE4C) index = (u8)((regaddr - 0xE20) / 4); break; - }; + } return index; } -- GitLab From 654e2751c9f00491c4622893de59a21784e39ccf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2015 14:04:44 +0200 Subject: [PATCH 4770/7006] ALSA: ppc: Add missing inclusion of linux/module.h Otherwise it triggers a compile warning like: sound/ppc/keywest.c:104:1: warning: data definition has no type or storage class sound/ppc/keywest.c:104:1: error: type defaults to 'int' in declaration of 'MODULE_DEVICE_TABLE' [-Werror=implicit-int] Fixes: a2bc2af66a5b ('ALSA: ppc: keywest: Export I2C module alias information') Reported-by: kbuild test robot Reviewed-by: Javier Martinez Canillas Signed-off-by: Takashi Iwai --- sound/ppc/keywest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/ppc/keywest.c b/sound/ppc/keywest.c index f644a8c57e0ad..4373615f13e29 100644 --- a/sound/ppc/keywest.c +++ b/sound/ppc/keywest.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include "pmac.h" -- GitLab From 1642d09fb9b128e8e538b2a4179962a34f38dff9 Mon Sep 17 00:00:00 2001 From: Adrien Schildknecht Date: Wed, 19 Aug 2015 17:33:12 +0200 Subject: [PATCH 4771/7006] rtlwifi: rtl8192cu: Add new device ID The v2 of NetGear WNA1000M uses a different idProduct: USB ID 0846:9043 Signed-off-by: Adrien Schildknecht Cc: Stable Acked-by: Larry Finger Signed-off-by: Kalle Valo --- drivers/net/wireless/rtlwifi/rtl8192cu/sw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index 23806c243a531..fd4a5353d2169 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -321,6 +321,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0846, 0x9043, rtl92cu_hal_cfg)}, /*NG WNA1000Mv2*/ {RTL_USB_DEVICE(0x0b05, 0x17ba, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ -- GitLab From 50f32e2d1044b1f1658a1e40c8831969a30ca6a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Thu, 20 Aug 2015 00:16:42 +0200 Subject: [PATCH 4772/7006] brcmfmac: check all combinations when setting wiphy's addresses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broadcom is working on better reflection of interface combinations. With upcoming patches we may have 1st combination supporting less interfaces than others. To don't run out of addresses check all combinations to find the one with the greatest max_interfaces value. Signed-off-by: Rafał Miłecki Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index ffe526070d6f1..c85e2db75f1d4 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5786,7 +5786,9 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy) static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) { struct brcmf_pub *drvr = ifp->drvr; + const struct ieee80211_iface_combination *combo; struct ieee80211_supported_band *band; + u16 max_interfaces = 0; __le32 bandlist[3]; u32 n_bands; int err, i; @@ -5799,8 +5801,13 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp) if (err) return err; - for (i = 0; i < wiphy->iface_combinations->max_interfaces && - i < ARRAY_SIZE(drvr->addresses); i++) { + for (i = 0, combo = wiphy->iface_combinations; + i < wiphy->n_iface_combinations; i++, combo++) { + max_interfaces = max(max_interfaces, combo->max_interfaces); + } + + for (i = 0; i < max_interfaces && i < ARRAY_SIZE(drvr->addresses); + i++) { u8 *addr = drvr->addresses[i].addr; memcpy(addr, drvr->mac, ETH_ALEN); -- GitLab From 0882dda3bcbb51e63c2fd25705ec8541bf86378e Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Aug 2015 22:06:03 +0200 Subject: [PATCH 4773/7006] brcmfmac: correct interface combination info The interface combination provided by brcmfmac did not truly reflect the combinations supported by driver and/or firmware. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Pontus Fuchs Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/brcm80211/brcmfmac/cfg80211.c | 151 +++++++++++++----- 1 file changed, 112 insertions(+), 39 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index c85e2db75f1d4..26e1fe8c132c6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -5695,63 +5695,132 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { } }; +/** + * brcmf_setup_ifmodes() - determine interface modes and combinations. + * + * @wiphy: wiphy object. + * @ifp: interface object needed for feat module api. + * + * The interface modes and combinations are determined dynamically here + * based on firmware functionality. + * + * no p2p and no mbss: + * + * #STA <= 1, #AP <= 1, channels = 1, 2 total + * + * no p2p and mbss: + * + * #STA <= 1, #AP <= 1, channels = 1, 2 total + * #AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, no mchan, and mbss: + * + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total + * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total + * #AP <= 4, matching BI, channels = 1, 4 total + * + * p2p, mchan, and mbss: + * + * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total + * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total + * #AP <= 4, matching BI, channels = 1, 4 total + */ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) { struct ieee80211_iface_combination *combo = NULL; - struct ieee80211_iface_limit *limits = NULL; - int i = 0, max_iface_cnt; + struct ieee80211_iface_limit *c0_limits = NULL; + struct ieee80211_iface_limit *p2p_limits = NULL; + struct ieee80211_iface_limit *mbss_limits = NULL; + bool mbss, p2p; + int i, c, n_combos; + + mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS); + p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P); - combo = kzalloc(sizeof(*combo), GFP_KERNEL); + n_combos = 1 + !!p2p + !!mbss; + combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL); if (!combo) goto err; - limits = kzalloc(sizeof(*limits) * 4, GFP_KERNEL); - if (!limits) + c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); + if (!c0_limits) goto err; + if (p2p) { + p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); + if (!p2p_limits) + goto err; + } + + if (mbss) { + mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); + if (!mbss_limits) + goto err; + } + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP); - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) - combo->num_different_channels = 2; - else - combo->num_different_channels = 1; - - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { - limits[i].max = 1; - limits[i++].types = BIT(NL80211_IFTYPE_STATION); - limits[i].max = 4; - limits[i++].types = BIT(NL80211_IFTYPE_AP); - max_iface_cnt = 5; - } else { - limits[i].max = 2; - limits[i++].types = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); - max_iface_cnt = 2; - } - - if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P)) { + c = 0; + i = 0; + combo[c].num_different_channels = 1; + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); + if (p2p) { + if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) + combo[c].num_different_channels = 2; wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) | BIT(NL80211_IFTYPE_P2P_DEVICE); - limits[i].max = 1; - limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); - limits[i].max = 1; - limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); - max_iface_cnt += 2; - } - combo->max_interfaces = max_iface_cnt; - combo->limits = limits; - combo->n_limits = i; - + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | + BIT(NL80211_IFTYPE_P2P_GO); + } else { + c0_limits[i].max = 1; + c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); + } + combo[c].max_interfaces = i; + combo[c].n_limits = i; + combo[c].limits = c0_limits; + + if (p2p) { + c++; + i = 0; + combo[c].num_different_channels = 1; + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_STATION); + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_AP); + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT); + p2p_limits[i].max = 1; + p2p_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); + combo[c].max_interfaces = i; + combo[c].n_limits = i; + combo[c].limits = p2p_limits; + } + + if (mbss) { + c++; + combo[c].beacon_int_infra_match = true; + combo[c].num_different_channels = 1; + mbss_limits[0].max = 4; + mbss_limits[0].types = BIT(NL80211_IFTYPE_AP); + combo[c].max_interfaces = 4; + combo[c].n_limits = 1; + combo[c].limits = mbss_limits; + } + wiphy->n_iface_combinations = n_combos; wiphy->iface_combinations = combo; - wiphy->n_iface_combinations = 1; return 0; err: - kfree(limits); + kfree(c0_limits); + kfree(p2p_limits); + kfree(mbss_limits); kfree(combo); return -ENOMEM; } @@ -6080,11 +6149,15 @@ static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy, static void brcmf_free_wiphy(struct wiphy *wiphy) { + int i; + if (!wiphy) return; - if (wiphy->iface_combinations) - kfree(wiphy->iface_combinations->limits); + if (wiphy->iface_combinations) { + for (i = 0; i < wiphy->n_iface_combinations; i++) + kfree(wiphy->iface_combinations[i].limits); + } kfree(wiphy->iface_combinations); if (wiphy->bands[IEEE80211_BAND_2GHZ]) { kfree(wiphy->bands[IEEE80211_BAND_2GHZ]->channels); -- GitLab From 2bb66a8183d6396babde51e558b1ab35733f275f Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 20 Aug 2015 22:06:04 +0200 Subject: [PATCH 4774/7006] brcmfmac: add debugfs entry for msgbuf statistics Expose ring buffer read/write pointers and other useful statistics through debugfs. Reviewed-by: Arend Van Spriel Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../net/wireless/brcm80211/brcmfmac/msgbuf.c | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c index 898c3801e6587..7b2136c9badb5 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c @@ -1360,6 +1360,60 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid) } } +#ifdef DEBUG +static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) +{ + struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); + struct brcmf_pub *drvr = bus_if->drvr; + struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd; + struct brcmf_commonring *commonring; + u16 i; + struct brcmf_flowring_ring *ring; + struct brcmf_flowring_hash *hash; + + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; + seq_printf(seq, "h2d_ctl_submit: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_RXPOST_SUBMIT]; + seq_printf(seq, "h2d_rx_submit: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_CONTROL_COMPLETE]; + seq_printf(seq, "d2h_ctl_cmplt: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_TX_COMPLETE]; + seq_printf(seq, "d2h_tx_cmplt: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + commonring = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE]; + seq_printf(seq, "d2h_rx_cmplt: rp %4u, wp %4u, depth %4u\n", + commonring->r_ptr, commonring->w_ptr, commonring->depth); + + seq_printf(seq, "\nh2d_flowrings: depth %u\n", + BRCMF_H2D_TXFLOWRING_MAX_ITEM); + seq_puts(seq, "Active flowrings:\n"); + hash = msgbuf->flow->hash; + for (i = 0; i < msgbuf->flow->nrofrings; i++) { + if (!msgbuf->flow->rings[i]) + continue; + ring = msgbuf->flow->rings[i]; + if (ring->status != RING_OPEN) + continue; + commonring = msgbuf->flowrings[i]; + hash = &msgbuf->flow->hash[ring->hash_id]; + seq_printf(seq, "id %3u: rp %4u, wp %4u, qlen %4u, blocked %u\n" + " ifidx %u, fifo %u, da %pM\n", + i, commonring->r_ptr, commonring->w_ptr, + skb_queue_len(&ring->skblist), ring->blocked, + hash->ifidx, hash->fifo, hash->mac); + } + + return 0; +} +#else +static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data) +{ + return 0; +} +#endif int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) { @@ -1460,6 +1514,8 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) spin_lock_init(&msgbuf->flowring_work_lock); INIT_LIST_HEAD(&msgbuf->work_queue); + brcmf_debugfs_add_entry(drvr, "msgbuf_stats", brcmf_msgbuf_stats_read); + return 0; fail: -- GitLab From 39504a2d21adde4748b5ce8c057e09edf3fe17bb Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Aug 2015 22:06:05 +0200 Subject: [PATCH 4775/7006] brcmfmac: make use of cfg80211_check_combinations() Use cfg80211_check_combinations() so we can bail out early when an interface add or change results in an invalid combination. Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/brcm80211/brcmfmac/cfg80211.c | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c index 26e1fe8c132c6..a293275c1b0bc 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c @@ -469,6 +469,36 @@ brcmf_find_wpsie(const u8 *parse, u32 len) return NULL; } +static int brcmf_vif_change_validate(struct brcmf_cfg80211_info *cfg, + struct brcmf_cfg80211_vif *vif, + enum nl80211_iftype new_type) +{ + int iftype_num[NUM_NL80211_IFTYPES]; + struct brcmf_cfg80211_vif *pos; + + memset(&iftype_num[0], 0, sizeof(iftype_num)); + list_for_each_entry(pos, &cfg->vif_list, list) + if (pos == vif) + iftype_num[new_type]++; + else + iftype_num[pos->wdev.iftype]++; + + return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); +} + +static int brcmf_vif_add_validate(struct brcmf_cfg80211_info *cfg, + enum nl80211_iftype new_type) +{ + int iftype_num[NUM_NL80211_IFTYPES]; + struct brcmf_cfg80211_vif *pos; + + memset(&iftype_num[0], 0, sizeof(iftype_num)); + list_for_each_entry(pos, &cfg->vif_list, list) + iftype_num[pos->wdev.iftype]++; + + iftype_num[new_type]++; + return cfg80211_check_combinations(cfg->wiphy, 1, 0, iftype_num); +} static void convert_key_from_CPU(struct brcmf_wsec_key *key, struct brcmf_wsec_key_le *key_le) @@ -663,8 +693,14 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, struct vif_params *params) { struct wireless_dev *wdev; + int err; brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); + err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); + if (err) { + brcmf_err("iface validation failed: err=%d\n", err); + return ERR_PTR(err); + } switch (type) { case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_STATION: @@ -823,8 +859,12 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev, s32 ap = 0; s32 err = 0; - brcmf_dbg(TRACE, "Enter, ndev=%p, type=%d\n", ndev, type); - + brcmf_dbg(TRACE, "Enter, idx=%d, type=%d\n", ifp->bssidx, type); + err = brcmf_vif_change_validate(wiphy_to_cfg(wiphy), vif, type); + if (err) { + brcmf_err("iface validation failed: err=%d\n", err); + return err; + } switch (type) { case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_WDS: -- GitLab From b02bf1932a4855dc860ed20cdab94f1ea9b1c56f Mon Sep 17 00:00:00 2001 From: Franky Lin Date: Thu, 20 Aug 2015 22:06:06 +0200 Subject: [PATCH 4776/7006] brcmfmac: block the correct flowring when backup queue overflow brcmf_flowring_block blocks the last active flowring under the same interface instead of the one provided by caller. This could lead to a dead lock of netif stop if there are more than one flowring under the interface and the traffic is high enough so brcmf_flowring_enqueue can not unblock the ring right away. Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Hante Meuleman Signed-off-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/flowring.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c index 59440631fec50..8d1ab4ab5be80 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c @@ -194,11 +194,15 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, spin_lock_irqsave(&flow->block_lock, flags); ring = flow->rings[flowid]; + if (ring->blocked == blocked) { + spin_unlock_irqrestore(&flow->block_lock, flags); + return; + } ifidx = brcmf_flowring_ifidx_get(flow, flowid); currently_blocked = false; for (i = 0; i < flow->nrofrings; i++) { - if (flow->rings[i]) { + if ((flow->rings[i]) && (i != flowid)) { ring = flow->rings[i]; if ((ring->status == RING_OPEN) && (brcmf_flowring_ifidx_get(flow, i) == ifidx)) { @@ -209,8 +213,8 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid, } } } - ring->blocked = blocked; - if (currently_blocked == blocked) { + flow->rings[flowid]->blocked = blocked; + if (currently_blocked) { spin_unlock_irqrestore(&flow->block_lock, flags); return; } -- GitLab From fc7c3ad5251cf76fc78b7f4701e35a0af6375335 Mon Sep 17 00:00:00 2001 From: Arend van Spriel Date: Thu, 20 Aug 2015 22:06:07 +0200 Subject: [PATCH 4777/7006] brcmfmac: bump highest event number for 4339 firmware The event mask length is determined by the highest event number that is specified in the driver. When this length is shorter than firmware expects setting event mask will fail and device becomes pretty useless. This issue was reported with bcm4339 firmware that was recently released. Reported-by: Pontus Fuchs Reviewed-by: Hante Meuleman Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Pontus Fuchs Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/brcm80211/brcmfmac/fweh.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h index cbf033f59109d..1326898d608ee 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h @@ -85,7 +85,6 @@ struct brcmf_event; BRCMF_ENUM_DEF(IF, 54) \ BRCMF_ENUM_DEF(P2P_DISC_LISTEN_COMPLETE, 55) \ BRCMF_ENUM_DEF(RSSI, 56) \ - BRCMF_ENUM_DEF(PFN_SCAN_COMPLETE, 57) \ BRCMF_ENUM_DEF(EXTLOG_MSG, 58) \ BRCMF_ENUM_DEF(ACTION_FRAME, 59) \ BRCMF_ENUM_DEF(ACTION_FRAME_COMPLETE, 60) \ @@ -103,8 +102,7 @@ struct brcmf_event; BRCMF_ENUM_DEF(FIFO_CREDIT_MAP, 74) \ BRCMF_ENUM_DEF(ACTION_FRAME_RX, 75) \ BRCMF_ENUM_DEF(TDLS_PEER_EVENT, 92) \ - BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) \ - BRCMF_ENUM_DEF(PSTA_PRIMARY_INTF_IND, 128) + BRCMF_ENUM_DEF(BCMC_CREDIT_SUPPORT, 127) #define BRCMF_ENUM_DEF(id, val) \ BRCMF_E_##id = (val), @@ -112,7 +110,11 @@ struct brcmf_event; /* firmware event codes sent by the dongle */ enum brcmf_fweh_event_code { BRCMF_FWEH_EVENT_ENUM_DEFLIST - BRCMF_E_LAST + /* this determines event mask length which must match + * minimum length check in device firmware so it is + * hard-coded here. + */ + BRCMF_E_LAST = 139 }; #undef BRCMF_ENUM_DEF -- GitLab From 4e70f2144db01f7214ed5846e47abf128fbfb5af Mon Sep 17 00:00:00 2001 From: Hante Meuleman Date: Thu, 20 Aug 2015 22:06:08 +0200 Subject: [PATCH 4778/7006] brcmfmac: Add support for host platform NVRAM loading. Host platforms such as routers supported by OpenWRT can support NVRAM reading directly from internal NVRAM store. With this patch the nvram load routines will fall back to this method when there is no nvram file and support is available in the kernel. Reviewed-by: Arend Van Spriel Reviewed-by: Franky (Zhenhui) Lin Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Daniel (Deognyoun) Kim Signed-off-by: Hante Meuleman Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- .../wireless/brcm80211/brcmfmac/firmware.c | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c index 743f16b6a0729..971920f77b68e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "debug.h" #include "firmware.h" @@ -426,18 +427,32 @@ static void brcmf_fw_request_nvram_done(const struct firmware *fw, void *ctx) struct brcmf_fw *fwctx = ctx; u32 nvram_length = 0; void *nvram = NULL; + u8 *data = NULL; + size_t data_len; + bool raw_nvram; brcmf_dbg(TRACE, "enter: dev=%s\n", dev_name(fwctx->dev)); - if (!fw && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) - goto fail; + if (fw && fw->data) { + data = (u8 *)fw->data; + data_len = fw->size; + raw_nvram = false; + } else { + data = bcm47xx_nvram_get_contents(&data_len); + if (!data && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; + raw_nvram = true; + } - if (fw) { - nvram = brcmf_fw_nvram_strip(fw->data, fw->size, &nvram_length, + if (data) + nvram = brcmf_fw_nvram_strip(data, data_len, &nvram_length, fwctx->domain_nr, fwctx->bus_nr); + + if (raw_nvram) + bcm47xx_nvram_release_contents(data); + if (fw) release_firmware(fw); - if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) - goto fail; - } + if (!nvram && !(fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL)) + goto fail; fwctx->done(fwctx->dev, fwctx->code, nvram, nvram_length); kfree(fwctx); @@ -473,15 +488,9 @@ static void brcmf_fw_request_code_done(const struct firmware *fw, void *ctx) if (!ret) return; - /* when nvram is optional call .done() callback here */ - if (fwctx->flags & BRCMF_FW_REQ_NV_OPTIONAL) { - fwctx->done(fwctx->dev, fw, NULL, 0); - kfree(fwctx); - return; - } + brcmf_fw_request_nvram_done(NULL, fwctx); + return; - /* failed nvram request */ - release_firmware(fw); fail: brcmf_dbg(TRACE, "failed: dev=%s\n", dev_name(fwctx->dev)); device_release_driver(fwctx->dev); -- GitLab From a8b9774571d46506a0774b1ced3493b1245cf893 Mon Sep 17 00:00:00 2001 From: Christian Engelmayer Date: Fri, 21 Aug 2015 23:14:26 +0200 Subject: [PATCH 4779/7006] rsi: Fix possible leak when loading firmware Commit 5d5cd85ff441 ("rsi: Fix failure to load firmware after memory leak fix and fix the leak") also added a check on the allocation of DMA-accessible memory that may directly return. In that case the already allocated firmware data is leaked. Make sure the data is always freed correctly. Detected by Coverity CID 1316519. Fixes: 5d5cd85ff441 ("rsi: Fix failure to load firmware after memory leak fix and fix the leak") Signed-off-by: Christian Engelmayer Signed-off-by: Kalle Valo --- drivers/net/wireless/rsi/rsi_91x_sdio_ops.c | 8 ++++++-- drivers/net/wireless/rsi/rsi_91x_usb_ops.c | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c index 1c6788aecc626..40d72312f3df2 100644 --- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c @@ -203,8 +203,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) /* Copy firmware into DMA-accessible memory */ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) - return -ENOMEM; + if (!fw) { + status = -ENOMEM; + goto out; + } len = fw_entry->size; if (len % 4) @@ -217,6 +219,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common) status = rsi_copy_to_card(common, fw, len, num_blocks); kfree(fw); + +out: release_firmware(fw_entry); return status; } diff --git a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c index 30c2cf7fa93b0..de4900862836a 100644 --- a/drivers/net/wireless/rsi/rsi_91x_usb_ops.c +++ b/drivers/net/wireless/rsi/rsi_91x_usb_ops.c @@ -148,8 +148,10 @@ static int rsi_load_ta_instructions(struct rsi_common *common) /* Copy firmware into DMA-accessible memory */ fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL); - if (!fw) - return -ENOMEM; + if (!fw) { + status = -ENOMEM; + goto out; + } len = fw_entry->size; if (len % 4) @@ -162,6 +164,8 @@ static int rsi_load_ta_instructions(struct rsi_common *common) status = rsi_copy_to_card(common, fw, len, num_blocks); kfree(fw); + +out: release_firmware(fw_entry); return status; } -- GitLab From 52293c67f1e7542a6dc61037d83c266e216bef27 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 24 Aug 2015 22:46:13 -0400 Subject: [PATCH 4780/7006] drm/amdgpu: fix IH ring allocation for bus addresses (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use pci_alloc_consistent rather than kzalloc since we need 256 byte aligned memory for the ring buffer. v2: fix copy paste typo in free function noticed by Jammy. bug: https://bugs.freedesktop.org/show_bug.cgi?id=91749 Reviewed-by: Christian König Reviewed-by: Jammy Zhou Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c index 90044b2544045..5c8a803acedcb 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ih.c @@ -98,18 +98,12 @@ int amdgpu_ih_ring_init(struct amdgpu_device *adev, unsigned ring_size, /* add 8 bytes for the rptr/wptr shadows and * add them to the end of the ring allocation. */ - adev->irq.ih.ring = kzalloc(adev->irq.ih.ring_size + 8, GFP_KERNEL); + adev->irq.ih.ring = pci_alloc_consistent(adev->pdev, + adev->irq.ih.ring_size + 8, + &adev->irq.ih.rb_dma_addr); if (adev->irq.ih.ring == NULL) return -ENOMEM; - adev->irq.ih.rb_dma_addr = pci_map_single(adev->pdev, - (void *)adev->irq.ih.ring, - adev->irq.ih.ring_size, - PCI_DMA_BIDIRECTIONAL); - if (pci_dma_mapping_error(adev->pdev, adev->irq.ih.rb_dma_addr)) { - dev_err(&adev->pdev->dev, "Failed to DMA MAP the IH RB page\n"); - kfree((void *)adev->irq.ih.ring); - return -ENOMEM; - } + memset((void *)adev->irq.ih.ring, 0, adev->irq.ih.ring_size + 8); adev->irq.ih.wptr_offs = (adev->irq.ih.ring_size / 4) + 0; adev->irq.ih.rptr_offs = (adev->irq.ih.ring_size / 4) + 1; } @@ -149,9 +143,9 @@ void amdgpu_ih_ring_fini(struct amdgpu_device *adev) /* add 8 bytes for the rptr/wptr shadows and * add them to the end of the ring allocation. */ - pci_unmap_single(adev->pdev, adev->irq.ih.rb_dma_addr, - adev->irq.ih.ring_size + 8, PCI_DMA_BIDIRECTIONAL); - kfree((void *)adev->irq.ih.ring); + pci_free_consistent(adev->pdev, adev->irq.ih.ring_size + 8, + (void *)adev->irq.ih.ring, + adev->irq.ih.rb_dma_addr); adev->irq.ih.ring = NULL; } } else { -- GitLab From 2fe2918fa3294edc9c3d8d1622bb1a07c00463ff Mon Sep 17 00:00:00 2001 From: Mike Looijmans Date: Wed, 12 Aug 2015 16:22:12 +0200 Subject: [PATCH 4781/7006] pinctrl: zynq: Fix typos in smc0_nand_grp and smc0_nor_grp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group names should be smc0_nand_grp and smc0_nor_grp, otherwise you'll get errors like this if you try to pinmux them via the devicetree: zynq-pinctrl 700.pinctrl: invalid group "smc0_nand_grp" for function "smc0_nand" Probably a typo while creating these tables. Signed-off-by: Mike Looijmans Acked-by: Sören Brinkmann Acked-by: Moritz Fischer Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-zynq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c index 7ce23b6282adf..5aafea8c6590a 100644 --- a/drivers/pinctrl/pinctrl-zynq.c +++ b/drivers/pinctrl/pinctrl-zynq.c @@ -706,10 +706,10 @@ static const char * const sdio1_wp_groups[] = {"gpio0_0_grp", "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp", "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp", "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_wp_grp"}; -static const char * const smc0_nor_groups[] = {"smc0_nor"}; +static const char * const smc0_nor_groups[] = {"smc0_nor_grp"}; static const char * const smc0_nor_cs1_groups[] = {"smc0_nor_cs1_grp"}; static const char * const smc0_nor_addr25_groups[] = {"smc0_nor_addr25_grp"}; -static const char * const smc0_nand_groups[] = {"smc0_nand"}; +static const char * const smc0_nand_groups[] = {"smc0_nand_grp"}; static const char * const can0_groups[] = {"can0_0_grp", "can0_1_grp", "can0_2_grp", "can0_3_grp", "can0_4_grp", "can0_5_grp", "can0_6_grp", "can0_7_grp", "can0_8_grp", "can0_9_grp", -- GitLab From 5e22ec019823b0204720e1ad9a5866c638332b3a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Thu, 13 Aug 2015 17:41:16 +0200 Subject: [PATCH 4782/7006] gpio: extraxfs: fix returnvar.cocci warnings Remove unneeded variable used to store return value. Generated by: scripts/coccinelle/misc/returnvar.cocci Signed-off-by: Fengguang Wu Signed-off-by: Julia Lawall Signed-off-by: Linus Walleij --- drivers/gpio/gpio-etraxfs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index 2ffcd9fdd1f2f..ca33bda8ec555 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -292,7 +292,6 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d) struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); struct etraxfs_gpio_block *block = chip->block; unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); - int ret = -EBUSY; spin_lock(&block->lock); if (block->group[grpirq]) @@ -314,7 +313,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d) out: spin_unlock(&block->lock); - return ret; + return -EBUSY; } static void etraxfs_gpio_irq_release_resources(struct irq_data *d) -- GitLab From 00133ffbf150bf145a946b3f4ee7031503e9751e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Thu, 13 Aug 2015 17:20:21 -0300 Subject: [PATCH 4783/7006] pinctrl: imx6ul: Remove .owner field platform_driver does not need to set an owner as it will be populated by the driver core. The semantic patch that makes this change is available in scripts/coccinelle/api/platform_no_drv_owner.cocci. Signed-off-by: Fabio Estevam Signed-off-by: Linus Walleij --- drivers/pinctrl/freescale/pinctrl-imx6ul.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/pinctrl/freescale/pinctrl-imx6ul.c b/drivers/pinctrl/freescale/pinctrl-imx6ul.c index b182be7293825..08e75764e7be0 100644 --- a/drivers/pinctrl/freescale/pinctrl-imx6ul.c +++ b/drivers/pinctrl/freescale/pinctrl-imx6ul.c @@ -299,7 +299,6 @@ static int imx6ul_pinctrl_probe(struct platform_device *pdev) static struct platform_driver imx6ul_pinctrl_driver = { .driver = { .name = "imx6ul-pinctrl", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(imx6ul_pinctrl_of_match), }, .probe = imx6ul_pinctrl_probe, -- GitLab From 1aa4051b7f5474cca6009c13868c59d78d06f983 Mon Sep 17 00:00:00 2001 From: Junwei Zhang Date: Wed, 19 Aug 2015 16:24:19 +0800 Subject: [PATCH 4784/7006] drm/amdgpu: modify amdgpu_fence_wait_any() to amdgpu_fence_wait_multiple() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename the function and update the related code with this modified function. Add the new parameter of bool wait_all. If wait_all is true, it will return when all fences are signaled or timeout. If wait_all is false, it will return when any fence is signaled or timeout. Signed-off-by: Junwei Zhang Reviewed-by: Monk Liu Reviewed-by: Jammy Zhou Reviewed-by: Christian König --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 9 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 79 +++++++++++++++++------ drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 3 +- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index d050f503d9ffb..4addac5f67631 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -440,9 +440,12 @@ int amdgpu_fence_wait_next(struct amdgpu_ring *ring); int amdgpu_fence_wait_empty(struct amdgpu_ring *ring); unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring); -signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, - struct amdgpu_fence **fences, - bool intr, long t); +signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, + struct amdgpu_fence **array, + uint32_t count, + bool wait_all, + bool intr, + signed long t); struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence); void amdgpu_fence_unref(struct amdgpu_fence **fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 98500f1756f73..ae014fcf524e3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -836,13 +836,12 @@ static inline bool amdgpu_test_signaled(struct amdgpu_fence *fence) return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags); } -static inline bool amdgpu_test_signaled_any(struct amdgpu_fence **fences) +static bool amdgpu_test_signaled_any(struct amdgpu_fence **fences, uint32_t count) { int idx; struct amdgpu_fence *fence; - idx = 0; - for (idx = 0; idx < AMDGPU_MAX_RINGS; ++idx) { + for (idx = 0; idx < count; ++idx) { fence = fences[idx]; if (fence) { if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) @@ -852,6 +851,22 @@ static inline bool amdgpu_test_signaled_any(struct amdgpu_fence **fences) return false; } +static bool amdgpu_test_signaled_all(struct amdgpu_fence **fences, uint32_t count) +{ + int idx; + struct amdgpu_fence *fence; + + for (idx = 0; idx < count; ++idx) { + fence = fences[idx]; + if (fence) { + if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + return false; + } + } + + return true; +} + struct amdgpu_wait_cb { struct fence_cb base; struct task_struct *task; @@ -867,33 +882,56 @@ static void amdgpu_fence_wait_cb(struct fence *fence, struct fence_cb *cb) static signed long amdgpu_fence_default_wait(struct fence *f, bool intr, signed long t) { - struct amdgpu_fence *array[AMDGPU_MAX_RINGS]; struct amdgpu_fence *fence = to_amdgpu_fence(f); struct amdgpu_device *adev = fence->ring->adev; - memset(&array[0], 0, sizeof(array)); - array[0] = fence; - - return amdgpu_fence_wait_any(adev, array, intr, t); + return amdgpu_fence_wait_multiple(adev, &fence, 1, false, intr, t); } -/* wait until any fence in array signaled */ -signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, - struct amdgpu_fence **array, bool intr, signed long t) +/** + * Wait the fence array with timeout + * + * @adev: amdgpu device + * @array: the fence array with amdgpu fence pointer + * @count: the number of the fence array + * @wait_all: the flag of wait all(true) or wait any(false) + * @intr: when sleep, set the current task interruptable or not + * @t: timeout to wait + * + * If wait_all is true, it will return when all fences are signaled or timeout. + * If wait_all is false, it will return when any fence is signaled or timeout. + */ +signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, + struct amdgpu_fence **array, + uint32_t count, + bool wait_all, + bool intr, + signed long t) { long idx = 0; - struct amdgpu_wait_cb cb[AMDGPU_MAX_RINGS]; + struct amdgpu_wait_cb *cb; struct amdgpu_fence *fence; BUG_ON(!array); - for (idx = 0; idx < AMDGPU_MAX_RINGS; ++idx) { + cb = kcalloc(count, sizeof(struct amdgpu_wait_cb), GFP_KERNEL); + if (cb == NULL) { + t = -ENOMEM; + goto err_free_cb; + } + + for (idx = 0; idx < count; ++idx) { fence = array[idx]; if (fence) { cb[idx].task = current; if (fence_add_callback(&fence->base, - &cb[idx].base, amdgpu_fence_wait_cb)) - return t; /* return if fence is already signaled */ + &cb[idx].base, amdgpu_fence_wait_cb)) { + /* The fence is already signaled */ + if (wait_all) + continue; + else + goto fence_rm_cb; + } } } @@ -907,7 +945,9 @@ signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, * amdgpu_test_signaled_any must be called after * set_current_state to prevent a race with wake_up_process */ - if (amdgpu_test_signaled_any(array)) + if (!wait_all && amdgpu_test_signaled_any(array, count)) + break; + if (wait_all && amdgpu_test_signaled_all(array, count)) break; if (adev->needs_reset) { @@ -923,13 +963,16 @@ signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, __set_current_state(TASK_RUNNING); - idx = 0; - for (idx = 0; idx < AMDGPU_MAX_RINGS; ++idx) { +fence_rm_cb: + for (idx = 0; idx < count; ++idx) { fence = array[idx]; if (fence) fence_remove_callback(&fence->base, &cb[idx].base); } +err_free_cb: + kfree(cb); + return t; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index d6398cf45f240..4597899e9758d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -352,7 +352,8 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev, } while (amdgpu_sa_bo_next_hole(sa_manager, fences, tries)); spin_unlock(&sa_manager->wq.lock); - t = amdgpu_fence_wait_any(adev, fences, false, MAX_SCHEDULE_TIMEOUT); + t = amdgpu_fence_wait_multiple(adev, fences, AMDGPU_MAX_RINGS, false, false, + MAX_SCHEDULE_TIMEOUT); r = (t > 0) ? 0 : t; spin_lock(&sa_manager->wq.lock); /* if we have nothing to wait for block */ -- GitLab From 4ce9891ee17c6e064cc334e3297f7e992d47f3a6 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Wed, 19 Aug 2015 16:41:19 +0800 Subject: [PATCH 4785/7006] drm/amdgpu: improve sa_bo->fence by kernel fence Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 8 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 22 ++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 4 +- drivers/gpu/drm/amd/amdgpu/amdgpu_object.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 50 ++++++++++++++----- drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 2 +- 8 files changed, 58 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 4addac5f67631..80f2ceaf6af64 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -441,7 +441,7 @@ int amdgpu_fence_wait_empty(struct amdgpu_ring *ring); unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring); signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, - struct amdgpu_fence **array, + struct fence **array, uint32_t count, bool wait_all, bool intr, @@ -654,7 +654,7 @@ struct amdgpu_sa_bo { struct amdgpu_sa_manager *manager; unsigned soffset; unsigned eoffset; - struct amdgpu_fence *fence; + struct fence *fence; }; /* @@ -696,7 +696,7 @@ bool amdgpu_semaphore_emit_wait(struct amdgpu_ring *ring, struct amdgpu_semaphore *semaphore); void amdgpu_semaphore_free(struct amdgpu_device *adev, struct amdgpu_semaphore **semaphore, - struct amdgpu_fence *fence); + struct fence *fence); /* * Synchronization @@ -717,7 +717,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, int amdgpu_sync_rings(struct amdgpu_sync *sync, struct amdgpu_ring *ring); void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync, - struct amdgpu_fence *fence); + struct fence *fence); /* * GART structures, functions & helpers diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index ae014fcf524e3..9a87372c3c792 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -836,30 +836,30 @@ static inline bool amdgpu_test_signaled(struct amdgpu_fence *fence) return test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags); } -static bool amdgpu_test_signaled_any(struct amdgpu_fence **fences, uint32_t count) +static bool amdgpu_test_signaled_any(struct fence **fences, uint32_t count) { int idx; - struct amdgpu_fence *fence; + struct fence *fence; for (idx = 0; idx < count; ++idx) { fence = fences[idx]; if (fence) { - if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + if (test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) return true; } } return false; } -static bool amdgpu_test_signaled_all(struct amdgpu_fence **fences, uint32_t count) +static bool amdgpu_test_signaled_all(struct fence **fences, uint32_t count) { int idx; - struct amdgpu_fence *fence; + struct fence *fence; for (idx = 0; idx < count; ++idx) { fence = fences[idx]; if (fence) { - if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->base.flags)) + if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) return false; } } @@ -885,7 +885,7 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr, struct amdgpu_fence *fence = to_amdgpu_fence(f); struct amdgpu_device *adev = fence->ring->adev; - return amdgpu_fence_wait_multiple(adev, &fence, 1, false, intr, t); + return amdgpu_fence_wait_multiple(adev, &f, 1, false, intr, t); } /** @@ -902,7 +902,7 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr, * If wait_all is false, it will return when any fence is signaled or timeout. */ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, - struct amdgpu_fence **array, + struct fence **array, uint32_t count, bool wait_all, bool intr, @@ -910,7 +910,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, { long idx = 0; struct amdgpu_wait_cb *cb; - struct amdgpu_fence *fence; + struct fence *fence; BUG_ON(!array); @@ -924,7 +924,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, fence = array[idx]; if (fence) { cb[idx].task = current; - if (fence_add_callback(&fence->base, + if (fence_add_callback(fence, &cb[idx].base, amdgpu_fence_wait_cb)) { /* The fence is already signaled */ if (wait_all) @@ -967,7 +967,7 @@ fence_rm_cb: for (idx = 0; idx < count; ++idx) { fence = array[idx]; if (fence) - fence_remove_callback(&fence->base, &cb[idx].base); + fence_remove_callback(fence, &cb[idx].base); } err_free_cb: diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 1c237f5e3365a..13c5978ac69b9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -93,8 +93,8 @@ int amdgpu_ib_get(struct amdgpu_ring *ring, struct amdgpu_vm *vm, */ void amdgpu_ib_free(struct amdgpu_device *adev, struct amdgpu_ib *ib) { - amdgpu_sync_free(adev, &ib->sync, ib->fence); - amdgpu_sa_bo_free(adev, &ib->sa_bo, ib->fence); + amdgpu_sync_free(adev, &ib->sync, &ib->fence->base); + amdgpu_sa_bo_free(adev, &ib->sa_bo, &ib->fence->base); amdgpu_fence_unref(&ib->fence); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h index 238465a9ac556..6ea18dcec5616 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.h @@ -193,7 +193,7 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev, unsigned size, unsigned align); void amdgpu_sa_bo_free(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo, - struct amdgpu_fence *fence); + struct fence *fence); #if defined(CONFIG_DEBUG_FS) void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager, struct seq_file *m); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index 4597899e9758d..b7cbaa9d532e4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -139,6 +139,20 @@ int amdgpu_sa_bo_manager_suspend(struct amdgpu_device *adev, return r; } +static uint32_t amdgpu_sa_get_ring_from_fence(struct fence *f) +{ + struct amdgpu_fence *a_fence; + struct amd_sched_fence *s_fence; + + s_fence = to_amd_sched_fence(f); + if (s_fence) + return s_fence->entity->scheduler->ring_id; + a_fence = to_amdgpu_fence(f); + if (a_fence) + return a_fence->ring->idx; + return 0; +} + static void amdgpu_sa_bo_remove_locked(struct amdgpu_sa_bo *sa_bo) { struct amdgpu_sa_manager *sa_manager = sa_bo->manager; @@ -147,7 +161,7 @@ static void amdgpu_sa_bo_remove_locked(struct amdgpu_sa_bo *sa_bo) } list_del_init(&sa_bo->olist); list_del_init(&sa_bo->flist); - amdgpu_fence_unref(&sa_bo->fence); + fence_put(sa_bo->fence); kfree(sa_bo); } @@ -161,7 +175,7 @@ static void amdgpu_sa_bo_try_free(struct amdgpu_sa_manager *sa_manager) sa_bo = list_entry(sa_manager->hole->next, struct amdgpu_sa_bo, olist); list_for_each_entry_safe_from(sa_bo, tmp, &sa_manager->olist, olist) { if (sa_bo->fence == NULL || - !fence_is_signaled(&sa_bo->fence->base)) { + !fence_is_signaled(sa_bo->fence)) { return; } amdgpu_sa_bo_remove_locked(sa_bo); @@ -246,7 +260,7 @@ static bool amdgpu_sa_event(struct amdgpu_sa_manager *sa_manager, } static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager, - struct amdgpu_fence **fences, + struct fence **fences, unsigned *tries) { struct amdgpu_sa_bo *best_bo = NULL; @@ -275,7 +289,7 @@ static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager, sa_bo = list_first_entry(&sa_manager->flist[i], struct amdgpu_sa_bo, flist); - if (!fence_is_signaled(&sa_bo->fence->base)) { + if (!fence_is_signaled(sa_bo->fence)) { fences[i] = sa_bo->fence; continue; } @@ -299,7 +313,8 @@ static bool amdgpu_sa_bo_next_hole(struct amdgpu_sa_manager *sa_manager, } if (best_bo) { - ++tries[best_bo->fence->ring->idx]; + uint32_t idx = amdgpu_sa_get_ring_from_fence(best_bo->fence); + ++tries[idx]; sa_manager->hole = best_bo->olist.prev; /* we knew that this one is signaled, @@ -315,7 +330,7 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo, unsigned size, unsigned align) { - struct amdgpu_fence *fences[AMDGPU_MAX_RINGS]; + struct fence *fences[AMDGPU_MAX_RINGS]; unsigned tries[AMDGPU_MAX_RINGS]; int i, r; signed long t; @@ -373,7 +388,7 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev, } void amdgpu_sa_bo_free(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo, - struct amdgpu_fence *fence) + struct fence *fence) { struct amdgpu_sa_manager *sa_manager; @@ -383,10 +398,11 @@ void amdgpu_sa_bo_free(struct amdgpu_device *adev, struct amdgpu_sa_bo **sa_bo, sa_manager = (*sa_bo)->manager; spin_lock(&sa_manager->wq.lock); - if (fence && !fence_is_signaled(&fence->base)) { - (*sa_bo)->fence = amdgpu_fence_ref(fence); - list_add_tail(&(*sa_bo)->flist, - &sa_manager->flist[fence->ring->idx]); + if (fence && !fence_is_signaled(fence)) { + uint32_t idx; + (*sa_bo)->fence = fence_get(fence); + idx = amdgpu_sa_get_ring_from_fence(fence); + list_add_tail(&(*sa_bo)->flist, &sa_manager->flist[idx]); } else { amdgpu_sa_bo_remove_locked(*sa_bo); } @@ -413,8 +429,16 @@ void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager, seq_printf(m, "[0x%010llx 0x%010llx] size %8lld", soffset, eoffset, eoffset - soffset); if (i->fence) { - seq_printf(m, " protected by 0x%016llx on ring %d", - i->fence->seq, i->fence->ring->idx); + struct amdgpu_fence *a_fence = to_amdgpu_fence(i->fence); + struct amd_sched_fence *s_fence = to_amd_sched_fence(i->fence); + if (a_fence) + seq_printf(m, " protected by 0x%016llx on ring %d", + a_fence->seq, a_fence->ring->idx); + if (s_fence) + seq_printf(m, " protected by 0x%016llx on ring %d", + s_fence->v_seq, + s_fence->entity->scheduler->ring_id); + } seq_printf(m, "\n"); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c index d6d41a42ab654..ff3ca52ec6fe5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_semaphore.c @@ -87,7 +87,7 @@ bool amdgpu_semaphore_emit_wait(struct amdgpu_ring *ring, void amdgpu_semaphore_free(struct amdgpu_device *adev, struct amdgpu_semaphore **semaphore, - struct amdgpu_fence *fence) + struct fence *fence) { if (semaphore == NULL || *semaphore == NULL) { return; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 7cb711fc1ee29..ee68eebfded10 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -234,7 +234,7 @@ int amdgpu_sync_rings(struct amdgpu_sync *sync, */ void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync, - struct amdgpu_fence *fence) + struct fence *fence) { unsigned i; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dd3415d2e45dc..d7c02e1a309e2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1042,7 +1042,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, } amdgpu_ring_unlock_commit(ring); - amdgpu_sync_free(adev, &sync, *fence); + amdgpu_sync_free(adev, &sync, &(*fence)->base); return 0; } -- GitLab From ce882e6dc241ab8dded0eeeb33a86482d44a5689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 19 Aug 2015 15:00:55 +0200 Subject: [PATCH 4786/7006] drm/amdgpu: remove v_seq handling from the scheduler v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simply not used any more. Only keep 32bit atomic for fence sequence numbering. v2: trivial rebase Signed-off-by: Christian König Reviewed-by: Alex Deucher (v1) Reviewed-by: Jammy Zhou (v1) Reviewed-by: Chunming Zhou (v1) --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 ++---- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 20 +++++-------------- drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 6 +----- drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 1 - drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 19 +----------------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 7 +------ drivers/gpu/drm/amd/scheduler/sched_fence.c | 13 +++++++----- 9 files changed, 21 insertions(+), 57 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 80f2ceaf6af64..65e0e9406abb0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1047,7 +1047,7 @@ int amdgpu_ctx_put(struct amdgpu_ctx *ctx); struct amdgpu_ctx *amdgpu_ctx_get_ref(struct amdgpu_ctx *ctx); uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring, - struct fence *fence, uint64_t queued_seq); + struct fence *fence); struct fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring, uint64_t seq); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index dc8d2829c1e94..f91849b12a0f6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -866,11 +866,9 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) kfree(job); goto out; } - job->ibs[parser->num_ibs - 1].sequence = + cs->out.handle = amdgpu_ctx_add_fence(job->ctx, ring, - &job->base.s_fence->base, - job->base.s_fence->v_seq); - cs->out.handle = job->base.s_fence->v_seq; + &job->base.s_fence->base); list_sort(NULL, &parser->validated, cmp_size_smaller_first); ttm_eu_fence_buffer_objects(&parser->ticket, &parser->validated, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index 8660c0854a1ea..f024effa60f9b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -236,17 +236,13 @@ int amdgpu_ctx_put(struct amdgpu_ctx *ctx) } uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring, - struct fence *fence, uint64_t queued_seq) + struct fence *fence) { struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx]; - uint64_t seq = 0; + uint64_t seq = cring->sequence; unsigned idx = 0; struct fence *other = NULL; - if (amdgpu_enable_scheduler) - seq = queued_seq; - else - seq = cring->sequence; idx = seq % AMDGPU_CTX_MAX_CS_PENDING; other = cring->fences[idx]; if (other) { @@ -260,8 +256,7 @@ uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring, spin_lock(&ctx->ring_lock); cring->fences[idx] = fence; - if (!amdgpu_enable_scheduler) - cring->sequence++; + cring->sequence++; spin_unlock(&ctx->ring_lock); fence_put(other); @@ -274,21 +269,16 @@ struct fence *amdgpu_ctx_get_fence(struct amdgpu_ctx *ctx, { struct amdgpu_ctx_ring *cring = & ctx->rings[ring->idx]; struct fence *fence; - uint64_t queued_seq; spin_lock(&ctx->ring_lock); - if (amdgpu_enable_scheduler) - queued_seq = amd_sched_next_queued_seq(&cring->entity); - else - queued_seq = cring->sequence; - if (seq >= queued_seq) { + if (seq >= cring->sequence) { spin_unlock(&ctx->ring_lock); return ERR_PTR(-EINVAL); } - if (seq + AMDGPU_CTX_MAX_CS_PENDING < queued_seq) { + if (seq + AMDGPU_CTX_MAX_CS_PENDING < cring->sequence) { spin_unlock(&ctx->ring_lock); return NULL; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 13c5978ac69b9..737c8e3e3a74d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -126,7 +126,6 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs, struct amdgpu_ring *ring; struct amdgpu_ctx *ctx, *old_ctx; struct amdgpu_vm *vm; - uint64_t sequence; unsigned i; int r = 0; @@ -199,12 +198,9 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs, return r; } - sequence = amdgpu_enable_scheduler ? ib->sequence : 0; - if (!amdgpu_enable_scheduler && ib->ctx) ib->sequence = amdgpu_ctx_add_fence(ib->ctx, ring, - &ib->fence->base, - sequence); + &ib->fence->base); /* wrap the last IB with fence */ if (ib->user) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index b7cbaa9d532e4..26b17939c9c95 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -435,8 +435,8 @@ void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager, seq_printf(m, " protected by 0x%016llx on ring %d", a_fence->seq, a_fence->ring->idx); if (s_fence) - seq_printf(m, " protected by 0x%016llx on ring %d", - s_fence->v_seq, + seq_printf(m, " protected by 0x%016x on ring %d", + s_fence->base.seqno, s_fence->entity->scheduler->ring_id); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 06d7bf51db9a0..964b54381febc 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -111,7 +111,6 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev, kfree(job); return r; } - ibs[num_ibs - 1].sequence = job->base.s_fence->v_seq; *f = fence_get(&job->base.s_fence->base); mutex_unlock(&job->job_lock); } else { diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 1125aa2e2a9a2..f8d46b0b4e3b8 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -156,14 +156,12 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_rq *rq, uint32_t jobs) { - uint64_t seq_ring = 0; char name[20]; if (!(sched && entity && rq)) return -EINVAL; memset(entity, 0, sizeof(struct amd_sched_entity)); - seq_ring = ((uint64_t)sched->ring_id) << 60; spin_lock_init(&entity->lock); entity->belongto_rq = rq; entity->scheduler = sched; @@ -179,8 +177,7 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, return -EINVAL; spin_lock_init(&entity->queue_lock); - atomic64_set(&entity->last_queued_v_seq, seq_ring); - atomic64_set(&entity->last_signaled_v_seq, seq_ring); + atomic_set(&entity->fence_seq, 0); /* Add the entity to the run queue */ amd_sched_rq_add_entity(rq, entity); @@ -299,8 +296,6 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) unsigned long flags; sched = sched_job->sched; - atomic64_set(&sched_job->s_entity->last_signaled_v_seq, - sched_job->s_fence->v_seq); amd_sched_fence_signal(sched_job->s_fence); spin_lock_irqsave(&sched->queue_lock, flags); list_del(&sched_job->list); @@ -421,15 +416,3 @@ int amd_sched_destroy(struct amd_gpu_scheduler *sched) kfree(sched); return 0; } - -/** - * Get next queued sequence number - * - * @entity The context entity - * - * return the next queued sequence number -*/ -uint64_t amd_sched_next_queued_seq(struct amd_sched_entity *c_entity) -{ - return atomic64_read(&c_entity->last_queued_v_seq) + 1; -} diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 6597d61266e7e..d328e968beb37 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -42,9 +42,7 @@ struct amd_sched_entity { struct list_head list; struct amd_sched_rq *belongto_rq; spinlock_t lock; - /* the virtual_seq is unique per context per ring */ - atomic64_t last_queued_v_seq; - atomic64_t last_signaled_v_seq; + atomic_t fence_seq; /* the job_queue maintains the jobs submitted by clients */ struct kfifo job_queue; spinlock_t queue_lock; @@ -72,7 +70,6 @@ struct amd_sched_fence { struct fence base; struct fence_cb cb; struct amd_sched_entity *entity; - uint64_t v_seq; spinlock_t lock; }; @@ -148,8 +145,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity); -uint64_t amd_sched_next_queued_seq(struct amd_sched_entity *c_entity); - struct amd_sched_fence *amd_sched_fence_create( struct amd_sched_entity *s_entity); void amd_sched_fence_signal(struct amd_sched_fence *fence); diff --git a/drivers/gpu/drm/amd/scheduler/sched_fence.c b/drivers/gpu/drm/amd/scheduler/sched_fence.c index a4751598c0b48..266ed7bbbc74f 100644 --- a/drivers/gpu/drm/amd/scheduler/sched_fence.c +++ b/drivers/gpu/drm/amd/scheduler/sched_fence.c @@ -30,16 +30,19 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity) { struct amd_sched_fence *fence = NULL; + unsigned seq; + fence = kzalloc(sizeof(struct amd_sched_fence), GFP_KERNEL); if (fence == NULL) return NULL; - fence->v_seq = atomic64_inc_return(&s_entity->last_queued_v_seq); + fence->entity = s_entity; spin_lock_init(&fence->lock); - fence_init(&fence->base, &amd_sched_fence_ops, - &fence->lock, - s_entity->fence_context, - fence->v_seq); + + seq = atomic_inc_return(&s_entity->fence_seq); + fence_init(&fence->base, &amd_sched_fence_ops, &fence->lock, + s_entity->fence_context, seq); + return fence; } -- GitLab From c746ba222363d2e0b0316b1c0bda21e2646b66f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 19 Aug 2015 16:12:15 +0200 Subject: [PATCH 4787/7006] drm/amdgpu: rework scheduler submission handling. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove active_hw_rq and it's protecting queue_lock, they are unused. User 32bit atomic for hw_rq_count, 64bits for counting to three is a bit overkill. Cleanup the function name and remove incorrect comments. Signed-off-by: Christian König Reviewed-by: Alex Deucher Reviewed-by: Jammy Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 43 +++++-------------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 5 +-- 2 files changed, 11 insertions(+), 37 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index f8d46b0b4e3b8..981420ea1cb5f 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -94,25 +94,12 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) } /** - * Note: This function should only been called inside scheduler main - * function for thread safety, there is no other protection here. - * return ture if scheduler has something ready to run. - * - * For active_hw_rq, there is only one producer(scheduler thread) and - * one consumer(ISR). It should be safe to use this function in scheduler - * main thread to decide whether to continue emit more IBs. -*/ -static bool is_scheduler_ready(struct amd_gpu_scheduler *sched) + * Return ture if we can push more jobs to the hw. + */ +static bool amd_sched_ready(struct amd_gpu_scheduler *sched) { - unsigned long flags; - bool full; - - spin_lock_irqsave(&sched->queue_lock, flags); - full = atomic64_read(&sched->hw_rq_count) < - sched->hw_submission_limit ? true : false; - spin_unlock_irqrestore(&sched->queue_lock, flags); - - return full; + return atomic_read(&sched->hw_rq_count) < + sched->hw_submission_limit; } /** @@ -124,7 +111,7 @@ select_context(struct amd_gpu_scheduler *sched) struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; - if (!is_scheduler_ready(sched)) + if (!amd_sched_ready(sched)) return NULL; /* Kernel run queue has higher priority than normal run queue*/ @@ -293,14 +280,10 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) struct amd_sched_job *sched_job = container_of(cb, struct amd_sched_job, cb); struct amd_gpu_scheduler *sched; - unsigned long flags; sched = sched_job->sched; amd_sched_fence_signal(sched_job->s_fence); - spin_lock_irqsave(&sched->queue_lock, flags); - list_del(&sched_job->list); - atomic64_dec(&sched->hw_rq_count); - spin_unlock_irqrestore(&sched->queue_lock, flags); + atomic_dec(&sched->hw_rq_count); fence_put(&sched_job->s_fence->base); sched->ops->process_job(sched, sched_job); wake_up_interruptible(&sched->wait_queue); @@ -320,7 +303,7 @@ static int amd_sched_main(void *param) struct fence *fence; wait_event_interruptible(sched->wait_queue, - is_scheduler_ready(sched) && + amd_sched_ready(sched) && (c_entity = select_context(sched))); r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) @@ -329,11 +312,7 @@ static int amd_sched_main(void *param) if (sched->ops->prepare_job) r = sched->ops->prepare_job(sched, c_entity, job); if (!r) { - unsigned long flags; - spin_lock_irqsave(&sched->queue_lock, flags); - list_add_tail(&job->list, &sched->active_hw_rq); - atomic64_inc(&sched->hw_rq_count); - spin_unlock_irqrestore(&sched->queue_lock, flags); + atomic_inc(&sched->hw_rq_count); } mutex_lock(&sched->sched_lock); fence = sched->ops->run_job(sched, c_entity, job); @@ -384,13 +363,11 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, sched->hw_submission_limit = hw_submission; snprintf(name, sizeof(name), "gpu_sched[%d]", ring); mutex_init(&sched->sched_lock); - spin_lock_init(&sched->queue_lock); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); init_waitqueue_head(&sched->wait_queue); - INIT_LIST_HEAD(&sched->active_hw_rq); - atomic64_set(&sched->hw_rq_count, 0); + atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ sched->thread = kthread_create(amd_sched_main, sched, name); if (sched->thread) { diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index d328e968beb37..81c00daa23fb2 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -74,7 +74,6 @@ struct amd_sched_fence { }; struct amd_sched_job { - struct list_head list; struct fence_cb cb; struct amd_gpu_scheduler *sched; struct amd_sched_entity *s_entity; @@ -115,8 +114,7 @@ struct amd_gpu_scheduler { struct task_struct *thread; struct amd_sched_rq sched_rq; struct amd_sched_rq kernel_rq; - struct list_head active_hw_rq; - atomic64_t hw_rq_count; + atomic_t hw_rq_count; struct amd_sched_backend_ops *ops; uint32_t ring_id; uint32_t granularity; /* in ms unit */ @@ -124,7 +122,6 @@ struct amd_gpu_scheduler { wait_queue_head_t wait_queue; struct amd_sched_entity *current_entity; struct mutex sched_lock; - spinlock_t queue_lock; uint32_t hw_submission_limit; }; -- GitLab From f91b3a69418120974c9a416939b903ec86607c52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 14:47:40 +0800 Subject: [PATCH 4788/7006] drm/amdgpu: fix fence wait in sync_fence, instead should be in sync_rings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 + drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 6 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 56 +++++++++++++++++++++++- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 65e0e9406abb0..3c5487257ef0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -704,6 +704,7 @@ void amdgpu_semaphore_free(struct amdgpu_device *adev, struct amdgpu_sync { struct amdgpu_semaphore *semaphores[AMDGPU_NUM_SYNCS]; struct amdgpu_fence *sync_to[AMDGPU_MAX_RINGS]; + DECLARE_HASHTABLE(fences, 4); struct amdgpu_fence *last_vm_update; }; @@ -716,6 +717,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, void *owner); int amdgpu_sync_rings(struct amdgpu_sync *sync, struct amdgpu_ring *ring); +int amdgpu_sync_wait(struct amdgpu_sync *sync); void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct fence *fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c index 737c8e3e3a74d..c439735ee670d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c @@ -140,7 +140,11 @@ int amdgpu_ib_schedule(struct amdgpu_device *adev, unsigned num_ibs, dev_err(adev->dev, "couldn't schedule ib\n"); return -EINVAL; } - + r = amdgpu_sync_wait(&ibs->sync); + if (r) { + dev_err(adev->dev, "IB sync failed (%d).\n", r); + return r; + } r = amdgpu_ring_lock(ring, (256 + AMDGPU_NUM_SYNCS * 8) * num_ibs); if (r) { dev_err(adev->dev, "scheduling IB failed (%d).\n", r); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index ee68eebfded10..febbf37b1412e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -32,6 +32,11 @@ #include "amdgpu.h" #include "amdgpu_trace.h" +struct amdgpu_sync_entry { + struct hlist_node node; + struct fence *fence; +}; + /** * amdgpu_sync_create - zero init sync object * @@ -49,6 +54,7 @@ void amdgpu_sync_create(struct amdgpu_sync *sync) for (i = 0; i < AMDGPU_MAX_RINGS; ++i) sync->sync_to[i] = NULL; + hash_init(sync->fences); sync->last_vm_update = NULL; } @@ -62,6 +68,7 @@ void amdgpu_sync_create(struct amdgpu_sync *sync) int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct fence *f) { + struct amdgpu_sync_entry *e; struct amdgpu_fence *fence; struct amdgpu_fence *other; @@ -69,8 +76,27 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, return 0; fence = to_amdgpu_fence(f); - if (!fence || fence->ring->adev != adev) - return fence_wait(f, true); + if (!fence || fence->ring->adev != adev) { + hash_for_each_possible(sync->fences, e, node, f->context) { + struct fence *new; + if (unlikely(e->fence->context != f->context)) + continue; + new = fence_get(fence_later(e->fence, f)); + if (new) { + fence_put(e->fence); + e->fence = new; + } + return 0; + } + + e = kmalloc(sizeof(struct amdgpu_sync_entry), GFP_KERNEL); + if (!e) + return -ENOMEM; + + hash_add(sync->fences, &e->node, f->context); + e->fence = fence_get(f); + return 0; + } other = sync->sync_to[fence->ring->idx]; sync->sync_to[fence->ring->idx] = amdgpu_fence_ref( @@ -147,6 +173,24 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, return r; } +int amdgpu_sync_wait(struct amdgpu_sync *sync) +{ + struct amdgpu_sync_entry *e; + struct hlist_node *tmp; + int i, r; + + hash_for_each_safe(sync->fences, i, tmp, e, node) { + r = fence_wait(e->fence, false); + if (r) + return r; + + hash_del(&e->node); + fence_put(e->fence); + kfree(e); + } + return 0; +} + /** * amdgpu_sync_rings - sync ring to all registered fences * @@ -236,8 +280,16 @@ void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct fence *fence) { + struct amdgpu_sync_entry *e; + struct hlist_node *tmp; unsigned i; + hash_for_each_safe(sync->fences, i, tmp, e, node) { + hash_del(&e->node); + fence_put(e->fence); + kfree(e); + } + for (i = 0; i < AMDGPU_NUM_SYNCS; ++i) amdgpu_semaphore_free(adev, &sync->semaphores[i], fence); -- GitLab From eb98d1c54d1e058f406f3f4acf15684ad26f9676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:28:36 +0200 Subject: [PATCH 4789/7006] drm/amdgpu: fix user fences when scheduler is enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index f91849b12a0f6..5d335522625ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -869,6 +869,8 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) cs->out.handle = amdgpu_ctx_add_fence(job->ctx, ring, &job->base.s_fence->base); + parser->ibs[parser->num_ibs - 1].sequence = cs->out.handle; + list_sort(NULL, &parser->validated, cmp_size_smaller_first); ttm_eu_fence_buffer_objects(&parser->ticket, &parser->validated, -- GitLab From 9788ec40322ef40d64f6d4276248f40666dc4505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 19 Aug 2015 17:34:20 +0200 Subject: [PATCH 4790/7006] drm/amdgpu: remove some more unused entity members v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit None of them are used any more. v2: fix type in error message Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 11 +++-------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 3 --- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 981420ea1cb5f..599318d3df0d2 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -149,11 +149,9 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, return -EINVAL; memset(entity, 0, sizeof(struct amd_sched_entity)); - spin_lock_init(&entity->lock); entity->belongto_rq = rq; entity->scheduler = sched; init_waitqueue_head(&entity->wait_queue); - init_waitqueue_head(&entity->wait_emit); entity->fence_context = fence_context_alloc(1); snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context); memcpy(entity->name, name, 20); @@ -228,12 +226,9 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS) ) ? 0 : -1; - if (r) { - if (entity->is_pending) - DRM_INFO("Entity %p is in waiting state during fini,\ - all pending ibs will be canceled.\n", - entity); - } + if (r) + DRM_INFO("Entity %p is in waiting state during fini\n", + entity); amd_sched_rq_remove_entity(rq, entity); kfifo_free(&entity->job_queue); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 81c00daa23fb2..bbfcc3770393e 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -41,15 +41,12 @@ struct amd_sched_rq; struct amd_sched_entity { struct list_head list; struct amd_sched_rq *belongto_rq; - spinlock_t lock; atomic_t fence_seq; /* the job_queue maintains the jobs submitted by clients */ struct kfifo job_queue; spinlock_t queue_lock; struct amd_gpu_scheduler *scheduler; wait_queue_head_t wait_queue; - wait_queue_head_t wait_emit; - bool is_pending; uint64_t fence_context; char name[20]; bool need_wakeup; -- GitLab From f85a6dd9ebd1bcaeb2f31cca71537e62606a23c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 19 Aug 2015 17:37:52 +0200 Subject: [PATCH 4791/7006] drm/amdgpu: cleanup entity picking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleanup function name, stop checking scheduler ready twice, but check if kernel thread should stop instead. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 599318d3df0d2..2dd9c8aceba54 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -106,7 +106,7 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) * Select next entity containing real IB submissions */ static struct amd_sched_entity * -select_context(struct amd_gpu_scheduler *sched) +amd_sched_select_context(struct amd_gpu_scheduler *sched) { struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; @@ -286,20 +286,24 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) static int amd_sched_main(void *param) { - int r; - struct amd_sched_job *job; struct sched_param sparam = {.sched_priority = 1}; - struct amd_sched_entity *c_entity = NULL; struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param; + int r; sched_setscheduler(current, SCHED_FIFO, &sparam); while (!kthread_should_stop()) { + struct amd_sched_entity *c_entity = NULL; + struct amd_sched_job *job; struct fence *fence; wait_event_interruptible(sched->wait_queue, - amd_sched_ready(sched) && - (c_entity = select_context(sched))); + kthread_should_stop() || + (c_entity = amd_sched_select_context(sched))); + + if (!c_entity) + continue; + r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) continue; -- GitLab From aef4852eed2841892796fb1e9abd7f8468384e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 14:47:46 +0200 Subject: [PATCH 4792/7006] drm/amdgpu: fix entity wakeup race condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That actually didn't worked at all. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 43 +++++++++---------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 1 - 2 files changed, 21 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2dd9c8aceba54..0133697c127eb 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -108,7 +108,6 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) static struct amd_sched_entity * amd_sched_select_context(struct amd_gpu_scheduler *sched) { - struct amd_sched_entity *wake_entity = NULL; struct amd_sched_entity *tmp; if (!amd_sched_ready(sched)) @@ -119,11 +118,6 @@ amd_sched_select_context(struct amd_gpu_scheduler *sched) if (tmp == NULL) tmp = amd_sched_rq_select_entity(&sched->sched_rq); - if (sched->current_entity && (sched->current_entity != tmp)) - wake_entity = sched->current_entity; - sched->current_entity = tmp; - if (wake_entity && wake_entity->need_wakeup) - wake_up(&wake_entity->wait_queue); return tmp; } @@ -184,16 +178,17 @@ static bool is_context_entity_initialized(struct amd_gpu_scheduler *sched, entity->belongto_rq != NULL; } -static bool is_context_entity_idle(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity) +/** + * Check if entity is idle + * + * @entity The pointer to a valid scheduler entity + * + * Return true if entity don't has any unscheduled jobs. + */ +static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity) { - /** - * Idle means no pending IBs, and the entity is not - * currently being used. - */ - barrier(); - if ((sched->current_entity != entity) && - kfifo_is_empty(&entity->job_queue)) + rmb(); + if (kfifo_is_empty(&entity->job_queue)) return true; return false; @@ -210,8 +205,8 @@ static bool is_context_entity_idle(struct amd_gpu_scheduler *sched, int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity) { - int r = 0; struct amd_sched_rq *rq = entity->belongto_rq; + long r; if (!is_context_entity_initialized(sched, entity)) return 0; @@ -220,13 +215,11 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, * The client will not queue more IBs during this fini, consume existing * queued IBs */ - r = wait_event_timeout( - entity->wait_queue, - is_context_entity_idle(sched, entity), - msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS) - ) ? 0 : -1; + r = wait_event_timeout(entity->wait_queue, + amd_sched_entity_is_idle(entity), + msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS)); - if (r) + if (r <= 0) DRM_INFO("Entity %p is in waiting state during fini\n", entity); @@ -325,6 +318,12 @@ static int amd_sched_main(void *param) fence_put(fence); } mutex_unlock(&sched->sched_lock); + + if (c_entity->need_wakeup) { + c_entity->need_wakeup = false; + wake_up(&c_entity->wait_queue); + } + } return 0; } diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index bbfcc3770393e..d4116bb47a1b8 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -117,7 +117,6 @@ struct amd_gpu_scheduler { uint32_t granularity; /* in ms unit */ uint32_t preemption; wait_queue_head_t wait_queue; - struct amd_sched_entity *current_entity; struct mutex sched_lock; uint32_t hw_submission_limit; }; -- GitLab From f49565982194d601f4f3a99892d0f3c765aec104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 16:59:38 +0200 Subject: [PATCH 4793/7006] drm/amdgpu: fix scheduler thread creation error checking MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 0133697c127eb..435d70499d3e9 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -367,15 +367,14 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, init_waitqueue_head(&sched->wait_queue); atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ - sched->thread = kthread_create(amd_sched_main, sched, name); - if (sched->thread) { - wake_up_process(sched->thread); - return sched; + sched->thread = kthread_run(amd_sched_main, sched, name); + if (IS_ERR(sched->thread)) { + DRM_ERROR("Failed to create scheduler for id %d.\n", ring); + kfree(sched); + return NULL; } - DRM_ERROR("Failed to create scheduler for id %d.\n", ring); - kfree(sched); - return NULL; + return sched; } /** -- GitLab From e688b728228b951f41175e3a7c0738708d045969 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:01:01 +0200 Subject: [PATCH 4794/7006] drm/amdgpu: reorder scheduler functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep run queue, entity and scheduler handling together. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 435d70499d3e9..5fb189ca7fbe6 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -93,34 +93,6 @@ amd_sched_rq_select_entity(struct amd_sched_rq *rq) return NULL; } -/** - * Return ture if we can push more jobs to the hw. - */ -static bool amd_sched_ready(struct amd_gpu_scheduler *sched) -{ - return atomic_read(&sched->hw_rq_count) < - sched->hw_submission_limit; -} - -/** - * Select next entity containing real IB submissions -*/ -static struct amd_sched_entity * -amd_sched_select_context(struct amd_gpu_scheduler *sched) -{ - struct amd_sched_entity *tmp; - - if (!amd_sched_ready(sched)) - return NULL; - - /* Kernel run queue has higher priority than normal run queue*/ - tmp = amd_sched_rq_select_entity(&sched->kernel_rq); - if (tmp == NULL) - tmp = amd_sched_rq_select_entity(&sched->sched_rq); - - return tmp; -} - /** * Init a context entity used by scheduler when submit to HW ring. * @@ -263,6 +235,34 @@ int amd_sched_push_job(struct amd_sched_job *sched_job) return 0; } +/** + * Return ture if we can push more jobs to the hw. + */ +static bool amd_sched_ready(struct amd_gpu_scheduler *sched) +{ + return atomic_read(&sched->hw_rq_count) < + sched->hw_submission_limit; +} + +/** + * Select next entity containing real IB submissions +*/ +static struct amd_sched_entity * +amd_sched_select_context(struct amd_gpu_scheduler *sched) +{ + struct amd_sched_entity *tmp; + + if (!amd_sched_ready(sched)) + return NULL; + + /* Kernel run queue has higher priority than normal run queue*/ + tmp = amd_sched_rq_select_entity(&sched->kernel_rq); + if (tmp == NULL) + tmp = amd_sched_rq_select_entity(&sched->sched_rq); + + return tmp; +} + static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) { struct amd_sched_job *sched_job = -- GitLab From d54fdb94b2fd4c989d498f69e8bbf4189fde42ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:03:48 +0200 Subject: [PATCH 4795/7006] drm/amdgpu: cleanup a scheduler function name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 5fb189ca7fbe6..37badd6292cb1 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -143,8 +143,8 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, * * return true if entity is initialized, false otherwise */ -static bool is_context_entity_initialized(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity) +static bool amd_sched_entity_is_initialized(struct amd_gpu_scheduler *sched, + struct amd_sched_entity *entity) { return entity->scheduler == sched && entity->belongto_rq != NULL; @@ -180,7 +180,7 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_rq *rq = entity->belongto_rq; long r; - if (!is_context_entity_initialized(sched, entity)) + if (!amd_sched_entity_is_initialized(sched, entity)) return 0; entity->need_wakeup = true; /** -- GitLab From b034b572f2823122d56cd0d235158873f84c7c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:08:25 +0200 Subject: [PATCH 4796/7006] drm/amdgpu: remove prepare_job callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not used any more. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 8 ++------ drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 3 --- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 37badd6292cb1..2ab63d2238911 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -300,12 +300,8 @@ static int amd_sched_main(void *param) r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); if (r != sizeof(void *)) continue; - r = 0; - if (sched->ops->prepare_job) - r = sched->ops->prepare_job(sched, c_entity, job); - if (!r) { - atomic_inc(&sched->hw_rq_count); - } + atomic_inc(&sched->hw_rq_count); + mutex_lock(&sched->sched_lock); fence = sched->ops->run_job(sched, c_entity, job); if (fence) { diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index d4116bb47a1b8..5913c5cd1c485 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -93,9 +93,6 @@ static inline struct amd_sched_fence *to_amd_sched_fence(struct fence *f) * these functions should be implemented in driver side */ struct amd_sched_backend_ops { - int (*prepare_job)(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *c_entity, - struct amd_sched_job *job); struct fence *(*run_job)(struct amd_gpu_scheduler *sched, struct amd_sched_entity *c_entity, struct amd_sched_job *job); -- GitLab From 1fca766b24d07e2daed1da0f224f5f395c73e32b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:09:54 +0200 Subject: [PATCH 4797/7006] drm/amdgpu: remove sched_lock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It isn't protecting anything. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 3 --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 1 - 2 files changed, 4 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2ab63d2238911..b13642f1e00b8 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -302,7 +302,6 @@ static int amd_sched_main(void *param) continue; atomic_inc(&sched->hw_rq_count); - mutex_lock(&sched->sched_lock); fence = sched->ops->run_job(sched, c_entity, job); if (fence) { r = fence_add_callback(fence, &job->cb, @@ -313,7 +312,6 @@ static int amd_sched_main(void *param) DRM_ERROR("fence add callback failed (%d)\n", r); fence_put(fence); } - mutex_unlock(&sched->sched_lock); if (c_entity->need_wakeup) { c_entity->need_wakeup = false; @@ -356,7 +354,6 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, sched->preemption = preemption; sched->hw_submission_limit = hw_submission; snprintf(name, sizeof(name), "gpu_sched[%d]", ring); - mutex_init(&sched->sched_lock); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 5913c5cd1c485..123b8f15d3fbc 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -114,7 +114,6 @@ struct amd_gpu_scheduler { uint32_t granularity; /* in ms unit */ uint32_t preemption; wait_queue_head_t wait_queue; - struct mutex sched_lock; uint32_t hw_submission_limit; }; -- GitLab From 69f7dd652c08bffb267f418ded7b358e74783045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:24:40 +0200 Subject: [PATCH 4798/7006] drm/amdgpu: remove unused parameters to amd_sched_create MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 5 ++--- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 21 ++++++------------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 12 +++-------- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 9a87372c3c792..e13e4452a349c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -626,9 +626,8 @@ void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) ring->fence_drv.ring = ring; if (amdgpu_enable_scheduler) { - ring->scheduler = amd_sched_create((void *)ring->adev, - &amdgpu_sched_ops, - ring->idx, 5, 0, + ring->scheduler = amd_sched_create(&amdgpu_sched_ops, + ring->idx, amdgpu_sched_hw_submission); if (!ring->scheduler) DRM_ERROR("Failed to create scheduler on ring %d.\n", diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index b13642f1e00b8..acae85572399b 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -325,20 +325,14 @@ static int amd_sched_main(void *param) /** * Create a gpu scheduler * - * @device The device context for this scheduler - * @ops The backend operations for this scheduler. - * @id The scheduler is per ring, here is ring id. - * @granularity The minumum ms unit the scheduler will scheduled. - * @preemption Indicate whether this ring support preemption, 0 is no. + * @ops The backend operations for this scheduler. + * @ring The the ring id for the scheduler. + * @hw_submissions Number of hw submissions to do. * - * return the pointer to scheduler for success, otherwise return NULL + * Return the pointer to scheduler for success, otherwise return NULL */ -struct amd_gpu_scheduler *amd_sched_create(void *device, - struct amd_sched_backend_ops *ops, - unsigned ring, - unsigned granularity, - unsigned preemption, - unsigned hw_submission) +struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, + unsigned ring, unsigned hw_submission) { struct amd_gpu_scheduler *sched; char name[20]; @@ -347,11 +341,8 @@ struct amd_gpu_scheduler *amd_sched_create(void *device, if (!sched) return NULL; - sched->device = device; sched->ops = ops; - sched->granularity = granularity; sched->ring_id = ring; - sched->preemption = preemption; sched->hw_submission_limit = hw_submission; snprintf(name, sizeof(name), "gpu_sched[%d]", ring); amd_sched_rq_init(&sched->sched_rq); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 123b8f15d3fbc..df365abaa125e 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -104,25 +104,19 @@ struct amd_sched_backend_ops { * One scheduler is implemented for each hardware ring */ struct amd_gpu_scheduler { - void *device; struct task_struct *thread; struct amd_sched_rq sched_rq; struct amd_sched_rq kernel_rq; atomic_t hw_rq_count; struct amd_sched_backend_ops *ops; uint32_t ring_id; - uint32_t granularity; /* in ms unit */ - uint32_t preemption; wait_queue_head_t wait_queue; uint32_t hw_submission_limit; }; -struct amd_gpu_scheduler *amd_sched_create(void *device, - struct amd_sched_backend_ops *ops, - uint32_t ring, - uint32_t granularity, - uint32_t preemption, - uint32_t hw_submission); +struct amd_gpu_scheduler * +amd_sched_create(struct amd_sched_backend_ops *ops, + uint32_t ring, uint32_t hw_submission); int amd_sched_destroy(struct amd_gpu_scheduler *sched); int amd_sched_push_job(struct amd_sched_job *sched_job); -- GitLab From 3a185a33a2d291883bd1d0691d22901c345b12c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:35:34 +0200 Subject: [PATCH 4799/7006] drm/amdgpu: remove the context from amdgpu_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 4 +--- drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 7 ------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 3c5487257ef0f..0088af1efd54a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1046,7 +1046,6 @@ void amdgpu_ctx_fini(struct amdgpu_ctx *ctx); struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id); int amdgpu_ctx_put(struct amdgpu_ctx *ctx); -struct amdgpu_ctx *amdgpu_ctx_get_ref(struct amdgpu_ctx *ctx); uint64_t amdgpu_ctx_add_fence(struct amdgpu_ctx *ctx, struct amdgpu_ring *ring, struct fence *fence); @@ -1267,7 +1266,6 @@ struct amdgpu_cs_parser { struct amdgpu_job { struct amd_sched_job base; struct amdgpu_device *adev; - struct amdgpu_ctx *ctx; struct drm_file *owner; struct amdgpu_ib *ibs; uint32_t num_ibs; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 5d335522625ee..780c0113e8f82 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -775,7 +775,6 @@ static int amdgpu_cs_dependencies(struct amdgpu_device *adev, static int amdgpu_cs_free_job(struct amdgpu_job *sched_job) { int i; - amdgpu_ctx_put(sched_job->ctx); if (sched_job->ibs) for (i = 0; i < sched_job->num_ibs; i++) amdgpu_ib_free(sched_job->adev, &sched_job->ibs[i]); @@ -849,7 +848,6 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) job->ibs = parser->ibs; job->num_ibs = parser->num_ibs; job->owner = parser->filp; - job->ctx = amdgpu_ctx_get_ref(parser->ctx); mutex_init(&job->job_lock); if (job->ibs[job->num_ibs - 1].user) { memcpy(&job->uf, &parser->uf, @@ -867,7 +865,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) goto out; } cs->out.handle = - amdgpu_ctx_add_fence(job->ctx, ring, + amdgpu_ctx_add_fence(parser->ctx, ring, &job->base.s_fence->base); parser->ibs[parser->num_ibs - 1].sequence = cs->out.handle; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c index f024effa60f9b..20cbc4eb5a6f7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c @@ -219,13 +219,6 @@ struct amdgpu_ctx *amdgpu_ctx_get(struct amdgpu_fpriv *fpriv, uint32_t id) return ctx; } -struct amdgpu_ctx *amdgpu_ctx_get_ref(struct amdgpu_ctx *ctx) -{ - if (ctx) - kref_get(&ctx->refcount); - return ctx; -} - int amdgpu_ctx_put(struct amdgpu_ctx *ctx) { if (ctx == NULL) -- GitLab From 87e0a87dabdbe9e1698ef85c620c4110b04992a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 17:36:28 +0200 Subject: [PATCH 4800/7006] drm/amdgpu: remove amdgpu_bo_list_clone MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not used any more. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 2 -- drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c | 33 --------------------- 2 files changed, 35 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 0088af1efd54a..a2d5cf7df56f4 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1083,8 +1083,6 @@ struct amdgpu_bo_list { struct amdgpu_bo_list_entry *array; }; -struct amdgpu_bo_list * -amdgpu_bo_list_clone(struct amdgpu_bo_list *list); struct amdgpu_bo_list * amdgpu_bo_list_get(struct amdgpu_fpriv *fpriv, int id); void amdgpu_bo_list_put(struct amdgpu_bo_list *list); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c index 7eed523bf28f2..f82a2dd83874d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bo_list.c @@ -62,39 +62,6 @@ static int amdgpu_bo_list_create(struct amdgpu_fpriv *fpriv, return 0; } -struct amdgpu_bo_list * -amdgpu_bo_list_clone(struct amdgpu_bo_list *list) -{ - struct amdgpu_bo_list *result; - unsigned i; - - result = kmalloc(sizeof(struct amdgpu_bo_list), GFP_KERNEL); - if (!result) - return NULL; - - result->array = drm_calloc_large(list->num_entries, - sizeof(struct amdgpu_bo_list_entry)); - if (!result->array) { - kfree(result); - return NULL; - } - - mutex_init(&result->lock); - result->gds_obj = list->gds_obj; - result->gws_obj = list->gws_obj; - result->oa_obj = list->oa_obj; - result->has_userptr = list->has_userptr; - result->num_entries = list->num_entries; - - memcpy(result->array, list->array, list->num_entries * - sizeof(struct amdgpu_bo_list_entry)); - - for (i = 0; i < result->num_entries; ++i) - amdgpu_bo_ref(result->array[i].robj); - - return result; -} - static void amdgpu_bo_list_destroy(struct amdgpu_fpriv *fpriv, int id) { struct amdgpu_bo_list *list; -- GitLab From 6c859274f363be9dc13f8849bdc59bb64f922f26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 20 Aug 2015 16:12:50 +0200 Subject: [PATCH 4801/7006] drm/amdgpu: fix and cleanup amd_sched_entity_push_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling schedule() is probably the worse things we can do. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 2 +- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 78 +++++++++++-------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 4 +- 4 files changed, 48 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 780c0113e8f82..82e14321e9c75 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -857,7 +857,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) job->free_job = amdgpu_cs_free_job; mutex_lock(&job->job_lock); - r = amd_sched_push_job((struct amd_sched_job *)job); + r = amd_sched_entity_push_job((struct amd_sched_job *)job); if (r) { mutex_unlock(&job->job_lock); amdgpu_cs_free_job(job); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 964b54381febc..1aa72edbce9a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -105,7 +105,7 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev, mutex_init(&job->job_lock); job->free_job = free_job; mutex_lock(&job->job_lock); - r = amd_sched_push_job((struct amd_sched_job *)job); + r = amd_sched_entity_push_job((struct amd_sched_job *)job); if (r) { mutex_unlock(&job->job_lock); kfree(job); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index acae85572399b..29c45ed7d02f5 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -121,7 +121,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, entity->fence_context = fence_context_alloc(1); snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context); memcpy(entity->name, name, 20); - entity->need_wakeup = false; if(kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL)) @@ -182,7 +181,7 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, if (!amd_sched_entity_is_initialized(sched, entity)) return 0; - entity->need_wakeup = true; + /** * The client will not queue more IBs during this fini, consume existing * queued IBs @@ -201,38 +200,55 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, } /** - * Submit a normal job to the job queue + * Helper to submit a job to the job queue * - * @sched The pointer to the scheduler - * @c_entity The pointer to amd_sched_entity * @job The pointer to job required to submit - * return 0 if succeed. -1 if failed. - * -2 indicate queue is full for this client, client should wait untill - * scheduler consum some queued command. - * -1 other fail. -*/ -int amd_sched_push_job(struct amd_sched_job *sched_job) + * + * Returns true if we could submit the job. + */ +static bool amd_sched_entity_in(struct amd_sched_job *job) +{ + struct amd_sched_entity *entity = job->s_entity; + bool added, first = false; + + spin_lock(&entity->queue_lock); + added = kfifo_in(&entity->job_queue, &job, sizeof(job)) == sizeof(job); + + if (added && kfifo_len(&entity->job_queue) == sizeof(job)) + first = true; + + spin_unlock(&entity->queue_lock); + + /* first job wakes up scheduler */ + if (first) + wake_up_interruptible(&job->sched->wait_queue); + + return added; +} + +/** + * Submit a job to the job queue + * + * @job The pointer to job required to submit + * + * Returns 0 for success, negative error code otherwise. + */ +int amd_sched_entity_push_job(struct amd_sched_job *sched_job) { - struct amd_sched_fence *fence = - amd_sched_fence_create(sched_job->s_entity); + struct amd_sched_entity *entity = sched_job->s_entity; + struct amd_sched_fence *fence = amd_sched_fence_create(entity); + int r; + if (!fence) - return -EINVAL; + return -ENOMEM; + fence_get(&fence->base); sched_job->s_fence = fence; - while (kfifo_in_spinlocked(&sched_job->s_entity->job_queue, - &sched_job, sizeof(void *), - &sched_job->s_entity->queue_lock) != - sizeof(void *)) { - /** - * Current context used up all its IB slots - * wait here, or need to check whether GPU is hung - */ - schedule(); - } - /* first job wake up scheduler */ - if ((kfifo_len(&sched_job->s_entity->job_queue) / sizeof(void *)) == 1) - wake_up_interruptible(&sched_job->sched->wait_queue); - return 0; + + r = wait_event_interruptible(entity->wait_queue, + amd_sched_entity_in(sched_job)); + + return r; } /** @@ -313,11 +329,7 @@ static int amd_sched_main(void *param) fence_put(fence); } - if (c_entity->need_wakeup) { - c_entity->need_wakeup = false; - wake_up(&c_entity->wait_queue); - } - + wake_up(&c_entity->wait_queue); } return 0; } diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index df365abaa125e..46b528d41f7f2 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -49,7 +49,6 @@ struct amd_sched_entity { wait_queue_head_t wait_queue; uint64_t fence_context; char name[20]; - bool need_wakeup; }; /** @@ -119,14 +118,13 @@ amd_sched_create(struct amd_sched_backend_ops *ops, uint32_t ring, uint32_t hw_submission); int amd_sched_destroy(struct amd_gpu_scheduler *sched); -int amd_sched_push_job(struct amd_sched_job *sched_job); - int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity, struct amd_sched_rq *rq, uint32_t jobs); int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity); +int amd_sched_entity_push_job(struct amd_sched_job *sched_job); struct amd_sched_fence *amd_sched_fence_create( struct amd_sched_entity *s_entity); -- GitLab From c14692f0a728a9d79fb03c7ce521eb07ec0e2b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 21 Aug 2015 15:18:47 +0200 Subject: [PATCH 4802/7006] drm/amdgpu: remove entity reference from sched fence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entity don't live as long as scheduler fences. Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 4 ++-- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 9 ++------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 5 ++--- drivers/gpu/drm/amd/scheduler/sched_fence.c | 4 ++-- 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index 26b17939c9c95..b92525329d6ce 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -146,7 +146,7 @@ static uint32_t amdgpu_sa_get_ring_from_fence(struct fence *f) s_fence = to_amd_sched_fence(f); if (s_fence) - return s_fence->entity->scheduler->ring_id; + return s_fence->scheduler->ring_id; a_fence = to_amdgpu_fence(f); if (a_fence) return a_fence->ring->idx; @@ -437,7 +437,7 @@ void amdgpu_sa_bo_dump_debug_info(struct amdgpu_sa_manager *sa_manager, if (s_fence) seq_printf(m, " protected by 0x%016x on ring %d", s_fence->base.seqno, - s_fence->entity->scheduler->ring_id); + s_fence->scheduler->ring_id); } seq_printf(m, "\n"); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 29c45ed7d02f5..d747f82808a71 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -109,8 +109,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_rq *rq, uint32_t jobs) { - char name[20]; - if (!(sched && entity && rq)) return -EINVAL; @@ -119,8 +117,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, entity->scheduler = sched; init_waitqueue_head(&entity->wait_queue); entity->fence_context = fence_context_alloc(1); - snprintf(name, sizeof(name), "c_entity[%llu]", entity->fence_context); - memcpy(entity->name, name, 20); if(kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), GFP_KERNEL)) @@ -347,7 +343,6 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, unsigned ring, unsigned hw_submission) { struct amd_gpu_scheduler *sched; - char name[20]; sched = kzalloc(sizeof(struct amd_gpu_scheduler), GFP_KERNEL); if (!sched) @@ -356,14 +351,14 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, sched->ops = ops; sched->ring_id = ring; sched->hw_submission_limit = hw_submission; - snprintf(name, sizeof(name), "gpu_sched[%d]", ring); + snprintf(sched->name, sizeof(sched->name), "amdgpu[%d]", ring); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); init_waitqueue_head(&sched->wait_queue); atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ - sched->thread = kthread_run(amd_sched_main, sched, name); + sched->thread = kthread_run(amd_sched_main, sched, sched->name); if (IS_ERR(sched->thread)) { DRM_ERROR("Failed to create scheduler for id %d.\n", ring); kfree(sched); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 46b528d41f7f2..62655f4cf11da 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -48,7 +48,6 @@ struct amd_sched_entity { struct amd_gpu_scheduler *scheduler; wait_queue_head_t wait_queue; uint64_t fence_context; - char name[20]; }; /** @@ -64,8 +63,7 @@ struct amd_sched_rq { struct amd_sched_fence { struct fence base; - struct fence_cb cb; - struct amd_sched_entity *entity; + struct amd_gpu_scheduler *scheduler; spinlock_t lock; }; @@ -111,6 +109,7 @@ struct amd_gpu_scheduler { uint32_t ring_id; wait_queue_head_t wait_queue; uint32_t hw_submission_limit; + char name[20]; }; struct amd_gpu_scheduler * diff --git a/drivers/gpu/drm/amd/scheduler/sched_fence.c b/drivers/gpu/drm/amd/scheduler/sched_fence.c index 266ed7bbbc74f..7f0f57819b62c 100644 --- a/drivers/gpu/drm/amd/scheduler/sched_fence.c +++ b/drivers/gpu/drm/amd/scheduler/sched_fence.c @@ -36,7 +36,7 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity if (fence == NULL) return NULL; - fence->entity = s_entity; + fence->scheduler = s_entity->scheduler; spin_lock_init(&fence->lock); seq = atomic_inc_return(&s_entity->fence_seq); @@ -63,7 +63,7 @@ static const char *amd_sched_fence_get_driver_name(struct fence *fence) static const char *amd_sched_fence_get_timeline_name(struct fence *f) { struct amd_sched_fence *fence = to_amd_sched_fence(f); - return (const char *)fence->entity->name; + return (const char *)fence->scheduler->name; } static bool amd_sched_fence_enable_signaling(struct fence *f) -- GitLab From 84f76ea6b03a766931e5d6d650af5ab980c6c4f4 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 24 Aug 2015 12:47:36 +0800 Subject: [PATCH 4803/7006] drm/amdgpu: add owner for sched fence Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 4 ++-- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 3 ++- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 4 +++- drivers/gpu/drm/amd/scheduler/sched_fence.c | 4 ++-- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index a2d5cf7df56f4..19a8cbead48b0 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1264,7 +1264,6 @@ struct amdgpu_cs_parser { struct amdgpu_job { struct amd_sched_job base; struct amdgpu_device *adev; - struct drm_file *owner; struct amdgpu_ib *ibs; uint32_t num_ibs; struct mutex job_lock; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 82e14321e9c75..6a206f15635fd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -847,7 +847,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) job->adev = parser->adev; job->ibs = parser->ibs; job->num_ibs = parser->num_ibs; - job->owner = parser->filp; + job->base.owner = parser->filp; mutex_init(&job->job_lock); if (job->ibs[job->num_ibs - 1].user) { memcpy(&job->uf, &parser->uf, diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 1aa72edbce9a5..4f5c0874ad2a7 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -44,7 +44,7 @@ static struct fence *amdgpu_sched_run_job(struct amd_gpu_scheduler *sched, r = amdgpu_ib_schedule(sched_job->adev, sched_job->num_ibs, sched_job->ibs, - sched_job->owner); + sched_job->base.owner); if (r) goto err; fence = amdgpu_fence_ref(sched_job->ibs[sched_job->num_ibs - 1].fence); @@ -101,7 +101,7 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev, job->adev = adev; job->ibs = ibs; job->num_ibs = num_ibs; - job->owner = owner; + job->base.owner = owner; mutex_init(&job->job_lock); job->free_job = free_job; mutex_lock(&job->job_lock); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index d747f82808a71..24593fd291505 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -232,7 +232,8 @@ static bool amd_sched_entity_in(struct amd_sched_job *job) int amd_sched_entity_push_job(struct amd_sched_job *sched_job) { struct amd_sched_entity *entity = sched_job->s_entity; - struct amd_sched_fence *fence = amd_sched_fence_create(entity); + struct amd_sched_fence *fence = amd_sched_fence_create( + entity, sched_job->owner); int r; if (!fence) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 62655f4cf11da..0927864af1f83 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -65,6 +65,7 @@ struct amd_sched_fence { struct fence base; struct amd_gpu_scheduler *scheduler; spinlock_t lock; + void *owner; }; struct amd_sched_job { @@ -72,6 +73,7 @@ struct amd_sched_job { struct amd_gpu_scheduler *sched; struct amd_sched_entity *s_entity; struct amd_sched_fence *s_fence; + void *owner; }; extern const struct fence_ops amd_sched_fence_ops; @@ -126,7 +128,7 @@ int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, int amd_sched_entity_push_job(struct amd_sched_job *sched_job); struct amd_sched_fence *amd_sched_fence_create( - struct amd_sched_entity *s_entity); + struct amd_sched_entity *s_entity, void *owner); void amd_sched_fence_signal(struct amd_sched_fence *fence); diff --git a/drivers/gpu/drm/amd/scheduler/sched_fence.c b/drivers/gpu/drm/amd/scheduler/sched_fence.c index 7f0f57819b62c..e62c37920e11c 100644 --- a/drivers/gpu/drm/amd/scheduler/sched_fence.c +++ b/drivers/gpu/drm/amd/scheduler/sched_fence.c @@ -27,7 +27,7 @@ #include #include "gpu_scheduler.h" -struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity) +struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity, void *owner) { struct amd_sched_fence *fence = NULL; unsigned seq; @@ -35,7 +35,7 @@ struct amd_sched_fence *amd_sched_fence_create(struct amd_sched_entity *s_entity fence = kzalloc(sizeof(struct amd_sched_fence), GFP_KERNEL); if (fence == NULL) return NULL; - + fence->owner = owner; fence->scheduler = s_entity->scheduler; spin_lock_init(&fence->lock); -- GitLab From f38fdfddfaab070e3ff2333a79e45169ee33dc28 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 24 Aug 2015 11:35:26 +0800 Subject: [PATCH 4804/7006] drm/amdgpu: add priv data to sched Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 3 ++- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 4 +++- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 3 ++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index e13e4452a349c..9787337a65a10 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -628,7 +628,8 @@ void amdgpu_fence_driver_init_ring(struct amdgpu_ring *ring) if (amdgpu_enable_scheduler) { ring->scheduler = amd_sched_create(&amdgpu_sched_ops, ring->idx, - amdgpu_sched_hw_submission); + amdgpu_sched_hw_submission, + (void *)ring->adev); if (!ring->scheduler) DRM_ERROR("Failed to create scheduler on ring %d.\n", ring->idx); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 24593fd291505..2df6f174ba7b1 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -341,7 +341,8 @@ static int amd_sched_main(void *param) * Return the pointer to scheduler for success, otherwise return NULL */ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, - unsigned ring, unsigned hw_submission) + unsigned ring, unsigned hw_submission, + void *priv) { struct amd_gpu_scheduler *sched; @@ -352,6 +353,7 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, sched->ops = ops; sched->ring_id = ring; sched->hw_submission_limit = hw_submission; + sched->priv = priv; snprintf(sched->name, sizeof(sched->name), "amdgpu[%d]", ring); amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 0927864af1f83..44909b16c3a3a 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -112,11 +112,12 @@ struct amd_gpu_scheduler { wait_queue_head_t wait_queue; uint32_t hw_submission_limit; char name[20]; + void *priv; }; struct amd_gpu_scheduler * amd_sched_create(struct amd_sched_backend_ops *ops, - uint32_t ring, uint32_t hw_submission); + uint32_t ring, uint32_t hw_submission, void *priv); int amd_sched_destroy(struct amd_gpu_scheduler *sched); int amd_sched_entity_init(struct amd_gpu_scheduler *sched, -- GitLab From 3c62338c26bf2677c8285b406cd769b92ee0dc10 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Thu, 20 Aug 2015 18:33:59 +0800 Subject: [PATCH 4805/7006] drm/amdgpu: fix last_vm_update fence is not effetive for sched fence Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 6 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 45 +++++++++++++++++++---- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 24 ++++++++---- 4 files changed, 58 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 19a8cbead48b0..c9160430b5acd 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -705,7 +705,7 @@ struct amdgpu_sync { struct amdgpu_semaphore *semaphores[AMDGPU_NUM_SYNCS]; struct amdgpu_fence *sync_to[AMDGPU_MAX_RINGS]; DECLARE_HASHTABLE(fences, 4); - struct amdgpu_fence *last_vm_update; + struct fence *last_vm_update; }; void amdgpu_sync_create(struct amdgpu_sync *sync); @@ -963,7 +963,7 @@ struct amdgpu_vm_id { unsigned id; uint64_t pd_gpu_addr; /* last flushed PD/PT update */ - struct amdgpu_fence *flushed_updates; + struct fence *flushed_updates; /* last use of vmid */ struct amdgpu_fence *last_id_use; }; @@ -2349,7 +2349,7 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, struct amdgpu_sync *sync); void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_vm *vm, - struct amdgpu_fence *updates); + struct fence *updates); void amdgpu_vm_fence(struct amdgpu_device *adev, struct amdgpu_vm *vm, struct amdgpu_fence *fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 4f5c0874ad2a7..757058d539f4b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -119,5 +119,6 @@ int amdgpu_sched_ib_submit_kernel_helper(struct amdgpu_device *adev, return r; *f = fence_get(&ibs[num_ibs - 1].fence->base); } + return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index febbf37b1412e..4fffb25393318 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -58,6 +58,29 @@ void amdgpu_sync_create(struct amdgpu_sync *sync) sync->last_vm_update = NULL; } +static bool amdgpu_sync_same_dev(struct amdgpu_device *adev, struct fence *f) +{ + struct amdgpu_fence *a_fence = to_amdgpu_fence(f); + struct amd_sched_fence *s_fence = to_amd_sched_fence(f); + + if (a_fence) + return a_fence->ring->adev == adev; + if (s_fence) + return (struct amdgpu_device *)s_fence->scheduler->priv == adev; + return false; +} + +static bool amdgpu_sync_test_owner(struct fence *f, void *owner) +{ + struct amdgpu_fence *a_fence = to_amdgpu_fence(f); + struct amd_sched_fence *s_fence = to_amd_sched_fence(f); + if (s_fence) + return s_fence->owner == owner; + if (a_fence) + return a_fence->owner == owner; + return false; +} + /** * amdgpu_sync_fence - remember to sync to this fence * @@ -71,10 +94,23 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct amdgpu_sync_entry *e; struct amdgpu_fence *fence; struct amdgpu_fence *other; + struct fence *tmp, *later; if (!f) return 0; + if (amdgpu_sync_same_dev(adev, f) && + amdgpu_sync_test_owner(f, AMDGPU_FENCE_OWNER_VM)) { + if (sync->last_vm_update) { + tmp = sync->last_vm_update; + BUG_ON(f->context != tmp->context); + later = (f->seqno - tmp->seqno <= INT_MAX) ? f : tmp; + sync->last_vm_update = fence_get(later); + fence_put(tmp); + } else + sync->last_vm_update = fence_get(f); + } + fence = to_amdgpu_fence(f); if (!fence || fence->ring->adev != adev) { hash_for_each_possible(sync->fences, e, node, f->context) { @@ -103,13 +139,6 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, amdgpu_fence_later(fence, other)); amdgpu_fence_unref(&other); - if (fence->owner == AMDGPU_FENCE_OWNER_VM) { - other = sync->last_vm_update; - sync->last_vm_update = amdgpu_fence_ref( - amdgpu_fence_later(fence, other)); - amdgpu_fence_unref(&other); - } - return 0; } @@ -296,5 +325,5 @@ void amdgpu_sync_free(struct amdgpu_device *adev, for (i = 0; i < AMDGPU_MAX_RINGS; ++i) amdgpu_fence_unref(&sync->sync_to[i]); - amdgpu_fence_unref(&sync->last_vm_update); + fence_put(sync->last_vm_update); } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5b99214d0ba6f..677266b90c749 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -200,19 +200,29 @@ int amdgpu_vm_grab_id(struct amdgpu_vm *vm, struct amdgpu_ring *ring, */ void amdgpu_vm_flush(struct amdgpu_ring *ring, struct amdgpu_vm *vm, - struct amdgpu_fence *updates) + struct fence *updates) { uint64_t pd_addr = amdgpu_bo_gpu_offset(vm->page_directory); struct amdgpu_vm_id *vm_id = &vm->ids[ring->idx]; - struct amdgpu_fence *flushed_updates = vm_id->flushed_updates; + struct fence *flushed_updates = vm_id->flushed_updates; + bool is_earlier = false; + + if (flushed_updates && updates) { + BUG_ON(flushed_updates->context != updates->context); + is_earlier = (updates->seqno - flushed_updates->seqno <= + INT_MAX) ? true : false; + } if (pd_addr != vm_id->pd_gpu_addr || !flushed_updates || - (updates && amdgpu_fence_is_earlier(flushed_updates, updates))) { + is_earlier) { trace_amdgpu_vm_flush(pd_addr, ring->idx, vm_id->id); - vm_id->flushed_updates = amdgpu_fence_ref( - amdgpu_fence_later(flushed_updates, updates)); - amdgpu_fence_unref(&flushed_updates); + if (is_earlier) { + vm_id->flushed_updates = fence_get(updates); + fence_put(flushed_updates); + } + if (!flushed_updates) + vm_id->flushed_updates = fence_get(updates); vm_id->pd_gpu_addr = pd_addr; amdgpu_ring_emit_vm_flush(ring, vm_id->id, vm_id->pd_gpu_addr); } @@ -1347,7 +1357,7 @@ void amdgpu_vm_fini(struct amdgpu_device *adev, struct amdgpu_vm *vm) fence_put(vm->page_directory_fence); for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { - amdgpu_fence_unref(&vm->ids[i].flushed_updates); + fence_put(vm->ids[i].flushed_updates); amdgpu_fence_unref(&vm->ids[i].last_id_use); } -- GitLab From 9066b0c318589f47b754a3def4fe8ec4688dc21a Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Tue, 25 Aug 2015 15:12:26 +0800 Subject: [PATCH 4806/7006] drm/amdgpu: fix no sync_wait in copy_buffer when eviction is happening, if don't handle dependency, then the fence could be dead off. Signed-off-by: Chunming Zhou Reviewed-by: Jammy Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index d7c02e1a309e2..4cb81320b0451 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1014,13 +1014,19 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, /* for fence and sync */ num_dw += 64 + AMDGPU_NUM_SYNCS * 8; + r = amdgpu_sync_wait(&sync); + if (r) { + DRM_ERROR("sync wait failed (%d).\n", r); + amdgpu_sync_free(adev, &sync, NULL); + return r; + } + r = amdgpu_ring_lock(ring, num_dw); if (r) { DRM_ERROR("ring lock failed (%d).\n", r); amdgpu_sync_free(adev, &sync, NULL); return r; } - amdgpu_sync_rings(&sync, ring); for (i = 0; i < num_loops; i++) { -- GitLab From 08446b129bbde34665c423d882f857a45b8c3aed Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 25 Aug 2015 14:59:15 +0100 Subject: [PATCH 4807/7006] ARM: mm: improve do_ldrd_abort macro Improve the do_ldrd_abort macro code - firstly, it inefficiently checks for the LDRD encoding by doing a multi-stage test of various bits. This can be simplified by generating a mask, bitmasking the instruction and then comparing the result. Secondly, we want to be able to test the result rather than branching to do_DataAbort, so remove the branch at the end and rename the macro to 'teq_ldrd' to reflect it's new usage. teq_ldrd macro returns 'eq' if the instruction was a LDRD. Signed-off-by: Russell King --- arch/arm/mm/abort-ev5t.S | 3 ++- arch/arm/mm/abort-ev5tj.S | 3 ++- arch/arm/mm/abort-ev6.S | 3 ++- arch/arm/mm/abort-macro.S | 13 +++++-------- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S index a0908d4653a34..c913031b79ccb 100644 --- a/arch/arm/mm/abort-ev5t.S +++ b/arch/arm/mm/abort-ev5t.S @@ -22,7 +22,8 @@ ENTRY(v5t_early_abort) do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 ldreq r3, [r4] @ read aborted ARM instruction bic r1, r1, #1 << 11 @ clear bits 11 of FSR - do_ldrd_abort tmp=ip, insn=r3 + teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? + beq do_DataAbort @ yes tst r3, #1 << 20 @ check write orreq r1, r1, #1 << 11 b do_DataAbort diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index 4006b7a612642..1b80d71adb0ff 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S @@ -24,7 +24,8 @@ ENTRY(v5tj_early_abort) bne do_DataAbort do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 ldreq r3, [r4] @ read aborted ARM instruction - do_ldrd_abort tmp=ip, insn=r3 + teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? + beq do_DataAbort @ yes tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. b do_DataAbort diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 8c48c5c22a331..113704f30e9f8 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -34,7 +34,8 @@ ENTRY(v6_early_abort) ldr r3, [r4] @ read aborted ARM instruction ARM_BE8(rev r3, r3) - do_ldrd_abort tmp=ip, insn=r3 + teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? + beq do_DataAbort @ yes tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. #endif diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index 2cbf68ef0e832..50d6c0a900b14 100644 --- a/arch/arm/mm/abort-macro.S +++ b/arch/arm/mm/abort-macro.S @@ -29,12 +29,9 @@ not_thumb: * [7:4] == 1101 * [20] == 0 */ - .macro do_ldrd_abort, tmp, insn - tst \insn, #0x0e100000 @ [27:25,20] == 0 - bne not_ldrd - and \tmp, \insn, #0x000000f0 @ [7:4] == 1101 - cmp \tmp, #0x000000d0 - beq do_DataAbort -not_ldrd: + .macro teq_ldrd, tmp, insn + mov \tmp, #0x0e100000 + orr \tmp, #0x000000f0 + and \tmp, \insn, \tmp + teq \tmp, #0x000000d0 .endm - -- GitLab From 3fba7e23f754a9a6e639b640fa2a393712ffe1b8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 19 Aug 2015 11:02:28 +0100 Subject: [PATCH 4808/7006] ARM: uaccess: provide uaccess_save_and_enable() and uaccess_restore() Provide uaccess_save_and_enable() and uaccess_restore() to permit control of userspace visibility to the kernel, and hook these into the appropriate places in the kernel where we need to access userspace. Signed-off-by: Russell King --- arch/arm/include/asm/futex.h | 19 +++++++- arch/arm/include/asm/uaccess.h | 71 +++++++++++++++++++++++++++--- arch/arm/kernel/armksyms.c | 6 +-- arch/arm/lib/clear_user.S | 6 +-- arch/arm/lib/copy_from_user.S | 6 +-- arch/arm/lib/copy_to_user.S | 6 +-- arch/arm/lib/uaccess_with_memcpy.c | 4 +- 7 files changed, 97 insertions(+), 21 deletions(-) diff --git a/arch/arm/include/asm/futex.h b/arch/arm/include/asm/futex.h index 5eed82809d82b..6795368ad0238 100644 --- a/arch/arm/include/asm/futex.h +++ b/arch/arm/include/asm/futex.h @@ -22,8 +22,11 @@ #ifdef CONFIG_SMP #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ +({ \ + unsigned int __ua_flags; \ smp_mb(); \ prefetchw(uaddr); \ + __ua_flags = uaccess_save_and_enable(); \ __asm__ __volatile__( \ "1: ldrex %1, [%3]\n" \ " " insn "\n" \ @@ -34,12 +37,15 @@ __futex_atomic_ex_table("%5") \ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ - : "cc", "memory") + : "cc", "memory"); \ + uaccess_restore(__ua_flags); \ +}) static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { + unsigned int __ua_flags; int ret; u32 val; @@ -49,6 +55,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, smp_mb(); /* Prefetching cannot fault */ prefetchw(uaddr); + __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: ldrex %1, [%4]\n" " teq %1, %2\n" @@ -61,6 +68,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "=&r" (ret), "=&r" (val) : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) : "cc", "memory"); + uaccess_restore(__ua_flags); smp_mb(); *uval = val; @@ -73,6 +81,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, #include #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ +({ \ + unsigned int __ua_flags = uaccess_save_and_enable(); \ __asm__ __volatile__( \ "1: " TUSER(ldr) " %1, [%3]\n" \ " " insn "\n" \ @@ -81,12 +91,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, __futex_atomic_ex_table("%5") \ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ - : "cc", "memory") + : "cc", "memory"); \ + uaccess_restore(__ua_flags); \ +}) static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { + unsigned int __ua_flags; int ret = 0; u32 val; @@ -94,6 +107,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; preempt_disable(); + __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: " TUSER(ldr) " %1, [%4]\n" " teq %1, %2\n" @@ -103,6 +117,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "+r" (ret), "=&r" (val) : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) : "cc", "memory"); + uaccess_restore(__ua_flags); *uval = val; preempt_enable(); diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 74b17d09ef7aa..82880132f941a 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -49,6 +49,21 @@ struct exception_table_entry extern int fixup_exception(struct pt_regs *regs); +/* + * These two functions allow hooking accesses to userspace to increase + * system integrity by ensuring that the kernel can not inadvertantly + * perform such accesses (eg, via list poison values) which could then + * be exploited for priviledge escalation. + */ +static inline unsigned int uaccess_save_and_enable(void) +{ + return 0; +} + +static inline void uaccess_restore(unsigned int flags) +{ +} + /* * These two are intentionally not defined anywhere - if the kernel * code generates any references to them, that's a bug. @@ -165,6 +180,7 @@ extern int __get_user_64t_4(void *); register typeof(x) __r2 asm("r2"); \ register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ + unsigned int __ua_flags = uaccess_save_and_enable(); \ switch (sizeof(*(__p))) { \ case 1: \ if (sizeof((x)) >= 8) \ @@ -192,6 +208,7 @@ extern int __get_user_64t_4(void *); break; \ default: __e = __get_user_bad(); break; \ } \ + uaccess_restore(__ua_flags); \ x = (typeof(*(p))) __r2; \ __e; \ }) @@ -224,6 +241,7 @@ extern int __put_user_8(void *, unsigned long long); register const typeof(*(p)) __user *__p asm("r0") = __tmp_p; \ register unsigned long __l asm("r1") = __limit; \ register int __e asm("r0"); \ + unsigned int __ua_flags = uaccess_save_and_enable(); \ switch (sizeof(*(__p))) { \ case 1: \ __put_user_x(__r2, __p, __e, __l, 1); \ @@ -239,6 +257,7 @@ extern int __put_user_8(void *, unsigned long long); break; \ default: __e = __put_user_bad(); break; \ } \ + uaccess_restore(__ua_flags); \ __e; \ }) @@ -300,14 +319,17 @@ static inline void set_fs(mm_segment_t fs) do { \ unsigned long __gu_addr = (unsigned long)(ptr); \ unsigned long __gu_val; \ + unsigned int __ua_flags; \ __chk_user_ptr(ptr); \ might_fault(); \ + __ua_flags = uaccess_save_and_enable(); \ switch (sizeof(*(ptr))) { \ case 1: __get_user_asm_byte(__gu_val, __gu_addr, err); break; \ case 2: __get_user_asm_half(__gu_val, __gu_addr, err); break; \ case 4: __get_user_asm_word(__gu_val, __gu_addr, err); break; \ default: (__gu_val) = __get_user_bad(); \ } \ + uaccess_restore(__ua_flags); \ (x) = (__typeof__(*(ptr)))__gu_val; \ } while (0) @@ -381,9 +403,11 @@ do { \ #define __put_user_err(x, ptr, err) \ do { \ unsigned long __pu_addr = (unsigned long)(ptr); \ + unsigned int __ua_flags; \ __typeof__(*(ptr)) __pu_val = (x); \ __chk_user_ptr(ptr); \ might_fault(); \ + __ua_flags = uaccess_save_and_enable(); \ switch (sizeof(*(ptr))) { \ case 1: __put_user_asm_byte(__pu_val, __pu_addr, err); break; \ case 2: __put_user_asm_half(__pu_val, __pu_addr, err); break; \ @@ -391,6 +415,7 @@ do { \ case 8: __put_user_asm_dword(__pu_val, __pu_addr, err); break; \ default: __put_user_bad(); \ } \ + uaccess_restore(__ua_flags); \ } while (0) #define __put_user_asm_byte(x, __pu_addr, err) \ @@ -474,11 +499,46 @@ do { \ #ifdef CONFIG_MMU -extern unsigned long __must_check __copy_from_user(void *to, const void __user *from, unsigned long n); -extern unsigned long __must_check __copy_to_user(void __user *to, const void *from, unsigned long n); -extern unsigned long __must_check __copy_to_user_std(void __user *to, const void *from, unsigned long n); -extern unsigned long __must_check __clear_user(void __user *addr, unsigned long n); -extern unsigned long __must_check __clear_user_std(void __user *addr, unsigned long n); +extern unsigned long __must_check +arm_copy_from_user(void *to, const void __user *from, unsigned long n); + +static inline unsigned long __must_check +__copy_from_user(void *to, const void __user *from, unsigned long n) +{ + unsigned int __ua_flags = uaccess_save_and_enable(); + n = arm_copy_from_user(to, from, n); + uaccess_restore(__ua_flags); + return n; +} + +extern unsigned long __must_check +arm_copy_to_user(void __user *to, const void *from, unsigned long n); +extern unsigned long __must_check +__copy_to_user_std(void __user *to, const void *from, unsigned long n); + +static inline unsigned long __must_check +__copy_to_user(void __user *to, const void *from, unsigned long n) +{ + unsigned int __ua_flags = uaccess_save_and_enable(); + n = arm_copy_to_user(to, from, n); + uaccess_restore(__ua_flags); + return n; +} + +extern unsigned long __must_check +arm_clear_user(void __user *addr, unsigned long n); +extern unsigned long __must_check +__clear_user_std(void __user *addr, unsigned long n); + +static inline unsigned long __must_check +__clear_user(void __user *addr, unsigned long n) +{ + unsigned int __ua_flags = uaccess_save_and_enable(); + n = arm_clear_user(addr, n); + uaccess_restore(__ua_flags); + return n; +} + #else #define __copy_from_user(to, from, n) (memcpy(to, (void __force *)from, n), 0) #define __copy_to_user(to, from, n) (memcpy((void __force *)to, from, n), 0) @@ -511,6 +571,7 @@ static inline unsigned long __must_check clear_user(void __user *to, unsigned lo return n; } +/* These are from lib/ code, and use __get_user() and friends */ extern long strncpy_from_user(char *dest, const char __user *src, long count); extern __must_check long strlen_user(const char __user *str); diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c index a88671cfe1ffb..a35d72d30b56a 100644 --- a/arch/arm/kernel/armksyms.c +++ b/arch/arm/kernel/armksyms.c @@ -91,9 +91,9 @@ EXPORT_SYMBOL(__memzero); #ifdef CONFIG_MMU EXPORT_SYMBOL(copy_page); -EXPORT_SYMBOL(__copy_from_user); -EXPORT_SYMBOL(__copy_to_user); -EXPORT_SYMBOL(__clear_user); +EXPORT_SYMBOL(arm_copy_from_user); +EXPORT_SYMBOL(arm_copy_to_user); +EXPORT_SYMBOL(arm_clear_user); EXPORT_SYMBOL(__get_user_1); EXPORT_SYMBOL(__get_user_2); diff --git a/arch/arm/lib/clear_user.S b/arch/arm/lib/clear_user.S index 1710fd7db2d57..970d6c0437743 100644 --- a/arch/arm/lib/clear_user.S +++ b/arch/arm/lib/clear_user.S @@ -12,14 +12,14 @@ .text -/* Prototype: int __clear_user(void *addr, size_t sz) +/* Prototype: unsigned long arm_clear_user(void *addr, size_t sz) * Purpose : clear some user memory * Params : addr - user memory address to clear * : sz - number of bytes to clear * Returns : number of bytes NOT cleared */ ENTRY(__clear_user_std) -WEAK(__clear_user) +WEAK(arm_clear_user) stmfd sp!, {r1, lr} mov r2, #0 cmp r1, #4 @@ -44,7 +44,7 @@ WEAK(__clear_user) USER( strnebt r2, [r0]) mov r0, #0 ldmfd sp!, {r1, pc} -ENDPROC(__clear_user) +ENDPROC(arm_clear_user) ENDPROC(__clear_user_std) .pushsection .text.fixup,"ax" diff --git a/arch/arm/lib/copy_from_user.S b/arch/arm/lib/copy_from_user.S index 7a235b9952be0..1512bebfbf1b1 100644 --- a/arch/arm/lib/copy_from_user.S +++ b/arch/arm/lib/copy_from_user.S @@ -17,7 +17,7 @@ /* * Prototype: * - * size_t __copy_from_user(void *to, const void *from, size_t n) + * size_t arm_copy_from_user(void *to, const void *from, size_t n) * * Purpose: * @@ -89,11 +89,11 @@ .text -ENTRY(__copy_from_user) +ENTRY(arm_copy_from_user) #include "copy_template.S" -ENDPROC(__copy_from_user) +ENDPROC(arm_copy_from_user) .pushsection .fixup,"ax" .align 0 diff --git a/arch/arm/lib/copy_to_user.S b/arch/arm/lib/copy_to_user.S index 9648b0675a3ef..caf5019d8161e 100644 --- a/arch/arm/lib/copy_to_user.S +++ b/arch/arm/lib/copy_to_user.S @@ -17,7 +17,7 @@ /* * Prototype: * - * size_t __copy_to_user(void *to, const void *from, size_t n) + * size_t arm_copy_to_user(void *to, const void *from, size_t n) * * Purpose: * @@ -93,11 +93,11 @@ .text ENTRY(__copy_to_user_std) -WEAK(__copy_to_user) +WEAK(arm_copy_to_user) #include "copy_template.S" -ENDPROC(__copy_to_user) +ENDPROC(arm_copy_to_user) ENDPROC(__copy_to_user_std) .pushsection .text.fixup,"ax" diff --git a/arch/arm/lib/uaccess_with_memcpy.c b/arch/arm/lib/uaccess_with_memcpy.c index 3e58d710013c3..77f020e75ccd2 100644 --- a/arch/arm/lib/uaccess_with_memcpy.c +++ b/arch/arm/lib/uaccess_with_memcpy.c @@ -136,7 +136,7 @@ out: } unsigned long -__copy_to_user(void __user *to, const void *from, unsigned long n) +arm_copy_to_user(void __user *to, const void *from, unsigned long n) { /* * This test is stubbed out of the main function above to keep @@ -190,7 +190,7 @@ out: return n; } -unsigned long __clear_user(void __user *addr, unsigned long n) +unsigned long arm_clear_user(void __user *addr, unsigned long n) { /* See rational for this in __copy_to_user() above. */ if (n < 64) -- GitLab From 43443ad692cf1d41a90cac2ed7066a10cd67a9c6 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sun, 2 Aug 2015 19:44:43 +0200 Subject: [PATCH 4809/7006] of/platform: add function to populate default bus When a default bus like the simple-bus should be used someone had to call of_platform_populate() with the default match table. This match table was not exported, so it is impossible for code build as a module to use this. Instead of exporting of_default_bus_match_table, add a new function which uses this default match table and populates the bus. Signed-off-by: Hauke Mehrtens Signed-off-by: Rob Herring --- drivers/of/platform.c | 9 +++++++++ include/linux/of_platform.h | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/drivers/of/platform.c b/drivers/of/platform.c index ddf8e42c9367d..918f01f26d4b9 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -456,6 +456,15 @@ int of_platform_populate(struct device_node *root, } EXPORT_SYMBOL_GPL(of_platform_populate); +int of_platform_default_populate(struct device_node *root, + const struct of_dev_auxdata *lookup, + struct device *parent) +{ + return of_platform_populate(root, of_default_bus_match_table, lookup, + parent); +} +EXPORT_SYMBOL_GPL(of_platform_default_populate); + static int of_platform_device_destroy(struct device *dev, void *data) { /* Do not touch devices not populated from the device tree */ diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index 611a691145c48..956a1006aefc2 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h @@ -72,6 +72,9 @@ extern int of_platform_populate(struct device_node *root, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, struct device *parent); +extern int of_platform_default_populate(struct device_node *root, + const struct of_dev_auxdata *lookup, + struct device *parent); extern void of_platform_depopulate(struct device *parent); #else static inline int of_platform_populate(struct device_node *root, @@ -81,6 +84,12 @@ static inline int of_platform_populate(struct device_node *root, { return -ENODEV; } +static inline int of_platform_default_populate(struct device_node *root, + const struct of_dev_auxdata *lookup, + struct device *parent) +{ + return -ENODEV; +} static inline void of_platform_depopulate(struct device *parent) { } #endif -- GitLab From 068627a5978a885b33f0f49da81860ce78c3ac6f Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 4 Aug 2015 15:11:21 +0200 Subject: [PATCH 4810/7006] of: Add vendor prefix for JEDEC Solid State Technology Association Add the "jedec" vendor prefix for the "JEDEC Solid State Technology Association" (formerly known as the "Joint Electron Device Engineering Council"), which is already in use in several bindings. Signed-off-by: Geert Uytterhoeven Acked-by: Brian Norris Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/vendor-prefixes.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 9a4ac79038e9c..953aa8f173cfc 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -112,6 +112,7 @@ intel Intel Corporation intercontrol Inter Control Group isee ISEE 2007 S.L. isil Intersil +jedec JEDEC Solid State Technology Association karo Ka-Ro electronics GmbH keymile Keymile GmbH kinetic Kinetic Technologies -- GitLab From 3a496b00b6f90c41bd21a410871dfc97d4f3c7ab Mon Sep 17 00:00:00 2001 From: David Daney Date: Wed, 19 Aug 2015 13:17:47 -0700 Subject: [PATCH 4811/7006] of/address: Don't loop forever in of_find_matching_node_by_address(). If the internal call to of_address_to_resource() fails, we end up looping forever in of_find_matching_node_by_address(). This can be caused by a defective device tree, or calling with an incorrect matches argument. Fix by calling of_find_matching_node() unconditionally at the end of the loop. Signed-off-by: David Daney Cc: stable@vger.kernel.org Signed-off-by: Rob Herring --- drivers/of/address.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/of/address.c b/drivers/of/address.c index 8bfda6ade2c02..384574c3987c3 100644 --- a/drivers/of/address.c +++ b/drivers/of/address.c @@ -845,10 +845,10 @@ struct device_node *of_find_matching_node_by_address(struct device_node *from, struct resource res; while (dn) { - if (of_address_to_resource(dn, 0, &res)) - continue; - if (res.start == base_address) + if (!of_address_to_resource(dn, 0, &res) && + res.start == base_address) return dn; + dn = of_find_matching_node(dn, matches); } -- GitLab From 7f5dcaf1fdf289767a126a0a5cc3ef39b5254b06 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 7 Jun 2015 15:20:11 +0100 Subject: [PATCH 4812/7006] drivercore: Fix unregistration path of platform devices The unregister path of platform_device is broken. On registration, it will register all resources with either a parent already set, or type==IORESOURCE_{IO,MEM}. However, on unregister it will release everything with type==IORESOURCE_{IO,MEM}, but ignore the others. There are also cases where resources don't get registered in the first place, like with devices created by of_platform_populate()*. Fix the unregister path to be symmetrical with the register path by checking the parent pointer instead of the type field to decide which resources to unregister. This is safe because the upshot of the registration path algorithm is that registered resources have a parent pointer, and non-registered resources do not. * It can be argued that of_platform_populate() should be registering it's resources, and they argument has some merit. However, there are quite a few platforms that end up broken if we try to do that due to overlapping resources in the device tree. Until that is fixed, we need to solve the immediate problem. Cc: Pantelis Antoniou Cc: Wolfram Sang Cc: Rob Herring Cc: Greg Kroah-Hartman Cc: Ricardo Ribalda Delgado Signed-off-by: Grant Likely Tested-by: Ricardo Ribalda Delgado Tested-by: Wolfram Sang Cc: stable@vger.kernel.org Signed-off-by: Rob Herring --- drivers/base/platform.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/base/platform.c b/drivers/base/platform.c index 063f0ab152590..f80aaaf9f6108 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -375,9 +375,7 @@ int platform_device_add(struct platform_device *pdev) while (--i >= 0) { struct resource *r = &pdev->resource[i]; - unsigned long type = resource_type(r); - - if (type == IORESOURCE_MEM || type == IORESOURCE_IO) + if (r->parent) release_resource(r); } @@ -408,9 +406,7 @@ void platform_device_del(struct platform_device *pdev) for (i = 0; i < pdev->num_resources; i++) { struct resource *r = &pdev->resource[i]; - unsigned long type = resource_type(r); - - if (type == IORESOURCE_MEM || type == IORESOURCE_IO) + if (r->parent) release_resource(r); } } -- GitLab From 126b16e2ad98c46aa0f53dbf62f71c09ba6b1d99 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 23 Jul 2015 17:52:43 +0100 Subject: [PATCH 4813/7006] Docs: dt: add generic MSI bindings Currently msi-parent is used in a couple of drivers despite being fairly underspecified. This patch adds a generic binding for MSIs (including the existing msi-parent property) enabling the description of platform devices capable of using MSIs. While MSIs are primarily distinguished by doorbell and payload, some MSI controllers (e.g. the GICv3 ITS) also use side-band information accompanying the write to identify the master which originated the MSI, to allow for sandboxing. This sideband information is non-probeable and needs to be described in the DT. Other MSI controllers may have additional configuration details which need to be described per-master. This patch adds a generic msi-parent binding document, extending the de-facto standard with a new (optional) #msi-cells which can be used to express any per-master configuration and/or sideband data. This is sufficient to describe non-hotpluggable devices. For busses where sideband data may be derived from some bus-specific master ID scheme, other properties will be required to describe the mapping. Signed-off-by: Mark Rutland Acked-by: Marc Zyngier Signed-off-by: Rob Herring --- .../bindings/interrupt-controller/msi.txt | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 Documentation/devicetree/bindings/interrupt-controller/msi.txt diff --git a/Documentation/devicetree/bindings/interrupt-controller/msi.txt b/Documentation/devicetree/bindings/interrupt-controller/msi.txt new file mode 100644 index 0000000000000..c60c034dcf195 --- /dev/null +++ b/Documentation/devicetree/bindings/interrupt-controller/msi.txt @@ -0,0 +1,135 @@ +This document describes the generic device tree binding for MSI controllers and +their master(s). + +Message Signaled Interrupts (MSIs) are a class of interrupts generated by a +write to an MMIO address. + +MSIs were originally specified by PCI (and are used with PCIe), but may also be +used with other busses, and hence a mechanism is required to relate devices on +those busses to the MSI controllers which they are capable of using, +potentially including additional information. + +MSIs are distinguished by some combination of: + +- The doorbell (the MMIO address written to). + + Devices may be configured by software to write to arbitrary doorbells which + they can address. An MSI controller may feature a number of doorbells. + +- The payload (the value written to the doorbell). + + Devices may be configured to write an arbitrary payload chosen by software. + MSI controllers may have restrictions on permitted payloads. + +- Sideband information accompanying the write. + + Typically this is neither configurable nor probeable, and depends on the path + taken through the memory system (i.e. it is a property of the combination of + MSI controller and device rather than a property of either in isolation). + + +MSI controllers: +================ + +An MSI controller signals interrupts to a CPU when a write is made to an MMIO +address by some master. An MSI controller may feature a number of doorbells. + +Required properties: +-------------------- + +- msi-controller: Identifies the node as an MSI controller. + +Optional properties: +-------------------- + +- #msi-cells: The number of cells in an msi-specifier, required if not zero. + + Typically this will encode information related to sideband data, and will + not encode doorbells or payloads as these can be configured dynamically. + + The meaning of the msi-specifier is defined by the device tree binding of + the specific MSI controller. + + +MSI clients +=========== + +MSI clients are devices which generate MSIs. For each MSI they wish to +generate, the doorbell and payload may be configured, though sideband +information may not be configurable. + +Required properties: +-------------------- + +- msi-parent: A list of phandle + msi-specifier pairs, one for each MSI + controller which the device is capable of using. + + This property is unordered, and MSIs may be allocated from any combination of + MSI controllers listed in the msi-parent property. + + If a device has restrictions on the allocation of MSIs, these restrictions + must be described with additional properties. + + When #msi-cells is non-zero, busses with an msi-parent will require + additional properties to describe the relationship between devices on the bus + and the set of MSIs they can potentially generate. + + +Example +======= + +/ { + #address-cells = <1>; + #size-cells = <1>; + + msi_a: msi-controller@a { + reg = <0xa 0xf00>; + compatible = "vendor-a,some-controller"; + msi-controller; + /* No sideband data, so #msi-cells omitted */ + }; + + msi_b: msi-controller@b { + reg = <0xb 0xf00>; + compatible = "vendor-b,another-controller"; + msi-controller; + /* Each device has some unique ID */ + #msi-cells = <1>; + }; + + msi_c: msi-controller@c { + reg = <0xb 0xf00>; + compatible = "vendor-b,another-controller"; + msi-controller; + /* Each device has some unique ID */ + #msi-cells = <1>; + }; + + dev@0 { + reg = <0x0 0xf00>; + compatible = "vendor-c,some-device"; + + /* Can only generate MSIs to msi_a */ + msi-parent = <&msi_a>; + }; + + dev@1 { + reg = <0x1 0xf00>; + compatible = "vendor-c,some-device"; + + /* + * Can generate MSIs to either A or B. + */ + msi-parent = <&msi_a>, <&msi_b 0x17>; + }; + + dev@2 { + reg = <0x2 0xf00>; + compatible = "vendor-c,some-device"; + /* + * Has different IDs at each MSI controller. + * Can generate MSIs to all of the MSI controllers. + */ + msi-parent = <&msi_a>, <&msi_b 0x17>, <&msi_c 0x53>; + }; +}; -- GitLab From 7d4d443eb4386d6dbd420fa96303dd8fbc1eefc8 Mon Sep 17 00:00:00 2001 From: Ben Zhang Date: Fri, 21 Aug 2015 21:17:00 -0700 Subject: [PATCH 4814/7006] ASoC: rt5677: Allow arbitrary block read/write via SPI Added rt5677_spi_read() and refactored rt5677_spi_write() so that an arbitrary block in the DSP address space can be read/written via SPI. For example, this allows us to load an ELF DSP firmware with sparse sections, and stream audio samples from DSP ring buffer. Signed-off-by: Ben Zhang Acked-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5677-spi.c | 233 +++++++++++++++++++++++++--------- sound/soc/codecs/rt5677-spi.h | 8 +- sound/soc/codecs/rt5677.c | 4 +- 3 files changed, 178 insertions(+), 67 deletions(-) diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c index ef6348cb9157d..3505aafbade49 100644 --- a/sound/soc/codecs/rt5677-spi.c +++ b/sound/soc/codecs/rt5677-spi.c @@ -31,84 +31,197 @@ #include "rt5677-spi.h" +#define RT5677_SPI_BURST_LEN 240 +#define RT5677_SPI_HEADER 5 +#define RT5677_SPI_FREQ 6000000 + +/* The AddressPhase and DataPhase of SPI commands are MSB first on the wire. + * DataPhase word size of 16-bit commands is 2 bytes. + * DataPhase word size of 32-bit commands is 4 bytes. + * DataPhase word size of burst commands is 8 bytes. + * The DSP CPU is little-endian. + */ +#define RT5677_SPI_WRITE_BURST 0x5 +#define RT5677_SPI_READ_BURST 0x4 +#define RT5677_SPI_WRITE_32 0x3 +#define RT5677_SPI_READ_32 0x2 +#define RT5677_SPI_WRITE_16 0x1 +#define RT5677_SPI_READ_16 0x0 + static struct spi_device *g_spi; +static DEFINE_MUTEX(spi_mutex); -/** - * rt5677_spi_write - Write data to SPI. - * @txbuf: Data Buffer for writing. - * @len: Data length. +/* Select a suitable transfer command for the next transfer to ensure + * the transfer address is always naturally aligned while minimizing + * the total number of transfers required. + * + * 3 transfer commands are available: + * RT5677_SPI_READ/WRITE_16: Transfer 2 bytes + * RT5677_SPI_READ/WRITE_32: Transfer 4 bytes + * RT5677_SPI_READ/WRITE_BURST: Transfer any multiples of 8 bytes + * + * For example, reading 260 bytes at 0x60030002 uses the following commands: + * 0x60030002 RT5677_SPI_READ_16 2 bytes + * 0x60030004 RT5677_SPI_READ_32 4 bytes + * 0x60030008 RT5677_SPI_READ_BURST 240 bytes + * 0x600300F8 RT5677_SPI_READ_BURST 8 bytes + * 0x60030100 RT5677_SPI_READ_32 4 bytes + * 0x60030104 RT5677_SPI_READ_16 2 bytes * + * Input: + * @read: true for read commands; false for write commands + * @align: alignment of the next transfer address + * @remain: number of bytes remaining to transfer * - * Returns true for success. + * Output: + * @len: number of bytes to transfer with the selected command + * Returns the selected command */ -int rt5677_spi_write(u8 *txbuf, size_t len) +static u8 rt5677_spi_select_cmd(bool read, u32 align, u32 remain, u32 *len) { - int status; - - status = spi_write(g_spi, txbuf, len); - - if (status) - dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status); - - return status; + u8 cmd; + + if (align == 2 || align == 6 || remain == 2) { + cmd = RT5677_SPI_READ_16; + *len = 2; + } else if (align == 4 || remain <= 6) { + cmd = RT5677_SPI_READ_32; + *len = 4; + } else { + cmd = RT5677_SPI_READ_BURST; + *len = min_t(u32, remain & ~7, RT5677_SPI_BURST_LEN); + } + return read ? cmd : cmd + 1; } -EXPORT_SYMBOL_GPL(rt5677_spi_write); -/** - * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address. - * @addr: Start address. - * @txbuf: Data Buffer for writng. - * @len: Data length, it must be a multiple of 8. - * - * - * Returns true for success. +/* Copy dstlen bytes from src to dst, while reversing byte order for each word. + * If srclen < dstlen, zeros are padded. */ -int rt5677_spi_burst_write(u32 addr, const struct firmware *fw) +static void rt5677_spi_reverse(u8 *dst, u32 dstlen, const u8 *src, u32 srclen) { - u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE; - u8 *write_buf; - unsigned int i, end, offset = 0; - - write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL); - - if (write_buf == NULL) - return -ENOMEM; - - while (offset < fw->size) { - if (offset + RT5677_SPI_BUF_LEN <= fw->size) - end = RT5677_SPI_BUF_LEN; - else - end = fw->size % RT5677_SPI_BUF_LEN; - - write_buf[0] = spi_cmd; - write_buf[1] = ((addr + offset) & 0xff000000) >> 24; - write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16; - write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8; - write_buf[4] = ((addr + offset) & 0x000000ff) >> 0; - - for (i = 0; i < end; i += 8) { - write_buf[i + 12] = fw->data[offset + i + 0]; - write_buf[i + 11] = fw->data[offset + i + 1]; - write_buf[i + 10] = fw->data[offset + i + 2]; - write_buf[i + 9] = fw->data[offset + i + 3]; - write_buf[i + 8] = fw->data[offset + i + 4]; - write_buf[i + 7] = fw->data[offset + i + 5]; - write_buf[i + 6] = fw->data[offset + i + 6]; - write_buf[i + 5] = fw->data[offset + i + 7]; + u32 w, i, si; + u32 word_size = min_t(u32, dstlen, 8); + + for (w = 0; w < dstlen; w += word_size) { + for (i = 0; i < word_size; i++) { + si = w + word_size - i - 1; + dst[w + i] = si < srclen ? src[si] : 0; } + } +} - write_buf[end + 5] = spi_cmd; +/* Read DSP address space using SPI. addr and len have to be 2-byte aligned. */ +int rt5677_spi_read(u32 addr, void *rxbuf, size_t len) +{ + u32 offset; + int status = 0; + struct spi_transfer t[2]; + struct spi_message m; + /* +4 bytes is for the DummyPhase following the AddressPhase */ + u8 header[RT5677_SPI_HEADER + 4]; + u8 body[RT5677_SPI_BURST_LEN]; + u8 spi_cmd; + u8 *cb = rxbuf; + + if (!g_spi) + return -ENODEV; + + if ((addr & 1) || (len & 1)) { + dev_err(&g_spi->dev, "Bad read align 0x%x(%zu)\n", addr, len); + return -EACCES; + } - rt5677_spi_write(write_buf, end + 6); + memset(t, 0, sizeof(t)); + t[0].tx_buf = header; + t[0].len = sizeof(header); + t[0].speed_hz = RT5677_SPI_FREQ; + t[1].rx_buf = body; + t[1].speed_hz = RT5677_SPI_FREQ; + spi_message_init_with_transfers(&m, t, ARRAY_SIZE(t)); + + for (offset = 0; offset < len; offset += t[1].len) { + spi_cmd = rt5677_spi_select_cmd(true, (addr + offset) & 7, + len - offset, &t[1].len); + + /* Construct SPI message header */ + header[0] = spi_cmd; + header[1] = ((addr + offset) & 0xff000000) >> 24; + header[2] = ((addr + offset) & 0x00ff0000) >> 16; + header[3] = ((addr + offset) & 0x0000ff00) >> 8; + header[4] = ((addr + offset) & 0x000000ff) >> 0; + + mutex_lock(&spi_mutex); + status |= spi_sync(g_spi, &m); + mutex_unlock(&spi_mutex); + + /* Copy data back to caller buffer */ + rt5677_spi_reverse(cb + offset, t[1].len, body, t[1].len); + } + return status; +} +EXPORT_SYMBOL_GPL(rt5677_spi_read); - offset += RT5677_SPI_BUF_LEN; +/* Write DSP address space using SPI. addr has to be 2-byte aligned. + * If len is not 2-byte aligned, an extra byte of zero is written at the end + * as padding. + */ +int rt5677_spi_write(u32 addr, const void *txbuf, size_t len) +{ + u32 offset, len_with_pad = len; + int status = 0; + struct spi_transfer t; + struct spi_message m; + /* +1 byte is for the DummyPhase following the DataPhase */ + u8 buf[RT5677_SPI_HEADER + RT5677_SPI_BURST_LEN + 1]; + u8 *body = buf + RT5677_SPI_HEADER; + u8 spi_cmd; + const u8 *cb = txbuf; + + if (!g_spi) + return -ENODEV; + + if (addr & 1) { + dev_err(&g_spi->dev, "Bad write align 0x%x(%zu)\n", addr, len); + return -EACCES; } - kfree(write_buf); + if (len & 1) + len_with_pad = len + 1; + + memset(&t, 0, sizeof(t)); + t.tx_buf = buf; + t.speed_hz = RT5677_SPI_FREQ; + spi_message_init_with_transfers(&m, &t, 1); + + for (offset = 0; offset < len_with_pad;) { + spi_cmd = rt5677_spi_select_cmd(false, (addr + offset) & 7, + len_with_pad - offset, &t.len); + + /* Construct SPI message header */ + buf[0] = spi_cmd; + buf[1] = ((addr + offset) & 0xff000000) >> 24; + buf[2] = ((addr + offset) & 0x00ff0000) >> 16; + buf[3] = ((addr + offset) & 0x0000ff00) >> 8; + buf[4] = ((addr + offset) & 0x000000ff) >> 0; + + /* Fetch data from caller buffer */ + rt5677_spi_reverse(body, t.len, cb + offset, len - offset); + offset += t.len; + t.len += RT5677_SPI_HEADER + 1; + + mutex_lock(&spi_mutex); + status |= spi_sync(g_spi, &m); + mutex_unlock(&spi_mutex); + } + return status; +} +EXPORT_SYMBOL_GPL(rt5677_spi_write); - return 0; +int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw) +{ + return rt5677_spi_write(addr, fw->data, fw->size); } -EXPORT_SYMBOL_GPL(rt5677_spi_burst_write); +EXPORT_SYMBOL_GPL(rt5677_spi_write_firmware); static int rt5677_spi_probe(struct spi_device *spi) { diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h index ec41b2b3b2ca2..662db16cfb6a4 100644 --- a/sound/soc/codecs/rt5677-spi.h +++ b/sound/soc/codecs/rt5677-spi.h @@ -12,10 +12,8 @@ #ifndef __RT5677_SPI_H__ #define __RT5677_SPI_H__ -#define RT5677_SPI_BUF_LEN 240 -#define RT5677_SPI_CMD_BURST_WRITE 0x05 - -int rt5677_spi_write(u8 *txbuf, size_t len); -int rt5677_spi_burst_write(u32 addr, const struct firmware *fw); +int rt5677_spi_read(u32 addr, void *rxbuf, size_t len); +int rt5677_spi_write(u32 addr, const void *txbuf, size_t len); +int rt5677_spi_write_firmware(u32 addr, const struct firmware *fw); #endif /* __RT5677_SPI_H__ */ diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c index 3f890a6708cd1..d916d0c72690d 100644 --- a/sound/soc/codecs/rt5677.c +++ b/sound/soc/codecs/rt5677.c @@ -745,14 +745,14 @@ static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on) ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1, codec->dev); if (ret == 0) { - rt5677_spi_burst_write(0x50000000, rt5677->fw1); + rt5677_spi_write_firmware(0x50000000, rt5677->fw1); release_firmware(rt5677->fw1); } ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2, codec->dev); if (ret == 0) { - rt5677_spi_burst_write(0x60000000, rt5677->fw2); + rt5677_spi_write_firmware(0x60000000, rt5677->fw2); release_firmware(rt5677->fw2); } -- GitLab From 9205b797dbe519a629267ec8c5766cd973d35063 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Mon, 24 Aug 2015 21:49:30 +0100 Subject: [PATCH 4815/7006] ARM: 8421/1: smp: Collapse arch_cpu_idle_dead() into cpu_die() The only caller of cpu_die() on ARM is arch_cpu_idle_dead(), so let's simplify the code by renaming cpu_die() to arch_cpu_idle_dead(). While were here, drop the __ref annotation because __cpuinit is gone nowadays. Signed-off-by: Stephen Boyd Signed-off-by: Russell King --- arch/arm/include/asm/smp.h | 1 - arch/arm/kernel/process.c | 7 ------- arch/arm/kernel/smp.c | 2 +- 3 files changed, 1 insertion(+), 9 deletions(-) diff --git a/arch/arm/include/asm/smp.h b/arch/arm/include/asm/smp.h index 318ce89eeff7d..ef356659b4f43 100644 --- a/arch/arm/include/asm/smp.h +++ b/arch/arm/include/asm/smp.h @@ -74,7 +74,6 @@ extern void secondary_startup_arm(void); extern int __cpu_disable(void); extern void __cpu_die(unsigned int cpu); -extern void cpu_die(void); extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index f192a2a417193..358984b7f249e 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -91,13 +91,6 @@ void arch_cpu_idle_exit(void) ledtrig_cpu(CPU_LED_IDLE_END); } -#ifdef CONFIG_HOTPLUG_CPU -void arch_cpu_idle_dead(void) -{ - cpu_die(); -} -#endif - void __show_regs(struct pt_regs *regs) { unsigned long flags; diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c index 3cd846f48eafe..0aad7cdf2e58b 100644 --- a/arch/arm/kernel/smp.c +++ b/arch/arm/kernel/smp.c @@ -266,7 +266,7 @@ void __cpu_die(unsigned int cpu) * of the other hotplug-cpu capable cores, so presumably coming * out of idle fixes this. */ -void __ref cpu_die(void) +void arch_cpu_idle_dead(void) { unsigned int cpu = smp_processor_id(); -- GitLab From 588cd850f5089cb63e031e8d70e9c081b0d97ab2 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:56 +0800 Subject: [PATCH 4816/7006] ASoC: rt5645: Modify the headphone depop and calibration function to prevent the pop sound in the booting time Remove the original calibration function and modify the depop and calibration function to prevent the pop sound in the booting time. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 111 +++++++++++--------------------------- 1 file changed, 32 insertions(+), 79 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 2ee42781cc52f..ac2f42f4e3a06 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -254,6 +254,7 @@ struct rt5645_priv { int jack_type; bool en_button_func; + bool hp_on; }; static int rt5645_reset(struct snd_soc_codec *codec) @@ -1364,15 +1365,23 @@ static void hp_amp_power(struct snd_soc_codec *codec, int on) if (on) { if (hp_amp_power_count <= 0) { if (rt5645->codec_type == CODEC_TYPE_RT5650) { + snd_soc_write(codec, RT5645_DEPOP_M2, 0x3100); snd_soc_write(codec, RT5645_CHARGE_PUMP, 0x0e06); - snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x000d); + regmap_write(rt5645->regmap, RT5645_PR_BASE + + RT5645_HP_DCC_INT1, 0x9f01); + msleep(20); + snd_soc_update_bits(codec, RT5645_DEPOP_M1, + RT5645_HP_CO_MASK, RT5645_HP_CO_EN); regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400); snd_soc_write(codec, RT5645_DEPOP_M3, 0x0737); regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, 0xfc00); snd_soc_write(codec, RT5645_DEPOP_M2, 0x1140); + mdelay(5); + rt5645->hp_on = true; } else { /* depop parameters */ snd_soc_update_bits(codec, RT5645_DEPOP_M2, @@ -1586,6 +1595,27 @@ static int rt5645_bst2_event(struct snd_soc_dapm_widget *w, return 0; } +static int rt5650_hp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (rt5645->hp_on) { + msleep(100); + rt5645->hp_on = false; + } + break; + + default: + return 0; + } + + return 0; +} + static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("LDO2", RT5645_PWR_MIXER, RT5645_PWR_LDO2_BIT, 0, NULL, 0), @@ -1870,6 +1900,7 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = { SND_SOC_DAPM_OUTPUT("PDM1R"), SND_SOC_DAPM_OUTPUT("SPOL"), SND_SOC_DAPM_OUTPUT("SPOR"), + SND_SOC_DAPM_POST("DAPM_POST", rt5650_hp_event), }; static const struct snd_soc_dapm_widget rt5645_specific_dapm_widgets[] = { @@ -2721,77 +2752,6 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec, return 0; } -static int rt5650_calibration(struct rt5645_priv *rt5645) -{ - int val, i; - int ret = -1; - - regcache_cache_bypass(rt5645->regmap, true); - regmap_write(rt5645->regmap, RT5645_RESET, 0); - regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0800); - regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_CHOP_DAC_ADC, - 0x3600); - regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x25, 0x7000); - regmap_write(rt5645->regmap, RT5645_I2S1_SDP, 0x8008); - /* headset type */ - regmap_write(rt5645->regmap, RT5645_GEN_CTRL1, 0x2061); - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0006); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0x2012); - regmap_write(rt5645->regmap, RT5645_PWR_MIXER, 0x0002); - regmap_write(rt5645->regmap, RT5645_PWR_VOL, 0x0020); - regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x1827); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL2, 0x0827); - msleep(400); - /* Inline command */ - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0001); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008); - /* Calbration */ - regmap_write(rt5645->regmap, RT5645_GLB_CLK, 0x8000); - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD2, 0xc000); - regmap_write(rt5645->regmap, RT5650_4BTN_IL_CMD1, 0x0008); - regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x8800); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG1, 0xe8fa); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x8c04); - regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x3100); - regmap_write(rt5645->regmap, RT5645_CHARGE_PUMP, 0x0e06); - regmap_write(rt5645->regmap, RT5645_BASS_BACK, 0x8a13); - regmap_write(rt5645->regmap, RT5645_GEN_CTRL3, 0x0820); - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x000d); - /* Power on and Calbration */ - regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_HP_DCC_INT1, - 0x9f01); - msleep(200); - for (i = 0; i < 5; i++) { - regmap_read(rt5645->regmap, RT5645_PR_BASE + 0x7a, &val); - if (val != 0 && val != 0x3f3f) { - ret = 0; - break; - } - msleep(50); - } - pr_debug("%s: PR-7A = 0x%x\n", __func__, val); - - /* mute */ - regmap_write(rt5645->regmap, RT5645_PR_BASE + 0x3e, 0x7400); - regmap_write(rt5645->regmap, RT5645_DEPOP_M3, 0x0737); - regmap_write(rt5645->regmap, RT5645_PR_BASE + RT5645_MAMP_INT_REG2, - 0xfc00); - regmap_write(rt5645->regmap, RT5645_DEPOP_M2, 0x1140); - regmap_write(rt5645->regmap, RT5645_DEPOP_M1, 0x0000); - regmap_write(rt5645->regmap, RT5645_GEN_CTRL2, 0x4020); - regmap_write(rt5645->regmap, RT5645_PWR_ANLG2, 0x0006); - regmap_write(rt5645->regmap, RT5645_PWR_DIG2, 0x0000); - msleep(350); - - regcache_cache_bypass(rt5645->regmap, false); - - return ret; -} - static void rt5645_enable_push_button_irq(struct snd_soc_codec *codec, bool enable) { @@ -3319,13 +3279,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, goto err_enable; } - if (rt5645->codec_type == CODEC_TYPE_RT5650) { - ret = rt5650_calibration(rt5645); - - if (ret < 0) - pr_err("calibration failed!\n"); - } - regmap_write(rt5645->regmap, RT5645_RESET, 0); ret = regmap_register_patch(rt5645->regmap, init_list, -- GitLab From 8db7f56ddf2c4571e33756b70a1a8f492c050449 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:57 +0800 Subject: [PATCH 4817/7006] ASoC: rt5645: Modify the jack detection function to prevent the pop sound while the jack plug in The patch corrects the sequence of the jack detection. It will prevent the pop sound while the jack plug in. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index ac2f42f4e3a06..bcb44de002c9b 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2805,14 +2805,15 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); - regmap_write(rt5645->regmap, RT5645_IN1_CTRL1, 0x0006); regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, 0x1000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, + 0x0004); msleep(100); regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, 0x0000); - msleep(450); + msleep(600); regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val); val &= 0x7; dev_dbg(codec->dev, "val = %d\n", val); @@ -2828,9 +2829,17 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) rt5645->jack_type = SND_JACK_HEADPHONE; } + snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x001d); + snd_soc_write(codec, RT5645_DEPOP_M1, 0x0001); } else { /* jack out */ rt5645->jack_type = 0; + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, + 0x1000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, + 0x0000); + if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); -- GitLab From 4aed4c9efb30253483869c58236ab00bdfa45630 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:58 +0800 Subject: [PATCH 4818/7006] ASoC: rt5645: Remove the incorrect setting of the JD mode The patch removes the incorrect setting of the JD mode. It will cause pop sound in the booting time. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index bcb44de002c9b..d9f34421414e7 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3373,8 +3373,6 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, RT5645_IRQ_CLK_GATE_CTRL, RT5645_IRQ_CLK_GATE_CTRL); - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, - RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); regmap_update_bits(rt5645->regmap, RT5645_MICBIAS, RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT); regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2, -- GitLab From b1d42598cb654ce63b55ccf27da09dcd914781f3 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Mon, 24 Aug 2015 20:32:59 +0800 Subject: [PATCH 4819/7006] ASoC: rt5645: Add the register RT5645_CHARGE_PUMP to readable check function Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index d9f34421414e7..0a4cb6bc34335 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -394,6 +394,7 @@ static bool rt5645_readable_register(struct device *dev, unsigned int reg) case RT5645_DEPOP_M1: case RT5645_DEPOP_M2: case RT5645_DEPOP_M3: + case RT5645_CHARGE_PUMP: case RT5645_MICBIAS: case RT5645_A_JD_CTRL1: case RT5645_VAD_CTRL4: -- GitLab From c1713485f9fc06e1f4de9800b43f6486f2527379 Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Tue, 25 Aug 2015 16:03:48 +0800 Subject: [PATCH 4820/7006] ASoC: rt5645: Add struct dmi_system_id "Google Celes" for chrome platform Signed-off-by: Oder Chiou Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/rt5645.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 9ce311e088fc5..610eacd34900d 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -3229,6 +3229,13 @@ static struct dmi_system_id dmi_platform_intel_braswell[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Strago"), }, }, + { + .ident = "Google Celes", + .callback = strago_quirk_cb, + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "Celes"), + }, + }, { } }; -- GitLab From 0e7659712836ca59b4735bc5cc94de38698a5e01 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Tue, 25 Aug 2015 12:43:48 +0100 Subject: [PATCH 4821/7006] ASoC: arizona: Poll for FLL clock OK rather than use interrupts The extcon driver takes the DAPM mutex from within the interrupt thread in several places, which makes it possible to get into a situation where the interrupt thread is blocked waiting on the DAPM mutex whilst a DAPM sequence is running which is attempting to configure the FLL. In this case the FLL completion can't be completed as as the IRQ handler is ONE_SHOT, which cause the FLL lock to use the full time out (250mS) and report that the process timed out. It is not really practical to make the extcon driver not take the DAPM mutex from within the interrupt thread, at least not without extensive modification. So this patch fixes the issue by switching the wait for the FLL lock to polling. A few fast polls are done first as the FLL should lock quickly for a good quality reference clock, (indeed it hits on the first poll on my system) and it will poll every 20mS after that until it times out. Signed-off-by: Charles Keepax Signed-off-by: Mark Brown Cc: stable@vger.kernel.org --- sound/soc/codecs/arizona.c | 47 +++++++++++++++----------------------- sound/soc/codecs/arizona.h | 1 - 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c index 4e5d0a96f9338..4180827a84800 100644 --- a/sound/soc/codecs/arizona.c +++ b/sound/soc/codecs/arizona.c @@ -1756,17 +1756,6 @@ int arizona_init_dai(struct arizona_priv *priv, int id) } EXPORT_SYMBOL_GPL(arizona_init_dai); -static irqreturn_t arizona_fll_clock_ok(int irq, void *data) -{ - struct arizona_fll *fll = data; - - arizona_fll_dbg(fll, "clock OK\n"); - - complete(&fll->ok); - - return IRQ_HANDLED; -} - static struct { unsigned int min; unsigned int max; @@ -2048,10 +2037,11 @@ static int arizona_is_enabled_fll(struct arizona_fll *fll) static int arizona_enable_fll(struct arizona_fll *fll) { struct arizona *arizona = fll->arizona; - unsigned long time_left; bool use_sync = false; int already_enabled = arizona_is_enabled_fll(fll); struct arizona_fll_cfg cfg; + int i; + unsigned int val; if (already_enabled < 0) return already_enabled; @@ -2110,9 +2100,6 @@ static int arizona_enable_fll(struct arizona_fll *fll) if (!already_enabled) pm_runtime_get(arizona->dev); - /* Clear any pending completions */ - try_wait_for_completion(&fll->ok); - regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_ENA, ARIZONA_FLL1_ENA); if (use_sync) @@ -2124,10 +2111,24 @@ static int arizona_enable_fll(struct arizona_fll *fll) regmap_update_bits_async(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); - time_left = wait_for_completion_timeout(&fll->ok, - msecs_to_jiffies(250)); - if (time_left == 0) + arizona_fll_dbg(fll, "Waiting for FLL lock...\n"); + val = 0; + for (i = 0; i < 15; i++) { + if (i < 5) + usleep_range(200, 400); + else + msleep(20); + + regmap_read(arizona->regmap, + ARIZONA_INTERRUPT_RAW_STATUS_5, + &val); + if (val & (ARIZONA_FLL1_CLOCK_OK_STS << (fll->id - 1))) + break; + } + if (i == 15) arizona_fll_warn(fll, "Timed out waiting for lock\n"); + else + arizona_fll_dbg(fll, "FLL locked (%d polls)\n", i); return 0; } @@ -2212,11 +2213,8 @@ EXPORT_SYMBOL_GPL(arizona_set_fll); int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, int ok_irq, struct arizona_fll *fll) { - int ret; unsigned int val; - init_completion(&fll->ok); - fll->id = id; fll->base = base; fll->arizona = arizona; @@ -2238,13 +2236,6 @@ int arizona_init_fll(struct arizona *arizona, int id, int base, int lock_irq, snprintf(fll->clock_ok_name, sizeof(fll->clock_ok_name), "FLL%d clock OK", id); - ret = arizona_request_irq(arizona, ok_irq, fll->clock_ok_name, - arizona_fll_clock_ok, fll); - if (ret != 0) { - dev_err(arizona->dev, "Failed to get FLL%d clock OK IRQ: %d\n", - id, ret); - } - regmap_update_bits(arizona->regmap, fll->base + 1, ARIZONA_FLL1_FREERUN, 0); diff --git a/sound/soc/codecs/arizona.h b/sound/soc/codecs/arizona.h index 43deb0462309e..36867d05e0bba 100644 --- a/sound/soc/codecs/arizona.h +++ b/sound/soc/codecs/arizona.h @@ -242,7 +242,6 @@ struct arizona_fll { int id; unsigned int base; unsigned int vco_mult; - struct completion ok; unsigned int fout; int sync_src; -- GitLab From ce52399520e4b97466165737e00c7b528ae8c8f5 Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Tue, 25 Aug 2015 12:50:44 +1000 Subject: [PATCH 4822/7006] cgroup: pids: fix invalid get/put usage Fix incorrect usage of css_get and css_put to put a different css in pids_{cancel_,}attach() than the one grabbed in pids_can_attach(). This could lead to quite serious memory leakage (and unsafe operations on the putted css). tj: minor comment update Signed-off-by: Aleksa Sarai Signed-off-by: Tejun Heo --- kernel/cgroup_pids.c | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/kernel/cgroup_pids.c b/kernel/cgroup_pids.c index d75488824ae22..806cd7693ac88 100644 --- a/kernel/cgroup_pids.c +++ b/kernel/cgroup_pids.c @@ -173,11 +173,11 @@ static int pids_can_attach(struct cgroup_subsys_state *css, struct pids_cgroup *old_pids; /* - * Grab a ref to each task's css. We don't drop the ref until - * we either fail and hit ->cancel_attach() or succeed and hit - * ->attach(). + * No need to pin @old_css between here and cancel_attach() + * because cgroup core protects it from being freed before + * the migration completes or fails. */ - old_css = task_get_css(task, pids_cgrp_id); + old_css = task_css(task, pids_cgrp_id); old_pids = css_pids(old_css); pids_charge(pids, 1); @@ -202,19 +202,9 @@ static void pids_cancel_attach(struct cgroup_subsys_state *css, pids_charge(old_pids, 1); pids_uncharge(pids, 1); - css_put(old_css); } } -static void pids_attach(struct cgroup_subsys_state *css, - struct cgroup_taskset *tset) -{ - struct task_struct *task; - - cgroup_taskset_for_each(task, tset) - css_put(task_css(task, pids_cgrp_id)); -} - static int pids_can_fork(struct task_struct *task, void **priv_p) { struct cgroup_subsys_state *css; @@ -354,7 +344,6 @@ static struct cftype pids_files[] = { struct cgroup_subsys pids_cgrp_subsys = { .css_alloc = pids_css_alloc, .css_free = pids_css_free, - .attach = pids_attach, .can_attach = pids_can_attach, .cancel_attach = pids_cancel_attach, .can_fork = pids_can_fork, -- GitLab From 6f021c62d64f38092bc2a0c5fe7b81d5e5b21a00 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Aug 2015 12:30:00 -0700 Subject: [PATCH 4823/7006] tcp: fix slow start after idle vs TSO/GSO slow start after idle might reduce cwnd, but we perform this after first packet was cooked and sent. With TSO/GSO, it means that we might send a full TSO packet even if cwnd should have been reduced to IW10. Moving the SSAI check in skb_entail() makes sense, because we slightly reduce number of times this check is done, especially for large send() and TCP Small queue callbacks from softirq context. As Neal pointed out, we also need to perform the check if/when receive window opens. Tested: Following packetdrill test demonstrates the problem // Test of slow start after idle `sysctl -q net.ipv4.tcp_slow_start_after_idle=1` 0.000 socket(..., SOCK_STREAM, IPPROTO_TCP) = 3 +0 setsockopt(3, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 +0 bind(3, ..., ...) = 0 +0 listen(3, 1) = 0 +0 < S 0:0(0) win 65535 +0 > S. 0:0(0) ack 1 +.100 < . 1:1(0) ack 1 win 511 +0 accept(3, ..., ...) = 4 +0 setsockopt(4, SOL_SOCKET, SO_SNDBUF, [200000], 4) = 0 +0 write(4, ..., 26000) = 26000 +0 > . 1:5001(5000) ack 1 +0 > . 5001:10001(5000) ack 1 +0 %{ assert tcpi_snd_cwnd == 10 }% +.100 < . 1:1(0) ack 10001 win 511 +0 %{ assert tcpi_snd_cwnd == 20, tcpi_snd_cwnd }% +0 > . 10001:20001(10000) ack 1 +0 > P. 20001:26001(6000) ack 1 +.100 < . 1:1(0) ack 26001 win 511 +0 %{ assert tcpi_snd_cwnd == 36, tcpi_snd_cwnd }% +4 write(4, ..., 20000) = 20000 // If slow start after idle works properly, we should send 5 MSS here (cwnd/2) +0 > . 26001:31001(5000) ack 1 +0 %{ assert tcpi_snd_cwnd == 10, tcpi_snd_cwnd }% +0 > . 31001:36001(5000) ack 1 Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- include/net/tcp.h | 13 +++++++++++++ net/ipv4/tcp.c | 2 ++ net/ipv4/tcp_input.c | 3 +++ net/ipv4/tcp_output.c | 12 ++++-------- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/include/net/tcp.h b/include/net/tcp.h index 364426a2be5a0..309801f7eb826 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1165,6 +1165,19 @@ static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) } u32 tcp_default_init_rwnd(u32 mss); +void tcp_cwnd_restart(struct sock *sk, s32 delta); + +static inline void tcp_slow_start_after_idle_check(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + s32 delta; + + if (!sysctl_tcp_slow_start_after_idle || tp->packets_out) + return; + delta = tcp_time_stamp - tp->lsndtime; + if (delta > inet_csk(sk)->icsk_rto) + tcp_cwnd_restart(sk, delta); +} /* Determine a window scaling and initial window to offer. */ void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 45534a5ab4306..b8b8fa184f757 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -627,6 +627,8 @@ static void skb_entail(struct sock *sk, struct sk_buff *skb) sk_mem_charge(sk, skb->truesize); if (tp->nonagle & TCP_NAGLE_PUSH) tp->nonagle &= ~TCP_NAGLE_PUSH; + + tcp_slow_start_after_idle_check(sk); } static inline void tcp_mark_urg(struct tcp_sock *tp, int flags) diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 4e4d6bcd0ca97..0abca2841de2a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3332,6 +3332,9 @@ static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 tp->pred_flags = 0; tcp_fast_path_check(sk); + if (tcp_send_head(sk)) + tcp_slow_start_after_idle_check(sk); + if (nwin > tp->max_window) { tp->max_window = nwin; tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie); diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 444ab5beecbd0..1188e4fcf23bf 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -137,12 +137,12 @@ static __u16 tcp_advertise_mss(struct sock *sk) } /* RFC2861. Reset CWND after idle period longer RTO to "restart window". - * This is the first part of cwnd validation mechanism. */ -static void tcp_cwnd_restart(struct sock *sk, const struct dst_entry *dst) + * This is the first part of cwnd validation mechanism. + */ +void tcp_cwnd_restart(struct sock *sk, s32 delta) { struct tcp_sock *tp = tcp_sk(sk); - s32 delta = tcp_time_stamp - tp->lsndtime; - u32 restart_cwnd = tcp_init_cwnd(tp, dst); + u32 restart_cwnd = tcp_init_cwnd(tp, __sk_dst_get(sk)); u32 cwnd = tp->snd_cwnd; tcp_ca_event(sk, CA_EVENT_CWND_RESTART); @@ -164,10 +164,6 @@ static void tcp_event_data_sent(struct tcp_sock *tp, struct inet_connection_sock *icsk = inet_csk(sk); const u32 now = tcp_time_stamp; - if (sysctl_tcp_slow_start_after_idle && - (!tp->packets_out && (s32)(now - tp->lsndtime) > icsk->icsk_rto)) - tcp_cwnd_restart(sk, __sk_dst_get(sk)); - tp->lsndtime = now; /* If it is a reply for ato after last received -- GitLab From 4ec3b28c2763e11a423d03810ff0be65f02e635e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 20 Aug 2015 15:06:30 -0700 Subject: [PATCH 4824/7006] xfrm: Use VRF master index if output device is enslaved Directs route lookups to VRF table. Compiles out if NET_VRF is not enabled. With this patch able to successfully bring up ipsec tunnels in VRFs, even with duplicate network configuration. Signed-off-by: David Ahern Acked-by: Nikolay Aleksandrov Acked-by: Steffen Klassert Signed-off-by: David S. Miller --- net/ipv4/xfrm4_policy.c | 7 +++++-- net/ipv6/xfrm6_policy.c | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index 55b3c0f4dde5b..bb919b28619fb 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -15,6 +15,7 @@ #include #include #include +#include static struct xfrm_policy_afinfo xfrm4_policy_afinfo; @@ -107,8 +108,10 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) struct flowi4 *fl4 = &fl->u.ip4; int oif = 0; - if (skb_dst(skb)) - oif = skb_dst(skb)->dev->ifindex; + if (skb_dst(skb)) { + oif = vrf_master_ifindex(skb_dst(skb)->dev) ? + : skb_dst(skb)->dev->ifindex; + } memset(fl4, 0, sizeof(struct flowi4)); fl4->flowi4_mark = skb->mark; diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index a74013d3eceb4..30caa289c5dbf 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -20,6 +20,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_IPV6_MIP6) #include #endif @@ -131,8 +132,10 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) nexthdr = nh[nhoff]; - if (skb_dst(skb)) - oif = skb_dst(skb)->dev->ifindex; + if (skb_dst(skb)) { + oif = vrf_master_ifindex(skb_dst(skb)->dev) ? + : skb_dst(skb)->dev->ifindex; + } memset(fl6, 0, sizeof(struct flowi6)); fl6->flowi6_mark = skb->mark; -- GitLab From 43e122b014c955a33220fabbd09c4b5e4f422c3c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 21 Aug 2015 17:38:02 -0700 Subject: [PATCH 4825/7006] tcp: refine pacing rate determination When TCP pacing was added back in linux-3.12, we chose to apply a fixed ratio of 200 % against current rate, to allow probing for optimal throughput even during slow start phase, where cwnd can be doubled every other gRTT. At Google, we found it was better applying a different ratio while in Congestion Avoidance phase. This ratio was set to 120 %. We've used the normal tcp_in_slow_start() helper for a while, then tuned the condition to select the conservative ratio as soon as cwnd >= ssthresh/2 : - After cwnd reduction, it is safer to ramp up more slowly, as we approach optimal cwnd. - Initial ramp up (ssthresh == INFINITY) still allows doubling cwnd every other RTT. Signed-off-by: Eric Dumazet Cc: Neal Cardwell Cc: Yuchung Cheng Acked-by: Neal Cardwell Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 15 +++++++++++++++ include/net/tcp.h | 2 ++ net/ipv4/sysctl_net_ipv4.c | 19 +++++++++++++++++++ net/ipv4/tcp_input.c | 18 +++++++++++++++++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index 46e88ed7f41d2..ac77a13d2ea2c 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -586,6 +586,21 @@ tcp_min_tso_segs - INTEGER if available window is too small. Default: 2 +tcp_pacing_ss_ratio - INTEGER + sk->sk_pacing_rate is set by TCP stack using a ratio applied + to current rate. (current_rate = cwnd * mss / srtt) + If TCP is in slow start, tcp_pacing_ss_ratio is applied + to let TCP probe for bigger speeds, assuming cwnd can be + doubled every other RTT. + Default: 200 + +tcp_pacing_ca_ratio - INTEGER + sk->sk_pacing_rate is set by TCP stack using a ratio applied + to current rate. (current_rate = cwnd * mss / srtt) + If TCP is in congestion avoidance phase, tcp_pacing_ca_ratio + is applied to conservatively probe for bigger throughput. + Default: 120 + tcp_tso_win_divisor - INTEGER This allows control over what percentage of the congestion window can be consumed by a single TSO frame. diff --git a/include/net/tcp.h b/include/net/tcp.h index 309801f7eb826..4a7b03947a38b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -281,6 +281,8 @@ extern unsigned int sysctl_tcp_notsent_lowat; extern int sysctl_tcp_min_tso_segs; extern int sysctl_tcp_autocorking; extern int sysctl_tcp_invalid_ratelimit; +extern int sysctl_tcp_pacing_ss_ratio; +extern int sysctl_tcp_pacing_ca_ratio; extern atomic_long_t tcp_memory_allocated; extern struct percpu_counter tcp_sockets_allocated; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 0330ab2e2b632..879bdc5c95b1d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -29,6 +29,7 @@ static int zero; static int one = 1; static int four = 4; +static int thousand = 1000; static int gso_max_segs = GSO_MAX_SEGS; static int tcp_retr1_max = 255; static int ip_local_port_range_min[] = { 1, 1 }; @@ -711,6 +712,24 @@ static struct ctl_table ipv4_table[] = { .extra1 = &one, .extra2 = &gso_max_segs, }, + { + .procname = "tcp_pacing_ss_ratio", + .data = &sysctl_tcp_pacing_ss_ratio, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &thousand, + }, + { + .procname = "tcp_pacing_ca_ratio", + .data = &sysctl_tcp_pacing_ca_ratio, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax, + .extra1 = &zero, + .extra2 = &thousand, + }, { .procname = "tcp_autocorking", .data = &sysctl_tcp_autocorking, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 0abca2841de2a..dc08e23526652 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -753,13 +753,29 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us) * TCP pacing, to smooth the burst on large writes when packets * in flight is significantly lower than cwnd (or rwin) */ +int sysctl_tcp_pacing_ss_ratio __read_mostly = 200; +int sysctl_tcp_pacing_ca_ratio __read_mostly = 120; + static void tcp_update_pacing_rate(struct sock *sk) { const struct tcp_sock *tp = tcp_sk(sk); u64 rate; /* set sk_pacing_rate to 200 % of current rate (mss * cwnd / srtt) */ - rate = (u64)tp->mss_cache * 2 * (USEC_PER_SEC << 3); + rate = (u64)tp->mss_cache * ((USEC_PER_SEC / 100) << 3); + + /* current rate is (cwnd * mss) / srtt + * In Slow Start [1], set sk_pacing_rate to 200 % the current rate. + * In Congestion Avoidance phase, set it to 120 % the current rate. + * + * [1] : Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh) + * If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching + * end of slow start and should slow down. + */ + if (tp->snd_cwnd < tp->snd_ssthresh / 2) + rate *= sysctl_tcp_pacing_ss_ratio; + else + rate *= sysctl_tcp_pacing_ca_ratio; rate *= max(tp->snd_cwnd, tp->packets_out); -- GitLab From aaae3f00d3f67f681a1f3cb7af999e976e8a24ce Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 20 Aug 2015 18:56:07 -0500 Subject: [PATCH 4826/7006] NFSv4: Force a post-op attribute update when holding a delegation If the ctime or mtime or change attribute have changed because of an operation we initiated, we should make sure that we force an attribute update. However we do not want to mark the page cache for revalidation. Signed-off-by: Trond Myklebust Cc: stable@vger.kernel.org # v4.0+ --- fs/nfs/inode.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 2744d48bbbfec..e2cc0031decb6 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -1477,6 +1477,13 @@ static int nfs_post_op_update_inode_locked(struct inode *inode, struct nfs_fattr { unsigned long invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + /* + * Don't revalidate the pagecache if we hold a delegation, but do + * force an attribute update + */ + if (NFS_PROTO(inode)->have_delegation(inode, FMODE_READ)) + invalid = NFS_INO_INVALID_ATTR|NFS_INO_REVAL_FORCED; + if (S_ISDIR(inode->i_mode)) invalid |= NFS_INO_INVALID_DATA; nfs_set_cache_invalid(inode, invalid); -- GitLab From 6a463beb9a433d91f3eaf85c2f0ca0aeddf3e0ab Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 20 Aug 2015 15:40:47 -0500 Subject: [PATCH 4827/7006] NFSv4.1/pnfs: Add a tracepoint for return-on-close events Allow tracing of return-on-close. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4trace.h | 1 + fs/nfs/pnfs.c | 1 + 2 files changed, 2 insertions(+) diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 470af1a78becf..0b67f7825d00a 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -1136,6 +1136,7 @@ TRACE_EVENT(nfs4_layoutget, DEFINE_NFS4_INODE_EVENT(nfs4_layoutcommit); DEFINE_NFS4_INODE_EVENT(nfs4_layoutreturn); +DEFINE_NFS4_INODE_EVENT(nfs4_layoutreturn_on_close); #endif /* CONFIG_NFS_V4_1 */ diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 8a3f30b695e28..cf90eeda9d719 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1144,6 +1144,7 @@ void pnfs_roc_set_barrier(struct inode *ino, u32 barrier) if (pnfs_seqid_is_newer(barrier, lo->plh_barrier)) lo->plh_barrier = barrier; spin_unlock(&ino->i_lock); + trace_nfs4_layoutreturn_on_close(ino, 0); } void pnfs_roc_get_barrier(struct inode *ino, u32 *barrier) -- GitLab From 7cd148610af9312aa6454395fe174ebfe9496aa1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 20 Aug 2015 20:07:54 -0500 Subject: [PATCH 4828/7006] NFSv4: Add a tracepoint for CB_GETATTR Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 6 ++++- fs/nfs/nfs4trace.h | 59 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 624bef79ba7c2..07258d269e5ae 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -40,8 +40,11 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); inode = nfs_delegation_find_inode(cps->clp, &args->fh); - if (inode == NULL) + if (inode == NULL) { + trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, + -ntohl(res->status)); goto out; + } nfsi = NFS_I(inode); rcu_read_lock(); delegation = rcu_dereference(nfsi->delegation); @@ -60,6 +63,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, res->status = 0; out_iput: rcu_read_unlock(); + trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, -ntohl(res->status)); iput(inode); out: dprintk("%s: exit with status = %d\n", __func__, ntohl(res->status)); diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 0b67f7825d00a..1aa096b665dc6 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -884,6 +884,65 @@ DEFINE_NFS4_GETATTR_EVENT(nfs4_getattr); DEFINE_NFS4_GETATTR_EVENT(nfs4_lookup_root); DEFINE_NFS4_GETATTR_EVENT(nfs4_fsinfo); +DECLARE_EVENT_CLASS(nfs4_inode_callback_event, + TP_PROTO( + const struct nfs_client *clp, + const struct nfs_fh *fhandle, + const struct inode *inode, + int error + ), + + TP_ARGS(clp, fhandle, inode, error), + + TP_STRUCT__entry( + __field(int, error) + __field(dev_t, dev) + __field(u32, fhandle) + __field(u64, fileid) + __string(dstaddr, clp ? + rpc_peeraddr2str(clp->cl_rpcclient, + RPC_DISPLAY_ADDR) : "unknown") + ), + + TP_fast_assign( + __entry->error = error; + __entry->fhandle = nfs_fhandle_hash(fhandle); + if (inode != NULL) { + __entry->fileid = NFS_FILEID(inode); + __entry->dev = inode->i_sb->s_dev; + } else { + __entry->fileid = 0; + __entry->dev = 0; + } + __assign_str(dstaddr, clp ? + rpc_peeraddr2str(clp->cl_rpcclient, + RPC_DISPLAY_ADDR) : "unknown") + ), + + TP_printk( + "error=%d (%s) fileid=%02x:%02x:%llu fhandle=0x%08x " + "dstaddr=%s", + __entry->error, + show_nfsv4_errors(__entry->error), + MAJOR(__entry->dev), MINOR(__entry->dev), + (unsigned long long)__entry->fileid, + __entry->fhandle, + __get_str(dstaddr) + ) +); + +#define DEFINE_NFS4_INODE_CALLBACK_EVENT(name) \ + DEFINE_EVENT(nfs4_inode_callback_event, name, \ + TP_PROTO( \ + const struct nfs_client *clp, \ + const struct nfs_fh *fhandle, \ + const struct inode *inode, \ + int error \ + ), \ + TP_ARGS(clp, fhandle, inode, error)) +DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_getattr); + + DECLARE_EVENT_CLASS(nfs4_idmap_event, TP_PROTO( const char *name, -- GitLab From 249b2eef647f97164b8bb61f2d9282f227a17992 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 20 Aug 2015 20:43:14 -0500 Subject: [PATCH 4829/7006] NFSv4: Add a tracepoint for CB_LAYOUTRECALL Only support for single file layoutrecall for now. Signed-off-by: Trond Myklebust --- fs/nfs/callback_proc.c | 3 ++- fs/nfs/nfs4trace.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 07258d269e5ae..b85cf7a30232a 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c @@ -41,7 +41,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, inode = nfs_delegation_find_inode(cps->clp, &args->fh); if (inode == NULL) { - trace_nfs4_cb_getattr(cps->clp, &args->fh, inode, + trace_nfs4_cb_getattr(cps->clp, &args->fh, NULL, -ntohl(res->status)); goto out; } @@ -198,6 +198,7 @@ unlock: spin_unlock(&ino->i_lock); pnfs_free_lseg_list(&free_me_list); pnfs_put_layout_hdr(lo); + trace_nfs4_cb_layoutrecall_inode(clp, &args->cbl_fh, ino, -rv); iput(ino); out: return rv; diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 1aa096b665dc6..28df12e525bac 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h @@ -941,6 +941,7 @@ DECLARE_EVENT_CLASS(nfs4_inode_callback_event, ), \ TP_ARGS(clp, fhandle, inode, error)) DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_getattr); +DEFINE_NFS4_INODE_CALLBACK_EVENT(nfs4_cb_layoutrecall_inode); DECLARE_EVENT_CLASS(nfs4_idmap_event, -- GitLab From 3976143b063e3c42fe5471d87860f6ae118e0eee Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Fri, 21 Aug 2015 12:49:44 +0800 Subject: [PATCH 4830/7006] NFS41: remove NFS_LAYOUT_ROC flag If we return delegation before closing, we fail to do roc check during close because NFS_LAYOUT_ROC is cleared by delegreturn and it causes layouts to be still hanging around after delegreturn + close, which is a voilation against protocol. Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 7 ++----- fs/nfs/pnfs.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index cf90eeda9d719..247c5a5d2d6b8 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1068,8 +1068,7 @@ bool pnfs_roc(struct inode *ino) spin_lock(&ino->i_lock); lo = nfsi->layout; - if (!lo || !test_and_clear_bit(NFS_LAYOUT_ROC, &lo->plh_flags) || - test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) + if (!lo || test_bit(NFS_LAYOUT_BULK_RECALL, &lo->plh_flags)) goto out_noroc; /* no roc if we hold a delegation */ @@ -1617,10 +1616,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) pnfs_get_lseg(lseg); pnfs_layout_insert_lseg(lo, lseg); - if (res->return_on_close) { + if (res->return_on_close) set_bit(NFS_LSEG_ROC, &lseg->pls_flags); - set_bit(NFS_LAYOUT_ROC, &lo->plh_flags); - } spin_unlock(&ino->i_lock); pnfs_free_lseg_list(&free_me); diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index a3d57a8fac762..02c27f93caf11 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -94,7 +94,6 @@ enum { NFS_LAYOUT_RO_FAILED = 0, /* get ro layout failed stop trying */ NFS_LAYOUT_RW_FAILED, /* get rw layout failed stop trying */ NFS_LAYOUT_BULK_RECALL, /* bulk recall affecting layout */ - NFS_LAYOUT_ROC, /* some lseg had roc bit set */ NFS_LAYOUT_RETURN, /* Return this layout ASAP */ NFS_LAYOUT_RETURN_BEFORE_CLOSE, /* Return this layout before close */ NFS_LAYOUT_INVALID_STID, /* layout stateid id is invalid */ -- GitLab From 5420401079e152ff68a8024f6a375804b1c21505 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Sat, 22 Aug 2015 06:40:00 +0800 Subject: [PATCH 4831/7006] NFS41/flexfiles: zero out DS write wcc We do not want to update inode attributes with DS values. Cc: stable@vger.kernel.org # v4.0+ Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 7e4cbdfb37131..cc2c5f7f2bc19 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -1218,6 +1218,8 @@ static int ff_layout_write_done_cb(struct rpc_task *task, hdr->res.verf->committed == NFS_DATA_SYNC) ff_layout_set_layoutcommit(hdr); + /* zero out fattr since we don't care DS attr at all */ + hdr->fattr.valid = 0; if (task->tk_status >= 0) nfs_writeback_update_inode(hdr); -- GitLab From a6970317f2d5f596302d957ae2f5b0d7c8676371 Mon Sep 17 00:00:00 2001 From: Oleg Drokin Date: Tue, 18 Aug 2015 21:04:35 -0400 Subject: [PATCH 4832/7006] staging/lustre/o2iblnd: remove references to ib_reg_phsy_mr() Removed references to ib_reg_phsy_mr() and PMR which was added to deal with some Chelsio specific scenario, but no longer needed now. Reported-by: Stephen Rothwell Signed-off-by: Amir Shehata Signed-off-by: Oleg Drokin Signed-off-by: Greg Kroah-Hartman Signed-off-by: Trond Myklebust --- .../lustre/lnet/klnds/o2iblnd/o2iblnd.c | 251 +----------------- .../lustre/lnet/klnds/o2iblnd/o2iblnd.h | 32 +-- .../lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c | 55 +--- .../lnet/klnds/o2iblnd/o2iblnd_modparams.c | 6 - 4 files changed, 19 insertions(+), 325 deletions(-) diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c index 4eb24a11b02a3..3c3e79a51a0fa 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c @@ -1789,140 +1789,6 @@ struct list_head *kiblnd_pool_alloc_node(kib_poolset_t *ps) goto again; } -void kiblnd_pmr_pool_unmap(kib_phys_mr_t *pmr) -{ - kib_pmr_pool_t *ppo = pmr->pmr_pool; - struct ib_mr *mr = pmr->pmr_mr; - - pmr->pmr_mr = NULL; - kiblnd_pool_free_node(&ppo->ppo_pool, &pmr->pmr_list); - if (mr != NULL) - ib_dereg_mr(mr); -} - -int kiblnd_pmr_pool_map(kib_pmr_poolset_t *pps, kib_hca_dev_t *hdev, - kib_rdma_desc_t *rd, __u64 *iova, kib_phys_mr_t **pp_pmr) -{ - kib_phys_mr_t *pmr; - struct list_head *node; - int rc; - int i; - - node = kiblnd_pool_alloc_node(&pps->pps_poolset); - if (node == NULL) { - CERROR("Failed to allocate PMR descriptor\n"); - return -ENOMEM; - } - - pmr = container_of(node, kib_phys_mr_t, pmr_list); - if (pmr->pmr_pool->ppo_hdev != hdev) { - kiblnd_pool_free_node(&pmr->pmr_pool->ppo_pool, node); - return -EAGAIN; - } - - for (i = 0; i < rd->rd_nfrags; i++) { - pmr->pmr_ipb[i].addr = rd->rd_frags[i].rf_addr; - pmr->pmr_ipb[i].size = rd->rd_frags[i].rf_nob; - } - - pmr->pmr_mr = ib_reg_phys_mr(hdev->ibh_pd, - pmr->pmr_ipb, rd->rd_nfrags, - IB_ACCESS_LOCAL_WRITE | - IB_ACCESS_REMOTE_WRITE, - iova); - if (!IS_ERR(pmr->pmr_mr)) { - pmr->pmr_iova = *iova; - *pp_pmr = pmr; - return 0; - } - - rc = PTR_ERR(pmr->pmr_mr); - CERROR("Failed ib_reg_phys_mr: %d\n", rc); - - pmr->pmr_mr = NULL; - kiblnd_pool_free_node(&pmr->pmr_pool->ppo_pool, node); - - return rc; -} - -static void kiblnd_destroy_pmr_pool(kib_pool_t *pool) -{ - kib_pmr_pool_t *ppo = container_of(pool, kib_pmr_pool_t, ppo_pool); - kib_phys_mr_t *pmr; - kib_phys_mr_t *tmp; - - LASSERT(pool->po_allocated == 0); - - list_for_each_entry_safe(pmr, tmp, &pool->po_free_list, pmr_list) { - LASSERT(pmr->pmr_mr == NULL); - list_del(&pmr->pmr_list); - - if (pmr->pmr_ipb != NULL) { - LIBCFS_FREE(pmr->pmr_ipb, - IBLND_MAX_RDMA_FRAGS * - sizeof(struct ib_phys_buf)); - } - - LIBCFS_FREE(pmr, sizeof(kib_phys_mr_t)); - } - - kiblnd_fini_pool(pool); - if (ppo->ppo_hdev != NULL) - kiblnd_hdev_decref(ppo->ppo_hdev); - - LIBCFS_FREE(ppo, sizeof(kib_pmr_pool_t)); -} - -static inline int kiblnd_pmr_pool_size(int ncpts) -{ - int size = *kiblnd_tunables.kib_pmr_pool_size / ncpts; - - return max(IBLND_PMR_POOL, size); -} - -static int kiblnd_create_pmr_pool(kib_poolset_t *ps, int size, - kib_pool_t **pp_po) -{ - struct kib_pmr_pool *ppo; - struct kib_pool *pool; - kib_phys_mr_t *pmr; - int i; - - LIBCFS_CPT_ALLOC(ppo, lnet_cpt_table(), - ps->ps_cpt, sizeof(kib_pmr_pool_t)); - if (ppo == NULL) { - CERROR("Failed to allocate PMR pool\n"); - return -ENOMEM; - } - - pool = &ppo->ppo_pool; - kiblnd_init_pool(ps, pool, size); - - for (i = 0; i < size; i++) { - LIBCFS_CPT_ALLOC(pmr, lnet_cpt_table(), - ps->ps_cpt, sizeof(kib_phys_mr_t)); - if (pmr == NULL) - break; - - pmr->pmr_pool = ppo; - LIBCFS_CPT_ALLOC(pmr->pmr_ipb, lnet_cpt_table(), ps->ps_cpt, - IBLND_MAX_RDMA_FRAGS * sizeof(*pmr->pmr_ipb)); - if (pmr->pmr_ipb == NULL) - break; - - list_add(&pmr->pmr_list, &pool->po_free_list); - } - - if (i < size) { - ps->ps_pool_destroy(pool); - return -ENOMEM; - } - - ppo->ppo_hdev = kiblnd_current_hdev(ps->ps_net->ibn_dev); - *pp_po = pool; - return 0; -} - static void kiblnd_destroy_tx_pool(kib_pool_t *pool) { kib_tx_pool_t *tpo = container_of(pool, kib_tx_pool_t, tpo_pool); @@ -2078,7 +1944,6 @@ static void kiblnd_net_fini_pools(kib_net_t *net) cfs_cpt_for_each(i, lnet_cpt_table()) { kib_tx_poolset_t *tps; kib_fmr_poolset_t *fps; - kib_pmr_poolset_t *pps; if (net->ibn_tx_ps != NULL) { tps = net->ibn_tx_ps[i]; @@ -2089,11 +1954,6 @@ static void kiblnd_net_fini_pools(kib_net_t *net) fps = net->ibn_fmr_ps[i]; kiblnd_fini_fmr_poolset(fps); } - - if (net->ibn_pmr_ps != NULL) { - pps = net->ibn_pmr_ps[i]; - kiblnd_fini_poolset(&pps->pps_poolset); - } } if (net->ibn_tx_ps != NULL) { @@ -2105,18 +1965,13 @@ static void kiblnd_net_fini_pools(kib_net_t *net) cfs_percpt_free(net->ibn_fmr_ps); net->ibn_fmr_ps = NULL; } - - if (net->ibn_pmr_ps != NULL) { - cfs_percpt_free(net->ibn_pmr_ps); - net->ibn_pmr_ps = NULL; - } } static int kiblnd_net_init_pools(kib_net_t *net, __u32 *cpts, int ncpts) { unsigned long flags; int cpt; - int rc; + int rc = 0; int i; read_lock_irqsave(&kiblnd_data.kib_global_lock, flags); @@ -2137,12 +1992,16 @@ static int kiblnd_net_init_pools(kib_net_t *net, __u32 *cpts, int ncpts) goto failed; } - /* TX pool must be created later than FMR/PMR, see LU-2268 - * for details */ + /* + * TX pool must be created later than FMR, see LU-2268 + * for details + */ LASSERT(net->ibn_tx_ps == NULL); - /* premapping can fail if ibd_nmr > 1, so we always create - * FMR/PMR pool and map-on-demand if premapping failed */ + /* + * premapping can fail if ibd_nmr > 1, so we always create + * FMR pool and map-on-demand if premapping failed + */ net->ibn_fmr_ps = cfs_percpt_alloc(lnet_cpt_table(), sizeof(kib_fmr_poolset_t)); @@ -2158,7 +2017,7 @@ static int kiblnd_net_init_pools(kib_net_t *net, __u32 *cpts, int ncpts) kiblnd_fmr_pool_size(ncpts), kiblnd_fmr_flush_trigger(ncpts)); if (rc == -ENOSYS && i == 0) /* no FMR */ - break; /* create PMR pool */ + break; if (rc != 0) { /* a real error */ CERROR("Can't initialize FMR pool for CPT %d: %d\n", @@ -2175,38 +2034,8 @@ static int kiblnd_net_init_pools(kib_net_t *net, __u32 *cpts, int ncpts) cfs_percpt_free(net->ibn_fmr_ps); net->ibn_fmr_ps = NULL; - CWARN("Device does not support FMR, failing back to PMR\n"); - - if (*kiblnd_tunables.kib_pmr_pool_size < - *kiblnd_tunables.kib_ntx / 4) { - CERROR("Can't set pmr pool size (%d) < ntx / 4(%d)\n", - *kiblnd_tunables.kib_pmr_pool_size, - *kiblnd_tunables.kib_ntx / 4); - rc = -EINVAL; - goto failed; - } - - net->ibn_pmr_ps = cfs_percpt_alloc(lnet_cpt_table(), - sizeof(kib_pmr_poolset_t)); - if (net->ibn_pmr_ps == NULL) { - CERROR("Failed to allocate PMR pool array\n"); - rc = -ENOMEM; - goto failed; - } - - for (i = 0; i < ncpts; i++) { - cpt = (cpts == NULL) ? i : cpts[i]; - rc = kiblnd_init_poolset(&net->ibn_pmr_ps[cpt]->pps_poolset, - cpt, net, "PMR", - kiblnd_pmr_pool_size(ncpts), - kiblnd_create_pmr_pool, - kiblnd_destroy_pmr_pool, NULL, NULL); - if (rc != 0) { - CERROR("Can't initialize PMR pool for CPT %d: %d\n", - cpt, rc); + CWARN("Device does not support FMR\n"); goto failed; - } - } create_tx_pool: net->ibn_tx_ps = cfs_percpt_alloc(lnet_cpt_table(), @@ -2318,17 +2147,13 @@ void kiblnd_hdev_destroy(kib_hca_dev_t *hdev) static int kiblnd_hdev_setup_mrs(kib_hca_dev_t *hdev) { struct ib_mr *mr; - int i; int rc; - __u64 mm_size; - __u64 mr_size; int acflags = IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_WRITE; rc = kiblnd_hdev_get_attr(hdev); if (rc != 0) return rc; - if (hdev->ibh_mr_shift == 64) { LIBCFS_ALLOC(hdev->ibh_mrs, 1 * sizeof(*hdev->ibh_mrs)); if (hdev->ibh_mrs == NULL) { CERROR("Failed to allocate MRs table\n"); @@ -2347,53 +2172,6 @@ static int kiblnd_hdev_setup_mrs(kib_hca_dev_t *hdev) hdev->ibh_mrs[0] = mr; - goto out; - } - - mr_size = 1ULL << hdev->ibh_mr_shift; - mm_size = (unsigned long)high_memory - PAGE_OFFSET; - - hdev->ibh_nmrs = (int)((mm_size + mr_size - 1) >> hdev->ibh_mr_shift); - - if (hdev->ibh_mr_shift < 32 || hdev->ibh_nmrs > 1024) { - /* it's 4T..., assume we will re-code at that time */ - CERROR("Can't support memory size: x%#llx with MR size: x%#llx\n", - mm_size, mr_size); - return -EINVAL; - } - - /* create an array of MRs to cover all memory */ - LIBCFS_ALLOC(hdev->ibh_mrs, sizeof(*hdev->ibh_mrs) * hdev->ibh_nmrs); - if (hdev->ibh_mrs == NULL) { - CERROR("Failed to allocate MRs' table\n"); - return -ENOMEM; - } - - for (i = 0; i < hdev->ibh_nmrs; i++) { - struct ib_phys_buf ipb; - __u64 iova; - - ipb.size = hdev->ibh_mr_size; - ipb.addr = i * mr_size; - iova = ipb.addr; - - mr = ib_reg_phys_mr(hdev->ibh_pd, &ipb, 1, acflags, &iova); - if (IS_ERR(mr)) { - CERROR("Failed ib_reg_phys_mr addr %#llx size %#llx : %ld\n", - ipb.addr, ipb.size, PTR_ERR(mr)); - kiblnd_hdev_cleanup_mrs(hdev); - return PTR_ERR(mr); - } - - LASSERT(iova == ipb.addr); - - hdev->ibh_mrs[i] = mr; - } - -out: - if (hdev->ibh_mr_size != ~0ULL || hdev->ibh_nmrs != 1) - LCONSOLE_INFO("Register global MR array, MR size: %#llx, array size: %d\n", - hdev->ibh_mr_size, hdev->ibh_nmrs); return 0; } @@ -2564,14 +2342,9 @@ int kiblnd_dev_failover(kib_dev_t *dev) kiblnd_fail_poolset(&net->ibn_tx_ps[i]->tps_poolset, &zombie_tpo); - if (net->ibn_fmr_ps != NULL) { + if (net->ibn_fmr_ps) kiblnd_fail_fmr_poolset(net->ibn_fmr_ps[i], &zombie_fpo); - - } else if (net->ibn_pmr_ps != NULL) { - kiblnd_fail_poolset(&net->ibn_pmr_ps[i]-> - pps_poolset, &zombie_ppo); - } } } diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h index f5d1d9f8f1ed3..2687ae39fcbbf 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h @@ -104,7 +104,6 @@ typedef struct { int *kib_map_on_demand; /* map-on-demand if RD has more * fragments than this value, 0 * disable map-on-demand */ - int *kib_pmr_pool_size; /* # physical MR in pool */ int *kib_fmr_pool_size; /* # FMRs in pool */ int *kib_fmr_flush_trigger; /* When to trigger FMR flush */ int *kib_fmr_cache; /* enable FMR pool cache? */ @@ -163,7 +162,6 @@ kiblnd_concurrent_sends_v1(void) /* Pools (shared by connections on each CPT) */ /* These pools can grow at runtime, so don't need give a very large value */ #define IBLND_TX_POOL 256 -#define IBLND_PMR_POOL 256 #define IBLND_FMR_POOL 256 #define IBLND_FMR_POOL_FLUSH 192 @@ -232,17 +230,6 @@ typedef struct { struct page *ibp_pages[0]; /* page array */ } kib_pages_t; -struct kib_pmr_pool; - -typedef struct { - struct list_head pmr_list; /* chain node */ - struct ib_phys_buf *pmr_ipb; /* physical buffer */ - struct ib_mr *pmr_mr; /* IB MR */ - struct kib_pmr_pool *pmr_pool; /* owner of this MR */ - __u64 pmr_iova; /* Virtual I/O address */ - int pmr_refcount; /* reference count */ -} kib_phys_mr_t; - struct kib_pool; struct kib_poolset; @@ -298,15 +285,6 @@ typedef struct { kib_pages_t *tpo_tx_pages; /* premapped tx msg pages */ } kib_tx_pool_t; -typedef struct { - kib_poolset_t pps_poolset; /* pool-set */ -} kib_pmr_poolset_t; - -typedef struct kib_pmr_pool { - struct kib_hca_dev *ppo_hdev; /* device for this pool */ - kib_pool_t ppo_pool; /* pool */ -} kib_pmr_pool_t; - typedef struct { spinlock_t fps_lock; /* serialize */ struct kib_net *fps_net; /* IB network */ @@ -347,7 +325,6 @@ typedef struct kib_net { kib_tx_poolset_t **ibn_tx_ps; /* tx pool-set */ kib_fmr_poolset_t **ibn_fmr_ps; /* fmr pool-set */ - kib_pmr_poolset_t **ibn_pmr_ps; /* pmr pool-set */ kib_dev_t *ibn_dev; /* underlying IB device */ } kib_net_t; @@ -554,10 +531,7 @@ typedef struct kib_tx /* transmit message */ int tx_nfrags; /* # entries in... */ struct scatterlist *tx_frags; /* dma_map_sg descriptor */ __u64 *tx_pages; /* rdma phys page addrs */ - union { - kib_phys_mr_t *pmr; /* MR for physical buffer */ - kib_fmr_t fmr; /* FMR */ - } tx_u; + kib_fmr_t fmr; /* FMR */ int tx_dmadir; /* dma direction */ } kib_tx_t; @@ -978,10 +952,6 @@ int kiblnd_fmr_pool_map(kib_fmr_poolset_t *fps, __u64 *pages, int npages, __u64 iov, kib_fmr_t *fmr); void kiblnd_fmr_pool_unmap(kib_fmr_t *fmr, int status); -int kiblnd_pmr_pool_map(kib_pmr_poolset_t *pps, kib_hca_dev_t *hdev, - kib_rdma_desc_t *rd, __u64 *iova, kib_phys_mr_t **pp_pmr); -void kiblnd_pmr_pool_unmap(kib_phys_mr_t *pmr); - int kiblnd_startup (lnet_ni_t *ni); void kiblnd_shutdown (lnet_ni_t *ni); int kiblnd_ctl (lnet_ni_t *ni, unsigned int cmd, void *arg); diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c index 477aa8b76f327..a131024e4932f 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c @@ -121,7 +121,6 @@ kiblnd_get_idle_tx(lnet_ni_t *ni, lnet_nid_t target) LASSERT(tx->tx_conn == NULL); LASSERT(tx->tx_lntmsg[0] == NULL); LASSERT(tx->tx_lntmsg[1] == NULL); - LASSERT(tx->tx_u.pmr == NULL); LASSERT(tx->tx_nfrags == 0); return tx; @@ -575,7 +574,7 @@ kiblnd_fmr_map_tx(kib_net_t *net, kib_tx_t *tx, kib_rdma_desc_t *rd, int nob) cpt = tx->tx_pool->tpo_pool.po_owner->ps_cpt; fps = net->ibn_fmr_ps[cpt]; - rc = kiblnd_fmr_pool_map(fps, pages, npages, 0, &tx->tx_u.fmr); + rc = kiblnd_fmr_pool_map(fps, pages, npages, 0, &tx->fmr); if (rc != 0) { CERROR("Can't map %d pages: %d\n", npages, rc); return rc; @@ -583,8 +582,8 @@ kiblnd_fmr_map_tx(kib_net_t *net, kib_tx_t *tx, kib_rdma_desc_t *rd, int nob) /* If rd is not tx_rd, it's going to get sent to a peer, who will need * the rkey */ - rd->rd_key = (rd != tx->tx_rd) ? tx->tx_u.fmr.fmr_pfmr->fmr->rkey : - tx->tx_u.fmr.fmr_pfmr->fmr->lkey; + rd->rd_key = (rd != tx->tx_rd) ? tx->fmr.fmr_pfmr->fmr->rkey : + tx->fmr.fmr_pfmr->fmr->lkey; rd->rd_frags[0].rf_addr &= ~hdev->ibh_page_mask; rd->rd_frags[0].rf_nob = nob; rd->rd_nfrags = 1; @@ -592,42 +591,6 @@ kiblnd_fmr_map_tx(kib_net_t *net, kib_tx_t *tx, kib_rdma_desc_t *rd, int nob) return 0; } -static int -kiblnd_pmr_map_tx(kib_net_t *net, kib_tx_t *tx, kib_rdma_desc_t *rd, int nob) -{ - kib_hca_dev_t *hdev; - kib_pmr_poolset_t *pps; - __u64 iova; - int cpt; - int rc; - - LASSERT(tx->tx_pool != NULL); - LASSERT(tx->tx_pool->tpo_pool.po_owner != NULL); - - hdev = tx->tx_pool->tpo_hdev; - - iova = rd->rd_frags[0].rf_addr & ~hdev->ibh_page_mask; - - cpt = tx->tx_pool->tpo_pool.po_owner->ps_cpt; - - pps = net->ibn_pmr_ps[cpt]; - rc = kiblnd_pmr_pool_map(pps, hdev, rd, &iova, &tx->tx_u.pmr); - if (rc != 0) { - CERROR("Failed to create MR by phybuf: %d\n", rc); - return rc; - } - - /* If rd is not tx_rd, it's going to get sent to a peer, who will need - * the rkey */ - rd->rd_key = (rd != tx->tx_rd) ? tx->tx_u.pmr->pmr_mr->rkey : - tx->tx_u.pmr->pmr_mr->lkey; - rd->rd_nfrags = 1; - rd->rd_frags[0].rf_addr = iova; - rd->rd_frags[0].rf_nob = nob; - - return 0; -} - void kiblnd_unmap_tx(lnet_ni_t *ni, kib_tx_t *tx) { @@ -635,13 +598,9 @@ kiblnd_unmap_tx(lnet_ni_t *ni, kib_tx_t *tx) LASSERT(net != NULL); - if (net->ibn_fmr_ps != NULL && tx->tx_u.fmr.fmr_pfmr != NULL) { - kiblnd_fmr_pool_unmap(&tx->tx_u.fmr, tx->tx_status); - tx->tx_u.fmr.fmr_pfmr = NULL; - - } else if (net->ibn_pmr_ps != NULL && tx->tx_u.pmr != NULL) { - kiblnd_pmr_pool_unmap(tx->tx_u.pmr); - tx->tx_u.pmr = NULL; + if (net->ibn_fmr_ps && tx->fmr.fmr_pfmr) { + kiblnd_fmr_pool_unmap(&tx->fmr, tx->tx_status); + tx->fmr.fmr_pfmr = NULL; } if (tx->tx_nfrags != 0) { @@ -687,8 +646,6 @@ kiblnd_map_tx(lnet_ni_t *ni, kib_tx_t *tx, if (net->ibn_fmr_ps != NULL) return kiblnd_fmr_map_tx(net, tx, rd, nob); - else if (net->ibn_pmr_ps != NULL) - return kiblnd_pmr_map_tx(net, tx, rd, nob); return -EINVAL; } diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c index b0e00361cfcef..b3d1b5d627cbd 100644 --- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c +++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_modparams.c @@ -126,11 +126,6 @@ static int fmr_cache = 1; module_param(fmr_cache, int, 0444); MODULE_PARM_DESC(fmr_cache, "non-zero to enable FMR caching"); -/* NB: this value is shared by all CPTs, it can grow at runtime */ -static int pmr_pool_size = 512; -module_param(pmr_pool_size, int, 0444); -MODULE_PARM_DESC(pmr_pool_size, "size of MR cache pmr pool on each CPT"); - /* * 0: disable failover * 1: enable failover if necessary @@ -170,7 +165,6 @@ kib_tunables_t kiblnd_tunables = { .kib_fmr_pool_size = &fmr_pool_size, .kib_fmr_flush_trigger = &fmr_flush_trigger, .kib_fmr_cache = &fmr_cache, - .kib_pmr_pool_size = &pmr_pool_size, .kib_require_priv_port = &require_privileged_port, .kib_use_priv_port = &use_privileged_port, .kib_nscheds = &nscheds -- GitLab From 28a0d72c6867af307c000e068a6da93ae98bcd0c Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 24 Aug 2015 18:08:30 -0400 Subject: [PATCH 4833/7006] NFSv4.1/flexfiles: Add refcounting to struct nfs4_ff_layout_mirror We do want to share mirrors between layout segments, so add a refcount to enable that. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 36 +++++++++++++++++++------- fs/nfs/flexfilelayout/flexfilelayout.h | 1 + 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index cc2c5f7f2bc19..62de0b8038c8d 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -135,6 +135,31 @@ decode_name(struct xdr_stream *xdr, u32 *id) return 0; } +static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags) +{ + struct nfs4_ff_layout_mirror *mirror; + + mirror = kzalloc(sizeof(*mirror), gfp_flags); + if (mirror != NULL) { + spin_lock_init(&mirror->lock); + atomic_set(&mirror->ref, 1); + } + return mirror; +} + +static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror) +{ + kfree(mirror->fh_versions); + nfs4_ff_layout_put_deviceid(mirror->mirror_ds); + kfree(mirror); +} + +static void ff_layout_put_mirror(struct nfs4_ff_layout_mirror *mirror) +{ + if (mirror != NULL && atomic_dec_and_test(&mirror->ref)) + ff_layout_free_mirror(mirror); +} + static void ff_layout_free_mirror_array(struct nfs4_ff_layout_segment *fls) { int i; @@ -144,11 +169,7 @@ static void ff_layout_free_mirror_array(struct nfs4_ff_layout_segment *fls) /* normally mirror_ds is freed in * .free_deviceid_node but we still do it here * for .alloc_lseg error path */ - if (fls->mirror_array[i]) { - kfree(fls->mirror_array[i]->fh_versions); - nfs4_ff_layout_put_deviceid(fls->mirror_array[i]->mirror_ds); - kfree(fls->mirror_array[i]); - } + ff_layout_put_mirror(fls->mirror_array[i]); } kfree(fls->mirror_array); fls->mirror_array = NULL; @@ -262,15 +283,12 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, if (ds_count != 1) goto out_err_free; - fls->mirror_array[i] = - kzalloc(sizeof(struct nfs4_ff_layout_mirror), - gfp_flags); + fls->mirror_array[i] = ff_layout_alloc_mirror(gfp_flags); if (fls->mirror_array[i] == NULL) { rc = -ENOMEM; goto out_err_free; } - spin_lock_init(&fls->mirror_array[i]->lock); fls->mirror_array[i]->ds_count = ds_count; fls->mirror_array[i]->lseg = &fls->generic_hdr; diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index f92f9a0a856b3..26b8258e256f8 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h @@ -77,6 +77,7 @@ struct nfs4_ff_layout_mirror { u32 uid; u32 gid; struct rpc_cred *cred; + atomic_t ref; spinlock_t lock; struct nfs4_ff_layoutstat read_stat; struct nfs4_ff_layoutstat write_stat; -- GitLab From 0b7baf9433d4e0a0c83eecbadc1f035d5370c6dc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 24 Aug 2015 18:22:28 -0400 Subject: [PATCH 4834/7006] NFSv4.1/flexfiles: Remove mirror backpointer to lseg. When we start sharing mirrors between several lsegs, we won't be able to keep it. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 25 ++++++++++++------------- fs/nfs/flexfilelayout/flexfilelayout.h | 1 - 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 62de0b8038c8d..f3efff640989b 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -290,7 +290,6 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, } fls->mirror_array[i]->ds_count = ds_count; - fls->mirror_array[i]->lseg = &fls->generic_hdr; /* deviceid */ rc = decode_deviceid(&stream, &devid); @@ -513,7 +512,8 @@ nfs4_ff_layout_stat_io_update_completed(struct nfs4_ff_layoutstat *layoutstat, } static void -nfs4_ff_layout_stat_io_start_read(struct nfs4_ff_layout_mirror *mirror, +nfs4_ff_layout_stat_io_start_read(struct inode *inode, + struct nfs4_ff_layout_mirror *mirror, __u64 requested, ktime_t now) { bool report; @@ -524,8 +524,7 @@ nfs4_ff_layout_stat_io_start_read(struct nfs4_ff_layout_mirror *mirror, spin_unlock(&mirror->lock); if (report) - pnfs_report_layoutstat(mirror->lseg->pls_layout->plh_inode, - GFP_KERNEL); + pnfs_report_layoutstat(inode, GFP_KERNEL); } static void @@ -542,7 +541,8 @@ nfs4_ff_layout_stat_io_end_read(struct rpc_task *task, } static void -nfs4_ff_layout_stat_io_start_write(struct nfs4_ff_layout_mirror *mirror, +nfs4_ff_layout_stat_io_start_write(struct inode *inode, + struct nfs4_ff_layout_mirror *mirror, __u64 requested, ktime_t now) { bool report; @@ -553,8 +553,7 @@ nfs4_ff_layout_stat_io_start_write(struct nfs4_ff_layout_mirror *mirror, spin_unlock(&mirror->lock); if (report) - pnfs_report_layoutstat(mirror->lseg->pls_layout->plh_inode, - GFP_NOIO); + pnfs_report_layoutstat(inode, GFP_NOIO); } static void @@ -1098,7 +1097,7 @@ ff_layout_reset_to_mds(struct pnfs_layout_segment *lseg, int idx) static int ff_layout_read_prepare_common(struct rpc_task *task, struct nfs_pgio_header *hdr) { - nfs4_ff_layout_stat_io_start_read( + nfs4_ff_layout_stat_io_start_read(hdr->inode, FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), hdr->args.count, task->tk_start); @@ -1285,7 +1284,7 @@ static int ff_layout_commit_done_cb(struct rpc_task *task, static int ff_layout_write_prepare_common(struct rpc_task *task, struct nfs_pgio_header *hdr) { - nfs4_ff_layout_stat_io_start_write( + nfs4_ff_layout_stat_io_start_write(hdr->inode, FF_LAYOUT_COMP(hdr->lseg, hdr->pgio_mirror_idx), hdr->args.count, task->tk_start); @@ -1367,7 +1366,7 @@ static void ff_layout_write_count_stats(struct rpc_task *task, void *data) static void ff_layout_commit_prepare_common(struct rpc_task *task, struct nfs_commit_data *cdata) { - nfs4_ff_layout_stat_io_start_write( + nfs4_ff_layout_stat_io_start_write(cdata->inode, FF_LAYOUT_COMP(cdata->lseg, cdata->ds_commit_index), 0, task->tk_start); } @@ -1912,8 +1911,8 @@ ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args, devinfo->layout_type = LAYOUT_FLEX_FILES; devinfo->layoutstats_encode = ff_layout_encode_layoutstats; devinfo->layout_private = mirror; - /* lseg refcount put in cleanup_layoutstats */ - pnfs_get_lseg(pls); + /* mirror refcount put in cleanup_layoutstats */ + atomic_inc(&mirror->ref); ++(*dev_count); } @@ -1965,7 +1964,7 @@ ff_layout_cleanup_layoutstats(struct nfs42_layoutstat_data *data) for (i = 0; i < data->args.num_dev; i++) { mirror = data->args.devinfo[i].layout_private; data->args.devinfo[i].layout_private = NULL; - pnfs_put_lseg(mirror->lseg); + ff_layout_put_mirror(mirror); } } diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index 26b8258e256f8..fe9d3ff7cf852 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h @@ -67,7 +67,6 @@ struct nfs4_ff_layoutstat { }; struct nfs4_ff_layout_mirror { - struct pnfs_layout_segment *lseg; /* back pointer */ u32 ds_count; u32 efficiency; struct nfs4_ff_layout_ds *mirror_ds; -- GitLab From 266d12d42ebd2587d3d0e8c4a4e54bfb5ed29543 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 24 Aug 2015 20:03:17 -0400 Subject: [PATCH 4835/7006] NFSv4.1/flexfile: Ensure uniqueness of mirrors across layout segments Keep the full list of mirrors in the struct nfs4_ff_layout_mirror so that they can be shared among the layout segments that use them. Also ensure that we send out only one copy of the layoutstats per mirror. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 125 +++++++++++++++++++------ fs/nfs/flexfilelayout/flexfilelayout.h | 3 + 2 files changed, 99 insertions(+), 29 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index f3efff640989b..0fbf37de2a410 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -34,6 +34,7 @@ ff_layout_alloc_layout_hdr(struct inode *inode, gfp_t gfp_flags) ffl = kzalloc(sizeof(*ffl), gfp_flags); if (ffl) { INIT_LIST_HEAD(&ffl->error_list); + INIT_LIST_HEAD(&ffl->mirrors); return &ffl->generic_hdr; } else return NULL; @@ -135,6 +136,66 @@ decode_name(struct xdr_stream *xdr, u32 *id) return 0; } +static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1, + const struct nfs4_ff_layout_mirror *m2) +{ + int i, j; + + if (m1->fh_versions_cnt != m2->fh_versions_cnt) + return false; + for (i = 0; i < m1->fh_versions_cnt; i++) { + bool found_fh = false; + for (j = 0; j < m2->fh_versions_cnt; i++) { + if (nfs_compare_fh(&m1->fh_versions[i], + &m2->fh_versions[j]) == 0) { + found_fh = true; + break; + } + } + if (!found_fh) + return false; + } + return true; +} + +static struct nfs4_ff_layout_mirror * +ff_layout_add_mirror(struct pnfs_layout_hdr *lo, + struct nfs4_ff_layout_mirror *mirror) +{ + struct nfs4_flexfile_layout *ff_layout = FF_LAYOUT_FROM_HDR(lo); + struct nfs4_ff_layout_mirror *pos; + struct inode *inode = lo->plh_inode; + + spin_lock(&inode->i_lock); + list_for_each_entry(pos, &ff_layout->mirrors, mirrors) { + if (mirror->mirror_ds != pos->mirror_ds) + continue; + if (!ff_mirror_match_fh(mirror, pos)) + continue; + if (atomic_inc_not_zero(&pos->ref)) { + spin_unlock(&inode->i_lock); + return pos; + } + } + list_add(&mirror->mirrors, &ff_layout->mirrors); + mirror->layout = lo; + spin_unlock(&inode->i_lock); + return mirror; +} + +void +ff_layout_remove_mirror(struct nfs4_ff_layout_mirror *mirror) +{ + struct inode *inode; + if (mirror->layout == NULL) + return; + inode = mirror->layout->plh_inode; + spin_lock(&inode->i_lock); + list_del(&mirror->mirrors); + spin_unlock(&inode->i_lock); + mirror->layout = NULL; +} + static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags) { struct nfs4_ff_layout_mirror *mirror; @@ -143,12 +204,14 @@ static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags) if (mirror != NULL) { spin_lock_init(&mirror->lock); atomic_set(&mirror->ref, 1); + INIT_LIST_HEAD(&mirror->mirrors); } return mirror; } static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror) { + ff_layout_remove_mirror(mirror); kfree(mirror->fh_versions); nfs4_ff_layout_put_deviceid(mirror->mirror_ds); kfree(mirror); @@ -267,6 +330,7 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, goto out_err_free; for (i = 0; i < fls->mirror_array_cnt; i++) { + struct nfs4_ff_layout_mirror *mirror; struct nfs4_deviceid devid; struct nfs4_deviceid_node *idnode; u32 ds_count; @@ -355,6 +419,12 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh, if (rc) goto out_err_free; + mirror = ff_layout_add_mirror(lh, fls->mirror_array[i]); + if (mirror != fls->mirror_array[i]) { + ff_layout_free_mirror(fls->mirror_array[i]); + fls->mirror_array[i] = mirror; + } + dprintk("%s: uid %d gid %d\n", __func__, fls->mirror_array[i]->uid, fls->mirror_array[i]->gid); @@ -1883,27 +1953,30 @@ ff_layout_encode_layoutstats(struct xdr_stream *xdr, *start = cpu_to_be32((xdr->p - start - 1) * 4); } -static bool +static int ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args, - struct pnfs_layout_segment *pls, - int *dev_count, int dev_limit) + struct pnfs_layout_hdr *lo, + int dev_limit) { + struct nfs4_flexfile_layout *ff_layout = FF_LAYOUT_FROM_HDR(lo); struct nfs4_ff_layout_mirror *mirror; struct nfs4_deviceid_node *dev; struct nfs42_layoutstat_devinfo *devinfo; - int i; + int i = 0; - for (i = 0; i < FF_LAYOUT_MIRROR_COUNT(pls); i++) { - if (*dev_count >= dev_limit) + list_for_each_entry(mirror, &ff_layout->mirrors, mirrors) { + if (i >= dev_limit) break; - mirror = FF_LAYOUT_COMP(pls, i); - if (!mirror || !mirror->mirror_ds) + if (!mirror->mirror_ds) continue; - dev = FF_LAYOUT_DEVID_NODE(pls, i); - devinfo = &args->devinfo[*dev_count]; + /* mirror refcount put in cleanup_layoutstats */ + if (!atomic_inc_not_zero(&mirror->ref)) + continue; + dev = &mirror->mirror_ds->id_node; + devinfo = &args->devinfo[i]; memcpy(&devinfo->dev_id, &dev->deviceid, NFS4_DEVICEID4_SIZE); - devinfo->offset = pls->pls_range.offset; - devinfo->length = pls->pls_range.length; + devinfo->offset = 0; + devinfo->length = NFS4_MAX_UINT64; devinfo->read_count = mirror->read_stat.io_stat.ops_completed; devinfo->read_bytes = mirror->read_stat.io_stat.bytes_completed; devinfo->write_count = mirror->write_stat.io_stat.ops_completed; @@ -1911,24 +1984,24 @@ ff_layout_mirror_prepare_stats(struct nfs42_layoutstat_args *args, devinfo->layout_type = LAYOUT_FLEX_FILES; devinfo->layoutstats_encode = ff_layout_encode_layoutstats; devinfo->layout_private = mirror; - /* mirror refcount put in cleanup_layoutstats */ - atomic_inc(&mirror->ref); - ++(*dev_count); + i++; } - - return *dev_count < dev_limit; + return i; } static int ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args) { - struct pnfs_layout_segment *pls; + struct nfs4_flexfile_layout *ff_layout; + struct nfs4_ff_layout_mirror *mirror; int dev_count = 0; spin_lock(&args->inode->i_lock); - list_for_each_entry(pls, &NFS_I(args->inode)->layout->plh_segs, pls_list) { - dev_count += FF_LAYOUT_MIRROR_COUNT(pls); + ff_layout = FF_LAYOUT_FROM_HDR(NFS_I(args->inode)->layout); + list_for_each_entry(mirror, &ff_layout->mirrors, mirrors) { + if (atomic_read(&mirror->ref) != 0) + dev_count ++; } spin_unlock(&args->inode->i_lock); /* For now, send at most PNFS_LAYOUTSTATS_MAXDEV statistics */ @@ -1937,20 +2010,14 @@ ff_layout_prepare_layoutstats(struct nfs42_layoutstat_args *args) __func__, dev_count, PNFS_LAYOUTSTATS_MAXDEV); dev_count = PNFS_LAYOUTSTATS_MAXDEV; } - args->devinfo = kmalloc(dev_count * sizeof(*args->devinfo), GFP_KERNEL); + args->devinfo = kmalloc_array(dev_count, sizeof(*args->devinfo), GFP_NOIO); if (!args->devinfo) return -ENOMEM; - dev_count = 0; spin_lock(&args->inode->i_lock); - list_for_each_entry(pls, &NFS_I(args->inode)->layout->plh_segs, pls_list) { - if (!ff_layout_mirror_prepare_stats(args, pls, &dev_count, - PNFS_LAYOUTSTATS_MAXDEV)) { - break; - } - } + args->num_dev = ff_layout_mirror_prepare_stats(args, + &ff_layout->generic_hdr, dev_count); spin_unlock(&args->inode->i_lock); - args->num_dev = dev_count; return 0; } diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h index fe9d3ff7cf852..68cc0d9828f9a 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.h +++ b/fs/nfs/flexfilelayout/flexfilelayout.h @@ -67,6 +67,8 @@ struct nfs4_ff_layoutstat { }; struct nfs4_ff_layout_mirror { + struct pnfs_layout_hdr *layout; + struct list_head mirrors; u32 ds_count; u32 efficiency; struct nfs4_ff_layout_ds *mirror_ds; @@ -95,6 +97,7 @@ struct nfs4_ff_layout_segment { struct nfs4_flexfile_layout { struct pnfs_layout_hdr generic_hdr; struct pnfs_ds_commit_info commit_info; + struct list_head mirrors; struct list_head error_list; /* nfs4_ff_layout_ds_err */ }; -- GitLab From bbf58bf3488e41f346536aa89d62bdf2fe771128 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 24 Aug 2015 20:39:18 -0400 Subject: [PATCH 4836/7006] NFSv4.2/pnfs: Make the layoutstats timer configurable Allow advanced users to set the layoutstats timer in order to lengthen or shorten the period between layoutstat transmissions to the server. Signed-off-by: Trond Myklebust --- Documentation/kernel-parameters.txt | 9 +++++++++ fs/nfs/flexfilelayout/flexfilelayout.c | 5 ++++- fs/nfs/pnfs.c | 4 ++++ fs/nfs/pnfs.h | 3 +++ 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1d6f0459cd7bb..30d78b5615742 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt @@ -2279,6 +2279,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted. The default parameter value of '0' causes the kernel not to attempt recovery of lost locks. + nfs4.layoutstats_timer = + [NFSv4.2] Change the rate at which the kernel sends + layoutstats to the pNFS metadata server. + + Setting this to value to 0 causes the kernel to use + whatever value is the default set by the layout + driver. A non-zero value sets the minimum interval + in seconds between layoutstats transmissions. + nfsd.nfs4_disable_idmapping= [NFSv4] When set to the default of '1', the NFSv4 server will return only numeric uids and gids to diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 0fbf37de2a410..9f6fb8876b3fa 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -533,14 +533,17 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror, ktime_t now) { static const ktime_t notime = {0}; + s64 report_interval = FF_LAYOUTSTATS_REPORT_INTERVAL; nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now); if (ktime_equal(mirror->start_time, notime)) mirror->start_time = now; if (ktime_equal(mirror->last_report_time, notime)) mirror->last_report_time = now; + if (layoutstats_timer != 0) + report_interval = (s64)layoutstats_timer * 1000LL; if (ktime_to_ms(ktime_sub(now, mirror->last_report_time)) >= - FF_LAYOUTSTATS_REPORT_INTERVAL) { + report_interval) { mirror->last_report_time = now; return true; } diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 247c5a5d2d6b8..3530bb703214f 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -2285,3 +2285,7 @@ out_put: } EXPORT_SYMBOL_GPL(pnfs_report_layoutstat); #endif + +unsigned int layoutstats_timer; +module_param(layoutstats_timer, uint, 0644); +EXPORT_SYMBOL_GPL(layoutstats_timer); diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 02c27f93caf11..d3979dd1037a6 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -528,12 +528,15 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src, nfss->pnfs_curr_ld->id == src->l_type); } +extern unsigned int layoutstats_timer; + #ifdef NFS_DEBUG void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id); #else static inline void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id) { } + #endif /* NFS_DEBUG */ #else /* CONFIG_NFS_V4_1 */ -- GitLab From e3b1df2dbd7bcda807a94db131fda6c2bbd1480a Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 25 Aug 2015 11:19:25 +0800 Subject: [PATCH 4837/7006] NFSv4.1/flexfile: ff_layout_remove_mirror can be static Signed-off-by: Fengguang Wu Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 9f6fb8876b3fa..7fefa8ad95785 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -183,7 +183,7 @@ ff_layout_add_mirror(struct pnfs_layout_hdr *lo, return mirror; } -void +static void ff_layout_remove_mirror(struct nfs4_ff_layout_mirror *mirror) { struct inode *inode; -- GitLab From 82714bd1424a88e4bb43813c8a78fbe8f6c5feab Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Aug 2015 08:41:24 -0400 Subject: [PATCH 4838/7006] NFSv4.1/pnfs Improve the packing of struct pnfs_layout_hdr Eliminate a couple of holes in the structure, and move the 2 atomics into the same cacheline. Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index d3979dd1037a6..4df87ef3dccc4 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -183,15 +183,15 @@ struct pnfs_layoutdriver_type { struct pnfs_layout_hdr { atomic_t plh_refcount; + atomic_t plh_outstanding; /* number of RPCs out */ struct list_head plh_layouts; /* other client layouts */ struct list_head plh_bulk_destroy; struct list_head plh_segs; /* layout segments list */ - nfs4_stateid plh_stateid; - atomic_t plh_outstanding; /* number of RPCs out */ unsigned long plh_block_lgets; /* block LAYOUTGET if >0 */ - u32 plh_barrier; /* ignore lower seqids */ unsigned long plh_retry_timestamp; unsigned long plh_flags; + nfs4_stateid plh_stateid; + u32 plh_barrier; /* ignore lower seqids */ enum pnfs_iomode plh_return_iomode; loff_t plh_lwb; /* last write byte for layoutcommit */ struct rpc_cred *plh_lc_cred; /* layoutcommit cred */ -- GitLab From 540d9864e1c5f8d3ca2ecc919e7d8a47e713ec3f Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Aug 2015 11:16:13 -0400 Subject: [PATCH 4839/7006] NFSv4.1/pnfs: Add sanity check for the layout range returned by the server Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 3530bb703214f..68cc4b1697697 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1561,6 +1561,26 @@ out_unlock: } EXPORT_SYMBOL_GPL(pnfs_update_layout); +static bool +pnfs_sanity_check_layout_range(struct pnfs_layout_range *range) +{ + switch (range->iomode) { + case IOMODE_READ: + case IOMODE_RW: + break; + default: + return false; + } + if (range->offset == NFS4_MAX_UINT64) + return false; + if (range->length == 0) + return false; + if (range->length != NFS4_MAX_UINT64 && + range->length > NFS4_MAX_UINT64 - range->offset) + return false; + return true; +} + struct pnfs_layout_segment * pnfs_layout_process(struct nfs4_layoutget *lgp) { @@ -1569,7 +1589,10 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) struct pnfs_layout_segment *lseg; struct inode *ino = lo->plh_inode; LIST_HEAD(free_me); - int status = 0; + int status = -EINVAL; + + if (!pnfs_sanity_check_layout_range(&res->range)) + goto out; /* Inject layout blob into I/O device driver */ lseg = NFS_SERVER(ino)->pnfs_curr_ld->alloc_lseg(lo, res, lgp->gfp_flags); -- GitLab From 0cb850486048ba4f64482a9d3e33dff47df34c79 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Wed, 31 Dec 2014 13:58:53 +0100 Subject: [PATCH 4840/7006] mtd: nand: add Toshiba TC58NVG0S3E to nand_ids table Add the full description of the Toshiba TC58NVG0S3E NAND chip in the nand_ids table so that we can later use the NAND ECC info and ONFI timing mode in controller drivers. Tested with asm9260_nand driver. [Brian: driver still under review] Signed-off-by: Oleksij Rempel Reviewed-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_ids.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 7124400d903b3..a8804a3da0760 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -29,6 +29,10 @@ struct nand_flash_dev nand_flash_ids[] = { * listed by full ID. We list them first so that we can easily identify * the most specific match. */ + {"TC58NVG0S3E 1G 3.3V 8-bit", + { .id = {0x98, 0xd1, 0x90, 0x15, 0x76, 0x14, 0x01, 0x00} }, + SZ_2K, SZ_128, SZ_128K, 0, 8, 64, NAND_ECC_INFO(1, SZ_512), + 2 }, {"TC58NVG2S0F 4G 3.3V 8-bit", { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, -- GitLab From b96f465035f9fae83c1d8de3e80eecfe6877608c Mon Sep 17 00:00:00 2001 From: David Teigland Date: Tue, 25 Aug 2015 12:51:44 -0500 Subject: [PATCH 4841/7006] dlm: fix lvb copy for user locks For a userland lock request, the previous and current lock modes are used to decide when the lvb should be copied back to the user. The wrong previous value was used, so that it always matched the current value. This caused the lvb to be copied back to the user in the wrong cases. Signed-off-by: David Teigland --- fs/dlm/user.c | 7 ++++--- include/uapi/linux/dlm_device.h | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/dlm/user.c b/fs/dlm/user.c index fb85f32e9eca6..35960502ec8d3 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -785,6 +785,7 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, DECLARE_WAITQUEUE(wait, current); struct dlm_callback cb; int rv, resid, copy_lvb = 0; + int old_mode, new_mode; if (count == sizeof(struct dlm_device_version)) { rv = copy_version_to_user(buf, count); @@ -841,6 +842,9 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_cb_list); + /* rem_lkb_callback sets a new lkb_last_cast */ + old_mode = lkb->lkb_last_cast.mode; + rv = dlm_rem_lkb_callback(lkb->lkb_resource->res_ls, lkb, &cb, &resid); if (rv < 0) { /* this shouldn't happen; lkb should have been removed from @@ -864,9 +868,6 @@ static ssize_t device_read(struct file *file, char __user *buf, size_t count, } if (cb.flags & DLM_CB_CAST) { - int old_mode, new_mode; - - old_mode = lkb->lkb_last_cast.mode; new_mode = cb.mode; if (!cb.sb_status && lkb->lkb_lksb->sb_lvbptr && diff --git a/include/uapi/linux/dlm_device.h b/include/uapi/linux/dlm_device.h index 3060783c41915..df56c8ff07698 100644 --- a/include/uapi/linux/dlm_device.h +++ b/include/uapi/linux/dlm_device.h @@ -26,7 +26,7 @@ /* Version of the device interface */ #define DLM_DEVICE_VERSION_MAJOR 6 #define DLM_DEVICE_VERSION_MINOR 0 -#define DLM_DEVICE_VERSION_PATCH 1 +#define DLM_DEVICE_VERSION_PATCH 2 /* struct passed to the lock write */ struct dlm_lock_params { -- GitLab From 1d2e3f396c532b95a37bbee92269f37efe908457 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:22 -0700 Subject: [PATCH 4842/7006] RDS: restore return value in rds_cmsg_rdma_args() In rds_cmsg_rdma_args() 'ret' is used by rds_pin_pages() which returns number of pinned pages on success. And the same value is returned to the caller of rds_cmsg_rdma_args() on success which is not intended. Commit f4a3fc03c1d7 ("RDS: Clean up error handling in rds_cmsg_rdma_args") removed the 'ret = 0' line which broke RDS RDMA mode. Fix it by restoring the return value on rds_pin_pages() success keeping the clean-up in place. Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/rdma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 40084d843e9fe..6401b501a215b 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -658,6 +658,8 @@ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, ret = rds_pin_pages(iov->addr, nr, pages, !op->op_write); if (ret < 0) goto out; + else + ret = 0; rdsdebug("RDS: nr_bytes %u nr %u iov->bytes %llu iov->addr %llx\n", nr_bytes, nr, iov->bytes, iov->addr); -- GitLab From 43962dd7ee192299c6e0c6cd7f0a65997308f1f4 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:23 -0700 Subject: [PATCH 4843/7006] RDS: always free recv frag as we free its ring entry We were still seeing rare occurrences of the WARN_ON(recv->r_frag) which indicates that the recv refill path was finding allocated frags in ring entries that were marked free. These were usually followed by OOM crashes. They only seem to be occurring in the presence of completion errors and connection resets. This patch ensures that we free the frag as we mark the ring entry free. This should stop the refill path from finding allocated frags in ring entries that were marked free. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_recv.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index cac5b4506ee38..2a6a75c599435 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -982,10 +982,17 @@ static inline void rds_poll_cq(struct rds_ib_connection *ic, } /* - * It's very important that we only free this ring entry if we've truly - * freed the resources allocated to the entry. The refilling path can - * leak if we don't. + * rds_ib_process_recv() doesn't always consume the frag, and + * we might not have called it at all if the wc didn't indicate + * success. We already unmapped the frag's pages, though, and + * the following rds_ib_ring_free() call tells the refill path + * that it will not find an allocated frag here. Make sure we + * keep that promise by freeing a frag that's still on the ring. */ + if (recv->r_frag) { + rds_ib_frag_free(ic, recv->r_frag); + recv->r_frag = NULL; + } rds_ib_ring_free(&ic->i_recv_ring, 1); } } -- GitLab From 1bc7b863f230e429dd7a06c0956ada7933d69f50 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:24 -0700 Subject: [PATCH 4844/7006] RDS: destroy the ib state earlier during shutdown Destroy ib state early during shutdown. Otherwise we can get callbacks after the QP isn't really able to handle them. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_cm.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index f40d8f52b7539..94d4427377b23 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -640,6 +640,16 @@ void rds_ib_conn_shutdown(struct rds_connection *conn) (atomic_read(&ic->i_signaled_sends) == 0)); tasklet_kill(&ic->i_recv_tasklet); + /* first destroy the ib state that generates callbacks */ + if (ic->i_cm_id->qp) + rdma_destroy_qp(ic->i_cm_id); + if (ic->i_send_cq) + ib_destroy_cq(ic->i_send_cq); + if (ic->i_recv_cq) + ib_destroy_cq(ic->i_recv_cq); + rdma_destroy_id(ic->i_cm_id); + + /* then free the resources that ib callbacks use */ if (ic->i_send_hdrs) ib_dma_free_coherent(dev, ic->i_send_ring.w_nr * @@ -663,14 +673,6 @@ void rds_ib_conn_shutdown(struct rds_connection *conn) if (ic->i_recvs) rds_ib_recv_clear_ring(ic); - if (ic->i_cm_id->qp) - rdma_destroy_qp(ic->i_cm_id); - if (ic->i_send_cq) - ib_destroy_cq(ic->i_send_cq); - if (ic->i_recv_cq) - ib_destroy_cq(ic->i_recv_cq); - rdma_destroy_id(ic->i_cm_id); - /* * Move connection back to the nodev list. */ -- GitLab From e1f475a738e4c861d8aff84b737a0538680cbe05 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:25 -0700 Subject: [PATCH 4845/7006] RDS: don't update ip address tables if the address hasn't changed If the ip address tables hasn't changed, there is no need to remove them only to be added back again. Lets fix it. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_rdma.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 657ba9f5d3086..e49c9568b4a5c 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -151,12 +151,17 @@ int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr) struct rds_ib_device *rds_ibdev_old; rds_ibdev_old = rds_ib_get_device(ipaddr); - if (rds_ibdev_old) { + if (!rds_ibdev_old) + return rds_ib_add_ipaddr(rds_ibdev, ipaddr); + + if (rds_ibdev_old != rds_ibdev) { rds_ib_remove_ipaddr(rds_ibdev_old, ipaddr); rds_ib_dev_put(rds_ibdev_old); + return rds_ib_add_ipaddr(rds_ibdev, ipaddr); } + rds_ib_dev_put(rds_ibdev_old); - return rds_ib_add_ipaddr(rds_ibdev, ipaddr); + return 0; } void rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn) -- GitLab From 73ce4317bf983282593aff710b112a7e705620c3 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:26 -0700 Subject: [PATCH 4846/7006] RDS: make sure we post recv buffers If we get an ENOMEM during rds_ib_recv_refill, we might never come back and refill again later. Patch makes sure to kick krdsd into helping out. To achieve this we add RDS_RECV_REFILL flag and update in the refill path based on that so that at least some therad will keep posting receive buffers. Since krdsd and softirq both might race for refill, we decide to schedule on work queue based on ring_low instead of ring_empty. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/connection.c | 2 ++ net/rds/ib.h | 2 +- net/rds/ib_cm.c | 2 +- net/rds/ib_recv.c | 58 +++++++++++++++++++++++++++++++++++++++----- net/rds/rds.h | 1 + 5 files changed, 57 insertions(+), 8 deletions(-) diff --git a/net/rds/connection.c b/net/rds/connection.c index d4fecb21ca254..a50e652eb269d 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -301,6 +301,8 @@ void rds_conn_shutdown(struct rds_connection *conn) wait_event(conn->c_waitq, !test_bit(RDS_IN_XMIT, &conn->c_flags)); + wait_event(conn->c_waitq, + !test_bit(RDS_RECV_REFILL, &conn->c_flags)); conn->c_trans->conn_shutdown(conn); rds_conn_reset(conn); diff --git a/net/rds/ib.h b/net/rds/ib.h index 86d88ec5d5563..6422c52682e56 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -320,7 +320,7 @@ void rds_ib_recv_exit(void); int rds_ib_recv(struct rds_connection *conn); int rds_ib_recv_alloc_caches(struct rds_ib_connection *ic); void rds_ib_recv_free_caches(struct rds_ib_connection *ic); -void rds_ib_recv_refill(struct rds_connection *conn, int prefill); +void rds_ib_recv_refill(struct rds_connection *conn, int prefill, gfp_t gfp); void rds_ib_inc_free(struct rds_incoming *inc); int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iov_iter *to); void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context); diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 94d4427377b23..04243dd1c2eae 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -135,7 +135,7 @@ void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_even rds_ib_recv_init_ring(ic); /* Post receive buffers - as a side effect, this will update * the posted credit count. */ - rds_ib_recv_refill(conn, 1); + rds_ib_recv_refill(conn, 1, GFP_KERNEL); /* Tune RNR behavior */ rds_ib_tune_rnr(ic, &qp_attr); diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 2a6a75c599435..3afdcbdd06b4e 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -297,7 +297,7 @@ static struct rds_page_frag *rds_ib_refill_one_frag(struct rds_ib_connection *ic } static int rds_ib_recv_refill_one(struct rds_connection *conn, - struct rds_ib_recv_work *recv, int prefill) + struct rds_ib_recv_work *recv, gfp_t gfp) { struct rds_ib_connection *ic = conn->c_transport_data; struct ib_sge *sge; @@ -305,7 +305,7 @@ static int rds_ib_recv_refill_one(struct rds_connection *conn, gfp_t slab_mask = GFP_NOWAIT; gfp_t page_mask = GFP_NOWAIT; - if (prefill) { + if (gfp & __GFP_WAIT) { slab_mask = GFP_KERNEL; page_mask = GFP_HIGHUSER; } @@ -347,6 +347,24 @@ out: return ret; } +static int acquire_refill(struct rds_connection *conn) +{ + return test_and_set_bit(RDS_RECV_REFILL, &conn->c_flags) == 0; +} + +static void release_refill(struct rds_connection *conn) +{ + clear_bit(RDS_RECV_REFILL, &conn->c_flags); + + /* We don't use wait_on_bit()/wake_up_bit() because our waking is in a + * hot path and finding waiters is very rare. We don't want to walk + * the system-wide hashed waitqueue buckets in the fast path only to + * almost never find waiters. + */ + if (waitqueue_active(&conn->c_waitq)) + wake_up_all(&conn->c_waitq); +} + /* * This tries to allocate and post unused work requests after making sure that * they have all the allocations they need to queue received fragments into @@ -354,15 +372,23 @@ out: * * -1 is returned if posting fails due to temporary resource exhaustion. */ -void rds_ib_recv_refill(struct rds_connection *conn, int prefill) +void rds_ib_recv_refill(struct rds_connection *conn, int prefill, gfp_t gfp) { struct rds_ib_connection *ic = conn->c_transport_data; struct rds_ib_recv_work *recv; struct ib_recv_wr *failed_wr; unsigned int posted = 0; int ret = 0; + int can_wait = gfp & __GFP_WAIT; u32 pos; + /* the goal here is to just make sure that someone, somewhere + * is posting buffers. If we can't get the refill lock, + * let them do their thing + */ + if (!acquire_refill(conn)) + return; + while ((prefill || rds_conn_up(conn)) && rds_ib_ring_alloc(&ic->i_recv_ring, 1, &pos)) { if (pos >= ic->i_recv_ring.w_nr) { @@ -372,7 +398,7 @@ void rds_ib_recv_refill(struct rds_connection *conn, int prefill) } recv = &ic->i_recvs[pos]; - ret = rds_ib_recv_refill_one(conn, recv, prefill); + ret = rds_ib_recv_refill_one(conn, recv, gfp); if (ret) { break; } @@ -402,6 +428,24 @@ void rds_ib_recv_refill(struct rds_connection *conn, int prefill) if (ret) rds_ib_ring_unalloc(&ic->i_recv_ring, 1); + + release_refill(conn); + + /* if we're called from the softirq handler, we'll be GFP_NOWAIT. + * in this case the ring being low is going to lead to more interrupts + * and we can safely let the softirq code take care of it unless the + * ring is completely empty. + * + * if we're called from krdsd, we'll be GFP_KERNEL. In this case + * we might have raced with the softirq code while we had the refill + * lock held. Use rds_ib_ring_low() instead of ring_empty to decide + * if we should requeue. + */ + if (rds_conn_up(conn) && + ((can_wait && rds_ib_ring_low(&ic->i_recv_ring)) || + rds_ib_ring_empty(&ic->i_recv_ring))) { + queue_delayed_work(rds_wq, &conn->c_recv_w, 1); + } } /* @@ -1023,7 +1067,7 @@ void rds_ib_recv_tasklet_fn(unsigned long data) rds_ib_stats_inc(s_ib_rx_ring_empty); if (rds_ib_ring_low(&ic->i_recv_ring)) - rds_ib_recv_refill(conn, 0); + rds_ib_recv_refill(conn, 0, GFP_NOWAIT); } int rds_ib_recv(struct rds_connection *conn) @@ -1032,8 +1076,10 @@ int rds_ib_recv(struct rds_connection *conn) int ret = 0; rdsdebug("conn %p\n", conn); - if (rds_conn_up(conn)) + if (rds_conn_up(conn)) { rds_ib_attempt_ack(ic); + rds_ib_recv_refill(conn, 0, GFP_KERNEL); + } return ret; } diff --git a/net/rds/rds.h b/net/rds/rds.h index 9005fb0586f62..afb4048d0cfd2 100644 --- a/net/rds/rds.h +++ b/net/rds/rds.h @@ -80,6 +80,7 @@ enum { #define RDS_LL_SEND_FULL 0 #define RDS_RECONNECT_PENDING 1 #define RDS_IN_XMIT 2 +#define RDS_RECV_REFILL 3 struct rds_connection { struct hlist_node c_hash_node; -- GitLab From 0c484240210a8c835a216dbca6f1d690e4094a7c Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:27 -0700 Subject: [PATCH 4847/7006] RDS: check for congestion updates during rds_send_xmit Ensure we don't keep sending the data if the link is congested. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/send.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/rds/send.c b/net/rds/send.c index 2581b8e3dbe70..dd901c324edf8 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -411,7 +411,8 @@ over_batch: */ if (ret == 0) { smp_mb(); - if (!list_empty(&conn->c_send_queue) && + if ((test_bit(0, &conn->c_map_queued) || + !list_empty(&conn->c_send_queue)) && send_gen == conn->c_send_gen) { rds_stats_inc(s_send_lock_queue_raced); goto restart; -- GitLab From 0df5f9a68a79f31e608b69a9369d6415a38843e1 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:28 -0700 Subject: [PATCH 4848/7006] RDS: add a sock_destruct callback debug aid This helps to detect the accidental processes/apps trying to destroy the RDS socket which they are sharing with other processes/apps. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/af_rds.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c index 896834cd3b9ad..a2f28a6d4dc57 100644 --- a/net/rds/af_rds.c +++ b/net/rds/af_rds.c @@ -438,6 +438,14 @@ static const struct proto_ops rds_proto_ops = { .sendpage = sock_no_sendpage, }; +static void rds_sock_destruct(struct sock *sk) +{ + struct rds_sock *rs = rds_sk_to_rs(sk); + + WARN_ON((&rs->rs_item != rs->rs_item.next || + &rs->rs_item != rs->rs_item.prev)); +} + static int __rds_create(struct socket *sock, struct sock *sk, int protocol) { struct rds_sock *rs; @@ -445,6 +453,7 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) sock_init_data(sock, sk); sock->ops = &rds_proto_ops; sk->sk_protocol = protocol; + sk->sk_destruct = rds_sock_destruct; rs = rds_sk_to_rs(sk); spin_lock_init(&rs->rs_lock); -- GitLab From 4f73113c63bae5cd092c93c2a9835b9d3c7f0b54 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:29 -0700 Subject: [PATCH 4849/7006] RDS: Mark message mapped before transmit rds_send_xmit() marks the rds message map flag after xmit_[rdma/atomic]() which is clearly wrong. We need to maintain the ownership between transport and rds. Also take care of error path. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/send.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/net/rds/send.c b/net/rds/send.c index dd901c324edf8..faad1be61ab6b 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -282,26 +282,34 @@ restart: /* The transport either sends the whole rdma or none of it */ if (rm->rdma.op_active && !conn->c_xmit_rdma_sent) { rm->m_final_op = &rm->rdma; + /* The transport owns the mapped memory for now. + * You can't unmap it while it's on the send queue + */ + set_bit(RDS_MSG_MAPPED, &rm->m_flags); ret = conn->c_trans->xmit_rdma(conn, &rm->rdma); - if (ret) + if (ret) { + clear_bit(RDS_MSG_MAPPED, &rm->m_flags); + wake_up_interruptible(&rm->m_flush_wait); break; + } conn->c_xmit_rdma_sent = 1; - /* The transport owns the mapped memory for now. - * You can't unmap it while it's on the send queue */ - set_bit(RDS_MSG_MAPPED, &rm->m_flags); } if (rm->atomic.op_active && !conn->c_xmit_atomic_sent) { rm->m_final_op = &rm->atomic; + /* The transport owns the mapped memory for now. + * You can't unmap it while it's on the send queue + */ + set_bit(RDS_MSG_MAPPED, &rm->m_flags); ret = conn->c_trans->xmit_atomic(conn, &rm->atomic); - if (ret) + if (ret) { + clear_bit(RDS_MSG_MAPPED, &rm->m_flags); + wake_up_interruptible(&rm->m_flush_wait); break; + } conn->c_xmit_atomic_sent = 1; - /* The transport owns the mapped memory for now. - * You can't unmap it while it's on the send queue */ - set_bit(RDS_MSG_MAPPED, &rm->m_flags); } /* -- GitLab From 3049147ca7c8426268433d16d7546a51dede316d Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:30 -0700 Subject: [PATCH 4850/7006] RDS: Make sure we do a signaled send for large-send WR(Work Requests )always generate a WC(Work Completion) with signaled send. Default RDS ib code is setup for un-signaled completion. Since RDS connction is persistent, we can end up sending the data even after large-send when the remote end is not active(for any reason). By doing a signaled send at least once per large-send, we can at least detect the problem in work completion handler there by avoiding sending more data to inactive remote. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_send.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index 5d0a704fa039f..c576ebeb4115a 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -709,6 +709,11 @@ int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm, if (scat == &rm->data.op_sg[rm->data.op_count]) { prev->s_op = ic->i_data_op; prev->s_wr.send_flags |= IB_SEND_SOLICITED; + if (!(prev->s_wr.send_flags & IB_SEND_SIGNALED)) { + ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs; + prev->s_wr.send_flags |= IB_SEND_SIGNALED; + nr_sig++; + } ic->i_data_op = NULL; } -- GitLab From 5c240fa2ab394af1dbde280e00cc038cbc7f0409 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:31 -0700 Subject: [PATCH 4851/7006] RDS: Fix assertion level from fatal to warning Fix the asserion level since its not fatal and can be hit in normal execution paths. There is no need to take the system down. We keep the WARN_ON() to detect the condition if we get here with bad pages. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_rdma.c | 2 +- net/rds/rdma.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index e49c9568b4a5c..7b7aac8cdb560 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -490,7 +490,7 @@ static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr) /* FIXME we need a way to tell a r/w MR * from a r/o MR */ - BUG_ON(irqs_disabled()); + WARN_ON(!page->mapping && irqs_disabled()); set_page_dirty(page); put_page(page); } diff --git a/net/rds/rdma.c b/net/rds/rdma.c index 6401b501a215b..c1df9b1cf3b25 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -451,7 +451,7 @@ void rds_rdma_free_op(struct rm_rdma_op *ro) * is the case for a RDMA_READ which copies from remote * to local memory */ if (!ro->op_write) { - BUG_ON(irqs_disabled()); + WARN_ON(!page->mapping && irqs_disabled()); set_page_dirty(page); } put_page(page); -- GitLab From 1c3be624f40acd6f2bd0f22ade081ac2467e8617 Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Sat, 22 Aug 2015 15:45:32 -0700 Subject: [PATCH 4852/7006] RDS: Don't destroy the rdma id until after we're done using it During connection resets, we are destroying the rdma id too soon. We can't destroy it when it is still in use. So lets move rdma_destroy_id() after we clear the rings. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_cm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 04243dd1c2eae..d150bb4aa3cb9 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -647,7 +647,6 @@ void rds_ib_conn_shutdown(struct rds_connection *conn) ib_destroy_cq(ic->i_send_cq); if (ic->i_recv_cq) ib_destroy_cq(ic->i_recv_cq); - rdma_destroy_id(ic->i_cm_id); /* then free the resources that ib callbacks use */ if (ic->i_send_hdrs) @@ -673,6 +672,8 @@ void rds_ib_conn_shutdown(struct rds_connection *conn) if (ic->i_recvs) rds_ib_recv_clear_ring(ic); + rdma_destroy_id(ic->i_cm_id); + /* * Move connection back to the nodev list. */ -- GitLab From dfcec251d22bab947d10cf37e9ad67085cf7f097 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:33 -0700 Subject: [PATCH 4853/7006] RDS: make sure rds_send_drop_to properly takes the m_rs_lock rds_send_drop_to() is used during socket tear down to find all the messages on the socket and flush them . It can race with the acking code unless it takes the m_rs_lock on each and every message. This plugs a hole where we didn't take m_rs_lock on any message that didn't have the RDS_MSG_ON_CONN set. Taking m_rs_lock avoids double frees and other memory corruptions as the ack code trusts the message m_rs pointer on a socket that had actually been freed. We must take m_rs_lock to access m_rs. Because of lock nesting and rs access, we also need to acquire rs_lock. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/send.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/net/rds/send.c b/net/rds/send.c index faad1be61ab6b..b40c2ea8e89a0 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -778,8 +778,22 @@ void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest) while (!list_empty(&list)) { rm = list_entry(list.next, struct rds_message, m_sock_item); list_del_init(&rm->m_sock_item); - rds_message_wait(rm); + + /* just in case the code above skipped this message + * because RDS_MSG_ON_CONN wasn't set, run it again here + * taking m_rs_lock is the only thing that keeps us + * from racing with ack processing. + */ + spin_lock_irqsave(&rm->m_rs_lock, flags); + + spin_lock(&rs->rs_lock); + __rds_send_complete(rs, rm, RDS_RDMA_CANCELED); + spin_unlock(&rs->rs_lock); + + rm->m_rs = NULL; + spin_unlock_irqrestore(&rm->m_rs_lock, flags); + rds_message_put(rm); } } -- GitLab From 06e8941e22f5cbaa4051f06d7ac99e3f302f6d48 Mon Sep 17 00:00:00 2001 From: Mukesh Kacker Date: Sat, 22 Aug 2015 15:45:34 -0700 Subject: [PATCH 4854/7006] RDS: return EMSGSIZE for oversize requests before processing/queueing rds_send_queue_rm() allows for the "current datagram" being queued to exceed SO_SNDBUF thresholds by checking bytes queued without counting in length of current datagram. (Since sk_sndbuf is set to twice requested SO_SNDBUF value as a kernel heuristic this is usually fine!) If this "current datagram" squeezing past the threshold is itself many times the size of the sk_sndbuf threshold itself then even twice the SO_SNDBUF does not save us and it gets queued but cannot be transmitted. Threads block and deadlock and device becomes unusable. The check for this datagram not exceeding SNDBUF thresholds (EMSGSIZE) is not done on this datagram as that check is only done if queueing attempt fails. (Datagrams that follow this datagram fail queueing attempts, go through the check and eventually trip EMSGSIZE error but zero length datagrams silently fail!) This fix moves the check for datagrams exceeding SNDBUF limits before any processing or queueing is attempted and returns EMSGSIZE early in the rds_sndmsg() code. This change also ensures that all datagrams get checked for exceeding SNDBUF/sk_sndbuf size limits and the large datagrams that exceed those limits do not get to rds_send_queue_rm() code for processing. Signed-off-by: Mukesh Kacker Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/send.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/net/rds/send.c b/net/rds/send.c index b40c2ea8e89a0..4df61a515b83d 100644 --- a/net/rds/send.c +++ b/net/rds/send.c @@ -1015,6 +1015,11 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) goto out; } + if (payload_len > rds_sk_sndbuf(rs)) { + ret = -EMSGSIZE; + goto out; + } + /* size of rm including all sgs */ ret = rds_rm_size(msg, payload_len); if (ret < 0) @@ -1087,11 +1092,7 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len) while (!rds_send_queue_rm(rs, conn, rm, rs->rs_bound_port, dport, &queued)) { rds_stats_inc(s_send_queue_full); - /* XXX make sure this is reasonable */ - if (payload_len > rds_sk_sndbuf(rs)) { - ret = -EMSGSIZE; - goto out; - } + if (nonblock) { ret = -EAGAIN; goto out; -- GitLab From ae05368afa7ea27fd906477874ed3ebc7df7e53c Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Sat, 22 Aug 2015 15:45:35 -0700 Subject: [PATCH 4855/7006] RDS: check for valid cm_id before initiating connection Connection could have been dropped while the route is being resolved so check for valid cm_id before initiating the connection. Reviewed-by: Ajaykumar Hotchandani Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/rdma_transport.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c index 2082408360432..b9b40af5345b6 100644 --- a/net/rds/rdma_transport.c +++ b/net/rds/rdma_transport.c @@ -34,6 +34,7 @@ #include #include "rdma_transport.h" +#include "ib.h" static struct rdma_cm_id *rds_rdma_listen_id; @@ -82,8 +83,18 @@ int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id, break; case RDMA_CM_EVENT_ROUTE_RESOLVED: - /* XXX worry about racing with listen acceptance */ - ret = trans->cm_initiate_connect(cm_id); + /* Connection could have been dropped so make sure the + * cm_id is valid before proceeding + */ + if (conn) { + struct rds_ib_connection *ibic; + + ibic = conn->c_transport_data; + if (ibic && ibic->i_cm_id == cm_id) + ret = trans->cm_initiate_connect(cm_id); + else + rds_conn_drop(conn); + } break; case RDMA_CM_EVENT_ESTABLISHED: -- GitLab From 1ef53ebfa9ff5b205604fc781868765e00ae875f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:14 +0200 Subject: [PATCH 4856/7006] net: davinci_emac: fix error return code Propagate error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/davinci_emac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c index aeebc0a7bf476..a21c77bc1b27c 100644 --- a/drivers/net/ethernet/ti/davinci_emac.c +++ b/drivers/net/ethernet/ti/davinci_emac.c @@ -2004,8 +2004,10 @@ static int davinci_emac_probe(struct platform_device *pdev) if (res_ctrl) { priv->ctrl_base = devm_ioremap_resource(&pdev->dev, res_ctrl); - if (IS_ERR(priv->ctrl_base)) + if (IS_ERR(priv->ctrl_base)) { + rc = PTR_ERR(priv->ctrl_base); goto no_pdata; + } } else { priv->ctrl_base = priv->remap_addr + pdata->ctrl_mod_reg_offset; } -- GitLab From 5c12197939be10c117039aabc06830297fb6d6ee Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:16 +0200 Subject: [PATCH 4857/7006] mlxsw: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index a34f4742aa00c..045f98fed476f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -1726,6 +1726,7 @@ static int mlxsw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) mlxsw_pci_dbg_root); if (!mlxsw_pci->dbg_dir) { dev_err(&pdev->dev, "Failed to create debugfs dir\n"); + err = -ENOMEM; goto err_dbg_create_dir; } -- GitLab From 25105051fde444cac11a2e2599350e5388936428 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:21 +0200 Subject: [PATCH 4858/7006] ah6: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Acked-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv6/ah6.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index ed7d4e3f9c108..0630a4d5daaab 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -577,8 +577,10 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb) work_iph = ah_alloc_tmp(ahash, nfrags + sglists, hdr_len + ahp->icv_trunc_len + seqhi_len); - if (!work_iph) + if (!work_iph) { + err = -ENOMEM; goto out; + } auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len); seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len); -- GitLab From 94c10f0ea303473884f69edd6bbb0cedcf570105 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 25 Aug 2015 13:38:50 -0700 Subject: [PATCH 4859/7006] ah4: Fix error return in ah_input(). Noticed by Herbert Xu. Signed-off-by: David S. Miller --- net/ipv4/ah4.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index ac9a32ec3ee46..f2a71025a7705 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -360,8 +360,10 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb) work_iph = ah_alloc_tmp(ahash, nfrags + sglists, ihl + ahp->icv_trunc_len + seqhi_len); - if (!work_iph) + if (!work_iph) { + err = -ENOMEM; goto out; + } seqhi = (__be32 *)((char *)work_iph + ihl); auth_data = ah_tmp_auth(seqhi, seqhi_len); -- GitLab From 06bb6f5a69dfc53b79dd5f7afabdcd070a18afbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Mon, 10 Aug 2015 21:39:03 +0200 Subject: [PATCH 4860/7006] mtd: spi-nor: stop (ab)using struct spi_device_id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Using struct spi_device_id for storing list of flash devices comes from early SPI NOR framework days. Thanks to the commit 70f3ce0510af ("mtd: spi-nor: make spi_nor_scan() take a chip type name, not spi_device_id") we can stop using spi_device_id and just switch to our own struct. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 62 +++++++++++++++-------------------- 1 file changed, 27 insertions(+), 35 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 47df4b5eae2fc..c27d427fead43 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -29,6 +29,8 @@ #define SPI_NOR_MAX_ID_LEN 6 struct flash_info { + char *name; + /* * This array stores the ID bytes. * The first three bytes are the JEDIC ID. @@ -59,7 +61,7 @@ struct flash_info { #define JEDEC_MFR(info) ((info)->id[0]) -static const struct spi_device_id *spi_nor_match_id(const char *name); +static const struct flash_info *spi_nor_match_id(const char *name); /* * Read the status register, returning its value in the location @@ -169,7 +171,7 @@ static inline struct spi_nor *mtd_to_spi_nor(struct mtd_info *mtd) } /* Enable/disable 4-byte addressing mode. */ -static inline int set_4byte(struct spi_nor *nor, struct flash_info *info, +static inline int set_4byte(struct spi_nor *nor, const struct flash_info *info, int enable) { int status; @@ -469,7 +471,6 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ .id = { \ ((_jedec_id) >> 16) & 0xff, \ ((_jedec_id) >> 8) & 0xff, \ @@ -481,11 +482,9 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ - .flags = (_flags), \ - }) + .flags = (_flags), #define INFO6(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ .id = { \ ((_jedec_id) >> 16) & 0xff, \ ((_jedec_id) >> 8) & 0xff, \ @@ -498,17 +497,14 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = 256, \ - .flags = (_flags), \ - }) + .flags = (_flags), #define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags) \ - ((kernel_ulong_t)&(struct flash_info) { \ .sector_size = (_sector_size), \ .n_sectors = (_n_sectors), \ .page_size = (_page_size), \ .addr_width = (_addr_width), \ - .flags = (_flags), \ - }) + .flags = (_flags), /* NOTE: double check command sets and memory organization when you add * more nor chips. This current list focusses on newer chips, which @@ -521,7 +517,7 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) * For historical (and compatibility) reasons (before we got above config) some * old entries may be missing 4K flag. */ -static const struct spi_device_id spi_nor_ids[] = { +static const struct flash_info spi_nor_ids[] = { /* Atmel -- some are (confusingly) marketed as "DataFlash" */ { "at25fs010", INFO(0x1f6601, 0, 32 * 1024, 4, SECT_4K) }, { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, @@ -703,11 +699,11 @@ static const struct spi_device_id spi_nor_ids[] = { { }, }; -static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) +static const struct flash_info *spi_nor_read_id(struct spi_nor *nor) { int tmp; u8 id[SPI_NOR_MAX_ID_LEN]; - struct flash_info *info; + const struct flash_info *info; tmp = nor->read_reg(nor, SPINOR_OP_RDID, id, SPI_NOR_MAX_ID_LEN); if (tmp < 0) { @@ -716,7 +712,7 @@ static const struct spi_device_id *spi_nor_read_id(struct spi_nor *nor) } for (tmp = 0; tmp < ARRAY_SIZE(spi_nor_ids) - 1; tmp++) { - info = (void *)spi_nor_ids[tmp].driver_data; + info = &spi_nor_ids[tmp]; if (info->id_len) { if (!memcmp(info->id, id, info->id_len)) return &spi_nor_ids[tmp]; @@ -962,7 +958,7 @@ static int micron_quad_enable(struct spi_nor *nor) return 0; } -static int set_quad_mode(struct spi_nor *nor, struct flash_info *info) +static int set_quad_mode(struct spi_nor *nor, const struct flash_info *info) { int status; @@ -1004,8 +1000,7 @@ static int spi_nor_check(struct spi_nor *nor) int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) { - const struct spi_device_id *id = NULL; - struct flash_info *info; + const struct flash_info *info = NULL; struct device *dev = nor->dev; struct mtd_info *mtd = nor->mtd; struct device_node *np = dev->of_node; @@ -1017,26 +1012,24 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) return ret; if (name) - id = spi_nor_match_id(name); + info = spi_nor_match_id(name); /* Try to auto-detect if chip name wasn't specified or not found */ - if (!id) - id = spi_nor_read_id(nor); - if (IS_ERR_OR_NULL(id)) + if (!info) + info = spi_nor_read_id(nor); + if (IS_ERR_OR_NULL(info)) return -ENOENT; - info = (void *)id->driver_data; - /* * If caller has specified name of flash model that can normally be * detected using JEDEC, let's verify it. */ if (name && info->id_len) { - const struct spi_device_id *jid; + const struct flash_info *jinfo; - jid = spi_nor_read_id(nor); - if (IS_ERR(jid)) { - return PTR_ERR(jid); - } else if (jid != id) { + jinfo = spi_nor_read_id(nor); + if (IS_ERR(jinfo)) { + return PTR_ERR(jinfo); + } else if (jinfo != info) { /* * JEDEC knows better, so overwrite platform ID. We * can't trust partitions any longer, but we'll let @@ -1045,9 +1038,8 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) * information, even if it's not 100% accurate. */ dev_warn(dev, "found %s, expected %s\n", - jid->name, id->name); - id = jid; - info = (void *)jid->driver_data; + jinfo->name, info->name); + info = jinfo; } } @@ -1197,7 +1189,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) nor->read_dummy = spi_nor_read_dummy_cycles(nor); - dev_info(dev, "%s (%lld Kbytes)\n", id->name, + dev_info(dev, "%s (%lld Kbytes)\n", info->name, (long long)mtd->size >> 10); dev_dbg(dev, @@ -1220,9 +1212,9 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) } EXPORT_SYMBOL_GPL(spi_nor_scan); -static const struct spi_device_id *spi_nor_match_id(const char *name) +static const struct flash_info *spi_nor_match_id(const char *name) { - const struct spi_device_id *id = spi_nor_ids; + const struct flash_info *id = spi_nor_ids; while (id->name[0]) { if (!strcmp(name, id->name)) -- GitLab From 5283af899adec1a7765e413e43b27a335fadac5d Mon Sep 17 00:00:00 2001 From: Rana Shahout Date: Sun, 23 Aug 2015 16:12:14 +0300 Subject: [PATCH 4861/7006] net/mlx5e: Avoid accessing NULL pointer at ndo_select_queue To avoid multiply/division operations on the data path, we hold a {channel, tc}==>txq mapping table. We held this mapping table inside the channel object that is being destroyed upon some configuration operations (e.g MTU change). So in case ndo_select_queue occurs during such a configuration operation, it may access a NULL channel pointer, resulting in kernel panic. To fix this issue we moved the {channel, tc}==>txq mapping table outside the channel object so that it will be available also during such configuration operations. Signed-off-by: Rana Shahout Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/en.h | 2 +- drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 8 ++++---- drivers/net/ethernet/mellanox/mlx5/core/en_tx.c | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en.h b/drivers/net/ethernet/mellanox/mlx5/core/en.h index 27ca4596775af..0983a208b2995 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en.h @@ -405,7 +405,6 @@ struct mlx5e_channel { __be32 mkey_be; u8 num_tc; unsigned long flags; - int tc_to_txq_map[MLX5E_MAX_NUM_TC]; /* control */ struct mlx5e_priv *priv; @@ -475,6 +474,7 @@ struct mlx5e_priv { /* priv data path fields - start */ int default_vlan_prio; struct mlx5e_sq **txq_to_sq_map; + int channeltc_to_txq_map[MLX5E_MAX_NUM_CHANNELS][MLX5E_MAX_NUM_TC]; /* priv data path fields - end */ unsigned long state; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 55166dd5b4ea5..59874d666cfff 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -949,13 +949,13 @@ static void mlx5e_close_sqs(struct mlx5e_channel *c) mlx5e_close_sq(&c->sq[tc]); } -static void mlx5e_build_tc_to_txq_map(struct mlx5e_channel *c, - int num_channels) +static void mlx5e_build_channeltc_to_txq_map(struct mlx5e_priv *priv, int ix) { int i; for (i = 0; i < MLX5E_MAX_NUM_TC; i++) - c->tc_to_txq_map[i] = c->ix + i * num_channels; + priv->channeltc_to_txq_map[ix][i] = + ix + i * priv->params.num_channels; } static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, @@ -979,7 +979,7 @@ static int mlx5e_open_channel(struct mlx5e_priv *priv, int ix, c->mkey_be = cpu_to_be32(priv->mr.key); c->num_tc = priv->params.num_tc; - mlx5e_build_tc_to_txq_map(c, priv->params.num_channels); + mlx5e_build_channeltc_to_txq_map(priv, ix); netif_napi_add(netdev, &c->napi, mlx5e_napi_poll, 64); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c index 64380bc0cd6a5..b73672f32e2c6 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c @@ -106,7 +106,7 @@ u16 mlx5e_select_queue(struct net_device *dev, struct sk_buff *skb, priv->default_vlan_prio; int tc = netdev_get_prio_tc_map(dev, up); - return priv->channel[channel_ix]->tc_to_txq_map[tc]; + return priv->channeltc_to_txq_map[channel_ix][tc]; } static inline u16 mlx5e_get_inline_hdr_size(struct mlx5e_sq *sq, -- GitLab From 2c0027cd54cc3ed856e87d9aeddb6ef00f5f17f4 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Sun, 23 Aug 2015 08:21:22 -0600 Subject: [PATCH 4862/7006] inetpeer: remove dead code Remove various inlined functions not referenced in the kernel. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/inetpeer.h | 67 ------------------------------------------ 1 file changed, 67 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index d5332ddcea3f3..002f0bd270013 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -65,71 +65,12 @@ struct inet_peer_base { int total; }; -#define INETPEER_BASE_BIT 0x1UL - -static inline struct inet_peer *inetpeer_ptr(unsigned long val) -{ - BUG_ON(val & INETPEER_BASE_BIT); - return (struct inet_peer *) val; -} - -static inline struct inet_peer_base *inetpeer_base_ptr(unsigned long val) -{ - if (!(val & INETPEER_BASE_BIT)) - return NULL; - val &= ~INETPEER_BASE_BIT; - return (struct inet_peer_base *) val; -} - -static inline bool inetpeer_ptr_is_peer(unsigned long val) -{ - return !(val & INETPEER_BASE_BIT); -} - -static inline void __inetpeer_ptr_set_peer(unsigned long *val, struct inet_peer *peer) -{ - /* This implicitly clears INETPEER_BASE_BIT */ - *val = (unsigned long) peer; -} - -static inline bool inetpeer_ptr_set_peer(unsigned long *ptr, struct inet_peer *peer) -{ - unsigned long val = (unsigned long) peer; - unsigned long orig = *ptr; - - if (!(orig & INETPEER_BASE_BIT) || - cmpxchg(ptr, orig, val) != orig) - return false; - return true; -} - -static inline void inetpeer_init_ptr(unsigned long *ptr, struct inet_peer_base *base) -{ - *ptr = (unsigned long) base | INETPEER_BASE_BIT; -} - -static inline void inetpeer_transfer_peer(unsigned long *to, unsigned long *from) -{ - unsigned long val = *from; - - *to = val; - if (inetpeer_ptr_is_peer(val)) { - struct inet_peer *peer = inetpeer_ptr(val); - atomic_inc(&peer->refcnt); - } -} - void inet_peer_base_init(struct inet_peer_base *); void inet_initpeers(void) __init; #define INETPEER_METRICS_NEW (~(u32) 0) -static inline bool inet_metrics_new(const struct inet_peer *p) -{ - return p->metrics[RTAX_LOCK-1] == INETPEER_METRICS_NEW; -} - /* can be called with or without local BH being disabled */ struct inet_peer *inet_getpeer(struct inet_peer_base *base, const struct inetpeer_addr *daddr, @@ -163,12 +104,4 @@ bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); void inetpeer_invalidate_tree(struct inet_peer_base *); -/* - * temporary check to make sure we dont access rid, tcp_ts, - * tcp_ts_stamp if no refcount is taken on inet_peer - */ -static inline void inet_peer_refcheck(const struct inet_peer *p) -{ - WARN_ON_ONCE(atomic_read(&p->refcnt) <= 0); -} #endif /* _NET_INETPEER_H */ -- GitLab From 542a64c7076565d73eea39057113914e1607db30 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Sun, 23 Aug 2015 20:31:38 +0200 Subject: [PATCH 4863/7006] net: sun4i-emac: Claim emac sram Claim the emac sram ourselves, rather then relying on the bootloader having mapped the sram to the emac controller during boot. Signed-off-by: Hans de Goede Signed-off-by: David S. Miller --- drivers/net/ethernet/allwinner/sun4i-emac.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/allwinner/sun4i-emac.c b/drivers/net/ethernet/allwinner/sun4i-emac.c index bab01c8491654..48ce83e443c2b 100644 --- a/drivers/net/ethernet/allwinner/sun4i-emac.c +++ b/drivers/net/ethernet/allwinner/sun4i-emac.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "sun4i-emac.h" @@ -857,11 +858,17 @@ static int emac_probe(struct platform_device *pdev) clk_prepare_enable(db->clk); + ret = sunxi_sram_claim(&pdev->dev); + if (ret) { + dev_err(&pdev->dev, "Error couldn't map SRAM to device\n"); + goto out; + } + db->phy_node = of_parse_phandle(np, "phy", 0); if (!db->phy_node) { dev_err(&pdev->dev, "no associated PHY\n"); ret = -ENODEV; - goto out; + goto out_release_sram; } /* Read MAC-address from DT */ @@ -893,7 +900,7 @@ static int emac_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Registering netdev failed!\n"); ret = -ENODEV; - goto out; + goto out_release_sram; } dev_info(&pdev->dev, "%s: at %p, IRQ %d MAC: %pM\n", @@ -901,6 +908,8 @@ static int emac_probe(struct platform_device *pdev) return 0; +out_release_sram: + sunxi_sram_release(&pdev->dev); out: dev_err(db->dev, "not found (%d).\n", ret); -- GitLab From cc7fce80229067890365c1ee196be5d304d36dea Mon Sep 17 00:00:00 2001 From: Tomer Barletz Date: Tue, 4 Aug 2015 21:00:24 -0700 Subject: [PATCH 4864/7006] mtd: blkdevs: fix switch-bool compilation warning With gcc 5.1 I get: warning: switch condition has boolean value [-Wswitch-bool] Signed-off-by: Tomer Barletz Signed-off-by: Brian Norris --- drivers/mtd/mtd_blkdevs.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 41acc507b22ed..88304751eb8a9 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -97,14 +97,13 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (req->cmd_flags & REQ_DISCARD) return tr->discard(dev, block, nsect); - switch(rq_data_dir(req)) { - case READ: + if (rq_data_dir(req) == READ) { for (; nsect > 0; nsect--, block++, buf += tr->blksize) if (tr->readsect(dev, block, buf)) return -EIO; rq_flush_dcache_pages(req); return 0; - case WRITE: + } else { if (!tr->writesect) return -EIO; @@ -113,9 +112,6 @@ static int do_blktrans_request(struct mtd_blktrans_ops *tr, if (tr->writesect(dev, block, buf)) return -EIO; return 0; - default: - printk(KERN_NOTICE "Unknown request %u\n", rq_data_dir(req)); - return -EIO; } } -- GitLab From 79c441ae505ccfaed9d80df95e83fb2573f23f8e Mon Sep 17 00:00:00 2001 From: Guillaume Nault Date: Mon, 24 Aug 2015 11:35:30 +0200 Subject: [PATCH 4865/7006] ppp: implement x-netns support Let packets move from one netns to the other at PPP encapsulation and decapsulation time. PPP units and channels remain in the netns in which they were originally created. Only the net_device may move to a different namespace. Cross netns handling is thus transparent to lower PPP layers (PPPoE, L2TP, etc.). PPP devices are automatically unregistered when their netns gets removed. So read() and poll() on the unit file descriptor will respectively receive EOF and POLLHUP. Channels aren't affected. Signed-off-by: Guillaume Nault Signed-off-by: David S. Miller --- drivers/net/ppp/ppp_generic.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/net/ppp/ppp_generic.c b/drivers/net/ppp/ppp_generic.c index fa8f5046afe90..0481daf9201a2 100644 --- a/drivers/net/ppp/ppp_generic.c +++ b/drivers/net/ppp/ppp_generic.c @@ -283,6 +283,8 @@ static int unit_set(struct idr *p, void *ptr, int n); static void unit_put(struct idr *p, int n); static void *unit_find(struct idr *p, int n); +static const struct net_device_ops ppp_netdev_ops; + static struct class *ppp_class; /* per net-namespace data */ @@ -919,13 +921,22 @@ static __net_init int ppp_init_net(struct net *net) static __net_exit void ppp_exit_net(struct net *net) { struct ppp_net *pn = net_generic(net, ppp_net_id); + struct net_device *dev; + struct net_device *aux; struct ppp *ppp; LIST_HEAD(list); int id; rtnl_lock(); + for_each_netdev_safe(net, dev, aux) { + if (dev->netdev_ops == &ppp_netdev_ops) + unregister_netdevice_queue(dev, &list); + } + idr_for_each_entry(&pn->units_idr, ppp, id) - unregister_netdevice_queue(ppp->dev, &list); + /* Skip devices already unregistered by previous loop */ + if (!net_eq(dev_net(ppp->dev), net)) + unregister_netdevice_queue(ppp->dev, &list); unregister_netdevice_many(&list); rtnl_unlock(); @@ -1017,6 +1028,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) proto = npindex_to_proto[npi]; put_unaligned_be16(proto, pp); + skb_scrub_packet(skb, !net_eq(ppp->ppp_net, dev_net(dev))); skb_queue_tail(&ppp->file.xq, skb); ppp_xmit_process(ppp); return NETDEV_TX_OK; @@ -1137,7 +1149,6 @@ static void ppp_setup(struct net_device *dev) dev->tx_queue_len = 3; dev->type = ARPHRD_PPP; dev->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST; - dev->features |= NETIF_F_NETNS_LOCAL; netif_keep_dst(dev); } @@ -1900,6 +1911,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb->dev = ppp->dev; skb->protocol = htons(npindex_to_ethertype[npi]); skb_reset_mac_header(skb); + skb_scrub_packet(skb, !net_eq(ppp->ppp_net, + dev_net(ppp->dev))); netif_rx(skb); } } -- GitLab From 4712f71b609d1805b958c0c355b16a995b11ab6e Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:28:26 +0800 Subject: [PATCH 4866/7006] ACPICA: Correctly cleanup after a ACPI table load failure ACPICA commit ed7769e832de6c7ba90615480d916c85fd100422 If a table load fails, delete all namespace objects created by the table, otherwise these objects will be uninitialized, causing problems later. This appears to be a very rare problem. Also handle the unitialized node problem to prevent possible faults. ACPICA BZ 1185. Link: https://github.com/acpica/acpica/commit/ed7769e8 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/exresnte.c | 2 +- drivers/acpi/acpica/exresolv.c | 16 +++++++++++----- drivers/acpi/acpica/nseval.c | 1 + drivers/acpi/acpica/nsload.c | 16 +++++++++++++++- drivers/acpi/acpica/tbxfload.c | 29 ++++++++++++++++++++++++++--- include/acpi/acexcep.h | 7 +++++-- 6 files changed, 59 insertions(+), 12 deletions(-) diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c index c7e3b929aa854..1b372ef693088 100644 --- a/drivers/acpi/acpica/exresnte.c +++ b/drivers/acpi/acpica/exresnte.c @@ -126,7 +126,7 @@ acpi_ex_resolve_node_to_value(struct acpi_namespace_node **object_ptr, if (!source_desc) { ACPI_ERROR((AE_INFO, "No object attached to node [%4.4s] %p", node->name.ascii, node)); - return_ACPI_STATUS(AE_AML_NO_OPERAND); + return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); } /* diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c index b6b7f3af29e44..7b109128b0350 100644 --- a/drivers/acpi/acpica/exresolv.c +++ b/drivers/acpi/acpica/exresolv.c @@ -337,8 +337,9 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, acpi_object_type * return_type, union acpi_operand_object **return_desc) { - union acpi_operand_object *obj_desc = (void *)operand; - struct acpi_namespace_node *node; + union acpi_operand_object *obj_desc = ACPI_CAST_PTR(void, operand); + struct acpi_namespace_node *node = + ACPI_CAST_PTR(struct acpi_namespace_node, operand); acpi_object_type type; acpi_status status; @@ -355,9 +356,7 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, case ACPI_DESC_TYPE_NAMED: type = ((struct acpi_namespace_node *)obj_desc)->type; - obj_desc = - acpi_ns_get_attached_object((struct acpi_namespace_node *) - obj_desc); + obj_desc = acpi_ns_get_attached_object(node); /* If we had an Alias node, use the attached object for type info */ @@ -368,6 +367,13 @@ acpi_ex_resolve_multiple(struct acpi_walk_state *walk_state, acpi_namespace_node *) obj_desc); } + + if (!obj_desc) { + ACPI_ERROR((AE_INFO, + "[%4.4s] Node is unresolved or uninitialized", + acpi_ut_get_node_name(node))); + return_ACPI_STATUS(AE_AML_UNINITIALIZED_NODE); + } break; default: diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 80670cb32b5a3..88822b7a958f1 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -274,6 +274,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info) acpi_ex_exit_interpreter(); if (ACPI_FAILURE(status)) { + info->return_object = NULL; goto cleanup; } diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c index bd6cd4a81316c..14ab83668207e 100644 --- a/drivers/acpi/acpica/nsload.c +++ b/drivers/acpi/acpica/nsload.c @@ -111,7 +111,21 @@ acpi_ns_load_table(u32 table_index, struct acpi_namespace_node *node) if (ACPI_SUCCESS(status)) { acpi_tb_set_table_loaded_flag(table_index, TRUE); } else { - (void)acpi_tb_release_owner_id(table_index); + /* + * On error, delete any namespace objects created by this table. + * We cannot initialize these objects, so delete them. There are + * a couple of expecially bad cases: + * AE_ALREADY_EXISTS - namespace collision. + * AE_NOT_FOUND - the target of a Scope operator does not + * exist. This target of Scope must already exist in the + * namespace, as per the ACPI specification. + */ + (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); + acpi_ns_delete_namespace_by_owner(acpi_gbl_root_table_list. + tables[table_index].owner_id); + acpi_tb_release_owner_id(table_index); + + return_ACPI_STATUS(status); } unlock: diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 9682d40ca6ffe..7862cf04a1640 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -102,6 +102,8 @@ static acpi_status acpi_tb_load_namespace(void) acpi_status status; u32 i; struct acpi_table_header *new_dsdt; + u32 tables_loaded = 0; + u32 tables_failed = 0; ACPI_FUNCTION_TRACE(tb_load_namespace); @@ -159,7 +161,10 @@ static acpi_status acpi_tb_load_namespace(void) status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed")); + tables_failed++; + } else { + tables_loaded++; } /* Load any SSDT or PSDT tables. Note: Loop leaves tables locked */ @@ -187,11 +192,29 @@ static acpi_status acpi_tb_load_namespace(void) /* Ignore errors while loading tables, get as many as possible */ (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - (void)acpi_ns_load_table(i, acpi_gbl_root_node); + status = acpi_ns_load_table(i, acpi_gbl_root_node); + if (ACPI_FAILURE(status)) { + ACPI_EXCEPTION((AE_INFO, status, + "[%4.4s] table load failed", + &acpi_gbl_root_table_list.tables[i]. + signature.ascii[0])); + tables_failed++; + } else { + tables_loaded++; + } + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); } - ACPI_INFO((AE_INFO, "All ACPI Tables successfully acquired")); + if (!tables_failed) { + ACPI_INFO((AE_INFO, + "All (%u) ACPI AML tables successfully loaded", + tables_loaded)); + } else { + ACPI_ERROR((AE_INFO, + "%u ACPI AML tables loaded, %u failed", + tables_loaded, tables_failed)); + } unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h index 11c3a011dcbf1..9f20eb4acaa60 100644 --- a/include/acpi/acexcep.h +++ b/include/acpi/acexcep.h @@ -192,8 +192,9 @@ struct acpi_exception_info { #define AE_AML_BAD_RESOURCE_LENGTH EXCEP_AML (0x001F) #define AE_AML_ILLEGAL_ADDRESS EXCEP_AML (0x0020) #define AE_AML_INFINITE_LOOP EXCEP_AML (0x0021) +#define AE_AML_UNINITIALIZED_NODE EXCEP_AML (0x0022) -#define AE_CODE_AML_MAX 0x0021 +#define AE_CODE_AML_MAX 0x0022 /* * Internal exceptions used for control @@ -355,7 +356,9 @@ static const struct acpi_exception_info acpi_gbl_exception_names_aml[] = { EXCEP_TXT("AE_AML_ILLEGAL_ADDRESS", "A memory, I/O, or PCI configuration address is invalid"), EXCEP_TXT("AE_AML_INFINITE_LOOP", - "An apparent infinite AML While loop, method was aborted") + "An apparent infinite AML While loop, method was aborted"), + EXCEP_TXT("AE_AML_UNINITIALIZED_NODE", + "A namespace node is uninitialized or unresolved") }; static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = { -- GitLab From 3534969721ba011b8c2bcb5686819852df7aa971 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:28:32 +0800 Subject: [PATCH 4867/7006] ACPICA: Disassembler: Remove duplicate code in _PLD processing. ACPICA commit 6d9c827b540837b6e54059e17756a06985e4a196 ACPICA BZ 1176. Link: https://bugs.acpica.org/show_bug.cgi?id=1176 Link: https://github.com/acpica/acpica/commit/6d9c827b Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/utxface.c | 5 +++-- include/acpi/acbuffer.h | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index 51cf52d52243c..c2bd5e2485a4c 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -517,7 +517,8 @@ acpi_decode_pld_buffer(u8 *in_buffer, /* Parameter validation */ - if (!in_buffer || !return_buffer || (length < 16)) { + if (!in_buffer || !return_buffer + || (length < ACPI_PLD_REV1_BUFFER_SIZE)) { return (AE_BAD_PARAMETER); } @@ -567,7 +568,7 @@ acpi_decode_pld_buffer(u8 *in_buffer, pld_info->rotation = ACPI_PLD_GET_ROTATION(&dword); pld_info->order = ACPI_PLD_GET_ORDER(&dword); - if (length >= ACPI_PLD_BUFFER_SIZE) { + if (length >= ACPI_PLD_REV2_BUFFER_SIZE) { /* Fifth 32-bit DWord (Revision 2 of _PLD) */ diff --git a/include/acpi/acbuffer.h b/include/acpi/acbuffer.h index 6b040f4ddfabc..fcf9080eae853 100644 --- a/include/acpi/acbuffer.h +++ b/include/acpi/acbuffer.h @@ -147,6 +147,7 @@ struct acpi_pld_info { * (Intended for BIOS use only) */ #define ACPI_PLD_REV1_BUFFER_SIZE 16 /* For Revision 1 of the buffer (From ACPI spec) */ +#define ACPI_PLD_REV2_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ #define ACPI_PLD_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ /* First 32-bit dword, bits 0:32 */ -- GitLab From 9f41fd8a175ff87ba610fc387a6922b0f49f8e19 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:28:39 +0800 Subject: [PATCH 4868/7006] ACPICA: Update parameter validation for data_table_region and load_table ACPICA commit 51ab555e60b4a3de3cc4a846e86d0de255be441a Add additional validation for the table signature and the OEM strings. Eliminates buffer read overrun in data_table_region. ACPICA BZ 1184. Link: https://bugs.acpica.org/show_bug.cgi?id=1184 Link: https://github.com/acpica/acpica/commit/51ab555e Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 2 ++ drivers/acpi/acpica/dsopcode.c | 31 ++++++++++++++++++++----------- drivers/acpi/acpica/exconfig.c | 8 -------- drivers/acpi/acpica/tbfind.c | 15 ++++++++++++++- drivers/acpi/acpica/tbutils.c | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+), 20 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 7e0b6f1bec9c9..58497b7e33472 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -164,4 +164,6 @@ acpi_tb_install_fixed_table(acpi_physical_address address, acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); +u8 acpi_is_valid_signature(char *signature); + #endif /* __ACTABLES_H__ */ diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c index ea0cc4e08f803..81d7b9863e321 100644 --- a/drivers/acpi/acpica/dsopcode.c +++ b/drivers/acpi/acpica/dsopcode.c @@ -480,8 +480,8 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, union acpi_operand_object **operand; struct acpi_namespace_node *node; union acpi_parse_object *next_op; - u32 table_index; struct acpi_table_header *table; + u32 table_index; ACPI_FUNCTION_TRACE_PTR(ds_eval_table_region_operands, op); @@ -504,6 +504,8 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, return_ACPI_STATUS(status); } + operand = &walk_state->operands[0]; + /* * Resolve the Signature string, oem_id string, * and oem_table_id string operands @@ -511,32 +513,34 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, status = acpi_ex_resolve_operands(op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto cleanup; } - operand = &walk_state->operands[0]; - /* Find the ACPI table */ status = acpi_tb_find_table(operand[0]->string.pointer, operand[1]->string.pointer, operand[2]->string.pointer, &table_index); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + if (status == AE_NOT_FOUND) { + ACPI_ERROR((AE_INFO, + "ACPI Table [%4.4s] OEM:(%s, %s) not found in RSDT/XSDT", + operand[0]->string.pointer, + operand[1]->string.pointer, + operand[2]->string.pointer)); + } + goto cleanup; } - acpi_ut_remove_reference(operand[0]); - acpi_ut_remove_reference(operand[1]); - acpi_ut_remove_reference(operand[2]); - status = acpi_get_table_by_index(table_index, &table); if (ACPI_FAILURE(status)) { - return_ACPI_STATUS(status); + goto cleanup; } obj_desc = acpi_ns_get_attached_object(node); if (!obj_desc) { - return_ACPI_STATUS(AE_NOT_EXIST); + status = AE_NOT_EXIST; + goto cleanup; } obj_desc->region.address = ACPI_PTR_TO_PHYSADDR(table); @@ -551,6 +555,11 @@ acpi_ds_eval_table_region_operands(struct acpi_walk_state *walk_state, obj_desc->region.flags |= AOPOBJ_DATA_VALID; +cleanup: + acpi_ut_remove_reference(operand[0]); + acpi_ut_remove_reference(operand[1]); + acpi_ut_remove_reference(operand[2]); + return_ACPI_STATUS(status); } diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c index 24a4c5c2b1248..b540913c11ace 100644 --- a/drivers/acpi/acpica/exconfig.c +++ b/drivers/acpi/acpica/exconfig.c @@ -162,14 +162,6 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state, ACPI_FUNCTION_TRACE(ex_load_table_op); - /* Validate lengths for the Signature, oem_id, and oem_table_id strings */ - - if ((operand[0]->string.length > ACPI_NAME_SIZE) || - (operand[1]->string.length > ACPI_OEM_ID_SIZE) || - (operand[2]->string.length > ACPI_OEM_TABLE_ID_SIZE)) { - return_ACPI_STATUS(AE_AML_STRING_LIMIT); - } - /* Find the ACPI table in the RSDT/XSDT */ status = acpi_tb_find_table(operand[0]->string.pointer, diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c index 119c84ad98334..405529d49a1ab 100644 --- a/drivers/acpi/acpica/tbfind.c +++ b/drivers/acpi/acpica/tbfind.c @@ -68,12 +68,25 @@ acpi_status acpi_tb_find_table(char *signature, char *oem_id, char *oem_table_id, u32 *table_index) { - u32 i; acpi_status status; struct acpi_table_header header; + u32 i; ACPI_FUNCTION_TRACE(tb_find_table); + /* Validate the input table signature */ + + if (!acpi_is_valid_signature(signature)) { + return_ACPI_STATUS(AE_BAD_SIGNATURE); + } + + /* Don't allow the OEM strings to be too long */ + + if ((strlen(oem_id) > ACPI_OEM_ID_SIZE) || + (strlen(oem_table_id) > ACPI_OEM_TABLE_ID_SIZE)) { + return_ACPI_STATUS(AE_AML_STRING_LIMIT); + } + /* Normalize the input strings */ memset(&header, 0, sizeof(struct acpi_table_header)); diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 568ac0e4a3c6a..db7f2aa9a457d 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -412,3 +412,36 @@ next_table: return_ACPI_STATUS(AE_OK); } + +/******************************************************************************* + * + * FUNCTION: acpi_is_valid_signature + * + * PARAMETERS: signature - Sig string to be validated + * + * RETURN: TRUE if signature is correct length and has valid characters + * + * DESCRIPTION: Validate an ACPI table signature. + * + ******************************************************************************/ + +u8 acpi_is_valid_signature(char *signature) +{ + u32 i; + + /* Validate the signature length */ + + if (strlen(signature) != ACPI_NAME_SIZE) { + return (FALSE); + } + + /* Validate each character in the signature */ + + for (i = 0; i < ACPI_NAME_SIZE; i++) { + if (!acpi_ut_valid_acpi_char(signature[i], i)) { + return (FALSE); + } + } + + return (TRUE); +} -- GitLab From 2aabfad7c6680178ffa8f02957287178a58a46ca Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:28:47 +0800 Subject: [PATCH 4869/7006] ACPICA: Disassembler: Update for new listing mode ACPICA commit 2ed09bb7619d25f5a5c065c33a8a775a6db3a856 ACPICA commit 2fefacf73825b0ec96bbfc4f70a256735b715d6c This mode emits AML code along with the ASL code. A new global was needed to ensure the listing mode is completely separate from the debugger verbose mode. Emits the correct AML offset for the AML code. The -l option now works for both the compiler and disassembler. Linux kernel is not affected by this commit. Link: https://github.com/acpica/acpica/commit/2fefacf7 Link: https://github.com/acpica/acpica/commit/2ed09bb7 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 79eb35d080a02..1283b19e29e89 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -307,9 +307,9 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); -ACPI_INIT_GLOBAL(union acpi_parse_object *, acpi_gbl_previous_op, NULL); ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm); +ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose); ACPI_GLOBAL(u8, acpi_gbl_num_external_methods); ACPI_GLOBAL(u32, acpi_gbl_resolved_external_methods); -- GitLab From 92b21a9502ea3a83464aea885b3c65c528b10190 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:28:54 +0800 Subject: [PATCH 4870/7006] ACPICA: Update info messages during ACPICA init ACPICA commit 4ccf8a1cc499ec8f00345f662a5887483980e1dd Small cleanup of messages. Link: https://github.com/acpica/acpica/commit/4ccf8a1c Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsinit.c | 9 +++++++++ drivers/acpi/acpica/tbxfload.c | 4 ++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index 95779e8ec3bb2..bbf52f0dc046c 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -237,6 +237,15 @@ acpi_ds_initialize_objects(u32 table_index, return_ACPI_STATUS(status); } + /* DSDT is always the first AML table */ + + if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT)) { + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, + "\nInitializing Namespace objects:\n")); + } + + /* Summary of objects initialized */ + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Table [%4.4s] (id %4.4X) - %4u Objects with %3u Devices, " "%3u Regions, %3u Methods (%u/%u/%u Serial/Non/Cvt)\n", diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 7862cf04a1640..6cbb2f7a35e85 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -208,11 +208,11 @@ static acpi_status acpi_tb_load_namespace(void) if (!tables_failed) { ACPI_INFO((AE_INFO, - "All (%u) ACPI AML tables successfully loaded", + "%u ACPI AML tables successfully acquired and loaded", tables_loaded)); } else { ACPI_ERROR((AE_INFO, - "%u ACPI AML tables loaded, %u failed", + "%u ACPI AML tables successfully acquired and loaded, %u failed", tables_loaded, tables_failed)); } -- GitLab From 8ec3f459073e67e5c6d78507dec693064b3040a2 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 25 Aug 2015 10:29:01 +0800 Subject: [PATCH 4871/7006] ACPICA: Tables: Fix global table list issues by removing fixed table indexes ACPICA commit c0b38b4c3982c2336ee92a2a14716107248bd941 The fixed table indexes leave holes in the global table list: 1. One hole can be seen when there is only 1 FACS provided by the BIOS. 2. Tow holes can be seen when it is a reduced hardware platform. The holes do not break OSPMs but have broken ACPI debugger "tables" command. Also the "fixed table indexes" mechanism may make the descriptors of the standard tables installed earlier than DSDT to be overwritten by the descriptors of the fixed tables. For example, FACP disappears from the global table list after DSDT is installed. This patch fixes all above issues by removing the "fixed table indexes" mechanism which is too complicated to be maintained in a regression safe manner. After removal, the table loader will determine the indexes of the fixed tables. Lv Zheng. Link: https://github.com/acpica/acpica/commit/c0b38b4c Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 3 +++ drivers/acpi/acpica/aclocal.h | 6 ++--- drivers/acpi/acpica/actables.h | 7 +++--- drivers/acpi/acpica/tbfadt.c | 6 ++--- drivers/acpi/acpica/tbinstal.c | 40 ++++++++++++++++++---------------- drivers/acpi/acpica/tbutils.c | 37 ++++++++++++------------------- drivers/acpi/acpica/tbxfload.c | 10 ++++----- 7 files changed, 51 insertions(+), 58 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 1283b19e29e89..e78667ee5d0b6 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -58,6 +58,9 @@ ACPI_GLOBAL(struct acpi_table_list, acpi_gbl_root_table_list); ACPI_GLOBAL(struct acpi_table_header *, acpi_gbl_DSDT); ACPI_GLOBAL(struct acpi_table_header, acpi_gbl_original_dsdt_header); +ACPI_INIT_GLOBAL(u32, acpi_gbl_dsdt_index, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL(u32, acpi_gbl_facs_index, ACPI_INVALID_TABLE_INDEX); +ACPI_INIT_GLOBAL(u32, acpi_gbl_xfacs_index, ACPI_INVALID_TABLE_INDEX); #if (!ACPI_REDUCED_HARDWARE) ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index a6b68878cdbe1..92cbaeef3f346 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -213,11 +213,9 @@ struct acpi_table_list { #define ACPI_ROOT_ORIGIN_ALLOCATED (1) #define ACPI_ROOT_ALLOW_RESIZE (2) -/* Predefined (fixed) table indexes */ +/* Predefined table indexes */ -#define ACPI_TABLE_INDEX_DSDT (0) -#define ACPI_TABLE_INDEX_FACS (1) -#define ACPI_TABLE_INDEX_X_FACS (2) +#define ACPI_INVALID_TABLE_INDEX (0xFFFFFFFF) struct acpi_find_context { char *search_for; diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 58497b7e33472..ab7f3a03f1797 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -154,13 +154,12 @@ void acpi_tb_check_dsdt_header(void); struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index); void -acpi_tb_install_table_with_override(u32 table_index, - struct acpi_table_desc *new_table_desc, - u8 override); +acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, + u8 override, u32 *table_index); acpi_status acpi_tb_install_fixed_table(acpi_physical_address address, - char *signature, u32 table_index); + char *signature, u32 *table_index); acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 6253001b6375d..455a0700db392 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -345,7 +345,7 @@ void acpi_tb_parse_fadt(u32 table_index) /* Obtain the DSDT and FACS tables via their addresses within the FADT */ acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt, - ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT); + ACPI_SIG_DSDT, &acpi_gbl_dsdt_index); /* If Hardware Reduced flag is set, there is no FACS */ @@ -354,13 +354,13 @@ void acpi_tb_parse_fadt(u32 table_index) acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.facs, ACPI_SIG_FACS, - ACPI_TABLE_INDEX_FACS); + &acpi_gbl_facs_index); } if (acpi_gbl_FADT.Xfacs) { acpi_tb_install_fixed_table((acpi_physical_address) acpi_gbl_FADT.Xfacs, ACPI_SIG_FACS, - ACPI_TABLE_INDEX_X_FACS); + &acpi_gbl_xfacs_index); } } } diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c index 15ea98e0068d8..6319b42420c61 100644 --- a/drivers/acpi/acpica/tbinstal.c +++ b/drivers/acpi/acpica/tbinstal.c @@ -100,9 +100,9 @@ acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) * * FUNCTION: acpi_tb_install_table_with_override * - * PARAMETERS: table_index - Index into root table array - * new_table_desc - New table descriptor to install + * PARAMETERS: new_table_desc - New table descriptor to install * override - Whether override should be performed + * table_index - Where the table index is returned * * RETURN: None * @@ -114,12 +114,14 @@ acpi_tb_compare_tables(struct acpi_table_desc *table_desc, u32 table_index) ******************************************************************************/ void -acpi_tb_install_table_with_override(u32 table_index, - struct acpi_table_desc *new_table_desc, - u8 override) +acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, + u8 override, u32 *table_index) { + u32 i; + acpi_status status; - if (table_index >= acpi_gbl_root_table_list.current_table_count) { + status = acpi_tb_get_next_table_descriptor(&i, NULL); + if (ACPI_FAILURE(status)) { return; } @@ -134,8 +136,7 @@ acpi_tb_install_table_with_override(u32 table_index, acpi_tb_override_table(new_table_desc); } - acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. - tables[table_index], + acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.tables[i], new_table_desc->address, new_table_desc->flags, new_table_desc->pointer); @@ -143,9 +144,13 @@ acpi_tb_install_table_with_override(u32 table_index, acpi_tb_print_table_header(new_table_desc->address, new_table_desc->pointer); + /* This synchronizes acpi_gbl_dsdt_index */ + + *table_index = i; + /* Set the global integer width (based upon revision of the DSDT) */ - if (table_index == ACPI_TABLE_INDEX_DSDT) { + if (i == acpi_gbl_dsdt_index) { acpi_ut_set_integer_width(new_table_desc->pointer->revision); } } @@ -157,7 +162,7 @@ acpi_tb_install_table_with_override(u32 table_index, * PARAMETERS: address - Physical address of DSDT or FACS * signature - Table signature, NULL if no need to * match - * table_index - Index into root table array + * table_index - Where the table index is returned * * RETURN: Status * @@ -168,7 +173,7 @@ acpi_tb_install_table_with_override(u32 table_index, acpi_status acpi_tb_install_fixed_table(acpi_physical_address address, - char *signature, u32 table_index) + char *signature, u32 *table_index) { struct acpi_table_desc new_table_desc; acpi_status status; @@ -200,7 +205,9 @@ acpi_tb_install_fixed_table(acpi_physical_address address, goto release_and_exit; } - acpi_tb_install_table_with_override(table_index, &new_table_desc, TRUE); + /* Add the table to the global root table list */ + + acpi_tb_install_table_with_override(&new_table_desc, TRUE, table_index); release_and_exit: @@ -355,13 +362,8 @@ acpi_tb_install_standard_table(acpi_physical_address address, /* Add the table to the global root table list */ - status = acpi_tb_get_next_table_descriptor(&i, NULL); - if (ACPI_FAILURE(status)) { - goto release_and_exit; - } - - *table_index = i; - acpi_tb_install_table_with_override(i, &new_table_desc, override); + acpi_tb_install_table_with_override(&new_table_desc, override, + table_index); release_and_exit: diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index db7f2aa9a457d..b1d500e47bdbf 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -74,22 +74,20 @@ acpi_status acpi_tb_initialize_facs(void) if (acpi_gbl_reduced_hardware) { acpi_gbl_FACS = NULL; return (AE_OK); - } - - (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &acpi_gbl_facs32)); - (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_X_FACS, - ACPI_CAST_INDIRECT_PTR(struct - acpi_table_header, - &acpi_gbl_facs64)); - - if (acpi_gbl_facs64 - && (!acpi_gbl_facs32 || !acpi_gbl_use32_bit_facs_addresses)) { - acpi_gbl_FACS = acpi_gbl_facs64; - } else if (acpi_gbl_facs32) { + } else if (acpi_gbl_FADT.Xfacs && + (!acpi_gbl_FADT.facs + || !acpi_gbl_use32_bit_facs_addresses)) { + (void)acpi_get_table_by_index(acpi_gbl_xfacs_index, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &acpi_gbl_facs32)); acpi_gbl_FACS = acpi_gbl_facs32; + } else if (acpi_gbl_FADT.facs) { + (void)acpi_get_table_by_index(acpi_gbl_facs_index, + ACPI_CAST_INDIRECT_PTR(struct + acpi_table_header, + &acpi_gbl_facs64)); + acpi_gbl_FACS = acpi_gbl_facs64; } /* If there is no FACS, just continue. There was already an error msg */ @@ -192,7 +190,7 @@ struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index) acpi_tb_uninstall_table(table_desc); acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list. - tables[ACPI_TABLE_INDEX_DSDT], + tables[acpi_gbl_dsdt_index], ACPI_PTR_TO_PHYSADDR(new_table), ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, new_table); @@ -369,13 +367,6 @@ acpi_status __init acpi_tb_parse_root_table(acpi_physical_address rsdp_address) table_entry_size); table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header)); - /* - * First three entries in the table array are reserved for the DSDT - * and 32bit/64bit FACS, which are not actually present in the - * RSDT/XSDT - they come from the FADT - */ - acpi_gbl_root_table_list.current_table_count = 3; - /* Initialize the root table array from the RSDT/XSDT */ for (i = 0; i < table_count; i++) { diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 6cbb2f7a35e85..fb4d4e64f8aa2 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -116,12 +116,12 @@ static acpi_status acpi_tb_load_namespace(void) if (!acpi_gbl_root_table_list.current_table_count || !ACPI_COMPARE_NAME(& (acpi_gbl_root_table_list. - tables[ACPI_TABLE_INDEX_DSDT].signature), + tables[acpi_gbl_dsdt_index].signature), ACPI_SIG_DSDT) || ACPI_FAILURE(acpi_tb_validate_table (&acpi_gbl_root_table_list. - tables[ACPI_TABLE_INDEX_DSDT]))) { + tables[acpi_gbl_dsdt_index]))) { status = AE_NO_ACPI_TABLES; goto unlock_and_exit; } @@ -133,7 +133,7 @@ static acpi_status acpi_tb_load_namespace(void) * .Pointer field is not validated until after call to acpi_tb_validate_table. */ acpi_gbl_DSDT = - acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer; + acpi_gbl_root_table_list.tables[acpi_gbl_dsdt_index].pointer; /* * Optionally copy the entire DSDT to local memory (instead of simply @@ -142,7 +142,7 @@ static acpi_status acpi_tb_load_namespace(void) * the DSDT. */ if (acpi_gbl_copy_dsdt_locally) { - new_dsdt = acpi_tb_copy_dsdt(ACPI_TABLE_INDEX_DSDT); + new_dsdt = acpi_tb_copy_dsdt(acpi_gbl_dsdt_index); if (new_dsdt) { acpi_gbl_DSDT = new_dsdt; } @@ -159,7 +159,7 @@ static acpi_status acpi_tb_load_namespace(void) /* Load and parse tables */ - status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node); + status = acpi_ns_load_table(acpi_gbl_dsdt_index, acpi_gbl_root_node); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "[DSDT] table load failed")); tables_failed++; -- GitLab From 7484619bff495c30e977dafe2ff735477bd569ff Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 25 Aug 2015 10:29:08 +0800 Subject: [PATCH 4872/7006] ACPICA: Tables: Cleanup to reduce FACS globals ACPICA commit 3f42ba76e2a0453976d3108296d5f656fdf2bd6e In this patch, FACS table mapping is also tuned a bit so that only the selected FACS table will be mapped by the OSPM (mapped on demand) and the FACS related global variables can be reduced. Lv Zheng. Link: https://github.com/acpica/acpica/commit/3f42ba76 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 -- drivers/acpi/acpica/hwxfsleep.c | 15 ++------------- drivers/acpi/acpica/tbutils.c | 9 +++++---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index e78667ee5d0b6..95ed861e8632c 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -64,8 +64,6 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_xfacs_index, ACPI_INVALID_TABLE_INDEX); #if (!ACPI_REDUCED_HARDWARE) ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_FACS); -ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_facs32); -ACPI_GLOBAL(struct acpi_table_facs *, acpi_gbl_facs64); #endif /* !ACPI_REDUCED_HARDWARE */ diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c index 52dfd0d050fa3..d62a61612b3f1 100644 --- a/drivers/acpi/acpica/hwxfsleep.c +++ b/drivers/acpi/acpica/hwxfsleep.c @@ -160,19 +160,8 @@ acpi_set_firmware_waking_vectors(acpi_physical_address physical_address, ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vectors); - /* If Hardware Reduced flag is set, there is no FACS */ - - if (acpi_gbl_reduced_hardware) { - return_ACPI_STATUS (AE_OK); - } - - if (acpi_gbl_facs32) { - (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_facs32, - physical_address, - physical_address64); - } - if (acpi_gbl_facs64) { - (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_facs64, + if (acpi_gbl_FACS) { + (void)acpi_hw_set_firmware_waking_vectors(acpi_gbl_FACS, physical_address, physical_address64); } diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index b1d500e47bdbf..4337990127cc3 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -68,6 +68,7 @@ acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size); acpi_status acpi_tb_initialize_facs(void) { + struct acpi_table_facs *facs; /* If Hardware Reduced flag is set, there is no FACS */ @@ -80,14 +81,14 @@ acpi_status acpi_tb_initialize_facs(void) (void)acpi_get_table_by_index(acpi_gbl_xfacs_index, ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, - &acpi_gbl_facs32)); - acpi_gbl_FACS = acpi_gbl_facs32; + &facs)); + acpi_gbl_FACS = facs; } else if (acpi_gbl_FADT.facs) { (void)acpi_get_table_by_index(acpi_gbl_facs_index, ACPI_CAST_INDIRECT_PTR(struct acpi_table_header, - &acpi_gbl_facs64)); - acpi_gbl_FACS = acpi_gbl_facs64; + &facs)); + acpi_gbl_FACS = facs; } /* If there is no FACS, just continue. There was already an error msg */ -- GitLab From 10ac218e9a1e76e0d3adec8fe2e2f84bbc138759 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:29:17 +0800 Subject: [PATCH 4873/7006] ACPICA: Headers: Fix some comments, no functional change ACPICA commit 539f8c03fe64305725bd85343e42f3b6c42aad14 A couple typos and long lines. Link: https://github.com/acpica/acpica/commit/539f8c03 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acenv.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 3cedd43943f42..1332537d40db7 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -89,8 +89,8 @@ #endif /* - * acpi_bin/acpi_dump/acpi_help/acpi_names/acpi_src/acpi_xtract/Example configuration. - * All single threaded. + * acpi_bin/acpi_dump/acpi_help/acpi_names/acpi_src/acpi_xtract/Example + * configuration. All single threaded. */ #if (defined ACPI_BIN_APP) || \ (defined ACPI_DUMP_APP) || \ @@ -123,7 +123,7 @@ #define ACPI_USE_NATIVE_RSDP_POINTER #endif -/* acpi_dump configuration. Native mapping used if provied by OSPMs */ +/* acpi_dump configuration. Native mapping used if provided by the host */ #ifdef ACPI_DUMP_APP #define ACPI_USE_NATIVE_MEMORY_MAPPING @@ -323,8 +323,8 @@ * ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and * the standard header files may be used. * - * The ACPICA subsystem only uses low level C library functions that do not call - * operating system services and may therefore be inlined in the code. + * The ACPICA subsystem only uses low level C library functions that do not + * call operating system services and may therefore be inlined in the code. * * It may be necessary to tailor these include files to the target * generation environment. -- GitLab From 17dd4dcfadffba93cf18652eb16b345526b04ce1 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:29:25 +0800 Subject: [PATCH 4874/7006] ACPICA: acpinames: Add new options and wildcard support ACPICA commit 0ecf5b5a41c3d2e09af48f0fdbc9ae784f631788 - Add wilcard support for input filenames. - Add -l option to load tables and exit, no display. This is useful for validation of the namespace during BIOS generation. - Add -x option for specifying debug level. Linux kernel is not affected by this commit. Link: https://github.com/acpica/acpica/commit/0ecf5b5a Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acutils.h | 2 +- drivers/acpi/acpica/utmisc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h index 566ff4df02fd4..fb2aa5066f3fa 100644 --- a/drivers/acpi/acpica/acutils.h +++ b/drivers/acpi/acpica/acutils.h @@ -517,7 +517,7 @@ const struct acpi_exception_info *acpi_ut_validate_exception(acpi_status u8 acpi_ut_is_pci_root_bridge(char *id); -#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP) +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) u8 acpi_ut_is_aml_table(struct acpi_table_header *table); #endif diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 98087ea1cdb3e..517a5ec477424 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -75,7 +75,7 @@ u8 acpi_ut_is_pci_root_bridge(char *id) return (FALSE); } -#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP) +#if (defined ACPI_ASL_COMPILER || defined ACPI_EXEC_APP || defined ACPI_NAMES_APP) /******************************************************************************* * * FUNCTION: acpi_ut_is_aml_table -- GitLab From 93cdafa071bd436596a0501fd43f4fab89c2be78 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:29:33 +0800 Subject: [PATCH 4875/7006] ACPICA: acpiexec/acpinames: Support very large number of ACPI tables ACPICA commit ca3bd4c5cdc39a9009280032adbbc20f34e94c47 Fix a couple of issues with >40 ACPI tables. Return exit error for acpinames to enable use with BIOS builds. The new exported function is used by acpinames. For Linux kernel, this change is a no-op. Link: https://github.com/acpica/acpica/commit/ca3bd4c5 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 5 +++++ drivers/acpi/acpica/tbxfload.c | 17 ++++++++++++----- drivers/acpi/acpica/utfileio.c | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index ab7f3a03f1797..f7731f260c318 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -165,4 +165,9 @@ acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); u8 acpi_is_valid_signature(char *signature); +/* + * tbxfload + */ +acpi_status acpi_tb_load_namespace(void); + #endif /* __ACTABLES_H__ */ diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index fb4d4e64f8aa2..96b82a818d766 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -51,9 +51,6 @@ #define _COMPONENT ACPI_TABLES ACPI_MODULE_NAME("tbxfload") -/* Local prototypes */ -static acpi_status acpi_tb_load_namespace(void); - /******************************************************************************* * * FUNCTION: acpi_load_tables @@ -65,7 +62,6 @@ static acpi_status acpi_tb_load_namespace(void); * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT * ******************************************************************************/ - acpi_status __init acpi_load_tables(void) { acpi_status status; @@ -75,6 +71,13 @@ acpi_status __init acpi_load_tables(void) /* Load the namespace from the tables */ status = acpi_tb_load_namespace(); + + /* Don't let single failures abort the load */ + + if (status == AE_CTRL_TERMINATE) { + status = AE_OK; + } + if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "While loading namespace from ACPI tables")); @@ -97,7 +100,7 @@ ACPI_EXPORT_SYMBOL_INIT(acpi_load_tables) * the RSDT/XSDT. * ******************************************************************************/ -static acpi_status acpi_tb_load_namespace(void) +acpi_status acpi_tb_load_namespace(void) { acpi_status status; u32 i; @@ -214,6 +217,10 @@ static acpi_status acpi_tb_load_namespace(void) ACPI_ERROR((AE_INFO, "%u ACPI AML tables successfully acquired and loaded, %u failed", tables_loaded, tables_failed)); + + /* Indicate at least one failure */ + + status = AE_CTRL_TERMINATE; } unlock_and_exit: diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c index 857af824337be..75a94f52b4bee 100644 --- a/drivers/acpi/acpica/utfileio.c +++ b/drivers/acpi/acpica/utfileio.c @@ -312,7 +312,7 @@ acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table) /* Get the entire file */ fprintf(stderr, - "Reading ACPI table from file %10s - Length %.8u (0x%06X)\n", + "Reading ACPI table from file %12s - Length %.8u (0x%06X)\n", filename, file_size, file_size); status = acpi_ut_read_table(file, table, &table_length); -- GitLab From 3c0503dd289eb6658f16d77fa12b3a30a4072be3 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:29:39 +0800 Subject: [PATCH 4876/7006] ACPICA: Table handling: Cleanup and update debug output for tools ACPICA commit 93862bd7a227543bc617d822ef5c4f8a5d68b519 Add output of table OEM ID along with signature to support lots of SSDTs. Cleanup use of table pointers. Link: https://github.com/acpica/acpica/commit/93862bd7 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsinit.c | 11 +++---- drivers/acpi/acpica/tbxfload.c | 53 +++++++++++++++------------------- 2 files changed, 30 insertions(+), 34 deletions(-) diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c index bbf52f0dc046c..920f1b199bc6f 100644 --- a/drivers/acpi/acpica/dsinit.c +++ b/drivers/acpi/acpica/dsinit.c @@ -247,11 +247,12 @@ acpi_ds_initialize_objects(u32 table_index, /* Summary of objects initialized */ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, - "Table [%4.4s] (id %4.4X) - %4u Objects with %3u Devices, " - "%3u Regions, %3u Methods (%u/%u/%u Serial/Non/Cvt)\n", - table->signature, owner_id, info.object_count, - info.device_count, info.op_region_count, - info.method_count, info.serial_method_count, + "Table [%4.4s:%8.8s] (id %.2X) - %4u Objects with %3u Devices, " + "%3u Regions, %4u Methods (%u/%u/%u Serial/Non/Cvt)\n", + table->signature, table->oem_table_id, owner_id, + info.object_count, info.device_count, + info.op_region_count, info.method_count, + info.serial_method_count, info.non_serial_method_count, info.serialized_method_count)); diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c index 96b82a818d766..55ee14ca94181 100644 --- a/drivers/acpi/acpica/tbxfload.c +++ b/drivers/acpi/acpica/tbxfload.c @@ -105,6 +105,7 @@ acpi_status acpi_tb_load_namespace(void) acpi_status status; u32 i; struct acpi_table_header *new_dsdt; + struct acpi_table_desc *table; u32 tables_loaded = 0; u32 tables_failed = 0; @@ -116,15 +117,11 @@ acpi_status acpi_tb_load_namespace(void) * Load the namespace. The DSDT is required, but any SSDT and * PSDT tables are optional. Verify the DSDT. */ + table = &acpi_gbl_root_table_list.tables[acpi_gbl_dsdt_index]; + if (!acpi_gbl_root_table_list.current_table_count || - !ACPI_COMPARE_NAME(& - (acpi_gbl_root_table_list. - tables[acpi_gbl_dsdt_index].signature), - ACPI_SIG_DSDT) - || - ACPI_FAILURE(acpi_tb_validate_table - (&acpi_gbl_root_table_list. - tables[acpi_gbl_dsdt_index]))) { + !ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_DSDT) || + ACPI_FAILURE(acpi_tb_validate_table(table))) { status = AE_NO_ACPI_TABLES; goto unlock_and_exit; } @@ -135,8 +132,7 @@ acpi_status acpi_tb_load_namespace(void) * array can change dynamically as tables are loaded at run-time. Note: * .Pointer field is not validated until after call to acpi_tb_validate_table. */ - acpi_gbl_DSDT = - acpi_gbl_root_table_list.tables[acpi_gbl_dsdt_index].pointer; + acpi_gbl_DSDT = table->pointer; /* * Optionally copy the entire DSDT to local memory (instead of simply @@ -174,21 +170,15 @@ acpi_status acpi_tb_load_namespace(void) (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) { + table = &acpi_gbl_root_table_list.tables[i]; + if (!acpi_gbl_root_table_list.tables[i].address || - (!ACPI_COMPARE_NAME - (&(acpi_gbl_root_table_list.tables[i].signature), - ACPI_SIG_SSDT) - && - !ACPI_COMPARE_NAME(& - (acpi_gbl_root_table_list.tables[i]. - signature), ACPI_SIG_PSDT) - && - !ACPI_COMPARE_NAME(& - (acpi_gbl_root_table_list.tables[i]. - signature), ACPI_SIG_OSDT)) - || - ACPI_FAILURE(acpi_tb_validate_table - (&acpi_gbl_root_table_list.tables[i]))) { + (!ACPI_COMPARE_NAME(table->signature.ascii, ACPI_SIG_SSDT) + && !ACPI_COMPARE_NAME(table->signature.ascii, + ACPI_SIG_PSDT) + && !ACPI_COMPARE_NAME(table->signature.ascii, + ACPI_SIG_OSDT)) + || ACPI_FAILURE(acpi_tb_validate_table(table))) { continue; } @@ -198,10 +188,15 @@ acpi_status acpi_tb_load_namespace(void) status = acpi_ns_load_table(i, acpi_gbl_root_node); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, - "[%4.4s] table load failed", - &acpi_gbl_root_table_list.tables[i]. - signature.ascii[0])); + "(%4.4s:%8.8s) while loading table", + table->signature.ascii, + table->pointer->oem_table_id)); tables_failed++; + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, + "Table [%4.4s:%8.8s] (id FF) - Table namespace load failed\n\n", + table->signature.ascii, + table->pointer->oem_table_id)); } else { tables_loaded++; } @@ -215,8 +210,8 @@ acpi_status acpi_tb_load_namespace(void) tables_loaded)); } else { ACPI_ERROR((AE_INFO, - "%u ACPI AML tables successfully acquired and loaded, %u failed", - tables_loaded, tables_failed)); + "%u table load failures, %u successful", + tables_failed, tables_loaded)); /* Indicate at least one failure */ -- GitLab From 25823e784aac78964ada0e49efe2766d2aeb9fa4 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:29:45 +0800 Subject: [PATCH 4877/7006] ACPICA: Add additional debug info/statements ACPICA commit 74094ca9f51e2652a9b5f01722d8640a653cc75a For _REG methods and module-level code blocks. For acpiexec, add deletion of module-level blocks in case of an early abort. Link: https://github.com/acpica/acpica/commit/74094ca9 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/aclocal.h | 7 +++++++ drivers/acpi/acpica/evregion.c | 22 ++++++++++++++++++---- drivers/acpi/acpica/nseval.c | 3 ++- drivers/acpi/acpica/nsutils.c | 17 +++++++++++++++++ drivers/acpi/acpica/psloop.c | 14 +++++++++++++- 5 files changed, 57 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index 92cbaeef3f346..acbf68baa04cb 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -406,6 +406,13 @@ struct acpi_simple_repair_info { #define ACPI_NUM_RTYPES 5 /* Number of actual object types */ +/* Info for running the _REG methods */ + +struct acpi_reg_walk_info { + acpi_adr_space_type space_id; + u32 reg_run_count; +}; + /***************************************************************************** * * Event typedefs and structs diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 2ba28a63fb685..5ee79a16fe33b 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c @@ -626,9 +626,17 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, acpi_adr_space_type space_id) { acpi_status status; + struct acpi_reg_walk_info info; ACPI_FUNCTION_TRACE(ev_execute_reg_methods); + info.space_id = space_id; + info.reg_run_count = 0; + + ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, + " Running _REG methods for SpaceId %s\n", + acpi_ut_get_region_name(info.space_id))); + /* * Run all _REG methods for all Operation Regions for this space ID. This * is a separate walk in order to handle any interdependencies between @@ -637,7 +645,7 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, */ status = acpi_ns_walk_namespace(ACPI_TYPE_ANY, node, ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run, - NULL, &space_id, NULL); + NULL, &info, NULL); /* Special case for EC: handle "orphan" _REG methods with no region */ @@ -645,6 +653,11 @@ acpi_ev_execute_reg_methods(struct acpi_namespace_node *node, acpi_ev_orphan_ec_reg_method(node); } + ACPI_DEBUG_PRINT_RAW((ACPI_DB_NAMES, + " Executed %u _REG methods for SpaceId %s\n", + info.reg_run_count, + acpi_ut_get_region_name(info.space_id))); + return_ACPI_STATUS(status); } @@ -664,10 +677,10 @@ acpi_ev_reg_run(acpi_handle obj_handle, { union acpi_operand_object *obj_desc; struct acpi_namespace_node *node; - acpi_adr_space_type space_id; acpi_status status; + struct acpi_reg_walk_info *info; - space_id = *ACPI_CAST_PTR(acpi_adr_space_type, context); + info = ACPI_CAST_PTR(struct acpi_reg_walk_info, context); /* Convert and validate the device handle */ @@ -696,13 +709,14 @@ acpi_ev_reg_run(acpi_handle obj_handle, /* Object is a Region */ - if (obj_desc->region.space_id != space_id) { + if (obj_desc->region.space_id != info->space_id) { /* This region is for a different address space, just ignore it */ return (AE_OK); } + info->reg_run_count++; status = acpi_ev_execute_reg_method(obj_desc, ACPI_REG_CONNECT); return (status); } diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index 88822b7a958f1..7eba578d36f36 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c @@ -465,7 +465,8 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, status = acpi_ns_evaluate(info); - ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", + ACPI_DEBUG_PRINT((ACPI_DB_INIT_NAMES, + "Executed module-level code at %p\n", method_obj->method.aml_start)); /* Delete a possible implicit return value (in slack mode) */ diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index 9a34c5f040759..d1261fe374d54 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -596,6 +596,23 @@ void acpi_ns_terminate(void) ACPI_FUNCTION_TRACE(ns_terminate); +#ifdef ACPI_EXEC_APP + { + union acpi_operand_object *prev; + union acpi_operand_object *next; + + /* Delete any module-level code blocks */ + + next = acpi_gbl_module_code_list; + while (next) { + prev = next; + next = next->method.mutex; + prev->method.mutex = NULL; /* Clear the Mutex (cheated) field */ + acpi_ut_remove_reference(prev); + } + } +#endif + /* * Free the entire namespace -- all nodes and all objects * attached to the nodes diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c index 6b11fd7a93dc2..03ac8c9a67ab0 100644 --- a/drivers/acpi/acpica/psloop.c +++ b/drivers/acpi/acpica/psloop.c @@ -321,6 +321,8 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op, union acpi_operand_object *method_obj; struct acpi_namespace_node *parent_node; + ACPI_FUNCTION_TRACE(ps_link_module_code); + /* Get the tail of the list */ prev = next = acpi_gbl_module_code_list; @@ -340,9 +342,13 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op, method_obj = acpi_ut_create_internal_object(ACPI_TYPE_METHOD); if (!method_obj) { - return; + return_VOID; } + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Create/Link new code block: %p\n", + method_obj)); + if (parent_op->common.node) { parent_node = parent_op->common.node; } else { @@ -367,8 +373,14 @@ acpi_ps_link_module_code(union acpi_parse_object *parent_op, prev->method.mutex = method_obj; } } else { + ACPI_DEBUG_PRINT((ACPI_DB_PARSE, + "Appending to existing code block: %p\n", + prev)); + prev->method.aml_length += aml_length; } + + return_VOID; } /******************************************************************************* -- GitLab From e69ab9a99e1d112045dd87902e467daec0d189da Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:29:52 +0800 Subject: [PATCH 4878/7006] ACPICA: Debugger: Add option to display namespace summary/counts ACPICA commit bba222c15c2ce79076eb3a5e9d4d5f7120db8a00 If "Objects" command is invoked with no arguments, the counts for each object type are displayed. Linux kernel is not affected by this commit as currently debugger is not enabled in the Linux kernel. Link: https://github.com/acpica/acpica/commit/bba222c1 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 4 ++-- drivers/acpi/acpica/aclocal.h | 4 ++++ include/acpi/actypes.h | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 95ed861e8632c..c5971923cba4c 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -346,8 +346,8 @@ ACPI_GLOBAL(char, acpi_gbl_db_debug_filename[ACPI_DB_LINE_BUFFER_SIZE]); /* * Statistic globals */ -ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TYPE_NS_NODE_MAX + 1]); -ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TYPE_NS_NODE_MAX + 1]); +ACPI_GLOBAL(u16, acpi_gbl_obj_type_count[ACPI_TOTAL_TYPES]); +ACPI_GLOBAL(u16, acpi_gbl_node_type_count[ACPI_TOTAL_TYPES]); ACPI_GLOBAL(u16, acpi_gbl_obj_type_count_misc); ACPI_GLOBAL(u16, acpi_gbl_node_type_count_misc); ACPI_GLOBAL(u32, acpi_gbl_num_nodes); diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h index acbf68baa04cb..6f708267ad8cb 100644 --- a/drivers/acpi/acpica/aclocal.h +++ b/drivers/acpi/acpica/aclocal.h @@ -1131,6 +1131,10 @@ struct acpi_integrity_info { #define ACPI_DB_CONSOLE_OUTPUT 0x02 #define ACPI_DB_DUPLICATE_OUTPUT 0x03 +struct acpi_object_info { + u32 types[ACPI_TOTAL_TYPES]; +}; + /***************************************************************************** * * Debug diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h index 531eca49edd43..f914958c4adbc 100644 --- a/include/acpi/actypes.h +++ b/include/acpi/actypes.h @@ -662,6 +662,7 @@ typedef u32 acpi_object_type; #define ACPI_TYPE_DEBUG_OBJECT 0x10 #define ACPI_TYPE_EXTERNAL_MAX 0x10 +#define ACPI_NUM_TYPES (ACPI_TYPE_EXTERNAL_MAX + 1) /* * These are object types that do not map directly to the ACPI @@ -683,6 +684,7 @@ typedef u32 acpi_object_type; #define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple object_list Nodes */ #define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ +#define ACPI_TOTAL_TYPES (ACPI_TYPE_NS_NODE_MAX + 1) /* * These are special object types that never appear in -- GitLab From 47cdf8c692d5a64855a7aff83800d5bc5c925d7c Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:30:00 +0800 Subject: [PATCH 4879/7006] ACPICA: Make the max-number-of-loops runtime configurable ACPICA commit a9d9c2d0c2d077bb3175ec9c252cf0e5da3efd45 Was previously compile-time only. Add support option for acpiexec. Link: https://github.com/acpica/acpica/commit/a9d9c2d0 Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 4 ++++ drivers/acpi/acpica/dscontrol.c | 2 +- drivers/acpi/acpica/utinit.c | 1 + include/acpi/acconfig.h | 4 ---- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index c5971923cba4c..03c443b87c766 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -236,6 +236,10 @@ ACPI_INIT_GLOBAL(u32, acpi_gbl_nesting_level, 0); ACPI_GLOBAL(struct acpi_thread_state *, acpi_gbl_current_walk_list); +/* Maximum number of While() loop iterations before forced abort */ + +ACPI_GLOBAL(u16, acpi_gbl_max_loop_iterations); + /* Control method single step flag */ ACPI_GLOBAL(u8, acpi_gbl_cm_single_step); diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c index 39da9da62bbf5..435fc16e2f832 100644 --- a/drivers/acpi/acpica/dscontrol.c +++ b/drivers/acpi/acpica/dscontrol.c @@ -212,7 +212,7 @@ acpi_ds_exec_end_control_op(struct acpi_walk_state * walk_state, */ control_state->control.loop_count++; if (control_state->control.loop_count > - ACPI_MAX_LOOP_ITERATIONS) { + acpi_gbl_max_loop_iterations) { status = AE_AML_INFINITE_LOOP; break; } diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c index 7f897c63aa5be..28ab3a1d5ec16 100644 --- a/drivers/acpi/acpica/utinit.c +++ b/drivers/acpi/acpica/utinit.c @@ -207,6 +207,7 @@ acpi_status acpi_ut_init_globals(void) acpi_gbl_debugger_configuration = DEBUGGER_THREADING; acpi_gbl_osi_mutex = NULL; acpi_gbl_reg_methods_executed = FALSE; + acpi_gbl_max_loop_iterations = 0xFFFF; /* Hardware oriented */ diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h index 03aacfb3e98b8..e11611ca72a49 100644 --- a/include/acpi/acconfig.h +++ b/include/acpi/acconfig.h @@ -136,10 +136,6 @@ #define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 -/* Maximum number of While() loop iterations before forced abort */ - -#define ACPI_MAX_LOOP_ITERATIONS 0xFFFF - /* Maximum sleep allowed via Sleep() operator */ #define ACPI_MAX_SLEEP 2000 /* 2000 millisec == two seconds */ -- GitLab From cff9406128a4f9b683eb8c52a8864496e7025467 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:30:11 +0800 Subject: [PATCH 4880/7006] ACPICA: Header support to improve compatibility with MSVC ACPICA commit 5b4087fba991d8383046b550bbe22f3d8d9b9c8f Needed to improve MSVC editor support for symbols. For Linux kernel, this change is a no-op. Link: https://github.com/acpica/acpica/commit/5b4087fb Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/platform/acenv.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h index 1332537d40db7..ec00e2bb029e6 100644 --- a/include/acpi/platform/acenv.h +++ b/include/acpi/platform/acenv.h @@ -70,13 +70,14 @@ #ifdef ACPI_ASL_COMPILER #define ACPI_APPLICATION -#define ACPI_DISASSEMBLER #define ACPI_DEBUG_OUTPUT #define ACPI_CONSTANT_EVAL_ONLY #define ACPI_LARGE_NAMESPACE_NODE #define ACPI_DATA_TABLE_DISASSEMBLY #define ACPI_SINGLE_THREADED #define ACPI_32BIT_PHYSICAL_ADDRESS + +#define ACPI_DISASSEMBLER 1 #endif /* acpi_exec configuration. Multithreaded with full AML debugger */ @@ -151,12 +152,12 @@ #define ACPI_USE_LOCAL_CACHE #endif -/* Common debug support */ +/* Common debug/disassembler support */ #ifdef ACPI_FULL_DEBUG -#define ACPI_DEBUGGER #define ACPI_DEBUG_OUTPUT -#define ACPI_DISASSEMBLER +#define ACPI_DEBUGGER 1 +#define ACPI_DISASSEMBLER 1 #endif -- GitLab From f8fb4c383e7342731b77693edde9c6ea02ab0365 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 25 Aug 2015 10:30:19 +0800 Subject: [PATCH 4881/7006] ACPICA: Debugger: Split debugger initialization/termination APIs ACPICA commit 7a3f22baab000b186779dac64ad71d9776b8f432 It is likely that the debugger is enabled only when a userspace program explicitly tells a kernel to do so, so it shouldn't be initialized as early as current implementation. The only tool requiring ACPI_DEBUGGER is acpiexec, so acpiexec need to call the new APIs by itself. And BSD developers may also get notified to invoke the APIs for DDB enabling. Lv Zheng. This patch doesn't affect Linux kernel as debugger is currently not enabled in the Linux kernel. Link: https://github.com/acpica/acpica/commit/7a3f22ba Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 4 ---- drivers/acpi/acpica/utxface.c | 7 ------- drivers/acpi/acpica/utxfinit.c | 11 ----------- include/acpi/acpixf.h | 3 +++ 4 files changed, 3 insertions(+), 22 deletions(-) diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index b5a9c5126209c..447f6d3b0c81c 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -77,10 +77,6 @@ struct acpi_db_execute_walk { /* * dbxface - external debugger interfaces */ -acpi_status acpi_db_initialize(void); - -void acpi_db_terminate(void); - acpi_status acpi_db_single_step(struct acpi_walk_state *walk_state, union acpi_parse_object *op, u32 op_type); diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c index c2bd5e2485a4c..4f332815db00c 100644 --- a/drivers/acpi/acpica/utxface.c +++ b/drivers/acpi/acpica/utxface.c @@ -92,13 +92,6 @@ acpi_status __init acpi_terminate(void) acpi_ut_mutex_terminate(); -#ifdef ACPI_DEBUGGER - - /* Shut down the debugger */ - - acpi_db_terminate(); -#endif - /* Now we can shutdown the OS-dependent layer */ status = acpi_os_terminate(); diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c index 42a32a66ef22a..a7137ec284478 100644 --- a/drivers/acpi/acpica/utxfinit.c +++ b/drivers/acpi/acpica/utxfinit.c @@ -124,17 +124,6 @@ acpi_status __init acpi_initialize_subsystem(void) return_ACPI_STATUS(status); } - /* If configured, initialize the AML debugger */ - -#ifdef ACPI_DEBUGGER - status = acpi_db_initialize(); - if (ACPI_FAILURE(status)) { - ACPI_EXCEPTION((AE_INFO, status, - "During Debugger initialization")); - return_ACPI_STATUS(status); - } -#endif - return_ACPI_STATUS(AE_OK); } diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index f2e232717770a..d3d7ea0512750 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -917,6 +917,9 @@ ACPI_DBG_DEPENDENT_RETURN_VOID(void ACPI_APP_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(1) void ACPI_INTERNAL_VAR_XFACE acpi_log_error(const char *format, ...)) + acpi_status acpi_initialize_debugger(void); + +void acpi_terminate_debugger(void); /* * Divergences -- GitLab From 1bdc63bf05096afac4b1e5361417fb730d77dfc7 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 25 Aug 2015 10:30:27 +0800 Subject: [PATCH 4882/7006] ACPICA: Disassembler: Cleanup acpi_gbl_db_opt_disasm ACPICA commit 969989cf7f85e2a2a0cd048cd25fc706246a48a2 This patch cleans up the following global variable - acpi_gbl_db_opt_disasm: The setting is used to control the full disassembly feature for iasl. ACPI debugger (acpiexec) shall have nothing to do with it. Actually, acpiexec never links to ad_aml_disassemble(). This patch thus renames this global option to acpi_gbl_dm_opt_disasm and removes all acpiexec and debugger references on it. Lv Zheng. This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/969989cf Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acglobal.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 03c443b87c766..0007eb7f3a858 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -313,7 +313,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); -ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm); +ACPI_GLOBAL(u8, acpi_gbl_dm_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose); ACPI_GLOBAL(u8, acpi_gbl_num_external_methods); -- GitLab From a2352db584d6402c044a07b5b252b7f133ab70cf Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 25 Aug 2015 10:30:34 +0800 Subject: [PATCH 4883/7006] ACPICA: Disassembler: Cleanup acpi_gbl_db_opt_verbose acpiexec usage ACPICA commit 42d7ad7bfb1cfb95183c1386c77509f2036f521d When acpi_gbl_db_opt_verbose is used in acpi_dm_descending_op() (invoked by acpi_dm_disassemble()), it is actually exported by the disassembler but used by the debugger to distinguish the output of the disassembler for different debugger commands. It is by default TRUE but is set to FALSE for control method disassembly command - "disassemble". So it's initialization should be a part of the ACPI_DISASSEMBLER conditioned code. This patch uses ACPI_INIT_GLOBAL to achieve a clean manner so that when ACPI_DISASSEMBLER is not defined, ACPI_DEBUGGER conditioned code needn't link to this option. Since it is a disassembler exported variable, it is renamed to acpi_gbl_dm_opt_Verbose in this patch. As VERBOSE_PRINT() macro has only one user, this patch also removes the definition of this macro. Lv Zheng. This patch doesn't affect Linux kernel. Link: https://github.com/acpica/acpica/commit/42d7ad7b Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/acdebug.h | 3 --- drivers/acpi/acpica/acglobal.h | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h index 447f6d3b0c81c..eb2e926d8218f 100644 --- a/drivers/acpi/acpica/acdebug.h +++ b/drivers/acpi/acpica/acdebug.h @@ -67,9 +67,6 @@ struct acpi_db_execute_walk { }; #define PARAM_LIST(pl) pl -#define DBTEST_OUTPUT_LEVEL(lvl) if (acpi_gbl_db_opt_verbose) -#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\ - acpi_os_printf PARAM_LIST(fp);} #define EX_NO_SINGLE_STEP 1 #define EX_SINGLE_STEP 2 diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h index 0007eb7f3a858..09f37b5168087 100644 --- a/drivers/acpi/acpica/acglobal.h +++ b/drivers/acpi/acpica/acglobal.h @@ -312,10 +312,10 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE); ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE); ACPI_INIT_GLOBAL(u8, acpi_gbl_force_aml_disassembly, FALSE); +ACPI_INIT_GLOBAL(u8, acpi_gbl_dm_opt_verbose, TRUE); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_disasm); ACPI_GLOBAL(u8, acpi_gbl_dm_opt_listing); -ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose); ACPI_GLOBAL(u8, acpi_gbl_num_external_methods); ACPI_GLOBAL(u32, acpi_gbl_resolved_external_methods); ACPI_GLOBAL(struct acpi_external_list *, acpi_gbl_external_list); -- GitLab From 2e5321cb62ca1b29941d483c21b41f71b4dc8c78 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Tue, 25 Aug 2015 10:30:41 +0800 Subject: [PATCH 4884/7006] ACPICA: Debugger: Cleanup debugging outputs to dump name path without trailing underscores ACPICA commit 51a49c2fb4a73f302a6df2b8ddc1350dd261684d It is better to use unified ASL path name to interact with the developers. There are following acpi_ns_build_normalized_pathname() users invoking it for debugging purposes (acpiexec test results are attached): 1. acpi_ut_display_init_pathname (acpi_ns_handle_to_pathname): --------------------------------------------- Initializing Region \_SB.H_EC.ECF2 --------------------------------------------- 2. acpi_ns_print_node_pathname (acpi_ns_handle_to_pathname): --------------------------------------------- - ex \_SB.H_EC._STA Evaluating \_SB.H_EC._STA --------------------------------------------- 3. acpi_ds_print_node_pathname (acpi_ns_handle_to_pathname): --------------------------------------------- - level 211b console - execute \M1 ... **** Exception AE_AML_UNINITIALIZED_ARG during execution of method [\M1] (Node 009CB6B8) --------------------------------------------- 4. acpi_ex_dump_reference_obj (acpi_ns_handle_to_pathname): --------------------------------------------- - dump \_TZ.FAN4._PR0 ... [00] 00835E98 [Object Reference] Type [Named Object] 05 00828878 \_TZ.FN04 --------------------------------------------- 5. acpi_db_bus_walk (acpi_ns_handle_to_pathname): --------------------------------------------- - businfo \_SB.PCI0 Type 6 ... --------------------------------------------- 6. acpi_db_walk_and_match_name (acpi_ns_handle_to_pathname): --------------------------------------------- - find _PR0 \_TZ.FAN4._PR0 Package 002D8DF8 01 Elements 01 --------------------------------------------- 7. acpi_db_walk_for_specific_objects (acpi_ns_handle_to_pathname): --------------------------------------------- - methods ... \_SB.PCI0._PRT Method 0026D918 01 Args 0 Len 0005 Aml 0026B199 ... --------------------------------------------- 8. acpi_db_decode_and_dispaly_object (acpi_get_name): --------------------------------------------- - gpes Block 0 - Info 003AC7B0 device_node 003A0E08 [\_GPE] - FADT-defined GPE block ... --------------------------------------------- 9. acpi_db_display_gpes (acpi_get_name): --------------------------------------------- - dump \_GPE Object (003A0E08) Pathname: \_GPE --------------------------------------------- 10.ae_miscellaneous_tests (acpi_get_name): No output available This patch cleans up all of the above usages. ACPICA BZ 1178, Lv Zheng. Linux kernel's ACPICA debugging messages may also be changed. Link: https://github.com/acpica/acpica/commit/51a49c2f Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/dsdebug.c | 2 +- drivers/acpi/acpica/exdump.c | 2 +- drivers/acpi/acpica/nsutils.c | 2 +- drivers/acpi/acpica/utmisc.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/acpi/acpica/dsdebug.c b/drivers/acpi/acpica/dsdebug.c index a651d30133d03..309556efc5539 100644 --- a/drivers/acpi/acpica/dsdebug.c +++ b/drivers/acpi/acpica/dsdebug.c @@ -89,7 +89,7 @@ acpi_ds_print_node_pathname(struct acpi_namespace_node *node, buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(node, &buffer, FALSE); + status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); if (ACPI_SUCCESS(status)) { if (message) { ACPI_DEBUG_PRINT_RAW((ACPI_DB_DISPATCH, "%s ", diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c index b6495fb552f0b..d836f888bb163 100644 --- a/drivers/acpi/acpica/exdump.c +++ b/drivers/acpi/acpica/exdump.c @@ -996,7 +996,7 @@ static void acpi_ex_dump_reference_obj(union acpi_operand_object *obj_desc) acpi_os_printf(" %p ", obj_desc->reference.node); status = acpi_ns_handle_to_pathname(obj_desc->reference.node, - &ret_buf, FALSE); + &ret_buf, TRUE); if (ACPI_FAILURE(status)) { acpi_os_printf(" Could not convert name to pathname\n"); } else { diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index d1261fe374d54..de325ae04ce1c 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c @@ -83,7 +83,7 @@ acpi_ns_print_node_pathname(struct acpi_namespace_node *node, buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(node, &buffer, FALSE); + status = acpi_ns_handle_to_pathname(node, &buffer, TRUE); if (ACPI_SUCCESS(status)) { if (message) { acpi_os_printf("%s ", message); diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c index 517a5ec477424..bd4443bdcbad8 100644 --- a/drivers/acpi/acpica/utmisc.c +++ b/drivers/acpi/acpica/utmisc.c @@ -376,7 +376,7 @@ acpi_ut_display_init_pathname(u8 type, /* Get the full pathname to the node */ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER; - status = acpi_ns_handle_to_pathname(obj_handle, &buffer, FALSE); + status = acpi_ns_handle_to_pathname(obj_handle, &buffer, TRUE); if (ACPI_FAILURE(status)) { return; } -- GitLab From b7a4f7ff7f83bd42ee765f666e6c0a28545bc6d6 Mon Sep 17 00:00:00 2001 From: Bob Moore Date: Tue, 25 Aug 2015 10:30:48 +0800 Subject: [PATCH 4885/7006] ACPICA: Update version to 20150818 ACPICA commit d93470de8febeecdc20633fde11cb0b200fa773b Version 20150818. Link: https://github.com/acpica/acpica/commit/d93470de Signed-off-by: Bob Moore Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- include/acpi/acpixf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index d3d7ea0512750..c33eeabde1602 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -46,7 +46,7 @@ /* Current ACPICA subsystem version in YYYYMMDD format */ -#define ACPI_CA_VERSION 0x20150717 +#define ACPI_CA_VERSION 0x20150818 #include #include -- GitLab From d7499160107dd1367cf34873564b522a5516430c Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Mon, 24 Aug 2015 22:56:54 +0900 Subject: [PATCH 4886/7006] net-next: Fix warning while make xmldocs caused by skbuff.c This patch fix following warnings. .//net/core/skbuff.c:407: warning: No description found for parameter 'len' .//net/core/skbuff.c:407: warning: Excess function parameter 'length' description in '__netdev_alloc_skb' .//net/core/skbuff.c:476: warning: No description found for parameter 'len' .//net/core/skbuff.c:476: warning: Excess function parameter 'length' description in '__napi_alloc_skb' Signed-off-by: Masanari Iida Signed-off-by: David S. Miller --- net/core/skbuff.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index bf9a5d93c2d10..8a725cc50a90d 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -392,7 +392,7 @@ EXPORT_SYMBOL(napi_alloc_frag); /** * __netdev_alloc_skb - allocate an skbuff for rx on a specific device * @dev: network device to receive on - * @length: length to allocate + * @len: length to allocate * @gfp_mask: get_free_pages mask, passed to alloc_skb * * Allocate a new &sk_buff and assign it a usage count of one. The @@ -461,7 +461,7 @@ EXPORT_SYMBOL(__netdev_alloc_skb); /** * __napi_alloc_skb - allocate skbuff for rx in a specific NAPI instance * @napi: napi instance this buffer was allocated for - * @length: length to allocate + * @len: length to allocate * @gfp_mask: get_free_pages mask, passed to alloc_skb and alloc_pages * * Allocate a new sk_buff for use in NAPI receive. This buffer will -- GitLab From e252b3d1a1744af1431aca30e091420734c2b012 Mon Sep 17 00:00:00 2001 From: WANG Cong Date: Tue, 25 Aug 2015 10:38:53 -0700 Subject: [PATCH 4887/7006] route: fix a use-after-free This patch fixes the following crash: general protection fault: 0000 [#1] SMP DEBUG_PAGEALLOC CPU: 1 PID: 0 Comm: swapper/1 Not tainted 4.2.0-rc7+ #166 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 task: ffff88010656d280 ti: ffff880106570000 task.ti: ffff880106570000 RIP: 0010:[] [] dst_destroy+0xa6/0xef RSP: 0018:ffff880107603e38 EFLAGS: 00010202 RAX: 0000000000000001 RBX: ffff8800d225a000 RCX: ffffffff82250fd0 RDX: 0000000000000001 RSI: ffffffff82250fd0 RDI: 6b6b6b6b6b6b6b6b RBP: ffff880107603e58 R08: 0000000000000001 R09: 0000000000000001 R10: 000000000000b530 R11: ffff880107609000 R12: 0000000000000000 R13: ffffffff82343c40 R14: 0000000000000000 R15: ffffffff8182fb4f FS: 0000000000000000(0000) GS:ffff880107600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 00007fcabd9d3000 CR3: 00000000d7279000 CR4: 00000000000006e0 Stack: ffffffff82250fd0 ffff8801077d6f00 ffffffff82253c40 ffff8800d225a000 ffff880107603e68 ffffffff8182fb5d ffff880107603f08 ffffffff810d795e ffffffff810d7648 ffff880106574000 ffff88010656d280 ffff88010656d280 Call Trace: [] dst_destroy_rcu+0xe/0x1d [] rcu_process_callbacks+0x618/0x7eb [] ? rcu_process_callbacks+0x302/0x7eb [] ? dst_gc_task+0x1eb/0x1eb [] __do_softirq+0x178/0x39f [] irq_exit+0x41/0x95 [] smp_apic_timer_interrupt+0x34/0x40 [] apic_timer_interrupt+0x6d/0x80 [] ? default_idle+0x21/0x32 [] ? default_idle+0x1f/0x32 [] arch_cpu_idle+0xf/0x11 [] default_idle_call+0x1f/0x21 [] cpu_startup_entry+0x1ad/0x273 [] start_secondary+0x135/0x156 dst is freed right before lwtstate_put(), this is not correct... Fixes: 61adedf3e3f1 ("route: move lwtunnel state to dst_entry") Acked-by: Jiri Benc Signed-off-by: Cong Wang Signed-off-by: Cong Wang Signed-off-by: David S. Miller --- net/core/dst.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/core/dst.c b/net/core/dst.c index 50dcdbb0ee46e..477035ed7903f 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -262,11 +262,12 @@ again: if (dst->dev) dev_put(dst->dev); + lwtstate_put(dst->lwtstate); + if (dst->flags & DST_METADATA) kfree(dst); else kmem_cache_free(dst->ops->kmem_cachep, dst); - lwtstate_put(dst->lwtstate); dst = child; if (dst) { -- GitLab From 081958ebe150dc42a0f50669169c4177786b747e Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 25 Aug 2015 10:26:22 -0700 Subject: [PATCH 4888/7006] MAINTAINERS: Add VRF entry Add entry for new VRF device driver. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- MAINTAINERS | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 4e6dcb692d306..5110e62a0e57c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11078,6 +11078,14 @@ S: Supported F: drivers/regulator/ F: include/linux/regulator/ +VRF +M: David Ahern +M: Shrijeet Mukherjee +L: netdev@vger.kernel.org +S: Maintained +F: drivers/net/vrf.c +F: include/net/vrf.h + VT1211 HARDWARE MONITOR DRIVER M: Juerg Haefliger L: lm-sensors@lm-sensors.org -- GitLab From 48e92c44bd73a8bc213560058e6b18e45929526e Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Tue, 25 Aug 2015 18:36:50 +0200 Subject: [PATCH 4889/7006] vxlan: fix multiple inclusion of vxlan.h The vxlan_get_sk_family inline function was added after the last #endif, making multiple inclusion of net/vxlan.h fail. Move it to the proper place. Reported-by: Mark Rustad Fixes: 705cc62f6728c ("vxlan: provide access function for vxlan socket address family") Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- include/net/vxlan.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/net/vxlan.h b/include/net/vxlan.h index 6b3234599a2c5..480a319b4c925 100644 --- a/include/net/vxlan.h +++ b/include/net/vxlan.h @@ -241,9 +241,10 @@ static inline void vxlan_get_rx_port(struct net_device *netdev) { } #endif -#endif static inline unsigned short vxlan_get_sk_family(struct vxlan_sock *vs) { return vs->sock->sk->sk_family; } + +#endif -- GitLab From 04e1b7341dc33abe4dd3f761e2e9137701e55684 Mon Sep 17 00:00:00 2001 From: Shrikrishna Khare Date: Mon, 24 Aug 2015 14:24:11 -0700 Subject: [PATCH 4890/7006] MAINTAINERS: update vmxnet3 driver maintainer Shreyas Bhatewara would no longer maintain the vmxnet3 driver. Taking over the role of vmxnet3 maintainer. Signed-off-by: Shrikrishna Khare Signed off-by: Shreyas Bhatewara Signed-off-by: David S. Miller --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 5110e62a0e57c..38df5702ada04 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11053,7 +11053,7 @@ F: drivers/input/mouse/vmmouse.c F: drivers/input/mouse/vmmouse.h VMWARE VMXNET3 ETHERNET DRIVER -M: Shreyas Bhatewara +M: Shrikrishna Khare M: "VMware, Inc." L: netdev@vger.kernel.org S: Maintained -- GitLab From b01d04aa511b78c795dd258bf8689a421a6b4d0c Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 25 Aug 2015 15:54:25 -0700 Subject: [PATCH 4891/7006] rds: Fix improper gfp_t usage. >> net/rds/ib_recv.c:382:28: sparse: incorrect type in initializer (different base types) net/rds/ib_recv.c:382:28: expected int [signed] can_wait net/rds/ib_recv.c:382:28: got restricted gfp_t net/rds/ib_recv.c:828:23: sparse: cast to restricted __le64 Reported-by: kbuild test robot Signed-off-by: David S. Miller --- net/rds/ib_recv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 3afdcbdd06b4e..ed9b41e3b2773 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -379,7 +379,7 @@ void rds_ib_recv_refill(struct rds_connection *conn, int prefill, gfp_t gfp) struct ib_recv_wr *failed_wr; unsigned int posted = 0; int ret = 0; - int can_wait = gfp & __GFP_WAIT; + bool can_wait = !!(gfp & __GFP_WAIT); u32 pos; /* the goal here is to just make sure that someone, somewhere -- GitLab From 6e85d5ad36a26debc23a9a865c029cbe242b2dc8 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Mon, 24 Aug 2015 12:52:39 +0200 Subject: [PATCH 4892/7006] r8169: Add values missing in @get_stats64 from HW counters The r8169 driver collects statistical information returned by @get_stats64 by counting them in the driver itself, even though many (but not all) of the values are already collected by tally counters (TCs) in the NIC. Some of these TC values are not returned by @get_stats64. Especially the received multicast packages are missing from /proc/net/dev. Rectify this by fetching the TCs and returning them from rtl8169_get_stats64. The counters collected in the driver obviously disappear as soon as the driver is unloaded so after a driver is loaded the counters always start at 0. The TCs on the other hand are only reset by a power cycle. Without further considerations the values collected by the driver would not match up against the TC values. This patch introduces a new function rtl8169_reset_counters which resets the TCs. Also, since rtl8169_reset_counters shares most of its code with rtl8169_update_counters, refactor the shared code into two new functions rtl8169_map_counters and rtl8169_unmap_counters. Unfortunately chip versions prior to RTL_GIGA_MAC_VER_19 don't allow to reset the TCs programatically. Therefore introduce an addition to the rtl8169_private struct and a function rtl8169_init_counter_offsets to store the TCs at first rtl_open. Use these values as offsets in rtl8169_get_stats64. Propagate a failure to reset *and* update the counters up to rtl_open and emit a warning message, if so. Signed-off-by: Corinna Vinschen Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 163 ++++++++++++++++++++++++--- 1 file changed, 149 insertions(+), 14 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index f790f61ea78a2..d6d39df5b3dc9 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -637,6 +637,9 @@ enum rtl_register_content { /* _TBICSRBit */ TBILinkOK = 0x02000000, + /* ResetCounterCommand */ + CounterReset = 0x1, + /* DumpCounterCommand */ CounterDump = 0x8, @@ -747,6 +750,14 @@ struct rtl8169_counters { __le16 tx_underun; }; +struct rtl8169_tc_offsets { + bool inited; + __le64 tx_errors; + __le32 tx_multi_collision; + __le32 rx_multicast; + __le16 tx_aborted; +}; + enum rtl_flag { RTL_FLAG_TASK_ENABLED, RTL_FLAG_TASK_SLOW_PENDING, @@ -824,6 +835,7 @@ struct rtl8169_private { struct mii_if_info mii; struct rtl8169_counters counters; + struct rtl8169_tc_offsets tc_offset; u32 saved_wolopts; u32 opts1_mask; @@ -2179,6 +2191,73 @@ static int rtl8169_get_sset_count(struct net_device *dev, int sset) } } +static struct rtl8169_counters *rtl8169_map_counters(struct net_device *dev, + dma_addr_t *paddr, + u32 counter_cmd) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pci_dev->dev; + struct rtl8169_counters *counters; + u32 cmd; + + counters = dma_alloc_coherent(d, sizeof(*counters), paddr, GFP_KERNEL); + if (counters) { + RTL_W32(CounterAddrHigh, (u64)*paddr >> 32); + cmd = (u64)*paddr & DMA_BIT_MASK(32); + RTL_W32(CounterAddrLow, cmd); + RTL_W32(CounterAddrLow, cmd | counter_cmd); + } + return counters; +} + +static void rtl8169_unmap_counters (struct net_device *dev, + dma_addr_t paddr, + struct rtl8169_counters *counters) +{ + struct rtl8169_private *tp = netdev_priv(dev); + void __iomem *ioaddr = tp->mmio_addr; + struct device *d = &tp->pci_dev->dev; + + RTL_W32(CounterAddrLow, 0); + RTL_W32(CounterAddrHigh, 0); + + dma_free_coherent(d, sizeof(*counters), counters, paddr); +} + +DECLARE_RTL_COND(rtl_reset_counters_cond) +{ + void __iomem *ioaddr = tp->mmio_addr; + + return RTL_R32(CounterAddrLow) & CounterReset; +} + +static bool rtl8169_reset_counters(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_counters *counters; + dma_addr_t paddr; + bool ret = true; + + /* + * Versions prior to RTL_GIGA_MAC_VER_19 don't support resetting the + * tally counters. + */ + if (tp->mac_version < RTL_GIGA_MAC_VER_19) + return true; + + counters = rtl8169_map_counters(dev, &paddr, CounterReset); + if (!counters) + return false; + + if (!rtl_udelay_loop_wait_low(tp, &rtl_reset_counters_cond, 10, 1000)) + ret = false; + + rtl8169_unmap_counters(dev, paddr, counters); + + return ret; +} + DECLARE_RTL_COND(rtl_counters_cond) { void __iomem *ioaddr = tp->mmio_addr; @@ -2186,38 +2265,72 @@ DECLARE_RTL_COND(rtl_counters_cond) return RTL_R32(CounterAddrLow) & CounterDump; } -static void rtl8169_update_counters(struct net_device *dev) +static bool rtl8169_update_counters(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - struct device *d = &tp->pci_dev->dev; struct rtl8169_counters *counters; dma_addr_t paddr; - u32 cmd; + bool ret = true; /* * Some chips are unable to dump tally counters when the receiver * is disabled. */ if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0) - return; + return true; - counters = dma_alloc_coherent(d, sizeof(*counters), &paddr, GFP_KERNEL); + counters = rtl8169_map_counters(dev, &paddr, CounterDump); if (!counters) - return; - - RTL_W32(CounterAddrHigh, (u64)paddr >> 32); - cmd = (u64)paddr & DMA_BIT_MASK(32); - RTL_W32(CounterAddrLow, cmd); - RTL_W32(CounterAddrLow, cmd | CounterDump); + return false; if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000)) memcpy(&tp->counters, counters, sizeof(*counters)); + else + ret = false; - RTL_W32(CounterAddrLow, 0); - RTL_W32(CounterAddrHigh, 0); + rtl8169_unmap_counters(dev, paddr, counters); - dma_free_coherent(d, sizeof(*counters), counters, paddr); + return ret; +} + +static bool rtl8169_init_counter_offsets(struct net_device *dev) +{ + struct rtl8169_private *tp = netdev_priv(dev); + bool ret = false; + + /* + * rtl8169_init_counter_offsets is called from rtl_open. On chip + * versions prior to RTL_GIGA_MAC_VER_19 the tally counters are only + * reset by a power cycle, while the counter values collected by the + * driver are reset at every driver unload/load cycle. + * + * To make sure the HW values returned by @get_stats64 match the SW + * values, we collect the initial values at first open(*) and use them + * as offsets to normalize the values returned by @get_stats64. + * + * (*) We can't call rtl8169_init_counter_offsets from rtl_init_one + * for the reason stated in rtl8169_update_counters; CmdRxEnb is only + * set at open time by rtl_hw_start. + */ + + if (tp->tc_offset.inited) + return true; + + /* If both, reset and update fail, propagate to caller. */ + if (rtl8169_reset_counters(dev)) + ret = true; + + if (rtl8169_update_counters(dev)) + ret = true; + + tp->tc_offset.tx_errors = tp->counters.tx_errors; + tp->tc_offset.tx_multi_collision = tp->counters.tx_multi_collision; + tp->tc_offset.rx_multicast = tp->counters.rx_multicast; + tp->tc_offset.tx_aborted = tp->counters.tx_aborted; + tp->tc_offset.inited = true; + + return ret; } static void rtl8169_get_ethtool_stats(struct net_device *dev, @@ -7631,6 +7744,9 @@ static int rtl_open(struct net_device *dev) rtl_hw_start(dev); + if (!rtl8169_init_counter_offsets(dev)) + netif_warn(tp, hw, dev, "counter reset/update failed\n"); + netif_start_queue(dev); rtl_unlock_work(tp); @@ -7689,6 +7805,25 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) stats->rx_fifo_errors = dev->stats.rx_fifo_errors; stats->rx_missed_errors = dev->stats.rx_missed_errors; + /* + * Fetch additonal counter values missing in stats collected by driver + * from tally counters. + */ + rtl8169_update_counters(dev); + + /* + * Subtract values fetched during initalization. + * See rtl8169_init_counter_offsets for a description why we do that. + */ + stats->tx_errors = le64_to_cpu(tp->counters.tx_errors) - + le64_to_cpu(tp->tc_offset.tx_errors); + stats->collisions = le32_to_cpu(tp->counters.tx_multi_collision) - + le32_to_cpu(tp->tc_offset.tx_multi_collision); + stats->multicast = le32_to_cpu(tp->counters.rx_multicast) - + le32_to_cpu(tp->tc_offset.rx_multicast); + stats->tx_aborted_errors = le16_to_cpu(tp->counters.tx_aborted) - + le16_to_cpu(tp->tc_offset.tx_aborted); + return stats; } -- GitLab From dafc21995db9b2ef61a2d613f872a5c565731548 Mon Sep 17 00:00:00 2001 From: Govindarajulu Varadarajan <_govind@gmx.com> Date: Tue, 25 Aug 2015 14:15:11 +0530 Subject: [PATCH 4893/7006] enic: reduce ioread in devcmd2 posted_index is RO in firmware. We need not do ioread everytime to get posted index. Store posted index locally. Signed-off-by: Govindarajulu Varadarajan <_govind@gmx.com> Signed-off-by: David S. Miller --- drivers/net/ethernet/cisco/enic/vnic_dev.c | 8 +++++--- drivers/net/ethernet/cisco/enic/vnic_wq.h | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/cisco/enic/vnic_dev.c b/drivers/net/ethernet/cisco/enic/vnic_dev.c index 19a49a6e3911b..a3badefaf360a 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_dev.c +++ b/drivers/net/ethernet/cisco/enic/vnic_dev.c @@ -301,12 +301,12 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, struct devcmd2_result *result = dc2c->result + dc2c->next_result; unsigned int i; int delay, err; - u32 fetch_index, posted, new_posted; + u32 fetch_index, new_posted; + u32 posted = dc2c->posted; - posted = ioread32(&dc2c->wq_ctrl->posted_index); fetch_index = ioread32(&dc2c->wq_ctrl->fetch_index); - if (posted == 0xFFFFFFFF || fetch_index == 0xFFFFFFFF) + if (fetch_index == 0xFFFFFFFF) return -ENODEV; new_posted = (posted + 1) % DEVCMD2_RING_SIZE; @@ -331,6 +331,7 @@ static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, */ wmb(); iowrite32(new_posted, &dc2c->wq_ctrl->posted_index); + dc2c->posted = new_posted; if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT) return 0; @@ -402,6 +403,7 @@ static int vnic_dev_init_devcmd2(struct vnic_dev *vdev) enic_wq_init_start(&vdev->devcmd2->wq, 0, fetch_index, fetch_index, 0, 0); + vdev->devcmd2->posted = fetch_index; vnic_wq_enable(&vdev->devcmd2->wq); err = vnic_dev_alloc_desc_ring(vdev, &vdev->devcmd2->results_ring, diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.h b/drivers/net/ethernet/cisco/enic/vnic_wq.h index 8944af935a607..01209613d57d4 100644 --- a/drivers/net/ethernet/cisco/enic/vnic_wq.h +++ b/drivers/net/ethernet/cisco/enic/vnic_wq.h @@ -97,6 +97,7 @@ struct devcmd2_controller { int color; struct vnic_dev_ring results_ring; struct vnic_wq wq; + u32 posted; }; static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq) -- GitLab From ba54d3ced958435e1802daf992cfd44c26cd4cb7 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Tue, 25 Aug 2015 12:01:58 -0700 Subject: [PATCH 4894/7006] RDS: fix the dangling reference to rds_ib_incoming_slab On rds_ib_frag_slab allocation failure, ensure rds_ib_incoming_slab is not pointing to the detsroyed memory. Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_recv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index ed9b41e3b2773..6bbe620600606 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -1102,9 +1102,10 @@ int rds_ib_recv_init(void) rds_ib_frag_slab = kmem_cache_create("rds_ib_frag", sizeof(struct rds_page_frag), 0, SLAB_HWCACHE_ALIGN, NULL); - if (!rds_ib_frag_slab) + if (!rds_ib_frag_slab) { kmem_cache_destroy(rds_ib_incoming_slab); - else + rds_ib_incoming_slab = NULL; + } else ret = 0; out: return ret; -- GitLab From 3f6b3143031b678a8577df1f24ca977510aefcf5 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Tue, 25 Aug 2015 12:01:59 -0700 Subject: [PATCH 4895/7006] RDS: Fix rds MR reference count in rds_rdma_unuse() rds_rdma_unuse() drops the mr reference count which it hasn't taken. Correct way of removing mr is to remove mr from the tree and then rdma_destroy_mr() it first, then rds_mr_put() to decrement its reference count. Whichever thread holds last reference will free the mr via rds_mr_put() This bug was triggering weird null pointer crashes. One if the trace for it is captured below. BUG: unable to handle kernel NULL pointer dereference at 0000000000000104 IP: [] rds_ib_free_mr+0x31/0x130 [rds_rdma] PGD 4366fa067 PUD 4366f9067 PMD 0 Oops: 0000 [#1] SMP [...] task: ffff88046da6a000 ti: ffff88046da6c000 task.ti: ffff88046da6c000 RIP: 0010:[] [] rds_ib_free_mr+0x31/0x130 [rds_rdma] RSP: 0018:ffff88046fa43bd8 EFLAGS: 00010286 RAX: 0000000071d38b80 RBX: 0000000000000000 RCX: 0000000000000000 RDX: 0000000000000001 RSI: 0000000000000000 RDI: ffff880079e7ff40 RBP: ffff88046fa43bf8 R08: 0000000000000000 R09: 0000000000000000 R10: ffff88046fa43ca8 R11: ffff88046a802ed8 R12: ffff880079e7fa40 R13: 0000000000000000 R14: ffff880079e7ff40 R15: 0000000000000000 FS: 0000000000000000(0000) GS:ffff88046fa40000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 0000000000000104 CR3: 00000004366fb000 CR4: 00000000000006e0 Stack: ffff880079e7fa40 ffff880671d38f08 ffff880079e7ff40 0000000000000296 ffff88046fa43c28 ffffffffa087a38b ffff880079e7fa40 ffff880671d38f10 0000000000000000 0000000000000292 ffff88046fa43c48 ffffffffa087a3b6 Call Trace: [] rds_destroy_mr+0x8b/0xa0 [rds] [] __rds_put_mr_final+0x16/0x30 [rds] [] rds_rdma_unuse+0xc2/0x120 [rds] [] rds_recv_incoming_exthdrs+0x83/0xa0 [rds] [] rds_recv_incoming+0x92/0x200 [rds] [] rds_ib_process_recv+0x259/0x320 [rds_rdma] [] rds_ib_recv_tasklet_fn+0x1a8/0x490 [rds_rdma] [] ? __remove_hrtimer+0x58/0x90 [] tasklet_action+0xb1/0xc0 [] __do_softirq+0xe2/0x290 [] irq_exit+0xa6/0xb0 [] do_IRQ+0x65/0xf0 [] common_interrupt+0x6b/0x6b Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/rdma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/net/rds/rdma.c b/net/rds/rdma.c index c1df9b1cf3b25..4c93badeabf22 100644 --- a/net/rds/rdma.c +++ b/net/rds/rdma.c @@ -435,9 +435,10 @@ void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force) /* If the MR was marked as invalidate, this will * trigger an async flush. */ - if (zot_me) + if (zot_me) { rds_destroy_mr(mr); - rds_mr_put(mr); + rds_mr_put(mr); + } } void rds_rdma_free_op(struct rm_rdma_op *ro) -- GitLab From 6116c2030fff91950f68b7fffb5959c91a05aaf6 Mon Sep 17 00:00:00 2001 From: Wengang Wang Date: Tue, 25 Aug 2015 12:02:00 -0700 Subject: [PATCH 4896/7006] RDS: fix fmr pool dirty_count In rds_ib_flush_mr_pool(), dirty_count accounts the clean ones which is wrong. This can lead to a negative dirty count value. Lets fix it. Signed-off-by: Wengang Wang Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_rdma.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 7b7aac8cdb560..a275b7d205ef4 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -528,11 +528,13 @@ static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int fr /* * given an llist of mrs, put them all into the list_head for more processing */ -static void llist_append_to_list(struct llist_head *llist, struct list_head *list) +static unsigned int llist_append_to_list(struct llist_head *llist, + struct list_head *list) { struct rds_ib_mr *ibmr; struct llist_node *node; struct llist_node *next; + unsigned int count = 0; node = llist_del_all(llist); while (node) { @@ -540,7 +542,9 @@ static void llist_append_to_list(struct llist_head *llist, struct list_head *lis ibmr = llist_entry(node, struct rds_ib_mr, llnode); list_add_tail(&ibmr->unmap_list, list); node = next; + count++; } + return count; } /* @@ -581,7 +585,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, LIST_HEAD(unmap_list); LIST_HEAD(fmr_list); unsigned long unpinned = 0; - unsigned int nfreed = 0, ncleaned = 0, free_goal; + unsigned int nfreed = 0, dirty_to_clean = 0, free_goal; int ret = 0; rds_ib_stats_inc(s_ib_rdma_mr_pool_flush); @@ -623,8 +627,8 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, /* Get the list of all MRs to be dropped. Ordering matters - * we want to put drop_list ahead of free_list. */ - llist_append_to_list(&pool->drop_list, &unmap_list); - llist_append_to_list(&pool->free_list, &unmap_list); + dirty_to_clean = llist_append_to_list(&pool->drop_list, &unmap_list); + dirty_to_clean += llist_append_to_list(&pool->free_list, &unmap_list); if (free_all) llist_append_to_list(&pool->clean_list, &unmap_list); @@ -652,7 +656,6 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, kfree(ibmr); nfreed++; } - ncleaned++; } if (!list_empty(&unmap_list)) { @@ -678,7 +681,7 @@ static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, } atomic_sub(unpinned, &pool->free_pinned); - atomic_sub(ncleaned, &pool->dirty_count); + atomic_sub(dirty_to_clean, &pool->dirty_count); atomic_sub(nfreed, &pool->item_count); out: -- GitLab From ad1d7dc0d79d3dd2c5d2931b13edbd4fe33e5fac Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Tue, 25 Aug 2015 12:02:01 -0700 Subject: [PATCH 4897/7006] RDS: push FMR pool flush work to its own worker RDS FMR flush operation and also it races with connect/reconect which happes a lot with RDS. FMR flush being on common rds_wq aggrevates the problem. Lets push RDS FMR pool flush work to its own worker. Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib.c | 9 ++++++++- net/rds/ib.h | 2 ++ net/rds/ib_rdma.c | 27 ++++++++++++++++++++++++--- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/net/rds/ib.c b/net/rds/ib.c index 13814227b3b23..d020fade312ce 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -366,6 +366,7 @@ void rds_ib_exit(void) rds_ib_sysctl_exit(); rds_ib_recv_exit(); rds_trans_unregister(&rds_ib_transport); + rds_ib_fmr_exit(); } struct rds_transport rds_ib_transport = { @@ -401,10 +402,14 @@ int rds_ib_init(void) INIT_LIST_HEAD(&rds_ib_devices); - ret = ib_register_client(&rds_ib_client); + ret = rds_ib_fmr_init(); if (ret) goto out; + ret = ib_register_client(&rds_ib_client); + if (ret) + goto out_fmr_exit; + ret = rds_ib_sysctl_init(); if (ret) goto out_ibreg; @@ -427,6 +432,8 @@ out_sysctl: rds_ib_sysctl_exit(); out_ibreg: rds_ib_unregister_client(); +out_fmr_exit: + rds_ib_fmr_exit(); out: return ret; } diff --git a/net/rds/ib.h b/net/rds/ib.h index 6422c52682e56..9fc95e38659a4 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -313,6 +313,8 @@ void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents, void rds_ib_sync_mr(void *trans_private, int dir); void rds_ib_free_mr(void *trans_private, int invalidate); void rds_ib_flush_mrs(void); +int rds_ib_fmr_init(void); +void rds_ib_fmr_exit(void); /* ib_recv.c */ int rds_ib_recv_init(void); diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index a275b7d205ef4..2ac78c9879ea2 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -83,6 +83,25 @@ struct rds_ib_mr_pool { struct ib_fmr_attr fmr_attr; }; +struct workqueue_struct *rds_ib_fmr_wq; + +int rds_ib_fmr_init(void) +{ + rds_ib_fmr_wq = create_workqueue("rds_fmr_flushd"); + if (!rds_ib_fmr_wq) + return -ENOMEM; + return 0; +} + +/* By the time this is called all the IB devices should have been torn down and + * had their pools freed. As each pool is freed its work struct is waited on, + * so the pool flushing work queue should be idle by the time we get here. + */ +void rds_ib_fmr_exit(void) +{ + destroy_workqueue(rds_ib_fmr_wq); +} + static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all, struct rds_ib_mr **); static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr); static void rds_ib_mr_pool_flush_worker(struct work_struct *work); @@ -719,15 +738,17 @@ void rds_ib_free_mr(void *trans_private, int invalidate) /* If we've pinned too many pages, request a flush */ if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned || atomic_read(&pool->dirty_count) >= pool->max_items / 10) - schedule_delayed_work(&pool->flush_worker, 10); + queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10); if (invalidate) { if (likely(!in_interrupt())) { rds_ib_flush_mr_pool(pool, 0, NULL); } else { /* We get here if the user created a MR marked - * as use_once and invalidate at the same time. */ - schedule_delayed_work(&pool->flush_worker, 10); + * as use_once and invalidate at the same time. + */ + queue_delayed_work(rds_ib_fmr_wq, + &pool->flush_worker, 10); } } -- GitLab From ef5217a6e2e60bc3d0679f2652480b99730956fe Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Tue, 25 Aug 2015 12:02:02 -0700 Subject: [PATCH 4898/7006] RDS: flush the FMR pool less often FMR flush is an expensive and time consuming operation. Reduce the frequency of FMR pool flush by 50% so that more FMR work gets accumulated for more efficient flushing. Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index 2ac78c9879ea2..e596dfb76038f 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -737,7 +737,7 @@ void rds_ib_free_mr(void *trans_private, int invalidate) /* If we've pinned too many pages, request a flush */ if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned || - atomic_read(&pool->dirty_count) >= pool->max_items / 10) + atomic_read(&pool->dirty_count) >= pool->max_items / 5) queue_delayed_work(rds_ib_fmr_wq, &pool->flush_worker, 10); if (invalidate) { -- GitLab From 272412141908c40517cc89d5bb2eb074a2ec1474 Mon Sep 17 00:00:00 2001 From: "santosh.shilimkar@oracle.com" Date: Tue, 25 Aug 2015 12:02:03 -0700 Subject: [PATCH 4899/7006] RDS: remove superfluous from rds_ib_alloc_fmr() Memory allocated for 'ibmr' uses kzalloc_node() which already initialises the memory to zero. There is no need to do memset() 0 on that memory. Signed-off-by: Santosh Shilimkar Signed-off-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/ib_rdma.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c index e596dfb76038f..251d1ce0b7c7a 100644 --- a/net/rds/ib_rdma.c +++ b/net/rds/ib_rdma.c @@ -360,8 +360,6 @@ static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev) goto out_no_cigar; } - memset(ibmr, 0, sizeof(*ibmr)); - ibmr->fmr = ib_alloc_fmr(rds_ibdev->pd, (IB_ACCESS_LOCAL_WRITE | IB_ACCESS_REMOTE_READ | -- GitLab From 03772d2f00313bb22d91b2019cb8e6e91b415653 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Aug 2015 08:54:17 -0400 Subject: [PATCH 4900/7006] NFSv4.1/pnfs: Allow pNFS device drivers to customise layout segment insertion This is needed in order to allow merging of contiguous layout segments, and also to correct the ordering of layouts for those device drivers that don't necessarily want to place the read-write layouts first. Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 59 +++++++++++++++++++++++++++++++++++++++++++-------- fs/nfs/pnfs.h | 11 ++++++++++ 2 files changed, 61 insertions(+), 9 deletions(-) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 68cc4b1697697..914c1daf08dfe 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1188,16 +1188,41 @@ pnfs_lseg_range_cmp(const struct pnfs_layout_range *l1, return (int)(l1->iomode == IOMODE_READ) - (int)(l2->iomode == IOMODE_READ); } -static void -pnfs_layout_insert_lseg(struct pnfs_layout_hdr *lo, - struct pnfs_layout_segment *lseg) +static bool +pnfs_lseg_range_is_after(const struct pnfs_layout_range *l1, + const struct pnfs_layout_range *l2) +{ + return pnfs_lseg_range_cmp(l1, l2) > 0; +} + +static bool +pnfs_lseg_no_merge(struct pnfs_layout_segment *lseg, + struct pnfs_layout_segment *old) +{ + return false; +} + +void +pnfs_generic_layout_insert_lseg(struct pnfs_layout_hdr *lo, + struct pnfs_layout_segment *lseg, + bool (*is_after)(const struct pnfs_layout_range *, + const struct pnfs_layout_range *), + bool (*do_merge)(struct pnfs_layout_segment *, + struct pnfs_layout_segment *), + struct list_head *free_me) { - struct pnfs_layout_segment *lp; + struct pnfs_layout_segment *lp, *tmp; dprintk("%s:Begin\n", __func__); - list_for_each_entry(lp, &lo->plh_segs, pls_list) { - if (pnfs_lseg_range_cmp(&lseg->pls_range, &lp->pls_range) > 0) + list_for_each_entry_safe(lp, tmp, &lo->plh_segs, pls_list) { + if (test_bit(NFS_LSEG_VALID, &lp->pls_flags) == 0) + continue; + if (do_merge(lseg, lp)) { + mark_lseg_invalid(lp, free_me); + continue; + } + if (is_after(&lseg->pls_range, &lp->pls_range)) continue; list_add_tail(&lseg->pls_list, &lp->pls_list); dprintk("%s: inserted lseg %p " @@ -1219,6 +1244,24 @@ out: dprintk("%s:Return\n", __func__); } +EXPORT_SYMBOL_GPL(pnfs_generic_layout_insert_lseg); + +static void +pnfs_layout_insert_lseg(struct pnfs_layout_hdr *lo, + struct pnfs_layout_segment *lseg, + struct list_head *free_me) +{ + struct inode *inode = lo->plh_inode; + struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; + + if (ld->add_lseg != NULL) + ld->add_lseg(lo, lseg, free_me); + else + pnfs_generic_layout_insert_lseg(lo, lseg, + pnfs_lseg_range_is_after, + pnfs_lseg_no_merge, + free_me); +} static struct pnfs_layout_hdr * alloc_init_layout_hdr(struct inode *ino, @@ -1311,8 +1354,6 @@ pnfs_find_lseg(struct pnfs_layout_hdr *lo, ret = pnfs_get_lseg(lseg); break; } - if (lseg->pls_range.offset > range->offset) - break; } dprintk("%s:Return lseg %p ref %d\n", @@ -1637,7 +1678,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) clear_bit(NFS_LAYOUT_INVALID_STID, &lo->plh_flags); pnfs_get_lseg(lseg); - pnfs_layout_insert_lseg(lo, lseg); + pnfs_layout_insert_lseg(lo, lseg, &free_me); if (res->return_on_close) set_bit(NFS_LSEG_ROC, &lseg->pls_flags); diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 4df87ef3dccc4..869069d8b9962 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -128,6 +128,9 @@ struct pnfs_layoutdriver_type { struct pnfs_layout_segment * (*alloc_lseg) (struct pnfs_layout_hdr *layoutid, struct nfs4_layoutget_res *lgr, gfp_t gfp_flags); void (*free_lseg) (struct pnfs_layout_segment *lseg); + void (*add_lseg) (struct pnfs_layout_hdr *layoutid, + struct pnfs_layout_segment *lseg, + struct list_head *free_me); void (*return_range) (struct pnfs_layout_hdr *lo, struct pnfs_layout_range *range); @@ -285,6 +288,14 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, gfp_t gfp_flags); void pnfs_clear_layoutreturn_waitbit(struct pnfs_layout_hdr *lo); +void pnfs_generic_layout_insert_lseg(struct pnfs_layout_hdr *lo, + struct pnfs_layout_segment *lseg, + bool (*is_after)(const struct pnfs_layout_range *lseg_range, + const struct pnfs_layout_range *old), + bool (*do_merge)(struct pnfs_layout_segment *lseg, + struct pnfs_layout_segment *old), + struct list_head *free_me); + void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *); int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *); -- GitLab From 0762ed2ced40bfe648378ef0e1635cf4d3a6fb76 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 25 Aug 2015 17:38:25 -0400 Subject: [PATCH 4901/7006] NFSv4.1/flexfiles: Allow coalescing of new layout segments and existing ones In order to ensure atomicity of updates, we merge the old layout segments into the new ones, and then invalidate the old ones. Also ensure that we order the list of layout segments so that RO segments are preferred over RW. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 60 ++++++++++++++++++++++++++ fs/nfs/pnfs.h | 16 +++++++ 2 files changed, 76 insertions(+) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 7fefa8ad95785..4ec624cfcf8b3 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -265,6 +265,65 @@ static void _ff_layout_free_lseg(struct nfs4_ff_layout_segment *fls) } } +static bool +ff_lseg_range_is_after(const struct pnfs_layout_range *l1, + const struct pnfs_layout_range *l2) +{ + u64 end1, end2; + + if (l1->iomode != l2->iomode) + return l1->iomode != IOMODE_READ; + end1 = pnfs_calc_offset_end(l1->offset, l1->length); + end2 = pnfs_calc_offset_end(l2->offset, l2->length); + if (end1 < l2->offset) + return false; + if (end2 < l1->offset) + return true; + return l2->offset <= l1->offset; +} + +static bool +ff_lseg_merge(struct pnfs_layout_segment *new, + struct pnfs_layout_segment *old) +{ + u64 new_end, old_end; + + if (new->pls_range.iomode != old->pls_range.iomode) + return false; + old_end = pnfs_calc_offset_end(old->pls_range.offset, + old->pls_range.length); + if (old_end < new->pls_range.offset) + return false; + new_end = pnfs_calc_offset_end(new->pls_range.offset, + new->pls_range.length); + if (new_end < old->pls_range.offset) + return false; + + /* Mergeable: copy info from 'old' to 'new' */ + if (new_end < old_end) + new_end = old_end; + if (new->pls_range.offset < old->pls_range.offset) + new->pls_range.offset = old->pls_range.offset; + new->pls_range.length = pnfs_calc_offset_length(new->pls_range.offset, + new_end); + if (test_bit(NFS_LSEG_ROC, &old->pls_flags)) + set_bit(NFS_LSEG_ROC, &new->pls_flags); + if (test_bit(NFS_LSEG_LAYOUTRETURN, &old->pls_flags)) + set_bit(NFS_LSEG_LAYOUTRETURN, &new->pls_flags); + return true; +} + +static void +ff_layout_add_lseg(struct pnfs_layout_hdr *lo, + struct pnfs_layout_segment *lseg, + struct list_head *free_me) +{ + pnfs_generic_layout_insert_lseg(lo, lseg, + ff_lseg_range_is_after, + ff_lseg_merge, + free_me); +} + static void ff_layout_sort_mirrors(struct nfs4_ff_layout_segment *fls) { int i, j; @@ -2046,6 +2105,7 @@ static struct pnfs_layoutdriver_type flexfilelayout_type = { .free_layout_hdr = ff_layout_free_layout_hdr, .alloc_lseg = ff_layout_alloc_lseg, .free_lseg = ff_layout_free_lseg, + .add_lseg = ff_layout_add_lseg, .pg_read_ops = &ff_layout_pg_read_ops, .pg_write_ops = &ff_layout_pg_write_ops, .get_ds_info = ff_layout_get_ds_info, diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 869069d8b9962..78c9351ff117b 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h @@ -539,6 +539,22 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src, nfss->pnfs_curr_ld->id == src->l_type); } +static inline u64 +pnfs_calc_offset_end(u64 offset, u64 len) +{ + if (len == NFS4_MAX_UINT64 || len >= NFS4_MAX_UINT64 - offset) + return NFS4_MAX_UINT64; + return offset + len - 1; +} + +static inline u64 +pnfs_calc_offset_length(u64 offset, u64 end) +{ + if (end == NFS4_MAX_UINT64 || end <= offset) + return NFS4_MAX_UINT64; + return 1 + end - offset; +} + extern unsigned int layoutstats_timer; #ifdef NFS_DEBUG -- GitLab From 4f73b0654d8a954540d49bb0a300f31663423db9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Aug 2015 19:56:47 +0300 Subject: [PATCH 4902/7006] device property: fallback to pset when gettng one string The one string as an equivalent to an array of one element. Allow user to read one string as a plain string. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/base/property.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/base/property.c b/drivers/base/property.c index 37a7bb7b239d0..841b15c5c058e 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -462,7 +462,8 @@ int fwnode_property_read_string(struct fwnode_handle *fwnode, return acpi_dev_prop_read(to_acpi_node(fwnode), propname, DEV_PROP_STRING, val, 1); - return -ENXIO; + return pset_prop_read_array(to_pset(fwnode), propname, + DEV_PROP_STRING, val, 1); } EXPORT_SYMBOL_GPL(fwnode_property_read_string); -- GitLab From 7dc59dc938f034c69dcf9080d45b936882b7ffa3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Aug 2015 19:56:48 +0300 Subject: [PATCH 4903/7006] device property: attach 'else if' to the proper 'if' Obviously in the current place the 'else' keyword is redundant, though it seems quite correct when we check if nval is in allowed range. Reattach the condition branch there. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/property.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c index 7836e2e980f41..6d99450549c59 100644 --- a/drivers/acpi/property.c +++ b/drivers/acpi/property.c @@ -528,13 +528,14 @@ int acpi_dev_prop_read(struct acpi_device *adev, const char *propname, if (!val) return obj->package.count; - else if (nval <= 0) - return -EINVAL; if (nval > obj->package.count) return -EOVERFLOW; + else if (nval <= 0) + return -EINVAL; items = obj->package.elements; + switch (proptype) { case DEV_PROP_U8: ret = acpi_copy_property_array_u8(items, (u8 *)val, nval); -- GitLab From 4bf011815f2e093c7f60004f4f5683cf40b905b9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 10 Aug 2015 19:56:46 +0300 Subject: [PATCH 4904/7006] device property: check fwnode type in to_of_node() Potentially one of platform can support both ACPI and OF. In that case when we call to_of_node() for non-OF fwnode types we will get non-NULL result, which is wrong. Check for the type and return a correspondent result. Signed-off-by: Andy Shevchenko Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- include/linux/of.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/linux/of.h b/include/linux/of.h index edc068d19c792..2194b8ca41f92 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -136,7 +136,8 @@ static inline bool is_of_node(struct fwnode_handle *fwnode) static inline struct device_node *to_of_node(struct fwnode_handle *fwnode) { - return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL; + return is_of_node(fwnode) ? + container_of(fwnode, struct device_node, fwnode) : NULL; } static inline bool of_have_populated_dt(void) -- GitLab From 77760e94928f910b745ab8d00298a7c8b5786fb3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 25 Aug 2015 15:33:13 -0700 Subject: [PATCH 4905/7006] Documentation: networking: add a DSA document Describe how the DSA subsystem works, its design principles, limitations, and describe in details how to implement a DSA switch driver. Acked-by: Andrew Lunn Acked-by: Scott Feldman Reviewed-by: Vivien Didelot Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- Documentation/networking/dsa/dsa.txt | 615 +++++++++++++++++++++++++++ 1 file changed, 615 insertions(+) create mode 100644 Documentation/networking/dsa/dsa.txt diff --git a/Documentation/networking/dsa/dsa.txt b/Documentation/networking/dsa/dsa.txt new file mode 100644 index 0000000000000..aa9c1f9313cda --- /dev/null +++ b/Documentation/networking/dsa/dsa.txt @@ -0,0 +1,615 @@ +Distributed Switch Architecture +=============================== + +Introduction +============ + +This document describes the Distributed Switch Architecture (DSA) subsystem +design principles, limitations, interactions with other subsystems, and how to +develop drivers for this subsystem as well as a TODO for developers interested +in joining the effort. + +Design principles +================= + +The Distributed Switch Architecture is a subsystem which was primarily designed +to support Marvell Ethernet switches (MV88E6xxx, a.k.a Linkstreet product line) +using Linux, but has since evolved to support other vendors as well. + +The original philosophy behind this design was to be able to use unmodified +Linux tools such as bridge, iproute2, ifconfig to work transparently whether +they configured/queried a switch port network device or a regular network +device. + +An Ethernet switch is typically comprised of multiple front-panel ports, and one +or more CPU or management port. The DSA subsystem currently relies on the +presence of a management port connected to an Ethernet controller capable of +receiving Ethernet frames from the switch. This is a very common setup for all +kinds of Ethernet switches found in Small Home and Office products: routers, +gateways, or even top-of-the rack switches. This host Ethernet controller will +be later referred to as "master" and "cpu" in DSA terminology and code. + +The D in DSA stands for Distributed, because the subsystem has been designed +with the ability to configure and manage cascaded switches on top of each other +using upstream and downstream Ethernet links between switches. These specific +ports are referred to as "dsa" ports in DSA terminology and code. A collection +of multiple switches connected to each other is called a "switch tree". + +For each front-panel port, DSA will create specialized network devices which are +used as controlling and data-flowing endpoints for use by the Linux networking +stack. These specialized network interfaces are referred to as "slave" network +interfaces in DSA terminology and code. + +The ideal case for using DSA is when an Ethernet switch supports a "switch tag" +which is a hardware feature making the switch insert a specific tag for each +Ethernet frames it received to/from specific ports to help the management +interface figure out: + +- what port is this frame coming from +- what was the reason why this frame got forwarded +- how to send CPU originated traffic to specific ports + +The subsystem does support switches not capable of inserting/stripping tags, but +the features might be slightly limited in that case (traffic separation relies +on Port-based VLAN IDs). + +Note that DSA does not currently create network interfaces for the "cpu" and +"dsa" ports because: + +- the "cpu" port is the Ethernet switch facing side of the management + controller, and as such, would create a duplication of feature, since you + would get two interfaces for the same conduit: master netdev, and "cpu" netdev + +- the "dsa" port(s) are just conduits between two or more switches, and as such + cannot really be used as proper network interfaces either, only the + downstream, or the top-most upstream interface makes sense with that model + +Switch tagging protocols +------------------------ + +DSA currently supports 4 different tagging protocols, and a tag-less mode as +well. The different protocols are implemented in: + +net/dsa/tag_trailer.c: Marvell's 4 trailer tag mode (legacy) +net/dsa/tag_dsa.c: Marvell's original DSA tag +net/dsa/tag_edsa.c: Marvell's enhanced DSA tag +net/dsa/tag_brcm.c: Broadcom's 4 bytes tag + +The exact format of the tag protocol is vendor specific, but in general, they +all contain something which: + +- identifies which port the Ethernet frame came from/should be sent to +- provides a reason why this frame was forwarded to the management interface + +Master network devices +---------------------- + +Master network devices are regular, unmodified Linux network device drivers for +the CPU/management Ethernet interface. Such a driver might occasionally need to +know whether DSA is enabled (e.g.: to enable/disable specific offload features), +but the DSA subsystem has been proven to work with industry standard drivers: +e1000e, mv643xx_eth etc. without having to introduce modifications to these +drivers. Such network devices are also often referred to as conduit network +devices since they act as a pipe between the host processor and the hardware +Ethernet switch. + +Networking stack hooks +---------------------- + +When a master netdev is used with DSA, a small hook is placed in in the +networking stack is in order to have the DSA subsystem process the Ethernet +switch specific tagging protocol. DSA accomplishes this by registering a +specific (and fake) Ethernet type (later becoming skb->protocol) with the +networking stack, this is also known as a ptype or packet_type. A typical +Ethernet Frame receive sequence looks like this: + +Master network device (e.g.: e1000e): + +Receive interrupt fires: +- receive function is invoked +- basic packet processing is done: getting length, status etc. +- packet is prepared to be processed by the Ethernet layer by calling + eth_type_trans + +net/ethernet/eth.c: + +eth_type_trans(skb, dev) + if (dev->dsa_ptr != NULL) + -> skb->protocol = ETH_P_XDSA + +drivers/net/ethernet/*: + +netif_receive_skb(skb) + -> iterate over registered packet_type + -> invoke handler for ETH_P_XDSA, calls dsa_switch_rcv() + +net/dsa/dsa.c: + -> dsa_switch_rcv() + -> invoke switch tag specific protocol handler in + net/dsa/tag_*.c + +net/dsa/tag_*.c: + -> inspect and strip switch tag protocol to determine originating port + -> locate per-port network device + -> invoke eth_type_trans() with the DSA slave network device + -> invoked netif_receive_skb() + +Past this point, the DSA slave network devices get delivered regular Ethernet +frames that can be processed by the networking stack. + +Slave network devices +--------------------- + +Slave network devices created by DSA are stacked on top of their master network +device, each of these network interfaces will be responsible for being a +controlling and data-flowing end-point for each front-panel port of the switch. +These interfaces are specialized in order to: + +- insert/remove the switch tag protocol (if it exists) when sending traffic + to/from specific switch ports +- query the switch for ethtool operations: statistics, link state, + Wake-on-LAN, register dumps... +- external/internal PHY management: link, auto-negotiation etc. + +These slave network devices have custom net_device_ops and ethtool_ops function +pointers which allow DSA to introduce a level of layering between the networking +stack/ethtool, and the switch driver implementation. + +Upon frame transmission from these slave network devices, DSA will look up which +switch tagging protocol is currently registered with these network devices, and +invoke a specific transmit routine which takes care of adding the relevant +switch tag in the Ethernet frames. + +These frames are then queued for transmission using the master network device +ndo_start_xmit() function, since they contain the appropriate switch tag, the +Ethernet switch will be able to process these incoming frames from the +management interface and delivers these frames to the physical switch port. + +Graphical representation +------------------------ + +Summarized, this is basically how DSA looks like from a network device +perspective: + + + |--------------------------- + | CPU network device (eth0)| + ---------------------------- + | | + |--------------------------------------------| + | Switch driver | + |--------------------------------------------| + || || || + |-------| |-------| |-------| + | sw0p0 | | sw0p1 | | sw0p2 | + |-------| |-------| |-------| + +Slave MDIO bus +-------------- + +In order to be able to read to/from a switch PHY built into it, DSA creates a +slave MDIO bus which allows a specific switch driver to divert and intercept +MDIO reads/writes towards specific PHY addresses. In most MDIO-connected +switches, these functions would utilize direct or indirect PHY addressing mode +to return standard MII registers from the switch builtin PHYs, allowing the PHY +library and/or to return link status, link partner pages, auto-negotiation +results etc.. + +For Ethernet switches which have both external and internal MDIO busses, the +slave MII bus can be utilized to mux/demux MDIO reads and writes towards either +internal or external MDIO devices this switch might be connected to: internal +PHYs, external PHYs, or even external switches. + +Data structures +--------------- + +DSA data structures are defined in include/net/dsa.h as well as +net/dsa/dsa_priv.h. + +dsa_chip_data: platform data configuration for a given switch device, this +structure describes a switch device's parent device, its address, as well as +various properties of its ports: names/labels, and finally a routing table +indication (when cascading switches) + +dsa_platform_data: platform device configuration data which can reference a +collection of dsa_chip_data structure if multiples switches are cascaded, the +master network device this switch tree is attached to needs to be referenced + +dsa_switch_tree: structure assigned to the master network device under +"dsa_ptr", this structure references a dsa_platform_data structure as well as +the tagging protocol supported by the switch tree, and which receive/transmit +function hooks should be invoked, information about the directly attached switch +is also provided: CPU port. Finally, a collection of dsa_switch are referenced +to address individual switches in the tree. + +dsa_switch: structure describing a switch device in the tree, referencing a +dsa_switch_tree as a backpointer, slave network devices, master network device, +and a reference to the backing dsa_switch_driver + +dsa_switch_driver: structure referencing function pointers, see below for a full +description. + +Design limitations +================== + +DSA is a platform device driver +------------------------------- + +DSA is implemented as a DSA platform device driver which is convenient because +it will register the entire DSA switch tree attached to a master network device +in one-shot, facilitating the device creation and simplifying the device driver +model a bit, this comes however with a number of limitations: + +- building DSA and its switch drivers as modules is currently not working +- the device driver parenting does not necessarily reflect the original + bus/device the switch can be created from +- supporting non-MDIO and non-MMIO (platform) switches is not possible + +Limits on the number of devices and ports +----------------------------------------- + +DSA currently limits the number of maximum switches within a tree to 4 +(DSA_MAX_SWITCHES), and the number of ports per switch to 12 (DSA_MAX_PORTS). +These limits could be extended to support larger configurations would this need +arise. + +Lack of CPU/DSA network devices +------------------------------- + +DSA does not currently create slave network devices for the CPU or DSA ports, as +described before. This might be an issue in the following cases: + +- inability to fetch switch CPU port statistics counters using ethtool, which + can make it harder to debug MDIO switch connected using xMII interfaces + +- inability to configure the CPU port link parameters based on the Ethernet + controller capabilities attached to it: http://patchwork.ozlabs.org/patch/509806/ + +- inability to configure specific VLAN IDs / trunking VLANs between switches + when using a cascaded setup + +Common pitfalls using DSA setups +-------------------------------- + +Once a master network device is configured to use DSA (dev->dsa_ptr becomes +non-NULL), and the switch behind it expects a tagging protocol, this network +interface can only exclusively be used as a conduit interface. Sending packets +directly through this interface (e.g.: opening a socket using this interface) +will not make us go through the switch tagging protocol transmit function, so +the Ethernet switch on the other end, expecting a tag will typically drop this +frame. + +Slave network devices check that the master network device is UP before allowing +you to administratively bring UP these slave network devices. A common +configuration mistake is forgetting to bring UP the master network device first. + +Interactions with other subsystems +================================== + +DSA currently leverages the following subsystems: + +- MDIO/PHY library: drivers/net/phy/phy.c, mdio_bus.c +- Switchdev: net/switchdev/* +- Device Tree for various of_* functions +- HWMON: drivers/hwmon/* + +MDIO/PHY library +---------------- + +Slave network devices exposed by DSA may or may not be interfacing with PHY +devices (struct phy_device as defined in include/linux/phy.h), but the DSA +subsystem deals with all possible combinations: + +- internal PHY devices, built into the Ethernet switch hardware +- external PHY devices, connected via an internal or external MDIO bus +- internal PHY devices, connected via an internal MDIO bus +- special, non-autonegotiated or non MDIO-managed PHY devices: SFPs, MoCA; a.k.a + fixed PHYs + +The PHY configuration is done by the dsa_slave_phy_setup() function and the +logic basically looks like this: + +- if Device Tree is used, the PHY device is looked up using the standard + "phy-handle" property, if found, this PHY device is created and registered + using of_phy_connect() + +- if Device Tree is used, and the PHY device is "fixed", that is, conforms to + the definition of a non-MDIO managed PHY as defined in + Documentation/devicetree/bindings/net/fixed-link.txt, the PHY is registered + and connected transparently using the special fixed MDIO bus driver + +- finally, if the PHY is built into the switch, as is very common with + standalone switch packages, the PHY is probed using the slave MII bus created + by DSA + + +SWITCHDEV +--------- + +DSA directly utilizes SWITCHDEV when interfacing with the bridge layer, and +more specifically with its VLAN filtering portion when configuring VLANs on top +of per-port slave network devices. Since DSA primarily deals with +MDIO-connected switches, although not exclusively, SWITCHDEV's +prepare/abort/commit phases are often simplified into a prepare phase which +checks whether the operation is supporte by the DSA switch driver, and a commit +phase which applies the changes. + +As of today, the only SWITCHDEV objects supported by DSA are the FDB and VLAN +objects. + +Device Tree +----------- + +DSA features a standardized binding which is documented in +Documentation/devicetree/bindings/net/dsa/dsa.txt. PHY/MDIO library helper +functions such as of_get_phy_mode(), of_phy_connect() are also used to query +per-port PHY specific details: interface connection, MDIO bus location etc.. + +HWMON +----- + +Some switch drivers feature internal temperature sensors which are exposed as +regular HWMON devices in /sys/class/hwmon/. + +Driver development +================== + +DSA switch drivers need to implement a dsa_switch_driver structure which will +contain the various members described below. + +register_switch_driver() registers this dsa_switch_driver in its internal list +of drivers to probe for. unregister_switch_driver() does the exact opposite. + +Unless requested differently by setting the priv_size member accordingly, DSA +does not allocate any driver private context space. + +Switch configuration +-------------------- + +- priv_size: additional size needed by the switch driver for its private context + +- tag_protocol: this is to indicate what kind of tagging protocol is supported, + should be a valid value from the dsa_tag_protocol enum + +- probe: probe routine which will be invoked by the DSA platform device upon + registration to test for the presence/absence of a switch device. For MDIO + devices, it is recommended to issue a read towards internal registers using + the switch pseudo-PHY and return whether this is a supported device. For other + buses, return a non-NULL string + +- setup: setup function for the switch, this function is responsible for setting + up the dsa_switch_driver private structure with all it needs: register maps, + interrupts, mutexes, locks etc.. This function is also expected to properly + configure the switch to separate all network interfaces from each other, that + is, they should be isolated by the switch hardware itself, typically by creating + a Port-based VLAN ID for each port and allowing only the CPU port and the + specific port to be in the forwarding vector. Ports that are unused by the + platform should be disabled. Past this function, the switch is expected to be + fully configured and ready to serve any kind of request. It is recommended + to issue a software reset of the switch during this setup function in order to + avoid relying on what a previous software agent such as a bootloader/firmware + may have previously configured. + +- set_addr: Some switches require the programming of the management interface's + Ethernet MAC address, switch drivers can also disable ageing of MAC addresses + on the management interface and "hardcode"/"force" this MAC address for the + CPU/management interface as an optimization + +PHY devices and link management +------------------------------- + +- get_phy_flags: Some switches are interfaced to various kinds of Ethernet PHYs, + if the PHY library PHY driver needs to know about information it cannot obtain + on its own (e.g.: coming from switch memory mapped registers), this function + should return a 32-bits bitmask of "flags", that is private between the switch + driver and the Ethernet PHY driver in drivers/net/phy/*. + +- phy_read: Function invoked by the DSA slave MDIO bus when attempting to read + the switch port MDIO registers. If unavailable, return 0xffff for each read. + For builtin switch Ethernet PHYs, this function should allow reading the link + status, auto-negotiation results, link partner pages etc.. + +- phy_write: Function invoked by the DSA slave MDIO bus when attempting to write + to the switch port MDIO registers. If unavailable return a negative error + code. + +- poll_link: Function invoked by DSA to query the link state of the switch + builtin Ethernet PHYs, per port. This function is responsible for calling + netif_carrier_{on,off} when appropriate, and can be used to poll all ports in a + single call. Executes from workqueue context. + +- adjust_link: Function invoked by the PHY library when a slave network device + is attached to a PHY device. This function is responsible for appropriately + configuring the switch port link parameters: speed, duplex, pause based on + what the phy_device is providing. + +- fixed_link_update: Function invoked by the PHY library, and specifically by + the fixed PHY driver asking the switch driver for link parameters that could + not be auto-negotiated, or obtained by reading the PHY registers through MDIO. + This is particularly useful for specific kinds of hardware such as QSGMII, + MoCA or other kinds of non-MDIO managed PHYs where out of band link + information is obtained + +Ethtool operations +------------------ + +- get_strings: ethtool function used to query the driver's strings, will + typically return statistics strings, private flags strings etc. + +- get_ethtool_stats: ethtool function used to query per-port statistics and + return their values. DSA overlays slave network devices general statistics: + RX/TX counters from the network device, with switch driver specific statistics + per port + +- get_sset_count: ethtool function used to query the number of statistics items + +- get_wol: ethtool function used to obtain Wake-on-LAN settings per-port, this + function may, for certain implementations also query the master network device + Wake-on-LAN settings if this interface needs to participate in Wake-on-LAN + +- set_wol: ethtool function used to configure Wake-on-LAN settings per-port, + direct counterpart to set_wol with similar restrictions + +- set_eee: ethtool function which is used to configure a switch port EEE (Green + Ethernet) settings, can optionally invoke the PHY library to enable EEE at the + PHY level if relevant. This function should enable EEE at the switch port MAC + controller and data-processing logic + +- get_eee: ethtool function which is used to query a switch port EEE settings, + this function should return the EEE state of the switch port MAC controller + and data-processing logic as well as query the PHY for its currently configured + EEE settings + +- get_eeprom_len: ethtool function returning for a given switch the EEPROM + length/size in bytes + +- get_eeprom: ethtool function returning for a given switch the EEPROM contents + +- set_eeprom: ethtool function writing specified data to a given switch EEPROM + +- get_regs_len: ethtool function returning the register length for a given + switch + +- get_regs: ethtool function returning the Ethernet switch internal register + contents. This function might require user-land code in ethtool to + pretty-print register values and registers + +Power management +---------------- + +- suspend: function invoked by the DSA platform device when the system goes to + suspend, should quiesce all Ethernet switch activities, but keep ports + participating in Wake-on-LAN active as well as additional wake-up logic if + supported + +- resume: function invoked by the DSA platform device when the system resumes, + should resume all Ethernet switch activities and re-configure the switch to be + in a fully active state + +- port_enable: function invoked by the DSA slave network device ndo_open + function when a port is administratively brought up, this function should be + fully enabling a given switch port. DSA takes care of marking the port with + BR_STATE_BLOCKING if the port is a bridge member, or BR_STATE_FORWARDING if it + was not, and propagating these changes down to the hardware + +- port_disable: function invoked by the DSA slave network device ndo_close + function when a port is administratively brought down, this function should be + fully disabling a given switch port. DSA takes care of marking the port with + BR_STATE_DISABLED and propagating changes to the hardware if this port is + disabled while being a bridge member + +Hardware monitoring +------------------- + +These callbacks are only available if CONFIG_NET_DSA_HWMON is enabled: + +- get_temp: this function queries the given switch for its temperature + +- get_temp_limit: this function returns the switch current maximum temperature + limit + +- set_temp_limit: this function configures the maximum temperature limit allowed + +- get_temp_alarm: this function returns the critical temperature threshold + returning an alarm notification + +See Documentation/hwmon/sysfs-interface for details. + +Bridge layer +------------ + +- port_join_bridge: bridge layer function invoked when a given switch port is + added to a bridge, this function should be doing the necessary at the switch + level to permit the joining port from being added to the relevant logical + domain for it to ingress/egress traffic with other members of the bridge. DSA + does nothing but calculate a bitmask of switch ports currently members of the + specified bridge being requested the join + +- port_leave_bridge: bridge layer function invoked when a given switch port is + removed from a bridge, this function should be doing the necessary at the + switch level to deny the leaving port from ingress/egress traffic from the + remaining bridge members. When the port leaves the bridge, it should be aged + out at the switch hardware for the switch to (re) learn MAC addresses behind + this port. DSA calculates the bitmask of ports still members of the bridge + being left + +- port_stp_update: bridge layer function invoked when a given switch port STP + state is computed by the bridge layer and should be propagated to switch + hardware to forward/block/learn traffic. The switch driver is responsible for + computing a STP state change based on current and asked parameters and perform + the relevant ageing based on the intersection results + +Bridge VLAN filtering +--------------------- + +- port_pvid_get: bridge layer function invoked when a Port-based VLAN ID is + queried for the given switch port + +- port_pvid_set: bridge layer function invoked when a Port-based VLAN ID needs + to be configured on the given switch port + +- port_vlan_add: bridge layer function invoked when a VLAN is configured + (tagged or untagged) for the given switch port + +- port_vlan_del: bridge layer function invoked when a VLAN is removed from the + given switch port + +- vlan_getnext: bridge layer function invoked to query the next configured VLAN + in the switch, i.e. returns the bitmaps of members and untagged ports + +- port_fdb_add: bridge layer function invoked when the bridge wants to install a + Forwarding Database entry, the switch hardware should be programmed with the + specified address in the specified VLAN Id in the forwarding database + associated with this VLAN ID + +Note: VLAN ID 0 corresponds to the port private database, which, in the context +of DSA, would be the its port-based VLAN, used by the associated bridge device. + +- port_fdb_del: bridge layer function invoked when the bridge wants to remove a + Forwarding Database entry, the switch hardware should be programmed to delete + the specified MAC address from the specified VLAN ID if it was mapped into + this port forwarding database + +TODO +==== + +The platform device problem +--------------------------- +DSA is currently implemented as a platform device driver which is far from ideal +as was discussed in this thread: + +http://permalink.gmane.org/gmane.linux.network/329848 + +This basically prevents the device driver model to be properly used and applied, +and support non-MDIO, non-MMIO Ethernet connected switches. + +Another problem with the platform device driver approach is that it prevents the +use of a modular switch drivers build due to a circular dependency, illustrated +here: + +http://comments.gmane.org/gmane.linux.network/345803 + +Attempts of reworking this has been done here: + +https://lwn.net/Articles/643149/ + +Making SWITCHDEV and DSA converge towards an unified codebase +------------------------------------------------------------- + +SWITCHDEV properly takes care of abstracting the networking stack with offload +capable hardware, but does not enforce a strict switch device driver model. On +the other DSA enforces a fairly strict device driver model, and deals with most +of the switch specific. At some point we should envision a merger between these +two subsystems and get the best of both worlds. + +Other hanging fruits +-------------------- + +- making the number of ports fully dynamic and not dependent on DSA_MAX_PORTS +- allowing more than one CPU/management interface: + http://comments.gmane.org/gmane.linux.network/365657 +- porting more drivers from other vendors: + http://comments.gmane.org/gmane.linux.network/365510 -- GitLab From ef6346386b096549972d5b62f773eafb772682e3 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 25 Aug 2015 15:33:14 -0700 Subject: [PATCH 4906/7006] Documentation: networking: dsa: Add Broadcom SF2 document Add a document describing the Broadcom Starfigther 2 switch hardware, its specifics, and how the driver is implemented and its specifics. Signed-off-by: Florian Fainelli Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- Documentation/networking/dsa/bcm_sf2.txt | 114 +++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 Documentation/networking/dsa/bcm_sf2.txt diff --git a/Documentation/networking/dsa/bcm_sf2.txt b/Documentation/networking/dsa/bcm_sf2.txt new file mode 100644 index 0000000000000..d999d0c1c5b83 --- /dev/null +++ b/Documentation/networking/dsa/bcm_sf2.txt @@ -0,0 +1,114 @@ +Broadcom Starfighter 2 Ethernet switch driver +============================================= + +Broadcom's Starfighter 2 Ethernet switch hardware block is commonly found and +deployed in the following products: + +- xDSL gateways such as BCM63138 +- streaming/multimedia Set Top Box such as BCM7445 +- Cable Modem/residential gateways such as BCM7145/BCM3390 + +The switch is typically deployed in a configuration involving between 5 to 13 +ports, offering a range of built-in and customizable interfaces: + +- single integrated Gigabit PHY +- quad integrated Gigabit PHY +- quad external Gigabit PHY w/ MDIO multiplexer +- integrated MoCA PHY +- several external MII/RevMII/GMII/RGMII interfaces + +The switch also supports specific congestion control features which allow MoCA +fail-over not to lose packets during a MoCA role re-election, as well as out of +band back-pressure to the host CPU network interface when downstream interfaces +are connected at a lower speed. + +The switch hardware block is typically interfaced using MMIO accesses and +contains a bunch of sub-blocks/registers: + +* SWITCH_CORE: common switch registers +* SWITCH_REG: external interfaces switch register +* SWITCH_MDIO: external MDIO bus controller (there is another one in SWITCH_CORE, + which is used for indirect PHY accesses) +* SWITCH_INDIR_RW: 64-bits wide register helper block +* SWITCH_INTRL2_0/1: Level-2 interrupt controllers +* SWITCH_ACB: Admission control block +* SWITCH_FCB: Fail-over control block + +Implementation details +====================== + +The driver is located in drivers/net/dsa/bcm_sf2.c and is implemented as a DSA +driver; see Documentation/networking/dsa/dsa.txt for details on the subsytem +and what it provides. + +The SF2 switch is configured to enable a Broadcom specific 4-bytes switch tag +which gets inserted by the switch for every packet forwarded to the CPU +interface, conversely, the CPU network interface should insert a similar tag for +packets entering the CPU port. The tag format is described in +net/dsa/tag_brcm.c. + +Overall, the SF2 driver is a fairly regular DSA driver; there are a few +specifics covered below. + +Device Tree probing +------------------- + +The DSA platform device driver is probed using a specific compatible string +provided in net/dsa/dsa.c. The reason for that is because the DSA subsystem gets +registered as a platform device driver currently. DSA will provide the needed +device_node pointers which are then accessible by the switch driver setup +function to setup resources such as register ranges and interrupts. This +currently works very well because none of the of_* functions utilized by the +driver require a struct device to be bound to a struct device_node, but things +may change in the future. + +MDIO indirect accesses +---------------------- + +Due to a limitation in how Broadcom switches have been designed, external +Broadcom switches connected to a SF2 require the use of the DSA slave MDIO bus +in order to properly configure them. By default, the SF2 pseudo-PHY address, and +an external switch pseudo-PHY address will both be snooping for incoming MDIO +transactions, since they are at the same address (30), resulting in some kind of +"double" programming. Using DSA, and setting ds->phys_mii_mask accordingly, we +selectively divert reads and writes towards external Broadcom switches +pseudo-PHY addresses. Newer revisions of the SF2 hardware have introduced a +configurable pseudo-PHY address which circumvents the initial design limitation. + +Multimedia over CoAxial (MoCA) interfaces +----------------------------------------- + +MoCA interfaces are fairly specific and require the use of a firmware blob which +gets loaded onto the MoCA processor(s) for packet processing. The switch +hardware contains logic which will assert/de-assert link states accordingly for +the MoCA interface whenever the MoCA coaxial cable gets disconnected or the +firmware gets reloaded. The SF2 driver relies on such events to properly set its +MoCA interface carrier state and properly report this to the networking stack. + +The MoCA interfaces are supported using the PHY library's fixed PHY/emulated PHY +device and the switch driver registers a fixed_link_update callback for such +PHYs which reflects the link state obtained from the interrupt handler. + + +Power Management +---------------- + +Whenever possible, the SF2 driver tries to minimize the overall switch power +consumption by applying a combination of: + +- turning off internal buffers/memories +- disabling packet processing logic +- putting integrated PHYs in IDDQ/low-power +- reducing the switch core clock based on the active port count +- enabling and advertising EEE +- turning off RGMII data processing logic when the link goes down + +Wake-on-LAN +----------- + +Wake-on-LAN is currently implemented by utilizing the host processor Ethernet +MAC controller wake-on logic. Whenever Wake-on-LAN is requested, an intersection +between the user request and the supported host Ethernet interface WoL +capabilities is done and the intersection result gets configured. During +system-wide suspend/resume, only ports not participating in Wake-on-LAN are +disabled. -- GitLab From 19cf6335134d82be792831e14aae9d037d0cb30b Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Wed, 26 Aug 2015 00:13:15 +0800 Subject: [PATCH 4907/7006] nfs42: decode_layoutstats does not need res parameter Reviewed-by: Christoph Hellwig Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/nfs42xdr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c index a6bd27da6286f..0eb29e14070d5 100644 --- a/fs/nfs/nfs42xdr.c +++ b/fs/nfs/nfs42xdr.c @@ -238,8 +238,7 @@ out_overflow: return -EIO; } -static int decode_layoutstats(struct xdr_stream *xdr, - struct nfs42_layoutstat_res *res) +static int decode_layoutstats(struct xdr_stream *xdr) { return decode_op_hdr(xdr, OP_LAYOUTSTATS); } @@ -343,7 +342,7 @@ static int nfs4_xdr_dec_layoutstats(struct rpc_rqst *rqstp, goto out; WARN_ON(res->num_dev > PNFS_LAYOUTSTATS_MAXDEV); for (i = 0; i < res->num_dev; i++) { - status = decode_layoutstats(xdr, res); + status = decode_layoutstats(xdr); if (status) goto out; } -- GitLab From 1090c3bf81ef12eb22383d4b6627d372ce5115d9 Mon Sep 17 00:00:00 2001 From: Peng Tao Date: Wed, 26 Aug 2015 00:13:16 +0800 Subject: [PATCH 4908/7006] nfs42: remove unused declaration Reviewed-by: Christoph Hellwig Signed-off-by: Peng Tao Signed-off-by: Trond Myklebust --- fs/nfs/nfs42.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h index ff66ae700b899..814c1255f1d2c 100644 --- a/fs/nfs/nfs42.h +++ b/fs/nfs/nfs42.h @@ -17,7 +17,5 @@ int nfs42_proc_deallocate(struct file *, loff_t, loff_t); loff_t nfs42_proc_llseek(struct file *, loff_t, int); int nfs42_proc_layoutstats_generic(struct nfs_server *, struct nfs42_layoutstat_data *); -/* nfs4.2xdr.h */ -extern struct rpc_procinfo nfs4_2_procedures[]; #endif /* __LINUX_FS_NFS_NFS4_2_H */ -- GitLab From b6fc6072b1268a0025850cd9d3dce25a7be0158d Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Wed, 5 Aug 2015 09:40:31 -0400 Subject: [PATCH 4909/7006] PCC: Disable compilation by default PCC is made selectable only by clients which use it. e.g. CPPC Default it to disabled so that it is not included accidentally on platforms which dont use it. Signed-off-by: Ashwin Chaugule Reviewed-by: Al Stone Signed-off-by: Rafael J. Wysocki --- drivers/mailbox/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index e269f084497dc..bbec5009cdc2b 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -46,6 +46,7 @@ config OMAP_MBOX_KFIFO_SIZE config PCC bool "Platform Communication Channel Driver" depends on ACPI + default n help ACPI 5.0+ spec defines a generic mode of communication between the OS and a platform such as the BMC. This medium -- GitLab From eeb72a8de8e5471cdce71ea7b2f908e851a73909 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 24 Aug 2015 13:43:14 +0530 Subject: [PATCH 4910/7006] dmaengine: sort the sh Kconfig Acked-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/sh/Kconfig | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig index 0f371524a4d96..9fda65af841eb 100644 --- a/drivers/dma/sh/Kconfig +++ b/drivers/dma/sh/Kconfig @@ -39,18 +39,6 @@ config SH_DMAE_R8A73A4 endif -config SUDMAC - tristate "Renesas SUDMAC support" - depends on SH_DMAE_BASE - help - Enable support for the Renesas SUDMAC controllers. - -config RCAR_HPB_DMAE - tristate "Renesas R-Car HPB DMAC support" - depends on SH_DMAE_BASE - help - Enable support for the Renesas R-Car series DMA controllers. - config RCAR_DMAC tristate "Renesas R-Car Gen2 DMA Controller" depends on ARCH_SHMOBILE || COMPILE_TEST @@ -59,6 +47,12 @@ config RCAR_DMAC This driver supports the general purpose DMA controller found in the Renesas R-Car second generation SoCs. +config RCAR_HPB_DMAE + tristate "Renesas R-Car HPB DMAC support" + depends on SH_DMAE_BASE + help + Enable support for the Renesas R-Car series DMA controllers. + config RENESAS_USB_DMAC tristate "Renesas USB-DMA Controller" depends on ARCH_SHMOBILE || COMPILE_TEST @@ -67,3 +61,9 @@ config RENESAS_USB_DMAC help This driver supports the USB-DMA controller found in the Renesas SoCs. + +config SUDMAC + tristate "Renesas SUDMAC support" + depends on SH_DMAE_BASE + help + Enable support for the Renesas SUDMAC controllers. -- GitLab From 8a4ce226b9061fe3ab04f6db34d4b2ae645b9f65 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Mon, 24 Aug 2015 13:43:14 +0530 Subject: [PATCH 4911/7006] dmaengine: sort the sh Makefile Acked-by: Geert Uytterhoeven Signed-off-by: Vinod Koul --- drivers/dma/sh/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile index b8a598066ce28..0133e46581968 100644 --- a/drivers/dma/sh/Makefile +++ b/drivers/dma/sh/Makefile @@ -13,7 +13,7 @@ shdma-$(CONFIG_SH_DMAE_R8A73A4) += shdma-r8a73a4.o shdma-objs := $(shdma-y) obj-$(CONFIG_SH_DMAE) += shdma.o -obj-$(CONFIG_SUDMAC) += sudmac.o -obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o obj-$(CONFIG_RCAR_DMAC) += rcar-dmac.o +obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o obj-$(CONFIG_RENESAS_USB_DMAC) += usb-dmac.o +obj-$(CONFIG_SUDMAC) += sudmac.o -- GitLab From 4d112426c3446d94b9bc56396075524b06913b1c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Mon, 24 Aug 2015 11:21:15 +0200 Subject: [PATCH 4912/7006] dmaengine: hdmac: Add memset capabilities Just like for the XDMAC, the SoCs that embed the HDMAC don't have any kind of GPU, and need to accelerate a few framebuffer-related operations through their DMA controller. However, unlike the XDMAC, the HDMAC doesn't have the memset capability built-in. That can be easily emulated though, by doing a transfer with a fixed address on the variable that holds the value we want to set. Signed-off-by: Maxime Ripard Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 121 +++++++++++++++++++++++++++++++++++- drivers/dma/at_hdmac_regs.h | 6 ++ 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index d313acbb50e00..64db0e611cd1a 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -390,6 +390,7 @@ static void atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) { struct dma_async_tx_descriptor *txd = &desc->txd; + struct at_dma *atdma = to_at_dma(atchan->chan_common.device); dev_vdbg(chan2dev(&atchan->chan_common), "descriptor %u complete\n", txd->cookie); @@ -398,6 +399,13 @@ atc_chain_complete(struct at_dma_chan *atchan, struct at_desc *desc) if (!atc_chan_is_cyclic(atchan)) dma_cookie_complete(txd); + /* If the transfer was a memset, free our temporary buffer */ + if (desc->memset) { + dma_pool_free(atdma->memset_pool, desc->memset_vaddr, + desc->memset_paddr); + desc->memset = false; + } + /* move children to free_list */ list_splice_init(&desc->tx_list, &atchan->free_list); /* move myself to free_list */ @@ -820,6 +828,93 @@ err_desc_get: return NULL; } +/** + * atc_prep_dma_memset - prepare a memcpy operation + * @chan: the channel to prepare operation on + * @dest: operation virtual destination address + * @value: value to set memory buffer to + * @len: operation length + * @flags: tx descriptor status flags + */ +static struct dma_async_tx_descriptor * +atc_prep_dma_memset(struct dma_chan *chan, dma_addr_t dest, int value, + size_t len, unsigned long flags) +{ + struct at_dma_chan *atchan = to_at_dma_chan(chan); + struct at_dma *atdma = to_at_dma(chan->device); + struct at_desc *desc = NULL; + size_t xfer_count; + u32 ctrla; + u32 ctrlb; + + dev_vdbg(chan2dev(chan), "%s: d0x%x v0x%x l0x%zx f0x%lx\n", __func__, + dest, value, len, flags); + + if (unlikely(!len)) { + dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__); + return NULL; + } + + if (!is_dma_fill_aligned(chan->device, dest, 0, len)) { + dev_dbg(chan2dev(chan), "%s: buffer is not aligned\n", + __func__); + return NULL; + } + + xfer_count = len >> 2; + if (xfer_count > ATC_BTSIZE_MAX) { + dev_err(chan2dev(chan), "%s: buffer is too big\n", + __func__); + return NULL; + } + + ctrlb = ATC_DEFAULT_CTRLB | ATC_IEN + | ATC_SRC_ADDR_MODE_FIXED + | ATC_DST_ADDR_MODE_INCR + | ATC_FC_MEM2MEM; + + ctrla = ATC_SRC_WIDTH(2) | + ATC_DST_WIDTH(2); + + desc = atc_desc_get(atchan); + if (!desc) { + dev_err(chan2dev(chan), "%s: can't get a descriptor\n", + __func__); + return NULL; + } + + desc->memset_vaddr = dma_pool_alloc(atdma->memset_pool, GFP_ATOMIC, + &desc->memset_paddr); + if (!desc->memset_vaddr) { + dev_err(chan2dev(chan), "%s: couldn't allocate buffer\n", + __func__); + goto err_put_desc; + } + + *desc->memset_vaddr = value; + desc->memset = true; + + desc->lli.saddr = desc->memset_paddr; + desc->lli.daddr = dest; + desc->lli.ctrla = ctrla | xfer_count; + desc->lli.ctrlb = ctrlb; + + desc->txd.cookie = -EBUSY; + desc->len = len; + desc->total_len = len; + + /* set end-of-link on the descriptor */ + set_desc_eol(desc); + + desc->txd.flags = flags; + + return &desc->txd; + +err_put_desc: + atc_desc_put(atchan, desc); + return NULL; +} + /** * atc_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction @@ -1713,6 +1808,8 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_cap_set(DMA_SG, at91sam9rl_config.cap_mask); dma_cap_set(DMA_INTERLEAVE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_MEMCPY, at91sam9g45_config.cap_mask); + dma_cap_set(DMA_MEMSET, at91sam9g45_config.cap_mask); + dma_cap_set(DMA_PRIVATE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_SLAVE, at91sam9g45_config.cap_mask); dma_cap_set(DMA_SG, at91sam9g45_config.cap_mask); @@ -1776,7 +1873,16 @@ static int __init at_dma_probe(struct platform_device *pdev) if (!atdma->dma_desc_pool) { dev_err(&pdev->dev, "No memory for descriptors dma pool\n"); err = -ENOMEM; - goto err_pool_create; + goto err_desc_pool_create; + } + + /* create a pool of consistent memory blocks for memset blocks */ + atdma->memset_pool = dma_pool_create("at_hdmac_memset_pool", + &pdev->dev, sizeof(int), 4, 0); + if (!atdma->memset_pool) { + dev_err(&pdev->dev, "No memory for memset dma pool\n"); + err = -ENOMEM; + goto err_memset_pool_create; } /* clear any pending interrupt */ @@ -1822,6 +1928,11 @@ static int __init at_dma_probe(struct platform_device *pdev) if (dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask)) atdma->dma_common.device_prep_dma_memcpy = atc_prep_dma_memcpy; + if (dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask)) { + atdma->dma_common.device_prep_dma_memset = atc_prep_dma_memset; + atdma->dma_common.fill_align = DMAENGINE_ALIGN_4_BYTES; + } + if (dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask)) { atdma->dma_common.device_prep_slave_sg = atc_prep_slave_sg; /* controller can do slave DMA: can trigger cyclic transfers */ @@ -1842,8 +1953,9 @@ static int __init at_dma_probe(struct platform_device *pdev) dma_writel(atdma, EN, AT_DMA_ENABLE); - dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s%s), %d channels\n", + dev_info(&pdev->dev, "Atmel AHB DMA Controller ( %s%s%s%s), %d channels\n", dma_has_cap(DMA_MEMCPY, atdma->dma_common.cap_mask) ? "cpy " : "", + dma_has_cap(DMA_MEMSET, atdma->dma_common.cap_mask) ? "set " : "", dma_has_cap(DMA_SLAVE, atdma->dma_common.cap_mask) ? "slave " : "", dma_has_cap(DMA_SG, atdma->dma_common.cap_mask) ? "sg-cpy " : "", plat_dat->nr_channels); @@ -1868,8 +1980,10 @@ static int __init at_dma_probe(struct platform_device *pdev) err_of_dma_controller_register: dma_async_device_unregister(&atdma->dma_common); + dma_pool_destroy(atdma->memset_pool); +err_memset_pool_create: dma_pool_destroy(atdma->dma_desc_pool); -err_pool_create: +err_desc_pool_create: free_irq(platform_get_irq(pdev, 0), atdma); err_irq: clk_disable_unprepare(atdma->clk); @@ -1894,6 +2008,7 @@ static int at_dma_remove(struct platform_device *pdev) at_dma_off(atdma); dma_async_device_unregister(&atdma->dma_common); + dma_pool_destroy(atdma->memset_pool); dma_pool_destroy(atdma->dma_desc_pool); free_irq(platform_get_irq(pdev, 0), atdma); diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h index bc8d5ebedd192..a2283886dd87f 100644 --- a/drivers/dma/at_hdmac_regs.h +++ b/drivers/dma/at_hdmac_regs.h @@ -201,6 +201,11 @@ struct at_desc { size_t boundary; size_t dst_hole; size_t src_hole; + + /* Memset temporary buffer */ + bool memset; + dma_addr_t memset_paddr; + int *memset_vaddr; }; static inline struct at_desc * @@ -331,6 +336,7 @@ struct at_dma { u8 all_chan_mask; struct dma_pool *dma_desc_pool; + struct dma_pool *memset_pool; /* AT THE END channels table */ struct at_dma_chan chan[0]; }; -- GitLab From 5c65cb93a3d066f52a109552572304675d5a52fc Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 25 Aug 2015 12:58:05 -0700 Subject: [PATCH 4913/7006] dmaengine: ioatdma: fix sparse "error" with prep lock The prep lock gets acquired in ioat_check_space_lock and released in ioat_tx_submit_unlock. Setting the annotations so sparse does not freak out. drivers/dma/ioat/dma.c:273:30: sparse: context imbalance in 'ioat_tx_submit_unlock' - unexpected unlock drivers/dma/ioat/dma.c:476:5: sparse: context imbalance in 'ioat_check_space_lock' - wrong count at exit Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 50d0112b602a1..f66b7e6406105 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -262,6 +262,7 @@ static int ioat_reset_sync(struct ioatdma_chan *ioat_chan, unsigned long tmo) } static dma_cookie_t ioat_tx_submit_unlock(struct dma_async_tx_descriptor *tx) + __releases(&ioat_chan->prep_lock) { struct dma_chan *c = tx->chan; struct ioatdma_chan *ioat_chan = to_ioat_chan(c); @@ -474,6 +475,7 @@ static bool reshape_ring(struct ioatdma_chan *ioat_chan, int order) * @num_descs: allocation length */ int ioat_check_space_lock(struct ioatdma_chan *ioat_chan, int num_descs) + __acquires(&ioat_chan->prep_lock) { bool retry; -- GitLab From 7b7d0ca7778d359584859cb5e75965ad34f42533 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 25 Aug 2015 12:58:11 -0700 Subject: [PATCH 4914/7006] dmaengine: ioatdma: Fix variable array length Sparse reported: drivers/dma/ioat/prep.c:637:27: sparse: Variable length array is used. Assigning a static value for the array. Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/prep.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/dma/ioat/prep.c b/drivers/dma/ioat/prep.c index e323a40369084..ad4fb41cd23be 100644 --- a/drivers/dma/ioat/prep.c +++ b/drivers/dma/ioat/prep.c @@ -26,6 +26,8 @@ #include "hw.h" #include "dma.h" +#define MAX_SCF 1024 + /* provide a lookup table for setting the source address in the base or * extended descriptor of an xor or pq descriptor */ @@ -634,9 +636,12 @@ struct dma_async_tx_descriptor * ioat_prep_pqxor(struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src, unsigned int src_cnt, size_t len, unsigned long flags) { - unsigned char scf[src_cnt]; + unsigned char scf[MAX_SCF]; dma_addr_t pq[2]; + if (src_cnt > MAX_SCF) + return NULL; + memset(scf, 0, src_cnt); pq[0] = dst; flags |= DMA_PREP_PQ_DISABLE_Q; @@ -654,9 +659,12 @@ ioat_prep_pqxor_val(struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, size_t len, enum sum_check_flags *result, unsigned long flags) { - unsigned char scf[src_cnt]; + unsigned char scf[MAX_SCF]; dma_addr_t pq[2]; + if (src_cnt > MAX_SCF) + return NULL; + /* the cleanup routine only sets bits on validate failure, it * does not clear bits on validate success... so clear it here */ -- GitLab From a92d5ee8666afcb4abc7686d7b760f0fb7a0c14c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Aug 2015 07:22:49 +0200 Subject: [PATCH 4915/7006] ALSA: hda - Fix widget sysfs tree corruption after refresh When snd_hdac_refresh_widget_sysfs() is called before the first hda_widget_sysfs_init(), the next call overrides and eventually fails. This results in unexpected Oops, something like: BUG: unable to handle kernel NULL pointer dereference at 00000000000000c8 IP: [] hdmi_chmap_ctl_info+0x23/0x40 The fix is to add a check of the existing sysfs tree. Also, for more safety, this patch adds the checks of device_is_registered() in snd-hdac_refresh_wdiget_sysfs(), too. Fixes: fa4f18b4f402 ('ALSA: hda - Refresh widgets sysfs at probing Haswell+ HDMI codecs') Bugizlla: https://bugzilla.kernel.org/show_bug.cgi?id=103431 Reported-by: Andreas Reis Signed-off-by: Takashi Iwai --- sound/hda/hdac_device.c | 14 ++++++++------ sound/hda/hdac_sysfs.c | 3 +++ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/sound/hda/hdac_device.c b/sound/hda/hdac_device.c index aa6d6cec23804..db96042a497f0 100644 --- a/sound/hda/hdac_device.c +++ b/sound/hda/hdac_device.c @@ -384,18 +384,20 @@ int snd_hdac_refresh_widget_sysfs(struct hdac_device *codec) { int ret; - hda_widget_sysfs_exit(codec); + if (device_is_registered(&codec->dev)) + hda_widget_sysfs_exit(codec); ret = snd_hdac_refresh_widgets(codec); if (ret) { dev_err(&codec->dev, "failed to refresh widget: %d\n", ret); return ret; } - ret = hda_widget_sysfs_init(codec); - if (ret) { - dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); - return ret; + if (device_is_registered(&codec->dev)) { + ret = hda_widget_sysfs_init(codec); + if (ret) { + dev_err(&codec->dev, "failed to init sysfs: %d\n", ret); + return ret; + } } - return ret; } EXPORT_SYMBOL_GPL(snd_hdac_refresh_widget_sysfs); diff --git a/sound/hda/hdac_sysfs.c b/sound/hda/hdac_sysfs.c index 089b35f6f1086..c71142dea98a1 100644 --- a/sound/hda/hdac_sysfs.c +++ b/sound/hda/hdac_sysfs.c @@ -390,6 +390,9 @@ int hda_widget_sysfs_init(struct hdac_device *codec) { int err; + if (codec->widgets) + return 0; /* already created */ + err = widget_tree_create(codec); if (err < 0) { widget_tree_free(codec); -- GitLab From f1c79abef5bae62aefcadf16917905cb7f98dc19 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 26 Jun 2015 18:07:25 +0800 Subject: [PATCH 4916/7006] drm/rockchip: vop: Fix virtual stride calculation vir_stride need number words of the virtual width, and fb->pitches save bytes_per_pixel, so just div 4 switch to stride. Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 34b78e7365324..6b447318ef510 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -667,7 +667,7 @@ static int vop_update_plane_event(struct drm_plane *plane, offset += (src.y1 >> 16) * fb->pitches[0]; yrgb_mst = rk_obj->dma_addr + offset; - y_vir_stride = fb->pitches[0] / (fb->bits_per_pixel >> 3); + y_vir_stride = fb->pitches[0] >> 2; /* * If this plane update changes the plane's framebuffer, (or more -- GitLab From acf8c3e0a9eb5658e6ac4379cba51dba9b941083 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 20 Jul 2015 16:02:47 +0800 Subject: [PATCH 4917/7006] drm/rockchip: vop: Fix window dest start point Dest start point use crtc_x/y is wrong, crtc_x/y is not equal to dest.x1/y1 at plane scale. Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 6b447318ef510..da72de9eb3d51 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -657,11 +657,9 @@ static int vop_update_plane_event(struct drm_plane *plane, actual_w = (src.x2 - src.x1) >> 16; actual_h = (src.y2 - src.y1) >> 16; - crtc_x = max(0, crtc_x); - crtc_y = max(0, crtc_y); - dsp_stx = crtc_x + crtc->mode.htotal - crtc->mode.hsync_start; - dsp_sty = crtc_y + crtc->mode.vtotal - crtc->mode.vsync_start; + dsp_stx = dest.x1 + crtc->mode.htotal - crtc->mode.hsync_start; + dsp_sty = dest.y1 + crtc->mode.vtotal - crtc->mode.vsync_start; offset = (src.x1 >> 16) * (fb->bits_per_pixel >> 3); offset += (src.y1 >> 16) * fb->pitches[0]; -- GitLab From 84c7f8ca43000ee97e556bddbbc4543e2514239d Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 20 Jul 2015 16:16:49 +0800 Subject: [PATCH 4918/7006] drm/rockchip: vop: Add yuv plane support vop support yuv with NV12, NV16 and NV24, only 2 plane yuv. Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 56 ++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index da72de9eb3d51..c1264d58b03b3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -393,6 +393,18 @@ static enum vop_data_format vop_convert_format(uint32_t format) } } +static bool is_yuv_support(uint32_t format) +{ + switch (format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: + case DRM_FORMAT_NV24: + return true; + default: + return false; + } +} + static bool is_alpha_support(uint32_t format) { switch (format) { @@ -598,17 +610,22 @@ static int vop_update_plane_event(struct drm_plane *plane, struct vop *vop = to_vop(crtc); struct drm_gem_object *obj; struct rockchip_gem_object *rk_obj; + struct drm_gem_object *uv_obj; + struct rockchip_gem_object *rk_uv_obj; unsigned long offset; unsigned int actual_w; unsigned int actual_h; unsigned int dsp_stx; unsigned int dsp_sty; unsigned int y_vir_stride; + unsigned int uv_vir_stride = 0; dma_addr_t yrgb_mst; + dma_addr_t uv_mst = 0; enum vop_data_format format; uint32_t val; bool is_alpha; bool rb_swap; + bool is_yuv; bool visible; int ret; struct drm_rect dest = { @@ -643,6 +660,8 @@ static int vop_update_plane_event(struct drm_plane *plane, is_alpha = is_alpha_support(fb->pixel_format); rb_swap = has_rb_swapped(fb->pixel_format); + is_yuv = is_yuv_support(fb->pixel_format); + format = vop_convert_format(fb->pixel_format); if (format < 0) return format; @@ -655,18 +674,47 @@ static int vop_update_plane_event(struct drm_plane *plane, rk_obj = to_rockchip_obj(obj); + if (is_yuv) { + /* + * Src.x1 can be odd when do clip, but yuv plane start point + * need align with 2 pixel. + */ + val = (src.x1 >> 16) % 2; + src.x1 += val << 16; + src.x2 += val << 16; + } + actual_w = (src.x2 - src.x1) >> 16; actual_h = (src.y2 - src.y1) >> 16; dsp_stx = dest.x1 + crtc->mode.htotal - crtc->mode.hsync_start; dsp_sty = dest.y1 + crtc->mode.vtotal - crtc->mode.vsync_start; - offset = (src.x1 >> 16) * (fb->bits_per_pixel >> 3); + offset = (src.x1 >> 16) * drm_format_plane_cpp(fb->pixel_format, 0); offset += (src.y1 >> 16) * fb->pitches[0]; - yrgb_mst = rk_obj->dma_addr + offset; + yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; y_vir_stride = fb->pitches[0] >> 2; + if (is_yuv) { + int hsub = drm_format_horz_chroma_subsampling(fb->pixel_format); + int vsub = drm_format_vert_chroma_subsampling(fb->pixel_format); + int bpp = drm_format_plane_cpp(fb->pixel_format, 1); + + uv_obj = rockchip_fb_get_gem_obj(fb, 1); + if (!uv_obj) { + DRM_ERROR("fail to get uv object from framebuffer\n"); + return -EINVAL; + } + rk_uv_obj = to_rockchip_obj(uv_obj); + uv_vir_stride = fb->pitches[1] >> 2; + + offset = (src.x1 >> 16) * bpp / hsub; + offset += (src.y1 >> 16) * fb->pitches[1] / vsub; + + uv_mst = rk_uv_obj->dma_addr + offset + fb->offsets[1]; + } + /* * If this plane update changes the plane's framebuffer, (or more * precisely, if this update has a different framebuffer than the last @@ -702,6 +750,10 @@ static int vop_update_plane_event(struct drm_plane *plane, VOP_WIN_SET(vop, win, format, format); VOP_WIN_SET(vop, win, yrgb_vir, y_vir_stride); VOP_WIN_SET(vop, win, yrgb_mst, yrgb_mst); + if (is_yuv) { + VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride); + VOP_WIN_SET(vop, win, uv_mst, uv_mst); + } val = (actual_h - 1) << 16; val |= (actual_w - 1) & 0xffff; VOP_WIN_SET(vop, win, act_info, val); -- GitLab From c1998f08587a252734bad42b66b430f126f2385b Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 26 Jun 2015 18:10:32 +0800 Subject: [PATCH 4919/7006] drm/rockchip: vop: Default enable win2/3 area0 bit Win2/3 support multiple area function, but we haven't found a suitable way to use it yet, so let's just use them as other windows with only area 0 enabled. Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index c1264d58b03b3..4a2923b0ee31a 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -279,6 +279,12 @@ static const struct vop_reg_data vop_init_reg_table[] = { {DSP_CTRL0, 0x00000000}, {WIN0_CTRL0, 0x00000080}, {WIN1_CTRL0, 0x00000080}, + /* TODO: Win2/3 support multiple area function, but we haven't found + * a suitable way to use it yet, so let's just use them as other windows + * with only area 0 enabled. + */ + {WIN2_CTRL0, 0x00000010}, + {WIN3_CTRL0, 0x00000010}, }; /* -- GitLab From 77faa1619a5ae9ed600b0836bc1eec57bad1895b Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Mon, 20 Jul 2015 16:25:20 +0800 Subject: [PATCH 4920/7006] drm/rockchip: vop: restore vop registers when resume The registers will be reset to default values when whole power domain off, so restore registers from regsbak. Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 4a2923b0ee31a..16b7d98362b06 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -496,6 +496,7 @@ static void vop_enable(struct drm_crtc *crtc) goto err_disable_aclk; } + memcpy(vop->regs, vop->regsbak, vop->len); /* * At here, vop clock & iommu is enable, R/W vop regs would be safe. */ -- GitLab From 4c156c21c7948a0be854cbe5914af3181303e529 Mon Sep 17 00:00:00 2001 From: Mark Yao Date: Fri, 26 Jun 2015 17:14:46 +0800 Subject: [PATCH 4921/7006] drm/rockchip: vop: support plane scale Win_full support 1/8 to 8 scale down/up engine, support all format scale. Signed-off-by: Mark Yao --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 198 +++++++++++++++++++- drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 88 +++++++++ 2 files changed, 284 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 16b7d98362b06..5d8ae5e49c440 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -50,6 +50,8 @@ #define VOP_WIN_SET(x, win, name, v) \ REG_SET(x, win->base, win->phy->name, v, RELAXED) +#define VOP_SCL_SET(x, win, name, v) \ + REG_SET(x, win->base, win->phy->scl->name, v, RELAXED) #define VOP_CTRL_SET(x, name, v) \ REG_SET(x, 0, (x)->data->ctrl->name, v, NORMAL) @@ -164,7 +166,37 @@ struct vop_ctrl { struct vop_reg vpost_st_end; }; +struct vop_scl_regs { + struct vop_reg cbcr_vsd_mode; + struct vop_reg cbcr_vsu_mode; + struct vop_reg cbcr_hsd_mode; + struct vop_reg cbcr_ver_scl_mode; + struct vop_reg cbcr_hor_scl_mode; + struct vop_reg yrgb_vsd_mode; + struct vop_reg yrgb_vsu_mode; + struct vop_reg yrgb_hsd_mode; + struct vop_reg yrgb_ver_scl_mode; + struct vop_reg yrgb_hor_scl_mode; + struct vop_reg line_load_mode; + struct vop_reg cbcr_axi_gather_num; + struct vop_reg yrgb_axi_gather_num; + struct vop_reg vsd_cbcr_gt2; + struct vop_reg vsd_cbcr_gt4; + struct vop_reg vsd_yrgb_gt2; + struct vop_reg vsd_yrgb_gt4; + struct vop_reg bic_coe_sel; + struct vop_reg cbcr_axi_gather_en; + struct vop_reg yrgb_axi_gather_en; + + struct vop_reg lb_mode; + struct vop_reg scale_yrgb_x; + struct vop_reg scale_yrgb_y; + struct vop_reg scale_cbcr_x; + struct vop_reg scale_cbcr_y; +}; + struct vop_win_phy { + const struct vop_scl_regs *scl; const uint32_t *data_formats; uint32_t nformats; @@ -222,7 +254,36 @@ static const uint32_t formats_234[] = { DRM_FORMAT_BGR565, }; +static const struct vop_scl_regs win_full_scl = { + .cbcr_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 31), + .cbcr_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 30), + .cbcr_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 28), + .cbcr_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 26), + .cbcr_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 24), + .yrgb_vsd_mode = VOP_REG(WIN0_CTRL1, 0x1, 23), + .yrgb_vsu_mode = VOP_REG(WIN0_CTRL1, 0x1, 22), + .yrgb_hsd_mode = VOP_REG(WIN0_CTRL1, 0x3, 20), + .yrgb_ver_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 18), + .yrgb_hor_scl_mode = VOP_REG(WIN0_CTRL1, 0x3, 16), + .line_load_mode = VOP_REG(WIN0_CTRL1, 0x1, 15), + .cbcr_axi_gather_num = VOP_REG(WIN0_CTRL1, 0x7, 12), + .yrgb_axi_gather_num = VOP_REG(WIN0_CTRL1, 0xf, 8), + .vsd_cbcr_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 7), + .vsd_cbcr_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 6), + .vsd_yrgb_gt2 = VOP_REG(WIN0_CTRL1, 0x1, 5), + .vsd_yrgb_gt4 = VOP_REG(WIN0_CTRL1, 0x1, 4), + .bic_coe_sel = VOP_REG(WIN0_CTRL1, 0x3, 2), + .cbcr_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 1), + .yrgb_axi_gather_en = VOP_REG(WIN0_CTRL1, 0x1, 0), + .lb_mode = VOP_REG(WIN0_CTRL0, 0x7, 5), + .scale_yrgb_x = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0), + .scale_yrgb_y = VOP_REG(WIN0_SCL_FACTOR_YRGB, 0xffff, 16), + .scale_cbcr_x = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 0x0), + .scale_cbcr_y = VOP_REG(WIN0_SCL_FACTOR_CBR, 0xffff, 16), +}; + static const struct vop_win_phy win01_data = { + .scl = &win_full_scl, .data_formats = formats_01, .nformats = ARRAY_SIZE(formats_01), .enable = VOP_REG(WIN0_CTRL0, 0x1, 0), @@ -422,6 +483,126 @@ static bool is_alpha_support(uint32_t format) } } +static uint16_t scl_vop_cal_scale(enum scale_mode mode, uint32_t src, + uint32_t dst, bool is_horizontal, + int vsu_mode, int *vskiplines) +{ + uint16_t val = 1 << SCL_FT_DEFAULT_FIXPOINT_SHIFT; + + if (is_horizontal) { + if (mode == SCALE_UP) + val = GET_SCL_FT_BIC(src, dst); + else if (mode == SCALE_DOWN) + val = GET_SCL_FT_BILI_DN(src, dst); + } else { + if (mode == SCALE_UP) { + if (vsu_mode == SCALE_UP_BIL) + val = GET_SCL_FT_BILI_UP(src, dst); + else + val = GET_SCL_FT_BIC(src, dst); + } else if (mode == SCALE_DOWN) { + if (vskiplines) { + *vskiplines = scl_get_vskiplines(src, dst); + val = scl_get_bili_dn_vskip(src, dst, + *vskiplines); + } else { + val = GET_SCL_FT_BILI_DN(src, dst); + } + } + } + + return val; +} + +static void scl_vop_cal_scl_fac(struct vop *vop, const struct vop_win_data *win, + uint32_t src_w, uint32_t src_h, uint32_t dst_w, + uint32_t dst_h, uint32_t pixel_format) +{ + uint16_t yrgb_hor_scl_mode, yrgb_ver_scl_mode; + uint16_t cbcr_hor_scl_mode = SCALE_NONE; + uint16_t cbcr_ver_scl_mode = SCALE_NONE; + int hsub = drm_format_horz_chroma_subsampling(pixel_format); + int vsub = drm_format_vert_chroma_subsampling(pixel_format); + bool is_yuv = is_yuv_support(pixel_format); + uint16_t cbcr_src_w = src_w / hsub; + uint16_t cbcr_src_h = src_h / vsub; + uint16_t vsu_mode; + uint16_t lb_mode; + uint32_t val; + int vskiplines; + + if (dst_w > 3840) { + DRM_ERROR("Maximum destination width (3840) exceeded\n"); + return; + } + + yrgb_hor_scl_mode = scl_get_scl_mode(src_w, dst_w); + yrgb_ver_scl_mode = scl_get_scl_mode(src_h, dst_h); + + if (is_yuv) { + cbcr_hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); + cbcr_ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); + if (cbcr_hor_scl_mode == SCALE_DOWN) + lb_mode = scl_vop_cal_lb_mode(dst_w, true); + else + lb_mode = scl_vop_cal_lb_mode(cbcr_src_w, true); + } else { + if (yrgb_hor_scl_mode == SCALE_DOWN) + lb_mode = scl_vop_cal_lb_mode(dst_w, false); + else + lb_mode = scl_vop_cal_lb_mode(src_w, false); + } + + VOP_SCL_SET(vop, win, lb_mode, lb_mode); + if (lb_mode == LB_RGB_3840X2) { + if (yrgb_ver_scl_mode != SCALE_NONE) { + DRM_ERROR("ERROR : not allow yrgb ver scale\n"); + return; + } + if (cbcr_ver_scl_mode != SCALE_NONE) { + DRM_ERROR("ERROR : not allow cbcr ver scale\n"); + return; + } + vsu_mode = SCALE_UP_BIL; + } else if (lb_mode == LB_RGB_2560X4) { + vsu_mode = SCALE_UP_BIL; + } else { + vsu_mode = SCALE_UP_BIC; + } + + val = scl_vop_cal_scale(yrgb_hor_scl_mode, src_w, dst_w, + true, 0, NULL); + VOP_SCL_SET(vop, win, scale_yrgb_x, val); + val = scl_vop_cal_scale(yrgb_ver_scl_mode, src_h, dst_h, + false, vsu_mode, &vskiplines); + VOP_SCL_SET(vop, win, scale_yrgb_y, val); + + VOP_SCL_SET(vop, win, vsd_yrgb_gt4, vskiplines == 4); + VOP_SCL_SET(vop, win, vsd_yrgb_gt2, vskiplines == 2); + + VOP_SCL_SET(vop, win, yrgb_hor_scl_mode, yrgb_hor_scl_mode); + VOP_SCL_SET(vop, win, yrgb_ver_scl_mode, yrgb_ver_scl_mode); + VOP_SCL_SET(vop, win, yrgb_hsd_mode, SCALE_DOWN_BIL); + VOP_SCL_SET(vop, win, yrgb_vsd_mode, SCALE_DOWN_BIL); + VOP_SCL_SET(vop, win, yrgb_vsu_mode, vsu_mode); + if (is_yuv) { + val = scl_vop_cal_scale(cbcr_hor_scl_mode, cbcr_src_w, + dst_w, true, 0, NULL); + VOP_SCL_SET(vop, win, scale_cbcr_x, val); + val = scl_vop_cal_scale(cbcr_ver_scl_mode, cbcr_src_h, + dst_h, false, vsu_mode, &vskiplines); + VOP_SCL_SET(vop, win, scale_cbcr_y, val); + + VOP_SCL_SET(vop, win, vsd_cbcr_gt4, vskiplines == 4); + VOP_SCL_SET(vop, win, vsd_cbcr_gt2, vskiplines == 2); + VOP_SCL_SET(vop, win, cbcr_hor_scl_mode, cbcr_hor_scl_mode); + VOP_SCL_SET(vop, win, cbcr_ver_scl_mode, cbcr_ver_scl_mode); + VOP_SCL_SET(vop, win, cbcr_hsd_mode, SCALE_DOWN_BIL); + VOP_SCL_SET(vop, win, cbcr_vsd_mode, SCALE_DOWN_BIL); + VOP_SCL_SET(vop, win, cbcr_vsu_mode, vsu_mode); + } +} + static void vop_dsp_hold_valid_irq_enable(struct vop *vop) { unsigned long flags; @@ -653,11 +834,15 @@ static int vop_update_plane_event(struct drm_plane *plane, .y2 = crtc->mode.vdisplay, }; bool can_position = plane->type != DRM_PLANE_TYPE_PRIMARY; + int min_scale = win->phy->scl ? FRAC_16_16(1, 8) : + DRM_PLANE_HELPER_NO_SCALING; + int max_scale = win->phy->scl ? FRAC_16_16(8, 1) : + DRM_PLANE_HELPER_NO_SCALING; ret = drm_plane_helper_check_update(plane, crtc, fb, &src, &dest, &clip, - DRM_PLANE_HELPER_NO_SCALING, - DRM_PLANE_HELPER_NO_SCALING, + min_scale, + max_scale, can_position, false, &visible); if (ret) return ret; @@ -761,9 +946,18 @@ static int vop_update_plane_event(struct drm_plane *plane, VOP_WIN_SET(vop, win, uv_vir, uv_vir_stride); VOP_WIN_SET(vop, win, uv_mst, uv_mst); } + + if (win->phy->scl) + scl_vop_cal_scl_fac(vop, win, actual_w, actual_h, + dest.x2 - dest.x1, dest.y2 - dest.y1, + fb->pixel_format); + val = (actual_h - 1) << 16; val |= (actual_w - 1) & 0xffff; VOP_WIN_SET(vop, win, act_info, val); + + val = (dest.y2 - dest.y1 - 1) << 16; + val |= (dest.x2 - dest.x1 - 1) & 0xffff; VOP_WIN_SET(vop, win, dsp_info, val); val = (dsp_sty - 1) << 16; val |= (dsp_stx - 1) & 0xffff; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h index 63e9b3a084c5b..a2d4ddb896fa3 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h @@ -198,4 +198,92 @@ enum factor_mode { ALPHA_SRC_GLOBAL, }; +enum scale_mode { + SCALE_NONE = 0x0, + SCALE_UP = 0x1, + SCALE_DOWN = 0x2 +}; + +enum lb_mode { + LB_YUV_3840X5 = 0x0, + LB_YUV_2560X8 = 0x1, + LB_RGB_3840X2 = 0x2, + LB_RGB_2560X4 = 0x3, + LB_RGB_1920X5 = 0x4, + LB_RGB_1280X8 = 0x5 +}; + +enum sacle_up_mode { + SCALE_UP_BIL = 0x0, + SCALE_UP_BIC = 0x1 +}; + +enum scale_down_mode { + SCALE_DOWN_BIL = 0x0, + SCALE_DOWN_AVG = 0x1 +}; + +#define FRAC_16_16(mult, div) (((mult) << 16) / (div)) +#define SCL_FT_DEFAULT_FIXPOINT_SHIFT 12 +#define SCL_MAX_VSKIPLINES 4 +#define MIN_SCL_FT_AFTER_VSKIP 1 + +static inline uint16_t scl_cal_scale(int src, int dst, int shift) +{ + return ((src * 2 - 3) << (shift - 1)) / (dst - 1); +} + +#define GET_SCL_FT_BILI_DN(src, dst) scl_cal_scale(src, dst, 12) +#define GET_SCL_FT_BILI_UP(src, dst) scl_cal_scale(src, dst, 16) +#define GET_SCL_FT_BIC(src, dst) scl_cal_scale(src, dst, 16) + +static inline uint16_t scl_get_bili_dn_vskip(int src_h, int dst_h, + int vskiplines) +{ + int act_height; + + act_height = (src_h + vskiplines - 1) / vskiplines; + + return GET_SCL_FT_BILI_DN(act_height, dst_h); +} + +static inline enum scale_mode scl_get_scl_mode(int src, int dst) +{ + if (src < dst) + return SCALE_UP; + else if (src > dst) + return SCALE_DOWN; + + return SCALE_NONE; +} + +static inline int scl_get_vskiplines(uint32_t srch, uint32_t dsth) +{ + uint32_t vskiplines; + + for (vskiplines = SCL_MAX_VSKIPLINES; vskiplines > 1; vskiplines /= 2) + if (srch >= vskiplines * dsth * MIN_SCL_FT_AFTER_VSKIP) + break; + + return vskiplines; +} + +static inline int scl_vop_cal_lb_mode(int width, bool is_yuv) +{ + int lb_mode; + + if (width > 2560) + lb_mode = LB_RGB_3840X2; + else if (width > 1920) + lb_mode = LB_RGB_2560X4; + else if (!is_yuv) + lb_mode = LB_RGB_1920X5; + else if (width > 1280) + lb_mode = LB_YUV_3840X5; + else + lb_mode = LB_YUV_2560X8; + + return lb_mode; +} + #endif /* _ROCKCHIP_DRM_VOP_H */ -- GitLab From fc0bfacd045a17e385b4272dfe2387ba3a6d8745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Giedrius=20Statkevi=C4=8Dius?= Date: Sun, 23 Aug 2015 14:41:09 +0300 Subject: [PATCH 4922/7006] hp-wireless: remove unneeded goto/label in hpwl_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit acpi_bus_register_driver() already returns an appropriate value (0 on success, and some negative value on error) to be used in __init functions so the goto/label is redundant in hpwl_init thus remove it and directly return the value Signed-off-by: Giedrius Statkevičius Signed-off-by: Darren Hart --- drivers/platform/x86/hp-wireless.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/platform/x86/hp-wireless.c b/drivers/platform/x86/hp-wireless.c index 4e4cc8bd7557d..988eedbd7c636 100644 --- a/drivers/platform/x86/hp-wireless.c +++ b/drivers/platform/x86/hp-wireless.c @@ -114,14 +114,9 @@ static int __init hpwl_init(void) pr_info("Initializing HPQ6001 module\n"); err = acpi_bus_register_driver(&hpwl_driver); - if (err) { + if (err) pr_err("Unable to register HP wireless control driver.\n"); - goto error_acpi_register; - } - - return 0; -error_acpi_register: return err; } -- GitLab From 5f8b253147c27b8244451ee28aeb3429c5aa2e52 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 24 Aug 2015 16:48:44 -0700 Subject: [PATCH 4923/7006] drm/i915/skl: Update DDI buffer translation programming. SKL-Y can now use the same programming for all VccIO values after an adjustment to I_boost. SKL-U DP table adjustments. 1. Remove SKL Y 0.95V from "SKL H and S" columns in all tables. The other SKL Y column removes the "0.85V VccIO" so it now applies to all voltages. 2. DP table changes SKL U 400mV+0db dword 0 value from 2016h to 201Bh. 3. DP table changes SKL U 600mv+0db dword 0 value from 2016h to 201Bh. 4. DP table increases I_boost to level 3 for SKL Y 400mv+9.5db. v2: Fix compilation warnings as pointed by Paulo. Reference: Graphics Spec Change r97962 Cc: Arthur Runyan Signed-off-by: Rodrigo Vivi Reviewed-by: Paulo Zanoni [Jani: reformatted commit message for shorter lines.] Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 75 +++++++++++--------------------- 1 file changed, 25 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 6cfe65d6a8cf9..19004557c868a 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -128,7 +128,7 @@ static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = { { 0x80FFFFFF, 0x001B0002, 0x0 },/* 9: 1000 1000 0 */ }; -/* Skylake H, S, and Skylake Y with 0.95V VccIO */ +/* Skylake H and S */ static const struct ddi_buf_trans skl_ddi_translations_dp[] = { { 0x00002016, 0x000000A0, 0x0 }, { 0x00005012, 0x0000009B, 0x0 }, @@ -143,23 +143,23 @@ static const struct ddi_buf_trans skl_ddi_translations_dp[] = { /* Skylake U */ static const struct ddi_buf_trans skl_u_ddi_translations_dp[] = { - { 0x00002016, 0x000000A2, 0x0 }, + { 0x0000201B, 0x000000A2, 0x0 }, { 0x00005012, 0x00000088, 0x0 }, { 0x00007011, 0x00000087, 0x0 }, - { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost */ - { 0x00002016, 0x0000009D, 0x0 }, + { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost level 0x1 */ + { 0x0000201B, 0x0000009D, 0x0 }, { 0x00005012, 0x000000C7, 0x0 }, { 0x00007011, 0x000000C7, 0x0 }, { 0x00002016, 0x00000088, 0x0 }, { 0x00005012, 0x000000C7, 0x0 }, }; -/* Skylake Y with 0.85V VccIO */ -static const struct ddi_buf_trans skl_y_085v_ddi_translations_dp[] = { +/* Skylake Y */ +static const struct ddi_buf_trans skl_y_ddi_translations_dp[] = { { 0x00000018, 0x000000A2, 0x0 }, { 0x00005012, 0x00000088, 0x0 }, { 0x00007011, 0x00000087, 0x0 }, - { 0x80009010, 0x000000C7, 0x1 }, /* Uses I_boost */ + { 0x80009010, 0x000000C7, 0x3 }, /* Uses I_boost level 0x3 */ { 0x00000018, 0x0000009D, 0x0 }, { 0x00005012, 0x000000C7, 0x0 }, { 0x00007011, 0x000000C7, 0x0 }, @@ -168,7 +168,7 @@ static const struct ddi_buf_trans skl_y_085v_ddi_translations_dp[] = { }; /* - * Skylake H and S, and Skylake Y with 0.95V VccIO + * Skylake H and S * eDP 1.4 low vswing translation parameters */ static const struct ddi_buf_trans skl_ddi_translations_edp[] = { @@ -202,10 +202,10 @@ static const struct ddi_buf_trans skl_u_ddi_translations_edp[] = { }; /* - * Skylake Y with 0.95V VccIO + * Skylake Y * eDP 1.4 low vswing translation parameters */ -static const struct ddi_buf_trans skl_y_085v_ddi_translations_edp[] = { +static const struct ddi_buf_trans skl_y_ddi_translations_edp[] = { { 0x00000018, 0x000000A8, 0x0 }, { 0x00004013, 0x000000AB, 0x0 }, { 0x00007011, 0x000000A4, 0x0 }, @@ -218,7 +218,7 @@ static const struct ddi_buf_trans skl_y_085v_ddi_translations_edp[] = { { 0x00000018, 0x0000008A, 0x0 }, }; -/* Skylake H, S and U, and Skylake Y with 0.95V VccIO */ +/* Skylake U, H and S */ static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { { 0x00000018, 0x000000AC, 0x0 }, { 0x00005012, 0x0000009D, 0x0 }, @@ -233,8 +233,8 @@ static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = { { 0x00000018, 0x000000C7, 0x0 }, }; -/* Skylake Y with 0.85V VccIO */ -static const struct ddi_buf_trans skl_y_085v_ddi_translations_hdmi[] = { +/* Skylake Y */ +static const struct ddi_buf_trans skl_y_ddi_translations_hdmi[] = { { 0x00000018, 0x000000A1, 0x0 }, { 0x00005012, 0x000000DF, 0x0 }, { 0x00007011, 0x00000084, 0x0 }, @@ -244,7 +244,7 @@ static const struct ddi_buf_trans skl_y_085v_ddi_translations_hdmi[] = { { 0x00006013, 0x000000C7, 0x0 }, { 0x00000018, 0x0000008A, 0x0 }, { 0x00003015, 0x000000C7, 0x0 }, /* Default */ - { 0x80003015, 0x000000C7, 0x7 }, /* Uses I_boost */ + { 0x80003015, 0x000000C7, 0x7 }, /* Uses I_boost level 0x7 */ { 0x00000018, 0x000000C7, 0x0 }, }; @@ -335,19 +335,11 @@ intel_dig_port_supports_hdmi(const struct intel_digital_port *intel_dig_port) static const struct ddi_buf_trans *skl_get_buf_trans_dp(struct drm_device *dev, int *n_entries) { - struct drm_i915_private *dev_priv = dev->dev_private; const struct ddi_buf_trans *ddi_translations; - static int is_095v = -1; - - if (is_095v == -1) { - u32 spr1 = I915_READ(UAIMI_SPR1); - - is_095v = spr1 & SKL_VCCIO_MASK; - } - if (IS_SKL_ULX(dev) && !is_095v) { - ddi_translations = skl_y_085v_ddi_translations_dp; - *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_dp); + if (IS_SKL_ULX(dev)) { + ddi_translations = skl_y_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp); } else if (IS_SKL_ULT(dev)) { ddi_translations = skl_u_ddi_translations_dp; *n_entries = ARRAY_SIZE(skl_u_ddi_translations_dp); @@ -364,23 +356,14 @@ static const struct ddi_buf_trans *skl_get_buf_trans_edp(struct drm_device *dev, { struct drm_i915_private *dev_priv = dev->dev_private; const struct ddi_buf_trans *ddi_translations; - static int is_095v = -1; - - if (is_095v == -1) { - u32 spr1 = I915_READ(UAIMI_SPR1); - is_095v = spr1 & SKL_VCCIO_MASK; - } - - if (IS_SKL_ULX(dev) && !is_095v) { + if (IS_SKL_ULX(dev)) { if (dev_priv->edp_low_vswing) { - ddi_translations = skl_y_085v_ddi_translations_edp; - *n_entries = - ARRAY_SIZE(skl_y_085v_ddi_translations_edp); + ddi_translations = skl_y_ddi_translations_edp; + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_edp); } else { - ddi_translations = skl_y_085v_ddi_translations_dp; - *n_entries = - ARRAY_SIZE(skl_y_085v_ddi_translations_dp); + ddi_translations = skl_y_ddi_translations_dp; + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_dp); } } else if (IS_SKL_ULT(dev)) { if (dev_priv->edp_low_vswing) { @@ -407,19 +390,11 @@ static const struct ddi_buf_trans * skl_get_buf_trans_hdmi(struct drm_device *dev, int *n_entries) { - struct drm_i915_private *dev_priv = dev->dev_private; const struct ddi_buf_trans *ddi_translations; - static int is_095v = -1; - - if (is_095v == -1) { - u32 spr1 = I915_READ(UAIMI_SPR1); - - is_095v = spr1 & SKL_VCCIO_MASK; - } - if (IS_SKL_ULX(dev) && !is_095v) { - ddi_translations = skl_y_085v_ddi_translations_hdmi; - *n_entries = ARRAY_SIZE(skl_y_085v_ddi_translations_hdmi); + if (IS_SKL_ULX(dev)) { + ddi_translations = skl_y_ddi_translations_hdmi; + *n_entries = ARRAY_SIZE(skl_y_ddi_translations_hdmi); } else { ddi_translations = skl_ddi_translations_hdmi; *n_entries = ARRAY_SIZE(skl_ddi_translations_hdmi); -- GitLab From 8e9d597a37e407476b4de725bef4cb1ad1f5c22c Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 14 Aug 2015 12:35:23 +0200 Subject: [PATCH 4924/7006] drm/i915: Fix build warning on 32-bit The gtt.stolen_size field is of type size_t, and so should be printed using %zu to avoid build warnings on either 32-bit and 64-bit builds. Signed-off-by: Thierry Reding Reviewed-by: Paulo Zanoni Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_stolen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index a36cb95ec798e..f361c4a569955 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -348,7 +348,7 @@ int i915_gem_init_stolen(struct drm_device *dev) * memory, so just consider the start. */ reserved_total = stolen_top - reserved_base; - DRM_DEBUG_KMS("Memory reserved for graphics device: %luK, usable: %luK\n", + DRM_DEBUG_KMS("Memory reserved for graphics device: %zuK, usable: %luK\n", dev_priv->gtt.stolen_size >> 10, (dev_priv->gtt.stolen_size - reserved_total) >> 10); -- GitLab From 2508a45a924dfa4a5f6e60675aa4732d888134a7 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Tue, 18 Aug 2015 23:30:25 +0800 Subject: [PATCH 4925/7006] surface pro 3: Add support driver for Surface Pro 3 buttons Since Surface Pro 3 does not follow the specs of "Windows ACPI Design Guide for SoC Platform", code in drivers/input/misc/soc_array.c can not detect these buttons on it. According to bios implementation, Surface Pro 3 encapsulates these buttons in a device named "VGBI", with _HID "MSHW0028". When any of the buttons is pressed, a specify ACPI notification code for this button will be delivered to "VGBI". For example, if power button is pressed down, ACPI notification code of 0xc6 will be sent by Notify(VGBI, 0xc6). This patch leverages "VGBI" to distinguish different ACPI notification code from Power button, Home button, Volume button, then dispatches these code to input layer. Lid is already covered by acpi button driver, so there's no need to rewrite. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=84651 Tested-by: Ethan Schoonover Tested-by: Peter Amidon Tested-by: Donavan Lance Tested-by: Stephen Just Signed-off-by: Chen Yu [dvhart@linux.intel.com: Formatting corrections in MAINTAINERS and Intel (c)] Signed-off-by: Darren Hart --- MAINTAINERS | 6 + drivers/platform/x86/Kconfig | 5 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/surfacepro3_button.c | 216 ++++++++++++++++++++++ 4 files changed, 228 insertions(+) create mode 100644 drivers/platform/x86/surfacepro3_button.c diff --git a/MAINTAINERS b/MAINTAINERS index cbeb4c145d8f7..884d398162864 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6709,6 +6709,12 @@ T: git git://git.monstr.eu/linux-2.6-microblaze.git S: Supported F: arch/microblaze/ +MICROSOFT SURFACE PRO 3 BUTTON DRIVER +M: Chen Yu +L: platform-driver-x86@vger.kernel.org +S: Supported +F: drivers/platform/x86/surfacepro3_button.c + MICROTEK X6 SCANNER M: Oliver Neukum S: Maintained diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 6dc13e4de3962..c69bb703f4835 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -919,4 +919,9 @@ config INTEL_PMC_IPC The PMC is an ARC processor which defines IPC commands for communication with other entities in the CPU. +config SURFACE_PRO3_BUTTON + tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3 tablet" + depends on ACPI && INPUT + ---help--- + This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3 tablet. endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index dda95a9853210..ada5128190285 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -60,3 +60,4 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o +obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o diff --git a/drivers/platform/x86/surfacepro3_button.c b/drivers/platform/x86/surfacepro3_button.c new file mode 100644 index 0000000000000..f7dade3fd2ab9 --- /dev/null +++ b/drivers/platform/x86/surfacepro3_button.c @@ -0,0 +1,216 @@ +/* + * power/home/volume button support for + * Microsoft Surface Pro 3 tablet. + * + * Copyright (c) 2015 Intel Corporation. + * All rights reserved. + * + * 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; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SURFACE_BUTTON_HID "MSHW0028" +#define SURFACE_BUTTON_OBJ_NAME "VGBI" +#define SURFACE_BUTTON_DEVICE_NAME "Surface Pro 3 Buttons" + +#define SURFACE_BUTTON_NOTIFY_PRESS_POWER 0xc6 +#define SURFACE_BUTTON_NOTIFY_RELEASE_POWER 0xc7 + +#define SURFACE_BUTTON_NOTIFY_PRESS_HOME 0xc4 +#define SURFACE_BUTTON_NOTIFY_RELEASE_HOME 0xc5 + +#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP 0xc0 +#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP 0xc1 + +#define SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN 0xc2 +#define SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN 0xc3 + +ACPI_MODULE_NAME("surface pro 3 button"); + +MODULE_AUTHOR("Chen Yu"); +MODULE_DESCRIPTION("Surface Pro3 Button Driver"); +MODULE_LICENSE("GPL v2"); + +/* + * Power button, Home button, Volume buttons support is supposed to + * be covered by drivers/input/misc/soc_button_array.c, which is implemented + * according to "Windows ACPI Design Guide for SoC Platforms". + * However surface pro3 seems not to obey the specs, instead it uses + * device VGBI(MSHW0028) for dispatching the events. + * We choose acpi_driver rather than platform_driver/i2c_driver because + * although VGBI has an i2c resource connected to i2c controller, it + * is not embedded in any i2c controller's scope, thus neither platform_device + * will be created, nor i2c_client will be enumerated, we have to use + * acpi_driver. + */ +static const struct acpi_device_id surface_button_device_ids[] = { + {SURFACE_BUTTON_HID, 0}, + {"", 0}, +}; +MODULE_DEVICE_TABLE(acpi, surface_button_device_ids); + +struct surface_button { + unsigned int type; + struct input_dev *input; + char phys[32]; /* for input device */ + unsigned long pushed; + bool suspended; +}; + +static void surface_button_notify(struct acpi_device *device, u32 event) +{ + struct surface_button *button = acpi_driver_data(device); + struct input_dev *input; + int key_code = KEY_RESERVED; + bool pressed = false; + + switch (event) { + /* Power button press,release handle */ + case SURFACE_BUTTON_NOTIFY_PRESS_POWER: + pressed = true; + /*fall through*/ + case SURFACE_BUTTON_NOTIFY_RELEASE_POWER: + key_code = KEY_POWER; + break; + /* Home button press,release handle */ + case SURFACE_BUTTON_NOTIFY_PRESS_HOME: + pressed = true; + /*fall through*/ + case SURFACE_BUTTON_NOTIFY_RELEASE_HOME: + key_code = KEY_LEFTMETA; + break; + /* Volume up button press,release handle */ + case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_UP: + pressed = true; + /*fall through*/ + case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_UP: + key_code = KEY_VOLUMEUP; + break; + /* Volume down button press,release handle */ + case SURFACE_BUTTON_NOTIFY_PRESS_VOLUME_DOWN: + pressed = true; + /*fall through*/ + case SURFACE_BUTTON_NOTIFY_RELEASE_VOLUME_DOWN: + key_code = KEY_VOLUMEDOWN; + break; + default: + dev_info_ratelimited(&device->dev, + "Unsupported event [0x%x]\n", event); + break; + } + input = button->input; + if (KEY_RESERVED == key_code) + return; + if (pressed) + pm_wakeup_event(&device->dev, 0); + if (button->suspended) + return; + input_report_key(input, key_code, pressed?1:0); + input_sync(input); +} + +#ifdef CONFIG_PM_SLEEP +static int surface_button_suspend(struct device *dev) +{ + struct acpi_device *device = to_acpi_device(dev); + struct surface_button *button = acpi_driver_data(device); + + button->suspended = true; + return 0; +} + +static int surface_button_resume(struct device *dev) +{ + struct acpi_device *device = to_acpi_device(dev); + struct surface_button *button = acpi_driver_data(device); + + button->suspended = false; + return 0; +} +#endif + +static int surface_button_add(struct acpi_device *device) +{ + struct surface_button *button; + struct input_dev *input; + const char *hid = acpi_device_hid(device); + char *name; + int error; + + if (strncmp(acpi_device_bid(device), SURFACE_BUTTON_OBJ_NAME, + strlen(SURFACE_BUTTON_OBJ_NAME))) + return -ENODEV; + + button = kzalloc(sizeof(struct surface_button), GFP_KERNEL); + if (!button) + return -ENOMEM; + + device->driver_data = button; + button->input = input = input_allocate_device(); + if (!input) { + error = -ENOMEM; + goto err_free_button; + } + + name = acpi_device_name(device); + strcpy(name, SURFACE_BUTTON_DEVICE_NAME); + snprintf(button->phys, sizeof(button->phys), "%s/buttons", hid); + + input->name = name; + input->phys = button->phys; + input->id.bustype = BUS_HOST; + input->dev.parent = &device->dev; + input_set_capability(input, EV_KEY, KEY_POWER); + input_set_capability(input, EV_KEY, KEY_LEFTMETA); + input_set_capability(input, EV_KEY, KEY_VOLUMEUP); + input_set_capability(input, EV_KEY, KEY_VOLUMEDOWN); + + error = input_register_device(input); + if (error) + goto err_free_input; + dev_info(&device->dev, + "%s [%s]\n", name, acpi_device_bid(device)); + return 0; + + err_free_input: + input_free_device(input); + err_free_button: + kfree(button); + return error; +} + +static int surface_button_remove(struct acpi_device *device) +{ + struct surface_button *button = acpi_driver_data(device); + + input_unregister_device(button->input); + kfree(button); + return 0; +} + +static SIMPLE_DEV_PM_OPS(surface_button_pm, + surface_button_suspend, surface_button_resume); + +static struct acpi_driver surface_button_driver = { + .name = "surface_pro3_button", + .class = "SurfacePro3", + .ids = surface_button_device_ids, + .ops = { + .add = surface_button_add, + .remove = surface_button_remove, + .notify = surface_button_notify, + }, + .drv.pm = &surface_button_pm, +}; + +module_acpi_driver(surface_button_driver); -- GitLab From 26951caf55d73ceb1967b0bf12f6d0b96853508e Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Mon, 17 Aug 2015 15:55:50 +0800 Subject: [PATCH 4926/7006] drm/i915/skl: enable DDI-E hotplug v2: fix one error found by checkpath.pl v3: Add one ignored break for switch-case. DDI-E hotplug function doesn't work after updating drm-intel tree, I checked the code and found this missing which isn't the root cause for broke DDI-E hp. The broken DDI-E hp function is fixed by "Adding DDI_E power well domain". Signed-off-by: Xiong Zhang Reviewed-by: Rodrigo Vivi Tested-by: Timo Aaltonen Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/i915_irq.c | 48 +++++++++++++++++++++++++--- drivers/gpu/drm/i915/i915_reg.h | 12 +++++++ drivers/gpu/drm/i915/intel_display.c | 3 ++ drivers/gpu/drm/i915/intel_dp.c | 3 ++ drivers/gpu/drm/i915/intel_hotplug.c | 3 ++ 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 599441beea17e..089459b397711 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -214,6 +214,7 @@ enum hpd_pin { HPD_PORT_B, HPD_PORT_C, HPD_PORT_D, + HPD_PORT_E, HPD_NUM_PINS }; diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index 1118c39281f98..d94c92d842fb9 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -61,6 +61,13 @@ static const u32 hpd_cpt[HPD_NUM_PINS] = { [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT }; +static const u32 hpd_spt[HPD_NUM_PINS] = { + [HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT, + [HPD_PORT_C] = SDE_PORTC_HOTPLUG_CPT, + [HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT, + [HPD_PORT_E] = SDE_PORTE_HOTPLUG_SPT +}; + static const u32 hpd_mask_i915[HPD_NUM_PINS] = { [HPD_CRT] = CRT_HOTPLUG_INT_EN, [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN, @@ -1252,6 +1259,8 @@ static bool pch_port_hotplug_long_detect(enum port port, u32 val) return val & PORTC_HOTPLUG_LONG_DETECT; case PORT_D: return val & PORTD_HOTPLUG_LONG_DETECT; + case PORT_E: + return val & PORTE_HOTPLUG_LONG_DETECT; default: return false; } @@ -1752,7 +1761,12 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) { struct drm_i915_private *dev_priv = dev->dev_private; int pipe; - u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; + u32 hotplug_trigger; + + if (HAS_PCH_SPT(dev)) + hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_SPT; + else + hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT; if (hotplug_trigger) { u32 dig_hotplug_reg, pin_mask, long_mask; @@ -1760,9 +1774,23 @@ static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir) dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG); I915_WRITE(PCH_PORT_HOTPLUG, dig_hotplug_reg); - intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - dig_hotplug_reg, hpd_cpt, - pch_port_hotplug_long_detect); + if (HAS_PCH_SPT(dev)) { + intel_get_hpd_pins(&pin_mask, &long_mask, + hotplug_trigger, + dig_hotplug_reg, hpd_spt, + pch_port_hotplug_long_detect); + + /* detect PORTE HP event */ + dig_hotplug_reg = I915_READ(PCH_PORT_HOTPLUG2); + if (pch_port_hotplug_long_detect(PORT_E, + dig_hotplug_reg)) + long_mask |= 1 << HPD_PORT_E; + } else + intel_get_hpd_pins(&pin_mask, &long_mask, + hotplug_trigger, + dig_hotplug_reg, hpd_cpt, + pch_port_hotplug_long_detect); + intel_hpd_irq_handler(dev, pin_mask, long_mask); } @@ -2984,6 +3012,11 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) for_each_intel_encoder(dev, intel_encoder) if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) enabled_irqs |= hpd_ibx[intel_encoder->hpd_pin]; + } else if (HAS_PCH_SPT(dev)) { + hotplug_irqs = SDE_HOTPLUG_MASK_SPT; + for_each_intel_encoder(dev, intel_encoder) + if (dev_priv->hotplug.stats[intel_encoder->hpd_pin].state == HPD_ENABLED) + enabled_irqs |= hpd_spt[intel_encoder->hpd_pin]; } else { hotplug_irqs = SDE_HOTPLUG_MASK_CPT; for_each_intel_encoder(dev, intel_encoder) @@ -3005,6 +3038,13 @@ static void ibx_hpd_irq_setup(struct drm_device *dev) hotplug |= PORTC_HOTPLUG_ENABLE | PORTC_PULSE_DURATION_2ms; hotplug |= PORTB_HOTPLUG_ENABLE | PORTB_PULSE_DURATION_2ms; I915_WRITE(PCH_PORT_HOTPLUG, hotplug); + + /* enable SPT PORTE hot plug */ + if (HAS_PCH_SPT(dev)) { + hotplug = I915_READ(PCH_PORT_HOTPLUG2); + hotplug |= PORTE_HOTPLUG_ENABLE; + I915_WRITE(PCH_PORT_HOTPLUG2, hotplug); + } } static void bxt_hpd_irq_setup(struct drm_device *dev) diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 8e46c348366bc..83a0888756d68 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -5949,6 +5949,7 @@ enum skl_disp_power_wells { #define SDE_AUXC_CPT (1 << 26) #define SDE_AUXB_CPT (1 << 25) #define SDE_AUX_MASK_CPT (7 << 25) +#define SDE_PORTE_HOTPLUG_SPT (1 << 25) #define SDE_PORTD_HOTPLUG_CPT (1 << 23) #define SDE_PORTC_HOTPLUG_CPT (1 << 22) #define SDE_PORTB_HOTPLUG_CPT (1 << 21) @@ -5959,6 +5960,10 @@ enum skl_disp_power_wells { SDE_PORTD_HOTPLUG_CPT | \ SDE_PORTC_HOTPLUG_CPT | \ SDE_PORTB_HOTPLUG_CPT) +#define SDE_HOTPLUG_MASK_SPT (SDE_PORTE_HOTPLUG_SPT | \ + SDE_PORTD_HOTPLUG_CPT | \ + SDE_PORTC_HOTPLUG_CPT | \ + SDE_PORTB_HOTPLUG_CPT) #define SDE_GMBUS_CPT (1 << 17) #define SDE_ERROR_CPT (1 << 16) #define SDE_AUDIO_CP_REQ_C_CPT (1 << 10) @@ -6030,6 +6035,13 @@ enum skl_disp_power_wells { #define PORTB_HOTPLUG_SHORT_DETECT (1 << 0) #define PORTB_HOTPLUG_LONG_DETECT (2 << 0) +#define PCH_PORT_HOTPLUG2 0xc403C /* SHOTPLUG_CTL2 */ +#define PORTE_HOTPLUG_ENABLE (1 << 4) +#define PORTE_HOTPLUG_STATUS_MASK (0x3 << 0) +#define PORTE_HOTPLUG_NO_DETECT (0 << 0) +#define PORTE_HOTPLUG_SHORT_DETECT (1 << 0) +#define PORTE_HOTPLUG_LONG_DETECT (2 << 0) + #define PCH_GPIOA 0xc5010 #define PCH_GPIOB 0xc5014 #define PCH_GPIOC 0xc5018 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 83936403502fb..53f5476bc4bb8 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -1098,6 +1098,9 @@ bool ibx_digital_port_connected(struct drm_i915_private *dev_priv, case PORT_D: bit = SDE_PORTD_HOTPLUG_CPT; break; + case PORT_E: + bit = SDE_PORTE_HOTPLUG_SPT; + break; default: return true; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 260ff8b084377..3781cd3e358a7 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5860,6 +5860,9 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, case PORT_D: intel_encoder->hpd_pin = HPD_PORT_D; break; + case PORT_E: + intel_encoder->hpd_pin = HPD_PORT_E; + break; default: BUG(); } diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c index 032a0bf75f3b1..53c0173a39fe1 100644 --- a/drivers/gpu/drm/i915/intel_hotplug.c +++ b/drivers/gpu/drm/i915/intel_hotplug.c @@ -91,6 +91,9 @@ bool intel_hpd_pin_to_port(enum hpd_pin pin, enum port *port) case HPD_PORT_D: *port = PORT_D; return true; + case HPD_PORT_E: + *port = PORT_E; + return true; default: return false; /* no hpd */ } -- GitLab From 78e1c896932df5b8bcdff7bf5417d8e72a4d0d6b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 17 Aug 2015 16:03:17 +0300 Subject: [PATCH 4927/7006] pinctrl: baytrail: Use raw_spinlock for locking The Intel Baytrail pinctrl driver implements irqchip callbacks which are called with desc->lock raw_spinlock held. In mainline this is fine because spinlock resolves to raw_spinlock. However, running the same code in -rt we get: BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:917 in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/0 Preemption disabled at:[] cpu_startup_entry+0x17f/0x480 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.1.5-rt5 #13 ... Call Trace: [] dump_stack+0x4a/0x61 [] ___might_sleep+0xe7/0x170 [] rt_spin_lock+0x1f/0x50 [] byt_gpio_clear_triggering+0x38/0x60 [] byt_irq_mask+0x11/0x20 [] handle_level_irq+0x83/0x150 [] generic_handle_irq+0x27/0x40 [] byt_gpio_irq_handler+0x7f/0xc0 [] handle_irq+0xaa/0x190 ... This is because in -rt spinlocks are preemptible so taking the driver private spinlock in irqchip callbacks causes might_sleep() to trigger. In order to keep -rt happy but at the same time make sure that register accesses get serialized, convert the driver to use raw_spinlock instead. Also shorten the critical section a bit in few places. Suggested-by: Linus Walleij Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-baytrail.c | 50 ++++++++++++------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c index 016b4019d2a56..dac4865f3203d 100644 --- a/drivers/pinctrl/intel/pinctrl-baytrail.c +++ b/drivers/pinctrl/intel/pinctrl-baytrail.c @@ -141,7 +141,7 @@ struct byt_gpio_pin_context { struct byt_gpio { struct gpio_chip chip; struct platform_device *pdev; - spinlock_t lock; + raw_spinlock_t lock; void __iomem *reg_base; struct pinctrl_gpio_range *range; struct byt_gpio_pin_context *saved_context; @@ -169,11 +169,11 @@ static void byt_gpio_clear_triggering(struct byt_gpio *vg, unsigned offset) unsigned long flags; u32 value; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); value = readl(reg); value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL); writel(value, reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); } static u32 byt_get_gpio_mux(struct byt_gpio *vg, unsigned offset) @@ -198,7 +198,7 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset) u32 value, gpio_mux; unsigned long flags; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); /* * In most cases, func pin mux 000 means GPIO function. @@ -220,7 +220,7 @@ static int byt_gpio_request(struct gpio_chip *chip, unsigned offset) "pin %u forcibly re-configured as GPIO\n", offset); } - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); pm_runtime_get(&vg->pdev->dev); @@ -246,7 +246,7 @@ static int byt_irq_type(struct irq_data *d, unsigned type) if (offset >= vg->chip.ngpio) return -EINVAL; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); value = readl(reg); WARN(value & BYT_DIRECT_IRQ_EN, @@ -265,7 +265,7 @@ static int byt_irq_type(struct irq_data *d, unsigned type) else if (type & IRQ_TYPE_LEVEL_MASK) irq_set_handler_locked(d, handle_level_irq); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); return 0; } @@ -277,9 +277,9 @@ static int byt_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned long flags; u32 val; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); val = readl(reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); return val & BYT_LEVEL; } @@ -291,7 +291,7 @@ static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) unsigned long flags; u32 old_val; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); old_val = readl(reg); @@ -300,7 +300,7 @@ static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value) else writel(old_val & ~BYT_LEVEL, reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); } static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) @@ -310,13 +310,13 @@ static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset) unsigned long flags; u32 value; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); value = readl(reg) | BYT_DIR_MASK; value &= ~BYT_INPUT_EN; /* active low */ writel(value, reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); return 0; } @@ -330,7 +330,7 @@ static int byt_gpio_direction_output(struct gpio_chip *chip, unsigned long flags; u32 reg_val; - spin_lock_irqsave(&vg->lock, flags); + raw_spin_lock_irqsave(&vg->lock, flags); /* * Before making any direction modifications, do a check if gpio @@ -349,7 +349,7 @@ static int byt_gpio_direction_output(struct gpio_chip *chip, else writel(reg_val & ~BYT_LEVEL, reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); return 0; } @@ -358,18 +358,19 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { struct byt_gpio *vg = to_byt_gpio(chip); int i; - unsigned long flags; u32 conf0, val, offs; - spin_lock_irqsave(&vg->lock, flags); - for (i = 0; i < vg->chip.ngpio; i++) { const char *pull_str = NULL; const char *pull = NULL; + unsigned long flags; const char *label; offs = vg->range->pins[i] * 16; + + raw_spin_lock_irqsave(&vg->lock, flags); conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG); val = readl(vg->reg_base + offs + BYT_VAL_REG); + raw_spin_unlock_irqrestore(&vg->lock, flags); label = gpiochip_is_requested(chip, i); if (!label) @@ -422,7 +423,6 @@ static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) seq_puts(s, "\n"); } - spin_unlock_irqrestore(&vg->lock, flags); } static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc) @@ -454,10 +454,10 @@ static void byt_irq_ack(struct irq_data *d) unsigned offset = irqd_to_hwirq(d); void __iomem *reg; - spin_lock(&vg->lock); + raw_spin_lock(&vg->lock); reg = byt_gpio_reg(&vg->chip, offset, BYT_INT_STAT_REG); writel(BIT(offset % 32), reg); - spin_unlock(&vg->lock); + raw_spin_unlock(&vg->lock); } static void byt_irq_unmask(struct irq_data *d) @@ -469,9 +469,9 @@ static void byt_irq_unmask(struct irq_data *d) void __iomem *reg; u32 value; - spin_lock_irqsave(&vg->lock, flags); - reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG); + + raw_spin_lock_irqsave(&vg->lock, flags); value = readl(reg); switch (irqd_get_trigger_type(d)) { @@ -492,7 +492,7 @@ static void byt_irq_unmask(struct irq_data *d) writel(value, reg); - spin_unlock_irqrestore(&vg->lock, flags); + raw_spin_unlock_irqrestore(&vg->lock, flags); } static void byt_irq_mask(struct irq_data *d) @@ -584,7 +584,7 @@ static int byt_gpio_probe(struct platform_device *pdev) if (IS_ERR(vg->reg_base)) return PTR_ERR(vg->reg_base); - spin_lock_init(&vg->lock); + raw_spin_lock_init(&vg->lock); gc = &vg->chip; gc->label = dev_name(&pdev->dev); -- GitLab From 109fdf1572be86aaf681e69b30dc5ada90ce6f35 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Mon, 17 Aug 2015 16:13:30 +0300 Subject: [PATCH 4928/7006] pinctrl: cherryview: Use raw_spinlock for locking When running -rt kernel and an interrupt happens on a GPIO line controlled by Intel Cherryview/Braswell pinctrl driver we get: BUG: sleeping function called from invalid context at kernel/locking/rtmutex.c:917 in_atomic(): 1, irqs_disabled(): 1, pid: 0, name: swapper/0 Preemption disabled at:[] cpu_startup_entry+0x17f/0x480 CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.1.5-rt5 #16 ... Call Trace: [] dump_stack+0x4a/0x61 [] ___might_sleep+0xe7/0x170 [] rt_spin_lock+0x1f/0x50 [] chv_gpio_irq_ack+0x3d/0xa0 [] handle_edge_irq+0x75/0x180 [] generic_handle_irq+0x27/0x40 [] chv_gpio_irq_handler+0x7e/0x110 [] handle_irq+0xaa/0x190 ... This is because desc->lock is raw_spinlock and is held when chv_gpio_irq_ack() is called by the genirq core. chv_gpio_irq_ack() in turn takes pctrl->lock which in -rt is an rt-mutex causing might_sleep() rightfully to complain about sleeping function called from invalid context. In order to keep -rt happy but at the same time make sure that register accesses get serialized, convert the driver to use raw_spinlock instead. Suggested-by: Linus Walleij Signed-off-by: Mika Westerberg Signed-off-by: Linus Walleij --- drivers/pinctrl/intel/pinctrl-cherryview.c | 70 +++++++++++----------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c index 2984b460bbc51..2d5d3ddc36e5b 100644 --- a/drivers/pinctrl/intel/pinctrl-cherryview.c +++ b/drivers/pinctrl/intel/pinctrl-cherryview.c @@ -174,7 +174,7 @@ struct chv_pinctrl { struct pinctrl_dev *pctldev; struct gpio_chip chip; void __iomem *regs; - spinlock_t lock; + raw_spinlock_t lock; unsigned intr_lines[16]; const struct chv_community *community; u32 saved_intmask; @@ -720,13 +720,13 @@ static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s, u32 ctrl0, ctrl1; bool locked; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1)); locked = chv_pad_locked(pctrl, offset); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); if (ctrl0 & CHV_PADCTRL0_GPIOEN) { seq_puts(s, "GPIO "); @@ -789,14 +789,14 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, grp = &pctrl->community->groups[group]; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); /* Check first that the pad is not locked */ for (i = 0; i < grp->npins; i++) { if (chv_pad_locked(pctrl, grp->pins[i])) { dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n", grp->pins[i]); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return -EBUSY; } } @@ -839,7 +839,7 @@ static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, pin, altfunc->mode, altfunc->invert_oe ? "" : "not "); } - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -853,13 +853,13 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, void __iomem *reg; u32 value; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); if (chv_pad_locked(pctrl, offset)) { value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0)); if (!(value & CHV_PADCTRL0_GPIOEN)) { /* Locked so cannot enable */ - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return -EBUSY; } } else { @@ -899,7 +899,7 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev, chv_writel(value, reg); } - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -913,13 +913,13 @@ static void chv_gpio_disable_free(struct pinctrl_dev *pctldev, void __iomem *reg; u32 value; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg = chv_padreg(pctrl, offset, CHV_PADCTRL0); value = readl(reg) & ~CHV_PADCTRL0_GPIOEN; chv_writel(value, reg); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, @@ -931,7 +931,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, unsigned long flags; u32 ctrl0; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK; if (input) @@ -940,7 +940,7 @@ static int chv_gpio_set_direction(struct pinctrl_dev *pctldev, ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT; chv_writel(ctrl0, reg); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -965,10 +965,10 @@ static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin, u16 arg = 0; u32 term; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT; @@ -1042,7 +1042,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, unsigned long flags; u32 ctrl0, pull; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ctrl0 = readl(reg); switch (param) { @@ -1065,7 +1065,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; break; default: - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return -EINVAL; } @@ -1083,7 +1083,7 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT; break; default: - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return -EINVAL; } @@ -1091,12 +1091,12 @@ static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin, break; default: - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return -EINVAL; } chv_writel(ctrl0, reg); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1172,9 +1172,9 @@ static int chv_gpio_get(struct gpio_chip *chip, unsigned offset) unsigned long flags; u32 ctrl0, cfg; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT; @@ -1192,7 +1192,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) void __iomem *reg; u32 ctrl0; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); reg = chv_padreg(pctrl, pin, CHV_PADCTRL0); ctrl0 = readl(reg); @@ -1204,7 +1204,7 @@ static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value) chv_writel(ctrl0, reg); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) @@ -1214,9 +1214,9 @@ static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset) u32 ctrl0, direction; unsigned long flags; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK; direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT; @@ -1254,14 +1254,14 @@ static void chv_gpio_irq_ack(struct irq_data *d) int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d)); u32 intr_line; - spin_lock(&pctrl->lock); + raw_spin_lock(&pctrl->lock); intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); intr_line &= CHV_PADCTRL0_INTSEL_MASK; intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT; chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT); - spin_unlock(&pctrl->lock); + raw_spin_unlock(&pctrl->lock); } static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) @@ -1272,7 +1272,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) u32 value, intr_line; unsigned long flags; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); intr_line &= CHV_PADCTRL0_INTSEL_MASK; @@ -1285,7 +1285,7 @@ static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask) value |= BIT(intr_line); chv_writel(value, pctrl->regs + CHV_INTMASK); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } static void chv_gpio_irq_mask(struct irq_data *d) @@ -1319,7 +1319,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) unsigned long flags; u32 intsel, value; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); intsel = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0)); intsel &= CHV_PADCTRL0_INTSEL_MASK; intsel >>= CHV_PADCTRL0_INTSEL_SHIFT; @@ -1334,7 +1334,7 @@ static unsigned chv_gpio_irq_startup(struct irq_data *d) irq_set_handler_locked(d, handler); pctrl->intr_lines[intsel] = offset; } - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); } chv_gpio_irq_unmask(d); @@ -1350,7 +1350,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) unsigned long flags; u32 value; - spin_lock_irqsave(&pctrl->lock, flags); + raw_spin_lock_irqsave(&pctrl->lock, flags); /* * Pins which can be used as shared interrupt are configured in @@ -1399,7 +1399,7 @@ static int chv_gpio_irq_type(struct irq_data *d, unsigned type) else if (type & IRQ_TYPE_LEVEL_MASK) irq_set_handler_locked(d, handle_level_irq); - spin_unlock_irqrestore(&pctrl->lock, flags); + raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; } @@ -1511,7 +1511,7 @@ static int chv_pinctrl_probe(struct platform_device *pdev) if (i == ARRAY_SIZE(chv_communities)) return -ENODEV; - spin_lock_init(&pctrl->lock); + raw_spin_lock_init(&pctrl->lock); pctrl->dev = &pdev->dev; #ifdef CONFIG_PM_SLEEP -- GitLab From 41d6bb4c890c8db01248b1bdd512a18e7bd29ca3 Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Mon, 17 Aug 2015 15:35:24 +0300 Subject: [PATCH 4929/7006] gpiolib: add description for gpio irqchip fields in struct gpio_chip Add missed description for GPIO irqchip fields in struct gpio_chip. Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- include/linux/gpio/driver.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 0c7004dab4376..1aed31c5ffba3 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -65,6 +65,17 @@ struct seq_file; * registers. * @irq_not_threaded: flag must be set if @can_sleep is set but the * IRQs don't need to be threaded + * @irqchip: GPIO IRQ chip impl, provided by GPIO driver + * @irqdomain: Interrupt translation domain; responsible for mapping + * between GPIO hwirq number and linux irq number + * @irq_base: first linux IRQ number assigned to GPIO IRQ chip (deprecated) + * @irq_handler: the irq handler to use (often a predefined irq core function) + * for GPIO IRQs, provided by GPIO driver + * @irq_default_type: default IRQ triggering type applied during GPIO driver + * initialization, provided by GPIO driver + * @irq_parent: GPIO IRQ chip parent/bank linux irq number, + * provided by GPIO driver + * @lock_key: per GPIO IRQ chip lockdep class * * A gpio_chip can help platforms abstract various sources of GPIOs so * they can all be accessed through a common programing interface. -- GitLab From 91d33cfedf181cd9e1230d38e466de2f6697d317 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Aug 2015 15:32:16 +0200 Subject: [PATCH 4930/7006] pinctrl: at91: Use generic irq_{request,release}_resources() The at91-specific irq_{request,release}_resources() callbacks are identical to the generic ones, modulo the bug fix in 5b76e79c77264899 ("gpiolib: irqchip: prevent driver unloading if gpio is used as irq only"). Until commit 8b67a1f0ad1f260f ("gpio: don't override irq_*_resources() callbacks"), the buggy at91-specific callbacks were never used, though. Hence drop the at91-specific ones in favor of the generic ones. Signed-off-by: Geert Uytterhoeven Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index e1ab69928bba3..72a3e632c4d9b 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -1488,28 +1488,6 @@ static void gpio_irq_ack(struct irq_data *d) /* the interrupt is already cleared before by reading ISR */ } -static int gpio_irq_request_res(struct irq_data *d) -{ - struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); - unsigned pin = d->hwirq; - int ret; - - ret = gpiochip_lock_as_irq(&at91_gpio->chip, pin); - if (ret) - dev_err(at91_gpio->chip.dev, "unable to lock pind %lu IRQ\n", - d->hwirq); - - return ret; -} - -static void gpio_irq_release_res(struct irq_data *d) -{ - struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d); - unsigned pin = d->hwirq; - - gpiochip_unlock_as_irq(&at91_gpio->chip, pin); -} - #ifdef CONFIG_PM static u32 wakeups[MAX_GPIO_BANKS]; @@ -1585,8 +1563,6 @@ void at91_pinctrl_gpio_resume(void) static struct irq_chip gpio_irqchip = { .name = "GPIO", .irq_ack = gpio_irq_ack, - .irq_request_resources = gpio_irq_request_res, - .irq_release_resources = gpio_irq_release_res, .irq_disable = gpio_irq_mask, .irq_mask = gpio_irq_mask, .irq_unmask = gpio_irq_unmask, -- GitLab From bb8cdf9510d5d2b67126b36747c51d531026215d Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 18 Aug 2015 14:10:52 +0300 Subject: [PATCH 4931/7006] gpio: omap: remove wrong irq_domain_remove usage in probe The bank->chip.irqdomain is uninitialized at the moment when irq_domain_remove() is called, so remove this call. Signed-off-by: Grygorii Strashko Acked-by: Santosh Shilimkar Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 466fe70cf303c..f38b01b5869cd 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1219,7 +1219,6 @@ static int omap_gpio_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); bank->base = devm_ioremap_resource(dev, res); if (IS_ERR(bank->base)) { - irq_domain_remove(bank->chip.irqdomain); return PTR_ERR(bank->base); } -- GitLab From 89d18e3af8b99481589e07f92fd966ceb86eff5d Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 18 Aug 2015 14:10:53 +0300 Subject: [PATCH 4932/7006] gpio: omap: switch to use platform_get_irq Switch OMAP GPIO driver to use platform_get_irq(), because it is not recommened to use platform_get_resource(pdev, IORESOURCE_IRQ, ..) for requesting IRQ resources any more, as they can be not ready yet in case of DT-boot. Signed-off-by: Grygorii Strashko Acked-by: Santosh Shilimkar Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index f38b01b5869cd..03fd111e2d17c 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -1178,13 +1178,16 @@ static int omap_gpio_probe(struct platform_device *pdev) irqc->irq_set_wake = omap_gpio_wake_enable, irqc->name = dev_name(&pdev->dev); - res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (unlikely(!res)) { - dev_err(dev, "Invalid IRQ resource\n"); - return -ENODEV; + bank->irq = platform_get_irq(pdev, 0); + if (bank->irq <= 0) { + if (!bank->irq) + bank->irq = -ENXIO; + if (bank->irq != -EPROBE_DEFER) + dev_err(dev, + "can't get irq resource ret=%d\n", bank->irq); + return bank->irq; } - bank->irq = res->start; bank->dev = dev; bank->chip.dev = dev; bank->chip.owner = THIS_MODULE; -- GitLab From e85ec6c3047be0646e7c572e24869c212b685c7c Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 18 Aug 2015 14:10:54 +0300 Subject: [PATCH 4933/7006] gpio: omap: fix omap2_set_gpio_debounce MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to TRMs: Required input line stable = (the value of the GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) × 31, where the value of the GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME bit field is from 0 to 255. But now omap2_set_gpio_debounce() will calculate debounce time and behave incorrectly in the following cases: 1) requested debounce time is !0 and <32 calculated DEBOUNCETIME = 0x1 == 62 us; expected value of DEBOUNCETIME = 0x0 == 31us 2) requested debounce time is 0 calculated DEBOUNCETIME = 0x1 == 62 us; expected: disable debounce and DEBOUNCETIME = 0x0 3) requested debounce time is >32 and <63 calculated DEBOUNCETIME = 0x0 and debounce will be disabled; expected: enable debounce and DEBOUNCETIME = 0x1 == 62 us Hence, rework omap2_set_gpio_debounce() to fix above cases: 1) introduce local variable "enable" and use it to identify when debounce need to be enabled or disabled. Disable debounce if requested debounce time is 0. 2) use below formula for debounce time calculation: debounce = (DIV_ROUND_UP(debounce, 31) - 1) & 0xFF; Signed-off-by: Grygorii Strashko Acked-by: Santosh Shilimkar Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 03fd111e2d17c..9ed5a675564cc 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -29,6 +29,7 @@ #include #define OFF_MODE 1 +#define OMAP4_GPIO_DEBOUNCINGTIME_MASK 0xFF static LIST_HEAD(omap_gpio_list); @@ -204,8 +205,9 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) * @offset: the gpio number on this @bank * @debounce: debounce time to use * - * OMAP's debounce time is in 31us steps so we need - * to convert and round up to the closest unit. + * OMAP's debounce time is in 31us steps + * = (GPIO_DEBOUNCINGTIME[7:0].DEBOUNCETIME + 1) x 31 + * so we need to convert and round up to the closest unit. */ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, unsigned debounce) @@ -213,16 +215,15 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, void __iomem *reg; u32 val; u32 l; + bool enable = !!debounce; if (!bank->dbck_flag) return; - if (debounce < 32) - debounce = 0x01; - else if (debounce > 7936) - debounce = 0xff; - else - debounce = (debounce / 0x1f) - 1; + if (enable) { + debounce = DIV_ROUND_UP(debounce, 31) - 1; + debounce &= OMAP4_GPIO_DEBOUNCINGTIME_MASK; + } l = BIT(offset); @@ -233,7 +234,7 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, reg = bank->base + bank->regs->debounce_en; val = readl_relaxed(reg); - if (debounce) + if (enable) val |= l; else val &= ~l; -- GitLab From 235f1eb1ab93a8e30a66c38949e6d2aeda136aec Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 18 Aug 2015 14:10:55 +0300 Subject: [PATCH 4934/7006] gpio: omap: protect regs access in omap_gpio_irq_handler The access to HW registers has to be be protected in omap_gpio_irq_handler(), as it may race with code executed on another CPUs. Signed-off-by: Grygorii Strashko Acked-by: Santosh Shilimkar Tested-by: Tony Lindgren Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 9ed5a675564cc..1f02acd577e34 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -718,6 +718,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) int unmasked = 0; struct irq_chip *irqchip = irq_desc_get_chip(desc); struct gpio_chip *chip = irq_desc_get_handler_data(desc); + unsigned long lock_flags; chained_irq_enter(irqchip, desc); @@ -732,6 +733,8 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) u32 isr_saved, level_mask = 0; u32 enabled; + raw_spin_lock_irqsave(&bank->lock, lock_flags); + enabled = omap_get_gpio_irqbank_mask(bank); isr_saved = isr = readl_relaxed(isr_reg) & enabled; @@ -745,6 +748,8 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) omap_clear_gpio_irqbank(bank, isr_saved & ~level_mask); omap_enable_gpio_irqbank(bank, isr_saved & ~level_mask); + raw_spin_unlock_irqrestore(&bank->lock, lock_flags); + /* if there is only edge sensitive GPIO pin interrupts configured, we could unmask GPIO bank interrupt immediately */ if (!level_mask && !unmasked) { @@ -759,6 +764,7 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) bit = __ffs(isr); isr &= ~(BIT(bit)); + raw_spin_lock_irqsave(&bank->lock, lock_flags); /* * Some chips can't respond to both rising and falling * at the same time. If this irq was requested with @@ -769,6 +775,8 @@ static void omap_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) if (bank->toggle_mask & (BIT(bit))) omap_toggle_gpio_edge_triggering(bank, bit); + raw_spin_unlock_irqrestore(&bank->lock, lock_flags); + generic_handle_irq(irq_find_mapping(bank->chip.irqdomain, bit)); } -- GitLab From 5d9452e7c52a106c9efdeb6c72fc73b184a6543f Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Tue, 18 Aug 2015 14:10:56 +0300 Subject: [PATCH 4935/7006] gpio: omap: fix clk_prepare/unprepare usage As per CCF documentation (clk.txt) the clk_prepare/unprepare APIs are not allowed in atomic context. But now OMAP GPIO driver uses them while applying debounce settings and as part of PM runtime irqsafe operations: - omap_gpio_debounce() is holding the lock with IRQs off. + omap2_set_gpio_debounce() + clk_prepare_enable() + clk_prepare() this one might sleep. - pm_runtime_get_sync() is holding the lock with IRQs off + omap_gpio_runtime_suspend() + raw_spin_lock_irqsave() + omap_gpio_dbck_disable() + clk_disable_unprepare() Hence, fix it by moeving dbclk prepare/unprepare in OMAP GPIO omap_gpio_probe/omap_gpio_remove. Also, while here, ensure that debounce functionality is disabled if clk_get() failed, because otherwise kernel will carsh in omap2_set_gpio_debounce(). Reported-by: Sebastian Andrzej Siewior Acked-by: Santosh Shilimkar Tested-by: Tony Lindgren Signed-off-by: Grygorii Strashko Signed-off-by: Linus Walleij --- drivers/gpio/gpio-omap.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c index 1f02acd577e34..2ae0d47e95544 100644 --- a/drivers/gpio/gpio-omap.c +++ b/drivers/gpio/gpio-omap.c @@ -176,7 +176,7 @@ static inline void omap_gpio_rmw(void __iomem *base, u32 reg, u32 mask, bool set static inline void omap_gpio_dbck_enable(struct gpio_bank *bank) { if (bank->dbck_enable_mask && !bank->dbck_enabled) { - clk_prepare_enable(bank->dbck); + clk_enable(bank->dbck); bank->dbck_enabled = true; writel_relaxed(bank->dbck_enable_mask, @@ -194,7 +194,7 @@ static inline void omap_gpio_dbck_disable(struct gpio_bank *bank) */ writel_relaxed(0, bank->base + bank->regs->debounce_en); - clk_disable_unprepare(bank->dbck); + clk_disable(bank->dbck); bank->dbck_enabled = false; } } @@ -227,7 +227,7 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, l = BIT(offset); - clk_prepare_enable(bank->dbck); + clk_enable(bank->dbck); reg = bank->base + bank->regs->debounce; writel_relaxed(debounce, reg); @@ -241,7 +241,7 @@ static void omap2_set_gpio_debounce(struct gpio_bank *bank, unsigned offset, bank->dbck_enable_mask = val; writel_relaxed(val, reg); - clk_disable_unprepare(bank->dbck); + clk_disable(bank->dbck); /* * Enable debounce clock per module. * This call is mandatory because in omap_gpio_request() when @@ -286,7 +286,7 @@ static void omap_clear_gpio_debounce(struct gpio_bank *bank, unsigned offset) bank->context.debounce = 0; writel_relaxed(bank->context.debounce, bank->base + bank->regs->debounce); - clk_disable_unprepare(bank->dbck); + clk_disable(bank->dbck); bank->dbck_enabled = false; } } @@ -1070,10 +1070,6 @@ static void omap_gpio_mod_init(struct gpio_bank *bank) /* Initialize interface clk ungated, module enabled */ if (bank->regs->ctrl) writel_relaxed(0, base + bank->regs->ctrl); - - bank->dbck = clk_get(bank->dev, "dbclk"); - if (IS_ERR(bank->dbck)) - dev_err(bank->dev, "Could not get gpio dbck\n"); } static int omap_gpio_chip_init(struct gpio_bank *bank, struct irq_chip *irqc) @@ -1234,6 +1230,17 @@ static int omap_gpio_probe(struct platform_device *pdev) return PTR_ERR(bank->base); } + if (bank->dbck_flag) { + bank->dbck = devm_clk_get(bank->dev, "dbclk"); + if (IS_ERR(bank->dbck)) { + dev_err(bank->dev, + "Could not get gpio dbck. Disable debounce\n"); + bank->dbck_flag = false; + } else { + clk_prepare(bank->dbck); + } + } + platform_set_drvdata(pdev, bank); pm_runtime_enable(bank->dev); @@ -1265,6 +1272,8 @@ static int omap_gpio_remove(struct platform_device *pdev) list_del(&bank->node); gpiochip_remove(&bank->chip); pm_runtime_disable(bank->dev); + if (bank->dbck_flag) + clk_unprepare(bank->dbck); return 0; } -- GitLab From 503422d95248c1d9698735bb5803b70aa51b18ef Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 19 Aug 2015 13:08:53 +0200 Subject: [PATCH 4936/7006] ath10k: add missing mutex unlock on failpath Kernel would complain about leaving a held lock after going back to userspace and would subsequently deadlock. Fixes: e04cafbc38c7 ("ath10k: fix peer limit enforcement") Reported-by: Dan Carpenter Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/mac.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c index 9bca378208487..64674c955d447 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c @@ -4144,7 +4144,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw, if (ar->num_peers >= ar->max_num_peers) { ath10k_warn(ar, "refusing vdev creation due to insufficient peer entry resources in firmware\n"); - return -ENOBUFS; + ret = -ENOBUFS; + goto err; } if (ar->free_vdev_map == 0) { -- GitLab From 5e55e3cbd1042cffa6249f22c10585e63f8a29bf Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Wed, 19 Aug 2015 13:10:43 +0200 Subject: [PATCH 4937/7006] ath10k: fix dma_mapping_error() handling The function returns 1 when DMA mapping fails. The driver would return bogus values and could possibly confuse itself if DMA failed. Fixes: 767d34fc67af ("ath10k: remove DMA mapping wrappers") Reported-by: Dan Carpenter Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/htc.c | 4 +++- drivers/net/wireless/ath/ath10k/htt_tx.c | 8 ++++++-- drivers/net/wireless/ath/ath10k/pci.c | 8 ++++++-- drivers/net/wireless/ath/ath10k/wmi.c | 1 + 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c index 85bfa2acb801b..32d9ff1b19dcd 100644 --- a/drivers/net/wireless/ath/ath10k/htc.c +++ b/drivers/net/wireless/ath/ath10k/htc.c @@ -145,8 +145,10 @@ int ath10k_htc_send(struct ath10k_htc *htc, skb_cb->eid = eid; skb_cb->paddr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); ret = dma_mapping_error(dev, skb_cb->paddr); - if (ret) + if (ret) { + ret = -EIO; goto err_credits; + } sg_item.transfer_id = ep->eid; sg_item.transfer_context = skb; diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c index 704bb5e071938..43aa5e2d1b87d 100644 --- a/drivers/net/wireless/ath/ath10k/htt_tx.c +++ b/drivers/net/wireless/ath/ath10k/htt_tx.c @@ -442,8 +442,10 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); - if (res) + if (res) { + res = -EIO; goto err_free_txdesc; + } skb_put(txdesc, len); cmd = (struct htt_cmd *)txdesc->data; @@ -533,8 +535,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu) skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len, DMA_TO_DEVICE); res = dma_mapping_error(dev, skb_cb->paddr); - if (res) + if (res) { + res = -EIO; goto err_free_txbuf; + } switch (skb_cb->txmode) { case ATH10K_HW_TXRX_RAW: diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index f00b251ec9ce9..826220f795c70 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -1667,8 +1667,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, req_paddr = dma_map_single(ar->dev, treq, req_len, DMA_TO_DEVICE); ret = dma_mapping_error(ar->dev, req_paddr); - if (ret) + if (ret) { + ret = -EIO; goto err_dma; + } if (resp && resp_len) { tresp = kzalloc(*resp_len, GFP_KERNEL); @@ -1680,8 +1682,10 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, resp_paddr = dma_map_single(ar->dev, tresp, *resp_len, DMA_FROM_DEVICE); ret = dma_mapping_error(ar->dev, resp_paddr); - if (ret) + if (ret) { + ret = EIO; goto err_req; + } xfer.wait_for_resp = true; xfer.resp_len = 0; diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 42c0aba04fb24..6ac016dc28f86 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3238,6 +3238,7 @@ void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb) ath10k_warn(ar, "failed to map beacon: %d\n", ret); dev_kfree_skb_any(bcn); + ret = -EIO; goto skip; } -- GitLab From 4535edbd4214ce21328655434c0b75da404e29b7 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Thu, 20 Aug 2015 10:29:05 +0530 Subject: [PATCH 4938/7006] ath10k: add spectral scan support for 10.4 fw To enable/configure spectral scan parameters in 10.4 firmware, existing wmi spectral related functions can be reused. Link those functions in 10.4 wmi ops table. In addition, adjust bin size (only when size is 68 bytes) before reporting bin samples to user space. The background for this adjustment is that qca99x0 reports bin size as 68 bytes (64 bytes + 4 bytes) in report mode 2. First 64 bytes carries in-band tones (-32 to +31) and last 4 byte carries band edge detection data (+32) mainly used in radar detection purpose. Additional last 4 bytes are stripped to make bin size valid one. This bin size adjustment will happen only for qca99x0, all other chipsets will report proper bin sizes (64/128) without extra 4 bytes being added at the end. The changes are validated in qca99x0 using 10.4 firmware. Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/spectral.c | 9 +++++++++ drivers/net/wireless/ath/ath10k/wmi.c | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c index e4219b1bbdceb..4671cfbcd8f7a 100644 --- a/drivers/net/wireless/ath/ath10k/spectral.c +++ b/drivers/net/wireless/ath/ath10k/spectral.c @@ -73,6 +73,15 @@ int ath10k_spectral_process_fft(struct ath10k *ar, if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS) return -EINVAL; + /* qca99x0 reports bin size as 68 bytes (64 bytes + 4 bytes) in + * report mode 2. First 64 bytes carries inband tones (-32 to +31) + * and last 4 byte carries band edge detection data (+32) mainly + * used in radar detection purpose. Strip last 4 byte to make bin + * size is valid one. + */ + if (bin_len == 68) + bin_len -= 4; + reg0 = __le32_to_cpu(fftr->reg0); reg1 = __le32_to_cpu(fftr->reg1); diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 6ac016dc28f86..7f8fa636b95a6 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -6582,6 +6582,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_vdev_down = ath10k_wmi_op_gen_vdev_down, .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param, .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key, + .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf, + .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable, .gen_peer_create = ath10k_wmi_op_gen_peer_create, .gen_peer_delete = ath10k_wmi_op_gen_peer_delete, .gen_peer_flush = ath10k_wmi_op_gen_peer_flush, -- GitLab From 36582e5d4daeccf68a8a3cef9bc37b60fb7d45b9 Mon Sep 17 00:00:00 2001 From: Michal Kazior Date: Thu, 13 Aug 2015 14:32:26 +0200 Subject: [PATCH 4939/7006] ath10k: add qca6164 support This adds additional 0x0041 PCI Device ID definition to ath10k for QCA6164 which is a 1 spatial stream sibling of the QCA6174 (which is 2 spatial stream chip). The QCA6164 needs a dedicated board.bin file which is different than the one used for QCA6174. If the board.bin is wrong the device will crash early while trying to boot firmware. The register dump will look like this: ath10k_pci 0000:02:00.0: firmware register dump: ath10k_pci 0000:02:00.0: [00]: 0x05010000 0x000015B3 0x000A012D 0x00955B31 ... Note the value 0x000A012D. Special credit goes to Alan Liu for providing support help which enabled me to come up with this patch. Signed-off-by: Michal Kazior Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/core.c | 11 +++++++++++ drivers/net/wireless/ath/ath10k/core.h | 1 + drivers/net/wireless/ath/ath10k/pci.c | 13 +++++++++++++ 3 files changed, 25 insertions(+) diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c index 7e378c2fa414d..b87b98617073b 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c @@ -236,6 +236,17 @@ static int ath10k_init_configure_target(struct ath10k *ar) return ret; } + /* Some devices have a special sanity check that verifies the PCI + * Device ID is written to this host interest var. It is known to be + * required to boot QCA6164. + */ + ret = ath10k_bmi_write32(ar, hi_hci_uart_pwr_mgmt_params_ext, + ar->dev_id); + if (ret) { + ath10k_err(ar, "failed to set pwr_mgmt_params: %d\n", ret); + return ret; + } + return 0; } diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h index 862f6d0fac57d..12542144fe125 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -554,6 +554,7 @@ struct ath10k { u8 mac_addr[ETH_ALEN]; enum ath10k_hw_rev hw_rev; + u16 dev_id; u32 chip_id; u32 target_version; u8 fw_version_major; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 826220f795c70..1046ab65b9ab3 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -58,11 +58,13 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)"); #define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3 #define QCA988X_2_0_DEVICE_ID (0x003c) +#define QCA6164_2_1_DEVICE_ID (0x0041) #define QCA6174_2_1_DEVICE_ID (0x003e) #define QCA99X0_2_0_DEVICE_ID (0x0040) static const struct pci_device_id ath10k_pci_id_table[] = { { PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */ + { PCI_VDEVICE(ATHEROS, QCA6164_2_1_DEVICE_ID) }, /* PCI-E QCA6164 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */ { PCI_VDEVICE(ATHEROS, QCA99X0_2_0_DEVICE_ID) }, /* PCI-E QCA99X0 V2 */ {0} @@ -74,11 +76,19 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = { * because of that. */ { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV }, + + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, + { QCA6164_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV }, { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV }, + { QCA99X0_2_0_DEVICE_ID, QCA99X0_HW_2_0_CHIP_ID_REV }, }; @@ -1814,6 +1824,7 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar) case QCA988X_2_0_DEVICE_ID: case QCA99X0_2_0_DEVICE_ID: return 1; + case QCA6164_2_1_DEVICE_ID: case QCA6174_2_1_DEVICE_ID: switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) { case QCA6174_HW_1_0_CHIP_ID_REV: @@ -2902,6 +2913,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, case QCA988X_2_0_DEVICE_ID: hw_rev = ATH10K_HW_QCA988X; break; + case QCA6164_2_1_DEVICE_ID: case QCA6174_2_1_DEVICE_ID: hw_rev = ATH10K_HW_QCA6174; break; @@ -2926,6 +2938,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev, ar_pci->pdev = pdev; ar_pci->dev = &pdev->dev; ar_pci->ar = ar; + ar->dev_id = pci_dev->device; if (pdev->subsystem_vendor || pdev->subsystem_device) scnprintf(ar->spec_board_id, sizeof(ar->spec_board_id), -- GitLab From a9dd941d840714b96b0a60451f6a3aa3a9be8fc6 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Thu, 13 Aug 2015 17:16:10 -0400 Subject: [PATCH 4940/7006] kbuild: avoid listing /lib/modules in kernel spec file This causes conflicts when using multiple kernels built with this mechanism. Reviewed-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Michal Marek --- scripts/package/mkspec | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/package/mkspec b/scripts/package/mkspec index 89f9669d4f007..71004daefe31b 100755 --- a/scripts/package/mkspec +++ b/scripts/package/mkspec @@ -140,7 +140,6 @@ echo "fi" echo "" echo "%files" echo '%defattr (-, root, root)' -echo "%dir /lib/modules" echo "/lib/modules/$KERNELRELEASE" echo "%exclude /lib/modules/$KERNELRELEASE/build" echo "%exclude /lib/modules/$KERNELRELEASE/source" -- GitLab From ee92a2099f79d47e1d6d4857ab308f5b15a00549 Mon Sep 17 00:00:00 2001 From: Raja Mani Date: Fri, 21 Aug 2015 18:42:36 +0530 Subject: [PATCH 4941/7006] ath10k: fix compilation warnings in wmi phyerr pull function Below compilation warnings are observed in gcc version 4.8.2. Even though it's not seen in bit older gcc versions (for ex, 4.7.3), It's good to fix it by changing format specifier from %d to %zd in wmi pull phyerr functions. wmi.c: In function 'ath10k_wmi_op_pull_phyerr_ev': wmi.c:3567:8: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=] left_len, sizeof(*phyerr)); ^ wmi.c: In function 'ath10k_wmi_10_4_op_pull_phyerr_ev': wmi.c:3612:8: warning: format '%d' expects argument of type 'int', but argument 4 has type 'long unsigned int' [-Wformat=] left_len, sizeof(*phyerr)); ^ Fixes: 991adf71a6cd ("ath10k: refactor phyerr event handlers") Fixes: 2b0a2e0d7c2f ("ath10k: handle 10.4 firmware phyerr event") Signed-off-by: Raja Mani Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index 7f8fa636b95a6..ce01107ef37aa 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -3564,7 +3564,7 @@ int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, int i; if (left_len < sizeof(*phyerr)) { - ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%d)\n", + ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%zd)\n", left_len, sizeof(*phyerr)); return -EINVAL; } @@ -3609,7 +3609,7 @@ static int ath10k_wmi_10_4_op_pull_phyerr_ev(struct ath10k *ar, int i; if (left_len < sizeof(*phyerr)) { - ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%d)\n", + ath10k_warn(ar, "wrong phyerr event head len %d (need: >=%zd)\n", left_len, sizeof(*phyerr)); return -EINVAL; } -- GitLab From f8ce20005d1694584448cd544be5fb32416a277c Mon Sep 17 00:00:00 2001 From: Xing Zheng Date: Tue, 25 Aug 2015 15:52:42 +0800 Subject: [PATCH 4942/7006] ASoC: rockchip: fix a misjudgement by return Being careless, judge the return value of snd_soc_card_jack_new is opposite, so it should be fixed. Signed-off-by: Xing Zheng Reviewed-by: Dylan Reid Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_rt5645.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 3c6bb1ea06ece..adfe98c5d26fb 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -118,7 +118,7 @@ static int rk_init(struct snd_soc_pcm_runtime *runtime) SND_JACK_BTN_0 | SND_JACK_BTN_1 | SND_JACK_BTN_2 | SND_JACK_BTN_3, &headset_jack, NULL, 0); - if (!ret) { + if (ret) { dev_err(card->dev, "New Headset Jack failed! (%d)\n", ret); return ret; } -- GitLab From 78de5d5220322456f2568de23bc2e97bba3957e3 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Tue, 18 Aug 2015 09:55:44 -0400 Subject: [PATCH 4943/7006] gpio: max732x: Fix error handling in probe() This fixes error handling in the function max732x_probe by checking if the calls to the function max732x_readb fail by returning a error code. Signed-off-by: Nicholas Krause Signed-off-by: Linus Walleij --- drivers/gpio/gpio-max732x.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c index 7d3c90e9da71a..8c5252c6c3277 100644 --- a/drivers/gpio/gpio-max732x.c +++ b/drivers/gpio/gpio-max732x.c @@ -685,9 +685,14 @@ static int max732x_probe(struct i2c_client *client, mutex_init(&chip->lock); - max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); - if (nr_port > 8) - max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); + ret = max732x_readb(chip, is_group_a(chip, 0), &chip->reg_out[0]); + if (ret) + goto out_failed; + if (nr_port > 8) { + ret = max732x_readb(chip, is_group_a(chip, 8), &chip->reg_out[1]); + if (ret) + goto out_failed; + } ret = gpiochip_add(&chip->gpio_chip); if (ret) -- GitLab From 580a7ee93317b901358f497c2de34f7a66066963 Mon Sep 17 00:00:00 2001 From: Shinobu Uehara Date: Wed, 19 Aug 2015 01:26:55 +0300 Subject: [PATCH 4944/7006] pinctrl: sh-pfc: r8a7794: add USB pin groups Add USB0/1 pin groups to R8A7794 PFC driver. Signed-off-by: Shinobu Uehara [Sergei: rebased, renamed, added changelog.] Signed-off-by: Sergei Shtylyov Acked-by: Laurent Pinchart Signed-off-by: Linus Walleij --- drivers/pinctrl/sh-pfc/pfc-r8a7794.c | 30 ++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c index bfdcac4b3bc4a..5248685dbb4e5 100644 --- a/drivers/pinctrl/sh-pfc/pfc-r8a7794.c +++ b/drivers/pinctrl/sh-pfc/pfc-r8a7794.c @@ -2770,6 +2770,24 @@ static const unsigned int sdhi2_wp_pins[] = { static const unsigned int sdhi2_wp_mux[] = { SD2_WP_MARK, }; +/* - USB0 ------------------------------------------------------------------- */ +static const unsigned int usb0_pins[] = { + RCAR_GP_PIN(5, 24), /* PWEN */ + RCAR_GP_PIN(5, 25), /* OVC */ +}; +static const unsigned int usb0_mux[] = { + USB0_PWEN_MARK, + USB0_OVC_MARK, +}; +/* - USB1 ------------------------------------------------------------------- */ +static const unsigned int usb1_pins[] = { + RCAR_GP_PIN(5, 26), /* PWEN */ + RCAR_GP_PIN(5, 27), /* OVC */ +}; +static const unsigned int usb1_mux[] = { + USB1_PWEN_MARK, + USB1_OVC_MARK, +}; static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(eth_link), @@ -2945,6 +2963,8 @@ static const struct sh_pfc_pin_group pinmux_groups[] = { SH_PFC_PIN_GROUP(sdhi2_ctrl), SH_PFC_PIN_GROUP(sdhi2_cd), SH_PFC_PIN_GROUP(sdhi2_wp), + SH_PFC_PIN_GROUP(usb0), + SH_PFC_PIN_GROUP(usb1), }; static const char * const eth_groups[] = { @@ -3219,6 +3239,14 @@ static const char * const sdhi2_groups[] = { "sdhi2_wp", }; +static const char * const usb0_groups[] = { + "usb0", +}; + +static const char * const usb1_groups[] = { + "usb1", +}; + static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(eth), SH_PFC_FUNCTION(hscif0), @@ -3253,6 +3281,8 @@ static const struct sh_pfc_function pinmux_functions[] = { SH_PFC_FUNCTION(sdhi0), SH_PFC_FUNCTION(sdhi1), SH_PFC_FUNCTION(sdhi2), + SH_PFC_FUNCTION(usb0), + SH_PFC_FUNCTION(usb1), }; static const struct pinmux_cfg_reg pinmux_config_regs[] = { -- GitLab From 0137d5ff8488f1d17a83508578976d3a67ba8e81 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 26 Aug 2015 19:44:10 +0800 Subject: [PATCH 4945/7006] ASoC: rockchip: fix platform_no_drv_owner.cocci warnings sound/soc/rockchip/rockchip_max98090.c:225:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_max98090.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index acace20d4127d..562e7ea3c55f7 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c @@ -222,7 +222,6 @@ static struct platform_driver snd_rk_mc_driver = { .probe = snd_rk_mc_probe, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = rockchip_max98090_of_match, }, -- GitLab From 1c0beb27443c98257a5bced2978f2556f2ae1709 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Wed, 26 Aug 2015 19:48:13 +0800 Subject: [PATCH 4946/7006] ASoC: rockchip: fix platform_no_drv_owner.cocci warnings sound/soc/rockchip/rockchip_rt5645.c:214:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/rockchip/rockchip_rt5645.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index adfe98c5d26fb..274b9b3dd9f67 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c @@ -211,7 +211,6 @@ static struct platform_driver snd_rk_mc_driver = { .probe = snd_rk_mc_probe, .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &snd_soc_pm_ops, .of_match_table = rockchip_rt5645_of_match, }, -- GitLab From b25cf30a013195a69c167209d13c19b90a7450f2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Aug 2015 14:21:14 +0200 Subject: [PATCH 4947/7006] ALSA: hda - Remove superfluous pcm NULL check The variable pcm can be never NULL since it was rewritten with list_for_each_entry(). Suggested-by: Markus Osterhoff Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2c021911f88a9..37f43a1b34ef1 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3102,8 +3102,7 @@ static int add_std_chmaps(struct hda_codec *codec) struct snd_pcm_chmap *chmap; const struct snd_pcm_chmap_elem *elem; - if (!pcm || !pcm->pcm || pcm->own_chmap || - !hinfo->substreams) + if (!pcm->pcm || pcm->own_chmap || !hinfo->substreams) continue; elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; err = snd_pcm_add_chmap_ctls(pcm->pcm, str, elem, -- GitLab From d48c2c02645392483f2b88b050d21ce1db6997b3 Mon Sep 17 00:00:00 2001 From: Hongzhou Yang Date: Tue, 25 Aug 2015 17:32:45 -0700 Subject: [PATCH 4948/7006] pinctrl: mediatek: Fix multiple registration issue. Since our common driver need support main chip and PMU at the same time, that means it will register two pinctrl device, and the pinctrl_desc structure should be used two times. But pinctrl_desc use global static definition, then the latest registered pinctrl device will overwrite the old one's, all members in pinctrl_desc will set to the new one's, such as name, pins and pins numbers, etc. This is a bug. Move pinctrl_desc into mtk_pinctrl, assign new value for each pinctrl device to fix it. Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Hongzhou Yang Reviewed-by: Axel Lin Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 21 +++++++++---------- drivers/pinctrl/mediatek/pinctrl-mtk-common.h | 1 + 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index 23f2de07f598b..f6cdeee6e63bd 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -1202,12 +1202,6 @@ static int mtk_pctrl_build_state(struct platform_device *pdev) return 0; } -static struct pinctrl_desc mtk_pctrl_desc = { - .confops = &mtk_pconf_ops, - .pctlops = &mtk_pctrl_ops, - .pmxops = &mtk_pmx_ops, -}; - int mtk_pctrl_init(struct platform_device *pdev, const struct mtk_pinctrl_devdata *data, struct regmap *regmap) @@ -1265,12 +1259,17 @@ int mtk_pctrl_init(struct platform_device *pdev, for (i = 0; i < pctl->devdata->npins; i++) pins[i] = pctl->devdata->pins[i].pin; - mtk_pctrl_desc.name = dev_name(&pdev->dev); - mtk_pctrl_desc.owner = THIS_MODULE; - mtk_pctrl_desc.pins = pins; - mtk_pctrl_desc.npins = pctl->devdata->npins; + + pctl->pctl_desc.name = dev_name(&pdev->dev); + pctl->pctl_desc.owner = THIS_MODULE; + pctl->pctl_desc.pins = pins; + pctl->pctl_desc.npins = pctl->devdata->npins; + pctl->pctl_desc.confops = &mtk_pconf_ops; + pctl->pctl_desc.pctlops = &mtk_pctrl_ops; + pctl->pctl_desc.pmxops = &mtk_pmx_ops; pctl->dev = &pdev->dev; - pctl->pctl_dev = pinctrl_register(&mtk_pctrl_desc, &pdev->dev, pctl); + + pctl->pctl_dev = pinctrl_register(&pctl->pctl_desc, &pdev->dev, pctl); if (IS_ERR(pctl->pctl_dev)) { dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); return PTR_ERR(pctl->pctl_dev); diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h index 30213e514c2f1..c532c23c70b47 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h @@ -256,6 +256,7 @@ struct mtk_pinctrl_devdata { struct mtk_pinctrl { struct regmap *regmap1; struct regmap *regmap2; + struct pinctrl_desc pctl_desc; struct device *dev; struct gpio_chip *chip; struct mtk_pinctrl_group *groups; -- GitLab From 58a5e1b64bb0a9ef7747840b79d290e1ad4eed44 Mon Sep 17 00:00:00 2001 From: Maoguang Meng Date: Fri, 14 Aug 2015 16:38:06 +0800 Subject: [PATCH 4949/7006] pinctrl: mediatek: Implement wake handler and suspend resume This patch implement irq_set_wake to get who is wakeup source and setup on suspend resume. Signed-off-by: Maoguang Meng Reviewed-by: Daniel Kurtz Acked-by: Yingjoe Chen Acked-by: Hongzhou Yang Signed-off-by: Linus Walleij --- drivers/pinctrl/mediatek/pinctrl-mt8173.c | 1 + drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 91 ++++++++++++++++++- drivers/pinctrl/mediatek/pinctrl-mtk-common.h | 4 + 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/mediatek/pinctrl-mt8173.c b/drivers/pinctrl/mediatek/pinctrl-mt8173.c index d0c811d5f07b7..ad271840d8652 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mt8173.c +++ b/drivers/pinctrl/mediatek/pinctrl-mt8173.c @@ -385,6 +385,7 @@ static struct platform_driver mtk_pinctrl_driver = { .driver = { .name = "mediatek-mt8173-pinctrl", .of_match_table = mt8173_pctrl_match, + .pm = &mtk_eint_pm_ops, }, }; diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c index f6cdeee6e63bd..7726c6caaf835 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "../core.h" @@ -1062,6 +1063,77 @@ static int mtk_eint_set_type(struct irq_data *d, return 0; } +static int mtk_eint_irq_set_wake(struct irq_data *d, unsigned int on) +{ + struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d); + int shift = d->hwirq & 0x1f; + int reg = d->hwirq >> 5; + + if (on) + pctl->wake_mask[reg] |= BIT(shift); + else + pctl->wake_mask[reg] &= ~BIT(shift); + + return 0; +} + +static void mtk_eint_chip_write_mask(const struct mtk_eint_offsets *chip, + void __iomem *eint_reg_base, u32 *buf) +{ + int port; + void __iomem *reg; + + for (port = 0; port < chip->ports; port++) { + reg = eint_reg_base + (port << 2); + writel_relaxed(~buf[port], reg + chip->mask_set); + writel_relaxed(buf[port], reg + chip->mask_clr); + } +} + +static void mtk_eint_chip_read_mask(const struct mtk_eint_offsets *chip, + void __iomem *eint_reg_base, u32 *buf) +{ + int port; + void __iomem *reg; + + for (port = 0; port < chip->ports; port++) { + reg = eint_reg_base + chip->mask + (port << 2); + buf[port] = ~readl_relaxed(reg); + /* Mask is 0 when irq is enabled, and 1 when disabled. */ + } +} + +static int mtk_eint_suspend(struct device *device) +{ + void __iomem *reg; + struct mtk_pinctrl *pctl = dev_get_drvdata(device); + const struct mtk_eint_offsets *eint_offsets = + &pctl->devdata->eint_offsets; + + reg = pctl->eint_reg_base; + mtk_eint_chip_read_mask(eint_offsets, reg, pctl->cur_mask); + mtk_eint_chip_write_mask(eint_offsets, reg, pctl->wake_mask); + + return 0; +} + +static int mtk_eint_resume(struct device *device) +{ + struct mtk_pinctrl *pctl = dev_get_drvdata(device); + const struct mtk_eint_offsets *eint_offsets = + &pctl->devdata->eint_offsets; + + mtk_eint_chip_write_mask(eint_offsets, + pctl->eint_reg_base, pctl->cur_mask); + + return 0; +} + +const struct dev_pm_ops mtk_eint_pm_ops = { + .suspend = mtk_eint_suspend, + .resume = mtk_eint_resume, +}; + static void mtk_eint_ack(struct irq_data *d) { struct mtk_pinctrl *pctl = irq_data_get_irq_chip_data(d); @@ -1076,10 +1148,12 @@ static void mtk_eint_ack(struct irq_data *d) static struct irq_chip mtk_pinctrl_irq_chip = { .name = "mt-eint", + .irq_disable = mtk_eint_mask, .irq_mask = mtk_eint_mask, .irq_unmask = mtk_eint_unmask, .irq_ack = mtk_eint_ack, .irq_set_type = mtk_eint_set_type, + .irq_set_wake = mtk_eint_irq_set_wake, .irq_request_resources = mtk_pinctrl_irq_request_resources, .irq_release_resources = mtk_pinctrl_irq_release_resources, }; @@ -1211,7 +1285,7 @@ int mtk_pctrl_init(struct platform_device *pdev, struct device_node *np = pdev->dev.of_node, *node; struct property *prop; struct resource *res; - int i, ret, irq; + int i, ret, irq, ports_buf; pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); if (!pctl) @@ -1318,6 +1392,21 @@ int mtk_pctrl_init(struct platform_device *pdev, goto chip_error; } + ports_buf = pctl->devdata->eint_offsets.ports; + pctl->wake_mask = devm_kcalloc(&pdev->dev, ports_buf, + sizeof(*pctl->wake_mask), GFP_KERNEL); + if (!pctl->wake_mask) { + ret = -ENOMEM; + goto chip_error; + } + + pctl->cur_mask = devm_kcalloc(&pdev->dev, ports_buf, + sizeof(*pctl->cur_mask), GFP_KERNEL); + if (!pctl->cur_mask) { + ret = -ENOMEM; + goto chip_error; + } + pctl->eint_dual_edges = devm_kcalloc(&pdev->dev, pctl->devdata->ap_num, sizeof(int), GFP_KERNEL); if (!pctl->eint_dual_edges) { diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h index c532c23c70b47..55a5343389315 100644 --- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.h +++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.h @@ -267,6 +267,8 @@ struct mtk_pinctrl { void __iomem *eint_reg_base; struct irq_domain *domain; int *eint_dual_edges; + u32 *wake_mask; + u32 *cur_mask; }; int mtk_pctrl_init(struct platform_device *pdev, @@ -282,4 +284,6 @@ int mtk_pconf_spec_set_ies_smt_range(struct regmap *regmap, const struct mtk_pin_ies_smt_set *ies_smt_infos, unsigned int info_num, unsigned int pin, unsigned char align, int value); +extern const struct dev_pm_ops mtk_eint_pm_ops; + #endif /* __PINCTRL_MTK_COMMON_H */ -- GitLab From fd96811576e646011489e38b0594dc017db21971 Mon Sep 17 00:00:00 2001 From: Stefan Agner Date: Fri, 21 Aug 2015 15:56:42 -0700 Subject: [PATCH 4950/7006] gpio: vf610: handle level IRQ's properly The GPIO IRQ controller is able to generate level triggered interrupts, however, these were handled by handle_simple_irq so far which did not take care of IRQ masking. This lead to "nobody cared (try booting with the "irqpoll" option)" stack traces. Use the generic interrupt handlers depending on the IRQ type. Signed-off-by: Stefan Agner Signed-off-by: Linus Walleij --- drivers/gpio/gpio-vf610.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c index fa344388f4daa..3d5714d4f405d 100644 --- a/drivers/gpio/gpio-vf610.c +++ b/drivers/gpio/gpio-vf610.c @@ -60,6 +60,8 @@ struct vf610_gpio_port { #define PORT_INT_EITHER_EDGE 0xb #define PORT_INT_LOGIC_ONE 0xc +static struct irq_chip vf610_gpio_irq_chip; + static const struct of_device_id vf610_gpio_dt_ids[] = { { .compatible = "fsl,vf610-gpio" }, { /* sentinel */ } @@ -173,6 +175,11 @@ static int vf610_gpio_irq_set_type(struct irq_data *d, u32 type) port->irqc[d->hwirq] = irqc; + if (type & IRQ_TYPE_LEVEL_MASK) + __irq_set_handler_locked(d->irq, handle_level_irq); + else + __irq_set_handler_locked(d->irq, handle_edge_irq); + return 0; } @@ -263,7 +270,7 @@ static int vf610_gpio_probe(struct platform_device *pdev) vf610_gpio_writel(~0, port->base + PORT_ISFR); ret = gpiochip_irqchip_add(gc, &vf610_gpio_irq_chip, 0, - handle_simple_irq, IRQ_TYPE_NONE); + handle_edge_irq, IRQ_TYPE_NONE); if (ret) { dev_err(dev, "failed to add irqchip\n"); gpiochip_remove(gc); -- GitLab From a0c81ce08791d3892aacba341efa29fadf30beda Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:22 +0200 Subject: [PATCH 4951/7006] gpio: xlp: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Linus Walleij --- drivers/gpio/gpio-xlp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-xlp.c b/drivers/gpio/gpio-xlp.c index 9bdab7203d651..e02499a15e722 100644 --- a/drivers/gpio/gpio-xlp.c +++ b/drivers/gpio/gpio-xlp.c @@ -387,7 +387,7 @@ static int xlp_gpio_probe(struct platform_device *pdev) irq_base = irq_alloc_descs(-1, XLP_GPIO_IRQ_BASE, gc->ngpio, 0); if (irq_base < 0) { dev_err(&pdev->dev, "Failed to allocate IRQ numbers\n"); - return err; + return -ENODEV; } err = gpiochip_add(gc); -- GitLab From 7653716bf989cf8be04c7bedcad6bb201b1df108 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Thu, 9 Jul 2015 10:51:36 +0200 Subject: [PATCH 4952/7006] MIPS: ath79: irq: IRQCHIP_DECLARE moved to linux/irqchip.h Remove the ugly cross tree include now that IRQCHIP_DECLARE moved to linux/irqchip.h. Signed-off-by: Alban Bedel Cc: linux-mips@linux-mips.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: Qais Yousef Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10633/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/irq.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index afb009603f7fa..2021be20d9d94 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -17,7 +17,6 @@ #include #include #include -#include "../../../drivers/irqchip/irqchip.h" #include #include -- GitLab From 90b8baa2c1acb8c270aa31e75d00b44193fb306f Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:35 +0100 Subject: [PATCH 4953/7006] MIPS: Add MIPS I6400 PRid and cputype identifiers Add a Processor ID and CPU type for the MIPS I6400 core. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10634/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index e46e40602af3c..5fa7b8ba48a90 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -120,6 +120,7 @@ #define PRID_IMP_PROAPTIV_MP 0xa300 #define PRID_IMP_M5150 0xa700 #define PRID_IMP_P5600 0xa800 +#define PRID_IMP_I6400 0xa900 /* * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE @@ -307,6 +308,7 @@ enum cpu_type_enum { CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350, CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC, CPU_M14KEC, CPU_INTERAPTIV, CPU_P5600, CPU_PROAPTIV, CPU_1074K, CPU_M5150, + CPU_I6400, /* * MIPS64 class processors -- GitLab From 4e88a8621301b992e8e3422e08bfb604772f3338 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:36 +0100 Subject: [PATCH 4954/7006] MIPS: Add cases for CPU_I6400 Add a CPU_I6400 case to various switch statements, doing the same thing as for CPU_P5600. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10635/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-type.h | 4 ++++ arch/mips/kernel/idle.c | 1 + arch/mips/kernel/perf_event_mipsxx.c | 6 ++++++ arch/mips/kernel/pm-cps.c | 2 ++ arch/mips/kernel/spram.c | 1 + arch/mips/kernel/traps.c | 1 + arch/mips/mm/c-r4k.c | 1 + arch/mips/oprofile/common.c | 1 + arch/mips/oprofile/op_model_mipsxx.c | 4 ++++ 9 files changed, 21 insertions(+) diff --git a/arch/mips/include/asm/cpu-type.h b/arch/mips/include/asm/cpu-type.h index d41e8e2848253..abee2bfd10dc1 100644 --- a/arch/mips/include/asm/cpu-type.h +++ b/arch/mips/include/asm/cpu-type.h @@ -77,6 +77,10 @@ static inline int __pure __get_cpu_type(const int cpu_type) */ #endif +#ifdef CONFIG_SYS_HAS_CPU_MIPS64_R6 + case CPU_I6400: +#endif + #ifdef CONFIG_SYS_HAS_CPU_R3000 case CPU_R2000: case CPU_R3000: diff --git a/arch/mips/kernel/idle.c b/arch/mips/kernel/idle.c index e4f62b7875d24..ab1478d5a4db1 100644 --- a/arch/mips/kernel/idle.c +++ b/arch/mips/kernel/idle.c @@ -196,6 +196,7 @@ void __init check_wait(void) case CPU_INTERAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: + case CPU_I6400: cpu_wait = r4k_wait; if (read_c0_config7() & MIPS_CONF7_WII) cpu_wait = r4k_wait_irqoff; diff --git a/arch/mips/kernel/perf_event_mipsxx.c b/arch/mips/kernel/perf_event_mipsxx.c index cc1b6fadf0898..d7b8dd43147a4 100644 --- a/arch/mips/kernel/perf_event_mipsxx.c +++ b/arch/mips/kernel/perf_event_mipsxx.c @@ -1556,6 +1556,7 @@ static const struct mips_perf_event *mipsxx_pmu_map_raw_event(u64 config) #endif break; case CPU_P5600: + case CPU_I6400: /* 8-bit event numbers */ raw_id = config & 0x1ff; base_id = raw_id & 0xff; @@ -1717,6 +1718,11 @@ init_hw_perf_events(void) mipspmu.general_event_map = &mipsxxcore_event_map2; mipspmu.cache_event_map = &mipsxxcore_cache_map2; break; + case CPU_I6400: + mipspmu.name = "mips/I6400"; + mipspmu.general_event_map = &mipsxxcore_event_map2; + mipspmu.cache_event_map = &mipsxxcore_cache_map2; + break; case CPU_1004K: mipspmu.name = "mips/1004K"; mipspmu.general_event_map = &mipsxxcore_event_map; diff --git a/arch/mips/kernel/pm-cps.c b/arch/mips/kernel/pm-cps.c index 06147179a175b..f63a289977cc5 100644 --- a/arch/mips/kernel/pm-cps.c +++ b/arch/mips/kernel/pm-cps.c @@ -267,6 +267,7 @@ static int __init cps_gen_flush_fsb(u32 **pp, struct uasm_label **pl, /* CPUs which do not require the workaround */ case CPU_P5600: + case CPU_I6400: return 0; default: @@ -671,6 +672,7 @@ static int __init cps_pm_init(void) case CPU_PROAPTIV: case CPU_M5150: case CPU_P5600: + case CPU_I6400: stype_intervention = 0x2; stype_memory = 0x3; stype_ordering = 0x10; diff --git a/arch/mips/kernel/spram.c b/arch/mips/kernel/spram.c index d1168d7c31e8e..8489c88f99323 100644 --- a/arch/mips/kernel/spram.c +++ b/arch/mips/kernel/spram.c @@ -209,6 +209,7 @@ void spram_config(void) case CPU_PROAPTIV: case CPU_P5600: case CPU_QEMU_GENERIC: + case CPU_I6400: config0 = read_c0_config(); /* FIXME: addresses are Malta specific */ if (config0 & (1<<24)) { diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 8ea28e6ab37de..01da120d75c44 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1651,6 +1651,7 @@ static inline void parity_protection_init(void) case CPU_PROAPTIV: case CPU_P5600: case CPU_QEMU_GENERIC: + case CPU_I6400: { #define ERRCTL_PE 0x80000000 #define ERRCTL_L2P 0x00800000 diff --git a/arch/mips/mm/c-r4k.c b/arch/mips/mm/c-r4k.c index fbea4432f3f23..5d3a25e1cfaea 100644 --- a/arch/mips/mm/c-r4k.c +++ b/arch/mips/mm/c-r4k.c @@ -1276,6 +1276,7 @@ static void probe_pcache(void) case CPU_PROAPTIV: case CPU_M5150: case CPU_QEMU_GENERIC: + case CPU_I6400: if (!(read_c0_config7() & MIPS_CONF7_IAR) && (c->icache.waysize > PAGE_SIZE)) c->icache.flags |= MIPS_CACHE_ALIASES; diff --git a/arch/mips/oprofile/common.c b/arch/mips/oprofile/common.c index 81f58958cf081..3c9ec3ddca845 100644 --- a/arch/mips/oprofile/common.c +++ b/arch/mips/oprofile/common.c @@ -91,6 +91,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops) case CPU_INTERAPTIV: case CPU_PROAPTIV: case CPU_P5600: + case CPU_I6400: case CPU_M5150: case CPU_LOONGSON1: case CPU_SB1: diff --git a/arch/mips/oprofile/op_model_mipsxx.c b/arch/mips/oprofile/op_model_mipsxx.c index 6a6e2cc55b892..8f988a61b7a85 100644 --- a/arch/mips/oprofile/op_model_mipsxx.c +++ b/arch/mips/oprofile/op_model_mipsxx.c @@ -392,6 +392,10 @@ static int __init mipsxx_init(void) op_model_mipsxx_ops.cpu_type = "mips/P5600"; break; + case CPU_I6400: + op_model_mipsxx_ops.cpu_type = "mips/I6400"; + break; + case CPU_M5150: op_model_mipsxx_ops.cpu_type = "mips/M5150"; break; -- GitLab From e57f9a2dcedc7f4847799e13a9987874a161d308 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:37 +0100 Subject: [PATCH 4955/7006] MIPS: Add MIPS I6400 probe support Add a case in cpu_probe_mips for the MIPS I6400 processor ID, which sets the CPU type to the new CPU_I6400. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10636/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dbe0792fc9c1b..02b75127dad3f 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1121,6 +1121,10 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu) c->cputype = CPU_P5600; __cpu_name[cpu] = "MIPS P5600"; break; + case PRID_IMP_I6400: + c->cputype = CPU_I6400; + __cpu_name[cpu] = "MIPS I6400"; + break; case PRID_IMP_M5150: c->cputype = CPU_M5150; __cpu_name[cpu] = "MIPS M5150"; -- GitLab From 5676319c91c8d668635ac0b9b6d9145c4fa418ac Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:38 +0100 Subject: [PATCH 4956/7006] MIPS: Kconfig: Disable MIPS MT and SMP implementations for R6 R6 does not support the MIPS MT ASE and the CMP/SMP options so restrict them in order to prevent users from selecting incompatible SMP configuration for R6 cores. We also disable the CPS/SMP option because its support hasn't been added to the CPS code yet. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10637/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 199a8357838cb..60d7ae76dd7e5 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2113,7 +2113,7 @@ config CPU_R4K_CACHE_TLB config MIPS_MT_SMP bool "MIPS MT SMP support (1 TC on each available VPE)" - depends on SYS_SUPPORTS_MULTITHREADING + depends on SYS_SUPPORTS_MULTITHREADING && !CPU_MIPSR6 select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select SYNC_R4K @@ -2214,7 +2214,7 @@ config MIPS_VPE_APSP_API_MT config MIPS_CMP bool "MIPS CMP framework support (DEPRECATED)" - depends on SYS_SUPPORTS_MIPS_CMP + depends on SYS_SUPPORTS_MIPS_CMP && !CPU_MIPSR6 select MIPS_GIC_IPI select SMP select SYNC_R4K @@ -2231,7 +2231,7 @@ config MIPS_CMP config MIPS_CPS bool "MIPS Coherent Processing System support" - depends on SYS_SUPPORTS_MIPS_CPS + depends on SYS_SUPPORTS_MIPS_CPS && !CPU_MIPSR6 select MIPS_CM select MIPS_CPC select MIPS_CPS_PM if HOTPLUG_CPU -- GitLab From 197e89e0984a2aaf1a5a998887b22e53051e3b6d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 10 Jul 2015 10:12:52 +0100 Subject: [PATCH 4957/7006] MIPS: mips-cm: Implement mips_cm_revision Provide a function to trivially return the version of the CM present in the system, or 0 if no CM is present. The mips_cm_revision() will be used later on to determine the CM register width, so it must not use the regular CM accessors to read the revision register since that will lead to build failures due to recursive inlines. Signed-off-by: Paul Burton Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10655/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index edc7ee95269e7..c70ba21e62f01 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -189,6 +189,13 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_REV_MINOR_SHF 0 #define CM_GCR_REV_MINOR_MSK (_ULCAST_(0xff) << 0) +#define CM_ENCODE_REV(major, minor) \ + (((major) << CM_GCR_REV_MAJOR_SHF) | \ + ((minor) << CM_GCR_REV_MINOR_SHF)) + +#define CM_REV_CM2 CM_ENCODE_REV(6, 0) +#define CM_REV_CM3 CM_ENCODE_REV(8, 0) + /* GCR_ERROR_CAUSE register fields */ #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) @@ -324,4 +331,18 @@ static inline int mips_cm_l2sync(void) return 0; } +/** + * mips_cm_revision() - return CM revision + * + * Return: The revision of the CM, from GCR_REV, or 0 if no CM is present. The + * return value should be checked against the CM_REV_* macros. + */ +static inline int mips_cm_revision(void) +{ + if (!mips_cm_present()) + return 0; + + return read_gcr_rev(); +} + #endif /* __MIPS_ASM_MIPS_CM_H__ */ -- GitLab From 0ba3c125aa0ff9f993c0f9629945a0dd18d42568 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 9 Jul 2015 10:40:40 +0100 Subject: [PATCH 4958/7006] MIPS: CM: Add GCR_L2_CONFIG register accessors Provide accessor functions for the GCR_L2_CONFIG register introduced with CM3, and define the bits included in the register. Signed-off-by: Paul Burton Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10639/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index c70ba21e62f01..ca3f2c963fbd5 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -144,6 +144,7 @@ BUILD_CM_RW(reg3_base, MIPS_CM_GCB_OFS + 0xc0) BUILD_CM_RW(reg3_mask, MIPS_CM_GCB_OFS + 0xc8) BUILD_CM_R_(gic_status, MIPS_CM_GCB_OFS + 0xd0) BUILD_CM_R_(cpc_status, MIPS_CM_GCB_OFS + 0xf0) +BUILD_CM_RW(l2_config, MIPS_CM_GCB_OFS + 0x130) /* Core Local & Core Other register accessor functions */ BUILD_CM_Cx_RW(reset_release, 0x00) @@ -256,6 +257,16 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_GCR_CPC_STATUS_EX_SHF 0 #define CM_GCR_CPC_STATUS_EX_MSK (_ULCAST_(0x1) << 0) +/* GCR_L2_CONFIG register fields */ +#define CM_GCR_L2_CONFIG_BYPASS_SHF 20 +#define CM_GCR_L2_CONFIG_BYPASS_MSK (_ULCAST_(0x1) << 20) +#define CM_GCR_L2_CONFIG_SET_SIZE_SHF 12 +#define CM_GCR_L2_CONFIG_SET_SIZE_MSK (_ULCAST_(0xf) << 12) +#define CM_GCR_L2_CONFIG_LINE_SIZE_SHF 8 +#define CM_GCR_L2_CONFIG_LINE_SIZE_MSK (_ULCAST_(0xf) << 8) +#define CM_GCR_L2_CONFIG_ASSOC_SHF 0 +#define CM_GCR_L2_CONFIG_ASSOC_MSK (_ULCAST_(0xff) << 0) + /* GCR_Cx_COHERENCE register fields */ #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_SHF 0 #define CM_GCR_Cx_COHERENCE_COHDOMAINEN_MSK (_ULCAST_(0xff) << 0) -- GitLab From 7d53e9c4cd21cbc82b7422c90852e56baaf7ddae Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 9 Jul 2015 10:40:42 +0100 Subject: [PATCH 4959/7006] MIPS: CM3: Add support for CM3 L2 cache. Detect the L2 cache configuration from GCR_L2_CONFIG when a CM3 is present in the system, rather than from Config2 which does not expose the L2 configuration on I6400. Signed-off-by: Paul Burton Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10641/ Signed-off-by: Ralf Baechle --- arch/mips/mm/sc-mips.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 4ceafd13870cd..5fa452e8cff92 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -14,6 +14,7 @@ #include #include #include +#include /* * MIPS32/MIPS64 L2 cache handling @@ -94,6 +95,34 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c) return 1; } +static int __init mips_sc_probe_cm3(void) +{ + struct cpuinfo_mips *c = ¤t_cpu_data; + unsigned long cfg = read_gcr_l2_config(); + unsigned long sets, line_sz, assoc; + + if (cfg & CM_GCR_L2_CONFIG_BYPASS_MSK) + return 0; + + sets = cfg & CM_GCR_L2_CONFIG_SET_SIZE_MSK; + sets >>= CM_GCR_L2_CONFIG_SET_SIZE_SHF; + c->scache.sets = 64 << sets; + + line_sz = cfg & CM_GCR_L2_CONFIG_LINE_SIZE_MSK; + line_sz >>= CM_GCR_L2_CONFIG_LINE_SIZE_SHF; + c->scache.linesz = 2 << line_sz; + + assoc = cfg & CM_GCR_L2_CONFIG_ASSOC_MSK; + assoc >>= CM_GCR_L2_CONFIG_ASSOC_SHF; + c->scache.ways = assoc + 1; + c->scache.waysize = c->scache.sets * c->scache.linesz; + c->scache.waybit = __ffs(c->scache.waysize); + + c->scache.flags &= ~MIPS_CACHE_NOT_PRESENT; + + return 1; +} + static inline int __init mips_sc_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -103,6 +132,9 @@ static inline int __init mips_sc_probe(void) /* Mark as not present until probe completed */ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; + if (mips_cm_revision() >= CM_REV_CM3) + return mips_sc_probe_cm3(); + /* Ignore anything but MIPSxx processors */ if (!(c->isa_level & (MIPS_CPU_ISA_M32R1 | MIPS_CPU_ISA_M32R2 | MIPS_CPU_ISA_M32R6 | MIPS_CPU_ISA_M64R1 | -- GitLab From c014d164f21dbdbe721a4ec7e5147591c4eed545 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:43 +0100 Subject: [PATCH 4960/7006] MIPS: Add platform callback before initializing the L2 cache Allow platforms to perform platform-specific steps before configuring the L2 cache. This is necessary for platforms with CM3 since the L2 parameters no longer live in the Config2 register. Signed-off-by: Markos Chandras Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10642/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 7 +++++++ arch/mips/mm/sc-mips.c | 10 ++++++++++ arch/mips/mti-malta/malta-init.c | 7 +++++++ 3 files changed, 24 insertions(+) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 85bbe9b967597..42602f30949fe 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -81,6 +81,13 @@ int mips_cm_probe(void) phys_addr_t addr; u32 base_reg; + /* + * No need to probe again if we have already been + * here before. + */ + if (mips_cm_base) + return 0; + addr = mips_cm_phys_base(); BUG_ON((addr & CM_GCR_BASE_GCRBASE_MSK) != addr); if (!addr) diff --git a/arch/mips/mm/sc-mips.c b/arch/mips/mm/sc-mips.c index 5fa452e8cff92..53ea8391f9bbf 100644 --- a/arch/mips/mm/sc-mips.c +++ b/arch/mips/mm/sc-mips.c @@ -123,6 +123,10 @@ static int __init mips_sc_probe_cm3(void) return 1; } +void __weak platform_early_l2_init(void) +{ +} + static inline int __init mips_sc_probe(void) { struct cpuinfo_mips *c = ¤t_cpu_data; @@ -132,6 +136,12 @@ static inline int __init mips_sc_probe(void) /* Mark as not present until probe completed */ c->scache.flags |= MIPS_CACHE_NOT_PRESENT; + /* + * Do we need some platform specific probing before + * we configure L2? + */ + platform_early_l2_init(); + if (mips_cm_revision() >= CM_REV_CM3) return mips_sc_probe_cm3(); diff --git a/arch/mips/mti-malta/malta-init.c b/arch/mips/mti-malta/malta-init.c index cec3e187c48f4..53c24784a2f7b 100644 --- a/arch/mips/mti-malta/malta-init.c +++ b/arch/mips/mti-malta/malta-init.c @@ -303,3 +303,10 @@ mips_pci_controller: if (!register_vsmp_smp_ops()) return; } + +void platform_early_l2_init(void) +{ + /* L2 configuration lives in the CM3 */ + if (mips_cm_revision() >= CM_REV_CM3) + mips_cm_probe(); +} -- GitLab From c0b584a2691ccbc3c0d4e6cb1874bcf00a921371 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 14 Jul 2015 09:14:12 +0100 Subject: [PATCH 4961/7006] MIPS: mips-cm: Extend CM accessors for 64-bit CPUs Previously, the CM accessors were only accessing CM registers as u32 types instead of using the native CM register with. However, newer CMs may actually be 64-bit on MIPS64 cores. Fortunately, current 64-bit CMs (CM3) hold all the useful configuration bits in the lower half of the 64-bit registers (at least most of them) so they can still be accessed using the current 32-bit accessors. Signed-off-by: Markos Chandras Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10707/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 48 ++++++++++++++++++++++++++++++--- arch/mips/kernel/mips-cm.c | 4 +++ 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index ca3f2c963fbd5..46cc0c69b77c0 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -33,6 +33,20 @@ extern void __iomem *mips_cm_l2sync_base; */ extern phys_addr_t __mips_cm_phys_base(void); +/* + * mips_cm_is64 - determine CM register width + * + * The CM register width is processor and CM specific. A 64-bit processor + * usually has a 64-bit CM and a 32-bit one has a 32-bit CM but a 64-bit + * processor could come with a 32-bit CM. Moreover, accesses on 64-bit CMs + * can be done either using regular 64-bit load/store instructions, or 32-bit + * load/store instruction on 32-bit register pairs. We opt for using 64-bit + * accesses on 64-bit CMs and kernels and 32-bit in any other case. + * + * It's set to 0 for 32-bit accesses and 1 for 64-bit accesses. + */ +extern int mips_cm_is64; + /** * mips_cm_probe - probe for a Coherence Manager * @@ -90,20 +104,46 @@ static inline bool mips_cm_has_l2sync(void) /* Macros to ease the creation of register access functions */ #define BUILD_CM_R_(name, off) \ -static inline u32 __iomem *addr_gcr_##name(void) \ +static inline unsigned long __iomem *addr_gcr_##name(void) \ { \ - return (u32 __iomem *)(mips_cm_base + (off)); \ + return (unsigned long __iomem *)(mips_cm_base + (off)); \ } \ \ -static inline u32 read_gcr_##name(void) \ +static inline u32 read32_gcr_##name(void) \ { \ return __raw_readl(addr_gcr_##name()); \ +} \ + \ +static inline u64 read64_gcr_##name(void) \ +{ \ + return __raw_readq(addr_gcr_##name()); \ +} \ + \ +static inline unsigned long read_gcr_##name(void) \ +{ \ + if (mips_cm_is64) \ + return read64_gcr_##name(); \ + else \ + return read32_gcr_##name(); \ } #define BUILD_CM__W(name, off) \ -static inline void write_gcr_##name(u32 value) \ +static inline void write32_gcr_##name(u32 value) \ { \ __raw_writel(value, addr_gcr_##name()); \ +} \ + \ +static inline void write64_gcr_##name(u64 value) \ +{ \ + __raw_writeq(value, addr_gcr_##name()); \ +} \ + \ +static inline void write_gcr_##name(unsigned long value) \ +{ \ + if (mips_cm_is64) \ + write64_gcr_##name(value); \ + else \ + write32_gcr_##name(value); \ } #define BUILD_CM_RW(name, off) \ diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 42602f30949fe..3d2cb6f478981 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -15,6 +15,7 @@ void __iomem *mips_cm_base; void __iomem *mips_cm_l2sync_base; +int mips_cm_is64; phys_addr_t __mips_cm_phys_base(void) { @@ -124,5 +125,8 @@ int mips_cm_probe(void) /* probe for an L2-only sync region */ mips_cm_probe_l2sync(); + /* determine register width for this CM */ + mips_cm_is64 = config_enabled(CONFIG_64BIT) && (mips_cm_revision() >= CM_REV_CM3); + return 0; } -- GitLab From 038b0f536e45d85038428d2edc169f1f4089c36d Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:45 +0100 Subject: [PATCH 4962/7006] MIPS: CM: The CMGCRBase register is 64-bit on 64 bit kernels. The CMGCRBase register (CP0, 15, 3) register is 64-bit on MIPS64 so we change its type to unsigned long. Signed-off-by: Markos Chandras Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10644/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index 3d2cb6f478981..c390be1cecc92 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -20,7 +20,7 @@ int mips_cm_is64; phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); - u32 cmgcr; + unsigned long cmgcr; /* Check the CMGCRBase register is implemented */ if (!(config3 & MIPS_CONF3_CMGCR)) -- GitLab From 391057d915f42d4942f0c65e7d55cec6662c8a54 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:46 +0100 Subject: [PATCH 4963/7006] MIPS: CPC: Fix type for GCR CPC base reg for 64-bit The GCR CPC base register is 64-bit on 64-bit processors so use the appropriate field. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10645/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/mips-cpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index 11964501c4b05..e05aca41e087e 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -23,7 +23,7 @@ static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); phys_addr_t __weak mips_cpc_phys_base(void) { - u32 cpc_base; + unsigned long cpc_base; if (!mips_cm_present()) return 0; -- GitLab From 3885c2b463f6a236e47df22ef13d13433006b951 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:47 +0100 Subject: [PATCH 4964/7006] MIPS: CM: Add support for reporting CM cache errors The CM cache error reporting code is not Malta specific and as such it should live in the mips-cm.c file. Moreover, CM2 and CM3 differ in the way cache errors are being recorded to the registers so extend the previous code to add support for the CM3 as well. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10646/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cm.h | 9 ++ arch/mips/kernel/mips-cm.c | 244 ++++++++++++++++++++++++++++++++ arch/mips/mti-malta/malta-int.c | 112 +-------------- 3 files changed, 254 insertions(+), 111 deletions(-) diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 46cc0c69b77c0..d75b75e78ebb4 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -47,6 +47,15 @@ extern phys_addr_t __mips_cm_phys_base(void); */ extern int mips_cm_is64; +/** + * mips_cm_error_report - Report CM cache errors + */ +#ifdef CONFIG_MIPS_CM +extern void mips_cm_error_report(void); +#else +static inline void mips_cm_error_report(void) {} +#endif + /** * mips_cm_probe - probe for a Coherence Manager * diff --git a/arch/mips/kernel/mips-cm.c b/arch/mips/kernel/mips-cm.c index c390be1cecc92..b8ceee576cdfc 100644 --- a/arch/mips/kernel/mips-cm.c +++ b/arch/mips/kernel/mips-cm.c @@ -17,6 +17,125 @@ void __iomem *mips_cm_base; void __iomem *mips_cm_l2sync_base; int mips_cm_is64; +static char *cm2_tr[8] = { + "mem", "gcr", "gic", "mmio", + "0x04", "cpc", "0x06", "0x07" +}; + +/* CM3 Tag ECC transation type */ +static char *cm3_tr[16] = { + [0x0] = "ReqNoData", + [0x1] = "0x1", + [0x2] = "ReqWData", + [0x3] = "0x3", + [0x4] = "IReqNoResp", + [0x5] = "IReqWResp", + [0x6] = "IReqNoRespDat", + [0x7] = "IReqWRespDat", + [0x8] = "RespNoData", + [0x9] = "RespDataFol", + [0xa] = "RespWData", + [0xb] = "RespDataOnly", + [0xc] = "IRespNoData", + [0xd] = "IRespDataFol", + [0xe] = "IRespWData", + [0xf] = "IRespDataOnly" +}; + +static char *cm2_cmd[32] = { + [0x00] = "0x00", + [0x01] = "Legacy Write", + [0x02] = "Legacy Read", + [0x03] = "0x03", + [0x04] = "0x04", + [0x05] = "0x05", + [0x06] = "0x06", + [0x07] = "0x07", + [0x08] = "Coherent Read Own", + [0x09] = "Coherent Read Share", + [0x0a] = "Coherent Read Discard", + [0x0b] = "Coherent Ready Share Always", + [0x0c] = "Coherent Upgrade", + [0x0d] = "Coherent Writeback", + [0x0e] = "0x0e", + [0x0f] = "0x0f", + [0x10] = "Coherent Copyback", + [0x11] = "Coherent Copyback Invalidate", + [0x12] = "Coherent Invalidate", + [0x13] = "Coherent Write Invalidate", + [0x14] = "Coherent Completion Sync", + [0x15] = "0x15", + [0x16] = "0x16", + [0x17] = "0x17", + [0x18] = "0x18", + [0x19] = "0x19", + [0x1a] = "0x1a", + [0x1b] = "0x1b", + [0x1c] = "0x1c", + [0x1d] = "0x1d", + [0x1e] = "0x1e", + [0x1f] = "0x1f" +}; + +/* CM3 Tag ECC command type */ +static char *cm3_cmd[16] = { + [0x0] = "Legacy Read", + [0x1] = "Legacy Write", + [0x2] = "Coherent Read Own", + [0x3] = "Coherent Read Share", + [0x4] = "Coherent Read Discard", + [0x5] = "Coherent Evicted", + [0x6] = "Coherent Upgrade", + [0x7] = "Coherent Upgrade for Store Conditional", + [0x8] = "Coherent Writeback", + [0x9] = "Coherent Write Invalidate", + [0xa] = "0xa", + [0xb] = "0xb", + [0xc] = "0xc", + [0xd] = "0xd", + [0xe] = "0xe", + [0xf] = "0xf" +}; + +/* CM3 Tag ECC command group */ +static char *cm3_cmd_group[8] = { + [0x0] = "Normal", + [0x1] = "Registers", + [0x2] = "TLB", + [0x3] = "0x3", + [0x4] = "L1I", + [0x5] = "L1D", + [0x6] = "L3", + [0x7] = "L2" +}; + +static char *cm2_core[8] = { + "Invalid/OK", "Invalid/Data", + "Shared/OK", "Shared/Data", + "Modified/OK", "Modified/Data", + "Exclusive/OK", "Exclusive/Data" +}; + +static char *cm2_causes[32] = { + "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", + "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", + "0x08", "0x09", "0x0a", "0x0b", + "0x0c", "0x0d", "0x0e", "0x0f", + "0x10", "0x11", "0x12", "0x13", + "0x14", "0x15", "0x16", "INTVN_WR_ERR", + "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", + "0x1c", "0x1d", "0x1e", "0x1f" +}; + +static char *cm3_causes[32] = { + "0x0", "MP_CORRECTABLE_ECC_ERR", "MP_REQUEST_DECODE_ERR", + "MP_UNCORRECTABLE_ECC_ERR", "MP_PARITY_ERR", "MP_COHERENCE_ERR", + "CMBIU_REQUEST_DECODE_ERR", "CMBIU_PARITY_ERR", "CMBIU_AXI_RESP_ERR", + "0x9", "RBI_BUS_ERR", "0xb", "0xc", "0xd", "0xe", "0xf", "0x10", + "0x11", "0x12", "0x13", "0x14", "0x15", "0x16", "0x17", "0x18", + "0x19", "0x1a", "0x1b", "0x1c", "0x1d", "0x1e", "0x1f" +}; + phys_addr_t __mips_cm_phys_base(void) { u32 config3 = read_c0_config3(); @@ -130,3 +249,128 @@ int mips_cm_probe(void) return 0; } + +void mips_cm_error_report(void) +{ + unsigned long revision = mips_cm_revision(); + /* + * CM3 has a 64-bit Error cause register with 0:57 containing the error + * info and 63:58 the error type. For old CMs, everything is contained + * in a single 32-bit register (0:26 and 31:27 respectively). Even + * though the cm_error is u64, we will simply ignore the upper word + * for CM2. + */ + u64 cm_error = read_gcr_error_cause(); + int cm_error_cause_sft = CM_GCR_ERROR_CAUSE_ERRTYPE_SHF + + ((revision >= CM_REV_CM3) ? 31 : 0); + unsigned long cm_addr = read_gcr_error_addr(); + unsigned long cm_other = read_gcr_error_mult(); + int ocause, cause; + char buf[256]; + + if (!mips_cm_present()) + return; + + cause = cm_error >> cm_error_cause_sft; + + if (!cause) + /* All good */ + return; + + ocause = cm_other >> CM_GCR_ERROR_MULT_ERR2ND_SHF; + if (revision < CM_REV_CM3) { /* CM2 */ + if (cause < 16) { + unsigned long cca_bits = (cm_error >> 15) & 7; + unsigned long tr_bits = (cm_error >> 12) & 7; + unsigned long cmd_bits = (cm_error >> 7) & 0x1f; + unsigned long stag_bits = (cm_error >> 3) & 15; + unsigned long sport_bits = (cm_error >> 0) & 7; + + snprintf(buf, sizeof(buf), + "CCA=%lu TR=%s MCmd=%s STag=%lu " + "SPort=%lu\n", cca_bits, cm2_tr[tr_bits], + cm2_cmd[cmd_bits], stag_bits, sport_bits); + } else { + /* glob state & sresp together */ + unsigned long c3_bits = (cm_error >> 18) & 7; + unsigned long c2_bits = (cm_error >> 15) & 7; + unsigned long c1_bits = (cm_error >> 12) & 7; + unsigned long c0_bits = (cm_error >> 9) & 7; + unsigned long sc_bit = (cm_error >> 8) & 1; + unsigned long cmd_bits = (cm_error >> 3) & 0x1f; + unsigned long sport_bits = (cm_error >> 0) & 7; + + snprintf(buf, sizeof(buf), + "C3=%s C2=%s C1=%s C0=%s SC=%s " + "MCmd=%s SPort=%lu\n", + cm2_core[c3_bits], cm2_core[c2_bits], + cm2_core[c1_bits], cm2_core[c0_bits], + sc_bit ? "True" : "False", + cm2_cmd[cmd_bits], sport_bits); + } + pr_err("CM_ERROR=%08llx %s <%s>\n", cm_error, + cm2_causes[cause], buf); + pr_err("CM_ADDR =%08lx\n", cm_addr); + pr_err("CM_OTHER=%08lx %s\n", cm_other, cm2_causes[ocause]); + } else { /* CM3 */ + /* Used by cause == {1,2,3} */ + unsigned long core_id_bits = (cm_error >> 22) & 0xf; + unsigned long vp_id_bits = (cm_error >> 18) & 0xf; + unsigned long cmd_bits = (cm_error >> 14) & 0xf; + unsigned long cmd_group_bits = (cm_error >> 11) & 0xf; + unsigned long cm3_cca_bits = (cm_error >> 8) & 7; + unsigned long mcp_bits = (cm_error >> 5) & 0xf; + unsigned long cm3_tr_bits = (cm_error >> 1) & 0xf; + unsigned long sched_bit = cm_error & 0x1; + + if (cause == 1 || cause == 3) { /* Tag ECC */ + unsigned long tag_ecc = (cm_error >> 57) & 0x1; + unsigned long tag_way_bits = (cm_error >> 29) & 0xffff; + unsigned long dword_bits = (cm_error >> 49) & 0xff; + unsigned long data_way_bits = (cm_error >> 45) & 0xf; + unsigned long data_sets_bits = (cm_error >> 29) & 0xfff; + unsigned long bank_bit = (cm_error >> 28) & 0x1; + snprintf(buf, sizeof(buf), + "%s ECC Error: Way=%lu (DWORD=%lu, Sets=%lu)" + "Bank=%lu CoreID=%lu VPID=%lu Command=%s" + "Command Group=%s CCA=%lu MCP=%d" + "Transaction type=%s Scheduler=%lu\n", + tag_ecc ? "TAG" : "DATA", + tag_ecc ? (unsigned long)ffs(tag_way_bits) - 1 : + data_way_bits, bank_bit, dword_bits, + data_sets_bits, + core_id_bits, vp_id_bits, + cm3_cmd[cmd_bits], + cm3_cmd_group[cmd_group_bits], + cm3_cca_bits, 1 << mcp_bits, + cm3_tr[cm3_tr_bits], sched_bit); + } else if (cause == 2) { + unsigned long data_error_type = (cm_error >> 41) & 0xfff; + unsigned long data_decode_cmd = (cm_error >> 37) & 0xf; + unsigned long data_decode_group = (cm_error >> 34) & 0x7; + unsigned long data_decode_destination_id = (cm_error >> 28) & 0x3f; + + snprintf(buf, sizeof(buf), + "Decode Request Error: Type=%lu, Command=%lu" + "Command Group=%lu Destination ID=%lu" + "CoreID=%lu VPID=%lu Command=%s" + "Command Group=%s CCA=%lu MCP=%d" + "Transaction type=%s Scheduler=%lu\n", + data_error_type, data_decode_cmd, + data_decode_group, data_decode_destination_id, + core_id_bits, vp_id_bits, + cm3_cmd[cmd_bits], + cm3_cmd_group[cmd_group_bits], + cm3_cca_bits, 1 << mcp_bits, + cm3_tr[cm3_tr_bits], sched_bit); + } + + pr_err("CM_ERROR=%llx %s <%s>\n", cm_error, + cm3_causes[cause], buf); + pr_err("CM_ADDR =%lx\n", cm_addr); + pr_err("CM_OTHER=%lx %s\n", cm_other, cm3_causes[ocause]); + } + + /* reprime cause register */ + write_gcr_error_cause(0); +} diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c index fa8f591f37136..c6a6c7afddab4 100644 --- a/arch/mips/mti-malta/malta-int.c +++ b/arch/mips/mti-malta/malta-int.c @@ -382,122 +382,12 @@ void malta_be_init(void) /* Could change CM error mask register. */ } - -static char *tr[8] = { - "mem", "gcr", "gic", "mmio", - "0x04", "0x05", "0x06", "0x07" -}; - -static char *mcmd[32] = { - [0x00] = "0x00", - [0x01] = "Legacy Write", - [0x02] = "Legacy Read", - [0x03] = "0x03", - [0x04] = "0x04", - [0x05] = "0x05", - [0x06] = "0x06", - [0x07] = "0x07", - [0x08] = "Coherent Read Own", - [0x09] = "Coherent Read Share", - [0x0a] = "Coherent Read Discard", - [0x0b] = "Coherent Ready Share Always", - [0x0c] = "Coherent Upgrade", - [0x0d] = "Coherent Writeback", - [0x0e] = "0x0e", - [0x0f] = "0x0f", - [0x10] = "Coherent Copyback", - [0x11] = "Coherent Copyback Invalidate", - [0x12] = "Coherent Invalidate", - [0x13] = "Coherent Write Invalidate", - [0x14] = "Coherent Completion Sync", - [0x15] = "0x15", - [0x16] = "0x16", - [0x17] = "0x17", - [0x18] = "0x18", - [0x19] = "0x19", - [0x1a] = "0x1a", - [0x1b] = "0x1b", - [0x1c] = "0x1c", - [0x1d] = "0x1d", - [0x1e] = "0x1e", - [0x1f] = "0x1f" -}; - -static char *core[8] = { - "Invalid/OK", "Invalid/Data", - "Shared/OK", "Shared/Data", - "Modified/OK", "Modified/Data", - "Exclusive/OK", "Exclusive/Data" -}; - -static char *causes[32] = { - "None", "GC_WR_ERR", "GC_RD_ERR", "COH_WR_ERR", - "COH_RD_ERR", "MMIO_WR_ERR", "MMIO_RD_ERR", "0x07", - "0x08", "0x09", "0x0a", "0x0b", - "0x0c", "0x0d", "0x0e", "0x0f", - "0x10", "0x11", "0x12", "0x13", - "0x14", "0x15", "0x16", "INTVN_WR_ERR", - "INTVN_RD_ERR", "0x19", "0x1a", "0x1b", - "0x1c", "0x1d", "0x1e", "0x1f" -}; - int malta_be_handler(struct pt_regs *regs, int is_fixup) { /* This duplicates the handling in do_be which seems wrong */ int retval = is_fixup ? MIPS_BE_FIXUP : MIPS_BE_FATAL; - if (mips_cm_present()) { - unsigned long cm_error = read_gcr_error_cause(); - unsigned long cm_addr = read_gcr_error_addr(); - unsigned long cm_other = read_gcr_error_mult(); - unsigned long cause, ocause; - char buf[256]; - - cause = cm_error & CM_GCR_ERROR_CAUSE_ERRTYPE_MSK; - if (cause != 0) { - cause >>= CM_GCR_ERROR_CAUSE_ERRTYPE_SHF; - if (cause < 16) { - unsigned long cca_bits = (cm_error >> 15) & 7; - unsigned long tr_bits = (cm_error >> 12) & 7; - unsigned long cmd_bits = (cm_error >> 7) & 0x1f; - unsigned long stag_bits = (cm_error >> 3) & 15; - unsigned long sport_bits = (cm_error >> 0) & 7; - - snprintf(buf, sizeof(buf), - "CCA=%lu TR=%s MCmd=%s STag=%lu " - "SPort=%lu\n", - cca_bits, tr[tr_bits], mcmd[cmd_bits], - stag_bits, sport_bits); - } else { - /* glob state & sresp together */ - unsigned long c3_bits = (cm_error >> 18) & 7; - unsigned long c2_bits = (cm_error >> 15) & 7; - unsigned long c1_bits = (cm_error >> 12) & 7; - unsigned long c0_bits = (cm_error >> 9) & 7; - unsigned long sc_bit = (cm_error >> 8) & 1; - unsigned long cmd_bits = (cm_error >> 3) & 0x1f; - unsigned long sport_bits = (cm_error >> 0) & 7; - snprintf(buf, sizeof(buf), - "C3=%s C2=%s C1=%s C0=%s SC=%s " - "MCmd=%s SPort=%lu\n", - core[c3_bits], core[c2_bits], - core[c1_bits], core[c0_bits], - sc_bit ? "True" : "False", - mcmd[cmd_bits], sport_bits); - } - - ocause = (cm_other & CM_GCR_ERROR_MULT_ERR2ND_MSK) >> - CM_GCR_ERROR_MULT_ERR2ND_SHF; - - pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error, - causes[cause], buf); - pr_err("CM_ADDR =%08lx\n", cm_addr); - pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]); - - /* reprime cause register */ - write_gcr_error_cause(0); - } - } + mips_cm_error_report(); return retval; } -- GitLab From c3f57f02e3a275d8b5c6dc692adb21525ccb392c Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Tue, 14 Jul 2015 10:26:09 +0100 Subject: [PATCH 4965/7006] IRQCHIP: irq-mips-gic: Extend GIC accessors for 64-bit CMs Previously, the GIC accessors were only accessing u32 registers but newer CMs may actually be 64-bit on MIPS64 cores. As a result of which, extended these accessors to support 64-bit reads and writes. Signed-off-by: Markos Chandras Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: Paul Burton Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10709/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-mips-gic.c | 121 +++++++++++++++++++------------ include/linux/irqchip/mips-gic.h | 10 ++- 2 files changed, 84 insertions(+), 47 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index ff4be0515a0dc..d8db854afded1 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -42,20 +42,46 @@ static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; static void __gic_irq_dispatch(void); -static inline unsigned int gic_read(unsigned int reg) +static inline u32 gic_read32(unsigned int reg) { return __raw_readl(gic_base + reg); } -static inline void gic_write(unsigned int reg, unsigned int val) +static inline u64 gic_read64(unsigned int reg) { - __raw_writel(val, gic_base + reg); + return __raw_readq(gic_base + reg); } -static inline void gic_update_bits(unsigned int reg, unsigned int mask, - unsigned int val) +static inline unsigned long gic_read(unsigned int reg) { - unsigned int regval; + if (!mips_cm_is64) + return gic_read32(reg); + else + return gic_read64(reg); +} + +static inline void gic_write32(unsigned int reg, u32 val) +{ + return __raw_writel(val, gic_base + reg); +} + +static inline void gic_write64(unsigned int reg, u64 val) +{ + return __raw_writeq(val, gic_base + reg); +} + +static inline void gic_write(unsigned int reg, unsigned long val) +{ + if (!mips_cm_is64) + return gic_write32(reg, (u32)val); + else + return gic_write64(reg, (u64)val); +} + +static inline void gic_update_bits(unsigned int reg, unsigned long mask, + unsigned long val) +{ + unsigned long regval; regval = gic_read(reg); regval &= ~mask; @@ -66,40 +92,40 @@ static inline void gic_update_bits(unsigned int reg, unsigned int mask, static inline void gic_reset_mask(unsigned int intr) { gic_write(GIC_REG(SHARED, GIC_SH_RMASK) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr)); } static inline void gic_set_mask(unsigned int intr) { gic_write(GIC_REG(SHARED, GIC_SH_SMASK) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr)); } static inline void gic_set_polarity(unsigned int intr, unsigned int pol) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_POLARITY) + - GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), - pol << GIC_INTR_BIT(intr)); + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), + (unsigned long)pol << GIC_INTR_BIT(intr)); } static inline void gic_set_trigger(unsigned int intr, unsigned int trig) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_TRIGGER) + - GIC_INTR_OFS(intr), 1 << GIC_INTR_BIT(intr), - trig << GIC_INTR_BIT(intr)); + GIC_INTR_OFS(intr), 1ul << GIC_INTR_BIT(intr), + (unsigned long)trig << GIC_INTR_BIT(intr)); } static inline void gic_set_dual_edge(unsigned int intr, unsigned int dual) { gic_update_bits(GIC_REG(SHARED, GIC_SH_SET_DUAL) + GIC_INTR_OFS(intr), - 1 << GIC_INTR_BIT(intr), - dual << GIC_INTR_BIT(intr)); + 1ul << GIC_INTR_BIT(intr), + (unsigned long)dual << GIC_INTR_BIT(intr)); } static inline void gic_map_to_pin(unsigned int intr, unsigned int pin) { - gic_write(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + - GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); + gic_write32(GIC_REG(SHARED, GIC_SH_INTR_MAP_TO_PIN_BASE) + + GIC_SH_MAP_TO_PIN(intr), GIC_MAP_TO_PIN_MSK | pin); } static inline void gic_map_to_vpe(unsigned int intr, unsigned int vpe) @@ -115,9 +141,9 @@ cycle_t gic_read_count(void) unsigned int hi, hi2, lo; do { - hi = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); - lo = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); - hi2 = gic_read(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); + lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); + hi2 = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); } while (hi2 != hi); return (((cycle_t) hi) << 32) + lo; @@ -136,9 +162,9 @@ unsigned int gic_get_count_width(void) void gic_write_compare(cycle_t cnt) { - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), (int)(cnt >> 32)); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), (int)(cnt & 0xffffffff)); } @@ -148,10 +174,10 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), (int)(cnt >> 32)); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), (int)(cnt & 0xffffffff)); local_irq_restore(flags); @@ -161,8 +187,8 @@ cycle_t gic_read_compare(void) { unsigned int hi, lo; - hi = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); - lo = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); + hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); + lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); return (((cycle_t) hi) << 32) + lo; } @@ -197,7 +223,7 @@ static bool gic_local_irq_is_routable(int intr) if (cpu_has_veic) return true; - vpe_ctl = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); + vpe_ctl = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_CTL)); switch (intr) { case GIC_LOCAL_INT_TIMER: return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK; @@ -263,7 +289,7 @@ int gic_get_c0_fdc_int(void) static void gic_handle_shared_int(bool chained) { - unsigned int i, intr, virq; + unsigned int i, intr, virq, gic_reg_step = mips_cm_is64 ? 8 : 4; unsigned long *pcpu_mask; unsigned long pending_reg, intrmask_reg; DECLARE_BITMAP(pending, GIC_MAX_INTRS); @@ -278,8 +304,8 @@ static void gic_handle_shared_int(bool chained) for (i = 0; i < BITS_TO_LONGS(gic_shared_intrs); i++) { pending[i] = gic_read(pending_reg); intrmask[i] = gic_read(intrmask_reg); - pending_reg += 0x4; - intrmask_reg += 0x4; + pending_reg += gic_reg_step; + intrmask_reg += gic_reg_step; } bitmap_and(pending, pending, intrmask, gic_shared_intrs); @@ -429,8 +455,8 @@ static void gic_handle_local_int(bool chained) unsigned long pending, masked; unsigned int intr, virq; - pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); - masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); + pending = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_PEND)); + masked = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_MASK)); bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS); @@ -453,14 +479,14 @@ static void gic_mask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr); } static void gic_unmask_local_irq(struct irq_data *d) { int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq); - gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr); } static struct irq_chip gic_local_irq_controller = { @@ -478,7 +504,7 @@ static void gic_mask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); } @@ -492,7 +518,7 @@ static void gic_unmask_local_irq_all_vpes(struct irq_data *d) spin_lock_irqsave(&gic_lock, flags); for (i = 0; i < gic_vpes; i++) { gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i); - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr); } spin_unlock_irqrestore(&gic_lock, flags); } @@ -612,7 +638,7 @@ static void __init gic_basic_init(void) for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) { if (!gic_local_irq_is_routable(j)) continue; - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j); } } } @@ -657,27 +683,32 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq, switch (intr) { case GIC_LOCAL_INT_WD: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val); break; case GIC_LOCAL_INT_COMPARE: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), + val); break; case GIC_LOCAL_INT_TIMER: /* CONFIG_MIPS_CMP workaround (see __gic_init) */ val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin; - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), + val); break; case GIC_LOCAL_INT_PERFCTR: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), + val); break; case GIC_LOCAL_INT_SWINT0: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), + val); break; case GIC_LOCAL_INT_SWINT1: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), + val); break; case GIC_LOCAL_INT_FDC: - gic_write(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val); break; default: pr_err("Invalid local IRQ %d\n", intr); @@ -782,7 +813,7 @@ static void __init __gic_init(unsigned long gic_base_addr, */ if (IS_ENABLED(CONFIG_MIPS_CMP) && gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) { - timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL, + timer_cpu_pin = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_TIMER_MAP)) & GIC_MAP_MSK; irq_set_chained_handler(MIPS_CPU_IRQ_BASE + diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index 9b1ad3734911b..10e4a90730190 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -45,8 +45,14 @@ #define GIC_SH_REVISIONID_OFS 0x0020 /* Convert an interrupt number to a byte offset/bit for multi-word registers */ -#define GIC_INTR_OFS(intr) (((intr) / 32) * 4) -#define GIC_INTR_BIT(intr) ((intr) % 32) +#define GIC_INTR_OFS(intr) ({ \ + unsigned bits = mips_cm_is64 ? 64 : 32; \ + unsigned reg_idx = (intr) / bits; \ + unsigned reg_width = bits / 8; \ + \ + reg_idx * reg_width; \ +}) +#define GIC_INTR_BIT(intr) ((intr) % (mips_cm_is64 ? 64 : 32)) /* Polarity : Reset Value is always 0 */ #define GIC_SH_SET_POLARITY_OFS 0x0100 -- GitLab From 6f50c83529ac1fa3444ff4be5f5b0bf3d76db678 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:49 +0100 Subject: [PATCH 4966/7006] IRQCHIP: irq-mips-gic: Add support for CM3 64-bit timer irqs CM3 uses a 64-bit counter and compare registers so add support for them in the GIC counter interrupt. Signed-off-by: Markos Chandras Cc: Thomas Gleixner Cc: Jason Cooper Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10648/ Signed-off-by: Ralf Baechle --- drivers/irqchip/irq-mips-gic.c | 33 +++++++++++++++++++++++--------- include/linux/irqchip/mips-gic.h | 4 ++++ 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c index d8db854afded1..7d4616963b5ae 100644 --- a/drivers/irqchip/irq-mips-gic.c +++ b/drivers/irqchip/irq-mips-gic.c @@ -140,6 +140,9 @@ cycle_t gic_read_count(void) { unsigned int hi, hi2, lo; + if (mips_cm_is64) + return (cycle_t)gic_read(GIC_REG(SHARED, GIC_SH_COUNTER)); + do { hi = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_63_32)); lo = gic_read32(GIC_REG(SHARED, GIC_SH_COUNTER_31_00)); @@ -162,10 +165,14 @@ unsigned int gic_get_count_width(void) void gic_write_compare(cycle_t cnt) { - gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); + if (mips_cm_is64) { + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE), cnt); + } else { + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + } } void gic_write_cpu_compare(cycle_t cnt, int cpu) @@ -174,11 +181,16 @@ void gic_write_cpu_compare(cycle_t cnt, int cpu) local_irq_save(flags); - gic_write32(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); - gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), - (int)(cnt >> 32)); - gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), - (int)(cnt & 0xffffffff)); + gic_write(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), cpu); + + if (mips_cm_is64) { + gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE), cnt); + } else { + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_HI), + (int)(cnt >> 32)); + gic_write32(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_LO), + (int)(cnt & 0xffffffff)); + } local_irq_restore(flags); } @@ -187,6 +199,9 @@ cycle_t gic_read_compare(void) { unsigned int hi, lo; + if (mips_cm_is64) + return (cycle_t)gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE)); + hi = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_HI)); lo = gic_read32(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_LO)); diff --git a/include/linux/irqchip/mips-gic.h b/include/linux/irqchip/mips-gic.h index 10e4a90730190..4e68616050504 100644 --- a/include/linux/irqchip/mips-gic.h +++ b/include/linux/irqchip/mips-gic.h @@ -41,6 +41,8 @@ /* Shared Global Counter */ #define GIC_SH_COUNTER_31_00_OFS 0x0010 +/* 64-bit counter register for CM3 */ +#define GIC_SH_COUNTER_OFS GIC_SH_COUNTER_31_00_OFS #define GIC_SH_COUNTER_63_32_OFS 0x0014 #define GIC_SH_REVISIONID_OFS 0x0020 @@ -104,6 +106,8 @@ #define GIC_VPE_WD_COUNT0_OFS 0x0094 #define GIC_VPE_WD_INITIAL0_OFS 0x0098 #define GIC_VPE_COMPARE_LO_OFS 0x00a0 +/* 64-bit Compare register on CM3 */ +#define GIC_VPE_COMPARE_OFS GIC_VPE_COMPARE_LO_OFS #define GIC_VPE_COMPARE_HI_OFS 0x00a4 #define GIC_VPE_EIC_SHADOW_SET_BASE_OFS 0x0100 -- GitLab From c982c6d6c48b48159db481581cadbb8773219677 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:50 +0100 Subject: [PATCH 4967/7006] MIPS: cpu-probe: Remove cp0 hazard barrier when enabling the FTLB We are so early in the boot process where we really don't want to stall and wait for CP0 FTLB related changes become visible so just drop the cp0 hazard barrier. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10649/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 02b75127dad3f..dc057f37305b6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -385,7 +385,6 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) else /* Disable FTLB */ write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); - back_to_back_c0_hazard(); break; } } -- GitLab From 912708c26d673f8d043bc4a9552495fefd6ddf18 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:51 +0100 Subject: [PATCH 4968/7006] MIPS: Add default case for the FTLB enable/disable code Add a default case for the FTLB enable/disable code. This will be used to detect that something went wrong in the set_ftlb_enable() function either because that function knows nothing about the running core, or simply because the core can't turn its FTLB on/off. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10650/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dc057f37305b6..6da5f2db67926 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -188,7 +188,7 @@ __setup("nohtw", htw_disable); static int mips_ftlb_disabled; static int mips_has_ftlb_configured; -static void set_ftlb_enable(struct cpuinfo_mips *c, int enable); +static int set_ftlb_enable(struct cpuinfo_mips *c, int enable); static int __init ftlb_disable(char *s) { @@ -202,7 +202,10 @@ static int __init ftlb_disable(char *s) return 1; /* Disable it in the boot cpu */ - set_ftlb_enable(&cpu_data[0], 0); + if (set_ftlb_enable(&cpu_data[0], 0)) { + pr_warn("Can't turn FTLB off\n"); + return 1; + } back_to_back_c0_hazard(); @@ -364,7 +367,7 @@ static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) return 3; } -static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) +static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) { unsigned int config6; @@ -386,7 +389,11 @@ static void set_ftlb_enable(struct cpuinfo_mips *c, int enable) /* Disable FTLB */ write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); break; + default: + return 1; } + + return 0; } static inline unsigned int decode_config0(struct cpuinfo_mips *c) -- GitLab From e87569cd6c57cfe8c3fbbd20a5cf5cefb8b14156 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:52 +0100 Subject: [PATCH 4969/7006] MIPS: cpu-probe: Fix VTLB/FTLB configuration for R6 R6 has dropped the MMUExtDef field from the config4 register and it now returns 0. However, the return value means nothing in that case and the only supported configuration for R6 is the VTLB+FTLB (MMUextDef == 3). As a result, rework the code so that the correct value is set for R6 cores. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10651/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 6da5f2db67926..62dae429fe706 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -546,7 +546,16 @@ static inline unsigned int decode_config4(struct cpuinfo_mips *c) if (cpu_has_tlb) { if (((config4 & MIPS_CONF4_IE) >> 29) == 2) c->options |= MIPS_CPU_TLBINV; - mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + /* + * This is a bit ugly. R6 has dropped that field from + * config4 and the only valid configuration is VTLB+FTLB so + * set a good value for mmuextdef for that case. + */ + if (cpu_has_mips_r6) + mmuextdef = MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT; + else + mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF; + switch (mmuextdef) { case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT: c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40; -- GitLab From 20a7f7e5a6739a3521529a5f2bbfddf9f545fef9 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 9 Jul 2015 10:40:53 +0100 Subject: [PATCH 4970/7006] MIPS: Set up FTLB probability for I6400 Set up the I6400 FTLB probability similar to P5600 and proAptiv. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10652/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 2 ++ arch/mips/kernel/cpu-probe.c | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index c5b0956a85302..723ee3c7849d2 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -579,6 +579,8 @@ #define MIPS_CONF7_IAR (_ULCAST_(1) << 10) #define MIPS_CONF7_AR (_ULCAST_(1) << 16) +/* FTLB probability bits for R6 */ +#define MIPS_CONF7_FTLBP_SHIFT (18) /* MAAR bit definitions */ #define MIPS_MAAR_ADDR ((BIT_ULL(BITS_PER_LONG - 12) - 1) << 12) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 62dae429fe706..4e39b340f3b77 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -369,25 +369,33 @@ static unsigned int calculate_ftlb_probability(struct cpuinfo_mips *c) static int set_ftlb_enable(struct cpuinfo_mips *c, int enable) { - unsigned int config6; + unsigned int config; /* It's implementation dependent how the FTLB can be enabled */ switch (c->cputype) { case CPU_PROAPTIV: case CPU_P5600: /* proAptiv & related cores use Config6 to enable the FTLB */ - config6 = read_c0_config6(); + config = read_c0_config6(); /* Clear the old probability value */ - config6 &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); + config &= ~(3 << MIPS_CONF6_FTLBP_SHIFT); if (enable) /* Enable FTLB */ - write_c0_config6(config6 | + write_c0_config6(config | (calculate_ftlb_probability(c) << MIPS_CONF6_FTLBP_SHIFT) | MIPS_CONF6_FTLBEN); else /* Disable FTLB */ - write_c0_config6(config6 & ~MIPS_CONF6_FTLBEN); + write_c0_config6(config & ~MIPS_CONF6_FTLBEN); + break; + case CPU_I6400: + /* I6400 & related cores use Config7 to configure FTLB */ + config = read_c0_config7(); + /* Clear the old probability value */ + config &= ~(3 << MIPS_CONF7_FTLBP_SHIFT); + write_c0_config7(config | (calculate_ftlb_probability(c) + << MIPS_CONF7_FTLBP_SHIFT)); break; default: return 1; -- GitLab From f058dc80d6f964fa466650f74290a964a7f91c92 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:53 +0000 Subject: [PATCH 4971/7006] MIPS: jz4740: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10695/ Signed-off-by: Ralf Baechle --- arch/mips/jz4740/gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c index 54c80d42a88d6..77df1602f8189 100644 --- a/arch/mips/jz4740/gpio.c +++ b/arch/mips/jz4740/gpio.c @@ -423,8 +423,8 @@ static void jz4740_gpio_chip_init(struct jz_gpio_chip *chip, unsigned int id) chip->base = ioremap(JZ4740_GPIO_BASE_ADDR + (id * 0x100), 0x100); chip->irq = JZ4740_IRQ_INTC_GPIO(id); - irq_set_handler_data(chip->irq, chip); - irq_set_chained_handler(chip->irq, jz_gpio_irq_demux_handler); + irq_set_chained_handler_and_data(chip->irq, + jz_gpio_irq_demux_handler, chip); gc = irq_alloc_generic_chip(chip->gpio_chip.label, 1, chip->irq_base, chip->base, handle_level_irq); -- GitLab From 777fd18a71866f5057b27535c47c817973293498 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:55 +0000 Subject: [PATCH 4972/7006] MIPS: pci-ar71xx: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10696/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-ar71xx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-ar71xx.c b/arch/mips/pci/pci-ar71xx.c index 283157f8dc647..ad35a5e6a56c5 100644 --- a/arch/mips/pci/pci-ar71xx.c +++ b/arch/mips/pci/pci-ar71xx.c @@ -312,8 +312,8 @@ static void ar71xx_pci_irq_init(struct ar71xx_pci_controller *apc) irq_set_chip_data(i, apc); } - irq_set_handler_data(apc->irq, apc); - irq_set_chained_handler(apc->irq, ar71xx_pci_irq_handler); + irq_set_chained_handler_and_data(apc->irq, ar71xx_pci_irq_handler, + apc); } static void ar71xx_pci_reset(void) -- GitLab From 4d3f77d855090e11c9823fcb00864745adaf6fae Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:56 +0000 Subject: [PATCH 4973/7006] MIPS: pci-ar724x: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10697/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-ar724x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-ar724x.c b/arch/mips/pci/pci-ar724x.c index 0af362b5af926..907d11dd921b3 100644 --- a/arch/mips/pci/pci-ar724x.c +++ b/arch/mips/pci/pci-ar724x.c @@ -321,8 +321,8 @@ static void ar724x_pci_irq_init(struct ar724x_pci_controller *apc, irq_set_chip_data(i, apc); } - irq_set_handler_data(apc->irq, apc); - irq_set_chained_handler(apc->irq, ar724x_pci_irq_handler); + irq_set_chained_handler_and_data(apc->irq, ar724x_pci_irq_handler, + apc); } static int ar724x_pci_probe(struct platform_device *pdev) -- GitLab From 586134a84c0e3e503d2e65a117e2cb06f376aac8 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:45:58 +0000 Subject: [PATCH 4974/7006] MIPS: pci-rt3883: Consolidate chained IRQ handler install/remove Chained irq handlers usually set up handler data as well. We now have a function to set both under irq_desc->lock. Replace the two calls with one. Search and conversion was done with coccinelle. Reported-by: Russell King Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10698/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-rt3883.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index 80fafe646e741..c156f48912e8e 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -225,8 +225,7 @@ static int rt3883_pci_irq_init(struct device *dev, return -ENODEV; } - irq_set_handler_data(irq, rpc); - irq_set_chained_handler(irq, rt3883_pci_irq_handler); + irq_set_chained_handler_and_data(irq, rt3883_pci_irq_handler, rpc); return 0; } -- GitLab From 5c1594224fffccb4adb76fb460871e1047accbbd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 13 Jul 2015 20:45:59 +0000 Subject: [PATCH 4975/7006] MIPS: irq: Use access helper irq_data_get_affinity_mask() This is a preparatory patch for moving irq_data struct members. Signed-off-by: Jiang Liu Signed-off-by: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10699/ Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/irq.c | 2 +- arch/mips/cavium-octeon/octeon-irq.c | 14 ++++++++------ arch/mips/pmcs-msp71xx/msp_irq_cic.c | 3 ++- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index e3e808a6c5426..02983b90826da 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -60,7 +60,7 @@ static inline int enable_irq_for_cpu(int cpu, struct irq_data *d, if (m) enable &= cpumask_test_cpu(cpu, m); else if (irqd_affinity_was_set(d)) - enable &= cpumask_test_cpu(cpu, d->affinity); + enable &= cpumask_test_cpu(cpu, irq_data_get_affinity_mask(d)); #endif return enable; } diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index d8124a3c5a853..18bf3dcb9d1b9 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -225,13 +225,14 @@ static int next_cpu_for_irq(struct irq_data *data) #ifdef CONFIG_SMP int cpu; - int weight = cpumask_weight(data->affinity); + struct cpumask *mask = irq_data_get_affinity_mask(data); + int weight = cpumask_weight(mask); struct octeon_ciu_chip_data *cd = irq_data_get_irq_chip_data(data); if (weight > 1) { cpu = cd->current_cpu; for (;;) { - cpu = cpumask_next(cpu, data->affinity); + cpu = cpumask_next(cpu, mask); if (cpu >= nr_cpu_ids) { cpu = -1; continue; @@ -240,7 +241,7 @@ static int next_cpu_for_irq(struct irq_data *data) } } } else if (weight == 1) { - cpu = cpumask_first(data->affinity); + cpu = cpumask_first(mask); } else { cpu = smp_processor_id(); } @@ -712,16 +713,17 @@ static void octeon_irq_cpu_offline_ciu(struct irq_data *data) { int cpu = smp_processor_id(); cpumask_t new_affinity; + struct cpumask *mask = irq_data_get_affinity_mask(data); - if (!cpumask_test_cpu(cpu, data->affinity)) + if (!cpumask_test_cpu(cpu, mask)) return; - if (cpumask_weight(data->affinity) > 1) { + if (cpumask_weight(mask) > 1) { /* * It has multi CPU affinity, just remove this CPU * from the affinity set. */ - cpumask_copy(&new_affinity, data->affinity); + cpumask_copy(&new_affinity, mask); cpumask_clear_cpu(cpu, &new_affinity); } else { /* Otherwise, put it on lowest numbered online CPU. */ diff --git a/arch/mips/pmcs-msp71xx/msp_irq_cic.c b/arch/mips/pmcs-msp71xx/msp_irq_cic.c index 1207ec4dfb770..8b9cf64630406 100644 --- a/arch/mips/pmcs-msp71xx/msp_irq_cic.c +++ b/arch/mips/pmcs-msp71xx/msp_irq_cic.c @@ -88,7 +88,8 @@ static void unmask_cic_irq(struct irq_data *d) * Make sure we have IRQ affinity. It may have changed while * we were processing the IRQ. */ - if (!cpumask_test_cpu(smp_processor_id(), d->affinity)) + if (!cpumask_test_cpu(smp_processor_id(), + irq_data_get_affinity_mask(d))) return; #endif -- GitLab From 5a06545008514ce4b9315284b4ddff31bfa9d77e Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:01 +0000 Subject: [PATCH 4976/7006] MIPS: alchemy: Use irq_set_chip_handler_name_locked() Hand in irq_data and avoid the redundant lookup of irq_desc. Originally-from: Jiang Liu Signed-off-by: Thomas Gleixner Cc: LKML Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10700/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/common/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c index 6cb60abfdcc90..4c496c50edf69 100644 --- a/arch/mips/alchemy/common/irq.c +++ b/arch/mips/alchemy/common/irq.c @@ -491,7 +491,7 @@ static int au1x_ic_settype(struct irq_data *d, unsigned int flow_type) default: ret = -EINVAL; } - __irq_set_chip_handler_name_locked(d->irq, chip, handler, name); + irq_set_chip_handler_name_locked(d, chip, handler, name); wmb(); @@ -703,7 +703,7 @@ static int au1300_gpic_settype(struct irq_data *d, unsigned int type) return -EINVAL; } - __irq_set_chip_handler_name_locked(d->irq, &au1300_gpic, hdl, name); + irq_set_chip_handler_name_locked(d, &au1300_gpic, hdl, name); au1300_gpic_chgcfg(d->irq - ALCHEMY_GPIC_INT_BASE, GPIC_CFG_IC_MASK, s); -- GitLab From 9154566ee3edd0f6a7aa4ef8bed76d3cd57bcb88 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:02 +0000 Subject: [PATCH 4977/7006] MIPS: bcm63xx: Use irq_set_handler_locked() Use irq_set_handler_locked() as it avoids a redundant lookup of the irq descriptor. Search and replacement was done with coccinelle. Signed-off-by: Thomas Gleixner Cc: Jiang Liu Cc: Julia Lawall Cc: Ralf Baechle Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10701/ Signed-off-by: Ralf Baechle --- arch/mips/bcm63xx/irq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/bcm63xx/irq.c b/arch/mips/bcm63xx/irq.c index 02983b90826da..1a47ec2a09062 100644 --- a/arch/mips/bcm63xx/irq.c +++ b/arch/mips/bcm63xx/irq.c @@ -365,9 +365,9 @@ static int bcm63xx_external_irq_set_type(struct irq_data *d, irqd_set_trigger_type(d, flow_type); if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) - __irq_set_handler_locked(d->irq, handle_level_irq); + irq_set_handler_locked(d, handle_level_irq); else - __irq_set_handler_locked(d->irq, handle_edge_irq); + irq_set_handler_locked(d, handle_edge_irq); return IRQ_SET_MASK_OK_NOCOPY; } -- GitLab From e0288a0a7bb8b28787453cb96f7aad272086def1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:04 +0000 Subject: [PATCH 4978/7006] MIPS: alchemy: Remove pointless irqdisable/enable bcsr_csc_handler() is a cascading interrupt handler. It has a disable_irq_nosync()/enable_irq() pair around the generic_handle_irq() call. The value of this disable/enable is zero because its a complete noop: disable_irq_nosync() merily increments the disable count without actually masking the interrupt. enable_irq() soleley decrements the disable count without touching the interrupt chip. The interrupt cannot arrive again because the complete call chain runs with interrupts disabled. Remove it. [ralf@linux-mips.org: Fold in followup fix from Thomas Gleixner.] Signed-off-by: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10702/ Patchwork: https://patchwork.linux-mips.org/patch/10708/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/devboards/bcsr.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/alchemy/devboards/bcsr.c b/arch/mips/alchemy/devboards/bcsr.c index c98c9ea3372c5..324ad72d7c362 100644 --- a/arch/mips/alchemy/devboards/bcsr.c +++ b/arch/mips/alchemy/devboards/bcsr.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -88,10 +89,11 @@ EXPORT_SYMBOL_GPL(bcsr_mod); static void bcsr_csc_handler(unsigned int irq, struct irq_desc *d) { unsigned short bisr = __raw_readw(bcsr_virt + BCSR_REG_INTSTAT); + struct irq_chip *chip = irq_desc_get_chip(d); - disable_irq_nosync(irq); + chained_irq_enter(chip, d); generic_handle_irq(bcsr_csc_base + __ffs(bisr)); - enable_irq(irq); + chained_irq_exit(chip, d); } static void bcsr_irq_mask(struct irq_data *d) -- GitLab From 9d9a2fa7dcbd05a1608a6a38b6ec1a092e117c3c Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:06 +0000 Subject: [PATCH 4979/7006] MIPS: ath91: Remove pointless irqdisable/enable The various interrupt flow handlers in ath79 are cascading interrupt handlers. They all have a disable_irq_nosync()/enable_irq() pair around the generic_handle_irq() call. The value of this disable/enable is zero because its a complete noop: disable_irq_nosync() merily increments the disable count without actually masking the interrupt. enable_irq() soleley decrements the disable count without touching the interrupt chip. The interrupt cannot arrive again because the complete call chain runs with interrupts disabled. Remove it. Signed-off-by: Thomas Gleixner Cc: linux-mips@linux-mips.org Cc: LKML Cc: Jiang Liu Patchwork: https://patchwork.linux-mips.org/patch/10703/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/irq.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/mips/ath79/irq.c b/arch/mips/ath79/irq.c index 2021be20d9d94..807132b838b24 100644 --- a/arch/mips/ath79/irq.c +++ b/arch/mips/ath79/irq.c @@ -123,8 +123,6 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) { u32 status; - disable_irq_nosync(irq); - status = ath79_reset_rr(AR934X_RESET_REG_PCIE_WMAC_INT_STATUS); if (status & AR934X_PCIE_WMAC_INT_PCIE_ALL) { @@ -136,8 +134,6 @@ static void ar934x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) } else { spurious_interrupt(); } - - enable_irq(irq); } static void ar934x_ip2_irq_init(void) @@ -156,14 +152,12 @@ static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) { u32 status; - disable_irq_nosync(irq); - status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); status &= QCA955X_EXT_INT_PCIE_RC1_ALL | QCA955X_EXT_INT_WMAC_ALL; if (status == 0) { spurious_interrupt(); - goto enable; + return; } if (status & QCA955X_EXT_INT_PCIE_RC1_ALL) { @@ -175,17 +169,12 @@ static void qca955x_ip2_irq_dispatch(unsigned int irq, struct irq_desc *desc) /* TODO: flush DDR? */ generic_handle_irq(ATH79_IP2_IRQ(1)); } - -enable: - enable_irq(irq); } static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) { u32 status; - disable_irq_nosync(irq); - status = ath79_reset_rr(QCA955X_RESET_REG_EXT_INT_STATUS); status &= QCA955X_EXT_INT_PCIE_RC2_ALL | QCA955X_EXT_INT_USB1 | @@ -193,7 +182,7 @@ static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) if (status == 0) { spurious_interrupt(); - goto enable; + return; } if (status & QCA955X_EXT_INT_USB1) { @@ -210,9 +199,6 @@ static void qca955x_ip3_irq_dispatch(unsigned int irq, struct irq_desc *desc) /* TODO: flush DDR? */ generic_handle_irq(ATH79_IP3_IRQ(2)); } - -enable: - enable_irq(irq); } static void qca955x_irq_init(void) -- GitLab From 56a86c352b02ce2fe09a72771ef4334632a1f9c1 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:07 +0000 Subject: [PATCH 4980/7006] MIPS: octeon: Replace the homebrewn flow handler The gpio interrupt handling of octeon contains a homebrewn flow handler which calls either handle_level_irq or handle_edge_irq depending on the trigger type. Thats an extra conditional and call in the interrupt handling path. The proper way to handle different types and therefor different flows is to update the handler in the irq_set_type() callback. Remove the extra indirection and add the handler update to octeon_irq_ciu_gpio_set_type(). At mapping time it defaults to handle_level_irq which gets updated if the device tree contains a different trigger type. Signed-off-by: Thomas Gleixner Cc: David Daney Cc: Jiang Liu Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10704/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/octeon-irq.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/arch/mips/cavium-octeon/octeon-irq.c b/arch/mips/cavium-octeon/octeon-irq.c index 18bf3dcb9d1b9..f26c3c661cca9 100644 --- a/arch/mips/cavium-octeon/octeon-irq.c +++ b/arch/mips/cavium-octeon/octeon-irq.c @@ -663,6 +663,11 @@ static int octeon_irq_ciu_gpio_set_type(struct irq_data *data, unsigned int t) irqd_set_trigger_type(data, t); octeon_irq_gpio_setup(data); + if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) + irq_set_handler_locked(data, handle_edge_irq); + else + irq_set_handler_locked(data, handle_level_irq); + return IRQ_SET_MASK_OK; } @@ -697,16 +702,6 @@ static void octeon_irq_ciu_gpio_ack(struct irq_data *data) cvmx_write_csr(CVMX_GPIO_INT_CLR, mask); } -static void octeon_irq_handle_trigger(unsigned int irq, struct irq_desc *desc) -{ - struct irq_data *data = irq_desc_get_irq_data(desc); - - if (irqd_get_trigger_type(data) & IRQ_TYPE_EDGE_BOTH) - handle_edge_irq(irq, desc); - else - handle_level_irq(irq, desc); -} - #ifdef CONFIG_SMP static void octeon_irq_cpu_offline_ciu(struct irq_data *data) @@ -1229,8 +1224,13 @@ static int octeon_irq_gpio_map(struct irq_domain *d, octeon_irq_ciu_to_irq[line][bit] != 0) return -EINVAL; + /* + * Default to handle_level_irq. If the DT contains a different + * trigger type, it will call the irq_set_type callback and + * the handler gets updated. + */ r = octeon_irq_set_ciu_mapping(virq, line, bit, hw, - octeon_irq_gpio_chip, octeon_irq_handle_trigger); + octeon_irq_gpio_chip, handle_level_irq); return r; } -- GitLab From 31429d1a74c01875d7dad72a6a1d75d8eeca2bc6 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:09 +0000 Subject: [PATCH 4981/7006] MIPS: netlogic: Prepare ipi handlers for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10705/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/common/smp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/netlogic/common/smp.c b/arch/mips/netlogic/common/smp.c index f5fff228b347b..0136b4f9c9cde 100644 --- a/arch/mips/netlogic/common/smp.c +++ b/arch/mips/netlogic/common/smp.c @@ -82,8 +82,9 @@ void nlm_send_ipi_mask(const struct cpumask *mask, unsigned int action) } /* IRQ_IPI_SMP_FUNCTION Handler */ -void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) +void nlm_smp_function_ipi_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); clear_c0_eimr(irq); ack_c0_eirr(irq); generic_smp_call_function_interrupt(); @@ -91,8 +92,9 @@ void nlm_smp_function_ipi_handler(unsigned int irq, struct irq_desc *desc) } /* IRQ_IPI_SMP_RESCHEDULE handler */ -void nlm_smp_resched_ipi_handler(unsigned int irq, struct irq_desc *desc) +void nlm_smp_resched_ipi_handler(unsigned int __irq, struct irq_desc *desc) { + unsigned int irq = irq_desc_get_irq(desc); clear_c0_eimr(irq); ack_c0_eirr(irq); scheduler_ipi(); -- GitLab From e51395d2739d0bb4991b6b531e1066475aae9bfd Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Mon, 13 Jul 2015 20:46:10 +0000 Subject: [PATCH 4982/7006] MIPS: rt3883: Prepare rt3883_pci_irq_handler for irq argument removal The irq argument of most interrupt flow handlers is unused or merily used instead of a local variable. The handlers which need the irq argument can retrieve the irq number from the irq descriptor. Search and update was done with coccinelle and the invaluable help of Julia Lawall. Signed-off-by: Thomas Gleixner Cc: Julia Lawall Cc: Jiang Liu Cc: linux-mips@linux-mips.org Cc: LKML Patchwork: https://patchwork.linux-mips.org/patch/10706/ Signed-off-by: Ralf Baechle --- arch/mips/pci/pci-rt3883.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/pci/pci-rt3883.c b/arch/mips/pci/pci-rt3883.c index c156f48912e8e..53c8efaf15723 100644 --- a/arch/mips/pci/pci-rt3883.c +++ b/arch/mips/pci/pci-rt3883.c @@ -129,7 +129,7 @@ static void rt3883_pci_write_cfg32(struct rt3883_pci_controller *rpc, rt3883_pci_w32(rpc, val, RT3883_PCI_REG_CFGDATA); } -static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) +static void rt3883_pci_irq_handler(unsigned int __irq, struct irq_desc *desc) { struct rt3883_pci_controller *rpc; u32 pending; @@ -145,7 +145,7 @@ static void rt3883_pci_irq_handler(unsigned int irq, struct irq_desc *desc) } while (pending) { - unsigned bit = __ffs(pending); + unsigned irq, bit = __ffs(pending); irq = irq_find_mapping(rpc->irq_domain, bit); generic_handle_irq(irq); -- GitLab From 2dca88da835616c3c65d1e4167288346fd67f02f Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 13 Jul 2015 17:14:21 +0100 Subject: [PATCH 4983/7006] MIPS: ops-emma2rh: Drop nonsensical db_assert The db_assert call checks whether the bus_num pointer is non-NULL, but does so after said pointer has been dereferenced by the assignment on the previous line. Thus the check is pointless & likely to have been optimised out by the compiler anyway. The check_args function is static & only ever called from the local file with bus_num being a pointer to an on-stack variable, so the check seems somewhat overzealous anyway. Simply remove it. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10692/ Signed-off-by: Ralf Baechle --- arch/mips/pci/ops-emma2rh.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/arch/mips/pci/ops-emma2rh.c b/arch/mips/pci/ops-emma2rh.c index 710aef5c070e8..2dc97c45685e8 100644 --- a/arch/mips/pci/ops-emma2rh.c +++ b/arch/mips/pci/ops-emma2rh.c @@ -25,7 +25,6 @@ #include #include -#include #include @@ -40,10 +39,9 @@ static int check_args(struct pci_bus *bus, u32 devfn, u32 * bus_num) { /* check if the bus is top-level */ - if (bus->parent != NULL) { + if (bus->parent != NULL) *bus_num = bus->number; - db_assert(bus_num != NULL); - } else + else *bus_num = 0; if (*bus_num == 0) { -- GitLab From 9b4685de77afd688407fd56cc350083a0a6a0516 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 13 Jul 2015 17:14:22 +0100 Subject: [PATCH 4984/7006] MIPS: Drop CONFIG_RUNTIME_DEBUG & debug.h The debug.h header provided some MIPS-specific debug macros, which are no longer used at all. Remove them. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10693/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig.debug | 9 ------- arch/mips/include/asm/debug.h | 48 ----------------------------------- 2 files changed, 57 deletions(-) delete mode 100644 arch/mips/include/asm/debug.h diff --git a/arch/mips/Kconfig.debug b/arch/mips/Kconfig.debug index 3a2b775e84589..e250524021aca 100644 --- a/arch/mips/Kconfig.debug +++ b/arch/mips/Kconfig.debug @@ -87,15 +87,6 @@ config SB1XXX_CORELIS Select compile flags that produce code that can be processed by the Corelis mksym utility and UDB Emulator. -config RUNTIME_DEBUG - bool "Enable run-time debugging" - depends on DEBUG_KERNEL - help - If you say Y here, some debugging macros will do run-time checking. - If you say N here, those macros will mostly turn to no-ops. See - arch/mips/include/asm/debug.h for debugging macros. - If unsure, say N. - config DEBUG_ZBOOT bool "Enable compressed kernel support debugging" depends on DEBUG_KERNEL && SYS_SUPPORTS_ZBOOT diff --git a/arch/mips/include/asm/debug.h b/arch/mips/include/asm/debug.h deleted file mode 100644 index 1fd5a2b39445a..0000000000000 --- a/arch/mips/include/asm/debug.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Debug macros for run-time debugging. - * Turned on/off with CONFIG_RUNTIME_DEBUG option. - * - * Copyright (C) 2001 MontaVista Software Inc. - * Author: Jun Sun, jsun@mvista.com or jsun@junsun.net - * - * 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 _ASM_DEBUG_H -#define _ASM_DEBUG_H - - -/* - * run-time macros for catching spurious errors. Eable CONFIG_RUNTIME_DEBUG in - * kernel hacking config menu to use them. - * - * Use them as run-time debugging aid. NEVER USE THEM AS ERROR HANDLING CODE!!! - */ - -#ifdef CONFIG_RUNTIME_DEBUG - -#include - -#define db_assert(x) if (!(x)) { \ - panic("assertion failed at %s:%d: %s", __FILE__, __LINE__, #x); } -#define db_warn(x) if (!(x)) { \ - printk(KERN_WARNING "warning at %s:%d: %s", __FILE__, __LINE__, #x); } -#define db_verify(x, y) db_assert(x y) -#define db_verify_warn(x, y) db_warn(x y) -#define db_run(x) do { x; } while (0) - -#else - -#define db_assert(x) -#define db_warn(x) -#define db_verify(x, y) x -#define db_verify_warn(x, y) x -#define db_run(x) - -#endif - -#endif /* _ASM_DEBUG_H */ -- GitLab From 8dedde6b289c51ba216fdf5467fc85a673775489 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:10:56 -0500 Subject: [PATCH 4985/7006] MIPS: CPC: Remove "weak" from mips_cpc_phys_base() and make it static There's only one implementation of mips_cpc_phys_base(), and it's only used within the same file, so it doesn't need to be weak, and it doesn't need an extern declaration. Remove the extern mips_cpc_phys_base() declaration and make it static. [ralf@linux-mips.org: Fixed conflict.] Signed-off-by: Bjorn Helgaas CC: linux-mips@linux-mips.org Cc: Andrew Bresticker Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10681/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mips-cpc.h | 10 ---------- arch/mips/kernel/mips-cpc.c | 9 ++++++++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/arch/mips/include/asm/mips-cpc.h b/arch/mips/include/asm/mips-cpc.h index 1cebe8c790513..f386f32702f17 100644 --- a/arch/mips/include/asm/mips-cpc.h +++ b/arch/mips/include/asm/mips-cpc.h @@ -27,16 +27,6 @@ extern void __iomem *mips_cpc_base; */ extern phys_addr_t mips_cpc_default_phys_base(void); -/** - * mips_cpc_phys_base - retrieve the physical base address of the CPC - * - * This function returns the physical base address of the Cluster Power - * Controller memory mapped registers, or 0 if no Cluster Power Controller - * is present. It may be overriden by individual platforms which determine - * this address in a different way. - */ -extern phys_addr_t __weak mips_cpc_phys_base(void); - /** * mips_cpc_probe - probe for a Cluster Power Controller * diff --git a/arch/mips/kernel/mips-cpc.c b/arch/mips/kernel/mips-cpc.c index e05aca41e087e..8af4d627b68b9 100644 --- a/arch/mips/kernel/mips-cpc.c +++ b/arch/mips/kernel/mips-cpc.c @@ -21,7 +21,14 @@ static DEFINE_PER_CPU_ALIGNED(spinlock_t, cpc_core_lock); static DEFINE_PER_CPU_ALIGNED(unsigned long, cpc_core_lock_flags); -phys_addr_t __weak mips_cpc_phys_base(void) +/** + * mips_cpc_phys_base - retrieve the physical base address of the CPC + * + * This function returns the physical base address of the Cluster Power + * Controller memory mapped registers, or 0 if no Cluster Power Controller + * is present. + */ +static phys_addr_t mips_cpc_phys_base(void) { unsigned long cpc_base; -- GitLab From 27d8d449ba7c553e9e004aaa07b225625b20fd2d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:04 -0500 Subject: [PATCH 4986/7006] MIPS: Remove "weak" from platform_maar_init() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). platform_maar_init() is defined in: - arch/mips/mm/init.c (where it is marked "weak") - arch/mips/mti-malta/malta-memory.c (without annotation) The "weak" attribute on the platform_maar_init() extern declaration applies to the platform-specific definition in arch/mips/mti-malta/malta-memory.c, so both definitions are weak, and which one we get depends on link order. Remove the "weak" attribute from the declaration. That makes the malta definition strong, so it will always be preferred if it is present. Signed-off-by: Bjorn Helgaas CC: linux-mips@linux-mips.org Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10682/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/maar.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/maar.h b/arch/mips/include/asm/maar.h index 6c62b0f899c0f..b02891f9caaf1 100644 --- a/arch/mips/include/asm/maar.h +++ b/arch/mips/include/asm/maar.h @@ -26,7 +26,7 @@ * * Return: The number of MAAR pairs configured. */ -unsigned __weak platform_maar_init(unsigned num_pairs); +unsigned platform_maar_init(unsigned num_pairs); /** * write_maar_pair() - write to a pair of MAARs -- GitLab From 1c205b9cc6f66c5caa91fa2644dcf75254c3bfe1 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:12 -0500 Subject: [PATCH 4987/7006] MIPS: VPE: Exit vpe_release() early if vpe_run() isn't defined vpe_run() is a weak symbol. If there's no definition of it, its value is zero. If vpe_run is zero, return failure early. We're going to fail anyway, so there's no point in getting a VPE and attempting to load it. Signed-off-by: Bjorn Helgaas Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10683/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/vpe.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 11da314565cc3..72cae9f554609 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -821,13 +821,18 @@ static int vpe_release(struct inode *inode, struct file *filp) Elf_Ehdr *hdr; int ret = 0; + if (!vpe_run) { + pr_warn("VPE loader: ELF load failed.\n"); + return -ENOEXEC; + } + v = get_vpe(aprp_cpu_index()); if (v == NULL) return -ENODEV; hdr = (Elf_Ehdr *) v->pbuffer; if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) { - if ((vpe_elfload(v) >= 0) && vpe_run) { + if (vpe_elfload(v) >= 0) { vpe_run(v); } else { pr_warn("VPE loader: ELF load failed.\n"); -- GitLab From c60f99445aed684b5a8d84dcb84f5a06c1f70430 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:20 -0500 Subject: [PATCH 4988/7006] MIPS: MT: Remove "weak" from vpe_run() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). That's not a problem for vpe_run() because Kconfig ensures there's never more than one definition: - vpe_run() is defined in arch/mips/kernel/vpe-mt.c if CONFIG_MIPS_VPE_LOADER_MT=y - vpe_run() is defined in arch/mips/mti-malta/malta-amon.c if CONFIG_MIPS_CMP=y - CONFIG_MIPS_VPE_LOADER_MT cannot be set if CONFIG_MIPS_CMP=y But it's simpler to verify correctness if we remove "weak" from the picture and test the config symbols directly. Remove "weak" from the vpe_run() declaration and use #if to test whether a definition should be present. Signed-off-by: Bjorn Helgaas Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: James Hogan Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10684/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/vpe.h | 2 +- arch/mips/kernel/vpe.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/mips/include/asm/vpe.h b/arch/mips/include/asm/vpe.h index 7849f3978feaf..80e70dbd1f641 100644 --- a/arch/mips/include/asm/vpe.h +++ b/arch/mips/include/asm/vpe.h @@ -122,7 +122,7 @@ void release_vpe(struct vpe *v); void *alloc_progmem(unsigned long len); void release_progmem(void *ptr); -int __weak vpe_run(struct vpe *v); +int vpe_run(struct vpe *v); void cleanup_tc(struct tc *tc); int __init vpe_module_init(void); diff --git a/arch/mips/kernel/vpe.c b/arch/mips/kernel/vpe.c index 72cae9f554609..9067b651c7a2d 100644 --- a/arch/mips/kernel/vpe.c +++ b/arch/mips/kernel/vpe.c @@ -817,15 +817,11 @@ static int vpe_open(struct inode *inode, struct file *filp) static int vpe_release(struct inode *inode, struct file *filp) { +#if defined(CONFIG_MIPS_VPE_LOADER_MT) || defined(CONFIG_MIPS_VPE_LOADER_CMP) struct vpe *v; Elf_Ehdr *hdr; int ret = 0; - if (!vpe_run) { - pr_warn("VPE loader: ELF load failed.\n"); - return -ENOEXEC; - } - v = get_vpe(aprp_cpu_index()); if (v == NULL) return -ENODEV; @@ -855,6 +851,10 @@ static int vpe_release(struct inode *inode, struct file *filp) v->plen = 0; return ret; +#else + pr_warn("VPE loader: ELF load failed.\n"); + return -ENOEXEC; +#endif } static ssize_t vpe_write(struct file *file, const char __user *buffer, -- GitLab From 47ab154593827b1a8f0713a2b9dd445753d551d8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 25 Aug 2015 16:09:00 +0200 Subject: [PATCH 4989/7006] ALSA: usb-audio: Avoid nested autoresume calls After the recent fix of runtime PM for USB-audio driver, we got a lockdep warning like: ============================================= [ INFO: possible recursive locking detected ] 4.2.0-rc8+ #61 Not tainted --------------------------------------------- pulseaudio/980 is trying to acquire lock: (&chip->shutdown_rwsem){.+.+.+}, at: [] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio] but task is already holding lock: (&chip->shutdown_rwsem){.+.+.+}, at: [] snd_usb_autoresume+0x1d/0x52 [snd_usb_audio] This comes from snd_usb_autoresume() invoking down_read() and it's used in a nested way. Although it's basically safe, per se (as these are read locks), it's better to reduce such spurious warnings. The read lock is needed to guarantee the execution of "shutdown" (cleanup at disconnection) task after all concurrent tasks are finished. This can be implemented in another better way. Also, the current check of chip->in_pm isn't good enough for protecting the racy execution of multiple auto-resumes. This patch rewrites the logic of snd_usb_autoresume() & co; namely, - The recursive call of autopm is avoided by the new refcount, chip->active. The chip->in_pm flag is removed accordingly. - Instead of rwsem, another refcount, chip->usage_count, is introduced for tracking the period to delay the shutdown procedure. At the last clear of this refcount, wake_up() to the shutdown waiter is called. - The shutdown flag is replaced with shutdown atomic count; this is for reducing the lock. - Two new helpers are introduced to simplify the management of these refcounts; snd_usb_lock_shutdown() increases the usage_count, checks the shutdown state, and does autoresume. snd_usb_unlock_shutdown() does the opposite. Most of mixer and other codes just need this, and simply returns an error if it receives an error from lock. Fixes: 9003ebb13f61 ('ALSA: usb-audio: Fix runtime PM unbalance') Reported-and-tested-by: Alexnader Kuleshov Signed-off-by: Takashi Iwai --- sound/usb/card.c | 74 ++++++++++++++++------- sound/usb/endpoint.c | 10 ++-- sound/usb/mixer.c | 32 ++++------ sound/usb/mixer_quirks.c | 126 +++++++++++++++++---------------------- sound/usb/pcm.c | 32 +++++----- sound/usb/proc.c | 4 +- sound/usb/usbaudio.h | 10 +++- 7 files changed, 145 insertions(+), 143 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 0450593980fd3..b6621bcba2dc8 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -365,13 +365,15 @@ static int snd_usb_audio_create(struct usb_interface *intf, } mutex_init(&chip->mutex); - init_rwsem(&chip->shutdown_rwsem); + init_waitqueue_head(&chip->shutdown_wait); chip->index = idx; chip->dev = dev; chip->card = card; chip->setup = device_setup[idx]; chip->autoclock = autoclock; chip->probing = 1; + atomic_set(&chip->usage_count, 0); + atomic_set(&chip->shutdown, 0); chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); @@ -495,7 +497,7 @@ static int usb_audio_probe(struct usb_interface *intf, mutex_lock(®ister_mutex); for (i = 0; i < SNDRV_CARDS; i++) { if (usb_chip[i] && usb_chip[i]->dev == dev) { - if (usb_chip[i]->shutdown) { + if (atomic_read(&usb_chip[i]->shutdown)) { dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n"); err = -EIO; goto __error; @@ -585,23 +587,23 @@ static void usb_audio_disconnect(struct usb_interface *intf) struct snd_usb_audio *chip = usb_get_intfdata(intf); struct snd_card *card; struct list_head *p; - bool was_shutdown; if (chip == (void *)-1L) return; card = chip->card; - down_write(&chip->shutdown_rwsem); - was_shutdown = chip->shutdown; - chip->shutdown = 1; - up_write(&chip->shutdown_rwsem); mutex_lock(®ister_mutex); - if (!was_shutdown) { + if (atomic_inc_return(&chip->shutdown) == 1) { struct snd_usb_stream *as; struct snd_usb_endpoint *ep; struct usb_mixer_interface *mixer; + /* wait until all pending tasks done; + * they are protected by snd_usb_lock_shutdown() + */ + wait_event(chip->shutdown_wait, + !atomic_read(&chip->usage_count)); snd_card_disconnect(card); /* release the pcm resources */ list_for_each_entry(as, &chip->pcm_list, list) { @@ -631,28 +633,54 @@ static void usb_audio_disconnect(struct usb_interface *intf) } } -#ifdef CONFIG_PM - -int snd_usb_autoresume(struct snd_usb_audio *chip) +/* lock the shutdown (disconnect) task and autoresume */ +int snd_usb_lock_shutdown(struct snd_usb_audio *chip) { - int err = -ENODEV; + int err; - down_read(&chip->shutdown_rwsem); - if (chip->probing || chip->in_pm) - err = 0; - else if (!chip->shutdown) - err = usb_autopm_get_interface(chip->pm_intf); - up_read(&chip->shutdown_rwsem); + atomic_inc(&chip->usage_count); + if (atomic_read(&chip->shutdown)) { + err = -EIO; + goto error; + } + err = snd_usb_autoresume(chip); + if (err < 0) + goto error; + return 0; + error: + if (atomic_dec_and_test(&chip->usage_count)) + wake_up(&chip->shutdown_wait); return err; } +/* autosuspend and unlock the shutdown */ +void snd_usb_unlock_shutdown(struct snd_usb_audio *chip) +{ + snd_usb_autosuspend(chip); + if (atomic_dec_and_test(&chip->usage_count)) + wake_up(&chip->shutdown_wait); +} + +#ifdef CONFIG_PM + +int snd_usb_autoresume(struct snd_usb_audio *chip) +{ + if (atomic_read(&chip->shutdown)) + return -EIO; + if (chip->probing) + return 0; + if (atomic_inc_return(&chip->active) == 1) + return usb_autopm_get_interface(chip->pm_intf); + return 0; +} + void snd_usb_autosuspend(struct snd_usb_audio *chip) { - down_read(&chip->shutdown_rwsem); - if (!chip->shutdown && !chip->probing && !chip->in_pm) + if (chip->probing) + return; + if (atomic_dec_and_test(&chip->active)) usb_autopm_put_interface(chip->pm_intf); - up_read(&chip->shutdown_rwsem); } static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) @@ -705,7 +733,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) if (--chip->num_suspended_intf) return 0; - chip->in_pm = 1; + atomic_inc(&chip->active); /* avoid autopm */ /* * ALSA leaves material resumption to user space * we just notify and restart the mixers @@ -725,7 +753,7 @@ static int __usb_audio_resume(struct usb_interface *intf, bool reset_resume) chip->autosuspended = 0; err_out: - chip->in_pm = 0; + atomic_dec(&chip->active); /* allow autopm after this point */ return err; } diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 03b0744199649..e6f71894ecdc9 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -355,8 +355,10 @@ static void snd_complete_urb(struct urb *urb) if (unlikely(urb->status == -ENOENT || /* unlinked */ urb->status == -ENODEV || /* device removed */ urb->status == -ECONNRESET || /* unlinked */ - urb->status == -ESHUTDOWN || /* device disabled */ - ep->chip->shutdown)) /* device disconnected */ + urb->status == -ESHUTDOWN)) /* device disabled */ + goto exit_clear; + /* device disconnected */ + if (unlikely(atomic_read(&ep->chip->shutdown))) goto exit_clear; if (usb_pipeout(ep->pipe)) { @@ -529,7 +531,7 @@ static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force) { unsigned int i; - if (!force && ep->chip->shutdown) /* to be sure... */ + if (!force && atomic_read(&ep->chip->shutdown)) /* to be sure... */ return -EBADFD; clear_bit(EP_FLAG_RUNNING, &ep->flags); @@ -868,7 +870,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep) int err; unsigned int i; - if (ep->chip->shutdown) + if (atomic_read(&ep->chip->shutdown)) return -EBADFD; /* already running? */ diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index c50790cb3f4d7..fd5c49e948672 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -311,14 +311,11 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int timeout = 10; int idx = 0, err; - err = snd_usb_autoresume(chip); + err = snd_usb_lock_shutdown(chip); if (err < 0) return -EIO; - down_read(&chip->shutdown_rwsem); while (timeout-- > 0) { - if (chip->shutdown) - break; idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, @@ -334,8 +331,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, err = -EINVAL; out: - up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(chip); + snd_usb_unlock_shutdown(chip); return err; } @@ -358,21 +354,15 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, memset(buf, 0, sizeof(buf)); - ret = snd_usb_autoresume(chip) ? -EIO : 0; + ret = snd_usb_lock_shutdown(chip) ? -EIO : 0; if (ret) goto error; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - ret = -ENODEV; - } else { - idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); - ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, + idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); + ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, validx, idx, buf, size); - } - up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(chip); + snd_usb_unlock_shutdown(chip); if (ret < 0) { error: @@ -485,13 +475,12 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, buf[1] = (value_set >> 8) & 0xff; buf[2] = (value_set >> 16) & 0xff; buf[3] = (value_set >> 24) & 0xff; - err = snd_usb_autoresume(chip); + + err = snd_usb_lock_shutdown(chip); if (err < 0) return -EIO; - down_read(&chip->shutdown_rwsem); + while (timeout-- > 0) { - if (chip->shutdown) - break; idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); if (snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), request, @@ -506,8 +495,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval, err = -EINVAL; out: - up_read(&chip->shutdown_rwsem); - snd_usb_autosuspend(chip); + snd_usb_unlock_shutdown(chip); return err; } diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 337c317ead6fb..d3608c0a29f34 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c @@ -308,11 +308,10 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, struct snd_usb_audio *chip = mixer->chip; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto out; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + if (chip->usb_id == USB_ID(0x041e, 0x3042)) err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 0x24, @@ -329,8 +328,7 @@ static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer, usb_sndctrlpipe(chip->dev, 0), 0x24, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, value, index + 2, NULL, 0); - out: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -441,16 +439,15 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, for (i = 0; jacks[i].name; ++i) { snd_iprintf(buffer, "%s: ", jacks[i].name); - down_read(&mixer->chip->shutdown_rwsem); - if (mixer->chip->shutdown) - err = 0; - else - err = snd_usb_ctl_msg(mixer->chip->dev, + err = snd_usb_lock_shutdown(mixer->chip); + if (err < 0) + return; + err = snd_usb_ctl_msg(mixer->chip->dev, usb_rcvctrlpipe(mixer->chip->dev, 0), UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0, jacks[i].unitid << 8, buf, 3); - up_read(&mixer->chip->shutdown_rwsem); + snd_usb_unlock_shutdown(mixer->chip); if (err == 3 && (buf[0] == 3 || buf[0] == 6)) snd_iprintf(buffer, "%02x %02x\n", buf[1], buf[2]); else @@ -481,11 +478,9 @@ static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, int err; unsigned char buf[2]; - down_read(&chip->shutdown_rwsem); - if (mixer->chip->shutdown) { - err = -ENODEV; - goto out; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; buf[0] = 0x01; buf[1] = value ? 0x02 : 0x01; @@ -493,8 +488,7 @@ static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, 0x0400, 0x0e00, buf, 2); - out: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -554,15 +548,14 @@ static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer, struct snd_usb_audio *chip = mixer->chip; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(chip->dev, + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), 0x08, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 50, 0, &status, 1); - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -623,11 +616,9 @@ static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val) int err; unsigned char buff[3]; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto err; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; /* Prepare for magic command to toggle clock source */ err = snd_usb_ctl_msg(chip->dev, @@ -683,7 +674,7 @@ static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val) goto err; err: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -778,15 +769,14 @@ static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list) unsigned int pval = list->kctl->private_value; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) - err = -ENODEV; - else - err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), - (pval >> 16) & 0xff, - USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, - pval >> 24, pval & 0xffff, NULL, 0, 1000); - up_read(&chip->shutdown_rwsem); + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), + (pval >> 16) & 0xff, + USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, + pval >> 24, pval & 0xffff, NULL, 0, 1000); + snd_usb_unlock_shutdown(chip); return err; } @@ -944,18 +934,17 @@ static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list) value[0] = pval >> 24; value[1] = 0; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) - err = -ENODEV; - else - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), - UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - pval & 0xff00, - snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), - value, 2); - up_read(&chip->shutdown_rwsem); + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; + err = snd_usb_ctl_msg(chip->dev, + usb_sndctrlpipe(chip->dev, 0), + UAC_SET_CUR, + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, + pval & 0xff00, + snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8), + value, 2); + snd_usb_unlock_shutdown(chip); return err; } @@ -1519,11 +1508,9 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, unsigned char data[3]; int rate; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto end; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff; ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff; @@ -1551,7 +1538,7 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol, err = 0; end: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -1562,11 +1549,9 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) u8 reg; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto end; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; reg = ((pval >> 4) & 0xf0) | (pval & 0x0f); err = snd_usb_ctl_msg(chip->dev, @@ -1594,7 +1579,7 @@ static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list) goto end; end: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } @@ -1650,11 +1635,9 @@ static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) u8 reg = list->kctl->private_value; int err; - down_read(&chip->shutdown_rwsem); - if (chip->shutdown) { - err = -ENODEV; - goto end; - } + err = snd_usb_lock_shutdown(chip); + if (err < 0) + return err; err = snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), @@ -1665,8 +1648,7 @@ static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list) NULL, 0); - end: - up_read(&chip->shutdown_rwsem); + snd_usb_unlock_shutdown(chip); return err; } diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 30797269d5aad..cdac5179db3f3 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -80,7 +80,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream unsigned int hwptr_done; subs = (struct snd_usb_substream *)substream->runtime->private_data; - if (subs->stream->chip->shutdown) + if (atomic_read(&subs->stream->chip->shutdown)) return SNDRV_PCM_POS_XRUN; spin_lock(&subs->lock); hwptr_done = subs->hwptr_done; @@ -735,12 +735,11 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - down_read(&subs->stream->chip->shutdown_rwsem); - if (subs->stream->chip->shutdown) - ret = -ENODEV; - else - ret = set_format(subs, fmt); - up_read(&subs->stream->chip->shutdown_rwsem); + ret = snd_usb_lock_shutdown(subs->stream->chip); + if (ret < 0) + return ret; + ret = set_format(subs, fmt); + snd_usb_unlock_shutdown(subs->stream->chip); if (ret < 0) return ret; @@ -763,13 +762,12 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; - down_read(&subs->stream->chip->shutdown_rwsem); - if (!subs->stream->chip->shutdown) { + if (!snd_usb_lock_shutdown(subs->stream->chip)) { stop_endpoints(subs, true); snd_usb_endpoint_deactivate(subs->sync_endpoint); snd_usb_endpoint_deactivate(subs->data_endpoint); + snd_usb_unlock_shutdown(subs->stream->chip); } - up_read(&subs->stream->chip->shutdown_rwsem); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -791,11 +789,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return -ENXIO; } - down_read(&subs->stream->chip->shutdown_rwsem); - if (subs->stream->chip->shutdown) { - ret = -ENODEV; - goto unlock; - } + ret = snd_usb_lock_shutdown(subs->stream->chip); + if (ret < 0) + return ret; if (snd_BUG_ON(!subs->data_endpoint)) { ret = -EIO; goto unlock; @@ -844,7 +840,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) ret = start_endpoints(subs, true); unlock: - up_read(&subs->stream->chip->shutdown_rwsem); + snd_usb_unlock_shutdown(subs->stream->chip); return ret; } @@ -1246,9 +1242,11 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) stop_endpoints(subs, true); - if (!as->chip->shutdown && subs->interface >= 0) { + if (subs->interface >= 0 && + !snd_usb_lock_shutdown(subs->stream->chip)) { usb_set_interface(subs->dev, subs->interface, 0); subs->interface = -1; + snd_usb_unlock_shutdown(subs->stream->chip); } subs->pcm_substream = NULL; diff --git a/sound/usb/proc.c b/sound/usb/proc.c index 5f761ab34c014..0ac89e294d31d 100644 --- a/sound/usb/proc.c +++ b/sound/usb/proc.c @@ -46,14 +46,14 @@ static inline unsigned get_high_speed_hz(unsigned int usb_rate) static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_audio *chip = entry->private_data; - if (!chip->shutdown) + if (!atomic_read(&chip->shutdown)) snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum); } static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct snd_usb_audio *chip = entry->private_data; - if (!chip->shutdown) + if (!atomic_read(&chip->shutdown)) snd_iprintf(buffer, "%04x:%04x\n", USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 91d0380431b4f..eb1ea7182cddb 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -37,11 +37,12 @@ struct snd_usb_audio { struct usb_interface *pm_intf; u32 usb_id; struct mutex mutex; - struct rw_semaphore shutdown_rwsem; - unsigned int shutdown:1; unsigned int probing:1; - unsigned int in_pm:1; unsigned int autosuspended:1; + atomic_t active; + atomic_t shutdown; + atomic_t usage_count; + wait_queue_head_t shutdown_wait; unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ int num_interfaces; @@ -115,4 +116,7 @@ struct snd_usb_audio_quirk { #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) +int snd_usb_lock_shutdown(struct snd_usb_audio *chip); +void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); + #endif /* __USBAUDIO_H */ -- GitLab From a6da499b76b1a75412f047ac388e9ffd69a5c55b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Aug 2015 10:20:59 +0200 Subject: [PATCH 4990/7006] ALSA: usb-audio: Replace probing flag with active refcount We can use active refcount for preventing autopm during probe. Signed-off-by: Takashi Iwai --- sound/usb/card.c | 12 ++++-------- sound/usb/usbaudio.h | 1 - 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index b6621bcba2dc8..73c5833e76574 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -371,7 +371,7 @@ static int snd_usb_audio_create(struct usb_interface *intf, chip->card = card; chip->setup = device_setup[idx]; chip->autoclock = autoclock; - chip->probing = 1; + atomic_set(&chip->active, 1); /* avoid autopm during probing */ atomic_set(&chip->usage_count, 0); atomic_set(&chip->shutdown, 0); @@ -503,7 +503,7 @@ static int usb_audio_probe(struct usb_interface *intf, goto __error; } chip = usb_chip[i]; - chip->probing = 1; + atomic_inc(&chip->active); /* avoid autopm */ break; } } @@ -563,8 +563,8 @@ static int usb_audio_probe(struct usb_interface *intf, usb_chip[chip->index] = chip; chip->num_interfaces++; - chip->probing = 0; usb_set_intfdata(intf, chip); + atomic_dec(&chip->active); mutex_unlock(®ister_mutex); return 0; @@ -572,7 +572,7 @@ static int usb_audio_probe(struct usb_interface *intf, if (chip) { if (!chip->num_interfaces) snd_card_free(chip->card); - chip->probing = 0; + atomic_dec(&chip->active); } mutex_unlock(®ister_mutex); return err; @@ -668,8 +668,6 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) { if (atomic_read(&chip->shutdown)) return -EIO; - if (chip->probing) - return 0; if (atomic_inc_return(&chip->active) == 1) return usb_autopm_get_interface(chip->pm_intf); return 0; @@ -677,8 +675,6 @@ int snd_usb_autoresume(struct snd_usb_audio *chip) void snd_usb_autosuspend(struct snd_usb_audio *chip) { - if (chip->probing) - return; if (atomic_dec_and_test(&chip->active)) usb_autopm_put_interface(chip->pm_intf); } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index eb1ea7182cddb..33a176437e2e4 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -37,7 +37,6 @@ struct snd_usb_audio { struct usb_interface *pm_intf; u32 usb_id; struct mutex mutex; - unsigned int probing:1; unsigned int autosuspended:1; atomic_t active; atomic_t shutdown; -- GitLab From e819cdb198319cccf4af4fc12ac4d796109d8c23 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 3 Jul 2015 11:53:03 +0300 Subject: [PATCH 4991/7006] mptfusion: prevent some memory corruption These are signed values the come from the user, we put a cap on the upper bounds but not on the lower bounds. We use "karg.dataSgeOffset" to calculate "sz". We verify "sz" and proceed as if that means that "karg.dataSgeOffset" is correct but this fails to consider that the "sz" calculations can have integer overflows. Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/message/fusion/mptctl.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 70bb7530b22cc..fc73937290812 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -1859,6 +1859,15 @@ mptctl_do_mpt_command (struct mpt_ioctl_command karg, void __user *mfPtr) } spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags); + /* Basic sanity checks to prevent underflows or integer overflows */ + if (karg.maxReplyBytes < 0 || + karg.dataInSize < 0 || + karg.dataOutSize < 0 || + karg.dataSgeOffset < 0 || + karg.maxSenseBytes < 0 || + karg.dataSgeOffset > ioc->req_sz / 4) + return -EINVAL; + /* Verify that the final request frame will not be too large. */ sz = karg.dataSgeOffset * 4; -- GitLab From 0662292aec0528363df037ad7c66bf9949c7ce46 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 26 Aug 2015 10:23:26 +0200 Subject: [PATCH 4992/7006] ALSA: usb-audio: Handle normal and auto-suspend equally In theory, the device may get suspended even at runtime PM suspend. Currently we don't save the mixer state for autopm, and it may bring inconsistency. This patch removes the special handling for autosuspend. Signed-off-by: Takashi Iwai --- sound/usb/card.c | 30 ++++++++++-------------------- 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/sound/usb/card.c b/sound/usb/card.c index 73c5833e76574..18f56646ce86d 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -689,30 +689,20 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) if (chip == (void *)-1L) return 0; - if (!PMSG_IS_AUTO(message)) { + chip->autosuspended = !!PMSG_IS_AUTO(message); + if (!chip->autosuspended) snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); - if (!chip->num_suspended_intf++) { - list_for_each_entry(as, &chip->pcm_list, list) { - snd_pcm_suspend_all(as->pcm); - as->substream[0].need_setup_ep = - as->substream[1].need_setup_ep = true; - } - list_for_each(p, &chip->midi_list) { - snd_usbmidi_suspend(p); - } + if (!chip->num_suspended_intf++) { + list_for_each_entry(as, &chip->pcm_list, list) { + snd_pcm_suspend_all(as->pcm); + as->substream[0].need_setup_ep = + as->substream[1].need_setup_ep = true; } - } else { - /* - * otherwise we keep the rest of the system in the dark - * to keep this transparent - */ - if (!chip->num_suspended_intf++) - chip->autosuspended = 1; - } - - if (chip->num_suspended_intf == 1) + list_for_each(p, &chip->midi_list) + snd_usbmidi_suspend(p); list_for_each_entry(mixer, &chip->mixer_list, list) snd_usb_mixer_suspend(mixer); + } return 0; } -- GitLab From 14c3e677df9fa2e4bf87b9de683452fc140934b2 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 6 Jul 2015 13:41:53 +0200 Subject: [PATCH 4993/7006] scsi: Add ALUA state change UA handling Log the ALUA state change unit attention correctly with the message log and emit an event to allow user-space tools to react to it. Signed-off-by: Hannes Reinecke Reviewed-by: Ewan D. Milne Reviewed-by: Bart Van Assche Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 4 ++++ drivers/scsi/scsi_lib.c | 4 ++++ include/scsi/scsi_device.h | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index cfadccef045c5..d7d28061b31d8 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -421,6 +421,10 @@ static void scsi_report_sense(struct scsi_device *sdev, evt_type = SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED; sdev_printk(KERN_WARNING, sdev, "Mode parameters changed"); + } else if (sshdr->asc == 0x2a && sshdr->ascq == 0x06) { + evt_type = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED; + sdev_printk(KERN_WARNING, sdev, + "Asymmetric access state changed"); } else if (sshdr->asc == 0x2a && sshdr->ascq == 0x09) { evt_type = SDEV_EVT_CAPACITY_CHANGE_REPORTED; sdev_printk(KERN_WARNING, sdev, diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index dffa91c67f5b9..882864f5cbae8 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2712,6 +2712,9 @@ static void scsi_evt_emit(struct scsi_device *sdev, struct scsi_event *evt) case SDEV_EVT_LUN_CHANGE_REPORTED: envp[idx++] = "SDEV_UA=REPORTED_LUNS_DATA_HAS_CHANGED"; break; + case SDEV_EVT_ALUA_STATE_CHANGE_REPORTED: + envp[idx++] = "SDEV_UA=ASYMMETRIC_ACCESS_STATE_CHANGED"; + break; default: /* do nothing */ break; @@ -2815,6 +2818,7 @@ struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, case SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED: case SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED: case SDEV_EVT_LUN_CHANGE_REPORTED: + case SDEV_EVT_ALUA_STATE_CHANGE_REPORTED: default: /* do nothing */ break; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index ae84b2214d407..50c2a363bc8fe 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -57,9 +57,10 @@ enum scsi_device_event { SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED, /* 38 07 UA reported */ SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED, /* 2A 01 UA reported */ SDEV_EVT_LUN_CHANGE_REPORTED, /* 3F 0E UA reported */ + SDEV_EVT_ALUA_STATE_CHANGE_REPORTED, /* 2A 06 UA reported */ SDEV_EVT_FIRST = SDEV_EVT_MEDIA_CHANGE, - SDEV_EVT_LAST = SDEV_EVT_LUN_CHANGE_REPORTED, + SDEV_EVT_LAST = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED, SDEV_EVT_MAXBITS = SDEV_EVT_LAST + 1 }; -- GitLab From 3b8a1ba378b7502c7206ab3da5ea484a132ad30c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 7 Jul 2015 15:52:25 -0500 Subject: [PATCH 4994/7006] megaraid : use dev_printk when possible Use dev_printk() when possible to make messages more useful. Signed-off-by: Bjorn Helgaas Reviewed-by: Hannes Reinecke Acked-by: Sumit Saxena Signed-off-by: James Bottomley --- drivers/scsi/megaraid.c | 140 +++++++++++++++++++--------------------- 1 file changed, 66 insertions(+), 74 deletions(-) diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index bc7b34c027238..9d05302a3bcd5 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -268,8 +268,8 @@ mega_query_adapter(adapter_t *adapter) raw_mbox[2] = NC_SUBOP_PRODUCT_INFO; /* i.e. 0x0E */ if ((retval = issue_scb_block(adapter, raw_mbox))) - printk(KERN_WARNING - "megaraid: Product_info cmd failed with error: %d\n", + dev_warn(&adapter->dev->dev, + "Product_info cmd failed with error: %d\n", retval); pci_unmap_single(adapter->dev, prod_info_dma_handle, @@ -334,7 +334,7 @@ mega_query_adapter(adapter_t *adapter) adapter->bios_version[4] = 0; } - printk(KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives.\n", + dev_notice(&adapter->dev->dev, "[%s:%s] detected %d logical drives\n", adapter->fw_version, adapter->bios_version, adapter->numldrv); /* @@ -342,7 +342,7 @@ mega_query_adapter(adapter_t *adapter) */ adapter->support_ext_cdb = mega_support_ext_cdb(adapter); if (adapter->support_ext_cdb) - printk(KERN_NOTICE "megaraid: supports extended CDBs.\n"); + dev_notice(&adapter->dev->dev, "supports extended CDBs\n"); return 0; @@ -678,11 +678,11 @@ mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy) if(!(adapter->flag & (1L << cmd->device->channel))) { - printk(KERN_NOTICE - "scsi%d: scanning scsi channel %d ", + dev_notice(&adapter->dev->dev, + "scsi%d: scanning scsi channel %d " + "for logical drives\n", adapter->host->host_no, cmd->device->channel); - printk("for logical drives.\n"); adapter->flag |= (1L << cmd->device->channel); } @@ -983,11 +983,11 @@ mega_prepare_passthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd, case READ_CAPACITY: if(!(adapter->flag & (1L << cmd->device->channel))) { - printk(KERN_NOTICE - "scsi%d: scanning scsi channel %d [P%d] ", + dev_notice(&adapter->dev->dev, + "scsi%d: scanning scsi channel %d [P%d] " + "for physical devices\n", adapter->host->host_no, cmd->device->channel, channel); - printk("for physical devices.\n"); adapter->flag |= (1L << cmd->device->channel); } @@ -1045,11 +1045,11 @@ mega_prepare_extpassthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd, case READ_CAPACITY: if(!(adapter->flag & (1L << cmd->device->channel))) { - printk(KERN_NOTICE - "scsi%d: scanning scsi channel %d [P%d] ", + dev_notice(&adapter->dev->dev, + "scsi%d: scanning scsi channel %d [P%d] " + "for physical devices\n", adapter->host->host_no, cmd->device->channel, channel); - printk("for physical devices.\n"); adapter->flag |= (1L << cmd->device->channel); } @@ -1241,7 +1241,7 @@ issue_scb_block(adapter_t *adapter, u_char *raw_mbox) return mbox->m_in.status; bug_blocked_mailbox: - printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n"); + dev_warn(&adapter->dev->dev, "Blocked mailbox......!!\n"); udelay (1000); return -1; } @@ -1454,9 +1454,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) * Make sure f/w has completed a valid command */ if( !(scb->state & SCB_ISSUED) || scb->cmd == NULL ) { - printk(KERN_CRIT - "megaraid: invalid command "); - printk("Id %d, scb->state:%x, scsi cmd:%p\n", + dev_crit(&adapter->dev->dev, "invalid command " + "Id %d, scb->state:%x, scsi cmd:%p\n", cmdid, scb->state, scb->cmd); continue; @@ -1467,8 +1466,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) */ if( scb->state & SCB_ABORT ) { - printk(KERN_WARNING - "megaraid: aborted cmd [%x] complete.\n", + dev_warn(&adapter->dev->dev, + "aborted cmd [%x] complete\n", scb->idx); scb->cmd->result = (DID_ABORT << 16); @@ -1486,8 +1485,8 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) */ if( scb->state & SCB_RESET ) { - printk(KERN_WARNING - "megaraid: reset cmd [%x] complete.\n", + dev_warn(&adapter->dev->dev, + "reset cmd [%x] complete\n", scb->idx); scb->cmd->result = (DID_RESET << 16); @@ -1553,8 +1552,7 @@ mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status) if( sg_page(sgl) ) { c = *(unsigned char *) sg_virt(&sgl[0]); } else { - printk(KERN_WARNING - "megaraid: invalid sg.\n"); + dev_warn(&adapter->dev->dev, "invalid sg\n"); c = 0; } @@ -1902,11 +1900,10 @@ megaraid_reset(struct scsi_cmnd *cmd) mc.opcode = MEGA_RESET_RESERVATIONS; if( mega_internal_command(adapter, &mc, NULL) != 0 ) { - printk(KERN_WARNING - "megaraid: reservation reset failed.\n"); + dev_warn(&adapter->dev->dev, "reservation reset failed\n"); } else { - printk(KERN_INFO "megaraid: reservation reset.\n"); + dev_info(&adapter->dev->dev, "reservation reset\n"); } #endif @@ -1939,7 +1936,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) struct list_head *pos, *next; scb_t *scb; - printk(KERN_WARNING "megaraid: %s cmd=%x \n", + dev_warn(&adapter->dev->dev, "%s cmd=%x \n", (aor == SCB_ABORT)? "ABORTING":"RESET", cmd->cmnd[0], cmd->device->channel, cmd->device->id, (u32)cmd->device->lun); @@ -1963,8 +1960,8 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) */ if( scb->state & SCB_ISSUED ) { - printk(KERN_WARNING - "megaraid: %s[%x], fw owner.\n", + dev_warn(&adapter->dev->dev, + "%s[%x], fw owner\n", (aor==SCB_ABORT) ? "ABORTING":"RESET", scb->idx); @@ -1976,8 +1973,8 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor) * Not yet issued! Remove from the pending * list */ - printk(KERN_WARNING - "megaraid: %s-[%x], driver owner.\n", + dev_warn(&adapter->dev->dev, + "%s-[%x], driver owner\n", (aor==SCB_ABORT) ? "ABORTING":"RESET", scb->idx); @@ -2197,7 +2194,7 @@ proc_show_rebuild_rate(struct seq_file *m, void *v) if( mega_adapinq(adapter, dma_handle) != 0 ) { seq_puts(m, "Adapter inquiry failed.\n"); - printk(KERN_WARNING "megaraid: inquiry failed.\n"); + dev_warn(&adapter->dev->dev, "inquiry failed\n"); goto free_inquiry; } @@ -2241,7 +2238,7 @@ proc_show_battery(struct seq_file *m, void *v) if( mega_adapinq(adapter, dma_handle) != 0 ) { seq_puts(m, "Adapter inquiry failed.\n"); - printk(KERN_WARNING "megaraid: inquiry failed.\n"); + dev_warn(&adapter->dev->dev, "inquiry failed\n"); goto free_inquiry; } @@ -2350,7 +2347,7 @@ proc_show_pdrv(struct seq_file *m, adapter_t *adapter, int channel) if( mega_adapinq(adapter, dma_handle) != 0 ) { seq_puts(m, "Adapter inquiry failed.\n"); - printk(KERN_WARNING "megaraid: inquiry failed.\n"); + dev_warn(&adapter->dev->dev, "inquiry failed\n"); goto free_inquiry; } @@ -2525,7 +2522,7 @@ proc_show_rdrv(struct seq_file *m, adapter_t *adapter, int start, int end ) if( mega_adapinq(adapter, dma_handle) != 0 ) { seq_puts(m, "Adapter inquiry failed.\n"); - printk(KERN_WARNING "megaraid: inquiry failed.\n"); + dev_warn(&adapter->dev->dev, "inquiry failed\n"); goto free_inquiry; } @@ -2799,7 +2796,7 @@ mega_create_proc_entry(int index, struct proc_dir_entry *parent) dir = adapter->controller_proc_dir_entry = proc_mkdir_data(string, 0, parent, adapter); if(!dir) { - printk(KERN_WARNING "\nmegaraid: proc_mkdir failed\n"); + dev_warn(&adapter->dev->dev, "proc_mkdir failed\n"); return; } @@ -2807,7 +2804,7 @@ mega_create_proc_entry(int index, struct proc_dir_entry *parent) de = proc_create_data(f->name, S_IRUSR, dir, &mega_proc_fops, f->show); if (!de) { - printk(KERN_WARNING "\nmegaraid: proc_create failed\n"); + dev_warn(&adapter->dev->dev, "proc_create failed\n"); return; } @@ -2874,9 +2871,9 @@ megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev, return rval; } - printk(KERN_INFO - "megaraid: invalid partition on this disk on channel %d\n", - sdev->channel); + dev_info(&adapter->dev->dev, + "invalid partition on this disk on channel %d\n", + sdev->channel); /* Default heads (64) & sectors (32) */ heads = 64; @@ -2936,7 +2933,7 @@ mega_init_scb(adapter_t *adapter) scb->sgl = (mega_sglist *)scb->sgl64; if( !scb->sgl ) { - printk(KERN_WARNING "RAID: Can't allocate sglist.\n"); + dev_warn(&adapter->dev->dev, "RAID: Can't allocate sglist\n"); mega_free_sgl(adapter); return -1; } @@ -2946,7 +2943,7 @@ mega_init_scb(adapter_t *adapter) &scb->pthru_dma_addr); if( !scb->pthru ) { - printk(KERN_WARNING "RAID: Can't allocate passthru.\n"); + dev_warn(&adapter->dev->dev, "RAID: Can't allocate passthru\n"); mega_free_sgl(adapter); return -1; } @@ -2956,8 +2953,8 @@ mega_init_scb(adapter_t *adapter) &scb->epthru_dma_addr); if( !scb->epthru ) { - printk(KERN_WARNING - "Can't allocate extended passthru.\n"); + dev_warn(&adapter->dev->dev, + "Can't allocate extended passthru\n"); mega_free_sgl(adapter); return -1; } @@ -3154,8 +3151,8 @@ megadev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) * Do we support this feature */ if( !adapter->support_random_del ) { - printk(KERN_WARNING "megaraid: logdrv "); - printk("delete on non-supporting F/W.\n"); + dev_warn(&adapter->dev->dev, "logdrv " + "delete on non-supporting F/W\n"); return (-EINVAL); } @@ -3179,7 +3176,7 @@ megadev_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU64 || uioc.uioc_rmbox[0] == MEGA_MBOXCMD_EXTPTHRU ) { - printk(KERN_WARNING "megaraid: rejected passthru.\n"); + dev_warn(&adapter->dev->dev, "rejected passthru\n"); return (-EINVAL); } @@ -3683,11 +3680,11 @@ mega_enum_raid_scsi(adapter_t *adapter) for( i = 0; i < adapter->product_info.nchannels; i++ ) { if( (adapter->mega_ch_class >> i) & 0x01 ) { - printk(KERN_INFO "megaraid: channel[%d] is raid.\n", + dev_info(&adapter->dev->dev, "channel[%d] is raid\n", i); } else { - printk(KERN_INFO "megaraid: channel[%d] is scsi.\n", + dev_info(&adapter->dev->dev, "channel[%d] is scsi\n", i); } } @@ -3893,7 +3890,7 @@ mega_do_del_logdrv(adapter_t *adapter, int logdrv) /* log this event */ if(rval) { - printk(KERN_WARNING "megaraid: Delete LD-%d failed.", logdrv); + dev_warn(&adapter->dev->dev, "Delete LD-%d failed", logdrv); return rval; } @@ -4161,7 +4158,7 @@ mega_internal_command(adapter_t *adapter, megacmd_t *mc, mega_passthru *pthru) * this information. */ if (rval && trace_level) { - printk("megaraid: cmd [%x, %x, %x] status:[%x]\n", + dev_info(&adapter->dev->dev, "cmd [%x, %x, %x] status:[%x]\n", mc->cmd, mc->opcode, mc->subopcode, rval); } @@ -4244,11 +4241,8 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) subsysvid = pdev->subsystem_vendor; subsysid = pdev->subsystem_device; - printk(KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:bus %d:", - id->vendor, id->device, pci_bus); - - printk("slot %d:func %d\n", - PCI_SLOT(pci_dev_func), PCI_FUNC(pci_dev_func)); + dev_notice(&pdev->dev, "found 0x%4.04x:0x%4.04x\n", + id->vendor, id->device); /* Read the base port and IRQ from PCI */ mega_baseport = pci_resource_start(pdev, 0); @@ -4259,14 +4253,13 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) flag |= BOARD_MEMMAP; if (!request_mem_region(mega_baseport, 128, "megaraid")) { - printk(KERN_WARNING "megaraid: mem region busy!\n"); + dev_warn(&pdev->dev, "mem region busy!\n"); goto out_disable_device; } mega_baseport = (unsigned long)ioremap(mega_baseport, 128); if (!mega_baseport) { - printk(KERN_WARNING - "megaraid: could not map hba memory\n"); + dev_warn(&pdev->dev, "could not map hba memory\n"); goto out_release_region; } } else { @@ -4285,7 +4278,7 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) adapter = (adapter_t *)host->hostdata; memset(adapter, 0, sizeof(adapter_t)); - printk(KERN_NOTICE + dev_notice(&pdev->dev, "scsi%d:Found MegaRAID controller at 0x%lx, IRQ:%d\n", host->host_no, mega_baseport, irq); @@ -4323,21 +4316,20 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) adapter->mega_buffer = pci_alloc_consistent(adapter->dev, MEGA_BUFFER_SIZE, &adapter->buf_dma_handle); if (!adapter->mega_buffer) { - printk(KERN_WARNING "megaraid: out of RAM.\n"); + dev_warn(&pdev->dev, "out of RAM\n"); goto out_host_put; } adapter->scb_list = kmalloc(sizeof(scb_t) * MAX_COMMANDS, GFP_KERNEL); if (!adapter->scb_list) { - printk(KERN_WARNING "megaraid: out of RAM.\n"); + dev_warn(&pdev->dev, "out of RAM\n"); goto out_free_cmd_buffer; } if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ? megaraid_isr_memmapped : megaraid_isr_iomapped, IRQF_SHARED, "megaraid", adapter)) { - printk(KERN_WARNING - "megaraid: Couldn't register IRQ %d!\n", irq); + dev_warn(&pdev->dev, "Couldn't register IRQ %d!\n", irq); goto out_free_scb_list; } @@ -4357,9 +4349,9 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (!strcmp(adapter->fw_version, "3.00") || !strcmp(adapter->fw_version, "3.01")) { - printk( KERN_WARNING - "megaraid: Your card is a Dell PERC " - "2/SC RAID controller with " + dev_warn(&pdev->dev, + "Your card is a Dell PERC " + "2/SC RAID controller with " "firmware\nmegaraid: 3.00 or 3.01. " "This driver is known to have " "corruption issues\nmegaraid: with " @@ -4390,12 +4382,12 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (!strcmp(adapter->fw_version, "H01.07") || !strcmp(adapter->fw_version, "H01.08") || !strcmp(adapter->fw_version, "H01.09") ) { - printk(KERN_WARNING - "megaraid: Firmware H.01.07, " + dev_warn(&pdev->dev, + "Firmware H.01.07, " "H.01.08, and H.01.09 on 1M/2M " "controllers\n" - "megaraid: do not support 64 bit " - "addressing.\nmegaraid: DISABLING " + "do not support 64 bit " + "addressing.\nDISABLING " "64 bit support.\n"); adapter->flag &= ~BOARD_64BIT; } @@ -4503,8 +4495,8 @@ megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) */ adapter->has_cluster = mega_support_cluster(adapter); if (adapter->has_cluster) { - printk(KERN_NOTICE - "megaraid: Cluster driver, initiator id:%d\n", + dev_notice(&pdev->dev, + "Cluster driver, initiator id:%d\n", adapter->this_id); } #endif @@ -4571,7 +4563,7 @@ __megaraid_shutdown(adapter_t *adapter) issue_scb_block(adapter, raw_mbox); if (atomic_read(&adapter->pend_cmds) > 0) - printk(KERN_WARNING "megaraid: pending commands!!\n"); + dev_warn(&adapter->dev->dev, "pending commands!!\n"); /* * Have a delibrate delay to make sure all the caches are -- GitLab From 1be1825453f6d75ea9c9ea0c8549ca481d94a7ab Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 7 Jul 2015 15:52:34 -0500 Subject: [PATCH 4995/7006] megaraid_sas: use dev_printk when possible Use dev_printk() when possible to make messages more useful. Signed-off-by: Bjorn Helgaas Reviewed-by: Hannes Reinecke Acked-by: Sumit Saxena Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_base.c | 304 ++++++++++---------- drivers/scsi/megaraid/megaraid_sas_fusion.c | 95 +++--- 2 files changed, 196 insertions(+), 203 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 71b884dae27c7..a9bd592fde370 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -216,7 +216,7 @@ struct megasas_cmd *megasas_get_cmd(struct megasas_instance struct megasas_cmd, list); list_del_init(&cmd->list); } else { - printk(KERN_ERR "megasas: Command pool empty!\n"); + dev_err(&instance->pdev->dev, "Command pool empty!\n"); } spin_unlock_irqrestore(&instance->mfi_pool_lock, flags); @@ -370,9 +370,9 @@ megasas_adp_reset_xscale(struct megasas_instance *instance, msleep(1000); /* sleep for 3 secs */ pcidata = 0; pci_read_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, &pcidata); - printk(KERN_NOTICE "pcidata = %x\n", pcidata); + dev_notice(&instance->pdev->dev, "pcidata = %x\n", pcidata); if (pcidata & 0x2) { - printk(KERN_NOTICE "mfi 1068 offset read=%x\n", pcidata); + dev_notice(&instance->pdev->dev, "mfi 1068 offset read=%x\n", pcidata); pcidata &= ~0x2; pci_write_config_dword(instance->pdev, MFI_1068_PCSR_OFFSET, pcidata); @@ -383,9 +383,9 @@ megasas_adp_reset_xscale(struct megasas_instance *instance, pcidata = 0; pci_read_config_dword(instance->pdev, MFI_1068_FW_HANDSHAKE_OFFSET, &pcidata); - printk(KERN_NOTICE "1068 offset handshake read=%x\n", pcidata); + dev_notice(&instance->pdev->dev, "1068 offset handshake read=%x\n", pcidata); if ((pcidata & 0xffff0000) == MFI_1068_FW_READY) { - printk(KERN_NOTICE "1068 offset pcidt=%x\n", pcidata); + dev_notice(&instance->pdev->dev, "1068 offset pcidt=%x\n", pcidata); pcidata = 0; pci_write_config_dword(instance->pdev, MFI_1068_FW_HANDSHAKE_OFFSET, pcidata); @@ -824,7 +824,7 @@ megasas_adp_reset_gen2(struct megasas_instance *instance, while ( !( HostDiag & DIAG_WRITE_ENABLE) ) { msleep(100); HostDiag = (u32)readl(hostdiag_offset); - printk(KERN_NOTICE "RESETGEN2: retry=%x, hostdiag=%x\n", + dev_notice(&instance->pdev->dev, "RESETGEN2: retry=%x, hostdiag=%x\n", retry, HostDiag); if (retry++ >= 100) @@ -832,7 +832,7 @@ megasas_adp_reset_gen2(struct megasas_instance *instance, } - printk(KERN_NOTICE "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag); + dev_notice(&instance->pdev->dev, "ADP_RESET_GEN2: HostDiag=%x\n", HostDiag); writel((HostDiag | DIAG_RESET_ADAPTER), hostdiag_offset); @@ -842,7 +842,7 @@ megasas_adp_reset_gen2(struct megasas_instance *instance, while ( ( HostDiag & DIAG_RESET_ADAPTER) ) { msleep(100); HostDiag = (u32)readl(hostdiag_offset); - printk(KERN_NOTICE "RESET_GEN2: retry=%x, hostdiag=%x\n", + dev_notice(&instance->pdev->dev, "RESET_GEN2: retry=%x, hostdiag=%x\n", retry, HostDiag); if (retry++ >= 1000) @@ -1241,7 +1241,7 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, &pthru->sgl); if (pthru->sge_count > instance->max_num_sge) { - printk(KERN_ERR "megasas: DCDB two many SGE NUM=%x\n", + dev_err(&instance->pdev->dev, "DCDB too many SGE NUM=%x\n", pthru->sge_count); return 0; } @@ -1382,7 +1382,7 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp, ldio->sge_count = megasas_make_sgl32(instance, scp, &ldio->sgl); if (ldio->sge_count > instance->max_num_sge) { - printk(KERN_ERR "megasas: build_ld_io: sge_count = %x\n", + dev_err(&instance->pdev->dev, "build_ld_io: sge_count = %x\n", ldio->sge_count); return 0; } @@ -1449,24 +1449,24 @@ megasas_dump_pending_frames(struct megasas_instance *instance) u32 sgcount; u32 max_cmd = instance->max_fw_cmds; - printk(KERN_ERR "\nmegasas[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no); - printk(KERN_ERR "megasas[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding)); + dev_err(&instance->pdev->dev, "[%d]: Dumping Frame Phys Address of all pending cmds in FW\n",instance->host->host_no); + dev_err(&instance->pdev->dev, "[%d]: Total OS Pending cmds : %d\n",instance->host->host_no,atomic_read(&instance->fw_outstanding)); if (IS_DMA64) - printk(KERN_ERR "\nmegasas[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no); + dev_err(&instance->pdev->dev, "[%d]: 64 bit SGLs were sent to FW\n",instance->host->host_no); else - printk(KERN_ERR "\nmegasas[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no); + dev_err(&instance->pdev->dev, "[%d]: 32 bit SGLs were sent to FW\n",instance->host->host_no); - printk(KERN_ERR "megasas[%d]: Pending OS cmds in FW : \n",instance->host->host_no); + dev_err(&instance->pdev->dev, "[%d]: Pending OS cmds in FW : \n",instance->host->host_no); for (i = 0; i < max_cmd; i++) { cmd = instance->cmd_list[i]; if(!cmd->scmd) continue; - printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); + dev_err(&instance->pdev->dev, "[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) { ldio = (struct megasas_io_frame *)cmd->frame; mfi_sgl = &ldio->sgl; sgcount = ldio->sge_count; - printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x," + dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x," " lba lo : 0x%x, lba_hi : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n", instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id, le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi), @@ -1476,7 +1476,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance) pthru = (struct megasas_pthru_frame *) cmd->frame; mfi_sgl = &pthru->sgl; sgcount = pthru->sge_count; - printk(KERN_ERR "megasas[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, " + dev_err(&instance->pdev->dev, "[%d]: frame count : 0x%x, Cmd : 0x%x, Tgt id : 0x%x, " "lun : 0x%x, cdb_len : 0x%x, data xfer len : 0x%x, sense_buf addr : 0x%x,sge count : 0x%x\n", instance->host->host_no, cmd->frame_count, pthru->cmd, pthru->target_id, pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len), @@ -1485,27 +1485,26 @@ megasas_dump_pending_frames(struct megasas_instance *instance) if(megasas_dbg_lvl & MEGASAS_DBG_LVL){ for (n = 0; n < sgcount; n++){ if (IS_DMA64) - printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%llx ", + dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n", le32_to_cpu(mfi_sgl->sge64[n].length), le64_to_cpu(mfi_sgl->sge64[n].phys_addr)); else - printk(KERN_ERR "megasas: sgl len : 0x%x, sgl addr : 0x%x ", + dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n", le32_to_cpu(mfi_sgl->sge32[n].length), le32_to_cpu(mfi_sgl->sge32[n].phys_addr)); } } - printk(KERN_ERR "\n"); } /*for max_cmd*/ - printk(KERN_ERR "\nmegasas[%d]: Pending Internal cmds in FW : \n",instance->host->host_no); + dev_err(&instance->pdev->dev, "[%d]: Pending Internal cmds in FW : \n",instance->host->host_no); for (i = 0; i < max_cmd; i++) { cmd = instance->cmd_list[i]; if(cmd->sync_cmd == 1){ - printk(KERN_ERR "0x%08lx : ", (unsigned long)cmd->frame_phys_addr); + dev_err(&instance->pdev->dev, "0x%08lx : ", (unsigned long)cmd->frame_phys_addr); } } - printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no); + dev_err(&instance->pdev->dev, "[%d]: Dumping Done\n\n",instance->host->host_no); } u32 @@ -1623,7 +1622,7 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd) } if (instance->instancet->build_and_issue_cmd(instance, scmd)) { - printk(KERN_ERR "megasas: Err returned from build_and_issue_cmd\n"); + dev_err(&instance->pdev->dev, "Err returned from build_and_issue_cmd\n"); return SCSI_MLQUEUE_HOST_BUSY; } @@ -1794,7 +1793,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) while (consumer != producer) { context = le32_to_cpu(instance->reply_queue[consumer]); if (context >= instance->max_fw_cmds) { - printk(KERN_ERR "Unexpected context value %x\n", + dev_err(&instance->pdev->dev, "Unexpected context value %x\n", context); BUG(); } @@ -1873,8 +1872,8 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: megasas_get_ld_vf_affiliation_111:" - "Failed to get cmd for scsi%d.\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation_111:" + "Failed to get cmd for scsi%d\n", instance->host->host_no); return -ENOMEM; } @@ -1882,8 +1881,8 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, dcmd = &cmd->frame->dcmd; if (!instance->vf_affiliation_111) { - printk(KERN_WARNING "megasas: SR-IOV: Couldn't get LD/VF " - "affiliation for scsi%d.\n", instance->host->host_no); + dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF " + "affiliation for scsi%d\n", instance->host->host_no); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -1897,8 +1896,8 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, sizeof(struct MR_LD_VF_AFFILIATION_111), &new_affiliation_111_h); if (!new_affiliation_111) { - printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate " - "memory for new affiliation for scsi%d.\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " + "memory for new affiliation for scsi%d\n", instance->host->host_no); megasas_return_cmd(instance, cmd); return -ENOMEM; @@ -1929,14 +1928,14 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, dcmd->sgl.sge32[0].length = cpu_to_le32( sizeof(struct MR_LD_VF_AFFILIATION_111)); - printk(KERN_WARNING "megasas: SR-IOV: Getting LD/VF affiliation for " + dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for " "scsi%d\n", instance->host->host_no); megasas_issue_blocked_cmd(instance, cmd, 0); if (dcmd->cmd_status) { - printk(KERN_WARNING "megasas: SR-IOV: LD/VF affiliation DCMD" - " failed with status 0x%x for scsi%d.\n", + dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD" + " failed with status 0x%x for scsi%d\n", dcmd->cmd_status, instance->host->host_no); retval = 1; /* Do a scan if we couldn't get affiliation */ goto out; @@ -1947,9 +1946,8 @@ static int megasas_get_ld_vf_affiliation_111(struct megasas_instance *instance, for (ld = 0 ; ld < new_affiliation_111->vdCount; ld++) if (instance->vf_affiliation_111->map[ld].policy[thisVf] != new_affiliation_111->map[ld].policy[thisVf]) { - printk(KERN_WARNING "megasas: SR-IOV: " - "Got new LD/VF affiliation " - "for scsi%d.\n", + dev_warn(&instance->pdev->dev, "SR-IOV: " + "Got new LD/VF affiliation for scsi%d\n", instance->host->host_no); memcpy(instance->vf_affiliation_111, new_affiliation_111, @@ -1985,8 +1983,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: megasas_get_ld_vf_affiliation12: " - "Failed to get cmd for scsi%d.\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_vf_affiliation12: " + "Failed to get cmd for scsi%d\n", instance->host->host_no); return -ENOMEM; } @@ -1994,8 +1992,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, dcmd = &cmd->frame->dcmd; if (!instance->vf_affiliation) { - printk(KERN_WARNING "megasas: SR-IOV: Couldn't get LD/VF " - "affiliation for scsi%d.\n", instance->host->host_no); + dev_warn(&instance->pdev->dev, "SR-IOV: Couldn't get LD/VF " + "affiliation for scsi%d\n", instance->host->host_no); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -2010,8 +2008,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, sizeof(struct MR_LD_VF_AFFILIATION), &new_affiliation_h); if (!new_affiliation) { - printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate " - "memory for new affiliation for scsi%d.\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate " + "memory for new affiliation for scsi%d\n", instance->host->host_no); megasas_return_cmd(instance, cmd); return -ENOMEM; @@ -2042,14 +2040,14 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, dcmd->sgl.sge32[0].length = cpu_to_le32((MAX_LOGICAL_DRIVES + 1) * sizeof(struct MR_LD_VF_AFFILIATION)); - printk(KERN_WARNING "megasas: SR-IOV: Getting LD/VF affiliation for " + dev_warn(&instance->pdev->dev, "SR-IOV: Getting LD/VF affiliation for " "scsi%d\n", instance->host->host_no); megasas_issue_blocked_cmd(instance, cmd, 0); if (dcmd->cmd_status) { - printk(KERN_WARNING "megasas: SR-IOV: LD/VF affiliation DCMD" - " failed with status 0x%x for scsi%d.\n", + dev_warn(&instance->pdev->dev, "SR-IOV: LD/VF affiliation DCMD" + " failed with status 0x%x for scsi%d\n", dcmd->cmd_status, instance->host->host_no); retval = 1; /* Do a scan if we couldn't get affiliation */ goto out; @@ -2057,8 +2055,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, if (!initial) { if (!new_affiliation->ldCount) { - printk(KERN_WARNING "megasas: SR-IOV: Got new LD/VF " - "affiliation for passive path for scsi%d.\n", + dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF " + "affiliation for passive path for scsi%d\n", instance->host->host_no); retval = 1; goto out; @@ -2123,8 +2121,8 @@ static int megasas_get_ld_vf_affiliation_12(struct megasas_instance *instance, } out: if (doscan) { - printk(KERN_WARNING "megasas: SR-IOV: Got new LD/VF " - "affiliation for scsi%d.\n", instance->host->host_no); + dev_warn(&instance->pdev->dev, "SR-IOV: Got new LD/VF " + "affiliation for scsi%d\n", instance->host->host_no); memcpy(instance->vf_affiliation, new_affiliation, new_affiliation->size); retval = 1; @@ -2164,8 +2162,8 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: megasas_sriov_start_heartbeat: " - "Failed to get cmd for scsi%d.\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_sriov_start_heartbeat: " + "Failed to get cmd for scsi%d\n", instance->host->host_no); return -ENOMEM; } @@ -2178,9 +2176,9 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, sizeof(struct MR_CTRL_HB_HOST_MEM), &instance->hb_host_mem_h); if (!instance->hb_host_mem) { - printk(KERN_DEBUG "megasas: SR-IOV: Couldn't allocate" - " memory for heartbeat host memory for " - "scsi%d.\n", instance->host->host_no); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "SR-IOV: Couldn't allocate" + " memory for heartbeat host memory for scsi%d\n", + instance->host->host_no); retval = -ENOMEM; goto out; } @@ -2200,7 +2198,7 @@ int megasas_sriov_start_heartbeat(struct megasas_instance *instance, dcmd->sgl.sge32[0].phys_addr = cpu_to_le32(instance->hb_host_mem_h); dcmd->sgl.sge32[0].length = cpu_to_le32(sizeof(struct MR_CTRL_HB_HOST_MEM)); - printk(KERN_WARNING "megasas: SR-IOV: Starting heartbeat for scsi%d\n", + dev_warn(&instance->pdev->dev, "SR-IOV: Starting heartbeat for scsi%d\n", instance->host->host_no); if (instance->ctrl_context && !instance->mask_interrupts) @@ -2236,7 +2234,7 @@ void megasas_sriov_heartbeat_handler(unsigned long instance_addr) mod_timer(&instance->sriov_heartbeat_timer, jiffies + MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF); } else { - printk(KERN_WARNING "megasas: SR-IOV: Heartbeat never " + dev_warn(&instance->pdev->dev, "SR-IOV: Heartbeat never " "completed for scsi%d\n", instance->host->host_no); schedule_work(&instance->work_init); } @@ -2274,7 +2272,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) &clist_local); spin_unlock_irqrestore(&instance->hba_lock, flags); - printk(KERN_NOTICE "megasas: HBA reset wait ...\n"); + dev_notice(&instance->pdev->dev, "HBA reset wait ...\n"); for (i = 0; i < wait_time; i++) { msleep(1000); spin_lock_irqsave(&instance->hba_lock, flags); @@ -2285,7 +2283,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) } if (adprecovery != MEGASAS_HBA_OPERATIONAL) { - printk(KERN_NOTICE "megasas: reset: Stopping HBA.\n"); + dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n"); spin_lock_irqsave(&instance->hba_lock, flags); instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; spin_unlock_irqrestore(&instance->hba_lock, flags); @@ -2299,14 +2297,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) list_del_init(&reset_cmd->list); if (reset_cmd->scmd) { reset_cmd->scmd->result = DID_RESET << 16; - printk(KERN_NOTICE "%d:%p reset [%02x]\n", + dev_notice(&instance->pdev->dev, "%d:%p reset [%02x]\n", reset_index, reset_cmd, reset_cmd->scmd->cmnd[0]); reset_cmd->scmd->scsi_done(reset_cmd->scmd); megasas_return_cmd(instance, reset_cmd); } else if (reset_cmd->sync_cmd) { - printk(KERN_NOTICE "megasas:%p synch cmds" + dev_notice(&instance->pdev->dev, "%p synch cmds" "reset queue\n", reset_cmd); @@ -2315,7 +2313,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) reset_cmd->frame_phys_addr, 0, instance->reg_set); } else { - printk(KERN_NOTICE "megasas: %p unexpected" + dev_notice(&instance->pdev->dev, "%p unexpected" "cmds lst\n", reset_cmd); } @@ -2333,7 +2331,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) break; if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: [%2d]waiting for %d " + dev_notice(&instance->pdev->dev, "[%2d]waiting for %d " "commands to complete\n",i,outstanding); /* * Call cmd completion routine. Cmd to be @@ -2384,7 +2382,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) if (atomic_read(&instance->fw_outstanding) || (kill_adapter_flag == 2)) { - printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n"); + dev_notice(&instance->pdev->dev, "pending cmds after reset\n"); /* * Send signal to FW to stop processing any pending cmds. * The controller will be taken offline by the OS now. @@ -2406,7 +2404,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) return FAILED; } - printk(KERN_NOTICE "megaraid_sas: no pending cmds after reset\n"); + dev_notice(&instance->pdev->dev, "no pending cmds after reset\n"); return SUCCESS; } @@ -2430,16 +2428,15 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) scmd->cmnd[0], scmd->retries); if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - printk(KERN_ERR "megasas: cannot recover from previous reset " - "failures\n"); + dev_err(&instance->pdev->dev, "cannot recover from previous reset failures\n"); return FAILED; } ret_val = megasas_wait_for_outstanding(instance); if (ret_val == SUCCESS) - printk(KERN_NOTICE "megasas: reset successful \n"); + dev_notice(&instance->pdev->dev, "reset successful\n"); else - printk(KERN_ERR "megasas: failed to do reset\n"); + dev_err(&instance->pdev->dev, "failed to do reset\n"); return ret_val; } @@ -2597,7 +2594,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) struct megasas_aen_event *ev; ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { - printk(KERN_ERR "megasas_service_aen: out of memory\n"); + dev_err(&instance->pdev->dev, "megasas_service_aen: out of memory\n"); } else { ev->instance = instance; instance->ev = ev; @@ -2847,10 +2844,10 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, MR_DCMD_CTRL_EVENT_GET_INFO left over from the main kernel when booting the kdump kernel. Ignore this command to prevent a kernel panic on shutdown of the kdump kernel. */ - printk(KERN_WARNING "megaraid_sas: MFI_CMD_INVALID command " - "completed.\n"); - printk(KERN_WARNING "megaraid_sas: If you have a controller " - "other than PERC5, please upgrade your firmware.\n"); + dev_warn(&instance->pdev->dev, "MFI_CMD_INVALID command " + "completed\n"); + dev_warn(&instance->pdev->dev, "If you have a controller " + "other than PERC5, please upgrade your firmware\n"); break; case MFI_CMD_PD_SCSI_IO: case MFI_CMD_LD_SCSI_IO: @@ -2918,7 +2915,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, break; default: - printk(KERN_DEBUG "megasas: MFI FW status %#x\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "MFI FW status %#x\n", hdr->cmd_status); cmd->scmd->result = DID_ERROR << 16; break; @@ -2944,8 +2941,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, if (cmd->frame->hdr.cmd_status != 0) { if (cmd->frame->hdr.cmd_status != MFI_STAT_NOT_FOUND) - printk(KERN_WARNING "megasas: map sync" - "failed, status = 0x%x.\n", + dev_warn(&instance->pdev->dev, "map syncfailed, status = 0x%x\n", cmd->frame->hdr.cmd_status); else { megasas_return_cmd(instance, cmd); @@ -2997,7 +2993,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, break; default: - printk("megasas: Unknown command completed! [0x%X]\n", + dev_info(&instance->pdev->dev, "Unknown command completed! [0x%X]\n", hdr->cmd); break; } @@ -3028,14 +3024,14 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) list_del_init(&cmd->list); if (cmd->sync_cmd || cmd->scmd) { - printk(KERN_NOTICE "megaraid_sas: command %p, %p:%d" - "detected to be pending while HBA reset.\n", + dev_notice(&instance->pdev->dev, "command %p, %p:%d" + "detected to be pending while HBA reset\n", cmd, cmd->scmd, cmd->sync_cmd); cmd->retry_for_fw_reset++; if (cmd->retry_for_fw_reset == 3) { - printk(KERN_NOTICE "megaraid_sas: cmd %p, %p:%d" + dev_notice(&instance->pdev->dev, "cmd %p, %p:%d" "was tried multiple times during reset." "Shutting down the HBA\n", cmd, cmd->scmd, cmd->sync_cmd); @@ -3048,10 +3044,10 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) if (cmd->sync_cmd == 1) { if (cmd->scmd) { - printk(KERN_NOTICE "megaraid_sas: unexpected" + dev_notice(&instance->pdev->dev, "unexpected" "cmd attached to internal command!\n"); } - printk(KERN_NOTICE "megasas: %p synchronous cmd" + dev_notice(&instance->pdev->dev, "%p synchronous cmd" "on the internal reset queue," "issue it again.\n", cmd); cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS; @@ -3059,7 +3055,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) cmd->frame_phys_addr , 0, instance->reg_set); } else if (cmd->scmd) { - printk(KERN_NOTICE "megasas: %p scsi cmd [%02x]" + dev_notice(&instance->pdev->dev, "%p scsi cmd [%02x]" "detected on the internal queue, issue again.\n", cmd, cmd->scmd->cmnd[0]); @@ -3068,14 +3064,14 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) cmd->frame_phys_addr, cmd->frame_count-1, instance->reg_set); } else { - printk(KERN_NOTICE "megasas: %p unexpected cmd on the" + dev_notice(&instance->pdev->dev, "%p unexpected cmd on the" "internal reset defer list while re-issue!!\n", cmd); } } if (instance->aen_cmd) { - printk(KERN_NOTICE "megaraid_sas: aen_cmd in def process\n"); + dev_notice(&instance->pdev->dev, "aen_cmd in def process\n"); megasas_return_cmd(instance, instance->aen_cmd); instance->aen_cmd = NULL; @@ -3115,12 +3111,12 @@ megasas_internal_reset_defer_cmds(struct megasas_instance *instance) for (i = 0; i < max_cmd; i++) { cmd = instance->cmd_list[i]; if (cmd->sync_cmd == 1 || cmd->scmd) { - printk(KERN_NOTICE "megasas: moving cmd[%d]:%p:%d:%p" + dev_notice(&instance->pdev->dev, "moving cmd[%d]:%p:%d:%p" "on the defer queue as internal\n", defer_index, cmd, cmd->sync_cmd, cmd->scmd); if (!list_empty(&cmd->list)) { - printk(KERN_NOTICE "megaraid_sas: ERROR while" + dev_notice(&instance->pdev->dev, "ERROR while" " moving this cmd:%p, %d %p, it was" "discovered on some list?\n", cmd, cmd->sync_cmd, cmd->scmd); @@ -3145,13 +3141,13 @@ process_fw_state_change_wq(struct work_struct *work) unsigned long flags; if (instance->adprecovery != MEGASAS_ADPRESET_SM_INFAULT) { - printk(KERN_NOTICE "megaraid_sas: error, recovery st %x \n", + dev_notice(&instance->pdev->dev, "error, recovery st %x\n", instance->adprecovery); return ; } if (instance->adprecovery == MEGASAS_ADPRESET_SM_INFAULT) { - printk(KERN_NOTICE "megaraid_sas: FW detected to be in fault" + dev_notice(&instance->pdev->dev, "FW detected to be in fault" "state, restarting it...\n"); instance->instancet->disable_intr(instance); @@ -3161,10 +3157,10 @@ process_fw_state_change_wq(struct work_struct *work) instance->instancet->adp_reset(instance, instance->reg_set); atomic_set(&instance->fw_reset_no_pci_access, 0 ); - printk(KERN_NOTICE "megaraid_sas: FW restarted successfully," + dev_notice(&instance->pdev->dev, "FW restarted successfully," "initiating next stage...\n"); - printk(KERN_NOTICE "megaraid_sas: HBA recovery state machine," + dev_notice(&instance->pdev->dev, "HBA recovery state machine," "state 2 starting...\n"); /*waitting for about 20 second before start the second init*/ @@ -3173,7 +3169,7 @@ process_fw_state_change_wq(struct work_struct *work) } if (megasas_transition_to_ready(instance, 1)) { - printk(KERN_NOTICE "megaraid_sas:adapter not ready\n"); + dev_notice(&instance->pdev->dev, "adapter not ready\n"); atomic_set(&instance->fw_reset_no_pci_access, 1); megaraid_sas_kill_hba(instance); @@ -3238,13 +3234,13 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, instance->reg_set) & MFI_STATE_MASK; if (fw_state != MFI_STATE_FAULT) { - printk(KERN_NOTICE "megaraid_sas: fw state:%x\n", + dev_notice(&instance->pdev->dev, "fw state:%x\n", fw_state); } if ((fw_state == MFI_STATE_FAULT) && (instance->disableOnlineCtrlReset == 0)) { - printk(KERN_NOTICE "megaraid_sas: wait adp restart\n"); + dev_notice(&instance->pdev->dev, "wait adp restart\n"); if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) || @@ -3265,14 +3261,14 @@ megasas_deplete_reply_queue(struct megasas_instance *instance, atomic_set(&instance->fw_outstanding, 0); megasas_internal_reset_defer_cmds(instance); - printk(KERN_NOTICE "megasas: fwState=%x, stage:%d\n", + dev_notice(&instance->pdev->dev, "fwState=%x, stage:%d\n", fw_state, instance->adprecovery); schedule_work(&instance->work_init); return IRQ_HANDLED; } else { - printk(KERN_NOTICE "megasas: fwstate:%x, dis_OCR=%x\n", + dev_notice(&instance->pdev->dev, "fwstate:%x, dis_OCR=%x\n", fw_state, instance->disableOnlineCtrlReset); } } @@ -3322,7 +3318,7 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) fw_state = abs_state & MFI_STATE_MASK; if (fw_state != MFI_STATE_READY) - printk(KERN_INFO "megasas: Waiting for FW to come to ready" + dev_info(&instance->pdev->dev, "Waiting for FW to come to ready" " state\n"); while (fw_state != MFI_STATE_READY) { @@ -3330,7 +3326,7 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) switch (fw_state) { case MFI_STATE_FAULT: - printk(KERN_DEBUG "megasas: FW in FAULT state!!\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW in FAULT state!!\n"); if (ocr) { max_wait = MEGASAS_RESET_WAIT_TIME; cur_state = MFI_STATE_FAULT; @@ -3469,7 +3465,7 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) break; default: - printk(KERN_DEBUG "megasas: Unknown state 0x%x\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Unknown state 0x%x\n", fw_state); return -ENODEV; } @@ -3491,7 +3487,7 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) * Return error if fw_state hasn't changed after max_wait */ if (curr_abs_state == abs_state) { - printk(KERN_DEBUG "FW state [%d] hasn't changed " + dev_printk(KERN_DEBUG, &instance->pdev->dev, "FW state [%d] hasn't changed " "in %d secs\n", fw_state, max_wait); return -ENODEV; } @@ -3499,7 +3495,7 @@ megasas_transition_to_ready(struct megasas_instance *instance, int ocr) abs_state = curr_abs_state; fw_state = curr_abs_state & MFI_STATE_MASK; } - printk(KERN_INFO "megasas: FW now in Ready state\n"); + dev_info(&instance->pdev->dev, "FW now in Ready state\n"); return 0; } @@ -3594,7 +3590,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) instance->pdev, total_sz, 256, 0); if (!instance->frame_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup frame pool\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup frame pool\n"); return -ENOMEM; } @@ -3602,7 +3598,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) instance->pdev, 128, 4, 0); if (!instance->sense_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup sense pool\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool\n"); pci_pool_destroy(instance->frame_dma_pool); instance->frame_dma_pool = NULL; @@ -3630,7 +3626,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) * whatever has been allocated */ if (!cmd->frame || !cmd->sense) { - printk(KERN_DEBUG "megasas: pci_pool_alloc failed \n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n"); megasas_teardown_frame_pool(instance); return -ENOMEM; } @@ -3708,7 +3704,7 @@ int megasas_alloc_cmds(struct megasas_instance *instance) instance->cmd_list = kcalloc(max_cmd, sizeof(struct megasas_cmd*), GFP_KERNEL); if (!instance->cmd_list) { - printk(KERN_DEBUG "megasas: out of memory\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory\n"); return -ENOMEM; } @@ -3744,7 +3740,7 @@ int megasas_alloc_cmds(struct megasas_instance *instance) * Create a frame pool and assign one frame to each cmd */ if (megasas_create_frame_pool(instance)) { - printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n"); megasas_free_cmds(instance); } @@ -3773,7 +3769,7 @@ megasas_get_pd_list(struct megasas_instance *instance) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas (get_pd_list): Failed to get cmd\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "(get_pd_list): Failed to get cmd\n"); return -ENOMEM; } @@ -3783,7 +3779,7 @@ megasas_get_pd_list(struct megasas_instance *instance) MEGASAS_MAX_PD * sizeof(struct MR_PD_LIST), &ci_h); if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem for pd_list\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc mem for pd_list\n"); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -3868,7 +3864,7 @@ megasas_get_ld_list(struct megasas_instance *instance) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas_get_ld_list: Failed to get cmd\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "megasas_get_ld_list: Failed to get cmd\n"); return -ENOMEM; } @@ -3879,7 +3875,7 @@ megasas_get_ld_list(struct megasas_instance *instance) &ci_h); if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem in get_ld_list\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc mem in get_ld_list\n"); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -3954,8 +3950,8 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_WARNING - "megasas:(megasas_ld_list_query): Failed to get cmd\n"); + dev_warn(&instance->pdev->dev, + "megasas_ld_list_query: Failed to get cmd\n"); return -ENOMEM; } @@ -3965,8 +3961,8 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type) sizeof(struct MR_LD_TARGETID_LIST), &ci_h); if (!ci) { - printk(KERN_WARNING - "megasas: Failed to alloc mem for ld_list_query\n"); + dev_warn(&instance->pdev->dev, + "Failed to alloc mem for ld_list_query\n"); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -4093,7 +4089,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get a free cmd\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a free cmd\n"); return -ENOMEM; } @@ -4103,7 +4099,7 @@ megasas_get_ctrl_info(struct megasas_instance *instance) sizeof(struct megasas_ctrl_info), &ci_h); if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem for ctrl info\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc mem for ctrl info\n"); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -4269,7 +4265,7 @@ megasas_issue_init_mfi(struct megasas_instance *instance) */ if (megasas_issue_polled(instance, cmd)) { - printk(KERN_ERR "megasas: Failed to init firmware\n"); + dev_err(&instance->pdev->dev, "Failed to init firmware\n"); megasas_return_cmd(instance, cmd); goto fail_fw_init; } @@ -4342,7 +4338,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) &instance->reply_queue_h); if (!instance->reply_queue) { - printk(KERN_DEBUG "megasas: Out of DMA mem for reply queue\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Out of DMA mem for reply queue\n"); goto fail_reply_queue; } @@ -4361,7 +4357,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance) (instance->instancet->read_fw_status_reg(reg_set) & 0x04000000); - printk(KERN_NOTICE "megasas_init_mfi: fw_support_ieee=%d", + dev_notice(&instance->pdev->dev, "megasas_init_mfi: fw_support_ieee=%d", instance->fw_support_ieee); if (instance->fw_support_ieee) @@ -4505,7 +4501,7 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->bar = find_first_bit(&bar_list, sizeof(unsigned long)); if (pci_request_selected_regions(instance->pdev, instance->bar, "megasas: LSI")) { - printk(KERN_DEBUG "megasas: IO memory region busy!\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "IO memory region busy!\n"); return -EBUSY; } @@ -4513,7 +4509,7 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->reg_set = ioremap_nocache(base_addr, 8192); if (!instance->reg_set) { - printk(KERN_DEBUG "megasas: Failed to map IO mem\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to map IO mem\n"); goto fail_ioremap; } @@ -4551,7 +4547,7 @@ static int megasas_init_fw(struct megasas_instance *instance) (instance, instance->reg_set); atomic_set(&instance->fw_reset_no_pci_access, 0); dev_info(&instance->pdev->dev, - "megasas: FW restarted successfully from %s!\n", + "FW restarted successfully from %s!\n", __func__); /*waitting for about 30 second before retry*/ @@ -4652,7 +4648,7 @@ static int megasas_init_fw(struct megasas_instance *instance) instance->instancet->enable_intr(instance); - printk(KERN_ERR "megasas: INIT adapter done\n"); + dev_err(&instance->pdev->dev, "INIT adapter done\n"); /** for passthrough * the following function will get the PD LIST. @@ -4661,7 +4657,7 @@ static int megasas_init_fw(struct megasas_instance *instance) memset(instance->pd_list, 0 , (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); if (megasas_get_pd_list(instance) < 0) { - printk(KERN_ERR "megasas: failed to get PD list\n"); + dev_err(&instance->pdev->dev, "failed to get PD list\n"); goto fail_get_pd_list; } @@ -4960,7 +4956,7 @@ megasas_register_aen(struct megasas_instance *instance, u32 seq_num, aen_cmd, 30); if (ret_val) { - printk(KERN_DEBUG "megasas: Failed to abort " + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to abort " "previous AEN command\n"); return ret_val; } @@ -5079,7 +5075,7 @@ static int megasas_io_attach(struct megasas_instance *instance) (max_sectors <= MEGASAS_MAX_SECTORS)) { instance->max_sectors_per_req = max_sectors; } else { - printk(KERN_INFO "megasas: max_sectors should be > 0" + dev_info(&instance->pdev->dev, "max_sectors should be > 0" "and <= %d (or < 1MB for GEN2 controller)\n", instance->max_sectors_per_req); } @@ -5206,7 +5202,7 @@ static int megasas_probe_one(struct pci_dev *pdev, sizeof(struct megasas_instance)); if (!host) { - printk(KERN_DEBUG "megasas: scsi_host_alloc failed\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "scsi_host_alloc failed\n"); goto fail_alloc_instance; } @@ -5226,7 +5222,7 @@ static int megasas_probe_one(struct pci_dev *pdev, instance->ctrl_context = (void *)__get_free_pages(GFP_KERNEL, instance->ctrl_context_pages); if (!instance->ctrl_context) { - printk(KERN_DEBUG "megasas: Failed to allocate " + dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate " "memory for Fusion context info\n"); goto fail_alloc_dma_buf; } @@ -5245,7 +5241,7 @@ static int megasas_probe_one(struct pci_dev *pdev, &instance->consumer_h); if (!instance->producer || !instance->consumer) { - printk(KERN_DEBUG "megasas: Failed to allocate" + dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate" "memory for producer, consumer\n"); goto fail_alloc_dma_buf; } @@ -5276,7 +5272,7 @@ static int megasas_probe_one(struct pci_dev *pdev, CRASH_DMA_BUF_SIZE, &instance->crash_dump_h); if (!instance->crash_dump_buf) - dev_err(&instance->pdev->dev, "Can't allocate Firmware " + dev_err(&pdev->dev, "Can't allocate Firmware " "crash dump DMA buffer\n"); megasas_poll_wait_aen = 0; @@ -5292,7 +5288,7 @@ static int megasas_probe_one(struct pci_dev *pdev, &instance->evt_detail_h); if (!instance->evt_detail) { - printk(KERN_DEBUG "megasas: Failed to allocate memory for " + dev_printk(KERN_DEBUG, &pdev->dev, "Failed to allocate memory for " "event detail structure\n"); goto fail_alloc_dma_buf; } @@ -5356,7 +5352,7 @@ static int megasas_probe_one(struct pci_dev *pdev, pci_alloc_consistent(pdev, sizeof(struct MR_LD_VF_AFFILIATION_111), &instance->vf_affiliation_111_h); if (!instance->vf_affiliation_111) - printk(KERN_WARNING "megasas: Can't allocate " + dev_warn(&pdev->dev, "Can't allocate " "memory for VF affiliation buffer\n"); } else { instance->vf_affiliation = @@ -5365,7 +5361,7 @@ static int megasas_probe_one(struct pci_dev *pdev, sizeof(struct MR_LD_VF_AFFILIATION), &instance->vf_affiliation_h); if (!instance->vf_affiliation) - printk(KERN_WARNING "megasas: Can't allocate " + dev_warn(&pdev->dev, "Can't allocate " "memory for VF affiliation buffer\n"); } } @@ -5399,7 +5395,7 @@ static int megasas_probe_one(struct pci_dev *pdev, * Initiate AEN (Asynchronous Event Notification) */ if (megasas_start_aen(instance)) { - printk(KERN_DEBUG "megasas: start aen failed\n"); + dev_printk(KERN_DEBUG, &pdev->dev, "start aen failed\n"); goto fail_start_aen; } @@ -5607,7 +5603,7 @@ megasas_resume(struct pci_dev *pdev) rval = pci_enable_device_mem(pdev); if (rval) { - printk(KERN_ERR "megasas: Enable device failed\n"); + dev_err(&pdev->dev, "Enable device failed\n"); return rval; } @@ -5686,7 +5682,7 @@ megasas_resume(struct pci_dev *pdev) * Initiate AEN (Asynchronous Event Notification) */ if (megasas_start_aen(instance)) - printk(KERN_ERR "megasas: Start AEN failed\n"); + dev_err(&instance->pdev->dev, "Start AEN failed\n"); return 0; @@ -5982,14 +5978,14 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, memset(kbuff_arr, 0, sizeof(kbuff_arr)); if (ioc->sge_count > MAX_IOCTL_SGE) { - printk(KERN_DEBUG "megasas: SGE count [%d] > max limit [%d]\n", + dev_printk(KERN_DEBUG, &instance->pdev->dev, "SGE count [%d] > max limit [%d]\n", ioc->sge_count, MAX_IOCTL_SGE); return -EINVAL; } cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get a cmd packet\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get a cmd packet\n"); return -ENOMEM; } @@ -6034,8 +6030,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, ioc->sgl[i].iov_len, &buf_handle, GFP_KERNEL); if (!kbuff_arr[i]) { - printk(KERN_DEBUG "megasas: Failed to alloc " - "kernel SGL buffer for IOCTL \n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc " + "kernel SGL buffer for IOCTL\n"); error = -ENOMEM; goto out; } @@ -6108,7 +6104,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, if (copy_to_user((void __user *)((unsigned long)(*sense_ptr)), sense, ioc->sense_len)) { - printk(KERN_ERR "megasas: Failed to copy out to user " + dev_err(&instance->pdev->dev, "Failed to copy out to user " "sense data\n"); error = -EFAULT; goto out; @@ -6120,7 +6116,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, */ if (copy_to_user(&user_ioc->frame.hdr.cmd_status, &cmd->frame->hdr.cmd_status, sizeof(u8))) { - printk(KERN_DEBUG "megasas: Error copying out cmd_status\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error copying out cmd_status\n"); error = -EFAULT; } @@ -6180,7 +6176,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) } if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - printk(KERN_ERR "Controller in crit error\n"); + dev_err(&instance->pdev->dev, "Controller in crit error\n"); error = -ENODEV; goto out_kfree_ioc; } @@ -6205,7 +6201,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) spin_unlock_irqrestore(&instance->hba_lock, flags); if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: waiting" + dev_notice(&instance->pdev->dev, "waiting" "for controller reset to finish\n"); } @@ -6216,7 +6212,7 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { spin_unlock_irqrestore(&instance->hba_lock, flags); - printk(KERN_ERR "megaraid_sas: timed out while" + dev_err(&instance->pdev->dev, "timed out while" "waiting for HBA to recover\n"); error = -ENODEV; goto out_up; @@ -6275,7 +6271,7 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) spin_unlock_irqrestore(&instance->hba_lock, flags); if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: waiting for" + dev_notice(&instance->pdev->dev, "waiting for" "controller reset to finish\n"); } @@ -6285,8 +6281,8 @@ static int megasas_mgmt_ioctl_aen(struct file *file, unsigned long arg) spin_lock_irqsave(&instance->hba_lock, flags); if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) { spin_unlock_irqrestore(&instance->hba_lock, flags); - printk(KERN_ERR "megaraid_sas: timed out while waiting" - "for HBA to recover.\n"); + dev_err(&instance->pdev->dev, "timed out while waiting" + "for HBA to recover\n"); return -ENODEV; } spin_unlock_irqrestore(&instance->hba_lock, flags); @@ -6502,7 +6498,7 @@ megasas_aen_polling(struct work_struct *work) if (instance->adprecovery == MEGASAS_HBA_OPERATIONAL) break; if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: %s waiting for " + dev_notice(&instance->pdev->dev, "%s waiting for " "controller reset to finish for scsi%d\n", __func__, instance->host->host_no); } @@ -6644,13 +6640,13 @@ megasas_aen_polling(struct work_struct *work) break; } } else { - printk(KERN_ERR "invalid evt_detail!\n"); + dev_err(&instance->pdev->dev, "invalid evt_detail!\n"); kfree(ev); return; } if (doscan) { - printk(KERN_INFO "megaraid_sas: scanning for scsi%d...\n", + dev_info(&instance->pdev->dev, "scanning for scsi%d...\n", instance->host->host_no); if (megasas_get_pd_list(instance) == 0) { for (i = 0; i < MEGASAS_MAX_PD_CHANNELS; i++) { @@ -6722,7 +6718,7 @@ megasas_aen_polling(struct work_struct *work) mutex_unlock(&instance->aen_mutex); if (error) - printk(KERN_ERR "register aen failed error %x\n", error); + dev_err(&instance->pdev->dev, "register aen failed error %x\n", error); kfree(ev); } diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c index 46a0f8f4f677e..f0837cc3b1639 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fusion.c +++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c @@ -221,7 +221,7 @@ static void megasas_teardown_frame_pool_fusion( struct megasas_cmd_fusion *cmd; if (!fusion->sg_dma_pool || !fusion->sense_dma_pool) { - printk(KERN_ERR "megasas: dma pool is null. SG Pool %p, " + dev_err(&instance->pdev->dev, "dma pool is null. SG Pool %p, " "sense pool : %p\n", fusion->sg_dma_pool, fusion->sense_dma_pool); return; @@ -332,8 +332,7 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) total_sz_chain_frame, 4, 0); if (!fusion->sg_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup request pool " - "fusion\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup request pool fusion\n"); return -ENOMEM; } fusion->sense_dma_pool = pci_pool_create("megasas sense pool fusion", @@ -341,8 +340,7 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) SCSI_SENSE_BUFFERSIZE, 64, 0); if (!fusion->sense_dma_pool) { - printk(KERN_DEBUG "megasas: failed to setup sense pool " - "fusion\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "failed to setup sense pool fusion\n"); pci_pool_destroy(fusion->sg_dma_pool); fusion->sg_dma_pool = NULL; return -ENOMEM; @@ -366,7 +364,7 @@ static int megasas_create_frame_pool_fusion(struct megasas_instance *instance) * whatever has been allocated */ if (!cmd->sg_frame || !cmd->sense) { - printk(KERN_DEBUG "megasas: pci_pool_alloc failed\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "pci_pool_alloc failed\n"); megasas_teardown_frame_pool_fusion(instance); return -ENOMEM; } @@ -412,7 +410,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) &fusion->req_frames_desc_phys, GFP_KERNEL); if (!fusion->req_frames_desc) { - printk(KERN_ERR "megasas; Could not allocate memory for " + dev_err(&instance->pdev->dev, "Could not allocate memory for " "request_frames\n"); goto fail_req_desc; } @@ -423,7 +421,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) fusion->reply_alloc_sz * count, 16, 0); if (!fusion->reply_frames_desc_pool) { - printk(KERN_ERR "megasas; Could not allocate memory for " + dev_err(&instance->pdev->dev, "Could not allocate memory for " "reply_frame pool\n"); goto fail_reply_desc; } @@ -432,7 +430,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) pci_pool_alloc(fusion->reply_frames_desc_pool, GFP_KERNEL, &fusion->reply_frames_desc_phys); if (!fusion->reply_frames_desc) { - printk(KERN_ERR "megasas; Could not allocate memory for " + dev_err(&instance->pdev->dev, "Could not allocate memory for " "reply_frame pool\n"); pci_pool_destroy(fusion->reply_frames_desc_pool); goto fail_reply_desc; @@ -449,7 +447,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) fusion->io_frames_alloc_sz, 16, 0); if (!fusion->io_request_frames_pool) { - printk(KERN_ERR "megasas: Could not allocate memory for " + dev_err(&instance->pdev->dev, "Could not allocate memory for " "io_request_frame pool\n"); goto fail_io_frames; } @@ -458,7 +456,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) pci_pool_alloc(fusion->io_request_frames_pool, GFP_KERNEL, &fusion->io_request_frames_phys); if (!fusion->io_request_frames) { - printk(KERN_ERR "megasas: Could not allocate memory for " + dev_err(&instance->pdev->dev, "Could not allocate memory for " "io_request_frames frames\n"); pci_pool_destroy(fusion->io_request_frames_pool); goto fail_io_frames; @@ -473,7 +471,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) * max_cmd, GFP_KERNEL); if (!fusion->cmd_list) { - printk(KERN_DEBUG "megasas: out of memory. Could not alloc " + dev_printk(KERN_DEBUG, &instance->pdev->dev, "out of memory. Could not alloc " "memory for cmd_list_fusion\n"); goto fail_cmd_list; } @@ -483,7 +481,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) fusion->cmd_list[i] = kmalloc(sizeof(struct megasas_cmd_fusion), GFP_KERNEL); if (!fusion->cmd_list[i]) { - printk(KERN_ERR "Could not alloc cmd list fusion\n"); + dev_err(&instance->pdev->dev, "Could not alloc cmd list fusion\n"); for (j = 0; j < i; j++) kfree(fusion->cmd_list[j]); @@ -527,7 +525,7 @@ megasas_alloc_cmds_fusion(struct megasas_instance *instance) * Create a frame pool and assign one frame to each cmd */ if (megasas_create_frame_pool_fusion(instance)) { - printk(KERN_DEBUG "megasas: Error creating frame DMA pool\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Error creating frame DMA pool\n"); megasas_free_cmds_fusion(instance); goto fail_req_desc; } @@ -613,7 +611,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_ERR "Could not allocate cmd for INIT Frame\n"); + dev_err(&instance->pdev->dev, "Could not allocate cmd for INIT Frame\n"); ret = 1; goto fail_get_cmd; } @@ -624,7 +622,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) &ioc_init_handle, GFP_KERNEL); if (!IOCInitMessage) { - printk(KERN_ERR "Could not allocate memory for " + dev_err(&instance->pdev->dev, "Could not allocate memory for " "IOCInitMessage\n"); ret = 1; goto fail_fw_init; @@ -714,7 +712,7 @@ megasas_ioc_init_fusion(struct megasas_instance *instance) ret = 1; goto fail_fw_init; } - printk(KERN_ERR "megasas:IOC Init cmd success\n"); + dev_err(&instance->pdev->dev, "Init cmd success\n"); ret = 0; @@ -757,7 +755,7 @@ megasas_get_ld_map_info(struct megasas_instance *instance) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get cmd for map info.\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get cmd for map info\n"); return -ENOMEM; } @@ -776,7 +774,7 @@ megasas_get_ld_map_info(struct megasas_instance *instance) ci_h = fusion->ld_map_phys[(instance->map_id & 1)]; if (!ci) { - printk(KERN_DEBUG "Failed to alloc mem for ld_map_info\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to alloc mem for ld_map_info\n"); megasas_return_cmd(instance, cmd); return -ENOMEM; } @@ -851,8 +849,7 @@ megasas_sync_map_info(struct megasas_instance *instance) cmd = megasas_get_cmd(instance); if (!cmd) { - printk(KERN_DEBUG "megasas: Failed to get cmd for sync" - "info.\n"); + dev_printk(KERN_DEBUG, &instance->pdev->dev, "Failed to get cmd for sync info\n"); return -ENOMEM; } @@ -1097,7 +1094,7 @@ megasas_init_adapter_fusion(struct megasas_instance *instance) &fusion->ld_map_phys[i], GFP_KERNEL); if (!fusion->ld_map[i]) { - printk(KERN_ERR "megasas: Could not allocate memory " + dev_err(&instance->pdev->dev, "Could not allocate memory " "for map info\n"); goto fail_map_info; } @@ -1162,7 +1159,7 @@ map_cmd_status(struct megasas_cmd_fusion *cmd, u8 status, u8 ext_status) cmd->scmd->result = DID_IMM_RETRY << 16; break; default: - printk(KERN_DEBUG "megasas: FW status %#x\n", status); + dev_printk(KERN_DEBUG, &cmd->instance->pdev->dev, "FW status %#x\n", status); cmd->scmd->result = DID_ERROR << 16; break; } @@ -1851,7 +1848,7 @@ megasas_build_io_fusion(struct megasas_instance *instance, &io_request->SGL, cmd); if (sge_count > instance->max_num_sge) { - printk(KERN_ERR "megasas: Error. sge_count (0x%x) exceeds " + dev_err(&instance->pdev->dev, "Error. sge_count (0x%x) exceeds " "max (0x%x) allowed\n", sge_count, instance->max_num_sge); return 1; @@ -1885,7 +1882,7 @@ megasas_get_request_descriptor(struct megasas_instance *instance, u16 index) struct fusion_context *fusion; if (index >= instance->max_fw_cmds) { - printk(KERN_ERR "megasas: Invalid SMID (0x%x)request for " + dev_err(&instance->pdev->dev, "Invalid SMID (0x%x)request for " "descriptor for scsi%d\n", index, instance->host->host_no); return NULL; @@ -1927,7 +1924,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, if (megasas_build_io_fusion(instance, scmd, cmd)) { megasas_return_cmd_fusion(instance, cmd); - printk(KERN_ERR "megasas: Error building command.\n"); + dev_err(&instance->pdev->dev, "Error building command\n"); cmd->request_desc = NULL; return 1; } @@ -1937,7 +1934,7 @@ megasas_build_and_issue_cmd_fusion(struct megasas_instance *instance, if (cmd->io_request->ChainOffset != 0 && cmd->io_request->ChainOffset != 0xF) - printk(KERN_ERR "megasas: The chain offset value is not " + dev_err(&instance->pdev->dev, "The chain offset value is not " "correct : %x\n", cmd->io_request->ChainOffset); /* @@ -2025,7 +2022,7 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex) if (reply_descript_type == MPI2_RPY_DESCRIPT_FLAGS_SCSI_IO_SUCCESS) { if (megasas_dbg_lvl == 5) - printk(KERN_ERR "\nmegasas: FAST Path " + dev_err(&instance->pdev->dev, "\nFAST Path " "IO Success\n"); } /* Fall thru and complete IO */ @@ -2186,7 +2183,7 @@ irqreturn_t megasas_isr_fusion(int irq, void *devp) else if (fw_state == MFI_STATE_FAULT) schedule_work(&instance->work_init); } else if (fw_state == MFI_STATE_FAULT) { - printk(KERN_WARNING "megaraid_sas: Iop2SysDoorbellInt" + dev_warn(&instance->pdev->dev, "Iop2SysDoorbellInt" "for scsi%d\n", instance->host->host_no); schedule_work(&instance->work_init); } @@ -2269,7 +2266,7 @@ build_mpt_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd) u16 index; if (build_mpt_mfi_pass_thru(instance, cmd)) { - printk(KERN_ERR "Couldn't build MFI pass thru cmd\n"); + dev_err(&instance->pdev->dev, "Couldn't build MFI pass thru cmd\n"); return NULL; } @@ -2303,7 +2300,7 @@ megasas_issue_dcmd_fusion(struct megasas_instance *instance, req_desc = build_mpt_cmd(instance, cmd); if (!req_desc) { - printk(KERN_ERR "Couldn't issue MFI pass thru cmd\n"); + dev_err(&instance->pdev->dev, "Couldn't issue MFI pass thru cmd\n"); return; } megasas_fire_cmd_fusion(instance, req_desc); @@ -2413,7 +2410,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, fw_state = instance->instancet->read_fw_status_reg( instance->reg_set) & MFI_STATE_MASK; if (fw_state == MFI_STATE_FAULT) { - printk(KERN_WARNING "megasas: Found FW in FAULT state," + dev_warn(&instance->pdev->dev, "Found FW in FAULT state," " will reset adapter scsi%d.\n", instance->host->host_no); retval = 1; @@ -2436,7 +2433,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, hb_seconds_missed++; if (hb_seconds_missed == (MEGASAS_SRIOV_HEARTBEAT_INTERVAL_VF/HZ)) { - printk(KERN_WARNING "megasas: SR-IOV:" + dev_warn(&instance->pdev->dev, "SR-IOV:" " Heartbeat never completed " " while polling during I/O " " timeout handling for " @@ -2454,7 +2451,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, goto out; if (!(i % MEGASAS_RESET_NOTICE_INTERVAL)) { - printk(KERN_NOTICE "megasas: [%2d]waiting for %d " + dev_notice(&instance->pdev->dev, "[%2d]waiting for %d " "commands to complete for scsi%d\n", i, outstanding, instance->host->host_no); megasas_complete_cmd_dpc_fusion( @@ -2464,7 +2461,7 @@ int megasas_wait_for_outstanding_fusion(struct megasas_instance *instance, } if (atomic_read(&instance->fw_outstanding)) { - printk("megaraid_sas: pending commands remain after waiting, " + dev_err(&instance->pdev->dev, "pending commands remain after waiting, " "will reset adapter scsi%d.\n", instance->host->host_no); retval = 1; @@ -2564,7 +2561,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) mutex_lock(&instance->reset_mutex); if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) { - printk(KERN_WARNING "megaraid_sas: Hardware critical error, " + dev_warn(&instance->pdev->dev, "Hardware critical error, " "returning FAILED for scsi%d.\n", instance->host->host_no); mutex_unlock(&instance->reset_mutex); @@ -2618,7 +2615,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) if (megasas_wait_for_outstanding_fusion(instance, iotimeout, &convert)) { instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT; - printk(KERN_WARNING "megaraid_sas: resetting fusion " + dev_warn(&instance->pdev->dev, "resetting fusion " "adapter scsi%d.\n", instance->host->host_no); if (convert) iotimeout = 0; @@ -2645,7 +2642,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) if (instance->disableOnlineCtrlReset || (abs_state == MFI_STATE_FAULT && !reset_adapter)) { /* Reset not supported, kill adapter */ - printk(KERN_WARNING "megaraid_sas: Reset not supported" + dev_warn(&instance->pdev->dev, "Reset not supported" ", killing adapter scsi%d.\n", instance->host->host_no); megaraid_sas_kill_hba(instance); @@ -2663,7 +2660,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) instance->hb_host_mem->HB.driverCounter)) { instance->hb_host_mem->HB.driverCounter = instance->hb_host_mem->HB.fwCounter; - printk(KERN_WARNING "megasas: SR-IOV:" + dev_warn(&instance->pdev->dev, "SR-IOV:" "Late FW heartbeat update for " "scsi%d.\n", instance->host->host_no); @@ -2679,8 +2676,8 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) abs_state = status_reg & MFI_STATE_MASK; if (abs_state == MFI_STATE_READY) { - printk(KERN_WARNING "megasas" - ": SR-IOV: FW was found" + dev_warn(&instance->pdev->dev, + "SR-IOV: FW was found" "to be in ready state " "for scsi%d.\n", instance->host->host_no); @@ -2689,7 +2686,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) msleep(20); } if (abs_state != MFI_STATE_READY) { - printk(KERN_WARNING "megasas: SR-IOV: " + dev_warn(&instance->pdev->dev, "SR-IOV: " "FW not in ready state after %d" " seconds for scsi%d, status_reg = " "0x%x.\n", @@ -2731,7 +2728,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) host_diag = readl(&instance->reg_set->fusion_host_diag); if (retry++ == 100) { - printk(KERN_WARNING "megaraid_sas: " + dev_warn(&instance->pdev->dev, "Host diag unlock failed! " "for scsi%d\n", instance->host->host_no); @@ -2754,7 +2751,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) host_diag = readl(&instance->reg_set->fusion_host_diag); if (retry++ == 1000) { - printk(KERN_WARNING "megaraid_sas: " + dev_warn(&instance->pdev->dev, "Diag reset adapter never " "cleared for scsi%d!\n", instance->host->host_no); @@ -2777,7 +2774,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) instance->reg_set) & MFI_STATE_MASK; } if (abs_state <= MFI_STATE_FW_INIT) { - printk(KERN_WARNING "megaraid_sas: firmware " + dev_warn(&instance->pdev->dev, "firmware " "state < MFI_STATE_FW_INIT, state = " "0x%x for scsi%d\n", abs_state, instance->host->host_no); @@ -2786,7 +2783,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) /* Wait for FW to become ready */ if (megasas_transition_to_ready(instance, 1)) { - printk(KERN_WARNING "megaraid_sas: Failed to " + dev_warn(&instance->pdev->dev, "Failed to " "transition controller to ready " "for scsi%d.\n", instance->host->host_no); @@ -2795,7 +2792,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) megasas_reset_reply_desc(instance); if (megasas_ioc_init_fusion(instance)) { - printk(KERN_WARNING "megaraid_sas: " + dev_warn(&instance->pdev->dev, "megasas_ioc_init_fusion() failed!" " for scsi%d\n", instance->host->host_no); @@ -2836,7 +2833,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) } /* Adapter reset completed successfully */ - printk(KERN_WARNING "megaraid_sas: Reset " + dev_warn(&instance->pdev->dev, "Reset " "successful for scsi%d.\n", instance->host->host_no); @@ -2852,7 +2849,7 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout) goto out; } /* Reset failed, kill the adapter */ - printk(KERN_WARNING "megaraid_sas: Reset failed, killing " + dev_warn(&instance->pdev->dev, "Reset failed, killing " "adapter scsi%d.\n", instance->host->host_no); megaraid_sas_kill_hba(instance); instance->skip_heartbeat_timer_del = 1; -- GitLab From da0dc9fb4e6b0ad5a947c27a3c48985f6a2377eb Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 7 Jul 2015 15:52:45 -0500 Subject: [PATCH 4996/7006] megaraid_sas: fix whitespace errors Fix whitespace and indentation errors. No code change. [jejb: checkpatch fixes] Signed-off-by: Bjorn Helgaas Reviewed-by: Hannes Reinecke Acked-by: Sumit Saxena Signed-off-by: James Bottomley --- drivers/scsi/megaraid/megaraid_sas_base.c | 244 +++++++++++----------- 1 file changed, 118 insertions(+), 126 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index a9bd592fde370..eaa81e552fd26 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -273,6 +273,7 @@ static inline void megasas_enable_intr_xscale(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; + regs = instance->reg_set; writel(0, &(regs)->outbound_intr_mask); @@ -289,6 +290,7 @@ megasas_disable_intr_xscale(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; u32 mask = 0x1f; + regs = instance->reg_set; writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -313,6 +315,7 @@ megasas_clear_intr_xscale(struct megasas_register_set __iomem * regs) { u32 status; u32 mfiStatus = 0; + /* * Check if it is our interrupt */ @@ -348,6 +351,7 @@ megasas_fire_cmd_xscale(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel((frame_phys_addr >> 3)|(frame_count), &(regs)->inbound_queue_port); @@ -364,6 +368,7 @@ megasas_adp_reset_xscale(struct megasas_instance *instance, { u32 i; u32 pcidata; + writel(MFI_ADP_RESET, ®s->inbound_doorbell); for (i = 0; i < 3; i++) @@ -402,7 +407,6 @@ static int megasas_check_reset_xscale(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { - if ((instance->adprecovery != MEGASAS_HBA_OPERATIONAL) && (le32_to_cpu(*instance->consumer) == MEGASAS_ADPRESET_INPROG_SIGN)) @@ -433,7 +437,7 @@ static struct megasas_instance_template megasas_instance_template_xscale = { /** * The following functions are defined for ppc (deviceid : 0x60) -* controllers +* controllers */ /** @@ -444,6 +448,7 @@ static inline void megasas_enable_intr_ppc(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; + regs = instance->reg_set; writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); @@ -462,6 +467,7 @@ megasas_disable_intr_ppc(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; u32 mask = 0xFFFFFFFF; + regs = instance->reg_set; writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -522,6 +528,7 @@ megasas_fire_cmd_ppc(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel((frame_phys_addr | (frame_count<<1))|1, &(regs)->inbound_queue_port); @@ -566,6 +573,7 @@ static inline void megasas_enable_intr_skinny(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; + regs = instance->reg_set; writel(0xFFFFFFFF, &(regs)->outbound_intr_mask); @@ -584,6 +592,7 @@ megasas_disable_intr_skinny(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; u32 mask = 0xFFFFFFFF; + regs = instance->reg_set; writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -634,8 +643,8 @@ megasas_clear_intr_skinny(struct megasas_register_set __iomem *regs) writel(status, ®s->outbound_intr_status); /* - * dummy read to flush PCI - */ + * dummy read to flush PCI + */ readl(®s->outbound_intr_status); return mfiStatus; @@ -654,6 +663,7 @@ megasas_fire_cmd_skinny(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel(upper_32_bits(frame_phys_addr), &(regs)->inbound_high_queue_port); @@ -706,6 +716,7 @@ static inline void megasas_enable_intr_gen2(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; + regs = instance->reg_set; writel(0xFFFFFFFF, &(regs)->outbound_doorbell_clear); @@ -725,6 +736,7 @@ megasas_disable_intr_gen2(struct megasas_instance *instance) { struct megasas_register_set __iomem *regs; u32 mask = 0xFFFFFFFF; + regs = instance->reg_set; writel(mask, ®s->outbound_intr_mask); /* Dummy readl to force pci flush */ @@ -750,6 +762,7 @@ megasas_clear_intr_gen2(struct megasas_register_set __iomem *regs) { u32 status; u32 mfiStatus = 0; + /* * Check if it is our interrupt */ @@ -786,6 +799,7 @@ megasas_fire_cmd_gen2(struct megasas_instance *instance, struct megasas_register_set __iomem *regs) { unsigned long flags; + spin_lock_irqsave(&instance->hba_lock, flags); writel((frame_phys_addr | (frame_count<<1))|1, &(regs)->inbound_queue_port); @@ -800,10 +814,10 @@ static int megasas_adp_reset_gen2(struct megasas_instance *instance, struct megasas_register_set __iomem *reg_set) { - u32 retry = 0 ; - u32 HostDiag; - u32 __iomem *seq_offset = ®_set->seq_offset; - u32 __iomem *hostdiag_offset = ®_set->host_diag; + u32 retry = 0 ; + u32 HostDiag; + u32 __iomem *seq_offset = ®_set->seq_offset; + u32 __iomem *hostdiag_offset = ®_set->host_diag; if (instance->instancet == &megasas_instance_template_skinny) { seq_offset = ®_set->fusion_seq_offset; @@ -821,7 +835,7 @@ megasas_adp_reset_gen2(struct megasas_instance *instance, HostDiag = (u32)readl(hostdiag_offset); - while ( !( HostDiag & DIAG_WRITE_ENABLE) ) { + while (!(HostDiag & DIAG_WRITE_ENABLE)) { msleep(100); HostDiag = (u32)readl(hostdiag_offset); dev_notice(&instance->pdev->dev, "RESETGEN2: retry=%x, hostdiag=%x\n", @@ -839,7 +853,7 @@ megasas_adp_reset_gen2(struct megasas_instance *instance, ssleep(10); HostDiag = (u32)readl(hostdiag_offset); - while ( ( HostDiag & DIAG_RESET_ADAPTER) ) { + while (HostDiag & DIAG_RESET_ADAPTER) { msleep(100); HostDiag = (u32)readl(hostdiag_offset); dev_notice(&instance->pdev->dev, "RESET_GEN2: retry=%x, hostdiag=%x\n", @@ -904,7 +918,6 @@ int megasas_issue_polled(struct megasas_instance *instance, struct megasas_cmd *cmd) { int seconds; - struct megasas_header *frame_hdr = &cmd->frame->hdr; frame_hdr->cmd_status = MFI_CMD_STATUS_POLL_MODE; @@ -940,6 +953,7 @@ megasas_issue_blocked_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, int timeout) { int ret = 0; + cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS; instance->instancet->issue_dcmd(instance, cmd); @@ -1120,7 +1134,7 @@ static u32 megasas_get_frame_count(struct megasas_instance *instance, int num_cnt; int sge_bytes; u32 sge_sz; - u32 frame_count=0; + u32 frame_count = 0; sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : sizeof(struct megasas_sge32); @@ -1151,14 +1165,14 @@ static u32 megasas_get_frame_count(struct megasas_instance *instance, num_cnt = sge_count - 3; } - if(num_cnt>0){ + if (num_cnt > 0) { sge_bytes = sge_sz * num_cnt; frame_count = (sge_bytes / MEGAMFI_FRAME_SIZE) + ((sge_bytes % MEGAMFI_FRAME_SIZE) ? 1 : 0) ; } /* Main frame */ - frame_count +=1; + frame_count += 1; if (frame_count > 7) frame_count = 8; @@ -1215,9 +1229,9 @@ megasas_build_dcdb(struct megasas_instance *instance, struct scsi_cmnd *scp, memcpy(pthru->cdb, scp->cmnd, scp->cmd_len); /* - * If the command is for the tape device, set the - * pthru timeout to the os layer timeout value. - */ + * If the command is for the tape device, set the + * pthru timeout to the os layer timeout value. + */ if (scp->device->type == TYPE_TAPE) { if ((scp->request->timeout / HZ) > 0xFFFF) pthru->timeout = cpu_to_le16(0xFFFF); @@ -1435,7 +1449,7 @@ inline int megasas_cmd_type(struct scsi_cmnd *cmd) /** * megasas_dump_pending_frames - Dumps the frame address of all pending cmds - * in FW + * in FW * @instance: Adapter soft state */ static inline void @@ -1459,7 +1473,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance) dev_err(&instance->pdev->dev, "[%d]: Pending OS cmds in FW : \n",instance->host->host_no); for (i = 0; i < max_cmd; i++) { cmd = instance->cmd_list[i]; - if(!cmd->scmd) + if (!cmd->scmd) continue; dev_err(&instance->pdev->dev, "[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr); if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) { @@ -1471,8 +1485,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance) instance->host->host_no, cmd->frame_count, ldio->cmd, ldio->target_id, le32_to_cpu(ldio->start_lba_lo), le32_to_cpu(ldio->start_lba_hi), le32_to_cpu(ldio->sense_buf_phys_addr_lo), sgcount); - } - else { + } else { pthru = (struct megasas_pthru_frame *) cmd->frame; mfi_sgl = &pthru->sgl; sgcount = pthru->sge_count; @@ -1482,16 +1495,16 @@ megasas_dump_pending_frames(struct megasas_instance *instance) pthru->lun, pthru->cdb_len, le32_to_cpu(pthru->data_xfer_len), le32_to_cpu(pthru->sense_buf_phys_addr_lo), sgcount); } - if(megasas_dbg_lvl & MEGASAS_DBG_LVL){ - for (n = 0; n < sgcount; n++){ - if (IS_DMA64) - dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n", - le32_to_cpu(mfi_sgl->sge64[n].length), - le64_to_cpu(mfi_sgl->sge64[n].phys_addr)); - else - dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n", - le32_to_cpu(mfi_sgl->sge32[n].length), - le32_to_cpu(mfi_sgl->sge32[n].phys_addr)); + if (megasas_dbg_lvl & MEGASAS_DBG_LVL) { + for (n = 0; n < sgcount; n++) { + if (IS_DMA64) + dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%llx\n", + le32_to_cpu(mfi_sgl->sge64[n].length), + le64_to_cpu(mfi_sgl->sge64[n].phys_addr)); + else + dev_err(&instance->pdev->dev, "sgl len : 0x%x, sgl addr : 0x%x\n", + le32_to_cpu(mfi_sgl->sge32[n].length), + le32_to_cpu(mfi_sgl->sge32[n].phys_addr)); } } } /*for max_cmd*/ @@ -1500,9 +1513,8 @@ megasas_dump_pending_frames(struct megasas_instance *instance) cmd = instance->cmd_list[i]; - if(cmd->sync_cmd == 1){ + if (cmd->sync_cmd == 1) dev_err(&instance->pdev->dev, "0x%08lx : ", (unsigned long)cmd->frame_phys_addr); - } } dev_err(&instance->pdev->dev, "[%d]: Dumping Done\n\n",instance->host->host_no); } @@ -1650,8 +1662,8 @@ static struct megasas_instance *megasas_lookup_instance(u16 host_no) static int megasas_slave_configure(struct scsi_device *sdev) { /* - * The RAID firmware may require extended timeouts. - */ + * The RAID firmware may require extended timeouts. + */ blk_queue_rq_timeout(sdev->request_queue, MEGASAS_DEFAULT_CMD_TIMEOUT * HZ); @@ -1660,8 +1672,9 @@ static int megasas_slave_configure(struct scsi_device *sdev) static int megasas_slave_alloc(struct scsi_device *sdev) { - u16 pd_index = 0; + u16 pd_index = 0; struct megasas_instance *instance ; + instance = megasas_lookup_instance(sdev->host->host_no); if (sdev->channel < MEGASAS_MAX_PD_CHANNELS) { /* @@ -1727,8 +1740,7 @@ void megaraid_sas_kill_hba(struct megasas_instance *instance) (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) || (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) || (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) { - writel(MFI_STOP_ADP, - &instance->reg_set->doorbell); + writel(MFI_STOP_ADP, &instance->reg_set->doorbell); /* Flush */ readl(&instance->reg_set->doorbell); if (instance->mpio && instance->requestorId) @@ -1782,7 +1794,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) unsigned long flags; /* If we have already declared adapter dead, donot complete cmds */ - if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR ) + if (instance->adprecovery == MEGASAS_HW_CRITICAL_ERROR) return; spin_lock_irqsave(&instance->completion_lock, flags); @@ -2285,14 +2297,14 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) if (adprecovery != MEGASAS_HBA_OPERATIONAL) { dev_notice(&instance->pdev->dev, "reset: Stopping HBA.\n"); spin_lock_irqsave(&instance->hba_lock, flags); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; spin_unlock_irqrestore(&instance->hba_lock, flags); return FAILED; } - reset_index = 0; + reset_index = 0; while (!list_empty(&clist_local)) { - reset_cmd = list_entry((&clist_local)->next, + reset_cmd = list_entry((&clist_local)->next, struct megasas_cmd, list); list_del_init(&reset_cmd->list); if (reset_cmd->scmd) { @@ -2324,7 +2336,6 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) } for (i = 0; i < resetwaittime; i++) { - int outstanding = atomic_read(&instance->fw_outstanding); if (!outstanding) @@ -2363,10 +2374,8 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) i++; } while (i <= 3); - if (atomic_read(&instance->fw_outstanding) && - !kill_adapter_flag) { + if (atomic_read(&instance->fw_outstanding) && !kill_adapter_flag) { if (instance->disableOnlineCtrlReset == 0) { - megasas_do_ocr(instance); /* wait for 5 secs to let FW finish the pending cmds */ @@ -2384,9 +2393,9 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) (kill_adapter_flag == 2)) { dev_notice(&instance->pdev->dev, "pending cmds after reset\n"); /* - * Send signal to FW to stop processing any pending cmds. - * The controller will be taken offline by the OS now. - */ + * Send signal to FW to stop processing any pending cmds. + * The controller will be taken offline by the OS now. + */ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) || (instance->pdev->device == @@ -2399,7 +2408,7 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance) } megasas_dump_pending_frames(instance); spin_lock_irqsave(&instance->hba_lock, flags); - instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; + instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR; spin_unlock_irqrestore(&instance->hba_lock, flags); return FAILED; } @@ -2478,14 +2487,10 @@ blk_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) */ static int megasas_reset_device(struct scsi_cmnd *scmd) { - int ret; - /* * First wait for all commands to complete */ - ret = megasas_generic_reset(scmd); - - return ret; + return megasas_generic_reset(scmd); } /** @@ -2495,6 +2500,7 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) { int ret; struct megasas_instance *instance; + instance = (struct megasas_instance *)scmd->device->host->hostdata; /* @@ -2513,7 +2519,7 @@ static int megasas_reset_bus_host(struct scsi_cmnd *scmd) /** * megasas_bios_param - Returns disk geometry for a disk - * @sdev: device handle + * @sdev: device handle * @bdev: block device * @capacity: drive capacity * @geom: geometry parameters @@ -2526,6 +2532,7 @@ megasas_bios_param(struct scsi_device *sdev, struct block_device *bdev, int sectors; sector_t cylinders; unsigned long tmp; + /* Default heads (64) & sectors (32) */ heads = 64; sectors = 32; @@ -2572,6 +2579,7 @@ static void megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) { unsigned long flags; + /* * Don't signal app if it is just an aborted previously registered aen */ @@ -2592,6 +2600,7 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd) if ((instance->unload == 0) && ((instance->issuepend_done == 1))) { struct megasas_aen_event *ev; + ev = kzalloc(sizeof(*ev), GFP_ATOMIC); if (!ev) { dev_err(&instance->pdev->dev, "megasas_service_aen: out of memory\n"); @@ -2651,8 +2660,7 @@ megasas_fw_crash_buffer_show(struct device *cdev, buff_addr = (unsigned long) buf; - if (buff_offset > - (instance->fw_crash_buffer_size * dmachunk)) { + if (buff_offset > (instance->fw_crash_buffer_size * dmachunk)) { dev_err(&instance->pdev->dev, "Firmware crash dump offset is out of range\n"); spin_unlock_irqrestore(&instance->crashdump_lock, flags); @@ -2664,7 +2672,7 @@ megasas_fw_crash_buffer_show(struct device *cdev, src_addr = (unsigned long)instance->crash_buf[buff_offset / dmachunk] + (buff_offset % dmachunk); - memcpy(buf, (void *)src_addr, size); + memcpy(buf, (void *)src_addr, size); spin_unlock_irqrestore(&instance->crashdump_lock, flags); return size; @@ -2724,6 +2732,7 @@ megasas_fw_crash_state_show(struct device *cdev, struct Scsi_Host *shost = class_to_shost(cdev); struct megasas_instance *instance = (struct megasas_instance *) shost->hostdata; + return snprintf(buf, PAGE_SIZE, "%d\n", instance->fw_crash_state); } @@ -2808,8 +2817,6 @@ megasas_complete_abort(struct megasas_instance *instance, cmd->cmd_status_drv = 0; wake_up(&instance->abort_cmd_wait_q); } - - return; } /** @@ -2817,10 +2824,10 @@ megasas_complete_abort(struct megasas_instance *instance, * @instance: Adapter soft state * @cmd: Command to be completed * @alt_status: If non-zero, use this value as status to - * SCSI mid-layer instead of the value returned - * by the FW. This should be used if caller wants - * an alternate status (as in the case of aborted - * commands) + * SCSI mid-layer instead of the value returned + * by the FW. This should be used if caller wants + * an alternate status (as in the case of aborted + * commands) */ void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, @@ -3001,7 +3008,7 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, /** * megasas_issue_pending_cmds_again - issue all pending cmds - * in FW again because of the fw reset + * in FW again because of the fw reset * @instance: Adapter soft state */ static inline void @@ -3019,7 +3026,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) spin_unlock_irqrestore(&instance->hba_lock, flags); while (!list_empty(&clist_local)) { - cmd = list_entry((&clist_local)->next, + cmd = list_entry((&clist_local)->next, struct megasas_cmd, list); list_del_init(&cmd->list); @@ -3052,7 +3059,7 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) "issue it again.\n", cmd); cmd->cmd_status_drv = MFI_STAT_INVALID_STATUS; instance->instancet->fire_cmd(instance, - cmd->frame_phys_addr , + cmd->frame_phys_addr, 0, instance->reg_set); } else if (cmd->scmd) { dev_notice(&instance->pdev->dev, "%p scsi cmd [%02x]" @@ -3074,12 +3081,12 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance) dev_notice(&instance->pdev->dev, "aen_cmd in def process\n"); megasas_return_cmd(instance, instance->aen_cmd); - instance->aen_cmd = NULL; + instance->aen_cmd = NULL; } /* - * Initiate AEN (Asynchronous Event Notification) - */ + * Initiate AEN (Asynchronous Event Notification) + */ seq_num = instance->last_seq_num; class_locale.members.reserved = 0; class_locale.members.locale = MR_EVT_LOCALE_ALL; @@ -3106,7 +3113,7 @@ megasas_internal_reset_defer_cmds(struct megasas_instance *instance) u32 defer_index; unsigned long flags; - defer_index = 0; + defer_index = 0; spin_lock_irqsave(&instance->mfi_pool_lock, flags); for (i = 0; i < max_cmd; i++) { cmd = instance->cmd_list[i]; @@ -3155,7 +3162,7 @@ process_fw_state_change_wq(struct work_struct *work) atomic_set(&instance->fw_reset_no_pci_access, 1); instance->instancet->adp_reset(instance, instance->reg_set); - atomic_set(&instance->fw_reset_no_pci_access, 0 ); + atomic_set(&instance->fw_reset_no_pci_access, 0); dev_notice(&instance->pdev->dev, "FW restarted successfully," "initiating next stage...\n"); @@ -3163,7 +3170,7 @@ process_fw_state_change_wq(struct work_struct *work) dev_notice(&instance->pdev->dev, "HBA recovery state machine," "state 2 starting...\n"); - /*waitting for about 20 second before start the second init*/ + /* waiting for about 20 second before start the second init */ for (wait = 0; wait < 30; wait++) { msleep(1000); } @@ -3196,15 +3203,14 @@ process_fw_state_change_wq(struct work_struct *work) megasas_issue_pending_cmds_again(instance); instance->issuepend_done = 1; } - return ; } /** * megasas_deplete_reply_queue - Processes all completed commands * @instance: Adapter soft state * @alt_status: Alternate status to be returned to - * SCSI mid-layer instead of the status - * returned by the FW + * SCSI mid-layer instead of the status + * returned by the FW * Note: this must be called with hba lock held */ static int @@ -3284,13 +3290,13 @@ static irqreturn_t megasas_isr(int irq, void *devp) struct megasas_irq_context *irq_context = devp; struct megasas_instance *instance = irq_context->instance; unsigned long flags; - irqreturn_t rc; + irqreturn_t rc; if (atomic_read(&instance->fw_reset_no_pci_access)) return IRQ_HANDLED; spin_lock_irqsave(&instance->hba_lock, flags); - rc = megasas_deplete_reply_queue(instance, DID_OK); + rc = megasas_deplete_reply_queue(instance, DID_OK); spin_unlock_irqrestore(&instance->hba_lock, flags); return rc; @@ -3566,9 +3572,8 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) sge_sz = (IS_DMA64) ? sizeof(struct megasas_sge64) : sizeof(struct megasas_sge32); - if (instance->flag_ieee) { + if (instance->flag_ieee) sge_sz = sizeof(struct megasas_sge_skinny); - } /* * For MFI controllers. @@ -3652,6 +3657,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance) void megasas_free_cmds(struct megasas_instance *instance) { int i; + /* First free the MFI frame pool */ megasas_teardown_frame_pool(instance); @@ -3807,12 +3813,12 @@ megasas_get_pd_list(struct megasas_instance *instance) ret = megasas_issue_polled(instance, cmd); /* - * the following function will get the instance PD LIST. - */ + * the following function will get the instance PD LIST. + */ pd_addr = ci->addr; - if ( ret == 0 && + if (ret == 0 && (le32_to_cpu(ci->count) < (MEGASAS_MAX_PD_CHANNELS * MEGASAS_MAX_DEV_PER_CHANNEL))) { @@ -4048,11 +4054,11 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance) instance->supportmax256vd ? "Extended VD(240 VD)firmware" : "Legacy(64 VD) firmware"); - old_map_sz = sizeof(struct MR_FW_RAID_MAP) + + old_map_sz = sizeof(struct MR_FW_RAID_MAP) + (sizeof(struct MR_LD_SPAN_MAP) * (instance->fw_supported_vd_count - 1)); - new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); - fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP) + + new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT); + fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP) + (sizeof(struct MR_LD_SPAN_MAP) * (instance->drv_supported_vd_count - 1)); @@ -4063,7 +4069,6 @@ static void megasas_update_ext_vd_details(struct megasas_instance *instance) fusion->current_map_sz = new_map_sz; else fusion->current_map_sz = old_map_sz; - } /** @@ -4210,9 +4215,7 @@ static int megasas_issue_init_mfi(struct megasas_instance *instance) { __le32 context; - struct megasas_cmd *cmd; - struct megasas_init_frame *init_frame; struct megasas_init_queue_info *initq_info; dma_addr_t init_frame_h; @@ -4651,10 +4654,9 @@ static int megasas_init_fw(struct megasas_instance *instance) dev_err(&instance->pdev->dev, "INIT adapter done\n"); /** for passthrough - * the following function will get the PD LIST. - */ - - memset(instance->pd_list, 0 , + * the following function will get the PD LIST. + */ + memset(instance->pd_list, 0, (MEGASAS_MAX_PD * sizeof(struct megasas_pd_list))); if (megasas_get_pd_list(instance) < 0) { dev_err(&instance->pdev->dev, "failed to get PD list\n"); @@ -4682,7 +4684,7 @@ static int megasas_init_fw(struct megasas_instance *instance) le16_to_cpu(ctrl_info->max_strips_per_io); max_sectors_2 = le32_to_cpu(ctrl_info->max_request_size); - tmp_sectors = min_t(u32, max_sectors_1 , max_sectors_2); + tmp_sectors = min_t(u32, max_sectors_1, max_sectors_2); instance->disableOnlineCtrlReset = ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset; @@ -5047,7 +5049,7 @@ static int megasas_start_aen(struct megasas_instance *instance) static int megasas_io_attach(struct megasas_instance *instance) { struct Scsi_Host *host = instance->host; - u32 error; + u32 error; /* * Export parameters required by SCSI mid-layer @@ -5122,7 +5124,7 @@ static int megasas_set_dma_mask(struct pci_dev *pdev) { /* - * All our contollers are capable of performing 64-bit DMA + * All our controllers are capable of performing 64-bit DMA */ if (IS_DMA64) { if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { @@ -5208,7 +5210,7 @@ static int megasas_probe_one(struct pci_dev *pdev, instance = (struct megasas_instance *)host->hostdata; memset(instance, 0, sizeof(*instance)); - atomic_set( &instance->fw_reset_no_pci_access, 0 ); + atomic_set(&instance->fw_reset_no_pci_access, 0); instance->pdev = pdev; switch (instance->pdev->device) { @@ -5405,8 +5407,8 @@ static int megasas_probe_one(struct pci_dev *pdev, return 0; - fail_start_aen: - fail_io_attach: +fail_start_aen: +fail_io_attach: megasas_mgmt_info.count--; megasas_mgmt_info.instance[megasas_mgmt_info.max_index] = NULL; megasas_mgmt_info.max_index--; @@ -5424,7 +5426,7 @@ static int megasas_probe_one(struct pci_dev *pdev, if (instance->msix_vectors) pci_disable_msix(instance->pdev); fail_init_mfi: - fail_alloc_dma_buf: +fail_alloc_dma_buf: if (instance->evt_detail) pci_free_consistent(pdev, sizeof(struct megasas_evt_detail), instance->evt_detail, @@ -5438,8 +5440,8 @@ fail_init_mfi: instance->consumer_h); scsi_host_put(host); - fail_alloc_instance: - fail_set_dma_mask: +fail_alloc_instance: +fail_set_dma_mask: pci_disable_device(pdev); return -ENODEV; @@ -5481,8 +5483,6 @@ static void megasas_flush_cache(struct megasas_instance *instance) " from %s\n", __func__); megasas_return_cmd(instance, cmd); - - return; } /** @@ -5528,8 +5528,6 @@ static void megasas_shutdown_controller(struct megasas_instance *instance, "from %s\n", __func__); megasas_return_cmd(instance, cmd); - - return; } #ifdef CONFIG_PM @@ -5835,8 +5833,6 @@ static void megasas_detach_one(struct pci_dev *pdev) scsi_host_put(host); pci_disable_device(pdev); - - return; } /** @@ -5905,11 +5901,11 @@ static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait) { unsigned int mask; unsigned long flags; + poll_wait(file, &megasas_poll_wait, wait); spin_lock_irqsave(&poll_aen_lock, flags); if (megasas_poll_wait_aen) - mask = (POLLIN | POLLRDNORM); - + mask = (POLLIN | POLLRDNORM); else mask = 0; megasas_poll_wait_aen = 0; @@ -5923,8 +5919,7 @@ static unsigned int megasas_mgmt_poll(struct file *file, poll_table *wait) * @cmd: MFI command frame */ -static int megasas_set_crash_dump_params_ioctl( - struct megasas_cmd *cmd) +static int megasas_set_crash_dump_params_ioctl(struct megasas_cmd *cmd) { struct megasas_instance *local_instance; int i, error = 0; @@ -6120,7 +6115,7 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, error = -EFAULT; } - out: +out: if (sense) { dma_free_coherent(&instance->pdev->dev, ioc->sense_len, sense, sense_handle); @@ -6220,10 +6215,10 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg) spin_unlock_irqrestore(&instance->hba_lock, flags); error = megasas_mgmt_fw_ioctl(instance, user_ioc, ioc); - out_up: +out_up: up(&instance->ioctl_sem); - out_kfree_ioc: +out_kfree_ioc: kfree(ioc); return error; } @@ -6458,7 +6453,8 @@ static ssize_t megasas_sysfs_set_dbg_lvl(struct device_driver *dd, const char *buf, size_t count) { int retval = count; - if(sscanf(buf,"%u",&megasas_dbg_lvl)<1){ + + if (sscanf(buf, "%u", &megasas_dbg_lvl) < 1) { printk(KERN_ERR "megasas: could not set dbg_lvl\n"); retval = -EINVAL; } @@ -6520,14 +6516,12 @@ megasas_aen_polling(struct work_struct *work) pd_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - sdev1 = - scsi_device_lookup(host, i, j, 0); + sdev1 = scsi_device_lookup(host, i, j, 0); if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { - if (!sdev1) { + if (!sdev1) scsi_add_device(host, i, j, 0); - } if (sdev1) scsi_device_put(sdev1); @@ -6548,14 +6542,12 @@ megasas_aen_polling(struct work_struct *work) pd_index = (i * MEGASAS_MAX_DEV_PER_CHANNEL) + j; - sdev1 = - scsi_device_lookup(host, i, j, 0); + sdev1 = scsi_device_lookup(host, i, j, 0); if (instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) { - if (sdev1) { + if (sdev1) scsi_device_put(sdev1); - } } else { if (sdev1) { scsi_remove_device(sdev1); @@ -6701,7 +6693,7 @@ megasas_aen_polling(struct work_struct *work) } } - if ( instance->aen_cmd != NULL ) { + if (instance->aen_cmd != NULL) { kfree(ev); return ; } -- GitLab From 2d3a5d215e24d9bfb822ae82c6c2c5d333be076d Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 8 Jul 2015 17:24:01 +0200 Subject: [PATCH 4997/7006] st: Destroy st_index_idr on module exit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Destroy st_index_idr on module exit, reclaiming the allocated memory. This was detected by the following semantic patch (written by Luis Rodriguez ) @ defines_module_init @ declarer name module_init, module_exit; declarer name DEFINE_IDR; identifier init; @@ module_init(init); @ defines_module_exit @ identifier exit; @@ module_exit(exit); @ declares_idr depends on defines_module_init && defines_module_exit @ identifier idr; @@ DEFINE_IDR(idr); @ on_exit_calls_destroy depends on declares_idr && defines_module_exit @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... idr_destroy(&idr); ... } @ missing_module_idr_destroy depends on declares_idr && defines_module_exit && !on_exit_calls_destroy @ identifier declares_idr.idr, defines_module_exit.exit; @@ exit(void) { ... +idr_destroy(&idr); } Signed-off-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Acked-by: Kai Mäkisara Signed-off-by: James Bottomley --- drivers/scsi/st.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 9cf3272daa699..b37b9b00c4b46 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -4419,6 +4419,7 @@ static void __exit exit_st(void) unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); class_unregister(&st_sysfs_class); + idr_destroy(&st_index_idr); printk(KERN_INFO "st: Unloaded.\n"); } -- GitLab From e19b127f5b76ec03b9c52b64f117dc75bb39eda1 Mon Sep 17 00:00:00 2001 From: Alok Pandey Date: Wed, 26 Aug 2015 08:56:14 -0600 Subject: [PATCH 4998/7006] NVMe: Using PRACT bit to generate and verify PI by controller This patch enables the PRCHK and reftag support when PRACT bit is set, and block layer integrity is disabled. Signed-off-by: Alok Pandey Reviewed-by: Keith Busch Signed-off-by: Jens Axboe --- drivers/block/nvme-core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c index caad00fbf820e..8de3de0107414 100644 --- a/drivers/block/nvme-core.c +++ b/drivers/block/nvme-core.c @@ -813,8 +813,7 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, cmnd.rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req))); cmnd.rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1); - if (blk_integrity_rq(req)) { - cmnd.rw.metadata = cpu_to_le64(sg_dma_address(iod->meta_sg)); + if (ns->ms) { switch (ns->pi_type) { case NVME_NS_DPS_PI_TYPE3: control |= NVME_RW_PRINFO_PRCHK_GUARD; @@ -827,8 +826,12 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod, nvme_block_nr(ns, blk_rq_pos(req))); break; } - } else if (ns->ms) - control |= NVME_RW_PRINFO_PRACT; + if (blk_integrity_rq(req)) + cmnd.rw.metadata = + cpu_to_le64(sg_dma_address(iod->meta_sg)); + else + control |= NVME_RW_PRINFO_PRACT; + } cmnd.rw.control = cpu_to_le16(control); cmnd.rw.dsmgmt = cpu_to_le32(dsmgmt); @@ -2037,7 +2040,7 @@ static int nvme_revalidate_disk(struct gendisk *disk) !ns->ext) nvme_init_integrity(ns); - if (ns->ms && !blk_get_integrity(disk)) + if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk)) set_capacity(disk, 0); else set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9)); -- GitLab From 6602c452caf532893c1bde50aacda0bd17f958aa Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 25 Aug 2015 17:04:02 -0700 Subject: [PATCH 4999/7006] of/irq: export of_get_irq_byname() Similarly to of_get_irq(), let's export of_irq_get_byname(), so if a bus core can be compiled as a module (such as I2C) it can have access to the symbol. Reported-by: Stephen Rothwell Reported-by: kbuild test robot Signed-off-by: Dmitry Torokhov Acked-by: Rob Herring Signed-off-by: Wolfram Sang --- drivers/of/irq.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 3cf7a01f557f4..e9eaed1dc996c 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -431,6 +431,7 @@ int of_irq_get_byname(struct device_node *dev, const char *name) return of_irq_get(dev, index); } +EXPORT_SYMBOL_GPL(of_irq_get_byname); /** * of_irq_count - Count the number of IRQs a node uses -- GitLab From 3fffd12839273429a185d68431f117f0a3654b07 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 17 Aug 2015 23:52:51 -0700 Subject: [PATCH 5000/7006] i2c: allow specifying separate wakeup interrupt in device tree Instead of having each i2c driver individually parse device tree data in case it or platform supports separate wakeup interrupt, and handle enabling and disabling wakeup interrupts in their power management routines, let's have i2c core do that for us. Platforms wishing to specify separate wakeup interrupt for the device should use named interrupt syntax in their DTSes: interrupt-parent = <&intc1>; interrupts = <5 0>, <6 0>; interrupt-names = "irq", "wakeup"; This patch is inspired by work done by Vignesh R for pixcir_i2c_ts driver. Note that the original code tried to preserve any existing wakeup settings from userspace but was not quite right in that regard: it would preserve wakeup flag set by userspace upon driver rebinding; but it would re-arm the wakeup flag if it was disabled by userspace. We think that resetting the flag upon re-binding the driver is proper behavior as the driver is responsible for setting up and handling wakeups. Signed-off-by: Dmitry Torokhov Tested-by: Vignesh R [wsa: updated the commit message] Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c.txt | 16 +++++- drivers/i2c/i2c-core.c | 51 +++++++++++++++---- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index 1175efed4a41b..8a99150ac3a7f 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -12,7 +12,7 @@ Required properties - compatible - name of I2C bus controller following generic names recommended practice. -For other required properties e.g. to describe register sets, interrupts, +For other required properties e.g. to describe register sets, clocks, etc. check the binding documentation of the specific driver. The cells properties above define that an address of children of an I2C bus @@ -29,5 +29,17 @@ Optional properties These properties may not be supported by all drivers. However, if a driver wants to support one of the below features, it should adapt the bindings below. -- clock-frequency - frequency of bus clock in Hz +- clock-frequency - frequency of bus clock in Hz. - wakeup-source - device can be used as a wakeup source. + +- interrupts - interrupts used by the device. +- interrupt-names - "irq" and "wakeup" names are recognized by I2C core, + other names are left to individual drivers. + +Binding may contain optional "interrupts" property, describing interrupts +used by the device. I2C core will assign "irq" interrupt (or the very first +interrupt if not using interrupt names) as primary interrupt for the slave. + +Also, if device is marked as a wakeup source, I2C core will set up "wakeup" +interrupt for the device. If "wakeup" interrupt name is not present in the +binding, then primary interrupt will be used as wakeup interrupt. diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 98f6c75b1d18e..5f89f1e3c2f24 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -645,11 +646,13 @@ static int i2c_device_probe(struct device *dev) if (!client->irq) { int irq = -ENOENT; - if (dev->of_node) - irq = of_irq_get(dev->of_node, 0); - else if (ACPI_COMPANION(dev)) + if (dev->of_node) { + irq = of_irq_get_byname(dev->of_node, "irq"); + if (irq == -EINVAL || irq == -ENODATA) + irq = of_irq_get(dev->of_node, 0); + } else if (ACPI_COMPANION(dev)) { irq = acpi_dev_gpio_irq_get(ACPI_COMPANION(dev), 0); - + } if (irq == -EPROBE_DEFER) return irq; if (irq < 0) @@ -662,23 +665,49 @@ static int i2c_device_probe(struct device *dev) if (!driver->probe || !driver->id_table) return -ENODEV; - if (!device_can_wakeup(&client->dev)) - device_init_wakeup(&client->dev, - client->flags & I2C_CLIENT_WAKE); + if (client->flags & I2C_CLIENT_WAKE) { + int wakeirq = -ENOENT; + + if (dev->of_node) { + wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); + if (wakeirq == -EPROBE_DEFER) + return wakeirq; + } + + device_init_wakeup(&client->dev, true); + + if (wakeirq > 0 && wakeirq != client->irq) + status = dev_pm_set_dedicated_wake_irq(dev, wakeirq); + else if (client->irq > 0) + status = dev_pm_set_wake_irq(dev, wakeirq); + else + status = 0; + + if (status) + dev_warn(&client->dev, "failed to set up wakeup irq"); + } + dev_dbg(dev, "probe\n"); status = of_clk_set_defaults(dev->of_node, false); if (status < 0) - return status; + goto err_clear_wakeup_irq; status = dev_pm_domain_attach(&client->dev, true); if (status != -EPROBE_DEFER) { status = driver->probe(client, i2c_match_id(driver->id_table, client)); if (status) - dev_pm_domain_detach(&client->dev, true); + goto err_detach_pm_domain; } + return 0; + +err_detach_pm_domain: + dev_pm_domain_detach(&client->dev, true); +err_clear_wakeup_irq: + dev_pm_clear_wake_irq(&client->dev); + device_init_wakeup(&client->dev, false); return status; } @@ -698,6 +727,10 @@ static int i2c_device_remove(struct device *dev) } dev_pm_domain_detach(&client->dev, true); + + dev_pm_clear_wake_irq(&client->dev); + device_init_wakeup(&client->dev, false); + return status; } -- GitLab From e51e38494a8ecc18650efb0c840600637891de2c Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 20 Aug 2015 14:28:48 -0700 Subject: [PATCH 5001/7006] Input: synaptics - fix handling of disabling gesture mode Bit 2 of the mode byte has dual meaning: it can disable reporting of gestures when touchpad works in Relative mode or normal Absolute mode, or it can enable so called Extended W-Mode when touchpad uses enhanced Absolute mode (W-mode). The extended W-Mode confuses our driver and causes missing button presses on some Thinkpads (x250, T450s), so let's make sure we do not enable it. Also, according to the spec W mode "... bit is defined only in Absolute mode on pads whose capExtended capability bit is set. In Relative mode and in TouchPads without this capability, the bit is reserved and should be left at 0.", so let's make sure we respect this requirement as well. Reported-by: Nick Bowler Suggested-by: Gabor Balla Tested-by: Gabor Balla Tested-by: Nick Bowler Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 6025eb430c0a5..994ae78861569 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -519,14 +519,18 @@ static int synaptics_set_mode(struct psmouse *psmouse) struct synaptics_data *priv = psmouse->private; priv->mode = 0; - if (priv->absolute_mode) + + if (priv->absolute_mode) { priv->mode |= SYN_BIT_ABSOLUTE_MODE; - if (priv->disable_gesture) + if (SYN_CAP_EXTENDED(priv->capabilities)) + priv->mode |= SYN_BIT_W_MODE; + } + + if (!SYN_MODE_WMODE(priv->mode) && priv->disable_gesture) priv->mode |= SYN_BIT_DISABLE_GESTURE; + if (psmouse->rate >= 80) priv->mode |= SYN_BIT_HIGH_RATE; - if (SYN_CAP_EXTENDED(priv->capabilities)) - priv->mode |= SYN_BIT_W_MODE; if (synaptics_mode_cmd(psmouse, priv->mode)) return -1; -- GitLab From c3ff356d08275960b4a36471a81d5b2685a4074e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:22:38 -0700 Subject: [PATCH 5002/7006] qla2xxx: Report both rsp_info and rsp_info_len Let the debug statement in qlafx00_tm_iocb_entry() report both rsp_info and rsp_info_len instead of reporting rsp_info_len twice. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 6d190b4b82a07..878fd3d961f84 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -2528,12 +2528,12 @@ check_scsi_status: ql_dbg(ql_dbg_io, fcport->vha, 0x3058, "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu " "tgt_id: 0x%x lscsi_status: 0x%x cdb=%10phN len=0x%x " - "rsp_info=0x%x resid=0x%x fw_resid=0x%x sense_len=0x%x, " + "rsp_info=%p resid=0x%x fw_resid=0x%x sense_len=0x%x, " "par_sense_len=0x%x, rsp_info_len=0x%x\n", comp_status, scsi_status, res, vha->host_no, cp->device->id, cp->device->lun, fcport->tgt_id, lscsi_status, cp->cmnd, scsi_bufflen(cp), - rsp_info_len, resid_len, fw_resid_len, sense_len, + rsp_info, resid_len, fw_resid_len, sense_len, par_sense_len, rsp_info_len); if (rsp->status_srb == NULL) -- GitLab From 2374dd238c287fb7a370b53aad2dbc4c8f0c241c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:23:02 -0700 Subject: [PATCH 5003/7006] qla2xxx: Declare local functions static Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_bsg.c | 2 +- drivers/scsi/qla2xxx/qla_iocb.c | 4 ++-- drivers/scsi/qla2xxx/qla_nx.c | 2 +- drivers/scsi/qla2xxx/qla_nx2.c | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index 2e2bb6f45ce67..e1c2a57a882f6 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -405,7 +405,7 @@ done: return rval; } -inline uint16_t +static inline uint16_t qla24xx_calc_ct_iocbs(uint16_t dsds) { uint16_t iocbs; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 36fbd4c7af8f5..d58ffb79c064e 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -680,7 +680,7 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, * * Returns the number of dsd list needed to store @dsds. */ -inline uint16_t +static inline uint16_t qla24xx_calc_dsd_lists(uint16_t dsds) { uint16_t dsd_lists = 0; @@ -700,7 +700,7 @@ qla24xx_calc_dsd_lists(uint16_t dsds) * @cmd_pkt: Command type 3 IOCB * @tot_dsds: Total number of segments to transfer */ -inline void +static inline void qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, uint16_t tot_dsds) { diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 1620b0ec977ba..47f8419adf418 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2298,7 +2298,7 @@ void qla82xx_init_flags(struct qla_hw_data *ha) ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg; } -inline void +static inline void qla82xx_set_idc_version(scsi_qla_host_t *vha) { int idc_ver; diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 000c57e4d0338..e06c851147d0f 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -561,7 +561,7 @@ qla8044_read_optrom_data(struct scsi_qla_host *vha, uint8_t *buf, return buf; } -inline int +static inline int qla8044_need_reset(struct scsi_qla_host *vha) { uint32_t drv_state, drv_active; @@ -1605,7 +1605,7 @@ qla8044_set_idc_dontreset(struct scsi_qla_host *vha) qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl); } -inline void +static inline void qla8044_set_rst_ready(struct scsi_qla_host *vha) { uint32_t drv_state; -- GitLab From 52c82823cc686d4faf9e9bc4feec4bf48c36fded Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:23:26 -0700 Subject: [PATCH 5004/7006] qla2xxx: Remove set-but-not-used variables Detected these variables by building with W=1. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 2 -- drivers/scsi/qla2xxx/qla_bsg.c | 5 ----- drivers/scsi/qla2xxx/qla_dbg.c | 24 ++++++------------------ drivers/scsi/qla2xxx/qla_init.c | 10 ++++------ drivers/scsi/qla2xxx/qla_iocb.c | 24 +++--------------------- drivers/scsi/qla2xxx/qla_isr.c | 3 +-- drivers/scsi/qla2xxx/qla_mbx.c | 4 ---- drivers/scsi/qla2xxx/qla_mid.c | 3 +-- drivers/scsi/qla2xxx/qla_mr.c | 10 +++------- drivers/scsi/qla2xxx/qla_nx.c | 9 +++------ drivers/scsi/qla2xxx/qla_nx2.c | 12 ++++-------- drivers/scsi/qla2xxx/qla_os.c | 6 ++---- drivers/scsi/qla2xxx/qla_target.c | 19 ++++--------------- drivers/scsi/qla2xxx/qla_tmpl.c | 3 +-- 14 files changed, 32 insertions(+), 102 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 82b92c414a9cf..741d6e0f40603 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -884,7 +884,6 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj, struct device, kobj))); struct qla_hw_data *ha = vha->hw; int rval; - uint16_t actual_size; if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE) return 0; @@ -901,7 +900,6 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj, } do_read: - actual_size = 0; memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE); rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma, diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index e1c2a57a882f6..c26acde797f0d 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -1733,7 +1733,6 @@ qla24xx_process_bidir_cmd(struct fc_bsg_job *bsg_job) struct Scsi_Host *host = bsg_job->shost; scsi_qla_host_t *vha = shost_priv(host); struct qla_hw_data *ha = vha->hw; - uint16_t thread_id; uint32_t rval = EXT_STATUS_OK; uint16_t req_sg_cnt = 0; uint16_t rsp_sg_cnt = 0; @@ -1790,8 +1789,6 @@ qla24xx_process_bidir_cmd(struct fc_bsg_job *bsg_job) goto done; } - thread_id = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1]; - mutex_lock(&ha->selflogin_lock); if (vha->self_login_loop_id == 0) { /* Initialize all required fields of fcport */ @@ -2174,7 +2171,6 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job) { int ret = -EINVAL; struct fc_rport *rport; - fc_port_t *fcport = NULL; struct Scsi_Host *host; scsi_qla_host_t *vha; @@ -2183,7 +2179,6 @@ qla24xx_bsg_request(struct fc_bsg_job *bsg_job) if (bsg_job->request->msgcode == FC_BSG_RPT_ELS) { rport = bsg_job->rport; - fcport = *(fc_port_t **) rport->dd_data; host = rport_to_shost(rport); vha = shost_priv(host); } else { diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 0e6ee3ca30e66..121ed5bdb4fa3 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -117,7 +117,7 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, { int rval; uint32_t cnt, stat, timer, dwords, idx; - uint16_t mb0, mb1; + uint16_t mb0; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; dma_addr_t dump_dma = ha->gid_list_dma; uint32_t *dump = (uint32_t *)ha->gid_list; @@ -161,7 +161,7 @@ qla27xx_dump_mpi_ram(struct qla_hw_data *ha, uint32_t addr, uint32_t *ram, &ha->mbx_cmd_flags); mb0 = RD_REG_WORD(®->mailbox0); - mb1 = RD_REG_WORD(®->mailbox1); + RD_REG_WORD(®->mailbox1); WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); @@ -1039,7 +1039,6 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) { int rval; uint32_t cnt; - uint32_t risc_address; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; @@ -1047,7 +1046,6 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint16_t __iomem *mbx_reg; unsigned long flags; struct qla24xx_fw_dump *fw; - uint32_t ext_mem_cnt; void *nxt; void *nxt_chain; uint32_t *last_chain = NULL; @@ -1056,7 +1054,6 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) if (IS_P3P_TYPE(ha)) return; - risc_address = ext_mem_cnt = 0; flags = 0; ha->fw_dump_cap_flags = 0; @@ -1294,7 +1291,6 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) { int rval; uint32_t cnt; - uint32_t risc_address; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; @@ -1302,12 +1298,10 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint16_t __iomem *mbx_reg; unsigned long flags; struct qla25xx_fw_dump *fw; - uint32_t ext_mem_cnt; void *nxt, *nxt_chain; uint32_t *last_chain = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - risc_address = ext_mem_cnt = 0; flags = 0; ha->fw_dump_cap_flags = 0; @@ -1613,7 +1607,6 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) { int rval; uint32_t cnt; - uint32_t risc_address; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; @@ -1621,12 +1614,10 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint16_t __iomem *mbx_reg; unsigned long flags; struct qla81xx_fw_dump *fw; - uint32_t ext_mem_cnt; void *nxt, *nxt_chain; uint32_t *last_chain = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - risc_address = ext_mem_cnt = 0; flags = 0; ha->fw_dump_cap_flags = 0; @@ -1933,8 +1924,7 @@ void qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) { int rval; - uint32_t cnt, reg_data; - uint32_t risc_address; + uint32_t cnt; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; uint32_t __iomem *dmp_reg; @@ -1942,12 +1932,10 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) uint16_t __iomem *mbx_reg; unsigned long flags; struct qla83xx_fw_dump *fw; - uint32_t ext_mem_cnt; void *nxt, *nxt_chain; uint32_t *last_chain = NULL; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - risc_address = ext_mem_cnt = 0; flags = 0; ha->fw_dump_cap_flags = 0; @@ -1979,16 +1967,16 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) WRT_REG_DWORD(®->iobase_addr, 0x6000); dmp_reg = ®->iobase_window; - reg_data = RD_REG_DWORD(dmp_reg); + RD_REG_DWORD(dmp_reg); WRT_REG_DWORD(dmp_reg, 0); dmp_reg = ®->unused_4_1[0]; - reg_data = RD_REG_DWORD(dmp_reg); + RD_REG_DWORD(dmp_reg); WRT_REG_DWORD(dmp_reg, 0); WRT_REG_DWORD(®->iobase_addr, 0x6010); dmp_reg = ®->unused_4_1[2]; - reg_data = RD_REG_DWORD(dmp_reg); + RD_REG_DWORD(dmp_reg); WRT_REG_DWORD(dmp_reg, 0); /* select PCR and disable ecc checking and correction */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 664013115c9da..f4a64a4fc40a4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1127,7 +1127,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) unsigned long flags = 0; struct qla_hw_data *ha = vha->hw; struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - uint32_t cnt, d2; + uint32_t cnt; uint16_t wd; static int abts_cnt; /* ISP abort retry counts */ int rval = QLA_SUCCESS; @@ -1159,7 +1159,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) udelay(100); /* Wait for firmware to complete NVRAM accesses. */ - d2 = (uint32_t) RD_REG_WORD(®->mailbox0); + RD_REG_WORD(®->mailbox0); for (cnt = 10000; RD_REG_WORD(®->mailbox0) != 0 && rval == QLA_SUCCESS; cnt--) { barrier(); @@ -1178,7 +1178,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) RD_REG_DWORD(®->mailbox0)); /* Wait for soft-reset to complete. */ - d2 = RD_REG_DWORD(®->ctrl_status); + RD_REG_DWORD(®->ctrl_status); for (cnt = 0; cnt < 6000000; cnt++) { barrier(); if ((RD_REG_DWORD(®->ctrl_status) & @@ -1221,7 +1221,7 @@ qla24xx_reset_risc(scsi_qla_host_t *vha) WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_RESET); RD_REG_DWORD(®->hccr); - d2 = (uint32_t) RD_REG_WORD(®->mailbox0); + RD_REG_WORD(®->mailbox0); for (cnt = 6000000; RD_REG_WORD(®->mailbox0) != 0 && rval == QLA_SUCCESS; cnt--) { barrier(); @@ -3856,12 +3856,10 @@ qla2x00_fabric_dev_login(scsi_qla_host_t *vha, fc_port_t *fcport, uint16_t *next_loopid) { int rval; - int retry; uint8_t opts; struct qla_hw_data *ha = vha->hw; rval = QLA_SUCCESS; - retry = 0; if (IS_ALOGIO_CAPABLE(ha)) { if (fcport->flags & FCF_ASYNC_SENT) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index d58ffb79c064e..e95162e1fcb75 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -310,7 +310,7 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, int qla2x00_start_scsi(srb_t *sp) { - int ret, nseg; + int nseg; unsigned long flags; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; @@ -327,7 +327,6 @@ qla2x00_start_scsi(srb_t *sp) struct rsp_que *rsp; /* Setup device pointers. */ - ret = 0; vha = sp->fcport->vha; ha = vha->hw; reg = &ha->iobase->isp; @@ -710,7 +709,6 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, struct scsi_cmnd *cmd; struct scatterlist *sg; int i; - struct req_que *req; cmd = GET_CMD_SP(sp); @@ -725,7 +723,6 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, } vha = sp->fcport->vha; - req = vha->req; /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { @@ -933,11 +930,9 @@ qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, dma_addr_t sle_dma; uint32_t sle_dma_len, tot_prot_dma_len = 0; struct scsi_cmnd *cmd; - struct scsi_qla_host *vha; memset(&sgx, 0, sizeof(struct qla2_sgx)); if (sp) { - vha = sp->fcport->vha; cmd = GET_CMD_SP(sp); prot_int = cmd->device->sector_size; @@ -947,7 +942,6 @@ qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *ha, srb_t *sp, sg_prot = scsi_prot_sglist(cmd); } else if (tc) { - vha = tc->vha; prot_int = tc->blk_sz; sgx.tot_bytes = tc->bufflen; sgx.cur_sg = tc->sg; @@ -1047,15 +1041,12 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, int i; uint16_t used_dsds = tot_dsds; struct scsi_cmnd *cmd; - struct scsi_qla_host *vha; if (sp) { cmd = GET_CMD_SP(sp); sgl = scsi_sglist(cmd); - vha = sp->fcport->vha; } else if (tc) { sgl = tc->sg; - vha = tc->vha; } else { BUG(); return 1; @@ -1231,7 +1222,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, uint32_t *cur_dsd, *fcp_dl; scsi_qla_host_t *vha; struct scsi_cmnd *cmd; - int sgc; uint32_t total_bytes = 0; uint32_t data_bytes; uint32_t dif_bytes; @@ -1247,7 +1237,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, cmd = GET_CMD_SP(sp); - sgc = 0; /* Update entry type to indicate Command Type CRC_2 IOCB */ *((uint32_t *)(&cmd_pkt->entry_type)) = __constant_cpu_to_le32(COMMAND_TYPE_CRC_2); @@ -1442,7 +1431,7 @@ crc_queuing_error: int qla24xx_start_scsi(srb_t *sp) { - int ret, nseg; + int nseg; unsigned long flags; uint32_t *clr_ptr; uint32_t index; @@ -1458,8 +1447,6 @@ qla24xx_start_scsi(srb_t *sp) struct qla_hw_data *ha = vha->hw; /* Setup device pointers. */ - ret = 0; - qla25xx_set_que(sp, &rsp); req = vha->req; @@ -2088,7 +2075,6 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) struct qla_hw_data *ha = vha->hw; struct fc_bsg_job *bsg_job = sp->u.bsg_job; int loop_iterartion = 0; - int cont_iocb_prsnt = 0; int entry_count = 1; memset(ct_iocb, 0, sizeof(ms_iocb_entry_t)); @@ -2139,7 +2125,6 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) vha->hw->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; - cont_iocb_prsnt = 1; entry_count++; } @@ -2167,7 +2152,6 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) struct qla_hw_data *ha = vha->hw; struct fc_bsg_job *bsg_job = sp->u.bsg_job; int loop_iterartion = 0; - int cont_iocb_prsnt = 0; int entry_count = 1; ct_iocb->entry_type = CT_IOCB_TYPE; @@ -2214,7 +2198,6 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) ha->req_q_map[0]); cur_dsd = (uint32_t *) cont_pkt->dseg_0_address; avail_dsds = 5; - cont_iocb_prsnt = 1; entry_count++; } @@ -2237,7 +2220,7 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) int qla82xx_start_scsi(srb_t *sp) { - int ret, nseg; + int nseg; unsigned long flags; struct scsi_cmnd *cmd; uint32_t *clr_ptr; @@ -2257,7 +2240,6 @@ qla82xx_start_scsi(srb_t *sp) struct rsp_que *rsp = NULL; /* Setup device pointers. */ - ret = 0; reg = &ha->iobase->isp82; cmd = GET_CMD_SP(sp); req = vha->req; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index dcfa4655ce436..a526c389fa2fc 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -575,7 +575,7 @@ qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb) struct device_reg_2xxx __iomem *reg = &ha->iobase->isp; struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24; struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; - uint32_t rscn_entry, host_pid, tmp_pid; + uint32_t rscn_entry, host_pid; unsigned long flags; fc_port_t *fcport = NULL; @@ -998,7 +998,6 @@ skip_rio: list_for_each_entry(fcport, &vha->vp_fcports, list) { if (atomic_read(&fcport->state) != FCS_ONLINE) continue; - tmp_pid = fcport->d_id.b24; if (fcport->d_id.b24 == rscn_entry) { qla2x00_mark_device_lost(vha, fcport, 0, 0); break; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 02b1c1c5355b9..65c2dc1e929a9 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1865,7 +1865,6 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, uint32_t iop[2]; struct qla_hw_data *ha = vha->hw; struct req_que *req; - struct rsp_que *rsp; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1061, "Entered %s.\n", __func__); @@ -1874,7 +1873,6 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, req = ha->req_q_map[0]; else req = vha->req; - rsp = req->rsp; lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -2142,7 +2140,6 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, dma_addr_t lg_dma; struct qla_hw_data *ha = vha->hw; struct req_que *req; - struct rsp_que *rsp; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x106d, "Entered %s.\n", __func__); @@ -2159,7 +2156,6 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, req = ha->req_q_map[0]; else req = vha->req; - rsp = req->rsp; lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; lg->handle = MAKE_HANDLE(req->id, lg->handle); diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index cc94192511cf5..c5dd594f6c316 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -371,7 +371,6 @@ qla2x00_do_dpc_vp(scsi_qla_host_t *vha) void qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) { - int ret; struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *vp; unsigned long flags = 0; @@ -392,7 +391,7 @@ qla2x00_do_dpc_all_vps(scsi_qla_host_t *vha) atomic_inc(&vp->vref_count); spin_unlock_irqrestore(&ha->vport_slock, flags); - ret = qla2x00_do_dpc_vp(vp); + qla2x00_do_dpc_vp(vp); spin_lock_irqsave(&ha->vport_slock, flags); atomic_dec(&vp->vref_count); diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 878fd3d961f84..1843ba91e2c8e 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -1317,10 +1317,10 @@ int qlafx00_configure_devices(scsi_qla_host_t *vha) { int rval; - unsigned long flags, save_flags; + unsigned long flags; rval = QLA_SUCCESS; - save_flags = flags = vha->dpc_flags; + flags = vha->dpc_flags; ql_dbg(ql_dbg_disc, vha, 0x2090, "Configure devices -- dpc flags =0x%lx\n", flags); @@ -2279,7 +2279,6 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) struct sts_entry_fx00 *sts; __le16 comp_status; __le16 scsi_status; - uint16_t ox_id; __le16 lscsi_status; int32_t resid; uint32_t sense_len, par_sense_len, rsp_info_len, resid_len, @@ -2344,7 +2343,6 @@ qlafx00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) fcport = sp->fcport; - ox_id = 0; sense_len = par_sense_len = rsp_info_len = resid_len = fw_resid_len = 0; if (scsi_status & cpu_to_le16((uint16_t)SS_SENSE_LEN_VALID)) @@ -3071,7 +3069,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt, int qlafx00_start_scsi(srb_t *sp) { - int ret, nseg; + int nseg; unsigned long flags; uint32_t index; uint32_t handle; @@ -3088,8 +3086,6 @@ qlafx00_start_scsi(srb_t *sp) struct scsi_lun llun; /* Setup device pointers. */ - ret = 0; - rsp = ha->rsp_q_map[0]; req = vha->req; diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 47f8419adf418..5bc40d8dbb967 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1740,8 +1740,8 @@ qla82xx_pci_config(scsi_qla_host_t *vha) ret = pci_set_mwi(ha->pdev); ha->chip_revision = ha->pdev->revision; ql_dbg(ql_dbg_init, vha, 0x0043, - "Chip revision:%d.\n", - ha->chip_revision); + "Chip revision:%d; pci_set_mwi() returned %d.\n", + ha->chip_revision, ret); return 0; } @@ -2671,7 +2671,7 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr, { int ret; uint32_t liter; - uint32_t sec_mask, rest_addr; + uint32_t rest_addr; dma_addr_t optrom_dma; void *optrom = NULL; int page_mode = 0; @@ -2693,7 +2693,6 @@ qla82xx_write_flash_data(struct scsi_qla_host *vha, uint32_t *dwptr, } rest_addr = ha->fdt_block_size - 1; - sec_mask = ~rest_addr; ret = qla82xx_unprotect_flash(ha); if (ret) { @@ -2789,7 +2788,6 @@ qla82xx_start_iocbs(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; - struct device_reg_82xx __iomem *reg; uint32_t dbval; /* Adjust ring index. */ @@ -2800,7 +2798,6 @@ qla82xx_start_iocbs(scsi_qla_host_t *vha) } else req->ring_ptr++; - reg = &ha->iobase->isp82; dbval = 0x04 | (ha->portnum << 5); dbval = dbval | (req->id << 8) | (req->ring_index << 16); diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index e06c851147d0f..50e36f0348c1d 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -462,12 +462,11 @@ qla8044_flash_lock(scsi_qla_host_t *vha) static void qla8044_flash_unlock(scsi_qla_host_t *vha) { - int ret_val; struct qla_hw_data *ha = vha->hw; /* Reading FLASH_UNLOCK register unlocks the Flash */ qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, 0xFF); - ret_val = qla8044_rd_reg(ha, QLA8044_FLASH_UNLOCK); + qla8044_rd_reg(ha, QLA8044_FLASH_UNLOCK); } @@ -2992,7 +2991,7 @@ qla8044_minidump_process_rddfe(struct scsi_qla_host *vha, uint32_t addr1, addr2, value, data, temp, wrVal; uint8_t stride, stride2; uint16_t count; - uint32_t poll, mask, data_size, modify_mask; + uint32_t poll, mask, modify_mask; uint32_t wait_count = 0; uint32_t *data_ptr = *d_ptr; @@ -3009,7 +3008,6 @@ qla8044_minidump_process_rddfe(struct scsi_qla_host *vha, poll = rddfe->poll; mask = rddfe->mask; modify_mask = rddfe->modify_mask; - data_size = rddfe->data_size; addr2 = addr1 + stride; @@ -3091,7 +3089,7 @@ qla8044_minidump_process_rdmdio(struct scsi_qla_host *vha, uint8_t stride1, stride2; uint32_t addr3, addr4, addr5, addr6, addr7; uint16_t count, loop_cnt; - uint32_t poll, mask; + uint32_t mask; uint32_t *data_ptr = *d_ptr; struct qla8044_minidump_entry_rdmdio *rdmdio; @@ -3105,7 +3103,6 @@ qla8044_minidump_process_rdmdio(struct scsi_qla_host *vha, stride2 = rdmdio->stride_2; count = rdmdio->count; - poll = rdmdio->poll; mask = rdmdio->mask; value2 = rdmdio->value_2; @@ -3164,7 +3161,7 @@ error: static uint32_t qla8044_minidump_process_pollwr(struct scsi_qla_host *vha, struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr) { - uint32_t addr1, addr2, value1, value2, poll, mask, r_value; + uint32_t addr1, addr2, value1, value2, poll, r_value; uint32_t wait_count = 0; struct qla8044_minidump_entry_pollwr *pollwr_hdr; @@ -3175,7 +3172,6 @@ static uint32_t qla8044_minidump_process_pollwr(struct scsi_qla_host *vha, value2 = pollwr_hdr->value_2; poll = pollwr_hdr->poll; - mask = pollwr_hdr->mask; while (wait_count < poll) { qla8044_rd_reg_indirect(vha, addr1, &r_value); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index a28815b8276f0..5a5166bd42879 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2973,7 +2973,6 @@ qla2x00_shutdown(struct pci_dev *pdev) static void qla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha) { - struct Scsi_Host *scsi_host; scsi_qla_host_t *vha; unsigned long flags; @@ -2984,7 +2983,7 @@ qla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha) BUG_ON(base_vha->list.next == &ha->vp_list); /* This assumes first entry in ha->vp_list is always base vha */ vha = list_first_entry(&base_vha->list, scsi_qla_host_t, list); - scsi_host = scsi_host_get(vha->host); + scsi_host_get(vha->host); spin_unlock_irqrestore(&ha->vport_slock, flags); mutex_unlock(&ha->vport_lock); @@ -4793,7 +4792,6 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) static int qla2x00_do_dpc(void *data) { - int rval; scsi_qla_host_t *base_vha; struct qla_hw_data *ha; @@ -5025,7 +5023,7 @@ loop_resync_check: if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE, &base_vha->dpc_flags))) { - rval = qla2x00_loop_resync(base_vha); + qla2x00_loop_resync(base_vha); clear_bit(LOOP_RESYNC_ACTIVE, &base_vha->dpc_flags); diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index b749026aa5924..b635c05f829fc 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -2077,7 +2077,6 @@ static inline int qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) { uint32_t *cur_dsd; - int sgc; uint32_t transfer_length = 0; uint32_t data_bytes; uint32_t dif_bytes; @@ -2094,7 +2093,6 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) struct atio_from_isp *atio = &prm->cmd->atio; uint16_t t16; - sgc = 0; ha = vha->hw; pkt = (struct ctio_crc2_to_fw *)vha->req->ring_ptr; @@ -2563,7 +2561,7 @@ qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, /* Update protection tag */ if (cmd->prot_sg_cnt) { - uint32_t i, j = 0, k = 0, num_ent; + uint32_t i, k = 0, num_ent; struct scatterlist *sg, *sgl; @@ -2576,7 +2574,6 @@ qlt_handle_dif_error(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd, k += num_ent; continue; } - j = blocks_done - k - 1; k = blocks_done; break; } @@ -3063,7 +3060,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, { struct qla_hw_data *ha = vha->hw; struct se_cmd *se_cmd; - const struct target_core_fabric_ops *tfo; struct qla_tgt_cmd *cmd; if (handle & CTIO_INTERMEDIATE_HANDLE_MARK) { @@ -3081,7 +3077,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, uint32_t handle, return; se_cmd = &cmd->se_cmd; - tfo = se_cmd->se_tfo; cmd->cmd_sent_to_fw = 0; qlt_unmap_sg(vha, cmd); @@ -3179,13 +3174,9 @@ skip_term: if (cmd->state == QLA_TGT_STATE_PROCESSED) { ; } else if (cmd->state == QLA_TGT_STATE_NEED_DATA) { - int rx_status = 0; - cmd->state = QLA_TGT_STATE_DATA_IN; - if (unlikely(status != CTIO_SUCCESS)) - rx_status = -EIO; - else + if (status == CTIO_SUCCESS) cmd->write_data_transferred = 1; ha->tgt.tgt_ops->handle_data(cmd); @@ -3580,12 +3571,11 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb) struct qla_tgt *tgt; struct qla_tgt_sess *sess; uint32_t lun, unpacked_lun; - int lun_size, fn; + int fn; tgt = vha->vha_tgt.qla_tgt; lun = a->u.isp24.fcp_cmnd.lun; - lun_size = sizeof(a->u.isp24.fcp_cmnd.lun); fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; sess = ha->tgt.tgt_ops->find_sess_by_s_id(vha, a->u.isp24.fcp_hdr.s_id); @@ -5044,7 +5034,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, uint8_t *s_id = NULL; /* to hide compiler warnings */ int rc; uint32_t lun, unpacked_lun; - int lun_size, fn; + int fn; void *iocb; spin_lock_irqsave(&ha->hardware_lock, flags); @@ -5071,7 +5061,6 @@ static void qlt_tmr_work(struct qla_tgt *tgt, iocb = a; lun = a->u.isp24.fcp_cmnd.lun; - lun_size = sizeof(lun); fn = a->u.isp24.fcp_cmnd.task_mgmt_flags; unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 962cb89fe0ae9..7e876d1e2f78b 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -805,9 +805,8 @@ static void qla27xx_driver_info(struct qla27xx_fwdt_template *tmp) { uint8_t v[] = { 0, 0, 0, 0, 0, 0 }; - int rval = 0; - rval = sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", + sscanf(qla2x00_version_str, "%hhu.%hhu.%hhu.%hhu.%hhu.%hhu", v+0, v+1, v+2, v+3, v+4, v+5); tmp->driver_info[0] = v[3] << 24 | v[2] << 16 | v[1] << 8 | v[0]; -- GitLab From df3f4cd0defd5f832a806ca1f0dd6638a2df17a5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:23:46 -0700 Subject: [PATCH 5005/7006] qla2xxx: Replace two macros with an inline function Replace the QLA82XX_ADDR_IN_RANGE() and QLA8044_ADDR_IN_RANGE() macros with the inline function addr_in_range(). This avoids that the compiler reports the following warning when building with W=1: comparison of unsigned expression >= 0 is always true. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 21 +++++++++------------ drivers/scsi/qla2xxx/qla_nx2.c | 4 ++-- drivers/scsi/qla2xxx/qla_nx2.h | 6 ++++-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 5bc40d8dbb967..89804d20c9263 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -547,9 +547,6 @@ void qla82xx_idc_unlock(struct qla_hw_data *ha) qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK)); } -/* PCI Windowing for DDR regions. */ -#define QLA82XX_ADDR_IN_RANGE(addr, low, high) \ - (((addr) <= (high)) && ((addr) >= (low))) /* * check memory access boundary. * used by test agent. support ddr access only for now @@ -558,9 +555,9 @@ static unsigned long qla82xx_pci_mem_bound_check(struct qla_hw_data *ha, unsigned long long addr, int size) { - if (!QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, + if (!addr_in_range(addr, QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX) || - !QLA82XX_ADDR_IN_RANGE(addr + size - 1, QLA82XX_ADDR_DDR_NET, + !addr_in_range(addr + size - 1, QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX) || ((size != 1) && (size != 2) && (size != 4) && (size != 8))) return 0; @@ -577,7 +574,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) u32 win_read; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, + if (addr_in_range(addr, QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX)) { /* DDR network side */ window = MN_WIN(addr); @@ -592,7 +589,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) __func__, window, win_read); } addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET; - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, + } else if (addr_in_range(addr, QLA82XX_ADDR_OCM0, QLA82XX_ADDR_OCM0_MAX)) { unsigned int temp1; if ((addr & 0x00ff800) == 0xff800) { @@ -615,7 +612,7 @@ qla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr) } addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M; - } else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, + } else if (addr_in_range(addr, QLA82XX_ADDR_QDR_NET, QLA82XX_P3_ADDR_QDR_NET_MAX)) { /* QDR network side */ window = MS_WIN(addr); @@ -656,16 +653,16 @@ static int qla82xx_pci_is_same_window(struct qla_hw_data *ha, qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX; /* DDR network side */ - if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_DDR_NET, + if (addr_in_range(addr, QLA82XX_ADDR_DDR_NET, QLA82XX_ADDR_DDR_NET_MAX)) BUG(); - else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM0, + else if (addr_in_range(addr, QLA82XX_ADDR_OCM0, QLA82XX_ADDR_OCM0_MAX)) return 1; - else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_OCM1, + else if (addr_in_range(addr, QLA82XX_ADDR_OCM1, QLA82XX_ADDR_OCM1_MAX)) return 1; - else if (QLA82XX_ADDR_IN_RANGE(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) { + else if (addr_in_range(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) { /* QDR network side */ window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f; if (ha->qdr_sn_window == window) diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c index 50e36f0348c1d..007192d7bad85 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.c +++ b/drivers/scsi/qla2xxx/qla_nx2.c @@ -1129,9 +1129,9 @@ qla8044_ms_mem_write_128b(struct scsi_qla_host *vha, } for (i = 0; i < count; i++, addr += 16) { - if (!((QLA8044_ADDR_IN_RANGE(addr, QLA8044_ADDR_QDR_NET, + if (!((addr_in_range(addr, QLA8044_ADDR_QDR_NET, QLA8044_ADDR_QDR_NET_MAX)) || - (QLA8044_ADDR_IN_RANGE(addr, QLA8044_ADDR_DDR_NET, + (addr_in_range(addr, QLA8044_ADDR_DDR_NET, QLA8044_ADDR_DDR_NET_MAX)))) { ret_val = QLA_FUNCTION_FAILED; goto exit_ms_mem_write_unlock; diff --git a/drivers/scsi/qla2xxx/qla_nx2.h b/drivers/scsi/qla2xxx/qla_nx2.h index ada36057d7cde..02fe3c4cdf557 100644 --- a/drivers/scsi/qla2xxx/qla_nx2.h +++ b/drivers/scsi/qla2xxx/qla_nx2.h @@ -58,8 +58,10 @@ #define QLA8044_PCI_QDR_NET_MAX ((unsigned long)0x043fffff) /* PCI Windowing for DDR regions. */ -#define QLA8044_ADDR_IN_RANGE(addr, low, high) \ - (((addr) <= (high)) && ((addr) >= (low))) +static inline bool addr_in_range(u64 addr, u64 low, u64 high) +{ + return addr <= high && addr >= low; +} /* Indirectly Mapped Registers */ #define QLA8044_FLASH_SPI_STATUS 0x2808E010 -- GitLab From ad950360eebb5f5f7610b13cfd08c0185ca3f146 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:24:08 -0700 Subject: [PATCH 5006/7006] qla2xxx: Remove __constant_ prefix Whether htonl() or __constant_htonl() is used, if the argument is a constant the conversion happens at compile time. Hence leave out the __constant_ prefix for this and other endianness conversion functions. This improves source code readability. [jejb: checkpatch fixes] Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.c | 36 ++++---- drivers/scsi/qla2xxx/qla_gs.c | 52 +++++------ drivers/scsi/qla2xxx/qla_init.c | 143 ++++++++++++++---------------- drivers/scsi/qla2xxx/qla_iocb.c | 88 ++++++++---------- drivers/scsi/qla2xxx/qla_isr.c | 2 +- drivers/scsi/qla2xxx/qla_mbx.c | 25 +++--- drivers/scsi/qla2xxx/qla_mr.c | 2 +- drivers/scsi/qla2xxx/qla_nx.c | 6 +- drivers/scsi/qla2xxx/qla_sup.c | 14 +-- drivers/scsi/qla2xxx/qla_target.c | 116 ++++++++++++------------ 10 files changed, 231 insertions(+), 253 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 121ed5bdb4fa3..3a786e4739ad2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -486,7 +486,7 @@ qla25xx_copy_fce(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) return ptr; *last_chain = &fcec->type; - fcec->type = __constant_htonl(DUMP_CHAIN_FCE); + fcec->type = htonl(DUMP_CHAIN_FCE); fcec->chain_size = htonl(sizeof(struct qla2xxx_fce_chain) + fce_calc_size(ha->fce_bufs)); fcec->size = htonl(fce_calc_size(ha->fce_bufs)); @@ -527,7 +527,7 @@ qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr, /* aqp = ha->atio_q_map[que]; */ q = ptr; *last_chain = &q->type; - q->type = __constant_htonl(DUMP_CHAIN_QUEUE); + q->type = htonl(DUMP_CHAIN_QUEUE); q->chain_size = htonl( sizeof(struct qla2xxx_mqueue_chain) + sizeof(struct qla2xxx_mqueue_header) + @@ -536,7 +536,7 @@ qla2xxx_copy_atioqueues(struct qla_hw_data *ha, void *ptr, /* Add header. */ qh = ptr; - qh->queue = __constant_htonl(TYPE_ATIO_QUEUE); + qh->queue = htonl(TYPE_ATIO_QUEUE); qh->number = htonl(que); qh->size = htonl(aqp->length * sizeof(request_t)); ptr += sizeof(struct qla2xxx_mqueue_header); @@ -571,7 +571,7 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) /* Add chain. */ q = ptr; *last_chain = &q->type; - q->type = __constant_htonl(DUMP_CHAIN_QUEUE); + q->type = htonl(DUMP_CHAIN_QUEUE); q->chain_size = htonl( sizeof(struct qla2xxx_mqueue_chain) + sizeof(struct qla2xxx_mqueue_header) + @@ -580,7 +580,7 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) /* Add header. */ qh = ptr; - qh->queue = __constant_htonl(TYPE_REQUEST_QUEUE); + qh->queue = htonl(TYPE_REQUEST_QUEUE); qh->number = htonl(que); qh->size = htonl(req->length * sizeof(request_t)); ptr += sizeof(struct qla2xxx_mqueue_header); @@ -599,7 +599,7 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) /* Add chain. */ q = ptr; *last_chain = &q->type; - q->type = __constant_htonl(DUMP_CHAIN_QUEUE); + q->type = htonl(DUMP_CHAIN_QUEUE); q->chain_size = htonl( sizeof(struct qla2xxx_mqueue_chain) + sizeof(struct qla2xxx_mqueue_header) + @@ -608,7 +608,7 @@ qla25xx_copy_mqueues(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) /* Add header. */ qh = ptr; - qh->queue = __constant_htonl(TYPE_RESPONSE_QUEUE); + qh->queue = htonl(TYPE_RESPONSE_QUEUE); qh->number = htonl(que); qh->size = htonl(rsp->length * sizeof(response_t)); ptr += sizeof(struct qla2xxx_mqueue_header); @@ -634,8 +634,8 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) mq = ptr; *last_chain = &mq->type; - mq->type = __constant_htonl(DUMP_CHAIN_MQ); - mq->chain_size = __constant_htonl(sizeof(struct qla2xxx_mq_chain)); + mq->type = htonl(DUMP_CHAIN_MQ); + mq->chain_size = htonl(sizeof(struct qla2xxx_mq_chain)); que_cnt = ha->max_req_queues > ha->max_rsp_queues ? ha->max_req_queues : ha->max_rsp_queues; @@ -1271,8 +1271,8 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) nxt_chain = (void *)ha->fw_dump + ha->chain_offset; nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); + ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); + *last_chain |= htonl(DUMP_CHAIN_LAST); } /* Adjust valid length. */ @@ -1323,7 +1323,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) } fw = &ha->fw_dump->isp.isp25; qla2xxx_prep_dump(ha, ha->fw_dump); - ha->fw_dump->version = __constant_htonl(2); + ha->fw_dump->version = htonl(2); fw->host_status = htonl(RD_REG_DWORD(®->host_status)); @@ -1587,8 +1587,8 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); + ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); + *last_chain |= htonl(DUMP_CHAIN_LAST); } /* Adjust valid length. */ @@ -1905,8 +1905,8 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); + ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); + *last_chain |= htonl(DUMP_CHAIN_LAST); } /* Adjust valid length. */ @@ -2408,8 +2408,8 @@ copy_queue: nxt_chain = qla25xx_copy_mqueues(ha, nxt_chain, &last_chain); nxt_chain = qla2xxx_copy_atioqueues(ha, nxt_chain, &last_chain); if (last_chain) { - ha->fw_dump->version |= __constant_htonl(DUMP_CHAIN_VARIANT); - *last_chain |= __constant_htonl(DUMP_CHAIN_LAST); + ha->fw_dump->version |= htonl(DUMP_CHAIN_VARIANT); + *last_chain |= htonl(DUMP_CHAIN_LAST); } /* Adjust valid length. */ diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index dccc4dcc39c88..94e8a8592f690 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -35,10 +35,10 @@ qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size) ms_pkt->entry_type = MS_IOCB_TYPE; ms_pkt->entry_count = 1; SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); - ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); + ms_pkt->control_flags = cpu_to_le16(CF_READ | CF_HEAD_TAG); ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); + ms_pkt->cmd_dsd_count = cpu_to_le16(1); + ms_pkt->total_dsd_count = cpu_to_le16(2); ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); ms_pkt->req_bytecount = cpu_to_le32(req_size); @@ -74,10 +74,10 @@ qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size) ct_pkt->entry_type = CT_IOCB_TYPE; ct_pkt->entry_count = 1; - ct_pkt->nport_handle = __constant_cpu_to_le16(NPH_SNS); + ct_pkt->nport_handle = cpu_to_le16(NPH_SNS); ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->cmd_dsd_count = cpu_to_le16(1); + ct_pkt->rsp_dsd_count = cpu_to_le16(1); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); ct_pkt->cmd_byte_count = cpu_to_le32(req_size); @@ -142,7 +142,7 @@ qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, case CS_DATA_UNDERRUN: case CS_DATA_OVERRUN: /* Overrun? */ if (ct_rsp->header.response != - __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) { + cpu_to_be16(CT_ACCEPT_RESPONSE)) { ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077, "%s failed rejected request on port_id: %02x%02x%02x Compeltion status 0x%x, response 0x%x\n", routine, vha->d_id.b.domain, @@ -1153,10 +1153,10 @@ qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, ms_pkt->entry_type = MS_IOCB_TYPE; ms_pkt->entry_count = 1; SET_TARGET_ID(ha, ms_pkt->loop_id, vha->mgmt_svr_loop_id); - ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); + ms_pkt->control_flags = cpu_to_le16(CF_READ | CF_HEAD_TAG); ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); + ms_pkt->cmd_dsd_count = cpu_to_le16(1); + ms_pkt->total_dsd_count = cpu_to_le16(2); ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); ms_pkt->req_bytecount = cpu_to_le32(req_size); @@ -1193,8 +1193,8 @@ qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, ct_pkt->entry_count = 1; ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id); ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->cmd_dsd_count = cpu_to_le16(1); + ct_pkt->rsp_dsd_count = cpu_to_le16(1); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); ct_pkt->cmd_byte_count = cpu_to_le32(req_size); @@ -1281,19 +1281,19 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Prepare FDMI command arguments -- attribute block, attributes. */ memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, WWN_SIZE); - ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1); + ct_req->req.rhba.entry_count = cpu_to_be32(1); memcpy(ct_req->req.rhba.port_name, vha->port_name, WWN_SIZE); size = 2 * WWN_SIZE + 4 + 4; /* Attributes */ ct_req->req.rhba.attrs.count = - __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT); + cpu_to_be32(FDMI_HBA_ATTR_COUNT); entries = ct_req->req.rhba.hba_identifier; /* Nodename. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME); - eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE); + eiter->type = cpu_to_be16(FDMI_HBA_NODE_NAME); + eiter->len = cpu_to_be16(4 + WWN_SIZE); memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE); size += 4 + WWN_SIZE; @@ -1302,7 +1302,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Manufacturer. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER); + eiter->type = cpu_to_be16(FDMI_HBA_MANUFACTURER); alen = strlen(QLA2XXX_MANUFACTURER); snprintf(eiter->a.manufacturer, sizeof(eiter->a.manufacturer), "%s", "QLogic Corporation"); @@ -1315,7 +1315,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Serial number. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); + eiter->type = cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); if (IS_FWI2_CAPABLE(ha)) qla2xxx_get_vpd_field(vha, "SN", eiter->a.serial_num, sizeof(eiter->a.serial_num)); @@ -1335,7 +1335,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Model name. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL); + eiter->type = cpu_to_be16(FDMI_HBA_MODEL); snprintf(eiter->a.model, sizeof(eiter->a.model), "%s", ha->model_number); alen = strlen(eiter->a.model); @@ -1348,7 +1348,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Model description. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); + eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); snprintf(eiter->a.model_desc, sizeof(eiter->a.model_desc), "%s", ha->model_desc); alen = strlen(eiter->a.model_desc); @@ -1361,7 +1361,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Hardware version. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); + eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); if (!IS_FWI2_CAPABLE(ha)) { snprintf(eiter->a.hw_version, sizeof(eiter->a.hw_version), "HW:%s", ha->adapter_id); @@ -1385,7 +1385,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Driver version. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION); + eiter->type = cpu_to_be16(FDMI_HBA_DRIVER_VERSION); snprintf(eiter->a.driver_version, sizeof(eiter->a.driver_version), "%s", qla2x00_version_str); alen = strlen(eiter->a.driver_version); @@ -1398,7 +1398,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Option ROM version. */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); + eiter->type = cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); snprintf(eiter->a.orom_version, sizeof(eiter->a.orom_version), "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); alen = strlen(eiter->a.orom_version); @@ -1411,7 +1411,7 @@ qla2x00_fdmi_rhba(scsi_qla_host_t *vha) /* Firmware version */ eiter = entries + size; - eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); + eiter->type = cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); ha->isp_ops->fw_version_str(vha, eiter->a.fw_version, sizeof(eiter->a.fw_version)); alen = strlen(eiter->a.fw_version); @@ -2484,8 +2484,8 @@ qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *vha, uint32_t req_size, ct_pkt->entry_count = 1; ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id); ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); - ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); - ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->cmd_dsd_count = cpu_to_le16(1); + ct_pkt->rsp_dsd_count = cpu_to_le16(1); ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); ct_pkt->cmd_byte_count = cpu_to_le32(req_size); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f4a64a4fc40a4..ceced7ff8083a 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1685,7 +1685,7 @@ allocate: ha->fw_dump->signature[1] = 'L'; ha->fw_dump->signature[2] = 'G'; ha->fw_dump->signature[3] = 'C'; - ha->fw_dump->version = __constant_htonl(1); + ha->fw_dump->version = htonl(1); ha->fw_dump->fixed_size = htonl(fixed_size); ha->fw_dump->mem_size = htonl(mem_size); @@ -2065,8 +2065,8 @@ qla2x00_config_rings(struct scsi_qla_host *vha) struct rsp_que *rsp = ha->rsp_q_map[0]; /* Setup ring parameters in initialization control block. */ - ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0); - ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0); + ha->init_cb->request_q_outpointer = cpu_to_le16(0); + ha->init_cb->response_q_inpointer = cpu_to_le16(0); ha->init_cb->request_q_length = cpu_to_le16(req->length); ha->init_cb->response_q_length = cpu_to_le16(rsp->length); ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); @@ -2095,8 +2095,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha) /* Setup ring parameters in initialization control block. */ icb = (struct init_cb_24xx *)ha->init_cb; - icb->request_q_outpointer = __constant_cpu_to_le16(0); - icb->response_q_inpointer = __constant_cpu_to_le16(0); + icb->request_q_outpointer = cpu_to_le16(0); + icb->response_q_inpointer = cpu_to_le16(0); icb->request_q_length = cpu_to_le16(req->length); icb->response_q_length = cpu_to_le16(rsp->length); icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); @@ -2105,18 +2105,17 @@ qla24xx_config_rings(struct scsi_qla_host *vha) icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); /* Setup ATIO queue dma pointers for target mode */ - icb->atio_q_inpointer = __constant_cpu_to_le16(0); + icb->atio_q_inpointer = cpu_to_le16(0); icb->atio_q_length = cpu_to_le16(ha->tgt.atio_q_length); icb->atio_q_address[0] = cpu_to_le32(LSD(ha->tgt.atio_dma)); icb->atio_q_address[1] = cpu_to_le32(MSD(ha->tgt.atio_dma)); if (IS_SHADOW_REG_CAPABLE(ha)) - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_30|BIT_29); + icb->firmware_options_2 |= cpu_to_le32(BIT_30|BIT_29); if (ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) { - icb->qos = __constant_cpu_to_le16(QLA_DEFAULT_QUE_QOS); - icb->rid = __constant_cpu_to_le16(rid); + icb->qos = cpu_to_le16(QLA_DEFAULT_QUE_QOS); + icb->rid = cpu_to_le16(rid); if (ha->flags.msix_enabled) { msix = &ha->msix_entries[1]; ql_dbg(ql_dbg_init, vha, 0x00fd, @@ -2126,26 +2125,22 @@ qla24xx_config_rings(struct scsi_qla_host *vha) } /* Use alternate PCI bus number */ if (MSB(rid)) - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_19); + icb->firmware_options_2 |= cpu_to_le32(BIT_19); /* Use alternate PCI devfn */ if (LSB(rid)) - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_18); + icb->firmware_options_2 |= cpu_to_le32(BIT_18); /* Use Disable MSIX Handshake mode for capable adapters */ if ((ha->fw_attributes & BIT_6) && (IS_MSIX_NACK_CAPABLE(ha)) && (ha->flags.msix_enabled)) { - icb->firmware_options_2 &= - __constant_cpu_to_le32(~BIT_22); + icb->firmware_options_2 &= cpu_to_le32(~BIT_22); ha->flags.disable_msix_handshake = 1; ql_dbg(ql_dbg_init, vha, 0x00fe, "MSIX Handshake Disable Mode turned on.\n"); } else { - icb->firmware_options_2 |= - __constant_cpu_to_le32(BIT_22); + icb->firmware_options_2 |= cpu_to_le32(BIT_22); } - icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23); + icb->firmware_options_2 |= cpu_to_le32(BIT_23); WRT_REG_DWORD(®->isp25mq.req_q_in, 0); WRT_REG_DWORD(®->isp25mq.req_q_out, 0); @@ -2243,7 +2238,7 @@ qla2x00_init_rings(scsi_qla_host_t *vha) } if (IS_FWI2_CAPABLE(ha)) { - mid_init_cb->options = __constant_cpu_to_le16(BIT_1); + mid_init_cb->options = cpu_to_le16(BIT_1); mid_init_cb->init_cb.execution_throttle = cpu_to_le16(ha->fw_xcb_count); /* D-Port Status */ @@ -2672,8 +2667,8 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) nv->frame_payload_size = 1024; } - nv->max_iocb_allocation = __constant_cpu_to_le16(256); - nv->execution_throttle = __constant_cpu_to_le16(16); + nv->max_iocb_allocation = cpu_to_le16(256); + nv->execution_throttle = cpu_to_le16(16); nv->retry_count = 8; nv->retry_delay = 1; @@ -2691,7 +2686,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) nv->host_p[1] = BIT_2; nv->reset_delay = 5; nv->port_down_retry_count = 8; - nv->max_luns_per_target = __constant_cpu_to_le16(8); + nv->max_luns_per_target = cpu_to_le16(8); nv->link_down_timeout = 60; rval = 1; @@ -2819,7 +2814,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) memcpy(vha->node_name, icb->node_name, WWN_SIZE); memcpy(vha->port_name, icb->port_name, WWN_SIZE); - icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); + icb->execution_throttle = cpu_to_le16(0xFFFF); ha->retry_count = nv->retry_count; @@ -2871,10 +2866,10 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) if (ql2xloginretrycount) ha->login_retry_count = ql2xloginretrycount; - icb->lun_enables = __constant_cpu_to_le16(0); + icb->lun_enables = cpu_to_le16(0); icb->command_resource_count = 0; icb->immediate_notify_resource_count = 0; - icb->timeout = __constant_cpu_to_le16(0); + icb->timeout = cpu_to_le16(0); if (IS_QLA2100(ha) || IS_QLA2200(ha)) { /* Enable RIO */ @@ -5005,7 +5000,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) /* Bad NVRAM data, set defaults parameters. */ if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' || nv->id[3] != ' ' || - nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { + nv->nvram_version < cpu_to_le16(ICB_VERSION)) { /* Reset NVRAM data. */ ql_log(ql_log_warn, vha, 0x006b, "Inconsistent NVRAM detected: checksum=0x%x id=%c " @@ -5018,12 +5013,12 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) * Set default initialization control block. */ memset(nv, 0, ha->nvram_size); - nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); - nv->version = __constant_cpu_to_le16(ICB_VERSION); + nv->nvram_version = cpu_to_le16(ICB_VERSION); + nv->version = cpu_to_le16(ICB_VERSION); nv->frame_payload_size = 2048; - nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); - nv->exchange_count = __constant_cpu_to_le16(0); - nv->hard_address = __constant_cpu_to_le16(124); + nv->execution_throttle = cpu_to_le16(0xFFFF); + nv->exchange_count = cpu_to_le16(0); + nv->hard_address = cpu_to_le16(124); nv->port_name[0] = 0x21; nv->port_name[1] = 0x00 + ha->port_no + 1; nv->port_name[2] = 0x00; @@ -5041,29 +5036,29 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) nv->node_name[6] = 0x55; nv->node_name[7] = 0x86; qla24xx_nvram_wwn_from_ofw(vha, nv); - nv->login_retry_count = __constant_cpu_to_le16(8); - nv->interrupt_delay_timer = __constant_cpu_to_le16(0); - nv->login_timeout = __constant_cpu_to_le16(0); + nv->login_retry_count = cpu_to_le16(8); + nv->interrupt_delay_timer = cpu_to_le16(0); + nv->login_timeout = cpu_to_le16(0); nv->firmware_options_1 = - __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); - nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); - nv->efi_parameters = __constant_cpu_to_le32(0); + cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); + nv->firmware_options_2 = cpu_to_le32(2 << 4); + nv->firmware_options_2 |= cpu_to_le32(BIT_12); + nv->firmware_options_3 = cpu_to_le32(2 << 13); + nv->host_p = cpu_to_le32(BIT_11|BIT_10); + nv->efi_parameters = cpu_to_le32(0); nv->reset_delay = 5; - nv->max_luns_per_target = __constant_cpu_to_le16(128); - nv->port_down_retry_count = __constant_cpu_to_le16(30); - nv->link_down_timeout = __constant_cpu_to_le16(30); + nv->max_luns_per_target = cpu_to_le16(128); + nv->port_down_retry_count = cpu_to_le16(30); + nv->link_down_timeout = cpu_to_le16(30); rval = 1; } if (!qla_ini_mode_enabled(vha)) { /* Don't enable full login after initial LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13); + nv->firmware_options_1 &= cpu_to_le32(~BIT_13); /* Don't enable LIP full login for initiator */ - nv->host_p &= __constant_cpu_to_le32(~BIT_10); + nv->host_p &= cpu_to_le32(~BIT_10); } qlt_24xx_config_nvram_stage1(vha, nv); @@ -5097,14 +5092,14 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) qlt_24xx_config_nvram_stage2(vha, icb); - if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { + if (nv->host_p & cpu_to_le32(BIT_15)) { /* Use alternate WWN? */ memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); } /* Prepare nodename */ - if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) { + if ((icb->firmware_options_1 & cpu_to_le32(BIT_14)) == 0) { /* * Firmware will apply the following mask if the nodename was * not provided. @@ -5136,7 +5131,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) memcpy(vha->node_name, icb->node_name, WWN_SIZE); memcpy(vha->port_name, icb->port_name, WWN_SIZE); - icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); + icb->execution_throttle = cpu_to_le16(0xFFFF); ha->retry_count = le16_to_cpu(nv->login_retry_count); @@ -5144,7 +5139,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) nv->login_timeout = cpu_to_le16(ql2xlogintimeout); if (le16_to_cpu(nv->login_timeout) < 4) - nv->login_timeout = __constant_cpu_to_le16(4); + nv->login_timeout = cpu_to_le16(4); ha->login_timeout = le16_to_cpu(nv->login_timeout); icb->login_timeout = nv->login_timeout; @@ -5195,7 +5190,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? le16_to_cpu(icb->interrupt_delay_timer): 2; } - icb->firmware_options_2 &= __constant_cpu_to_le32( + icb->firmware_options_2 &= cpu_to_le32( ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); vha->flags.process_response_queue = 0; if (ha->zio_mode != QLA_ZIO_DISABLED) { @@ -5951,7 +5946,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* Bad NVRAM data, set defaults parameters. */ if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || nv->id[2] != 'P' || nv->id[3] != ' ' || - nv->nvram_version < __constant_cpu_to_le16(ICB_VERSION)) { + nv->nvram_version < cpu_to_le16(ICB_VERSION)) { /* Reset NVRAM data. */ ql_log(ql_log_info, vha, 0x0073, "Inconsistent NVRAM detected: checksum=0x%x id=%c " @@ -5965,11 +5960,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) * Set default initialization control block. */ memset(nv, 0, ha->nvram_size); - nv->nvram_version = __constant_cpu_to_le16(ICB_VERSION); - nv->version = __constant_cpu_to_le16(ICB_VERSION); + nv->nvram_version = cpu_to_le16(ICB_VERSION); + nv->version = cpu_to_le16(ICB_VERSION); nv->frame_payload_size = 2048; - nv->execution_throttle = __constant_cpu_to_le16(0xFFFF); - nv->exchange_count = __constant_cpu_to_le16(0); + nv->execution_throttle = cpu_to_le16(0xFFFF); + nv->exchange_count = cpu_to_le16(0); nv->port_name[0] = 0x21; nv->port_name[1] = 0x00 + ha->port_no + 1; nv->port_name[2] = 0x00; @@ -5986,20 +5981,20 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) nv->node_name[5] = 0x1c; nv->node_name[6] = 0x55; nv->node_name[7] = 0x86; - nv->login_retry_count = __constant_cpu_to_le16(8); - nv->interrupt_delay_timer = __constant_cpu_to_le16(0); - nv->login_timeout = __constant_cpu_to_le16(0); + nv->login_retry_count = cpu_to_le16(8); + nv->interrupt_delay_timer = cpu_to_le16(0); + nv->login_timeout = cpu_to_le16(0); nv->firmware_options_1 = - __constant_cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); - nv->firmware_options_2 = __constant_cpu_to_le32(2 << 4); - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_12); - nv->firmware_options_3 = __constant_cpu_to_le32(2 << 13); - nv->host_p = __constant_cpu_to_le32(BIT_11|BIT_10); - nv->efi_parameters = __constant_cpu_to_le32(0); + cpu_to_le32(BIT_14|BIT_13|BIT_2|BIT_1); + nv->firmware_options_2 = cpu_to_le32(2 << 4); + nv->firmware_options_2 |= cpu_to_le32(BIT_12); + nv->firmware_options_3 = cpu_to_le32(2 << 13); + nv->host_p = cpu_to_le32(BIT_11|BIT_10); + nv->efi_parameters = cpu_to_le32(0); nv->reset_delay = 5; - nv->max_luns_per_target = __constant_cpu_to_le16(128); - nv->port_down_retry_count = __constant_cpu_to_le16(30); - nv->link_down_timeout = __constant_cpu_to_le16(180); + nv->max_luns_per_target = cpu_to_le16(128); + nv->port_down_retry_count = cpu_to_le16(30); + nv->link_down_timeout = cpu_to_le16(180); nv->enode_mac[0] = 0x00; nv->enode_mac[1] = 0xC0; nv->enode_mac[2] = 0xDD; @@ -6058,13 +6053,13 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) qlt_81xx_config_nvram_stage2(vha, icb); /* Use alternate WWN? */ - if (nv->host_p & __constant_cpu_to_le32(BIT_15)) { + if (nv->host_p & cpu_to_le32(BIT_15)) { memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); memcpy(icb->port_name, nv->alternate_port_name, WWN_SIZE); } /* Prepare nodename */ - if ((icb->firmware_options_1 & __constant_cpu_to_le32(BIT_14)) == 0) { + if ((icb->firmware_options_1 & cpu_to_le32(BIT_14)) == 0) { /* * Firmware will apply the following mask if the nodename was * not provided. @@ -6093,7 +6088,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) memcpy(vha->node_name, icb->node_name, WWN_SIZE); memcpy(vha->port_name, icb->port_name, WWN_SIZE); - icb->execution_throttle = __constant_cpu_to_le16(0xFFFF); + icb->execution_throttle = cpu_to_le16(0xFFFF); ha->retry_count = le16_to_cpu(nv->login_retry_count); @@ -6101,7 +6096,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) if (le16_to_cpu(nv->login_timeout) < ql2xlogintimeout) nv->login_timeout = cpu_to_le16(ql2xlogintimeout); if (le16_to_cpu(nv->login_timeout) < 4) - nv->login_timeout = __constant_cpu_to_le16(4); + nv->login_timeout = cpu_to_le16(4); ha->login_timeout = le16_to_cpu(nv->login_timeout); icb->login_timeout = nv->login_timeout; @@ -6147,7 +6142,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* if not running MSI-X we need handshaking on interrupts */ if (!vha->hw->flags.msix_enabled && (IS_QLA83XX(ha) || IS_QLA27XX(ha))) - icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22); + icb->firmware_options_2 |= cpu_to_le32(BIT_22); /* Enable ZIO. */ if (!vha->flags.init_done) { @@ -6156,7 +6151,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) ha->zio_timer = le16_to_cpu(icb->interrupt_delay_timer) ? le16_to_cpu(icb->interrupt_delay_timer): 2; } - icb->firmware_options_2 &= __constant_cpu_to_le32( + icb->firmware_options_2 &= cpu_to_le32( ~(BIT_3 | BIT_2 | BIT_1 | BIT_0)); vha->flags.process_response_queue = 0; if (ha->zio_mode != QLA_ZIO_DISABLED) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index e95162e1fcb75..fbb1fe9fd3577 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -108,8 +108,7 @@ qla2x00_prep_cont_type0_iocb(struct scsi_qla_host *vha) cont_pkt = (cont_entry_t *)req->ring_ptr; /* Load packet defaults. */ - *((uint32_t *)(&cont_pkt->entry_type)) = - __constant_cpu_to_le32(CONTINUE_TYPE); + *((uint32_t *)(&cont_pkt->entry_type)) = cpu_to_le32(CONTINUE_TYPE); return (cont_pkt); } @@ -138,8 +137,8 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) /* Load packet defaults. */ *((uint32_t *)(&cont_pkt->entry_type)) = IS_QLAFX00(vha->hw) ? - __constant_cpu_to_le32(CONTINUE_A64_TYPE_FX00) : - __constant_cpu_to_le32(CONTINUE_A64_TYPE); + cpu_to_le32(CONTINUE_A64_TYPE_FX00) : + cpu_to_le32(CONTINUE_A64_TYPE); return (cont_pkt); } @@ -204,11 +203,11 @@ void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt, /* Update entry type to indicate Command Type 2 IOCB */ *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE); + cpu_to_le32(COMMAND_TYPE); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); + cmd_pkt->byte_count = cpu_to_le32(0); return; } @@ -261,12 +260,11 @@ void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_A64_TYPE); + *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_A64_TYPE); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); + cmd_pkt->byte_count = cpu_to_le32(0); return; } @@ -402,7 +400,7 @@ qla2x00_start_scsi(srb_t *sp) /* Set target ID and LUN number*/ SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id); cmd_pkt->lun = cpu_to_le16(cmd->device->lun); - cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG); + cmd_pkt->control_flags = cpu_to_le16(CF_SIMPLE_TAG); /* Load SCSI command packet. */ memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len); @@ -596,12 +594,11 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_6); + *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_6); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); + cmd_pkt->byte_count = cpu_to_le32(0); return 0; } @@ -610,13 +607,11 @@ qla24xx_build_scsi_type_6_iocbs(srb_t *sp, struct cmd_type_6 *cmd_pkt, /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_WRITE_DATA); + cmd_pkt->control_flags = cpu_to_le16(CF_WRITE_DATA); vha->qla_stats.output_bytes += scsi_bufflen(cmd); vha->qla_stats.output_requests++; } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_READ_DATA); + cmd_pkt->control_flags = cpu_to_le16(CF_READ_DATA); vha->qla_stats.input_bytes += scsi_bufflen(cmd); vha->qla_stats.input_requests++; } @@ -713,12 +708,11 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type 3 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_7); + *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_7); /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); + cmd_pkt->byte_count = cpu_to_le32(0); return; } @@ -726,13 +720,11 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { - cmd_pkt->task_mgmt_flags = - __constant_cpu_to_le16(TMF_WRITE_DATA); + cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_WRITE_DATA); vha->qla_stats.output_bytes += scsi_bufflen(cmd); vha->qla_stats.output_requests++; } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { - cmd_pkt->task_mgmt_flags = - __constant_cpu_to_le16(TMF_READ_DATA); + cmd_pkt->task_mgmt_flags = cpu_to_le16(TMF_READ_DATA); vha->qla_stats.input_bytes += scsi_bufflen(cmd); vha->qla_stats.input_requests++; } @@ -806,7 +798,7 @@ qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, * match LBA in CDB + N */ case SCSI_PROT_DIF_TYPE2: - pkt->app_tag = __constant_cpu_to_le16(0); + pkt->app_tag = cpu_to_le16(0); pkt->app_tag_mask[0] = 0x0; pkt->app_tag_mask[1] = 0x0; @@ -837,7 +829,7 @@ qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, case SCSI_PROT_DIF_TYPE1: pkt->ref_tag = cpu_to_le32((uint32_t) (0xffffffff & scsi_get_lba(cmd))); - pkt->app_tag = __constant_cpu_to_le16(0); + pkt->app_tag = cpu_to_le16(0); pkt->app_tag_mask[0] = 0x0; pkt->app_tag_mask[1] = 0x0; @@ -1238,8 +1230,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, cmd = GET_CMD_SP(sp); /* Update entry type to indicate Command Type CRC_2 IOCB */ - *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_TYPE_CRC_2); + *((uint32_t *)(&cmd_pkt->entry_type)) = cpu_to_le32(COMMAND_TYPE_CRC_2); vha = sp->fcport->vha; ha = vha->hw; @@ -1247,7 +1238,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, /* No data transfer */ data_bytes = scsi_bufflen(cmd); if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); + cmd_pkt->byte_count = cpu_to_le32(0); return QLA_SUCCESS; } @@ -1256,10 +1247,10 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, /* Set transfer direction */ if (cmd->sc_data_direction == DMA_TO_DEVICE) { cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_WRITE_DATA); + cpu_to_le16(CF_WRITE_DATA); } else if (cmd->sc_data_direction == DMA_FROM_DEVICE) { cmd_pkt->control_flags = - __constant_cpu_to_le16(CF_READ_DATA); + cpu_to_le16(CF_READ_DATA); } if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || @@ -1381,7 +1372,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, crc_ctx_pkt->blk_size = cpu_to_le16(blk_size); crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); - crc_ctx_pkt->guard_seed = __constant_cpu_to_le16(0); + crc_ctx_pkt->guard_seed = cpu_to_le16(0); /* Fibre channel byte count */ cmd_pkt->byte_count = cpu_to_le32(total_bytes); fcp_dl = (uint32_t *)(crc_ctx_pkt->fcp_cmnd.cdb + 16 + @@ -1389,13 +1380,12 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, *fcp_dl = htonl(total_bytes); if (!data_bytes || cmd->sc_data_direction == DMA_NONE) { - cmd_pkt->byte_count = __constant_cpu_to_le32(0); + cmd_pkt->byte_count = cpu_to_le32(0); return QLA_SUCCESS; } /* Walks data segments */ - cmd_pkt->control_flags |= - __constant_cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); + cmd_pkt->control_flags |= cpu_to_le16(CF_DATA_SEG_DESCR_ENABLE); if (!bundling && tot_prot_dsds) { if (qla24xx_walk_and_build_sglist_no_difb(ha, sp, @@ -1407,8 +1397,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, if (bundling && tot_prot_dsds) { /* Walks dif segments */ - cmd_pkt->control_flags |= - __constant_cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); + cmd_pkt->control_flags |= cpu_to_le16(CF_DIF_SEG_DESCR_ENABLE); cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; if (qla24xx_walk_and_build_prot_sglist(ha, sp, cur_dsd, tot_prot_dsds, NULL)) @@ -1740,7 +1729,7 @@ qla24xx_dif_start_scsi(srb_t *sp) cmd_pkt->entry_count = (uint8_t)req_cnt; /* Specify response queue number where completion should happen */ cmd_pkt->entry_status = (uint8_t) rsp->id; - cmd_pkt->timeout = __constant_cpu_to_le16(0); + cmd_pkt->timeout = cpu_to_le16(0); wmb(); /* Adjust ring index. */ @@ -2028,10 +2017,10 @@ qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->entry_status = 0; els_iocb->handle = sp->handle; els_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); - els_iocb->tx_dsd_count = __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + els_iocb->tx_dsd_count = cpu_to_le16(bsg_job->request_payload.sg_cnt); els_iocb->vp_index = sp->fcport->vha->vp_idx; els_iocb->sof_type = EST_SOFI3; - els_iocb->rx_dsd_count = __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); + els_iocb->rx_dsd_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt); els_iocb->opcode = sp->type == SRB_ELS_CMD_RPT ? @@ -2082,13 +2071,13 @@ qla2x00_ct_iocb(srb_t *sp, ms_iocb_entry_t *ct_iocb) ct_iocb->entry_status = 0; ct_iocb->handle1 = sp->handle; SET_TARGET_ID(ha, ct_iocb->loop_id, sp->fcport->loop_id); - ct_iocb->status = __constant_cpu_to_le16(0); - ct_iocb->control_flags = __constant_cpu_to_le16(0); + ct_iocb->status = cpu_to_le16(0); + ct_iocb->control_flags = cpu_to_le16(0); ct_iocb->timeout = 0; ct_iocb->cmd_dsd_count = - __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + cpu_to_le16(bsg_job->request_payload.sg_cnt); ct_iocb->total_dsd_count = - __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt + 1); + cpu_to_le16(bsg_job->request_payload.sg_cnt + 1); ct_iocb->req_bytecount = cpu_to_le32(bsg_job->request_payload.payload_len); ct_iocb->rsp_bytecount = @@ -2161,13 +2150,13 @@ qla24xx_ct_iocb(srb_t *sp, struct ct_entry_24xx *ct_iocb) ct_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); ct_iocb->vp_index = sp->fcport->vha->vp_idx; - ct_iocb->comp_status = __constant_cpu_to_le16(0); + ct_iocb->comp_status = cpu_to_le16(0); ct_iocb->cmd_dsd_count = - __constant_cpu_to_le16(bsg_job->request_payload.sg_cnt); + cpu_to_le16(bsg_job->request_payload.sg_cnt); ct_iocb->timeout = 0; ct_iocb->rsp_dsd_count = - __constant_cpu_to_le16(bsg_job->reply_payload.sg_cnt); + cpu_to_le16(bsg_job->reply_payload.sg_cnt); ct_iocb->rsp_byte_count = cpu_to_le32(bsg_job->reply_payload.payload_len); ct_iocb->cmd_byte_count = @@ -2661,7 +2650,7 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, /*Update entry type to indicate bidir command */ *((uint32_t *)(&cmd_pkt->entry_type)) = - __constant_cpu_to_le32(COMMAND_BIDIRECTIONAL); + cpu_to_le32(COMMAND_BIDIRECTIONAL); /* Set the transfer direction, in this set both flags * Also set the BD_WRAP_BACK flag, firmware will take care @@ -2669,8 +2658,7 @@ qla25xx_build_bidir_iocb(srb_t *sp, struct scsi_qla_host *vha, */ cmd_pkt->wr_dseg_count = cpu_to_le16(bsg_job->request_payload.sg_cnt); cmd_pkt->rd_dseg_count = cpu_to_le16(bsg_job->reply_payload.sg_cnt); - cmd_pkt->control_flags = - __constant_cpu_to_le16(BD_WRITE_DATA | BD_READ_DATA | + cmd_pkt->control_flags = cpu_to_le16(BD_WRITE_DATA | BD_READ_DATA | BD_WRAP_BACK); req_data_len = rsp_data_len = bsg_job->request_payload.payload_len; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index a526c389fa2fc..2cb0fba38c9e8 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1564,7 +1564,7 @@ qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk) "Async-%s error - hdl=%x entry-status(%x).\n", type, sp->handle, sts->entry_status); iocb->u.tmf.data = QLA_FUNCTION_FAILED; - } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { + } else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_log(ql_log_warn, fcport->vha, 0x5039, "Async-%s error - hdl=%x completion status(%x).\n", type, sp->handle, sts->comp_status); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 65c2dc1e929a9..0c5477f1bfbad 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1886,11 +1886,11 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->entry_count = 1; lg->handle = MAKE_HANDLE(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); - lg->control_flags = __constant_cpu_to_le16(LCF_COMMAND_PLOGI); + lg->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); if (opt & BIT_0) - lg->control_flags |= __constant_cpu_to_le16(LCF_COND_PLOGI); + lg->control_flags |= cpu_to_le16(LCF_COND_PLOGI); if (opt & BIT_1) - lg->control_flags |= __constant_cpu_to_le16(LCF_SKIP_PRLI); + lg->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); lg->port_id[0] = al_pa; lg->port_id[1] = area; lg->port_id[2] = domain; @@ -1905,7 +1905,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, "Failed to complete IOCB -- error status (%x).\n", lg->entry_status); rval = QLA_FUNCTION_FAILED; - } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { + } else if (lg->comp_status != cpu_to_le16(CS_COMPLETE)) { iop[0] = le32_to_cpu(lg->io_parameter[0]); iop[1] = le32_to_cpu(lg->io_parameter[1]); @@ -1959,7 +1959,7 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, mb[10] |= BIT_0; /* Class 2. */ if (lg->io_parameter[9] || lg->io_parameter[10]) mb[10] |= BIT_1; /* Class 3. */ - if (lg->io_parameter[0] & __constant_cpu_to_le32(BIT_7)) + if (lg->io_parameter[0] & cpu_to_le32(BIT_7)) mb[10] |= BIT_7; /* Confirmed Completion * Allowed */ @@ -2161,7 +2161,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, lg->handle = MAKE_HANDLE(req->id, lg->handle); lg->nport_handle = cpu_to_le16(loop_id); lg->control_flags = - __constant_cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| + cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO| LCF_FREE_NPORT); lg->port_id[0] = al_pa; lg->port_id[1] = area; @@ -2177,7 +2177,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, "Failed to complete IOCB -- error status (%x).\n", lg->entry_status); rval = QLA_FUNCTION_FAILED; - } else if (lg->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { + } else if (lg->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_dbg(ql_dbg_mbx, vha, 0x1071, "Failed to complete IOCB -- completion status (%x) " "ioparam=%x/%x.\n", le16_to_cpu(lg->comp_status), @@ -2668,7 +2668,7 @@ qla24xx_abort_command(srb_t *sp) "Failed to complete IOCB -- error status (%x).\n", abt->entry_status); rval = QLA_FUNCTION_FAILED; - } else if (abt->nport_handle != __constant_cpu_to_le16(0)) { + } else if (abt->nport_handle != cpu_to_le16(0)) { ql_dbg(ql_dbg_mbx, vha, 0x1090, "Failed to complete IOCB -- completion status (%x).\n", le16_to_cpu(abt->nport_handle)); @@ -2751,8 +2751,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, "Failed to complete IOCB -- error status (%x).\n", sts->entry_status); rval = QLA_FUNCTION_FAILED; - } else if (sts->comp_status != - __constant_cpu_to_le16(CS_COMPLETE)) { + } else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_dbg(ql_dbg_mbx, vha, 0x1096, "Failed to complete IOCB -- completion status (%x).\n", le16_to_cpu(sts->comp_status)); @@ -3478,7 +3477,7 @@ qla24xx_modify_vp_config(scsi_qla_host_t *vha) "Failed to complete IOCB -- error status (%x).\n", vpmod->comp_status); rval = QLA_FUNCTION_FAILED; - } else if (vpmod->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { + } else if (vpmod->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_dbg(ql_dbg_mbx, vha, 0x10bf, "Failed to complete IOCB -- completion status (%x).\n", le16_to_cpu(vpmod->comp_status)); @@ -3537,7 +3536,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) vce->entry_type = VP_CTRL_IOCB_TYPE; vce->entry_count = 1; vce->command = cpu_to_le16(cmd); - vce->vp_count = __constant_cpu_to_le16(1); + vce->vp_count = cpu_to_le16(1); /* index map in firmware starts with 1; decrement index * this is ok as we never use index 0 @@ -3557,7 +3556,7 @@ qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) "Failed to complete IOCB -- error status (%x).\n", vce->entry_status); rval = QLA_FUNCTION_FAILED; - } else if (vce->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) { + } else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) { ql_dbg(ql_dbg_mbx, vha, 0x10c5, "Failed to complet IOCB -- completion status (%x).\n", le16_to_cpu(vce->comp_status)); diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 1843ba91e2c8e..2d798e6fadb31 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -3007,7 +3007,7 @@ qlafx00_build_scsi_iocbs(srb_t *sp, struct cmd_type_7_fx00 *cmd_pkt, /* No data transfer */ if (!scsi_bufflen(cmd) || cmd->sc_data_direction == DMA_NONE) { - lcmd_pkt->byte_count = __constant_cpu_to_le32(0); + lcmd_pkt->byte_count = cpu_to_le32(0); return; } diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 89804d20c9263..264be49d04900 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -1765,8 +1765,8 @@ void qla82xx_config_rings(struct scsi_qla_host *vha) /* Setup ring parameters in initialization control block. */ icb = (struct init_cb_81xx *)ha->init_cb; - icb->request_q_outpointer = __constant_cpu_to_le16(0); - icb->response_q_inpointer = __constant_cpu_to_le16(0); + icb->request_q_outpointer = cpu_to_le16(0); + icb->response_q_inpointer = cpu_to_le16(0); icb->request_q_length = cpu_to_le16(req->length); icb->response_q_length = cpu_to_le16(rsp->length); icb->request_q_address[0] = cpu_to_le32(LSD(req->dma)); @@ -2546,7 +2546,7 @@ qla82xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr, "Do ROM fast read failed.\n"); goto done_read; } - dwptr[i] = __constant_cpu_to_le32(val); + dwptr[i] = cpu_to_le32(val); } done_read: return dwptr; diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 028e8c8a7de9a..e44d54231cdc0 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -316,7 +316,7 @@ qla2x00_clear_nvram_protection(struct qla_hw_data *ha) wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); stat = qla2x00_write_nvram_word_tmo(ha, ha->nvram_base, - __constant_cpu_to_le16(0x1234), 100000); + cpu_to_le16(0x1234), 100000); wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base)); if (stat != QLA_SUCCESS || wprot != 0x1234) { /* Write enable. */ @@ -691,9 +691,9 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr) region = (struct qla_flt_region *)&flt[1]; ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, flt_addr << 2, OPTROM_BURST_SIZE); - if (*wptr == __constant_cpu_to_le16(0xffff)) + if (*wptr == cpu_to_le16(0xffff)) goto no_flash_data; - if (flt->version != __constant_cpu_to_le16(1)) { + if (flt->version != cpu_to_le16(1)) { ql_log(ql_log_warn, vha, 0x0047, "Unsupported FLT detected: version=0x%x length=0x%x checksum=0x%x.\n", le16_to_cpu(flt->version), le16_to_cpu(flt->length), @@ -892,7 +892,7 @@ qla2xxx_get_fdt_info(scsi_qla_host_t *vha) fdt = (struct qla_fdt_layout *)req->ring; ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, ha->flt_region_fdt << 2, OPTROM_BURST_SIZE); - if (*wptr == __constant_cpu_to_le16(0xffff)) + if (*wptr == cpu_to_le16(0xffff)) goto no_flash_data; if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' || fdt->sig[3] != 'D') @@ -991,7 +991,7 @@ qla2xxx_get_idc_param(scsi_qla_host_t *vha) ha->isp_ops->read_optrom(vha, (uint8_t *)req->ring, QLA82XX_IDC_PARAM_ADDR , 8); - if (*wptr == __constant_cpu_to_le32(0xffffffff)) { + if (*wptr == cpu_to_le32(0xffffffff)) { ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT; ha->fcoe_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT; } else { @@ -1051,9 +1051,9 @@ qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha) ha->isp_ops->read_optrom(vha, (uint8_t *)&hdr, ha->flt_region_npiv_conf << 2, sizeof(struct qla_npiv_header)); - if (hdr.version == __constant_cpu_to_le16(0xffff)) + if (hdr.version == cpu_to_le16(0xffff)) return; - if (hdr.version != __constant_cpu_to_le16(1)) { + if (hdr.version != cpu_to_le16(1)) { ql_dbg(ql_dbg_user, vha, 0x7090, "Unsupported NPIV-Config " "detected: version=0x%x entries=0x%x checksum=0x%x.\n", diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index b635c05f829fc..445af44c9a7a6 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -1023,7 +1023,7 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha, nack->u.isp24.nport_handle = ntfy->u.isp24.nport_handle; if (le16_to_cpu(ntfy->u.isp24.status) == IMM_NTFY_ELS) { nack->u.isp24.flags = ntfy->u.isp24.flags & - __constant_cpu_to_le32(NOTIFY24XX_FLAGS_PUREX_IOCB); + cpu_to_le32(NOTIFY24XX_FLAGS_PUREX_IOCB); } nack->u.isp24.srr_rx_id = ntfy->u.isp24.srr_rx_id; nack->u.isp24.status = ntfy->u.isp24.status; @@ -1081,7 +1081,7 @@ static void qlt_24xx_send_abts_resp(struct scsi_qla_host *vha, resp->sof_type = abts->sof_type; resp->exchange_address = abts->exchange_address; resp->fcp_hdr_le = abts->fcp_hdr_le; - f_ctl = __constant_cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | + f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | F_CTL_LAST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE); p = (uint8_t *)&f_ctl; @@ -1156,15 +1156,14 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, ctio->entry_count = 1; ctio->nport_handle = entry->nport_handle; ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; - ctio->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); + ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio->vp_index = vha->vp_idx; ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; ctio->exchange_addr = entry->exchange_addr_to_abort; - ctio->u.status1.flags = - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_TERMINATE); + ctio->u.status1.flags = cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | + CTIO7_FLAGS_TERMINATE); ctio->u.status1.ox_id = cpu_to_le16(entry->fcp_hdr_le.ox_id); /* Memory Barrier */ @@ -1324,20 +1323,19 @@ static void qlt_24xx_send_task_mgmt_ctio(struct scsi_qla_host *ha, ctio->entry_count = 1; ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; ctio->nport_handle = mcmd->sess->loop_id; - ctio->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); + ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio->vp_index = ha->vp_idx; ctio->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; ctio->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio->exchange_addr = atio->u.isp24.exchange_addr; ctio->u.status1.flags = (atio->u.isp24.attr << 9) | - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_SEND_STATUS); + cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS); temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); ctio->u.status1.ox_id = cpu_to_le16(temp); ctio->u.status1.scsi_status = - __constant_cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID); - ctio->u.status1.response_len = __constant_cpu_to_le16(8); + cpu_to_le16(SS_RESPONSE_INFO_LEN_VALID); + ctio->u.status1.response_len = cpu_to_le16(8); ctio->u.status1.sense_data[0] = resp_code; /* Memory Barrier */ @@ -1588,7 +1586,7 @@ static int qlt_24xx_build_ctio_pkt(struct qla_tgt_prm *prm, pkt->handle = h | CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = prm->cmd->loop_id; - pkt->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); + pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; @@ -1903,10 +1901,9 @@ static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, { prm->sense_buffer_len = min_t(uint32_t, prm->sense_buffer_len, (uint32_t)sizeof(ctio->u.status1.sense_data)); - ctio->u.status0.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_SEND_STATUS); + ctio->u.status0.flags |= cpu_to_le16(CTIO7_FLAGS_SEND_STATUS); if (qlt_need_explicit_conf(prm->tgt->ha, prm->cmd, 0)) { - ctio->u.status0.flags |= __constant_cpu_to_le16( + ctio->u.status0.flags |= cpu_to_le16( CTIO7_FLAGS_EXPLICIT_CONFORM | CTIO7_FLAGS_CONFORM_REQ); } @@ -1923,17 +1920,17 @@ static void qlt_24xx_init_ctio_to_isp(struct ctio7_to_24xx *ctio, "non GOOD status\n"); goto skip_explict_conf; } - ctio->u.status1.flags |= __constant_cpu_to_le16( + ctio->u.status1.flags |= cpu_to_le16( CTIO7_FLAGS_EXPLICIT_CONFORM | CTIO7_FLAGS_CONFORM_REQ); } skip_explict_conf: ctio->u.status1.flags &= - ~__constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); + ~cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); ctio->u.status1.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); + cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); ctio->u.status1.scsi_status |= - __constant_cpu_to_le16(SS_SENSE_LEN_VALID); + cpu_to_le16(SS_SENSE_LEN_VALID); ctio->u.status1.sense_length = cpu_to_le16(prm->sense_buffer_len); for (i = 0; i < prm->sense_buffer_len/4; i++) @@ -1953,9 +1950,9 @@ skip_explict_conf: #endif } else { ctio->u.status1.flags &= - ~__constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); + ~cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_0); ctio->u.status1.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); + cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1); ctio->u.status1.sense_length = 0; memset(ctio->u.status1.sense_data, 0, sizeof(ctio->u.status1.sense_data)); @@ -2182,7 +2179,7 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) pkt->handle = h | CTIO_COMPLETION_HANDLE_MARK; pkt->nport_handle = prm->cmd->loop_id; - pkt->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); + pkt->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); pkt->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; pkt->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; pkt->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; @@ -2198,9 +2195,9 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) /* Set transfer direction */ if (cmd->dma_data_direction == DMA_TO_DEVICE) - pkt->flags = __constant_cpu_to_le16(CTIO7_FLAGS_DATA_IN); + pkt->flags = cpu_to_le16(CTIO7_FLAGS_DATA_IN); else if (cmd->dma_data_direction == DMA_FROM_DEVICE) - pkt->flags = __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT); + pkt->flags = cpu_to_le16(CTIO7_FLAGS_DATA_OUT); pkt->dseg_count = prm->tot_dsds; @@ -2252,11 +2249,11 @@ qlt_build_ctio_crc2_pkt(struct qla_tgt_prm *prm, scsi_qla_host_t *vha) crc_ctx_pkt->blk_size = cpu_to_le16(cmd->blk_sz); crc_ctx_pkt->prot_opts = cpu_to_le16(fw_prot_opts); crc_ctx_pkt->byte_count = cpu_to_le32(data_bytes); - crc_ctx_pkt->guard_seed = __constant_cpu_to_le16(0); + crc_ctx_pkt->guard_seed = cpu_to_le16(0); /* Walks data segments */ - pkt->flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DSD_PTR); + pkt->flags |= cpu_to_le16(CTIO7_FLAGS_DSD_PTR); if (!bundling && prm->prot_seg_cnt) { if (qla24xx_walk_and_build_sglist_no_difb(ha, NULL, cur_dsd, @@ -2351,7 +2348,7 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, if (qlt_has_data(cmd) && (xmit_type & QLA_TGT_XMIT_DATA)) { pkt->u.status0.flags |= - __constant_cpu_to_le16(CTIO7_FLAGS_DATA_IN | + cpu_to_le16(CTIO7_FLAGS_DATA_IN | CTIO7_FLAGS_STATUS_MODE_0); if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) @@ -2363,11 +2360,11 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cpu_to_le16(prm.rq_result); pkt->u.status0.residual = cpu_to_le32(prm.residual); - pkt->u.status0.flags |= __constant_cpu_to_le16( + pkt->u.status0.flags |= cpu_to_le16( CTIO7_FLAGS_SEND_STATUS); if (qlt_need_explicit_conf(ha, cmd, 0)) { pkt->u.status0.flags |= - __constant_cpu_to_le16( + cpu_to_le16( CTIO7_FLAGS_EXPLICIT_CONFORM | CTIO7_FLAGS_CONFORM_REQ); } @@ -2395,12 +2392,12 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, ctio->entry_count = 1; ctio->entry_type = CTIO_TYPE7; ctio->dseg_count = 0; - ctio->u.status1.flags &= ~__constant_cpu_to_le16( + ctio->u.status1.flags &= ~cpu_to_le16( CTIO7_FLAGS_DATA_IN); /* Real finish is ctio_m1's finish */ pkt->handle |= CTIO_INTERMEDIATE_HANDLE_MARK; - pkt->u.status0.flags |= __constant_cpu_to_le16( + pkt->u.status0.flags |= cpu_to_le16( CTIO7_FLAGS_DONT_RET_CTIO); /* qlt_24xx_init_ctio_to_isp will correct @@ -2486,7 +2483,7 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) if (unlikely(res != 0)) goto out_unlock_free_unmap; pkt = (struct ctio7_to_24xx *)prm.pkt; - pkt->u.status0.flags |= __constant_cpu_to_le16(CTIO7_FLAGS_DATA_OUT | + pkt->u.status0.flags |= cpu_to_le16(CTIO7_FLAGS_DATA_OUT | CTIO7_FLAGS_STATUS_MODE_0); if (cmd->se_cmd.prot_op == TARGET_PROT_NORMAL) @@ -2684,14 +2681,14 @@ static int __qlt_send_term_exchange(struct scsi_qla_host *vha, ctio24 = (struct ctio7_to_24xx *)pkt; ctio24->entry_type = CTIO_TYPE7; ctio24->nport_handle = cmd ? cmd->loop_id : CTIO7_NHANDLE_UNRECOGNIZED; - ctio24->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); + ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio24->vp_index = vha->vp_idx; ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio24->exchange_addr = atio->u.isp24.exchange_addr; ctio24->u.status1.flags = (atio->u.isp24.attr << 9) | - __constant_cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | + cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE); temp = be16_to_cpu(atio->u.isp24.fcp_hdr.ox_id); ctio24->u.status1.ox_id = cpu_to_le16(temp); @@ -2912,7 +2909,7 @@ static int qlt_term_ctio_exchange(struct scsi_qla_host *vha, void *ctio, if (ctio != NULL) { struct ctio7_from_24xx *c = (struct ctio7_from_24xx *)ctio; term = !(c->flags & - __constant_cpu_to_le16(OF_TERM_EXCH)); + cpu_to_le16(OF_TERM_EXCH)); } else term = 1; @@ -4311,14 +4308,14 @@ static int __qlt_send_busy(struct scsi_qla_host *vha, ctio24 = (struct ctio7_to_24xx *)pkt; ctio24->entry_type = CTIO_TYPE7; ctio24->nport_handle = sess->loop_id; - ctio24->timeout = __constant_cpu_to_le16(QLA_TGT_TIMEOUT); + ctio24->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio24->vp_index = vha->vp_idx; ctio24->initiator_id[0] = atio->u.isp24.fcp_hdr.s_id[2]; ctio24->initiator_id[1] = atio->u.isp24.fcp_hdr.s_id[1]; ctio24->initiator_id[2] = atio->u.isp24.fcp_hdr.s_id[0]; ctio24->exchange_addr = atio->u.isp24.exchange_addr; ctio24->u.status1.flags = (atio->u.isp24.attr << 9) | - __constant_cpu_to_le16( + cpu_to_le16( CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_SEND_STATUS | CTIO7_FLAGS_DONT_RET_CTIO); /* @@ -4646,7 +4643,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) struct atio_from_isp *atio = (struct atio_from_isp *)pkt; int rc; if (atio->u.isp2x.status != - __constant_cpu_to_le16(ATIO_CDB_VALID)) { + cpu_to_le16(ATIO_CDB_VALID)) { ql_dbg(ql_dbg_tgt, vha, 0xe05e, "qla_target(%d): ATIO with error " "status %x received\n", vha->vp_idx, @@ -4720,7 +4717,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt) le16_to_cpu(entry->u.isp2x.status)); tgt->notify_ack_expected--; if (entry->u.isp2x.status != - __constant_cpu_to_le16(NOTIFY_ACK_SUCCESS)) { + cpu_to_le16(NOTIFY_ACK_SUCCESS)) { ql_dbg(ql_dbg_tgt, vha, 0xe061, "qla_target(%d): NOTIFY_ACK " "failed %x\n", vha->vp_idx, @@ -5583,19 +5580,19 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) ha->tgt.saved_set = 1; } - nv->exchange_count = __constant_cpu_to_le16(0xFFFF); + nv->exchange_count = cpu_to_le16(0xFFFF); /* Enable target mode */ - nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_4); + nv->firmware_options_1 |= cpu_to_le32(BIT_4); /* Disable ini mode, if requested */ if (!qla_ini_mode_enabled(vha)) - nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_5); + nv->firmware_options_1 |= cpu_to_le32(BIT_5); /* Disable Full Login after LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13); + nv->firmware_options_1 &= cpu_to_le32(~BIT_13); /* Enable initial LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_9); + nv->firmware_options_1 &= cpu_to_le32(~BIT_9); if (ql2xtgt_tape_enable) /* Enable FC Tape support */ nv->firmware_options_2 |= cpu_to_le32(BIT_12); @@ -5604,9 +5601,9 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) nv->firmware_options_2 &= cpu_to_le32(~BIT_12); /* Disable Full Login after LIP */ - nv->host_p &= __constant_cpu_to_le32(~BIT_10); + nv->host_p &= cpu_to_le32(~BIT_10); /* Enable target PRLI control */ - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_14); + nv->firmware_options_2 |= cpu_to_le32(BIT_14); } else { if (ha->tgt.saved_set) { nv->exchange_count = ha->tgt.saved_exchange_count; @@ -5628,12 +5625,12 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) fc_host_supported_classes(vha->host) = FC_COS_CLASS2 | FC_COS_CLASS3; - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_8); + nv->firmware_options_2 |= cpu_to_le32(BIT_8); } else { if (vha->flags.init_done) fc_host_supported_classes(vha->host) = FC_COS_CLASS3; - nv->firmware_options_2 &= ~__constant_cpu_to_le32(BIT_8); + nv->firmware_options_2 &= ~cpu_to_le32(BIT_8); } } @@ -5645,7 +5642,7 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha, if (ha->tgt.node_name_set) { memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); - icb->firmware_options_1 |= __constant_cpu_to_le32(BIT_14); + icb->firmware_options_1 |= cpu_to_le32(BIT_14); } } @@ -5670,20 +5667,19 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) ha->tgt.saved_set = 1; } - nv->exchange_count = __constant_cpu_to_le16(0xFFFF); + nv->exchange_count = cpu_to_le16(0xFFFF); /* Enable target mode */ - nv->firmware_options_1 |= __constant_cpu_to_le32(BIT_4); + nv->firmware_options_1 |= cpu_to_le32(BIT_4); /* Disable ini mode, if requested */ if (!qla_ini_mode_enabled(vha)) - nv->firmware_options_1 |= - __constant_cpu_to_le32(BIT_5); + nv->firmware_options_1 |= cpu_to_le32(BIT_5); /* Disable Full Login after LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_13); + nv->firmware_options_1 &= cpu_to_le32(~BIT_13); /* Enable initial LIP */ - nv->firmware_options_1 &= __constant_cpu_to_le32(~BIT_9); + nv->firmware_options_1 &= cpu_to_le32(~BIT_9); if (ql2xtgt_tape_enable) /* Enable FC tape support */ nv->firmware_options_2 |= cpu_to_le32(BIT_12); @@ -5692,9 +5688,9 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) nv->firmware_options_2 &= cpu_to_le32(~BIT_12); /* Disable Full Login after LIP */ - nv->host_p &= __constant_cpu_to_le32(~BIT_10); + nv->host_p &= cpu_to_le32(~BIT_10); /* Enable target PRLI control */ - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_14); + nv->firmware_options_2 |= cpu_to_le32(BIT_14); } else { if (ha->tgt.saved_set) { nv->exchange_count = ha->tgt.saved_exchange_count; @@ -5716,12 +5712,12 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) fc_host_supported_classes(vha->host) = FC_COS_CLASS2 | FC_COS_CLASS3; - nv->firmware_options_2 |= __constant_cpu_to_le32(BIT_8); + nv->firmware_options_2 |= cpu_to_le32(BIT_8); } else { if (vha->flags.init_done) fc_host_supported_classes(vha->host) = FC_COS_CLASS3; - nv->firmware_options_2 &= ~__constant_cpu_to_le32(BIT_8); + nv->firmware_options_2 &= ~cpu_to_le32(BIT_8); } } @@ -5736,7 +5732,7 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, if (ha->tgt.node_name_set) { memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); - icb->firmware_options_1 |= __constant_cpu_to_le32(BIT_14); + icb->firmware_options_1 |= cpu_to_le32(BIT_14); } } -- GitLab From 118e2ef9df2297147706d21d2a1dfeefea878c5a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:24:27 -0700 Subject: [PATCH 5007/7006] qla2xxx: Avoid that sparse complains about duplicate [noderef] attributes Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_iocb.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 3a786e4739ad2..1a1a221e1759f 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -627,7 +627,7 @@ qla25xx_copy_mq(struct qla_hw_data *ha, void *ptr, uint32_t **last_chain) uint32_t cnt, que_idx; uint8_t que_cnt; struct qla2xxx_mq_chain *mq = ptr; - device_reg_t __iomem *reg; + device_reg_t *reg; if (!ha->mqenable || IS_QLA83XX(ha) || IS_QLA27XX(ha)) return ptr; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ceced7ff8083a..5a5ca43e5e905 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2085,7 +2085,7 @@ void qla24xx_config_rings(struct scsi_qla_host *vha) { struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, 0); + device_reg_t *reg = ISP_QUE_REG(ha, 0); struct device_reg_2xxx __iomem *ioreg = &ha->iobase->isp; struct qla_msix_entry *msix; struct init_cb_24xx *icb; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index fbb1fe9fd3577..5c0bf290d5dfb 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -451,7 +451,7 @@ void qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) { struct qla_hw_data *ha = vha->hw; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + device_reg_t *reg = ISP_QUE_REG(ha, req->id); if (IS_P3P_TYPE(ha)) { qla82xx_start_iocbs(vha); @@ -1795,7 +1795,7 @@ qla2x00_alloc_iocbs(scsi_qla_host_t *vha, srb_t *sp) { struct qla_hw_data *ha = vha->hw; struct req_que *req = ha->req_q_map[0]; - device_reg_t __iomem *reg = ISP_QUE_REG(ha, req->id); + device_reg_t *reg = ISP_QUE_REG(ha, req->id); uint32_t index, handle; request_t *pkt; uint16_t cnt, req_cnt; -- GitLab From 8dfa4b5a9b44714d7710f9f452f65763629f10df Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:24:50 -0700 Subject: [PATCH 5008/7006] qla2xxx: Fix sparse annotations This patch removes 21 casts between an __iomem pointer type and another data type but also introduces five new casts (see also the casts with "__force"). Although this patch does not change any functionality, IMHO the code with __force casts needs further review. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 6 +- drivers/scsi/qla2xxx/qla_iocb.c | 12 ++-- drivers/scsi/qla2xxx/qla_mbx.c | 2 +- drivers/scsi/qla2xxx/qla_mr.c | 6 +- drivers/scsi/qla2xxx/qla_nx.c | 107 +++++++++++++++----------------- drivers/scsi/qla2xxx/qla_tmpl.c | 20 +++--- 6 files changed, 71 insertions(+), 82 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index e86201d3b8c6d..ac88c4e7cf130 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3418,9 +3418,9 @@ struct qla_hw_data { mempool_t *ctx_mempool; #define FCP_CMND_DMA_POOL_SIZE 512 - unsigned long nx_pcibase; /* Base I/O address */ - uint8_t *nxdb_rd_ptr; /* Doorbell read pointer */ - unsigned long nxdb_wr_ptr; /* Door bell write pointer */ + void __iomem *nx_pcibase; /* Base I/O address */ + void __iomem *nxdb_rd_ptr; /* Doorbell read pointer */ + void __iomem *nxdb_wr_ptr; /* Door bell write pointer */ uint32_t crb_win; uint32_t curr_window; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 5c0bf290d5dfb..e07161c1eda1c 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2507,16 +2507,12 @@ sufficient_dsds: /* write, read and verify logic */ dbval = dbval | (req->id << 8) | (req->ring_index << 16); if (ql2xdbwr) - qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); + qla82xx_wr_32(ha, (uintptr_t __force)ha->nxdb_wr_ptr, dbval); else { - WRT_REG_DWORD( - (unsigned long __iomem *)ha->nxdb_wr_ptr, - dbval); + WRT_REG_DWORD(ha->nxdb_wr_ptr, dbval); wmb(); - while (RD_REG_DWORD((void __iomem *)ha->nxdb_rd_ptr) != dbval) { - WRT_REG_DWORD( - (unsigned long __iomem *)ha->nxdb_wr_ptr, - dbval); + while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { + WRT_REG_DWORD(ha->nxdb_wr_ptr, dbval); wmb(); } } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 0c5477f1bfbad..26ca18c3fa6a3 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1239,7 +1239,7 @@ qla2x00_init_firmware(scsi_qla_host_t *vha, uint16_t size) "Entered %s.\n", __func__); if (IS_P3P_TYPE(ha) && ql2xdbwr) - qla82xx_wr_32(ha, ha->nxdb_wr_ptr, + qla82xx_wr_32(ha, (uintptr_t __force)ha->nxdb_wr_ptr, (0x04 | (ha->portnum << 5) | (0 << 8) | (0 << 16))); if (ha->flags.npiv_supported) diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c index 2d798e6fadb31..b5029e543b918 100644 --- a/drivers/scsi/qla2xxx/qla_mr.c +++ b/drivers/scsi/qla2xxx/qla_mr.c @@ -862,7 +862,7 @@ qlafx00_config_queues(struct scsi_qla_host *vha) dma_addr_t bar2_hdl = pci_resource_start(ha->pdev, 2); req->length = ha->req_que_len; - req->ring = (void *)ha->iobase + ha->req_que_off; + req->ring = (void __force *)ha->iobase + ha->req_que_off; req->dma = bar2_hdl + ha->req_que_off; if ((!req->ring) || (req->length == 0)) { ql_log_pci(ql_log_info, ha->pdev, 0x012f, @@ -877,7 +877,7 @@ qlafx00_config_queues(struct scsi_qla_host *vha) ha->req_que_off, (u64)req->dma); rsp->length = ha->rsp_que_len; - rsp->ring = (void *)ha->iobase + ha->rsp_que_off; + rsp->ring = (void __force *)ha->iobase + ha->rsp_que_off; rsp->dma = bar2_hdl + ha->rsp_que_off; if ((!rsp->ring) || (rsp->length == 0)) { ql_log_pci(ql_log_info, ha->pdev, 0x0131, @@ -1425,7 +1425,7 @@ qlafx00_init_response_q_entries(struct rsp_que *rsp) pkt = rsp->ring_ptr; for (cnt = 0; cnt < rsp->length; cnt++) { pkt->signature = RESPONSE_PROCESSED; - WRT_REG_DWORD((void __iomem *)&pkt->signature, + WRT_REG_DWORD((void __force __iomem *)&pkt->signature, RESPONSE_PROCESSED); pkt++; } diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 264be49d04900..3d3ea84cca079 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -347,32 +347,31 @@ char *qdev_state(uint32_t dev_state) } /* - * In: 'off' is offset from CRB space in 128M pci map - * Out: 'off' is 2M pci map addr + * In: 'off_in' is offset from CRB space in 128M pci map + * Out: 'off_out' is 2M pci map addr * side effect: lock crb window */ static void -qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong *off) +qla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong off_in, + void __iomem **off_out) { u32 win_read; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - ha->crb_win = CRB_HI(*off); - writel(ha->crb_win, - (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); + ha->crb_win = CRB_HI(off_in); + writel(ha->crb_win, CRB_WINDOW_2M + ha->nx_pcibase); /* Read back value to make sure write has gone through before trying * to use it. */ - win_read = RD_REG_DWORD((void __iomem *) - (CRB_WINDOW_2M + ha->nx_pcibase)); + win_read = RD_REG_DWORD(CRB_WINDOW_2M + ha->nx_pcibase); if (win_read != ha->crb_win) { ql_dbg(ql_dbg_p3p, vha, 0xb000, "%s: Written crbwin (0x%x) " "!= Read crbwin (0x%x), off=0x%lx.\n", - __func__, ha->crb_win, win_read, *off); + __func__, ha->crb_win, win_read, off_in); } - *off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; + *off_out = (off_in & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase; } static inline unsigned long @@ -417,29 +416,30 @@ qla82xx_pci_set_crbwindow(struct qla_hw_data *ha, u64 off) } static int -qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong *off) +qla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in, + void __iomem **off_out) { struct crb_128M_2M_sub_block_map *m; - if (*off >= QLA82XX_CRB_MAX) + if (off_in >= QLA82XX_CRB_MAX) return -1; - if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) { - *off = (*off - QLA82XX_PCI_CAMQM) + + if (off_in >= QLA82XX_PCI_CAMQM && off_in < QLA82XX_PCI_CAMQM_2M_END) { + *off_out = (off_in - QLA82XX_PCI_CAMQM) + QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase; return 0; } - if (*off < QLA82XX_PCI_CRBSPACE) + if (off_in < QLA82XX_PCI_CRBSPACE) return -1; - *off -= QLA82XX_PCI_CRBSPACE; + *off_out = (void __iomem *)(off_in - QLA82XX_PCI_CRBSPACE); /* Try direct map */ - m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)]; + m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)]; - if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) { - *off = *off + m->start_2M - m->start_128M + ha->nx_pcibase; + if (m->valid && (m->start_128M <= off_in) && (m->end_128M > off_in)) { + *off_out = off_in + m->start_2M - m->start_128M + ha->nx_pcibase; return 0; } /* Not in direct map, use crb window */ @@ -465,19 +465,20 @@ static int qla82xx_crb_win_lock(struct qla_hw_data *ha) } int -qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data) +qla82xx_wr_32(struct qla_hw_data *ha, ulong off_in, u32 data) { + void __iomem *off; unsigned long flags = 0; int rv; - rv = qla82xx_pci_get_crb_addr_2M(ha, &off); + rv = qla82xx_pci_get_crb_addr_2M(ha, off_in, &off); BUG_ON(rv == -1); if (rv == 1) { write_lock_irqsave(&ha->hw_lock, flags); qla82xx_crb_win_lock(ha); - qla82xx_pci_set_crbwindow_2M(ha, &off); + qla82xx_pci_set_crbwindow_2M(ha, off_in, &off); } writel(data, (void __iomem *)off); @@ -490,22 +491,23 @@ qla82xx_wr_32(struct qla_hw_data *ha, ulong off, u32 data) } int -qla82xx_rd_32(struct qla_hw_data *ha, ulong off) +qla82xx_rd_32(struct qla_hw_data *ha, ulong off_in) { + void __iomem *off; unsigned long flags = 0; int rv; u32 data; - rv = qla82xx_pci_get_crb_addr_2M(ha, &off); + rv = qla82xx_pci_get_crb_addr_2M(ha, off_in, &off); BUG_ON(rv == -1); if (rv == 1) { write_lock_irqsave(&ha->hw_lock, flags); qla82xx_crb_win_lock(ha); - qla82xx_pci_set_crbwindow_2M(ha, &off); + qla82xx_pci_set_crbwindow_2M(ha, off_in, &off); } - data = RD_REG_DWORD((void __iomem *)off); + data = RD_REG_DWORD(off); if (rv == 1) { qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); @@ -919,20 +921,18 @@ qla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag) { uint32_t off_value, rval = 0; - WRT_REG_DWORD((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase), - (off & 0xFFFF0000)); + WRT_REG_DWORD(CRB_WINDOW_2M + ha->nx_pcibase, off & 0xFFFF0000); /* Read back value to make sure write has gone through */ - RD_REG_DWORD((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase)); + RD_REG_DWORD(CRB_WINDOW_2M + ha->nx_pcibase); off_value = (off & 0x0000FFFF); if (flag) - WRT_REG_DWORD((void __iomem *) - (off_value + CRB_INDIRECT_2M + ha->nx_pcibase), - data); + WRT_REG_DWORD(off_value + CRB_INDIRECT_2M + ha->nx_pcibase, + data); else - rval = RD_REG_DWORD((void __iomem *) - (off_value + CRB_INDIRECT_2M + ha->nx_pcibase)); + rval = RD_REG_DWORD(off_value + CRB_INDIRECT_2M + + ha->nx_pcibase); return rval; } @@ -1660,8 +1660,7 @@ qla82xx_iospace_config(struct qla_hw_data *ha) } len = pci_resource_len(ha->pdev, 0); - ha->nx_pcibase = - (unsigned long)ioremap(pci_resource_start(ha->pdev, 0), len); + ha->nx_pcibase = ioremap(pci_resource_start(ha->pdev, 0), len); if (!ha->nx_pcibase) { ql_log_pci(ql_log_fatal, ha->pdev, 0x000e, "Cannot remap pcibase MMIO, aborting.\n"); @@ -1670,17 +1669,13 @@ qla82xx_iospace_config(struct qla_hw_data *ha) /* Mapping of IO base pointer */ if (IS_QLA8044(ha)) { - ha->iobase = - (device_reg_t *)((uint8_t *)ha->nx_pcibase); + ha->iobase = ha->nx_pcibase; } else if (IS_QLA82XX(ha)) { - ha->iobase = - (device_reg_t *)((uint8_t *)ha->nx_pcibase + - 0xbc000 + (ha->pdev->devfn << 11)); + ha->iobase = ha->nx_pcibase + 0xbc000 + (ha->pdev->devfn << 11); } if (!ql2xdbwr) { - ha->nxdb_wr_ptr = - (unsigned long)ioremap((pci_resource_start(ha->pdev, 4) + + ha->nxdb_wr_ptr = ioremap((pci_resource_start(ha->pdev, 4) + (ha->pdev->devfn << 12)), 4); if (!ha->nxdb_wr_ptr) { ql_log_pci(ql_log_fatal, ha->pdev, 0x000f, @@ -1691,10 +1686,10 @@ qla82xx_iospace_config(struct qla_hw_data *ha) /* Mapping of IO base pointer, * door bell read and write pointer */ - ha->nxdb_rd_ptr = (uint8_t *) ha->nx_pcibase + (512 * 1024) + + ha->nxdb_rd_ptr = ha->nx_pcibase + (512 * 1024) + (ha->pdev->devfn * 8); } else { - ha->nxdb_wr_ptr = (ha->pdev->devfn == 6 ? + ha->nxdb_wr_ptr = (void __iomem *)(ha->pdev->devfn == 6 ? QLA82XX_CAMRAM_DB1 : QLA82XX_CAMRAM_DB2); } @@ -1704,12 +1699,12 @@ qla82xx_iospace_config(struct qla_hw_data *ha) ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006, "nx_pci_base=%p iobase=%p " "max_req_queues=%d msix_count=%d.\n", - (void *)ha->nx_pcibase, ha->iobase, + ha->nx_pcibase, ha->iobase, ha->max_req_queues, ha->msix_count); ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010, "nx_pci_base=%p iobase=%p " "max_req_queues=%d msix_count=%d.\n", - (void *)ha->nx_pcibase, ha->iobase, + ha->nx_pcibase, ha->iobase, ha->max_req_queues, ha->msix_count); return 0; @@ -1774,9 +1769,9 @@ void qla82xx_config_rings(struct scsi_qla_host *vha) icb->response_q_address[0] = cpu_to_le32(LSD(rsp->dma)); icb->response_q_address[1] = cpu_to_le32(MSD(rsp->dma)); - WRT_REG_DWORD((unsigned long __iomem *)®->req_q_out[0], 0); - WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_in[0], 0); - WRT_REG_DWORD((unsigned long __iomem *)®->rsp_q_out[0], 0); + WRT_REG_DWORD(®->req_q_out[0], 0); + WRT_REG_DWORD(®->rsp_q_in[0], 0); + WRT_REG_DWORD(®->rsp_q_out[0], 0); } static int @@ -2799,13 +2794,12 @@ qla82xx_start_iocbs(scsi_qla_host_t *vha) dbval = dbval | (req->id << 8) | (req->ring_index << 16); if (ql2xdbwr) - qla82xx_wr_32(ha, ha->nxdb_wr_ptr, dbval); + qla82xx_wr_32(ha, (unsigned long)ha->nxdb_wr_ptr, dbval); else { - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, dbval); + WRT_REG_DWORD(ha->nxdb_wr_ptr, dbval); wmb(); - while (RD_REG_DWORD((void __iomem *)ha->nxdb_rd_ptr) != dbval) { - WRT_REG_DWORD((unsigned long __iomem *)ha->nxdb_wr_ptr, - dbval); + while (RD_REG_DWORD(ha->nxdb_rd_ptr) != dbval) { + WRT_REG_DWORD(ha->nxdb_wr_ptr, dbval); wmb(); } } @@ -3836,8 +3830,7 @@ qla82xx_minidump_process_rdocm(scsi_qla_host_t *vha, loop_cnt = ocm_hdr->op_count; for (i = 0; i < loop_cnt; i++) { - r_value = RD_REG_DWORD((void __iomem *) - (r_addr + ha->nx_pcibase)); + r_value = RD_REG_DWORD(r_addr + ha->nx_pcibase); *data_ptr++ = cpu_to_le32(r_value); r_addr += r_stride; } diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 7e876d1e2f78b..f4eb65524ae4f 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -137,39 +137,39 @@ qla27xx_insertbuf(void *mem, ulong size, void *buf, ulong *len) } static inline void -qla27xx_read8(void *window, void *buf, ulong *len) +qla27xx_read8(void __iomem *window, void *buf, ulong *len) { uint8_t value = ~0; if (buf) { - value = RD_REG_BYTE((__iomem void *)window); + value = RD_REG_BYTE(window); } qla27xx_insert32(value, buf, len); } static inline void -qla27xx_read16(void *window, void *buf, ulong *len) +qla27xx_read16(void __iomem *window, void *buf, ulong *len) { uint16_t value = ~0; if (buf) { - value = RD_REG_WORD((__iomem void *)window); + value = RD_REG_WORD(window); } qla27xx_insert32(value, buf, len); } static inline void -qla27xx_read32(void *window, void *buf, ulong *len) +qla27xx_read32(void __iomem *window, void *buf, ulong *len) { uint32_t value = ~0; if (buf) { - value = RD_REG_DWORD((__iomem void *)window); + value = RD_REG_DWORD(window); } qla27xx_insert32(value, buf, len); } -static inline void (*qla27xx_read_vector(uint width))(void *, void *, ulong *) +static inline void (*qla27xx_read_vector(uint width))(void __iomem*, void *, ulong *) { return (width == 1) ? qla27xx_read8 : @@ -181,7 +181,7 @@ static inline void qla27xx_read_reg(__iomem struct device_reg_24xx *reg, uint offset, void *buf, ulong *len) { - void *window = (void *)reg + offset; + void __iomem *window = (void __iomem *)reg + offset; qla27xx_read32(window, buf, len); } @@ -202,8 +202,8 @@ qla27xx_read_window(__iomem struct device_reg_24xx *reg, uint32_t addr, uint offset, uint count, uint width, void *buf, ulong *len) { - void *window = (void *)reg + offset; - void (*readn)(void *, void *, ulong *) = qla27xx_read_vector(width); + void __iomem *window = (void __iomem *)reg + offset; + void (*readn)(void __iomem*, void *, ulong *) = qla27xx_read_vector(width); qla27xx_write_reg(reg, IOBASE_ADDR, addr, buf); while (count--) { -- GitLab From 82e6afd49d9a5da8cdb648cb66e54432173298d7 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:25:07 -0700 Subject: [PATCH 5009/7006] qla2xxx: Remove a superfluous test Avoid that smatch reports the following warning: drivers/scsi/qla2xxx/qla_attr.c:1081: qla2x00_model_desc_show() warn: this array is probably non-NULL. 'vha->hw->model_desc' Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 741d6e0f40603..2087b73927ce7 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1077,8 +1077,7 @@ qla2x00_model_desc_show(struct device *dev, struct device_attribute *attr, char *buf) { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); - return scnprintf(buf, PAGE_SIZE, "%s\n", - vha->hw->model_desc ? vha->hw->model_desc : ""); + return scnprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_desc); } static ssize_t -- GitLab From 8a318fe16096a45c03e8c9a39449d1f750fafd27 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:25:25 -0700 Subject: [PATCH 5010/7006] qla2xxx: Remove dead code The "return QLA_SUCCESS" statement just above the "fw_load_failed" label cannot be reached, hence remove it. Additionally remove the "else" keyword since the code block below the if-statement ends with a return statement. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_nx.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index 3d3ea84cca079..bb0ee7c604c76 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -2473,14 +2473,12 @@ try_blob_fw: ql_log(ql_log_info, vha, 0x00a5, "Firmware loaded successfully from binary blob.\n"); return QLA_SUCCESS; - } else { - ql_log(ql_log_fatal, vha, 0x00a6, - "Firmware load failed for binary blob.\n"); - blob->fw = NULL; - blob = NULL; - goto fw_load_failed; } - return QLA_SUCCESS; + + ql_log(ql_log_fatal, vha, 0x00a6, + "Firmware load failed for binary blob.\n"); + blob->fw = NULL; + blob = NULL; fw_load_failed: return QLA_FUNCTION_FAILED; -- GitLab From 8d16366b5f23e928e5fd22eaeaceeb0356921fc0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 9 Jul 2015 07:25:46 -0700 Subject: [PATCH 5011/7006] qla2xxx: Avoid that sparse complains about context imbalances Surround conditional locking statements with "#ifndef __CHECKER__" / "#endif" to hide these for the sparse static source code analysis tool. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.c | 36 +++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_nx.c | 8 +++++++ drivers/scsi/qla2xxx/qla_target.c | 4 ++++ drivers/scsi/qla2xxx/qla_tmpl.c | 4 ++++ 4 files changed, 52 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 1a1a221e1759f..583d52aae79d2 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -695,8 +695,10 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked) flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif if (!ha->fw_dump) { ql_log(ql_log_warn, vha, 0xd002, @@ -832,8 +834,12 @@ qla2300_fw_dump(scsi_qla_host_t *vha, int hardware_locked) qla2xxx_dump_post_process(base_vha, rval); qla2300_fw_dump_failed: +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#else + ; +#endif } /** @@ -859,8 +865,10 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked) mb0 = mb2 = 0; flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif if (!ha->fw_dump) { ql_log(ql_log_warn, vha, 0xd004, @@ -1030,8 +1038,12 @@ qla2100_fw_dump(scsi_qla_host_t *vha, int hardware_locked) qla2xxx_dump_post_process(base_vha, rval); qla2100_fw_dump_failed: +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#else + ; +#endif } void @@ -1057,8 +1069,10 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) flags = 0; ha->fw_dump_cap_flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif if (!ha->fw_dump) { ql_log(ql_log_warn, vha, 0xd006, @@ -1282,8 +1296,12 @@ qla24xx_fw_dump_failed_0: qla2xxx_dump_post_process(base_vha, rval); qla24xx_fw_dump_failed: +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#else + ; +#endif } void @@ -1305,8 +1323,10 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) flags = 0; ha->fw_dump_cap_flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif if (!ha->fw_dump) { ql_log(ql_log_warn, vha, 0xd008, @@ -1598,8 +1618,12 @@ qla25xx_fw_dump_failed_0: qla2xxx_dump_post_process(base_vha, rval); qla25xx_fw_dump_failed: +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#else + ; +#endif } void @@ -1621,8 +1645,10 @@ qla81xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) flags = 0; ha->fw_dump_cap_flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif if (!ha->fw_dump) { ql_log(ql_log_warn, vha, 0xd00a, @@ -1916,8 +1942,12 @@ qla81xx_fw_dump_failed_0: qla2xxx_dump_post_process(base_vha, rval); qla81xx_fw_dump_failed: +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#else + ; +#endif } void @@ -1939,8 +1969,10 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) flags = 0; ha->fw_dump_cap_flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif if (!ha->fw_dump) { ql_log(ql_log_warn, vha, 0xd00c, @@ -2419,8 +2451,12 @@ qla83xx_fw_dump_failed_0: qla2xxx_dump_post_process(base_vha, rval); qla83xx_fw_dump_failed: +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#else + ; +#endif } /****************************************************************************/ diff --git a/drivers/scsi/qla2xxx/qla_nx.c b/drivers/scsi/qla2xxx/qla_nx.c index bb0ee7c604c76..eb0cc5475c451 100644 --- a/drivers/scsi/qla2xxx/qla_nx.c +++ b/drivers/scsi/qla2xxx/qla_nx.c @@ -476,7 +476,9 @@ qla82xx_wr_32(struct qla_hw_data *ha, ulong off_in, u32 data) BUG_ON(rv == -1); if (rv == 1) { +#ifndef __CHECKER__ write_lock_irqsave(&ha->hw_lock, flags); +#endif qla82xx_crb_win_lock(ha); qla82xx_pci_set_crbwindow_2M(ha, off_in, &off); } @@ -485,7 +487,9 @@ qla82xx_wr_32(struct qla_hw_data *ha, ulong off_in, u32 data) if (rv == 1) { qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +#ifndef __CHECKER__ write_unlock_irqrestore(&ha->hw_lock, flags); +#endif } return 0; } @@ -503,7 +507,9 @@ qla82xx_rd_32(struct qla_hw_data *ha, ulong off_in) BUG_ON(rv == -1); if (rv == 1) { +#ifndef __CHECKER__ write_lock_irqsave(&ha->hw_lock, flags); +#endif qla82xx_crb_win_lock(ha); qla82xx_pci_set_crbwindow_2M(ha, off_in, &off); } @@ -511,7 +517,9 @@ qla82xx_rd_32(struct qla_hw_data *ha, ulong off_in) if (rv == 1) { qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK)); +#ifndef __CHECKER__ write_unlock_irqrestore(&ha->hw_lock, flags); +#endif } return data; } diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 445af44c9a7a6..6b7736d02534d 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -3955,16 +3955,20 @@ static void qlt_reject_free_srr_imm(struct scsi_qla_host *vha, struct qla_hw_data *ha = vha->hw; unsigned long flags = 0; +#ifndef __CHECKER__ if (!ha_locked) spin_lock_irqsave(&ha->hardware_lock, flags); +#endif qlt_send_notify_ack(vha, (void *)&imm->imm_ntfy, 0, 0, 0, NOTIFY_ACK_SRR_FLAGS_REJECT, NOTIFY_ACK_SRR_REJECT_REASON_UNABLE_TO_PERFORM, NOTIFY_ACK_SRR_FLAGS_REJECT_EXPL_NO_EXPL); +#ifndef __CHECKER__ if (!ha_locked) spin_unlock_irqrestore(&ha->hardware_lock, flags); +#endif kfree(imm); } diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index f4eb65524ae4f..ddbe2e7ac14d0 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -939,8 +939,10 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) { ulong flags = 0; +#ifndef __CHECKER__ if (!hardware_locked) spin_lock_irqsave(&vha->hw->hardware_lock, flags); +#endif if (!vha->hw->fw_dump) ql_log(ql_log_warn, vha, 0xd01e, "fwdump buffer missing.\n"); @@ -953,6 +955,8 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) else qla27xx_execute_fwdt_template(vha); +#ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); +#endif } -- GitLab From dc8242f704fee4fddcbebfcc5a4d08526951444a Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Wed, 26 Aug 2015 15:36:12 +0200 Subject: [PATCH 5012/7006] lib/Makefile: remove CONFIG_AVERAGE build rule The Kconfig option AVERAGE and its implementation has been removed by commit f4e774f55fe0 ("average: remove out-of-line implementation"). Remove the dead build rule in lib/Makefile. Signed-off-by: Valentin Rothberg Reviewed-by: Johannes Berg Signed-off-by: David S. Miller --- lib/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index 6897b527581a8..0d4b30fb60e66 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -138,8 +138,6 @@ obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o -obj-$(CONFIG_AVERAGE) += average.o - obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o obj-$(CONFIG_CORDIC) += cordic.o -- GitLab From 7d40acc38be55abb095f517e4e3a634818bc5253 Mon Sep 17 00:00:00 2001 From: Jyri Sarha Date: Wed, 26 Aug 2015 16:11:40 +0300 Subject: [PATCH 5013/7006] ASoC: omap-hdmi-audio: Set buffer bytes step constraint to 128 Set buffer bytes step constraint to 128. A matching constraint has already been set to period size. This helps PCM setup to tolerate ALSA clients that set the PCM hw params in unusual order. Signed-off-by: Jyri Sarha Signed-off-by: Mark Brown --- sound/soc/omap/omap-hdmi-audio.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c index aeef25c0cb3d9..584b2372339ef 100644 --- a/sound/soc/omap/omap-hdmi-audio.c +++ b/sound/soc/omap/omap-hdmi-audio.c @@ -81,7 +81,15 @@ static int hdmi_dai_startup(struct snd_pcm_substream *substream, ret = snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128); if (ret < 0) { - dev_err(dai->dev, "could not apply constraint\n"); + dev_err(dai->dev, "Could not apply period constraint: %d\n", + ret); + return ret; + } + ret = snd_pcm_hw_constraint_step(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 128); + if (ret < 0) { + dev_err(dai->dev, "Could not apply buffer constraint: %d\n", + ret); return ret; } -- GitLab From 5aeeb78aeb4c8607cbda54a7b0dc7315171e214f Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Wed, 15 Jul 2015 10:19:56 +0530 Subject: [PATCH 5014/7006] mpt2sas, mpt3sas: Abort initialization if no memory I/O resources detected Driver crashes if the BIOS do not set up at least one memory I/O resource. This failure can happen if the device is too slow to respond during POST and is missed by the BIOS, but Linux then detects the device later in the boot process. Based on a patch from Timothy Pearson Signed-off-by: Sreekanth Reddy Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 16 +++++++++------- drivers/scsi/mpt3sas/mpt3sas_base.c | 16 +++++++++------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 11248de92b3b1..6dec7cff316f4 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -1557,7 +1557,8 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) goto out_fail; } - for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { + for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) && + (!memap_sz || !pio_sz); i++) { if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { if (pio_sz) continue; @@ -1572,16 +1573,17 @@ mpt2sas_base_map_resources(struct MPT2SAS_ADAPTER *ioc) chip_phys = (u64)ioc->chip_phys; memap_sz = pci_resource_len(pdev, i); ioc->chip = ioremap(ioc->chip_phys, memap_sz); - if (ioc->chip == NULL) { - printk(MPT2SAS_ERR_FMT "unable to map " - "adapter memory!\n", ioc->name); - r = -EINVAL; - goto out_fail; - } } } } + if (ioc->chip == NULL) { + printk(MPT2SAS_ERR_FMT "unable to map adapter memory! " + "or resource not found\n", ioc->name); + r = -EINVAL; + goto out_fail; + } + _base_mask_interrupts(ioc); r = _base_get_ioc_facts(ioc, CAN_SLEEP); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 14a781b6b88da..43f87e904b988 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1843,7 +1843,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) goto out_fail; } - for (i = 0, memap_sz = 0, pio_sz = 0 ; i < DEVICE_COUNT_RESOURCE; i++) { + for (i = 0, memap_sz = 0, pio_sz = 0; (i < DEVICE_COUNT_RESOURCE) && + (!memap_sz || !pio_sz); i++) { if (pci_resource_flags(pdev, i) & IORESOURCE_IO) { if (pio_sz) continue; @@ -1856,15 +1857,16 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) chip_phys = (u64)ioc->chip_phys; memap_sz = pci_resource_len(pdev, i); ioc->chip = ioremap(ioc->chip_phys, memap_sz); - if (ioc->chip == NULL) { - pr_err(MPT3SAS_FMT "unable to map adapter memory!\n", - ioc->name); - r = -EINVAL; - goto out_fail; - } } } + if (ioc->chip == NULL) { + pr_err(MPT3SAS_FMT "unable to map adapter memory! " + " or resource not found\n", ioc->name); + r = -EINVAL; + goto out_fail; + } + _base_mask_interrupts(ioc); r = _base_get_ioc_facts(ioc, CAN_SLEEP); -- GitLab From f57ddcdfa146636dbdcd6ac0a6d22c15d47b08c8 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 23 Aug 2015 23:32:14 +0800 Subject: [PATCH 5015/7006] ASoC: tegra: Use devm_ioremap_resource instead of open code Use devm_ioremap_resource() to simplify the code. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/tegra/tegra20_das.c | 23 +++--------------- sound/soc/tegra/tegra20_i2s.c | 23 +++--------------- sound/soc/tegra/tegra20_spdif.c | 22 +++-------------- sound/soc/tegra/tegra30_ahub.c | 43 ++++++--------------------------- sound/soc/tegra/tegra30_i2s.c | 23 +++--------------- 5 files changed, 23 insertions(+), 111 deletions(-) diff --git a/sound/soc/tegra/tegra20_das.c b/sound/soc/tegra/tegra20_das.c index f52600b4f3fd3..89add13c31cfc 100644 --- a/sound/soc/tegra/tegra20_das.c +++ b/sound/soc/tegra/tegra20_das.c @@ -133,7 +133,7 @@ static const struct regmap_config tegra20_das_regmap_config = { static int tegra20_das_probe(struct platform_device *pdev) { - struct resource *res, *region; + struct resource *res; void __iomem *regs; int ret = 0; @@ -149,24 +149,9 @@ static int tegra20_das_probe(struct platform_device *pdev) das->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err; - } - - region = devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), pdev->name); - if (!region) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err; - } - - regs = devm_ioremap(&pdev->dev, res->start, resource_size(res)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); goto err; } diff --git a/sound/soc/tegra/tegra20_i2s.c b/sound/soc/tegra/tegra20_i2s.c index 05f1c6ee99e36..14106fa82bca3 100644 --- a/sound/soc/tegra/tegra20_i2s.c +++ b/sound/soc/tegra/tegra20_i2s.c @@ -339,7 +339,7 @@ static const struct regmap_config tegra20_i2s_regmap_config = { static int tegra20_i2s_platform_probe(struct platform_device *pdev) { struct tegra20_i2s *i2s; - struct resource *mem, *memregion; + struct resource *mem; void __iomem *regs; int ret; @@ -362,24 +362,9 @@ static int tegra20_i2s_platform_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); goto err_clk_put; } diff --git a/sound/soc/tegra/tegra20_spdif.c b/sound/soc/tegra/tegra20_spdif.c index 0809b1ec11710..a0c3640572b98 100644 --- a/sound/soc/tegra/tegra20_spdif.c +++ b/sound/soc/tegra/tegra20_spdif.c @@ -265,7 +265,7 @@ static const struct regmap_config tegra20_spdif_regmap_config = { static int tegra20_spdif_platform_probe(struct platform_device *pdev) { struct tegra20_spdif *spdif; - struct resource *mem, *memregion, *dmareq; + struct resource *mem, *dmareq; void __iomem *regs; int ret; @@ -285,10 +285,9 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - return -ENODEV; - } + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) + return PTR_ERR(regs); dmareq = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmareq) { @@ -296,19 +295,6 @@ static int tegra20_spdif_platform_probe(struct platform_device *pdev) return -ENODEV; } - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - return -EBUSY; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - return -ENOMEM; - } - spdif->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &tegra20_spdif_regmap_config); if (IS_ERR(spdif->regmap)) { diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c index 989b1e8c6184f..fef3b9a21a667 100644 --- a/sound/soc/tegra/tegra30_ahub.c +++ b/sound/soc/tegra/tegra30_ahub.c @@ -521,7 +521,7 @@ static int tegra30_ahub_probe(struct platform_device *pdev) const struct tegra30_ahub_soc_data *soc_data; struct reset_control *rst; int i; - struct resource *res0, *res1, *region; + struct resource *res0, *res1; void __iomem *regs_apbif, *regs_ahub; int ret = 0; @@ -584,26 +584,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev) } res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res0) { - dev_err(&pdev->dev, "No apbif memory resource\n"); - return -ENODEV; - } + regs_apbif = devm_ioremap_resource(&pdev->dev, res0); + if (IS_ERR(regs_apbif)) + return PTR_ERR(regs_apbif); - region = devm_request_mem_region(&pdev->dev, res0->start, - resource_size(res0), DRV_NAME); - if (!region) { - dev_err(&pdev->dev, "request region apbif failed\n"); - return -EBUSY; - } ahub->apbif_addr = res0->start; - regs_apbif = devm_ioremap(&pdev->dev, res0->start, - resource_size(res0)); - if (!regs_apbif) { - dev_err(&pdev->dev, "ioremap apbif failed\n"); - return -ENOMEM; - } - ahub->regmap_apbif = devm_regmap_init_mmio(&pdev->dev, regs_apbif, &tegra30_ahub_apbif_regmap_config); if (IS_ERR(ahub->regmap_apbif)) { @@ -614,24 +600,9 @@ static int tegra30_ahub_probe(struct platform_device *pdev) regcache_cache_only(ahub->regmap_apbif, true); res1 = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res1) { - dev_err(&pdev->dev, "No ahub memory resource\n"); - return -ENODEV; - } - - region = devm_request_mem_region(&pdev->dev, res1->start, - resource_size(res1), DRV_NAME); - if (!region) { - dev_err(&pdev->dev, "request region ahub failed\n"); - return -EBUSY; - } - - regs_ahub = devm_ioremap(&pdev->dev, res1->start, - resource_size(res1)); - if (!regs_ahub) { - dev_err(&pdev->dev, "ioremap ahub failed\n"); - return -ENOMEM; - } + regs_ahub = devm_ioremap_resource(&pdev->dev, res1); + if (IS_ERR(regs_ahub)) + return PTR_ERR(regs_ahub); ahub->regmap_ahub = devm_regmap_init_mmio(&pdev->dev, regs_ahub, &tegra30_ahub_ahub_regmap_config); diff --git a/sound/soc/tegra/tegra30_i2s.c b/sound/soc/tegra/tegra30_i2s.c index fe36375ba89c5..8e55583aa104e 100644 --- a/sound/soc/tegra/tegra30_i2s.c +++ b/sound/soc/tegra/tegra30_i2s.c @@ -379,7 +379,7 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) struct tegra30_i2s *i2s; const struct of_device_id *match; u32 cif_ids[2]; - struct resource *mem, *memregion; + struct resource *mem; void __iomem *regs; int ret; @@ -419,24 +419,9 @@ static int tegra30_i2s_platform_probe(struct platform_device *pdev) } mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "No memory resource\n"); - ret = -ENODEV; - goto err_clk_put; - } - - memregion = devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), DRV_NAME); - if (!memregion) { - dev_err(&pdev->dev, "Memory region already claimed\n"); - ret = -EBUSY; - goto err_clk_put; - } - - regs = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (!regs) { - dev_err(&pdev->dev, "ioremap failed\n"); - ret = -ENOMEM; + regs = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(regs)) { + ret = PTR_ERR(regs); goto err_clk_put; } -- GitLab From 30b139dfe0bfa8727ceec2a1d5294766943dcdc8 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Wed, 26 Aug 2015 14:36:46 +0100 Subject: [PATCH 5016/7006] scripts: add extract-cert and sign-file to .gitignore ...so "git status" doesn't nag us about them. Cc: David Woodhouse Signed-off-by: Paul Gortmaker Signed-off-by: David Howells Signed-off-by: James Morris --- scripts/.gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/.gitignore b/scripts/.gitignore index 5ecfe93f20287..12efbbefd4d75 100644 --- a/scripts/.gitignore +++ b/scripts/.gitignore @@ -10,3 +10,5 @@ recordmcount docproc sortextable asn1_compiler +extract-cert +sign-file -- GitLab From 3c645621b79828be7a46fb2694eb423b343b4bbe Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 25 Aug 2015 20:06:31 -0700 Subject: [PATCH 5017/7006] net_sched: make tcf_hash_destroy() static tcf_hash_destroy() used once. Make it static. Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/act_api.h | 1 - net/sched/act_api.c | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/include/net/act_api.h b/include/net/act_api.h index 4519c81304bd2..9d446f136607e 100644 --- a/include/net/act_api.h +++ b/include/net/act_api.h @@ -111,7 +111,6 @@ struct tc_action_ops { }; int tcf_hash_search(struct tc_action *a, u32 index); -void tcf_hash_destroy(struct tc_action *a); u32 tcf_hash_new_index(struct tcf_hashinfo *hinfo); int tcf_hash_check(u32 index, struct tc_action *a, int bind); int tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, diff --git a/net/sched/act_api.c b/net/sched/act_api.c index b087087ccfa94..06e7c4a372451 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -36,7 +36,7 @@ static void free_tcf(struct rcu_head *head) kfree(p); } -void tcf_hash_destroy(struct tc_action *a) +static void tcf_hash_destroy(struct tc_action *a) { struct tcf_common *p = a->priv; struct tcf_hashinfo *hinfo = a->ops->hinfo; @@ -52,7 +52,6 @@ void tcf_hash_destroy(struct tc_action *a) */ call_rcu(&p->tcfc_rcu, free_tcf); } -EXPORT_SYMBOL(tcf_hash_destroy); int __tcf_hash_release(struct tc_action *a, bool bind, bool strict) { -- GitLab From faa54be4c78da6aa2148c539659867afdecd3e8d Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 25 Aug 2015 20:06:32 -0700 Subject: [PATCH 5018/7006] net_sched: act_bpf: remove unnecessary copy Fix harmless typo and avoid unnecessary copy of empty 'prog' into unused 'strcut tcf_bpf_cfg old'. Fixes: f4eaed28c783 ("act_bpf: fix memory leaks when replacing bpf programs") Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sched/act_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 1b97dabc621a5..458cf647e698a 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -327,7 +327,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, prog = to_bpf(act); spin_lock_bh(&prog->tcf_lock); - if (ret != ACT_P_CREATED) + if (res != ACT_P_CREATED) tcf_bpf_prog_fill_cfg(prog, &old); prog->bpf_ops = cfg.bpf_ops; -- GitLab From ed7aa879ce1a0ff6468c5a6d3eb4e31169b95c4a Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 25 Aug 2015 20:06:33 -0700 Subject: [PATCH 5019/7006] net_sched: convert tcindex to call tcf_exts_destroy from rcu callback Adjust destroy path of cls_tcindex to call tcf_exts_destroy() after rcu grace period. Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sched/cls_tcindex.c | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index a557dbaf5afed..944c8ff450558 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -27,6 +27,7 @@ struct tcindex_filter_result { struct tcf_exts exts; struct tcf_result res; + struct rcu_head rcu; }; struct tcindex_filter { @@ -133,8 +134,23 @@ static int tcindex_init(struct tcf_proto *tp) return 0; } -static int -tcindex_delete(struct tcf_proto *tp, unsigned long arg) +static void tcindex_destroy_rexts(struct rcu_head *head) +{ + struct tcindex_filter_result *r; + + r = container_of(head, struct tcindex_filter_result, rcu); + tcf_exts_destroy(&r->exts); +} + +static void tcindex_destroy_fexts(struct rcu_head *head) +{ + struct tcindex_filter *f = container_of(head, struct tcindex_filter, rcu); + + tcf_exts_destroy(&f->result.exts); + kfree(f); +} + +static int tcindex_delete(struct tcf_proto *tp, unsigned long arg) { struct tcindex_data *p = rtnl_dereference(tp->root); struct tcindex_filter_result *r = (struct tcindex_filter_result *) arg; @@ -162,9 +178,14 @@ found: rcu_assign_pointer(*walk, rtnl_dereference(f->next)); } tcf_unbind_filter(tp, &r->res); - tcf_exts_destroy(&r->exts); + /* all classifiers are required to call tcf_exts_destroy() after rcu + * grace period, since converted-to-rcu actions are relying on that + * in cleanup() callback + */ if (f) - kfree_rcu(f, rcu); + call_rcu(&f->rcu, tcindex_destroy_fexts); + else + call_rcu(&r->rcu, tcindex_destroy_rexts); return 0; } -- GitLab From 9e528d89154b602209fda2fb92e89927bbffc976 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 25 Aug 2015 20:06:34 -0700 Subject: [PATCH 5020/7006] net_sched: convert rsvp to call tcf_exts_destroy from rcu callback Adjust destroy path of cls_rsvp to call tcf_exts_destroy() after rcu grace period. Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/sched/cls_rsvp.h | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h index 02fa82792dab8..f9c9fc075fe65 100644 --- a/net/sched/cls_rsvp.h +++ b/net/sched/cls_rsvp.h @@ -283,12 +283,22 @@ static int rsvp_init(struct tcf_proto *tp) return -ENOBUFS; } -static void -rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) +static void rsvp_delete_filter_rcu(struct rcu_head *head) { - tcf_unbind_filter(tp, &f->res); + struct rsvp_filter *f = container_of(head, struct rsvp_filter, rcu); + tcf_exts_destroy(&f->exts); - kfree_rcu(f, rcu); + kfree(f); +} + +static void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) +{ + tcf_unbind_filter(tp, &f->res); + /* all classifiers are required to call tcf_exts_destroy() after rcu + * grace period, since converted-to-rcu actions are relying on that + * in cleanup() callback + */ + call_rcu(&f->rcu, rsvp_delete_filter_rcu); } static bool rsvp_destroy(struct tcf_proto *tp, bool force) -- GitLab From cff82457c5584f6a96d2b85d1a88b81ba304a330 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 25 Aug 2015 20:06:35 -0700 Subject: [PATCH 5021/7006] net_sched: act_bpf: remove spinlock in fast path Similar to act_gact/act_mirred, act_bpf can be lockless in packet processing with extra care taken to free bpf programs after rcu grace period. Replacement of existing act_bpf (very rare) is done with synchronize_rcu() and final destruction is done from tc_action_ops->cleanup() callback that is called from tcf_exts_destroy()->tcf_action_destroy()->__tcf_hash_release() when bind and refcnt reach zero which is only possible when classifier is destroyed. Previous two patches fixed the last two classifiers (tcindex and rsvp) to call tcf_exts_destroy() from rcu callback. Similar to gact/mirred there is a race between prog->filter and prog->tcf_action. Meaning that the program being replaced may use previous default action if it happened to return TC_ACT_UNSPEC. act_mirred race betwen tcf_action and tcfm_dev is similar. In all cases the race is harmless. Long term we may want to improve the situation by replacing the whole tc_action->priv as single pointer instead of updating inner fields one by one. Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/net/tc_act/tc_bpf.h | 2 +- net/sched/act_bpf.c | 36 +++++++++++++++++++----------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/net/tc_act/tc_bpf.h b/include/net/tc_act/tc_bpf.h index a152e9858b2c8..958d69cfb19cc 100644 --- a/include/net/tc_act/tc_bpf.h +++ b/include/net/tc_act/tc_bpf.h @@ -15,7 +15,7 @@ struct tcf_bpf { struct tcf_common common; - struct bpf_prog *filter; + struct bpf_prog __rcu *filter; union { u32 bpf_fd; u16 bpf_num_ops; diff --git a/net/sched/act_bpf.c b/net/sched/act_bpf.c index 458cf647e698a..559bfa011bda7 100644 --- a/net/sched/act_bpf.c +++ b/net/sched/act_bpf.c @@ -37,25 +37,24 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act, struct tcf_result *res) { struct tcf_bpf *prog = act->priv; + struct bpf_prog *filter; int action, filter_res; bool at_ingress = G_TC_AT(skb->tc_verd) & AT_INGRESS; if (unlikely(!skb_mac_header_was_set(skb))) return TC_ACT_UNSPEC; - spin_lock(&prog->tcf_lock); - - prog->tcf_tm.lastuse = jiffies; - bstats_update(&prog->tcf_bstats, skb); + tcf_lastuse_update(&prog->tcf_tm); + bstats_cpu_update(this_cpu_ptr(prog->common.cpu_bstats), skb); - /* Needed here for accessing maps. */ rcu_read_lock(); + filter = rcu_dereference(prog->filter); if (at_ingress) { __skb_push(skb, skb->mac_len); - filter_res = BPF_PROG_RUN(prog->filter, skb); + filter_res = BPF_PROG_RUN(filter, skb); __skb_pull(skb, skb->mac_len); } else { - filter_res = BPF_PROG_RUN(prog->filter, skb); + filter_res = BPF_PROG_RUN(filter, skb); } rcu_read_unlock(); @@ -77,7 +76,7 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act, break; case TC_ACT_SHOT: action = filter_res; - prog->tcf_qstats.drops++; + qstats_drop_inc(this_cpu_ptr(prog->common.cpu_qstats)); break; case TC_ACT_UNSPEC: action = prog->tcf_action; @@ -87,7 +86,6 @@ static int tcf_bpf(struct sk_buff *skb, const struct tc_action *act, break; } - spin_unlock(&prog->tcf_lock); return action; } @@ -263,7 +261,10 @@ static void tcf_bpf_prog_fill_cfg(const struct tcf_bpf *prog, struct tcf_bpf_cfg *cfg) { cfg->is_ebpf = tcf_bpf_is_ebpf(prog); - cfg->filter = prog->filter; + /* updates to prog->filter are prevented, since it's called either + * with rtnl lock or during final cleanup in rcu callback + */ + cfg->filter = rcu_dereference_protected(prog->filter, 1); cfg->bpf_ops = prog->bpf_ops; cfg->bpf_name = prog->bpf_name; @@ -294,7 +295,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, if (!tcf_hash_check(parm->index, act, bind)) { ret = tcf_hash_create(parm->index, est, act, - sizeof(*prog), bind, false); + sizeof(*prog), bind, true); if (ret < 0) return ret; @@ -325,7 +326,7 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, goto out; prog = to_bpf(act); - spin_lock_bh(&prog->tcf_lock); + ASSERT_RTNL(); if (res != ACT_P_CREATED) tcf_bpf_prog_fill_cfg(prog, &old); @@ -339,14 +340,15 @@ static int tcf_bpf_init(struct net *net, struct nlattr *nla, prog->bpf_fd = cfg.bpf_fd; prog->tcf_action = parm->action; - prog->filter = cfg.filter; - - spin_unlock_bh(&prog->tcf_lock); + rcu_assign_pointer(prog->filter, cfg.filter); - if (res == ACT_P_CREATED) + if (res == ACT_P_CREATED) { tcf_hash_insert(act); - else + } else { + /* make sure the program being replaced is no longer executing */ + synchronize_rcu(); tcf_bpf_cfg_cleanup(&old); + } return res; out: -- GitLab From 1afe839e6b31a85fc53adbf8757d6373908d414d Mon Sep 17 00:00:00 2001 From: Andreas Herz Date: Fri, 21 Aug 2015 11:31:32 +0200 Subject: [PATCH 5022/7006] netfilter: ip6t_REJECT: added missing icmpv6 codes RFC 4443 added two new codes values for ICMPv6 type 1: 5 - Source address failed ingress/egress policy 6 - Reject route to destination And RFC 7084 states in L-14 that IPv6 Router MUST send ICMPv6 Destination Unreachable with code 5 for packets forwarded to it that use an address from a prefix that has been invalidated. Codes 5 and 6 are more informative subsets of code 1. Signed-off-by: Andreas Herz Signed-off-by: Pablo Neira Ayuso --- include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h | 4 +++- net/ipv6/netfilter/ip6t_REJECT.c | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h b/include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h index 205ed62e4605d..cd2e940c8bf53 100644 --- a/include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h +++ b/include/uapi/linux/netfilter_ipv6/ip6t_REJECT.h @@ -10,7 +10,9 @@ enum ip6t_reject_with { IP6T_ICMP6_ADDR_UNREACH, IP6T_ICMP6_PORT_UNREACH, IP6T_ICMP6_ECHOREPLY, - IP6T_TCP_RESET + IP6T_TCP_RESET, + IP6T_ICMP6_POLICY_FAIL, + IP6T_ICMP6_REJECT_ROUTE }; struct ip6t_reject_info { diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 567367a751720..0ed841a3fa33a 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -63,6 +63,12 @@ reject_tg6(struct sk_buff *skb, const struct xt_action_param *par) case IP6T_TCP_RESET: nf_send_reset6(net, skb, par->hooknum); break; + case IP6T_ICMP6_POLICY_FAIL: + nf_send_unreach6(net, skb, ICMPV6_POLICY_FAIL, par->hooknum); + break; + case IP6T_ICMP6_REJECT_ROUTE: + nf_send_unreach6(net, skb, ICMPV6_REJECT_ROUTE, par->hooknum); + break; } return NF_DROP; -- GitLab From 19b2c30d3cce928010138cae4b9e57c388aa065c Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Wed, 26 Aug 2015 20:34:48 +0800 Subject: [PATCH 5023/7006] f2fs: update extent tree in batches This patch introduce a new helper f2fs_update_extent_tree_range which can do extent mapping update at a specified range. The main idea is: 1) punch all mapping info in extent node(s) which are at a specified range; 2) try to merge new extent mapping with adjacent node, or failing that, insert the mapping into extent tree as a new node. In order to see the benefit, I add a function for stating time stamping count as below: uint64_t rdtsc(void) { uint32_t lo, hi; __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); return (uint64_t)hi << 32 | lo; } My test environment is: ubuntu, intel i7-3770, 16G memory, 256g micron ssd. truncation path: update extent cache from truncate_data_blocks_range non-truncataion path: update extent cache from other paths total: all update paths a) Removing 128MB file which has one extent node mapping whole range of file: 1. dd if=/dev/zero of=/mnt/f2fs/128M bs=1M count=128 2. sync 3. rm /mnt/f2fs/128M Before: total count average truncation: 7651022 32768 233.49 Patched: total count average truncation: 3321 33 100.64 b) fsstress: fsstress -d /mnt/f2fs -l 5 -n 100 -p 20 Test times: 5 times. Before: total count average truncation: 5812480.6 20911.6 277.95 non-truncation: 7783845.6 13440.8 579.12 total: 13596326.2 34352.4 395.79 Patched: total count average truncation: 1281283.0 3041.6 421.25 non-truncation: 7355844.4 13662.8 538.38 total: 8637127.4 16704.4 517.06 1) For the updates in truncation path: - we can see updating in batches leads total tsc and update count reducing explicitly; - besides, for a single batched updating, punching multiple extent nodes in a loop, result in executing more operations, so our average tsc increase intensively. 2) For the updates in non-truncation path: - there is a little improvement, that is because for the scenario that we just need to update in the head or tail of extent node, new interface optimize to update info in extent node directly, rather than removing original extent node for updating and then inserting that updated one into cache as new node. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/extent_cache.c | 217 ++++++++++++++++++++++++++++++----------- fs/f2fs/f2fs.h | 2 + fs/f2fs/file.c | 12 ++- 3 files changed, 170 insertions(+), 61 deletions(-) diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index dcfeb43a59752..e6b245718ef0a 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -386,23 +386,21 @@ do_insert: return en; } -/* return true, if on-disk extent should be updated */ -static bool f2fs_update_extent_tree(struct inode *inode, pgoff_t fofs, - block_t blkaddr) +unsigned int f2fs_update_extent_tree_range(struct inode *inode, + pgoff_t fofs, block_t blkaddr, unsigned int len) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); struct extent_tree *et = F2FS_I(inode)->extent_tree; struct extent_node *en = NULL, *en1 = NULL, *en2 = NULL, *en3 = NULL; - struct extent_node *den = NULL, *prev_ex = NULL, *next_ex = NULL; + struct extent_node *prev_en = NULL, *next_en = NULL; struct extent_info ei, dei, prev; struct rb_node **insert_p = NULL, *insert_parent = NULL; - unsigned int endofs; + unsigned int end = fofs + len; + unsigned int pos = (unsigned int)fofs; if (!et) return false; - trace_f2fs_update_extent_tree(inode, fofs, blkaddr); - write_lock(&et->lock); if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) { @@ -416,39 +414,143 @@ static bool f2fs_update_extent_tree(struct inode *inode, pgoff_t fofs, /* we do not guarantee that the largest extent is cached all the time */ f2fs_drop_largest_extent(inode, fofs); - /* 1. lookup and remove existing extent info in cache */ - en = __lookup_extent_tree_ret(et, fofs, &prev_ex, &next_ex, + /* 1. lookup first extent node in range [fofs, fofs + len - 1] */ + en = __lookup_extent_tree_ret(et, fofs, &prev_en, &next_en, &insert_p, &insert_parent); - if (!en) - goto update_extent; - - dei = en->ei; - __detach_extent_node(sbi, et, en); - - /* 2. if extent can be split, try to split it */ - if (dei.len > F2FS_MIN_EXTENT_LEN) { - /* insert left part of split extent into cache */ - if (fofs - dei.fofs >= F2FS_MIN_EXTENT_LEN) { - set_extent_info(&ei, dei.fofs, dei.blk, - fofs - dei.fofs); - en1 = __insert_extent_tree(sbi, et, &ei, NULL, NULL); + if (!en) { + if (next_en) { + en = next_en; + f2fs_bug_on(sbi, en->ei.fofs <= pos); + pos = en->ei.fofs; + } else { + /* + * skip searching in the tree since there is no + * larger extent node in the cache. + */ + goto update_extent; + } + } + + /* 2. invlidate all extent nodes in range [fofs, fofs + len - 1] */ + while (en) { + struct rb_node *node; + + if (pos >= end) + break; + + dei = en->ei; + en1 = en2 = NULL; + + node = rb_next(&en->rb_node); + + /* + * 2.1 there are four cases when we invalidate blkaddr in extent + * node, |V: valid address, X: will be invalidated| + */ + /* case#1, invalidate right part of extent node |VVVVVXXXXX| */ + if (pos > dei.fofs && end >= dei.fofs + dei.len) { + en->ei.len = pos - dei.fofs; + + if (en->ei.len < F2FS_MIN_EXTENT_LEN) { + __detach_extent_node(sbi, et, en); + insert_p = NULL; + insert_parent = NULL; + goto update; + } + + if (__is_extent_same(&dei, &et->largest)) + et->largest = en->ei; + goto next; + } + + /* case#2, invalidate left part of extent node |XXXXXVVVVV| */ + if (pos <= dei.fofs && end < dei.fofs + dei.len) { + en->ei.fofs = end; + en->ei.blk += end - dei.fofs; + en->ei.len -= end - dei.fofs; + + if (en->ei.len < F2FS_MIN_EXTENT_LEN) { + __detach_extent_node(sbi, et, en); + insert_p = NULL; + insert_parent = NULL; + goto update; + } + + if (__is_extent_same(&dei, &et->largest)) + et->largest = en->ei; + goto next; } - /* insert right part of split extent into cache */ - endofs = dei.fofs + dei.len - 1; - if (endofs - fofs >= F2FS_MIN_EXTENT_LEN) { - set_extent_info(&ei, fofs + 1, - fofs - dei.fofs + dei.blk + 1, endofs - fofs); - en2 = __insert_extent_tree(sbi, et, &ei, NULL, NULL); + __detach_extent_node(sbi, et, en); + + /* + * if we remove node in rb-tree, our parent node pointer may + * point the wrong place, discard them. + */ + insert_p = NULL; + insert_parent = NULL; + + /* case#3, invalidate entire extent node |XXXXXXXXXX| */ + if (pos <= dei.fofs && end >= dei.fofs + dei.len) { + if (__is_extent_same(&dei, &et->largest)) + et->largest.len = 0; + goto update; + } + + /* + * case#4, invalidate data in the middle of extent node + * |VVVXXXXVVV| + */ + if (dei.len > F2FS_MIN_EXTENT_LEN) { + unsigned int endofs; + + /* insert left part of split extent into cache */ + if (pos - dei.fofs >= F2FS_MIN_EXTENT_LEN) { + set_extent_info(&ei, dei.fofs, dei.blk, + pos - dei.fofs); + en1 = __insert_extent_tree(sbi, et, &ei, + NULL, NULL); + } + + /* insert right part of split extent into cache */ + endofs = dei.fofs + dei.len; + if (endofs - end >= F2FS_MIN_EXTENT_LEN) { + set_extent_info(&ei, end, + end - dei.fofs + dei.blk, + endofs - end); + en2 = __insert_extent_tree(sbi, et, &ei, + NULL, NULL); + } } +update: + /* 2.2 update in global extent list */ + spin_lock(&sbi->extent_lock); + if (en && !list_empty(&en->list)) + list_del(&en->list); + if (en1) + list_add_tail(&en1->list, &sbi->extent_list); + if (en2) + list_add_tail(&en2->list, &sbi->extent_list); + spin_unlock(&sbi->extent_lock); + + /* 2.3 release extent node */ + if (en) + kmem_cache_free(extent_node_slab, en); +next: + en = node ? rb_entry(node, struct extent_node, rb_node) : NULL; + next_en = en; + if (en) + pos = en->ei.fofs; } update_extent: /* 3. update extent in extent cache */ if (blkaddr) { - set_extent_info(&ei, fofs, blkaddr, 1); + struct extent_node *den = NULL; + + set_extent_info(&ei, fofs, blkaddr, len); en3 = __try_merge_extent_node(sbi, et, &ei, &den, - prev_ex, next_ex); + prev_en, next_en); if (!en3) en3 = __insert_extent_tree(sbi, et, &ei, insert_p, insert_parent); @@ -460,36 +562,21 @@ update_extent: et->largest.len = 0; set_inode_flag(F2FS_I(inode), FI_NO_EXTENT); } - } - /* 4. update in global extent list */ - spin_lock(&sbi->extent_lock); - if (en && !list_empty(&en->list)) - list_del(&en->list); - /* - * en1 and en2 split from en, they will become more and more smaller - * fragments after splitting several times. So if the length is smaller - * than F2FS_MIN_EXTENT_LEN, we will not add them into extent tree. - */ - if (en1) - list_add_tail(&en1->list, &sbi->extent_list); - if (en2) - list_add_tail(&en2->list, &sbi->extent_list); - if (en3) { - if (list_empty(&en3->list)) - list_add_tail(&en3->list, &sbi->extent_list); - else - list_move_tail(&en3->list, &sbi->extent_list); - } - if (den && !list_empty(&den->list)) - list_del(&den->list); - spin_unlock(&sbi->extent_lock); + spin_lock(&sbi->extent_lock); + if (en3) { + if (list_empty(&en3->list)) + list_add_tail(&en3->list, &sbi->extent_list); + else + list_move_tail(&en3->list, &sbi->extent_list); + } + if (den && !list_empty(&den->list)) + list_del(&den->list); + spin_unlock(&sbi->extent_lock); - /* 5. release extent node */ - if (en) - kmem_cache_free(extent_node_slab, en); - if (den) - kmem_cache_free(extent_node_slab, den); + if (den) + kmem_cache_free(extent_node_slab, den); + } if (is_inode_flag_set(F2FS_I(inode), FI_NO_EXTENT)) __free_extent_tree(sbi, et, true); @@ -645,10 +732,22 @@ void f2fs_update_extent_cache(struct dnode_of_data *dn) f2fs_bug_on(F2FS_I_SB(dn->inode), dn->data_blkaddr == NEW_ADDR); + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), fi) + dn->ofs_in_node; - if (f2fs_update_extent_tree(dn->inode, fofs, dn->data_blkaddr)) + if (f2fs_update_extent_tree_range(dn->inode, fofs, dn->data_blkaddr, 1)) + sync_inode_page(dn); +} + +void f2fs_update_extent_cache_range(struct dnode_of_data *dn, + pgoff_t fofs, block_t blkaddr, unsigned int len) + +{ + if (!f2fs_may_extent_tree(dn->inode)) + return; + + if (f2fs_update_extent_tree_range(dn->inode, fofs, blkaddr, len)) sync_inode_page(dn); } diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h index 69827ee8a0eef..f1a90ffd7cad1 100644 --- a/fs/f2fs/f2fs.h +++ b/fs/f2fs/f2fs.h @@ -2017,6 +2017,8 @@ unsigned int f2fs_destroy_extent_node(struct inode *); void f2fs_destroy_extent_tree(struct inode *); bool f2fs_lookup_extent_cache(struct inode *, pgoff_t, struct extent_info *); void f2fs_update_extent_cache(struct dnode_of_data *); +void f2fs_update_extent_cache_range(struct dnode_of_data *dn, + pgoff_t, block_t, unsigned int); void init_extent_cache_info(struct f2fs_sb_info *); int __init create_extent_cache(void); void destroy_extent_cache(void); diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index 86a5c76eb106d..8120f86851419 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -445,9 +445,9 @@ static int f2fs_file_open(struct inode *inode, struct file *filp) int truncate_data_blocks_range(struct dnode_of_data *dn, int count) { - int nr_free = 0, ofs = dn->ofs_in_node; struct f2fs_sb_info *sbi = F2FS_I_SB(dn->inode); struct f2fs_node *raw_node; + int nr_free = 0, ofs = dn->ofs_in_node, len = count; __le32 *addr; raw_node = F2FS_NODE(dn->node_page); @@ -460,14 +460,22 @@ int truncate_data_blocks_range(struct dnode_of_data *dn, int count) dn->data_blkaddr = NULL_ADDR; set_data_blkaddr(dn); - f2fs_update_extent_cache(dn); invalidate_blocks(sbi, blkaddr); if (dn->ofs_in_node == 0 && IS_INODE(dn->node_page)) clear_inode_flag(F2FS_I(dn->inode), FI_FIRST_BLOCK_WRITTEN); nr_free++; } + if (nr_free) { + pgoff_t fofs; + /* + * once we invalidate valid blkaddr in range [ofs, ofs + count], + * we will invalidate all blkaddr in the whole range. + */ + fofs = start_bidx_of_node(ofs_of_node(dn->node_page), + F2FS_I(dn->inode)) + ofs; + f2fs_update_extent_cache_range(dn, fofs, 0, len); dec_valid_block_count(sbi, dn->inode, nr_free); set_page_dirty(dn->node_page); sync_inode_page(dn); -- GitLab From aa06e5c1f9c2b466712be904cc5b56a813e24cfd Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 26 Aug 2015 20:07:25 +0100 Subject: [PATCH 5024/7006] ARM: entry: get rid of multiple macro definitions The following structure is just asking for trouble: #ifdef CONFIG_symbol .macro foo ... .endm .macro bar ... .endm .macro baz ... .endm #else .macro foo ... .endm .macro bar ... .endm #ifdef CONFIG_symbol2 .macro baz ... .endm #else .macro baz ... .endm #endif #endif such as one defintion being updated, but the other definitions miss out. Where the contents of a macro needs to be conditional, the hint is in the first clause of this very sentence. "contents" "conditional". Not multiple separate definitions, especially not when much of the macro is the same between different configs. This patch fixes this bad style, which had caused the Thumb2 code to miss-out on the uaccess updates. Signed-off-by: Russell King --- arch/arm/kernel/entry-header.S | 109 +++++++++++++-------------------- 1 file changed, 44 insertions(+), 65 deletions(-) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 1a0045abead75..d47b5161b029e 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -196,7 +196,7 @@ msr cpsr_c, \rtemp @ switch back to the SVC mode .endm -#ifndef CONFIG_THUMB2_KERNEL + .macro svc_exit, rpsr, irq = 0 .if \irq != 0 @ IRQs already off @@ -215,6 +215,9 @@ blne trace_hardirqs_off #endif .endif + +#ifndef CONFIG_THUMB2_KERNEL + @ ARM mode SVC restore msr spsr_cxsf, \rpsr #if defined(CONFIG_CPU_V6) || defined(CONFIG_CPU_32v6K) @ We must avoid clrex due to Cortex-A15 erratum #830321 @@ -222,6 +225,20 @@ strex r1, r2, [r0] @ clear the exclusive monitor #endif ldmia sp, {r0 - pc}^ @ load r0 - pc, cpsr +#else + @ Thumb mode SVC restore + ldr lr, [sp, #S_SP] @ top of the stack + ldrd r0, r1, [sp, #S_LR] @ calling lr and pc + + @ We must avoid clrex due to Cortex-A15 erratum #830321 + strex r2, r1, [sp, #S_LR] @ clear the exclusive monitor + + stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context + ldmia sp, {r0 - r12} + mov sp, lr + ldr lr, [sp], #4 + rfeia sp! +#endif .endm @ @@ -241,6 +258,8 @@ @ on the stack remains correct). @ .macro svc_exit_via_fiq +#ifndef CONFIG_THUMB2_KERNEL + @ ARM mode restore mov r0, sp ldmib r0, {r1 - r14} @ abort is deadly from here onward (it will @ clobber state restored below) @@ -250,9 +269,26 @@ msr spsr_cxsf, r9 ldr r0, [r0, #S_R0] ldmia r8, {pc}^ +#else + @ Thumb mode restore + add r0, sp, #S_R2 + ldr lr, [sp, #S_LR] + ldr sp, [sp, #S_SP] @ abort is deadly from here onward (it will + @ clobber state restored below) + ldmia r0, {r2 - r12} + mov r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT + msr cpsr_c, r1 + sub r0, #S_R2 + add r8, r0, #S_PC + ldmia r0, {r0 - r1} + rfeia r8 +#endif .endm + .macro restore_user_regs, fast = 0, offset = 0 +#ifndef CONFIG_THUMB2_KERNEL + @ ARM mode restore mov r2, sp ldr r1, [r2, #\offset + S_PSR] @ get calling cpsr ldr lr, [r2, #\offset + S_PC]! @ get pc @@ -270,72 +306,16 @@ @ after ldm {}^ add sp, sp, #\offset + S_FRAME_SIZE movs pc, lr @ return & move spsr_svc into cpsr - .endm - -#else /* CONFIG_THUMB2_KERNEL */ - .macro svc_exit, rpsr, irq = 0 - .if \irq != 0 - @ IRQs already off -#ifdef CONFIG_TRACE_IRQFLAGS - @ The parent context IRQs must have been enabled to get here in - @ the first place, so there's no point checking the PSR I bit. - bl trace_hardirqs_on -#endif - .else - @ IRQs off again before pulling preserved data off the stack - disable_irq_notrace -#ifdef CONFIG_TRACE_IRQFLAGS - tst \rpsr, #PSR_I_BIT - bleq trace_hardirqs_on - tst \rpsr, #PSR_I_BIT - blne trace_hardirqs_off -#endif - .endif - ldr lr, [sp, #S_SP] @ top of the stack - ldrd r0, r1, [sp, #S_LR] @ calling lr and pc - - @ We must avoid clrex due to Cortex-A15 erratum #830321 - strex r2, r1, [sp, #S_LR] @ clear the exclusive monitor - - stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context - ldmia sp, {r0 - r12} - mov sp, lr - ldr lr, [sp], #4 - rfeia sp! - .endm - - @ - @ svc_exit_via_fiq - like svc_exit but switches to FIQ mode before exit - @ - @ For full details see non-Thumb implementation above. - @ - .macro svc_exit_via_fiq - add r0, sp, #S_R2 - ldr lr, [sp, #S_LR] - ldr sp, [sp, #S_SP] @ abort is deadly from here onward (it will - @ clobber state restored below) - ldmia r0, {r2 - r12} - mov r1, #FIQ_MODE | PSR_I_BIT | PSR_F_BIT - msr cpsr_c, r1 - sub r0, #S_R2 - add r8, r0, #S_PC - ldmia r0, {r0 - r1} - rfeia r8 - .endm - -#ifdef CONFIG_CPU_V7M - /* - * Note we don't need to do clrex here as clearing the local monitor is - * part of each exception entry and exit sequence. - */ - .macro restore_user_regs, fast = 0, offset = 0 +#elif defined(CONFIG_CPU_V7M) + @ V7M restore. + @ Note that we don't need to do clrex here as clearing the local + @ monitor is part of the exception entry and exit sequence. .if \offset add sp, #\offset .endif v7m_exception_slow_exit ret_r0 = \fast - .endm -#else /* ifdef CONFIG_CPU_V7M */ - .macro restore_user_regs, fast = 0, offset = 0 +#else + @ Thumb mode restore mov r2, sp load_user_sp_lr r2, r3, \offset + S_SP @ calling sp, lr ldr r1, [sp, #\offset + S_PSR] @ get calling cpsr @@ -353,9 +333,8 @@ .endif add sp, sp, #S_FRAME_SIZE - S_SP movs pc, lr @ return & move spsr_svc into cpsr - .endm -#endif /* ifdef CONFIG_CPU_V7M / else */ #endif /* !CONFIG_THUMB2_KERNEL */ + .endm /* * Context tracking subsystem. Used to instrument transitions -- GitLab From 2190fed67ba6f3e8129513929f2395843645e928 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 20 Aug 2015 10:32:02 +0100 Subject: [PATCH 5025/7006] ARM: entry: provide uaccess assembly macro hooks Provide hooks into the kernel entry and exit paths to permit control of userspace visibility to the kernel. The intended use is: - on entry to kernel from user, uaccess_disable will be called to disable userspace visibility - on exit from kernel to user, uaccess_enable will be called to enable userspace visibility - on entry from a kernel exception, uaccess_save_and_disable will be called to save the current userspace visibility setting, and disable access - on exit from a kernel exception, uaccess_restore will be called to restore the userspace visibility as it was before the exception occurred. These hooks allows us to keep userspace visibility disabled for the vast majority of the kernel, except for localised regions where we want to explicitly access userspace. Signed-off-by: Russell King --- arch/arm/include/asm/assembler.h | 17 +++++++++++++++++ arch/arm/kernel/entry-armv.S | 30 ++++++++++++++++++++++-------- arch/arm/kernel/entry-common.S | 2 ++ arch/arm/kernel/entry-header.S | 3 +++ arch/arm/mm/abort-ev4.S | 1 + arch/arm/mm/abort-ev5t.S | 1 + arch/arm/mm/abort-ev5tj.S | 1 + arch/arm/mm/abort-ev6.S | 7 ++++--- arch/arm/mm/abort-ev7.S | 1 + arch/arm/mm/abort-lv4t.S | 2 ++ arch/arm/mm/abort-macro.S | 1 + 11 files changed, 55 insertions(+), 11 deletions(-) diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index 4abe57279c66f..a911770434673 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -445,6 +445,23 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm + .macro uaccess_disable, tmp, isb=1 + .endm + + .macro uaccess_enable, tmp, isb=1 + .endm + + .macro uaccess_save, tmp + .endm + + .macro uaccess_restore + .endm + + .macro uaccess_save_and_disable, tmp + uaccess_save \tmp + uaccess_disable \tmp + .endm + .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo .macro ret\c, reg #if __LINUX_ARM_ARCH__ < 6 diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S index d19adcf6c580c..61f00a3f30476 100644 --- a/arch/arm/kernel/entry-armv.S +++ b/arch/arm/kernel/entry-armv.S @@ -149,10 +149,10 @@ ENDPROC(__und_invalid) #define SPFIX(code...) #endif - .macro svc_entry, stack_hole=0, trace=1 + .macro svc_entry, stack_hole=0, trace=1, uaccess=1 UNWIND(.fnstart ) UNWIND(.save {r0 - pc} ) - sub sp, sp, #(S_FRAME_SIZE + \stack_hole - 4) + sub sp, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4) #ifdef CONFIG_THUMB2_KERNEL SPFIX( str r0, [sp] ) @ temporarily saved SPFIX( mov r0, sp ) @@ -167,7 +167,7 @@ ENDPROC(__und_invalid) ldmia r0, {r3 - r5} add r7, sp, #S_SP - 4 @ here for interlock avoidance mov r6, #-1 @ "" "" "" "" - add r2, sp, #(S_FRAME_SIZE + \stack_hole - 4) + add r2, sp, #(S_FRAME_SIZE + 8 + \stack_hole - 4) SPFIX( addeq r2, r2, #4 ) str r3, [sp, #-4]! @ save the "real" r0 copied @ from the exception stack @@ -185,6 +185,11 @@ ENDPROC(__und_invalid) @ stmia r7, {r2 - r6} + uaccess_save r0 + .if \uaccess + uaccess_disable r0 + .endif + .if \trace #ifdef CONFIG_TRACE_IRQFLAGS bl trace_hardirqs_off @@ -194,7 +199,7 @@ ENDPROC(__und_invalid) .align 5 __dabt_svc: - svc_entry + svc_entry uaccess=0 mov r2, sp dabt_helper THUMB( ldr r5, [sp, #S_PSR] ) @ potentially updated CPSR @@ -368,7 +373,7 @@ ENDPROC(__fiq_abt) #error "sizeof(struct pt_regs) must be a multiple of 8" #endif - .macro usr_entry, trace=1 + .macro usr_entry, trace=1, uaccess=1 UNWIND(.fnstart ) UNWIND(.cantunwind ) @ don't unwind the user space sub sp, sp, #S_FRAME_SIZE @@ -400,6 +405,10 @@ ENDPROC(__fiq_abt) ARM( stmdb r0, {sp, lr}^ ) THUMB( store_user_sp_lr r0, r1, S_SP - S_PC ) + .if \uaccess + uaccess_disable ip + .endif + @ Enable the alignment trap while in kernel mode ATRAP( teq r8, r7) ATRAP( mcrne p15, 0, r8, c1, c0, 0) @@ -435,7 +444,7 @@ ENDPROC(__fiq_abt) .align 5 __dabt_usr: - usr_entry + usr_entry uaccess=0 kuser_cmpxchg_check mov r2, sp dabt_helper @@ -458,7 +467,7 @@ ENDPROC(__irq_usr) .align 5 __und_usr: - usr_entry + usr_entry uaccess=0 mov r2, r4 mov r3, r5 @@ -484,6 +493,8 @@ __und_usr: 1: ldrt r0, [r4] ARM_BE8(rev r0, r0) @ little endian instruction + uaccess_disable ip + @ r0 = 32-bit ARM instruction which caused the exception @ r2 = PC value for the following instruction (:= regs->ARM_pc) @ r4 = PC value for the faulting instruction @@ -518,9 +529,10 @@ __und_usr_thumb: 2: ldrht r5, [r4] ARM_BE8(rev16 r5, r5) @ little endian instruction cmp r5, #0xe800 @ 32bit instruction if xx != 0 - blo __und_usr_fault_16 @ 16bit undefined instruction + blo __und_usr_fault_16_pan @ 16bit undefined instruction 3: ldrht r0, [r2] ARM_BE8(rev16 r0, r0) @ little endian instruction + uaccess_disable ip add r2, r2, #2 @ r2 is PC + 2, make it PC + 4 str r2, [sp, #S_PC] @ it's a 2x16bit instr, update orr r0, r0, r5, lsl #16 @@ -715,6 +727,8 @@ ENDPROC(no_fp) __und_usr_fault_32: mov r1, #4 b 1f +__und_usr_fault_16_pan: + uaccess_disable ip __und_usr_fault_16: mov r1, #2 1: mov r0, sp diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index 92828a1dec80c..1891549807036 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S @@ -173,6 +173,8 @@ ENTRY(vector_swi) USER( ldr scno, [lr, #-4] ) @ get SWI instruction #endif + uaccess_disable tbl + adr tbl, sys_call_table @ load syscall table pointer #if defined(CONFIG_OABI_COMPAT) diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index d47b5161b029e..0d22ad206d523 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S @@ -215,6 +215,7 @@ blne trace_hardirqs_off #endif .endif + uaccess_restore #ifndef CONFIG_THUMB2_KERNEL @ ARM mode SVC restore @@ -258,6 +259,7 @@ @ on the stack remains correct). @ .macro svc_exit_via_fiq + uaccess_restore #ifndef CONFIG_THUMB2_KERNEL @ ARM mode restore mov r0, sp @@ -287,6 +289,7 @@ .macro restore_user_regs, fast = 0, offset = 0 + uaccess_enable r1, isb=0 #ifndef CONFIG_THUMB2_KERNEL @ ARM mode restore mov r2, sp diff --git a/arch/arm/mm/abort-ev4.S b/arch/arm/mm/abort-ev4.S index 54473cd4aba95..b3b31e30cadd2 100644 --- a/arch/arm/mm/abort-ev4.S +++ b/arch/arm/mm/abort-ev4.S @@ -19,6 +19,7 @@ ENTRY(v4_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR ldr r3, [r4] @ read aborted ARM instruction + uaccess_disable ip @ disable userspace access bic r1, r1, #1 << 11 | 1 << 10 @ clear bits 11 and 10 of FSR tst r3, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. diff --git a/arch/arm/mm/abort-ev5t.S b/arch/arm/mm/abort-ev5t.S index c913031b79ccb..a6a381a6caa5a 100644 --- a/arch/arm/mm/abort-ev5t.S +++ b/arch/arm/mm/abort-ev5t.S @@ -21,6 +21,7 @@ ENTRY(v5t_early_abort) mrc p15, 0, r0, c6, c0, 0 @ get FAR do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 ldreq r3, [r4] @ read aborted ARM instruction + uaccess_disable ip @ disable user access bic r1, r1, #1 << 11 @ clear bits 11 of FSR teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? beq do_DataAbort @ yes diff --git a/arch/arm/mm/abort-ev5tj.S b/arch/arm/mm/abort-ev5tj.S index 1b80d71adb0ff..00ab011bef584 100644 --- a/arch/arm/mm/abort-ev5tj.S +++ b/arch/arm/mm/abort-ev5tj.S @@ -24,6 +24,7 @@ ENTRY(v5tj_early_abort) bne do_DataAbort do_thumb_abort fsr=r1, pc=r4, psr=r5, tmp=r3 ldreq r3, [r4] @ read aborted ARM instruction + uaccess_disable ip @ disable userspace access teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? beq do_DataAbort @ yes tst r3, #1 << 20 @ L = 0 -> write diff --git a/arch/arm/mm/abort-ev6.S b/arch/arm/mm/abort-ev6.S index 113704f30e9f8..8801a15aa1059 100644 --- a/arch/arm/mm/abort-ev6.S +++ b/arch/arm/mm/abort-ev6.S @@ -26,17 +26,18 @@ ENTRY(v6_early_abort) ldr ip, =0x4107b36 mrc p15, 0, r3, c0, c0, 0 @ get processor id teq ip, r3, lsr #4 @ r0 ARM1136? - bne do_DataAbort + bne 1f tst r5, #PSR_J_BIT @ Java? tsteq r5, #PSR_T_BIT @ Thumb? - bne do_DataAbort + bne 1f bic r1, r1, #1 << 11 @ clear bit 11 of FSR ldr r3, [r4] @ read aborted ARM instruction ARM_BE8(rev r3, r3) teq_ldrd tmp=ip, insn=r3 @ insn was LDRD? - beq do_DataAbort @ yes + beq 1f @ yes tst r3, #1 << 20 @ L = 0 -> write orreq r1, r1, #1 << 11 @ yes. #endif +1: uaccess_disable ip @ disable userspace access b do_DataAbort diff --git a/arch/arm/mm/abort-ev7.S b/arch/arm/mm/abort-ev7.S index 4812ad0542145..e8d0e08c227fc 100644 --- a/arch/arm/mm/abort-ev7.S +++ b/arch/arm/mm/abort-ev7.S @@ -15,6 +15,7 @@ ENTRY(v7_early_abort) mrc p15, 0, r1, c5, c0, 0 @ get FSR mrc p15, 0, r0, c6, c0, 0 @ get FAR + uaccess_disable ip @ disable userspace access /* * V6 code adjusts the returned DFSR. diff --git a/arch/arm/mm/abort-lv4t.S b/arch/arm/mm/abort-lv4t.S index f3982580c2730..6d8e8e3365d17 100644 --- a/arch/arm/mm/abort-lv4t.S +++ b/arch/arm/mm/abort-lv4t.S @@ -26,6 +26,7 @@ ENTRY(v4t_late_abort) #endif bne .data_thumb_abort ldr r8, [r4] @ read arm instruction + uaccess_disable ip @ disable userspace access tst r8, #1 << 20 @ L = 1 -> write? orreq r1, r1, #1 << 11 @ yes. and r7, r8, #15 << 24 @@ -155,6 +156,7 @@ ENTRY(v4t_late_abort) .data_thumb_abort: ldrh r8, [r4] @ read instruction + uaccess_disable ip @ disable userspace access tst r8, #1 << 11 @ L = 1 -> write? orreq r1, r1, #1 << 8 @ yes and r7, r8, #15 << 12 diff --git a/arch/arm/mm/abort-macro.S b/arch/arm/mm/abort-macro.S index 50d6c0a900b14..4509bee4e081c 100644 --- a/arch/arm/mm/abort-macro.S +++ b/arch/arm/mm/abort-macro.S @@ -13,6 +13,7 @@ tst \psr, #PSR_T_BIT beq not_thumb ldrh \tmp, [\pc] @ Read aborted Thumb instruction + uaccess_disable ip @ disable userspace access and \tmp, \tmp, # 0xfe00 @ Mask opcode field cmp \tmp, # 0x5600 @ Is it ldrsb? orreq \tmp, \tmp, #1 << 11 @ Set L-bit if yes -- GitLab From a5e090acbf545c0a3b04080f8a488b17ec41fe02 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 19 Aug 2015 20:40:41 +0100 Subject: [PATCH 5026/7006] ARM: software-based priviledged-no-access support Provide a software-based implementation of the priviledged no access support found in ARMv8.1. Userspace pages are mapped using a different domain number from the kernel and IO mappings. If we switch the user domain to "no access" when we enter the kernel, we can prevent the kernel from touching userspace. However, the kernel needs to be able to access userspace via the various user accessor functions. With the wrapping in the previous patch, we can temporarily enable access when the kernel needs user access, and re-disable it afterwards. This allows us to trap non-intended accesses to userspace, eg, caused by an inadvertent dereference of the LIST_POISON* values, which, with appropriate user mappings setup, can be made to succeed. This in turn can allow use-after-free bugs to be further exploited than would otherwise be possible. Signed-off-by: Russell King --- arch/arm/Kconfig | 15 +++++++++++++ arch/arm/include/asm/assembler.h | 30 +++++++++++++++++++++++++ arch/arm/include/asm/domain.h | 21 +++++++++++++++-- arch/arm/include/asm/uaccess.h | 14 ++++++++++++ arch/arm/kernel/process.c | 36 +++++++++++++++++++++++++----- arch/arm/kernel/swp_emulate.c | 3 +++ arch/arm/lib/csumpartialcopyuser.S | 14 ++++++++++++ 7 files changed, 125 insertions(+), 8 deletions(-) diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index a750c1425c3a6..e15d5ed4d5f16 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -1694,6 +1694,21 @@ config HIGHPTE bool "Allocate 2nd-level pagetables from highmem" depends on HIGHMEM +config CPU_SW_DOMAIN_PAN + bool "Enable use of CPU domains to implement privileged no-access" + depends on MMU && !ARM_LPAE + default y + help + Increase kernel security by ensuring that normal kernel accesses + are unable to access userspace addresses. This can help prevent + use-after-free bugs becoming an exploitable privilege escalation + by ensuring that magic values (such as LIST_POISON) will always + fault when dereferenced. + + CPUs with low-vector mappings use a best-efforts implementation. + Their lower 1MB needs to remain accessible for the vectors, but + the remainder of userspace will become appropriately inaccessible. + config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" depends on PERF_EVENTS diff --git a/arch/arm/include/asm/assembler.h b/arch/arm/include/asm/assembler.h index a911770434673..3ae0eda5e64fb 100644 --- a/arch/arm/include/asm/assembler.h +++ b/arch/arm/include/asm/assembler.h @@ -446,15 +446,45 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) .endm .macro uaccess_disable, tmp, isb=1 +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + /* + * Whenever we re-enter userspace, the domains should always be + * set appropriately. + */ + mov \tmp, #DACR_UACCESS_DISABLE + mcr p15, 0, \tmp, c3, c0, 0 @ Set domain register + .if \isb + instr_sync + .endif +#endif .endm .macro uaccess_enable, tmp, isb=1 +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + /* + * Whenever we re-enter userspace, the domains should always be + * set appropriately. + */ + mov \tmp, #DACR_UACCESS_ENABLE + mcr p15, 0, \tmp, c3, c0, 0 + .if \isb + instr_sync + .endif +#endif .endm .macro uaccess_save, tmp +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + mrc p15, 0, \tmp, c3, c0, 0 + str \tmp, [sp, #S_FRAME_SIZE] +#endif .endm .macro uaccess_restore +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + ldr r0, [sp, #S_FRAME_SIZE] + mcr p15, 0, r0, c3, c0, 0 +#endif .endm .macro uaccess_save_and_disable, tmp diff --git a/arch/arm/include/asm/domain.h b/arch/arm/include/asm/domain.h index 2be929549938e..e878129f2fee5 100644 --- a/arch/arm/include/asm/domain.h +++ b/arch/arm/include/asm/domain.h @@ -57,11 +57,29 @@ #define domain_mask(dom) ((3) << (2 * (dom))) #define domain_val(dom,type) ((type) << (2 * (dom))) +#ifdef CONFIG_CPU_SW_DOMAIN_PAN +#define DACR_INIT \ + (domain_val(DOMAIN_USER, DOMAIN_NOACCESS) | \ + domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ + domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ + domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) +#else #define DACR_INIT \ (domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) +#endif + +#define __DACR_DEFAULT \ + domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT) | \ + domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ + domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT) + +#define DACR_UACCESS_DISABLE \ + (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) +#define DACR_UACCESS_ENABLE \ + (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_CLIENT)) #ifndef __ASSEMBLY__ @@ -76,7 +94,6 @@ static inline unsigned int get_domain(void) return domain; } -#ifdef CONFIG_CPU_USE_DOMAINS static inline void set_domain(unsigned val) { asm volatile( @@ -85,6 +102,7 @@ static inline void set_domain(unsigned val) isb(); } +#ifdef CONFIG_CPU_USE_DOMAINS #define modify_domain(dom,type) \ do { \ unsigned int domain = get_domain(); \ @@ -94,7 +112,6 @@ static inline void set_domain(unsigned val) } while (0) #else -static inline void set_domain(unsigned val) { } static inline void modify_domain(unsigned dom, unsigned type) { } #endif diff --git a/arch/arm/include/asm/uaccess.h b/arch/arm/include/asm/uaccess.h index 82880132f941a..01bae13b2cea0 100644 --- a/arch/arm/include/asm/uaccess.h +++ b/arch/arm/include/asm/uaccess.h @@ -57,11 +57,25 @@ extern int fixup_exception(struct pt_regs *regs); */ static inline unsigned int uaccess_save_and_enable(void) { +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + unsigned int old_domain = get_domain(); + + /* Set the current domain access to permit user accesses */ + set_domain((old_domain & ~domain_mask(DOMAIN_USER)) | + domain_val(DOMAIN_USER, DOMAIN_CLIENT)); + + return old_domain; +#else return 0; +#endif } static inline void uaccess_restore(unsigned int flags) { +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + /* Restore the user access mask */ + set_domain(flags); +#endif } /* diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c index e722f9b3c9b10..3f18098dfd080 100644 --- a/arch/arm/kernel/process.c +++ b/arch/arm/kernel/process.c @@ -129,12 +129,36 @@ void __show_regs(struct pt_regs *regs) buf[4] = '\0'; #ifndef CONFIG_CPU_V7M - printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", - buf, interrupts_enabled(regs) ? "n" : "ff", - fast_interrupts_enabled(regs) ? "n" : "ff", - processor_modes[processor_mode(regs)], - isa_modes[isa_mode(regs)], - get_fs() == get_ds() ? "kernel" : "user"); + { + unsigned int domain = get_domain(); + const char *segment; + +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + /* + * Get the domain register for the parent context. In user + * mode, we don't save the DACR, so lets use what it should + * be. For other modes, we place it after the pt_regs struct. + */ + if (user_mode(regs)) + domain = DACR_UACCESS_ENABLE; + else + domain = *(unsigned int *)(regs + 1); +#endif + + if ((domain & domain_mask(DOMAIN_USER)) == + domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) + segment = "none"; + else if (get_fs() == get_ds()) + segment = "kernel"; + else + segment = "user"; + + printk("Flags: %s IRQs o%s FIQs o%s Mode %s ISA %s Segment %s\n", + buf, interrupts_enabled(regs) ? "n" : "ff", + fast_interrupts_enabled(regs) ? "n" : "ff", + processor_modes[processor_mode(regs)], + isa_modes[isa_mode(regs)], segment); + } #else printk("xPSR: %08lx\n", regs->ARM_cpsr); #endif diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index 1361756782c73..5b26e7efa9ea4 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -141,11 +141,14 @@ static int emulate_swpX(unsigned int address, unsigned int *data, while (1) { unsigned long temp; + unsigned int __ua_flags; + __ua_flags = uaccess_save_and_enable(); if (type == TYPE_SWPB) __user_swpb_asm(*data, address, res, temp); else __user_swp_asm(*data, address, res, temp); + uaccess_restore(__ua_flags); if (likely(res != -EAGAIN) || signal_pending(current)) break; diff --git a/arch/arm/lib/csumpartialcopyuser.S b/arch/arm/lib/csumpartialcopyuser.S index 1d0957e61f898..1712f132b80d2 100644 --- a/arch/arm/lib/csumpartialcopyuser.S +++ b/arch/arm/lib/csumpartialcopyuser.S @@ -17,6 +17,19 @@ .text +#ifdef CONFIG_CPU_SW_DOMAIN_PAN + .macro save_regs + mrc p15, 0, ip, c3, c0, 0 + stmfd sp!, {r1, r2, r4 - r8, ip, lr} + uaccess_enable ip + .endm + + .macro load_regs + ldmfd sp!, {r1, r2, r4 - r8, ip, lr} + mcr p15, 0, ip, c3, c0, 0 + ret lr + .endm +#else .macro save_regs stmfd sp!, {r1, r2, r4 - r8, lr} .endm @@ -24,6 +37,7 @@ .macro load_regs ldmfd sp!, {r1, r2, r4 - r8, pc} .endm +#endif .macro load1b, reg1 ldrusr \reg1, r0, 1 -- GitLab From 66bc2f51ef7deabc8b8f3baa98ae64b65e5e973a Mon Sep 17 00:00:00 2001 From: Stefan Assmann Date: Wed, 26 Aug 2015 13:11:49 -0700 Subject: [PATCH 5027/7006] Input: psmouse - add small delay for IBM trackpoint pass-through mode There are trackpoint devices that fail to respond to the PS2 command PSMOUSE_CMD_GETID if immediately queried after the parent device is deactivated. Add a small delay for the hardware to get in a sane state before sending any PS2 commands. One example of such a system is: Lenovo ThinkPad X120e, model 30515QG synaptics: Touchpad model: 1, fw: 8.0, id: 0x1e2b1, caps: 0xd001a3/0x940300/0x121c00, board id: 1811, fw id: 797391 Signed-off-by: Stefan Assmann Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index ec34770361501..ad18dab0ac476 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -1540,6 +1540,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) if (error) goto err_clear_drvdata; + /* give PT device some time to settle down before probing */ + if (serio->id.type == SERIO_PS_PSTHRU) + usleep_range(10000, 15000); + if (psmouse_probe(psmouse) < 0) { error = -ENODEV; goto err_close_serio; -- GitLab From ecbb44e8f81b860ef279b0f176a878da9ebd614e Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 10 Jul 2015 19:35:56 -0400 Subject: [PATCH 5028/7006] i40e: don't degrade __le16 Sparse cries when we compare an __le16 to a u16, almost like it cares about architectures other than x86. Weird. Use the le16_to_cpu macro to make it stop crying. Change-ID: Id068f4d7868a2d3df234a791a76d15938f37db35 Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 ++ drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 3bb832a2ec51a..ded62eb3204fc 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1255,6 +1255,8 @@ struct i40e_mac_filter *i40e_put_mac_in_vlan(struct i40e_vsi *vsi, u8 *macaddr, struct i40e_mac_filter *f; list_for_each_entry(f, &vsi->mac_filter_list, list) { + if (vsi->info.pvid) + f->vlan = le16_to_cpu(vsi->info.pvid); if (!i40e_find_filter(vsi, macaddr, f->vlan, is_vf, is_netdev)) { if (!i40e_add_filter(vsi, macaddr, f->vlan, diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 8a7607c6e142d..70a6fb14f6dea 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -2106,11 +2106,12 @@ int i40e_ndo_set_vf_port_vlan(struct net_device *netdev, goto error_pvid; } - if (vsi->info.pvid == (vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT))) + if (le16_to_cpu(vsi->info.pvid) == + (vlan_id | (qos << I40E_VLAN_PRIORITY_SHIFT))) /* duplicate request, so just return success */ goto error_pvid; - if (vsi->info.pvid == 0 && i40e_is_vsi_in_vlan(vsi)) { + if (le16_to_cpu(vsi->info.pvid) == 0 && i40e_is_vsi_in_vlan(vsi)) { dev_err(&pf->pdev->dev, "VF %d has already configured VLAN filters and the administrator is requesting a port VLAN override.\nPlease unload and reload the VF driver for this change to take effect.\n", vf_id); -- GitLab From 9f7c94487197df9aaca172027419af57e5dc7d6f Mon Sep 17 00:00:00 2001 From: Shannon Nelson Date: Fri, 10 Jul 2015 19:35:57 -0400 Subject: [PATCH 5029/7006] i40e: add RX to port CRC errors label The port.crc_errors is really an RX counter, so let's mark it as such. Change-ID: I179afd3f8a95d45229bb4163a6aeb01f0d2d250b Signed-off-by: Shannon Nelson Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 83d41c2cb02d4..d6c7eb75baf3a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -114,7 +114,7 @@ static struct i40e_stats i40e_gstrings_stats[] = { I40E_PF_STAT("tx_errors", stats.eth.tx_errors), I40E_PF_STAT("rx_dropped", stats.eth.rx_discards), I40E_PF_STAT("tx_dropped_link_down", stats.tx_dropped_link_down), - I40E_PF_STAT("crc_errors", stats.crc_errors), + I40E_PF_STAT("rx_crc_errors", stats.crc_errors), I40E_PF_STAT("illegal_bytes", stats.illegal_bytes), I40E_PF_STAT("mac_local_faults", stats.mac_local_faults), I40E_PF_STAT("mac_remote_faults", stats.mac_remote_faults), -- GitLab From 02b42498f383a6c24f7c751d4fe89a911a249242 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Fri, 10 Jul 2015 19:35:59 -0400 Subject: [PATCH 5030/7006] i40e: Move function calls to i40e_shutdown instead of i40e_suspend We should be stopping the service task and flow director on shutdown not on suspension. Signed-off-by: Catherine Sullivan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index ded62eb3204fc..07bfe61e5f719 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -10450,6 +10450,19 @@ static void i40e_shutdown(struct pci_dev *pdev) wr32(hw, I40E_PFPM_APM, (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0)); wr32(hw, I40E_PFPM_WUFC, (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); + del_timer_sync(&pf->service_timer); + cancel_work_sync(&pf->service_task); + i40e_fdir_teardown(pf); + + rtnl_lock(); + i40e_prep_for_reset(pf); + rtnl_unlock(); + + wr32(hw, I40E_PFPM_APM, + (pf->wol_en ? I40E_PFPM_APM_APME_MASK : 0)); + wr32(hw, I40E_PFPM_WUFC, + (pf->wol_en ? I40E_PFPM_WUFC_MAG_MASK : 0)); + i40e_clear_interrupt_scheme(pf); if (system_state == SYSTEM_POWER_OFF) { @@ -10470,9 +10483,6 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state) set_bit(__I40E_SUSPENDED, &pf->state); set_bit(__I40E_DOWN, &pf->state); - del_timer_sync(&pf->service_timer); - cancel_work_sync(&pf->service_task); - i40e_fdir_teardown(pf); rtnl_lock(); i40e_prep_for_reset(pf); -- GitLab From 113cd9dacbad4906e1c8db09233b9fdcb002f80d Mon Sep 17 00:00:00 2001 From: Junwei Zhang Date: Wed, 26 Aug 2015 09:34:59 +0800 Subject: [PATCH 5031/7006] drm/amdgpu: adjust the judgement of removing fence callback The fence in the array may be skipped if wait_all is false, thus the related callback is not initialized with list head. So removing this kind callback will cause NULL pointer reference. Signed-off-by: Junwei Zhang Reviewed-by: Jammy Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index 9787337a65a10..f446bf2fedc99 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -966,7 +966,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, fence_rm_cb: for (idx = 0; idx < count; ++idx) { fence = array[idx]; - if (fence) + if (fence && cb[idx].base.func) fence_remove_callback(fence, &cb[idx].base); } -- GitLab From c7ae72c01be10f539f385f624713f8ba0aa11a8f Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Tue, 25 Aug 2015 17:23:45 +0800 Subject: [PATCH 5032/7006] drm/amdgpu: use IB for copy buffer of eviction This aids handling buffers moves with the scheduler. Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 8 +- drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c | 8 +- drivers/gpu/drm/amd/amdgpu/amdgpu_test.c | 12 +-- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 77 ++++++++++--------- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 3 +- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 16 ++-- drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 18 ++--- drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 18 ++--- 8 files changed, 81 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index c9160430b5acd..aa2dcf578dd6d 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -247,7 +247,7 @@ struct amdgpu_buffer_funcs { unsigned copy_num_dw; /* used for buffer migration */ - void (*emit_copy_buffer)(struct amdgpu_ring *ring, + void (*emit_copy_buffer)(struct amdgpu_ib *ib, /* src addr in bytes */ uint64_t src_offset, /* dst addr in bytes */ @@ -518,7 +518,7 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t dst_offset, uint32_t byte_count, struct reservation_object *resv, - struct amdgpu_fence **fence); + struct fence **fence); int amdgpu_mmap(struct file *filp, struct vm_area_struct *vma); struct amdgpu_bo_list_entry { @@ -2247,7 +2247,7 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v) #define amdgpu_display_add_connector(adev, ci, sd, ct, ib, coi, h, r) (adev)->mode_info.funcs->add_connector((adev), (ci), (sd), (ct), (ib), (coi), (h), (r)) #define amdgpu_display_stop_mc_access(adev, s) (adev)->mode_info.funcs->stop_mc_access((adev), (s)) #define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s)) -#define amdgpu_emit_copy_buffer(adev, r, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((r), (s), (d), (b)) +#define amdgpu_emit_copy_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((ib), (s), (d), (b)) #define amdgpu_emit_fill_buffer(adev, r, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((r), (s), (d), (b)) #define amdgpu_dpm_get_temperature(adev) (adev)->pm.funcs->get_temperature((adev)) #define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev)) @@ -2379,7 +2379,7 @@ int amdgpu_vm_bo_unmap(struct amdgpu_device *adev, uint64_t addr); void amdgpu_vm_bo_rmv(struct amdgpu_device *adev, struct amdgpu_bo_va *bo_va); - +int amdgpu_vm_free_job(struct amdgpu_job *job); /* * functions used by amdgpu_encoder.c */ diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c index 759482e4300d1..98d59ee640cef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_benchmark.c @@ -33,7 +33,7 @@ static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size, { unsigned long start_jiffies; unsigned long end_jiffies; - struct amdgpu_fence *fence = NULL; + struct fence *fence = NULL; int i, r; start_jiffies = jiffies; @@ -42,17 +42,17 @@ static int amdgpu_benchmark_do_move(struct amdgpu_device *adev, unsigned size, r = amdgpu_copy_buffer(ring, saddr, daddr, size, NULL, &fence); if (r) goto exit_do_move; - r = fence_wait(&fence->base, false); + r = fence_wait(fence, false); if (r) goto exit_do_move; - amdgpu_fence_unref(&fence); + fence_put(fence); } end_jiffies = jiffies; r = jiffies_to_msecs(end_jiffies - start_jiffies); exit_do_move: if (fence) - amdgpu_fence_unref(&fence); + fence_put(fence); return r; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c index 962dd55521375..f80b1a43be8a5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_test.c @@ -77,7 +77,7 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) void *gtt_map, *vram_map; void **gtt_start, **gtt_end; void **vram_start, **vram_end; - struct amdgpu_fence *fence = NULL; + struct fence *fence = NULL; r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_GTT, 0, NULL, gtt_obj + i); @@ -116,13 +116,13 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) goto out_lclean_unpin; } - r = fence_wait(&fence->base, false); + r = fence_wait(fence, false); if (r) { DRM_ERROR("Failed to wait for GTT->VRAM fence %d\n", i); goto out_lclean_unpin; } - amdgpu_fence_unref(&fence); + fence_put(fence); r = amdgpu_bo_kmap(vram_obj, &vram_map); if (r) { @@ -161,13 +161,13 @@ static void amdgpu_do_test_moves(struct amdgpu_device *adev) goto out_lclean_unpin; } - r = fence_wait(&fence->base, false); + r = fence_wait(fence, false); if (r) { DRM_ERROR("Failed to wait for VRAM->GTT fence %d\n", i); goto out_lclean_unpin; } - amdgpu_fence_unref(&fence); + fence_put(fence); r = amdgpu_bo_kmap(gtt_obj[i], >t_map); if (r) { @@ -214,7 +214,7 @@ out_lclean: amdgpu_bo_unref(>t_obj[i]); } if (fence) - amdgpu_fence_unref(&fence); + fence_put(fence); break; } diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 4cb81320b0451..399143541d8a2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -228,7 +228,7 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, struct amdgpu_device *adev; struct amdgpu_ring *ring; uint64_t old_start, new_start; - struct amdgpu_fence *fence; + struct fence *fence; int r; adev = amdgpu_get_adev(bo->bdev); @@ -269,9 +269,9 @@ static int amdgpu_move_blit(struct ttm_buffer_object *bo, new_mem->num_pages * PAGE_SIZE, /* bytes */ bo->resv, &fence); /* FIXME: handle copy error */ - r = ttm_bo_move_accel_cleanup(bo, &fence->base, + r = ttm_bo_move_accel_cleanup(bo, fence, evict, no_wait_gpu, new_mem); - amdgpu_fence_unref(&fence); + fence_put(fence); return r; } @@ -987,52 +987,48 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, uint64_t dst_offset, uint32_t byte_count, struct reservation_object *resv, - struct amdgpu_fence **fence) + struct fence **fence) { struct amdgpu_device *adev = ring->adev; - struct amdgpu_sync sync; uint32_t max_bytes; unsigned num_loops, num_dw; + struct amdgpu_ib *ib; unsigned i; int r; - /* sync other rings */ - amdgpu_sync_create(&sync); - if (resv) { - r = amdgpu_sync_resv(adev, &sync, resv, false); - if (r) { - DRM_ERROR("sync failed (%d).\n", r); - amdgpu_sync_free(adev, &sync, NULL); - return r; - } - } - max_bytes = adev->mman.buffer_funcs->copy_max_bytes; num_loops = DIV_ROUND_UP(byte_count, max_bytes); num_dw = num_loops * adev->mman.buffer_funcs->copy_num_dw; - /* for fence and sync */ - num_dw += 64 + AMDGPU_NUM_SYNCS * 8; + /* for IB padding */ + while (num_dw & 0x7) + num_dw++; + + ib = kzalloc(sizeof(struct amdgpu_ib), GFP_KERNEL); + if (!ib) + return -ENOMEM; - r = amdgpu_sync_wait(&sync); + r = amdgpu_ib_get(ring, NULL, num_dw * 4, ib); if (r) { - DRM_ERROR("sync wait failed (%d).\n", r); - amdgpu_sync_free(adev, &sync, NULL); + kfree(ib); return r; } - r = amdgpu_ring_lock(ring, num_dw); - if (r) { - DRM_ERROR("ring lock failed (%d).\n", r); - amdgpu_sync_free(adev, &sync, NULL); - return r; + ib->length_dw = 0; + + if (resv) { + r = amdgpu_sync_resv(adev, &ib->sync, resv, + AMDGPU_FENCE_OWNER_UNDEFINED); + if (r) { + DRM_ERROR("sync failed (%d).\n", r); + goto error_free; + } } - amdgpu_sync_rings(&sync, ring); for (i = 0; i < num_loops; i++) { uint32_t cur_size_in_bytes = min(byte_count, max_bytes); - amdgpu_emit_copy_buffer(adev, ring, src_offset, dst_offset, + amdgpu_emit_copy_buffer(adev, ib, src_offset, dst_offset, cur_size_in_bytes); src_offset += cur_size_in_bytes; @@ -1040,17 +1036,24 @@ int amdgpu_copy_buffer(struct amdgpu_ring *ring, byte_count -= cur_size_in_bytes; } - r = amdgpu_fence_emit(ring, AMDGPU_FENCE_OWNER_MOVE, fence); - if (r) { - amdgpu_ring_unlock_undo(ring); - amdgpu_sync_free(adev, &sync, NULL); - return r; - } - - amdgpu_ring_unlock_commit(ring); - amdgpu_sync_free(adev, &sync, &(*fence)->base); + amdgpu_vm_pad_ib(adev, ib); + WARN_ON(ib->length_dw > num_dw); + r = amdgpu_sched_ib_submit_kernel_helper(adev, ring, ib, 1, + &amdgpu_vm_free_job, + AMDGPU_FENCE_OWNER_MOVE, + fence); + if (r) + goto error_free; + if (!amdgpu_enable_scheduler) { + amdgpu_ib_free(adev, ib); + kfree(ib); + } return 0; +error_free: + amdgpu_ib_free(adev, ib); + kfree(ib); + return r; } #if defined(CONFIG_DEBUG_FS) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 677266b90c749..83b7ce6f5f72a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -316,8 +316,7 @@ static void amdgpu_vm_update_pages(struct amdgpu_device *adev, } } -static int amdgpu_vm_free_job( - struct amdgpu_job *sched_job) +int amdgpu_vm_free_job(struct amdgpu_job *sched_job) { int i; for (i = 0; i < sched_job->num_ibs; i++) diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index af526557ac663..3920c1e346f8e 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -1339,18 +1339,18 @@ static void cik_sdma_set_irq_funcs(struct amdgpu_device *adev) * Used by the amdgpu ttm implementation to move pages if * registered as the asic copy callback. */ -static void cik_sdma_emit_copy_buffer(struct amdgpu_ring *ring, +static void cik_sdma_emit_copy_buffer(struct amdgpu_ib *ib, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count) { - amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0)); - amdgpu_ring_write(ring, byte_count); - amdgpu_ring_write(ring, 0); /* src/dst endian swap */ - amdgpu_ring_write(ring, lower_32_bits(src_offset)); - amdgpu_ring_write(ring, upper_32_bits(src_offset)); - amdgpu_ring_write(ring, lower_32_bits(dst_offset)); - amdgpu_ring_write(ring, upper_32_bits(dst_offset)); + ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_COPY, SDMA_COPY_SUB_OPCODE_LINEAR, 0); + ib->ptr[ib->length_dw++] = byte_count; + ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ + ib->ptr[ib->length_dw++] = lower_32_bits(src_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(src_offset); + ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 2b0e89e05b1df..715e02d3bfbac 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -1350,19 +1350,19 @@ static void sdma_v2_4_set_irq_funcs(struct amdgpu_device *adev) * Used by the amdgpu ttm implementation to move pages if * registered as the asic copy callback. */ -static void sdma_v2_4_emit_copy_buffer(struct amdgpu_ring *ring, +static void sdma_v2_4_emit_copy_buffer(struct amdgpu_ib *ib, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count) { - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | - SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR)); - amdgpu_ring_write(ring, byte_count); - amdgpu_ring_write(ring, 0); /* src/dst endian swap */ - amdgpu_ring_write(ring, lower_32_bits(src_offset)); - amdgpu_ring_write(ring, upper_32_bits(src_offset)); - amdgpu_ring_write(ring, lower_32_bits(dst_offset)); - amdgpu_ring_write(ring, upper_32_bits(dst_offset)); + ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | + SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); + ib->ptr[ib->length_dw++] = byte_count; + ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ + ib->ptr[ib->length_dw++] = lower_32_bits(src_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(src_offset); + ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); } /** diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 6f1df03ebc704..67128c8e78b84 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1474,19 +1474,19 @@ static void sdma_v3_0_set_irq_funcs(struct amdgpu_device *adev) * Used by the amdgpu ttm implementation to move pages if * registered as the asic copy callback. */ -static void sdma_v3_0_emit_copy_buffer(struct amdgpu_ring *ring, +static void sdma_v3_0_emit_copy_buffer(struct amdgpu_ib *ib, uint64_t src_offset, uint64_t dst_offset, uint32_t byte_count) { - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | - SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR)); - amdgpu_ring_write(ring, byte_count); - amdgpu_ring_write(ring, 0); /* src/dst endian swap */ - amdgpu_ring_write(ring, lower_32_bits(src_offset)); - amdgpu_ring_write(ring, upper_32_bits(src_offset)); - amdgpu_ring_write(ring, lower_32_bits(dst_offset)); - amdgpu_ring_write(ring, upper_32_bits(dst_offset)); + ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_COPY) | + SDMA_PKT_HEADER_SUB_OP(SDMA_SUBOP_COPY_LINEAR); + ib->ptr[ib->length_dw++] = byte_count; + ib->ptr[ib->length_dw++] = 0; /* src/dst endian swap */ + ib->ptr[ib->length_dw++] = lower_32_bits(src_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(src_offset); + ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); } /** -- GitLab From 26cdc443fd8fccccdfb17fd2845cf9233a995325 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 10 Jul 2015 19:36:00 -0400 Subject: [PATCH 5033/7006] i40e: Fix legacy interrupt mode in the driver This patch fixes the driver flow to take into account legacy interrupts. Over time we added code that assumes MSIX is the only mode that the driver runs in. It also enables a legacy workaround to trigger SWINT when the TX ring has non-cache aligned descriptors pending and interrupts are disabled. We work with a single vector in MSI mode too, so apply the same restrictions as Legacy. Change-ID: I826ddff1f9bd45d2dbe11f56a3ddcef0dbf42563 Signed-off-by: Anjali Singhai Jain Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 07bfe61e5f719..481f427cedd92 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1550,7 +1550,10 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, * vectors available and so we need to lower the used * q count. */ - qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix); + if (pf->flags & I40E_FLAG_MSIX_ENABLED) + qcount = min_t(int, vsi->alloc_queue_pairs, pf->num_lan_msix); + else + qcount = vsi->alloc_queue_pairs; num_tc_qps = qcount / numtc; num_tc_qps = min_t(int, num_tc_qps, i40e_pf_get_max_q_per_tc(pf)); @@ -1614,7 +1617,7 @@ static void i40e_vsi_setup_queue_map(struct i40e_vsi *vsi, if ((vsi->type == I40E_VSI_MAIN) && (numtc == 1)) { if (vsi->req_queue_pairs > 0) vsi->num_queue_pairs = vsi->req_queue_pairs; - else + else if (pf->flags & I40E_FLAG_MSIX_ENABLED) vsi->num_queue_pairs = pf->num_lan_msix; } @@ -3416,7 +3419,7 @@ static irqreturn_t i40e_fdir_clean_ring(int irq, void *data) * @v_idx: vector index * @qp_idx: queue pair index **/ -static void map_vector_to_qp(struct i40e_vsi *vsi, int v_idx, int qp_idx) +static void i40e_map_vector_to_qp(struct i40e_vsi *vsi, int v_idx, int qp_idx) { struct i40e_q_vector *q_vector = vsi->q_vectors[v_idx]; struct i40e_ring *tx_ring = vsi->tx_rings[qp_idx]; @@ -3470,7 +3473,7 @@ static void i40e_vsi_map_rings_to_vectors(struct i40e_vsi *vsi) q_vector->tx.ring = NULL; while (num_ringpairs--) { - map_vector_to_qp(vsi, v_start, qp_idx); + i40e_map_vector_to_qp(vsi, v_start, qp_idx); qp_idx++; qp_remaining--; } @@ -8798,6 +8801,11 @@ static int i40e_vsi_setup_vectors(struct i40e_vsi *vsi) goto vector_setup_out; } + /* In Legacy mode, we do not have to get any other vector since we + * piggyback on the misc/ICR0 for queue interrupts. + */ + if (!(pf->flags & I40E_FLAG_MSIX_ENABLED)) + return ret; if (vsi->num_q_vectors) vsi->base_vector = i40e_get_lump(pf, pf->irq_pile, vsi->num_q_vectors, vsi->idx); -- GitLab From 02537d63623ce5281c20d76f1b61797a7836acf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 25 Aug 2015 15:05:20 +0200 Subject: [PATCH 5034/7006] drm/amdgpu: fix postclose order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The context needs to finish before everything else. Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c index 87da6b1848fdf..22367939ebf1a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c @@ -560,6 +560,8 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, if (!fpriv) return; + amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr); + amdgpu_vm_fini(adev, &fpriv->vm); idr_for_each_entry(&fpriv->bo_list_handles, list, handle) @@ -568,8 +570,6 @@ void amdgpu_driver_postclose_kms(struct drm_device *dev, idr_destroy(&fpriv->bo_list_handles); mutex_destroy(&fpriv->bo_list_lock); - amdgpu_ctx_mgr_fini(&fpriv->ctx_mgr); - kfree(fpriv); file_priv->driver_priv = NULL; } -- GitLab From 062c7fb3ebb42d2a50d4644b3e49e731361e6951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 21 Aug 2015 15:46:43 +0200 Subject: [PATCH 5035/7006] drm/amdgpu: remove entity idle timeout v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removing the entity from scheduling can deadlock the whole system. Wait forever till the remaining IBs are scheduled. v2: fix comment as well Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou (v1) --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 18 +++++------------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 6 ++---- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2df6f174ba7b1..ca22d90324779 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -167,32 +167,24 @@ static bool amd_sched_entity_is_idle(struct amd_sched_entity *entity) * @sched Pointer to scheduler instance * @entity The pointer to a valid scheduler entity * - * return 0 if succeed. negative error code on failure + * Cleanup and free the allocated resources. */ -int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity) +void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, + struct amd_sched_entity *entity) { struct amd_sched_rq *rq = entity->belongto_rq; - long r; if (!amd_sched_entity_is_initialized(sched, entity)) - return 0; + return; /** * The client will not queue more IBs during this fini, consume existing * queued IBs */ - r = wait_event_timeout(entity->wait_queue, - amd_sched_entity_is_idle(entity), - msecs_to_jiffies(AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS)); - - if (r <= 0) - DRM_INFO("Entity %p is in waiting state during fini\n", - entity); + wait_event(entity->wait_queue, amd_sched_entity_is_idle(entity)); amd_sched_rq_remove_entity(rq, entity); kfifo_free(&entity->job_queue); - return r; } /** diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 44909b16c3a3a..128f908c60216 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -27,8 +27,6 @@ #include #include -#define AMD_GPU_WAIT_IDLE_TIMEOUT_IN_MS 3000 - struct amd_gpu_scheduler; struct amd_sched_rq; @@ -124,8 +122,8 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, struct amd_sched_entity *entity, struct amd_sched_rq *rq, uint32_t jobs); -int amd_sched_entity_fini(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity); +void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, + struct amd_sched_entity *entity); int amd_sched_entity_push_job(struct amd_sched_job *sched_job); struct amd_sched_fence *amd_sched_fence_create( -- GitLab From 88079006dc412c5d1676f9f6e9c4d72a209eb556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 24 Aug 2015 14:29:40 +0200 Subject: [PATCH 5036/7006] drm/amdgpu: wake up scheduler only when neccessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index ca22d90324779..4145365576730 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -27,6 +27,8 @@ #include #include "gpu_scheduler.h" +static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); + /* Initialize a given run queue struct */ static void amd_sched_rq_init(struct amd_sched_rq *rq) { @@ -209,7 +211,7 @@ static bool amd_sched_entity_in(struct amd_sched_job *job) /* first job wakes up scheduler */ if (first) - wake_up_interruptible(&job->sched->wait_queue); + amd_sched_wakeup(job->sched); return added; } @@ -249,6 +251,15 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) sched->hw_submission_limit; } +/** + * Wake up the scheduler when it is ready + */ +static void amd_sched_wakeup(struct amd_gpu_scheduler *sched) +{ + if (amd_sched_ready(sched)) + wake_up_interruptible(&sched->wait_queue); +} + /** * Select next entity containing real IB submissions */ -- GitLab From 510efb2682b35790b2274639ab985fe385bb526a Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 10 Jul 2015 19:36:01 -0400 Subject: [PATCH 5037/7006] i40e: Fix ethtool offline diagnostic with netqueues Treat netqueues the same way we do virtual functions when someone wants to run the ethtool offline diagnostic test. Change-ID: Id48d2b933f1fd0db7be06305a93c6ebe3dc821f5 Signed-off-by: Greg Rose Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40e/i40e_ethtool.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index d6c7eb75baf3a..230d1270bfaae 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1559,6 +1559,21 @@ static inline bool i40e_active_vfs(struct i40e_pf *pf) return false; } +static inline bool i40e_active_vmdqs(struct i40e_pf *pf) +{ + struct i40e_vsi **vsi = pf->vsi; + int i; + + for (i = 0; i < pf->num_alloc_vsi; i++) { + if (!vsi[i]) + continue; + if (vsi[i]->type == I40E_VSI_VMDQ2) + return true; + } + + return false; +} + static void i40e_diag_test(struct net_device *netdev, struct ethtool_test *eth_test, u64 *data) { @@ -1572,9 +1587,9 @@ static void i40e_diag_test(struct net_device *netdev, set_bit(__I40E_TESTING, &pf->state); - if (i40e_active_vfs(pf)) { + if (i40e_active_vfs(pf) || i40e_active_vmdqs(pf)) { dev_warn(&pf->pdev->dev, - "Please take active VFS offline and restart the adapter before running NIC diagnostics\n"); + "Please take active VFs and Netqueues offline and restart the adapter before running NIC diagnostics\n"); data[I40E_ETH_TEST_REG] = 1; data[I40E_ETH_TEST_EEPROM] = 1; data[I40E_ETH_TEST_INTR] = 1; -- GitLab From bd755d08709f05a81104e8f81d721b5cc353a2b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Mon, 24 Aug 2015 14:57:26 +0200 Subject: [PATCH 5038/7006] drm/amdgpu: remove extra parameters from scheduler callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Christian König Acked-by: Alex Deucher Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 11 ++++------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 4 ++-- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 7 ++----- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index 757058d539f4b..f93fb35414884 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -27,13 +27,11 @@ #include #include "amdgpu.h" -static struct fence *amdgpu_sched_run_job(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *entity, - struct amd_sched_job *job) +static struct fence *amdgpu_sched_run_job(struct amd_sched_job *job) { - int r = 0; struct amdgpu_job *sched_job; struct amdgpu_fence *fence; + int r; if (!job) { DRM_ERROR("job is null\n"); @@ -58,12 +56,11 @@ static struct fence *amdgpu_sched_run_job(struct amd_gpu_scheduler *sched, err: DRM_ERROR("Run job error\n"); mutex_unlock(&sched_job->job_lock); - sched->ops->process_job(sched, (struct amd_sched_job *)sched_job); + job->sched->ops->process_job(job); return NULL; } -static void amdgpu_sched_process_job(struct amd_gpu_scheduler *sched, - struct amd_sched_job *job) +static void amdgpu_sched_process_job(struct amd_sched_job *job) { struct amdgpu_job *sched_job; diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 4145365576730..6dfbdea85e874 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -289,7 +289,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) amd_sched_fence_signal(sched_job->s_fence); atomic_dec(&sched->hw_rq_count); fence_put(&sched_job->s_fence->base); - sched->ops->process_job(sched, sched_job); + sched->ops->process_job(sched_job); wake_up_interruptible(&sched->wait_queue); } @@ -318,7 +318,7 @@ static int amd_sched_main(void *param) continue; atomic_inc(&sched->hw_rq_count); - fence = sched->ops->run_job(sched, c_entity, job); + fence = sched->ops->run_job(job); if (fence) { r = fence_add_callback(fence, &job->cb, amd_sched_process_job); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 128f908c60216..13349a6a00af1 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -90,11 +90,8 @@ static inline struct amd_sched_fence *to_amd_sched_fence(struct fence *f) * these functions should be implemented in driver side */ struct amd_sched_backend_ops { - struct fence *(*run_job)(struct amd_gpu_scheduler *sched, - struct amd_sched_entity *c_entity, - struct amd_sched_job *job); - void (*process_job)(struct amd_gpu_scheduler *sched, - struct amd_sched_job *job); + struct fence *(*run_job)(struct amd_sched_job *job); + void (*process_job)(struct amd_sched_job *job); }; /** -- GitLab From c2b6bd7e91aad8440a2f55bdbde6f5a8ae19fac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 25 Aug 2015 21:39:31 +0200 Subject: [PATCH 5039/7006] drm/amdgpu: fix wait queue handling in the scheduler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Freeing up a queue after signalling it isn't race free. Signed-off-by: Christian König Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 16 ++++++++-------- drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 6dfbdea85e874..d99fe90991dc4 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -117,7 +117,6 @@ int amd_sched_entity_init(struct amd_gpu_scheduler *sched, memset(entity, 0, sizeof(struct amd_sched_entity)); entity->belongto_rq = rq; entity->scheduler = sched; - init_waitqueue_head(&entity->wait_queue); entity->fence_context = fence_context_alloc(1); if(kfifo_alloc(&entity->job_queue, jobs * sizeof(void *), @@ -183,7 +182,7 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, * The client will not queue more IBs during this fini, consume existing * queued IBs */ - wait_event(entity->wait_queue, amd_sched_entity_is_idle(entity)); + wait_event(sched->job_scheduled, amd_sched_entity_is_idle(entity)); amd_sched_rq_remove_entity(rq, entity); kfifo_free(&entity->job_queue); @@ -236,7 +235,7 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job) fence_get(&fence->base); sched_job->s_fence = fence; - r = wait_event_interruptible(entity->wait_queue, + r = wait_event_interruptible(entity->scheduler->job_scheduled, amd_sched_entity_in(sched_job)); return r; @@ -257,7 +256,7 @@ static bool amd_sched_ready(struct amd_gpu_scheduler *sched) static void amd_sched_wakeup(struct amd_gpu_scheduler *sched) { if (amd_sched_ready(sched)) - wake_up_interruptible(&sched->wait_queue); + wake_up_interruptible(&sched->wake_up_worker); } /** @@ -290,7 +289,7 @@ static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) atomic_dec(&sched->hw_rq_count); fence_put(&sched_job->s_fence->base); sched->ops->process_job(sched_job); - wake_up_interruptible(&sched->wait_queue); + wake_up_interruptible(&sched->wake_up_worker); } static int amd_sched_main(void *param) @@ -306,7 +305,7 @@ static int amd_sched_main(void *param) struct amd_sched_job *job; struct fence *fence; - wait_event_interruptible(sched->wait_queue, + wait_event_interruptible(sched->wake_up_worker, kthread_should_stop() || (c_entity = amd_sched_select_context(sched))); @@ -329,7 +328,7 @@ static int amd_sched_main(void *param) fence_put(fence); } - wake_up(&c_entity->wait_queue); + wake_up(&sched->job_scheduled); } return 0; } @@ -361,7 +360,8 @@ struct amd_gpu_scheduler *amd_sched_create(struct amd_sched_backend_ops *ops, amd_sched_rq_init(&sched->sched_rq); amd_sched_rq_init(&sched->kernel_rq); - init_waitqueue_head(&sched->wait_queue); + init_waitqueue_head(&sched->wake_up_worker); + init_waitqueue_head(&sched->job_scheduled); atomic_set(&sched->hw_rq_count, 0); /* Each scheduler will run on a seperate kernel thread */ sched->thread = kthread_run(amd_sched_main, sched, sched->name); diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index 13349a6a00af1..e797796dcad75 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -44,7 +44,6 @@ struct amd_sched_entity { struct kfifo job_queue; spinlock_t queue_lock; struct amd_gpu_scheduler *scheduler; - wait_queue_head_t wait_queue; uint64_t fence_context; }; @@ -104,7 +103,8 @@ struct amd_gpu_scheduler { atomic_t hw_rq_count; struct amd_sched_backend_ops *ops; uint32_t ring_id; - wait_queue_head_t wait_queue; + wait_queue_head_t wake_up_worker; + wait_queue_head_t job_scheduled; uint32_t hw_submission_limit; char name[20]; void *priv; -- GitLab From fe860afb4638f5e62e7d861bfc35a1580fb633bb Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Fri, 10 Jul 2015 19:36:02 -0400 Subject: [PATCH 5040/7006] i40e/i40evf: Add capability to gather VEB per TC stats This patch adds capability to update per VEB per TC statistics and dump it via ethtool. It also adds a structure to hold VEB per TC statistics. The fields can be filled by reading the GLVEBTC_* counters. Change-ID: I28b4759b9ab6ad5a61f046a1bc9ef6b16fe31538 Signed-off-by: Neerav Parikh Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 2 ++ .../net/ethernet/intel/i40e/i40e_ethtool.c | 23 ++++++++++++++- drivers/net/ethernet/intel/i40e/i40e_main.c | 28 ++++++++++++++++++- drivers/net/ethernet/intel/i40e/i40e_type.h | 8 ++++++ drivers/net/ethernet/intel/i40evf/i40e_type.h | 8 ++++++ 5 files changed, 67 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 0f97883c14930..05df21c16c790 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -442,6 +442,8 @@ struct i40e_veb { bool stat_offsets_loaded; struct i40e_eth_stats stats; struct i40e_eth_stats stats_offsets; + struct i40e_veb_tc_stats tc_stats; + struct i40e_veb_tc_stats tc_stats_offsets; }; /* struct that defines a VSI, associated with a dev */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 230d1270bfaae..74c16a1851588 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -197,7 +197,14 @@ static const struct i40e_stats i40e_gstrings_fcoe_stats[] = { FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_tx) + \ FIELD_SIZEOF(struct i40e_pf, stats.priority_xon_2_xoff)) \ / sizeof(u64)) +#define I40E_VEB_TC_STATS_LEN ( \ + (FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_rx_packets) + \ + FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_rx_bytes) + \ + FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_tx_packets) + \ + FIELD_SIZEOF(struct i40e_veb, tc_stats.tc_tx_bytes)) \ + / sizeof(u64)) #define I40E_VEB_STATS_LEN ARRAY_SIZE(i40e_gstrings_veb_stats) +#define I40E_VEB_STATS_TOTAL (I40E_VEB_STATS_LEN + I40E_VEB_TC_STATS_LEN) #define I40E_PF_STATS_LEN(n) (I40E_GLOBAL_STATS_LEN + \ I40E_PFC_STATS_LEN + \ I40E_VSI_STATS_LEN((n))) @@ -1257,7 +1264,7 @@ static int i40e_get_sset_count(struct net_device *netdev, int sset) int len = I40E_PF_STATS_LEN(netdev); if (pf->lan_veb != I40E_NO_VEB) - len += I40E_VEB_STATS_LEN; + len += I40E_VEB_STATS_TOTAL; return len; } else { return I40E_VSI_STATS_LEN(netdev); @@ -1408,6 +1415,20 @@ static void i40e_get_strings(struct net_device *netdev, u32 stringset, i40e_gstrings_veb_stats[i].stat_string); p += ETH_GSTRING_LEN; } + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + snprintf(p, ETH_GSTRING_LEN, + "veb.tc_%u_tx_packets", i); + p += ETH_GSTRING_LEN; + snprintf(p, ETH_GSTRING_LEN, + "veb.tc_%u_tx_bytes", i); + p += ETH_GSTRING_LEN; + snprintf(p, ETH_GSTRING_LEN, + "veb.tc_%u_rx_packets", i); + p += ETH_GSTRING_LEN; + snprintf(p, ETH_GSTRING_LEN, + "veb.tc_%u_rx_bytes", i); + p += ETH_GSTRING_LEN; + } } for (i = 0; i < I40E_GLOBAL_STATS_LEN; i++) { snprintf(p, ETH_GSTRING_LEN, "port.%s", diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 481f427cedd92..c0bfb557bed64 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -624,11 +624,15 @@ static void i40e_update_veb_stats(struct i40e_veb *veb) struct i40e_hw *hw = &pf->hw; struct i40e_eth_stats *oes; struct i40e_eth_stats *es; /* device's eth stats */ - int idx = 0; + struct i40e_veb_tc_stats *veb_oes; + struct i40e_veb_tc_stats *veb_es; + int i, idx = 0; idx = veb->stats_idx; es = &veb->stats; oes = &veb->stats_offsets; + veb_es = &veb->tc_stats; + veb_oes = &veb->tc_stats_offsets; /* Gather up the stats that the hw collects */ i40e_stat_update32(hw, I40E_GLSW_TDPC(idx), @@ -664,6 +668,28 @@ static void i40e_update_veb_stats(struct i40e_veb *veb) i40e_stat_update48(hw, I40E_GLSW_BPTCH(idx), I40E_GLSW_BPTCL(idx), veb->stat_offsets_loaded, &oes->tx_broadcast, &es->tx_broadcast); + for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) { + i40e_stat_update48(hw, I40E_GLVEBTC_RPCH(i, idx), + I40E_GLVEBTC_RPCL(i, idx), + veb->stat_offsets_loaded, + &veb_oes->tc_rx_packets[i], + &veb_es->tc_rx_packets[i]); + i40e_stat_update48(hw, I40E_GLVEBTC_RBCH(i, idx), + I40E_GLVEBTC_RBCL(i, idx), + veb->stat_offsets_loaded, + &veb_oes->tc_rx_bytes[i], + &veb_es->tc_rx_bytes[i]); + i40e_stat_update48(hw, I40E_GLVEBTC_TPCH(i, idx), + I40E_GLVEBTC_TPCL(i, idx), + veb->stat_offsets_loaded, + &veb_oes->tc_tx_packets[i], + &veb_es->tc_tx_packets[i]); + i40e_stat_update48(hw, I40E_GLVEBTC_TBCH(i, idx), + I40E_GLVEBTC_TBCL(i, idx), + veb->stat_offsets_loaded, + &veb_oes->tc_tx_bytes[i], + &veb_es->tc_tx_bytes[i]); + } veb->stat_offsets_loaded = true; } diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index 61b6b114b4bc2..acb2aad54b48b 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -1105,6 +1105,14 @@ struct i40e_eth_stats { u64 tx_errors; /* tepc */ }; +/* Statistics collected per VEB per TC */ +struct i40e_veb_tc_stats { + u64 tc_rx_packets[I40E_MAX_TRAFFIC_CLASS]; + u64 tc_rx_bytes[I40E_MAX_TRAFFIC_CLASS]; + u64 tc_tx_packets[I40E_MAX_TRAFFIC_CLASS]; + u64 tc_tx_bytes[I40E_MAX_TRAFFIC_CLASS]; +}; + #ifdef I40E_FCOE /* Statistics collected per function for FCoE */ struct i40e_fcoe_stats { diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index e32dc0b3616dc..1ab2498d68df2 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -1095,6 +1095,14 @@ struct i40e_eth_stats { u64 tx_errors; /* tepc */ }; +/* Statistics collected per VEB per TC */ +struct i40e_veb_tc_stats { + u64 tc_rx_packets[I40E_MAX_TRAFFIC_CLASS]; + u64 tc_rx_bytes[I40E_MAX_TRAFFIC_CLASS]; + u64 tc_tx_packets[I40E_MAX_TRAFFIC_CLASS]; + u64 tc_tx_bytes[I40E_MAX_TRAFFIC_CLASS]; +}; + /* Statistics collected by the MAC */ struct i40e_hw_port_stats { /* eth stats collected by the port */ -- GitLab From b4e53f02d7356809acbab673e6c20773cf56dbd6 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 10 Jul 2015 19:36:03 -0400 Subject: [PATCH 5041/7006] i40e: Fix comment for ethtool diagnostic link test The existing comment is incorrect. Add new comment to point out that the PF reset does not affect link but if the reset is changed to a different type that does affect link then the link test would need to be moved to before the reset. Change-ID: I28d786f46e9465860babdee61c1dba51016464df Reported-by: Jeremiah Kyle Signed-off-by: Greg Rose Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 74c16a1851588..62824f5c82669 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -1626,11 +1626,13 @@ static void i40e_diag_test(struct net_device *netdev, /* indicate we're in test mode */ dev_close(netdev); else + /* This reset does not affect link - if it is + * changed to a type of reset that does affect + * link then the following link test would have + * to be moved to before the reset + */ i40e_do_reset(pf, BIT(__I40E_PF_RESET_REQUESTED)); - /* Link test performed before hardware reset - * so autoneg doesn't interfere with test result - */ if (i40e_link_test(netdev, &data[I40E_ETH_TEST_LINK])) eth_test->flags |= ETH_TEST_FL_FAILED; -- GitLab From cd494fb4c2ba56dd9bb3919dc55565c2cc1551b6 Mon Sep 17 00:00:00 2001 From: Mitch Williams Date: Fri, 10 Jul 2015 19:36:04 -0400 Subject: [PATCH 5042/7006] i40e: correct spelling error Turns out that 'inavlid' is an inavlid spelling for 'invalid'. Change-ID: Ie1fe2d0f8d1ba75ab880594875ec2e4152a76f61 Signed-off-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_ethtool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c index 62824f5c82669..e972b5ecbf0b6 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c @@ -2546,7 +2546,7 @@ static int i40e_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, * @indir: indirection table * @key: hash key * - * Returns -EINVAL if the table specifies an inavlid queue id, otherwise + * Returns -EINVAL if the table specifies an invalid queue id, otherwise * returns 0 after programming the table. **/ static int i40e_set_rxfh(struct net_device *netdev, const u32 *indir, -- GitLab From b1f3366b86a9e99f4d4d557b02e0f53fa7ccd72c Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 10 Jul 2015 19:36:05 -0400 Subject: [PATCH 5043/7006] i40evf: Use the correct defines to match the VF registers Use CTLN1 instead of CTLN for the VF relative register space. Change-ID: Iefba63faf0307af55fec8dbb64f26059f7d91318 Signed-off-by: Anjali Singhai Jain Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40evf/i40e_txrx.c | 28 +++++++------- .../net/ethernet/intel/i40evf/i40evf_main.c | 38 +++++++++---------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c index 7309479a07642..7e91d825c760f 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c @@ -1293,17 +1293,17 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, old_itr = q_vector->rx.itr; i40e_set_new_dynamic_itr(&q_vector->rx); if (old_itr != q_vector->rx.itr) { - val = I40E_VFINT_DYN_CTLN_INTENA_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK | (I40E_RX_ITR << - I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) | + I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) | (q_vector->rx.itr << - I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT); + I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT); } else { - val = I40E_VFINT_DYN_CTLN_INTENA_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK | (I40E_ITR_NONE << - I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT); + I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT); } if (!test_bit(__I40E_DOWN, &vsi->state)) wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); @@ -1315,18 +1315,18 @@ static inline void i40e_update_enable_itr(struct i40e_vsi *vsi, old_itr = q_vector->tx.itr; i40e_set_new_dynamic_itr(&q_vector->tx); if (old_itr != q_vector->tx.itr) { - val = I40E_VFINT_DYN_CTLN_INTENA_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK | (I40E_TX_ITR << - I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) | + I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT) | (q_vector->tx.itr << - I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT); + I40E_VFINT_DYN_CTLN1_INTERVAL_SHIFT); } else { - val = I40E_VFINT_DYN_CTLN_INTENA_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK | + val = I40E_VFINT_DYN_CTLN1_INTENA_MASK | + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK | (I40E_ITR_NONE << - I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT); + I40E_VFINT_DYN_CTLN1_ITR_INDX_SHIFT); } if (!test_bit(__I40E_DOWN, &vsi->state)) wr32(hw, I40E_VFINT_DYN_CTLN1(vector - 1), val); diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index 2a6063a3a14d8..c2ba40f37ecf0 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -204,7 +204,7 @@ static void i40evf_misc_irq_enable(struct i40evf_adapter *adapter) wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK | I40E_VFINT_DYN_CTL01_ITR_INDX_MASK); - wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA_ADMINQ_MASK); + wr32(hw, I40E_VFINT_ICR0_ENA1, I40E_VFINT_ICR0_ENA1_ADMINQ_MASK); /* read flush */ rd32(hw, I40E_VFGEN_RSTAT); @@ -245,7 +245,7 @@ void i40evf_irq_enable_queues(struct i40evf_adapter *adapter, u32 mask) wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), I40E_VFINT_DYN_CTLN1_INTENA_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK); + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK); } } } @@ -263,17 +263,17 @@ static void i40evf_fire_sw_int(struct i40evf_adapter *adapter, u32 mask) if (mask & 1) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTL01); - dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | + dyn_ctl |= I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK; + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, dyn_ctl); } for (i = 1; i < adapter->num_msix_vectors; i++) { if (mask & BIT(i)) { dyn_ctl = rd32(hw, I40E_VFINT_DYN_CTLN1(i - 1)); - dyn_ctl |= I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK | + dyn_ctl |= I40E_VFINT_DYN_CTLN1_SWINT_TRIG_MASK | I40E_VFINT_DYN_CTLN1_ITR_INDX_MASK | - I40E_VFINT_DYN_CTLN_CLEARPBA_MASK; + I40E_VFINT_DYN_CTLN1_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTLN1(i - 1), dyn_ctl); } } @@ -313,7 +313,7 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data) val = rd32(hw, I40E_VFINT_DYN_CTL01); - val = val | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK; + val = val | I40E_VFINT_DYN_CTL01_CLEARPBA_MASK; wr32(hw, I40E_VFINT_DYN_CTL01, val); /* schedule work on the private workqueue */ @@ -1779,34 +1779,34 @@ static void i40evf_adminq_task(struct work_struct *work) /* check for error indications */ val = rd32(hw, hw->aq.arq.len); oldval = val; - if (val & I40E_VF_ARQLEN_ARQVFE_MASK) { + if (val & I40E_VF_ARQLEN1_ARQVFE_MASK) { dev_info(&adapter->pdev->dev, "ARQ VF Error detected\n"); - val &= ~I40E_VF_ARQLEN_ARQVFE_MASK; + val &= ~I40E_VF_ARQLEN1_ARQVFE_MASK; } - if (val & I40E_VF_ARQLEN_ARQOVFL_MASK) { + if (val & I40E_VF_ARQLEN1_ARQOVFL_MASK) { dev_info(&adapter->pdev->dev, "ARQ Overflow Error detected\n"); - val &= ~I40E_VF_ARQLEN_ARQOVFL_MASK; + val &= ~I40E_VF_ARQLEN1_ARQOVFL_MASK; } - if (val & I40E_VF_ARQLEN_ARQCRIT_MASK) { + if (val & I40E_VF_ARQLEN1_ARQCRIT_MASK) { dev_info(&adapter->pdev->dev, "ARQ Critical Error detected\n"); - val &= ~I40E_VF_ARQLEN_ARQCRIT_MASK; + val &= ~I40E_VF_ARQLEN1_ARQCRIT_MASK; } if (oldval != val) wr32(hw, hw->aq.arq.len, val); val = rd32(hw, hw->aq.asq.len); oldval = val; - if (val & I40E_VF_ATQLEN_ATQVFE_MASK) { + if (val & I40E_VF_ATQLEN1_ATQVFE_MASK) { dev_info(&adapter->pdev->dev, "ASQ VF Error detected\n"); - val &= ~I40E_VF_ATQLEN_ATQVFE_MASK; + val &= ~I40E_VF_ATQLEN1_ATQVFE_MASK; } - if (val & I40E_VF_ATQLEN_ATQOVFL_MASK) { + if (val & I40E_VF_ATQLEN1_ATQOVFL_MASK) { dev_info(&adapter->pdev->dev, "ASQ Overflow Error detected\n"); - val &= ~I40E_VF_ATQLEN_ATQOVFL_MASK; + val &= ~I40E_VF_ATQLEN1_ATQOVFL_MASK; } - if (val & I40E_VF_ATQLEN_ATQCRIT_MASK) { + if (val & I40E_VF_ATQLEN1_ATQCRIT_MASK) { dev_info(&adapter->pdev->dev, "ASQ Critical Error detected\n"); - val &= ~I40E_VF_ATQLEN_ATQCRIT_MASK; + val &= ~I40E_VF_ATQLEN1_ATQCRIT_MASK; } if (oldval != val) wr32(hw, hw->aq.asq.len, val); -- GitLab From e02a7f83d84d0580a62df8d4c4e95cd8791c6645 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 10 Jul 2015 19:36:06 -0400 Subject: [PATCH 5044/7006] i40evf: Remove PF specific register definitions from the VF There were quite a few issues when the wrong defines were getting used in the VF driver. This patch fixes the code where PF driver registers were getting used for VF driver, and also removes the registers that are not being used from the VF register file. Change-ID: If116a9730112950d006eb8ec763998fc914cc839 Signed-off-by: Anjali Singhai Jain Acked-by: Mitch Williams Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/i40evf/i40e_adminq.c | 17 +- .../net/ethernet/intel/i40evf/i40e_common.c | 2 +- .../net/ethernet/intel/i40evf/i40e_register.h | 3093 ----------------- 3 files changed, 4 insertions(+), 3108 deletions(-) diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c index c1d25f8c1abca..f08450b907745 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.c @@ -60,17 +60,6 @@ static void i40e_adminq_init_regs(struct i40e_hw *hw) hw->aq.arq.len = I40E_VF_ARQLEN1; hw->aq.arq.bal = I40E_VF_ARQBAL1; hw->aq.arq.bah = I40E_VF_ARQBAH1; - } else { - hw->aq.asq.tail = I40E_PF_ATQT; - hw->aq.asq.head = I40E_PF_ATQH; - hw->aq.asq.len = I40E_PF_ATQLEN; - hw->aq.asq.bal = I40E_PF_ATQBAL; - hw->aq.asq.bah = I40E_PF_ATQBAH; - hw->aq.arq.tail = I40E_PF_ARQT; - hw->aq.arq.head = I40E_PF_ARQH; - hw->aq.arq.len = I40E_PF_ARQLEN; - hw->aq.arq.bal = I40E_PF_ARQBAL; - hw->aq.arq.bah = I40E_PF_ARQBAH; } } @@ -308,7 +297,7 @@ static i40e_status i40e_config_asq_regs(struct i40e_hw *hw) /* set starting point */ wr32(hw, hw->aq.asq.len, (hw->aq.num_asq_entries | - I40E_PF_ATQLEN_ATQENABLE_MASK)); + I40E_VF_ATQLEN1_ATQENABLE_MASK)); wr32(hw, hw->aq.asq.bal, lower_32_bits(hw->aq.asq.desc_buf.pa)); wr32(hw, hw->aq.asq.bah, upper_32_bits(hw->aq.asq.desc_buf.pa)); @@ -337,7 +326,7 @@ static i40e_status i40e_config_arq_regs(struct i40e_hw *hw) /* set starting point */ wr32(hw, hw->aq.arq.len, (hw->aq.num_arq_entries | - I40E_PF_ARQLEN_ARQENABLE_MASK)); + I40E_VF_ARQLEN1_ARQENABLE_MASK)); wr32(hw, hw->aq.arq.bal, lower_32_bits(hw->aq.arq.desc_buf.pa)); wr32(hw, hw->aq.arq.bah, upper_32_bits(hw->aq.arq.desc_buf.pa)); @@ -899,7 +888,7 @@ i40e_status i40evf_clean_arq_element(struct i40e_hw *hw, mutex_lock(&hw->aq.arq_mutex); /* set next_to_use to head */ - ntu = (rd32(hw, hw->aq.arq.head) & I40E_PF_ARQH_ARQH_MASK); + ntu = (rd32(hw, hw->aq.arq.head) & I40E_VF_ARQH1_ARQH_MASK); if (ntu == ntc) { /* nothing to do - shouldn't need to update ring's values */ ret_code = I40E_ERR_ADMIN_QUEUE_NO_WORK; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_common.c b/drivers/net/ethernet/intel/i40evf/i40e_common.c index 023d32d090ce4..d45d0ae6bd3b6 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_common.c +++ b/drivers/net/ethernet/intel/i40evf/i40e_common.c @@ -361,7 +361,7 @@ bool i40evf_check_asq_alive(struct i40e_hw *hw) { if (hw->aq.asq.len) return !!(rd32(hw, hw->aq.asq.len) & - I40E_PF_ATQLEN_ATQENABLE_MASK); + I40E_VF_ATQLEN1_ATQENABLE_MASK); else return false; } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_register.h b/drivers/net/ethernet/intel/i40evf/i40e_register.h index 2e2ccc1719b68..10febcfd7cd82 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_register.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_register.h @@ -27,1580 +27,6 @@ #ifndef _I40E_REGISTER_H_ #define _I40E_REGISTER_H_ -#define I40E_GL_ARQBAH 0x000801C0 /* Reset: EMPR */ -#define I40E_GL_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_GL_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAH_ARQBAH_SHIFT) -#define I40E_GL_ARQBAL 0x000800C0 /* Reset: EMPR */ -#define I40E_GL_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_GL_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ARQBAL_ARQBAL_SHIFT) -#define I40E_GL_ARQH 0x000803C0 /* Reset: EMPR */ -#define I40E_GL_ARQH_ARQH_SHIFT 0 -#define I40E_GL_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_GL_ARQH_ARQH_SHIFT) -#define I40E_GL_ARQT 0x000804C0 /* Reset: EMPR */ -#define I40E_GL_ARQT_ARQT_SHIFT 0 -#define I40E_GL_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_GL_ARQT_ARQT_SHIFT) -#define I40E_GL_ATQBAH 0x00080140 /* Reset: EMPR */ -#define I40E_GL_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_GL_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAH_ATQBAH_SHIFT) -#define I40E_GL_ATQBAL 0x00080040 /* Reset: EMPR */ -#define I40E_GL_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_GL_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_ATQBAL_ATQBAL_SHIFT) -#define I40E_GL_ATQH 0x00080340 /* Reset: EMPR */ -#define I40E_GL_ATQH_ATQH_SHIFT 0 -#define I40E_GL_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_GL_ATQH_ATQH_SHIFT) -#define I40E_GL_ATQLEN 0x00080240 /* Reset: EMPR */ -#define I40E_GL_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_GL_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_GL_ATQLEN_ATQLEN_SHIFT) -#define I40E_GL_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_GL_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQVFE_SHIFT) -#define I40E_GL_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_GL_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQOVFL_SHIFT) -#define I40E_GL_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_GL_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQCRIT_SHIFT) -#define I40E_GL_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_GL_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_GL_ATQLEN_ATQENABLE_SHIFT) -#define I40E_GL_ATQT 0x00080440 /* Reset: EMPR */ -#define I40E_GL_ATQT_ATQT_SHIFT 0 -#define I40E_GL_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_GL_ATQT_ATQT_SHIFT) -#define I40E_PF_ARQBAH 0x00080180 /* Reset: EMPR */ -#define I40E_PF_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_PF_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ARQBAH_ARQBAH_SHIFT) -#define I40E_PF_ARQBAL 0x00080080 /* Reset: EMPR */ -#define I40E_PF_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_PF_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ARQBAL_ARQBAL_SHIFT) -#define I40E_PF_ARQH 0x00080380 /* Reset: EMPR */ -#define I40E_PF_ARQH_ARQH_SHIFT 0 -#define I40E_PF_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_PF_ARQH_ARQH_SHIFT) -#define I40E_PF_ARQLEN 0x00080280 /* Reset: EMPR */ -#define I40E_PF_ARQLEN_ARQLEN_SHIFT 0 -#define I40E_PF_ARQLEN_ARQLEN_MASK I40E_MASK(0x3FF, I40E_PF_ARQLEN_ARQLEN_SHIFT) -#define I40E_PF_ARQLEN_ARQVFE_SHIFT 28 -#define I40E_PF_ARQLEN_ARQVFE_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQVFE_SHIFT) -#define I40E_PF_ARQLEN_ARQOVFL_SHIFT 29 -#define I40E_PF_ARQLEN_ARQOVFL_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQOVFL_SHIFT) -#define I40E_PF_ARQLEN_ARQCRIT_SHIFT 30 -#define I40E_PF_ARQLEN_ARQCRIT_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQCRIT_SHIFT) -#define I40E_PF_ARQLEN_ARQENABLE_SHIFT 31 -#define I40E_PF_ARQLEN_ARQENABLE_MASK I40E_MASK(0x1, I40E_PF_ARQLEN_ARQENABLE_SHIFT) -#define I40E_PF_ARQT 0x00080480 /* Reset: EMPR */ -#define I40E_PF_ARQT_ARQT_SHIFT 0 -#define I40E_PF_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_PF_ARQT_ARQT_SHIFT) -#define I40E_PF_ATQBAH 0x00080100 /* Reset: EMPR */ -#define I40E_PF_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_PF_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ATQBAH_ATQBAH_SHIFT) -#define I40E_PF_ATQBAL 0x00080000 /* Reset: EMPR */ -#define I40E_PF_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_PF_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_ATQBAL_ATQBAL_SHIFT) -#define I40E_PF_ATQH 0x00080300 /* Reset: EMPR */ -#define I40E_PF_ATQH_ATQH_SHIFT 0 -#define I40E_PF_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_PF_ATQH_ATQH_SHIFT) -#define I40E_PF_ATQLEN 0x00080200 /* Reset: EMPR */ -#define I40E_PF_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_PF_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_PF_ATQLEN_ATQLEN_SHIFT) -#define I40E_PF_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_PF_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQVFE_SHIFT) -#define I40E_PF_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_PF_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQOVFL_SHIFT) -#define I40E_PF_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_PF_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQCRIT_SHIFT) -#define I40E_PF_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_PF_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_PF_ATQLEN_ATQENABLE_SHIFT) -#define I40E_PF_ATQT 0x00080400 /* Reset: EMPR */ -#define I40E_PF_ATQT_ATQT_SHIFT 0 -#define I40E_PF_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_PF_ATQT_ATQT_SHIFT) -#define I40E_VF_ARQBAH(_VF) (0x00081400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ARQBAH_MAX_INDEX 127 -#define I40E_VF_ARQBAH_ARQBAH_SHIFT 0 -#define I40E_VF_ARQBAH_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH_ARQBAH_SHIFT) -#define I40E_VF_ARQBAL(_VF) (0x00080C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ARQBAL_MAX_INDEX 127 -#define I40E_VF_ARQBAL_ARQBAL_SHIFT 0 -#define I40E_VF_ARQBAL_ARQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAL_ARQBAL_SHIFT) -#define I40E_VF_ARQH(_VF) (0x00082400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ARQH_MAX_INDEX 127 -#define I40E_VF_ARQH_ARQH_SHIFT 0 -#define I40E_VF_ARQH_ARQH_MASK I40E_MASK(0x3FF, I40E_VF_ARQH_ARQH_SHIFT) -#define I40E_VF_ARQLEN(_VF) (0x00081C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ARQLEN_MAX_INDEX 127 -#define I40E_VF_ARQLEN_ARQLEN_SHIFT 0 -#define I40E_VF_ARQLEN_ARQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ARQLEN_ARQLEN_SHIFT) -#define I40E_VF_ARQLEN_ARQVFE_SHIFT 28 -#define I40E_VF_ARQLEN_ARQVFE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQVFE_SHIFT) -#define I40E_VF_ARQLEN_ARQOVFL_SHIFT 29 -#define I40E_VF_ARQLEN_ARQOVFL_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQOVFL_SHIFT) -#define I40E_VF_ARQLEN_ARQCRIT_SHIFT 30 -#define I40E_VF_ARQLEN_ARQCRIT_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQCRIT_SHIFT) -#define I40E_VF_ARQLEN_ARQENABLE_SHIFT 31 -#define I40E_VF_ARQLEN_ARQENABLE_MASK I40E_MASK(0x1, I40E_VF_ARQLEN_ARQENABLE_SHIFT) -#define I40E_VF_ARQT(_VF) (0x00082C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ARQT_MAX_INDEX 127 -#define I40E_VF_ARQT_ARQT_SHIFT 0 -#define I40E_VF_ARQT_ARQT_MASK I40E_MASK(0x3FF, I40E_VF_ARQT_ARQT_SHIFT) -#define I40E_VF_ATQBAH(_VF) (0x00081000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ATQBAH_MAX_INDEX 127 -#define I40E_VF_ATQBAH_ATQBAH_SHIFT 0 -#define I40E_VF_ATQBAH_ATQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAH_ATQBAH_SHIFT) -#define I40E_VF_ATQBAL(_VF) (0x00080800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ATQBAL_MAX_INDEX 127 -#define I40E_VF_ATQBAL_ATQBAL_SHIFT 0 -#define I40E_VF_ATQBAL_ATQBAL_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ATQBAL_ATQBAL_SHIFT) -#define I40E_VF_ATQH(_VF) (0x00082000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ATQH_MAX_INDEX 127 -#define I40E_VF_ATQH_ATQH_SHIFT 0 -#define I40E_VF_ATQH_ATQH_MASK I40E_MASK(0x3FF, I40E_VF_ATQH_ATQH_SHIFT) -#define I40E_VF_ATQLEN(_VF) (0x00081800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ATQLEN_MAX_INDEX 127 -#define I40E_VF_ATQLEN_ATQLEN_SHIFT 0 -#define I40E_VF_ATQLEN_ATQLEN_MASK I40E_MASK(0x3FF, I40E_VF_ATQLEN_ATQLEN_SHIFT) -#define I40E_VF_ATQLEN_ATQVFE_SHIFT 28 -#define I40E_VF_ATQLEN_ATQVFE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQVFE_SHIFT) -#define I40E_VF_ATQLEN_ATQOVFL_SHIFT 29 -#define I40E_VF_ATQLEN_ATQOVFL_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQOVFL_SHIFT) -#define I40E_VF_ATQLEN_ATQCRIT_SHIFT 30 -#define I40E_VF_ATQLEN_ATQCRIT_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQCRIT_SHIFT) -#define I40E_VF_ATQLEN_ATQENABLE_SHIFT 31 -#define I40E_VF_ATQLEN_ATQENABLE_MASK I40E_MASK(0x1, I40E_VF_ATQLEN_ATQENABLE_SHIFT) -#define I40E_VF_ATQT(_VF) (0x00082800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: EMPR */ -#define I40E_VF_ATQT_MAX_INDEX 127 -#define I40E_VF_ATQT_ATQT_SHIFT 0 -#define I40E_VF_ATQT_ATQT_MASK I40E_MASK(0x3FF, I40E_VF_ATQT_ATQT_SHIFT) -#define I40E_PRT_L2TAGSEN 0x001C0B20 /* Reset: CORER */ -#define I40E_PRT_L2TAGSEN_ENABLE_SHIFT 0 -#define I40E_PRT_L2TAGSEN_ENABLE_MASK I40E_MASK(0xFF, I40E_PRT_L2TAGSEN_ENABLE_SHIFT) -#define I40E_PFCM_LAN_ERRDATA 0x0010C080 /* Reset: PFR */ -#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT 0 -#define I40E_PFCM_LAN_ERRDATA_ERROR_CODE_MASK I40E_MASK(0xF, I40E_PFCM_LAN_ERRDATA_ERROR_CODE_SHIFT) -#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT 4 -#define I40E_PFCM_LAN_ERRDATA_Q_TYPE_MASK I40E_MASK(0x7, I40E_PFCM_LAN_ERRDATA_Q_TYPE_SHIFT) -#define I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT 8 -#define I40E_PFCM_LAN_ERRDATA_Q_NUM_MASK I40E_MASK(0xFFF, I40E_PFCM_LAN_ERRDATA_Q_NUM_SHIFT) -#define I40E_PFCM_LAN_ERRINFO 0x0010C000 /* Reset: PFR */ -#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT 0 -#define I40E_PFCM_LAN_ERRINFO_ERROR_VALID_MASK I40E_MASK(0x1, I40E_PFCM_LAN_ERRINFO_ERROR_VALID_SHIFT) -#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT 4 -#define I40E_PFCM_LAN_ERRINFO_ERROR_INST_MASK I40E_MASK(0x7, I40E_PFCM_LAN_ERRINFO_ERROR_INST_SHIFT) -#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT 8 -#define I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_DBL_ERROR_CNT_SHIFT) -#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT 16 -#define I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_RLU_ERROR_CNT_SHIFT) -#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT 24 -#define I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_PFCM_LAN_ERRINFO_RLS_ERROR_CNT_SHIFT) -#define I40E_PFCM_LANCTXCTL 0x0010C300 /* Reset: CORER */ -#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT 0 -#define I40E_PFCM_LANCTXCTL_QUEUE_NUM_MASK I40E_MASK(0xFFF, I40E_PFCM_LANCTXCTL_QUEUE_NUM_SHIFT) -#define I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT 12 -#define I40E_PFCM_LANCTXCTL_SUB_LINE_MASK I40E_MASK(0x7, I40E_PFCM_LANCTXCTL_SUB_LINE_SHIFT) -#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT 15 -#define I40E_PFCM_LANCTXCTL_QUEUE_TYPE_MASK I40E_MASK(0x3, I40E_PFCM_LANCTXCTL_QUEUE_TYPE_SHIFT) -#define I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT 17 -#define I40E_PFCM_LANCTXCTL_OP_CODE_MASK I40E_MASK(0x3, I40E_PFCM_LANCTXCTL_OP_CODE_SHIFT) -#define I40E_PFCM_LANCTXDATA(_i) (0x0010C100 + ((_i) * 128)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_PFCM_LANCTXDATA_MAX_INDEX 3 -#define I40E_PFCM_LANCTXDATA_DATA_SHIFT 0 -#define I40E_PFCM_LANCTXDATA_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_PFCM_LANCTXDATA_DATA_SHIFT) -#define I40E_PFCM_LANCTXSTAT 0x0010C380 /* Reset: CORER */ -#define I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT 0 -#define I40E_PFCM_LANCTXSTAT_CTX_DONE_MASK I40E_MASK(0x1, I40E_PFCM_LANCTXSTAT_CTX_DONE_SHIFT) -#define I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT 1 -#define I40E_PFCM_LANCTXSTAT_CTX_MISS_MASK I40E_MASK(0x1, I40E_PFCM_LANCTXSTAT_CTX_MISS_SHIFT) -#define I40E_VFCM_PE_ERRDATA1(_VF) (0x00138800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VFCM_PE_ERRDATA1_MAX_INDEX 127 -#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT 0 -#define I40E_VFCM_PE_ERRDATA1_ERROR_CODE_MASK I40E_MASK(0xF, I40E_VFCM_PE_ERRDATA1_ERROR_CODE_SHIFT) -#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT 4 -#define I40E_VFCM_PE_ERRDATA1_Q_TYPE_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRDATA1_Q_TYPE_SHIFT) -#define I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT 8 -#define I40E_VFCM_PE_ERRDATA1_Q_NUM_MASK I40E_MASK(0x3FFFF, I40E_VFCM_PE_ERRDATA1_Q_NUM_SHIFT) -#define I40E_VFCM_PE_ERRINFO1(_VF) (0x00138400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VFCM_PE_ERRINFO1_MAX_INDEX 127 -#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT 0 -#define I40E_VFCM_PE_ERRINFO1_ERROR_VALID_MASK I40E_MASK(0x1, I40E_VFCM_PE_ERRINFO1_ERROR_VALID_SHIFT) -#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT 4 -#define I40E_VFCM_PE_ERRINFO1_ERROR_INST_MASK I40E_MASK(0x7, I40E_VFCM_PE_ERRINFO1_ERROR_INST_SHIFT) -#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT 8 -#define I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_DBL_ERROR_CNT_SHIFT) -#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT 16 -#define I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_RLU_ERROR_CNT_SHIFT) -#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT 24 -#define I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_MASK I40E_MASK(0xFF, I40E_VFCM_PE_ERRINFO1_RLS_ERROR_CNT_SHIFT) -#define I40E_GLDCB_GENC 0x00083044 /* Reset: CORER */ -#define I40E_GLDCB_GENC_PCIRTT_SHIFT 0 -#define I40E_GLDCB_GENC_PCIRTT_MASK I40E_MASK(0xFFFF, I40E_GLDCB_GENC_PCIRTT_SHIFT) -#define I40E_GLDCB_RUPTI 0x00122618 /* Reset: CORER */ -#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT 0 -#define I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLDCB_RUPTI_PFCTIMEOUT_UP_SHIFT) -#define I40E_PRTDCB_FCCFG 0x001E4640 /* Reset: GLOBR */ -#define I40E_PRTDCB_FCCFG_TFCE_SHIFT 3 -#define I40E_PRTDCB_FCCFG_TFCE_MASK I40E_MASK(0x3, I40E_PRTDCB_FCCFG_TFCE_SHIFT) -#define I40E_PRTDCB_FCRTV 0x001E4600 /* Reset: GLOBR */ -#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT 0 -#define I40E_PRTDCB_FCRTV_FC_REFRESH_TH_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCRTV_FC_REFRESH_TH_SHIFT) -#define I40E_PRTDCB_FCTTVN(_i) (0x001E4580 + ((_i) * 32)) /* _i=0...3 */ /* Reset: GLOBR */ -#define I40E_PRTDCB_FCTTVN_MAX_INDEX 3 -#define I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT 0 -#define I40E_PRTDCB_FCTTVN_TTV_2N_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCTTVN_TTV_2N_SHIFT) -#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT 16 -#define I40E_PRTDCB_FCTTVN_TTV_2N_P1_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_FCTTVN_TTV_2N_P1_SHIFT) -#define I40E_PRTDCB_GENC 0x00083000 /* Reset: CORER */ -#define I40E_PRTDCB_GENC_RESERVED_1_SHIFT 0 -#define I40E_PRTDCB_GENC_RESERVED_1_MASK I40E_MASK(0x3, I40E_PRTDCB_GENC_RESERVED_1_SHIFT) -#define I40E_PRTDCB_GENC_NUMTC_SHIFT 2 -#define I40E_PRTDCB_GENC_NUMTC_MASK I40E_MASK(0xF, I40E_PRTDCB_GENC_NUMTC_SHIFT) -#define I40E_PRTDCB_GENC_FCOEUP_SHIFT 6 -#define I40E_PRTDCB_GENC_FCOEUP_MASK I40E_MASK(0x7, I40E_PRTDCB_GENC_FCOEUP_SHIFT) -#define I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT 9 -#define I40E_PRTDCB_GENC_FCOEUP_VALID_MASK I40E_MASK(0x1, I40E_PRTDCB_GENC_FCOEUP_VALID_SHIFT) -#define I40E_PRTDCB_GENC_PFCLDA_SHIFT 16 -#define I40E_PRTDCB_GENC_PFCLDA_MASK I40E_MASK(0xFFFF, I40E_PRTDCB_GENC_PFCLDA_SHIFT) -#define I40E_PRTDCB_GENS 0x00083020 /* Reset: CORER */ -#define I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT 0 -#define I40E_PRTDCB_GENS_DCBX_STATUS_MASK I40E_MASK(0x7, I40E_PRTDCB_GENS_DCBX_STATUS_SHIFT) -#define I40E_PRTDCB_MFLCN 0x001E2400 /* Reset: GLOBR */ -#define I40E_PRTDCB_MFLCN_PMCF_SHIFT 0 -#define I40E_PRTDCB_MFLCN_PMCF_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_PMCF_SHIFT) -#define I40E_PRTDCB_MFLCN_DPF_SHIFT 1 -#define I40E_PRTDCB_MFLCN_DPF_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_DPF_SHIFT) -#define I40E_PRTDCB_MFLCN_RPFCM_SHIFT 2 -#define I40E_PRTDCB_MFLCN_RPFCM_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_RPFCM_SHIFT) -#define I40E_PRTDCB_MFLCN_RFCE_SHIFT 3 -#define I40E_PRTDCB_MFLCN_RFCE_MASK I40E_MASK(0x1, I40E_PRTDCB_MFLCN_RFCE_SHIFT) -#define I40E_PRTDCB_MFLCN_RPFCE_SHIFT 4 -#define I40E_PRTDCB_MFLCN_RPFCE_MASK I40E_MASK(0xFF, I40E_PRTDCB_MFLCN_RPFCE_SHIFT) -#define I40E_PRTDCB_RETSC 0x001223E0 /* Reset: CORER */ -#define I40E_PRTDCB_RETSC_ETS_MODE_SHIFT 0 -#define I40E_PRTDCB_RETSC_ETS_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSC_ETS_MODE_SHIFT) -#define I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT 1 -#define I40E_PRTDCB_RETSC_NON_ETS_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSC_NON_ETS_MODE_SHIFT) -#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT 2 -#define I40E_PRTDCB_RETSC_ETS_MAX_EXP_MASK I40E_MASK(0xF, I40E_PRTDCB_RETSC_ETS_MAX_EXP_SHIFT) -#define I40E_PRTDCB_RETSC_LLTC_SHIFT 8 -#define I40E_PRTDCB_RETSC_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_RETSC_LLTC_SHIFT) -#define I40E_PRTDCB_RETSTCC(_i) (0x00122180 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTDCB_RETSTCC_MAX_INDEX 7 -#define I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT 0 -#define I40E_PRTDCB_RETSTCC_BWSHARE_MASK I40E_MASK(0x7F, I40E_PRTDCB_RETSTCC_BWSHARE_SHIFT) -#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT 30 -#define I40E_PRTDCB_RETSTCC_UPINTC_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSTCC_UPINTC_MODE_SHIFT) -#define I40E_PRTDCB_RETSTCC_ETSTC_SHIFT 31 -#define I40E_PRTDCB_RETSTCC_ETSTC_MASK I40E_MASK(0x1, I40E_PRTDCB_RETSTCC_ETSTC_SHIFT) -#define I40E_PRTDCB_RPPMC 0x001223A0 /* Reset: CORER */ -#define I40E_PRTDCB_RPPMC_LANRPPM_SHIFT 0 -#define I40E_PRTDCB_RPPMC_LANRPPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_LANRPPM_SHIFT) -#define I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT 8 -#define I40E_PRTDCB_RPPMC_RDMARPPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_RDMARPPM_SHIFT) -#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT 16 -#define I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_MASK I40E_MASK(0xFF, I40E_PRTDCB_RPPMC_RX_FIFO_SIZE_SHIFT) -#define I40E_PRTDCB_RUP 0x001C0B00 /* Reset: CORER */ -#define I40E_PRTDCB_RUP_NOVLANUP_SHIFT 0 -#define I40E_PRTDCB_RUP_NOVLANUP_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP_NOVLANUP_SHIFT) -#define I40E_PRTDCB_RUP2TC 0x001C09A0 /* Reset: CORER */ -#define I40E_PRTDCB_RUP2TC_UP0TC_SHIFT 0 -#define I40E_PRTDCB_RUP2TC_UP0TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP0TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP1TC_SHIFT 3 -#define I40E_PRTDCB_RUP2TC_UP1TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP1TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP2TC_SHIFT 6 -#define I40E_PRTDCB_RUP2TC_UP2TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP2TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP3TC_SHIFT 9 -#define I40E_PRTDCB_RUP2TC_UP3TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP3TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP4TC_SHIFT 12 -#define I40E_PRTDCB_RUP2TC_UP4TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP4TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP5TC_SHIFT 15 -#define I40E_PRTDCB_RUP2TC_UP5TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP5TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP6TC_SHIFT 18 -#define I40E_PRTDCB_RUP2TC_UP6TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP6TC_SHIFT) -#define I40E_PRTDCB_RUP2TC_UP7TC_SHIFT 21 -#define I40E_PRTDCB_RUP2TC_UP7TC_MASK I40E_MASK(0x7, I40E_PRTDCB_RUP2TC_UP7TC_SHIFT) -#define I40E_PRTDCB_RUPTQ(_i) (0x00122400 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTDCB_RUPTQ_MAX_INDEX 7 -#define I40E_PRTDCB_RUPTQ_RXQNUM_SHIFT 0 -#define I40E_PRTDCB_RUPTQ_RXQNUM_MASK I40E_MASK(0x3FFF, I40E_PRTDCB_RUPTQ_RXQNUM_SHIFT) -#define I40E_PRTDCB_TC2PFC 0x001C0980 /* Reset: CORER */ -#define I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT 0 -#define I40E_PRTDCB_TC2PFC_TC2PFC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TC2PFC_TC2PFC_SHIFT) -#define I40E_PRTDCB_TCMSTC(_i) (0x000A0040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTDCB_TCMSTC_MAX_INDEX 7 -#define I40E_PRTDCB_TCMSTC_MSTC_SHIFT 0 -#define I40E_PRTDCB_TCMSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCMSTC_MSTC_SHIFT) -#define I40E_PRTDCB_TCPMC 0x000A21A0 /* Reset: CORER */ -#define I40E_PRTDCB_TCPMC_CPM_SHIFT 0 -#define I40E_PRTDCB_TCPMC_CPM_MASK I40E_MASK(0x1FFF, I40E_PRTDCB_TCPMC_CPM_SHIFT) -#define I40E_PRTDCB_TCPMC_LLTC_SHIFT 13 -#define I40E_PRTDCB_TCPMC_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TCPMC_LLTC_SHIFT) -#define I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT 30 -#define I40E_PRTDCB_TCPMC_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TCPMC_TCPM_MODE_SHIFT) -#define I40E_PRTDCB_TCWSTC(_i) (0x000A2040 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTDCB_TCWSTC_MAX_INDEX 7 -#define I40E_PRTDCB_TCWSTC_MSTC_SHIFT 0 -#define I40E_PRTDCB_TCWSTC_MSTC_MASK I40E_MASK(0xFFFFF, I40E_PRTDCB_TCWSTC_MSTC_SHIFT) -#define I40E_PRTDCB_TDPMC 0x000A0180 /* Reset: CORER */ -#define I40E_PRTDCB_TDPMC_DPM_SHIFT 0 -#define I40E_PRTDCB_TDPMC_DPM_MASK I40E_MASK(0xFF, I40E_PRTDCB_TDPMC_DPM_SHIFT) -#define I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT 30 -#define I40E_PRTDCB_TDPMC_TCPM_MODE_MASK I40E_MASK(0x1, I40E_PRTDCB_TDPMC_TCPM_MODE_SHIFT) -#define I40E_PRTDCB_TETSC_TCB 0x000AE060 /* Reset: CORER */ -#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT 0 -#define I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_MASK I40E_MASK(0x1, I40E_PRTDCB_TETSC_TCB_EN_LL_STRICT_PRIORITY_SHIFT) -#define I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT 8 -#define I40E_PRTDCB_TETSC_TCB_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TETSC_TCB_LLTC_SHIFT) -#define I40E_PRTDCB_TETSC_TPB 0x00098060 /* Reset: CORER */ -#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT 0 -#define I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_MASK I40E_MASK(0x1, I40E_PRTDCB_TETSC_TPB_EN_LL_STRICT_PRIORITY_SHIFT) -#define I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT 8 -#define I40E_PRTDCB_TETSC_TPB_LLTC_MASK I40E_MASK(0xFF, I40E_PRTDCB_TETSC_TPB_LLTC_SHIFT) -#define I40E_PRTDCB_TFCS 0x001E4560 /* Reset: GLOBR */ -#define I40E_PRTDCB_TFCS_TXOFF_SHIFT 0 -#define I40E_PRTDCB_TFCS_TXOFF_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF0_SHIFT 8 -#define I40E_PRTDCB_TFCS_TXOFF0_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF0_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF1_SHIFT 9 -#define I40E_PRTDCB_TFCS_TXOFF1_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF1_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF2_SHIFT 10 -#define I40E_PRTDCB_TFCS_TXOFF2_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF2_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF3_SHIFT 11 -#define I40E_PRTDCB_TFCS_TXOFF3_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF3_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF4_SHIFT 12 -#define I40E_PRTDCB_TFCS_TXOFF4_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF4_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF5_SHIFT 13 -#define I40E_PRTDCB_TFCS_TXOFF5_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF5_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF6_SHIFT 14 -#define I40E_PRTDCB_TFCS_TXOFF6_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF6_SHIFT) -#define I40E_PRTDCB_TFCS_TXOFF7_SHIFT 15 -#define I40E_PRTDCB_TFCS_TXOFF7_MASK I40E_MASK(0x1, I40E_PRTDCB_TFCS_TXOFF7_SHIFT) -#define I40E_PRTDCB_TPFCTS(_i) (0x001E4660 + ((_i) * 32)) /* _i=0...7 */ /* Reset: GLOBR */ -#define I40E_PRTDCB_TPFCTS_MAX_INDEX 7 -#define I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT 0 -#define I40E_PRTDCB_TPFCTS_PFCTIMER_MASK I40E_MASK(0x3FFF, I40E_PRTDCB_TPFCTS_PFCTIMER_SHIFT) -#define I40E_GLFCOE_RCTL 0x00269B94 /* Reset: CORER */ -#define I40E_GLFCOE_RCTL_FCOEVER_SHIFT 0 -#define I40E_GLFCOE_RCTL_FCOEVER_MASK I40E_MASK(0xF, I40E_GLFCOE_RCTL_FCOEVER_SHIFT) -#define I40E_GLFCOE_RCTL_SAVBAD_SHIFT 4 -#define I40E_GLFCOE_RCTL_SAVBAD_MASK I40E_MASK(0x1, I40E_GLFCOE_RCTL_SAVBAD_SHIFT) -#define I40E_GLFCOE_RCTL_ICRC_SHIFT 5 -#define I40E_GLFCOE_RCTL_ICRC_MASK I40E_MASK(0x1, I40E_GLFCOE_RCTL_ICRC_SHIFT) -#define I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT 16 -#define I40E_GLFCOE_RCTL_MAX_SIZE_MASK I40E_MASK(0x3FFF, I40E_GLFCOE_RCTL_MAX_SIZE_SHIFT) -#define I40E_GL_FWSTS 0x00083048 /* Reset: POR */ -#define I40E_GL_FWSTS_FWS0B_SHIFT 0 -#define I40E_GL_FWSTS_FWS0B_MASK I40E_MASK(0xFF, I40E_GL_FWSTS_FWS0B_SHIFT) -#define I40E_GL_FWSTS_FWRI_SHIFT 9 -#define I40E_GL_FWSTS_FWRI_MASK I40E_MASK(0x1, I40E_GL_FWSTS_FWRI_SHIFT) -#define I40E_GL_FWSTS_FWS1B_SHIFT 16 -#define I40E_GL_FWSTS_FWS1B_MASK I40E_MASK(0xFF, I40E_GL_FWSTS_FWS1B_SHIFT) -#define I40E_GLGEN_CLKSTAT 0x000B8184 /* Reset: POR */ -#define I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT 0 -#define I40E_GLGEN_CLKSTAT_CLKMODE_MASK I40E_MASK(0x1, I40E_GLGEN_CLKSTAT_CLKMODE_SHIFT) -#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT 4 -#define I40E_GLGEN_CLKSTAT_U_CLK_SPEED_MASK I40E_MASK(0x3, I40E_GLGEN_CLKSTAT_U_CLK_SPEED_SHIFT) -#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT 8 -#define I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P0_CLK_SPEED_SHIFT) -#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT 12 -#define I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P1_CLK_SPEED_SHIFT) -#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT 16 -#define I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P2_CLK_SPEED_SHIFT) -#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT 20 -#define I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_MASK I40E_MASK(0x7, I40E_GLGEN_CLKSTAT_P3_CLK_SPEED_SHIFT) -#define I40E_GLGEN_GPIO_CTL(_i) (0x00088100 + ((_i) * 4)) /* _i=0...29 */ /* Reset: POR */ -#define I40E_GLGEN_GPIO_CTL_MAX_INDEX 29 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT 0 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_MASK I40E_MASK(0x3, I40E_GLGEN_GPIO_CTL_PRT_NUM_SHIFT) -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT 3 -#define I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_PRT_NUM_NA_SHIFT) -#define I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT 4 -#define I40E_GLGEN_GPIO_CTL_PIN_DIR_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_PIN_DIR_SHIFT) -#define I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT 5 -#define I40E_GLGEN_GPIO_CTL_TRI_CTL_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_TRI_CTL_SHIFT) -#define I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT 6 -#define I40E_GLGEN_GPIO_CTL_OUT_CTL_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_OUT_CTL_SHIFT) -#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT 7 -#define I40E_GLGEN_GPIO_CTL_PIN_FUNC_MASK I40E_MASK(0x7, I40E_GLGEN_GPIO_CTL_PIN_FUNC_SHIFT) -#define I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT 10 -#define I40E_GLGEN_GPIO_CTL_LED_INVRT_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_LED_INVRT_SHIFT) -#define I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT 11 -#define I40E_GLGEN_GPIO_CTL_LED_BLINK_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT) -#define I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT 12 -#define I40E_GLGEN_GPIO_CTL_LED_MODE_MASK I40E_MASK(0x1F, I40E_GLGEN_GPIO_CTL_LED_MODE_SHIFT) -#define I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT 17 -#define I40E_GLGEN_GPIO_CTL_INT_MODE_MASK I40E_MASK(0x3, I40E_GLGEN_GPIO_CTL_INT_MODE_SHIFT) -#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT 19 -#define I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_CTL_OUT_DEFAULT_SHIFT) -#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT 20 -#define I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_MASK I40E_MASK(0x3F, I40E_GLGEN_GPIO_CTL_PHY_PIN_NAME_SHIFT) -#define I40E_GLGEN_GPIO_CTL_PRT_BIT_MAP_SHIFT 26 -#define I40E_GLGEN_GPIO_CTL_PRT_BIT_MAP_MASK I40E_MASK(0xF, I40E_GLGEN_GPIO_CTL_PRT_BIT_MAP_SHIFT) -#define I40E_GLGEN_GPIO_SET 0x00088184 /* Reset: POR */ -#define I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT 0 -#define I40E_GLGEN_GPIO_SET_GPIO_INDX_MASK I40E_MASK(0x1F, I40E_GLGEN_GPIO_SET_GPIO_INDX_SHIFT) -#define I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT 5 -#define I40E_GLGEN_GPIO_SET_SDP_DATA_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_SET_SDP_DATA_SHIFT) -#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT 6 -#define I40E_GLGEN_GPIO_SET_DRIVE_SDP_MASK I40E_MASK(0x1, I40E_GLGEN_GPIO_SET_DRIVE_SDP_SHIFT) -#define I40E_GLGEN_GPIO_STAT 0x0008817C /* Reset: POR */ -#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT 0 -#define I40E_GLGEN_GPIO_STAT_GPIO_VALUE_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_GPIO_STAT_GPIO_VALUE_SHIFT) -#define I40E_GLGEN_GPIO_TRANSIT 0x00088180 /* Reset: POR */ -#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT 0 -#define I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_MASK I40E_MASK(0x3FFFFFFF, I40E_GLGEN_GPIO_TRANSIT_GPIO_TRANSITION_SHIFT) -#define I40E_GLGEN_I2CCMD(_i) (0x000881E0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_GLGEN_I2CCMD_MAX_INDEX 3 -#define I40E_GLGEN_I2CCMD_DATA_SHIFT 0 -#define I40E_GLGEN_I2CCMD_DATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_I2CCMD_DATA_SHIFT) -#define I40E_GLGEN_I2CCMD_REGADD_SHIFT 16 -#define I40E_GLGEN_I2CCMD_REGADD_MASK I40E_MASK(0xFF, I40E_GLGEN_I2CCMD_REGADD_SHIFT) -#define I40E_GLGEN_I2CCMD_PHYADD_SHIFT 24 -#define I40E_GLGEN_I2CCMD_PHYADD_MASK I40E_MASK(0x7, I40E_GLGEN_I2CCMD_PHYADD_SHIFT) -#define I40E_GLGEN_I2CCMD_OP_SHIFT 27 -#define I40E_GLGEN_I2CCMD_OP_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_OP_SHIFT) -#define I40E_GLGEN_I2CCMD_RESET_SHIFT 28 -#define I40E_GLGEN_I2CCMD_RESET_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_RESET_SHIFT) -#define I40E_GLGEN_I2CCMD_R_SHIFT 29 -#define I40E_GLGEN_I2CCMD_R_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_R_SHIFT) -#define I40E_GLGEN_I2CCMD_E_SHIFT 31 -#define I40E_GLGEN_I2CCMD_E_MASK I40E_MASK(0x1, I40E_GLGEN_I2CCMD_E_SHIFT) -#define I40E_GLGEN_I2CPARAMS(_i) (0x000881AC + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_GLGEN_I2CPARAMS_MAX_INDEX 3 -#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT 0 -#define I40E_GLGEN_I2CPARAMS_WRITE_TIME_MASK I40E_MASK(0x1F, I40E_GLGEN_I2CPARAMS_WRITE_TIME_SHIFT) -#define I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT 5 -#define I40E_GLGEN_I2CPARAMS_READ_TIME_MASK I40E_MASK(0x7, I40E_GLGEN_I2CPARAMS_READ_TIME_SHIFT) -#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT 8 -#define I40E_GLGEN_I2CPARAMS_I2CBB_EN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_I2CBB_EN_SHIFT) -#define I40E_GLGEN_I2CPARAMS_CLK_SHIFT 9 -#define I40E_GLGEN_I2CPARAMS_CLK_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_SHIFT) -#define I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT 10 -#define I40E_GLGEN_I2CPARAMS_DATA_OUT_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_OUT_SHIFT) -#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT 11 -#define I40E_GLGEN_I2CPARAMS_DATA_OE_N_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_OE_N_SHIFT) -#define I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT 12 -#define I40E_GLGEN_I2CPARAMS_DATA_IN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_DATA_IN_SHIFT) -#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT 13 -#define I40E_GLGEN_I2CPARAMS_CLK_OE_N_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_OE_N_SHIFT) -#define I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT 14 -#define I40E_GLGEN_I2CPARAMS_CLK_IN_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_IN_SHIFT) -#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT 15 -#define I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_CLK_STRETCH_DIS_SHIFT) -#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT 31 -#define I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_MASK I40E_MASK(0x1, I40E_GLGEN_I2CPARAMS_I2C_DATA_ORDER_SHIFT) -#define I40E_GLGEN_LED_CTL 0x00088178 /* Reset: POR */ -#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT 0 -#define I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_MASK I40E_MASK(0x1, I40E_GLGEN_LED_CTL_GLOBAL_BLINK_MODE_SHIFT) -#define I40E_GLGEN_MDIO_CTRL(_i) (0x000881D0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_GLGEN_MDIO_CTRL_MAX_INDEX 3 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT 0 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_MASK I40E_MASK(0x1FFFF, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD2_SHIFT) -#define I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT 17 -#define I40E_GLGEN_MDIO_CTRL_CONTMDC_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_CTRL_CONTMDC_SHIFT) -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT 18 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_MASK I40E_MASK(0x7FF, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD1_SHIFT) -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD0_SHIFT 29 -#define I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD0_MASK I40E_MASK(0x7, I40E_GLGEN_MDIO_CTRL_LEGACY_RSVD0_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL(_i) (0x000881C0 + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_GLGEN_MDIO_I2C_SEL_MAX_INDEX 3 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT 0 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_I2C_SEL_MDIO_I2C_SEL_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT 1 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_MASK I40E_MASK(0xF, I40E_GLGEN_MDIO_I2C_SEL_PHY_PORT_NUM_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT 5 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY0_ADDRESS_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT 10 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY1_ADDRESS_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT 15 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY2_ADDRESS_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT 20 -#define I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_MASK I40E_MASK(0x1F, I40E_GLGEN_MDIO_I2C_SEL_PHY3_ADDRESS_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT 25 -#define I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_MASK I40E_MASK(0xF, I40E_GLGEN_MDIO_I2C_SEL_MDIO_IF_MODE_SHIFT) -#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT 31 -#define I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_MASK I40E_MASK(0x1, I40E_GLGEN_MDIO_I2C_SEL_EN_FAST_MODE_SHIFT) -#define I40E_GLGEN_MSCA(_i) (0x0008818C + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_GLGEN_MSCA_MAX_INDEX 3 -#define I40E_GLGEN_MSCA_MDIADD_SHIFT 0 -#define I40E_GLGEN_MSCA_MDIADD_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSCA_MDIADD_SHIFT) -#define I40E_GLGEN_MSCA_DEVADD_SHIFT 16 -#define I40E_GLGEN_MSCA_DEVADD_MASK I40E_MASK(0x1F, I40E_GLGEN_MSCA_DEVADD_SHIFT) -#define I40E_GLGEN_MSCA_PHYADD_SHIFT 21 -#define I40E_GLGEN_MSCA_PHYADD_MASK I40E_MASK(0x1F, I40E_GLGEN_MSCA_PHYADD_SHIFT) -#define I40E_GLGEN_MSCA_OPCODE_SHIFT 26 -#define I40E_GLGEN_MSCA_OPCODE_MASK I40E_MASK(0x3, I40E_GLGEN_MSCA_OPCODE_SHIFT) -#define I40E_GLGEN_MSCA_STCODE_SHIFT 28 -#define I40E_GLGEN_MSCA_STCODE_MASK I40E_MASK(0x3, I40E_GLGEN_MSCA_STCODE_SHIFT) -#define I40E_GLGEN_MSCA_MDICMD_SHIFT 30 -#define I40E_GLGEN_MSCA_MDICMD_MASK I40E_MASK(0x1, I40E_GLGEN_MSCA_MDICMD_SHIFT) -#define I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT 31 -#define I40E_GLGEN_MSCA_MDIINPROGEN_MASK I40E_MASK(0x1, I40E_GLGEN_MSCA_MDIINPROGEN_SHIFT) -#define I40E_GLGEN_MSRWD(_i) (0x0008819C + ((_i) * 4)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_GLGEN_MSRWD_MAX_INDEX 3 -#define I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT 0 -#define I40E_GLGEN_MSRWD_MDIWRDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIWRDATA_SHIFT) -#define I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT 16 -#define I40E_GLGEN_MSRWD_MDIRDDATA_MASK I40E_MASK(0xFFFF, I40E_GLGEN_MSRWD_MDIRDDATA_SHIFT) -#define I40E_GLGEN_PCIFCNCNT 0x001C0AB4 /* Reset: PCIR */ -#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT 0 -#define I40E_GLGEN_PCIFCNCNT_PCIPFCNT_MASK I40E_MASK(0x1F, I40E_GLGEN_PCIFCNCNT_PCIPFCNT_SHIFT) -#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT 16 -#define I40E_GLGEN_PCIFCNCNT_PCIVFCNT_MASK I40E_MASK(0xFF, I40E_GLGEN_PCIFCNCNT_PCIVFCNT_SHIFT) -#define I40E_GLGEN_RSTAT 0x000B8188 /* Reset: POR */ -#define I40E_GLGEN_RSTAT_DEVSTATE_SHIFT 0 -#define I40E_GLGEN_RSTAT_DEVSTATE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_DEVSTATE_SHIFT) -#define I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT 2 -#define I40E_GLGEN_RSTAT_RESET_TYPE_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_RESET_TYPE_SHIFT) -#define I40E_GLGEN_RSTAT_CORERCNT_SHIFT 4 -#define I40E_GLGEN_RSTAT_CORERCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_CORERCNT_SHIFT) -#define I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT 6 -#define I40E_GLGEN_RSTAT_GLOBRCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_GLOBRCNT_SHIFT) -#define I40E_GLGEN_RSTAT_EMPRCNT_SHIFT 8 -#define I40E_GLGEN_RSTAT_EMPRCNT_MASK I40E_MASK(0x3, I40E_GLGEN_RSTAT_EMPRCNT_SHIFT) -#define I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT 10 -#define I40E_GLGEN_RSTAT_TIME_TO_RST_MASK I40E_MASK(0x3F, I40E_GLGEN_RSTAT_TIME_TO_RST_SHIFT) -#define I40E_GLGEN_RSTCTL 0x000B8180 /* Reset: POR */ -#define I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT 0 -#define I40E_GLGEN_RSTCTL_GRSTDEL_MASK I40E_MASK(0x3F, I40E_GLGEN_RSTCTL_GRSTDEL_SHIFT) -#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT 8 -#define I40E_GLGEN_RSTCTL_ECC_RST_ENA_MASK I40E_MASK(0x1, I40E_GLGEN_RSTCTL_ECC_RST_ENA_SHIFT) -#define I40E_GLGEN_RTRIG 0x000B8190 /* Reset: CORER */ -#define I40E_GLGEN_RTRIG_CORER_SHIFT 0 -#define I40E_GLGEN_RTRIG_CORER_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_CORER_SHIFT) -#define I40E_GLGEN_RTRIG_GLOBR_SHIFT 1 -#define I40E_GLGEN_RTRIG_GLOBR_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_GLOBR_SHIFT) -#define I40E_GLGEN_RTRIG_EMPFWR_SHIFT 2 -#define I40E_GLGEN_RTRIG_EMPFWR_MASK I40E_MASK(0x1, I40E_GLGEN_RTRIG_EMPFWR_SHIFT) -#define I40E_GLGEN_STAT 0x000B612C /* Reset: POR */ -#define I40E_GLGEN_STAT_HWRSVD0_SHIFT 0 -#define I40E_GLGEN_STAT_HWRSVD0_MASK I40E_MASK(0x3, I40E_GLGEN_STAT_HWRSVD0_SHIFT) -#define I40E_GLGEN_STAT_DCBEN_SHIFT 2 -#define I40E_GLGEN_STAT_DCBEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_DCBEN_SHIFT) -#define I40E_GLGEN_STAT_VTEN_SHIFT 3 -#define I40E_GLGEN_STAT_VTEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_VTEN_SHIFT) -#define I40E_GLGEN_STAT_FCOEN_SHIFT 4 -#define I40E_GLGEN_STAT_FCOEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_FCOEN_SHIFT) -#define I40E_GLGEN_STAT_EVBEN_SHIFT 5 -#define I40E_GLGEN_STAT_EVBEN_MASK I40E_MASK(0x1, I40E_GLGEN_STAT_EVBEN_SHIFT) -#define I40E_GLGEN_STAT_HWRSVD1_SHIFT 6 -#define I40E_GLGEN_STAT_HWRSVD1_MASK I40E_MASK(0x3, I40E_GLGEN_STAT_HWRSVD1_SHIFT) -#define I40E_GLGEN_VFLRSTAT(_i) (0x00092600 + ((_i) * 4)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLGEN_VFLRSTAT_MAX_INDEX 3 -#define I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT 0 -#define I40E_GLGEN_VFLRSTAT_VFLRE_MASK I40E_MASK(0xFFFFFFFF, I40E_GLGEN_VFLRSTAT_VFLRE_SHIFT) -#define I40E_GLVFGEN_TIMER 0x000881BC /* Reset: CORER */ -#define I40E_GLVFGEN_TIMER_GTIME_SHIFT 0 -#define I40E_GLVFGEN_TIMER_GTIME_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVFGEN_TIMER_GTIME_SHIFT) -#define I40E_PFGEN_CTRL 0x00092400 /* Reset: PFR */ -#define I40E_PFGEN_CTRL_PFSWR_SHIFT 0 -#define I40E_PFGEN_CTRL_PFSWR_MASK I40E_MASK(0x1, I40E_PFGEN_CTRL_PFSWR_SHIFT) -#define I40E_PFGEN_DRUN 0x00092500 /* Reset: CORER */ -#define I40E_PFGEN_DRUN_DRVUNLD_SHIFT 0 -#define I40E_PFGEN_DRUN_DRVUNLD_MASK I40E_MASK(0x1, I40E_PFGEN_DRUN_DRVUNLD_SHIFT) -#define I40E_PFGEN_PORTNUM 0x001C0480 /* Reset: CORER */ -#define I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT 0 -#define I40E_PFGEN_PORTNUM_PORT_NUM_MASK I40E_MASK(0x3, I40E_PFGEN_PORTNUM_PORT_NUM_SHIFT) -#define I40E_PFGEN_STATE 0x00088000 /* Reset: CORER */ -#define I40E_PFGEN_STATE_RESERVED_0_SHIFT 0 -#define I40E_PFGEN_STATE_RESERVED_0_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_RESERVED_0_SHIFT) -#define I40E_PFGEN_STATE_PFFCEN_SHIFT 1 -#define I40E_PFGEN_STATE_PFFCEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFFCEN_SHIFT) -#define I40E_PFGEN_STATE_PFLINKEN_SHIFT 2 -#define I40E_PFGEN_STATE_PFLINKEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFLINKEN_SHIFT) -#define I40E_PFGEN_STATE_PFSCEN_SHIFT 3 -#define I40E_PFGEN_STATE_PFSCEN_MASK I40E_MASK(0x1, I40E_PFGEN_STATE_PFSCEN_SHIFT) -#define I40E_PRTGEN_CNF 0x000B8120 /* Reset: POR */ -#define I40E_PRTGEN_CNF_PORT_DIS_SHIFT 0 -#define I40E_PRTGEN_CNF_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_PORT_DIS_SHIFT) -#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT 1 -#define I40E_PRTGEN_CNF_ALLOW_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_ALLOW_PORT_DIS_SHIFT) -#define I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT 2 -#define I40E_PRTGEN_CNF_EMP_PORT_DIS_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF_EMP_PORT_DIS_SHIFT) -#define I40E_PRTGEN_CNF2 0x000B8160 /* Reset: POR */ -#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT 0 -#define I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_MASK I40E_MASK(0x1, I40E_PRTGEN_CNF2_ACTIVATE_PORT_LINK_SHIFT) -#define I40E_PRTGEN_STATUS 0x000B8100 /* Reset: POR */ -#define I40E_PRTGEN_STATUS_PORT_VALID_SHIFT 0 -#define I40E_PRTGEN_STATUS_PORT_VALID_MASK I40E_MASK(0x1, I40E_PRTGEN_STATUS_PORT_VALID_SHIFT) -#define I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT 1 -#define I40E_PRTGEN_STATUS_PORT_ACTIVE_MASK I40E_MASK(0x1, I40E_PRTGEN_STATUS_PORT_ACTIVE_SHIFT) -#define I40E_VFGEN_RSTAT1(_VF) (0x00074400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VFGEN_RSTAT1_MAX_INDEX 127 -#define I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT 0 -#define I40E_VFGEN_RSTAT1_VFR_STATE_MASK I40E_MASK(0x3, I40E_VFGEN_RSTAT1_VFR_STATE_SHIFT) -#define I40E_VPGEN_VFRSTAT(_VF) (0x00091C00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VPGEN_VFRSTAT_MAX_INDEX 127 -#define I40E_VPGEN_VFRSTAT_VFRD_SHIFT 0 -#define I40E_VPGEN_VFRSTAT_VFRD_MASK I40E_MASK(0x1, I40E_VPGEN_VFRSTAT_VFRD_SHIFT) -#define I40E_VPGEN_VFRTRIG(_VF) (0x00091800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VPGEN_VFRTRIG_MAX_INDEX 127 -#define I40E_VPGEN_VFRTRIG_VFSWR_SHIFT 0 -#define I40E_VPGEN_VFRTRIG_VFSWR_MASK I40E_MASK(0x1, I40E_VPGEN_VFRTRIG_VFSWR_SHIFT) -#define I40E_VSIGEN_RSTAT(_VSI) (0x00090800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_VSIGEN_RSTAT_MAX_INDEX 383 -#define I40E_VSIGEN_RSTAT_VMRD_SHIFT 0 -#define I40E_VSIGEN_RSTAT_VMRD_MASK I40E_MASK(0x1, I40E_VSIGEN_RSTAT_VMRD_SHIFT) -#define I40E_VSIGEN_RTRIG(_VSI) (0x00090000 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_VSIGEN_RTRIG_MAX_INDEX 383 -#define I40E_VSIGEN_RTRIG_VMSWR_SHIFT 0 -#define I40E_VSIGEN_RTRIG_VMSWR_MASK I40E_MASK(0x1, I40E_VSIGEN_RTRIG_VMSWR_SHIFT) -#define I40E_GLHMC_FCOEDDPBASE(_i) (0x000C6600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FCOEDDPBASE_MAX_INDEX 15 -#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT 0 -#define I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FCOEDDPBASE_FPMFCOEDDPBASE_SHIFT) -#define I40E_GLHMC_FCOEDDPCNT(_i) (0x000C6700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FCOEDDPCNT_MAX_INDEX 15 -#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT 0 -#define I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_MASK I40E_MASK(0xFFFFF, I40E_GLHMC_FCOEDDPCNT_FPMFCOEDDPCNT_SHIFT) -#define I40E_GLHMC_FCOEDDPOBJSZ 0x000C2010 /* Reset: CORER */ -#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT 0 -#define I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FCOEDDPOBJSZ_PMFCOEDDPOBJSZ_SHIFT) -#define I40E_GLHMC_FCOEFBASE(_i) (0x000C6800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FCOEFBASE_MAX_INDEX 15 -#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT 0 -#define I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FCOEFBASE_FPMFCOEFBASE_SHIFT) -#define I40E_GLHMC_FCOEFCNT(_i) (0x000C6900 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FCOEFCNT_MAX_INDEX 15 -#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT 0 -#define I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_MASK I40E_MASK(0x7FFFFF, I40E_GLHMC_FCOEFCNT_FPMFCOEFCNT_SHIFT) -#define I40E_GLHMC_FCOEFMAX 0x000C20D0 /* Reset: CORER */ -#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT 0 -#define I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_MASK I40E_MASK(0xFFFF, I40E_GLHMC_FCOEFMAX_PMFCOEFMAX_SHIFT) -#define I40E_GLHMC_FCOEFOBJSZ 0x000C2018 /* Reset: CORER */ -#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT 0 -#define I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FCOEFOBJSZ_PMFCOEFOBJSZ_SHIFT) -#define I40E_GLHMC_FCOEMAX 0x000C2014 /* Reset: CORER */ -#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT 0 -#define I40E_GLHMC_FCOEMAX_PMFCOEMAX_MASK I40E_MASK(0x1FFF, I40E_GLHMC_FCOEMAX_PMFCOEMAX_SHIFT) -#define I40E_GLHMC_FSIAVBASE(_i) (0x000C5600 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FSIAVBASE_MAX_INDEX 15 -#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT 0 -#define I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FSIAVBASE_FPMFSIAVBASE_SHIFT) -#define I40E_GLHMC_FSIAVCNT(_i) (0x000C5700 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FSIAVCNT_MAX_INDEX 15 -#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT 0 -#define I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_FSIAVCNT_FPMFSIAVCNT_SHIFT) -#define I40E_GLHMC_FSIAVCNT_RSVD_SHIFT 29 -#define I40E_GLHMC_FSIAVCNT_RSVD_MASK I40E_MASK(0x7, I40E_GLHMC_FSIAVCNT_RSVD_SHIFT) -#define I40E_GLHMC_FSIAVMAX 0x000C2068 /* Reset: CORER */ -#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT 0 -#define I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_MASK I40E_MASK(0x1FFFF, I40E_GLHMC_FSIAVMAX_PMFSIAVMAX_SHIFT) -#define I40E_GLHMC_FSIAVOBJSZ 0x000C2064 /* Reset: CORER */ -#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT 0 -#define I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FSIAVOBJSZ_PMFSIAVOBJSZ_SHIFT) -#define I40E_GLHMC_FSIMCBASE(_i) (0x000C6000 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FSIMCBASE_MAX_INDEX 15 -#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT 0 -#define I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_FSIMCBASE_FPMFSIMCBASE_SHIFT) -#define I40E_GLHMC_FSIMCCNT(_i) (0x000C6100 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_FSIMCCNT_MAX_INDEX 15 -#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT 0 -#define I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_MASK I40E_MASK(0x1FFFFFFF, I40E_GLHMC_FSIMCCNT_FPMFSIMCSZ_SHIFT) -#define I40E_GLHMC_FSIMCMAX 0x000C2060 /* Reset: CORER */ -#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT 0 -#define I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_MASK I40E_MASK(0x3FFF, I40E_GLHMC_FSIMCMAX_PMFSIMCMAX_SHIFT) -#define I40E_GLHMC_FSIMCOBJSZ 0x000C205c /* Reset: CORER */ -#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT 0 -#define I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_FSIMCOBJSZ_PMFSIMCOBJSZ_SHIFT) -#define I40E_GLHMC_LANQMAX 0x000C2008 /* Reset: CORER */ -#define I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT 0 -#define I40E_GLHMC_LANQMAX_PMLANQMAX_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANQMAX_PMLANQMAX_SHIFT) -#define I40E_GLHMC_LANRXBASE(_i) (0x000C6400 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_LANRXBASE_MAX_INDEX 15 -#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT 0 -#define I40E_GLHMC_LANRXBASE_FPMLANRXBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_LANRXBASE_FPMLANRXBASE_SHIFT) -#define I40E_GLHMC_LANRXCNT(_i) (0x000C6500 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_LANRXCNT_MAX_INDEX 15 -#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT 0 -#define I40E_GLHMC_LANRXCNT_FPMLANRXCNT_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANRXCNT_FPMLANRXCNT_SHIFT) -#define I40E_GLHMC_LANRXOBJSZ 0x000C200c /* Reset: CORER */ -#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT 0 -#define I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_LANRXOBJSZ_PMLANRXOBJSZ_SHIFT) -#define I40E_GLHMC_LANTXBASE(_i) (0x000C6200 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_LANTXBASE_MAX_INDEX 15 -#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT 0 -#define I40E_GLHMC_LANTXBASE_FPMLANTXBASE_MASK I40E_MASK(0xFFFFFF, I40E_GLHMC_LANTXBASE_FPMLANTXBASE_SHIFT) -#define I40E_GLHMC_LANTXBASE_RSVD_SHIFT 24 -#define I40E_GLHMC_LANTXBASE_RSVD_MASK I40E_MASK(0xFF, I40E_GLHMC_LANTXBASE_RSVD_SHIFT) -#define I40E_GLHMC_LANTXCNT(_i) (0x000C6300 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_LANTXCNT_MAX_INDEX 15 -#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT 0 -#define I40E_GLHMC_LANTXCNT_FPMLANTXCNT_MASK I40E_MASK(0x7FF, I40E_GLHMC_LANTXCNT_FPMLANTXCNT_SHIFT) -#define I40E_GLHMC_LANTXOBJSZ 0x000C2004 /* Reset: CORER */ -#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT 0 -#define I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_MASK I40E_MASK(0xF, I40E_GLHMC_LANTXOBJSZ_PMLANTXOBJSZ_SHIFT) -#define I40E_GLHMC_PFASSIGN(_i) (0x000C0c00 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_PFASSIGN_MAX_INDEX 15 -#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT 0 -#define I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_MASK I40E_MASK(0xF, I40E_GLHMC_PFASSIGN_PMFCNPFASSIGN_SHIFT) -#define I40E_GLHMC_SDPART(_i) (0x000C0800 + ((_i) * 4)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLHMC_SDPART_MAX_INDEX 15 -#define I40E_GLHMC_SDPART_PMSDBASE_SHIFT 0 -#define I40E_GLHMC_SDPART_PMSDBASE_MASK I40E_MASK(0xFFF, I40E_GLHMC_SDPART_PMSDBASE_SHIFT) -#define I40E_GLHMC_SDPART_PMSDSIZE_SHIFT 16 -#define I40E_GLHMC_SDPART_PMSDSIZE_MASK I40E_MASK(0x1FFF, I40E_GLHMC_SDPART_PMSDSIZE_SHIFT) -#define I40E_PFHMC_ERRORDATA 0x000C0500 /* Reset: PFR */ -#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT 0 -#define I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_MASK I40E_MASK(0x3FFFFFFF, I40E_PFHMC_ERRORDATA_HMC_ERROR_DATA_SHIFT) -#define I40E_PFHMC_ERRORINFO 0x000C0400 /* Reset: PFR */ -#define I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT 0 -#define I40E_PFHMC_ERRORINFO_PMF_INDEX_MASK I40E_MASK(0x1F, I40E_PFHMC_ERRORINFO_PMF_INDEX_SHIFT) -#define I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT 7 -#define I40E_PFHMC_ERRORINFO_PMF_ISVF_MASK I40E_MASK(0x1, I40E_PFHMC_ERRORINFO_PMF_ISVF_SHIFT) -#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT 8 -#define I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_MASK I40E_MASK(0xF, I40E_PFHMC_ERRORINFO_HMC_ERROR_TYPE_SHIFT) -#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT 16 -#define I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_MASK I40E_MASK(0x1F, I40E_PFHMC_ERRORINFO_HMC_OBJECT_TYPE_SHIFT) -#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT 31 -#define I40E_PFHMC_ERRORINFO_ERROR_DETECTED_MASK I40E_MASK(0x1, I40E_PFHMC_ERRORINFO_ERROR_DETECTED_SHIFT) -#define I40E_PFHMC_PDINV 0x000C0300 /* Reset: PFR */ -#define I40E_PFHMC_PDINV_PMSDIDX_SHIFT 0 -#define I40E_PFHMC_PDINV_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_PFHMC_PDINV_PMSDIDX_SHIFT) -#define I40E_PFHMC_PDINV_PMPDIDX_SHIFT 16 -#define I40E_PFHMC_PDINV_PMPDIDX_MASK I40E_MASK(0x1FF, I40E_PFHMC_PDINV_PMPDIDX_SHIFT) -#define I40E_PFHMC_SDCMD 0x000C0000 /* Reset: PFR */ -#define I40E_PFHMC_SDCMD_PMSDIDX_SHIFT 0 -#define I40E_PFHMC_SDCMD_PMSDIDX_MASK I40E_MASK(0xFFF, I40E_PFHMC_SDCMD_PMSDIDX_SHIFT) -#define I40E_PFHMC_SDCMD_PMSDWR_SHIFT 31 -#define I40E_PFHMC_SDCMD_PMSDWR_MASK I40E_MASK(0x1, I40E_PFHMC_SDCMD_PMSDWR_SHIFT) -#define I40E_PFHMC_SDDATAHIGH 0x000C0200 /* Reset: PFR */ -#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT 0 -#define I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_MASK I40E_MASK(0xFFFFFFFF, I40E_PFHMC_SDDATAHIGH_PMSDDATAHIGH_SHIFT) -#define I40E_PFHMC_SDDATALOW 0x000C0100 /* Reset: PFR */ -#define I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT 0 -#define I40E_PFHMC_SDDATALOW_PMSDVALID_MASK I40E_MASK(0x1, I40E_PFHMC_SDDATALOW_PMSDVALID_SHIFT) -#define I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT 1 -#define I40E_PFHMC_SDDATALOW_PMSDTYPE_MASK I40E_MASK(0x1, I40E_PFHMC_SDDATALOW_PMSDTYPE_SHIFT) -#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT 2 -#define I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_MASK I40E_MASK(0x3FF, I40E_PFHMC_SDDATALOW_PMSDBPCOUNT_SHIFT) -#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT 12 -#define I40E_PFHMC_SDDATALOW_PMSDDATALOW_MASK I40E_MASK(0xFFFFF, I40E_PFHMC_SDDATALOW_PMSDDATALOW_SHIFT) -#define I40E_GL_GP_FUSE(_i) (0x0009400C + ((_i) * 4)) /* _i=0...28 */ /* Reset: POR */ -#define I40E_GL_GP_FUSE_MAX_INDEX 28 -#define I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT 0 -#define I40E_GL_GP_FUSE_GL_GP_FUSE_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_GP_FUSE_GL_GP_FUSE_SHIFT) -#define I40E_GL_UFUSE 0x00094008 /* Reset: POR */ -#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT 1 -#define I40E_GL_UFUSE_FOUR_PORT_ENABLE_MASK I40E_MASK(0x1, I40E_GL_UFUSE_FOUR_PORT_ENABLE_SHIFT) -#define I40E_GL_UFUSE_NIC_ID_SHIFT 2 -#define I40E_GL_UFUSE_NIC_ID_MASK I40E_MASK(0x1, I40E_GL_UFUSE_NIC_ID_SHIFT) -#define I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT 10 -#define I40E_GL_UFUSE_ULT_LOCKOUT_MASK I40E_MASK(0x1, I40E_GL_UFUSE_ULT_LOCKOUT_SHIFT) -#define I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT 11 -#define I40E_GL_UFUSE_CLS_LOCKOUT_MASK I40E_MASK(0x1, I40E_GL_UFUSE_CLS_LOCKOUT_SHIFT) -#define I40E_EMPINT_GPIO_ENA 0x00088188 /* Reset: POR */ -#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT 0 -#define I40E_EMPINT_GPIO_ENA_GPIO0_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO0_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT 1 -#define I40E_EMPINT_GPIO_ENA_GPIO1_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO1_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT 2 -#define I40E_EMPINT_GPIO_ENA_GPIO2_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO2_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT 3 -#define I40E_EMPINT_GPIO_ENA_GPIO3_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO3_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT 4 -#define I40E_EMPINT_GPIO_ENA_GPIO4_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO4_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT 5 -#define I40E_EMPINT_GPIO_ENA_GPIO5_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO5_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT 6 -#define I40E_EMPINT_GPIO_ENA_GPIO6_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO6_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT 7 -#define I40E_EMPINT_GPIO_ENA_GPIO7_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO7_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT 8 -#define I40E_EMPINT_GPIO_ENA_GPIO8_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO8_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT 9 -#define I40E_EMPINT_GPIO_ENA_GPIO9_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO9_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT 10 -#define I40E_EMPINT_GPIO_ENA_GPIO10_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO10_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT 11 -#define I40E_EMPINT_GPIO_ENA_GPIO11_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO11_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT 12 -#define I40E_EMPINT_GPIO_ENA_GPIO12_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO12_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT 13 -#define I40E_EMPINT_GPIO_ENA_GPIO13_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO13_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT 14 -#define I40E_EMPINT_GPIO_ENA_GPIO14_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO14_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT 15 -#define I40E_EMPINT_GPIO_ENA_GPIO15_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO15_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT 16 -#define I40E_EMPINT_GPIO_ENA_GPIO16_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO16_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT 17 -#define I40E_EMPINT_GPIO_ENA_GPIO17_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO17_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT 18 -#define I40E_EMPINT_GPIO_ENA_GPIO18_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO18_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT 19 -#define I40E_EMPINT_GPIO_ENA_GPIO19_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO19_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT 20 -#define I40E_EMPINT_GPIO_ENA_GPIO20_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO20_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT 21 -#define I40E_EMPINT_GPIO_ENA_GPIO21_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO21_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT 22 -#define I40E_EMPINT_GPIO_ENA_GPIO22_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO22_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT 23 -#define I40E_EMPINT_GPIO_ENA_GPIO23_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO23_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT 24 -#define I40E_EMPINT_GPIO_ENA_GPIO24_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO24_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT 25 -#define I40E_EMPINT_GPIO_ENA_GPIO25_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO25_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT 26 -#define I40E_EMPINT_GPIO_ENA_GPIO26_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO26_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT 27 -#define I40E_EMPINT_GPIO_ENA_GPIO27_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO27_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT 28 -#define I40E_EMPINT_GPIO_ENA_GPIO28_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO28_ENA_SHIFT) -#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT 29 -#define I40E_EMPINT_GPIO_ENA_GPIO29_ENA_MASK I40E_MASK(0x1, I40E_EMPINT_GPIO_ENA_GPIO29_ENA_SHIFT) -#define I40E_PFGEN_PORTMDIO_NUM 0x0003F100 /* Reset: CORER */ -#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT 0 -#define I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_MASK I40E_MASK(0x3, I40E_PFGEN_PORTMDIO_NUM_PORT_NUM_SHIFT) -#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT 4 -#define I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_MASK I40E_MASK(0x1, I40E_PFGEN_PORTMDIO_NUM_VFLINK_STAT_ENA_SHIFT) -#define I40E_PFINT_AEQCTL 0x00038700 /* Reset: CORER */ -#define I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_PFINT_AEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_PFINT_AEQCTL_MSIX_INDX_SHIFT) -#define I40E_PFINT_AEQCTL_ITR_INDX_SHIFT 11 -#define I40E_PFINT_AEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_AEQCTL_ITR_INDX_SHIFT) -#define I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_PFINT_AEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_PFINT_AEQCTL_MSIX0_INDX_SHIFT) -#define I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_PFINT_AEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_AEQCTL_CAUSE_ENA_SHIFT) -#define I40E_PFINT_AEQCTL_INTEVENT_SHIFT 31 -#define I40E_PFINT_AEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_AEQCTL_INTEVENT_SHIFT) -#define I40E_PFINT_CEQCTL(_INTPF) (0x00036800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: CORER */ -#define I40E_PFINT_CEQCTL_MAX_INDEX 511 -#define I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_PFINT_CEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_PFINT_CEQCTL_MSIX_INDX_SHIFT) -#define I40E_PFINT_CEQCTL_ITR_INDX_SHIFT 11 -#define I40E_PFINT_CEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_CEQCTL_ITR_INDX_SHIFT) -#define I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_PFINT_CEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_PFINT_CEQCTL_MSIX0_INDX_SHIFT) -#define I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_PFINT_CEQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_CEQCTL_NEXTQ_INDX_SHIFT) -#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_PFINT_CEQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_CEQCTL_NEXTQ_TYPE_SHIFT) -#define I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT) -#define I40E_PFINT_CEQCTL_INTEVENT_SHIFT 31 -#define I40E_PFINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_INTEVENT_SHIFT) -#define I40E_PFINT_DYN_CTL0 0x00038480 /* Reset: PFR */ -#define I40E_PFINT_DYN_CTL0_INTENA_SHIFT 0 -#define I40E_PFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_SHIFT) -#define I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT 1 -#define I40E_PFINT_DYN_CTL0_CLEARPBA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_CLEARPBA_SHIFT) -#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2 -#define I40E_PFINT_DYN_CTL0_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_SWINT_TRIG_SHIFT) -#define I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT 3 -#define I40E_PFINT_DYN_CTL0_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTL0_ITR_INDX_SHIFT) -#define I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT 5 -#define I40E_PFINT_DYN_CTL0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTL0_INTERVAL_SHIFT) -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25 -#define I40E_PFINT_DYN_CTL0_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) -#define I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT 31 -#define I40E_PFINT_DYN_CTL0_INTENA_MSK_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_MSK_SHIFT) -#define I40E_PFINT_DYN_CTLN(_INTPF) (0x00034800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ -#define I40E_PFINT_DYN_CTLN_MAX_INDEX 511 -#define I40E_PFINT_DYN_CTLN_INTENA_SHIFT 0 -#define I40E_PFINT_DYN_CTLN_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_INTENA_SHIFT) -#define I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT 1 -#define I40E_PFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_CLEARPBA_SHIFT) -#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2 -#define I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SWINT_TRIG_SHIFT) -#define I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT 3 -#define I40E_PFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_ITR_INDX_SHIFT) -#define I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT 5 -#define I40E_PFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_DYN_CTLN_INTERVAL_SHIFT) -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 -#define I40E_PFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) -#define I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT 31 -#define I40E_PFINT_DYN_CTLN_INTENA_MSK_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTLN_INTENA_MSK_SHIFT) -#define I40E_PFINT_GPIO_ENA 0x00088080 /* Reset: CORER */ -#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT 0 -#define I40E_PFINT_GPIO_ENA_GPIO0_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO0_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT 1 -#define I40E_PFINT_GPIO_ENA_GPIO1_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO1_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT 2 -#define I40E_PFINT_GPIO_ENA_GPIO2_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO2_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT 3 -#define I40E_PFINT_GPIO_ENA_GPIO3_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO3_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT 4 -#define I40E_PFINT_GPIO_ENA_GPIO4_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO4_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT 5 -#define I40E_PFINT_GPIO_ENA_GPIO5_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO5_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT 6 -#define I40E_PFINT_GPIO_ENA_GPIO6_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO6_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT 7 -#define I40E_PFINT_GPIO_ENA_GPIO7_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO7_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT 8 -#define I40E_PFINT_GPIO_ENA_GPIO8_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO8_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT 9 -#define I40E_PFINT_GPIO_ENA_GPIO9_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO9_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT 10 -#define I40E_PFINT_GPIO_ENA_GPIO10_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO10_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT 11 -#define I40E_PFINT_GPIO_ENA_GPIO11_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO11_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT 12 -#define I40E_PFINT_GPIO_ENA_GPIO12_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO12_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT 13 -#define I40E_PFINT_GPIO_ENA_GPIO13_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO13_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT 14 -#define I40E_PFINT_GPIO_ENA_GPIO14_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO14_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT 15 -#define I40E_PFINT_GPIO_ENA_GPIO15_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO15_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT 16 -#define I40E_PFINT_GPIO_ENA_GPIO16_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO16_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT 17 -#define I40E_PFINT_GPIO_ENA_GPIO17_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO17_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT 18 -#define I40E_PFINT_GPIO_ENA_GPIO18_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO18_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT 19 -#define I40E_PFINT_GPIO_ENA_GPIO19_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO19_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT 20 -#define I40E_PFINT_GPIO_ENA_GPIO20_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO20_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT 21 -#define I40E_PFINT_GPIO_ENA_GPIO21_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO21_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT 22 -#define I40E_PFINT_GPIO_ENA_GPIO22_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO22_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT 23 -#define I40E_PFINT_GPIO_ENA_GPIO23_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO23_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT 24 -#define I40E_PFINT_GPIO_ENA_GPIO24_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO24_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT 25 -#define I40E_PFINT_GPIO_ENA_GPIO25_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO25_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT 26 -#define I40E_PFINT_GPIO_ENA_GPIO26_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO26_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT 27 -#define I40E_PFINT_GPIO_ENA_GPIO27_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO27_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT 28 -#define I40E_PFINT_GPIO_ENA_GPIO28_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO28_ENA_SHIFT) -#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT 29 -#define I40E_PFINT_GPIO_ENA_GPIO29_ENA_MASK I40E_MASK(0x1, I40E_PFINT_GPIO_ENA_GPIO29_ENA_SHIFT) -#define I40E_PFINT_ICR0 0x00038780 /* Reset: CORER */ -#define I40E_PFINT_ICR0_INTEVENT_SHIFT 0 -#define I40E_PFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_INTEVENT_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_0_SHIFT 1 -#define I40E_PFINT_ICR0_QUEUE_0_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_0_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_1_SHIFT 2 -#define I40E_PFINT_ICR0_QUEUE_1_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_1_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_2_SHIFT 3 -#define I40E_PFINT_ICR0_QUEUE_2_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_2_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_3_SHIFT 4 -#define I40E_PFINT_ICR0_QUEUE_3_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_3_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_4_SHIFT 5 -#define I40E_PFINT_ICR0_QUEUE_4_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_4_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_5_SHIFT 6 -#define I40E_PFINT_ICR0_QUEUE_5_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_5_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_6_SHIFT 7 -#define I40E_PFINT_ICR0_QUEUE_6_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_6_SHIFT) -#define I40E_PFINT_ICR0_QUEUE_7_SHIFT 8 -#define I40E_PFINT_ICR0_QUEUE_7_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_QUEUE_7_SHIFT) -#define I40E_PFINT_ICR0_ECC_ERR_SHIFT 16 -#define I40E_PFINT_ICR0_ECC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ECC_ERR_SHIFT) -#define I40E_PFINT_ICR0_MAL_DETECT_SHIFT 19 -#define I40E_PFINT_ICR0_MAL_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_MAL_DETECT_SHIFT) -#define I40E_PFINT_ICR0_GRST_SHIFT 20 -#define I40E_PFINT_ICR0_GRST_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_GRST_SHIFT) -#define I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT 21 -#define I40E_PFINT_ICR0_PCI_EXCEPTION_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_PCI_EXCEPTION_SHIFT) -#define I40E_PFINT_ICR0_GPIO_SHIFT 22 -#define I40E_PFINT_ICR0_GPIO_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_GPIO_SHIFT) -#define I40E_PFINT_ICR0_TIMESYNC_SHIFT 23 -#define I40E_PFINT_ICR0_TIMESYNC_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_TIMESYNC_SHIFT) -#define I40E_PFINT_ICR0_STORM_DETECT_SHIFT 24 -#define I40E_PFINT_ICR0_STORM_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_STORM_DETECT_SHIFT) -#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_PFINT_ICR0_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_LINK_STAT_CHANGE_SHIFT) -#define I40E_PFINT_ICR0_HMC_ERR_SHIFT 26 -#define I40E_PFINT_ICR0_HMC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_HMC_ERR_SHIFT) -#define I40E_PFINT_ICR0_PE_CRITERR_SHIFT 28 -#define I40E_PFINT_ICR0_PE_CRITERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_PE_CRITERR_SHIFT) -#define I40E_PFINT_ICR0_VFLR_SHIFT 29 -#define I40E_PFINT_ICR0_VFLR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_VFLR_SHIFT) -#define I40E_PFINT_ICR0_ADMINQ_SHIFT 30 -#define I40E_PFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ADMINQ_SHIFT) -#define I40E_PFINT_ICR0_SWINT_SHIFT 31 -#define I40E_PFINT_ICR0_SWINT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_SWINT_SHIFT) -#define I40E_PFINT_ICR0_ENA 0x00038800 /* Reset: CORER */ -#define I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT 16 -#define I40E_PFINT_ICR0_ENA_ECC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_ECC_ERR_SHIFT) -#define I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT 19 -#define I40E_PFINT_ICR0_ENA_MAL_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_MAL_DETECT_SHIFT) -#define I40E_PFINT_ICR0_ENA_GRST_SHIFT 20 -#define I40E_PFINT_ICR0_ENA_GRST_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_GRST_SHIFT) -#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT 21 -#define I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_SHIFT) -#define I40E_PFINT_ICR0_ENA_GPIO_SHIFT 22 -#define I40E_PFINT_ICR0_ENA_GPIO_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_GPIO_SHIFT) -#define I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT 23 -#define I40E_PFINT_ICR0_ENA_TIMESYNC_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_TIMESYNC_SHIFT) -#define I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT 24 -#define I40E_PFINT_ICR0_ENA_STORM_DETECT_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_STORM_DETECT_SHIFT) -#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) -#define I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT 26 -#define I40E_PFINT_ICR0_ENA_HMC_ERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_HMC_ERR_SHIFT) -#define I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT 28 -#define I40E_PFINT_ICR0_ENA_PE_CRITERR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_PE_CRITERR_SHIFT) -#define I40E_PFINT_ICR0_ENA_VFLR_SHIFT 29 -#define I40E_PFINT_ICR0_ENA_VFLR_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_VFLR_SHIFT) -#define I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT 30 -#define I40E_PFINT_ICR0_ENA_ADMINQ_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_ADMINQ_SHIFT) -#define I40E_PFINT_ICR0_ENA_RSVD_SHIFT 31 -#define I40E_PFINT_ICR0_ENA_RSVD_MASK I40E_MASK(0x1, I40E_PFINT_ICR0_ENA_RSVD_SHIFT) -#define I40E_PFINT_ITR0(_i) (0x00038000 + ((_i) * 128)) /* _i=0...2 */ /* Reset: PFR */ -#define I40E_PFINT_ITR0_MAX_INDEX 2 -#define I40E_PFINT_ITR0_INTERVAL_SHIFT 0 -#define I40E_PFINT_ITR0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_ITR0_INTERVAL_SHIFT) -#define I40E_PFINT_ITRN(_i, _INTPF) (0x00030000 + ((_i) * 2048 + (_INTPF) * 4)) /* _i=0...2, _INTPF=0...511 */ /* Reset: PFR */ -#define I40E_PFINT_ITRN_MAX_INDEX 2 -#define I40E_PFINT_ITRN_INTERVAL_SHIFT 0 -#define I40E_PFINT_ITRN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_PFINT_ITRN_INTERVAL_SHIFT) -#define I40E_PFINT_LNKLST0 0x00038500 /* Reset: PFR */ -#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT 0 -#define I40E_PFINT_LNKLST0_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_LNKLST0_FIRSTQ_INDX_SHIFT) -#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11 -#define I40E_PFINT_LNKLST0_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_LNKLST0_FIRSTQ_TYPE_SHIFT) -#define I40E_PFINT_LNKLSTN(_INTPF) (0x00035000 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ -#define I40E_PFINT_LNKLSTN_MAX_INDEX 511 -#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0 -#define I40E_PFINT_LNKLSTN_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_PFINT_LNKLSTN_FIRSTQ_INDX_SHIFT) -#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11 -#define I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_PFINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) -#define I40E_PFINT_RATE0 0x00038580 /* Reset: PFR */ -#define I40E_PFINT_RATE0_INTERVAL_SHIFT 0 -#define I40E_PFINT_RATE0_INTERVAL_MASK I40E_MASK(0x3F, I40E_PFINT_RATE0_INTERVAL_SHIFT) -#define I40E_PFINT_RATE0_INTRL_ENA_SHIFT 6 -#define I40E_PFINT_RATE0_INTRL_ENA_MASK I40E_MASK(0x1, I40E_PFINT_RATE0_INTRL_ENA_SHIFT) -#define I40E_PFINT_RATEN(_INTPF) (0x00035800 + ((_INTPF) * 4)) /* _i=0...511 */ /* Reset: PFR */ -#define I40E_PFINT_RATEN_MAX_INDEX 511 -#define I40E_PFINT_RATEN_INTERVAL_SHIFT 0 -#define I40E_PFINT_RATEN_INTERVAL_MASK I40E_MASK(0x3F, I40E_PFINT_RATEN_INTERVAL_SHIFT) -#define I40E_PFINT_RATEN_INTRL_ENA_SHIFT 6 -#define I40E_PFINT_RATEN_INTRL_ENA_MASK I40E_MASK(0x1, I40E_PFINT_RATEN_INTRL_ENA_SHIFT) -#define I40E_PFINT_STAT_CTL0 0x00038400 /* Reset: CORER */ -#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2 -#define I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_PFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) -#define I40E_QINT_RQCTL(_Q) (0x0003A000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ -#define I40E_QINT_RQCTL_MAX_INDEX 1535 -#define I40E_QINT_RQCTL_MSIX_INDX_SHIFT 0 -#define I40E_QINT_RQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_QINT_RQCTL_MSIX_INDX_SHIFT) -#define I40E_QINT_RQCTL_ITR_INDX_SHIFT 11 -#define I40E_QINT_RQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_QINT_RQCTL_ITR_INDX_SHIFT) -#define I40E_QINT_RQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_QINT_RQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_QINT_RQCTL_MSIX0_INDX_SHIFT) -#define I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_QINT_RQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_QINT_RQCTL_NEXTQ_INDX_SHIFT) -#define I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_QINT_RQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_QINT_RQCTL_NEXTQ_TYPE_SHIFT) -#define I40E_QINT_RQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_QINT_RQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_QINT_RQCTL_CAUSE_ENA_SHIFT) -#define I40E_QINT_RQCTL_INTEVENT_SHIFT 31 -#define I40E_QINT_RQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_QINT_RQCTL_INTEVENT_SHIFT) -#define I40E_QINT_TQCTL(_Q) (0x0003C000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ -#define I40E_QINT_TQCTL_MAX_INDEX 1535 -#define I40E_QINT_TQCTL_MSIX_INDX_SHIFT 0 -#define I40E_QINT_TQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_QINT_TQCTL_MSIX_INDX_SHIFT) -#define I40E_QINT_TQCTL_ITR_INDX_SHIFT 11 -#define I40E_QINT_TQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_QINT_TQCTL_ITR_INDX_SHIFT) -#define I40E_QINT_TQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_QINT_TQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_QINT_TQCTL_MSIX0_INDX_SHIFT) -#define I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_QINT_TQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_QINT_TQCTL_NEXTQ_INDX_SHIFT) -#define I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_QINT_TQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_QINT_TQCTL_NEXTQ_TYPE_SHIFT) -#define I40E_QINT_TQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_QINT_TQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_QINT_TQCTL_CAUSE_ENA_SHIFT) -#define I40E_QINT_TQCTL_INTEVENT_SHIFT 31 -#define I40E_QINT_TQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_QINT_TQCTL_INTEVENT_SHIFT) -#define I40E_VFINT_DYN_CTL0(_VF) (0x0002A400 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VFINT_DYN_CTL0_MAX_INDEX 127 -#define I40E_VFINT_DYN_CTL0_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_INTENA_SHIFT) -#define I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTL0_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_CLEARPBA_SHIFT) -#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTL0_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_SWINT_TRIG_SHIFT) -#define I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTL0_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL0_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTL0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTL0_INTERVAL_SHIFT) -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_SW_ITR_INDX_ENA_SHIFT) -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTL0_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTL0_SW_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTL0_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTL0_INTENA_MSK_SHIFT) -#define I40E_VFINT_DYN_CTLN(_INTVF) (0x00024800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ -#define I40E_VFINT_DYN_CTLN_MAX_INDEX 511 -#define I40E_VFINT_DYN_CTLN_INTENA_SHIFT 0 -#define I40E_VFINT_DYN_CTLN_INTENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_INTENA_SHIFT) -#define I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT 1 -#define I40E_VFINT_DYN_CTLN_CLEARPBA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_CLEARPBA_SHIFT) -#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT 2 -#define I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_SWINT_TRIG_SHIFT) -#define I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT 3 -#define I40E_VFINT_DYN_CTLN_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT 5 -#define I40E_VFINT_DYN_CTLN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_DYN_CTLN_INTERVAL_SHIFT) -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT 24 -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_SHIFT) -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT 25 -#define I40E_VFINT_DYN_CTLN_SW_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_DYN_CTLN_SW_ITR_INDX_SHIFT) -#define I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT 31 -#define I40E_VFINT_DYN_CTLN_INTENA_MSK_MASK I40E_MASK(0x1, I40E_VFINT_DYN_CTLN_INTENA_MSK_SHIFT) -#define I40E_VFINT_ICR0(_VF) (0x0002BC00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VFINT_ICR0_MAX_INDEX 127 -#define I40E_VFINT_ICR0_INTEVENT_SHIFT 0 -#define I40E_VFINT_ICR0_INTEVENT_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_INTEVENT_SHIFT) -#define I40E_VFINT_ICR0_QUEUE_0_SHIFT 1 -#define I40E_VFINT_ICR0_QUEUE_0_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_0_SHIFT) -#define I40E_VFINT_ICR0_QUEUE_1_SHIFT 2 -#define I40E_VFINT_ICR0_QUEUE_1_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_1_SHIFT) -#define I40E_VFINT_ICR0_QUEUE_2_SHIFT 3 -#define I40E_VFINT_ICR0_QUEUE_2_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_2_SHIFT) -#define I40E_VFINT_ICR0_QUEUE_3_SHIFT 4 -#define I40E_VFINT_ICR0_QUEUE_3_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_QUEUE_3_SHIFT) -#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_LINK_STAT_CHANGE_SHIFT) -#define I40E_VFINT_ICR0_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ADMINQ_SHIFT) -#define I40E_VFINT_ICR0_SWINT_SHIFT 31 -#define I40E_VFINT_ICR0_SWINT_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_SWINT_SHIFT) -#define I40E_VFINT_ICR0_ENA(_VF) (0x0002C000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VFINT_ICR0_ENA_MAX_INDEX 127 -#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT 25 -#define I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_LINK_STAT_CHANGE_SHIFT) -#define I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT 30 -#define I40E_VFINT_ICR0_ENA_ADMINQ_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_ADMINQ_SHIFT) -#define I40E_VFINT_ICR0_ENA_RSVD_SHIFT 31 -#define I40E_VFINT_ICR0_ENA_RSVD_MASK I40E_MASK(0x1, I40E_VFINT_ICR0_ENA_RSVD_SHIFT) -#define I40E_VFINT_ITR0(_i, _VF) (0x00028000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...2, _VF=0...127 */ /* Reset: VFR */ -#define I40E_VFINT_ITR0_MAX_INDEX 2 -#define I40E_VFINT_ITR0_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITR0_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITR0_INTERVAL_SHIFT) -#define I40E_VFINT_ITRN(_i, _INTVF) (0x00020000 + ((_i) * 2048 + (_INTVF) * 4)) /* _i=0...2, _INTVF=0...511 */ /* Reset: VFR */ -#define I40E_VFINT_ITRN_MAX_INDEX 2 -#define I40E_VFINT_ITRN_INTERVAL_SHIFT 0 -#define I40E_VFINT_ITRN_INTERVAL_MASK I40E_MASK(0xFFF, I40E_VFINT_ITRN_INTERVAL_SHIFT) -#define I40E_VFINT_STAT_CTL0(_VF) (0x0002A000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VFINT_STAT_CTL0_MAX_INDEX 127 -#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT 2 -#define I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_MASK I40E_MASK(0x3, I40E_VFINT_STAT_CTL0_OTHER_ITR_INDX_SHIFT) -#define I40E_VPINT_AEQCTL(_VF) (0x0002B800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VPINT_AEQCTL_MAX_INDEX 127 -#define I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_VPINT_AEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_VPINT_AEQCTL_MSIX_INDX_SHIFT) -#define I40E_VPINT_AEQCTL_ITR_INDX_SHIFT 11 -#define I40E_VPINT_AEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_VPINT_AEQCTL_ITR_INDX_SHIFT) -#define I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_VPINT_AEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_VPINT_AEQCTL_MSIX0_INDX_SHIFT) -#define I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_VPINT_AEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_VPINT_AEQCTL_CAUSE_ENA_SHIFT) -#define I40E_VPINT_AEQCTL_INTEVENT_SHIFT 31 -#define I40E_VPINT_AEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_VPINT_AEQCTL_INTEVENT_SHIFT) -#define I40E_VPINT_CEQCTL(_INTVF) (0x00026800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: CORER */ -#define I40E_VPINT_CEQCTL_MAX_INDEX 511 -#define I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT 0 -#define I40E_VPINT_CEQCTL_MSIX_INDX_MASK I40E_MASK(0xFF, I40E_VPINT_CEQCTL_MSIX_INDX_SHIFT) -#define I40E_VPINT_CEQCTL_ITR_INDX_SHIFT 11 -#define I40E_VPINT_CEQCTL_ITR_INDX_MASK I40E_MASK(0x3, I40E_VPINT_CEQCTL_ITR_INDX_SHIFT) -#define I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT 13 -#define I40E_VPINT_CEQCTL_MSIX0_INDX_MASK I40E_MASK(0x7, I40E_VPINT_CEQCTL_MSIX0_INDX_SHIFT) -#define I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT 16 -#define I40E_VPINT_CEQCTL_NEXTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_CEQCTL_NEXTQ_INDX_SHIFT) -#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT 27 -#define I40E_VPINT_CEQCTL_NEXTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_CEQCTL_NEXTQ_TYPE_SHIFT) -#define I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT 30 -#define I40E_VPINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_VPINT_CEQCTL_CAUSE_ENA_SHIFT) -#define I40E_VPINT_CEQCTL_INTEVENT_SHIFT 31 -#define I40E_VPINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_VPINT_CEQCTL_INTEVENT_SHIFT) -#define I40E_VPINT_LNKLST0(_VF) (0x0002A800 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VPINT_LNKLST0_MAX_INDEX 127 -#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT 0 -#define I40E_VPINT_LNKLST0_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_LNKLST0_FIRSTQ_INDX_SHIFT) -#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT 11 -#define I40E_VPINT_LNKLST0_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_LNKLST0_FIRSTQ_TYPE_SHIFT) -#define I40E_VPINT_LNKLSTN(_INTVF) (0x00025000 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ -#define I40E_VPINT_LNKLSTN_MAX_INDEX 511 -#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT 0 -#define I40E_VPINT_LNKLSTN_FIRSTQ_INDX_MASK I40E_MASK(0x7FF, I40E_VPINT_LNKLSTN_FIRSTQ_INDX_SHIFT) -#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT 11 -#define I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_MASK I40E_MASK(0x3, I40E_VPINT_LNKLSTN_FIRSTQ_TYPE_SHIFT) -#define I40E_VPINT_RATE0(_VF) (0x0002AC00 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VPINT_RATE0_MAX_INDEX 127 -#define I40E_VPINT_RATE0_INTERVAL_SHIFT 0 -#define I40E_VPINT_RATE0_INTERVAL_MASK I40E_MASK(0x3F, I40E_VPINT_RATE0_INTERVAL_SHIFT) -#define I40E_VPINT_RATE0_INTRL_ENA_SHIFT 6 -#define I40E_VPINT_RATE0_INTRL_ENA_MASK I40E_MASK(0x1, I40E_VPINT_RATE0_INTRL_ENA_SHIFT) -#define I40E_VPINT_RATEN(_INTVF) (0x00025800 + ((_INTVF) * 4)) /* _i=0...511 */ /* Reset: VFR */ -#define I40E_VPINT_RATEN_MAX_INDEX 511 -#define I40E_VPINT_RATEN_INTERVAL_SHIFT 0 -#define I40E_VPINT_RATEN_INTERVAL_MASK I40E_MASK(0x3F, I40E_VPINT_RATEN_INTERVAL_SHIFT) -#define I40E_VPINT_RATEN_INTRL_ENA_SHIFT 6 -#define I40E_VPINT_RATEN_INTRL_ENA_MASK I40E_MASK(0x1, I40E_VPINT_RATEN_INTRL_ENA_SHIFT) -#define I40E_GL_RDPU_CNTRL 0x00051060 /* Reset: CORER */ -#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT 0 -#define I40E_GL_RDPU_CNTRL_RX_PAD_EN_MASK I40E_MASK(0x1, I40E_GL_RDPU_CNTRL_RX_PAD_EN_SHIFT) -#define I40E_GL_RDPU_CNTRL_ECO_SHIFT 1 -#define I40E_GL_RDPU_CNTRL_ECO_MASK I40E_MASK(0x7FFFFFFF, I40E_GL_RDPU_CNTRL_ECO_SHIFT) -#define I40E_GLLAN_RCTL_0 0x0012A500 /* Reset: CORER */ -#define I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT 0 -#define I40E_GLLAN_RCTL_0_PXE_MODE_MASK I40E_MASK(0x1, I40E_GLLAN_RCTL_0_PXE_MODE_SHIFT) -#define I40E_GLLAN_TSOMSK_F 0x000442D8 /* Reset: CORER */ -#define I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT 0 -#define I40E_GLLAN_TSOMSK_F_TCPMSKF_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_F_TCPMSKF_SHIFT) -#define I40E_GLLAN_TSOMSK_L 0x000442E0 /* Reset: CORER */ -#define I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT 0 -#define I40E_GLLAN_TSOMSK_L_TCPMSKL_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_L_TCPMSKL_SHIFT) -#define I40E_GLLAN_TSOMSK_M 0x000442DC /* Reset: CORER */ -#define I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT 0 -#define I40E_GLLAN_TSOMSK_M_TCPMSKM_MASK I40E_MASK(0xFFF, I40E_GLLAN_TSOMSK_M_TCPMSKM_SHIFT) -#define I40E_GLLAN_TXPRE_QDIS(_i) (0x000e6500 + ((_i) * 4)) /* _i=0...11 */ /* Reset: CORER */ -#define I40E_GLLAN_TXPRE_QDIS_MAX_INDEX 11 -#define I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT 0 -#define I40E_GLLAN_TXPRE_QDIS_QINDX_MASK I40E_MASK(0x7FF, I40E_GLLAN_TXPRE_QDIS_QINDX_SHIFT) -#define I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_SHIFT 16 -#define I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_QDIS_STAT_SHIFT) -#define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT 30 -#define I40E_GLLAN_TXPRE_QDIS_SET_QDIS_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_SET_QDIS_SHIFT) -#define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT 31 -#define I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_MASK I40E_MASK(0x1, I40E_GLLAN_TXPRE_QDIS_CLEAR_QDIS_SHIFT) -#define I40E_PFLAN_QALLOC 0x001C0400 /* Reset: CORER */ -#define I40E_PFLAN_QALLOC_FIRSTQ_SHIFT 0 -#define I40E_PFLAN_QALLOC_FIRSTQ_MASK I40E_MASK(0x7FF, I40E_PFLAN_QALLOC_FIRSTQ_SHIFT) -#define I40E_PFLAN_QALLOC_LASTQ_SHIFT 16 -#define I40E_PFLAN_QALLOC_LASTQ_MASK I40E_MASK(0x7FF, I40E_PFLAN_QALLOC_LASTQ_SHIFT) -#define I40E_PFLAN_QALLOC_VALID_SHIFT 31 -#define I40E_PFLAN_QALLOC_VALID_MASK I40E_MASK(0x1, I40E_PFLAN_QALLOC_VALID_SHIFT) -#define I40E_QRX_ENA(_Q) (0x00120000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ -#define I40E_QRX_ENA_MAX_INDEX 1535 -#define I40E_QRX_ENA_QENA_REQ_SHIFT 0 -#define I40E_QRX_ENA_QENA_REQ_MASK I40E_MASK(0x1, I40E_QRX_ENA_QENA_REQ_SHIFT) -#define I40E_QRX_ENA_FAST_QDIS_SHIFT 1 -#define I40E_QRX_ENA_FAST_QDIS_MASK I40E_MASK(0x1, I40E_QRX_ENA_FAST_QDIS_SHIFT) -#define I40E_QRX_ENA_QENA_STAT_SHIFT 2 -#define I40E_QRX_ENA_QENA_STAT_MASK I40E_MASK(0x1, I40E_QRX_ENA_QENA_STAT_SHIFT) -#define I40E_QRX_TAIL(_Q) (0x00128000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ -#define I40E_QRX_TAIL_MAX_INDEX 1535 -#define I40E_QRX_TAIL_TAIL_SHIFT 0 -#define I40E_QRX_TAIL_TAIL_MASK I40E_MASK(0x1FFF, I40E_QRX_TAIL_TAIL_SHIFT) -#define I40E_QTX_CTL(_Q) (0x00104000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ -#define I40E_QTX_CTL_MAX_INDEX 1535 -#define I40E_QTX_CTL_PFVF_Q_SHIFT 0 -#define I40E_QTX_CTL_PFVF_Q_MASK I40E_MASK(0x3, I40E_QTX_CTL_PFVF_Q_SHIFT) -#define I40E_QTX_CTL_PF_INDX_SHIFT 2 -#define I40E_QTX_CTL_PF_INDX_MASK I40E_MASK(0xF, I40E_QTX_CTL_PF_INDX_SHIFT) -#define I40E_QTX_CTL_VFVM_INDX_SHIFT 7 -#define I40E_QTX_CTL_VFVM_INDX_MASK I40E_MASK(0x1FF, I40E_QTX_CTL_VFVM_INDX_SHIFT) -#define I40E_QTX_ENA(_Q) (0x00100000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ -#define I40E_QTX_ENA_MAX_INDEX 1535 -#define I40E_QTX_ENA_QENA_REQ_SHIFT 0 -#define I40E_QTX_ENA_QENA_REQ_MASK I40E_MASK(0x1, I40E_QTX_ENA_QENA_REQ_SHIFT) -#define I40E_QTX_ENA_FAST_QDIS_SHIFT 1 -#define I40E_QTX_ENA_FAST_QDIS_MASK I40E_MASK(0x1, I40E_QTX_ENA_FAST_QDIS_SHIFT) -#define I40E_QTX_ENA_QENA_STAT_SHIFT 2 -#define I40E_QTX_ENA_QENA_STAT_MASK I40E_MASK(0x1, I40E_QTX_ENA_QENA_STAT_SHIFT) -#define I40E_QTX_HEAD(_Q) (0x000E4000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: CORER */ -#define I40E_QTX_HEAD_MAX_INDEX 1535 -#define I40E_QTX_HEAD_HEAD_SHIFT 0 -#define I40E_QTX_HEAD_HEAD_MASK I40E_MASK(0x1FFF, I40E_QTX_HEAD_HEAD_SHIFT) -#define I40E_QTX_HEAD_RS_PENDING_SHIFT 16 -#define I40E_QTX_HEAD_RS_PENDING_MASK I40E_MASK(0x1, I40E_QTX_HEAD_RS_PENDING_SHIFT) -#define I40E_QTX_TAIL(_Q) (0x00108000 + ((_Q) * 4)) /* _i=0...1535 */ /* Reset: PFR */ -#define I40E_QTX_TAIL_MAX_INDEX 1535 -#define I40E_QTX_TAIL_TAIL_SHIFT 0 -#define I40E_QTX_TAIL_TAIL_MASK I40E_MASK(0x1FFF, I40E_QTX_TAIL_TAIL_SHIFT) -#define I40E_VPLAN_MAPENA(_VF) (0x00074000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VPLAN_MAPENA_MAX_INDEX 127 -#define I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT 0 -#define I40E_VPLAN_MAPENA_TXRX_ENA_MASK I40E_MASK(0x1, I40E_VPLAN_MAPENA_TXRX_ENA_SHIFT) -#define I40E_VPLAN_QTABLE(_i, _VF) (0x00070000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: VFR */ -#define I40E_VPLAN_QTABLE_MAX_INDEX 15 -#define I40E_VPLAN_QTABLE_QINDEX_SHIFT 0 -#define I40E_VPLAN_QTABLE_QINDEX_MASK I40E_MASK(0x7FF, I40E_VPLAN_QTABLE_QINDEX_SHIFT) -#define I40E_VSILAN_QBASE(_VSI) (0x0020C800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: PFR */ -#define I40E_VSILAN_QBASE_MAX_INDEX 383 -#define I40E_VSILAN_QBASE_VSIBASE_SHIFT 0 -#define I40E_VSILAN_QBASE_VSIBASE_MASK I40E_MASK(0x7FF, I40E_VSILAN_QBASE_VSIBASE_SHIFT) -#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT 11 -#define I40E_VSILAN_QBASE_VSIQTABLE_ENA_MASK I40E_MASK(0x1, I40E_VSILAN_QBASE_VSIQTABLE_ENA_SHIFT) -#define I40E_VSILAN_QTABLE(_i, _VSI) (0x00200000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...7, _VSI=0...383 */ /* Reset: PFR */ -#define I40E_VSILAN_QTABLE_MAX_INDEX 7 -#define I40E_VSILAN_QTABLE_QINDEX_0_SHIFT 0 -#define I40E_VSILAN_QTABLE_QINDEX_0_MASK I40E_MASK(0x7FF, I40E_VSILAN_QTABLE_QINDEX_0_SHIFT) -#define I40E_VSILAN_QTABLE_QINDEX_1_SHIFT 16 -#define I40E_VSILAN_QTABLE_QINDEX_1_MASK I40E_MASK(0x7FF, I40E_VSILAN_QTABLE_QINDEX_1_SHIFT) -#define I40E_PRTGL_SAH 0x001E2140 /* Reset: GLOBR */ -#define I40E_PRTGL_SAH_FC_SAH_SHIFT 0 -#define I40E_PRTGL_SAH_FC_SAH_MASK I40E_MASK(0xFFFF, I40E_PRTGL_SAH_FC_SAH_SHIFT) -#define I40E_PRTGL_SAH_MFS_SHIFT 16 -#define I40E_PRTGL_SAH_MFS_MASK I40E_MASK(0xFFFF, I40E_PRTGL_SAH_MFS_SHIFT) -#define I40E_PRTGL_SAL 0x001E2120 /* Reset: GLOBR */ -#define I40E_PRTGL_SAL_FC_SAL_SHIFT 0 -#define I40E_PRTGL_SAL_FC_SAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTGL_SAL_FC_SAL_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP 0x001E30E0 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GCP_HSEC_CTL_RX_ENABLE_GCP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP 0x001E3260 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_GPP_HSEC_CTL_RX_ENABLE_GPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP 0x001E32E0 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_ENABLE_PPP_HSEC_CTL_RX_ENABLE_PPP_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL 0x001E3360 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_MASK I40E_MASK(0x1, I40E_PRTMAC_HSEC_CTL_RX_FORWARD_CONTROL_HSEC_CTL_RX_FORWARD_CONTROL_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1 0x001E3110 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_HSEC_CTL_RX_PAUSE_DA_UCAST_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2 0x001E3120 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_HSEC_CTL_RX_PAUSE_DA_UCAST_PART2_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE 0x001E30C0 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_MASK I40E_MASK(0x1FF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_ENABLE_HSEC_CTL_RX_PAUSE_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1 0x001E3140 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART1_HSEC_CTL_RX_PAUSE_SA_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2 0x001E3150 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_RX_PAUSE_SA_PART2_HSEC_CTL_RX_PAUSE_SA_PART2_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE 0x001E30D0 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_MASK I40E_MASK(0x1FF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_ENABLE_HSEC_CTL_TX_PAUSE_ENABLE_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA(_i) (0x001E3370 + ((_i) * 16)) /* _i=0...8 */ /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_MAX_INDEX 8 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_QUANTA_HSEC_CTL_TX_PAUSE_QUANTA_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER(_i) (0x001E3400 + ((_i) * 16)) /* _i=0...8 */ /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MAX_INDEX 8 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1 0x001E34B0 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTMAC_HSEC_CTL_TX_SA_PART1_HSEC_CTL_TX_SA_PART1_SHIFT) -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2 0x001E34C0 /* Reset: GLOBR */ -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT 0 -#define I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_MASK I40E_MASK(0xFFFF, I40E_PRTMAC_HSEC_CTL_TX_SA_PART2_HSEC_CTL_TX_SA_PART2_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A 0x0008C480 /* Reset: GLOBR */ -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT 0 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE3_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT 2 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE2_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT 4 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE1_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT 6 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_TX_LANE0_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT 8 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE3_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT 10 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE2_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT 12 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE1_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT 14 -#define I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_A_SWAP_RX_LANE0_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B 0x0008C484 /* Reset: GLOBR */ -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT 0 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE3_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT 2 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE2_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT 4 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE1_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT 6 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_TX_LANE0_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT 8 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE3_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT 10 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE2_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT 12 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE1_SHIFT) -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT 14 -#define I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_MASK I40E_MASK(0x3, I40E_PRTMAC_PCS_XAUI_SWAP_B_SWAP_RX_LANE0_SHIFT) -#define I40E_GL_FWRESETCNT 0x00083100 /* Reset: POR */ -#define I40E_GL_FWRESETCNT_FWRESETCNT_SHIFT 0 -#define I40E_GL_FWRESETCNT_FWRESETCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FWRESETCNT_FWRESETCNT_SHIFT) -#define I40E_GL_MNG_FWSM 0x000B6134 /* Reset: POR */ -#define I40E_GL_MNG_FWSM_FW_MODES_SHIFT 0 -#define I40E_GL_MNG_FWSM_FW_MODES_MASK I40E_MASK(0x3, I40E_GL_MNG_FWSM_FW_MODES_SHIFT) -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT 10 -#define I40E_GL_MNG_FWSM_EEP_RELOAD_IND_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_EEP_RELOAD_IND_SHIFT) -#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT 11 -#define I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_MASK I40E_MASK(0xF, I40E_GL_MNG_FWSM_CRC_ERROR_MODULE_SHIFT) -#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT 15 -#define I40E_GL_MNG_FWSM_FW_STATUS_VALID_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_FW_STATUS_VALID_SHIFT) -#define I40E_GL_MNG_FWSM_RESET_CNT_SHIFT 16 -#define I40E_GL_MNG_FWSM_RESET_CNT_MASK I40E_MASK(0x7, I40E_GL_MNG_FWSM_RESET_CNT_SHIFT) -#define I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT 19 -#define I40E_GL_MNG_FWSM_EXT_ERR_IND_MASK I40E_MASK(0x3F, I40E_GL_MNG_FWSM_EXT_ERR_IND_SHIFT) -#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT 26 -#define I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES0_CONFIG_ERR_SHIFT) -#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT 27 -#define I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES1_CONFIG_ERR_SHIFT) -#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT 28 -#define I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES2_CONFIG_ERR_SHIFT) -#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT 29 -#define I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_MASK I40E_MASK(0x1, I40E_GL_MNG_FWSM_PHY_SERDES3_CONFIG_ERR_SHIFT) -#define I40E_GL_MNG_HWARB_CTRL 0x000B6130 /* Reset: POR */ -#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT 0 -#define I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_MASK I40E_MASK(0x1, I40E_GL_MNG_HWARB_CTRL_NCSI_ARB_EN_SHIFT) -#define I40E_PRT_MNG_FTFT_DATA(_i) (0x000852A0 + ((_i) * 32)) /* _i=0...31 */ /* Reset: POR */ -#define I40E_PRT_MNG_FTFT_DATA_MAX_INDEX 31 -#define I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT 0 -#define I40E_PRT_MNG_FTFT_DATA_DWORD_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_FTFT_DATA_DWORD_SHIFT) -#define I40E_PRT_MNG_FTFT_LENGTH 0x00085260 /* Reset: POR */ -#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT 0 -#define I40E_PRT_MNG_FTFT_LENGTH_LENGTH_MASK I40E_MASK(0xFF, I40E_PRT_MNG_FTFT_LENGTH_LENGTH_SHIFT) -#define I40E_PRT_MNG_FTFT_MASK(_i) (0x00085160 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ -#define I40E_PRT_MNG_FTFT_MASK_MAX_INDEX 7 -#define I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT 0 -#define I40E_PRT_MNG_FTFT_MASK_MASK_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_FTFT_MASK_MASK_SHIFT) -#define I40E_PRT_MNG_MANC 0x00256A20 /* Reset: POR */ -#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT 0 -#define I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_FLOW_CONTROL_DISCARD_SHIFT) -#define I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT 1 -#define I40E_PRT_MNG_MANC_NCSI_DISCARD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_NCSI_DISCARD_SHIFT) -#define I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT 17 -#define I40E_PRT_MNG_MANC_RCV_TCO_EN_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_RCV_TCO_EN_SHIFT) -#define I40E_PRT_MNG_MANC_RCV_ALL_SHIFT 19 -#define I40E_PRT_MNG_MANC_RCV_ALL_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_RCV_ALL_SHIFT) -#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT 25 -#define I40E_PRT_MNG_MANC_FIXED_NET_TYPE_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_FIXED_NET_TYPE_SHIFT) -#define I40E_PRT_MNG_MANC_NET_TYPE_SHIFT 26 -#define I40E_PRT_MNG_MANC_NET_TYPE_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_NET_TYPE_SHIFT) -#define I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT 28 -#define I40E_PRT_MNG_MANC_EN_BMC2OS_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_EN_BMC2OS_SHIFT) -#define I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT 29 -#define I40E_PRT_MNG_MANC_EN_BMC2NET_MASK I40E_MASK(0x1, I40E_PRT_MNG_MANC_EN_BMC2NET_SHIFT) -#define I40E_PRT_MNG_MAVTV(_i) (0x00255900 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ -#define I40E_PRT_MNG_MAVTV_MAX_INDEX 7 -#define I40E_PRT_MNG_MAVTV_VID_SHIFT 0 -#define I40E_PRT_MNG_MAVTV_VID_MASK I40E_MASK(0xFFF, I40E_PRT_MNG_MAVTV_VID_SHIFT) -#define I40E_PRT_MNG_MDEF(_i) (0x00255D00 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ -#define I40E_PRT_MNG_MDEF_MAX_INDEX 7 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT 0 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_MAC_EXACT_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT 4 -#define I40E_PRT_MNG_MDEF_BROADCAST_AND_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_BROADCAST_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT 5 -#define I40E_PRT_MNG_MDEF_VLAN_AND_MASK I40E_MASK(0xFF, I40E_PRT_MNG_MDEF_VLAN_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT 13 -#define I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_IPV4_ADDRESS_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT 17 -#define I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_IPV6_ADDRESS_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT 21 -#define I40E_PRT_MNG_MDEF_MAC_EXACT_OR_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_MAC_EXACT_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT 25 -#define I40E_PRT_MNG_MDEF_BROADCAST_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_BROADCAST_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT 26 -#define I40E_PRT_MNG_MDEF_MULTICAST_AND_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_MULTICAST_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT 27 -#define I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_ARP_REQUEST_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT 28 -#define I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_ARP_RESPONSE_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT 29 -#define I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_NEIGHBOR_DISCOVERY_134_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT 30 -#define I40E_PRT_MNG_MDEF_PORT_0X298_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_PORT_0X298_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT 31 -#define I40E_PRT_MNG_MDEF_PORT_0X26F_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_PORT_0X26F_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT(_i) (0x00255F00 + ((_i) * 32)) /* _i=0...7 */ /* Reset: POR */ -#define I40E_PRT_MNG_MDEF_EXT_MAX_INDEX 7 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT 0 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_AND_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT 4 -#define I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_MASK I40E_MASK(0xF, I40E_PRT_MNG_MDEF_EXT_L2_ETHERTYPE_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT 8 -#define I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEF_EXT_FLEX_PORT_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT 24 -#define I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_FLEX_TCO_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT 25 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_135_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT 26 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_136_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT 27 -#define I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_NEIGHBOR_DISCOVERY_137_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT 28 -#define I40E_PRT_MNG_MDEF_EXT_ICMP_OR_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_ICMP_OR_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT 29 -#define I40E_PRT_MNG_MDEF_EXT_MLD_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_MLD_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT 30 -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_APPLY_TO_NETWORK_TRAFFIC_SHIFT) -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT 31 -#define I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_MASK I40E_MASK(0x1, I40E_PRT_MNG_MDEF_EXT_APPLY_TO_HOST_TRAFFIC_SHIFT) -#define I40E_PRT_MNG_MDEFVSI(_i) (0x00256580 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_PRT_MNG_MDEFVSI_MAX_INDEX 3 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT 0 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEFVSI_MDEFVSI_2N_SHIFT) -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT 16 -#define I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MDEFVSI_MDEFVSI_2NP1_SHIFT) -#define I40E_PRT_MNG_METF(_i) (0x00256780 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_PRT_MNG_METF_MAX_INDEX 3 -#define I40E_PRT_MNG_METF_ETYPE_SHIFT 0 -#define I40E_PRT_MNG_METF_ETYPE_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_METF_ETYPE_SHIFT) -#define I40E_PRT_MNG_METF_POLARITY_SHIFT 30 -#define I40E_PRT_MNG_METF_POLARITY_MASK I40E_MASK(0x1, I40E_PRT_MNG_METF_POLARITY_SHIFT) -#define I40E_PRT_MNG_MFUTP(_i) (0x00254E00 + ((_i) * 32)) /* _i=0...15 */ /* Reset: POR */ -#define I40E_PRT_MNG_MFUTP_MAX_INDEX 15 -#define I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT 0 -#define I40E_PRT_MNG_MFUTP_MFUTP_N_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MFUTP_MFUTP_N_SHIFT) -#define I40E_PRT_MNG_MFUTP_UDP_SHIFT 16 -#define I40E_PRT_MNG_MFUTP_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_UDP_SHIFT) -#define I40E_PRT_MNG_MFUTP_TCP_SHIFT 17 -#define I40E_PRT_MNG_MFUTP_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_TCP_SHIFT) -#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT 18 -#define I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_MASK I40E_MASK(0x1, I40E_PRT_MNG_MFUTP_SOURCE_DESTINATION_SHIFT) -#define I40E_PRT_MNG_MIPAF4(_i) (0x00256280 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_PRT_MNG_MIPAF4_MAX_INDEX 3 -#define I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT 0 -#define I40E_PRT_MNG_MIPAF4_MIPAF_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MIPAF4_MIPAF_SHIFT) -#define I40E_PRT_MNG_MIPAF6(_i) (0x00254200 + ((_i) * 32)) /* _i=0...15 */ /* Reset: POR */ -#define I40E_PRT_MNG_MIPAF6_MAX_INDEX 15 -#define I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT 0 -#define I40E_PRT_MNG_MIPAF6_MIPAF_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MIPAF6_MIPAF_SHIFT) -#define I40E_PRT_MNG_MMAH(_i) (0x00256380 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_PRT_MNG_MMAH_MAX_INDEX 3 -#define I40E_PRT_MNG_MMAH_MMAH_SHIFT 0 -#define I40E_PRT_MNG_MMAH_MMAH_MASK I40E_MASK(0xFFFF, I40E_PRT_MNG_MMAH_MMAH_SHIFT) -#define I40E_PRT_MNG_MMAL(_i) (0x00256480 + ((_i) * 32)) /* _i=0...3 */ /* Reset: POR */ -#define I40E_PRT_MNG_MMAL_MAX_INDEX 3 -#define I40E_PRT_MNG_MMAL_MMAL_SHIFT 0 -#define I40E_PRT_MNG_MMAL_MMAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRT_MNG_MMAL_MMAL_SHIFT) -#define I40E_PRT_MNG_MNGONLY 0x00256A60 /* Reset: POR */ -#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT 0 -#define I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_MASK I40E_MASK(0xFF, I40E_PRT_MNG_MNGONLY_EXCLUSIVE_TO_MANAGEABILITY_SHIFT) -#define I40E_PRT_MNG_MSFM 0x00256AA0 /* Reset: POR */ -#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT 0 -#define I40E_PRT_MNG_MSFM_PORT_26F_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_26F_UDP_SHIFT) -#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT 1 -#define I40E_PRT_MNG_MSFM_PORT_26F_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_26F_TCP_SHIFT) -#define I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT 2 -#define I40E_PRT_MNG_MSFM_PORT_298_UDP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_298_UDP_SHIFT) -#define I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT 3 -#define I40E_PRT_MNG_MSFM_PORT_298_TCP_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_PORT_298_TCP_SHIFT) -#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT 4 -#define I40E_PRT_MNG_MSFM_IPV6_0_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_0_MASK_SHIFT) -#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT 5 -#define I40E_PRT_MNG_MSFM_IPV6_1_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_1_MASK_SHIFT) -#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT 6 -#define I40E_PRT_MNG_MSFM_IPV6_2_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_2_MASK_SHIFT) -#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT 7 -#define I40E_PRT_MNG_MSFM_IPV6_3_MASK_MASK I40E_MASK(0x1, I40E_PRT_MNG_MSFM_IPV6_3_MASK_SHIFT) -#define I40E_MSIX_PBA(_i) (0x00001000 + ((_i) * 4)) /* _i=0...5 */ /* Reset: FLR */ -#define I40E_MSIX_PBA_MAX_INDEX 5 -#define I40E_MSIX_PBA_PENBIT_SHIFT 0 -#define I40E_MSIX_PBA_PENBIT_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_PBA_PENBIT_SHIFT) -#define I40E_MSIX_TADD(_i) (0x00000000 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ -#define I40E_MSIX_TADD_MAX_INDEX 128 -#define I40E_MSIX_TADD_MSIXTADD10_SHIFT 0 -#define I40E_MSIX_TADD_MSIXTADD10_MASK I40E_MASK(0x3, I40E_MSIX_TADD_MSIXTADD10_SHIFT) -#define I40E_MSIX_TADD_MSIXTADD_SHIFT 2 -#define I40E_MSIX_TADD_MSIXTADD_MASK I40E_MASK(0x3FFFFFFF, I40E_MSIX_TADD_MSIXTADD_SHIFT) -#define I40E_MSIX_TMSG(_i) (0x00000008 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ -#define I40E_MSIX_TMSG_MAX_INDEX 128 -#define I40E_MSIX_TMSG_MSIXTMSG_SHIFT 0 -#define I40E_MSIX_TMSG_MSIXTMSG_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_TMSG_MSIXTMSG_SHIFT) -#define I40E_MSIX_TUADD(_i) (0x00000004 + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ -#define I40E_MSIX_TUADD_MAX_INDEX 128 -#define I40E_MSIX_TUADD_MSIXTUADD_SHIFT 0 -#define I40E_MSIX_TUADD_MSIXTUADD_MASK I40E_MASK(0xFFFFFFFF, I40E_MSIX_TUADD_MSIXTUADD_SHIFT) -#define I40E_MSIX_TVCTRL(_i) (0x0000000C + ((_i) * 16)) /* _i=0...128 */ /* Reset: FLR */ -#define I40E_MSIX_TVCTRL_MAX_INDEX 128 -#define I40E_MSIX_TVCTRL_MASK_SHIFT 0 -#define I40E_MSIX_TVCTRL_MASK_MASK I40E_MASK(0x1, I40E_MSIX_TVCTRL_MASK_SHIFT) #define I40E_VFMSIX_PBA1(_i) (0x00002000 + ((_i) * 4)) /* _i=0...19 */ /* Reset: VFLR */ #define I40E_VFMSIX_PBA1_MAX_INDEX 19 #define I40E_VFMSIX_PBA1_PENBIT_SHIFT 0 @@ -1623,1525 +49,6 @@ #define I40E_VFMSIX_TVCTRL1_MAX_INDEX 639 #define I40E_VFMSIX_TVCTRL1_MASK_SHIFT 0 #define I40E_VFMSIX_TVCTRL1_MASK_MASK I40E_MASK(0x1, I40E_VFMSIX_TVCTRL1_MASK_SHIFT) -#define I40E_GLNVM_FLA 0x000B6108 /* Reset: POR */ -#define I40E_GLNVM_FLA_FL_SCK_SHIFT 0 -#define I40E_GLNVM_FLA_FL_SCK_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SCK_SHIFT) -#define I40E_GLNVM_FLA_FL_CE_SHIFT 1 -#define I40E_GLNVM_FLA_FL_CE_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_CE_SHIFT) -#define I40E_GLNVM_FLA_FL_SI_SHIFT 2 -#define I40E_GLNVM_FLA_FL_SI_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SI_SHIFT) -#define I40E_GLNVM_FLA_FL_SO_SHIFT 3 -#define I40E_GLNVM_FLA_FL_SO_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_SO_SHIFT) -#define I40E_GLNVM_FLA_FL_REQ_SHIFT 4 -#define I40E_GLNVM_FLA_FL_REQ_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_REQ_SHIFT) -#define I40E_GLNVM_FLA_FL_GNT_SHIFT 5 -#define I40E_GLNVM_FLA_FL_GNT_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_GNT_SHIFT) -#define I40E_GLNVM_FLA_LOCKED_SHIFT 6 -#define I40E_GLNVM_FLA_LOCKED_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_LOCKED_SHIFT) -#define I40E_GLNVM_FLA_FL_SADDR_SHIFT 18 -#define I40E_GLNVM_FLA_FL_SADDR_MASK I40E_MASK(0x7FF, I40E_GLNVM_FLA_FL_SADDR_SHIFT) -#define I40E_GLNVM_FLA_FL_BUSY_SHIFT 30 -#define I40E_GLNVM_FLA_FL_BUSY_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_BUSY_SHIFT) -#define I40E_GLNVM_FLA_FL_DER_SHIFT 31 -#define I40E_GLNVM_FLA_FL_DER_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_FL_DER_SHIFT) -#define I40E_GLNVM_FLASHID 0x000B6104 /* Reset: POR */ -#define I40E_GLNVM_FLASHID_FLASHID_SHIFT 0 -#define I40E_GLNVM_FLASHID_FLASHID_MASK I40E_MASK(0xFFFFFF, I40E_GLNVM_FLASHID_FLASHID_SHIFT) -#define I40E_GLNVM_FLASHID_FLEEP_PERF_SHIFT 31 -#define I40E_GLNVM_FLASHID_FLEEP_PERF_MASK I40E_MASK(0x1, I40E_GLNVM_FLASHID_FLEEP_PERF_SHIFT) -#define I40E_GLNVM_GENS 0x000B6100 /* Reset: POR */ -#define I40E_GLNVM_GENS_NVM_PRES_SHIFT 0 -#define I40E_GLNVM_GENS_NVM_PRES_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_NVM_PRES_SHIFT) -#define I40E_GLNVM_GENS_SR_SIZE_SHIFT 5 -#define I40E_GLNVM_GENS_SR_SIZE_MASK I40E_MASK(0x7, I40E_GLNVM_GENS_SR_SIZE_SHIFT) -#define I40E_GLNVM_GENS_BANK1VAL_SHIFT 8 -#define I40E_GLNVM_GENS_BANK1VAL_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_BANK1VAL_SHIFT) -#define I40E_GLNVM_GENS_ALT_PRST_SHIFT 23 -#define I40E_GLNVM_GENS_ALT_PRST_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_ALT_PRST_SHIFT) -#define I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT 25 -#define I40E_GLNVM_GENS_FL_AUTO_RD_MASK I40E_MASK(0x1, I40E_GLNVM_GENS_FL_AUTO_RD_SHIFT) -#define I40E_GLNVM_PROTCSR(_i) (0x000B6010 + ((_i) * 4)) /* _i=0...59 */ /* Reset: POR */ -#define I40E_GLNVM_PROTCSR_MAX_INDEX 59 -#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT 0 -#define I40E_GLNVM_PROTCSR_ADDR_BLOCK_MASK I40E_MASK(0xFFFFFF, I40E_GLNVM_PROTCSR_ADDR_BLOCK_SHIFT) -#define I40E_GLNVM_SRCTL 0x000B6110 /* Reset: POR */ -#define I40E_GLNVM_SRCTL_SRBUSY_SHIFT 0 -#define I40E_GLNVM_SRCTL_SRBUSY_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_SRBUSY_SHIFT) -#define I40E_GLNVM_SRCTL_ADDR_SHIFT 14 -#define I40E_GLNVM_SRCTL_ADDR_MASK I40E_MASK(0x7FFF, I40E_GLNVM_SRCTL_ADDR_SHIFT) -#define I40E_GLNVM_SRCTL_WRITE_SHIFT 29 -#define I40E_GLNVM_SRCTL_WRITE_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_WRITE_SHIFT) -#define I40E_GLNVM_SRCTL_START_SHIFT 30 -#define I40E_GLNVM_SRCTL_START_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_START_SHIFT) -#define I40E_GLNVM_SRCTL_DONE_SHIFT 31 -#define I40E_GLNVM_SRCTL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_SRCTL_DONE_SHIFT) -#define I40E_GLNVM_SRDATA 0x000B6114 /* Reset: POR */ -#define I40E_GLNVM_SRDATA_WRDATA_SHIFT 0 -#define I40E_GLNVM_SRDATA_WRDATA_MASK I40E_MASK(0xFFFF, I40E_GLNVM_SRDATA_WRDATA_SHIFT) -#define I40E_GLNVM_SRDATA_RDDATA_SHIFT 16 -#define I40E_GLNVM_SRDATA_RDDATA_MASK I40E_MASK(0xFFFF, I40E_GLNVM_SRDATA_RDDATA_SHIFT) -#define I40E_GLNVM_ULD 0x000B6008 /* Reset: POR */ -#define I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT 0 -#define I40E_GLNVM_ULD_CONF_PCIR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIR_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT 1 -#define I40E_GLNVM_ULD_CONF_PCIRTL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIRTL_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT 2 -#define I40E_GLNVM_ULD_CONF_LCB_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_LCB_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT 3 -#define I40E_GLNVM_ULD_CONF_CORE_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_CORE_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT 4 -#define I40E_GLNVM_ULD_CONF_GLOBAL_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_GLOBAL_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT 5 -#define I40E_GLNVM_ULD_CONF_POR_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_POR_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT 6 -#define I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIE_ANA_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT 7 -#define I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PHY_ANA_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT 8 -#define I40E_GLNVM_ULD_CONF_EMP_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_EMP_DONE_SHIFT) -#define I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT 9 -#define I40E_GLNVM_ULD_CONF_PCIALT_DONE_MASK I40E_MASK(0x1, I40E_GLNVM_ULD_CONF_PCIALT_DONE_SHIFT) -#define I40E_GLPCI_BYTCTH 0x0009C484 /* Reset: PCIR */ -#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT 0 -#define I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_BYTCTH_PCI_COUNT_BW_BCT_SHIFT) -#define I40E_GLPCI_BYTCTL 0x0009C488 /* Reset: PCIR */ -#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT 0 -#define I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_BYTCTL_PCI_COUNT_BW_BCT_SHIFT) -#define I40E_GLPCI_CAPCTRL 0x000BE4A4 /* Reset: PCIR */ -#define I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT 0 -#define I40E_GLPCI_CAPCTRL_VPD_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPCTRL_VPD_EN_SHIFT) -#define I40E_GLPCI_CAPSUP 0x000BE4A8 /* Reset: PCIR */ -#define I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT 0 -#define I40E_GLPCI_CAPSUP_PCIE_VER_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_PCIE_VER_SHIFT) -#define I40E_GLPCI_CAPSUP_LTR_EN_SHIFT 2 -#define I40E_GLPCI_CAPSUP_LTR_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LTR_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_TPH_EN_SHIFT 3 -#define I40E_GLPCI_CAPSUP_TPH_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_TPH_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_ARI_EN_SHIFT 4 -#define I40E_GLPCI_CAPSUP_ARI_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ARI_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_IOV_EN_SHIFT 5 -#define I40E_GLPCI_CAPSUP_IOV_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_IOV_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_ACS_EN_SHIFT 6 -#define I40E_GLPCI_CAPSUP_ACS_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ACS_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_SEC_EN_SHIFT 7 -#define I40E_GLPCI_CAPSUP_SEC_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_SEC_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT 16 -#define I40E_GLPCI_CAPSUP_ECRC_GEN_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ECRC_GEN_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT 17 -#define I40E_GLPCI_CAPSUP_ECRC_CHK_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_ECRC_CHK_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_IDO_EN_SHIFT 18 -#define I40E_GLPCI_CAPSUP_IDO_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_IDO_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT 19 -#define I40E_GLPCI_CAPSUP_MSI_MASK_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_MSI_MASK_SHIFT) -#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT 20 -#define I40E_GLPCI_CAPSUP_CSR_CONF_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_CSR_CONF_EN_SHIFT) -#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT 30 -#define I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LOAD_SUBSYS_ID_SHIFT) -#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT 31 -#define I40E_GLPCI_CAPSUP_LOAD_DEV_ID_MASK I40E_MASK(0x1, I40E_GLPCI_CAPSUP_LOAD_DEV_ID_SHIFT) -#define I40E_GLPCI_CNF 0x000BE4C0 /* Reset: POR */ -#define I40E_GLPCI_CNF_FLEX10_SHIFT 1 -#define I40E_GLPCI_CNF_FLEX10_MASK I40E_MASK(0x1, I40E_GLPCI_CNF_FLEX10_SHIFT) -#define I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT 2 -#define I40E_GLPCI_CNF_WAKE_PIN_EN_MASK I40E_MASK(0x1, I40E_GLPCI_CNF_WAKE_PIN_EN_SHIFT) -#define I40E_GLPCI_CNF2 0x000BE494 /* Reset: PCIR */ -#define I40E_GLPCI_CNF2_RO_DIS_SHIFT 0 -#define I40E_GLPCI_CNF2_RO_DIS_MASK I40E_MASK(0x1, I40E_GLPCI_CNF2_RO_DIS_SHIFT) -#define I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT 1 -#define I40E_GLPCI_CNF2_CACHELINE_SIZE_MASK I40E_MASK(0x1, I40E_GLPCI_CNF2_CACHELINE_SIZE_SHIFT) -#define I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT 2 -#define I40E_GLPCI_CNF2_MSI_X_PF_N_MASK I40E_MASK(0x7FF, I40E_GLPCI_CNF2_MSI_X_PF_N_SHIFT) -#define I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT 13 -#define I40E_GLPCI_CNF2_MSI_X_VF_N_MASK I40E_MASK(0x7FF, I40E_GLPCI_CNF2_MSI_X_VF_N_SHIFT) -#define I40E_GLPCI_DREVID 0x0009C480 /* Reset: PCIR */ -#define I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT 0 -#define I40E_GLPCI_DREVID_DEFAULT_REVID_MASK I40E_MASK(0xFF, I40E_GLPCI_DREVID_DEFAULT_REVID_SHIFT) -#define I40E_GLPCI_GSCL_1 0x0009C48C /* Reset: PCIR */ -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT 0 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_0_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT 1 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_1_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT 2 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_2_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT 3 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_EN_3_SHIFT) -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT 4 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_0_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_0_SHIFT) -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT 5 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_1_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_1_SHIFT) -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT 6 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_2_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_2_SHIFT) -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT 7 -#define I40E_GLPCI_GSCL_1_LBC_ENABLE_3_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_LBC_ENABLE_3_SHIFT) -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT 8 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EN_SHIFT) -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT 9 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_MASK I40E_MASK(0x1F, I40E_GLPCI_GSCL_1_PCI_COUNT_LAT_EV_SHIFT) -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT 14 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EN_SHIFT) -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT 15 -#define I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_MASK I40E_MASK(0x1F, I40E_GLPCI_GSCL_1_PCI_COUNT_BW_EV_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT 28 -#define I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_64_BIT_EN_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT 29 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_RESET_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT 30 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_STOP_SHIFT) -#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT 31 -#define I40E_GLPCI_GSCL_1_GIO_COUNT_START_MASK I40E_MASK(0x1, I40E_GLPCI_GSCL_1_GIO_COUNT_START_SHIFT) -#define I40E_GLPCI_GSCL_2 0x0009C490 /* Reset: PCIR */ -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT 0 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_0_SHIFT) -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT 8 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_1_SHIFT) -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT 16 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_2_SHIFT) -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT 24 -#define I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_MASK I40E_MASK(0xFF, I40E_GLPCI_GSCL_2_GIO_EVENT_NUM_3_SHIFT) -#define I40E_GLPCI_GSCL_5_8(_i) (0x0009C494 + ((_i) * 4)) /* _i=0...3 */ /* Reset: PCIR */ -#define I40E_GLPCI_GSCL_5_8_MAX_INDEX 3 -#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT 0 -#define I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_MASK I40E_MASK(0xFFFF, I40E_GLPCI_GSCL_5_8_LBC_THRESHOLD_N_SHIFT) -#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT 16 -#define I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_MASK I40E_MASK(0xFFFF, I40E_GLPCI_GSCL_5_8_LBC_TIMER_N_SHIFT) -#define I40E_GLPCI_GSCN_0_3(_i) (0x0009C4A4 + ((_i) * 4)) /* _i=0...3 */ /* Reset: PCIR */ -#define I40E_GLPCI_GSCN_0_3_MAX_INDEX 3 -#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT 0 -#define I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_GSCN_0_3_EVENT_COUNTER_SHIFT) -#define I40E_GLPCI_LBARCTRL 0x000BE484 /* Reset: POR */ -#define I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT 0 -#define I40E_GLPCI_LBARCTRL_PREFBAR_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_PREFBAR_SHIFT) -#define I40E_GLPCI_LBARCTRL_BAR32_SHIFT 1 -#define I40E_GLPCI_LBARCTRL_BAR32_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_BAR32_SHIFT) -#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT 3 -#define I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_FLASH_EXPOSE_SHIFT) -#define I40E_GLPCI_LBARCTRL_RSVD_4_SHIFT 4 -#define I40E_GLPCI_LBARCTRL_RSVD_4_MASK I40E_MASK(0x3, I40E_GLPCI_LBARCTRL_RSVD_4_SHIFT) -#define I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT 6 -#define I40E_GLPCI_LBARCTRL_FL_SIZE_MASK I40E_MASK(0x7, I40E_GLPCI_LBARCTRL_FL_SIZE_SHIFT) -#define I40E_GLPCI_LBARCTRL_RSVD_10_SHIFT 10 -#define I40E_GLPCI_LBARCTRL_RSVD_10_MASK I40E_MASK(0x1, I40E_GLPCI_LBARCTRL_RSVD_10_SHIFT) -#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT 11 -#define I40E_GLPCI_LBARCTRL_EXROM_SIZE_MASK I40E_MASK(0x7, I40E_GLPCI_LBARCTRL_EXROM_SIZE_SHIFT) -#define I40E_GLPCI_LINKCAP 0x000BE4AC /* Reset: PCIR */ -#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT 0 -#define I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_MASK I40E_MASK(0x3F, I40E_GLPCI_LINKCAP_LINK_SPEEDS_VECTOR_SHIFT) -#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT 6 -#define I40E_GLPCI_LINKCAP_MAX_PAYLOAD_MASK I40E_MASK(0x7, I40E_GLPCI_LINKCAP_MAX_PAYLOAD_SHIFT) -#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT 9 -#define I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_MASK I40E_MASK(0xF, I40E_GLPCI_LINKCAP_MAX_LINK_WIDTH_SHIFT) -#define I40E_GLPCI_PCIERR 0x000BE4FC /* Reset: PCIR */ -#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT 0 -#define I40E_GLPCI_PCIERR_PCIE_ERR_REP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_PCIERR_PCIE_ERR_REP_SHIFT) -#define I40E_GLPCI_PKTCT 0x0009C4BC /* Reset: PCIR */ -#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT 0 -#define I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_PKTCT_PCI_COUNT_BW_PCT_SHIFT) -#define I40E_GLPCI_PM_MUX_NPQ 0x0009C4F4 /* Reset: PCIR */ -#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT 0 -#define I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_MASK I40E_MASK(0x7, I40E_GLPCI_PM_MUX_NPQ_NPQ_NUM_PORT_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT 16 -#define I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_MASK I40E_MASK(0x1F, I40E_GLPCI_PM_MUX_NPQ_INNER_NPQ_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_PFB 0x0009C4F0 /* Reset: PCIR */ -#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT 0 -#define I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_MASK I40E_MASK(0x1F, I40E_GLPCI_PM_MUX_PFB_PFB_PORT_SEL_SHIFT) -#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT 16 -#define I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_MASK I40E_MASK(0x7, I40E_GLPCI_PM_MUX_PFB_INNER_PORT_SEL_SHIFT) -#define I40E_GLPCI_PMSUP 0x000BE4B0 /* Reset: PCIR */ -#define I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT 0 -#define I40E_GLPCI_PMSUP_ASPM_SUP_MASK I40E_MASK(0x3, I40E_GLPCI_PMSUP_ASPM_SUP_SHIFT) -#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT 2 -#define I40E_GLPCI_PMSUP_L0S_EXIT_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L0S_EXIT_LAT_SHIFT) -#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT 5 -#define I40E_GLPCI_PMSUP_L1_EXIT_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L1_EXIT_LAT_SHIFT) -#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT 8 -#define I40E_GLPCI_PMSUP_L0S_ACC_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L0S_ACC_LAT_SHIFT) -#define I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT 11 -#define I40E_GLPCI_PMSUP_L1_ACC_LAT_MASK I40E_MASK(0x7, I40E_GLPCI_PMSUP_L1_ACC_LAT_SHIFT) -#define I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT 14 -#define I40E_GLPCI_PMSUP_SLOT_CLK_MASK I40E_MASK(0x1, I40E_GLPCI_PMSUP_SLOT_CLK_SHIFT) -#define I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT 15 -#define I40E_GLPCI_PMSUP_OBFF_SUP_MASK I40E_MASK(0x3, I40E_GLPCI_PMSUP_OBFF_SUP_SHIFT) -#define I40E_GLPCI_PQ_MAX_USED_SPC 0x0009C4EC /* Reset: PCIR */ -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT 0 -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_MASK I40E_MASK(0xFF, I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_12_SHIFT) -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT 8 -#define I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_MASK I40E_MASK(0xFF, I40E_GLPCI_PQ_MAX_USED_SPC_GLPCI_PQ_MAX_USED_SPC_13_SHIFT) -#define I40E_GLPCI_PWRDATA 0x000BE490 /* Reset: PCIR */ -#define I40E_GLPCI_PWRDATA_D0_POWER_SHIFT 0 -#define I40E_GLPCI_PWRDATA_D0_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_D0_POWER_SHIFT) -#define I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT 8 -#define I40E_GLPCI_PWRDATA_COMM_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_COMM_POWER_SHIFT) -#define I40E_GLPCI_PWRDATA_D3_POWER_SHIFT 16 -#define I40E_GLPCI_PWRDATA_D3_POWER_MASK I40E_MASK(0xFF, I40E_GLPCI_PWRDATA_D3_POWER_SHIFT) -#define I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT 24 -#define I40E_GLPCI_PWRDATA_DATA_SCALE_MASK I40E_MASK(0x3, I40E_GLPCI_PWRDATA_DATA_SCALE_SHIFT) -#define I40E_GLPCI_REVID 0x000BE4B4 /* Reset: PCIR */ -#define I40E_GLPCI_REVID_NVM_REVID_SHIFT 0 -#define I40E_GLPCI_REVID_NVM_REVID_MASK I40E_MASK(0xFF, I40E_GLPCI_REVID_NVM_REVID_SHIFT) -#define I40E_GLPCI_SERH 0x000BE49C /* Reset: PCIR */ -#define I40E_GLPCI_SERH_SER_NUM_H_SHIFT 0 -#define I40E_GLPCI_SERH_SER_NUM_H_MASK I40E_MASK(0xFFFF, I40E_GLPCI_SERH_SER_NUM_H_SHIFT) -#define I40E_GLPCI_SERL 0x000BE498 /* Reset: PCIR */ -#define I40E_GLPCI_SERL_SER_NUM_L_SHIFT 0 -#define I40E_GLPCI_SERL_SER_NUM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SERL_SER_NUM_L_SHIFT) -#define I40E_GLPCI_SPARE_BITS_0 0x0009C4F8 /* Reset: PCIR */ -#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT 0 -#define I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SPARE_BITS_0_SPARE_BITS_SHIFT) -#define I40E_GLPCI_SPARE_BITS_1 0x0009C4FC /* Reset: PCIR */ -#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT 0 -#define I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPCI_SPARE_BITS_1_SPARE_BITS_SHIFT) -#define I40E_GLPCI_SUBVENID 0x000BE48C /* Reset: PCIR */ -#define I40E_GLPCI_SUBVENID_SUB_VEN_ID_SHIFT 0 -#define I40E_GLPCI_SUBVENID_SUB_VEN_ID_MASK I40E_MASK(0xFFFF, I40E_GLPCI_SUBVENID_SUB_VEN_ID_SHIFT) -#define I40E_GLPCI_UPADD 0x000BE4F8 /* Reset: PCIR */ -#define I40E_GLPCI_UPADD_ADDRESS_SHIFT 1 -#define I40E_GLPCI_UPADD_ADDRESS_MASK I40E_MASK(0x7FFFFFFF, I40E_GLPCI_UPADD_ADDRESS_SHIFT) -#define I40E_GLPCI_VENDORID 0x000BE518 /* Reset: PCIR */ -#define I40E_GLPCI_VENDORID_VENDORID_SHIFT 0 -#define I40E_GLPCI_VENDORID_VENDORID_MASK I40E_MASK(0xFFFF, I40E_GLPCI_VENDORID_VENDORID_SHIFT) -#define I40E_GLPCI_VFSUP 0x000BE4B8 /* Reset: PCIR */ -#define I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT 0 -#define I40E_GLPCI_VFSUP_VF_PREFETCH_MASK I40E_MASK(0x1, I40E_GLPCI_VFSUP_VF_PREFETCH_SHIFT) -#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT 1 -#define I40E_GLPCI_VFSUP_VR_BAR_TYPE_MASK I40E_MASK(0x1, I40E_GLPCI_VFSUP_VR_BAR_TYPE_SHIFT) -#define I40E_GLTPH_CTRL 0x000BE480 /* Reset: PCIR */ -#define I40E_GLTPH_CTRL_DESC_PH_SHIFT 9 -#define I40E_GLTPH_CTRL_DESC_PH_MASK I40E_MASK(0x3, I40E_GLTPH_CTRL_DESC_PH_SHIFT) -#define I40E_GLTPH_CTRL_DATA_PH_SHIFT 11 -#define I40E_GLTPH_CTRL_DATA_PH_MASK I40E_MASK(0x3, I40E_GLTPH_CTRL_DATA_PH_SHIFT) -#define I40E_PF_FUNC_RID 0x0009C000 /* Reset: PCIR */ -#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT 0 -#define I40E_PF_FUNC_RID_FUNCTION_NUMBER_MASK I40E_MASK(0x7, I40E_PF_FUNC_RID_FUNCTION_NUMBER_SHIFT) -#define I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT 3 -#define I40E_PF_FUNC_RID_DEVICE_NUMBER_MASK I40E_MASK(0x1F, I40E_PF_FUNC_RID_DEVICE_NUMBER_SHIFT) -#define I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT 8 -#define I40E_PF_FUNC_RID_BUS_NUMBER_MASK I40E_MASK(0xFF, I40E_PF_FUNC_RID_BUS_NUMBER_SHIFT) -#define I40E_PF_PCI_CIAA 0x0009C080 /* Reset: FLR */ -#define I40E_PF_PCI_CIAA_ADDRESS_SHIFT 0 -#define I40E_PF_PCI_CIAA_ADDRESS_MASK I40E_MASK(0xFFF, I40E_PF_PCI_CIAA_ADDRESS_SHIFT) -#define I40E_PF_PCI_CIAA_VF_NUM_SHIFT 12 -#define I40E_PF_PCI_CIAA_VF_NUM_MASK I40E_MASK(0x7F, I40E_PF_PCI_CIAA_VF_NUM_SHIFT) -#define I40E_PF_PCI_CIAD 0x0009C100 /* Reset: FLR */ -#define I40E_PF_PCI_CIAD_DATA_SHIFT 0 -#define I40E_PF_PCI_CIAD_DATA_MASK I40E_MASK(0xFFFFFFFF, I40E_PF_PCI_CIAD_DATA_SHIFT) -#define I40E_PFPCI_CLASS 0x000BE400 /* Reset: PCIR */ -#define I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT 0 -#define I40E_PFPCI_CLASS_STORAGE_CLASS_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_STORAGE_CLASS_SHIFT) -#define I40E_PFPCI_CLASS_RESERVED_1_SHIFT 1 -#define I40E_PFPCI_CLASS_RESERVED_1_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_RESERVED_1_SHIFT) -#define I40E_PFPCI_CLASS_PF_IS_LAN_SHIFT 2 -#define I40E_PFPCI_CLASS_PF_IS_LAN_MASK I40E_MASK(0x1, I40E_PFPCI_CLASS_PF_IS_LAN_SHIFT) -#define I40E_PFPCI_CNF 0x000BE000 /* Reset: PCIR */ -#define I40E_PFPCI_CNF_MSI_EN_SHIFT 2 -#define I40E_PFPCI_CNF_MSI_EN_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_MSI_EN_SHIFT) -#define I40E_PFPCI_CNF_EXROM_DIS_SHIFT 3 -#define I40E_PFPCI_CNF_EXROM_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_EXROM_DIS_SHIFT) -#define I40E_PFPCI_CNF_IO_BAR_SHIFT 4 -#define I40E_PFPCI_CNF_IO_BAR_MASK I40E_MASK(0x1, I40E_PFPCI_CNF_IO_BAR_SHIFT) -#define I40E_PFPCI_CNF_INT_PIN_SHIFT 5 -#define I40E_PFPCI_CNF_INT_PIN_MASK I40E_MASK(0x3, I40E_PFPCI_CNF_INT_PIN_SHIFT) -#define I40E_PFPCI_DEVID 0x000BE080 /* Reset: PCIR */ -#define I40E_PFPCI_DEVID_PF_DEV_ID_SHIFT 0 -#define I40E_PFPCI_DEVID_PF_DEV_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_DEVID_PF_DEV_ID_SHIFT) -#define I40E_PFPCI_DEVID_VF_DEV_ID_SHIFT 16 -#define I40E_PFPCI_DEVID_VF_DEV_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_DEVID_VF_DEV_ID_SHIFT) -#define I40E_PFPCI_FACTPS 0x0009C180 /* Reset: FLR */ -#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT 0 -#define I40E_PFPCI_FACTPS_FUNC_POWER_STATE_MASK I40E_MASK(0x3, I40E_PFPCI_FACTPS_FUNC_POWER_STATE_SHIFT) -#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT 3 -#define I40E_PFPCI_FACTPS_FUNC_AUX_EN_MASK I40E_MASK(0x1, I40E_PFPCI_FACTPS_FUNC_AUX_EN_SHIFT) -#define I40E_PFPCI_FUNC 0x000BE200 /* Reset: POR */ -#define I40E_PFPCI_FUNC_FUNC_DIS_SHIFT 0 -#define I40E_PFPCI_FUNC_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_FUNC_DIS_SHIFT) -#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT 1 -#define I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_ALLOW_FUNC_DIS_SHIFT) -#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT 2 -#define I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC_DIS_FUNC_ON_PORT_DIS_SHIFT) -#define I40E_PFPCI_FUNC2 0x000BE180 /* Reset: PCIR */ -#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT 0 -#define I40E_PFPCI_FUNC2_EMP_FUNC_DIS_MASK I40E_MASK(0x1, I40E_PFPCI_FUNC2_EMP_FUNC_DIS_SHIFT) -#define I40E_PFPCI_ICAUSE 0x0009C200 /* Reset: PFR */ -#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT 0 -#define I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPCI_ICAUSE_PCIE_ERR_CAUSE_SHIFT) -#define I40E_PFPCI_IENA 0x0009C280 /* Reset: PFR */ -#define I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT 0 -#define I40E_PFPCI_IENA_PCIE_ERR_EN_MASK I40E_MASK(0xFFFFFFFF, I40E_PFPCI_IENA_PCIE_ERR_EN_SHIFT) -#define I40E_PFPCI_PF_FLUSH_DONE 0x0009C800 /* Reset: PCIR */ -#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_PF_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_PM 0x000BE300 /* Reset: POR */ -#define I40E_PFPCI_PM_PME_EN_SHIFT 0 -#define I40E_PFPCI_PM_PME_EN_MASK I40E_MASK(0x1, I40E_PFPCI_PM_PME_EN_SHIFT) -#define I40E_PFPCI_STATUS1 0x000BE280 /* Reset: POR */ -#define I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT 0 -#define I40E_PFPCI_STATUS1_FUNC_VALID_MASK I40E_MASK(0x1, I40E_PFPCI_STATUS1_FUNC_VALID_SHIFT) -#define I40E_PFPCI_SUBSYSID 0x000BE100 /* Reset: PCIR */ -#define I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_SHIFT 0 -#define I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_SUBSYSID_PF_SUBSYS_ID_SHIFT) -#define I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_SHIFT 16 -#define I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_MASK I40E_MASK(0xFFFF, I40E_PFPCI_SUBSYSID_VF_SUBSYS_ID_SHIFT) -#define I40E_PFPCI_VF_FLUSH_DONE 0x0000E400 /* Reset: PCIR */ -#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VF_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VF_FLUSH_DONE1(_VF) (0x0009C600 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: PCIR */ -#define I40E_PFPCI_VF_FLUSH_DONE1_MAX_INDEX 127 -#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VF_FLUSH_DONE1_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VM_FLUSH_DONE 0x0009C880 /* Reset: PCIR */ -#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT 0 -#define I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_MASK I40E_MASK(0x1, I40E_PFPCI_VM_FLUSH_DONE_FLUSH_DONE_SHIFT) -#define I40E_PFPCI_VMINDEX 0x0009C300 /* Reset: PCIR */ -#define I40E_PFPCI_VMINDEX_VMINDEX_SHIFT 0 -#define I40E_PFPCI_VMINDEX_VMINDEX_MASK I40E_MASK(0x1FF, I40E_PFPCI_VMINDEX_VMINDEX_SHIFT) -#define I40E_PFPCI_VMPEND 0x0009C380 /* Reset: PCIR */ -#define I40E_PFPCI_VMPEND_PENDING_SHIFT 0 -#define I40E_PFPCI_VMPEND_PENDING_MASK I40E_MASK(0x1, I40E_PFPCI_VMPEND_PENDING_SHIFT) -#define I40E_PRTPM_EEE_STAT 0x001E4320 /* Reset: GLOBR */ -#define I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT 29 -#define I40E_PRTPM_EEE_STAT_EEE_NEG_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_EEE_NEG_SHIFT) -#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT 30 -#define I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_RX_LPI_STATUS_SHIFT) -#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT 31 -#define I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_MASK I40E_MASK(0x1, I40E_PRTPM_EEE_STAT_TX_LPI_STATUS_SHIFT) -#define I40E_PRTPM_EEEC 0x001E4380 /* Reset: GLOBR */ -#define I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT 16 -#define I40E_PRTPM_EEEC_TW_WAKE_MIN_MASK I40E_MASK(0x3F, I40E_PRTPM_EEEC_TW_WAKE_MIN_SHIFT) -#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT 24 -#define I40E_PRTPM_EEEC_TX_LU_LPI_DLY_MASK I40E_MASK(0x3, I40E_PRTPM_EEEC_TX_LU_LPI_DLY_SHIFT) -#define I40E_PRTPM_EEEC_TEEE_DLY_SHIFT 26 -#define I40E_PRTPM_EEEC_TEEE_DLY_MASK I40E_MASK(0x3F, I40E_PRTPM_EEEC_TEEE_DLY_SHIFT) -#define I40E_PRTPM_EEEFWD 0x001E4400 /* Reset: GLOBR */ -#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT 31 -#define I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_MASK I40E_MASK(0x1, I40E_PRTPM_EEEFWD_EEE_FW_CONFIG_DONE_SHIFT) -#define I40E_PRTPM_EEER 0x001E4360 /* Reset: GLOBR */ -#define I40E_PRTPM_EEER_TW_SYSTEM_SHIFT 0 -#define I40E_PRTPM_EEER_TW_SYSTEM_MASK I40E_MASK(0xFFFF, I40E_PRTPM_EEER_TW_SYSTEM_SHIFT) -#define I40E_PRTPM_EEER_TX_LPI_EN_SHIFT 16 -#define I40E_PRTPM_EEER_TX_LPI_EN_MASK I40E_MASK(0x1, I40E_PRTPM_EEER_TX_LPI_EN_SHIFT) -#define I40E_PRTPM_EEETXC 0x001E43E0 /* Reset: GLOBR */ -#define I40E_PRTPM_EEETXC_TW_PHY_SHIFT 0 -#define I40E_PRTPM_EEETXC_TW_PHY_MASK I40E_MASK(0xFFFF, I40E_PRTPM_EEETXC_TW_PHY_SHIFT) -#define I40E_PRTPM_GC 0x000B8140 /* Reset: POR */ -#define I40E_PRTPM_GC_EMP_LINK_ON_SHIFT 0 -#define I40E_PRTPM_GC_EMP_LINK_ON_MASK I40E_MASK(0x1, I40E_PRTPM_GC_EMP_LINK_ON_SHIFT) -#define I40E_PRTPM_GC_MNG_VETO_SHIFT 1 -#define I40E_PRTPM_GC_MNG_VETO_MASK I40E_MASK(0x1, I40E_PRTPM_GC_MNG_VETO_SHIFT) -#define I40E_PRTPM_GC_RATD_SHIFT 2 -#define I40E_PRTPM_GC_RATD_MASK I40E_MASK(0x1, I40E_PRTPM_GC_RATD_SHIFT) -#define I40E_PRTPM_GC_LCDMP_SHIFT 3 -#define I40E_PRTPM_GC_LCDMP_MASK I40E_MASK(0x1, I40E_PRTPM_GC_LCDMP_SHIFT) -#define I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT 31 -#define I40E_PRTPM_GC_LPLU_ASSERTED_MASK I40E_MASK(0x1, I40E_PRTPM_GC_LPLU_ASSERTED_SHIFT) -#define I40E_PRTPM_RLPIC 0x001E43A0 /* Reset: GLOBR */ -#define I40E_PRTPM_RLPIC_ERLPIC_SHIFT 0 -#define I40E_PRTPM_RLPIC_ERLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_RLPIC_ERLPIC_SHIFT) -#define I40E_PRTPM_TLPIC 0x001E43C0 /* Reset: GLOBR */ -#define I40E_PRTPM_TLPIC_ETLPIC_SHIFT 0 -#define I40E_PRTPM_TLPIC_ETLPIC_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_TLPIC_ETLPIC_SHIFT) -#define I40E_GLRPB_DPSS 0x000AC828 /* Reset: CORER */ -#define I40E_GLRPB_DPSS_DPS_TCN_SHIFT 0 -#define I40E_GLRPB_DPSS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_DPSS_DPS_TCN_SHIFT) -#define I40E_GLRPB_GHW 0x000AC830 /* Reset: CORER */ -#define I40E_GLRPB_GHW_GHW_SHIFT 0 -#define I40E_GLRPB_GHW_GHW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_GHW_GHW_SHIFT) -#define I40E_GLRPB_GLW 0x000AC834 /* Reset: CORER */ -#define I40E_GLRPB_GLW_GLW_SHIFT 0 -#define I40E_GLRPB_GLW_GLW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_GLW_GLW_SHIFT) -#define I40E_GLRPB_PHW 0x000AC844 /* Reset: CORER */ -#define I40E_GLRPB_PHW_PHW_SHIFT 0 -#define I40E_GLRPB_PHW_PHW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_PHW_PHW_SHIFT) -#define I40E_GLRPB_PLW 0x000AC848 /* Reset: CORER */ -#define I40E_GLRPB_PLW_PLW_SHIFT 0 -#define I40E_GLRPB_PLW_PLW_MASK I40E_MASK(0xFFFFF, I40E_GLRPB_PLW_PLW_SHIFT) -#define I40E_PRTRPB_DHW(_i) (0x000AC100 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTRPB_DHW_MAX_INDEX 7 -#define I40E_PRTRPB_DHW_DHW_TCN_SHIFT 0 -#define I40E_PRTRPB_DHW_DHW_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DHW_DHW_TCN_SHIFT) -#define I40E_PRTRPB_DLW(_i) (0x000AC220 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTRPB_DLW_MAX_INDEX 7 -#define I40E_PRTRPB_DLW_DLW_TCN_SHIFT 0 -#define I40E_PRTRPB_DLW_DLW_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DLW_DLW_TCN_SHIFT) -#define I40E_PRTRPB_DPS(_i) (0x000AC320 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTRPB_DPS_MAX_INDEX 7 -#define I40E_PRTRPB_DPS_DPS_TCN_SHIFT 0 -#define I40E_PRTRPB_DPS_DPS_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_DPS_DPS_TCN_SHIFT) -#define I40E_PRTRPB_SHT(_i) (0x000AC480 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTRPB_SHT_MAX_INDEX 7 -#define I40E_PRTRPB_SHT_SHT_TCN_SHIFT 0 -#define I40E_PRTRPB_SHT_SHT_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SHT_SHT_TCN_SHIFT) -#define I40E_PRTRPB_SHW 0x000AC580 /* Reset: CORER */ -#define I40E_PRTRPB_SHW_SHW_SHIFT 0 -#define I40E_PRTRPB_SHW_SHW_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SHW_SHW_SHIFT) -#define I40E_PRTRPB_SLT(_i) (0x000AC5A0 + ((_i) * 32)) /* _i=0...7 */ /* Reset: CORER */ -#define I40E_PRTRPB_SLT_MAX_INDEX 7 -#define I40E_PRTRPB_SLT_SLT_TCN_SHIFT 0 -#define I40E_PRTRPB_SLT_SLT_TCN_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SLT_SLT_TCN_SHIFT) -#define I40E_PRTRPB_SLW 0x000AC6A0 /* Reset: CORER */ -#define I40E_PRTRPB_SLW_SLW_SHIFT 0 -#define I40E_PRTRPB_SLW_SLW_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SLW_SLW_SHIFT) -#define I40E_PRTRPB_SPS 0x000AC7C0 /* Reset: CORER */ -#define I40E_PRTRPB_SPS_SPS_SHIFT 0 -#define I40E_PRTRPB_SPS_SPS_MASK I40E_MASK(0xFFFFF, I40E_PRTRPB_SPS_SPS_SHIFT) -#define I40E_GLQF_CTL 0x00269BA4 /* Reset: CORER */ -#define I40E_GLQF_CTL_HTOEP_SHIFT 1 -#define I40E_GLQF_CTL_HTOEP_MASK I40E_MASK(0x1, I40E_GLQF_CTL_HTOEP_SHIFT) -#define I40E_GLQF_CTL_HTOEP_FCOE_SHIFT 2 -#define I40E_GLQF_CTL_HTOEP_FCOE_MASK I40E_MASK(0x1, I40E_GLQF_CTL_HTOEP_FCOE_SHIFT) -#define I40E_GLQF_CTL_PCNT_ALLOC_SHIFT 3 -#define I40E_GLQF_CTL_PCNT_ALLOC_MASK I40E_MASK(0x7, I40E_GLQF_CTL_PCNT_ALLOC_SHIFT) -#define I40E_GLQF_CTL_FD_AUTO_PCTYPE_SHIFT 6 -#define I40E_GLQF_CTL_FD_AUTO_PCTYPE_MASK I40E_MASK(0x1, I40E_GLQF_CTL_FD_AUTO_PCTYPE_SHIFT) -#define I40E_GLQF_CTL_RSVD_SHIFT 7 -#define I40E_GLQF_CTL_RSVD_MASK I40E_MASK(0x1, I40E_GLQF_CTL_RSVD_SHIFT) -#define I40E_GLQF_CTL_MAXPEBLEN_SHIFT 8 -#define I40E_GLQF_CTL_MAXPEBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXPEBLEN_SHIFT) -#define I40E_GLQF_CTL_MAXFCBLEN_SHIFT 11 -#define I40E_GLQF_CTL_MAXFCBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXFCBLEN_SHIFT) -#define I40E_GLQF_CTL_MAXFDBLEN_SHIFT 14 -#define I40E_GLQF_CTL_MAXFDBLEN_MASK I40E_MASK(0x7, I40E_GLQF_CTL_MAXFDBLEN_SHIFT) -#define I40E_GLQF_CTL_FDBEST_SHIFT 17 -#define I40E_GLQF_CTL_FDBEST_MASK I40E_MASK(0xFF, I40E_GLQF_CTL_FDBEST_SHIFT) -#define I40E_GLQF_CTL_PROGPRIO_SHIFT 25 -#define I40E_GLQF_CTL_PROGPRIO_MASK I40E_MASK(0x1, I40E_GLQF_CTL_PROGPRIO_SHIFT) -#define I40E_GLQF_CTL_INVALPRIO_SHIFT 26 -#define I40E_GLQF_CTL_INVALPRIO_MASK I40E_MASK(0x1, I40E_GLQF_CTL_INVALPRIO_SHIFT) -#define I40E_GLQF_CTL_IGNORE_IP_SHIFT 27 -#define I40E_GLQF_CTL_IGNORE_IP_MASK I40E_MASK(0x1, I40E_GLQF_CTL_IGNORE_IP_SHIFT) -#define I40E_GLQF_FDCNT_0 0x00269BAC /* Reset: CORER */ -#define I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT 0 -#define I40E_GLQF_FDCNT_0_GUARANT_CNT_MASK I40E_MASK(0x1FFF, I40E_GLQF_FDCNT_0_GUARANT_CNT_SHIFT) -#define I40E_GLQF_FDCNT_0_BESTCNT_SHIFT 13 -#define I40E_GLQF_FDCNT_0_BESTCNT_MASK I40E_MASK(0x1FFF, I40E_GLQF_FDCNT_0_BESTCNT_SHIFT) -#define I40E_GLQF_HKEY(_i) (0x00270140 + ((_i) * 4)) /* _i=0...12 */ /* Reset: CORER */ -#define I40E_GLQF_HKEY_MAX_INDEX 12 -#define I40E_GLQF_HKEY_KEY_0_SHIFT 0 -#define I40E_GLQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_0_SHIFT) -#define I40E_GLQF_HKEY_KEY_1_SHIFT 8 -#define I40E_GLQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_1_SHIFT) -#define I40E_GLQF_HKEY_KEY_2_SHIFT 16 -#define I40E_GLQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_2_SHIFT) -#define I40E_GLQF_HKEY_KEY_3_SHIFT 24 -#define I40E_GLQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_GLQF_HKEY_KEY_3_SHIFT) -#define I40E_GLQF_HSYM(_i) (0x00269D00 + ((_i) * 4)) /* _i=0...63 */ /* Reset: CORER */ -#define I40E_GLQF_HSYM_MAX_INDEX 63 -#define I40E_GLQF_HSYM_SYMH_ENA_SHIFT 0 -#define I40E_GLQF_HSYM_SYMH_ENA_MASK I40E_MASK(0x1, I40E_GLQF_HSYM_SYMH_ENA_SHIFT) -#define I40E_GLQF_PCNT(_i) (0x00266800 + ((_i) * 4)) /* _i=0...511 */ /* Reset: CORER */ -#define I40E_GLQF_PCNT_MAX_INDEX 511 -#define I40E_GLQF_PCNT_PCNT_SHIFT 0 -#define I40E_GLQF_PCNT_PCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLQF_PCNT_PCNT_SHIFT) -#define I40E_GLQF_SWAP(_i, _j) (0x00267E00 + ((_i) * 4 + (_j) * 8)) /* _i=0...1, _j=0...63 */ /* Reset: CORER */ -#define I40E_GLQF_SWAP_MAX_INDEX 1 -#define I40E_GLQF_SWAP_OFF0_SRC0_SHIFT 0 -#define I40E_GLQF_SWAP_OFF0_SRC0_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF0_SRC0_SHIFT) -#define I40E_GLQF_SWAP_OFF0_SRC1_SHIFT 6 -#define I40E_GLQF_SWAP_OFF0_SRC1_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF0_SRC1_SHIFT) -#define I40E_GLQF_SWAP_FLEN0_SHIFT 12 -#define I40E_GLQF_SWAP_FLEN0_MASK I40E_MASK(0xF, I40E_GLQF_SWAP_FLEN0_SHIFT) -#define I40E_GLQF_SWAP_OFF1_SRC0_SHIFT 16 -#define I40E_GLQF_SWAP_OFF1_SRC0_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF1_SRC0_SHIFT) -#define I40E_GLQF_SWAP_OFF1_SRC1_SHIFT 22 -#define I40E_GLQF_SWAP_OFF1_SRC1_MASK I40E_MASK(0x3F, I40E_GLQF_SWAP_OFF1_SRC1_SHIFT) -#define I40E_GLQF_SWAP_FLEN1_SHIFT 28 -#define I40E_GLQF_SWAP_FLEN1_MASK I40E_MASK(0xF, I40E_GLQF_SWAP_FLEN1_SHIFT) -#define I40E_PFQF_CTL_0 0x001C0AC0 /* Reset: CORER */ -#define I40E_PFQF_CTL_0_PEHSIZE_SHIFT 0 -#define I40E_PFQF_CTL_0_PEHSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_0_PEHSIZE_SHIFT) -#define I40E_PFQF_CTL_0_PEDSIZE_SHIFT 5 -#define I40E_PFQF_CTL_0_PEDSIZE_MASK I40E_MASK(0x1F, I40E_PFQF_CTL_0_PEDSIZE_SHIFT) -#define I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT 10 -#define I40E_PFQF_CTL_0_PFFCHSIZE_MASK I40E_MASK(0xF, I40E_PFQF_CTL_0_PFFCHSIZE_SHIFT) -#define I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT 14 -#define I40E_PFQF_CTL_0_PFFCDSIZE_MASK I40E_MASK(0x3, I40E_PFQF_CTL_0_PFFCDSIZE_SHIFT) -#define I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT 16 -#define I40E_PFQF_CTL_0_HASHLUTSIZE_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_HASHLUTSIZE_SHIFT) -#define I40E_PFQF_CTL_0_FD_ENA_SHIFT 17 -#define I40E_PFQF_CTL_0_FD_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_FD_ENA_SHIFT) -#define I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT 18 -#define I40E_PFQF_CTL_0_ETYPE_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_ETYPE_ENA_SHIFT) -#define I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT 19 -#define I40E_PFQF_CTL_0_MACVLAN_ENA_MASK I40E_MASK(0x1, I40E_PFQF_CTL_0_MACVLAN_ENA_SHIFT) -#define I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT 20 -#define I40E_PFQF_CTL_0_VFFCHSIZE_MASK I40E_MASK(0xF, I40E_PFQF_CTL_0_VFFCHSIZE_SHIFT) -#define I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT 24 -#define I40E_PFQF_CTL_0_VFFCDSIZE_MASK I40E_MASK(0x3, I40E_PFQF_CTL_0_VFFCDSIZE_SHIFT) -#define I40E_PFQF_CTL_1 0x00245D80 /* Reset: CORER */ -#define I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT 0 -#define I40E_PFQF_CTL_1_CLEARFDTABLE_MASK I40E_MASK(0x1, I40E_PFQF_CTL_1_CLEARFDTABLE_SHIFT) -#define I40E_PFQF_FDALLOC 0x00246280 /* Reset: CORER */ -#define I40E_PFQF_FDALLOC_FDALLOC_SHIFT 0 -#define I40E_PFQF_FDALLOC_FDALLOC_MASK I40E_MASK(0xFF, I40E_PFQF_FDALLOC_FDALLOC_SHIFT) -#define I40E_PFQF_FDALLOC_FDBEST_SHIFT 8 -#define I40E_PFQF_FDALLOC_FDBEST_MASK I40E_MASK(0xFF, I40E_PFQF_FDALLOC_FDBEST_SHIFT) -#define I40E_PFQF_FDSTAT 0x00246380 /* Reset: CORER */ -#define I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT 0 -#define I40E_PFQF_FDSTAT_GUARANT_CNT_MASK I40E_MASK(0x1FFF, I40E_PFQF_FDSTAT_GUARANT_CNT_SHIFT) -#define I40E_PFQF_FDSTAT_BEST_CNT_SHIFT 16 -#define I40E_PFQF_FDSTAT_BEST_CNT_MASK I40E_MASK(0x1FFF, I40E_PFQF_FDSTAT_BEST_CNT_SHIFT) -#define I40E_PFQF_HENA(_i) (0x00245900 + ((_i) * 128)) /* _i=0...1 */ /* Reset: CORER */ -#define I40E_PFQF_HENA_MAX_INDEX 1 -#define I40E_PFQF_HENA_PTYPE_ENA_SHIFT 0 -#define I40E_PFQF_HENA_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_PFQF_HENA_PTYPE_ENA_SHIFT) -#define I40E_PFQF_HKEY(_i) (0x00244800 + ((_i) * 128)) /* _i=0...12 */ /* Reset: CORER */ -#define I40E_PFQF_HKEY_MAX_INDEX 12 -#define I40E_PFQF_HKEY_KEY_0_SHIFT 0 -#define I40E_PFQF_HKEY_KEY_0_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_0_SHIFT) -#define I40E_PFQF_HKEY_KEY_1_SHIFT 8 -#define I40E_PFQF_HKEY_KEY_1_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_1_SHIFT) -#define I40E_PFQF_HKEY_KEY_2_SHIFT 16 -#define I40E_PFQF_HKEY_KEY_2_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_2_SHIFT) -#define I40E_PFQF_HKEY_KEY_3_SHIFT 24 -#define I40E_PFQF_HKEY_KEY_3_MASK I40E_MASK(0xFF, I40E_PFQF_HKEY_KEY_3_SHIFT) -#define I40E_PFQF_HLUT(_i) (0x00240000 + ((_i) * 128)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_PFQF_HLUT_MAX_INDEX 127 -#define I40E_PFQF_HLUT_LUT0_SHIFT 0 -#define I40E_PFQF_HLUT_LUT0_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT0_SHIFT) -#define I40E_PFQF_HLUT_LUT1_SHIFT 8 -#define I40E_PFQF_HLUT_LUT1_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT1_SHIFT) -#define I40E_PFQF_HLUT_LUT2_SHIFT 16 -#define I40E_PFQF_HLUT_LUT2_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT2_SHIFT) -#define I40E_PFQF_HLUT_LUT3_SHIFT 24 -#define I40E_PFQF_HLUT_LUT3_MASK I40E_MASK(0x3F, I40E_PFQF_HLUT_LUT3_SHIFT) -#define I40E_PRTQF_CTL_0 0x00256E60 /* Reset: CORER */ -#define I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT 0 -#define I40E_PRTQF_CTL_0_HSYM_ENA_MASK I40E_MASK(0x1, I40E_PRTQF_CTL_0_HSYM_ENA_SHIFT) -#define I40E_PRTQF_FD_FLXINSET(_i) (0x00253800 + ((_i) * 32)) /* _i=0...63 */ /* Reset: CORER */ -#define I40E_PRTQF_FD_FLXINSET_MAX_INDEX 63 -#define I40E_PRTQF_FD_FLXINSET_INSET_SHIFT 0 -#define I40E_PRTQF_FD_FLXINSET_INSET_MASK I40E_MASK(0xFF, I40E_PRTQF_FD_FLXINSET_INSET_SHIFT) -#define I40E_PRTQF_FD_MSK(_i, _j) (0x00252000 + ((_i) * 64 + (_j) * 32)) /* _i=0...63, _j=0...1 */ /* Reset: CORER */ -#define I40E_PRTQF_FD_MSK_MAX_INDEX 63 -#define I40E_PRTQF_FD_MSK_MASK_SHIFT 0 -#define I40E_PRTQF_FD_MSK_MASK_MASK I40E_MASK(0xFFFF, I40E_PRTQF_FD_MSK_MASK_SHIFT) -#define I40E_PRTQF_FD_MSK_OFFSET_SHIFT 16 -#define I40E_PRTQF_FD_MSK_OFFSET_MASK I40E_MASK(0x3F, I40E_PRTQF_FD_MSK_OFFSET_SHIFT) -#define I40E_PRTQF_FLX_PIT(_i) (0x00255200 + ((_i) * 32)) /* _i=0...8 */ /* Reset: CORER */ -#define I40E_PRTQF_FLX_PIT_MAX_INDEX 8 -#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT 0 -#define I40E_PRTQF_FLX_PIT_SOURCE_OFF_MASK I40E_MASK(0x1F, I40E_PRTQF_FLX_PIT_SOURCE_OFF_SHIFT) -#define I40E_PRTQF_FLX_PIT_FSIZE_SHIFT 5 -#define I40E_PRTQF_FLX_PIT_FSIZE_MASK I40E_MASK(0x1F, I40E_PRTQF_FLX_PIT_FSIZE_SHIFT) -#define I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT 10 -#define I40E_PRTQF_FLX_PIT_DEST_OFF_MASK I40E_MASK(0x3F, I40E_PRTQF_FLX_PIT_DEST_OFF_SHIFT) -#define I40E_VFQF_HENA1(_i, _VF) (0x00230800 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...1, _VF=0...127 */ /* Reset: CORER */ -#define I40E_VFQF_HENA1_MAX_INDEX 1 -#define I40E_VFQF_HENA1_PTYPE_ENA_SHIFT 0 -#define I40E_VFQF_HENA1_PTYPE_ENA_MASK I40E_MASK(0xFFFFFFFF, I40E_VFQF_HENA1_PTYPE_ENA_SHIFT) -#define I40E_VFQF_HKEY1(_i, _VF) (0x00228000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...12, _VF=0...127 */ /* Reset: CORER */ -#define I40E_VFQF_HKEY1_MAX_INDEX 12 -#define I40E_VFQF_HKEY1_KEY_0_SHIFT 0 -#define I40E_VFQF_HKEY1_KEY_0_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_0_SHIFT) -#define I40E_VFQF_HKEY1_KEY_1_SHIFT 8 -#define I40E_VFQF_HKEY1_KEY_1_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_1_SHIFT) -#define I40E_VFQF_HKEY1_KEY_2_SHIFT 16 -#define I40E_VFQF_HKEY1_KEY_2_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_2_SHIFT) -#define I40E_VFQF_HKEY1_KEY_3_SHIFT 24 -#define I40E_VFQF_HKEY1_KEY_3_MASK I40E_MASK(0xFF, I40E_VFQF_HKEY1_KEY_3_SHIFT) -#define I40E_VFQF_HLUT1(_i, _VF) (0x00220000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...15, _VF=0...127 */ /* Reset: CORER */ -#define I40E_VFQF_HLUT1_MAX_INDEX 15 -#define I40E_VFQF_HLUT1_LUT0_SHIFT 0 -#define I40E_VFQF_HLUT1_LUT0_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT0_SHIFT) -#define I40E_VFQF_HLUT1_LUT1_SHIFT 8 -#define I40E_VFQF_HLUT1_LUT1_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT1_SHIFT) -#define I40E_VFQF_HLUT1_LUT2_SHIFT 16 -#define I40E_VFQF_HLUT1_LUT2_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT2_SHIFT) -#define I40E_VFQF_HLUT1_LUT3_SHIFT 24 -#define I40E_VFQF_HLUT1_LUT3_MASK I40E_MASK(0xF, I40E_VFQF_HLUT1_LUT3_SHIFT) -#define I40E_VFQF_HREGION1(_i, _VF) (0x0022E000 + ((_i) * 1024 + (_VF) * 4)) /* _i=0...7, _VF=0...127 */ /* Reset: CORER */ -#define I40E_VFQF_HREGION1_MAX_INDEX 7 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT 0 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_0_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_0_SHIFT) -#define I40E_VFQF_HREGION1_REGION_0_SHIFT 1 -#define I40E_VFQF_HREGION1_REGION_0_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_0_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT 4 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_1_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_1_SHIFT) -#define I40E_VFQF_HREGION1_REGION_1_SHIFT 5 -#define I40E_VFQF_HREGION1_REGION_1_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_1_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT 8 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_2_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_2_SHIFT) -#define I40E_VFQF_HREGION1_REGION_2_SHIFT 9 -#define I40E_VFQF_HREGION1_REGION_2_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_2_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT 12 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_3_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_3_SHIFT) -#define I40E_VFQF_HREGION1_REGION_3_SHIFT 13 -#define I40E_VFQF_HREGION1_REGION_3_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_3_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT 16 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_4_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_4_SHIFT) -#define I40E_VFQF_HREGION1_REGION_4_SHIFT 17 -#define I40E_VFQF_HREGION1_REGION_4_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_4_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT 20 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_5_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_5_SHIFT) -#define I40E_VFQF_HREGION1_REGION_5_SHIFT 21 -#define I40E_VFQF_HREGION1_REGION_5_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_5_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT 24 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_6_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_6_SHIFT) -#define I40E_VFQF_HREGION1_REGION_6_SHIFT 25 -#define I40E_VFQF_HREGION1_REGION_6_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_6_SHIFT) -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT 28 -#define I40E_VFQF_HREGION1_OVERRIDE_ENA_7_MASK I40E_MASK(0x1, I40E_VFQF_HREGION1_OVERRIDE_ENA_7_SHIFT) -#define I40E_VFQF_HREGION1_REGION_7_SHIFT 29 -#define I40E_VFQF_HREGION1_REGION_7_MASK I40E_MASK(0x7, I40E_VFQF_HREGION1_REGION_7_SHIFT) -#define I40E_VPQF_CTL(_VF) (0x001C0000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: VFR */ -#define I40E_VPQF_CTL_MAX_INDEX 127 -#define I40E_VPQF_CTL_PEHSIZE_SHIFT 0 -#define I40E_VPQF_CTL_PEHSIZE_MASK I40E_MASK(0x1F, I40E_VPQF_CTL_PEHSIZE_SHIFT) -#define I40E_VPQF_CTL_PEDSIZE_SHIFT 5 -#define I40E_VPQF_CTL_PEDSIZE_MASK I40E_MASK(0x1F, I40E_VPQF_CTL_PEDSIZE_SHIFT) -#define I40E_VPQF_CTL_FCHSIZE_SHIFT 10 -#define I40E_VPQF_CTL_FCHSIZE_MASK I40E_MASK(0xF, I40E_VPQF_CTL_FCHSIZE_SHIFT) -#define I40E_VPQF_CTL_FCDSIZE_SHIFT 14 -#define I40E_VPQF_CTL_FCDSIZE_MASK I40E_MASK(0x3, I40E_VPQF_CTL_FCDSIZE_SHIFT) -#define I40E_VSIQF_CTL(_VSI) (0x0020D800 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: PFR */ -#define I40E_VSIQF_CTL_MAX_INDEX 383 -#define I40E_VSIQF_CTL_FCOE_ENA_SHIFT 0 -#define I40E_VSIQF_CTL_FCOE_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_FCOE_ENA_SHIFT) -#define I40E_VSIQF_CTL_PETCP_ENA_SHIFT 1 -#define I40E_VSIQF_CTL_PETCP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PETCP_ENA_SHIFT) -#define I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT 2 -#define I40E_VSIQF_CTL_PEUUDP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEUUDP_ENA_SHIFT) -#define I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT 3 -#define I40E_VSIQF_CTL_PEMUDP_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEMUDP_ENA_SHIFT) -#define I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT 4 -#define I40E_VSIQF_CTL_PEUFRAG_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEUFRAG_ENA_SHIFT) -#define I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT 5 -#define I40E_VSIQF_CTL_PEMFRAG_ENA_MASK I40E_MASK(0x1, I40E_VSIQF_CTL_PEMFRAG_ENA_SHIFT) -#define I40E_VSIQF_TCREGION(_i, _VSI) (0x00206000 + ((_i) * 2048 + (_VSI) * 4)) /* _i=0...3, _VSI=0...383 */ /* Reset: PFR */ -#define I40E_VSIQF_TCREGION_MAX_INDEX 3 -#define I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT 0 -#define I40E_VSIQF_TCREGION_TC_OFFSET_MASK I40E_MASK(0x1FF, I40E_VSIQF_TCREGION_TC_OFFSET_SHIFT) -#define I40E_VSIQF_TCREGION_TC_SIZE_SHIFT 9 -#define I40E_VSIQF_TCREGION_TC_SIZE_MASK I40E_MASK(0x7, I40E_VSIQF_TCREGION_TC_SIZE_SHIFT) -#define I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT 16 -#define I40E_VSIQF_TCREGION_TC_OFFSET2_MASK I40E_MASK(0x1FF, I40E_VSIQF_TCREGION_TC_OFFSET2_SHIFT) -#define I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT 25 -#define I40E_VSIQF_TCREGION_TC_SIZE2_MASK I40E_MASK(0x7, I40E_VSIQF_TCREGION_TC_SIZE2_SHIFT) -#define I40E_GL_FCOECRC(_i) (0x00314d80 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOECRC_MAX_INDEX 143 -#define I40E_GL_FCOECRC_FCOECRC_SHIFT 0 -#define I40E_GL_FCOECRC_FCOECRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOECRC_FCOECRC_SHIFT) -#define I40E_GL_FCOEDDPC(_i) (0x00314480 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDDPC_MAX_INDEX 143 -#define I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT 0 -#define I40E_GL_FCOEDDPC_FCOEDDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDDPC_FCOEDDPC_SHIFT) -#define I40E_GL_FCOEDIFEC(_i) (0x00318480 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDIFEC_MAX_INDEX 143 -#define I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT 0 -#define I40E_GL_FCOEDIFEC_FCOEDIFRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIFEC_FCOEDIFRC_SHIFT) -#define I40E_GL_FCOEDIFTCL(_i) (0x00354000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDIFTCL_MAX_INDEX 143 -#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT 0 -#define I40E_GL_FCOEDIFTCL_FCOEDIFTC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIFTCL_FCOEDIFTC_SHIFT) -#define I40E_GL_FCOEDIXEC(_i) (0x0034c000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDIXEC_MAX_INDEX 143 -#define I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT 0 -#define I40E_GL_FCOEDIXEC_FCOEDIXEC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIXEC_FCOEDIXEC_SHIFT) -#define I40E_GL_FCOEDIXVC(_i) (0x00350000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDIXVC_MAX_INDEX 143 -#define I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT 0 -#define I40E_GL_FCOEDIXVC_FCOEDIXVC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDIXVC_FCOEDIXVC_SHIFT) -#define I40E_GL_FCOEDWRCH(_i) (0x00320004 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDWRCH_MAX_INDEX 143 -#define I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT 0 -#define I40E_GL_FCOEDWRCH_FCOEDWRCH_MASK I40E_MASK(0xFFFF, I40E_GL_FCOEDWRCH_FCOEDWRCH_SHIFT) -#define I40E_GL_FCOEDWRCL(_i) (0x00320000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDWRCL_MAX_INDEX 143 -#define I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT 0 -#define I40E_GL_FCOEDWRCL_FCOEDWRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDWRCL_FCOEDWRCL_SHIFT) -#define I40E_GL_FCOEDWTCH(_i) (0x00348084 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDWTCH_MAX_INDEX 143 -#define I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT 0 -#define I40E_GL_FCOEDWTCH_FCOEDWTCH_MASK I40E_MASK(0xFFFF, I40E_GL_FCOEDWTCH_FCOEDWTCH_SHIFT) -#define I40E_GL_FCOEDWTCL(_i) (0x00348080 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEDWTCL_MAX_INDEX 143 -#define I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT 0 -#define I40E_GL_FCOEDWTCL_FCOEDWTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEDWTCL_FCOEDWTCL_SHIFT) -#define I40E_GL_FCOELAST(_i) (0x00314000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOELAST_MAX_INDEX 143 -#define I40E_GL_FCOELAST_FCOELAST_SHIFT 0 -#define I40E_GL_FCOELAST_FCOELAST_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOELAST_FCOELAST_SHIFT) -#define I40E_GL_FCOEPRC(_i) (0x00315200 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEPRC_MAX_INDEX 143 -#define I40E_GL_FCOEPRC_FCOEPRC_SHIFT 0 -#define I40E_GL_FCOEPRC_FCOEPRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEPRC_FCOEPRC_SHIFT) -#define I40E_GL_FCOEPTC(_i) (0x00344C00 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOEPTC_MAX_INDEX 143 -#define I40E_GL_FCOEPTC_FCOEPTC_SHIFT 0 -#define I40E_GL_FCOEPTC_FCOEPTC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOEPTC_FCOEPTC_SHIFT) -#define I40E_GL_FCOERPDC(_i) (0x00324000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_FCOERPDC_MAX_INDEX 143 -#define I40E_GL_FCOERPDC_FCOERPDC_SHIFT 0 -#define I40E_GL_FCOERPDC_FCOERPDC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_FCOERPDC_FCOERPDC_SHIFT) -#define I40E_GL_RXERR1_L(_i) (0x00318000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_RXERR1_L_MAX_INDEX 143 -#define I40E_GL_RXERR1_L_FCOEDIFRC_SHIFT 0 -#define I40E_GL_RXERR1_L_FCOEDIFRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR1_L_FCOEDIFRC_SHIFT) -#define I40E_GL_RXERR2_L(_i) (0x0031c000 + ((_i) * 8)) /* _i=0...143 */ /* Reset: CORER */ -#define I40E_GL_RXERR2_L_MAX_INDEX 143 -#define I40E_GL_RXERR2_L_FCOEDIXAC_SHIFT 0 -#define I40E_GL_RXERR2_L_FCOEDIXAC_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_RXERR2_L_FCOEDIXAC_SHIFT) -#define I40E_GLPRT_BPRCH(_i) (0x003005E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_BPRCH_MAX_INDEX 3 -#define I40E_GLPRT_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLPRT_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_BPRCH_BPRCH_SHIFT) -#define I40E_GLPRT_BPRCL(_i) (0x003005E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_BPRCL_MAX_INDEX 3 -#define I40E_GLPRT_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLPRT_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_BPRCL_BPRCL_SHIFT) -#define I40E_GLPRT_BPTCH(_i) (0x00300A04 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_BPTCH_MAX_INDEX 3 -#define I40E_GLPRT_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLPRT_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_BPTCH_BPTCH_SHIFT) -#define I40E_GLPRT_BPTCL(_i) (0x00300A00 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_BPTCL_MAX_INDEX 3 -#define I40E_GLPRT_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLPRT_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_BPTCL_BPTCL_SHIFT) -#define I40E_GLPRT_CRCERRS(_i) (0x00300080 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_CRCERRS_MAX_INDEX 3 -#define I40E_GLPRT_CRCERRS_CRCERRS_SHIFT 0 -#define I40E_GLPRT_CRCERRS_CRCERRS_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_CRCERRS_CRCERRS_SHIFT) -#define I40E_GLPRT_GORCH(_i) (0x00300004 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_GORCH_MAX_INDEX 3 -#define I40E_GLPRT_GORCH_GORCH_SHIFT 0 -#define I40E_GLPRT_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_GORCH_GORCH_SHIFT) -#define I40E_GLPRT_GORCL(_i) (0x00300000 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_GORCL_MAX_INDEX 3 -#define I40E_GLPRT_GORCL_GORCL_SHIFT 0 -#define I40E_GLPRT_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_GORCL_GORCL_SHIFT) -#define I40E_GLPRT_GOTCH(_i) (0x00300684 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_GOTCH_MAX_INDEX 3 -#define I40E_GLPRT_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLPRT_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_GOTCH_GOTCH_SHIFT) -#define I40E_GLPRT_GOTCL(_i) (0x00300680 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_GOTCL_MAX_INDEX 3 -#define I40E_GLPRT_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLPRT_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_GOTCL_GOTCL_SHIFT) -#define I40E_GLPRT_ILLERRC(_i) (0x003000E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_ILLERRC_MAX_INDEX 3 -#define I40E_GLPRT_ILLERRC_ILLERRC_SHIFT 0 -#define I40E_GLPRT_ILLERRC_ILLERRC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_ILLERRC_ILLERRC_SHIFT) -#define I40E_GLPRT_LDPC(_i) (0x00300620 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_LDPC_MAX_INDEX 3 -#define I40E_GLPRT_LDPC_LDPC_SHIFT 0 -#define I40E_GLPRT_LDPC_LDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LDPC_LDPC_SHIFT) -#define I40E_GLPRT_LXOFFRXC(_i) (0x00300160 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_LXOFFRXC_MAX_INDEX 3 -#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT 0 -#define I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXOFFRXC_LXOFFRXCNT_SHIFT) -#define I40E_GLPRT_LXOFFTXC(_i) (0x003009A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_LXOFFTXC_MAX_INDEX 3 -#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT 0 -#define I40E_GLPRT_LXOFFTXC_LXOFFTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXOFFTXC_LXOFFTXC_SHIFT) -#define I40E_GLPRT_LXONRXC(_i) (0x00300140 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_LXONRXC_MAX_INDEX 3 -#define I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT 0 -#define I40E_GLPRT_LXONRXC_LXONRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXONRXC_LXONRXCNT_SHIFT) -#define I40E_GLPRT_LXONTXC(_i) (0x00300980 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_LXONTXC_MAX_INDEX 3 -#define I40E_GLPRT_LXONTXC_LXONTXC_SHIFT 0 -#define I40E_GLPRT_LXONTXC_LXONTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_LXONTXC_LXONTXC_SHIFT) -#define I40E_GLPRT_MLFC(_i) (0x00300020 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_MLFC_MAX_INDEX 3 -#define I40E_GLPRT_MLFC_MLFC_SHIFT 0 -#define I40E_GLPRT_MLFC_MLFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MLFC_MLFC_SHIFT) -#define I40E_GLPRT_MPRCH(_i) (0x003005C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_MPRCH_MAX_INDEX 3 -#define I40E_GLPRT_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLPRT_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_MPRCH_MPRCH_SHIFT) -#define I40E_GLPRT_MPRCL(_i) (0x003005C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_MPRCL_MAX_INDEX 3 -#define I40E_GLPRT_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLPRT_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MPRCL_MPRCL_SHIFT) -#define I40E_GLPRT_MPTCH(_i) (0x003009E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_MPTCH_MAX_INDEX 3 -#define I40E_GLPRT_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLPRT_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_MPTCH_MPTCH_SHIFT) -#define I40E_GLPRT_MPTCL(_i) (0x003009E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_MPTCL_MAX_INDEX 3 -#define I40E_GLPRT_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLPRT_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MPTCL_MPTCL_SHIFT) -#define I40E_GLPRT_MRFC(_i) (0x00300040 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_MRFC_MAX_INDEX 3 -#define I40E_GLPRT_MRFC_MRFC_SHIFT 0 -#define I40E_GLPRT_MRFC_MRFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_MRFC_MRFC_SHIFT) -#define I40E_GLPRT_PRC1023H(_i) (0x00300504 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC1023H_MAX_INDEX 3 -#define I40E_GLPRT_PRC1023H_PRC1023H_SHIFT 0 -#define I40E_GLPRT_PRC1023H_PRC1023H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC1023H_PRC1023H_SHIFT) -#define I40E_GLPRT_PRC1023L(_i) (0x00300500 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC1023L_MAX_INDEX 3 -#define I40E_GLPRT_PRC1023L_PRC1023L_SHIFT 0 -#define I40E_GLPRT_PRC1023L_PRC1023L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC1023L_PRC1023L_SHIFT) -#define I40E_GLPRT_PRC127H(_i) (0x003004A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC127H_MAX_INDEX 3 -#define I40E_GLPRT_PRC127H_PRC127H_SHIFT 0 -#define I40E_GLPRT_PRC127H_PRC127H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC127H_PRC127H_SHIFT) -#define I40E_GLPRT_PRC127L(_i) (0x003004A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC127L_MAX_INDEX 3 -#define I40E_GLPRT_PRC127L_PRC127L_SHIFT 0 -#define I40E_GLPRT_PRC127L_PRC127L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC127L_PRC127L_SHIFT) -#define I40E_GLPRT_PRC1522H(_i) (0x00300524 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC1522H_MAX_INDEX 3 -#define I40E_GLPRT_PRC1522H_PRC1522H_SHIFT 0 -#define I40E_GLPRT_PRC1522H_PRC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC1522H_PRC1522H_SHIFT) -#define I40E_GLPRT_PRC1522L(_i) (0x00300520 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC1522L_MAX_INDEX 3 -#define I40E_GLPRT_PRC1522L_PRC1522L_SHIFT 0 -#define I40E_GLPRT_PRC1522L_PRC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC1522L_PRC1522L_SHIFT) -#define I40E_GLPRT_PRC255H(_i) (0x003004C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC255H_MAX_INDEX 3 -#define I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT 0 -#define I40E_GLPRT_PRC255H_PRTPRC255H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC255H_PRTPRC255H_SHIFT) -#define I40E_GLPRT_PRC255L(_i) (0x003004C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC255L_MAX_INDEX 3 -#define I40E_GLPRT_PRC255L_PRC255L_SHIFT 0 -#define I40E_GLPRT_PRC255L_PRC255L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC255L_PRC255L_SHIFT) -#define I40E_GLPRT_PRC511H(_i) (0x003004E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC511H_MAX_INDEX 3 -#define I40E_GLPRT_PRC511H_PRC511H_SHIFT 0 -#define I40E_GLPRT_PRC511H_PRC511H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC511H_PRC511H_SHIFT) -#define I40E_GLPRT_PRC511L(_i) (0x003004E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC511L_MAX_INDEX 3 -#define I40E_GLPRT_PRC511L_PRC511L_SHIFT 0 -#define I40E_GLPRT_PRC511L_PRC511L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC511L_PRC511L_SHIFT) -#define I40E_GLPRT_PRC64H(_i) (0x00300484 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC64H_MAX_INDEX 3 -#define I40E_GLPRT_PRC64H_PRC64H_SHIFT 0 -#define I40E_GLPRT_PRC64H_PRC64H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC64H_PRC64H_SHIFT) -#define I40E_GLPRT_PRC64L(_i) (0x00300480 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC64L_MAX_INDEX 3 -#define I40E_GLPRT_PRC64L_PRC64L_SHIFT 0 -#define I40E_GLPRT_PRC64L_PRC64L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC64L_PRC64L_SHIFT) -#define I40E_GLPRT_PRC9522H(_i) (0x00300544 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC9522H_MAX_INDEX 3 -#define I40E_GLPRT_PRC9522H_PRC1522H_SHIFT 0 -#define I40E_GLPRT_PRC9522H_PRC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PRC9522H_PRC1522H_SHIFT) -#define I40E_GLPRT_PRC9522L(_i) (0x00300540 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PRC9522L_MAX_INDEX 3 -#define I40E_GLPRT_PRC9522L_PRC1522L_SHIFT 0 -#define I40E_GLPRT_PRC9522L_PRC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PRC9522L_PRC1522L_SHIFT) -#define I40E_GLPRT_PTC1023H(_i) (0x00300724 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC1023H_MAX_INDEX 3 -#define I40E_GLPRT_PTC1023H_PTC1023H_SHIFT 0 -#define I40E_GLPRT_PTC1023H_PTC1023H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC1023H_PTC1023H_SHIFT) -#define I40E_GLPRT_PTC1023L(_i) (0x00300720 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC1023L_MAX_INDEX 3 -#define I40E_GLPRT_PTC1023L_PTC1023L_SHIFT 0 -#define I40E_GLPRT_PTC1023L_PTC1023L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC1023L_PTC1023L_SHIFT) -#define I40E_GLPRT_PTC127H(_i) (0x003006C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC127H_MAX_INDEX 3 -#define I40E_GLPRT_PTC127H_PTC127H_SHIFT 0 -#define I40E_GLPRT_PTC127H_PTC127H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC127H_PTC127H_SHIFT) -#define I40E_GLPRT_PTC127L(_i) (0x003006C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC127L_MAX_INDEX 3 -#define I40E_GLPRT_PTC127L_PTC127L_SHIFT 0 -#define I40E_GLPRT_PTC127L_PTC127L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC127L_PTC127L_SHIFT) -#define I40E_GLPRT_PTC1522H(_i) (0x00300744 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC1522H_MAX_INDEX 3 -#define I40E_GLPRT_PTC1522H_PTC1522H_SHIFT 0 -#define I40E_GLPRT_PTC1522H_PTC1522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC1522H_PTC1522H_SHIFT) -#define I40E_GLPRT_PTC1522L(_i) (0x00300740 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC1522L_MAX_INDEX 3 -#define I40E_GLPRT_PTC1522L_PTC1522L_SHIFT 0 -#define I40E_GLPRT_PTC1522L_PTC1522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC1522L_PTC1522L_SHIFT) -#define I40E_GLPRT_PTC255H(_i) (0x003006E4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC255H_MAX_INDEX 3 -#define I40E_GLPRT_PTC255H_PTC255H_SHIFT 0 -#define I40E_GLPRT_PTC255H_PTC255H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC255H_PTC255H_SHIFT) -#define I40E_GLPRT_PTC255L(_i) (0x003006E0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC255L_MAX_INDEX 3 -#define I40E_GLPRT_PTC255L_PTC255L_SHIFT 0 -#define I40E_GLPRT_PTC255L_PTC255L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC255L_PTC255L_SHIFT) -#define I40E_GLPRT_PTC511H(_i) (0x00300704 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC511H_MAX_INDEX 3 -#define I40E_GLPRT_PTC511H_PTC511H_SHIFT 0 -#define I40E_GLPRT_PTC511H_PTC511H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC511H_PTC511H_SHIFT) -#define I40E_GLPRT_PTC511L(_i) (0x00300700 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC511L_MAX_INDEX 3 -#define I40E_GLPRT_PTC511L_PTC511L_SHIFT 0 -#define I40E_GLPRT_PTC511L_PTC511L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC511L_PTC511L_SHIFT) -#define I40E_GLPRT_PTC64H(_i) (0x003006A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC64H_MAX_INDEX 3 -#define I40E_GLPRT_PTC64H_PTC64H_SHIFT 0 -#define I40E_GLPRT_PTC64H_PTC64H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC64H_PTC64H_SHIFT) -#define I40E_GLPRT_PTC64L(_i) (0x003006A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC64L_MAX_INDEX 3 -#define I40E_GLPRT_PTC64L_PTC64L_SHIFT 0 -#define I40E_GLPRT_PTC64L_PTC64L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC64L_PTC64L_SHIFT) -#define I40E_GLPRT_PTC9522H(_i) (0x00300764 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC9522H_MAX_INDEX 3 -#define I40E_GLPRT_PTC9522H_PTC9522H_SHIFT 0 -#define I40E_GLPRT_PTC9522H_PTC9522H_MASK I40E_MASK(0xFFFF, I40E_GLPRT_PTC9522H_PTC9522H_SHIFT) -#define I40E_GLPRT_PTC9522L(_i) (0x00300760 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_PTC9522L_MAX_INDEX 3 -#define I40E_GLPRT_PTC9522L_PTC9522L_SHIFT 0 -#define I40E_GLPRT_PTC9522L_PTC9522L_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PTC9522L_PTC9522L_SHIFT) -#define I40E_GLPRT_PXOFFRXC(_i, _j) (0x00300280 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ -#define I40E_GLPRT_PXOFFRXC_MAX_INDEX 3 -#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT 0 -#define I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXOFFRXC_PRPXOFFRXCNT_SHIFT) -#define I40E_GLPRT_PXOFFTXC(_i, _j) (0x00300880 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ -#define I40E_GLPRT_PXOFFTXC_MAX_INDEX 3 -#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT 0 -#define I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXOFFTXC_PRPXOFFTXCNT_SHIFT) -#define I40E_GLPRT_PXONRXC(_i, _j) (0x00300180 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ -#define I40E_GLPRT_PXONRXC_MAX_INDEX 3 -#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT 0 -#define I40E_GLPRT_PXONRXC_PRPXONRXCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXONRXC_PRPXONRXCNT_SHIFT) -#define I40E_GLPRT_PXONTXC(_i, _j) (0x00300780 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ -#define I40E_GLPRT_PXONTXC_MAX_INDEX 3 -#define I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT 0 -#define I40E_GLPRT_PXONTXC_PRPXONTXC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_PXONTXC_PRPXONTXC_SHIFT) -#define I40E_GLPRT_RDPC(_i) (0x00300600 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_RDPC_MAX_INDEX 3 -#define I40E_GLPRT_RDPC_RDPC_SHIFT 0 -#define I40E_GLPRT_RDPC_RDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RDPC_RDPC_SHIFT) -#define I40E_GLPRT_RFC(_i) (0x00300560 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_RFC_MAX_INDEX 3 -#define I40E_GLPRT_RFC_RFC_SHIFT 0 -#define I40E_GLPRT_RFC_RFC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RFC_RFC_SHIFT) -#define I40E_GLPRT_RJC(_i) (0x00300580 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_RJC_MAX_INDEX 3 -#define I40E_GLPRT_RJC_RJC_SHIFT 0 -#define I40E_GLPRT_RJC_RJC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RJC_RJC_SHIFT) -#define I40E_GLPRT_RLEC(_i) (0x003000A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_RLEC_MAX_INDEX 3 -#define I40E_GLPRT_RLEC_RLEC_SHIFT 0 -#define I40E_GLPRT_RLEC_RLEC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RLEC_RLEC_SHIFT) -#define I40E_GLPRT_ROC(_i) (0x00300120 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_ROC_MAX_INDEX 3 -#define I40E_GLPRT_ROC_ROC_SHIFT 0 -#define I40E_GLPRT_ROC_ROC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_ROC_ROC_SHIFT) -#define I40E_GLPRT_RUC(_i) (0x00300100 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_RUC_MAX_INDEX 3 -#define I40E_GLPRT_RUC_RUC_SHIFT 0 -#define I40E_GLPRT_RUC_RUC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RUC_RUC_SHIFT) -#define I40E_GLPRT_RUPP(_i) (0x00300660 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_RUPP_MAX_INDEX 3 -#define I40E_GLPRT_RUPP_RUPP_SHIFT 0 -#define I40E_GLPRT_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RUPP_RUPP_SHIFT) -#define I40E_GLPRT_RXON2OFFCNT(_i, _j) (0x00300380 + ((_i) * 8 + (_j) * 32)) /* _i=0...3, _j=0...7 */ /* Reset: CORER */ -#define I40E_GLPRT_RXON2OFFCNT_MAX_INDEX 3 -#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT 0 -#define I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_RXON2OFFCNT_PRRXON2OFFCNT_SHIFT) -#define I40E_GLPRT_TDOLD(_i) (0x00300A20 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_TDOLD_MAX_INDEX 3 -#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT 0 -#define I40E_GLPRT_TDOLD_GLPRT_TDOLD_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_TDOLD_GLPRT_TDOLD_SHIFT) -#define I40E_GLPRT_UPRCH(_i) (0x003005A4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_UPRCH_MAX_INDEX 3 -#define I40E_GLPRT_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLPRT_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_UPRCH_UPRCH_SHIFT) -#define I40E_GLPRT_UPRCL(_i) (0x003005A0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_UPRCL_MAX_INDEX 3 -#define I40E_GLPRT_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLPRT_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_UPRCL_UPRCL_SHIFT) -#define I40E_GLPRT_UPTCH(_i) (0x003009C4 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_UPTCH_MAX_INDEX 3 -#define I40E_GLPRT_UPTCH_UPTCH_SHIFT 0 -#define I40E_GLPRT_UPTCH_UPTCH_MASK I40E_MASK(0xFFFF, I40E_GLPRT_UPTCH_UPTCH_SHIFT) -#define I40E_GLPRT_UPTCL(_i) (0x003009C0 + ((_i) * 8)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_GLPRT_UPTCL_MAX_INDEX 3 -#define I40E_GLPRT_UPTCL_VUPTCH_SHIFT 0 -#define I40E_GLPRT_UPTCL_VUPTCH_MASK I40E_MASK(0xFFFFFFFF, I40E_GLPRT_UPTCL_VUPTCH_SHIFT) -#define I40E_GLSW_BPRCH(_i) (0x00370104 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_BPRCH_MAX_INDEX 15 -#define I40E_GLSW_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLSW_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_BPRCH_BPRCH_SHIFT) -#define I40E_GLSW_BPRCL(_i) (0x00370100 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_BPRCL_MAX_INDEX 15 -#define I40E_GLSW_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLSW_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_BPRCL_BPRCL_SHIFT) -#define I40E_GLSW_BPTCH(_i) (0x00340104 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_BPTCH_MAX_INDEX 15 -#define I40E_GLSW_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLSW_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_BPTCH_BPTCH_SHIFT) -#define I40E_GLSW_BPTCL(_i) (0x00340100 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_BPTCL_MAX_INDEX 15 -#define I40E_GLSW_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLSW_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_BPTCL_BPTCL_SHIFT) -#define I40E_GLSW_GORCH(_i) (0x0035C004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_GORCH_MAX_INDEX 15 -#define I40E_GLSW_GORCH_GORCH_SHIFT 0 -#define I40E_GLSW_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_GORCH_GORCH_SHIFT) -#define I40E_GLSW_GORCL(_i) (0x0035c000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_GORCL_MAX_INDEX 15 -#define I40E_GLSW_GORCL_GORCL_SHIFT 0 -#define I40E_GLSW_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_GORCL_GORCL_SHIFT) -#define I40E_GLSW_GOTCH(_i) (0x0032C004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_GOTCH_MAX_INDEX 15 -#define I40E_GLSW_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLSW_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_GOTCH_GOTCH_SHIFT) -#define I40E_GLSW_GOTCL(_i) (0x0032c000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_GOTCL_MAX_INDEX 15 -#define I40E_GLSW_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLSW_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_GOTCL_GOTCL_SHIFT) -#define I40E_GLSW_MPRCH(_i) (0x00370084 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_MPRCH_MAX_INDEX 15 -#define I40E_GLSW_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLSW_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_MPRCH_MPRCH_SHIFT) -#define I40E_GLSW_MPRCL(_i) (0x00370080 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_MPRCL_MAX_INDEX 15 -#define I40E_GLSW_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLSW_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_MPRCL_MPRCL_SHIFT) -#define I40E_GLSW_MPTCH(_i) (0x00340084 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_MPTCH_MAX_INDEX 15 -#define I40E_GLSW_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLSW_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_MPTCH_MPTCH_SHIFT) -#define I40E_GLSW_MPTCL(_i) (0x00340080 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_MPTCL_MAX_INDEX 15 -#define I40E_GLSW_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLSW_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_MPTCL_MPTCL_SHIFT) -#define I40E_GLSW_RUPP(_i) (0x00370180 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_RUPP_MAX_INDEX 15 -#define I40E_GLSW_RUPP_RUPP_SHIFT 0 -#define I40E_GLSW_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_RUPP_RUPP_SHIFT) -#define I40E_GLSW_TDPC(_i) (0x00348000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_TDPC_MAX_INDEX 15 -#define I40E_GLSW_TDPC_TDPC_SHIFT 0 -#define I40E_GLSW_TDPC_TDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_TDPC_TDPC_SHIFT) -#define I40E_GLSW_UPRCH(_i) (0x00370004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_UPRCH_MAX_INDEX 15 -#define I40E_GLSW_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLSW_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_UPRCH_UPRCH_SHIFT) -#define I40E_GLSW_UPRCL(_i) (0x00370000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_UPRCL_MAX_INDEX 15 -#define I40E_GLSW_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLSW_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_UPRCL_UPRCL_SHIFT) -#define I40E_GLSW_UPTCH(_i) (0x00340004 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_UPTCH_MAX_INDEX 15 -#define I40E_GLSW_UPTCH_UPTCH_SHIFT 0 -#define I40E_GLSW_UPTCH_UPTCH_MASK I40E_MASK(0xFFFF, I40E_GLSW_UPTCH_UPTCH_SHIFT) -#define I40E_GLSW_UPTCL(_i) (0x00340000 + ((_i) * 8)) /* _i=0...15 */ /* Reset: CORER */ -#define I40E_GLSW_UPTCL_MAX_INDEX 15 -#define I40E_GLSW_UPTCL_UPTCL_SHIFT 0 -#define I40E_GLSW_UPTCL_UPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLSW_UPTCL_UPTCL_SHIFT) -#define I40E_GLV_BPRCH(_i) (0x0036D804 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_BPRCH_MAX_INDEX 383 -#define I40E_GLV_BPRCH_BPRCH_SHIFT 0 -#define I40E_GLV_BPRCH_BPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_BPRCH_BPRCH_SHIFT) -#define I40E_GLV_BPRCL(_i) (0x0036d800 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_BPRCL_MAX_INDEX 383 -#define I40E_GLV_BPRCL_BPRCL_SHIFT 0 -#define I40E_GLV_BPRCL_BPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_BPRCL_BPRCL_SHIFT) -#define I40E_GLV_BPTCH(_i) (0x0033D804 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_BPTCH_MAX_INDEX 383 -#define I40E_GLV_BPTCH_BPTCH_SHIFT 0 -#define I40E_GLV_BPTCH_BPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_BPTCH_BPTCH_SHIFT) -#define I40E_GLV_BPTCL(_i) (0x0033d800 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_BPTCL_MAX_INDEX 383 -#define I40E_GLV_BPTCL_BPTCL_SHIFT 0 -#define I40E_GLV_BPTCL_BPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_BPTCL_BPTCL_SHIFT) -#define I40E_GLV_GORCH(_i) (0x00358004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_GORCH_MAX_INDEX 383 -#define I40E_GLV_GORCH_GORCH_SHIFT 0 -#define I40E_GLV_GORCH_GORCH_MASK I40E_MASK(0xFFFF, I40E_GLV_GORCH_GORCH_SHIFT) -#define I40E_GLV_GORCL(_i) (0x00358000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_GORCL_MAX_INDEX 383 -#define I40E_GLV_GORCL_GORCL_SHIFT 0 -#define I40E_GLV_GORCL_GORCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_GORCL_GORCL_SHIFT) -#define I40E_GLV_GOTCH(_i) (0x00328004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_GOTCH_MAX_INDEX 383 -#define I40E_GLV_GOTCH_GOTCH_SHIFT 0 -#define I40E_GLV_GOTCH_GOTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_GOTCH_GOTCH_SHIFT) -#define I40E_GLV_GOTCL(_i) (0x00328000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_GOTCL_MAX_INDEX 383 -#define I40E_GLV_GOTCL_GOTCL_SHIFT 0 -#define I40E_GLV_GOTCL_GOTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_GOTCL_GOTCL_SHIFT) -#define I40E_GLV_MPRCH(_i) (0x0036CC04 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_MPRCH_MAX_INDEX 383 -#define I40E_GLV_MPRCH_MPRCH_SHIFT 0 -#define I40E_GLV_MPRCH_MPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_MPRCH_MPRCH_SHIFT) -#define I40E_GLV_MPRCL(_i) (0x0036cc00 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_MPRCL_MAX_INDEX 383 -#define I40E_GLV_MPRCL_MPRCL_SHIFT 0 -#define I40E_GLV_MPRCL_MPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_MPRCL_MPRCL_SHIFT) -#define I40E_GLV_MPTCH(_i) (0x0033CC04 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_MPTCH_MAX_INDEX 383 -#define I40E_GLV_MPTCH_MPTCH_SHIFT 0 -#define I40E_GLV_MPTCH_MPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_MPTCH_MPTCH_SHIFT) -#define I40E_GLV_MPTCL(_i) (0x0033cc00 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_MPTCL_MAX_INDEX 383 -#define I40E_GLV_MPTCL_MPTCL_SHIFT 0 -#define I40E_GLV_MPTCL_MPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_MPTCL_MPTCL_SHIFT) -#define I40E_GLV_RDPC(_i) (0x00310000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_RDPC_MAX_INDEX 383 -#define I40E_GLV_RDPC_RDPC_SHIFT 0 -#define I40E_GLV_RDPC_RDPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_RDPC_RDPC_SHIFT) -#define I40E_GLV_RUPP(_i) (0x0036E400 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_RUPP_MAX_INDEX 383 -#define I40E_GLV_RUPP_RUPP_SHIFT 0 -#define I40E_GLV_RUPP_RUPP_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_RUPP_RUPP_SHIFT) -#define I40E_GLV_TEPC(_VSI) (0x00344000 + ((_VSI) * 4)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_TEPC_MAX_INDEX 383 -#define I40E_GLV_TEPC_TEPC_SHIFT 0 -#define I40E_GLV_TEPC_TEPC_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_TEPC_TEPC_SHIFT) -#define I40E_GLV_UPRCH(_i) (0x0036C004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_UPRCH_MAX_INDEX 383 -#define I40E_GLV_UPRCH_UPRCH_SHIFT 0 -#define I40E_GLV_UPRCH_UPRCH_MASK I40E_MASK(0xFFFF, I40E_GLV_UPRCH_UPRCH_SHIFT) -#define I40E_GLV_UPRCL(_i) (0x0036c000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_UPRCL_MAX_INDEX 383 -#define I40E_GLV_UPRCL_UPRCL_SHIFT 0 -#define I40E_GLV_UPRCL_UPRCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_UPRCL_UPRCL_SHIFT) -#define I40E_GLV_UPTCH(_i) (0x0033C004 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_UPTCH_MAX_INDEX 383 -#define I40E_GLV_UPTCH_GLVUPTCH_SHIFT 0 -#define I40E_GLV_UPTCH_GLVUPTCH_MASK I40E_MASK(0xFFFF, I40E_GLV_UPTCH_GLVUPTCH_SHIFT) -#define I40E_GLV_UPTCL(_i) (0x0033c000 + ((_i) * 8)) /* _i=0...383 */ /* Reset: CORER */ -#define I40E_GLV_UPTCL_MAX_INDEX 383 -#define I40E_GLV_UPTCL_UPTCL_SHIFT 0 -#define I40E_GLV_UPTCL_UPTCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLV_UPTCL_UPTCL_SHIFT) -#define I40E_GLVEBTC_RBCH(_i, _j) (0x00364004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_RBCH_MAX_INDEX 7 -#define I40E_GLVEBTC_RBCH_TCBCH_SHIFT 0 -#define I40E_GLVEBTC_RBCH_TCBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_RBCH_TCBCH_SHIFT) -#define I40E_GLVEBTC_RBCL(_i, _j) (0x00364000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_RBCL_MAX_INDEX 7 -#define I40E_GLVEBTC_RBCL_TCBCL_SHIFT 0 -#define I40E_GLVEBTC_RBCL_TCBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_RBCL_TCBCL_SHIFT) -#define I40E_GLVEBTC_RPCH(_i, _j) (0x00368004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_RPCH_MAX_INDEX 7 -#define I40E_GLVEBTC_RPCH_TCPCH_SHIFT 0 -#define I40E_GLVEBTC_RPCH_TCPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_RPCH_TCPCH_SHIFT) -#define I40E_GLVEBTC_RPCL(_i, _j) (0x00368000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_RPCL_MAX_INDEX 7 -#define I40E_GLVEBTC_RPCL_TCPCL_SHIFT 0 -#define I40E_GLVEBTC_RPCL_TCPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_RPCL_TCPCL_SHIFT) -#define I40E_GLVEBTC_TBCH(_i, _j) (0x00334004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_TBCH_MAX_INDEX 7 -#define I40E_GLVEBTC_TBCH_TCBCH_SHIFT 0 -#define I40E_GLVEBTC_TBCH_TCBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_TBCH_TCBCH_SHIFT) -#define I40E_GLVEBTC_TBCL(_i, _j) (0x00334000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_TBCL_MAX_INDEX 7 -#define I40E_GLVEBTC_TBCL_TCBCL_SHIFT 0 -#define I40E_GLVEBTC_TBCL_TCBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_TBCL_TCBCL_SHIFT) -#define I40E_GLVEBTC_TPCH(_i, _j) (0x00338004 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_TPCH_MAX_INDEX 7 -#define I40E_GLVEBTC_TPCH_TCPCH_SHIFT 0 -#define I40E_GLVEBTC_TPCH_TCPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBTC_TPCH_TCPCH_SHIFT) -#define I40E_GLVEBTC_TPCL(_i, _j) (0x00338000 + ((_i) * 8 + (_j) * 64)) /* _i=0...7, _j=0...15 */ /* Reset: CORER */ -#define I40E_GLVEBTC_TPCL_MAX_INDEX 7 -#define I40E_GLVEBTC_TPCL_TCPCL_SHIFT 0 -#define I40E_GLVEBTC_TPCL_TCPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBTC_TPCL_TCPCL_SHIFT) -#define I40E_GLVEBVL_BPCH(_i) (0x00374804 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_BPCH_MAX_INDEX 127 -#define I40E_GLVEBVL_BPCH_VLBPCH_SHIFT 0 -#define I40E_GLVEBVL_BPCH_VLBPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_BPCH_VLBPCH_SHIFT) -#define I40E_GLVEBVL_BPCL(_i) (0x00374800 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_BPCL_MAX_INDEX 127 -#define I40E_GLVEBVL_BPCL_VLBPCL_SHIFT 0 -#define I40E_GLVEBVL_BPCL_VLBPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_BPCL_VLBPCL_SHIFT) -#define I40E_GLVEBVL_GORCH(_i) (0x00360004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_GORCH_MAX_INDEX 127 -#define I40E_GLVEBVL_GORCH_VLBCH_SHIFT 0 -#define I40E_GLVEBVL_GORCH_VLBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_GORCH_VLBCH_SHIFT) -#define I40E_GLVEBVL_GORCL(_i) (0x00360000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_GORCL_MAX_INDEX 127 -#define I40E_GLVEBVL_GORCL_VLBCL_SHIFT 0 -#define I40E_GLVEBVL_GORCL_VLBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_GORCL_VLBCL_SHIFT) -#define I40E_GLVEBVL_GOTCH(_i) (0x00330004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_GOTCH_MAX_INDEX 127 -#define I40E_GLVEBVL_GOTCH_VLBCH_SHIFT 0 -#define I40E_GLVEBVL_GOTCH_VLBCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_GOTCH_VLBCH_SHIFT) -#define I40E_GLVEBVL_GOTCL(_i) (0x00330000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_GOTCL_MAX_INDEX 127 -#define I40E_GLVEBVL_GOTCL_VLBCL_SHIFT 0 -#define I40E_GLVEBVL_GOTCL_VLBCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_GOTCL_VLBCL_SHIFT) -#define I40E_GLVEBVL_MPCH(_i) (0x00374404 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_MPCH_MAX_INDEX 127 -#define I40E_GLVEBVL_MPCH_VLMPCH_SHIFT 0 -#define I40E_GLVEBVL_MPCH_VLMPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_MPCH_VLMPCH_SHIFT) -#define I40E_GLVEBVL_MPCL(_i) (0x00374400 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_MPCL_MAX_INDEX 127 -#define I40E_GLVEBVL_MPCL_VLMPCL_SHIFT 0 -#define I40E_GLVEBVL_MPCL_VLMPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_MPCL_VLMPCL_SHIFT) -#define I40E_GLVEBVL_UPCH(_i) (0x00374004 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_UPCH_MAX_INDEX 127 -#define I40E_GLVEBVL_UPCH_VLUPCH_SHIFT 0 -#define I40E_GLVEBVL_UPCH_VLUPCH_MASK I40E_MASK(0xFFFF, I40E_GLVEBVL_UPCH_VLUPCH_SHIFT) -#define I40E_GLVEBVL_UPCL(_i) (0x00374000 + ((_i) * 8)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_GLVEBVL_UPCL_MAX_INDEX 127 -#define I40E_GLVEBVL_UPCL_VLUPCL_SHIFT 0 -#define I40E_GLVEBVL_UPCL_VLUPCL_MASK I40E_MASK(0xFFFFFFFF, I40E_GLVEBVL_UPCL_VLUPCL_SHIFT) -#define I40E_GL_MTG_FLU_MSK_H 0x00269F4C /* Reset: CORER */ -#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT 0 -#define I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_MASK I40E_MASK(0xFFFF, I40E_GL_MTG_FLU_MSK_H_MASK_HIGH_SHIFT) -#define I40E_GL_SWR_DEF_ACT(_i) (0x00270200 + ((_i) * 4)) /* _i=0...35 */ /* Reset: CORER */ -#define I40E_GL_SWR_DEF_ACT_MAX_INDEX 35 -#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT 0 -#define I40E_GL_SWR_DEF_ACT_DEF_ACTION_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_SWR_DEF_ACT_DEF_ACTION_SHIFT) -#define I40E_GL_SWR_DEF_ACT_EN(_i) (0x0026CFB8 + ((_i) * 4)) /* _i=0...1 */ /* Reset: CORER */ -#define I40E_GL_SWR_DEF_ACT_EN_MAX_INDEX 1 -#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT 0 -#define I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_MASK I40E_MASK(0xFFFFFFFF, I40E_GL_SWR_DEF_ACT_EN_DEF_ACT_EN_BITMAP_SHIFT) -#define I40E_PRTTSYN_ADJ 0x001E4280 /* Reset: GLOBR */ -#define I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT 0 -#define I40E_PRTTSYN_ADJ_TSYNADJ_MASK I40E_MASK(0x7FFFFFFF, I40E_PRTTSYN_ADJ_TSYNADJ_SHIFT) -#define I40E_PRTTSYN_ADJ_SIGN_SHIFT 31 -#define I40E_PRTTSYN_ADJ_SIGN_MASK I40E_MASK(0x1, I40E_PRTTSYN_ADJ_SIGN_SHIFT) -#define I40E_PRTTSYN_AUX_0(_i) (0x001E42A0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_AUX_0_MAX_INDEX 1 -#define I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT 0 -#define I40E_PRTTSYN_AUX_0_OUT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_0_OUT_ENA_SHIFT) -#define I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT 1 -#define I40E_PRTTSYN_AUX_0_OUTMOD_MASK I40E_MASK(0x3, I40E_PRTTSYN_AUX_0_OUTMOD_SHIFT) -#define I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT 3 -#define I40E_PRTTSYN_AUX_0_OUTLVL_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_0_OUTLVL_SHIFT) -#define I40E_PRTTSYN_AUX_0_PULSEW_SHIFT 8 -#define I40E_PRTTSYN_AUX_0_PULSEW_MASK I40E_MASK(0xF, I40E_PRTTSYN_AUX_0_PULSEW_SHIFT) -#define I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT 16 -#define I40E_PRTTSYN_AUX_0_EVNTLVL_MASK I40E_MASK(0x3, I40E_PRTTSYN_AUX_0_EVNTLVL_SHIFT) -#define I40E_PRTTSYN_AUX_1(_i) (0x001E42E0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_AUX_1_MAX_INDEX 1 -#define I40E_PRTTSYN_AUX_1_INSTNT_SHIFT 0 -#define I40E_PRTTSYN_AUX_1_INSTNT_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_1_INSTNT_SHIFT) -#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT 1 -#define I40E_PRTTSYN_AUX_1_SAMPLE_TIME_MASK I40E_MASK(0x1, I40E_PRTTSYN_AUX_1_SAMPLE_TIME_SHIFT) -#define I40E_PRTTSYN_CLKO(_i) (0x001E4240 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_CLKO_MAX_INDEX 1 -#define I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT 0 -#define I40E_PRTTSYN_CLKO_TSYNCLKO_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_CLKO_TSYNCLKO_SHIFT) -#define I40E_PRTTSYN_CTL0 0x001E4200 /* Reset: GLOBR */ -#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT 0 -#define I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_CLEAR_TSYNTIMER_SHIFT) -#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT 1 -#define I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TXTIME_INT_ENA_SHIFT) -#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT 2 -#define I40E_PRTTSYN_CTL0_EVENT_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_EVENT_INT_ENA_SHIFT) -#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT 3 -#define I40E_PRTTSYN_CTL0_TGT_INT_ENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TGT_INT_ENA_SHIFT) -#define I40E_PRTTSYN_CTL0_PF_ID_SHIFT 8 -#define I40E_PRTTSYN_CTL0_PF_ID_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL0_PF_ID_SHIFT) -#define I40E_PRTTSYN_CTL0_TSYNACT_SHIFT 12 -#define I40E_PRTTSYN_CTL0_TSYNACT_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL0_TSYNACT_SHIFT) -#define I40E_PRTTSYN_CTL0_TSYNENA_SHIFT 31 -#define I40E_PRTTSYN_CTL0_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL0_TSYNENA_SHIFT) -#define I40E_PRTTSYN_CTL1 0x00085020 /* Reset: CORER */ -#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT 0 -#define I40E_PRTTSYN_CTL1_V1MESSTYPE0_MASK I40E_MASK(0xFF, I40E_PRTTSYN_CTL1_V1MESSTYPE0_SHIFT) -#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT 8 -#define I40E_PRTTSYN_CTL1_V1MESSTYPE1_MASK I40E_MASK(0xFF, I40E_PRTTSYN_CTL1_V1MESSTYPE1_SHIFT) -#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT 16 -#define I40E_PRTTSYN_CTL1_V2MESSTYPE0_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE0_SHIFT) -#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT 20 -#define I40E_PRTTSYN_CTL1_V2MESSTYPE1_MASK I40E_MASK(0xF, I40E_PRTTSYN_CTL1_V2MESSTYPE1_SHIFT) -#define I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT 24 -#define I40E_PRTTSYN_CTL1_TSYNTYPE_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_TSYNTYPE_SHIFT) -#define I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT 26 -#define I40E_PRTTSYN_CTL1_UDP_ENA_MASK I40E_MASK(0x3, I40E_PRTTSYN_CTL1_UDP_ENA_SHIFT) -#define I40E_PRTTSYN_CTL1_TSYNENA_SHIFT 31 -#define I40E_PRTTSYN_CTL1_TSYNENA_MASK I40E_MASK(0x1, I40E_PRTTSYN_CTL1_TSYNENA_SHIFT) -#define I40E_PRTTSYN_EVNT_H(_i) (0x001E40C0 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_EVNT_H_MAX_INDEX 1 -#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT 0 -#define I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_EVNT_H_TSYNEVNT_H_SHIFT) -#define I40E_PRTTSYN_EVNT_L(_i) (0x001E4080 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_EVNT_L_MAX_INDEX 1 -#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT 0 -#define I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_EVNT_L_TSYNEVNT_L_SHIFT) -#define I40E_PRTTSYN_INC_H 0x001E4060 /* Reset: GLOBR */ -#define I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT 0 -#define I40E_PRTTSYN_INC_H_TSYNINC_H_MASK I40E_MASK(0x3F, I40E_PRTTSYN_INC_H_TSYNINC_H_SHIFT) -#define I40E_PRTTSYN_INC_L 0x001E4040 /* Reset: GLOBR */ -#define I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT 0 -#define I40E_PRTTSYN_INC_L_TSYNINC_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_INC_L_TSYNINC_L_SHIFT) -#define I40E_PRTTSYN_RXTIME_H(_i) (0x00085040 + ((_i) * 32)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_PRTTSYN_RXTIME_H_MAX_INDEX 3 -#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT 0 -#define I40E_PRTTSYN_RXTIME_H_RXTIEM_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_RXTIME_H_RXTIEM_H_SHIFT) -#define I40E_PRTTSYN_RXTIME_L(_i) (0x000850C0 + ((_i) * 32)) /* _i=0...3 */ /* Reset: CORER */ -#define I40E_PRTTSYN_RXTIME_L_MAX_INDEX 3 -#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT 0 -#define I40E_PRTTSYN_RXTIME_L_RXTIEM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_RXTIME_L_RXTIEM_L_SHIFT) -#define I40E_PRTTSYN_STAT_0 0x001E4220 /* Reset: GLOBR */ -#define I40E_PRTTSYN_STAT_0_EVENT0_SHIFT 0 -#define I40E_PRTTSYN_STAT_0_EVENT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_EVENT0_SHIFT) -#define I40E_PRTTSYN_STAT_0_EVENT1_SHIFT 1 -#define I40E_PRTTSYN_STAT_0_EVENT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_EVENT1_SHIFT) -#define I40E_PRTTSYN_STAT_0_TGT0_SHIFT 2 -#define I40E_PRTTSYN_STAT_0_TGT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TGT0_SHIFT) -#define I40E_PRTTSYN_STAT_0_TGT1_SHIFT 3 -#define I40E_PRTTSYN_STAT_0_TGT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TGT1_SHIFT) -#define I40E_PRTTSYN_STAT_0_TXTIME_SHIFT 4 -#define I40E_PRTTSYN_STAT_0_TXTIME_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_0_TXTIME_SHIFT) -#define I40E_PRTTSYN_STAT_1 0x00085140 /* Reset: CORER */ -#define I40E_PRTTSYN_STAT_1_RXT0_SHIFT 0 -#define I40E_PRTTSYN_STAT_1_RXT0_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT0_SHIFT) -#define I40E_PRTTSYN_STAT_1_RXT1_SHIFT 1 -#define I40E_PRTTSYN_STAT_1_RXT1_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT1_SHIFT) -#define I40E_PRTTSYN_STAT_1_RXT2_SHIFT 2 -#define I40E_PRTTSYN_STAT_1_RXT2_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT2_SHIFT) -#define I40E_PRTTSYN_STAT_1_RXT3_SHIFT 3 -#define I40E_PRTTSYN_STAT_1_RXT3_MASK I40E_MASK(0x1, I40E_PRTTSYN_STAT_1_RXT3_SHIFT) -#define I40E_PRTTSYN_TGT_H(_i) (0x001E4180 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_TGT_H_MAX_INDEX 1 -#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT 0 -#define I40E_PRTTSYN_TGT_H_TSYNTGTT_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TGT_H_TSYNTGTT_H_SHIFT) -#define I40E_PRTTSYN_TGT_L(_i) (0x001E4140 + ((_i) * 32)) /* _i=0...1 */ /* Reset: GLOBR */ -#define I40E_PRTTSYN_TGT_L_MAX_INDEX 1 -#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT 0 -#define I40E_PRTTSYN_TGT_L_TSYNTGTT_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TGT_L_TSYNTGTT_L_SHIFT) -#define I40E_PRTTSYN_TIME_H 0x001E4120 /* Reset: GLOBR */ -#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT 0 -#define I40E_PRTTSYN_TIME_H_TSYNTIME_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TIME_H_TSYNTIME_H_SHIFT) -#define I40E_PRTTSYN_TIME_L 0x001E4100 /* Reset: GLOBR */ -#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT 0 -#define I40E_PRTTSYN_TIME_L_TSYNTIME_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TIME_L_TSYNTIME_L_SHIFT) -#define I40E_PRTTSYN_TXTIME_H 0x001E41E0 /* Reset: GLOBR */ -#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT 0 -#define I40E_PRTTSYN_TXTIME_H_TXTIEM_H_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TXTIME_H_TXTIEM_H_SHIFT) -#define I40E_PRTTSYN_TXTIME_L 0x001E41C0 /* Reset: GLOBR */ -#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT 0 -#define I40E_PRTTSYN_TXTIME_L_TXTIEM_L_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTTSYN_TXTIME_L_TXTIEM_L_SHIFT) -#define I40E_GL_MDET_RX 0x0012A510 /* Reset: CORER */ -#define I40E_GL_MDET_RX_FUNCTION_SHIFT 0 -#define I40E_GL_MDET_RX_FUNCTION_MASK I40E_MASK(0xFF, I40E_GL_MDET_RX_FUNCTION_SHIFT) -#define I40E_GL_MDET_RX_EVENT_SHIFT 8 -#define I40E_GL_MDET_RX_EVENT_MASK I40E_MASK(0x1FF, I40E_GL_MDET_RX_EVENT_SHIFT) -#define I40E_GL_MDET_RX_QUEUE_SHIFT 17 -#define I40E_GL_MDET_RX_QUEUE_MASK I40E_MASK(0x3FFF, I40E_GL_MDET_RX_QUEUE_SHIFT) -#define I40E_GL_MDET_RX_VALID_SHIFT 31 -#define I40E_GL_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_GL_MDET_RX_VALID_SHIFT) -#define I40E_GL_MDET_TX 0x000E6480 /* Reset: CORER */ -#define I40E_GL_MDET_TX_QUEUE_SHIFT 0 -#define I40E_GL_MDET_TX_QUEUE_MASK I40E_MASK(0xFFF, I40E_GL_MDET_TX_QUEUE_SHIFT) -#define I40E_GL_MDET_TX_VF_NUM_SHIFT 12 -#define I40E_GL_MDET_TX_VF_NUM_MASK I40E_MASK(0x1FF, I40E_GL_MDET_TX_VF_NUM_SHIFT) -#define I40E_GL_MDET_TX_PF_NUM_SHIFT 21 -#define I40E_GL_MDET_TX_PF_NUM_MASK I40E_MASK(0xF, I40E_GL_MDET_TX_PF_NUM_SHIFT) -#define I40E_GL_MDET_TX_EVENT_SHIFT 25 -#define I40E_GL_MDET_TX_EVENT_MASK I40E_MASK(0x1F, I40E_GL_MDET_TX_EVENT_SHIFT) -#define I40E_GL_MDET_TX_VALID_SHIFT 31 -#define I40E_GL_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_GL_MDET_TX_VALID_SHIFT) -#define I40E_PF_MDET_RX 0x0012A400 /* Reset: CORER */ -#define I40E_PF_MDET_RX_VALID_SHIFT 0 -#define I40E_PF_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_PF_MDET_RX_VALID_SHIFT) -#define I40E_PF_MDET_TX 0x000E6400 /* Reset: CORER */ -#define I40E_PF_MDET_TX_VALID_SHIFT 0 -#define I40E_PF_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_PF_MDET_TX_VALID_SHIFT) -#define I40E_PF_VT_PFALLOC 0x001C0500 /* Reset: CORER */ -#define I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT 0 -#define I40E_PF_VT_PFALLOC_FIRSTVF_MASK I40E_MASK(0xFF, I40E_PF_VT_PFALLOC_FIRSTVF_SHIFT) -#define I40E_PF_VT_PFALLOC_LASTVF_SHIFT 8 -#define I40E_PF_VT_PFALLOC_LASTVF_MASK I40E_MASK(0xFF, I40E_PF_VT_PFALLOC_LASTVF_SHIFT) -#define I40E_PF_VT_PFALLOC_VALID_SHIFT 31 -#define I40E_PF_VT_PFALLOC_VALID_MASK I40E_MASK(0x1, I40E_PF_VT_PFALLOC_VALID_SHIFT) -#define I40E_VP_MDET_RX(_VF) (0x0012A000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VP_MDET_RX_MAX_INDEX 127 -#define I40E_VP_MDET_RX_VALID_SHIFT 0 -#define I40E_VP_MDET_RX_VALID_MASK I40E_MASK(0x1, I40E_VP_MDET_RX_VALID_SHIFT) -#define I40E_VP_MDET_TX(_VF) (0x000E6000 + ((_VF) * 4)) /* _i=0...127 */ /* Reset: CORER */ -#define I40E_VP_MDET_TX_MAX_INDEX 127 -#define I40E_VP_MDET_TX_VALID_SHIFT 0 -#define I40E_VP_MDET_TX_VALID_MASK I40E_MASK(0x1, I40E_VP_MDET_TX_VALID_SHIFT) -#define I40E_GLPM_WUMC 0x0006C800 /* Reset: POR */ -#define I40E_GLPM_WUMC_NOTCO_SHIFT 0 -#define I40E_GLPM_WUMC_NOTCO_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_NOTCO_SHIFT) -#define I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT 1 -#define I40E_GLPM_WUMC_SRST_PIN_VAL_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_SRST_PIN_VAL_SHIFT) -#define I40E_GLPM_WUMC_ROL_MODE_SHIFT 2 -#define I40E_GLPM_WUMC_ROL_MODE_MASK I40E_MASK(0x1, I40E_GLPM_WUMC_ROL_MODE_SHIFT) -#define I40E_GLPM_WUMC_RESERVED_4_SHIFT 3 -#define I40E_GLPM_WUMC_RESERVED_4_MASK I40E_MASK(0x1FFF, I40E_GLPM_WUMC_RESERVED_4_SHIFT) -#define I40E_GLPM_WUMC_MNG_WU_PF_SHIFT 16 -#define I40E_GLPM_WUMC_MNG_WU_PF_MASK I40E_MASK(0xFFFF, I40E_GLPM_WUMC_MNG_WU_PF_SHIFT) -#define I40E_PFPM_APM 0x000B8080 /* Reset: POR */ -#define I40E_PFPM_APM_APME_SHIFT 0 -#define I40E_PFPM_APM_APME_MASK I40E_MASK(0x1, I40E_PFPM_APM_APME_SHIFT) -#define I40E_PFPM_FHFT_LENGTH(_i) (0x0006A000 + ((_i) * 128)) /* _i=0...7 */ /* Reset: POR */ -#define I40E_PFPM_FHFT_LENGTH_MAX_INDEX 7 -#define I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT 0 -#define I40E_PFPM_FHFT_LENGTH_LENGTH_MASK I40E_MASK(0xFF, I40E_PFPM_FHFT_LENGTH_LENGTH_SHIFT) -#define I40E_PFPM_WUC 0x0006B200 /* Reset: POR */ -#define I40E_PFPM_WUC_EN_APM_D0_SHIFT 5 -#define I40E_PFPM_WUC_EN_APM_D0_MASK I40E_MASK(0x1, I40E_PFPM_WUC_EN_APM_D0_SHIFT) -#define I40E_PFPM_WUFC 0x0006B400 /* Reset: POR */ -#define I40E_PFPM_WUFC_LNKC_SHIFT 0 -#define I40E_PFPM_WUFC_LNKC_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_LNKC_SHIFT) -#define I40E_PFPM_WUFC_MAG_SHIFT 1 -#define I40E_PFPM_WUFC_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MAG_SHIFT) -#define I40E_PFPM_WUFC_MNG_SHIFT 3 -#define I40E_PFPM_WUFC_MNG_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_MNG_SHIFT) -#define I40E_PFPM_WUFC_FLX0_ACT_SHIFT 4 -#define I40E_PFPM_WUFC_FLX0_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX0_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX1_ACT_SHIFT 5 -#define I40E_PFPM_WUFC_FLX1_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX1_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX2_ACT_SHIFT 6 -#define I40E_PFPM_WUFC_FLX2_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX2_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX3_ACT_SHIFT 7 -#define I40E_PFPM_WUFC_FLX3_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX3_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX4_ACT_SHIFT 8 -#define I40E_PFPM_WUFC_FLX4_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX4_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX5_ACT_SHIFT 9 -#define I40E_PFPM_WUFC_FLX5_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX5_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX6_ACT_SHIFT 10 -#define I40E_PFPM_WUFC_FLX6_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX6_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX7_ACT_SHIFT 11 -#define I40E_PFPM_WUFC_FLX7_ACT_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX7_ACT_SHIFT) -#define I40E_PFPM_WUFC_FLX0_SHIFT 16 -#define I40E_PFPM_WUFC_FLX0_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX0_SHIFT) -#define I40E_PFPM_WUFC_FLX1_SHIFT 17 -#define I40E_PFPM_WUFC_FLX1_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX1_SHIFT) -#define I40E_PFPM_WUFC_FLX2_SHIFT 18 -#define I40E_PFPM_WUFC_FLX2_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX2_SHIFT) -#define I40E_PFPM_WUFC_FLX3_SHIFT 19 -#define I40E_PFPM_WUFC_FLX3_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX3_SHIFT) -#define I40E_PFPM_WUFC_FLX4_SHIFT 20 -#define I40E_PFPM_WUFC_FLX4_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX4_SHIFT) -#define I40E_PFPM_WUFC_FLX5_SHIFT 21 -#define I40E_PFPM_WUFC_FLX5_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX5_SHIFT) -#define I40E_PFPM_WUFC_FLX6_SHIFT 22 -#define I40E_PFPM_WUFC_FLX6_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX6_SHIFT) -#define I40E_PFPM_WUFC_FLX7_SHIFT 23 -#define I40E_PFPM_WUFC_FLX7_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FLX7_SHIFT) -#define I40E_PFPM_WUFC_FW_RST_WK_SHIFT 31 -#define I40E_PFPM_WUFC_FW_RST_WK_MASK I40E_MASK(0x1, I40E_PFPM_WUFC_FW_RST_WK_SHIFT) -#define I40E_PFPM_WUS 0x0006B600 /* Reset: POR */ -#define I40E_PFPM_WUS_LNKC_SHIFT 0 -#define I40E_PFPM_WUS_LNKC_MASK I40E_MASK(0x1, I40E_PFPM_WUS_LNKC_SHIFT) -#define I40E_PFPM_WUS_MAG_SHIFT 1 -#define I40E_PFPM_WUS_MAG_MASK I40E_MASK(0x1, I40E_PFPM_WUS_MAG_SHIFT) -#define I40E_PFPM_WUS_PME_STATUS_SHIFT 2 -#define I40E_PFPM_WUS_PME_STATUS_MASK I40E_MASK(0x1, I40E_PFPM_WUS_PME_STATUS_SHIFT) -#define I40E_PFPM_WUS_MNG_SHIFT 3 -#define I40E_PFPM_WUS_MNG_MASK I40E_MASK(0x1, I40E_PFPM_WUS_MNG_SHIFT) -#define I40E_PFPM_WUS_FLX0_SHIFT 16 -#define I40E_PFPM_WUS_FLX0_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX0_SHIFT) -#define I40E_PFPM_WUS_FLX1_SHIFT 17 -#define I40E_PFPM_WUS_FLX1_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX1_SHIFT) -#define I40E_PFPM_WUS_FLX2_SHIFT 18 -#define I40E_PFPM_WUS_FLX2_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX2_SHIFT) -#define I40E_PFPM_WUS_FLX3_SHIFT 19 -#define I40E_PFPM_WUS_FLX3_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX3_SHIFT) -#define I40E_PFPM_WUS_FLX4_SHIFT 20 -#define I40E_PFPM_WUS_FLX4_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX4_SHIFT) -#define I40E_PFPM_WUS_FLX5_SHIFT 21 -#define I40E_PFPM_WUS_FLX5_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX5_SHIFT) -#define I40E_PFPM_WUS_FLX6_SHIFT 22 -#define I40E_PFPM_WUS_FLX6_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX6_SHIFT) -#define I40E_PFPM_WUS_FLX7_SHIFT 23 -#define I40E_PFPM_WUS_FLX7_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FLX7_SHIFT) -#define I40E_PFPM_WUS_FW_RST_WK_SHIFT 31 -#define I40E_PFPM_WUS_FW_RST_WK_MASK I40E_MASK(0x1, I40E_PFPM_WUS_FW_RST_WK_SHIFT) -#define I40E_PRTPM_FHFHR 0x0006C000 /* Reset: POR */ -#define I40E_PRTPM_FHFHR_UNICAST_SHIFT 0 -#define I40E_PRTPM_FHFHR_UNICAST_MASK I40E_MASK(0x1, I40E_PRTPM_FHFHR_UNICAST_SHIFT) -#define I40E_PRTPM_FHFHR_MULTICAST_SHIFT 1 -#define I40E_PRTPM_FHFHR_MULTICAST_MASK I40E_MASK(0x1, I40E_PRTPM_FHFHR_MULTICAST_SHIFT) -#define I40E_PRTPM_SAH(_i) (0x001E44C0 + ((_i) * 32)) /* _i=0...3 */ /* Reset: PFR */ -#define I40E_PRTPM_SAH_MAX_INDEX 3 -#define I40E_PRTPM_SAH_PFPM_SAH_SHIFT 0 -#define I40E_PRTPM_SAH_PFPM_SAH_MASK I40E_MASK(0xFFFF, I40E_PRTPM_SAH_PFPM_SAH_SHIFT) -#define I40E_PRTPM_SAH_PF_NUM_SHIFT 26 -#define I40E_PRTPM_SAH_PF_NUM_MASK I40E_MASK(0xF, I40E_PRTPM_SAH_PF_NUM_SHIFT) -#define I40E_PRTPM_SAH_MC_MAG_EN_SHIFT 30 -#define I40E_PRTPM_SAH_MC_MAG_EN_MASK I40E_MASK(0x1, I40E_PRTPM_SAH_MC_MAG_EN_SHIFT) -#define I40E_PRTPM_SAH_AV_SHIFT 31 -#define I40E_PRTPM_SAH_AV_MASK I40E_MASK(0x1, I40E_PRTPM_SAH_AV_SHIFT) -#define I40E_PRTPM_SAL(_i) (0x001E4440 + ((_i) * 32)) /* _i=0...3 */ /* Reset: PFR */ -#define I40E_PRTPM_SAL_MAX_INDEX 3 -#define I40E_PRTPM_SAL_PFPM_SAL_SHIFT 0 -#define I40E_PRTPM_SAL_PFPM_SAL_MASK I40E_MASK(0xFFFFFFFF, I40E_PRTPM_SAL_PFPM_SAL_SHIFT) #define I40E_VF_ARQBAH1 0x00006000 /* Reset: EMPR */ #define I40E_VF_ARQBAH1_ARQBAH_SHIFT 0 #define I40E_VF_ARQBAH1_ARQBAH_MASK I40E_MASK(0xFFFFFFFF, I40E_VF_ARQBAH1_ARQBAH_SHIFT) -- GitLab From 2b20c88397fde2902c7834bb9e3ef8afc0237306 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 10 Jul 2015 19:36:07 -0400 Subject: [PATCH 5045/7006] i40e: Remove redundant and unneeded messages The kernel notifies all VXLAN capable registered drivers, i.e. any driver that implements ndo_add_vxlan_port(), of the addition of a port so that the driver can track which ports are in use. There's no need to log this - it just fills the system log with useless and irksome noise. Also, when failing to init SR-IOV interfaces the driver was printing the same message twice. Just remove the inner printk and let the outer message catch enable as well as the other failures. Change-ID: Id5ecb1d425c2a357ee2bc1635dab24553831dade Signed-off-by: Greg Rose Signed-off-by: Jesse Brandeburg Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 -- drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 2 -- 2 files changed, 4 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index c0bfb557bed64..5b605583633df 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -8068,8 +8068,6 @@ static void i40e_add_vxlan_port(struct net_device *netdev, pf->vxlan_ports[next_idx] = port; pf->pending_vxlan_bitmap |= BIT_ULL(next_idx); pf->flags |= I40E_FLAG_VXLAN_FILTER_SYNC; - - dev_info(&pf->pdev->dev, "adding vxlan port %d\n", ntohs(port)); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index 70a6fb14f6dea..ca7a568f28091 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -921,8 +921,6 @@ int i40e_alloc_vfs(struct i40e_pf *pf, u16 num_alloc_vfs) if (pci_num_vf(pf->pdev) != num_alloc_vfs) { ret = pci_enable_sriov(pf->pdev, num_alloc_vfs); if (ret) { - dev_err(&pf->pdev->dev, - "Failed to enable SR-IOV, error %d.\n", ret); pf->num_alloc_vfs = 0; goto err_iov; } -- GitLab From b8262a6dfad8825e0b117fe5e3a1715a585bbd79 Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Fri, 10 Jul 2015 19:36:08 -0400 Subject: [PATCH 5046/7006] i40e/i40evf: add VIRTCHNL_VF_OFFLOAD flag Add virtual channel offload capability to support RX polling mode in the VF. Change-ID: Ib643ae2a7506dfc75fc489fc207493fabefa4832 Signed-off-by: Jingjing Wu Signed-off-by: Anjali Singhai Jain Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_register.h | 7 +++++++ drivers/net/ethernet/intel/i40e/i40e_virtchnl.h | 1 + drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c | 12 ++++++++++++ drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h | 1 + 4 files changed, 21 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index acae6c744bc2e..dc0402fe33700 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -873,6 +873,13 @@ #define I40E_PFINT_CEQCTL_CAUSE_ENA_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_CAUSE_ENA_SHIFT) #define I40E_PFINT_CEQCTL_INTEVENT_SHIFT 31 #define I40E_PFINT_CEQCTL_INTEVENT_MASK I40E_MASK(0x1, I40E_PFINT_CEQCTL_INTEVENT_SHIFT) +#define I40E_GLINT_CTL 0x0003F800 /* Reset: CORER */ +#define I40E_GLINT_CTL_DIS_AUTOMASK_PF0_SHIFT 0 +#define I40E_GLINT_CTL_DIS_AUTOMASK_PF0_MASK I40E_MASK(0x1, I40E_GLINT_CTL_DIS_AUTOMASK_PF0_SHIFT) +#define I40E_GLINT_CTL_DIS_AUTOMASK_VF0_SHIFT 1 +#define I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK I40E_MASK(0x1, I40E_GLINT_CTL_DIS_AUTOMASK_VF0_SHIFT) +#define I40E_GLINT_CTL_DIS_AUTOMASK_N_SHIFT 2 +#define I40E_GLINT_CTL_DIS_AUTOMASK_N_MASK I40E_MASK(0x1, I40E_GLINT_CTL_DIS_AUTOMASK_N_SHIFT) #define I40E_PFINT_DYN_CTL0 0x00038480 /* Reset: PFR */ #define I40E_PFINT_DYN_CTL0_INTENA_SHIFT 0 #define I40E_PFINT_DYN_CTL0_INTENA_MASK I40E_MASK(0x1, I40E_PFINT_DYN_CTL0_INTENA_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h index a7ab463b44746..0f8d4156f8b10 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl.h @@ -152,6 +152,7 @@ struct i40e_virtchnl_vsi_resource { #define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 #define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 #define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 +#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000 struct i40e_virtchnl_vf_resource { u16 num_vsis; diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c index ca7a568f28091..d99c116032f36 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c +++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c @@ -335,6 +335,18 @@ static void i40e_config_irq_link_list(struct i40e_vf *vf, u16 vsi_id, wr32(hw, reg_idx, reg); } + /* if the vf is running in polling mode and using interrupt zero, + * need to disable auto-mask on enabling zero interrupt for VFs. + */ + if ((vf->driver_caps & I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING) && + (vector_id == 0)) { + reg = rd32(hw, I40E_GLINT_CTL); + if (!(reg & I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK)) { + reg |= I40E_GLINT_CTL_DIS_AUTOMASK_VF0_MASK; + wr32(hw, I40E_GLINT_CTL, reg); + } + } + irq_list_done: i40e_flush(hw); } diff --git a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h index 1e89dea0d5292..e6db20e8a395b 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_virtchnl.h @@ -152,6 +152,7 @@ struct i40e_virtchnl_vsi_resource { #define I40E_VIRTCHNL_VF_OFFLOAD_RSS_AQ 0x00000008 #define I40E_VIRTCHNL_VF_OFFLOAD_RSS_REG 0x00000010 #define I40E_VIRTCHNL_VF_OFFLOAD_VLAN 0x00010000 +#define I40E_VIRTCHNL_VF_OFFLOAD_RX_POLLING 0x00020000 struct i40e_virtchnl_vf_resource { u16 num_vsis; -- GitLab From 9fffa3f34dff2585ae86cd5b59c68ad2d4172f25 Mon Sep 17 00:00:00 2001 From: Neerav Parikh Date: Fri, 10 Jul 2015 19:36:09 -0400 Subject: [PATCH 5047/7006] i40e/i40evf: Cache the CEE TLV status returned from firmware Store the CEE TLV status returned by firmware to allow drivers to dump that for debug purposes. Change-ID: Ie3c4cf8cebabee4f15e1e3fdc4fc8a68bbca40ee Signed-off-by: Neerav Parikh Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_dcb.c | 4 ++++ drivers/net/ethernet/intel/i40e/i40e_type.h | 1 + drivers/net/ethernet/intel/i40evf/i40e_type.h | 1 + 3 files changed, 6 insertions(+) diff --git a/drivers/net/ethernet/intel/i40e/i40e_dcb.c b/drivers/net/ethernet/intel/i40e/i40e_dcb.c index 2547aa21b2cac..90de46aef5579 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_dcb.c +++ b/drivers/net/ethernet/intel/i40e/i40e_dcb.c @@ -588,6 +588,8 @@ i40e_status i40e_get_dcb_config(struct i40e_hw *hw) if (!ret) { /* CEE mode */ hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; + hw->local_dcbx_config.tlv_status = + le16_to_cpu(cee_v1_cfg.tlv_status); i40e_cee_to_dcb_v1_config(&cee_v1_cfg, &hw->local_dcbx_config); } @@ -597,6 +599,8 @@ i40e_status i40e_get_dcb_config(struct i40e_hw *hw) if (!ret) { /* CEE mode */ hw->local_dcbx_config.dcbx_mode = I40E_DCBX_MODE_CEE; + hw->local_dcbx_config.tlv_status = + le32_to_cpu(cee_cfg.tlv_status); i40e_cee_to_dcb_config(&cee_cfg, &hw->local_dcbx_config); } diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index acb2aad54b48b..4842239ee7779 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -440,6 +440,7 @@ struct i40e_dcbx_config { #define I40E_DCBX_MODE_CEE 0x1 #define I40E_DCBX_MODE_IEEE 0x2 u32 numapps; + u32 tlv_status; /* CEE mode TLV status */ struct i40e_dcb_ets_config etscfg; struct i40e_dcb_ets_config etsrec; struct i40e_dcb_pfc_config pfc; diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h index 1ab2498d68df2..24a2693869a10 100644 --- a/drivers/net/ethernet/intel/i40evf/i40e_type.h +++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h @@ -434,6 +434,7 @@ struct i40e_ieee_app_priority_table { struct i40e_dcbx_config { u32 numapps; + u32 tlv_status; /* CEE mode TLV status */ struct i40e_ieee_ets_config etscfg; struct i40e_ieee_ets_recommend etsrec; struct i40e_ieee_pfc_config pfc; -- GitLab From bf41846edf5b1618a37f8ec830251b31d8ed6ab3 Mon Sep 17 00:00:00 2001 From: Catherine Sullivan Date: Fri, 10 Jul 2015 19:36:10 -0400 Subject: [PATCH 5048/7006] i40e/i40evf: Bump i40e to 1.3.9 and i40evf to 1.3.5 Bump version and update the copyright year for i40evf. Change-ID: Iddb81b9dba09f0dc57ab54937b5821ecdd721ff6 Signed-off-by: Catherine Sullivan Tested-by: Andrew Bowers Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e_main.c | 2 +- drivers/net/ethernet/intel/i40evf/i40evf_main.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index 5b605583633df..a97f193382d79 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -39,7 +39,7 @@ static const char i40e_driver_string[] = #define DRV_VERSION_MAJOR 1 #define DRV_VERSION_MINOR 3 -#define DRV_VERSION_BUILD 6 +#define DRV_VERSION_BUILD 9 #define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \ __stringify(DRV_VERSION_MINOR) "." \ __stringify(DRV_VERSION_BUILD) DRV_KERN diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c index c2ba40f37ecf0..e85849b9ff98a 100644 --- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c +++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c @@ -34,10 +34,10 @@ char i40evf_driver_name[] = "i40evf"; static const char i40evf_driver_string[] = "Intel(R) XL710/X710 Virtual Function Network Driver"; -#define DRV_VERSION "1.3.2" +#define DRV_VERSION "1.3.5" const char i40evf_driver_version[] = DRV_VERSION; static const char i40evf_copyright[] = - "Copyright (c) 2013 - 2014 Intel Corporation."; + "Copyright (c) 2013 - 2015 Intel Corporation."; /* i40evf_pci_tbl - PCI Device ID Table * -- GitLab From 5d0ddfebb93069061880fc57ee4ba7246bd1e1ee Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Fri, 21 Aug 2015 15:36:23 +0800 Subject: [PATCH 5049/7006] ACPI, PCI: Penalize legacy IRQ used by ACPI SCI Nick Meier reported a regression with HyperV that " After rebooting the VM, the following messages are logged in syslog when trying to load the tulip driver: tulip: Linux Tulip drivers version 1.1.15 (Feb 27, 2007) tulip: 0000:00:0a.0: PCI INT A: failed to register GSI tulip: Cannot enable tulip board #0, aborting tulip: probe of 0000:00:0a.0 failed with error -16 Errors occur in 3.19.0 kernel Works in 3.17 kernel. " According to the ACPI dump file posted by Nick at https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1440072 The ACPI MADT table includes an interrupt source overridden entry for ACPI SCI: [236h 0566 1] Subtable Type : 02 [237h 0567 1] Length : 0A [238h 0568 1] Bus : 00 [239h 0569 1] Source : 09 [23Ah 0570 4] Interrupt : 00000009 [23Eh 0574 2] Flags (decoded below) : 000D Polarity : 1 Trigger Mode : 3 And in DSDT table, we have _PRT method to define PCI interrupts, which eventually goes to: Name (PRSA, ResourceTemplate () { IRQ (Level, ActiveLow, Shared, ) {3,4,5,7,9,10,11,12,14,15} }) Name (PRSB, ResourceTemplate () { IRQ (Level, ActiveLow, Shared, ) {3,4,5,7,9,10,11,12,14,15} }) Name (PRSC, ResourceTemplate () { IRQ (Level, ActiveLow, Shared, ) {3,4,5,7,9,10,11,12,14,15} }) Name (PRSD, ResourceTemplate () { IRQ (Level, ActiveLow, Shared, ) {3,4,5,7,9,10,11,12,14,15} }) According to the MADT and DSDT tables, IRQ 9 may be used for: 1) ACPI SCI in level, high mode 2) PCI legacy IRQ in level, low mode So there's a conflict in polarity setting for IRQ 9. Prior to commit cd68f6bd53cf ("x86, irq, acpi: Get rid of special handling of GSI for ACPI SCI"), ACPI SCI is handled specially and there's no check for conflicts between ACPI SCI and PCI legagy IRQ. And it seems that the HyperV hypervisor doesn't make use of the polarity configuration in IOAPIC entry, so it just works. Commit cd68f6bd53cf gets rid of the specially handling of ACPI SCI, and then the pin attribute checking code discloses the conflicts between ACPI SCI and PCI legacy IRQ on HyperV virtual machine, and rejects the request to assign IRQ9 to PCI devices. So penalize legacy IRQ used by ACPI SCI and mark it unusable if ACPI SCI attributes conflict with PCI IRQ attributes. Please refer to following links for more information: https://bugzilla.kernel.org/show_bug.cgi?id=101301 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1440072 Fixes: cd68f6bd53cf ("x86, irq, acpi: Get rid of special handling of GSI for ACPI SCI") Reported-and-tested-by: Nick Meier Acked-by: Thomas Gleixner Cc: 3.19+ # 3.19+ Signed-off-by: Jiang Liu Signed-off-by: Rafael J. Wysocki --- arch/x86/kernel/acpi/boot.c | 1 + drivers/acpi/pci_link.c | 16 ++++++++++++++++ include/linux/acpi.h | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index e49ee24da85e1..9393896717d0c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -445,6 +445,7 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); + acpi_penalize_sci_irq(bus_irq, trigger, polarity); /* * stash over-ride to indicate we've been here diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c index cfd7581cc19fa..b09ad554430ac 100644 --- a/drivers/acpi/pci_link.c +++ b/drivers/acpi/pci_link.c @@ -825,6 +825,22 @@ void acpi_penalize_isa_irq(int irq, int active) } } +/* + * Penalize IRQ used by ACPI SCI. If ACPI SCI pin attributes conflict with + * PCI IRQ attributes, mark ACPI SCI as ISA_ALWAYS so it won't be use for + * PCI IRQs. + */ +void acpi_penalize_sci_irq(int irq, int trigger, int polarity) +{ + if (irq >= 0 && irq < ARRAY_SIZE(acpi_irq_penalty)) { + if (trigger != ACPI_MADT_TRIGGER_LEVEL || + polarity != ACPI_MADT_POLARITY_ACTIVE_LOW) + acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_ALWAYS; + else + acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING; + } +} + /* * Over-ride default table to reserve additional IRQs for use by ISA * e.g. acpi_irq_isa=5 diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d2445fa9999f9..0b2394f61af4d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -221,7 +221,7 @@ struct pci_dev; int acpi_pci_irq_enable (struct pci_dev *dev); void acpi_penalize_isa_irq(int irq, int active); - +void acpi_penalize_sci_irq(int irq, int trigger, int polarity); void acpi_pci_irq_disable (struct pci_dev *dev); extern int ec_read(u8 addr, u8 *val); -- GitLab From 77678d3a35455d7b7c4da4e56b20de17ee63cec1 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:12:22 -0500 Subject: [PATCH 5050/7006] hpsa: Correct double unlock of mutex Reported-by: Dan Carpenter Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cab4e98b2b0e8..cb11421f9cb83 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -2749,11 +2749,10 @@ static int hpsa_do_reset(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, lockup_detected(h)); if (unlikely(lockup_detected(h))) { - dev_warn(&h->pdev->dev, - "Controller lockup detected during reset wait\n"); - mutex_unlock(&h->reset_mutex); - rc = -ENODEV; - } + dev_warn(&h->pdev->dev, + "Controller lockup detected during reset wait\n"); + rc = -ENODEV; + } if (unlikely(rc)) atomic_set(&dev->reset_cmds_out, 0); -- GitLab From 81c275576bcee1a80e046117c7923586216a2dd4 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:12:28 -0500 Subject: [PATCH 5051/7006] hpsa: correct decode sense data Reported-by: Dan Carpenter Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index cb11421f9cb83..ce9122d37a8b7 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -325,7 +325,7 @@ static int check_for_unit_attention(struct ctlr_info *h, decode_sense_data(c->err_info->SenseInfo, sense_len, &sense_key, &asc, &ascq); - if (sense_key != UNIT_ATTENTION || asc == -1) + if (sense_key != UNIT_ATTENTION || asc == 0xff) return 0; switch (asc) { -- GitLab From 7ef7323f4bf467ce9fe51177301ad8cbb7dc2631 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:12:33 -0500 Subject: [PATCH 5052/7006] hpsa: correct static checker warnings on driver init cleanup Reported-by: Dan Carpenter Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index ce9122d37a8b7..47d02871371d5 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8056,7 +8056,7 @@ reinit_after_soft_reset: rc = hpsa_kdump_soft_reset(h); if (rc) /* Neither hard nor soft reset worked, we're hosed. */ - goto clean9; + goto clean7; dev_info(&h->pdev->dev, "Board READY.\n"); dev_info(&h->pdev->dev, @@ -8102,8 +8102,6 @@ reinit_after_soft_reset: h->heartbeat_sample_interval); return 0; -clean9: /* wq, sh, perf, sg, cmd, irq, shost, pci, lu, aer/h */ - kfree(h->hba_inquiry_data); clean7: /* perf, sg, cmd, irq, shost, pci, lu, aer/h */ hpsa_free_performant_mode(h); h->access.set_intr_mask(h, HPSA_INTR_OFF); -- GitLab From 1358f6dc5875f5cef06eeeeb4532f382aaff8483 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:12:38 -0500 Subject: [PATCH 5053/7006] hpsa: add PMC to copyright need to add PMC to copyright notice and update the Hewlett-Packard copyright notification. Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Reviewed-by: Justin Lindley Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 9 +++------ drivers/scsi/hpsa.h | 9 +++------ drivers/scsi/hpsa_cmd.h | 9 +++------ 3 files changed, 9 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 47d02871371d5..984bbd9e0535e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1,6 +1,7 @@ /* * Disk Array driver for HP Smart Array SAS controllers - * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P. + * Copyright 2014-2015 PMC-Sierra, Inc. + * Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P. * * 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 @@ -11,11 +12,7 @@ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com + * Questions/Comments/Bugfixes to storagedev@pmcs.com * */ diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 6ee4da6b11536..6f6084b394201 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -1,6 +1,7 @@ /* * Disk Array driver for HP Smart Array SAS controllers - * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P. + * Copyright 2014-2015 PMC-Sierra, Inc. + * Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P. * * 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 @@ -11,11 +12,7 @@ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com + * Questions/Comments/Bugfixes to storagedev@pmcs.com * */ #ifndef HPSA_H diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index c601622cc98e5..1a98bbebf15b9 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -1,6 +1,7 @@ /* * Disk Array driver for HP Smart Array SAS controllers - * Copyright 2000, 2014 Hewlett-Packard Development Company, L.P. + * Copyright 2014-2015 PMC-Sierra, Inc. + * Copyright 2000,2009-2015 Hewlett-Packard Development Company, L.P. * * 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 @@ -11,11 +12,7 @@ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or * NON INFRINGEMENT. See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Questions/Comments/Bugfixes to iss_storagedev@hp.com + * Questions/Comments/Bugfixes to storagedev@pmcs.com * */ #ifndef HPSA_CMD_H -- GitLab From 8270b8624365887a716615294d0ac28af07c9287 Mon Sep 17 00:00:00 2001 From: Joe Handzik Date: Sat, 18 Jul 2015 11:12:43 -0500 Subject: [PATCH 5054/7006] hpsa: add sysfs entry path_info to show box and bay information host no, bus, target, lun, scsi_device_type for hba mode add: box and bay information report if the path is active/inactive Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 122 ++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/hpsa.h | 5 ++ 2 files changed, 127 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 984bbd9e0535e..43c34a61c66c3 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -264,6 +264,7 @@ static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h, static void hpsa_command_resubmit_worker(struct work_struct *work); static u32 lockup_detected(struct ctlr_info *h); static int detect_controller_lockup(struct ctlr_info *h); +static int is_ext_target(struct ctlr_info *h, struct hpsa_scsi_dev_t *device); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) { @@ -714,12 +715,106 @@ static ssize_t host_show_hp_ssd_smart_path_enabled(struct device *dev, return snprintf(buf, 20, "%d\n", offload_enabled); } +#define MAX_PATHS 8 +#define PATH_STRING_LEN 50 + +static ssize_t path_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ctlr_info *h; + struct scsi_device *sdev; + struct hpsa_scsi_dev_t *hdev; + unsigned long flags; + int i; + int output_len = 0; + u8 box; + u8 bay; + u8 path_map_index = 0; + char *active; + unsigned char phys_connector[2]; + unsigned char path[MAX_PATHS][PATH_STRING_LEN]; + + memset(path, 0, MAX_PATHS * PATH_STRING_LEN); + sdev = to_scsi_device(dev); + h = sdev_to_hba(sdev); + spin_lock_irqsave(&h->devlock, flags); + hdev = sdev->hostdata; + if (!hdev) { + spin_unlock_irqrestore(&h->devlock, flags); + return -ENODEV; + } + + bay = hdev->bay; + for (i = 0; i < MAX_PATHS; i++) { + path_map_index = 1<active_path_index) + active = "Active"; + else if (hdev->path_map & path_map_index) + active = "Inactive"; + else + continue; + + output_len = snprintf(path[i], + PATH_STRING_LEN, "[%d:%d:%d:%d] %20.20s ", + h->scsi_host->host_no, + hdev->bus, hdev->target, hdev->lun, + scsi_device_type(hdev->devtype)); + + if (is_ext_target(h, hdev) || + (hdev->devtype == TYPE_RAID) || + is_logical_dev_addr_mode(hdev->scsi3addr)) { + output_len += snprintf(path[i] + output_len, + PATH_STRING_LEN, "%s\n", + active); + continue; + } + + box = hdev->box[i]; + memcpy(&phys_connector, &hdev->phys_connector[i], + sizeof(phys_connector)); + if (phys_connector[0] < '0') + phys_connector[0] = '0'; + if (phys_connector[1] < '0') + phys_connector[1] = '0'; + if (hdev->phys_connector[i] > 0) + output_len += snprintf(path[i] + output_len, + PATH_STRING_LEN, + "PORT: %.2s ", + phys_connector); + if (hdev->devtype == TYPE_DISK && h->hba_mode_enabled) { + if (box == 0 || box == 0xFF) { + output_len += snprintf(path[i] + output_len, + PATH_STRING_LEN, + "BAY: %hhu %s\n", + bay, active); + } else { + output_len += snprintf(path[i] + output_len, + PATH_STRING_LEN, + "BOX: %hhu BAY: %hhu %s\n", + box, bay, active); + } + } else if (box != 0 && box != 0xFF) { + output_len += snprintf(path[i] + output_len, + PATH_STRING_LEN, "BOX: %hhu %s\n", + box, active); + } else + output_len += snprintf(path[i] + output_len, + PATH_STRING_LEN, "%s\n", active); + } + + spin_unlock_irqrestore(&h->devlock, flags); + return snprintf(buf, output_len+1, "%s%s%s%s%s%s%s%s", + path[0], path[1], path[2], path[3], + path[4], path[5], path[6], path[7]); +} + static DEVICE_ATTR(raid_level, S_IRUGO, raid_level_show, NULL); static DEVICE_ATTR(lunid, S_IRUGO, lunid_show, NULL); static DEVICE_ATTR(unique_id, S_IRUGO, unique_id_show, NULL); static DEVICE_ATTR(rescan, S_IWUSR, NULL, host_store_rescan); static DEVICE_ATTR(hp_ssd_smart_path_enabled, S_IRUGO, host_show_hp_ssd_smart_path_enabled, NULL); +static DEVICE_ATTR(path_info, S_IRUGO, path_info_show, NULL); static DEVICE_ATTR(hp_ssd_smart_path_status, S_IWUSR|S_IRUGO|S_IROTH, host_show_hp_ssd_smart_path_status, host_store_hp_ssd_smart_path_status); @@ -741,6 +836,7 @@ static struct device_attribute *hpsa_sdev_attrs[] = { &dev_attr_lunid, &dev_attr_unique_id, &dev_attr_hp_ssd_smart_path_enabled, + &dev_attr_path_info, &dev_attr_lockup_detected, NULL, }; @@ -3611,6 +3707,31 @@ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, atomic_set(&dev->reset_cmds_out, 0); } +static void hpsa_get_path_info(struct hpsa_scsi_dev_t *this_device, + u8 *lunaddrbytes, + struct bmic_identify_physical_device *id_phys) +{ + if (PHYS_IOACCEL(lunaddrbytes) + && this_device->ioaccel_handle) + this_device->hba_ioaccel_enabled = 1; + + memcpy(&this_device->active_path_index, + &id_phys->active_path_number, + sizeof(this_device->active_path_index)); + memcpy(&this_device->path_map, + &id_phys->redundant_path_present_map, + sizeof(this_device->path_map)); + memcpy(&this_device->box, + &id_phys->alternate_paths_phys_box_on_port, + sizeof(this_device->box)); + memcpy(&this_device->phys_connector, + &id_phys->alternate_paths_phys_connector, + sizeof(this_device->phys_connector)); + memcpy(&this_device->bay, + &id_phys->phys_bay_in_box, + sizeof(this_device->bay)); +} + static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) { /* the idea here is we could get notified @@ -3771,6 +3892,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) hpsa_get_ioaccel_drive_info(h, this_device, lunaddrbytes, id_phys); + hpsa_get_path_info(this_device, lunaddrbytes, id_phys); atomic_set(&this_device->ioaccel_cmds_out, 0); ncurrent++; break; diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 6f6084b394201..ab014d3f3656a 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -50,6 +50,11 @@ struct hpsa_scsi_dev_t { * device via "ioaccel" path. */ u32 ioaccel_handle; + u8 active_path_index; + u8 path_map; + u8 bay; + u8 box[8]; + u16 phys_connector[8]; int offload_config; /* I/O accel RAID offload configured */ int offload_enabled; /* I/O accel RAID offload enabled */ int offload_to_be_enabled; -- GitLab From 9384950809d96ee08dcd7bb2eadc9628b99d0474 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:12:49 -0500 Subject: [PATCH 5055/7006] hpsa: cleanup update scsi devices showing that tables have been updated unnecessarily. Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 43c34a61c66c3..9d3291379b294 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1379,8 +1379,9 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1, return 1; if (dev1->offload_enabled != dev2->offload_enabled) return 1; - if (dev1->queue_depth != dev2->queue_depth) - return 1; + if (!is_logical_dev_addr_mode(dev1->scsi3addr)) + if (dev1->queue_depth != dev2->queue_depth) + return 1; return 0; } @@ -3889,7 +3890,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) else if (!(h->transMethod & CFGTBL_Trans_io_accel1 || h->transMethod & CFGTBL_Trans_io_accel2)) break; - hpsa_get_ioaccel_drive_info(h, this_device, lunaddrbytes, id_phys); hpsa_get_path_info(this_device, lunaddrbytes, id_phys); -- GitLab From cbb47dcbb405d4a694801e6ad6d63c2992f83bb4 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:12:54 -0500 Subject: [PATCH 5056/7006] hpsa: add in new controllers Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Signed-off-by: Don Brace Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 9d3291379b294..212e82663707e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -129,6 +129,11 @@ static const struct pci_device_id hpsa_pci_device_id[] = { {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CD}, {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSI, 0x103C, 0x21CE}, {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0580}, + {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0581}, + {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0582}, + {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0583}, + {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0584}, + {PCI_VENDOR_ID_ADAPTEC2, 0x0290, 0x9005, 0x0585}, {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0076}, {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x0087}, {PCI_VENDOR_ID_HP_3PAR, 0x0075, 0x1590, 0x007D}, @@ -187,6 +192,11 @@ static struct board_type products[] = { {0x21CD103C, "Smart Array", &SA5_access}, {0x21CE103C, "Smart HBA", &SA5_access}, {0x05809005, "SmartHBA-SA", &SA5_access}, + {0x05819005, "SmartHBA-SA 8i", &SA5_access}, + {0x05829005, "SmartHBA-SA 8i8e", &SA5_access}, + {0x05839005, "SmartHBA-SA 8e", &SA5_access}, + {0x05849005, "SmartHBA-SA 16i", &SA5_access}, + {0x05859005, "SmartHBA-SA 4i4e", &SA5_access}, {0x00761590, "HP Storage P1224 Array Controller", &SA5_access}, {0x00871590, "HP Storage P1224e Array Controller", &SA5_access}, {0x007D1590, "HP Storage P1228 Array Controller", &SA5_access}, -- GitLab From b9092b79ccaf4404509d6aeb2c76eb7cbfa57bf1 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Sat, 18 Jul 2015 11:12:59 -0500 Subject: [PATCH 5057/7006] Change how controllers in mixed mode are handled. Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 97 +++++---------------------------------------- drivers/scsi/hpsa.h | 2 - 2 files changed, 11 insertions(+), 88 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 212e82663707e..bf877eb61016e 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -791,7 +791,8 @@ static ssize_t path_info_show(struct device *dev, PATH_STRING_LEN, "PORT: %.2s ", phys_connector); - if (hdev->devtype == TYPE_DISK && h->hba_mode_enabled) { + if (hdev->devtype == TYPE_DISK && + hdev->expose_state != HPSA_DO_NOT_EXPOSE) { if (box == 0 || box == 0xFF) { output_len += snprintf(path[i] + output_len, PATH_STRING_LEN, @@ -2689,34 +2690,6 @@ out: return rc; } -static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h, - unsigned char *scsi3addr, unsigned char page, - struct bmic_controller_parameters *buf, size_t bufsize) -{ - int rc = IO_OK; - struct CommandList *c; - struct ErrorInfo *ei; - - c = cmd_alloc(h); - if (fill_cmd(c, BMIC_SENSE_CONTROLLER_PARAMETERS, h, buf, bufsize, - page, scsi3addr, TYPE_CMD)) { - rc = -1; - goto out; - } - rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, - PCI_DMA_FROMDEVICE, NO_TIMEOUT); - if (rc) - goto out; - ei = c->err_info; - if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { - hpsa_scsi_interpret_error(h, c); - rc = -1; - } -out: - cmd_free(h, c); - return rc; -} - static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr, u8 reset_type, int reply_queue) { @@ -3665,29 +3638,6 @@ static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, return NULL; } -static int hpsa_hba_mode_enabled(struct ctlr_info *h) -{ - int rc; - int hba_mode_enabled; - struct bmic_controller_parameters *ctlr_params; - ctlr_params = kzalloc(sizeof(struct bmic_controller_parameters), - GFP_KERNEL); - - if (!ctlr_params) - return -ENOMEM; - rc = hpsa_bmic_ctrl_mode_sense(h, RAID_CTLR_LUNID, 0, ctlr_params, - sizeof(struct bmic_controller_parameters)); - if (rc) { - kfree(ctlr_params); - return rc; - } - - hba_mode_enabled = - ((ctlr_params->nvram_flags & HBA_MODE_ENABLED_FLAG) != 0); - kfree(ctlr_params); - return hba_mode_enabled; -} - /* get physical drive ioaccel handle and queue depth */ static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h, struct hpsa_scsi_dev_t *dev, @@ -3765,7 +3715,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) int ncurrent = 0; int i, n_ext_target_devs, ndevs_to_allocate; int raid_ctlr_position; - int rescan_hba_mode; DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS); currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL); @@ -3781,17 +3730,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) } memset(lunzerobits, 0, sizeof(lunzerobits)); - rescan_hba_mode = hpsa_hba_mode_enabled(h); - if (rescan_hba_mode < 0) - goto out; - - if (!h->hba_mode_enabled && rescan_hba_mode) - dev_warn(&h->pdev->dev, "HBA mode enabled\n"); - else if (h->hba_mode_enabled && !rescan_hba_mode) - dev_warn(&h->pdev->dev, "HBA mode disabled\n"); - - h->hba_mode_enabled = rescan_hba_mode; - if (hpsa_gather_lun_info(h, physdev_list, &nphysicals, logdev_list, &nlogicals)) goto out; @@ -3867,9 +3805,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) /* do not expose masked devices */ if (MASKED_DEVICE(lunaddrbytes) && i < nphysicals + (raid_ctlr_position == 0)) { - if (h->hba_mode_enabled) - dev_warn(&h->pdev->dev, - "Masked physical device detected\n"); this_device->expose_state = HPSA_DO_NOT_EXPOSE; } else { this_device->expose_state = @@ -3889,30 +3824,21 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) ncurrent++; break; case TYPE_DISK: - if (i >= nphysicals) { - ncurrent++; - break; - } - - if (h->hba_mode_enabled) - /* never use raid mapper in HBA mode */ + if (i < nphysicals + (raid_ctlr_position == 0)) { + /* The disk is in HBA mode. */ + /* Never use RAID mapper in HBA mode. */ this_device->offload_enabled = 0; - else if (!(h->transMethod & CFGTBL_Trans_io_accel1 || - h->transMethod & CFGTBL_Trans_io_accel2)) - break; - hpsa_get_ioaccel_drive_info(h, this_device, - lunaddrbytes, id_phys); - hpsa_get_path_info(this_device, lunaddrbytes, id_phys); - atomic_set(&this_device->ioaccel_cmds_out, 0); + hpsa_get_ioaccel_drive_info(h, this_device, + lunaddrbytes, id_phys); + hpsa_get_path_info(this_device, lunaddrbytes, + id_phys); + } ncurrent++; break; case TYPE_TAPE: case TYPE_MEDIUM_CHANGER: - ncurrent++; - break; case TYPE_ENCLOSURE: - if (h->hba_mode_enabled) - ncurrent++; + ncurrent++; break; case TYPE_RAID: /* Only present the Smartarray HBA as a RAID controller. @@ -8120,7 +8046,6 @@ reinit_after_soft_reset: pci_set_drvdata(pdev, h); h->ndevices = 0; - h->hba_mode_enabled = 0; spin_lock_init(&h->devlock); rc = hpsa_put_ctlr_into_performant_mode(h); diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index ab014d3f3656a..27debb363529e 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -116,7 +116,6 @@ struct bmic_controller_parameters { u8 automatic_drive_slamming; u8 reserved1; u8 nvram_flags; -#define HBA_MODE_ENABLED_FLAG (1 << 3) u8 cache_nvram_flags; u8 drive_config_flags; u16 reserved2; @@ -155,7 +154,6 @@ struct ctlr_info { unsigned int msi_vector; int intr_mode; /* either PERF_MODE_INT or SIMPLE_MODE_INT */ struct access_method access; - char hba_mode_enabled; /* queue and queue Info */ unsigned int Qdepth; -- GitLab From 5ca0120447ae8d485e2ee5100f25b6645e3e320f Mon Sep 17 00:00:00 2001 From: Scott Benesh Date: Sat, 18 Jul 2015 11:13:04 -0500 Subject: [PATCH 5058/7006] hpsa: add in new offline mode prevent adding volumes that are not available. Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Justin Lindley Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 15 +++++++++++---- drivers/scsi/hpsa_cmd.h | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index bf877eb61016e..07512463b9901 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1481,17 +1481,23 @@ static void hpsa_show_volume_status(struct ctlr_info *h, h->scsi_host->host_no, sd->bus, sd->target, sd->lun); break; + case HPSA_LV_NOT_AVAILABLE: + dev_info(&h->pdev->dev, + "C%d:B%d:T%d:L%d Volume is waiting for transforming volume.\n", + h->scsi_host->host_no, + sd->bus, sd->target, sd->lun); + break; case HPSA_LV_UNDERGOING_RPI: dev_info(&h->pdev->dev, - "C%d:B%d:T%d:L%d Volume is undergoing rapid parity initialization process.\n", + "C%d:B%d:T%d:L%d Volume is undergoing rapid parity init.\n", h->scsi_host->host_no, sd->bus, sd->target, sd->lun); break; case HPSA_LV_PENDING_RPI: dev_info(&h->pdev->dev, - "C%d:B%d:T%d:L%d Volume is queued for rapid parity initialization process.\n", - h->scsi_host->host_no, - sd->bus, sd->target, sd->lun); + "C%d:B%d:T%d:L%d Volume is queued for rapid parity initialization process.\n", + h->scsi_host->host_no, + sd->bus, sd->target, sd->lun); break; case HPSA_LV_ENCRYPTED_NO_KEY: dev_info(&h->pdev->dev, @@ -3262,6 +3268,7 @@ static int hpsa_volume_offline(struct ctlr_info *h, /* Keep volume offline in certain cases: */ switch (ldstat) { case HPSA_LV_UNDERGOING_ERASE: + case HPSA_LV_NOT_AVAILABLE: case HPSA_LV_UNDERGOING_RPI: case HPSA_LV_PENDING_RPI: case HPSA_LV_ENCRYPTED_NO_KEY: diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 1a98bbebf15b9..47c756ba8dce4 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -164,6 +164,7 @@ /* Logical volume states */ #define HPSA_VPD_LV_STATUS_UNSUPPORTED 0xff #define HPSA_LV_OK 0x0 +#define HPSA_LV_NOT_AVAILABLE 0x0b #define HPSA_LV_UNDERGOING_ERASE 0x0F #define HPSA_LV_UNDERGOING_RPI 0x12 #define HPSA_LV_PENDING_RPI 0x13 -- GitLab From 9a4178b76a973684750d20b684bae4f57ab9a355 Mon Sep 17 00:00:00 2001 From: "shane.seymour" Date: Sat, 18 Jul 2015 11:13:09 -0500 Subject: [PATCH 5059/7006] hpsa: fix issues with multilun devices A regression was introduced into the hpsa driver a while back so non-zero LUNs of multi-LUN devices may no longer be presented via a SAS based Smart Array. I have not done a bisection to discover the change that caused it. The CISS firmware specification (available on sourceforge) defines an 8 byte lunid that describes devices that the Smart Array can see/present to the system. The current code in the hpsa driver attempts to find matches for non-zero LUNs with LUN 0 for a bus/target by zeroing out byte 4 of the lunid and find a match. This method is sufficient for SCSI based Smart Arrays because byte 5 is always 0. For SAS based Smart arrays byte 5 of the lunid contains the path number for a multipath device and either one or two bits (the documentation does not define how many bits are used but it appears it may be one only) that indicate if the given path number in byte 5 must always be used to access that device. Byte 5 may not always be zero. The following are lunids (spaces added for clarity) for a MSL2024 single drive library connected via a H241 Smart Array: 00 00 00 00 01 00 00 01 (changer) 00 00 00 00 00 80 00 01 (tape) In the 4th byte (counting from 0) you can see that the tape is LUN 0 and the changer is LUN 1. The 0x80 set in the 5th byte for the tape drive means the driver should force access to path 0 (the library in this case was connected to one path only anyway). After the changes we can see the following in the dmesg output: scsi 0:3:0:0: RAID HP H241 1.18 \ PQ: 0 ANSI: 5 scsi 0:2:0:0: Sequential-Access HP Ultrium 6-SCSI 354W \ PQ: 0 ANSI: 6 scsi 0:2:0:1: Medium Changer HP MSL G3 Series 8.70 \ PQ: 0 ANSI: 5 Showing that the changer is correctly identified as LUN 1 of bus 2 target 0. Before the change the changer device is not seen. Suggested-by: shane.seymour Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 07512463b9901..3f1c2a88b2043 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1187,17 +1187,19 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno, /* This is a non-zero lun of a multi-lun device. * Search through our list and find the device which - * has the same 8 byte LUN address, excepting byte 4. + * has the same 8 byte LUN address, excepting byte 4 and 5. * Assign the same bus and target for this new LUN. * Use the logical unit number from the firmware. */ memcpy(addr1, device->scsi3addr, 8); addr1[4] = 0; + addr1[5] = 0; for (i = 0; i < n; i++) { sd = h->dev[i]; memcpy(addr2, sd->scsi3addr, 8); addr2[4] = 0; - /* differ only in byte 4? */ + addr2[5] = 0; + /* differ only in byte 4 and 5? */ if (memcmp(addr1, addr2, 8) == 0) { device->bus = sd->bus; device->target = sd->target; -- GitLab From 2d041306b669e281427de7dd398e74335c9f5042 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Sat, 18 Jul 2015 11:13:15 -0500 Subject: [PATCH 5060/7006] hpsa: fix rmmod issues The driver is calling hpsa_shutdown before calling scsi_remove_host. hpsa_shutdown is disabling interrupts. scsi_remove_host can trigger I/O operations, such as SYNCHRONIZE CACHE when multipath is enabled which hang the system. Call scsi_remove_host before calling hpsa_shutdown. Reviewed-by: Kevin Barnett Reviewed-by: Scott Teel Reviewed-by: Tomas Henzl Signed-off-by: Don Brace Signed-off-by: James Bottomley --- drivers/scsi/hpsa.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 3f1c2a88b2043..40669f8dd0df1 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -8272,6 +8272,14 @@ static void hpsa_remove_one(struct pci_dev *pdev) destroy_workqueue(h->rescan_ctlr_wq); destroy_workqueue(h->resubmit_wq); + /* + * Call before disabling interrupts. + * scsi_remove_host can trigger I/O operations especially + * when multipath is enabled. There can be SYNCHRONIZE CACHE + * operations which cannot complete and will hang the system. + */ + if (h->scsi_host) + scsi_remove_host(h->scsi_host); /* init_one 8 */ /* includes hpsa_free_irqs - init_one 4 */ /* includes hpsa_disable_interrupt_mode - pci_init 2 */ hpsa_shutdown(pdev); @@ -8280,8 +8288,6 @@ static void hpsa_remove_one(struct pci_dev *pdev) kfree(h->hba_inquiry_data); /* init_one 10 */ h->hba_inquiry_data = NULL; /* init_one 10 */ - if (h->scsi_host) - scsi_remove_host(h->scsi_host); /* init_one 8 */ hpsa_free_ioaccel2_sg_chain_blocks(h); hpsa_free_performant_mode(h); /* init_one 7 */ hpsa_free_sg_chain_blocks(h); /* init_one 6 */ -- GitLab From 5155ce5f8395730f681fe48cdc8867838e3a3f2c Mon Sep 17 00:00:00 2001 From: Dilip Kumar Uppugandla Date: Tue, 21 Jul 2015 15:07:55 -0700 Subject: [PATCH 5061/7006] qla2xxx: Return the fabric command state for non-task management requests Invoking get_cmd_state for qla2xxx always returns 0. Instead change it to return the actual fabric state from qla_tgt_cmd. This will help with debugging. Signed-off-by: Dilip Kumar Uppugandla Signed-off-by: Spencer Baugh Acked-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index d9a8c60843467..e8595867bb8d2 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -420,6 +420,12 @@ static void tcm_qla2xxx_set_default_node_attrs(struct se_node_acl *nacl) static int tcm_qla2xxx_get_cmd_state(struct se_cmd *se_cmd) { + if (!(se_cmd->se_cmd_flags & SCF_SCSI_TMR_CDB)) { + struct qla_tgt_cmd *cmd = container_of(se_cmd, + struct qla_tgt_cmd, se_cmd); + return cmd->state; + } + return 0; } -- GitLab From b103918a5f21a51d12018a09919617687e584384 Mon Sep 17 00:00:00 2001 From: Sebastian Herbszt Date: Wed, 22 Jul 2015 10:53:22 +0200 Subject: [PATCH 5062/7006] lpfc: Use && instead of & for boolean expression Use logical instead of bitwise AND. Signed-off-by: Sebastian Herbszt Reviewed-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index ce96d5bf8ae7d..759cbebed7c73 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -701,7 +701,7 @@ lpfc_work_done(struct lpfc_hba *phba) HA_RXMASK)); } } - if ((phba->sli_rev == LPFC_SLI_REV4) & + if ((phba->sli_rev == LPFC_SLI_REV4) && (!list_empty(&pring->txq))) lpfc_drain_txq(phba); /* -- GitLab From d32477e2a72cf9b99bb174e0f11e1b1c7834b76f Mon Sep 17 00:00:00 2001 From: Jack Wang Date: Wed, 29 Jul 2015 12:02:50 +0200 Subject: [PATCH 5063/7006] MAINTAINERS: update email for pm8001 Company has policy to use company email address, so update my email address to company address. Signed-off-by: Jack Wang Signed-off-by: James Bottomley --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index fd60784430838..7a41c94d81dc1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8038,7 +8038,7 @@ S: Supported F: drivers/scsi/pmcraid.* PMC SIERRA PM8001 DRIVER -M: xjtuwjp@gmail.com +M: Jack Wang M: lindar_liu@usish.com L: pmchba@pmcs.com L: linux-scsi@vger.kernel.org -- GitLab From b093d590367f6eafbec89243fabb12d4b96a9997 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:25 +0530 Subject: [PATCH 5064/7006] pm80xx: Updated link rate Updated 12G linkrate to libsas. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_defs.h | 1 + drivers/scsi/pm8001/pm8001_hwi.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_defs.h b/drivers/scsi/pm8001/pm8001_defs.h index dc4233be52c81..f14ec6e042b9a 100644 --- a/drivers/scsi/pm8001/pm8001_defs.h +++ b/drivers/scsi/pm8001/pm8001_defs.h @@ -57,6 +57,7 @@ enum phy_speed { PHY_SPEED_15 = 0x01, PHY_SPEED_30 = 0x02, PHY_SPEED_60 = 0x04, + PHY_SPEED_120 = 0x08, }; enum data_direction { diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 96dcc097a4632..39306b1e704c5 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -3263,6 +3263,10 @@ void pm8001_get_lrate_mode(struct pm8001_phy *phy, u8 link_rate) struct sas_phy *sas_phy = phy->sas_phy.phy; switch (link_rate) { + case PHY_SPEED_120: + phy->sas_phy.linkrate = SAS_LINK_RATE_12_0_GBPS; + phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_12_0_GBPS; + break; case PHY_SPEED_60: phy->sas_phy.linkrate = SAS_LINK_RATE_6_0_GBPS; phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; -- GitLab From 3a1ae967741c301a5ad26665dcfb184082b969b2 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:26 +0530 Subject: [PATCH 5065/7006] pm80xx: Corrected device state changes in I_T_Nexus_Reset. In Nexus reset the device state request are not needed. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Acked-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_sas.c | 18 +++++++++++++----- drivers/scsi/pm8001/pm8001_sas.h | 8 ++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index b93f289b42b36..48f4627e05a4b 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -975,19 +975,27 @@ int pm8001_I_T_nexus_reset(struct domain_device *dev) phy = sas_get_local_phy(dev); if (dev_is_sata(dev)) { - DECLARE_COMPLETION_ONSTACK(completion_setstate); if (scsi_is_sas_phy_local(phy)) { rc = 0; goto out; } rc = sas_phy_reset(phy, 1); + if (rc) { + PM8001_EH_DBG(pm8001_ha, + pm8001_printk("phy reset failed for device %x\n" + "with rc %d\n", pm8001_dev->device_id, rc)); + rc = TMF_RESP_FUNC_FAILED; + goto out; + } msleep(2000); rc = pm8001_exec_internal_task_abort(pm8001_ha, pm8001_dev , dev, 1, 0); - pm8001_dev->setds_completion = &completion_setstate; - rc = PM8001_CHIP_DISP->set_dev_state_req(pm8001_ha, - pm8001_dev, 0x01); - wait_for_completion(&completion_setstate); + if (rc) { + PM8001_EH_DBG(pm8001_ha, + pm8001_printk("task abort failed %x\n" + "with rc %d\n", pm8001_dev->device_id, rc)); + rc = TMF_RESP_FUNC_FAILED; + } } else { rc = sas_phy_reset(phy, 1); msleep(2000); diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 8dd8b7840f042..c9736cc17520f 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -569,6 +569,14 @@ struct pm8001_fw_image_header { #define NCQ_READ_LOG_FLAG 0x80000000 #define NCQ_ABORT_ALL_FLAG 0x40000000 #define NCQ_2ND_RLE_FLAG 0x20000000 + +/* Device states */ +#define DS_OPERATIONAL 0x01 +#define DS_PORT_IN_RESET 0x02 +#define DS_IN_RECOVERY 0x03 +#define DS_IN_ERROR 0x04 +#define DS_NON_OPERATIONAL 0x07 + /** * brief param structure for firmware flash update. */ -- GitLab From 842784e0d15bc21b31ce69f8f3518a8cf86084e3 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:27 +0530 Subject: [PATCH 5066/7006] pm80xx: Update For Thermal Page Code Thermal page code has been changed to 7 for the 12G controllers. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm80xx_hwi.c | 9 ++++++++- drivers/scsi/pm8001/pm80xx_hwi.h | 3 ++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 05cce463ab01c..dced9f7755e72 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -843,6 +843,7 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) int rc; u32 tag; u32 opc = OPC_INB_SET_CONTROLLER_CONFIG; + u32 page_code; memset(&payload, 0, sizeof(struct set_ctrl_cfg_req)); rc = pm8001_tag_alloc(pm8001_ha, &tag); @@ -851,8 +852,14 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) circularQ = &pm8001_ha->inbnd_q_tbl[0]; payload.tag = cpu_to_le32(tag); + + if (IS_SPCV_12G(pm8001_ha->pdev)) + page_code = THERMAL_PAGE_CODE_7H; + else + page_code = THERMAL_PAGE_CODE_8H; + payload.cfg_pg[0] = (THERMAL_LOG_ENABLE << 9) | - (THERMAL_ENABLE << 8) | THERMAL_OP_CODE; + (THERMAL_ENABLE << 8) | page_code; payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index 9970a385795d1..a083cc68d9377 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -177,7 +177,8 @@ /* Thermal related */ #define THERMAL_ENABLE 0x1 #define THERMAL_LOG_ENABLE 0x1 -#define THERMAL_OP_CODE 0x6 +#define THERMAL_PAGE_CODE_7H 0x6 +#define THERMAL_PAGE_CODE_8H 0x7 #define LTEMPHIL 70 #define RTEMPHIL 100 -- GitLab From 3b700e341144f278b8248418991c086d09b7137b Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:28 +0530 Subject: [PATCH 5067/7006] pm80xx: Fix for Incorrect DMA Unmapping of SG List In pm8001_ccb_task_free(), the dma unmapping is done based on ccb->n_elem value. This should be initialized to zero in the task_abort(). Otherwise, pm8001_ccb_task_free() will try for dma_unmap_sg() which is invalid for task abort and can lead to kernel crash. Changes From V1: None Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_sas.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 48f4627e05a4b..949198c01ced6 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -790,6 +790,7 @@ pm8001_exec_internal_task_abort(struct pm8001_hba_info *pm8001_ha, ccb->device = pm8001_dev; ccb->ccb_tag = ccb_tag; ccb->task = task; + ccb->n_elem = 0; res = PM8001_CHIP_DISP->task_abort(pm8001_ha, pm8001_dev, flag, task_tag, ccb_tag); -- GitLab From 3b77894b2c32ed3326c47b550f30684beb64abd3 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:29 +0530 Subject: [PATCH 5068/7006] pm80xx: Remove unnecessary phy disconnect while link error If the link error happens, we don't need to disconnect the phy, which will remove the drive. Instead acknowledging the controller and logging the error will be enough. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm80xx_hwi.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index dced9f7755e72..3d8b4ae06ae63 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3176,9 +3176,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("HW_EVENT_LINK_ERR_INVALID_DWORD\n")); pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_INVALID_DWORD, port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_DISPARITY_ERROR: PM8001_MSG_DBG(pm8001_ha, @@ -3186,9 +3183,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_DISPARITY_ERROR, port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_CODE_VIOLATION: PM8001_MSG_DBG(pm8001_ha, @@ -3196,9 +3190,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_CODE_VIOLATION, port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH: PM8001_MSG_DBG(pm8001_ha, pm8001_printk( @@ -3206,9 +3197,6 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_LINK_ERR_LOSS_OF_DWORD_SYNCH, port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); break; case HW_EVENT_MALFUNCTION: PM8001_MSG_DBG(pm8001_ha, -- GitLab From 8414cd8057c29f60cda241aa489b33e4db6652f2 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:30 +0530 Subject: [PATCH 5069/7006] pm80xx: Add PORT RECOVERY TIMEOUT support PORT RECOVERY TIMEOUT is the maximum time between the controller's detection of the PHY down until the receipt of the ID_Frame (from the same remote SAS port). If the time expires before the ID_FRAME is received, the port is considered INVALID and can be removed. The IOP_EVENT_PORT_RECOVERY_TIMER_TMO event is reported following the IOP_EVENT_ PHY_DOWN event when the PHY/port does not recover after Port Recovery Time. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_sas.h | 2 +- drivers/scsi/pm8001/pm80xx_hwi.c | 83 ++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index c9736cc17520f..27880261aafd1 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -241,7 +241,7 @@ struct pm8001_chip_info { struct pm8001_port { struct asd_sas_port sas_port; u8 port_attached; - u8 wide_port_phymap; + u16 wide_port_phymap; u8 port_state; struct list_head list; }; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 3d8b4ae06ae63..8817ce6ad4b8f 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -309,6 +309,9 @@ static void read_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_mr32(address, MAIN_INT_VECTOR_TABLE_OFFSET); pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset = pm8001_mr32(address, MAIN_SAS_PHY_ATTR_TABLE_OFFSET); + /* read port recover and reset timeout */ + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer = + pm8001_mr32(address, MAIN_PORT_RECOVERY_TIMER); } /** @@ -585,6 +588,12 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); pm8001_mw32(address, MAIN_INT_REASSERTION_DELAY, pm8001_ha->main_cfg_tbl.pm80xx_tbl.interrupt_reassertion_delay); + + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer &= 0xffff0000; + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer |= + PORT_RECOVERY_TIMEOUT; + pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); } /** @@ -2836,6 +2845,32 @@ static void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, u32 phyId, u32 phy_op); +static void hw_event_port_recover(struct pm8001_hba_info *pm8001_ha, + void *piomb) +{ + struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4); + u32 phyid_npip_portstate = le32_to_cpu(pPayload->phyid_npip_portstate); + u8 phy_id = (u8)((phyid_npip_portstate & 0xFF0000) >> 16); + u32 lr_status_evt_portid = + le32_to_cpu(pPayload->lr_status_evt_portid); + u8 deviceType = pPayload->sas_identify.dev_type; + u8 link_rate = (u8)((lr_status_evt_portid & 0xF0000000) >> 28); + struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; + u8 port_id = (u8)(lr_status_evt_portid & 0x000000FF); + struct pm8001_port *port = &pm8001_ha->port[port_id]; + + if (deviceType == SAS_END_DEVICE) { + pm80xx_chip_phy_ctl_req(pm8001_ha, phy_id, + PHY_NOTIFY_ENABLE_SPINUP); + } + + port->wide_port_phymap |= (1U << phy_id); + pm8001_get_lrate_mode(phy, link_rate); + phy->sas_phy.oob_mode = SAS_OOB_MODE; + phy->phy_state = PHY_STATE_LINK_UP_SPCV; + phy->phy_attached = 1; +} + /** * hw_event_sas_phy_up -FW tells me a SAS phy up event. * @pm8001_ha: our hba card information @@ -2863,6 +2898,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) unsigned long flags; u8 deviceType = pPayload->sas_identify.dev_type; port->port_state = portstate; + port->wide_port_phymap |= (1U << phy_id); phy->phy_state = PHY_STATE_LINK_UP_SPCV; PM8001_MSG_DBG(pm8001_ha, pm8001_printk( "portid:%d; phyid:%d; linkrate:%d; " @@ -2988,7 +3024,6 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_port *port = &pm8001_ha->port[port_id]; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; port->port_state = portstate; - phy->phy_type = 0; phy->identify.device_type = 0; phy->phy_attached = 0; memset(&phy->dev_sas_addr, 0, SAS_ADDR_SIZE); @@ -3000,9 +3035,13 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk(" PortInvalid portID %d\n", port_id)); PM8001_MSG_DBG(pm8001_ha, pm8001_printk(" Last phy Down and port invalid\n")); - port->port_attached = 0; - pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, - port_id, phy_id, 0, 0); + if (phy->phy_type & PORT_TYPE_SATA) { + phy->phy_type = 0; + port->port_attached = 0; + pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, + port_id, phy_id, 0, 0); + } + sas_phy_disconnected(&phy->sas_phy); break; case PORT_IN_RESET: PM8001_MSG_DBG(pm8001_ha, @@ -3010,22 +3049,26 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) break; case PORT_NOT_ESTABLISHED: PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_NOT_ESTABLISHED\n")); + pm8001_printk(" Phy Down and PORT_NOT_ESTABLISHED\n")); port->port_attached = 0; break; case PORT_LOSTCOMM: PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and PORT_LOSTCOMM\n")); + pm8001_printk(" Phy Down and PORT_LOSTCOMM\n")); PM8001_MSG_DBG(pm8001_ha, pm8001_printk(" Last phy Down and port invalid\n")); - port->port_attached = 0; - pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, - port_id, phy_id, 0, 0); + if (phy->phy_type & PORT_TYPE_SATA) { + port->port_attached = 0; + phy->phy_type = 0; + pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PHY_DOWN, + port_id, phy_id, 0, 0); + } + sas_phy_disconnected(&phy->sas_phy); break; default: port->port_attached = 0; PM8001_MSG_DBG(pm8001_ha, - pm8001_printk(" phy Down and(default) = 0x%x\n", + pm8001_printk(" Phy Down and(default) = 0x%x\n", portstate)); break; @@ -3091,7 +3134,7 @@ static int mpi_thermal_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) */ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) { - unsigned long flags; + unsigned long flags, i; struct hw_event_resp *pPayload = (struct hw_event_resp *)(piomb + 4); u32 lr_status_evt_portid = @@ -3104,9 +3147,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) (u16)((lr_status_evt_portid & 0x00FFFF00) >> 8); u8 status = (u8)((lr_status_evt_portid & 0x0F000000) >> 24); - struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; + struct pm8001_port *port = &pm8001_ha->port[port_id]; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; PM8001_MSG_DBG(pm8001_ha, pm8001_printk("portid:%d phyid:%d event:0x%x status:0x%x\n", @@ -3132,7 +3175,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) case HW_EVENT_PHY_DOWN: PM8001_MSG_DBG(pm8001_ha, pm8001_printk("HW_EVENT_PHY_DOWN\n")); - sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); + if (phy->phy_type & PORT_TYPE_SATA) + sas_ha->notify_phy_event(&phy->sas_phy, + PHYE_LOSS_OF_SIGNAL); phy->phy_attached = 0; phy->phy_state = 0; hw_event_phy_down(pm8001_ha, piomb); @@ -3252,13 +3297,19 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm80xx_hw_event_ack_req(pm8001_ha, 0, HW_EVENT_PORT_RECOVERY_TIMER_TMO, port_id, phy_id, 0, 0); - sas_phy_disconnected(sas_phy); - phy->phy_attached = 0; - sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); + for (i = 0; i < pm8001_ha->chip->n_phy; i++) { + if (port->wide_port_phymap & (1 << i)) { + phy = &pm8001_ha->phy[i]; + sas_ha->notify_phy_event(&phy->sas_phy, + PHYE_LOSS_OF_SIGNAL); + port->wide_port_phymap &= ~(1 << i); + } + } break; case HW_EVENT_PORT_RECOVER: PM8001_MSG_DBG(pm8001_ha, pm8001_printk("HW_EVENT_PORT_RECOVER\n")); + hw_event_port_recover(pm8001_ha, piomb); break; case HW_EVENT_PORT_RESET_COMPLETE: PM8001_MSG_DBG(pm8001_ha, -- GitLab From 27ecfa5e79bfc2e4efca67a6077080acab546a4a Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:31 +0530 Subject: [PATCH 5070/7006] pm80xx: Handling Invalid SSP Response frame The request has to be retried incase if the length of the SSP Response IU is invalid. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm80xx_hwi.c | 7 +++++++ drivers/scsi/pm8001/pm80xx_hwi.h | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 8817ce6ad4b8f..0e1628f2018e5 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1609,6 +1609,13 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; + case IO_XFER_ERROR_INVALID_SSP_RSP_FRAME: + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("IO_XFER_ERROR_INVALID_SSP_RSP_FRAME\n")); + ts->resp = SAS_TASK_COMPLETE; + ts->stat = SAS_OPEN_REJECT; + ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + break; case IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED: PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_OPEN_CNX_ERROR_PROTOCOL_NOT_SUPPORTED\n")); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index a083cc68d9377..7a443bad61634 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -1175,7 +1175,7 @@ typedef struct SASProtocolTimerConfig SASProtocolTimerConfig_t; #define IO_XFER_ERROR_INTERNAL_CRC_ERROR 0x54 #define MPI_IO_RQE_BUSY_FULL 0x55 #define IO_XFER_ERR_EOB_DATA_OVERRUN 0x56 -#define IO_XFR_ERROR_INVALID_SSP_RSP_FRAME 0x57 +#define IO_XFER_ERROR_INVALID_SSP_RSP_FRAME 0x57 #define IO_OPEN_CNX_ERROR_OPEN_PREEMPTED 0x58 #define MPI_ERR_IO_RESOURCE_UNAVAILABLE 0x1004 -- GitLab From 1cd129918f14f42f8b1940096dba629ce7e7a243 Mon Sep 17 00:00:00 2001 From: Viswas G Date: Tue, 11 Aug 2015 15:06:32 +0530 Subject: [PATCH 5071/7006] pm80xx: Bump pm80xx driver version to 0.1.38 Bump pm80xx driver version to 0.1.38. Signed-off-by: Viswas G Reviewed-by: Suresh Thiagarajan Reviewed-by: Hannes Reinecke Reviewed-by: Jack Wang Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_sas.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 27880261aafd1..e2e97db38ae8c 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -58,7 +58,7 @@ #include "pm8001_defs.h" #define DRV_NAME "pm80xx" -#define DRV_VERSION "0.1.37" +#define DRV_VERSION "0.1.38" #define PM8001_FAIL_LOGGING 0x01 /* Error message logging */ #define PM8001_INIT_LOGGING 0x02 /* driver init logging */ #define PM8001_DISC_LOGGING 0x04 /* discovery layer logging */ -- GitLab From 709c75b5a2411c31e5a649a2cd6d4866dd11f456 Mon Sep 17 00:00:00 2001 From: "jiang.biao2@zte.com.cn" Date: Fri, 31 Jul 2015 17:52:10 +0800 Subject: [PATCH 5072/7006] scsi_error: should not get sense for timeout IO in scsi error handler scsi_error: should not get sense for timeout IO in scsi error handler When an IO timeout occurs, the IO will be aborted in scsi_abort_command() and SCSI_EH_ABORT_SCHEDULED will be set. Because of that, the SCSI_EH_CANCEL_CMD will be clear in scsi_eh_scmd_add(). So when scsi error handler starts, it will get sense for this timeout IO and the scmd of the IO request will be reused. In that case, the scmd may be double released when racing with io_done(), which will result in crash. SO SCSI_EH_ABORT_SCHEDULED should also be checked when getting sense. The bug maybe reproduced when the link between host and disk is unstable. Signed-off-by: Jiang Biao Signed-off-by: Long Chun Reviewed-by: Tan Hu Reviewed-by: Chen Donghai Reviewed-by: Cai Qu Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index d7d28061b31d8..3aacd96d63f3f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1160,8 +1160,13 @@ int scsi_eh_get_sense(struct list_head *work_q, struct Scsi_Host *shost; int rtn; + /* + * If SCSI_EH_ABORT_SCHEDULED has been set, it is timeout IO, + * should not get sense. + */ list_for_each_entry_safe(scmd, next, work_q, eh_entry) { if ((scmd->eh_eflags & SCSI_EH_CANCEL_CMD) || + (scmd->eh_eflags & SCSI_EH_ABORT_SCHEDULED) || SCSI_SENSE_VALID(scmd)) continue; -- GitLab From f299c7c2ab5df78e3201af34e596e8a3ba4d2791 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 4 Aug 2015 13:37:51 -0400 Subject: [PATCH 5073/7006] qla2xxx: Add serdes register read/write support for ISP25xx. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_mbx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 26ca18c3fa6a3..6e22052afc89b 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2847,7 +2847,8 @@ qla2x00_write_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t data) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (!IS_QLA2031(vha->hw) && !IS_QLA27XX(vha->hw)) + if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) && + !IS_QLA27XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1182, @@ -2885,7 +2886,8 @@ qla2x00_read_serdes_word(scsi_qla_host_t *vha, uint16_t addr, uint16_t *data) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; - if (!IS_QLA2031(vha->hw) && !IS_QLA27XX(vha->hw)) + if (!IS_QLA25XX(vha->hw) && !IS_QLA2031(vha->hw) && + !IS_QLA27XX(vha->hw)) return QLA_FUNCTION_FAILED; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1185, -- GitLab From 1dd34b5ad8aebaff17b625fc0126e18243008a3f Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Wed, 26 Aug 2015 15:57:38 -0700 Subject: [PATCH 5074/7006] bpf: fix bpf_skb_set_tunnel_key() helper Make sure to indicate to tunnel driver that key.tun_id is set, otherwise gre won't recognize the metadata. Fixes: d3aa45ce6b94 ("bpf: add helpers to access tunnel metadata") Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- net/core/filter.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/core/filter.c b/net/core/filter.c index b4adc961413ff..66500d4909951 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1528,6 +1528,7 @@ static u64 bpf_skb_set_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5) info = &md->u.tun_info; info->mode = IP_TUNNEL_INFO_TX; + info->key.tun_flags = TUNNEL_KEY; info->key.tun_id = cpu_to_be64(from->tunnel_id); info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4); -- GitLab From 17cac3a175a02cd1ae21f9183b09f30a719832df Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 4 Aug 2015 13:37:52 -0400 Subject: [PATCH 5075/7006] qla2xxx: Handle AEN8014 incoming port logout. When we get logged out, mark the port lost and set dpc flag for relogin. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 35 +++++++++++++++++++++++++++++++--- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 583d52aae79d2..05d8cf0165433 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -26,7 +26,7 @@ * | | | 0x3036,0x3038 | * | | | 0x303a | * | DPC Thread | 0x4023 | 0x4002,0x4013 | - * | Async Events | 0x5087 | 0x502b-0x502f | + * | Async Events | 0x508a | 0x502b-0x502f | * | | | 0x5047 | * | | | 0x5084,0x5075 | * | | | 0x503d,0x5044 | diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 2cb0fba38c9e8..b2b93dfbffd36 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -560,6 +560,17 @@ qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry) return ret; } +static inline fc_port_t * +qla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id) +{ + fc_port_t *fcport; + + list_for_each_entry(fcport, &vha->vp_fcports, list) + if (fcport->loop_id == loop_id) + return fcport; + return NULL; +} + /** * qla2x00_async_event() - Process aynchronous events. * @ha: SCSI driver HA context @@ -897,11 +908,29 @@ skip_rio: (mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff)) break; - /* Global event -- port logout or port unavailable. */ - if (mb[1] == 0xffff && mb[2] == 0x7) { + if (mb[2] == 0x7) { ql_dbg(ql_dbg_async, vha, 0x5010, - "Port unavailable %04x %04x %04x.\n", + "Port %s %04x %04x %04x.\n", + mb[1] == 0xffff ? "unavailable" : "logout", mb[1], mb[2], mb[3]); + + if (mb[1] == 0xffff) + goto global_port_update; + + /* Port logout */ + fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]); + if (!fcport) + break; + if (atomic_read(&fcport->state) != FCS_ONLINE) + break; + ql_dbg(ql_dbg_async, vha, 0x508a, + "Marking port lost loopid=%04x portid=%06x.\n", + fcport->loop_id, fcport->d_id.b24); + qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1); + break; + +global_port_update: + /* Port unavailable. */ ql_log(ql_log_warn, vha, 0x505e, "Link is offline.\n"); -- GitLab From cc790764391a68511cf6a7e4dd18eeb6e7640233 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 4 Aug 2015 13:37:53 -0400 Subject: [PATCH 5076/7006] qla2xxx: Use ssdid to gate semaphore manipulation. Execute qla25xx_manipulate_risc_semaphore() only for ssdid 0x0175 and 0x0240. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5a5ca43e5e905..f64bb6b7a08f4 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1272,14 +1272,14 @@ qla25xx_write_risc_sema_reg(scsi_qla_host_t *vha, uint32_t data) static void qla25xx_manipulate_risc_semaphore(scsi_qla_host_t *vha) { - struct qla_hw_data *ha = vha->hw; uint32_t wd32 = 0; uint delta_msec = 100; uint elapsed_msec = 0; uint timeout_msec; ulong n; - if (!IS_QLA25XX(ha) && !IS_QLA2031(ha)) + if (vha->hw->pdev->subsystem_device != 0x0175 && + vha->hw->pdev->subsystem_device != 0x0240) return; attempt: -- GitLab From 8dd7e3a55949f17fecba4aedb2cb943b153e5e55 Mon Sep 17 00:00:00 2001 From: Joe Carnuccio Date: Tue, 4 Aug 2015 13:37:54 -0400 Subject: [PATCH 5077/7006] qla2xxx: Pause risc before manipulating risc semaphore. Signed-off-by: Joe Carnuccio Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index f64bb6b7a08f4..014f44f7a7c44 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1282,6 +1282,9 @@ qla25xx_manipulate_risc_semaphore(scsi_qla_host_t *vha) vha->hw->pdev->subsystem_device != 0x0240) return; + WRT_REG_DWORD(&vha->hw->iobase->isp24.hccr, HCCRX_SET_RISC_PAUSE); + udelay(100); + attempt: timeout_msec = TIMEOUT_SEMAPHORE; n = timeout_msec / delta_msec; -- GitLab From d6b9b42b49518c30df9de92ce499f005d336e97b Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Tue, 4 Aug 2015 13:37:55 -0400 Subject: [PATCH 5078/7006] qla2xxx: Add adapter checks for FAWWN functionality. Signed-off-by: Saurav Kashyap Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_mbx.c | 30 ++++++++++++++++-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ac88c4e7cf130..cbcc6fc9f5622 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3164,6 +3164,7 @@ struct qla_hw_data { #define IS_TGT_MODE_CAPABLE(ha) (ha->tgt.atio_q_length) #define IS_SHADOW_REG_CAPABLE(ha) (IS_QLA27XX(ha)) #define IS_DPORT_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) +#define IS_FAWWN_CAPABLE(ha) (IS_QLA83XX(ha) || IS_QLA27XX(ha)) /* HBA serial number */ uint8_t serial0; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 6e22052afc89b..62a83e39f6ed7 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1135,20 +1135,22 @@ qla2x00_get_adapter_id(scsi_qla_host_t *vha, uint16_t *id, uint8_t *al_pa, vha->fcoe_vn_port_mac[0] = mcp->mb[13] & 0xff; } /* If FA-WWN supported */ - if (mcp->mb[7] & BIT_14) { - vha->port_name[0] = MSB(mcp->mb[16]); - vha->port_name[1] = LSB(mcp->mb[16]); - vha->port_name[2] = MSB(mcp->mb[17]); - vha->port_name[3] = LSB(mcp->mb[17]); - vha->port_name[4] = MSB(mcp->mb[18]); - vha->port_name[5] = LSB(mcp->mb[18]); - vha->port_name[6] = MSB(mcp->mb[19]); - vha->port_name[7] = LSB(mcp->mb[19]); - fc_host_port_name(vha->host) = - wwn_to_u64(vha->port_name); - ql_dbg(ql_dbg_mbx, vha, 0x10ca, - "FA-WWN acquired %016llx\n", - wwn_to_u64(vha->port_name)); + if (IS_FAWWN_CAPABLE(vha->hw)) { + if (mcp->mb[7] & BIT_14) { + vha->port_name[0] = MSB(mcp->mb[16]); + vha->port_name[1] = LSB(mcp->mb[16]); + vha->port_name[2] = MSB(mcp->mb[17]); + vha->port_name[3] = LSB(mcp->mb[17]); + vha->port_name[4] = MSB(mcp->mb[18]); + vha->port_name[5] = LSB(mcp->mb[18]); + vha->port_name[6] = MSB(mcp->mb[19]); + vha->port_name[7] = LSB(mcp->mb[19]); + fc_host_port_name(vha->host) = + wwn_to_u64(vha->port_name); + ql_dbg(ql_dbg_mbx, vha, 0x10ca, + "FA-WWN acquired %016llx\n", + wwn_to_u64(vha->port_name)); + } } } -- GitLab From 8fbdac8c70d378016f568106f09fb3ff153a47c3 Mon Sep 17 00:00:00 2001 From: Hiral Patel Date: Tue, 4 Aug 2015 13:37:56 -0400 Subject: [PATCH 5079/7006] qla2xxx: Do not crash system for sp ref count zero Aovid crashing the system in the scenario where firmware just completes the command and it can not find the command during abort mailbox processing. This scenario can lead to sp reference counter being zero. Instead of crashing the system, use WARN_ON to print warning in log file. Signed-off-by: Hiral Patel Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5a5166bd42879..8763c12cb6c27 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -656,7 +656,7 @@ qla2x00_sp_compl(void *data, void *ptr, int res) "SP reference-count to ZERO -- sp=%p cmd=%p.\n", sp, GET_CMD_SP(sp)); if (ql2xextended_error_logging & ql_dbg_io) - BUG(); + WARN_ON(atomic_read(&sp->ref_count) == 0); return; } if (!atomic_dec_and_test(&sp->ref_count)) -- GitLab From c7bc4cae0d5c9703d8b15fcc0fd53b86b135bde8 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 4 Aug 2015 13:37:57 -0400 Subject: [PATCH 5080/7006] qla2xxx: Do not reset adapter if SRB handle is in range. If an SRB is NULL but the handle is in range just drop the command instead of also resetting the adapter. If the handle is in range then the command was valid at some point and may have been aborted. Resetting the adapter can lead to extended recovery times in this case. Signed-off-by: Chad Dupuis Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 20 ++++++++++++-------- drivers/scsi/qla2xxx/qla_os.c | 4 ++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 05d8cf0165433..c6e51c6cd3dca 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -19,7 +19,7 @@ * | Device Discovery | 0x2016 | 0x2020-0x2022, | * | | | 0x2011-0x2012, | * | | | 0x2099-0x20a4 | - * | Queue Command and IO tracing | 0x3059 | 0x300b | + * | Queue Command and IO tracing | 0x3075 | 0x300b | * | | | 0x3027-0x3028 | * | | | 0x303d-0x3041 | * | | | 0x302d,0x3033 | diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index b2b93dfbffd36..08190e07c6405 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2073,14 +2073,18 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } /* Validate handle. */ - if (handle < req->num_outstanding_cmds) + if (handle < req->num_outstanding_cmds) { sp = req->outstanding_cmds[handle]; - else - sp = NULL; - - if (sp == NULL) { + if (!sp) { + ql_dbg(ql_dbg_io, vha, 0x3075, + "%s(%ld): Already returned command for status handle (0x%x).\n", + __func__, vha->host_no, sts->handle); + return; + } + } else { ql_dbg(ql_dbg_io, vha, 0x3017, - "Invalid status handle (0x%x).\n", sts->handle); + "Invalid status handle, out of range (0x%x).\n", + sts->handle); if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { if (IS_P3P_TYPE(ha)) @@ -2367,12 +2371,12 @@ out: ql_dbg(ql_dbg_io, fcport->vha, 0x3022, "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu " "portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x " - "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n", + "rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n", comp_status, scsi_status, res, vha->host_no, cp->device->id, cp->device->lun, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len, - resid_len, fw_resid_len); + resid_len, fw_resid_len, sp, cp); if (rsp->status_srb == NULL) sp->done(ha, sp, res); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 8763c12cb6c27..f70809feca90a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -958,8 +958,8 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } ql_dbg(ql_dbg_taskm, vha, 0x8002, - "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p\n", - vha->host_no, id, lun, sp, cmd); + "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n", + vha->host_no, id, lun, sp, cmd, sp->handle); /* Get a reference to the sp and drop the lock.*/ sp_get(sp); -- GitLab From fd49a540ead94ce5769f6eb2028e97577739e24b Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 4 Aug 2015 13:37:58 -0400 Subject: [PATCH 5081/7006] qla2xxx: Do not reset ISP for error entry with an out of range handle. Instead of resetting the adapter wait for the login to timeout and retry. Resetting the adapter can cause extended path recovery times. Signed-off-by: Chad Dupuis Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_isr.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 08190e07c6405..ccf6a7f990240 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2473,13 +2473,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) } fatal: ql_log(ql_log_warn, vha, 0x5030, - "Error entry - invalid handle/queue.\n"); - - if (IS_P3P_TYPE(ha)) - set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags); - else - set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); + "Error entry - invalid handle/queue (%04x).\n", que); } /** -- GitLab From 03aa868c1b7b2633a4faa97b28c40e64c91a8e7f Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Tue, 4 Aug 2015 13:37:59 -0400 Subject: [PATCH 5082/7006] qla2xxx: Add support to show MPI and PEP FW version for ISP27xx. Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 19 ++++++++++++++++++- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_mbx.c | 13 ++++++++++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 2087b73927ce7..b352d234b70a3 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1345,7 +1345,8 @@ qla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr, scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); struct qla_hw_data *ha = vha->hw; - if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha)) + if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) && + !IS_QLA27XX(ha)) return scnprintf(buf, PAGE_SIZE, "\n"); return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n", @@ -1534,6 +1535,20 @@ qla2x00_allow_cna_fw_dump_store(struct device *dev, return strlen(buf); } +static ssize_t +qla2x00_pep_version_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA27XX(ha)) + return scnprintf(buf, PAGE_SIZE, "\n"); + + return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n", + ha->pep_version[0], ha->pep_version[1], ha->pep_version[2]); +} + static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); @@ -1578,6 +1593,7 @@ static DEVICE_ATTR(fw_dump_size, S_IRUGO, qla2x00_fw_dump_size_show, NULL); static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR, qla2x00_allow_cna_fw_dump_show, qla2x00_allow_cna_fw_dump_store); +static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL); struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -1611,6 +1627,7 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_diag_megabytes, &dev_attr_fw_dump_size, &dev_attr_allow_cna_fw_dump, + &dev_attr_pep_version, NULL, }; diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cbcc6fc9f5622..e8073917e7a39 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3287,6 +3287,7 @@ struct qla_hw_data { uint8_t mpi_version[3]; uint32_t mpi_capabilities; uint8_t phy_version[3]; + uint8_t pep_version[3]; /* Firmware dump template */ void *fw_dump_template; diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 62a83e39f6ed7..97b5bd569d036 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -555,7 +555,9 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) if (IS_FWI2_CAPABLE(ha)) mcp->in_mb |= MBX_17|MBX_16|MBX_15; if (IS_QLA27XX(ha)) - mcp->in_mb |= MBX_21|MBX_20|MBX_19|MBX_18; + mcp->in_mb |= MBX_23 | MBX_22 | MBX_21 | MBX_20 | MBX_19 | + MBX_18 | MBX_14 | MBX_13 | MBX_11 | MBX_10 | MBX_9 | MBX_8; + mcp->flags = 0; mcp->tov = MBX_TOV_SECONDS; rval = qla2x00_mailbox_command(vha, mcp); @@ -571,6 +573,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->fw_memory_size = 0x1FFFF; /* Defaults to 128KB. */ else ha->fw_memory_size = (mcp->mb[5] << 16) | mcp->mb[4]; + if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) || IS_QLA8044(ha)) { ha->mpi_version[0] = mcp->mb[10] & 0xff; ha->mpi_version[1] = mcp->mb[11] >> 8; @@ -580,6 +583,7 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) ha->phy_version[1] = mcp->mb[9] >> 8; ha->phy_version[2] = mcp->mb[9] & 0xff; } + if (IS_FWI2_CAPABLE(ha)) { ha->fw_attributes_h = mcp->mb[15]; ha->fw_attributes_ext[0] = mcp->mb[16]; @@ -591,7 +595,14 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) "%s: Ext_FwAttributes Upper: 0x%x, Lower: 0x%x.\n", __func__, mcp->mb[17], mcp->mb[16]); } + if (IS_QLA27XX(ha)) { + ha->mpi_version[0] = mcp->mb[10] & 0xff; + ha->mpi_version[1] = mcp->mb[11] >> 8; + ha->mpi_version[2] = mcp->mb[11] & 0xff; + ha->pep_version[0] = mcp->mb[13] & 0xff; + ha->pep_version[1] = mcp->mb[14] >> 8; + ha->pep_version[2] = mcp->mb[14] & 0xff; ha->fw_shared_ram_start = (mcp->mb[19] << 16) | mcp->mb[18]; ha->fw_shared_ram_end = (mcp->mb[21] << 16) | mcp->mb[20]; } -- GitLab From 96219424f2c7b767e42ccf203df40d7df677a5e3 Mon Sep 17 00:00:00 2001 From: Chad Dupuis Date: Tue, 4 Aug 2015 13:38:00 -0400 Subject: [PATCH 5083/7006] qla2xxx: Remove decrement of sp reference count in abort handler. Fix for memory leak when command is not found by firmware due to mismatch in sp reference count. Signed-off-by: Chad Dupuis Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f70809feca90a..95bee6807f46e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -967,14 +967,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) spin_unlock_irqrestore(&ha->hardware_lock, flags); rval = ha->isp_ops->abort_command(sp); if (rval) { - if (rval == QLA_FUNCTION_PARAMETER_ERROR) { - /* - * Decrement the ref_count since we can't find the - * command - */ - atomic_dec(&sp->ref_count); + if (rval == QLA_FUNCTION_PARAMETER_ERROR) ret = SUCCESS; - } else + else ret = FAILED; ql_dbg(ql_dbg_taskm, vha, 0x8003, -- GitLab From 63e322aaa6a00536055558ac1307b2919ee57aef Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 4 Aug 2015 13:38:01 -0400 Subject: [PATCH 5084/7006] qla2xxx: do not clear slot in outstanding cmd array Signed-off-by: Himanshu Madhani Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 95bee6807f46e..0b90fac255d3b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -981,12 +981,6 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) } spin_lock_irqsave(&ha->hardware_lock, flags); - /* - * Clear the slot in the oustanding_cmds array if we can't find the - * command to reclaim the resources. - */ - if (rval == QLA_FUNCTION_PARAMETER_ERROR) - vha->req->outstanding_cmds[sp->handle] = NULL; sp->done(ha, sp, 0); spin_unlock_irqrestore(&ha->hardware_lock, flags); -- GitLab From a1d0285ecb61800a9e6808f716b880eae95f14bc Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 4 Aug 2015 13:38:02 -0400 Subject: [PATCH 5085/7006] qla2xxx: Fix missing device login retries. On certain conditions, login failures will just invoke qla2x00_mark_device_lost() with the intend to do login again; but if login_retry has been set already, that would fail to set the relogin needed flag which is required to wakeup the DPC to retry. Signed-off-by: Arun Easi Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0b90fac255d3b..0d0ff33d010f2 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3258,9 +3258,10 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, if (!do_login) return; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + if (fcport->login_retry == 0) { fcport->login_retry = vha->hw->login_retry_count; - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); ql_dbg(ql_dbg_disc, vha, 0x2067, "Port login retry %8phN, id = 0x%04x retry cnt=%d.\n", -- GitLab From 2b48992f656e109b9d7357cedc0406b50ec82c22 Mon Sep 17 00:00:00 2001 From: Sawan Chandak Date: Tue, 4 Aug 2015 13:38:03 -0400 Subject: [PATCH 5086/7006] qla2xxx: Add pci device id 0x2261. Signed-off-by: Sawan Chandak Signed-off-by: Himanshu Madhani Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 7 +++++-- drivers/scsi/qla2xxx/qla_os.c | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index e8073917e7a39..a72b29f4dd79d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -3059,6 +3059,7 @@ struct qla_hw_data { #define PCI_DEVICE_ID_QLOGIC_ISP2031 0x2031 #define PCI_DEVICE_ID_QLOGIC_ISP2071 0x2071 #define PCI_DEVICE_ID_QLOGIC_ISP2271 0x2271 +#define PCI_DEVICE_ID_QLOGIC_ISP2261 0x2261 uint32_t device_type; #define DT_ISP2100 BIT_0 @@ -3082,7 +3083,8 @@ struct qla_hw_data { #define DT_ISP8044 BIT_18 #define DT_ISP2071 BIT_19 #define DT_ISP2271 BIT_20 -#define DT_ISP_LAST (DT_ISP2271 << 1) +#define DT_ISP2261 BIT_21 +#define DT_ISP_LAST (DT_ISP2261 << 1) #define DT_T10_PI BIT_25 #define DT_IIDMA BIT_26 @@ -3114,6 +3116,7 @@ struct qla_hw_data { #define IS_QLAFX00(ha) (DT_MASK(ha) & DT_ISPFX00) #define IS_QLA2071(ha) (DT_MASK(ha) & DT_ISP2071) #define IS_QLA2271(ha) (DT_MASK(ha) & DT_ISP2271) +#define IS_QLA2261(ha) (DT_MASK(ha) & DT_ISP2261) #define IS_QLA23XX(ha) (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \ IS_QLA6312(ha) || IS_QLA6322(ha)) @@ -3122,7 +3125,7 @@ struct qla_hw_data { #define IS_QLA25XX(ha) (IS_QLA2532(ha)) #define IS_QLA83XX(ha) (IS_QLA2031(ha) || IS_QLA8031(ha)) #define IS_QLA84XX(ha) (IS_QLA8432(ha)) -#define IS_QLA27XX(ha) (IS_QLA2071(ha) || IS_QLA2271(ha)) +#define IS_QLA27XX(ha) (IS_QLA2071(ha) || IS_QLA2271(ha) || IS_QLA2261(ha)) #define IS_QLA24XX_TYPE(ha) (IS_QLA24XX(ha) || IS_QLA54XX(ha) || \ IS_QLA84XX(ha)) #define IS_CNA_CAPABLE(ha) (IS_QLA81XX(ha) || IS_QLA82XX(ha) || \ diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0d0ff33d010f2..913a72506748a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -2208,6 +2208,13 @@ qla2x00_set_isp_flags(struct qla_hw_data *ha) ha->device_type |= DT_IIDMA; ha->fw_srisc_address = RISC_START_ADDRESS_2400; break; + case PCI_DEVICE_ID_QLOGIC_ISP2261: + ha->device_type |= DT_ISP2261; + ha->device_type |= DT_ZIO_SUPPORTED; + ha->device_type |= DT_FWI2; + ha->device_type |= DT_IIDMA; + ha->fw_srisc_address = RISC_START_ADDRESS_2400; + break; } if (IS_QLA82XX(ha)) @@ -2285,7 +2292,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) pdev->device == PCI_DEVICE_ID_QLOGIC_ISPF001 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP8044 || pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2071 || - pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2271) { + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2271 || + pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2261) { bars = pci_select_bars(pdev, IORESOURCE_MEM); mem_only = 1; ql_dbg_pci(ql_dbg_init, pdev, 0x0007, @@ -5697,6 +5705,7 @@ static struct pci_device_id qla2xxx_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP8044) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2071) }, { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2271) }, + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP2261) }, { 0 }, }; MODULE_DEVICE_TABLE(pci, qla2xxx_pci_tbl); -- GitLab From ef2a388dfce6ddc2fd0d1d798a8974396f6b6a22 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 4 Aug 2015 13:38:04 -0400 Subject: [PATCH 5087/7006] qla2xxx: Update driver version to 8.07.00.26-k Signed-off-by: Himanshu Madhani Signed-off-by: Giridhar Malavali Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 2ed9ab90a455b..6d31faa8c57b8 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.07.00.18-k" +#define QLA2XXX_VERSION "8.07.00.26-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 7 -- GitLab From 5cdac81a870f3bb65c50d3f5566a86fb086118d2 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Thu, 13 Aug 2015 21:47:34 -0500 Subject: [PATCH 5088/7006] cxlflash: Base error recovery support Introduce support for enhanced I/O error handling. A device state is added to track 3 possible states of the device: Normal - the device is operating normally and is fully operational Limbo - the device is in a reset/recovery scenario and its operational status is paused Failed/terminating - the device has either failed to be reset/recovered or is being terminated (removed); it is no longer operational All operations are allowed when the device is operating normally. When the device transitions to limbo state, I/O must be paused. To help accomplish this, a wait queue is introduced where existing and new threads can wait until the device is no longer in limbo. When coming out of limbo, threads need to check the state and error out gracefully when encountering the failed state. When the device transitions to the failed/terminating state, normal operations are no longer allowed. Only specially designated operations related to graceful cleanup are permitted. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Daniel Axtens Reviewed-by: Michael Neuling Reviewed-by: Wen Xiong Reviewed-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/Kconfig | 2 +- drivers/scsi/cxlflash/common.h | 11 +- drivers/scsi/cxlflash/main.c | 174 ++++++++++++++++++++++++++++++-- drivers/scsi/cxlflash/main.h | 6 +- drivers/scsi/cxlflash/sislite.h | 0 5 files changed, 177 insertions(+), 16 deletions(-) mode change 100755 => 100644 drivers/scsi/cxlflash/sislite.h diff --git a/drivers/scsi/cxlflash/Kconfig b/drivers/scsi/cxlflash/Kconfig index c7075084cfdbb..c052104e523ee 100644 --- a/drivers/scsi/cxlflash/Kconfig +++ b/drivers/scsi/cxlflash/Kconfig @@ -4,7 +4,7 @@ config CXLFLASH tristate "Support for IBM CAPI Flash" - depends on PCI && SCSI && CXL + depends on PCI && SCSI && CXL && EEH default m help Allows CAPI Accelerated IO to Flash diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index 5f43608dc8a18..ffdbc572d1808 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -76,6 +76,12 @@ enum cxlflash_init_state { INIT_STATE_SCSI }; +enum cxlflash_state { + STATE_NORMAL, /* Normal running state, everything good */ + STATE_LIMBO, /* Limbo running state, trying to reset/recover */ + STATE_FAILTERM /* Failed/terminating state, error out users/threads */ +}; + /* * Each context has its own set of resource handles that is visible * only from that context. @@ -91,8 +97,6 @@ struct cxlflash_cfg { ulong cxlflash_regs_pci; - wait_queue_head_t eeh_waitq; - struct work_struct work_q; enum cxlflash_init_state init_state; enum cxlflash_lr_state lr_state; @@ -105,7 +109,8 @@ struct cxlflash_cfg { wait_queue_head_t tmf_waitq; bool tmf_active; - u8 err_recovery_active:1; + wait_queue_head_t limbo_waitq; + enum cxlflash_state state; }; struct afu_cmd { diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 0720d2f13c2a0..3ae8dca236ef3 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -353,6 +353,7 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; struct afu *afu = cfg->afu; struct pci_dev *pdev = cfg->dev; + struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd; u32 port_sel = scp->device->channel + 1; int nseg, i, ncount; @@ -380,6 +381,21 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) } spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + switch (cfg->state) { + case STATE_LIMBO: + dev_dbg_ratelimited(dev, "%s: device in limbo!\n", __func__); + rc = SCSI_MLQUEUE_HOST_BUSY; + goto out; + case STATE_FAILTERM: + dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); + scp->result = (DID_NO_CONNECT << 16); + scp->scsi_done(scp); + rc = 0; + goto out; + default: + break; + } + cmd = cxlflash_cmd_checkout(afu); if (unlikely(!cmd)) { pr_err("%s: could not get a free command\n", __func__); @@ -455,9 +471,21 @@ static int cxlflash_eh_device_reset_handler(struct scsi_cmnd *scp) get_unaligned_be32(&((u32 *)scp->cmnd)[2]), get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - rcr = send_tmf(afu, scp, TMF_LUN_RESET); - if (unlikely(rcr)) + switch (cfg->state) { + case STATE_NORMAL: + rcr = send_tmf(afu, scp, TMF_LUN_RESET); + if (unlikely(rcr)) + rc = FAILED; + break; + case STATE_LIMBO: + wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); + if (cfg->state == STATE_NORMAL) + break; + /* fall through */ + default: rc = FAILED; + break; + } pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; @@ -487,11 +515,29 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) get_unaligned_be32(&((u32 *)scp->cmnd)[2]), get_unaligned_be32(&((u32 *)scp->cmnd)[3])); - rcr = cxlflash_afu_reset(cfg); - if (rcr == 0) - rc = SUCCESS; - else + switch (cfg->state) { + case STATE_NORMAL: + cfg->state = STATE_LIMBO; + scsi_block_requests(cfg->host); + + rcr = cxlflash_afu_reset(cfg); + if (rcr) { + rc = FAILED; + cfg->state = STATE_FAILTERM; + } else + cfg->state = STATE_NORMAL; + wake_up_all(&cfg->limbo_waitq); + scsi_unblock_requests(cfg->host); + break; + case STATE_LIMBO: + wait_event(cfg->limbo_waitq, cfg->state != STATE_LIMBO); + if (cfg->state == STATE_NORMAL) + break; + /* fall through */ + default: rc = FAILED; + break; + } pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; @@ -642,7 +688,7 @@ static void cxlflash_wait_for_pci_err_recovery(struct cxlflash_cfg *cfg) struct pci_dev *pdev = cfg->dev; if (pci_channel_offline(pdev)) - wait_event_timeout(cfg->eeh_waitq, + wait_event_timeout(cfg->limbo_waitq, !pci_channel_offline(pdev), CXLFLASH_PCI_ERROR_RECOVERY_TIMEOUT); } @@ -825,6 +871,8 @@ static void cxlflash_remove(struct pci_dev *pdev) !cfg->tmf_active); spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); + cfg->state = STATE_FAILTERM; + switch (cfg->init_state) { case INIT_STATE_SCSI: scsi_remove_host(cfg->host); @@ -1879,6 +1927,8 @@ static int init_afu(struct cxlflash_cfg *cfg) struct afu *afu = cfg->afu; struct device *dev = &cfg->dev->dev; + cxl_perst_reloads_same_image(cfg->cxl_afu, true); + rc = init_mc(cfg); if (rc) { dev_err(dev, "%s: call to init_mc failed, rc=%d!\n", @@ -2021,6 +2071,12 @@ void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) * the sync. This design point requires calling threads to not be on interrupt * context due to the possibility of sleeping during concurrent sync operations. * + * AFU sync operations are only necessary and allowed when the device is + * operating normally. When not operating normally, sync requests can occur as + * part of cleaning up resources associated with an adapter prior to removal. + * In this scenario, these requests are simply ignored (safe due to the AFU + * going away). + * * Return: * 0 on success * -1 on failure @@ -2028,11 +2084,17 @@ void cxlflash_wait_resp(struct afu *afu, struct afu_cmd *cmd) int cxlflash_afu_sync(struct afu *afu, ctx_hndl_t ctx_hndl_u, res_hndl_t res_hndl_u, u8 mode) { + struct cxlflash_cfg *cfg = afu->parent; struct afu_cmd *cmd = NULL; int rc = 0; int retry_cnt = 0; static DEFINE_MUTEX(sync_active); + if (cfg->state != STATE_NORMAL) { + pr_debug("%s: Sync not required! (%u)\n", __func__, cfg->state); + return 0; + } + mutex_lock(&sync_active); retry: cmd = cxlflash_cmd_checkout(afu); @@ -2116,12 +2178,17 @@ int cxlflash_afu_reset(struct cxlflash_cfg *cfg) */ static void cxlflash_worker_thread(struct work_struct *work) { - struct cxlflash_cfg *cfg = - container_of(work, struct cxlflash_cfg, work_q); + struct cxlflash_cfg *cfg = container_of(work, struct cxlflash_cfg, + work_q); struct afu *afu = cfg->afu; int port; ulong lock_flags; + /* Avoid MMIO if the device has failed */ + + if (cfg->state != STATE_NORMAL) + return; + spin_lock_irqsave(cfg->host->host_lock, lock_flags); if (cfg->lr_state == LINK_RESET_REQUIRED) { @@ -2200,10 +2267,9 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->dev = pdev; cfg->dev_id = (struct pci_device_id *)dev_id; cfg->mcctx = NULL; - cfg->err_recovery_active = 0; init_waitqueue_head(&cfg->tmf_waitq); - init_waitqueue_head(&cfg->eeh_waitq); + init_waitqueue_head(&cfg->limbo_waitq); INIT_WORK(&cfg->work_q, cxlflash_worker_thread); cfg->lr_state = LINK_RESET_INVALID; @@ -2259,6 +2325,91 @@ out_remove: goto out; } +/** + * cxlflash_pci_error_detected() - called when a PCI error is detected + * @pdev: PCI device struct. + * @state: PCI channel state. + * + * Return: PCI_ERS_RESULT_NEED_RESET or PCI_ERS_RESULT_DISCONNECT + */ +static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, + pci_channel_state_t state) +{ + struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + struct device *dev = &cfg->dev->dev; + + dev_dbg(dev, "%s: pdev=%p state=%u\n", __func__, pdev, state); + + switch (state) { + case pci_channel_io_frozen: + cfg->state = STATE_LIMBO; + + /* Turn off legacy I/O */ + scsi_block_requests(cfg->host); + + term_mc(cfg, UNDO_START); + stop_afu(cfg); + + return PCI_ERS_RESULT_NEED_RESET; + case pci_channel_io_perm_failure: + cfg->state = STATE_FAILTERM; + wake_up_all(&cfg->limbo_waitq); + scsi_unblock_requests(cfg->host); + return PCI_ERS_RESULT_DISCONNECT; + default: + break; + } + return PCI_ERS_RESULT_NEED_RESET; +} + +/** + * cxlflash_pci_slot_reset() - called when PCI slot has been reset + * @pdev: PCI device struct. + * + * This routine is called by the pci error recovery code after the PCI + * slot has been reset, just before we should resume normal operations. + * + * Return: PCI_ERS_RESULT_RECOVERED or PCI_ERS_RESULT_DISCONNECT + */ +static pci_ers_result_t cxlflash_pci_slot_reset(struct pci_dev *pdev) +{ + int rc = 0; + struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + struct device *dev = &cfg->dev->dev; + + dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); + + rc = init_afu(cfg); + if (unlikely(rc)) { + dev_err(dev, "%s: EEH recovery failed! (%d)\n", __func__, rc); + return PCI_ERS_RESULT_DISCONNECT; + } + + return PCI_ERS_RESULT_RECOVERED; +} + +/** + * cxlflash_pci_resume() - called when normal operation can resume + * @pdev: PCI device struct + */ +static void cxlflash_pci_resume(struct pci_dev *pdev) +{ + struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); + struct device *dev = &cfg->dev->dev; + + dev_dbg(dev, "%s: pdev=%p\n", __func__, pdev); + + cfg->state = STATE_NORMAL; + wake_up_all(&cfg->limbo_waitq); + scsi_unblock_requests(cfg->host); +} + +static const struct pci_error_handlers cxlflash_err_handler = { + .error_detected = cxlflash_pci_error_detected, + .slot_reset = cxlflash_pci_slot_reset, + .resume = cxlflash_pci_resume, +}; + /* * PCI device structure */ @@ -2267,6 +2418,7 @@ static struct pci_driver cxlflash_driver = { .id_table = cxlflash_pci_table, .probe = cxlflash_probe, .remove = cxlflash_remove, + .err_handler = &cxlflash_err_handler, }; /** diff --git a/drivers/scsi/cxlflash/main.h b/drivers/scsi/cxlflash/main.h index 7f890ccf32897..cf0e80938b132 100644 --- a/drivers/scsi/cxlflash/main.h +++ b/drivers/scsi/cxlflash/main.h @@ -22,7 +22,7 @@ #define CXLFLASH_NAME "cxlflash" #define CXLFLASH_ADAPTER_NAME "IBM POWER CXL Flash Adapter" -#define CXLFLASH_DRIVER_DATE "(June 2, 2015)" +#define CXLFLASH_DRIVER_DATE "(August 13, 2015)" #define PCI_DEVICE_ID_IBM_CORSA 0x04F0 #define CXLFLASH_SUBS_DEV_ID 0x04F0 @@ -101,4 +101,8 @@ struct asyc_intr_info { #define LINK_RESET 0x02 }; +#ifndef CONFIG_CXL_EEH +#define cxl_perst_reloads_same_image(_a, _b) do { } while (0) +#endif + #endif /* _CXLFLASH_MAIN_H */ diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h old mode 100755 new mode 100644 -- GitLab From 65be2c79acc3aa0f9c0e8d4871f5a451d854465a Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Thu, 13 Aug 2015 21:47:43 -0500 Subject: [PATCH 5089/7006] cxlflash: Superpipe support Add superpipe supporting infrastructure to device driver for the IBM CXL Flash adapter. This patch allows userspace applications to take advantage of the accelerated I/O features that this adapter provides and bypass the traditional filesystem stack. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Michael Neuling Reviewed-by: Wen Xiong Reviewed-by: Brian King Signed-off-by: James Bottomley --- Documentation/ioctl/ioctl-number.txt | 1 + Documentation/powerpc/cxlflash.txt | 257 ++++ drivers/scsi/cxlflash/Makefile | 2 +- drivers/scsi/cxlflash/common.h | 19 + drivers/scsi/cxlflash/lunmgt.c | 263 ++++ drivers/scsi/cxlflash/main.c | 38 +- drivers/scsi/cxlflash/sislite.h | 5 +- drivers/scsi/cxlflash/superpipe.c | 2014 ++++++++++++++++++++++++++ drivers/scsi/cxlflash/superpipe.h | 132 ++ include/uapi/scsi/Kbuild | 1 + include/uapi/scsi/cxlflash_ioctl.h | 140 ++ 11 files changed, 2868 insertions(+), 4 deletions(-) create mode 100644 Documentation/powerpc/cxlflash.txt create mode 100644 drivers/scsi/cxlflash/lunmgt.c create mode 100644 drivers/scsi/cxlflash/superpipe.c create mode 100644 drivers/scsi/cxlflash/superpipe.h create mode 100644 include/uapi/scsi/cxlflash_ioctl.h diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 611c52267d248..9bd118d26a8ab 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -314,6 +314,7 @@ Code Seq#(hex) Include File Comments 0xB3 00 linux/mmc/ioctl.h 0xC0 00-0F linux/usb/iowarrior.h 0xCA 00-0F uapi/misc/cxl.h +0xCA 80-8F uapi/scsi/cxlflash_ioctl.h 0xCB 00-1F CBM serial IEC bus in development: 0xCD 01 linux/reiserfs_fs.h diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt new file mode 100644 index 0000000000000..f943967f90ce0 --- /dev/null +++ b/Documentation/powerpc/cxlflash.txt @@ -0,0 +1,257 @@ +Introduction +============ + + The IBM Power architecture provides support for CAPI (Coherent + Accelerator Power Interface), which is available to certain PCIe slots + on Power 8 systems. CAPI can be thought of as a special tunneling + protocol through PCIe that allow PCIe adapters to look like special + purpose co-processors which can read or write an application's + memory and generate page faults. As a result, the host interface to + an adapter running in CAPI mode does not require the data buffers to + be mapped to the device's memory (IOMMU bypass) nor does it require + memory to be pinned. + + On Linux, Coherent Accelerator (CXL) kernel services present CAPI + devices as a PCI device by implementing a virtual PCI host bridge. + This abstraction simplifies the infrastructure and programming + model, allowing for drivers to look similar to other native PCI + device drivers. + + CXL provides a mechanism by which user space applications can + directly talk to a device (network or storage) bypassing the typical + kernel/device driver stack. The CXL Flash Adapter Driver enables a + user space application direct access to Flash storage. + + The CXL Flash Adapter Driver is a kernel module that sits in the + SCSI stack as a low level device driver (below the SCSI disk and + protocol drivers) for the IBM CXL Flash Adapter. This driver is + responsible for the initialization of the adapter, setting up the + special path for user space access, and performing error recovery. It + communicates directly the Flash Accelerator Functional Unit (AFU) + as described in Documentation/powerpc/cxl.txt. + + The cxlflash driver supports two, mutually exclusive, modes of + operation at the device (LUN) level: + + - Any flash device (LUN) can be configured to be accessed as a + regular disk device (i.e.: /dev/sdc). This is the default mode. + + - Any flash device (LUN) can be configured to be accessed from + user space with a special block library. This mode further + specifies the means of accessing the device and provides for + either raw access to the entire LUN (referred to as direct + or physical LUN access) or access to a kernel/AFU-mediated + partition of the LUN (referred to as virtual LUN access). The + segmentation of a disk device into virtual LUNs is assisted + by special translation services provided by the Flash AFU. + +Overview +======== + + The Coherent Accelerator Interface Architecture (CAIA) introduces a + concept of a master context. A master typically has special privileges + granted to it by the kernel or hypervisor allowing it to perform AFU + wide management and control. The master may or may not be involved + directly in each user I/O, but at the minimum is involved in the + initial setup before the user application is allowed to send requests + directly to the AFU. + + The CXL Flash Adapter Driver establishes a master context with the + AFU. It uses memory mapped I/O (MMIO) for this control and setup. The + Adapter Problem Space Memory Map looks like this: + + +-------------------------------+ + | 512 * 64 KB User MMIO | + | (per context) | + | User Accessible | + +-------------------------------+ + | 512 * 128 B per context | + | Provisioning and Control | + | Trusted Process accessible | + +-------------------------------+ + | 64 KB Global | + | Trusted Process accessible | + +-------------------------------+ + + This driver configures itself into the SCSI software stack as an + adapter driver. The driver is the only entity that is considered a + Trusted Process to program the Provisioning and Control and Global + areas in the MMIO Space shown above. The master context driver + discovers all LUNs attached to the CXL Flash adapter and instantiates + scsi block devices (/dev/sdb, /dev/sdc etc.) for each unique LUN + seen from each path. + + Once these scsi block devices are instantiated, an application + written to a specification provided by the block library may get + access to the Flash from user space (without requiring a system call). + + This master context driver also provides a series of ioctls for this + block library to enable this user space access. The driver supports + two modes for accessing the block device. + + The first mode is called a virtual mode. In this mode a single scsi + block device (/dev/sdb) may be carved up into any number of distinct + virtual LUNs. The virtual LUNs may be resized as long as the sum of + the sizes of all the virtual LUNs, along with the meta-data associated + with it does not exceed the physical capacity. + + The second mode is called the physical mode. In this mode a single + block device (/dev/sdb) may be opened directly by the block library + and the entire space for the LUN is available to the application. + + Only the physical mode provides persistence of the data. i.e. The + data written to the block device will survive application exit and + restart and also reboot. The virtual LUNs do not persist (i.e. do + not survive after the application terminates or the system reboots). + + +Block library API +================= + + Applications intending to get access to the CXL Flash from user + space should use the block library, as it abstracts the details of + interfacing directly with the cxlflash driver that are necessary for + performing administrative actions (i.e.: setup, tear down, resize). + The block library can be thought of as a 'user' of services, + implemented as IOCTLs, that are provided by the cxlflash driver + specifically for devices (LUNs) operating in user space access + mode. While it is not a requirement that applications understand + the interface between the block library and the cxlflash driver, + a high-level overview of each supported service (IOCTL) is provided + below. + + The block library can be found on GitHub: + http://www.github.com/mikehollinger/ibmcapikv + + +CXL Flash Driver IOCTLs +======================= + + Users, such as the block library, that wish to interface with a flash + device (LUN) via user space access need to use the services provided + by the cxlflash driver. As these services are implemented as ioctls, + a file descriptor handle must first be obtained in order to establish + the communication channel between a user and the kernel. This file + descriptor is obtained by opening the device special file associated + with the scsi disk device (/dev/sdb) that was created during LUN + discovery. As per the location of the cxlflash driver within the + SCSI protocol stack, this open is actually not seen by the cxlflash + driver. Upon successful open, the user receives a file descriptor + (herein referred to as fd1) that should be used for issuing the + subsequent ioctls listed below. + + The structure definitions for these IOCTLs are available in: + uapi/scsi/cxlflash_ioctl.h + +DK_CXLFLASH_ATTACH +------------------ + + This ioctl obtains, initializes, and starts a context using the CXL + kernel services. These services specify a context id (u16) by which + to uniquely identify the context and its allocated resources. The + services additionally provide a second file descriptor (herein + referred to as fd2) that is used by the block library to initiate + memory mapped I/O (via mmap()) to the CXL flash device and poll for + completion events. This file descriptor is intentionally installed by + this driver and not the CXL kernel services to allow for intermediary + notification and access in the event of a non-user-initiated close(), + such as a killed process. This design point is described in further + detail in the description for the DK_CXLFLASH_DETACH ioctl. + + There are a few important aspects regarding the "tokens" (context id + and fd2) that are provided back to the user: + + - These tokens are only valid for the process under which they + were created. The child of a forked process cannot continue + to use the context id or file descriptor created by its parent. + + - These tokens are only valid for the lifetime of the context and + the process under which they were created. Once either is + destroyed, the tokens are to be considered stale and subsequent + usage will result in errors. + + - When a context is no longer needed, the user shall detach from + the context via the DK_CXLFLASH_DETACH ioctl. + + - A close on fd2 will invalidate the tokens. This operation is not + required by the user. + +DK_CXLFLASH_USER_DIRECT +----------------------- + This ioctl is responsible for transitioning the LUN to direct + (physical) mode access and configuring the AFU for direct access from + user space on a per-context basis. Additionally, the block size and + last logical block address (LBA) are returned to the user. + + As mentioned previously, when operating in user space access mode, + LUNs may be accessed in whole or in part. Only one mode is allowed + at a time and if one mode is active (outstanding references exist), + requests to use the LUN in a different mode are denied. + + The AFU is configured for direct access from user space by adding an + entry to the AFU's resource handle table. The index of the entry is + treated as a resource handle that is returned to the user. The user + is then able to use the handle to reference the LUN during I/O. + +DK_CXLFLASH_RELEASE +------------------- + This ioctl is responsible for releasing a previously obtained + reference to either a physical or virtual LUN. This can be + thought of as the inverse of the DK_CXLFLASH_USER_DIRECT or + DK_CXLFLASH_USER_VIRTUAL ioctls. Upon success, the resource handle + is no longer valid and the entry in the resource handle table is + made available to be used again. + + As part of the release process for virtual LUNs, the virtual LUN + is first resized to 0 to clear out and free the translation tables + associated with the virtual LUN reference. + +DK_CXLFLASH_DETACH +------------------ + This ioctl is responsible for unregistering a context with the + cxlflash driver and release outstanding resources that were + not explicitly released via the DK_CXLFLASH_RELEASE ioctl. Upon + success, all "tokens" which had been provided to the user from the + DK_CXLFLASH_ATTACH onward are no longer valid. + +DK_CXLFLASH_VERIFY +------------------ + This ioctl is used to detect various changes such as the capacity of + the disk changing, the number of LUNs visible changing, etc. In cases + where the changes affect the application (such as a LUN resize), the + cxlflash driver will report the changed state to the application. + + The user calls in when they want to validate that a LUN hasn't been + changed in response to a check condition. As the user is operating out + of band from the kernel, they will see these types of events without + the kernel's knowledge. When encountered, the user's architected + behavior is to call in to this ioctl, indicating what they want to + verify and passing along any appropriate information. For now, only + verifying a LUN change (ie: size different) with sense data is + supported. + +DK_CXLFLASH_RECOVER_AFU +----------------------- + This ioctl is used to drive recovery (if such an action is warranted) + of a specified user context. Any state associated with the user context + is re-established upon successful recovery. + + User contexts are put into an error condition when the device needs to + be reset or is terminating. Users are notified of this error condition + by seeing all 0xF's on an MMIO read. Upon encountering this, the + architected behavior for a user is to call into this ioctl to recover + their context. A user may also call into this ioctl at any time to + check if the device is operating normally. If a failure is returned + from this ioctl, the user is expected to gracefully clean up their + context via release/detach ioctls. Until they do, the context they + hold is not relinquished. The user may also optionally exit the process + at which time the context/resources they held will be freed as part of + the release fop. + +DK_CXLFLASH_MANAGE_LUN +---------------------- + This ioctl is used to switch a LUN from a mode where it is available + for file-system access (legacy), to a mode where it is set aside for + exclusive user space access (superpipe). In case a LUN is visible + across multiple ports and adapters, this ioctl is used to uniquely + identify each LUN by its World Wide Node Name (WWNN). diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile index dc95e203e3afa..c14d24c720d68 100644 --- a/drivers/scsi/cxlflash/Makefile +++ b/drivers/scsi/cxlflash/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CXLFLASH) += cxlflash.o -cxlflash-y += main.o +cxlflash-y += main.o superpipe.o lunmgt.o diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index ffdbc572d1808..d3e54e61c7a51 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -107,6 +107,17 @@ struct cxlflash_cfg { struct pci_pool *cxlflash_cmd_pool; struct pci_dev *parent_dev; + atomic_t recovery_threads; + struct mutex ctx_recovery_mutex; + struct mutex ctx_tbl_list_mutex; + struct ctx_info *ctx_tbl[MAX_CONTEXT]; + struct list_head ctx_err_recovery; /* contexts w/ recovery pending */ + struct file_operations cxl_fops; + + atomic_t num_user_contexts; + + struct list_head lluns; /* list of llun_info structs */ + wait_queue_head_t tmf_waitq; bool tmf_active; wait_queue_head_t limbo_waitq; @@ -182,4 +193,12 @@ int cxlflash_afu_reset(struct cxlflash_cfg *); struct afu_cmd *cxlflash_cmd_checkout(struct afu *); void cxlflash_cmd_checkin(struct afu_cmd *); int cxlflash_afu_sync(struct afu *, ctx_hndl_t, res_hndl_t, u8); +void cxlflash_list_init(void); +void cxlflash_term_global_luns(void); +void cxlflash_free_errpage(void); +int cxlflash_ioctl(struct scsi_device *, int, void __user *); +void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *); +int cxlflash_mark_contexts_error(struct cxlflash_cfg *); +void cxlflash_term_local_luns(struct cxlflash_cfg *); + #endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c new file mode 100644 index 0000000000000..66d5bef11ee60 --- /dev/null +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -0,0 +1,263 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * 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 +#include + +#include +#include + +#include "sislite.h" +#include "common.h" +#include "superpipe.h" + +/** + * create_local() - allocate and initialize a local LUN information structure + * @sdev: SCSI device associated with LUN. + * @wwid: World Wide Node Name for LUN. + * + * Return: Allocated local llun_info structure on success, NULL on failure + */ +static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) +{ + struct llun_info *lli = NULL; + + lli = kzalloc(sizeof(*lli), GFP_KERNEL); + if (unlikely(!lli)) { + pr_err("%s: could not allocate lli\n", __func__); + goto out; + } + + lli->sdev = sdev; + lli->newly_created = true; + lli->host_no = sdev->host->host_no; + + memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); +out: + return lli; +} + +/** + * create_global() - allocate and initialize a global LUN information structure + * @sdev: SCSI device associated with LUN. + * @wwid: World Wide Node Name for LUN. + * + * Return: Allocated global glun_info structure on success, NULL on failure + */ +static struct glun_info *create_global(struct scsi_device *sdev, u8 *wwid) +{ + struct glun_info *gli = NULL; + + gli = kzalloc(sizeof(*gli), GFP_KERNEL); + if (unlikely(!gli)) { + pr_err("%s: could not allocate gli\n", __func__); + goto out; + } + + mutex_init(&gli->mutex); + memcpy(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); +out: + return gli; +} + +/** + * refresh_local() - find and update local LUN information structure by WWID + * @cfg: Internal structure associated with the host. + * @wwid: WWID associated with LUN. + * + * When the LUN is found, mark it by updating it's newly_created field. + * + * Return: Found local lun_info structure on success, NULL on failure + * If a LUN with the WWID is found in the list, refresh it's state. + */ +static struct llun_info *refresh_local(struct cxlflash_cfg *cfg, u8 *wwid) +{ + struct llun_info *lli, *temp; + + list_for_each_entry_safe(lli, temp, &cfg->lluns, list) + if (!memcmp(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) { + lli->newly_created = false; + return lli; + } + + return NULL; +} + +/** + * lookup_global() - find a global LUN information structure by WWID + * @wwid: WWID associated with LUN. + * + * Return: Found global lun_info structure on success, NULL on failure + */ +static struct glun_info *lookup_global(u8 *wwid) +{ + struct glun_info *gli, *temp; + + list_for_each_entry_safe(gli, temp, &global.gluns, list) + if (!memcmp(gli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN)) + return gli; + + return NULL; +} + +/** + * find_and_create_lun() - find or create a local LUN information structure + * @sdev: SCSI device associated with LUN. + * @wwid: WWID associated with LUN. + * + * The LUN is kept both in a local list (per adapter) and in a global list + * (across all adapters). Certain attributes of the LUN are local to the + * adapter (such as index, port selection mask etc.). + * The block allocation map is shared across all adapters (i.e. associated + * wih the global list). Since different attributes are associated with + * the per adapter and global entries, allocate two separate structures for each + * LUN (one local, one global). + * + * Keep a pointer back from the local to the global entry. + * + * Return: Found/Allocated local lun_info structure on success, NULL on failure + */ +static struct llun_info *find_and_create_lun(struct scsi_device *sdev, u8 *wwid) +{ + struct llun_info *lli = NULL; + struct glun_info *gli = NULL; + struct Scsi_Host *shost = sdev->host; + struct cxlflash_cfg *cfg = shost_priv(shost); + + mutex_lock(&global.mutex); + if (unlikely(!wwid)) + goto out; + + lli = refresh_local(cfg, wwid); + if (lli) + goto out; + + lli = create_local(sdev, wwid); + if (unlikely(!lli)) + goto out; + + gli = lookup_global(wwid); + if (gli) { + lli->parent = gli; + list_add(&lli->list, &cfg->lluns); + goto out; + } + + gli = create_global(sdev, wwid); + if (unlikely(!gli)) { + kfree(lli); + lli = NULL; + goto out; + } + + lli->parent = gli; + list_add(&lli->list, &cfg->lluns); + + list_add(&gli->list, &global.gluns); + +out: + mutex_unlock(&global.mutex); + pr_debug("%s: returning %p\n", __func__, lli); + return lli; +} + +/** + * cxlflash_term_local_luns() - Delete all entries from local LUN list, free. + * @cfg: Internal structure associated with the host. + */ +void cxlflash_term_local_luns(struct cxlflash_cfg *cfg) +{ + struct llun_info *lli, *temp; + + mutex_lock(&global.mutex); + list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { + list_del(&lli->list); + kfree(lli); + } + mutex_unlock(&global.mutex); +} + +/** + * cxlflash_list_init() - initializes the global LUN list + */ +void cxlflash_list_init(void) +{ + INIT_LIST_HEAD(&global.gluns); + mutex_init(&global.mutex); + global.err_page = NULL; +} + +/** + * cxlflash_term_global_luns() - frees resources associated with global LUN list + */ +void cxlflash_term_global_luns(void) +{ + struct glun_info *gli, *temp; + + mutex_lock(&global.mutex); + list_for_each_entry_safe(gli, temp, &global.gluns, list) { + list_del(&gli->list); + kfree(gli); + } + mutex_unlock(&global.mutex); +} + +/** + * cxlflash_manage_lun() - handles LUN management activities + * @sdev: SCSI device associated with LUN. + * @manage: Manage ioctl data structure. + * + * This routine is used to notify the driver about a LUN's WWID and associate + * SCSI devices (sdev) with a global LUN instance. Additionally it serves to + * change a LUN's operating mode: legacy or superpipe. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_manage_lun(struct scsi_device *sdev, + struct dk_cxlflash_manage_lun *manage) +{ + int rc = 0; + struct llun_info *lli = NULL; + u64 flags = manage->hdr.flags; + u32 chan = sdev->channel; + + lli = find_and_create_lun(sdev, manage->wwid); + pr_debug("%s: ENTER: WWID = %016llX%016llX, flags = %016llX li = %p\n", + __func__, get_unaligned_le64(&manage->wwid[0]), + get_unaligned_le64(&manage->wwid[8]), + manage->hdr.flags, lli); + if (unlikely(!lli)) { + rc = -ENOMEM; + goto out; + } + + if (flags & DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE) { + if (lli->newly_created) + lli->port_sel = CHAN2PORT(chan); + else + lli->port_sel = BOTH_PORTS; + /* Store off lun in unpacked, AFU-friendly format */ + lli->lun_id[chan] = lun_to_lunid(sdev->lun); + sdev->hostdata = lli; + } else if (flags & DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE) { + if (lli->parent->mode != MODE_NONE) + rc = -EBUSY; + else + sdev->hostdata = NULL; + } + +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 3ae8dca236ef3..02d464f41b7fa 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -23,6 +23,7 @@ #include #include +#include #include "main.h" #include "sislite.h" @@ -519,7 +520,7 @@ static int cxlflash_eh_host_reset_handler(struct scsi_cmnd *scp) case STATE_NORMAL: cfg->state = STATE_LIMBO; scsi_block_requests(cfg->host); - + cxlflash_mark_contexts_error(cfg); rcr = cxlflash_afu_reset(cfg); if (rcr) { rc = FAILED; @@ -662,6 +663,21 @@ static ssize_t cxlflash_store_lun_mode(struct device *dev, return count; } +/** + * cxlflash_show_ioctl_version() - presents the current ioctl version of the host + * @dev: Generic device associated with the host. + * @attr: Device attribute representing the ioctl version. + * @buf: Buffer of length PAGE_SIZE to report back the ioctl version. + * + * Return: The size of the ASCII string returned in @buf. + */ +static ssize_t cxlflash_show_ioctl_version(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return scnprintf(buf, PAGE_SIZE, "%u\n", DK_CXLFLASH_VERSION_0); +} + /** * cxlflash_show_dev_mode() - presents the current mode of the device * @dev: Generic device associated with the device. @@ -700,11 +716,13 @@ static DEVICE_ATTR(port0, S_IRUGO, cxlflash_show_port_status, NULL); static DEVICE_ATTR(port1, S_IRUGO, cxlflash_show_port_status, NULL); static DEVICE_ATTR(lun_mode, S_IRUGO | S_IWUSR, cxlflash_show_lun_mode, cxlflash_store_lun_mode); +static DEVICE_ATTR(ioctl_version, S_IRUGO, cxlflash_show_ioctl_version, NULL); static struct device_attribute *cxlflash_host_attrs[] = { &dev_attr_port0, &dev_attr_port1, &dev_attr_lun_mode, + &dev_attr_ioctl_version, NULL }; @@ -725,6 +743,7 @@ static struct scsi_host_template driver_template = { .module = THIS_MODULE, .name = CXLFLASH_ADAPTER_NAME, .info = cxlflash_driver_info, + .ioctl = cxlflash_ioctl, .proc_name = CXLFLASH_NAME, .queuecommand = cxlflash_queuecommand, .eh_device_reset_handler = cxlflash_eh_device_reset_handler, @@ -872,9 +891,11 @@ static void cxlflash_remove(struct pci_dev *pdev) spin_unlock_irqrestore(&cfg->tmf_waitq.lock, lock_flags); cfg->state = STATE_FAILTERM; + cxlflash_stop_term_user_contexts(cfg); switch (cfg->init_state) { case INIT_STATE_SCSI: + cxlflash_term_local_luns(cfg); scsi_remove_host(cfg->host); scsi_host_put(cfg->host); /* Fall through */ @@ -2274,6 +2295,10 @@ static int cxlflash_probe(struct pci_dev *pdev, INIT_WORK(&cfg->work_q, cxlflash_worker_thread); cfg->lr_state = LINK_RESET_INVALID; cfg->lr_port = -1; + mutex_init(&cfg->ctx_tbl_list_mutex); + mutex_init(&cfg->ctx_recovery_mutex); + INIT_LIST_HEAD(&cfg->ctx_err_recovery); + INIT_LIST_HEAD(&cfg->lluns); pci_set_drvdata(pdev, cfg); @@ -2335,6 +2360,7 @@ out_remove: static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { + int rc = 0; struct cxlflash_cfg *cfg = pci_get_drvdata(pdev); struct device *dev = &cfg->dev->dev; @@ -2346,7 +2372,10 @@ static pci_ers_result_t cxlflash_pci_error_detected(struct pci_dev *pdev, /* Turn off legacy I/O */ scsi_block_requests(cfg->host); - + rc = cxlflash_mark_contexts_error(cfg); + if (unlikely(rc)) + dev_err(dev, "%s: Failed to mark user contexts!(%d)\n", + __func__, rc); term_mc(cfg, UNDO_START); stop_afu(cfg); @@ -2431,6 +2460,8 @@ static int __init init_cxlflash(void) pr_info("%s: IBM Power CXL Flash Adapter: %s\n", __func__, CXLFLASH_DRIVER_DATE); + cxlflash_list_init(); + return pci_register_driver(&cxlflash_driver); } @@ -2439,6 +2470,9 @@ static int __init init_cxlflash(void) */ static void __exit exit_cxlflash(void) { + cxlflash_term_global_luns(); + cxlflash_free_errpage(); + pci_unregister_driver(&cxlflash_driver); } diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index bf5d39978630f..66b889151a4cb 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -409,7 +409,10 @@ struct sisl_lxt_entry { }; -/* Per the SISlite spec, RHT entries are to be 16-byte aligned */ +/* + * RHT - Resource Handle Table + * Per the SISlite spec, RHT entries are to be 16-byte aligned + */ struct sisl_rht_entry { struct sisl_lxt_entry *lxt_start; u32 lxt_cnt; diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c new file mode 100644 index 0000000000000..3c8bce8bbb0b9 --- /dev/null +++ b/drivers/scsi/cxlflash/superpipe.c @@ -0,0 +1,2014 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "sislite.h" +#include "common.h" +#include "superpipe.h" + +struct cxlflash_global global; + +/** + * marshal_det_to_rele() - translate detach to release structure + * @detach: Destination structure for the translate/copy. + * @rele: Source structure from which to translate/copy. + */ +static void marshal_det_to_rele(struct dk_cxlflash_detach *detach, + struct dk_cxlflash_release *release) +{ + release->hdr = detach->hdr; + release->context_id = detach->context_id; +} + +/** + * cxlflash_free_errpage() - frees resources associated with global error page + */ +void cxlflash_free_errpage(void) +{ + + mutex_lock(&global.mutex); + if (global.err_page) { + __free_page(global.err_page); + global.err_page = NULL; + } + mutex_unlock(&global.mutex); +} + +/** + * cxlflash_stop_term_user_contexts() - stops/terminates known user contexts + * @cfg: Internal structure associated with the host. + * + * When the host needs to go down, all users must be quiesced and their + * memory freed. This is accomplished by putting the contexts in error + * state which will notify the user and let them 'drive' the tear-down. + * Meanwhile, this routine camps until all user contexts have been removed. + */ +void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *cfg) +{ + struct device *dev = &cfg->dev->dev; + int i, found; + + cxlflash_mark_contexts_error(cfg); + + while (true) { + found = false; + + for (i = 0; i < MAX_CONTEXT; i++) + if (cfg->ctx_tbl[i]) { + found = true; + break; + } + + if (!found && list_empty(&cfg->ctx_err_recovery)) + return; + + dev_dbg(dev, "%s: Wait for user contexts to quiesce...\n", + __func__); + wake_up_all(&cfg->limbo_waitq); + ssleep(1); + } +} + +/** + * find_error_context() - locates a context by cookie on the error recovery list + * @cfg: Internal structure associated with the host. + * @rctxid: Desired context by id. + * @file: Desired context by file. + * + * Return: Found context on success, NULL on failure + */ +static struct ctx_info *find_error_context(struct cxlflash_cfg *cfg, u64 rctxid, + struct file *file) +{ + struct ctx_info *ctxi; + + list_for_each_entry(ctxi, &cfg->ctx_err_recovery, list) + if ((ctxi->ctxid == rctxid) || (ctxi->file == file)) + return ctxi; + + return NULL; +} + +/** + * get_context() - obtains a validated and locked context reference + * @cfg: Internal structure associated with the host. + * @rctxid: Desired context (raw, un-decoded format). + * @arg: LUN information or file associated with request. + * @ctx_ctrl: Control information to 'steer' desired lookup. + * + * NOTE: despite the name pid, in linux, current->pid actually refers + * to the lightweight process id (tid) and can change if the process is + * multi threaded. The tgid remains constant for the process and only changes + * when the process of fork. For all intents and purposes, think of tgid + * as a pid in the traditional sense. + * + * Return: Validated context on success, NULL on failure + */ +struct ctx_info *get_context(struct cxlflash_cfg *cfg, u64 rctxid, + void *arg, enum ctx_ctrl ctx_ctrl) +{ + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + struct lun_access *lun_access = NULL; + struct file *file = NULL; + struct llun_info *lli = arg; + u64 ctxid = DECODE_CTXID(rctxid); + int rc; + pid_t pid = current->tgid, ctxpid = 0; + + if (ctx_ctrl & CTX_CTRL_FILE) { + lli = NULL; + file = (struct file *)arg; + } + + if (ctx_ctrl & CTX_CTRL_CLONE) + pid = current->parent->tgid; + + if (likely(ctxid < MAX_CONTEXT)) { + while (true) { + rc = mutex_lock_interruptible(&cfg->ctx_tbl_list_mutex); + if (rc) + goto out; + + ctxi = cfg->ctx_tbl[ctxid]; + if (ctxi) + if ((file && (ctxi->file != file)) || + (!file && (ctxi->ctxid != rctxid))) + ctxi = NULL; + + if ((ctx_ctrl & CTX_CTRL_ERR) || + (!ctxi && (ctx_ctrl & CTX_CTRL_ERR_FALLBACK))) + ctxi = find_error_context(cfg, rctxid, file); + if (!ctxi) { + mutex_unlock(&cfg->ctx_tbl_list_mutex); + goto out; + } + + /* + * Need to acquire ownership of the context while still + * under the table/list lock to serialize with a remove + * thread. Use the 'try' to avoid stalling the + * table/list lock for a single context. + * + * Note that the lock order is: + * + * cfg->ctx_tbl_list_mutex -> ctxi->mutex + * + * Therefore release ctx_tbl_list_mutex before retrying. + */ + rc = mutex_trylock(&ctxi->mutex); + mutex_unlock(&cfg->ctx_tbl_list_mutex); + if (rc) + break; /* got the context's lock! */ + } + + if (ctxi->unavail) + goto denied; + + ctxpid = ctxi->pid; + if (likely(!(ctx_ctrl & CTX_CTRL_NOPID))) + if (pid != ctxpid) + goto denied; + + if (lli) { + list_for_each_entry(lun_access, &ctxi->luns, list) + if (lun_access->lli == lli) + goto out; + goto denied; + } + } + +out: + dev_dbg(dev, "%s: rctxid=%016llX ctxinfo=%p ctxpid=%u pid=%u " + "ctx_ctrl=%u\n", __func__, rctxid, ctxi, ctxpid, pid, + ctx_ctrl); + + return ctxi; + +denied: + mutex_unlock(&ctxi->mutex); + ctxi = NULL; + goto out; +} + +/** + * put_context() - release a context that was retrieved from get_context() + * @ctxi: Context to release. + * + * For now, releasing the context equates to unlocking it's mutex. + */ +void put_context(struct ctx_info *ctxi) +{ + mutex_unlock(&ctxi->mutex); +} + +/** + * afu_attach() - attach a context to the AFU + * @cfg: Internal structure associated with the host. + * @ctxi: Context to attach. + * + * Upon setting the context capabilities, they must be confirmed with + * a read back operation as the context might have been closed since + * the mailbox was unlocked. When this occurs, registration is failed. + * + * Return: 0 on success, -errno on failure + */ +static int afu_attach(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) +{ + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct sisl_ctrl_map *ctrl_map = ctxi->ctrl_map; + int rc = 0; + u64 val; + + /* Unlock cap and restrict user to read/write cmds in translated mode */ + readq_be(&ctrl_map->mbox_r); + val = (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD); + writeq_be(val, &ctrl_map->ctx_cap); + val = readq_be(&ctrl_map->ctx_cap); + if (val != (SISL_CTX_CAP_READ_CMD | SISL_CTX_CAP_WRITE_CMD)) { + dev_err(dev, "%s: ctx may be closed val=%016llX\n", + __func__, val); + rc = -EAGAIN; + goto out; + } + + /* Set up MMIO registers pointing to the RHT */ + writeq_be((u64)ctxi->rht_start, &ctrl_map->rht_start); + val = SISL_RHT_CNT_ID((u64)MAX_RHT_PER_CONTEXT, (u64)(afu->ctx_hndl)); + writeq_be(val, &ctrl_map->rht_cnt_id); +out: + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * read_cap16() - issues a SCSI READ_CAP16 command + * @sdev: SCSI device associated with LUN. + * @lli: LUN destined for capacity request. + * + * Return: 0 on success, -errno on failure + */ +static int read_cap16(struct scsi_device *sdev, struct llun_info *lli) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct glun_info *gli = lli->parent; + u8 *cmd_buf = NULL; + u8 *scsi_cmd = NULL; + u8 *sense_buf = NULL; + int rc = 0; + int result = 0; + int retry_cnt = 0; + u32 tout = (MC_DISCOVERY_TIMEOUT * HZ); + +retry: + cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); + scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); + sense_buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (unlikely(!cmd_buf || !scsi_cmd || !sense_buf)) { + rc = -ENOMEM; + goto out; + } + + scsi_cmd[0] = SERVICE_ACTION_IN_16; /* read cap(16) */ + scsi_cmd[1] = SAI_READ_CAPACITY_16; /* service action */ + put_unaligned_be32(CMD_BUFSIZE, &scsi_cmd[10]); + + dev_dbg(dev, "%s: %ssending cmd(0x%x)\n", __func__, + retry_cnt ? "re" : "", scsi_cmd[0]); + + result = scsi_execute(sdev, scsi_cmd, DMA_FROM_DEVICE, cmd_buf, + CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + + if (driver_byte(result) == DRIVER_SENSE) { + result &= ~(0xFF<<24); /* DRIVER_SENSE is not an error */ + if (result & SAM_STAT_CHECK_CONDITION) { + struct scsi_sense_hdr sshdr; + + scsi_normalize_sense(sense_buf, SCSI_SENSE_BUFFERSIZE, + &sshdr); + switch (sshdr.sense_key) { + case NO_SENSE: + case RECOVERED_ERROR: + /* fall through */ + case NOT_READY: + result &= ~SAM_STAT_CHECK_CONDITION; + break; + case UNIT_ATTENTION: + switch (sshdr.asc) { + case 0x29: /* Power on Reset or Device Reset */ + /* fall through */ + case 0x2A: /* Device capacity changed */ + case 0x3F: /* Report LUNs changed */ + /* Retry the command once more */ + if (retry_cnt++ < 1) { + kfree(cmd_buf); + kfree(scsi_cmd); + kfree(sense_buf); + goto retry; + } + } + break; + default: + break; + } + } + } + + if (result) { + dev_err(dev, "%s: command failed, result=0x%x\n", + __func__, result); + rc = -EIO; + goto out; + } + + /* + * Read cap was successful, grab values from the buffer; + * note that we don't need to worry about unaligned access + * as the buffer is allocated on an aligned boundary. + */ + mutex_lock(&gli->mutex); + gli->max_lba = be64_to_cpu(*((u64 *)&cmd_buf[0])); + gli->blk_len = be32_to_cpu(*((u32 *)&cmd_buf[8])); + mutex_unlock(&gli->mutex); + +out: + kfree(cmd_buf); + kfree(scsi_cmd); + kfree(sense_buf); + + dev_dbg(dev, "%s: maxlba=%lld blklen=%d rc=%d\n", + __func__, gli->max_lba, gli->blk_len, rc); + return rc; +} + +/** + * get_rhte() - obtains validated resource handle table entry reference + * @ctxi: Context owning the resource handle. + * @rhndl: Resource handle associated with entry. + * @lli: LUN associated with request. + * + * Return: Validated RHTE on success, NULL on failure + */ +struct sisl_rht_entry *get_rhte(struct ctx_info *ctxi, res_hndl_t rhndl, + struct llun_info *lli) +{ + struct sisl_rht_entry *rhte = NULL; + + if (unlikely(!ctxi->rht_start)) { + pr_debug("%s: Context does not have allocated RHT!\n", + __func__); + goto out; + } + + if (unlikely(rhndl >= MAX_RHT_PER_CONTEXT)) { + pr_debug("%s: Bad resource handle! (%d)\n", __func__, rhndl); + goto out; + } + + if (unlikely(ctxi->rht_lun[rhndl] != lli)) { + pr_debug("%s: Bad resource handle LUN! (%d)\n", + __func__, rhndl); + goto out; + } + + rhte = &ctxi->rht_start[rhndl]; + if (unlikely(rhte->nmask == 0)) { + pr_debug("%s: Unopened resource handle! (%d)\n", + __func__, rhndl); + rhte = NULL; + goto out; + } + +out: + return rhte; +} + +/** + * rhte_checkout() - obtains free/empty resource handle table entry + * @ctxi: Context owning the resource handle. + * @lli: LUN associated with request. + * + * Return: Free RHTE on success, NULL on failure + */ +struct sisl_rht_entry *rhte_checkout(struct ctx_info *ctxi, + struct llun_info *lli) +{ + struct sisl_rht_entry *rhte = NULL; + int i; + + /* Find a free RHT entry */ + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) + if (ctxi->rht_start[i].nmask == 0) { + rhte = &ctxi->rht_start[i]; + ctxi->rht_out++; + break; + } + + if (likely(rhte)) + ctxi->rht_lun[i] = lli; + + pr_debug("%s: returning rhte=%p (%d)\n", __func__, rhte, i); + return rhte; +} + +/** + * rhte_checkin() - releases a resource handle table entry + * @ctxi: Context owning the resource handle. + * @rhte: RHTE to release. + */ +void rhte_checkin(struct ctx_info *ctxi, + struct sisl_rht_entry *rhte) +{ + u32 rsrc_handle = rhte - ctxi->rht_start; + + rhte->nmask = 0; + rhte->fp = 0; + ctxi->rht_out--; + ctxi->rht_lun[rsrc_handle] = NULL; +} + +/** + * rhte_format1() - populates a RHTE for format 1 + * @rhte: RHTE to populate. + * @lun_id: LUN ID of LUN associated with RHTE. + * @perm: Desired permissions for RHTE. + * @port_sel: Port selection mask + */ +static void rht_format1(struct sisl_rht_entry *rhte, u64 lun_id, u32 perm, + u32 port_sel) +{ + /* + * Populate the Format 1 RHT entry for direct access (physical + * LUN) using the synchronization sequence defined in the + * SISLite specification. + */ + struct sisl_rht_entry_f1 dummy = { 0 }; + struct sisl_rht_entry_f1 *rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; + + memset(rhte_f1, 0, sizeof(*rhte_f1)); + rhte_f1->fp = SISL_RHT_FP(1U, 0); + dma_wmb(); /* Make setting of format bit visible */ + + rhte_f1->lun_id = lun_id; + dma_wmb(); /* Make setting of LUN id visible */ + + /* + * Use a dummy RHT Format 1 entry to build the second dword + * of the entry that must be populated in a single write when + * enabled (valid bit set to TRUE). + */ + dummy.valid = 0x80; + dummy.fp = SISL_RHT_FP(1U, perm); + dummy.port_sel = port_sel; + rhte_f1->dw = dummy.dw; + + dma_wmb(); /* Make remaining RHT entry fields visible */ +} + +/** + * cxlflash_lun_attach() - attaches a user to a LUN and manages the LUN's mode + * @gli: LUN to attach. + * @mode: Desired mode of the LUN. + * @locked: Mutex status on current thread. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_lun_attach(struct glun_info *gli, enum lun_mode mode, bool locked) +{ + int rc = 0; + + if (!locked) + mutex_lock(&gli->mutex); + + if (gli->mode == MODE_NONE) + gli->mode = mode; + else if (gli->mode != mode) { + pr_debug("%s: LUN operating in mode %d, requested mode %d\n", + __func__, gli->mode, mode); + rc = -EINVAL; + goto out; + } + + gli->users++; + WARN_ON(gli->users <= 0); +out: + pr_debug("%s: Returning rc=%d gli->mode=%u gli->users=%u\n", + __func__, rc, gli->mode, gli->users); + if (!locked) + mutex_unlock(&gli->mutex); + return rc; +} + +/** + * cxlflash_lun_detach() - detaches a user from a LUN and resets the LUN's mode + * @gli: LUN to detach. + */ +void cxlflash_lun_detach(struct glun_info *gli) +{ + mutex_lock(&gli->mutex); + WARN_ON(gli->mode == MODE_NONE); + if (--gli->users == 0) + gli->mode = MODE_NONE; + pr_debug("%s: gli->users=%u\n", __func__, gli->users); + WARN_ON(gli->users < 0); + mutex_unlock(&gli->mutex); +} + +/** + * _cxlflash_disk_release() - releases the specified resource entry + * @sdev: SCSI device associated with LUN. + * @ctxi: Context owning resources. + * @release: Release ioctl data structure. + * + * Note that the AFU sync should _not_ be performed when the context is sitting + * on the error recovery list. A context on the error recovery list is not known + * to the AFU due to reset. When the context is recovered, it will be reattached + * and made known again to the AFU. + * + * Return: 0 on success, -errno on failure + */ +int _cxlflash_disk_release(struct scsi_device *sdev, + struct ctx_info *ctxi, + struct dk_cxlflash_release *release) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct afu *afu = cfg->afu; + bool put_ctx = false; + + res_hndl_t rhndl = release->rsrc_handle; + + int rc = 0; + u64 ctxid = DECODE_CTXID(release->context_id), + rctxid = release->context_id; + + struct sisl_rht_entry *rhte; + struct sisl_rht_entry_f1 *rhte_f1; + + dev_dbg(dev, "%s: ctxid=%llu rhndl=0x%llx gli->mode=%u gli->users=%u\n", + __func__, ctxid, release->rsrc_handle, gli->mode, gli->users); + + if (!ctxi) { + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", + __func__, ctxid); + rc = -EINVAL; + goto out; + } + + put_ctx = true; + } + + rhte = get_rhte(ctxi, rhndl, lli); + if (unlikely(!rhte)) { + dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + __func__, rhndl); + rc = -EINVAL; + goto out; + } + + switch (gli->mode) { + case MODE_PHYSICAL: + /* + * Clear the Format 1 RHT entry for direct access + * (physical LUN) using the synchronization sequence + * defined in the SISLite specification. + */ + rhte_f1 = (struct sisl_rht_entry_f1 *)rhte; + + rhte_f1->valid = 0; + dma_wmb(); /* Make revocation of RHT entry visible */ + + rhte_f1->lun_id = 0; + dma_wmb(); /* Make clearing of LUN id visible */ + + rhte_f1->dw = 0; + dma_wmb(); /* Make RHT entry bottom-half clearing visible */ + + if (!ctxi->err_recovery_active) + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); + break; + default: + WARN(1, "Unsupported LUN mode!"); + goto out; + } + + rhte_checkin(ctxi, rhte); + cxlflash_lun_detach(gli); + +out: + if (put_ctx) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +int cxlflash_disk_release(struct scsi_device *sdev, + struct dk_cxlflash_release *release) +{ + return _cxlflash_disk_release(sdev, NULL, release); +} + +/** + * destroy_context() - releases a context + * @cfg: Internal structure associated with the host. + * @ctxi: Context to release. + * + * Note that the rht_lun member of the context was cut from a single + * allocation when the context was created and therefore does not need + * to be explicitly freed. Also note that we conditionally check for the + * existence of the context control map before clearing the RHT registers + * and context capabilities because it is possible to destroy a context + * while the context is in the error state (previous mapping was removed + * [so we don't have to worry about clearing] and context is waiting for + * a new mapping). + */ +static void destroy_context(struct cxlflash_cfg *cfg, + struct ctx_info *ctxi) +{ + struct afu *afu = cfg->afu; + + WARN_ON(!list_empty(&ctxi->luns)); + + /* Clear RHT registers and drop all capabilities for this context */ + if (afu->afu_map && ctxi->ctrl_map) { + writeq_be(0, &ctxi->ctrl_map->rht_start); + writeq_be(0, &ctxi->ctrl_map->rht_cnt_id); + writeq_be(0, &ctxi->ctrl_map->ctx_cap); + } + + /* Free memory associated with context */ + free_page((ulong)ctxi->rht_start); + kfree(ctxi->rht_lun); + kfree(ctxi); + atomic_dec_if_positive(&cfg->num_user_contexts); +} + +/** + * create_context() - allocates and initializes a context + * @cfg: Internal structure associated with the host. + * @ctx: Previously obtained CXL context reference. + * @ctxid: Previously obtained process element associated with CXL context. + * @adap_fd: Previously obtained adapter fd associated with CXL context. + * @file: Previously obtained file associated with CXL context. + * @perms: User-specified permissions. + * + * The context's mutex is locked when an allocated context is returned. + * + * Return: Allocated context on success, NULL on failure + */ +static struct ctx_info *create_context(struct cxlflash_cfg *cfg, + struct cxl_context *ctx, int ctxid, + int adap_fd, struct file *file, + u32 perms) +{ + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct ctx_info *ctxi = NULL; + struct llun_info **lli = NULL; + struct sisl_rht_entry *rhte; + + ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); + lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); + if (unlikely(!ctxi || !lli)) { + dev_err(dev, "%s: Unable to allocate context!\n", __func__); + goto err; + } + + rhte = (struct sisl_rht_entry *)get_zeroed_page(GFP_KERNEL); + if (unlikely(!rhte)) { + dev_err(dev, "%s: Unable to allocate RHT!\n", __func__); + goto err; + } + + ctxi->rht_lun = lli; + ctxi->rht_start = rhte; + ctxi->rht_perms = perms; + + ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; + ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); + ctxi->lfd = adap_fd; + ctxi->pid = current->tgid; /* tgid = pid */ + ctxi->ctx = ctx; + ctxi->file = file; + mutex_init(&ctxi->mutex); + INIT_LIST_HEAD(&ctxi->luns); + INIT_LIST_HEAD(&ctxi->list); /* initialize for list_empty() */ + + atomic_inc(&cfg->num_user_contexts); + mutex_lock(&ctxi->mutex); +out: + return ctxi; + +err: + kfree(lli); + kfree(ctxi); + ctxi = NULL; + goto out; +} + +/** + * _cxlflash_disk_detach() - detaches a LUN from a context + * @sdev: SCSI device associated with LUN. + * @ctxi: Context owning resources. + * @detach: Detach ioctl data structure. + * + * As part of the detach, all per-context resources associated with the LUN + * are cleaned up. When detaching the last LUN for a context, the context + * itself is cleaned up and released. + * + * Return: 0 on success, -errno on failure + */ +static int _cxlflash_disk_detach(struct scsi_device *sdev, + struct ctx_info *ctxi, + struct dk_cxlflash_detach *detach) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct lun_access *lun_access, *t; + struct dk_cxlflash_release rel; + bool put_ctx = false; + + int i; + int rc = 0; + int lfd; + u64 ctxid = DECODE_CTXID(detach->context_id), + rctxid = detach->context_id; + + dev_dbg(dev, "%s: ctxid=%llu\n", __func__, ctxid); + + if (!ctxi) { + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", + __func__, ctxid); + rc = -EINVAL; + goto out; + } + + put_ctx = true; + } + + /* Cleanup outstanding resources tied to this LUN */ + if (ctxi->rht_out) { + marshal_det_to_rele(detach, &rel); + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { + if (ctxi->rht_lun[i] == lli) { + rel.rsrc_handle = i; + _cxlflash_disk_release(sdev, ctxi, &rel); + } + + /* No need to loop further if we're done */ + if (ctxi->rht_out == 0) + break; + } + } + + /* Take our LUN out of context, free the node */ + list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) + if (lun_access->lli == lli) { + list_del(&lun_access->list); + kfree(lun_access); + lun_access = NULL; + break; + } + + /* Tear down context following last LUN cleanup */ + if (list_empty(&ctxi->luns)) { + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + + /* Might not have been in error list so conditionally remove */ + if (!list_empty(&ctxi->list)) + list_del(&ctxi->list); + cfg->ctx_tbl[ctxid] = NULL; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + mutex_unlock(&ctxi->mutex); + + lfd = ctxi->lfd; + destroy_context(cfg, ctxi); + ctxi = NULL; + put_ctx = false; + + /* + * As a last step, clean up external resources when not + * already on an external cleanup thread, i.e.: close(adap_fd). + * + * NOTE: this will free up the context from the CXL services, + * allowing it to dole out the same context_id on a future + * (or even currently in-flight) disk_attach operation. + */ + if (lfd != -1) + sys_close(lfd); + } + +out: + if (put_ctx) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; +} + +static int cxlflash_disk_detach(struct scsi_device *sdev, + struct dk_cxlflash_detach *detach) +{ + return _cxlflash_disk_detach(sdev, NULL, detach); +} + +/** + * cxlflash_cxl_release() - release handler for adapter file descriptor + * @inode: File-system inode associated with fd. + * @file: File installed with adapter file descriptor. + * + * This routine is the release handler for the fops registered with + * the CXL services on an initial attach for a context. It is called + * when a close is performed on the adapter file descriptor returned + * to the user. Programmatically, the user is not required to perform + * the close, as it is handled internally via the detach ioctl when + * a context is being removed. Note that nothing prevents the user + * from performing a close, but the user should be aware that doing + * so is considered catastrophic and subsequent usage of the superpipe + * API with previously saved off tokens will fail. + * + * When initiated from an external close (either by the user or via + * a process tear down), the routine derives the context reference + * and calls detach for each LUN associated with the context. The + * final detach operation will cause the context itself to be freed. + * Note that the saved off lfd is reset prior to calling detach to + * signify that the final detach should not perform a close. + * + * When initiated from a detach operation as part of the tear down + * of a context, the context is first completely freed and then the + * close is performed. This routine will fail to derive the context + * reference (due to the context having already been freed) and then + * call into the CXL release entry point. + * + * Thus, with exception to when the CXL process element (context id) + * lookup fails (a case that should theoretically never occur), every + * call into this routine results in a complete freeing of a context. + * + * As part of the detach, all per-context resources associated with the LUN + * are cleaned up. When detaching the last LUN for a context, the context + * itself is cleaned up and released. + * + * Return: 0 on success + */ +static int cxlflash_cxl_release(struct inode *inode, struct file *file) +{ + struct cxl_context *ctx = cxl_fops_get_context(file); + struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, + cxl_fops); + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + struct dk_cxlflash_detach detach = { { 0 }, 0 }; + struct lun_access *lun_access, *t; + enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; + int ctxid; + + ctxid = cxl_process_element(ctx); + if (unlikely(ctxid < 0)) { + dev_err(dev, "%s: Context %p was closed! (%d)\n", + __func__, ctx, ctxid); + goto out; + } + + ctxi = get_context(cfg, ctxid, file, ctrl); + if (unlikely(!ctxi)) { + ctxi = get_context(cfg, ctxid, file, ctrl | CTX_CTRL_CLONE); + if (!ctxi) { + dev_dbg(dev, "%s: Context %d already free!\n", + __func__, ctxid); + goto out_release; + } + + dev_dbg(dev, "%s: Another process owns context %d!\n", + __func__, ctxid); + put_context(ctxi); + goto out; + } + + dev_dbg(dev, "%s: close(%d) for context %d\n", + __func__, ctxi->lfd, ctxid); + + /* Reset the file descriptor to indicate we're on a close() thread */ + ctxi->lfd = -1; + detach.context_id = ctxi->ctxid; + list_for_each_entry_safe(lun_access, t, &ctxi->luns, list) + _cxlflash_disk_detach(lun_access->sdev, ctxi, &detach); +out_release: + cxl_fd_release(inode, file); +out: + dev_dbg(dev, "%s: returning\n", __func__); + return 0; +} + +/** + * unmap_context() - clears a previously established mapping + * @ctxi: Context owning the mapping. + * + * This routine is used to switch between the error notification page + * (dummy page of all 1's) and the real mapping (established by the CXL + * fault handler). + */ +static void unmap_context(struct ctx_info *ctxi) +{ + unmap_mapping_range(ctxi->file->f_mapping, 0, 0, 1); +} + +/** + * get_err_page() - obtains and allocates the error notification page + * + * Return: error notification page on success, NULL on failure + */ +static struct page *get_err_page(void) +{ + struct page *err_page = global.err_page; + + if (unlikely(!err_page)) { + err_page = alloc_page(GFP_KERNEL); + if (unlikely(!err_page)) { + pr_err("%s: Unable to allocate err_page!\n", __func__); + goto out; + } + + memset(page_address(err_page), -1, PAGE_SIZE); + + /* Serialize update w/ other threads to avoid a leak */ + mutex_lock(&global.mutex); + if (likely(!global.err_page)) + global.err_page = err_page; + else { + __free_page(err_page); + err_page = global.err_page; + } + mutex_unlock(&global.mutex); + } + +out: + pr_debug("%s: returning err_page=%p\n", __func__, err_page); + return err_page; +} + +/** + * cxlflash_mmap_fault() - mmap fault handler for adapter file descriptor + * @vma: VM area associated with mapping. + * @vmf: VM fault associated with current fault. + * + * To support error notification via MMIO, faults are 'caught' by this routine + * that was inserted before passing back the adapter file descriptor on attach. + * When a fault occurs, this routine evaluates if error recovery is active and + * if so, installs the error page to 'notify' the user about the error state. + * During normal operation, the fault is simply handled by the original fault + * handler that was installed by CXL services as part of initializing the + * adapter file descriptor. The VMA's page protection bits are toggled to + * indicate cached/not-cached depending on the memory backing the fault. + * + * Return: 0 on success, VM_FAULT_SIGBUS on failure + */ +static int cxlflash_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct file *file = vma->vm_file; + struct cxl_context *ctx = cxl_fops_get_context(file); + struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, + cxl_fops); + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + struct page *err_page = NULL; + enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; + int rc = 0; + int ctxid; + + ctxid = cxl_process_element(ctx); + if (unlikely(ctxid < 0)) { + dev_err(dev, "%s: Context %p was closed! (%d)\n", + __func__, ctx, ctxid); + goto err; + } + + ctxi = get_context(cfg, ctxid, file, ctrl); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + goto err; + } + + dev_dbg(dev, "%s: fault(%d) for context %d\n", + __func__, ctxi->lfd, ctxid); + + if (likely(!ctxi->err_recovery_active)) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + rc = ctxi->cxl_mmap_vmops->fault(vma, vmf); + } else { + dev_dbg(dev, "%s: err recovery active, use err_page!\n", + __func__); + + err_page = get_err_page(); + if (unlikely(!err_page)) { + dev_err(dev, "%s: Could not obtain error page!\n", + __func__); + rc = VM_FAULT_RETRY; + goto out; + } + + get_page(err_page); + vmf->page = err_page; + vma->vm_page_prot = pgprot_cached(vma->vm_page_prot); + } + +out: + if (likely(ctxi)) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d\n", __func__, rc); + return rc; + +err: + rc = VM_FAULT_SIGBUS; + goto out; +} + +/* + * Local MMAP vmops to 'catch' faults + */ +static const struct vm_operations_struct cxlflash_mmap_vmops = { + .fault = cxlflash_mmap_fault, +}; + +/** + * cxlflash_cxl_mmap() - mmap handler for adapter file descriptor + * @file: File installed with adapter file descriptor. + * @vma: VM area associated with mapping. + * + * Installs local mmap vmops to 'catch' faults for error notification support. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_cxl_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct cxl_context *ctx = cxl_fops_get_context(file); + struct cxlflash_cfg *cfg = container_of(file->f_op, struct cxlflash_cfg, + cxl_fops); + struct device *dev = &cfg->dev->dev; + struct ctx_info *ctxi = NULL; + enum ctx_ctrl ctrl = CTX_CTRL_ERR_FALLBACK | CTX_CTRL_FILE; + int ctxid; + int rc = 0; + + ctxid = cxl_process_element(ctx); + if (unlikely(ctxid < 0)) { + dev_err(dev, "%s: Context %p was closed! (%d)\n", + __func__, ctx, ctxid); + rc = -EIO; + goto out; + } + + ctxi = get_context(cfg, ctxid, file, ctrl); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%d)\n", __func__, ctxid); + rc = -EIO; + goto out; + } + + dev_dbg(dev, "%s: mmap(%d) for context %d\n", + __func__, ctxi->lfd, ctxid); + + rc = cxl_fd_mmap(file, vma); + if (likely(!rc)) { + /* Insert ourself in the mmap fault handler path */ + ctxi->cxl_mmap_vmops = vma->vm_ops; + vma->vm_ops = &cxlflash_mmap_vmops; + } + +out: + if (likely(ctxi)) + put_context(ctxi); + return rc; +} + +/* + * Local fops for adapter file descriptor + */ +static const struct file_operations cxlflash_cxl_fops = { + .owner = THIS_MODULE, + .mmap = cxlflash_cxl_mmap, + .release = cxlflash_cxl_release, +}; + +/** + * cxlflash_mark_contexts_error() - move contexts to error state and list + * @cfg: Internal structure associated with the host. + * + * A context is only moved over to the error list when there are no outstanding + * references to it. This ensures that a running operation has completed. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_mark_contexts_error(struct cxlflash_cfg *cfg) +{ + int i, rc = 0; + struct ctx_info *ctxi = NULL; + + mutex_lock(&cfg->ctx_tbl_list_mutex); + + for (i = 0; i < MAX_CONTEXT; i++) { + ctxi = cfg->ctx_tbl[i]; + if (ctxi) { + mutex_lock(&ctxi->mutex); + cfg->ctx_tbl[i] = NULL; + list_add(&ctxi->list, &cfg->ctx_err_recovery); + ctxi->err_recovery_active = true; + ctxi->ctrl_map = NULL; + unmap_context(ctxi); + mutex_unlock(&ctxi->mutex); + } + } + + mutex_unlock(&cfg->ctx_tbl_list_mutex); + return rc; +} + +/* + * Dummy NULL fops + */ +static const struct file_operations null_fops = { + .owner = THIS_MODULE, +}; + +/** + * cxlflash_disk_attach() - attach a LUN to a context + * @sdev: SCSI device associated with LUN. + * @attach: Attach ioctl data structure. + * + * Creates a context and attaches LUN to it. A LUN can only be attached + * one time to a context (subsequent attaches for the same context/LUN pair + * are not supported). Additional LUNs can be attached to a context by + * specifying the 'reuse' flag defined in the cxlflash_ioctl.h header. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_disk_attach(struct scsi_device *sdev, + struct dk_cxlflash_attach *attach) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct cxl_ioctl_start_work *work; + struct ctx_info *ctxi = NULL; + struct lun_access *lun_access = NULL; + int rc = 0; + u32 perms; + int ctxid = -1; + u64 rctxid = 0UL; + struct file *file; + + struct cxl_context *ctx; + + int fd = -1; + + /* On first attach set fileops */ + if (atomic_read(&cfg->num_user_contexts) == 0) + cfg->cxl_fops = cxlflash_cxl_fops; + + if (attach->num_interrupts > 4) { + dev_dbg(dev, "%s: Cannot support this many interrupts %llu\n", + __func__, attach->num_interrupts); + rc = -EINVAL; + goto out; + } + + if (gli->max_lba == 0) { + dev_dbg(dev, "%s: No capacity info for this LUN (%016llX)\n", + __func__, lli->lun_id[sdev->channel]); + rc = read_cap16(sdev, lli); + if (rc) { + dev_err(dev, "%s: Invalid device! (%d)\n", + __func__, rc); + rc = -ENODEV; + goto out; + } + dev_dbg(dev, "%s: LBA = %016llX\n", __func__, gli->max_lba); + dev_dbg(dev, "%s: BLK_LEN = %08X\n", __func__, gli->blk_len); + } + + if (attach->hdr.flags & DK_CXLFLASH_ATTACH_REUSE_CONTEXT) { + rctxid = attach->context_id; + ctxi = get_context(cfg, rctxid, NULL, 0); + if (!ctxi) { + dev_dbg(dev, "%s: Bad context! (%016llX)\n", + __func__, rctxid); + rc = -EINVAL; + goto out; + } + + list_for_each_entry(lun_access, &ctxi->luns, list) + if (lun_access->lli == lli) { + dev_dbg(dev, "%s: Already attached!\n", + __func__); + rc = -EINVAL; + goto out; + } + } + + lun_access = kzalloc(sizeof(*lun_access), GFP_KERNEL); + if (unlikely(!lun_access)) { + dev_err(dev, "%s: Unable to allocate lun_access!\n", __func__); + rc = -ENOMEM; + goto out; + } + + lun_access->lli = lli; + lun_access->sdev = sdev; + + /* Non-NULL context indicates reuse */ + if (ctxi) { + dev_dbg(dev, "%s: Reusing context for LUN! (%016llX)\n", + __func__, rctxid); + list_add(&lun_access->list, &ctxi->luns); + fd = ctxi->lfd; + goto out_attach; + } + + ctx = cxl_dev_context_init(cfg->dev); + if (unlikely(IS_ERR_OR_NULL(ctx))) { + dev_err(dev, "%s: Could not initialize context %p\n", + __func__, ctx); + rc = -ENODEV; + goto err0; + } + + ctxid = cxl_process_element(ctx); + if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) { + dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + rc = -EPERM; + goto err1; + } + + file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); + if (unlikely(fd < 0)) { + rc = -ENODEV; + dev_err(dev, "%s: Could not get file descriptor\n", __func__); + goto err1; + } + + /* Translate read/write O_* flags from fcntl.h to AFU permission bits */ + perms = SISL_RHT_PERM(attach->hdr.flags + 1); + + ctxi = create_context(cfg, ctx, ctxid, fd, file, perms); + if (unlikely(!ctxi)) { + dev_err(dev, "%s: Failed to create context! (%d)\n", + __func__, ctxid); + goto err2; + } + + work = &ctxi->work; + work->num_interrupts = attach->num_interrupts; + work->flags = CXL_START_WORK_NUM_IRQS; + + rc = cxl_start_work(ctx, work); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Could not start context rc=%d\n", + __func__, rc); + goto err3; + } + + rc = afu_attach(cfg, ctxi); + if (unlikely(rc)) { + dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); + goto err4; + } + + /* + * No error paths after this point. Once the fd is installed it's + * visible to user space and can't be undone safely on this thread. + * There is no need to worry about a deadlock here because no one + * knows about us yet; we can be the only one holding our mutex. + */ + list_add(&lun_access->list, &ctxi->luns); + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + cfg->ctx_tbl[ctxid] = ctxi; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + fd_install(fd, file); + +out_attach: + attach->hdr.return_flags = 0; + attach->context_id = ctxi->ctxid; + attach->block_size = gli->blk_len; + attach->mmio_size = sizeof(afu->afu_map->hosts[0].harea); + attach->last_lba = gli->max_lba; + attach->max_xfer = (sdev->host->max_sectors * 512) / gli->blk_len; + +out: + attach->adap_fd = fd; + + if (ctxi) + put_context(ctxi); + + dev_dbg(dev, "%s: returning ctxid=%d fd=%d bs=%lld rc=%d llba=%lld\n", + __func__, ctxid, fd, attach->block_size, rc, attach->last_lba); + return rc; + +err4: + cxl_stop_context(ctx); +err3: + put_context(ctxi); + destroy_context(cfg, ctxi); + ctxi = NULL; +err2: + /* + * Here, we're overriding the fops with a dummy all-NULL fops because + * fput() calls the release fop, which will cause us to mistakenly + * call into the CXL code. Rather than try to add yet more complexity + * to that routine (cxlflash_cxl_release) we should try to fix the + * issue here. + */ + file->f_op = &null_fops; + fput(file); + put_unused_fd(fd); + fd = -1; +err1: + cxl_release_context(ctx); +err0: + kfree(lun_access); + goto out; +} + +/** + * recover_context() - recovers a context in error + * @cfg: Internal structure associated with the host. + * @ctxi: Context to release. + * + * Restablishes the state for a context-in-error. + * + * Return: 0 on success, -errno on failure + */ +static int recover_context(struct cxlflash_cfg *cfg, struct ctx_info *ctxi) +{ + struct device *dev = &cfg->dev->dev; + int rc = 0; + int old_fd, fd = -1; + int ctxid = -1; + struct file *file; + struct cxl_context *ctx; + struct afu *afu = cfg->afu; + + ctx = cxl_dev_context_init(cfg->dev); + if (unlikely(IS_ERR_OR_NULL(ctx))) { + dev_err(dev, "%s: Could not initialize context %p\n", + __func__, ctx); + rc = -ENODEV; + goto out; + } + + ctxid = cxl_process_element(ctx); + if (unlikely((ctxid > MAX_CONTEXT) || (ctxid < 0))) { + dev_err(dev, "%s: ctxid (%d) invalid!\n", __func__, ctxid); + rc = -EPERM; + goto err1; + } + + file = cxl_get_fd(ctx, &cfg->cxl_fops, &fd); + if (unlikely(fd < 0)) { + rc = -ENODEV; + dev_err(dev, "%s: Could not get file descriptor\n", __func__); + goto err1; + } + + rc = cxl_start_work(ctx, &ctxi->work); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Could not start context rc=%d\n", + __func__, rc); + goto err2; + } + + /* Update with new MMIO area based on updated context id */ + ctxi->ctrl_map = &afu->afu_map->ctrls[ctxid].ctrl; + + rc = afu_attach(cfg, ctxi); + if (rc) { + dev_err(dev, "%s: Could not attach AFU rc %d\n", __func__, rc); + goto err3; + } + + /* + * No error paths after this point. Once the fd is installed it's + * visible to user space and can't be undone safely on this thread. + */ + old_fd = ctxi->lfd; + ctxi->ctxid = ENCODE_CTXID(ctxi, ctxid); + ctxi->lfd = fd; + ctxi->ctx = ctx; + ctxi->file = file; + + /* + * Put context back in table (note the reinit of the context list); + * we must first drop the context's mutex and then acquire it in + * order with the table/list mutex to avoid a deadlock - safe to do + * here because no one can find us at this moment in time. + */ + mutex_unlock(&ctxi->mutex); + mutex_lock(&cfg->ctx_tbl_list_mutex); + mutex_lock(&ctxi->mutex); + list_del_init(&ctxi->list); + cfg->ctx_tbl[ctxid] = ctxi; + mutex_unlock(&cfg->ctx_tbl_list_mutex); + fd_install(fd, file); + + /* Release the original adapter fd and associated CXL resources */ + sys_close(old_fd); +out: + dev_dbg(dev, "%s: returning ctxid=%d fd=%d rc=%d\n", + __func__, ctxid, fd, rc); + return rc; + +err3: + cxl_stop_context(ctx); +err2: + fput(file); + put_unused_fd(fd); +err1: + cxl_release_context(ctx); + goto out; +} + +/** + * check_state() - checks and responds to the current adapter state + * @cfg: Internal structure associated with the host. + * + * This routine can block and should only be used on process context. + * Note that when waking up from waiting in limbo, the state is unknown + * and must be checked again before proceeding. + * + * Return: 0 on success, -errno on failure + */ +static int check_state(struct cxlflash_cfg *cfg) +{ + struct device *dev = &cfg->dev->dev; + int rc = 0; + +retry: + switch (cfg->state) { + case STATE_LIMBO: + dev_dbg(dev, "%s: Limbo, going to wait...\n", __func__); + rc = wait_event_interruptible(cfg->limbo_waitq, + cfg->state != STATE_LIMBO); + if (unlikely(rc)) + break; + goto retry; + case STATE_FAILTERM: + dev_dbg(dev, "%s: Failed/Terminating!\n", __func__); + rc = -ENODEV; + break; + default: + break; + } + + return rc; +} + +/** + * cxlflash_afu_recover() - initiates AFU recovery + * @sdev: SCSI device associated with LUN. + * @recover: Recover ioctl data structure. + * + * Only a single recovery is allowed at a time to avoid exhausting CXL + * resources (leading to recovery failure) in the event that we're up + * against the maximum number of contexts limit. For similar reasons, + * a context recovery is retried if there are multiple recoveries taking + * place at the same time and the failure was due to CXL services being + * unable to keep up. + * + * Because a user can detect an error condition before the kernel, it is + * quite possible for this routine to act as the kernel's EEH detection + * source (MMIO read of mbox_r). Because of this, there is a window of + * time where an EEH might have been detected but not yet 'serviced' + * (callback invoked, causing the device to enter limbo state). To avoid + * looping in this routine during that window, a 1 second sleep is in place + * between the time the MMIO failure is detected and the time a wait on the + * limbo wait queue is attempted via check_state(). + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_afu_recover(struct scsi_device *sdev, + struct dk_cxlflash_recover_afu *recover) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct afu *afu = cfg->afu; + struct ctx_info *ctxi = NULL; + struct mutex *mutex = &cfg->ctx_recovery_mutex; + u64 ctxid = DECODE_CTXID(recover->context_id), + rctxid = recover->context_id; + long reg; + int lretry = 20; /* up to 2 seconds */ + int rc = 0; + + atomic_inc(&cfg->recovery_threads); + rc = mutex_lock_interruptible(mutex); + if (rc) + goto out; + + dev_dbg(dev, "%s: reason 0x%016llX rctxid=%016llX\n", + __func__, recover->reason, rctxid); + +retry: + /* Ensure that this process is attached to the context */ + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto out; + } + + if (ctxi->err_recovery_active) { +retry_recover: + rc = recover_context(cfg, ctxi); + if (unlikely(rc)) { + dev_err(dev, "%s: Recovery failed for context %llu (rc=%d)\n", + __func__, ctxid, rc); + if ((rc == -ENODEV) && + ((atomic_read(&cfg->recovery_threads) > 1) || + (lretry--))) { + dev_dbg(dev, "%s: Going to try again!\n", + __func__); + mutex_unlock(mutex); + msleep(100); + rc = mutex_lock_interruptible(mutex); + if (rc) + goto out; + goto retry_recover; + } + + goto out; + } + + ctxi->err_recovery_active = false; + recover->context_id = ctxi->ctxid; + recover->adap_fd = ctxi->lfd; + recover->mmio_size = sizeof(afu->afu_map->hosts[0].harea); + recover->hdr.return_flags |= + DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET; + goto out; + } + + /* Test if in error state */ + reg = readq_be(&afu->ctrl_map->mbox_r); + if (reg == -1) { + dev_dbg(dev, "%s: MMIO read fail! Wait for recovery...\n", + __func__); + mutex_unlock(&ctxi->mutex); + ctxi = NULL; + ssleep(1); + rc = check_state(cfg); + if (unlikely(rc)) + goto out; + goto retry; + } + + dev_dbg(dev, "%s: MMIO working, no recovery required!\n", __func__); +out: + if (likely(ctxi)) + put_context(ctxi); + mutex_unlock(mutex); + atomic_dec_if_positive(&cfg->recovery_threads); + return rc; +} + +/** + * process_sense() - evaluates and processes sense data + * @sdev: SCSI device associated with LUN. + * @verify: Verify ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +static int process_sense(struct scsi_device *sdev, + struct dk_cxlflash_verify *verify) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + u64 prev_lba = gli->max_lba; + struct scsi_sense_hdr sshdr = { 0 }; + int rc = 0; + + rc = scsi_normalize_sense((const u8 *)&verify->sense_data, + DK_CXLFLASH_VERIFY_SENSE_LEN, &sshdr); + if (!rc) { + dev_err(dev, "%s: Failed to normalize sense data!\n", __func__); + rc = -EINVAL; + goto out; + } + + switch (sshdr.sense_key) { + case NO_SENSE: + case RECOVERED_ERROR: + /* fall through */ + case NOT_READY: + break; + case UNIT_ATTENTION: + switch (sshdr.asc) { + case 0x29: /* Power on Reset or Device Reset */ + /* fall through */ + case 0x2A: /* Device settings/capacity changed */ + rc = read_cap16(sdev, lli); + if (rc) { + rc = -ENODEV; + break; + } + if (prev_lba != gli->max_lba) + dev_dbg(dev, "%s: Capacity changed old=%lld " + "new=%lld\n", __func__, prev_lba, + gli->max_lba); + break; + case 0x3F: /* Report LUNs changed, Rescan. */ + scsi_scan_host(cfg->host); + break; + default: + rc = -EIO; + break; + } + break; + default: + rc = -EIO; + break; + } +out: + dev_dbg(dev, "%s: sense_key %x asc %x ascq %x rc %d\n", __func__, + sshdr.sense_key, sshdr.asc, sshdr.ascq, rc); + return rc; +} + +/** + * cxlflash_disk_verify() - verifies a LUN is the same and handle size changes + * @sdev: SCSI device associated with LUN. + * @verify: Verify ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_disk_verify(struct scsi_device *sdev, + struct dk_cxlflash_verify *verify) +{ + int rc = 0; + struct ctx_info *ctxi = NULL; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct sisl_rht_entry *rhte = NULL; + res_hndl_t rhndl = verify->rsrc_handle; + u64 ctxid = DECODE_CTXID(verify->context_id), + rctxid = verify->context_id; + u64 last_lba = 0; + + dev_dbg(dev, "%s: ctxid=%llu rhndl=%016llX, hint=%016llX, " + "flags=%016llX\n", __func__, ctxid, verify->rsrc_handle, + verify->hint, verify->hdr.flags); + + ctxi = get_context(cfg, rctxid, lli, 0); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto out; + } + + rhte = get_rhte(ctxi, rhndl, lli); + if (unlikely(!rhte)) { + dev_dbg(dev, "%s: Bad resource handle! (%d)\n", + __func__, rhndl); + rc = -EINVAL; + goto out; + } + + /* + * Look at the hint/sense to see if it requires us to redrive + * inquiry (i.e. the Unit attention is due to the WWN changing). + */ + if (verify->hint & DK_CXLFLASH_VERIFY_HINT_SENSE) { + rc = process_sense(sdev, verify); + if (unlikely(rc)) { + dev_err(dev, "%s: Failed to validate sense data (%d)\n", + __func__, rc); + goto out; + } + } + + switch (gli->mode) { + case MODE_PHYSICAL: + last_lba = gli->max_lba; + break; + default: + WARN(1, "Unsupported LUN mode!"); + } + + verify->last_lba = last_lba; + +out: + if (likely(ctxi)) + put_context(ctxi); + dev_dbg(dev, "%s: returning rc=%d llba=%llX\n", + __func__, rc, verify->last_lba); + return rc; +} + +/** + * decode_ioctl() - translates an encoded ioctl to an easily identifiable string + * @cmd: The ioctl command to decode. + * + * Return: A string identifying the decoded ioctl. + */ +static char *decode_ioctl(int cmd) +{ + switch (cmd) { + case DK_CXLFLASH_ATTACH: + return __stringify_1(DK_CXLFLASH_ATTACH); + case DK_CXLFLASH_USER_DIRECT: + return __stringify_1(DK_CXLFLASH_USER_DIRECT); + case DK_CXLFLASH_RELEASE: + return __stringify_1(DK_CXLFLASH_RELEASE); + case DK_CXLFLASH_DETACH: + return __stringify_1(DK_CXLFLASH_DETACH); + case DK_CXLFLASH_VERIFY: + return __stringify_1(DK_CXLFLASH_VERIFY); + case DK_CXLFLASH_RECOVER_AFU: + return __stringify_1(DK_CXLFLASH_RECOVER_AFU); + case DK_CXLFLASH_MANAGE_LUN: + return __stringify_1(DK_CXLFLASH_MANAGE_LUN); + } + + return "UNKNOWN"; +} + +/** + * cxlflash_disk_direct_open() - opens a direct (physical) disk + * @sdev: SCSI device associated with LUN. + * @arg: UDirect ioctl data structure. + * + * On successful return, the user is informed of the resource handle + * to be used to identify the direct lun and the size (in blocks) of + * the direct lun in last LBA format. + * + * Return: 0 on success, -errno on failure + */ +static int cxlflash_disk_direct_open(struct scsi_device *sdev, void *arg) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + + struct dk_cxlflash_udirect *pphys = (struct dk_cxlflash_udirect *)arg; + + u64 ctxid = DECODE_CTXID(pphys->context_id), + rctxid = pphys->context_id; + u64 lun_size = 0; + u64 last_lba = 0; + u64 rsrc_handle = -1; + u32 port = CHAN2PORT(sdev->channel); + + int rc = 0; + + struct ctx_info *ctxi = NULL; + struct sisl_rht_entry *rhte = NULL; + + pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + + rc = cxlflash_lun_attach(gli, MODE_PHYSICAL, false); + if (unlikely(rc)) { + dev_dbg(dev, "%s: Failed to attach to LUN! (PHYSICAL)\n", + __func__); + goto out; + } + + ctxi = get_context(cfg, rctxid, lli, 0); + if (unlikely(!ctxi)) { + dev_dbg(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto err1; + } + + rhte = rhte_checkout(ctxi, lli); + if (unlikely(!rhte)) { + dev_dbg(dev, "%s: too many opens for this context\n", __func__); + rc = -EMFILE; /* too many opens */ + goto err1; + } + + rsrc_handle = (rhte - ctxi->rht_start); + + rht_format1(rhte, lli->lun_id[sdev->channel], ctxi->rht_perms, port); + cxlflash_afu_sync(afu, ctxid, rsrc_handle, AFU_LW_SYNC); + + last_lba = gli->max_lba; + pphys->hdr.return_flags = 0; + pphys->last_lba = last_lba; + pphys->rsrc_handle = rsrc_handle; + +out: + if (likely(ctxi)) + put_context(ctxi); + dev_dbg(dev, "%s: returning handle 0x%llx rc=%d llba %lld\n", + __func__, rsrc_handle, rc, last_lba); + return rc; + +err1: + cxlflash_lun_detach(gli); + goto out; +} + +/** + * ioctl_common() - common IOCTL handler for driver + * @sdev: SCSI device associated with LUN. + * @cmd: IOCTL command. + * + * Handles common fencing operations that are valid for multiple ioctls. Always + * allow through ioctls that are cleanup oriented in nature, even when operating + * in a failed/terminating state. + * + * Return: 0 on success, -errno on failure + */ +static int ioctl_common(struct scsi_device *sdev, int cmd) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + int rc = 0; + + if (unlikely(!lli)) { + dev_dbg(dev, "%s: Unknown LUN\n", __func__); + rc = -EINVAL; + goto out; + } + + rc = check_state(cfg); + if (unlikely(rc) && (cfg->state == STATE_FAILTERM)) { + switch (cmd) { + case DK_CXLFLASH_RELEASE: + case DK_CXLFLASH_DETACH: + dev_dbg(dev, "%s: Command override! (%d)\n", + __func__, rc); + rc = 0; + break; + } + } +out: + return rc; +} + +/** + * cxlflash_ioctl() - IOCTL handler for driver + * @sdev: SCSI device associated with LUN. + * @cmd: IOCTL command. + * @arg: Userspace ioctl data structure. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) +{ + typedef int (*sioctl) (struct scsi_device *, void *); + + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct afu *afu = cfg->afu; + struct dk_cxlflash_hdr *hdr; + char buf[sizeof(union cxlflash_ioctls)]; + size_t size = 0; + bool known_ioctl = false; + int idx; + int rc = 0; + struct Scsi_Host *shost = sdev->host; + sioctl do_ioctl = NULL; + + static const struct { + size_t size; + sioctl ioctl; + } ioctl_tbl[] = { /* NOTE: order matters here */ + {sizeof(struct dk_cxlflash_attach), (sioctl)cxlflash_disk_attach}, + {sizeof(struct dk_cxlflash_udirect), cxlflash_disk_direct_open}, + {sizeof(struct dk_cxlflash_release), (sioctl)cxlflash_disk_release}, + {sizeof(struct dk_cxlflash_detach), (sioctl)cxlflash_disk_detach}, + {sizeof(struct dk_cxlflash_verify), (sioctl)cxlflash_disk_verify}, + {sizeof(struct dk_cxlflash_recover_afu), (sioctl)cxlflash_afu_recover}, + {sizeof(struct dk_cxlflash_manage_lun), (sioctl)cxlflash_manage_lun}, + }; + + /* Restrict command set to physical support only for internal LUN */ + if (afu->internal_lun) + switch (cmd) { + case DK_CXLFLASH_RELEASE: + dev_dbg(dev, "%s: %s not supported for lun_mode=%d\n", + __func__, decode_ioctl(cmd), afu->internal_lun); + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + switch (cmd) { + case DK_CXLFLASH_ATTACH: + case DK_CXLFLASH_USER_DIRECT: + case DK_CXLFLASH_RELEASE: + case DK_CXLFLASH_DETACH: + case DK_CXLFLASH_VERIFY: + case DK_CXLFLASH_RECOVER_AFU: + dev_dbg(dev, "%s: %s (%08X) on dev(%d/%d/%d/%llu)\n", + __func__, decode_ioctl(cmd), cmd, shost->host_no, + sdev->channel, sdev->id, sdev->lun); + rc = ioctl_common(sdev, cmd); + if (unlikely(rc)) + goto cxlflash_ioctl_exit; + + /* fall through */ + + case DK_CXLFLASH_MANAGE_LUN: + known_ioctl = true; + idx = _IOC_NR(cmd) - _IOC_NR(DK_CXLFLASH_ATTACH); + size = ioctl_tbl[idx].size; + do_ioctl = ioctl_tbl[idx].ioctl; + + if (likely(do_ioctl)) + break; + + /* fall through */ + default: + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + if (unlikely(copy_from_user(&buf, arg, size))) { + dev_err(dev, "%s: copy_from_user() fail! " + "size=%lu cmd=%d (%s) arg=%p\n", + __func__, size, cmd, decode_ioctl(cmd), arg); + rc = -EFAULT; + goto cxlflash_ioctl_exit; + } + + hdr = (struct dk_cxlflash_hdr *)&buf; + if (hdr->version != DK_CXLFLASH_VERSION_0) { + dev_dbg(dev, "%s: Version %u not supported for %s\n", + __func__, hdr->version, decode_ioctl(cmd)); + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + if (hdr->rsvd[0] || hdr->rsvd[1] || hdr->rsvd[2] || hdr->return_flags) { + dev_dbg(dev, "%s: Reserved/rflags populated!\n", __func__); + rc = -EINVAL; + goto cxlflash_ioctl_exit; + } + + rc = do_ioctl(sdev, (void *)&buf); + if (likely(!rc)) + if (unlikely(copy_to_user(arg, &buf, size))) { + dev_err(dev, "%s: copy_to_user() fail! " + "size=%lu cmd=%d (%s) arg=%p\n", + __func__, size, cmd, decode_ioctl(cmd), arg); + rc = -EFAULT; + } + + /* fall through to exit */ + +cxlflash_ioctl_exit: + if (unlikely(rc && known_ioctl)) + dev_err(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " + "returned rc %d\n", __func__, + decode_ioctl(cmd), cmd, shost->host_no, + sdev->channel, sdev->id, sdev->lun, rc); + else + dev_dbg(dev, "%s: ioctl %s (%08X) on dev(%d/%d/%d/%llu) " + "returned rc %d\n", __func__, decode_ioctl(cmd), + cmd, shost->host_no, sdev->channel, sdev->id, + sdev->lun, rc); + return rc; +} diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h new file mode 100644 index 0000000000000..ae39b9627118c --- /dev/null +++ b/drivers/scsi/cxlflash/superpipe.h @@ -0,0 +1,132 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * 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 _CXLFLASH_SUPERPIPE_H +#define _CXLFLASH_SUPERPIPE_H + +extern struct cxlflash_global global; + +/* + * Terminology: use afu (and not adapter) to refer to the HW. + * Adapter is the entire slot and includes PSL out of which + * only the AFU is visible to user space. + */ + +/* Chunk size parms: note sislite minimum chunk size is + 0x10000 LBAs corresponding to a NMASK or 16. +*/ +#define MC_CHUNK_SIZE (1 << MC_RHT_NMASK) /* in LBAs */ + +#define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ + +#define CHAN2PORT(_x) ((_x) + 1) + +enum lun_mode { + MODE_NONE = 0, + MODE_PHYSICAL +}; + +/* Global (entire driver, spans adapters) lun_info structure */ +struct glun_info { + u64 max_lba; /* from read cap(16) */ + u32 blk_len; /* from read cap(16) */ + enum lun_mode mode; /* NONE, PHYSICAL */ + int users; /* Number of users w/ references to LUN */ + + u8 wwid[16]; + + struct mutex mutex; + + struct list_head list; +}; + +/* Local (per-adapter) lun_info structure */ +struct llun_info { + u64 lun_id[CXLFLASH_NUM_FC_PORTS]; /* from REPORT_LUNS */ + u32 lun_index; /* Index in the LUN table */ + u32 host_no; /* host_no from Scsi_host */ + u32 port_sel; /* What port to use for this LUN */ + bool newly_created; /* Whether the LUN was just discovered */ + + u8 wwid[16]; /* Keep a duplicate copy here? */ + + struct glun_info *parent; /* Pointer to entry in global LUN structure */ + struct scsi_device *sdev; + struct list_head list; +}; + +struct lun_access { + struct llun_info *lli; + struct scsi_device *sdev; + struct list_head list; +}; + +enum ctx_ctrl { + CTX_CTRL_CLONE = (1 << 1), + CTX_CTRL_ERR = (1 << 2), + CTX_CTRL_ERR_FALLBACK = (1 << 3), + CTX_CTRL_NOPID = (1 << 4), + CTX_CTRL_FILE = (1 << 5) +}; + +#define ENCODE_CTXID(_ctx, _id) (((((u64)_ctx) & 0xFFFFFFFF0) << 28) | _id) +#define DECODE_CTXID(_val) (_val & 0xFFFFFFFF) + +struct ctx_info { + struct sisl_ctrl_map *ctrl_map; /* initialized at startup */ + struct sisl_rht_entry *rht_start; /* 1 page (req'd for alignment), + alloc/free on attach/detach */ + u32 rht_out; /* Number of checked out RHT entries */ + u32 rht_perms; /* User-defined permissions for RHT entries */ + struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ + + struct cxl_ioctl_start_work work; + u64 ctxid; + int lfd; + pid_t pid; + bool unavail; + bool err_recovery_active; + struct mutex mutex; /* Context protection */ + struct cxl_context *ctx; + struct list_head luns; /* LUNs attached to this context */ + const struct vm_operations_struct *cxl_mmap_vmops; + struct file *file; + struct list_head list; /* Link contexts in error recovery */ +}; + +struct cxlflash_global { + struct mutex mutex; + struct list_head gluns;/* list of glun_info structs */ + struct page *err_page; /* One page of all 0xF for error notification */ +}; + +int cxlflash_disk_release(struct scsi_device *, struct dk_cxlflash_release *); +int _cxlflash_disk_release(struct scsi_device *, struct ctx_info *, + struct dk_cxlflash_release *); + +int cxlflash_lun_attach(struct glun_info *, enum lun_mode, bool); +void cxlflash_lun_detach(struct glun_info *); + +struct ctx_info *get_context(struct cxlflash_cfg *, u64, void *, enum ctx_ctrl); +void put_context(struct ctx_info *); + +struct sisl_rht_entry *get_rhte(struct ctx_info *, res_hndl_t, + struct llun_info *); + +struct sisl_rht_entry *rhte_checkout(struct ctx_info *, struct llun_info *); +void rhte_checkin(struct ctx_info *, struct sisl_rht_entry *); + +int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); + +#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/include/uapi/scsi/Kbuild b/include/uapi/scsi/Kbuild index 75746d52f208b..d791e0ad509d3 100644 --- a/include/uapi/scsi/Kbuild +++ b/include/uapi/scsi/Kbuild @@ -3,3 +3,4 @@ header-y += fc/ header-y += scsi_bsg_fc.h header-y += scsi_netlink.h header-y += scsi_netlink_fc.h +header-y += cxlflash_ioctl.h diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h new file mode 100644 index 0000000000000..5707734065310 --- /dev/null +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -0,0 +1,140 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * 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 _CXLFLASH_IOCTL_H +#define _CXLFLASH_IOCTL_H + +#include + +/* + * Structure and flag definitions CXL Flash superpipe ioctls + */ + +#define DK_CXLFLASH_VERSION_0 0 + +struct dk_cxlflash_hdr { + __u16 version; /* Version data */ + __u16 rsvd[3]; /* Reserved for future use */ + __u64 flags; /* Input flags */ + __u64 return_flags; /* Returned flags */ +}; + +/* + * Notes: + * ----- + * The 'context_id' field of all ioctl structures contains the context + * identifier for a context in the lower 32-bits (upper 32-bits are not + * to be used when identifying a context to the AFU). That said, the value + * in its entirety (all 64-bits) is to be treated as an opaque cookie and + * should be presented as such when issuing ioctls. + * + * For DK_CXLFLASH_ATTACH ioctl, user specifies read/write access + * permissions via the O_RDONLY, O_WRONLY, and O_RDWR flags defined in + * the fcntl.h header file. + */ +#define DK_CXLFLASH_ATTACH_REUSE_CONTEXT 0x8000000000000000ULL + +struct dk_cxlflash_attach { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 num_interrupts; /* Requested number of interrupts */ + __u64 context_id; /* Returned context */ + __u64 mmio_size; /* Returned size of MMIO area */ + __u64 block_size; /* Returned block size, in bytes */ + __u64 adap_fd; /* Returned adapter file descriptor */ + __u64 last_lba; /* Returned last LBA on the device */ + __u64 max_xfer; /* Returned max transfer size, blocks */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_detach { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context to detach */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_udirect { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context to own physical resources */ + __u64 rsrc_handle; /* Returned resource handle */ + __u64 last_lba; /* Returned last LBA on the device */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_release { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context owning resources */ + __u64 rsrc_handle; /* Resource handle to release */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +#define DK_CXLFLASH_VERIFY_SENSE_LEN 18 +#define DK_CXLFLASH_VERIFY_HINT_SENSE 0x8000000000000000ULL + +struct dk_cxlflash_verify { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context owning resources to verify */ + __u64 rsrc_handle; /* Resource handle of LUN */ + __u64 hint; /* Reasons for verify */ + __u64 last_lba; /* Returned last LBA of device */ + __u8 sense_data[DK_CXLFLASH_VERIFY_SENSE_LEN]; /* SCSI sense data */ + __u8 pad[6]; /* Pad to next 8-byte boundary */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +#define DK_CXLFLASH_RECOVER_AFU_CONTEXT_RESET 0x8000000000000000ULL + +struct dk_cxlflash_recover_afu { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 reason; /* Reason for recovery request */ + __u64 context_id; /* Context to recover / updated ID */ + __u64 mmio_size; /* Returned size of MMIO area */ + __u64 adap_fd; /* Returned adapter file descriptor */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +#define DK_CXLFLASH_MANAGE_LUN_WWID_LEN 16 +#define DK_CXLFLASH_MANAGE_LUN_ENABLE_SUPERPIPE 0x8000000000000000ULL +#define DK_CXLFLASH_MANAGE_LUN_DISABLE_SUPERPIPE 0x4000000000000000ULL +#define DK_CXLFLASH_MANAGE_LUN_ALL_PORTS_ACCESSIBLE 0x2000000000000000ULL + +struct dk_cxlflash_manage_lun { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u8 wwid[DK_CXLFLASH_MANAGE_LUN_WWID_LEN]; /* Page83 WWID, NAA-6 */ + __u64 reserved[8]; /* Rsvd, future use */ +}; + +union cxlflash_ioctls { + struct dk_cxlflash_attach attach; + struct dk_cxlflash_detach detach; + struct dk_cxlflash_udirect udirect; + struct dk_cxlflash_release release; + struct dk_cxlflash_verify verify; + struct dk_cxlflash_recover_afu recover_afu; + struct dk_cxlflash_manage_lun manage_lun; +}; + +#define MAX_CXLFLASH_IOCTL_SZ (sizeof(union cxlflash_ioctls)) + +#define CXL_MAGIC 0xCA +#define CXL_IOWR(_n, _s) _IOWR(CXL_MAGIC, _n, struct _s) + +#define DK_CXLFLASH_ATTACH CXL_IOWR(0x80, dk_cxlflash_attach) +#define DK_CXLFLASH_USER_DIRECT CXL_IOWR(0x81, dk_cxlflash_udirect) +#define DK_CXLFLASH_RELEASE CXL_IOWR(0x82, dk_cxlflash_release) +#define DK_CXLFLASH_DETACH CXL_IOWR(0x83, dk_cxlflash_detach) +#define DK_CXLFLASH_VERIFY CXL_IOWR(0x84, dk_cxlflash_verify) +#define DK_CXLFLASH_RECOVER_AFU CXL_IOWR(0x85, dk_cxlflash_recover_afu) +#define DK_CXLFLASH_MANAGE_LUN CXL_IOWR(0x86, dk_cxlflash_manage_lun) + +#endif /* ifndef _CXLFLASH_IOCTL_H */ -- GitLab From 2cb79266d6b229dbebd31fe114af1bdab25c8076 Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Thu, 13 Aug 2015 21:47:53 -0500 Subject: [PATCH 5090/7006] cxlflash: Virtual LUN support Add support for physical LUN segmentation (virtual LUNs) to device driver supporting the IBM CXL Flash adapter. This patch allows user space applications to virtually segment a physical LUN into N virtual LUNs, taking advantage of the translation features provided by this adapter. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reviewed-by: Michael Neuling Reviewed-by: Wen Xiong Signed-off-by: James Bottomley --- Documentation/powerpc/cxlflash.txt | 63 +- drivers/scsi/cxlflash/Makefile | 2 +- drivers/scsi/cxlflash/common.h | 4 + drivers/scsi/cxlflash/lunmgt.c | 3 + drivers/scsi/cxlflash/main.c | 13 + drivers/scsi/cxlflash/sislite.h | 20 +- drivers/scsi/cxlflash/superpipe.c | 82 +- drivers/scsi/cxlflash/superpipe.h | 17 +- drivers/scsi/cxlflash/vlun.c | 1243 ++++++++++++++++++++++++++++ drivers/scsi/cxlflash/vlun.h | 86 ++ include/uapi/scsi/cxlflash_ioctl.h | 34 + 11 files changed, 1550 insertions(+), 17 deletions(-) create mode 100644 drivers/scsi/cxlflash/vlun.c create mode 100644 drivers/scsi/cxlflash/vlun.h diff --git a/Documentation/powerpc/cxlflash.txt b/Documentation/powerpc/cxlflash.txt index f943967f90ce0..4202d1bc583c5 100644 --- a/Documentation/powerpc/cxlflash.txt +++ b/Documentation/powerpc/cxlflash.txt @@ -163,7 +163,8 @@ DK_CXLFLASH_ATTACH - These tokens are only valid for the process under which they were created. The child of a forked process cannot continue - to use the context id or file descriptor created by its parent. + to use the context id or file descriptor created by its parent + (see DK_CXLFLASH_VLUN_CLONE for further details). - These tokens are only valid for the lifetime of the context and the process under which they were created. Once either is @@ -193,6 +194,45 @@ DK_CXLFLASH_USER_DIRECT treated as a resource handle that is returned to the user. The user is then able to use the handle to reference the LUN during I/O. +DK_CXLFLASH_USER_VIRTUAL +------------------------ + This ioctl is responsible for transitioning the LUN to virtual mode + of access and configuring the AFU for virtual access from user space + on a per-context basis. Additionally, the block size and last logical + block address (LBA) are returned to the user. + + As mentioned previously, when operating in user space access mode, + LUNs may be accessed in whole or in part. Only one mode is allowed + at a time and if one mode is active (outstanding references exist), + requests to use the LUN in a different mode are denied. + + The AFU is configured for virtual access from user space by adding + an entry to the AFU's resource handle table. The index of the entry + is treated as a resource handle that is returned to the user. The + user is then able to use the handle to reference the LUN during I/O. + + By default, the virtual LUN is created with a size of 0. The user + would need to use the DK_CXLFLASH_VLUN_RESIZE ioctl to adjust the grow + the virtual LUN to a desired size. To avoid having to perform this + resize for the initial creation of the virtual LUN, the user has the + option of specifying a size as part of the DK_CXLFLASH_USER_VIRTUAL + ioctl, such that when success is returned to the user, the + resource handle that is provided is already referencing provisioned + storage. This is reflected by the last LBA being a non-zero value. + +DK_CXLFLASH_VLUN_RESIZE +----------------------- + This ioctl is responsible for resizing a previously created virtual + LUN and will fail if invoked upon a LUN that is not in virtual + mode. Upon success, an updated last LBA is returned to the user + indicating the new size of the virtual LUN associated with the + resource handle. + + The partitioning of virtual LUNs is jointly mediated by the cxlflash + driver and the AFU. An allocation table is kept for each LUN that is + operating in the virtual mode and used to program a LUN translation + table that the AFU references when provided with a resource handle. + DK_CXLFLASH_RELEASE ------------------- This ioctl is responsible for releasing a previously obtained @@ -214,6 +254,27 @@ DK_CXLFLASH_DETACH success, all "tokens" which had been provided to the user from the DK_CXLFLASH_ATTACH onward are no longer valid. +DK_CXLFLASH_VLUN_CLONE +---------------------- + This ioctl is responsible for cloning a previously created + context to a more recently created context. It exists solely to + support maintaining user space access to storage after a process + forks. Upon success, the child process (which invoked the ioctl) + will have access to the same LUNs via the same resource handle(s) + and fd2 as the parent, but under a different context. + + Context sharing across processes is not supported with CXL and + therefore each fork must be met with establishing a new context + for the child process. This ioctl simplifies the state management + and playback required by a user in such a scenario. When a process + forks, child process can clone the parents context by first creating + a context (via DK_CXLFLASH_ATTACH) and then using this ioctl to + perform the clone from the parent to the child. + + The clone itself is fairly simple. The resource handle and lun + translation tables are copied from the parent context to the child's + and then synced with the AFU. + DK_CXLFLASH_VERIFY ------------------ This ioctl is used to detect various changes such as the capacity of diff --git a/drivers/scsi/cxlflash/Makefile b/drivers/scsi/cxlflash/Makefile index c14d24c720d68..9e39866d473b5 100644 --- a/drivers/scsi/cxlflash/Makefile +++ b/drivers/scsi/cxlflash/Makefile @@ -1,2 +1,2 @@ obj-$(CONFIG_CXLFLASH) += cxlflash.o -cxlflash-y += main.o superpipe.o lunmgt.o +cxlflash-y += main.o superpipe.o lunmgt.o vlun.o diff --git a/drivers/scsi/cxlflash/common.h b/drivers/scsi/cxlflash/common.h index d3e54e61c7a51..1c56037146e1e 100644 --- a/drivers/scsi/cxlflash/common.h +++ b/drivers/scsi/cxlflash/common.h @@ -116,6 +116,9 @@ struct cxlflash_cfg { atomic_t num_user_contexts; + /* Parameters that are LUN table related */ + int last_lun_index[CXLFLASH_NUM_FC_PORTS]; + int promote_lun_index; struct list_head lluns; /* list of llun_info structs */ wait_queue_head_t tmf_waitq; @@ -200,5 +203,6 @@ int cxlflash_ioctl(struct scsi_device *, int, void __user *); void cxlflash_stop_term_user_contexts(struct cxlflash_cfg *); int cxlflash_mark_contexts_error(struct cxlflash_cfg *); void cxlflash_term_local_luns(struct cxlflash_cfg *); +void cxlflash_restore_luntable(struct cxlflash_cfg *); #endif /* ifndef _CXLFLASH_COMMON_H */ diff --git a/drivers/scsi/cxlflash/lunmgt.c b/drivers/scsi/cxlflash/lunmgt.c index 66d5bef11ee60..d98ad0ff64c18 100644 --- a/drivers/scsi/cxlflash/lunmgt.c +++ b/drivers/scsi/cxlflash/lunmgt.c @@ -20,6 +20,7 @@ #include "sislite.h" #include "common.h" +#include "vlun.h" #include "superpipe.h" /** @@ -42,6 +43,7 @@ static struct llun_info *create_local(struct scsi_device *sdev, u8 *wwid) lli->sdev = sdev; lli->newly_created = true; lli->host_no = sdev->host->host_no; + lli->in_table = false; memcpy(lli->wwid, wwid, DK_CXLFLASH_MANAGE_LUN_WWID_LEN); out: @@ -208,6 +210,7 @@ void cxlflash_term_global_luns(void) mutex_lock(&global.mutex); list_for_each_entry_safe(gli, temp, &global.gluns, list) { list_del(&gli->list); + cxlflash_ba_terminate(&gli->blka.ba_lun); kfree(gli); } mutex_unlock(&global.mutex); diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 02d464f41b7fa..458ed838f83a1 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1989,6 +1989,8 @@ static int init_afu(struct cxlflash_cfg *cfg) afu_err_intr_init(cfg->afu); atomic64_set(&afu->room, readq_be(&afu->host_map->cmd_room)); + /* Restore the LUN mappings */ + cxlflash_restore_luntable(cfg); err1: pr_debug("%s: returning rc=%d\n", __func__, rc); return rc; @@ -2286,6 +2288,17 @@ static int cxlflash_probe(struct pci_dev *pdev, cfg->init_state = INIT_STATE_NONE; cfg->dev = pdev; + + /* + * The promoted LUNs move to the top of the LUN table. The rest stay + * on the bottom half. The bottom half grows from the end + * (index = 255), whereas the top half grows from the beginning + * (index = 0). + */ + cfg->promote_lun_index = 0; + cfg->last_lun_index[0] = CXLFLASH_NUM_VLUNS/2 - 1; + cfg->last_lun_index[1] = CXLFLASH_NUM_VLUNS/2 - 1; + cfg->dev_id = (struct pci_device_id *)dev_id; cfg->mcctx = NULL; diff --git a/drivers/scsi/cxlflash/sislite.h b/drivers/scsi/cxlflash/sislite.h index 66b889151a4cb..63bf394fe78c7 100644 --- a/drivers/scsi/cxlflash/sislite.h +++ b/drivers/scsi/cxlflash/sislite.h @@ -397,16 +397,17 @@ struct cxlflash_afu_map { }; }; -/* LBA translation control blocks */ - +/* + * LXT - LBA Translation Table + * LXT control blocks + */ struct sisl_lxt_entry { u64 rlba_base; /* bits 0:47 is base - * b48:55 is lun index - * b58:59 is write & read perms - * (if no perm, afu_rc=0x15) - * b60:63 is port_sel mask - */ - + * b48:55 is lun index + * b58:59 is write & read perms + * (if no perm, afu_rc=0x15) + * b60:63 is port_sel mask + */ }; /* @@ -465,4 +466,7 @@ struct sisl_rht_entry_f1 { #define TMF_LUN_RESET 0x1U #define TMF_CLEAR_ACA 0x2U + +#define SISLITE_MAX_WS_BLOCKS 512 + #endif /* _SISLITE_H */ diff --git a/drivers/scsi/cxlflash/superpipe.c b/drivers/scsi/cxlflash/superpipe.c index 3c8bce8bbb0b9..f1b62cea75b16 100644 --- a/drivers/scsi/cxlflash/superpipe.c +++ b/drivers/scsi/cxlflash/superpipe.c @@ -26,10 +26,24 @@ #include "sislite.h" #include "common.h" +#include "vlun.h" #include "superpipe.h" struct cxlflash_global global; +/** + * marshal_rele_to_resize() - translate release to resize structure + * @rele: Source structure from which to translate/copy. + * @resize: Destination structure for the translate/copy. + */ +static void marshal_rele_to_resize(struct dk_cxlflash_release *release, + struct dk_cxlflash_resize *resize) +{ + resize->hdr = release->hdr; + resize->context_id = release->context_id; + resize->rsrc_handle = release->rsrc_handle; +} + /** * marshal_det_to_rele() - translate detach to release structure * @detach: Destination structure for the translate/copy. @@ -449,6 +463,7 @@ void rhte_checkin(struct ctx_info *ctxi, rhte->fp = 0; ctxi->rht_out--; ctxi->rht_lun[rsrc_handle] = NULL; + ctxi->rht_needs_ws[rsrc_handle] = false; } /** @@ -526,13 +541,21 @@ out: /** * cxlflash_lun_detach() - detaches a user from a LUN and resets the LUN's mode * @gli: LUN to detach. + * + * When resetting the mode, terminate block allocation resources as they + * are no longer required (service is safe to call even when block allocation + * resources were not present - such as when transitioning from physical mode). + * These resources will be reallocated when needed (subsequent transition to + * virtual mode). */ void cxlflash_lun_detach(struct glun_info *gli) { mutex_lock(&gli->mutex); WARN_ON(gli->mode == MODE_NONE); - if (--gli->users == 0) + if (--gli->users == 0) { gli->mode = MODE_NONE; + cxlflash_ba_terminate(&gli->blka.ba_lun); + } pr_debug("%s: gli->users=%u\n", __func__, gli->users); WARN_ON(gli->users < 0); mutex_unlock(&gli->mutex); @@ -544,10 +567,12 @@ void cxlflash_lun_detach(struct glun_info *gli) * @ctxi: Context owning resources. * @release: Release ioctl data structure. * - * Note that the AFU sync should _not_ be performed when the context is sitting - * on the error recovery list. A context on the error recovery list is not known - * to the AFU due to reset. When the context is recovered, it will be reattached - * and made known again to the AFU. + * For LUNs in virtual mode, the virtual LUN associated with the specified + * resource handle is resized to 0 prior to releasing the RHTE. Note that the + * AFU sync should _not_ be performed when the context is sitting on the error + * recovery list. A context on the error recovery list is not known to the AFU + * due to reset. When the context is recovered, it will be reattached and made + * known again to the AFU. * * Return: 0 on success, -errno on failure */ @@ -562,6 +587,7 @@ int _cxlflash_disk_release(struct scsi_device *sdev, struct afu *afu = cfg->afu; bool put_ctx = false; + struct dk_cxlflash_resize size; res_hndl_t rhndl = release->rsrc_handle; int rc = 0; @@ -594,7 +620,24 @@ int _cxlflash_disk_release(struct scsi_device *sdev, goto out; } + /* + * Resize to 0 for virtual LUNS by setting the size + * to 0. This will clear LXT_START and LXT_CNT fields + * in the RHT entry and properly sync with the AFU. + * + * Afterwards we clear the remaining fields. + */ switch (gli->mode) { + case MODE_VIRTUAL: + marshal_rele_to_resize(release, &size); + size.req_size = 0; + rc = _cxlflash_vlun_resize(sdev, ctxi, &size); + if (rc) { + dev_dbg(dev, "%s: resize failed rc %d\n", __func__, rc); + goto out; + } + + break; case MODE_PHYSICAL: /* * Clear the Format 1 RHT entry for direct access @@ -666,6 +709,7 @@ static void destroy_context(struct cxlflash_cfg *cfg, /* Free memory associated with context */ free_page((ulong)ctxi->rht_start); + kfree(ctxi->rht_needs_ws); kfree(ctxi->rht_lun); kfree(ctxi); atomic_dec_if_positive(&cfg->num_user_contexts); @@ -693,11 +737,13 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, struct afu *afu = cfg->afu; struct ctx_info *ctxi = NULL; struct llun_info **lli = NULL; + bool *ws = NULL; struct sisl_rht_entry *rhte; ctxi = kzalloc(sizeof(*ctxi), GFP_KERNEL); lli = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*lli)), GFP_KERNEL); - if (unlikely(!ctxi || !lli)) { + ws = kzalloc((MAX_RHT_PER_CONTEXT * sizeof(*ws)), GFP_KERNEL); + if (unlikely(!ctxi || !lli || !ws)) { dev_err(dev, "%s: Unable to allocate context!\n", __func__); goto err; } @@ -709,6 +755,7 @@ static struct ctx_info *create_context(struct cxlflash_cfg *cfg, } ctxi->rht_lun = lli; + ctxi->rht_needs_ws = ws; ctxi->rht_start = rhte; ctxi->rht_perms = perms; @@ -728,6 +775,7 @@ out: return ctxi; err: + kfree(ws); kfree(lli); kfree(ctxi); ctxi = NULL; @@ -1729,6 +1777,12 @@ static int cxlflash_disk_verify(struct scsi_device *sdev, case MODE_PHYSICAL: last_lba = gli->max_lba; break; + case MODE_VIRTUAL: + /* Cast lxt_cnt to u64 for multiply to be treated as 64bit op */ + last_lba = ((u64)rhte->lxt_cnt * MC_CHUNK_SIZE * gli->blk_len); + last_lba /= CXLFLASH_BLOCK_SIZE; + last_lba--; + break; default: WARN(1, "Unsupported LUN mode!"); } @@ -1756,12 +1810,18 @@ static char *decode_ioctl(int cmd) return __stringify_1(DK_CXLFLASH_ATTACH); case DK_CXLFLASH_USER_DIRECT: return __stringify_1(DK_CXLFLASH_USER_DIRECT); + case DK_CXLFLASH_USER_VIRTUAL: + return __stringify_1(DK_CXLFLASH_USER_VIRTUAL); + case DK_CXLFLASH_VLUN_RESIZE: + return __stringify_1(DK_CXLFLASH_VLUN_RESIZE); case DK_CXLFLASH_RELEASE: return __stringify_1(DK_CXLFLASH_RELEASE); case DK_CXLFLASH_DETACH: return __stringify_1(DK_CXLFLASH_DETACH); case DK_CXLFLASH_VERIFY: return __stringify_1(DK_CXLFLASH_VERIFY); + case DK_CXLFLASH_VLUN_CLONE: + return __stringify_1(DK_CXLFLASH_VLUN_CLONE); case DK_CXLFLASH_RECOVER_AFU: return __stringify_1(DK_CXLFLASH_RECOVER_AFU); case DK_CXLFLASH_MANAGE_LUN: @@ -1876,6 +1936,7 @@ static int ioctl_common(struct scsi_device *sdev, int cmd) rc = check_state(cfg); if (unlikely(rc) && (cfg->state == STATE_FAILTERM)) { switch (cmd) { + case DK_CXLFLASH_VLUN_RESIZE: case DK_CXLFLASH_RELEASE: case DK_CXLFLASH_DETACH: dev_dbg(dev, "%s: Command override! (%d)\n", @@ -1923,12 +1984,18 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) {sizeof(struct dk_cxlflash_verify), (sioctl)cxlflash_disk_verify}, {sizeof(struct dk_cxlflash_recover_afu), (sioctl)cxlflash_afu_recover}, {sizeof(struct dk_cxlflash_manage_lun), (sioctl)cxlflash_manage_lun}, + {sizeof(struct dk_cxlflash_uvirtual), cxlflash_disk_virtual_open}, + {sizeof(struct dk_cxlflash_resize), (sioctl)cxlflash_vlun_resize}, + {sizeof(struct dk_cxlflash_clone), (sioctl)cxlflash_disk_clone}, }; /* Restrict command set to physical support only for internal LUN */ if (afu->internal_lun) switch (cmd) { case DK_CXLFLASH_RELEASE: + case DK_CXLFLASH_USER_VIRTUAL: + case DK_CXLFLASH_VLUN_RESIZE: + case DK_CXLFLASH_VLUN_CLONE: dev_dbg(dev, "%s: %s not supported for lun_mode=%d\n", __func__, decode_ioctl(cmd), afu->internal_lun); rc = -EINVAL; @@ -1942,6 +2009,9 @@ int cxlflash_ioctl(struct scsi_device *sdev, int cmd, void __user *arg) case DK_CXLFLASH_DETACH: case DK_CXLFLASH_VERIFY: case DK_CXLFLASH_RECOVER_AFU: + case DK_CXLFLASH_USER_VIRTUAL: + case DK_CXLFLASH_VLUN_RESIZE: + case DK_CXLFLASH_VLUN_CLONE: dev_dbg(dev, "%s: %s (%08X) on dev(%d/%d/%d/%llu)\n", __func__, decode_ioctl(cmd), cmd, shost->host_no, sdev->channel, sdev->id, sdev->lun); diff --git a/drivers/scsi/cxlflash/superpipe.h b/drivers/scsi/cxlflash/superpipe.h index ae39b9627118c..d7dc88bc64a4b 100644 --- a/drivers/scsi/cxlflash/superpipe.h +++ b/drivers/scsi/cxlflash/superpipe.h @@ -31,9 +31,11 @@ extern struct cxlflash_global global; #define MC_DISCOVERY_TIMEOUT 5 /* 5 secs */ #define CHAN2PORT(_x) ((_x) + 1) +#define PORT2CHAN(_x) ((_x) - 1) enum lun_mode { MODE_NONE = 0, + MODE_VIRTUAL, MODE_PHYSICAL }; @@ -41,13 +43,14 @@ enum lun_mode { struct glun_info { u64 max_lba; /* from read cap(16) */ u32 blk_len; /* from read cap(16) */ - enum lun_mode mode; /* NONE, PHYSICAL */ + enum lun_mode mode; /* NONE, VIRTUAL, PHYSICAL */ int users; /* Number of users w/ references to LUN */ u8 wwid[16]; struct mutex mutex; + struct blka blka; struct list_head list; }; @@ -58,6 +61,7 @@ struct llun_info { u32 host_no; /* host_no from Scsi_host */ u32 port_sel; /* What port to use for this LUN */ bool newly_created; /* Whether the LUN was just discovered */ + bool in_table; /* Whether a LUN table entry was created */ u8 wwid[16]; /* Keep a duplicate copy here? */ @@ -90,6 +94,7 @@ struct ctx_info { u32 rht_out; /* Number of checked out RHT entries */ u32 rht_perms; /* User-defined permissions for RHT entries */ struct llun_info **rht_lun; /* Mapping of RHT entries to LUNs */ + bool *rht_needs_ws; /* User-desired write-same function per RHTE */ struct cxl_ioctl_start_work work; u64 ctxid; @@ -111,10 +116,18 @@ struct cxlflash_global { struct page *err_page; /* One page of all 0xF for error notification */ }; +int cxlflash_vlun_resize(struct scsi_device *, struct dk_cxlflash_resize *); +int _cxlflash_vlun_resize(struct scsi_device *, struct ctx_info *, + struct dk_cxlflash_resize *); + int cxlflash_disk_release(struct scsi_device *, struct dk_cxlflash_release *); int _cxlflash_disk_release(struct scsi_device *, struct ctx_info *, struct dk_cxlflash_release *); +int cxlflash_disk_clone(struct scsi_device *, struct dk_cxlflash_clone *); + +int cxlflash_disk_virtual_open(struct scsi_device *, void *); + int cxlflash_lun_attach(struct glun_info *, enum lun_mode, bool); void cxlflash_lun_detach(struct glun_info *); @@ -127,6 +140,8 @@ struct sisl_rht_entry *get_rhte(struct ctx_info *, res_hndl_t, struct sisl_rht_entry *rhte_checkout(struct ctx_info *, struct llun_info *); void rhte_checkin(struct ctx_info *, struct sisl_rht_entry *); +void cxlflash_ba_terminate(struct ba_lun *); + int cxlflash_manage_lun(struct scsi_device *, struct dk_cxlflash_manage_lun *); #endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/drivers/scsi/cxlflash/vlun.c b/drivers/scsi/cxlflash/vlun.c new file mode 100644 index 0000000000000..6155cb1d4ed37 --- /dev/null +++ b/drivers/scsi/cxlflash/vlun.c @@ -0,0 +1,1243 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * 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 +#include +#include +#include + +#include +#include +#include + +#include "sislite.h" +#include "common.h" +#include "vlun.h" +#include "superpipe.h" + +/** + * marshal_virt_to_resize() - translate uvirtual to resize structure + * @virt: Source structure from which to translate/copy. + * @resize: Destination structure for the translate/copy. + */ +static void marshal_virt_to_resize(struct dk_cxlflash_uvirtual *virt, + struct dk_cxlflash_resize *resize) +{ + resize->hdr = virt->hdr; + resize->context_id = virt->context_id; + resize->rsrc_handle = virt->rsrc_handle; + resize->req_size = virt->lun_size; + resize->last_lba = virt->last_lba; +} + +/** + * marshal_clone_to_rele() - translate clone to release structure + * @clone: Source structure from which to translate/copy. + * @rele: Destination structure for the translate/copy. + */ +static void marshal_clone_to_rele(struct dk_cxlflash_clone *clone, + struct dk_cxlflash_release *release) +{ + release->hdr = clone->hdr; + release->context_id = clone->context_id_dst; +} + +/** + * ba_init() - initializes a block allocator + * @ba_lun: Block allocator to initialize. + * + * Return: 0 on success, -errno on failure + */ +static int ba_init(struct ba_lun *ba_lun) +{ + struct ba_lun_info *bali = NULL; + int lun_size_au = 0, i = 0; + int last_word_underflow = 0; + u64 *lam; + + pr_debug("%s: Initializing LUN: lun_id = %llX, " + "ba_lun->lsize = %lX, ba_lun->au_size = %lX\n", + __func__, ba_lun->lun_id, ba_lun->lsize, ba_lun->au_size); + + /* Calculate bit map size */ + lun_size_au = ba_lun->lsize / ba_lun->au_size; + if (lun_size_au == 0) { + pr_debug("%s: Requested LUN size of 0!\n", __func__); + return -EINVAL; + } + + /* Allocate lun information container */ + bali = kzalloc(sizeof(struct ba_lun_info), GFP_KERNEL); + if (unlikely(!bali)) { + pr_err("%s: Failed to allocate lun_info for lun_id %llX\n", + __func__, ba_lun->lun_id); + return -ENOMEM; + } + + bali->total_aus = lun_size_au; + bali->lun_bmap_size = lun_size_au / BITS_PER_LONG; + + if (lun_size_au % BITS_PER_LONG) + bali->lun_bmap_size++; + + /* Allocate bitmap space */ + bali->lun_alloc_map = kzalloc((bali->lun_bmap_size * sizeof(u64)), + GFP_KERNEL); + if (unlikely(!bali->lun_alloc_map)) { + pr_err("%s: Failed to allocate lun allocation map: " + "lun_id = %llX\n", __func__, ba_lun->lun_id); + kfree(bali); + return -ENOMEM; + } + + /* Initialize the bit map size and set all bits to '1' */ + bali->free_aun_cnt = lun_size_au; + + for (i = 0; i < bali->lun_bmap_size; i++) + bali->lun_alloc_map[i] = 0xFFFFFFFFFFFFFFFFULL; + + /* If the last word not fully utilized, mark extra bits as allocated */ + last_word_underflow = (bali->lun_bmap_size * BITS_PER_LONG); + last_word_underflow -= bali->free_aun_cnt; + if (last_word_underflow > 0) { + lam = &bali->lun_alloc_map[bali->lun_bmap_size - 1]; + for (i = (HIBIT - last_word_underflow + 1); + i < BITS_PER_LONG; + i++) + clear_bit(i, (ulong *)lam); + } + + /* Initialize high elevator index, low/curr already at 0 from kzalloc */ + bali->free_high_idx = bali->lun_bmap_size; + + /* Allocate clone map */ + bali->aun_clone_map = kzalloc((bali->total_aus * sizeof(u8)), + GFP_KERNEL); + if (unlikely(!bali->aun_clone_map)) { + pr_err("%s: Failed to allocate clone map: lun_id = %llX\n", + __func__, ba_lun->lun_id); + kfree(bali->lun_alloc_map); + kfree(bali); + return -ENOMEM; + } + + /* Pass the allocated lun info as a handle to the user */ + ba_lun->ba_lun_handle = bali; + + pr_debug("%s: Successfully initialized the LUN: " + "lun_id = %llX, bitmap size = %X, free_aun_cnt = %llX\n", + __func__, ba_lun->lun_id, bali->lun_bmap_size, + bali->free_aun_cnt); + return 0; +} + +/** + * find_free_range() - locates a free bit within the block allocator + * @low: First word in block allocator to start search. + * @high: Last word in block allocator to search. + * @bali: LUN information structure owning the block allocator to search. + * @bit_word: Passes back the word in the block allocator owning the free bit. + * + * Return: The bit position within the passed back word, -1 on failure + */ +static int find_free_range(u32 low, + u32 high, + struct ba_lun_info *bali, int *bit_word) +{ + int i; + u64 bit_pos = -1; + ulong *lam, num_bits; + + for (i = low; i < high; i++) + if (bali->lun_alloc_map[i] != 0) { + lam = (ulong *)&bali->lun_alloc_map[i]; + num_bits = (sizeof(*lam) * BITS_PER_BYTE); + bit_pos = find_first_bit(lam, num_bits); + + pr_devel("%s: Found free bit %llX in lun " + "map entry %llX at bitmap index = %X\n", + __func__, bit_pos, bali->lun_alloc_map[i], + i); + + *bit_word = i; + bali->free_aun_cnt--; + clear_bit(bit_pos, lam); + break; + } + + return bit_pos; +} + +/** + * ba_alloc() - allocates a block from the block allocator + * @ba_lun: Block allocator from which to allocate a block. + * + * Return: The allocated block, -1 on failure + */ +static u64 ba_alloc(struct ba_lun *ba_lun) +{ + u64 bit_pos = -1; + int bit_word = 0; + struct ba_lun_info *bali = NULL; + + bali = ba_lun->ba_lun_handle; + + pr_debug("%s: Received block allocation request: " + "lun_id = %llX, free_aun_cnt = %llX\n", + __func__, ba_lun->lun_id, bali->free_aun_cnt); + + if (bali->free_aun_cnt == 0) { + pr_debug("%s: No space left on LUN: lun_id = %llX\n", + __func__, ba_lun->lun_id); + return -1ULL; + } + + /* Search to find a free entry, curr->high then low->curr */ + bit_pos = find_free_range(bali->free_curr_idx, + bali->free_high_idx, bali, &bit_word); + if (bit_pos == -1) { + bit_pos = find_free_range(bali->free_low_idx, + bali->free_curr_idx, + bali, &bit_word); + if (bit_pos == -1) { + pr_debug("%s: Could not find an allocation unit on LUN:" + " lun_id = %llX\n", __func__, ba_lun->lun_id); + return -1ULL; + } + } + + /* Update the free_curr_idx */ + if (bit_pos == HIBIT) + bali->free_curr_idx = bit_word + 1; + else + bali->free_curr_idx = bit_word; + + pr_debug("%s: Allocating AU number %llX, on lun_id %llX, " + "free_aun_cnt = %llX\n", __func__, + ((bit_word * BITS_PER_LONG) + bit_pos), ba_lun->lun_id, + bali->free_aun_cnt); + + return (u64) ((bit_word * BITS_PER_LONG) + bit_pos); +} + +/** + * validate_alloc() - validates the specified block has been allocated + * @ba_lun_info: LUN info owning the block allocator. + * @aun: Block to validate. + * + * Return: 0 on success, -1 on failure + */ +static int validate_alloc(struct ba_lun_info *bali, u64 aun) +{ + int idx = 0, bit_pos = 0; + + idx = aun / BITS_PER_LONG; + bit_pos = aun % BITS_PER_LONG; + + if (test_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx])) + return -1; + + return 0; +} + +/** + * ba_free() - frees a block from the block allocator + * @ba_lun: Block allocator from which to allocate a block. + * @to_free: Block to free. + * + * Return: 0 on success, -1 on failure + */ +static int ba_free(struct ba_lun *ba_lun, u64 to_free) +{ + int idx = 0, bit_pos = 0; + struct ba_lun_info *bali = NULL; + + bali = ba_lun->ba_lun_handle; + + if (validate_alloc(bali, to_free)) { + pr_debug("%s: The AUN %llX is not allocated on lun_id %llX\n", + __func__, to_free, ba_lun->lun_id); + return -1; + } + + pr_debug("%s: Received a request to free AU %llX on lun_id %llX, " + "free_aun_cnt = %llX\n", __func__, to_free, ba_lun->lun_id, + bali->free_aun_cnt); + + if (bali->aun_clone_map[to_free] > 0) { + pr_debug("%s: AUN %llX on lun_id %llX has been cloned. Clone " + "count = %X\n", __func__, to_free, ba_lun->lun_id, + bali->aun_clone_map[to_free]); + bali->aun_clone_map[to_free]--; + return 0; + } + + idx = to_free / BITS_PER_LONG; + bit_pos = to_free % BITS_PER_LONG; + + set_bit(bit_pos, (ulong *)&bali->lun_alloc_map[idx]); + bali->free_aun_cnt++; + + if (idx < bali->free_low_idx) + bali->free_low_idx = idx; + else if (idx > bali->free_high_idx) + bali->free_high_idx = idx; + + pr_debug("%s: Successfully freed AU at bit_pos %X, bit map index %X on " + "lun_id %llX, free_aun_cnt = %llX\n", __func__, bit_pos, idx, + ba_lun->lun_id, bali->free_aun_cnt); + + return 0; +} + +/** + * ba_clone() - Clone a chunk of the block allocation table + * @ba_lun: Block allocator from which to allocate a block. + * @to_free: Block to free. + * + * Return: 0 on success, -1 on failure + */ +static int ba_clone(struct ba_lun *ba_lun, u64 to_clone) +{ + struct ba_lun_info *bali = ba_lun->ba_lun_handle; + + if (validate_alloc(bali, to_clone)) { + pr_debug("%s: AUN %llX is not allocated on lun_id %llX\n", + __func__, to_clone, ba_lun->lun_id); + return -1; + } + + pr_debug("%s: Received a request to clone AUN %llX on lun_id %llX\n", + __func__, to_clone, ba_lun->lun_id); + + if (bali->aun_clone_map[to_clone] == MAX_AUN_CLONE_CNT) { + pr_debug("%s: AUN %llX on lun_id %llX hit max clones already\n", + __func__, to_clone, ba_lun->lun_id); + return -1; + } + + bali->aun_clone_map[to_clone]++; + + return 0; +} + +/** + * ba_space() - returns the amount of free space left in the block allocator + * @ba_lun: Block allocator. + * + * Return: Amount of free space in block allocator + */ +static u64 ba_space(struct ba_lun *ba_lun) +{ + struct ba_lun_info *bali = ba_lun->ba_lun_handle; + + return bali->free_aun_cnt; +} + +/** + * cxlflash_ba_terminate() - frees resources associated with the block allocator + * @ba_lun: Block allocator. + * + * Safe to call in a partially allocated state. + */ +void cxlflash_ba_terminate(struct ba_lun *ba_lun) +{ + struct ba_lun_info *bali = ba_lun->ba_lun_handle; + + if (bali) { + kfree(bali->aun_clone_map); + kfree(bali->lun_alloc_map); + kfree(bali); + ba_lun->ba_lun_handle = NULL; + } +} + +/** + * init_vlun() - initializes a LUN for virtual use + * @lun_info: LUN information structure that owns the block allocator. + * + * Return: 0 on success, -errno on failure + */ +static int init_vlun(struct llun_info *lli) +{ + int rc = 0; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + + memset(blka, 0, sizeof(*blka)); + mutex_init(&blka->mutex); + + /* LUN IDs are unique per port, save the index instead */ + blka->ba_lun.lun_id = lli->lun_index; + blka->ba_lun.lsize = gli->max_lba + 1; + blka->ba_lun.lba_size = gli->blk_len; + + blka->ba_lun.au_size = MC_CHUNK_SIZE; + blka->nchunk = blka->ba_lun.lsize / MC_CHUNK_SIZE; + + rc = ba_init(&blka->ba_lun); + if (unlikely(rc)) + pr_debug("%s: cannot init block_alloc, rc=%d\n", __func__, rc); + + pr_debug("%s: returning rc=%d lli=%p\n", __func__, rc, lli); + return rc; +} + +/** + * write_same16() - sends a SCSI WRITE_SAME16 (0) command to specified LUN + * @sdev: SCSI device associated with LUN. + * @lba: Logical block address to start write same. + * @nblks: Number of logical blocks to write same. + * + * Return: 0 on success, -errno on failure + */ +static int write_same16(struct scsi_device *sdev, + u64 lba, + u32 nblks) +{ + u8 *cmd_buf = NULL; + u8 *scsi_cmd = NULL; + u8 *sense_buf = NULL; + int rc = 0; + int result = 0; + int ws_limit = SISLITE_MAX_WS_BLOCKS; + u64 offset = lba; + int left = nblks; + u32 tout = sdev->request_queue->rq_timeout; + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + + cmd_buf = kzalloc(CMD_BUFSIZE, GFP_KERNEL); + scsi_cmd = kzalloc(MAX_COMMAND_SIZE, GFP_KERNEL); + sense_buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (unlikely(!cmd_buf || !scsi_cmd || !sense_buf)) { + rc = -ENOMEM; + goto out; + } + + while (left > 0) { + + scsi_cmd[0] = WRITE_SAME_16; + put_unaligned_be64(offset, &scsi_cmd[2]); + put_unaligned_be32(ws_limit < left ? ws_limit : left, + &scsi_cmd[10]); + + result = scsi_execute(sdev, scsi_cmd, DMA_TO_DEVICE, cmd_buf, + CMD_BUFSIZE, sense_buf, tout, 5, 0, NULL); + if (result) { + dev_err_ratelimited(dev, "%s: command failed for " + "offset %lld result=0x%x\n", + __func__, offset, result); + rc = -EIO; + goto out; + } + left -= ws_limit; + offset += ws_limit; + } + +out: + kfree(cmd_buf); + kfree(scsi_cmd); + kfree(sense_buf); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * grow_lxt() - expands the translation table associated with the specified RHTE + * @afu: AFU associated with the host. + * @sdev: SCSI device associated with LUN. + * @ctxid: Context ID of context owning the RHTE. + * @rhndl: Resource handle associated with the RHTE. + * @rhte: Resource handle entry (RHTE). + * @new_size: Number of translation entries associated with RHTE. + * + * By design, this routine employs a 'best attempt' allocation and will + * truncate the requested size down if there is not sufficient space in + * the block allocator to satisfy the request but there does exist some + * amount of space. The user is made aware of this by returning the size + * allocated. + * + * Return: 0 on success, -errno on failure + */ +static int grow_lxt(struct afu *afu, + struct scsi_device *sdev, + ctx_hndl_t ctxid, + res_hndl_t rhndl, + struct sisl_rht_entry *rhte, + u64 *new_size) +{ + struct sisl_lxt_entry *lxt = NULL, *lxt_old = NULL; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + u32 av_size; + u32 ngrps, ngrps_old; + u64 aun; /* chunk# allocated by block allocator */ + u64 delta = *new_size - rhte->lxt_cnt; + u64 my_new_size; + int i, rc = 0; + + /* + * Check what is available in the block allocator before re-allocating + * LXT array. This is done up front under the mutex which must not be + * released until after allocation is complete. + */ + mutex_lock(&blka->mutex); + av_size = ba_space(&blka->ba_lun); + if (unlikely(av_size <= 0)) { + pr_debug("%s: ba_space error: av_size %d\n", __func__, av_size); + mutex_unlock(&blka->mutex); + rc = -ENOSPC; + goto out; + } + + if (av_size < delta) + delta = av_size; + + lxt_old = rhte->lxt_start; + ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); + ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt + delta); + + if (ngrps != ngrps_old) { + /* reallocate to fit new size */ + lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), + GFP_KERNEL); + if (unlikely(!lxt)) { + mutex_unlock(&blka->mutex); + rc = -ENOMEM; + goto out; + } + + /* copy over all old entries */ + memcpy(lxt, lxt_old, (sizeof(*lxt) * rhte->lxt_cnt)); + } else + lxt = lxt_old; + + /* nothing can fail from now on */ + my_new_size = rhte->lxt_cnt + delta; + + /* add new entries to the end */ + for (i = rhte->lxt_cnt; i < my_new_size; i++) { + /* + * Due to the earlier check of available space, ba_alloc + * cannot fail here. If it did due to internal error, + * leave a rlba_base of -1u which will likely be a + * invalid LUN (too large). + */ + aun = ba_alloc(&blka->ba_lun); + if ((aun == -1ULL) || (aun >= blka->nchunk)) + pr_debug("%s: ba_alloc error: allocated chunk# %llX, " + "max %llX\n", __func__, aun, blka->nchunk - 1); + + /* select both ports, use r/w perms from RHT */ + lxt[i].rlba_base = ((aun << MC_CHUNK_SHIFT) | + (lli->lun_index << LXT_LUNIDX_SHIFT) | + (RHT_PERM_RW << LXT_PERM_SHIFT | + lli->port_sel)); + } + + mutex_unlock(&blka->mutex); + + /* + * The following sequence is prescribed in the SISlite spec + * for syncing up with the AFU when adding LXT entries. + */ + dma_wmb(); /* Make LXT updates are visible */ + + rhte->lxt_start = lxt; + dma_wmb(); /* Make RHT entry's LXT table update visible */ + + rhte->lxt_cnt = my_new_size; + dma_wmb(); /* Make RHT entry's LXT table size update visible */ + + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); + + /* free old lxt if reallocated */ + if (lxt != lxt_old) + kfree(lxt_old); + *new_size = my_new_size; +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * shrink_lxt() - reduces translation table associated with the specified RHTE + * @afu: AFU associated with the host. + * @sdev: SCSI device associated with LUN. + * @rhndl: Resource handle associated with the RHTE. + * @rhte: Resource handle entry (RHTE). + * @ctxi: Context owning resources. + * @new_size: Number of translation entries associated with RHTE. + * + * Return: 0 on success, -errno on failure + */ +static int shrink_lxt(struct afu *afu, + struct scsi_device *sdev, + res_hndl_t rhndl, + struct sisl_rht_entry *rhte, + struct ctx_info *ctxi, + u64 *new_size) +{ + struct sisl_lxt_entry *lxt, *lxt_old; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + ctx_hndl_t ctxid = DECODE_CTXID(ctxi->ctxid); + bool needs_ws = ctxi->rht_needs_ws[rhndl]; + bool needs_sync = !ctxi->err_recovery_active; + u32 ngrps, ngrps_old; + u64 aun; /* chunk# allocated by block allocator */ + u64 delta = rhte->lxt_cnt - *new_size; + u64 my_new_size; + int i, rc = 0; + + lxt_old = rhte->lxt_start; + ngrps_old = LXT_NUM_GROUPS(rhte->lxt_cnt); + ngrps = LXT_NUM_GROUPS(rhte->lxt_cnt - delta); + + if (ngrps != ngrps_old) { + /* Reallocate to fit new size unless new size is 0 */ + if (ngrps) { + lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), + GFP_KERNEL); + if (unlikely(!lxt)) { + rc = -ENOMEM; + goto out; + } + + /* Copy over old entries that will remain */ + memcpy(lxt, lxt_old, + (sizeof(*lxt) * (rhte->lxt_cnt - delta))); + } else + lxt = NULL; + } else + lxt = lxt_old; + + /* Nothing can fail from now on */ + my_new_size = rhte->lxt_cnt - delta; + + /* + * The following sequence is prescribed in the SISlite spec + * for syncing up with the AFU when removing LXT entries. + */ + rhte->lxt_cnt = my_new_size; + dma_wmb(); /* Make RHT entry's LXT table size update visible */ + + rhte->lxt_start = lxt; + dma_wmb(); /* Make RHT entry's LXT table update visible */ + + if (needs_sync) + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_HW_SYNC); + + if (needs_ws) { + /* + * Mark the context as unavailable, so that we can release + * the mutex safely. + */ + ctxi->unavail = true; + mutex_unlock(&ctxi->mutex); + } + + /* Free LBAs allocated to freed chunks */ + mutex_lock(&blka->mutex); + for (i = delta - 1; i >= 0; i--) { + /* Mask the higher 48 bits before shifting, even though + * it is a noop + */ + aun = (lxt_old[my_new_size + i].rlba_base & SISL_ASTATUS_MASK); + aun = (aun >> MC_CHUNK_SHIFT); + if (needs_ws) + write_same16(sdev, aun, MC_CHUNK_SIZE); + ba_free(&blka->ba_lun, aun); + } + mutex_unlock(&blka->mutex); + + if (needs_ws) { + /* Make the context visible again */ + mutex_lock(&ctxi->mutex); + ctxi->unavail = false; + } + + /* Free old lxt if reallocated */ + if (lxt != lxt_old) + kfree(lxt_old); + *new_size = my_new_size; +out: + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * _cxlflash_vlun_resize() - changes the size of a virtual lun + * @sdev: SCSI device associated with LUN owning virtual LUN. + * @ctxi: Context owning resources. + * @resize: Resize ioctl data structure. + * + * On successful return, the user is informed of the new size (in blocks) + * of the virtual lun in last LBA format. When the size of the virtual + * lun is zero, the last LBA is reflected as -1. See comment in the + * prologue for _cxlflash_disk_release() regarding AFU syncs and contexts + * on the error recovery list. + * + * Return: 0 on success, -errno on failure + */ +int _cxlflash_vlun_resize(struct scsi_device *sdev, + struct ctx_info *ctxi, + struct dk_cxlflash_resize *resize) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct afu *afu = cfg->afu; + bool put_ctx = false; + + res_hndl_t rhndl = resize->rsrc_handle; + u64 new_size; + u64 nsectors; + u64 ctxid = DECODE_CTXID(resize->context_id), + rctxid = resize->context_id; + + struct sisl_rht_entry *rhte; + + int rc = 0; + + /* + * The requested size (req_size) is always assumed to be in 4k blocks, + * so we have to convert it here from 4k to chunk size. + */ + nsectors = (resize->req_size * CXLFLASH_BLOCK_SIZE) / gli->blk_len; + new_size = DIV_ROUND_UP(nsectors, MC_CHUNK_SIZE); + + pr_debug("%s: ctxid=%llu rhndl=0x%llx, req_size=0x%llx," + "new_size=%llx\n", __func__, ctxid, resize->rsrc_handle, + resize->req_size, new_size); + + if (unlikely(gli->mode != MODE_VIRTUAL)) { + pr_debug("%s: LUN mode does not support resize! (%d)\n", + __func__, gli->mode); + rc = -EINVAL; + goto out; + + } + + if (!ctxi) { + ctxi = get_context(cfg, rctxid, lli, CTX_CTRL_ERR_FALLBACK); + if (unlikely(!ctxi)) { + pr_debug("%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto out; + } + + put_ctx = true; + } + + rhte = get_rhte(ctxi, rhndl, lli); + if (unlikely(!rhte)) { + pr_debug("%s: Bad resource handle! (%u)\n", __func__, rhndl); + rc = -EINVAL; + goto out; + } + + if (new_size > rhte->lxt_cnt) + rc = grow_lxt(afu, sdev, ctxid, rhndl, rhte, &new_size); + else if (new_size < rhte->lxt_cnt) + rc = shrink_lxt(afu, sdev, rhndl, rhte, ctxi, &new_size); + + resize->hdr.return_flags = 0; + resize->last_lba = (new_size * MC_CHUNK_SIZE * gli->blk_len); + resize->last_lba /= CXLFLASH_BLOCK_SIZE; + resize->last_lba--; + +out: + if (put_ctx) + put_context(ctxi); + pr_debug("%s: resized to %lld returning rc=%d\n", + __func__, resize->last_lba, rc); + return rc; +} + +int cxlflash_vlun_resize(struct scsi_device *sdev, + struct dk_cxlflash_resize *resize) +{ + return _cxlflash_vlun_resize(sdev, NULL, resize); +} + +/** + * cxlflash_restore_luntable() - Restore LUN table to prior state + * @cfg: Internal structure associated with the host. + */ +void cxlflash_restore_luntable(struct cxlflash_cfg *cfg) +{ + struct llun_info *lli, *temp; + u32 chan; + u32 lind; + struct afu *afu = cfg->afu; + struct sisl_global_map *agm = &afu->afu_map->global; + + mutex_lock(&global.mutex); + + list_for_each_entry_safe(lli, temp, &cfg->lluns, list) { + if (!lli->in_table) + continue; + + lind = lli->lun_index; + + if (lli->port_sel == BOTH_PORTS) { + writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); + writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); + pr_debug("%s: Virtual LUN on slot %d id0=%llx, " + "id1=%llx\n", __func__, lind, + lli->lun_id[0], lli->lun_id[1]); + } else { + chan = PORT2CHAN(lli->port_sel); + writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); + pr_debug("%s: Virtual LUN on slot %d chan=%d, " + "id=%llx\n", __func__, lind, chan, + lli->lun_id[chan]); + } + } + + mutex_unlock(&global.mutex); +} + +/** + * init_luntable() - write an entry in the LUN table + * @cfg: Internal structure associated with the host. + * @lli: Per adapter LUN information structure. + * + * On successful return, a LUN table entry is created. + * At the top for LUNs visible on both ports. + * At the bottom for LUNs visible only on one port. + * + * Return: 0 on success, -errno on failure + */ +static int init_luntable(struct cxlflash_cfg *cfg, struct llun_info *lli) +{ + u32 chan; + u32 lind; + int rc = 0; + struct afu *afu = cfg->afu; + struct sisl_global_map *agm = &afu->afu_map->global; + + mutex_lock(&global.mutex); + + if (lli->in_table) + goto out; + + if (lli->port_sel == BOTH_PORTS) { + /* + * If this LUN is visible from both ports, we will put + * it in the top half of the LUN table. + */ + if ((cfg->promote_lun_index == cfg->last_lun_index[0]) || + (cfg->promote_lun_index == cfg->last_lun_index[1])) { + rc = -ENOSPC; + goto out; + } + + lind = lli->lun_index = cfg->promote_lun_index; + writeq_be(lli->lun_id[0], &agm->fc_port[0][lind]); + writeq_be(lli->lun_id[1], &agm->fc_port[1][lind]); + cfg->promote_lun_index++; + pr_debug("%s: Virtual LUN on slot %d id0=%llx, id1=%llx\n", + __func__, lind, lli->lun_id[0], lli->lun_id[1]); + } else { + /* + * If this LUN is visible only from one port, we will put + * it in the bottom half of the LUN table. + */ + chan = PORT2CHAN(lli->port_sel); + if (cfg->promote_lun_index == cfg->last_lun_index[chan]) { + rc = -ENOSPC; + goto out; + } + + lind = lli->lun_index = cfg->last_lun_index[chan]; + writeq_be(lli->lun_id[chan], &agm->fc_port[chan][lind]); + cfg->last_lun_index[chan]--; + pr_debug("%s: Virtual LUN on slot %d chan=%d, id=%llx\n", + __func__, lind, chan, lli->lun_id[chan]); + } + + lli->in_table = true; +out: + mutex_unlock(&global.mutex); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; +} + +/** + * cxlflash_disk_virtual_open() - open a virtual disk of specified size + * @sdev: SCSI device associated with LUN owning virtual LUN. + * @arg: UVirtual ioctl data structure. + * + * On successful return, the user is informed of the resource handle + * to be used to identify the virtual lun and the size (in blocks) of + * the virtual lun in last LBA format. When the size of the virtual lun + * is zero, the last LBA is reflected as -1. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_disk_virtual_open(struct scsi_device *sdev, void *arg) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct device *dev = &cfg->dev->dev; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + + struct dk_cxlflash_uvirtual *virt = (struct dk_cxlflash_uvirtual *)arg; + struct dk_cxlflash_resize resize; + + u64 ctxid = DECODE_CTXID(virt->context_id), + rctxid = virt->context_id; + u64 lun_size = virt->lun_size; + u64 last_lba = 0; + u64 rsrc_handle = -1; + + int rc = 0; + + struct ctx_info *ctxi = NULL; + struct sisl_rht_entry *rhte = NULL; + + pr_debug("%s: ctxid=%llu ls=0x%llx\n", __func__, ctxid, lun_size); + + mutex_lock(&gli->mutex); + if (gli->mode == MODE_NONE) { + /* Setup the LUN table and block allocator on first call */ + rc = init_luntable(cfg, lli); + if (rc) { + dev_err(dev, "%s: call to init_luntable failed " + "rc=%d!\n", __func__, rc); + goto err0; + } + + rc = init_vlun(lli); + if (rc) { + dev_err(dev, "%s: call to init_vlun failed rc=%d!\n", + __func__, rc); + rc = -ENOMEM; + goto err0; + } + } + + rc = cxlflash_lun_attach(gli, MODE_VIRTUAL, true); + if (unlikely(rc)) { + dev_err(dev, "%s: Failed to attach to LUN! (VIRTUAL)\n", + __func__); + goto err0; + } + mutex_unlock(&gli->mutex); + + ctxi = get_context(cfg, rctxid, lli, 0); + if (unlikely(!ctxi)) { + dev_err(dev, "%s: Bad context! (%llu)\n", __func__, ctxid); + rc = -EINVAL; + goto err1; + } + + rhte = rhte_checkout(ctxi, lli); + if (unlikely(!rhte)) { + dev_err(dev, "%s: too many opens for this context\n", __func__); + rc = -EMFILE; /* too many opens */ + goto err1; + } + + rsrc_handle = (rhte - ctxi->rht_start); + + /* Populate RHT format 0 */ + rhte->nmask = MC_RHT_NMASK; + rhte->fp = SISL_RHT_FP(0U, ctxi->rht_perms); + + /* Resize even if requested size is 0 */ + marshal_virt_to_resize(virt, &resize); + resize.rsrc_handle = rsrc_handle; + rc = _cxlflash_vlun_resize(sdev, ctxi, &resize); + if (rc) { + dev_err(dev, "%s: resize failed rc %d\n", __func__, rc); + goto err2; + } + last_lba = resize.last_lba; + + if (virt->hdr.flags & DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME) + ctxi->rht_needs_ws[rsrc_handle] = true; + + virt->hdr.return_flags = 0; + virt->last_lba = last_lba; + virt->rsrc_handle = rsrc_handle; + +out: + if (likely(ctxi)) + put_context(ctxi); + pr_debug("%s: returning handle 0x%llx rc=%d llba %lld\n", + __func__, rsrc_handle, rc, last_lba); + return rc; + +err2: + rhte_checkin(ctxi, rhte); +err1: + cxlflash_lun_detach(gli); + goto out; +err0: + /* Special common cleanup prior to successful LUN attach */ + cxlflash_ba_terminate(&gli->blka.ba_lun); + mutex_unlock(&gli->mutex); + goto out; +} + +/** + * clone_lxt() - copies translation tables from source to destination RHTE + * @afu: AFU associated with the host. + * @blka: Block allocator associated with LUN. + * @ctxid: Context ID of context owning the RHTE. + * @rhndl: Resource handle associated with the RHTE. + * @rhte: Destination resource handle entry (RHTE). + * @rhte_src: Source resource handle entry (RHTE). + * + * Return: 0 on success, -errno on failure + */ +static int clone_lxt(struct afu *afu, + struct blka *blka, + ctx_hndl_t ctxid, + res_hndl_t rhndl, + struct sisl_rht_entry *rhte, + struct sisl_rht_entry *rhte_src) +{ + struct sisl_lxt_entry *lxt; + u32 ngrps; + u64 aun; /* chunk# allocated by block allocator */ + int i, j; + + ngrps = LXT_NUM_GROUPS(rhte_src->lxt_cnt); + + if (ngrps) { + /* allocate new LXTs for clone */ + lxt = kzalloc((sizeof(*lxt) * LXT_GROUP_SIZE * ngrps), + GFP_KERNEL); + if (unlikely(!lxt)) + return -ENOMEM; + + /* copy over */ + memcpy(lxt, rhte_src->lxt_start, + (sizeof(*lxt) * rhte_src->lxt_cnt)); + + /* clone the LBAs in block allocator via ref_cnt */ + mutex_lock(&blka->mutex); + for (i = 0; i < rhte_src->lxt_cnt; i++) { + aun = (lxt[i].rlba_base >> MC_CHUNK_SHIFT); + if (ba_clone(&blka->ba_lun, aun) == -1ULL) { + /* free the clones already made */ + for (j = 0; j < i; j++) { + aun = (lxt[j].rlba_base >> + MC_CHUNK_SHIFT); + ba_free(&blka->ba_lun, aun); + } + + mutex_unlock(&blka->mutex); + kfree(lxt); + return -EIO; + } + } + mutex_unlock(&blka->mutex); + } else { + lxt = NULL; + } + + /* + * The following sequence is prescribed in the SISlite spec + * for syncing up with the AFU when adding LXT entries. + */ + dma_wmb(); /* Make LXT updates are visible */ + + rhte->lxt_start = lxt; + dma_wmb(); /* Make RHT entry's LXT table update visible */ + + rhte->lxt_cnt = rhte_src->lxt_cnt; + dma_wmb(); /* Make RHT entry's LXT table size update visible */ + + cxlflash_afu_sync(afu, ctxid, rhndl, AFU_LW_SYNC); + + pr_debug("%s: returning\n", __func__); + return 0; +} + +/** + * cxlflash_disk_clone() - clone a context by making snapshot of another + * @sdev: SCSI device associated with LUN owning virtual LUN. + * @clone: Clone ioctl data structure. + * + * This routine effectively performs cxlflash_disk_open operation for each + * in-use virtual resource in the source context. Note that the destination + * context must be in pristine state and cannot have any resource handles + * open at the time of the clone. + * + * Return: 0 on success, -errno on failure + */ +int cxlflash_disk_clone(struct scsi_device *sdev, + struct dk_cxlflash_clone *clone) +{ + struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)sdev->host->hostdata; + struct llun_info *lli = sdev->hostdata; + struct glun_info *gli = lli->parent; + struct blka *blka = &gli->blka; + struct afu *afu = cfg->afu; + struct dk_cxlflash_release release = { { 0 }, 0 }; + + struct ctx_info *ctxi_src = NULL, + *ctxi_dst = NULL; + struct lun_access *lun_access_src, *lun_access_dst; + u32 perms; + u64 ctxid_src = DECODE_CTXID(clone->context_id_src), + ctxid_dst = DECODE_CTXID(clone->context_id_dst), + rctxid_src = clone->context_id_src, + rctxid_dst = clone->context_id_dst; + int adap_fd_src = clone->adap_fd_src; + int i, j; + int rc = 0; + bool found; + LIST_HEAD(sidecar); + + pr_debug("%s: ctxid_src=%llu ctxid_dst=%llu adap_fd_src=%d\n", + __func__, ctxid_src, ctxid_dst, adap_fd_src); + + /* Do not clone yourself */ + if (unlikely(rctxid_src == rctxid_dst)) { + rc = -EINVAL; + goto out; + } + + if (unlikely(gli->mode != MODE_VIRTUAL)) { + rc = -EINVAL; + pr_debug("%s: Clone not supported on physical LUNs! (%d)\n", + __func__, gli->mode); + goto out; + } + + ctxi_src = get_context(cfg, rctxid_src, lli, CTX_CTRL_CLONE); + ctxi_dst = get_context(cfg, rctxid_dst, lli, 0); + if (unlikely(!ctxi_src || !ctxi_dst)) { + pr_debug("%s: Bad context! (%llu,%llu)\n", __func__, + ctxid_src, ctxid_dst); + rc = -EINVAL; + goto out; + } + + if (unlikely(adap_fd_src != ctxi_src->lfd)) { + pr_debug("%s: Invalid source adapter fd! (%d)\n", + __func__, adap_fd_src); + rc = -EINVAL; + goto out; + } + + /* Verify there is no open resource handle in the destination context */ + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) + if (ctxi_dst->rht_start[i].nmask != 0) { + rc = -EINVAL; + goto out; + } + + /* Clone LUN access list */ + list_for_each_entry(lun_access_src, &ctxi_src->luns, list) { + found = false; + list_for_each_entry(lun_access_dst, &ctxi_dst->luns, list) + if (lun_access_dst->sdev == lun_access_src->sdev) { + found = true; + break; + } + + if (!found) { + lun_access_dst = kzalloc(sizeof(*lun_access_dst), + GFP_KERNEL); + if (unlikely(!lun_access_dst)) { + pr_err("%s: Unable to allocate lun_access!\n", + __func__); + rc = -ENOMEM; + goto out; + } + + *lun_access_dst = *lun_access_src; + list_add(&lun_access_dst->list, &sidecar); + } + } + + if (unlikely(!ctxi_src->rht_out)) { + pr_debug("%s: Nothing to clone!\n", __func__); + goto out_success; + } + + /* User specified permission on attach */ + perms = ctxi_dst->rht_perms; + + /* + * Copy over checked-out RHT (and their associated LXT) entries by + * hand, stopping after we've copied all outstanding entries and + * cleaning up if the clone fails. + * + * Note: This loop is equivalent to performing cxlflash_disk_open and + * cxlflash_vlun_resize. As such, LUN accounting needs to be taken into + * account by attaching after each successful RHT entry clone. In the + * event that a clone failure is experienced, the LUN detach is handled + * via the cleanup performed by _cxlflash_disk_release. + */ + for (i = 0; i < MAX_RHT_PER_CONTEXT; i++) { + if (ctxi_src->rht_out == ctxi_dst->rht_out) + break; + if (ctxi_src->rht_start[i].nmask == 0) + continue; + + /* Consume a destination RHT entry */ + ctxi_dst->rht_out++; + ctxi_dst->rht_start[i].nmask = ctxi_src->rht_start[i].nmask; + ctxi_dst->rht_start[i].fp = + SISL_RHT_FP_CLONE(ctxi_src->rht_start[i].fp, perms); + ctxi_dst->rht_lun[i] = ctxi_src->rht_lun[i]; + + rc = clone_lxt(afu, blka, ctxid_dst, i, + &ctxi_dst->rht_start[i], + &ctxi_src->rht_start[i]); + if (rc) { + marshal_clone_to_rele(clone, &release); + for (j = 0; j < i; j++) { + release.rsrc_handle = j; + _cxlflash_disk_release(sdev, ctxi_dst, + &release); + } + + /* Put back the one we failed on */ + rhte_checkin(ctxi_dst, &ctxi_dst->rht_start[i]); + goto err; + } + + cxlflash_lun_attach(gli, gli->mode, false); + } + +out_success: + list_splice(&sidecar, &ctxi_dst->luns); + sys_close(adap_fd_src); + + /* fall through */ +out: + if (ctxi_src) + put_context(ctxi_src); + if (ctxi_dst) + put_context(ctxi_dst); + pr_debug("%s: returning rc=%d\n", __func__, rc); + return rc; + +err: + list_for_each_entry_safe(lun_access_src, lun_access_dst, &sidecar, list) + kfree(lun_access_src); + goto out; +} diff --git a/drivers/scsi/cxlflash/vlun.h b/drivers/scsi/cxlflash/vlun.h new file mode 100644 index 0000000000000..8b29a74946e4b --- /dev/null +++ b/drivers/scsi/cxlflash/vlun.h @@ -0,0 +1,86 @@ +/* + * CXL Flash Device Driver + * + * Written by: Manoj N. Kumar , IBM Corporation + * Matthew R. Ochs , IBM Corporation + * + * Copyright (C) 2015 IBM Corporation + * + * 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 _CXLFLASH_VLUN_H +#define _CXLFLASH_VLUN_H + +/* RHT - Resource Handle Table */ +#define MC_RHT_NMASK 16 /* in bits */ +#define MC_CHUNK_SHIFT MC_RHT_NMASK /* shift to go from LBA to chunk# */ + +#define HIBIT (BITS_PER_LONG - 1) + +#define MAX_AUN_CLONE_CNT 0xFF + +/* + * LXT - LBA Translation Table + * + * +-------+-------+-------+-------+-------+-------+-------+---+---+ + * | RLBA_BASE |LUN_IDX| P |SEL| + * +-------+-------+-------+-------+-------+-------+-------+---+---+ + * + * The LXT Entry contains the physical LBA where the chunk starts (RLBA_BASE). + * AFU ORes the low order bits from the virtual LBA (offset into the chunk) + * with RLBA_BASE. The result is the physical LBA to be sent to storage. + * The LXT Entry also contains an index to a LUN TBL and a bitmask of which + * outgoing (FC) * ports can be selected. The port select bit-mask is ANDed + * with a global port select bit-mask maintained by the driver. + * In addition, it has permission bits that are ANDed with the + * RHT permissions to arrive at the final permissions for the chunk. + * + * LXT tables are allocated dynamically in groups. This is done to avoid + * a malloc/free overhead each time the LXT has to grow or shrink. + * + * Based on the current lxt_cnt (used), it is always possible to know + * how many are allocated (used+free). The number of allocated entries is + * not stored anywhere. + * + * The LXT table is re-allocated whenever it needs to cross into another group. +*/ +#define LXT_GROUP_SIZE 8 +#define LXT_NUM_GROUPS(lxt_cnt) (((lxt_cnt) + 7)/8) /* alloc'ed groups */ +#define LXT_LUNIDX_SHIFT 8 /* LXT entry, shift for LUN index */ +#define LXT_PERM_SHIFT 4 /* LXT entry, shift for permission bits */ + +struct ba_lun_info { + u64 *lun_alloc_map; + u32 lun_bmap_size; + u32 total_aus; + u64 free_aun_cnt; + + /* indices to be used for elevator lookup of free map */ + u32 free_low_idx; + u32 free_curr_idx; + u32 free_high_idx; + + u8 *aun_clone_map; +}; + +struct ba_lun { + u64 lun_id; + u64 wwpn; + size_t lsize; /* LUN size in number of LBAs */ + size_t lba_size; /* LBA size in number of bytes */ + size_t au_size; /* Allocation Unit size in number of LBAs */ + struct ba_lun_info *ba_lun_handle; +}; + +/* Block Allocator */ +struct blka { + struct ba_lun ba_lun; + u64 nchunk; /* number of chunks */ + struct mutex mutex; +}; + +#endif /* ifndef _CXLFLASH_SUPERPIPE_H */ diff --git a/include/uapi/scsi/cxlflash_ioctl.h b/include/uapi/scsi/cxlflash_ioctl.h index 5707734065310..831351b2e6602 100644 --- a/include/uapi/scsi/cxlflash_ioctl.h +++ b/include/uapi/scsi/cxlflash_ioctl.h @@ -71,6 +71,17 @@ struct dk_cxlflash_udirect { __u64 reserved[8]; /* Reserved for future use */ }; +#define DK_CXLFLASH_UVIRTUAL_NEED_WRITE_SAME 0x8000000000000000ULL + +struct dk_cxlflash_uvirtual { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context to own virtual resources */ + __u64 lun_size; /* Requested size, in 4K blocks */ + __u64 rsrc_handle; /* Returned resource handle */ + __u64 last_lba; /* Returned last LBA of LUN */ + __u64 reserved[8]; /* Reserved for future use */ +}; + struct dk_cxlflash_release { struct dk_cxlflash_hdr hdr; /* Common fields */ __u64 context_id; /* Context owning resources */ @@ -78,6 +89,23 @@ struct dk_cxlflash_release { __u64 reserved[8]; /* Reserved for future use */ }; +struct dk_cxlflash_resize { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id; /* Context owning resources */ + __u64 rsrc_handle; /* Resource handle of LUN to resize */ + __u64 req_size; /* New requested size, in 4K blocks */ + __u64 last_lba; /* Returned last LBA of LUN */ + __u64 reserved[8]; /* Reserved for future use */ +}; + +struct dk_cxlflash_clone { + struct dk_cxlflash_hdr hdr; /* Common fields */ + __u64 context_id_src; /* Context to clone from */ + __u64 context_id_dst; /* Context to clone to */ + __u64 adap_fd_src; /* Source context adapter fd */ + __u64 reserved[8]; /* Reserved for future use */ +}; + #define DK_CXLFLASH_VERIFY_SENSE_LEN 18 #define DK_CXLFLASH_VERIFY_HINT_SENSE 0x8000000000000000ULL @@ -118,7 +146,10 @@ union cxlflash_ioctls { struct dk_cxlflash_attach attach; struct dk_cxlflash_detach detach; struct dk_cxlflash_udirect udirect; + struct dk_cxlflash_uvirtual uvirtual; struct dk_cxlflash_release release; + struct dk_cxlflash_resize resize; + struct dk_cxlflash_clone clone; struct dk_cxlflash_verify verify; struct dk_cxlflash_recover_afu recover_afu; struct dk_cxlflash_manage_lun manage_lun; @@ -136,5 +167,8 @@ union cxlflash_ioctls { #define DK_CXLFLASH_VERIFY CXL_IOWR(0x84, dk_cxlflash_verify) #define DK_CXLFLASH_RECOVER_AFU CXL_IOWR(0x85, dk_cxlflash_recover_afu) #define DK_CXLFLASH_MANAGE_LUN CXL_IOWR(0x86, dk_cxlflash_manage_lun) +#define DK_CXLFLASH_USER_VIRTUAL CXL_IOWR(0x87, dk_cxlflash_uvirtual) +#define DK_CXLFLASH_VLUN_RESIZE CXL_IOWR(0x88, dk_cxlflash_resize) +#define DK_CXLFLASH_VLUN_CLONE CXL_IOWR(0x89, dk_cxlflash_clone) #endif /* ifndef _CXLFLASH_IOCTL_H */ -- GitLab From 46c6d45d7875a0328258a574e376ae75f7b2a64b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Aug 2015 23:35:25 +0300 Subject: [PATCH 5091/7006] cxlflash: off by one bug in cxlflash_show_port_status() The > should be >= or we read one element past the end of the array. Fixes: c21e0bbfc485 ('cxlflash: Base support for IBM CXL Flash Adapter') Signed-off-by: Dan Carpenter Acked-by: Matthew R. Ochs Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 458ed838f83a1..fde2ba9342dcb 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -586,7 +586,7 @@ static ssize_t cxlflash_show_port_status(struct device *dev, u64 *fc_regs; rc = kstrtouint((attr->attr.name + 4), 10, &port); - if (rc || (port > NUM_FC_PORTS)) + if (rc || (port >= NUM_FC_PORTS)) return 0; fc_regs = &afu->afu_map->global.fc_regs[port][0]; -- GitLab From 4da74db0d9a6ffe053d3a3efa756906e0afc4cf7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Aug 2015 11:57:43 +0300 Subject: [PATCH 5092/7006] cxlflash: shift wrapping bug in afu_link_reset() "port_sel" is a u64 so the shifting should also be a 64 bit shift. Fixes: c21e0bbfc485 ('cxlflash: Base support for IBM CXL Flash Adapter') Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Acked-by: Matthew R. Ochs Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index fde2ba9342dcb..caa1d09dafec2 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -1248,7 +1248,7 @@ static void afu_link_reset(struct afu *afu, int port, u64 *fc_regs) /* first switch the AFU to the other links, if any */ port_sel = readq_be(&afu->afu_map->global.regs.afu_port_sel); - port_sel &= ~(1 << port); + port_sel &= ~(1ULL << port); writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); @@ -1265,7 +1265,7 @@ static void afu_link_reset(struct afu *afu, int port, u64 *fc_regs) __func__, port); /* switch back to include this port */ - port_sel |= (1 << port); + port_sel |= (1ULL << port); writeq_be(port_sel, &afu->afu_map->global.regs.afu_port_sel); cxlflash_afu_sync(afu, 0, 0, AFU_GSYNC); -- GitLab From 89576205de8a5b6c19a4b3bb25bd16484a567b4e Mon Sep 17 00:00:00 2001 From: "Matthew R. Ochs" Date: Wed, 26 Aug 2015 18:36:12 -0500 Subject: [PATCH 5093/7006] cxlflash: Remove unused variable from queuecommand The queuecommand routine has a local dev pointer used for the dev_* prints. The two prints that currently exist are tucked under a debug define and thus can be left out. Use the actual location instead of a local to avoid this warning. This patch is intended to be applied after the "CXL Flash Error Recovery and Superpipe" series. Signed-off-by: Matthew R. Ochs Signed-off-by: Manoj N. Kumar Reported-by: kbuild test robot Signed-off-by: James Bottomley --- drivers/scsi/cxlflash/main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index caa1d09dafec2..3e3ccf16e7c25 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -354,7 +354,6 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) struct cxlflash_cfg *cfg = (struct cxlflash_cfg *)host->hostdata; struct afu *afu = cfg->afu; struct pci_dev *pdev = cfg->dev; - struct device *dev = &cfg->dev->dev; struct afu_cmd *cmd; u32 port_sel = scp->device->channel + 1; int nseg, i, ncount; @@ -384,11 +383,13 @@ static int cxlflash_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scp) switch (cfg->state) { case STATE_LIMBO: - dev_dbg_ratelimited(dev, "%s: device in limbo!\n", __func__); + dev_dbg_ratelimited(&cfg->dev->dev, "%s: device in limbo!\n", + __func__); rc = SCSI_MLQUEUE_HOST_BUSY; goto out; case STATE_FAILTERM: - dev_dbg_ratelimited(dev, "%s: device has failed!\n", __func__); + dev_dbg_ratelimited(&cfg->dev->dev, "%s: device has failed!\n", + __func__); scp->result = (DID_NO_CONNECT << 16); scp->scsi_done(scp); rc = 0; -- GitLab From a6897f39660cc07fa78b4459d82f12b07abb50b1 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Tue, 25 Aug 2015 11:04:48 +0530 Subject: [PATCH 5094/7006] cxl: Release irqs if memory allocation fails This minor patch plugs a potential irq leak in case of a memory allocation failure inside function the afu_allocate_irqs. Presently the irqs allocated to the context gets leaked if allocation of either one of context irq_bitmap or irq_names fails. Signed-off-by: Vaibhav Jain Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/irq.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index 72bf45ae38060..583b42afeda23 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -430,6 +430,9 @@ int afu_allocate_irqs(struct cxl_context *ctx, u32 count) int rc, r, i, j = 1; struct cxl_irq_name *irq_name; + /* Initialize the list head to hold irq names */ + INIT_LIST_HEAD(&ctx->irq_names); + if ((rc = cxl_alloc_irq_ranges(&ctx->irqs, ctx->afu->adapter, count))) return rc; @@ -441,13 +444,12 @@ int afu_allocate_irqs(struct cxl_context *ctx, u32 count) ctx->irq_bitmap = kcalloc(BITS_TO_LONGS(count), sizeof(*ctx->irq_bitmap), GFP_KERNEL); if (!ctx->irq_bitmap) - return -ENOMEM; + goto out; /* * Allocate names first. If any fail, bail out before allocating * actual hardware IRQs. */ - INIT_LIST_HEAD(&ctx->irq_names); for (r = 1; r < CXL_IRQ_RANGES; r++) { for (i = 0; i < ctx->irqs.range[r]; i++) { irq_name = kmalloc(sizeof(struct cxl_irq_name), @@ -469,6 +471,7 @@ int afu_allocate_irqs(struct cxl_context *ctx, u32 count) return 0; out: + cxl_release_irq_ranges(&ctx->irqs, ctx->afu->adapter); afu_irq_name_free(ctx); return -ENOMEM; } -- GitLab From 9d8e27673c45927fee9e7d8992ffb325a6b0b0e4 Mon Sep 17 00:00:00 2001 From: Daniel Axtens Date: Fri, 21 Aug 2015 17:25:15 +1000 Subject: [PATCH 5095/7006] cxl: Remove racy attempt to force EEH invocation in reset cxl_reset currently PERSTs the slot, and then repeatedly tries to read MMIO space in order to kick off EEH. There are 2 problems with this: it's unnecessary, and it's racy. It's unnecessary because the PERST will bring down the PHB link. That will be picked up by the CAPP, which will send out an HMI. Skiboot, noticing an HMI from the CAPP, will send an OPAL notification to the kernel, which will trigger EEH recovery. It's also racy: the EEH recovery triggered by the CAPP will eventually cause the MMIO space to have its mapping invalidated and the pointer NULLed out. This races with our attempt to read the MMIO space. This is causing OOPSes in testing. Simply drop all the attempts to force EEH detection, and trust that Skiboot will send the notification and that we'll act on it. The Skiboot code to send the EEH notification has been in Skiboot for as long as CAPP recovery has been supported, so we don't need to worry about breaking obscure setups with ancient firmware. Cc: Ryan Grimm Cc: stable@vger.kernel.org Fixes: 62fa19d4b4fd ("cxl: Add ability to reset the card") Signed-off-by: Daniel Axtens Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 273374c507f7a..6ca7c3d0ef9b4 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -876,8 +876,6 @@ int cxl_reset(struct cxl *adapter) { struct pci_dev *dev = to_pci_dev(adapter->dev.parent); int rc; - int i; - u32 val; if (adapter->perst_same_image) { dev_warn(&dev->dev, @@ -895,20 +893,6 @@ int cxl_reset(struct cxl *adapter) return rc; } - /* the PERST done above fences the PHB. So, reset depends on EEH - * to unbind the driver, tell Sapphire to reinit the PHB, and rebind - * the driver. Do an mmio read explictly to ensure EEH notices the - * fenced PHB. Retry for a few seconds before giving up. */ - i = 0; - while (((val = mmio_read32be(adapter->p1_mmio)) != 0xffffffff) && - (i < 5)) { - msleep(500); - i++; - } - - if (val != 0xffffffff) - dev_err(&dev->dev, "cxl: PERST failed to trigger EEH\n"); - return rc; } -- GitLab From 6ee5c61535a2df807069145970d3e7fa492a3fac Mon Sep 17 00:00:00 2001 From: Keith Mange Date: Thu, 13 Aug 2015 08:43:46 -0700 Subject: [PATCH 5096/7006] storvsc: Rather than look for sets of specific protocol versions, make decisions based on ranges. Rather than look for sets of specific protocol versions, make decisions based on ranges. This will be safer and require fewer changes going forward as we add more storage protocol versions. Tested-by: Alex Ng Signed-off-by: Keith Mange Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index dbc9d9a1c89d4..05f6f970826ed 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -981,8 +981,7 @@ static int storvsc_channel_init(struct hv_device *device) * support multi-channel. */ max_chns = vstor_packet->storage_channel_properties.max_channel_cnt; - if ((vmbus_proto_version != VERSION_WIN7) && - (vmbus_proto_version != VERSION_WS2008)) { + if (vmbus_proto_version >= VERSION_WIN8) { if (vstor_packet->storage_channel_properties.flags & STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL) process_sub_channels = true; @@ -1759,9 +1758,7 @@ static int storvsc_probe(struct hv_device *device, * set state to properly communicate with the host. */ - switch (vmbus_proto_version) { - case VERSION_WS2008: - case VERSION_WIN7: + if (vmbus_proto_version < VERSION_WIN8) { sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); vmstor_current_major = VMSTOR_WIN7_MAJOR; @@ -1769,8 +1766,7 @@ static int storvsc_probe(struct hv_device *device, max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET; max_targets = STORVSC_IDE_MAX_TARGETS; max_channels = STORVSC_IDE_MAX_CHANNELS; - break; - default: + } else { sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = 0; vmstor_current_major = VMSTOR_WIN8_MAJOR; @@ -1784,7 +1780,6 @@ static int storvsc_probe(struct hv_device *device, * VCPUs in the guest. */ max_sub_channels = (num_cpus / storvsc_vcpus_per_sub_channel); - break; } scsi_driver.can_queue = (max_outstanding_req_per_channel * -- GitLab From 2492fd7a60270b81b7ed491745fd595a26841a45 Mon Sep 17 00:00:00 2001 From: Keith Mange Date: Thu, 13 Aug 2015 08:43:47 -0700 Subject: [PATCH 5097/7006] storvsc: Use a single value to track protocol versions Use a single value to track protocol versions to simplify comparisons and to be consistent with vmbus version tracking. Tested-by: Alex Ng Signed-off-by: Keith Mange Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 35 +++++++++-------------------------- 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 05f6f970826ed..367f66cc1f072 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -58,12 +58,11 @@ * Win8: 5.1 */ +#define VMSTOR_PROTO_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ + (((MINOR_) & 0xff))) -#define VMSTOR_WIN7_MAJOR 4 -#define VMSTOR_WIN7_MINOR 2 - -#define VMSTOR_WIN8_MAJOR 5 -#define VMSTOR_WIN8_MINOR 1 +#define VMSTOR_PROTO_VERSION_WIN7 VMSTOR_PROTO_VERSION(4, 2) +#define VMSTOR_PROTO_VERSION_WIN8 VMSTOR_PROTO_VERSION(5, 1) /* Packet structure describing virtual storage requests. */ @@ -161,8 +160,7 @@ static int sense_buffer_size; */ static int vmscsi_size_delta; -static int vmstor_current_major; -static int vmstor_current_minor; +static int vmstor_proto_version; struct vmscsi_win8_extension { /* @@ -474,18 +472,6 @@ done: kfree(wrk); } -/* - * Major/minor macros. Minor version is in LSB, meaning that earlier flat - * version numbers will be interpreted as "0.x" (i.e., 1 becomes 0.1). - */ - -static inline u16 storvsc_get_version(u8 major, u8 minor) -{ - u16 version; - - version = ((major << 8) | minor); - return version; -} /* * We can get incoming messages from the host that are not in response to @@ -923,8 +909,7 @@ static int storvsc_channel_init(struct hv_device *device) vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->version.major_minor = - storvsc_get_version(vmstor_current_major, vmstor_current_minor); + vstor_packet->version.major_minor = vmstor_proto_version; /* * The revision number is only used in Windows; set it to 0. @@ -1555,7 +1540,7 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd) u32 payload_sz; u32 length; - if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) { + if (vmstor_proto_version <= VMSTOR_PROTO_VERSION_WIN8) { /* * On legacy hosts filter unimplemented commands. * Future hosts are expected to correctly handle @@ -1761,16 +1746,14 @@ static int storvsc_probe(struct hv_device *device, if (vmbus_proto_version < VERSION_WIN8) { sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); - vmstor_current_major = VMSTOR_WIN7_MAJOR; - vmstor_current_minor = VMSTOR_WIN7_MINOR; + vmstor_proto_version = VMSTOR_PROTO_VERSION_WIN7; max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET; max_targets = STORVSC_IDE_MAX_TARGETS; max_channels = STORVSC_IDE_MAX_CHANNELS; } else { sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = 0; - vmstor_current_major = VMSTOR_WIN8_MAJOR; - vmstor_current_minor = VMSTOR_WIN8_MINOR; + vmstor_proto_version = VMSTOR_PROTO_VERSION_WIN8; max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET; max_targets = STORVSC_MAX_TARGETS; max_channels = STORVSC_MAX_CHANNELS; -- GitLab From 1a3631081d88180f5cc421711e40b4aecff8618e Mon Sep 17 00:00:00 2001 From: Keith Mange Date: Thu, 13 Aug 2015 08:43:48 -0700 Subject: [PATCH 5098/7006] storvsc: Untangle the storage protocol negotiation from the vmbus protocol negotiation. Currently we are making decisions based on vmbus protocol versions that have been negotiated; use storage potocol versions instead. [jejb: fold ARRAY_SIZE conversion suggested by Johannes Thumshirn make vmstor_protocol static] Tested-by: Alex Ng Signed-off-by: Keith Mange Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 108 +++++++++++++++++++++++++++++-------- 1 file changed, 86 insertions(+), 22 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 367f66cc1f072..d6a42c0000481 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -56,14 +56,18 @@ * V1 RC > 2008/1/31: 2.0 * Win7: 4.2 * Win8: 5.1 + * Win8.1: 6.0 + * Win10: 6.2 */ #define VMSTOR_PROTO_VERSION(MAJOR_, MINOR_) ((((MAJOR_) & 0xff) << 8) | \ (((MINOR_) & 0xff))) +#define VMSTOR_PROTO_VERSION_WIN6 VMSTOR_PROTO_VERSION(2, 0) #define VMSTOR_PROTO_VERSION_WIN7 VMSTOR_PROTO_VERSION(4, 2) #define VMSTOR_PROTO_VERSION_WIN8 VMSTOR_PROTO_VERSION(5, 1) - +#define VMSTOR_PROTO_VERSION_WIN8_1 VMSTOR_PROTO_VERSION(6, 0) +#define VMSTOR_PROTO_VERSION_WIN10 VMSTOR_PROTO_VERSION(6, 2) /* Packet structure describing virtual storage requests. */ enum vstor_packet_operation { @@ -204,6 +208,45 @@ struct vmscsi_request { } __attribute((packed)); +/* + * The list of storage protocols in order of preference. + */ +struct vmstor_protocol { + int protocol_version; + int sense_buffer_size; + int vmscsi_size_delta; +}; + + +static const struct vmstor_protocol vmstor_protocols[] = { + { + VMSTOR_PROTO_VERSION_WIN10, + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, + 0 + }, + { + VMSTOR_PROTO_VERSION_WIN8_1, + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, + 0 + }, + { + VMSTOR_PROTO_VERSION_WIN8, + POST_WIN7_STORVSC_SENSE_BUFFER_SIZE, + 0 + }, + { + VMSTOR_PROTO_VERSION_WIN7, + PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE, + sizeof(struct vmscsi_win8_extension), + }, + { + VMSTOR_PROTO_VERSION_WIN6, + PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE, + sizeof(struct vmscsi_win8_extension), + } +}; + + /* * This structure is sent during the intialization phase to get the different * properties of the channel. @@ -864,7 +907,7 @@ static int storvsc_channel_init(struct hv_device *device) struct storvsc_device *stor_device; struct storvsc_cmd_request *request; struct vstor_packet *vstor_packet; - int ret, t; + int ret, t, i; int max_chns; bool process_sub_channels = false; @@ -904,36 +947,59 @@ static int storvsc_channel_init(struct hv_device *device) goto cleanup; - /* reuse the packet for version range supported */ - memset(vstor_packet, 0, sizeof(struct vstor_packet)); - vstor_packet->operation = VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; - vstor_packet->flags = REQUEST_COMPLETION_FLAG; + for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) { + /* reuse the packet for version range supported */ + memset(vstor_packet, 0, sizeof(struct vstor_packet)); + vstor_packet->operation = + VSTOR_OPERATION_QUERY_PROTOCOL_VERSION; + vstor_packet->flags = REQUEST_COMPLETION_FLAG; - vstor_packet->version.major_minor = vmstor_proto_version; + vstor_packet->version.major_minor = + vmstor_protocols[i].protocol_version; - /* - * The revision number is only used in Windows; set it to 0. - */ - vstor_packet->version.revision = 0; + /* + * The revision number is only used in Windows; set it to 0. + */ + vstor_packet->version.revision = 0; - ret = vmbus_sendpacket(device->channel, vstor_packet, + ret = vmbus_sendpacket(device->channel, vstor_packet, (sizeof(struct vstor_packet) - vmscsi_size_delta), (unsigned long)request, VM_PKT_DATA_INBAND, VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); - if (ret != 0) - goto cleanup; + if (ret != 0) + goto cleanup; - t = wait_for_completion_timeout(&request->wait_event, 5*HZ); - if (t == 0) { - ret = -ETIMEDOUT; - goto cleanup; + t = wait_for_completion_timeout(&request->wait_event, 5*HZ); + if (t == 0) { + ret = -ETIMEDOUT; + goto cleanup; + } + + if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO) { + ret = -EINVAL; + goto cleanup; + } + + if (vstor_packet->status == 0) { + vmstor_proto_version = + vmstor_protocols[i].protocol_version; + + sense_buffer_size = + vmstor_protocols[i].sense_buffer_size; + + vmscsi_size_delta = + vmstor_protocols[i].vmscsi_size_delta; + + break; + } } - if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) + if (vstor_packet->status != 0) { + ret = -EINVAL; goto cleanup; + } memset(vstor_packet, 0, sizeof(struct vstor_packet)); @@ -1746,14 +1812,12 @@ static int storvsc_probe(struct hv_device *device, if (vmbus_proto_version < VERSION_WIN8) { sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); - vmstor_proto_version = VMSTOR_PROTO_VERSION_WIN7; max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET; max_targets = STORVSC_IDE_MAX_TARGETS; max_channels = STORVSC_IDE_MAX_CHANNELS; } else { sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; vmscsi_size_delta = 0; - vmstor_proto_version = VMSTOR_PROTO_VERSION_WIN8; max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET; max_targets = STORVSC_MAX_TARGETS; max_channels = STORVSC_MAX_CHANNELS; -- GitLab From cb11feada9c049bc633831d3a5dcc50163f13b5e Mon Sep 17 00:00:00 2001 From: Keith Mange Date: Thu, 13 Aug 2015 08:43:49 -0700 Subject: [PATCH 5099/7006] storvsc: use correct defaults for values determined by protocol negotiation Use correct defaults for values determined by protocol negotiation, instead of resetting them with every scsi controller. Tested-by: Alex Ng Signed-off-by: Keith Mange Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index d6a42c0000481..8937ce92f8752 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -151,19 +151,17 @@ struct hv_fc_wwn_packet { /* * Sense buffer size changed in win8; have a run-time - * variable to track the size we should use. + * variable to track the size we should use. This value will + * likely change during protocol negotiation but it is valid + * to start by assuming pre-Win8. */ -static int sense_buffer_size; +static int sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; /* - * The size of the vmscsi_request has changed in win8. The - * additional size is because of new elements added to the - * structure. These elements are valid only when we are talking - * to a win8 host. - * Track the correction to size we need to apply. - */ - -static int vmscsi_size_delta; + * The storage protocol version is determined during the + * initial exchange with the host. It will indicate which + * storage functionality is available in the host. +*/ static int vmstor_proto_version; struct vmscsi_win8_extension { @@ -208,6 +206,17 @@ struct vmscsi_request { } __attribute((packed)); +/* + * The size of the vmscsi_request has changed in win8. The + * additional size is because of new elements added to the + * structure. These elements are valid only when we are talking + * to a win8 host. + * Track the correction to size we need to apply. This value + * will likely change during protocol negotiation but it is + * valid to start by assuming pre-Win8. + */ +static int vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); + /* * The list of storage protocols in order of preference. */ @@ -1810,14 +1819,10 @@ static int storvsc_probe(struct hv_device *device, */ if (vmbus_proto_version < VERSION_WIN8) { - sense_buffer_size = PRE_WIN8_STORVSC_SENSE_BUFFER_SIZE; - vmscsi_size_delta = sizeof(struct vmscsi_win8_extension); max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET; max_targets = STORVSC_IDE_MAX_TARGETS; max_channels = STORVSC_IDE_MAX_CHANNELS; } else { - sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE; - vmscsi_size_delta = 0; max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET; max_targets = STORVSC_MAX_TARGETS; max_channels = STORVSC_MAX_CHANNELS; -- GitLab From e6c4bc66842752110a66746e2d044fafc01e4800 Mon Sep 17 00:00:00 2001 From: Keith Mange Date: Thu, 13 Aug 2015 08:43:50 -0700 Subject: [PATCH 5100/7006] storvsc: use storage protocol version to determine storage capabilities Use storage protocol version instead of vmbus protocol version when determining storage capabilities. Tested-by: Alex Ng Signed-off-by: Keith Mange Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 8937ce92f8752..97219a0bb2803 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1041,7 +1041,7 @@ static int storvsc_channel_init(struct hv_device *device) * support multi-channel. */ max_chns = vstor_packet->storage_channel_properties.max_channel_cnt; - if (vmbus_proto_version >= VERSION_WIN8) { + if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN8) { if (vstor_packet->storage_channel_properties.flags & STORAGE_CHANNEL_SUPPORTS_MULTI_CHANNEL) process_sub_channels = true; @@ -1483,9 +1483,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice) * if the device is a MSFT virtual device. */ if (!strncmp(sdevice->vendor, "Msft", 4)) { - switch (vmbus_proto_version) { - case VERSION_WIN8: - case VERSION_WIN8_1: + switch (vmstor_proto_version) { + case VMSTOR_PROTO_VERSION_WIN8: + case VMSTOR_PROTO_VERSION_WIN8_1: sdevice->scsi_level = SCSI_SPC_3; break; } -- GitLab From b95f5be09069526cf53705acbc1e22600f3f550b Mon Sep 17 00:00:00 2001 From: Keith Mange Date: Thu, 13 Aug 2015 08:43:51 -0700 Subject: [PATCH 5101/7006] storvsc: Allow write_same when host is windows 10 Allow WRITE_SAME for Windows10 and above hosts. Tested-by: Alex Ng Signed-off-by: Keith Mange Signed-off-by: K. Y. Srinivasan Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index 97219a0bb2803..cbb1bd1e020c4 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -1480,7 +1480,8 @@ static int storvsc_device_configure(struct scsi_device *sdevice) /* * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3 - * if the device is a MSFT virtual device. + * if the device is a MSFT virtual device. If the host is + * WIN10 or newer, allow write_same. */ if (!strncmp(sdevice->vendor, "Msft", 4)) { switch (vmstor_proto_version) { @@ -1489,6 +1490,9 @@ static int storvsc_device_configure(struct scsi_device *sdevice) sdevice->scsi_level = SCSI_SPC_3; break; } + + if (vmstor_proto_version >= VMSTOR_PROTO_VERSION_WIN10) + sdevice->no_write_same = 0; } return 0; -- GitLab From 111f2d15b543e15c1e0ee89745fae84e3eb91932 Mon Sep 17 00:00:00 2001 From: "K. Y. Srinivasan" Date: Thu, 13 Aug 2015 08:43:52 -0700 Subject: [PATCH 5102/7006] storvsc: Set the error code correctly in failure conditions In the function storvsc_channel_init(), error code was not getting set correctly in some of the failure cases. Fix this issue. Signed-off-by: K. Y. Srinivasan Reported-by: Dan Carpenter Signed-off-by: James Bottomley --- drivers/scsi/storvsc_drv.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c index cbb1bd1e020c4..40c43aeb4ff36 100644 --- a/drivers/scsi/storvsc_drv.c +++ b/drivers/scsi/storvsc_drv.c @@ -952,8 +952,10 @@ static int storvsc_channel_init(struct hv_device *device) } if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) + vstor_packet->status != 0) { + ret = -EINVAL; goto cleanup; + } for (i = 0; i < ARRAY_SIZE(vmstor_protocols); i++) { @@ -1032,8 +1034,10 @@ static int storvsc_channel_init(struct hv_device *device) } if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) + vstor_packet->status != 0) { + ret = -EINVAL; goto cleanup; + } /* * Check to see if multi-channel support is there. @@ -1070,8 +1074,10 @@ static int storvsc_channel_init(struct hv_device *device) } if (vstor_packet->operation != VSTOR_OPERATION_COMPLETE_IO || - vstor_packet->status != 0) + vstor_packet->status != 0) { + ret = -EINVAL; goto cleanup; + } if (process_sub_channels) handle_multichannel_storage(device, max_chns); -- GitLab From 9f55bca2b82a77a3cc3204900db2fc40ab30019e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Aug 2015 12:20:29 +0300 Subject: [PATCH 5103/7006] aic94xx: set an error code on failure We recently did some cleanup here and now the static checkers notice that there is a missing error code when ioremap() fails. Let's set it to -ENOMEM. Signed-off-by: Dan Carpenter Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/aic94xx_init.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c index 4b135cca42a12..31e8576cbaab4 100644 --- a/drivers/scsi/aic94xx/aic94xx_init.c +++ b/drivers/scsi/aic94xx/aic94xx_init.c @@ -109,6 +109,7 @@ static int asd_map_memio(struct asd_ha_struct *asd_ha) if (!io_handle->addr) { asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1, pci_name(asd_ha->pcidev)); + err = -ENOMEM; goto Err_unreq; } } -- GitLab From 76c28f1fcfeb42b47f798fe498351ee1d60086ae Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 24 Aug 2015 10:26:03 -0700 Subject: [PATCH 5104/7006] target/iscsi: Fix np_ip bracket issue by removing np_ip Revert commit 1997e6259, which causes double brackets on ipv6 inaddr_any addresses. Since we have np_sockaddr, if we need a textual representation we can use "%pISc". Change iscsit_add_network_portal() and iscsit_add_np() signatures to remove *ip_str parameter. Fix and extend some comments earlier in the function. Tested to work for :: and ::1 via iscsiadm, previously :: failed, see https://bugzilla.redhat.com/show_bug.cgi?id=1249107 . CC: stable@vger.kernel.org Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target.c | 33 ++++++++++---------- drivers/target/iscsi/iscsi_target.h | 2 +- drivers/target/iscsi/iscsi_target_configfs.c | 14 ++++----- drivers/target/iscsi/iscsi_target_login.c | 8 ++--- drivers/target/iscsi/iscsi_target_tpg.c | 15 +++++---- drivers/target/iscsi/iscsi_target_tpg.h | 2 +- include/target/iscsi/iscsi_target_core.h | 1 - 7 files changed, 36 insertions(+), 39 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index e55f49c7c847c..d75eeb5ce13a8 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -341,7 +341,6 @@ static struct iscsi_np *iscsit_get_np( struct iscsi_np *iscsit_add_np( struct __kernel_sockaddr_storage *sockaddr, - char *ip_str, int network_transport) { struct sockaddr_in *sock_in; @@ -370,11 +369,9 @@ struct iscsi_np *iscsit_add_np( np->np_flags |= NPF_IP_NETWORK; if (sockaddr->ss_family == AF_INET6) { sock_in6 = (struct sockaddr_in6 *)sockaddr; - snprintf(np->np_ip, IPV6_ADDRESS_SPACE, "%s", ip_str); np->np_port = ntohs(sock_in6->sin6_port); } else { sock_in = (struct sockaddr_in *)sockaddr; - sprintf(np->np_ip, "%s", ip_str); np->np_port = ntohs(sock_in->sin_port); } @@ -411,8 +408,8 @@ struct iscsi_np *iscsit_add_np( list_add_tail(&np->np_list, &g_np_list); mutex_unlock(&np_lock); - pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", - np->np_ip, np->np_port, np->np_transport->name); + pr_debug("CORE[0] - Added Network Portal: %pISc:%hu on %s\n", + &np->np_sockaddr, np->np_port, np->np_transport->name); return np; } @@ -481,8 +478,8 @@ int iscsit_del_np(struct iscsi_np *np) list_del(&np->np_list); mutex_unlock(&np_lock); - pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", - np->np_ip, np->np_port, np->np_transport->name); + pr_debug("CORE[0] - Removed Network Portal: %pISc:%hu on %s\n", + &np->np_sockaddr, np->np_port, np->np_transport->name); iscsit_put_transport(np->np_transport); kfree(np); @@ -3463,7 +3460,6 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, tpg_np_list) { struct iscsi_np *np = tpg_np->tpg_np; bool inaddr_any = iscsit_check_inaddr_any(np); - char *fmt_str; if (np->np_network_transport != network_transport) continue; @@ -3491,15 +3487,18 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, } } - if (np->np_sockaddr.ss_family == AF_INET6) - fmt_str = "TargetAddress=[%s]:%hu,%hu"; - else - fmt_str = "TargetAddress=%s:%hu,%hu"; - - len = sprintf(buf, fmt_str, - inaddr_any ? conn->local_ip : np->np_ip, - np->np_port, - tpg->tpgt); + if (inaddr_any) { + len = sprintf(buf, "TargetAddress=" + "%s:%hu,%hu", + conn->local_ip, + np->np_port, + tpg->tpgt); + } else { + len = sprintf(buf, "TargetAddress=" + "%pISpc,%hu", + &np->np_sockaddr, + tpg->tpgt); + } len += 1; if ((len + payload_len) > buffer_len) { diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index 7d0f9c00d9c25..d294f030a0978 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -13,7 +13,7 @@ extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *, extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, struct iscsi_np *, int); extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, - char *, int); + int); extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, struct iscsi_portal_group *, bool); extern int iscsit_del_np(struct iscsi_np *); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 48f708bc101d2..ad6a889dadc0c 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -99,7 +99,7 @@ static ssize_t lio_target_np_store_sctp( * Use existing np->np_sockaddr for SCTP network portal reference */ tpg_np_sctp = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr, - np->np_ip, tpg_np, ISCSI_SCTP_TCP); + tpg_np, ISCSI_SCTP_TCP); if (!tpg_np_sctp || IS_ERR(tpg_np_sctp)) goto out; } else { @@ -177,7 +177,7 @@ static ssize_t lio_target_np_store_iser( } tpg_np_iser = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr, - np->np_ip, tpg_np, ISCSI_INFINIBAND); + tpg_np, ISCSI_INFINIBAND); if (IS_ERR(tpg_np_iser)) { rc = PTR_ERR(tpg_np_iser); goto out; @@ -248,8 +248,8 @@ static struct se_tpg_np *lio_target_call_addnptotpg( return ERR_PTR(-EINVAL); } str++; /* Skip over leading "[" */ - *str2 = '\0'; /* Terminate the IPv6 address */ - str2++; /* Skip over the "]" */ + *str2 = '\0'; /* Terminate the unbracketed IPv6 address */ + str2++; /* Skip over the \0 */ port_str = strstr(str2, ":"); if (!port_str) { pr_err("Unable to locate \":port\"" @@ -316,7 +316,7 @@ static struct se_tpg_np *lio_target_call_addnptotpg( * sys/kernel/config/iscsi/$IQN/$TPG/np/$IP:$PORT/ * */ - tpg_np = iscsit_tpg_add_network_portal(tpg, &sockaddr, str, NULL, + tpg_np = iscsit_tpg_add_network_portal(tpg, &sockaddr, NULL, ISCSI_TCP); if (IS_ERR(tpg_np)) { iscsit_put_tpg(tpg); @@ -344,8 +344,8 @@ static void lio_target_call_delnpfromtpg( se_tpg = &tpg->tpg_se_tpg; pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s TPGT: %hu" - " PORTAL: %s:%hu\n", config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item), - tpg->tpgt, tpg_np->tpg_np->np_ip, tpg_np->tpg_np->np_port); + " PORTAL: %pISc:%hu\n", config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item), + tpg->tpgt, &tpg_np->tpg_np->np_sockaddr, tpg_np->tpg_np->np_port); ret = iscsit_tpg_del_network_portal(tpg, tpg_np); if (ret < 0) diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index bd192f88e1e68..88e0b97e8ea64 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -823,8 +823,8 @@ static void iscsi_handle_login_thread_timeout(unsigned long data) struct iscsi_np *np = (struct iscsi_np *) data; spin_lock_bh(&np->np_thread_lock); - pr_err("iSCSI Login timeout on Network Portal %s:%hu\n", - np->np_ip, np->np_port); + pr_err("iSCSI Login timeout on Network Portal %pISc:%hu\n", + &np->np_sockaddr, np->np_port); if (np->np_login_timer_flags & ISCSI_TF_STOP) { spin_unlock_bh(&np->np_thread_lock); @@ -1302,8 +1302,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) spin_lock_bh(&np->np_thread_lock); if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { spin_unlock_bh(&np->np_thread_lock); - pr_err("iSCSI Network Portal on %s:%hu currently not" - " active.\n", np->np_ip, np->np_port); + pr_err("iSCSI Network Portal on %pISc:%hu currently not" + " active.\n", &np->np_sockaddr, np->np_port); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); goto new_sess_out; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 8262a853e8884..31007cb4c8774 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -461,7 +461,6 @@ static bool iscsit_tpg_check_network_portal( struct iscsi_tpg_np *iscsit_tpg_add_network_portal( struct iscsi_portal_group *tpg, struct __kernel_sockaddr_storage *sockaddr, - char *ip_str, struct iscsi_tpg_np *tpg_np_parent, int network_transport) { @@ -471,8 +470,8 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( if (!tpg_np_parent) { if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, network_transport)) { - pr_err("Network Portal: %s already exists on a" - " different TPG on %s\n", ip_str, + pr_err("Network Portal: %pISc already exists on a" + " different TPG on %s\n", sockaddr, tpg->tpg_tiqn->tiqn); return ERR_PTR(-EEXIST); } @@ -485,7 +484,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( return ERR_PTR(-ENOMEM); } - np = iscsit_add_np(sockaddr, ip_str, network_transport); + np = iscsit_add_np(sockaddr, network_transport); if (IS_ERR(np)) { kfree(tpg_np); return ERR_CAST(np); @@ -515,8 +514,8 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( spin_unlock(&tpg_np_parent->tpg_np_parent_lock); } - pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n", - tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, + pr_debug("CORE[%s] - Added Network Portal: %pISc:%hu,%hu on %s\n", + tpg->tpg_tiqn->tiqn, &np->np_sockaddr, np->np_port, tpg->tpgt, np->np_transport->name); return tpg_np; @@ -529,8 +528,8 @@ static int iscsit_tpg_release_np( { iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true); - pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", - tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, + pr_debug("CORE[%s] - Removed Network Portal: %pISc:%hu,%hu on %s\n", + tpg->tpg_tiqn->tiqn, &np->np_sockaddr, np->np_port, tpg->tpgt, np->np_transport->name); tpg_np->tpg_np = NULL; diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index a2790fd8f7da0..1c0b1d6605cf6 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -22,7 +22,7 @@ extern struct iscsi_node_attrib *iscsit_tpg_get_node_attrib(struct iscsi_session extern void iscsit_tpg_del_external_nps(struct iscsi_tpg_np *); extern struct iscsi_tpg_np *iscsit_tpg_locate_child_np(struct iscsi_tpg_np *, int); extern struct iscsi_tpg_np *iscsit_tpg_add_network_portal(struct iscsi_portal_group *, - struct __kernel_sockaddr_storage *, char *, struct iscsi_tpg_np *, + struct __kernel_sockaddr_storage *, struct iscsi_tpg_np *, int); extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *, struct iscsi_tpg_np *); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index d4616ef12e04f..1051d0c40ddde 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -778,7 +778,6 @@ struct iscsi_np { enum iscsi_timer_flags_table np_login_timer_flags; u32 np_exports; enum np_flags_table np_flags; - unsigned char np_ip[IPV6_ADDRESS_SPACE]; u16 np_port; spinlock_t np_thread_lock; struct completion np_restart_comp; -- GitLab From 69d755747d31c07a416064f251c2f408938fb67a Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 24 Aug 2015 10:26:04 -0700 Subject: [PATCH 5105/7006] target/iscsi: Keep local_ip as the actual sockaddr This is a more natural format that lets us format it with the appropriate printk specifier as needed. This also lets us handle v4-mapped ipv6 addresses a little more nicely, by storing the addr as an actual v4 sockaddr in conn->local_sockaddr. Finally, we no longer need to maintain variables for port, since this is contained in sockaddr. Remove iscsi_np.np_port and iscsi_conn.local_port. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/isert/ib_isert.c | 8 +--- drivers/target/iscsi/iscsi_target.c | 46 ++++++++------------ drivers/target/iscsi/iscsi_target_configfs.c | 4 +- drivers/target/iscsi/iscsi_target_login.c | 43 +++++++++--------- drivers/target/iscsi/iscsi_target_tpg.c | 8 ++-- include/target/iscsi/iscsi_target_core.h | 4 +- 6 files changed, 48 insertions(+), 65 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 7717009631271..9e7094c244eab 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -3218,9 +3218,7 @@ isert_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn, conn->login_port = ntohs(sock_in6->sin6_port); sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.src_addr; - snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", - &sock_in6->sin6_addr.in6_u); - conn->local_port = ntohs(sock_in6->sin6_port); + memcpy(&conn->local_sockaddr , &sock_in6, sizeof(sock_in6)); } else { sock_in = (struct sockaddr_in *)&cm_route->addr.dst_addr; sprintf(conn->login_ip, "%pI4", @@ -3228,9 +3226,7 @@ isert_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn, conn->login_port = ntohs(sock_in->sin_port); sock_in = (struct sockaddr_in *)&cm_route->addr.src_addr; - sprintf(conn->local_ip, "%pI4", - &sock_in->sin_addr.s_addr); - conn->local_port = ntohs(sock_in->sin_port); + memcpy(&conn->local_sockaddr , &sock_in, sizeof(sock_in)); } } diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d75eeb5ce13a8..f752235a1615d 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -276,7 +276,7 @@ bool iscsit_check_np_match( struct sockaddr_in *sock_in, *sock_in_e; struct sockaddr_in6 *sock_in6, *sock_in6_e; bool ip_match = false; - u16 port; + u16 port, port_e; if (sockaddr->ss_family == AF_INET6) { sock_in6 = (struct sockaddr_in6 *)sockaddr; @@ -288,6 +288,7 @@ bool iscsit_check_np_match( ip_match = true; port = ntohs(sock_in6->sin6_port); + port_e = ntohs(sock_in6_e->sin6_port); } else { sock_in = (struct sockaddr_in *)sockaddr; sock_in_e = (struct sockaddr_in *)&np->np_sockaddr; @@ -296,9 +297,10 @@ bool iscsit_check_np_match( ip_match = true; port = ntohs(sock_in->sin_port); + port_e = ntohs(sock_in_e->sin_port); } - if (ip_match && (np->np_port == port) && + if (ip_match && (port_e == port) && (np->np_network_transport == network_transport)) return true; @@ -343,8 +345,6 @@ struct iscsi_np *iscsit_add_np( struct __kernel_sockaddr_storage *sockaddr, int network_transport) { - struct sockaddr_in *sock_in; - struct sockaddr_in6 *sock_in6; struct iscsi_np *np; int ret; @@ -367,14 +367,6 @@ struct iscsi_np *iscsit_add_np( } np->np_flags |= NPF_IP_NETWORK; - if (sockaddr->ss_family == AF_INET6) { - sock_in6 = (struct sockaddr_in6 *)sockaddr; - np->np_port = ntohs(sock_in6->sin6_port); - } else { - sock_in = (struct sockaddr_in *)sockaddr; - np->np_port = ntohs(sock_in->sin_port); - } - np->np_network_transport = network_transport; spin_lock_init(&np->np_thread_lock); init_completion(&np->np_restart_comp); @@ -408,8 +400,8 @@ struct iscsi_np *iscsit_add_np( list_add_tail(&np->np_list, &g_np_list); mutex_unlock(&np_lock); - pr_debug("CORE[0] - Added Network Portal: %pISc:%hu on %s\n", - &np->np_sockaddr, np->np_port, np->np_transport->name); + pr_debug("CORE[0] - Added Network Portal: %pISpc on %s\n", + &np->np_sockaddr, np->np_transport->name); return np; } @@ -478,8 +470,8 @@ int iscsit_del_np(struct iscsi_np *np) list_del(&np->np_list); mutex_unlock(&np_lock); - pr_debug("CORE[0] - Removed Network Portal: %pISc:%hu on %s\n", - &np->np_sockaddr, np->np_port, np->np_transport->name); + pr_debug("CORE[0] - Removed Network Portal: %pISpc on %s\n", + &np->np_sockaddr, np->np_transport->name); iscsit_put_transport(np->np_transport); kfree(np); @@ -3460,6 +3452,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, tpg_np_list) { struct iscsi_np *np = tpg_np->tpg_np; bool inaddr_any = iscsit_check_inaddr_any(np); + struct __kernel_sockaddr_storage *sockaddr; if (np->np_network_transport != network_transport) continue; @@ -3487,18 +3480,15 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, } } - if (inaddr_any) { - len = sprintf(buf, "TargetAddress=" - "%s:%hu,%hu", - conn->local_ip, - np->np_port, - tpg->tpgt); - } else { - len = sprintf(buf, "TargetAddress=" - "%pISpc,%hu", - &np->np_sockaddr, - tpg->tpgt); - } + if (inaddr_any) + sockaddr = &conn->local_sockaddr; + else + sockaddr = &np->np_sockaddr; + + len = sprintf(buf, "TargetAddress=" + "%pISpc,%hu", + sockaddr, + tpg->tpgt); len += 1; if ((len + payload_len) > buffer_len) { diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index ad6a889dadc0c..8d69c4132221b 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -344,8 +344,8 @@ static void lio_target_call_delnpfromtpg( se_tpg = &tpg->tpg_se_tpg; pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s TPGT: %hu" - " PORTAL: %pISc:%hu\n", config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item), - tpg->tpgt, &tpg_np->tpg_np->np_sockaddr, tpg_np->tpg_np->np_port); + " PORTAL: %pISpc\n", config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item), + tpg->tpgt, &tpg_np->tpg_np->np_sockaddr); ret = iscsit_tpg_del_network_portal(tpg, tpg_np); if (ret < 0) diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 88e0b97e8ea64..007299acefbdb 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -729,8 +729,8 @@ int iscsi_post_login_handler( } pr_debug("iSCSI Login successful on CID: %hu from %s to" - " %s:%hu,%hu\n", conn->cid, conn->login_ip, - conn->local_ip, conn->local_port, tpg->tpgt); + " %pISpc,%hu\n", conn->cid, conn->login_ip, + &conn->local_sockaddr, tpg->tpgt); list_add_tail(&conn->conn_list, &sess->sess_conn_list); atomic_inc(&sess->nconn); @@ -774,8 +774,8 @@ int iscsi_post_login_handler( pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n"); sess->session_state = TARG_SESS_STATE_LOGGED_IN; - pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n", - conn->cid, conn->login_ip, conn->local_ip, conn->local_port, + pr_debug("iSCSI Login successful on CID: %hu from %s to %pISpc,%hu\n", + conn->cid, conn->login_ip, &conn->local_sockaddr, tpg->tpgt); spin_lock_bh(&sess->conn_lock); @@ -823,8 +823,8 @@ static void iscsi_handle_login_thread_timeout(unsigned long data) struct iscsi_np *np = (struct iscsi_np *) data; spin_lock_bh(&np->np_thread_lock); - pr_err("iSCSI Login timeout on Network Portal %pISc:%hu\n", - &np->np_sockaddr, np->np_port); + pr_err("iSCSI Login timeout on Network Portal %pISpc\n", + &np->np_sockaddr); if (np->np_login_timer_flags & ISCSI_TF_STOP) { spin_unlock_bh(&np->np_thread_lock); @@ -1027,13 +1027,15 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in6, &err, 0); if (!rc) { - if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) - snprintf(conn->local_ip, sizeof(conn->local_ip), "[%pI6c]", - &sock_in6.sin6_addr.in6_u); - else - snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI4", - &sock_in6.sin6_addr.s6_addr32[3]); - conn->local_port = ntohs(sock_in6.sin6_port); + if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) { + memcpy(&conn->local_sockaddr, &sock_in6, sizeof(sock_in6)); + } else { + /* Pretend to be an ipv4 socket */ + sock_in.sin_family = AF_INET; + sock_in.sin_port = sock_in6.sin6_port; + memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4); + memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in)); + } } } else { memset(&sock_in, 0, sizeof(struct sockaddr_in)); @@ -1048,11 +1050,8 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in, &err, 0); - if (!rc) { - sprintf(conn->local_ip, "%pI4", - &sock_in.sin_addr.s_addr); - conn->local_port = ntohs(sock_in.sin_port); - } + if (!rc) + memcpy(&conn->local_sockaddr, &sock_in, sizeof(sock_in)); } return 0; @@ -1302,8 +1301,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) spin_lock_bh(&np->np_thread_lock); if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { spin_unlock_bh(&np->np_thread_lock); - pr_err("iSCSI Network Portal on %pISc:%hu currently not" - " active.\n", &np->np_sockaddr, np->np_port); + pr_err("iSCSI Network Portal on %pISpc currently not" + " active.\n", &np->np_sockaddr); iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); goto new_sess_out; @@ -1313,8 +1312,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) conn->network_transport = np->np_network_transport; pr_debug("Received iSCSI login request from %s on %s Network" - " Portal %s:%hu\n", conn->login_ip, np->np_transport->name, - conn->local_ip, conn->local_port); + " Portal %pISpc\n", conn->login_ip, np->np_transport->name, + &conn->local_sockaddr); pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); conn->conn_state = TARG_CONN_STATE_IN_LOGIN; diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 31007cb4c8774..d61ae5167c421 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -514,8 +514,8 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( spin_unlock(&tpg_np_parent->tpg_np_parent_lock); } - pr_debug("CORE[%s] - Added Network Portal: %pISc:%hu,%hu on %s\n", - tpg->tpg_tiqn->tiqn, &np->np_sockaddr, np->np_port, tpg->tpgt, + pr_debug("CORE[%s] - Added Network Portal: %pISpc,%hu on %s\n", + tpg->tpg_tiqn->tiqn, &np->np_sockaddr, tpg->tpgt, np->np_transport->name); return tpg_np; @@ -528,8 +528,8 @@ static int iscsit_tpg_release_np( { iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true); - pr_debug("CORE[%s] - Removed Network Portal: %pISc:%hu,%hu on %s\n", - tpg->tpg_tiqn->tiqn, &np->np_sockaddr, np->np_port, tpg->tpgt, + pr_debug("CORE[%s] - Removed Network Portal: %pISpc,%hu on %s\n", + tpg->tpg_tiqn->tiqn, &np->np_sockaddr, tpg->tpgt, np->np_transport->name); tpg_np->tpg_np = NULL; diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 1051d0c40ddde..b9434117785f4 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -519,7 +519,6 @@ struct iscsi_conn { u16 cid; /* Remote TCP Port */ u16 login_port; - u16 local_port; int net_size; int login_family; u32 auth_id; @@ -531,7 +530,7 @@ struct iscsi_conn { u32 stat_sn; #define IPV6_ADDRESS_SPACE 48 unsigned char login_ip[IPV6_ADDRESS_SPACE]; - unsigned char local_ip[IPV6_ADDRESS_SPACE]; + struct __kernel_sockaddr_storage local_sockaddr; int conn_usage_count; int conn_waiting_on_uc; atomic_t check_immediate_queue; @@ -778,7 +777,6 @@ struct iscsi_np { enum iscsi_timer_flags_table np_login_timer_flags; u32 np_exports; enum np_flags_table np_flags; - u16 np_port; spinlock_t np_thread_lock; struct completion np_restart_comp; struct socket *np_socket; -- GitLab From dc58f760e2e1f8f2265b581d35f211415c4fee0c Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 24 Aug 2015 10:26:05 -0700 Subject: [PATCH 5106/7006] target/iscsi: Replace conn->login_ip with login_sockaddr Very similar to how it went with local_sockaddr. It was embedded in iscsi_login_stats so some changes there, and we needed to copy in a sockaddr_storage comparison function. Hopefully the kernel will get a standard one soon, our implementation makes the 3rd. isert_set_conn_info() became much smaller. IPV6_ADDRESS_SPACE define goes away, had to modify a call to in6_pton(), can just use -1 since we are sure string is null-terminated. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/isert/ib_isert.c | 21 ++---------- drivers/target/iscsi/iscsi_target_configfs.c | 4 +-- drivers/target/iscsi/iscsi_target_login.c | 35 ++++++++++---------- drivers/target/iscsi/iscsi_target_stat.c | 2 +- drivers/target/iscsi/iscsi_target_util.c | 32 ++++++++++++++++-- include/target/iscsi/iscsi_target_core.h | 3 +- include/target/iscsi/iscsi_target_stat.h | 2 +- 7 files changed, 53 insertions(+), 46 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 9e7094c244eab..aa08606f75a28 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -3206,28 +3206,11 @@ isert_set_conn_info(struct iscsi_np *np, struct iscsi_conn *conn, { struct rdma_cm_id *cm_id = isert_conn->cm_id; struct rdma_route *cm_route = &cm_id->route; - struct sockaddr_in *sock_in; - struct sockaddr_in6 *sock_in6; conn->login_family = np->np_sockaddr.ss_family; - if (np->np_sockaddr.ss_family == AF_INET6) { - sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.dst_addr; - snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", - &sock_in6->sin6_addr.in6_u); - conn->login_port = ntohs(sock_in6->sin6_port); - - sock_in6 = (struct sockaddr_in6 *)&cm_route->addr.src_addr; - memcpy(&conn->local_sockaddr , &sock_in6, sizeof(sock_in6)); - } else { - sock_in = (struct sockaddr_in *)&cm_route->addr.dst_addr; - sprintf(conn->login_ip, "%pI4", - &sock_in->sin_addr.s_addr); - conn->login_port = ntohs(sock_in->sin_port); - - sock_in = (struct sockaddr_in *)&cm_route->addr.src_addr; - memcpy(&conn->local_sockaddr , &sock_in, sizeof(sock_in)); - } + conn->login_sockaddr = cm_route->addr.dst_addr; + conn->local_sockaddr = cm_route->addr.src_addr; } static int diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 8d69c4132221b..5afa6294eda2f 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -267,7 +267,7 @@ static struct se_tpg_np *lio_target_call_addnptotpg( sock_in6 = (struct sockaddr_in6 *)&sockaddr; sock_in6->sin6_family = AF_INET6; sock_in6->sin6_port = htons((unsigned short)port); - ret = in6_pton(str, IPV6_ADDRESS_SPACE, + ret = in6_pton(str, -1, (void *)&sock_in6->sin6_addr.in6_u, -1, &end); if (ret <= 0) { pr_err("in6_pton returned: %d\n", ret); @@ -753,7 +753,7 @@ static ssize_t lio_target_nacl_show_info( break; } - rb += sprintf(page+rb, " Address %s %s", conn->login_ip, + rb += sprintf(page+rb, " Address %pISc %s", &conn->login_sockaddr, (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); rb += sprintf(page+rb, " StatSN: 0x%08x\n", diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 007299acefbdb..b7ef6fa82fbfb 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -728,8 +728,8 @@ int iscsi_post_login_handler( stop_timer = 1; } - pr_debug("iSCSI Login successful on CID: %hu from %s to" - " %pISpc,%hu\n", conn->cid, conn->login_ip, + pr_debug("iSCSI Login successful on CID: %hu from %pISpc to" + " %pISpc,%hu\n", conn->cid, &conn->login_sockaddr, &conn->local_sockaddr, tpg->tpgt); list_add_tail(&conn->conn_list, &sess->sess_conn_list); @@ -774,8 +774,8 @@ int iscsi_post_login_handler( pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n"); sess->session_state = TARG_SESS_STATE_LOGGED_IN; - pr_debug("iSCSI Login successful on CID: %hu from %s to %pISpc,%hu\n", - conn->cid, conn->login_ip, &conn->local_sockaddr, + pr_debug("iSCSI Login successful on CID: %hu from %pISpc to %pISpc,%hu\n", + conn->cid, &conn->login_sockaddr, &conn->local_sockaddr, tpg->tpgt); spin_lock_bh(&sess->conn_lock); @@ -1015,13 +1015,15 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in6, &err, 1); if (!rc) { - if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) - snprintf(conn->login_ip, sizeof(conn->login_ip), "[%pI6c]", - &sock_in6.sin6_addr.in6_u); - else - snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI4", - &sock_in6.sin6_addr.s6_addr32[3]); - conn->login_port = ntohs(sock_in6.sin6_port); + if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) { + memcpy(&conn->login_sockaddr, &sock_in6, sizeof(sock_in6)); + } else { + /* Pretend to be an ipv4 socket */ + sock_in.sin_family = AF_INET; + sock_in.sin_port = sock_in6.sin6_port; + memcpy(&sock_in.sin_addr, &sock_in6.sin6_addr.s6_addr32[3], 4); + memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in)); + } } rc = conn->sock->ops->getname(conn->sock, @@ -1042,11 +1044,8 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in, &err, 1); - if (!rc) { - sprintf(conn->login_ip, "%pI4", - &sock_in.sin_addr.s_addr); - conn->login_port = ntohs(sock_in.sin_port); - } + if (!rc) + memcpy(&conn->login_sockaddr, &sock_in, sizeof(sock_in)); rc = conn->sock->ops->getname(conn->sock, (struct sockaddr *)&sock_in, &err, 0); @@ -1311,8 +1310,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) conn->network_transport = np->np_network_transport; - pr_debug("Received iSCSI login request from %s on %s Network" - " Portal %pISpc\n", conn->login_ip, np->np_transport->name, + pr_debug("Received iSCSI login request from %pISpc on %s Network" + " Portal %pISpc\n", &conn->login_sockaddr, np->np_transport->name, &conn->local_sockaddr); pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index 5e1349a3b1438..9dd94ff0b62c0 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c @@ -430,7 +430,7 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( int ret; spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%s\n", lstat->last_intr_fail_ip_addr); + ret = snprintf(page, PAGE_SIZE, "%pISc\n", &lstat->last_intr_fail_sockaddr); spin_unlock(&lstat->lock); return ret; diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 7df4fac69f398..428b0d9e3dbab 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -1372,6 +1372,33 @@ int tx_data( return iscsit_do_tx_data(conn, &c); } +static bool sockaddr_equal(struct sockaddr_storage *x, struct sockaddr_storage *y) +{ + switch (x->ss_family) { + case AF_INET: { + struct sockaddr_in *sinx = (struct sockaddr_in *)x; + struct sockaddr_in *siny = (struct sockaddr_in *)y; + if (sinx->sin_addr.s_addr != siny->sin_addr.s_addr) + return false; + if (sinx->sin_port != siny->sin_port) + return false; + break; + } + case AF_INET6: { + struct sockaddr_in6 *sinx = (struct sockaddr_in6 *)x; + struct sockaddr_in6 *siny = (struct sockaddr_in6 *)y; + if (!ipv6_addr_equal(&sinx->sin6_addr, &siny->sin6_addr)) + return false; + if (sinx->sin6_port != siny->sin6_port) + return false; + break; + } + default: + return false; + } + return true; +} + void iscsit_collect_login_stats( struct iscsi_conn *conn, u8 status_class, @@ -1388,7 +1415,7 @@ void iscsit_collect_login_stats( ls = &tiqn->login_stats; spin_lock(&ls->lock); - if (!strcmp(conn->login_ip, ls->last_intr_fail_ip_addr) && + if (sockaddr_equal(&conn->login_sockaddr, &ls->last_intr_fail_sockaddr) && ((get_jiffies_64() - ls->last_fail_time) < 10)) { /* We already have the failure info for this login */ spin_unlock(&ls->lock); @@ -1428,8 +1455,7 @@ void iscsit_collect_login_stats( ls->last_intr_fail_ip_family = conn->login_family; - snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE, - "%s", conn->login_ip); + ls->last_intr_fail_sockaddr = conn->login_sockaddr; ls->last_fail_time = get_jiffies_64(); } diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index b9434117785f4..f3eb998095576 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -528,8 +528,7 @@ struct iscsi_conn { u32 exp_statsn; /* Per connection status sequence number */ u32 stat_sn; -#define IPV6_ADDRESS_SPACE 48 - unsigned char login_ip[IPV6_ADDRESS_SPACE]; + struct __kernel_sockaddr_storage login_sockaddr; struct __kernel_sockaddr_storage local_sockaddr; int conn_usage_count; int conn_waiting_on_uc; diff --git a/include/target/iscsi/iscsi_target_stat.h b/include/target/iscsi/iscsi_target_stat.h index 3ff76b4faad32..f2a583cdf08be 100644 --- a/include/target/iscsi/iscsi_target_stat.h +++ b/include/target/iscsi/iscsi_target_stat.h @@ -50,7 +50,7 @@ struct iscsi_login_stats { u64 last_fail_time; /* time stamp (jiffies) */ u32 last_fail_type; int last_intr_fail_ip_family; - unsigned char last_intr_fail_ip_addr[IPV6_ADDRESS_SPACE]; + struct __kernel_sockaddr_storage last_intr_fail_sockaddr; char last_intr_fail_name[224]; } ____cacheline_aligned; -- GitLab From 13a3cf08fa1e4b3a252f24202d47a556242aea03 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 24 Aug 2015 10:26:06 -0700 Subject: [PATCH 5107/7006] target/iscsi: Replace __kernel_sockaddr_storage with sockaddr_storage It appears to be what the rest of the kernel does, so let's do it too. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/infiniband/ulp/isert/ib_isert.c | 4 ++-- drivers/target/iscsi/iscsi_target.c | 8 ++++---- drivers/target/iscsi/iscsi_target.h | 4 ++-- drivers/target/iscsi/iscsi_target_configfs.c | 4 ++-- drivers/target/iscsi/iscsi_target_login.c | 6 +++--- drivers/target/iscsi/iscsi_target_login.h | 4 ++-- drivers/target/iscsi/iscsi_target_tpg.c | 4 ++-- drivers/target/iscsi/iscsi_target_tpg.h | 2 +- include/target/iscsi/iscsi_target_core.h | 6 +++--- include/target/iscsi/iscsi_target_stat.h | 2 +- include/target/iscsi/iscsi_transport.h | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index aa08606f75a28..20a0a46294567 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -3102,7 +3102,7 @@ out: static int isert_setup_np(struct iscsi_np *np, - struct __kernel_sockaddr_storage *ksockaddr) + struct sockaddr_storage *ksockaddr) { struct isert_np *isert_np; struct rdma_cm_id *isert_lid; @@ -3124,7 +3124,7 @@ isert_setup_np(struct iscsi_np *np, * in iscsi_target_configfs.c code.. */ memcpy(&np->np_sockaddr, ksockaddr, - sizeof(struct __kernel_sockaddr_storage)); + sizeof(struct sockaddr_storage)); isert_lid = isert_setup_id(isert_np); if (IS_ERR(isert_lid)) { diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index f752235a1615d..a9257a083c395 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -269,7 +269,7 @@ int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg, } bool iscsit_check_np_match( - struct __kernel_sockaddr_storage *sockaddr, + struct sockaddr_storage *sockaddr, struct iscsi_np *np, int network_transport) { @@ -311,7 +311,7 @@ bool iscsit_check_np_match( * Called with mutex np_lock held */ static struct iscsi_np *iscsit_get_np( - struct __kernel_sockaddr_storage *sockaddr, + struct sockaddr_storage *sockaddr, int network_transport) { struct iscsi_np *np; @@ -342,7 +342,7 @@ static struct iscsi_np *iscsit_get_np( } struct iscsi_np *iscsit_add_np( - struct __kernel_sockaddr_storage *sockaddr, + struct sockaddr_storage *sockaddr, int network_transport) { struct iscsi_np *np; @@ -3452,7 +3452,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, tpg_np_list) { struct iscsi_np *np = tpg_np->tpg_np; bool inaddr_any = iscsit_check_inaddr_any(np); - struct __kernel_sockaddr_storage *sockaddr; + struct sockaddr_storage *sockaddr; if (np->np_network_transport != network_transport) continue; diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index d294f030a0978..4cf2c0f2ba2f9 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -10,9 +10,9 @@ extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); extern void iscsit_login_kref_put(struct kref *); extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *, struct iscsi_tpg_np *); -extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, +extern bool iscsit_check_np_match(struct sockaddr_storage *, struct iscsi_np *, int); -extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, +extern struct iscsi_np *iscsit_add_np(struct sockaddr_storage *, int); extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, struct iscsi_portal_group *, bool); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 5afa6294eda2f..c7461d770d3a8 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -220,7 +220,7 @@ static struct se_tpg_np *lio_target_call_addnptotpg( struct iscsi_portal_group *tpg; struct iscsi_tpg_np *tpg_np; char *str, *str2, *ip_str, *port_str; - struct __kernel_sockaddr_storage sockaddr; + struct sockaddr_storage sockaddr; struct sockaddr_in *sock_in; struct sockaddr_in6 *sock_in6; unsigned long port; @@ -235,7 +235,7 @@ static struct se_tpg_np *lio_target_call_addnptotpg( memset(buf, 0, MAX_PORTAL_LEN + 1); snprintf(buf, MAX_PORTAL_LEN + 1, "%s", name); - memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage)); + memset(&sockaddr, 0, sizeof(struct sockaddr_storage)); str = strstr(buf, "["); if (str) { diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index b7ef6fa82fbfb..fc7b79672d056 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -877,7 +877,7 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np) int iscsit_setup_np( struct iscsi_np *np, - struct __kernel_sockaddr_storage *sockaddr) + struct sockaddr_storage *sockaddr) { struct socket *sock = NULL; int backlog = ISCSIT_TCP_BACKLOG, ret, opt = 0, len; @@ -916,7 +916,7 @@ int iscsit_setup_np( * in iscsi_target_configfs.c code.. */ memcpy(&np->np_sockaddr, sockaddr, - sizeof(struct __kernel_sockaddr_storage)); + sizeof(struct sockaddr_storage)); if (sockaddr->ss_family == AF_INET6) len = sizeof(struct sockaddr_in6); @@ -975,7 +975,7 @@ fail: int iscsi_target_setup_login_socket( struct iscsi_np *np, - struct __kernel_sockaddr_storage *sockaddr) + struct sockaddr_storage *sockaddr) { struct iscsit_transport *t; int rc; diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 1c7358081533a..35aeffee06869 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h @@ -5,9 +5,9 @@ extern int iscsi_login_setup_crypto(struct iscsi_conn *); extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *); extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32); extern int iscsit_setup_np(struct iscsi_np *, - struct __kernel_sockaddr_storage *); + struct sockaddr_storage *); extern int iscsi_target_setup_login_socket(struct iscsi_np *, - struct __kernel_sockaddr_storage *); + struct sockaddr_storage *); extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *); extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index d61ae5167c421..23c95cd14167a 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -431,7 +431,7 @@ struct iscsi_tpg_np *iscsit_tpg_locate_child_np( static bool iscsit_tpg_check_network_portal( struct iscsi_tiqn *tiqn, - struct __kernel_sockaddr_storage *sockaddr, + struct sockaddr_storage *sockaddr, int network_transport) { struct iscsi_portal_group *tpg; @@ -460,7 +460,7 @@ static bool iscsit_tpg_check_network_portal( struct iscsi_tpg_np *iscsit_tpg_add_network_portal( struct iscsi_portal_group *tpg, - struct __kernel_sockaddr_storage *sockaddr, + struct sockaddr_storage *sockaddr, struct iscsi_tpg_np *tpg_np_parent, int network_transport) { diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 1c0b1d6605cf6..9db32bd24cd46 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -22,7 +22,7 @@ extern struct iscsi_node_attrib *iscsit_tpg_get_node_attrib(struct iscsi_session extern void iscsit_tpg_del_external_nps(struct iscsi_tpg_np *); extern struct iscsi_tpg_np *iscsit_tpg_locate_child_np(struct iscsi_tpg_np *, int); extern struct iscsi_tpg_np *iscsit_tpg_add_network_portal(struct iscsi_portal_group *, - struct __kernel_sockaddr_storage *, struct iscsi_tpg_np *, + struct sockaddr_storage *, struct iscsi_tpg_np *, int); extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *, struct iscsi_tpg_np *); diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index f3eb998095576..84abe73450c5c 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -528,8 +528,8 @@ struct iscsi_conn { u32 exp_statsn; /* Per connection status sequence number */ u32 stat_sn; - struct __kernel_sockaddr_storage login_sockaddr; - struct __kernel_sockaddr_storage local_sockaddr; + struct sockaddr_storage login_sockaddr; + struct sockaddr_storage local_sockaddr; int conn_usage_count; int conn_waiting_on_uc; atomic_t check_immediate_queue; @@ -779,7 +779,7 @@ struct iscsi_np { spinlock_t np_thread_lock; struct completion np_restart_comp; struct socket *np_socket; - struct __kernel_sockaddr_storage np_sockaddr; + struct sockaddr_storage np_sockaddr; struct task_struct *np_thread; struct timer_list np_login_timer; void *np_context; diff --git a/include/target/iscsi/iscsi_target_stat.h b/include/target/iscsi/iscsi_target_stat.h index f2a583cdf08be..e615bb485d0b3 100644 --- a/include/target/iscsi/iscsi_target_stat.h +++ b/include/target/iscsi/iscsi_target_stat.h @@ -50,7 +50,7 @@ struct iscsi_login_stats { u64 last_fail_time; /* time stamp (jiffies) */ u32 last_fail_type; int last_intr_fail_ip_family; - struct __kernel_sockaddr_storage last_intr_fail_sockaddr; + struct sockaddr_storage last_intr_fail_sockaddr; char last_intr_fail_name[224]; } ____cacheline_aligned; diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h index e6bb166f12c21..90e37faa2ede5 100644 --- a/include/target/iscsi/iscsi_transport.h +++ b/include/target/iscsi/iscsi_transport.h @@ -9,7 +9,7 @@ struct iscsit_transport { int priv_size; struct module *owner; struct list_head t_node; - int (*iscsit_setup_np)(struct iscsi_np *, struct __kernel_sockaddr_storage *); + int (*iscsit_setup_np)(struct iscsi_np *, struct sockaddr_storage *); int (*iscsit_accept_np)(struct iscsi_np *, struct iscsi_conn *); void (*iscsit_free_np)(struct iscsi_np *); void (*iscsit_wait_conn)(struct iscsi_conn *); -- GitLab From 674c242c9323d3c293fc4f9a3a3a619fe3063290 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Thu, 27 Aug 2015 07:12:33 +0100 Subject: [PATCH 5108/7006] arm64: flush FP/SIMD state correctly after execve() When a task calls execve(), its FP/SIMD state is flushed so that none of the original program state is observeable by the incoming program. However, since this flushing consists of setting the in-memory copy of the FP/SIMD state to all zeroes, the CPU field is set to CPU 0 as well, which indicates to the lazy FP/SIMD preserve/restore code that the FP/SIMD state does not need to be reread from memory if the task is scheduled again on CPU 0 without any other tasks having entered userland (or used the FP/SIMD in kernel mode) on the same CPU in the mean time. If this happens, the FP/SIMD state of the old program will still be present in the registers when the new program starts. So set the CPU field to the invalid value of NR_CPUS when performing the flush, by calling fpsimd_flush_task_state(). Cc: Reported-by: Chunyan Zhang Reported-by: Janet Liu Signed-off-by: Ard Biesheuvel Signed-off-by: Will Deacon --- arch/arm64/kernel/fpsimd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 44d6f7545505f..c56956a16d3f0 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -158,6 +158,7 @@ void fpsimd_thread_switch(struct task_struct *next) void fpsimd_flush_thread(void) { memset(¤t->thread.fpsimd_state, 0, sizeof(struct fpsimd_state)); + fpsimd_flush_task_state(current); set_thread_flag(TIF_FOREIGN_FPSTATE); } -- GitLab From 0e1ffef02cf94e46f95957af0f822531fecf741c Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Thu, 27 Aug 2015 16:01:16 +1000 Subject: [PATCH 5109/7006] powerpc/iommu: Set default DMA offset in dma_dev_setup Commit e91c25111aa3 "powerpc/iommu: Cleanup setting of DMA base/offset" expects that the default DMA offset is set from pnv_ioda_setup_bus_dma() which is correct unless it is SRIOV where the code flow is different - at the moment when pnv_ioda_setup_bus_dma() is called, PCI devices for VFs are not created yet. This adds missing set_dma_offset() to pnv_pci_ioda_dma_dev_setup() to cover the case of SRIOV. Note that we still need set_dma_offset() in pnv_ioda_setup_bus_dma() as at the boot time pnv_pci_ioda_dma_dev_setup() is called when no PE was created yet, this happens at the PHB fixup stage. Fixes: e91c25111aa3 ("powerpc/iommu: Cleanup setting of DMA base/offset") Signed-off-by: Alexey Kardashevskiy Reviewed-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/powernv/pci-ioda.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c b/arch/powerpc/platforms/powernv/pci-ioda.c index 9ab30698890fa..4b8d3bd72a781 100644 --- a/arch/powerpc/platforms/powernv/pci-ioda.c +++ b/arch/powerpc/platforms/powernv/pci-ioda.c @@ -1560,6 +1560,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev pe = &phb->ioda.pe_array[pdn->pe_number]; WARN_ON(get_dma_ops(&pdev->dev) != &dma_iommu_ops); + set_dma_offset(&pdev->dev, pe->tce_bypass_base); set_iommu_table_base(&pdev->dev, pe->table_group.tables[0]); /* * Note: iommu_add_device() will fail here as -- GitLab From d690740f22f6520873f96e66aae7119ec2215755 Mon Sep 17 00:00:00 2001 From: Vasant Hegde Date: Thu, 27 Aug 2015 11:34:10 +0530 Subject: [PATCH 5110/7006] powerpc/powernv: Enable LEDS support Commit 84ad6e5c added LEDS support for PowerNV platform. Lets update ppc64_defconfig to pick LEDS driver. PowerNV LEDS driver looks for "/ibm,opal/leds" node in device tree and loads if this node exists. Hence added it as 'm'. Also note that powernv LEDS driver needs NEW_LEDS and LEDS_CLASS as well. Hence added them to config file. mpe: Also add them to pseries_defconfig, which is currently also used for powernv systems. Suggested-by: Michael Ellerman Signed-off-by: Vasant Hegde Cc: Stewart Smith Signed-off-by: Michael Ellerman --- arch/powerpc/configs/ppc64_defconfig | 3 +++ arch/powerpc/configs/pseries_defconfig | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/powerpc/configs/ppc64_defconfig b/arch/powerpc/configs/ppc64_defconfig index a97efc2146fdf..6bc0ee4b1070a 100644 --- a/arch/powerpc/configs/ppc64_defconfig +++ b/arch/powerpc/configs/ppc64_defconfig @@ -355,3 +355,6 @@ CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_POWERNV=m diff --git a/arch/powerpc/configs/pseries_defconfig b/arch/powerpc/configs/pseries_defconfig index 2404271ec4aeb..7991f37e5fe2a 100644 --- a/arch/powerpc/configs/pseries_defconfig +++ b/arch/powerpc/configs/pseries_defconfig @@ -320,3 +320,6 @@ CONFIG_CRYPTO_DEV_NX_ENCRYPT=m CONFIG_VIRTUALIZATION=y CONFIG_KVM_BOOK3S_64=m CONFIG_KVM_BOOK3S_64_HV=m +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=m +CONFIG_LEDS_POWERNV=m -- GitLab From 0c9fc10df211e0c931787a51c58caf487035f74e Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Thu, 27 Aug 2015 14:05:26 +0200 Subject: [PATCH 5111/7006] gpio: tc3589x: use static container helper There is a helper function to do the container_of() magic for the tc3589x GPIO, so use it. Signed-off-by: Linus Walleij --- drivers/gpio/gpio-tc3589x.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c index 31b244cffabb2..d1d585ddb9ab7 100644 --- a/drivers/gpio/gpio-tc3589x.c +++ b/drivers/gpio/gpio-tc3589x.c @@ -102,7 +102,7 @@ static struct gpio_chip template_chip = { static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -130,7 +130,7 @@ static int tc3589x_gpio_irq_set_type(struct irq_data *d, unsigned int type) static void tc3589x_gpio_irq_lock(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); mutex_lock(&tc3589x_gpio->irq_lock); } @@ -138,7 +138,7 @@ static void tc3589x_gpio_irq_lock(struct irq_data *d) static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); struct tc3589x *tc3589x = tc3589x_gpio->tc3589x; static const u8 regmap[] = { [REG_IBE] = TC3589x_GPIOIBE0, @@ -167,7 +167,7 @@ static void tc3589x_gpio_irq_sync_unlock(struct irq_data *d) static void tc3589x_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -178,7 +178,7 @@ static void tc3589x_gpio_irq_mask(struct irq_data *d) static void tc3589x_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); - struct tc3589x_gpio *tc3589x_gpio = container_of(gc, struct tc3589x_gpio, chip); + struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); -- GitLab From 22d7e85ff8e5826845e9a4fa34b4723e5a97ee9b Mon Sep 17 00:00:00 2001 From: Robin van der Gracht Date: Tue, 4 Aug 2015 08:58:33 +0200 Subject: [PATCH 5112/7006] mmc: core: Fixed bug in one erase-group budget TRIM When requesting a trim for several bytes, everything up to the next erase-group is erased. This causes data corruption. Signed-off-by: Robin van der Gracht Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 083cade3ffc5d..57edb2a9bb04b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2227,9 +2227,8 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr, * and call mmc_do_erase() twice if necessary. This special case is * identified by the card->eg_boundary flag. */ - if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && - (from % card->erase_size)) { - rem = card->erase_size - (from % card->erase_size); + rem = card->erase_size - (from % card->erase_size); + if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) { err = mmc_do_erase(card, from, from + rem - 1, arg); from += rem; if ((err) || (to <= from)) -- GitLab From 143b648ddf1583905fa15d32be27a31442fc7933 Mon Sep 17 00:00:00 2001 From: Adam Lee Date: Mon, 3 Aug 2015 14:33:28 +0800 Subject: [PATCH 5113/7006] mmc: sdhci-pci: set the clear transfer mode register quirk for O2Micro This patch fixes MMC not working issue on O2Micro/BayHub Host, which requires transfer mode register to be cleared when sending no DMA command. Signed-off-by: Peter Guo Signed-off-by: Adam Lee Cc: stable Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 94f54d2772e88..b3b0a3e4fca16 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -618,6 +618,7 @@ static int jmicron_resume(struct sdhci_pci_chip *chip) static const struct sdhci_pci_fixes sdhci_o2 = { .probe = sdhci_pci_o2_probe, .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC, + .quirks2 = SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD, .probe_slot = sdhci_pci_o2_probe_slot, .resume = sdhci_pci_o2_resume, }; -- GitLab From 90614cd9045dc7003913ee58cbc77950351485a0 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 7 Aug 2015 01:06:48 +0300 Subject: [PATCH 5114/7006] mmc: host: use of_property_read_bool() Use more compact of_property_read_bool() calls instead of the of_find_property() calls. Signed-off-by: Sergei Shtylyov Signed-off-by: Ulf Hansson --- drivers/mmc/core/host.c | 42 ++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c index 99a9c9011c501..abd933b7029be 100644 --- a/drivers/mmc/core/host.c +++ b/drivers/mmc/core/host.c @@ -398,7 +398,7 @@ int mmc_of_parse(struct mmc_host *host) { struct device_node *np; u32 bus_width; - int len, ret; + int ret; bool cd_cap_invert, cd_gpio_invert = false; bool ro_cap_invert, ro_gpio_invert = false; @@ -445,12 +445,12 @@ int mmc_of_parse(struct mmc_host *host) */ /* Parse Card Detection */ - if (of_find_property(np, "non-removable", &len)) { + if (of_property_read_bool(np, "non-removable")) { host->caps |= MMC_CAP_NONREMOVABLE; } else { cd_cap_invert = of_property_read_bool(np, "cd-inverted"); - if (of_find_property(np, "broken-cd", &len)) + if (of_property_read_bool(np, "broken-cd")) host->caps |= MMC_CAP_NEEDS_POLL; ret = mmc_gpiod_request_cd(host, "cd", 0, true, @@ -491,41 +491,41 @@ int mmc_of_parse(struct mmc_host *host) if (ro_cap_invert ^ ro_gpio_invert) host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH; - if (of_find_property(np, "cap-sd-highspeed", &len)) + if (of_property_read_bool(np, "cap-sd-highspeed")) host->caps |= MMC_CAP_SD_HIGHSPEED; - if (of_find_property(np, "cap-mmc-highspeed", &len)) + if (of_property_read_bool(np, "cap-mmc-highspeed")) host->caps |= MMC_CAP_MMC_HIGHSPEED; - if (of_find_property(np, "sd-uhs-sdr12", &len)) + if (of_property_read_bool(np, "sd-uhs-sdr12")) host->caps |= MMC_CAP_UHS_SDR12; - if (of_find_property(np, "sd-uhs-sdr25", &len)) + if (of_property_read_bool(np, "sd-uhs-sdr25")) host->caps |= MMC_CAP_UHS_SDR25; - if (of_find_property(np, "sd-uhs-sdr50", &len)) + if (of_property_read_bool(np, "sd-uhs-sdr50")) host->caps |= MMC_CAP_UHS_SDR50; - if (of_find_property(np, "sd-uhs-sdr104", &len)) + if (of_property_read_bool(np, "sd-uhs-sdr104")) host->caps |= MMC_CAP_UHS_SDR104; - if (of_find_property(np, "sd-uhs-ddr50", &len)) + if (of_property_read_bool(np, "sd-uhs-ddr50")) host->caps |= MMC_CAP_UHS_DDR50; - if (of_find_property(np, "cap-power-off-card", &len)) + if (of_property_read_bool(np, "cap-power-off-card")) host->caps |= MMC_CAP_POWER_OFF_CARD; - if (of_find_property(np, "cap-sdio-irq", &len)) + if (of_property_read_bool(np, "cap-sdio-irq")) host->caps |= MMC_CAP_SDIO_IRQ; - if (of_find_property(np, "full-pwr-cycle", &len)) + if (of_property_read_bool(np, "full-pwr-cycle")) host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE; - if (of_find_property(np, "keep-power-in-suspend", &len)) + if (of_property_read_bool(np, "keep-power-in-suspend")) host->pm_caps |= MMC_PM_KEEP_POWER; - if (of_find_property(np, "enable-sdio-wakeup", &len)) + if (of_property_read_bool(np, "enable-sdio-wakeup")) host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ; - if (of_find_property(np, "mmc-ddr-1_8v", &len)) + if (of_property_read_bool(np, "mmc-ddr-1_8v")) host->caps |= MMC_CAP_1_8V_DDR; - if (of_find_property(np, "mmc-ddr-1_2v", &len)) + if (of_property_read_bool(np, "mmc-ddr-1_2v")) host->caps |= MMC_CAP_1_2V_DDR; - if (of_find_property(np, "mmc-hs200-1_8v", &len)) + if (of_property_read_bool(np, "mmc-hs200-1_8v")) host->caps2 |= MMC_CAP2_HS200_1_8V_SDR; - if (of_find_property(np, "mmc-hs200-1_2v", &len)) + if (of_property_read_bool(np, "mmc-hs200-1_2v")) host->caps2 |= MMC_CAP2_HS200_1_2V_SDR; - if (of_find_property(np, "mmc-hs400-1_8v", &len)) + if (of_property_read_bool(np, "mmc-hs400-1_8v")) host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR; - if (of_find_property(np, "mmc-hs400-1_2v", &len)) + if (of_property_read_bool(np, "mmc-hs400-1_2v")) host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR; host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr); -- GitLab From d31911b9374a76560d2c8ea4aa6ce5781621e81d Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 25 Aug 2015 10:02:11 +0800 Subject: [PATCH 5115/7006] mmc: sdhci: fix dma memory leak in sdhci_pre_req() Currently one mrq->data maybe execute dma_map_sg() twice when mmc subsystem prepare over one new request, and the following log show up: sdhci[sdhci_pre_dma_transfer] invalid cookie: 24, next-cookie 25 In this condition, mrq->date map a dma-memory(1) in sdhci_pre_req for the first time, and map another dma-memory(2) in sdhci_prepare_data for the second time. But driver only unmap the dma-memory(2), and dma-memory(1) never unmapped, which cause the dma memory leak issue. This patch use another method to map the dma memory for the mrq->data which can fix this dma memory leak issue. Fixes: 348487cb28e6 ("mmc: sdhci: use pipeline mmc requests to improve performance") Reported-and-tested-by: Jiri Slaby Signed-off-by: Haibo Chen Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 67 +++++++++++++++------------------------- drivers/mmc/host/sdhci.h | 8 ++--- 2 files changed, 29 insertions(+), 46 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 0f1a8876e3b10..31678b55b5ec5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -54,8 +54,7 @@ static void sdhci_finish_command(struct sdhci_host *); static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode); static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable); static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data, - struct sdhci_host_next *next); + struct mmc_data *data); static int sdhci_do_get_cd(struct sdhci_host *host); #ifdef CONFIG_PM @@ -495,7 +494,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host, goto fail; BUG_ON(host->align_addr & host->align_mask); - host->sg_count = sdhci_pre_dma_transfer(host, data, NULL); + host->sg_count = sdhci_pre_dma_transfer(host, data); if (host->sg_count < 0) goto unmap_align; @@ -634,9 +633,11 @@ static void sdhci_adma_table_post(struct sdhci_host *host, } } - if (!data->host_cookie) + if (data->host_cookie == COOKIE_MAPPED) { dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, direction); + data->host_cookie = COOKIE_UNMAPPED; + } } static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd) @@ -832,7 +833,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd) } else { int sg_cnt; - sg_cnt = sdhci_pre_dma_transfer(host, data, NULL); + sg_cnt = sdhci_pre_dma_transfer(host, data); if (sg_cnt <= 0) { /* * This only happens when someone fed @@ -948,11 +949,13 @@ static void sdhci_finish_data(struct sdhci_host *host) if (host->flags & SDHCI_USE_ADMA) sdhci_adma_table_post(host, data); else { - if (!data->host_cookie) + if (data->host_cookie == COOKIE_MAPPED) { dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, (data->flags & MMC_DATA_READ) ? DMA_FROM_DEVICE : DMA_TO_DEVICE); + data->host_cookie = COOKIE_UNMAPPED; + } } } @@ -2116,49 +2119,36 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq, struct mmc_data *data = mrq->data; if (host->flags & SDHCI_REQ_USE_DMA) { - if (data->host_cookie) + if (data->host_cookie == COOKIE_GIVEN || + data->host_cookie == COOKIE_MAPPED) dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len, data->flags & MMC_DATA_WRITE ? DMA_TO_DEVICE : DMA_FROM_DEVICE); - mrq->data->host_cookie = 0; + data->host_cookie = COOKIE_UNMAPPED; } } static int sdhci_pre_dma_transfer(struct sdhci_host *host, - struct mmc_data *data, - struct sdhci_host_next *next) + struct mmc_data *data) { int sg_count; - if (!next && data->host_cookie && - data->host_cookie != host->next_data.cookie) { - pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n", - __func__, data->host_cookie, host->next_data.cookie); - data->host_cookie = 0; + if (data->host_cookie == COOKIE_MAPPED) { + data->host_cookie = COOKIE_GIVEN; + return data->sg_count; } - /* Check if next job is already prepared */ - if (next || - (!next && data->host_cookie != host->next_data.cookie)) { - sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, - data->sg_len, - data->flags & MMC_DATA_WRITE ? - DMA_TO_DEVICE : DMA_FROM_DEVICE); - - } else { - sg_count = host->next_data.sg_count; - host->next_data.sg_count = 0; - } + WARN_ON(data->host_cookie == COOKIE_GIVEN); + sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len, + data->flags & MMC_DATA_WRITE ? + DMA_TO_DEVICE : DMA_FROM_DEVICE); if (sg_count == 0) - return -EINVAL; + return -ENOSPC; - if (next) { - next->sg_count = sg_count; - data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie; - } else - host->sg_count = sg_count; + data->sg_count = sg_count; + data->host_cookie = COOKIE_MAPPED; return sg_count; } @@ -2168,16 +2158,10 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq, { struct sdhci_host *host = mmc_priv(mmc); - if (mrq->data->host_cookie) { - mrq->data->host_cookie = 0; - return; - } + mrq->data->host_cookie = COOKIE_UNMAPPED; if (host->flags & SDHCI_REQ_USE_DMA) - if (sdhci_pre_dma_transfer(host, - mrq->data, - &host->next_data) < 0) - mrq->data->host_cookie = 0; + sdhci_pre_dma_transfer(host, mrq->data); } static void sdhci_card_event(struct mmc_host *mmc) @@ -3049,7 +3033,6 @@ int sdhci_add_host(struct sdhci_host *host) host->max_clk = host->ops->get_max_clock(host); } - host->next_data.cookie = 1; /* * In case of Host Controller v3.00, find out whether clock * multiplier is supported. diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 67046ca0c1f05..7c02ff46c8ac3 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -309,9 +309,10 @@ struct sdhci_adma2_64_desc { */ #define SDHCI_MAX_SEGS 128 -struct sdhci_host_next { - unsigned int sg_count; - s32 cookie; +enum sdhci_cookie { + COOKIE_UNMAPPED, + COOKIE_MAPPED, + COOKIE_GIVEN, }; struct sdhci_host { @@ -505,7 +506,6 @@ struct sdhci_host { unsigned int tuning_mode; /* Re-tuning mode supported by host */ #define SDHCI_TUNING_MODE_1 0 - struct sdhci_host_next next_data; unsigned long private[0] ____cacheline_aligned; }; -- GitLab From 77bd2f6f6c65b4ad259394d416855ed561f21e8f Mon Sep 17 00:00:00 2001 From: Yangbo Lu Date: Tue, 11 Aug 2015 10:53:34 +0800 Subject: [PATCH 5116/7006] mmc: sdhci-of-esdhc: add workaround for pre divider initial value For eSDHC(version < 2.3), the pre divider only could divide base clock by 2 at least. Add workaround for this to avoid unexpected issue. Signed-off-by: Yangbo Lu Acked-by: Joakim Tjernlund Fixes: bd455029d01c ("mmc: sdhci-of-esdhc: Pre divider starts at 1") Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-esdhc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c index 797be7549a15c..653f335bef151 100644 --- a/drivers/mmc/host/sdhci-of-esdhc.c +++ b/drivers/mmc/host/sdhci-of-esdhc.c @@ -208,6 +208,12 @@ static void esdhc_of_set_clock(struct sdhci_host *host, unsigned int clock) if (clock == 0) return; + /* Workaround to start pre_div at 2 for VNN < VENDOR_V_23 */ + temp = esdhc_readw(host, SDHCI_HOST_VERSION); + temp = (temp & SDHCI_VENDOR_VER_MASK) >> SDHCI_VENDOR_VER_SHIFT; + if (temp < VENDOR_V_23) + pre_div = 2; + /* Workaround to reduce the clock frequency for p1010 esdhc */ if (of_find_compatible_node(NULL, NULL, "fsl,p1010-esdhc")) { if (clock > 20000000) -- GitLab From 2a2a7ea7c0126d388c14c28927cdba429b4858dd Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 11 Aug 2015 19:38:28 +0800 Subject: [PATCH 5117/7006] mmc: sdhci-esdhc-imx: Document new DT bindings for imx7d support Add a required property "fsl,imx7d-usdhc" in binding doc. Add an optional property "fsl,tuning-step" in binding doc. Signed-off-by: Haibo Chen Acked-by: Dong Aisheng Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt index 211e7785f4d24..dca56d6248f59 100644 --- a/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt +++ b/Documentation/devicetree/bindings/mmc/fsl-imx-esdhc.txt @@ -15,6 +15,7 @@ Required properties: "fsl,imx6q-usdhc" "fsl,imx6sl-usdhc" "fsl,imx6sx-usdhc" + "fsl,imx7d-usdhc" Optional properties: - fsl,wp-controller : Indicate to use controller internal write protection @@ -27,6 +28,11 @@ Optional properties: transparent level shifters on the outputs of the controller. Two cells are required, first cell specifies minimum slot voltage (mV), second cell specifies maximum slot voltage (mV). Several ranges could be specified. +- fsl,tuning-step: Specify the increasing delay cell steps in tuning procedure. + The uSDHC use one delay cell as default increasing step to do tuning process. + This property allows user to change the tuning step to more than one delay + cells which is useful for some special boards or cards when the default + tuning step can't find the proper delay window within limited tuning retries. Examples: -- GitLab From 28b07674f287092f3b63a7d5e5c7e68bdeed0247 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 11 Aug 2015 19:38:26 +0800 Subject: [PATCH 5118/7006] mmc: sdhci-esdhc-imx: add imx7d support and support HS400 The imx7d usdhc is derived from imx6sx, the difference is that imx7d support HS400. So introduce a new compatible string for imx7d and add HS400 support for imx7d usdhc. Signed-off-by: Haibo Chen Acked-by: Dong Aisheng Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 86 ++++++++++++++++++++++++++++-- 1 file changed, 83 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index c6b9f6492e1a2..b8b7e8842ed0c 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -44,6 +44,7 @@ #define ESDHC_MIX_CTRL_EXE_TUNE (1 << 22) #define ESDHC_MIX_CTRL_SMPCLK_SEL (1 << 23) #define ESDHC_MIX_CTRL_FBCLK_SEL (1 << 25) +#define ESDHC_MIX_CTRL_HS400_EN (1 << 26) /* Bits 3 and 6 are not SDHCI standard definitions */ #define ESDHC_MIX_CTRL_SDHCI_MASK 0xb7 /* Tuning bits */ @@ -60,6 +61,16 @@ #define ESDHC_TUNE_CTRL_MIN 0 #define ESDHC_TUNE_CTRL_MAX ((1 << 7) - 1) +/* strobe dll register */ +#define ESDHC_STROBE_DLL_CTRL 0x70 +#define ESDHC_STROBE_DLL_CTRL_ENABLE (1 << 0) +#define ESDHC_STROBE_DLL_CTRL_RESET (1 << 1) +#define ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT 3 + +#define ESDHC_STROBE_DLL_STATUS 0x74 +#define ESDHC_STROBE_DLL_STS_REF_LOCK (1 << 1) +#define ESDHC_STROBE_DLL_STS_SLV_LOCK 0x1 + #define ESDHC_TUNING_CTRL 0xcc #define ESDHC_STD_TUNING_EN (1 << 24) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ @@ -120,6 +131,11 @@ #define ESDHC_FLAG_ERR004536 BIT(7) /* The IP supports HS200 mode */ #define ESDHC_FLAG_HS200 BIT(8) +/* The IP supports HS400 mode */ +#define ESDHC_FLAG_HS400 BIT(9) + +/* A higher clock ferquency than this rate requires strobell dll control */ +#define ESDHC_STROBE_DLL_CLK_FREQ 100000000 struct esdhc_soc_data { u32 flags; @@ -156,6 +172,12 @@ static struct esdhc_soc_data usdhc_imx6sx_data = { | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200, }; +static struct esdhc_soc_data usdhc_imx7d_data = { + .flags = ESDHC_FLAG_USDHC | ESDHC_FLAG_STD_TUNING + | ESDHC_FLAG_HAVE_CAP1 | ESDHC_FLAG_HS200 + | ESDHC_FLAG_HS400, +}; + struct pltfm_imx_data { u32 scratchpad; struct pinctrl *pinctrl; @@ -199,6 +221,7 @@ static const struct of_device_id imx_esdhc_dt_ids[] = { { .compatible = "fsl,imx6sx-usdhc", .data = &usdhc_imx6sx_data, }, { .compatible = "fsl,imx6sl-usdhc", .data = &usdhc_imx6sl_data, }, { .compatible = "fsl,imx6q-usdhc", .data = &usdhc_imx6q_data, }, + { .compatible = "fsl,imx7d-usdhc", .data = &usdhc_imx7d_data, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, imx_esdhc_dt_ids); @@ -274,6 +297,9 @@ static u32 esdhc_readl_le(struct sdhci_host *host, int reg) val = SDHCI_SUPPORT_DDR50 | SDHCI_SUPPORT_SDR104 | SDHCI_SUPPORT_SDR50 | SDHCI_USE_SDR50_TUNING; + + if (imx_data->socdata->flags & ESDHC_FLAG_HS400) + val |= SDHCI_SUPPORT_HS400; } } @@ -774,6 +800,7 @@ static int esdhc_change_pinstate(struct sdhci_host *host, break; case MMC_TIMING_UHS_SDR104: case MMC_TIMING_MMC_HS200: + case MMC_TIMING_MMC_HS400: pinctrl = imx_data->pins_200mhz; break; default: @@ -784,24 +811,68 @@ static int esdhc_change_pinstate(struct sdhci_host *host, return pinctrl_select_state(imx_data->pinctrl, pinctrl); } +/* + * For HS400 eMMC, there is a data_strobe line, this signal is generated + * by the device and used for data output and CRC status response output + * in HS400 mode. The frequency of this signal follows the frequency of + * CLK generated by host. Host receive the data which is aligned to the + * edge of data_strobe line. Due to the time delay between CLK line and + * data_strobe line, if the delay time is larger than one clock cycle, + * then CLK and data_strobe line will misaligned, read error shows up. + * So when the CLK is higher than 100MHz, each clock cycle is short enough, + * host should config the delay target. + */ +static void esdhc_set_strobe_dll(struct sdhci_host *host) +{ + u32 v; + + if (host->mmc->actual_clock > ESDHC_STROBE_DLL_CLK_FREQ) { + /* force a reset on strobe dll */ + writel(ESDHC_STROBE_DLL_CTRL_RESET, + host->ioaddr + ESDHC_STROBE_DLL_CTRL); + /* + * enable strobe dll ctrl and adjust the delay target + * for the uSDHC loopback read clock + */ + v = ESDHC_STROBE_DLL_CTRL_ENABLE | + (7 << ESDHC_STROBE_DLL_CTRL_SLV_DLY_TARGET_SHIFT); + writel(v, host->ioaddr + ESDHC_STROBE_DLL_CTRL); + /* wait 1us to make sure strobe dll status register stable */ + udelay(1); + v = readl(host->ioaddr + ESDHC_STROBE_DLL_STATUS); + if (!(v & ESDHC_STROBE_DLL_STS_REF_LOCK)) + dev_warn(mmc_dev(host->mmc), + "warning! HS400 strobe DLL status REF not lock!\n"); + if (!(v & ESDHC_STROBE_DLL_STS_SLV_LOCK)) + dev_warn(mmc_dev(host->mmc), + "warning! HS400 strobe DLL status SLV not lock!\n"); + } +} + static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) { + u32 m; struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct pltfm_imx_data *imx_data = pltfm_host->priv; struct esdhc_platform_data *boarddata = &imx_data->boarddata; + /* disable ddr mode and disable HS400 mode */ + m = readl(host->ioaddr + ESDHC_MIX_CTRL); + m &= ~(ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN); + imx_data->is_ddr = 0; + switch (timing) { case MMC_TIMING_UHS_SDR12: case MMC_TIMING_UHS_SDR25: case MMC_TIMING_UHS_SDR50: case MMC_TIMING_UHS_SDR104: case MMC_TIMING_MMC_HS200: + writel(m, host->ioaddr + ESDHC_MIX_CTRL); break; case MMC_TIMING_UHS_DDR50: case MMC_TIMING_MMC_DDR52: - writel(readl(host->ioaddr + ESDHC_MIX_CTRL) | - ESDHC_MIX_CTRL_DDREN, - host->ioaddr + ESDHC_MIX_CTRL); + m |= ESDHC_MIX_CTRL_DDREN; + writel(m, host->ioaddr + ESDHC_MIX_CTRL); imx_data->is_ddr = 1; if (boarddata->delay_line) { u32 v; @@ -813,6 +884,12 @@ static void esdhc_set_uhs_signaling(struct sdhci_host *host, unsigned timing) writel(v, host->ioaddr + ESDHC_DLL_CTRL); } break; + case MMC_TIMING_MMC_HS400: + m |= ESDHC_MIX_CTRL_DDREN | ESDHC_MIX_CTRL_HS400_EN; + writel(m, host->ioaddr + ESDHC_MIX_CTRL); + imx_data->is_ddr = 1; + esdhc_set_strobe_dll(host); + break; } esdhc_change_pinstate(host, timing); @@ -1100,6 +1177,9 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) if (imx_data->socdata->flags & ESDHC_FLAG_ERR004536) host->quirks |= SDHCI_QUIRK_BROKEN_ADMA; + if (imx_data->socdata->flags & ESDHC_FLAG_HS400) + host->quirks2 |= SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400; + if (of_id) err = sdhci_esdhc_imx_probe_dt(pdev, host, imx_data); else -- GitLab From d407e30ba614b1542c8ac032f8fb2332b8071efe Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 11 Aug 2015 19:38:27 +0800 Subject: [PATCH 5119/7006] mmc: sdhci-esdhc-imx: add tuning-step setting support tuning-step is the delay cell steps in tuning procedure. The default value of tuning-step is 1. Some boards or cards need another value to pass the tuning procedure. For example, imx7d-sdb board need the tuning-step value as 2, otherwise it can't pass the tuning procedure. So this patch add the tuning-step setting in driver, so that user can set the tuning-step value in dts. Signed-off-by: Haibo Chen Acked-by: Dong Aisheng Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 9 +++++++++ include/linux/platform_data/mmc-esdhc-imx.h | 1 + 2 files changed, 10 insertions(+) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index b8b7e8842ed0c..298551d00fa4c 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -75,6 +75,7 @@ #define ESDHC_STD_TUNING_EN (1 << 24) /* NOTE: the minimum valid tuning start tap for mx6sl is 1 */ #define ESDHC_TUNING_START_TAP 0x1 +#define ESDHC_TUNING_STEP_SHIFT 16 /* pinctrl state */ #define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz" @@ -474,6 +475,7 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) } else if (imx_data->socdata->flags & ESDHC_FLAG_STD_TUNING) { u32 v = readl(host->ioaddr + SDHCI_ACMD12_ERR); u32 m = readl(host->ioaddr + ESDHC_MIX_CTRL); + u32 tuning_ctrl; if (val & SDHCI_CTRL_TUNED_CLK) { v |= ESDHC_MIX_CTRL_SMPCLK_SEL; } else { @@ -484,6 +486,11 @@ static void esdhc_writew_le(struct sdhci_host *host, u16 val, int reg) if (val & SDHCI_CTRL_EXEC_TUNING) { v |= ESDHC_MIX_CTRL_EXE_TUNE; m |= ESDHC_MIX_CTRL_FBCLK_SEL; + tuning_ctrl = readl(host->ioaddr + ESDHC_TUNING_CTRL); + tuning_ctrl |= ESDHC_STD_TUNING_EN | ESDHC_TUNING_START_TAP; + if (imx_data->boarddata.tuning_step) + tuning_ctrl |= imx_data->boarddata.tuning_step << ESDHC_TUNING_STEP_SHIFT; + writel(tuning_ctrl, host->ioaddr + ESDHC_TUNING_CTRL); } else { v &= ~ESDHC_MIX_CTRL_EXE_TUNE; } @@ -963,6 +970,8 @@ sdhci_esdhc_imx_probe_dt(struct platform_device *pdev, if (gpio_is_valid(boarddata->wp_gpio)) boarddata->wp_type = ESDHC_WP_GPIO; + of_property_read_u32(np, "fsl,tuning-step", &boarddata->tuning_step); + if (of_find_property(np, "no-1-8-v", NULL)) boarddata->support_vsel = false; else diff --git a/include/linux/platform_data/mmc-esdhc-imx.h b/include/linux/platform_data/mmc-esdhc-imx.h index e1571efa3f2b2..95ccab3f454a9 100644 --- a/include/linux/platform_data/mmc-esdhc-imx.h +++ b/include/linux/platform_data/mmc-esdhc-imx.h @@ -45,5 +45,6 @@ struct esdhc_platform_data { int max_bus_width; bool support_vsel; unsigned int delay_line; + unsigned int tuning_step; /* The delay cell steps in tuning procedure */ }; #endif /* __ASM_ARCH_IMX_ESDHC_H */ -- GitLab From fd44954e77b436673eb5221e5485a32ea6550128 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 11 Aug 2015 19:38:30 +0800 Subject: [PATCH 5120/7006] mmc: sdhci-esdhc-imx: set back the burst_length_enable bit to 1 Currently we find that if a usdhc is choosed to boot system, then ROM code will set the burst length enable bit of this usdhc as 0. This will make performance drop a lot if this usdhc's burst length is configed. So this patch set back the burst_length_enable bit as 1, which is the default value, and means burst length is enabled for INCR. Signed-off-by: Haibo Chen Acked-by: Dong Aisheng Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index 298551d00fa4c..ac8ec01b89aa5 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -32,6 +32,7 @@ #include "sdhci-esdhc.h" #define ESDHC_CTRL_D3CD 0x08 +#define ESDHC_BURST_LEN_EN_INCR (1 << 27) /* VENDOR SPEC register */ #define ESDHC_VENDOR_SPEC 0xc0 #define ESDHC_VENDOR_SPEC_SDIO_QUIRK (1 << 1) @@ -1163,6 +1164,21 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->mmc->caps |= MMC_CAP_1_8V_DDR; + /* + * ROM code will change the bit burst_length_enable setting + * to zero if this usdhc is choosed to boot system. Change + * it back here, otherwise it will impact the performance a + * lot. This bit is used to enable/disable the burst length + * for the external AHB2AXI bridge, it's usefully especially + * for INCR transfer because without burst length indicator, + * the AHB2AXI bridge does not know the burst length in + * advance. And without burst length indicator, AHB INCR + * transfer can only be converted to singles on the AXI side. + */ + writel(readl(host->ioaddr + SDHCI_HOST_CONTROL) + | ESDHC_BURST_LEN_EN_INCR, + host->ioaddr + SDHCI_HOST_CONTROL); + if (!(imx_data->socdata->flags & ESDHC_FLAG_HS200)) host->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200; -- GitLab From e31e67cf2578bd05e99afabb22403542306d6bed Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Tue, 11 Aug 2015 19:38:31 +0800 Subject: [PATCH 5121/7006] mmc: sdhci-esdhc-imx: change default watermark level and burst length By default, for all imx SoC types, the watermark level is 16, and the burst length is 8. But if the SDIO/SD/MMC I/O speed is fast enough, this default watermark level and burst length will be the performance bottleneck. For example, i.MX7D support eMMC HS400 mode, this mode can run in 8 bit, 200MHZ DDR mode. So the I/O speed improve a lot compare to SD3.0. The default burst length is 8, if we don't change this value, in HS400 mode, when we do eMMC read operation, we can find that the clock signal will stop for a period of time. This means the speed of data moving on AHB bus is slower than I/O speed. So we should improve the speed of data moving on AHB bus. This patch set the default burst length as 16, and set the default watermark level as 64. The test result is the clock signal has no stop during the eMMC HS400 operation. Signed-off-by: Haibo Chen Acked-by: Dong Aisheng Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-esdhc-imx.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c index ac8ec01b89aa5..886d230f41d07 100644 --- a/drivers/mmc/host/sdhci-esdhc-imx.c +++ b/drivers/mmc/host/sdhci-esdhc-imx.c @@ -1160,7 +1160,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev) * to something insane. Change it back here. */ if (esdhc_is_usdhc(imx_data)) { - writel(0x08100810, host->ioaddr + ESDHC_WTMK_LVL); + writel(0x10401040, host->ioaddr + ESDHC_WTMK_LVL); + host->quirks2 |= SDHCI_QUIRK2_PRESET_VALUE_BROKEN; host->mmc->caps |= MMC_CAP_1_8V_DDR; -- GitLab From b5b4ff0a633910b2b9dca7915fd6ab17aa10dc3e Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 12 Aug 2015 13:08:32 +0800 Subject: [PATCH 5122/7006] mmc: block: skip trim for some kingston eMMCs For some mass production of kingston eMMCs which adopt Phison's firmware will meet an unrecoverable data conrruption occasionally if performing trim due to a firmware bug confirmed by vendor. We found it on Intel-C3230RK platform. So we add fixup of broken trim for it. Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/card/block.c | 10 ++++++++++ drivers/mmc/core/core.c | 3 ++- include/linux/mmc/card.h | 2 ++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index a58287e574cc8..c742cfd7674e0 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -2389,6 +2389,7 @@ force_ro_fail: #define CID_MANFID_TOSHIBA 0x11 #define CID_MANFID_MICRON 0x13 #define CID_MANFID_SAMSUNG 0x15 +#define CID_MANFID_KINGSTON 0x70 static const struct mmc_fixup blk_fixups[] = { @@ -2451,6 +2452,15 @@ static const struct mmc_fixup blk_fixups[] = MMC_FIXUP("VZL00M", CID_MANFID_SAMSUNG, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_SEC_ERASE_TRIM_BROKEN), + /* + * On Some Kingston eMMCs, performing trim can result in + * unrecoverable data conrruption occasionally due to a firmware bug. + */ + MMC_FIXUP("V10008", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_TRIM_BROKEN), + MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, + MMC_QUIRK_TRIM_BROKEN), + END_FIXUP }; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 57edb2a9bb04b..664b61729fa96 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2250,7 +2250,8 @@ EXPORT_SYMBOL(mmc_can_erase); int mmc_can_trim(struct mmc_card *card) { - if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) + if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) && + (!(card->quirks & MMC_QUIRK_TRIM_BROKEN))) return 1; return 0; } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 8fcbcd13218f5..fdd0779ccdfa5 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -279,6 +279,8 @@ struct mmc_card { #define MMC_QUIRK_LONG_READ_TIME (1<<9) /* Data read time > CSD says */ #define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */ #define MMC_QUIRK_BROKEN_IRQ_POLLING (1<<11) /* Polling SDIO_CCCR_INTx could create a fake interrupt */ +#define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */ + unsigned int erase_size; /* erase size in sectors */ unsigned int erase_shift; /* if erase unit is power 2 */ -- GitLab From 1880d8f6fbb01a16404dee7167621dc09b5f1d35 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Wed, 12 Aug 2015 06:59:33 +0000 Subject: [PATCH 5123/7006] mmc: sdhci-sirf: corrent quirk according to real chips the current quirk set is for an old FPGA, and this patch corrects quirks according to real SoC. Signed-off-by: Barry Song Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-sirf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c index 0110bae25b7e8..884294576356d 100644 --- a/drivers/mmc/host/sdhci-sirf.c +++ b/drivers/mmc/host/sdhci-sirf.c @@ -161,8 +161,8 @@ static struct sdhci_pltfm_data sdhci_sirf_pdata = { .quirks = SDHCI_QUIRK_BROKEN_TIMEOUT_VAL | SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK | SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | - SDHCI_QUIRK_INVERTED_WRITE_PROTECT | - SDHCI_QUIRK_DELAY_AFTER_POWER, + SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, + .quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN, }; static int sdhci_sirf_probe(struct platform_device *pdev) -- GitLab From 7bb9c244356d2d45ac03cf65e55b035c5954d7de Mon Sep 17 00:00:00 2001 From: Michal Suchanek Date: Wed, 12 Aug 2015 15:29:31 +0200 Subject: [PATCH 5124/7006] mmc: sunxi: fix timeout in sunxi_mmc_oclk_onoff The 250ms timeout is too short. On my system enabling the oclk takes under 50ms and disabling slightly over 100ms when idle. Under load disabling the clock can take over 350ms. This does not make mmc clock gating look like good option to have on sunxi but the system should not crash with mmc clock gating enabled nonetheless. This patch sets the timeout to 750ms. Signed-off-by: Michal Suchanek Acked-by: Hans de Goede Signed-off-by: Ulf Hansson --- drivers/mmc/host/sunxi-mmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c index 4d3e1ffe55082..a7b7a67715986 100644 --- a/drivers/mmc/host/sunxi-mmc.c +++ b/drivers/mmc/host/sunxi-mmc.c @@ -595,7 +595,7 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id) static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en) { - unsigned long expire = jiffies + msecs_to_jiffies(250); + unsigned long expire = jiffies + msecs_to_jiffies(750); u32 rval; rval = mmc_readl(host, REG_CLKCR); -- GitLab From f912632b6086d4464af2443dee0c6f4055cf5159 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:26:48 +0200 Subject: [PATCH 5125/7006] mmc: atmel-mci: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni Acked-by: Ludovic Desroches Signed-off-by: Ulf Hansson --- drivers/mmc/host/atmel-mci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c index 9a39e0b7e5836..bf62e429f7fcc 100644 --- a/drivers/mmc/host/atmel-mci.c +++ b/drivers/mmc/host/atmel-mci.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include -- GitLab From 0dafa60eb2506617e6968b97cc5a44914a7fb1a6 Mon Sep 17 00:00:00 2001 From: Jisheng Zhang Date: Tue, 18 Aug 2015 16:21:39 +0800 Subject: [PATCH 5126/7006] mmc: sdhci: also get preset value and driver type for MMC_DDR52 commit bb8175a8aa42 ("mmc: sdhci: clarify DDR timing mode between SD-UHS and eMMC") added MMC_DDR52 as eMMC's DDR mode to be distinguished from SD-UHS, but it missed setting driver type for MMC_DDR52 timing mode. So sometimes we get the following error on Marvell BG2Q DMP board: [ 1.559598] mmcblk0: error -84 transferring data, sector 0, nr 8, cmd response 0x900, card status 0xb00 [ 1.569314] mmcblk0: retrying using single block read [ 1.575676] mmcblk0: error -84 transferring data, sector 2, nr 6, cmd response 0x900, card status 0x0 [ 1.585202] blk_update_request: I/O error, dev mmcblk0, sector 2 [ 1.591818] mmcblk0: error -84 transferring data, sector 3, nr 5, cmd response 0x900, card status 0x0 [ 1.601341] blk_update_request: I/O error, dev mmcblk0, sector 3 This patches fixes this by adding the missing driver type setting. Fixes: bb8175a8aa42 ("mmc: sdhci: clarify DDR timing mode ...") Signed-off-by: Jisheng Zhang Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 31678b55b5ec5..64b7fdbd1a9cc 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1134,6 +1134,7 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host) preset = sdhci_readw(host, SDHCI_PRESET_FOR_SDR104); break; case MMC_TIMING_UHS_DDR50: + case MMC_TIMING_MMC_DDR52: preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50); break; case MMC_TIMING_MMC_HS400: @@ -1575,7 +1576,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios) (ios->timing == MMC_TIMING_UHS_SDR25) || (ios->timing == MMC_TIMING_UHS_SDR50) || (ios->timing == MMC_TIMING_UHS_SDR104) || - (ios->timing == MMC_TIMING_UHS_DDR50))) { + (ios->timing == MMC_TIMING_UHS_DDR50) || + (ios->timing == MMC_TIMING_MMC_DDR52))) { u16 preset; sdhci_enable_preset_value(host, true); -- GitLab From da795ec26e2542f1e306598a1d7a31c0762f2bd7 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Tue, 11 Aug 2015 15:57:05 +0800 Subject: [PATCH 5127/7006] mmc: sdhci-of-arasan: Add the support for sdhci-5.1 This patch adds the compatible string in sdhci-of-arasan.c to support sdhci-arasan5.1 version of controller. No documented controller IP version is found in the TRM, so we use ths version of command queueing engine integrated into this controller by arasan to specify our controller. Signed-off-by: Shawn Lin Acked-by: Michal Simek Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/arasan,sdhci.txt | 2 +- drivers/mmc/host/sdhci-of-arasan.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt index 7e9490313d5ad..da541c3631f81 100644 --- a/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt +++ b/Documentation/devicetree/bindings/mmc/arasan,sdhci.txt @@ -9,7 +9,7 @@ Device Tree Bindings for the Arasan SDHCI Controller Required Properties: - compatible: Compatibility string. Must be 'arasan,sdhci-8.9a' or - 'arasan,sdhci-4.9a' + 'arasan,sdhci-4.9a' or 'arasan,sdhci-5.1' - reg: From mmc bindings: Register location and length. - clocks: From clock bindings: Handles to clock inputs. - clock-names: From clock bindings: Tuple including "clk_xin" and "clk_ahb" diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c index ef5a7d241323a..75379cb0fb354 100644 --- a/drivers/mmc/host/sdhci-of-arasan.c +++ b/drivers/mmc/host/sdhci-of-arasan.c @@ -217,6 +217,7 @@ static int sdhci_arasan_remove(struct platform_device *pdev) static const struct of_device_id sdhci_arasan_of_match[] = { { .compatible = "arasan,sdhci-8.9a" }, + { .compatible = "arasan,sdhci-5.1" }, { .compatible = "arasan,sdhci-4.9a" }, { } }; -- GitLab From 767264725d6c0c8e2a42f14ded88c8f05fec5863 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 19 Aug 2015 15:41:34 +0200 Subject: [PATCH 5128/7006] mmc: usdhi6rol0: handle probe deferral for regulator We ignore errors from mmc_regulator_get_supply() because the usage of the regulators is optional for the driver, but we still need to check for and handle EPROBE_DEFER, like it's done in for example dw_mmc. Otherwise we might end up not using the specified regulators just because of probe order. Signed-off-by: Rabin Vincent Signed-off-by: Ulf Hansson --- drivers/mmc/host/usdhi6rol0.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 54b082b1804a5..63d5d722b01f4 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1715,12 +1715,14 @@ static int usdhi6_probe(struct platform_device *pdev) if (!mmc) return -ENOMEM; + ret = mmc_regulator_get_supply(mmc); + if (ret == -EPROBE_DEFER) + goto e_free_mmc; + ret = mmc_of_parse(mmc); if (ret < 0) goto e_free_mmc; - mmc_regulator_get_supply(mmc); - host = mmc_priv(mmc); host->mmc = mmc; host->wait = USDHI6_WAIT_FOR_REQUEST; -- GitLab From bb08a7d489bd22a9b6e489f8c8449b0bc92594d0 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 19 Aug 2015 15:41:35 +0200 Subject: [PATCH 5129/7006] mmc: usdhi6rol0: fix NULL pointer deref in debug print host->sg is only set when we're transferring multiple blocks. Check for its availibility before dereferencing it in the timeout work debug print. Signed-off-by: Rabin Vincent Signed-off-by: Ulf Hansson --- drivers/mmc/host/usdhi6rol0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 63d5d722b01f4..4188e84ea4501 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1634,6 +1634,7 @@ static void usdhi6_timeout_work(struct work_struct *work) struct usdhi6_host *host = container_of(d, struct usdhi6_host, timeout_work); struct mmc_request *mrq = host->mrq; struct mmc_data *data = mrq ? mrq->data : NULL; + struct scatterlist *sg = host->sg ?: data->sg; dev_warn(mmc_dev(host->mmc), "%s timeout wait %u CMD%d: IRQ 0x%08x:0x%08x, last IRQ 0x%08x\n", @@ -1669,7 +1670,7 @@ static void usdhi6_timeout_work(struct work_struct *work) "%c: page #%u @ +0x%zx %ux%u in SG%u. Current SG %u bytes @ %u\n", data->flags & MMC_DATA_READ ? 'R' : 'W', host->page_idx, host->offset, data->blocks, data->blksz, data->sg_len, - sg_dma_len(host->sg), host->sg->offset); + sg_dma_len(sg), sg->offset); usdhi6_sg_unmap(host, true); /* * If USDHI6_WAIT_FOR_DATA_END times out, we have already unmapped -- GitLab From 3fe95db19be6a98bcb45d2780c6a90d1e96bfcc9 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Wed, 19 Aug 2015 15:41:36 +0200 Subject: [PATCH 5130/7006] mmc: usdhi6rol0: fix ack register write The intent appears to be to clear only the bits which are set in status (by setting them to zero in the ack write), like in the other interrupt handlers, and not to always clear everything (by always writing zero). Use the correct not operator. Signed-off-by: Rabin Vincent Signed-off-by: Ulf Hansson --- drivers/mmc/host/usdhi6rol0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index 4188e84ea4501..b505cbc25aac5 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1611,7 +1611,7 @@ static irqreturn_t usdhi6_cd(int irq, void *dev_id) return IRQ_NONE; /* Ack */ - usdhi6_write(host, USDHI6_SD_INFO1, !status); + usdhi6_write(host, USDHI6_SD_INFO1, ~status); if (!work_pending(&mmc->detect.work) && (((status & USDHI6_SD_INFO1_CARD_INSERT) && -- GitLab From 38276a912c9bb6dc48e21dc23a92b6286ca00962 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:12 +0200 Subject: [PATCH 5131/7006] mmc: omap: fix error return code Return a negative error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/omap.c b/drivers/mmc/host/omap.c index 70dcf074fbe3f..b763b11ed9e1e 100644 --- a/drivers/mmc/host/omap.c +++ b/drivers/mmc/host/omap.c @@ -1420,8 +1420,10 @@ static int mmc_omap_probe(struct platform_device *pdev) host->reg_shift = (mmc_omap7xx() ? 1 : 2); host->mmc_omap_wq = alloc_workqueue("mmc_omap", 0, 0); - if (!host->mmc_omap_wq) + if (!host->mmc_omap_wq) { + ret = -ENOMEM; goto err_plat_cleanup; + } for (i = 0; i < pdata->nr_slots; i++) { ret = mmc_omap_new_slot(host, i); -- GitLab From 3b1cac4d9f915758d0d755f11bb8fd4373cf653b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:17 +0200 Subject: [PATCH 5132/7006] mmc: usdhi6rol0: fix error return code Propagate error code on failure. A simplified version of the semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Ulf Hansson --- drivers/mmc/host/usdhi6rol0.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/mmc/host/usdhi6rol0.c b/drivers/mmc/host/usdhi6rol0.c index b505cbc25aac5..4498e92116b80 100644 --- a/drivers/mmc/host/usdhi6rol0.c +++ b/drivers/mmc/host/usdhi6rol0.c @@ -1737,8 +1737,10 @@ static int usdhi6_probe(struct platform_device *pdev) } host->clk = devm_clk_get(dev, NULL); - if (IS_ERR(host->clk)) + if (IS_ERR(host->clk)) { + ret = PTR_ERR(host->clk); goto e_free_mmc; + } host->imclk = clk_get_rate(host->clk); -- GitLab From 5afc30fc666165c1c37c246e08b4282bc8c31d98 Mon Sep 17 00:00:00 2001 From: Koji Matsuoka Date: Sun, 23 Aug 2015 21:58:08 +0900 Subject: [PATCH 5133/7006] mmc: sh_mmcif: Fix suspend process The clock should be enable when SDHI registers are accessed. Signed-off-by: Koji Matsuoka Signed-off-by: Yoshihiro Kaneko Signed-off-by: Ulf Hansson --- drivers/mmc/host/sh_mmcif.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 5a1fdd405b1af..ad9ffea7d659d 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -1632,7 +1632,9 @@ static int sh_mmcif_suspend(struct device *dev) { struct sh_mmcif_host *host = dev_get_drvdata(dev); + pm_runtime_get_sync(dev); sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); + pm_runtime_put(dev); return 0; } -- GitLab From 5f2b3eab3fade514f9647e88356d29c7795ed7ef Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Tue, 25 Aug 2015 16:13:29 +0200 Subject: [PATCH 5134/7006] mmc: sdhci-of-at91: fix platform_no_drv_owner.cocci warnings Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: ludovic.desroches@atmel.com Signed-off-by: Fengguang Wu Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci-of-at91.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/sdhci-of-at91.c b/drivers/mmc/host/sdhci-of-at91.c index 7a9f4b19f9895..d1556643a41d3 100644 --- a/drivers/mmc/host/sdhci-of-at91.c +++ b/drivers/mmc/host/sdhci-of-at91.c @@ -177,7 +177,6 @@ static int sdhci_at91_remove(struct platform_device *pdev) static struct platform_driver sdhci_at91_driver = { .driver = { .name = "sdhci-at91", - .owner = THIS_MODULE, .of_match_table = sdhci_at91_dt_match, .pm = SDHCI_PLTFM_PMOPS, }, -- GitLab From 7d607f917008218564ae44ca3ef47076a9b36e8f Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:53 +0530 Subject: [PATCH 5135/7006] mmc: host: omap_hsmmc: use devm_regulator_get_optional() for vmmc Since vmmc can be optional for some platforms, use devm_regulator_get_optional() for vmmc. Now return error only if the return value of devm_regulator_get_optional() is not the same as -ENODEV, since with -EPROBE_DEFER, the regulator can be obtained later and all other errors are fatal. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 19ae7e6935260..9b335aff58828 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -345,15 +345,19 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { struct regulator *reg; int ocr_value = 0; + int ret; if (mmc_pdata(host)->set_power) return 0; - reg = devm_regulator_get(host->dev, "vmmc"); + reg = devm_regulator_get_optional(host->dev, "vmmc"); if (IS_ERR(reg)) { - dev_err(host->dev, "unable to get vmmc regulator %ld\n", + ret = PTR_ERR(reg); + if (ret != -ENODEV) + return ret; + host->vcc = NULL; + dev_dbg(host->dev, "unable to get vmmc regulator %ld\n", PTR_ERR(reg)); - return PTR_ERR(reg); } else { host->vcc = reg; ocr_value = mmc_regulator_get_ocrmask(reg); -- GitLab From 6a9b2ff07d0415ad19fb07b9a141863fb86c3497 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:54 +0530 Subject: [PATCH 5136/7006] mmc: host: omap_hsmmc: return on fatal errors from omap_hsmmc_reg_get Now return error only if the return value of devm_regulator_get_optional() is not the same as -ENODEV, since with -EPROBE_DEFER, the regulator can be obtained later and all other errors are fatal. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 9b335aff58828..2eafd6f646768 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -375,10 +375,28 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) /* Allow an aux regulator */ reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); - host->vcc_aux = IS_ERR(reg) ? NULL : reg; + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + if (ret != -ENODEV) + return ret; + host->vcc_aux = NULL; + dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n", + PTR_ERR(reg)); + } else { + host->vcc_aux = reg; + } reg = devm_regulator_get_optional(host->dev, "pbias"); - host->pbias = IS_ERR(reg) ? NULL : reg; + if (IS_ERR(reg)) { + ret = PTR_ERR(reg); + if (ret != -ENODEV) + return ret; + host->pbias = NULL; + dev_dbg(host->dev, "unable to get pbias regulator %ld\n", + PTR_ERR(reg)); + } else { + host->pbias = reg; + } /* For eMMC do not power off when not in sleep state */ if (mmc_pdata(host)->no_regulator_off_init) -- GitLab From c299dc39883ca5596905507cc945332fa4bae8bd Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:55 +0530 Subject: [PATCH 5137/7006] mmc: host: omap_hsmmc: cleanup omap_hsmmc_reg_get() No functional change. Instead of using a local regulator variable in omap_hsmmc_reg_get() for holding the return value of devm_regulator_get_optional() and then assigning to omap_hsmmc_host regulator members: vcc, vcc_aux and pbias, directly use the omap_hsmmc_host regulator members. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 38 +++++++++++++++-------------------- 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 2eafd6f646768..3fde2f9dfb25e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -343,24 +343,22 @@ error_set_power: static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { - struct regulator *reg; int ocr_value = 0; int ret; if (mmc_pdata(host)->set_power) return 0; - reg = devm_regulator_get_optional(host->dev, "vmmc"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); + host->vcc = devm_regulator_get_optional(host->dev, "vmmc"); + if (IS_ERR(host->vcc)) { + ret = PTR_ERR(host->vcc); if (ret != -ENODEV) return ret; - host->vcc = NULL; dev_dbg(host->dev, "unable to get vmmc regulator %ld\n", - PTR_ERR(reg)); + PTR_ERR(host->vcc)); + host->vcc = NULL; } else { - host->vcc = reg; - ocr_value = mmc_regulator_get_ocrmask(reg); + ocr_value = mmc_regulator_get_ocrmask(host->vcc); if (!mmc_pdata(host)->ocr_mask) { mmc_pdata(host)->ocr_mask = ocr_value; } else { @@ -374,28 +372,24 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) } /* Allow an aux regulator */ - reg = devm_regulator_get_optional(host->dev, "vmmc_aux"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); + host->vcc_aux = devm_regulator_get_optional(host->dev, "vmmc_aux"); + if (IS_ERR(host->vcc_aux)) { + ret = PTR_ERR(host->vcc_aux); if (ret != -ENODEV) return ret; - host->vcc_aux = NULL; dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n", - PTR_ERR(reg)); - } else { - host->vcc_aux = reg; + PTR_ERR(host->vcc_aux)); + host->vcc_aux = NULL; } - reg = devm_regulator_get_optional(host->dev, "pbias"); - if (IS_ERR(reg)) { - ret = PTR_ERR(reg); + host->pbias = devm_regulator_get_optional(host->dev, "pbias"); + if (IS_ERR(host->pbias)) { + ret = PTR_ERR(host->pbias); if (ret != -ENODEV) return ret; - host->pbias = NULL; dev_dbg(host->dev, "unable to get pbias regulator %ld\n", - PTR_ERR(reg)); - } else { - host->pbias = reg; + PTR_ERR(host->pbias)); + host->pbias = NULL; } /* For eMMC do not power off when not in sleep state */ -- GitLab From b49069fc0b96de5dd508ccba0a1417e524734712 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:56 +0530 Subject: [PATCH 5138/7006] mmc: host: omap_hsmmc: use the ocrmask provided by the vmmc regulator If the vmmc regulator provides a valid ocrmask, use it. By this even if the pdata has a valid ocrmask, it will be overwritten with the ocrmask of the vmmc regulator. Also remove the unnecessary compatibility check between the ocrmask in the pdata and the ocrmask from the vmmc regulator. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3fde2f9dfb25e..30f363da1987c 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -359,16 +359,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) host->vcc = NULL; } else { ocr_value = mmc_regulator_get_ocrmask(host->vcc); - if (!mmc_pdata(host)->ocr_mask) { + if (ocr_value > 0) mmc_pdata(host)->ocr_mask = ocr_value; - } else { - if (!(mmc_pdata(host)->ocr_mask & ocr_value)) { - dev_err(host->dev, "ocrmask %x is not supported\n", - mmc_pdata(host)->ocr_mask); - mmc_pdata(host)->ocr_mask = 0; - return -EINVAL; - } - } } /* Allow an aux regulator */ -- GitLab From aa9a68014bb6c6e1052d79561815885b797d15ea Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:57 +0530 Subject: [PATCH 5139/7006] mmc: host: omap_hsmmc: use mmc_host's vmmc and vqmmc No functional change. Instead of using omap_hsmmc_host's vcc and vcc_aux members, use vmmc and vqmmc present in mmc_host which is present for the same purpose. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 63 ++++++++++++++++------------------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 30f363da1987c..58e4ffd3c70e9 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -181,15 +181,6 @@ struct omap_hsmmc_host { struct mmc_data *data; struct clk *fclk; struct clk *dbclk; - /* - * vcc == configured supply - * vcc_aux == optional - * - MMC1, supply for DAT4..DAT7 - * - MMC2/MMC2, external level shifter voltage supply, for - * chip (SDIO, eMMC, etc) or transceiver (MMC2 only) - */ - struct regulator *vcc; - struct regulator *vcc_aux; struct regulator *pbias; bool pbias_enabled; void __iomem *base; @@ -259,6 +250,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = platform_get_drvdata(to_platform_device(dev)); + struct mmc_host *mmc = host->mmc; int ret = 0; if (mmc_pdata(host)->set_power) @@ -268,7 +260,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * If we don't see a Vcc regulator, assume it's a fixed * voltage always-on regulator. */ - if (!host->vcc) + if (!mmc->supply.vmmc) return 0; if (mmc_pdata(host)->before_set_reg) @@ -297,23 +289,23 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - if (host->vcc) - ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd); + if (mmc->supply.vmmc) + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); /* Enable interface voltage rail, if needed */ - if (ret == 0 && host->vcc_aux) { - ret = regulator_enable(host->vcc_aux); - if (ret < 0 && host->vcc) - ret = mmc_regulator_set_ocr(host->mmc, - host->vcc, 0); + if (ret == 0 && mmc->supply.vqmmc) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret < 0 && mmc->supply.vmmc) + ret = mmc_regulator_set_ocr(mmc, + mmc->supply.vmmc, + 0); } } else { /* Shut down the rail */ - if (host->vcc_aux) - ret = regulator_disable(host->vcc_aux); - if (host->vcc) { + if (mmc->supply.vqmmc) + ret = regulator_disable(mmc->supply.vqmmc); + if (mmc->supply.vmmc) { /* Then proceed to shut down the local regulator */ - ret = mmc_regulator_set_ocr(host->mmc, - host->vcc, 0); + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); } } @@ -345,33 +337,34 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { int ocr_value = 0; int ret; + struct mmc_host *mmc = host->mmc; if (mmc_pdata(host)->set_power) return 0; - host->vcc = devm_regulator_get_optional(host->dev, "vmmc"); - if (IS_ERR(host->vcc)) { - ret = PTR_ERR(host->vcc); + mmc->supply.vmmc = devm_regulator_get_optional(host->dev, "vmmc"); + if (IS_ERR(mmc->supply.vmmc)) { + ret = PTR_ERR(mmc->supply.vmmc); if (ret != -ENODEV) return ret; dev_dbg(host->dev, "unable to get vmmc regulator %ld\n", - PTR_ERR(host->vcc)); - host->vcc = NULL; + PTR_ERR(mmc->supply.vmmc)); + mmc->supply.vmmc = NULL; } else { - ocr_value = mmc_regulator_get_ocrmask(host->vcc); + ocr_value = mmc_regulator_get_ocrmask(mmc->supply.vmmc); if (ocr_value > 0) mmc_pdata(host)->ocr_mask = ocr_value; } /* Allow an aux regulator */ - host->vcc_aux = devm_regulator_get_optional(host->dev, "vmmc_aux"); - if (IS_ERR(host->vcc_aux)) { - ret = PTR_ERR(host->vcc_aux); + mmc->supply.vqmmc = devm_regulator_get_optional(host->dev, "vmmc_aux"); + if (IS_ERR(mmc->supply.vqmmc)) { + ret = PTR_ERR(mmc->supply.vqmmc); if (ret != -ENODEV) return ret; dev_dbg(host->dev, "unable to get vmmc_aux regulator %ld\n", - PTR_ERR(host->vcc_aux)); - host->vcc_aux = NULL; + PTR_ERR(mmc->supply.vqmmc)); + mmc->supply.vqmmc = NULL; } host->pbias = devm_regulator_get_optional(host->dev, "pbias"); @@ -391,8 +384,8 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) * To disable boot_on regulator, enable regulator * to increase usecount and then disable it. */ - if ((host->vcc && regulator_is_enabled(host->vcc) > 0) || - (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) { + if ((mmc->supply.vmmc && regulator_is_enabled(mmc->supply.vmmc) > 0) || + (mmc->supply.vqmmc && regulator_is_enabled(mmc->supply.vqmmc))) { int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; omap_hsmmc_set_power(host->dev, 1, vdd); -- GitLab From ef62b8bc2c740a7f72525a4797aa45056c833e3d Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:58 +0530 Subject: [PATCH 5140/7006] mmc: host: omap_hsmmc: remove unnecessary pbias set_voltage Remove the unnecessary pbias regulator_set_voltage done after pbias regulator_disable in omap_hsmmc_set_power. Signed-off-by: Kishon Vijay Abraham I Reviewed-by: Roger Quadros Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 58e4ffd3c70e9..c4c284e0246ad 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -272,7 +272,6 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) if (!ret) host->pbias_enabled = 0; } - regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0); } /* -- GitLab From 229f329265d6d2a738fc861b7b9b6144980580f6 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:43:59 +0530 Subject: [PATCH 5141/7006] mmc: host: omap_hsmmc: return error if any of the regulator APIs fail Return error if any of the regulator APIs (regulator_enable, regulator_disable, regulator_set_voltage) fails in omap_hsmmc_set_power to avoid undefined behavior. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 52 +++++++++++++++++++++++++++-------- 1 file changed, 40 insertions(+), 12 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index c4c284e0246ad..284ab0063156e 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -269,8 +269,11 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) if (host->pbias) { if (host->pbias_enabled == 1) { ret = regulator_disable(host->pbias); - if (!ret) - host->pbias_enabled = 0; + if (ret) { + dev_err(dev, "pbias reg disable failed\n"); + return ret; + } + host->pbias_enabled = 0; } } @@ -288,23 +291,35 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - if (mmc->supply.vmmc) + if (mmc->supply.vmmc) { ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + if (ret) + return ret; + } + /* Enable interface voltage rail, if needed */ - if (ret == 0 && mmc->supply.vqmmc) { + if (mmc->supply.vqmmc) { ret = regulator_enable(mmc->supply.vqmmc); - if (ret < 0 && mmc->supply.vmmc) - ret = mmc_regulator_set_ocr(mmc, - mmc->supply.vmmc, - 0); + if (ret) { + dev_err(dev, "vmmc_aux reg enable failed\n"); + goto err_set_vqmmc; + } } } else { /* Shut down the rail */ - if (mmc->supply.vqmmc) + if (mmc->supply.vqmmc) { ret = regulator_disable(mmc->supply.vqmmc); + if (ret) { + dev_err(dev, "vmmc_aux reg disable failed\n"); + return ret; + } + } + if (mmc->supply.vmmc) { /* Then proceed to shut down the local regulator */ ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + if (ret) + return ret; } } @@ -316,19 +331,32 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) ret = regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0); if (ret < 0) - goto error_set_power; + goto err_set_voltage; if (host->pbias_enabled == 0) { ret = regulator_enable(host->pbias); - if (!ret) + if (ret) { + dev_err(dev, "pbias reg enable failed\n"); + goto err_set_voltage; + } else { host->pbias_enabled = 1; + } } } if (mmc_pdata(host)->after_set_reg) mmc_pdata(host)->after_set_reg(dev, power_on, vdd); -error_set_power: + return 0; + +err_set_voltage: + if (mmc->supply.vqmmc) + regulator_disable(mmc->supply.vqmmc); + +err_set_vqmmc: + if (mmc->supply.vmmc) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + return ret; } -- GitLab From 2a17f84442e22cd1522400fcc0356c4a36b38361 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:00 +0530 Subject: [PATCH 5142/7006] mmc: host: omap_hsmmc: add separate functions for enable/disable supply No functional change. Cleanup omap_hsmmc_set_power by adding separate functions for enable/disable supply and invoke it from omap_hsmmc_set_power. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 101 ++++++++++++++++++++++------------ 1 file changed, 66 insertions(+), 35 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 284ab0063156e..3fa78d477a415 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -246,6 +246,65 @@ static int omap_hsmmc_get_cover_state(struct device *dev) #ifdef CONFIG_REGULATOR +static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) +{ + int ret; + + if (mmc->supply.vmmc) { + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + if (ret) + return ret; + } + + /* Enable interface voltage rail, if needed */ + if (mmc->supply.vqmmc) { + ret = regulator_enable(mmc->supply.vqmmc); + if (ret) { + dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n"); + goto err_vqmmc; + } + } + + return 0; + +err_vqmmc: + if (mmc->supply.vmmc) + mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + + return ret; +} + +static int omap_hsmmc_disable_supply(struct mmc_host *mmc) +{ + int ret; + int status; + + if (mmc->supply.vqmmc) { + ret = regulator_disable(mmc->supply.vqmmc); + if (ret) { + dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n"); + return ret; + } + } + + if (mmc->supply.vmmc) { + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + if (ret) + goto err_set_ocr; + } + + return 0; + +err_set_ocr: + if (mmc->supply.vqmmc) { + status = regulator_enable(mmc->supply.vqmmc); + if (status) + dev_err(mmc_dev(mmc), "vmmc_aux re-enable failed\n"); + } + + return ret; +} + static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = @@ -291,36 +350,13 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - if (mmc->supply.vmmc) { - ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); - if (ret) - return ret; - } - - /* Enable interface voltage rail, if needed */ - if (mmc->supply.vqmmc) { - ret = regulator_enable(mmc->supply.vqmmc); - if (ret) { - dev_err(dev, "vmmc_aux reg enable failed\n"); - goto err_set_vqmmc; - } - } + ret = omap_hsmmc_enable_supply(mmc, vdd); + if (ret) + return ret; } else { - /* Shut down the rail */ - if (mmc->supply.vqmmc) { - ret = regulator_disable(mmc->supply.vqmmc); - if (ret) { - dev_err(dev, "vmmc_aux reg disable failed\n"); - return ret; - } - } - - if (mmc->supply.vmmc) { - /* Then proceed to shut down the local regulator */ - ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); - if (ret) - return ret; - } + ret = omap_hsmmc_disable_supply(mmc); + if (ret) + return ret; } if (host->pbias) { @@ -350,12 +386,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) return 0; err_set_voltage: - if (mmc->supply.vqmmc) - regulator_disable(mmc->supply.vqmmc); - -err_set_vqmmc: - if (mmc->supply.vmmc) - mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); + omap_hsmmc_disable_supply(mmc); return ret; } -- GitLab From ec85c95e8ce5df18608ee9aa6a2626d903f548af Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:01 +0530 Subject: [PATCH 5143/7006] mmc: host: omap_hsmmc: add separate function to set pbias No functional change. Cleanup omap_hsmmc_set_power by adding separate functions to set pbias and invoke it from omap_hsmmc_set_power. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 78 +++++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 3fa78d477a415..810d612f58a0b 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -305,6 +305,48 @@ err_set_ocr: return ret; } +static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, + int vdd) +{ + int ret; + + if (!host->pbias) + return 0; + + if (power_on) { + if (vdd <= VDD_165_195) + ret = regulator_set_voltage(host->pbias, VDD_1V8, + VDD_1V8); + else + ret = regulator_set_voltage(host->pbias, VDD_3V0, + VDD_3V0); + if (ret < 0) { + dev_err(host->dev, "pbias set voltage fail\n"); + return ret; + } + + if (host->pbias_enabled == 0) { + ret = regulator_enable(host->pbias); + if (ret) { + dev_err(host->dev, "pbias reg enable fail\n"); + return ret; + } + host->pbias_enabled = 1; + } + } else { + if (host->pbias_enabled == 1) { + ret = regulator_disable(host->pbias); + if (ret) { + dev_err(host->dev, "pbias reg disable fail\n"); + return ret; + } + host->pbias_enabled = 0; + } + } + + return 0; +} + static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) { struct omap_hsmmc_host *host = @@ -325,16 +367,9 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) if (mmc_pdata(host)->before_set_reg) mmc_pdata(host)->before_set_reg(dev, power_on, vdd); - if (host->pbias) { - if (host->pbias_enabled == 1) { - ret = regulator_disable(host->pbias); - if (ret) { - dev_err(dev, "pbias reg disable failed\n"); - return ret; - } - host->pbias_enabled = 0; - } - } + ret = omap_hsmmc_set_pbias(host, false, 0); + if (ret) + return ret; /* * Assume Vcc regulator is used only to power the card ... OMAP @@ -359,26 +394,9 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) return ret; } - if (host->pbias) { - if (vdd <= VDD_165_195) - ret = regulator_set_voltage(host->pbias, VDD_1V8, - VDD_1V8); - else - ret = regulator_set_voltage(host->pbias, VDD_3V0, - VDD_3V0); - if (ret < 0) - goto err_set_voltage; - - if (host->pbias_enabled == 0) { - ret = regulator_enable(host->pbias); - if (ret) { - dev_err(dev, "pbias reg enable failed\n"); - goto err_set_voltage; - } else { - host->pbias_enabled = 1; - } - } - } + ret = omap_hsmmc_set_pbias(host, true, vdd); + if (ret) + goto err_set_voltage; if (mmc_pdata(host)->after_set_reg) mmc_pdata(host)->after_set_reg(dev, power_on, vdd); -- GitLab From 97fe7e5ab6318ea5716f86be3b4ca8776a9e609c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:02 +0530 Subject: [PATCH 5144/7006] mmc: host: omap_hsmmc: avoid pbias regulator enable on power off Fix omap_hsmmc_set_power so that pbias regulator is not enabled during power off. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 810d612f58a0b..eec69752a189d 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -388,16 +388,16 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) ret = omap_hsmmc_enable_supply(mmc, vdd); if (ret) return ret; + + ret = omap_hsmmc_set_pbias(host, true, vdd); + if (ret) + goto err_set_voltage; } else { ret = omap_hsmmc_disable_supply(mmc); if (ret) return ret; } - ret = omap_hsmmc_set_pbias(host, true, vdd); - if (ret) - goto err_set_voltage; - if (mmc_pdata(host)->after_set_reg) mmc_pdata(host)->after_set_reg(dev, power_on, vdd); -- GitLab From c8518efa6de999bcbd638702c2a2d72fe83431e4 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:03 +0530 Subject: [PATCH 5145/7006] mmc: host: omap_hsmmc: don't use ->set_power to set initial regulator state If the regulator is enabled on boot (checked using regulator_is_enabled), invoke regulator_enable() so that the usecount reflects the correct state of the regulator and then disable the regulator so that the initial state of the regulator is disabled. Avoid using ->set_power, since set_power also takes care of setting the voltages which is not needed at this point. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 66 +++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 10 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index eec69752a189d..cd4bd6d4c71e2 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -409,6 +409,59 @@ err_set_voltage: return ret; } +static int omap_hsmmc_disable_boot_regulator(struct regulator *reg) +{ + int ret; + + if (!reg) + return 0; + + if (regulator_is_enabled(reg)) { + ret = regulator_enable(reg); + if (ret) + return ret; + + ret = regulator_disable(reg); + if (ret) + return ret; + } + + return 0; +} + +static int omap_hsmmc_disable_boot_regulators(struct omap_hsmmc_host *host) +{ + struct mmc_host *mmc = host->mmc; + int ret; + + /* + * disable regulators enabled during boot and get the usecount + * right so that regulators can be enabled/disabled by checking + * the return value of regulator_is_enabled + */ + ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vmmc); + if (ret) { + dev_err(host->dev, "fail to disable boot enabled vmmc reg\n"); + return ret; + } + + ret = omap_hsmmc_disable_boot_regulator(mmc->supply.vqmmc); + if (ret) { + dev_err(host->dev, + "fail to disable boot enabled vmmc_aux reg\n"); + return ret; + } + + ret = omap_hsmmc_disable_boot_regulator(host->pbias); + if (ret) { + dev_err(host->dev, + "failed to disable boot enabled pbias reg\n"); + return ret; + } + + return 0; +} + static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) { int ocr_value = 0; @@ -456,17 +509,10 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) /* For eMMC do not power off when not in sleep state */ if (mmc_pdata(host)->no_regulator_off_init) return 0; - /* - * To disable boot_on regulator, enable regulator - * to increase usecount and then disable it. - */ - if ((mmc->supply.vmmc && regulator_is_enabled(mmc->supply.vmmc) > 0) || - (mmc->supply.vqmmc && regulator_is_enabled(mmc->supply.vqmmc))) { - int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1; - omap_hsmmc_set_power(host->dev, 1, vdd); - omap_hsmmc_set_power(host->dev, 0, 0); - } + ret = omap_hsmmc_disable_boot_regulators(host); + if (ret) + return ret; return 0; } -- GitLab From 3f77f702389b7fbc955ec95721ce3861e40697fc Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:04 +0530 Subject: [PATCH 5146/7006] mmc: host: omap_hsmmc: enable/disable vmmc_aux regulator based on previous state enable vmmc_aux regulator only if it is in disabled state and disable vmmc_aux regulator only if it is in enabled state. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index cd4bd6d4c71e2..5a5946a7f2df8 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -184,6 +184,7 @@ struct omap_hsmmc_host { struct regulator *pbias; bool pbias_enabled; void __iomem *base; + int vqmmc_enabled; resource_size_t mapbase; spinlock_t irq_lock; /* Prevent races with irq handler */ unsigned int dma_len; @@ -249,6 +250,7 @@ static int omap_hsmmc_get_cover_state(struct device *dev) static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) { int ret; + struct omap_hsmmc_host *host = mmc_priv(mmc); if (mmc->supply.vmmc) { ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); @@ -257,12 +259,13 @@ static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) } /* Enable interface voltage rail, if needed */ - if (mmc->supply.vqmmc) { + if (mmc->supply.vqmmc && !host->vqmmc_enabled) { ret = regulator_enable(mmc->supply.vqmmc); if (ret) { dev_err(mmc_dev(mmc), "vmmc_aux reg enable failed\n"); goto err_vqmmc; } + host->vqmmc_enabled = 1; } return 0; @@ -278,13 +281,15 @@ static int omap_hsmmc_disable_supply(struct mmc_host *mmc) { int ret; int status; + struct omap_hsmmc_host *host = mmc_priv(mmc); - if (mmc->supply.vqmmc) { + if (mmc->supply.vqmmc && host->vqmmc_enabled) { ret = regulator_disable(mmc->supply.vqmmc); if (ret) { dev_err(mmc_dev(mmc), "vmmc_aux reg disable failed\n"); return ret; } + host->vqmmc_enabled = 0; } if (mmc->supply.vmmc) { @@ -2077,6 +2082,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; host->pbias_enabled = 0; + host->vqmmc_enabled = 0; ret = omap_hsmmc_gpio_init(mmc, host, pdata); if (ret) -- GitLab From c55d7a0553643a7e8f120688b82b594471084d3c Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:05 +0530 Subject: [PATCH 5147/7006] mmc: host: omap_hsmmc: use regulator_is_enabled to find pbias status Use regulator_is_enabled of pbias regulator to find pbias regulator status instead of maintaining a custom bookkeeping pbias_enabled variable. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 5a5946a7f2df8..4cd7a5805de8d 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -182,7 +182,6 @@ struct omap_hsmmc_host { struct clk *fclk; struct clk *dbclk; struct regulator *pbias; - bool pbias_enabled; void __iomem *base; int vqmmc_enabled; resource_size_t mapbase; @@ -330,22 +329,20 @@ static int omap_hsmmc_set_pbias(struct omap_hsmmc_host *host, bool power_on, return ret; } - if (host->pbias_enabled == 0) { + if (!regulator_is_enabled(host->pbias)) { ret = regulator_enable(host->pbias); if (ret) { dev_err(host->dev, "pbias reg enable fail\n"); return ret; } - host->pbias_enabled = 1; } } else { - if (host->pbias_enabled == 1) { + if (regulator_is_enabled(host->pbias)) { ret = regulator_disable(host->pbias); if (ret) { dev_err(host->dev, "pbias reg disable fail\n"); return ret; } - host->pbias_enabled = 0; } } @@ -2081,7 +2078,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev) host->base = base + pdata->reg_offset; host->power_mode = MMC_POWER_OFF; host->next_data.cookie = 1; - host->pbias_enabled = 0; host->vqmmc_enabled = 0; ret = omap_hsmmc_gpio_init(mmc, host, pdata); -- GitLab From 1d17f30bd87bf4857478b2a68dadf0096ca1cb40 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:06 +0530 Subject: [PATCH 5148/7006] mmc: host: omap_hsmmc: use ios->vdd for setting vmmc voltage vdd voltage is set in mmc core to ios->vdd and vmmc should actually be set to this voltage. Modify omap_hsmmc_enable_supply to not take vdd as argument since now it's directly set to the voltage in ios->vdd. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 4cd7a5805de8d..58683b3c55b64 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -246,13 +246,14 @@ static int omap_hsmmc_get_cover_state(struct device *dev) #ifdef CONFIG_REGULATOR -static int omap_hsmmc_enable_supply(struct mmc_host *mmc, int vdd) +static int omap_hsmmc_enable_supply(struct mmc_host *mmc) { int ret; struct omap_hsmmc_host *host = mmc_priv(mmc); + struct mmc_ios *ios = &mmc->ios; if (mmc->supply.vmmc) { - ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, vdd); + ret = mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); if (ret) return ret; } @@ -387,7 +388,7 @@ static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) * chips/cards need an interface voltage rail too. */ if (power_on) { - ret = omap_hsmmc_enable_supply(mmc, vdd); + ret = omap_hsmmc_enable_supply(mmc); if (ret) return ret; -- GitLab From 987e05c9c3fbffba81104b8ae9a0dde9c73758e9 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Thu, 27 Aug 2015 14:44:07 +0530 Subject: [PATCH 5149/7006] mmc: host: omap_hsmmc: remove CONFIG_REGULATOR check Now that support for platforms which have optional regulator is added, remove CONFIG_REGULATOR check in omap_hsmmc. Signed-off-by: Kishon Vijay Abraham I Tested-by: Tony Lindgren Signed-off-by: Ulf Hansson --- drivers/mmc/host/omap_hsmmc.c | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c index 58683b3c55b64..781e4db317671 100644 --- a/drivers/mmc/host/omap_hsmmc.c +++ b/drivers/mmc/host/omap_hsmmc.c @@ -244,8 +244,6 @@ static int omap_hsmmc_get_cover_state(struct device *dev) return mmc_gpio_get_cd(host->mmc); } -#ifdef CONFIG_REGULATOR - static int omap_hsmmc_enable_supply(struct mmc_host *mmc) { int ret; @@ -520,30 +518,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) return 0; } -static inline int omap_hsmmc_have_reg(void) -{ - return 1; -} - -#else - -static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd) -{ - return 0; -} - -static inline int omap_hsmmc_reg_get(struct omap_hsmmc_host *host) -{ - return -EINVAL; -} - -static inline int omap_hsmmc_have_reg(void) -{ - return 0; -} - -#endif - static irqreturn_t omap_hsmmc_cover_irq(int irq, void *dev_id); static int omap_hsmmc_gpio_init(struct mmc_host *mmc, @@ -2204,11 +2178,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev) goto err_irq; } - if (omap_hsmmc_have_reg()) { - ret = omap_hsmmc_reg_get(host); - if (ret) - goto err_irq; - } + ret = omap_hsmmc_reg_get(host); + if (ret) + goto err_irq; mmc->ocr_avail = mmc_pdata(host)->ocr_mask; -- GitLab From b3a5bbfd780d9e9291f5f257be06e9ad6db11657 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Thu, 27 Aug 2015 09:34:47 -0500 Subject: [PATCH 5150/7006] dlm: print error from kernel_sendpage Print a dlm-specific error when a socket error occurs when sending a dlm message. Signed-off-by: Bob Peterson Signed-off-by: David Teigland --- fs/dlm/lowcomms.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/fs/dlm/lowcomms.c b/fs/dlm/lowcomms.c index c6da6c33ae469..87e9d796cf7dd 100644 --- a/fs/dlm/lowcomms.c +++ b/fs/dlm/lowcomms.c @@ -124,6 +124,7 @@ struct connection { struct connection *othercon; struct work_struct rwork; /* Receive workqueue */ struct work_struct swork; /* Send workqueue */ + void (*orig_error_report)(struct sock *sk); }; #define sock2con(x) ((struct connection *)(x)->sk_user_data) @@ -464,6 +465,43 @@ int dlm_lowcomms_connect_node(int nodeid) return 0; } +static void lowcomms_error_report(struct sock *sk) +{ + struct connection *con = sock2con(sk); + struct sockaddr_storage saddr; + + if (nodeid_to_addr(con->nodeid, &saddr, NULL, false)) { + printk_ratelimited(KERN_ERR "dlm: node %d: socket error " + "sending to node %d, port %d, " + "sk_err=%d/%d\n", dlm_our_nodeid(), + con->nodeid, dlm_config.ci_tcp_port, + sk->sk_err, sk->sk_err_soft); + return; + } else if (saddr.ss_family == AF_INET) { + struct sockaddr_in *sin4 = (struct sockaddr_in *)&saddr; + + printk_ratelimited(KERN_ERR "dlm: node %d: socket error " + "sending to node %d at %pI4, port %d, " + "sk_err=%d/%d\n", dlm_our_nodeid(), + con->nodeid, &sin4->sin_addr.s_addr, + dlm_config.ci_tcp_port, sk->sk_err, + sk->sk_err_soft); + } else { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&saddr; + + printk_ratelimited(KERN_ERR "dlm: node %d: socket error " + "sending to node %d at %u.%u.%u.%u, " + "port %d, sk_err=%d/%d\n", dlm_our_nodeid(), + con->nodeid, sin6->sin6_addr.s6_addr32[0], + sin6->sin6_addr.s6_addr32[1], + sin6->sin6_addr.s6_addr32[2], + sin6->sin6_addr.s6_addr32[3], + dlm_config.ci_tcp_port, sk->sk_err, + sk->sk_err_soft); + } + con->orig_error_report(sk); +} + /* Make a socket active */ static void add_sock(struct socket *sock, struct connection *con) { @@ -475,6 +513,8 @@ static void add_sock(struct socket *sock, struct connection *con) con->sock->sk->sk_state_change = lowcomms_state_change; con->sock->sk->sk_user_data = con; con->sock->sk->sk_allocation = GFP_NOFS; + con->orig_error_report = con->sock->sk->sk_error_report; + con->sock->sk->sk_error_report = lowcomms_error_report; } /* Add the port number to an IPv6 or 4 sockaddr and return the address -- GitLab From 0b6a3da9617a08e13afc09cb7e148470ed0eb280 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 26 Aug 2015 17:00:42 +0100 Subject: [PATCH 5151/7006] irqchip/GICv3: Convert to EOImode == 1 So far, GICv3 has been used in with EOImode == 0. The effect of this mode is to perform the priority drop and the deactivation of the interrupt at the same time. While this works perfectly for Linux (we only have a single priority), it causes issues when an interrupt is forwarded to a guest, and when we want the guest to perform the EOI itself. For this case, the GIC architecture provides EOImode == 1, where: - A write to ICC_EOIR1_EL1 drops the priority of the interrupt and leaves it active. Other interrupts at the same priority level can now be taken, but the active interrupt cannot be taken again - A write to ICC_DIR_EL1 marks the interrupt as inactive, meaning it can now be taken again. This patch converts the driver to be able to use this new mode, depending on whether or not the kernel can behave as a hypervisor. No feature change. Signed-off-by: Marc Zyngier Reviewed-and-tested-by: Eric Auger Cc: Christoffer Dall Cc: Jiang Liu Cc: Cc: kvmarm@lists.cs.columbia.edu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1440604845-28229-2-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v3.c | 68 +++++++++++++++++++++++++++--- include/linux/irqchip/arm-gic-v3.h | 9 ++++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index e406bc5f13e4f..5c31cc9353d5f 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "irq-gic-common.h" @@ -50,6 +51,7 @@ struct gic_chip_data { }; static struct gic_chip_data gic_data __read_mostly; +static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; #define gic_data_rdist() (this_cpu_ptr(gic_data.rdists.rdist)) #define gic_data_rdist_rd_base() (gic_data_rdist()->rd_base) @@ -231,6 +233,11 @@ static void gic_mask_irq(struct irq_data *d) gic_poke_irq(d, GICD_ICENABLER); } +static void gic_eoimode1_mask_irq(struct irq_data *d) +{ + gic_mask_irq(d); +} + static void gic_unmask_irq(struct irq_data *d) { gic_poke_irq(d, GICD_ISENABLER); @@ -296,6 +303,16 @@ static void gic_eoi_irq(struct irq_data *d) gic_write_eoir(gic_irq(d)); } +static void gic_eoimode1_eoi_irq(struct irq_data *d) +{ + /* + * No need to deactivate an LPI. + */ + if (gic_irq(d) >= 8192) + return; + gic_write_dir(gic_irq(d)); +} + static int gic_set_type(struct irq_data *d, unsigned int type) { unsigned int irq = gic_irq(d); @@ -343,15 +360,26 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs if (likely(irqnr > 15 && irqnr < 1020) || irqnr >= 8192) { int err; + + if (static_key_true(&supports_deactivate)) + gic_write_eoir(irqnr); + err = handle_domain_irq(gic_data.domain, irqnr, regs); if (err) { WARN_ONCE(true, "Unexpected interrupt received!\n"); - gic_write_eoir(irqnr); + if (static_key_true(&supports_deactivate)) { + if (irqnr < 8192) + gic_write_dir(irqnr); + } else { + gic_write_eoir(irqnr); + } } continue; } if (irqnr < 16) { gic_write_eoir(irqnr); + if (static_key_true(&supports_deactivate)) + gic_write_dir(irqnr); #ifdef CONFIG_SMP handle_IPI(irqnr, regs); #else @@ -451,8 +479,13 @@ static void gic_cpu_sys_reg_init(void) /* Set priority mask register */ gic_write_pmr(DEFAULT_PMR_VALUE); - /* EOI deactivates interrupt too (mode 0) */ - gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); + if (static_key_true(&supports_deactivate)) { + /* EOI drops priority only (mode 1) */ + gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop); + } else { + /* EOI deactivates interrupt too (mode 0) */ + gic_write_ctlr(ICC_CTLR_EL1_EOImode_drop_dir); + } /* ... and let's hit the road... */ gic_write_grpen1(1); @@ -661,11 +694,28 @@ static struct irq_chip gic_chip = { .flags = IRQCHIP_SET_TYPE_MASKED, }; +static struct irq_chip gic_eoimode1_chip = { + .name = "GICv3", + .irq_mask = gic_eoimode1_mask_irq, + .irq_unmask = gic_unmask_irq, + .irq_eoi = gic_eoimode1_eoi_irq, + .irq_set_type = gic_set_type, + .irq_set_affinity = gic_set_affinity, + .irq_get_irqchip_state = gic_irq_get_irqchip_state, + .irq_set_irqchip_state = gic_irq_set_irqchip_state, + .flags = IRQCHIP_SET_TYPE_MASKED, +}; + #define GIC_ID_NR (1U << gic_data.rdists.id_bits) static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { + struct irq_chip *chip = &gic_chip; + + if (static_key_true(&supports_deactivate)) + chip = &gic_eoimode1_chip; + /* SGIs are private to the core kernel */ if (hw < 16) return -EPERM; @@ -679,13 +729,13 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, /* PPIs */ if (hw < 32) { irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, + irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); } /* SPIs */ if (hw >= 32 && hw < gic_data.irq_nr) { - irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, + irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } @@ -693,7 +743,7 @@ static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, if (hw >= 8192 && hw < GIC_ID_NR) { if (!gic_dist_supports_lpis()) return -EPERM; - irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, + irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); set_irq_flags(irq, IRQF_VALID); } @@ -820,6 +870,12 @@ static int __init gic_of_init(struct device_node *node, struct device_node *pare if (of_property_read_u64(node, "redistributor-stride", &redist_stride)) redist_stride = 0; + if (!is_hyp_mode_available()) + static_key_slow_dec(&supports_deactivate); + + if (static_key_true(&supports_deactivate)) + pr_info("GIC: Using split EOI/Deactivate mode\n"); + gic_data.dist_base = dist_base; gic_data.redist_regions = rdist_regs; gic_data.nr_redist_regions = nr_redist_regions; diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h index bf982e021fbd0..71e4faf33091a 100644 --- a/include/linux/irqchip/arm-gic-v3.h +++ b/include/linux/irqchip/arm-gic-v3.h @@ -104,6 +104,8 @@ #define GICR_SYNCR 0x00C0 #define GICR_MOVLPIR 0x0100 #define GICR_MOVALLR 0x0110 +#define GICR_ISACTIVER GICD_ISACTIVER +#define GICR_ICACTIVER GICD_ICACTIVER #define GICR_IDREGS GICD_IDREGS #define GICR_PIDR2 GICD_PIDR2 @@ -288,6 +290,7 @@ #define ICH_VMCR_PMR_MASK (0xffUL << ICH_VMCR_PMR_SHIFT) #define ICC_EOIR1_EL1 sys_reg(3, 0, 12, 12, 1) +#define ICC_DIR_EL1 sys_reg(3, 0, 12, 11, 1) #define ICC_IAR1_EL1 sys_reg(3, 0, 12, 12, 0) #define ICC_SGI1R_EL1 sys_reg(3, 0, 12, 11, 5) #define ICC_PMR_EL1 sys_reg(3, 0, 4, 6, 0) @@ -385,6 +388,12 @@ static inline void gic_write_eoir(u64 irq) isb(); } +static inline void gic_write_dir(u64 irq) +{ + asm volatile("msr_s " __stringify(ICC_DIR_EL1) ", %0" : : "r" (irq)); + isb(); +} + struct irq_domain; int its_cpu_init(void); int its_init(struct device_node *node, struct rdists *rdists, -- GitLab From 530bf353e4eb06bcba5078390c949650cd26a7c7 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 26 Aug 2015 17:00:43 +0100 Subject: [PATCH 5152/7006] irqchip/GICv3: Don't deactivate interrupts forwarded to a guest Commit 0a4377de3056 ("genirq: Introduce irq_set_vcpu_affinity() to target an interrupt to a VCPU") added just what we needed at the lowest level to allow an interrupt to be deactivated by a guest. When such a request reaches the GIC, it knows it doesn't need to perform the deactivation anymore, and can safely leave the guest do its magic. This of course requires additional support in both VFIO and KVM. Signed-off-by: Marc Zyngier Reviewed-and-tested-by: Eric Auger Cc: Christoffer Dall Cc: Jiang Liu Cc: Cc: kvmarm@lists.cs.columbia.edu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1440604845-28229-3-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic-v3.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c index 5c31cc9353d5f..7deed6ef54c2e 100644 --- a/drivers/irqchip/irq-gic-v3.c +++ b/drivers/irqchip/irq-gic-v3.c @@ -70,6 +70,11 @@ static inline int gic_irq_in_rdist(struct irq_data *d) return gic_irq(d) < 32; } +static inline bool forwarded_irq(struct irq_data *d) +{ + return d->handler_data != NULL; +} + static inline void __iomem *gic_dist_base(struct irq_data *d) { if (gic_irq_in_rdist(d)) /* SGI+PPI -> SGI_base for this CPU */ @@ -236,6 +241,16 @@ static void gic_mask_irq(struct irq_data *d) static void gic_eoimode1_mask_irq(struct irq_data *d) { gic_mask_irq(d); + /* + * When masking a forwarded interrupt, make sure it is + * deactivated as well. + * + * This ensures that an interrupt that is getting + * disabled/masked will not get "stuck", because there is + * noone to deactivate it (guest is being terminated). + */ + if (forwarded_irq(d)) + gic_poke_irq(d, GICD_ICACTIVER); } static void gic_unmask_irq(struct irq_data *d) @@ -306,9 +321,10 @@ static void gic_eoi_irq(struct irq_data *d) static void gic_eoimode1_eoi_irq(struct irq_data *d) { /* - * No need to deactivate an LPI. + * No need to deactivate an LPI, or an interrupt that + * is is getting forwarded to a vcpu. */ - if (gic_irq(d) >= 8192) + if (gic_irq(d) >= 8192 || forwarded_irq(d)) return; gic_write_dir(gic_irq(d)); } @@ -339,6 +355,12 @@ static int gic_set_type(struct irq_data *d, unsigned int type) return gic_configure_irq(irq, type, base, rwp_wait); } +static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) +{ + d->handler_data = vcpu; + return 0; +} + static u64 gic_mpidr_to_affinity(u64 mpidr) { u64 aff; @@ -703,6 +725,7 @@ static struct irq_chip gic_eoimode1_chip = { .irq_set_affinity = gic_set_affinity, .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, + .irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity, .flags = IRQCHIP_SET_TYPE_MASKED, }; -- GitLab From 0b996fd35957a30568cddbce05b917c1897966e0 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 26 Aug 2015 17:00:44 +0100 Subject: [PATCH 5153/7006] irqchip/GIC: Convert to EOImode == 1 So far, GICv2 has been used with EOImode == 0. The effect of this mode is to perform the priority drop and the deactivation of the interrupt at the same time. While this works perfectly for Linux (we only have a single priority), it causes issues when an interrupt is forwarded to a guest, and when we want the guest to perform the EOI itself. For this case, the GIC architecture provides EOImode == 1, where: - A write to the EOI register drops the priority of the interrupt and leaves it active. Other interrupts at the same priority level can now be taken, but the active interrupt cannot be taken again - A write to the DIR marks the interrupt as inactive, meaning it can now be taken again. We only enable this feature when booted in HYP mode and that the device-tree reported a suitable CPU interface. Observable behaviour should remain unchanged. Signed-off-by: Marc Zyngier Reviewed-and-tested-by: Eric Auger Cc: Christoffer Dall Cc: Jiang Liu Cc: Cc: kvmarm@lists.cs.columbia.edu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1440604845-28229-4-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic.c | 71 +++++++++++++++++++++++++++++++-- include/linux/irqchip/arm-gic.h | 4 ++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index aa3e7b8a69c43..c835f4c60d21c 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "irq-gic-common.h" @@ -82,6 +83,8 @@ static DEFINE_RAW_SPINLOCK(irq_controller_lock); #define NR_GIC_CPU_IF 8 static u8 gic_cpu_map[NR_GIC_CPU_IF] __read_mostly; +static struct static_key supports_deactivate = STATIC_KEY_INIT_TRUE; + #ifndef MAX_GIC_NR #define MAX_GIC_NR 1 #endif @@ -157,6 +160,11 @@ static void gic_mask_irq(struct irq_data *d) gic_poke_irq(d, GIC_DIST_ENABLE_CLEAR); } +static void gic_eoimode1_mask_irq(struct irq_data *d) +{ + gic_mask_irq(d); +} + static void gic_unmask_irq(struct irq_data *d) { gic_poke_irq(d, GIC_DIST_ENABLE_SET); @@ -167,6 +175,11 @@ static void gic_eoi_irq(struct irq_data *d) writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_EOI); } +static void gic_eoimode1_eoi_irq(struct irq_data *d) +{ + writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE); +} + static int gic_irq_set_irqchip_state(struct irq_data *d, enum irqchip_irq_state which, bool val) { @@ -272,11 +285,15 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs) irqnr = irqstat & GICC_IAR_INT_ID_MASK; if (likely(irqnr > 15 && irqnr < 1021)) { + if (static_key_true(&supports_deactivate)) + writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); handle_domain_irq(gic->domain, irqnr, regs); continue; } if (irqnr < 16) { writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI); + if (static_key_true(&supports_deactivate)) + writel_relaxed(irqstat, cpu_base + GIC_CPU_DEACTIVATE); #ifdef CONFIG_SMP handle_IPI(irqnr, regs); #endif @@ -329,6 +346,22 @@ static struct irq_chip gic_chip = { IRQCHIP_MASK_ON_SUSPEND, }; +static struct irq_chip gic_eoimode1_chip = { + .name = "GICv2", + .irq_mask = gic_eoimode1_mask_irq, + .irq_unmask = gic_unmask_irq, + .irq_eoi = gic_eoimode1_eoi_irq, + .irq_set_type = gic_set_type, +#ifdef CONFIG_SMP + .irq_set_affinity = gic_set_affinity, +#endif + .irq_get_irqchip_state = gic_irq_get_irqchip_state, + .irq_set_irqchip_state = gic_irq_set_irqchip_state, + .flags = IRQCHIP_SET_TYPE_MASKED | + IRQCHIP_SKIP_SET_WAKE | + IRQCHIP_MASK_ON_SUSPEND, +}; + void __init gic_cascade_irq(unsigned int gic_nr, unsigned int irq) { if (gic_nr >= MAX_GIC_NR) @@ -360,6 +393,10 @@ static void gic_cpu_if_up(struct gic_chip_data *gic) { void __iomem *cpu_base = gic_data_cpu_base(gic); u32 bypass = 0; + u32 mode = 0; + + if (static_key_true(&supports_deactivate)) + mode = GIC_CPU_CTRL_EOImodeNS; /* * Preserve bypass disable bits to be written back later @@ -367,7 +404,7 @@ static void gic_cpu_if_up(struct gic_chip_data *gic) bypass = readl(cpu_base + GIC_CPU_CTRL); bypass &= GICC_DIS_BYPASS_MASK; - writel_relaxed(bypass | GICC_ENABLE, cpu_base + GIC_CPU_CTRL); + writel_relaxed(bypass | mode | GICC_ENABLE, cpu_base + GIC_CPU_CTRL); } @@ -803,13 +840,20 @@ void __init gic_init_physaddr(struct device_node *node) static int gic_irq_domain_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { + struct irq_chip *chip = &gic_chip; + + if (static_key_true(&supports_deactivate)) { + if (d->host_data == (void *)&gic_data[0]) + chip = &gic_eoimode1_chip; + } + if (hw < 32) { irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, + irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_percpu_devid_irq, NULL, NULL); set_irq_flags(irq, IRQF_VALID | IRQF_NOAUTOEN); } else { - irq_domain_set_info(d, irq, hw, &gic_chip, d->host_data, + irq_domain_set_info(d, irq, hw, chip, d->host_data, handle_fasteoi_irq, NULL, NULL); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } @@ -995,6 +1039,8 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, register_cpu_notifier(&gic_cpu_notifier); #endif set_handle_irq(gic_handle_irq); + if (static_key_true(&supports_deactivate)) + pr_info("GIC: Using split EOI/Deactivate mode\n"); } gic_dist_init(gic); @@ -1010,6 +1056,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) { void __iomem *cpu_base; void __iomem *dist_base; + struct resource cpu_res; u32 percpu_offset; int irq; @@ -1022,6 +1069,16 @@ gic_of_init(struct device_node *node, struct device_node *parent) cpu_base = of_iomap(node, 1); WARN(!cpu_base, "unable to map gic cpu registers\n"); + of_address_to_resource(node, 1, &cpu_res); + + /* + * Disable split EOI/Deactivate if either HYP is not available + * or the CPU interface is too small. + */ + if (gic_cnt == 0 && (!is_hyp_mode_available() || + resource_size(&cpu_res) < SZ_8K)) + static_key_slow_dec(&supports_deactivate); + if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; @@ -1140,6 +1197,14 @@ gic_v2_acpi_init(struct acpi_table_header *table) return -ENOMEM; } + /* + * Disable split EOI/Deactivate if HYP is not available. ACPI + * guarantees that we'll always have a GICv2, so the CPU + * interface will always be the right size. + */ + if (!is_hyp_mode_available()) + static_key_slow_dec(&supports_deactivate); + /* * Initialize zero GIC instance (no multi-GIC support). Also, set GIC * as default IRQ domain to allow for GSI registration and GSI to IRQ diff --git a/include/linux/irqchip/arm-gic.h b/include/linux/irqchip/arm-gic.h index 65da435d01c10..af3d29f707811 100644 --- a/include/linux/irqchip/arm-gic.h +++ b/include/linux/irqchip/arm-gic.h @@ -20,9 +20,13 @@ #define GIC_CPU_ALIAS_BINPOINT 0x1c #define GIC_CPU_ACTIVEPRIO 0xd0 #define GIC_CPU_IDENT 0xfc +#define GIC_CPU_DEACTIVATE 0x1000 #define GICC_ENABLE 0x1 #define GICC_INT_PRI_THRESHOLD 0xf0 + +#define GIC_CPU_CTRL_EOImodeNS (1 << 9) + #define GICC_IAR_INT_ID_MASK 0x3ff #define GICC_INT_SPURIOUS 1023 #define GICC_DIS_BYPASS_MASK 0x1e0 -- GitLab From 01f779f4862b53810ba4eb247f57bd1ad31d1c18 Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Wed, 26 Aug 2015 17:00:45 +0100 Subject: [PATCH 5154/7006] irqchip/GIC: Don't deactivate interrupts forwarded to a guest Commit 0a4377de3056 ("genirq: Introduce irq_set_vcpu_affinity() to target an interrupt to a VCPU") added just what we needed at the lowest level to allow an interrupt to be deactivated by a guest. When such a request reaches the GIC, it knows it doesn't need to perform the deactivation anymore, and can safely leave the guest do its magic. This of course requires additional support in both VFIO and KVM. Signed-off-by: Marc Zyngier Reviewed-and-tested-by: Eric Auger Cc: Christoffer Dall Cc: Jiang Liu Cc: Cc: kvmarm@lists.cs.columbia.edu Cc: Jason Cooper Link: http://lkml.kernel.org/r/1440604845-28229-5-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic.c | 55 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index c835f4c60d21c..72bf81b8abfcd 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -140,6 +140,36 @@ static inline unsigned int gic_irq(struct irq_data *d) return d->hwirq; } +static inline bool cascading_gic_irq(struct irq_data *d) +{ + void *data = irq_data_get_irq_handler_data(d); + + /* + * If handler_data pointing to one of the secondary GICs, then + * this is a cascading interrupt, and it cannot possibly be + * forwarded. + */ + if (data >= (void *)(gic_data + 1) && + data < (void *)(gic_data + MAX_GIC_NR)) + return true; + + return false; +} + +static inline bool forwarded_irq(struct irq_data *d) +{ + /* + * A forwarded interrupt: + * - is on the primary GIC + * - has its handler_data set to a value + * - that isn't a secondary GIC + */ + if (d->handler_data && !cascading_gic_irq(d)) + return true; + + return false; +} + /* * Routines to acknowledge, disable and enable interrupts */ @@ -163,6 +193,16 @@ static void gic_mask_irq(struct irq_data *d) static void gic_eoimode1_mask_irq(struct irq_data *d) { gic_mask_irq(d); + /* + * When masking a forwarded interrupt, make sure it is + * deactivated as well. + * + * This ensures that an interrupt that is getting + * disabled/masked will not get "stuck", because there is + * noone to deactivate it (guest is being terminated). + */ + if (forwarded_irq(d)) + gic_poke_irq(d, GIC_DIST_ACTIVE_CLEAR); } static void gic_unmask_irq(struct irq_data *d) @@ -177,6 +217,10 @@ static void gic_eoi_irq(struct irq_data *d) static void gic_eoimode1_eoi_irq(struct irq_data *d) { + /* Do not deactivate an IRQ forwarded to a vcpu. */ + if (forwarded_irq(d)) + return; + writel_relaxed(gic_irq(d), gic_cpu_base(d) + GIC_CPU_DEACTIVATE); } @@ -246,6 +290,16 @@ static int gic_set_type(struct irq_data *d, unsigned int type) return gic_configure_irq(gicirq, type, base, NULL); } +static int gic_irq_set_vcpu_affinity(struct irq_data *d, void *vcpu) +{ + /* Only interrupts on the primary GIC can be forwarded to a vcpu. */ + if (cascading_gic_irq(d)) + return -EINVAL; + + d->handler_data = vcpu; + return 0; +} + #ifdef CONFIG_SMP static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val, bool force) @@ -357,6 +411,7 @@ static struct irq_chip gic_eoimode1_chip = { #endif .irq_get_irqchip_state = gic_irq_get_irqchip_state, .irq_set_irqchip_state = gic_irq_set_irqchip_state, + .irq_set_vcpu_affinity = gic_irq_set_vcpu_affinity, .flags = IRQCHIP_SET_TYPE_MASKED | IRQCHIP_SKIP_SET_WAKE | IRQCHIP_MASK_ON_SUSPEND, -- GitLab From 8d03bc56cc27ddd93f70a630686ef06289787c78 Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Wed, 26 Aug 2015 13:09:28 -0400 Subject: [PATCH 5155/7006] tile: correct some typos in opcode type names These particular opcode names are not used in the kernel directly, so updating them just has the effect of making downstream consumers more likely to end up using better names; this was reported from the qemu community. Reported-by: Richard Henderson Signed-off-by: Chris Metcalf --- arch/tile/include/uapi/arch/opcode_tilegx.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/tile/include/uapi/arch/opcode_tilegx.h b/arch/tile/include/uapi/arch/opcode_tilegx.h index d76ff2db745e2..9e46eaa847d4e 100644 --- a/arch/tile/include/uapi/arch/opcode_tilegx.h +++ b/arch/tile/include/uapi/arch/opcode_tilegx.h @@ -830,11 +830,11 @@ enum ADDX_RRR_0_OPCODE_X0 = 2, ADDX_RRR_0_OPCODE_X1 = 2, ADDX_RRR_0_OPCODE_Y0 = 0, - ADDX_SPECIAL_0_OPCODE_Y1 = 0, + ADDX_RRR_0_OPCODE_Y1 = 0, ADD_RRR_0_OPCODE_X0 = 3, ADD_RRR_0_OPCODE_X1 = 3, ADD_RRR_0_OPCODE_Y0 = 1, - ADD_SPECIAL_0_OPCODE_Y1 = 1, + ADD_RRR_0_OPCODE_Y1 = 1, ANDI_IMM8_OPCODE_X0 = 3, ANDI_IMM8_OPCODE_X1 = 3, ANDI_OPCODE_Y0 = 2, @@ -995,6 +995,7 @@ enum LD4U_ADD_IMM8_OPCODE_X1 = 12, LD4U_OPCODE_Y2 = 2, LD4U_UNARY_OPCODE_X1 = 20, + LDNA_ADD_IMM8_OPCODE_X1 = 21, LDNA_UNARY_OPCODE_X1 = 21, LDNT1S_ADD_IMM8_OPCODE_X1 = 13, LDNT1S_UNARY_OPCODE_X1 = 22, @@ -1015,7 +1016,6 @@ enum LD_UNARY_OPCODE_X1 = 29, LNK_UNARY_OPCODE_X1 = 30, LNK_UNARY_OPCODE_Y1 = 14, - LWNA_ADD_IMM8_OPCODE_X1 = 21, MFSPR_IMM8_OPCODE_X1 = 22, MF_UNARY_OPCODE_X1 = 31, MM_BF_OPCODE_X0 = 7, -- GitLab From 3b7ce99748f0d006f9d1aa85709872e7b46787f7 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Thu, 27 Aug 2015 11:35:20 +0200 Subject: [PATCH 5156/7006] ASoC: ics43432: Add codec driver for InvenSense ICS-43432 Add support for the InvenSense ICS-43432 I2S MEMS microphone. This is a non-software-configurable MEMS microphone with I2S output. Tested on a setup with a single ICS-43432 (the device itself supports stereo operation using a hardware pin controlling left vs. right channel output). Signed-off-by: Ricard Wanderlof Signed-off-by: Mark Brown --- .../devicetree/bindings/sound/ics43432.txt | 17 ++++ .../devicetree/bindings/vendor-prefixes.txt | 1 + sound/soc/codecs/Kconfig | 4 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/ics43432.c | 77 +++++++++++++++++++ 5 files changed, 101 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/ics43432.txt create mode 100644 sound/soc/codecs/ics43432.c diff --git a/Documentation/devicetree/bindings/sound/ics43432.txt b/Documentation/devicetree/bindings/sound/ics43432.txt new file mode 100644 index 0000000000000..b02e3a6c0fef9 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/ics43432.txt @@ -0,0 +1,17 @@ +Invensense ICS-43432 MEMS microphone with I2S output. + +There are no software configuration options for this device, indeed, the only +host connection is the I2S interface. Apart from requirements on clock +frequency (460 kHz to 3.379 MHz according to the data sheet) there must be +64 clock cycles in each stereo output frame; 24 of the 32 available bits +contain audio data. A hardware pin determines if the device outputs data +on the left or right channel of the I2S frame. + +Required properties: + - compatible : Must be "invensense,ics43432" + +Example: + + ics43432: ics43432 { + compatible = "invensense,ics43432"; + }; diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index d444757c4d9ec..80bf96d4795f2 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -110,6 +110,7 @@ ingenic Ingenic Semiconductor innolux Innolux Corporation intel Intel Corporation intercontrol Inter Control Group +invensense InvenSense Inc. isee ISEE 2007 S.L. isil Intersil karo Ka-Ro electronics GmbH diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index efaafce8ba387..1bb6446dce535 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -62,6 +62,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_BT_SCO select SND_SOC_ES8328_SPI if SPI_MASTER select SND_SOC_ES8328_I2C if I2C + select SND_SOC_ICS43432 select SND_SOC_ISABELLE if I2C select SND_SOC_JZ4740_CODEC select SND_SOC_LM4857 if I2C @@ -446,6 +447,9 @@ config SND_SOC_ES8328_SPI tristate select SND_SOC_ES8328 +config SND_SOC_ICS43432 + tristate + config SND_SOC_ISABELLE tristate diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index cf160d972cb36..5a19a670a82b6 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -55,6 +55,7 @@ snd-soc-dmic-objs := dmic.o snd-soc-es8328-objs := es8328.o snd-soc-es8328-i2c-objs := es8328-i2c.o snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-ics43432-objs := ics43432.o snd-soc-isabelle-objs := isabelle.o snd-soc-jz4740-codec-objs := jz4740.o snd-soc-l3-objs := l3.o @@ -242,6 +243,7 @@ obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c new file mode 100644 index 0000000000000..4f202c15df395 --- /dev/null +++ b/sound/soc/codecs/ics43432.c @@ -0,0 +1,77 @@ +/* + * I2S MEMS microphone driver for InvenSense ICS-43432 + * + * - Non configurable. + * - I2S interface, 64 BCLs per frame, 32 bits per channel, 24 bit data + * + * Copyright (c) 2015 Axis Communications AB + * + * Licensed under GPL2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ICS43432_RATE_MIN 7190 /* Hz, from data sheet */ +#define ICS43432_RATE_MAX 52800 /* Hz, from data sheet */ + +#define ICS43432_FORMATS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32) + +static struct snd_soc_dai_driver ics43432_dai = { + .name = "ics43432-hifi", + .capture = { + .stream_name = "Capture", + .channels_min = 1, + .channels_max = 2, + .rate_min = ICS43432_RATE_MIN, + .rate_max = ICS43432_RATE_MAX, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .formats = ICS43432_FORMATS, + }, +}; + +static struct snd_soc_codec_driver ics43432_codec_driver = { +}; + +static int ics43432_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &ics43432_codec_driver, + &ics43432_dai, 1); +} + +static int ics43432_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +#ifdef CONFIG_OF +static const struct of_device_id ics43432_ids[] = { + { .compatible = "invensense,ics43432", }, + { } +}; +MODULE_DEVICE_TABLE(of, ics43432_dt_ids); +#endif + +static struct platform_driver ics43432_driver = { + .driver = { + .name = "ics43432", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(ics43432_ids), + }, + .probe = ics43432_probe, + .remove = ics43432_remove, +}; + +module_platform_driver(ics43432_driver); + +MODULE_DESCRIPTION("ASoC ICS43432 driver"); +MODULE_AUTHOR("Ricard Wanderlof "); +MODULE_LICENSE("GPLv2"); -- GitLab From b00855aecbb166428c67b26e1bfeb675463a0212 Mon Sep 17 00:00:00 2001 From: Srinidhi Kasagar Date: Thu, 27 Aug 2015 21:30:55 +0530 Subject: [PATCH 5157/7006] ACPI / LPSS: Ignore 10ms delay for Braswell LPSS devices in Braswell does not need the default 10ms d3_delay imposed by PCI specification. Removing this unnecessary delay significantly reduces the resume time approximately upto 200ms on this platform. Signed-off-by: Srinidhi Kasagar Acked-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpi_lpss.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 46b58abb08c5e..10020e04f5744 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -60,6 +60,7 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_CLK_DIVIDER BIT(2) #define LPSS_LTR BIT(3) #define LPSS_SAVE_CTX BIT(4) +#define LPSS_NO_D3_DELAY BIT(5) struct lpss_private_data; @@ -156,6 +157,10 @@ static const struct lpss_device_desc byt_pwm_dev_desc = { .flags = LPSS_SAVE_CTX, }; +static const struct lpss_device_desc bsw_pwm_dev_desc = { + .flags = LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, +}; + static const struct lpss_device_desc byt_uart_dev_desc = { .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, .clk_con_id = "baudclk", @@ -163,6 +168,14 @@ static const struct lpss_device_desc byt_uart_dev_desc = { .setup = lpss_uart_setup, }; +static const struct lpss_device_desc bsw_uart_dev_desc = { + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX + | LPSS_NO_D3_DELAY, + .clk_con_id = "baudclk", + .prv_offset = 0x800, + .setup = lpss_uart_setup, +}; + static const struct lpss_device_desc byt_spi_dev_desc = { .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, .prv_offset = 0x400, @@ -178,8 +191,15 @@ static const struct lpss_device_desc byt_i2c_dev_desc = { .setup = byt_i2c_setup, }; +static const struct lpss_device_desc bsw_i2c_dev_desc = { + .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_NO_D3_DELAY, + .prv_offset = 0x800, + .setup = byt_i2c_setup, +}; + static struct lpss_device_desc bsw_spi_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX + | LPSS_NO_D3_DELAY, .prv_offset = 0x400, .setup = lpss_deassert_reset, }; @@ -214,11 +234,12 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = { { "INT33FC", }, /* Braswell LPSS devices */ - { "80862288", LPSS_ADDR(byt_pwm_dev_desc) }, - { "8086228A", LPSS_ADDR(byt_uart_dev_desc) }, + { "80862288", LPSS_ADDR(bsw_pwm_dev_desc) }, + { "8086228A", LPSS_ADDR(bsw_uart_dev_desc) }, { "8086228E", LPSS_ADDR(bsw_spi_dev_desc) }, - { "808622C1", LPSS_ADDR(byt_i2c_dev_desc) }, + { "808622C1", LPSS_ADDR(bsw_i2c_dev_desc) }, + /* Broadwell LPSS devices */ { "INT3430", LPSS_ADDR(lpt_dev_desc) }, { "INT3431", LPSS_ADDR(lpt_dev_desc) }, { "INT3432", LPSS_ADDR(lpt_i2c_dev_desc) }, @@ -558,9 +579,14 @@ static void acpi_lpss_restore_ctx(struct device *dev, * The following delay is needed or the subsequent write operations may * fail. The LPSS devices are actually PCI devices and the PCI spec * expects 10ms delay before the device can be accessed after D3 to D0 - * transition. + * transition. However some platforms like BSW does not need this delay. */ - msleep(10); + unsigned int delay = 10; /* default 10ms delay */ + + if (pdata->dev_desc->flags & LPSS_NO_D3_DELAY) + delay = 0; + + msleep(delay); for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { unsigned long offset = i * sizeof(u32); -- GitLab From fb77bb5376a55f4e6c8d9243249e82831a276ee5 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:47 +0530 Subject: [PATCH 5158/7006] mpt3sas: Added Combined Reply Queue feature to extend up-to 96 MSIX vector support In this patch, increased the number of MSIX vector support for SAS3 C0 HBAs to up-to 96. Following are changes that are done in this patch 1. This feature is enabled only for SAS3 C0 and higher revision cards and also only when reply post free queue count is greater than 8. 2. To support this feature 12 SupplementalReplyPostHostIndex system interfaces are used. MSI-X index numbered from 0 to 7 use the first SupplementalReplyPostHostIndex system interface to update its corresponding ReplyPostHostIndex values, MSI-X index numbered from 8 to 15 will use the second SupplementalReplyPostHostIndex system interface and so on. These 12 SuppementalReplyPostHostIndex system interfaces address are saved in the array replyPostRegisterIndex[]. 3. As each SupplementalReplyPostHostIndex register supports 8 MSI-X vectors. So MSIxIndex field in these register must contain a value between 0 and 7. 4. After processing the reply descriptors from a reply post free queues then update the new reply post host index value in ReplyPostHostIndex field and (msix_index mod 8) value in MSIxIndex field of SupplementalReplyPostHostIndex register. The Address of this SupplementalReplyPostHostIndex register is retrived from (msix_index/8)th entry of replyPostRegisterIndex[] array. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 93 ++++++++++++++++++++++++++--- drivers/scsi/mpt3sas/mpt3sas_base.h | 14 ++++- 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 43f87e904b988..f27c6729f57a9 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -83,10 +83,10 @@ static int msix_disable = -1; module_param(msix_disable, int, 0); MODULE_PARM_DESC(msix_disable, " disable msix routed interrupts (default=0)"); -static int max_msix_vectors = 8; +static int max_msix_vectors = -1; module_param(max_msix_vectors, int, 0); MODULE_PARM_DESC(max_msix_vectors, - " max msix vectors - (default=8)"); + " max msix vectors"); static int mpt3sas_fwfault_debug; MODULE_PARM_DESC(mpt3sas_fwfault_debug, @@ -1009,8 +1009,30 @@ _base_interrupt(int irq, void *bus_id) } wmb(); - writel(reply_q->reply_post_host_index | (msix_index << - MPI2_RPHI_MSIX_INDEX_SHIFT), &ioc->chip->ReplyPostHostIndex); + + /* Update Reply Post Host Index. + * For those HBA's which support combined reply queue feature + * 1. Get the correct Supplemental Reply Post Host Index Register. + * i.e. (msix_index / 8)th entry from Supplemental Reply Post Host + * Index Register address bank i.e replyPostRegisterIndex[], + * 2. Then update this register with new reply host index value + * in ReplyPostIndex field and the MSIxIndex field with + * msix_index value reduced to a value between 0 and 7, + * using a modulo 8 operation. Since each Supplemental Reply Post + * Host Index Register supports 8 MSI-X vectors. + * + * For other HBA's just update the Reply Post Host Index register with + * new reply host index value in ReplyPostIndex Field and msix_index + * value in MSIxIndex field. + */ + if (ioc->msix96_vector) + writel(reply_q->reply_post_host_index | ((msix_index & 7) << + MPI2_RPHI_MSIX_INDEX_SHIFT), + ioc->replyPostRegisterIndex[msix_index/8]); + else + writel(reply_q->reply_post_host_index | (msix_index << + MPI2_RPHI_MSIX_INDEX_SHIFT), + &ioc->chip->ReplyPostHostIndex); atomic_dec(&reply_q->busy); return IRQ_HANDLED; } @@ -1560,8 +1582,6 @@ _base_check_enable_msix(struct MPT3SAS_ADAPTER *ioc) pci_read_config_word(ioc->pdev, base + 2, &message_control); ioc->msix_vector_count = (message_control & 0x3FF) + 1; - if (ioc->msix_vector_count > 8) - ioc->msix_vector_count = 8; dinitprintk(ioc, pr_info(MPT3SAS_FMT "msix is supported, vector_count(%d)\n", ioc->name, ioc->msix_vector_count)); @@ -1882,6 +1902,36 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) if (r) goto out_fail; + /* Use the Combined reply queue feature only for SAS3 C0 & higher + * revision HBAs and also only when reply queue count is greater than 8 + */ + if (ioc->msix96_vector && ioc->reply_queue_count > 8) { + /* Determine the Supplemental Reply Post Host Index Registers + * Addresse. Supplemental Reply Post Host Index Registers + * starts at offset MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET and + * each register is at offset bytes of + * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET from previous one. + */ + ioc->replyPostRegisterIndex = kcalloc( + MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT, + sizeof(resource_size_t *), GFP_KERNEL); + if (!ioc->replyPostRegisterIndex) { + dfailprintk(ioc, printk(MPT3SAS_FMT + "allocation for reply Post Register Index failed!!!\n", + ioc->name)); + r = -ENOMEM; + goto out_fail; + } + + for (i = 0; i < MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT; i++) { + ioc->replyPostRegisterIndex[i] = (resource_size_t *) + ((u8 *)&ioc->chip->Doorbell + + MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET + + (i * MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET)); + } + } else + ioc->msix96_vector = 0; + list_for_each_entry(reply_q, &ioc->reply_queue_list, list) pr_info(MPT3SAS_FMT "%s: IRQ %d\n", reply_q->name, ((ioc->msix_enable) ? "PCI-MSI-X enabled" : @@ -1903,6 +1953,8 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) pci_release_selected_regions(ioc->pdev, ioc->bars); pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); + if (ioc->msix96_vector) + kfree(ioc->replyPostRegisterIndex); return r; } @@ -4524,8 +4576,15 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) /* initialize reply post host index */ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) { - writel(reply_q->msix_index << MPI2_RPHI_MSIX_INDEX_SHIFT, - &ioc->chip->ReplyPostHostIndex); + if (ioc->msix96_vector) + writel((reply_q->msix_index & 7)<< + MPI2_RPHI_MSIX_INDEX_SHIFT, + ioc->replyPostRegisterIndex[reply_q->msix_index/8]); + else + writel(reply_q->msix_index << + MPI2_RPHI_MSIX_INDEX_SHIFT, + &ioc->chip->ReplyPostHostIndex); + if (!_base_is_controller_msix_enabled(ioc)) goto skip_init_reply_post_host_index; } @@ -4579,6 +4638,9 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) _base_free_irq(ioc); _base_disable_msix(ioc); + if (ioc->msix96_vector) + kfree(ioc->replyPostRegisterIndex); + if (ioc->chip_phys && ioc->chip) iounmap(ioc->chip); ioc->chip_phys = 0; @@ -4602,6 +4664,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) { int r, i; int cpu_id, last_cpu_id = 0; + u8 revision; dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); @@ -4621,6 +4684,20 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) goto out_free_resources; } + /* Check whether the controller revision is C0 or above. + * only C0 and above revision controllers support 96 MSI-X vectors. + */ + revision = ioc->pdev->revision; + + if ((ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3004 || + ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3008 || + ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_1 || + ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_2 || + ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_5 || + ioc->pdev->device == MPI25_MFGPAGE_DEVID_SAS3108_6) && + (revision >= 0x02)) + ioc->msix96_vector = 1; + ioc->rdpq_array_enable_assigned = 0; ioc->dma_mask = 0; r = mpt3sas_base_map_resources(ioc); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index afa881682bef4..a7386ee767152 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -158,6 +158,13 @@ #define MPT3_DIAG_BUFFER_IS_RELEASED (0x02) #define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) +/* + * Combined Reply Queue constants, + * There are twelve Supplemental Reply Post Host Index Registers + * and each register is at offset 0x10 bytes from the previous one. + */ +#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_COUNT 12 +#define MPT3_SUP_REPLY_POST_HOST_INDEX_REG_OFFSET (0x10) /* OEM Identifiers */ #define MFG10_OEM_ID_INVALID (0x00000000) @@ -728,7 +735,8 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * is assigned only ones * @reply_queue_count: number of reply queue's * @reply_queue_list: link list contaning the reply queue info - * @reply_post_host_index: head index in the pool where FW completes IO + * @msix96_vector: 96 MSI-X vector support + * @replyPostRegisterIndex: index of next position in Reply Desc Post Queue * @delayed_tr_list: target reset link list * @delayed_tr_volume_list: volume target reset link list * @@temp_sensors_count: flag to carry the number of temperature sensors @@ -937,6 +945,10 @@ struct MPT3SAS_ADAPTER { u8 reply_queue_count; struct list_head reply_queue_list; + u8 msix96_vector; + /* reply post register index */ + resource_size_t **replyPostRegisterIndex; + struct list_head delayed_tr_list; struct list_head delayed_tr_volume_list; u8 temp_sensors_count; -- GitLab From 4dc8c8087f0304ff8d06f862520406b11aac4a66 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:48 +0530 Subject: [PATCH 5159/7006] mpt3sas: Get IOC_FACTS information using handshake protocol only after HBA card gets into READY or Operational state. Driver initialization fails if driver tries to send IOC facts request message when the IOC is in reset or in a fault state. This patch will make sure that 1.Driver to send IOC facts request message only if HBA is in operational or ready state. 2.If IOC is in fault state, a diagnostic reset would be issued. 3.If IOC is in reset state then driver will wait for 10 seconds to exit out of reset state. If the HBA continues to be in reset state, then the HBA wouldn't be claimed by the driver. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Tomas Henzl Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 68 +++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index f27c6729f57a9..9a6ac1eb2562c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3190,6 +3190,9 @@ _base_wait_on_iocstate(struct MPT3SAS_ADAPTER *ioc, u32 ioc_state, int timeout, * * Notes: MPI2_HIS_IOC2SYS_DB_STATUS - set to one when IOC writes to doorbell. */ +static int +_base_diag_reset(struct MPT3SAS_ADAPTER *ioc, int sleep_flag); + static int _base_wait_for_doorbell_int(struct MPT3SAS_ADAPTER *ioc, int timeout, int sleep_flag) @@ -3732,6 +3735,64 @@ _base_get_port_facts(struct MPT3SAS_ADAPTER *ioc, int port, int sleep_flag) return 0; } +/** + * _base_wait_for_iocstate - Wait until the card is in READY or OPERATIONAL + * @ioc: per adapter object + * @timeout: + * @sleep_flag: CAN_SLEEP or NO_SLEEP + * + * Returns 0 for success, non-zero for failure. + */ +static int +_base_wait_for_iocstate(struct MPT3SAS_ADAPTER *ioc, int timeout, + int sleep_flag) +{ + u32 ioc_state; + int rc; + + dinitprintk(ioc, printk(MPT3SAS_FMT "%s\n", ioc->name, + __func__)); + + if (ioc->pci_error_recovery) { + dfailprintk(ioc, printk(MPT3SAS_FMT + "%s: host in pci error recovery\n", ioc->name, __func__)); + return -EFAULT; + } + + ioc_state = mpt3sas_base_get_iocstate(ioc, 0); + dhsprintk(ioc, printk(MPT3SAS_FMT "%s: ioc_state(0x%08x)\n", + ioc->name, __func__, ioc_state)); + + if (((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_READY) || + (ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_OPERATIONAL) + return 0; + + if (ioc_state & MPI2_DOORBELL_USED) { + dhsprintk(ioc, printk(MPT3SAS_FMT + "unexpected doorbell active!\n", ioc->name)); + goto issue_diag_reset; + } + + if ((ioc_state & MPI2_IOC_STATE_MASK) == MPI2_IOC_STATE_FAULT) { + mpt3sas_base_fault_info(ioc, ioc_state & + MPI2_DOORBELL_DATA_MASK); + goto issue_diag_reset; + } + + ioc_state = _base_wait_on_iocstate(ioc, MPI2_IOC_STATE_READY, + timeout, sleep_flag); + if (ioc_state) { + dfailprintk(ioc, printk(MPT3SAS_FMT + "%s: failed going to ready state (ioc_state=0x%x)\n", + ioc->name, __func__, ioc_state)); + return -EFAULT; + } + + issue_diag_reset: + rc = _base_diag_reset(ioc, sleep_flag); + return rc; +} + /** * _base_get_ioc_facts - obtain ioc facts reply and save in ioc * @ioc: per adapter object @@ -3750,6 +3811,13 @@ _base_get_ioc_facts(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) dinitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); + r = _base_wait_for_iocstate(ioc, 10, sleep_flag); + if (r) { + dfailprintk(ioc, printk(MPT3SAS_FMT + "%s: failed getting to correct state\n", + ioc->name, __func__)); + return r; + } mpi_reply_sz = sizeof(Mpi2IOCFactsReply_t); mpi_request_sz = sizeof(Mpi2IOCFactsRequest_t); memset(&mpi_request, 0, mpi_request_sz); -- GitLab From e4bc7f5c21a18cab9acd30940df0ee791fcd7b9e Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:49 +0530 Subject: [PATCH 5160/7006] mpt3sas: Don't block the drive when drive addition under the control of SML During hot-plugging of a disk(having a flaky link), the disk addition stops and any further disk addition or removal doesn't happen on that controller. This is because, when driver receives DELAY_NOT_RESPONDING event for a disk while it is undergoing addition at the SCSI Transport layer, the driver would block the I/O to that disk resulting in a deadlock. i.e the disk addition work couldn't be completed at the SCSI Transport Layer as it can't send any I/Os (such as Inquiry, Report LUNs etc) to the disk as I/Os are blocked to this drive. Also any subsequent device removal (TARGET_NOT_RESPONDING) or link update(RC_PHY_CHANGED) event couldn't be processed as they are in the queue to get processed after disk addition event. Description of Change: Don't block the drive when drive addition is under the control of SML. So that SML won't be blocked of issuing the device dicovery commands (such as Inquiry, Report LUNs etc). Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 +++- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 7 +++++++ drivers/scsi/mpt3sas/mpt3sas_transport.c | 18 ++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index a7386ee767152..01d92dbab5fd7 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -301,7 +301,8 @@ struct _internal_cmd { * @responding: used in _scsih_sas_device_mark_responding * @fast_path: fast path feature enable bit * @pfa_led_on: flag for PFA LED status - * + * @pend_sas_rphy_add: flag to check if device is in sas_rphy_add() + * addition routine. */ struct _sas_device { struct list_head list; @@ -322,6 +323,7 @@ struct _sas_device { u8 responding; u8 fast_path; u8 pfa_led_on; + u8 pend_sas_rphy_add; }; /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5a97e3286719d..d457dbaa79d29 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2644,6 +2644,11 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) { struct MPT3SAS_DEVICE *sas_device_priv_data; struct scsi_device *sdev; + struct _sas_device *sas_device; + + sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + if (!sas_device) + return; shost_for_each_device(sdev, ioc->shost) { sas_device_priv_data = sdev->hostdata; @@ -2653,6 +2658,8 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) continue; if (sas_device_priv_data->block) continue; + if (sas_device->pend_sas_rphy_add) + continue; sas_device_priv_data->block = 1; scsi_internal_device_block(sdev); sdev_printk(KERN_INFO, sdev, diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index efb98afc46e08..7a7aa68a3f5f5 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -649,6 +649,7 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, unsigned long flags; struct _sas_node *sas_node; struct sas_rphy *rphy; + struct _sas_device *sas_device = NULL; int i; struct sas_port *port; @@ -731,10 +732,27 @@ mpt3sas_transport_port_add(struct MPT3SAS_ADAPTER *ioc, u16 handle, mpt3sas_port->remote_identify.device_type); rphy->identify = mpt3sas_port->remote_identify; + + if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) { + sas_device = mpt3sas_scsih_sas_device_find_by_sas_address(ioc, + mpt3sas_port->remote_identify.sas_address); + if (!sas_device) { + dfailprintk(ioc, printk(MPT3SAS_FMT + "failure at %s:%d/%s()!\n", + ioc->name, __FILE__, __LINE__, __func__)); + goto out_fail; + } + sas_device->pend_sas_rphy_add = 1; + } + if ((sas_rphy_add(rphy))) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); } + + if (mpt3sas_port->remote_identify.device_type == SAS_END_DEVICE) + sas_device->pend_sas_rphy_add = 0; + if ((ioc->logging_level & MPT_DEBUG_TRANSPORT)) dev_printk(KERN_INFO, &rphy->dev, "add: handle(0x%04x), sas_addr(0x%016llx)\n", -- GitLab From 580d4e3153f0d7a9a9235b675b0b7b13e2185a8b Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:50 +0530 Subject: [PATCH 5161/7006] mpt3sas: Remove redundancy code while freeing the controller resources. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 57 ++++++++++++++++------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 9a6ac1eb2562c..7e8ede2fee9d7 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1812,6 +1812,36 @@ _base_enable_msix(struct MPT3SAS_ADAPTER *ioc) return r; } +/** + * mpt3sas_base_unmap_resources - free controller resources + * @ioc: per adapter object + */ +void +mpt3sas_base_unmap_resources(struct MPT3SAS_ADAPTER *ioc) +{ + struct pci_dev *pdev = ioc->pdev; + + dexitprintk(ioc, printk(MPT3SAS_FMT "%s\n", + ioc->name, __func__)); + + _base_free_irq(ioc); + _base_disable_msix(ioc); + + if (ioc->msix96_vector) + kfree(ioc->replyPostRegisterIndex); + + if (ioc->chip_phys) { + iounmap(ioc->chip); + ioc->chip_phys = 0; + } + + if (pci_is_enabled(pdev)) { + pci_release_selected_regions(ioc->pdev, ioc->bars); + pci_disable_pcie_error_reporting(pdev); + pci_disable_device(pdev); + } +} + /** * mpt3sas_base_map_resources - map in controller resources (io/irq/memap) * @ioc: per adapter object @@ -1947,14 +1977,7 @@ mpt3sas_base_map_resources(struct MPT3SAS_ADAPTER *ioc) return 0; out_fail: - if (ioc->chip_phys) - iounmap(ioc->chip); - ioc->chip_phys = 0; - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - if (ioc->msix96_vector) - kfree(ioc->replyPostRegisterIndex); + mpt3sas_base_unmap_resources(ioc); return r; } @@ -4691,8 +4714,6 @@ _base_make_ioc_operational(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) void mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) { - struct pci_dev *pdev = ioc->pdev; - dexitprintk(ioc, pr_info(MPT3SAS_FMT "%s\n", ioc->name, __func__)); @@ -4703,21 +4724,7 @@ mpt3sas_base_free_resources(struct MPT3SAS_ADAPTER *ioc) ioc->shost_recovery = 0; } - _base_free_irq(ioc); - _base_disable_msix(ioc); - - if (ioc->msix96_vector) - kfree(ioc->replyPostRegisterIndex); - - if (ioc->chip_phys && ioc->chip) - iounmap(ioc->chip); - ioc->chip_phys = 0; - - if (pci_is_enabled(pdev)) { - pci_release_selected_regions(ioc->pdev, ioc->bars); - pci_disable_pcie_error_reporting(pdev); - pci_disable_device(pdev); - } + mpt3sas_base_unmap_resources(ioc); return; } -- GitLab From a94bea343c2f747c62ef66b52d2430e6aeb75434 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:51 +0530 Subject: [PATCH 5162/7006] mpt3sas: MPI 2.5 Rev I (2.5.4) specifications. Update MPI 2.5 Release: MPI 2.5 Rev I (2.5.4) specification and 2.00.33 header files Below is the change set from the MPI specification for I Rev 1) Added Base Enclosure Level bit to the Flags field of Manufacturing Page 7. 2) Updated description of the MaxTargetPortConnectTime field of SAS IO Unit Page 1. 3) Added EnclosureLevel and ConnectorName fields to SAS Device Page 0. Also, added EnclosureLevel and ConnectorName Valid bit to the Flags field. 4) Added EnclosureLevel field to SAS Enclosure Page 0. Also, added EnclosureLevel Valid bit to the Flags field. 5) Added value for BIOS image to HashImageType. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpi/mpi2.h | 6 ++++-- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 27 +++++++++++++++++++++------ drivers/scsi/mpt3sas/mpi/mpi2_ioc.h | 4 +++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h index c34c1157907be..d730c5ca14669 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.31 + * mpi2.h Version: 02.00.33 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -88,6 +88,8 @@ * Added MPI25_SUP_REPLY_POST_HOST_INDEX_OFFSET. * 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT. * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. + * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. + * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -121,7 +123,7 @@ #define MPI2_VERSION_02_05 (0x0205) /*Unit and Dev versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x1F) +#define MPI2_HEADER_VERSION_UNIT (0x21) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index e261a3153bb36..62dfbf6bcba0d 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.26 + * mpi2_cnfg.h Version: 02.00.27 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -165,6 +165,16 @@ * match the specification. * 08-19-13 02.00.26 Added reserved words to MPI2_CONFIG_PAGE_IO_UNIT_7 for * future use. + * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for + * MPI2_CONFIG_PAGE_MAN_7. + * Added EnclosureLevel and ConnectorName fields to + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_DEV_0. + * Added EnclosureLevel field to + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for + * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. * -------------------------------------------------------------------------- */ @@ -724,6 +734,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 { #define MPI2_MANUFACTURING7_PAGEVERSION (0x01) /*defines for the Flags field */ +#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008) #define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002) #define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001) @@ -2633,9 +2644,9 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 { U8 ControlGroup; /*0x2E */ U8 - Reserved1; /*0x2F */ + EnclosureLevel; /*0x2F */ U32 - Reserved2; /*0x30 */ + ConnectorName[4]; /*0x30 */ U32 Reserved3; /*0x34 */ } MPI2_CONFIG_PAGE_SAS_DEV_0, @@ -2643,7 +2654,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 { Mpi2SasDevicePage0_t, *pMpi2SasDevicePage0_t; -#define MPI2_SASDEVICE0_PAGEVERSION (0x08) +#define MPI2_SASDEVICE0_PAGEVERSION (0x09) /*values for SAS Device Page 0 AccessStatus field */ #define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00) @@ -2683,6 +2694,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0 { #define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020) #define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010) #define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008) +#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002) #define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001) @@ -3019,8 +3031,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { NumSlots; /*0x18 */ U16 StartSlot; /*0x1A */ - U16 + U8 Reserved2; /*0x1C */ + U8 + EnclosureLevel; /*0x1D */ U16 SEPDevHandle; /*0x1E */ U32 @@ -3031,9 +3045,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { *PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0, Mpi2SasEnclosurePage0_t, *pMpi2SasEnclosurePage0_t; -#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03) +#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04) /*values for SAS Enclosure Page 0 Flags field */ +#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010) #define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F) #define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000) #define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h index 4908309578061..d7598cc4bb8ed 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: October 11, 2006 * - * mpi2_ioc.h Version: 02.00.23 + * mpi2_ioc.h Version: 02.00.24 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -132,6 +132,7 @@ * Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE. * Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY. * Added Encrypted Hash Extended Image. + * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS. * -------------------------------------------------------------------------- */ @@ -1598,6 +1599,7 @@ Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t; /* values for HashImageType */ #define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00) #define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01) +#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02) /* values for HashAlgorithm */ #define MPI25_HASH_ALGORITHM_UNUSED (0x00) -- GitLab From e6d45e3e7e6582fa206ef84631639ce70d50e5c5 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:52 +0530 Subject: [PATCH 5163/7006] mpt3sas: Provides the physical location of sas drives This Patch will provide more details of the devices such as slot number, enclosure logical id, enclosure level & connector name in the following scenarios, - When end device is added in the topology, - When the end device is removed from the setup, - When the SCSI mid layer issues TASK ABORT/ DEVICE RESET/ TARGET RESET during error handling, - When any command to the device fails with Sense key Hardware error or Medium error or Unit Attention, - When firmware returns device error or device not ready status for the end device, - When a Predicted fault is detected on an end device. This information can be used by the user to identify the location of the desired drive in the topology. Driver will get these information by reading the sas device page0. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.h | 2 + drivers/scsi/mpt3sas/mpt3sas_scsih.c | 240 ++++++++++++++++++++++----- 2 files changed, 203 insertions(+), 39 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 01d92dbab5fd7..da82a97d73922 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -324,6 +324,8 @@ struct _sas_device { u8 fast_path; u8 pfa_led_on; u8 pend_sas_rphy_add; + u8 enclosure_level; + u8 connector_name[4]; }; /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index d457dbaa79d29..ec3b3d3bde38e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -585,6 +585,22 @@ _scsih_sas_device_remove(struct MPT3SAS_ADAPTER *ioc, if (!sas_device) return; + pr_info(MPT3SAS_FMT + "removing handle(0x%04x), sas_addr(0x%016llx)\n", + ioc->name, sas_device->handle, + (unsigned long long) sas_device->sas_address); + + if (sas_device->enclosure_handle != 0) + pr_info(MPT3SAS_FMT + "removing enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, (unsigned long long) + sas_device->enclosure_logical_id, sas_device->slot); + + if (sas_device->connector_name[0] != '\0') + pr_info(MPT3SAS_FMT + "removing enclosure level(0x%04x), connector name( %s)\n", + ioc->name, sas_device->enclosure_level, + sas_device->connector_name); spin_lock_irqsave(&ioc->sas_device_lock, flags); list_del(&sas_device->list); @@ -663,6 +679,18 @@ _scsih_sas_device_add(struct MPT3SAS_ADAPTER *ioc, ioc->name, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); + if (sas_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure logical id(0x%016llx), slot( %d)\n", + ioc->name, __func__, (unsigned long long) + sas_device->enclosure_logical_id, sas_device->slot)); + + if (sas_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, + sas_device->enclosure_level, sas_device->connector_name)); + spin_lock_irqsave(&ioc->sas_device_lock, flags); list_add_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -704,6 +732,18 @@ _scsih_sas_device_init_add(struct MPT3SAS_ADAPTER *ioc, __func__, sas_device->handle, (unsigned long long)sas_device->sas_address)); + if (sas_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure logical id(0x%016llx), slot( %d)\n", + ioc->name, __func__, (unsigned long long) + sas_device->enclosure_logical_id, sas_device->slot)); + + if (sas_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, sas_device->enclosure_level, + sas_device->connector_name)); + spin_lock_irqsave(&ioc->sas_device_lock, flags); list_add_tail(&sas_device->list, &ioc->sas_device_init_list); _scsih_determine_boot_device(ioc, sas_device, 0); @@ -1772,10 +1812,16 @@ _scsih_slave_configure(struct scsi_device *sdev) "sas_addr(0x%016llx), phy(%d), device_name(0x%016llx)\n", ds, handle, (unsigned long long)sas_device->sas_address, sas_device->phy, (unsigned long long)sas_device->device_name); - sdev_printk(KERN_INFO, sdev, - "%s: enclosure_logical_id(0x%016llx), slot(%d)\n", - ds, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot); + if (sas_device->enclosure_handle != 0) + sdev_printk(KERN_INFO, sdev, + "%s: enclosure_logical_id(0x%016llx), slot(%d)\n", + ds, (unsigned long long) + sas_device->enclosure_logical_id, sas_device->slot); + if (sas_device->connector_name[0] != '\0') + sdev_printk(KERN_INFO, sdev, + "%s: enclosure level(0x%04x), connector name( %s)\n", + ds, sas_device->enclosure_level, + sas_device->connector_name); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -2189,10 +2235,17 @@ _scsih_tm_display_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) sas_device->handle, (unsigned long long)sas_device->sas_address, sas_device->phy); - starget_printk(KERN_INFO, starget, - "enclosure_logical_id(0x%016llx), slot(%d)\n", - (unsigned long long)sas_device->enclosure_logical_id, - sas_device->slot); + if (sas_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, + "enclosure_logical_id(0x%016llx), slot(%d)\n", + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name) + starget_printk(KERN_INFO, starget, + "enclosure level(0x%04x),connector name(%s)\n", + sas_device->enclosure_level, + sas_device->connector_name); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -2813,6 +2866,18 @@ _scsih_tm_tr_send(struct MPT3SAS_ADAPTER *ioc, u16 handle) "setting delete flag: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, handle, (unsigned long long)sas_address)); + if (sas_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting delete flag:enclosure logical id(0x%016llx)," + " slot(%d)\n", ioc->name, (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot)); + if (sas_device->connector_name) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "setting delete flag: enclosure level(0x%04x)," + " connector name( %s)\n", ioc->name, + sas_device->enclosure_level, + sas_device->connector_name)); _scsih_ublock_io_device(ioc, sas_address); sas_target_priv_data->handle = MPT3SAS_INVALID_DEVICE_HANDLE; } @@ -3828,10 +3893,19 @@ _scsih_scsi_ioc_info(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, "\tsas_address(0x%016llx), phy(%d)\n", ioc->name, (unsigned long long) sas_device->sas_address, sas_device->phy); - pr_warn(MPT3SAS_FMT - "\tenclosure_logical_id(0x%016llx), slot(%d)\n", - ioc->name, (unsigned long long) - sas_device->enclosure_logical_id, sas_device->slot); + if (sas_device->enclosure_handle != 0) + pr_warn(MPT3SAS_FMT + "\tenclosure_logical_id(0x%016llx)," + "slot(%d)\n", ioc->name, + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name[0]) + pr_warn(MPT3SAS_FMT + "\tenclosure level(0x%04x)," + " connector name( %s)\n", ioc->name, + sas_device->enclosure_level, + sas_device->connector_name); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -4006,7 +4080,16 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return; } - starget_printk(KERN_WARNING, starget, "predicted fault\n"); + if (sas_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, "predicted fault, " + "enclosure logical id(0x%016llx), slot(%d)\n", + (unsigned long long)sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name[0] != '\0') + starget_printk(KERN_WARNING, starget, "predicted fault, " + "enclosure level(0x%04x), connector name( %s)\n", + sas_device->enclosure_level, + sas_device->connector_name); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (ioc->pdev->subsystem_vendor == PCI_VENDOR_ID_IBM) @@ -4126,8 +4209,15 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) _scsih_smart_predicted_fault(ioc, le16_to_cpu(mpi_reply->DevHandle)); mpt3sas_trigger_scsi(ioc, data.skey, data.asc, data.ascq); - } +#ifdef CONFIG_SCSI_MPT3SAS_LOGGING + if (!(ioc->logging_level & MPT_DEBUG_REPLY) && + ((scmd->sense_buffer[2] == UNIT_ATTENTION) || + (scmd->sense_buffer[2] == MEDIUM_ERROR) || + (scmd->sense_buffer[2] == HARDWARE_ERROR))) + _scsih_scsi_ioc_info(ioc, scmd, mpi_reply, smid); +#endif + } switch (ioc_status) { case MPI2_IOCSTATUS_BUSY: case MPI2_IOCSTATUS_INSUFFICIENT_RESOURCES: @@ -4795,6 +4885,16 @@ _scsih_check_device(struct MPT3SAS_ADAPTER *ioc, sas_device->handle, handle); sas_target_priv_data->handle = handle; sas_device->handle = handle; + if (sas_device_pg0.Flags & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + sas_device->enclosure_level = + le16_to_cpu(sas_device_pg0.EnclosureLevel); + memcpy(&sas_device->connector_name[0], + &sas_device_pg0.ConnectorName[0], 4); + } else { + sas_device->enclosure_level = 0; + sas_device->connector_name[0] = '\0'; + } } /* check if device is present */ @@ -4901,14 +5001,24 @@ _scsih_add_device(struct MPT3SAS_ADAPTER *ioc, u16 handle, u8 phy_num, ioc->name, __FILE__, __LINE__, __func__); sas_device->enclosure_handle = le16_to_cpu(sas_device_pg0.EnclosureHandle); - sas_device->slot = - le16_to_cpu(sas_device_pg0.Slot); + if (sas_device->enclosure_handle != 0) + sas_device->slot = + le16_to_cpu(sas_device_pg0.Slot); sas_device->device_info = device_info; sas_device->sas_address = sas_address; sas_device->phy = sas_device_pg0.PhyNum; sas_device->fast_path = (le16_to_cpu(sas_device_pg0.Flags) & MPI25_SAS_DEVICE0_FLAGS_FAST_PATH_CAPABLE) ? 1 : 0; + if (sas_device_pg0.Flags & MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + sas_device->enclosure_level = + le16_to_cpu(sas_device_pg0.EnclosureLevel); + memcpy(&sas_device->connector_name[0], + &sas_device_pg0.ConnectorName[0], 4); + } else { + sas_device->enclosure_level = 0; + sas_device->connector_name[0] = '\0'; + } /* get enclosure_logical_id */ if (sas_device->enclosure_handle && !(mpt3sas_config_get_enclosure_pg0( ioc, &mpi_reply, &enclosure_pg0, MPI2_SAS_ENCLOS_PGAD_FORM_HANDLE, @@ -4950,6 +5060,18 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, ioc->name, __func__, sas_device->handle, (unsigned long long) sas_device->sas_address)); + if (sas_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enter: enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, __func__, + (unsigned long long)sas_device->enclosure_logical_id, + sas_device->slot)); + if (sas_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: enter: enclosure level(0x%04x), connector name( %s)\n", + ioc->name, __func__, + sas_device->enclosure_level, + sas_device->connector_name)); if (sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; @@ -4966,12 +5088,34 @@ _scsih_remove_device(struct MPT3SAS_ADAPTER *ioc, "removing handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, sas_device->handle, (unsigned long long) sas_device->sas_address); + if (sas_device->enclosure_handle != 0) + pr_info(MPT3SAS_FMT + "removing : enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, + (unsigned long long)sas_device->enclosure_logical_id, + sas_device->slot); + if (sas_device->connector_name[0] != '\0') + pr_info(MPT3SAS_FMT + "removing enclosure level(0x%04x), connector name( %s)\n", + ioc->name, sas_device->enclosure_level, + sas_device->connector_name); dewtprintk(ioc, pr_info(MPT3SAS_FMT "%s: exit: handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, - sas_device->handle, (unsigned long long) - sas_device->sas_address)); + sas_device->handle, (unsigned long long) + sas_device->sas_address)); + if (sas_device->enclosure_handle != 0) + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: exit: enclosure logical id(0x%016llx), slot(%d)\n", + ioc->name, __func__, + (unsigned long long)sas_device->enclosure_logical_id, + sas_device->slot)); + if (sas_device->connector_name[0] != '\0') + dewtprintk(ioc, pr_info(MPT3SAS_FMT + "%s: exit: enclosure level(0x%04x), connector name(%s)\n", + ioc->name, __func__, sas_device->enclosure_level, + sas_device->connector_name)); kfree(sas_device); } @@ -6364,9 +6508,7 @@ _scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc) /** * _scsih_mark_responding_sas_device - mark a sas_devices as responding * @ioc: per adapter object - * @sas_address: sas address - * @slot: enclosure slot id - * @handle: device handle + * @sas_device_pg0: SAS Device page 0 * * After host reset, find out whether devices are still responding. * Used in _scsih_remove_unresponsive_sas_devices. @@ -6374,8 +6516,8 @@ _scsih_prep_device_scan(struct MPT3SAS_ADAPTER *ioc) * Return nothing. */ static void -_scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, - u16 slot, u16 handle) +_scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, +Mpi2SasDevicePage0_t *sas_device_pg0) { struct MPT3SAS_TARGET *sas_target_priv_data = NULL; struct scsi_target *starget; @@ -6384,8 +6526,8 @@ _scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry(sas_device, &ioc->sas_device_list, list) { - if (sas_device->sas_address == sas_address && - sas_device->slot == slot) { + if ((sas_device->sas_address == sas_device_pg0->SASAddress) && + (sas_device->slot == sas_device_pg0->Slot)) { sas_device->responding = 1; starget = sas_device->starget; if (starget && starget->hostdata) { @@ -6394,22 +6536,40 @@ _scsih_mark_responding_sas_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address, sas_target_priv_data->deleted = 0; } else sas_target_priv_data = NULL; - if (starget) + if (starget) { starget_printk(KERN_INFO, starget, - "handle(0x%04x), sas_addr(0x%016llx), " - "enclosure logical id(0x%016llx), " - "slot(%d)\n", handle, - (unsigned long long)sas_device->sas_address, + "handle(0x%04x), sas_addr(0x%016llx)\n", + sas_device_pg0->DevHandle, (unsigned long long) - sas_device->enclosure_logical_id, - sas_device->slot); - if (sas_device->handle == handle) + sas_device->sas_address); + + if (sas_device->enclosure_handle != 0) + starget_printk(KERN_INFO, starget, + "enclosure logical id(0x%016llx)," + " slot(%d)\n", + (unsigned long long) + sas_device->enclosure_logical_id, + sas_device->slot); + } + if (sas_device_pg0->Flags & + MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID) { + sas_device->enclosure_level = + le16_to_cpu(sas_device_pg0->EnclosureLevel); + memcpy(&sas_device->connector_name[0], + &sas_device_pg0->ConnectorName[0], 4); + } else { + sas_device->enclosure_level = 0; + sas_device->connector_name[0] = '\0'; + } + + if (sas_device->handle == sas_device_pg0->DevHandle) goto out; pr_info("\thandle changed from(0x%04x)!!!\n", sas_device->handle); - sas_device->handle = handle; + sas_device->handle = sas_device_pg0->DevHandle; if (sas_target_priv_data) - sas_target_priv_data->handle = handle; + sas_target_priv_data->handle = + sas_device_pg0->DevHandle; goto out; } } @@ -6448,13 +6608,15 @@ _scsih_search_responding_sas_devices(struct MPT3SAS_ADAPTER *ioc) MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) break; - handle = le16_to_cpu(sas_device_pg0.DevHandle); + handle = sas_device_pg0.DevHandle = + le16_to_cpu(sas_device_pg0.DevHandle); device_info = le32_to_cpu(sas_device_pg0.DeviceInfo); if (!(_scsih_is_end_device(device_info))) continue; - _scsih_mark_responding_sas_device(ioc, - le64_to_cpu(sas_device_pg0.SASAddress), - le16_to_cpu(sas_device_pg0.Slot), handle); + sas_device_pg0.SASAddress = + le64_to_cpu(sas_device_pg0.SASAddress); + sas_device_pg0.Slot = le16_to_cpu(sas_device_pg0.Slot); + _scsih_mark_responding_sas_device(ioc, &sas_device_pg0); } out: -- GitLab From f9d81cfc23151eb6e9e498663c9784c351646d0e Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:53 +0530 Subject: [PATCH 5164/7006] mpt3sas: Bump mpt3sas Driver version to v5.100.00.00 Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index da82a97d73922..d6356126dadfa 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -71,8 +71,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "04.100.00.00" -#define MPT3SAS_MAJOR_VERSION 4 +#define MPT3SAS_DRIVER_VERSION "05.100.00.00" +#define MPT3SAS_MAJOR_VERSION 5 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 -- GitLab From 2e26c3853206ba166c3434e5f2ca4c82078ad84e Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:54 +0530 Subject: [PATCH 5165/7006] mpt3sas: Update MPI2 strings to MPI2.5 Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 3 +-- drivers/scsi/mpt3sas/mpt3sas_base.h | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 7e8ede2fee9d7..0af5744fb25c4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3926,7 +3926,7 @@ _base_send_ioc_init(struct MPT3SAS_ADAPTER *ioc, int sleep_flag) mpi_request.WhoInit = MPI2_WHOINIT_HOST_DRIVER; mpi_request.VF_ID = 0; /* TODO */ mpi_request.VP_ID = 0; - mpi_request.MsgVersion = cpu_to_le16(MPI2_VERSION); + mpi_request.MsgVersion = cpu_to_le16(MPI25_VERSION); mpi_request.HeaderVersion = cpu_to_le16(MPI2_HEADER_VERSION); if (_base_is_controller_msix_enabled(ioc)) @@ -4795,7 +4795,6 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc) ioc->build_sg_scmd = &_base_build_sg_scmd_ieee; ioc->build_sg = &_base_build_sg_ieee; ioc->build_zero_len_sge = &_base_build_zero_len_sge_ieee; - ioc->mpi25 = 1; ioc->sge_size_ieee = sizeof(Mpi2IeeeSgeSimple64_t); /* diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index d6356126dadfa..c0c774f885d52 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -826,7 +826,6 @@ struct MPT3SAS_ADAPTER { MPT_BUILD_SG_SCMD build_sg_scmd; MPT_BUILD_SG build_sg; MPT_BUILD_ZERO_LEN_SGE build_zero_len_sge; - u8 mpi25; u16 sge_size_ieee; /* function ptr for MPI sg elements only */ -- GitLab From 35c319b47884e49d9d0a84779097916ccb173947 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:55 +0530 Subject: [PATCH 5166/7006] mpt3sas: MPI 2.5 Rev J (2.5.5) specification and 2.00.34 header files Following is the change set, 1. Added more defines for the BiosOptions field of MPI2_CONFIG_PAGE_BIOS_1. 2. Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC definition. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpi/mpi2.h | 5 +++-- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 14 ++++++++++++-- drivers/scsi/mpt3sas/mpi/mpi2_tool.h | 4 +++- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h index d730c5ca14669..c2d127c7d4e29 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.33 + * mpi2.h Version: 02.00.34 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -90,6 +90,7 @@ * 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT. * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. + * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT * -------------------------------------------------------------------------- */ @@ -123,7 +124,7 @@ #define MPI2_VERSION_02_05 (0x0205) /*Unit and Dev versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x21) +#define MPI2_HEADER_VERSION_UNIT (0x22) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 62dfbf6bcba0d..cf2b6bf6480f3 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.27 + * mpi2_cnfg.h Version: 02.00.28 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -175,6 +175,8 @@ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. + * 01-08-14 02.00.28 Added more defines for the BiosOptions field of + * MPI2_CONFIG_PAGE_BIOS_1. * -------------------------------------------------------------------------- */ @@ -1334,9 +1336,17 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 { *PTR_MPI2_CONFIG_PAGE_BIOS_1, Mpi2BiosPage1_t, *pMpi2BiosPage1_t; -#define MPI2_BIOSPAGE1_PAGEVERSION (0x05) +#define MPI2_BIOSPAGE1_PAGEVERSION (0x06) /*values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) + +#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) +#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100) +#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200) +#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300) + #define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0) #define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h index 904910d8a7374..1629e5bce7e12 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_tool.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_tool.h @@ -6,7 +6,7 @@ * Title: MPI diagnostic tool structures and definitions * Creation Date: March 26, 2007 * - * mpi2_tool.h Version: 02.00.11 + * mpi2_tool.h Version: 02.00.12 * * Version History * --------------- @@ -33,6 +33,7 @@ * 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that * it uses MPI Chain SGE as well as MPI Simple SGE. * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info. + * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC. * -------------------------------------------------------------------------- */ @@ -100,6 +101,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST { #define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000) #define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000) #define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000) +#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000) #define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000) #define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000) #define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004) -- GitLab From fb84dfc44718ef4099a827d147f738e428828d02 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:56 +0530 Subject: [PATCH 5167/7006] mpt3sas: Add branding string support for OEM's HBA Added the following Dell branding to the mpt3sas driver. "VendorID" "DeviceID" "SubsystemVendor ID" "SubsystemDevice ID" Dell Branding String 0x1000 0x0097 0x1028 0x1F46 DELL 12Gbps HBA Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 36 +++++++++++++++++++++++++++++ drivers/scsi/mpt3sas/mpt3sas_base.h | 11 +++++++++ 2 files changed, 47 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 0af5744fb25c4..3318e4313765c 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2366,6 +2366,41 @@ _base_display_intel_branding(struct MPT3SAS_ADAPTER *ioc) +/** + * _base_display_dell_branding - Display branding string + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc) +{ + if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_DELL) + return; + + switch (ioc->pdev->device) { + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_DELL_12G_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_DELL_12G_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name, + ioc->pdev->subsystem_device); + break; + } + break; + default: + pr_info(MPT3SAS_FMT + "Dell 12Gbps HBA: Subsystem ID: 0x%X\n", ioc->name, + ioc->pdev->subsystem_device); + break; + } +} + + /** * _base_display_ioc_capabilities - Disply IOC's capabilities. * @ioc: per adapter object @@ -2396,6 +2431,7 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) bios_version & 0x000000FF); _base_display_intel_branding(ioc); + _base_display_dell_branding(ioc); pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index c0c774f885d52..a5a34f3e2d539 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -151,6 +151,17 @@ #define MPT3SAS_INTEL_RS3FC044_SSDID 0x3523 #define MPT3SAS_INTEL_RS3UC080_SSDID 0x3524 +/* + * Dell HBA branding + */ +#define MPT3SAS_DELL_12G_HBA_BRANDING \ + "Dell 12Gbps HBA" + +/* + * Dell HBA SSDIDs + */ +#define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 + /* * status bits for ioc->diag_buffer_status */ -- GitLab From 38e4141ecb0e59c93d85ec5948f98d1f1e331a88 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:57 +0530 Subject: [PATCH 5168/7006] mpt3sas: Add branding string support for OEM custom HBA Add the following OEM's branding to the mpt3sas driver. "VendorID" "DeviceID" "SubsystemVendor ID" "SubsystemDevice ID" Cisco Branding String 0x1000 0x97 SVID = 0x1137 0x014C Cisco 9300-8E 12G SAS HBA Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 34 +++++++++++++++++++++++++++++ drivers/scsi/mpt3sas/mpt3sas_base.h | 11 ++++++++++ 2 files changed, 45 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 3318e4313765c..3c8561cb6d846 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2400,6 +2400,39 @@ _base_display_dell_branding(struct MPT3SAS_ADAPTER *ioc) } } +/** + * _base_display_cisco_branding - Display branding string + * @ioc: per adapter object + * + * Return nothing. + */ +static void +_base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc) +{ + if (ioc->pdev->subsystem_vendor != PCI_VENDOR_ID_CISCO) + return; + + switch (ioc->pdev->device) { + case MPI25_MFGPAGE_DEVID_SAS3008: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_CISCO_12G_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } +} /** * _base_display_ioc_capabilities - Disply IOC's capabilities. @@ -2432,6 +2465,7 @@ _base_display_ioc_capabilities(struct MPT3SAS_ADAPTER *ioc) _base_display_intel_branding(ioc); _base_display_dell_branding(ioc); + _base_display_cisco_branding(ioc); pr_info(MPT3SAS_FMT "Protocol=(", ioc->name); diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index a5a34f3e2d539..736682c3a54b7 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -162,6 +162,17 @@ */ #define MPT3SAS_DELL_12G_HBA_SSDID 0x1F46 +/* + * Cisco HBA branding + */ +#define MPT3SAS_CISCO_12G_HBA_BRANDING \ + "Cisco 9300-8E 12G SAS HBA" + +/* + * Cisco HBA SSSDIDs + */ + #define MPT3SAS_CISCO_12G_HBA_SSDID 0x14C + /* * status bits for ioc->diag_buffer_status */ -- GitLab From 2b89669ae4addfa68a58e0fc16afdd24739720d8 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:58 +0530 Subject: [PATCH 5169/7006] mpt3sas: Bump mpt3sas driver version to v6.100.00.00 Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 736682c3a54b7..4196fbbfa3d2f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -71,8 +71,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "05.100.00.00" -#define MPT3SAS_MAJOR_VERSION 5 +#define MPT3SAS_DRIVER_VERSION "06.100.00.00" +#define MPT3SAS_MAJOR_VERSION 6 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 -- GitLab From a6f84009b9d7ca97c400ca929f9d58f43b0ece9d Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:24:59 +0530 Subject: [PATCH 5170/7006] mpt3sas: MPI 2.5 Rev K (2.5.6) specifications Below are the new changes to MPI 2.5 Rev K(2.5.6) specification and 2.00.35 header files 1) Added a minimum size requirement for target mode command buffers. 2) Added MinMSIxIndex and MaxMSIxIndex fields to CommandBufferPostBase Request. 3) For BIOS Page 1, added SSUTimeout field, and added Product Name String Format bits to the BiosOptions field Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpi/mpi2.h | 5 +++-- drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h | 17 ++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2.h b/drivers/scsi/mpt3sas/mpi/mpi2.h index c2d127c7d4e29..ec27ad2d186f9 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2.h @@ -8,7 +8,7 @@ * scatter/gather formats. * Creation Date: June 21, 2006 * - * mpi2.h Version: 02.00.34 + * mpi2.h Version: 02.00.35 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -91,6 +91,7 @@ * 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT. * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT. * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT + * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT. * -------------------------------------------------------------------------- */ @@ -124,7 +125,7 @@ #define MPI2_VERSION_02_05 (0x0205) /*Unit and Dev versioning for this MPI header set */ -#define MPI2_HEADER_VERSION_UNIT (0x22) +#define MPI2_HEADER_VERSION_UNIT (0x23) #define MPI2_HEADER_VERSION_DEV (0x00) #define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI2_HEADER_VERSION_UNIT_SHIFT (8) diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index cf2b6bf6480f3..581fdb375db51 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Configuration messages and pages * Creation Date: November 10, 2006 * - * mpi2_cnfg.h Version: 02.00.28 + * mpi2_cnfg.h Version: 02.00.29 * * NOTE: Names (typedefs, defines, etc.) beginning with an MPI25 or Mpi25 * prefix are for use only on MPI v2.5 products, and must not be used @@ -177,6 +177,8 @@ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0. * 01-08-14 02.00.28 Added more defines for the BiosOptions field of * MPI2_CONFIG_PAGE_BIOS_1. + * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and + * more defines for the BiosOptions field.. * -------------------------------------------------------------------------- */ @@ -1324,7 +1326,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ U32 BiosOptions; /*0x04 */ U32 IOCSettings; /*0x08 */ - U32 Reserved1; /*0x0C */ + U8 SSUTimeout; /*0x0C */ + U8 Reserved1; /*0x0D */ + U16 Reserved2; /*0x0E */ U32 DeviceSettings; /*0x10 */ U16 NumberOfDevices; /*0x14 */ U16 UEFIVersion; /*0x16 */ @@ -1336,9 +1340,16 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1 { *PTR_MPI2_CONFIG_PAGE_BIOS_1, Mpi2BiosPage1_t, *pMpi2BiosPage1_t; -#define MPI2_BIOSPAGE1_PAGEVERSION (0x06) +#define MPI2_BIOSPAGE1_PAGEVERSION (0x07) /*values for BIOS Page 1 BiosOptions field */ +#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800) +#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000) + #define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400) #define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300) -- GitLab From 3898f08e8ccfc8b7b4c297960ecdde970869e950 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:00 +0530 Subject: [PATCH 5171/7006] mpt3sas: Complete the SCSI command with DID_RESET status for log_info value 0x0x32010081 For any SCSI command, if the driver receives IOC status = SCSI_IOC_TERMINATED and log info = 0x32010081 then that command will be completed with DID_RESET host status. The definition of this log info value is "Virtual IO has failed and has to be retried". Firmware will provide this log info value with IOC Status "SCSI_IOC_TERMINATED", whenever a drive (with is a part of a volume) is pulled and pushed back within some minimal delay. With this log info value, firmware informs the driver to retry the failed IO command infinite times, so to provide some time for the firmware to discover the reinserted drive successfully instated of just retrying failed command for five times(doesn't giving enough time for firmware to complete the drive discovery) and failing the IO permanently even though drive came back successfully. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.h | 2 ++ drivers/scsi/mpt3sas/mpt3sas_scsih.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 4196fbbfa3d2f..3b0363912587e 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -202,6 +202,8 @@ #define MFG10_GF0_SSD_DATA_SCRUB_DISABLE (0x00000008) #define MFG10_GF0_SINGLE_DRIVE_R0 (0x00000010) +#define VIRTUAL_IO_FAILED_RETRY (0x32010081) + /* OEM Specific Flags will come from OEM specific header files */ struct Mpi2ManufacturingPage10_t { MPI2_CONFIG_PAGE_HEADER Header; /* 00h */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index ec3b3d3bde38e..9dbc71ffb9363 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4243,6 +4243,9 @@ _scsih_io_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply) scmd->device->expecting_cc_ua = 1; } break; + } else if (log_info == VIRTUAL_IO_FAILED_RETRY) { + scmd->result = DID_RESET << 16; + break; } scmd->result = DID_SOFT_ERROR << 16; break; -- GitLab From 62f5c74c97037c7c00fdefb69dcfe39810c34a05 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:01 +0530 Subject: [PATCH 5172/7006] mpt3sas: Return host busy error status to SML when DMA mapping of scatter gather list fails for a SCSI command scsi_dma_map API will return a negative value (i.e. -ENOMEM) if DMA mapping of sg lists fails and zero if the sg list in the SCSI cmd is NULL. But drivers doesn't handled sg list DMA mapping failure case properly. So, Updated the code to return host busy error status to SCSI MID Layer(SML), when DMA mapping of scatter gather list fails for a SCSI command. So that SML will retry this SCSI cmd after some time. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 3c8561cb6d846..d4d4e6c0b9567 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -1360,7 +1360,7 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, sg_scmd = scsi_sglist(scmd); sges_left = scsi_dma_map(scmd); - if (!sges_left) { + if (sges_left < 0) { sdev_printk(KERN_ERR, scmd->device, "pci_map_sg failed: request for %d bytes!\n", scsi_bufflen(scmd)); @@ -1429,7 +1429,7 @@ _base_build_sg_scmd_ieee(struct MPT3SAS_ADAPTER *ioc, fill_in_last_segment: /* fill the last segment */ - while (sges_left) { + while (sges_left > 0) { if (sges_left == 1) _base_add_sg_single_ieee(sg_local, simple_sgl_flags_last, 0, sg_dma_len(sg_scmd), -- GitLab From d8eb4a47c70b4bab34b938d2f682044687f53c64 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:02 +0530 Subject: [PATCH 5173/7006] mpt3sas: Added support for customer specific branding "VendorID" "DeviceID" "SubsystemVendor ID" "SubsystemDevice ID" Cisco Branding String 0x1000 0x97 0x1137 0x154 Cisco 9300-8i 12Gbps SAS HBA 0x1000 0x97 0x1137 0x155 Cisco 12G Modular SAS Pass through Controller 0x1000 0x97 0x1137 0x156 UCS C3X60 12G SAS Pass through Controller Signed-off-by: Sreekanth Reddy Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.c | 29 +++++++++++++++++++++++++++-- drivers/scsi/mpt3sas/mpt3sas_base.h | 16 ++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index d4d4e6c0b9567..d4f1dcdb83619 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -2415,9 +2415,17 @@ _base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc) switch (ioc->pdev->device) { case MPI25_MFGPAGE_DEVID_SAS3008: switch (ioc->pdev->subsystem_device) { - case MPT3SAS_CISCO_12G_HBA_SSDID: + case MPT3SAS_CISCO_12G_8E_HBA_SSDID: pr_info(MPT3SAS_FMT "%s\n", ioc->name, - MPT3SAS_CISCO_12G_HBA_BRANDING); + MPT3SAS_CISCO_12G_8E_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_8I_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_8I_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); break; default: pr_info(MPT3SAS_FMT @@ -2426,6 +2434,23 @@ _base_display_cisco_branding(struct MPT3SAS_ADAPTER *ioc) break; } break; + case MPI25_MFGPAGE_DEVID_SAS3108_1: + switch (ioc->pdev->subsystem_device) { + case MPT3SAS_CISCO_12G_AVILA_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING); + break; + case MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID: + pr_info(MPT3SAS_FMT "%s\n", ioc->name, + MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING); + break; + default: + pr_info(MPT3SAS_FMT + "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", + ioc->name, ioc->pdev->subsystem_device); + break; + } + break; default: pr_info(MPT3SAS_FMT "Cisco 12Gbps SAS HBA: Subsystem ID: 0x%X\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 3b0363912587e..87e900033b135 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -165,13 +165,21 @@ /* * Cisco HBA branding */ -#define MPT3SAS_CISCO_12G_HBA_BRANDING \ - "Cisco 9300-8E 12G SAS HBA" - +#define MPT3SAS_CISCO_12G_8E_HBA_BRANDING \ + "Cisco 9300-8E 12G SAS HBA" +#define MPT3SAS_CISCO_12G_8I_HBA_BRANDING \ + "Cisco 9300-8i 12G SAS HBA" +#define MPT3SAS_CISCO_12G_AVILA_HBA_BRANDING \ + "Cisco 12G Modular SAS Pass through Controller" +#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_BRANDING \ + "UCS C3X60 12G SAS Pass through Controller" /* * Cisco HBA SSSDIDs */ - #define MPT3SAS_CISCO_12G_HBA_SSDID 0x14C +#define MPT3SAS_CISCO_12G_8E_HBA_SSDID 0x14C +#define MPT3SAS_CISCO_12G_8I_HBA_SSDID 0x154 +#define MPT3SAS_CISCO_12G_AVILA_HBA_SSDID 0x155 +#define MPT3SAS_CISCO_12G_COLUSA_MEZZANINE_HBA_SSDID 0x156 /* * status bits for ioc->diag_buffer_status -- GitLab From bdff785e4f593218816fa3677e043aae1481aa98 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:03 +0530 Subject: [PATCH 5174/7006] mpt3sas: Use alloc_ordered_workqueue() API instead of create_singlethread_workqueue() API Created a thread using alloc_ordered_workqueue() API in order to process the works from firmware Work-queue sequentially instead of create_singlethread_workqueue() API. Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Joe Lawrence Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 9dbc71ffb9363..6e0a7fdfd6264 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -8026,8 +8026,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) /* event thread */ snprintf(ioc->firmware_event_name, sizeof(ioc->firmware_event_name), "fw_event%d", ioc->id); - ioc->firmware_event_thread = create_singlethread_workqueue( - ioc->firmware_event_name); + ioc->firmware_event_thread = alloc_ordered_workqueue( + ioc->firmware_event_name, WQ_MEM_RECLAIM); if (!ioc->firmware_event_thread) { pr_err(MPT3SAS_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); -- GitLab From 36814028ad720165a6febcf9ddd7de20833fd240 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:04 +0530 Subject: [PATCH 5175/7006] mpt3sas: Call dma_mapping_error() API after mapping an address with dma_map_single() API Added dma_mapping_error() API after mapping an address with dma_map_single() API. Otherwise when CONFIG_DMA_API_DEBUG is enabled in the kernel, then it complains about mpt3sas driver not calling dma_mapping_error after mapping an address with dma_map_single Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_transport.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index 7a7aa68a3f5f5..70fd019e7ee58 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -1964,7 +1964,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } else { dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio), blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_out) { + if (pci_dma_mapping_error(ioc->pdev, dma_addr_out)) { pr_info(MPT3SAS_FMT "%s(): DMA Addr out = NULL\n", ioc->name, __func__); rc = -ENOMEM; @@ -1986,7 +1986,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, } else { dma_addr_in = pci_map_single(ioc->pdev, bio_data(rsp->bio), blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL); - if (!dma_addr_in) { + if (pci_dma_mapping_error(ioc->pdev, dma_addr_in)) { pr_info(MPT3SAS_FMT "%s(): DMA Addr in = NULL\n", ioc->name, __func__); rc = -ENOMEM; -- GitLab From df838f92f3f5240dca54e1629e8547818e8ea646 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:05 +0530 Subject: [PATCH 5176/7006] mpt3sas: When device is blocked followed by unblock fails, unfreeze the I/Os Issue: When the disks are getting discovered and assigned device handles by the kernel, a device block followed by an unblock (due to broadcast primitives) issued by the driver is interspersed by the kernel changing the state of the device. Therefore the unblock by the driver results in a no operation within the kernel API. To fix this one, the below patch checks the return of the unblock API and performs a block followed by an unblock to unfreeze the block layer's I/O queue. Sufficient checks and prints are also added in the driver to identify this condition caused by the kernel. Signed-off-by: Sreekanth Reddy Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 89 +++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 6e0a7fdfd6264..8ccef38523fa4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2604,6 +2604,75 @@ _scsih_fw_event_cleanup_queue(struct MPT3SAS_ADAPTER *ioc) } } +/** + * _scsih_internal_device_block - block the sdev device + * @sdev: per device object + * @sas_device_priv_data : per device driver private data + * + * make sure device is blocked without error, if not + * print an error + */ +static void +_scsih_internal_device_block(struct scsi_device *sdev, + struct MPT3SAS_DEVICE *sas_device_priv_data) +{ + int r = 0; + + sdev_printk(KERN_INFO, sdev, "device_block, handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle); + sas_device_priv_data->block = 1; + + r = scsi_internal_device_block(sdev); + if (r == -EINVAL) + sdev_printk(KERN_WARNING, sdev, + "device_block failed with return(%d) for handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle, r); +} + +/** + * _scsih_internal_device_unblock - unblock the sdev device + * @sdev: per device object + * @sas_device_priv_data : per device driver private data + * make sure device is unblocked without error, if not retry + * by blocking and then unblocking + */ + +static void +_scsih_internal_device_unblock(struct scsi_device *sdev, + struct MPT3SAS_DEVICE *sas_device_priv_data) +{ + int r = 0; + + sdev_printk(KERN_WARNING, sdev, "device_unblock and setting to running, " + "handle(0x%04x)\n", sas_device_priv_data->sas_target->handle); + sas_device_priv_data->block = 0; + r = scsi_internal_device_unblock(sdev, SDEV_RUNNING); + if (r == -EINVAL) { + /* The device has been set to SDEV_RUNNING by SD layer during + * device addition but the request queue is still stopped by + * our earlier block call. We need to perform a block again + * to get the device to SDEV_BLOCK and then to SDEV_RUNNING */ + + sdev_printk(KERN_WARNING, sdev, + "device_unblock failed with return(%d) for handle(0x%04x) " + "performing a block followed by an unblock\n", + sas_device_priv_data->sas_target->handle, r); + sas_device_priv_data->block = 1; + r = scsi_internal_device_block(sdev); + if (r) + sdev_printk(KERN_WARNING, sdev, "retried device_block " + "failed with return(%d) for handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle, r); + + sas_device_priv_data->block = 0; + r = scsi_internal_device_unblock(sdev, SDEV_RUNNING); + if (r) + sdev_printk(KERN_WARNING, sdev, "retried device_unblock" + " failed with return(%d) for handle(0x%04x)\n", + sas_device_priv_data->sas_target->handle, r); + } +} + /** * _scsih_ublock_io_all_device - unblock every device * @ioc: per adapter object @@ -2623,11 +2692,10 @@ _scsih_ublock_io_all_device(struct MPT3SAS_ADAPTER *ioc) if (!sas_device_priv_data->block) continue; - sas_device_priv_data->block = 0; dewtprintk(ioc, sdev_printk(KERN_INFO, sdev, "device_running, handle(0x%04x)\n", sas_device_priv_data->sas_target->handle)); - scsi_internal_device_unblock(sdev, SDEV_RUNNING); + _scsih_internal_device_unblock(sdev, sas_device_priv_data); } } @@ -2652,10 +2720,9 @@ _scsih_ublock_io_device(struct MPT3SAS_ADAPTER *ioc, u64 sas_address) if (sas_device_priv_data->sas_target->sas_address != sas_address) continue; - if (sas_device_priv_data->block) { - sas_device_priv_data->block = 0; - scsi_internal_device_unblock(sdev, SDEV_RUNNING); - } + if (sas_device_priv_data->block) + _scsih_internal_device_unblock(sdev, + sas_device_priv_data); } } @@ -2678,10 +2745,7 @@ _scsih_block_io_all_device(struct MPT3SAS_ADAPTER *ioc) continue; if (sas_device_priv_data->block) continue; - sas_device_priv_data->block = 1; - scsi_internal_device_block(sdev); - sdev_printk(KERN_INFO, sdev, "device_blocked, handle(0x%04x)\n", - sas_device_priv_data->sas_target->handle); + _scsih_internal_device_block(sdev, sas_device_priv_data); } } @@ -2713,10 +2777,7 @@ _scsih_block_io_device(struct MPT3SAS_ADAPTER *ioc, u16 handle) continue; if (sas_device->pend_sas_rphy_add) continue; - sas_device_priv_data->block = 1; - scsi_internal_device_block(sdev); - sdev_printk(KERN_INFO, sdev, - "device_blocked, handle(0x%04x)\n", handle); + _scsih_internal_device_block(sdev, sas_device_priv_data); } } -- GitLab From c75683ca13d12a700531864bcd3118e94bc9eaa0 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Tue, 30 Jun 2015 12:25:06 +0530 Subject: [PATCH 5177/7006] mpt3sas : Bump mpt3sas driver version to 9.100.00.00 Signed-off-by: Sreekanth Reddy Reviewed-by: Martin K. Petersen Reviewed-by: Johannes Thumshirn Signed-off-by: James Bottomley --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 87e900033b135..f0e462b0880d2 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -71,8 +71,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "06.100.00.00" -#define MPT3SAS_MAJOR_VERSION 6 +#define MPT3SAS_DRIVER_VERSION "09.100.00.00" +#define MPT3SAS_MAJOR_VERSION 9 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 -- GitLab From f729dc70dafec281e524f51ae496a72ea4f8e319 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sun, 26 Jul 2015 04:37:15 +0800 Subject: [PATCH 5178/7006] batman-adv: move hardif refcount inc to batadv_neigh_node_new() The batadv_neigh_node cleanup function 'batadv_neigh_node_free_rcu()' takes care of reducing the hardif refcounter, hence it's only logical to assume the creating function of that same object 'batadv_neigh_node_new()' takes care of increasing the same refcounter. Signed-off-by: Marek Lindner Acked-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 6 ------ net/batman-adv/originator.c | 6 ++++++ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 5c122000688fb..b9b8b333b3634 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -303,12 +303,6 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, if (!neigh_node) goto out; - if (!atomic_inc_not_zero(&hard_iface->refcount)) { - kfree(neigh_node); - neigh_node = NULL; - goto out; - } - neigh_node->orig_node = orig_neigh; neigh_node->if_incoming = hard_iface; diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 610620aa8d261..f8317c1db4274 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -461,6 +461,12 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, if (!neigh_node) goto out; + if (!atomic_inc_not_zero(&hard_iface->refcount)) { + kfree(neigh_node); + neigh_node = NULL; + goto out; + } + INIT_HLIST_NODE(&neigh_node->list); INIT_HLIST_HEAD(&neigh_node->ifinfo_list); spin_lock_init(&neigh_node->ifinfo_lock); -- GitLab From 39bf7618f038474a0ccbeb0be173f11e147bd083 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sun, 26 Jul 2015 04:37:47 +0800 Subject: [PATCH 5179/7006] batman-adv: remove redundant hard_iface assignment The batadv_neigh_node_new() function already sets the hard_iface pointer. Signed-off-by: Marek Lindner Acked-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index b9b8b333b3634..b18184e0c497b 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -304,7 +304,6 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, goto out; neigh_node->orig_node = orig_neigh; - neigh_node->if_incoming = hard_iface; spin_lock_bh(&orig_node->neigh_list_lock); tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, -- GitLab From 741aa06bfb0ab731086d258a1838152fe2502b5f Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sun, 26 Jul 2015 04:57:43 +0800 Subject: [PATCH 5180/7006] batman-adv: move neigh_node list add into batadv_neigh_node_new() All batadv_neigh_node_* functions expect the neigh_node list item to be part of the orig_node->neigh_list, therefore the constructor of said list item should be adding the newly created neigh_node to the respective list. Signed-off-by: Marek Lindner Acked-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 21 +-------------------- net/batman-adv/originator.c | 12 ++++++++++++ 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index b18184e0c497b..5e93af4cb97f1 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -296,8 +296,7 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, struct batadv_orig_node *orig_node, struct batadv_orig_node *orig_neigh) { - struct batadv_priv *bat_priv = netdev_priv(hard_iface->soft_iface); - struct batadv_neigh_node *neigh_node, *tmp_neigh_node; + struct batadv_neigh_node *neigh_node; neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node); if (!neigh_node) @@ -305,24 +304,6 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, neigh_node->orig_node = orig_neigh; - spin_lock_bh(&orig_node->neigh_list_lock); - tmp_neigh_node = batadv_neigh_node_get(orig_node, hard_iface, - neigh_addr); - if (!tmp_neigh_node) { - hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); - } else { - kfree(neigh_node); - batadv_hardif_free_ref(hard_iface); - neigh_node = tmp_neigh_node; - } - spin_unlock_bh(&orig_node->neigh_list_lock); - - if (!tmp_neigh_node) - batadv_dbg(BATADV_DBG_BATMAN, bat_priv, - "Creating new neighbor %pM for orig_node %pM on interface %s\n", - neigh_addr, orig_node->orig, - hard_iface->net_dev->name); - out: return neigh_node; } diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index f8317c1db4274..f7517757d435b 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -457,6 +457,10 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, { struct batadv_neigh_node *neigh_node; + neigh_node = batadv_neigh_node_get(orig_node, hard_iface, neigh_addr); + if (neigh_node) + goto out; + neigh_node = kzalloc(sizeof(*neigh_node), GFP_ATOMIC); if (!neigh_node) goto out; @@ -478,6 +482,14 @@ batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, /* extra reference for return */ atomic_set(&neigh_node->refcount, 2); + spin_lock_bh(&orig_node->neigh_list_lock); + hlist_add_head_rcu(&neigh_node->list, &orig_node->neigh_list); + spin_unlock_bh(&orig_node->neigh_list_lock); + + batadv_dbg(BATADV_DBG_BATMAN, orig_node->bat_priv, + "Creating new neighbor %pM for orig_node %pM on interface %s\n", + neigh_addr, orig_node->orig, hard_iface->net_dev->name); + out: return neigh_node; } -- GitLab From bd3524c14bd02f94a4fa33e700883e01182f5ed5 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Mon, 3 Aug 2015 19:13:58 +0200 Subject: [PATCH 5181/7006] batman-adv: remove obsolete deleted attribute for gateway node With rcu, the gateway node deleted attribute is not needed anymore. In fact, it may delay the free of the gateway node and its referenced structures. Therefore remove it altogether and simplify purging as well. Signed-off-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/gateway_client.c | 48 +++++++++------------------------ net/batman-adv/gateway_client.h | 2 +- net/batman-adv/main.c | 2 +- net/batman-adv/originator.c | 1 - net/batman-adv/types.h | 2 -- 5 files changed, 14 insertions(+), 41 deletions(-) diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index d7ca2144e62c1..634c7e3b4e89f 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -161,9 +161,6 @@ batadv_gw_get_best_gw_node(struct batadv_priv *bat_priv) rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { - if (gw_node->deleted) - continue; - orig_node = gw_node->orig_node; router = batadv_orig_router_get(orig_node, BATADV_IF_DEFAULT); if (!router) @@ -473,9 +470,6 @@ batadv_gw_node_get(struct batadv_priv *bat_priv, if (gw_node_tmp->orig_node != orig_node) continue; - if (gw_node_tmp->deleted) - continue; - if (!atomic_inc_not_zero(&gw_node_tmp->refcount)) continue; @@ -525,9 +519,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, gw_node->bandwidth_down = ntohl(gateway->bandwidth_down); gw_node->bandwidth_up = ntohl(gateway->bandwidth_up); - gw_node->deleted = 0; if (ntohl(gateway->bandwidth_down) == 0) { - gw_node->deleted = jiffies; batadv_dbg(BATADV_DBG_BATMAN, bat_priv, "Gateway %pM removed from gateway list\n", orig_node->orig); @@ -535,14 +527,21 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, /* Note: We don't need a NULL check here, since curr_gw never * gets dereferenced. */ + spin_lock_bh(&bat_priv->gw.list_lock); + hlist_del_init_rcu(&gw_node->list); + spin_unlock_bh(&bat_priv->gw.list_lock); + + batadv_gw_node_free_ref(gw_node); + curr_gw = batadv_gw_get_selected_gw_node(bat_priv); if (gw_node == curr_gw) batadv_gw_reselect(bat_priv); + + if (curr_gw) + batadv_gw_node_free_ref(curr_gw); } out: - if (curr_gw) - batadv_gw_node_free_ref(curr_gw); if (gw_node) batadv_gw_node_free_ref(gw_node); } @@ -558,39 +557,19 @@ void batadv_gw_node_delete(struct batadv_priv *bat_priv, batadv_gw_node_update(bat_priv, orig_node, &gateway); } -void batadv_gw_node_purge(struct batadv_priv *bat_priv) +void batadv_gw_node_free(struct batadv_priv *bat_priv) { - struct batadv_gw_node *gw_node, *curr_gw; + struct batadv_gw_node *gw_node; struct hlist_node *node_tmp; - unsigned long timeout = msecs_to_jiffies(2 * BATADV_PURGE_TIMEOUT); - int do_reselect = 0; - - curr_gw = batadv_gw_get_selected_gw_node(bat_priv); spin_lock_bh(&bat_priv->gw.list_lock); - hlist_for_each_entry_safe(gw_node, node_tmp, &bat_priv->gw.list, list) { - if (((!gw_node->deleted) || - (time_before(jiffies, gw_node->deleted + timeout))) && - atomic_read(&bat_priv->mesh_state) == BATADV_MESH_ACTIVE) - continue; - if (curr_gw == gw_node) - do_reselect = 1; - - hlist_del_rcu(&gw_node->list); + hlist_del_init_rcu(&gw_node->list); batadv_gw_node_free_ref(gw_node); } - spin_unlock_bh(&bat_priv->gw.list_lock); - - /* gw_reselect() needs to acquire the gw_list_lock */ - if (do_reselect) - batadv_gw_reselect(bat_priv); - - if (curr_gw) - batadv_gw_node_free_ref(curr_gw); } /* fails if orig_node has no router */ @@ -654,9 +633,6 @@ int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset) rcu_read_lock(); hlist_for_each_entry_rcu(gw_node, &bat_priv->gw.list, list) { - if (gw_node->deleted) - continue; - /* fails if orig_node has no router */ if (batadv_write_buffer_text(bat_priv, seq, gw_node) < 0) continue; diff --git a/net/batman-adv/gateway_client.h b/net/batman-adv/gateway_client.h index ef4d7e336651f..fa9527785ed3c 100644 --- a/net/batman-adv/gateway_client.h +++ b/net/batman-adv/gateway_client.h @@ -38,7 +38,7 @@ void batadv_gw_node_update(struct batadv_priv *bat_priv, struct batadv_tvlv_gateway_data *gateway); void batadv_gw_node_delete(struct batadv_priv *bat_priv, struct batadv_orig_node *orig_node); -void batadv_gw_node_purge(struct batadv_priv *bat_priv); +void batadv_gw_node_free(struct batadv_priv *bat_priv); int batadv_gw_client_seq_print_text(struct seq_file *seq, void *offset); bool batadv_gw_out_of_range(struct batadv_priv *bat_priv, struct sk_buff *skb); enum batadv_dhcp_recipient diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c index e61c5f3633d0e..d7f17c1aa4a4b 100644 --- a/net/batman-adv/main.c +++ b/net/batman-adv/main.c @@ -199,7 +199,7 @@ void batadv_mesh_free(struct net_device *soft_iface) batadv_purge_outstanding_packets(bat_priv, NULL); - batadv_gw_node_purge(bat_priv); + batadv_gw_node_free(bat_priv); batadv_nc_mesh_free(bat_priv); batadv_dat_free(bat_priv); batadv_bla_free(bat_priv); diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index f7517757d435b..d6d9809fee661 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -1028,7 +1028,6 @@ static void _batadv_purge_orig(struct batadv_priv *bat_priv) spin_unlock_bh(list_lock); } - batadv_gw_node_purge(bat_priv); batadv_gw_election(bat_priv); } diff --git a/net/batman-adv/types.h b/net/batman-adv/types.h index 2f5e6c39f9135..d260efd70499b 100644 --- a/net/batman-adv/types.h +++ b/net/batman-adv/types.h @@ -328,7 +328,6 @@ enum batadv_orig_capabilities { * @orig_node: pointer to corresponding orig node * @bandwidth_down: advertised uplink download bandwidth * @bandwidth_up: advertised uplink upload bandwidth - * @deleted: this struct is scheduled for deletion * @refcount: number of contexts the object is used * @rcu: struct used for freeing in an RCU-safe manner */ @@ -337,7 +336,6 @@ struct batadv_gw_node { struct batadv_orig_node *orig_node; u32 bandwidth_down; u32 bandwidth_up; - unsigned long deleted; atomic_t refcount; struct rcu_head rcu; }; -- GitLab From 3f32f8a6874ae2515c8894588a5c60dd65ecc7e5 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Sun, 26 Jul 2015 04:59:15 +0800 Subject: [PATCH 5182/7006] batman-adv: rearrange batadv_neigh_node_new() arguments to follow convention Signed-off-by: Marek Lindner Acked-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- net/batman-adv/bat_iv_ogm.c | 2 +- net/batman-adv/originator.c | 7 ++++--- net/batman-adv/originator.h | 5 +++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c index 5e93af4cb97f1..912d9c36fb1c9 100644 --- a/net/batman-adv/bat_iv_ogm.c +++ b/net/batman-adv/bat_iv_ogm.c @@ -298,7 +298,7 @@ batadv_iv_ogm_neigh_new(struct batadv_hard_iface *hard_iface, { struct batadv_neigh_node *neigh_node; - neigh_node = batadv_neigh_node_new(hard_iface, neigh_addr, orig_node); + neigh_node = batadv_neigh_node_new(orig_node, hard_iface, neigh_addr); if (!neigh_node) goto out; diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index d6d9809fee661..099a84afcd615 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -444,16 +444,17 @@ out: /** * batadv_neigh_node_new - create and init a new neigh_node object + * @orig_node: originator object representing the neighbour * @hard_iface: the interface where the neighbour is connected to * @neigh_addr: the mac address of the neighbour interface - * @orig_node: originator object representing the neighbour * * Allocates a new neigh_node object and initialises all the generic fields. * Returns the new object or NULL on failure. */ struct batadv_neigh_node * -batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, - const u8 *neigh_addr, struct batadv_orig_node *orig_node) +batadv_neigh_node_new(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *hard_iface, + const u8 *neigh_addr) { struct batadv_neigh_node *neigh_node; diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index 3fc76f6f710c4..fde34385c62c4 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -46,8 +46,9 @@ batadv_neigh_node_get(const struct batadv_orig_node *orig_node, const struct batadv_hard_iface *hard_iface, const u8 *addr); struct batadv_neigh_node * -batadv_neigh_node_new(struct batadv_hard_iface *hard_iface, - const u8 *neigh_addr, struct batadv_orig_node *orig_node); +batadv_neigh_node_new(struct batadv_orig_node *orig_node, + struct batadv_hard_iface *hard_iface, + const u8 *neigh_addr); void batadv_neigh_node_free_ref(struct batadv_neigh_node *neigh_node); struct batadv_neigh_node * batadv_orig_router_get(struct batadv_orig_node *orig_node, -- GitLab From 1e3b4669e79253748073b0ee95270f92f0372b20 Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Tue, 4 Aug 2015 15:44:06 +0200 Subject: [PATCH 5183/7006] batman-adv: fix gateway client style issues commit 0511575c4d03 ("batman-adv: remove obsolete deleted attribute for gateway node") incorrectly added an empy line and forgot to remove an include. Signed-off-by: Simon Wunderlich Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/gateway_client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/batman-adv/gateway_client.c b/net/batman-adv/gateway_client.c index 634c7e3b4e89f..e6c8382c79ba8 100644 --- a/net/batman-adv/gateway_client.c +++ b/net/batman-adv/gateway_client.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -565,7 +564,6 @@ void batadv_gw_node_free(struct batadv_priv *bat_priv) spin_lock_bh(&bat_priv->gw.list_lock); hlist_for_each_entry_safe(gw_node, node_tmp, &bat_priv->gw.list, list) { - hlist_del_init_rcu(&gw_node->list); batadv_gw_node_free_ref(gw_node); } -- GitLab From 07c48eca1661decbd52393ef535f0c97e5313c4e Mon Sep 17 00:00:00 2001 From: Simon Wunderlich Date: Tue, 4 Aug 2015 14:43:16 +0200 Subject: [PATCH 5184/7006] batman-adv: Start new development cycle Signed-off-by: Simon Wunderlich Signed-off-by: Antonio Quartulli --- net/batman-adv/main.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/batman-adv/main.h b/net/batman-adv/main.h index 78500ac725d62..ebd8af0a1eb04 100644 --- a/net/batman-adv/main.h +++ b/net/batman-adv/main.h @@ -24,7 +24,7 @@ #define BATADV_DRIVER_DEVICE "batman-adv" #ifndef BATADV_SOURCE_VERSION -#define BATADV_SOURCE_VERSION "2015.1" +#define BATADV_SOURCE_VERSION "2015.2" #endif /* B.A.T.M.A.N. parameters */ -- GitLab From a5256f7e74d85d7ae60ac3bd557d5fe3444be810 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 4 Aug 2015 22:26:19 +0200 Subject: [PATCH 5185/7006] batman-adv: don't access unregistered net_device object In batadv_hardif_disable_interface() there is a call to batadv_softif_destroy_sysfs() which in turns invokes unregister_netdevice() on the soft_iface. After this point we cannot rely on the soft_iface object anymore because it might get free'd by the netdev periodic routine at any time. For this reason the netdev_upper_dev_unlink(.., soft_iface) call is moved before the invocation of batadv_softif_destroy_sysfs() so that we can be sure that the soft_iface object is still valid. Signed-off-by: Antonio Quartulli Signed-off-by: Marek Lindner --- net/batman-adv/hard-interface.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index f4a15d2e5eaf8..0565b20bfa6db 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -528,6 +528,8 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, batadv_purge_outstanding_packets(bat_priv, hard_iface); dev_put(hard_iface->soft_iface); + netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface); + /* nobody uses this interface anymore */ if (!bat_priv->num_ifaces) { batadv_gw_check_client_stop(bat_priv); @@ -536,7 +538,6 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, batadv_softif_destroy_sysfs(hard_iface->soft_iface); } - netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface); hard_iface->soft_iface = NULL; batadv_hardif_free_ref(hard_iface); -- GitLab From 7bca68c7844b1642868809a5ef4387c1f099ab1d Mon Sep 17 00:00:00 2001 From: Sven Eckelmann Date: Fri, 7 Aug 2015 19:28:42 +0200 Subject: [PATCH 5186/7006] batman-adv: Add lower layer needed_(head|tail)room to own ones The maximum of hard_header_len and maximum of all needed_(head|tail)room of all slave interfaces of a batman-adv device must be used to define the batman-adv device needed_(head|tail)room. This is required to avoid too small buffer problems when these slave devices try to send the encapsulated packet in a tx path without the possibility to resize the skbuff. Signed-off-by: Sven Eckelmann Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/hard-interface.c | 41 +++++++++++++++++++++++++++++++++ net/batman-adv/soft-interface.c | 2 -- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/net/batman-adv/hard-interface.c b/net/batman-adv/hard-interface.c index 0565b20bfa6db..f11345e163d7f 100644 --- a/net/batman-adv/hard-interface.c +++ b/net/batman-adv/hard-interface.c @@ -252,6 +252,44 @@ static void batadv_check_known_mac_addr(const struct net_device *net_dev) rcu_read_unlock(); } +/** + * batadv_hardif_recalc_extra_skbroom() - Recalculate skbuff extra head/tailroom + * @soft_iface: netdev struct of the mesh interface + */ +static void batadv_hardif_recalc_extra_skbroom(struct net_device *soft_iface) +{ + const struct batadv_hard_iface *hard_iface; + unsigned short lower_header_len = ETH_HLEN; + unsigned short lower_headroom = 0; + unsigned short lower_tailroom = 0; + unsigned short needed_headroom; + + rcu_read_lock(); + list_for_each_entry_rcu(hard_iface, &batadv_hardif_list, list) { + if (hard_iface->if_status == BATADV_IF_NOT_IN_USE) + continue; + + if (hard_iface->soft_iface != soft_iface) + continue; + + lower_header_len = max_t(unsigned short, lower_header_len, + hard_iface->net_dev->hard_header_len); + + lower_headroom = max_t(unsigned short, lower_headroom, + hard_iface->net_dev->needed_headroom); + + lower_tailroom = max_t(unsigned short, lower_tailroom, + hard_iface->net_dev->needed_tailroom); + } + rcu_read_unlock(); + + needed_headroom = lower_headroom + (lower_header_len - ETH_HLEN); + needed_headroom += batadv_max_header_len(); + + soft_iface->needed_headroom = needed_headroom; + soft_iface->needed_tailroom = lower_tailroom; +} + int batadv_hardif_min_mtu(struct net_device *soft_iface) { struct batadv_priv *bat_priv = netdev_priv(soft_iface); @@ -474,6 +512,8 @@ int batadv_hardif_enable_interface(struct batadv_hard_iface *hard_iface, "Not using interface %s (retrying later): interface not active\n", hard_iface->net_dev->name); + batadv_hardif_recalc_extra_skbroom(soft_iface); + /* begin scheduling originator messages on that interface */ batadv_schedule_bat_ogm(hard_iface); @@ -529,6 +569,7 @@ void batadv_hardif_disable_interface(struct batadv_hard_iface *hard_iface, dev_put(hard_iface->soft_iface); netdev_upper_dev_unlink(hard_iface->net_dev, hard_iface->soft_iface); + batadv_hardif_recalc_extra_skbroom(hard_iface->soft_iface); /* nobody uses this interface anymore */ if (!bat_priv->num_ifaces) { diff --git a/net/batman-adv/soft-interface.c b/net/batman-adv/soft-interface.c index d5c5ad93a6116..ac4d08de5df46 100644 --- a/net/batman-adv/soft-interface.c +++ b/net/batman-adv/soft-interface.c @@ -947,8 +947,6 @@ static void batadv_softif_init_early(struct net_device *dev) * have not been initialized yet */ dev->mtu = ETH_DATA_LEN; - /* reserve more space in the skbuff for our header */ - dev->hard_header_len = batadv_max_header_len(); /* generate random address */ eth_hw_addr_random(dev); -- GitLab From ed29266347025a19ee689807b07d121f0a7441f1 Mon Sep 17 00:00:00 2001 From: Marek Lindner Date: Tue, 4 Aug 2015 23:31:44 +0800 Subject: [PATCH 5187/7006] batman-adv: turn batadv_neigh_node_get() into local function commit c214ebe1eb29 ("batman-adv: move neigh_node list add into batadv_neigh_node_new()") removed external calls to batadv_neigh_node_get(). Signed-off-by: Marek Lindner Signed-off-by: Antonio Quartulli --- net/batman-adv/originator.c | 72 ++++++++++++++++++------------------- net/batman-adv/originator.h | 4 --- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/net/batman-adv/originator.c b/net/batman-adv/originator.c index 099a84afcd615..7486df9ed48db 100644 --- a/net/batman-adv/originator.c +++ b/net/batman-adv/originator.c @@ -442,6 +442,42 @@ out: return neigh_ifinfo; } +/** + * batadv_neigh_node_get - retrieve a neighbour from the list + * @orig_node: originator which the neighbour belongs to + * @hard_iface: the interface where this neighbour is connected to + * @addr: the address of the neighbour + * + * Looks for and possibly returns a neighbour belonging to this originator list + * which is connected through the provided hard interface. + * Returns NULL if the neighbour is not found. + */ +static struct batadv_neigh_node * +batadv_neigh_node_get(const struct batadv_orig_node *orig_node, + const struct batadv_hard_iface *hard_iface, + const u8 *addr) +{ + struct batadv_neigh_node *tmp_neigh_node, *res = NULL; + + rcu_read_lock(); + hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) { + if (!batadv_compare_eth(tmp_neigh_node->addr, addr)) + continue; + + if (tmp_neigh_node->if_incoming != hard_iface) + continue; + + if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) + continue; + + res = tmp_neigh_node; + break; + } + rcu_read_unlock(); + + return res; +} + /** * batadv_neigh_node_new - create and init a new neigh_node object * @orig_node: originator object representing the neighbour @@ -495,42 +531,6 @@ out: return neigh_node; } -/** - * batadv_neigh_node_get - retrieve a neighbour from the list - * @orig_node: originator which the neighbour belongs to - * @hard_iface: the interface where this neighbour is connected to - * @addr: the address of the neighbour - * - * Looks for and possibly returns a neighbour belonging to this originator list - * which is connected through the provided hard interface. - * Returns NULL if the neighbour is not found. - */ -struct batadv_neigh_node * -batadv_neigh_node_get(const struct batadv_orig_node *orig_node, - const struct batadv_hard_iface *hard_iface, - const u8 *addr) -{ - struct batadv_neigh_node *tmp_neigh_node, *res = NULL; - - rcu_read_lock(); - hlist_for_each_entry_rcu(tmp_neigh_node, &orig_node->neigh_list, list) { - if (!batadv_compare_eth(tmp_neigh_node->addr, addr)) - continue; - - if (tmp_neigh_node->if_incoming != hard_iface) - continue; - - if (!atomic_inc_not_zero(&tmp_neigh_node->refcount)) - continue; - - res = tmp_neigh_node; - break; - } - rcu_read_unlock(); - - return res; -} - /** * batadv_orig_ifinfo_free_rcu - free the orig_ifinfo object * @rcu: rcu pointer of the orig_ifinfo object diff --git a/net/batman-adv/originator.h b/net/batman-adv/originator.h index fde34385c62c4..fa18f9bf266b0 100644 --- a/net/batman-adv/originator.h +++ b/net/batman-adv/originator.h @@ -42,10 +42,6 @@ void batadv_orig_node_free_ref_now(struct batadv_orig_node *orig_node); struct batadv_orig_node *batadv_orig_node_new(struct batadv_priv *bat_priv, const u8 *addr); struct batadv_neigh_node * -batadv_neigh_node_get(const struct batadv_orig_node *orig_node, - const struct batadv_hard_iface *hard_iface, - const u8 *addr); -struct batadv_neigh_node * batadv_neigh_node_new(struct batadv_orig_node *orig_node, struct batadv_hard_iface *hard_iface, const u8 *neigh_addr); -- GitLab From 538e4563198cd3d1a8e74c47fee3e49dc93e4a95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= Date: Wed, 26 Aug 2015 17:53:45 +0200 Subject: [PATCH 5188/7006] bgmac: support up to 3 cores (devices) on a bus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Broadcom buses may have more than 1 Ethernet device. This is used e.g. to have few interfaces connected to different switch ports. So far we saw chipsets with only 2 devices (e.g. BCM4706) but recent ones have up to 3 (e.g. Netgear R8000 uses 3rd interface for most of switch traffic, lower interfaces are for some kind of offloading). Signed-off-by: Rafał Miłecki Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 28 ++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index 21e3c38c7c752..d043746e2fc56 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1549,11 +1549,20 @@ static int bgmac_probe(struct bcma_device *core) struct net_device *net_dev; struct bgmac *bgmac; struct ssb_sprom *sprom = &core->bus->sprom; - u8 *mac = core->core_unit ? sprom->et1mac : sprom->et0mac; + u8 *mac; int err; - /* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */ - if (core->core_unit > 1) { + switch (core->core_unit) { + case 0: + mac = sprom->et0mac; + break; + case 1: + mac = sprom->et1mac; + break; + case 2: + mac = sprom->et2mac; + break; + default: pr_err("Unsupported core_unit %d\n", core->core_unit); return -ENOTSUPP; } @@ -1588,8 +1597,17 @@ static int bgmac_probe(struct bcma_device *core) } bgmac->cmn = core->bus->drv_gmac_cmn.core; - bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr : - sprom->et0phyaddr; + switch (core->core_unit) { + case 0: + bgmac->phyaddr = sprom->et0phyaddr; + break; + case 1: + bgmac->phyaddr = sprom->et1phyaddr; + break; + case 2: + bgmac->phyaddr = sprom->et2phyaddr; + break; + } bgmac->phyaddr &= BGMAC_PHY_MASK; if (bgmac->phyaddr == BGMAC_PHY_MASK) { bgmac_err(bgmac, "No PHY found\n"); -- GitLab From 8e2fed1c0cfbb29995a4301060acc0ef4ee84420 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:44 -0700 Subject: [PATCH 5189/7006] openvswitch: Serialize acts with original netlink len Previously, we used the kernel-internal netlink actions length to calculate the size of messages to serialize back to userspace. However,the sw_flow_actions may not be formatted exactly the same as the actions on the wire, so store the original actions length when de-serializing and re-use the original length when serializing. Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/openvswitch/datapath.c | 2 +- net/openvswitch/flow.h | 1 + net/openvswitch/flow_netlink.c | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index ffe984f5b95ce..d5b5473758878 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -713,7 +713,7 @@ static size_t ovs_flow_cmd_msg_size(const struct sw_flow_actions *acts, /* OVS_FLOW_ATTR_ACTIONS */ if (should_fill_actions(ufid_flags)) - len += nla_total_size(acts->actions_len); + len += nla_total_size(acts->orig_len); return len + nla_total_size(sizeof(struct ovs_flow_stats)) /* OVS_FLOW_ATTR_STATS */ diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index b62cdb3e35892..082a87bac8196 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -144,6 +144,7 @@ struct sw_flow_id { struct sw_flow_actions { struct rcu_head rcu; + size_t orig_len; /* From flow_cmd_new netlink actions size */ u32 actions_len; struct nlattr actions[]; }; diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 4e7a3f7facc22..c182b28c0884a 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -1619,6 +1619,7 @@ static struct nlattr *reserve_sfa_size(struct sw_flow_actions **sfa, memcpy(acts->actions, (*sfa)->actions, (*sfa)->actions_len); acts->actions_len = (*sfa)->actions_len; + acts->orig_len = (*sfa)->orig_len; kfree(*sfa); *sfa = acts; @@ -2223,6 +2224,7 @@ int ovs_nla_copy_actions(const struct nlattr *attr, if (IS_ERR(*sfa)) return PTR_ERR(*sfa); + (*sfa)->orig_len = nla_len(attr); err = __ovs_nla_copy_actions(attr, key, 0, sfa, key->eth.type, key->eth.tci, log); if (err) -- GitLab From be26b9a88fcee570796c67701f50800039e25aec Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:45 -0700 Subject: [PATCH 5190/7006] openvswitch: Move MASKED* macros to datapath.h This will allow the ovs-conntrack code to reuse these macros. Signed-off-by: Joe Stringer Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/actions.c | 52 ++++++++++++++++++-------------------- net/openvswitch/datapath.h | 4 +++ 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 4f4200717bef9..520438b77dc8c 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -185,10 +185,6 @@ static int pop_mpls(struct sk_buff *skb, struct sw_flow_key *key, return 0; } -/* 'KEY' must not have any bits set outside of the 'MASK' */ -#define MASKED(OLD, KEY, MASK) ((KEY) | ((OLD) & ~(MASK))) -#define SET_MASKED(OLD, KEY, MASK) ((OLD) = MASKED(OLD, KEY, MASK)) - static int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key, const __be32 *mpls_lse, const __be32 *mask) { @@ -201,7 +197,7 @@ static int set_mpls(struct sk_buff *skb, struct sw_flow_key *flow_key, return err; stack = (__be32 *)skb_mpls_header(skb); - lse = MASKED(*stack, *mpls_lse, *mask); + lse = OVS_MASKED(*stack, *mpls_lse, *mask); if (skb->ip_summed == CHECKSUM_COMPLETE) { __be32 diff[] = { ~(*stack), lse }; @@ -244,9 +240,9 @@ static void ether_addr_copy_masked(u8 *dst_, const u8 *src_, const u8 *mask_) const u16 *src = (const u16 *)src_; const u16 *mask = (const u16 *)mask_; - SET_MASKED(dst[0], src[0], mask[0]); - SET_MASKED(dst[1], src[1], mask[1]); - SET_MASKED(dst[2], src[2], mask[2]); + OVS_SET_MASKED(dst[0], src[0], mask[0]); + OVS_SET_MASKED(dst[1], src[1], mask[1]); + OVS_SET_MASKED(dst[2], src[2], mask[2]); } static int set_eth_addr(struct sk_buff *skb, struct sw_flow_key *flow_key, @@ -338,10 +334,10 @@ static void update_ipv6_checksum(struct sk_buff *skb, u8 l4_proto, static void mask_ipv6_addr(const __be32 old[4], const __be32 addr[4], const __be32 mask[4], __be32 masked[4]) { - masked[0] = MASKED(old[0], addr[0], mask[0]); - masked[1] = MASKED(old[1], addr[1], mask[1]); - masked[2] = MASKED(old[2], addr[2], mask[2]); - masked[3] = MASKED(old[3], addr[3], mask[3]); + masked[0] = OVS_MASKED(old[0], addr[0], mask[0]); + masked[1] = OVS_MASKED(old[1], addr[1], mask[1]); + masked[2] = OVS_MASKED(old[2], addr[2], mask[2]); + masked[3] = OVS_MASKED(old[3], addr[3], mask[3]); } static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, @@ -358,15 +354,15 @@ static void set_ipv6_addr(struct sk_buff *skb, u8 l4_proto, static void set_ipv6_fl(struct ipv6hdr *nh, u32 fl, u32 mask) { /* Bits 21-24 are always unmasked, so this retains their values. */ - SET_MASKED(nh->flow_lbl[0], (u8)(fl >> 16), (u8)(mask >> 16)); - SET_MASKED(nh->flow_lbl[1], (u8)(fl >> 8), (u8)(mask >> 8)); - SET_MASKED(nh->flow_lbl[2], (u8)fl, (u8)mask); + OVS_SET_MASKED(nh->flow_lbl[0], (u8)(fl >> 16), (u8)(mask >> 16)); + OVS_SET_MASKED(nh->flow_lbl[1], (u8)(fl >> 8), (u8)(mask >> 8)); + OVS_SET_MASKED(nh->flow_lbl[2], (u8)fl, (u8)mask); } static void set_ip_ttl(struct sk_buff *skb, struct iphdr *nh, u8 new_ttl, u8 mask) { - new_ttl = MASKED(nh->ttl, new_ttl, mask); + new_ttl = OVS_MASKED(nh->ttl, new_ttl, mask); csum_replace2(&nh->check, htons(nh->ttl << 8), htons(new_ttl << 8)); nh->ttl = new_ttl; @@ -392,7 +388,7 @@ static int set_ipv4(struct sk_buff *skb, struct sw_flow_key *flow_key, * makes sense to check if the value actually changed. */ if (mask->ipv4_src) { - new_addr = MASKED(nh->saddr, key->ipv4_src, mask->ipv4_src); + new_addr = OVS_MASKED(nh->saddr, key->ipv4_src, mask->ipv4_src); if (unlikely(new_addr != nh->saddr)) { set_ip_addr(skb, nh, &nh->saddr, new_addr); @@ -400,7 +396,7 @@ static int set_ipv4(struct sk_buff *skb, struct sw_flow_key *flow_key, } } if (mask->ipv4_dst) { - new_addr = MASKED(nh->daddr, key->ipv4_dst, mask->ipv4_dst); + new_addr = OVS_MASKED(nh->daddr, key->ipv4_dst, mask->ipv4_dst); if (unlikely(new_addr != nh->daddr)) { set_ip_addr(skb, nh, &nh->daddr, new_addr); @@ -488,7 +484,8 @@ static int set_ipv6(struct sk_buff *skb, struct sw_flow_key *flow_key, *(__be32 *)nh & htonl(IPV6_FLOWINFO_FLOWLABEL); } if (mask->ipv6_hlimit) { - SET_MASKED(nh->hop_limit, key->ipv6_hlimit, mask->ipv6_hlimit); + OVS_SET_MASKED(nh->hop_limit, key->ipv6_hlimit, + mask->ipv6_hlimit); flow_key->ip.ttl = nh->hop_limit; } return 0; @@ -517,8 +514,8 @@ static int set_udp(struct sk_buff *skb, struct sw_flow_key *flow_key, uh = udp_hdr(skb); /* Either of the masks is non-zero, so do not bother checking them. */ - src = MASKED(uh->source, key->udp_src, mask->udp_src); - dst = MASKED(uh->dest, key->udp_dst, mask->udp_dst); + src = OVS_MASKED(uh->source, key->udp_src, mask->udp_src); + dst = OVS_MASKED(uh->dest, key->udp_dst, mask->udp_dst); if (uh->check && skb->ip_summed != CHECKSUM_PARTIAL) { if (likely(src != uh->source)) { @@ -558,12 +555,12 @@ static int set_tcp(struct sk_buff *skb, struct sw_flow_key *flow_key, return err; th = tcp_hdr(skb); - src = MASKED(th->source, key->tcp_src, mask->tcp_src); + src = OVS_MASKED(th->source, key->tcp_src, mask->tcp_src); if (likely(src != th->source)) { set_tp_port(skb, &th->source, src, &th->check); flow_key->tp.src = src; } - dst = MASKED(th->dest, key->tcp_dst, mask->tcp_dst); + dst = OVS_MASKED(th->dest, key->tcp_dst, mask->tcp_dst); if (likely(dst != th->dest)) { set_tp_port(skb, &th->dest, dst, &th->check); flow_key->tp.dst = dst; @@ -590,8 +587,8 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key, old_csum = sh->checksum; old_correct_csum = sctp_compute_cksum(skb, sctphoff); - sh->source = MASKED(sh->source, key->sctp_src, mask->sctp_src); - sh->dest = MASKED(sh->dest, key->sctp_dst, mask->sctp_dst); + sh->source = OVS_MASKED(sh->source, key->sctp_src, mask->sctp_src); + sh->dest = OVS_MASKED(sh->dest, key->sctp_dst, mask->sctp_dst); new_csum = sctp_compute_cksum(skb, sctphoff); @@ -770,12 +767,13 @@ static int execute_masked_set_action(struct sk_buff *skb, switch (nla_type(a)) { case OVS_KEY_ATTR_PRIORITY: - SET_MASKED(skb->priority, nla_get_u32(a), *get_mask(a, u32 *)); + OVS_SET_MASKED(skb->priority, nla_get_u32(a), + *get_mask(a, u32 *)); flow_key->phy.priority = skb->priority; break; case OVS_KEY_ATTR_SKB_MARK: - SET_MASKED(skb->mark, nla_get_u32(a), *get_mask(a, u32 *)); + OVS_SET_MASKED(skb->mark, nla_get_u32(a), *get_mask(a, u32 *)); flow_key->phy.skb_mark = skb->mark; break; diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 6b28c5cedb238..487a85f7d967f 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -200,6 +200,10 @@ void ovs_dp_notify_wq(struct work_struct *work); int action_fifos_init(void); void action_fifos_exit(void); +/* 'KEY' must not have any bits set outside of the 'MASK' */ +#define OVS_MASKED(OLD, KEY, MASK) ((KEY) | ((OLD) & ~(MASK))) +#define OVS_SET_MASKED(OLD, KEY, MASK) ((OLD) = OVS_MASKED(OLD, KEY, MASK)) + #define OVS_NLERR(logging_allowed, fmt, ...) \ do { \ if (logging_allowed && net_ratelimit()) \ -- GitLab From 5b490047240f7b986228de968334ddd7a341e1fe Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:46 -0700 Subject: [PATCH 5191/7006] ipv6: Export nf_ct_frag6_gather() Signed-off-by: Joe Stringer Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/ipv6/netfilter/nf_conntrack_reasm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 6d02498172c16..701cd2bae0a92 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -633,6 +633,7 @@ ret_orig: kfree_skb(clone); return skb; } +EXPORT_SYMBOL_GPL(nf_ct_frag6_gather); void nf_ct_frag6_consume_orig(struct sk_buff *skb) { -- GitLab From e79e259588a414589a016edc428ee8dd308f81ad Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:47 -0700 Subject: [PATCH 5192/7006] dst: Add __skb_dst_copy() variation This variation on skb_dst_copy() doesn't require two skbs. Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar Acked-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/dst.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index ef8f1d43a2033..4c4801645371d 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -289,13 +289,18 @@ static inline void skb_dst_drop(struct sk_buff *skb) } } -static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb) +static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst) { - nskb->_skb_refdst = oskb->_skb_refdst; + nskb->_skb_refdst = refdst; if (!(nskb->_skb_refdst & SKB_DST_NOREF)) dst_clone(skb_dst(nskb)); } +static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb) +{ + __skb_dst_copy(nskb, oskb->_skb_refdst); +} + /** * skb_dst_force - makes sure skb dst is refcounted * @skb: buffer -- GitLab From 7f8a436eaa2c3ddd8e1ff2fbca267e6275085536 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:48 -0700 Subject: [PATCH 5193/7006] openvswitch: Add conntrack action Expose the kernel connection tracker via OVS. Userspace components can make use of the CT action to populate the connection state (ct_state) field for a flow. This state can be subsequently matched. Exposed connection states are OVS_CS_F_*: - NEW (0x01) - Beginning of a new connection. - ESTABLISHED (0x02) - Part of an existing connection. - RELATED (0x04) - Related to an established connection. - INVALID (0x20) - Could not track the connection for this packet. - REPLY_DIR (0x40) - This packet is in the reply direction for the flow. - TRACKED (0x80) - This packet has been sent through conntrack. When the CT action is executed by itself, it will send the packet through the connection tracker and populate the ct_state field with one or more of the connection state flags above. The CT action will always set the TRACKED bit. When the COMMIT flag is passed to the conntrack action, this specifies that information about the connection should be stored. This allows subsequent packets for the same (or related) connections to be correlated with this connection. Sending subsequent packets for the connection through conntrack allows the connection tracker to consider the packets as ESTABLISHED, RELATED, and/or REPLY_DIR. The CT action may optionally take a zone to track the flow within. This allows connections with the same 5-tuple to be kept logically separate from connections in other zones. If the zone is specified, then the "ct_zone" match field will be subsequently populated with the zone id. IP fragments are handled by transparently assembling them as part of the CT action. The maximum received unit (MRU) size is tracked so that refragmentation can occur during output. IP frag handling contributed by Andy Zhou. Based on original design by Justin Pettit. Signed-off-by: Joe Stringer Signed-off-by: Justin Pettit Signed-off-by: Andy Zhou Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- include/uapi/linux/openvswitch.h | 40 +++ net/openvswitch/Kconfig | 11 + net/openvswitch/Makefile | 2 + net/openvswitch/actions.c | 175 +++++++++++- net/openvswitch/conntrack.c | 454 +++++++++++++++++++++++++++++++ net/openvswitch/conntrack.h | 78 ++++++ net/openvswitch/datapath.c | 66 +++-- net/openvswitch/datapath.h | 6 + net/openvswitch/flow.c | 2 + net/openvswitch/flow.h | 6 + net/openvswitch/flow_netlink.c | 69 ++++- net/openvswitch/flow_netlink.h | 4 +- net/openvswitch/vport.c | 1 + 13 files changed, 877 insertions(+), 37 deletions(-) create mode 100644 net/openvswitch/conntrack.c create mode 100644 net/openvswitch/conntrack.h diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index d6b8854601872..55f5997926737 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -164,6 +164,9 @@ enum ovs_packet_cmd { * %OVS_USERSPACE_ATTR_EGRESS_TUN_PORT attribute, which is sent only if the * output port is actually a tunnel port. Contains the output tunnel key * extracted from the packet as nested %OVS_TUNNEL_KEY_ATTR_* attributes. + * @OVS_PACKET_ATTR_MRU: Present for an %OVS_PACKET_CMD_ACTION and + * %OVS_PACKET_ATTR_USERSPACE action specify the Maximum received fragment + * size. * * These attributes follow the &struct ovs_header within the Generic Netlink * payload for %OVS_PACKET_* commands. @@ -180,6 +183,7 @@ enum ovs_packet_attr { OVS_PACKET_ATTR_UNUSED2, OVS_PACKET_ATTR_PROBE, /* Packet operation is a feature probe, error logging should be suppressed. */ + OVS_PACKET_ATTR_MRU, /* Maximum received IP fragment size. */ __OVS_PACKET_ATTR_MAX }; @@ -319,6 +323,8 @@ enum ovs_key_attr { OVS_KEY_ATTR_MPLS, /* array of struct ovs_key_mpls. * The implementation may restrict * the accepted length of the array. */ + OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */ + OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */ #ifdef __KERNEL__ OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ @@ -431,6 +437,15 @@ struct ovs_key_nd { __u8 nd_tll[ETH_ALEN]; }; +/* OVS_KEY_ATTR_CT_STATE flags */ +#define OVS_CS_F_NEW 0x01 /* Beginning of a new connection. */ +#define OVS_CS_F_ESTABLISHED 0x02 /* Part of an existing connection. */ +#define OVS_CS_F_RELATED 0x04 /* Related to an established + * connection. */ +#define OVS_CS_F_INVALID 0x20 /* Could not track connection. */ +#define OVS_CS_F_REPLY_DIR 0x40 /* Flow is in the reply direction. */ +#define OVS_CS_F_TRACKED 0x80 /* Conntrack has occurred. */ + /** * enum ovs_flow_attr - attributes for %OVS_FLOW_* commands. * @OVS_FLOW_ATTR_KEY: Nested %OVS_KEY_ATTR_* attributes specifying the flow @@ -594,6 +609,28 @@ struct ovs_action_hash { uint32_t hash_basis; }; +/** + * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action. + * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags. + * @OVS_CT_ATTR_ZONE: u16 connection tracking zone. + */ +enum ovs_ct_attr { + OVS_CT_ATTR_UNSPEC, + OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */ + OVS_CT_ATTR_ZONE, /* u16 zone id. */ + __OVS_CT_ATTR_MAX +}; + +#define OVS_CT_ATTR_MAX (__OVS_CT_ATTR_MAX - 1) + +/* + * OVS_CT_ATTR_FLAGS flags - bitmask of %OVS_CT_F_* + * @OVS_CT_F_COMMIT: Commits the flow to the conntrack table. This allows + * future packets for the same connection to be identified as 'established' + * or 'related'. + */ +#define OVS_CT_F_COMMIT 0x01 + /** * enum ovs_action_attr - Action types. * @@ -623,6 +660,8 @@ struct ovs_action_hash { * indicate the new packet contents. This could potentially still be * %ETH_P_MPLS if the resulting MPLS label stack is not empty. If there * is no MPLS label stack, as determined by ethertype, no action is taken. + * @OVS_ACTION_ATTR_CT: Track the connection. Populate the conntrack-related + * entries in the flow key. * * Only a single header can be set with a single %OVS_ACTION_ATTR_SET. Not all * fields within a header are modifiable, e.g. the IPv4 protocol and fragment @@ -648,6 +687,7 @@ enum ovs_action_attr { * data immediately followed by a mask. * The data must be zero for the unmasked * bits. */ + OVS_ACTION_ATTR_CT, /* One nested OVS_CT_ATTR_* . */ __OVS_ACTION_ATTR_MAX, /* Nothing past this will be accepted * from userspace. */ diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 422dc0567de9d..98f343d0d6dd6 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig @@ -31,6 +31,17 @@ config OPENVSWITCH If unsure, say N. +config OPENVSWITCH_CONNTRACK + bool "Open vSwitch conntrack action support" + depends on OPENVSWITCH + depends on NF_CONNTRACK + default OPENVSWITCH + ---help--- + If you say Y here, then Open vSwitch module will be able to pass + packets through conntrack. + + Say N to exclude this support and reduce the binary size. + config OPENVSWITCH_GRE tristate "Open vSwitch GRE tunneling support" depends on OPENVSWITCH diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 6e1701de04d80..5b5913b06f540 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile @@ -15,6 +15,8 @@ openvswitch-y := \ vport-internal_dev.o \ vport-netdev.o +openvswitch-$(CONFIG_OPENVSWITCH_CONNTRACK) += conntrack.o + obj-$(CONFIG_OPENVSWITCH_VXLAN)+= vport-vxlan.o obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o obj-$(CONFIG_OPENVSWITCH_GRE) += vport-gre.o diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 520438b77dc8c..72ca2c491b0aa 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include +#include #include #include #include @@ -38,6 +40,7 @@ #include "datapath.h" #include "flow.h" +#include "conntrack.h" #include "vport.h" static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, @@ -52,6 +55,20 @@ struct deferred_action { struct sw_flow_key pkt_key; }; +#define MAX_L2_LEN (VLAN_ETH_HLEN + 3 * MPLS_HLEN) +struct ovs_frag_data { + unsigned long dst; + struct vport *vport; + struct ovs_skb_cb cb; + __be16 inner_protocol; + __u16 vlan_tci; + __be16 vlan_proto; + unsigned int l2_len; + u8 l2_data[MAX_L2_LEN]; +}; + +static DEFINE_PER_CPU(struct ovs_frag_data, ovs_frag_data_storage); + #define DEFERRED_ACTION_FIFO_SIZE 10 struct action_fifo { int head; @@ -602,14 +619,145 @@ static int set_sctp(struct sk_buff *skb, struct sw_flow_key *flow_key, return 0; } -static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port) +static int ovs_vport_output(struct sock *sock, struct sk_buff *skb) +{ + struct ovs_frag_data *data = this_cpu_ptr(&ovs_frag_data_storage); + struct vport *vport = data->vport; + + if (skb_cow_head(skb, data->l2_len) < 0) { + kfree_skb(skb); + return -ENOMEM; + } + + __skb_dst_copy(skb, data->dst); + *OVS_CB(skb) = data->cb; + skb->inner_protocol = data->inner_protocol; + skb->vlan_tci = data->vlan_tci; + skb->vlan_proto = data->vlan_proto; + + /* Reconstruct the MAC header. */ + skb_push(skb, data->l2_len); + memcpy(skb->data, &data->l2_data, data->l2_len); + ovs_skb_postpush_rcsum(skb, skb->data, data->l2_len); + skb_reset_mac_header(skb); + + ovs_vport_send(vport, skb); + return 0; +} + +static unsigned int +ovs_dst_get_mtu(const struct dst_entry *dst) +{ + return dst->dev->mtu; +} + +static struct dst_ops ovs_dst_ops = { + .family = AF_UNSPEC, + .mtu = ovs_dst_get_mtu, +}; + +/* prepare_frag() is called once per (larger-than-MTU) frame; its inverse is + * ovs_vport_output(), which is called once per fragmented packet. + */ +static void prepare_frag(struct vport *vport, struct sk_buff *skb) +{ + unsigned int hlen = skb_network_offset(skb); + struct ovs_frag_data *data; + + data = this_cpu_ptr(&ovs_frag_data_storage); + data->dst = skb->_skb_refdst; + data->vport = vport; + data->cb = *OVS_CB(skb); + data->inner_protocol = skb->inner_protocol; + data->vlan_tci = skb->vlan_tci; + data->vlan_proto = skb->vlan_proto; + data->l2_len = hlen; + memcpy(&data->l2_data, skb->data, hlen); + + memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); + skb_pull(skb, hlen); +} + +static void ovs_fragment(struct vport *vport, struct sk_buff *skb, u16 mru, + __be16 ethertype) +{ + if (skb_network_offset(skb) > MAX_L2_LEN) { + OVS_NLERR(1, "L2 header too long to fragment"); + return; + } + + if (ethertype == htons(ETH_P_IP)) { + struct dst_entry ovs_dst; + unsigned long orig_dst; + + prepare_frag(vport, skb); + dst_init(&ovs_dst, &ovs_dst_ops, NULL, 1, + DST_OBSOLETE_NONE, DST_NOCOUNT); + ovs_dst.dev = vport->dev; + + orig_dst = skb->_skb_refdst; + skb_dst_set_noref(skb, &ovs_dst); + IPCB(skb)->frag_max_size = mru; + + ip_do_fragment(skb->sk, skb, ovs_vport_output); + refdst_drop(orig_dst); + } else if (ethertype == htons(ETH_P_IPV6)) { + const struct nf_ipv6_ops *v6ops = nf_get_ipv6_ops(); + unsigned long orig_dst; + struct rt6_info ovs_rt; + + if (!v6ops) { + kfree_skb(skb); + return; + } + + prepare_frag(vport, skb); + memset(&ovs_rt, 0, sizeof(ovs_rt)); + dst_init(&ovs_rt.dst, &ovs_dst_ops, NULL, 1, + DST_OBSOLETE_NONE, DST_NOCOUNT); + ovs_rt.dst.dev = vport->dev; + + orig_dst = skb->_skb_refdst; + skb_dst_set_noref(skb, &ovs_rt.dst); + IP6CB(skb)->frag_max_size = mru; + + v6ops->fragment(skb->sk, skb, ovs_vport_output); + refdst_drop(orig_dst); + } else { + WARN_ONCE(1, "Failed fragment ->%s: eth=%04x, MRU=%d, MTU=%d.", + ovs_vport_name(vport), ntohs(ethertype), mru, + vport->dev->mtu); + kfree_skb(skb); + } +} + +static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port, + struct sw_flow_key *key) { struct vport *vport = ovs_vport_rcu(dp, out_port); - if (likely(vport)) - ovs_vport_send(vport, skb); - else + if (likely(vport)) { + u16 mru = OVS_CB(skb)->mru; + + if (likely(!mru || (skb->len <= mru + ETH_HLEN))) { + ovs_vport_send(vport, skb); + } else if (mru <= vport->dev->mtu) { + __be16 ethertype = key->eth.type; + + if (!is_flow_key_valid(key)) { + if (eth_p_mpls(skb->protocol)) + ethertype = skb->inner_protocol; + else + ethertype = vlan_get_protocol(skb); + } + + ovs_fragment(vport, skb, mru, ethertype); + } else { + kfree_skb(skb); + } + } else { kfree_skb(skb); + } } static int output_userspace(struct datapath *dp, struct sk_buff *skb, @@ -623,6 +771,7 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, memset(&upcall, 0, sizeof(upcall)); upcall.cmd = OVS_PACKET_CMD_ACTION; + upcall.mru = OVS_CB(skb)->mru; for (a = nla_data(attr), rem = nla_len(attr); rem > 0; a = nla_next(a, &rem)) { @@ -816,6 +965,11 @@ static int execute_masked_set_action(struct sk_buff *skb, err = set_mpls(skb, flow_key, nla_data(a), get_mask(a, __be32 *)); break; + + case OVS_KEY_ATTR_CT_STATE: + case OVS_KEY_ATTR_CT_ZONE: + err = -EINVAL; + break; } return err; @@ -885,7 +1039,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, struct sk_buff *out_skb = skb_clone(skb, GFP_ATOMIC); if (out_skb) - do_output(dp, out_skb, prev_port); + do_output(dp, out_skb, prev_port, key); prev_port = -1; } @@ -942,6 +1096,15 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, case OVS_ACTION_ATTR_SAMPLE: err = sample(dp, skb, key, a, attr, len); break; + + case OVS_ACTION_ATTR_CT: + err = ovs_ct_execute(ovs_dp_get_net(dp), skb, key, + nla_data(a)); + + /* Hide stolen IP fragments from user space. */ + if (err == -EINPROGRESS) + return 0; + break; } if (unlikely(err)) { @@ -951,7 +1114,7 @@ static int do_execute_actions(struct datapath *dp, struct sk_buff *skb, } if (prev_port != -1) - do_output(dp, skb, prev_port); + do_output(dp, skb, prev_port, key); else consume_skb(skb); diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c new file mode 100644 index 0000000000000..1189fd50f1cf1 --- /dev/null +++ b/net/openvswitch/conntrack.c @@ -0,0 +1,454 @@ +/* + * Copyright (c) 2015 Nicira, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "datapath.h" +#include "conntrack.h" +#include "flow.h" +#include "flow_netlink.h" + +struct ovs_ct_len_tbl { + size_t maxlen; + size_t minlen; +}; + +/* Conntrack action context for execution. */ +struct ovs_conntrack_info { + struct nf_conntrack_zone zone; + struct nf_conn *ct; + u32 flags; + u16 family; +}; + +static u16 key_to_nfproto(const struct sw_flow_key *key) +{ + switch (ntohs(key->eth.type)) { + case ETH_P_IP: + return NFPROTO_IPV4; + case ETH_P_IPV6: + return NFPROTO_IPV6; + default: + return NFPROTO_UNSPEC; + } +} + +/* Map SKB connection state into the values used by flow definition. */ +static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo) +{ + u8 ct_state = OVS_CS_F_TRACKED; + + switch (ctinfo) { + case IP_CT_ESTABLISHED_REPLY: + case IP_CT_RELATED_REPLY: + case IP_CT_NEW_REPLY: + ct_state |= OVS_CS_F_REPLY_DIR; + break; + default: + break; + } + + switch (ctinfo) { + case IP_CT_ESTABLISHED: + case IP_CT_ESTABLISHED_REPLY: + ct_state |= OVS_CS_F_ESTABLISHED; + break; + case IP_CT_RELATED: + case IP_CT_RELATED_REPLY: + ct_state |= OVS_CS_F_RELATED; + break; + case IP_CT_NEW: + case IP_CT_NEW_REPLY: + ct_state |= OVS_CS_F_NEW; + break; + default: + break; + } + + return ct_state; +} + +static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, + const struct nf_conntrack_zone *zone) +{ + key->ct.state = state; + key->ct.zone = zone->id; +} + +/* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has + * previously sent the packet to conntrack via the ct action. + */ +static void ovs_ct_update_key(const struct sk_buff *skb, + struct sw_flow_key *key, bool post_ct) +{ + const struct nf_conntrack_zone *zone = &nf_ct_zone_dflt; + enum ip_conntrack_info ctinfo; + struct nf_conn *ct; + u8 state = 0; + + ct = nf_ct_get(skb, &ctinfo); + if (ct) { + state = ovs_ct_get_state(ctinfo); + if (ct->master) + state |= OVS_CS_F_RELATED; + zone = nf_ct_zone(ct); + } else if (post_ct) { + state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID; + } + __ovs_ct_update_key(key, state, zone); +} + +void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key) +{ + ovs_ct_update_key(skb, key, false); +} + +int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) +{ + if (nla_put_u8(skb, OVS_KEY_ATTR_CT_STATE, key->ct.state)) + return -EMSGSIZE; + + if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && + nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone)) + return -EMSGSIZE; + + return 0; +} + +static int handle_fragments(struct net *net, struct sw_flow_key *key, + u16 zone, struct sk_buff *skb) +{ + struct ovs_skb_cb ovs_cb = *OVS_CB(skb); + + if (key->eth.type == htons(ETH_P_IP)) { + enum ip_defrag_users user = IP_DEFRAG_CONNTRACK_IN + zone; + int err; + + memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); + err = ip_defrag(skb, user); + if (err) + return err; + + ovs_cb.mru = IPCB(skb)->frag_max_size; + } else if (key->eth.type == htons(ETH_P_IPV6)) { +#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) + enum ip6_defrag_users user = IP6_DEFRAG_CONNTRACK_IN + zone; + struct sk_buff *reasm; + + memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); + reasm = nf_ct_frag6_gather(skb, user); + if (!reasm) + return -EINPROGRESS; + + if (skb == reasm) + return -EINVAL; + + key->ip.proto = ipv6_hdr(reasm)->nexthdr; + skb_morph(skb, reasm); + consume_skb(reasm); + ovs_cb.mru = IP6CB(skb)->frag_max_size; +#else + return -EPFNOSUPPORT; +#endif + } else { + return -EPFNOSUPPORT; + } + + key->ip.frag = OVS_FRAG_TYPE_NONE; + skb_clear_hash(skb); + skb->ignore_df = 1; + *OVS_CB(skb) = ovs_cb; + + return 0; +} + +static struct nf_conntrack_expect * +ovs_ct_expect_find(struct net *net, const struct nf_conntrack_zone *zone, + u16 proto, const struct sk_buff *skb) +{ + struct nf_conntrack_tuple tuple; + + if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb), proto, &tuple)) + return NULL; + return __nf_ct_expect_find(net, zone, &tuple); +} + +/* Determine whether skb->nfct is equal to the result of conntrack lookup. */ +static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb, + const struct ovs_conntrack_info *info) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return false; + if (!net_eq(net, read_pnet(&ct->ct_net))) + return false; + if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct))) + return false; + + return true; +} + +static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, + const struct ovs_conntrack_info *info, + struct sk_buff *skb) +{ + /* If we are recirculating packets to match on conntrack fields and + * committing with a separate conntrack action, then we don't need to + * actually run the packet through conntrack twice unless it's for a + * different zone. + */ + if (!skb_nfct_cached(net, skb, info)) { + struct nf_conn *tmpl = info->ct; + + /* Associate skb with specified zone. */ + if (tmpl) { + if (skb->nfct) + nf_conntrack_put(skb->nfct); + nf_conntrack_get(&tmpl->ct_general); + skb->nfct = &tmpl->ct_general; + skb->nfctinfo = IP_CT_NEW; + } + + if (nf_conntrack_in(net, info->family, NF_INET_PRE_ROUTING, + skb) != NF_ACCEPT) + return -ENOENT; + } + + return 0; +} + +/* Lookup connection and read fields into key. */ +static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, + const struct ovs_conntrack_info *info, + struct sk_buff *skb) +{ + struct nf_conntrack_expect *exp; + + exp = ovs_ct_expect_find(net, &info->zone, info->family, skb); + if (exp) { + u8 state; + + state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; + __ovs_ct_update_key(key, state, &info->zone); + } else { + int err; + + err = __ovs_ct_lookup(net, key, info, skb); + if (err) + return err; + + ovs_ct_update_key(skb, key, true); + } + + return 0; +} + +/* Lookup connection and confirm if unconfirmed. */ +static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, + const struct ovs_conntrack_info *info, + struct sk_buff *skb) +{ + u8 state; + int err; + + state = key->ct.state; + if (key->ct.zone == info->zone.id && + ((state & OVS_CS_F_TRACKED) && !(state & OVS_CS_F_NEW))) { + /* Previous lookup has shown that this connection is already + * tracked and committed. Skip committing. + */ + return 0; + } + + err = __ovs_ct_lookup(net, key, info, skb); + if (err) + return err; + if (nf_conntrack_confirm(skb) != NF_ACCEPT) + return -EINVAL; + + ovs_ct_update_key(skb, key, true); + + return 0; +} + +int ovs_ct_execute(struct net *net, struct sk_buff *skb, + struct sw_flow_key *key, + const struct ovs_conntrack_info *info) +{ + int nh_ofs; + int err; + + /* The conntrack module expects to be working at L3. */ + nh_ofs = skb_network_offset(skb); + skb_pull(skb, nh_ofs); + + if (key->ip.frag != OVS_FRAG_TYPE_NONE) { + err = handle_fragments(net, key, info->zone.id, skb); + if (err) + return err; + } + + if (info->flags & OVS_CT_F_COMMIT) + err = ovs_ct_commit(net, key, info, skb); + else + err = ovs_ct_lookup(net, key, info, skb); + + skb_push(skb, nh_ofs); + return err; +} + +static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { + [OVS_CT_ATTR_FLAGS] = { .minlen = sizeof(u32), + .maxlen = sizeof(u32) }, + [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), + .maxlen = sizeof(u16) }, +}; + +static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, + bool log) +{ + struct nlattr *a; + int rem; + + nla_for_each_nested(a, attr, rem) { + int type = nla_type(a); + int maxlen = ovs_ct_attr_lens[type].maxlen; + int minlen = ovs_ct_attr_lens[type].minlen; + + if (type > OVS_CT_ATTR_MAX) { + OVS_NLERR(log, + "Unknown conntrack attr (type=%d, max=%d)", + type, OVS_CT_ATTR_MAX); + return -EINVAL; + } + if (nla_len(a) < minlen || nla_len(a) > maxlen) { + OVS_NLERR(log, + "Conntrack attr type has unexpected length (type=%d, length=%d, expected=%d)", + type, nla_len(a), maxlen); + return -EINVAL; + } + + switch (type) { + case OVS_CT_ATTR_FLAGS: + info->flags = nla_get_u32(a); + break; +#ifdef CONFIG_NF_CONNTRACK_ZONES + case OVS_CT_ATTR_ZONE: + info->zone.id = nla_get_u16(a); + break; +#endif + default: + OVS_NLERR(log, "Unknown conntrack attr (%d)", + type); + return -EINVAL; + } + } + + if (rem > 0) { + OVS_NLERR(log, "Conntrack attr has %d unknown bytes", rem); + return -EINVAL; + } + + return 0; +} + +bool ovs_ct_verify(enum ovs_key_attr attr) +{ + if (attr == OVS_KEY_ATTR_CT_STATE) + return true; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && + attr == OVS_KEY_ATTR_CT_ZONE) + return true; + + return false; +} + +int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, + const struct sw_flow_key *key, + struct sw_flow_actions **sfa, bool log) +{ + struct ovs_conntrack_info ct_info; + u16 family; + int err; + + family = key_to_nfproto(key); + if (family == NFPROTO_UNSPEC) { + OVS_NLERR(log, "ct family unspecified"); + return -EINVAL; + } + + memset(&ct_info, 0, sizeof(ct_info)); + ct_info.family = family; + + nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID, + NF_CT_DEFAULT_ZONE_DIR, 0); + + err = parse_ct(attr, &ct_info, log); + if (err) + return err; + + /* Set up template for tracking connections in specific zones. */ + ct_info.ct = nf_ct_tmpl_alloc(net, &ct_info.zone, GFP_KERNEL); + if (!ct_info.ct) { + OVS_NLERR(log, "Failed to allocate conntrack template"); + return -ENOMEM; + } + + err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info, + sizeof(ct_info), log); + if (err) + goto err_free_ct; + + __set_bit(IPS_CONFIRMED_BIT, &ct_info.ct->status); + nf_conntrack_get(&ct_info.ct->ct_general); + return 0; +err_free_ct: + nf_conntrack_free(ct_info.ct); + return err; +} + +int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, + struct sk_buff *skb) +{ + struct nlattr *start; + + start = nla_nest_start(skb, OVS_ACTION_ATTR_CT); + if (!start) + return -EMSGSIZE; + + if (nla_put_u32(skb, OVS_CT_ATTR_FLAGS, ct_info->flags)) + return -EMSGSIZE; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && + nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) + return -EMSGSIZE; + + nla_nest_end(skb, start); + + return 0; +} + +void ovs_ct_free_action(const struct nlattr *a) +{ + struct ovs_conntrack_info *ct_info = nla_data(a); + + if (ct_info->ct) + nf_ct_put(ct_info->ct); +} diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h new file mode 100644 index 0000000000000..e812ee64a718c --- /dev/null +++ b/net/openvswitch/conntrack.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2015 Nicira, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ + +#ifndef OVS_CONNTRACK_H +#define OVS_CONNTRACK_H 1 + +#include "flow.h" + +struct ovs_conntrack_info; +enum ovs_key_attr; + +#if defined(CONFIG_OPENVSWITCH_CONNTRACK) +bool ovs_ct_verify(enum ovs_key_attr attr); +int ovs_ct_copy_action(struct net *, const struct nlattr *, + const struct sw_flow_key *, struct sw_flow_actions **, + bool log); +int ovs_ct_action_to_attr(const struct ovs_conntrack_info *, struct sk_buff *); + +int ovs_ct_execute(struct net *, struct sk_buff *, struct sw_flow_key *, + const struct ovs_conntrack_info *); + +void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key); +int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb); +void ovs_ct_free_action(const struct nlattr *a); +#else +#include + +static inline bool ovs_ct_verify(int attr) +{ + return false; +} + +static inline int ovs_ct_copy_action(struct net *net, const struct nlattr *nla, + const struct sw_flow_key *key, + struct sw_flow_actions **acts, bool log) +{ + return -ENOTSUPP; +} + +static inline int ovs_ct_action_to_attr(const struct ovs_conntrack_info *info, + struct sk_buff *skb) +{ + return -ENOTSUPP; +} + +static inline int ovs_ct_execute(struct net *net, struct sk_buff *skb, + struct sw_flow_key *key, + const struct ovs_conntrack_info *info) +{ + return -ENOTSUPP; +} + +static inline void ovs_ct_fill_key(const struct sk_buff *skb, + struct sw_flow_key *key) +{ + key->ct.state = 0; + key->ct.zone = 0; +} + +static inline int ovs_ct_put_key(const struct sw_flow_key *key, + struct sk_buff *skb) +{ + return 0; +} + +static inline void ovs_ct_free_action(const struct nlattr *a) { } +#endif +#endif /* ovs_conntrack.h */ diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index d5b5473758878..72e63726efa0d 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -275,6 +275,7 @@ void ovs_dp_process_packet(struct sk_buff *skb, struct sw_flow_key *key) memset(&upcall, 0, sizeof(upcall)); upcall.cmd = OVS_PACKET_CMD_MISS; upcall.portid = ovs_vport_find_upcall_portid(p, skb); + upcall.mru = OVS_CB(skb)->mru; error = ovs_dp_upcall(dp, skb, key, &upcall); if (unlikely(error)) kfree_skb(skb); @@ -400,9 +401,23 @@ static size_t upcall_msg_size(const struct dp_upcall_info *upcall_info, if (upcall_info->actions_len) size += nla_total_size(upcall_info->actions_len); + /* OVS_PACKET_ATTR_MRU */ + if (upcall_info->mru) + size += nla_total_size(sizeof(upcall_info->mru)); + return size; } +static void pad_packet(struct datapath *dp, struct sk_buff *skb) +{ + if (!(dp->user_features & OVS_DP_F_UNALIGNED)) { + size_t plen = NLA_ALIGN(skb->len) - skb->len; + + if (plen > 0) + memset(skb_put(skb, plen), 0, plen); + } +} + static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, const struct sw_flow_key *key, const struct dp_upcall_info *upcall_info) @@ -492,6 +507,16 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, nla_nest_cancel(user_skb, nla); } + /* Add OVS_PACKET_ATTR_MRU */ + if (upcall_info->mru) { + if (nla_put_u16(user_skb, OVS_PACKET_ATTR_MRU, + upcall_info->mru)) { + err = -ENOBUFS; + goto out; + } + pad_packet(dp, user_skb); + } + /* Only reserve room for attribute header, packet data is added * in skb_zerocopy() */ if (!(nla = nla_reserve(user_skb, OVS_PACKET_ATTR_PACKET, 0))) { @@ -505,12 +530,7 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, goto out; /* Pad OVS_PACKET_ATTR_PACKET if linear copy was performed */ - if (!(dp->user_features & OVS_DP_F_UNALIGNED)) { - size_t plen = NLA_ALIGN(user_skb->len) - user_skb->len; - - if (plen > 0) - memset(skb_put(user_skb, plen), 0, plen); - } + pad_packet(dp, user_skb); ((struct nlmsghdr *) user_skb->data)->nlmsg_len = user_skb->len; @@ -527,6 +547,7 @@ out: static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) { struct ovs_header *ovs_header = info->userhdr; + struct net *net = sock_net(skb->sk); struct nlattr **a = info->attrs; struct sw_flow_actions *acts; struct sk_buff *packet; @@ -535,6 +556,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) struct datapath *dp; struct ethhdr *eth; struct vport *input_vport; + u16 mru = 0; int len; int err; bool log = !a[OVS_PACKET_ATTR_PROBE]; @@ -564,6 +586,13 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) else packet->protocol = htons(ETH_P_802_2); + /* Set packet's mru */ + if (a[OVS_PACKET_ATTR_MRU]) { + mru = nla_get_u16(a[OVS_PACKET_ATTR_MRU]); + packet->ignore_df = 1; + } + OVS_CB(packet)->mru = mru; + /* Build an sw_flow for sending this packet. */ flow = ovs_flow_alloc(); err = PTR_ERR(flow); @@ -575,7 +604,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) if (err) goto err_flow_free; - err = ovs_nla_copy_actions(a[OVS_PACKET_ATTR_ACTIONS], + err = ovs_nla_copy_actions(net, a[OVS_PACKET_ATTR_ACTIONS], &flow->key, &acts, log); if (err) goto err_flow_free; @@ -586,7 +615,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) packet->mark = flow->key.phy.skb_mark; rcu_read_lock(); - dp = get_dp_rcu(sock_net(skb->sk), ovs_header->dp_ifindex); + dp = get_dp_rcu(net, ovs_header->dp_ifindex); err = -ENODEV; if (!dp) goto err_unlock; @@ -598,6 +627,7 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) if (!input_vport) goto err_unlock; + packet->dev = input_vport->dev; OVS_CB(packet)->input_vport = input_vport; sf_acts = rcu_dereference(flow->sf_acts); @@ -624,6 +654,7 @@ static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG }, + [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 }, }; static const struct genl_ops dp_packet_genl_ops[] = { @@ -880,6 +911,7 @@ static struct sk_buff *ovs_flow_cmd_build_info(const struct sw_flow *flow, static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) { + struct net *net = sock_net(skb->sk); struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; struct sw_flow *flow = NULL, *new_flow; @@ -929,8 +961,8 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) goto err_kfree_flow; /* Validate actions. */ - error = ovs_nla_copy_actions(a[OVS_FLOW_ATTR_ACTIONS], &new_flow->key, - &acts, log); + error = ovs_nla_copy_actions(net, a[OVS_FLOW_ATTR_ACTIONS], + &new_flow->key, &acts, log); if (error) { OVS_NLERR(log, "Flow actions may not be safe on all matching packets."); goto err_kfree_flow; @@ -944,7 +976,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) } ovs_lock(); - dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); + dp = get_dp(net, ovs_header->dp_ifindex); if (unlikely(!dp)) { error = -ENODEV; goto err_unlock_ovs; @@ -1038,7 +1070,8 @@ error: } /* Factor out action copy to avoid "Wframe-larger-than=1024" warning. */ -static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, +static struct sw_flow_actions *get_flow_actions(struct net *net, + const struct nlattr *a, const struct sw_flow_key *key, const struct sw_flow_mask *mask, bool log) @@ -1048,7 +1081,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, int error; ovs_flow_mask_key(&masked_key, key, mask); - error = ovs_nla_copy_actions(a, &masked_key, &acts, log); + error = ovs_nla_copy_actions(net, a, &masked_key, &acts, log); if (error) { OVS_NLERR(log, "Actions may not be safe on all matching packets"); @@ -1060,6 +1093,7 @@ static struct sw_flow_actions *get_flow_actions(const struct nlattr *a, static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) { + struct net *net = sock_net(skb->sk); struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; struct sw_flow_key key; @@ -1091,8 +1125,8 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) /* Validate actions. */ if (a[OVS_FLOW_ATTR_ACTIONS]) { - acts = get_flow_actions(a[OVS_FLOW_ATTR_ACTIONS], &key, &mask, - log); + acts = get_flow_actions(net, a[OVS_FLOW_ATTR_ACTIONS], &key, + &mask, log); if (IS_ERR(acts)) { error = PTR_ERR(acts); goto error; @@ -1108,7 +1142,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) } ovs_lock(); - dp = get_dp(sock_net(skb->sk), ovs_header->dp_ifindex); + dp = get_dp(net, ovs_header->dp_ifindex); if (unlikely(!dp)) { error = -ENODEV; goto err_unlock_ovs; diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 487a85f7d967f..d24ba98024bec 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -27,6 +27,7 @@ #include #include +#include "conntrack.h" #include "flow.h" #include "flow_table.h" #include "vport.h" @@ -97,10 +98,13 @@ struct datapath { * NULL if the packet is not being tunneled. * @input_vport: The original vport packet came in on. This value is cached * when a packet is received by OVS. + * @mru: The maximum received fragement size; 0 if the packet is not + * fragmented. */ struct ovs_skb_cb { struct ip_tunnel_info *egress_tun_info; struct vport *input_vport; + u16 mru; }; #define OVS_CB(skb) ((struct ovs_skb_cb *)(skb)->cb) @@ -113,6 +117,7 @@ struct ovs_skb_cb { * then no packet is sent and the packet is accounted in the datapath's @n_lost * counter. * @egress_tun_info: If nonnull, becomes %OVS_PACKET_ATTR_EGRESS_TUN_KEY. + * @mru: If not zero, Maximum received IP fragment size. */ struct dp_upcall_info { const struct ip_tunnel_info *egress_tun_info; @@ -121,6 +126,7 @@ struct dp_upcall_info { int actions_len; u32 portid; u8 cmd; + u16 mru; }; /** diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 8db22ef73626c..376ca8738fd43 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -49,6 +49,7 @@ #include "datapath.h" #include "flow.h" #include "flow_netlink.h" +#include "conntrack.h" u64 ovs_flow_used_time(unsigned long flow_jiffies) { @@ -707,6 +708,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, key->phy.priority = skb->priority; key->phy.in_port = OVS_CB(skb)->input_vport->port_no; key->phy.skb_mark = skb->mark; + ovs_ct_fill_key(skb, key); key->ovs_flow_hash = 0; key->recirc_id = 0; diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 082a87bac8196..312c7d755b9b2 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -111,6 +111,12 @@ struct sw_flow_key { } nd; } ipv6; }; + struct { + /* Connection tracking fields. */ + u16 zone; + u8 state; + } ct; + } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */ struct sw_flow_key_range { diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index c182b28c0884a..4e795b289eb76 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void) /* Whenever adding new OVS_KEY_ FIELDS, we should consider * updating this function. */ - BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 22); + BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24); return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ @@ -290,6 +290,8 @@ size_t ovs_key_attr_size(void) + nla_total_size(4) /* OVS_KEY_ATTR_SKB_MARK */ + nla_total_size(4) /* OVS_KEY_ATTR_DP_HASH */ + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ + + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */ + + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ @@ -339,6 +341,8 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_TUNNEL] = { .len = OVS_ATTR_NESTED, .next = ovs_tunnel_key_lens, }, [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, + [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) }, + [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, }; static bool is_all_zero(const u8 *fp, size_t size) @@ -768,6 +772,21 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, return -EINVAL; *attrs &= ~(1 << OVS_KEY_ATTR_TUNNEL); } + + if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) && + ovs_ct_verify(OVS_KEY_ATTR_CT_STATE)) { + u8 ct_state = nla_get_u8(a[OVS_KEY_ATTR_CT_STATE]); + + SW_FLOW_KEY_PUT(match, ct.state, ct_state, is_mask); + *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE); + } + if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) && + ovs_ct_verify(OVS_KEY_ATTR_CT_ZONE)) { + u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]); + + SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask); + *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE); + } return 0; } @@ -1266,6 +1285,7 @@ int ovs_nla_get_flow_metadata(const struct nlattr *attr, memset(&match, 0, sizeof(match)); match.key = key; + memset(&key->ct, 0, sizeof(key->ct)); key->phy.in_port = DP_MAX_PORTS; return metadata_from_nlattrs(&match, &attrs, a, false, log); @@ -1314,6 +1334,9 @@ static int __ovs_nla_put_key(const struct sw_flow_key *swkey, if (nla_put_u32(skb, OVS_KEY_ATTR_SKB_MARK, output->phy.skb_mark)) goto nla_put_failure; + if (ovs_ct_put_key(output, skb)) + goto nla_put_failure; + nla = nla_reserve(skb, OVS_KEY_ATTR_ETHERNET, sizeof(*eth_key)); if (!nla) goto nla_put_failure; @@ -1574,6 +1597,9 @@ void ovs_nla_free_flow_actions(struct sw_flow_actions *sf_acts) case OVS_ACTION_ATTR_SET: ovs_nla_free_set_action(a); break; + case OVS_ACTION_ATTR_CT: + ovs_ct_free_action(a); + break; } } @@ -1647,8 +1673,8 @@ static struct nlattr *__add_action(struct sw_flow_actions **sfa, return a; } -static int add_action(struct sw_flow_actions **sfa, int attrtype, - void *data, int len, bool log) +int ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, void *data, + int len, bool log) { struct nlattr *a; @@ -1663,7 +1689,7 @@ static inline int add_nested_action_start(struct sw_flow_actions **sfa, int used = (*sfa)->actions_len; int err; - err = add_action(sfa, attrtype, NULL, 0, log); + err = ovs_nla_add_action(sfa, attrtype, NULL, 0, log); if (err) return err; @@ -1679,12 +1705,12 @@ static inline void add_nested_action_end(struct sw_flow_actions *sfa, a->nla_len = sfa->actions_len - st_offset; } -static int __ovs_nla_copy_actions(const struct nlattr *attr, +static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, int depth, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, bool log); -static int validate_and_copy_sample(const struct nlattr *attr, +static int validate_and_copy_sample(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, int depth, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, bool log) @@ -1716,15 +1742,15 @@ static int validate_and_copy_sample(const struct nlattr *attr, start = add_nested_action_start(sfa, OVS_ACTION_ATTR_SAMPLE, log); if (start < 0) return start; - err = add_action(sfa, OVS_SAMPLE_ATTR_PROBABILITY, - nla_data(probability), sizeof(u32), log); + err = ovs_nla_add_action(sfa, OVS_SAMPLE_ATTR_PROBABILITY, + nla_data(probability), sizeof(u32), log); if (err) return err; st_acts = add_nested_action_start(sfa, OVS_SAMPLE_ATTR_ACTIONS, log); if (st_acts < 0) return st_acts; - err = __ovs_nla_copy_actions(actions, key, depth + 1, sfa, + err = __ovs_nla_copy_actions(net, actions, key, depth + 1, sfa, eth_type, vlan_tci, log); if (err) return err; @@ -2058,7 +2084,7 @@ static int copy_action(const struct nlattr *from, return 0; } -static int __ovs_nla_copy_actions(const struct nlattr *attr, +static int __ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, int depth, struct sw_flow_actions **sfa, __be16 eth_type, __be16 vlan_tci, bool log) @@ -2082,7 +2108,8 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, [OVS_ACTION_ATTR_SET] = (u32)-1, [OVS_ACTION_ATTR_SET_MASKED] = (u32)-1, [OVS_ACTION_ATTR_SAMPLE] = (u32)-1, - [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash) + [OVS_ACTION_ATTR_HASH] = sizeof(struct ovs_action_hash), + [OVS_ACTION_ATTR_CT] = (u32)-1, }; const struct ovs_action_push_vlan *vlan; int type = nla_type(a); @@ -2189,13 +2216,20 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, break; case OVS_ACTION_ATTR_SAMPLE: - err = validate_and_copy_sample(a, key, depth, sfa, + err = validate_and_copy_sample(net, a, key, depth, sfa, eth_type, vlan_tci, log); if (err) return err; skip_copy = true; break; + case OVS_ACTION_ATTR_CT: + err = ovs_ct_copy_action(net, a, key, sfa, log); + if (err) + return err; + skip_copy = true; + break; + default: OVS_NLERR(log, "Unknown Action type %d", type); return -EINVAL; @@ -2214,7 +2248,7 @@ static int __ovs_nla_copy_actions(const struct nlattr *attr, } /* 'key' must be the masked key. */ -int ovs_nla_copy_actions(const struct nlattr *attr, +int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, struct sw_flow_actions **sfa, bool log) { @@ -2225,7 +2259,7 @@ int ovs_nla_copy_actions(const struct nlattr *attr, return PTR_ERR(*sfa); (*sfa)->orig_len = nla_len(attr); - err = __ovs_nla_copy_actions(attr, key, 0, sfa, key->eth.type, + err = __ovs_nla_copy_actions(net, attr, key, 0, sfa, key->eth.type, key->eth.tci, log); if (err) ovs_nla_free_flow_actions(*sfa); @@ -2350,6 +2384,13 @@ int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb) if (err) return err; break; + + case OVS_ACTION_ATTR_CT: + err = ovs_ct_action_to_attr(nla_data(a), skb); + if (err) + return err; + break; + default: if (nla_put(skb, type, nla_len(a), nla_data(a))) return -EMSGSIZE; diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index acd074408f0aa..c0b484b237c93 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h @@ -62,9 +62,11 @@ int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, const struct sw_flow_key *key, bool log); u32 ovs_nla_get_ufid_flags(const struct nlattr *attr); -int ovs_nla_copy_actions(const struct nlattr *attr, +int ovs_nla_copy_actions(struct net *net, const struct nlattr *attr, const struct sw_flow_key *key, struct sw_flow_actions **sfa, bool log); +int ovs_nla_add_action(struct sw_flow_actions **sfa, int attrtype, + void *data, int len, bool log); int ovs_nla_put_actions(const struct nlattr *attr, int len, struct sk_buff *skb); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index d73e5a16e7ca8..e2dc9dac59e68 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -484,6 +484,7 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, OVS_CB(skb)->input_vport = vport; OVS_CB(skb)->egress_tun_info = NULL; + OVS_CB(skb)->mru = 0; /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_key_extract(tun_info, skb, &key); if (unlikely(error)) { -- GitLab From 182e3042e15de759e81618d11fe4f62f5259d982 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:49 -0700 Subject: [PATCH 5194/7006] openvswitch: Allow matching on conntrack mark Allow matching and setting the ct_mark field. As with ct_state and ct_zone, these fields are populated when the CT action is executed. To write to this field, a value and mask can be specified as a nested attribute under the CT action. This data is stored with the conntrack entry, and is executed after the lookup occurs for the CT action. The conntrack entry itself must be committed using the COMMIT flag in the CT action flags for this change to persist. Signed-off-by: Justin Pettit Signed-off-by: Joe Stringer Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- include/uapi/linux/openvswitch.h | 5 +++ net/openvswitch/actions.c | 1 + net/openvswitch/conntrack.c | 67 ++++++++++++++++++++++++++++++-- net/openvswitch/conntrack.h | 1 + net/openvswitch/flow.h | 1 + net/openvswitch/flow_netlink.c | 12 +++++- 6 files changed, 83 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 55f5997926737..7a185b5543434 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -325,6 +325,7 @@ enum ovs_key_attr { * the accepted length of the array. */ OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */ OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */ + OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */ #ifdef __KERNEL__ OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ @@ -613,11 +614,15 @@ struct ovs_action_hash { * enum ovs_ct_attr - Attributes for %OVS_ACTION_ATTR_CT action. * @OVS_CT_ATTR_FLAGS: u32 connection tracking flags. * @OVS_CT_ATTR_ZONE: u16 connection tracking zone. + * @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the + * mask, the corresponding bit in the value is copied to the connection + * tracking mark field in the connection. */ enum ovs_ct_attr { OVS_CT_ATTR_UNSPEC, OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */ OVS_CT_ATTR_ZONE, /* u16 zone id. */ + OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ __OVS_CT_ATTR_MAX }; diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 72ca2c491b0aa..9741d2c703df2 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -968,6 +968,7 @@ static int execute_masked_set_action(struct sk_buff *skb, case OVS_KEY_ATTR_CT_STATE: case OVS_KEY_ATTR_CT_ZONE: + case OVS_KEY_ATTR_CT_MARK: err = -EINVAL; break; } diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 1189fd50f1cf1..e53dafccf21fd 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -28,12 +28,19 @@ struct ovs_ct_len_tbl { size_t minlen; }; +/* Metadata mark for masked write to conntrack mark */ +struct md_mark { + u32 value; + u32 mask; +}; + /* Conntrack action context for execution. */ struct ovs_conntrack_info { struct nf_conntrack_zone zone; struct nf_conn *ct; u32 flags; u16 family; + struct md_mark mark; }; static u16 key_to_nfproto(const struct sw_flow_key *key) @@ -84,10 +91,12 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo) } static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, - const struct nf_conntrack_zone *zone) + const struct nf_conntrack_zone *zone, + const struct nf_conn *ct) { key->ct.state = state; key->ct.zone = zone->id; + key->ct.mark = ct ? ct->mark : 0; } /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has @@ -110,7 +119,7 @@ static void ovs_ct_update_key(const struct sk_buff *skb, } else if (post_ct) { state = OVS_CS_F_TRACKED | OVS_CS_F_INVALID; } - __ovs_ct_update_key(key, state, zone); + __ovs_ct_update_key(key, state, zone, ct); } void ovs_ct_fill_key(const struct sk_buff *skb, struct sw_flow_key *key) @@ -127,6 +136,35 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) nla_put_u16(skb, OVS_KEY_ATTR_CT_ZONE, key->ct.zone)) return -EMSGSIZE; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && + nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark)) + return -EMSGSIZE; + + return 0; +} + +static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key, + u32 ct_mark, u32 mask) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn *ct; + u32 new_mark; + + if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)) + return -ENOTSUPP; + + /* The connection could be invalid, in which case set_mark is no-op. */ + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return 0; + + new_mark = ct_mark | (ct->mark & ~(mask)); + if (ct->mark != new_mark) { + ct->mark = new_mark; + nf_conntrack_event_cache(IPCT_MARK, ct); + key->ct.mark = new_mark; + } + return 0; } @@ -247,7 +285,7 @@ static int ovs_ct_lookup(struct net *net, struct sw_flow_key *key, u8 state; state = OVS_CS_F_TRACKED | OVS_CS_F_NEW | OVS_CS_F_RELATED; - __ovs_ct_update_key(key, state, &info->zone); + __ovs_ct_update_key(key, state, &info->zone, exp->master); } else { int err; @@ -310,7 +348,13 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, err = ovs_ct_commit(net, key, info, skb); else err = ovs_ct_lookup(net, key, info, skb); + if (err) + goto err; + if (info->mark.mask) + err = ovs_ct_set_mark(skb, key, info->mark.value, + info->mark.mask); +err: skb_push(skb, nh_ofs); return err; } @@ -320,6 +364,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { .maxlen = sizeof(u32) }, [OVS_CT_ATTR_ZONE] = { .minlen = sizeof(u16), .maxlen = sizeof(u16) }, + [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), + .maxlen = sizeof(struct md_mark) }, }; static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, @@ -354,6 +400,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, case OVS_CT_ATTR_ZONE: info->zone.id = nla_get_u16(a); break; +#endif +#ifdef CONFIG_NF_CONNTRACK_MARK + case OVS_CT_ATTR_MARK: { + struct md_mark *mark = nla_data(a); + + info->mark = *mark; + break; + } #endif default: OVS_NLERR(log, "Unknown conntrack attr (%d)", @@ -377,6 +431,9 @@ bool ovs_ct_verify(enum ovs_key_attr attr) if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && attr == OVS_KEY_ATTR_CT_ZONE) return true; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && + attr == OVS_KEY_ATTR_CT_MARK) + return true; return false; } @@ -439,6 +496,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, if (IS_ENABLED(CONFIG_NF_CONNTRACK_ZONES) && nla_put_u16(skb, OVS_CT_ATTR_ZONE, ct_info->zone.id)) return -EMSGSIZE; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && + nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), + &ct_info->mark)) + return -EMSGSIZE; nla_nest_end(skb, start); diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h index e812ee64a718c..87b289c589787 100644 --- a/net/openvswitch/conntrack.h +++ b/net/openvswitch/conntrack.h @@ -65,6 +65,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb, { key->ct.state = 0; key->ct.zone = 0; + key->ct.mark = 0; } static inline int ovs_ct_put_key(const struct sw_flow_key *key, diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index 312c7d755b9b2..e05e69711ce17 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -114,6 +114,7 @@ struct sw_flow_key { struct { /* Connection tracking fields. */ u16 zone; + u32 mark; u8 state; } ct; diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index 4e795b289eb76..b17a4ec348f9f 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void) /* Whenever adding new OVS_KEY_ FIELDS, we should consider * updating this function. */ - BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 24); + BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 25); return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ @@ -292,6 +292,7 @@ size_t ovs_key_attr_size(void) + nla_total_size(4) /* OVS_KEY_ATTR_RECIRC_ID */ + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */ + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ + + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ @@ -343,6 +344,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_MPLS] = { .len = sizeof(struct ovs_key_mpls) }, [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) }, [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, + [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) }, }; static bool is_all_zero(const u8 *fp, size_t size) @@ -787,6 +789,13 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask); *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE); } + if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) && + ovs_ct_verify(OVS_KEY_ATTR_CT_MARK)) { + u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]); + + SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask); + *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK); + } return 0; } @@ -1919,6 +1928,7 @@ static int validate_set(const struct nlattr *a, case OVS_KEY_ATTR_PRIORITY: case OVS_KEY_ATTR_SKB_MARK: + case OVS_KEY_ATTR_CT_MARK: case OVS_KEY_ATTR_ETHERNET: break; -- GitLab From 55e5713f2b5cefed98e3674017e994d688e47b85 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:50 -0700 Subject: [PATCH 5195/7006] netfilter: Always export nf_connlabels_replace() The following patches will reuse this code from OVS. Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/netfilter/nf_conntrack_labels.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c index bb53f120e79cb..daa7c1383becc 100644 --- a/net/netfilter/nf_conntrack_labels.c +++ b/net/netfilter/nf_conntrack_labels.c @@ -48,7 +48,6 @@ int nf_connlabel_set(struct nf_conn *ct, u16 bit) } EXPORT_SYMBOL_GPL(nf_connlabel_set); -#if IS_ENABLED(CONFIG_NF_CT_NETLINK) static void replace_u32(u32 *address, u32 mask, u32 new) { u32 old, tmp; @@ -89,7 +88,6 @@ int nf_connlabels_replace(struct nf_conn *ct, return 0; } EXPORT_SYMBOL_GPL(nf_connlabels_replace); -#endif static struct nf_ct_ext_type labels_extend __read_mostly = { .len = sizeof(struct nf_conn_labels), -- GitLab From 86ca02e77408bb58ba596c1a411ec7f631733690 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:51 -0700 Subject: [PATCH 5196/7006] netfilter: connlabels: Export setting connlabel length Add functions to change connlabel length into nf_conntrack_labels.c so they may be reused by other modules like OVS and nftables without needing to jump through xt_match_check() hoops. Suggested-by: Florian Westphal Signed-off-by: Joe Stringer Acked-by: Florian Westphal Acked-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/netfilter/nf_conntrack_labels.h | 4 +++ net/netfilter/nf_conntrack_labels.c | 32 +++++++++++++++++++++ net/netfilter/xt_connlabel.c | 16 +++-------- 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h index dec6336bf850f..7e2b1d025f503 100644 --- a/include/net/netfilter/nf_conntrack_labels.h +++ b/include/net/netfilter/nf_conntrack_labels.h @@ -54,7 +54,11 @@ int nf_connlabels_replace(struct nf_conn *ct, #ifdef CONFIG_NF_CONNTRACK_LABELS int nf_conntrack_labels_init(void); void nf_conntrack_labels_fini(void); +int nf_connlabels_get(struct net *net, unsigned int n_bits); +void nf_connlabels_put(struct net *net); #else static inline int nf_conntrack_labels_init(void) { return 0; } static inline void nf_conntrack_labels_fini(void) {} +static inline int nf_connlabels_get(struct net *net, unsigned int n_bits) { return 0; } +static inline void nf_connlabels_put(struct net *net) {} #endif diff --git a/net/netfilter/nf_conntrack_labels.c b/net/netfilter/nf_conntrack_labels.c index daa7c1383becc..3ce5c314ea4bc 100644 --- a/net/netfilter/nf_conntrack_labels.c +++ b/net/netfilter/nf_conntrack_labels.c @@ -14,6 +14,8 @@ #include #include +static spinlock_t nf_connlabels_lock; + static unsigned int label_bits(const struct nf_conn_labels *l) { unsigned int longs = l->words; @@ -89,6 +91,35 @@ int nf_connlabels_replace(struct nf_conn *ct, } EXPORT_SYMBOL_GPL(nf_connlabels_replace); +int nf_connlabels_get(struct net *net, unsigned int n_bits) +{ + size_t words; + + if (n_bits > (NF_CT_LABELS_MAX_SIZE * BITS_PER_BYTE)) + return -ERANGE; + + words = BITS_TO_LONGS(n_bits); + + spin_lock(&nf_connlabels_lock); + net->ct.labels_used++; + if (words > net->ct.label_words) + net->ct.label_words = words; + spin_unlock(&nf_connlabels_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(nf_connlabels_get); + +void nf_connlabels_put(struct net *net) +{ + spin_lock(&nf_connlabels_lock); + net->ct.labels_used--; + if (net->ct.labels_used == 0) + net->ct.label_words = 0; + spin_unlock(&nf_connlabels_lock); +} +EXPORT_SYMBOL_GPL(nf_connlabels_put); + static struct nf_ct_ext_type labels_extend __read_mostly = { .len = sizeof(struct nf_conn_labels), .align = __alignof__(struct nf_conn_labels), @@ -97,6 +128,7 @@ static struct nf_ct_ext_type labels_extend __read_mostly = { int nf_conntrack_labels_init(void) { + spin_lock_init(&nf_connlabels_lock); return nf_ct_extend_register(&labels_extend); } diff --git a/net/netfilter/xt_connlabel.c b/net/netfilter/xt_connlabel.c index 9f8719df20019..bb9cbeb188686 100644 --- a/net/netfilter/xt_connlabel.c +++ b/net/netfilter/xt_connlabel.c @@ -42,10 +42,6 @@ static int connlabel_mt_check(const struct xt_mtchk_param *par) XT_CONNLABEL_OP_SET; struct xt_connlabel_mtinfo *info = par->matchinfo; int ret; - size_t words; - - if (info->bit > XT_CONNLABEL_MAXBIT) - return -ERANGE; if (info->options & ~options) { pr_err("Unknown options in mask %x\n", info->options); @@ -59,19 +55,15 @@ static int connlabel_mt_check(const struct xt_mtchk_param *par) return ret; } - par->net->ct.labels_used++; - words = BITS_TO_LONGS(info->bit+1); - if (words > par->net->ct.label_words) - par->net->ct.label_words = words; - + ret = nf_connlabels_get(par->net, info->bit + 1); + if (ret < 0) + nf_ct_l3proto_module_put(par->family); return ret; } static void connlabel_mt_destroy(const struct xt_mtdtor_param *par) { - par->net->ct.labels_used--; - if (par->net->ct.labels_used == 0) - par->net->ct.label_words = 0; + nf_connlabels_put(par->net); nf_ct_l3proto_module_put(par->family); } -- GitLab From c2ac667358708d7cce64c78f58af6adf4c1e848b Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:52 -0700 Subject: [PATCH 5197/7006] openvswitch: Allow matching on conntrack label Allow matching and setting the ct_label field. As with ct_mark, this is populated by executing the CT action. The label field may be modified by specifying a label and mask nested under the CT action. It is stored as metadata attached to the connection. Label modification occurs after lookup, and will only persist when the conntrack entry is committed by providing the COMMIT flag to the CT action. Labels are currently fixed to 128 bits in size. Signed-off-by: Joe Stringer Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- include/uapi/linux/openvswitch.h | 10 +++ net/openvswitch/actions.c | 1 + net/openvswitch/conntrack.c | 128 ++++++++++++++++++++++++++++++- net/openvswitch/conntrack.h | 11 ++- net/openvswitch/datapath.c | 18 +++-- net/openvswitch/datapath.h | 3 + net/openvswitch/flow.c | 4 +- net/openvswitch/flow.h | 3 +- net/openvswitch/flow_netlink.c | 46 +++++++---- net/openvswitch/flow_netlink.h | 9 ++- 10 files changed, 199 insertions(+), 34 deletions(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 7a185b5543434..9d52058a93308 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -326,6 +326,7 @@ enum ovs_key_attr { OVS_KEY_ATTR_CT_STATE, /* u8 bitmask of OVS_CS_F_* */ OVS_KEY_ATTR_CT_ZONE, /* u16 connection tracking zone. */ OVS_KEY_ATTR_CT_MARK, /* u32 connection tracking mark */ + OVS_KEY_ATTR_CT_LABEL, /* 16-octet connection tracking label */ #ifdef __KERNEL__ OVS_KEY_ATTR_TUNNEL_INFO, /* struct ip_tunnel_info */ @@ -438,6 +439,11 @@ struct ovs_key_nd { __u8 nd_tll[ETH_ALEN]; }; +#define OVS_CT_LABEL_LEN 16 +struct ovs_key_ct_label { + __u8 ct_label[OVS_CT_LABEL_LEN]; +}; + /* OVS_KEY_ATTR_CT_STATE flags */ #define OVS_CS_F_NEW 0x01 /* Beginning of a new connection. */ #define OVS_CS_F_ESTABLISHED 0x02 /* Part of an existing connection. */ @@ -617,12 +623,16 @@ struct ovs_action_hash { * @OVS_CT_ATTR_MARK: u32 value followed by u32 mask. For each bit set in the * mask, the corresponding bit in the value is copied to the connection * tracking mark field in the connection. + * @OVS_CT_ATTR_LABEL: %OVS_CT_LABEL_LEN value followed by %OVS_CT_LABEL_LEN + * mask. For each bit set in the mask, the corresponding bit in the value is + * copied to the connection tracking label field in the connection. */ enum ovs_ct_attr { OVS_CT_ATTR_UNSPEC, OVS_CT_ATTR_FLAGS, /* u8 bitmask of OVS_CT_F_*. */ OVS_CT_ATTR_ZONE, /* u16 zone id. */ OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ + OVS_CT_ATTR_LABEL, /* label to associate with this connection. */ __OVS_CT_ATTR_MAX }; diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 9741d2c703df2..736a113a75c38 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -969,6 +969,7 @@ static int execute_masked_set_action(struct sk_buff *skb, case OVS_KEY_ATTR_CT_STATE: case OVS_KEY_ATTR_CT_ZONE: case OVS_KEY_ATTR_CT_MARK: + case OVS_KEY_ATTR_CT_LABEL: err = -EINVAL; break; } diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index e53dafccf21fd..a0417fb33d1d7 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,12 @@ struct md_mark { u32 mask; }; +/* Metadata label for masked write to conntrack label. */ +struct md_label { + struct ovs_key_ct_label value; + struct ovs_key_ct_label mask; +}; + /* Conntrack action context for execution. */ struct ovs_conntrack_info { struct nf_conntrack_zone zone; @@ -41,6 +48,7 @@ struct ovs_conntrack_info { u32 flags; u16 family; struct md_mark mark; + struct md_label label; }; static u16 key_to_nfproto(const struct sw_flow_key *key) @@ -90,6 +98,24 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo) return ct_state; } +static void ovs_ct_get_label(const struct nf_conn *ct, + struct ovs_key_ct_label *label) +{ + struct nf_conn_labels *cl = ct ? nf_ct_labels_find(ct) : NULL; + + if (cl) { + size_t len = cl->words * sizeof(long); + + if (len > OVS_CT_LABEL_LEN) + len = OVS_CT_LABEL_LEN; + else if (len < OVS_CT_LABEL_LEN) + memset(label, 0, OVS_CT_LABEL_LEN); + memcpy(label, cl->bits, len); + } else { + memset(label, 0, OVS_CT_LABEL_LEN); + } +} + static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, const struct nf_conntrack_zone *zone, const struct nf_conn *ct) @@ -97,6 +123,7 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, key->ct.state = state; key->ct.zone = zone->id; key->ct.mark = ct ? ct->mark : 0; + ovs_ct_get_label(ct, &key->ct.label); } /* Update 'key' based on skb->nfct. If 'post_ct' is true, then OVS has @@ -140,6 +167,11 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark)) return -EMSGSIZE; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABEL) && + nla_put(skb, OVS_KEY_ATTR_CT_LABEL, sizeof(key->ct.label), + &key->ct.label)) + return -EMSGSIZE; + return 0; } @@ -168,6 +200,40 @@ static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key, return 0; } +static int ovs_ct_set_label(struct sk_buff *skb, struct sw_flow_key *key, + const struct ovs_key_ct_label *label, + const struct ovs_key_ct_label *mask) +{ + enum ip_conntrack_info ctinfo; + struct nf_conn_labels *cl; + struct nf_conn *ct; + int err; + + if (!IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS)) + return -ENOTSUPP; + + /* The connection could be invalid, in which case set_label is no-op.*/ + ct = nf_ct_get(skb, &ctinfo); + if (!ct) + return 0; + + cl = nf_ct_labels_find(ct); + if (!cl) { + nf_ct_labels_ext_add(ct); + cl = nf_ct_labels_find(ct); + } + if (!cl || cl->words * sizeof(long) < OVS_CT_LABEL_LEN) + return -ENOSPC; + + err = nf_connlabels_replace(ct, (u32 *)label, (u32 *)mask, + OVS_CT_LABEL_LEN / sizeof(u32)); + if (err) + return err; + + ovs_ct_get_label(ct, &key->ct.label); + return 0; +} + static int handle_fragments(struct net *net, struct sw_flow_key *key, u16 zone, struct sk_buff *skb) { @@ -327,6 +393,17 @@ static int ovs_ct_commit(struct net *net, struct sw_flow_key *key, return 0; } +static bool label_nonzero(const struct ovs_key_ct_label *label) +{ + size_t i; + + for (i = 0; i < sizeof(*label); i++) + if (label->ct_label[i]) + return true; + + return false; +} + int ovs_ct_execute(struct net *net, struct sk_buff *skb, struct sw_flow_key *key, const struct ovs_conntrack_info *info) @@ -351,9 +428,15 @@ int ovs_ct_execute(struct net *net, struct sk_buff *skb, if (err) goto err; - if (info->mark.mask) + if (info->mark.mask) { err = ovs_ct_set_mark(skb, key, info->mark.value, info->mark.mask); + if (err) + goto err; + } + if (label_nonzero(&info->label.mask)) + err = ovs_ct_set_label(skb, key, &info->label.value, + &info->label.mask); err: skb_push(skb, nh_ofs); return err; @@ -366,6 +449,8 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { .maxlen = sizeof(u16) }, [OVS_CT_ATTR_MARK] = { .minlen = sizeof(struct md_mark), .maxlen = sizeof(struct md_mark) }, + [OVS_CT_ATTR_LABEL] = { .minlen = sizeof(struct md_label), + .maxlen = sizeof(struct md_label) }, }; static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, @@ -408,6 +493,14 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, info->mark = *mark; break; } +#endif +#ifdef CONFIG_NF_CONNTRACK_LABELS + case OVS_CT_ATTR_LABEL: { + struct md_label *label = nla_data(a); + + info->label = *label; + break; + } #endif default: OVS_NLERR(log, "Unknown conntrack attr (%d)", @@ -424,7 +517,7 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, return 0; } -bool ovs_ct_verify(enum ovs_key_attr attr) +bool ovs_ct_verify(struct net *net, enum ovs_key_attr attr) { if (attr == OVS_KEY_ATTR_CT_STATE) return true; @@ -434,6 +527,12 @@ bool ovs_ct_verify(enum ovs_key_attr attr) if (IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) && attr == OVS_KEY_ATTR_CT_MARK) return true; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && + attr == OVS_KEY_ATTR_CT_LABEL) { + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + + return ovs_net->xt_label; + } return false; } @@ -500,6 +599,10 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, nla_put(skb, OVS_CT_ATTR_MARK, sizeof(ct_info->mark), &ct_info->mark)) return -EMSGSIZE; + if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && + nla_put(skb, OVS_CT_ATTR_LABEL, sizeof(ct_info->label), + &ct_info->label)) + return -EMSGSIZE; nla_nest_end(skb, start); @@ -513,3 +616,24 @@ void ovs_ct_free_action(const struct nlattr *a) if (ct_info->ct) nf_ct_put(ct_info->ct); } + +void ovs_ct_init(struct net *net) +{ + unsigned int n_bits = sizeof(struct ovs_key_ct_label) * BITS_PER_BYTE; + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + + if (nf_connlabels_get(net, n_bits)) { + ovs_net->xt_label = false; + OVS_NLERR(true, "Failed to set connlabel length"); + } else { + ovs_net->xt_label = true; + } +} + +void ovs_ct_exit(struct net *net) +{ + struct ovs_net *ovs_net = net_generic(net, ovs_net_id); + + if (ovs_net->xt_label) + nf_connlabels_put(net); +} diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h index 87b289c589787..3cb30667a7dcb 100644 --- a/net/openvswitch/conntrack.h +++ b/net/openvswitch/conntrack.h @@ -20,7 +20,9 @@ struct ovs_conntrack_info; enum ovs_key_attr; #if defined(CONFIG_OPENVSWITCH_CONNTRACK) -bool ovs_ct_verify(enum ovs_key_attr attr); +void ovs_ct_init(struct net *); +void ovs_ct_exit(struct net *); +bool ovs_ct_verify(struct net *, enum ovs_key_attr attr); int ovs_ct_copy_action(struct net *, const struct nlattr *, const struct sw_flow_key *, struct sw_flow_actions **, bool log); @@ -35,7 +37,11 @@ void ovs_ct_free_action(const struct nlattr *a); #else #include -static inline bool ovs_ct_verify(int attr) +static inline void ovs_ct_init(struct net *net) { } + +static inline void ovs_ct_exit(struct net *net) { } + +static inline bool ovs_ct_verify(struct net *net, int attr) { return false; } @@ -66,6 +72,7 @@ static inline void ovs_ct_fill_key(const struct sk_buff *skb, key->ct.state = 0; key->ct.zone = 0; key->ct.mark = 0; + memset(&key->ct.label, 0, sizeof(key->ct.label)); } static inline int ovs_ct_put_key(const struct sw_flow_key *key, diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 72e63726efa0d..ec0f8d9cee731 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -599,8 +599,8 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) if (IS_ERR(flow)) goto err_kfree_skb; - err = ovs_flow_key_extract_userspace(a[OVS_PACKET_ATTR_KEY], packet, - &flow->key, log); + err = ovs_flow_key_extract_userspace(net, a[OVS_PACKET_ATTR_KEY], + packet, &flow->key, log); if (err) goto err_flow_free; @@ -947,7 +947,7 @@ static int ovs_flow_cmd_new(struct sk_buff *skb, struct genl_info *info) /* Extract key. */ ovs_match_init(&match, &key, &mask); - error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], + error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK], log); if (error) goto err_kfree_flow; @@ -1118,7 +1118,7 @@ static int ovs_flow_cmd_set(struct sk_buff *skb, struct genl_info *info) ufid_present = ovs_nla_get_ufid(&sfid, a[OVS_FLOW_ATTR_UFID], log); ovs_match_init(&match, &key, &mask); - error = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], + error = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], a[OVS_FLOW_ATTR_MASK], log); if (error) goto error; @@ -1208,6 +1208,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) { struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; + struct net *net = sock_net(skb->sk); struct sw_flow_key key; struct sk_buff *reply; struct sw_flow *flow; @@ -1222,7 +1223,7 @@ static int ovs_flow_cmd_get(struct sk_buff *skb, struct genl_info *info) ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log); if (a[OVS_FLOW_ATTR_KEY]) { ovs_match_init(&match, &key, NULL); - err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, + err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], NULL, log); } else if (!ufid_present) { OVS_NLERR(log, @@ -1266,6 +1267,7 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) { struct nlattr **a = info->attrs; struct ovs_header *ovs_header = info->userhdr; + struct net *net = sock_net(skb->sk); struct sw_flow_key key; struct sk_buff *reply; struct sw_flow *flow = NULL; @@ -1280,8 +1282,8 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) ufid_present = ovs_nla_get_ufid(&ufid, a[OVS_FLOW_ATTR_UFID], log); if (a[OVS_FLOW_ATTR_KEY]) { ovs_match_init(&match, &key, NULL); - err = ovs_nla_get_match(&match, a[OVS_FLOW_ATTR_KEY], NULL, - log); + err = ovs_nla_get_match(net, &match, a[OVS_FLOW_ATTR_KEY], + NULL, log); if (unlikely(err)) return err; } @@ -2237,6 +2239,7 @@ static int __net_init ovs_init_net(struct net *net) INIT_LIST_HEAD(&ovs_net->dps); INIT_WORK(&ovs_net->dp_notify_work, ovs_dp_notify_wq); + ovs_ct_init(net); return 0; } @@ -2271,6 +2274,7 @@ static void __net_exit ovs_exit_net(struct net *dnet) struct net *net; LIST_HEAD(head); + ovs_ct_exit(dnet); ovs_lock(); list_for_each_entry_safe(dp, dp_next, &ovs_net->dps, list_node) __dp_destroy(dp); diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index d24ba98024bec..4e785ab889732 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -138,6 +138,9 @@ struct ovs_net { struct list_head dps; struct work_struct dp_notify_work; struct vport_net vport_net; + + /* Module reference for configuring conntrack. */ + bool xt_label; }; extern int ovs_net_id; diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 376ca8738fd43..5a3195e538ce5 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -715,7 +715,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, return key_extract(skb, key); } -int ovs_flow_key_extract_userspace(const struct nlattr *attr, +int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, struct sk_buff *skb, struct sw_flow_key *key, bool log) { @@ -724,7 +724,7 @@ int ovs_flow_key_extract_userspace(const struct nlattr *attr, memset(key, 0, OVS_SW_FLOW_KEY_METADATA_SIZE); /* Extract metadata from netlink attributes. */ - err = ovs_nla_get_flow_metadata(attr, key, log); + err = ovs_nla_get_flow_metadata(net, attr, key, log); if (err) return err; diff --git a/net/openvswitch/flow.h b/net/openvswitch/flow.h index e05e69711ce17..fe527d2dd4b7a 100644 --- a/net/openvswitch/flow.h +++ b/net/openvswitch/flow.h @@ -116,6 +116,7 @@ struct sw_flow_key { u16 zone; u32 mark; u8 state; + struct ovs_key_ct_label label; } ct; } __aligned(BITS_PER_LONG/8); /* Ensure that we can do comparisons as longs. */ @@ -220,7 +221,7 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, struct sk_buff *skb, struct sw_flow_key *key); /* Extract key from packet coming from userspace. */ -int ovs_flow_key_extract_userspace(const struct nlattr *attr, +int ovs_flow_key_extract_userspace(struct net *net, const struct nlattr *attr, struct sk_buff *skb, struct sw_flow_key *key, bool log); diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index b17a4ec348f9f..e22c5bfe85756 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -281,7 +281,7 @@ size_t ovs_key_attr_size(void) /* Whenever adding new OVS_KEY_ FIELDS, we should consider * updating this function. */ - BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 25); + BUILD_BUG_ON(OVS_KEY_ATTR_TUNNEL_INFO != 26); return nla_total_size(4) /* OVS_KEY_ATTR_PRIORITY */ + nla_total_size(0) /* OVS_KEY_ATTR_TUNNEL */ @@ -293,6 +293,7 @@ size_t ovs_key_attr_size(void) + nla_total_size(1) /* OVS_KEY_ATTR_CT_STATE */ + nla_total_size(2) /* OVS_KEY_ATTR_CT_ZONE */ + nla_total_size(4) /* OVS_KEY_ATTR_CT_MARK */ + + nla_total_size(16) /* OVS_KEY_ATTR_CT_LABEL */ + nla_total_size(12) /* OVS_KEY_ATTR_ETHERNET */ + nla_total_size(2) /* OVS_KEY_ATTR_ETHERTYPE */ + nla_total_size(4) /* OVS_KEY_ATTR_VLAN */ @@ -345,6 +346,7 @@ static const struct ovs_len_tbl ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = { [OVS_KEY_ATTR_CT_STATE] = { .len = sizeof(u8) }, [OVS_KEY_ATTR_CT_ZONE] = { .len = sizeof(u16) }, [OVS_KEY_ATTR_CT_MARK] = { .len = sizeof(u32) }, + [OVS_KEY_ATTR_CT_LABEL] = { .len = sizeof(struct ovs_key_ct_label) }, }; static bool is_all_zero(const u8 *fp, size_t size) @@ -721,9 +723,9 @@ int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, egress_tun_info->options_len); } -static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, - const struct nlattr **a, bool is_mask, - bool log) +static int metadata_from_nlattrs(struct net *net, struct sw_flow_match *match, + u64 *attrs, const struct nlattr **a, + bool is_mask, bool log) { if (*attrs & (1 << OVS_KEY_ATTR_DP_HASH)) { u32 hash_val = nla_get_u32(a[OVS_KEY_ATTR_DP_HASH]); @@ -776,36 +778,45 @@ static int metadata_from_nlattrs(struct sw_flow_match *match, u64 *attrs, } if (*attrs & (1 << OVS_KEY_ATTR_CT_STATE) && - ovs_ct_verify(OVS_KEY_ATTR_CT_STATE)) { + ovs_ct_verify(net, OVS_KEY_ATTR_CT_STATE)) { u8 ct_state = nla_get_u8(a[OVS_KEY_ATTR_CT_STATE]); SW_FLOW_KEY_PUT(match, ct.state, ct_state, is_mask); *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_STATE); } if (*attrs & (1 << OVS_KEY_ATTR_CT_ZONE) && - ovs_ct_verify(OVS_KEY_ATTR_CT_ZONE)) { + ovs_ct_verify(net, OVS_KEY_ATTR_CT_ZONE)) { u16 ct_zone = nla_get_u16(a[OVS_KEY_ATTR_CT_ZONE]); SW_FLOW_KEY_PUT(match, ct.zone, ct_zone, is_mask); *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_ZONE); } if (*attrs & (1 << OVS_KEY_ATTR_CT_MARK) && - ovs_ct_verify(OVS_KEY_ATTR_CT_MARK)) { + ovs_ct_verify(net, OVS_KEY_ATTR_CT_MARK)) { u32 mark = nla_get_u32(a[OVS_KEY_ATTR_CT_MARK]); SW_FLOW_KEY_PUT(match, ct.mark, mark, is_mask); *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_MARK); } + if (*attrs & (1 << OVS_KEY_ATTR_CT_LABEL) && + ovs_ct_verify(net, OVS_KEY_ATTR_CT_LABEL)) { + const struct ovs_key_ct_label *cl; + + cl = nla_data(a[OVS_KEY_ATTR_CT_LABEL]); + SW_FLOW_KEY_MEMCPY(match, ct.label, cl->ct_label, + sizeof(*cl), is_mask); + *attrs &= ~(1ULL << OVS_KEY_ATTR_CT_LABEL); + } return 0; } -static int ovs_key_from_nlattrs(struct sw_flow_match *match, u64 attrs, - const struct nlattr **a, bool is_mask, - bool log) +static int ovs_key_from_nlattrs(struct net *net, struct sw_flow_match *match, + u64 attrs, const struct nlattr **a, + bool is_mask, bool log) { int err; - err = metadata_from_nlattrs(match, &attrs, a, is_mask, log); + err = metadata_from_nlattrs(net, match, &attrs, a, is_mask, log); if (err) return err; @@ -1057,6 +1068,7 @@ static void mask_set_nlattr(struct nlattr *attr, u8 val) * mask. In case the 'mask' is NULL, the flow is treated as exact match * flow. Otherwise, it is treated as a wildcarded flow, except the mask * does not include any don't care bit. + * @net: Used to determine per-namespace field support. * @match: receives the extracted flow match information. * @key: Netlink attribute holding nested %OVS_KEY_ATTR_* Netlink attribute * sequence. The fields should of the packet that triggered the creation @@ -1067,7 +1079,7 @@ static void mask_set_nlattr(struct nlattr *attr, u8 val) * probing for feature compatibility this should be passed in as false to * suppress unnecessary error logging. */ -int ovs_nla_get_match(struct sw_flow_match *match, +int ovs_nla_get_match(struct net *net, struct sw_flow_match *match, const struct nlattr *nla_key, const struct nlattr *nla_mask, bool log) @@ -1117,7 +1129,7 @@ int ovs_nla_get_match(struct sw_flow_match *match, } } - err = ovs_key_from_nlattrs(match, key_attrs, a, false, log); + err = ovs_key_from_nlattrs(net, match, key_attrs, a, false, log); if (err) return err; @@ -1197,7 +1209,8 @@ int ovs_nla_get_match(struct sw_flow_match *match, } } - err = ovs_key_from_nlattrs(match, mask_attrs, a, true, log); + err = ovs_key_from_nlattrs(net, match, mask_attrs, a, true, + log); if (err) goto free_newmask; } @@ -1278,7 +1291,7 @@ u32 ovs_nla_get_ufid_flags(const struct nlattr *attr) * extracted from the packet itself. */ -int ovs_nla_get_flow_metadata(const struct nlattr *attr, +int ovs_nla_get_flow_metadata(struct net *net, const struct nlattr *attr, struct sw_flow_key *key, bool log) { @@ -1297,7 +1310,7 @@ int ovs_nla_get_flow_metadata(const struct nlattr *attr, memset(&key->ct, 0, sizeof(key->ct)); key->phy.in_port = DP_MAX_PORTS; - return metadata_from_nlattrs(&match, &attrs, a, false, log); + return metadata_from_nlattrs(net, &match, &attrs, a, false, log); } static int __ovs_nla_put_key(const struct sw_flow_key *swkey, @@ -1929,6 +1942,7 @@ static int validate_set(const struct nlattr *a, case OVS_KEY_ATTR_PRIORITY: case OVS_KEY_ATTR_SKB_MARK: case OVS_KEY_ATTR_CT_MARK: + case OVS_KEY_ATTR_CT_LABEL: case OVS_KEY_ATTR_ETHERNET: break; diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index c0b484b237c93..07878e22e7830 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h @@ -45,15 +45,16 @@ void ovs_match_init(struct sw_flow_match *match, int ovs_nla_put_key(const struct sw_flow_key *, const struct sw_flow_key *, int attr, bool is_mask, struct sk_buff *); -int ovs_nla_get_flow_metadata(const struct nlattr *, struct sw_flow_key *, - bool log); +int ovs_nla_get_flow_metadata(struct net *, const struct nlattr *, + struct sw_flow_key *, bool log); int ovs_nla_put_identifier(const struct sw_flow *flow, struct sk_buff *skb); int ovs_nla_put_masked_key(const struct sw_flow *flow, struct sk_buff *skb); int ovs_nla_put_mask(const struct sw_flow *flow, struct sk_buff *skb); -int ovs_nla_get_match(struct sw_flow_match *, const struct nlattr *key, - const struct nlattr *mask, bool log); +int ovs_nla_get_match(struct net *, struct sw_flow_match *, + const struct nlattr *key, const struct nlattr *mask, + bool log); int ovs_nla_put_egress_tunnel_key(struct sk_buff *, const struct ip_tunnel_info *); -- GitLab From cae3a2627520c3795b54533c5328b77af3405dbe Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Wed, 26 Aug 2015 11:31:53 -0700 Subject: [PATCH 5198/7006] openvswitch: Allow attaching helpers to ct action Add support for using conntrack helpers to assist protocol detection. The new OVS_CT_ATTR_HELPER attribute of the CT action specifies a helper to be used for this connection. If no helper is specified, then helpers will be automatically applied as per the sysctl configuration of net.netfilter.nf_conntrack_helper. The helper may be specified as part of the conntrack action, eg: ct(helper=ftp). Initial packets for related connections should be committed to allow later packets for the flow to be considered established. Example ovs-ofctl flows allowing FTP connections from ports 1->2: in_port=1,tcp,action=ct(helper=ftp,commit),2 in_port=2,tcp,ct_state=-trk,action=ct(recirc) in_port=2,tcp,ct_state=+trk-new+est,action=1 in_port=2,tcp,ct_state=+trk+rel,action=1 Signed-off-by: Joe Stringer Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- include/uapi/linux/openvswitch.h | 3 + net/openvswitch/conntrack.c | 109 ++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/openvswitch.h b/include/uapi/linux/openvswitch.h index 9d52058a93308..32e07d8cbaf47 100644 --- a/include/uapi/linux/openvswitch.h +++ b/include/uapi/linux/openvswitch.h @@ -626,6 +626,7 @@ struct ovs_action_hash { * @OVS_CT_ATTR_LABEL: %OVS_CT_LABEL_LEN value followed by %OVS_CT_LABEL_LEN * mask. For each bit set in the mask, the corresponding bit in the value is * copied to the connection tracking label field in the connection. + * @OVS_CT_ATTR_HELPER: variable length string defining conntrack ALG. */ enum ovs_ct_attr { OVS_CT_ATTR_UNSPEC, @@ -633,6 +634,8 @@ enum ovs_ct_attr { OVS_CT_ATTR_ZONE, /* u16 zone id. */ OVS_CT_ATTR_MARK, /* mark to associate with this connection. */ OVS_CT_ATTR_LABEL, /* label to associate with this connection. */ + OVS_CT_ATTR_HELPER, /* netlink helper to assist detection of + related connections. */ __OVS_CT_ATTR_MAX }; diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index a0417fb33d1d7..890d3eedb447c 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,7 @@ struct md_label { /* Conntrack action context for execution. */ struct ovs_conntrack_info { + struct nf_conntrack_helper *helper; struct nf_conntrack_zone zone; struct nf_conn *ct; u32 flags; @@ -234,6 +236,51 @@ static int ovs_ct_set_label(struct sk_buff *skb, struct sw_flow_key *key, return 0; } +/* 'skb' should already be pulled to nh_ofs. */ +static int ovs_ct_helper(struct sk_buff *skb, u16 proto) +{ + const struct nf_conntrack_helper *helper; + const struct nf_conn_help *help; + enum ip_conntrack_info ctinfo; + unsigned int protoff; + struct nf_conn *ct; + + ct = nf_ct_get(skb, &ctinfo); + if (!ct || ctinfo == IP_CT_RELATED_REPLY) + return NF_ACCEPT; + + help = nfct_help(ct); + if (!help) + return NF_ACCEPT; + + helper = rcu_dereference(help->helper); + if (!helper) + return NF_ACCEPT; + + switch (proto) { + case NFPROTO_IPV4: + protoff = ip_hdrlen(skb); + break; + case NFPROTO_IPV6: { + u8 nexthdr = ipv6_hdr(skb)->nexthdr; + __be16 frag_off; + + protoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), + &nexthdr, &frag_off); + if (protoff < 0 || (frag_off & htons(~0x7)) != 0) { + pr_debug("proto header not found\n"); + return NF_ACCEPT; + } + break; + } + default: + WARN_ONCE(1, "helper invoked on non-IP family!"); + return NF_DROP; + } + + return helper->help(skb, protoff, ct, ctinfo); +} + static int handle_fragments(struct net *net, struct sw_flow_key *key, u16 zone, struct sk_buff *skb) { @@ -306,6 +353,13 @@ static bool skb_nfct_cached(const struct net *net, const struct sk_buff *skb, return false; if (!nf_ct_zone_equal_any(info->ct, nf_ct_zone(ct))) return false; + if (info->helper) { + struct nf_conn_help *help; + + help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER); + if (help && rcu_access_pointer(help->helper) != info->helper) + return false; + } return true; } @@ -334,6 +388,11 @@ static int __ovs_ct_lookup(struct net *net, const struct sw_flow_key *key, if (nf_conntrack_in(net, info->family, NF_INET_PRE_ROUTING, skb) != NF_ACCEPT) return -ENOENT; + + if (ovs_ct_helper(skb, info->family) != NF_ACCEPT) { + WARN_ONCE(1, "helper rejected packet"); + return -EINVAL; + } } return 0; @@ -442,6 +501,30 @@ err: return err; } +static int ovs_ct_add_helper(struct ovs_conntrack_info *info, const char *name, + const struct sw_flow_key *key, bool log) +{ + struct nf_conntrack_helper *helper; + struct nf_conn_help *help; + + helper = nf_conntrack_helper_try_module_get(name, info->family, + key->ip.proto); + if (!helper) { + OVS_NLERR(log, "Unknown helper \"%s\"", name); + return -EINVAL; + } + + help = nf_ct_helper_ext_add(info->ct, helper, GFP_KERNEL); + if (!help) { + module_put(helper->me); + return -ENOMEM; + } + + rcu_assign_pointer(help->helper, helper); + info->helper = helper; + return 0; +} + static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { [OVS_CT_ATTR_FLAGS] = { .minlen = sizeof(u32), .maxlen = sizeof(u32) }, @@ -451,10 +534,12 @@ static const struct ovs_ct_len_tbl ovs_ct_attr_lens[OVS_CT_ATTR_MAX + 1] = { .maxlen = sizeof(struct md_mark) }, [OVS_CT_ATTR_LABEL] = { .minlen = sizeof(struct md_label), .maxlen = sizeof(struct md_label) }, + [OVS_CT_ATTR_HELPER] = { .minlen = 1, + .maxlen = NF_CT_HELPER_NAME_LEN } }; static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, - bool log) + const char **helper, bool log) { struct nlattr *a; int rem; @@ -502,6 +587,13 @@ static int parse_ct(const struct nlattr *attr, struct ovs_conntrack_info *info, break; } #endif + case OVS_CT_ATTR_HELPER: + *helper = nla_data(a); + if (!memchr(*helper, '\0', nla_len(a))) { + OVS_NLERR(log, "Invalid conntrack helper"); + return -EINVAL; + } + break; default: OVS_NLERR(log, "Unknown conntrack attr (%d)", type); @@ -542,6 +634,7 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, struct sw_flow_actions **sfa, bool log) { struct ovs_conntrack_info ct_info; + const char *helper = NULL; u16 family; int err; @@ -557,7 +650,7 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, nf_ct_zone_init(&ct_info.zone, NF_CT_DEFAULT_ZONE_ID, NF_CT_DEFAULT_ZONE_DIR, 0); - err = parse_ct(attr, &ct_info, log); + err = parse_ct(attr, &ct_info, &helper, log); if (err) return err; @@ -567,6 +660,11 @@ int ovs_ct_copy_action(struct net *net, const struct nlattr *attr, OVS_NLERR(log, "Failed to allocate conntrack template"); return -ENOMEM; } + if (helper) { + err = ovs_ct_add_helper(&ct_info, helper, key, log); + if (err) + goto err_free_ct; + } err = ovs_nla_add_action(sfa, OVS_ACTION_ATTR_CT, &ct_info, sizeof(ct_info), log); @@ -603,6 +701,11 @@ int ovs_ct_action_to_attr(const struct ovs_conntrack_info *ct_info, nla_put(skb, OVS_CT_ATTR_LABEL, sizeof(ct_info->label), &ct_info->label)) return -EMSGSIZE; + if (ct_info->helper) { + if (nla_put_string(skb, OVS_CT_ATTR_HELPER, + ct_info->helper->name)) + return -EMSGSIZE; + } nla_nest_end(skb, start); @@ -613,6 +716,8 @@ void ovs_ct_free_action(const struct nlattr *a) { struct ovs_conntrack_info *ct_info = nla_data(a); + if (ct_info->helper) + module_put(ct_info->helper->me); if (ct_info->ct) nf_ct_put(ct_info->ct); } -- GitLab From f2988afedf2c19880a3c65d79dfc7939e1b53d8a Mon Sep 17 00:00:00 2001 From: Oder Chiou Date: Thu, 27 Aug 2015 15:14:51 +0800 Subject: [PATCH 5199/7006] ASoC: rt5645: Prevent the pop sound of the headphone while rebooting or shutdowning Add i2c shutdown function to prevent the pop sound of the headphone while the system is rebooting or shutdowning. It de-initials the jack detection function, and it cannot be turned off in _BIAS_OFF. If we don't de-initial it, the pop sound will be heard in the situation of powering off. And replace the related register settings from magic number to meaningful defined name. Signed-off-by: Oder Chiou Signed-off-by: Mark Brown --- sound/soc/codecs/rt5645.c | 35 ++++++++++++++++++++++++----------- sound/soc/codecs/rt5645.h | 1 + 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 0a4cb6bc34335..db50b035b00b9 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c @@ -2806,13 +2806,13 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } regmap_write(rt5645->regmap, RT5645_JD_CTRL3, 0x00f0); - regmap_update_bits(rt5645->regmap, - RT5645_IN1_CTRL2, 0x1000, 0x1000); - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, - 0x0004); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, + RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN); msleep(100); - regmap_update_bits(rt5645->regmap, - RT5645_IN1_CTRL2, 0x1000, 0x0000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, 0); msleep(600); regmap_read(rt5645->regmap, RT5645_IN1_CTRL3, &val); @@ -2836,10 +2836,10 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec, int jack_insert) } else { /* jack out */ rt5645->jack_type = 0; - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, 0x1000, - 0x1000); - regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, 0x0004, - 0x0000); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, + RT5645_CBJ_MN_JD, RT5645_CBJ_MN_JD); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, + RT5645_CBJ_BST1_EN, 0); if (rt5645->en_button_func) rt5645_enable_push_button_irq(codec, false); @@ -3449,6 +3449,18 @@ static int rt5645_i2c_remove(struct i2c_client *i2c) return 0; } +static void rt5645_i2c_shutdown(struct i2c_client *i2c) +{ + struct rt5645_priv *rt5645 = i2c_get_clientdata(i2c); + + regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3, + RT5645_RING2_SLEEVE_GND, RT5645_RING2_SLEEVE_GND); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL2, RT5645_CBJ_MN_JD, + RT5645_CBJ_MN_JD); + regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1, RT5645_CBJ_BST1_EN, + 0); +} + static struct i2c_driver rt5645_i2c_driver = { .driver = { .name = "rt5645", @@ -3456,7 +3468,8 @@ static struct i2c_driver rt5645_i2c_driver = { .acpi_match_table = ACPI_PTR(rt5645_acpi_match), }, .probe = rt5645_i2c_probe, - .remove = rt5645_i2c_remove, + .remove = rt5645_i2c_remove, + .shutdown = rt5645_i2c_shutdown, .id_table = rt5645_i2c_id, }; module_i2c_driver(rt5645_i2c_driver); diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h index 199b22fe1bf36..1987eb825e41f 100644 --- a/sound/soc/codecs/rt5645.h +++ b/sound/soc/codecs/rt5645.h @@ -2111,6 +2111,7 @@ enum { #define RT5645_JD_PSV_MODE (0x1 << 12) #define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11) #define RT5645_MICINDET_MANU (0x1 << 7) +#define RT5645_RING2_SLEEVE_GND (0x1 << 5) /* Vendor ID (0xfd) */ #define RT5645_VER_C 0x2 -- GitLab From 054bc835d27b558393541c32a209c01d89cda75a Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 27 Aug 2015 17:04:01 +0200 Subject: [PATCH 5200/7006] ASoC: bcm2835-i2s: Fix module autoload for OF platform drivers These platform drivers have a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Mark Brown --- sound/soc/bcm/bcm2835-i2s.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sound/soc/bcm/bcm2835-i2s.c b/sound/soc/bcm/bcm2835-i2s.c index 03fa1cbf8ec1d..8c435beb263df 100644 --- a/sound/soc/bcm/bcm2835-i2s.c +++ b/sound/soc/bcm/bcm2835-i2s.c @@ -862,6 +862,8 @@ static const struct of_device_id bcm2835_i2s_of_match[] = { {}, }; +MODULE_DEVICE_TABLE(of, bcm2835_i2s_of_match); + static struct platform_driver bcm2835_i2s_driver = { .probe = bcm2835_i2s_probe, .driver = { -- GitLab From 949c40bb16bcf5f9584ce585f8a477481ab6aa80 Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 26 Aug 2015 11:48:05 -0700 Subject: [PATCH 5201/7006] drivers: net: xgene: Preparatory patch for TSO support - Rearranged descriptor writes - Moved increment command write to xgene_enet_setup_tx_desc Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- .../net/ethernet/apm/xgene/xgene_enet_main.c | 29 ++++++++++++++----- .../net/ethernet/apm/xgene/xgene_enet_main.h | 1 + 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 4f68d19c45bda..652b4c3ff05ca 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -219,6 +219,11 @@ out: return hopinfo; } +static u16 xgene_enet_encode_len(u16 len) +{ + return (len == BUFLEN_16K) ? 0 : len; +} + static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, struct sk_buff *skb) { @@ -227,27 +232,36 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, dma_addr_t dma_addr; u16 tail = tx_ring->tail; u64 hopinfo; + u32 len, hw_len; + u8 count = 1; raw_desc = &tx_ring->raw_desc[tail]; memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc)); - dma_addr = dma_map_single(dev, skb->data, skb->len, DMA_TO_DEVICE); + len = skb_headlen(skb); + hw_len = xgene_enet_encode_len(len); + + dma_addr = dma_map_single(dev, skb->data, len, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma_addr)) { netdev_err(tx_ring->ndev, "DMA mapping error\n"); return -EINVAL; } /* Hardware expects descriptor in little endian format */ - raw_desc->m0 = cpu_to_le64(tail); raw_desc->m1 = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) | - SET_VAL(BUFDATALEN, skb->len) | + SET_VAL(BUFDATALEN, hw_len) | SET_BIT(COHERENT)); + + raw_desc->m0 = cpu_to_le64(SET_VAL(USERINFO, tail)); hopinfo = xgene_enet_work_msg(skb); raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) | hopinfo); tx_ring->cp_ring->cp_skb[tail] = skb; - return 0; + tail = (tail + 1) & (tx_ring->slots - 1); + tx_ring->tail = tail; + + return count; } static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, @@ -257,6 +271,7 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, struct xgene_enet_desc_ring *tx_ring = pdata->tx_ring; struct xgene_enet_desc_ring *cp_ring = tx_ring->cp_ring; u32 tx_level, cq_level; + int count; tx_level = pdata->ring_ops->len(tx_ring); cq_level = pdata->ring_ops->len(cp_ring); @@ -266,14 +281,14 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, return NETDEV_TX_BUSY; } - if (xgene_enet_setup_tx_desc(tx_ring, skb)) { + count = xgene_enet_setup_tx_desc(tx_ring, skb); + if (count <= 0) { dev_kfree_skb_any(skb); return NETDEV_TX_OK; } - pdata->ring_ops->wr_cmd(tx_ring, 1); + pdata->ring_ops->wr_cmd(tx_ring, count); skb_tx_timestamp(skb); - tx_ring->tail = (tx_ring->tail + 1) & (tx_ring->slots - 1); pdata->stats.tx_packets++; pdata->stats.tx_bytes += skb->len; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 1c85fc87703ab..2ac547e0c9986 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -40,6 +40,7 @@ #define XGENE_DRV_VERSION "v1.0" #define XGENE_ENET_MAX_MTU 1536 #define SKB_BUFFER_SIZE (XGENE_ENET_MAX_MTU - NET_IP_ALIGN) +#define BUFLEN_16K (16 * 1024) #define NUM_PKT_BUF 64 #define NUM_BUFPOOL 32 -- GitLab From 9b00eb494dc7c19ee69afef46e864f842cc1824f Mon Sep 17 00:00:00 2001 From: Iyappan Subramanian Date: Wed, 26 Aug 2015 11:48:06 -0700 Subject: [PATCH 5202/7006] drivers: net: xgene: Adding support for TSO Signed-off-by: Iyappan Subramanian Signed-off-by: David S. Miller --- .../net/ethernet/apm/xgene/xgene_enet_hw.h | 16 +- .../net/ethernet/apm/xgene/xgene_enet_main.c | 249 ++++++++++++++++-- .../net/ethernet/apm/xgene/xgene_enet_main.h | 11 + .../net/ethernet/apm/xgene/xgene_enet_xgmac.c | 8 +- .../net/ethernet/apm/xgene/xgene_enet_xgmac.h | 2 + 5 files changed, 262 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h index 541bed0560126..ff05bbcff26dc 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.h @@ -193,12 +193,16 @@ enum xgene_enet_rm { #define USERINFO_LEN 32 #define FPQNUM_POS 32 #define FPQNUM_LEN 12 +#define NV_POS 50 +#define NV_LEN 1 +#define LL_POS 51 +#define LL_LEN 1 #define LERR_POS 60 #define LERR_LEN 3 #define STASH_POS 52 #define STASH_LEN 2 #define BUFDATALEN_POS 48 -#define BUFDATALEN_LEN 12 +#define BUFDATALEN_LEN 15 #define DATAADDR_POS 0 #define DATAADDR_LEN 42 #define COHERENT_POS 63 @@ -215,9 +219,19 @@ enum xgene_enet_rm { #define IPHDR_LEN 6 #define EC_POS 22 /* Enable checksum */ #define EC_LEN 1 +#define ET_POS 23 /* Enable TSO */ #define IS_POS 24 /* IP protocol select */ #define IS_LEN 1 #define TYPE_ETH_WORK_MESSAGE_POS 44 +#define LL_BYTES_MSB_POS 56 +#define LL_BYTES_MSB_LEN 8 +#define LL_BYTES_LSB_POS 48 +#define LL_BYTES_LSB_LEN 12 +#define LL_LEN_POS 48 +#define LL_LEN_LEN 8 +#define DATALEN_MASK GENMASK(11, 0) + +#define LAST_BUFFER (0x7800ULL << BUFDATALEN_POS) struct xgene_enet_raw_desc { __le64 m0; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c index 652b4c3ff05ca..b330cb6fa8bba 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c @@ -147,18 +147,27 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, { struct sk_buff *skb; struct device *dev; + skb_frag_t *frag; + dma_addr_t *frag_dma_addr; u16 skb_index; u8 status; - int ret = 0; + int i, ret = 0; skb_index = GET_VAL(USERINFO, le64_to_cpu(raw_desc->m0)); skb = cp_ring->cp_skb[skb_index]; + frag_dma_addr = &cp_ring->frag_dma_addr[skb_index * MAX_SKB_FRAGS]; dev = ndev_to_dev(cp_ring->ndev); dma_unmap_single(dev, GET_VAL(DATAADDR, le64_to_cpu(raw_desc->m1)), - GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)), + skb_headlen(skb), DMA_TO_DEVICE); + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { + frag = &skb_shinfo(skb)->frags[i]; + dma_unmap_page(dev, frag_dma_addr[i], skb_frag_size(frag), + DMA_TO_DEVICE); + } + /* Checking for error */ status = GET_VAL(LERR, le64_to_cpu(raw_desc->m0)); if (unlikely(status > 2)) { @@ -179,12 +188,16 @@ static int xgene_enet_tx_completion(struct xgene_enet_desc_ring *cp_ring, static u64 xgene_enet_work_msg(struct sk_buff *skb) { + struct net_device *ndev = skb->dev; + struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct iphdr *iph; - u8 l3hlen, l4hlen = 0; - u8 csum_enable = 0; - u8 proto = 0; - u8 ethhdr; - u64 hopinfo; + u8 l3hlen = 0, l4hlen = 0; + u8 ethhdr, proto = 0, csum_enable = 0; + u64 hopinfo = 0; + u32 hdr_len, mss = 0; + u32 i, len, nr_frags; + + ethhdr = xgene_enet_hdr_len(skb->data); if (unlikely(skb->protocol != htons(ETH_P_IP)) && unlikely(skb->protocol != htons(ETH_P_8021Q))) @@ -201,14 +214,40 @@ static u64 xgene_enet_work_msg(struct sk_buff *skb) l4hlen = tcp_hdrlen(skb) >> 2; csum_enable = 1; proto = TSO_IPPROTO_TCP; + if (ndev->features & NETIF_F_TSO) { + hdr_len = ethhdr + ip_hdrlen(skb) + tcp_hdrlen(skb); + mss = skb_shinfo(skb)->gso_size; + + if (skb_is_nonlinear(skb)) { + len = skb_headlen(skb); + nr_frags = skb_shinfo(skb)->nr_frags; + + for (i = 0; i < 2 && i < nr_frags; i++) + len += skb_shinfo(skb)->frags[i].size; + + /* HW requires header must reside in 3 buffer */ + if (unlikely(hdr_len > len)) { + if (skb_linearize(skb)) + return 0; + } + } + + if (!mss || ((skb->len - hdr_len) <= mss)) + goto out; + + if (mss != pdata->mss) { + pdata->mss = mss; + pdata->mac_ops->set_mss(pdata); + } + hopinfo |= SET_BIT(ET); + } } else if (iph->protocol == IPPROTO_UDP) { l4hlen = UDP_HDR_SIZE; csum_enable = 1; } out: l3hlen = ip_hdrlen(skb) >> 2; - ethhdr = xgene_enet_hdr_len(skb->data); - hopinfo = SET_VAL(TCPHDR, l4hlen) | + hopinfo |= SET_VAL(TCPHDR, l4hlen) | SET_VAL(IPHDR, l3hlen) | SET_VAL(ETHHDR, ethhdr) | SET_VAL(EC, csum_enable) | @@ -224,20 +263,54 @@ static u16 xgene_enet_encode_len(u16 len) return (len == BUFLEN_16K) ? 0 : len; } +static void xgene_set_addr_len(__le64 *desc, u32 idx, dma_addr_t addr, u32 len) +{ + desc[idx ^ 1] = cpu_to_le64(SET_VAL(DATAADDR, addr) | + SET_VAL(BUFDATALEN, len)); +} + +static __le64 *xgene_enet_get_exp_bufs(struct xgene_enet_desc_ring *ring) +{ + __le64 *exp_bufs; + + exp_bufs = &ring->exp_bufs[ring->exp_buf_tail * MAX_EXP_BUFFS]; + memset(exp_bufs, 0, sizeof(__le64) * MAX_EXP_BUFFS); + ring->exp_buf_tail = (ring->exp_buf_tail + 1) & ((ring->slots / 2) - 1); + + return exp_bufs; +} + +static dma_addr_t *xgene_get_frag_dma_array(struct xgene_enet_desc_ring *ring) +{ + return &ring->cp_ring->frag_dma_addr[ring->tail * MAX_SKB_FRAGS]; +} + static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, struct sk_buff *skb) { struct device *dev = ndev_to_dev(tx_ring->ndev); struct xgene_enet_raw_desc *raw_desc; - dma_addr_t dma_addr; + __le64 *exp_desc = NULL, *exp_bufs = NULL; + dma_addr_t dma_addr, pbuf_addr, *frag_dma_addr; + skb_frag_t *frag; u16 tail = tx_ring->tail; u64 hopinfo; u32 len, hw_len; - u8 count = 1; + u8 ll = 0, nv = 0, idx = 0; + bool split = false; + u32 size, offset, ell_bytes = 0; + u32 i, fidx, nr_frags, count = 1; raw_desc = &tx_ring->raw_desc[tail]; + tail = (tail + 1) & (tx_ring->slots - 1); memset(raw_desc, 0, sizeof(struct xgene_enet_raw_desc)); + hopinfo = xgene_enet_work_msg(skb); + if (!hopinfo) + return -EINVAL; + raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) | + hopinfo); + len = skb_headlen(skb); hw_len = xgene_enet_encode_len(len); @@ -252,13 +325,100 @@ static int xgene_enet_setup_tx_desc(struct xgene_enet_desc_ring *tx_ring, SET_VAL(BUFDATALEN, hw_len) | SET_BIT(COHERENT)); - raw_desc->m0 = cpu_to_le64(SET_VAL(USERINFO, tail)); - hopinfo = xgene_enet_work_msg(skb); - raw_desc->m3 = cpu_to_le64(SET_VAL(HENQNUM, tx_ring->dst_ring_num) | - hopinfo); - tx_ring->cp_ring->cp_skb[tail] = skb; + if (!skb_is_nonlinear(skb)) + goto out; + /* scatter gather */ + nv = 1; + exp_desc = (void *)&tx_ring->raw_desc[tail]; tail = (tail + 1) & (tx_ring->slots - 1); + memset(exp_desc, 0, sizeof(struct xgene_enet_raw_desc)); + + nr_frags = skb_shinfo(skb)->nr_frags; + for (i = nr_frags; i < 4 ; i++) + exp_desc[i ^ 1] = cpu_to_le64(LAST_BUFFER); + + frag_dma_addr = xgene_get_frag_dma_array(tx_ring); + + for (i = 0, fidx = 0; split || (fidx < nr_frags); i++) { + if (!split) { + frag = &skb_shinfo(skb)->frags[fidx]; + size = skb_frag_size(frag); + offset = 0; + + pbuf_addr = skb_frag_dma_map(dev, frag, 0, size, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, pbuf_addr)) + return -EINVAL; + + frag_dma_addr[fidx] = pbuf_addr; + fidx++; + + if (size > BUFLEN_16K) + split = true; + } + + if (size > BUFLEN_16K) { + len = BUFLEN_16K; + size -= BUFLEN_16K; + } else { + len = size; + split = false; + } + + dma_addr = pbuf_addr + offset; + hw_len = xgene_enet_encode_len(len); + + switch (i) { + case 0: + case 1: + case 2: + xgene_set_addr_len(exp_desc, i, dma_addr, hw_len); + break; + case 3: + if (split || (fidx != nr_frags)) { + exp_bufs = xgene_enet_get_exp_bufs(tx_ring); + xgene_set_addr_len(exp_bufs, idx, dma_addr, + hw_len); + idx++; + ell_bytes += len; + } else { + xgene_set_addr_len(exp_desc, i, dma_addr, + hw_len); + } + break; + default: + xgene_set_addr_len(exp_bufs, idx, dma_addr, hw_len); + idx++; + ell_bytes += len; + break; + } + + if (split) + offset += BUFLEN_16K; + } + count++; + + if (idx) { + ll = 1; + dma_addr = dma_map_single(dev, exp_bufs, + sizeof(u64) * MAX_EXP_BUFFS, + DMA_TO_DEVICE); + if (dma_mapping_error(dev, dma_addr)) { + dev_kfree_skb_any(skb); + return -EINVAL; + } + i = ell_bytes >> LL_BYTES_LSB_LEN; + exp_desc[2] = cpu_to_le64(SET_VAL(DATAADDR, dma_addr) | + SET_VAL(LL_BYTES_MSB, i) | + SET_VAL(LL_LEN, idx)); + raw_desc->m2 = cpu_to_le64(SET_VAL(LL_BYTES_LSB, ell_bytes)); + } + +out: + raw_desc->m0 = cpu_to_le64(SET_VAL(LL, ll) | SET_VAL(NV, nv) | + SET_VAL(USERINFO, tx_ring->tail)); + tx_ring->cp_ring->cp_skb[tx_ring->tail] = skb; tx_ring->tail = tail; return count; @@ -281,6 +441,9 @@ static netdev_tx_t xgene_enet_start_xmit(struct sk_buff *skb, return NETDEV_TX_BUSY; } + if (skb_padto(skb, XGENE_MIN_ENET_FRAME_SIZE)) + return NETDEV_TX_OK; + count = xgene_enet_setup_tx_desc(tx_ring, skb); if (count <= 0) { dev_kfree_skb_any(skb); @@ -341,7 +504,7 @@ static int xgene_enet_rx_frame(struct xgene_enet_desc_ring *rx_ring, /* strip off CRC as HW isn't doing this */ datalen = GET_VAL(BUFDATALEN, le64_to_cpu(raw_desc->m1)); - datalen -= 4; + datalen = (datalen & DATALEN_MASK) - 4; prefetch(skb->data - NET_IP_ALIGN); skb_put(skb, datalen); @@ -373,26 +536,41 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, int budget) { struct xgene_enet_pdata *pdata = netdev_priv(ring->ndev); - struct xgene_enet_raw_desc *raw_desc; + struct xgene_enet_raw_desc *raw_desc, *exp_desc; u16 head = ring->head; u16 slots = ring->slots - 1; - int ret, count = 0; + int ret, count = 0, processed = 0; do { raw_desc = &ring->raw_desc[head]; + exp_desc = NULL; if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc))) break; /* read fpqnum field after dataaddr field */ dma_rmb(); + if (GET_BIT(NV, le64_to_cpu(raw_desc->m0))) { + head = (head + 1) & slots; + exp_desc = &ring->raw_desc[head]; + + if (unlikely(xgene_enet_is_desc_slot_empty(exp_desc))) { + head = (head - 1) & slots; + break; + } + dma_rmb(); + count++; + } if (is_rx_desc(raw_desc)) ret = xgene_enet_rx_frame(ring, raw_desc); else ret = xgene_enet_tx_completion(ring, raw_desc); xgene_enet_mark_desc_slot_empty(raw_desc); + if (exp_desc) + xgene_enet_mark_desc_slot_empty(exp_desc); head = (head + 1) & slots; count++; + processed++; if (ret) break; @@ -408,7 +586,7 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring, } } - return count; + return processed; } static int xgene_enet_napi(struct napi_struct *napi, const int budget) @@ -753,12 +931,13 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) struct xgene_enet_desc_ring *rx_ring, *tx_ring, *cp_ring; struct xgene_enet_desc_ring *buf_pool = NULL; enum xgene_ring_owner owner; + dma_addr_t dma_exp_bufs; u8 cpu_bufnum = pdata->cpu_bufnum; u8 eth_bufnum = pdata->eth_bufnum; u8 bp_bufnum = pdata->bp_bufnum; u16 ring_num = pdata->ring_num; u16 ring_id; - int ret; + int ret, size; /* allocate rx descriptor ring */ owner = xgene_derive_ring_owner(pdata); @@ -809,6 +988,15 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) ret = -ENOMEM; goto err; } + + size = (tx_ring->slots / 2) * sizeof(__le64) * MAX_EXP_BUFFS; + tx_ring->exp_bufs = dma_zalloc_coherent(dev, size, &dma_exp_bufs, + GFP_KERNEL); + if (!tx_ring->exp_bufs) { + ret = -ENOMEM; + goto err; + } + pdata->tx_ring = tx_ring; if (!pdata->cq_cnt) { @@ -833,6 +1021,16 @@ static int xgene_enet_create_desc_rings(struct net_device *ndev) ret = -ENOMEM; goto err; } + + size = sizeof(dma_addr_t) * MAX_SKB_FRAGS; + cp_ring->frag_dma_addr = devm_kcalloc(dev, tx_ring->slots, + size, GFP_KERNEL); + if (!cp_ring->frag_dma_addr) { + devm_kfree(dev, cp_ring->cp_skb); + ret = -ENOMEM; + goto err; + } + pdata->tx_ring->cp_ring = cp_ring; pdata->tx_ring->dst_ring_num = xgene_enet_dst_ring_num(cp_ring); @@ -1188,7 +1386,8 @@ static int xgene_enet_probe(struct platform_device *pdev) xgene_enet_set_ethtool_ops(ndev); ndev->features |= NETIF_F_IP_CSUM | NETIF_F_GSO | - NETIF_F_GRO; + NETIF_F_GRO | + NETIF_F_SG; of_id = of_match_device(xgene_enet_of_match, &pdev->dev); if (of_id) { @@ -1214,6 +1413,12 @@ static int xgene_enet_probe(struct platform_device *pdev) xgene_enet_setup_ops(pdata); + if (pdata->phy_mode == PHY_INTERFACE_MODE_XGMII) { + ndev->features |= NETIF_F_TSO; + pdata->mss = XGENE_ENET_MSS; + } + ndev->hw_features = ndev->features; + ret = register_netdev(ndev); if (ret) { netdev_err(ndev, "Failed to register netdev\n"); diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h index 2ac547e0c9986..50f92c39ed2a2 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h @@ -43,6 +43,9 @@ #define BUFLEN_16K (16 * 1024) #define NUM_PKT_BUF 64 #define NUM_BUFPOOL 32 +#define MAX_EXP_BUFFS 256 +#define XGENE_ENET_MSS 1448 +#define XGENE_MIN_ENET_FRAME_SIZE 60 #define START_CPU_BUFNUM_0 0 #define START_ETH_BUFNUM_0 2 @@ -80,6 +83,7 @@ struct xgene_enet_desc_ring { u16 num; u16 head; u16 tail; + u16 exp_buf_tail; u16 slots; u16 irq; char irq_name[IRQ_ID_SIZE]; @@ -94,6 +98,7 @@ struct xgene_enet_desc_ring { u8 nbufpool; struct sk_buff *(*rx_skb); struct sk_buff *(*cp_skb); + dma_addr_t *frag_dma_addr; enum xgene_enet_ring_cfgsize cfgsize; struct xgene_enet_desc_ring *cp_ring; struct xgene_enet_desc_ring *buf_pool; @@ -103,6 +108,7 @@ struct xgene_enet_desc_ring { struct xgene_enet_raw_desc *raw_desc; struct xgene_enet_raw_desc16 *raw_desc16; }; + __le64 *exp_bufs; }; struct xgene_mac_ops { @@ -113,6 +119,7 @@ struct xgene_mac_ops { void (*tx_disable)(struct xgene_enet_pdata *pdata); void (*rx_disable)(struct xgene_enet_pdata *pdata); void (*set_mac_addr)(struct xgene_enet_pdata *pdata); + void (*set_mss)(struct xgene_enet_pdata *pdata); void (*link_state)(struct work_struct *work); }; @@ -171,6 +178,7 @@ struct xgene_enet_pdata { u8 eth_bufnum; u8 bp_bufnum; u16 ring_num; + u32 mss; }; struct xgene_indirect_ctl { @@ -205,6 +213,9 @@ static inline u64 xgene_enet_get_field_value(int pos, int len, u64 src) #define GET_VAL(field, src) \ xgene_enet_get_field_value(field ## _POS, field ## _LEN, src) +#define GET_BIT(field, src) \ + xgene_enet_get_field_value(field ## _POS, 1, src) + static inline struct device *ndev_to_dev(struct net_device *ndev) { return ndev->dev.parent; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c index 05edb847cf261..7a28a48cb2c77 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.c @@ -184,6 +184,11 @@ static void xgene_xgmac_set_mac_addr(struct xgene_enet_pdata *pdata) xgene_enet_wr_mac(pdata, HSTMACADR_MSW_ADDR, addr1); } +static void xgene_xgmac_set_mss(struct xgene_enet_pdata *pdata) +{ + xgene_enet_wr_csr(pdata, XG_TSIF_MSS_REG0_ADDR, pdata->mss); +} + static u32 xgene_enet_link_status(struct xgene_enet_pdata *pdata) { u32 data; @@ -204,8 +209,8 @@ static void xgene_xgmac_init(struct xgene_enet_pdata *pdata) data &= ~HSTLENCHK; xgene_enet_wr_mac(pdata, AXGMAC_CONFIG_1, data); - xgene_enet_wr_mac(pdata, HSTMAXFRAME_LENGTH_ADDR, 0x06000600); xgene_xgmac_set_mac_addr(pdata); + xgene_xgmac_set_mss(pdata); xgene_enet_rd_csr(pdata, XG_RSIF_CONFIG_REG_ADDR, &data); data |= CFG_RSIF_FPBUFF_TIMEOUT_EN; @@ -329,6 +334,7 @@ struct xgene_mac_ops xgene_xgmac_ops = { .rx_disable = xgene_xgmac_rx_disable, .tx_disable = xgene_xgmac_tx_disable, .set_mac_addr = xgene_xgmac_set_mac_addr, + .set_mss = xgene_xgmac_set_mss, .link_state = xgene_enet_link_state }; diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h index bf0a994357370..f8f908dbf51c1 100644 --- a/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h +++ b/drivers/net/ethernet/apm/xgene/xgene_enet_xgmac.h @@ -62,7 +62,9 @@ #define XCLE_BYPASS_REG0_ADDR 0x0160 #define XCLE_BYPASS_REG1_ADDR 0x0164 #define XG_CFG_BYPASS_ADDR 0x0204 +#define XG_CFG_LINK_AGGR_RESUME_0_ADDR 0x0214 #define XG_LINK_STATUS_ADDR 0x0228 +#define XG_TSIF_MSS_REG0_ADDR 0x02a4 #define XG_ENET_SPARE_CFG_REG_ADDR 0x040c #define XG_ENET_SPARE_CFG_REG_1_ADDR 0x0410 #define XGENET_RX_DV_GATE_REG_0_ADDR 0x0804 -- GitLab From 0118e01935cae83261f1c52f1c88c6514ef330f6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 26 Aug 2015 11:49:35 -0700 Subject: [PATCH 5203/7006] smsc9194: Remove uncompilable #if 0'd use of pr_dbg No pr_dbg method exists. While this code is #if 0'd, it'd be nicer to use the generic hex_dump, so use it instead. Signed-off-by: Joe Perches Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smc9194.c | 32 ++--------------------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/drivers/net/ethernet/smsc/smc9194.c b/drivers/net/ethernet/smsc/smc9194.c index 67d9fdeedd86d..664f596971b5f 100644 --- a/drivers/net/ethernet/smsc/smc9194.c +++ b/drivers/net/ethernet/smsc/smc9194.c @@ -1031,36 +1031,8 @@ err_out: static void print_packet( byte * buf, int length ) { #if 0 - int i; - int remainder; - int lines; - - pr_dbg("Packet of length %d\n", length); - lines = length / 16; - remainder = length % 16; - - for ( i = 0; i < lines ; i ++ ) { - int cur; - - printk(KERN_DEBUG); - for ( cur = 0; cur < 8; cur ++ ) { - byte a, b; - - a = *(buf ++ ); - b = *(buf ++ ); - pr_cont("%02x%02x ", a, b); - } - pr_cont("\n"); - } - printk(KERN_DEBUG); - for ( i = 0; i < remainder/2 ; i++ ) { - byte a, b; - - a = *(buf ++ ); - b = *(buf ++ ); - pr_cont("%02x%02x ", a, b); - } - pr_cont("\n"); + print_hex_dump_debug(DRV_NAME, DUMP_PREFIX_OFFSET, 16, 1, + buf, length, true); #endif } #endif -- GitLab From 3b3ae880266d148bf73a573a766bc9b78c08d805 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 26 Aug 2015 23:00:06 +0200 Subject: [PATCH 5204/7006] net: sched: consolidate tc_classify{,_compat} For classifiers getting invoked via tc_classify(), we always need an extra function call into tc_classify_compat(), as both are being exported as symbols and tc_classify() itself doesn't do much except handling of reclassifications when tp->classify() returned with TC_ACT_RECLASSIFY. CBQ and ATM are the only qdiscs that directly call into tc_classify_compat(), all others use tc_classify(). When tc actions are being configured out in the kernel, tc_classify() effectively does nothing besides delegating. We could spare this layer and consolidate both functions. pktgen on single CPU constantly pushing skbs directly into the netif_receive_skb() path with a dummy classifier on ingress qdisc attached, improves slightly from 22.3Mpps to 23.1Mpps. Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 4 +-- net/core/dev.c | 2 +- net/sched/sch_api.c | 55 ++++++++++++++++++---------------------- net/sched/sch_atm.c | 2 +- net/sched/sch_cbq.c | 2 +- net/sched/sch_choke.c | 2 +- net/sched/sch_drr.c | 2 +- net/sched/sch_dsmark.c | 2 +- net/sched/sch_fq_codel.c | 2 +- net/sched/sch_hfsc.c | 2 +- net/sched/sch_htb.c | 2 +- net/sched/sch_multiq.c | 2 +- net/sched/sch_prio.c | 2 +- net/sched/sch_qfq.c | 2 +- net/sched/sch_sfb.c | 2 +- net/sched/sch_sfq.c | 2 +- 16 files changed, 40 insertions(+), 47 deletions(-) diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index 2342bf12cb78a..401038d2f9b88 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -110,10 +110,8 @@ static inline void qdisc_run(struct Qdisc *q) __qdisc_run(q); } -int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp, - struct tcf_result *res); int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, - struct tcf_result *res); + struct tcf_result *res, bool compat_mode); static inline __be16 tc_skb_protocol(const struct sk_buff *skb) { diff --git a/net/core/dev.c b/net/core/dev.c index b1f3f4844e60c..7bb24f1879b89 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -3657,7 +3657,7 @@ static inline struct sk_buff *handle_ing(struct sk_buff *skb, skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); qdisc_bstats_cpu_update(cl->q, skb); - switch (tc_classify(skb, cl, &cl_res)) { + switch (tc_classify(skb, cl, &cl_res, false)) { case TC_ACT_OK: case TC_ACT_RECLASSIFY: skb->tc_index = TC_H_MIN(cl_res.classid); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index f06aa01d60fd3..59c227f26b56f 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1806,51 +1806,46 @@ done: * to this qdisc, (optionally) tests for protocol and asks * specific classifiers. */ -int tc_classify_compat(struct sk_buff *skb, const struct tcf_proto *tp, - struct tcf_result *res) +int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, + struct tcf_result *res, bool compat_mode) { __be16 protocol = tc_skb_protocol(skb); - int err; +#ifdef CONFIG_NET_CLS_ACT + const struct tcf_proto *old_tp = tp; + int limit = 0; +reclassify: +#endif for (; tp; tp = rcu_dereference_bh(tp->next)) { + int err; + if (tp->protocol != protocol && tp->protocol != htons(ETH_P_ALL)) continue; - err = tp->classify(skb, tp, res); + err = tp->classify(skb, tp, res); +#ifdef CONFIG_NET_CLS_ACT + if (unlikely(err == TC_ACT_RECLASSIFY && + !compat_mode)) + goto reset; +#endif if (err >= 0) return err; } - return -1; -} -EXPORT_SYMBOL(tc_classify_compat); -int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, - struct tcf_result *res) -{ - int err = 0; -#ifdef CONFIG_NET_CLS_ACT - const struct tcf_proto *otp = tp; - int limit = 0; -reclassify: -#endif - - err = tc_classify_compat(skb, tp, res); + return -1; #ifdef CONFIG_NET_CLS_ACT - if (err == TC_ACT_RECLASSIFY) { - tp = otp; - - if (unlikely(limit++ >= MAX_REC_LOOP)) { - net_notice_ratelimited("%s: packet reclassify loop rule prio %u protocol %02x\n", - tp->q->ops->id, - tp->prio & 0xffff, - ntohs(tp->protocol)); - return TC_ACT_SHOT; - } - goto reclassify; +reset: + if (unlikely(limit++ >= MAX_REC_LOOP)) { + net_notice_ratelimited("%s: reclassify loop, rule prio %u, " + "protocol %02x\n", tp->q->ops->id, + tp->prio & 0xffff, ntohs(tp->protocol)); + return TC_ACT_SHOT; } + + tp = old_tp; + goto reclassify; #endif - return err; } EXPORT_SYMBOL(tc_classify); diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index e3e2cc5fd0689..1911af3ca7c01 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -375,7 +375,7 @@ static int atm_tc_enqueue(struct sk_buff *skb, struct Qdisc *sch) list_for_each_entry(flow, &p->flows, list) { fl = rcu_dereference_bh(flow->filter_list); if (fl) { - result = tc_classify_compat(skb, fl, &res); + result = tc_classify(skb, fl, &res, true); if (result < 0) continue; flow = (struct atm_flow_data *)res.class; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index beeb75f80fdb9..c538d9e4a8f6c 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -240,7 +240,7 @@ cbq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) /* * Step 2+n. Apply classifier. */ - result = tc_classify_compat(skb, fl, &res); + result = tc_classify(skb, fl, &res, true); if (!fl || result < 0) goto fallback; diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 6a783afe49600..665bde07916b8 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -201,7 +201,7 @@ static bool choke_classify(struct sk_buff *skb, int result; fl = rcu_dereference_bh(q->filter_list); - result = tc_classify(skb, fl, &res); + result = tc_classify(skb, fl, &res, false); if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c index 338706092c27d..f26bdea875c1a 100644 --- a/net/sched/sch_drr.c +++ b/net/sched/sch_drr.c @@ -331,7 +331,7 @@ static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch, *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; fl = rcu_dereference_bh(q->filter_list); - result = tc_classify(skb, fl, &res); + result = tc_classify(skb, fl, &res, false); if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index 66700a6116aa9..c4d45fd8c551e 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -230,7 +230,7 @@ static int dsmark_enqueue(struct sk_buff *skb, struct Qdisc *sch) else { struct tcf_result res; struct tcf_proto *fl = rcu_dereference_bh(p->filter_list); - int result = tc_classify(skb, fl, &res); + int result = tc_classify(skb, fl, &res, false); pr_debug("result %d class 0x%04x\n", result, res.classid); diff --git a/net/sched/sch_fq_codel.c b/net/sched/sch_fq_codel.c index a9ba030435a2a..4c834e93dafbe 100644 --- a/net/sched/sch_fq_codel.c +++ b/net/sched/sch_fq_codel.c @@ -92,7 +92,7 @@ static unsigned int fq_codel_classify(struct sk_buff *skb, struct Qdisc *sch, return fq_codel_hash(q, skb) + 1; *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; - result = tc_classify(skb, filter, &res); + result = tc_classify(skb, filter, &res, false); if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index e6c7416d03321..b7ebe2c875864 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -1165,7 +1165,7 @@ hfsc_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; head = &q->root; tcf = rcu_dereference_bh(q->root.filter_list); - while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { + while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { case TC_ACT_QUEUED: diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index cf4b0f865d1bc..15ccd7f8fb2ae 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -229,7 +229,7 @@ static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch, } *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; - while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) { + while (tcf && (result = tc_classify(skb, tcf, &res, false)) >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { case TC_ACT_QUEUED: diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 42dd218871e09..4e904ca0af9d1 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -46,7 +46,7 @@ multiq_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) int err; *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; - err = tc_classify(skb, fl, &res); + err = tc_classify(skb, fl, &res, false); #ifdef CONFIG_NET_CLS_ACT switch (err) { case TC_ACT_STOLEN: diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 8e5cd34aaa74d..ba6487f2741f9 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -42,7 +42,7 @@ prio_classify(struct sk_buff *skb, struct Qdisc *sch, int *qerr) *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; if (TC_H_MAJ(skb->priority) != sch->handle) { fl = rcu_dereference_bh(q->filter_list); - err = tc_classify(skb, fl, &res); + err = tc_classify(skb, fl, &res, false); #ifdef CONFIG_NET_CLS_ACT switch (err) { case TC_ACT_STOLEN: diff --git a/net/sched/sch_qfq.c b/net/sched/sch_qfq.c index ffaeea63d4738..3dc3a6e560520 100644 --- a/net/sched/sch_qfq.c +++ b/net/sched/sch_qfq.c @@ -717,7 +717,7 @@ static struct qfq_class *qfq_classify(struct sk_buff *skb, struct Qdisc *sch, *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; fl = rcu_dereference_bh(q->filter_list); - result = tc_classify(skb, fl, &res); + result = tc_classify(skb, fl, &res, false); if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { diff --git a/net/sched/sch_sfb.c b/net/sched/sch_sfb.c index dcdff5c769a1c..5bbb6332ec574 100644 --- a/net/sched/sch_sfb.c +++ b/net/sched/sch_sfb.c @@ -258,7 +258,7 @@ static bool sfb_classify(struct sk_buff *skb, struct tcf_proto *fl, struct tcf_result res; int result; - result = tc_classify(skb, fl, &res); + result = tc_classify(skb, fl, &res, false); if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 52f75a5473e12..3abab534eb5cd 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -179,7 +179,7 @@ static unsigned int sfq_classify(struct sk_buff *skb, struct Qdisc *sch, return sfq_hash(q, skb) + 1; *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; - result = tc_classify(skb, fl, &res); + result = tc_classify(skb, fl, &res, false); if (result >= 0) { #ifdef CONFIG_NET_CLS_ACT switch (result) { -- GitLab From 4fa7508e9f1c64ae39516e40ee5495aaa4616ad7 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 Aug 2015 20:27:04 -0700 Subject: [PATCH 5205/7006] device property: Return -ENXIO if there is no suitable FW interface Return -ENXIO if device property array access functions don't find a suitable firmware interface. This lets drivers decide if they should use available platform data instead. Cc: Rafael J. Wysocki Signed-off-by: Guenter Roeck Tested-by: Jeremy Linton Signed-off-by: David S. Miller --- drivers/base/property.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/base/property.c b/drivers/base/property.c index 4c20828993222..a5efb43258a9f 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -155,6 +155,7 @@ EXPORT_SYMBOL_GPL(fwnode_property_present); * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, * %-EOVERFLOW if the size of the property is not as expected. + * %-ENXIO if no suitable firmware interface is present. */ int device_property_read_u8_array(struct device *dev, const char *propname, u8 *val, size_t nval) @@ -179,6 +180,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u8_array); * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, * %-EOVERFLOW if the size of the property is not as expected. + * %-ENXIO if no suitable firmware interface is present. */ int device_property_read_u16_array(struct device *dev, const char *propname, u16 *val, size_t nval) @@ -203,6 +205,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u16_array); * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, * %-EOVERFLOW if the size of the property is not as expected. + * %-ENXIO if no suitable firmware interface is present. */ int device_property_read_u32_array(struct device *dev, const char *propname, u32 *val, size_t nval) @@ -227,6 +230,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u32_array); * %-ENODATA if the property does not have a value, * %-EPROTO if the property is not an array of numbers, * %-EOVERFLOW if the size of the property is not as expected. + * %-ENXIO if no suitable firmware interface is present. */ int device_property_read_u64_array(struct device *dev, const char *propname, u64 *val, size_t nval) @@ -251,6 +255,7 @@ EXPORT_SYMBOL_GPL(device_property_read_u64_array); * %-ENODATA if the property does not have a value, * %-EPROTO or %-EILSEQ if the property is not an array of strings, * %-EOVERFLOW if the size of the property is not as expected. + * %-ENXIO if no suitable firmware interface is present. */ int device_property_read_string_array(struct device *dev, const char *propname, const char **val, size_t nval) @@ -272,6 +277,7 @@ EXPORT_SYMBOL_GPL(device_property_read_string_array); * %-EINVAL if given arguments are not valid, * %-ENODATA if the property does not have a value, * %-EPROTO or %-EILSEQ if the property type is not a string. + * %-ENXIO if no suitable firmware interface is present. */ int device_property_read_string(struct device *dev, const char *propname, const char **val) @@ -293,9 +299,11 @@ EXPORT_SYMBOL_GPL(device_property_read_string); else if (is_acpi_node(_fwnode_)) \ _ret_ = acpi_dev_prop_read(to_acpi_node(_fwnode_), _propname_, \ _proptype_, _val_, _nval_); \ - else \ + else if (is_pset(_fwnode_)) \ _ret_ = pset_prop_read_array(to_pset(_fwnode_), _propname_, \ _proptype_, _val_, _nval_); \ + else \ + _ret_ = -ENXIO; \ _ret_; \ }) @@ -433,9 +441,10 @@ int fwnode_property_read_string_array(struct fwnode_handle *fwnode, else if (is_acpi_node(fwnode)) return acpi_dev_prop_read(to_acpi_node(fwnode), propname, DEV_PROP_STRING, val, nval); - - return pset_prop_read_array(to_pset(fwnode), propname, - DEV_PROP_STRING, val, nval); + else if (is_pset(fwnode)) + return pset_prop_read_array(to_pset(fwnode), propname, + DEV_PROP_STRING, val, nval); + return -ENXIO; } EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); -- GitLab From 31cb5c9e69cedd4bdd7bb7b442582914ceae8c2b Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 26 Aug 2015 20:27:05 -0700 Subject: [PATCH 5206/7006] smsc911x: Ignore error return from device_get_phy_mode() Commit 62ee783bf1f8 ("smsc911x: Fix crash seen if neither ACPI nor OF is configured or used") introduces an error check for the return value from device_get_phy_mode() and bails out if there is an error. Unfortunately, there are configurations where no phy is configured. Those configurations now fail. To fix the problem, accept error returns from device_get_phy_mode(), and use the return value from device_property_read_u32() to determine if there is a suitable firmware interface to read the configuration. Fixes: 62ee783bf1f8 ("smsc911x: Fix crash seen if neither ACPI nor OF is configured or used") Tested-by: Tony Lindgren Signed-off-by: Guenter Roeck Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smsc911x.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 6eef3251d8333..c8b26259c9cf5 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2369,23 +2369,25 @@ static int smsc911x_probe_config(struct smsc911x_platform_config *config, { int phy_interface; u32 width = 0; + int err; phy_interface = device_get_phy_mode(dev); if (phy_interface < 0) - return phy_interface; - + phy_interface = PHY_INTERFACE_MODE_NA; config->phy_interface = phy_interface; device_get_mac_address(dev, config->mac, ETH_ALEN); - device_property_read_u32(dev, "reg-shift", &config->shift); - - device_property_read_u32(dev, "reg-io-width", &width); - if (width == 4) + err = device_property_read_u32(dev, "reg-io-width", &width); + if (err == -ENXIO) + return err; + if (!err && width == 4) config->flags |= SMSC911X_USE_32BIT; else config->flags |= SMSC911X_USE_16BIT; + device_property_read_u32(dev, "reg-shift", &config->shift); + if (device_property_present(dev, "smsc,irq-active-high")) config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH; -- GitLab From 3f1d44ae640172482a8c0125efe9ca93331b056b Mon Sep 17 00:00:00 2001 From: David Howells Date: Thu, 27 Aug 2015 11:13:36 +0100 Subject: [PATCH 5207/7006] Documentation/Changes: Now need OpenSSL devel packages for module signing The module signing script (sign-file) used to be a wrapper around the openssl program. It has now been replaced by a C program that uses the crypto library from the OpenSSL package meaning that the OpenSSL devel packages are necessary to provide the devel library link and the header files. This would be openssl-devel on Fedora and libssl-dev on Debian. Reported-by: Stephen Rothwell Signed-off-by: David Howells Acked-by: Stephen Rothwell Signed-off-by: James Morris --- Documentation/Changes | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Documentation/Changes b/Documentation/Changes index 646cdaa6e9d13..6d88630048582 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -43,6 +43,7 @@ o udev 081 # udevd --version o grub 0.93 # grub --version || grub-install --version o mcelog 0.6 # mcelog --version o iptables 1.4.2 # iptables -V +o openssl & libcrypto 1.0.1k # openssl version Kernel compilation @@ -79,6 +80,17 @@ BC You will need bc to build kernels 3.10 and higher +OpenSSL +------- + +Module signing and external certificate handling use the OpenSSL program and +crypto library to do key creation and signature generation. + +You will need openssl to build kernels 3.7 and higher if module signing is +enabled. You will also need openssl development packages to build kernels 4.3 +and higher. + + System utilities ================ @@ -295,6 +307,10 @@ Binutils -------- o +OpenSSL +------- +o + System utilities **************** @@ -392,4 +408,3 @@ o NFS-Utils --------- o - -- GitLab From f21fb798fe38cf87b177d45820991f0e315c0ba8 Mon Sep 17 00:00:00 2001 From: Naresh Kamboju Date: Tue, 18 Aug 2015 12:31:59 +0530 Subject: [PATCH 5208/7006] selftests/zram: Adding zram tests zram: Compressed RAM based block devices ---------------------------------------- The zram module creates RAM based block devices named /dev/zram ( = 0, 1, ...). Pages written to these disks are compressed and stored in memory itself. These disks allow very fast I/O and compression provides good amounts of memory savings. Some of the usecases include /tmp storage, use as swap disks, various caches under /var and maybe many more :) Statistics for individual zram devices are exported through sysfs nodes at /sys/block/zram/ This patch is to validate the zram functionality. Test interacts with block device /dev/zram and sysfs nodes /sys/block/zram/ zram.sh: sanity check of CONFIG_ZRAM and to run zram01 and zram02 tests zram01.sh: creates general purpose ram disks with different filesystems zram02.sh: creates block device for swap zram_lib.sh: create library with initialization/cleanup functions README: ZRAM introduction and Kconfig required. Makefile: To run zram tests zram test output ----------------- ./zram.sh -------------------- running zram tests -------------------- /dev/zram0 device file found: OK set max_comp_streams to zram device(s) /sys/block/zram0/max_comp_streams = '2' (1/1) zram max streams: OK test that we can set compression algorithm supported algs: [lzo] lz4 /sys/block/zram0/comp_algorithm = 'lzo' (1/1) zram set compression algorithm: OK set disk size to zram device(s) /sys/block/zram0/disksize = '2097152' (1/1) zram set disksizes: OK set memory limit to zram device(s) /sys/block/zram0/mem_limit = '2M' (1/1) zram set memory limit: OK make ext4 filesystem on /dev/zram0 zram mkfs.ext4: OK mount /dev/zram0 zram mount of zram device(s): OK fill zram0... zram0 can be filled with '1932' KB zram used 3M, zram disk sizes 2097152M zram compression ratio: 699050.66:1: OK zram cleanup zram01 : [PASS] /dev/zram0 device file found: OK set max_comp_streams to zram device(s) /sys/block/zram0/max_comp_streams = '2' (1/1) zram max streams: OK set disk size to zram device(s) /sys/block/zram0/disksize = '1048576' (1/1) zram set disksizes: OK set memory limit to zram device(s) /sys/block/zram0/mem_limit = '1M' (1/1) zram set memory limit: OK make swap with zram device(s) done with /dev/zram0 zram making zram mkswap and swapon: OK zram swapoff: OK zram cleanup zram02 : [PASS] CC: Shuah Khan CC: Tyler Baker CC: Milosz Wasilewski CC: Alexey Kodanev Signed-off-by: Naresh Kamboju Signed-off-by: Alexey Kodanev Reviewed-By: Tyler Baker Signed-off-by: Shuah Khan --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/zram/Makefile | 12 ++ tools/testing/selftests/zram/README | 40 ++++ tools/testing/selftests/zram/zram.sh | 23 +++ tools/testing/selftests/zram/zram01.sh | 98 ++++++++++ tools/testing/selftests/zram/zram02.sh | 53 ++++++ tools/testing/selftests/zram/zram_lib.sh | 222 +++++++++++++++++++++++ 7 files changed, 449 insertions(+) create mode 100644 tools/testing/selftests/zram/Makefile create mode 100644 tools/testing/selftests/zram/README create mode 100755 tools/testing/selftests/zram/zram.sh create mode 100755 tools/testing/selftests/zram/zram01.sh create mode 100755 tools/testing/selftests/zram/zram02.sh create mode 100755 tools/testing/selftests/zram/zram_lib.sh diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 24ae9e829e9aa..9763dd95b4c82 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -22,6 +22,7 @@ endif TARGETS += user TARGETS += vm TARGETS += x86 +TARGETS += zram #Please keep the TARGETS list alphabetically sorted # Run "make quicktest=1 run_tests" or # "make quicktest=1 kselftest from top level Makefile diff --git a/tools/testing/selftests/zram/Makefile b/tools/testing/selftests/zram/Makefile new file mode 100644 index 0000000000000..ec45513c73035 --- /dev/null +++ b/tools/testing/selftests/zram/Makefile @@ -0,0 +1,12 @@ +all: + +TEST_PROGS := zram.sh +TEST_FILES := zram01.sh zram02.sh zram_lib.sh + +include ../lib.mk + +run_tests: + @/bin/bash ./zram.sh + +clean: + $(RM) err.log diff --git a/tools/testing/selftests/zram/README b/tools/testing/selftests/zram/README new file mode 100644 index 0000000000000..eb17917c8a3a5 --- /dev/null +++ b/tools/testing/selftests/zram/README @@ -0,0 +1,40 @@ +zram: Compressed RAM based block devices +---------------------------------------- +* Introduction + +The zram module creates RAM based block devices named /dev/zram +( = 0, 1, ...). Pages written to these disks are compressed and stored +in memory itself. These disks allow very fast I/O and compression provides +good amounts of memory savings. Some of the usecases include /tmp storage, +use as swap disks, various caches under /var and maybe many more :) + +Statistics for individual zram devices are exported through sysfs nodes at +/sys/block/zram/ + +Kconfig required: +CONFIG_ZRAM=y +CONFIG_ZRAM_LZ4_COMPRESS=y +CONFIG_ZPOOL=y +CONFIG_ZSMALLOC=y + +ZRAM Testcases +-------------- +zram_lib.sh: create library with initialization/cleanup functions +zram.sh: For sanity check of CONFIG_ZRAM and to run zram01 and zram02 + +Two functional tests: zram01 and zram02: +zram01.sh: creates general purpose ram disks with ext4 filesystems +zram02.sh: creates block device for swap + +Commands required for testing: + - bc + - dd + - free + - awk + - mkswap + - swapon + - swapoff + - mkfs/ mkfs.ext4 + +For more information please refer: +kernel-source-tree/Documentation/blockdev/zram.txt diff --git a/tools/testing/selftests/zram/zram.sh b/tools/testing/selftests/zram/zram.sh new file mode 100755 index 0000000000000..6ea4b6a5ccab6 --- /dev/null +++ b/tools/testing/selftests/zram/zram.sh @@ -0,0 +1,23 @@ +#!/bin/bash +TCID="zram.sh" + +run_zram () { +echo "--------------------" +echo "running zram tests" +echo "--------------------" +./zram01.sh +echo "" +./zram02.sh +} + +# check zram module exists +MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko +if [ -f $MODULE_PATH ]; then + run_zram +elif [ -b /dev/zram0 ]; then + run_zram +else + echo "$TCID : No zram.ko module or /dev/zram0 device file not found" + echo "$TCID : CONFIG_ZRAM is not set" + exit 1 +fi diff --git a/tools/testing/selftests/zram/zram01.sh b/tools/testing/selftests/zram/zram01.sh new file mode 100755 index 0000000000000..2a2475d4b201a --- /dev/null +++ b/tools/testing/selftests/zram/zram01.sh @@ -0,0 +1,98 @@ +#!/bin/bash +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# +# 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. +# +# This program is distributed in the hope that it would be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Test creates several zram devices with different filesystems on them. +# It fills each device with zeros and checks that compression works. +# +# Author: Alexey Kodanev +# Modified: Naresh Kamboju + +TCID="zram01" +ERR_CODE=0 + +. ./zram_lib.sh + +# Test will create the following number of zram devices: +dev_num=1 +# This is a list of parameters for zram devices. +# Number of items must be equal to 'dev_num' parameter. +zram_max_streams="2" + +# The zram sysfs node 'disksize' value can be either in bytes, +# or you can use mem suffixes. But in some old kernels, mem +# suffixes are not supported, for example, in RHEL6.6GA's kernel +# layer, it uses strict_strtoull() to parse disksize which does +# not support mem suffixes, in some newer kernels, they use +# memparse() which supports mem suffixes. So here we just use +# bytes to make sure everything works correctly. +zram_sizes="2097152" # 2MB +zram_mem_limits="2M" +zram_filesystems="ext4" +zram_algs="lzo" + +zram_fill_fs() +{ + local mem_free0=$(free -m | awk 'NR==2 {print $4}') + + for i in $(seq 0 $(($dev_num - 1))); do + echo "fill zram$i..." + local b=0 + while [ true ]; do + dd conv=notrunc if=/dev/zero of=zram${i}/file \ + oflag=append count=1 bs=1024 status=none \ + > /dev/null 2>&1 || break + b=$(($b + 1)) + done + echo "zram$i can be filled with '$b' KB" + done + + local mem_free1=$(free -m | awk 'NR==2 {print $4}') + local used_mem=$(($mem_free0 - $mem_free1)) + + local total_size=0 + for sm in $zram_sizes; do + local s=$(echo $sm | sed 's/M//') + total_size=$(($total_size + $s)) + done + + echo "zram used ${used_mem}M, zram disk sizes ${total_size}M" + + local v=$((100 * $total_size / $used_mem)) + + if [ "$v" -lt 100 ]; then + echo "FAIL compression ratio: 0.$v:1" + ERR_CODE=-1 + zram_cleanup + return + fi + + echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK" +} + +zram_load +zram_max_streams +zram_compress_alg +zram_set_disksizes +zram_set_memlimit +zram_makefs +zram_mount + +zram_fill_fs +zram_cleanup +zram_unload + +if [ $ERR_CODE -ne 0 ]; then + echo "$TCID : [FAIL]" +else + echo "$TCID : [PASS]" +fi diff --git a/tools/testing/selftests/zram/zram02.sh b/tools/testing/selftests/zram/zram02.sh new file mode 100755 index 0000000000000..96e82dcc195b4 --- /dev/null +++ b/tools/testing/selftests/zram/zram02.sh @@ -0,0 +1,53 @@ +#!/bin/bash +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# +# 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. +# +# This program is distributed in the hope that it would be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Test checks that we can create swap zram device. +# +# Author: Alexey Kodanev +# Modified: Naresh Kamboju + +TCID="zram02" +ERR_CODE=0 + +. ./zram_lib.sh + +# Test will create the following number of zram devices: +dev_num=1 +# This is a list of parameters for zram devices. +# Number of items must be equal to 'dev_num' parameter. +zram_max_streams="2" + +# The zram sysfs node 'disksize' value can be either in bytes, +# or you can use mem suffixes. But in some old kernels, mem +# suffixes are not supported, for example, in RHEL6.6GA's kernel +# layer, it uses strict_strtoull() to parse disksize which does +# not support mem suffixes, in some newer kernels, they use +# memparse() which supports mem suffixes. So here we just use +# bytes to make sure everything works correctly. +zram_sizes="1048576" # 1M +zram_mem_limits="1M" + +zram_load +zram_max_streams +zram_set_disksizes +zram_set_memlimit +zram_makeswap +zram_swapoff +zram_cleanup +zram_unload + +if [ $ERR_CODE -ne 0 ]; then + echo "$TCID : [FAIL]" +else + echo "$TCID : [PASS]" +fi diff --git a/tools/testing/selftests/zram/zram_lib.sh b/tools/testing/selftests/zram/zram_lib.sh new file mode 100755 index 0000000000000..3b6abf1942d72 --- /dev/null +++ b/tools/testing/selftests/zram/zram_lib.sh @@ -0,0 +1,222 @@ +#!/bin/sh +# Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. +# +# 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. +# +# This program is distributed in the hope that it would be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# Author: Alexey Kodanev +# Modified: Naresh Kamboju + +MODULE=0 +dev_makeswap=-1 +dev_mounted=-1 + +trap INT + +zram_cleanup() +{ + echo "zram cleanup" + local i= + for i in $(seq 0 $dev_makeswap); do + swapoff /dev/zram$i + done + + for i in $(seq 0 $dev_mounted); do + umount /dev/zram$i + done + + for i in $(seq 0 $(($dev_num - 1))); do + echo 1 > /sys/block/zram${i}/reset + rm -rf zram$i + done + +} + +zram_unload() +{ + if [ $MODULE -ne 0 ] ; then + echo "zram rmmod zram" + rmmod zram > /dev/null 2>&1 + fi +} + +zram_load() +{ + # check zram module exists + MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko + if [ -f $MODULE_PATH ]; then + MODULE=1 + echo "create '$dev_num' zram device(s)" + modprobe zram num_devices=$dev_num + if [ $? -ne 0 ]; then + echo "failed to insert zram module" + exit 1 + fi + + dev_num_created=$(ls /dev/zram* | wc -w) + + if [ "$dev_num_created" -ne "$dev_num" ]; then + echo "unexpected num of devices: $dev_num_created" + ERR_CODE=-1 + else + echo "zram load module successful" + fi + elif [ -b /dev/zram0 ]; then + echo "/dev/zram0 device file found: OK" + else + echo "ERROR: No zram.ko module or no /dev/zram0 device found" + echo "$TCID : CONFIG_ZRAM is not set" + exit 1 + fi +} + +zram_max_streams() +{ + echo "set max_comp_streams to zram device(s)" + + local i=0 + for max_s in $zram_max_streams; do + local sys_path="/sys/block/zram${i}/max_comp_streams" + echo $max_s > $sys_path || \ + echo "FAIL failed to set '$max_s' to $sys_path" + sleep 1 + local max_streams=$(cat $sys_path) + + [ "$max_s" -ne "$max_streams" ] && \ + echo "FAIL can't set max_streams '$max_s', get $max_stream" + + i=$(($i + 1)) + echo "$sys_path = '$max_streams' ($i/$dev_num)" + done + + echo "zram max streams: OK" +} + +zram_compress_alg() +{ + echo "test that we can set compression algorithm" + + local algs=$(cat /sys/block/zram0/comp_algorithm) + echo "supported algs: $algs" + local i=0 + for alg in $zram_algs; do + local sys_path="/sys/block/zram${i}/comp_algorithm" + echo "$alg" > $sys_path || \ + echo "FAIL can't set '$alg' to $sys_path" + i=$(($i + 1)) + echo "$sys_path = '$alg' ($i/$dev_num)" + done + + echo "zram set compression algorithm: OK" +} + +zram_set_disksizes() +{ + echo "set disk size to zram device(s)" + local i=0 + for ds in $zram_sizes; do + local sys_path="/sys/block/zram${i}/disksize" + echo "$ds" > $sys_path || \ + echo "FAIL can't set '$ds' to $sys_path" + + i=$(($i + 1)) + echo "$sys_path = '$ds' ($i/$dev_num)" + done + + echo "zram set disksizes: OK" +} + +zram_set_memlimit() +{ + echo "set memory limit to zram device(s)" + + local i=0 + for ds in $zram_mem_limits; do + local sys_path="/sys/block/zram${i}/mem_limit" + echo "$ds" > $sys_path || \ + echo "FAIL can't set '$ds' to $sys_path" + + i=$(($i + 1)) + echo "$sys_path = '$ds' ($i/$dev_num)" + done + + echo "zram set memory limit: OK" +} + +zram_makeswap() +{ + echo "make swap with zram device(s)" + local i=0 + for i in $(seq 0 $(($dev_num - 1))); do + mkswap /dev/zram$i > err.log 2>&1 + if [ $? -ne 0 ]; then + cat err.log + echo "FAIL mkswap /dev/zram$1 failed" + fi + + swapon /dev/zram$i > err.log 2>&1 + if [ $? -ne 0 ]; then + cat err.log + echo "FAIL swapon /dev/zram$1 failed" + fi + + echo "done with /dev/zram$i" + dev_makeswap=$i + done + + echo "zram making zram mkswap and swapon: OK" +} + +zram_swapoff() +{ + local i= + for i in $(seq 0 $dev_makeswap); do + swapoff /dev/zram$i > err.log 2>&1 + if [ $? -ne 0 ]; then + cat err.log + echo "FAIL swapoff /dev/zram$i failed" + fi + done + dev_makeswap=-1 + + echo "zram swapoff: OK" +} + +zram_makefs() +{ + local i=0 + for fs in $zram_filesystems; do + # if requested fs not supported default it to ext2 + which mkfs.$fs > /dev/null 2>&1 || fs=ext2 + + echo "make $fs filesystem on /dev/zram$i" + mkfs.$fs /dev/zram$i > err.log 2>&1 + if [ $? -ne 0 ]; then + cat err.log + echo "FAIL failed to make $fs on /dev/zram$i" + fi + i=$(($i + 1)) + echo "zram mkfs.$fs: OK" + done +} + +zram_mount() +{ + local i=0 + for i in $(seq 0 $(($dev_num - 1))); do + echo "mount /dev/zram$i" + mkdir zram$i + mount /dev/zram$i zram$i > /dev/null || \ + echo "FAIL mount /dev/zram$i failed" + dev_mounted=$i + done + + echo "zram mount of zram device(s): OK" +} -- GitLab From a7d0f078892ee5e737cbe79541353c630bc71651 Mon Sep 17 00:00:00 2001 From: Bamvor Jian Zhang Date: Fri, 14 Aug 2015 21:43:35 +0800 Subject: [PATCH 5209/7006] selftests: check before install When the test cases is not supported by the current architecture the install files(TEST_PROGS, TEST_PROGS_EXTENDED and TEST_FILES) will be empty. Check it before installation to dismiss a failure reported by install program. Signed-off-by: Bamvor Jian Zhang Signed-off-by: Shuah Khan --- tools/testing/selftests/Makefile | 1 - tools/testing/selftests/lib.mk | 13 ++++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 9763dd95b4c82..b2179587c8fe0 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -72,7 +72,6 @@ ifdef INSTALL_PATH @# Ask all targets to install their files mkdir -p $(INSTALL_PATH) for TARGET in $(TARGETS); do \ - mkdir -p $(INSTALL_PATH)/$$TARGET ; \ make -C $$TARGET INSTALL_PATH=$(INSTALL_PATH)/$$TARGET install; \ done; diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index ee412bab7ed4b..97f1c67420663 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -12,11 +12,14 @@ run_tests: all $(RUN_TESTS) define INSTALL_RULE - mkdir -p $(INSTALL_PATH) - @for TEST_DIR in $(TEST_DIRS); do\ - cp -r $$TEST_DIR $(INSTALL_PATH); \ - done; - install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) + @if [ "X$(TEST_PROGS)$(TEST_PROGS_EXTENDED)$(TEST_FILES)" != "X" ]; then \ + mkdir -p $(INSTALL_PATH); \ + for TEST_DIR in $(TEST_DIRS); do \ + cp -r $$TEST_DIR $(INSTALL_PATH); \ + done; \ + echo "install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)"; \ + install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES); \ + fi endef install: all -- GitLab From 9fae100cbd1049057bbc3e3180a6de339b9b73a9 Mon Sep 17 00:00:00 2001 From: Bamvor Jian Zhang Date: Fri, 14 Aug 2015 21:43:38 +0800 Subject: [PATCH 5210/7006] selftests: breakpoints: fix installing error on the architecture except x86 Signed-off-by: Bamvor Jian Zhang Signed-off-by: Shuah Khan --- tools/testing/selftests/breakpoints/Makefile | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/tools/testing/selftests/breakpoints/Makefile b/tools/testing/selftests/breakpoints/Makefile index 1822356402090..d27108b4f2081 100644 --- a/tools/testing/selftests/breakpoints/Makefile +++ b/tools/testing/selftests/breakpoints/Makefile @@ -1,22 +1,12 @@ # Taken from perf makefile uname_M := $(shell uname -m 2>/dev/null || echo not) -ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) -ifeq ($(ARCH),i386) - ARCH := x86 -endif -ifeq ($(ARCH),x86_64) - ARCH := x86 -endif +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/) - -all: ifeq ($(ARCH),x86) - gcc breakpoint_test.c -o breakpoint_test -else - echo "Not an x86 target, can't build breakpoints selftests" +TEST_PROGS := breakpoint_test endif -TEST_PROGS := breakpoint_test +all: include ../lib.mk -- GitLab From 9c9a6524b5fdf6cb57c9ff627b7f242a6a4e0b00 Mon Sep 17 00:00:00 2001 From: Yuval Mintz Date: Thu, 27 Aug 2015 08:03:08 +0300 Subject: [PATCH 5211/7006] bnx2x: Add new device ids under the Qlogic vendor This adds support for 3 new PCI device combinations - 1077:16a1, 1077:16a4 and 1077:16ad. Signed-off-by: Yuval Mintz Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c index 26fbfcc6f7db8..e3da2bddf143f 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c @@ -266,11 +266,14 @@ static const struct pci_device_id bnx2x_pci_tbl[] = { { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_MF), BCM57810_MF }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_O), BCM57840_O }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 }, + { PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_NX2_57840_4_10), BCM57840_4_10 }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_2_20), BCM57840_2_20 }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57810_VF), BCM57810_VF }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MFO), BCM57840_MFO }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF }, + { PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_NX2_57840_MF), BCM57840_MF }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF }, + { PCI_VDEVICE(QLOGIC, PCI_DEVICE_ID_NX2_57840_VF), BCM57840_VF }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811), BCM57811 }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_MF), BCM57811_MF }, { PCI_VDEVICE(BROADCOM, PCI_DEVICE_ID_NX2_57811_VF), BCM57811_VF }, -- GitLab From d2d427b3927bd7a0348fc7f323d0e291f79a2779 Mon Sep 17 00:00:00 2001 From: Toshiaki Makita Date: Thu, 27 Aug 2015 15:32:26 +0900 Subject: [PATCH 5212/7006] bridge: Add netlink support for vlan_protocol attribute This enables bridge vlan_protocol to be configured through netlink. When CONFIG_BRIDGE_VLAN_FILTERING is disabled, kernel behaves the same way as this feature is not implemented. Signed-off-by: Toshiaki Makita Signed-off-by: David S. Miller --- include/uapi/linux/if_link.h | 1 + net/bridge/br_netlink.c | 34 ++++++++++++++++++++++++++++++++++ net/bridge/br_private.h | 1 + net/bridge/br_vlan.c | 35 +++++++++++++++++++++-------------- 4 files changed, 57 insertions(+), 14 deletions(-) diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 313c305fd1ad4..2d13dd44ecaaf 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -231,6 +231,7 @@ enum { IFLA_BR_STP_STATE, IFLA_BR_PRIORITY, IFLA_BR_VLAN_FILTERING, + IFLA_BR_VLAN_PROTOCOL, __IFLA_BR_MAX, }; diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index dbcb1949ea58c..af5e187553fd6 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -673,6 +673,21 @@ static int br_validate(struct nlattr *tb[], struct nlattr *data[]) return -EADDRNOTAVAIL; } + if (!data) + return 0; + +#ifdef CONFIG_BRIDGE_VLAN_FILTERING + if (data[IFLA_BR_VLAN_PROTOCOL]) { + switch (nla_get_be16(data[IFLA_BR_VLAN_PROTOCOL])) { + case htons(ETH_P_8021Q): + case htons(ETH_P_8021AD): + break; + default: + return -EPROTONOSUPPORT; + } + } +#endif + return 0; } @@ -729,6 +744,7 @@ static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = { [IFLA_BR_STP_STATE] = { .type = NLA_U32 }, [IFLA_BR_PRIORITY] = { .type = NLA_U16 }, [IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 }, + [IFLA_BR_VLAN_PROTOCOL] = { .type = NLA_U16 }, }; static int br_changelink(struct net_device *brdev, struct nlattr *tb[], @@ -784,6 +800,16 @@ static int br_changelink(struct net_device *brdev, struct nlattr *tb[], return err; } +#ifdef CONFIG_BRIDGE_VLAN_FILTERING + if (data[IFLA_BR_VLAN_PROTOCOL]) { + __be16 vlan_proto = nla_get_be16(data[IFLA_BR_VLAN_PROTOCOL]); + + err = __br_vlan_set_proto(br, vlan_proto); + if (err) + return err; + } +#endif + return 0; } @@ -796,6 +822,9 @@ static size_t br_get_size(const struct net_device *brdev) nla_total_size(sizeof(u32)) + /* IFLA_BR_STP_STATE */ nla_total_size(sizeof(u16)) + /* IFLA_BR_PRIORITY */ nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_FILTERING */ +#ifdef CONFIG_BRIDGE_VLAN_FILTERING + nla_total_size(sizeof(__be16)) + /* IFLA_BR_VLAN_PROTOCOL */ +#endif 0; } @@ -819,6 +848,11 @@ static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev) nla_put_u8(skb, IFLA_BR_VLAN_FILTERING, vlan_enabled)) return -EMSGSIZE; +#ifdef CONFIG_BRIDGE_VLAN_FILTERING + if (nla_put_be16(skb, IFLA_BR_VLAN_PROTOCOL, br->vlan_proto)) + return -EMSGSIZE; +#endif + return 0; } diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 3d95647039d0f..19e8f79b6b99f 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -616,6 +616,7 @@ bool br_vlan_find(struct net_bridge *br, u16 vid); void br_recalculate_fwd_mask(struct net_bridge *br); int __br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); +int __br_vlan_set_proto(struct net_bridge *br, __be16 proto); int br_vlan_set_proto(struct net_bridge *br, unsigned long val); int br_vlan_init(struct net_bridge *br); int br_vlan_set_default_pvid(struct net_bridge *br, unsigned long val); diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 3cef6892c0bbd..3cd8cc9e804b3 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -492,23 +492,16 @@ int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) return 0; } -int br_vlan_set_proto(struct net_bridge *br, unsigned long val) +int __br_vlan_set_proto(struct net_bridge *br, __be16 proto) { int err = 0; struct net_bridge_port *p; struct net_port_vlans *pv; - __be16 proto, oldproto; + __be16 oldproto; u16 vid, errvid; - if (val != ETH_P_8021Q && val != ETH_P_8021AD) - return -EPROTONOSUPPORT; - - if (!rtnl_trylock()) - return restart_syscall(); - - proto = htons(val); if (br->vlan_proto == proto) - goto unlock; + return 0; /* Add VLANs for the new proto to the device filter. */ list_for_each_entry(p, &br->port_list, list) { @@ -539,9 +532,7 @@ int br_vlan_set_proto(struct net_bridge *br, unsigned long val) vlan_vid_del(p->dev, oldproto, vid); } -unlock: - rtnl_unlock(); - return err; + return 0; err_filt: errvid = vid; @@ -557,7 +548,23 @@ err_filt: vlan_vid_del(p->dev, proto, vid); } - goto unlock; + return err; +} + +int br_vlan_set_proto(struct net_bridge *br, unsigned long val) +{ + int err; + + if (val != ETH_P_8021Q && val != ETH_P_8021AD) + return -EPROTONOSUPPORT; + + if (!rtnl_trylock()) + return restart_syscall(); + + err = __br_vlan_set_proto(br, htons(val)); + rtnl_unlock(); + + return err; } static bool vlan_default_pvid(struct net_port_vlans *pv, u16 vid) -- GitLab From 87cd3dcaf4bd135e44ee187baf788deeb011e58d Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:48 -0700 Subject: [PATCH 5213/7006] geneve: Initialize ethernet address in device setup. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: Thomas Graf Acked-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 897e1a3f035bc..95e9da0a52f2f 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -297,6 +297,7 @@ static void geneve_setup(struct net_device *dev) netif_keep_dst(dev); dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; + eth_hw_addr_random(dev); } static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { @@ -364,9 +365,6 @@ static int geneve_newlink(struct net *net, struct net_device *dev, return -EBUSY; } - if (tb[IFLA_ADDRESS] == NULL) - eth_hw_addr_random(dev); - err = register_netdevice(dev); if (err) return err; -- GitLab From 980c394c53e420f7e5484d011378a4bec861ec7a Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:49 -0700 Subject: [PATCH 5214/7006] geneve: Use skb mark and protocol to lookup route. On packet transmit path geneve need to lookup route. Following patch improves route lookup using more parameters. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: Thomas Graf Acked-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 95e9da0a52f2f..3c5b2b100943c 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -202,6 +202,9 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) memset(&fl4, 0, sizeof(fl4)); fl4.flowi4_tos = RT_TOS(tos); fl4.daddr = geneve->remote.sin_addr.s_addr; + fl4.flowi4_mark = skb->mark; + fl4.flowi4_proto = IPPROTO_UDP; + rt = ip_route_output_key(geneve->net, &fl4); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); -- GitLab From c29a70d2cadfea443c027d23481f820530b70057 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:50 -0700 Subject: [PATCH 5215/7006] tunnel: introduce udp_tun_rx_dst() Introduce function udp_tun_rx_dst() to initialize tunnel dst on receive path. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 29 ++---------------- include/net/dst_metadata.h | 61 ++++++++++++++++++++++++++++++++++++++ include/net/udp_tunnel.h | 4 +++ net/ipv4/ip_gre.c | 21 ++++--------- net/ipv4/udp_tunnel.c | 25 +++++++++++++++- 5 files changed, 97 insertions(+), 43 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 61b457b9ec005..5b4cf66e632ee 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1264,36 +1264,13 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) } if (vxlan_collect_metadata(vs)) { - tun_dst = metadata_dst_alloc(sizeof(*md), GFP_ATOMIC); + tun_dst = udp_tun_rx_dst(skb, vxlan_get_sk_family(vs), TUNNEL_KEY, + cpu_to_be64(vni >> 8), sizeof(*md)); + if (!tun_dst) goto drop; info = &tun_dst->u.tun_info; - if (vxlan_get_sk_family(vs) == AF_INET) { - const struct iphdr *iph = ip_hdr(skb); - - info->key.u.ipv4.src = iph->saddr; - info->key.u.ipv4.dst = iph->daddr; - info->key.tos = iph->tos; - info->key.ttl = iph->ttl; - } else { - const struct ipv6hdr *ip6h = ipv6_hdr(skb); - - info->key.u.ipv6.src = ip6h->saddr; - info->key.u.ipv6.dst = ip6h->daddr; - info->key.tos = ipv6_get_dsfield(ip6h); - info->key.ttl = ip6h->hop_limit; - } - - info->key.tp_src = udp_hdr(skb)->source; - info->key.tp_dst = udp_hdr(skb)->dest; - - info->mode = IP_TUNNEL_INFO_RX; - info->key.tun_flags = TUNNEL_KEY; - info->key.tun_id = cpu_to_be64(vni >> 8); - if (udp_hdr(skb)->check != 0) - info->key.tun_flags |= TUNNEL_CSUM; - md = ip_tunnel_info_opts(info, sizeof(*md)); } else { memset(md, 0, sizeof(*md)); diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 2cb52d562272a..60c03326c0876 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -48,4 +48,65 @@ static inline bool skb_valid_dst(const struct sk_buff *skb) struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags); struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags); +static inline struct metadata_dst *tun_rx_dst(__be16 flags, + __be64 tunnel_id, int md_size) +{ + struct metadata_dst *tun_dst; + struct ip_tunnel_info *info; + + tun_dst = metadata_dst_alloc(md_size, GFP_ATOMIC); + if (!tun_dst) + return NULL; + + info = &tun_dst->u.tun_info; + info->mode = IP_TUNNEL_INFO_RX; + info->key.tun_flags = flags; + info->key.tun_id = tunnel_id; + info->key.tp_src = 0; + info->key.tp_dst = 0; + return tun_dst; +} + +static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb, + __be16 flags, + __be64 tunnel_id, + int md_size) +{ + const struct iphdr *iph = ip_hdr(skb); + struct metadata_dst *tun_dst; + struct ip_tunnel_info *info; + + tun_dst = tun_rx_dst(flags, tunnel_id, md_size); + if (!tun_dst) + return NULL; + + info = &tun_dst->u.tun_info; + info->key.u.ipv4.src = iph->saddr; + info->key.u.ipv4.dst = iph->daddr; + info->key.tos = iph->tos; + info->key.ttl = iph->ttl; + return tun_dst; +} + +static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb, + __be16 flags, + __be64 tunnel_id, + int md_size) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + struct metadata_dst *tun_dst; + struct ip_tunnel_info *info; + + tun_dst = tun_rx_dst(flags, tunnel_id, md_size); + if (!tun_dst) + return NULL; + + info = &tun_dst->u.tun_info; + info->key.u.ipv6.src = ip6h->saddr; + info->key.u.ipv6.dst = ip6h->daddr; + info->key.tos = ipv6_get_dsfield(ip6h); + info->key.ttl = ip6h->hop_limit; + return tun_dst; +} + #endif /* __NET_DST_METADATA_H */ diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index c491c1221606e..35041d0fc21ed 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -93,6 +93,10 @@ int udp_tunnel6_xmit_skb(struct dst_entry *dst, struct sock *sk, void udp_tunnel_sock_release(struct socket *sock); +struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, + int md_size); + static inline struct sk_buff *udp_tunnel_handle_offloads(struct sk_buff *skb, bool udp_csum) { diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 1bf328182697b..faf1cde6f8da2 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -400,25 +400,14 @@ static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) if (tunnel) { skb_pop_mac_header(skb); if (tunnel->collect_md) { - struct ip_tunnel_info *info; + __be16 flags; + __be64 tun_id; - tun_dst = metadata_dst_alloc(0, GFP_ATOMIC); + flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY); + tun_id = key_to_tunnel_id(tpi->key); + tun_dst = ip_tun_rx_dst(skb, flags, tun_id, 0); if (!tun_dst) return PACKET_REJECT; - - info = &tun_dst->u.tun_info; - info->key.u.ipv4.src = iph->saddr; - info->key.u.ipv4.dst = iph->daddr; - info->key.tos = iph->tos; - info->key.ttl = iph->ttl; - - info->mode = IP_TUNNEL_INFO_RX; - info->key.tun_flags = tpi->flags & - (TUNNEL_CSUM | TUNNEL_KEY); - info->key.tun_id = key_to_tunnel_id(tpi->key); - - info->key.tp_src = 0; - info->key.tp_dst = 0; } ip_tunnel_rcv(tunnel, skb, tpi, tun_dst, log_ecn_error); diff --git a/net/ipv4/udp_tunnel.c b/net/ipv4/udp_tunnel.c index 933ea903f7b8f..aba428626b529 100644 --- a/net/ipv4/udp_tunnel.c +++ b/net/ipv4/udp_tunnel.c @@ -4,9 +4,10 @@ #include #include #include +#include +#include #include #include -#include int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, struct socket **sockp) @@ -103,4 +104,26 @@ void udp_tunnel_sock_release(struct socket *sock) } EXPORT_SYMBOL_GPL(udp_tunnel_sock_release); +struct metadata_dst *udp_tun_rx_dst(struct sk_buff *skb, unsigned short family, + __be16 flags, __be64 tunnel_id, int md_size) +{ + struct metadata_dst *tun_dst; + struct ip_tunnel_info *info; + + if (family == AF_INET) + tun_dst = ip_tun_rx_dst(skb, flags, tunnel_id, md_size); + else + tun_dst = ipv6_tun_rx_dst(skb, flags, tunnel_id, md_size); + if (!tun_dst) + return NULL; + + info = &tun_dst->u.tun_info; + info->key.tp_src = udp_hdr(skb)->source; + info->key.tp_dst = udp_hdr(skb)->dest; + if (udp_hdr(skb)->check) + info->key.tun_flags |= TUNNEL_CSUM; + return tun_dst; +} +EXPORT_SYMBOL_GPL(udp_tun_rx_dst); + MODULE_LICENSE("GPL"); -- GitLab From cd7918b35f0ee0106bbe2ce4a14b5a8c9763deb8 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:51 -0700 Subject: [PATCH 5216/7006] geneve: Make dst-port configurable. Add netlink interface to configure Geneve UDP port number. So that user can configure it for a Gevene device. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: Thomas Graf Acked-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 25 +++++++++++++++++++++---- include/uapi/linux/if_link.h | 1 + 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 3c5b2b100943c..0a6d9741d956c 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -49,6 +49,7 @@ struct geneve_dev { u8 tos; /* TOS override */ struct sockaddr_in remote; /* IPv4 address for link partner */ struct list_head next; /* geneve's per namespace list */ + __be16 dst_port; }; static int geneve_net_id; @@ -64,6 +65,7 @@ static inline __u32 geneve_net_vni_hash(u8 vni[3]) /* geneve receive/decap routine */ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) { + struct inet_sock *sk = inet_sk(gs->sock->sk); struct genevehdr *gnvh = geneve_hdr(skb); struct geneve_dev *dummy, *geneve = NULL; struct geneve_net *gn; @@ -82,7 +84,8 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) vni_list_head = &gn->vni_list[hash]; hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { if (!memcmp(gnvh->vni, dummy->vni, sizeof(dummy->vni)) && - iph->saddr == dummy->remote.sin_addr.s_addr) { + iph->saddr == dummy->remote.sin_addr.s_addr && + sk->inet_sport == dummy->dst_port) { geneve = dummy; break; } @@ -157,7 +160,7 @@ static int geneve_open(struct net_device *dev) struct geneve_net *gn = net_generic(geneve->net, geneve_net_id); struct geneve_sock *gs; - gs = geneve_sock_add(net, htons(GENEVE_UDP_PORT), geneve_rx, gn, + gs = geneve_sock_add(net, geneve->dst_port, geneve_rx, gn, false, false); if (IS_ERR(gs)) return PTR_ERR(gs); @@ -228,7 +231,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) /* no need to handle local destination and encap bypass...yet... */ err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, - tos, ttl, 0, sport, htons(GENEVE_UDP_PORT), 0, + tos, ttl, 0, sport, geneve->dst_port, 0, geneve->vni, 0, NULL, false, !net_eq(geneve->net, dev_net(geneve->dev))); if (err < 0) @@ -308,6 +311,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_REMOTE] = { .len = FIELD_SIZEOF(struct iphdr, daddr) }, [IFLA_GENEVE_TTL] = { .type = NLA_U8 }, [IFLA_GENEVE_TOS] = { .type = NLA_U8 }, + [IFLA_GENEVE_PORT] = { .type = NLA_U16 }, }; static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -341,6 +345,7 @@ static int geneve_newlink(struct net *net, struct net_device *dev, struct hlist_head *vni_list_head; struct sockaddr_in remote; /* IPv4 address for link partner */ __u32 vni, hash; + __be16 dst_port; int err; if (!data[IFLA_GENEVE_ID] || !data[IFLA_GENEVE_REMOTE]) @@ -359,13 +364,20 @@ static int geneve_newlink(struct net *net, struct net_device *dev, if (IN_MULTICAST(ntohl(geneve->remote.sin_addr.s_addr))) return -EINVAL; + if (data[IFLA_GENEVE_PORT]) + dst_port = htons(nla_get_u16(data[IFLA_GENEVE_PORT])); + else + dst_port = htons(GENEVE_UDP_PORT); + remote = geneve->remote; hash = geneve_net_vni_hash(geneve->vni); vni_list_head = &gn->vni_list[hash]; hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { if (!memcmp(geneve->vni, dummy->vni, sizeof(dummy->vni)) && - !memcmp(&remote, &dummy->remote, sizeof(dummy->remote))) + !memcmp(&remote, &dummy->remote, sizeof(dummy->remote)) && + dst_port == dummy->dst_port) { return -EBUSY; + } } err = register_netdevice(dev); @@ -378,6 +390,7 @@ static int geneve_newlink(struct net *net, struct net_device *dev, if (data[IFLA_GENEVE_TOS]) geneve->tos = nla_get_u8(data[IFLA_GENEVE_TOS]); + geneve->dst_port = dst_port; list_add(&geneve->next, &gn->geneve_list); hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); @@ -402,6 +415,7 @@ static size_t geneve_get_size(const struct net_device *dev) nla_total_size(sizeof(struct in_addr)) + /* IFLA_GENEVE_REMOTE */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */ + nla_total_size(sizeof(__u16)) + /* IFLA_GENEVE_PORT */ 0; } @@ -422,6 +436,9 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) nla_put_u8(skb, IFLA_GENEVE_TOS, geneve->tos)) goto nla_put_failure; + if (nla_put_u16(skb, IFLA_GENEVE_PORT, ntohs(geneve->dst_port))) + goto nla_put_failure; + return 0; nla_put_failure: diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 2d13dd44ecaaf..9d73c31896d0e 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -410,6 +410,7 @@ enum { IFLA_GENEVE_REMOTE, IFLA_GENEVE_TTL, IFLA_GENEVE_TOS, + IFLA_GENEVE_PORT, /* destination port */ __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) -- GitLab From e305ac6cf5a1e1386aedce7ef9cb773635d5845c Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:52 -0700 Subject: [PATCH 5217/7006] geneve: Add support to collect tunnel metadata. Following patch create new tunnel flag which enable tunnel metadata collection on given device. These devices can be used by tunnel metadata based routing or by OVS. Geneve Consolidation patch get rid of collect_md_tun to simplify tunnel lookup further. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/geneve.c | 356 ++++++++++++++++++++++++++--------- include/net/geneve.h | 3 + include/uapi/linux/if_link.h | 1 + 3 files changed, 275 insertions(+), 85 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 0a6d9741d956c..d05150cc25d4b 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,7 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); struct geneve_net { struct list_head geneve_list; struct hlist_head vni_list[VNI_HASH_SIZE]; + struct geneve_dev __rcu *collect_md_tun; }; /* Pseudo network device */ @@ -50,6 +52,7 @@ struct geneve_dev { struct sockaddr_in remote; /* IPv4 address for link partner */ struct list_head next; /* geneve's per namespace list */ __be16 dst_port; + bool collect_md; }; static int geneve_net_id; @@ -62,48 +65,95 @@ static inline __u32 geneve_net_vni_hash(u8 vni[3]) return hash_32(vnid, VNI_HASH_BITS); } -/* geneve receive/decap routine */ -static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) +static __be64 vni_to_tunnel_id(const __u8 *vni) +{ +#ifdef __BIG_ENDIAN + return (vni[0] << 16) | (vni[1] << 8) | vni[2]; +#else + return (__force __be64)(((__force u64)vni[0] << 40) | + ((__force u64)vni[1] << 48) | + ((__force u64)vni[2] << 56)); +#endif +} + +static struct geneve_dev *geneve_lookup(struct geneve_net *gn, + struct geneve_sock *gs, + struct iphdr *iph, + struct genevehdr *gnvh) { struct inet_sock *sk = inet_sk(gs->sock->sk); - struct genevehdr *gnvh = geneve_hdr(skb); - struct geneve_dev *dummy, *geneve = NULL; - struct geneve_net *gn; - struct iphdr *iph = NULL; - struct pcpu_sw_netstats *stats; struct hlist_head *vni_list_head; - int err = 0; + struct geneve_dev *geneve; __u32 hash; - iph = ip_hdr(skb); /* Still outer IP header... */ - - gn = gs->rcv_data; + geneve = rcu_dereference(gn->collect_md_tun); + if (geneve) + return geneve; /* Find the device for this VNI */ hash = geneve_net_vni_hash(gnvh->vni); vni_list_head = &gn->vni_list[hash]; - hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { - if (!memcmp(gnvh->vni, dummy->vni, sizeof(dummy->vni)) && - iph->saddr == dummy->remote.sin_addr.s_addr && - sk->inet_sport == dummy->dst_port) { - geneve = dummy; - break; + hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) { + if (!memcmp(gnvh->vni, geneve->vni, sizeof(geneve->vni)) && + iph->saddr == geneve->remote.sin_addr.s_addr && + sk->inet_sport == geneve->dst_port) { + return geneve; } } + return NULL; +} + +/* geneve receive/decap routine */ +static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) +{ + struct genevehdr *gnvh = geneve_hdr(skb); + struct metadata_dst *tun_dst = NULL; + struct geneve_dev *geneve = NULL; + struct pcpu_sw_netstats *stats; + struct geneve_net *gn; + struct iphdr *iph; + int err; + + iph = ip_hdr(skb); /* Still outer IP header... */ + gn = gs->rcv_data; + geneve = geneve_lookup(gn, gs, iph, gnvh); if (!geneve) goto drop; - /* Drop packets w/ critical options, - * since we don't support any... - */ - if (gnvh->critical) - goto drop; + if (ip_tunnel_collect_metadata() || geneve->collect_md) { + __be16 flags; + void *opts; + + flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT | + (gnvh->oam ? TUNNEL_OAM : 0) | + (gnvh->critical ? TUNNEL_CRIT_OPT : 0); + + tun_dst = udp_tun_rx_dst(skb, AF_INET, flags, + vni_to_tunnel_id(gnvh->vni), + gnvh->opt_len * 4); + if (!tun_dst) + goto drop; + + /* Update tunnel dst according to Geneve options. */ + opts = ip_tunnel_info_opts(&tun_dst->u.tun_info, + gnvh->opt_len * 4); + memcpy(opts, gnvh->options, gnvh->opt_len * 4); + } else { + /* Drop packets w/ critical options, + * since we don't support any... + */ + if (gnvh->critical) + goto drop; + } skb_reset_mac_header(skb); skb_scrub_packet(skb, !net_eq(geneve->net, dev_net(geneve->dev))); skb->protocol = eth_type_trans(skb, geneve->dev); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + if (tun_dst) + skb_dst_set(skb, &tun_dst->dst); + /* Ignore packet loops (and multicast echo) */ if (ether_addr_equal(eth_hdr(skb)->h_source, geneve->dev->dev_addr)) goto drop; @@ -131,7 +181,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) u64_stats_update_end(&stats->syncp); netif_rx(skb); - return; drop: /* Consume bad packet */ @@ -144,7 +193,6 @@ static int geneve_init(struct net_device *dev) dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; - return 0; } @@ -180,69 +228,137 @@ static int geneve_stop(struct net_device *dev) return 0; } +static struct rtable *geneve_get_rt(struct sk_buff *skb, + struct net_device *dev, + struct flowi4 *fl4, + struct ip_tunnel_info *info) +{ + struct geneve_dev *geneve = netdev_priv(dev); + struct rtable *rt = NULL; + __u8 tos; + + memset(fl4, 0, sizeof(*fl4)); + fl4->flowi4_mark = skb->mark; + fl4->flowi4_proto = IPPROTO_UDP; + + if (info) { + fl4->daddr = info->key.u.ipv4.dst; + fl4->saddr = info->key.u.ipv4.src; + fl4->flowi4_tos = RT_TOS(info->key.tos); + } else { + tos = geneve->tos; + if (tos == 1) { + const struct iphdr *iip = ip_hdr(skb); + + tos = ip_tunnel_get_dsfield(iip, skb); + } + + fl4->flowi4_tos = RT_TOS(tos); + fl4->daddr = geneve->remote.sin_addr.s_addr; + } + + rt = ip_route_output_key(geneve->net, fl4); + if (IS_ERR(rt)) { + netdev_dbg(dev, "no route to %pI4\n", &fl4->daddr); + dev->stats.tx_carrier_errors++; + return rt; + } + if (rt->dst.dev == dev) { /* is this necessary? */ + netdev_dbg(dev, "circular route to %pI4\n", &fl4->daddr); + dev->stats.collisions++; + ip_rt_put(rt); + return ERR_PTR(-EINVAL); + } + + return rt; +} + +/* Convert 64 bit tunnel ID to 24 bit VNI. */ +static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni) +{ +#ifdef __BIG_ENDIAN + vni[0] = (__force __u8)(tun_id >> 16); + vni[1] = (__force __u8)(tun_id >> 8); + vni[2] = (__force __u8)tun_id; +#else + vni[0] = (__force __u8)((__force u64)tun_id >> 40); + vni[1] = (__force __u8)((__force u64)tun_id >> 48); + vni[2] = (__force __u8)((__force u64)tun_id >> 56); +#endif +} + static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); struct geneve_sock *gs = geneve->sock; + struct ip_tunnel_info *info = NULL; struct rtable *rt = NULL; const struct iphdr *iip; /* interior IP header */ struct flowi4 fl4; - int err; - __be16 sport; __u8 tos, ttl; + __be16 sport; + bool xnet; + int err; - iip = ip_hdr(skb); - - skb_reset_mac_header(skb); - - /* TODO: port min/max limits should be configurable */ - sport = udp_flow_src_port(dev_net(dev), skb, 0, 0, true); - - tos = geneve->tos; - if (tos == 1) - tos = ip_tunnel_get_dsfield(iip, skb); + sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); - memset(&fl4, 0, sizeof(fl4)); - fl4.flowi4_tos = RT_TOS(tos); - fl4.daddr = geneve->remote.sin_addr.s_addr; - fl4.flowi4_mark = skb->mark; - fl4.flowi4_proto = IPPROTO_UDP; + if (geneve->collect_md) { + info = skb_tunnel_info(skb); + if (unlikely(info && info->mode != IP_TUNNEL_INFO_TX)) { + netdev_dbg(dev, "no tunnel metadata\n"); + goto tx_error; + } + } - rt = ip_route_output_key(geneve->net, &fl4); + rt = geneve_get_rt(skb, dev, &fl4, info); if (IS_ERR(rt)) { netdev_dbg(dev, "no route to %pI4\n", &fl4.daddr); dev->stats.tx_carrier_errors++; goto tx_error; } - if (rt->dst.dev == dev) { /* is this necessary? */ - netdev_dbg(dev, "circular route to %pI4\n", &fl4.daddr); - dev->stats.collisions++; - goto rt_tx_error; + skb_reset_mac_header(skb); + xnet = !net_eq(geneve->net, dev_net(geneve->dev)); + + if (info) { + const struct ip_tunnel_key *key = &info->key; + bool udp_csum; + u8 *opts = NULL; + u8 vni[3]; + __be16 df; + + tunnel_id_to_vni(key->tun_id, vni); + df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; + udp_csum = !!(key->tun_flags & TUNNEL_CSUM); + + if (key->tun_flags & TUNNEL_GENEVE_OPT) + opts = ip_tunnel_info_opts(info, info->options_len); + + err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, + key->tos, key->ttl, df, + sport, geneve->dst_port, + key->tun_flags, vni, + info->options_len, opts, udp_csum, xnet); + } else { + iip = ip_hdr(skb); + tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb); + + ttl = geneve->ttl; + if (!ttl && IN_MULTICAST(ntohl(fl4.daddr))) + ttl = 1; + + ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); + + /* no need to handle local destination and encap bypass...yet... */ + err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, tos, + ttl, 0, sport, geneve->dst_port, 0, + geneve->vni, 0, NULL, false, xnet); } - - tos = ip_tunnel_ecn_encap(tos, iip, skb); - - ttl = geneve->ttl; - if (!ttl && IN_MULTICAST(ntohl(fl4.daddr))) - ttl = 1; - - ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - - /* no need to handle local destination and encap bypass...yet... */ - - err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, - tos, ttl, 0, sport, geneve->dst_port, 0, - geneve->vni, 0, NULL, false, - !net_eq(geneve->net, dev_net(geneve->dev))); if (err < 0) ip_rt_put(rt); iptunnel_xmit_stats(err, &dev->stats, dev->tstats); - return NETDEV_TX_OK; -rt_tx_error: - ip_rt_put(rt); tx_error: dev->stats.tx_errors++; dev_kfree_skb(skb); @@ -312,6 +428,7 @@ static const struct nla_policy geneve_policy[IFLA_GENEVE_MAX + 1] = { [IFLA_GENEVE_TTL] = { .type = NLA_U8 }, [IFLA_GENEVE_TOS] = { .type = NLA_U8 }, [IFLA_GENEVE_PORT] = { .type = NLA_U16 }, + [IFLA_GENEVE_COLLECT_METADATA] = { .type = NLA_FLAG }, }; static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) @@ -337,71 +454,112 @@ static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static int geneve_newlink(struct net *net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) +static int geneve_configure(struct net *net, struct net_device *dev, + __be32 rem_addr, __u32 vni, __u8 ttl, __u8 tos, + __u16 dst_port, bool metadata) { struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_dev *dummy, *geneve = netdev_priv(dev); struct hlist_head *vni_list_head; struct sockaddr_in remote; /* IPv4 address for link partner */ - __u32 vni, hash; - __be16 dst_port; + __u32 hash; int err; - if (!data[IFLA_GENEVE_ID] || !data[IFLA_GENEVE_REMOTE]) - return -EINVAL; + if (metadata) { + if (rtnl_dereference(gn->collect_md_tun)) + return -EEXIST; + if (!list_empty(&gn->geneve_list)) + return -EPERM; + } else { + if (rtnl_dereference(gn->collect_md_tun)) + return -EPERM; + } geneve->net = net; geneve->dev = dev; - vni = nla_get_u32(data[IFLA_GENEVE_ID]); geneve->vni[0] = (vni & 0x00ff0000) >> 16; geneve->vni[1] = (vni & 0x0000ff00) >> 8; geneve->vni[2] = vni & 0x000000ff; - geneve->remote.sin_addr.s_addr = - nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); + geneve->remote.sin_addr.s_addr = rem_addr; if (IN_MULTICAST(ntohl(geneve->remote.sin_addr.s_addr))) return -EINVAL; - if (data[IFLA_GENEVE_PORT]) - dst_port = htons(nla_get_u16(data[IFLA_GENEVE_PORT])); - else - dst_port = htons(GENEVE_UDP_PORT); - remote = geneve->remote; + if (metadata) { + if (rem_addr || vni || tos || ttl) + return -EINVAL; + } + hash = geneve_net_vni_hash(geneve->vni); vni_list_head = &gn->vni_list[hash]; hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { if (!memcmp(geneve->vni, dummy->vni, sizeof(dummy->vni)) && !memcmp(&remote, &dummy->remote, sizeof(dummy->remote)) && - dst_port == dummy->dst_port) { + htons(dst_port) == dummy->dst_port) { return -EBUSY; } } + geneve->ttl = ttl; + geneve->tos = tos; + geneve->dst_port = htons(dst_port); + geneve->collect_md = metadata; + err = register_netdevice(dev); if (err) return err; + list_add(&geneve->next, &gn->geneve_list); + hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); + + if (geneve->collect_md) + rcu_assign_pointer(gn->collect_md_tun, geneve); + return 0; +} + +static int geneve_newlink(struct net *net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +{ + __u16 dst_port = GENEVE_UDP_PORT; + __u8 ttl = 0, tos = 0; + bool metadata = false; + __be32 rem_addr; + __u32 vni; + + if (!data[IFLA_GENEVE_ID] || !data[IFLA_GENEVE_REMOTE]) + return -EINVAL; + + vni = nla_get_u32(data[IFLA_GENEVE_ID]); + rem_addr = nla_get_in_addr(data[IFLA_GENEVE_REMOTE]); + if (data[IFLA_GENEVE_TTL]) - geneve->ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); + ttl = nla_get_u8(data[IFLA_GENEVE_TTL]); if (data[IFLA_GENEVE_TOS]) - geneve->tos = nla_get_u8(data[IFLA_GENEVE_TOS]); + tos = nla_get_u8(data[IFLA_GENEVE_TOS]); - geneve->dst_port = dst_port; - list_add(&geneve->next, &gn->geneve_list); + if (data[IFLA_GENEVE_PORT]) + dst_port = nla_get_u16(data[IFLA_GENEVE_PORT]); - hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); + if (data[IFLA_GENEVE_COLLECT_METADATA]) + metadata = true; - return 0; + return geneve_configure(net, dev, rem_addr, vni, + ttl, tos, dst_port, metadata); } static void geneve_dellink(struct net_device *dev, struct list_head *head) { struct geneve_dev *geneve = netdev_priv(dev); + if (geneve->collect_md) { + struct geneve_net *gn = net_generic(geneve->net, geneve_net_id); + + rcu_assign_pointer(gn->collect_md_tun, NULL); + } + if (!hlist_unhashed(&geneve->hlist)) hlist_del_rcu(&geneve->hlist); @@ -416,6 +574,7 @@ static size_t geneve_get_size(const struct net_device *dev) nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TTL */ nla_total_size(sizeof(__u8)) + /* IFLA_GENEVE_TOS */ nla_total_size(sizeof(__u16)) + /* IFLA_GENEVE_PORT */ + nla_total_size(0) + /* IFLA_GENEVE_COLLECT_METADATA */ 0; } @@ -439,6 +598,11 @@ static int geneve_fill_info(struct sk_buff *skb, const struct net_device *dev) if (nla_put_u16(skb, IFLA_GENEVE_PORT, ntohs(geneve->dst_port))) goto nla_put_failure; + if (geneve->collect_md) { + if (nla_put_flag(skb, IFLA_GENEVE_COLLECT_METADATA)) + goto nla_put_failure; + } + return 0; nla_put_failure: @@ -458,6 +622,28 @@ static struct rtnl_link_ops geneve_link_ops __read_mostly = { .fill_info = geneve_fill_info, }; +struct net_device *geneve_dev_create_fb(struct net *net, const char *name, + u8 name_assign_type, u16 dst_port) +{ + struct nlattr *tb[IFLA_MAX + 1]; + struct net_device *dev; + int err; + + memset(tb, 0, sizeof(tb)); + dev = rtnl_create_link(net, name, name_assign_type, + &geneve_link_ops, tb); + if (IS_ERR(dev)) + return dev; + + err = geneve_configure(net, dev, 0, 0, 0, 0, dst_port, true); + if (err) { + free_netdev(dev); + return ERR_PTR(err); + } + return dev; +} +EXPORT_SYMBOL_GPL(geneve_dev_create_fb); + static __net_init int geneve_init_net(struct net *net) { struct geneve_net *gn = net_generic(net, geneve_net_id); diff --git a/include/net/geneve.h b/include/net/geneve.h index 2a0543a1899dd..4245e1d23b9b8 100644 --- a/include/net/geneve.h +++ b/include/net/geneve.h @@ -96,6 +96,9 @@ int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt, bool csum, bool xnet); + +struct net_device *geneve_dev_create_fb(struct net *net, const char *name, + u8 name_assign_type, u16 dst_port); #endif /*ifdef CONFIG_INET */ #endif /*ifdef__NET_GENEVE_H */ diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h index 9d73c31896d0e..3a5f263cfc2ff 100644 --- a/include/uapi/linux/if_link.h +++ b/include/uapi/linux/if_link.h @@ -411,6 +411,7 @@ enum { IFLA_GENEVE_TTL, IFLA_GENEVE_TOS, IFLA_GENEVE_PORT, /* destination port */ + IFLA_GENEVE_COLLECT_METADATA, __IFLA_GENEVE_MAX }; #define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) -- GitLab From 6b001e682e90d7edf21f93687f5c3b39d412ad6c Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:53 -0700 Subject: [PATCH 5218/7006] openvswitch: Use Geneve device. With help of tunnel metadata mode OVS can directly use Geneve devices to implement Geneve tunnels. This patch removes all of the OVS specific Geneve code and make OVS use a Geneve net_device. Basic geneve vport is still there to handle compatibility with current userspace application. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: Thomas Graf Signed-off-by: David S. Miller --- net/openvswitch/Kconfig | 2 +- net/openvswitch/vport-geneve.c | 179 ++++++--------------------------- 2 files changed, 33 insertions(+), 148 deletions(-) diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index 98f343d0d6dd6..af7cdef42066b 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig @@ -70,7 +70,7 @@ config OPENVSWITCH_VXLAN config OPENVSWITCH_GENEVE tristate "Open vSwitch Geneve tunneling support" depends on OPENVSWITCH - depends on GENEVE_CORE + depends on GENEVE default OPENVSWITCH ---help--- If you say Y here, then the Open vSwitch will be able create geneve vport. diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index d01bd63609708..fa37c95f73394 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -26,95 +26,44 @@ #include "datapath.h" #include "vport.h" +#include "vport-netdev.h" static struct vport_ops ovs_geneve_vport_ops; - /** * struct geneve_port - Keeps track of open UDP ports - * @gs: The socket created for this port number. - * @name: vport name. + * @dst_port: destination port. */ struct geneve_port { - struct geneve_sock *gs; - char name[IFNAMSIZ]; + u16 port_no; }; -static LIST_HEAD(geneve_ports); - static inline struct geneve_port *geneve_vport(const struct vport *vport) { return vport_priv(vport); } -/* Convert 64 bit tunnel ID to 24 bit VNI. */ -static void tunnel_id_to_vni(__be64 tun_id, __u8 *vni) -{ -#ifdef __BIG_ENDIAN - vni[0] = (__force __u8)(tun_id >> 16); - vni[1] = (__force __u8)(tun_id >> 8); - vni[2] = (__force __u8)tun_id; -#else - vni[0] = (__force __u8)((__force u64)tun_id >> 40); - vni[1] = (__force __u8)((__force u64)tun_id >> 48); - vni[2] = (__force __u8)((__force u64)tun_id >> 56); -#endif -} - -/* Convert 24 bit VNI to 64 bit tunnel ID. */ -static __be64 vni_to_tunnel_id(const __u8 *vni) -{ -#ifdef __BIG_ENDIAN - return (vni[0] << 16) | (vni[1] << 8) | vni[2]; -#else - return (__force __be64)(((__force u64)vni[0] << 40) | - ((__force u64)vni[1] << 48) | - ((__force u64)vni[2] << 56)); -#endif -} - -static void geneve_rcv(struct geneve_sock *gs, struct sk_buff *skb) -{ - struct vport *vport = gs->rcv_data; - struct genevehdr *geneveh = geneve_hdr(skb); - int opts_len; - struct ip_tunnel_info tun_info; - __be64 key; - __be16 flags; - - opts_len = geneveh->opt_len * 4; - - flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT | - (udp_hdr(skb)->check != 0 ? TUNNEL_CSUM : 0) | - (geneveh->oam ? TUNNEL_OAM : 0) | - (geneveh->critical ? TUNNEL_CRIT_OPT : 0); - - key = vni_to_tunnel_id(geneveh->vni); - - ip_tunnel_info_init(&tun_info, ip_hdr(skb), - udp_hdr(skb)->source, udp_hdr(skb)->dest, - key, flags, geneveh->options, opts_len); - - ovs_vport_receive(vport, skb, &tun_info); -} - static int geneve_get_options(const struct vport *vport, struct sk_buff *skb) { struct geneve_port *geneve_port = geneve_vport(vport); - struct inet_sock *sk = inet_sk(geneve_port->gs->sock->sk); - if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, ntohs(sk->inet_sport))) + if (nla_put_u16(skb, OVS_TUNNEL_ATTR_DST_PORT, geneve_port->port_no)) return -EMSGSIZE; return 0; } -static void geneve_tnl_destroy(struct vport *vport) +static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, + struct ip_tunnel_info *egress_tun_info) { struct geneve_port *geneve_port = geneve_vport(vport); + struct net *net = ovs_dp_get_net(vport->dp); + __be16 dport = htons(geneve_port->port_no); + __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); - geneve_sock_release(geneve_port->gs); - - ovs_vport_deferred_free(vport); + return ovs_tunnel_get_egress_info(egress_tun_info, + ovs_dp_get_net(vport->dp), + OVS_CB(skb)->egress_tun_info, + IPPROTO_UDP, skb->mark, sport, dport); } static struct vport *geneve_tnl_create(const struct vport_parms *parms) @@ -122,11 +71,11 @@ static struct vport *geneve_tnl_create(const struct vport_parms *parms) struct net *net = ovs_dp_get_net(parms->dp); struct nlattr *options = parms->options; struct geneve_port *geneve_port; - struct geneve_sock *gs; + struct net_device *dev; struct vport *vport; struct nlattr *a; - int err; u16 dst_port; + int err; if (!options) { err = -EINVAL; @@ -148,104 +97,40 @@ static struct vport *geneve_tnl_create(const struct vport_parms *parms) return vport; geneve_port = geneve_vport(vport); - strncpy(geneve_port->name, parms->name, IFNAMSIZ); + geneve_port->port_no = dst_port; - gs = geneve_sock_add(net, htons(dst_port), geneve_rcv, vport, true, 0); - if (IS_ERR(gs)) { + rtnl_lock(); + dev = geneve_dev_create_fb(net, parms->name, NET_NAME_USER, dst_port); + if (IS_ERR(dev)) { + rtnl_unlock(); ovs_vport_free(vport); - return (void *)gs; + return ERR_CAST(dev); } - geneve_port->gs = gs; + dev_change_flags(dev, dev->flags | IFF_UP); + rtnl_unlock(); return vport; error: return ERR_PTR(err); } -static int geneve_tnl_send(struct vport *vport, struct sk_buff *skb) +static struct vport *geneve_create(const struct vport_parms *parms) { - const struct ip_tunnel_key *tun_key; - struct ip_tunnel_info *tun_info; - struct net *net = ovs_dp_get_net(vport->dp); - struct geneve_port *geneve_port = geneve_vport(vport); - __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport; - __be16 sport; - struct rtable *rt; - struct flowi4 fl; - u8 vni[3], opts_len, *opts; - __be16 df; - int err; - - tun_info = OVS_CB(skb)->egress_tun_info; - if (unlikely(!tun_info)) { - err = -EINVAL; - goto error; - } - - tun_key = &tun_info->key; - rt = ovs_tunnel_route_lookup(net, tun_key, skb->mark, &fl, IPPROTO_UDP); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto error; - } - - df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; - sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); - tunnel_id_to_vni(tun_key->tun_id, vni); - skb->ignore_df = 1; - - if (tun_key->tun_flags & TUNNEL_GENEVE_OPT) { - opts = (u8 *)tun_info->options; - opts_len = tun_info->options_len; - } else { - opts = NULL; - opts_len = 0; - } - - err = geneve_xmit_skb(geneve_port->gs, rt, skb, fl.saddr, - tun_key->u.ipv4.dst, tun_key->tos, - tun_key->ttl, df, sport, dport, - tun_key->tun_flags, vni, opts_len, opts, - !!(tun_key->tun_flags & TUNNEL_CSUM), false); - if (err < 0) - ip_rt_put(rt); - return err; - -error: - kfree_skb(skb); - return err; -} - -static const char *geneve_get_name(const struct vport *vport) -{ - struct geneve_port *geneve_port = geneve_vport(vport); - - return geneve_port->name; -} + struct vport *vport; -static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *egress_tun_info) -{ - struct geneve_port *geneve_port = geneve_vport(vport); - struct net *net = ovs_dp_get_net(vport->dp); - __be16 dport = inet_sk(geneve_port->gs->sock->sk)->inet_sport; - __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); + vport = geneve_tnl_create(parms); + if (IS_ERR(vport)) + return vport; - /* Get tp_src and tp_dst, refert to geneve_build_header(). - */ - return ovs_tunnel_get_egress_info(egress_tun_info, - ovs_dp_get_net(vport->dp), - OVS_CB(skb)->egress_tun_info, - IPPROTO_UDP, skb->mark, sport, dport); + return ovs_netdev_link(vport, parms->name); } static struct vport_ops ovs_geneve_vport_ops = { .type = OVS_VPORT_TYPE_GENEVE, - .create = geneve_tnl_create, - .destroy = geneve_tnl_destroy, - .get_name = geneve_get_name, + .create = geneve_create, + .destroy = ovs_netdev_tunnel_destroy, .get_options = geneve_get_options, - .send = geneve_tnl_send, + .send = ovs_netdev_send, .owner = THIS_MODULE, .get_egress_tun_info = geneve_get_egress_tun_info, }; -- GitLab From 371bd1061d29562e6423435073623add8c475ee2 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:54 -0700 Subject: [PATCH 5219/7006] geneve: Consolidate Geneve functionality in single module. geneve_core module handles send and receive functionality. This way OVS could use the Geneve API. Now with use of tunnel meatadata mode OVS can directly use Geneve netdevice. So there is no need for separate module for Geneve. Following patch consolidates Geneve protocol processing in single module. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Acked-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/Kconfig | 4 +- drivers/net/geneve.c | 507 ++++++++++++++++++++++++++++++++++------- include/net/geneve.h | 34 --- net/ipv4/Kconfig | 14 -- net/ipv4/Makefile | 1 - net/ipv4/geneve_core.c | 447 ------------------------------------ 6 files changed, 421 insertions(+), 586 deletions(-) delete mode 100644 net/ipv4/geneve_core.c diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 770483b31d624..d18eb607bee66 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -180,8 +180,8 @@ config VXLAN will be called vxlan. config GENEVE - tristate "Generic Network Virtualization Encapsulation netdev" - depends on INET && GENEVE_CORE + tristate "Generic Network Virtualization Encapsulation" + depends on INET && NET_UDP_TUNNEL select NET_IP_TUNNEL ---help--- This allows one to create geneve virtual interfaces that provide diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index d05150cc25d4b..90d4d433f1c97 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -18,6 +18,7 @@ #include #include #include +#include #define GENEVE_NETDEV_VER "0.6" @@ -33,13 +34,18 @@ static bool log_ecn_error = true; module_param(log_ecn_error, bool, 0644); MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); +#define GENEVE_VER 0 +#define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr)) + /* per-network namespace private data for this module */ struct geneve_net { - struct list_head geneve_list; - struct hlist_head vni_list[VNI_HASH_SIZE]; - struct geneve_dev __rcu *collect_md_tun; + struct list_head geneve_list; + struct hlist_head vni_list[VNI_HASH_SIZE]; + struct list_head sock_list; }; +static int geneve_net_id; + /* Pseudo network device */ struct geneve_dev { struct hlist_node hlist; /* vni hash table */ @@ -55,7 +61,15 @@ struct geneve_dev { bool collect_md; }; -static int geneve_net_id; +struct geneve_sock { + bool collect_md; + struct geneve_net *gn; + struct list_head list; + struct socket *sock; + struct rcu_head rcu; + int refcnt; + struct udp_offload udp_offloads; +}; static inline __u32 geneve_net_vni_hash(u8 vni[3]) { @@ -76,51 +90,62 @@ static __be64 vni_to_tunnel_id(const __u8 *vni) #endif } -static struct geneve_dev *geneve_lookup(struct geneve_net *gn, - struct geneve_sock *gs, - struct iphdr *iph, - struct genevehdr *gnvh) +static struct geneve_dev *geneve_lookup(struct geneve_net *gn, __be16 port, + __be32 addr, u8 vni[]) { - struct inet_sock *sk = inet_sk(gs->sock->sk); struct hlist_head *vni_list_head; struct geneve_dev *geneve; __u32 hash; - geneve = rcu_dereference(gn->collect_md_tun); - if (geneve) - return geneve; - /* Find the device for this VNI */ - hash = geneve_net_vni_hash(gnvh->vni); + hash = geneve_net_vni_hash(vni); vni_list_head = &gn->vni_list[hash]; hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) { - if (!memcmp(gnvh->vni, geneve->vni, sizeof(geneve->vni)) && - iph->saddr == geneve->remote.sin_addr.s_addr && - sk->inet_sport == geneve->dst_port) { + if (!memcmp(vni, geneve->vni, sizeof(geneve->vni)) && + addr == geneve->remote.sin_addr.s_addr && + port == geneve->dst_port) { return geneve; } } return NULL; } +static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) +{ + return (struct genevehdr *)(udp_hdr(skb) + 1); +} + /* geneve receive/decap routine */ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) { + struct inet_sock *sk = inet_sk(gs->sock->sk); struct genevehdr *gnvh = geneve_hdr(skb); + struct geneve_net *gn = gs->gn; struct metadata_dst *tun_dst = NULL; struct geneve_dev *geneve = NULL; struct pcpu_sw_netstats *stats; - struct geneve_net *gn; struct iphdr *iph; + u8 *vni; + __be32 addr; int err; iph = ip_hdr(skb); /* Still outer IP header... */ - gn = gs->rcv_data; - geneve = geneve_lookup(gn, gs, iph, gnvh); + + if (gs->collect_md) { + static u8 zero_vni[3]; + + vni = zero_vni; + addr = 0; + } else { + vni = gnvh->vni; + addr = iph->saddr; + } + + geneve = geneve_lookup(gn, sk->inet_sport, addr, vni); if (!geneve) goto drop; - if (ip_tunnel_collect_metadata() || geneve->collect_md) { + if (ip_tunnel_collect_metadata() || gs->collect_md) { __be16 flags; void *opts; @@ -201,31 +226,326 @@ static void geneve_uninit(struct net_device *dev) free_percpu(dev->tstats); } +/* Callback from net/ipv4/udp.c to receive packets */ +static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) +{ + struct genevehdr *geneveh; + struct geneve_sock *gs; + int opts_len; + + /* Need Geneve and inner Ethernet header to be present */ + if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN))) + goto error; + + /* Return packets with reserved bits set */ + geneveh = geneve_hdr(skb); + if (unlikely(geneveh->ver != GENEVE_VER)) + goto error; + + if (unlikely(geneveh->proto_type != htons(ETH_P_TEB))) + goto error; + + opts_len = geneveh->opt_len * 4; + if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, + htons(ETH_P_TEB))) + goto drop; + + gs = rcu_dereference_sk_user_data(sk); + if (!gs) + goto drop; + + geneve_rx(gs, skb); + return 0; + +drop: + /* Consume bad packet */ + kfree_skb(skb); + return 0; + +error: + /* Let the UDP layer deal with the skb */ + return 1; +} + +static struct socket *geneve_create_sock(struct net *net, bool ipv6, + __be16 port) +{ + struct socket *sock; + struct udp_port_cfg udp_conf; + int err; + + memset(&udp_conf, 0, sizeof(udp_conf)); + + if (ipv6) { + udp_conf.family = AF_INET6; + } else { + udp_conf.family = AF_INET; + udp_conf.local_ip.s_addr = htonl(INADDR_ANY); + } + + udp_conf.local_udp_port = port; + + /* Open UDP socket */ + err = udp_sock_create(net, &udp_conf, &sock); + if (err < 0) + return ERR_PTR(err); + + return sock; +} + +static void geneve_notify_add_rx_port(struct geneve_sock *gs) +{ + struct sock *sk = gs->sock->sk; + sa_family_t sa_family = sk->sk_family; + int err; + + if (sa_family == AF_INET) { + err = udp_add_offload(&gs->udp_offloads); + if (err) + pr_warn("geneve: udp_add_offload failed with status %d\n", + err); + } +} + +static int geneve_hlen(struct genevehdr *gh) +{ + return sizeof(*gh) + gh->opt_len * 4; +} + +static struct sk_buff **geneve_gro_receive(struct sk_buff **head, + struct sk_buff *skb, + struct udp_offload *uoff) +{ + struct sk_buff *p, **pp = NULL; + struct genevehdr *gh, *gh2; + unsigned int hlen, gh_len, off_gnv; + const struct packet_offload *ptype; + __be16 type; + int flush = 1; + + off_gnv = skb_gro_offset(skb); + hlen = off_gnv + sizeof(*gh); + gh = skb_gro_header_fast(skb, off_gnv); + if (skb_gro_header_hard(skb, hlen)) { + gh = skb_gro_header_slow(skb, hlen, off_gnv); + if (unlikely(!gh)) + goto out; + } + + if (gh->ver != GENEVE_VER || gh->oam) + goto out; + gh_len = geneve_hlen(gh); + + hlen = off_gnv + gh_len; + if (skb_gro_header_hard(skb, hlen)) { + gh = skb_gro_header_slow(skb, hlen, off_gnv); + if (unlikely(!gh)) + goto out; + } + + flush = 0; + + for (p = *head; p; p = p->next) { + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + gh2 = (struct genevehdr *)(p->data + off_gnv); + if (gh->opt_len != gh2->opt_len || + memcmp(gh, gh2, gh_len)) { + NAPI_GRO_CB(p)->same_flow = 0; + continue; + } + } + + type = gh->proto_type; + + rcu_read_lock(); + ptype = gro_find_receive_by_type(type); + if (!ptype) { + flush = 1; + goto out_unlock; + } + + skb_gro_pull(skb, gh_len); + skb_gro_postpull_rcsum(skb, gh, gh_len); + pp = ptype->callbacks.gro_receive(head, skb); + +out_unlock: + rcu_read_unlock(); +out: + NAPI_GRO_CB(skb)->flush |= flush; + + return pp; +} + +static int geneve_gro_complete(struct sk_buff *skb, int nhoff, + struct udp_offload *uoff) +{ + struct genevehdr *gh; + struct packet_offload *ptype; + __be16 type; + int gh_len; + int err = -ENOSYS; + + udp_tunnel_gro_complete(skb, nhoff); + + gh = (struct genevehdr *)(skb->data + nhoff); + gh_len = geneve_hlen(gh); + type = gh->proto_type; + + rcu_read_lock(); + ptype = gro_find_complete_by_type(type); + if (ptype) + err = ptype->callbacks.gro_complete(skb, nhoff + gh_len); + + rcu_read_unlock(); + return err; +} + +/* Create new listen socket if needed */ +static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, + bool ipv6) +{ + struct geneve_net *gn = net_generic(net, geneve_net_id); + struct geneve_sock *gs; + struct socket *sock; + struct udp_tunnel_sock_cfg tunnel_cfg; + + gs = kzalloc(sizeof(*gs), GFP_KERNEL); + if (!gs) + return ERR_PTR(-ENOMEM); + + sock = geneve_create_sock(net, ipv6, port); + if (IS_ERR(sock)) { + kfree(gs); + return ERR_CAST(sock); + } + + gs->sock = sock; + gs->refcnt = 1; + gs->gn = gn; + + /* Initialize the geneve udp offloads structure */ + gs->udp_offloads.port = port; + gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive; + gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete; + geneve_notify_add_rx_port(gs); + + /* Mark socket as an encapsulation socket */ + tunnel_cfg.sk_user_data = gs; + tunnel_cfg.encap_type = 1; + tunnel_cfg.encap_rcv = geneve_udp_encap_recv; + tunnel_cfg.encap_destroy = NULL; + setup_udp_tunnel_sock(net, sock, &tunnel_cfg); + + list_add(&gs->list, &gn->sock_list); + return gs; +} + +static void geneve_notify_del_rx_port(struct geneve_sock *gs) +{ + struct sock *sk = gs->sock->sk; + sa_family_t sa_family = sk->sk_family; + + if (sa_family == AF_INET) + udp_del_offload(&gs->udp_offloads); +} + +static void geneve_sock_release(struct geneve_sock *gs) +{ + if (--gs->refcnt) + return; + + list_del(&gs->list); + geneve_notify_del_rx_port(gs); + udp_tunnel_sock_release(gs->sock); + kfree_rcu(gs, rcu); +} + +static struct geneve_sock *geneve_find_sock(struct geneve_net *gn, + __be16 dst_port) +{ + struct geneve_sock *gs; + + list_for_each_entry(gs, &gn->sock_list, list) { + if (inet_sk(gs->sock->sk)->inet_sport == dst_port && + inet_sk(gs->sock->sk)->sk.sk_family == AF_INET) { + return gs; + } + } + return NULL; +} + static int geneve_open(struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); struct net *net = geneve->net; - struct geneve_net *gn = net_generic(geneve->net, geneve_net_id); + struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_sock *gs; - gs = geneve_sock_add(net, geneve->dst_port, geneve_rx, gn, - false, false); + gs = geneve_find_sock(gn, geneve->dst_port); + if (gs) { + gs->refcnt++; + goto out; + } + + gs = geneve_socket_create(net, geneve->dst_port, false); if (IS_ERR(gs)) return PTR_ERR(gs); +out: + gs->collect_md = geneve->collect_md; geneve->sock = gs; - return 0; } static int geneve_stop(struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); - struct geneve_sock *gs = geneve->sock; - geneve_sock_release(gs); + geneve_sock_release(geneve->sock); + return 0; +} + +static int geneve_build_skb(struct rtable *rt, struct sk_buff *skb, + __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt, + bool csum) +{ + struct genevehdr *gnvh; + int min_headroom; + int err; + min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr); + err = skb_cow_head(skb, min_headroom); + if (unlikely(err)) { + kfree_skb(skb); + goto free_rt; + } + + skb = udp_tunnel_handle_offloads(skb, csum); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto free_rt; + } + + gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); + gnvh->ver = GENEVE_VER; + gnvh->opt_len = opt_len / 4; + gnvh->oam = !!(tun_flags & TUNNEL_OAM); + gnvh->critical = !!(tun_flags & TUNNEL_CRIT_OPT); + gnvh->rsvd1 = 0; + memcpy(gnvh->vni, vni, 3); + gnvh->proto_type = htons(ETH_P_TEB); + gnvh->rsvd2 = 0; + memcpy(gnvh->options, opt, opt_len); + + skb_set_inner_protocol(skb, htons(ETH_P_TEB)); return 0; + +free_rt: + ip_rt_put(rt); + return err; } static struct rtable *geneve_get_rt(struct sk_buff *skb, @@ -269,7 +589,6 @@ static struct rtable *geneve_get_rt(struct sk_buff *skb, ip_rt_put(rt); return ERR_PTR(-EINVAL); } - return rt; } @@ -293,15 +612,13 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) struct geneve_sock *gs = geneve->sock; struct ip_tunnel_info *info = NULL; struct rtable *rt = NULL; - const struct iphdr *iip; /* interior IP header */ struct flowi4 fl4; __u8 tos, ttl; __be16 sport; - bool xnet; + bool udp_csum; + __be16 df; int err; - sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); - if (geneve->collect_md) { info = skb_tunnel_info(skb); if (unlikely(info && info->mode != IP_TUNNEL_INFO_TX)) { @@ -316,52 +633,57 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) dev->stats.tx_carrier_errors++; goto tx_error; } + + sport = udp_flow_src_port(geneve->net, skb, 1, USHRT_MAX, true); skb_reset_mac_header(skb); - xnet = !net_eq(geneve->net, dev_net(geneve->dev)); if (info) { const struct ip_tunnel_key *key = &info->key; - bool udp_csum; u8 *opts = NULL; u8 vni[3]; - __be16 df; tunnel_id_to_vni(key->tun_id, vni); - df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; - udp_csum = !!(key->tun_flags & TUNNEL_CSUM); - if (key->tun_flags & TUNNEL_GENEVE_OPT) opts = ip_tunnel_info_opts(info, info->options_len); - err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, - key->tos, key->ttl, df, - sport, geneve->dst_port, - key->tun_flags, vni, - info->options_len, opts, udp_csum, xnet); + udp_csum = !!(key->tun_flags & TUNNEL_CSUM); + err = geneve_build_skb(rt, skb, key->tun_flags, vni, + info->options_len, opts, udp_csum); + if (unlikely(err)) + goto err; + + tos = key->tos; + ttl = key->ttl; + df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; } else { + const struct iphdr *iip; /* interior IP header */ + + udp_csum = false; + err = geneve_build_skb(rt, skb, 0, geneve->vni, + 0, NULL, udp_csum); + if (unlikely(err)) + goto err; + iip = ip_hdr(skb); tos = ip_tunnel_ecn_encap(fl4.flowi4_tos, iip, skb); - ttl = geneve->ttl; if (!ttl && IN_MULTICAST(ntohl(fl4.daddr))) ttl = 1; - ttl = ttl ? : ip4_dst_hoplimit(&rt->dst); - - /* no need to handle local destination and encap bypass...yet... */ - err = geneve_xmit_skb(gs, rt, skb, fl4.saddr, fl4.daddr, tos, - ttl, 0, sport, geneve->dst_port, 0, - geneve->vni, 0, NULL, false, xnet); + df = 0; } - if (err < 0) - ip_rt_put(rt); + err = udp_tunnel_xmit_skb(rt, gs->sock->sk, skb, fl4.saddr, fl4.daddr, + tos, ttl, df, sport, geneve->dst_port, + !net_eq(geneve->net, dev_net(geneve->dev)), + !udp_csum); iptunnel_xmit_stats(err, &dev->stats, dev->tstats); return NETDEV_TX_OK; tx_error: - dev->stats.tx_errors++; dev_kfree_skb(skb); +err: + dev->stats.tx_errors++; return NETDEV_TX_OK; } @@ -454,25 +776,44 @@ static int geneve_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } +static struct geneve_dev *geneve_find_dev(struct geneve_net *gn, + __be16 dst_port, + __be32 rem_addr, + u8 vni[], + bool *tun_on_same_port, + bool *tun_collect_md) +{ + struct geneve_dev *geneve, *t; + + *tun_on_same_port = false; + *tun_collect_md = false; + t = NULL; + list_for_each_entry(geneve, &gn->geneve_list, next) { + if (geneve->dst_port == dst_port) { + *tun_collect_md = geneve->collect_md; + *tun_on_same_port = true; + } + if (!memcmp(vni, geneve->vni, sizeof(geneve->vni)) && + rem_addr == geneve->remote.sin_addr.s_addr && + dst_port == geneve->dst_port) + t = geneve; + } + return t; +} + static int geneve_configure(struct net *net, struct net_device *dev, __be32 rem_addr, __u32 vni, __u8 ttl, __u8 tos, __u16 dst_port, bool metadata) { struct geneve_net *gn = net_generic(net, geneve_net_id); - struct geneve_dev *dummy, *geneve = netdev_priv(dev); - struct hlist_head *vni_list_head; - struct sockaddr_in remote; /* IPv4 address for link partner */ + struct geneve_dev *t, *geneve = netdev_priv(dev); + bool tun_collect_md, tun_on_same_port; __u32 hash; int err; if (metadata) { - if (rtnl_dereference(gn->collect_md_tun)) - return -EEXIST; - if (!list_empty(&gn->geneve_list)) - return -EPERM; - } else { - if (rtnl_dereference(gn->collect_md_tun)) - return -EPERM; + if (rem_addr || vni || tos || ttl) + return -EINVAL; } geneve->net = net; @@ -486,36 +827,31 @@ static int geneve_configure(struct net *net, struct net_device *dev, if (IN_MULTICAST(ntohl(geneve->remote.sin_addr.s_addr))) return -EINVAL; - remote = geneve->remote; - if (metadata) { - if (rem_addr || vni || tos || ttl) - return -EINVAL; - } - - hash = geneve_net_vni_hash(geneve->vni); - vni_list_head = &gn->vni_list[hash]; - hlist_for_each_entry_rcu(dummy, vni_list_head, hlist) { - if (!memcmp(geneve->vni, dummy->vni, sizeof(dummy->vni)) && - !memcmp(&remote, &dummy->remote, sizeof(dummy->remote)) && - htons(dst_port) == dummy->dst_port) { - return -EBUSY; - } - } - geneve->ttl = ttl; geneve->tos = tos; geneve->dst_port = htons(dst_port); geneve->collect_md = metadata; + t = geneve_find_dev(gn, htons(dst_port), rem_addr, geneve->vni, + &tun_on_same_port, &tun_collect_md); + if (t) + return -EBUSY; + + if (metadata) { + if (tun_on_same_port) + return -EPERM; + } else { + if (tun_collect_md) + return -EPERM; + } + err = register_netdevice(dev); if (err) return err; list_add(&geneve->next, &gn->geneve_list); + hash = geneve_net_vni_hash(geneve->vni); hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); - - if (geneve->collect_md) - rcu_assign_pointer(gn->collect_md_tun, geneve); return 0; } @@ -554,12 +890,6 @@ static void geneve_dellink(struct net_device *dev, struct list_head *head) { struct geneve_dev *geneve = netdev_priv(dev); - if (geneve->collect_md) { - struct geneve_net *gn = net_generic(geneve->net, geneve_net_id); - - rcu_assign_pointer(gn->collect_md_tun, NULL); - } - if (!hlist_unhashed(&geneve->hlist)) hlist_del_rcu(&geneve->hlist); @@ -651,6 +981,7 @@ static __net_init int geneve_init_net(struct net *net) INIT_LIST_HEAD(&gn->geneve_list); + INIT_LIST_HEAD(&gn->sock_list); for (h = 0; h < VNI_HASH_SIZE; ++h) INIT_HLIST_HEAD(&gn->vni_list[h]); diff --git a/include/net/geneve.h b/include/net/geneve.h index 4245e1d23b9b8..3106ed6eae0d1 100644 --- a/include/net/geneve.h +++ b/include/net/geneve.h @@ -62,41 +62,7 @@ struct genevehdr { struct geneve_opt options[]; }; -static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) -{ - return (struct genevehdr *)(udp_hdr(skb) + 1); -} - #ifdef CONFIG_INET -struct geneve_sock; - -typedef void (geneve_rcv_t)(struct geneve_sock *gs, struct sk_buff *skb); - -struct geneve_sock { - struct list_head list; - geneve_rcv_t *rcv; - void *rcv_data; - struct socket *sock; - struct rcu_head rcu; - int refcnt; - struct udp_offload udp_offloads; -}; - -#define GENEVE_VER 0 -#define GENEVE_BASE_HLEN (sizeof(struct udphdr) + sizeof(struct genevehdr)) - -struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, - geneve_rcv_t *rcv, void *data, - bool no_share, bool ipv6); - -void geneve_sock_release(struct geneve_sock *vs); - -int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, - struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, - __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, - __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt, - bool csum, bool xnet); - struct net_device *geneve_dev_create_fb(struct net *net, const char *name, u8 name_assign_type, u16 dst_port); #endif /*ifdef CONFIG_INET */ diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index 6fb3c90ad7261..416dfa004cfb1 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -331,20 +331,6 @@ config NET_FOU_IP_TUNNELS When this option is enabled IP tunnels can be configured to use FOU or GUE encapsulation. -config GENEVE_CORE - tristate "Generic Network Virtualization Encapsulation library" - depends on INET - select NET_UDP_TUNNEL - ---help--- - This allows one to create Geneve virtual interfaces that provide - Layer 2 Networks over Layer 3 Networks. Geneve is often used - to tunnel virtual network infrastructure in virtualized environments. - For more information see: - http://tools.ietf.org/html/draft-gross-geneve-01 - - To compile this driver as a module, choose M here: the module - - config INET_AH tristate "IP: AH transformation" select XFRM_ALGO diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index efc43f300b8c2..89aacb630a533 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile @@ -57,7 +57,6 @@ obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o obj-$(CONFIG_MEMCG_KMEM) += tcp_memcontrol.o obj-$(CONFIG_NETLABEL) += cipso_ipv4.o -obj-$(CONFIG_GENEVE_CORE) += geneve_core.o obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ xfrm4_output.o xfrm4_protocol.o diff --git a/net/ipv4/geneve_core.c b/net/ipv4/geneve_core.c deleted file mode 100644 index 311a4ba6950a6..0000000000000 --- a/net/ipv4/geneve_core.c +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Geneve: Generic Network Virtualization Encapsulation - * - * Copyright (c) 2014 Nicira, Inc. - * - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if IS_ENABLED(CONFIG_IPV6) -#include -#include -#include -#include -#endif - -/* Protects sock_list and refcounts. */ -static DEFINE_MUTEX(geneve_mutex); - -/* per-network namespace private data for this module */ -struct geneve_net { - struct list_head sock_list; -}; - -static int geneve_net_id; - -static struct geneve_sock *geneve_find_sock(struct net *net, - sa_family_t family, __be16 port) -{ - struct geneve_net *gn = net_generic(net, geneve_net_id); - struct geneve_sock *gs; - - list_for_each_entry(gs, &gn->sock_list, list) { - if (inet_sk(gs->sock->sk)->inet_sport == port && - inet_sk(gs->sock->sk)->sk.sk_family == family) - return gs; - } - - return NULL; -} - -static void geneve_build_header(struct genevehdr *geneveh, - __be16 tun_flags, u8 vni[3], - u8 options_len, u8 *options) -{ - geneveh->ver = GENEVE_VER; - geneveh->opt_len = options_len / 4; - geneveh->oam = !!(tun_flags & TUNNEL_OAM); - geneveh->critical = !!(tun_flags & TUNNEL_CRIT_OPT); - geneveh->rsvd1 = 0; - memcpy(geneveh->vni, vni, 3); - geneveh->proto_type = htons(ETH_P_TEB); - geneveh->rsvd2 = 0; - - memcpy(geneveh->options, options, options_len); -} - -/* Transmit a fully formatted Geneve frame. - * - * When calling this function. The skb->data should point - * to the geneve header which is fully formed. - * - * This function will add other UDP tunnel headers. - */ -int geneve_xmit_skb(struct geneve_sock *gs, struct rtable *rt, - struct sk_buff *skb, __be32 src, __be32 dst, __u8 tos, - __u8 ttl, __be16 df, __be16 src_port, __be16 dst_port, - __be16 tun_flags, u8 vni[3], u8 opt_len, u8 *opt, - bool csum, bool xnet) -{ - struct genevehdr *gnvh; - int min_headroom; - int err; - - min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len - + GENEVE_BASE_HLEN + opt_len + sizeof(struct iphdr) - + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); - - err = skb_cow_head(skb, min_headroom); - if (unlikely(err)) { - kfree_skb(skb); - return err; - } - - skb = vlan_hwaccel_push_inside(skb); - if (unlikely(!skb)) - return -ENOMEM; - - skb = udp_tunnel_handle_offloads(skb, csum); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - gnvh = (struct genevehdr *)__skb_push(skb, sizeof(*gnvh) + opt_len); - geneve_build_header(gnvh, tun_flags, vni, opt_len, opt); - - skb_set_inner_protocol(skb, htons(ETH_P_TEB)); - - return udp_tunnel_xmit_skb(rt, gs->sock->sk, skb, src, dst, - tos, ttl, df, src_port, dst_port, xnet, - !csum); -} -EXPORT_SYMBOL_GPL(geneve_xmit_skb); - -static int geneve_hlen(struct genevehdr *gh) -{ - return sizeof(*gh) + gh->opt_len * 4; -} - -static struct sk_buff **geneve_gro_receive(struct sk_buff **head, - struct sk_buff *skb, - struct udp_offload *uoff) -{ - struct sk_buff *p, **pp = NULL; - struct genevehdr *gh, *gh2; - unsigned int hlen, gh_len, off_gnv; - const struct packet_offload *ptype; - __be16 type; - int flush = 1; - - off_gnv = skb_gro_offset(skb); - hlen = off_gnv + sizeof(*gh); - gh = skb_gro_header_fast(skb, off_gnv); - if (skb_gro_header_hard(skb, hlen)) { - gh = skb_gro_header_slow(skb, hlen, off_gnv); - if (unlikely(!gh)) - goto out; - } - - if (gh->ver != GENEVE_VER || gh->oam) - goto out; - gh_len = geneve_hlen(gh); - - hlen = off_gnv + gh_len; - if (skb_gro_header_hard(skb, hlen)) { - gh = skb_gro_header_slow(skb, hlen, off_gnv); - if (unlikely(!gh)) - goto out; - } - - flush = 0; - - for (p = *head; p; p = p->next) { - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - gh2 = (struct genevehdr *)(p->data + off_gnv); - if (gh->opt_len != gh2->opt_len || - memcmp(gh, gh2, gh_len)) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - } - - type = gh->proto_type; - - rcu_read_lock(); - ptype = gro_find_receive_by_type(type); - if (!ptype) { - flush = 1; - goto out_unlock; - } - - skb_gro_pull(skb, gh_len); - skb_gro_postpull_rcsum(skb, gh, gh_len); - pp = ptype->callbacks.gro_receive(head, skb); - -out_unlock: - rcu_read_unlock(); -out: - NAPI_GRO_CB(skb)->flush |= flush; - - return pp; -} - -static int geneve_gro_complete(struct sk_buff *skb, int nhoff, - struct udp_offload *uoff) -{ - struct genevehdr *gh; - struct packet_offload *ptype; - __be16 type; - int gh_len; - int err = -ENOSYS; - - udp_tunnel_gro_complete(skb, nhoff); - - gh = (struct genevehdr *)(skb->data + nhoff); - gh_len = geneve_hlen(gh); - type = gh->proto_type; - - rcu_read_lock(); - ptype = gro_find_complete_by_type(type); - if (ptype) - err = ptype->callbacks.gro_complete(skb, nhoff + gh_len); - - rcu_read_unlock(); - return err; -} - -static void geneve_notify_add_rx_port(struct geneve_sock *gs) -{ - struct sock *sk = gs->sock->sk; - sa_family_t sa_family = sk->sk_family; - int err; - - if (sa_family == AF_INET) { - err = udp_add_offload(&gs->udp_offloads); - if (err) - pr_warn("geneve: udp_add_offload failed with status %d\n", - err); - } -} - -static void geneve_notify_del_rx_port(struct geneve_sock *gs) -{ - struct sock *sk = gs->sock->sk; - sa_family_t sa_family = sk->sk_family; - - if (sa_family == AF_INET) - udp_del_offload(&gs->udp_offloads); -} - -/* Callback from net/ipv4/udp.c to receive packets */ -static int geneve_udp_encap_recv(struct sock *sk, struct sk_buff *skb) -{ - struct genevehdr *geneveh; - struct geneve_sock *gs; - int opts_len; - - /* Need Geneve and inner Ethernet header to be present */ - if (unlikely(!pskb_may_pull(skb, GENEVE_BASE_HLEN))) - goto error; - - /* Return packets with reserved bits set */ - geneveh = geneve_hdr(skb); - - if (unlikely(geneveh->ver != GENEVE_VER)) - goto error; - - if (unlikely(geneveh->proto_type != htons(ETH_P_TEB))) - goto error; - - opts_len = geneveh->opt_len * 4; - if (iptunnel_pull_header(skb, GENEVE_BASE_HLEN + opts_len, - htons(ETH_P_TEB))) - goto drop; - - gs = rcu_dereference_sk_user_data(sk); - if (!gs) - goto drop; - - gs->rcv(gs, skb); - return 0; - -drop: - /* Consume bad packet */ - kfree_skb(skb); - return 0; - -error: - /* Let the UDP layer deal with the skb */ - return 1; -} - -static struct socket *geneve_create_sock(struct net *net, bool ipv6, - __be16 port) -{ - struct socket *sock; - struct udp_port_cfg udp_conf; - int err; - - memset(&udp_conf, 0, sizeof(udp_conf)); - - if (ipv6) { - udp_conf.family = AF_INET6; - } else { - udp_conf.family = AF_INET; - udp_conf.local_ip.s_addr = htonl(INADDR_ANY); - } - - udp_conf.local_udp_port = port; - - /* Open UDP socket */ - err = udp_sock_create(net, &udp_conf, &sock); - if (err < 0) - return ERR_PTR(err); - - return sock; -} - -/* Create new listen socket if needed */ -static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, - geneve_rcv_t *rcv, void *data, - bool ipv6) -{ - struct geneve_net *gn = net_generic(net, geneve_net_id); - struct geneve_sock *gs; - struct socket *sock; - struct udp_tunnel_sock_cfg tunnel_cfg; - - gs = kzalloc(sizeof(*gs), GFP_KERNEL); - if (!gs) - return ERR_PTR(-ENOMEM); - - sock = geneve_create_sock(net, ipv6, port); - if (IS_ERR(sock)) { - kfree(gs); - return ERR_CAST(sock); - } - - gs->sock = sock; - gs->refcnt = 1; - gs->rcv = rcv; - gs->rcv_data = data; - - /* Initialize the geneve udp offloads structure */ - gs->udp_offloads.port = port; - gs->udp_offloads.callbacks.gro_receive = geneve_gro_receive; - gs->udp_offloads.callbacks.gro_complete = geneve_gro_complete; - geneve_notify_add_rx_port(gs); - - /* Mark socket as an encapsulation socket */ - tunnel_cfg.sk_user_data = gs; - tunnel_cfg.encap_type = 1; - tunnel_cfg.encap_rcv = geneve_udp_encap_recv; - tunnel_cfg.encap_destroy = NULL; - setup_udp_tunnel_sock(net, sock, &tunnel_cfg); - - list_add(&gs->list, &gn->sock_list); - - return gs; -} - -struct geneve_sock *geneve_sock_add(struct net *net, __be16 port, - geneve_rcv_t *rcv, void *data, - bool no_share, bool ipv6) -{ - struct geneve_sock *gs; - - mutex_lock(&geneve_mutex); - - gs = geneve_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port); - if (gs) { - if (!no_share && gs->rcv == rcv) - gs->refcnt++; - else - gs = ERR_PTR(-EBUSY); - } else { - gs = geneve_socket_create(net, port, rcv, data, ipv6); - } - - mutex_unlock(&geneve_mutex); - - return gs; -} -EXPORT_SYMBOL_GPL(geneve_sock_add); - -void geneve_sock_release(struct geneve_sock *gs) -{ - mutex_lock(&geneve_mutex); - - if (--gs->refcnt) - goto unlock; - - list_del(&gs->list); - geneve_notify_del_rx_port(gs); - udp_tunnel_sock_release(gs->sock); - kfree_rcu(gs, rcu); - -unlock: - mutex_unlock(&geneve_mutex); -} -EXPORT_SYMBOL_GPL(geneve_sock_release); - -static __net_init int geneve_init_net(struct net *net) -{ - struct geneve_net *gn = net_generic(net, geneve_net_id); - - INIT_LIST_HEAD(&gn->sock_list); - - return 0; -} - -static struct pernet_operations geneve_net_ops = { - .init = geneve_init_net, - .id = &geneve_net_id, - .size = sizeof(struct geneve_net), -}; - -static int __init geneve_init_module(void) -{ - int rc; - - rc = register_pernet_subsys(&geneve_net_ops); - if (rc) - return rc; - - pr_info("Geneve core logic\n"); - - return 0; -} -module_init(geneve_init_module); - -static void __exit geneve_cleanup_module(void) -{ - unregister_pernet_subsys(&geneve_net_ops); -} -module_exit(geneve_cleanup_module); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Jesse Gross "); -MODULE_DESCRIPTION("Driver library for GENEVE encapsulated traffic"); -- GitLab From 66d47003f7c1034d66776ab869030f73f6c9ce81 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Wed, 26 Aug 2015 23:46:55 -0700 Subject: [PATCH 5220/7006] geneve: Move device hash table to geneve socket. This change simplifies Geneve Tunnel hash table management. Signed-off-by: Pravin B Shelar Reviewed-by: Jesse Gross Reviewed-by: John W. Linville Signed-off-by: David S. Miller --- drivers/net/geneve.c | 43 +++++++++++++++++-------------------------- 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 90d4d433f1c97..4357bae732d73 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -40,7 +40,6 @@ MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); /* per-network namespace private data for this module */ struct geneve_net { struct list_head geneve_list; - struct hlist_head vni_list[VNI_HASH_SIZE]; struct list_head sock_list; }; @@ -63,12 +62,12 @@ struct geneve_dev { struct geneve_sock { bool collect_md; - struct geneve_net *gn; struct list_head list; struct socket *sock; struct rcu_head rcu; int refcnt; struct udp_offload udp_offloads; + struct hlist_head vni_list[VNI_HASH_SIZE]; }; static inline __u32 geneve_net_vni_hash(u8 vni[3]) @@ -90,7 +89,7 @@ static __be64 vni_to_tunnel_id(const __u8 *vni) #endif } -static struct geneve_dev *geneve_lookup(struct geneve_net *gn, __be16 port, +static struct geneve_dev *geneve_lookup(struct geneve_sock *gs, __be32 addr, u8 vni[]) { struct hlist_head *vni_list_head; @@ -99,13 +98,11 @@ static struct geneve_dev *geneve_lookup(struct geneve_net *gn, __be16 port, /* Find the device for this VNI */ hash = geneve_net_vni_hash(vni); - vni_list_head = &gn->vni_list[hash]; + vni_list_head = &gs->vni_list[hash]; hlist_for_each_entry_rcu(geneve, vni_list_head, hlist) { if (!memcmp(vni, geneve->vni, sizeof(geneve->vni)) && - addr == geneve->remote.sin_addr.s_addr && - port == geneve->dst_port) { + addr == geneve->remote.sin_addr.s_addr) return geneve; - } } return NULL; } @@ -118,9 +115,7 @@ static inline struct genevehdr *geneve_hdr(const struct sk_buff *skb) /* geneve receive/decap routine */ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) { - struct inet_sock *sk = inet_sk(gs->sock->sk); struct genevehdr *gnvh = geneve_hdr(skb); - struct geneve_net *gn = gs->gn; struct metadata_dst *tun_dst = NULL; struct geneve_dev *geneve = NULL; struct pcpu_sw_netstats *stats; @@ -129,8 +124,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) __be32 addr; int err; - iph = ip_hdr(skb); /* Still outer IP header... */ - if (gs->collect_md) { static u8 zero_vni[3]; @@ -138,10 +131,11 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) addr = 0; } else { vni = gnvh->vni; + iph = ip_hdr(skb); /* Still outer IP header... */ addr = iph->saddr; } - geneve = geneve_lookup(gn, sk->inet_sport, addr, vni); + geneve = geneve_lookup(gs, addr, vni); if (!geneve) goto drop; @@ -410,6 +404,7 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, struct geneve_sock *gs; struct socket *sock; struct udp_tunnel_sock_cfg tunnel_cfg; + int h; gs = kzalloc(sizeof(*gs), GFP_KERNEL); if (!gs) @@ -423,7 +418,8 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, gs->sock = sock; gs->refcnt = 1; - gs->gn = gn; + for (h = 0; h < VNI_HASH_SIZE; ++h) + INIT_HLIST_HEAD(&gs->vni_list[h]); /* Initialize the geneve udp offloads structure */ gs->udp_offloads.port = port; @@ -437,7 +433,6 @@ static struct geneve_sock *geneve_socket_create(struct net *net, __be16 port, tunnel_cfg.encap_rcv = geneve_udp_encap_recv; tunnel_cfg.encap_destroy = NULL; setup_udp_tunnel_sock(net, sock, &tunnel_cfg); - list_add(&gs->list, &gn->sock_list); return gs; } @@ -482,6 +477,7 @@ static int geneve_open(struct net_device *dev) struct net *net = geneve->net; struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_sock *gs; + __u32 hash; gs = geneve_find_sock(gn, geneve->dst_port); if (gs) { @@ -496,14 +492,20 @@ static int geneve_open(struct net_device *dev) out: gs->collect_md = geneve->collect_md; geneve->sock = gs; + + hash = geneve_net_vni_hash(geneve->vni); + hlist_add_head_rcu(&geneve->hlist, &gs->vni_list[hash]); return 0; } static int geneve_stop(struct net_device *dev) { struct geneve_dev *geneve = netdev_priv(dev); + struct geneve_sock *gs = geneve->sock; - geneve_sock_release(geneve->sock); + if (!hlist_unhashed(&geneve->hlist)) + hlist_del_rcu(&geneve->hlist); + geneve_sock_release(gs); return 0; } @@ -808,7 +810,6 @@ static int geneve_configure(struct net *net, struct net_device *dev, struct geneve_net *gn = net_generic(net, geneve_net_id); struct geneve_dev *t, *geneve = netdev_priv(dev); bool tun_collect_md, tun_on_same_port; - __u32 hash; int err; if (metadata) { @@ -850,8 +851,6 @@ static int geneve_configure(struct net *net, struct net_device *dev, return err; list_add(&geneve->next, &gn->geneve_list); - hash = geneve_net_vni_hash(geneve->vni); - hlist_add_head_rcu(&geneve->hlist, &gn->vni_list[hash]); return 0; } @@ -890,9 +889,6 @@ static void geneve_dellink(struct net_device *dev, struct list_head *head) { struct geneve_dev *geneve = netdev_priv(dev); - if (!hlist_unhashed(&geneve->hlist)) - hlist_del_rcu(&geneve->hlist); - list_del(&geneve->next); unregister_netdevice_queue(dev, head); } @@ -977,14 +973,9 @@ EXPORT_SYMBOL_GPL(geneve_dev_create_fb); static __net_init int geneve_init_net(struct net *net) { struct geneve_net *gn = net_generic(net, geneve_net_id); - unsigned int h; INIT_LIST_HEAD(&gn->geneve_list); - INIT_LIST_HEAD(&gn->sock_list); - for (h = 0; h < VNI_HASH_SIZE; ++h) - INIT_HLIST_HEAD(&gn->vni_list[h]); - return 0; } -- GitLab From 547c890cfd26010e01b3faf98f29ca9b2252c8d8 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Thu, 27 Aug 2015 14:53:06 +0800 Subject: [PATCH 5221/7006] virtio-net: avoid unnecessary sg initialzation Usually an skb does not have up to MAX_SKB_FRAGS frags. So no need to initialize the unuse part of sg. This patch initialize the sg based on the real number it will used: - during xmit, it could be inferred from nr_frags and can_push. - for small receive buffer, it will also be 2. Cc: Michael S. Tsirkin Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 9b950f2db836f..d8838dedb7a4c 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -540,7 +540,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, skb_put(skb, GOOD_PACKET_LEN); hdr = skb_vnet_hdr(skb); - sg_init_table(rq->sg, MAX_SKB_FRAGS + 2); + sg_init_table(rq->sg, 2); sg_set_buf(rq->sg, hdr, vi->hdr_len); skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); @@ -893,7 +893,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) if (vi->mergeable_rx_bufs) hdr->num_buffers = 0; - sg_init_table(sq->sg, MAX_SKB_FRAGS + 2); + sg_init_table(sq->sg, skb_shinfo(skb)->nr_frags + (can_push ? 1 : 2)); if (can_push) { __skb_push(skb, hdr_len); num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); -- GitLab From 0bdb8fa6ecb4a356f26c6874db51b5488706e088 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Aug 2015 19:17:33 -0400 Subject: [PATCH 5222/7006] NFSv4.1/pNFS: pnfs_mark_matching_lsegs_return must notify of layout return It's not sufficient to just mark the layout segment for layout return. We also need to set the NFS_LAYOUT_RETURN_BEFORE_CLOSE flag in the layout header. Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 914c1daf08dfe..4eec540de9ea0 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1717,6 +1717,8 @@ pnfs_mark_matching_lsegs_return(struct pnfs_layout_hdr *lo, lseg->pls_range.length); set_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags); mark_lseg_invalid(lseg, tmp_list); + set_bit(NFS_LAYOUT_RETURN_BEFORE_CLOSE, + &lo->plh_flags); } } -- GitLab From 0e4ead9d7b3655d76371604abb9b0dcc4e79bb7d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 09:31:18 +0200 Subject: [PATCH 5223/7006] net: introduce change upper device notifier change info Add info that is passed along with NETDEV_CHANGEUPPER event. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 7 +++++++ net/core/dev.c | 16 ++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 6abe0d6f1e1d4..39f30daac4830 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -2127,6 +2127,13 @@ struct netdev_notifier_change_info { unsigned int flags_changed; }; +struct netdev_notifier_changeupper_info { + struct netdev_notifier_info info; /* must be first */ + struct net_device *upper_dev; /* new upper dev */ + bool master; /* is upper dev master */ + bool linking; /* is the nofication for link or unlink */ +}; + static inline void netdev_notifier_info_init(struct netdev_notifier_info *info, struct net_device *dev) { diff --git a/net/core/dev.c b/net/core/dev.c index 7bb24f1879b89..a8e6cf4298d32 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5311,6 +5311,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev, bool master, void *private) { + struct netdev_notifier_changeupper_info changeupper_info; struct netdev_adjacent *i, *j, *to_i, *to_j; int ret = 0; @@ -5329,6 +5330,10 @@ static int __netdev_upper_dev_link(struct net_device *dev, if (master && netdev_master_upper_dev_get(dev)) return -EBUSY; + changeupper_info.upper_dev = upper_dev; + changeupper_info.master = master; + changeupper_info.linking = true; + ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, private, master); if (ret) @@ -5367,7 +5372,8 @@ static int __netdev_upper_dev_link(struct net_device *dev, goto rollback_lower_mesh; } - call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, + &changeupper_info.info); return 0; rollback_lower_mesh: @@ -5462,9 +5468,14 @@ EXPORT_SYMBOL(netdev_master_upper_dev_link_private); void netdev_upper_dev_unlink(struct net_device *dev, struct net_device *upper_dev) { + struct netdev_notifier_changeupper_info changeupper_info; struct netdev_adjacent *i, *j; ASSERT_RTNL(); + changeupper_info.upper_dev = upper_dev; + changeupper_info.master = netdev_master_upper_dev_get(dev) == upper_dev; + changeupper_info.linking = false; + __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); /* Here is the tricky part. We must remove all dev's lower @@ -5484,7 +5495,8 @@ void netdev_upper_dev_unlink(struct net_device *dev, list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) __netdev_adjacent_dev_unlink(dev, i->dev); - call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, + &changeupper_info.info); } EXPORT_SYMBOL(netdev_upper_dev_unlink); -- GitLab From 0894ae3f0a587bda9733ec4a4b67af7ded3a9498 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 09:31:19 +0200 Subject: [PATCH 5224/7006] net: add netif_is_bridge_master helper Add this helper so code can easily figure out if netdev is a bridge. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 39f30daac4830..be625f4754b9c 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3848,6 +3848,11 @@ static inline bool netif_is_vrf(const struct net_device *dev) return dev->priv_flags & IFF_VRF_MASTER; } +static inline bool netif_is_bridge_master(const struct net_device *dev) +{ + return dev->priv_flags & IFF_EBRIDGE; +} + static inline bool netif_index_is_vrf(struct net *net, int ifindex) { bool rc = false; -- GitLab From 35d4e1725202e6656fcfa8b88447327ad3ae0c0c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 09:31:20 +0200 Subject: [PATCH 5225/7006] net: add netif_is_ovs_master helper with IFF_OPENVSWITCH private flag Add this helper so code can easily figure out if netdev is openswitch. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 8 ++++++++ net/openvswitch/vport-internal_dev.c | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index be625f4754b9c..6656a43c072db 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1264,6 +1264,7 @@ struct net_device_ops { * @IFF_MACVLAN: Macvlan device * @IFF_VRF_MASTER: device is a VRF master * @IFF_NO_QUEUE: device can run without qdisc attached + * @IFF_OPENVSWITCH: device is a Open vSwitch master */ enum netdev_priv_flags { IFF_802_1Q_VLAN = 1<<0, @@ -1293,6 +1294,7 @@ enum netdev_priv_flags { IFF_IPVLAN_SLAVE = 1<<24, IFF_VRF_MASTER = 1<<25, IFF_NO_QUEUE = 1<<26, + IFF_OPENVSWITCH = 1<<27, }; #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN @@ -1322,6 +1324,7 @@ enum netdev_priv_flags { #define IFF_IPVLAN_SLAVE IFF_IPVLAN_SLAVE #define IFF_VRF_MASTER IFF_VRF_MASTER #define IFF_NO_QUEUE IFF_NO_QUEUE +#define IFF_OPENVSWITCH IFF_OPENVSWITCH /** * struct net_device - The DEVICE structure. @@ -3853,6 +3856,11 @@ static inline bool netif_is_bridge_master(const struct net_device *dev) return dev->priv_flags & IFF_EBRIDGE; } +static inline bool netif_is_ovs_master(const struct net_device *dev) +{ + return dev->priv_flags & IFF_OPENVSWITCH; +} + static inline bool netif_index_is_vrf(struct net *net, int ifindex) { bool rc = false; diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index c058bbf876c34..80b3e12ec8827 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -135,7 +135,7 @@ static void do_setup(struct net_device *netdev) netdev->netdev_ops = &internal_dev_netdev_ops; netdev->priv_flags &= ~IFF_TX_SKB_SHARING; - netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netdev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_OPENVSWITCH; netdev->destructor = internal_dev_destructor; netdev->ethtool_ops = &internal_dev_ethtool_ops; netdev->rtnl_link_ops = &internal_dev_link_ops; -- GitLab From 0dc1549bfd67053181415a3f7544628a6bcd2a08 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 09:31:21 +0200 Subject: [PATCH 5226/7006] net: kill long time unused bonding private flags We don't use them for years, just kill them now. Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- include/linux/netdevice.h | 57 +++++++++++++++------------------------ 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 6656a43c072db..88a00694eda5f 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -1240,13 +1240,8 @@ struct net_device_ops { * * @IFF_802_1Q_VLAN: 802.1Q VLAN device * @IFF_EBRIDGE: Ethernet bridging device - * @IFF_SLAVE_INACTIVE: bonding slave not the curr. active - * @IFF_MASTER_8023AD: bonding master, 802.3ad - * @IFF_MASTER_ALB: bonding master, balance-alb * @IFF_BONDING: bonding master or slave - * @IFF_SLAVE_NEEDARP: need ARPs for validation * @IFF_ISATAP: ISATAP interface (RFC4214) - * @IFF_MASTER_ARPMON: bonding master, ARP mon in use * @IFF_WAN_HDLC: WAN HDLC device * @IFF_XMIT_DST_RELEASE: dev_hard_start_xmit() is allowed to * release skb->dst @@ -1269,43 +1264,33 @@ struct net_device_ops { enum netdev_priv_flags { IFF_802_1Q_VLAN = 1<<0, IFF_EBRIDGE = 1<<1, - IFF_SLAVE_INACTIVE = 1<<2, - IFF_MASTER_8023AD = 1<<3, - IFF_MASTER_ALB = 1<<4, - IFF_BONDING = 1<<5, - IFF_SLAVE_NEEDARP = 1<<6, - IFF_ISATAP = 1<<7, - IFF_MASTER_ARPMON = 1<<8, - IFF_WAN_HDLC = 1<<9, - IFF_XMIT_DST_RELEASE = 1<<10, - IFF_DONT_BRIDGE = 1<<11, - IFF_DISABLE_NETPOLL = 1<<12, - IFF_MACVLAN_PORT = 1<<13, - IFF_BRIDGE_PORT = 1<<14, - IFF_OVS_DATAPATH = 1<<15, - IFF_TX_SKB_SHARING = 1<<16, - IFF_UNICAST_FLT = 1<<17, - IFF_TEAM_PORT = 1<<18, - IFF_SUPP_NOFCS = 1<<19, - IFF_LIVE_ADDR_CHANGE = 1<<20, - IFF_MACVLAN = 1<<21, - IFF_XMIT_DST_RELEASE_PERM = 1<<22, - IFF_IPVLAN_MASTER = 1<<23, - IFF_IPVLAN_SLAVE = 1<<24, - IFF_VRF_MASTER = 1<<25, - IFF_NO_QUEUE = 1<<26, - IFF_OPENVSWITCH = 1<<27, + IFF_BONDING = 1<<2, + IFF_ISATAP = 1<<3, + IFF_WAN_HDLC = 1<<4, + IFF_XMIT_DST_RELEASE = 1<<5, + IFF_DONT_BRIDGE = 1<<6, + IFF_DISABLE_NETPOLL = 1<<7, + IFF_MACVLAN_PORT = 1<<8, + IFF_BRIDGE_PORT = 1<<9, + IFF_OVS_DATAPATH = 1<<10, + IFF_TX_SKB_SHARING = 1<<11, + IFF_UNICAST_FLT = 1<<12, + IFF_TEAM_PORT = 1<<13, + IFF_SUPP_NOFCS = 1<<14, + IFF_LIVE_ADDR_CHANGE = 1<<15, + IFF_MACVLAN = 1<<16, + IFF_XMIT_DST_RELEASE_PERM = 1<<17, + IFF_IPVLAN_MASTER = 1<<18, + IFF_IPVLAN_SLAVE = 1<<19, + IFF_VRF_MASTER = 1<<20, + IFF_NO_QUEUE = 1<<21, + IFF_OPENVSWITCH = 1<<22, }; #define IFF_802_1Q_VLAN IFF_802_1Q_VLAN #define IFF_EBRIDGE IFF_EBRIDGE -#define IFF_SLAVE_INACTIVE IFF_SLAVE_INACTIVE -#define IFF_MASTER_8023AD IFF_MASTER_8023AD -#define IFF_MASTER_ALB IFF_MASTER_ALB #define IFF_BONDING IFF_BONDING -#define IFF_SLAVE_NEEDARP IFF_SLAVE_NEEDARP #define IFF_ISATAP IFF_ISATAP -#define IFF_MASTER_ARPMON IFF_MASTER_ARPMON #define IFF_WAN_HDLC IFF_WAN_HDLC #define IFF_XMIT_DST_RELEASE IFF_XMIT_DST_RELEASE #define IFF_DONT_BRIDGE IFF_DONT_BRIDGE -- GitLab From fb4bf214346e37778bcf00a89bfb90112859b23c Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 09:31:22 +0200 Subject: [PATCH 5227/7006] rocker: use new helper to figure out master kind Looking at rtnl kind string is kind of ugly. So use new helpers to do this in nicer way. Signed-off-by: Jiri Pirko Acked-by: Scott Feldman --- drivers/net/ethernet/rocker/rocker.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index a7cb74ac47586..62f383c84a664 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -322,21 +322,16 @@ static u16 rocker_port_vlan_to_vid(const struct rocker_port *rocker_port, return ntohs(vlan_id); } -static bool rocker_port_is_slave(const struct rocker_port *rocker_port, - const char *kind) -{ - return rocker_port->bridge_dev && - !strcmp(rocker_port->bridge_dev->rtnl_link_ops->kind, kind); -} - static bool rocker_port_is_bridged(const struct rocker_port *rocker_port) { - return rocker_port_is_slave(rocker_port, "bridge"); + return rocker_port->bridge_dev && + netif_is_bridge_master(rocker_port->bridge_dev); } static bool rocker_port_is_ovsed(const struct rocker_port *rocker_port) { - return rocker_port_is_slave(rocker_port, "openvswitch"); + return rocker_port->bridge_dev && + netif_is_ovs_master(rocker_port->bridge_dev); } #define ROCKER_OP_FLAG_REMOVE BIT(0) @@ -5338,10 +5333,10 @@ static int rocker_port_master_changed(struct net_device *dev) int err = 0; /* N.B: Do nothing if the type of master is not supported */ - if (master && master->rtnl_link_ops) { - if (!strcmp(master->rtnl_link_ops->kind, "bridge")) + if (master) { + if (netif_is_bridge_master(master)) err = rocker_port_bridge_join(rocker_port, master); - else if (!strcmp(master->rtnl_link_ops->kind, "openvswitch")) + else if (netif_is_ovs_master(master)) err = rocker_port_ovs_changed(rocker_port, master); } else if (rocker_port_is_bridged(rocker_port)) { err = rocker_port_bridge_leave(rocker_port); -- GitLab From 686ed3047e8727fe3c7eb5a3c63a5e9b1556bbbb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 09:31:23 +0200 Subject: [PATCH 5228/7006] rocker: use change upper info Since now information about changed upper is passed along, benefit from that and use this info directly. This also fixes possible issues that could happen when non-master device is added (current code does not distinguish between master and non-master upper device). Signed-off-by: Jiri Pirko Acked-by: Scott Feldman --- drivers/net/ethernet/rocker/rocker.c | 61 +++++++++++++++++----------- 1 file changed, 38 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c index 62f383c84a664..34ac41ac9e610 100644 --- a/drivers/net/ethernet/rocker/rocker.c +++ b/drivers/net/ethernet/rocker/rocker.c @@ -5326,46 +5326,61 @@ static int rocker_port_ovs_changed(struct rocker_port *rocker_port, return err; } -static int rocker_port_master_changed(struct net_device *dev) +static int rocker_port_master_linked(struct rocker_port *rocker_port, + struct net_device *master) +{ + int err = 0; + + if (netif_is_bridge_master(master)) + err = rocker_port_bridge_join(rocker_port, master); + else if (netif_is_ovs_master(master)) + err = rocker_port_ovs_changed(rocker_port, master); + return err; +} + +static int rocker_port_master_unlinked(struct rocker_port *rocker_port) { - struct rocker_port *rocker_port = netdev_priv(dev); - struct net_device *master = netdev_master_upper_dev_get(dev); int err = 0; - /* N.B: Do nothing if the type of master is not supported */ - if (master) { - if (netif_is_bridge_master(master)) - err = rocker_port_bridge_join(rocker_port, master); - else if (netif_is_ovs_master(master)) - err = rocker_port_ovs_changed(rocker_port, master); - } else if (rocker_port_is_bridged(rocker_port)) { + if (rocker_port_is_bridged(rocker_port)) err = rocker_port_bridge_leave(rocker_port); - } else if (rocker_port_is_ovsed(rocker_port)) { + else if (rocker_port_is_ovsed(rocker_port)) err = rocker_port_ovs_changed(rocker_port, NULL); - } - return err; } static int rocker_netdevice_event(struct notifier_block *unused, unsigned long event, void *ptr) { - struct net_device *dev; + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct netdev_notifier_changeupper_info *info; + struct rocker_port *rocker_port; int err; + if (!rocker_port_dev_check(dev)) + return NOTIFY_DONE; + switch (event) { case NETDEV_CHANGEUPPER: - dev = netdev_notifier_info_to_dev(ptr); - if (!rocker_port_dev_check(dev)) - return NOTIFY_DONE; - err = rocker_port_master_changed(dev); - if (err) - netdev_warn(dev, - "failed to reflect master change (err %d)\n", - err); + info = ptr; + if (!info->master) + goto out; + rocker_port = netdev_priv(dev); + if (info->linking) { + err = rocker_port_master_linked(rocker_port, + info->upper_dev); + if (err) + netdev_warn(dev, "failed to reflect master linked (err %d)\n", + err); + } else { + err = rocker_port_master_unlinked(rocker_port); + if (err) + netdev_warn(dev, "failed to reflect master unlinked (err %d)\n", + err); + } break; } - +out: return NOTIFY_DONE; } -- GitLab From 718e38b4d96085b4dab08d3d32e5e033aa1ba6e9 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Wed, 8 Jul 2015 14:50:19 +0300 Subject: [PATCH 5229/7006] mtd: mtd_oobtest: Fix the address offset with vary_offset case When vary_offset is set (e.g. test case 3), the offset is not always zero so memcmpshow() will show the wrong offset in the print message. To fix this we introduce a new function memcmpshowoffset() which takes offset as a parameter and displays the right offset and use it in the case where offset is non zero. The old memcmpshow() functionality is preserved by converting it into a macro with offset preset to 0. Signed-off-by: Roger Quadros Signed-off-by: Brian Norris --- drivers/mtd/tests/oobtest.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 8e8525f0202f6..31762120eb56f 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -125,7 +125,8 @@ static int write_whole_device(void) * Display the address, offset and data bytes at comparison failure. * Return number of bitflips encountered. */ -static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t count) +static size_t memcmpshowoffset(loff_t addr, loff_t offset, const void *cs, + const void *ct, size_t count) { const unsigned char *su1, *su2; int res; @@ -135,8 +136,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--, i++) { res = *su1 ^ *su2; if (res) { - pr_info("error @addr[0x%lx:0x%zx] 0x%x -> 0x%x diff 0x%x\n", - (unsigned long)addr, i, *su1, *su2, res); + pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0x%x diff 0x%x\n", + (unsigned long)addr, (unsigned long)offset + i, + *su1, *su2, res); bitflips += hweight8(res); } } @@ -144,6 +146,9 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou return bitflips; } +#define memcmpshow(addr, cs, ct, count) memcmpshowoffset((addr), 0, (cs), (ct),\ + (count)) + /* * Compare with 0xff and show the address, offset and data bytes at * comparison failure. Return number of bitflips encountered. @@ -228,9 +233,10 @@ static int verify_eraseblock(int ebnum) errcnt += 1; return err ? err : -1; } - bitflips = memcmpshow(addr, readbuf + use_offset, - writebuf + (use_len_max * i) + use_offset, - use_len); + bitflips = memcmpshowoffset(addr, use_offset, + readbuf + use_offset, + writebuf + (use_len_max * i) + use_offset, + use_len); /* verify pre-offset area for 0xff */ bitflips += memffshow(addr, 0, readbuf, use_offset); -- GitLab From a585dabd96f3ccb4ada36cf616ab4477873b506c Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 27 Aug 2015 17:59:55 +0200 Subject: [PATCH 5230/7006] mlxsw: Remove duplicate included header Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: Elad Raz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 09325b72d5240..0415ff6428fc5 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include -- GitLab From 262df6919edd837c0745fc2a751364af671feaf7 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 27 Aug 2015 17:59:56 +0200 Subject: [PATCH 5231/7006] mlxsw: adjust transmit fail log message level in __mlxsw_emad_transmit When transmit fails, it is an error, not a warning. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: Elad Raz Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/core.c b/drivers/net/ethernet/mellanox/mlxsw/core.c index 0415ff6428fc5..dbcaf5df8967e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/core.c +++ b/drivers/net/ethernet/mellanox/mlxsw/core.c @@ -376,8 +376,8 @@ static int __mlxsw_emad_transmit(struct mlxsw_core *mlxsw_core, err = mlxsw_core_skb_transmit(mlxsw_core->driver_priv, skb, tx_info); if (err) { - dev_warn(mlxsw_core->bus_info->dev, "Failed to transmit EMAD (tid=%llx)\n", - mlxsw_core->emad.tid); + dev_err(mlxsw_core->bus_info->dev, "Failed to transmit EMAD (tid=%llx)\n", + mlxsw_core->emad.tid); dev_kfree_skb(skb); return err; } -- GitLab From 1e81779ae41e5d14174ce5e61790ace34914ade0 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Thu, 27 Aug 2015 17:59:57 +0200 Subject: [PATCH 5232/7006] mlxsw: Make mailboxes 4KB aligned The HW-SW contract requires mailboxes passed to the firmware to be 4KB aligned. Previously, these mailboxes were mapped using streaming DMA routines, which do not guarantee the bus addresses to be 4KB aligned. Under certain conditions this constraint was indeed violated and errors were observed. By using consistent DMA mapping routines together with a mailbox size of 4KB we are guaranteed not to violate the constraint. Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/pci.c | 83 ++++++++++++++--------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/pci.c b/drivers/net/ethernet/mellanox/mlxsw/pci.c index 045f98fed476f..462cea31ecbb7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/pci.c +++ b/drivers/net/ethernet/mellanox/mlxsw/pci.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "pci.h" #include "core.h" @@ -174,6 +175,8 @@ struct mlxsw_pci { struct mlxsw_pci_mem_item *items; } fw_area; struct { + struct mlxsw_pci_mem_item out_mbox; + struct mlxsw_pci_mem_item in_mbox; struct mutex lock; /* Lock access to command registers */ bool nopoll; wait_queue_head_t wait; @@ -1341,6 +1344,32 @@ static irqreturn_t mlxsw_pci_eq_irq_handler(int irq, void *dev_id) return IRQ_HANDLED; } +static int mlxsw_pci_mbox_alloc(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_mem_item *mbox) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + int err = 0; + + mbox->size = MLXSW_CMD_MBOX_SIZE; + mbox->buf = pci_alloc_consistent(pdev, MLXSW_CMD_MBOX_SIZE, + &mbox->mapaddr); + if (!mbox->buf) { + dev_err(&pdev->dev, "Failed allocating memory for mailbox\n"); + err = -ENOMEM; + } + + return err; +} + +static void mlxsw_pci_mbox_free(struct mlxsw_pci *mlxsw_pci, + struct mlxsw_pci_mem_item *mbox) +{ + struct pci_dev *pdev = mlxsw_pci->pdev; + + pci_free_consistent(pdev, MLXSW_CMD_MBOX_SIZE, mbox->buf, + mbox->mapaddr); +} + static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, const struct mlxsw_config_profile *profile) { @@ -1358,6 +1387,15 @@ static int mlxsw_pci_init(void *bus_priv, struct mlxsw_core *mlxsw_core, mbox = mlxsw_cmd_mbox_alloc(); if (!mbox) return -ENOMEM; + + err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); + if (err) + goto mbox_put; + + err = mlxsw_pci_mbox_alloc(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); + if (err) + goto err_out_mbox_alloc; + err = mlxsw_cmd_query_fw(mlxsw_core, mbox); if (err) goto err_query_fw; @@ -1420,6 +1458,9 @@ err_fw_area_init: err_doorbell_page_bar: err_iface_rev: err_query_fw: + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); +err_out_mbox_alloc: + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); mbox_put: mlxsw_cmd_mbox_free(mbox); return err; @@ -1432,6 +1473,8 @@ static void mlxsw_pci_fini(void *bus_priv) free_irq(mlxsw_pci->msix_entry.vector, mlxsw_pci); mlxsw_pci_aqs_fini(mlxsw_pci); mlxsw_pci_fw_area_fini(mlxsw_pci); + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.out_mbox); + mlxsw_pci_mbox_free(mlxsw_pci, &mlxsw_pci->cmd.in_mbox); } static struct mlxsw_pci_queue * @@ -1524,8 +1567,8 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, u8 *p_status) { struct mlxsw_pci *mlxsw_pci = bus_priv; - dma_addr_t in_mapaddr = 0; - dma_addr_t out_mapaddr = 0; + dma_addr_t in_mapaddr = mlxsw_pci->cmd.in_mbox.mapaddr; + dma_addr_t out_mapaddr = mlxsw_pci->cmd.out_mbox.mapaddr; bool evreq = mlxsw_pci->cmd.nopoll; unsigned long timeout = msecs_to_jiffies(MLXSW_PCI_CIR_TIMEOUT_MSECS); bool *p_wait_done = &mlxsw_pci->cmd.wait_done; @@ -1537,27 +1580,11 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, if (err) return err; - if (in_mbox) { - in_mapaddr = pci_map_single(mlxsw_pci->pdev, in_mbox, - in_mbox_size, PCI_DMA_TODEVICE); - if (unlikely(pci_dma_mapping_error(mlxsw_pci->pdev, - in_mapaddr))) { - err = -EIO; - goto err_in_mbox_map; - } - } + if (in_mbox) + memcpy(mlxsw_pci->cmd.in_mbox.buf, in_mbox, in_mbox_size); mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_HI, in_mapaddr >> 32); mlxsw_pci_write32(mlxsw_pci, CIR_IN_PARAM_LO, in_mapaddr); - if (out_mbox) { - out_mapaddr = pci_map_single(mlxsw_pci->pdev, out_mbox, - out_mbox_size, PCI_DMA_FROMDEVICE); - if (unlikely(pci_dma_mapping_error(mlxsw_pci->pdev, - out_mapaddr))) { - err = -EIO; - goto err_out_mbox_map; - } - } mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_HI, out_mapaddr >> 32); mlxsw_pci_write32(mlxsw_pci, CIR_OUT_PARAM_LO, out_mapaddr); @@ -1601,7 +1628,7 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, } if (!err && out_mbox && out_mbox_direct) { - /* Some commands does not use output param as address to mailbox + /* Some commands don't use output param as address to mailbox * but they store output directly into registers. In that case, * copy registers into mbox buffer. */ @@ -1615,19 +1642,9 @@ static int mlxsw_pci_cmd_exec(void *bus_priv, u16 opcode, u8 opcode_mod, CIR_OUT_PARAM_LO)); memcpy(out_mbox + sizeof(tmp), &tmp, sizeof(tmp)); } - } - - if (out_mapaddr) - pci_unmap_single(mlxsw_pci->pdev, out_mapaddr, out_mbox_size, - PCI_DMA_FROMDEVICE); - - /* fall through */ + } else if (!err && out_mbox) + memcpy(out_mbox, mlxsw_pci->cmd.out_mbox.buf, out_mbox_size); -err_out_mbox_map: - if (in_mapaddr) - pci_unmap_single(mlxsw_pci->pdev, in_mapaddr, in_mbox_size, - PCI_DMA_TODEVICE); -err_in_mbox_map: mutex_unlock(&mlxsw_pci->cmd.lock); return err; -- GitLab From a06a7576526e10a99ea7721533e7f2df3e26baad Mon Sep 17 00:00:00 2001 From: yalin wang Date: Thu, 27 Aug 2015 19:35:48 -0400 Subject: [PATCH 5233/7006] nvdimm: change to use generic kvfree() Signed-off-by: yalin wang Reviewed-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/dimm_devs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index c05eb807d674d..651b8d19d324f 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -241,10 +241,7 @@ void nvdimm_drvdata_release(struct kref *kref) nvdimm_free_dpa(ndd, res); nvdimm_bus_unlock(dev); - if (ndd->data && is_vmalloc_addr(ndd->data)) - vfree(ndd->data); - else - kfree(ndd->data); + kvfree(ndd->data); kfree(ndd); put_device(dev); } -- GitLab From 2e4cfae2a8e3f9ce3925c9b6e9e865fe8476fc4f Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Thu, 27 Aug 2015 15:25:45 -0700 Subject: [PATCH 5234/7006] netfilter: Define v6ops in !CONFIG_NETFILTER case. When CONFIG_OPENVSWITCH is set, and CONFIG_NETFILTER is not set, the openvswitch IPv6 fragmentation handling cannot refer to ipv6_ops because it isn't defined. Add a dummy version to avoid #ifdefs in source files. Fixes: 7f8a436 "openvswitch: Add conntrack action" Signed-off-by: Joe Stringer Signed-off-by: David S. Miller --- include/linux/netfilter_ipv6.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/include/linux/netfilter_ipv6.h b/include/linux/netfilter_ipv6.h index 8b7d28f3aadae..771574677e831 100644 --- a/include/linux/netfilter_ipv6.h +++ b/include/linux/netfilter_ipv6.h @@ -9,15 +9,6 @@ #include - -#ifdef CONFIG_NETFILTER -int ip6_route_me_harder(struct sk_buff *skb); -__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, u_int8_t protocol); - -int ipv6_netfilter_init(void); -void ipv6_netfilter_fini(void); - /* * Hook functions for ipv6 to allow xt_* modules to be built-in even * if IPv6 is a module. @@ -30,6 +21,14 @@ struct nf_ipv6_ops { int (*output)(struct sock *, struct sk_buff *)); }; +#ifdef CONFIG_NETFILTER +int ip6_route_me_harder(struct sk_buff *skb); +__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, + unsigned int dataoff, u_int8_t protocol); + +int ipv6_netfilter_init(void); +void ipv6_netfilter_fini(void); + extern const struct nf_ipv6_ops __rcu *nf_ipv6_ops; static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void) { @@ -39,6 +38,7 @@ static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void) #else /* CONFIG_NETFILTER */ static inline int ipv6_netfilter_init(void) { return 0; } static inline void ipv6_netfilter_fini(void) { return; } +static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void) { return NULL; } #endif /* CONFIG_NETFILTER */ #endif /*__LINUX_IP6_NETFILTER_H*/ -- GitLab From 7b85b4dff2caa5e52726093fd058f87bbc14f156 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Thu, 27 Aug 2015 15:25:46 -0700 Subject: [PATCH 5235/7006] openvswitch: Include ip6_fib.h. kbuild test robot reports that certain configurations will not automatically pick up on the "struct rt6_info" definition, so explicitly include the header for this structure. Fixes: 7f8a436 "openvswitch: Add conntrack action" Signed-off-by: Joe Stringer Signed-off-by: David S. Miller --- net/openvswitch/actions.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 736a113a75c38..4487543806bbe 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include -- GitLab From 67a3e8fe90156d41cd480d3dfbb40f3bc007c262 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Thu, 27 Aug 2015 13:14:20 -0600 Subject: [PATCH 5236/7006] nd_blk: change aperture mapping from WC to WB This should result in a pretty sizeable performance gain for reads. For rough comparison I did some simple read testing using PMEM to compare reads of write combining (WC) mappings vs write-back (WB). This was done on a random lab machine. PMEM reads from a write combining mapping: # dd of=/dev/null if=/dev/pmem0 bs=4096 count=100000 100000+0 records in 100000+0 records out 409600000 bytes (410 MB) copied, 9.2855 s, 44.1 MB/s PMEM reads from a write-back mapping: # dd of=/dev/null if=/dev/pmem0 bs=4096 count=1000000 1000000+0 records in 1000000+0 records out 4096000000 bytes (4.1 GB) copied, 3.44034 s, 1.2 GB/s To be able to safely support a write-back aperture I needed to add support for the "read flush" _DSM flag, as outlined in the DSM spec: http://pmem.io/documents/NVDIMM_DSM_Interface_Example.pdf This flag tells the ND BLK driver that it needs to flush the cache lines associated with the aperture after the aperture is moved but before any new data is read. This ensures that any stale cache lines from the previous contents of the aperture will be discarded from the processor cache, and the new data will be read properly from the DIMM. We know that the cache lines are clean and will be discarded without any writeback because either a) the previous aperture operation was a read, and we never modified the contents of the aperture, or b) the previous aperture operation was a write and we must have written back the dirtied contents of the aperture to the DIMM before the I/O was completed. In order to add support for the "read flush" flag I needed to add a generic routine to invalidate cache lines, mmio_flush_range(). This is protected by the ARCH_HAS_MMIO_FLUSH Kconfig variable, and is currently only supported on x86. Signed-off-by: Ross Zwisler Signed-off-by: Dan Williams --- arch/x86/Kconfig | 1 + arch/x86/include/asm/cacheflush.h | 2 ++ arch/x86/include/asm/io.h | 2 -- arch/x86/include/asm/pmem.h | 2 ++ drivers/acpi/Kconfig | 1 + drivers/acpi/nfit.c | 55 +++++++++++++++++-------------- drivers/acpi/nfit.h | 16 ++++++--- lib/Kconfig | 3 ++ tools/testing/nvdimm/Kbuild | 2 ++ tools/testing/nvdimm/test/iomap.c | 30 +++++++++++++++-- tools/testing/nvdimm/test/nfit.c | 10 ++++-- 11 files changed, 88 insertions(+), 36 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index b3a1a5d77d92c..5d4980e6bc4f0 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -28,6 +28,7 @@ config X86 select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_GCOV_PROFILE_ALL select ARCH_HAS_PMEM_API + select ARCH_HAS_MMIO_FLUSH select ARCH_HAS_SG_CHAIN select ARCH_HAVE_NMI_SAFE_CMPXCHG select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h index 471418ac1ff95..e63aa38e85fb2 100644 --- a/arch/x86/include/asm/cacheflush.h +++ b/arch/x86/include/asm/cacheflush.h @@ -89,6 +89,8 @@ int set_pages_rw(struct page *page, int numpages); void clflush_cache_range(void *addr, unsigned int size); +#define mmio_flush_range(addr, size) clflush_cache_range(addr, size) + #ifdef CONFIG_DEBUG_RODATA void mark_rodata_ro(void); extern const int rodata_test_data; diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h index d241fbd5c87b2..83ec9b1d77cc1 100644 --- a/arch/x86/include/asm/io.h +++ b/arch/x86/include/asm/io.h @@ -248,8 +248,6 @@ static inline void flush_write_buffers(void) #endif } -#define ARCH_MEMREMAP_PMEM MEMREMAP_WB - #endif /* __KERNEL__ */ extern void native_io_delay(void); diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h index a3a0df6545eef..bb026c5adf8a8 100644 --- a/arch/x86/include/asm/pmem.h +++ b/arch/x86/include/asm/pmem.h @@ -18,6 +18,8 @@ #include #include +#define ARCH_MEMREMAP_PMEM MEMREMAP_WB + #ifdef CONFIG_ARCH_HAS_PMEM_API /** * arch_memcpy_to_pmem - copy data to persistent memory diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 114cf48085abd..4baeb853e0c37 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -410,6 +410,7 @@ config ACPI_NFIT tristate "ACPI NVDIMM Firmware Interface Table (NFIT)" depends on PHYS_ADDR_T_64BIT depends on BLK_DEV + depends on ARCH_HAS_MMIO_FLUSH select LIBNVDIMM help Infrastructure to probe ACPI 6 compliant platforms for diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 7c2638f914a90..56fff01416369 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -1017,7 +1017,7 @@ static u64 read_blk_stat(struct nfit_blk *nfit_blk, unsigned int bw) if (mmio->num_lines) offset = to_interleave_offset(offset, mmio); - return readq(mmio->base + offset); + return readq(mmio->addr.base + offset); } static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, @@ -1042,11 +1042,11 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, unsigned int bw, if (mmio->num_lines) offset = to_interleave_offset(offset, mmio); - writeq(cmd, mmio->base + offset); + writeq(cmd, mmio->addr.base + offset); wmb_blk(nfit_blk); if (nfit_blk->dimm_flags & ND_BLK_DCR_LATCH) - readq(mmio->base + offset); + readq(mmio->addr.base + offset); } static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, @@ -1078,11 +1078,16 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *nfit_blk, } if (rw) - memcpy_to_pmem(mmio->aperture + offset, + memcpy_to_pmem(mmio->addr.aperture + offset, iobuf + copied, c); - else + else { + if (nfit_blk->dimm_flags & ND_BLK_READ_FLUSH) + mmio_flush_range((void __force *) + mmio->addr.aperture + offset, c); + memcpy_from_pmem(iobuf + copied, - mmio->aperture + offset, c); + mmio->addr.aperture + offset, c); + } copied += c; len -= c; @@ -1129,7 +1134,10 @@ static void nfit_spa_mapping_release(struct kref *kref) WARN_ON(!mutex_is_locked(&acpi_desc->spa_map_mutex)); dev_dbg(acpi_desc->dev, "%s: SPA%d\n", __func__, spa->range_index); - iounmap(spa_map->iomem); + if (spa_map->type == SPA_MAP_APERTURE) + memunmap((void __force *)spa_map->addr.aperture); + else + iounmap(spa_map->addr.base); release_mem_region(spa->address, spa->length); list_del(&spa_map->list); kfree(spa_map); @@ -1175,7 +1183,7 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, spa_map = find_spa_mapping(acpi_desc, spa); if (spa_map) { kref_get(&spa_map->kref); - return spa_map->iomem; + return spa_map->addr.base; } spa_map = kzalloc(sizeof(*spa_map), GFP_KERNEL); @@ -1191,20 +1199,19 @@ static void __iomem *__nfit_spa_map(struct acpi_nfit_desc *acpi_desc, if (!res) goto err_mem; - if (type == SPA_MAP_APERTURE) { - /* - * TODO: memremap_pmem() support, but that requires cache - * flushing when the aperture is moved. - */ - spa_map->iomem = ioremap_wc(start, n); - } else - spa_map->iomem = ioremap_nocache(start, n); + spa_map->type = type; + if (type == SPA_MAP_APERTURE) + spa_map->addr.aperture = (void __pmem *)memremap(start, n, + ARCH_MEMREMAP_PMEM); + else + spa_map->addr.base = ioremap_nocache(start, n); + - if (!spa_map->iomem) + if (!spa_map->addr.base) goto err_map; list_add_tail(&spa_map->list, &acpi_desc->spa_maps); - return spa_map->iomem; + return spa_map->addr.base; err_map: release_mem_region(start, n); @@ -1267,7 +1274,7 @@ static int acpi_nfit_blk_get_flags(struct nvdimm_bus_descriptor *nd_desc, nfit_blk->dimm_flags = flags.flags; else if (rc == -ENOTTY) { /* fall back to a conservative default */ - nfit_blk->dimm_flags = ND_BLK_DCR_LATCH; + nfit_blk->dimm_flags = ND_BLK_DCR_LATCH | ND_BLK_READ_FLUSH; rc = 0; } else rc = -ENXIO; @@ -1307,9 +1314,9 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, /* map block aperture memory */ nfit_blk->bdw_offset = nfit_mem->bdw->offset; mmio = &nfit_blk->mmio[BDW]; - mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw, + mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_bdw, SPA_MAP_APERTURE); - if (!mmio->base) { + if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map bdw\n", __func__, nvdimm_name(nvdimm)); return -ENOMEM; @@ -1330,9 +1337,9 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, nfit_blk->cmd_offset = nfit_mem->dcr->command_offset; nfit_blk->stat_offset = nfit_mem->dcr->status_offset; mmio = &nfit_blk->mmio[DCR]; - mmio->base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr, + mmio->addr.base = nfit_spa_map(acpi_desc, nfit_mem->spa_dcr, SPA_MAP_CONTROL); - if (!mmio->base) { + if (!mmio->addr.base) { dev_dbg(dev, "%s: %s failed to map dcr\n", __func__, nvdimm_name(nvdimm)); return -ENOMEM; @@ -1399,7 +1406,7 @@ static void acpi_nfit_blk_region_disable(struct nvdimm_bus *nvdimm_bus, for (i = 0; i < 2; i++) { struct nfit_blk_mmio *mmio = &nfit_blk->mmio[i]; - if (mmio->base) + if (mmio->addr.base) nfit_spa_unmap(acpi_desc, mmio->spa); } nd_blk_region_set_provider_data(ndbr, NULL); diff --git a/drivers/acpi/nfit.h b/drivers/acpi/nfit.h index f2c2bb751882c..7e740156b9c29 100644 --- a/drivers/acpi/nfit.h +++ b/drivers/acpi/nfit.h @@ -41,6 +41,7 @@ enum nfit_uuids { }; enum { + ND_BLK_READ_FLUSH = 1, ND_BLK_DCR_LATCH = 2, }; @@ -117,12 +118,16 @@ enum nd_blk_mmio_selector { DCR, }; +struct nd_blk_addr { + union { + void __iomem *base; + void __pmem *aperture; + }; +}; + struct nfit_blk { struct nfit_blk_mmio { - union { - void __iomem *base; - void __pmem *aperture; - }; + struct nd_blk_addr addr; u64 size; u64 base_offset; u32 line_size; @@ -149,7 +154,8 @@ struct nfit_spa_mapping { struct acpi_nfit_system_address *spa; struct list_head list; struct kref kref; - void __iomem *iomem; + enum spa_map_type type; + struct nd_blk_addr addr; }; static inline struct nfit_spa_mapping *to_spa_map(struct kref *kref) diff --git a/lib/Kconfig b/lib/Kconfig index 3a2ef67db6c72..a938a39191b3c 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -531,4 +531,7 @@ config ARCH_HAS_SG_CHAIN config ARCH_HAS_PMEM_API bool +config ARCH_HAS_MMIO_FLUSH + bool + endmenu diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 04c5fc09576de..94a5e0eda2d21 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -1,8 +1,10 @@ ldflags-y += --wrap=ioremap_wc +ldflags-y += --wrap=memremap ldflags-y += --wrap=devm_ioremap_nocache ldflags-y += --wrap=devm_memremap ldflags-y += --wrap=ioremap_nocache ldflags-y += --wrap=iounmap +ldflags-y += --wrap=memunmap ldflags-y += --wrap=__devm_request_region ldflags-y += --wrap=__request_region ldflags-y += --wrap=__release_region diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index ff1e004588640..179d2289f3a82 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c @@ -89,12 +89,25 @@ void *__wrap_devm_memremap(struct device *dev, resource_size_t offset, nfit_res = get_nfit_res(offset); rcu_read_unlock(); if (nfit_res) - return (void __iomem *) nfit_res->buf + offset - - nfit_res->res->start; + return nfit_res->buf + offset - nfit_res->res->start; return devm_memremap(dev, offset, size, flags); } EXPORT_SYMBOL(__wrap_devm_memremap); +void *__wrap_memremap(resource_size_t offset, size_t size, + unsigned long flags) +{ + struct nfit_test_resource *nfit_res; + + rcu_read_lock(); + nfit_res = get_nfit_res(offset); + rcu_read_unlock(); + if (nfit_res) + return nfit_res->buf + offset - nfit_res->res->start; + return memremap(offset, size, flags); +} +EXPORT_SYMBOL(__wrap_memremap); + void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size) { return __nfit_test_ioremap(offset, size, ioremap_nocache); @@ -120,6 +133,19 @@ void __wrap_iounmap(volatile void __iomem *addr) } EXPORT_SYMBOL(__wrap_iounmap); +void __wrap_memunmap(void *addr) +{ + struct nfit_test_resource *nfit_res; + + rcu_read_lock(); + nfit_res = get_nfit_res((unsigned long) addr); + rcu_read_unlock(); + if (nfit_res) + return; + return memunmap(addr); +} +EXPORT_SYMBOL(__wrap_memunmap); + static struct resource *nfit_test_request_region(struct device *dev, struct resource *parent, resource_size_t start, resource_size_t n, const char *name, int flags) diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 28dba918524e5..021e6f97f33e7 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -1029,9 +1029,13 @@ static int nfit_test_blk_do_io(struct nd_blk_region *ndbr, resource_size_t dpa, lane = nd_region_acquire_lane(nd_region); if (rw) - memcpy(mmio->base + dpa, iobuf, len); - else - memcpy(iobuf, mmio->base + dpa, len); + memcpy(mmio->addr.base + dpa, iobuf, len); + else { + memcpy(iobuf, mmio->addr.base + dpa, len); + + /* give us some some coverage of the mmio_flush_range() API */ + mmio_flush_range(mmio->addr.base + dpa, len); + } nd_region_release_lane(nd_region, lane); return 0; -- GitLab From b22fbf22f8469d8cacb6fcf5d266426826e1137d Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Thu, 27 Aug 2015 14:19:20 -0700 Subject: [PATCH 5237/7006] bridge: fdb: rearrange net_bridge_fdb_entry While looking into fixing the local entries scalability issue I noticed that the structure is badly arranged because vlan_id would fall in a second cache line while keeping rcu which is used only when deleting in the first, so re-arrange the structure and push rcu to the end so we can get 16 bytes which can be used for other fields (by pushing rcu fully in the second 64 byte chunk). With this change all the core necessary information when doing fdb lookups will be available in a single cache line. pahole before (note vlan_id): struct net_bridge_fdb_entry { struct hlist_node hlist; /* 0 16 */ struct net_bridge_port * dst; /* 16 8 */ struct callback_head rcu; /* 24 16 */ long unsigned int updated; /* 40 8 */ long unsigned int used; /* 48 8 */ mac_addr addr; /* 56 6 */ unsigned char is_local:1; /* 62: 7 1 */ unsigned char is_static:1; /* 62: 6 1 */ unsigned char added_by_user:1; /* 62: 5 1 */ unsigned char added_by_external_learn:1; /* 62: 4 1 */ /* XXX 4 bits hole, try to pack */ /* XXX 1 byte hole, try to pack */ /* --- cacheline 1 boundary (64 bytes) --- */ __u16 vlan_id; /* 64 2 */ /* size: 72, cachelines: 2, members: 11 */ /* sum members: 65, holes: 1, sum holes: 1 */ /* bit holes: 1, sum bit holes: 4 bits */ /* padding: 6 */ /* last cacheline: 8 bytes */ } pahole after (note vlan_id): struct net_bridge_fdb_entry { struct hlist_node hlist; /* 0 16 */ struct net_bridge_port * dst; /* 16 8 */ long unsigned int updated; /* 24 8 */ long unsigned int used; /* 32 8 */ mac_addr addr; /* 40 6 */ __u16 vlan_id; /* 46 2 */ unsigned char is_local:1; /* 48: 7 1 */ unsigned char is_static:1; /* 48: 6 1 */ unsigned char added_by_user:1; /* 48: 5 1 */ unsigned char added_by_external_learn:1; /* 48: 4 1 */ /* XXX 4 bits hole, try to pack */ /* XXX 7 bytes hole, try to pack */ struct callback_head rcu; /* 56 16 */ /* --- cacheline 1 boundary (64 bytes) was 8 bytes ago --- */ /* size: 72, cachelines: 2, members: 11 */ /* sum members: 65, holes: 1, sum holes: 7 */ /* bit holes: 1, sum bit holes: 4 bits */ /* last cacheline: 8 bytes */ } Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/bridge/br_private.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 19e8f79b6b99f..213baf7aaa930 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h @@ -95,15 +95,15 @@ struct net_bridge_fdb_entry struct hlist_node hlist; struct net_bridge_port *dst; - struct rcu_head rcu; unsigned long updated; unsigned long used; mac_addr addr; + __u16 vlan_id; unsigned char is_local:1, is_static:1, added_by_user:1, added_by_external_learn:1; - __u16 vlan_id; + struct rcu_head rcu; }; struct net_bridge_port_group { -- GitLab From 9293267a3e2a7a2555d8ddc8f9301525e5b03b1b Mon Sep 17 00:00:00 2001 From: Carol L Soto Date: Thu, 27 Aug 2015 14:43:25 -0500 Subject: [PATCH 5238/7006] net/mlx4_core: Capping number of requested MSIXs to MAX_MSIX We currently manage IRQs in pool_bm which is a bit field of MAX_MSIX bits. Thus, allocating more than MAX_MSIX interrupts can't be managed in pool_bm. Fixing this by capping number of requested MSIXs to MAX_MSIX. Signed-off-by: Matan Barak Signed-off-by: Carol L Soto Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/main.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 121c579888bba..006757f80988b 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -2669,9 +2669,14 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) if (msi_x) { int nreq = dev->caps.num_ports * num_online_cpus() + 1; + bool shared_ports = false; nreq = min_t(int, dev->caps.num_eqs - dev->caps.reserved_eqs, nreq); + if (nreq > MAX_MSIX) { + nreq = MAX_MSIX; + shared_ports = true; + } entries = kcalloc(nreq, sizeof *entries, GFP_KERNEL); if (!entries) @@ -2694,6 +2699,9 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) bitmap_zero(priv->eq_table.eq[MLX4_EQ_ASYNC].actv_ports.ports, dev->caps.num_ports); + if (MLX4_IS_LEGACY_EQ_MODE(dev->caps)) + shared_ports = true; + for (i = 0; i < dev->caps.num_comp_vectors + 1; i++) { if (i == MLX4_EQ_ASYNC) continue; @@ -2701,7 +2709,7 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev) priv->eq_table.eq[i].irq = entries[i + 1 - !!(i > MLX4_EQ_ASYNC)].vector; - if (MLX4_IS_LEGACY_EQ_MODE(dev->caps)) { + if (shared_ports) { bitmap_fill(priv->eq_table.eq[i].actv_ports.ports, dev->caps.num_ports); /* We don't set affinity hint when there -- GitLab From b0f6446377e72bcabafe83d29bf6a2f6dd19d0b0 Mon Sep 17 00:00:00 2001 From: Carol L Soto Date: Thu, 27 Aug 2015 14:43:26 -0500 Subject: [PATCH 5239/7006] net/mlx4_core: Fix unintialized variable used in error path The uninitialized value name in mlx4_en_activate_cq was used in order to print an error message. Fixing it by replacing it with cq->vector. Signed-off-by: Matan Barak Signed-off-by: Carol L Soto Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_cq.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c index 63769df872a42..eb8a4988de632 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c @@ -100,7 +100,6 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, { struct mlx4_en_dev *mdev = priv->mdev; int err = 0; - char name[25]; int timestamp_en = 0; bool assigned_eq = false; @@ -119,8 +118,8 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq, err = mlx4_assign_eq(mdev->dev, priv->port, &cq->vector); if (err) { - mlx4_err(mdev, "Failed assigning an EQ to %s\n", - name); + mlx4_err(mdev, "Failed assigning an EQ to CQ vector %d\n", + cq->vector); goto free_eq; } -- GitLab From cb389b9c0e00c30c9daf20287f7d91e2466edbb1 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 7 Aug 2015 17:41:00 -0400 Subject: [PATCH 5240/7006] dax: drop size parameter to ->direct_access() None of the implementations currently use it. The common bdev_direct_access() entry point handles all the size checks before calling ->direct_access(). Signed-off-by: Christoph Hellwig Signed-off-by: Dan Williams --- arch/powerpc/sysdev/axonram.c | 2 +- drivers/block/brd.c | 6 +----- drivers/nvdimm/pmem.c | 2 +- drivers/s390/block/dcssblk.c | 4 ++-- fs/block_dev.c | 2 +- include/linux/blkdev.h | 2 +- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/sysdev/axonram.c b/arch/powerpc/sysdev/axonram.c index a2be2a66dab6d..4419c84ac15ae 100644 --- a/arch/powerpc/sysdev/axonram.c +++ b/arch/powerpc/sysdev/axonram.c @@ -141,7 +141,7 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio) */ static long axon_ram_direct_access(struct block_device *device, sector_t sector, - void __pmem **kaddr, unsigned long *pfn, long size) + void __pmem **kaddr, unsigned long *pfn) { struct axon_ram_bank *bank = device->bd_disk->private_data; loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT; diff --git a/drivers/block/brd.c b/drivers/block/brd.c index c96402fd15605..03c45c41bdfa8 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -371,7 +371,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector, #ifdef CONFIG_BLK_DEV_RAM_DAX static long brd_direct_access(struct block_device *bdev, sector_t sector, - void __pmem **kaddr, unsigned long *pfn, long size) + void __pmem **kaddr, unsigned long *pfn) { struct brd_device *brd = bdev->bd_disk->private_data; struct page *page; @@ -384,10 +384,6 @@ static long brd_direct_access(struct block_device *bdev, sector_t sector, *kaddr = (void __pmem *)page_address(page); *pfn = page_to_pfn(page); - /* - * TODO: If size > PAGE_SIZE, we could look to see if the next page in - * the file happens to be mapped to the next page of physical RAM. - */ return PAGE_SIZE; } #else diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index f3b629779266a..3b5b9cb758b64 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -92,7 +92,7 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector, } static long pmem_direct_access(struct block_device *bdev, sector_t sector, - void __pmem **kaddr, unsigned long *pfn, long size) + void __pmem **kaddr, unsigned long *pfn) { struct pmem_device *pmem = bdev->bd_disk->private_data; size_t offset = sector << 9; diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c index 2c5a397b9f3e7..8c027a9e4e8a4 100644 --- a/drivers/s390/block/dcssblk.c +++ b/drivers/s390/block/dcssblk.c @@ -29,7 +29,7 @@ static int dcssblk_open(struct block_device *bdev, fmode_t mode); static void dcssblk_release(struct gendisk *disk, fmode_t mode); static void dcssblk_make_request(struct request_queue *q, struct bio *bio); static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum, - void __pmem **kaddr, unsigned long *pfn, long size); + void __pmem **kaddr, unsigned long *pfn); static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0"; @@ -879,7 +879,7 @@ fail: static long dcssblk_direct_access (struct block_device *bdev, sector_t secnum, - void __pmem **kaddr, unsigned long *pfn, long size) + void __pmem **kaddr, unsigned long *pfn) { struct dcssblk_dev_info *dev_info; unsigned long offset, dev_sz; diff --git a/fs/block_dev.c b/fs/block_dev.c index 2345a9870e2ca..3831e5691b322 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -462,7 +462,7 @@ long bdev_direct_access(struct block_device *bdev, sector_t sector, sector += get_start_sect(bdev); if (sector % (PAGE_SIZE / 512)) return -EINVAL; - avail = ops->direct_access(bdev, sector, addr, pfn, size); + avail = ops->direct_access(bdev, sector, addr, pfn); if (!avail) return -ERANGE; return min(avail, size); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index c401ecdff9cb4..c22064f326b29 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1556,7 +1556,7 @@ struct block_device_operations { int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); long (*direct_access)(struct block_device *, sector_t, void __pmem **, - unsigned long *pfn, long size); + unsigned long *pfn); unsigned int (*check_events) (struct gendisk *disk, unsigned int clearing); /* ->media_changed() is DEPRECATED, use ->check_events() instead */ -- GitLab From 012dcef3f058385268630c0003e9b7f8dcafbeb4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 7 Aug 2015 17:41:01 -0400 Subject: [PATCH 5241/7006] mm: move __phys_to_pfn and __pfn_to_phys to asm/generic/memory_model.h Three architectures already define these, and we'll need them genericly soon. Signed-off-by: Christoph Hellwig Signed-off-by: Dan Williams --- arch/arm/include/asm/memory.h | 6 ------ arch/arm64/include/asm/memory.h | 6 ------ arch/unicore32/include/asm/memory.h | 6 ------ include/asm-generic/memory_model.h | 6 ++++++ 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h index b7f6fb462ea0d..98d58bb04ac57 100644 --- a/arch/arm/include/asm/memory.h +++ b/arch/arm/include/asm/memory.h @@ -118,12 +118,6 @@ #define DTCM_OFFSET UL(0xfffe8000) #endif -/* - * Convert a physical address to a Page Frame Number and back - */ -#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) -#define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT) - /* * Convert a page to/from a physical address */ diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h index f800d45ea2265..d808bb6887514 100644 --- a/arch/arm64/include/asm/memory.h +++ b/arch/arm64/include/asm/memory.h @@ -80,12 +80,6 @@ #define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET)) #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET)) -/* - * Convert a physical address to a Page Frame Number and back - */ -#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) -#define __pfn_to_phys(pfn) ((phys_addr_t)(pfn) << PAGE_SHIFT) - /* * Convert a page to/from a physical address */ diff --git a/arch/unicore32/include/asm/memory.h b/arch/unicore32/include/asm/memory.h index debafc40200a4..3bb0a29fd2d7b 100644 --- a/arch/unicore32/include/asm/memory.h +++ b/arch/unicore32/include/asm/memory.h @@ -60,12 +60,6 @@ #define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET) #endif -/* - * Convert a physical address to a Page Frame Number and back - */ -#define __phys_to_pfn(paddr) ((paddr) >> PAGE_SHIFT) -#define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) - /* * Convert a page to/from a physical address */ diff --git a/include/asm-generic/memory_model.h b/include/asm-generic/memory_model.h index 14909b0b9cae7..f20f407ce45d2 100644 --- a/include/asm-generic/memory_model.h +++ b/include/asm-generic/memory_model.h @@ -69,6 +69,12 @@ }) #endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */ +/* + * Convert a physical address to a Page Frame Number and back + */ +#define __phys_to_pfn(paddr) ((unsigned long)((paddr) >> PAGE_SHIFT)) +#define __pfn_to_phys(pfn) ((pfn) << PAGE_SHIFT) + #define page_to_pfn __page_to_pfn #define pfn_to_page __pfn_to_page -- GitLab From 033fbae988fcb67e5077203512181890848b8e90 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sun, 9 Aug 2015 15:29:06 -0400 Subject: [PATCH 5242/7006] mm: ZONE_DEVICE for "device memory" While pmem is usable as a block device or via DAX mappings to userspace there are several usage scenarios that can not target pmem due to its lack of struct page coverage. In preparation for "hot plugging" pmem into the vmemmap add ZONE_DEVICE as a new zone to tag these pages separately from the ones that are subject to standard page allocations. Importantly "device memory" can be removed at will by userspace unbinding the driver of the device. Having a separate zone prevents allocation and otherwise marks these pages that are distinct from typical uniform memory. Device memory has different lifetime and performance characteristics than RAM. However, since we have run out of ZONES_SHIFT bits this functionality currently depends on sacrificing ZONE_DMA. Cc: H. Peter Anvin Cc: Ingo Molnar Cc: Dave Hansen Cc: Rik van Riel Cc: Mel Gorman Cc: Jerome Glisse [hch: various simplifications in the arch interface] Signed-off-by: Christoph Hellwig Signed-off-by: Dan Williams --- arch/ia64/mm/init.c | 4 ++-- arch/powerpc/mm/mem.c | 4 ++-- arch/s390/mm/init.c | 2 +- arch/sh/mm/init.c | 5 +++-- arch/tile/mm/init.c | 2 +- arch/x86/mm/init_32.c | 4 ++-- arch/x86/mm/init_64.c | 4 ++-- include/linux/memory_hotplug.h | 5 +++-- include/linux/mmzone.h | 23 +++++++++++++++++++++++ mm/Kconfig | 17 +++++++++++++++++ mm/memory_hotplug.c | 14 +++++++++++--- mm/page_alloc.c | 3 +++ 12 files changed, 70 insertions(+), 17 deletions(-) diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 97e48b0eefc7c..1841ef69183d8 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -645,7 +645,7 @@ mem_init (void) } #ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { pg_data_t *pgdat; struct zone *zone; @@ -656,7 +656,7 @@ int arch_add_memory(int nid, u64 start, u64 size) pgdat = NODE_DATA(nid); zone = pgdat->node_zones + - zone_for_memory(nid, start, size, ZONE_NORMAL); + zone_for_memory(nid, start, size, ZONE_NORMAL, for_device); ret = __add_pages(nid, zone, start_pfn, nr_pages); if (ret) diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index 0f11819d8f1dc..6571cfb056686 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c @@ -113,7 +113,7 @@ int memory_add_physaddr_to_nid(u64 start) } #endif -int arch_add_memory(int nid, u64 start, u64 size) +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { struct pglist_data *pgdata; struct zone *zone; @@ -128,7 +128,7 @@ int arch_add_memory(int nid, u64 start, u64 size) /* this should work for most non-highmem platforms */ zone = pgdata->node_zones + - zone_for_memory(nid, start, size, 0); + zone_for_memory(nid, start, size, 0, for_device); return __add_pages(nid, zone, start_pfn, nr_pages); } diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 76e873748b56e..48ee78be88ba6 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -168,7 +168,7 @@ void __init free_initrd_mem(unsigned long start, unsigned long end) #endif #ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { unsigned long zone_start_pfn, zone_end_pfn, nr_pages; unsigned long start_pfn = PFN_DOWN(start); diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 2790b6a64157f..c1490096b8637 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -485,7 +485,7 @@ void free_initrd_mem(unsigned long start, unsigned long end) #endif #ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { pg_data_t *pgdat; unsigned long start_pfn = start >> PAGE_SHIFT; @@ -496,7 +496,8 @@ int arch_add_memory(int nid, u64 start, u64 size) /* We only have ZONE_NORMAL, so this is easy.. */ ret = __add_pages(nid, pgdat->node_zones + - zone_for_memory(nid, start, size, ZONE_NORMAL), + zone_for_memory(nid, start, size, ZONE_NORMAL, + for_device), start_pfn, nr_pages); if (unlikely(ret)) printk("%s: Failed, __add_pages() == %d\n", __func__, ret); diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c index 5bd252e3fdc50..d4e1fc41d06db 100644 --- a/arch/tile/mm/init.c +++ b/arch/tile/mm/init.c @@ -863,7 +863,7 @@ void __init mem_init(void) * memory to the highmem for now. */ #ifndef CONFIG_NEED_MULTIPLE_NODES -int arch_add_memory(u64 start, u64 size) +int arch_add_memory(u64 start, u64 size, bool for_device) { struct pglist_data *pgdata = &contig_page_data; struct zone *zone = pgdata->node_zones + MAX_NR_ZONES-1; diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index 8340e45c891a1..2a9237d20a701 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -822,11 +822,11 @@ void __init mem_init(void) } #ifdef CONFIG_MEMORY_HOTPLUG -int arch_add_memory(int nid, u64 start, u64 size) +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { struct pglist_data *pgdata = NODE_DATA(nid); struct zone *zone = pgdata->node_zones + - zone_for_memory(nid, start, size, ZONE_HIGHMEM); + zone_for_memory(nid, start, size, ZONE_HIGHMEM, for_device); unsigned long start_pfn = start >> PAGE_SHIFT; unsigned long nr_pages = size >> PAGE_SHIFT; diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 3fba623e3ba55..30564e2752d36 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -687,11 +687,11 @@ static void update_end_of_memory_vars(u64 start, u64 size) * Memory is added always to NORMAL zone. This means you will never get * additional DMA/DMA32 memory. */ -int arch_add_memory(int nid, u64 start, u64 size) +int arch_add_memory(int nid, u64 start, u64 size, bool for_device) { struct pglist_data *pgdat = NODE_DATA(nid); struct zone *zone = pgdat->node_zones + - zone_for_memory(nid, start, size, ZONE_NORMAL); + zone_for_memory(nid, start, size, ZONE_NORMAL, for_device); unsigned long start_pfn = start >> PAGE_SHIFT; unsigned long nr_pages = size >> PAGE_SHIFT; int ret; diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h index 6ffa0ac7f7d62..8f60e899b33c5 100644 --- a/include/linux/memory_hotplug.h +++ b/include/linux/memory_hotplug.h @@ -266,8 +266,9 @@ static inline void remove_memory(int nid, u64 start, u64 size) {} extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, void *arg, int (*func)(struct memory_block *, void *)); extern int add_memory(int nid, u64 start, u64 size); -extern int zone_for_memory(int nid, u64 start, u64 size, int zone_default); -extern int arch_add_memory(int nid, u64 start, u64 size); +extern int zone_for_memory(int nid, u64 start, u64 size, int zone_default, + bool for_device); +extern int arch_add_memory(int nid, u64 start, u64 size, bool for_device); extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); extern bool is_memblock_offlined(struct memory_block *mem); extern void remove_memory(int nid, u64 start, u64 size); diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 754c25966a0a7..9217fd93c25b4 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -319,7 +319,11 @@ enum zone_type { ZONE_HIGHMEM, #endif ZONE_MOVABLE, +#ifdef CONFIG_ZONE_DEVICE + ZONE_DEVICE, +#endif __MAX_NR_ZONES + }; #ifndef __GENERATING_BOUNDS_H @@ -794,6 +798,25 @@ static inline bool pgdat_is_empty(pg_data_t *pgdat) return !pgdat->node_start_pfn && !pgdat->node_spanned_pages; } +static inline int zone_id(const struct zone *zone) +{ + struct pglist_data *pgdat = zone->zone_pgdat; + + return zone - pgdat->node_zones; +} + +#ifdef CONFIG_ZONE_DEVICE +static inline bool is_dev_zone(const struct zone *zone) +{ + return zone_id(zone) == ZONE_DEVICE; +} +#else +static inline bool is_dev_zone(const struct zone *zone) +{ + return false; +} +#endif + #include extern struct mutex zonelists_mutex; diff --git a/mm/Kconfig b/mm/Kconfig index e79de2bd12cd0..a0cd086df16be 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -654,3 +654,20 @@ config DEFERRED_STRUCT_PAGE_INIT when kswapd starts. This has a potential performance impact on processes running early in the lifetime of the systemm until kswapd finishes the initialisation. + +config ZONE_DEVICE + bool "Device memory (pmem, etc...) hotplug support" if EXPERT + default !ZONE_DMA + depends on !ZONE_DMA + depends on MEMORY_HOTPLUG + depends on MEMORY_HOTREMOVE + depends on X86_64 #arch_add_memory() comprehends device memory + + help + Device memory hotplug support allows for establishing pmem, + or other device driver discovered memory regions, in the + memmap. This allows pfn_to_page() lookups of otherwise + "device-physical" addresses which is needed for using a DAX + mapping in an O_DIRECT operation, among other things. + + If FS_DAX is enabled, then say Y. diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 26fbba7d888f8..24e4c76c951be 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -770,7 +770,10 @@ int __remove_pages(struct zone *zone, unsigned long phys_start_pfn, start = phys_start_pfn << PAGE_SHIFT; size = nr_pages * PAGE_SIZE; - ret = release_mem_region_adjustable(&iomem_resource, start, size); + + /* in the ZONE_DEVICE case device driver owns the memory region */ + if (!is_dev_zone(zone)) + ret = release_mem_region_adjustable(&iomem_resource, start, size); if (ret) { resource_size_t endres = start + size - 1; @@ -1207,8 +1210,13 @@ static int should_add_memory_movable(int nid, u64 start, u64 size) return 0; } -int zone_for_memory(int nid, u64 start, u64 size, int zone_default) +int zone_for_memory(int nid, u64 start, u64 size, int zone_default, + bool for_device) { +#ifdef CONFIG_ZONE_DEVICE + if (for_device) + return ZONE_DEVICE; +#endif if (should_add_memory_movable(nid, start, size)) return ZONE_MOVABLE; @@ -1249,7 +1257,7 @@ int __ref add_memory(int nid, u64 start, u64 size) } /* call arch's memory hotadd */ - ret = arch_add_memory(nid, start, size); + ret = arch_add_memory(nid, start, size, false); if (ret < 0) goto error; diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ef19f22b2b7de..0f19b4e182339 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -207,6 +207,9 @@ static char * const zone_names[MAX_NR_ZONES] = { "HighMem", #endif "Movable", +#ifdef CONFIG_ZONE_DEVICE + "Device", +#endif }; int min_free_kbytes = 1024; -- GitLab From 41e94a851304f7acac840adec4004f8aeee53ad4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 17 Aug 2015 16:00:35 +0200 Subject: [PATCH 5243/7006] add devm_memremap_pages This behaves like devm_memremap except that it ensures we have page structures available that can back the region. Signed-off-by: Christoph Hellwig [djbw: catch attempts to remap RAM, drop flags] Signed-off-by: Dan Williams --- include/linux/io.h | 20 +++++++++++++++++ kernel/memremap.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/include/linux/io.h b/include/linux/io.h index d8d749abd6658..de64c1e536125 100644 --- a/include/linux/io.h +++ b/include/linux/io.h @@ -20,10 +20,13 @@ #include #include +#include +#include #include #include struct device; +struct resource; __visible void __iowrite32_copy(void __iomem *to, const void *from, size_t count); void __iowrite64_copy(void __iomem *to, const void *from, size_t count); @@ -84,6 +87,23 @@ void *devm_memremap(struct device *dev, resource_size_t offset, size_t size, unsigned long flags); void devm_memunmap(struct device *dev, void *addr); +void *__devm_memremap_pages(struct device *dev, struct resource *res); + +#ifdef CONFIG_ZONE_DEVICE +void *devm_memremap_pages(struct device *dev, struct resource *res); +#else +static inline void *devm_memremap_pages(struct device *dev, struct resource *res) +{ + /* + * Fail attempts to call devm_memremap_pages() without + * ZONE_DEVICE support enabled, this requires callers to fall + * back to plain devm_memremap() based on config + */ + WARN_ON_ONCE(1); + return ERR_PTR(-ENXIO); +} +#endif + /* * Some systems do not have legacy ISA devices. * /dev/port is not a valid interface on these systems. diff --git a/kernel/memremap.c b/kernel/memremap.c index 5c9b55eaf121a..72b0c66628b6b 100644 --- a/kernel/memremap.c +++ b/kernel/memremap.c @@ -14,6 +14,7 @@ #include #include #include +#include #ifndef ioremap_cache /* temporary while we convert existing ioremap_cache users to memremap */ @@ -135,3 +136,55 @@ void devm_memunmap(struct device *dev, void *addr) memunmap(addr); } EXPORT_SYMBOL(devm_memunmap); + +#ifdef CONFIG_ZONE_DEVICE +struct page_map { + struct resource res; +}; + +static void devm_memremap_pages_release(struct device *dev, void *res) +{ + struct page_map *page_map = res; + + /* pages are dead and unused, undo the arch mapping */ + arch_remove_memory(page_map->res.start, resource_size(&page_map->res)); +} + +void *devm_memremap_pages(struct device *dev, struct resource *res) +{ + int is_ram = region_intersects(res->start, resource_size(res), + "System RAM"); + struct page_map *page_map; + int error, nid; + + if (is_ram == REGION_MIXED) { + WARN_ONCE(1, "%s attempted on mixed region %pr\n", + __func__, res); + return ERR_PTR(-ENXIO); + } + + if (is_ram == REGION_INTERSECTS) + return __va(res->start); + + page_map = devres_alloc(devm_memremap_pages_release, + sizeof(*page_map), GFP_KERNEL); + if (!page_map) + return ERR_PTR(-ENOMEM); + + memcpy(&page_map->res, res, sizeof(*res)); + + nid = dev_to_node(dev); + if (nid < 0) + nid = 0; + + error = arch_add_memory(nid, res->start, resource_size(res), true); + if (error) { + devres_free(page_map); + return ERR_PTR(error); + } + + devres_add(dev, page_map); + return __va(res->start); +} +EXPORT_SYMBOL(devm_memremap_pages); +#endif /* CONFIG_ZONE_DEVICE */ -- GitLab From 96601adb745186ccbcf5b078d4756f13381ec2af Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 24 Aug 2015 18:29:38 -0400 Subject: [PATCH 5244/7006] x86, pmem: clarify that ARCH_HAS_PMEM_API implies PMEM mapped WB Given that a write-back (WB) mapping plus non-temporal stores is expected to be the most efficient way to access PMEM, update the definition of ARCH_HAS_PMEM_API to imply arch support for WB-mapped-PMEM. This is needed as a pre-requisite for adding PMEM to the direct map and mapping it with struct page. The above clarification for X86_64 means that memcpy_to_pmem() is permitted to use the non-temporal arch_memcpy_to_pmem() rather than needlessly fall back to default_memcpy_to_pmem() when the pcommit instruction is not available. When arch_memcpy_to_pmem() is not guaranteed to flush writes out of cache, i.e. on older X86_32 implementations where non-temporal stores may just dirty cache, ARCH_HAS_PMEM_API is simply disabled. The default fall back for persistent memory handling remains. Namely, map it with the WT (write-through) cache-type and hope for the best. arch_has_pmem_api() is updated to only indicate whether the arch provides the proper helpers to meet the minimum "writes are visible outside the cache hierarchy after memcpy_to_pmem() + wmb_pmem()". Code that cares whether wmb_pmem() actually flushes writes to pmem must now call arch_has_wmb_pmem() directly. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Reviewed-by: Ross Zwisler [hch: set ARCH_HAS_PMEM_API=n on x86_32] Reviewed-by: Christoph Hellwig [toshi: x86_32 compile fixes] Signed-off-by: Toshi Kani Signed-off-by: Dan Williams --- arch/x86/Kconfig | 2 +- arch/x86/include/asm/pmem.h | 9 +-------- drivers/acpi/nfit.c | 3 ++- drivers/nvdimm/pmem.c | 2 +- include/linux/pmem.h | 36 ++++++++++++++++++++++-------------- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 03ab6122325a5..ef4c6bbb3af15 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -27,7 +27,7 @@ config X86 select ARCH_HAS_ELF_RANDOMIZE select ARCH_HAS_FAST_MULTIPLIER select ARCH_HAS_GCOV_PROFILE_ALL - select ARCH_HAS_PMEM_API + select ARCH_HAS_PMEM_API if X86_64 select ARCH_HAS_MMIO_FLUSH select ARCH_HAS_SG_CHAIN select ARCH_HAVE_NMI_SAFE_CMPXCHG diff --git a/arch/x86/include/asm/pmem.h b/arch/x86/include/asm/pmem.h index bb026c5adf8a8..d8ce3ec816ab1 100644 --- a/arch/x86/include/asm/pmem.h +++ b/arch/x86/include/asm/pmem.h @@ -18,8 +18,6 @@ #include #include -#define ARCH_MEMREMAP_PMEM MEMREMAP_WB - #ifdef CONFIG_ARCH_HAS_PMEM_API /** * arch_memcpy_to_pmem - copy data to persistent memory @@ -143,18 +141,13 @@ static inline void arch_clear_pmem(void __pmem *addr, size_t size) __arch_wb_cache_pmem(vaddr, size); } -static inline bool arch_has_wmb_pmem(void) +static inline bool __arch_has_wmb_pmem(void) { -#ifdef CONFIG_X86_64 /* * We require that wmb() be an 'sfence', that is only guaranteed on * 64-bit builds */ return static_cpu_has(X86_FEATURE_PCOMMIT); -#else - return false; -#endif } #endif /* CONFIG_ARCH_HAS_PMEM_API */ - #endif /* __ASM_X86_PMEM_H__ */ diff --git a/drivers/acpi/nfit.c b/drivers/acpi/nfit.c index 56fff01416369..f61e69fa2ad11 100644 --- a/drivers/acpi/nfit.c +++ b/drivers/acpi/nfit.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "nfit.h" /* @@ -1371,7 +1372,7 @@ static int acpi_nfit_blk_region_enable(struct nvdimm_bus *nvdimm_bus, return -ENOMEM; } - if (!arch_has_pmem_api() && !nfit_blk->nvdimm_flush) + if (!arch_has_wmb_pmem() && !nfit_blk->nvdimm_flush) dev_warn(dev, "unable to guarantee persistence of writes\n"); if (mmio->line_size == 0) diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 3b5b9cb758b64..20bf122328da5 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -125,7 +125,7 @@ static struct pmem_device *pmem_alloc(struct device *dev, pmem->phys_addr = res->start; pmem->size = resource_size(res); - if (!arch_has_pmem_api()) + if (!arch_has_wmb_pmem()) dev_warn(dev, "unable to guarantee persistence of writes\n"); if (!devm_request_mem_region(dev, pmem->phys_addr, pmem->size, diff --git a/include/linux/pmem.h b/include/linux/pmem.h index a9d84bf335eee..85f810b339175 100644 --- a/include/linux/pmem.h +++ b/include/linux/pmem.h @@ -17,16 +17,23 @@ #include #ifdef CONFIG_ARCH_HAS_PMEM_API +#define ARCH_MEMREMAP_PMEM MEMREMAP_WB #include #else -static inline void arch_wmb_pmem(void) +#define ARCH_MEMREMAP_PMEM MEMREMAP_WT +/* + * These are simply here to enable compilation, all call sites gate + * calling these symbols with arch_has_pmem_api() and redirect to the + * implementation in asm/pmem.h. + */ +static inline bool __arch_has_wmb_pmem(void) { - BUG(); + return false; } -static inline bool arch_has_wmb_pmem(void) +static inline void arch_wmb_pmem(void) { - return false; + BUG(); } static inline void arch_memcpy_to_pmem(void __pmem *dst, const void *src, @@ -53,7 +60,6 @@ static inline void arch_clear_pmem(void __pmem *addr, size_t size) * implementations for arch_memcpy_to_pmem(), arch_wmb_pmem(), * arch_copy_from_iter_pmem(), arch_clear_pmem() and arch_has_wmb_pmem(). */ - static inline void memcpy_from_pmem(void *dst, void __pmem const *src, size_t size) { memcpy(dst, (void __force const *) src, size); @@ -64,8 +70,13 @@ static inline void memunmap_pmem(struct device *dev, void __pmem *addr) devm_memunmap(dev, (void __force *) addr); } +static inline bool arch_has_pmem_api(void) +{ + return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API); +} + /** - * arch_has_pmem_api - true if wmb_pmem() ensures durability + * arch_has_wmb_pmem - true if wmb_pmem() ensures durability * * For a given cpu implementation within an architecture it is possible * that wmb_pmem() resolves to a nop. In the case this returns @@ -73,9 +84,9 @@ static inline void memunmap_pmem(struct device *dev, void __pmem *addr) * fall back to a different data consistency model, or otherwise notify * the user. */ -static inline bool arch_has_pmem_api(void) +static inline bool arch_has_wmb_pmem(void) { - return IS_ENABLED(CONFIG_ARCH_HAS_PMEM_API) && arch_has_wmb_pmem(); + return arch_has_pmem_api() && __arch_has_wmb_pmem(); } /* @@ -120,13 +131,8 @@ static inline void default_clear_pmem(void __pmem *addr, size_t size) static inline void __pmem *memremap_pmem(struct device *dev, resource_size_t offset, unsigned long size) { -#ifdef ARCH_MEMREMAP_PMEM return (void __pmem *) devm_memremap(dev, offset, size, ARCH_MEMREMAP_PMEM); -#else - return (void __pmem *) devm_memremap(dev, offset, size, - MEMREMAP_WT); -#endif } /** @@ -158,8 +164,10 @@ static inline void memcpy_to_pmem(void __pmem *dst, const void *src, size_t n) */ static inline void wmb_pmem(void) { - if (arch_has_pmem_api()) + if (arch_has_wmb_pmem()) arch_wmb_pmem(); + else + wmb(); } /** -- GitLab From ae57ca0f4fce219ef34c28f0edc210598c465a4d Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Wed, 26 Aug 2015 21:10:55 +0800 Subject: [PATCH 5245/7006] NFS: Check size by inode_newsize_ok in nfs_setattr Set rlimit for NFS's files is useless right now. For local process's rlimit, it should be checked by nfs client. The same, CIFS also call inode_change_ok checking rlimit at its client in cifs_setattr_nounix() and cifs_setattr_unix(). v3, fix bad using of error Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index e2cc0031decb6..99a68bd9c1782 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -504,7 +504,7 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = d_inode(dentry); struct nfs_fattr *fattr; - int error = -ENOMEM; + int error = 0; nfs_inc_stats(inode, NFSIOS_VFSSETATTR); @@ -513,15 +513,14 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) attr->ia_valid &= ~ATTR_MODE; if (attr->ia_valid & ATTR_SIZE) { - loff_t i_size; - BUG_ON(!S_ISREG(inode->i_mode)); - i_size = i_size_read(inode); - if (attr->ia_size == i_size) + error = inode_newsize_ok(inode, attr->ia_size); + if (error) + return error; + + if (attr->ia_size == i_size_read(inode)) attr->ia_valid &= ~ATTR_SIZE; - else if (attr->ia_size < i_size && IS_SWAPFILE(inode)) - return -ETXTBSY; } /* Optimization: if the end result is no change, don't RPC */ @@ -536,8 +535,11 @@ nfs_setattr(struct dentry *dentry, struct iattr *attr) nfs_sync_inode(inode); fattr = nfs_alloc_fattr(); - if (fattr == NULL) + if (fattr == NULL) { + error = -ENOMEM; goto out; + } + /* * Return any delegations if we're going to change ACLs */ -- GitLab From c5c3fb5f975a8bcc42cd039b83d9a4729ce489bb Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Wed, 26 Aug 2015 21:11:39 +0800 Subject: [PATCH 5246/7006] NFS: Make opened as optional argument in _nfs4_do_open Check opened, only update it when non-NULL. It's not needs define an unused value for the opened when calling _nfs4_do_open. v3, same as v2. Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/nfs4file.c | 3 +-- fs/nfs/nfs4proc.c | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index dcd39d4e2efeb..43f1590b9240d 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -27,7 +27,6 @@ nfs4_file_open(struct inode *inode, struct file *filp) struct inode *dir; unsigned openflags = filp->f_flags; struct iattr attr; - int opened = 0; int err; /* @@ -66,7 +65,7 @@ nfs4_file_open(struct inode *inode, struct file *filp) nfs_sync_inode(inode); } - inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, &opened); + inode = NFS_PROTO(dir)->open_context(dir, ctx, openflags, &attr, NULL); if (IS_ERR(inode)) { err = PTR_ERR(inode); switch (err) { diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6e988fd92f69a..4687661bfbdcd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2452,7 +2452,7 @@ static int _nfs4_do_open(struct inode *dir, nfs_setsecurity(state->inode, opendata->o_res.f_attr, olabel); } } - if (opendata->file_created) + if (opened && opendata->file_created) *opened |= FILE_CREATED; if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) { @@ -3562,7 +3562,6 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, struct nfs4_label l, *ilabel = NULL; struct nfs_open_context *ctx; struct nfs4_state *state; - int opened = 0; int status = 0; ctx = alloc_nfs_open_context(dentry, FMODE_READ); @@ -3572,7 +3571,7 @@ nfs4_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr, ilabel = nfs4_label_init_security(dir, dentry, sattr, &l); sattr->ia_mode &= ~current_umask(); - state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, &opened); + state = nfs4_do_open(dir, ctx, flags, sattr, ilabel, NULL); if (IS_ERR(state)) { status = PTR_ERR(state); goto out; -- GitLab From 5153aacfb8e2744af68e7b84ccd3f02aeefe4f48 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Wed, 26 Aug 2015 21:12:15 +0800 Subject: [PATCH 5247/7006] NFS: Update NFS4_BITMAP_SIZE v4.1/v4.2 have define attributes at word2, nfs client also support security label now. v3, same as v2. Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- include/uapi/linux/nfs4.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/nfs4.h b/include/uapi/linux/nfs4.h index 2119c7c274d71..2b871e0858d9f 100644 --- a/include/uapi/linux/nfs4.h +++ b/include/uapi/linux/nfs4.h @@ -15,7 +15,7 @@ #include -#define NFS4_BITMAP_SIZE 2 +#define NFS4_BITMAP_SIZE 3 #define NFS4_VERIFIER_SIZE 8 #define NFS4_STATEID_SEQID_SIZE 4 #define NFS4_STATEID_OTHER_SIZE 12 -- GitLab From 8c61282ff61c28d5a12bb53f0eaa221d30fd3ae1 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Wed, 26 Aug 2015 21:12:58 +0800 Subject: [PATCH 5248/7006] NFS: Get suppattr_exclcreat when getting server capabilities Create file with attributs as NFS4_CREATE_EXCLUSIVE4_1 mode depends on suppattr_exclcreat attribut. v3, same as v2. Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 14 +++++++++++++- fs/nfs/nfs4xdr.c | 26 +++++++++++++++++++++----- include/linux/nfs_fs_sb.h | 5 +++++ include/linux/nfs_xdr.h | 2 ++ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4687661bfbdcd..a6a28d45cca4a 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2893,8 +2893,10 @@ static void nfs4_close_context(struct nfs_open_context *ctx, int is_sync) static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) { + u32 bitmask[3] = {}, minorversion = server->nfs_client->cl_minorversion; struct nfs4_server_caps_arg args = { .fhandle = fhandle, + .bitmask = bitmask, }; struct nfs4_server_caps_res res = {}; struct rpc_message msg = { @@ -2904,10 +2906,18 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f }; int status; + bitmask[0] = FATTR4_WORD0_SUPPORTED_ATTRS | + FATTR4_WORD0_FH_EXPIRE_TYPE | + FATTR4_WORD0_LINK_SUPPORT | + FATTR4_WORD0_SYMLINK_SUPPORT | + FATTR4_WORD0_ACLSUPPORT; + if (minorversion) + bitmask[2] = FATTR4_WORD2_SUPPATTR_EXCLCREAT; + status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); if (status == 0) { /* Sanity check the server answers */ - switch (server->nfs_client->cl_minorversion) { + switch (minorversion) { case 0: res.attr_bitmask[1] &= FATTR4_WORD1_NFS40_MASK; res.attr_bitmask[2] = 0; @@ -2960,6 +2970,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f server->cache_consistency_bitmask[0] &= FATTR4_WORD0_CHANGE|FATTR4_WORD0_SIZE; server->cache_consistency_bitmask[1] &= FATTR4_WORD1_TIME_METADATA|FATTR4_WORD1_TIME_MODIFY; server->cache_consistency_bitmask[2] = 0; + memcpy(server->exclcreat_bitmask, res.exclcreat_bitmask, + sizeof(server->exclcreat_bitmask)); server->acl_bitmask = res.acl_bitmask; server->fh_expire_type = res.fh_expire_type; } diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index c42459e45f622..ad8dde12f23bc 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -2582,6 +2582,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req, struct xdr_stream *xdr, struct nfs4_server_caps_arg *args) { + const u32 *bitmask = args->bitmask; struct compound_hdr hdr = { .minorversion = nfs4_xdr_minorversion(&args->seq_args), }; @@ -2589,11 +2590,7 @@ static void nfs4_xdr_enc_server_caps(struct rpc_rqst *req, encode_compound_hdr(xdr, req, &hdr); encode_sequence(xdr, &args->seq_args, &hdr); encode_putfh(xdr, args->fhandle, &hdr); - encode_getattr_one(xdr, FATTR4_WORD0_SUPPORTED_ATTRS| - FATTR4_WORD0_FH_EXPIRE_TYPE| - FATTR4_WORD0_LINK_SUPPORT| - FATTR4_WORD0_SYMLINK_SUPPORT| - FATTR4_WORD0_ACLSUPPORT, &hdr); + encode_getattr_three(xdr, bitmask[0], bitmask[1], bitmask[2], &hdr); encode_nops(&hdr); } @@ -3370,6 +3367,22 @@ out_overflow: return -EIO; } +static int decode_attr_exclcreat_supported(struct xdr_stream *xdr, + uint32_t *bitmap, uint32_t *bitmask) +{ + if (likely(bitmap[2] & FATTR4_WORD2_SUPPATTR_EXCLCREAT)) { + int ret; + ret = decode_attr_bitmap(xdr, bitmask); + if (unlikely(ret < 0)) + return ret; + bitmap[2] &= ~FATTR4_WORD2_SUPPATTR_EXCLCREAT; + } else + bitmask[0] = bitmask[1] = bitmask[2] = 0; + dprintk("%s: bitmask=%08x:%08x:%08x\n", __func__, + bitmask[0], bitmask[1], bitmask[2]); + return 0; +} + static int decode_attr_filehandle(struct xdr_stream *xdr, uint32_t *bitmap, struct nfs_fh *fh) { __be32 *p; @@ -4323,6 +4336,9 @@ static int decode_server_caps(struct xdr_stream *xdr, struct nfs4_server_caps_re goto xdr_error; if ((status = decode_attr_aclsupport(xdr, bitmap, &res->acl_bitmask)) != 0) goto xdr_error; + if ((status = decode_attr_exclcreat_supported(xdr, bitmap, + res->exclcreat_bitmask)) != 0) + goto xdr_error; status = verify_attr_len(xdr, savep, attrlen); xdr_error: dprintk("%s: xdr returned %d!\n", __func__, -status); diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 20bc8e51b1612..570a7df2775b5 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -173,6 +173,11 @@ struct nfs_server { set of attributes supported on this filesystem excluding the label support bit. */ + u32 exclcreat_bitmask[3]; + /* V4 bitmask representing the + set of attributes supported + on this filesystem for the + exclusive create. */ u32 cache_consistency_bitmask[3]; /* V4 bitmask representing the subset of change attribute, size, ctime diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index b9b530409ff7c..0d7c832ec4152 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -1057,11 +1057,13 @@ struct nfs4_statfs_res { struct nfs4_server_caps_arg { struct nfs4_sequence_args seq_args; struct nfs_fh *fhandle; + const u32 * bitmask; }; struct nfs4_server_caps_res { struct nfs4_sequence_res seq_res; u32 attr_bitmask[3]; + u32 exclcreat_bitmask[3]; u32 acl_bitmask; u32 has_links; u32 has_symlinks; -- GitLab From 5334c5bdac926c5f8d89729beccb46fe88eda9e7 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Wed, 26 Aug 2015 21:13:37 +0800 Subject: [PATCH 5249/7006] NFS: Send attributes in OPEN request for NFS4_CREATE_EXCLUSIVE4_1 Client sends a SETATTR request after OPEN for updating attributes. For create file with S_ISGID is set, the S_ISGID in SETATTR will be ignored at nfs server as chmod of no PERMISSION. v3, same as v2. Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 18 ++++++++++++++---- fs/nfs/nfs4xdr.c | 26 ++++++++++++++++++-------- include/linux/nfs_xdr.h | 2 +- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a6a28d45cca4a..2923abf2fc0cd 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -2307,15 +2307,25 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st * fields corresponding to attributes that were used to store the verifier. * Make sure we clobber those fields in the later setattr call */ -static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, struct iattr *sattr) +static inline void nfs4_exclusive_attrset(struct nfs4_opendata *opendata, + struct iattr *sattr, struct nfs4_label **label) { - if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_ACCESS) && + const u32 *attrset = opendata->o_res.attrset; + + if ((attrset[1] & FATTR4_WORD1_TIME_ACCESS) && !(sattr->ia_valid & ATTR_ATIME_SET)) sattr->ia_valid |= ATTR_ATIME; - if ((opendata->o_res.attrset[1] & FATTR4_WORD1_TIME_MODIFY) && + if ((attrset[1] & FATTR4_WORD1_TIME_MODIFY) && !(sattr->ia_valid & ATTR_MTIME_SET)) sattr->ia_valid |= ATTR_MTIME; + + /* Except MODE, it seems harmless of setting twice. */ + if ((attrset[1] & FATTR4_WORD1_MODE)) + sattr->ia_valid &= ~ATTR_MODE; + + if (attrset[2] & FATTR4_WORD2_SECURITY_LABEL) + *label = NULL; } static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, @@ -2440,7 +2450,7 @@ static int _nfs4_do_open(struct inode *dir, if ((opendata->o_arg.open_flags & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) && (opendata->o_arg.createmode != NFS4_CREATE_GUARDED)) { - nfs4_exclusive_attrset(opendata, sattr); + nfs4_exclusive_attrset(opendata, sattr, &label); nfs_fattr_init(opendata->o_res.f_attr); status = nfs4_do_setattr(state->inode, cred, diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ad8dde12f23bc..a7be571c1666b 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -1001,7 +1001,8 @@ static void encode_nfs4_verifier(struct xdr_stream *xdr, const nfs4_verifier *ve static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, const struct nfs4_label *label, - const struct nfs_server *server) + const struct nfs_server *server, + bool excl_check) { char owner_name[IDMAP_NAMESZ]; char owner_group[IDMAP_NAMESZ]; @@ -1067,6 +1068,17 @@ static void encode_attrs(struct xdr_stream *xdr, const struct iattr *iap, bmval[1] |= FATTR4_WORD1_TIME_MODIFY_SET; len += 4; } + + if (excl_check) { + const u32 *excl_bmval = server->exclcreat_bitmask; + bmval[0] &= excl_bmval[0]; + bmval[1] &= excl_bmval[1]; + bmval[2] &= excl_bmval[2]; + + if (!(excl_bmval[2] & FATTR4_WORD2_SECURITY_LABEL)) + label = NULL; + } + if (label) { len += 4 + 4 + 4 + (XDR_QUADLEN(label->len) << 2); bmval[2] |= FATTR4_WORD2_SECURITY_LABEL; @@ -1170,7 +1182,7 @@ static void encode_create(struct xdr_stream *xdr, const struct nfs4_create_arg * } encode_string(xdr, create->name->len, create->name->name); - encode_attrs(xdr, create->attrs, create->label, create->server); + encode_attrs(xdr, create->attrs, create->label, create->server, false); } static void encode_getattr_one(struct xdr_stream *xdr, uint32_t bitmap, struct compound_hdr *hdr) @@ -1384,18 +1396,17 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_openargs *arg) { - struct iattr dummy; __be32 *p; p = reserve_space(xdr, 4); switch(arg->createmode) { case NFS4_CREATE_UNCHECKED: *p = cpu_to_be32(NFS4_CREATE_UNCHECKED); - encode_attrs(xdr, arg->u.attrs, arg->label, arg->server); + encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false); break; case NFS4_CREATE_GUARDED: *p = cpu_to_be32(NFS4_CREATE_GUARDED); - encode_attrs(xdr, arg->u.attrs, arg->label, arg->server); + encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, false); break; case NFS4_CREATE_EXCLUSIVE: *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE); @@ -1404,8 +1415,7 @@ static inline void encode_createmode(struct xdr_stream *xdr, const struct nfs_op case NFS4_CREATE_EXCLUSIVE4_1: *p = cpu_to_be32(NFS4_CREATE_EXCLUSIVE4_1); encode_nfs4_verifier(xdr, &arg->u.verifier); - dummy.ia_valid = 0; - encode_attrs(xdr, &dummy, arg->label, arg->server); + encode_attrs(xdr, arg->u.attrs, arg->label, arg->server, true); } } @@ -1661,7 +1671,7 @@ static void encode_setattr(struct xdr_stream *xdr, const struct nfs_setattrargs { encode_op_hdr(xdr, OP_SETATTR, decode_setattr_maxsz, hdr); encode_nfs4_stateid(xdr, &arg->stateid); - encode_attrs(xdr, arg->iap, arg->label, server); + encode_attrs(xdr, arg->iap, arg->label, server, false); } static void encode_setclientid(struct xdr_stream *xdr, const struct nfs4_setclientid *setclientid, struct compound_hdr *hdr) diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 0d7c832ec4152..b4392d86d157a 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -379,7 +379,7 @@ struct nfs_openargs { struct stateowner_id id; union { struct { - struct iattr * attrs; /* UNCHECKED, GUARDED */ + struct iattr * attrs; /* UNCHECKED, GUARDED, EXCLUSIVE4_1 */ nfs4_verifier verifier; /* EXCLUSIVE */ }; nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ -- GitLab From 69dba9bbc50609f19ee89d62d5199c81fcbc74b2 Mon Sep 17 00:00:00 2001 From: Jean Sacren Date: Thu, 27 Aug 2015 18:05:49 -0600 Subject: [PATCH 5250/7006] sock: fix kernel doc error The symbol '__sk_reclaim' is not present in the current tree. Apparently '__sk_reclaim' was meant to be '__sk_mem_reclaim', so fix it with the right symbol name for the kernel doc. Signed-off-by: Jean Sacren Cc: Hideo Aoki Signed-off-by: David S. Miller --- net/core/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/sock.c b/net/core/sock.c index 193901d097577..ca2984afe16ed 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -2078,7 +2078,7 @@ suppress_allocation: EXPORT_SYMBOL(__sk_mem_schedule); /** - * __sk_reclaim - reclaim memory_allocated + * __sk_mem_reclaim - reclaim memory_allocated * @sk: socket * @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple) */ -- GitLab From f84bb1eac0275283ccd76455e20f926e186ea8c8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 27 Aug 2015 21:21:36 +0200 Subject: [PATCH 5251/7006] net: fix IFF_NO_QUEUE for drivers using alloc_netdev Printing a warning in alloc_netdev_mqs() if tx_queue_len is zero and IFF_NO_QUEUE not set is not appropriate since drivers may use one of the alloc_netdev* macros instead of alloc_etherdev*, thereby not intentionally leaving tx_queue_len uninitialized. Instead check here if tx_queue_len is zero and set IFF_NO_QUEUE, so the value of tx_queue_len can be ignored in net/sched_generic.c. Fixes: 906470c ("net: warn if drivers set tx_queue_len = 0") Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/core/dev.c b/net/core/dev.c index a8e6cf4298d32..877c84834d81a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -7010,7 +7010,7 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, setup(dev); if (!dev->tx_queue_len) - printk(KERN_WARNING "%s uses DEPRECATED zero tx_queue_len - convert driver to use IFF_NO_QUEUE instead.\n", name); + dev->priv_flags |= IFF_NO_QUEUE; dev->num_tx_queues = txqs; dev->real_num_tx_queues = txqs; -- GitLab From db4094bca7a5746bc8e36db0557e8732963e88f0 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 27 Aug 2015 21:21:37 +0200 Subject: [PATCH 5252/7006] net: sched: ignore tx_queue_len when assigning default qdisc Since alloc_netdev_mqs() sets IFF_NO_QUEUE for drivers not initializing tx_queue_len, it is safe to assume that if tx_queue_len is zero, dev->priv flags always contains IFF_NO_QUEUE. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index 942fea8405a47..f501b7409320a 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -735,7 +735,7 @@ static void attach_one_default_qdisc(struct net_device *dev, { struct Qdisc *qdisc = &noqueue_qdisc; - if (dev->tx_queue_len && !(dev->priv_flags & IFF_NO_QUEUE)) { + if (!(dev->priv_flags & IFF_NO_QUEUE)) { qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, TC_H_ROOT); if (!qdisc) { @@ -756,7 +756,6 @@ static void attach_default_qdiscs(struct net_device *dev) txq = netdev_get_tx_queue(dev, 0); if (!netif_is_multiqueue(dev) || - dev->tx_queue_len == 0 || dev->priv_flags & IFF_NO_QUEUE) { netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); dev->qdisc = txq->qdisc_sleeping; -- GitLab From d66d6c3152e8d5a6db42a56bf7ae1c6cae87ba48 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 27 Aug 2015 21:21:38 +0200 Subject: [PATCH 5253/7006] net: sched: register noqueue qdisc This way users can attach noqueue just like any other qdisc using tc without having to mess with tx_queue_len first. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- include/net/sch_generic.h | 1 + net/sched/sch_api.c | 1 + net/sched/sch_generic.c | 12 +++++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 2eab08c38e328..444faa89a55fd 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -340,6 +340,7 @@ extern struct Qdisc noop_qdisc; extern struct Qdisc_ops noop_qdisc_ops; extern struct Qdisc_ops pfifo_fast_ops; extern struct Qdisc_ops mq_qdisc_ops; +extern struct Qdisc_ops noqueue_qdisc_ops; extern const struct Qdisc_ops *default_qdisc_ops; struct Qdisc_class_common { diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 59c227f26b56f..a3c70a18a7647 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1942,6 +1942,7 @@ static int __init pktsched_init(void) register_qdisc(&bfifo_qdisc_ops); register_qdisc(&pfifo_head_drop_qdisc_ops); register_qdisc(&mq_qdisc_ops); + register_qdisc(&noqueue_qdisc_ops); rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL, NULL); rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL, NULL); diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index f501b7409320a..d5c7c0d887864 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -416,9 +416,19 @@ struct Qdisc noop_qdisc = { }; EXPORT_SYMBOL(noop_qdisc); -static struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { +static int noqueue_init(struct Qdisc *qdisc, struct nlattr *opt) +{ + /* register_qdisc() assigns a default of noop_enqueue if unset, + * but __dev_queue_xmit() treats noqueue only as such + * if this is NULL - so clear it here. */ + qdisc->enqueue = NULL; + return 0; +} + +struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { .id = "noqueue", .priv_size = 0, + .init = noqueue_init, .enqueue = noop_enqueue, .dequeue = noop_dequeue, .peek = noop_dequeue, -- GitLab From 3e692f21532a54eeb5e6fc0ccc214cfa56fe23d3 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Thu, 27 Aug 2015 21:21:39 +0200 Subject: [PATCH 5254/7006] net: sched: simplify attach_one_default_qdisc() Now that noqueue qdisc can be attached just like any other qdisc, no special treatment is necessary anymore when attaching it as default qdisc. This change has the added benefit that 'tc qdisc show' prints noqueue instead of nothing for devices defaulting to noqueue. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- net/sched/sch_generic.c | 41 ++++++++++++----------------------------- 1 file changed, 12 insertions(+), 29 deletions(-) diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index d5c7c0d887864..cb5d4ad32946c 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -435,24 +435,6 @@ struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { .owner = THIS_MODULE, }; -static struct Qdisc noqueue_qdisc; -static struct netdev_queue noqueue_netdev_queue = { - .qdisc = &noqueue_qdisc, - .qdisc_sleeping = &noqueue_qdisc, -}; - -static struct Qdisc noqueue_qdisc = { - .enqueue = NULL, - .dequeue = noop_dequeue, - .flags = TCQ_F_BUILTIN, - .ops = &noqueue_qdisc_ops, - .list = LIST_HEAD_INIT(noqueue_qdisc.list), - .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), - .dev_queue = &noqueue_netdev_queue, - .busylock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.busylock), -}; - - static const u8 prio2band[TC_PRIO_MAX + 1] = { 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 }; @@ -743,18 +725,19 @@ static void attach_one_default_qdisc(struct net_device *dev, struct netdev_queue *dev_queue, void *_unused) { - struct Qdisc *qdisc = &noqueue_qdisc; + struct Qdisc *qdisc; + const struct Qdisc_ops *ops = default_qdisc_ops; - if (!(dev->priv_flags & IFF_NO_QUEUE)) { - qdisc = qdisc_create_dflt(dev_queue, - default_qdisc_ops, TC_H_ROOT); - if (!qdisc) { - netdev_info(dev, "activation failed\n"); - return; - } - if (!netif_is_multiqueue(dev)) - qdisc->flags |= TCQ_F_ONETXQUEUE; + if (dev->priv_flags & IFF_NO_QUEUE) + ops = &noqueue_qdisc_ops; + + qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT); + if (!qdisc) { + netdev_info(dev, "activation failed\n"); + return; } + if (!netif_is_multiqueue(dev)) + qdisc->flags |= TCQ_F_ONETXQUEUE; dev_queue->qdisc_sleeping = qdisc; } @@ -790,7 +773,7 @@ static void transition_one_qdisc(struct net_device *dev, clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state); rcu_assign_pointer(dev_queue->qdisc, new_qdisc); - if (need_watchdog_p && new_qdisc != &noqueue_qdisc) { + if (need_watchdog_p) { dev_queue->trans_start = 0; *need_watchdog_p = 1; } -- GitLab From d13549074cf066d6d5bb29903d044beffea342d3 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Aug 2015 20:37:39 -0400 Subject: [PATCH 5255/7006] NFSv4.1/flexfiles: Fix a protocol error in layoutreturn According to the flexfiles protocol, the layoutreturn should specify an array of errors in the following format: struct ff_ioerr4 { offset4 ffie_offset; length4 ffie_length; stateid4 ffie_stateid; device_error4 ffie_errors<>; }; This patch fixes up the code to ensure that our ffie_errors is indeed encoded as an array (albeit with only a single entry). Reported-by: Tom Haynes Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index f13e1969eedd9..b28fa4cbea526 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -500,16 +500,19 @@ int ff_layout_encode_ds_ioerr(struct nfs4_flexfile_layout *flo, range->offset, range->length)) continue; /* offset(8) + length(8) + stateid(NFS4_STATEID_SIZE) - * + deviceid(NFS4_DEVICEID4_SIZE) + status(4) + opnum(4) + * + array length + deviceid(NFS4_DEVICEID4_SIZE) + * + status(4) + opnum(4) */ p = xdr_reserve_space(xdr, - 24 + NFS4_STATEID_SIZE + NFS4_DEVICEID4_SIZE); + 28 + NFS4_STATEID_SIZE + NFS4_DEVICEID4_SIZE); if (unlikely(!p)) return -ENOBUFS; p = xdr_encode_hyper(p, err->offset); p = xdr_encode_hyper(p, err->length); p = xdr_encode_opaque_fixed(p, &err->stateid, NFS4_STATEID_SIZE); + /* Encode 1 error */ + *p++ = cpu_to_be32(1); p = xdr_encode_opaque_fixed(p, &err->deviceid, NFS4_DEVICEID4_SIZE); *p++ = cpu_to_be32(err->status); -- GitLab From 6669cb8bed02ec1b60e80f2e1e317afc28544207 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 27 Aug 2015 20:43:20 -0400 Subject: [PATCH 5256/7006] NFSv4.1/pnfs: Ensure layoutreturn reserves space for the opaque payload The "FIXME" is outdated. Flexfiles does add a payload. Signed-off-by: Trond Myklebust --- fs/nfs/nfs4xdr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index a7be571c1666b..ff4784c54e04f 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -400,7 +400,8 @@ static int nfs4_stat_to_errno(int); #define decode_layoutcommit_maxsz (op_decode_hdr_maxsz + 3) #define encode_layoutreturn_maxsz (8 + op_encode_hdr_maxsz + \ encode_stateid_maxsz + \ - 1 /* FIXME: opaque lrf_body always empty at the moment */) + 1 + \ + XDR_QUADLEN(NFS4_OPAQUE_LIMIT)) #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \ 1 + decode_stateid_maxsz) #define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1) -- GitLab From 590c7567a2895f939525ead57b0334c6d47986f0 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 27 Aug 2015 14:12:36 +1000 Subject: [PATCH 5257/7006] powerpc/pseries: Fix corrupted pdn list Commit cca87d30 ("powerpc/pci: Refactor pci_dn") introduced pdn list for SRIOV VFs. It means the pdn is be put into the child list of its parent pdn when the pdn is created. When doing PCI hot unplugging on pSeries, the PCI device node as well as its pdn are released through procfs entry "powerpc/ofdt". Some one else grabs the memory chunk of the pdn and update it accordingly. At the same time, the pdn is still tracked in the child list of parent pdn. It leads to corrupted child list in the parent pdn. This fixes above issue by removing the pdn from the child list of its parent pdn when the device node is detached from the system. Note the pdn is free'd when the device node is released if the device node is dynamic one. Otherwise, the device node as well as the pdn won't be released. Fixes: cca87d30 ("powerpc/pci: Refactor pci_dn") Cc: stable@vger.kernel.org # 4.1+ Reported-by: Santwana Samantray Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/setup.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index df6a7041922b6..e6e8b241d7173 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -268,6 +268,11 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act eeh_dev_init(PCI_DN(np), pci->phb); } break; + case OF_RECONFIG_DETACH_NODE: + pci = PCI_DN(np); + if (pci) + list_del(&pci->list); + break; default: err = NOTIFY_DONE; break; -- GitLab From ea0f8acf4d44727f7d3a38072566029bf5e17b44 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Thu, 27 Aug 2015 14:12:37 +1000 Subject: [PATCH 5258/7006] powerpc/pseries: Cleanup on pci_dn_reconfig_notifier() This applies cleanup on pci_dn_reconfig_notifier(), no functional changes: * Rename variable "pci" to "pdn" to indicate its purpose clearly. * The parent node can be released at any time. So it should be hold with of_get_parent() before accessing it. * The device node doesn't have to have parent node in theory. More check on this. Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/platforms/pseries/setup.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e6e8b241d7173..39a74fad3e045 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c @@ -254,24 +254,26 @@ static void __init pseries_discover_pic(void) static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *data) { struct of_reconfig_data *rd = data; - struct device_node *np = rd->dn; - struct pci_dn *pci = NULL; + struct device_node *parent, *np = rd->dn; + struct pci_dn *pdn; int err = NOTIFY_OK; switch (action) { case OF_RECONFIG_ATTACH_NODE: - pci = np->parent->data; - if (pci) { - update_dn_pci_info(np, pci->phb); - - /* Create EEH device for the OF node */ - eeh_dev_init(PCI_DN(np), pci->phb); + parent = of_get_parent(np); + pdn = parent ? PCI_DN(parent) : NULL; + if (pdn) { + /* Create pdn and EEH device */ + update_dn_pci_info(np, pdn->phb); + eeh_dev_init(PCI_DN(np), pdn->phb); } + + of_node_put(parent); break; case OF_RECONFIG_DETACH_NODE: - pci = PCI_DN(np); - if (pci) - list_del(&pci->list); + pdn = PCI_DN(np); + if (pdn) + list_del(&pdn->list); break; default: err = NOTIFY_DONE; -- GitLab From 1f821ed7afaa7ed689322ee2369f270e374a6350 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 12 Aug 2015 16:30:18 +0530 Subject: [PATCH 5259/7006] PM / OPP: Free resources and properly return error on failure _of_init_opp_table_v2() isn't freeing up resources on some errors and the error values returned are also not correct always. This fixes following problems: - Return -ENOENT, if no entries are found in the table. - Use IS_ERR() to properly check return value of _find_device_opp(). - Return error value with PTR_ERR() in above case. - Free table if _find_device_opp() fails. Reported-by: Dan Carpenter Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 204c6c9451686..4d6c4576f7ae0 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -1323,28 +1323,30 @@ static int _of_init_opp_table_v2(struct device *dev, if (ret) { dev_err(dev, "%s: Failed to add OPP, %d\n", __func__, ret); - break; + goto free_table; } } /* There should be one of more OPP defined */ - if (WARN_ON(!count)) + if (WARN_ON(!count)) { + ret = -ENOENT; goto put_opp_np; + } - if (!ret) { - if (!dev_opp) { - dev_opp = _find_device_opp(dev); - if (WARN_ON(!dev_opp)) - goto put_opp_np; - } - - dev_opp->np = opp_np; - dev_opp->shared_opp = of_property_read_bool(opp_np, - "opp-shared"); - } else { - of_free_opp_table(dev); + dev_opp = _find_device_opp(dev); + if (WARN_ON(IS_ERR(dev_opp))) { + ret = PTR_ERR(dev_opp); + goto free_table; } + dev_opp->np = opp_np; + dev_opp->shared_opp = of_property_read_bool(opp_np, "opp-shared"); + + of_node_put(opp_np); + return 0; + +free_table: + of_free_opp_table(dev); put_opp_np: of_node_put(opp_np); -- GitLab From 4a68ccc8e49854e071e14995de2a35016b240131 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Wed, 29 Apr 2015 10:28:17 +1000 Subject: [PATCH 5260/7006] remove unnecessary include This was merged with core/device.h in an earlier commit, but somehow never got removed. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/device.h | 30 ------------------- 1 file changed, 30 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/engine/device.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h deleted file mode 100644 index 5d4805e67e764..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __NOUVEAU_SUBDEV_DEVICE_H__ -#define __NOUVEAU_SUBDEV_DEVICE_H__ - -#include - -struct platform_device; - -enum nv_bus_type { - NOUVEAU_BUS_PCI, - NOUVEAU_BUS_PLATFORM, -}; - -#define nouveau_device_create(p,t,n,s,c,d,u) \ - nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d), \ - sizeof(**u), (void **)u) - -int nouveau_device_create_(void *, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - int, void **); - -int nv04_identify(struct nouveau_device *); -int nv10_identify(struct nouveau_device *); -int nv20_identify(struct nouveau_device *); -int nv30_identify(struct nouveau_device *); -int nv40_identify(struct nouveau_device *); -int nv50_identify(struct nouveau_device *); -int nvc0_identify(struct nouveau_device *); -int nve0_identify(struct nouveau_device *); -int gm100_identify(struct nouveau_device *); -#endif -- GitLab From 7164f4c5b2cfe9aa59d290ea71268022f8950eba Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sat, 23 May 2015 10:37:43 +0200 Subject: [PATCH 5261/7006] drm/nouveau/bios/rammap: Pull DLLoff bit out of version 0x10 struct In preparation of NV50 reclocking, where there is no version Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h index 420426793880e..c6fb6aa2c143b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h @@ -32,6 +32,7 @@ struct nvbios_ramcfg { unsigned ramcfg_ver; unsigned ramcfg_hdr; unsigned ramcfg_timing; + unsigned ramcfg_DLLoff; union { struct { unsigned ramcfg_10_02_01:1; @@ -40,7 +41,6 @@ struct nvbios_ramcfg { unsigned ramcfg_10_02_08:1; unsigned ramcfg_10_02_10:1; unsigned ramcfg_10_02_20:1; - unsigned ramcfg_10_DLLoff:1; unsigned ramcfg_10_03_0f:4; unsigned ramcfg_10_04_01:1; unsigned ramcfg_10_05:8; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index 8b17bb4b220ca..a688d3b4ef375 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -157,7 +157,7 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5; - p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0; p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index 15b462ae33cb5..e1d11f709a711 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -77,7 +77,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) CWL = ram->next->bios.timing_10_CWL; CL = ram->next->bios.timing_10_CL; WR = ram->next->bios.timing_10_WR; - DLL = !ram->next->bios.ramcfg_10_DLLoff; + DLL = !ram->next->bios.ramcfg_DLLoff; ODT = ram->next->bios.timing_10_ODT; break; case 0x20: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 24176401b49ba..47d53edbf9bcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -590,7 +590,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) r100da0 = 0x00000000; } - if (!next->bios.ramcfg_10_DLLoff) + if (!next->bios.ramcfg_DLLoff) r004018 |= 0x00004000; /* pll2pll requires to switch to a safe clock first */ @@ -630,7 +630,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) } /* If we're disabling the DLL, do it now */ - switch (next->bios.ramcfg_10_DLLoff * ram->base.type) { + switch (next->bios.ramcfg_DLLoff * ram->base.type) { case NV_MEM_TYPE_DDR3: nvkm_sddr3_dll_disable(fuc, ram->base.mr); break; @@ -810,7 +810,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) gt215_ram_fbvref(fuc, 1); /* Reset DLL */ - if (!next->bios.ramcfg_10_DLLoff) + if (!next->bios.ramcfg_DLLoff) nvkm_sddr2_dll_reset(fuc); if (ram->base.type == NV_MEM_TYPE_GDDR3) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c index afab42df28d40..86bf67456b143 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c @@ -65,7 +65,7 @@ nvkm_sddr2_calc(struct nvkm_ram *ram) case 0x10: CL = ram->next->bios.timing_10_CL; WR = ram->next->bios.timing_10_WR; - DLL = !ram->next->bios.ramcfg_10_DLLoff; + DLL = !ram->next->bios.ramcfg_DLLoff; ODT = ram->next->bios.timing_10_ODT & 3; break; case 0x20: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c index 10844355c3f30..77c53f9559cd2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c @@ -79,7 +79,7 @@ nvkm_sddr3_calc(struct nvkm_ram *ram) CWL = ram->next->bios.timing_10_CWL; CL = ram->next->bios.timing_10_CL; WR = ram->next->bios.timing_10_WR; - DLL = !ram->next->bios.ramcfg_10_DLLoff; + DLL = !ram->next->bios.ramcfg_DLLoff; ODT = ram->next->bios.timing_10_ODT; break; case 0x20: -- GitLab From d4cc5f0c2aea8350fe07a87cd312ca6a8f1f3129 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sat, 23 May 2015 10:37:44 +0200 Subject: [PATCH 5262/7006] drm/nouveau/fb/ramnv50: Make 0x100da0 per-partition Like on GT215 Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index d2c81dd635dc3..67715c69e158b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -42,7 +42,7 @@ struct nv50_ramseq { struct hwsq_reg r_0x1002d0; struct hwsq_reg r_0x1002d4; struct hwsq_reg r_0x1002dc; - struct hwsq_reg r_0x100da0[8]; + struct hwsq_reg r_0x100da0; struct hwsq_reg r_0x100e20; struct hwsq_reg r_0x100e24; struct hwsq_reg r_0x611200; @@ -70,6 +70,7 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) u8 size; } ramcfg, timing; u8 ver, hdr, cnt, len, strap; + u32 r100da0; int N1, M1, N2, M2, P; int ret, i; @@ -109,6 +110,13 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) timing.data = 0; } + /* XXX: 750MHz seems rather arbitrary */ + if (freq <= 750000) { + r100da0 = 0x00000010; + } else { + r100da0 = 0x00000000; + } + ret = ram_init(hwsq, nv_subdev(pfb)); if (ret) return ret; @@ -144,10 +152,9 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) | (P << 22) | (P << 16)); -#if QFX5800NVA0 - for (i = 0; i < 8; i++) - ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/ -#endif + + if (nv_device(pfb)->chipset == 0xa0) + ram_wr32(hwsq, 0x100da0, r100da0); /*XXX: here?*/ ram_nsec(hwsq, 96000); /*XXX*/ ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000); @@ -430,8 +437,7 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0); ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4); ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc); - for (i = 0; i < 8; i++) - ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04)); + ram->hwsq.r_0x100da0 = hwsq_stride(0x100da0, 4, ram->base.part_mask); ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20); ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24); ram->hwsq.r_0x611200 = hwsq_reg(0x611200); -- GitLab From 3b582bed907a26b30e511c83c24254c0ae987f47 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sat, 23 May 2015 10:37:45 +0200 Subject: [PATCH 5263/7006] drm/nouveau/fb/ramgt215: No need to cuss like that Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 47d53edbf9bcd..bc36a4ff15f45 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -579,7 +579,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) if (ret) return ret; - /* XXX: where the fuck does 750MHz come from? */ + /* XXX: 750MHz seems rather arbitrary */ if (freq <= 750000) { r004018 = 0x10000000; r100760 = 0x22222222; -- GitLab From 35fe024acffc2c29bade5a68a09962bf7ea3c8ed Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sat, 23 May 2015 10:37:46 +0200 Subject: [PATCH 5264/7006] drm/nouveau/fb/ramnv50: Ressurect timing code, use proper timing/rammap handlers Might need some generalisation to < GT200. For those: use at your own risk! Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- .../nouveau/include/nvkm/subdev/bios/ramcfg.h | 16 ++ .../nouveau/include/nvkm/subdev/bios/rammap.h | 2 + .../gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 29 +++ .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 168 ++++++++++++++---- 4 files changed, 182 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h index c6fb6aa2c143b..f09b6bf69098c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h @@ -34,6 +34,22 @@ struct nvbios_ramcfg { unsigned ramcfg_timing; unsigned ramcfg_DLLoff; union { + struct { + unsigned ramcfg_00_03_01:1; + unsigned ramcfg_00_03_02:1; + unsigned ramcfg_00_03_08:1; + unsigned ramcfg_00_03_10:1; + unsigned ramcfg_00_04_02:1; + unsigned ramcfg_00_04_04:1; + unsigned ramcfg_00_04_20:1; + unsigned ramcfg_00_05:8; + unsigned ramcfg_00_06:8; + unsigned ramcfg_00_07:8; + unsigned ramcfg_00_08:8; + unsigned ramcfg_00_09:8; + unsigned ramcfg_00_0a_0f:4; + unsigned ramcfg_00_0a_f0:4; + }; struct { unsigned ramcfg_10_02_01:1; unsigned ramcfg_10_02_02:1; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h index 609a905ec780c..2044fc911ceb9 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h @@ -15,6 +15,8 @@ u32 nvbios_rammapEm(struct nvkm_bios *, u16 mhz, u32 nvbios_rammapSe(struct nvkm_bios *, u32 data, u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr); +u32 nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx, + struct nvbios_ramcfg *p); u32 nvbios_rammapSp(struct nvkm_bios *, u32 data, u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr, struct nvbios_ramcfg *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index a688d3b4ef375..d6e4af7606ba8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -140,6 +140,35 @@ nvbios_rammapSe(struct nvkm_bios *bios, u32 data, return 0; } +u32 +nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx, + struct nvbios_ramcfg *p) +{ + data += (idx * size); + + if (size < 11) + return 0x00000000; + + p->ramcfg_timing = nv_ro08(bios, data + 0x01); + p->ramcfg_00_03_01 = (nv_ro08(bios, data + 0x03) & 0x01) >> 0; + p->ramcfg_00_03_02 = (nv_ro08(bios, data + 0x03) & 0x02) >> 1; + p->ramcfg_DLLoff = (nv_ro08(bios, data + 0x03) & 0x04) >> 2; + p->ramcfg_00_03_08 = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; + p->ramcfg_00_03_10 = (nv_ro08(bios, data + 0x03) & 0x10) >> 4; + p->ramcfg_00_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1; + p->ramcfg_00_04_04 = (nv_ro08(bios, data + 0x04) & 0x04) >> 2; + p->ramcfg_00_04_20 = (nv_ro08(bios, data + 0x04) & 0x20) >> 5; + p->ramcfg_00_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; + p->ramcfg_00_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_00_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0; + p->ramcfg_00_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0; + p->ramcfg_00_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0; + p->ramcfg_00_0a_0f = (nv_ro08(bios, data + 0x0a) & 0x0f) >> 0; + p->ramcfg_00_0a_f0 = (nv_ro08(bios, data + 0x0a) & 0xf0) >> 4; + + return data; +} + u32 nvbios_rammapSp(struct nvkm_bios *bios, u32 data, u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 67715c69e158b..37ccc4dbeaf55 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,85 @@ struct nv50_ram { struct nv50_ramseq hwsq; }; +#define T(t) cfg->timing_10_##t +static int +nv50_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) +{ + struct nv50_ram *ram = (void *)pfb->ram; + struct nvbios_ramcfg *cfg = &ram->base.target.bios; + u32 cur2, cur3, cur4, cur7, cur8; + u8 unkt3b; + + cur2 = nv_rd32(pfb, 0x100228); + cur3 = nv_rd32(pfb, 0x10022c); + cur4 = nv_rd32(pfb, 0x100230); + cur7 = nv_rd32(pfb, 0x10023c); + cur8 = nv_rd32(pfb, 0x100240); + + switch ((!T(CWL)) * ram->base.type) { + case NV_MEM_TYPE_DDR2: + T(CWL) = T(CL) - 1; + break; + case NV_MEM_TYPE_GDDR3: + T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; + break; + } + + /* XXX: N=1 is not proper statistics */ + if (nv_device(pfb)->chipset == 0xa0) { + unkt3b = 0x19 + ram->base.next->bios.rammap_00_16_40; + timing[6] = (0x2d + T(CL) - T(CWL) + + ram->base.next->bios.rammap_00_16_40) << 16 | + T(CWL) << 8 | + (0x2f + T(CL) - T(CWL)); + } else { + unkt3b = 0x16; + timing[6] = (0x2b + T(CL) - T(CWL)) << 16 | + max_t(s8, T(CWL) - 2, 1) << 8 | + (0x2e + T(CL) - T(CWL)); + } + + timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC)); + timing[1] = (T(WR) + 1 + T(CWL)) << 24 | + max_t(u8, T(18), 1) << 16 | + (T(WTR) + 1 + T(CWL)) << 8 | + (3 + T(CL) - T(CWL)); + timing[2] = (T(CWL) - 1) << 24 | + (T(RRD) << 16) | + (T(RCDWR) << 8) | + T(RCDRD); + timing[3] = (unkt3b - 2 + T(CL)) << 24 | + unkt3b << 16 | + (T(CL) - 1) << 8 | + (T(CL) - 1); + timing[4] = (cur4 & 0xffff0000) | + T(13) << 8 | + T(13); + timing[5] = T(RFC) << 24 | + max_t(u8, T(RCDRD), T(RCDWR)) << 16 | + T(RP); + /* Timing 6 is already done above */ + timing[7] = (cur7 & 0xff00ffff) | (T(CL) - 1) << 16; + timing[8] = (cur8 & 0xffffff00); + + /* XXX: P.version == 1 only has DDR2 and GDDR3? */ + if (pfb->ram->type == NV_MEM_TYPE_DDR2) { + timing[5] |= (T(CL) + 3) << 8; + timing[8] |= (T(CL) - 4); + } else if (pfb->ram->type == NV_MEM_TYPE_GDDR3) { + timing[5] |= (T(CL) + 2) << 8; + timing[8] |= (T(CL) - 2); + } + + nv_debug(pfb, " 220: %08x %08x %08x %08x\n", + timing[0], timing[1], timing[2], timing[3]); + nv_debug(pfb, " 230: %08x %08x %08x %08x\n", + timing[4], timing[5], timing[6], timing[7]); + nv_debug(pfb, " 240: %08x\n", timing[8]); + return 0; +} +#undef T + #define QFX5800NVA0 1 static int @@ -65,22 +145,25 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) struct nv50_ramseq *hwsq = &ram->hwsq; struct nvbios_perfE perfE; struct nvbios_pll mpll; - struct { - u32 data; - u8 size; - } ramcfg, timing; - u8 ver, hdr, cnt, len, strap; + struct nvkm_ram_data *next; + u8 ver, hdr, cnt, len, strap, size; + u32 data; u32 r100da0; int N1, M1, N2, M2, P; int ret, i; + u32 timing[9]; + + next = &ram->base.target; + next->freq = freq; + ram->base.next = next; /* lookup closest matching performance table entry for frequency */ i = 0; do { - ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, - &ramcfg.size, &perfE); - if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) || - (ramcfg.size < 2)) { + data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, + &size, &perfE); + if (!data || (ver < 0x25 || ver >= 0x40) || + (size < 2)) { nv_error(pfb, "invalid/missing perftab entry\n"); return -EINVAL; } @@ -93,23 +176,48 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) return -EINVAL; } - ramcfg.data += hdr + (strap * ramcfg.size); + data = nvbios_rammapSp_from_perf(bios, data + hdr, size, strap, + &next->bios); + if (!data) { + nv_error(pfb, "invalid/missing rammap entry "); + return -EINVAL; + } /* lookup memory timings, if bios says they're present */ - strap = nv_ro08(bios, ramcfg.data + 0x01); - if (strap != 0xff) { - timing.data = nvbios_timingEe(bios, strap, &ver, &hdr, - &cnt, &len); - if (!timing.data || ver != 0x10 || hdr < 0x12) { + if (next->bios.ramcfg_timing != 0xff) { + data = nvbios_timingEp(bios, next->bios.ramcfg_timing, + &ver, &hdr, &cnt, &len, &next->bios); + if (!data || ver != 0x10 || hdr < 0x12) { nv_error(pfb, "invalid/missing timing entry " "%02x %04x %02x %02x\n", - strap, timing.data, ver, hdr); + strap, data, ver, hdr); return -EINVAL; } - } else { - timing.data = 0; } + nv50_ram_timing_calc(pfb, timing); + + ret = ram_init(hwsq, nv_subdev(pfb)); + if (ret) + return ret; + + /* Determine ram-specific MR values */ + ram->base.mr[0] = ram_rd32(hwsq, mr[0]); + ram->base.mr[1] = ram_rd32(hwsq, mr[1]); + ram->base.mr[2] = ram_rd32(hwsq, mr[2]); + + switch (ram->base.type) { + case NV_MEM_TYPE_GDDR3: + ret = nvkm_gddr3_calc(&ram->base); + break; + default: + ret = -ENOSYS; + break; + } + + if (ret) + return ret; + /* XXX: 750MHz seems rather arbitrary */ if (freq <= 750000) { r100da0 = 0x00000010; @@ -117,10 +225,6 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) r100da0 = 0x00000000; } - ret = ram_init(hwsq, nv_subdev(pfb)); - if (ret) - return ret; - ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */ ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */ ram_wr32(hwsq, 0x611200, 0x00003300); @@ -177,17 +281,15 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) break; } - ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/ - ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/ - - ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/ + ram_mask(hwsq, timing[3], 0xffffffff, timing[3]); + ram_mask(hwsq, timing[1], 0xffffffff, timing[1]); + ram_mask(hwsq, timing[6], 0xffffffff, timing[6]); + ram_mask(hwsq, timing[7], 0xffffffff, timing[7]); + ram_mask(hwsq, timing[8], 0xffffffff, timing[8]); + ram_mask(hwsq, timing[0], 0xffffffff, timing[0]); + ram_mask(hwsq, timing[2], 0xffffffff, timing[2]); + ram_mask(hwsq, timing[4], 0xffffffff, timing[4]); + ram_mask(hwsq, timing[5], 0xffffffff, timing[5]); #if QFX5800NVA0 ram_nuke(hwsq, 0x100e24); -- GitLab From 2813e19f13035e5971b6f4001782135cfc0909e0 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sat, 23 May 2015 10:37:47 +0200 Subject: [PATCH 5265/7006] drm/nouveau/bios/rammap: Parse perf mode as if it's a rammap entry Some of the bits in there are similar to the bits in the gt215 rammap. Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/bios/ramcfg.h | 5 +++++ .../drm/nouveau/include/nvkm/subdev/bios/rammap.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 15 +++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 2 ++ 4 files changed, 24 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h index f09b6bf69098c..26e233a7b4d4c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h @@ -6,6 +6,11 @@ struct nvbios_ramcfg { unsigned rammap_min; unsigned rammap_max; union { + struct { + unsigned rammap_00_16_20:1; + unsigned rammap_00_16_40:1; + unsigned rammap_00_17_02:1; + }; struct { unsigned rammap_10_04_02:1; unsigned rammap_10_04_08:1; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h index 2044fc911ceb9..8d8ee13721ec8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h @@ -7,6 +7,8 @@ u32 nvbios_rammapTe(struct nvkm_bios *, u8 *ver, u8 *hdr, u32 nvbios_rammapEe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len); +u32 nvbios_rammapEp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, + struct nvbios_ramcfg *p); u32 nvbios_rammapEp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *); u32 nvbios_rammapEm(struct nvkm_bios *, u16 mhz, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index d6e4af7606ba8..29ba85387adcf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -72,6 +72,21 @@ nvbios_rammapEe(struct nvkm_bios *bios, int idx, return 0x0000; } +/* Pretend a performance mode is also a rammap entry, helps coalesce entries + * later on */ +u32 +nvbios_rammapEp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, + struct nvbios_ramcfg *p) +{ + memset(p, 0x00, sizeof(*p)); + + p->rammap_00_16_20 = (nv_ro08(bios, data + 0x16) & 0x20) >> 5; + p->rammap_00_16_40 = (nv_ro08(bios, data + 0x16) & 0x40) >> 6; + p->rammap_00_17_02 = (nv_ro08(bios, data + 0x17) & 0x02) >> 1; + + return data; +} + u32 nvbios_rammapEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 37ccc4dbeaf55..91e9cff7a6458 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -169,6 +169,8 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) } } while (perfE.memory < freq); + nvbios_rammapEp_from_perf(bios, data, hdr, &next->bios); + /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(pfb)); if (strap >= cnt) { -- GitLab From c25bf7b6155cb1e737c39ab76c844469deed3c98 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sun, 24 May 2015 10:43:59 +0200 Subject: [PATCH 5266/7006] drm/nouveau/bios/ramcfg: Separate out RON pull value Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 3 ++- drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c | 2 ++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c | 6 ++++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h index 26e233a7b4d4c..3a9abd38aca8d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h @@ -38,6 +38,7 @@ struct nvbios_ramcfg { unsigned ramcfg_hdr; unsigned ramcfg_timing; unsigned ramcfg_DLLoff; + unsigned ramcfg_RON; union { struct { unsigned ramcfg_00_03_01:1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index 29ba85387adcf..1abd9fe4194ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -164,12 +164,13 @@ nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx, if (size < 11) return 0x00000000; + p->ramcfg_ver = 0; p->ramcfg_timing = nv_ro08(bios, data + 0x01); p->ramcfg_00_03_01 = (nv_ro08(bios, data + 0x03) & 0x01) >> 0; p->ramcfg_00_03_02 = (nv_ro08(bios, data + 0x03) & 0x02) >> 1; p->ramcfg_DLLoff = (nv_ro08(bios, data + 0x03) & 0x04) >> 2; p->ramcfg_00_03_08 = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; - p->ramcfg_00_03_10 = (nv_ro08(bios, data + 0x03) & 0x10) >> 4; + p->ramcfg_RON = (nv_ro08(bios, data + 0x03) & 0x10) >> 3; p->ramcfg_00_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1; p->ramcfg_00_04_04 = (nv_ro08(bios, data + 0x04) & 0x04) >> 2; p->ramcfg_00_04_20 = (nv_ro08(bios, data + 0x04) & 0x20) >> 5; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c index 763fd29a58f21..bacd43321826f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c @@ -102,6 +102,8 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, p->timing_10_RRD = nv_ro08(bios, data + 0x0c); p->timing_10_13 = nv_ro08(bios, data + 0x0d); p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07; + if (p->ramcfg_ver >= 0x10) + p->ramcfg_RON = nv_ro08(bios, data + 0x0e) & 0x07; p->timing_10_24 = 0xff; p->timing_10_21 = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index e1d11f709a711..8d759f8a87531 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -70,7 +70,7 @@ ramgddr3_wr_lo[] = { int nvkm_gddr3_calc(struct nvkm_ram *ram) { - int CL, WR, CWL, DLL = 0, ODT = 0, hi; + int CL, WR, CWL, DLL = 0, ODT = 0, RON, hi; switch (ram->next->bios.timing_ver) { case 0x10: @@ -79,6 +79,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) WR = ram->next->bios.timing_10_WR; DLL = !ram->next->bios.ramcfg_DLLoff; ODT = ram->next->bios.timing_10_ODT; + RON = ram->next->bios.ramcfg_RON; break; case 0x20: CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7; @@ -89,6 +90,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) ODT = (ram->mr[1] & 0x004) >> 2 | (ram->mr[1] & 0x040) >> 5 | (ram->mr[1] & 0x200) >> 7; + RON = !(ram->mr[1] & 0x300) >> 8; break; default: return -ENOSYS; @@ -107,7 +109,7 @@ nvkm_gddr3_calc(struct nvkm_ram *ram) ram->mr[1] &= ~0x3fc; ram->mr[1] |= (ODT & 0x03) << 2; - ram->mr[1] |= (ODT & 0x03) << 8; + ram->mr[1] |= (RON & 0x03) << 8; ram->mr[1] |= (WR & 0x03) << 4; ram->mr[1] |= (WR & 0x04) << 5; ram->mr[1] |= !DLL << 6; -- GitLab From 82a74fd2936afd97e83cf195c41dc372ebe9fc84 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sun, 24 May 2015 10:44:00 +0200 Subject: [PATCH 5267/7006] drm/nouveau/fb/ramnv50: GDDR3 script for NVA0 This looks surprisingly similar to scripts on earlier cards as well but they don't seem to work just yet. That... and I don't have any, which makes it a tough job to reverse engineer. Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 129 ++++++++++++++---- 1 file changed, 104 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 91e9cff7a6458..66db0a4e25386 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -39,10 +39,19 @@ struct nv50_ramseq { struct hwsq_reg r_0x004008; struct hwsq_reg r_0x00400c; struct hwsq_reg r_0x00c040; + struct hwsq_reg r_0x100200; struct hwsq_reg r_0x100210; + struct hwsq_reg r_0x10021c; struct hwsq_reg r_0x1002d0; struct hwsq_reg r_0x1002d4; struct hwsq_reg r_0x1002dc; + struct hwsq_reg r_0x10053c; + struct hwsq_reg r_0x1005a0; + struct hwsq_reg r_0x1005a4; + struct hwsq_reg r_0x100710; + struct hwsq_reg r_0x100714; + struct hwsq_reg r_0x100718; + struct hwsq_reg r_0x10071c; struct hwsq_reg r_0x100da0; struct hwsq_reg r_0x100e20; struct hwsq_reg r_0x100e24; @@ -135,7 +144,13 @@ nv50_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) } #undef T -#define QFX5800NVA0 1 +static void +nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq) +{ + ram_mask(hwsq, mr[0], 0x100, 0x100); + ram_mask(hwsq, mr[0], 0x100, 0x000); + ram_nsec(hwsq, 24000); +} static int nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) @@ -148,7 +163,7 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) struct nvkm_ram_data *next; u8 ver, hdr, cnt, len, strap, size; u32 data; - u32 r100da0; + u32 r100da0, r004008, unk710, unk714, unk718, unk71c; int N1, M1, N2, M2, P; int ret, i; u32 timing[9]; @@ -220,12 +235,8 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) if (ret) return ret; - /* XXX: 750MHz seems rather arbitrary */ - if (freq <= 750000) { - r100da0 = 0x00000010; - } else { - r100da0 = 0x00000000; - } + /* Always disable this bit during reclock */ + ram_mask(hwsq, 0x100200, 0x00000800, 0x00000000); ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */ ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */ @@ -234,6 +245,7 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_nsec(hwsq, 8000); ram_setf(hwsq, 0x10, 0x00); /* disable fb */ ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */ + ram_nsec(hwsq, 2000); ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */ ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */ @@ -253,18 +265,33 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) if (ret < 0) return ret; + /* XXX: 750MHz seems rather arbitrary */ + if (freq <= 750000) { + r100da0 = 0x00000010; + r004008 = 0x90000000; + } else { + r100da0 = 0x00000000; + r004008 = 0x80000000; + } + + r004008 |= (mpll.bias_p << 19) | (P << 22) | (P << 16); + ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000); - ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200); + /* XXX: Is rammap_00_16_40 the DLL bit we've seen in GT215? Why does + * it have a different rammap bit from DLLoff? */ + ram_mask(hwsq, 0x004008, 0x00004200, 0x00000200 | + next->bios.rammap_00_16_40 << 14); ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); - ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) | - (P << 22) | (P << 16)); + ram_mask(hwsq, 0x004008, 0x91ff0000, r004008); + if (nv_device(pfb)->chipset >= 0x96) + ram_wr32(hwsq, 0x100da0, r100da0); + ram_nsec(hwsq, 64000); /*XXX*/ + ram_nsec(hwsq, 32000); /*XXX*/ - if (nv_device(pfb)->chipset == 0xa0) - ram_wr32(hwsq, 0x100da0, r100da0); /*XXX: here?*/ - ram_nsec(hwsq, 96000); /*XXX*/ ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000); ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */ + ram_wr32(hwsq, 0x1002d4, 0x00000001); /* disable self-refresh */ ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */ ram_nsec(hwsq, 12000); @@ -275,9 +302,10 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_mask(hwsq, mr[0], 0x000, 0x000); break; case NV_MEM_TYPE_GDDR3: - ram_mask(hwsq, mr[2], 0x000, 0x000); + ram_nuke(hwsq, mr[1]); /* force update */ + ram_wr32(hwsq, mr[1], ram->base.mr[1]); ram_nuke(hwsq, mr[0]); /* force update */ - ram_mask(hwsq, mr[0], 0x000, 0x000); + ram_wr32(hwsq, mr[0], ram->base.mr[0]); break; default: break; @@ -293,20 +321,62 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_mask(hwsq, timing[4], 0xffffffff, timing[4]); ram_mask(hwsq, timing[5], 0xffffffff, timing[5]); -#if QFX5800NVA0 - ram_nuke(hwsq, 0x100e24); - ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000); - ram_nuke(hwsq, 0x100e20); - ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000); -#endif + if (!next->bios.ramcfg_00_03_02) + ram_mask(hwsq, 0x10021c, 0x00010000, 0x00000000); + ram_mask(hwsq, 0x100200, 0x00001000, !next->bios.ramcfg_00_04_02 << 12); + + /* XXX: A lot of this could be "chipset"/"ram type" specific stuff */ + unk710 = ram_rd32(hwsq, 0x100710) & ~0x00000101; + unk714 = ram_rd32(hwsq, 0x100714) & ~0xf0000020; + unk718 = ram_rd32(hwsq, 0x100718) & ~0x00000100; + unk71c = ram_rd32(hwsq, 0x10071c) & ~0x00000100; + + if ( next->bios.ramcfg_00_03_01) + unk71c |= 0x00000100; + if ( next->bios.ramcfg_00_03_02) + unk710 |= 0x00000100; + if (!next->bios.ramcfg_00_03_08) { + unk710 |= 0x1; + unk714 |= 0x20; + } + if ( next->bios.ramcfg_00_04_04) + unk714 |= 0x70000000; + if ( next->bios.ramcfg_00_04_20) + unk718 |= 0x00000100; + + ram_mask(hwsq, 0x100714, 0xffffffff, unk714); + ram_mask(hwsq, 0x10071c, 0xffffffff, unk71c); + ram_mask(hwsq, 0x100718, 0xffffffff, unk718); + ram_mask(hwsq, 0x100710, 0xffffffff, unk710); + + if (next->bios.rammap_00_16_20) { + ram_wr32(hwsq, 0x1005a0, next->bios.ramcfg_00_07 << 16 | + next->bios.ramcfg_00_06 << 8 | + next->bios.ramcfg_00_05); + ram_wr32(hwsq, 0x1005a4, next->bios.ramcfg_00_09 << 8 | + next->bios.ramcfg_00_08); + ram_mask(hwsq, 0x10053c, 0x00001000, 0x00000000); + } else { + ram_mask(hwsq, 0x10053c, 0x00001000, 0x00001000); + } + ram_mask(hwsq, mr[1], 0xffffffff, ram->base.mr[1]); - ram_mask(hwsq, mr[0], 0x100, 0x100); - ram_mask(hwsq, mr[0], 0x100, 0x000); + /* Reset DLL */ + if (!next->bios.ramcfg_DLLoff) + nvkm_sddr2_dll_reset(hwsq); ram_setf(hwsq, 0x10, 0x01); /* enable fb */ ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */ ram_wr32(hwsq, 0x611200, 0x00003330); ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */ + + if (next->bios.rammap_00_17_02) + ram_mask(hwsq, 0x100200, 0x00000800, 0x00000800); + if (!next->bios.rammap_00_16_40) + ram_mask(hwsq, 0x004008, 0x00004000, 0x00000000); + if (next->bios.ramcfg_00_03_02) + ram_mask(hwsq, 0x10021c, 0x00010000, 0x00010000); + return 0; } @@ -522,12 +592,12 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: case NV_MEM_TYPE_GDDR3: ram->base.calc = nv50_ram_calc; ram->base.prog = nv50_ram_prog; ram->base.tidy = nv50_ram_tidy; break; + case NV_MEM_TYPE_DDR2: default: nv_warn(ram, "reclocking of this ram type unsupported\n"); return 0; @@ -537,10 +607,19 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040); ram->hwsq.r_0x004008 = hwsq_reg(0x004008); ram->hwsq.r_0x00400c = hwsq_reg(0x00400c); + ram->hwsq.r_0x100200 = hwsq_reg(0x100200); ram->hwsq.r_0x100210 = hwsq_reg(0x100210); + ram->hwsq.r_0x10021c = hwsq_reg(0x10021c); ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0); ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4); ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc); + ram->hwsq.r_0x10053c = hwsq_reg(0x10053c); + ram->hwsq.r_0x1005a0 = hwsq_reg(0x1005a0); + ram->hwsq.r_0x1005a4 = hwsq_reg(0x1005a4); + ram->hwsq.r_0x100710 = hwsq_reg(0x100710); + ram->hwsq.r_0x100714 = hwsq_reg(0x100714); + ram->hwsq.r_0x100718 = hwsq_reg(0x100718); + ram->hwsq.r_0x10071c = hwsq_reg(0x10071c); ram->hwsq.r_0x100da0 = hwsq_stride(0x100da0, 4, ram->base.part_mask); ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20); ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24); -- GitLab From 852c619b6e6e33509b405a5ad7400255e02ba8ec Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sun, 24 May 2015 10:44:01 +0200 Subject: [PATCH 5268/7006] drm/nouveau/fb/gddr3: Add a few CL and WR entries observed on GTX260 Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index 8d759f8a87531..4465446c80639 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -42,9 +42,9 @@ ramxlat(const struct ramxlat *xlat, int id) static const struct ramxlat ramgddr3_cl_lo[] = { - { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 }, + { 5, 5 }, { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 }, { 12, 8 }, /* the below are mentioned in some, but not all, gddr3 docs */ - { 12, 4 }, { 13, 5 }, { 14, 6 }, + { 13, 9 }, { 14, 6 }, /* XXX: Per Samsung docs, are these used? They overlap with Qimonda */ /* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 }, * { 15, 11 }, */ @@ -61,9 +61,9 @@ ramgddr3_cl_hi[] = { static const struct ramxlat ramgddr3_wr_lo[] = { { 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 }, - { 11, 0 }, + { 11, 0 }, { 13 , 1 }, /* the below are mentioned in some, but not all, gddr3 docs */ - { 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 }, + { 4, 1 }, { 6, 3 }, { 12, 1 }, { -1 } }; -- GitLab From 087cd0db87a79b03d35567a32d4a29bee179ad9e Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Sun, 24 May 2015 10:44:02 +0200 Subject: [PATCH 5269/7006] drm/nouveau/clk/nv50: Enable user reclocking for NVA0 Tested on a few cards. Probably works quite well for most, given they should all be GDDR3. Signed-off-by: Roy Spliet Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 9b4ffd6347ce2..89c5d886f2adf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -509,7 +509,8 @@ nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int ret; ret = nvkm_clk_create(parent, engine, oclass, pclass->domains, - NULL, 0, false, &priv); + NULL, 0, nv_device(parent)->chipset == 0xa0, + &priv); *pobject = nv_object(priv); if (ret) return ret; -- GitLab From 0b7515c035d26faee91b6c3023622385c109b99e Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:13 +0200 Subject: [PATCH 5270/7006] drm/nouveau/pm: remove pmu signals PDAEMON signals don't have to be exposed by the perfmon engine. Signed-off-by: Samuel Pitoiset Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 4 - drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild | 1 - .../gpu/drm/nouveau/nvkm/engine/pm/daemon.c | 108 ------------------ .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 5 - .../gpu/drm/nouveau/nvkm/engine/pm/gk104.c | 6 - .../gpu/drm/nouveau/nvkm/engine/pm/gk110.c | 4 - .../gpu/drm/nouveau/nvkm/engine/pm/gt215.c | 20 +--- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 4 - 8 files changed, 1 insertion(+), 151 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index 93181bbf0f63d..6c2d0578400a0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -12,10 +12,6 @@ struct nvkm_pm { struct list_head domains; u32 sequence; - - /*XXX: temp for daemon backend */ - u32 pwr[8]; - u32 last; }; static inline struct nvkm_pm * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild index 413b6091e2565..c5ee8d566b0d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild @@ -1,5 +1,4 @@ nvkm-y += nvkm/engine/pm/base.o -nvkm-y += nvkm/engine/pm/daemon.o nvkm-y += nvkm/engine/pm/nv40.o nvkm-y += nvkm/engine/pm/nv50.o nvkm-y += nvkm/engine/pm/g84.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c deleted file mode 100644 index a7a5f3a3c91bf..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright 2013 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -static void -pwr_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, - struct nvkm_perfctr *ctr) -{ - u32 mask = 0x00000000; - u32 ctrl = 0x00000001; - int i; - - for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++) - mask |= 1 << (ctr->signal[i] - dom->signal); - - nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask); - nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl); - nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003); -} - -static void -pwr_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, - struct nvkm_perfctr *ctr) -{ - ctr->ctr = ppm->pwr[ctr->slot]; - ctr->clk = ppm->pwr[ppm->last]; -} - -static void -pwr_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom) -{ - int i; - - for (i = 0; i <= ppm->last; i++) { - ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10)); - nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000); - } -} - -static const struct nvkm_funcdom -pwr_perfctr_func = { - .init = pwr_perfctr_init, - .read = pwr_perfctr_read, - .next = pwr_perfctr_next, -}; - -const struct nvkm_specdom -gt215_pm_pwr[] = { - { 0x20, (const struct nvkm_specsig[]) { - { 0x00, "pwr_gr_idle" }, - { 0x04, "pwr_bsp_idle" }, - { 0x05, "pwr_vp_idle" }, - { 0x06, "pwr_ppp_idle" }, - { 0x13, "pwr_ce0_idle" }, - {} - }, &pwr_perfctr_func }, - {} -}; - -const struct nvkm_specdom -gf100_pm_pwr[] = { - { 0x20, (const struct nvkm_specsig[]) { - { 0x00, "pwr_gr_idle" }, - { 0x04, "pwr_bsp_idle" }, - { 0x05, "pwr_vp_idle" }, - { 0x06, "pwr_ppp_idle" }, - { 0x13, "pwr_ce0_idle" }, - { 0x14, "pwr_ce1_idle" }, - {} - }, &pwr_perfctr_func }, - {} -}; - -const struct nvkm_specdom -gk104_pm_pwr[] = { - { 0x20, (const struct nvkm_specsig[]) { - { 0x00, "pwr_gr_idle" }, - { 0x04, "pwr_bsp_idle" }, - { 0x05, "pwr_vp_idle" }, - { 0x06, "pwr_ppp_idle" }, - { 0x13, "pwr_ce0_idle" }, - { 0x14, "pwr_ce1_idle" }, - { 0x15, "pwr_ce2_idle" }, - {} - }, &pwr_perfctr_func }, - {} -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 008fed73dd82d..69303b5dbcbcf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -111,10 +111,6 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gf100_pm_pwr); - if (ret) - return ret; - /* HUB */ ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, gf100_pm_hub); @@ -143,7 +139,6 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_engine(priv)->cclass = &nvkm_pm_cclass; nv_engine(priv)->sclass = nvkm_pm_sclass; - priv->base.last = 7; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c index 75b9ff3d1a2c2..3565f292984f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c @@ -99,11 +99,6 @@ gk104_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - /* PDAEMON */ - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr); - if (ret) - return ret; - /* HUB */ ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, gk104_pm_hub); @@ -132,7 +127,6 @@ gk104_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_engine(priv)->cclass = &nvkm_pm_cclass; nv_engine(priv)->sclass = nvkm_pm_sclass; - priv->base.last = 7; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c index 6820176e5f78a..8373cd87a7d6a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c @@ -36,10 +36,6 @@ gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr); - if (ret) - return ret; - nv_engine(priv)->cclass = &nvkm_pm_cclass; nv_engine(priv)->sclass = nvkm_pm_sclass; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c index d065bfc59bbfe..ab69ab5dfc290 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c @@ -52,29 +52,11 @@ gt215_pm[] = { {} }; -static int -gt215_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **object) -{ - int ret = nv40_pm_ctor(parent, engine, oclass, data, size, object); - if (ret == 0) { - struct nv40_pm_priv *priv = (void *)*object; - ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, - gt215_pm_pwr); - if (ret) - return ret; - - priv->base.last = 3; - } - return ret; -} - struct nvkm_oclass * gt215_pm_oclass = &(struct nv40_pm_oclass) { .base.handle = NV_ENGINE(PM, 0xa3), .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_pm_ctor, + .ctor = nv40_pm_ctor, .dtor = _nvkm_pm_dtor, .init = _nvkm_pm_init, .fini = _nvkm_pm_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 1e6eff2a6d79c..95796c7504ac0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -41,10 +41,6 @@ struct nvkm_specdom { const struct nvkm_funcdom *func; }; -extern const struct nvkm_specdom gt215_pm_pwr[]; -extern const struct nvkm_specdom gf100_pm_pwr[]; -extern const struct nvkm_specdom gk104_pm_pwr[]; - struct nvkm_perfdom { struct list_head head; struct list_head list; -- GitLab From a78ce96f96d76311fd165207a6ffb64b0ebd85cc Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:14 +0200 Subject: [PATCH 5271/7006] drm/nouveau/pm: remove unused nvkm_perfsig_wrap() function Signed-off-by: Samuel Pitoiset Reviewed-by: Martin Peres Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 20 ------------------- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 4 ---- 2 files changed, 24 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 4cf36a3aa8146..7b07e8b04052b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -79,26 +79,6 @@ nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size, return nvkm_perfsig_find_(dom, name, size); } -struct nvkm_perfctr * -nvkm_perfsig_wrap(struct nvkm_pm *ppm, const char *name, - struct nvkm_perfdom **pdom) -{ - struct nvkm_perfsig *sig; - struct nvkm_perfctr *ctr; - - sig = nvkm_perfsig_find(ppm, name, strlen(name), pdom); - if (!sig) - return NULL; - - ctr = kzalloc(sizeof(*ctr), GFP_KERNEL); - if (ctr) { - ctr->signal[0] = sig; - ctr->logic_op = 0xaaaa; - } - - return ctr; -} - /******************************************************************************* * Perfmon object classes ******************************************************************************/ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 95796c7504ac0..06a6e60856ff4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -31,10 +31,6 @@ struct nvkm_perfsig { const char *name; }; -struct nvkm_perfdom; -struct nvkm_perfctr * -nvkm_perfsig_wrap(struct nvkm_pm *, const char *, struct nvkm_perfdom **); - struct nvkm_specdom { u16 signal_nr; const struct nvkm_specsig *signal; -- GitLab From 5a0bc4b5aeba3bb32eb7da6a98108e93bbd64f7e Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:15 +0200 Subject: [PATCH 5272/7006] drm/nouveau/pm: reorganize the nvif interface This commit introduces the NVIF_IOCTL_NEW_V0_PERFMON class which will be used in order to query domains, signals and sources. This separates the querying and the counting interface. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 26 ++++++++----- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 5 ++- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 38 ++++++++++++++++--- 3 files changed, 51 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 64f8b2f687d29..11935a048744c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -251,6 +251,20 @@ struct gf110_dma_v0 { * perfmon ******************************************************************************/ +#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x00 + +struct nvif_perfmon_query_signal_v0 { + __u8 version; + __u8 pad01[3]; + __u32 iter; + char name[64]; +}; + + +/******************************************************************************* + * perfctr + ******************************************************************************/ + struct nvif_perfctr_v0 { __u8 version; __u8 pad01[1]; @@ -259,16 +273,8 @@ struct nvif_perfctr_v0 { char name[4][64]; }; -#define NVIF_PERFCTR_V0_QUERY 0x00 -#define NVIF_PERFCTR_V0_SAMPLE 0x01 -#define NVIF_PERFCTR_V0_READ 0x02 - -struct nvif_perfctr_query_v0 { - __u8 version; - __u8 pad01[3]; - __u32 iter; - char name[64]; -}; +#define NVIF_PERFCTR_V0_SAMPLE 0x00 +#define NVIF_PERFCTR_V0_READ 0x01 struct nvif_perfctr_sample { }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 4cd8e323b23d7..517cd27cdc377 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -49,8 +49,9 @@ struct nvif_ioctl_new_v0 { __u64 token; __u32 handle; /* these class numbers are made up by us, and not nvidia-assigned */ -#define NVIF_IOCTL_NEW_V0_PERFCTR 0x0000ffff -#define NVIF_IOCTL_NEW_V0_CONTROL 0x0000fffe +#define NVIF_IOCTL_NEW_V0_PERFMON 0x0000ffff +#define NVIF_IOCTL_NEW_V0_PERFCTR 0x0000fffe +#define NVIF_IOCTL_NEW_V0_CONTROL 0x0000fffd __u32 oclass; __u8 data[]; /* class data (class.h) */ }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 7b07e8b04052b..cb88170610bbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -83,10 +83,10 @@ nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size, * Perfmon object classes ******************************************************************************/ static int -nvkm_perfctr_query(struct nvkm_object *object, void *data, u32 size) +nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) { union { - struct nvif_perfctr_query_v0 v0; + struct nvif_perfmon_query_signal_v0 v0; } *args = data; struct nvkm_device *device = nv_device(object); struct nvkm_pm *ppm = (void *)object->engine; @@ -97,9 +97,9 @@ nvkm_perfctr_query(struct nvkm_object *object, void *data, u32 size) int tmp = 0, di, si; int ret; - nv_ioctl(object, "perfctr query size %d\n", size); + nv_ioctl(object, "perfmon query signal size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfctr query vers %d iter %08x\n", + nv_ioctl(object, "perfmon query signal vers %d iter %08x\n", args->v0.version, args->v0.iter); di = (args->v0.iter & 0xff000000) >> 24; si = (args->v0.iter & 0x00ffffff) - 1; @@ -141,6 +141,30 @@ nvkm_perfctr_query(struct nvkm_object *object, void *data, u32 size) return 0; } +static int +nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + switch (mthd) { + case NVIF_PERFMON_V0_QUERY_SIGNAL: + return nvkm_perfmon_mthd_query_signal(object, data, size); + default: + break; + } + return -EINVAL; +} + +static struct nvkm_ofuncs +nvkm_perfmon_ofuncs = { + .ctor = _nvkm_object_ctor, + .dtor = nvkm_object_destroy, + .init = nvkm_object_init, + .fini = nvkm_object_fini, + .mthd = nvkm_perfmon_mthd, +}; + +/******************************************************************************* + * Perfctr object classes + ******************************************************************************/ static int nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) { @@ -221,8 +245,6 @@ static int nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { - case NVIF_PERFCTR_V0_QUERY: - return nvkm_perfctr_query(object, data, size); case NVIF_PERFCTR_V0_SAMPLE: return nvkm_perfctr_sample(object, data, size); case NVIF_PERFCTR_V0_READ: @@ -299,6 +321,10 @@ nvkm_perfctr_ofuncs = { struct nvkm_oclass nvkm_pm_sclass[] = { + { + .handle = NVIF_IOCTL_NEW_V0_PERFMON, + .ofuncs = &nvkm_perfmon_ofuncs, + }, { .handle = NVIF_IOCTL_NEW_V0_PERFCTR, .ofuncs = &nvkm_perfctr_ofuncs, }, -- GitLab From 44d9de58ea5633e4f2d062e718016383b28b4eed Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:16 +0200 Subject: [PATCH 5273/7006] drm/nouveau/pm: prevent creating a perfctr object when signals are not found Since a new class has been introduced to query signals, we can now return an error when the userspace wants to monitor unknown signals. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index cb88170610bbb..2f851473cecfd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -294,6 +294,9 @@ nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } + if (!dom) + return -EINVAL; + ret = nvkm_object_create(parent, engine, oclass, 0, &ctr); *pobject = nv_object(ctr); if (ret) @@ -305,8 +308,7 @@ nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ctr->signal[1] = sig[1]; ctr->signal[2] = sig[2]; ctr->signal[3] = sig[3]; - if (dom) - list_add_tail(&ctr->head, &dom->list); + list_add_tail(&ctr->head, &dom->list); return 0; } -- GitLab From 45f0f94db285009a41a94e069618ea9bb269af84 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:17 +0200 Subject: [PATCH 5274/7006] drm/nouveau/pm: implement NVIF_PERFMON_V0_QUERY_DOMAIN method This allows to query the number of available domains, including the number of hardware counter and the number of signals per domain. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 11 ++- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 86 +++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 11935a048744c..0b28929f5be6c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -251,7 +251,16 @@ struct gf110_dma_v0 { * perfmon ******************************************************************************/ -#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x00 +#define NVIF_PERFMON_V0_QUERY_DOMAIN 0x00 +#define NVIF_PERFMON_V0_QUERY_SIGNAL 0x01 + +struct nvif_perfmon_query_domain_v0 { + __u8 version; + __u8 id; + __u8 counter_nr; + __u8 iter; + __u32 signal_nr; +}; struct nvif_perfmon_query_signal_v0 { __u8 version; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 2f851473cecfd..3d9bcbc1064c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -34,6 +34,45 @@ #define QUAD_MASK 0x0f #define QUAD_FREE 0x01 +static u8 +nvkm_pm_count_perfdom(struct nvkm_pm *ppm) +{ + struct nvkm_perfdom *dom; + u8 domain_nr = 0; + + list_for_each_entry(dom, &ppm->domains, head) + domain_nr++; + return domain_nr; +} + +static u32 +nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom) +{ + u32 signal_nr = 0; + int i; + + if (dom) { + for (i = 0; i < dom->signal_nr; i++) { + if (dom->signal[i].name) + signal_nr++; + } + } + return signal_nr; +} + +static struct nvkm_perfdom * +nvkm_perfdom_find(struct nvkm_pm *ppm, int di) +{ + struct nvkm_perfdom *dom; + int tmp = 0; + + list_for_each_entry(dom, &ppm->domains, head) { + if (tmp++ == di) + return dom; + } + return NULL; +} + static struct nvkm_perfsig * nvkm_perfsig_find_(struct nvkm_perfdom *dom, const char *name, u32 size) { @@ -82,6 +121,51 @@ nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size, /******************************************************************************* * Perfmon object classes ******************************************************************************/ +static int +nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfmon_query_domain_v0 v0; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom; + u8 domain_nr; + int di, ret; + + nv_ioctl(object, "perfmon query domain size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "perfmon domain vers %d iter %02x\n", + args->v0.version, args->v0.iter); + di = (args->v0.iter & 0xff) - 1; + } else + return ret; + + domain_nr = nvkm_pm_count_perfdom(ppm); + if (di >= (int)domain_nr) + return -EINVAL; + + if (di >= 0) { + dom = nvkm_perfdom_find(ppm, di); + if (dom == NULL) + return -EINVAL; + + args->v0.id = di; + args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); + + /* Currently only global counters (PCOUNTER) are implemented + * but this will be different for local counters (MP). */ + args->v0.counter_nr = 4; + } + + if (++di < domain_nr) { + args->v0.iter = ++di; + return 0; + } + + args->v0.iter = 0xff; + return 0; +} + static int nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) { @@ -145,6 +229,8 @@ static int nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { + case NVIF_PERFMON_V0_QUERY_DOMAIN: + return nvkm_perfmon_mthd_query_domain(object, data, size); case NVIF_PERFMON_V0_QUERY_SIGNAL: return nvkm_perfmon_mthd_query_signal(object, data, size); default: -- GitLab From 3e1b33571ab4937cbd400976a115e4922797559a Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:18 +0200 Subject: [PATCH 5275/7006] drm/nouveau/pm: allow to query signals by domain This will allow to configure performance counters with hardware signal indexes instead of user-readable names in an upcoming patch. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 36 +++++++------------ 2 files changed, 14 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 0b28929f5be6c..cf2af89b71124 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -264,7 +264,8 @@ struct nvif_perfmon_query_domain_v0 { struct nvif_perfmon_query_signal_v0 { __u8 version; - __u8 pad01[3]; + __u8 domain; + __u8 pad02[2]; __u32 iter; char name[64]; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 3d9bcbc1064c5..d61beffd2404e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -174,29 +174,22 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) } *args = data; struct nvkm_device *device = nv_device(object); struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfdom *dom = NULL, *chk; + struct nvkm_perfdom *dom; const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); const char *name; - int tmp = 0, di, si; - int ret; + int ret, si; nv_ioctl(object, "perfmon query signal size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfmon query signal vers %d iter %08x\n", - args->v0.version, args->v0.iter); - di = (args->v0.iter & 0xff000000) >> 24; - si = (args->v0.iter & 0x00ffffff) - 1; + nv_ioctl(object, + "perfmon query signal vers %d dom %d iter %08x\n", + args->v0.version, args->v0.domain, args->v0.iter); + si = (args->v0.iter & 0xffffffff) - 1; } else return ret; - list_for_each_entry(chk, &ppm->domains, head) { - if (tmp++ == di) { - dom = chk; - break; - } - } - + dom = nvkm_perfdom_find(ppm, args->v0.domain); if (dom == NULL || si >= (int)dom->signal_nr) return -EINVAL; @@ -209,17 +202,12 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) } } - do { - while (++si < dom->signal_nr) { - if (all || dom->signal[si].name) { - args->v0.iter = (di << 24) | ++si; - return 0; - } + while (++si < dom->signal_nr) { + if (all || dom->signal[si].name) { + args->v0.iter = ++si; + return 0; } - si = -1; - di = di + 1; - dom = list_entry(dom->head.next, typeof(*dom), head); - } while (&dom->head != &ppm->domains); + } args->v0.iter = 0xffffffff; return 0; -- GitLab From e4047599aede7a7aca97ace770002c4e29e403d2 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:19 +0200 Subject: [PATCH 5276/7006] drm/nouveau/pm: change signal iter to u16 16 bits is large enough to store the maximum number of signals available for one domain (i.e. 256). Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 7 ++++--- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index cf2af89b71124..871247c654a6c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -259,14 +259,15 @@ struct nvif_perfmon_query_domain_v0 { __u8 id; __u8 counter_nr; __u8 iter; - __u32 signal_nr; + __u16 signal_nr; + __u8 pad05[2]; }; struct nvif_perfmon_query_signal_v0 { __u8 version; __u8 domain; - __u8 pad02[2]; - __u32 iter; + __u16 iter; + __u8 pad03[4]; char name[64]; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index d61beffd2404e..fab05985ba40a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -45,10 +45,10 @@ nvkm_pm_count_perfdom(struct nvkm_pm *ppm) return domain_nr; } -static u32 +static u16 nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom) { - u32 signal_nr = 0; + u16 signal_nr = 0; int i; if (dom) { @@ -183,9 +183,9 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) nv_ioctl(object, "perfmon query signal size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(object, - "perfmon query signal vers %d dom %d iter %08x\n", + "perfmon query signal vers %d dom %d iter %04x\n", args->v0.version, args->v0.domain, args->v0.iter); - si = (args->v0.iter & 0xffffffff) - 1; + si = (args->v0.iter & 0xffff) - 1; } else return ret; @@ -209,7 +209,7 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) } } - args->v0.iter = 0xffffffff; + args->v0.iter = 0xffff; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 06a6e60856ff4..71667fcbd9de2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -44,7 +44,7 @@ struct nvkm_perfdom { char name[32]; u32 addr; u8 quad; - u32 signal_nr; + u16 signal_nr; struct nvkm_perfsig signal[]; }; -- GitLab From 10a4d2b2489394e32f17afc6cc63ccdfc1b6050b Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:20 +0200 Subject: [PATCH 5277/7006] drm/nouveau/pm: use hardware signals indexes instead of user-readable names Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 11 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 52 +++++-------------- 2 files changed, 19 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 871247c654a6c..9e4db3aaada7d 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -267,7 +267,8 @@ struct nvif_perfmon_query_signal_v0 { __u8 version; __u8 domain; __u16 iter; - __u8 pad03[4]; + __u8 signal; + __u8 pad04[3]; char name[64]; }; @@ -278,10 +279,12 @@ struct nvif_perfmon_query_signal_v0 { struct nvif_perfctr_v0 { __u8 version; - __u8 pad01[1]; + __u8 domain; + __u8 pad02[2]; __u16 logic_op; - __u8 pad04[4]; - char name[4][64]; + __u8 pad04[2]; + __u8 signal[4]; + __u8 pad06[4]; }; #define NVIF_PERFCTR_V0_SAMPLE 0x00 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index fab05985ba40a..71834b96ca9ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -73,49 +73,22 @@ nvkm_perfdom_find(struct nvkm_pm *ppm, int di) return NULL; } -static struct nvkm_perfsig * -nvkm_perfsig_find_(struct nvkm_perfdom *dom, const char *name, u32 size) -{ - char path[64]; - int i; - - if (name[0] != '/') { - for (i = 0; i < dom->signal_nr; i++) { - if ( dom->signal[i].name && - !strncmp(name, dom->signal[i].name, size)) - return &dom->signal[i]; - } - } else { - for (i = 0; i < dom->signal_nr; i++) { - snprintf(path, sizeof(path), "/%s/%02x", dom->name, i); - if (!strncmp(name, path, size)) - return &dom->signal[i]; - } - } - - return NULL; -} - struct nvkm_perfsig * -nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size, +nvkm_perfsig_find(struct nvkm_pm *ppm, uint8_t di, uint8_t si, struct nvkm_perfdom **pdom) { struct nvkm_perfdom *dom = *pdom; - struct nvkm_perfsig *sig; if (dom == NULL) { - list_for_each_entry(dom, &ppm->domains, head) { - sig = nvkm_perfsig_find_(dom, name, size); - if (sig) { - *pdom = dom; - return sig; - } - } - - return NULL; + dom = nvkm_perfdom_find(ppm, di); + if (dom == NULL) + return NULL; + *pdom = dom; } - return nvkm_perfsig_find_(dom, name, size); + if (!dom->signal[si].name) + return NULL; + return &dom->signal[si]; } /******************************************************************************* @@ -200,6 +173,7 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) } else { strncpy(args->v0.name, name, sizeof(args->v0.name)); } + args->v0.signal = si; } while (++si < dom->signal_nr) { @@ -359,11 +333,9 @@ nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } else return ret; - for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) { - sig[i] = nvkm_perfsig_find(ppm, args->v0.name[i], - strnlen(args->v0.name[i], - sizeof(args->v0.name[i])), - &dom); + for (i = 0; i < ARRAY_SIZE(args->v0.signal) && args->v0.signal[i]; i++) { + sig[i] = nvkm_perfsig_find(ppm, args->v0.domain, + args->v0.signal[i], &dom); if (!sig[i]) return -EINVAL; } -- GitLab From 40a3b22c92ac3dad5adc818a84671bfb00303731 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:21 +0200 Subject: [PATCH 5278/7006] drm/nouveau/pm: allow to monitor hardware signal index 0x00 This signal index must be always allowed even if it's not clearly defined in a domain in order to monitor a counter like 0x03020100 because it's the default value of signals. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 6 ++++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 6 ++++-- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 71834b96ca9ef..610c0ca5c80b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -333,10 +333,10 @@ nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } else return ret; - for (i = 0; i < ARRAY_SIZE(args->v0.signal) && args->v0.signal[i]; i++) { + for (i = 0; i < ARRAY_SIZE(args->v0.signal); i++) { sig[i] = nvkm_perfsig_find(ppm, args->v0.domain, args->v0.signal[i], &dom); - if (!sig[i]) + if (args->v0.signal[i] && !sig[i]) return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 69303b5dbcbcf..41350d6199a57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -48,8 +48,10 @@ gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, u32 src = 0x00000000; int i; - for (i = 0; i < 4 && ctr->signal[i]; i++) - src |= (ctr->signal[i] - dom->signal) << (i * 8); + for (i = 0; i < 4; i++) { + if (ctr->signal[i]) + src |= (ctr->signal[i] - dom->signal) << (i * 8); + } nv_wr32(priv, dom->addr + 0x09c, 0x00040002); nv_wr32(priv, dom->addr + 0x100, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index ff22f06b22b8e..603874ec0fbac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -33,8 +33,10 @@ nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, u32 src = 0x00000000; int i; - for (i = 0; i < 4 && ctr->signal[i]; i++) - src |= (ctr->signal[i] - dom->signal) << (i * 8); + for (i = 0; i < 4; i++) { + if (ctr->signal[i]) + src |= (ctr->signal[i] - dom->signal) << (i * 8); + } nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001); nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); -- GitLab From e82661e23c60fc41424ca138820d729d8e4a2226 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:22 +0200 Subject: [PATCH 5279/7006] drm/nouveau/pm: add concept of sources A source (or multiplexer) is a tuple addr+mask+shift which allows to control a block of signals. The maximum number of sources that a signal can define is arbitrary limited to 8 and this should be large enough. This patch allows to define multi-level of sources for a signal. Each different sources are stored to a global list and will be exposed to the userspace through the nvif interface in order to avoid conflicts. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 82 ++++++++++++++++++- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 24 ++++++ 3 files changed, 103 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index 6c2d0578400a0..130b545b4e9e9 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -11,6 +11,7 @@ struct nvkm_pm { void *profile_data; struct list_head domains; + struct list_head sources; u32 sequence; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 610c0ca5c80b8..dfafefd9facf1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -433,6 +433,67 @@ nvkm_pm_cclass = { /******************************************************************************* * PPM engine/subdev functions ******************************************************************************/ +int +nvkm_perfsrc_new(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, + const struct nvkm_specsrc *spec) +{ + const struct nvkm_specsrc *ssrc; + const struct nvkm_specmux *smux; + struct nvkm_perfsrc *src; + u8 source_nr = 0; + + if (!spec) { + /* No sources are defined for this signal. */ + return 0; + } + + ssrc = spec; + while (ssrc->name) { + smux = ssrc->mux; + while (smux->name) { + bool found = false; + u8 source_id = 0; + u32 len; + + list_for_each_entry(src, &ppm->sources, head) { + if (src->addr == ssrc->addr && + src->shift == smux->shift) { + found = true; + break; + } + source_id++; + } + + if (!found) { + src = kzalloc(sizeof(*src), GFP_KERNEL); + if (!src) + return -ENOMEM; + + src->addr = ssrc->addr; + src->mask = smux->mask; + src->shift = smux->shift; + src->enable = smux->enable; + + len = strlen(ssrc->name) + + strlen(smux->name) + 2; + src->name = kzalloc(len, GFP_KERNEL); + if (!src->name) + return -ENOMEM; + snprintf(src->name, len, "%s_%s", ssrc->name, + smux->name); + + list_add_tail(&src->head, &ppm->sources); + } + + sig->source[source_nr++] = source_id + 1; + smux++; + } + ssrc++; + } + + return 0; +} + int nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, u32 base, u32 size_unit, u32 size_domain, @@ -441,7 +502,7 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, const struct nvkm_specdom *sdom; const struct nvkm_specsig *ssig; struct nvkm_perfdom *dom; - int i; + int ret, i; for (i = 0; i == 0 || mask; i++) { u32 addr = base + (i * size_unit); @@ -473,7 +534,12 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, ssig = (sdom++)->signal; while (ssig->name) { - dom->signal[ssig->signal].name = ssig->name; + struct nvkm_perfsig *sig = + &dom->signal[ssig->signal]; + sig->name = ssig->name; + ret = nvkm_perfsrc_new(ppm, sig, ssig->source); + if (ret) + return ret; ssig++; } @@ -504,13 +570,20 @@ void _nvkm_pm_dtor(struct nvkm_object *object) { struct nvkm_pm *ppm = (void *)object; - struct nvkm_perfdom *dom, *tmp; + struct nvkm_perfdom *dom, *next_dom; + struct nvkm_perfsrc *src, *next_src; - list_for_each_entry_safe(dom, tmp, &ppm->domains, head) { + list_for_each_entry_safe(dom, next_dom, &ppm->domains, head) { list_del(&dom->head); kfree(dom); } + list_for_each_entry_safe(src, next_src, &ppm->sources, head) { + list_del(&src->head); + kfree(src->name); + kfree(src); + } + nvkm_engine_destroy(&ppm->base); } @@ -528,5 +601,6 @@ nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine, return ret; INIT_LIST_HEAD(&ppm->domains); + INIT_LIST_HEAD(&ppm->sources); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 71667fcbd9de2..f954c98685940 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -22,13 +22,37 @@ struct nvkm_perfctx { extern struct nvkm_oclass nvkm_pm_cclass; +struct nvkm_specmux { + u32 mask; + u8 shift; + const char *name; + bool enable; +}; + +struct nvkm_specsrc { + u32 addr; + const struct nvkm_specmux *mux; + const char *name; +}; + +struct nvkm_perfsrc { + struct list_head head; + char *name; + u32 addr; + u32 mask; + u8 shift; + bool enable; +}; + struct nvkm_specsig { u8 signal; const char *name; + const struct nvkm_specsrc *source; }; struct nvkm_perfsig { const char *name; + u8 source[8]; }; struct nvkm_specdom { -- GitLab From 50d138d7528c3370ebf3a54079091a35a60a23be Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:23 +0200 Subject: [PATCH 5280/7006] drm/nouveau/pm: allow to query the number of sources for a signal Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 3 ++- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 22 ++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 9e4db3aaada7d..caae193f354e8 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -268,7 +268,8 @@ struct nvif_perfmon_query_signal_v0 { __u8 domain; __u16 iter; __u8 signal; - __u8 pad04[3]; + __u8 source_nr; + __u8 pad05[2]; char name[64]; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index dfafefd9facf1..a9c57a20186ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -91,6 +91,18 @@ nvkm_perfsig_find(struct nvkm_pm *ppm, uint8_t di, uint8_t si, return &dom->signal[si]; } +static u8 +nvkm_perfsig_count_perfsrc(struct nvkm_perfsig *sig) +{ + u8 source_nr = 0, i; + + for (i = 0; i < ARRAY_SIZE(sig->source); i++) { + if (sig->source[i]) + source_nr++; + } + return source_nr; +} + /******************************************************************************* * Perfmon object classes ******************************************************************************/ @@ -148,9 +160,9 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) struct nvkm_device *device = nv_device(object); struct nvkm_pm *ppm = (void *)object->engine; struct nvkm_perfdom *dom; + struct nvkm_perfsig *sig; const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); - const char *name; int ret, si; nv_ioctl(object, "perfmon query signal size %d\n", size); @@ -167,13 +179,17 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) return -EINVAL; if (si >= 0) { - if (raw || !(name = dom->signal[si].name)) { + sig = &dom->signal[si]; + if (raw || !sig->name) { snprintf(args->v0.name, sizeof(args->v0.name), "/%s/%02x", dom->name, si); } else { - strncpy(args->v0.name, name, sizeof(args->v0.name)); + strncpy(args->v0.name, sig->name, + sizeof(args->v0.name)); } + args->v0.signal = si; + args->v0.source_nr = nvkm_perfsig_count_perfsrc(sig); } while (++si < dom->signal_nr) { -- GitLab From 6f99c84873f455a76a0356061b276bc0c89b5d92 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:24 +0200 Subject: [PATCH 5281/7006] drm/nouveau/pm: implement NVIF_PERFMON_V0_QUERY_SOURCE method This allows to query the ID, the mask and the user-readable name of sources for each signal. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 12 +++ drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 77 +++++++++++++++++++ 2 files changed, 89 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index caae193f354e8..d85fb0d945e85 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -253,6 +253,7 @@ struct gf110_dma_v0 { #define NVIF_PERFMON_V0_QUERY_DOMAIN 0x00 #define NVIF_PERFMON_V0_QUERY_SIGNAL 0x01 +#define NVIF_PERFMON_V0_QUERY_SOURCE 0x02 struct nvif_perfmon_query_domain_v0 { __u8 version; @@ -273,6 +274,17 @@ struct nvif_perfmon_query_signal_v0 { char name[64]; }; +struct nvif_perfmon_query_source_v0 { + __u8 version; + __u8 domain; + __u8 signal; + __u8 iter; + __u8 pad04[4]; + __u32 source; + __u32 mask; + char name[64]; +}; + /******************************************************************************* * perfctr diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index a9c57a20186ad..ec02abfd86b0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -103,6 +103,31 @@ nvkm_perfsig_count_perfsrc(struct nvkm_perfsig *sig) return source_nr; } +static struct nvkm_perfsrc * +nvkm_perfsrc_find(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, int si) +{ + struct nvkm_perfsrc *src; + bool found = false; + int tmp = 1; /* Sources ID start from 1 */ + u8 i; + + for (i = 0; i < ARRAY_SIZE(sig->source) && sig->source[i]; i++) { + if (sig->source[i] == si) { + found = true; + break; + } + } + + if (found) { + list_for_each_entry(src, &ppm->sources, head) { + if (tmp++ == si) + return src; + } + } + + return NULL; +} + /******************************************************************************* * Perfmon object classes ******************************************************************************/ @@ -203,6 +228,56 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) return 0; } +static int +nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfmon_query_source_v0 v0; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom = NULL; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + u8 source_nr = 0; + int si, ret; + + nv_ioctl(object, "perfmon query source size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, + "perfmon source vers %d dom %d sig %02x iter %02x\n", + args->v0.version, args->v0.domain, args->v0.signal, + args->v0.iter); + si = (args->v0.iter & 0xff) - 1; + } else + return ret; + + sig = nvkm_perfsig_find(ppm, args->v0.domain, args->v0.signal, &dom); + if (!sig) + return -EINVAL; + + source_nr = nvkm_perfsig_count_perfsrc(sig); + if (si >= (int)source_nr) + return -EINVAL; + + if (si >= 0) { + src = nvkm_perfsrc_find(ppm, sig, sig->source[si]); + if (!src) + return -EINVAL; + + args->v0.source = sig->source[si]; + args->v0.mask = src->mask; + strncpy(args->v0.name, src->name, sizeof(args->v0.name)); + } + + if (++si < source_nr) { + args->v0.iter = ++si; + return 0; + } + + args->v0.iter = 0xff; + return 0; +} + static int nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { @@ -211,6 +286,8 @@ nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return nvkm_perfmon_mthd_query_domain(object, data, size); case NVIF_PERFMON_V0_QUERY_SIGNAL: return nvkm_perfmon_mthd_query_signal(object, data, size); + case NVIF_PERFMON_V0_QUERY_SOURCE: + return nvkm_perfmon_mthd_query_source(object, data, size); default: break; } -- GitLab From 3bfdde178a959cb5e490e4a3a2433c95a9a1af26 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:25 +0200 Subject: [PATCH 5282/7006] drm/nouveau/pm: allow the userspace to schedule hardware counters This adds a new method NVIF_PERFCTR_V0_INIT which starts a batch of hardware counters for sampling. This will allow the userspace to start a monitoring session using the INIT method and to stop it with SAMPLE, for example before and after a frame is rendered. This commit temporarily breaks nv_perfmon but this is going to be fixed with the upcoming patch. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 8 ++- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 64 ++++++++++++------- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 1 + 3 files changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index d85fb0d945e85..528eac8c8403a 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -300,8 +300,12 @@ struct nvif_perfctr_v0 { __u8 pad06[4]; }; -#define NVIF_PERFCTR_V0_SAMPLE 0x00 -#define NVIF_PERFCTR_V0_READ 0x01 +#define NVIF_PERFCTR_V0_INIT 0x00 +#define NVIF_PERFCTR_V0_SAMPLE 0x01 +#define NVIF_PERFCTR_V0_READ 0x02 + +struct nvif_perfctr_init { +}; struct nvif_perfctr_sample { }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index ec02abfd86b0a..5dbb3b4e2ebbf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -306,6 +306,36 @@ nvkm_perfmon_ofuncs = { /******************************************************************************* * Perfctr object classes ******************************************************************************/ +static int +nvkm_perfctr_init(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfctr_init none; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfctr *ctr = (void *)object; + struct nvkm_perfdom *dom = ctr->dom; + int ret; + + nv_ioctl(object, "perfctr init size %d\n", size); + if (nvif_unvers(args->none)) { + nv_ioctl(object, "perfctr init\n"); + } else + return ret; + + ctr->slot = ffs(dom->quad) - 1; + if (ctr->slot < 0) { + /* no free slots are available */ + return -EINVAL; + } + dom->quad &= ~(QUAD_FREE << ctr->slot); + dom->func->init(ppm, dom, ctr); + + /* start next batch of counters for sampling */ + dom->func->next(ppm, dom); + return 0; +} + static int nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) { @@ -313,7 +343,7 @@ nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) struct nvif_perfctr_sample none; } *args = data; struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfctr *ctr, *tmp; + struct nvkm_perfctr *ctr; struct nvkm_perfdom *dom; int ret; @@ -328,32 +358,15 @@ nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) /* sample previous batch of counters */ if (dom->quad != QUAD_MASK) { dom->func->next(ppm, dom); - tmp = NULL; - while (!list_empty(&dom->list)) { - ctr = list_first_entry(&dom->list, - typeof(*ctr), head); - if (ctr->slot < 0) break; - if ( tmp && tmp == ctr) break; - if (!tmp) tmp = ctr; + + /* read counter values */ + list_for_each_entry(ctr, &dom->list, head) { dom->func->read(ppm, dom, ctr); - ctr->slot = -1; - list_move_tail(&ctr->head, &dom->list); + ctr->slot = -1; } - } - - dom->quad = QUAD_MASK; - /* setup next batch of counters for sampling */ - list_for_each_entry(ctr, &dom->list, head) { - ctr->slot = ffs(dom->quad) - 1; - if (ctr->slot < 0) - break; - dom->quad &= ~(QUAD_FREE << ctr->slot); - dom->func->init(ppm, dom, ctr); + dom->quad = QUAD_MASK; } - - if (dom->quad != QUAD_MASK) - dom->func->next(ppm, dom); } return 0; @@ -386,6 +399,8 @@ static int nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { + case NVIF_PERFCTR_V0_INIT: + return nvkm_perfctr_init(object, data, size); case NVIF_PERFCTR_V0_SAMPLE: return nvkm_perfctr_sample(object, data, size); case NVIF_PERFCTR_V0_READ: @@ -400,6 +415,8 @@ static void nvkm_perfctr_dtor(struct nvkm_object *object) { struct nvkm_perfctr *ctr = (void *)object; + if (ctr->dom) + ctr->dom->quad |= (QUAD_FREE << ctr->slot); if (ctr->head.next) list_del(&ctr->head); nvkm_object_destroy(&ctr->base); @@ -441,6 +458,7 @@ nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ctr->dom = dom; ctr->slot = -1; ctr->logic_op = args->v0.logic_op; ctr->signal[0] = sig[0]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index f954c98685940..4ed77ff4922cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -6,6 +6,7 @@ struct nvkm_perfctr { struct nvkm_object base; struct list_head head; struct nvkm_perfsig *signal[4]; + struct nvkm_perfdom *dom; int slot; u32 logic_op; u32 clk; -- GitLab From 0f3804360dd4f88332b9c0b2d7cb4c1f30893cc7 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:26 +0200 Subject: [PATCH 5283/7006] drm/nouveau/pm: allow to configure domains instead of simple counters Configuring counters from the userspace require the kernel to handle some logic related to performance counters. Basically, it has to find a free slot to assign a counter, to handle extra counting modes like B4/B6 and it must return and error when it can't configure a counter. In my opinion, the kernel should not handle all of that logic but it should only write the configuration sent by the userspace without checking anything. In other words, it should overwrite the configuration even if it's already counting and do not return any errors. This patch allows the userspace to configure a domain instead of separate counters. This has the advantage to move all of the logic to the userspace. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 30 +-- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 208 ++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 10 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 10 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 10 +- 6 files changed, 146 insertions(+), 124 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 528eac8c8403a..1a76a7fe38059 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -287,34 +287,36 @@ struct nvif_perfmon_query_source_v0 { /******************************************************************************* - * perfctr + * perfdom ******************************************************************************/ -struct nvif_perfctr_v0 { +struct nvif_perfdom_v0 { __u8 version; __u8 domain; - __u8 pad02[2]; - __u16 logic_op; - __u8 pad04[2]; - __u8 signal[4]; - __u8 pad06[4]; + __u8 mode; + __u8 pad03[1]; + struct { + __u8 signal[4]; + __u16 logic_op; + } ctr[4]; }; -#define NVIF_PERFCTR_V0_INIT 0x00 -#define NVIF_PERFCTR_V0_SAMPLE 0x01 -#define NVIF_PERFCTR_V0_READ 0x02 +#define NVIF_PERFDOM_V0_INIT 0x00 +#define NVIF_PERFDOM_V0_SAMPLE 0x01 +#define NVIF_PERFDOM_V0_READ 0x02 -struct nvif_perfctr_init { +struct nvif_perfdom_init { }; -struct nvif_perfctr_sample { +struct nvif_perfdom_sample { }; -struct nvif_perfctr_read_v0 { +struct nvif_perfdom_read_v0 { __u8 version; __u8 pad01[7]; - __u32 ctr; + __u32 ctr[4]; __u32 clk; + __u8 pad04[4]; }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 517cd27cdc377..2eb9b899ab36b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -50,7 +50,7 @@ struct nvif_ioctl_new_v0 { __u32 handle; /* these class numbers are made up by us, and not nvidia-assigned */ #define NVIF_IOCTL_NEW_V0_PERFMON 0x0000ffff -#define NVIF_IOCTL_NEW_V0_PERFCTR 0x0000fffe +#define NVIF_IOCTL_NEW_V0_PERFDOM 0x0000fffe #define NVIF_IOCTL_NEW_V0_CONTROL 0x0000fffd __u32 oclass; __u8 data[]; /* class data (class.h) */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 5dbb3b4e2ebbf..8960bf4ff459c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -31,9 +31,6 @@ #include #include -#define QUAD_MASK 0x0f -#define QUAD_FREE 0x01 - static u8 nvkm_pm_count_perfdom(struct nvkm_pm *ppm) { @@ -304,32 +301,27 @@ nvkm_perfmon_ofuncs = { }; /******************************************************************************* - * Perfctr object classes + * Perfdom object classes ******************************************************************************/ static int -nvkm_perfctr_init(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) { union { - struct nvif_perfctr_init none; + struct nvif_perfdom_init none; } *args = data; struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfctr *ctr = (void *)object; - struct nvkm_perfdom *dom = ctr->dom; - int ret; + struct nvkm_perfdom *dom = (void *)object; + int ret, i; - nv_ioctl(object, "perfctr init size %d\n", size); + nv_ioctl(object, "perfdom init size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "perfctr init\n"); + nv_ioctl(object, "perfdom init\n"); } else return ret; - ctr->slot = ffs(dom->quad) - 1; - if (ctr->slot < 0) { - /* no free slots are available */ - return -EINVAL; - } - dom->quad &= ~(QUAD_FREE << ctr->slot); - dom->func->init(ppm, dom, ctr); + for (i = 0; i < 4; i++) + if (dom->ctr[i]) + dom->func->init(ppm, dom, dom->ctr[i]); /* start next batch of counters for sampling */ dom->func->next(ppm, dom); @@ -337,74 +329,70 @@ nvkm_perfctr_init(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size) { union { - struct nvif_perfctr_sample none; + struct nvif_perfdom_sample none; } *args = data; struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfctr *ctr; struct nvkm_perfdom *dom; int ret; - nv_ioctl(object, "perfctr sample size %d\n", size); + nv_ioctl(object, "perfdom sample size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "perfctr sample\n"); + nv_ioctl(object, "perfdom sample\n"); } else return ret; ppm->sequence++; - list_for_each_entry(dom, &ppm->domains, head) { - /* sample previous batch of counters */ - if (dom->quad != QUAD_MASK) { - dom->func->next(ppm, dom); - - /* read counter values */ - list_for_each_entry(ctr, &dom->list, head) { - dom->func->read(ppm, dom, ctr); - ctr->slot = -1; - } - - dom->quad = QUAD_MASK; - } - } + /* sample previous batch of counters */ + list_for_each_entry(dom, &ppm->domains, head) + dom->func->next(ppm, dom); return 0; } static int -nvkm_perfctr_read(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size) { union { - struct nvif_perfctr_read_v0 v0; + struct nvif_perfdom_read_v0 v0; } *args = data; - struct nvkm_perfctr *ctr = (void *)object; - int ret; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom = (void *)object; + int ret, i; - nv_ioctl(object, "perfctr read size %d\n", size); + nv_ioctl(object, "perfdom read size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfctr read vers %d\n", args->v0.version); + nv_ioctl(object, "perfdom read vers %d\n", args->v0.version); } else return ret; - if (!ctr->clk) + for (i = 0; i < 4; i++) { + if (dom->ctr[i]) + dom->func->read(ppm, dom, dom->ctr[i]); + } + + if (!dom->clk) return -EAGAIN; - args->v0.clk = ctr->clk; - args->v0.ctr = ctr->ctr; + for (i = 0; i < 4; i++) + if (dom->ctr[i]) + args->v0.ctr[i] = dom->ctr[i]->ctr; + args->v0.clk = dom->clk; return 0; } static int -nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { - case NVIF_PERFCTR_V0_INIT: - return nvkm_perfctr_init(object, data, size); - case NVIF_PERFCTR_V0_SAMPLE: - return nvkm_perfctr_sample(object, data, size); - case NVIF_PERFCTR_V0_READ: - return nvkm_perfctr_read(object, data, size); + case NVIF_PERFDOM_V0_INIT: + return nvkm_perfdom_init(object, data, size); + case NVIF_PERFDOM_V0_SAMPLE: + return nvkm_perfdom_sample(object, data, size); + case NVIF_PERFDOM_V0_READ: + return nvkm_perfdom_read(object, data, size); default: break; } @@ -412,70 +400,107 @@ nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) } static void -nvkm_perfctr_dtor(struct nvkm_object *object) +nvkm_perfdom_dtor(struct nvkm_object *object) { - struct nvkm_perfctr *ctr = (void *)object; - if (ctr->dom) - ctr->dom->quad |= (QUAD_FREE << ctr->slot); - if (ctr->head.next) - list_del(&ctr->head); - nvkm_object_destroy(&ctr->base); + struct nvkm_perfdom *dom = (void *)object; + int i; + + for (i = 0; i < 4; i++) { + struct nvkm_perfctr *ctr = dom->ctr[i]; + if (ctr && ctr->head.next) + list_del(&ctr->head); + kfree(ctr); + } + nvkm_object_destroy(&dom->base); } static int -nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, +nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, + struct nvkm_perfsig *signal[4], uint16_t logic_op, + struct nvkm_perfctr **pctr) +{ + struct nvkm_perfctr *ctr; + int i; + + if (!dom) + return -EINVAL; + + ctr = *pctr = kzalloc(sizeof(*ctr), GFP_KERNEL); + if (!ctr) + return -ENOMEM; + + ctr->logic_op = logic_op; + ctr->slot = slot; + for (i = 0; i < 4; i++) { + if (signal[i]) + ctr->signal[i] = signal[i] - dom->signal; + } + list_add_tail(&ctr->head, &dom->list); + + return 0; +} + +static int +nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { - struct nvif_perfctr_v0 v0; + struct nvif_perfdom_v0 v0; } *args = data; struct nvkm_pm *ppm = (void *)engine; - struct nvkm_perfdom *dom = NULL; - struct nvkm_perfsig *sig[4] = {}; - struct nvkm_perfctr *ctr; - int ret, i; + struct nvkm_perfdom *sdom = NULL; + struct nvkm_perfctr *ctr[4] = {}; + struct nvkm_perfdom *dom; + int c, s; + int ret; - nv_ioctl(parent, "create perfctr size %d\n", size); + nv_ioctl(parent, "create perfdom size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n", - args->v0.version, args->v0.logic_op); + nv_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n", + args->v0.version, args->v0.domain, args->v0.mode); } else return ret; - for (i = 0; i < ARRAY_SIZE(args->v0.signal); i++) { - sig[i] = nvkm_perfsig_find(ppm, args->v0.domain, - args->v0.signal[i], &dom); - if (args->v0.signal[i] && !sig[i]) - return -EINVAL; + for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) { + struct nvkm_perfsig *sig[4] = {}; + for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) { + sig[s] = nvkm_perfsig_find(ppm, args->v0.domain, + args->v0.ctr[c].signal[s], + &sdom); + if (args->v0.ctr[c].signal[s] && !sig[s]) + return -EINVAL; + } + + ret = nvkm_perfctr_new(sdom, c, sig, + args->v0.ctr[c].logic_op, &ctr[c]); + if (ret) + return ret; } - if (!dom) + if (!sdom) return -EINVAL; - ret = nvkm_object_create(parent, engine, oclass, 0, &ctr); - *pobject = nv_object(ctr); + ret = nvkm_object_create(parent, engine, oclass, 0, &dom); + *pobject = nv_object(dom); if (ret) return ret; - ctr->dom = dom; - ctr->slot = -1; - ctr->logic_op = args->v0.logic_op; - ctr->signal[0] = sig[0]; - ctr->signal[1] = sig[1]; - ctr->signal[2] = sig[2]; - ctr->signal[3] = sig[3]; - list_add_tail(&ctr->head, &dom->list); + dom->func = sdom->func; + dom->addr = sdom->addr; + dom->mode = args->v0.mode; + for (c = 0; c < ARRAY_SIZE(ctr); c++) + dom->ctr[c] = ctr[c]; return 0; } static struct nvkm_ofuncs -nvkm_perfctr_ofuncs = { - .ctor = nvkm_perfctr_ctor, - .dtor = nvkm_perfctr_dtor, +nvkm_perfdom_ofuncs = { + .ctor = nvkm_perfdom_ctor, + .dtor = nvkm_perfdom_dtor, .init = nvkm_object_init, .fini = nvkm_object_fini, - .mthd = nvkm_perfctr_mthd, + .mthd = nvkm_perfdom_mthd, }; struct nvkm_oclass @@ -484,8 +509,8 @@ nvkm_pm_sclass[] = { .handle = NVIF_IOCTL_NEW_V0_PERFMON, .ofuncs = &nvkm_perfmon_ofuncs, }, - { .handle = NVIF_IOCTL_NEW_V0_PERFCTR, - .ofuncs = &nvkm_perfctr_ofuncs, + { .handle = NVIF_IOCTL_NEW_V0_PERFDOM, + .ofuncs = &nvkm_perfdom_ofuncs, }, {}, }; @@ -640,7 +665,6 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, INIT_LIST_HEAD(&dom->list); dom->func = sdom->func; dom->addr = addr; - dom->quad = QUAD_MASK; dom->signal_nr = sdom->signal_nr; ssig = (sdom++)->signal; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 41350d6199a57..edab97aa918e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -48,12 +48,10 @@ gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, u32 src = 0x00000000; int i; - for (i = 0; i < 4; i++) { - if (ctr->signal[i]) - src |= (ctr->signal[i] - dom->signal) << (i * 8); - } + for (i = 0; i < 4; i++) + src |= ctr->signal[i] << (i * 8); - nv_wr32(priv, dom->addr + 0x09c, 0x00040002); + nv_wr32(priv, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); nv_wr32(priv, dom->addr + 0x100, 0x00000000); nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); @@ -72,7 +70,7 @@ gf100_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break; case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break; } - cntr->base.clk = nv_rd32(priv, dom->addr + 0x070); + dom->clk = nv_rd32(priv, dom->addr + 0x070); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index 603874ec0fbac..1c6d1ca4799ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -33,12 +33,10 @@ nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, u32 src = 0x00000000; int i; - for (i = 0; i < 4; i++) { - if (ctr->signal[i]) - src |= (ctr->signal[i] - dom->signal) << (i * 8); - } + for (i = 0; i < 4; i++) + src |= ctr->signal[i] << (i * 8); - nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001); + nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); } @@ -56,7 +54,7 @@ nv40_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break; case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break; } - cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr); + dom->clk = nv_rd32(priv, 0x00a600 + dom->addr); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 4ed77ff4922cf..38adeb731b966 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -3,13 +3,10 @@ #include struct nvkm_perfctr { - struct nvkm_object base; struct list_head head; - struct nvkm_perfsig *signal[4]; - struct nvkm_perfdom *dom; + u8 signal[4]; int slot; u32 logic_op; - u32 clk; u32 ctr; }; @@ -63,12 +60,15 @@ struct nvkm_specdom { }; struct nvkm_perfdom { + struct nvkm_object base; struct list_head head; struct list_head list; const struct nvkm_funcdom *func; + struct nvkm_perfctr *ctr[4]; char name[32]; u32 addr; - u8 quad; + u8 mode; + u32 clk; u16 signal_nr; struct nvkm_perfsig signal[]; }; -- GitLab From 6137b5a7c2aeca9f72229c120504f5d083fa9127 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:27 +0200 Subject: [PATCH 5284/7006] drm/nouveau/pm: allow the userspace to configure sources Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 102 ++++++++++++++++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 2 + 3 files changed, 95 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 1a76a7fe38059..3b7f49f876abe 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -297,6 +297,7 @@ struct nvif_perfdom_v0 { __u8 pad03[1]; struct { __u8 signal[4]; + __u64 source[4][8]; __u16 logic_op; } ctr[4]; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 8960bf4ff459c..a4bb6fe5e90b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -125,6 +125,66 @@ nvkm_perfsrc_find(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, int si) return NULL; } +static int +nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) +{ + struct nvkm_perfdom *dom = NULL; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + u32 mask, value; + int i, j; + + for (i = 0; i < 4 && ctr->signal[i]; i++) { + for (j = 0; j < 8 && ctr->source[i][j]; j++) { + sig = nvkm_perfsig_find(ppm, ctr->domain, + ctr->signal[i], &dom); + if (!sig) + return -EINVAL; + + src = nvkm_perfsrc_find(ppm, sig, ctr->source[i][j]); + if (!src) + return -EINVAL; + + /* set enable bit if needed */ + mask = value = 0x00000000; + if (src->enable) + mask = value = 0x80000000; + mask |= (src->mask << src->shift); + value |= ((ctr->source[i][j] >> 32) << src->shift); + + /* enable the source */ + nv_mask(ppm, src->addr, mask, value); + } + } + return 0; +} + +static int +nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) +{ + struct nvkm_perfdom *dom = NULL; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + int i, j; + + for (i = 0; i < 4 && ctr->signal[i]; i++) { + for (j = 0; j < 8 && ctr->source[i][j]; j++) { + sig = nvkm_perfsig_find(ppm, ctr->domain, + ctr->signal[i], &dom); + if (!sig) + return -EINVAL; + + src = nvkm_perfsrc_find(ppm, sig, ctr->source[i][j]); + if (!src) + return -EINVAL; + + /* disable the source */ + nv_mask(ppm, src->addr, src->mask << src->shift, 0); + } + } + return 0; +} + /******************************************************************************* * Perfmon object classes ******************************************************************************/ @@ -319,10 +379,15 @@ nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) } else return ret; - for (i = 0; i < 4; i++) - if (dom->ctr[i]) + for (i = 0; i < 4; i++) { + if (dom->ctr[i]) { dom->func->init(ppm, dom, dom->ctr[i]); + /* enable sources */ + nvkm_perfsrc_enable(ppm, dom->ctr[i]); + } + } + /* start next batch of counters for sampling */ dom->func->next(ppm, dom); return 0; @@ -402,13 +467,17 @@ nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) static void nvkm_perfdom_dtor(struct nvkm_object *object) { + struct nvkm_pm *ppm = (void *)object->engine; struct nvkm_perfdom *dom = (void *)object; int i; for (i = 0; i < 4; i++) { struct nvkm_perfctr *ctr = dom->ctr[i]; - if (ctr && ctr->head.next) - list_del(&ctr->head); + if (ctr) { + nvkm_perfsrc_disable(ppm, ctr); + if (ctr->head.next) + list_del(&ctr->head); + } kfree(ctr); } nvkm_object_destroy(&dom->base); @@ -416,11 +485,11 @@ nvkm_perfdom_dtor(struct nvkm_object *object) static int nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, - struct nvkm_perfsig *signal[4], uint16_t logic_op, - struct nvkm_perfctr **pctr) + struct nvkm_perfsig *signal[4], uint64_t source[4][8], + uint16_t logic_op, struct nvkm_perfctr **pctr) { struct nvkm_perfctr *ctr; - int i; + int i, j; if (!dom) return -EINVAL; @@ -432,8 +501,11 @@ nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, ctr->logic_op = logic_op; ctr->slot = slot; for (i = 0; i < 4; i++) { - if (signal[i]) + if (signal[i]) { ctr->signal[i] = signal[i] - dom->signal; + for (j = 0; j < 8; j++) + ctr->source[i][j] = source[i][j]; + } } list_add_tail(&ctr->head, &dom->list); @@ -452,7 +524,7 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_perfdom *sdom = NULL; struct nvkm_perfctr *ctr[4] = {}; struct nvkm_perfdom *dom; - int c, s; + int c, s, m; int ret; nv_ioctl(parent, "create perfdom size %d\n", size); @@ -464,18 +536,28 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) { struct nvkm_perfsig *sig[4] = {}; + u64 src[4][8]; + for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) { sig[s] = nvkm_perfsig_find(ppm, args->v0.domain, args->v0.ctr[c].signal[s], &sdom); if (args->v0.ctr[c].signal[s] && !sig[s]) return -EINVAL; + + for (m = 0; m < 8; m++) { + src[s][m] = args->v0.ctr[c].source[s][m]; + if (src[s][m] && !nvkm_perfsrc_find(ppm, sig[s], + src[s][m])) + return -EINVAL; + } } - ret = nvkm_perfctr_new(sdom, c, sig, + ret = nvkm_perfctr_new(sdom, c, sig, src, args->v0.ctr[c].logic_op, &ctr[c]); if (ret) return ret; + ctr[c]->domain = args->v0.domain; } if (!sdom) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 38adeb731b966..da419c1d5481f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -4,7 +4,9 @@ struct nvkm_perfctr { struct list_head head; + u8 domain; u8 signal[4]; + u64 source[4][8]; int slot; u32 logic_op; u32 ctr; -- GitLab From 06b7972dc915e60051cd6531d988a7c72645d00a Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 7 Jun 2015 22:40:28 +0200 Subject: [PATCH 5285/7006] drm/nouveau/pm/nv50: add compute and graphics signals/sources These signals and sources have been reverse engineered from NVIDIA PerfKit (Windows) and CUPTI (Linux), they will be used to build complex hardware events from the userspace. This commit also adds a new class for GT200. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c | 101 ++++++++++- .../gpu/drm/nouveau/nvkm/engine/pm/gt200.c | 163 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/pm/gt215.c | 84 ++++++++- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c | 136 ++++++++++++++- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 8 + 8 files changed, 485 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index 130b545b4e9e9..82f1c7f5243a1 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -24,6 +24,7 @@ nvkm_pm(void *obj) extern struct nvkm_oclass *nv40_pm_oclass; extern struct nvkm_oclass *nv50_pm_oclass; extern struct nvkm_oclass *g84_pm_oclass; +extern struct nvkm_oclass *gt200_pm_oclass; extern struct nvkm_oclass *gt215_pm_oclass; extern struct nvkm_oclass gf100_pm_oclass; extern struct nvkm_oclass gk104_pm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 249b844546125..a2627ec67c116 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -288,7 +288,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt200_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: device->cname = "MCP77/MCP78"; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild index c5ee8d566b0d6..cc01048a8cabe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild @@ -2,6 +2,7 @@ nvkm-y += nvkm/engine/pm/base.o nvkm-y += nvkm/engine/pm/nv40.o nvkm-y += nvkm/engine/pm/nv50.o nvkm-y += nvkm/engine/pm/g84.o +nvkm-y += nvkm/engine/pm/gt200.o nvkm-y += nvkm/engine/pm/gt215.o nvkm-y += nvkm/engine/pm/gf100.o nvkm-y += nvkm/engine/pm/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c index d54c6705ba170..dda539cf0764f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c @@ -23,15 +23,112 @@ */ #include "nv40.h" +const struct nvkm_specsrc +g84_vfetch_sources[] = { + { 0x400c0c, (const struct nvkm_specmux[]) { + { 0x3, 0, "unk0" }, + {} + }, "pgraph_vfetch_unk0c" }, + {} +}; + +static const struct nvkm_specsrc +g84_crop_sources[] = { + { 0x407008, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x7, 16, "sel1", true }, + {} + }, "pgraph_rop0_crop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +g84_tex_sources[] = { + { 0x408808, (const struct nvkm_specmux[]) { + { 0xfffff, 0, "unk0" }, + {} + }, "pgraph_tpc0_tex_unk08" }, + {} +}; + static const struct nvkm_specdom g84_pm[] = { { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { + { 0xbd, "pc01_gr_idle" }, + { 0x5e, "pc01_strmout_00" }, + { 0x5f, "pc01_strmout_01" }, + { 0xd2, "pc01_trast_00" }, + { 0xd3, "pc01_trast_01" }, + { 0xd4, "pc01_trast_02" }, + { 0xd5, "pc01_trast_03" }, + { 0xd8, "pc01_trast_04" }, + { 0xd9, "pc01_trast_05" }, + { 0x5c, "pc01_vattr_00" }, + { 0x5d, "pc01_vattr_01" }, + { 0x66, "pc01_vfetch_00", g84_vfetch_sources }, + { 0x67, "pc01_vfetch_01", g84_vfetch_sources }, + { 0x68, "pc01_vfetch_02", g84_vfetch_sources }, + { 0x69, "pc01_vfetch_03", g84_vfetch_sources }, + { 0x6a, "pc01_vfetch_04", g84_vfetch_sources }, + { 0x6b, "pc01_vfetch_05", g84_vfetch_sources }, + { 0x6c, "pc01_vfetch_06", g84_vfetch_sources }, + { 0x6d, "pc01_vfetch_07", g84_vfetch_sources }, + { 0x6e, "pc01_vfetch_08", g84_vfetch_sources }, + { 0x6f, "pc01_vfetch_09", g84_vfetch_sources }, + { 0x70, "pc01_vfetch_0a", g84_vfetch_sources }, + { 0x71, "pc01_vfetch_0b", g84_vfetch_sources }, + { 0x72, "pc01_vfetch_0c", g84_vfetch_sources }, + { 0x73, "pc01_vfetch_0d", g84_vfetch_sources }, + { 0x74, "pc01_vfetch_0e", g84_vfetch_sources }, + { 0x75, "pc01_vfetch_0f", g84_vfetch_sources }, + { 0x76, "pc01_vfetch_10", g84_vfetch_sources }, + { 0x77, "pc01_vfetch_11", g84_vfetch_sources }, + { 0x78, "pc01_vfetch_12", g84_vfetch_sources }, + { 0x79, "pc01_vfetch_13", g84_vfetch_sources }, + { 0x7a, "pc01_vfetch_14", g84_vfetch_sources }, + { 0x7b, "pc01_vfetch_15", g84_vfetch_sources }, + { 0x7c, "pc01_vfetch_16", g84_vfetch_sources }, + { 0x7d, "pc01_vfetch_17", g84_vfetch_sources }, + { 0x7e, "pc01_vfetch_18", g84_vfetch_sources }, + { 0x7f, "pc01_vfetch_19", g84_vfetch_sources }, + { 0x07, "pc01_zcull_00", nv50_zcull_sources }, + { 0x08, "pc01_zcull_01", nv50_zcull_sources }, + { 0x09, "pc01_zcull_02", nv50_zcull_sources }, + { 0x0a, "pc01_zcull_03", nv50_zcull_sources }, + { 0x0b, "pc01_zcull_04", nv50_zcull_sources }, + { 0x0c, "pc01_zcull_05", nv50_zcull_sources }, + { 0xa4, "pc01_unk00" }, + { 0xec, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xa0, (const struct nvkm_specsig[]) { + { 0x30, "pc02_crop_00", g84_crop_sources }, + { 0x31, "pc02_crop_01", g84_crop_sources }, + { 0x32, "pc02_crop_02", g84_crop_sources }, + { 0x33, "pc02_crop_03", g84_crop_sources }, + { 0x00, "pc02_prop_00", nv50_prop_sources }, + { 0x01, "pc02_prop_01", nv50_prop_sources }, + { 0x02, "pc02_prop_02", nv50_prop_sources }, + { 0x03, "pc02_prop_03", nv50_prop_sources }, + { 0x04, "pc02_prop_04", nv50_prop_sources }, + { 0x05, "pc02_prop_05", nv50_prop_sources }, + { 0x06, "pc02_prop_06", nv50_prop_sources }, + { 0x07, "pc02_prop_07", nv50_prop_sources }, + { 0x48, "pc02_tex_00", g84_tex_sources }, + { 0x49, "pc02_tex_01", g84_tex_sources }, + { 0x4a, "pc02_tex_02", g84_tex_sources }, + { 0x4b, "pc02_tex_03", g84_tex_sources }, + { 0x1a, "pc02_tex_04", g84_tex_sources }, + { 0x1b, "pc02_tex_05", g84_tex_sources }, + { 0x1c, "pc02_tex_06", g84_tex_sources }, + { 0x44, "pc02_zrop_00", nv50_zrop_sources }, + { 0x45, "pc02_zrop_01", nv50_zrop_sources }, + { 0x46, "pc02_zrop_02", nv50_zrop_sources }, + { 0x47, "pc02_zrop_03", nv50_zrop_sources }, + { 0x8c, "pc02_trailer" }, {} }, &nv40_perfctr_func }, { 0x20, (const struct nvkm_specsig[]) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c new file mode 100644 index 0000000000000..220a027534ef3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c @@ -0,0 +1,163 @@ +/* + * Copyright 2015 Nouveau project + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Samuel Pitoiset + */ +#include "nv40.h" + +const struct nvkm_specsrc +gt200_crop_sources[] = { + { 0x407008, (const struct nvkm_specmux[]) { + { 0x7, 0, "sel0", true }, + { 0x1f, 16, "sel1", true }, + {} + }, "pgraph_rop0_crop_pm_mux" }, + {} +}; + +const struct nvkm_specsrc +gt200_prop_sources[] = { + { 0x408750, (const struct nvkm_specmux[]) { + { 0x3f, 0, "sel", true }, + {} + }, "pgraph_tpc0_prop_pm_mux" }, + {} +}; + +const struct nvkm_specsrc +gt200_tex_sources[] = { + { 0x408508, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pgraph_tpc0_tex_unk08" }, + {} +}; + +static const struct nvkm_specdom +gt200_pm[] = { + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0xf0, (const struct nvkm_specsig[]) { + { 0xc9, "pc01_gr_idle" }, + { 0x84, "pc01_strmout_00" }, + { 0x85, "pc01_strmout_01" }, + { 0xde, "pc01_trast_00" }, + { 0xdf, "pc01_trast_01" }, + { 0xe0, "pc01_trast_02" }, + { 0xe1, "pc01_trast_03" }, + { 0xe4, "pc01_trast_04" }, + { 0xe5, "pc01_trast_05" }, + { 0x82, "pc01_vattr_00" }, + { 0x83, "pc01_vattr_01" }, + { 0x46, "pc01_vfetch_00", g84_vfetch_sources }, + { 0x47, "pc01_vfetch_01", g84_vfetch_sources }, + { 0x48, "pc01_vfetch_02", g84_vfetch_sources }, + { 0x49, "pc01_vfetch_03", g84_vfetch_sources }, + { 0x4a, "pc01_vfetch_04", g84_vfetch_sources }, + { 0x4b, "pc01_vfetch_05", g84_vfetch_sources }, + { 0x4c, "pc01_vfetch_06", g84_vfetch_sources }, + { 0x4d, "pc01_vfetch_07", g84_vfetch_sources }, + { 0x4e, "pc01_vfetch_08", g84_vfetch_sources }, + { 0x4f, "pc01_vfetch_09", g84_vfetch_sources }, + { 0x50, "pc01_vfetch_0a", g84_vfetch_sources }, + { 0x51, "pc01_vfetch_0b", g84_vfetch_sources }, + { 0x52, "pc01_vfetch_0c", g84_vfetch_sources }, + { 0x53, "pc01_vfetch_0d", g84_vfetch_sources }, + { 0x54, "pc01_vfetch_0e", g84_vfetch_sources }, + { 0x55, "pc01_vfetch_0f", g84_vfetch_sources }, + { 0x56, "pc01_vfetch_10", g84_vfetch_sources }, + { 0x57, "pc01_vfetch_11", g84_vfetch_sources }, + { 0x58, "pc01_vfetch_12", g84_vfetch_sources }, + { 0x59, "pc01_vfetch_13", g84_vfetch_sources }, + { 0x5a, "pc01_vfetch_14", g84_vfetch_sources }, + { 0x5b, "pc01_vfetch_15", g84_vfetch_sources }, + { 0x5c, "pc01_vfetch_16", g84_vfetch_sources }, + { 0x5d, "pc01_vfetch_17", g84_vfetch_sources }, + { 0x5e, "pc01_vfetch_18", g84_vfetch_sources }, + { 0x5f, "pc01_vfetch_19", g84_vfetch_sources }, + { 0x07, "pc01_zcull_00", nv50_zcull_sources }, + { 0x08, "pc01_zcull_01", nv50_zcull_sources }, + { 0x09, "pc01_zcull_02", nv50_zcull_sources }, + { 0x0a, "pc01_zcull_03", nv50_zcull_sources }, + { 0x0b, "pc01_zcull_04", nv50_zcull_sources }, + { 0x0c, "pc01_zcull_05", nv50_zcull_sources }, + + { 0xb0, "pc01_unk00" }, + { 0xec, "pc01_trailer" }, + {} + }, &nv40_perfctr_func }, + { 0xe0, (const struct nvkm_specsig[]) { + { 0x55, "pc02_crop_00", gt200_crop_sources }, + { 0x56, "pc02_crop_01", gt200_crop_sources }, + { 0x57, "pc02_crop_02", gt200_crop_sources }, + { 0x58, "pc02_crop_03", gt200_crop_sources }, + { 0x00, "pc02_prop_00", gt200_prop_sources }, + { 0x01, "pc02_prop_01", gt200_prop_sources }, + { 0x02, "pc02_prop_02", gt200_prop_sources }, + { 0x03, "pc02_prop_03", gt200_prop_sources }, + { 0x04, "pc02_prop_04", gt200_prop_sources }, + { 0x05, "pc02_prop_05", gt200_prop_sources }, + { 0x06, "pc02_prop_06", gt200_prop_sources }, + { 0x07, "pc02_prop_07", gt200_prop_sources }, + { 0x78, "pc02_tex_00", gt200_tex_sources }, + { 0x79, "pc02_tex_01", gt200_tex_sources }, + { 0x7a, "pc02_tex_02", gt200_tex_sources }, + { 0x7b, "pc02_tex_03", gt200_tex_sources }, + { 0x32, "pc02_tex_04", gt200_tex_sources }, + { 0x33, "pc02_tex_05", gt200_tex_sources }, + { 0x34, "pc02_tex_06", gt200_tex_sources }, + { 0x74, "pc02_zrop_00", nv50_zrop_sources }, + { 0x75, "pc02_zrop_01", nv50_zrop_sources }, + { 0x76, "pc02_zrop_02", nv50_zrop_sources }, + { 0x77, "pc02_zrop_03", nv50_zrop_sources }, + { 0xec, "pc02_trailer" }, + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &nv40_perfctr_func }, + {} +}; + +struct nvkm_oclass * +gt200_pm_oclass = &(struct nv40_pm_oclass) { + .base.handle = NV_ENGINE(PM, 0xa0), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = nv40_pm_ctor, + .dtor = _nvkm_pm_dtor, + .init = _nvkm_pm_init, + .fini = _nvkm_pm_fini, + }, + .doms = gt200_pm, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c index ab69ab5dfc290..b5542dc0d9dde 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c @@ -23,15 +23,95 @@ */ #include "nv40.h" +// TODO: check for GT200 +static const struct nvkm_specsrc +gt215_zcull_sources[] = { + { 0x4002ca4, (const struct nvkm_specmux[]) { + { 0x7fff, 0, "unk0" }, + { 0xff, 24, "unk24" }, + {} + }, "pgraph_zcull_pm_unka4" }, + {} +}; + static const struct nvkm_specdom gt215_pm[] = { { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { + { 0xcb, "pc01_gr_idle" }, + { 0x86, "pc01_strmout_00" }, + { 0x87, "pc01_strmout_01" }, + { 0xe0, "pc01_trast_00" }, + { 0xe1, "pc01_trast_01" }, + { 0xe2, "pc01_trast_02" }, + { 0xe3, "pc01_trast_03" }, + { 0xe6, "pc01_trast_04" }, + { 0xe7, "pc01_trast_05" }, + { 0x84, "pc01_vattr_00" }, + { 0x85, "pc01_vattr_01" }, + { 0x46, "pc01_vfetch_00", g84_vfetch_sources }, + { 0x47, "pc01_vfetch_01", g84_vfetch_sources }, + { 0x48, "pc01_vfetch_02", g84_vfetch_sources }, + { 0x49, "pc01_vfetch_03", g84_vfetch_sources }, + { 0x4a, "pc01_vfetch_04", g84_vfetch_sources }, + { 0x4b, "pc01_vfetch_05", g84_vfetch_sources }, + { 0x4c, "pc01_vfetch_06", g84_vfetch_sources }, + { 0x4d, "pc01_vfetch_07", g84_vfetch_sources }, + { 0x4e, "pc01_vfetch_08", g84_vfetch_sources }, + { 0x4f, "pc01_vfetch_09", g84_vfetch_sources }, + { 0x50, "pc01_vfetch_0a", g84_vfetch_sources }, + { 0x51, "pc01_vfetch_0b", g84_vfetch_sources }, + { 0x52, "pc01_vfetch_0c", g84_vfetch_sources }, + { 0x53, "pc01_vfetch_0d", g84_vfetch_sources }, + { 0x54, "pc01_vfetch_0e", g84_vfetch_sources }, + { 0x55, "pc01_vfetch_0f", g84_vfetch_sources }, + { 0x56, "pc01_vfetch_10", g84_vfetch_sources }, + { 0x57, "pc01_vfetch_11", g84_vfetch_sources }, + { 0x58, "pc01_vfetch_12", g84_vfetch_sources }, + { 0x59, "pc01_vfetch_13", g84_vfetch_sources }, + { 0x5a, "pc01_vfetch_14", g84_vfetch_sources }, + { 0x5b, "pc01_vfetch_15", g84_vfetch_sources }, + { 0x5c, "pc01_vfetch_16", g84_vfetch_sources }, + { 0x5d, "pc01_vfetch_17", g84_vfetch_sources }, + { 0x5e, "pc01_vfetch_18", g84_vfetch_sources }, + { 0x5f, "pc01_vfetch_19", g84_vfetch_sources }, + { 0x07, "pc01_zcull_00", gt215_zcull_sources }, + { 0x08, "pc01_zcull_01", gt215_zcull_sources }, + { 0x09, "pc01_zcull_02", gt215_zcull_sources }, + { 0x0a, "pc01_zcull_03", gt215_zcull_sources }, + { 0x0b, "pc01_zcull_04", gt215_zcull_sources }, + { 0x0c, "pc01_zcull_05", gt215_zcull_sources }, + { 0xb2, "pc01_unk00" }, + { 0xec, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0x20, (const struct nvkm_specsig[]) { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x64, "pc02_crop_00", gt200_crop_sources }, + { 0x65, "pc02_crop_01", gt200_crop_sources }, + { 0x66, "pc02_crop_02", gt200_crop_sources }, + { 0x67, "pc02_crop_03", gt200_crop_sources }, + { 0x00, "pc02_prop_00", gt200_prop_sources }, + { 0x01, "pc02_prop_01", gt200_prop_sources }, + { 0x02, "pc02_prop_02", gt200_prop_sources }, + { 0x03, "pc02_prop_03", gt200_prop_sources }, + { 0x04, "pc02_prop_04", gt200_prop_sources }, + { 0x05, "pc02_prop_05", gt200_prop_sources }, + { 0x06, "pc02_prop_06", gt200_prop_sources }, + { 0x07, "pc02_prop_07", gt200_prop_sources }, + { 0x80, "pc02_tex_00", gt200_tex_sources }, + { 0x81, "pc02_tex_01", gt200_tex_sources }, + { 0x82, "pc02_tex_02", gt200_tex_sources }, + { 0x83, "pc02_tex_03", gt200_tex_sources }, + { 0x3a, "pc02_tex_04", gt200_tex_sources }, + { 0x3b, "pc02_tex_05", gt200_tex_sources }, + { 0x3c, "pc02_tex_06", gt200_tex_sources }, + { 0x7c, "pc02_zrop_00", nv50_zrop_sources }, + { 0x7d, "pc02_zrop_01", nv50_zrop_sources }, + { 0x7e, "pc02_zrop_02", nv50_zrop_sources }, + { 0x7f, "pc02_zrop_03", nv50_zrop_sources }, + { 0xcc, "pc02_trailer" }, {} }, &nv40_perfctr_func }, { 0x20, (const struct nvkm_specsig[]) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c index 6af83b5d1b119..a778bc738ffc4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c @@ -23,22 +23,146 @@ */ #include "nv40.h" +const struct nvkm_specsrc +nv50_prop_sources[] = { + { 0x408e50, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_tpc0_prop_pm_mux" }, + {} +}; + +const struct nvkm_specsrc +nv50_zcull_sources[] = { + { 0x4002ca4, (const struct nvkm_specmux[]) { + { 0x7fff, 0, "unk0" }, + {} + }, "pgraph_zcull_pm_unka4" }, + {} +}; + +const struct nvkm_specsrc +nv50_zrop_sources[] = { + { 0x40708c, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0xf, 16, "sel1", true }, + {} + }, "pgraph_rop0_zrop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +nv50_crop_sources[] = { + { 0x407008, (const struct nvkm_specmux[]) { + { 0x7, 0, "sel0", true }, + { 0x7, 16, "sel1", true }, + {} + }, "pgraph_rop0_crop_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +nv50_tex_sources[] = { + { 0x408808, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pgraph_tpc0_tex_unk08" }, + {} +}; + +static const struct nvkm_specsrc +nv50_vfetch_sources[] = { + { 0x400c0c, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + {} + }, "pgraph_vfetch_unk0c" }, + {} +}; + static const struct nvkm_specdom nv50_pm[] = { - { 0x040, (const struct nvkm_specsig[]) { + { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x100, (const struct nvkm_specsig[]) { - { 0xc8, "gr_idle" }, + { 0xf0, (const struct nvkm_specsig[]) { + { 0xc8, "pc01_gr_idle" }, + { 0x7f, "pc01_strmout_00" }, + { 0x80, "pc01_strmout_01" }, + { 0xdc, "pc01_trast_00" }, + { 0xdd, "pc01_trast_01" }, + { 0xde, "pc01_trast_02" }, + { 0xdf, "pc01_trast_03" }, + { 0xe2, "pc01_trast_04" }, + { 0xe3, "pc01_trast_05" }, + { 0x7c, "pc01_vattr_00" }, + { 0x7d, "pc01_vattr_01" }, + { 0x26, "pc01_vfetch_00", nv50_vfetch_sources }, + { 0x27, "pc01_vfetch_01", nv50_vfetch_sources }, + { 0x28, "pc01_vfetch_02", nv50_vfetch_sources }, + { 0x29, "pc01_vfetch_03", nv50_vfetch_sources }, + { 0x2a, "pc01_vfetch_04", nv50_vfetch_sources }, + { 0x2b, "pc01_vfetch_05", nv50_vfetch_sources }, + { 0x2c, "pc01_vfetch_06", nv50_vfetch_sources }, + { 0x2d, "pc01_vfetch_07", nv50_vfetch_sources }, + { 0x2e, "pc01_vfetch_08", nv50_vfetch_sources }, + { 0x2f, "pc01_vfetch_09", nv50_vfetch_sources }, + { 0x30, "pc01_vfetch_0a", nv50_vfetch_sources }, + { 0x31, "pc01_vfetch_0b", nv50_vfetch_sources }, + { 0x32, "pc01_vfetch_0c", nv50_vfetch_sources }, + { 0x33, "pc01_vfetch_0d", nv50_vfetch_sources }, + { 0x34, "pc01_vfetch_0e", nv50_vfetch_sources }, + { 0x35, "pc01_vfetch_0f", nv50_vfetch_sources }, + { 0x36, "pc01_vfetch_10", nv50_vfetch_sources }, + { 0x37, "pc01_vfetch_11", nv50_vfetch_sources }, + { 0x38, "pc01_vfetch_12", nv50_vfetch_sources }, + { 0x39, "pc01_vfetch_13", nv50_vfetch_sources }, + { 0x3a, "pc01_vfetch_14", nv50_vfetch_sources }, + { 0x3b, "pc01_vfetch_15", nv50_vfetch_sources }, + { 0x3c, "pc01_vfetch_16", nv50_vfetch_sources }, + { 0x3d, "pc01_vfetch_17", nv50_vfetch_sources }, + { 0x3e, "pc01_vfetch_18", nv50_vfetch_sources }, + { 0x3f, "pc01_vfetch_19", nv50_vfetch_sources }, + { 0x20, "pc01_zcull_00", nv50_zcull_sources }, + { 0x21, "pc01_zcull_01", nv50_zcull_sources }, + { 0x22, "pc01_zcull_02", nv50_zcull_sources }, + { 0x23, "pc01_zcull_03", nv50_zcull_sources }, + { 0x24, "pc01_zcull_04", nv50_zcull_sources }, + { 0x25, "pc01_zcull_05", nv50_zcull_sources }, + { 0xae, "pc01_unk00" }, + { 0xee, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0x100, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { + { 0x52, "pc02_crop_00", nv50_crop_sources }, + { 0x53, "pc02_crop_01", nv50_crop_sources }, + { 0x54, "pc02_crop_02", nv50_crop_sources }, + { 0x55, "pc02_crop_03", nv50_crop_sources }, + { 0x00, "pc02_prop_00", nv50_prop_sources }, + { 0x01, "pc02_prop_01", nv50_prop_sources }, + { 0x02, "pc02_prop_02", nv50_prop_sources }, + { 0x03, "pc02_prop_03", nv50_prop_sources }, + { 0x04, "pc02_prop_04", nv50_prop_sources }, + { 0x05, "pc02_prop_05", nv50_prop_sources }, + { 0x06, "pc02_prop_06", nv50_prop_sources }, + { 0x07, "pc02_prop_07", nv50_prop_sources }, + { 0x70, "pc02_tex_00", nv50_tex_sources }, + { 0x71, "pc02_tex_01", nv50_tex_sources }, + { 0x72, "pc02_tex_02", nv50_tex_sources }, + { 0x73, "pc02_tex_03", nv50_tex_sources }, + { 0x40, "pc02_tex_04", nv50_tex_sources }, + { 0x41, "pc02_tex_05", nv50_tex_sources }, + { 0x42, "pc02_tex_06", nv50_tex_sources }, + { 0x6c, "pc02_zrop_00", nv50_zrop_sources }, + { 0x6d, "pc02_zrop_01", nv50_zrop_sources }, + { 0x6e, "pc02_zrop_02", nv50_zrop_sources }, + { 0x6f, "pc02_zrop_03", nv50_zrop_sources }, + { 0xee, "pc02_trailer" }, {} }, &nv40_perfctr_func }, - { 0x020, (const struct nvkm_specsig[]) { + { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, - { 0x040, (const struct nvkm_specsig[]) { + { 0x20, (const struct nvkm_specsig[]) { {} }, &nv40_perfctr_func }, {} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index da419c1d5481f..5bcc739ae03c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -44,6 +44,14 @@ struct nvkm_perfsrc { bool enable; }; +extern const struct nvkm_specsrc nv50_prop_sources[]; +extern const struct nvkm_specsrc nv50_zcull_sources[]; +extern const struct nvkm_specsrc nv50_zrop_sources[]; +extern const struct nvkm_specsrc g84_vfetch_sources[]; +extern const struct nvkm_specsrc gt200_crop_sources[]; +extern const struct nvkm_specsrc gt200_prop_sources[]; +extern const struct nvkm_specsrc gt200_tex_sources[]; + struct nvkm_specsig { u8 signal; const char *name; -- GitLab From 2d4b94b95f30b0a4244fce4866583094d991c0ec Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 14 Jun 2015 12:10:59 +1000 Subject: [PATCH 5286/7006] drm/nouveau/pm: swap perfmon/perfdom code to avoid forward decl in next commit Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 350 +++++++++--------- 1 file changed, 175 insertions(+), 175 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index a4bb6fe5e90b5..0e1536d5c7770 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -185,181 +185,6 @@ nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) return 0; } -/******************************************************************************* - * Perfmon object classes - ******************************************************************************/ -static int -nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_perfmon_query_domain_v0 v0; - } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfdom *dom; - u8 domain_nr; - int di, ret; - - nv_ioctl(object, "perfmon query domain size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfmon domain vers %d iter %02x\n", - args->v0.version, args->v0.iter); - di = (args->v0.iter & 0xff) - 1; - } else - return ret; - - domain_nr = nvkm_pm_count_perfdom(ppm); - if (di >= (int)domain_nr) - return -EINVAL; - - if (di >= 0) { - dom = nvkm_perfdom_find(ppm, di); - if (dom == NULL) - return -EINVAL; - - args->v0.id = di; - args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); - - /* Currently only global counters (PCOUNTER) are implemented - * but this will be different for local counters (MP). */ - args->v0.counter_nr = 4; - } - - if (++di < domain_nr) { - args->v0.iter = ++di; - return 0; - } - - args->v0.iter = 0xff; - return 0; -} - -static int -nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_perfmon_query_signal_v0 v0; - } *args = data; - struct nvkm_device *device = nv_device(object); - struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfdom *dom; - struct nvkm_perfsig *sig; - const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); - const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); - int ret, si; - - nv_ioctl(object, "perfmon query signal size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, - "perfmon query signal vers %d dom %d iter %04x\n", - args->v0.version, args->v0.domain, args->v0.iter); - si = (args->v0.iter & 0xffff) - 1; - } else - return ret; - - dom = nvkm_perfdom_find(ppm, args->v0.domain); - if (dom == NULL || si >= (int)dom->signal_nr) - return -EINVAL; - - if (si >= 0) { - sig = &dom->signal[si]; - if (raw || !sig->name) { - snprintf(args->v0.name, sizeof(args->v0.name), - "/%s/%02x", dom->name, si); - } else { - strncpy(args->v0.name, sig->name, - sizeof(args->v0.name)); - } - - args->v0.signal = si; - args->v0.source_nr = nvkm_perfsig_count_perfsrc(sig); - } - - while (++si < dom->signal_nr) { - if (all || dom->signal[si].name) { - args->v0.iter = ++si; - return 0; - } - } - - args->v0.iter = 0xffff; - return 0; -} - -static int -nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) -{ - union { - struct nvif_perfmon_query_source_v0 v0; - } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; - struct nvkm_perfdom *dom = NULL; - struct nvkm_perfsig *sig; - struct nvkm_perfsrc *src; - u8 source_nr = 0; - int si, ret; - - nv_ioctl(object, "perfmon query source size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, - "perfmon source vers %d dom %d sig %02x iter %02x\n", - args->v0.version, args->v0.domain, args->v0.signal, - args->v0.iter); - si = (args->v0.iter & 0xff) - 1; - } else - return ret; - - sig = nvkm_perfsig_find(ppm, args->v0.domain, args->v0.signal, &dom); - if (!sig) - return -EINVAL; - - source_nr = nvkm_perfsig_count_perfsrc(sig); - if (si >= (int)source_nr) - return -EINVAL; - - if (si >= 0) { - src = nvkm_perfsrc_find(ppm, sig, sig->source[si]); - if (!src) - return -EINVAL; - - args->v0.source = sig->source[si]; - args->v0.mask = src->mask; - strncpy(args->v0.name, src->name, sizeof(args->v0.name)); - } - - if (++si < source_nr) { - args->v0.iter = ++si; - return 0; - } - - args->v0.iter = 0xff; - return 0; -} - -static int -nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - switch (mthd) { - case NVIF_PERFMON_V0_QUERY_DOMAIN: - return nvkm_perfmon_mthd_query_domain(object, data, size); - case NVIF_PERFMON_V0_QUERY_SIGNAL: - return nvkm_perfmon_mthd_query_signal(object, data, size); - case NVIF_PERFMON_V0_QUERY_SOURCE: - return nvkm_perfmon_mthd_query_source(object, data, size); - default: - break; - } - return -EINVAL; -} - -static struct nvkm_ofuncs -nvkm_perfmon_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, - .mthd = nvkm_perfmon_mthd, -}; - /******************************************************************************* * Perfdom object classes ******************************************************************************/ @@ -585,6 +410,181 @@ nvkm_perfdom_ofuncs = { .mthd = nvkm_perfdom_mthd, }; +/******************************************************************************* + * Perfmon object classes + ******************************************************************************/ +static int +nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfmon_query_domain_v0 v0; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom; + u8 domain_nr; + int di, ret; + + nv_ioctl(object, "perfmon query domain size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, "perfmon domain vers %d iter %02x\n", + args->v0.version, args->v0.iter); + di = (args->v0.iter & 0xff) - 1; + } else + return ret; + + domain_nr = nvkm_pm_count_perfdom(ppm); + if (di >= (int)domain_nr) + return -EINVAL; + + if (di >= 0) { + dom = nvkm_perfdom_find(ppm, di); + if (dom == NULL) + return -EINVAL; + + args->v0.id = di; + args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); + + /* Currently only global counters (PCOUNTER) are implemented + * but this will be different for local counters (MP). */ + args->v0.counter_nr = 4; + } + + if (++di < domain_nr) { + args->v0.iter = ++di; + return 0; + } + + args->v0.iter = 0xff; + return 0; +} + +static int +nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfmon_query_signal_v0 v0; + } *args = data; + struct nvkm_device *device = nv_device(object); + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom; + struct nvkm_perfsig *sig; + const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); + const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); + int ret, si; + + nv_ioctl(object, "perfmon query signal size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, + "perfmon query signal vers %d dom %d iter %04x\n", + args->v0.version, args->v0.domain, args->v0.iter); + si = (args->v0.iter & 0xffff) - 1; + } else + return ret; + + dom = nvkm_perfdom_find(ppm, args->v0.domain); + if (dom == NULL || si >= (int)dom->signal_nr) + return -EINVAL; + + if (si >= 0) { + sig = &dom->signal[si]; + if (raw || !sig->name) { + snprintf(args->v0.name, sizeof(args->v0.name), + "/%s/%02x", dom->name, si); + } else { + strncpy(args->v0.name, sig->name, + sizeof(args->v0.name)); + } + + args->v0.signal = si; + args->v0.source_nr = nvkm_perfsig_count_perfsrc(sig); + } + + while (++si < dom->signal_nr) { + if (all || dom->signal[si].name) { + args->v0.iter = ++si; + return 0; + } + } + + args->v0.iter = 0xffff; + return 0; +} + +static int +nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) +{ + union { + struct nvif_perfmon_query_source_v0 v0; + } *args = data; + struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_perfdom *dom = NULL; + struct nvkm_perfsig *sig; + struct nvkm_perfsrc *src; + u8 source_nr = 0; + int si, ret; + + nv_ioctl(object, "perfmon query source size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nv_ioctl(object, + "perfmon source vers %d dom %d sig %02x iter %02x\n", + args->v0.version, args->v0.domain, args->v0.signal, + args->v0.iter); + si = (args->v0.iter & 0xff) - 1; + } else + return ret; + + sig = nvkm_perfsig_find(ppm, args->v0.domain, args->v0.signal, &dom); + if (!sig) + return -EINVAL; + + source_nr = nvkm_perfsig_count_perfsrc(sig); + if (si >= (int)source_nr) + return -EINVAL; + + if (si >= 0) { + src = nvkm_perfsrc_find(ppm, sig, sig->source[si]); + if (!src) + return -EINVAL; + + args->v0.source = sig->source[si]; + args->v0.mask = src->mask; + strncpy(args->v0.name, src->name, sizeof(args->v0.name)); + } + + if (++si < source_nr) { + args->v0.iter = ++si; + return 0; + } + + args->v0.iter = 0xff; + return 0; +} + +static int +nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + switch (mthd) { + case NVIF_PERFMON_V0_QUERY_DOMAIN: + return nvkm_perfmon_mthd_query_domain(object, data, size); + case NVIF_PERFMON_V0_QUERY_SIGNAL: + return nvkm_perfmon_mthd_query_signal(object, data, size); + case NVIF_PERFMON_V0_QUERY_SOURCE: + return nvkm_perfmon_mthd_query_source(object, data, size); + default: + break; + } + return -EINVAL; +} + +static struct nvkm_ofuncs +nvkm_perfmon_ofuncs = { + .ctor = _nvkm_object_ctor, + .dtor = nvkm_object_destroy, + .init = nvkm_object_init, + .fini = nvkm_object_fini, + .mthd = nvkm_perfmon_mthd, +}; + struct nvkm_oclass nvkm_pm_sclass[] = { { -- GitLab From f21950ea35c86be79c293b199fe48b5152ec8311 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Sun, 14 Jun 2015 12:20:37 +1000 Subject: [PATCH 5287/7006] drm/nouveau/pm: stack perfdom class under perfmon Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 0e1536d5c7770..f505a11a938a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -576,12 +576,32 @@ nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } +static struct nvkm_oclass +nvkm_perfmon_sclass[] = { + { .handle = NVIF_IOCTL_NEW_V0_PERFDOM, + .ofuncs = &nvkm_perfdom_ofuncs, + }, + {} +}; + +static int +nvkm_perfmon_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_parent *perfmon; + int ret = nvkm_parent_create(parent, engine, oclass, 0, + nvkm_perfmon_sclass, 0, &perfmon); + *pobject = perfmon ? &perfmon->object : NULL; + return ret; +} + static struct nvkm_ofuncs nvkm_perfmon_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .ctor = nvkm_perfmon_ctor, + .dtor = _nvkm_parent_dtor, + .init = _nvkm_parent_init, + .fini = _nvkm_parent_fini, .mthd = nvkm_perfmon_mthd, }; @@ -591,9 +611,6 @@ nvkm_pm_sclass[] = { .handle = NVIF_IOCTL_NEW_V0_PERFMON, .ofuncs = &nvkm_perfmon_ofuncs, }, - { .handle = NVIF_IOCTL_NEW_V0_PERFDOM, - .ofuncs = &nvkm_perfdom_ofuncs, - }, {}, }; @@ -622,6 +639,13 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_perfctx *ctx; int ret; + /* no context needed for perfdom objects... */ + if (nv_mclass(parent) != NV_DEVICE) { + atomic_inc(&parent->refcount); + *pobject = parent; + return 1; + } + ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0, 0, 0, &ctx); *pobject = nv_object(ctx); if (ret) -- GitLab From 060f50e3b100b8f51fbf165de48c2ea097ff7390 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 14 Jun 2015 13:33:54 +0200 Subject: [PATCH 5288/7006] drm/nouveau/pm/gf100: allow to share GPC, HUB and PART domains Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 2 +- .../drm/nouveau/nvkm/engine/device/gf100.c | 18 +++++++-------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 22 +++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.h | 11 ++++++++++ 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index 82f1c7f5243a1..ce5d93ec88862 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -26,7 +26,7 @@ extern struct nvkm_oclass *nv50_pm_oclass; extern struct nvkm_oclass *g84_pm_oclass; extern struct nvkm_oclass *gt200_pm_oclass; extern struct nvkm_oclass *gt215_pm_oclass; -extern struct nvkm_oclass gf100_pm_oclass; +extern struct nvkm_oclass *gf100_pm_oclass; extern struct nvkm_oclass gk104_pm_oclass; extern struct nvkm_oclass gk110_pm_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 82b38d7e97301..84a6abb17880e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -90,7 +90,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: device->cname = "GF104"; @@ -123,7 +123,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: device->cname = "GF106"; @@ -155,7 +155,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: device->cname = "GF114"; @@ -188,7 +188,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: device->cname = "GF116"; @@ -220,7 +220,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: device->cname = "GF108"; @@ -252,7 +252,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc8: device->cname = "GF110"; @@ -285,7 +285,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: device->cname = "GF119"; @@ -317,7 +317,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd7: device->cname = "GF117"; @@ -347,7 +347,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; default: nv_fatal(device, "unknown Fermi chipset\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index edab97aa918e0..64db47e3742b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -97,11 +97,12 @@ gf100_pm_fini(struct nvkm_object *object, bool suspend) return nvkm_pm_fini(&priv->base, suspend); } -static int +int gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct gf100_pm_oclass *mclass = (void *)oclass; struct gf100_pm_priv *priv; u32 mask; int ret; @@ -113,7 +114,7 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* HUB */ ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, - gf100_pm_hub); + mclass->doms_hub); if (ret) return ret; @@ -123,7 +124,7 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mask &= ~nv_rd32(priv, 0x022584); ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000, - 0x1000, 0x200, gf100_pm_gpc); + 0x1000, 0x200, mclass->doms_gpc); if (ret) return ret; @@ -133,7 +134,7 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mask &= ~nv_rd32(priv, 0x0225c8); ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000, - 0x1000, 0x200, gf100_pm_part); + 0x1000, 0x200, mclass->doms_part); if (ret) return ret; @@ -142,13 +143,16 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass -gf100_pm_oclass = { - .handle = NV_ENGINE(PM, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { +struct nvkm_oclass * +gf100_pm_oclass = &(struct gf100_pm_oclass) { + .base.handle = NV_ENGINE(PM, 0xc0), + .base.ofuncs = &(struct nvkm_ofuncs) { .ctor = gf100_pm_ctor, .dtor = _nvkm_pm_dtor, .init = _nvkm_pm_init, .fini = gf100_pm_fini, }, -}; + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf100_pm_hub, + .doms_part = gf100_pm_part, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index 6a01fc7fec6f0..51b176feb4299 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -2,10 +2,21 @@ #define __NVKM_PM_NVC0_H__ #include "priv.h" +struct gf100_pm_oclass { + struct nvkm_oclass base; + const struct nvkm_specdom *doms_hub; + const struct nvkm_specdom *doms_gpc; + const struct nvkm_specdom *doms_part; +}; + struct gf100_pm_priv { struct nvkm_pm base; }; +int gf100_pm_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **pobject); + struct gf100_pm_cntr { struct nvkm_perfctr base; }; -- GitLab From 94a2ef69aa0c3612577ab1a6f5c248b206118e68 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 14 Jun 2015 13:33:55 +0200 Subject: [PATCH 5289/7006] drm/nouveau/pm/gf100: add compute signals/sources These signals and sources have been reverse engineered from CUPTI (Linux). Graphics signals exposed by PerfKit (Windows only) will be added later. I need to reverse engineer them and it's a bit painful. This commit also adds a new class for GF108 and GF117. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 2 + .../drm/nouveau/nvkm/engine/device/gf100.c | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 96 ++++++++++++++++++- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.h | 5 + .../gpu/drm/nouveau/nvkm/engine/pm/gf108.c | 84 ++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/pm/gf117.c | 92 ++++++++++++++++++ 7 files changed, 282 insertions(+), 5 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index ce5d93ec88862..ed36daf345782 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -27,6 +27,8 @@ extern struct nvkm_oclass *g84_pm_oclass; extern struct nvkm_oclass *gt200_pm_oclass; extern struct nvkm_oclass *gt215_pm_oclass; extern struct nvkm_oclass *gf100_pm_oclass; +extern struct nvkm_oclass *gf108_pm_oclass; +extern struct nvkm_oclass *gf117_pm_oclass; extern struct nvkm_oclass gk104_pm_oclass; extern struct nvkm_oclass gk110_pm_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 84a6abb17880e..65b151da83178 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -252,7 +252,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: device->cname = "GF110"; @@ -317,7 +317,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: device->cname = "GF117"; @@ -347,7 +347,7 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; default: nv_fatal(device, "unknown Fermi chipset\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild index cc01048a8cabe..4fadf55f51f9f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild @@ -5,5 +5,7 @@ nvkm-y += nvkm/engine/pm/g84.o nvkm-y += nvkm/engine/pm/gt200.o nvkm-y += nvkm/engine/pm/gt215.o nvkm-y += nvkm/engine/pm/gf100.o +nvkm-y += nvkm/engine/pm/gf108.o +nvkm-y += nvkm/engine/pm/gf117.o nvkm-y += nvkm/engine/pm/gk104.o nvkm-y += nvkm/engine/pm/gk110.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 64db47e3742b6..b40c2188d0037 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -23,18 +23,110 @@ */ #include "gf100.h" +const struct nvkm_specsrc +gf100_pmfb_sources[] = { + { 0x140028, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + { 0x7, 16, "unk16" }, + { 0x3, 24, "unk24" }, + { 0x2, 29, "unk29" }, + {} + }, "pmfb0_pm_unk28" }, + {} +}; + +static const struct nvkm_specsrc +gf100_l1_sources[] = { + { 0x5044a8, (const struct nvkm_specmux[]) { + { 0x3f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_l1_pm_mux" }, + {} +}; + +static const struct nvkm_specsrc +gf100_pbfb_sources[] = { + { 0x10f100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0xf, 4, "unk4" }, + { 0x3, 8, "unk8" }, + {} + }, "pbfb_broadcast_pm_unk100" }, + {} +}; + +static const struct nvkm_specsrc +gf100_tex_sources[] = { + { 0x5042c0, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x7, 8, "sel1", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_mux_c_d" }, + { 0x5042c8, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_unkc8" }, + {} +}; + +static const struct nvkm_specsrc +gf100_unk400_sources[] = { + { 0x50440c, (const struct nvkm_specmux[]) { + { 0x3f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_unk400_pm_mux" }, + {} +}; + static const struct nvkm_specdom gf100_pm_hub[] = { {} }; -static const struct nvkm_specdom +const struct nvkm_specdom gf100_pm_gpc[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x00, "gpc00_l1_00", gf100_l1_sources }, + { 0x01, "gpc00_l1_01", gf100_l1_sources }, + { 0x02, "gpc00_l1_02", gf100_l1_sources }, + { 0x03, "gpc00_l1_03", gf100_l1_sources }, + { 0x05, "gpc00_l1_04", gf100_l1_sources }, + { 0x06, "gpc00_l1_05", gf100_l1_sources }, + { 0x0a, "gpc00_tex_00", gf100_tex_sources }, + { 0x0b, "gpc00_tex_01", gf100_tex_sources }, + { 0x0c, "gpc00_tex_02", gf100_tex_sources }, + { 0x0d, "gpc00_tex_03", gf100_tex_sources }, + { 0x0e, "gpc00_tex_04", gf100_tex_sources }, + { 0x0e, "gpc00_tex_05", gf100_tex_sources }, + { 0x0f, "gpc00_tex_06", gf100_tex_sources }, + { 0x10, "gpc00_tex_07", gf100_tex_sources }, + { 0x11, "gpc00_tex_08", gf100_tex_sources }, + { 0x12, "gpc00_tex_09", gf100_tex_sources }, + { 0x26, "gpc00_unk400_00", gf100_unk400_sources }, + {} + }, &gf100_perfctr_func }, {} }; -static const struct nvkm_specdom +const struct nvkm_specdom gf100_pm_part[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x0f, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x10, "part00_pbfb_01", gf100_pbfb_sources }, + { 0x21, "part00_pmfb_00", gf100_pmfb_sources }, + { 0x04, "part00_pmfb_01", gf100_pmfb_sources }, + { 0x00, "part00_pmfb_02", gf100_pmfb_sources }, + { 0x02, "part00_pmfb_03", gf100_pmfb_sources }, + { 0x01, "part00_pmfb_04", gf100_pmfb_sources }, + { 0x2e, "part00_pmfb_05", gf100_pmfb_sources }, + { 0x2f, "part00_pmfb_06", gf100_pmfb_sources }, + { 0x1b, "part00_pmfb_07", gf100_pmfb_sources }, + { 0x1c, "part00_pmfb_08", gf100_pmfb_sources }, + { 0x1d, "part00_pmfb_09", gf100_pmfb_sources }, + { 0x1e, "part00_pmfb_0a", gf100_pmfb_sources }, + { 0x1f, "part00_pmfb_0b", gf100_pmfb_sources }, + {} + }, &gf100_perfctr_func }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index 51b176feb4299..40ced895bad33 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -23,4 +23,9 @@ struct gf100_pm_cntr { extern const struct nvkm_funcdom gf100_perfctr_func; int gf100_pm_fini(struct nvkm_object *, bool); + +extern const struct nvkm_specdom gf100_pm_gpc[]; + +extern const struct nvkm_specsrc gf100_pmfb_sources[]; + #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c new file mode 100644 index 0000000000000..a74c68520ea72 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Samuel Pitoiset + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Samuel Pitoiset + */ +#include "gf100.h" + +static const struct nvkm_specsrc +gf108_pbfb_sources[] = { + { 0x110100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0xf, 4, "unk4" }, + { 0x3, 8, "unk8" }, + {} + }, "pbfb0_pm_unk100" }, + { 0x111100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0xf, 4, "unk4" }, + { 0x3, 8, "unk8" }, + {} + }, "pbfb1_pm_unk100" }, + {} +}; + +static const struct nvkm_specdom +gf108_pm_hub[] = { + {} +}; + +static const struct nvkm_specdom +gf108_pm_part[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x14, "part00_pbfb_00", gf108_pbfb_sources }, + { 0x15, "part00_pbfb_01", gf108_pbfb_sources }, + { 0x20, "part00_pbfb_02", gf108_pbfb_sources }, + { 0x21, "part00_pbfb_03", gf108_pbfb_sources }, + { 0x01, "part00_pmfb_00", gf100_pmfb_sources }, + { 0x04, "part00_pmfb_01", gf100_pmfb_sources }, + { 0x05, "part00_pmfb_02", gf100_pmfb_sources}, + { 0x07, "part00_pmfb_03", gf100_pmfb_sources }, + { 0x0d, "part00_pmfb_04", gf100_pmfb_sources }, + { 0x12, "part00_pmfb_05", gf100_pmfb_sources }, + { 0x13, "part00_pmfb_06", gf100_pmfb_sources }, + { 0x2c, "part00_pmfb_07", gf100_pmfb_sources }, + { 0x2d, "part00_pmfb_08", gf100_pmfb_sources }, + { 0x2e, "part00_pmfb_09", gf100_pmfb_sources }, + { 0x2f, "part00_pmfb_0a", gf100_pmfb_sources }, + { 0x30, "part00_pmfb_0b", gf100_pmfb_sources }, + {} + }, &gf100_perfctr_func }, + {} +}; + +struct nvkm_oclass * +gf108_pm_oclass = &(struct gf100_pm_oclass) { + .base.handle = NV_ENGINE(PM, 0xc1), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf100_pm_ctor, + .dtor = _nvkm_pm_dtor, + .init = _nvkm_pm_init, + .fini = gf100_pm_fini, + }, + .doms_hub = gf108_pm_hub, + .doms_gpc = gf100_pm_gpc, + .doms_part = gf108_pm_part, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c new file mode 100644 index 0000000000000..911ff3f19990e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c @@ -0,0 +1,92 @@ +/* + * Copyright 2015 Samuel Pitoiset + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Samuel Pitoiset + */ +#include "gf100.h" + +static const struct nvkm_specsrc +gf117_pmfb_sources[] = { + { 0x140028, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + { 0x7, 16, "unk16" }, + { 0x3, 24, "unk24" }, + { 0x2, 28, "unk28" }, + {} + }, "pmfb0_pm_unk28" }, + { 0x14125c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp0_pm_unk25c" }, + {} +}; + +static const struct nvkm_specsrc +gf117_pbfb_sources[] = { + { 0x110100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0xf, 4, "unk4" }, + { 0x3, 8, "unk8" }, + {} + }, "pbfb0_pm_unk100" }, + {} +}; + +static const struct nvkm_specdom +gf117_pm_hub[] = { + {} +}; + +static const struct nvkm_specdom +gf117_pm_part[] = { + { 0xe0, (const struct nvkm_specsig[]) { + { 0x00, "part00_pbfb_00", gf117_pbfb_sources }, + { 0x01, "part00_pbfb_01", gf117_pbfb_sources }, + { 0x12, "part00_pmfb_00", gf117_pmfb_sources }, + { 0x15, "part00_pmfb_01", gf117_pmfb_sources }, + { 0x16, "part00_pmfb_02", gf117_pmfb_sources }, + { 0x18, "part00_pmfb_03", gf117_pmfb_sources }, + { 0x1e, "part00_pmfb_04", gf117_pmfb_sources }, + { 0x23, "part00_pmfb_05", gf117_pmfb_sources }, + { 0x24, "part00_pmfb_06", gf117_pmfb_sources }, + { 0x0c, "part00_pmfb_07", gf117_pmfb_sources }, + { 0x0d, "part00_pmfb_08", gf117_pmfb_sources }, + { 0x0e, "part00_pmfb_09", gf117_pmfb_sources }, + { 0x0f, "part00_pmfb_0a", gf117_pmfb_sources }, + { 0x10, "part00_pmfb_0b", gf117_pmfb_sources }, + {} + }, &gf100_perfctr_func }, + {} +}; + +struct nvkm_oclass * +gf117_pm_oclass = &(struct gf100_pm_oclass) { + .base.handle = NV_ENGINE(PM, 0xd7), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf100_pm_ctor, + .dtor = _nvkm_pm_dtor, + .init = _nvkm_pm_init, + .fini = gf100_pm_fini, + }, + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf117_pm_hub, + .doms_part = gf117_pm_part, +}.base; -- GitLab From eb94345a93204f0d7d7e0809dde329977522aec0 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 14 Jun 2015 13:50:05 +0200 Subject: [PATCH 5290/7006] drm/nouveau/pm: fix signals/sources for GT200+ Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c | 3 +-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c index 220a027534ef3..e92f9c711bccf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c @@ -26,7 +26,7 @@ const struct nvkm_specsrc gt200_crop_sources[] = { { 0x407008, (const struct nvkm_specmux[]) { - { 0x7, 0, "sel0", true }, + { 0xf, 0, "sel0", true }, { 0x1f, 16, "sel1", true }, {} }, "pgraph_rop0_crop_pm_mux" }, @@ -45,7 +45,7 @@ gt200_prop_sources[] = { const struct nvkm_specsrc gt200_tex_sources[] = { { 0x408508, (const struct nvkm_specmux[]) { - { 0x3fff, 0, "unk0" }, + { 0xfffff, 0, "unk0" }, {} }, "pgraph_tpc0_tex_unk08" }, {} @@ -94,7 +94,7 @@ gt200_pm[] = { { 0x5d, "pc01_vfetch_17", g84_vfetch_sources }, { 0x5e, "pc01_vfetch_18", g84_vfetch_sources }, { 0x5f, "pc01_vfetch_19", g84_vfetch_sources }, - { 0x07, "pc01_zcull_00", nv50_zcull_sources }, + { 0x07, "pc01_zcull_00", nv50_zcull_sources }, { 0x08, "pc01_zcull_01", nv50_zcull_sources }, { 0x09, "pc01_zcull_02", nv50_zcull_sources }, { 0x0a, "pc01_zcull_03", nv50_zcull_sources }, @@ -105,7 +105,7 @@ gt200_pm[] = { { 0xec, "pc01_trailer" }, {} }, &nv40_perfctr_func }, - { 0xe0, (const struct nvkm_specsig[]) { + { 0xf0, (const struct nvkm_specsig[]) { { 0x55, "pc02_crop_00", gt200_crop_sources }, { 0x56, "pc02_crop_01", gt200_crop_sources }, { 0x57, "pc02_crop_02", gt200_crop_sources }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c index b5542dc0d9dde..f5eae63d9f48d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c @@ -23,10 +23,9 @@ */ #include "nv40.h" -// TODO: check for GT200 static const struct nvkm_specsrc gt215_zcull_sources[] = { - { 0x4002ca4, (const struct nvkm_specmux[]) { + { 0x402ca4, (const struct nvkm_specmux[]) { { 0x7fff, 0, "unk0" }, { 0xff, 24, "unk24" }, {} -- GitLab From d4a312dc90a7c1079133b038aec0120ee9e3d0ce Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 14 Jun 2015 13:50:06 +0200 Subject: [PATCH 5291/7006] drm/nouveau/pm: some fixes related to sources Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index f505a11a938a9..7866e220b66fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -154,6 +154,8 @@ nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) /* enable the source */ nv_mask(ppm, src->addr, mask, value); + nv_debug(ppm, "enabled source 0x%08x 0x%08x 0x%08x\n", + src->addr, mask, value); } } return 0; @@ -165,6 +167,7 @@ nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; + u32 mask; int i, j; for (i = 0; i < 4 && ctr->signal[i]; i++) { @@ -178,8 +181,16 @@ nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) if (!src) return -EINVAL; + /* unset enable bit if needed */ + mask = 0x00000000; + if (src->enable) + mask = 0x80000000; + mask |= (src->mask << src->shift); + /* disable the source */ - nv_mask(ppm, src->addr, src->mask << src->shift, 0); + nv_mask(ppm, src->addr, mask, 0); + nv_debug(ppm, "disabled source 0x%08x 0x%08x\n", + src->addr, mask); } } return 0; @@ -309,7 +320,7 @@ nvkm_perfdom_dtor(struct nvkm_object *object) } static int -nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, +nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, uint8_t domain, struct nvkm_perfsig *signal[4], uint64_t source[4][8], uint16_t logic_op, struct nvkm_perfctr **pctr) { @@ -323,6 +334,7 @@ nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, if (!ctr) return -ENOMEM; + ctr->domain = domain; ctr->logic_op = logic_op; ctr->slot = slot; for (i = 0; i < 4; i++) { @@ -361,7 +373,7 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (c = 0; c < ARRAY_SIZE(args->v0.ctr); c++) { struct nvkm_perfsig *sig[4] = {}; - u64 src[4][8]; + u64 src[4][8] = {}; for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) { sig[s] = nvkm_perfsig_find(ppm, args->v0.domain, @@ -378,11 +390,10 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } } - ret = nvkm_perfctr_new(sdom, c, sig, src, + ret = nvkm_perfctr_new(sdom, c, args->v0.domain, sig, src, args->v0.ctr[c].logic_op, &ctr[c]); if (ret) return ret; - ctr[c]->domain = args->v0.domain; } if (!sdom) -- GitLab From 85fa319d8a5240bab2e4123cfc9178bff55694ca Mon Sep 17 00:00:00 2001 From: Wei Ni Date: Tue, 16 Jun 2015 17:35:12 +0800 Subject: [PATCH 5292/7006] drm/nouveau/drm/nouveau/clk: fix tstate to pstate calculation According to the tstate calculation in nvkm_clk_tstate(), the range of tstate is from -(clk->state_nr - 1) to 0, it mean the tstate is negative value. But in nvkm_pstate_work(), it use (clk->state_nr - 1 - clk->tstate) to limit pstate, it's not correct. This patch fix it to use (clk->state_nr - 1 + clk->tstate) to limit pstate. Signed-off-by: Wei Ni Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 39a83d82e0cd9..77a0ab5ca3b01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -214,7 +214,7 @@ nvkm_pstate_work(struct work_struct *work) pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; if (clk->state_nr && pstate != -1) { pstate = (pstate < 0) ? clk->astate : pstate; - pstate = min(pstate, clk->state_nr - 1 - clk->tstate); + pstate = min(pstate, clk->state_nr - 1 + clk->tstate); pstate = max(pstate, clk->dstate); } else { pstate = clk->pstate = -1; -- GitLab From df0b37ee1aa19fc1b948099bf449fdd94f36036c Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Fri, 19 Jun 2015 17:36:37 +0200 Subject: [PATCH 5293/7006] drm/nouveau/pm: expose name of domains This is going to be very useful for GF100+ because each GPC can have its own domain of counters. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 3b7f49f876abe..59d598357a43b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -262,6 +262,7 @@ struct nvif_perfmon_query_domain_v0 { __u8 iter; __u16 signal_nr; __u8 pad05[2]; + char name[64]; }; struct nvif_perfmon_query_signal_v0 { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 7866e220b66fc..94991d63640ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -454,6 +454,7 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) args->v0.id = di; args->v0.signal_nr = nvkm_perfdom_count_perfsig(dom); + strncpy(args->v0.name, dom->name, sizeof(args->v0.name)); /* Currently only global counters (PCOUNTER) are implemented * but this will be different for local counters (MP). */ -- GitLab From 261d678d10d9ba866e279e0da0415267f1e6e561 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Fri, 19 Jun 2015 17:36:38 +0200 Subject: [PATCH 5294/7006] drm/nouveau/pm/nv40: rename pcounter domains to 'pc' instead of 'pm' This trivial patch makes thing more consistent since hardware signals names are prefixed by 'pcXX'. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index 1c6d1ca4799ed..5a87f3a1b947d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -108,7 +108,7 @@ nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms); + ret = nvkm_perfdom_new(&priv->base, "pc", 0, 0, 0, 4, mclass->doms); if (ret) return ret; -- GitLab From 1914f673ec8b440a03ed56e0a1f42e3565c405c7 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Fri, 19 Jun 2015 17:37:17 +0200 Subject: [PATCH 5295/7006] drm/nouveau/pm/gk104: re-use gf100_pm_ctor() gk104_pm_ctor() is equal to gf100_pm_ctor(). Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 2 +- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 +-- .../gpu/drm/nouveau/nvkm/engine/pm/gk104.c | 60 +++---------------- 3 files changed, 14 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index ed36daf345782..c4c704bc10c63 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -29,6 +29,6 @@ extern struct nvkm_oclass *gt215_pm_oclass; extern struct nvkm_oclass *gf100_pm_oclass; extern struct nvkm_oclass *gf108_pm_oclass; extern struct nvkm_oclass *gf117_pm_oclass; -extern struct nvkm_oclass gk104_pm_oclass; +extern struct nvkm_oclass *gk104_pm_oclass; extern struct nvkm_oclass gk110_pm_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 6a9483f65d83a..2b1fce20445b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -91,7 +91,7 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: device->cname = "GK107"; @@ -125,7 +125,7 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: device->cname = "GK106"; @@ -159,7 +159,7 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: device->cname = "GK20A"; @@ -179,7 +179,7 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass; + device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c index 3565f292984f4..7462dffa853c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c @@ -85,58 +85,16 @@ gk104_pm_part[] = { {} }; -static int -gk104_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_pm_priv *priv; - u32 mask; - int ret; - - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); - if (ret) - return ret; - - /* HUB */ - ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, - gk104_pm_hub); - if (ret) - return ret; - - /* GPC */ - mask = (1 << nv_rd32(priv, 0x022430)) - 1; - mask &= ~nv_rd32(priv, 0x022504); - mask &= ~nv_rd32(priv, 0x022584); - - ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000, - 0x1000, 0x200, gk104_pm_gpc); - if (ret) - return ret; - - /* PART */ - mask = (1 << nv_rd32(priv, 0x022438)) - 1; - mask &= ~nv_rd32(priv, 0x022548); - mask &= ~nv_rd32(priv, 0x0225c8); - - ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000, - 0x1000, 0x200, gk104_pm_part); - if (ret) - return ret; - - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; - return 0; -} - -struct nvkm_oclass -gk104_pm_oclass = { - .handle = NV_ENGINE(PM, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_pm_ctor, +struct nvkm_oclass * +gk104_pm_oclass = &(struct gf100_pm_oclass) { + .base.handle = NV_ENGINE(PM, 0xe0), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf100_pm_ctor, .dtor = _nvkm_pm_dtor, .init = _nvkm_pm_init, .fini = gf100_pm_fini, }, -}; + .doms_gpc = gk104_pm_gpc, + .doms_hub = gk104_pm_hub, + .doms_part = gk104_pm_part, +}.base; -- GitLab From 13cffadced770954fc647e1aee8c959a99ecf0f4 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Fri, 19 Jun 2015 17:37:18 +0200 Subject: [PATCH 5296/7006] drm/nouveau/pm/gk104: add compute signals/sources These signals and sources have been reverse engineered from CUPTI (Linux). Graphics signals exposed by PerfKit (Windows only) will be added later. I need to reverse engineer them and it's a bit painful. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.h | 1 + .../gpu/drm/nouveau/nvkm/engine/pm/gf117.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/pm/gk104.c | 85 +++++++++++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index 40ced895bad33..d73f0ca442ebe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -27,5 +27,6 @@ int gf100_pm_fini(struct nvkm_object *, bool); extern const struct nvkm_specdom gf100_pm_gpc[]; extern const struct nvkm_specsrc gf100_pmfb_sources[]; +extern const struct nvkm_specsrc gf117_pbfb_sources[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c index 911ff3f19990e..01d3a485e506b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c @@ -39,7 +39,7 @@ gf117_pmfb_sources[] = { {} }; -static const struct nvkm_specsrc +const struct nvkm_specsrc gf117_pbfb_sources[] = { { 0x110100, (const struct nvkm_specmux[]) { { 0x1, 0, "unk0" }, @@ -47,6 +47,12 @@ gf117_pbfb_sources[] = { { 0x3, 8, "unk8" }, {} }, "pbfb0_pm_unk100" }, + { 0x10f100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0xf, 4, "unk4" }, + { 0x3, 8, "unk8" }, + {} + }, "pbfb_broadcast_pm_unk100" }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c index 7462dffa853c3..5067f72b8dda9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c @@ -23,6 +23,52 @@ */ #include "gf100.h" +static const struct nvkm_specsrc +gk104_pmfb_sources[] = { + { 0x140028, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + { 0x7, 16, "unk16" }, + { 0x3, 24, "unk24" }, + { 0x2, 28, "unk28" }, + {} + }, "pmfb0_pm_unk28" }, + { 0x14125c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp0_pm_unk25c" }, + { 0x14165c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp1_pm_unk25c" }, + { 0x141a5c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp2_pm_unk25c" }, + { 0x141e5c, (const struct nvkm_specmux[]) { + { 0x3fff, 0, "unk0" }, + {} + }, "pmfb0_subp3_pm_unk25c" }, + {} +}; + +static const struct nvkm_specsrc +gk104_tex_sources[] = { + { 0x5042c0, (const struct nvkm_specmux[]) { + { 0xf, 0, "sel0", true }, + { 0x7, 8, "sel1", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_mux_c_d" }, + { 0x5042c8, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_unkc8" }, + { 0x5042b8, (const struct nvkm_specmux[]) { + { 0xff, 0, "sel", true }, + {} + }, "pgraph_gpc0_tpc0_tex_pm_unkb8" }, + {} +}; + static const struct nvkm_specdom gk104_pm_hub[] = { { 0x60, (const struct nvkm_specsig[]) { @@ -69,12 +115,51 @@ gk104_pm_gpc[] = { { 0xc7, "gpc00_user_0" }, {} }, &gf100_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + {} + }, &gf100_perfctr_func }, + { 0x20, (const struct nvkm_specsig[]) { + { 0x00, "gpc02_tex_00", gk104_tex_sources }, + { 0x01, "gpc02_tex_01", gk104_tex_sources }, + { 0x02, "gpc02_tex_02", gk104_tex_sources }, + { 0x03, "gpc02_tex_03", gk104_tex_sources }, + { 0x04, "gpc02_tex_04", gk104_tex_sources }, + { 0x05, "gpc02_tex_05", gk104_tex_sources }, + { 0x06, "gpc02_tex_06", gk104_tex_sources }, + { 0x07, "gpc02_tex_07", gk104_tex_sources }, + { 0x08, "gpc02_tex_08", gk104_tex_sources }, + { 0x0a, "gpc02_tex_0a", gk104_tex_sources }, + { 0x0b, "gpc02_tex_0b", gk104_tex_sources }, + { 0x0d, "gpc02_tex_0c", gk104_tex_sources }, + { 0x0c, "gpc02_tex_0d", gk104_tex_sources }, + { 0x0e, "gpc02_tex_0e", gk104_tex_sources }, + { 0x0f, "gpc02_tex_0f", gk104_tex_sources }, + { 0x10, "gpc02_tex_10", gk104_tex_sources }, + { 0x11, "gpc02_tex_11", gk104_tex_sources }, + { 0x12, "gpc02_tex_12", gk104_tex_sources }, + {} + }, &gf100_perfctr_func }, {} }; static const struct nvkm_specdom gk104_pm_part[] = { { 0x60, (const struct nvkm_specsig[]) { + { 0x00, "part00_pbfb_00", gf117_pbfb_sources }, + { 0x01, "part00_pbfb_01", gf117_pbfb_sources }, + { 0x0c, "part00_pmfb_00", gk104_pmfb_sources }, + { 0x0d, "part00_pmfb_01", gk104_pmfb_sources }, + { 0x0e, "part00_pmfb_02", gk104_pmfb_sources }, + { 0x0f, "part00_pmfb_03", gk104_pmfb_sources }, + { 0x10, "part00_pmfb_04", gk104_pmfb_sources }, + { 0x12, "part00_pmfb_05", gk104_pmfb_sources }, + { 0x15, "part00_pmfb_06", gk104_pmfb_sources }, + { 0x16, "part00_pmfb_07", gk104_pmfb_sources }, + { 0x18, "part00_pmfb_08", gk104_pmfb_sources }, + { 0x21, "part00_pmfb_09", gk104_pmfb_sources }, + { 0x25, "part00_pmfb_0a", gk104_pmfb_sources }, + { 0x26, "part00_pmfb_0b", gk104_pmfb_sources }, + { 0x27, "part00_pmfb_0c", gk104_pmfb_sources }, { 0x47, "part00_user_0" }, {} }, &gf100_perfctr_func }, -- GitLab From 8539b37acef73949861a16808b60cb8b5b9b3bab Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 23 Jun 2015 15:16:01 +0900 Subject: [PATCH 5297/7006] drm/nouveau/gr: use NVIDIA-provided external firmwares NVIDIA will officially start providing GR firmwares through linux-firmware for GPUs that require it. Change the GR firmware lookup function to use these files. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index ca11ddb6ed467..454080339572c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1550,18 +1550,25 @@ gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname, { struct nvkm_device *device = nv_device(priv); const struct firmware *fw; - char f[32]; + char f[64]; + char cname[16]; int ret; + int i; + + /* Convert device name to lowercase */ + strncpy(cname, device->cname, sizeof(cname)); + cname[sizeof(cname) - 1] = '\0'; + i = strlen(cname); + while (i) { + --i; + cname[i] = tolower(cname[i]); + } - snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname); + snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { - snprintf(f, sizeof(f), "nouveau/%s", fwname); - ret = request_firmware(&fw, f, nv_device_base(device)); - if (ret) { - nv_error(priv, "failed to load %s\n", fwname); - return ret; - } + nv_error(priv, "failed to load %s\n", fwname); + return ret; } fuc->size = fw->size; @@ -1615,10 +1622,10 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (use_ext_fw) { nv_info(priv, "using external firmware\n"); - if (gf100_gr_ctor_fw(priv, "fuc409c", &priv->fuc409c) || - gf100_gr_ctor_fw(priv, "fuc409d", &priv->fuc409d) || - gf100_gr_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) || - gf100_gr_ctor_fw(priv, "fuc41ad", &priv->fuc41ad)) + if (gf100_gr_ctor_fw(priv, "fecs_inst", &priv->fuc409c) || + gf100_gr_ctor_fw(priv, "fecs_data", &priv->fuc409d) || + gf100_gr_ctor_fw(priv, "gpccs_inst", &priv->fuc41ac) || + gf100_gr_ctor_fw(priv, "gpccs_data", &priv->fuc41ad)) return -ENODEV; priv->firmware = true; } -- GitLab From c4d0f8f6f8c8dc09cd32e7fdb31e3d1a65a0f8f1 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 23 Jun 2015 15:16:02 +0900 Subject: [PATCH 5298/7006] drm/nouveau/gr/gk20a: use same initialization sequence as nvgpu GK20A's initialization was based on GK104, but differences exist in the way the initial context is built and the initialization process itself. This patch follows the same initialization sequence as nvgpu performs to avoid bad surprises. Since the register bundles initialization also differ considerably from GK104, the register packs are now loaded from firmware files, again similarly to what is done with nvgpu. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c | 65 +++- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 12 + .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 336 +++++++++++++++++- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.h | 35 ++ 5 files changed, 421 insertions(+), 30 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index 2f241f6f0f0a7..3fe080e31a861 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -19,14 +19,56 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ + #include "ctxgf100.h" +#include "gk20a.h" + +#include + +static void +gk20a_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +{ + struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + int idle_timeout_save; + int i; + + gf100_gr_mmio(priv, priv->fuc_sw_ctx); + + gf100_gr_wait_idle(priv); + + idle_timeout_save = nv_rd32(priv, 0x404154); + nv_wr32(priv, 0x404154, 0x00000000); + + oclass->attrib(info); + + oclass->unkn(priv); + + gf100_grctx_generate_tpcid(priv); + gf100_grctx_generate_r406028(priv); + gk104_grctx_generate_r418bb8(priv); + gf100_grctx_generate_r406800(priv); + + for (i = 0; i < 8; i++) + nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + + nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + + gk104_grctx_generate_rop_active_fbps(priv); + + nv_mask(priv, 0x5044b0, 0x8000000, 0x8000000); + + gf100_gr_wait_idle(priv); + + nv_wr32(priv, 0x404154, idle_timeout_save); + gf100_gr_wait_idle(priv); + + gf100_gr_mthd(priv, priv->fuc_method); + gf100_gr_wait_idle(priv); -static const struct gf100_gr_pack -gk20a_grctx_pack_mthd[] = { - { gk104_grctx_init_a097_0, 0xa297 }, - { gf100_grctx_init_902d_0, 0x902d }, - {} -}; + gf100_gr_icmd(priv, priv->fuc_bundle); + oclass->pagepool(info); + oclass->bundle(info); +} struct nvkm_oclass * gk20a_grctx_oclass = &(struct gf100_grctx_oclass) { @@ -39,15 +81,8 @@ gk20a_grctx_oclass = &(struct gf100_grctx_oclass) { .rd32 = _nvkm_gr_context_rd32, .wr32 = _nvkm_gr_context_wr32, }, - .main = gk104_grctx_generate_main, + .main = gk20a_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, - .hub = gk104_grctx_pack_hub, - .gpc = gk104_grctx_pack_gpc, - .zcull = gf100_grctx_pack_zcull, - .tpc = gk104_grctx_pack_tpc, - .ppc = gk104_grctx_pack_ppc, - .icmd = gk104_grctx_pack_icmd, - .mthd = gk20a_grctx_pack_mthd, .bundle = gk104_grctx_generate_bundle, .bundle_size = 0x1800, .bundle_min_gpm_fifo_depth = 0x62, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 454080339572c..288423b846678 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1537,7 +1537,7 @@ gf100_gr_init(struct nvkm_object *object) return gf100_gr_init_ctxctl(priv); } -static void +void gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc) { kfree(fuc->data); @@ -1690,6 +1690,7 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, break; case 0xd7: case 0xd9: /* 1/0/0/0, 1 */ + case 0xea: /* gk20a */ priv->magic_not_rop_nr = 0x01; break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index c9533fdac4fc8..972efd7b79348 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -76,6 +76,15 @@ struct gf100_gr_priv { struct gf100_gr_fuc fuc41ad; bool firmware; + /* + * Used if the register packs are loaded from NVIDIA fw instead of + * using hardcoded arrays. + */ + struct gf100_gr_pack *fuc_sw_nonctx; + struct gf100_gr_pack *fuc_sw_ctx; + struct gf100_gr_pack *fuc_bundle; + struct gf100_gr_pack *fuc_method; + struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_CNT]; struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; @@ -116,6 +125,9 @@ void gf100_gr_context_dtor(struct nvkm_object *); void gf100_gr_ctxctl_debug(struct gf100_gr_priv *); +void gf100_gr_dtor_fw(struct gf100_gr_fuc *); +int gf100_gr_ctor_fw(struct gf100_gr_priv *, const char *, + struct gf100_gr_fuc *); u64 gf100_gr_units(struct nvkm_gr *); int gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *data, u32 size, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index 40ff5eb9180c0..d27ef3ea22265 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -19,10 +19,11 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "gf100.h" +#include "gk20a.h" #include "ctxgf100.h" #include +#include static struct nvkm_oclass gk20a_gr_sclass[] = { @@ -33,17 +34,324 @@ gk20a_gr_sclass[] = { {} }; +static void +gk20a_gr_init_dtor(struct gf100_gr_pack *pack) +{ + vfree(pack); +} + +struct gk20a_fw_av +{ + u32 addr; + u32 data; +}; + +static struct gf100_gr_pack * +gk20a_gr_av_to_init(struct gf100_gr_fuc *fuc) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + const int nent = (fuc->size / sizeof(struct gk20a_fw_av)); + int i; + + pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); + if (!pack) + return ERR_PTR(-ENOMEM); + + init = (void *)(pack + 2); + + pack[0].init = init; + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc->data)[i]; + + ent->addr = av->addr; + ent->data = av->data; + ent->count = 1; + ent->pitch = 1; + } + + return pack; +} + +struct gk20a_fw_aiv +{ + u32 addr; + u32 index; + u32 data; +}; + +static struct gf100_gr_pack * +gk20a_gr_aiv_to_init(struct gf100_gr_fuc *fuc) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + const int nent = (fuc->size / sizeof(struct gk20a_fw_aiv)); + int i; + + pack = vzalloc((sizeof(*pack) * 2) + (sizeof(*init) * (nent + 1))); + if (!pack) + return ERR_PTR(-ENOMEM); + + init = (void *)(pack + 2); + + pack[0].init = init; + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct gk20a_fw_aiv *av = &((struct gk20a_fw_aiv *)fuc->data)[i]; + + ent->addr = av->addr; + ent->data = av->data; + ent->count = 1; + ent->pitch = 1; + } + + return pack; +} + +static struct gf100_gr_pack * +gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc) +{ + struct gf100_gr_init *init; + struct gf100_gr_pack *pack; + /* We don't suppose we will initialize more than 16 classes here... */ + static const unsigned int max_classes = 16; + const int nent = (fuc->size / sizeof(struct gk20a_fw_av)); + int i, classidx = 0; + u32 prevclass = 0; + + pack = vzalloc((sizeof(*pack) * max_classes) + + (sizeof(*init) * (nent + 1))); + if (!pack) + return ERR_PTR(-ENOMEM); + + init = (void *)(pack + max_classes); + + for (i = 0; i < nent; i++) { + struct gf100_gr_init *ent = &init[i]; + struct gk20a_fw_av *av = &((struct gk20a_fw_av *)fuc->data)[i]; + u32 class = av->addr & 0xffff; + u32 addr = (av->addr & 0xffff0000) >> 14; + + if (prevclass != class) { + pack[classidx].init = ent; + pack[classidx].type = class; + prevclass = class; + if (++classidx >= max_classes) { + vfree(pack); + return ERR_PTR(-ENOSPC); + } + } + + ent->addr = addr; + ent->data = av->data; + ent->count = 1; + ent->pitch = 1; + } + + return pack; +} + +static int +gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + int err; + struct gf100_gr_priv *priv; + struct gf100_gr_fuc fuc; + + err = gf100_gr_ctor(parent, engine, oclass, data, size, pobject); + if (err) + return err; + + priv = (void *)*pobject; + + err = gf100_gr_ctor_fw(priv, "sw_nonctx", &fuc); + if (err) + return err; + priv->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(priv->fuc_sw_nonctx)) + return PTR_ERR(priv->fuc_sw_nonctx); + + err = gf100_gr_ctor_fw(priv, "sw_ctx", &fuc); + if (err) + return err; + priv->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(priv->fuc_sw_ctx)) + return PTR_ERR(priv->fuc_sw_ctx); + + err = gf100_gr_ctor_fw(priv, "sw_bundle_init", &fuc); + if (err) + return err; + priv->fuc_bundle = gk20a_gr_av_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(priv->fuc_bundle)) + return PTR_ERR(priv->fuc_bundle); + + err = gf100_gr_ctor_fw(priv, "sw_method_init", &fuc); + if (err) + return err; + priv->fuc_method = gk20a_gr_av_to_method(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(priv->fuc_method)) + return PTR_ERR(priv->fuc_method); + + return 0; +} + +static void +gk20a_gr_dtor(struct nvkm_object *object) +{ + struct gf100_gr_priv *priv = (void *)object; + + gk20a_gr_init_dtor(priv->fuc_method); + gk20a_gr_init_dtor(priv->fuc_bundle); + gk20a_gr_init_dtor(priv->fuc_sw_ctx); + gk20a_gr_init_dtor(priv->fuc_sw_nonctx); + + gf100_gr_dtor(object); +} + +static int +gk20a_gr_wait_mem_scrubbing(struct gf100_gr_priv *priv) +{ + if (!nv_wait(priv, 0x40910c, 0x6, 0x0)) { + nv_error(priv, "FECS mem scrubbing timeout\n"); + return -ETIMEDOUT; + } + + if (!nv_wait(priv, 0x41a10c, 0x6, 0x0)) { + nv_error(priv, "GPCCS mem scrubbing timeout\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void +gk20a_gr_set_hww_esr_report_mask(struct gf100_gr_priv *priv) +{ + nv_wr32(priv, 0x419e44, 0x1ffffe); + nv_wr32(priv, 0x419e4c, 0x7f); +} + +static int +gk20a_gr_init(struct nvkm_object *object) +{ + struct gk20a_gr_oclass *oclass = (void *)object->oclass; + struct gf100_gr_priv *priv = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + u32 data[TPC_MAX / 8] = {}; + u8 tpcnr[GPC_MAX]; + int gpc, tpc; + int ret, i; + + ret = nvkm_gr_init(&priv->base); + if (ret) + return ret; + + /* Clear SCC RAM */ + nv_wr32(priv, 0x40802c, 0x1); + + gf100_gr_mmio(priv, priv->fuc_sw_nonctx); + + ret = gk20a_gr_wait_mem_scrubbing(priv); + if (ret) + return ret; + + ret = gf100_gr_wait_idle(priv); + if (ret) + return ret; + + /* MMU debug buffer */ + nv_wr32(priv, 0x100cc8, priv->unk4188b4->addr >> 8); + nv_wr32(priv, 0x100ccc, priv->unk4188b8->addr >> 8); + + if (oclass->init_gpc_mmu) + oclass->init_gpc_mmu(priv); + + /* Set the PE as stream master */ + nv_mask(priv, 0x503018, 0x1, 0x1); + + /* Zcull init */ + memset(data, 0x00, sizeof(data)); + memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + do { + gpc = (gpc + 1) % priv->gpc_nr; + } while (!tpcnr[gpc]); + tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + + data[i / 8] |= tpc << ((i % 8) * 4); + } + + nv_wr32(priv, GPC_BCAST(0x0980), data[0]); + nv_wr32(priv, GPC_BCAST(0x0984), data[1]); + nv_wr32(priv, GPC_BCAST(0x0988), data[2]); + nv_wr32(priv, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < priv->gpc_nr; gpc++) { + nv_wr32(priv, GPC_UNIT(gpc, 0x0914), + priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); + nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | + priv->tpc_total); + nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + } + + nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); + + /* Enable FIFO access */ + nv_wr32(priv, 0x400500, 0x00010001); + + /* Enable interrupts */ + nv_wr32(priv, 0x400100, 0xffffffff); + nv_wr32(priv, 0x40013c, 0xffffffff); + + /* Enable FECS error interrupts */ + nv_wr32(priv, 0x409c24, 0x000f0000); + + /* Enable hardware warning exceptions */ + nv_wr32(priv, 0x404000, 0xc0000000); + nv_wr32(priv, 0x404600, 0xc0000000); + + if (oclass->set_hww_esr_report_mask) + oclass->set_hww_esr_report_mask(priv); + + /* Enable TPC exceptions per GPC */ + nv_wr32(priv, 0x419d0c, 0x2); + nv_wr32(priv, 0x41ac94, (((1 << priv->tpc_total) - 1) & 0xff) << 16); + + /* Reset and enable all exceptions */ + nv_wr32(priv, 0x400108, 0xffffffff); + nv_wr32(priv, 0x400138, 0xffffffff); + nv_wr32(priv, 0x400118, 0xffffffff); + nv_wr32(priv, 0x400130, 0xffffffff); + nv_wr32(priv, 0x40011c, 0xffffffff); + nv_wr32(priv, 0x400134, 0xffffffff); + + gf100_gr_zbc_init(priv); + + return gf100_gr_init_ctxctl(priv); +} + struct nvkm_oclass * -gk20a_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, +gk20a_gr_oclass = &(struct gk20a_gr_oclass) { + .gf100 = { + .base.handle = NV_ENGINE(GR, 0xea), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gk20a_gr_ctor, + .dtor = gk20a_gr_dtor, + .init = gk20a_gr_init, + .fini = _nvkm_gr_fini, + }, + .cclass = &gk20a_grctx_oclass, + .sclass = gk20a_gr_sclass, + .ppc_nr = 1, }, - .cclass = &gk20a_grctx_oclass, - .sclass = gk20a_gr_sclass, - .mmio = gk104_gr_pack_mmio, - .ppc_nr = 1, -}.base; + .set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask, +}.gf100.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h new file mode 100644 index 0000000000000..b36958505a81f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * 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 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. + */ + +#ifndef __GK20A_GR_H__ +#define __GK20A_GR_H__ + +#include "gf100.h" + +struct gk20a_gr_oclass { + struct gf100_gr_oclass gf100; + + void (*init_gpc_mmu)(struct gf100_gr_priv *); + void (*set_hww_esr_report_mask)(struct gf100_gr_priv *); +}; + +#endif -- GitLab From 3326060a17f6ef8ca3d3f785b1ae31ff76f713f6 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 23 Jun 2015 15:16:03 +0900 Subject: [PATCH 5299/7006] drm/nouveau/fifo: add GM20B fifo GM20B has a 512-channels FIFO similar to GK104. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/fifo.h | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 4 +++ .../gpu/drm/nouveau/nvkm/engine/fifo/gm204.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c | 34 +++++++++++++++++++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 97cdeab8e44c2..9100b800562ef 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -117,6 +117,7 @@ extern struct nvkm_oclass *gk104_fifo_oclass; extern struct nvkm_oclass *gk20a_fifo_oclass; extern struct nvkm_oclass *gk208_fifo_oclass; extern struct nvkm_oclass *gm204_fifo_oclass; +extern struct nvkm_oclass *gm20b_fifo_oclass; int nvkm_fifo_uevent_ctor(struct nvkm_object *, void *, u32, struct nvkm_notify *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 42891cb71ea34..dc81a8b64f359 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -10,3 +10,4 @@ nvkm-y += nvkm/engine/fifo/gk104.o nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gk208.o nvkm-y += nvkm/engine/fifo/gm204.o +nvkm-y += nvkm/engine/fifo/gm20b.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index 318d30d6ee1ae..b77d75f86b734 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -15,4 +15,8 @@ struct gk104_fifo_impl { }; extern struct nvkm_ofuncs gk104_fifo_chan_ofuncs; + +int gm204_fifo_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void *, u32, + struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c index 749d525dd8e3f..7596587b0e7c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c @@ -31,7 +31,7 @@ gm204_fifo_sclass[] = { {} }; -static int +int gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c new file mode 100644 index 0000000000000..4abf547c34e64 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * 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 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. + */ +#include "gk104.h" + +struct nvkm_oclass * +gm20b_fifo_oclass = &(struct gk104_fifo_impl) { + .base.handle = NV_ENGINE(FIFO, 0x2b), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gm204_fifo_ctor, + .dtor = gk104_fifo_dtor, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + }, + .channels = 512, +}.base; -- GitLab From a032fb9da665ed6e6a36fa6788eff1db43ba2703 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 23 Jun 2015 15:16:04 +0900 Subject: [PATCH 5300/7006] drm/nouveau/gr: add GM20B support Add support for GM20B's graphics engine, based on GK20A. Note that this code alone will not allow the engine to initialize on released devices which require PMU-assisted secure boot. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/gr.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h | 7 ++ .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c | 110 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 1 + .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 6 + .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c | 84 +++++++++++++ 10 files changed, 217 insertions(+), 6 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index 7cbe202807604..c772497cac3e2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -74,6 +74,7 @@ extern struct nvkm_oclass *gk208_gr_oclass; extern struct nvkm_oclass *gm107_gr_oclass; extern struct nvkm_oclass *gm204_gr_oclass; extern struct nvkm_oclass *gm206_gr_oclass; +extern struct nvkm_oclass *gm20b_gr_oclass; #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index 2e1b92f71d9eb..e91b4dfc0bf3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -14,6 +14,7 @@ nvkm-y += nvkm/engine/gr/ctxgk208.o nvkm-y += nvkm/engine/gr/ctxgm107.o nvkm-y += nvkm/engine/gr/ctxgm204.o nvkm-y += nvkm/engine/gr/ctxgm206.o +nvkm-y += nvkm/engine/gr/ctxgm20b.o nvkm-y += nvkm/engine/gr/nv04.o nvkm-y += nvkm/engine/gr/nv10.o nvkm-y += nvkm/engine/gr/nv20.o @@ -38,3 +39,4 @@ nvkm-y += nvkm/engine/gr/gk208.o nvkm-y += nvkm/engine/gr/gm107.o nvkm-y += nvkm/engine/gr/gm204.o nvkm-y += nvkm/engine/gr/gm206.o +nvkm-y += nvkm/engine/gr/gm20b.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index 3676a3342bc58..f89ab3706cf31 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -91,6 +91,10 @@ void gk104_grctx_generate_r418bb8(struct gf100_gr_priv *); void gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *); +void gm107_grctx_generate_bundle(struct gf100_grctx *); +void gm107_grctx_generate_pagepool(struct gf100_grctx *); +void gm107_grctx_generate_attrib(struct gf100_grctx *); + extern struct nvkm_oclass *gk110_grctx_oclass; extern struct nvkm_oclass *gk110b_grctx_oclass; extern struct nvkm_oclass *gk208_grctx_oclass; @@ -102,8 +106,11 @@ void gm107_grctx_generate_attrib(struct gf100_grctx *); extern struct nvkm_oclass *gm204_grctx_oclass; void gm204_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); +void gm204_grctx_generate_tpcid(struct gf100_gr_priv *); +void gm204_grctx_generate_405b60(struct gf100_gr_priv *); extern struct nvkm_oclass *gm206_grctx_oclass; +extern struct nvkm_oclass *gm20b_grctx_oclass; /* context init value lists */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index fbeaae3ae6ce9..6bf2fd1a05ba8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -931,7 +931,7 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info) } } -static void +void gm107_grctx_generate_tpcid(struct gf100_gr_priv *priv) { int gpc, tpc, id; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c index ea8e66151aa89..efc76bfae8960 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c @@ -918,7 +918,7 @@ gm204_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -static void +void gm204_grctx_generate_tpcid(struct gf100_gr_priv *priv) { int gpc, tpc, id; @@ -943,7 +943,7 @@ gm204_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv) nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */ } -static void +void gm204_grctx_generate_405b60(struct gf100_gr_priv *priv) { const u32 dist_nr = DIV_ROUND_UP(priv->tpc_total, 4); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c new file mode 100644 index 0000000000000..c011bf327276d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * 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 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. + */ +#include "ctxgf100.h" + +static void +gm20b_grctx_generate_r406028(struct gf100_gr_priv *priv) +{ + u32 tpc_per_gpc = 0; + int i; + + for (i = 0; i < priv->gpc_nr; i++) + tpc_per_gpc |= priv->tpc_nr[i] << (4 * i); + + nv_wr32(priv, 0x406028, tpc_per_gpc); + nv_wr32(priv, 0x405870, tpc_per_gpc); +} + +static void +gm20b_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +{ + struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + int idle_timeout_save; + int i, tmp; + + gf100_gr_mmio(priv, priv->fuc_sw_ctx); + + gf100_gr_wait_idle(priv); + + idle_timeout_save = nv_rd32(priv, 0x404154); + nv_wr32(priv, 0x404154, 0x00000000); + + oclass->attrib(info); + + oclass->unkn(priv); + + gm204_grctx_generate_tpcid(priv); + gm20b_grctx_generate_r406028(priv); + gk104_grctx_generate_r418bb8(priv); + + for (i = 0; i < 8; i++) + nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + + nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + + gk104_grctx_generate_rop_active_fbps(priv); + nv_wr32(priv, 0x408908, nv_rd32(priv, 0x410108) | 0x80000000); + + for (tmp = 0, i = 0; i < priv->gpc_nr; i++) + tmp |= ((1 << priv->tpc_nr[i]) - 1) << (i * 4); + nv_wr32(priv, 0x4041c4, tmp); + + gm204_grctx_generate_405b60(priv); + + gf100_gr_wait_idle(priv); + + nv_wr32(priv, 0x404154, idle_timeout_save); + gf100_gr_wait_idle(priv); + + gf100_gr_mthd(priv, priv->fuc_method); + gf100_gr_wait_idle(priv); + + gf100_gr_icmd(priv, priv->fuc_bundle); + oclass->pagepool(info); + oclass->bundle(info); +} + +struct nvkm_oclass * +gm20b_grctx_oclass = &(struct gf100_grctx_oclass) { + .base.handle = NV_ENGCTX(GR, 0x2b), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf100_gr_context_ctor, + .dtor = gf100_gr_context_dtor, + .init = _nvkm_gr_context_init, + .fini = _nvkm_gr_context_fini, + .rd32 = _nvkm_gr_context_rd32, + .wr32 = _nvkm_gr_context_wr32, + }, + .main = gm20b_grctx_generate_main, + .unkn = gk104_grctx_generate_unkn, + .bundle = gm107_grctx_generate_bundle, + .bundle_size = 0x1800, + .bundle_min_gpm_fifo_depth = 0x182, + .bundle_token_limit = 0x1c0, + .pagepool = gm107_grctx_generate_pagepool, + .pagepool_size = 0x8000, + .attrib = gm107_grctx_generate_attrib, + .attrib_nr_max = 0x600, + .attrib_nr = 0x400, + .alpha_nr_max = 0xc00, + .alpha_nr = 0x800, +}.base; \ No newline at end of file diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 288423b846678..e7c3e9e57385b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1691,6 +1691,7 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, case 0xd7: case 0xd9: /* 1/0/0/0, 1 */ case 0xea: /* gk20a */ + case 0x12b: /* gm20b */ priv->magic_not_rop_nr = 0x01; break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 972efd7b79348..f185f034d1ea9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -141,6 +141,12 @@ int gk104_gr_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_object **); int gk104_gr_init(struct nvkm_object *); +int gk20a_gr_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +void gk20a_gr_dtor(struct nvkm_object *); +int gk20a_gr_init(struct nvkm_object *); + int gm204_gr_init(struct nvkm_object *); extern struct nvkm_ofuncs gf100_fermi_ofuncs; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index d27ef3ea22265..fc4a910b24982 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -154,7 +154,7 @@ gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc) return pack; } -static int +int gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) @@ -204,7 +204,7 @@ gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -static void +void gk20a_gr_dtor(struct nvkm_object *object) { struct gf100_gr_priv *priv = (void *)object; @@ -240,7 +240,7 @@ gk20a_gr_set_hww_esr_report_mask(struct gf100_gr_priv *priv) nv_wr32(priv, 0x419e4c, 0x7f); } -static int +int gk20a_gr_init(struct nvkm_object *object) { struct gk20a_gr_oclass *oclass = (void *)object->oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c new file mode 100644 index 0000000000000..897628062d589 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * + * 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 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. + */ +#include "gk20a.h" +#include "ctxgf100.h" + +#include +#include + +static struct nvkm_oclass +gm20b_gr_sclass[] = { + { FERMI_TWOD_A, &nvkm_object_ofuncs }, + { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, + { MAXWELL_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, + { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + {} +}; + +static void +gm20b_gr_init_gpc_mmu(struct gf100_gr_priv *priv) +{ + u32 val; + + /* TODO this needs to be removed once secure boot works */ + if (1) { + nv_wr32(priv, 0x100ce4, 0xffffffff); + } + + /* TODO update once secure boot works */ + val = nv_rd32(priv, 0x100c80); + val &= 0xf000087f; + nv_wr32(priv, 0x418880, val); + nv_wr32(priv, 0x418890, 0); + nv_wr32(priv, 0x418894, 0); + + nv_wr32(priv, 0x4188b0, nv_rd32(priv, 0x100cc4)); + nv_wr32(priv, 0x4188b4, nv_rd32(priv, 0x100cc8)); + nv_wr32(priv, 0x4188b8, nv_rd32(priv, 0x100ccc)); + + nv_wr32(priv, 0x4188ac, nv_rd32(priv, 0x100800)); +} + +static void +gm20b_gr_set_hww_esr_report_mask(struct gf100_gr_priv *priv) +{ + nv_wr32(priv, 0x419e44, 0xdffffe); + nv_wr32(priv, 0x419e4c, 0x5); +} + +struct nvkm_oclass * +gm20b_gr_oclass = &(struct gk20a_gr_oclass) { + .gf100 = { + .base.handle = NV_ENGINE(GR, 0x2b), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gk20a_gr_ctor, + .dtor = gf100_gr_dtor, + .init = gk20a_gr_init, + .fini = _nvkm_gr_fini, + }, + .cclass = &gm20b_grctx_oclass, + .sclass = gm20b_gr_sclass, + .ppc_nr = 1, + }, + .init_gpc_mmu = gm20b_gr_init_gpc_mmu, + .set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask, +}.gf100.base; -- GitLab From d10ae271301803c2720b8ad53d6a90b5620ea439 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 23 Jun 2015 15:16:05 +0900 Subject: [PATCH 5301/7006] drm/nouveau/device: recognize GM20B Recognize GM20B and assign the right engines and subdevs. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/device/gm100.c | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 70abf1ec7c985..a51b3ce50f364 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -181,6 +181,26 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; #endif break; + case 0x12b: + device->cname = "GM20B"; + + device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; + device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; + device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; + device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; + device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; + device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; + device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; + device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; + device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; + device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; + device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; + device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; + device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; + device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; + device->oclass[NVDEV_ENGINE_GR ] = gm20b_gr_oclass; + device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; + break; default: nv_fatal(device, "unknown Maxwell chipset\n"); return -EINVAL; -- GitLab From 970fee29d036eda3ea869033d6b0b7b42238b22a Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 23 Jun 2015 15:16:06 +0900 Subject: [PATCH 5302/7006] drm/nouveau/platform: recognize GM20B Allow the platform driver to recognize GM20B. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_platform.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index dcfbbfaf17397..7a39d449fefa6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -252,6 +252,7 @@ static int nouveau_platform_remove(struct platform_device *pdev) #if IS_ENABLED(CONFIG_OF) static const struct of_device_id nouveau_platform_match[] = { { .compatible = "nvidia,gk20a" }, + { .compatible = "nvidia,gm20b" }, { } }; -- GitLab From bacbad17fbc636125bf472240860a58a54ad62db Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Fri, 19 Jun 2015 02:51:23 -0400 Subject: [PATCH 5303/7006] drm/nouveau/bios: add opcodes 0x73 and 0x77 No known VBIOSes use these, but they are present in the actual VBIOS table parsing logic. No harm in adding these too. Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index f4611e3f09718..8e5f6ce76232c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -1741,6 +1741,24 @@ init_resume(struct nvbios_init *init) init_exec_set(init, true); } +/** + * INIT_STRAP_CONDITION - opcode 0x73 + * + */ +static void +init_strap_condition(struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + u32 mask = nv_ro32(bios, init->offset + 1); + u32 value = nv_ro32(bios, init->offset + 5); + + trace("STRAP_CONDITION\t(R[0x101000] & 0x%08x) == 0x%08x\n", mask, value); + init->offset += 9; + + if ((init_rd32(init, 0x101000) & mask) != value) + init_exec_set(init, false); +} + /** * INIT_TIME - opcode 0x74 * @@ -1796,6 +1814,23 @@ init_io_condition(struct nvbios_init *init) init_exec_set(init, false); } +/** + * INIT_ZM_REG16 - opcode 0x77 + * + */ +static void +init_zm_reg16(struct nvbios_init *init) +{ + struct nvkm_bios *bios = init->bios; + u32 addr = nv_ro32(bios, init->offset + 1); + u16 data = nv_ro16(bios, init->offset + 5); + + trace("ZM_REG\tR[0x%06x] = 0x%04x\n", addr, data); + init->offset += 7; + + init_wr32(init, addr, data); +} + /** * INIT_INDEX_IO - opcode 0x78 * @@ -2202,9 +2237,11 @@ static struct nvbios_init_opcode { [0x6f] = { init_macro }, [0x71] = { init_done }, [0x72] = { init_resume }, + [0x73] = { init_strap_condition }, [0x74] = { init_time }, [0x75] = { init_condition }, [0x76] = { init_io_condition }, + [0x77] = { init_zm_reg16 }, [0x78] = { init_index_io }, [0x79] = { init_pll }, [0x7a] = { init_zm_reg }, -- GitLab From a4650ed9bd6564b5135ccebf8a5b108ed16abbac Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 26 Jul 2015 11:30:07 +0200 Subject: [PATCH 5304/7006] drm/nouveau/pm/nv50: fix wrong addr for ZCULL source on G80:GT215 Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c index a778bc738ffc4..14d474ba8c9be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c @@ -34,7 +34,7 @@ nv50_prop_sources[] = { const struct nvkm_specsrc nv50_zcull_sources[] = { - { 0x4002ca4, (const struct nvkm_specmux[]) { + { 0x402ca4, (const struct nvkm_specmux[]) { { 0x7fff, 0, "unk0" }, {} }, "pgraph_zcull_pm_unka4" }, -- GitLab From 5a23936129b87833e3f3e90a610c65f73c7bbeaa Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Sun, 26 Jul 2015 11:30:08 +0200 Subject: [PATCH 5305/7006] drm/nouveau/pm/nv50: TPC[0x3] must be used for PGRAPH muxs on G80 I thought that using TPC[0x0] like for G84:GT215 was sufficient on G80, but it's actually not the case. According to NVIDIA PerfKit on Windows, we have to configure PGRAPH related muxs on TPC[0x3] for this chipset. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c | 25 +++++++++++++------ drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c | 22 ++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 1 - 3 files changed, 28 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c index dda539cf0764f..815bb0dcbf7ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c @@ -32,6 +32,15 @@ g84_vfetch_sources[] = { {} }; +static const struct nvkm_specsrc +g84_prop_sources[] = { + { 0x408e50, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_tpc0_prop_pm_mux" }, + {} +}; + static const struct nvkm_specsrc g84_crop_sources[] = { { 0x407008, (const struct nvkm_specmux[]) { @@ -109,14 +118,14 @@ g84_pm[] = { { 0x31, "pc02_crop_01", g84_crop_sources }, { 0x32, "pc02_crop_02", g84_crop_sources }, { 0x33, "pc02_crop_03", g84_crop_sources }, - { 0x00, "pc02_prop_00", nv50_prop_sources }, - { 0x01, "pc02_prop_01", nv50_prop_sources }, - { 0x02, "pc02_prop_02", nv50_prop_sources }, - { 0x03, "pc02_prop_03", nv50_prop_sources }, - { 0x04, "pc02_prop_04", nv50_prop_sources }, - { 0x05, "pc02_prop_05", nv50_prop_sources }, - { 0x06, "pc02_prop_06", nv50_prop_sources }, - { 0x07, "pc02_prop_07", nv50_prop_sources }, + { 0x00, "pc02_prop_00", g84_prop_sources }, + { 0x01, "pc02_prop_01", g84_prop_sources }, + { 0x02, "pc02_prop_02", g84_prop_sources }, + { 0x03, "pc02_prop_03", g84_prop_sources }, + { 0x04, "pc02_prop_04", g84_prop_sources }, + { 0x05, "pc02_prop_05", g84_prop_sources }, + { 0x06, "pc02_prop_06", g84_prop_sources }, + { 0x07, "pc02_prop_07", g84_prop_sources }, { 0x48, "pc02_tex_00", g84_tex_sources }, { 0x49, "pc02_tex_01", g84_tex_sources }, { 0x4a, "pc02_tex_02", g84_tex_sources }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c index 14d474ba8c9be..dee73af1c62ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c @@ -23,15 +23,6 @@ */ #include "nv40.h" -const struct nvkm_specsrc -nv50_prop_sources[] = { - { 0x408e50, (const struct nvkm_specmux[]) { - { 0x1f, 0, "sel", true }, - {} - }, "pgraph_tpc0_prop_pm_mux" }, - {} -}; - const struct nvkm_specsrc nv50_zcull_sources[] = { { 0x402ca4, (const struct nvkm_specmux[]) { @@ -51,6 +42,15 @@ nv50_zrop_sources[] = { {} }; +static const struct nvkm_specsrc +nv50_prop_sources[] = { + { 0x40be50, (const struct nvkm_specmux[]) { + { 0x1f, 0, "sel", true }, + {} + }, "pgraph_tpc3_prop_pm_mux" }, + {} +}; + static const struct nvkm_specsrc nv50_crop_sources[] = { { 0x407008, (const struct nvkm_specmux[]) { @@ -63,10 +63,10 @@ nv50_crop_sources[] = { static const struct nvkm_specsrc nv50_tex_sources[] = { - { 0x408808, (const struct nvkm_specmux[]) { + { 0x40b808, (const struct nvkm_specmux[]) { { 0x3fff, 0, "unk0" }, {} - }, "pgraph_tpc0_tex_unk08" }, + }, "pgraph_tpc3_tex_unk08" }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 5bcc739ae03c9..69b72780b34b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -44,7 +44,6 @@ struct nvkm_perfsrc { bool enable; }; -extern const struct nvkm_specsrc nv50_prop_sources[]; extern const struct nvkm_specsrc nv50_zcull_sources[]; extern const struct nvkm_specsrc nv50_zrop_sources[]; extern const struct nvkm_specsrc g84_vfetch_sources[]; -- GitLab From 7fe882eb90844f79acd9cdd3ccd5d3459c27cf3f Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Tue, 4 Aug 2015 23:58:12 +0200 Subject: [PATCH 5306/7006] drm/nouveau/pm: allow zeroed signals to enable sources Hardware signals index 0x00 are defined for some domains and they have to be allowed to enable sources like the others. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 94991d63640ce..48c1ce6e663c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -134,7 +134,7 @@ nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) u32 mask, value; int i, j; - for (i = 0; i < 4 && ctr->signal[i]; i++) { + for (i = 0; i < 4; i++) { for (j = 0; j < 8 && ctr->source[i][j]; j++) { sig = nvkm_perfsig_find(ppm, ctr->domain, ctr->signal[i], &dom); @@ -170,7 +170,7 @@ nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) u32 mask; int i, j; - for (i = 0; i < 4 && ctr->signal[i]; i++) { + for (i = 0; i < 4; i++) { for (j = 0; j < 8 && ctr->source[i][j]; j++) { sig = nvkm_perfsig_find(ppm, ctr->domain, ctr->signal[i], &dom); -- GitLab From 9b4dc66d4772a432f271e1ebafd70aafe2b9bb27 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Tue, 4 Aug 2015 23:58:13 +0200 Subject: [PATCH 5307/7006] drm/nouveau/pm/gf100: remove undefined TEX.PM_UNKC8 mux This mux only exists on GF108+ (except for GF110 one), but since it is not used by the userspace we can drop it for now. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index b40c2188d0037..37b1636d0f29d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -62,10 +62,6 @@ gf100_tex_sources[] = { { 0x7, 8, "sel1", true }, {} }, "pgraph_gpc0_tpc0_tex_pm_mux_c_d" }, - { 0x5042c8, (const struct nvkm_specmux[]) { - { 0x1f, 0, "sel", true }, - {} - }, "pgraph_gpc0_tpc0_tex_pm_unkc8" }, {} }; -- GitLab From 8feece04db884e04c31c008b76a7610849757720 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Tue, 4 Aug 2015 23:58:14 +0200 Subject: [PATCH 5308/7006] drm/nouveau/pm/gf100: remove multiple definitions of GPC_DOM signal 0x0e Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 37b1636d0f29d..ab463898b437d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -93,11 +93,10 @@ gf100_pm_gpc[] = { { 0x0c, "gpc00_tex_02", gf100_tex_sources }, { 0x0d, "gpc00_tex_03", gf100_tex_sources }, { 0x0e, "gpc00_tex_04", gf100_tex_sources }, - { 0x0e, "gpc00_tex_05", gf100_tex_sources }, - { 0x0f, "gpc00_tex_06", gf100_tex_sources }, - { 0x10, "gpc00_tex_07", gf100_tex_sources }, - { 0x11, "gpc00_tex_08", gf100_tex_sources }, - { 0x12, "gpc00_tex_09", gf100_tex_sources }, + { 0x0f, "gpc00_tex_05", gf100_tex_sources }, + { 0x10, "gpc00_tex_06", gf100_tex_sources }, + { 0x11, "gpc00_tex_07", gf100_tex_sources }, + { 0x12, "gpc00_tex_08", gf100_tex_sources }, { 0x26, "gpc00_unk400_00", gf100_unk400_sources }, {} }, &gf100_perfctr_func }, -- GitLab From 2df0bf57f89cfa6e6adafb44d666ecc4a228a731 Mon Sep 17 00:00:00 2001 From: Samuel Pitoiset Date: Tue, 4 Aug 2015 23:58:15 +0200 Subject: [PATCH 5309/7006] drm/nouveau/pm/gf100: only use PBFB_BROADCAST.PM_UNK100 for PBFB signals High level hardware events related to PBFB will monitor all partitions. While we are at it, fix bitfield for this mux. Signed-off-by: Samuel Pitoiset Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 21 ++++++++-------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/pm/gf108.c | 25 +++---------------- .../gpu/drm/nouveau/nvkm/engine/pm/gf117.c | 21 ++-------------- .../gpu/drm/nouveau/nvkm/engine/pm/gk104.c | 4 +-- 5 files changed, 19 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index ab463898b437d..887d2dfeaa3cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -23,6 +23,16 @@ */ #include "gf100.h" +const struct nvkm_specsrc +gf100_pbfb_sources[] = { + { 0x10f100, (const struct nvkm_specmux[]) { + { 0x1, 0, "unk0" }, + { 0x3f, 4, "unk4" }, + {} + }, "pbfb_broadcast_pm_unk100" }, + {} +}; + const struct nvkm_specsrc gf100_pmfb_sources[] = { { 0x140028, (const struct nvkm_specmux[]) { @@ -44,17 +54,6 @@ gf100_l1_sources[] = { {} }; -static const struct nvkm_specsrc -gf100_pbfb_sources[] = { - { 0x10f100, (const struct nvkm_specmux[]) { - { 0x1, 0, "unk0" }, - { 0xf, 4, "unk4" }, - { 0x3, 8, "unk8" }, - {} - }, "pbfb_broadcast_pm_unk100" }, - {} -}; - static const struct nvkm_specsrc gf100_tex_sources[] = { { 0x5042c0, (const struct nvkm_specmux[]) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index d73f0ca442ebe..3a3a901e59296 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -26,7 +26,7 @@ int gf100_pm_fini(struct nvkm_object *, bool); extern const struct nvkm_specdom gf100_pm_gpc[]; +extern const struct nvkm_specsrc gf100_pbfb_sources[]; extern const struct nvkm_specsrc gf100_pmfb_sources[]; -extern const struct nvkm_specsrc gf117_pbfb_sources[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c index a74c68520ea72..a4d86d1ab1b0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c @@ -23,23 +23,6 @@ */ #include "gf100.h" -static const struct nvkm_specsrc -gf108_pbfb_sources[] = { - { 0x110100, (const struct nvkm_specmux[]) { - { 0x1, 0, "unk0" }, - { 0xf, 4, "unk4" }, - { 0x3, 8, "unk8" }, - {} - }, "pbfb0_pm_unk100" }, - { 0x111100, (const struct nvkm_specmux[]) { - { 0x1, 0, "unk0" }, - { 0xf, 4, "unk4" }, - { 0x3, 8, "unk8" }, - {} - }, "pbfb1_pm_unk100" }, - {} -}; - static const struct nvkm_specdom gf108_pm_hub[] = { {} @@ -48,10 +31,10 @@ gf108_pm_hub[] = { static const struct nvkm_specdom gf108_pm_part[] = { { 0xe0, (const struct nvkm_specsig[]) { - { 0x14, "part00_pbfb_00", gf108_pbfb_sources }, - { 0x15, "part00_pbfb_01", gf108_pbfb_sources }, - { 0x20, "part00_pbfb_02", gf108_pbfb_sources }, - { 0x21, "part00_pbfb_03", gf108_pbfb_sources }, + { 0x14, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x15, "part00_pbfb_01", gf100_pbfb_sources }, + { 0x20, "part00_pbfb_02", gf100_pbfb_sources }, + { 0x21, "part00_pbfb_03", gf100_pbfb_sources }, { 0x01, "part00_pmfb_00", gf100_pmfb_sources }, { 0x04, "part00_pmfb_01", gf100_pmfb_sources }, { 0x05, "part00_pmfb_02", gf100_pmfb_sources}, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c index 01d3a485e506b..a76c9283237d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c @@ -39,23 +39,6 @@ gf117_pmfb_sources[] = { {} }; -const struct nvkm_specsrc -gf117_pbfb_sources[] = { - { 0x110100, (const struct nvkm_specmux[]) { - { 0x1, 0, "unk0" }, - { 0xf, 4, "unk4" }, - { 0x3, 8, "unk8" }, - {} - }, "pbfb0_pm_unk100" }, - { 0x10f100, (const struct nvkm_specmux[]) { - { 0x1, 0, "unk0" }, - { 0xf, 4, "unk4" }, - { 0x3, 8, "unk8" }, - {} - }, "pbfb_broadcast_pm_unk100" }, - {} -}; - static const struct nvkm_specdom gf117_pm_hub[] = { {} @@ -64,8 +47,8 @@ gf117_pm_hub[] = { static const struct nvkm_specdom gf117_pm_part[] = { { 0xe0, (const struct nvkm_specsig[]) { - { 0x00, "part00_pbfb_00", gf117_pbfb_sources }, - { 0x01, "part00_pbfb_01", gf117_pbfb_sources }, + { 0x00, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x01, "part00_pbfb_01", gf100_pbfb_sources }, { 0x12, "part00_pmfb_00", gf117_pmfb_sources }, { 0x15, "part00_pmfb_01", gf117_pmfb_sources }, { 0x16, "part00_pmfb_02", gf117_pmfb_sources }, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c index 5067f72b8dda9..a236db9b7a686 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c @@ -145,8 +145,8 @@ gk104_pm_gpc[] = { static const struct nvkm_specdom gk104_pm_part[] = { { 0x60, (const struct nvkm_specsig[]) { - { 0x00, "part00_pbfb_00", gf117_pbfb_sources }, - { 0x01, "part00_pbfb_01", gf117_pbfb_sources }, + { 0x00, "part00_pbfb_00", gf100_pbfb_sources }, + { 0x01, "part00_pbfb_01", gf100_pbfb_sources }, { 0x0c, "part00_pmfb_00", gk104_pmfb_sources }, { 0x0d, "part00_pmfb_01", gk104_pmfb_sources }, { 0x0e, "part00_pmfb_02", gk104_pmfb_sources }, -- GitLab From 0a363e85cdafbceeee6a49b91c604d0d4d070dc7 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 23 Jul 2015 17:20:12 +0200 Subject: [PATCH 5310/7006] drm/nouveau/nv46: Change mc subdev oclass from nv44 to nv4c MSI interrupts appear to not work for nv46 based cards. Change the mc subdev oclass for these cards from nv44 to nv4c, the nv4c mc code is identical to the nv44 mc code except that it does not use msi (it does not define a msi_rearm callback). BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=90435 Signed-off-by: Hans de Goede Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index c6301361d14f3..b4ad791b48519 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -265,7 +265,7 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; + device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; -- GitLab From 895fb8e6f77589b9c50ff1f231b5025935d1d59f Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Mon, 17 Aug 2015 19:37:34 -0400 Subject: [PATCH 5311/7006] drm/nouveau/fb/sddr3: add WR/CWL values seen on a GK208 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c index 77c53f9559cd2..b4edc97dc8c58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c @@ -53,7 +53,7 @@ static const struct ramxlat ramddr3_wr[] = { { 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 }, /* the below are mentioned in some, but not all, ddr3 docs */ - { 14, 7 }, { 16, 0 }, + { 14, 7 }, { 15, 7 }, { 16, 0 }, { -1 } }; @@ -61,7 +61,7 @@ static const struct ramxlat ramddr3_cwl[] = { { 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 }, /* the below are mentioned in some, but not all, ddr3 docs */ - { 9, 4 }, + { 9, 4 }, { 10, 5 }, { -1 } }; -- GitLab From 7c11c99b3c66a8e03494e56ce6e6c5303ee85934 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 21 Aug 2015 10:52:54 +1000 Subject: [PATCH 5312/7006] drm/nouveau/bios/dcb: accept "maxwell" lane count values for dcb 4.0 We previously assumed that the values "2" and "4" were new in DCB 4.1, however, there's at least one GM107 DCB 4.0 board (Quadro K620) that uses the newer values. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_bios.c | 25 +++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/bios/dcb.c | 27 +++++++++---------- 2 files changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 0190b69bbe25f..e9de6e37af56d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1481,19 +1481,18 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, entry->dpconf.link_bw = 540000; break; } - entry->dpconf.link_nr = (conf & 0x0f000000) >> 24; - if (dcb->version < 0x41) { - switch (entry->dpconf.link_nr) { - case 0xf: - entry->dpconf.link_nr = 4; - break; - case 0x3: - entry->dpconf.link_nr = 2; - break; - default: - entry->dpconf.link_nr = 1; - break; - } + switch ((conf & 0x0f000000) >> 24) { + case 0xf: + case 0x4: + entry->dpconf.link_nr = 4; + break; + case 0x3: + case 0x2: + entry->dpconf.link_nr = 2; + break; + default: + entry->dpconf.link_nr = 1; + break; } link = entry->dpconf.sor.link; entry->i2c_index += NV_I2C_AUX(0); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c index 8d78140f94012..95e9208e47d14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c @@ -156,20 +156,19 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, break; } - outp->dpconf.link_nr = (conf & 0x0f000000) >> 24; - if (*ver < 0x41) { - switch (outp->dpconf.link_nr) { - case 0x0f: - outp->dpconf.link_nr = 4; - break; - case 0x03: - outp->dpconf.link_nr = 2; - break; - case 0x01: - default: - outp->dpconf.link_nr = 1; - break; - } + switch ((conf & 0x0f000000) >> 24) { + case 0xf: + case 0x4: + outp->dpconf.link_nr = 4; + break; + case 0x3: + case 0x2: + outp->dpconf.link_nr = 2; + break; + case 0x1: + default: + outp->dpconf.link_nr = 1; + break; } /* fall-through... */ -- GitLab From f10956d4455fcb24ecbdca30e6d9d88c95dc2588 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 21 Aug 2015 13:19:13 +1000 Subject: [PATCH 5313/7006] drm/nouveau/bios/dp: use alternate set of drvctl values where necessary Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c index 95970faae6c8a..20975d38542cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c @@ -148,7 +148,8 @@ nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx, outp = nvbios_dp_table(bios, ver, hdr, cnt, len); *hdr = *hdr + (*len * * cnt); *len = nv_ro08(bios, outp + 0x06); - *cnt = nv_ro08(bios, outp + 0x07); + *cnt = nv_ro08(bios, outp + 0x07) * + nv_ro08(bios, outp + 0x05); } if (idx < *cnt) @@ -196,12 +197,10 @@ nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, u16 data; if (*ver >= 0x30) { - /*XXX: there's a second set of these on at least 4.1, that - * i've witnessed nvidia using instead of the first - * on gm204. figure out what/why - */ const u8 vsoff[] = { 0, 4, 7, 9 }; idx = (pc * 10) + vsoff[vs] + pe; + if (*ver >= 0x40 && *hdr >= 0x12) + idx += nv_ro08(bios, outp + 0x11) * 40; } else { while ((data = nvbios_dpcfg_entry(bios, outp, ++idx, ver, hdr, cnt, len))) { -- GitLab From fe0f5d08806dcf7fd51092dfc6ea666ea2392692 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 21 Aug 2015 12:50:07 +1000 Subject: [PATCH 5314/7006] drm/nouveau/disp/dp: fix some tx_pu mishandling We only need to mask 0x0f on GM2xx, and want to keep the higher bits on earlier cards. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c | 7 ++++--- drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 8918da7ffdf25..2982ebf1affd1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -125,7 +125,7 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); + nv_wr32(priv, 0x61c130 + loff, data[2]); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c index 52fbe4880e13a..2107e314a1171 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c @@ -102,7 +102,7 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); + nv_wr32(priv, 0x61c130 + loff, data[2]); data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 1e40dfe113190..a2706e24f5c1d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -109,15 +109,16 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; + ocfg.tx_pu &= 0x0f; data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); data[2] = nv_rd32(priv, 0x61c130 + loff); - if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) - data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); + if ((data[2] & 0x00000f00) < (ocfg.tx_pu << 8) || ln == 0) + data[2] = (data[2] & ~0x00000f00) | (ocfg.tx_pu << 8); nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8)); + nv_wr32(priv, 0x61c130 + loff, data[2]); data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c index 20975d38542cc..dee047bbfd30d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c @@ -178,7 +178,7 @@ nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, info->pc = nv_ro08(bios, data + 0x00); info->dc = nv_ro08(bios, data + 0x01); info->pe = nv_ro08(bios, data + 0x02); - info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f; + info->tx_pu = nv_ro08(bios, data + 0x03); break; default: data = 0x0000; -- GitLab From 2a89359415da2fc1250b4c205de3c384bd781f54 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Fri, 21 Aug 2015 13:38:31 +1000 Subject: [PATCH 5315/7006] drm/nouveau/disp/dp: gm1xx appears to have same dp lane ordering as gm2xx Fixes 2-lane DP on Quadro K620. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 7 +++++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c | 9 +-------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index b4ed620070fa8..b9dfa660e7dd0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -214,6 +214,7 @@ extern struct nvkm_output_dp_impl nv50_pior_dp_impl; extern struct nvkm_oclass *nv50_disp_outp_sclass[]; extern struct nvkm_output_dp_impl g94_sor_dp_impl; +u32 g94_sor_dp_lane_map(struct nv50_disp_priv *, u8 lane); int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); extern struct nvkm_oclass *g94_disp_outp_sclass[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 2982ebf1affd1..22443627a0862 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -39,11 +39,14 @@ g94_sor_loff(struct nvkm_output_dp *outp) return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } -static inline u32 +u32 g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) { + static const u8 gm100[] = { 0, 8, 16, 24 }; static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ - static const u8 g94[] = { 16, 8, 0, 24 }; + static const u8 g94[] = { 16, 8, 0, 24 }; + if (nv_device(priv)->chipset >= 0x110) + return gm100[lane]; if (nv_device(priv)->chipset == 0xaf) return mcp89[lane]; return g94[lane]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c index 2107e314a1171..1f02b603e19a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c @@ -36,13 +36,6 @@ gf110_sor_loff(struct nvkm_output_dp *outp) return gf110_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } -static inline u32 -gf110_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) -{ - static const u8 gf110[] = { 16, 8, 0, 24 }; - return gf110[lane]; -} - static int gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { @@ -77,7 +70,7 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, { struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = gf110_sor_dp_lane_map(priv, ln); + const u32 shift = g94_sor_dp_lane_map(priv, ln); const u32 loff = gf110_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; -- GitLab From 205877f9156daebb975fb46205488da6fdf5b3f5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 27 Aug 2015 17:33:19 +1000 Subject: [PATCH 5316/7006] drm/nouveau/pmu/gk104: implement a hackish workaround for a hw bug Only a handful of machines have this enabled by default, where it's been proven to work. The workaround can be explicitly enabled with a module option also. Still waiting on feedback from NVIDIA for a proper idea of exactly what this fix is doing, and how to implement it properly. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 28fdb8ea9ed85..b744136f55267 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -26,9 +26,36 @@ #include "priv.h" #include "fuc/gf110.fuc4.h" +#include +#include +#include + +static void +magic_(struct nvkm_pmu *pmu, u32 ctrl, int size) +{ + nv_wr32(pmu, 0x00c800, 0x00000000); + nv_wr32(pmu, 0x00c808, 0x00000000); + nv_wr32(pmu, 0x00c800, ctrl); + if (nv_wait(pmu, 0x00c800, 0x40000000, 0x40000000)) { + while (size--) + nv_wr32(pmu, 0x00c804, 0x00000000); + } + nv_wr32(pmu, 0x00c800, 0x00000000); +} + +static void +magic(struct nvkm_pmu *pmu, u32 ctrl) +{ + magic_(pmu, 0x8000a41f | ctrl, 6); + magic_(pmu, 0x80000421 | ctrl, 1); +} + static void gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { + struct nvkm_device *device = nv_device(pmu); + struct nvkm_object *dev = nv_object(device); + nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); nv_rd32(pmu, 0x000200); nv_mask(pmu, 0x000200, 0x08000000, 0x08000000); @@ -48,6 +75,30 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nv_mask(pmu, 0x000200, 0x08000000, 0x00000000); nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); nv_rd32(pmu, 0x000200); + + if (nv_device_match(dev, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ + || nv_device_match(dev, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ + || nvkm_boolopt(device->cfgopt, "War00C800_0", false)) { + nv_info(pmu, "hw bug workaround enabled\n"); + switch (device->chipset) { + case 0xe4: + magic(pmu, 0x04000000); + magic(pmu, 0x06000000); + magic(pmu, 0x0c000000); + magic(pmu, 0x0e000000); + break; + case 0xe6: + magic(pmu, 0x02000000); + magic(pmu, 0x04000000); + magic(pmu, 0x0a000000); + break; + case 0xe7: + magic(pmu, 0x02000000); + break; + default: + break; + } + } } struct nvkm_oclass * -- GitLab From 0d5dd3f301bbc66c41b219f50fa97a6df1965cfe Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:05 +1000 Subject: [PATCH 5317/7006] drm/nouveau/lib: various tweaks Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 63d8e52f4b226..0f6ce3749e14d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -727,7 +727,7 @@ nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name, nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE"); nv_engine(device)->sclass = nvkm_device_sclass; - list_add(&device->head, &nv_devices); + list_add_tail(&device->head, &nv_devices); ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); done: -- GitLab From d351b8569e3c57bf5dc3dd5a1295974a9e04316e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:05 +1000 Subject: [PATCH 5318/7006] drm/nouveau/subdev: add direct pointer to nvkm_device Will be utilised in upcoming commits to remove the need for heuristics to lookup the device a subdev belongs to. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/tvnv17.c | 8 ++++---- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 3 +-- drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h | 3 +++ drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 3 +++ drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 3 ++- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 5 ++--- 6 files changed, 15 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index d9720dda83851..792bf5428f354 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -130,17 +130,17 @@ static bool get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->device; + struct nvkm_device *device = nvxx_device(&drm->device); /* Zotac FX5200 */ - if (nv_device_match(nvxx_object(device), 0x0322, 0x19da, 0x1035) || - nv_device_match(nvxx_object(device), 0x0322, 0x19da, 0x2035)) { + if (nv_device_match(device, 0x0322, 0x19da, 0x1035) || + nv_device_match(device, 0x0322, 0x19da, 0x2035)) { *pin_mask = 0xc; return false; } /* MSI nForce2 IGP */ - if (nv_device_match(nvxx_object(device), 0x01f0, 0x1462, 0x5710)) { + if (nv_device_match(device, 0x01f0, 0x1462, 0x5710)) { *pin_mask = 0xc; return false; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 333db33a162c8..5983b307e1278 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -49,9 +49,8 @@ int nvkm_device_list(u64 *name, int size); struct nvkm_device *nv_device(void *obj); static inline bool -nv_device_match(struct nvkm_object *object, u16 dev, u16 ven, u16 sub) +nv_device_match(struct nvkm_device *device, u16 dev, u16 ven, u16 sub) { - struct nvkm_device *device = nv_device(object); return device->pdev->device == dev && device->pdev->subsystem_vendor == ven && device->pdev->subsystem_device == sub; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index 6fdc39116aac9..8357319f5a147 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -8,6 +8,9 @@ struct nvkm_subdev { struct nvkm_object object; + + struct nvkm_device *device; + struct mutex mutex; const char *name; void __iomem *mmio; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index c5fb3a7931741..b96cb2cca55e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -114,6 +114,9 @@ nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_device *device = nv_device(parent); subdev->debug = nvkm_dbgopt(device->dbgopt, subname); subdev->mmio = nv_subdev(device)->mmio; + subdev->device = device; + } else { + subdev->device = nv_device(subdev); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index dea58161ba465..980822d6d6451 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -44,6 +44,7 @@ static int nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { + struct nvkm_device *device = gpio->base.device; struct nvkm_bios *bios = nvkm_bios(gpio); u8 ver, len; u16 data; @@ -56,7 +57,7 @@ nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, return 0; /* Apple iMac G4 NV18 */ - if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) { + if (nv_device_match(device, 0x0189, 0x10de, 0x0010)) { if (tag == DCB_GPIO_TVDAC0) { *func = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index b744136f55267..1e9f1d0f7a7d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -54,7 +54,6 @@ static void gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { struct nvkm_device *device = nv_device(pmu); - struct nvkm_object *dev = nv_object(device); nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); nv_rd32(pmu, 0x000200); @@ -76,8 +75,8 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); nv_rd32(pmu, 0x000200); - if (nv_device_match(dev, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ - || nv_device_match(dev, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ + if (nv_device_match(device, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ + || nv_device_match(device, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ || nvkm_boolopt(device->cfgopt, "War00C800_0", false)) { nv_info(pmu, "hw bug workaround enabled\n"); switch (device->chipset) { -- GitLab From 741d778ea0dde26a345717f1843407760f02fe03 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:05 +1000 Subject: [PATCH 5319/7006] drm/nouveau/device: add direct pointers to subdevs from nvkm_device Will be used in upcoming commits to remove the need for lookup/runtime type-checking functions when accessing foreign subdevs. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 40 ++++++++++++ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 63 ++++++++++++++++--- 2 files changed, 96 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 5983b307e1278..a3037f7d128d5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -41,6 +41,46 @@ struct nvkm_device { struct { struct notifier_block nb; } acpi; + + struct nvkm_bar *bar; + struct nvkm_bios *bios; + struct nvkm_bus *bus; + struct nvkm_clk *clk; + struct nvkm_devinit *devinit; + struct nvkm_fb *fb; + struct nvkm_fuse *fuse; + struct nvkm_gpio *gpio; + struct nvkm_i2c *i2c; + struct nvkm_subdev *ibus; + struct nvkm_instmem *imem; + struct nvkm_ltc *ltc; + struct nvkm_mc *mc; + struct nvkm_mmu *mmu; + struct nvkm_subdev *mxm; + struct nvkm_pmu *pmu; + struct nvkm_therm *therm; + struct nvkm_timer *timer; + struct nvkm_volt *volt; + + struct nvkm_engine *bsp; + struct nvkm_engine *ce[3]; + struct nvkm_engine *cipher; + struct nvkm_disp *disp; + struct nvkm_dmaeng *dma; + struct nvkm_fifo *fifo; + struct nvkm_gr *gr; + struct nvkm_engine *ifb; + struct nvkm_engine *me; + struct nvkm_engine *mpeg; + struct nvkm_engine *msenc; + struct nvkm_engine *mspdec; + struct nvkm_engine *msppp; + struct nvkm_engine *msvld; + struct nvkm_pm *pm; + struct nvkm_engine *sec; + struct nvkm_sw *sw; + struct nvkm_engine *vic; + struct nvkm_engine *vp; }; struct nvkm_device *nvkm_device_find(u64 name); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 0f6ce3749e14d..2bceecc9c1e01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -463,14 +463,63 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, continue; } - ret = nvkm_object_ctor(nv_object(device), NULL, oclass, - NULL, i, &devobj->subdev[i]); - if (ret == -ENODEV) +#define _(s,m) case s: \ + ret = nvkm_object_ctor(nv_object(device), NULL, oclass, NULL, \ + (s), (struct nvkm_object **)&device->m);\ + if (ret == -ENODEV) \ + continue; \ + if (ret) \ + return ret; \ + devobj->subdev[s] = (struct nvkm_object *)device->m; \ + device->subdev[s] = devobj->subdev[s]; \ + break + + switch (i) { + _(NVDEV_SUBDEV_BAR , bar); + _(NVDEV_SUBDEV_VBIOS , bios); + _(NVDEV_SUBDEV_BUS , bus); + _(NVDEV_SUBDEV_CLK , clk); + _(NVDEV_SUBDEV_DEVINIT, devinit); + _(NVDEV_SUBDEV_FB , fb); + _(NVDEV_SUBDEV_FUSE , fuse); + _(NVDEV_SUBDEV_GPIO , gpio); + _(NVDEV_SUBDEV_I2C , i2c); + _(NVDEV_SUBDEV_IBUS , ibus); + _(NVDEV_SUBDEV_INSTMEM, imem); + _(NVDEV_SUBDEV_LTC , ltc); + _(NVDEV_SUBDEV_MC , mc); + _(NVDEV_SUBDEV_MMU , mmu); + _(NVDEV_SUBDEV_MXM , mxm); + _(NVDEV_SUBDEV_PMU , pmu); + _(NVDEV_SUBDEV_THERM , therm); + _(NVDEV_SUBDEV_TIMER , timer); + _(NVDEV_SUBDEV_VOLT , volt); + _(NVDEV_ENGINE_BSP , bsp); + _(NVDEV_ENGINE_CE0 , ce[0]); + _(NVDEV_ENGINE_CE1 , ce[1]); + _(NVDEV_ENGINE_CE2 , ce[2]); + _(NVDEV_ENGINE_CIPHER , cipher); + _(NVDEV_ENGINE_DISP , disp); + _(NVDEV_ENGINE_DMAOBJ , dma); + _(NVDEV_ENGINE_FIFO , fifo); + _(NVDEV_ENGINE_GR , gr); + _(NVDEV_ENGINE_IFB , ifb); + _(NVDEV_ENGINE_ME , me); + _(NVDEV_ENGINE_MPEG , mpeg); + _(NVDEV_ENGINE_MSENC , msenc); + _(NVDEV_ENGINE_MSPDEC , mspdec); + _(NVDEV_ENGINE_MSPPP , msppp); + _(NVDEV_ENGINE_MSVLD , msvld); + _(NVDEV_ENGINE_PM , pm); + _(NVDEV_ENGINE_SEC , sec); + _(NVDEV_ENGINE_SW , sw); + _(NVDEV_ENGINE_VIC , vic); + _(NVDEV_ENGINE_VP , vp); + default: + WARN_ON(1); continue; - if (ret) - return ret; - - device->subdev[i] = devobj->subdev[i]; + } +#undef _ /* note: can't init *any* subdevs until devinit has been run * due to not knowing exactly what the vbios init tables will -- GitLab From 6d0d40e7a577bbc7497ee7fbfeb2315d46a872a6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5320/7006] drm/nouveau/device: add direct pointer to struct device A future commit will hide the platform/pci specifics from nvkm_device, but it's still very useful in a lot of places to have access to the Linux device struct. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index a3037f7d128d5..d5811a0212bea 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -9,6 +9,7 @@ struct nvkm_device { struct pci_dev *pdev; struct platform_device *platformdev; + struct device *dev; u64 handle; struct nvkm_event event; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 2bceecc9c1e01..28ebe06e87b93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -764,9 +764,11 @@ nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name, switch (type) { case NVKM_BUS_PCI: device->pdev = dev; + device->dev = &device->pdev->dev; break; case NVKM_BUS_PLATFORM: device->platformdev = dev; + device->dev = &device->platformdev->dev; break; } device->handle = name; -- GitLab From 9ace404b1098221021b01c2ba0eeea0c257fa4a5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5321/7006] drm/nouveau/device: include core/device.h automatically for subdevs/engines Pretty much every subdev/engine is going to need access to nvkm_device shortly to touch registers and/or output messages. The odd placement of the includes is necessary to work around some inter-dependencies that currently exist. This will be fixed later. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 60 ++++++++++++++++++ .../drm/nouveau/include/nvkm/core/devidx.h | 62 ------------------- .../drm/nouveau/include/nvkm/core/engine.h | 2 + .../drm/nouveau/include/nvkm/core/subdev.h | 3 +- .../gpu/drm/nouveau/include/nvkm/subdev/vga.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 1 - .../gpu/drm/nouveau/nvkm/engine/disp/vga.c | 2 - .../gpu/drm/nouveau/nvkm/engine/dmaobj/base.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 1 - .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c | 1 - .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 1 - .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h | 1 - drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/bar/base.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/bios/dcb.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/bios/perf.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 1 - .../drm/nouveau/nvkm/subdev/bios/shadowacpi.c | 2 - .../drm/nouveau/nvkm/subdev/bios/shadowof.c | 1 - .../drm/nouveau/nvkm/subdev/bios/shadowpci.c | 2 - .../nouveau/nvkm/subdev/bios/shadowramin.c | 2 - .../drm/nouveau/nvkm/subdev/bios/shadowrom.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/bios/therm.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/clk/nv40.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 1 - .../drm/nouveau/nvkm/subdev/devinit/base.c | 1 - .../drm/nouveau/nvkm/subdev/devinit/fbmem.h | 1 - .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 2 - drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c | 2 - drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 1 - .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 1 - drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 1 - drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/pmu/memx.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/therm/base.c | 2 - .../drm/nouveau/nvkm/subdev/therm/fanpwm.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/therm/gf110.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/therm/gm107.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/therm/gt215.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/therm/nv40.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/therm/nv50.c | 2 - .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 2 - 78 files changed, 65 insertions(+), 159 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index d5811a0212bea..4ae876096c7d1 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -3,6 +3,66 @@ #include #include +enum nvkm_devidx { + NVDEV_ENGINE_DEVICE, + NVDEV_SUBDEV_VBIOS, + + /* All subdevs from DEVINIT to DEVINIT_LAST will be created before + * *any* of them are initialised. This subdev category is used + * for any subdevs that the VBIOS init table parsing may call out + * to during POST. + */ + NVDEV_SUBDEV_DEVINIT, + NVDEV_SUBDEV_IBUS, + NVDEV_SUBDEV_GPIO, + NVDEV_SUBDEV_I2C, + NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C, + + /* This grouping of subdevs are initialised right after they've + * been created, and are allowed to assume any subdevs in the + * list above them exist and have been initialised. + */ + NVDEV_SUBDEV_FUSE, + NVDEV_SUBDEV_MXM, + NVDEV_SUBDEV_MC, + NVDEV_SUBDEV_BUS, + NVDEV_SUBDEV_TIMER, + NVDEV_SUBDEV_FB, + NVDEV_SUBDEV_LTC, + NVDEV_SUBDEV_INSTMEM, + NVDEV_SUBDEV_MMU, + NVDEV_SUBDEV_BAR, + NVDEV_SUBDEV_PMU, + NVDEV_SUBDEV_VOLT, + NVDEV_SUBDEV_THERM, + NVDEV_SUBDEV_CLK, + + NVDEV_ENGINE_FIRST, + NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST, + NVDEV_ENGINE_IFB, + NVDEV_ENGINE_FIFO, + NVDEV_ENGINE_SW, + NVDEV_ENGINE_GR, + NVDEV_ENGINE_MPEG, + NVDEV_ENGINE_ME, + NVDEV_ENGINE_VP, + NVDEV_ENGINE_CIPHER, + NVDEV_ENGINE_BSP, + NVDEV_ENGINE_MSPPP, + NVDEV_ENGINE_CE0, + NVDEV_ENGINE_CE1, + NVDEV_ENGINE_CE2, + NVDEV_ENGINE_VIC, + NVDEV_ENGINE_MSENC, + NVDEV_ENGINE_DISP, + NVDEV_ENGINE_PM, + NVDEV_ENGINE_MSVLD, + NVDEV_ENGINE_SEC, + NVDEV_ENGINE_MSPDEC, + + NVDEV_SUBDEV_NR, +}; + struct nvkm_device { struct nvkm_engine engine; struct list_head head; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h deleted file mode 100644 index 60c5888b5df3d..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef __NVKM_DEVIDX_H__ -#define __NVKM_DEVIDX_H__ -enum nvkm_devidx { - NVDEV_ENGINE_DEVICE, - NVDEV_SUBDEV_VBIOS, - - /* All subdevs from DEVINIT to DEVINIT_LAST will be created before - * *any* of them are initialised. This subdev category is used - * for any subdevs that the VBIOS init table parsing may call out - * to during POST. - */ - NVDEV_SUBDEV_DEVINIT, - NVDEV_SUBDEV_IBUS, - NVDEV_SUBDEV_GPIO, - NVDEV_SUBDEV_I2C, - NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C, - - /* This grouping of subdevs are initialised right after they've - * been created, and are allowed to assume any subdevs in the - * list above them exist and have been initialised. - */ - NVDEV_SUBDEV_FUSE, - NVDEV_SUBDEV_MXM, - NVDEV_SUBDEV_MC, - NVDEV_SUBDEV_BUS, - NVDEV_SUBDEV_TIMER, - NVDEV_SUBDEV_FB, - NVDEV_SUBDEV_LTC, - NVDEV_SUBDEV_INSTMEM, - NVDEV_SUBDEV_MMU, - NVDEV_SUBDEV_BAR, - NVDEV_SUBDEV_PMU, - NVDEV_SUBDEV_VOLT, - NVDEV_SUBDEV_THERM, - NVDEV_SUBDEV_CLK, - - NVDEV_ENGINE_FIRST, - NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST, - NVDEV_ENGINE_IFB, - NVDEV_ENGINE_FIFO, - NVDEV_ENGINE_SW, - NVDEV_ENGINE_GR, - NVDEV_ENGINE_MPEG, - NVDEV_ENGINE_ME, - NVDEV_ENGINE_VP, - NVDEV_ENGINE_CIPHER, - NVDEV_ENGINE_BSP, - NVDEV_ENGINE_MSPPP, - NVDEV_ENGINE_CE0, - NVDEV_ENGINE_CE1, - NVDEV_ENGINE_CE2, - NVDEV_ENGINE_VIC, - NVDEV_ENGINE_MSENC, - NVDEV_ENGINE_DISP, - NVDEV_ENGINE_PM, - NVDEV_ENGINE_MSVLD, - NVDEV_ENGINE_SEC, - NVDEV_ENGINE_MSPDEC, - - NVDEV_SUBDEV_NR, -}; -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index faf0fd2f0638c..441f843f24909 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -53,4 +53,6 @@ int nvkm_engine_create_(struct nvkm_object *, struct nvkm_object *, #define _nvkm_engine_dtor _nvkm_subdev_dtor #define _nvkm_engine_init _nvkm_subdev_init #define _nvkm_engine_fini _nvkm_subdev_fini + +#include #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index 8357319f5a147..d2dac06f2b8bd 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -1,7 +1,6 @@ #ifndef __NVKM_SUBDEV_H__ #define __NVKM_SUBDEV_H__ #include -#include #define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub)) #define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var)) @@ -119,4 +118,6 @@ nv_mask(void *obj, u32 addr, u32 mask, u32 data) nv_wr32(obj, addr, (temp & ~mask) | data); return temp; } + +#include #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h index fee09ad818e48..53294f42c690c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h @@ -1,7 +1,6 @@ #ifndef __NOUVEAU_VGA_H__ #define __NOUVEAU_VGA_H__ - -#include +#include /* access to various legacy io ports */ u8 nv_rdport(void *obj, int head, u16 port); @@ -26,5 +25,4 @@ void nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value); bool nv_lockvgac(void *obj, bool lock); u8 nv_rdvgaowner(void *obj); void nv_wrvgaowner(void *obj, u8); - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index d8bb4293bc11d..72604d332596b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -27,7 +27,6 @@ #include "fuc/gt215.fuc3.h" #include -#include #include struct gt215_ce_priv { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index ff09b2659c176..b8f9e5c2b3c85 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -24,7 +24,6 @@ #include "priv.h" #include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 8ba808df24ad2..25fcabcb1d6c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -26,7 +26,6 @@ #include "outpdp.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 22443627a0862..0b4ecb8375976 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -24,7 +24,6 @@ #include "nv50.h" #include "outpdp.h" -#include #include static inline u32 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c index c4622c7388d08..c91d73bc9c9bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c @@ -23,8 +23,6 @@ */ #include -#include - u8 nv_rdport(void *obj, int head, u16 port) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c index a2b60d86baba9..3adab2ed7c08c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c @@ -24,7 +24,6 @@ #include "priv.h" #include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 30958c19e61d9..f6e9ae95c8224 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -21,7 +21,6 @@ */ #include -#include #include void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index fa223f88d25ea..a85014bb37a77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -24,7 +24,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 043e4296084c1..d157aaede4050 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -24,7 +24,6 @@ #include "nv04.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 5bfc96265f3bf..24930d9b6ae44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -24,7 +24,6 @@ #include "nv04.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c index dc31462afe655..a3b0b366f5829 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c @@ -111,7 +111,6 @@ #include "ctxnv40.h" #include "nv40.h" -#include /* TODO: * - get vs count from 0x1540 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index 9c9528d2cd90d..a9a4e0e3f2cb7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -107,7 +107,6 @@ #include "ctxnv40.h" -#include #include #define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index e7c3e9e57385b..1ca9385f5479c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -26,7 +26,6 @@ #include "fuc/os.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 2614510c28d0d..81abe6fb38724 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -25,7 +25,6 @@ #include "regs.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 389904eb603f7..62a4d797498aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -25,7 +25,6 @@ #include "regs.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 1713ffb669e89..5d8dbac3cdb82 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -2,7 +2,6 @@ #include "regs.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index dcc84eb54fb6d..207464c3c40ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -1,7 +1,6 @@ #include "nv20.h" #include "regs.h" -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h index d852bd6de5713..01d9f73a024cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h @@ -2,7 +2,6 @@ #define __NV40_GR_H__ #include -#include struct nvkm_gpuobj; /* returns 1 if device is one of the nv4x using the 0x4497 object class, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 270d7cd63fc7f..754284feae915 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -24,7 +24,6 @@ #include "nv50.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 48c1ce6e663c0..8741201d4236e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -24,7 +24,6 @@ #include "priv.h" #include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 401fcd73086b3..14d9650f47790 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -23,7 +23,6 @@ */ #include "nv50.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index cea90df533d96..3995d2cf06681 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -20,7 +20,6 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include -#include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 3502d00122ef1..9b6b9ac34cedc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 12a1aebd9a96e..4c6d238dd3da4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 8548adb91dcc5..36c5c083c1e93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c index 95e9208e47d14..1463571717574 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c @@ -24,8 +24,6 @@ #include #include -#include - u16 dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 8e5f6ce76232c..045b7ddb4d665 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -31,7 +31,6 @@ #include #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c index 382ae9cdbf58a..1e70d0eaed418 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c @@ -25,8 +25,6 @@ #include #include -#include - u16 nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index ebd402e19dbf8..ac48ccc5d2c43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -27,7 +27,6 @@ #include #include -#include struct pll_mapping { u8 type; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index 8c2b7cba5cffa..6192a9e27bb70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c index f9d0eb5647fa3..74604d4a7ff2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c @@ -22,8 +22,6 @@ */ #include "priv.h" -#include - #if defined(CONFIG_ACPI) && defined(CONFIG_X86) int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); bool nouveau_acpi_rom_supported(struct pci_dev *pdev); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index 4c19a7dba8037..4f5cbf4d9666e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c @@ -22,7 +22,6 @@ */ #include "priv.h" -#include #if defined(__powerpc__) struct priv { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c index 1b045483dc87b..ae1e229b617f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c @@ -22,8 +22,6 @@ */ #include "priv.h" -#include - struct priv { struct pci_dev *pdev; void __iomem *rom; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c index abe8ae4d3a9f5..c2c31ba59868d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c @@ -22,8 +22,6 @@ */ #include "priv.h" -#include - struct priv { struct nvkm_bios *bios; u32 bar0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c index 6ec3b237925e3..cd0b06fbc3c2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c @@ -22,8 +22,6 @@ */ #include "priv.h" -#include - static u32 prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c index 249ff6d583dff..8fbb8917b0e22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c @@ -25,8 +25,6 @@ #include #include -#include - static u16 therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 77a0ab5ca3b01..cba018d02b4b0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -30,7 +30,6 @@ #include #include -#include #include /****************************************************************************** diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 3d7330d54b02d..e8125b5199a47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -24,7 +24,6 @@ #include #include "pll.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index e9b2310bdfbbe..e380d62df2320 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -24,7 +24,6 @@ #include #include "pll.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 65c532742b08d..94d3839fd444d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -25,8 +25,6 @@ #include #include -#include - #ifdef __KERNEL__ #include #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 065e9f5c8db98..581e3a696fd8f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -25,7 +25,6 @@ #include "gt215.h" #include "pll.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index c54417b146c7a..d735de2dbd74c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -24,7 +24,6 @@ #include "gt215.h" #include "pll.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index ed838130c89d1..15668d2883f1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -24,7 +24,6 @@ #include #include "pll.h" -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 89c5d886f2adf..b58f4786e4076 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -25,7 +25,6 @@ #include "pll.h" #include "seq.h" -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index b0d7c5f40db1f..5cc7dd24a2135 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h index 36684c3f9e9c8..4e484c40b5c63 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h @@ -23,7 +23,6 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include #include #define NV04_PFB_DEBUG_0 0x00100080 diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index d51aa0237baf0..5a6c2b7a6ef18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -23,8 +23,6 @@ */ #include "gf100.h" -#include - extern const u8 gf100_pte_storage_type_map[256]; bool diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c index 09ebb9477e00c..6c0b82f35d94f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c @@ -25,8 +25,6 @@ */ #include "nv04.h" -#include - void nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 0480ce52aa062..48fd5a5bcd3ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -24,7 +24,6 @@ #include "nv50.h" #include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index de9f39569943b..dcb175bea84bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -24,7 +24,6 @@ #include "gf100.h" #include "ramfuc.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 1ef15c3e6a81b..97060ccfb80c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -24,7 +24,6 @@ #include "ramfuc.h" #include "gf100.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index bc36a4ff15f45..1d604c075a3ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -26,7 +26,6 @@ #include "ramfuc.h" #include "nv50.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c index fbae05db4ffdf..8bb7e432ad044 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c @@ -23,8 +23,6 @@ */ #include "priv.h" -#include - static int nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 3d31fa45c1a6f..a36a90c29ba90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -23,7 +23,6 @@ */ #include "nv40.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 66db0a4e25386..fd0e9cecef62c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -24,7 +24,6 @@ #include "nv50.h" #include "ramseq.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index 980822d6d6451..f60284f3b8b50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 9200f122c02cc..3e2c2882d5153 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -24,7 +24,6 @@ #include "priv.h" #include "pad.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index dd0994d9ebfc3..cd8ab5fcb585f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -40,7 +40,6 @@ #include #include -#include #ifdef __KERNEL__ #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 5b051a26653eb..8699e5b2f497d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include static inline void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 40e3019e1fdeb..9c43ddce9992d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -23,8 +23,6 @@ */ #include "nv04.h" -#include - const struct nvkm_mc_intr nv50_mc_intr[] = { { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index fe93ea2711c99..861c97adec70c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -23,7 +23,6 @@ */ #include "nv04.h" -#include #include #define NV04_PDMA_SIZE (128 * 1024 * 1024) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 61ee3ab11660a..37b943aba1146 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -23,7 +23,6 @@ */ #include "nv04.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index b90ded1887aad..87824693f9ccf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -23,7 +23,6 @@ */ #include "nv04.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 0ca9dcabb6d37..7ecacf60f5417 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -23,7 +23,6 @@ */ #include "mxms.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index b75c5b8859802..8e69bc75e5716 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -2,8 +2,6 @@ #define __NVKM_PMU_MEMX_H__ #include "priv.h" -#include - struct nvkm_memx { struct nvkm_pmu *pmu; u32 base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index ec327cb64a0da..eb86c3ed5f568 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -23,8 +23,6 @@ */ #include "priv.h" -#include - static int nvkm_therm_update_trip(struct nvkm_therm *therm) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index bde5ceaeb70ae..3cf4192a33af9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -24,7 +24,6 @@ */ #include "priv.h" -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c index 46b7e656a752a..0540e6886d7d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c @@ -23,8 +23,6 @@ */ #include "priv.h" -#include - struct gf110_therm_priv { struct nvkm_therm_priv base; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c index 2fd110f098784..c1f3cf3618378 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c @@ -23,8 +23,6 @@ */ #include "priv.h" -#include - struct gm107_therm_priv { struct nvkm_therm_priv base; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c index e99be20332f2d..b7fa4716ca9f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c @@ -23,7 +23,6 @@ */ #include "priv.h" -#include #include struct gt215_therm_priv { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c index 8496fffd46888..20f65fd7679ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c @@ -24,8 +24,6 @@ */ #include "priv.h" -#include - struct nv40_therm_priv { struct nvkm_therm_priv base; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c index 1ef59e8922d49..489dcf355d346 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c @@ -24,8 +24,6 @@ */ #include "priv.h" -#include - struct nv50_therm_priv { struct nvkm_therm_priv base; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index 6b7facbe59a26..cf386f9c84c92 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -23,8 +23,6 @@ */ #include "nv04.h" -#include - static u64 nv04_timer_read(struct nvkm_timer *ptimer) { -- GitLab From 5b0c189fcb232daa1cabac8892e42cdee57254bd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5322/7006] drm/nouveau/bar: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/bar.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/base.c | 14 +- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 86 +++++----- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 156 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/bar/priv.h | 4 +- 5 files changed, 127 insertions(+), 135 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h index c7a007b8bc10f..753b7e9530351 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h @@ -5,7 +5,7 @@ struct nvkm_mem; struct nvkm_vma; struct nvkm_bar { - struct nvkm_subdev base; + struct nvkm_subdev subdev; int (*alloc)(struct nvkm_bar *, struct nvkm_object *, struct nvkm_mem *, struct nvkm_object **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 9b6b9ac34cedc..664a1789500ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -117,22 +117,14 @@ int nvkm_bar_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_bar *bar; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "BARCTL", - "bar", length, pobject); - bar = *pobject; - if (ret) - return ret; - - return 0; + return nvkm_subdev_create_(parent, engine, oclass, 0, "BARCTL", + "bar", length, pobject); } void nvkm_bar_destroy(struct nvkm_bar *bar) { - nvkm_subdev_destroy(&bar->base); + nvkm_subdev_destroy(&bar->subdev); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 4c6d238dd3da4..5f091d2c560b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -27,26 +27,26 @@ #include #include -struct gf100_bar_priv_vm { +struct gf100_bar_vm { struct nvkm_gpuobj *mem; struct nvkm_gpuobj *pgd; struct nvkm_vm *vm; }; -struct gf100_bar_priv { +struct gf100_bar { struct nvkm_bar base; spinlock_t lock; - struct gf100_bar_priv_vm bar[2]; + struct gf100_bar_vm bar[2]; }; static int -gf100_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, +gf100_bar_kmap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, struct nvkm_vma *vma) { - struct gf100_bar_priv *priv = (void *)bar; + struct gf100_bar *bar = container_of(obj, typeof(*bar), base); int ret; - ret = nvkm_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma); + ret = nvkm_vm_get(bar->bar[0].vm, mem->size << 12, 12, flags, vma); if (ret) return ret; @@ -55,13 +55,13 @@ gf100_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, } static int -gf100_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, +gf100_bar_umap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, struct nvkm_vma *vma) { - struct gf100_bar_priv *priv = (void *)bar; + struct gf100_bar *bar = container_of(obj, typeof(*bar), base); int ret; - ret = nvkm_vm_get(priv->bar[1].vm, mem->size << 12, + ret = nvkm_vm_get(bar->bar[1].vm, mem->size << 12, mem->page_shift, flags, vma); if (ret) return ret; @@ -78,20 +78,20 @@ gf100_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) } static int -gf100_bar_ctor_vm(struct gf100_bar_priv *priv, struct gf100_bar_priv_vm *bar_vm, +gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, int bar_nr) { - struct nvkm_device *device = nv_device(&priv->base); + struct nvkm_device *device = nv_device(&bar->base); struct nvkm_vm *vm; resource_size_t bar_len; int ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0, + ret = nvkm_gpuobj_new(nv_object(bar), NULL, 0x1000, 0, 0, &bar_vm->mem); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0, + ret = nvkm_gpuobj_new(nv_object(bar), NULL, 0x8000, 0, 0, &bar_vm->pgd); if (ret) return ret; @@ -108,7 +108,7 @@ gf100_bar_ctor_vm(struct gf100_bar_priv *priv, struct gf100_bar_priv_vm *bar_vm, * Bootstrap page table lookup. */ if (bar_nr == 3) { - ret = nvkm_gpuobj_new(nv_object(priv), NULL, + ret = nvkm_gpuobj_new(nv_object(bar), NULL, (bar_len >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); @@ -135,74 +135,74 @@ gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = nv_device(parent); - struct gf100_bar_priv *priv; + struct gf100_bar *bar; bool has_bar3 = nv_device_resource_len(device, 3) != 0; int ret; - ret = nvkm_bar_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_bar_create(parent, engine, oclass, &bar); + *pobject = nv_object(bar); if (ret) return ret; /* BAR3 */ if (has_bar3) { - ret = gf100_bar_ctor_vm(priv, &priv->bar[0], 3); + ret = gf100_bar_ctor_vm(bar, &bar->bar[0], 3); if (ret) return ret; } /* BAR1 */ - ret = gf100_bar_ctor_vm(priv, &priv->bar[1], 1); + ret = gf100_bar_ctor_vm(bar, &bar->bar[1], 1); if (ret) return ret; if (has_bar3) { - priv->base.alloc = nvkm_bar_alloc; - priv->base.kmap = gf100_bar_kmap; + bar->base.alloc = nvkm_bar_alloc; + bar->base.kmap = gf100_bar_kmap; } - priv->base.umap = gf100_bar_umap; - priv->base.unmap = gf100_bar_unmap; - priv->base.flush = g84_bar_flush; - spin_lock_init(&priv->lock); + bar->base.umap = gf100_bar_umap; + bar->base.unmap = gf100_bar_unmap; + bar->base.flush = g84_bar_flush; + spin_lock_init(&bar->lock); return 0; } void gf100_bar_dtor(struct nvkm_object *object) { - struct gf100_bar_priv *priv = (void *)object; + struct gf100_bar *bar = (void *)object; - nvkm_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd); - nvkm_gpuobj_ref(NULL, &priv->bar[1].pgd); - nvkm_gpuobj_ref(NULL, &priv->bar[1].mem); + nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); + nvkm_gpuobj_ref(NULL, &bar->bar[1].pgd); + nvkm_gpuobj_ref(NULL, &bar->bar[1].mem); - if (priv->bar[0].vm) { - nvkm_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]); - nvkm_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd); + if (bar->bar[0].vm) { + nvkm_gpuobj_ref(NULL, &bar->bar[0].vm->pgt[0].obj[0]); + nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); } - nvkm_gpuobj_ref(NULL, &priv->bar[0].pgd); - nvkm_gpuobj_ref(NULL, &priv->bar[0].mem); + nvkm_gpuobj_ref(NULL, &bar->bar[0].pgd); + nvkm_gpuobj_ref(NULL, &bar->bar[0].mem); - nvkm_bar_destroy(&priv->base); + nvkm_bar_destroy(&bar->base); } int gf100_bar_init(struct nvkm_object *object) { - struct gf100_bar_priv *priv = (void *)object; + struct gf100_bar *bar = (void *)object; int ret; - ret = nvkm_bar_init(&priv->base); + ret = nvkm_bar_init(&bar->base); if (ret) return ret; - nv_mask(priv, 0x000200, 0x00000100, 0x00000000); - nv_mask(priv, 0x000200, 0x00000100, 0x00000100); + nv_mask(bar, 0x000200, 0x00000100, 0x00000000); + nv_mask(bar, 0x000200, 0x00000100, 0x00000100); - nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12); - if (priv->bar[0].mem) - nv_wr32(priv, 0x001714, - 0xc0000000 | priv->bar[0].mem->addr >> 12); + nv_wr32(bar, 0x001704, 0x80000000 | bar->bar[1].mem->addr >> 12); + if (bar->bar[0].mem) + nv_wr32(bar, 0x001714, + 0xc0000000 | bar->bar[0].mem->addr >> 12); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 36c5c083c1e93..07f6b2a7d3c4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -28,7 +28,7 @@ #include #include -struct nv50_bar_priv { +struct nv50_bar { struct nvkm_bar base; spinlock_t lock; struct nvkm_gpuobj *mem; @@ -41,13 +41,13 @@ struct nv50_bar_priv { }; static int -nv50_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, +nv50_bar_kmap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, struct nvkm_vma *vma) { - struct nv50_bar_priv *priv = (void *)bar; + struct nv50_bar *bar = container_of(obj, typeof(*bar), base); int ret; - ret = nvkm_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma); + ret = nvkm_vm_get(bar->bar3_vm, mem->size << 12, 12, flags, vma); if (ret) return ret; @@ -56,13 +56,13 @@ nv50_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, } static int -nv50_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags, +nv50_bar_umap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, struct nvkm_vma *vma) { - struct nv50_bar_priv *priv = (void *)bar; + struct nv50_bar *bar = container_of(obj, typeof(*bar), base); int ret; - ret = nvkm_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma); + ret = nvkm_vm_get(bar->bar1_vm, mem->size << 12, 12, flags, vma); if (ret) return ret; @@ -78,27 +78,27 @@ nv50_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) } static void -nv50_bar_flush(struct nvkm_bar *bar) +nv50_bar_flush(struct nvkm_bar *obj) { - struct nv50_bar_priv *priv = (void *)bar; + struct nv50_bar *bar = container_of(obj, typeof(*bar), base); unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - nv_wr32(priv, 0x00330c, 0x00000001); - if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000)) - nv_warn(priv, "flush timeout\n"); - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&bar->lock, flags); + nv_wr32(bar, 0x00330c, 0x00000001); + if (!nv_wait(bar, 0x00330c, 0x00000002, 0x00000000)) + nv_warn(bar, "flush timeout\n"); + spin_unlock_irqrestore(&bar->lock, flags); } void -g84_bar_flush(struct nvkm_bar *bar) +g84_bar_flush(struct nvkm_bar *obj) { - struct nv50_bar_priv *priv = (void *)bar; + struct nv50_bar *bar = container_of(obj, typeof(*bar), base); unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&bar->lock, flags); nv_wr32(bar, 0x070000, 0x00000001); - if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000)) - nv_warn(priv, "flush timeout\n"); - spin_unlock_irqrestore(&priv->lock, flags); + if (!nv_wait(bar, 0x070000, 0x00000002, 0x00000000)) + nv_warn(bar, "flush timeout\n"); + spin_unlock_irqrestore(&bar->lock, flags); } static int @@ -109,28 +109,28 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_device *device = nv_device(parent); struct nvkm_object *heap; struct nvkm_vm *vm; - struct nv50_bar_priv *priv; + struct nv50_bar *bar; u64 start, limit; int ret; - ret = nvkm_bar_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_bar_create(parent, engine, oclass, &bar); + *pobject = nv_object(bar); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0, - NVOBJ_FLAG_HEAP, &priv->mem); - heap = nv_object(priv->mem); + ret = nvkm_gpuobj_new(nv_object(bar), NULL, 0x20000, 0, + NVOBJ_FLAG_HEAP, &bar->mem); + heap = nv_object(bar->mem); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, + ret = nvkm_gpuobj_new(nv_object(bar), heap, (device->chipset == 0x50) ? 0x1400 : 0x0200, - 0, 0, &priv->pad); + 0, 0, &bar->pad); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, 0x4000, 0, 0, &priv->pgd); + ret = nvkm_gpuobj_new(nv_object(bar), heap, 0x4000, 0, 0, &bar->pgd); if (ret) return ret; @@ -144,29 +144,29 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); - ret = nvkm_gpuobj_new(nv_object(priv), heap, + ret = nvkm_gpuobj_new(nv_object(bar), heap, ((limit-- - start) >> 12) * 8, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); vm->pgt[0].refcount[0] = 1; if (ret) return ret; - ret = nvkm_vm_ref(vm, &priv->bar3_vm, priv->pgd); + ret = nvkm_vm_ref(vm, &bar->bar3_vm, bar->pgd); nvkm_vm_ref(NULL, &vm, NULL); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3); + ret = nvkm_gpuobj_new(nv_object(bar), heap, 24, 16, 0, &bar->bar3); if (ret) return ret; - nv_wo32(priv->bar3, 0x00, 0x7fc00000); - nv_wo32(priv->bar3, 0x04, lower_32_bits(limit)); - nv_wo32(priv->bar3, 0x08, lower_32_bits(start)); - nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 | + nv_wo32(bar->bar3, 0x00, 0x7fc00000); + nv_wo32(bar->bar3, 0x04, lower_32_bits(limit)); + nv_wo32(bar->bar3, 0x08, lower_32_bits(start)); + nv_wo32(bar->bar3, 0x0c, upper_32_bits(limit) << 24 | upper_32_bits(start)); - nv_wo32(priv->bar3, 0x10, 0x00000000); - nv_wo32(priv->bar3, 0x14, 0x00000000); + nv_wo32(bar->bar3, 0x10, 0x00000000); + nv_wo32(bar->bar3, 0x14, 0x00000000); /* BAR1 */ start = 0x0000000000ULL; @@ -178,84 +178,84 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); - ret = nvkm_vm_ref(vm, &priv->bar1_vm, priv->pgd); + ret = nvkm_vm_ref(vm, &bar->bar1_vm, bar->pgd); nvkm_vm_ref(NULL, &vm, NULL); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1); + ret = nvkm_gpuobj_new(nv_object(bar), heap, 24, 16, 0, &bar->bar1); if (ret) return ret; - nv_wo32(priv->bar1, 0x00, 0x7fc00000); - nv_wo32(priv->bar1, 0x04, lower_32_bits(limit)); - nv_wo32(priv->bar1, 0x08, lower_32_bits(start)); - nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 | + nv_wo32(bar->bar1, 0x00, 0x7fc00000); + nv_wo32(bar->bar1, 0x04, lower_32_bits(limit)); + nv_wo32(bar->bar1, 0x08, lower_32_bits(start)); + nv_wo32(bar->bar1, 0x0c, upper_32_bits(limit) << 24 | upper_32_bits(start)); - nv_wo32(priv->bar1, 0x10, 0x00000000); - nv_wo32(priv->bar1, 0x14, 0x00000000); + nv_wo32(bar->bar1, 0x10, 0x00000000); + nv_wo32(bar->bar1, 0x14, 0x00000000); - priv->base.alloc = nvkm_bar_alloc; - priv->base.kmap = nv50_bar_kmap; - priv->base.umap = nv50_bar_umap; - priv->base.unmap = nv50_bar_unmap; + bar->base.alloc = nvkm_bar_alloc; + bar->base.kmap = nv50_bar_kmap; + bar->base.umap = nv50_bar_umap; + bar->base.unmap = nv50_bar_unmap; if (device->chipset == 0x50) - priv->base.flush = nv50_bar_flush; + bar->base.flush = nv50_bar_flush; else - priv->base.flush = g84_bar_flush; - spin_lock_init(&priv->lock); + bar->base.flush = g84_bar_flush; + spin_lock_init(&bar->lock); return 0; } static void nv50_bar_dtor(struct nvkm_object *object) { - struct nv50_bar_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->bar1); - nvkm_vm_ref(NULL, &priv->bar1_vm, priv->pgd); - nvkm_gpuobj_ref(NULL, &priv->bar3); - if (priv->bar3_vm) { - nvkm_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]); - nvkm_vm_ref(NULL, &priv->bar3_vm, priv->pgd); + struct nv50_bar *bar = (void *)object; + nvkm_gpuobj_ref(NULL, &bar->bar1); + nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd); + nvkm_gpuobj_ref(NULL, &bar->bar3); + if (bar->bar3_vm) { + nvkm_gpuobj_ref(NULL, &bar->bar3_vm->pgt[0].obj[0]); + nvkm_vm_ref(NULL, &bar->bar3_vm, bar->pgd); } - nvkm_gpuobj_ref(NULL, &priv->pgd); - nvkm_gpuobj_ref(NULL, &priv->pad); - nvkm_gpuobj_ref(NULL, &priv->mem); - nvkm_bar_destroy(&priv->base); + nvkm_gpuobj_ref(NULL, &bar->pgd); + nvkm_gpuobj_ref(NULL, &bar->pad); + nvkm_gpuobj_ref(NULL, &bar->mem); + nvkm_bar_destroy(&bar->base); } static int nv50_bar_init(struct nvkm_object *object) { - struct nv50_bar_priv *priv = (void *)object; + struct nv50_bar *bar = (void *)object; int ret, i; - ret = nvkm_bar_init(&priv->base); + ret = nvkm_bar_init(&bar->base); if (ret) return ret; - nv_mask(priv, 0x000200, 0x00000100, 0x00000000); - nv_mask(priv, 0x000200, 0x00000100, 0x00000100); - nv_wr32(priv, 0x100c80, 0x00060001); - if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) { - nv_error(priv, "vm flush timeout\n"); + nv_mask(bar, 0x000200, 0x00000100, 0x00000000); + nv_mask(bar, 0x000200, 0x00000100, 0x00000100); + nv_wr32(bar, 0x100c80, 0x00060001); + if (!nv_wait(bar, 0x100c80, 0x00000001, 0x00000000)) { + nv_error(bar, "vm flush timeout\n"); return -EBUSY; } - nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12); - nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12); - nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4); - nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4); + nv_wr32(bar, 0x001704, 0x00000000 | bar->mem->addr >> 12); + nv_wr32(bar, 0x001704, 0x40000000 | bar->mem->addr >> 12); + nv_wr32(bar, 0x001708, 0x80000000 | bar->bar1->node->offset >> 4); + nv_wr32(bar, 0x00170c, 0x80000000 | bar->bar3->node->offset >> 4); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x001900 + (i * 4), 0x00000000); + nv_wr32(bar, 0x001900 + (i * 4), 0x00000000); return 0; } static int nv50_bar_fini(struct nvkm_object *object, bool suspend) { - struct nv50_bar_priv *priv = (void *)object; - return nvkm_bar_fini(&priv->base, suspend); + struct nv50_bar *bar = (void *)object; + return nvkm_bar_fini(&bar->base, suspend); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h index aa85f61b48c25..e6e4dfc97dcc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h @@ -5,9 +5,9 @@ #define nvkm_bar_create(p,e,o,d) \ nvkm_bar_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_bar_init(p) \ - nvkm_subdev_init(&(p)->base) + nvkm_subdev_init(&(p)->subdev) #define nvkm_bar_fini(p,s) \ - nvkm_subdev_fini(&(p)->base, (s)) + nvkm_subdev_fini(&(p)->subdev, (s)) int nvkm_bar_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); -- GitLab From a00014e3963642e7cf7206a9fa814b547d642a72 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5323/7006] drm/nouveau/bios: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h index cef287e0bbf22..0b102c8f69c8f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h @@ -3,7 +3,7 @@ #include struct nvkm_bios { - struct nvkm_subdev base; + struct nvkm_subdev subdev; u32 size; u8 *data; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index 8db204f92ed30..0cd9ab4ed8eec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -171,21 +171,21 @@ nvkm_bios_dtor(struct nvkm_object *object) { struct nvkm_bios *bios = (void *)object; kfree(bios->data); - nvkm_subdev_destroy(&bios->base); + nvkm_subdev_destroy(&bios->subdev); } static int nvkm_bios_init(struct nvkm_object *object) { struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_init(&bios->base); + return nvkm_subdev_init(&bios->subdev); } static int nvkm_bios_fini(struct nvkm_object *object, bool suspend) { struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_fini(&bios->base, suspend); + return nvkm_subdev_fini(&bios->subdev, suspend); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index 6192a9e27bb70..c64a5484c9c81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -206,7 +206,7 @@ nvbios_shadow(struct nvkm_bios *bios) { shadow_class, 1, &nvbios_pcirom }, { shadow_class, 1, &nvbios_platform }, { shadow_class } - }, *mthd = mthds, *best = NULL; + }, *mthd, *best = NULL; const char *optarg; char *source; int optlen; -- GitLab From 01d6b95605ad5c5be9ce0c7bf37b1a6d51cbb9e4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5324/7006] drm/nouveau/bus: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/bus.h | 8 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c | 17 ++++---- .../gpu/drm/nouveau/nvkm/subdev/bus/gf100.c | 26 +++++------ .../gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c | 26 +++++------ .../gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h | 4 +- .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.c | 34 +++++++-------- .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.h | 4 -- .../gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 32 +++++++------- .../gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 43 +++++++++---------- 9 files changed, 94 insertions(+), 100 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h index fba83c04849ea..ce7663c60015c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h @@ -8,7 +8,7 @@ struct nvkm_bus_intr { }; struct nvkm_bus { - struct nvkm_subdev base; + struct nvkm_subdev subdev; int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32); u32 hwsq_size; }; @@ -23,11 +23,11 @@ nvkm_bus(void *obj) nvkm_subdev_create_((p), (e), (o), 0, "PBUS", "master", \ sizeof(**d), (void **)d) #define nvkm_bus_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) + nvkm_subdev_destroy(&(p)->subdev) #define nvkm_bus_init(p) \ - nvkm_subdev_init(&(p)->base) + nvkm_subdev_init(&(p)->subdev) #define nvkm_bus_fini(p, s) \ - nvkm_subdev_fini(&(p)->base, (s)) + nvkm_subdev_fini(&(p)->subdev, (s)) #define _nvkm_bus_dtor _nvkm_subdev_dtor #define _nvkm_bus_init _nvkm_subdev_init diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c index cbe699e825932..ae924dda7b3d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c @@ -27,20 +27,19 @@ #include static int -g94_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size) +g94_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) { - struct nv50_bus_priv *priv = (void *)pbus; int i; - nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); - nv_wr32(pbus, 0x001304, 0x00000000); - nv_wr32(pbus, 0x001318, 0x00000000); + nv_mask(bus, 0x001098, 0x00000008, 0x00000000); + nv_wr32(bus, 0x001304, 0x00000000); + nv_wr32(bus, 0x001318, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x080000 + (i * 4), data[i]); - nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); - nv_wr32(pbus, 0x00130c, 0x00000001); + nv_wr32(bus, 0x080000 + (i * 4), data[i]); + nv_mask(bus, 0x001098, 0x00000018, 0x00000018); + nv_wr32(bus, 0x00130c, 0x00000001); - return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; + return nv_wait(bus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c index ebc63ba968d42..d46ecd8e754fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c @@ -27,43 +27,43 @@ static void gf100_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); + struct nvkm_bus *bus = nvkm_bus(subdev); + u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); if (stat & 0x0000000e) { - u32 addr = nv_rd32(pbus, 0x009084); - u32 data = nv_rd32(pbus, 0x009088); + u32 addr = nv_rd32(bus, 0x009084); + u32 data = nv_rd32(bus, 0x009088); - nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", + nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", (addr & 0x00000002) ? "write" : "read", data, (addr & 0x00fffffc), (stat & 0x00000002) ? "!ENGINE " : "", (stat & 0x00000004) ? "IBUS " : "", (stat & 0x00000008) ? "TIMEOUT " : ""); - nv_wr32(pbus, 0x009084, 0x00000000); - nv_wr32(pbus, 0x001100, (stat & 0x0000000e)); + nv_wr32(bus, 0x009084, 0x00000000); + nv_wr32(bus, 0x001100, (stat & 0x0000000e)); stat &= ~0x0000000e; } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0x00000000); + nv_error(bus, "unknown intr 0x%08x\n", stat); + nv_mask(bus, 0x001140, stat, 0x00000000); } } static int gf100_bus_init(struct nvkm_object *object) { - struct nv04_bus_priv *priv = (void *)object; + struct nvkm_bus *bus = (void *)object; int ret; - ret = nvkm_bus_init(&priv->base); + ret = nvkm_bus_init(bus); if (ret) return ret; - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x0000000e); + nv_wr32(bus, 0x001100, 0xffffffff); + nv_wr32(bus, 0x001140, 0x0000000e); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c index 7622b41619a07..90549602b6576 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c @@ -24,7 +24,7 @@ #include struct nvkm_hwsq { - struct nvkm_bus *pbus; + struct nvkm_bus *bus; u32 addr; u32 data; struct { @@ -41,13 +41,13 @@ hwsq_cmd(struct nvkm_hwsq *hwsq, int size, u8 data[]) } int -nvkm_hwsq_init(struct nvkm_bus *pbus, struct nvkm_hwsq **phwsq) +nvkm_hwsq_init(struct nvkm_bus *bus, struct nvkm_hwsq **phwsq) { struct nvkm_hwsq *hwsq; hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL); if (hwsq) { - hwsq->pbus = pbus; + hwsq->bus = bus; hwsq->addr = ~0; hwsq->data = ~0; memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data)); @@ -63,21 +63,21 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) struct nvkm_hwsq *hwsq = *phwsq; int ret = 0, i; if (hwsq) { - struct nvkm_bus *pbus = hwsq->pbus; + struct nvkm_bus *bus = hwsq->bus; hwsq->c.size = (hwsq->c.size + 4) / 4; - if (hwsq->c.size <= pbus->hwsq_size) { + if (hwsq->c.size <= bus->hwsq_size) { if (exec) - ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data, + ret = bus->hwsq_exec(bus, (u32 *)hwsq->c.data, hwsq->c.size); if (ret) - nv_error(pbus, "hwsq exec failed: %d\n", ret); + nv_error(bus, "hwsq exec failed: %d\n", ret); } else { - nv_error(pbus, "hwsq ucode too large\n"); + nv_error(bus, "hwsq ucode too large\n"); ret = -ENOSPC; } for (i = 0; ret && i < hwsq->c.size; i++) - nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]); + nv_error(bus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]); *phwsq = NULL; kfree(hwsq); @@ -88,7 +88,7 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) void nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) { - nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data); + nv_debug(hwsq->bus, "R[%06x] = 0x%08x\n", addr, data); if (hwsq->data != data) { if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) { @@ -113,7 +113,7 @@ nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) void nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) { - nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data); + nv_debug(hwsq->bus, " FLAG[%02x] = %d\n", flag, data); flag += 0x80; if (data >= 0) flag += 0x20; @@ -125,7 +125,7 @@ nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) void nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data) { - nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data); + nv_debug(hwsq->bus, " WAIT[%02x] = %d\n", flag, data); hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data }); } @@ -138,6 +138,6 @@ nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec) shift++; } - nv_debug(hwsq->pbus, " DELAY = %d ns\n", nsec); + nv_debug(hwsq->bus, " DELAY = %d ns\n", nsec); hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec }); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h index ebf709c27e3a0..4ce54d4f2e731 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h @@ -59,10 +59,10 @@ hwsq_reg(u32 addr) static inline int hwsq_init(struct hwsq *ram, struct nvkm_subdev *subdev) { - struct nvkm_bus *pbus = nvkm_bus(subdev); + struct nvkm_bus *bus = nvkm_bus(subdev); int ret; - ret = nvkm_hwsq_init(pbus, &ram->hwsq); + ret = nvkm_hwsq_init(bus, &ram->hwsq); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c index 19c8e50eeff7f..2066d38d12ded 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c @@ -27,13 +27,13 @@ static void nv04_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); + struct nvkm_bus *bus = nvkm_bus(subdev); + u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); if (stat & 0x00000001) { - nv_error(pbus, "BUS ERROR\n"); + nv_error(bus, "BUS ERROR\n"); stat &= ~0x00000001; - nv_wr32(pbus, 0x001100, 0x00000001); + nv_wr32(bus, 0x001100, 0x00000001); } if (stat & 0x00000110) { @@ -41,24 +41,24 @@ nv04_bus_intr(struct nvkm_subdev *subdev) if (subdev && subdev->intr) subdev->intr(subdev); stat &= ~0x00000110; - nv_wr32(pbus, 0x001100, 0x00000110); + nv_wr32(bus, 0x001100, 0x00000110); } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0x00000000); + nv_error(bus, "unknown intr 0x%08x\n", stat); + nv_mask(bus, 0x001140, stat, 0x00000000); } } static int nv04_bus_init(struct nvkm_object *object) { - struct nv04_bus_priv *priv = (void *)object; + struct nvkm_bus *bus = (void *)object; - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00000111); + nv_wr32(bus, 0x001100, 0xffffffff); + nv_wr32(bus, 0x001140, 0x00000111); - return nvkm_bus_init(&priv->base); + return nvkm_bus_init(bus); } int @@ -67,17 +67,17 @@ nv04_bus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv04_bus_impl *impl = (void *)oclass; - struct nv04_bus_priv *priv; + struct nvkm_bus *bus; int ret; - ret = nvkm_bus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_bus_create(parent, engine, oclass, &bus); + *pobject = nv_object(bus); if (ret) return ret; - nv_subdev(priv)->intr = impl->intr; - priv->base.hwsq_exec = impl->hwsq_exec; - priv->base.hwsq_size = impl->hwsq_size; + nv_subdev(bus)->intr = impl->intr; + bus->hwsq_exec = impl->hwsq_exec; + bus->hwsq_size = impl->hwsq_size; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h index 3ddc8f91b1e37..e8674f2370c8c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h @@ -2,10 +2,6 @@ #define __NVKM_BUS_NV04_H__ #include -struct nv04_bus_priv { - struct nvkm_bus base; -}; - int nv04_bus_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c index c5739bce80524..7565d2f047e7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c @@ -27,54 +27,54 @@ static void nv31_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); - u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144); + struct nvkm_bus *bus = nvkm_bus(subdev); + u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); + u32 gpio = nv_rd32(bus, 0x001104) & nv_rd32(bus, 0x001144); if (gpio) { - subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_GPIO); + subdev = nvkm_subdev(bus, NVDEV_SUBDEV_GPIO); if (subdev && subdev->intr) subdev->intr(subdev); } if (stat & 0x00000008) { /* NV41- */ - u32 addr = nv_rd32(pbus, 0x009084); - u32 data = nv_rd32(pbus, 0x009088); + u32 addr = nv_rd32(bus, 0x009084); + u32 data = nv_rd32(bus, 0x009088); - nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", + nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", (addr & 0x00000002) ? "write" : "read", data, (addr & 0x00fffffc)); stat &= ~0x00000008; - nv_wr32(pbus, 0x001100, 0x00000008); + nv_wr32(bus, 0x001100, 0x00000008); } if (stat & 0x00070000) { - subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM); + subdev = nvkm_subdev(bus, NVDEV_SUBDEV_THERM); if (subdev && subdev->intr) subdev->intr(subdev); stat &= ~0x00070000; - nv_wr32(pbus, 0x001100, 0x00070000); + nv_wr32(bus, 0x001100, 0x00070000); } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0x00000000); + nv_error(bus, "unknown intr 0x%08x\n", stat); + nv_mask(bus, 0x001140, stat, 0x00000000); } } static int nv31_bus_init(struct nvkm_object *object) { - struct nv04_bus_priv *priv = (void *)object; + struct nvkm_bus *bus = (void *)object; int ret; - ret = nvkm_bus_init(&priv->base); + ret = nvkm_bus_init(bus); if (ret) return ret; - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00070008); + nv_wr32(bus, 0x001100, 0xffffffff); + nv_wr32(bus, 0x001140, 0x00070008); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index 1987863d71eed..f6a55b831ea2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -27,65 +27,64 @@ #include static int -nv50_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size) +nv50_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) { - struct nv50_bus_priv *priv = (void *)pbus; int i; - nv_mask(pbus, 0x001098, 0x00000008, 0x00000000); - nv_wr32(pbus, 0x001304, 0x00000000); + nv_mask(bus, 0x001098, 0x00000008, 0x00000000); + nv_wr32(bus, 0x001304, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x001400 + (i * 4), data[i]); - nv_mask(pbus, 0x001098, 0x00000018, 0x00000018); - nv_wr32(pbus, 0x00130c, 0x00000003); + nv_wr32(bus, 0x001400 + (i * 4), data[i]); + nv_mask(bus, 0x001098, 0x00000018, 0x00000018); + nv_wr32(bus, 0x00130c, 0x00000003); - return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; + return nv_wait(bus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; } void nv50_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *pbus = nvkm_bus(subdev); - u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140); + struct nvkm_bus *bus = nvkm_bus(subdev); + u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); if (stat & 0x00000008) { - u32 addr = nv_rd32(pbus, 0x009084); - u32 data = nv_rd32(pbus, 0x009088); + u32 addr = nv_rd32(bus, 0x009084); + u32 data = nv_rd32(bus, 0x009088); - nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", + nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", (addr & 0x00000002) ? "write" : "read", data, (addr & 0x00fffffc)); stat &= ~0x00000008; - nv_wr32(pbus, 0x001100, 0x00000008); + nv_wr32(bus, 0x001100, 0x00000008); } if (stat & 0x00010000) { - subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM); + subdev = nvkm_subdev(bus, NVDEV_SUBDEV_THERM); if (subdev && subdev->intr) subdev->intr(subdev); stat &= ~0x00010000; - nv_wr32(pbus, 0x001100, 0x00010000); + nv_wr32(bus, 0x001100, 0x00010000); } if (stat) { - nv_error(pbus, "unknown intr 0x%08x\n", stat); - nv_mask(pbus, 0x001140, stat, 0); + nv_error(bus, "unknown intr 0x%08x\n", stat); + nv_mask(bus, 0x001140, stat, 0); } } int nv50_bus_init(struct nvkm_object *object) { - struct nv04_bus_priv *priv = (void *)object; + struct nvkm_bus *bus = (void *)object; int ret; - ret = nvkm_bus_init(&priv->base); + ret = nvkm_bus_init(bus); if (ret) return ret; - nv_wr32(priv, 0x001100, 0xffffffff); - nv_wr32(priv, 0x001140, 0x00010008); + nv_wr32(bus, 0x001100, 0xffffffff); + nv_wr32(bus, 0x001140, 0x00010008); return 0; } -- GitLab From 3eca809b3c05ea6918c1d13da478abdae5e712ba Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5325/7006] drm/nouveau/clk: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/clk.h | 14 +- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 235 ++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 242 ++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 252 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 234 ++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.h | 4 +- .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 193 +++++++------- .../gpu/drm/nouveau/nvkm/subdev/clk/nv04.c | 14 +- .../gpu/drm/nouveau/nvkm/subdev/clk/nv40.c | 116 ++++---- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 227 ++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.h | 2 +- 12 files changed, 765 insertions(+), 776 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h index f5d303850d8ce..5c982401e142a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h @@ -71,7 +71,7 @@ struct nvkm_domain { }; struct nvkm_clk { - struct nvkm_subdev base; + struct nvkm_subdev subdev; struct nvkm_domain *domains; struct nvkm_pstate bstate; @@ -117,16 +117,16 @@ nvkm_clk(void *obj) nvkm_clk_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \ (void **)d) #define nvkm_clk_destroy(p) ({ \ - struct nvkm_clk *clk = (p); \ - _nvkm_clk_dtor(nv_object(clk)); \ + struct nvkm_clk *_clk = (p); \ + _nvkm_clk_dtor(nv_object(_clk)); \ }) #define nvkm_clk_init(p) ({ \ - struct nvkm_clk *clk = (p); \ - _nvkm_clk_init(nv_object(clk)); \ + struct nvkm_clk *_clk = (p); \ + _nvkm_clk_init(nv_object(_clk)); \ }) #define nvkm_clk_fini(p,s) ({ \ - struct nvkm_clk *clk = (p); \ - _nvkm_clk_fini(nv_object(clk), (s)); \ + struct nvkm_clk *_clk = (p); \ + _nvkm_clk_fini(nv_object(_clk), (s)); \ }) int nvkm_clk_create_(struct nvkm_object *, struct nvkm_object *, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index cba018d02b4b0..572fbf1bc72f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -121,7 +121,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) nv_error(clk, "failed to lower fan speed: %d\n", ret); } - return 0; + return ret; } static void @@ -474,7 +474,7 @@ _nvkm_clk_fini(struct nvkm_object *object, bool suspend) { struct nvkm_clk *clk = (void *)object; nvkm_notify_put(&clk->pwrsrc_ntfy); - return nvkm_subdev_fini(&clk->base, suspend); + return nvkm_subdev_fini(&clk->subdev, suspend); } int @@ -484,7 +484,7 @@ _nvkm_clk_init(struct nvkm_object *object) struct nvkm_domain *clock = clk->domains; int ret; - ret = nvkm_subdev_init(&clk->base); + ret = nvkm_subdev_init(&clk->subdev); if (ret) return ret; @@ -524,7 +524,7 @@ _nvkm_clk_dtor(struct nvkm_object *object) nvkm_pstate_del(pstate); } - nvkm_subdev_destroy(&clk->base); + nvkm_subdev_destroy(&clk->subdev); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index e8125b5199a47..99cfa09b21598 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -37,29 +37,27 @@ struct gf100_clk_info { u32 coef; }; -struct gf100_clk_priv { +struct gf100_clk { struct nvkm_clk base; struct gf100_clk_info eng[16]; }; -static u32 read_div(struct gf100_clk_priv *, int, u32, u32); +static u32 read_div(struct gf100_clk *, int, u32, u32); static u32 -read_vco(struct gf100_clk_priv *priv, u32 dsrc) +read_vco(struct gf100_clk *clk, u32 dsrc) { - struct nvkm_clk *clk = &priv->base; - u32 ssrc = nv_rd32(priv, dsrc); + u32 ssrc = nv_rd32(clk, dsrc); if (!(ssrc & 0x00000100)) - return clk->read(clk, nv_clk_src_sppll0); - return clk->read(clk, nv_clk_src_sppll1); + return clk->base.read(&clk->base, nv_clk_src_sppll0); + return clk->base.read(&clk->base, nv_clk_src_sppll1); } static u32 -read_pll(struct gf100_clk_priv *priv, u32 pll) +read_pll(struct gf100_clk *clk, u32 pll) { - struct nvkm_clk *clk = &priv->base; - u32 ctrl = nv_rd32(priv, pll + 0x00); - u32 coef = nv_rd32(priv, pll + 0x04); + u32 ctrl = nv_rd32(clk, pll + 0x00); + u32 coef = nv_rd32(clk, pll + 0x04); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -71,20 +69,20 @@ read_pll(struct gf100_clk_priv *priv, u32 pll) switch (pll) { case 0x00e800: case 0x00e820: - sclk = nv_device(priv)->crystal; + sclk = nv_device(clk)->crystal; P = 1; break; case 0x132000: - sclk = clk->read(clk, nv_clk_src_mpllsrc); + sclk = clk->base.read(&clk->base, nv_clk_src_mpllsrc); break; case 0x132020: - sclk = clk->read(clk, nv_clk_src_mpllsrcref); + sclk = clk->base.read(&clk->base, nv_clk_src_mpllsrcref); break; case 0x137000: case 0x137020: case 0x137040: case 0x1370e0: - sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + sclk = read_div(clk, (pll & 0xff) / 0x20, 0x137120, 0x137140); break; default: return 0; @@ -94,46 +92,46 @@ read_pll(struct gf100_clk_priv *priv, u32 pll) } static u32 -read_div(struct gf100_clk_priv *priv, int doff, u32 dsrc, u32 dctl) +read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); - u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + u32 ssrc = nv_rd32(clk, dsrc + (doff * 4)); + u32 sctl = nv_rd32(clk, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; return 108000; case 2: return 100000; case 3: if (sctl & 0x80000000) { - u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sclk = read_vco(clk, dsrc + (doff * 4)); u32 sdiv = (sctl & 0x0000003f) + 2; return (sclk * 2) / sdiv; } - return read_vco(priv, dsrc + (doff * 4)); + return read_vco(clk, dsrc + (doff * 4)); default: return 0; } } static u32 -read_clk(struct gf100_clk_priv *priv, int clk) +read_clk(struct gf100_clk *clk, int idx) { - u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); - u32 ssel = nv_rd32(priv, 0x137100); + u32 sctl = nv_rd32(clk, 0x137250 + (idx * 4)); + u32 ssel = nv_rd32(clk, 0x137100); u32 sclk, sdiv; - if (ssel & (1 << clk)) { - if (clk < 7) - sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + if (ssel & (1 << idx)) { + if (idx < 7) + sclk = read_pll(clk, 0x137000 + (idx * 0x20)); else - sclk = read_pll(priv, 0x1370e0); + sclk = read_pll(clk, 0x1370e0); sdiv = ((sctl & 0x00003f00) >> 8) + 2; } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); sdiv = ((sctl & 0x0000003f) >> 0) + 2; } @@ -144,10 +142,10 @@ read_clk(struct gf100_clk_priv *priv, int clk) } static int -gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { + struct gf100_clk *clk = container_of(obj, typeof(*clk), base); struct nvkm_device *device = nv_device(clk); - struct gf100_clk_priv *priv = (void *)clk; switch (src) { case nv_clk_src_crystal: @@ -155,39 +153,39 @@ gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) case nv_clk_src_href: return 100000; case nv_clk_src_sppll0: - return read_pll(priv, 0x00e800); + return read_pll(clk, 0x00e800); case nv_clk_src_sppll1: - return read_pll(priv, 0x00e820); + return read_pll(clk, 0x00e820); case nv_clk_src_mpllsrcref: - return read_div(priv, 0, 0x137320, 0x137330); + return read_div(clk, 0, 0x137320, 0x137330); case nv_clk_src_mpllsrc: - return read_pll(priv, 0x132020); + return read_pll(clk, 0x132020); case nv_clk_src_mpll: - return read_pll(priv, 0x132000); + return read_pll(clk, 0x132000); case nv_clk_src_mdiv: - return read_div(priv, 0, 0x137300, 0x137310); + return read_div(clk, 0, 0x137300, 0x137310); case nv_clk_src_mem: - if (nv_rd32(priv, 0x1373f0) & 0x00000002) - return clk->read(clk, nv_clk_src_mpll); - return clk->read(clk, nv_clk_src_mdiv); + if (nv_rd32(clk, 0x1373f0) & 0x00000002) + return clk->base.read(&clk->base, nv_clk_src_mpll); + return clk->base.read(&clk->base, nv_clk_src_mdiv); case nv_clk_src_gpc: - return read_clk(priv, 0x00); + return read_clk(clk, 0x00); case nv_clk_src_rop: - return read_clk(priv, 0x01); + return read_clk(clk, 0x01); case nv_clk_src_hubk07: - return read_clk(priv, 0x02); + return read_clk(clk, 0x02); case nv_clk_src_hubk06: - return read_clk(priv, 0x07); + return read_clk(clk, 0x07); case nv_clk_src_hubk01: - return read_clk(priv, 0x08); + return read_clk(clk, 0x08); case nv_clk_src_copy: - return read_clk(priv, 0x09); + return read_clk(clk, 0x09); case nv_clk_src_daemon: - return read_clk(priv, 0x0c); + return read_clk(clk, 0x0c); case nv_clk_src_vdec: - return read_clk(priv, 0x0e); + return read_clk(clk, 0x0e); default: nv_error(clk, "invalid clock source %d\n", src); return -EINVAL; @@ -195,7 +193,7 @@ gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) } static u32 -calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +calc_div(struct gf100_clk *clk, int idx, u32 ref, u32 freq, u32 *ddiv) { u32 div = min((ref * 2) / freq, (u32)65); if (div < 2) @@ -206,7 +204,7 @@ calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) } static u32 -calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +calc_src(struct gf100_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv) { u32 sclk; @@ -228,28 +226,28 @@ calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) } /* otherwise, calculate the closest divider */ - sclk = read_vco(priv, 0x137160 + (clk * 4)); - if (clk < 7) - sclk = calc_div(priv, clk, sclk, freq, ddiv); + sclk = read_vco(clk, 0x137160 + (idx * 4)); + if (idx < 7) + sclk = calc_div(clk, idx, sclk, freq, ddiv); return sclk; } static u32 -calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef) +calc_pll(struct gf100_clk *clk, int idx, u32 freq, u32 *coef) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(clk); struct nvbios_pll limits; int N, M, P, ret; - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + ret = nvbios_pll_parse(bios, 0x137000 + (idx * 0x20), &limits); if (ret) return 0; - limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + limits.refclk = read_div(clk, idx, 0x137120, 0x137140); if (!limits.refclk) return 0; - ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + ret = gt215_pll_calc(nv_subdev(clk), &limits, freq, &N, NULL, &M, &P); if (ret <= 0) return 0; @@ -258,10 +256,9 @@ calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef) } static int -calc_clk(struct gf100_clk_priv *priv, - struct nvkm_cstate *cstate, int clk, int dom) +calc_clk(struct gf100_clk *clk, struct nvkm_cstate *cstate, int idx, int dom) { - struct gf100_clk_info *info = &priv->eng[clk]; + struct gf100_clk_info *info = &clk->eng[idx]; u32 freq = cstate->domain[dom]; u32 src0, div0, div1D, div1P = 0; u32 clk0, clk1 = 0; @@ -271,16 +268,16 @@ calc_clk(struct gf100_clk_priv *priv, return 0; /* first possible path, using only dividers */ - clk0 = calc_src(priv, clk, freq, &src0, &div0); - clk0 = calc_div(priv, clk, clk0, freq, &div1D); + clk0 = calc_src(clk, idx, freq, &src0, &div0); + clk0 = calc_div(clk, idx, clk0, freq, &div1D); /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x00004387 & (1 << clk))) { - if (clk <= 7) - clk1 = calc_pll(priv, clk, freq, &info->coef); + if (clk0 != freq && (0x00004387 & (1 << idx))) { + if (idx <= 7) + clk1 = calc_pll(clk, idx, freq, &info->coef); else clk1 = cstate->domain[nv_clk_src_hubk06]; - clk1 = calc_div(priv, clk, clk1, freq, &div1P); + clk1 = calc_div(clk, idx, clk1, freq, &div1P); } /* select the method which gets closest to target freq */ @@ -302,7 +299,7 @@ calc_clk(struct gf100_clk_priv *priv, info->mdiv |= 0x80000000; info->mdiv |= div1P << 8; } - info->ssel = (1 << clk); + info->ssel = (1 << idx); info->freq = clk1; } @@ -310,81 +307,81 @@ calc_clk(struct gf100_clk_priv *priv, } static int -gf100_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gf100_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct gf100_clk_priv *priv = (void *)clk; + struct gf100_clk *clk = container_of(obj, typeof(*clk), base); int ret; - if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || - (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || - (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || - (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || - (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || - (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) || - (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || - (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(clk, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(clk, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(clk, cstate, 0x09, nv_clk_src_copy)) || + (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec))) return ret; return 0; } static void -gf100_clk_prog_0(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_0(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; - if (clk < 7 && !info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv); - nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + struct gf100_clk_info *info = &clk->eng[idx]; + if (idx < 7 && !info->ssel) { + nv_mask(clk, 0x1371d0 + (idx * 0x04), 0x80003f3f, info->ddiv); + nv_wr32(clk, 0x137160 + (idx * 0x04), info->dsrc); } } static void -gf100_clk_prog_1(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_1(struct gf100_clk *clk, int idx) { - nv_mask(priv, 0x137100, (1 << clk), 0x00000000); - nv_wait(priv, 0x137100, (1 << clk), 0x00000000); + nv_mask(clk, 0x137100, (1 << idx), 0x00000000); + nv_wait(clk, 0x137100, (1 << idx), 0x00000000); } static void -gf100_clk_prog_2(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_2(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; - const u32 addr = 0x137000 + (clk * 0x20); - if (clk <= 7) { - nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + struct gf100_clk_info *info = &clk->eng[idx]; + const u32 addr = 0x137000 + (idx * 0x20); + if (idx <= 7) { + nv_mask(clk, addr + 0x00, 0x00000004, 0x00000000); + nv_mask(clk, addr + 0x00, 0x00000001, 0x00000000); if (info->coef) { - nv_wr32(priv, addr + 0x04, info->coef); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + nv_wr32(clk, addr + 0x04, info->coef); + nv_mask(clk, addr + 0x00, 0x00000001, 0x00000001); + nv_wait(clk, addr + 0x00, 0x00020000, 0x00020000); + nv_mask(clk, addr + 0x00, 0x00020004, 0x00000004); } } } static void -gf100_clk_prog_3(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_3(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; + struct gf100_clk_info *info = &clk->eng[idx]; if (info->ssel) { - nv_mask(priv, 0x137100, (1 << clk), info->ssel); - nv_wait(priv, 0x137100, (1 << clk), info->ssel); + nv_mask(clk, 0x137100, (1 << idx), info->ssel); + nv_wait(clk, 0x137100, (1 << idx), info->ssel); } } static void -gf100_clk_prog_4(struct gf100_clk_priv *priv, int clk) +gf100_clk_prog_4(struct gf100_clk *clk, int idx) { - struct gf100_clk_info *info = &priv->eng[clk]; - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv); + struct gf100_clk_info *info = &clk->eng[idx]; + nv_mask(clk, 0x137250 + (idx * 0x04), 0x00003f3f, info->mdiv); } static int -gf100_clk_prog(struct nvkm_clk *clk) +gf100_clk_prog(struct nvkm_clk *obj) { - struct gf100_clk_priv *priv = (void *)clk; + struct gf100_clk *clk = container_of(obj, typeof(*clk), base); struct { - void (*exec)(struct gf100_clk_priv *, int); + void (*exec)(struct gf100_clk *, int); } stage[] = { { gf100_clk_prog_0 }, /* div programming */ { gf100_clk_prog_1 }, /* select div mode */ @@ -395,10 +392,10 @@ gf100_clk_prog(struct nvkm_clk *clk) int i, j; for (i = 0; i < ARRAY_SIZE(stage); i++) { - for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { - if (!priv->eng[j].freq) + for (j = 0; j < ARRAY_SIZE(clk->eng); j++) { + if (!clk->eng[j].freq) continue; - stage[i].exec(priv, j); + stage[i].exec(clk, j); } } @@ -406,10 +403,10 @@ gf100_clk_prog(struct nvkm_clk *clk) } static void -gf100_clk_tidy(struct nvkm_clk *clk) +gf100_clk_tidy(struct nvkm_clk *obj) { - struct gf100_clk_priv *priv = (void *)clk; - memset(priv->eng, 0x00, sizeof(priv->eng)); + struct gf100_clk *clk = container_of(obj, typeof(*clk), base); + memset(clk->eng, 0x00, sizeof(clk->eng)); } static struct nvkm_domain @@ -433,19 +430,19 @@ gf100_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_clk_priv *priv; + struct gf100_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, gf100_domain, - NULL, 0, false, &priv); - *pobject = nv_object(priv); + NULL, 0, false, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->base.read = gf100_clk_read; - priv->base.calc = gf100_clk_calc; - priv->base.prog = gf100_clk_prog; - priv->base.tidy = gf100_clk_tidy; + clk->base.read = gf100_clk_read; + clk->base.calc = gf100_clk_calc; + clk->base.prog = gf100_clk_prog; + clk->base.tidy = gf100_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index e380d62df2320..7723e9379ab8d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -37,28 +37,28 @@ struct gk104_clk_info { u32 coef; }; -struct gk104_clk_priv { +struct gk104_clk { struct nvkm_clk base; struct gk104_clk_info eng[16]; }; -static u32 read_div(struct gk104_clk_priv *, int, u32, u32); -static u32 read_pll(struct gk104_clk_priv *, u32); +static u32 read_div(struct gk104_clk *, int, u32, u32); +static u32 read_pll(struct gk104_clk *, u32); static u32 -read_vco(struct gk104_clk_priv *priv, u32 dsrc) +read_vco(struct gk104_clk *clk, u32 dsrc) { - u32 ssrc = nv_rd32(priv, dsrc); + u32 ssrc = nv_rd32(clk, dsrc); if (!(ssrc & 0x00000100)) - return read_pll(priv, 0x00e800); - return read_pll(priv, 0x00e820); + return read_pll(clk, 0x00e800); + return read_pll(clk, 0x00e820); } static u32 -read_pll(struct gk104_clk_priv *priv, u32 pll) +read_pll(struct gk104_clk *clk, u32 pll) { - u32 ctrl = nv_rd32(priv, pll + 0x00); - u32 coef = nv_rd32(priv, pll + 0x04); + u32 ctrl = nv_rd32(clk, pll + 0x00); + u32 coef = nv_rd32(clk, pll + 0x04); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -71,22 +71,22 @@ read_pll(struct gk104_clk_priv *priv, u32 pll) switch (pll) { case 0x00e800: case 0x00e820: - sclk = nv_device(priv)->crystal; + sclk = nv_device(clk)->crystal; P = 1; break; case 0x132000: - sclk = read_pll(priv, 0x132020); + sclk = read_pll(clk, 0x132020); P = (coef & 0x10000000) ? 2 : 1; break; case 0x132020: - sclk = read_div(priv, 0, 0x137320, 0x137330); - fN = nv_rd32(priv, pll + 0x10) >> 16; + sclk = read_div(clk, 0, 0x137320, 0x137330); + fN = nv_rd32(clk, pll + 0x10) >> 16; break; case 0x137000: case 0x137020: case 0x137040: case 0x1370e0: - sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140); + sclk = read_div(clk, (pll & 0xff) / 0x20, 0x137120, 0x137140); break; default: return 0; @@ -100,70 +100,70 @@ read_pll(struct gk104_clk_priv *priv, u32 pll) } static u32 -read_div(struct gk104_clk_priv *priv, int doff, u32 dsrc, u32 dctl) +read_div(struct gk104_clk *clk, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(priv, dsrc + (doff * 4)); - u32 sctl = nv_rd32(priv, dctl + (doff * 4)); + u32 ssrc = nv_rd32(clk, dsrc + (doff * 4)); + u32 sctl = nv_rd32(clk, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; return 108000; case 2: return 100000; case 3: if (sctl & 0x80000000) { - u32 sclk = read_vco(priv, dsrc + (doff * 4)); + u32 sclk = read_vco(clk, dsrc + (doff * 4)); u32 sdiv = (sctl & 0x0000003f) + 2; return (sclk * 2) / sdiv; } - return read_vco(priv, dsrc + (doff * 4)); + return read_vco(clk, dsrc + (doff * 4)); default: return 0; } } static u32 -read_mem(struct gk104_clk_priv *priv) +read_mem(struct gk104_clk *clk) { - switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) { - case 1: return read_pll(priv, 0x132020); - case 2: return read_pll(priv, 0x132000); + switch (nv_rd32(clk, 0x1373f4) & 0x0000000f) { + case 1: return read_pll(clk, 0x132020); + case 2: return read_pll(clk, 0x132000); default: return 0; } } static u32 -read_clk(struct gk104_clk_priv *priv, int clk) +read_clk(struct gk104_clk *clk, int idx) { - u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4)); + u32 sctl = nv_rd32(clk, 0x137250 + (idx * 4)); u32 sclk, sdiv; - if (clk < 7) { - u32 ssel = nv_rd32(priv, 0x137100); - if (ssel & (1 << clk)) { - sclk = read_pll(priv, 0x137000 + (clk * 0x20)); + if (idx < 7) { + u32 ssel = nv_rd32(clk, 0x137100); + if (ssel & (1 << idx)) { + sclk = read_pll(clk, 0x137000 + (idx * 0x20)); sdiv = 1; } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); sdiv = 0; } } else { - u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04)); + u32 ssrc = nv_rd32(clk, 0x137160 + (idx * 0x04)); if ((ssrc & 0x00000003) == 0x00000003) { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); if (ssrc & 0x00000100) { if (ssrc & 0x40000000) - sclk = read_pll(priv, 0x1370e0); + sclk = read_pll(clk, 0x1370e0); sdiv = 1; } else { sdiv = 0; } } else { - sclk = read_div(priv, clk, 0x137160, 0x1371d0); + sclk = read_div(clk, idx, 0x137160, 0x1371d0); sdiv = 0; } } @@ -180,10 +180,10 @@ read_clk(struct gk104_clk_priv *priv, int clk) } static int -gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gk104_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { + struct gk104_clk *clk = container_of(obj, typeof(*clk), base); struct nvkm_device *device = nv_device(clk); - struct gk104_clk_priv *priv = (void *)clk; switch (src) { case nv_clk_src_crystal: @@ -191,21 +191,21 @@ gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) case nv_clk_src_href: return 100000; case nv_clk_src_mem: - return read_mem(priv); + return read_mem(clk); case nv_clk_src_gpc: - return read_clk(priv, 0x00); + return read_clk(clk, 0x00); case nv_clk_src_rop: - return read_clk(priv, 0x01); + return read_clk(clk, 0x01); case nv_clk_src_hubk07: - return read_clk(priv, 0x02); + return read_clk(clk, 0x02); case nv_clk_src_hubk06: - return read_clk(priv, 0x07); + return read_clk(clk, 0x07); case nv_clk_src_hubk01: - return read_clk(priv, 0x08); + return read_clk(clk, 0x08); case nv_clk_src_daemon: - return read_clk(priv, 0x0c); + return read_clk(clk, 0x0c); case nv_clk_src_vdec: - return read_clk(priv, 0x0e); + return read_clk(clk, 0x0e); default: nv_error(clk, "invalid clock source %d\n", src); return -EINVAL; @@ -213,7 +213,7 @@ gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) } static u32 -calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) +calc_div(struct gk104_clk *clk, int idx, u32 ref, u32 freq, u32 *ddiv) { u32 div = min((ref * 2) / freq, (u32)65); if (div < 2) @@ -224,7 +224,7 @@ calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv) } static u32 -calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) +calc_src(struct gk104_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv) { u32 sclk; @@ -246,28 +246,28 @@ calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv) } /* otherwise, calculate the closest divider */ - sclk = read_vco(priv, 0x137160 + (clk * 4)); - if (clk < 7) - sclk = calc_div(priv, clk, sclk, freq, ddiv); + sclk = read_vco(clk, 0x137160 + (idx * 4)); + if (idx < 7) + sclk = calc_div(clk, idx, sclk, freq, ddiv); return sclk; } static u32 -calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef) +calc_pll(struct gk104_clk *clk, int idx, u32 freq, u32 *coef) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(clk); struct nvbios_pll limits; int N, M, P, ret; - ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits); + ret = nvbios_pll_parse(bios, 0x137000 + (idx * 0x20), &limits); if (ret) return 0; - limits.refclk = read_div(priv, clk, 0x137120, 0x137140); + limits.refclk = read_div(clk, idx, 0x137120, 0x137140); if (!limits.refclk) return 0; - ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P); + ret = gt215_pll_calc(nv_subdev(clk), &limits, freq, &N, NULL, &M, &P); if (ret <= 0) return 0; @@ -276,10 +276,10 @@ calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef) } static int -calc_clk(struct gk104_clk_priv *priv, - struct nvkm_cstate *cstate, int clk, int dom) +calc_clk(struct gk104_clk *clk, + struct nvkm_cstate *cstate, int idx, int dom) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; u32 freq = cstate->domain[dom]; u32 src0, div0, div1D, div1P = 0; u32 clk0, clk1 = 0; @@ -289,16 +289,16 @@ calc_clk(struct gk104_clk_priv *priv, return 0; /* first possible path, using only dividers */ - clk0 = calc_src(priv, clk, freq, &src0, &div0); - clk0 = calc_div(priv, clk, clk0, freq, &div1D); + clk0 = calc_src(clk, idx, freq, &src0, &div0); + clk0 = calc_div(clk, idx, clk0, freq, &div1D); /* see if we can get any closer using PLLs */ - if (clk0 != freq && (0x0000ff87 & (1 << clk))) { - if (clk <= 7) - clk1 = calc_pll(priv, clk, freq, &info->coef); + if (clk0 != freq && (0x0000ff87 & (1 << idx))) { + if (idx <= 7) + clk1 = calc_pll(clk, idx, freq, &info->coef); else clk1 = cstate->domain[nv_clk_src_hubk06]; - clk1 = calc_div(priv, clk, clk1, freq, &div1P); + clk1 = calc_div(clk, idx, clk1, freq, &div1P); } /* select the method which gets closest to target freq */ @@ -319,7 +319,7 @@ calc_clk(struct gk104_clk_priv *priv, info->mdiv |= 0x80000000; info->mdiv |= div1P << 8; } - info->ssel = (1 << clk); + info->ssel = (1 << idx); info->dsrc = 0x40000100; info->freq = clk1; } @@ -328,98 +328,98 @@ calc_clk(struct gk104_clk_priv *priv, } static int -gk104_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gk104_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct gk104_clk_priv *priv = (void *)clk; + struct gk104_clk *clk = container_of(obj, typeof(*clk), base); int ret; - if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) || - (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) || - (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) || - (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) || - (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) || - (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) || - (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec))) + if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) || + (ret = calc_clk(clk, cstate, 0x01, nv_clk_src_rop)) || + (ret = calc_clk(clk, cstate, 0x02, nv_clk_src_hubk07)) || + (ret = calc_clk(clk, cstate, 0x07, nv_clk_src_hubk06)) || + (ret = calc_clk(clk, cstate, 0x08, nv_clk_src_hubk01)) || + (ret = calc_clk(clk, cstate, 0x0c, nv_clk_src_daemon)) || + (ret = calc_clk(clk, cstate, 0x0e, nv_clk_src_vdec))) return ret; return 0; } static void -gk104_clk_prog_0(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_0(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; if (!info->ssel) { - nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv); - nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc); + nv_mask(clk, 0x1371d0 + (idx * 0x04), 0x8000003f, info->ddiv); + nv_wr32(clk, 0x137160 + (idx * 0x04), info->dsrc); } } static void -gk104_clk_prog_1_0(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_1_0(struct gk104_clk *clk, int idx) { - nv_mask(priv, 0x137100, (1 << clk), 0x00000000); - nv_wait(priv, 0x137100, (1 << clk), 0x00000000); + nv_mask(clk, 0x137100, (1 << idx), 0x00000000); + nv_wait(clk, 0x137100, (1 << idx), 0x00000000); } static void -gk104_clk_prog_1_1(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_1_1(struct gk104_clk *clk, int idx) { - nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000); + nv_mask(clk, 0x137160 + (idx * 0x04), 0x00000100, 0x00000000); } static void -gk104_clk_prog_2(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_2(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; - const u32 addr = 0x137000 + (clk * 0x20); - nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000); + struct gk104_clk_info *info = &clk->eng[idx]; + const u32 addr = 0x137000 + (idx * 0x20); + nv_mask(clk, addr + 0x00, 0x00000004, 0x00000000); + nv_mask(clk, addr + 0x00, 0x00000001, 0x00000000); if (info->coef) { - nv_wr32(priv, addr + 0x04, info->coef); - nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004); + nv_wr32(clk, addr + 0x04, info->coef); + nv_mask(clk, addr + 0x00, 0x00000001, 0x00000001); + nv_wait(clk, addr + 0x00, 0x00020000, 0x00020000); + nv_mask(clk, addr + 0x00, 0x00020004, 0x00000004); } } static void -gk104_clk_prog_3(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_3(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; if (info->ssel) - nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv); + nv_mask(clk, 0x137250 + (idx * 0x04), 0x00003f00, info->mdiv); else - nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv); + nv_mask(clk, 0x137250 + (idx * 0x04), 0x0000003f, info->mdiv); } static void -gk104_clk_prog_4_0(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_4_0(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; if (info->ssel) { - nv_mask(priv, 0x137100, (1 << clk), info->ssel); - nv_wait(priv, 0x137100, (1 << clk), info->ssel); + nv_mask(clk, 0x137100, (1 << idx), info->ssel); + nv_wait(clk, 0x137100, (1 << idx), info->ssel); } } static void -gk104_clk_prog_4_1(struct gk104_clk_priv *priv, int clk) +gk104_clk_prog_4_1(struct gk104_clk *clk, int idx) { - struct gk104_clk_info *info = &priv->eng[clk]; + struct gk104_clk_info *info = &clk->eng[idx]; if (info->ssel) { - nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000); - nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100); + nv_mask(clk, 0x137160 + (idx * 0x04), 0x40000000, 0x40000000); + nv_mask(clk, 0x137160 + (idx * 0x04), 0x00000100, 0x00000100); } } static int -gk104_clk_prog(struct nvkm_clk *clk) +gk104_clk_prog(struct nvkm_clk *obj) { - struct gk104_clk_priv *priv = (void *)clk; + struct gk104_clk *clk = container_of(obj, typeof(*clk), base); struct { u32 mask; - void (*exec)(struct gk104_clk_priv *, int); + void (*exec)(struct gk104_clk *, int); } stage[] = { { 0x007f, gk104_clk_prog_0 }, /* div programming */ { 0x007f, gk104_clk_prog_1_0 }, /* select div mode */ @@ -432,12 +432,12 @@ gk104_clk_prog(struct nvkm_clk *clk) int i, j; for (i = 0; i < ARRAY_SIZE(stage); i++) { - for (j = 0; j < ARRAY_SIZE(priv->eng); j++) { + for (j = 0; j < ARRAY_SIZE(clk->eng); j++) { if (!(stage[i].mask & (1 << j))) continue; - if (!priv->eng[j].freq) + if (!clk->eng[j].freq) continue; - stage[i].exec(priv, j); + stage[i].exec(clk, j); } } @@ -445,10 +445,10 @@ gk104_clk_prog(struct nvkm_clk *clk) } static void -gk104_clk_tidy(struct nvkm_clk *clk) +gk104_clk_tidy(struct nvkm_clk *obj) { - struct gk104_clk_priv *priv = (void *)clk; - memset(priv->eng, 0x00, sizeof(priv->eng)); + struct gk104_clk *clk = container_of(obj, typeof(*clk), base); + memset(clk->eng, 0x00, sizeof(clk->eng)); } static struct nvkm_domain @@ -471,19 +471,19 @@ gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_clk_priv *priv; + struct gk104_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, gk104_domain, - NULL, 0, true, &priv); - *pobject = nv_object(priv); + NULL, 0, true, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->base.read = gk104_clk_read; - priv->base.calc = gk104_clk_calc; - priv->base.prog = gk104_clk_prog; - priv->base.tidy = gk104_clk_tidy; + clk->base.read = gk104_clk_read; + clk->base.calc = gk104_clk_calc; + clk->base.prog = gk104_clk_prog; + clk->base.tidy = gk104_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 94d3839fd444d..2019368775dac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -115,40 +115,40 @@ static const struct gk20a_clk_pllg_params gk20a_pllg_params = { .min_pl = 1, .max_pl = 32, }; -struct gk20a_clk_priv { +struct gk20a_clk { struct nvkm_clk base; const struct gk20a_clk_pllg_params *params; u32 m, n, pl; u32 parent_rate; }; -#define to_gk20a_clk(base) container_of(base, struct gk20a_clk_priv, base) +#define to_gk20a_clk(base) container_of(base, struct gk20a_clk, base) static void -gk20a_pllg_read_mnp(struct gk20a_clk_priv *priv) +gk20a_pllg_read_mnp(struct gk20a_clk *clk) { u32 val; - val = nv_rd32(priv, GPCPLL_COEFF); - priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); - priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH); - priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); + val = nv_rd32(clk, GPCPLL_COEFF); + clk->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); + clk->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH); + clk->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); } static u32 -gk20a_pllg_calc_rate(struct gk20a_clk_priv *priv) +gk20a_pllg_calc_rate(struct gk20a_clk *clk) { u32 rate; u32 divider; - rate = priv->parent_rate * priv->n; - divider = priv->m * pl_to_div[priv->pl]; + rate = clk->parent_rate * clk->n; + divider = clk->m * pl_to_div[clk->pl]; do_div(rate, divider); return rate / 2; } static int -gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) +gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) { u32 target_clk_f, ref_clk_f, target_freq; u32 min_vco_f, max_vco_f; @@ -161,13 +161,13 @@ gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) u32 pl; target_clk_f = rate * 2 / MHZ; - ref_clk_f = priv->parent_rate / MHZ; + ref_clk_f = clk->parent_rate / MHZ; - max_vco_f = priv->params->max_vco; - min_vco_f = priv->params->min_vco; - best_m = priv->params->max_m; - best_n = priv->params->min_n; - best_pl = priv->params->min_pl; + max_vco_f = clk->params->max_vco; + min_vco_f = clk->params->min_vco; + best_m = clk->params->max_m; + best_n = clk->params->min_n; + best_pl = clk->params->min_pl; target_vco_f = target_clk_f + target_clk_f / 50; if (max_vco_f < target_vco_f) @@ -175,13 +175,13 @@ gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) /* min_pl <= high_pl <= max_pl */ high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f; - high_pl = min(high_pl, priv->params->max_pl); - high_pl = max(high_pl, priv->params->min_pl); + high_pl = min(high_pl, clk->params->max_pl); + high_pl = max(high_pl, clk->params->min_pl); /* min_pl <= low_pl <= max_pl */ low_pl = min_vco_f / target_vco_f; - low_pl = min(low_pl, priv->params->max_pl); - low_pl = max(low_pl, priv->params->min_pl); + low_pl = min(low_pl, clk->params->max_pl); + low_pl = max(low_pl, clk->params->min_pl); /* Find Indices of high_pl and low_pl */ for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) { @@ -197,30 +197,30 @@ gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate) } } - nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, + nv_debug(clk, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, pl_to_div[low_pl], high_pl, pl_to_div[high_pl]); /* Select lowest possible VCO */ for (pl = low_pl; pl <= high_pl; pl++) { target_vco_f = target_clk_f * pl_to_div[pl]; - for (m = priv->params->min_m; m <= priv->params->max_m; m++) { + for (m = clk->params->min_m; m <= clk->params->max_m; m++) { u_f = ref_clk_f / m; - if (u_f < priv->params->min_u) + if (u_f < clk->params->min_u) break; - if (u_f > priv->params->max_u) + if (u_f > clk->params->max_u) continue; n = (target_vco_f * m) / ref_clk_f; n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f; - if (n > priv->params->max_n) + if (n > clk->params->max_n) break; for (; n <= n2; n++) { - if (n < priv->params->min_n) + if (n < clk->params->min_n) continue; - if (n > priv->params->max_n) + if (n > clk->params->max_n) break; vco_f = ref_clk_f * n / m; @@ -248,71 +248,71 @@ found_match: WARN_ON(best_delta == ~0); if (best_delta != 0) - nv_debug(priv, "no best match for target @ %dMHz on gpc_pll", + nv_debug(clk, "no best match for target @ %dMHz on gpc_pll", target_clk_f); - priv->m = best_m; - priv->n = best_n; - priv->pl = best_pl; + clk->m = best_m; + clk->n = best_n; + clk->pl = best_pl; - target_freq = gk20a_pllg_calc_rate(priv) / MHZ; + target_freq = gk20a_pllg_calc_rate(clk) / MHZ; - nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", - target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]); + nv_debug(clk, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", + target_freq, clk->m, clk->n, clk->pl, pl_to_div[clk->pl]); return 0; } static int -gk20a_pllg_slide(struct gk20a_clk_priv *priv, u32 n) +gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) { u32 val; int ramp_timeout; /* get old coefficients */ - val = nv_rd32(priv, GPCPLL_COEFF); + val = nv_rd32(clk, GPCPLL_COEFF); /* do nothing if NDIV is the same */ if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH))) return 0; /* setup */ - nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, + nv_mask(clk, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT); - nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, + nv_mask(clk, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT); /* pll slowdown mode */ - nv_mask(priv, GPCPLL_NDIV_SLOWDOWN, + nv_mask(clk, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT), BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT)); /* new ndiv ready for ramp */ - val = nv_rd32(priv, GPCPLL_COEFF); + val = nv_rd32(clk, GPCPLL_COEFF); val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT); val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT; udelay(1); - nv_wr32(priv, GPCPLL_COEFF, val); + nv_wr32(clk, GPCPLL_COEFF, val); /* dynamic ramp to new ndiv */ - val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN); + val = nv_rd32(clk, GPCPLL_NDIV_SLOWDOWN); val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT; udelay(1); - nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val); + nv_wr32(clk, GPCPLL_NDIV_SLOWDOWN, val); for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) { udelay(1); - val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); + val = nv_rd32(clk, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) break; } /* exit slowdown mode */ - nv_mask(priv, GPCPLL_NDIV_SLOWDOWN, + nv_mask(clk, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) | BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0); - nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN); + nv_rd32(clk, GPCPLL_NDIV_SLOWDOWN); if (ramp_timeout <= 0) { - nv_error(priv, "gpcpll dynamic ramp timeout\n"); + nv_error(clk, "gpcpll dynamic ramp timeout\n"); return -ETIMEDOUT; } @@ -320,138 +320,138 @@ gk20a_pllg_slide(struct gk20a_clk_priv *priv, u32 n) } static void -_gk20a_pllg_enable(struct gk20a_clk_priv *priv) +_gk20a_pllg_enable(struct gk20a_clk *clk) { - nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); - nv_rd32(priv, GPCPLL_CFG); + nv_mask(clk, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); + nv_rd32(clk, GPCPLL_CFG); } static void -_gk20a_pllg_disable(struct gk20a_clk_priv *priv) +_gk20a_pllg_disable(struct gk20a_clk *clk) { - nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); - nv_rd32(priv, GPCPLL_CFG); + nv_mask(clk, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); + nv_rd32(clk, GPCPLL_CFG); } static int -_gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv, bool allow_slide) +_gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) { u32 val, cfg; u32 m_old, pl_old, n_lo; /* get old coefficients */ - val = nv_rd32(priv, GPCPLL_COEFF); + val = nv_rd32(clk, GPCPLL_COEFF); m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); /* do NDIV slide if there is no change in M and PL */ - cfg = nv_rd32(priv, GPCPLL_CFG); - if (allow_slide && priv->m == m_old && priv->pl == pl_old && + cfg = nv_rd32(clk, GPCPLL_CFG); + if (allow_slide && clk->m == m_old && clk->pl == pl_old && (cfg & GPCPLL_CFG_ENABLE)) { - return gk20a_pllg_slide(priv, priv->n); + return gk20a_pllg_slide(clk, clk->n); } /* slide down to NDIV_LO */ - n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco, - priv->parent_rate / MHZ); + n_lo = DIV_ROUND_UP(m_old * clk->params->min_vco, + clk->parent_rate / MHZ); if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) { - int ret = gk20a_pllg_slide(priv, n_lo); + int ret = gk20a_pllg_slide(clk, n_lo); if (ret) return ret; } /* split FO-to-bypass jump in halfs by setting out divider 1:2 */ - nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + nv_mask(clk, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, 0x2 << GPC2CLK_OUT_VCODIV_SHIFT); /* put PLL in bypass before programming it */ - val = nv_rd32(priv, SEL_VCO); + val = nv_rd32(clk, SEL_VCO); val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); udelay(2); - nv_wr32(priv, SEL_VCO, val); + nv_wr32(clk, SEL_VCO, val); /* get out from IDDQ */ - val = nv_rd32(priv, GPCPLL_CFG); + val = nv_rd32(clk, GPCPLL_CFG); if (val & GPCPLL_CFG_IDDQ) { val &= ~GPCPLL_CFG_IDDQ; - nv_wr32(priv, GPCPLL_CFG, val); - nv_rd32(priv, GPCPLL_CFG); + nv_wr32(clk, GPCPLL_CFG, val); + nv_rd32(clk, GPCPLL_CFG); udelay(2); } - _gk20a_pllg_disable(priv); + _gk20a_pllg_disable(clk); - nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n, - priv->pl); + nv_debug(clk, "%s: m=%d n=%d pl=%d\n", __func__, clk->m, clk->n, + clk->pl); - n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco, - priv->parent_rate / MHZ); - val = priv->m << GPCPLL_COEFF_M_SHIFT; - val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT; - val |= priv->pl << GPCPLL_COEFF_P_SHIFT; - nv_wr32(priv, GPCPLL_COEFF, val); + n_lo = DIV_ROUND_UP(clk->m * clk->params->min_vco, + clk->parent_rate / MHZ); + val = clk->m << GPCPLL_COEFF_M_SHIFT; + val |= (allow_slide ? n_lo : clk->n) << GPCPLL_COEFF_N_SHIFT; + val |= clk->pl << GPCPLL_COEFF_P_SHIFT; + nv_wr32(clk, GPCPLL_COEFF, val); - _gk20a_pllg_enable(priv); + _gk20a_pllg_enable(clk); - val = nv_rd32(priv, GPCPLL_CFG); + val = nv_rd32(clk, GPCPLL_CFG); if (val & GPCPLL_CFG_LOCK_DET_OFF) { val &= ~GPCPLL_CFG_LOCK_DET_OFF; - nv_wr32(priv, GPCPLL_CFG, val); + nv_wr32(clk, GPCPLL_CFG, val); } - if (!nvkm_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, + if (!nvkm_timer_wait_eq(clk, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, GPCPLL_CFG_LOCK)) { - nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__); + nv_error(clk, "%s: timeout waiting for pllg lock\n", __func__); return -ETIMEDOUT; } /* switch to VCO mode */ - nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + nv_mask(clk, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); /* restore out divider 1:1 */ - val = nv_rd32(priv, GPC2CLK_OUT); + val = nv_rd32(clk, GPC2CLK_OUT); val &= ~GPC2CLK_OUT_VCODIV_MASK; udelay(2); - nv_wr32(priv, GPC2CLK_OUT, val); + nv_wr32(clk, GPC2CLK_OUT, val); /* slide up to new NDIV */ - return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0; + return allow_slide ? gk20a_pllg_slide(clk, clk->n) : 0; } static int -gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv) +gk20a_pllg_program_mnp(struct gk20a_clk *clk) { int err; - err = _gk20a_pllg_program_mnp(priv, true); + err = _gk20a_pllg_program_mnp(clk, true); if (err) - err = _gk20a_pllg_program_mnp(priv, false); + err = _gk20a_pllg_program_mnp(clk, false); return err; } static void -gk20a_pllg_disable(struct gk20a_clk_priv *priv) +gk20a_pllg_disable(struct gk20a_clk *clk) { u32 val; /* slide to VCO min */ - val = nv_rd32(priv, GPCPLL_CFG); + val = nv_rd32(clk, GPCPLL_CFG); if (val & GPCPLL_CFG_ENABLE) { u32 coeff, m, n_lo; - coeff = nv_rd32(priv, GPCPLL_COEFF); + coeff = nv_rd32(clk, GPCPLL_COEFF); m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); - n_lo = DIV_ROUND_UP(m * priv->params->min_vco, - priv->parent_rate / MHZ); - gk20a_pllg_slide(priv, n_lo); + n_lo = DIV_ROUND_UP(m * clk->params->min_vco, + clk->parent_rate / MHZ); + gk20a_pllg_slide(clk, n_lo); } /* put PLL in bypass before disabling it */ - nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); + nv_mask(clk, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); - _gk20a_pllg_disable(priv); + _gk20a_pllg_disable(clk); } #define GK20A_CLK_GPC_MDIV 1000 @@ -558,16 +558,16 @@ gk20a_pstates[] = { }; static int -gk20a_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gk20a_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { - struct gk20a_clk_priv *priv = (void *)clk; + struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); switch (src) { case nv_clk_src_crystal: return nv_device(clk)->crystal; case nv_clk_src_gpc: - gk20a_pllg_read_mnp(priv); - return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV; + gk20a_pllg_read_mnp(clk); + return gk20a_pllg_calc_rate(clk) / GK20A_CLK_GPC_MDIV; default: nv_error(clk, "invalid clock source %d\n", src); return -EINVAL; @@ -575,36 +575,36 @@ gk20a_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) } static int -gk20a_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gk20a_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct gk20a_clk_priv *priv = (void *)clk; + struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); - return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] * + return gk20a_pllg_calc_mnp(clk, cstate->domain[nv_clk_src_gpc] * GK20A_CLK_GPC_MDIV); } static int -gk20a_clk_prog(struct nvkm_clk *clk) +gk20a_clk_prog(struct nvkm_clk *obj) { - struct gk20a_clk_priv *priv = (void *)clk; + struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); - return gk20a_pllg_program_mnp(priv); + return gk20a_pllg_program_mnp(clk); } static void -gk20a_clk_tidy(struct nvkm_clk *clk) +gk20a_clk_tidy(struct nvkm_clk *obj) { } static int gk20a_clk_fini(struct nvkm_object *object, bool suspend) { - struct gk20a_clk_priv *priv = (void *)object; + struct gk20a_clk *clk = (void *)object; int ret; - ret = nvkm_clk_fini(&priv->base, false); + ret = nvkm_clk_fini(&clk->base, false); - gk20a_pllg_disable(priv); + gk20a_pllg_disable(clk); return ret; } @@ -612,18 +612,18 @@ gk20a_clk_fini(struct nvkm_object *object, bool suspend) static int gk20a_clk_init(struct nvkm_object *object) { - struct gk20a_clk_priv *priv = (void *)object; + struct gk20a_clk *clk = (void *)object; int ret; - nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); + nv_mask(clk, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); - ret = nvkm_clk_init(&priv->base); + ret = nvkm_clk_init(&clk->base); if (ret) return ret; - ret = gk20a_clk_prog(&priv->base); + ret = gk20a_clk_prog(&clk->base); if (ret) { - nv_error(priv, "cannot initialize clock\n"); + nv_error(clk, "cannot initialize clock\n"); return ret; } @@ -635,7 +635,7 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk20a_clk_priv *priv; + struct gk20a_clk *clk; struct nouveau_platform_device *plat; int ret; int i; @@ -648,21 +648,21 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ret = nvkm_clk_create(parent, engine, oclass, gk20a_domains, gk20a_pstates, ARRAY_SIZE(gk20a_pstates), - true, &priv); - *pobject = nv_object(priv); + true, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->params = &gk20a_pllg_params; + clk->params = &gk20a_pllg_params; plat = nv_device_to_platform(nv_device(parent)); - priv->parent_rate = clk_get_rate(plat->gpu->clk); - nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ); + clk->parent_rate = clk_get_rate(plat->gpu->clk); + nv_info(clk, "parent clock rate: %d Mhz\n", clk->parent_rate / MHZ); - priv->base.read = gk20a_clk_read; - priv->base.calc = gk20a_clk_calc; - priv->base.prog = gk20a_clk_prog; - priv->base.tidy = gk20a_clk_tidy; + clk->base.read = gk20a_clk_read; + clk->base.calc = gk20a_clk_calc; + clk->base.prog = gk20a_clk_prog; + clk->base.tidy = gk20a_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 581e3a696fd8f..5dc637840a651 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -30,47 +30,47 @@ #include #include -struct gt215_clk_priv { +struct gt215_clk { struct nvkm_clk base; struct gt215_clk_info eng[nv_clk_src_max]; }; -static u32 read_clk(struct gt215_clk_priv *, int, bool); -static u32 read_pll(struct gt215_clk_priv *, int, u32); +static u32 read_clk(struct gt215_clk *, int, bool); +static u32 read_pll(struct gt215_clk *, int, u32); static u32 -read_vco(struct gt215_clk_priv *priv, int clk) +read_vco(struct gt215_clk *clk, int idx) { - u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + u32 sctl = nv_rd32(clk, 0x4120 + (idx * 4)); switch (sctl & 0x00000030) { case 0x00000000: - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; case 0x00000020: - return read_pll(priv, 0x41, 0x00e820); + return read_pll(clk, 0x41, 0x00e820); case 0x00000030: - return read_pll(priv, 0x42, 0x00e8a0); + return read_pll(clk, 0x42, 0x00e8a0); default: return 0; } } static u32 -read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) +read_clk(struct gt215_clk *clk, int idx, bool ignore_en) { u32 sctl, sdiv, sclk; /* refclk for the 0xe8xx plls is a fixed frequency */ - if (clk >= 0x40) { - if (nv_device(priv)->chipset == 0xaf) { + if (idx >= 0x40) { + if (nv_device(clk)->chipset == 0xaf) { /* no joke.. seriously.. sigh.. */ - return nv_rd32(priv, 0x00471c) * 1000; + return nv_rd32(clk, 0x00471c) * 1000; } - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; } - sctl = nv_rd32(priv, 0x4120 + (clk * 4)); + sctl = nv_rd32(clk, 0x4120 + (idx * 4)); if (!ignore_en && !(sctl & 0x00000100)) return 0; @@ -82,7 +82,7 @@ read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) switch (sctl & 0x00003000) { case 0x00000000: if (!(sctl & 0x00000200)) - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; return 0; case 0x00002000: if (sctl & 0x00000040) @@ -93,7 +93,7 @@ read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) if (!(sctl & 0x00000001)) return 0; - sclk = read_vco(priv, clk); + sclk = read_vco(clk, idx); sdiv = ((sctl & 0x003f0000) >> 16) + 2; return (sclk * 2) / sdiv; default: @@ -102,14 +102,14 @@ read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en) } static u32 -read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) +read_pll(struct gt215_clk *clk, int idx, u32 pll) { - u32 ctrl = nv_rd32(priv, pll + 0); + u32 ctrl = nv_rd32(clk, pll + 0); u32 sclk = 0, P = 1, N = 1, M = 1; if (!(ctrl & 0x00000008)) { if (ctrl & 0x00000001) { - u32 coef = nv_rd32(priv, pll + 4); + u32 coef = nv_rd32(clk, pll + 4); M = (coef & 0x000000ff) >> 0; N = (coef & 0x0000ff00) >> 8; P = (coef & 0x003f0000) >> 16; @@ -120,10 +120,10 @@ read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) if ((pll & 0x00ff00) == 0x00e800) P = 1; - sclk = read_clk(priv, 0x00 + clk, false); + sclk = read_clk(clk, 0x00 + idx, false); } } else { - sclk = read_clk(priv, 0x10 + clk, false); + sclk = read_clk(clk, 0x10 + idx, false); } if (M * P) @@ -133,32 +133,32 @@ read_pll(struct gt215_clk_priv *priv, int clk, u32 pll) } static int -gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { - struct gt215_clk_priv *priv = (void *)clk; + struct gt215_clk *clk = container_of(obj, typeof(*clk), base); u32 hsrc; switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; case nv_clk_src_core: case nv_clk_src_core_intm: - return read_pll(priv, 0x00, 0x4200); + return read_pll(clk, 0x00, 0x4200); case nv_clk_src_shader: - return read_pll(priv, 0x01, 0x4220); + return read_pll(clk, 0x01, 0x4220); case nv_clk_src_mem: - return read_pll(priv, 0x02, 0x4000); + return read_pll(clk, 0x02, 0x4000); case nv_clk_src_disp: - return read_clk(priv, 0x20, false); + return read_clk(clk, 0x20, false); case nv_clk_src_vdec: - return read_clk(priv, 0x21, false); + return read_clk(clk, 0x21, false); case nv_clk_src_daemon: - return read_clk(priv, 0x25, false); + return read_clk(clk, 0x25, false); case nv_clk_src_host: - hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28; + hsrc = (nv_rd32(clk, 0xc040) & 0x30000000) >> 28; switch (hsrc) { case 0: - return read_clk(priv, 0x1d, false); + return read_clk(clk, 0x1d, false); case 2: case 3: return 277000; @@ -175,10 +175,10 @@ gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) } int -gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, +gt215_clk_info(struct nvkm_clk *obj, int idx, u32 khz, struct gt215_clk_info *info) { - struct gt215_clk_priv *priv = (void *)clock; + struct gt215_clk *clk = container_of(obj, typeof(*clk), base); u32 oclk, sclk, sdiv; s32 diff; @@ -195,7 +195,7 @@ gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, info->clk = 0x00002140; return khz; default: - sclk = read_vco(priv, clk); + sclk = read_vco(clk, idx); sdiv = min((sclk * 2) / khz, (u32)65); oclk = (sclk * 2) / sdiv; diff = ((khz + 3000) - oclk); @@ -223,11 +223,11 @@ gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz, } int -gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz, +gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, struct gt215_clk_info *info) { struct nvkm_bios *bios = nvkm_bios(clock); - struct gt215_clk_priv *priv = (void *)clock; + struct gt215_clk *clk = (void *)clock; struct nvbios_pll limits; int P, N, M, diff; int ret; @@ -236,7 +236,7 @@ gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz, /* If we can get a within [-2, 3) MHz of a divider, we'll disable the * PLL and use the divider instead. */ - ret = gt215_clk_info(clock, clk, khz, info); + ret = gt215_clk_info(clock, idx, khz, info); diff = khz - ret; if (!pll || (diff >= -2000 && diff < 3000)) { goto out; @@ -247,11 +247,11 @@ gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz, if (ret) return ret; - ret = gt215_clk_info(clock, clk - 0x10, limits.refclk, info); + ret = gt215_clk_info(clock, idx - 0x10, limits.refclk, info); if (ret != limits.refclk) return -EINVAL; - ret = gt215_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P); + ret = gt215_pll_calc(nv_subdev(clk), &limits, khz, &N, NULL, &M, &P); if (ret >= 0) { info->pll = (P << 16) | (N << 8) | M; } @@ -262,22 +262,22 @@ out: } static int -calc_clk(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate, - int clk, u32 pll, int idx) +calc_clk(struct gt215_clk *clk, struct nvkm_cstate *cstate, + int idx, u32 pll, int dom) { - int ret = gt215_pll_info(&priv->base, clk, pll, cstate->domain[idx], - &priv->eng[idx]); + int ret = gt215_pll_info(&clk->base, idx, pll, cstate->domain[dom], + &clk->eng[dom]); if (ret >= 0) return 0; return ret; } static int -calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate) +calc_host(struct gt215_clk *clk, struct nvkm_cstate *cstate) { int ret = 0; u32 kHz = cstate->domain[nv_clk_src_host]; - struct gt215_clk_info *info = &priv->eng[nv_clk_src_host]; + struct gt215_clk_info *info = &clk->eng[nv_clk_src_host]; if (kHz == 277000) { info->clk = 0; @@ -287,7 +287,7 @@ calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate) info->host_out = NVA3_HOST_CLK; - ret = gt215_clk_info(&priv->base, 0x1d, kHz, info); + ret = gt215_clk_info(&clk->base, 0x1d, kHz, info); if (ret >= 0) return 0; @@ -330,76 +330,76 @@ gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) } static void -disable_clk_src(struct gt215_clk_priv *priv, u32 src) +disable_clk_src(struct gt215_clk *clk, u32 src) { - nv_mask(priv, src, 0x00000100, 0x00000000); - nv_mask(priv, src, 0x00000001, 0x00000000); + nv_mask(clk, src, 0x00000100, 0x00000000); + nv_mask(clk, src, 0x00000001, 0x00000000); } static void -prog_pll(struct gt215_clk_priv *priv, int clk, u32 pll, int idx) +prog_pll(struct gt215_clk *clk, int idx, u32 pll, int dom) { - struct gt215_clk_info *info = &priv->eng[idx]; - const u32 src0 = 0x004120 + (clk * 4); - const u32 src1 = 0x004160 + (clk * 4); + struct gt215_clk_info *info = &clk->eng[dom]; + const u32 src0 = 0x004120 + (idx * 4); + const u32 src1 = 0x004160 + (idx * 4); const u32 ctrl = pll + 0; const u32 coef = pll + 4; u32 bypass; if (info->pll) { /* Always start from a non-PLL clock */ - bypass = nv_rd32(priv, ctrl) & 0x00000008; + bypass = nv_rd32(clk, ctrl) & 0x00000008; if (!bypass) { - nv_mask(priv, src1, 0x00000101, 0x00000101); - nv_mask(priv, ctrl, 0x00000008, 0x00000008); + nv_mask(clk, src1, 0x00000101, 0x00000101); + nv_mask(clk, ctrl, 0x00000008, 0x00000008); udelay(20); } - nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk); - nv_wr32(priv, coef, info->pll); - nv_mask(priv, ctrl, 0x00000015, 0x00000015); - nv_mask(priv, ctrl, 0x00000010, 0x00000000); - if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) { - nv_mask(priv, ctrl, 0x00000010, 0x00000010); - nv_mask(priv, src0, 0x00000101, 0x00000000); + nv_mask(clk, src0, 0x003f3141, 0x00000101 | info->clk); + nv_wr32(clk, coef, info->pll); + nv_mask(clk, ctrl, 0x00000015, 0x00000015); + nv_mask(clk, ctrl, 0x00000010, 0x00000000); + if (!nv_wait(clk, ctrl, 0x00020000, 0x00020000)) { + nv_mask(clk, ctrl, 0x00000010, 0x00000010); + nv_mask(clk, src0, 0x00000101, 0x00000000); return; } - nv_mask(priv, ctrl, 0x00000010, 0x00000010); - nv_mask(priv, ctrl, 0x00000008, 0x00000000); - disable_clk_src(priv, src1); + nv_mask(clk, ctrl, 0x00000010, 0x00000010); + nv_mask(clk, ctrl, 0x00000008, 0x00000000); + disable_clk_src(clk, src1); } else { - nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk); - nv_mask(priv, ctrl, 0x00000018, 0x00000018); + nv_mask(clk, src1, 0x003f3141, 0x00000101 | info->clk); + nv_mask(clk, ctrl, 0x00000018, 0x00000018); udelay(20); - nv_mask(priv, ctrl, 0x00000001, 0x00000000); - disable_clk_src(priv, src0); + nv_mask(clk, ctrl, 0x00000001, 0x00000000); + disable_clk_src(clk, src0); } } static void -prog_clk(struct gt215_clk_priv *priv, int clk, int idx) +prog_clk(struct gt215_clk *clk, int idx, int dom) { - struct gt215_clk_info *info = &priv->eng[idx]; - nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk); + struct gt215_clk_info *info = &clk->eng[dom]; + nv_mask(clk, 0x004120 + (idx * 4), 0x003f3141, 0x00000101 | info->clk); } static void -prog_host(struct gt215_clk_priv *priv) +prog_host(struct gt215_clk *clk) { - struct gt215_clk_info *info = &priv->eng[nv_clk_src_host]; - u32 hsrc = (nv_rd32(priv, 0xc040)); + struct gt215_clk_info *info = &clk->eng[nv_clk_src_host]; + u32 hsrc = (nv_rd32(clk, 0xc040)); switch (info->host_out) { case NVA3_HOST_277: if ((hsrc & 0x30000000) == 0) { - nv_wr32(priv, 0xc040, hsrc | 0x20000000); - disable_clk_src(priv, 0x4194); + nv_wr32(clk, 0xc040, hsrc | 0x20000000); + disable_clk_src(clk, 0x4194); } break; case NVA3_HOST_CLK: - prog_clk(priv, 0x1d, nv_clk_src_host); + prog_clk(clk, 0x1d, nv_clk_src_host); if ((hsrc & 0x30000000) >= 0x20000000) { - nv_wr32(priv, 0xc040, hsrc & ~0x30000000); + nv_wr32(clk, 0xc040, hsrc & ~0x30000000); } break; default: @@ -407,44 +407,44 @@ prog_host(struct gt215_clk_priv *priv) } /* This seems to be a clock gating factor on idle, always set to 64 */ - nv_wr32(priv, 0xc044, 0x3e); + nv_wr32(clk, 0xc044, 0x3e); } static void -prog_core(struct gt215_clk_priv *priv, int idx) +prog_core(struct gt215_clk *clk, int dom) { - struct gt215_clk_info *info = &priv->eng[idx]; - u32 fb_delay = nv_rd32(priv, 0x10002c); + struct gt215_clk_info *info = &clk->eng[dom]; + u32 fb_delay = nv_rd32(clk, 0x10002c); if (fb_delay < info->fb_delay) - nv_wr32(priv, 0x10002c, info->fb_delay); + nv_wr32(clk, 0x10002c, info->fb_delay); - prog_pll(priv, 0x00, 0x004200, idx); + prog_pll(clk, 0x00, 0x004200, dom); if (fb_delay > info->fb_delay) - nv_wr32(priv, 0x10002c, info->fb_delay); + nv_wr32(clk, 0x10002c, info->fb_delay); } static int -gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +gt215_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct gt215_clk_priv *priv = (void *)clk; - struct gt215_clk_info *core = &priv->eng[nv_clk_src_core]; + struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct gt215_clk_info *core = &clk->eng[nv_clk_src_core]; int ret; - if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) || - (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) || - (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) || - (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || - (ret = calc_host(priv, cstate))) + if ((ret = calc_clk(clk, cstate, 0x10, 0x4200, nv_clk_src_core)) || + (ret = calc_clk(clk, cstate, 0x11, 0x4220, nv_clk_src_shader)) || + (ret = calc_clk(clk, cstate, 0x20, 0x0000, nv_clk_src_disp)) || + (ret = calc_clk(clk, cstate, 0x21, 0x0000, nv_clk_src_vdec)) || + (ret = calc_host(clk, cstate))) return ret; /* XXX: Should be reading the highest bit in the VBIOS clock to decide * whether to use a PLL or not... but using a PLL defeats the purpose */ if (core->pll) { - ret = gt215_clk_info(clk, 0x10, + ret = gt215_clk_info(&clk->base, 0x10, cstate->domain[nv_clk_src_core_intm], - &priv->eng[nv_clk_src_core_intm]); + &clk->eng[nv_clk_src_core_intm]); if (ret < 0) return ret; } @@ -453,37 +453,37 @@ gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) } static int -gt215_clk_prog(struct nvkm_clk *clk) +gt215_clk_prog(struct nvkm_clk *obj) { - struct gt215_clk_priv *priv = (void *)clk; - struct gt215_clk_info *core = &priv->eng[nv_clk_src_core]; + struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct gt215_clk_info *core = &clk->eng[nv_clk_src_core]; int ret = 0; unsigned long flags; unsigned long *f = &flags; - ret = gt215_clk_pre(clk, f); + ret = gt215_clk_pre(&clk->base, f); if (ret) goto out; if (core->pll) - prog_core(priv, nv_clk_src_core_intm); + prog_core(clk, nv_clk_src_core_intm); - prog_core(priv, nv_clk_src_core); - prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader); - prog_clk(priv, 0x20, nv_clk_src_disp); - prog_clk(priv, 0x21, nv_clk_src_vdec); - prog_host(priv); + prog_core(clk, nv_clk_src_core); + prog_pll(clk, 0x01, 0x004220, nv_clk_src_shader); + prog_clk(clk, 0x20, nv_clk_src_disp); + prog_clk(clk, 0x21, nv_clk_src_vdec); + prog_host(clk); out: if (ret == -EBUSY) f = NULL; - gt215_clk_post(clk, f); + gt215_clk_post(&clk->base, f); return ret; } static void -gt215_clk_tidy(struct nvkm_clk *clk) +gt215_clk_tidy(struct nvkm_clk *obj) { } @@ -505,19 +505,19 @@ gt215_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gt215_clk_priv *priv; + struct gt215_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, gt215_domain, - NULL, 0, true, &priv); - *pobject = nv_object(priv); + NULL, 0, true, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->base.read = gt215_clk_read; - priv->base.calc = gt215_clk_calc; - priv->base.prog = gt215_clk_prog; - priv->base.tidy = gt215_clk_tidy; + clk->base.read = gt215_clk_read; + clk->base.calc = gt215_clk_calc; + clk->base.prog = gt215_clk_prog; + clk->base.tidy = gt215_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h index b447d9cd4d376..39b0ef8187ea8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h @@ -13,6 +13,6 @@ struct gt215_clk_info { }; int gt215_pll_info(struct nvkm_clk *, int, u32, u32, struct gt215_clk_info *); -int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags); -void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags); +int gt215_clk_pre(struct nvkm_clk *, unsigned long *flags); +void gt215_clk_post(struct nvkm_clk *, unsigned long *flags); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index d735de2dbd74c..7203bb3e0a9a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -28,7 +28,7 @@ #include #include -struct mcp77_clk_priv { +struct mcp77_clk { struct nvkm_clk base; enum nv_clk_src csrc, ssrc, vsrc; u32 cctrl, sctrl; @@ -38,17 +38,17 @@ struct mcp77_clk_priv { }; static u32 -read_div(struct nvkm_clk *clk) +read_div(struct mcp77_clk *clk) { return nv_rd32(clk, 0x004600); } static u32 -read_pll(struct nvkm_clk *clk, u32 base) +read_pll(struct mcp77_clk *clk, u32 base) { u32 ctrl = nv_rd32(clk, base + 0); u32 coef = nv_rd32(clk, base + 4); - u32 ref = clk->read(clk, nv_clk_src_href); + u32 ref = clk->base.read(&clk->base, nv_clk_src_href); u32 post_div = 0; u32 clock = 0; int N1, M1; @@ -75,50 +75,50 @@ read_pll(struct nvkm_clk *clk, u32 base) } static int -mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { - struct mcp77_clk_priv *priv = (void *)clk; + struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); u32 mast = nv_rd32(clk, 0x00c054); u32 P = 0; switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclkm4: - return clk->read(clk, nv_clk_src_href) * 4; + return clk->base.read(&clk->base, nv_clk_src_href) * 4; case nv_clk_src_hclkm2d3: - return clk->read(clk, nv_clk_src_href) * 2 / 3; + return clk->base.read(&clk->base, nv_clk_src_href) * 2 / 3; case nv_clk_src_host: switch (mast & 0x000c0000) { - case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3); + case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_hclkm2d3); case 0x00040000: break; - case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4); - case 0x000c0000: return clk->read(clk, nv_clk_src_cclk); + case 0x00080000: return clk->base.read(&clk->base, nv_clk_src_hclkm4); + case 0x000c0000: return clk->base.read(&clk->base, nv_clk_src_cclk); } break; case nv_clk_src_core: P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { - case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; + case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000001: return 0; - case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P; + case 0x00000002: return clk->base.read(&clk->base, nv_clk_src_hclkm4) >> P; case 0x00000003: return read_pll(clk, 0x004028) >> P; } break; case nv_clk_src_cclk: if ((mast & 0x03000000) != 0x03000000) - return clk->read(clk, nv_clk_src_core); + return clk->base.read(&clk->base, nv_clk_src_core); if ((mast & 0x00000200) == 0x00000000) - return clk->read(clk, nv_clk_src_core); + return clk->base.read(&clk->base, nv_clk_src_core); switch (mast & 0x00000c00) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); - case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4); - case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3); + case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_href); + case 0x00000400: return clk->base.read(&clk->base, nv_clk_src_hclkm4); + case 0x00000800: return clk->base.read(&clk->base, nv_clk_src_hclkm2d3); default: return 0; } case nv_clk_src_shader: @@ -126,8 +126,8 @@ mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000040) - return clk->read(clk, nv_clk_src_href) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; + return clk->base.read(&clk->base, nv_clk_src_href) >> P; + return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000010: break; case 0x00000020: return read_pll(clk, 0x004028) >> P; case 0x00000030: return read_pll(clk, 0x004020) >> P; @@ -141,7 +141,7 @@ mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) switch (mast & 0x00400000) { case 0x00400000: - return clk->read(clk, nv_clk_src_core) >> P; + return clk->base.read(&clk->base, nv_clk_src_core) >> P; break; default: return 500000 >> P; @@ -152,17 +152,16 @@ mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) break; } - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + nv_debug(clk, "unknown clock source %d 0x%08x\n", src, mast); return 0; } static u32 -calc_pll(struct mcp77_clk_priv *priv, u32 reg, +calc_pll(struct mcp77_clk *clk, u32 reg, u32 clock, int *N, int *M, int *P) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(clk); struct nvbios_pll pll; - struct nvkm_clk *clk = &priv->base; int ret; ret = nvbios_pll_parse(bios, reg, &pll); @@ -170,11 +169,11 @@ calc_pll(struct mcp77_clk_priv *priv, u32 reg, return 0; pll.vco2.max_freq = 0; - pll.refclk = clk->read(clk, nv_clk_src_href); + pll.refclk = clk->base.read(&clk->base, nv_clk_src_href); if (!pll.refclk) return 0; - return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P); + return nv04_pll_calc(nv_subdev(clk), &pll, clock, N, M, NULL, NULL, P); } static inline u32 @@ -196,9 +195,9 @@ calc_P(u32 src, u32 target, int *div) } static int -mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct mcp77_clk_priv *priv = (void *)clk; + struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; @@ -207,15 +206,15 @@ mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) int divs = 0; /* cclk: find suitable source, disable PLL if we can */ - if (core < clk->read(clk, nv_clk_src_hclkm4)) - out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs); + if (core < clk->base.read(&clk->base, nv_clk_src_hclkm4)) + out = calc_P(clk->base.read(&clk->base, nv_clk_src_hclkm4), core, &divs); /* Calculate clock * 2, so shader clock can use it too */ - clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1); + clock = calc_pll(clk, 0x4028, (core << 1), &N, &M, &P1); if (abs(core - out) <= abs(core - (clock >> 1))) { - priv->csrc = nv_clk_src_hclkm4; - priv->cctrl = divs << 16; + clk->csrc = nv_clk_src_hclkm4; + clk->cctrl = divs << 16; } else { /* NVCTRL is actually used _after_ NVPOST, and after what we * call NVPLL. To make matters worse, NVPOST is an integer @@ -225,31 +224,31 @@ mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) P1 = 2; } - priv->csrc = nv_clk_src_core; - priv->ccoef = (N << 8) | M; + clk->csrc = nv_clk_src_core; + clk->ccoef = (N << 8) | M; - priv->cctrl = (P2 + 1) << 16; - priv->cpost = (1 << P1) << 16; + clk->cctrl = (P2 + 1) << 16; + clk->cpost = (1 << P1) << 16; } /* sclk: nvpll + divisor, href or spll */ out = 0; - if (shader == clk->read(clk, nv_clk_src_href)) { - priv->ssrc = nv_clk_src_href; + if (shader == clk->base.read(&clk->base, nv_clk_src_href)) { + clk->ssrc = nv_clk_src_href; } else { - clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1); - if (priv->csrc == nv_clk_src_core) + clock = calc_pll(clk, 0x4020, shader, &N, &M, &P1); + if (clk->csrc == nv_clk_src_core) out = calc_P((core << 1), shader, &divs); if (abs(shader - out) <= abs(shader - clock) && (divs + P2) <= 7) { - priv->ssrc = nv_clk_src_core; - priv->sctrl = (divs + P2) << 16; + clk->ssrc = nv_clk_src_core; + clk->sctrl = (divs + P2) << 16; } else { - priv->ssrc = nv_clk_src_shader; - priv->scoef = (N << 8) | M; - priv->sctrl = P1 << 16; + clk->ssrc = nv_clk_src_shader; + clk->scoef = (N << 8) | M; + clk->sctrl = P1 << 16; } } @@ -257,49 +256,49 @@ mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) out = calc_P(core, vdec, &divs); clock = calc_P(500000, vdec, &P1); if(abs(vdec - out) <= abs(vdec - clock)) { - priv->vsrc = nv_clk_src_cclk; - priv->vdiv = divs << 16; + clk->vsrc = nv_clk_src_cclk; + clk->vdiv = divs << 16; } else { - priv->vsrc = nv_clk_src_vdec; - priv->vdiv = P1 << 16; + clk->vsrc = nv_clk_src_vdec; + clk->vdiv = P1 << 16; } /* Print strategy! */ - nv_debug(priv, "nvpll: %08x %08x %08x\n", - priv->ccoef, priv->cpost, priv->cctrl); - nv_debug(priv, " spll: %08x %08x %08x\n", - priv->scoef, priv->spost, priv->sctrl); - nv_debug(priv, " vdiv: %08x\n", priv->vdiv); - if (priv->csrc == nv_clk_src_hclkm4) - nv_debug(priv, "core: hrefm4\n"); + nv_debug(clk, "nvpll: %08x %08x %08x\n", + clk->ccoef, clk->cpost, clk->cctrl); + nv_debug(clk, " spll: %08x %08x %08x\n", + clk->scoef, clk->spost, clk->sctrl); + nv_debug(clk, " vdiv: %08x\n", clk->vdiv); + if (clk->csrc == nv_clk_src_hclkm4) + nv_debug(clk, "core: hrefm4\n"); else - nv_debug(priv, "core: nvpll\n"); + nv_debug(clk, "core: nvpll\n"); - if (priv->ssrc == nv_clk_src_hclkm4) - nv_debug(priv, "shader: hrefm4\n"); - else if (priv->ssrc == nv_clk_src_core) - nv_debug(priv, "shader: nvpll\n"); + if (clk->ssrc == nv_clk_src_hclkm4) + nv_debug(clk, "shader: hrefm4\n"); + else if (clk->ssrc == nv_clk_src_core) + nv_debug(clk, "shader: nvpll\n"); else - nv_debug(priv, "shader: spll\n"); + nv_debug(clk, "shader: spll\n"); - if (priv->vsrc == nv_clk_src_hclkm4) - nv_debug(priv, "vdec: 500MHz\n"); + if (clk->vsrc == nv_clk_src_hclkm4) + nv_debug(clk, "vdec: 500MHz\n"); else - nv_debug(priv, "vdec: core\n"); + nv_debug(clk, "vdec: core\n"); return 0; } static int -mcp77_clk_prog(struct nvkm_clk *clk) +mcp77_clk_prog(struct nvkm_clk *obj) { - struct mcp77_clk_priv *priv = (void *)clk; + struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); u32 pllmask = 0, mast; unsigned long flags; unsigned long *f = &flags; int ret = 0; - ret = gt215_clk_pre(clk, f); + ret = gt215_clk_pre(&clk->base, f); if (ret) goto out; @@ -308,66 +307,66 @@ mcp77_clk_prog(struct nvkm_clk *clk) mast &= ~0x00400e73; mast |= 0x03000000; - switch (priv->csrc) { + switch (clk->csrc) { case nv_clk_src_hclkm4: - nv_mask(clk, 0x4028, 0x00070000, priv->cctrl); + nv_mask(clk, 0x4028, 0x00070000, clk->cctrl); mast |= 0x00000002; break; case nv_clk_src_core: - nv_wr32(clk, 0x402c, priv->ccoef); - nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl); - nv_wr32(clk, 0x4040, priv->cpost); + nv_wr32(clk, 0x402c, clk->ccoef); + nv_wr32(clk, 0x4028, 0x80000000 | clk->cctrl); + nv_wr32(clk, 0x4040, clk->cpost); pllmask |= (0x3 << 8); mast |= 0x00000003; break; default: - nv_warn(priv,"Reclocking failed: unknown core clock\n"); + nv_warn(clk,"Reclocking failed: unknown core clock\n"); goto resume; } - switch (priv->ssrc) { + switch (clk->ssrc) { case nv_clk_src_href: nv_mask(clk, 0x4020, 0x00070000, 0x00000000); /* mast |= 0x00000000; */ break; case nv_clk_src_core: - nv_mask(clk, 0x4020, 0x00070000, priv->sctrl); + nv_mask(clk, 0x4020, 0x00070000, clk->sctrl); mast |= 0x00000020; break; case nv_clk_src_shader: - nv_wr32(clk, 0x4024, priv->scoef); - nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl); - nv_wr32(clk, 0x4070, priv->spost); + nv_wr32(clk, 0x4024, clk->scoef); + nv_wr32(clk, 0x4020, 0x80000000 | clk->sctrl); + nv_wr32(clk, 0x4070, clk->spost); pllmask |= (0x3 << 12); mast |= 0x00000030; break; default: - nv_warn(priv,"Reclocking failed: unknown sclk clock\n"); + nv_warn(clk,"Reclocking failed: unknown sclk clock\n"); goto resume; } if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { - nv_warn(priv,"Reclocking failed: unstable PLLs\n"); + nv_warn(clk,"Reclocking failed: unstable PLLs\n"); goto resume; } - switch (priv->vsrc) { + switch (clk->vsrc) { case nv_clk_src_cclk: mast |= 0x00400000; default: - nv_wr32(clk, 0x4600, priv->vdiv); + nv_wr32(clk, 0x4600, clk->vdiv); } nv_wr32(clk, 0xc054, mast); resume: /* Disable some PLLs and dividers when unused */ - if (priv->csrc != nv_clk_src_core) { + if (clk->csrc != nv_clk_src_core) { nv_wr32(clk, 0x4040, 0x00000000); nv_mask(clk, 0x4028, 0x80000000, 0x00000000); } - if (priv->ssrc != nv_clk_src_shader) { + if (clk->ssrc != nv_clk_src_shader) { nv_wr32(clk, 0x4070, 0x00000000); nv_mask(clk, 0x4020, 0x80000000, 0x00000000); } @@ -376,12 +375,12 @@ out: if (ret == -EBUSY) f = NULL; - gt215_clk_post(clk, f); + gt215_clk_post(&clk->base, f); return ret; } static void -mcp77_clk_tidy(struct nvkm_clk *clk) +mcp77_clk_tidy(struct nvkm_clk *obj) { } @@ -400,19 +399,19 @@ mcp77_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct mcp77_clk_priv *priv; + struct mcp77_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, mcp77_domains, - NULL, 0, true, &priv); - *pobject = nv_object(priv); + NULL, 0, true, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->base.read = mcp77_clk_read; - priv->base.calc = mcp77_clk_calc; - priv->base.prog = mcp77_clk_prog; - priv->base.tidy = mcp77_clk_tidy; + clk->base.read = mcp77_clk_read; + clk->base.calc = mcp77_clk_calc; + clk->base.prog = mcp77_clk_prog; + clk->base.tidy = mcp77_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c index 63dbbb575228d..3d6c423b81f34 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c @@ -28,10 +28,6 @@ #include #include -struct nv04_clk_priv { - struct nvkm_clk base; -}; - int nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info, int clk, struct nvkm_pll_vals *pv) @@ -77,17 +73,17 @@ nv04_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_clk_priv *priv; + struct nvkm_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, nv04_domain, - NULL, 0, false, &priv); - *pobject = nv_object(priv); + NULL, 0, false, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->base.pll_calc = nv04_clk_pll_calc; - priv->base.pll_prog = nv04_clk_pll_prog; + clk->pll_calc = nv04_clk_pll_calc; + clk->pll_prog = nv04_clk_pll_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index 15668d2883f1f..eb4a8affd0ecc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -27,7 +27,7 @@ #include #include -struct nv40_clk_priv { +struct nv40_clk { struct nvkm_clk base; u32 ctrl; u32 npll_ctrl; @@ -46,53 +46,53 @@ nv40_domain[] = { }; static u32 -read_pll_1(struct nv40_clk_priv *priv, u32 reg) +read_pll_1(struct nv40_clk *clk, u32 reg) { - u32 ctrl = nv_rd32(priv, reg + 0x00); + u32 ctrl = nv_rd32(clk, reg + 0x00); int P = (ctrl & 0x00070000) >> 16; int N = (ctrl & 0x0000ff00) >> 8; int M = (ctrl & 0x000000ff) >> 0; - u32 ref = 27000, clk = 0; + u32 ref = 27000, khz = 0; if (ctrl & 0x80000000) - clk = ref * N / M; + khz = ref * N / M; - return clk >> P; + return khz >> P; } static u32 -read_pll_2(struct nv40_clk_priv *priv, u32 reg) +read_pll_2(struct nv40_clk *clk, u32 reg) { - u32 ctrl = nv_rd32(priv, reg + 0x00); - u32 coef = nv_rd32(priv, reg + 0x04); + u32 ctrl = nv_rd32(clk, reg + 0x00); + u32 coef = nv_rd32(clk, reg + 0x04); int N2 = (coef & 0xff000000) >> 24; int M2 = (coef & 0x00ff0000) >> 16; int N1 = (coef & 0x0000ff00) >> 8; int M1 = (coef & 0x000000ff) >> 0; int P = (ctrl & 0x00070000) >> 16; - u32 ref = 27000, clk = 0; + u32 ref = 27000, khz = 0; if ((ctrl & 0x80000000) && M1) { - clk = ref * N1 / M1; + khz = ref * N1 / M1; if ((ctrl & 0x40000100) == 0x40000000) { if (M2) - clk = clk * N2 / M2; + khz = khz * N2 / M2; else - clk = 0; + khz = 0; } } - return clk >> P; + return khz >> P; } static u32 -read_clk(struct nv40_clk_priv *priv, u32 src) +read_clk(struct nv40_clk *clk, u32 src) { switch (src) { case 3: - return read_pll_2(priv, 0x004000); + return read_pll_2(clk, 0x004000); case 2: - return read_pll_1(priv, 0x004008); + return read_pll_1(clk, 0x004008); default: break; } @@ -101,35 +101,35 @@ read_clk(struct nv40_clk_priv *priv, u32 src) } static int -nv40_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +nv40_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { - struct nv40_clk_priv *priv = (void *)clk; - u32 mast = nv_rd32(priv, 0x00c040); + struct nv40_clk *clk = container_of(obj, typeof(*clk), base); + u32 mast = nv_rd32(clk, 0x00c040); switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; case nv_clk_src_href: return 100000; /*XXX: PCIE/AGP differ*/ case nv_clk_src_core: - return read_clk(priv, (mast & 0x00000003) >> 0); + return read_clk(clk, (mast & 0x00000003) >> 0); case nv_clk_src_shader: - return read_clk(priv, (mast & 0x00000030) >> 4); + return read_clk(clk, (mast & 0x00000030) >> 4); case nv_clk_src_mem: - return read_pll_2(priv, 0x4020); + return read_pll_2(clk, 0x4020); default: break; } - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + nv_debug(clk, "unknown clock source %d 0x%08x\n", src, mast); return -EINVAL; } static int -nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, +nv40_clk_calc_pll(struct nv40_clk *clk, u32 reg, u32 khz, int *N1, int *M1, int *N2, int *M2, int *log2P) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(clk); struct nvbios_pll pll; int ret; @@ -137,10 +137,10 @@ nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, if (ret) return ret; - if (clk < pll.vco1.max_freq) + if (khz < pll.vco1.max_freq) pll.vco2.max_freq = 0; - ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P); + ret = nv04_pll_calc(nv_subdev(clk), &pll, khz, N1, M1, N2, M2, log2P); if (ret == 0) return -ERANGE; @@ -148,60 +148,60 @@ nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk, } static int -nv40_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +nv40_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct nv40_clk_priv *priv = (void *)clk; + struct nv40_clk *clk = container_of(obj, typeof(*clk), base); int gclk = cstate->domain[nv_clk_src_core]; int sclk = cstate->domain[nv_clk_src_shader]; int N1, M1, N2, M2, log2P; int ret; /* core/geometric clock */ - ret = nv40_clk_calc_pll(priv, 0x004000, gclk, + ret = nv40_clk_calc_pll(clk, 0x004000, gclk, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; if (N2 == M2) { - priv->npll_ctrl = 0x80000100 | (log2P << 16); - priv->npll_coef = (N1 << 8) | M1; + clk->npll_ctrl = 0x80000100 | (log2P << 16); + clk->npll_coef = (N1 << 8) | M1; } else { - priv->npll_ctrl = 0xc0000000 | (log2P << 16); - priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; + clk->npll_ctrl = 0xc0000000 | (log2P << 16); + clk->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1; } /* use the second pll for shader/rop clock, if it differs from core */ if (sclk && sclk != gclk) { - ret = nv40_clk_calc_pll(priv, 0x004008, sclk, + ret = nv40_clk_calc_pll(clk, 0x004008, sclk, &N1, &M1, NULL, NULL, &log2P); if (ret < 0) return ret; - priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; - priv->ctrl = 0x00000223; + clk->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1; + clk->ctrl = 0x00000223; } else { - priv->spll = 0x00000000; - priv->ctrl = 0x00000333; + clk->spll = 0x00000000; + clk->ctrl = 0x00000333; } return 0; } static int -nv40_clk_prog(struct nvkm_clk *clk) +nv40_clk_prog(struct nvkm_clk *obj) { - struct nv40_clk_priv *priv = (void *)clk; - nv_mask(priv, 0x00c040, 0x00000333, 0x00000000); - nv_wr32(priv, 0x004004, priv->npll_coef); - nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl); - nv_mask(priv, 0x004008, 0xc007ffff, priv->spll); + struct nv40_clk *clk = container_of(obj, typeof(*clk), base); + nv_mask(clk, 0x00c040, 0x00000333, 0x00000000); + nv_wr32(clk, 0x004004, clk->npll_coef); + nv_mask(clk, 0x004000, 0xc0070100, clk->npll_ctrl); + nv_mask(clk, 0x004008, 0xc007ffff, clk->spll); mdelay(5); - nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl); + nv_mask(clk, 0x00c040, 0x00000333, clk->ctrl); return 0; } static void -nv40_clk_tidy(struct nvkm_clk *clk) +nv40_clk_tidy(struct nvkm_clk *obj) { } @@ -210,21 +210,21 @@ nv40_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv40_clk_priv *priv; + struct nv40_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, nv40_domain, - NULL, 0, true, &priv); - *pobject = nv_object(priv); + NULL, 0, true, &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->base.pll_calc = nv04_clk_pll_calc; - priv->base.pll_prog = nv04_clk_pll_prog; - priv->base.read = nv40_clk_read; - priv->base.calc = nv40_clk_calc; - priv->base.prog = nv40_clk_prog; - priv->base.tidy = nv40_clk_tidy; + clk->base.pll_calc = nv04_clk_pll_calc; + clk->base.pll_prog = nv04_clk_pll_prog; + clk->base.read = nv40_clk_read; + clk->base.calc = nv40_clk_calc; + clk->base.prog = nv40_clk_prog; + clk->base.tidy = nv40_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index b58f4786e4076..2b44ff4449094 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -29,33 +29,32 @@ #include static u32 -read_div(struct nv50_clk_priv *priv) +read_div(struct nv50_clk *clk) { - switch (nv_device(priv)->chipset) { + switch (nv_device(clk)->chipset) { case 0x50: /* it exists, but only has bit 31, not the dividers.. */ case 0x84: case 0x86: case 0x98: case 0xa0: - return nv_rd32(priv, 0x004700); + return nv_rd32(clk, 0x004700); case 0x92: case 0x94: case 0x96: - return nv_rd32(priv, 0x004800); + return nv_rd32(clk, 0x004800); default: return 0x00000000; } } static u32 -read_pll_src(struct nv50_clk_priv *priv, u32 base) +read_pll_src(struct nv50_clk *clk, u32 base) { - struct nvkm_clk *clk = &priv->base; - u32 coef, ref = clk->read(clk, nv_clk_src_crystal); - u32 rsel = nv_rd32(priv, 0x00e18c); + u32 coef, ref = clk->base.read(&clk->base, nv_clk_src_crystal); + u32 rsel = nv_rd32(clk, 0x00e18c); int P, N, M, id; - switch (nv_device(priv)->chipset) { + switch (nv_device(clk)->chipset) { case 0x50: case 0xa0: switch (base) { @@ -64,11 +63,11 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) case 0x4008: id = !!(rsel & 0x00000008); break; case 0x4030: id = 0; break; default: - nv_error(priv, "ref: bad pll 0x%06x\n", base); + nv_error(clk, "ref: bad pll 0x%06x\n", base); return 0; } - coef = nv_rd32(priv, 0x00e81c + (id * 0x0c)); + coef = nv_rd32(clk, 0x00e81c + (id * 0x0c)); ref *= (coef & 0x01000000) ? 2 : 4; P = (coef & 0x00070000) >> 16; N = ((coef & 0x0000ff00) >> 8) + 1; @@ -77,7 +76,7 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) case 0x84: case 0x86: case 0x92: - coef = nv_rd32(priv, 0x00e81c); + coef = nv_rd32(clk, 0x00e81c); P = (coef & 0x00070000) >> 16; N = (coef & 0x0000ff00) >> 8; M = (coef & 0x000000ff) >> 0; @@ -85,26 +84,26 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) case 0x94: case 0x96: case 0x98: - rsel = nv_rd32(priv, 0x00c050); + rsel = nv_rd32(clk, 0x00c050); switch (base) { case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; case 0x4030: rsel = 3; break; default: - nv_error(priv, "ref: bad pll 0x%06x\n", base); + nv_error(clk, "ref: bad pll 0x%06x\n", base); return 0; } switch (rsel) { case 0: id = 1; break; - case 1: return clk->read(clk, nv_clk_src_crystal); - case 2: return clk->read(clk, nv_clk_src_href); + case 1: return clk->base.read(&clk->base, nv_clk_src_crystal); + case 2: return clk->base.read(&clk->base, nv_clk_src_href); case 3: id = 0; break; } - coef = nv_rd32(priv, 0x00e81c + (id * 0x28)); - P = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7; + coef = nv_rd32(clk, 0x00e81c + (id * 0x28)); + P = (nv_rd32(clk, 0x00e824 + (id * 0x28)) >> 16) & 7; P += (coef & 0x00070000) >> 16; N = (coef & 0x0000ff00) >> 8; M = (coef & 0x000000ff) >> 0; @@ -120,10 +119,9 @@ read_pll_src(struct nv50_clk_priv *priv, u32 base) } static u32 -read_pll_ref(struct nv50_clk_priv *priv, u32 base) +read_pll_ref(struct nv50_clk *clk, u32 base) { - struct nvkm_clk *clk = &priv->base; - u32 src, mast = nv_rd32(priv, 0x00c040); + u32 src, mast = nv_rd32(clk, 0x00c040); switch (base) { case 0x004028: @@ -139,33 +137,32 @@ read_pll_ref(struct nv50_clk_priv *priv, u32 base) src = !!(mast & 0x02000000); break; case 0x00e810: - return clk->read(clk, nv_clk_src_crystal); + return clk->base.read(&clk->base, nv_clk_src_crystal); default: - nv_error(priv, "bad pll 0x%06x\n", base); + nv_error(clk, "bad pll 0x%06x\n", base); return 0; } if (src) - return clk->read(clk, nv_clk_src_href); + return clk->base.read(&clk->base, nv_clk_src_href); - return read_pll_src(priv, base); + return read_pll_src(clk, base); } static u32 -read_pll(struct nv50_clk_priv *priv, u32 base) +read_pll(struct nv50_clk *clk, u32 base) { - struct nvkm_clk *clk = &priv->base; - u32 mast = nv_rd32(priv, 0x00c040); - u32 ctrl = nv_rd32(priv, base + 0); - u32 coef = nv_rd32(priv, base + 4); - u32 ref = read_pll_ref(priv, base); + u32 mast = nv_rd32(clk, 0x00c040); + u32 ctrl = nv_rd32(clk, base + 0); + u32 coef = nv_rd32(clk, base + 4); + u32 ref = read_pll_ref(clk, base); u32 freq = 0; int N1, N2, M1, M2; if (base == 0x004028 && (mast & 0x00100000)) { /* wtf, appears to only disable post-divider on gt200 */ - if (nv_device(priv)->chipset != 0xa0) - return clk->read(clk, nv_clk_src_dom6); + if (nv_device(clk)->chipset != 0xa0) + return clk->base.read(&clk->base, nv_clk_src_dom6); } N2 = (coef & 0xff000000) >> 24; @@ -186,70 +183,70 @@ read_pll(struct nv50_clk_priv *priv, u32 base) } static int -nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) +nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { - struct nv50_clk_priv *priv = (void *)clk; - u32 mast = nv_rd32(priv, 0x00c040); + struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + u32 mast = nv_rd32(clk, 0x00c040); u32 P = 0; switch (src) { case nv_clk_src_crystal: - return nv_device(priv)->crystal; + return nv_device(clk)->crystal; case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclk: - return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000); + return div_u64((u64)clk->base.read(&clk->base, nv_clk_src_href) * 27778, 10000); case nv_clk_src_hclkm3: - return clk->read(clk, nv_clk_src_hclk) * 3; + return clk->base.read(&clk->base, nv_clk_src_hclk) * 3; case nv_clk_src_hclkm3d2: - return clk->read(clk, nv_clk_src_hclk) * 3 / 2; + return clk->base.read(&clk->base, nv_clk_src_hclk) * 3 / 2; case nv_clk_src_host: switch (mast & 0x30000000) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_href); case 0x10000000: break; case 0x20000000: /* !0x50 */ - case 0x30000000: return clk->read(clk, nv_clk_src_hclk); + case 0x30000000: return clk->base.read(&clk->base, nv_clk_src_hclk); } break; case nv_clk_src_core: if (!(mast & 0x00100000)) - P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16; + P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { - case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P; - case 0x00000001: return clk->read(clk, nv_clk_src_dom6); - case 0x00000002: return read_pll(priv, 0x004020) >> P; - case 0x00000003: return read_pll(priv, 0x004028) >> P; + case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; + case 0x00000001: return clk->base.read(&clk->base, nv_clk_src_dom6); + case 0x00000002: return read_pll(clk, 0x004020) >> P; + case 0x00000003: return read_pll(clk, 0x004028) >> P; } break; case nv_clk_src_shader: - P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16; + P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000080) - return clk->read(clk, nv_clk_src_host) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; + return clk->base.read(&clk->base, nv_clk_src_host) >> P; + return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000010: break; - case 0x00000020: return read_pll(priv, 0x004028) >> P; - case 0x00000030: return read_pll(priv, 0x004020) >> P; + case 0x00000020: return read_pll(clk, 0x004028) >> P; + case 0x00000030: return read_pll(clk, 0x004020) >> P; } break; case nv_clk_src_mem: - P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16; - if (nv_rd32(priv, 0x004008) & 0x00000200) { + P = (nv_rd32(clk, 0x004008) & 0x00070000) >> 16; + if (nv_rd32(clk, 0x004008) & 0x00000200) { switch (mast & 0x0000c000) { case 0x00000000: - return clk->read(clk, nv_clk_src_crystal) >> P; + return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00008000: case 0x0000c000: - return clk->read(clk, nv_clk_src_href) >> P; + return clk->base.read(&clk->base, nv_clk_src_href) >> P; } } else { - return read_pll(priv, 0x004008) >> P; + return read_pll(clk, 0x004008) >> P; } break; case nv_clk_src_vdec: - P = (read_div(priv) & 0x00000700) >> 8; - switch (nv_device(priv)->chipset) { + P = (read_div(clk) & 0x00000700) >> 8; + switch (nv_device(clk)->chipset) { case 0x84: case 0x86: case 0x92: @@ -258,51 +255,51 @@ nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) case 0xa0: switch (mast & 0x00000c00) { case 0x00000000: - if (nv_device(priv)->chipset == 0xa0) /* wtf?? */ - return clk->read(clk, nv_clk_src_core) >> P; - return clk->read(clk, nv_clk_src_crystal) >> P; + if (nv_device(clk)->chipset == 0xa0) /* wtf?? */ + return clk->base.read(&clk->base, nv_clk_src_core) >> P; + return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000400: return 0; case 0x00000800: if (mast & 0x01000000) - return read_pll(priv, 0x004028) >> P; - return read_pll(priv, 0x004030) >> P; + return read_pll(clk, 0x004028) >> P; + return read_pll(clk, 0x004030) >> P; case 0x00000c00: - return clk->read(clk, nv_clk_src_core) >> P; + return clk->base.read(&clk->base, nv_clk_src_core) >> P; } break; case 0x98: switch (mast & 0x00000c00) { case 0x00000000: - return clk->read(clk, nv_clk_src_core) >> P; + return clk->base.read(&clk->base, nv_clk_src_core) >> P; case 0x00000400: return 0; case 0x00000800: - return clk->read(clk, nv_clk_src_hclkm3d2) >> P; + return clk->base.read(&clk->base, nv_clk_src_hclkm3d2) >> P; case 0x00000c00: - return clk->read(clk, nv_clk_src_mem) >> P; + return clk->base.read(&clk->base, nv_clk_src_mem) >> P; } break; } break; case nv_clk_src_dom6: - switch (nv_device(priv)->chipset) { + switch (nv_device(clk)->chipset) { case 0x50: case 0xa0: - return read_pll(priv, 0x00e810) >> 2; + return read_pll(clk, 0x00e810) >> 2; case 0x84: case 0x86: case 0x92: case 0x94: case 0x96: case 0x98: - P = (read_div(priv) & 0x00000007) >> 0; + P = (read_div(clk) & 0x00000007) >> 0; switch (mast & 0x0c000000) { - case 0x00000000: return clk->read(clk, nv_clk_src_href); + case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_href); case 0x04000000: break; - case 0x08000000: return clk->read(clk, nv_clk_src_hclk); + case 0x08000000: return clk->base.read(&clk->base, nv_clk_src_hclk); case 0x0c000000: - return clk->read(clk, nv_clk_src_hclkm3) >> P; + return clk->base.read(&clk->base, nv_clk_src_hclkm3) >> P; } break; default: @@ -312,14 +309,14 @@ nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) break; } - nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast); + nv_debug(clk, "unknown clock source %d 0x%08x\n", src, mast); return -EINVAL; } static u32 -calc_pll(struct nv50_clk_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P) +calc_pll(struct nv50_clk *clk, u32 reg, u32 idx, int *N, int *M, int *P) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(clk); struct nvbios_pll pll; int ret; @@ -328,11 +325,11 @@ calc_pll(struct nv50_clk_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P) return 0; pll.vco2.max_freq = 0; - pll.refclk = read_pll_ref(priv, reg); + pll.refclk = read_pll_ref(clk, reg); if (!pll.refclk) return 0; - return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P); + return nv04_pll_calc(nv_subdev(clk), &pll, idx, N, M, NULL, NULL, P); } static inline u32 @@ -360,10 +357,10 @@ clk_same(u32 a, u32 b) } static int -nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) +nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) { - struct nv50_clk_priv *priv = (void *)clk; - struct nv50_clk_hwsq *hwsq = &priv->hwsq; + struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + struct nv50_clk_hwsq *hwsq = &clk->hwsq; const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; @@ -392,15 +389,15 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) freq = calc_div(core, vdec, &P1); /* see how close we can get using xpll/hclk as a source */ - if (nv_device(priv)->chipset != 0x98) - out = read_pll(priv, 0x004030); + if (nv_device(clk)->chipset != 0x98) + out = read_pll(clk, 0x004030); else - out = clk->read(clk, nv_clk_src_hclkm3d2); + out = clk->base.read(&clk->base, nv_clk_src_hclkm3d2); out = calc_div(out, vdec, &P2); /* select whichever gets us closest */ if (abs(vdec - freq) <= abs(vdec - out)) { - if (nv_device(priv)->chipset != 0x98) + if (nv_device(clk)->chipset != 0x98) mastv |= 0x00000c00; divsv |= P1 << 8; } else { @@ -416,14 +413,14 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) * of the host clock frequency */ if (dom6) { - if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) { + if (clk_same(dom6, clk->base.read(&clk->base, nv_clk_src_href))) { mastv |= 0x00000000; } else - if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) { + if (clk_same(dom6, clk->base.read(&clk->base, nv_clk_src_hclk))) { mastv |= 0x08000000; } else { - freq = clk->read(clk, nv_clk_src_hclk) * 3; - freq = calc_div(freq, dom6, &P1); + freq = clk->base.read(&clk->base, nv_clk_src_hclk) * 3; + calc_div(freq, dom6, &P1); mastv |= 0x0c000000; divsv |= P1; @@ -443,13 +440,13 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6, * sclk to hclk) before reprogramming */ - if (nv_device(priv)->chipset < 0x92) + if (nv_device(clk)->chipset < 0x92) clk_mask(hwsq, mast, 0x001000b0, 0x00100080); else clk_mask(hwsq, mast, 0x000000b3, 0x00000081); /* core: for the moment at least, always use nvpll */ - freq = calc_pll(priv, 0x4028, core, &N, &M, &P1); + freq = calc_pll(clk, 0x4028, core, &N, &M, &P1); if (freq == 0) return -ERANGE; @@ -467,7 +464,7 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16)); clk_mask(hwsq, mast, 0x00100033, 0x00000023); } else { - freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1); + freq = calc_pll(clk, 0x4020, shader, &N, &M, &P1); if (freq == 0) return -ERANGE; @@ -485,17 +482,17 @@ nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate) } static int -nv50_clk_prog(struct nvkm_clk *clk) +nv50_clk_prog(struct nvkm_clk *obj) { - struct nv50_clk_priv *priv = (void *)clk; - return clk_exec(&priv->hwsq, true); + struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + return clk_exec(&clk->hwsq, true); } static void -nv50_clk_tidy(struct nvkm_clk *clk) +nv50_clk_tidy(struct nvkm_clk *obj) { - struct nv50_clk_priv *priv = (void *)clk; - clk_exec(&priv->hwsq, false); + struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + clk_exec(&clk->hwsq, false); } int @@ -504,37 +501,37 @@ nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv50_clk_oclass *pclass = (void *)oclass; - struct nv50_clk_priv *priv; + struct nv50_clk *clk; int ret; ret = nvkm_clk_create(parent, engine, oclass, pclass->domains, NULL, 0, nv_device(parent)->chipset == 0xa0, - &priv); - *pobject = nv_object(priv); + &clk); + *pobject = nv_object(clk); if (ret) return ret; - priv->hwsq.r_fifo = hwsq_reg(0x002504); - priv->hwsq.r_spll[0] = hwsq_reg(0x004020); - priv->hwsq.r_spll[1] = hwsq_reg(0x004024); - priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028); - priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c); - switch (nv_device(priv)->chipset) { + clk->hwsq.r_fifo = hwsq_reg(0x002504); + clk->hwsq.r_spll[0] = hwsq_reg(0x004020); + clk->hwsq.r_spll[1] = hwsq_reg(0x004024); + clk->hwsq.r_nvpll[0] = hwsq_reg(0x004028); + clk->hwsq.r_nvpll[1] = hwsq_reg(0x00402c); + switch (nv_device(clk)->chipset) { case 0x92: case 0x94: case 0x96: - priv->hwsq.r_divs = hwsq_reg(0x004800); + clk->hwsq.r_divs = hwsq_reg(0x004800); break; default: - priv->hwsq.r_divs = hwsq_reg(0x004700); + clk->hwsq.r_divs = hwsq_reg(0x004700); break; } - priv->hwsq.r_mast = hwsq_reg(0x00c040); + clk->hwsq.r_mast = hwsq_reg(0x00c040); - priv->base.read = nv50_clk_read; - priv->base.calc = nv50_clk_calc; - priv->base.prog = nv50_clk_prog; - priv->base.tidy = nv50_clk_tidy; + clk->base.read = nv50_clk_read; + clk->base.calc = nv50_clk_calc; + clk->base.prog = nv50_clk_prog; + clk->base.tidy = nv50_clk_tidy; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h index 0ead76a32f109..7432b9f921ea6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h @@ -12,7 +12,7 @@ struct nv50_clk_hwsq { struct hwsq_reg r_mast; }; -struct nv50_clk_priv { +struct nv50_clk { struct nvkm_clk base; struct nv50_clk_hwsq hwsq; }; -- GitLab From 266f8b5ee6e98979f3251efc81451a2a2cbf2a28 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5326/7006] drm/nouveau/devinit: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/devinit.h | 2 +- .../drm/nouveau/nvkm/subdev/devinit/base.c | 34 ++++---- .../gpu/drm/nouveau/nvkm/subdev/devinit/g84.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/devinit/g98.c | 6 +- .../drm/nouveau/nvkm/subdev/devinit/gf100.c | 26 +++--- .../drm/nouveau/nvkm/subdev/devinit/gm107.c | 6 +- .../drm/nouveau/nvkm/subdev/devinit/gm204.c | 84 +++++++++---------- .../drm/nouveau/nvkm/subdev/devinit/gt215.c | 28 +++---- .../drm/nouveau/nvkm/subdev/devinit/mcp89.c | 6 +- .../drm/nouveau/nvkm/subdev/devinit/nv04.c | 80 +++++++++--------- .../drm/nouveau/nvkm/subdev/devinit/nv04.h | 2 +- .../drm/nouveau/nvkm/subdev/devinit/nv05.c | 38 ++++----- .../drm/nouveau/nvkm/subdev/devinit/nv10.c | 18 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv20.c | 18 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 54 ++++++------ .../drm/nouveau/nvkm/subdev/devinit/nv50.h | 2 +- 16 files changed, 205 insertions(+), 205 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h index d1bbe0d62b35b..856ff5064dd3b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h @@ -3,7 +3,7 @@ #include struct nvkm_devinit { - struct nvkm_subdev base; + struct nvkm_subdev subdev; bool post; void (*meminit)(struct nvkm_devinit *); int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index 5cc7dd24a2135..4338e437bcc39 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -29,47 +29,47 @@ int _nvkm_devinit_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_devinit *devinit = (void *)object; + struct nvkm_devinit *init = (void *)object; /* force full reinit on resume */ if (suspend) - devinit->post = true; + init->post = true; /* unlock the extended vga crtc regs */ - nv_lockvgac(devinit, false); + nv_lockvgac(init, false); - return nvkm_subdev_fini(&devinit->base, suspend); + return nvkm_subdev_fini(&init->subdev, suspend); } int _nvkm_devinit_init(struct nvkm_object *object) { struct nvkm_devinit_impl *impl = (void *)object->oclass; - struct nvkm_devinit *devinit = (void *)object; + struct nvkm_devinit *init = (void *)object; int ret; - ret = nvkm_subdev_init(&devinit->base); + ret = nvkm_subdev_init(&init->subdev); if (ret) return ret; - ret = impl->post(&devinit->base, devinit->post); + ret = impl->post(&init->subdev, init->post); if (ret) return ret; if (impl->disable) - nv_device(devinit)->disable_mask |= impl->disable(devinit); + nv_device(init)->disable_mask |= impl->disable(init); return 0; } void _nvkm_devinit_dtor(struct nvkm_object *object) { - struct nvkm_devinit *devinit = (void *)object; + struct nvkm_devinit *init = (void *)object; /* lock crtc regs */ - nv_lockvgac(devinit, true); + nv_lockvgac(init, true); - nvkm_subdev_destroy(&devinit->base); + nvkm_subdev_destroy(&init->subdev); } int @@ -78,18 +78,18 @@ nvkm_devinit_create_(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_devinit_impl *impl = (void *)oclass; struct nvkm_device *device = nv_device(parent); - struct nvkm_devinit *devinit; + struct nvkm_devinit *init; int ret; ret = nvkm_subdev_create_(parent, engine, oclass, 0, "DEVINIT", "init", size, pobject); - devinit = *pobject; + init = *pobject; if (ret) return ret; - devinit->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); - devinit->meminit = impl->meminit; - devinit->pll_set = impl->pll_set; - devinit->mmio = impl->mmio; + init->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); + init->meminit = impl->meminit; + init->pll_set = impl->pll_set; + init->mmio = impl->mmio; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c index ca776ce75f4f1..69f28feda861e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c @@ -29,9 +29,9 @@ static u64 g84_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nv50_devinit *init = (void *)devinit; + u32 r001540 = nv_rd32(init, 0x001540); + u32 r00154c = nv_rd32(init, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c index d29bacee65ee4..06a269c0ac057 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c @@ -29,9 +29,9 @@ static u64 g98_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nv50_devinit *init = (void *)devinit; + u32 r001540 = nv_rd32(init, 0x001540); + u32 r00154c = nv_rd32(init, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index c61102f708055..b6eb2540fcbd1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -31,8 +31,8 @@ int gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) { - struct nv50_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nv50_devinit *init = (void *)devinit; + struct nvkm_bios *bios = nvkm_bios(init); struct nvbios_pll info; int N, fN, M, P; int ret; @@ -50,12 +50,12 @@ gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) case PLL_VPLL1: case PLL_VPLL2: case PLL_VPLL3: - nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100); - nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M); - nv_wr32(priv, info.reg + 0x10, fN << 16); + nv_mask(init, info.reg + 0x0c, 0x00000000, 0x00000100); + nv_wr32(init, info.reg + 0x04, (P << 16) | (N << 8) | M); + nv_wr32(init, info.reg + 0x10, fN << 16); break; default: - nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); + nv_warn(init, "0x%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } @@ -66,8 +66,8 @@ gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) static u64 gf100_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r022500 = nv_rd32(priv, 0x022500); + struct nv50_devinit *init = (void *)devinit; + u32 r022500 = nv_rd32(init, 0x022500); u64 disable = 0ULL; if (r022500 & 0x00000001) @@ -96,18 +96,18 @@ gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_devinit_impl *impl = (void *)oclass; - struct nv50_devinit_priv *priv; + struct nv50_devinit *init; u64 disable; int ret; - ret = nvkm_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_devinit_create(parent, engine, oclass, &init); + *pobject = nv_object(init); if (ret) return ret; - disable = impl->disable(&priv->base); + disable = impl->disable(&init->base); if (disable & (1ULL << NVDEV_ENGINE_DISP)) - priv->base.post = true; + init->base.post = true; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c index 87ca0ece37b42..16150177f6c6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c @@ -29,9 +29,9 @@ u64 gm107_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r021c00 = nv_rd32(priv, 0x021c00); - u32 r021c04 = nv_rd32(priv, 0x021c04); + struct nv50_devinit *init = (void *)devinit; + u32 r021c00 = nv_rd32(init, 0x021c00); + u32 r021c04 = nv_rd32(init, 0x021c04); u64 disable = 0ULL; if (r021c00 & 0x00000001) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c index 1076fcf0d7161..3c513be9817fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c @@ -28,69 +28,69 @@ #include static void -pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec) +pmu_code(struct nv50_devinit *init, u32 pmu, u32 img, u32 len, bool sec) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(init); int i; - nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu); + nv_wr32(init, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu); for (i = 0; i < len; i += 4) { if ((i & 0xff) == 0) - nv_wr32(priv, 0x10a188, (pmu + i) >> 8); - nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i)); + nv_wr32(init, 0x10a188, (pmu + i) >> 8); + nv_wr32(init, 0x10a184, nv_ro32(bios, img + i)); } while (i & 0xff) { - nv_wr32(priv, 0x10a184, 0x00000000); + nv_wr32(init, 0x10a184, 0x00000000); i += 4; } } static void -pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len) +pmu_data(struct nv50_devinit *init, u32 pmu, u32 img, u32 len) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(init); int i; - nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu); + nv_wr32(init, 0x10a1c0, 0x01000000 | pmu); for (i = 0; i < len; i += 4) - nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i)); + nv_wr32(init, 0x10a1c4, nv_ro32(bios, img + i)); } static u32 -pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi) +pmu_args(struct nv50_devinit *init, u32 argp, u32 argi) { - nv_wr32(priv, 0x10a1c0, argp); - nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi); - return nv_rd32(priv, 0x10a1c4); + nv_wr32(init, 0x10a1c0, argp); + nv_wr32(init, 0x10a1c0, nv_rd32(init, 0x10a1c4) + argi); + return nv_rd32(init, 0x10a1c4); } static void -pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr) +pmu_exec(struct nv50_devinit *init, u32 init_addr) { - nv_wr32(priv, 0x10a104, init_addr); - nv_wr32(priv, 0x10a10c, 0x00000000); - nv_wr32(priv, 0x10a100, 0x00000002); + nv_wr32(init, 0x10a104, init_addr); + nv_wr32(init, 0x10a10c, 0x00000000); + nv_wr32(init, 0x10a100, 0x00000002); } static int -pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post, +pmu_load(struct nv50_devinit *init, u8 type, bool post, u32 *init_addr_pmu, u32 *args_addr_pmu) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(init); struct nvbios_pmuR pmu; if (!nvbios_pmuRm(bios, type, &pmu)) { - nv_error(priv, "VBIOS PMU fuc %02x not found\n", type); + nv_error(init, "VBIOS PMU fuc %02x not found\n", type); return -EINVAL; } if (!post) return 0; - pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false); - pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true); - pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size); + pmu_code(init, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false); + pmu_code(init, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true); + pmu_data(init, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size); if (init_addr_pmu) { *init_addr_pmu = pmu.init_addr_pmu; @@ -98,63 +98,63 @@ pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post, return 0; } - return pmu_exec(priv, pmu.init_addr_pmu), 0; + return pmu_exec(init, pmu.init_addr_pmu), 0; } static int gm204_devinit_post(struct nvkm_subdev *subdev, bool post) { - struct nv50_devinit_priv *priv = (void *)nvkm_devinit(subdev); - struct nvkm_bios *bios = nvkm_bios(priv); + struct nv50_devinit *init = (void *)nvkm_devinit(subdev); + struct nvkm_bios *bios = nvkm_bios(init); struct bit_entry bit_I; - u32 init, args; + u32 exec, args; int ret; if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 || bit_I.length < 0x1c) { - nv_error(priv, "VBIOS PMU init data not found\n"); + nv_error(init, "VBIOS PMU init data not found\n"); return -EINVAL; } /* reset PMU and load init table parser ucode */ if (post) { - nv_mask(priv, 0x000200, 0x00002000, 0x00000000); - nv_mask(priv, 0x000200, 0x00002000, 0x00002000); - nv_rd32(priv, 0x000200); - while (nv_rd32(priv, 0x10a10c) & 0x00000006) { + nv_mask(init, 0x000200, 0x00002000, 0x00000000); + nv_mask(init, 0x000200, 0x00002000, 0x00002000); + nv_rd32(init, 0x000200); + while (nv_rd32(init, 0x10a10c) & 0x00000006) { } } - ret = pmu_load(priv, 0x04, post, &init, &args); + ret = pmu_load(init, 0x04, post, &exec, &args); if (ret) return ret; /* upload first chunk of init data */ if (post) { - u32 pmu = pmu_args(priv, args + 0x08, 0x08); + u32 pmu = pmu_args(init, args + 0x08, 0x08); u32 img = nv_ro16(bios, bit_I.offset + 0x14); u32 len = nv_ro16(bios, bit_I.offset + 0x16); - pmu_data(priv, pmu, img, len); + pmu_data(init, pmu, img, len); } /* upload second chunk of init data */ if (post) { - u32 pmu = pmu_args(priv, args + 0x08, 0x10); + u32 pmu = pmu_args(init, args + 0x08, 0x10); u32 img = nv_ro16(bios, bit_I.offset + 0x18); u32 len = nv_ro16(bios, bit_I.offset + 0x1a); - pmu_data(priv, pmu, img, len); + pmu_data(init, pmu, img, len); } /* execute init tables */ if (post) { - nv_wr32(priv, 0x10a040, 0x00005000); - pmu_exec(priv, init); - while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) { + nv_wr32(init, 0x10a040, 0x00005000); + pmu_exec(init, exec); + while (!(nv_rd32(init, 0x10a040) & 0x00002000)) { } } /* load and execute some other ucode image (bios therm?) */ - return pmu_load(priv, 0x01, post, NULL, NULL); + return pmu_load(init, 0x01, post, NULL, NULL); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c index 6a3e8d4efed7d..ffe3828c23c8c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c @@ -31,8 +31,8 @@ int gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) { - struct nv50_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nv50_devinit *init = (void *)devinit; + struct nvkm_bios *bios = nvkm_bios(init); struct nvbios_pll info; int N, fN, M, P; int ret; @@ -48,13 +48,13 @@ gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: - nv_wr32(priv, info.reg + 0, 0x50000610); - nv_mask(priv, info.reg + 4, 0x003fffff, + nv_wr32(init, info.reg + 0, 0x50000610); + nv_mask(init, info.reg + 4, 0x003fffff, (P << 16) | (M << 8) | N); - nv_wr32(priv, info.reg + 8, fN); + nv_wr32(init, info.reg + 8, fN); break; default: - nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq); + nv_warn(init, "0x%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } @@ -65,9 +65,9 @@ gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) static u64 gt215_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nv50_devinit *init = (void *)devinit; + u32 r001540 = nv_rd32(init, 0x001540); + u32 r00154c = nv_rd32(init, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { @@ -101,7 +101,7 @@ gt215_devinit_mmio_part[] = { static u32 gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) { - struct nv50_devinit_priv *priv = (void *)devinit; + struct nv50_devinit *init = (void *)devinit; u32 *mmio = gt215_devinit_mmio_part; /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP @@ -113,7 +113,7 @@ gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) * * the binary driver avoids touching these registers at all, however, * the video bios doesn't care and does what the scripts say. it's - * presumed that the io-port access to priv registers isn't effected + * presumed that the io-port access to init registers isn't effected * by the screw-up bug mentioned above. * * really, a new opcode should've been invented to handle these @@ -122,9 +122,9 @@ gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) while (mmio[0]) { if (addr >= mmio[0] && addr <= mmio[1]) { u32 part = (addr / mmio[2]) & 7; - if (!priv->r001540) - priv->r001540 = nv_rd32(priv, 0x001540); - if (part >= hweight8((priv->r001540 >> 16) & 0xff)) + if (!init->r001540) + init->r001540 = nv_rd32(init, 0x001540); + if (part >= hweight8((init->r001540 >> 16) & 0xff)) return ~0; return addr; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c index 55cf48bbca1c1..27085758b67b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c @@ -29,9 +29,9 @@ static u64 mcp89_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); - u32 r00154c = nv_rd32(priv, 0x00154c); + struct nv50_devinit *init = (void *)devinit; + u32 r001540 = nv_rd32(init, 0x001540); + u32 r00154c = nv_rd32(init, 0x00154c); u64 disable = 0; if (!(r001540 & 0x40000000)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 03a0da8342440..28cb38160ce1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -35,23 +35,23 @@ static void nv04_devinit_meminit(struct nvkm_devinit *devinit) { - struct nv04_devinit_priv *priv = (void *)devinit; + struct nv04_devinit *init = (void *)devinit; u32 patt = 0xdeadbeef; struct io_mapping *fb; int i; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(nv_device(init)); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nv_error(init, "failed to map fb\n"); return; } /* Sequencer and refresh off */ - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); - nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); + nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) | 0x20); + nv_mask(init, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); - nv_mask(priv, NV04_PFB_BOOT_0, ~0, + nv_mask(init, NV04_PFB_BOOT_0, ~0, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB | NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT); @@ -62,49 +62,49 @@ nv04_devinit_meminit(struct nvkm_devinit *devinit) fbmem_poke(fb, 0x400000, patt + 1); if (fbmem_peek(fb, 0) == patt + 1) { - nv_mask(priv, NV04_PFB_BOOT_0, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT); - nv_mask(priv, NV04_PFB_DEBUG_0, + nv_mask(init, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff)) - nv_mask(priv, NV04_PFB_BOOT_0, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); } else if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) { - nv_mask(priv, NV04_PFB_BOOT_0, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); } else if (fbmem_peek(fb, 0) != patt) { if (fbmem_readback(fb, 0x800000, patt)) - nv_mask(priv, NV04_PFB_BOOT_0, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); else - nv_mask(priv, NV04_PFB_BOOT_0, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT); } else if (!fbmem_readback(fb, 0x800000, patt)) { - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); } /* Refresh on, sequencer on */ - nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); + nv_mask(init, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) & ~0x20); fbmem_fini(fb); } @@ -390,52 +390,52 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) int nv04_devinit_fini(struct nvkm_object *object, bool suspend) { - struct nv04_devinit_priv *priv = (void *)object; + struct nv04_devinit *init = (void *)object; int ret; /* make i2c busses accessible */ - nv_mask(priv, 0x000200, 0x00000001, 0x00000001); + nv_mask(init, 0x000200, 0x00000001, 0x00000001); - ret = nvkm_devinit_fini(&priv->base, suspend); + ret = nvkm_devinit_fini(&init->base, suspend); if (ret) return ret; /* unslave crtcs */ - if (priv->owner < 0) - priv->owner = nv_rdvgaowner(priv); - nv_wrvgaowner(priv, 0); + if (init->owner < 0) + init->owner = nv_rdvgaowner(init); + nv_wrvgaowner(init, 0); return 0; } int nv04_devinit_init(struct nvkm_object *object) { - struct nv04_devinit_priv *priv = (void *)object; - - if (!priv->base.post) { - u32 htotal = nv_rdvgac(priv, 0, 0x06); - htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8; - htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4; - htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10; - htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11; + struct nv04_devinit *init = (void *)object; + + if (!init->base.post) { + u32 htotal = nv_rdvgac(init, 0, 0x06); + htotal |= (nv_rdvgac(init, 0, 0x07) & 0x01) << 8; + htotal |= (nv_rdvgac(init, 0, 0x07) & 0x20) << 4; + htotal |= (nv_rdvgac(init, 0, 0x25) & 0x01) << 10; + htotal |= (nv_rdvgac(init, 0, 0x41) & 0x01) << 11; if (!htotal) { - nv_info(priv, "adaptor not initialised\n"); - priv->base.post = true; + nv_info(init, "adaptor not initialised\n"); + init->base.post = true; } } - return nvkm_devinit_init(&priv->base); + return nvkm_devinit_init(&init->base); } void nv04_devinit_dtor(struct nvkm_object *object) { - struct nv04_devinit_priv *priv = (void *)object; + struct nv04_devinit *init = (void *)object; /* restore vga owner saved at first init */ - nv_wrvgaowner(priv, priv->owner); + nv_wrvgaowner(init, init->owner); - nvkm_devinit_destroy(&priv->base); + nvkm_devinit_destroy(&init->base); } int @@ -443,15 +443,15 @@ nv04_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_devinit_priv *priv; + struct nv04_devinit *init; int ret; - ret = nvkm_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_devinit_create(parent, engine, oclass, &init); + *pobject = nv_object(init); if (ret) return ret; - priv->owner = -1; + init->owner = -1; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h index 7c63abf11e226..abf6748c072ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h @@ -3,7 +3,7 @@ #include "priv.h" struct nvkm_pll_vals; -struct nv04_devinit_priv { +struct nv04_devinit { struct nvkm_devinit base; int owner; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index def8649216c20..2659b9c37df4b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -44,8 +44,8 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) { 0x06, 0x00 }, { 0x00, 0x00 } }; - struct nv04_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nv04_devinit *init = (void *)devinit; + struct nvkm_bios *bios = nvkm_bios(init); struct io_mapping *fb; u32 patt = 0xdeadbeef; u16 data; @@ -53,13 +53,13 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) int i, v; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(nv_device(init)); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nv_error(init, "failed to map fb\n"); return; } - strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2; + strap = (nv_rd32(init, 0x101000) & 0x0000003c) >> 2; if ((data = bmp_mem_init_table(bios))) { ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0); ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1); @@ -69,59 +69,59 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) } /* Sequencer off */ - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20); + nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) | 0x20); - if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) + if (nv_rd32(init, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) goto out; - nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nv_mask(init, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); /* If present load the hardcoded scrambling table */ if (data) { for (i = 0, data += 0x10; i < 8; i++, data += 4) { u32 scramble = nv_ro32(bios, data); - nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble); + nv_wr32(init, NV04_PFB_SCRAMBLE(i), scramble); } } /* Set memory type/width/length defaults depending on the straps */ - nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); + nv_mask(init, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); if (ramcfg[1] & 0x80) - nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); + nv_mask(init, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); - nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); - nv_mask(priv, NV04_PFB_CFG1, 0, 1); + nv_mask(init, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); + nv_mask(init, NV04_PFB_CFG1, 0, 1); /* Probe memory bus width */ for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if (fbmem_peek(fb, 0xc) != patt) - nv_mask(priv, NV04_PFB_BOOT_0, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); /* Probe memory length */ - v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; + v = nv_rd32(init, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && (!fbmem_readback(fb, 0x1000000, ++patt) || !fbmem_readback(fb, 0, ++patt))) - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && !fbmem_readback(fb, 0x800000, ++patt)) - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); if (!fbmem_readback(fb, 0x400000, ++patt)) - nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); out: /* Sequencer on */ - nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20); + nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) & ~0x20); fbmem_fini(fb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c index 7aabc1bf06403..bbf791eaa0ab7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c @@ -32,31 +32,31 @@ static void nv10_devinit_meminit(struct nvkm_devinit *devinit) { - struct nv04_devinit_priv *priv = (void *)devinit; + struct nv04_devinit *init = (void *)devinit; static const int mem_width[] = { 0x10, 0x00, 0x20 }; int mem_width_count; uint32_t patt = 0xdeadbeef; struct io_mapping *fb; int i, j, k; - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) + if (nv_device(init)->card_type >= NV_11 && + nv_device(init)->chipset >= 0x17) mem_width_count = 3; else mem_width_count = 2; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(nv_device(init)); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nv_error(init, "failed to map fb\n"); return; } - nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + nv_wr32(init, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Probe memory bus width */ for (i = 0; i < mem_width_count; i++) { - nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]); + nv_mask(init, NV04_PFB_CFG0, 0x30, mem_width[i]); for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) @@ -75,7 +75,7 @@ mem_width_found: /* Probe amount of installed memory */ for (i = 0; i < 4; i++) { - int off = nv_rd32(priv, 0x10020c) - 0x100000; + int off = nv_rd32(init, 0x10020c) - 0x100000; fbmem_poke(fb, off, patt); fbmem_poke(fb, 0, 0); @@ -90,7 +90,7 @@ mem_width_found: } /* IC missing - disable the upper half memory space. */ - nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0); + nv_mask(init, NV04_PFB_CFG0, 0x1000, 0); amount_found: fbmem_fini(fb); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c index 02fcfd921c42f..50f9849cdfb59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c @@ -32,32 +32,32 @@ static void nv20_devinit_meminit(struct nvkm_devinit *devinit) { - struct nv04_devinit_priv *priv = (void *)devinit; - struct nvkm_device *device = nv_device(priv); + struct nv04_devinit *init = (void *)devinit; + struct nvkm_device *device = nv_device(init); uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900); uint32_t amount, off; struct io_mapping *fb; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(priv)); + fb = fbmem_init(nv_device(init)); if (!fb) { - nv_error(priv, "failed to map fb\n"); + nv_error(init, "failed to map fb\n"); return; } - nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + nv_wr32(init, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Allow full addressing */ - nv_mask(priv, NV04_PFB_CFG0, 0, mask); + nv_mask(init, NV04_PFB_CFG0, 0, mask); - amount = nv_rd32(priv, 0x10020c); + amount = nv_rd32(init, 0x10020c); for (off = amount; off > 0x2000000; off -= 0x2000000) fbmem_poke(fb, off - 4, off); - amount = nv_rd32(priv, 0x10020c); + amount = nv_rd32(init, 0x10020c); if (amount != fbmem_peek(fb, amount - 4)) /* IC missing - disable the upper half memory space. */ - nv_mask(priv, NV04_PFB_CFG0, mask, 0); + nv_mask(init, NV04_PFB_CFG0, mask, 0); fbmem_fini(fb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index 26b7cb13e1673..8e9633096bece 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -35,8 +35,8 @@ int nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) { - struct nv50_devinit_priv *priv = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nv50_devinit *init = (void *)devinit; + struct nvkm_bios *bios = nvkm_bios(init); struct nvbios_pll info; int N1, M1, N2, M2, P; int ret; @@ -56,20 +56,20 @@ nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: - nv_wr32(priv, info.reg + 0, 0x10000611); - nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); - nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) | + nv_wr32(init, info.reg + 0, 0x10000611); + nv_mask(init, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); + nv_mask(init, info.reg + 8, 0x7fff00ff, (P << 28) | (M2 << 16) | N2); break; case PLL_MEMORY: - nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) | + nv_mask(init, info.reg + 0, 0x01ff0000, (P << 22) | (info.bias_p << 19) | (P << 16)); - nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); + nv_wr32(init, info.reg + 4, (N1 << 8) | M1); break; default: - nv_mask(priv, info.reg + 0, 0x00070000, (P << 16)); - nv_wr32(priv, info.reg + 4, (N1 << 8) | M1); + nv_mask(init, info.reg + 0, 0x00070000, (P << 16)); + nv_wr32(init, info.reg + 4, (N1 << 8) | M1); break; } @@ -79,8 +79,8 @@ nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) static u64 nv50_devinit_disable(struct nvkm_devinit *devinit) { - struct nv50_devinit_priv *priv = (void *)devinit; - u32 r001540 = nv_rd32(priv, 0x001540); + struct nv50_devinit *init = (void *)devinit; + u32 r001540 = nv_rd32(init, 0x001540); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) @@ -94,28 +94,28 @@ nv50_devinit_init(struct nvkm_object *object) { struct nvkm_bios *bios = nvkm_bios(object); struct nvkm_ibus *ibus = nvkm_ibus(object); - struct nv50_devinit_priv *priv = (void *)object; + struct nv50_devinit *init = (void *)object; struct nvbios_outp info; struct dcb_output outp; u8 ver = 0xff, hdr, cnt, len; int ret, i = 0; - if (!priv->base.post) { - if (!nv_rdvgac(priv, 0, 0x00) && - !nv_rdvgac(priv, 0, 0x1a)) { - nv_info(priv, "adaptor not initialised\n"); - priv->base.post = true; + if (!init->base.post) { + if (!nv_rdvgac(init, 0, 0x00) && + !nv_rdvgac(init, 0, 0x1a)) { + nv_info(init, "adaptor not initialised\n"); + init->base.post = true; } } - /* some boards appear to require certain priv register timeouts + /* some boards appear to require certain init register timeouts * to be bumped before runing devinit scripts. not a clue why * the vbios engineers didn't make the scripts just work... */ - if (priv->base.post && ibus) + if (init->base.post && ibus) nv_ofuncs(ibus)->init(nv_object(ibus)); - ret = nvkm_devinit_init(&priv->base); + ret = nvkm_devinit_init(&init->base); if (ret) return ret; @@ -123,11 +123,11 @@ nv50_devinit_init(struct nvkm_object *object) * pointer of each dcb entry's display encoder table in order * to properly initialise each encoder. */ - while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { + while (init->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) { if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { - struct nvbios_init init = { - .subdev = nv_subdev(priv), + struct nvbios_init exec = { + .subdev = nv_subdev(init), .bios = bios, .offset = info.script[0], .outp = &outp, @@ -135,7 +135,7 @@ nv50_devinit_init(struct nvkm_object *object) .execute = 1, }; - nvbios_exec(&init); + nvbios_exec(&exec); } i++; } @@ -148,11 +148,11 @@ nv50_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_devinit_priv *priv; + struct nv50_devinit *init; int ret; - ret = nvkm_devinit_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_devinit_create(parent, engine, oclass, &init); + *pobject = nv_object(init); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h index 9243521c80ac2..c132fb4ae4f5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h @@ -2,7 +2,7 @@ #define __NVKM_DEVINIT_NV50_H__ #include "priv.h" -struct nv50_devinit_priv { +struct nv50_devinit { struct nvkm_devinit base; u32 r001540; }; -- GitLab From b1e4553cb1f9deddbd8c13d95e9cef81967a3f41 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5327/7006] drm/nouveau/fb: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/fb.h | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 20 +-- drivers/gpu/drm/nouveau/nouveau_gem.c | 4 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 20 +-- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/base.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 10 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 64 +++---- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 56 +++--- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c | 16 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c | 24 +-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h | 4 - drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c | 14 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c | 26 +-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c | 6 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c | 36 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c | 6 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c | 6 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c | 12 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c | 18 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c | 20 +-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 52 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h | 12 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h | 18 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 118 ++++++------ .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 169 ++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 170 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c | 50 +++--- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c | 10 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 88 ++++----- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c | 16 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c | 12 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c | 12 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 125 +++++++------ .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 18 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 4 +- 51 files changed, 649 insertions(+), 663 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index 16da56cf43b07..344cc99f0dc17 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -46,7 +46,7 @@ struct nvkm_fb_tile { }; struct nvkm_fb { - struct nvkm_subdev base; + struct nvkm_subdev subdev; bool (*memtype_valid)(struct nvkm_fb *, u32 memtype); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6edcce1658b70..37ed3b250ac5e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -48,23 +48,23 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg, { struct nouveau_drm *drm = nouveau_drm(dev); int i = reg - drm->tile.reg; - struct nvkm_fb *pfb = nvxx_fb(&drm->device); - struct nvkm_fb_tile *tile = &pfb->tile.region[i]; + struct nvkm_fb *fb = nvxx_fb(&drm->device); + struct nvkm_fb_tile *tile = &fb->tile.region[i]; struct nvkm_engine *engine; nouveau_fence_unref(®->fence); if (tile->pitch) - pfb->tile.fini(pfb, i, tile); + fb->tile.fini(fb, i, tile); if (pitch) - pfb->tile.init(pfb, i, addr, size, pitch, flags, tile); + fb->tile.init(fb, i, addr, size, pitch, flags, tile); - pfb->tile.prog(pfb, i, tile); + fb->tile.prog(fb, i, tile); - if ((engine = nvkm_engine(pfb, NVDEV_ENGINE_GR))) + if ((engine = nvkm_engine(fb, NVDEV_ENGINE_GR))) engine->tile_prog(engine, i); - if ((engine = nvkm_engine(pfb, NVDEV_ENGINE_MPEG))) + if ((engine = nvkm_engine(fb, NVDEV_ENGINE_MPEG))) engine->tile_prog(engine, i); } @@ -105,18 +105,18 @@ nv10_bo_set_tiling(struct drm_device *dev, u32 addr, u32 size, u32 pitch, u32 flags) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_fb *pfb = nvxx_fb(&drm->device); + struct nvkm_fb *fb = nvxx_fb(&drm->device); struct nouveau_drm_tile *tile, *found = NULL; int i; - for (i = 0; i < pfb->tile.regions; i++) { + for (i = 0; i < fb->tile.regions; i++) { tile = nv10_bo_get_tile_region(dev, i); if (pitch && !found) { found = tile; continue; - } else if (tile && pfb->tile.region[i].pitch) { + } else if (tile && fb->tile.region[i].pitch) { /* Kill an unused tile region. */ nv10_bo_update_tile_region(dev, tile, 0, 0, 0, 0); } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index af1ee517f3722..a747eccbc79fb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -254,12 +254,12 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, { struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli = nouveau_cli(file_priv); - struct nvkm_fb *pfb = nvxx_fb(&drm->device); + struct nvkm_fb *fb = nvxx_fb(&drm->device); struct drm_nouveau_gem_new *req = data; struct nouveau_bo *nvbo = NULL; int ret = 0; - if (!pfb->memtype_valid(pfb, req->info.tile_flags)) { + if (!fb->memtype_valid(fb, req->info.tile_flags)) { NV_PRINTK(error, cli, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 737e8f976a983..d9c64c2aabc8a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -33,8 +33,8 @@ static int nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nvkm_fb *pfb = nvxx_fb(&drm->device); - man->priv = pfb; + struct nvkm_fb *fb = nvxx_fb(&drm->device); + man->priv = fb; return 0; } @@ -64,9 +64,9 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nvkm_fb *pfb = nvxx_fb(&drm->device); + struct nvkm_fb *fb = nvxx_fb(&drm->device); nvkm_mem_node_cleanup(mem->mm_node); - pfb->ram->put(pfb, (struct nvkm_mem **)&mem->mm_node); + fb->ram->put(fb, (struct nvkm_mem **)&mem->mm_node); } static int @@ -76,7 +76,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nvkm_fb *pfb = nvxx_fb(&drm->device); + struct nvkm_fb *fb = nvxx_fb(&drm->device); struct nouveau_bo *nvbo = nouveau_bo(bo); struct nvkm_mem *node; u32 size_nc = 0; @@ -88,7 +88,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) size_nc = 1 << nvbo->page_shift; - ret = pfb->ram->get(pfb, mem->num_pages << PAGE_SHIFT, + ret = fb->ram->get(fb, mem->num_pages << PAGE_SHIFT, mem->page_alignment << PAGE_SHIFT, size_nc, (nvbo->tile_flags >> 8) & 0x3ff, &node); if (ret) { @@ -106,12 +106,12 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, static void nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) { - struct nvkm_fb *pfb = man->priv; - struct nvkm_mm *mm = &pfb->vram; + struct nvkm_fb *fb = man->priv; + struct nvkm_mm *mm = &fb->vram; struct nvkm_mm_node *r; u32 total = 0, free = 0; - mutex_lock(&nv_subdev(pfb)->mutex); + mutex_lock(&nv_subdev(fb)->mutex); list_for_each_entry(r, &mm->nodes, nl_entry) { printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n", prefix, r->type, ((u64)r->offset << 12), @@ -121,7 +121,7 @@ nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) if (!r->type) free += r->length; } - mutex_unlock(&nv_subdev(pfb)->mutex); + mutex_unlock(&nv_subdev(fb)->mutex); printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n", prefix, (u64)total << 12, (u64)free << 12); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 28ebe06e87b93..106ec87749a4f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -80,7 +80,7 @@ static int nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size) { struct nvkm_device *device = nv_device(object); - struct nvkm_fb *pfb = nvkm_fb(device); + struct nvkm_fb *fb = nvkm_fb(device); struct nvkm_instmem *imem = nvkm_instmem(device); union { struct nv_device_info_v0 v0; @@ -139,8 +139,8 @@ nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size) args->v0.chipset = device->chipset; args->v0.revision = device->chiprev; - if (pfb && pfb->ram) - args->v0.ram_size = args->v0.ram_user = pfb->ram->size; + if (fb && fb->ram) + args->v0.ram_size = args->v0.ram_user = fb->ram->size; else args->v0.ram_size = args->v0.ram_user = 0; if (imem && args->v0.ram_size > 0) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c index 3adab2ed7c08c..b6572f1b69810 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c @@ -64,7 +64,7 @@ nvkm_dmaobj_create_(struct nvkm_object *parent, struct nvkm_instmem *instmem = nvkm_instmem(parent); struct nvkm_client *client = nvkm_client(parent); struct nvkm_device *device = nv_device(parent); - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_dmaobj *dmaobj; void *data = *pdata; u32 size = *psize; @@ -100,7 +100,7 @@ nvkm_dmaobj_create_(struct nvkm_object *parent, break; case NV_DMA_V0_TARGET_VRAM: if (!client->super) { - if (dmaobj->limit >= pfb->ram->size - instmem->reserved) + if (dmaobj->limit >= fb->ram->size - instmem->reserved) return -EACCES; if (device->card_type >= NV_50) return -EACCES; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 24930d9b6ae44..a9bb6a53f9faa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -295,7 +295,7 @@ static int nv40_fifo_init(struct nvkm_object *object) { struct nv04_fifo_priv *priv = (void *)object; - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); int ret; ret = nvkm_fifo_init(&priv->base); @@ -326,7 +326,7 @@ nv40_fifo_init(struct nvkm_object *object) break; default: nv_wr32(priv, 0x002230, 0x00000000); - nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 + + nv_wr32(priv, 0x002220, ((fb->ram->size - 512 * 1024 + priv->ramfc->addr) >> 16) | 0x00030000); break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 62a4d797498aa..535f5930c40b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -1249,7 +1249,7 @@ static int nv10_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); struct nv10_gr_priv *priv = (void *)engine; int ret, i; @@ -1279,7 +1279,7 @@ nv10_gr_init(struct nvkm_object *object) } /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) + for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 5d8dbac3cdb82..0aa4cc9f74e1b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -271,7 +271,7 @@ nv20_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv20_gr_priv *priv = (void *)engine; - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); u32 tmp, vramsz; int ret, i; @@ -324,7 +324,7 @@ nv20_gr_init(struct nvkm_object *object) } /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) + for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324)); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 207464c3c40ec..0214e8a91dac9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -153,7 +153,7 @@ nv30_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv20_gr_priv *priv = (void *)engine; - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); int ret, i; ret = nvkm_gr_init(&priv->base); @@ -198,7 +198,7 @@ nv30_gr_init(struct nvkm_object *object) nv_wr32(priv, 0x4000c0, 0x00000016); /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) + for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 7e1937980e3f7..ed05c6d7875b4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -366,7 +366,7 @@ static int nv40_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); struct nv40_gr_priv *priv = (void *)engine; int ret, i, j; u32 vramsz; @@ -470,7 +470,7 @@ nv40_gr_init(struct nvkm_object *object) } /* Turn all the tiling regions off. */ - for (i = 0; i < pfb->tile.regions; i++) + for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); /* begin RAM config */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index b5bef07183595..891004157ea84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -260,7 +260,7 @@ nv31_mpeg_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv31_mpeg_priv *priv = (void *)object; - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); int ret, i; ret = nvkm_mpeg_init(&priv->base); @@ -271,7 +271,7 @@ nv31_mpeg_init(struct nvkm_object *object) nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - for (i = 0; i < pfb->tile.regions; i++) + for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); /* PMPEG init */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 572fbf1bc72f7..a624e9eb0c3b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -171,7 +171,7 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) static int nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) { - struct nvkm_fb *pfb = nvkm_fb(clk); + struct nvkm_fb *fb = nvkm_fb(clk); struct nvkm_pstate *pstate; int ret, idx = 0; @@ -183,14 +183,14 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) nv_debug(clk, "setting performance state %d\n", pstatei); clk->pstate = pstatei; - if (pfb->ram && pfb->ram->calc) { + if (fb->ram && fb->ram->calc) { int khz = pstate->base.domain[nv_clk_src_mem]; do { - ret = pfb->ram->calc(pfb, khz); + ret = fb->ram->calc(fb, khz); if (ret == 0) - ret = pfb->ram->prog(pfb); + ret = fb->ram->prog(fb); } while (ret > 0); - pfb->ram->tidy(pfb); + fb->ram->tidy(fb); } return nvkm_cstate_prog(clk, pstate, 0); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 61fde43dab71d..8bd560d61bd8c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -52,36 +52,36 @@ nvkm_fb_bios_memtype(struct nvkm_bios *bios) int _nvkm_fb_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_fb *pfb = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret; - if (pfb->ram) { - ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend); + if (fb->ram) { + ret = nv_ofuncs(fb->ram)->fini(nv_object(fb->ram), suspend); if (ret && suspend) return ret; } - return nvkm_subdev_fini(&pfb->base, suspend); + return nvkm_subdev_fini(&fb->subdev, suspend); } int _nvkm_fb_init(struct nvkm_object *object) { - struct nvkm_fb *pfb = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret, i; - ret = nvkm_subdev_init(&pfb->base); + ret = nvkm_subdev_init(&fb->subdev); if (ret) return ret; - if (pfb->ram) { - ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram)); + if (fb->ram) { + ret = nv_ofuncs(fb->ram)->init(nv_object(fb->ram)); if (ret) return ret; } - for (i = 0; i < pfb->tile.regions; i++) - pfb->tile.prog(pfb, i, &pfb->tile.region[i]); + for (i = 0; i < fb->tile.regions; i++) + fb->tile.prog(fb, i, &fb->tile.region[i]); return 0; } @@ -89,19 +89,19 @@ _nvkm_fb_init(struct nvkm_object *object) void _nvkm_fb_dtor(struct nvkm_object *object) { - struct nvkm_fb *pfb = (void *)object; + struct nvkm_fb *fb = (void *)object; int i; - for (i = 0; i < pfb->tile.regions; i++) - pfb->tile.fini(pfb, i, &pfb->tile.region[i]); - nvkm_mm_fini(&pfb->tags); + for (i = 0; i < fb->tile.regions; i++) + fb->tile.fini(fb, i, &fb->tile.region[i]); + nvkm_mm_fini(&fb->tags); - if (pfb->ram) { - nvkm_mm_fini(&pfb->vram); - nvkm_object_ref(NULL, (struct nvkm_object **)&pfb->ram); + if (fb->ram) { + nvkm_mm_fini(&fb->vram); + nvkm_object_ref(NULL, (struct nvkm_object **)&fb->ram); } - nvkm_subdev_destroy(&pfb->base); + nvkm_subdev_destroy(&fb->subdev); } int @@ -123,43 +123,43 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, [NV_MEM_TYPE_GDDR5 ] = "GDDR5", }; struct nvkm_object *ram; - struct nvkm_fb *pfb; + struct nvkm_fb *fb; int ret; ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PFB", "fb", length, pobject); - pfb = *pobject; + fb = *pobject; if (ret) return ret; - pfb->memtype_valid = impl->memtype; + fb->memtype_valid = impl->memtype; if (!impl->ram) return 0; - ret = nvkm_object_ctor(nv_object(pfb), NULL, impl->ram, NULL, 0, &ram); + ret = nvkm_object_ctor(nv_object(fb), NULL, impl->ram, NULL, 0, &ram); if (ret) { - nv_fatal(pfb, "error detecting memory configuration!!\n"); + nv_fatal(fb, "error detecting memory configuration!!\n"); return ret; } - pfb->ram = (void *)ram; + fb->ram = (void *)ram; - if (!nvkm_mm_initialised(&pfb->vram)) { - ret = nvkm_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1); + if (!nvkm_mm_initialised(&fb->vram)) { + ret = nvkm_mm_init(&fb->vram, 0, fb->ram->size >> 12, 1); if (ret) return ret; } - if (!nvkm_mm_initialised(&pfb->tags)) { - ret = nvkm_mm_init(&pfb->tags, 0, pfb->ram->tags ? - ++pfb->ram->tags : 0, 1); + if (!nvkm_mm_initialised(&fb->tags)) { + ret = nvkm_mm_init(&fb->tags, 0, fb->ram->tags ? + ++fb->ram->tags : 0, 1); if (ret) return ret; } - nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]); - nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20)); - nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags); + nv_info(fb, "RAM type: %s\n", name[fb->ram->type]); + nv_info(fb, "RAM size: %d MiB\n", (int)(fb->ram->size >> 20)); + nv_info(fb, " ZCOMP: %d tags\n", fb->ram->tags); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index 5a6c2b7a6ef18..db6bbb4391762 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -26,7 +26,7 @@ extern const u8 gf100_pte_storage_type_map[256]; bool -gf100_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags) +gf100_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) { u8 memtype = (tile_flags & 0x0000ff00) >> 8; return likely((gf100_pte_storage_type_map[memtype] != 0xff)); @@ -35,32 +35,28 @@ gf100_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags) static void gf100_fb_intr(struct nvkm_subdev *subdev) { - struct gf100_fb_priv *priv = (void *)subdev; - u32 intr = nv_rd32(priv, 0x000100); - if (intr & 0x08000000) { - nv_debug(priv, "PFFB intr\n"); - intr &= ~0x08000000; - } - if (intr & 0x00002000) { - nv_debug(priv, "PBFB intr\n"); - intr &= ~0x00002000; - } + struct gf100_fb *fb = (void *)subdev; + u32 intr = nv_rd32(fb, 0x000100); + if (intr & 0x08000000) + nv_debug(fb, "PFFB intr\n"); + if (intr & 0x00002000) + nv_debug(fb, "PBFB intr\n"); } int gf100_fb_init(struct nvkm_object *object) { - struct gf100_fb_priv *priv = (void *)object; + struct gf100_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(&fb->base); if (ret) return ret; - if (priv->r100c10_page) - nv_wr32(priv, 0x100c10, priv->r100c10 >> 8); + if (fb->r100c10_page) + nv_wr32(fb, 0x100c10, fb->r100c10 >> 8); - nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + nv_mask(fb, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ return 0; } @@ -68,15 +64,15 @@ void gf100_fb_dtor(struct nvkm_object *object) { struct nvkm_device *device = nv_device(object); - struct gf100_fb_priv *priv = (void *)object; + struct gf100_fb *fb = (void *)object; - if (priv->r100c10_page) { - dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE, + if (fb->r100c10_page) { + dma_unmap_page(nv_device_base(device), fb->r100c10, PAGE_SIZE, DMA_BIDIRECTIONAL); - __free_page(priv->r100c10_page); + __free_page(fb->r100c10_page); } - nvkm_fb_destroy(&priv->base); + nvkm_fb_destroy(&fb->base); } int @@ -85,24 +81,24 @@ gf100_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = nv_device(parent); - struct gf100_fb_priv *priv; + struct gf100_fb *fb; int ret; - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fb_create(parent, engine, oclass, &fb); + *pobject = nv_object(fb); if (ret) return ret; - priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (priv->r100c10_page) { - priv->r100c10 = dma_map_page(nv_device_base(device), - priv->r100c10_page, 0, PAGE_SIZE, + fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (fb->r100c10_page) { + fb->r100c10 = dma_map_page(nv_device_base(device), + fb->r100c10_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), priv->r100c10)) + if (dma_mapping_error(nv_device_base(device), fb->r100c10)) return -EFAULT; } - nv_subdev(priv)->intr = gf100_fb_intr; + nv_subdev(fb)->intr = gf100_fb_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index 0af4da259471d..add84641cd817 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -3,7 +3,7 @@ #include "priv.h" #include "nv50.h" -struct gf100_fb_priv { +struct gf100_fb { struct nvkm_fb base; struct page *r100c10_page; dma_addr_t r100c10; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index a5d7857d3898b..91c0409312cf1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -21,21 +21,17 @@ */ #include "gf100.h" -struct gk20a_fb_priv { - struct nvkm_fb base; -}; - static int gk20a_fb_init(struct nvkm_object *object) { - struct gk20a_fb_priv *priv = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(fb); if (ret) return ret; - nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + nv_mask(fb, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ return 0; } @@ -44,11 +40,11 @@ gk20a_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk20a_fb_priv *priv; + struct nvkm_fb *fb; int ret; - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fb_create(parent, engine, oclass, &fb); + *pobject = nv_object(fb); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c index c063dec7d03af..9e55308c99456 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c @@ -25,7 +25,7 @@ #include "regsnv04.h" bool -nv04_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags) +nv04_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) { if (!(tile_flags & 0xff00)) return true; @@ -36,10 +36,10 @@ nv04_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags) static int nv04_fb_init(struct nvkm_object *object) { - struct nv04_fb_priv *priv = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(fb); if (ret) return ret; @@ -47,7 +47,7 @@ nv04_fb_init(struct nvkm_object *object) * nvidia reading PFB_CFG_0, then writing back its original value. * (which was 0x701114 in this case) */ - nv_wr32(priv, NV04_PFB_CFG0, 0x1114); + nv_wr32(fb, NV04_PFB_CFG0, 0x1114); return 0; } @@ -57,19 +57,19 @@ nv04_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv04_fb_impl *impl = (void *)oclass; - struct nv04_fb_priv *priv; + struct nvkm_fb *fb; int ret; - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fb_create(parent, engine, oclass, &fb); + *pobject = nv_object(fb); if (ret) return ret; - priv->base.tile.regions = impl->tile.regions; - priv->base.tile.init = impl->tile.init; - priv->base.tile.comp = impl->tile.comp; - priv->base.tile.fini = impl->tile.fini; - priv->base.tile.prog = impl->tile.prog; + fb->tile.regions = impl->tile.regions; + fb->tile.init = impl->tile.init; + fb->tile.comp = impl->tile.comp; + fb->tile.fini = impl->tile.fini; + fb->tile.prog = impl->tile.prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h index caa0d03aaacc9..b85ef39835393 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h @@ -2,10 +2,6 @@ #define __NVKM_FB_NV04_H__ #include "priv.h" -struct nv04_fb_priv { - struct nvkm_fb base; -}; - int nv04_fb_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c index f3530e4a67600..b657ddc1e0132 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c @@ -26,7 +26,7 @@ #include "nv04.h" void -nv10_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv10_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { tile->addr = 0x80000000 | addr; @@ -35,7 +35,7 @@ nv10_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, } void -nv10_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv10_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { tile->addr = 0; tile->limit = 0; @@ -44,12 +44,12 @@ nv10_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) } void -nv10_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv10_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100240 + (i * 0x10)); + nv_wr32(fb, 0x100244 + (i * 0x10), tile->limit); + nv_wr32(fb, 0x100248 + (i * 0x10), tile->pitch); + nv_wr32(fb, 0x100240 + (i * 0x10), tile->addr); + nv_rd32(fb, 0x100240 + (i * 0x10)); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c index e37084b8d05e6..b1b50a41f161b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c @@ -26,25 +26,25 @@ #include "nv04.h" void -nv20_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv20_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { tile->addr = 0x00000001 | addr; tile->limit = max(1u, addr + size) - 1; tile->pitch = pitch; if (flags & 4) { - pfb->tile.comp(pfb, i, size, flags, tile); + fb->tile.comp(fb, i, size, flags, tile); tile->addr |= 2; } } static void -nv20_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv20_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */ else tile->zcomp = 0x04000000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; @@ -56,23 +56,23 @@ nv20_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } void -nv20_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv20_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { tile->addr = 0; tile->limit = 0; tile->pitch = 0; tile->zcomp = 0; - nvkm_mm_free(&pfb->tags, &tile->tag); + nvkm_mm_free(&fb->tags, &tile->tag); } void -nv20_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv20_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100240 + (i * 0x10)); - nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp); + nv_wr32(fb, 0x100244 + (i * 0x10), tile->limit); + nv_wr32(fb, 0x100248 + (i * 0x10), tile->pitch); + nv_wr32(fb, 0x100240 + (i * 0x10), tile->addr); + nv_rd32(fb, 0x100240 + (i * 0x10)); + nv_wr32(fb, 0x100300 + (i * 0x04), tile->zcomp); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c index bc9f54f38fba0..90b17004ffb24 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c @@ -26,12 +26,12 @@ #include "nv04.h" static void -nv25_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */ else tile->zcomp = 0x00200000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c index 6c0b82f35d94f..40c3962848155 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c @@ -26,15 +26,15 @@ #include "nv04.h" void -nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv30_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { /* for performance, select alternate bank offset for zeta */ if (!(flags & 4)) { tile->addr = (0 << 4); } else { - if (pfb->tile.comp) /* z compression */ - pfb->tile.comp(pfb, i, size, flags, tile); + if (fb->tile.comp) /* z compression */ + fb->tile.comp(fb, i, size, flags, tile); tile->addr = (1 << 4); } @@ -45,12 +45,12 @@ nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, } static void -nv30_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv30_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */ else tile->zcomp |= 0x02000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -62,23 +62,23 @@ nv30_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, } static int -calc_bias(struct nv04_fb_priv *priv, int k, int i, int j) +calc_bias(struct nvkm_fb *fb, int k, int i, int j) { - struct nvkm_device *device = nv_device(priv); + struct nvkm_device *device = nv_device(fb); int b = (device->chipset > 0x30 ? - nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : + nv_rd32(fb, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : 0) & 0xf; return 2 * (b & 0x8 ? b - 0x10 : b); } static int -calc_ref(struct nv04_fb_priv *priv, int l, int k, int i) +calc_ref(struct nvkm_fb *fb, int l, int k, int i) { int j, x = 0; for (j = 0; j < 4; j++) { - int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j); + int m = (l >> (8 * i) & 0xff) + calc_bias(fb, k, i, j); x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j); } @@ -90,10 +90,10 @@ int nv30_fb_init(struct nvkm_object *object) { struct nvkm_device *device = nv_device(object); - struct nv04_fb_priv *priv = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret, i, j; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(fb); if (ret) return ret; @@ -103,16 +103,16 @@ nv30_fb_init(struct nvkm_object *object) device->chipset == 0x35) { /* Related to ROP count */ int n = (device->chipset == 0x31 ? 2 : 4); - int l = nv_rd32(priv, 0x1003d0); + int l = nv_rd32(fb, 0x1003d0); for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) - nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j, - calc_ref(priv, l, 0, j)); + nv_wr32(fb, 0x10037c + 0xc * i + 0x4 * j, + calc_ref(fb, l, 0, j)); for (j = 0; j < 2; j++) - nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j, - calc_ref(priv, l, 1, j)); + nv_wr32(fb, 0x1003ac + 0x8 * i + 0x4 * j, + calc_ref(fb, l, 1, j)); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c index c01dc1839ea4c..7de68c6bea749 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c @@ -26,12 +26,12 @@ #include "nv04.h" static void -nv35_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv35_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */ else tile->zcomp |= 0x08000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c index cad75a1cef228..b78062fd6a3a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c @@ -26,12 +26,12 @@ #include "nv04.h" static void -nv36_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv36_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x40); - u32 tags = round_up(tiles / pfb->ram->parts, 0x40); - if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + u32 tags = round_up(tiles / fb->ram->parts, 0x40); + if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */ else tile->zcomp |= 0x20000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c index dbe5c1910c2c1..fe4ae2d7bfcbf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c @@ -26,13 +26,13 @@ #include "nv04.h" void -nv40_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, +nv40_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, struct nvkm_fb_tile *tile) { u32 tiles = DIV_ROUND_UP(size, 0x80); - u32 tags = round_up(tiles / pfb->ram->parts, 0x100); + u32 tags = round_up(tiles / fb->ram->parts, 0x100); if ( (flags & 2) && - !nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + !nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */ tile->zcomp |= ((tile->tag->offset ) >> 8); tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13; @@ -45,14 +45,14 @@ nv40_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags, static int nv40_fb_init(struct nvkm_object *object) { - struct nv04_fb_priv *priv = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(fb); if (ret) return ret; - nv_mask(priv, 0x10033c, 0x00008000, 0x00000000); + nv_mask(fb, 0x10033c, 0x00008000, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c index d9e1a40a2955b..ba0e6e327b6cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c @@ -26,26 +26,26 @@ #include "nv04.h" void -nv41_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv41_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100600 + (i * 0x10)); - nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp); + nv_wr32(fb, 0x100604 + (i * 0x10), tile->limit); + nv_wr32(fb, 0x100608 + (i * 0x10), tile->pitch); + nv_wr32(fb, 0x100600 + (i * 0x10), tile->addr); + nv_rd32(fb, 0x100600 + (i * 0x10)); + nv_wr32(fb, 0x100700 + (i * 0x04), tile->zcomp); } int nv41_fb_init(struct nvkm_object *object) { - struct nv04_fb_priv *priv = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(fb); if (ret) return ret; - nv_wr32(priv, 0x100800, 0x00000001); + nv_wr32(fb, 0x100800, 0x00000001); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c index 20b97c83c4af8..d6b917f709102 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c @@ -26,7 +26,7 @@ #include "nv04.h" static void -nv44_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv44_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { tile->addr = 0x00000001; /* mode = vram */ @@ -36,26 +36,26 @@ nv44_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, } void -nv44_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile) +nv44_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit); - nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch); - nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr); - nv_rd32(pfb, 0x100600 + (i * 0x10)); + nv_wr32(fb, 0x100604 + (i * 0x10), tile->limit); + nv_wr32(fb, 0x100608 + (i * 0x10), tile->pitch); + nv_wr32(fb, 0x100600 + (i * 0x10), tile->addr); + nv_rd32(fb, 0x100600 + (i * 0x10)); } int nv44_fb_init(struct nvkm_object *object) { - struct nv04_fb_priv *priv = (void *)object; + struct nvkm_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(fb); if (ret) return ret; - nv_wr32(priv, 0x100850, 0x80000000); - nv_wr32(priv, 0x100800, 0x00000001); + nv_wr32(fb, 0x100850, 0x80000000); + nv_wr32(fb, 0x100800, 0x00000001); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c index 5bfac38cdf242..1f8b69d375f90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c @@ -26,7 +26,7 @@ #include "nv04.h" void -nv46_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch, +nv46_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, u32 flags, struct nvkm_fb_tile *tile) { /* for performance, select alternate bank offset for zeta */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 48fd5a5bcd3ca..093d2a0ae152e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -40,7 +40,7 @@ nv50_fb_memtype[0x80] = { }; bool -nv50_fb_memtype_valid(struct nvkm_fb *pfb, u32 memtype) +nv50_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) { return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0; } @@ -146,23 +146,23 @@ nv50_fb_intr(struct nvkm_subdev *subdev) { struct nvkm_device *device = nv_device(subdev); struct nvkm_engine *engine; - struct nv50_fb_priv *priv = (void *)subdev; + struct nv50_fb *fb = (void *)subdev; const struct nvkm_enum *en, *cl; struct nvkm_object *engctx = NULL; u32 trap[6], idx, chan; u8 st0, st1, st2, st3; int i; - idx = nv_rd32(priv, 0x100c90); + idx = nv_rd32(fb, 0x100c90); if (!(idx & 0x80000000)) return; idx &= 0x00ffffff; for (i = 0; i < 6; i++) { - nv_wr32(priv, 0x100c90, idx | i << 24); - trap[i] = nv_rd32(priv, 0x100c94); + nv_wr32(fb, 0x100c90, idx | i << 24); + trap[i] = nv_rd32(fb, 0x100c94); } - nv_wr32(priv, 0x100c90, idx | 0x80000000); + nv_wr32(fb, 0x100c90, idx | 0x80000000); /* decode status bits into something more useful */ if (device->chipset < 0xa3 || @@ -203,7 +203,7 @@ nv50_fb_intr(struct nvkm_subdev *subdev) en = orig_en; } - nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ", + nv_error(fb, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ", (trap[5] & 0x00000100) ? "read" : "write", trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan, nvkm_client_name(engctx)); @@ -243,26 +243,26 @@ nv50_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = nv_device(parent); - struct nv50_fb_priv *priv; + struct nv50_fb *fb; int ret; - ret = nvkm_fb_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fb_create(parent, engine, oclass, &fb); + *pobject = nv_object(fb); if (ret) return ret; - priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (priv->r100c08_page) { - priv->r100c08 = dma_map_page(nv_device_base(device), - priv->r100c08_page, 0, PAGE_SIZE, + fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (fb->r100c08_page) { + fb->r100c08 = dma_map_page(nv_device_base(device), + fb->r100c08_page, 0, PAGE_SIZE, DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), priv->r100c08)) + if (dma_mapping_error(nv_device_base(device), fb->r100c08)) return -EFAULT; } else { - nv_warn(priv, "failed 0x100c08 page alloc\n"); + nv_warn(fb, "failed 0x100c08 page alloc\n"); } - nv_subdev(priv)->intr = nv50_fb_intr; + nv_subdev(fb)->intr = nv50_fb_intr; return 0; } @@ -270,25 +270,25 @@ void nv50_fb_dtor(struct nvkm_object *object) { struct nvkm_device *device = nv_device(object); - struct nv50_fb_priv *priv = (void *)object; + struct nv50_fb *fb = (void *)object; - if (priv->r100c08_page) { - dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE, + if (fb->r100c08_page) { + dma_unmap_page(nv_device_base(device), fb->r100c08, PAGE_SIZE, DMA_BIDIRECTIONAL); - __free_page(priv->r100c08_page); + __free_page(fb->r100c08_page); } - nvkm_fb_destroy(&priv->base); + nvkm_fb_destroy(&fb->base); } int nv50_fb_init(struct nvkm_object *object) { struct nv50_fb_impl *impl = (void *)object->oclass; - struct nv50_fb_priv *priv = (void *)object; + struct nv50_fb *fb = (void *)object; int ret; - ret = nvkm_fb_init(&priv->base); + ret = nvkm_fb_init(&fb->base); if (ret) return ret; @@ -296,11 +296,11 @@ nv50_fb_init(struct nvkm_object *object) * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) * cause IOMMU "read from address 0" errors (rh#561267) */ - nv_wr32(priv, 0x100c08, priv->r100c08 >> 8); + nv_wr32(fb, 0x100c08, fb->r100c08 >> 8); /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ - nv_wr32(priv, 0x100c90, impl->trap); + nv_wr32(fb, 0x100c90, impl->trap); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h index f3cde3f1f5111..002b95ae419dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h @@ -2,7 +2,7 @@ #define __NVKM_FB_NV50_H__ #include "priv.h" -struct nv50_fb_priv { +struct nv50_fb { struct nvkm_fb base; struct page *r100c08_page; dma_addr_t r100c08; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index 485c4b64819a8..74eb9a22705bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -42,16 +42,16 @@ int nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts); #define nvkm_fb_create(p,e,c,d) \ nvkm_fb_create_((p), (e), (c), sizeof(**d), (void **)d) #define nvkm_fb_destroy(p) ({ \ - struct nvkm_fb *pfb = (p); \ - _nvkm_fb_dtor(nv_object(pfb)); \ + struct nvkm_fb *_fb = (p); \ + _nvkm_fb_dtor(nv_object(_fb)); \ }) #define nvkm_fb_init(p) ({ \ - struct nvkm_fb *pfb = (p); \ - _nvkm_fb_init(nv_object(pfb)); \ + struct nvkm_fb *_fb = (p); \ + _nvkm_fb_init(nv_object(_fb)); \ }) #define nvkm_fb_fini(p,s) ({ \ - struct nvkm_fb *pfb = (p); \ - _nvkm_fb_fini(nv_object(pfb), (s)); \ + struct nvkm_fb *_fb = (p); \ + _nvkm_fb_fini(nv_object(_fb), (s)); \ }) int nvkm_fb_create_(struct nvkm_object *, struct nvkm_object *, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h index f343682b1387e..72ffb3a4a5d72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h @@ -4,7 +4,7 @@ struct ramfuc { struct nvkm_memx *memx; - struct nvkm_fb *pfb; + struct nvkm_fb *fb; int sequence; }; @@ -54,9 +54,9 @@ ramfuc_reg(u32 addr) } static inline int -ramfuc_init(struct ramfuc *ram, struct nvkm_fb *pfb) +ramfuc_init(struct ramfuc *ram, struct nvkm_fb *fb) { - struct nvkm_pmu *pmu = nvkm_pmu(pfb); + struct nvkm_pmu *pmu = nvkm_pmu(fb); int ret; ret = nvkm_memx_init(pmu, &ram->memx); @@ -64,7 +64,7 @@ ramfuc_init(struct ramfuc *ram, struct nvkm_fb *pfb) return ret; ram->sequence++; - ram->pfb = pfb; + ram->fb = fb; return 0; } @@ -72,9 +72,9 @@ static inline int ramfuc_exec(struct ramfuc *ram, bool exec) { int ret = 0; - if (ram->pfb) { + if (ram->fb) { ret = nvkm_memx_fini(&ram->memx, exec); - ram->pfb = NULL; + ram->fb = NULL; } return ret; } @@ -83,7 +83,7 @@ static inline u32 ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg) { if (reg->sequence != ram->sequence) - reg->data = nv_rd32(ram->pfb, reg->addr); + reg->data = nv_rd32(ram->fb, reg->addr); return reg->data; } @@ -144,9 +144,9 @@ ramfuc_train(struct ramfuc *ram) } static inline int -ramfuc_train_result(struct nvkm_fb *pfb, u32 *result, u32 rsize) +ramfuc_train_result(struct nvkm_fb *fb, u32 *result, u32 rsize) { - struct nvkm_pmu *pmu = nvkm_pmu(pfb); + struct nvkm_pmu *pmu = nvkm_pmu(fb); return nvkm_memx_train_result(pmu, result, rsize); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index dcb175bea84bd..ad1ce222b28f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -107,9 +107,9 @@ static void gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) { struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc); - struct nvkm_fb *pfb = nvkm_fb(ram); - u32 part = nv_rd32(pfb, 0x022438), i; - u32 mask = nv_rd32(pfb, 0x022554); + struct nvkm_fb *fb = nvkm_fb(ram); + u32 part = nv_rd32(fb, 0x022438), i; + u32 mask = nv_rd32(fb, 0x022554); u32 addr = 0x110974; ram_wr32(fuc, 0x10f910, magic); @@ -123,11 +123,11 @@ gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) } static int -gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) +gf100_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_clk *clk = nvkm_clk(pfb); - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gf100_ram *ram = (void *)pfb->ram; + struct nvkm_clk *clk = nvkm_clk(fb); + struct nvkm_bios *bios = nvkm_bios(fb); + struct gf100_ram *ram = (void *)fb->ram; struct gf100_ramfuc *fuc = &ram->fuc; struct nvbios_ramcfg cfg; u8 ver, cnt, len, strap; @@ -144,20 +144,20 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, &cnt, &ramcfg.size, &cfg); if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { - nv_error(pfb, "invalid/missing rammap entry\n"); + nv_error(fb, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); + strap = nvbios_ramcfg_index(nv_subdev(fb)); if (strap >= cnt) { - nv_error(pfb, "invalid ramcfg strap\n"); + nv_error(fb, "invalid ramcfg strap\n"); return -EINVAL; } ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) { - nv_error(pfb, "invalid/missing ramcfg entry\n"); + nv_error(fb, "invalid/missing ramcfg entry\n"); return -EINVAL; } @@ -167,14 +167,14 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, &cnt, &len); if (!timing.data || ver != 0x10 || timing.size < 0x19) { - nv_error(pfb, "invalid/missing timing entry\n"); + nv_error(fb, "invalid/missing timing entry\n"); return -EINVAL; } } else { timing.data = 0; } - ret = ram_init(fuc, pfb); + ret = ram_init(fuc, fb); if (ret) return ret; @@ -209,10 +209,10 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) if (mode == 1 && from == 0) { /* calculate refpll */ - ret = gt215_pll_calc(nv_subdev(pfb), &ram->refpll, + ret = gt215_pll_calc(nv_subdev(fb), &ram->refpll, ram->mempll.refclk, &N1, NULL, &M1, &P); if (ret <= 0) { - nv_error(pfb, "unable to calc refpll\n"); + nv_error(fb, "unable to calc refpll\n"); return ret ? ret : -ERANGE; } @@ -224,10 +224,10 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); /* calculate mempll */ - ret = gt215_pll_calc(nv_subdev(pfb), &ram->mempll, freq, + ret = gt215_pll_calc(nv_subdev(fb), &ram->mempll, freq, &N1, NULL, &M1, &P); if (ret <= 0) { - nv_error(pfb, "unable to calc refpll\n"); + nv_error(fb, "unable to calc refpll\n"); return ret ? ret : -ERANGE; } @@ -401,19 +401,19 @@ gf100_ram_calc(struct nvkm_fb *pfb, u32 freq) } static int -gf100_ram_prog(struct nvkm_fb *pfb) +gf100_ram_prog(struct nvkm_fb *fb) { - struct nvkm_device *device = nv_device(pfb); - struct gf100_ram *ram = (void *)pfb->ram; + struct nvkm_device *device = nv_device(fb); + struct gf100_ram *ram = (void *)fb->ram; struct gf100_ramfuc *fuc = &ram->fuc; ram_exec(fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); return 0; } static void -gf100_ram_tidy(struct nvkm_fb *pfb) +gf100_ram_tidy(struct nvkm_fb *fb) { - struct gf100_ram *ram = (void *)pfb->ram; + struct gf100_ram *ram = (void *)fb->ram; struct gf100_ramfuc *fuc = &ram->fuc; ram_exec(fuc, false); } @@ -421,29 +421,29 @@ gf100_ram_tidy(struct nvkm_fb *pfb) extern const u8 gf100_pte_storage_type_map[256]; void -gf100_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) +gf100_ram_put(struct nvkm_fb *fb, struct nvkm_mem **pmem) { - struct nvkm_ltc *ltc = nvkm_ltc(pfb); + struct nvkm_ltc *ltc = nvkm_ltc(fb); struct nvkm_mem *mem = *pmem; *pmem = NULL; if (unlikely(mem == NULL)) return; - mutex_lock(&pfb->base.mutex); + mutex_lock(&fb->subdev.mutex); if (mem->tag) ltc->tags_free(ltc, &mem->tag); - __nv50_ram_put(pfb, mem); - mutex_unlock(&pfb->base.mutex); + __nv50_ram_put(fb, mem); + mutex_unlock(&fb->subdev.mutex); kfree(mem); } int -gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, +gf100_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, u32 memtype, struct nvkm_mem **pmem) { - struct nvkm_mm *mm = &pfb->vram; + struct nvkm_mm *mm = &fb->vram; struct nvkm_mm_node *r; struct nvkm_mem *mem; int type = (memtype & 0x0ff); @@ -464,9 +464,9 @@ gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, INIT_LIST_HEAD(&mem->regions); mem->size = size; - mutex_lock(&pfb->base.mutex); + mutex_lock(&fb->subdev.mutex); if (comp) { - struct nvkm_ltc *ltc = nvkm_ltc(pfb); + struct nvkm_ltc *ltc = nvkm_ltc(fb); /* compression only works with lpages */ if (align == (1 << (17 - 12))) { @@ -485,15 +485,15 @@ gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, else ret = nvkm_mm_head(mm, 0, 1, size, ncmin, align, &r); if (ret) { - mutex_unlock(&pfb->base.mutex); - pfb->ram->put(pfb, &mem); + mutex_unlock(&fb->subdev.mutex); + fb->ram->put(fb, &mem); return ret; } list_add_tail(&r->rl_entry, &mem->regions); size -= r->length; } while (size); - mutex_unlock(&pfb->base.mutex); + mutex_unlock(&fb->subdev.mutex); r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); mem->offset = (u64)r->offset << 12; @@ -506,14 +506,14 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 maskaddr, int size, void **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_bios *bios = nvkm_bios(fb); struct nvkm_ram *ram; const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 parts = nv_rd32(pfb, 0x022438); - u32 pmask = nv_rd32(pfb, maskaddr); - u32 bsize = nv_rd32(pfb, 0x10f20c); + u32 parts = nv_rd32(fb, 0x022438); + u32 pmask = nv_rd32(fb, maskaddr); + u32 bsize = nv_rd32(fb, 0x10f20c); u32 offset, length; bool uniform = true; int ret, part; @@ -523,23 +523,23 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800)); - nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask); + nv_debug(fb, "0x100800: 0x%08x\n", nv_rd32(fb, 0x100800)); + nv_debug(fb, "parts 0x%08x mask 0x%08x\n", parts, pmask); ram->type = nvkm_fb_bios_memtype(bios); - ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1; + ram->ranks = (nv_rd32(fb, 0x10f200) & 0x00000004) ? 2 : 1; /* read amount of vram attached to each memory controller */ for (part = 0; part < parts; part++) { if (!(pmask & (1 << part))) { - u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000)); + u32 psize = nv_rd32(fb, 0x11020c + (part * 0x1000)); if (psize != bsize) { if (psize < bsize) bsize = psize; uniform = false; } - nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize); + nv_debug(fb, "%d: mem_amount 0x%08x\n", part, psize); ram->size += (u64)psize << 20; } } @@ -548,10 +548,10 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (uniform) { offset = rsvd_head; length = (ram->size >> 12) - rsvd_head - rsvd_tail; - ret = nvkm_mm_init(&pfb->vram, offset, length, 1); + ret = nvkm_mm_init(&fb->vram, offset, length, 1); } else { /* otherwise, address lowest common amount from 0GiB */ - ret = nvkm_mm_init(&pfb->vram, rsvd_head, + ret = nvkm_mm_init(&fb->vram, rsvd_head, (bsize << 8) * parts - rsvd_head, 1); if (ret) return ret; @@ -560,9 +560,9 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, offset = (0x0200000000ULL >> 12) + (bsize << 8); length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail; - ret = nvkm_mm_init(&pfb->vram, offset, length, 1); + ret = nvkm_mm_init(&fb->vram, offset, length, 1); if (ret) - nvkm_mm_fini(&pfb->vram); + nvkm_mm_fini(&fb->vram); } if (ret) @@ -576,7 +576,7 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, static int gf100_ram_init(struct nvkm_object *object) { - struct nvkm_fb *pfb = (void *)object->parent; + struct nvkm_fb *fb = (void *)object->parent; struct gf100_ram *ram = (void *)object; int ret, i; @@ -601,16 +601,16 @@ gf100_ram_init(struct nvkm_object *object) }; for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]); - nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]); - nv_wr32(pfb, 0x10f918, train1[i % 12]); - nv_wr32(pfb, 0x10f91c, train1[i % 12]); - nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]); - nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]); - nv_wr32(pfb, 0x10f918, train1[i % 12]); - nv_wr32(pfb, 0x10f91c, train1[i % 12]); + nv_wr32(fb, 0x10f968, 0x00000000 | (i << 8)); + nv_wr32(fb, 0x10f96c, 0x00000000 | (i << 8)); + nv_wr32(fb, 0x10f920, 0x00000100 | train0[i % 12]); + nv_wr32(fb, 0x10f924, 0x00000100 | train0[i % 12]); + nv_wr32(fb, 0x10f918, train1[i % 12]); + nv_wr32(fb, 0x10f91c, train1[i % 12]); + nv_wr32(fb, 0x10f920, 0x00000000 | train0[i % 12]); + nv_wr32(fb, 0x10f924, 0x00000000 | train0[i % 12]); + nv_wr32(fb, 0x10f918, train1[i % 12]); + nv_wr32(fb, 0x10f91c, train1[i % 12]); } } break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 97060ccfb80c1..e9f3ee344a17c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -228,7 +228,7 @@ static void gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, u32 _mask, u32 _data, u32 _copy) { - struct gk104_fb_priv *priv = (void *)nvkm_fb(ram); + struct gk104_fb *fb = (void *)nvkm_fb(ram); struct ramfuc *fuc = &ram->fuc.base; u32 addr = 0x110000 + (reg->addr & 0xfff); u32 mask = _mask | _copy; @@ -237,7 +237,7 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, for (i = 0; i < 16; i++, addr += 0x1000) { if (ram->pnuts & (1 << i)) { - u32 prev = nv_rd32(priv, addr); + u32 prev = nv_rd32(fb, addr); u32 next = (prev & ~mask) | data; nvkm_memx_wr32(fuc->memx, addr, next); } @@ -247,9 +247,9 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, gk104_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c)) static int -gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq) +gk104_ram_calc_gddr5(struct nvkm_fb *fb, u32 freq) { - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; struct nvkm_ram_data *next = ram->base.next; int vc = !next->bios.ramcfg_11_02_08; @@ -673,9 +673,9 @@ gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq) ******************************************************************************/ static int -gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq) +gk104_ram_calc_sddr3(struct nvkm_fb *fb, u32 freq) { - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1); const u32 runk0 = ram->fN1 << 16; @@ -925,9 +925,9 @@ gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq) ******************************************************************************/ static int -gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data) +gk104_ram_calc_data(struct nvkm_fb *fb, u32 khz, struct nvkm_ram_data *data) { - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = (void *)fb->ram; struct nvkm_ram_data *cfg; u32 mhz = khz / 1000; @@ -945,14 +945,14 @@ gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data) } static int -gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) +gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) { - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; int refclk, i; int ret; - ret = ram_init(fuc, pfb); + ret = ram_init(fuc, fb); if (ret) return ret; @@ -972,11 +972,11 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) refclk = fuc->mempll.refclk; /* calculate refpll coefficients */ - ret = gt215_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1, + ret = gt215_pll_calc(nv_subdev(fb), &fuc->refpll, refclk, &ram->N1, &ram->fN1, &ram->M1, &ram->P1); fuc->mempll.refclk = ret; if (ret <= 0) { - nv_error(pfb, "unable to calc refpll\n"); + nv_error(fb, "unable to calc refpll\n"); return -EINVAL; } @@ -989,10 +989,10 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) fuc->mempll.min_p = 1; fuc->mempll.max_p = 2; - ret = gt215_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq, + ret = gt215_pll_calc(nv_subdev(fb), &fuc->mempll, next->freq, &ram->N2, NULL, &ram->M2, &ram->P2); if (ret <= 0) { - nv_error(pfb, "unable to calc mempll\n"); + nv_error(fb, "unable to calc mempll\n"); return -EINVAL; } } @@ -1007,12 +1007,12 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) case NV_MEM_TYPE_DDR3: ret = nvkm_sddr3_calc(&ram->base); if (ret == 0) - ret = gk104_ram_calc_sddr3(pfb, next->freq); + ret = gk104_ram_calc_sddr3(fb, next->freq); break; case NV_MEM_TYPE_GDDR5: ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0); if (ret == 0) - ret = gk104_ram_calc_gddr5(pfb, next->freq); + ret = gk104_ram_calc_gddr5(fb, next->freq); break; default: ret = -ENOSYS; @@ -1023,21 +1023,21 @@ gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next) } static int -gk104_ram_calc(struct nvkm_fb *pfb, u32 freq) +gk104_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_clk *clk = nvkm_clk(pfb); - struct gk104_ram *ram = (void *)pfb->ram; + struct nvkm_clk *clk = nvkm_clk(fb); + struct gk104_ram *ram = (void *)fb->ram; struct nvkm_ram_data *xits = &ram->base.xition; struct nvkm_ram_data *copy; int ret; if (ram->base.next == NULL) { - ret = gk104_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem), + ret = gk104_ram_calc_data(fb, clk->read(clk, nv_clk_src_mem), &ram->base.former); if (ret) return ret; - ret = gk104_ram_calc_data(pfb, freq, &ram->base.target); + ret = gk104_ram_calc_data(fb, freq, &ram->base.target); if (ret) return ret; @@ -1061,13 +1061,13 @@ gk104_ram_calc(struct nvkm_fb *pfb, u32 freq) ram->base.next = &ram->base.target; } - return gk104_ram_calc_xits(pfb, ram->base.next); + return gk104_ram_calc_xits(fb, ram->base.next); } static void -gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) +gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) { - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = (void *)fb->ram; struct nvkm_ram_data *cfg; u32 mhz = freq / 1000; u32 mask, data; @@ -1089,31 +1089,31 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) data |= cfg->bios.rammap_11_09_01ff; mask |= 0x000001ff; } - nv_mask(pfb, 0x10f468, mask, data); + nv_mask(fb, 0x10f468, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) { data |= cfg->bios.rammap_11_0a_0400; mask |= 0x00000001; } - nv_mask(pfb, 0x10f420, mask, data); + nv_mask(fb, 0x10f420, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) { data |= cfg->bios.rammap_11_0a_0800; mask |= 0x00000001; } - nv_mask(pfb, 0x10f430, mask, data); + nv_mask(fb, 0x10f430, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) { data |= cfg->bios.rammap_11_0b_01f0; mask |= 0x0000001f; } - nv_mask(pfb, 0x10f400, mask, data); + nv_mask(fb, 0x10f400, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) { data |= cfg->bios.rammap_11_0b_0200 << 9; mask |= 0x00000200; } - nv_mask(pfb, 0x10f410, mask, data); + nv_mask(fb, 0x10f410, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0d) { data |= cfg->bios.rammap_11_0d << 16; @@ -1123,7 +1123,7 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) data |= cfg->bios.rammap_11_0f << 8; mask |= 0x0000ff00; } - nv_mask(pfb, 0x10f440, mask, data); + nv_mask(fb, 0x10f440, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0e) { data |= cfg->bios.rammap_11_0e << 8; @@ -1137,14 +1137,14 @@ gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq) data |= cfg->bios.rammap_11_0b_0400 << 5; mask |= 0x00000020; } - nv_mask(pfb, 0x10f444, mask, data); + nv_mask(fb, 0x10f444, mask, data); } static int -gk104_ram_prog(struct nvkm_fb *pfb) +gk104_ram_prog(struct nvkm_fb *fb) { - struct nvkm_device *device = nv_device(pfb); - struct gk104_ram *ram = (void *)pfb->ram; + struct nvkm_device *device = nv_device(fb); + struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; struct nvkm_ram_data *next = ram->base.next; @@ -1153,17 +1153,17 @@ gk104_ram_prog(struct nvkm_fb *pfb) return (ram->base.next == &ram->base.xition); } - gk104_ram_prog_0(pfb, 1000); + gk104_ram_prog_0(fb, 1000); ram_exec(fuc, true); - gk104_ram_prog_0(pfb, next->freq); + gk104_ram_prog_0(fb, next->freq); return (ram->base.next == &ram->base.xition); } static void -gk104_ram_tidy(struct nvkm_fb *pfb) +gk104_ram_tidy(struct nvkm_fb *fb) { - struct gk104_ram *ram = (void *)pfb->ram; + struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; ram->base.next = NULL; ram_exec(fuc, false); @@ -1182,10 +1182,10 @@ struct gk104_ram_train { }; static int -gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg, +gk104_ram_train_type(struct nvkm_fb *fb, int i, u8 ramcfg, struct gk104_ram_train *train) { - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_bios *bios = nvkm_bios(fb); struct nvbios_M0205E M0205E; struct nvbios_M0205S M0205S; struct nvbios_M0209E M0209E; @@ -1243,33 +1243,33 @@ gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg, } static int -gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train) +gk104_ram_train_init_0(struct nvkm_fb *fb, struct gk104_ram_train *train) { int i, j; if ((train->mask & 0x03d3) != 0x03d3) { - nv_warn(pfb, "missing link training data\n"); + nv_warn(fb, "missing link training data\n"); return -EINVAL; } for (i = 0; i < 0x30; i++) { for (j = 0; j < 8; j += 4) { - nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8)); - nv_wr32(pfb, 0x10f920 + j, 0x00000000 | + nv_wr32(fb, 0x10f968 + j, 0x00000000 | (i << 8)); + nv_wr32(fb, 0x10f920 + j, 0x00000000 | train->type08.data[i] << 4 | train->type06.data[i]); - nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]); - nv_wr32(pfb, 0x10f920 + j, 0x00000100 | + nv_wr32(fb, 0x10f918 + j, train->type00.data[i]); + nv_wr32(fb, 0x10f920 + j, 0x00000100 | train->type09.data[i] << 4 | train->type07.data[i]); - nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]); + nv_wr32(fb, 0x10f918 + j, train->type01.data[i]); } } for (j = 0; j < 8; j += 4) { for (i = 0; i < 0x100; i++) { - nv_wr32(pfb, 0x10f968 + j, i); - nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]); + nv_wr32(fb, 0x10f968 + j, i); + nv_wr32(fb, 0x10f900 + j, train->type04.data[i]); } } @@ -1277,23 +1277,24 @@ gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train) } static int -gk104_ram_train_init(struct nvkm_fb *pfb) +gk104_ram_train_init(struct nvkm_fb *fb) { - u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb)); + u8 ramcfg = nvbios_ramcfg_index(nv_subdev(fb)); struct gk104_ram_train *train; - int ret = -ENOMEM, i; + int ret, i; - if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) { - for (i = 0; i < 0x100; i++) { - ret = gk104_ram_train_type(pfb, i, ramcfg, train); - if (ret && ret != -ENOENT) - break; - } + if (!(train = kzalloc(sizeof(*train), GFP_KERNEL))) + return -ENOMEM; + + for (i = 0; i < 0x100; i++) { + ret = gk104_ram_train_type(fb, i, ramcfg, train); + if (ret && ret != -ENOENT) + break; } - switch (pfb->ram->type) { + switch (fb->ram->type) { case NV_MEM_TYPE_GDDR5: - ret = gk104_ram_train_init_0(pfb, train); + ret = gk104_ram_train_init_0(fb, train); break; default: ret = 0; @@ -1307,9 +1308,9 @@ gk104_ram_train_init(struct nvkm_fb *pfb) int gk104_ram_init(struct nvkm_object *object) { - struct nvkm_fb *pfb = (void *)object->parent; + struct nvkm_fb *fb = (void *)object->parent; struct gk104_ram *ram = (void *)object; - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_bios *bios = nvkm_bios(fb); u8 ver, hdr, cnt, len, snr, ssz; u32 data, save; int ret, i; @@ -1335,31 +1336,31 @@ gk104_ram_init(struct nvkm_object *object) cnt = nv_ro08(bios, data + 0x14); /* guess at count */ data = nv_ro32(bios, data + 0x10); /* guess u32... */ - save = nv_rd32(pfb, 0x10f65c) & 0x000000f0; + save = nv_rd32(fb, 0x10f65c) & 0x000000f0; for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) { - nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4); + nv_mask(fb, 0x10f65c, 0x000000f0, i << 4); nvbios_exec(&(struct nvbios_init) { - .subdev = nv_subdev(pfb), + .subdev = nv_subdev(fb), .bios = bios, .offset = nv_ro32(bios, data), .execute = 1, }); } } - nv_mask(pfb, 0x10f65c, 0x000000f0, save); - nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000); - nv_wr32(pfb, 0x10ecc0, 0xffffffff); - nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010); + nv_mask(fb, 0x10f65c, 0x000000f0, save); + nv_mask(fb, 0x10f584, 0x11000000, 0x00000000); + nv_wr32(fb, 0x10ecc0, 0xffffffff); + nv_mask(fb, 0x10f160, 0x00000010, 0x00000010); - return gk104_ram_train_init(pfb); + return gk104_ram_train_init(fb); } static int gk104_ram_ctor_data(struct gk104_ram *ram, u8 ramcfg, int i) { - struct nvkm_fb *pfb = (void *)nv_object(ram)->parent; - struct nvkm_bios *bios = nvkm_bios(pfb); + struct nvkm_fb *fb = (void *)nv_object(ram)->parent; + struct nvkm_bios *bios = nvkm_bios(fb); struct nvkm_ram_data *cfg; struct nvbios_ramcfg *d = &ram->diff; struct nvbios_ramcfg *p, *n; @@ -1443,13 +1444,13 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nvkm_gpio *gpio = nvkm_gpio(pfb); + struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_gpio *gpio = nvkm_gpio(fb); struct dcb_gpio_func func; struct gk104_ram *ram; int ret, i; - u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb)); + u8 ramcfg = nvbios_ramcfg_index(nv_subdev(fb)); u32 tmp; ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram); @@ -1467,7 +1468,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->base.tidy = gk104_ram_tidy; break; default: - nv_warn(pfb, "reclocking of this RAM type is unsupported\n"); + nv_warn(fb, "reclocking of this RAM type is unsupported\n"); break; } @@ -1476,12 +1477,12 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * already without having to treat some of them differently to * the others.... */ - ram->parts = nv_rd32(pfb, 0x022438); - ram->pmask = nv_rd32(pfb, 0x022554); + ram->parts = nv_rd32(fb, 0x022438); + ram->pmask = nv_rd32(fb, 0x022554); ram->pnuts = 0; for (i = 0, tmp = 0; i < ram->parts; i++) { if (!(ram->pmask & (1 << i))) { - u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000)); + u32 cfg1 = nv_rd32(fb, 0x110204 + (i * 0x1000)); if (tmp && tmp != cfg1) { ram->pnuts |= (1 << i); continue; @@ -1504,7 +1505,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (i = 0; !ret; i++) { ret = gk104_ram_ctor_data(ram, ramcfg, i); if (ret && ret != -ENOENT) { - nv_error(pfb, "failed to parse ramcfg data\n"); + nv_error(fb, "failed to parse ramcfg data\n"); return ret; } } @@ -1512,13 +1513,13 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* parse bios data for both pll's */ ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); if (ret) { - nv_error(pfb, "mclk refpll data not found\n"); + nv_error(fb, "mclk refpll data not found\n"); return ret; } ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll); if (ret) { - nv_error(pfb, "mclk pll data not found\n"); + nv_error(fb, "mclk pll data not found\n"); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c index a298b39f55c5e..40079eb44e703 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c @@ -23,16 +23,12 @@ */ #include "gf100.h" -struct gm107_ram { - struct nvkm_ram base; -}; - static int gm107_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gm107_ram *ram; + struct nvkm_ram *ram; int ret; ret = gf100_ram_create(parent, engine, oclass, 0x021c14, &ram); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 1d604c075a3ce..2195e4be68eba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -153,13 +153,13 @@ gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) * Link training for (at least) DDR3 */ int -gt215_link_train(struct nvkm_fb *pfb) +gt215_link_train(struct nvkm_fb *fb) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gt215_ram *ram = (void *)pfb->ram; - struct nvkm_clk *clk = nvkm_clk(pfb); + struct nvkm_bios *bios = nvkm_bios(fb); + struct gt215_ram *ram = (void *)fb->ram; + struct nvkm_clk *clk = nvkm_clk(fb); struct gt215_ltrain *train = &ram->ltrain; - struct nvkm_device *device = nv_device(pfb); + struct nvkm_device *device = nv_device(fb); struct gt215_ramfuc *fuc = &ram->fuc; u32 *result, r1700; int ret, i; @@ -181,8 +181,10 @@ gt215_link_train(struct nvkm_fb *pfb) /* Clock speeds for training and back */ nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T); - if (M0205T.freq == 0) + if (M0205T.freq == 0) { + kfree(result); return -ENOENT; + } clk_current = clk->read(clk, nv_clk_src_mem); @@ -191,17 +193,17 @@ gt215_link_train(struct nvkm_fb *pfb) goto out; /* First: clock up/down */ - ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000); + ret = ram->base.calc(fb, (u32) M0205T.freq * 1000); if (ret) goto out; /* Do this *after* calc, eliminates write in script */ - nv_wr32(pfb, 0x111400, 0x00000000); + nv_wr32(fb, 0x111400, 0x00000000); /* XXX: Magic writes that improve train reliability? */ - nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000); - nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000); - nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000); - nv_wr32(pfb, 0x100c04, 0x00000400); + nv_mask(fb, 0x100674, 0x0000ffff, 0x00000000); + nv_mask(fb, 0x1005e4, 0x0000ffff, 0x00000000); + nv_mask(fb, 0x100b0c, 0x000000ff, 0x00000000); + nv_wr32(fb, 0x100c04, 0x00000400); /* Now the training script */ r1700 = ram_rd32(fuc, 0x001700); @@ -234,21 +236,21 @@ gt215_link_train(struct nvkm_fb *pfb) ram_exec(fuc, true); - ram->base.calc(pfb, clk_current); + ram->base.calc(fb, clk_current); ram_exec(fuc, true); /* Post-processing, avoids flicker */ - nv_mask(pfb, 0x616308, 0x10, 0x10); - nv_mask(pfb, 0x616b08, 0x10, 0x10); + nv_mask(fb, 0x616308, 0x10, 0x10); + nv_mask(fb, 0x616b08, 0x10, 0x10); gt215_clk_post(clk, f); - ram_train_result(pfb, result, 64); + ram_train_result(fb, result, 64); for (i = 0; i < 64; i++) - nv_debug(pfb, "Train: %08x", result[i]); + nv_debug(fb, "Train: %08x", result[i]); gt215_link_train_calc(result, train); - nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720, + nv_debug(fb, "Train: %08x %08x %08x", train->r_100720, train->r_1111e0, train->r_111400); kfree(result); @@ -264,11 +266,12 @@ out: train->state = NVA3_TRAIN_UNSUPPORTED; gt215_clk_post(clk, f); + kfree(result); return ret; } int -gt215_link_train_init(struct nvkm_fb *pfb) +gt215_link_train_init(struct nvkm_fb *fb) { static const u32 pattern[16] = { 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, @@ -276,8 +279,8 @@ gt215_link_train_init(struct nvkm_fb *pfb) 0x33333333, 0x55555555, 0x77777777, 0x66666666, 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, }; - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gt215_ram *ram = (void *)pfb->ram; + struct nvkm_bios *bios = nvkm_bios(fb); + struct gt215_ram *ram = (void *)fb->ram; struct gt215_ltrain *train = &ram->ltrain; struct nvkm_mem *mem; struct nvbios_M0205E M0205E; @@ -297,48 +300,48 @@ gt215_link_train_init(struct nvkm_fb *pfb) train->state = NVA3_TRAIN_ONCE; - ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem); + ret = fb->ram->get(fb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem); if (ret) return ret; mem = ram->ltrain.mem; - nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16)); - nv_wr32(pfb, 0x1005a8, 0x0000ffff); - nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001); + nv_wr32(fb, 0x100538, 0x10000000 | (mem->offset >> 16)); + nv_wr32(fb, 0x1005a8, 0x0000ffff); + nv_mask(fb, 0x10f800, 0x00000001, 0x00000001); for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f8c0, (i << 8) | i); - nv_wr32(pfb, 0x10f900, pattern[i % 16]); + nv_wr32(fb, 0x10f8c0, (i << 8) | i); + nv_wr32(fb, 0x10f900, pattern[i % 16]); } for (i = 0; i < 0x30; i++) { - nv_wr32(pfb, 0x10f8e0, (i << 8) | i); - nv_wr32(pfb, 0x10f920, pattern[i % 16]); + nv_wr32(fb, 0x10f8e0, (i << 8) | i); + nv_wr32(fb, 0x10f920, pattern[i % 16]); } /* And upload the pattern */ - r001700 = nv_rd32(pfb, 0x1700); - nv_wr32(pfb, 0x1700, mem->offset >> 16); + r001700 = nv_rd32(fb, 0x1700); + nv_wr32(fb, 0x1700, mem->offset >> 16); for (i = 0; i < 16; i++) - nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]); + nv_wr32(fb, 0x700000 + (i << 2), pattern[i]); for (i = 0; i < 16; i++) - nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]); - nv_wr32(pfb, 0x1700, r001700); + nv_wr32(fb, 0x700100 + (i << 2), pattern[i]); + nv_wr32(fb, 0x1700, r001700); - train->r_100720 = nv_rd32(pfb, 0x100720); - train->r_1111e0 = nv_rd32(pfb, 0x1111e0); - train->r_111400 = nv_rd32(pfb, 0x111400); + train->r_100720 = nv_rd32(fb, 0x100720); + train->r_1111e0 = nv_rd32(fb, 0x1111e0); + train->r_111400 = nv_rd32(fb, 0x111400); return 0; } void -gt215_link_train_fini(struct nvkm_fb *pfb) +gt215_link_train_fini(struct nvkm_fb *fb) { - struct gt215_ram *ram = (void *)pfb->ram; + struct gt215_ram *ram = (void *)fb->ram; if (ram->ltrain.mem) - pfb->ram->put(pfb, &ram->ltrain.mem); + fb->ram->put(fb, &ram->ltrain.mem); } /* @@ -346,17 +349,17 @@ gt215_link_train_fini(struct nvkm_fb *pfb) */ #define T(t) cfg->timing_10_##t static int -gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) +gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) { - struct gt215_ram *ram = (void *)pfb->ram; + struct gt215_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; int tUNK_base, tUNK_40_0, prevCL; u32 cur2, cur3, cur7, cur8; - cur2 = nv_rd32(pfb, 0x100228); - cur3 = nv_rd32(pfb, 0x10022c); - cur7 = nv_rd32(pfb, 0x10023c); - cur8 = nv_rd32(pfb, 0x100240); + cur2 = nv_rd32(fb, 0x100228); + cur3 = nv_rd32(fb, 0x10022c); + cur7 = nv_rd32(fb, 0x10023c); + cur8 = nv_rd32(fb, 0x100240); switch ((!T(CWL)) * ram->base.type) { @@ -411,11 +414,11 @@ gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) break; } - nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n", + nv_debug(fb, "Entry: 220: %08x %08x %08x %08x\n", timing[0], timing[1], timing[2], timing[3]); - nv_debug(pfb, " 230: %08x %08x %08x %08x\n", + nv_debug(fb, " 230: %08x %08x %08x %08x\n", timing[4], timing[5], timing[6], timing[7]); - nv_debug(pfb, " 240: %08x\n", timing[8]); + nv_debug(fb, " 240: %08x\n", timing[8]); return 0; } #undef T @@ -465,7 +468,7 @@ gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk) static void gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) { - struct nvkm_gpio *gpio = nvkm_gpio(fuc->base.pfb); + struct nvkm_gpio *gpio = nvkm_gpio(fuc->base.fb); struct dcb_gpio_func func; u32 reg, sh, gpio_val; int ret; @@ -486,10 +489,10 @@ gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) } static int -gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) +gt215_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct gt215_ram *ram = (void *)pfb->ram; + struct nvkm_bios *bios = nvkm_bios(fb); + struct gt215_ram *ram = (void *)fb->ram; struct gt215_ramfuc *fuc = &ram->fuc; struct gt215_ltrain *train = &ram->ltrain; struct gt215_clk_info mclk; @@ -507,28 +510,27 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram->base.next = next; if (ram->ltrain.state == NVA3_TRAIN_ONCE) - gt215_link_train(pfb); + gt215_link_train(fb); /* lookup memory config data relevant to the target frequency */ - i = 0; data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x05) { - nv_error(pfb, "invalid/missing rammap entry\n"); + nv_error(fb, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); + strap = nvbios_ramcfg_index(nv_subdev(fb)); if (strap >= cnt) { - nv_error(pfb, "invalid ramcfg strap\n"); + nv_error(fb, "invalid ramcfg strap\n"); return -EINVAL; } data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, &ver, &hdr, &next->bios); if (!data || ver != 0x10 || hdr < 0x09) { - nv_error(pfb, "invalid/missing ramcfg entry\n"); + nv_error(fb, "invalid/missing ramcfg entry\n"); return -EINVAL; } @@ -538,20 +540,20 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x17) { - nv_error(pfb, "invalid/missing timing entry\n"); + nv_error(fb, "invalid/missing timing entry\n"); return -EINVAL; } } - ret = gt215_pll_info(nvkm_clk(pfb), 0x12, 0x4000, freq, &mclk); + ret = gt215_pll_info(nvkm_clk(fb), 0x12, 0x4000, freq, &mclk); if (ret < 0) { - nv_error(pfb, "failed mclk calculation\n"); + nv_error(fb, "failed mclk calculation\n"); return ret; } - gt215_ram_timing_calc(pfb, timing); + gt215_ram_timing_calc(fb, timing); - ret = ram_init(fuc, pfb); + ret = ram_init(fuc, fb); if (ret) return ret; @@ -649,7 +651,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_wr32(fuc, 0x1002dc, 0x00000001); ram_nsec(fuc, 2000); - if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000) + if (nv_device(fb)->chipset == 0xa3 && freq <= 500000) ram_mask(fuc, 0x100700, 0x00000006, 0x00000006); /* Fiddle with clocks */ @@ -707,7 +709,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) ram_mask(fuc, 0x1007e0, 0x22222222, r100760); } - if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) { + if (nv_device(fb)->chipset == 0xa3 && freq > 500000) { ram_mask(fuc, 0x100700, 0x00000006, 0x00000000); } @@ -752,7 +754,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) if (next->bios.ramcfg_10_02_04) { switch (ram->base.type) { case NV_MEM_TYPE_DDR3: - if (nv_device(pfb)->chipset != 0xa8) + if (nv_device(fb)->chipset != 0xa8) r111100 |= 0x00000004; /* no break */ case NV_MEM_TYPE_DDR2: @@ -768,7 +770,7 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) unk714 |= 0x00000010; break; case NV_MEM_TYPE_DDR3: - if (nv_device(pfb)->chipset == 0xa8) { + if (nv_device(fb)->chipset == 0xa8) { r111100 |= 0x08000000; } else { r111100 &= ~0x00000004; @@ -854,24 +856,24 @@ gt215_ram_calc(struct nvkm_fb *pfb, u32 freq) } static int -gt215_ram_prog(struct nvkm_fb *pfb) +gt215_ram_prog(struct nvkm_fb *fb) { - struct nvkm_device *device = nv_device(pfb); - struct gt215_ram *ram = (void *)pfb->ram; + struct nvkm_device *device = nv_device(fb); + struct gt215_ram *ram = (void *)fb->ram; struct gt215_ramfuc *fuc = &ram->fuc; bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true); if (exec) { - nv_mask(pfb, 0x001534, 0x2, 0x2); + nv_mask(fb, 0x001534, 0x2, 0x2); ram_exec(fuc, true); /* Post-processing, avoids flicker */ - nv_mask(pfb, 0x002504, 0x1, 0x0); - nv_mask(pfb, 0x001534, 0x2, 0x0); + nv_mask(fb, 0x002504, 0x1, 0x0); + nv_mask(fb, 0x001534, 0x2, 0x0); - nv_mask(pfb, 0x616308, 0x10, 0x10); - nv_mask(pfb, 0x616b08, 0x10, 0x10); + nv_mask(fb, 0x616308, 0x10, 0x10); + nv_mask(fb, 0x616b08, 0x10, 0x10); } else { ram_exec(fuc, false); } @@ -879,9 +881,9 @@ gt215_ram_prog(struct nvkm_fb *pfb) } static void -gt215_ram_tidy(struct nvkm_fb *pfb) +gt215_ram_tidy(struct nvkm_fb *fb) { - struct gt215_ram *ram = (void *)pfb->ram; + struct gt215_ram *ram = (void *)fb->ram; struct gt215_ramfuc *fuc = &ram->fuc; ram_exec(fuc, false); } @@ -889,7 +891,7 @@ gt215_ram_tidy(struct nvkm_fb *pfb) static int gt215_ram_init(struct nvkm_object *object) { - struct nvkm_fb *pfb = (void *)object->parent; + struct nvkm_fb *fb = (void *)object->parent; struct gt215_ram *ram = (void *)object; int ret; @@ -897,17 +899,17 @@ gt215_ram_init(struct nvkm_object *object) if (ret) return ret; - gt215_link_train_init(pfb); + gt215_link_train_init(fb); return 0; } static int gt215_ram_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_fb *pfb = (void *)object->parent; + struct nvkm_fb *fb = (void *)object->parent; if (!suspend) - gt215_link_train_fini(pfb); + gt215_link_train_fini(fb); return 0; } @@ -917,8 +919,8 @@ gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 datasize, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); - struct nvkm_gpio *gpio = nvkm_gpio(pfb); + struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_gpio *gpio = nvkm_gpio(fb); struct dcb_gpio_func func; struct gt215_ram *ram; int ret, i; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c index abc18e89a97c7..7f378788d3e51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c @@ -23,7 +23,7 @@ */ #include "nv50.h" -struct mcp77_ram_priv { +struct mcp77_ram { struct nvkm_ram base; u64 poller_base; }; @@ -35,58 +35,58 @@ mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, { u32 rsvd_head = ( 256 * 1024); /* vga memory */ u32 rsvd_tail = (1024 * 1024); /* vbios etc */ - struct nvkm_fb *pfb = nvkm_fb(parent); - struct mcp77_ram_priv *priv; + struct nvkm_fb *fb = nvkm_fb(parent); + struct mcp77_ram *ram; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_ram_create(parent, engine, oclass, &ram); + *pobject = nv_object(fb); if (ret) return ret; - priv->base.type = NV_MEM_TYPE_STOLEN; - priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12; - priv->base.size = (u64)nv_rd32(pfb, 0x100e14) << 12; + ram->base.type = NV_MEM_TYPE_STOLEN; + ram->base.stolen = (u64)nv_rd32(fb, 0x100e10) << 12; + ram->base.size = (u64)nv_rd32(fb, 0x100e14) << 12; rsvd_tail += 0x1000; - priv->poller_base = priv->base.size - rsvd_tail; + ram->poller_base = ram->base.size - rsvd_tail; - ret = nvkm_mm_init(&pfb->vram, rsvd_head >> 12, - (priv->base.size - (rsvd_head + rsvd_tail)) >> 12, + ret = nvkm_mm_init(&fb->vram, rsvd_head >> 12, + (ram->base.size - (rsvd_head + rsvd_tail)) >> 12, 1); if (ret) return ret; - priv->base.get = nv50_ram_get; - priv->base.put = nv50_ram_put; + ram->base.get = nv50_ram_get; + ram->base.put = nv50_ram_put; return 0; } static int mcp77_ram_init(struct nvkm_object *object) { - struct nvkm_fb *pfb = nvkm_fb(object); - struct mcp77_ram_priv *priv = (void *)object; + struct nvkm_fb *fb = nvkm_fb(object); + struct mcp77_ram *ram = (void *)object; int ret; u64 dniso, hostnb, flush; - ret = nvkm_ram_init(&priv->base); + ret = nvkm_ram_init(&ram->base); if (ret) return ret; - dniso = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1; - hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1; - flush = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1; + dniso = ((ram->base.size - (ram->poller_base + 0x00)) >> 5) - 1; + hostnb = ((ram->base.size - (ram->poller_base + 0x20)) >> 5) - 1; + flush = ((ram->base.size - (ram->poller_base + 0x40)) >> 5) - 1; /* Enable NISO poller for various clients and set their associated * read address, only for MCP77/78 and MCP79/7A. (fd#25701) */ - nv_wr32(pfb, 0x100c18, dniso); - nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001); - nv_wr32(pfb, 0x100c1c, hostnb); - nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002); - nv_wr32(pfb, 0x100c24, flush); - nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000); + nv_wr32(fb, 0x100c18, dniso); + nv_mask(fb, 0x100c14, 0x00000000, 0x00000001); + nv_wr32(fb, 0x100c1c, hostnb); + nv_mask(fb, 0x100c14, 0x00000000, 0x00000002); + nv_wr32(fb, 0x100c24, flush); + nv_mask(fb, 0x100c14, 0x00000000, 0x00010000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c index 855de1617229a..12311c56c4a7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c @@ -29,9 +29,9 @@ nv04_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; - u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0); + u32 boot0 = nv_rd32(fb, NV04_PFB_BOOT_0); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c index 3b8a1eda5b641..0999ac2e47715 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c @@ -28,9 +28,9 @@ nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; - u32 cfg0 = nv_rd32(pfb, 0x100200); + u32 cfg0 = nv_rd32(fb, 0x100200); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -43,7 +43,7 @@ nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, else ram->type = NV_MEM_TYPE_SDRAM; - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->size = nv_rd32(fb, 0x10020c) & 0xff000000; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c index 8bb7e432ad044..98b14b03d743c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c @@ -28,7 +28,7 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; struct pci_dev *bridge; u32 mem, mib; @@ -36,7 +36,7 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); if (!bridge) { - nv_fatal(pfb, "no bridge device\n"); + nv_fatal(fb, "no bridge device\n"); return -ENODEV; } @@ -45,7 +45,7 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - if (nv_device(pfb)->chipset == 0x1a) { + if (nv_device(fb)->chipset == 0x1a) { pci_read_config_dword(bridge, 0x7c, &mem); mib = ((mem >> 6) & 31) + 1; } else { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c index d9e7187bd2354..929fa1678444f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c @@ -28,9 +28,9 @@ nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; - u32 pbus1218 = nv_rd32(pfb, 0x001218); + u32 pbus1218 = nv_rd32(fb, 0x001218); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -44,9 +44,9 @@ nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break; } - ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000); - ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->tags = nv_rd32(pfb, 0x100320); + ram->size = (nv_rd32(fb, 0x10020c) & 0xff000000); + ram->parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; + ram->tags = nv_rd32(fb, 0x100320); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index a36a90c29ba90..bf795846bd8ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -31,21 +31,21 @@ #include int -nv40_ram_calc(struct nvkm_fb *pfb, u32 freq) +nv40_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nv40_ram *ram = (void *)pfb->ram; + struct nvkm_bios *bios = nvkm_bios(fb); + struct nv40_ram *ram = (void *)fb->ram; struct nvbios_pll pll; int N1, M1, N2, M2; int log2P, ret; ret = nvbios_pll_parse(bios, 0x04, &pll); if (ret) { - nv_error(pfb, "mclk pll data not found\n"); + nv_error(fb, "mclk pll data not found\n"); return ret; } - ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq, + ret = nv04_pll_calc(nv_subdev(fb), &pll, freq, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; @@ -64,10 +64,10 @@ nv40_ram_calc(struct nvkm_fb *pfb, u32 freq) } int -nv40_ram_prog(struct nvkm_fb *pfb) +nv40_ram_prog(struct nvkm_fb *fb) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nv40_ram *ram = (void *)pfb->ram; + struct nvkm_bios *bios = nvkm_bios(fb); + struct nv40_ram *ram = (void *)fb->ram; struct bit_entry M; u32 crtc_mask = 0; u8 sr1[2]; @@ -75,12 +75,12 @@ nv40_ram_prog(struct nvkm_fb *pfb) /* determine which CRTCs are active, fetch VGA_SR1 for each */ for (i = 0; i < 2; i++) { - u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000)); + u32 vbl = nv_rd32(fb, 0x600808 + (i * 0x2000)); u32 cnt = 0; do { - if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) { - nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); - sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000)); + if (vbl != nv_rd32(fb, 0x600808 + (i * 0x2000))) { + nv_wr08(fb, 0x0c03c4 + (i * 0x2000), 0x01); + sr1[i] = nv_rd08(fb, 0x0c03c5 + (i * 0x2000)); if (!(sr1[i] & 0x20)) crtc_mask |= (1 << i); break; @@ -93,53 +93,53 @@ nv40_ram_prog(struct nvkm_fb *pfb) for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) continue; - nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); - nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); + nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); + nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + nv_wr08(fb, 0x0c03c4 + (i * 0x2000), 0x01); + nv_wr08(fb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); } /* prepare ram for reclocking */ - nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */ - nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */ - nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */ - nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ - nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */ + nv_wr32(fb, 0x1002d4, 0x00000001); /* precharge */ + nv_wr32(fb, 0x1002d0, 0x00000001); /* refresh */ + nv_wr32(fb, 0x1002d0, 0x00000001); /* refresh */ + nv_mask(fb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ + nv_wr32(fb, 0x1002dc, 0x00000001); /* enable self-refresh */ /* change the PLL of each memory partition */ - nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000); - switch (nv_device(pfb)->chipset) { + nv_mask(fb, 0x00c040, 0x0000c000, 0x00000000); + switch (nv_device(fb)->chipset) { case 0x40: case 0x45: case 0x41: case 0x42: case 0x47: - nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl); - nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl); - nv_wr32(pfb, 0x004048, ram->coef); - nv_wr32(pfb, 0x004030, ram->coef); + nv_mask(fb, 0x004044, 0xc0771100, ram->ctrl); + nv_mask(fb, 0x00402c, 0xc0771100, ram->ctrl); + nv_wr32(fb, 0x004048, ram->coef); + nv_wr32(fb, 0x004030, ram->coef); case 0x43: case 0x49: case 0x4b: - nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl); - nv_wr32(pfb, 0x00403c, ram->coef); + nv_mask(fb, 0x004038, 0xc0771100, ram->ctrl); + nv_wr32(fb, 0x00403c, ram->coef); default: - nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl); - nv_wr32(pfb, 0x004024, ram->coef); + nv_mask(fb, 0x004020, 0xc0771100, ram->ctrl); + nv_wr32(fb, 0x004024, ram->coef); break; } udelay(100); - nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000); + nv_mask(fb, 0x00c040, 0x0000c000, 0x0000c000); /* re-enable normal operation of memory controller */ - nv_wr32(pfb, 0x1002dc, 0x00000000); - nv_mask(pfb, 0x100210, 0x80000000, 0x80000000); + nv_wr32(fb, 0x1002dc, 0x00000000); + nv_mask(fb, 0x100210, 0x80000000, 0x80000000); udelay(100); /* execute memory reset script from vbios */ if (!bit_entry(bios, 'M', &M)) { struct nvbios_init init = { - .subdev = nv_subdev(pfb), + .subdev = nv_subdev(fb), .bios = bios, .offset = nv_ro16(bios, M.offset + 0x00), .execute = 1, @@ -154,16 +154,16 @@ nv40_ram_prog(struct nvkm_fb *pfb) for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) continue; - nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]); + nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + nv_wr08(fb, 0x0c03c4 + (i * 0x2000), 0x01); + nv_wr08(fb, 0x0c03c5 + (i * 0x2000), sr1[i]); } return 0; } void -nv40_ram_tidy(struct nvkm_fb *pfb) +nv40_ram_tidy(struct nvkm_fb *fb) { } @@ -172,9 +172,9 @@ nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 pbus1218 = nv_rd32(pfb, 0x001218); + u32 pbus1218 = nv_rd32(fb, 0x001218); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -189,9 +189,9 @@ nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break; } - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(pfb, 0x100320); + ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; + ram->base.parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; + ram->base.tags = nv_rd32(fb, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c index 33c612b1355fb..ba0bca729012e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c @@ -28,9 +28,9 @@ nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 pfb474 = nv_rd32(pfb, 0x100474); + u32 fb474 = nv_rd32(fb, 0x100474); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -38,16 +38,16 @@ nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - if (pfb474 & 0x00000004) + if (fb474 & 0x00000004) ram->base.type = NV_MEM_TYPE_GDDR3; - if (pfb474 & 0x00000002) + if (fb474 & 0x00000002) ram->base.type = NV_MEM_TYPE_DDR2; - if (pfb474 & 0x00000001) + if (fb474 & 0x00000001) ram->base.type = NV_MEM_TYPE_DDR1; - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(pfb, 0x100320); + ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; + ram->base.parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; + ram->base.tags = nv_rd32(fb, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c index f575a7246403e..ef84bafad5466 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c @@ -28,9 +28,9 @@ nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 pfb474 = nv_rd32(pfb, 0x100474); + u32 fb474 = nv_rd32(fb, 0x100474); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -38,14 +38,14 @@ nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - if (pfb474 & 0x00000004) + if (fb474 & 0x00000004) ram->base.type = NV_MEM_TYPE_GDDR3; - if (pfb474 & 0x00000002) + if (fb474 & 0x00000002) ram->base.type = NV_MEM_TYPE_DDR2; - if (pfb474 & 0x00000001) + if (fb474 & 0x00000001) ram->base.type = NV_MEM_TYPE_DDR1; - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c index 51b44cdb27327..75c62115260e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c @@ -28,9 +28,9 @@ nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 pfb914 = nv_rd32(pfb, 0x100914); + u32 fb914 = nv_rd32(fb, 0x100914); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -38,16 +38,16 @@ nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - switch (pfb914 & 0x00000003) { + switch (fb914 & 0x00000003) { case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break; case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break; case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break; case 0x00000003: break; } - ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(pfb, 0x100320); + ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; + ram->base.parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; + ram->base.tags = nv_rd32(fb, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c index f3ed1c60d7304..0eef65933ae77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c @@ -28,7 +28,7 @@ nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; int ret; @@ -37,7 +37,7 @@ nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000; + ram->size = nv_rd32(fb, 0x10020c) & 0xff000000; ram->type = NV_MEM_TYPE_STOLEN; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index fd0e9cecef62c..49e21cf57e226 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -66,18 +66,17 @@ struct nv50_ram { #define T(t) cfg->timing_10_##t static int -nv50_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) +nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) { - struct nv50_ram *ram = (void *)pfb->ram; + struct nv50_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; - u32 cur2, cur3, cur4, cur7, cur8; + u32 cur2, cur4, cur7, cur8; u8 unkt3b; - cur2 = nv_rd32(pfb, 0x100228); - cur3 = nv_rd32(pfb, 0x10022c); - cur4 = nv_rd32(pfb, 0x100230); - cur7 = nv_rd32(pfb, 0x10023c); - cur8 = nv_rd32(pfb, 0x100240); + cur2 = nv_rd32(fb, 0x100228); + cur4 = nv_rd32(fb, 0x100230); + cur7 = nv_rd32(fb, 0x10023c); + cur8 = nv_rd32(fb, 0x100240); switch ((!T(CWL)) * ram->base.type) { case NV_MEM_TYPE_DDR2: @@ -89,7 +88,7 @@ nv50_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) } /* XXX: N=1 is not proper statistics */ - if (nv_device(pfb)->chipset == 0xa0) { + if (nv_device(fb)->chipset == 0xa0) { unkt3b = 0x19 + ram->base.next->bios.rammap_00_16_40; timing[6] = (0x2d + T(CL) - T(CWL) + ram->base.next->bios.rammap_00_16_40) << 16 | @@ -126,19 +125,19 @@ nv50_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing) timing[8] = (cur8 & 0xffffff00); /* XXX: P.version == 1 only has DDR2 and GDDR3? */ - if (pfb->ram->type == NV_MEM_TYPE_DDR2) { + if (fb->ram->type == NV_MEM_TYPE_DDR2) { timing[5] |= (T(CL) + 3) << 8; timing[8] |= (T(CL) - 4); - } else if (pfb->ram->type == NV_MEM_TYPE_GDDR3) { + } else if (fb->ram->type == NV_MEM_TYPE_GDDR3) { timing[5] |= (T(CL) + 2) << 8; timing[8] |= (T(CL) - 2); } - nv_debug(pfb, " 220: %08x %08x %08x %08x\n", + nv_debug(fb, " 220: %08x %08x %08x %08x\n", timing[0], timing[1], timing[2], timing[3]); - nv_debug(pfb, " 230: %08x %08x %08x %08x\n", + nv_debug(fb, " 230: %08x %08x %08x %08x\n", timing[4], timing[5], timing[6], timing[7]); - nv_debug(pfb, " 240: %08x\n", timing[8]); + nv_debug(fb, " 240: %08x\n", timing[8]); return 0; } #undef T @@ -152,10 +151,10 @@ nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq) } static int -nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) +nv50_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(pfb); - struct nv50_ram *ram = (void *)pfb->ram; + struct nvkm_bios *bios = nvkm_bios(fb); + struct nv50_ram *ram = (void *)fb->ram; struct nv50_ramseq *hwsq = &ram->hwsq; struct nvbios_perfE perfE; struct nvbios_pll mpll; @@ -178,7 +177,7 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) &size, &perfE); if (!data || (ver < 0x25 || ver >= 0x40) || (size < 2)) { - nv_error(pfb, "invalid/missing perftab entry\n"); + nv_error(fb, "invalid/missing perftab entry\n"); return -EINVAL; } } while (perfE.memory < freq); @@ -186,16 +185,16 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) nvbios_rammapEp_from_perf(bios, data, hdr, &next->bios); /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(pfb)); + strap = nvbios_ramcfg_index(nv_subdev(fb)); if (strap >= cnt) { - nv_error(pfb, "invalid ramcfg strap\n"); + nv_error(fb, "invalid ramcfg strap\n"); return -EINVAL; } data = nvbios_rammapSp_from_perf(bios, data + hdr, size, strap, &next->bios); if (!data) { - nv_error(pfb, "invalid/missing rammap entry "); + nv_error(fb, "invalid/missing rammap entry "); return -EINVAL; } @@ -204,16 +203,16 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) data = nvbios_timingEp(bios, next->bios.ramcfg_timing, &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x12) { - nv_error(pfb, "invalid/missing timing entry " + nv_error(fb, "invalid/missing timing entry " "%02x %04x %02x %02x\n", strap, data, ver, hdr); return -EINVAL; } } - nv50_ram_timing_calc(pfb, timing); + nv50_ram_timing_calc(fb, timing); - ret = ram_init(hwsq, nv_subdev(pfb)); + ret = ram_init(hwsq, nv_subdev(fb)); if (ret) return ret; @@ -254,10 +253,10 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) ret = nvbios_pll_parse(bios, 0x004008, &mpll); mpll.vco2.max_freq = 0; - if (ret == 0) { - ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq, + if (ret >= 0) { + ret = nv04_pll_calc(nv_subdev(fb), &mpll, freq, &N1, &M1, &N2, &M2, &P); - if (ret == 0) + if (ret <= 0) ret = -EINVAL; } @@ -282,7 +281,7 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) next->bios.rammap_00_16_40 << 14); ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); ram_mask(hwsq, 0x004008, 0x91ff0000, r004008); - if (nv_device(pfb)->chipset >= 0x96) + if (nv_device(fb)->chipset >= 0x96) ram_wr32(hwsq, 0x100da0, r100da0); ram_nsec(hwsq, 64000); /*XXX*/ ram_nsec(hwsq, 32000); /*XXX*/ @@ -380,10 +379,10 @@ nv50_ram_calc(struct nvkm_fb *pfb, u32 freq) } static int -nv50_ram_prog(struct nvkm_fb *pfb) +nv50_ram_prog(struct nvkm_fb *fb) { - struct nvkm_device *device = nv_device(pfb); - struct nv50_ram *ram = (void *)pfb->ram; + struct nvkm_device *device = nv_device(fb); + struct nv50_ram *ram = (void *)fb->ram; struct nv50_ramseq *hwsq = &ram->hwsq; ram_exec(hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); @@ -391,15 +390,15 @@ nv50_ram_prog(struct nvkm_fb *pfb) } static void -nv50_ram_tidy(struct nvkm_fb *pfb) +nv50_ram_tidy(struct nvkm_fb *fb) { - struct nv50_ram *ram = (void *)pfb->ram; + struct nv50_ram *ram = (void *)fb->ram; struct nv50_ramseq *hwsq = &ram->hwsq; ram_exec(hwsq, false); } void -__nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem *mem) +__nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem *mem) { struct nvkm_mm_node *this; @@ -407,14 +406,14 @@ __nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem *mem) this = list_first_entry(&mem->regions, typeof(*this), rl_entry); list_del(&this->rl_entry); - nvkm_mm_free(&pfb->vram, &this); + nvkm_mm_free(&fb->vram, &this); } - nvkm_mm_free(&pfb->tags, &mem->tag); + nvkm_mm_free(&fb->tags, &mem->tag); } void -nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) +nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem **pmem) { struct nvkm_mem *mem = *pmem; @@ -422,19 +421,19 @@ nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem) if (unlikely(mem == NULL)) return; - mutex_lock(&pfb->base.mutex); - __nv50_ram_put(pfb, mem); - mutex_unlock(&pfb->base.mutex); + mutex_lock(&fb->subdev.mutex); + __nv50_ram_put(fb, mem); + mutex_unlock(&fb->subdev.mutex); kfree(mem); } int -nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, +nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, u32 memtype, struct nvkm_mem **pmem) { - struct nvkm_mm *heap = &pfb->vram; - struct nvkm_mm *tags = &pfb->tags; + struct nvkm_mm *heap = &fb->vram; + struct nvkm_mm *tags = &fb->tags; struct nvkm_mm_node *r; struct nvkm_mem *mem; int comp = (memtype & 0x300) >> 8; @@ -450,7 +449,7 @@ nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, if (!mem) return -ENOMEM; - mutex_lock(&pfb->base.mutex); + mutex_lock(&fb->subdev.mutex); if (comp) { if (align == 16) { int n = (max >> 4) * comp; @@ -475,15 +474,15 @@ nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, else ret = nvkm_mm_head(heap, 0, type, max, min, align, &r); if (ret) { - mutex_unlock(&pfb->base.mutex); - pfb->ram->put(pfb, &mem); + mutex_unlock(&fb->subdev.mutex); + fb->ram->put(fb, &mem); return ret; } list_add_tail(&r->rl_entry, &mem->regions); max -= r->length; } while (max); - mutex_unlock(&pfb->base.mutex); + mutex_unlock(&fb->subdev.mutex); r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); mem->offset = (u64)r->offset << 12; @@ -492,17 +491,17 @@ nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin, } static u32 -nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram) +nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) { int colbits, rowbitsa, rowbitsb, banks; u64 rowsize, predicted; u32 r0, r4, rt, rblock_size; - r0 = nv_rd32(pfb, 0x100200); - r4 = nv_rd32(pfb, 0x100204); - rt = nv_rd32(pfb, 0x100250); - nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", - r0, r4, rt, nv_rd32(pfb, 0x001540)); + r0 = nv_rd32(fb, 0x100200); + r4 = nv_rd32(fb, 0x100204); + rt = nv_rd32(fb, 0x100250); + nv_debug(fb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", + r0, r4, rt, nv_rd32(fb, 0x001540)); colbits = (r4 & 0x0000f000) >> 12; rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; @@ -515,7 +514,7 @@ nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram) predicted += rowsize << rowbitsb; if (predicted != ram->size) { - nv_warn(pfb, "memory controller reports %d MiB VRAM\n", + nv_warn(fb, "memory controller reports %d MiB VRAM\n", (u32)(ram->size >> 20)); } @@ -523,7 +522,7 @@ nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram) if (rt & 1) rblock_size *= 3; - nv_debug(pfb, "rblock %d bytes\n", rblock_size); + nv_debug(fb, "rblock %d bytes\n", rblock_size); return rblock_size; } @@ -534,7 +533,7 @@ nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; int ret; @@ -543,13 +542,13 @@ nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ram->size = nv_rd32(pfb, 0x10020c); + ram->size = nv_rd32(fb, 0x10020c); ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); - ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16; + ram->part_mask = (nv_rd32(fb, 0x001540) & 0x00ff0000) >> 16; ram->parts = hweight8(ram->part_mask); - switch (nv_rd32(pfb, 0x100714) & 0x00000007) { + switch (nv_rd32(fb, 0x100714) & 0x00000007) { case 0: ram->type = NV_MEM_TYPE_DDR1; break; case 1: if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) @@ -564,14 +563,14 @@ nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, break; } - ret = nvkm_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) - + ret = nvkm_mm_init(&fb->vram, rsvd_head, (ram->size >> 12) - (rsvd_head + rsvd_tail), - nv50_fb_vram_rblock(pfb, ram) >> 12); + nv50_fb_vram_rblock(fb, ram) >> 12); if (ret) return ret; - ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1; - ram->tags = nv_rd32(pfb, 0x100320); + ram->ranks = (nv_rd32(fb, 0x100200) & 0x4) ? 2 : 1; + ram->tags = nv_rd32(fb, 0x100320); ram->get = nv50_ram_get; ram->put = nv50_ram_put; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 8404143f93ee4..b6c5e2d12f205 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -82,8 +82,8 @@ static void nv50_instobj_dtor(struct nvkm_object *object) { struct nv50_instobj_priv *node = (void *)object; - struct nvkm_fb *pfb = nvkm_fb(object); - pfb->ram->put(pfb, &node->mem); + struct nvkm_fb *fb = nvkm_fb(object); + fb->ram->put(fb, &node->mem); nvkm_instobj_destroy(&node->base); } @@ -92,7 +92,7 @@ nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_instobj_args *args = data; struct nv50_instobj_priv *node; int ret; @@ -105,7 +105,7 @@ nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem); + ret = fb->ram->get(fb, args->size, args->align, 0, 0x800, &node->mem); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index 7fb5ea0314cb4..a78ae4ea40081 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -132,12 +132,12 @@ gf100_ltc_init(struct nvkm_object *object) void gf100_ltc_dtor(struct nvkm_object *object) { - struct nvkm_fb *pfb = nvkm_fb(object); + struct nvkm_fb *fb = nvkm_fb(object); struct nvkm_ltc_priv *priv = (void *)object; nvkm_mm_fini(&priv->tags); - if (pfb->ram) - nvkm_mm_free(&pfb->vram, &priv->tag_ram); + if (fb->ram) + nvkm_mm_free(&fb->vram, &priv->tag_ram); nvkm_ltc_destroy(priv); } @@ -145,19 +145,19 @@ gf100_ltc_dtor(struct nvkm_object *object) /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ int -gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv) +gf100_ltc_init_tag_ram(struct nvkm_fb *fb, struct nvkm_ltc_priv *priv) { u32 tag_size, tag_margin, tag_align; int ret; /* No VRAM, no tags for now. */ - if (!pfb->ram) { + if (!fb->ram) { priv->num_tags = 0; goto mm_init; } /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ - priv->num_tags = (pfb->ram->size >> 17) / 4; + priv->num_tags = (fb->ram->size >> 17) / 4; if (priv->num_tags > (1 << 17)) priv->num_tags = 1 << 17; /* we have 17 bits in PTE */ priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */ @@ -177,7 +177,7 @@ gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv) tag_size += tag_align; tag_size = (tag_size + 0xfff) >> 12; /* round up */ - ret = nvkm_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1, + ret = nvkm_mm_tail(&fb->vram, 1, 1, tag_size, tag_size, 1, &priv->tag_ram); if (ret) { priv->num_tags = 0; @@ -200,7 +200,7 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ltc_priv *priv; u32 parts, mask; int ret, i; @@ -218,7 +218,7 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; - ret = gf100_ltc_init_tag_ram(pfb, priv); + ret = gf100_ltc_init_tag_ram(fb, priv); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 6b3f6f4ce1076..477190d274978 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -110,7 +110,7 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *pfb = nvkm_fb(parent); + struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ltc_priv *priv; u32 parts, mask; int ret, i; @@ -128,7 +128,7 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28; - ret = gf100_ltc_init_tag_ram(pfb, priv); + ret = gf100_ltc_init_tag_ram(fb, priv); if (ret) return ret; -- GitLab From ce7b4f60a84cfb1533f217198b01758aab05f4dc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5328/7006] drm/nouveau/fuse: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/fuse.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fuse/base.c | 13 +++------- .../gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c | 26 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c | 14 ++++------ .../gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c | 22 ++++++++-------- 5 files changed, 34 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h index a1384786adc98..ebfb6aa2a8559 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h @@ -4,7 +4,7 @@ #include struct nvkm_fuse { - struct nvkm_subdev base; + struct nvkm_subdev subdev; }; static inline struct nvkm_fuse * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c index b7b7193bbce7a..4c1884ee7e385 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c @@ -27,25 +27,20 @@ int _nvkm_fuse_init(struct nvkm_object *object) { struct nvkm_fuse *fuse = (void *)object; - return nvkm_subdev_init(&fuse->base); + return nvkm_subdev_init(&fuse->subdev); } void _nvkm_fuse_dtor(struct nvkm_object *object) { struct nvkm_fuse *fuse = (void *)object; - nvkm_subdev_destroy(&fuse->base); + nvkm_subdev_destroy(&fuse->subdev); } int nvkm_fuse_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_fuse *fuse; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "FUSE", - "fuse", length, pobject); - fuse = *pobject; - return ret; + return nvkm_subdev_create_(parent, engine, oclass, 0, "FUSE", + "fuse", length, pobject); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c index 393ef3a0faaf9..8f0eeb952e7aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c @@ -23,7 +23,7 @@ */ #include "priv.h" -struct gf100_fuse_priv { +struct gf100_fuse { struct nvkm_fuse base; spinlock_t fuse_enable_lock; @@ -32,18 +32,18 @@ struct gf100_fuse_priv { static u32 gf100_fuse_rd32(struct nvkm_object *object, u64 addr) { - struct gf100_fuse_priv *priv = (void *)object; + struct gf100_fuse *fuse = (void *)object; unsigned long flags; u32 fuse_enable, unk, val; /* racy if another part of nvkm start writing to these regs */ - spin_lock_irqsave(&priv->fuse_enable_lock, flags); - fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800); - unk = nv_mask(priv, 0x21000, 0x1, 0x1); - val = nv_rd32(priv, 0x21100 + addr); - nv_wr32(priv, 0x21000, unk); - nv_wr32(priv, 0x22400, fuse_enable); - spin_unlock_irqrestore(&priv->fuse_enable_lock, flags); + spin_lock_irqsave(&fuse->fuse_enable_lock, flags); + fuse_enable = nv_mask(fuse, 0x22400, 0x800, 0x800); + unk = nv_mask(fuse, 0x21000, 0x1, 0x1); + val = nv_rd32(fuse, 0x21100 + addr); + nv_wr32(fuse, 0x21000, unk); + nv_wr32(fuse, 0x22400, fuse_enable); + spin_unlock_irqrestore(&fuse->fuse_enable_lock, flags); return val; } @@ -53,15 +53,15 @@ gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_fuse_priv *priv; + struct gf100_fuse *fuse; int ret; - ret = nvkm_fuse_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fuse_create(parent, engine, oclass, &fuse); + *pobject = nv_object(fuse); if (ret) return ret; - spin_lock_init(&priv->fuse_enable_lock); + spin_lock_init(&fuse->fuse_enable_lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c index 0b256aa4960f7..e669b648e8fa8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c @@ -23,15 +23,11 @@ */ #include "priv.h" -struct gm107_fuse_priv { - struct nvkm_fuse base; -}; - static u32 gm107_fuse_rd32(struct nvkm_object *object, u64 addr) { - struct gf100_fuse_priv *priv = (void *)object; - return nv_rd32(priv, 0x21100 + addr); + struct nvkm_fuse *fuse = (void *)object; + return nv_rd32(fuse, 0x21100 + addr); } @@ -40,11 +36,11 @@ gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gm107_fuse_priv *priv; + struct nvkm_fuse *fuse; int ret; - ret = nvkm_fuse_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fuse_create(parent, engine, oclass, &fuse); + *pobject = nv_object(fuse); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c index 0d2afc4261002..ac9d5fd3e8d1b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c @@ -23,7 +23,7 @@ */ #include "priv.h" -struct nv50_fuse_priv { +struct nv50_fuse { struct nvkm_fuse base; spinlock_t fuse_enable_lock; @@ -32,16 +32,16 @@ struct nv50_fuse_priv { static u32 nv50_fuse_rd32(struct nvkm_object *object, u64 addr) { - struct nv50_fuse_priv *priv = (void *)object; + struct nv50_fuse *fuse = (void *)object; unsigned long flags; u32 fuse_enable, val; /* racy if another part of nvkm start writing to this reg */ - spin_lock_irqsave(&priv->fuse_enable_lock, flags); - fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800); - val = nv_rd32(priv, 0x21000 + addr); - nv_wr32(priv, 0x1084, fuse_enable); - spin_unlock_irqrestore(&priv->fuse_enable_lock, flags); + spin_lock_irqsave(&fuse->fuse_enable_lock, flags); + fuse_enable = nv_mask(fuse, 0x1084, 0x800, 0x800); + val = nv_rd32(fuse, 0x21000 + addr); + nv_wr32(fuse, 0x1084, fuse_enable); + spin_unlock_irqrestore(&fuse->fuse_enable_lock, flags); return val; } @@ -51,15 +51,15 @@ nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_fuse_priv *priv; + struct nv50_fuse *fuse; int ret; - ret = nvkm_fuse_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_fuse_create(parent, engine, oclass, &fuse); + *pobject = nv_object(fuse); if (ret) return ret; - spin_lock_init(&priv->fuse_enable_lock); + spin_lock_init(&fuse->fuse_enable_lock); return 0; } -- GitLab From e7d65181045898a6da80add0392765e253b0023c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5329/7006] drm/nouveau/gpio: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h index ca5099a81b5a2..f409cbb2bce78 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h @@ -19,7 +19,7 @@ struct nvkm_gpio_ntfy_rep { }; struct nvkm_gpio { - struct nvkm_subdev base; + struct nvkm_subdev subdev; struct nvkm_event event; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index f60284f3b8b50..1f10e7e773c27 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -43,7 +43,7 @@ static int nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { - struct nvkm_device *device = gpio->base.device; + struct nvkm_device *device = gpio->subdev.device; struct nvkm_bios *bios = nvkm_bios(gpio); u8 ver, len; u16 data; @@ -168,7 +168,7 @@ _nvkm_gpio_fini(struct nvkm_object *object, bool suspend) impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); impl->intr_stat(gpio, &mask, &mask); - return nvkm_subdev_fini(&gpio->base, suspend); + return nvkm_subdev_fini(&gpio->subdev, suspend); } static struct dmi_system_id gpio_reset_ids[] = { @@ -188,7 +188,7 @@ _nvkm_gpio_init(struct nvkm_object *object) struct nvkm_gpio *gpio = nvkm_gpio(object); int ret; - ret = nvkm_subdev_init(&gpio->base); + ret = nvkm_subdev_init(&gpio->subdev); if (ret) return ret; @@ -203,7 +203,7 @@ _nvkm_gpio_dtor(struct nvkm_object *object) { struct nvkm_gpio *gpio = (void *)object; nvkm_event_fini(&gpio->event); - nvkm_subdev_destroy(&gpio->base); + nvkm_subdev_destroy(&gpio->subdev); } int -- GitLab From 5b920d926422fdc5b40b703d72344d5e20b3872a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5330/7006] drm/nouveau/i2c: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/i2c.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 6 ++--- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c | 8 +++---- .../gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c | 24 ++++++++----------- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c | 20 +++++++--------- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c | 20 ++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h | 4 ---- 9 files changed, 38 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h index a2e33730f05ec..6b71cb6d59522 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h @@ -59,7 +59,7 @@ struct nvkm_i2c_board_info { }; struct nvkm_i2c { - struct nvkm_subdev base; + struct nvkm_subdev subdev; struct nvkm_event event; struct nvkm_i2c_port *(*find)(struct nvkm_i2c *, u8 index); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 3e2c2882d5153..187af1183f2d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -413,7 +413,7 @@ _nvkm_i2c_fini(struct nvkm_object *object, bool suspend) impl->aux_stat(i2c, &mask, &mask, &mask, &mask); } - return nvkm_subdev_fini(&i2c->base, suspend); + return nvkm_subdev_fini(&i2c->subdev, suspend); fail: list_for_each_entry_continue_reverse(port, &i2c->ports, head) { nv_ofuncs(port)->init(nv_object(port)); @@ -429,7 +429,7 @@ _nvkm_i2c_init(struct nvkm_object *object) struct nvkm_i2c_port *port; int ret; - ret = nvkm_subdev_init(&i2c->base); + ret = nvkm_subdev_init(&i2c->subdev); if (ret == 0) { list_for_each_entry(port, &i2c->ports, head) { ret = nv_ofuncs(port)->init(nv_object(port)); @@ -459,7 +459,7 @@ _nvkm_i2c_dtor(struct nvkm_object *object) nvkm_object_ref(NULL, (struct nvkm_object **)&port); } - nvkm_subdev_destroy(&i2c->base); + nvkm_subdev_destroy(&i2c->subdev); } static struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c index 2a2dd47b98355..be936479ff95c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c @@ -111,7 +111,7 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, AUX_DBG("%d: 0x%08x %d\n", type, addr, size); ret = auxch_init(aux, ch); - if (ret) + if (ret < 0) goto out; stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50)); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c index 4d4ac66381406..bf86502012631 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c @@ -26,17 +26,17 @@ static int gf110_i2c_sense_scl(struct nvkm_i2c_port *base) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000010); + return !!(nv_rd32(i2c, port->addr) & 0x00000010); } static int gf110_i2c_sense_sda(struct nvkm_i2c_port *base) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000020); + return !!(nv_rd32(i2c, port->addr) & 0x00000020); } static const struct nvkm_i2c_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c index ab64237b3842f..ece2529f8f868 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c @@ -81,7 +81,7 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, AUX_DBG("%d: 0x%08x %d\n", type, addr, size); ret = auxch_init(aux, ch); - if (ret) + if (ret < 0) goto out; stat = nv_rd32(aux, 0x00d958 + (ch * 0x50)); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c index 4cdf1c4893534..230727847c68b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c @@ -25,10 +25,6 @@ #include -struct nv04_i2c_priv { - struct nvkm_i2c base; -}; - struct nv04_i2c_port { struct nvkm_i2c_port base; u8 drive; @@ -38,39 +34,39 @@ struct nv04_i2c_port { static void nv04_i2c_drive_scl(struct nvkm_i2c_port *base, int state) { - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv04_i2c_port *port = (void *)base; - u8 val = nv_rdvgac(priv, 0, port->drive); + u8 val = nv_rdvgac(i2c, 0, port->drive); if (state) val |= 0x20; else val &= 0xdf; - nv_wrvgac(priv, 0, port->drive, val | 0x01); + nv_wrvgac(i2c, 0, port->drive, val | 0x01); } static void nv04_i2c_drive_sda(struct nvkm_i2c_port *base, int state) { - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv04_i2c_port *port = (void *)base; - u8 val = nv_rdvgac(priv, 0, port->drive); + u8 val = nv_rdvgac(i2c, 0, port->drive); if (state) val |= 0x10; else val &= 0xef; - nv_wrvgac(priv, 0, port->drive, val | 0x01); + nv_wrvgac(i2c, 0, port->drive, val | 0x01); } static int nv04_i2c_sense_scl(struct nvkm_i2c_port *base) { - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv04_i2c_port *port = (void *)base; - return !!(nv_rdvgac(priv, 0, port->sense) & 0x04); + return !!(nv_rdvgac(i2c, 0, port->sense) & 0x04); } static int nv04_i2c_sense_sda(struct nvkm_i2c_port *base) { - struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv04_i2c_port *port = (void *)base; - return !!(nv_rdvgac(priv, 0, port->sense) & 0x08); + return !!(nv_rdvgac(i2c, 0, port->sense) & 0x08); } static const struct nvkm_i2c_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c index 046fe5e2ea19e..ba3116f686fa1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c @@ -25,10 +25,6 @@ #include -struct nv4e_i2c_priv { - struct nvkm_i2c base; -}; - struct nv4e_i2c_port { struct nvkm_i2c_port base; u32 addr; @@ -37,33 +33,33 @@ struct nv4e_i2c_port { static void nv4e_i2c_drive_scl(struct nvkm_i2c_port *base, int state) { - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv4e_i2c_port *port = (void *)base; - nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01); + nv_mask(i2c, port->addr, 0x2f, state ? 0x21 : 0x01); } static void nv4e_i2c_drive_sda(struct nvkm_i2c_port *base, int state) { - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv4e_i2c_port *port = (void *)base; - nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01); + nv_mask(i2c, port->addr, 0x1f, state ? 0x11 : 0x01); } static int nv4e_i2c_sense_scl(struct nvkm_i2c_port *base) { - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv4e_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00040000); + return !!(nv_rd32(i2c, port->addr) & 0x00040000); } static int nv4e_i2c_sense_sda(struct nvkm_i2c_port *base) { - struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv4e_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00080000); + return !!(nv_rd32(i2c, port->addr) & 0x00080000); } static const struct nvkm_i2c_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c index fba5b26a56822..21f24864a6d2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c @@ -26,37 +26,37 @@ void nv50_i2c_drive_scl(struct nvkm_i2c_port *base, int state) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv50_i2c_port *port = (void *)base; if (state) port->state |= 0x01; else port->state &= 0xfe; - nv_wr32(priv, port->addr, port->state); + nv_wr32(i2c, port->addr, port->state); } void nv50_i2c_drive_sda(struct nvkm_i2c_port *base, int state) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv50_i2c_port *port = (void *)base; if (state) port->state |= 0x02; else port->state &= 0xfd; - nv_wr32(priv, port->addr, port->state); + nv_wr32(i2c, port->addr, port->state); } int nv50_i2c_sense_scl(struct nvkm_i2c_port *base) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000001); + return !!(nv_rd32(i2c, port->addr) & 0x00000001); } int nv50_i2c_sense_sda(struct nvkm_i2c_port *base) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(priv, port->addr) & 0x00000002); + return !!(nv_rd32(i2c, port->addr) & 0x00000002); } static const struct nvkm_i2c_func @@ -100,9 +100,9 @@ nv50_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int nv50_i2c_port_init(struct nvkm_object *object) { - struct nv50_i2c_priv *priv = (void *)nvkm_i2c(object); + struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); struct nv50_i2c_port *port = (void *)object; - nv_wr32(priv, port->addr, port->state); + nv_wr32(i2c, port->addr, port->state); return nvkm_i2c_port_init(&port->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h index b3139e721b027..520bafbf1a70e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h @@ -2,10 +2,6 @@ #define __NV50_I2C_H__ #include "priv.h" -struct nv50_i2c_priv { - struct nvkm_i2c base; -}; - struct nv50_i2c_port { struct nvkm_i2c_port base; u32 addr; -- GitLab From ac51596f27d5cece39cb63b857e6ebbffa05ca33 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5331/7006] drm/nouveau/ibus: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/ibus.h | 8 +- .../gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c | 66 +++++++-------- .../gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c | 84 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c | 48 +++++------ 4 files changed, 97 insertions(+), 109 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h index 2150d8af0040d..3538e87a44528 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h @@ -3,7 +3,7 @@ #include struct nvkm_ibus { - struct nvkm_subdev base; + struct nvkm_subdev subdev; }; static inline struct nvkm_ibus * @@ -16,11 +16,11 @@ nvkm_ibus(void *obj) nvkm_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus", \ sizeof(**d), (void **)d) #define nvkm_ibus_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) + nvkm_subdev_destroy(&(p)->subdev) #define nvkm_ibus_init(p) \ - nvkm_subdev_init(&(p)->base) + nvkm_subdev_init(&(p)->subdev) #define nvkm_ibus_fini(p,s) \ - nvkm_subdev_fini(&(p)->base, (s)) + nvkm_subdev_fini(&(p)->subdev, (s)) #define _nvkm_ibus_dtor _nvkm_subdev_dtor #define _nvkm_ibus_init _nvkm_subdev_init diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c index 8e578f802f666..d4c175dfc797e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c @@ -23,55 +23,51 @@ */ #include -struct gf100_ibus_priv { - struct nvkm_ibus base; -}; - static void -gf100_ibus_intr_hub(struct gf100_ibus_priv *priv, int i) +gf100_ibus_intr_hub(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400)); - u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400)); - u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400)); - nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); + u32 addr = nv_rd32(ibus, 0x122120 + (i * 0x0400)); + u32 data = nv_rd32(ibus, 0x122124 + (i * 0x0400)); + u32 stat = nv_rd32(ibus, 0x122128 + (i * 0x0400)); + nv_error(ibus, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(ibus, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr_rop(struct gf100_ibus_priv *priv, int i) +gf100_ibus_intr_rop(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400)); - u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400)); - u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400)); - nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); + u32 addr = nv_rd32(ibus, 0x124120 + (i * 0x0400)); + u32 data = nv_rd32(ibus, 0x124124 + (i * 0x0400)); + u32 stat = nv_rd32(ibus, 0x124128 + (i * 0x0400)); + nv_error(ibus, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(ibus, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr_gpc(struct gf100_ibus_priv *priv, int i) +gf100_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400)); - u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400)); - u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400)); - nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); + u32 addr = nv_rd32(ibus, 0x128120 + (i * 0x0400)); + u32 data = nv_rd32(ibus, 0x128124 + (i * 0x0400)); + u32 stat = nv_rd32(ibus, 0x128128 + (i * 0x0400)); + nv_error(ibus, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(ibus, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); } static void gf100_ibus_intr(struct nvkm_subdev *subdev) { - struct gf100_ibus_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0x121c58); - u32 intr1 = nv_rd32(priv, 0x121c5c); - u32 hubnr = nv_rd32(priv, 0x121c70); - u32 ropnr = nv_rd32(priv, 0x121c74); - u32 gpcnr = nv_rd32(priv, 0x121c78); + struct nvkm_ibus *ibus = (void *)subdev; + u32 intr0 = nv_rd32(ibus, 0x121c58); + u32 intr1 = nv_rd32(ibus, 0x121c5c); + u32 hubnr = nv_rd32(ibus, 0x121c70); + u32 ropnr = nv_rd32(ibus, 0x121c74); + u32 gpcnr = nv_rd32(ibus, 0x121c78); u32 i; for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { u32 stat = 0x00000100 << i; if (intr0 & stat) { - gf100_ibus_intr_hub(priv, i); + gf100_ibus_intr_hub(ibus, i); intr0 &= ~stat; } } @@ -79,7 +75,7 @@ gf100_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) { u32 stat = 0x00010000 << i; if (intr0 & stat) { - gf100_ibus_intr_rop(priv, i); + gf100_ibus_intr_rop(ibus, i); intr0 &= ~stat; } } @@ -87,7 +83,7 @@ gf100_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; intr1 && i < gpcnr; i++) { u32 stat = 0x00000001 << i; if (intr1 & stat) { - gf100_ibus_intr_gpc(priv, i); + gf100_ibus_intr_gpc(ibus, i); intr1 &= ~stat; } } @@ -98,15 +94,15 @@ gf100_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_ibus_priv *priv; + struct nvkm_ibus *ibus; int ret; - ret = nvkm_ibus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_ibus_create(parent, engine, oclass, &ibus); + *pobject = nv_object(ibus); if (ret) return ret; - nv_subdev(priv)->intr = gf100_ibus_intr; + nv_subdev(ibus)->intr = gf100_ibus_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c index 7b6e9a6cd7b20..4107d9d25a04a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c @@ -23,55 +23,51 @@ */ #include -struct gk104_ibus_priv { - struct nvkm_ibus base; -}; - static void -gk104_ibus_intr_hub(struct gk104_ibus_priv *priv, int i) +gk104_ibus_intr_hub(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800)); - u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800)); - u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800)); - nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); + u32 addr = nv_rd32(ibus, 0x122120 + (i * 0x0800)); + u32 data = nv_rd32(ibus, 0x122124 + (i * 0x0800)); + u32 stat = nv_rd32(ibus, 0x122128 + (i * 0x0800)); + nv_error(ibus, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(ibus, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr_rop(struct gk104_ibus_priv *priv, int i) +gk104_ibus_intr_rop(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800)); - u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800)); - u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800)); - nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); + u32 addr = nv_rd32(ibus, 0x124120 + (i * 0x0800)); + u32 data = nv_rd32(ibus, 0x124124 + (i * 0x0800)); + u32 stat = nv_rd32(ibus, 0x124128 + (i * 0x0800)); + nv_error(ibus, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(ibus, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr_gpc(struct gk104_ibus_priv *priv, int i) +gk104_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800)); - u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800)); - u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800)); - nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); + u32 addr = nv_rd32(ibus, 0x128120 + (i * 0x0800)); + u32 data = nv_rd32(ibus, 0x128124 + (i * 0x0800)); + u32 stat = nv_rd32(ibus, 0x128128 + (i * 0x0800)); + nv_error(ibus, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nv_mask(ibus, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); } static void gk104_ibus_intr(struct nvkm_subdev *subdev) { - struct gk104_ibus_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0x120058); - u32 intr1 = nv_rd32(priv, 0x12005c); - u32 hubnr = nv_rd32(priv, 0x120070); - u32 ropnr = nv_rd32(priv, 0x120074); - u32 gpcnr = nv_rd32(priv, 0x120078); + struct nvkm_ibus *ibus = (void *)subdev; + u32 intr0 = nv_rd32(ibus, 0x120058); + u32 intr1 = nv_rd32(ibus, 0x12005c); + u32 hubnr = nv_rd32(ibus, 0x120070); + u32 ropnr = nv_rd32(ibus, 0x120074); + u32 gpcnr = nv_rd32(ibus, 0x120078); u32 i; for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { u32 stat = 0x00000100 << i; if (intr0 & stat) { - gk104_ibus_intr_hub(priv, i); + gk104_ibus_intr_hub(ibus, i); intr0 &= ~stat; } } @@ -79,7 +75,7 @@ gk104_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) { u32 stat = 0x00010000 << i; if (intr0 & stat) { - gk104_ibus_intr_rop(priv, i); + gk104_ibus_intr_rop(ibus, i); intr0 &= ~stat; } } @@ -87,7 +83,7 @@ gk104_ibus_intr(struct nvkm_subdev *subdev) for (i = 0; intr1 && i < gpcnr; i++) { u32 stat = 0x00000001 << i; if (intr1 & stat) { - gk104_ibus_intr_gpc(priv, i); + gk104_ibus_intr_gpc(ibus, i); intr1 &= ~stat; } } @@ -96,16 +92,16 @@ gk104_ibus_intr(struct nvkm_subdev *subdev) static int gk104_ibus_init(struct nvkm_object *object) { - struct gk104_ibus_priv *priv = (void *)object; - int ret = nvkm_ibus_init(&priv->base); + struct nvkm_ibus *ibus = (void *)object; + int ret = nvkm_ibus_init(ibus); if (ret == 0) { - nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000); - nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200); - nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800); - nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100); - nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff); - nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200); - nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880); + nv_mask(ibus, 0x122318, 0x0003ffff, 0x00001000); + nv_mask(ibus, 0x12231c, 0x0003ffff, 0x00000200); + nv_mask(ibus, 0x122310, 0x0003ffff, 0x00000800); + nv_mask(ibus, 0x122348, 0x0003ffff, 0x00000100); + nv_mask(ibus, 0x1223b0, 0x0003ffff, 0x00000fff); + nv_mask(ibus, 0x122348, 0x0003ffff, 0x00000200); + nv_mask(ibus, 0x122358, 0x0003ffff, 0x00002880); } return ret; } @@ -115,15 +111,15 @@ gk104_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_ibus_priv *priv; + struct nvkm_ibus *ibus; int ret; - ret = nvkm_ibus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_ibus_create(parent, engine, oclass, &ibus); + *pobject = nv_object(ibus); if (ret) return ret; - nv_subdev(priv)->intr = gk104_ibus_intr; + nv_subdev(ibus)->intr = gk104_ibus_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index 24dcdfb58a8d8..7bdedc53e1b44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -22,61 +22,57 @@ #include #include -struct gk20a_ibus_priv { - struct nvkm_ibus base; -}; - static void -gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv) +gk20a_ibus_init_ibus_ring(struct nvkm_ibus *ibus) { - nv_mask(priv, 0x137250, 0x3f, 0); + nv_mask(ibus, 0x137250, 0x3f, 0); - nv_mask(priv, 0x000200, 0x20, 0); + nv_mask(ibus, 0x000200, 0x20, 0); usleep_range(20, 30); - nv_mask(priv, 0x000200, 0x20, 0x20); + nv_mask(ibus, 0x000200, 0x20, 0x20); - nv_wr32(priv, 0x12004c, 0x4); - nv_wr32(priv, 0x122204, 0x2); - nv_rd32(priv, 0x122204); + nv_wr32(ibus, 0x12004c, 0x4); + nv_wr32(ibus, 0x122204, 0x2); + nv_rd32(ibus, 0x122204); /* * Bug: increase clock timeout to avoid operation failure at high * gpcclk rate. */ - nv_wr32(priv, 0x122354, 0x800); - nv_wr32(priv, 0x128328, 0x800); - nv_wr32(priv, 0x124320, 0x800); + nv_wr32(ibus, 0x122354, 0x800); + nv_wr32(ibus, 0x128328, 0x800); + nv_wr32(ibus, 0x124320, 0x800); } static void gk20a_ibus_intr(struct nvkm_subdev *subdev) { - struct gk20a_ibus_priv *priv = (void *)subdev; - u32 status0 = nv_rd32(priv, 0x120058); + struct nvkm_ibus *ibus = (void *)subdev; + u32 status0 = nv_rd32(ibus, 0x120058); if (status0 & 0x7) { - nv_debug(priv, "resetting priv ring\n"); - gk20a_ibus_init_priv_ring(priv); + nv_debug(ibus, "resetting ibus ring\n"); + gk20a_ibus_init_ibus_ring(ibus); } /* Acknowledge interrupt */ - nv_mask(priv, 0x12004c, 0x2, 0x2); + nv_mask(ibus, 0x12004c, 0x2, 0x2); if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00)) - nv_warn(priv, "timeout waiting for ringmaster ack\n"); + nv_warn(ibus, "timeout waiting for ringmaster ack\n"); } static int gk20a_ibus_init(struct nvkm_object *object) { - struct gk20a_ibus_priv *priv = (void *)object; + struct nvkm_ibus *ibus = (void *)object; int ret; ret = _nvkm_ibus_init(object); if (ret) return ret; - gk20a_ibus_init_priv_ring(priv); + gk20a_ibus_init_ibus_ring(ibus); return 0; } @@ -86,15 +82,15 @@ gk20a_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk20a_ibus_priv *priv; + struct nvkm_ibus *ibus; int ret; - ret = nvkm_ibus_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_ibus_create(parent, engine, oclass, &ibus); + *pobject = nv_object(ibus); if (ret) return ret; - nv_subdev(priv)->intr = gk20a_ibus_intr; + nv_subdev(ibus)->intr = gk20a_ibus_intr; return 0; } -- GitLab From c44c06aeebf481fb69c665a21090f2f0aac878c5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:06 +1000 Subject: [PATCH 5332/7006] drm/nouveau/imem: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/instmem.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 2 +- .../drm/nouveau/nvkm/subdev/instmem/base.c | 18 +- .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 156 +++++++++--------- .../drm/nouveau/nvkm/subdev/instmem/nv04.c | 78 +++++---- .../drm/nouveau/nvkm/subdev/instmem/nv04.h | 6 +- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 60 +++---- .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 54 +++--- .../drm/nouveau/nvkm/subdev/instmem/priv.h | 10 +- 12 files changed, 194 insertions(+), 198 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index 1bcb763cfca0f..f9812a9e8a8cf 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -21,7 +21,7 @@ nv_memobj(void *obj) } struct nvkm_instmem { - struct nvkm_subdev base; + struct nvkm_subdev subdev; struct list_head list; u32 reserved; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index d157aaede4050..bdf635f9ab5f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -559,7 +559,7 @@ nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_instmem *imem = nv04_instmem(parent); struct nv04_fifo_priv *priv; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 48ce4af6f543c..3537accc927bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -143,7 +143,7 @@ nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_instmem *imem = nv04_instmem(parent); struct nv04_fifo_priv *priv; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 4a20a6fd3887b..e9c88da81f107 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -150,7 +150,7 @@ nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_instmem *imem = nv04_instmem(parent); struct nv04_fifo_priv *priv; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index a9bb6a53f9faa..f9456a5c762c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -268,7 +268,7 @@ nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem_priv *imem = nv04_instmem(parent); + struct nv04_instmem *imem = nv04_instmem(parent); struct nv04_fifo_priv *priv; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index d16358cc6cbba..43a8f4e19eb6b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -56,9 +56,9 @@ nvkm_instobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - mutex_lock(&imem->base.mutex); + mutex_lock(&imem->subdev.mutex); list_add(&iobj->head, &imem->list); - mutex_unlock(&imem->base.mutex); + mutex_unlock(&imem->subdev.mutex); return 0; } @@ -70,7 +70,7 @@ static int nvkm_instmem_alloc(struct nvkm_instmem *imem, struct nvkm_object *parent, u32 size, u32 align, struct nvkm_object **pobject) { - struct nvkm_instmem_impl *impl = (void *)imem->base.object.oclass; + struct nvkm_instmem_impl *impl = (void *)imem->subdev.object.oclass; struct nvkm_instobj_args args = { .size = size, .align = align }; return nvkm_object_ctor(parent, &parent->engine->subdev.object, impl->instobj, &args, sizeof(args), pobject); @@ -84,7 +84,7 @@ _nvkm_instmem_fini(struct nvkm_object *object, bool suspend) int i, ret = 0; if (suspend) { - mutex_lock(&imem->base.mutex); + mutex_lock(&imem->subdev.mutex); list_for_each_entry(iobj, &imem->list, head) { iobj->suspend = vmalloc(iobj->size); if (!iobj->suspend) { @@ -95,12 +95,12 @@ _nvkm_instmem_fini(struct nvkm_object *object, bool suspend) for (i = 0; i < iobj->size; i += 4) iobj->suspend[i / 4] = nv_ro32(iobj, i); } - mutex_unlock(&imem->base.mutex); + mutex_unlock(&imem->subdev.mutex); if (ret) return ret; } - return nvkm_subdev_fini(&imem->base, suspend); + return nvkm_subdev_fini(&imem->subdev, suspend); } int @@ -110,11 +110,11 @@ _nvkm_instmem_init(struct nvkm_object *object) struct nvkm_instobj *iobj; int ret, i; - ret = nvkm_subdev_init(&imem->base); + ret = nvkm_subdev_init(&imem->subdev); if (ret) return ret; - mutex_lock(&imem->base.mutex); + mutex_lock(&imem->subdev.mutex); list_for_each_entry(iobj, &imem->list, head) { if (iobj->suspend) { for (i = 0; i < iobj->size; i += 4) @@ -123,7 +123,7 @@ _nvkm_instmem_init(struct nvkm_object *object) iobj->suspend = NULL; } } - mutex_unlock(&imem->base.mutex); + mutex_unlock(&imem->subdev.mutex); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index cd8ab5fcb585f..abc41c0a4ad83 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -49,7 +49,7 @@ #include "priv.h" -struct gk20a_instobj_priv { +struct gk20a_instobj { struct nvkm_instobj base; /* Must be second member here - see nouveau_gpuobj_map_vm() */ struct nvkm_mem *mem; @@ -61,7 +61,7 @@ struct gk20a_instobj_priv { * Used for objects allocated using the DMA API */ struct gk20a_instobj_dma { - struct gk20a_instobj_priv base; + struct gk20a_instobj base; void *cpuaddr; dma_addr_t handle; @@ -72,13 +72,13 @@ struct gk20a_instobj_dma { * Used for objects flattened using the IOMMU API */ struct gk20a_instobj_iommu { - struct gk20a_instobj_priv base; + struct gk20a_instobj base; /* array of base.mem->size pages */ struct page *pages[]; }; -struct gk20a_instmem_priv { +struct gk20a_instmem { struct nvkm_instmem base; spinlock_t lock; u64 addr; @@ -105,60 +105,60 @@ struct gk20a_instmem_priv { static u32 gk20a_instobj_rd32(struct nvkm_object *object, u64 offset) { - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object); - struct gk20a_instobj_priv *node = (void *)object; + struct gk20a_instmem *imem = (void *)nvkm_instmem(object); + struct gk20a_instobj *node = (void *)object; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; u32 data; - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + spin_lock_irqsave(&imem->lock, flags); + if (unlikely(imem->addr != base)) { + nv_wr32(imem, 0x001700, base >> 16); + imem->addr = base; } - data = nv_rd32(priv, 0x700000 + addr); - spin_unlock_irqrestore(&priv->lock, flags); + data = nv_rd32(imem, 0x700000 + addr); + spin_unlock_irqrestore(&imem->lock, flags); return data; } static void gk20a_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) { - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(object); - struct gk20a_instobj_priv *node = (void *)object; + struct gk20a_instmem *imem = (void *)nvkm_instmem(object); + struct gk20a_instobj *node = (void *)object; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + spin_lock_irqsave(&imem->lock, flags); + if (unlikely(imem->addr != base)) { + nv_wr32(imem, 0x001700, base >> 16); + imem->addr = base; } - nv_wr32(priv, 0x700000 + addr, data); - spin_unlock_irqrestore(&priv->lock, flags); + nv_wr32(imem, 0x700000 + addr, data); + spin_unlock_irqrestore(&imem->lock, flags); } static void -gk20a_instobj_dtor_dma(struct gk20a_instobj_priv *_node) +gk20a_instobj_dtor_dma(struct gk20a_instobj *_node) { struct gk20a_instobj_dma *node = (void *)_node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); - struct device *dev = nv_device_base(nv_device(priv)); + struct gk20a_instmem *imem = (void *)nvkm_instmem(node); + struct device *dev = nv_device_base(nv_device(imem)); if (unlikely(!node->cpuaddr)) return; dma_free_attrs(dev, _node->mem->size << PAGE_SHIFT, node->cpuaddr, - node->handle, &priv->attrs); + node->handle, &imem->attrs); } static void -gk20a_instobj_dtor_iommu(struct gk20a_instobj_priv *_node) +gk20a_instobj_dtor_iommu(struct gk20a_instobj *_node) { struct gk20a_instobj_iommu *node = (void *)_node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); + struct gk20a_instmem *imem = (void *)nvkm_instmem(node); struct nvkm_mm_node *r; int i; @@ -169,28 +169,28 @@ gk20a_instobj_dtor_iommu(struct gk20a_instobj_priv *_node) rl_entry); /* clear bit 34 to unmap pages */ - r->offset &= ~BIT(34 - priv->iommu_pgshift); + r->offset &= ~BIT(34 - imem->iommu_pgshift); /* Unmap pages from GPU address space and free them */ for (i = 0; i < _node->mem->size; i++) { - iommu_unmap(priv->domain, - (r->offset + i) << priv->iommu_pgshift, PAGE_SIZE); + iommu_unmap(imem->domain, + (r->offset + i) << imem->iommu_pgshift, PAGE_SIZE); __free_page(node->pages[i]); } /* Release area from GPU address space */ - mutex_lock(priv->mm_mutex); - nvkm_mm_free(priv->mm, &r); - mutex_unlock(priv->mm_mutex); + mutex_lock(imem->mm_mutex); + nvkm_mm_free(imem->mm, &r); + mutex_unlock(imem->mm_mutex); } static void gk20a_instobj_dtor(struct nvkm_object *object) { - struct gk20a_instobj_priv *node = (void *)object; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(node); + struct gk20a_instobj *node = (void *)object; + struct gk20a_instmem *imem = (void *)nvkm_instmem(node); - if (priv->domain) + if (imem->domain) gk20a_instobj_dtor_iommu(node); else gk20a_instobj_dtor_dma(node); @@ -201,10 +201,10 @@ gk20a_instobj_dtor(struct nvkm_object *object) static int gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 npages, u32 align, - struct gk20a_instobj_priv **_node) + struct gk20a_instobj **_node) { struct gk20a_instobj_dma *node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); + struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); struct device *dev = nv_device_base(nv_device(parent)); int ret; @@ -216,15 +216,15 @@ gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, node->cpuaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT, &node->handle, GFP_KERNEL, - &priv->attrs); + &imem->attrs); if (!node->cpuaddr) { - nv_error(priv, "cannot allocate DMA memory\n"); + nv_error(imem, "cannot allocate DMA memory\n"); return -ENOMEM; } /* alignment check */ if (unlikely(node->handle & (align - 1))) - nv_warn(priv, "memory not aligned as requested: %pad (0x%x)\n", + nv_warn(imem, "memory not aligned as requested: %pad (0x%x)\n", &node->handle, align); /* present memory for being mapped using small pages */ @@ -243,10 +243,10 @@ gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, static int gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 npages, u32 align, - struct gk20a_instobj_priv **_node) + struct gk20a_instobj **_node) { struct gk20a_instobj_iommu *node; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); + struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); struct nvkm_mm_node *r; int ret; int i; @@ -269,38 +269,38 @@ gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, node->pages[i] = p; } - mutex_lock(priv->mm_mutex); + mutex_lock(imem->mm_mutex); /* Reserve area from GPU address space */ - ret = nvkm_mm_head(priv->mm, 0, 1, npages, npages, - align >> priv->iommu_pgshift, &r); - mutex_unlock(priv->mm_mutex); + ret = nvkm_mm_head(imem->mm, 0, 1, npages, npages, + align >> imem->iommu_pgshift, &r); + mutex_unlock(imem->mm_mutex); if (ret) { - nv_error(priv, "virtual space is full!\n"); + nv_error(imem, "virtual space is full!\n"); goto free_pages; } /* Map into GPU address space */ for (i = 0; i < npages; i++) { struct page *p = node->pages[i]; - u32 offset = (r->offset + i) << priv->iommu_pgshift; + u32 offset = (r->offset + i) << imem->iommu_pgshift; - ret = iommu_map(priv->domain, offset, page_to_phys(p), + ret = iommu_map(imem->domain, offset, page_to_phys(p), PAGE_SIZE, IOMMU_READ | IOMMU_WRITE); if (ret < 0) { - nv_error(priv, "IOMMU mapping failure: %d\n", ret); + nv_error(imem, "IOMMU mapping failure: %d\n", ret); while (i-- > 0) { offset -= PAGE_SIZE; - iommu_unmap(priv->domain, offset, PAGE_SIZE); + iommu_unmap(imem->domain, offset, PAGE_SIZE); } goto release_area; } } /* Bit 34 tells that an address is to be resolved through the IOMMU */ - r->offset |= BIT(34 - priv->iommu_pgshift); + r->offset |= BIT(34 - imem->iommu_pgshift); - node->base._mem.offset = ((u64)r->offset) << priv->iommu_pgshift; + node->base._mem.offset = ((u64)r->offset) << imem->iommu_pgshift; INIT_LIST_HEAD(&node->base._mem.regions); list_add_tail(&r->rl_entry, &node->base._mem.regions); @@ -308,9 +308,9 @@ gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, return 0; release_area: - mutex_lock(priv->mm_mutex); - nvkm_mm_free(priv->mm, &r); - mutex_unlock(priv->mm_mutex); + mutex_lock(imem->mm_mutex); + nvkm_mm_free(imem->mm, &r); + mutex_unlock(imem->mm_mutex); free_pages: for (i = 0; i < npages && node->pages[i] != NULL; i++) @@ -325,19 +325,19 @@ gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_instobj_args *args = data; - struct gk20a_instmem_priv *priv = (void *)nvkm_instmem(parent); - struct gk20a_instobj_priv *node; + struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); + struct gk20a_instobj *node; u32 size, align; int ret; nv_debug(parent, "%s (%s): size: %x align: %x\n", __func__, - priv->domain ? "IOMMU" : "DMA", args->size, args->align); + imem->domain ? "IOMMU" : "DMA", args->size, args->align); /* Round size and align to page bounds */ size = max(roundup(args->size, PAGE_SIZE), PAGE_SIZE); align = max(roundup(args->align, PAGE_SIZE), PAGE_SIZE); - if (priv->domain) + if (imem->domain) ret = gk20a_instobj_ctor_iommu(parent, engine, oclass, size >> PAGE_SHIFT, align, &node); else @@ -380,9 +380,9 @@ gk20a_instobj_oclass = { static int gk20a_instmem_fini(struct nvkm_object *object, bool suspend) { - struct gk20a_instmem_priv *priv = (void *)object; - priv->addr = ~0ULL; - return nvkm_instmem_fini(&priv->base, suspend); + struct gk20a_instmem *imem = (void *)object; + imem->addr = ~0ULL; + return nvkm_instmem_fini(&imem->base, suspend); } static int @@ -390,37 +390,37 @@ gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk20a_instmem_priv *priv; + struct gk20a_instmem *imem; struct nouveau_platform_device *plat; int ret; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_instmem_create(parent, engine, oclass, &imem); + *pobject = nv_object(imem); if (ret) return ret; - spin_lock_init(&priv->lock); + spin_lock_init(&imem->lock); plat = nv_device_to_platform(nv_device(parent)); if (plat->gpu->iommu.domain) { - priv->domain = plat->gpu->iommu.domain; - priv->mm = plat->gpu->iommu.mm; - priv->iommu_pgshift = plat->gpu->iommu.pgshift; - priv->mm_mutex = &plat->gpu->iommu.mutex; + imem->domain = plat->gpu->iommu.domain; + imem->mm = plat->gpu->iommu.mm; + imem->iommu_pgshift = plat->gpu->iommu.pgshift; + imem->mm_mutex = &plat->gpu->iommu.mutex; - nv_info(priv, "using IOMMU\n"); + nv_info(imem, "using IOMMU\n"); } else { - init_dma_attrs(&priv->attrs); + init_dma_attrs(&imem->attrs); /* * We will access instmem through PRAMIN and thus do not need a * consistent CPU pointer or kernel mapping */ - dma_set_attr(DMA_ATTR_NON_CONSISTENT, &priv->attrs); - dma_set_attr(DMA_ATTR_WEAK_ORDERING, &priv->attrs); - dma_set_attr(DMA_ATTR_WRITE_COMBINE, &priv->attrs); - dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &priv->attrs); + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &imem->attrs); + dma_set_attr(DMA_ATTR_WEAK_ORDERING, &imem->attrs); + dma_set_attr(DMA_ATTR_WRITE_COMBINE, &imem->attrs); + dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &imem->attrs); - nv_info(priv, "using DMA API\n"); + nv_info(imem, "using DMA API\n"); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 282143f49d72e..23084f18199ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -32,30 +32,27 @@ static u32 nv04_instobj_rd32(struct nvkm_object *object, u64 addr) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv04_instobj_priv *node = (void *)object; - return nv_ro32(priv, node->mem->offset + addr); + struct nv04_instmem *imem = (void *)nvkm_instmem(object); + struct nv04_instobj *node = (void *)object; + return nv_ro32(imem, node->mem->offset + addr); } static void nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv04_instobj_priv *node = (void *)object; - nv_wo32(priv, node->mem->offset + addr, data); + struct nv04_instmem *imem = (void *)nvkm_instmem(object); + struct nv04_instobj *node = (void *)object; + nv_wo32(imem, node->mem->offset + addr, data); } static void nv04_instobj_dtor(struct nvkm_object *object) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv04_instobj_priv *node = (void *)object; - struct nvkm_subdev *subdev = (void *)priv; - - mutex_lock(&subdev->mutex); - nvkm_mm_free(&priv->heap, &node->mem); - mutex_unlock(&subdev->mutex); - + struct nv04_instmem *imem = (void *)nvkm_instmem(object); + struct nv04_instobj *node = (void *)object; + mutex_lock(&imem->base.subdev.mutex); + nvkm_mm_free(&imem->heap, &node->mem); + mutex_unlock(&imem->base.subdev.mutex); nvkm_instobj_destroy(&node->base); } @@ -64,10 +61,9 @@ nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent); - struct nv04_instobj_priv *node; + struct nv04_instmem *imem = (void *)nvkm_instmem(parent); + struct nv04_instobj *node; struct nvkm_instobj_args *args = data; - struct nvkm_subdev *subdev = (void *)priv; int ret; if (!args->align) @@ -78,10 +74,10 @@ nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - mutex_lock(&subdev->mutex); - ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size, + mutex_lock(&imem->base.subdev.mutex); + ret = nvkm_mm_head(&imem->heap, 0, 1, args->size, args->size, args->align, &node->mem); - mutex_unlock(&subdev->mutex); + mutex_unlock(&imem->base.subdev.mutex); if (ret) return ret; @@ -121,15 +117,15 @@ nv04_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) void nv04_instmem_dtor(struct nvkm_object *object) { - struct nv04_instmem_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->ramfc); - nvkm_gpuobj_ref(NULL, &priv->ramro); - nvkm_ramht_ref(NULL, &priv->ramht); - nvkm_gpuobj_ref(NULL, &priv->vbios); - nvkm_mm_fini(&priv->heap); - if (priv->iomem) - iounmap(priv->iomem); - nvkm_instmem_destroy(&priv->base); + struct nv04_instmem *imem = (void *)object; + nvkm_gpuobj_ref(NULL, &imem->ramfc); + nvkm_gpuobj_ref(NULL, &imem->ramro); + nvkm_ramht_ref(NULL, &imem->ramht); + nvkm_gpuobj_ref(NULL, &imem->vbios); + nvkm_mm_fini(&imem->heap); + if (imem->iomem) + iounmap(imem->iomem); + nvkm_instmem_destroy(&imem->base); } static int @@ -137,41 +133,41 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem_priv *priv; + struct nv04_instmem *imem; int ret; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_instmem_create(parent, engine, oclass, &imem); + *pobject = nv_object(imem); if (ret) return ret; /* PRAMIN aperture maps over the end of VRAM, reserve it */ - priv->base.reserved = 512 * 1024; + imem->base.reserved = 512 * 1024; - ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1); + ret = nvkm_mm_init(&imem->heap, 0, imem->base.reserved, 1); if (ret) return ret; /* 0x00000-0x10000: reserve for probable vbios image */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0, - &priv->vbios); + ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x10000, 0, 0, + &imem->vbios); if (ret) return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht); + ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, &imem->ramht); if (ret) return ret; /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00800, 0, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc); + ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x00800, 0, + NVOBJ_FLAG_ZERO_ALLOC, &imem->ramfc); if (ret) return ret; /* 0x18800-0x18a00: reserve for RAMRO */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0, - &priv->ramro); + ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x00200, 0, 0, + &imem->ramro); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h index 42b6c928047c1..6065e34e2f0d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h @@ -6,7 +6,7 @@ extern struct nvkm_instobj_impl nv04_instobj_oclass; -struct nv04_instmem_priv { +struct nv04_instmem { struct nvkm_instmem base; void __iomem *iomem; @@ -18,13 +18,13 @@ struct nv04_instmem_priv { struct nvkm_gpuobj *ramfc; }; -static inline struct nv04_instmem_priv * +static inline struct nv04_instmem * nv04_instmem(void *obj) { return (void *)nvkm_instmem(obj); } -struct nv04_instobj_priv { +struct nv04_instobj { struct nvkm_instobj base; struct nvkm_mm_node *mem; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index b42b8588fc0e8..d6827b377bd95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -33,15 +33,15 @@ static u32 nv40_instmem_rd32(struct nvkm_object *object, u64 addr) { - struct nv04_instmem_priv *priv = (void *)object; - return ioread32_native(priv->iomem + addr); + struct nv04_instmem *imem = (void *)object; + return ioread32_native(imem->iomem + addr); } static void nv40_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nv04_instmem_priv *priv = (void *)object; - iowrite32_native(data, priv->iomem + addr); + struct nv04_instmem *imem = (void *)object; + iowrite32_native(data, imem->iomem + addr); } static int @@ -50,11 +50,11 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = nv_device(parent); - struct nv04_instmem_priv *priv; + struct nv04_instmem *imem; int ret, bar, vs; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_instmem_create(parent, engine, oclass, &imem); + *pobject = nv_object(imem); if (ret) return ret; @@ -64,10 +64,10 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, else bar = 3; - priv->iomem = ioremap(nv_device_resource_start(device, bar), + imem->iomem = ioremap(nv_device_resource_start(device, bar), nv_device_resource_len(device, bar)); - if (!priv->iomem) { - nv_error(priv, "unable to map PRAMIN BAR\n"); + if (!imem->iomem) { + nv_error(imem, "unable to map PRAMIN BAR\n"); return -EFAULT; } @@ -75,46 +75,46 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * to fit graphics contexts for every channel, the magics come * from engine/gr/nv40.c */ - vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8); - if (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs; - else if (device->chipset < 0x43) priv->base.reserved = 0x4f00 * vs; - else if (nv44_gr_class(priv)) priv->base.reserved = 0x4980 * vs; - else priv->base.reserved = 0x4a40 * vs; - priv->base.reserved += 16 * 1024; - priv->base.reserved *= 32; /* per-channel */ - priv->base.reserved += 512 * 1024; /* pci(e)gart table */ - priv->base.reserved += 512 * 1024; /* object storage */ - - priv->base.reserved = round_up(priv->base.reserved, 4096); - - ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1); + vs = hweight8((nv_rd32(imem, 0x001540) & 0x0000ff00) >> 8); + if (device->chipset == 0x40) imem->base.reserved = 0x6aa0 * vs; + else if (device->chipset < 0x43) imem->base.reserved = 0x4f00 * vs; + else if (nv44_gr_class(imem)) imem->base.reserved = 0x4980 * vs; + else imem->base.reserved = 0x4a40 * vs; + imem->base.reserved += 16 * 1024; + imem->base.reserved *= 32; /* per-channel */ + imem->base.reserved += 512 * 1024; /* pci(e)gart table */ + imem->base.reserved += 512 * 1024; /* object storage */ + + imem->base.reserved = round_up(imem->base.reserved, 4096); + + ret = nvkm_mm_init(&imem->heap, 0, imem->base.reserved, 1); if (ret) return ret; /* 0x00000-0x10000: reserve for probable vbios image */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0, - &priv->vbios); + ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x10000, 0, 0, + &imem->vbios); if (ret) return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht); + ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, &imem->ramht); if (ret) return ret; /* 0x18000-0x18200: reserve for RAMRO * 0x18200-0x20000: padding */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x08000, 0, 0, - &priv->ramro); + ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x08000, 0, 0, + &imem->ramro); if (ret) return ret; /* 0x20000-0x21000: reserve for RAMFC * 0x21000-0x40000: padding and some unknown crap */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc); + ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x20000, 0, + NVOBJ_FLAG_ZERO_ALLOC, &imem->ramfc); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index b6c5e2d12f205..6c83c5797e322 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -25,13 +25,13 @@ #include -struct nv50_instmem_priv { +struct nv50_instmem { struct nvkm_instmem base; spinlock_t lock; u64 addr; }; -struct nv50_instobj_priv { +struct nv50_instobj { struct nvkm_instobj base; struct nvkm_mem *mem; }; @@ -43,45 +43,45 @@ struct nv50_instobj_priv { static u32 nv50_instobj_rd32(struct nvkm_object *object, u64 offset) { - struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv50_instobj_priv *node = (void *)object; + struct nv50_instmem *imem = (void *)nvkm_instmem(object); + struct nv50_instobj *node = (void *)object; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; u32 data; - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + spin_lock_irqsave(&imem->lock, flags); + if (unlikely(imem->addr != base)) { + nv_wr32(imem, 0x001700, base >> 16); + imem->addr = base; } - data = nv_rd32(priv, 0x700000 + addr); - spin_unlock_irqrestore(&priv->lock, flags); + data = nv_rd32(imem, 0x700000 + addr); + spin_unlock_irqrestore(&imem->lock, flags); return data; } static void nv50_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) { - struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object); - struct nv50_instobj_priv *node = (void *)object; + struct nv50_instmem *imem = (void *)nvkm_instmem(object); + struct nv50_instobj *node = (void *)object; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; - spin_lock_irqsave(&priv->lock, flags); - if (unlikely(priv->addr != base)) { - nv_wr32(priv, 0x001700, base >> 16); - priv->addr = base; + spin_lock_irqsave(&imem->lock, flags); + if (unlikely(imem->addr != base)) { + nv_wr32(imem, 0x001700, base >> 16); + imem->addr = base; } - nv_wr32(priv, 0x700000 + addr, data); - spin_unlock_irqrestore(&priv->lock, flags); + nv_wr32(imem, 0x700000 + addr, data); + spin_unlock_irqrestore(&imem->lock, flags); } static void nv50_instobj_dtor(struct nvkm_object *object) { - struct nv50_instobj_priv *node = (void *)object; + struct nv50_instobj *node = (void *)object; struct nvkm_fb *fb = nvkm_fb(object); fb->ram->put(fb, &node->mem); nvkm_instobj_destroy(&node->base); @@ -94,7 +94,7 @@ nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_instobj_args *args = data; - struct nv50_instobj_priv *node; + struct nv50_instobj *node; int ret; args->size = max((args->size + 4095) & ~4095, (u32)4096); @@ -134,9 +134,9 @@ nv50_instobj_oclass = { static int nv50_instmem_fini(struct nvkm_object *object, bool suspend) { - struct nv50_instmem_priv *priv = (void *)object; - priv->addr = ~0ULL; - return nvkm_instmem_fini(&priv->base, suspend); + struct nv50_instmem *imem = (void *)object; + imem->addr = ~0ULL; + return nvkm_instmem_fini(&imem->base, suspend); } static int @@ -144,15 +144,15 @@ nv50_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_instmem_priv *priv; + struct nv50_instmem *imem; int ret; - ret = nvkm_instmem_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_instmem_create(parent, engine, oclass, &imem); + *pobject = nv_object(imem); if (ret) return ret; - spin_lock_init(&priv->lock); + spin_lock_init(&imem->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index b10e292e5607d..e217ebebd325b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -36,14 +36,14 @@ struct nvkm_instmem_impl { #define nvkm_instmem_create(p,e,o,d) \ nvkm_instmem_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_instmem_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) + nvkm_subdev_destroy(&(p)->subdev) #define nvkm_instmem_init(p) ({ \ - struct nvkm_instmem *imem = (p); \ - _nvkm_instmem_init(nv_object(imem)); \ + struct nvkm_instmem *_imem = (p); \ + _nvkm_instmem_init(nv_object(_imem)); \ }) #define nvkm_instmem_fini(p,s) ({ \ - struct nvkm_instmem *imem = (p); \ - _nvkm_instmem_fini(nv_object(imem), (s)); \ + struct nvkm_instmem *_imem = (p); \ + _nvkm_instmem_fini(nv_object(_imem), (s)); \ }) int nvkm_instmem_create_(struct nvkm_object *, struct nvkm_object *, -- GitLab From c7750cfbc150460a507deb27b8eed93fcf60ea8d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5333/7006] drm/nouveau/ltc: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/ltc.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/base.c | 74 +++++------ .../gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 124 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c | 14 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 84 ++++++------ 5 files changed, 149 insertions(+), 149 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h index cd5d29fc05655..e8234e5b735cf 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h @@ -6,7 +6,7 @@ struct nvkm_mm_node; #define NVKM_LTC_MAX_ZBC_CNT 16 struct nvkm_ltc { - struct nvkm_subdev base; + struct nvkm_subdev subdev; int (*tags_alloc)(struct nvkm_ltc *, u32 count, struct nvkm_mm_node **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c index 2fb87fbfd11c1..f9cfbabeeeb32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c @@ -24,12 +24,12 @@ #include "priv.h" static int -nvkm_ltc_tags_alloc(struct nvkm_ltc *ltc, u32 n, struct nvkm_mm_node **pnode) +nvkm_ltc_tags_alloc(struct nvkm_ltc *obj, u32 n, struct nvkm_mm_node **pnode) { - struct nvkm_ltc_priv *priv = (void *)ltc; + struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); int ret; - ret = nvkm_mm_head(&priv->tags, 0, 1, n, n, 1, pnode); + ret = nvkm_mm_head(<c->tags, 0, 1, n, n, 1, pnode); if (ret) *pnode = NULL; @@ -37,59 +37,59 @@ nvkm_ltc_tags_alloc(struct nvkm_ltc *ltc, u32 n, struct nvkm_mm_node **pnode) } static void -nvkm_ltc_tags_free(struct nvkm_ltc *ltc, struct nvkm_mm_node **pnode) +nvkm_ltc_tags_free(struct nvkm_ltc *obj, struct nvkm_mm_node **pnode) { - struct nvkm_ltc_priv *priv = (void *)ltc; - nvkm_mm_free(&priv->tags, pnode); + struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); + nvkm_mm_free(<c->tags, pnode); } static void -nvkm_ltc_tags_clear(struct nvkm_ltc *ltc, u32 first, u32 count) +nvkm_ltc_tags_clear(struct nvkm_ltc *obj, u32 first, u32 count) { + struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); - struct nvkm_ltc_priv *priv = (void *)ltc; const u32 limit = first + count - 1; - BUG_ON((first > limit) || (limit >= priv->num_tags)); + BUG_ON((first > limit) || (limit >= ltc->num_tags)); - impl->cbc_clear(priv, first, limit); - impl->cbc_wait(priv); + impl->cbc_clear(ltc, first, limit); + impl->cbc_wait(ltc); } static int -nvkm_ltc_zbc_color_get(struct nvkm_ltc *ltc, int index, const u32 color[4]) +nvkm_ltc_zbc_color_get(struct nvkm_ltc *obj, int index, const u32 color[4]) { + struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); - struct nvkm_ltc_priv *priv = (void *)ltc; - memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index])); - impl->zbc_clear_color(priv, index, color); + memcpy(ltc->zbc_color[index], color, sizeof(ltc->zbc_color[index])); + impl->zbc_clear_color(ltc, index, color); return index; } static int -nvkm_ltc_zbc_depth_get(struct nvkm_ltc *ltc, int index, const u32 depth) +nvkm_ltc_zbc_depth_get(struct nvkm_ltc *obj, int index, const u32 depth) { + struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); - struct nvkm_ltc_priv *priv = (void *)ltc; - priv->zbc_depth[index] = depth; - impl->zbc_clear_depth(priv, index, depth); + ltc->zbc_depth[index] = depth; + impl->zbc_clear_depth(ltc, index, depth); return index; } int _nvkm_ltc_init(struct nvkm_object *object) { + struct nvkm_ltc_priv *ltc = (void *)object; const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object); - struct nvkm_ltc_priv *priv = (void *)object; int ret, i; - ret = nvkm_subdev_init(&priv->base.base); + ret = nvkm_subdev_init(<c->base.subdev); if (ret) return ret; - for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) { - impl->zbc_clear_color(priv, i, priv->zbc_color[i]); - impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]); + for (i = ltc->base.zbc_min; i <= ltc->base.zbc_max; i++) { + impl->zbc_clear_color(ltc, i, ltc->zbc_color[i]); + impl->zbc_clear_depth(ltc, i, ltc->zbc_depth[i]); } return 0; @@ -100,25 +100,25 @@ nvkm_ltc_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { const struct nvkm_ltc_impl *impl = (void *)oclass; - struct nvkm_ltc_priv *priv; + struct nvkm_ltc_priv *ltc; int ret; ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PLTCG", "l2c", length, pobject); - priv = *pobject; + ltc = *pobject; if (ret) return ret; - memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color)); - memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth)); - - priv->base.base.intr = impl->intr; - priv->base.tags_alloc = nvkm_ltc_tags_alloc; - priv->base.tags_free = nvkm_ltc_tags_free; - priv->base.tags_clear = nvkm_ltc_tags_clear; - priv->base.zbc_min = 1; /* reserve 0 for disabled */ - priv->base.zbc_max = min(impl->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; - priv->base.zbc_color_get = nvkm_ltc_zbc_color_get; - priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get; + memset(ltc->zbc_color, 0x00, sizeof(ltc->zbc_color)); + memset(ltc->zbc_depth, 0x00, sizeof(ltc->zbc_depth)); + + ltc->base.subdev.intr = impl->intr; + ltc->base.tags_alloc = nvkm_ltc_tags_alloc; + ltc->base.tags_free = nvkm_ltc_tags_free; + ltc->base.tags_clear = nvkm_ltc_tags_clear; + ltc->base.zbc_min = 1; /* reserve 0 for disabled */ + ltc->base.zbc_max = min(impl->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; + ltc->base.zbc_color_get = nvkm_ltc_zbc_color_get; + ltc->base.zbc_depth_get = nvkm_ltc_zbc_depth_get; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index a78ae4ea40081..b56e63f507d38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -28,38 +28,38 @@ #include void -gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit) +gf100_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) { - nv_wr32(priv, 0x17e8cc, start); - nv_wr32(priv, 0x17e8d0, limit); - nv_wr32(priv, 0x17e8c8, 0x00000004); + nv_wr32(ltc, 0x17e8cc, start); + nv_wr32(ltc, 0x17e8d0, limit); + nv_wr32(ltc, 0x17e8c8, 0x00000004); } void -gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv) +gf100_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) { int c, s; - for (c = 0; c < priv->ltc_nr; c++) { - for (s = 0; s < priv->lts_nr; s++) - nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0); + for (c = 0; c < ltc->ltc_nr; c++) { + for (s = 0; s < ltc->lts_nr; s++) + nv_wait(ltc, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0); } } void -gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) +gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) { - nv_mask(priv, 0x17ea44, 0x0000000f, i); - nv_wr32(priv, 0x17ea48, color[0]); - nv_wr32(priv, 0x17ea4c, color[1]); - nv_wr32(priv, 0x17ea50, color[2]); - nv_wr32(priv, 0x17ea54, color[3]); + nv_mask(ltc, 0x17ea44, 0x0000000f, i); + nv_wr32(ltc, 0x17ea48, color[0]); + nv_wr32(ltc, 0x17ea4c, color[1]); + nv_wr32(ltc, 0x17ea50, color[2]); + nv_wr32(ltc, 0x17ea54, color[3]); } void -gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth) +gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) { - nv_mask(priv, 0x17ea44, 0x0000000f, i); - nv_wr32(priv, 0x17ea58, depth); + nv_mask(ltc, 0x17ea44, 0x0000000f, i); + nv_wr32(ltc, 0x17ea58, depth); } static const struct nvkm_bitfield @@ -81,51 +81,51 @@ gf100_ltc_lts_intr_name[] = { }; static void -gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts) +gf100_ltc_lts_intr(struct nvkm_ltc_priv *ltc, int c, int s) { - u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400); - u32 intr = nv_rd32(priv, base + 0x020); + u32 base = 0x141000 + (c * 0x2000) + (s * 0x400); + u32 intr = nv_rd32(ltc, base + 0x020); u32 stat = intr & 0x0000ffff; if (stat) { - nv_info(priv, "LTC%d_LTS%d:", ltc, lts); + nv_info(ltc, "LTC%d_LTS%d:", c, s); nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat); pr_cont("\n"); } - nv_wr32(priv, base + 0x020, intr); + nv_wr32(ltc, base + 0x020, intr); } void gf100_ltc_intr(struct nvkm_subdev *subdev) { - struct nvkm_ltc_priv *priv = (void *)subdev; + struct nvkm_ltc_priv *ltc = (void *)subdev; u32 mask; - mask = nv_rd32(priv, 0x00017c); + mask = nv_rd32(ltc, 0x00017c); while (mask) { - u32 lts, ltc = __ffs(mask); - for (lts = 0; lts < priv->lts_nr; lts++) - gf100_ltc_lts_intr(priv, ltc, lts); - mask &= ~(1 << ltc); + u32 s, c = __ffs(mask); + for (s = 0; s < ltc->lts_nr; s++) + gf100_ltc_lts_intr(ltc, c, s); + mask &= ~(1 << c); } } static int gf100_ltc_init(struct nvkm_object *object) { - struct nvkm_ltc_priv *priv = (void *)object; - u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); + struct nvkm_ltc_priv *ltc = (void *)object; + u32 lpg128 = !(nv_rd32(ltc, 0x100c80) & 0x00000001); int ret; - ret = nvkm_ltc_init(priv); + ret = nvkm_ltc_init(ltc); if (ret) return ret; - nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nv_wr32(priv, 0x17e8d8, priv->ltc_nr); - nv_wr32(priv, 0x17e8d4, priv->tag_base); - nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + nv_mask(ltc, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + nv_wr32(ltc, 0x17e8d8, ltc->ltc_nr); + nv_wr32(ltc, 0x17e8d4, ltc->tag_base); + nv_mask(ltc, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; } @@ -133,36 +133,36 @@ void gf100_ltc_dtor(struct nvkm_object *object) { struct nvkm_fb *fb = nvkm_fb(object); - struct nvkm_ltc_priv *priv = (void *)object; + struct nvkm_ltc_priv *ltc = (void *)object; - nvkm_mm_fini(&priv->tags); + nvkm_mm_fini(<c->tags); if (fb->ram) - nvkm_mm_free(&fb->vram, &priv->tag_ram); + nvkm_mm_free(&fb->vram, <c->tag_ram); - nvkm_ltc_destroy(priv); + nvkm_ltc_destroy(ltc); } /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ int -gf100_ltc_init_tag_ram(struct nvkm_fb *fb, struct nvkm_ltc_priv *priv) +gf100_ltc_init_tag_ram(struct nvkm_fb *fb, struct nvkm_ltc_priv *ltc) { u32 tag_size, tag_margin, tag_align; int ret; /* No VRAM, no tags for now. */ if (!fb->ram) { - priv->num_tags = 0; + ltc->num_tags = 0; goto mm_init; } /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ - priv->num_tags = (fb->ram->size >> 17) / 4; - if (priv->num_tags > (1 << 17)) - priv->num_tags = 1 << 17; /* we have 17 bits in PTE */ - priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */ + ltc->num_tags = (fb->ram->size >> 17) / 4; + if (ltc->num_tags > (1 << 17)) + ltc->num_tags = 1 << 17; /* we have 17 bits in PTE */ + ltc->num_tags = (ltc->num_tags + 63) & ~63; /* round up to 64 */ - tag_align = priv->ltc_nr * 0x800; + tag_align = ltc->ltc_nr * 0x800; tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align; /* 4 part 4 sub: 0x2000 bytes for 56 tags */ @@ -173,25 +173,25 @@ gf100_ltc_init_tag_ram(struct nvkm_fb *fb, struct nvkm_ltc_priv *priv) * * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %. */ - tag_size = (priv->num_tags / 64) * 0x6000 + tag_margin; + tag_size = (ltc->num_tags / 64) * 0x6000 + tag_margin; tag_size += tag_align; tag_size = (tag_size + 0xfff) >> 12; /* round up */ ret = nvkm_mm_tail(&fb->vram, 1, 1, tag_size, tag_size, 1, - &priv->tag_ram); + <c->tag_ram); if (ret) { - priv->num_tags = 0; + ltc->num_tags = 0; } else { - u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin; + u64 tag_base = ((u64)ltc->tag_ram->offset << 12) + tag_margin; tag_base += tag_align - 1; - ret = do_div(tag_base, tag_align); + do_div(tag_base, tag_align); - priv->tag_base = tag_base; + ltc->tag_base = tag_base; } mm_init: - ret = nvkm_mm_init(&priv->tags, 0, priv->num_tags, 1); + ret = nvkm_mm_init(<c->tags, 0, ltc->num_tags, 1); return ret; } @@ -201,28 +201,28 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ltc_priv *priv; + struct nvkm_ltc_priv *ltc; u32 parts, mask; int ret, i; - ret = nvkm_ltc_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_ltc_create(parent, engine, oclass, <c); + *pobject = nv_object(ltc); if (ret) return ret; - parts = nv_rd32(priv, 0x022438); - mask = nv_rd32(priv, 0x022554); + parts = nv_rd32(ltc, 0x022438); + mask = nv_rd32(ltc, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) - priv->ltc_nr++; + ltc->ltc_nr++; } - priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28; + ltc->lts_nr = nv_rd32(ltc, 0x17e8dc) >> 28; - ret = gf100_ltc_init_tag_ram(fb, priv); + ret = gf100_ltc_init_tag_ram(fb, ltc); if (ret) return ret; - nv_subdev(priv)->intr = gf100_ltc_intr; + nv_subdev(ltc)->intr = gf100_ltc_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c index d53959b5ec678..c83a49dd1cb32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c @@ -26,18 +26,18 @@ static int gk104_ltc_init(struct nvkm_object *object) { - struct nvkm_ltc_priv *priv = (void *)object; - u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); + struct nvkm_ltc_priv *ltc = (void *)object; + u32 lpg128 = !(nv_rd32(ltc, 0x100c80) & 0x00000001); int ret; - ret = nvkm_ltc_init(priv); + ret = nvkm_ltc_init(ltc); if (ret) return ret; - nv_wr32(priv, 0x17e8d8, priv->ltc_nr); - nv_wr32(priv, 0x17e000, priv->ltc_nr); - nv_wr32(priv, 0x17e8d4, priv->tag_base); - nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + nv_wr32(ltc, 0x17e8d8, ltc->ltc_nr); + nv_wr32(ltc, 0x17e000, ltc->ltc_nr); + nv_wr32(ltc, 0x17e8d4, ltc->tag_base); + nv_mask(ltc, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 477190d274978..fc4697cfe68d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -27,81 +27,81 @@ #include static void -gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit) +gm107_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) { - nv_wr32(priv, 0x17e270, start); - nv_wr32(priv, 0x17e274, limit); - nv_wr32(priv, 0x17e26c, 0x00000004); + nv_wr32(ltc, 0x17e270, start); + nv_wr32(ltc, 0x17e274, limit); + nv_wr32(ltc, 0x17e26c, 0x00000004); } static void -gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv) +gm107_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) { int c, s; - for (c = 0; c < priv->ltc_nr; c++) { - for (s = 0; s < priv->lts_nr; s++) - nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0); + for (c = 0; c < ltc->ltc_nr; c++) { + for (s = 0; s < ltc->lts_nr; s++) + nv_wait(ltc, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0); } } static void -gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4]) +gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) { - nv_mask(priv, 0x17e338, 0x0000000f, i); - nv_wr32(priv, 0x17e33c, color[0]); - nv_wr32(priv, 0x17e340, color[1]); - nv_wr32(priv, 0x17e344, color[2]); - nv_wr32(priv, 0x17e348, color[3]); + nv_mask(ltc, 0x17e338, 0x0000000f, i); + nv_wr32(ltc, 0x17e33c, color[0]); + nv_wr32(ltc, 0x17e340, color[1]); + nv_wr32(ltc, 0x17e344, color[2]); + nv_wr32(ltc, 0x17e348, color[3]); } static void -gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth) +gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) { - nv_mask(priv, 0x17e338, 0x0000000f, i); - nv_wr32(priv, 0x17e34c, depth); + nv_mask(ltc, 0x17e338, 0x0000000f, i); + nv_wr32(ltc, 0x17e34c, depth); } static void -gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts) +gm107_ltc_lts_isr(struct nvkm_ltc_priv *ltc, int c, int s) { - u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400); - u32 stat = nv_rd32(priv, base + 0x00c); + u32 base = 0x140000 + (c * 0x2000) + (s * 0x400); + u32 stat = nv_rd32(ltc, base + 0x00c); if (stat) { - nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat); - nv_wr32(priv, base + 0x00c, stat); + nv_info(ltc, "LTC%d_LTS%d: 0x%08x\n", c, s, stat); + nv_wr32(ltc, base + 0x00c, stat); } } static void gm107_ltc_intr(struct nvkm_subdev *subdev) { - struct nvkm_ltc_priv *priv = (void *)subdev; + struct nvkm_ltc_priv *ltc = (void *)subdev; u32 mask; - mask = nv_rd32(priv, 0x00017c); + mask = nv_rd32(ltc, 0x00017c); while (mask) { - u32 lts, ltc = __ffs(mask); - for (lts = 0; lts < priv->lts_nr; lts++) - gm107_ltc_lts_isr(priv, ltc, lts); - mask &= ~(1 << ltc); + u32 s, c = __ffs(mask); + for (s = 0; s < ltc->lts_nr; s++) + gm107_ltc_lts_isr(ltc, c, s); + mask &= ~(1 << c); } } static int gm107_ltc_init(struct nvkm_object *object) { - struct nvkm_ltc_priv *priv = (void *)object; - u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001); + struct nvkm_ltc_priv *ltc = (void *)object; + u32 lpg128 = !(nv_rd32(ltc, 0x100c80) & 0x00000001); int ret; - ret = nvkm_ltc_init(priv); + ret = nvkm_ltc_init(ltc); if (ret) return ret; - nv_wr32(priv, 0x17e27c, priv->ltc_nr); - nv_wr32(priv, 0x17e278, priv->tag_base); - nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + nv_wr32(ltc, 0x17e27c, ltc->ltc_nr); + nv_wr32(ltc, 0x17e278, ltc->tag_base); + nv_mask(ltc, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; } @@ -111,24 +111,24 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ltc_priv *priv; + struct nvkm_ltc_priv *ltc; u32 parts, mask; int ret, i; - ret = nvkm_ltc_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_ltc_create(parent, engine, oclass, <c); + *pobject = nv_object(ltc); if (ret) return ret; - parts = nv_rd32(priv, 0x022438); - mask = nv_rd32(priv, 0x021c14); + parts = nv_rd32(ltc, 0x022438); + mask = nv_rd32(ltc, 0x021c14); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) - priv->ltc_nr++; + ltc->ltc_nr++; } - priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28; + ltc->lts_nr = nv_rd32(ltc, 0x17e280) >> 28; - ret = gf100_ltc_init_tag_ram(fb, priv); + ret = gf100_ltc_init_tag_ram(fb, ltc); if (ret) return ret; -- GitLab From 2ca0ddbc03917f94c6d34820f91d0c920c057df2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5334/7006] drm/nouveau/mc: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 80 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 9 +-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c | 14 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h | 4 - drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c | 16 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 10 +-- 8 files changed, 67 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index 055bea7702a1e..726e3f02e3ec0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -3,7 +3,7 @@ #include struct nvkm_mc { - struct nvkm_subdev base; + struct nvkm_subdev subdev; bool use_msi; unsigned int irq; void (*unk260)(struct nvkm_mc *, u32); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 8699e5b2f497d..3aa6efcf6725b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -26,17 +26,17 @@ #include static inline void -nvkm_mc_unk260(struct nvkm_mc *pmc, u32 data) +nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) { - const struct nvkm_mc_oclass *impl = (void *)nv_oclass(pmc); + const struct nvkm_mc_oclass *impl = (void *)nv_oclass(mc); if (impl->unk260) - impl->unk260(pmc, data); + impl->unk260(mc, data); } static inline u32 -nvkm_mc_intr_mask(struct nvkm_mc *pmc) +nvkm_mc_intr_mask(struct nvkm_mc *mc) { - u32 intr = nv_rd32(pmc, 0x000100); + u32 intr = nv_rd32(mc, 0x000100); if (intr == 0xffffffff) /* likely fallen off the bus */ intr = 0x00000000; return intr; @@ -45,23 +45,23 @@ nvkm_mc_intr_mask(struct nvkm_mc *pmc) static irqreturn_t nvkm_mc_intr(int irq, void *arg) { - struct nvkm_mc *pmc = arg; - const struct nvkm_mc_oclass *oclass = (void *)nv_object(pmc)->oclass; + struct nvkm_mc *mc = arg; + const struct nvkm_mc_oclass *oclass = (void *)nv_object(mc)->oclass; const struct nvkm_mc_intr *map = oclass->intr; struct nvkm_subdev *unit; u32 intr; - nv_wr32(pmc, 0x000140, 0x00000000); - nv_rd32(pmc, 0x000140); - intr = nvkm_mc_intr_mask(pmc); - if (pmc->use_msi) - oclass->msi_rearm(pmc); + nv_wr32(mc, 0x000140, 0x00000000); + nv_rd32(mc, 0x000140); + intr = nvkm_mc_intr_mask(mc); + if (mc->use_msi) + oclass->msi_rearm(mc); if (intr) { - u32 stat = intr = nvkm_mc_intr_mask(pmc); + u32 stat = intr = nvkm_mc_intr_mask(mc); while (map->stat) { if (intr & map->stat) { - unit = nvkm_subdev(pmc, map->unit); + unit = nvkm_subdev(mc, map->unit); if (unit && unit->intr) unit->intr(unit); stat &= ~map->stat; @@ -70,29 +70,29 @@ nvkm_mc_intr(int irq, void *arg) } if (stat) - nv_error(pmc, "unknown intr 0x%08x\n", stat); + nv_error(mc, "unknown intr 0x%08x\n", stat); } - nv_wr32(pmc, 0x000140, 0x00000001); + nv_wr32(mc, 0x000140, 0x00000001); return intr ? IRQ_HANDLED : IRQ_NONE; } int _nvkm_mc_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_mc *pmc = (void *)object; - nv_wr32(pmc, 0x000140, 0x00000000); - return nvkm_subdev_fini(&pmc->base, suspend); + struct nvkm_mc *mc = (void *)object; + nv_wr32(mc, 0x000140, 0x00000000); + return nvkm_subdev_fini(&mc->subdev, suspend); } int _nvkm_mc_init(struct nvkm_object *object) { - struct nvkm_mc *pmc = (void *)object; - int ret = nvkm_subdev_init(&pmc->base); + struct nvkm_mc *mc = (void *)object; + int ret = nvkm_subdev_init(&mc->subdev); if (ret) return ret; - nv_wr32(pmc, 0x000140, 0x00000001); + nv_wr32(mc, 0x000140, 0x00000001); return 0; } @@ -100,11 +100,11 @@ void _nvkm_mc_dtor(struct nvkm_object *object) { struct nvkm_device *device = nv_device(object); - struct nvkm_mc *pmc = (void *)object; - free_irq(pmc->irq, pmc); - if (pmc->use_msi) + struct nvkm_mc *mc = (void *)object; + free_irq(mc->irq, mc); + if (mc->use_msi) pci_disable_msi(device->pdev); - nvkm_subdev_destroy(&pmc->base); + nvkm_subdev_destroy(&mc->subdev); } int @@ -113,16 +113,16 @@ nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, { const struct nvkm_mc_oclass *oclass = (void *)bclass; struct nvkm_device *device = nv_device(parent); - struct nvkm_mc *pmc; + struct nvkm_mc *mc; int ret; ret = nvkm_subdev_create_(parent, engine, bclass, 0, "PMC", "master", length, pobject); - pmc = *pobject; + mc = *pobject; if (ret) return ret; - pmc->unk260 = nvkm_mc_unk260; + mc->unk260 = nvkm_mc_unk260; if (nv_device_is_pci(device)) { switch (device->pdev->device & 0x0ff0) { @@ -136,31 +136,31 @@ nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, /* reported broken, nv also disable it */ break; default: - pmc->use_msi = true; + mc->use_msi = true; break; } } - pmc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI", - pmc->use_msi); + mc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI", + mc->use_msi); - if (pmc->use_msi && oclass->msi_rearm) { - pmc->use_msi = pci_enable_msi(device->pdev) == 0; - if (pmc->use_msi) { - nv_info(pmc, "MSI interrupts enabled\n"); - oclass->msi_rearm(pmc); + if (mc->use_msi && oclass->msi_rearm) { + mc->use_msi = pci_enable_msi(device->pdev) == 0; + if (mc->use_msi) { + nv_info(mc, "MSI interrupts enabled\n"); + oclass->msi_rearm(mc); } } else { - pmc->use_msi = false; + mc->use_msi = false; } } ret = nv_device_get_irq(device, true); if (ret < 0) return ret; - pmc->irq = ret; + mc->irq = ret; - ret = request_irq(pmc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", pmc); + ret = request_irq(mc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", mc); if (ret < 0) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 2425984b045e7..a2c4dbe64eebb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -49,16 +49,15 @@ gf100_mc_intr[] = { }; static void -gf100_mc_msi_rearm(struct nvkm_mc *pmc) +gf100_mc_msi_rearm(struct nvkm_mc *mc) { - struct nv04_mc_priv *priv = (void *)pmc; - nv_wr32(priv, 0x088704, 0x00000000); + nv_wr32(mc, 0x088704, 0x00000000); } void -gf100_mc_unk260(struct nvkm_mc *pmc, u32 data) +gf100_mc_unk260(struct nvkm_mc *mc, u32 data) { - nv_wr32(pmc, 0x000260, data); + nv_wr32(mc, 0x000260, data); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index 32713827b4dcf..84670aac664f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -41,12 +41,12 @@ nv04_mc_intr[] = { int nv04_mc_init(struct nvkm_object *object) { - struct nv04_mc_priv *priv = (void *)object; + struct nvkm_mc *mc = (void *)object; - nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ - nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */ + nv_wr32(mc, 0x000200, 0xffffffff); /* everything enabled */ + nv_wr32(mc, 0x001850, 0x00000001); /* disable rom access */ - return nvkm_mc_init(&priv->base); + return nvkm_mc_init(mc); } int @@ -54,11 +54,11 @@ nv04_mc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_mc_priv *priv; + struct nvkm_mc *mc; int ret; - ret = nvkm_mc_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mc_create(parent, engine, oclass, &mc); + *pobject = nv_object(mc); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h index 411de3d08ab6d..aa2e58fa69f0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h @@ -2,10 +2,6 @@ #define __NVKM_MC_NV04_H__ #include "priv.h" -struct nv04_mc_priv { - struct nvkm_mc base; -}; - int nv04_mc_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c index b7613059da087..80431b51bf620 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c @@ -24,10 +24,9 @@ #include "nv04.h" void -nv40_mc_msi_rearm(struct nvkm_mc *pmc) +nv40_mc_msi_rearm(struct nvkm_mc *mc) { - struct nv04_mc_priv *priv = (void *)pmc; - nv_wr08(priv, 0x088068, 0xff); + nv_wr08(mc, 0x088068, 0xff); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 2c7f7c701a2b6..63c2d6603f9c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -26,17 +26,17 @@ int nv44_mc_init(struct nvkm_object *object) { - struct nv04_mc_priv *priv = (void *)object; - u32 tmp = nv_rd32(priv, 0x10020c); + struct nvkm_mc *mc = (void *)object; + u32 tmp = nv_rd32(mc, 0x10020c); - nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */ + nv_wr32(mc, 0x000200, 0xffffffff); /* everything enabled */ - nv_wr32(priv, 0x001700, tmp); - nv_wr32(priv, 0x001704, 0); - nv_wr32(priv, 0x001708, 0); - nv_wr32(priv, 0x00170c, tmp); + nv_wr32(mc, 0x001700, tmp); + nv_wr32(mc, 0x001704, 0); + nv_wr32(mc, 0x001708, 0); + nv_wr32(mc, 0x00170c, tmp); - return nvkm_mc_init(&priv->base); + return nvkm_mc_init(mc); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 9c43ddce9992d..4387e686ff6b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -42,18 +42,18 @@ nv50_mc_intr[] = { }; static void -nv50_mc_msi_rearm(struct nvkm_mc *pmc) +nv50_mc_msi_rearm(struct nvkm_mc *mc) { - struct nvkm_device *device = nv_device(pmc); + struct nvkm_device *device = nv_device(mc); pci_write_config_byte(device->pdev, 0x68, 0xff); } int nv50_mc_init(struct nvkm_object *object) { - struct nv04_mc_priv *priv = (void *)object; - nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */ - return nvkm_mc_init(&priv->base); + struct nvkm_mc *mc = (void *)object; + nv_wr32(mc, 0x000200, 0xffffffff); /* everything on */ + return nvkm_mc_init(mc); } struct nvkm_oclass * -- GitLab From 1f5bffca226929a834c7d631464d420e78cbe5f1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5335/7006] drm/nouveau/mmu: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 8 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 57 ++++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 54 +++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h | 6 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 64 ++++++------- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 92 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 48 +++++----- 9 files changed, 162 insertions(+), 173 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 3a5368776c313..b596a1dd5b81c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -38,7 +38,7 @@ struct nvkm_vm { }; struct nvkm_mmu { - struct nvkm_subdev base; + struct nvkm_subdev subdev; u64 limit; u8 dma_bits; @@ -69,11 +69,11 @@ nvkm_mmu(void *obj) #define nvkm_mmu_create(p,e,o,i,f,d) \ nvkm_subdev_create((p), (e), (o), 0, (i), (f), (d)) #define nvkm_mmu_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) + nvkm_subdev_destroy(&(p)->subdev) #define nvkm_mmu_init(p) \ - nvkm_subdev_init(&(p)->base) + nvkm_subdev_init(&(p)->subdev) #define nvkm_mmu_fini(p,s) \ - nvkm_subdev_fini(&(p)->base, (s)) + nvkm_subdev_fini(&(p)->subdev, (s)) #define _nvkm_mmu_dtor _nvkm_subdev_dtor #define _nvkm_mmu_init _nvkm_subdev_init diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index d9c64c2aabc8a..44e878b5601a7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -221,7 +221,7 @@ nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); struct nvkm_mmu *mmu = nvxx_mmu(&drm->device); - struct nv04_mmu_priv *priv = (void *)mmu; + struct nv04_mmu *priv = (void *)mmu; struct nvkm_vm *vm = NULL; nvkm_vm_ref(priv->vm, &vm, NULL); man->priv = vm; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c index b4379c2a2fb57..a6bfd0894f58b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c @@ -60,7 +60,7 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, } if (priv->clone) { - struct nv04_mmu_priv *mmu = nv04_mmu(dmaobj); + struct nv04_mmu *mmu = nv04_mmu(dmaobj); struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0]; if (!dmaobj->start) return nvkm_gpuobj_dup(parent, pgt, pgpuobj); @@ -86,7 +86,7 @@ nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_dmaeng *dmaeng = (void *)engine; - struct nv04_mmu_priv *mmu = nv04_mmu(engine); + struct nv04_mmu *mmu = nv04_mmu(engine); struct nv04_dmaobj_priv *priv; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 294cda37f0688..982f7c7079343 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -29,11 +29,6 @@ #include -struct gf100_mmu_priv { - struct nvkm_mmu base; -}; - - /* Map from compressed to corresponding uncompressed storage type. * The value 0xff represents an invalid storage type. */ @@ -158,8 +153,8 @@ gf100_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) static void gf100_vm_flush(struct nvkm_vm *vm) { - struct gf100_mmu_priv *priv = (void *)vm->mmu; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_mmu *mmu = (void *)vm->mmu; + struct nvkm_bar *bar = nvkm_bar(mmu); struct nvkm_vm_pgd *vpgd; u32 type; @@ -169,26 +164,26 @@ gf100_vm_flush(struct nvkm_vm *vm) if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ - mutex_lock(&nv_subdev(priv)->mutex); + mutex_lock(&nv_subdev(mmu)->mutex); list_for_each_entry(vpgd, &vm->pgd_list, head) { /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases */ - if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) { - nv_error(priv, "vm timeout 0: 0x%08x %d\n", - nv_rd32(priv, 0x100c80), type); + if (!nv_wait_ne(mmu, 0x100c80, 0x00ff0000, 0x00000000)) { + nv_error(mmu, "vm timeout 0: 0x%08x %d\n", + nv_rd32(mmu, 0x100c80), type); } - nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8); - nv_wr32(priv, 0x100cbc, 0x80000000 | type); + nv_wr32(mmu, 0x100cb8, vpgd->obj->addr >> 8); + nv_wr32(mmu, 0x100cbc, 0x80000000 | type); /* wait for flush to be queued? */ - if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) { - nv_error(priv, "vm timeout 1: 0x%08x %d\n", - nv_rd32(priv, 0x100c80), type); + if (!nv_wait(mmu, 0x100c80, 0x00008000, 0x00008000)) { + nv_error(mmu, "vm timeout 1: 0x%08x %d\n", + nv_rd32(mmu, 0x100c80), type); } } - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_unlock(&nv_subdev(mmu)->mutex); } static int @@ -203,25 +198,25 @@ gf100_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_mmu_priv *priv; + struct nvkm_mmu *mmu; int ret; - ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv); - *pobject = nv_object(priv); + ret = nvkm_mmu_create(parent, engine, oclass, "VM", "mmu", &mmu); + *pobject = nv_object(mmu); if (ret) return ret; - priv->base.limit = 1ULL << 40; - priv->base.dma_bits = 40; - priv->base.pgt_bits = 27 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 17; - priv->base.create = gf100_vm_create; - priv->base.map_pgt = gf100_vm_map_pgt; - priv->base.map = gf100_vm_map; - priv->base.map_sg = gf100_vm_map_sg; - priv->base.unmap = gf100_vm_unmap; - priv->base.flush = gf100_vm_flush; + mmu->limit = 1ULL << 40; + mmu->dma_bits = 40; + mmu->pgt_bits = 27 - 12; + mmu->spg_shift = 12; + mmu->lpg_shift = 17; + mmu->create = gf100_vm_create; + mmu->map_pgt = gf100_vm_map_pgt; + mmu->map = gf100_vm_map; + mmu->map_sg = gf100_vm_map_sg; + mmu->unmap = gf100_vm_unmap; + mmu->flush = gf100_vm_flush; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index 861c97adec70c..5c66720ed2521 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -84,37 +84,37 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_mmu_priv *priv; + struct nv04_mmu *mmu; struct nvkm_gpuobj *dma; int ret; ret = nvkm_mmu_create(parent, engine, oclass, "PCIGART", - "pcigart", &priv); - *pobject = nv_object(priv); + "mmu", &mmu); + *pobject = nv_object(mmu); if (ret) return ret; - priv->base.create = nv04_vm_create; - priv->base.limit = NV04_PDMA_SIZE; - priv->base.dma_bits = 32; - priv->base.pgt_bits = 32 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 12; - priv->base.map_sg = nv04_vm_map_sg; - priv->base.unmap = nv04_vm_unmap; - priv->base.flush = nv04_vm_flush; - - ret = nvkm_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096, - &priv->vm); + mmu->base.create = nv04_vm_create; + mmu->base.limit = NV04_PDMA_SIZE; + mmu->base.dma_bits = 32; + mmu->base.pgt_bits = 32 - 12; + mmu->base.spg_shift = 12; + mmu->base.lpg_shift = 12; + mmu->base.map_sg = nv04_vm_map_sg; + mmu->base.unmap = nv04_vm_unmap; + mmu->base.flush = nv04_vm_flush; + + ret = nvkm_vm_create(&mmu->base, 0, NV04_PDMA_SIZE, 0, 4096, + &mmu->vm); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, + ret = nvkm_gpuobj_new(nv_object(mmu), NULL, (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 + 8, 16, NVOBJ_FLAG_ZERO_ALLOC, - &priv->vm->pgt[0].obj[0]); - dma = priv->vm->pgt[0].obj[0]; - priv->vm->pgt[0].refcount[0] = 1; + &mmu->vm->pgt[0].obj[0]); + dma = mmu->vm->pgt[0].obj[0]; + mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; @@ -126,16 +126,16 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, void nv04_mmu_dtor(struct nvkm_object *object) { - struct nv04_mmu_priv *priv = (void *)object; - if (priv->vm) { - nvkm_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]); - nvkm_vm_ref(NULL, &priv->vm, NULL); + struct nv04_mmu *mmu = (void *)object; + if (mmu->vm) { + nvkm_gpuobj_ref(NULL, &mmu->vm->pgt[0].obj[0]); + nvkm_vm_ref(NULL, &mmu->vm, NULL); } - if (priv->nullp) { - pci_free_consistent(nv_device(priv)->pdev, 16 * 1024, - priv->nullp, priv->null); + if (mmu->nullp) { + pci_free_consistent(nv_device(mmu)->pdev, 16 * 1024, + mmu->nullp, mmu->null); } - nvkm_mmu_destroy(&priv->base); + nvkm_mmu_destroy(&mmu->base); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h index 7bf6f4b38f1d0..80a404eab441c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h @@ -1,19 +1,17 @@ #ifndef __NV04_MMU_PRIV__ #define __NV04_MMU_PRIV__ - #include -struct nv04_mmu_priv { +struct nv04_mmu { struct nvkm_mmu base; struct nvkm_vm *vm; dma_addr_t null; void *nullp; }; -static inline struct nv04_mmu_priv * +static inline struct nv04_mmu * nv04_mmu(void *obj) { return (void *)nvkm_mmu(obj); } - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 37b943aba1146..17b2b3979da43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -64,16 +64,16 @@ nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) static void nv41_vm_flush(struct nvkm_vm *vm) { - struct nv04_mmu_priv *priv = (void *)vm->mmu; + struct nv04_mmu *mmu = (void *)vm->mmu; - mutex_lock(&nv_subdev(priv)->mutex); - nv_wr32(priv, 0x100810, 0x00000022); - if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) { - nv_warn(priv, "flush timeout, 0x%08x\n", - nv_rd32(priv, 0x100810)); + mutex_lock(&nv_subdev(mmu)->mutex); + nv_wr32(mmu, 0x100810, 0x00000022); + if (!nv_wait(mmu, 0x100810, 0x00000020, 0x00000020)) { + nv_warn(mmu, "flush timeout, 0x%08x\n", + nv_rd32(mmu, 0x100810)); } - nv_wr32(priv, 0x100810, 0x00000000); - mutex_unlock(&nv_subdev(priv)->mutex); + nv_wr32(mmu, 0x100810, 0x00000000); + mutex_unlock(&nv_subdev(mmu)->mutex); } /******************************************************************************* @@ -86,7 +86,7 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = nv_device(parent); - struct nv04_mmu_priv *priv; + struct nv04_mmu *mmu; int ret; if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || @@ -96,31 +96,31 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART", - "pciegart", &priv); - *pobject = nv_object(priv); + "mmu", &mmu); + *pobject = nv_object(mmu); if (ret) return ret; - priv->base.create = nv04_vm_create; - priv->base.limit = NV41_GART_SIZE; - priv->base.dma_bits = 39; - priv->base.pgt_bits = 32 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 12; - priv->base.map_sg = nv41_vm_map_sg; - priv->base.unmap = nv41_vm_unmap; - priv->base.flush = nv41_vm_flush; - - ret = nvkm_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096, - &priv->vm); + mmu->base.create = nv04_vm_create; + mmu->base.limit = NV41_GART_SIZE; + mmu->base.dma_bits = 39; + mmu->base.pgt_bits = 32 - 12; + mmu->base.spg_shift = 12; + mmu->base.lpg_shift = 12; + mmu->base.map_sg = nv41_vm_map_sg; + mmu->base.unmap = nv41_vm_unmap; + mmu->base.flush = nv41_vm_flush; + + ret = nvkm_vm_create(&mmu->base, 0, NV41_GART_SIZE, 0, 4096, + &mmu->vm); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, + ret = nvkm_gpuobj_new(nv_object(mmu), NULL, (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16, NVOBJ_FLAG_ZERO_ALLOC, - &priv->vm->pgt[0].obj[0]); - priv->vm->pgt[0].refcount[0] = 1; + &mmu->vm->pgt[0].obj[0]); + mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; @@ -130,17 +130,17 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, static int nv41_mmu_init(struct nvkm_object *object) { - struct nv04_mmu_priv *priv = (void *)object; - struct nvkm_gpuobj *dma = priv->vm->pgt[0].obj[0]; + struct nv04_mmu *mmu = (void *)object; + struct nvkm_gpuobj *dma = mmu->vm->pgt[0].obj[0]; int ret; - ret = nvkm_mmu_init(&priv->base); + ret = nvkm_mmu_init(&mmu->base); if (ret) return ret; - nv_wr32(priv, 0x100800, dma->addr | 0x00000002); - nv_mask(priv, 0x10008c, 0x00000100, 0x00000100); - nv_wr32(priv, 0x100820, 0x00000000); + nv_wr32(mmu, 0x100800, dma->addr | 0x00000002); + nv_mask(mmu, 0x10008c, 0x00000100, 0x00000100); + nv_wr32(mmu, 0x100820, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 87824693f9ccf..860654fee3876 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -84,14 +84,14 @@ static void nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { - struct nv04_mmu_priv *priv = (void *)vma->vm->mmu; + struct nv04_mmu *mmu = (void *)vma->vm->mmu; u32 tmp[4]; int i; if (pte & 3) { u32 max = 4 - (pte & 3); u32 part = (cnt > max) ? max : cnt; - nv44_vm_fill(pgt, priv->null, list, pte, part); + nv44_vm_fill(pgt, mmu->null, list, pte, part); pte += part; list += part; cnt -= part; @@ -108,18 +108,18 @@ nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } if (cnt) - nv44_vm_fill(pgt, priv->null, list, pte, cnt); + nv44_vm_fill(pgt, mmu->null, list, pte, cnt); } static void nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) { - struct nv04_mmu_priv *priv = (void *)nvkm_mmu(pgt); + struct nv04_mmu *mmu = (void *)nvkm_mmu(pgt); if (pte & 3) { u32 max = 4 - (pte & 3); u32 part = (cnt > max) ? max : cnt; - nv44_vm_fill(pgt, priv->null, NULL, pte, part); + nv44_vm_fill(pgt, mmu->null, NULL, pte, part); pte += part; cnt -= part; } @@ -133,18 +133,18 @@ nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) } if (cnt) - nv44_vm_fill(pgt, priv->null, NULL, pte, cnt); + nv44_vm_fill(pgt, mmu->null, NULL, pte, cnt); } static void nv44_vm_flush(struct nvkm_vm *vm) { - struct nv04_mmu_priv *priv = (void *)vm->mmu; - nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE); - nv_wr32(priv, 0x100808, 0x00000020); - if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001)) - nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808)); - nv_wr32(priv, 0x100808, 0x00000000); + struct nv04_mmu *mmu = (void *)vm->mmu; + nv_wr32(mmu, 0x100814, mmu->base.limit - NV44_GART_PAGE); + nv_wr32(mmu, 0x100808, 0x00000020); + if (!nv_wait(mmu, 0x100808, 0x00000001, 0x00000001)) + nv_error(mmu, "timeout: 0x%08x\n", nv_rd32(mmu, 0x100808)); + nv_wr32(mmu, 0x100808, 0x00000000); } /******************************************************************************* @@ -157,7 +157,7 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = nv_device(parent); - struct nv04_mmu_priv *priv; + struct nv04_mmu *mmu; int ret; if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || @@ -167,37 +167,37 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART", - "pciegart", &priv); - *pobject = nv_object(priv); + "mmu", &mmu); + *pobject = nv_object(mmu); if (ret) return ret; - priv->base.create = nv04_vm_create; - priv->base.limit = NV44_GART_SIZE; - priv->base.dma_bits = 39; - priv->base.pgt_bits = 32 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 12; - priv->base.map_sg = nv44_vm_map_sg; - priv->base.unmap = nv44_vm_unmap; - priv->base.flush = nv44_vm_flush; - - priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null); - if (!priv->nullp) { - nv_error(priv, "unable to allocate dummy pages\n"); - return -ENOMEM; + mmu->base.create = nv04_vm_create; + mmu->base.limit = NV44_GART_SIZE; + mmu->base.dma_bits = 39; + mmu->base.pgt_bits = 32 - 12; + mmu->base.spg_shift = 12; + mmu->base.lpg_shift = 12; + mmu->base.map_sg = nv44_vm_map_sg; + mmu->base.unmap = nv44_vm_unmap; + mmu->base.flush = nv44_vm_flush; + + mmu->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &mmu->null); + if (!mmu->nullp) { + nv_warn(mmu, "unable to allocate dummy pages\n"); + mmu->null = 0; } - ret = nvkm_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096, - &priv->vm); + ret = nvkm_vm_create(&mmu->base, 0, NV44_GART_SIZE, 0, 4096, + &mmu->vm); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, + ret = nvkm_gpuobj_new(nv_object(mmu), NULL, (NV44_GART_SIZE / NV44_GART_PAGE) * 4, 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC, - &priv->vm->pgt[0].obj[0]); - priv->vm->pgt[0].refcount[0] = 1; + &mmu->vm->pgt[0].obj[0]); + mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; @@ -207,12 +207,12 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, static int nv44_mmu_init(struct nvkm_object *object) { - struct nv04_mmu_priv *priv = (void *)object; - struct nvkm_gpuobj *gart = priv->vm->pgt[0].obj[0]; + struct nv04_mmu *mmu = (void *)object; + struct nvkm_gpuobj *gart = mmu->vm->pgt[0].obj[0]; u32 addr; int ret; - ret = nvkm_mmu_init(&priv->base); + ret = nvkm_mmu_init(&mmu->base); if (ret) return ret; @@ -220,17 +220,17 @@ nv44_mmu_init(struct nvkm_object *object) * allocated on 512KiB alignment, and not exceed a total size * of 512KiB for this to work correctly */ - addr = nv_rd32(priv, 0x10020c); + addr = nv_rd32(mmu, 0x10020c); addr -= ((gart->addr >> 19) + 1) << 19; - nv_wr32(priv, 0x100850, 0x80000000); - nv_wr32(priv, 0x100818, priv->null); - nv_wr32(priv, 0x100804, NV44_GART_SIZE); - nv_wr32(priv, 0x100850, 0x00008000); - nv_mask(priv, 0x10008c, 0x00000200, 0x00000200); - nv_wr32(priv, 0x100820, 0x00000000); - nv_wr32(priv, 0x10082c, 0x00000001); - nv_wr32(priv, 0x100800, addr | 0x00000010); + nv_wr32(mmu, 0x100850, 0x80000000); + nv_wr32(mmu, 0x100818, mmu->null); + nv_wr32(mmu, 0x100804, NV44_GART_SIZE); + nv_wr32(mmu, 0x100850, 0x00008000); + nv_mask(mmu, 0x10008c, 0x00000200, 0x00000200); + nv_wr32(mmu, 0x100820, 0x00000000); + nv_wr32(mmu, 0x10082c, 0x00000001); + nv_wr32(mmu, 0x100800, addr | 0x00000010); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index b83550fa7f96f..75c6a07e2dd54 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -29,10 +29,6 @@ #include #include -struct nv50_mmu_priv { - struct nvkm_mmu base; -}; - static void nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2]) { @@ -149,20 +145,20 @@ nv50_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) static void nv50_vm_flush(struct nvkm_vm *vm) { - struct nv50_mmu_priv *priv = (void *)vm->mmu; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_mmu *mmu = (void *)vm->mmu; + struct nvkm_bar *bar = nvkm_bar(mmu); struct nvkm_engine *engine; int i, vme; bar->flush(bar); - mutex_lock(&nv_subdev(priv)->mutex); + mutex_lock(&nv_subdev(mmu)->mutex); for (i = 0; i < NVDEV_SUBDEV_NR; i++) { if (!atomic_read(&vm->engref[i])) continue; /* unfortunate hw bug workaround... */ - engine = nvkm_engine(priv, i); + engine = nvkm_engine(mmu, i); if (engine && engine->tlb_flush) { engine->tlb_flush(engine); continue; @@ -184,11 +180,11 @@ nv50_vm_flush(struct nvkm_vm *vm) continue; } - nv_wr32(priv, 0x100c80, (vme << 16) | 1); - if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) - nv_error(priv, "vm flush timeout: engine %d\n", vme); + nv_wr32(mmu, 0x100c80, (vme << 16) | 1); + if (!nv_wait(mmu, 0x100c80, 0x00000001, 0x00000000)) + nv_error(mmu, "vm flush timeout: engine %d\n", vme); } - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_unlock(&nv_subdev(mmu)->mutex); } static int @@ -207,25 +203,25 @@ nv50_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_mmu_priv *priv; + struct nvkm_mmu *mmu; int ret; - ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv); - *pobject = nv_object(priv); + ret = nvkm_mmu_create(parent, engine, oclass, "VM", "mmu", &mmu); + *pobject = nv_object(mmu); if (ret) return ret; - priv->base.limit = 1ULL << 40; - priv->base.dma_bits = 40; - priv->base.pgt_bits = 29 - 12; - priv->base.spg_shift = 12; - priv->base.lpg_shift = 16; - priv->base.create = nv50_vm_create; - priv->base.map_pgt = nv50_vm_map_pgt; - priv->base.map = nv50_vm_map; - priv->base.map_sg = nv50_vm_map_sg; - priv->base.unmap = nv50_vm_unmap; - priv->base.flush = nv50_vm_flush; + mmu->limit = 1ULL << 40; + mmu->dma_bits = 40; + mmu->pgt_bits = 29 - 12; + mmu->spg_shift = 12; + mmu->lpg_shift = 16; + mmu->create = nv50_vm_create; + mmu->map_pgt = nv50_vm_map_pgt; + mmu->map = nv50_vm_map; + mmu->map_sg = nv50_vm_map_sg; + mmu->unmap = nv50_vm_unmap; + mmu->flush = nv50_vm_flush; return 0; } -- GitLab From 2d9d5889e8848501ffe71b4e99c639a29a1fe10f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5336/7006] drm/nouveau/mxm: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c | 14 +++++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h index fba613477b1a5..98904392547d6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h @@ -5,7 +5,7 @@ #define MXM_SANITISE_DCB 0x00000001 struct nvkm_mxm { - struct nvkm_subdev base; + struct nvkm_subdev subdev; u32 action; u8 *mxms; }; @@ -19,9 +19,9 @@ nvkm_mxm(void *obj) #define nvkm_mxm_create(p,e,o,d) \ nvkm_mxm_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_mxm_init(p) \ - nvkm_subdev_init(&(p)->base) + nvkm_subdev_init(&(p)->subdev) #define nvkm_mxm_fini(p,s) \ - nvkm_subdev_fini(&(p)->base, (s)) + nvkm_subdev_fini(&(p)->subdev, (s)) int nvkm_mxm_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); void nvkm_mxm_destroy(struct nvkm_mxm *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c index f20e4ca87e17d..0add310c3fbbc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c @@ -28,10 +28,6 @@ #include #include -struct nv50_mxm_priv { - struct nvkm_mxm base; -}; - struct context { u32 *outp; struct mxms_odev desc; @@ -206,16 +202,16 @@ nv50_mxm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_mxm_priv *priv; + struct nvkm_mxm *mxm; int ret; - ret = nvkm_mxm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mxm_create(parent, engine, oclass, &mxm); + *pobject = nv_object(mxm); if (ret) return ret; - if (priv->base.action & MXM_SANITISE_DCB) - mxm_dcb_sanitise(&priv->base); + if (mxm->action & MXM_SANITISE_DCB) + mxm_dcb_sanitise(mxm); return 0; } -- GitLab From 5a7d1e22feedd3cfab5a94bba5f26ab61610bc62 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5337/7006] drm/nouveau/pmu: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/pmu.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 86 +++++++++---------- 3 files changed, 45 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h index 755942352557b..64b3a177bf88a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h @@ -3,7 +3,7 @@ #include struct nvkm_pmu { - struct nvkm_subdev base; + struct nvkm_subdev subdev; struct { u32 base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index 054b2d2eec351..e0fbf5aaeeebd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -178,7 +178,7 @@ _nvkm_pmu_fini(struct nvkm_object *object, bool suspend) nv_wr32(pmu, 0x10a014, 0x00000060); flush_work(&pmu->recv.work); - return nvkm_subdev_fini(&pmu->base, suspend); + return nvkm_subdev_fini(&pmu->subdev, suspend); } int @@ -188,7 +188,7 @@ _nvkm_pmu_init(struct nvkm_object *object) struct nvkm_pmu *pmu = (void *)object; int ret, i; - ret = nvkm_subdev_init(&pmu->base); + ret = nvkm_subdev_init(&pmu->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 594f746e68f2d..069e9dacc6d3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -35,7 +35,7 @@ struct gk20a_pmu_dvfs_data { unsigned int avg_load; }; -struct gk20a_pmu_priv { +struct gk20a_pmu { struct nvkm_pmu base; struct nvkm_alarm alarm; struct gk20a_pmu_dvfs_data *data; @@ -48,28 +48,28 @@ struct gk20a_pmu_dvfs_dev_status { }; static int -gk20a_pmu_dvfs_target(struct gk20a_pmu_priv *priv, int *state) +gk20a_pmu_dvfs_target(struct gk20a_pmu *pmu, int *state) { - struct nvkm_clk *clk = nvkm_clk(priv); + struct nvkm_clk *clk = nvkm_clk(pmu); return nvkm_clk_astate(clk, *state, 0, false); } static int -gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu_priv *priv, int *state) +gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu *pmu, int *state) { - struct nvkm_clk *clk = nvkm_clk(priv); + struct nvkm_clk *clk = nvkm_clk(pmu); *state = clk->pstate; return 0; } static int -gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv, +gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu *pmu, int *state, int load) { - struct gk20a_pmu_dvfs_data *data = priv->data; - struct nvkm_clk *clk = nvkm_clk(priv); + struct gk20a_pmu_dvfs_data *data = pmu->data; + struct nvkm_clk *clk = nvkm_clk(pmu); int cur_level, level; /* For GK20A, the performance level is directly mapped to pstate */ @@ -84,7 +84,7 @@ gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv, level = min(clk->state_nr - 1, level); } - nv_trace(priv, "cur level = %d, new level = %d\n", cur_level, level); + nv_trace(pmu, "cur level = %d, new level = %d\n", cur_level, level); *state = level; @@ -95,30 +95,30 @@ gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv, } static int -gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu_priv *priv, +gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu *pmu, struct gk20a_pmu_dvfs_dev_status *status) { - status->busy = nv_rd32(priv, 0x10a508 + (BUSY_SLOT * 0x10)); - status->total= nv_rd32(priv, 0x10a508 + (CLK_SLOT * 0x10)); + status->busy = nv_rd32(pmu, 0x10a508 + (BUSY_SLOT * 0x10)); + status->total= nv_rd32(pmu, 0x10a508 + (CLK_SLOT * 0x10)); return 0; } static void -gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu_priv *priv) +gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu *pmu) { - nv_wr32(priv, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000); - nv_wr32(priv, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000); + nv_wr32(pmu, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000); + nv_wr32(pmu, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000); } static void gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) { - struct gk20a_pmu_priv *priv = - container_of(alarm, struct gk20a_pmu_priv, alarm); - struct gk20a_pmu_dvfs_data *data = priv->data; + struct gk20a_pmu *pmu = + container_of(alarm, struct gk20a_pmu, alarm); + struct gk20a_pmu_dvfs_data *data = pmu->data; struct gk20a_pmu_dvfs_dev_status status; - struct nvkm_clk *clk = nvkm_clk(priv); - struct nvkm_volt *volt = nvkm_volt(priv); + struct nvkm_clk *clk = nvkm_clk(pmu); + struct nvkm_volt *volt = nvkm_volt(pmu); u32 utilization = 0; int state, ret; @@ -129,9 +129,9 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) if (!clk || !volt) goto resched; - ret = gk20a_pmu_dvfs_get_dev_status(priv, &status); + ret = gk20a_pmu_dvfs_get_dev_status(pmu, &status); if (ret) { - nv_warn(priv, "failed to get device status\n"); + nv_warn(pmu, "failed to get device status\n"); goto resched; } @@ -140,55 +140,53 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) data->avg_load = (data->p_smooth * data->avg_load) + utilization; data->avg_load /= data->p_smooth + 1; - nv_trace(priv, "utilization = %d %%, avg_load = %d %%\n", + nv_trace(pmu, "utilization = %d %%, avg_load = %d %%\n", utilization, data->avg_load); - ret = gk20a_pmu_dvfs_get_cur_state(priv, &state); + ret = gk20a_pmu_dvfs_get_cur_state(pmu, &state); if (ret) { - nv_warn(priv, "failed to get current state\n"); + nv_warn(pmu, "failed to get current state\n"); goto resched; } - if (gk20a_pmu_dvfs_get_target_state(priv, &state, data->avg_load)) { - nv_trace(priv, "set new state to %d\n", state); - gk20a_pmu_dvfs_target(priv, &state); + if (gk20a_pmu_dvfs_get_target_state(pmu, &state, data->avg_load)) { + nv_trace(pmu, "set new state to %d\n", state); + gk20a_pmu_dvfs_target(pmu, &state); } resched: - gk20a_pmu_dvfs_reset_dev_status(priv); - nvkm_timer_alarm(priv, 100000000, alarm); + gk20a_pmu_dvfs_reset_dev_status(pmu); + nvkm_timer_alarm(pmu, 100000000, alarm); } static int gk20a_pmu_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_pmu *pmu = (void *)object; - struct gk20a_pmu_priv *priv = (void *)pmu; + struct gk20a_pmu *pmu = (void *)object; - nvkm_timer_alarm_cancel(priv, &priv->alarm); + nvkm_timer_alarm_cancel(pmu, &pmu->alarm); - return nvkm_subdev_fini(&pmu->base, suspend); + return nvkm_subdev_fini(&pmu->base.subdev, suspend); } static int gk20a_pmu_init(struct nvkm_object *object) { - struct nvkm_pmu *pmu = (void *)object; - struct gk20a_pmu_priv *priv = (void *)pmu; + struct gk20a_pmu *pmu = (void *)object; int ret; - ret = nvkm_subdev_init(&pmu->base); + ret = nvkm_subdev_init(&pmu->base.subdev); if (ret) return ret; - pmu->pgob = nvkm_pmu_pgob; + pmu->base.pgob = nvkm_pmu_pgob; /* init pwr perf counter */ nv_wr32(pmu, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001); nv_wr32(pmu, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); nv_wr32(pmu, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); - nvkm_timer_alarm(pmu, 2000000000, &priv->alarm); + nvkm_timer_alarm(pmu, 2000000000, &pmu->alarm); return ret; } @@ -204,17 +202,17 @@ gk20a_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk20a_pmu_priv *priv; + struct gk20a_pmu *pmu; int ret; - ret = nvkm_pmu_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_pmu_create(parent, engine, oclass, &pmu); + *pobject = nv_object(pmu); if (ret) return ret; - priv->data = &gk20a_dvfs_data; + pmu->data = &gk20a_dvfs_data; - nvkm_alarm_init(&priv->alarm, gk20a_pmu_dvfs_work); + nvkm_alarm_init(&pmu->alarm, gk20a_pmu_dvfs_work); return 0; } -- GitLab From da06b46b720687117178d3ee85a601762f1c36b5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5338/7006] drm/nouveau/therm: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/therm.h | 14 +- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 10 +- .../gpu/drm/nouveau/nvkm/subdev/therm/base.c | 232 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 122 ++++----- .../drm/nouveau/nvkm/subdev/therm/fannil.c | 6 +- .../drm/nouveau/nvkm/subdev/therm/fanpwm.c | 65 ++--- .../drm/nouveau/nvkm/subdev/therm/fantog.c | 84 +++---- .../gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 67 +++-- .../gpu/drm/nouveau/nvkm/subdev/therm/gf110.c | 44 ++-- .../gpu/drm/nouveau/nvkm/subdev/therm/gm107.c | 26 +- .../gpu/drm/nouveau/nvkm/subdev/therm/gt215.c | 44 ++-- .../gpu/drm/nouveau/nvkm/subdev/therm/ic.c | 16 +- .../gpu/drm/nouveau/nvkm/subdev/therm/nv40.c | 32 ++- .../gpu/drm/nouveau/nvkm/subdev/therm/nv50.c | 32 ++- .../gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 112 ++++----- 15 files changed, 440 insertions(+), 466 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h index 6662829b6db1a..6e60f9bceabaf 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h @@ -24,7 +24,7 @@ enum nvkm_therm_attr_type { }; struct nvkm_therm { - struct nvkm_subdev base; + struct nvkm_subdev subdev; int (*pwm_ctrl)(struct nvkm_therm *, int line, bool); int (*pwm_get)(struct nvkm_therm *, int line, u32 *, u32 *); @@ -50,16 +50,16 @@ nvkm_therm(void *obj) #define nvkm_therm_create(p,e,o,d) \ nvkm_therm_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_therm_destroy(p) ({ \ - struct nvkm_therm *therm = (p); \ - _nvkm_therm_dtor(nv_object(therm)); \ + struct nvkm_therm *_therm = (p); \ + _nvkm_therm_dtor(nv_object(_therm)); \ }) #define nvkm_therm_init(p) ({ \ - struct nvkm_therm *therm = (p); \ - _nvkm_therm_init(nv_object(therm)); \ + struct nvkm_therm *_therm = (p); \ + _nvkm_therm_init(nv_object(_therm)); \ }) #define nvkm_therm_fini(p,s) ({ \ - struct nvkm_therm *therm = (p); \ - _nvkm_therm_init(nv_object(therm), (s)); \ + struct nvkm_therm *_therm = (p); \ + _nvkm_therm_init(nv_object(_therm), (s)); \ }) int nvkm_therm_create_(struct nvkm_object *, struct nvkm_object *, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index a624e9eb0c3b9..d54d84aaf763c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -76,7 +76,7 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, static int nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) { - struct nvkm_therm *ptherm = nvkm_therm(clk); + struct nvkm_therm *therm = nvkm_therm(clk); struct nvkm_volt *volt = nvkm_volt(clk); struct nvkm_cstate *cstate; int ret; @@ -87,8 +87,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) cstate = &pstate->base; } - if (ptherm) { - ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, +1); + if (therm) { + ret = nvkm_therm_cstate(therm, pstate->fanspeed, +1); if (ret && ret != -ENODEV) { nv_error(clk, "failed to raise fan speed: %d\n", ret); return ret; @@ -115,8 +115,8 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) nv_error(clk, "failed to lower voltage: %d\n", ret); } - if (ptherm) { - ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, -1); + if (therm) { + ret = nvkm_therm_cstate(therm, pstate->fanspeed, -1); if (ret && ret != -ENODEV) nv_error(clk, "failed to lower fan speed: %d\n", ret); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index eb86c3ed5f568..abb3fdc18910d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -24,18 +24,18 @@ #include "priv.h" static int -nvkm_therm_update_trip(struct nvkm_therm *therm) +nvkm_therm_update_trip(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_trip_point *trip = priv->fan->bios.trip, + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvbios_therm_trip_point *trip = therm->fan->bios.trip, *cur_trip = NULL, - *last_trip = priv->last_trip; - u8 temp = therm->temp_get(therm); + *last_trip = therm->last_trip; + u8 temp = therm->base.temp_get(&therm->base); u16 duty, i; /* look for the trip point corresponding to the current temperature */ cur_trip = NULL; - for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) { + for (i = 0; i < therm->fan->bios.nr_fan_trip; i++) { if (temp >= trip[i].temp) cur_trip = &trip[i]; } @@ -47,72 +47,72 @@ nvkm_therm_update_trip(struct nvkm_therm *therm) if (cur_trip) { duty = cur_trip->fan_duty; - priv->last_trip = cur_trip; + therm->last_trip = cur_trip; } else { duty = 0; - priv->last_trip = NULL; + therm->last_trip = NULL; } return duty; } static int -nvkm_therm_update_linear(struct nvkm_therm *therm) +nvkm_therm_update_linear(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - u8 linear_min_temp = priv->fan->bios.linear_min_temp; - u8 linear_max_temp = priv->fan->bios.linear_max_temp; - u8 temp = therm->temp_get(therm); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + u8 linear_min_temp = therm->fan->bios.linear_min_temp; + u8 linear_max_temp = therm->fan->bios.linear_max_temp; + u8 temp = therm->base.temp_get(&therm->base); u16 duty; /* handle the non-linear part first */ if (temp < linear_min_temp) - return priv->fan->bios.min_duty; + return therm->fan->bios.min_duty; else if (temp > linear_max_temp) - return priv->fan->bios.max_duty; + return therm->fan->bios.max_duty; /* we are in the linear zone */ duty = (temp - linear_min_temp); - duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty); + duty *= (therm->fan->bios.max_duty - therm->fan->bios.min_duty); duty /= (linear_max_temp - linear_min_temp); - duty += priv->fan->bios.min_duty; + duty += therm->fan->bios.min_duty; return duty; } static void -nvkm_therm_update(struct nvkm_therm *therm, int mode) +nvkm_therm_update(struct nvkm_therm *obj, int mode) { + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_timer *ptimer = nvkm_timer(therm); - struct nvkm_therm_priv *priv = (void *)therm; unsigned long flags; bool immd = true; bool poll = true; int duty = -1; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&therm->lock, flags); if (mode < 0) - mode = priv->mode; - priv->mode = mode; + mode = therm->mode; + therm->mode = mode; switch (mode) { case NVKM_THERM_CTRL_MANUAL: - ptimer->alarm_cancel(ptimer, &priv->alarm); - duty = nvkm_therm_fan_get(therm); + ptimer->alarm_cancel(ptimer, &therm->alarm); + duty = nvkm_therm_fan_get(&therm->base); if (duty < 0) duty = 100; poll = false; break; case NVKM_THERM_CTRL_AUTO: - switch(priv->fan->bios.fan_mode) { + switch(therm->fan->bios.fan_mode) { case NVBIOS_THERM_FAN_TRIP: - duty = nvkm_therm_update_trip(therm); + duty = nvkm_therm_update_trip(&therm->base); break; case NVBIOS_THERM_FAN_LINEAR: - duty = nvkm_therm_update_linear(therm); + duty = nvkm_therm_update_linear(&therm->base); break; case NVBIOS_THERM_FAN_OTHER: - if (priv->cstate) - duty = priv->cstate; + if (therm->cstate) + duty = therm->cstate; poll = false; break; } @@ -120,29 +120,29 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) break; case NVKM_THERM_CTRL_NONE: default: - ptimer->alarm_cancel(ptimer, &priv->alarm); + ptimer->alarm_cancel(ptimer, &therm->alarm); poll = false; } - if (list_empty(&priv->alarm.head) && poll) - ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm); - spin_unlock_irqrestore(&priv->lock, flags); + if (list_empty(&therm->alarm.head) && poll) + ptimer->alarm(ptimer, 1000000000ULL, &therm->alarm); + spin_unlock_irqrestore(&therm->lock, flags); if (duty >= 0) { nv_debug(therm, "FAN target request: %d%%\n", duty); - nvkm_therm_fan_set(therm, immd, duty); + nvkm_therm_fan_set(&therm->base, immd, duty); } } int -nvkm_therm_cstate(struct nvkm_therm *ptherm, int fan, int dir) +nvkm_therm_cstate(struct nvkm_therm *obj, int fan, int dir) { - struct nvkm_therm_priv *priv = (void *)ptherm; - if (!dir || (dir < 0 && fan < priv->cstate) || - (dir > 0 && fan > priv->cstate)) { - nv_debug(ptherm, "default fan speed -> %d%%\n", fan); - priv->cstate = fan; - nvkm_therm_update(ptherm, -1); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + if (!dir || (dir < 0 && fan < therm->cstate) || + (dir > 0 && fan > therm->cstate)) { + nv_debug(therm, "default fan speed -> %d%%\n", fan); + therm->cstate = fan; + nvkm_therm_update(&therm->base, -1); } return 0; } @@ -150,15 +150,15 @@ nvkm_therm_cstate(struct nvkm_therm *ptherm, int fan, int dir) static void nvkm_therm_alarm(struct nvkm_alarm *alarm) { - struct nvkm_therm_priv *priv = + struct nvkm_therm_priv *therm = container_of(alarm, struct nvkm_therm_priv, alarm); - nvkm_therm_update(&priv->base, -1); + nvkm_therm_update(&therm->base, -1); } int -nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode) +nvkm_therm_fan_mode(struct nvkm_therm *obj, int mode) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_device *device = nv_device(therm); static const char *name[] = { "disabled", @@ -174,105 +174,105 @@ nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode) /* do not allow automatic fan management if the thermal sensor is * not available */ - if (mode == NVKM_THERM_CTRL_AUTO && therm->temp_get(therm) < 0) + if (mode == NVKM_THERM_CTRL_AUTO && + therm->base.temp_get(&therm->base) < 0) return -EINVAL; - if (priv->mode == mode) + if (therm->mode == mode) return 0; nv_info(therm, "fan management: %s\n", name[mode]); - nvkm_therm_update(therm, mode); + nvkm_therm_update(&therm->base, mode); return 0; } int -nvkm_therm_attr_get(struct nvkm_therm *therm, - enum nvkm_therm_attr_type type) +nvkm_therm_attr_get(struct nvkm_therm *obj, enum nvkm_therm_attr_type type) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); switch (type) { case NVKM_THERM_ATTR_FAN_MIN_DUTY: - return priv->fan->bios.min_duty; + return therm->fan->bios.min_duty; case NVKM_THERM_ATTR_FAN_MAX_DUTY: - return priv->fan->bios.max_duty; + return therm->fan->bios.max_duty; case NVKM_THERM_ATTR_FAN_MODE: - return priv->mode; + return therm->mode; case NVKM_THERM_ATTR_THRS_FAN_BOOST: - return priv->bios_sensor.thrs_fan_boost.temp; + return therm->bios_sensor.thrs_fan_boost.temp; case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST: - return priv->bios_sensor.thrs_fan_boost.hysteresis; + return therm->bios_sensor.thrs_fan_boost.hysteresis; case NVKM_THERM_ATTR_THRS_DOWN_CLK: - return priv->bios_sensor.thrs_down_clock.temp; + return therm->bios_sensor.thrs_down_clock.temp; case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST: - return priv->bios_sensor.thrs_down_clock.hysteresis; + return therm->bios_sensor.thrs_down_clock.hysteresis; case NVKM_THERM_ATTR_THRS_CRITICAL: - return priv->bios_sensor.thrs_critical.temp; + return therm->bios_sensor.thrs_critical.temp; case NVKM_THERM_ATTR_THRS_CRITICAL_HYST: - return priv->bios_sensor.thrs_critical.hysteresis; + return therm->bios_sensor.thrs_critical.hysteresis; case NVKM_THERM_ATTR_THRS_SHUTDOWN: - return priv->bios_sensor.thrs_shutdown.temp; + return therm->bios_sensor.thrs_shutdown.temp; case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST: - return priv->bios_sensor.thrs_shutdown.hysteresis; + return therm->bios_sensor.thrs_shutdown.hysteresis; } return -EINVAL; } int -nvkm_therm_attr_set(struct nvkm_therm *therm, +nvkm_therm_attr_set(struct nvkm_therm *obj, enum nvkm_therm_attr_type type, int value) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); switch (type) { case NVKM_THERM_ATTR_FAN_MIN_DUTY: if (value < 0) value = 0; - if (value > priv->fan->bios.max_duty) - value = priv->fan->bios.max_duty; - priv->fan->bios.min_duty = value; + if (value > therm->fan->bios.max_duty) + value = therm->fan->bios.max_duty; + therm->fan->bios.min_duty = value; return 0; case NVKM_THERM_ATTR_FAN_MAX_DUTY: if (value < 0) value = 0; - if (value < priv->fan->bios.min_duty) - value = priv->fan->bios.min_duty; - priv->fan->bios.max_duty = value; + if (value < therm->fan->bios.min_duty) + value = therm->fan->bios.min_duty; + therm->fan->bios.max_duty = value; return 0; case NVKM_THERM_ATTR_FAN_MODE: - return nvkm_therm_fan_mode(therm, value); + return nvkm_therm_fan_mode(&therm->base, value); case NVKM_THERM_ATTR_THRS_FAN_BOOST: - priv->bios_sensor.thrs_fan_boost.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_fan_boost.temp = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST: - priv->bios_sensor.thrs_fan_boost.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_fan_boost.hysteresis = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_DOWN_CLK: - priv->bios_sensor.thrs_down_clock.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_down_clock.temp = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST: - priv->bios_sensor.thrs_down_clock.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_down_clock.hysteresis = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_CRITICAL: - priv->bios_sensor.thrs_critical.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_critical.temp = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_CRITICAL_HYST: - priv->bios_sensor.thrs_critical.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_critical.hysteresis = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_SHUTDOWN: - priv->bios_sensor.thrs_shutdown.temp = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_shutdown.temp = value; + therm->sensor.program_alarms(&therm->base); return 0; case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST: - priv->bios_sensor.thrs_shutdown.hysteresis = value; - priv->sensor.program_alarms(therm); + therm->bios_sensor.thrs_shutdown.hysteresis = value; + therm->sensor.program_alarms(&therm->base); return 0; } @@ -282,65 +282,63 @@ nvkm_therm_attr_set(struct nvkm_therm *therm, int _nvkm_therm_init(struct nvkm_object *object) { - struct nvkm_therm *therm = (void *)object; - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = (void *)object; int ret; - ret = nvkm_subdev_init(&therm->base); + ret = nvkm_subdev_init(&therm->base.subdev); if (ret) return ret; - if (priv->suspend >= 0) { + if (therm->suspend >= 0) { /* restore the pwm value only when on manual or auto mode */ - if (priv->suspend > 0) - nvkm_therm_fan_set(therm, true, priv->fan->percent); + if (therm->suspend > 0) + nvkm_therm_fan_set(&therm->base, true, therm->fan->percent); - nvkm_therm_fan_mode(therm, priv->suspend); + nvkm_therm_fan_mode(&therm->base, therm->suspend); } - nvkm_therm_sensor_init(therm); - nvkm_therm_fan_init(therm); + nvkm_therm_sensor_init(&therm->base); + nvkm_therm_fan_init(&therm->base); return 0; } int _nvkm_therm_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_therm *therm = (void *)object; - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = (void *)object; - nvkm_therm_fan_fini(therm, suspend); - nvkm_therm_sensor_fini(therm, suspend); + nvkm_therm_fan_fini(&therm->base, suspend); + nvkm_therm_sensor_fini(&therm->base, suspend); if (suspend) { - priv->suspend = priv->mode; - priv->mode = NVKM_THERM_CTRL_NONE; + therm->suspend = therm->mode; + therm->mode = NVKM_THERM_CTRL_NONE; } - return nvkm_subdev_fini(&therm->base, suspend); + return nvkm_subdev_fini(&therm->base.subdev, suspend); } int nvkm_therm_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PTHERM", "therm", length, pobject); - priv = *pobject; + therm = *pobject; if (ret) return ret; - nvkm_alarm_init(&priv->alarm, nvkm_therm_alarm); - spin_lock_init(&priv->lock); - spin_lock_init(&priv->sensor.alarm_program_lock); + nvkm_alarm_init(&therm->alarm, nvkm_therm_alarm); + spin_lock_init(&therm->lock); + spin_lock_init(&therm->sensor.alarm_program_lock); - priv->base.fan_get = nvkm_therm_fan_user_get; - priv->base.fan_set = nvkm_therm_fan_user_set; - priv->base.fan_sense = nvkm_therm_fan_sense; - priv->base.attr_get = nvkm_therm_attr_get; - priv->base.attr_set = nvkm_therm_attr_set; - priv->mode = priv->suspend = -1; /* undefined */ + therm->base.fan_get = nvkm_therm_fan_user_get; + therm->base.fan_set = nvkm_therm_fan_user_set; + therm->base.fan_sense = nvkm_therm_fan_sense; + therm->base.attr_get = nvkm_therm_attr_get; + therm->base.attr_set = nvkm_therm_attr_set; + therm->mode = therm->suspend = -1; /* undefined */ return 0; } @@ -359,7 +357,7 @@ nvkm_therm_preinit(struct nvkm_therm *therm) void _nvkm_therm_dtor(struct nvkm_object *object) { - struct nvkm_therm_priv *priv = (void *)object; - kfree(priv->fan); - nvkm_subdev_destroy(&priv->base.base); + struct nvkm_therm_priv *therm = (void *)object; + kfree(therm->fan); + nvkm_subdev_destroy(&therm->base.subdev); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index 434fa745ca40f..37b9f47f663c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -31,9 +31,8 @@ static int nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) { - struct nvkm_therm *therm = fan->parent; - struct nvkm_therm_priv *priv = (void *)therm; - struct nvkm_timer *ptimer = nvkm_timer(priv); + struct nvkm_therm_priv *therm = (void *)fan->parent; + struct nvkm_timer *ptimer = nvkm_timer(therm); unsigned long flags; int ret = 0; int duty; @@ -50,7 +49,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) } /* check that we're not already at the target duty cycle */ - duty = fan->get(therm); + duty = fan->get(&therm->base); if (duty == target) { spin_unlock_irqrestore(&fan->lock, flags); return 0; @@ -71,7 +70,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) } nv_debug(therm, "FAN update: %d\n", duty); - ret = fan->set(therm, duty); + ret = fan->set(&therm->base, duty); if (ret) { spin_unlock_irqrestore(&fan->lock, flags); return ret; @@ -109,29 +108,29 @@ nvkm_fan_alarm(struct nvkm_alarm *alarm) } int -nvkm_therm_fan_get(struct nvkm_therm *therm) +nvkm_therm_fan_get(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - return priv->fan->get(therm); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + return therm->fan->get(&therm->base); } int -nvkm_therm_fan_set(struct nvkm_therm *therm, bool immediate, int percent) +nvkm_therm_fan_set(struct nvkm_therm *obj, bool immediate, int percent) { - struct nvkm_therm_priv *priv = (void *)therm; - return nvkm_fan_update(priv->fan, immediate, percent); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + return nvkm_fan_update(therm->fan, immediate, percent); } int -nvkm_therm_fan_sense(struct nvkm_therm *therm) +nvkm_therm_fan_sense(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_timer *ptimer = nvkm_timer(therm); struct nvkm_gpio *gpio = nvkm_gpio(therm); u32 cycles, cur, prev; u64 start, end, tach; - if (priv->fan->tach.func == DCB_GPIO_UNUSED) + if (therm->fan->tach.func == DCB_GPIO_UNUSED) return -ENODEV; /* Time a complete rotation and extrapolate to RPM: @@ -139,12 +138,12 @@ nvkm_therm_fan_sense(struct nvkm_therm *therm) * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ start = ptimer->read(ptimer); - prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); + prev = gpio->get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); cycles = 0; do { usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ - cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line); + cur = gpio->get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); if (prev != cur) { if (!start) start = ptimer->read(ptimer); @@ -163,71 +162,72 @@ nvkm_therm_fan_sense(struct nvkm_therm *therm) } int -nvkm_therm_fan_user_get(struct nvkm_therm *therm) +nvkm_therm_fan_user_get(struct nvkm_therm *obj) { - return nvkm_therm_fan_get(therm); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + return nvkm_therm_fan_get(&therm->base); } int -nvkm_therm_fan_user_set(struct nvkm_therm *therm, int percent) +nvkm_therm_fan_user_set(struct nvkm_therm *obj, int percent) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - if (priv->mode != NVKM_THERM_CTRL_MANUAL) + if (therm->mode != NVKM_THERM_CTRL_MANUAL) return -EINVAL; - return nvkm_therm_fan_set(therm, true, percent); + return nvkm_therm_fan_set(&therm->base, true, percent); } static void -nvkm_therm_fan_set_defaults(struct nvkm_therm *therm) +nvkm_therm_fan_set_defaults(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - - priv->fan->bios.pwm_freq = 0; - priv->fan->bios.min_duty = 0; - priv->fan->bios.max_duty = 100; - priv->fan->bios.bump_period = 500; - priv->fan->bios.slow_down_period = 2000; - priv->fan->bios.linear_min_temp = 40; - priv->fan->bios.linear_max_temp = 85; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + + therm->fan->bios.pwm_freq = 0; + therm->fan->bios.min_duty = 0; + therm->fan->bios.max_duty = 100; + therm->fan->bios.bump_period = 500; + therm->fan->bios.slow_down_period = 2000; + therm->fan->bios.linear_min_temp = 40; + therm->fan->bios.linear_max_temp = 85; } static void -nvkm_therm_fan_safety_checks(struct nvkm_therm *therm) +nvkm_therm_fan_safety_checks(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - if (priv->fan->bios.min_duty > 100) - priv->fan->bios.min_duty = 100; - if (priv->fan->bios.max_duty > 100) - priv->fan->bios.max_duty = 100; + if (therm->fan->bios.min_duty > 100) + therm->fan->bios.min_duty = 100; + if (therm->fan->bios.max_duty > 100) + therm->fan->bios.max_duty = 100; - if (priv->fan->bios.min_duty > priv->fan->bios.max_duty) - priv->fan->bios.min_duty = priv->fan->bios.max_duty; + if (therm->fan->bios.min_duty > therm->fan->bios.max_duty) + therm->fan->bios.min_duty = therm->fan->bios.max_duty; } int -nvkm_therm_fan_init(struct nvkm_therm *therm) +nvkm_therm_fan_init(struct nvkm_therm *obj) { return 0; } int -nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend) +nvkm_therm_fan_fini(struct nvkm_therm *obj, bool suspend) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_timer *ptimer = nvkm_timer(therm); if (suspend) - ptimer->alarm_cancel(ptimer, &priv->fan->alarm); + ptimer->alarm_cancel(ptimer, &therm->fan->alarm); return 0; } int -nvkm_therm_fan_ctor(struct nvkm_therm *therm) +nvkm_therm_fan_ctor(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_gpio *gpio = nvkm_gpio(therm); struct nvkm_bios *bios = nvkm_bios(therm); struct dcb_gpio_func func; @@ -241,42 +241,42 @@ nvkm_therm_fan_ctor(struct nvkm_therm *therm) nv_debug(therm, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { - ret = nvkm_fanpwm_create(therm, &func); + ret = nvkm_fanpwm_create(&therm->base, &func); if (ret != 0) - ret = nvkm_fantog_create(therm, &func); + ret = nvkm_fantog_create(&therm->base, &func); } } /* no controllable fan found, create a dummy fan module */ if (ret != 0) { - ret = nvkm_fannil_create(therm); + ret = nvkm_fannil_create(&therm->base); if (ret) return ret; } - nv_info(therm, "FAN control: %s\n", priv->fan->type); + nv_info(therm, "FAN control: %s\n", therm->fan->type); /* read the current speed, it is useful when resuming */ - priv->fan->percent = nvkm_therm_fan_get(therm); + therm->fan->percent = nvkm_therm_fan_get(&therm->base); /* attempt to detect a tachometer connection */ - ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach); + ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &therm->fan->tach); if (ret) - priv->fan->tach.func = DCB_GPIO_UNUSED; + therm->fan->tach.func = DCB_GPIO_UNUSED; /* initialise fan bump/slow update handling */ - priv->fan->parent = therm; - nvkm_alarm_init(&priv->fan->alarm, nvkm_fan_alarm); - spin_lock_init(&priv->fan->lock); + therm->fan->parent = &therm->base; + nvkm_alarm_init(&therm->fan->alarm, nvkm_fan_alarm); + spin_lock_init(&therm->fan->lock); /* other random init... */ - nvkm_therm_fan_set_defaults(therm); - nvbios_perf_fan_parse(bios, &priv->fan->perf); - if (!nvbios_fan_parse(bios, &priv->fan->bios)) { + nvkm_therm_fan_set_defaults(&therm->base); + nvbios_perf_fan_parse(bios, &therm->fan->perf); + if (!nvbios_fan_parse(bios, &therm->fan->bios)) { nv_debug(therm, "parsing the fan table failed\n"); - if (nvbios_therm_fan_parse(bios, &priv->fan->bios)) + if (nvbios_therm_fan_parse(bios, &therm->fan->bios)) nv_error(therm, "parsing both fan tables failed\n"); } - nvkm_therm_fan_safety_checks(therm); + nvkm_therm_fan_safety_checks(&therm->base); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c index 534e5970ec9c6..693b4efd18410 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c @@ -36,13 +36,13 @@ nvkm_fannil_set(struct nvkm_therm *therm, int percent) } int -nvkm_fannil_create(struct nvkm_therm *therm) +nvkm_fannil_create(struct nvkm_therm *obj) { - struct nvkm_therm_priv *tpriv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fan *priv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); - tpriv->fan = priv; + therm->fan = priv; if (!priv) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index 3cf4192a33af9..97917c532e148 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -29,84 +29,85 @@ #include #include -struct nvkm_fanpwm_priv { +struct nvkm_fanpwm { struct nvkm_fan base; struct dcb_gpio_func func; }; static int -nvkm_fanpwm_get(struct nvkm_therm *therm) +nvkm_fanpwm_get(struct nvkm_therm *obj) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_fanpwm *fan = (void *)therm->fan; struct nvkm_gpio *gpio = nvkm_gpio(therm); int card_type = nv_device(therm)->card_type; u32 divs, duty; int ret; - ret = therm->pwm_get(therm, priv->func.line, &divs, &duty); + ret = therm->base.pwm_get(&therm->base, fan->func.line, &divs, &duty); if (ret == 0 && divs) { divs = max(divs, duty); - if (card_type <= NV_40 || (priv->func.log[0] & 1)) + if (card_type <= NV_40 || (fan->func.log[0] & 1)) duty = divs - duty; return (duty * 100) / divs; } - return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100; + return gpio->get(gpio, 0, fan->func.func, fan->func.line) * 100; } static int -nvkm_fanpwm_set(struct nvkm_therm *therm, int percent) +nvkm_fanpwm_set(struct nvkm_therm *obj, int percent) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_fanpwm *fan = (void *)therm->fan; int card_type = nv_device(therm)->card_type; u32 divs, duty; int ret; - divs = priv->base.perf.pwm_divisor; - if (priv->base.bios.pwm_freq) { + divs = fan->base.perf.pwm_divisor; + if (fan->base.bios.pwm_freq) { divs = 1; - if (therm->pwm_clock) - divs = therm->pwm_clock(therm, priv->func.line); - divs /= priv->base.bios.pwm_freq; + if (therm->base.pwm_clock) + divs = therm->base.pwm_clock(&therm->base, + fan->func.line); + divs /= fan->base.bios.pwm_freq; } duty = ((divs * percent) + 99) / 100; - if (card_type <= NV_40 || (priv->func.log[0] & 1)) + if (card_type <= NV_40 || (fan->func.log[0] & 1)) duty = divs - duty; - ret = therm->pwm_set(therm, priv->func.line, divs, duty); + ret = therm->base.pwm_set(&therm->base, fan->func.line, divs, duty); if (ret == 0) - ret = therm->pwm_ctrl(therm, priv->func.line, true); + ret = therm->base.pwm_ctrl(&therm->base, fan->func.line, true); return ret; } int -nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) +nvkm_fanpwm_create(struct nvkm_therm *obj, struct dcb_gpio_func *func) { + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_device *device = nv_device(therm); - struct nvkm_therm_priv *tpriv = (void *)therm; struct nvkm_bios *bios = nvkm_bios(therm); - struct nvkm_fanpwm_priv *priv; - struct nvbios_therm_fan fan; + struct nvkm_fanpwm *fan; + struct nvbios_therm_fan info; u32 divs, duty; - nvbios_fan_parse(bios, &fan); + nvbios_fan_parse(bios, &info); if (!nvkm_boolopt(device->cfgopt, "NvFanPWM", func->param) || - !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE || - therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) + !therm->base.pwm_ctrl || info.type == NVBIOS_THERM_FAN_TOGGLE || + therm->base.pwm_get(&therm->base, func->line, &divs, &duty) == -ENODEV) return -ENODEV; - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - tpriv->fan = &priv->base; - if (!priv) + fan = kzalloc(sizeof(*fan), GFP_KERNEL); + therm->fan = &fan->base; + if (!fan) return -ENOMEM; - priv->base.type = "PWM"; - priv->base.get = nvkm_fanpwm_get; - priv->base.set = nvkm_fanpwm_set; - priv->func = *func; + fan->base.type = "PWM"; + fan->base.get = nvkm_fanpwm_get; + fan->base.set = nvkm_fanpwm_set; + fan->func = *func; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 4ce041e813713..138ee99ec0ea1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -26,7 +26,7 @@ #include #include -struct nvkm_fantog_priv { +struct nvkm_fantog { struct nvkm_fan base; struct nvkm_alarm alarm; spinlock_t lock; @@ -36,83 +36,83 @@ struct nvkm_fantog_priv { }; static void -nvkm_fantog_update(struct nvkm_fantog_priv *priv, int percent) +nvkm_fantog_update(struct nvkm_fantog *fan, int percent) { - struct nvkm_therm_priv *tpriv = (void *)priv->base.parent; - struct nvkm_timer *ptimer = nvkm_timer(tpriv); - struct nvkm_gpio *gpio = nvkm_gpio(tpriv); + struct nvkm_therm_priv *therm = (void *)fan->base.parent; + struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_gpio *gpio = nvkm_gpio(therm); unsigned long flags; int duty; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&fan->lock, flags); if (percent < 0) - percent = priv->percent; - priv->percent = percent; + percent = fan->percent; + fan->percent = percent; duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff); gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty); - if (list_empty(&priv->alarm.head) && percent != (duty * 100)) { - u64 next_change = (percent * priv->period_us) / 100; + if (list_empty(&fan->alarm.head) && percent != (duty * 100)) { + u64 next_change = (percent * fan->period_us) / 100; if (!duty) - next_change = priv->period_us - next_change; - ptimer->alarm(ptimer, next_change * 1000, &priv->alarm); + next_change = fan->period_us - next_change; + ptimer->alarm(ptimer, next_change * 1000, &fan->alarm); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&fan->lock, flags); } static void nvkm_fantog_alarm(struct nvkm_alarm *alarm) { - struct nvkm_fantog_priv *priv = - container_of(alarm, struct nvkm_fantog_priv, alarm); - nvkm_fantog_update(priv, -1); + struct nvkm_fantog *fan = + container_of(alarm, struct nvkm_fantog, alarm); + nvkm_fantog_update(fan, -1); } static int -nvkm_fantog_get(struct nvkm_therm *therm) +nvkm_fantog_get(struct nvkm_therm *obj) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fantog_priv *priv = (void *)tpriv->fan; - return priv->percent; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_fantog *fan = (void *)therm->fan; + return fan->percent; } static int -nvkm_fantog_set(struct nvkm_therm *therm, int percent) +nvkm_fantog_set(struct nvkm_therm *obj, int percent) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fantog_priv *priv = (void *)tpriv->fan; - if (therm->pwm_ctrl) - therm->pwm_ctrl(therm, priv->func.line, false); - nvkm_fantog_update(priv, percent); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_fantog *fan = (void *)therm->fan; + if (therm->base.pwm_ctrl) + therm->base.pwm_ctrl(&therm->base, fan->func.line, false); + nvkm_fantog_update(fan, percent); return 0; } int -nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) +nvkm_fantog_create(struct nvkm_therm *obj, struct dcb_gpio_func *func) { - struct nvkm_therm_priv *tpriv = (void *)therm; - struct nvkm_fantog_priv *priv; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_fantog *fan; int ret; - if (therm->pwm_ctrl) { - ret = therm->pwm_ctrl(therm, func->line, false); + if (therm->base.pwm_ctrl) { + ret = therm->base.pwm_ctrl(&therm->base, func->line, false); if (ret) return ret; } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - tpriv->fan = &priv->base; - if (!priv) + fan = kzalloc(sizeof(*fan), GFP_KERNEL); + therm->fan = &fan->base; + if (!fan) return -ENOMEM; - priv->base.type = "toggle"; - priv->base.get = nvkm_fantog_get; - priv->base.set = nvkm_fantog_set; - nvkm_alarm_init(&priv->alarm, nvkm_fantog_alarm); - priv->period_us = 100000; /* 10Hz */ - priv->percent = 100; - priv->func = *func; - spin_lock_init(&priv->lock); + fan->base.type = "toggle"; + fan->base.get = nvkm_fantog_get; + fan->base.set = nvkm_fantog_set; + nvkm_alarm_init(&fan->alarm, nvkm_fantog_alarm); + fan->period_us = 100000; /* 10Hz */ + fan->percent = 100; + fan->func = *func; + spin_lock_init(&fan->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index 85b5d0c18c0bb..555722900bb38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -26,10 +26,6 @@ #include -struct g84_therm_priv { - struct nvkm_therm_priv base; -}; - int g84_temp_get(struct nvkm_therm *therm) { @@ -55,13 +51,13 @@ g84_sensor_setup(struct nvkm_therm *therm) } static void -g84_therm_program_alarms(struct nvkm_therm *therm) +g84_therm_program_alarms(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; unsigned long flags; - spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); + spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); /* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */ nv_wr32(therm, 0x20000, 0x000003ff); @@ -78,7 +74,7 @@ g84_therm_program_alarms(struct nvkm_therm *therm) /* THRS_4 : down clock */ nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp); - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); nv_debug(therm, "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", @@ -137,19 +133,18 @@ g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm, static void g84_therm_intr(struct nvkm_subdev *subdev) { - struct nvkm_therm *therm = nvkm_therm(subdev); - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_therm_priv *therm = (void *)subdev; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; unsigned long flags; uint32_t intr; - spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); + spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); intr = nv_rd32(therm, 0x20100) & 0x3ff; /* THRS_4: downclock */ if (intr & 0x002) { - g84_therm_threshold_hyst_emulation(therm, 0x20414, 24, + g84_therm_threshold_hyst_emulation(&therm->base, 0x20414, 24, &sensor->thrs_down_clock, NVKM_THERM_THRS_DOWNCLOCK); intr &= ~0x002; @@ -157,7 +152,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* shutdown */ if (intr & 0x004) { - g84_therm_threshold_hyst_emulation(therm, 0x20480, 20, + g84_therm_threshold_hyst_emulation(&therm->base, 0x20480, 20, &sensor->thrs_shutdown, NVKM_THERM_THRS_SHUTDOWN); intr &= ~0x004; @@ -165,7 +160,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* THRS_1 : fan boost */ if (intr & 0x008) { - g84_therm_threshold_hyst_emulation(therm, 0x204c4, 21, + g84_therm_threshold_hyst_emulation(&therm->base, 0x204c4, 21, &sensor->thrs_fan_boost, NVKM_THERM_THRS_FANBOOST); intr &= ~0x008; @@ -173,7 +168,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* THRS_2 : critical */ if (intr & 0x010) { - g84_therm_threshold_hyst_emulation(therm, 0x204c0, 22, + g84_therm_threshold_hyst_emulation(&therm->base, 0x204c0, 22, &sensor->thrs_critical, NVKM_THERM_THRS_CRITICAL); intr &= ~0x010; @@ -186,20 +181,20 @@ g84_therm_intr(struct nvkm_subdev *subdev) nv_wr32(therm, 0x20100, 0xffffffff); nv_wr32(therm, 0x1100, 0x10000); /* PBUS */ - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); } static int g84_therm_init(struct nvkm_object *object) { - struct g84_therm_priv *priv = (void *)object; + struct nvkm_therm_priv *therm = (void *)object; int ret; - ret = nvkm_therm_init(&priv->base.base); + ret = nvkm_therm_init(&therm->base); if (ret) return ret; - g84_sensor_setup(&priv->base.base); + g84_sensor_setup(&therm->base); return 0; } @@ -208,37 +203,37 @@ g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g84_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_therm_create(parent, engine, oclass, &therm); + *pobject = nv_object(therm); if (ret) return ret; - priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; - priv->base.base.pwm_get = nv50_fan_pwm_get; - priv->base.base.pwm_set = nv50_fan_pwm_set; - priv->base.base.pwm_clock = nv50_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.sensor.program_alarms = g84_therm_program_alarms; - nv_subdev(priv)->intr = g84_therm_intr; + therm->base.pwm_ctrl = nv50_fan_pwm_ctrl; + therm->base.pwm_get = nv50_fan_pwm_get; + therm->base.pwm_set = nv50_fan_pwm_set; + therm->base.pwm_clock = nv50_fan_pwm_clock; + therm->base.temp_get = g84_temp_get; + therm->sensor.program_alarms = g84_therm_program_alarms; + nv_subdev(therm)->intr = g84_therm_intr; /* init the thresholds */ - nvkm_therm_sensor_set_threshold_state(&priv->base.base, + nvkm_therm_sensor_set_threshold_state(&therm->base, NVKM_THERM_THRS_SHUTDOWN, NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&priv->base.base, + nvkm_therm_sensor_set_threshold_state(&therm->base, NVKM_THERM_THRS_FANBOOST, NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&priv->base.base, + nvkm_therm_sensor_set_threshold_state(&therm->base, NVKM_THERM_THRS_CRITICAL, NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&priv->base.base, + nvkm_therm_sensor_set_threshold_state(&therm->base, NVKM_THERM_THRS_DOWNCLOCK, NVKM_THERM_THRS_LOWER); - return nvkm_therm_preinit(&priv->base.base); + return nvkm_therm_preinit(&therm->base); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c index 0540e6886d7d3..4a2a2de9ef0b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c @@ -23,10 +23,6 @@ */ #include "priv.h" -struct gf110_therm_priv { - struct nvkm_therm_priv base; -}; - static int pwm_info(struct nvkm_therm *therm, int line) { @@ -116,21 +112,21 @@ gf110_fan_pwm_clock(struct nvkm_therm *therm, int line) int gf110_therm_init(struct nvkm_object *object) { - struct gf110_therm_priv *priv = (void *)object; + struct nvkm_therm_priv *therm = (void *)object; int ret; - ret = nvkm_therm_init(&priv->base.base); + ret = nvkm_therm_init(&therm->base); if (ret) return ret; /* enable fan tach, count revolutions per-second */ - nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); - if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) { - nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line); - nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000); - nv_mask(priv, 0x00e720, 0x00000001, 0x00000001); + nv_mask(therm, 0x00e720, 0x00000003, 0x00000002); + if (therm->fan->tach.func != DCB_GPIO_UNUSED) { + nv_mask(therm, 0x00d79c, 0x000000ff, therm->fan->tach.line); + nv_wr32(therm, 0x00e724, nv_device(therm)->crystal * 1000); + nv_mask(therm, 0x00e720, 0x00000001, 0x00000001); } - nv_mask(priv, 0x00e720, 0x00000002, 0x00000000); + nv_mask(therm, 0x00e720, 0x00000002, 0x00000000); return 0; } @@ -140,24 +136,24 @@ gf110_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf110_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_therm_create(parent, engine, oclass, &therm); + *pobject = nv_object(therm); if (ret) return ret; - g84_sensor_setup(&priv->base.base); + g84_sensor_setup(&therm->base); - priv->base.base.pwm_ctrl = gf110_fan_pwm_ctrl; - priv->base.base.pwm_get = gf110_fan_pwm_get; - priv->base.base.pwm_set = gf110_fan_pwm_set; - priv->base.base.pwm_clock = gf110_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.base.fan_sense = gt215_therm_fan_sense; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&priv->base.base); + therm->base.pwm_ctrl = gf110_fan_pwm_ctrl; + therm->base.pwm_get = gf110_fan_pwm_get; + therm->base.pwm_set = gf110_fan_pwm_set; + therm->base.pwm_clock = gf110_fan_pwm_clock; + therm->base.temp_get = g84_temp_get; + therm->base.fan_sense = gt215_therm_fan_sense; + therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; + return nvkm_therm_preinit(&therm->base); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c index c1f3cf3618378..f2271f3e5990f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c @@ -23,10 +23,6 @@ */ #include "priv.h" -struct gm107_therm_priv { - struct nvkm_therm_priv base; -}; - static int gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { @@ -61,22 +57,22 @@ gm107_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gm107_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_therm_create(parent, engine, oclass, &therm); + *pobject = nv_object(therm); if (ret) return ret; - priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl; - priv->base.base.pwm_get = gm107_fan_pwm_get; - priv->base.base.pwm_set = gm107_fan_pwm_set; - priv->base.base.pwm_clock = gm107_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.base.fan_sense = gt215_therm_fan_sense; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&priv->base.base); + therm->base.pwm_ctrl = gm107_fan_pwm_ctrl; + therm->base.pwm_get = gm107_fan_pwm_get; + therm->base.pwm_set = gm107_fan_pwm_set; + therm->base.pwm_clock = gm107_fan_pwm_clock; + therm->base.temp_get = g84_temp_get; + therm->base.fan_sense = gt215_therm_fan_sense; + therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; + return nvkm_therm_preinit(&therm->base); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c index b7fa4716ca9f7..e6ba6e26da79a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c @@ -25,10 +25,6 @@ #include -struct gt215_therm_priv { - struct nvkm_therm_priv base; -}; - int gt215_therm_fan_sense(struct nvkm_therm *therm) { @@ -42,24 +38,24 @@ gt215_therm_fan_sense(struct nvkm_therm *therm) static int gt215_therm_init(struct nvkm_object *object) { - struct gt215_therm_priv *priv = (void *)object; - struct dcb_gpio_func *tach = &priv->base.fan->tach; + struct nvkm_therm_priv *therm = (void *)object; + struct dcb_gpio_func *tach = &therm->fan->tach; int ret; - ret = nvkm_therm_init(&priv->base.base); + ret = nvkm_therm_init(&therm->base); if (ret) return ret; - g84_sensor_setup(&priv->base.base); + g84_sensor_setup(&therm->base); /* enable fan tach, count revolutions per-second */ - nv_mask(priv, 0x00e720, 0x00000003, 0x00000002); + nv_mask(therm, 0x00e720, 0x00000003, 0x00000002); if (tach->func != DCB_GPIO_UNUSED) { - nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000); - nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16); - nv_mask(priv, 0x00e720, 0x00000001, 0x00000001); + nv_wr32(therm, 0x00e724, nv_device(therm)->crystal * 1000); + nv_mask(therm, 0x00e720, 0x001f0000, tach->line << 16); + nv_mask(therm, 0x00e720, 0x00000001, 0x00000001); } - nv_mask(priv, 0x00e720, 0x00000002, 0x00000000); + nv_mask(therm, 0x00e720, 0x00000002, 0x00000000); return 0; } @@ -69,22 +65,22 @@ gt215_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gt215_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_therm_create(parent, engine, oclass, &therm); + *pobject = nv_object(therm); if (ret) return ret; - priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; - priv->base.base.pwm_get = nv50_fan_pwm_get; - priv->base.base.pwm_set = nv50_fan_pwm_set; - priv->base.base.pwm_clock = nv50_fan_pwm_clock; - priv->base.base.temp_get = g84_temp_get; - priv->base.base.fan_sense = gt215_therm_fan_sense; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&priv->base.base); + therm->base.pwm_ctrl = nv50_fan_pwm_ctrl; + therm->base.pwm_get = nv50_fan_pwm_get; + therm->base.pwm_set = nv50_fan_pwm_set; + therm->base.pwm_clock = nv50_fan_pwm_clock; + therm->base.temp_get = g84_temp_get; + therm->base.fan_sense = gt215_therm_fan_sense; + therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; + return nvkm_therm_preinit(&therm->base); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c index 09fc4605e8531..f62198aa29690 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c @@ -30,8 +30,8 @@ static bool probe_monitoring_device(struct nvkm_i2c_port *i2c, struct i2c_board_info *info, void *data) { - struct nvkm_therm_priv *priv = data; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_therm_priv *therm = data; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; struct i2c_client *client; request_module("%s%s", I2C_MODULE_PREFIX, info->type); @@ -46,11 +46,11 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c, return false; } - nv_info(priv, + nv_info(therm, "Found an %s at address 0x%x (controlled by lm_sensors, " "temp offset %+i C)\n", info->type, info->addr, sensor->offset_constant); - priv->ic = client; + therm->ic = client; return true; } @@ -80,9 +80,9 @@ nv_board_infos[] = { }; void -nvkm_therm_ic_ctor(struct nvkm_therm *therm) +nvkm_therm_ic_ctor(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_bios *bios = nvkm_bios(therm); struct nvkm_i2c *i2c = nvkm_i2c(therm); struct nvbios_extdev_func extdev_entry; @@ -95,7 +95,7 @@ nvkm_therm_ic_ctor(struct nvkm_therm *therm) i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", board, probe_monitoring_device, therm); - if (priv->ic) + if (therm->ic) return; } @@ -107,7 +107,7 @@ nvkm_therm_ic_ctor(struct nvkm_therm *therm) i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", board, probe_monitoring_device, therm); - if (priv->ic) + if (therm->ic) return; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c index 20f65fd7679ae..e66672dce7ca4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c @@ -24,10 +24,6 @@ */ #include "priv.h" -struct nv40_therm_priv { - struct nvkm_therm_priv base; -}; - enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 }; static enum nv40_sensor_style @@ -76,11 +72,11 @@ nv40_sensor_setup(struct nvkm_therm *therm) } static int -nv40_temp_get(struct nvkm_therm *therm) +nv40_temp_get(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; - enum nv40_sensor_style style = nv40_sensor_style(therm); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; + enum nv40_sensor_style style = nv40_sensor_style(&therm->base); int core_temp; if (style == NEW_STYLE) { @@ -184,21 +180,21 @@ nv40_therm_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv40_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_therm_create(parent, engine, oclass, &therm); + *pobject = nv_object(therm); if (ret) return ret; - priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl; - priv->base.base.pwm_get = nv40_fan_pwm_get; - priv->base.base.pwm_set = nv40_fan_pwm_set; - priv->base.base.temp_get = nv40_temp_get; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - nv_subdev(priv)->intr = nv40_therm_intr; - return nvkm_therm_preinit(&priv->base.base); + therm->base.pwm_ctrl = nv40_fan_pwm_ctrl; + therm->base.pwm_get = nv40_fan_pwm_get; + therm->base.pwm_set = nv40_fan_pwm_set; + therm->base.temp_get = nv40_temp_get; + therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; + nv_subdev(therm)->intr = nv40_therm_intr; + return nvkm_therm_preinit(&therm->base); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c index 489dcf355d346..f57bac1156285 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c @@ -24,10 +24,6 @@ */ #include "priv.h" -struct nv50_therm_priv { - struct nvkm_therm_priv base; -}; - static int pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) { @@ -125,10 +121,10 @@ nv50_sensor_setup(struct nvkm_therm *therm) } static int -nv50_temp_get(struct nvkm_therm *therm) +nv50_temp_get(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; int core_temp; core_temp = nv_rd32(therm, 0x20014) & 0x3fff; @@ -155,23 +151,23 @@ nv50_therm_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_therm_priv *priv; + struct nvkm_therm_priv *therm; int ret; - ret = nvkm_therm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_therm_create(parent, engine, oclass, &therm); + *pobject = nv_object(therm); if (ret) return ret; - priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl; - priv->base.base.pwm_get = nv50_fan_pwm_get; - priv->base.base.pwm_set = nv50_fan_pwm_set; - priv->base.base.pwm_clock = nv50_fan_pwm_clock; - priv->base.base.temp_get = nv50_temp_get; - priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling; - nv_subdev(priv)->intr = nv40_therm_intr; + therm->base.pwm_ctrl = nv50_fan_pwm_ctrl; + therm->base.pwm_get = nv50_fan_pwm_get; + therm->base.pwm_set = nv50_fan_pwm_set; + therm->base.pwm_clock = nv50_fan_pwm_clock; + therm->base.temp_get = nv50_temp_get; + therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; + nv_subdev(therm)->intr = nv40_therm_intr; - return nvkm_therm_preinit(&priv->base.base); + return nvkm_therm_preinit(&therm->base); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index aa13744f3854b..a6f46ed0e2ae9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -24,31 +24,31 @@ #include "priv.h" static void -nvkm_therm_temp_set_defaults(struct nvkm_therm *therm) +nvkm_therm_temp_set_defaults(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - priv->bios_sensor.offset_constant = 0; + therm->bios_sensor.offset_constant = 0; - priv->bios_sensor.thrs_fan_boost.temp = 90; - priv->bios_sensor.thrs_fan_boost.hysteresis = 3; + therm->bios_sensor.thrs_fan_boost.temp = 90; + therm->bios_sensor.thrs_fan_boost.hysteresis = 3; - priv->bios_sensor.thrs_down_clock.temp = 95; - priv->bios_sensor.thrs_down_clock.hysteresis = 3; + therm->bios_sensor.thrs_down_clock.temp = 95; + therm->bios_sensor.thrs_down_clock.hysteresis = 3; - priv->bios_sensor.thrs_critical.temp = 105; - priv->bios_sensor.thrs_critical.hysteresis = 5; + therm->bios_sensor.thrs_critical.temp = 105; + therm->bios_sensor.thrs_critical.hysteresis = 5; - priv->bios_sensor.thrs_shutdown.temp = 135; - priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */ + therm->bios_sensor.thrs_shutdown.temp = 135; + therm->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */ } static void -nvkm_therm_temp_safety_checks(struct nvkm_therm *therm) +nvkm_therm_temp_safety_checks(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *s = &priv->bios_sensor; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvbios_therm_sensor *s = &therm->bios_sensor; /* enforce a minimum hysteresis on thresholds */ s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2); @@ -59,21 +59,21 @@ nvkm_therm_temp_safety_checks(struct nvkm_therm *therm) /* must be called with alarm_program_lock taken ! */ void -nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *therm, +nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_state st) { - struct nvkm_therm_priv *priv = (void *)therm; - priv->sensor.alarm_state[thrs] = st; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + therm->sensor.alarm_state[thrs] = st; } /* must be called with alarm_program_lock taken ! */ enum nvkm_therm_thrs_state -nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *therm, +nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs) { - struct nvkm_therm_priv *priv = (void *)therm; - return priv->sensor.alarm_state[thrs]; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + return therm->sensor.alarm_state[thrs]; } static void @@ -84,15 +84,15 @@ nv_poweroff_work(struct work_struct *work) } void -nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, +nvkm_therm_sensor_event(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_direction dir) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); bool active; const char *thresolds[] = { "fanboost", "downclock", "critical", "shutdown" }; - int temperature = therm->temp_get(therm); + int temperature = therm->base.temp_get(&therm->base); if (thrs < 0 || thrs > 3) return; @@ -108,17 +108,17 @@ nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, switch (thrs) { case NVKM_THERM_THRS_FANBOOST: if (active) { - nvkm_therm_fan_set(therm, true, 100); - nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO); + nvkm_therm_fan_set(&therm->base, true, 100); + nvkm_therm_fan_mode(&therm->base, NVKM_THERM_CTRL_AUTO); } break; case NVKM_THERM_THRS_DOWNCLOCK: - if (priv->emergency.downclock) - priv->emergency.downclock(therm, active); + if (therm->emergency.downclock) + therm->emergency.downclock(&therm->base, active); break; case NVKM_THERM_THRS_CRITICAL: - if (priv->emergency.pause) - priv->emergency.pause(therm, active); + if (therm->emergency.pause) + therm->emergency.pause(&therm->base, active); break; case NVKM_THERM_THRS_SHUTDOWN: if (active) { @@ -166,39 +166,39 @@ nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm, static void alarm_timer_callback(struct nvkm_alarm *alarm) { - struct nvkm_therm_priv *priv = + struct nvkm_therm_priv *therm = container_of(alarm, struct nvkm_therm_priv, sensor.therm_poll_alarm); - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; - struct nvkm_timer *ptimer = nvkm_timer(priv); - struct nvkm_therm *therm = &priv->base; + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; + struct nvkm_timer *ptimer = nvkm_timer(therm); unsigned long flags; - spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags); + spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); - nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, + nvkm_therm_threshold_hyst_polling(&therm->base, &sensor->thrs_fan_boost, NVKM_THERM_THRS_FANBOOST); - nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock, + nvkm_therm_threshold_hyst_polling(&therm->base, + &sensor->thrs_down_clock, NVKM_THERM_THRS_DOWNCLOCK); - nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_critical, + nvkm_therm_threshold_hyst_polling(&therm->base, &sensor->thrs_critical, NVKM_THERM_THRS_CRITICAL); - nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown, + nvkm_therm_threshold_hyst_polling(&therm->base, &sensor->thrs_shutdown, NVKM_THERM_THRS_SHUTDOWN); - spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags); + spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); /* schedule the next poll in one second */ - if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head)) + if (therm->base.temp_get(&therm->base) >= 0 && list_empty(&alarm->head)) ptimer->alarm(ptimer, 1000000000ULL, alarm); } void -nvkm_therm_program_alarms_polling(struct nvkm_therm *therm) +nvkm_therm_program_alarms_polling(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - struct nvbios_therm_sensor *sensor = &priv->bios_sensor; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvbios_therm_sensor *sensor = &therm->bios_sensor; nv_debug(therm, "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", @@ -208,25 +208,25 @@ nvkm_therm_program_alarms_polling(struct nvkm_therm *therm) sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); - alarm_timer_callback(&priv->sensor.therm_poll_alarm); + alarm_timer_callback(&therm->sensor.therm_poll_alarm); } int -nvkm_therm_sensor_init(struct nvkm_therm *therm) +nvkm_therm_sensor_init(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; - priv->sensor.program_alarms(therm); + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + therm->sensor.program_alarms(&therm->base); return 0; } int -nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend) +nvkm_therm_sensor_fini(struct nvkm_therm *obj, bool suspend) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_timer *ptimer = nvkm_timer(therm); if (suspend) - ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm); + ptimer->alarm_cancel(ptimer, &therm->sensor.therm_poll_alarm); return 0; } @@ -242,18 +242,18 @@ nvkm_therm_sensor_preinit(struct nvkm_therm *therm) } int -nvkm_therm_sensor_ctor(struct nvkm_therm *therm) +nvkm_therm_sensor_ctor(struct nvkm_therm *obj) { - struct nvkm_therm_priv *priv = (void *)therm; + struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_bios *bios = nvkm_bios(therm); - nvkm_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback); + nvkm_alarm_init(&therm->sensor.therm_poll_alarm, alarm_timer_callback); - nvkm_therm_temp_set_defaults(therm); + nvkm_therm_temp_set_defaults(&therm->base); if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, - &priv->bios_sensor)) + &therm->bios_sensor)) nv_error(therm, "nvbios_therm_sensor_parse failed\n"); - nvkm_therm_temp_safety_checks(therm); + nvkm_therm_temp_safety_checks(&therm->base); return 0; } -- GitLab From cb8bb9cedb6015eafd56ef9e9c5b2c216e8e7960 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5339/7006] drm/nouveau/tmr: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/dac.c | 8 +- drivers/gpu/drm/nouveau/dispnv04/hw.c | 6 +- .../drm/nouveau/include/nvkm/subdev/timer.h | 8 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/therm/base.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 18 +-- .../drm/nouveau/nvkm/subdev/therm/fantog.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/timer/base.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c | 16 +- .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 147 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.h | 2 +- 13 files changed, 121 insertions(+), 122 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index af7249ca0f4b1..2408728942b54 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -66,7 +66,7 @@ int nv04_dac_output_offset(struct drm_encoder *encoder) static int sample_load_twice(struct drm_device *dev, bool sense[2]) { struct nvif_device *device = &nouveau_drm(dev)->device; - struct nvkm_timer *ptimer = nvxx_timer(device); + struct nvkm_timer *tmr = nvxx_timer(device); int i; for (i = 0; i < 2; i++) { @@ -80,15 +80,15 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2]) * use a 10ms timeout (guards against crtc being inactive, in * which case blank state would never change) */ - if (!nvkm_timer_wait_eq(ptimer, 10000000, + if (!nvkm_timer_wait_eq(tmr, 10000000, NV_PRMCIO_INP0__COLOR, 0x00000001, 0x00000000)) return -EBUSY; - if (!nvkm_timer_wait_eq(ptimer, 10000000, + if (!nvkm_timer_wait_eq(tmr, 10000000, NV_PRMCIO_INP0__COLOR, 0x00000001, 0x00000001)) return -EBUSY; - if (!nvkm_timer_wait_eq(ptimer, 10000000, + if (!nvkm_timer_wait_eq(tmr, 10000000, NV_PRMCIO_INP0__COLOR, 0x00000001, 0x00000000)) return -EBUSY; diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c index 42e07afc4c2b2..e0d196e67000e 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.c +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c @@ -661,7 +661,7 @@ nv_load_state_ext(struct drm_device *dev, int head, { struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; - struct nvkm_timer *ptimer = nvxx_timer(device); + struct nvkm_timer *tmr = nvxx_timer(device); struct nv04_crtc_reg *regp = &state->crtc_reg[head]; uint32_t reg900; int i; @@ -741,8 +741,8 @@ nv_load_state_ext(struct drm_device *dev, int head, if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) { /* Not waiting for vertical retrace before modifying CRE_53/CRE_54 causes lockups. */ - nvkm_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); - nvkm_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); + nvkm_timer_wait_eq(tmr, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); + nvkm_timer_wait_eq(tmr, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); } wr_cio_state(dev, head, regp, NV_CIO_CRE_42); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index 4ad55082ef7ad..2c27ce6919390 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -31,7 +31,7 @@ void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *); nvkm_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d)) struct nvkm_timer { - struct nvkm_subdev base; + struct nvkm_subdev subdev; u64 (*read)(struct nvkm_timer *); void (*alarm)(struct nvkm_timer *, u64 time, struct nvkm_alarm *); void (*alarm_cancel)(struct nvkm_timer *, struct nvkm_alarm *); @@ -47,11 +47,11 @@ nvkm_timer(void *obj) nvkm_subdev_create_((p), (e), (o), 0, "PTIMER", "timer", \ sizeof(**d), (void **)d) #define nvkm_timer_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) + nvkm_subdev_destroy(&(p)->subdev) #define nvkm_timer_init(p) \ - nvkm_subdev_init(&(p)->base) + nvkm_subdev_init(&(p)->subdev) #define nvkm_timer_fini(p,s) \ - nvkm_subdev_fini(&(p)->base, (s)) + nvkm_subdev_fini(&(p)->subdev, (s)) int nvkm_timer_create_(struct nvkm_object *, struct nvkm_engine *, struct nvkm_oclass *, int size, void **); diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index d8b0891a141c6..1bdde99155a0b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -164,7 +164,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) struct nouveau_cli *cli = nouveau_cli(file_priv); struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; - struct nvkm_timer *ptimer = nvxx_timer(device); + struct nvkm_timer *tmr = nvxx_timer(device); struct nvkm_gr *gr = nvxx_gr(device); struct drm_nouveau_getparam *getparam = data; @@ -206,7 +206,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = 0; /* deprecated */ break; case NOUVEAU_GETPARAM_PTIMER_TIME: - getparam->value = ptimer->read(ptimer); + getparam->value = tmr->read(tmr); break; case NOUVEAU_GETPARAM_HAS_BO_USAGE: getparam->value = 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 754284feae915..f18b75b883ac8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -237,7 +237,7 @@ nvkm_pgr_vstatus_print(struct nv50_gr_priv *priv, int r, static int g84_gr_tlb_flush(struct nvkm_engine *engine) { - struct nvkm_timer *ptimer = nvkm_timer(engine); + struct nvkm_timer *tmr = nvkm_timer(engine); struct nv50_gr_priv *priv = (void *)engine; bool idle, timeout = false; unsigned long flags; @@ -247,7 +247,7 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) spin_lock_irqsave(&priv->lock, flags); nv_mask(priv, 0x400500, 0x00000001, 0x00000000); - start = ptimer->read(ptimer); + start = tmr->read(tmr); do { idle = true; @@ -266,7 +266,7 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) idle = false; } } while (!idle && - !(timeout = ptimer->read(ptimer) - start > 2000000000)); + !(timeout = tmr->read(tmr) - start > 2000000000)); if (timeout) { nv_error(priv, "PGRAPH TLB flush idle timeout fail\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index abb3fdc18910d..87c20d197102b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -83,7 +83,7 @@ static void nvkm_therm_update(struct nvkm_therm *obj, int mode) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); unsigned long flags; bool immd = true; bool poll = true; @@ -96,7 +96,7 @@ nvkm_therm_update(struct nvkm_therm *obj, int mode) switch (mode) { case NVKM_THERM_CTRL_MANUAL: - ptimer->alarm_cancel(ptimer, &therm->alarm); + tmr->alarm_cancel(tmr, &therm->alarm); duty = nvkm_therm_fan_get(&therm->base); if (duty < 0) duty = 100; @@ -120,12 +120,12 @@ nvkm_therm_update(struct nvkm_therm *obj, int mode) break; case NVKM_THERM_CTRL_NONE: default: - ptimer->alarm_cancel(ptimer, &therm->alarm); + tmr->alarm_cancel(tmr, &therm->alarm); poll = false; } if (list_empty(&therm->alarm.head) && poll) - ptimer->alarm(ptimer, 1000000000ULL, &therm->alarm); + tmr->alarm(tmr, 1000000000ULL, &therm->alarm); spin_unlock_irqrestore(&therm->lock, flags); if (duty >= 0) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index 37b9f47f663c2..83ebf366a221a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -32,7 +32,7 @@ static int nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) { struct nvkm_therm_priv *therm = (void *)fan->parent; - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); unsigned long flags; int ret = 0; int duty; @@ -94,7 +94,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) else delay = bump_period; - ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm); + tmr->alarm(tmr, delay * 1000 * 1000, &fan->alarm); } return ret; @@ -125,7 +125,7 @@ int nvkm_therm_fan_sense(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); struct nvkm_gpio *gpio = nvkm_gpio(therm); u32 cycles, cur, prev; u64 start, end, tach; @@ -137,7 +137,7 @@ nvkm_therm_fan_sense(struct nvkm_therm *obj) * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ - start = ptimer->read(ptimer); + start = tmr->read(tmr); prev = gpio->get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); cycles = 0; do { @@ -146,12 +146,12 @@ nvkm_therm_fan_sense(struct nvkm_therm *obj) cur = gpio->get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); if (prev != cur) { if (!start) - start = ptimer->read(ptimer); + start = tmr->read(tmr); cycles++; prev = cur; } - } while (cycles < 5 && ptimer->read(ptimer) - start < 250000000); - end = ptimer->read(ptimer); + } while (cycles < 5 && tmr->read(tmr) - start < 250000000); + end = tmr->read(tmr); if (cycles == 5) { tach = (u64)60000000000ULL; @@ -217,10 +217,10 @@ int nvkm_therm_fan_fini(struct nvkm_therm *obj, bool suspend) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); if (suspend) - ptimer->alarm_cancel(ptimer, &therm->fan->alarm); + tmr->alarm_cancel(tmr, &therm->fan->alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 138ee99ec0ea1..88cc190f5a3e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -39,7 +39,7 @@ static void nvkm_fantog_update(struct nvkm_fantog *fan, int percent) { struct nvkm_therm_priv *therm = (void *)fan->base.parent; - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); struct nvkm_gpio *gpio = nvkm_gpio(therm); unsigned long flags; int duty; @@ -56,7 +56,7 @@ nvkm_fantog_update(struct nvkm_fantog *fan, int percent) u64 next_change = (percent * fan->period_us) / 100; if (!duty) next_change = fan->period_us - next_change; - ptimer->alarm(ptimer, next_change * 1000, &fan->alarm); + tmr->alarm(tmr, next_change * 1000, &fan->alarm); } spin_unlock_irqrestore(&fan->lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index a6f46ed0e2ae9..41628de3bf6ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -169,7 +169,7 @@ alarm_timer_callback(struct nvkm_alarm *alarm) struct nvkm_therm_priv *therm = container_of(alarm, struct nvkm_therm_priv, sensor.therm_poll_alarm); struct nvbios_therm_sensor *sensor = &therm->bios_sensor; - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); unsigned long flags; spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); @@ -191,7 +191,7 @@ alarm_timer_callback(struct nvkm_alarm *alarm) /* schedule the next poll in one second */ if (therm->base.temp_get(&therm->base) >= 0 && list_empty(&alarm->head)) - ptimer->alarm(ptimer, 1000000000ULL, alarm); + tmr->alarm(tmr, 1000000000ULL, alarm); } void @@ -223,10 +223,10 @@ int nvkm_therm_sensor_fini(struct nvkm_therm *obj, bool suspend) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *ptimer = nvkm_timer(therm); + struct nvkm_timer *tmr = nvkm_timer(therm); if (suspend) - ptimer->alarm_cancel(ptimer, &therm->sensor.therm_poll_alarm); + tmr->alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index d894061ced528..216f44f9ca7a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -81,13 +81,13 @@ nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data) void nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - ptimer->alarm(ptimer, nsec, alarm); + struct nvkm_timer *tmr = nvkm_timer(obj); + tmr->alarm(tmr, nsec, alarm); } void nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm) { - struct nvkm_timer *ptimer = nvkm_timer(obj); - ptimer->alarm_cancel(ptimer, alarm); + struct nvkm_timer *tmr = nvkm_timer(obj); + tmr->alarm_cancel(tmr, alarm); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c index 80e38063dd9ba..16965325dbfdb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c @@ -26,21 +26,21 @@ static int gk20a_timer_init(struct nvkm_object *object) { - struct nv04_timer_priv *priv = (void *)object; - u32 hi = upper_32_bits(priv->suspend_time); - u32 lo = lower_32_bits(priv->suspend_time); + struct nv04_timer *tmr = (void *)object; + u32 hi = upper_32_bits(tmr->suspend_time); + u32 lo = lower_32_bits(tmr->suspend_time); int ret; - ret = nvkm_timer_init(&priv->base); + ret = nvkm_timer_init(&tmr->base); if (ret) return ret; - nv_debug(priv, "time low : 0x%08x\n", lo); - nv_debug(priv, "time high : 0x%08x\n", hi); + nv_debug(tmr, "time low : 0x%08x\n", lo); + nv_debug(tmr, "time high : 0x%08x\n", hi); /* restore the time before suspend */ - nv_wr32(priv, NV04_PTIMER_TIME_1, hi); - nv_wr32(priv, NV04_PTIMER_TIME_0, lo); + nv_wr32(tmr, NV04_PTIMER_TIME_1, hi); + nv_wr32(tmr, NV04_PTIMER_TIME_0, lo); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index cf386f9c84c92..c9b3eb8c8e071 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -24,43 +24,42 @@ #include "nv04.h" static u64 -nv04_timer_read(struct nvkm_timer *ptimer) +nv04_timer_read(struct nvkm_timer *tmr) { - struct nv04_timer_priv *priv = (void *)ptimer; u32 hi, lo; do { - hi = nv_rd32(priv, NV04_PTIMER_TIME_1); - lo = nv_rd32(priv, NV04_PTIMER_TIME_0); - } while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1)); + hi = nv_rd32(tmr, NV04_PTIMER_TIME_1); + lo = nv_rd32(tmr, NV04_PTIMER_TIME_0); + } while (hi != nv_rd32(tmr, NV04_PTIMER_TIME_1)); return ((u64)hi << 32 | lo); } static void -nv04_timer_alarm_trigger(struct nvkm_timer *ptimer) +nv04_timer_alarm_trigger(struct nvkm_timer *obj) { - struct nv04_timer_priv *priv = (void *)ptimer; + struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); struct nvkm_alarm *alarm, *atemp; unsigned long flags; LIST_HEAD(exec); /* move any due alarms off the pending list */ - spin_lock_irqsave(&priv->lock, flags); - list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) { - if (alarm->timestamp <= ptimer->read(ptimer)) + spin_lock_irqsave(&tmr->lock, flags); + list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) { + if (alarm->timestamp <= tmr->base.read(&tmr->base)) list_move_tail(&alarm->head, &exec); } /* reschedule interrupt for next alarm time */ - if (!list_empty(&priv->alarms)) { - alarm = list_first_entry(&priv->alarms, typeof(*alarm), head); - nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001); + if (!list_empty(&tmr->alarms)) { + alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); + nv_wr32(tmr, NV04_PTIMER_ALARM_0, alarm->timestamp); + nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000001); } else { - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); + nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000000); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&tmr->lock, flags); /* execute any pending alarm handlers */ list_for_each_entry_safe(alarm, atemp, &exec, head) { @@ -70,79 +69,79 @@ nv04_timer_alarm_trigger(struct nvkm_timer *ptimer) } static void -nv04_timer_alarm(struct nvkm_timer *ptimer, u64 time, struct nvkm_alarm *alarm) +nv04_timer_alarm(struct nvkm_timer *obj, u64 time, struct nvkm_alarm *alarm) { - struct nv04_timer_priv *priv = (void *)ptimer; + struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); struct nvkm_alarm *list; unsigned long flags; - alarm->timestamp = ptimer->read(ptimer) + time; + alarm->timestamp = tmr->base.read(&tmr->base) + time; /* append new alarm to list, in soonest-alarm-first order */ - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&tmr->lock, flags); if (!time) { if (!list_empty(&alarm->head)) list_del(&alarm->head); } else { - list_for_each_entry(list, &priv->alarms, head) { + list_for_each_entry(list, &tmr->alarms, head) { if (list->timestamp > alarm->timestamp) break; } list_add_tail(&alarm->head, &list->head); } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&tmr->lock, flags); /* process pending alarms */ - nv04_timer_alarm_trigger(ptimer); + nv04_timer_alarm_trigger(&tmr->base); } static void -nv04_timer_alarm_cancel(struct nvkm_timer *ptimer, struct nvkm_alarm *alarm) +nv04_timer_alarm_cancel(struct nvkm_timer *obj, struct nvkm_alarm *alarm) { - struct nv04_timer_priv *priv = (void *)ptimer; + struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irqsave(&tmr->lock, flags); list_del_init(&alarm->head); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&tmr->lock, flags); } static void nv04_timer_intr(struct nvkm_subdev *subdev) { - struct nv04_timer_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0); + struct nv04_timer *tmr = (void *)subdev; + u32 stat = nv_rd32(tmr, NV04_PTIMER_INTR_0); if (stat & 0x00000001) { - nv04_timer_alarm_trigger(&priv->base); - nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001); + nv04_timer_alarm_trigger(&tmr->base); + nv_wr32(tmr, NV04_PTIMER_INTR_0, 0x00000001); stat &= ~0x00000001; } if (stat) { - nv_error(priv, "unknown stat 0x%08x\n", stat); - nv_wr32(priv, NV04_PTIMER_INTR_0, stat); + nv_error(tmr, "unknown stat 0x%08x\n", stat); + nv_wr32(tmr, NV04_PTIMER_INTR_0, stat); } } int nv04_timer_fini(struct nvkm_object *object, bool suspend) { - struct nv04_timer_priv *priv = (void *)object; + struct nv04_timer *tmr = (void *)object; if (suspend) - priv->suspend_time = nv04_timer_read(&priv->base); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - return nvkm_timer_fini(&priv->base, suspend); + tmr->suspend_time = nv04_timer_read(&tmr->base); + nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000000); + return nvkm_timer_fini(&tmr->base, suspend); } static int nv04_timer_init(struct nvkm_object *object) { struct nvkm_device *device = nv_device(object); - struct nv04_timer_priv *priv = (void *)object; + struct nv04_timer *tmr = (void *)object; u32 m = 1, f, n, d, lo, hi; int ret; - ret = nvkm_timer_init(&priv->base); + ret = nvkm_timer_init(&tmr->base); if (ret) return ret; @@ -167,15 +166,15 @@ nv04_timer_init(struct nvkm_object *object) m++; } - nv_wr32(priv, 0x009220, m - 1); + nv_wr32(tmr, 0x009220, m - 1); } if (!n) { - nv_warn(priv, "unknown input clock freq\n"); - if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) || - !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) { - nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1); - nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1); + nv_warn(tmr, "unknown input clock freq\n"); + if (!nv_rd32(tmr, NV04_PTIMER_NUMERATOR) || + !nv_rd32(tmr, NV04_PTIMER_DENOMINATOR)) { + nv_wr32(tmr, NV04_PTIMER_NUMERATOR, 1); + nv_wr32(tmr, NV04_PTIMER_DENOMINATOR, 1); } return 0; } @@ -197,31 +196,31 @@ nv04_timer_init(struct nvkm_object *object) } /* restore the time before suspend */ - lo = priv->suspend_time; - hi = (priv->suspend_time >> 32); - - nv_debug(priv, "input frequency : %dHz\n", f); - nv_debug(priv, "input multiplier: %d\n", m); - nv_debug(priv, "numerator : 0x%08x\n", n); - nv_debug(priv, "denominator : 0x%08x\n", d); - nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n); - nv_debug(priv, "time low : 0x%08x\n", lo); - nv_debug(priv, "time high : 0x%08x\n", hi); - - nv_wr32(priv, NV04_PTIMER_NUMERATOR, n); - nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d); - nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff); - nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000); - nv_wr32(priv, NV04_PTIMER_TIME_1, hi); - nv_wr32(priv, NV04_PTIMER_TIME_0, lo); + lo = tmr->suspend_time; + hi = (tmr->suspend_time >> 32); + + nv_debug(tmr, "input frequency : %dHz\n", f); + nv_debug(tmr, "input multiplier: %d\n", m); + nv_debug(tmr, "numerator : 0x%08x\n", n); + nv_debug(tmr, "denominator : 0x%08x\n", d); + nv_debug(tmr, "timer frequency : %dHz\n", (f * m) * d / n); + nv_debug(tmr, "time low : 0x%08x\n", lo); + nv_debug(tmr, "time high : 0x%08x\n", hi); + + nv_wr32(tmr, NV04_PTIMER_NUMERATOR, n); + nv_wr32(tmr, NV04_PTIMER_DENOMINATOR, d); + nv_wr32(tmr, NV04_PTIMER_INTR_0, 0xffffffff); + nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000000); + nv_wr32(tmr, NV04_PTIMER_TIME_1, hi); + nv_wr32(tmr, NV04_PTIMER_TIME_0, lo); return 0; } void nv04_timer_dtor(struct nvkm_object *object) { - struct nv04_timer_priv *priv = (void *)object; - return nvkm_timer_destroy(&priv->base); + struct nv04_timer *tmr = (void *)object; + return nvkm_timer_destroy(&tmr->base); } int @@ -229,22 +228,22 @@ nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_timer_priv *priv; + struct nv04_timer *tmr; int ret; - ret = nvkm_timer_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_timer_create(parent, engine, oclass, &tmr); + *pobject = nv_object(tmr); if (ret) return ret; - priv->base.base.intr = nv04_timer_intr; - priv->base.read = nv04_timer_read; - priv->base.alarm = nv04_timer_alarm; - priv->base.alarm_cancel = nv04_timer_alarm_cancel; - priv->suspend_time = 0; + tmr->base.subdev.intr = nv04_timer_intr; + tmr->base.read = nv04_timer_read; + tmr->base.alarm = nv04_timer_alarm; + tmr->base.alarm_cancel = nv04_timer_alarm_cancel; + tmr->suspend_time = 0; - INIT_LIST_HEAD(&priv->alarms); - spin_lock_init(&priv->lock); + INIT_LIST_HEAD(&tmr->alarms); + spin_lock_init(&tmr->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h index 89996a9826b19..1bc0d7c073ef1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h @@ -10,7 +10,7 @@ #define NV04_PTIMER_TIME_1 0x009410 #define NV04_PTIMER_ALARM_0 0x009420 -struct nv04_timer_priv { +struct nv04_timer { struct nvkm_timer base; struct list_head alarms; spinlock_t lock; -- GitLab From 6052dc5775ac0be49db3e25d2719c72a250189a2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5340/7006] drm/nouveau/volt: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/volt.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/volt/base.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 70 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/volt/nv40.c | 10 +-- 4 files changed, 40 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index e3d7243fbb1d8..1eeb80a380d22 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -8,7 +8,7 @@ struct nvkm_voltage { }; struct nvkm_volt { - struct nvkm_subdev base; + struct nvkm_subdev subdev; int (*vid_get)(struct nvkm_volt *); int (*get)(struct nvkm_volt *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 39f15803f2d46..53a173694fb4c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -140,7 +140,7 @@ _nvkm_volt_init(struct nvkm_object *object) struct nvkm_volt *volt = (void *)object; int ret; - ret = nvkm_subdev_init(&volt->base); + ret = nvkm_subdev_init(&volt->subdev); if (ret) return ret; @@ -159,7 +159,7 @@ void _nvkm_volt_dtor(struct nvkm_object *object) { struct nvkm_volt *volt = (void *)object; - nvkm_subdev_destroy(&volt->base); + nvkm_subdev_destroy(&volt->subdev); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 871fd51011dbe..2be1aa39602fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -33,7 +33,7 @@ struct cvb_coef { int c5; }; -struct gk20a_volt_priv { +struct gk20a_volt { struct nvkm_volt base; struct regulator *vdd; }; @@ -101,35 +101,35 @@ gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) } static int -gk20a_volt_vid_get(struct nvkm_volt *volt) +gk20a_volt_vid_get(struct nvkm_volt *obj) { - struct gk20a_volt_priv *priv = (void *)volt; + struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); int i, uv; - uv = regulator_get_voltage(priv->vdd); + uv = regulator_get_voltage(volt->vdd); - for (i = 0; i < volt->vid_nr; i++) - if (volt->vid[i].uv >= uv) + for (i = 0; i < volt->base.vid_nr; i++) + if (volt->base.vid[i].uv >= uv) return i; return -EINVAL; } static int -gk20a_volt_vid_set(struct nvkm_volt *volt, u8 vid) +gk20a_volt_vid_set(struct nvkm_volt *obj, u8 vid) { - struct gk20a_volt_priv *priv = (void *)volt; + struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); - nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv); - return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000); + nv_debug(volt, "set voltage as %duv\n", volt->base.vid[vid].uv); + return regulator_set_voltage(volt->vdd, volt->base.vid[vid].uv, 1200000); } static int -gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) +gk20a_volt_set_id(struct nvkm_volt *obj, u8 id, int condition) { - struct gk20a_volt_priv *priv = (void *)volt; - int prev_uv = regulator_get_voltage(priv->vdd); - int target_uv = volt->vid[id].uv; + struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); + int prev_uv = regulator_get_voltage(volt->vdd); + int target_uv = volt->base.vid[id].uv; int ret; nv_debug(volt, "prev=%d, target=%d, condition=%d\n", @@ -137,7 +137,7 @@ gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) if (!condition || (condition < 0 && target_uv < prev_uv) || (condition > 0 && target_uv > prev_uv)) { - ret = gk20a_volt_vid_set(volt, volt->vid[id].vid); + ret = gk20a_volt_vid_set(&volt->base, volt->base.vid[id].vid); } else { ret = 0; } @@ -150,36 +150,34 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk20a_volt_priv *priv; - struct nvkm_volt *volt; + struct gk20a_volt *volt; struct nouveau_platform_device *plat; int i, ret, uv; - ret = nvkm_volt_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_volt_create(parent, engine, oclass, &volt); + *pobject = nv_object(volt); if (ret) return ret; - volt = &priv->base; - plat = nv_device_to_platform(nv_device(parent)); uv = regulator_get_voltage(plat->gpu->vdd); - nv_info(priv, "The default voltage is %duV\n", uv); - - priv->vdd = plat->gpu->vdd; - priv->base.vid_get = gk20a_volt_vid_get; - priv->base.vid_set = gk20a_volt_vid_set; - priv->base.set_id = gk20a_volt_set_id; - - volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef); - nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr); - for (i = 0; i < volt->vid_nr; i++) { - volt->vid[i].vid = i; - volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], - plat->gpu_speedo); - nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid, - volt->vid[i].uv); + nv_info(volt, "The default voltage is %duV\n", uv); + + volt->vdd = plat->gpu->vdd; + volt->base.vid_get = gk20a_volt_vid_get; + volt->base.vid_set = gk20a_volt_vid_set; + volt->base.set_id = gk20a_volt_set_id; + + volt->base.vid_nr = ARRAY_SIZE(gk20a_cvb_coef); + nv_debug(volt, "%s - vid_nr = %d\n", __func__, volt->base.vid_nr); + for (i = 0; i < volt->base.vid_nr; i++) { + volt->base.vid[i].vid = i; + volt->base.vid[i].uv = + gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], + plat->gpu_speedo); + nv_debug(volt, "%2d: vid=%d, uv=%d\n", i, + volt->base.vid[i].vid, volt->base.vid[i].uv); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c index 0ac5a3f8c9a8f..16e8965c72f95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c @@ -23,20 +23,16 @@ */ #include -struct nv40_volt_priv { - struct nvkm_volt base; -}; - static int nv40_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv40_volt_priv *priv; + struct nvkm_volt *volt; int ret; - ret = nvkm_volt_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_volt_create(parent, engine, oclass, &volt); + *pobject = nv_object(volt); if (ret) return ret; -- GitLab From b26ada6fedeb7cf6dacb1275a8ea08f4e39b53d2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5341/7006] drm/nouveau/falcon: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index bd38cf9130fc6..d811db7dbfd8d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -29,7 +29,7 @@ struct nvkm_falcon_data { #include struct nvkm_falcon { - struct nvkm_engine base; + struct nvkm_engine engine; u32 addr; u8 version; @@ -57,7 +57,7 @@ struct nvkm_falcon { nvkm_falcon_create_((p), (e), (c), (b), (d), (i), (f), \ sizeof(**r),(void **)r) #define nvkm_falcon_destroy(p) \ - nvkm_engine_destroy(&(p)->base) + nvkm_engine_destroy(&(p)->engine) #define nvkm_falcon_init(p) ({ \ struct nvkm_falcon *falcon = (p); \ _nvkm_falcon_init(nv_object(falcon)); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 2d2e549c2e347..7791428fcafbd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -85,7 +85,7 @@ gf100_ce_init(struct nvkm_object *object) if (ret) return ret; - nv_wo32(priv, 0x084, nv_engidx(&priv->base.base) - NVDEV_ENGINE_CE0); + nv_wo32(priv, 0x084, nv_engidx(&priv->base.engine) - NVDEV_ENGINE_CE0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index f6e9ae95c8224..90175ab62e542 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -77,7 +77,7 @@ _nvkm_falcon_init(struct nvkm_object *object) u32 caps; /* enable engine, and determine its capabilities */ - ret = nvkm_engine_init(&falcon->base); + ret = nvkm_engine_init(&falcon->engine); if (ret) return ret; @@ -253,7 +253,7 @@ _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) nv_mo32(falcon, 0x048, 0x00000003, 0x00000000); nv_wo32(falcon, 0x014, 0xffffffff); - return nvkm_engine_fini(&falcon->base, suspend); + return nvkm_engine_fini(&falcon->engine, suspend); } int -- GitLab From f0961867b817e3aca45dca7e1885a7ec99a260ed Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5342/7006] drm/nouveau/xtensa: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h index 7a216cca28655..bfe49b6f42a4f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h @@ -4,7 +4,7 @@ struct nvkm_gpuobj; struct nvkm_xtensa { - struct nvkm_engine base; + struct nvkm_engine engine; u32 addr; struct nvkm_gpuobj *gpu_fw; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index 3995d2cf06681..7cc33836aadde 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -100,7 +100,7 @@ _nvkm_xtensa_init(struct nvkm_object *object) int i, ret; u32 tmp; - ret = nvkm_engine_init(&xtensa->base); + ret = nvkm_engine_init(&xtensa->engine); if (ret) return ret; @@ -167,5 +167,5 @@ _nvkm_xtensa_fini(struct nvkm_object *object, bool suspend) if (!suspend) nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw); - return nvkm_engine_fini(&xtensa->base, suspend); + return nvkm_engine_fini(&xtensa->engine, suspend); } -- GitLab From d8c304b504bc2709eaec742be1b30d5e53e47449 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5343/7006] drm/nouveau/bsp: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c index a0b1fd80fa936..6b69d6671173b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c @@ -62,20 +62,20 @@ g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_xtensa *priv; + struct nvkm_xtensa *bsp; int ret; ret = nvkm_xtensa_create(parent, engine, oclass, 0x103000, true, - "PBSP", "bsp", &priv); - *pobject = nv_object(priv); + "PBSP", "bsp", &bsp); + *pobject = nv_object(bsp); if (ret) return ret; - nv_subdev(priv)->unit = 0x04008000; - nv_engine(priv)->cclass = &g84_bsp_cclass; - nv_engine(priv)->sclass = g84_bsp_sclass; - priv->fifo_val = 0x1111; - priv->unkd28 = 0x90044; + nv_subdev(bsp)->unit = 0x04008000; + nv_engine(bsp)->cclass = &g84_bsp_cclass; + nv_engine(bsp)->sclass = g84_bsp_sclass; + bsp->fifo_val = 0x1111; + bsp->unkd28 = 0x90044; return 0; } -- GitLab From d9261a68374fbeda5a180fbba926aaba29321a75 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5344/7006] drm/nouveau/ce: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/falcon.h | 2 +- .../drm/nouveau/nvkm/engine/ce/fuc/com.fuc | 8 +-- .../nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h | 4 +- .../nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 54 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/ce/gk104.c | 56 +++++++++---------- .../gpu/drm/nouveau/nvkm/engine/ce/gm204.c | 56 +++++++++---------- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 26 ++++----- 8 files changed, 97 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index d811db7dbfd8d..2a27646ed770f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -51,7 +51,7 @@ struct nvkm_falcon { } data; }; -#define nv_falcon(priv) (&(priv)->base) +#define nv_falcon(priv) ((struct nvkm_falcon *)priv) #define nvkm_falcon_create(p,e,c,b,d,i,f,r) \ nvkm_falcon_create_((p), (e), (c), (b), (d), (i), (f), \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc index a558dfa4d76a2..6226bcd98ca9f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc @@ -24,9 +24,9 @@ */ #ifdef GT215 -.section #gt215_pce_data +.section #gt215_ce_data #else -.section #gf100_pce_data +.section #gf100_ce_data #endif ctx_object: .b32 0 @@ -128,9 +128,9 @@ dispatch_dma: .b16 0x800 0 #ifdef GT215 -.section #gt215_pce_code +.section #gt215_ce_code #else -.section #gf100_pce_code +.section #gf100_ce_code #endif main: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h index d9af6e4e45851..05bb65608dfe1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gf100_pce_data[] = { +uint32_t gf100_ce_data[] = { /* 0x0000: ctx_object */ 0x00000000, /* 0x0004: ctx_query_address_high */ @@ -171,7 +171,7 @@ uint32_t gf100_pce_data[] = { 0x00000800, }; -uint32_t gf100_pce_code[] = { +uint32_t gf100_ce_code[] = { /* 0x0000: main */ 0x04fe04bd, 0x3517f000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h index f42c0d0d6ceeb..972281d10f389 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h @@ -1,4 +1,4 @@ -uint32_t gt215_pce_data[] = { +uint32_t gt215_ce_data[] = { /* 0x0000: ctx_object */ 0x00000000, /* 0x0004: ctx_dma */ @@ -183,7 +183,7 @@ uint32_t gt215_pce_data[] = { 0x00000800, }; -uint32_t gt215_pce_code[] = { +uint32_t gt215_ce_code[] = { /* 0x0000: main */ 0x04fe04bd, 0x3517f000, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 7791428fcafbd..bbe07c4d08434 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -25,10 +25,6 @@ #include #include "fuc/gf100.fuc3.h" -struct gf100_ce_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * Copy object classes ******************************************************************************/ @@ -78,14 +74,14 @@ gf100_ce1_cclass = { static int gf100_ce_init(struct nvkm_object *object) { - struct gf100_ce_priv *priv = (void *)object; + struct nvkm_falcon *ce = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(ce); if (ret) return ret; - nv_wo32(priv, 0x084, nv_engidx(&priv->base.engine) - NVDEV_ENGINE_CE0); + nv_wo32(ce, 0x084, nv_engidx(&ce->engine) - NVDEV_ENGINE_CE0); return 0; } @@ -94,23 +90,23 @@ gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_ce_priv *priv; + struct nvkm_falcon *ce; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, true, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); + "PCE0", "ce0", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000040; - nv_subdev(priv)->intr = gt215_ce_intr; - nv_engine(priv)->cclass = &gf100_ce0_cclass; - nv_engine(priv)->sclass = gf100_ce0_sclass; - nv_falcon(priv)->code.data = gf100_pce_code; - nv_falcon(priv)->code.size = sizeof(gf100_pce_code); - nv_falcon(priv)->data.data = gf100_pce_data; - nv_falcon(priv)->data.size = sizeof(gf100_pce_data); + nv_subdev(ce)->unit = 0x00000040; + nv_subdev(ce)->intr = gt215_ce_intr; + nv_engine(ce)->cclass = &gf100_ce0_cclass; + nv_engine(ce)->sclass = gf100_ce0_sclass; + nv_falcon(ce)->code.data = gf100_ce_code; + nv_falcon(ce)->code.size = sizeof(gf100_ce_code); + nv_falcon(ce)->data.data = gf100_ce_data; + nv_falcon(ce)->data.size = sizeof(gf100_ce_data); return 0; } @@ -119,23 +115,23 @@ gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_ce_priv *priv; + struct nvkm_falcon *ce; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x105000, true, - "PCE1", "ce1", &priv); - *pobject = nv_object(priv); + "PCE1", "ce1", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000080; - nv_subdev(priv)->intr = gt215_ce_intr; - nv_engine(priv)->cclass = &gf100_ce1_cclass; - nv_engine(priv)->sclass = gf100_ce1_sclass; - nv_falcon(priv)->code.data = gf100_pce_code; - nv_falcon(priv)->code.size = sizeof(gf100_pce_code); - nv_falcon(priv)->data.data = gf100_pce_data; - nv_falcon(priv)->data.size = sizeof(gf100_pce_data); + nv_subdev(ce)->unit = 0x00000080; + nv_subdev(ce)->intr = gt215_ce_intr; + nv_engine(ce)->cclass = &gf100_ce1_cclass; + nv_engine(ce)->sclass = gf100_ce1_sclass; + nv_falcon(ce)->code.data = gf100_ce_code; + nv_falcon(ce)->code.size = sizeof(gf100_ce_code); + nv_falcon(ce)->data.data = gf100_ce_data; + nv_falcon(ce)->data.size = sizeof(gf100_ce_data); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index a998932fae45f..1abf22f87c710 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -25,10 +25,6 @@ #include -struct gk104_ce_priv { - struct nvkm_engine base; -}; - /******************************************************************************* * Copy object classes ******************************************************************************/ @@ -66,13 +62,13 @@ gk104_ce_cclass = { static void gk104_ce_intr(struct nvkm_subdev *subdev) { - const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - struct gk104_ce_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000)); + const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; + struct nvkm_engine *ce = (void *)subdev; + u32 stat = nv_rd32(ce, 0x104908 + (idx * 0x1000)); if (stat) { - nv_warn(priv, "unhandled intr 0x%08x\n", stat); - nv_wr32(priv, 0x104908 + (ce * 0x1000), stat); + nv_warn(ce, "unhandled intr 0x%08x\n", stat); + nv_wr32(ce, 0x104908 + (idx * 0x1000), stat); } } @@ -81,19 +77,19 @@ gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_ce_priv *priv; + struct nvkm_engine *ce; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); + "PCE0", "ce0", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000040; - nv_subdev(priv)->intr = gk104_ce_intr; - nv_engine(priv)->cclass = &gk104_ce_cclass; - nv_engine(priv)->sclass = gk104_ce_sclass; + nv_subdev(ce)->unit = 0x00000040; + nv_subdev(ce)->intr = gk104_ce_intr; + nv_engine(ce)->cclass = &gk104_ce_cclass; + nv_engine(ce)->sclass = gk104_ce_sclass; return 0; } @@ -102,19 +98,19 @@ gk104_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_ce_priv *priv; + struct nvkm_engine *ce; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE1", "ce1", &priv); - *pobject = nv_object(priv); + "PCE1", "ce1", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000080; - nv_subdev(priv)->intr = gk104_ce_intr; - nv_engine(priv)->cclass = &gk104_ce_cclass; - nv_engine(priv)->sclass = gk104_ce_sclass; + nv_subdev(ce)->unit = 0x00000080; + nv_subdev(ce)->intr = gk104_ce_intr; + nv_engine(ce)->cclass = &gk104_ce_cclass; + nv_engine(ce)->sclass = gk104_ce_sclass; return 0; } @@ -123,19 +119,19 @@ gk104_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_ce_priv *priv; + struct nvkm_engine *ce; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE2", "ce2", &priv); - *pobject = nv_object(priv); + "PCE2", "ce2", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00200000; - nv_subdev(priv)->intr = gk104_ce_intr; - nv_engine(priv)->cclass = &gk104_ce_cclass; - nv_engine(priv)->sclass = gk104_ce_sclass; + nv_subdev(ce)->unit = 0x00200000; + nv_subdev(ce)->intr = gk104_ce_intr; + nv_engine(ce)->cclass = &gk104_ce_cclass; + nv_engine(ce)->sclass = gk104_ce_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index 577eb2eead058..3fd896a92978d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -25,10 +25,6 @@ #include -struct gm204_ce_priv { - struct nvkm_engine base; -}; - /******************************************************************************* * Copy object classes ******************************************************************************/ @@ -66,13 +62,13 @@ gm204_ce_cclass = { static void gm204_ce_intr(struct nvkm_subdev *subdev) { - const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - struct gm204_ce_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000)); + const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; + struct nvkm_engine *ce = (void *)subdev; + u32 stat = nv_rd32(ce, 0x104908 + (idx * 0x1000)); if (stat) { - nv_warn(priv, "unhandled intr 0x%08x\n", stat); - nv_wr32(priv, 0x104908 + (ce * 0x1000), stat); + nv_warn(ce, "unhandled intr 0x%08x\n", stat); + nv_wr32(ce, 0x104908 + (idx * 0x1000), stat); } } @@ -81,19 +77,19 @@ gm204_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gm204_ce_priv *priv; + struct nvkm_engine *ce; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); + "PCE0", "ce0", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000040; - nv_subdev(priv)->intr = gm204_ce_intr; - nv_engine(priv)->cclass = &gm204_ce_cclass; - nv_engine(priv)->sclass = gm204_ce_sclass; + nv_subdev(ce)->unit = 0x00000040; + nv_subdev(ce)->intr = gm204_ce_intr; + nv_engine(ce)->cclass = &gm204_ce_cclass; + nv_engine(ce)->sclass = gm204_ce_sclass; return 0; } @@ -102,19 +98,19 @@ gm204_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gm204_ce_priv *priv; + struct nvkm_engine *ce; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE1", "ce1", &priv); - *pobject = nv_object(priv); + "PCE1", "ce1", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000080; - nv_subdev(priv)->intr = gm204_ce_intr; - nv_engine(priv)->cclass = &gm204_ce_cclass; - nv_engine(priv)->sclass = gm204_ce_sclass; + nv_subdev(ce)->unit = 0x00000080; + nv_subdev(ce)->intr = gm204_ce_intr; + nv_engine(ce)->cclass = &gm204_ce_cclass; + nv_engine(ce)->sclass = gm204_ce_sclass; return 0; } @@ -123,19 +119,19 @@ gm204_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gm204_ce_priv *priv; + struct nvkm_engine *ce; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE2", "ce2", &priv); - *pobject = nv_object(priv); + "PCE2", "ce2", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00200000; - nv_subdev(priv)->intr = gm204_ce_intr; - nv_engine(priv)->cclass = &gm204_ce_cclass; - nv_engine(priv)->sclass = gm204_ce_sclass; + nv_subdev(ce)->unit = 0x00200000; + nv_subdev(ce)->intr = gm204_ce_intr; + nv_engine(ce)->cclass = &gm204_ce_cclass; + nv_engine(ce)->sclass = gm204_ce_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 72604d332596b..9addf43e07d43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -29,10 +29,6 @@ #include #include -struct gt215_ce_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * Copy object classes ******************************************************************************/ @@ -117,23 +113,23 @@ gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { bool enable = (nv_device(parent)->chipset != 0xaf); - struct gt215_ce_priv *priv; + struct nvkm_falcon *ce; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, enable, - "PCE0", "ce0", &priv); - *pobject = nv_object(priv); + "PCE0", "ce0", &ce); + *pobject = nv_object(ce); if (ret) return ret; - nv_subdev(priv)->unit = 0x00802000; - nv_subdev(priv)->intr = gt215_ce_intr; - nv_engine(priv)->cclass = >215_ce_cclass; - nv_engine(priv)->sclass = gt215_ce_sclass; - nv_falcon(priv)->code.data = gt215_pce_code; - nv_falcon(priv)->code.size = sizeof(gt215_pce_code); - nv_falcon(priv)->data.data = gt215_pce_data; - nv_falcon(priv)->data.size = sizeof(gt215_pce_data); + nv_subdev(ce)->unit = 0x00802000; + nv_subdev(ce)->intr = gt215_ce_intr; + nv_engine(ce)->cclass = >215_ce_cclass; + nv_engine(ce)->sclass = gt215_ce_sclass; + nv_falcon(ce)->code.data = gt215_ce_code; + nv_falcon(ce)->code.size = sizeof(gt215_ce_code); + nv_falcon(ce)->data.data = gt215_ce_data; + nv_falcon(ce)->data.size = sizeof(gt215_ce_data); return 0; } -- GitLab From e2f1cf253e0cf5b64fa6fee439aeeda49c6f09d8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5345/7006] drm/nouveau/cipher: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 44 +++++++++---------- 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 13f30428a3051..c1f065d8efa4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -28,10 +28,6 @@ #include #include -struct g84_cipher_priv { - struct nvkm_engine base; -}; - /******************************************************************************* * Crypt object classes ******************************************************************************/ @@ -111,26 +107,26 @@ g84_cipher_intr(struct nvkm_subdev *subdev) struct nvkm_fifo *pfifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; - struct g84_cipher_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x102130); - u32 mthd = nv_rd32(priv, 0x102190); - u32 data = nv_rd32(priv, 0x102194); - u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff; + struct nvkm_engine *cipher = (void *)subdev; + u32 stat = nv_rd32(cipher, 0x102130); + u32 mthd = nv_rd32(cipher, 0x102190); + u32 data = nv_rd32(cipher, 0x102194); + u32 inst = nv_rd32(cipher, 0x102188) & 0x7fffffff; int chid; engctx = nvkm_engctx_get(engine, inst); chid = pfifo->chid(pfifo, engctx); if (stat) { - nv_error(priv, "%s", ""); + nv_error(cipher, "%s", ""); nvkm_bitfield_print(g84_cipher_intr_mask, stat); pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n", chid, (u64)inst << 12, nvkm_client_name(engctx), mthd, data); } - nv_wr32(priv, 0x102130, stat); - nv_wr32(priv, 0x10200c, 0x10); + nv_wr32(cipher, 0x102130, stat); + nv_wr32(cipher, 0x10200c, 0x10); nvkm_engctx_put(engctx); } @@ -140,35 +136,35 @@ g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g84_cipher_priv *priv; + struct nvkm_engine *cipher; int ret; ret = nvkm_engine_create(parent, engine, oclass, true, - "PCIPHER", "cipher", &priv); - *pobject = nv_object(priv); + "PCIPHER", "cipher", &cipher); + *pobject = nv_object(cipher); if (ret) return ret; - nv_subdev(priv)->unit = 0x00004000; - nv_subdev(priv)->intr = g84_cipher_intr; - nv_engine(priv)->cclass = &g84_cipher_cclass; - nv_engine(priv)->sclass = g84_cipher_sclass; + nv_subdev(cipher)->unit = 0x00004000; + nv_subdev(cipher)->intr = g84_cipher_intr; + nv_engine(cipher)->cclass = &g84_cipher_cclass; + nv_engine(cipher)->sclass = g84_cipher_sclass; return 0; } static int g84_cipher_init(struct nvkm_object *object) { - struct g84_cipher_priv *priv = (void *)object; + struct nvkm_engine *cipher = (void *)object; int ret; - ret = nvkm_engine_init(&priv->base); + ret = nvkm_engine_init(cipher); if (ret) return ret; - nv_wr32(priv, 0x102130, 0xffffffff); - nv_wr32(priv, 0x102140, 0xffffffbf); - nv_wr32(priv, 0x10200c, 0x00000010); + nv_wr32(cipher, 0x102130, 0xffffffff); + nv_wr32(cipher, 0x102140, 0xffffffbf); + nv_wr32(cipher, 0x10200c, 0x00000010); return 0; } -- GitLab From fd166a1832db138f22ad95eacd0879af30742f57 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5346/7006] drm/nouveau/disp: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 6 +- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 20 +- .../gpu/drm/nouveau/nvkm/engine/disp/dport.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 36 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 36 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 416 +++++++------- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 34 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 34 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 34 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm204.c | 36 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 36 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 38 +- .../drm/nouveau/nvkm/engine/disp/hdagf110.c | 18 +- .../drm/nouveau/nvkm/engine/disp/hdagt215.c | 16 +- .../drm/nouveau/nvkm/engine/disp/hdmig84.c | 44 +- .../drm/nouveau/nvkm/engine/disp/hdmigf110.c | 28 +- .../drm/nouveau/nvkm/engine/disp/hdmigk104.c | 30 +- .../drm/nouveau/nvkm/engine/disp/hdmigt215.c | 44 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 54 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 535 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 10 +- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 44 +- .../drm/nouveau/nvkm/engine/disp/sorgf110.c | 32 +- .../drm/nouveau/nvkm/engine/disp/sorgm204.c | 46 +- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 8 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 6 +- 28 files changed, 826 insertions(+), 833 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index a5e1ed81312f7..24bce1a93dbfa 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -4,7 +4,7 @@ #include struct nvkm_disp { - struct nvkm_engine base; + struct nvkm_engine engine; struct list_head outp; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 23d1b5c0dc162..2090e90d67702 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -127,7 +127,7 @@ _nvkm_disp_fini(struct nvkm_object *object, bool suspend) goto fail_outp; } - return nvkm_engine_fini(&disp->base, suspend); + return nvkm_engine_fini(&disp->engine, suspend); fail_outp: list_for_each_entry_continue_reverse(outp, &disp->outp, head) { @@ -144,7 +144,7 @@ _nvkm_disp_init(struct nvkm_object *object) struct nvkm_output *outp; int ret; - ret = nvkm_engine_init(&disp->base); + ret = nvkm_engine_init(&disp->engine); if (ret) return ret; @@ -179,7 +179,7 @@ _nvkm_disp_dtor(struct nvkm_object *object) } } - nvkm_engine_destroy(&disp->base); + nvkm_engine_destroy(&disp->engine); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 0f7d1ec4d37ed..f64dec917f85e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -53,9 +53,9 @@ nv50_dac_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); + nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); return 0; } @@ -79,18 +79,18 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) } else return ret; - nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000); - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61a004 + doff, 0x807f0000, 0x80150000); + nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval); + nv_wr32(disp, 0x61a00c + doff, 0x00100000 | loadval); mdelay(9); udelay(500); - loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000); + loadval = nv_mask(disp, 0x61a00c + doff, 0xffffffff, 0x00000000); - nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000); - nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61a004 + doff, 0x807f0000, 0x80550000); + nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval); + nv_debug(disp, "DAC%d sense: 0x%08x\n", outp->or, loadval); if (!(loadval & 0x80000000)) return -ETIMEDOUT; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index 68347661adca8..bc24ae70b4057 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -322,7 +322,7 @@ void nvkm_dp_train(struct work_struct *w) { struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const struct dp_rates *cfg = nvkm_dp_rates; struct dp_state _dp = { .outp = outp, @@ -330,11 +330,11 @@ nvkm_dp_train(struct work_struct *w) u32 datarate = 0; int ret; - if (!outp->base.info.location && priv->sor.magic) - priv->sor.magic(&outp->base); + if (!outp->base.info.location && disp->sor.magic) + disp->sor.magic(&outp->base); /* bring capabilities within encoder limits */ - if (nv_mclass(priv) < GF110_DISP) + if (nv_mclass(disp) < GF110_DISP) outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index a0dcf534cb209..a0801846b4777 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -223,33 +223,33 @@ g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int ret; ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); + "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = g84_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = g84_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 2; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hdmi = g84_hdmi_ctrl; - priv->pior.power = nv50_pior_power; + nv_engine(disp)->sclass = g84_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = nv50_disp_intr; + INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); + disp->sclass = g84_disp_sclass; + disp->head.nr = 2; + disp->dac.nr = 3; + disp->sor.nr = 2; + disp->pior.nr = 3; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hdmi = g84_hdmi_ctrl; + disp->pior.power = nv50_pior_power; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 1ab0d0ae3cc89..9082fb71cda91 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -83,33 +83,33 @@ g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int ret; ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); + "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = g94_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = g94_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hdmi = g84_hdmi_ctrl; - priv->pior.power = nv50_pior_power; + nv_engine(disp)->sclass = g94_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = nv50_disp_intr; + INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); + disp->sclass = g94_disp_sclass; + disp->head.nr = 2; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->pior.nr = 3; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hdmi = g84_hdmi_ctrl; + disp->pior.power = nv50_pior_power; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index 7f2f05f78cc8c..3301fedfe768c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -46,17 +46,17 @@ static void gf110_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) { - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index); - nv_wr32(priv, 0x61008c, 0x00000001 << index); + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + nv_mask(disp, 0x610090, 0x00000001 << index, 0x00000000 << index); + nv_wr32(disp, 0x61008c, 0x00000001 << index); } static void gf110_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) { - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_wr32(priv, 0x61008c, 0x00000001 << index); - nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index); + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + nv_wr32(disp, 0x61008c, 0x00000001 << index); + nv_mask(disp, 0x610090, 0x00000001 << index, 0x00000001 << index); } const struct nvkm_event_func @@ -91,7 +91,7 @@ gf110_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) static int gf110_disp_dmac_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; int chid = dmac->base.chid; int ret; @@ -101,20 +101,20 @@ gf110_disp_dmac_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push); - nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000); - nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001); - nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000); - nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013); + nv_wr32(disp, 0x610494 + (chid * 0x0010), dmac->push); + nv_wr32(disp, 0x610498 + (chid * 0x0010), 0x00010000); + nv_wr32(disp, 0x61049c + (chid * 0x0010), 0x00000001); + nv_mask(disp, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); + nv_wr32(disp, 0x640000 + (chid * 0x1000), 0x00000000); + nv_wr32(disp, 0x610490 + (chid * 0x0010), 0x00000013); /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) { + if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) { nv_error(dmac, "init: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); + nv_rd32(disp, 0x610490 + (chid * 0x10))); return -EBUSY; } @@ -124,23 +124,23 @@ gf110_disp_dmac_init(struct nvkm_object *object) static int gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; int chid = dmac->base.chid; /* deactivate channel */ - nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); - nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) { + nv_mask(disp, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); + nv_mask(disp, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); + if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) { nv_error(dmac, "fini: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); + nv_rd32(disp, 0x610490 + (chid * 0x10))); if (suspend) return -EBUSY; } /* disable error reporting and completion notification */ - nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000); - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000); + nv_mask(disp, 0x610090, 0x00000001 << chid, 0x00000000); + nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000000); return nv50_disp_chan_fini(&dmac->base, suspend); } @@ -292,7 +292,7 @@ gf110_disp_core_mthd_chan = { static int gf110_disp_core_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; int ret; @@ -301,19 +301,19 @@ gf110_disp_core_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001); + nv_mask(disp, 0x6100a0, 0x00000001, 0x00000001); /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610494, mast->push); - nv_wr32(priv, 0x610498, 0x00010000); - nv_wr32(priv, 0x61049c, 0x00000001); - nv_mask(priv, 0x610490, 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000, 0x00000000); - nv_wr32(priv, 0x610490, 0x01000013); + nv_wr32(disp, 0x610494, mast->push); + nv_wr32(disp, 0x610498, 0x00010000); + nv_wr32(disp, 0x61049c, 0x00000001); + nv_mask(disp, 0x610490, 0x00000010, 0x00000010); + nv_wr32(disp, 0x640000, 0x00000000); + nv_wr32(disp, 0x610490, 0x01000013); /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) { - nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490)); + if (!nv_wait(disp, 0x610490, 0x80000000, 0x00000000)) { + nv_error(mast, "init: 0x%08x\n", nv_rd32(disp, 0x610490)); return -EBUSY; } @@ -323,21 +323,21 @@ gf110_disp_core_init(struct nvkm_object *object) static int gf110_disp_core_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; /* deactivate channel */ - nv_mask(priv, 0x610490, 0x00000010, 0x00000000); - nv_mask(priv, 0x610490, 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) { - nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490)); + nv_mask(disp, 0x610490, 0x00000010, 0x00000000); + nv_mask(disp, 0x610490, 0x00000003, 0x00000000); + if (!nv_wait(disp, 0x610490, 0x001e0000, 0x00000000)) { + nv_error(mast, "fini: 0x%08x\n", nv_rd32(disp, 0x610490)); if (suspend) return -EBUSY; } /* disable error reporting and completion notification */ - nv_mask(priv, 0x610090, 0x00000001, 0x00000000); - nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000); + nv_mask(disp, 0x610090, 0x00000001, 0x00000000); + nv_mask(disp, 0x6100a0, 0x00000001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); } @@ -539,7 +539,7 @@ gf110_disp_ovly_ofuncs = { static int gf110_disp_pioc_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; int chid = pioc->base.chid; int ret; @@ -549,13 +549,13 @@ gf110_disp_pioc_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* activate channel */ - nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001); - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) { + nv_wr32(disp, 0x610490 + (chid * 0x10), 0x00000001); + if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) { nv_error(pioc, "init: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); + nv_rd32(disp, 0x610490 + (chid * 0x10))); return -EBUSY; } @@ -565,21 +565,21 @@ gf110_disp_pioc_init(struct nvkm_object *object) static int gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; int chid = pioc->base.chid; - nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) { + nv_mask(disp, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); + if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) { nv_error(pioc, "timeout: 0x%08x\n", - nv_rd32(priv, 0x610490 + (chid * 0x10))); + nv_rd32(disp, 0x610490 + (chid * 0x10))); if (suspend) return -EBUSY; } /* disable error reporting and completion notification */ - nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000); - nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000); + nv_mask(disp, 0x610090, 0x00000001 << chid, 0x00000000); + nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000000); return nv50_disp_chan_fini(&pioc->base, suspend); } @@ -625,9 +625,9 @@ gf110_disp_curs_ofuncs = { int gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) { - const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300)); - const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300)); - const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300)); + const u32 total = nv_rd32(disp, 0x640414 + (head * 0x300)); + const u32 blanke = nv_rd32(disp, 0x64041c + (head * 0x300)); + const u32 blanks = nv_rd32(disp, 0x640420 + (head * 0x300)); union { struct nv04_disp_scanoutpos_v0 v0; } *args = data; @@ -644,10 +644,10 @@ gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) args->v0.htotal = ( total & 0x0000ffff); args->v0.time[0] = ktime_to_ns(ktime_get()); args->v0.vline = /* vline read locks hline */ - nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; + nv_rd32(disp, 0x616340 + (head * 0x800)) & 0xffff; args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = - nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; + nv_rd32(disp, 0x616344 + (head * 0x800)) & 0xffff; } else return ret; @@ -657,7 +657,7 @@ gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) static int gf110_disp_main_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; int ret, i; u32 tmp; @@ -672,44 +672,44 @@ gf110_disp_main_init(struct nvkm_object *object) */ /* ... CRTC caps */ - for (i = 0; i < priv->head.nr; i++) { - tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); - nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp); - tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); - nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp); - tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); - nv_wr32(priv, 0x6101bc + (i * 0x800), tmp); + for (i = 0; i < disp->head.nr; i++) { + tmp = nv_rd32(disp, 0x616104 + (i * 0x800)); + nv_wr32(disp, 0x6101b4 + (i * 0x800), tmp); + tmp = nv_rd32(disp, 0x616108 + (i * 0x800)); + nv_wr32(disp, 0x6101b8 + (i * 0x800), tmp); + tmp = nv_rd32(disp, 0x61610c + (i * 0x800)); + nv_wr32(disp, 0x6101bc + (i * 0x800), tmp); } /* ... DAC caps */ - for (i = 0; i < priv->dac.nr; i++) { - tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); - nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp); + for (i = 0; i < disp->dac.nr; i++) { + tmp = nv_rd32(disp, 0x61a000 + (i * 0x800)); + nv_wr32(disp, 0x6101c0 + (i * 0x800), tmp); } /* ... SOR caps */ - for (i = 0; i < priv->sor.nr; i++) { - tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); - nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp); + for (i = 0; i < disp->sor.nr; i++) { + tmp = nv_rd32(disp, 0x61c000 + (i * 0x800)); + nv_wr32(disp, 0x6301c4 + (i * 0x800), tmp); } /* steal display away from vbios, or something like that */ - if (nv_rd32(priv, 0x6100ac) & 0x00000100) { - nv_wr32(priv, 0x6100ac, 0x00000100); - nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { - nv_error(priv, "timeout acquiring display\n"); + if (nv_rd32(disp, 0x6100ac) & 0x00000100) { + nv_wr32(disp, 0x6100ac, 0x00000100); + nv_mask(disp, 0x6194e8, 0x00000001, 0x00000000); + if (!nv_wait(disp, 0x6194e8, 0x00000002, 0x00000000)) { + nv_error(disp, "timeout acquiring display\n"); return -EBUSY; } } /* point at display engine memory area (hash table, objects) */ - nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); + nv_wr32(disp, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ - nv_wr32(priv, 0x610090, 0x00000000); - nv_wr32(priv, 0x6100a0, 0x00000000); - nv_wr32(priv, 0x6100b0, 0x00000307); + nv_wr32(disp, 0x610090, 0x00000000); + nv_wr32(disp, 0x6100a0, 0x00000000); + nv_wr32(disp, 0x6100b0, 0x00000307); /* disable underflow reporting, preventing an intermittent issue * on some gk104 boards where the production vbios left this @@ -717,8 +717,8 @@ gf110_disp_main_init(struct nvkm_object *object) * * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt */ - for (i = 0; i < priv->head.nr; i++) - nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + for (i = 0; i < disp->head.nr; i++) + nv_mask(disp, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); return 0; } @@ -726,11 +726,11 @@ gf110_disp_main_init(struct nvkm_object *object) static int gf110_disp_main_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; /* disable all interrupts */ - nv_wr32(priv, 0x6100b0, 0x00000000); + nv_wr32(disp, 0x6100b0, 0x00000000); return nvkm_parent_fini(&base->base, suspend); } @@ -787,11 +787,11 @@ gf110_disp_vblank_func = { }; static struct nvkm_output * -exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, +exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); struct nvkm_output *outp; u16 mask, type; @@ -808,7 +808,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; default: - nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); + nv_error(disp, "unknown SOR mc 0x%08x\n", ctrl); return NULL; } } @@ -817,7 +817,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, mask |= 0x0001 << or; mask |= 0x0100 << head; - list_for_each_entry(outp, &priv->base.outp, head) { + list_for_each_entry(outp, &disp->base.outp, head) { if ((outp->info.hasht & 0xff) == type && (outp->info.hashm & mask) == mask) { *data = nvbios_outp_match(bios, outp->info.hasht, @@ -833,9 +833,9 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, } static struct nvkm_output * -exec_script(struct nv50_disp_priv *priv, int head, int id) +exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); struct nvkm_output *outp; struct nvbios_outp info; u8 ver, hdr, cnt, len; @@ -843,7 +843,7 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) int or; for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nv_rd32(priv, 0x640180 + (or * 0x20)); + ctrl = nv_rd32(disp, 0x640180 + (or * 0x20)); if (ctrl & (1 << head)) break; } @@ -851,10 +851,10 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) if (or == 8) return NULL; - outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); if (outp) { struct nvbios_init init = { - .subdev = nv_subdev(priv), + .subdev = nv_subdev(disp), .bios = bios, .offset = info.script[id], .outp = &outp->info, @@ -869,9 +869,9 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) } static struct nvkm_output * -exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) +exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; @@ -880,7 +880,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) int or; for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nv_rd32(priv, 0x660180 + (or * 0x20)); + ctrl = nv_rd32(disp, 0x660180 + (or * 0x20)); if (ctrl & (1 << head)) break; } @@ -888,7 +888,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) if (or == 8) return NULL; - outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); if (!outp) return NULL; @@ -899,7 +899,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) *conf |= 0x0100; break; case DCB_OUTPUT_LVDS: - *conf = priv->sor.lvdsconf; + *conf = disp->sor.lvdsconf; break; case DCB_OUTPUT_DP: *conf = (ctrl & 0x00000f00) >> 8; @@ -915,7 +915,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { - .subdev = nv_subdev(priv), + .subdev = nv_subdev(disp), .bios = bios, .offset = data, .outp = &outp->info, @@ -931,22 +931,22 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) } static void -gf110_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head) +gf110_disp_intr_unk1_0(struct nv50_disp *disp, int head) { - exec_script(priv, head, 1); + exec_script(disp, head, 1); } static void -gf110_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) +gf110_disp_intr_unk2_0(struct nv50_disp *disp, int head) { - struct nvkm_output *outp = exec_script(priv, head, 2); + struct nvkm_output *outp = exec_script(disp, head, 2); /* see note in nv50_disp_intr_unk20_0() */ if (outp && outp->info.type == DCB_OUTPUT_DP) { struct nvkm_output_dp *outpdp = (void *)outp; struct nvbios_init init = { - .subdev = nv_subdev(priv), - .bios = nvkm_bios(priv), + .subdev = nv_subdev(disp), + .bios = nvkm_bios(disp), .outp = &outp->info, .crtc = head, .offset = outpdp->info.script[4], @@ -959,34 +959,34 @@ gf110_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head) } static void -gf110_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head) +gf110_disp_intr_unk2_1(struct nv50_disp *disp, int head) { - struct nvkm_devinit *devinit = nvkm_devinit(priv); - u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; + struct nvkm_devinit *devinit = nvkm_devinit(disp); + u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; if (pclk) devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); - nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000); + nv_wr32(disp, 0x612200 + (head * 0x800), 0x00000000); } static void -gf110_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, +gf110_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, struct dcb_output *outp) { const int or = ffs(outp->or) - 1; - const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020)); - const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300)); - const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff; - const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff; - const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff; - const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; + const u32 ctrl = nv_rd32(disp, 0x660200 + (or * 0x020)); + const u32 conf = nv_rd32(disp, 0x660404 + (head * 0x300)); + const s32 vactive = nv_rd32(disp, 0x660414 + (head * 0x300)) & 0xffff; + const s32 vblanke = nv_rd32(disp, 0x66041c + (head * 0x300)) & 0xffff; + const s32 vblanks = nv_rd32(disp, 0x660420 + (head * 0x300)) & 0xffff; + const u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; const u32 hoff = (head * 0x800); const u32 soff = ( or * 0x800); const u32 loff = (link * 0x080) + soff; const u32 symbol = 100000; const u32 TU = 64; - u32 dpctrl = nv_rd32(priv, 0x61c10c + loff); - u32 clksor = nv_rd32(priv, 0x612300 + soff); + u32 dpctrl = nv_rd32(disp, 0x61c10c + loff); + u32 clksor = nv_rd32(disp, 0x612300 + soff); u32 datarate, link_nr, link_bw, bits; u64 ratio, value; @@ -999,14 +999,14 @@ gf110_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, value = value * link_bw; do_div(value, pclk); value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value); + nv_mask(disp, 0x616620 + hoff, 0x0000ffff, value); /* symbols/vblank - algorithm taken from comments in tegra driver */ value = vblanks - vblanke - 25; value = value * link_bw; do_div(value, pclk); value = value - ((36 / link_nr) + 3) - 1; - nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value); + nv_mask(disp, 0x616624 + hoff, 0x00ffffff, value); /* watermark */ if ((conf & 0x3c0) == 0x180) bits = 30; @@ -1026,23 +1026,23 @@ gf110_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head, value += 5; value |= 0x08000000; - nv_wr32(priv, 0x616610 + hoff, value); + nv_wr32(disp, 0x616610 + hoff, value); } static void -gf110_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) +gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) { struct nvkm_output *outp; - u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; + u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; u32 conf, addr, data; - outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); + outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); if (!outp) return; /* see note in nv50_disp_intr_unk20_2() */ if (outp->info.type == DCB_OUTPUT_DP) { - u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300)); + u32 sync = nv_rd32(disp, 0x660404 + (head * 0x300)); switch ((sync & 0x000003c0) >> 6) { case 6: pclk = pclk * 30; break; case 5: pclk = pclk * 24; break; @@ -1055,11 +1055,11 @@ gf110_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) if (nvkm_output_dp_train(outp, pclk, true)) ERR("link not trained before attach\n"); } else { - if (priv->sor.magic) - priv->sor.magic(outp); + if (disp->sor.magic) + disp->sor.magic(outp); } - exec_clkcmp(priv, head, 0, pclk, &conf); + exec_clkcmp(disp, head, 0, pclk, &conf); if (outp->info.type == DCB_OUTPUT_ANALOG) { addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; @@ -1069,102 +1069,102 @@ gf110_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head) data = (conf & 0x0100) ? 0x00000101 : 0x00000000; switch (outp->info.type) { case DCB_OUTPUT_TMDS: - nv_mask(priv, addr, 0x007c0000, 0x00280000); + nv_mask(disp, addr, 0x007c0000, 0x00280000); break; case DCB_OUTPUT_DP: - gf110_disp_intr_unk2_2_tu(priv, head, &outp->info); + gf110_disp_intr_unk2_2_tu(disp, head, &outp->info); break; default: break; } } - nv_mask(priv, addr, 0x00000707, data); + nv_mask(disp, addr, 0x00000707, data); } static void -gf110_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head) +gf110_disp_intr_unk4_0(struct nv50_disp *disp, int head) { - u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000; + u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; u32 conf; - exec_clkcmp(priv, head, 1, pclk, &conf); + exec_clkcmp(disp, head, 1, pclk, &conf); } void gf110_disp_intr_supervisor(struct work_struct *work) { - struct nv50_disp_priv *priv = - container_of(work, struct nv50_disp_priv, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; + struct nv50_disp *disp = + container_of(work, struct nv50_disp, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; u32 mask[4]; int head; - nv_debug(priv, "supervisor %d\n", ffs(priv->super)); - for (head = 0; head < priv->head.nr; head++) { - mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800)); - nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]); + nv_debug(disp, "supervisor %d\n", ffs(disp->super)); + for (head = 0; head < disp->head.nr; head++) { + mask[head] = nv_rd32(disp, 0x6101d4 + (head * 0x800)); + nv_debug(disp, "head %d: 0x%08x\n", head, mask[head]); } - if (priv->super & 0x00000001) { - nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000001) { + nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); + for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(priv, "supervisor 1.0 - head %d\n", head); - gf110_disp_intr_unk1_0(priv, head); + nv_debug(disp, "supervisor 1.0 - head %d\n", head); + gf110_disp_intr_unk1_0(disp, head); } } else - if (priv->super & 0x00000002) { - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000002) { + for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(priv, "supervisor 2.0 - head %d\n", head); - gf110_disp_intr_unk2_0(priv, head); + nv_debug(disp, "supervisor 2.0 - head %d\n", head); + gf110_disp_intr_unk2_0(disp, head); } - for (head = 0; head < priv->head.nr; head++) { + for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00010000)) continue; - nv_debug(priv, "supervisor 2.1 - head %d\n", head); - gf110_disp_intr_unk2_1(priv, head); + nv_debug(disp, "supervisor 2.1 - head %d\n", head); + gf110_disp_intr_unk2_1(disp, head); } - for (head = 0; head < priv->head.nr; head++) { + for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(priv, "supervisor 2.2 - head %d\n", head); - gf110_disp_intr_unk2_2(priv, head); + nv_debug(disp, "supervisor 2.2 - head %d\n", head); + gf110_disp_intr_unk2_2(disp, head); } } else - if (priv->super & 0x00000004) { - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000004) { + for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(priv, "supervisor 3.0 - head %d\n", head); - gf110_disp_intr_unk4_0(priv, head); + nv_debug(disp, "supervisor 3.0 - head %d\n", head); + gf110_disp_intr_unk4_0(disp, head); } } - for (head = 0; head < priv->head.nr; head++) - nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000); - nv_wr32(priv, 0x6101d0, 0x80000000); + for (head = 0; head < disp->head.nr; head++) + nv_wr32(disp, 0x6101d4 + (head * 0x800), 0x00000000); + nv_wr32(disp, 0x6101d0, 0x80000000); } static void -gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid) +gf110_disp_intr_error(struct nv50_disp *disp, int chid) { - const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12)); - u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12)); - u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12)); + const struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; + u32 mthd = nv_rd32(disp, 0x6101f0 + (chid * 12)); + u32 data = nv_rd32(disp, 0x6101f4 + (chid * 12)); + u32 unkn = nv_rd32(disp, 0x6101f8 + (chid * 12)); - nv_error(priv, "chid %d mthd 0x%04x data 0x%08x " + nv_error(disp, "chid %d mthd 0x%04x data 0x%08x " "0x%08x 0x%08x\n", chid, (mthd & 0x0000ffc), data, mthd, unkn); if (chid == 0) { switch (mthd & 0xffc) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 0, impl->mthd.core); break; default: @@ -1174,7 +1174,7 @@ gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid) if (chid <= 4) { switch (mthd & 0xffc) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 1, impl->mthd.base); break; default: @@ -1184,7 +1184,7 @@ gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid) if (chid <= 8) { switch (mthd & 0xffc) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5, + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 5, impl->mthd.ovly); break; default: @@ -1192,60 +1192,60 @@ gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid) } } - nv_wr32(priv, 0x61009c, (1 << chid)); - nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000); + nv_wr32(disp, 0x61009c, (1 << chid)); + nv_wr32(disp, 0x6101f0 + (chid * 12), 0x90000000); } void gf110_disp_intr(struct nvkm_subdev *subdev) { - struct nv50_disp_priv *priv = (void *)subdev; - u32 intr = nv_rd32(priv, 0x610088); + struct nv50_disp *disp = (void *)subdev; + u32 intr = nv_rd32(disp, 0x610088); int i; if (intr & 0x00000001) { - u32 stat = nv_rd32(priv, 0x61008c); + u32 stat = nv_rd32(disp, 0x61008c); while (stat) { int chid = __ffs(stat); stat &= ~(1 << chid); - nv50_disp_chan_uevent_send(priv, chid); - nv_wr32(priv, 0x61008c, 1 << chid); + nv50_disp_chan_uevent_send(disp, chid); + nv_wr32(disp, 0x61008c, 1 << chid); } intr &= ~0x00000001; } if (intr & 0x00000002) { - u32 stat = nv_rd32(priv, 0x61009c); + u32 stat = nv_rd32(disp, 0x61009c); int chid = ffs(stat) - 1; if (chid >= 0) - gf110_disp_intr_error(priv, chid); + gf110_disp_intr_error(disp, chid); intr &= ~0x00000002; } if (intr & 0x00100000) { - u32 stat = nv_rd32(priv, 0x6100ac); + u32 stat = nv_rd32(disp, 0x6100ac); if (stat & 0x00000007) { - priv->super = (stat & 0x00000007); - schedule_work(&priv->supervisor); - nv_wr32(priv, 0x6100ac, priv->super); + disp->super = (stat & 0x00000007); + schedule_work(&disp->supervisor); + nv_wr32(disp, 0x6100ac, disp->super); stat &= ~0x00000007; } if (stat) { - nv_info(priv, "unknown intr24 0x%08x\n", stat); - nv_wr32(priv, 0x6100ac, stat); + nv_info(disp, "unknown intr24 0x%08x\n", stat); + nv_wr32(disp, 0x6100ac, stat); } intr &= ~0x00100000; } - for (i = 0; i < priv->head.nr; i++) { + for (i = 0; i < disp->head.nr; i++) { u32 mask = 0x01000000 << i; if (mask & intr) { - u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800)); + u32 stat = nv_rd32(disp, 0x6100bc + (i * 0x800)); if (stat & 0x00000001) - nvkm_disp_vblank(&priv->base, i); - nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0); - nv_rd32(priv, 0x6100c0 + (i * 0x800)); + nvkm_disp_vblank(&disp->base, i); + nv_mask(disp, 0x6100bc + (i * 0x800), 0, 0); + nv_rd32(disp, 0x6100c0 + (i * 0x800)); } } } @@ -1255,33 +1255,33 @@ gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int heads = nv_rd32(parent, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); + "PDISP", "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); + ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gf110_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gf110_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gf110_hdmi_ctrl; + nv_engine(disp)->sclass = gf110_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = gf110_disp_intr; + INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + disp->sclass = gf110_disp_sclass; + disp->head.nr = heads; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hdmi = gf110_hdmi_ctrl; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 6f4019ab4e650..ccb5bfad9ec8a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -219,33 +219,33 @@ gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int heads = nv_rd32(parent, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); + "PDISP", "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); + ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gk104_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gk104_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gk104_hdmi_ctrl; + nv_engine(disp)->sclass = gk104_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = gf110_disp_intr; + INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + disp->sclass = gk104_disp_sclass; + disp->head.nr = heads; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hdmi = gk104_hdmi_ctrl; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index daa4b460a6ba2..f4372fb382463 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -54,33 +54,33 @@ gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int heads = nv_rd32(parent, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); + "PDISP", "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); + ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gk110_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gk110_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gk104_hdmi_ctrl; + nv_engine(disp)->sclass = gk110_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = gf110_disp_intr; + INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + disp->sclass = gk110_disp_sclass; + disp->head.nr = heads; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hdmi = gk104_hdmi_ctrl; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 881cc94385a1b..558c38736f55a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -54,33 +54,33 @@ gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int heads = nv_rd32(parent, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); + "PDISP", "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); + ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gm107_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gm107_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gk104_hdmi_ctrl; + nv_engine(disp)->sclass = gm107_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = gf110_disp_intr; + INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + disp->sclass = gm107_disp_sclass; + disp->head.nr = heads; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hdmi = gk104_hdmi_ctrl; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index 67004f8302b30..a56ef7bd6623f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -55,34 +55,34 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int heads = nv_rd32(parent, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &priv); - *pobject = nv_object(priv); + "PDISP", "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent); + ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gm204_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = gf110_disp_intr; - INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor); - priv->sclass = gm204_disp_sclass; - priv->head.nr = heads; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gf110_hda_eld; - priv->sor.hdmi = gf110_hdmi_ctrl; - priv->sor.magic = gm204_sor_magic; + nv_engine(disp)->sclass = gm204_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = gf110_disp_intr; + INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + disp->sclass = gm204_disp_sclass; + disp->head.nr = heads; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hdmi = gf110_hdmi_ctrl; + disp->sor.magic = gm204_sor_magic; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index a45307213f4b1..65cf51f3e8bd3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -99,33 +99,33 @@ gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int ret; ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); + "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gt200_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = gt200_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 2; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hdmi = g84_hdmi_ctrl; - priv->pior.power = nv50_pior_power; + nv_engine(disp)->sclass = gt200_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = nv50_disp_intr; + INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); + disp->sclass = gt200_disp_sclass; + disp->head.nr = 2; + disp->dac.nr = 3; + disp->sor.nr = 2; + disp->pior.nr = 3; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hdmi = g84_hdmi_ctrl; + disp->pior.power = nv50_pior_power; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 55f0d3ac591e7..0a2b794c3f63f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -54,34 +54,34 @@ gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int ret; ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); + "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = gt215_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = gt215_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 4; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->sor.hda_eld = gt215_hda_eld; - priv->sor.hdmi = gt215_hdmi_ctrl; - priv->pior.power = nv50_pior_power; + nv_engine(disp)->sclass = gt215_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = nv50_disp_intr; + INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); + disp->sclass = gt215_disp_sclass; + disp->head.nr = 2; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->pior.nr = 3; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gt215_hda_eld; + disp->sor.hdmi = gt215_hdmi_ctrl; + disp->pior.power = nv50_pior_power; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c index b9813d246ba5d..fe07d7cb4dd7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c @@ -52,21 +52,21 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001); - nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000); + nv_mask(disp, 0x616618 + hoff, 0x8000000c, 0x80000001); + nv_wait(disp, 0x616618 + hoff, 0x80000000, 0x00000000); } - nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000); + nv_mask(disp, 0x616548 + hoff, 0x00000070, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); + nv_wr32(disp, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); for (; i < 0x60; i++) - nv_wr32(priv, 0x10ec00 + soff, (i << 8)); - nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003); + nv_wr32(disp, 0x10ec00 + soff, (i << 8)); + nv_mask(disp, 0x10ec10 + soff, 0x80000003, 0x80000003); } else { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000); - nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000); + nv_mask(disp, 0x616618 + hoff, 0x80000001, 0x80000000); + nv_wait(disp, 0x616618 + hoff, 0x80000000, 0x00000000); } - nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); + nv_mask(disp, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index 891d1e7bf7d28..67d3cf99e0b54 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -49,20 +49,20 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001); - nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61c1e0 + soff, 0x8000000d, 0x80000001); + nv_wait(disp, 0x61c1e0 + soff, 0x80000000, 0x00000000); } for (i = 0; i < size; i++) - nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]); + nv_wr32(disp, 0x61c440 + soff, (i << 8) | args->v0.data[0]); for (; i < 0x60; i++) - nv_wr32(priv, 0x61c440 + soff, (i << 8)); - nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003); + nv_wr32(disp, 0x61c440 + soff, (i << 8)); + nv_mask(disp, 0x61c448 + soff, 0x80000003, 0x80000003); } else { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000); - nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61c1e0 + soff, 0x80000001, 0x80000000); + nv_wait(disp, 0x61c1e0 + soff, 0x80000000, 0x00000000); } - nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); + nv_mask(disp, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index 621cb0b7ff190..0c282a4d31a88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -54,38 +54,38 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000); - nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000); - nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000); + nv_mask(disp, 0x6165a4 + hoff, 0x40000000, 0x00000000); + nv_mask(disp, 0x616520 + hoff, 0x00000001, 0x00000000); + nv_mask(disp, 0x616500 + hoff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x616528 + hoff, 0x000d0282); - nv_wr32(priv, 0x61652c + hoff, 0x0000006f); - nv_wr32(priv, 0x616530 + hoff, 0x00000000); - nv_wr32(priv, 0x616534 + hoff, 0x00000000); - nv_wr32(priv, 0x616538 + hoff, 0x00000000); - nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001); + nv_mask(disp, 0x616520 + hoff, 0x00000001, 0x00000000); + nv_wr32(disp, 0x616528 + hoff, 0x000d0282); + nv_wr32(disp, 0x61652c + hoff, 0x0000006f); + nv_wr32(disp, 0x616530 + hoff, 0x00000000); + nv_wr32(disp, 0x616534 + hoff, 0x00000000); + nv_wr32(disp, 0x616538 + hoff, 0x00000000); + nv_mask(disp, 0x616520 + hoff, 0x00000001, 0x00000001); /* Audio InfoFrame */ - nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x616508 + hoff, 0x000a0184); - nv_wr32(priv, 0x61650c + hoff, 0x00000071); - nv_wr32(priv, 0x616510 + hoff, 0x00000000); - nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001); + nv_mask(disp, 0x616500 + hoff, 0x00000001, 0x00000000); + nv_wr32(disp, 0x616508 + hoff, 0x000a0184); + nv_wr32(disp, 0x61650c + hoff, 0x00000071); + nv_wr32(disp, 0x616510 + hoff, 0x00000000); + nv_mask(disp, 0x616500 + hoff, 0x00000001, 0x00000001); - nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ - nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ - nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + nv_mask(disp, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nv_mask(disp, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nv_mask(disp, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ /* ??? */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ - nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ + nv_mask(disp, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ + nv_mask(disp, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ + nv_mask(disp, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl); + nv_mask(disp, 0x6165a4 + hoff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c index c28449061bbde..5dcbc8e50d815 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c @@ -53,27 +53,27 @@ gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); - nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); - nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); + nv_mask(disp, 0x616798 + hoff, 0x40000000, 0x00000000); + nv_mask(disp, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nv_mask(disp, 0x616714 + hoff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x61671c + hoff, 0x000d0282); - nv_wr32(priv, 0x616720 + hoff, 0x0000006f); - nv_wr32(priv, 0x616724 + hoff, 0x00000000); - nv_wr32(priv, 0x616728 + hoff, 0x00000000); - nv_wr32(priv, 0x61672c + hoff, 0x00000000); - nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001); + nv_mask(disp, 0x616714 + hoff, 0x00000001, 0x00000000); + nv_wr32(disp, 0x61671c + hoff, 0x000d0282); + nv_wr32(disp, 0x616720 + hoff, 0x0000006f); + nv_wr32(disp, 0x616724 + hoff, 0x00000000); + nv_wr32(disp, 0x616728 + hoff, 0x00000000); + nv_wr32(disp, 0x61672c + hoff, 0x00000000); + nv_mask(disp, 0x616714 + hoff, 0x00000001, 0x00000001); /* ??? InfoFrame? */ - nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x6167ac + hoff, 0x00000010); - nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001); + nv_mask(disp, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nv_wr32(disp, 0x6167ac + hoff, 0x00000010); + nv_mask(disp, 0x6167a4 + hoff, 0x00000001, 0x00000001); /* HDMI_CTRL */ - nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); + nv_mask(disp, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index ca34ff81ad7f5..719d21e85301b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -54,30 +54,30 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000); - nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); - nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); + nv_mask(disp, 0x616798 + hoff, 0x40000000, 0x00000000); + nv_mask(disp, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nv_mask(disp, 0x690000 + hdmi, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000); - nv_wr32(priv, 0x690008 + hdmi, 0x000d0282); - nv_wr32(priv, 0x69000c + hdmi, 0x0000006f); - nv_wr32(priv, 0x690010 + hdmi, 0x00000000); - nv_wr32(priv, 0x690014 + hdmi, 0x00000000); - nv_wr32(priv, 0x690018 + hdmi, 0x00000000); - nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001); + nv_mask(disp, 0x690000 + hdmi, 0x00000001, 0x00000000); + nv_wr32(disp, 0x690008 + hdmi, 0x000d0282); + nv_wr32(disp, 0x69000c + hdmi, 0x0000006f); + nv_wr32(disp, 0x690010 + hdmi, 0x00000000); + nv_wr32(disp, 0x690014 + hdmi, 0x00000000); + nv_wr32(disp, 0x690018 + hdmi, 0x00000000); + nv_mask(disp, 0x690000 + hdmi, 0x00000001, 0x00000001); /* ??? InfoFrame? */ - nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000); - nv_wr32(priv, 0x6900cc + hdmi, 0x00000010); - nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001); + nv_mask(disp, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nv_wr32(disp, 0x6900cc + hdmi, 0x00000010); + nv_mask(disp, 0x6900c0 + hdmi, 0x00000001, 0x00000001); /* ??? */ - nv_wr32(priv, 0x690080 + hdmi, 0x82000000); + nv_wr32(disp, 0x690080 + hdmi, 0x82000000); /* HDMI_CTRL */ - nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl); + nv_mask(disp, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index b641c167dcfa3..dde989158153f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -55,38 +55,38 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000); - nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000); - nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000); + nv_mask(disp, 0x61c5a4 + soff, 0x40000000, 0x00000000); + nv_mask(disp, 0x61c520 + soff, 0x00000001, 0x00000000); + nv_mask(disp, 0x61c500 + soff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x61c528 + soff, 0x000d0282); - nv_wr32(priv, 0x61c52c + soff, 0x0000006f); - nv_wr32(priv, 0x61c530 + soff, 0x00000000); - nv_wr32(priv, 0x61c534 + soff, 0x00000000); - nv_wr32(priv, 0x61c538 + soff, 0x00000000); - nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001); + nv_mask(disp, 0x61c520 + soff, 0x00000001, 0x00000000); + nv_wr32(disp, 0x61c528 + soff, 0x000d0282); + nv_wr32(disp, 0x61c52c + soff, 0x0000006f); + nv_wr32(disp, 0x61c530 + soff, 0x00000000); + nv_wr32(disp, 0x61c534 + soff, 0x00000000); + nv_wr32(disp, 0x61c538 + soff, 0x00000000); + nv_mask(disp, 0x61c520 + soff, 0x00000001, 0x00000001); /* Audio InfoFrame */ - nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000); - nv_wr32(priv, 0x61c508 + soff, 0x000a0184); - nv_wr32(priv, 0x61c50c + soff, 0x00000071); - nv_wr32(priv, 0x61c510 + soff, 0x00000000); - nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001); + nv_mask(disp, 0x61c500 + soff, 0x00000001, 0x00000000); + nv_wr32(disp, 0x61c508 + soff, 0x000a0184); + nv_wr32(disp, 0x61c50c + soff, 0x00000071); + nv_wr32(disp, 0x61c510 + soff, 0x00000000); + nv_mask(disp, 0x61c500 + soff, 0x00000001, 0x00000001); - nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ - nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ - nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + nv_mask(disp, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nv_mask(disp, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nv_mask(disp, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ /* ??? */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ - nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ - nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ + nv_mask(disp, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ + nv_mask(disp, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ + nv_mask(disp, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl); + nv_mask(disp, 0x61c5a4 + soff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index b8f9e5c2b3c85..81359d25afce8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -28,12 +28,8 @@ #include #include -struct nv04_disp_priv { - struct nvkm_disp base; -}; - static int -nv04_disp_scanoutpos(struct nvkm_object *object, struct nv04_disp_priv *priv, +nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, void *data, u32 size, int head) { const u32 hoff = head * 0x2000; @@ -46,12 +42,12 @@ nv04_disp_scanoutpos(struct nvkm_object *object, struct nv04_disp_priv *priv, nv_ioctl(object, "disp scanoutpos size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); - args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff; - args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff; + args->v0.vblanks = nv_rd32(disp, 0x680800 + hoff) & 0xffff; + args->v0.vtotal = nv_rd32(disp, 0x680804 + hoff) & 0xffff; args->v0.vblanke = args->v0.vtotal - 1; - args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff; - args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff; + args->v0.hblanks = nv_rd32(disp, 0x680820 + hoff) & 0xffff; + args->v0.htotal = nv_rd32(disp, 0x680824 + hoff) & 0xffff; args->v0.hblanke = args->v0.htotal - 1; /* @@ -63,7 +59,7 @@ nv04_disp_scanoutpos(struct nvkm_object *object, struct nv04_disp_priv *priv, return -ENOTSUPP; args->v0.time[0] = ktime_to_ns(ktime_get()); - line = nv_rd32(priv, 0x600868 + hoff); + line = nv_rd32(disp, 0x600868 + hoff); args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = (line & 0xffff0000) >> 16; args->v0.vline = (line & 0x0000ffff); @@ -79,7 +75,7 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) union { struct nv04_disp_mthd_v0 v0; } *args = data; - struct nv04_disp_priv *priv = (void *)object->engine; + struct nvkm_disp *disp = (void *)object->engine; int head, ret; nv_ioctl(object, "disp mthd size %d\n", size); @@ -96,7 +92,7 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) switch (mthd) { case NV04_DISP_SCANOUTPOS: - return nv04_disp_scanoutpos(object, priv, data, size, head); + return nv04_disp_scanoutpos(object, disp, data, size, head); default: break; } @@ -148,27 +144,27 @@ nv04_disp_vblank_func = { static void nv04_disp_intr(struct nvkm_subdev *subdev) { - struct nv04_disp_priv *priv = (void *)subdev; - u32 crtc0 = nv_rd32(priv, 0x600100); - u32 crtc1 = nv_rd32(priv, 0x602100); + struct nvkm_disp *disp = (void *)subdev; + u32 crtc0 = nv_rd32(disp, 0x600100); + u32 crtc1 = nv_rd32(disp, 0x602100); u32 pvideo; if (crtc0 & 0x00000001) { - nvkm_disp_vblank(&priv->base, 0); - nv_wr32(priv, 0x600100, 0x00000001); + nvkm_disp_vblank(disp, 0); + nv_wr32(disp, 0x600100, 0x00000001); } if (crtc1 & 0x00000001) { - nvkm_disp_vblank(&priv->base, 1); - nv_wr32(priv, 0x602100, 0x00000001); + nvkm_disp_vblank(disp, 1); + nv_wr32(disp, 0x602100, 0x00000001); } - if (nv_device(priv)->chipset >= 0x10 && - nv_device(priv)->chipset <= 0x40) { - pvideo = nv_rd32(priv, 0x8100); + if (nv_device(disp)->chipset >= 0x10 && + nv_device(disp)->chipset <= 0x40) { + pvideo = nv_rd32(disp, 0x8100); if (pvideo & ~0x11) - nv_info(priv, "PVIDEO intr: %08x\n", pvideo); - nv_wr32(priv, 0x8100, pvideo); + nv_info(disp, "PVIDEO intr: %08x\n", pvideo); + nv_wr32(disp, 0x8100, pvideo); } } @@ -177,17 +173,17 @@ nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_disp_priv *priv; + struct nvkm_disp *disp; int ret; ret = nvkm_disp_create(parent, engine, oclass, 2, "DISPLAY", - "display", &priv); - *pobject = nv_object(priv); + "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - nv_engine(priv)->sclass = nv04_disp_sclass; - nv_subdev(priv)->intr = nv04_disp_intr; + nv_engine(disp)->sclass = nv04_disp_sclass; + nv_subdev(disp)->intr = nv04_disp_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 25fcabcb1d6c4..9551cfe5622a7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -88,26 +88,26 @@ nv50_disp_chan_destroy(struct nv50_disp_chan *chan) static void nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) { - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index); - nv_wr32(priv, 0x610020, 0x00000001 << index); + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + nv_mask(disp, 0x610028, 0x00000001 << index, 0x00000000 << index); + nv_wr32(disp, 0x610020, 0x00000001 << index); } static void nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) { - struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent); - nv_wr32(priv, 0x610020, 0x00000001 << index); - nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index); + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + nv_wr32(disp, 0x610020, 0x00000001 << index); + nv_mask(disp, 0x610028, 0x00000001 << index, 0x00000001 << index); } void -nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid) +nv50_disp_chan_uevent_send(struct nv50_disp *disp, int chid) { struct nvif_notify_uevent_rep { } rep; - nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep)); + nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep)); } int @@ -141,10 +141,10 @@ int nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; switch (type) { case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: - *pevent = &priv->uevent; + *pevent = &disp->uevent; return 0; default: break; @@ -165,17 +165,17 @@ nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) u32 nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_chan *chan = (void *)object; - return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr); + return nv_rd32(disp, 0x640000 + (chan->chid * 0x1000) + addr); } void nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_chan *chan = (void *)object; - nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data); + nv_wr32(disp, 0x640000 + (chan->chid * 0x1000) + addr, data); } /******************************************************************************* @@ -255,7 +255,7 @@ nv50_disp_dmac_dtor(struct nvkm_object *object) static int nv50_disp_dmac_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; int chid = dmac->base.chid; int ret; @@ -265,20 +265,20 @@ nv50_disp_dmac_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid); + nv_mask(disp, 0x610028, 0x00010000 << chid, 0x00010000 << chid); /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push); - nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000); - nv_wr32(priv, 0x61020c + (chid * 0x0010), chid); - nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000); - nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013); + nv_wr32(disp, 0x610204 + (chid * 0x0010), dmac->push); + nv_wr32(disp, 0x610208 + (chid * 0x0010), 0x00010000); + nv_wr32(disp, 0x61020c + (chid * 0x0010), chid); + nv_mask(disp, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); + nv_wr32(disp, 0x640000 + (chid * 0x1000), 0x00000000); + nv_wr32(disp, 0x610200 + (chid * 0x0010), 0x00000013); /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) { + if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) { nv_error(dmac, "init timeout, 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); + nv_rd32(disp, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -288,22 +288,22 @@ nv50_disp_dmac_init(struct nvkm_object *object) static int nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; int chid = dmac->base.chid; /* deactivate channel */ - nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); - nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) { + nv_mask(disp, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); + nv_mask(disp, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); + if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) { nv_error(dmac, "fini timeout, 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); + nv_rd32(disp, 0x610200 + (chid * 0x10))); if (suspend) return -EBUSY; } /* disable error reporting and completion notifications */ - nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid); + nv_mask(disp, 0x610028, 0x00010001 << chid, 0x00000000 << chid); return nv50_disp_chan_fini(&dmac->base, suspend); } @@ -313,16 +313,16 @@ nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) ******************************************************************************/ static void -nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, +nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, const struct nv50_disp_mthd_list *list, int inst) { - struct nvkm_object *disp = nv_object(priv); + struct nvkm_object *object = nv_object(disp); int i; for (i = 0; list->data[i].mthd; i++) { if (list->data[i].addr) { - u32 next = nv_rd32(priv, list->data[i].addr + base + 0); - u32 prev = nv_rd32(priv, list->data[i].addr + base + c); + u32 next = nv_rd32(disp, list->data[i].addr + base + 0); + u32 prev = nv_rd32(disp, list->data[i].addr + base + c); u32 mthd = list->data[i].mthd + (list->mthd * inst); const char *name = list->data[i].name; char mods[16]; @@ -332,7 +332,7 @@ nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, else snprintf(mods, sizeof(mods), "%13c", ' '); - nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n", + nv_printk_(object, debug, "\t0x%04x: 0x%08x %s%s%s\n", mthd, prev, mods, name ? " // " : "", name ? name : ""); } @@ -340,15 +340,15 @@ nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c, } void -nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, +nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, const struct nv50_disp_mthd_chan *chan) { - struct nvkm_object *disp = nv_object(priv); - const struct nv50_disp_impl *impl = (void *)disp->oclass; + struct nvkm_object *object = nv_object(disp); + const struct nv50_disp_impl *impl = (void *)object->oclass; const struct nv50_disp_mthd_list *list; int i, j; - if (debug > nv_subdev(priv)->debug) + if (debug > nv_subdev(disp)->debug) return; for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { @@ -370,8 +370,8 @@ nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head, sname = sname_; } - nv_printk_(disp, debug, "%s%s:\n", cname, sname); - nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev, + nv_printk_(object, debug, "%s%s:\n", cname, sname); + nv50_disp_mthd_list(disp, debug, base, impl->mthd.prev, list, j); } } @@ -515,7 +515,7 @@ nv50_disp_core_ctor(struct nvkm_object *parent, static int nv50_disp_core_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; int ret; @@ -524,25 +524,25 @@ nv50_disp_core_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(priv, 0x610028, 0x00010000, 0x00010000); + nv_mask(disp, 0x610028, 0x00010000, 0x00010000); /* attempt to unstick channel from some unknown state */ - if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000) - nv_mask(priv, 0x610200, 0x00800000, 0x00800000); - if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000) - nv_mask(priv, 0x610200, 0x00600000, 0x00600000); + if ((nv_rd32(disp, 0x610200) & 0x009f0000) == 0x00020000) + nv_mask(disp, 0x610200, 0x00800000, 0x00800000); + if ((nv_rd32(disp, 0x610200) & 0x003f0000) == 0x00030000) + nv_mask(disp, 0x610200, 0x00600000, 0x00600000); /* initialise channel for dma command submission */ - nv_wr32(priv, 0x610204, mast->push); - nv_wr32(priv, 0x610208, 0x00010000); - nv_wr32(priv, 0x61020c, 0x00000000); - nv_mask(priv, 0x610200, 0x00000010, 0x00000010); - nv_wr32(priv, 0x640000, 0x00000000); - nv_wr32(priv, 0x610200, 0x01000013); + nv_wr32(disp, 0x610204, mast->push); + nv_wr32(disp, 0x610208, 0x00010000); + nv_wr32(disp, 0x61020c, 0x00000000); + nv_mask(disp, 0x610200, 0x00000010, 0x00000010); + nv_wr32(disp, 0x640000, 0x00000000); + nv_wr32(disp, 0x610200, 0x01000013); /* wait for it to go inactive */ - if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) { - nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200)); + if (!nv_wait(disp, 0x610200, 0x80000000, 0x00000000)) { + nv_error(mast, "init: 0x%08x\n", nv_rd32(disp, 0x610200)); return -EBUSY; } @@ -552,20 +552,20 @@ nv50_disp_core_init(struct nvkm_object *object) static int nv50_disp_core_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; /* deactivate channel */ - nv_mask(priv, 0x610200, 0x00000010, 0x00000000); - nv_mask(priv, 0x610200, 0x00000003, 0x00000000); - if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) { - nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200)); + nv_mask(disp, 0x610200, 0x00000010, 0x00000000); + nv_mask(disp, 0x610200, 0x00000003, 0x00000000); + if (!nv_wait(disp, 0x610200, 0x001e0000, 0x00000000)) { + nv_error(mast, "fini: 0x%08x\n", nv_rd32(disp, 0x610200)); if (suspend) return -EBUSY; } /* disable error reporting and completion notifications */ - nv_mask(priv, 0x610028, 0x00010001, 0x00000000); + nv_mask(disp, 0x610028, 0x00010001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); } @@ -648,7 +648,7 @@ nv50_disp_base_ctor(struct nvkm_object *parent, union { struct nv50_disp_base_channel_dma_v0 v0; } *args = data; - struct nv50_disp_priv *priv = (void *)engine; + struct nv50_disp *disp = (void *)engine; struct nv50_disp_dmac *dmac; int ret; @@ -657,7 +657,7 @@ nv50_disp_base_ctor(struct nvkm_object *parent, nv_ioctl(parent, "create disp base channel dma vers %d " "pushbuf %08x head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > priv->head.nr) + if (args->v0.head > disp->head.nr) return -EINVAL; } else return ret; @@ -738,7 +738,7 @@ nv50_disp_ovly_ctor(struct nvkm_object *parent, union { struct nv50_disp_overlay_channel_dma_v0 v0; } *args = data; - struct nv50_disp_priv *priv = (void *)engine; + struct nv50_disp *disp = (void *)engine; struct nv50_disp_dmac *dmac; int ret; @@ -747,7 +747,7 @@ nv50_disp_ovly_ctor(struct nvkm_object *parent, nv_ioctl(parent, "create disp overlay channel dma vers %d " "pushbuf %08x head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > priv->head.nr) + if (args->v0.head > disp->head.nr) return -EINVAL; } else return ret; @@ -801,7 +801,7 @@ nv50_disp_pioc_dtor(struct nvkm_object *object) static int nv50_disp_pioc_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; int chid = pioc->base.chid; int ret; @@ -810,17 +810,17 @@ nv50_disp_pioc_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) { + nv_wr32(disp, 0x610200 + (chid * 0x10), 0x00002000); + if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) { nv_error(pioc, "timeout0: 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); + nv_rd32(disp, 0x610200 + (chid * 0x10))); return -EBUSY; } - nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) { + nv_wr32(disp, 0x610200 + (chid * 0x10), 0x00000001); + if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) { nv_error(pioc, "timeout1: 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); + nv_rd32(disp, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -830,14 +830,14 @@ nv50_disp_pioc_init(struct nvkm_object *object) static int nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; int chid = pioc->base.chid; - nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) { + nv_mask(disp, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); + if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) { nv_error(pioc, "timeout: 0x%08x\n", - nv_rd32(priv, 0x610200 + (chid * 0x10))); + nv_rd32(disp, 0x610200 + (chid * 0x10))); if (suspend) return -EBUSY; } @@ -858,7 +858,7 @@ nv50_disp_oimm_ctor(struct nvkm_object *parent, union { struct nv50_disp_overlay_v0 v0; } *args = data; - struct nv50_disp_priv *priv = (void *)engine; + struct nv50_disp *disp = (void *)engine; struct nv50_disp_pioc *pioc; int ret; @@ -866,7 +866,7 @@ nv50_disp_oimm_ctor(struct nvkm_object *parent, if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(parent, "create disp overlay vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > priv->head.nr) + if (args->v0.head > disp->head.nr) return -EINVAL; } else return ret; @@ -906,7 +906,7 @@ nv50_disp_curs_ctor(struct nvkm_object *parent, union { struct nv50_disp_cursor_v0 v0; } *args = data; - struct nv50_disp_priv *priv = (void *)engine; + struct nv50_disp *disp = (void *)engine; struct nv50_disp_pioc *pioc; int ret; @@ -914,7 +914,7 @@ nv50_disp_curs_ctor(struct nvkm_object *parent, if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(parent, "create disp cursor vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > priv->head.nr) + if (args->v0.head > disp->head.nr) return -EINVAL; } else return ret; @@ -948,9 +948,9 @@ nv50_disp_curs_ofuncs = { int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) { - const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540)); - const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540)); - const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540)); + const u32 blanke = nv_rd32(disp, 0x610aec + (head * 0x540)); + const u32 blanks = nv_rd32(disp, 0x610af4 + (head * 0x540)); + const u32 total = nv_rd32(disp, 0x610afc + (head * 0x540)); union { struct nv04_disp_scanoutpos_v0 v0; } *args = data; @@ -967,10 +967,10 @@ nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) args->v0.htotal = ( total & 0x0000ffff); args->v0.time[0] = ktime_to_ns(ktime_get()); args->v0.vline = /* vline read locks hline */ - nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff; + nv_rd32(disp, 0x616340 + (head * 0x800)) & 0xffff; args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = - nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff; + nv_rd32(disp, 0x616344 + (head * 0x800)) & 0xffff; } else return ret; @@ -985,7 +985,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) struct nv50_disp_mthd_v0 v0; struct nv50_disp_mthd_v1 v1; } *args = data; - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nvkm_output *outp = NULL; struct nvkm_output *temp; u16 type, mask = 0; @@ -1013,11 +1013,11 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) } else return ret; - if (head < 0 || head >= priv->head.nr) + if (head < 0 || head >= disp->head.nr) return -ENXIO; if (mask) { - list_for_each_entry(temp, &priv->base.outp, head) { + list_for_each_entry(temp, &disp->base.outp, head) { if ((temp->info.hasht == type) && (temp->info.hashm & mask) == mask) { outp = temp; @@ -1030,26 +1030,26 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) switch (mthd) { case NV50_DISP_SCANOUTPOS: - return impl->head.scanoutpos(object, priv, data, size, head); + return impl->head.scanoutpos(object, disp, data, size, head); default: break; } switch (mthd * !!outp) { case NV50_DISP_MTHD_V1_DAC_PWR: - return priv->dac.power(object, priv, data, size, head, outp); + return disp->dac.power(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_DAC_LOAD: - return priv->dac.sense(object, priv, data, size, head, outp); + return disp->dac.sense(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_PWR: - return priv->sor.power(object, priv, data, size, head, outp); + return disp->sor.power(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_HDA_ELD: - if (!priv->sor.hda_eld) + if (!disp->sor.hda_eld) return -ENODEV; - return priv->sor.hda_eld(object, priv, data, size, head, outp); + return disp->sor.hda_eld(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: - if (!priv->sor.hdmi) + if (!disp->sor.hdmi) return -ENODEV; - return priv->sor.hdmi(object, priv, data, size, head, outp); + return disp->sor.hdmi(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { union { struct nv50_disp_sor_lvds_script_v0 v0; @@ -1059,7 +1059,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) nv_ioctl(object, "disp sor lvds script " "vers %d name %04x\n", args->v0.version, args->v0.script); - priv->sor.lvdsconf = args->v0.script; + disp->sor.lvdsconf = args->v0.script; return 0; } else return ret; @@ -1090,9 +1090,9 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) } break; case NV50_DISP_MTHD_V1_PIOR_PWR: - if (!priv->pior.power) + if (!disp->pior.power) return -ENODEV; - return priv->pior.power(object, priv, data, size, head, outp); + return disp->pior.power(object, disp, data, size, head, outp); default: break; } @@ -1106,12 +1106,12 @@ nv50_disp_main_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv = (void *)engine; + struct nv50_disp *disp = (void *)engine; struct nv50_disp_base *base; int ret; ret = nvkm_parent_create(parent, engine, oclass, 0, - priv->sclass, 0, &base); + disp->sclass, 0, &base); *pobject = nv_object(base); if (ret) return ret; @@ -1131,7 +1131,7 @@ nv50_disp_main_dtor(struct nvkm_object *object) static int nv50_disp_main_init(struct nvkm_object *object) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; int ret, i; u32 tmp; @@ -1144,67 +1144,67 @@ nv50_disp_main_init(struct nvkm_object *object) * another appear to inform EVO of the display capabilities or * something similar. NFI what the 0x614004 caps are for.. */ - tmp = nv_rd32(priv, 0x614004); - nv_wr32(priv, 0x610184, tmp); + tmp = nv_rd32(disp, 0x614004); + nv_wr32(disp, 0x610184, tmp); /* ... CRTC caps */ - for (i = 0; i < priv->head.nr; i++) { - tmp = nv_rd32(priv, 0x616100 + (i * 0x800)); - nv_wr32(priv, 0x610190 + (i * 0x10), tmp); - tmp = nv_rd32(priv, 0x616104 + (i * 0x800)); - nv_wr32(priv, 0x610194 + (i * 0x10), tmp); - tmp = nv_rd32(priv, 0x616108 + (i * 0x800)); - nv_wr32(priv, 0x610198 + (i * 0x10), tmp); - tmp = nv_rd32(priv, 0x61610c + (i * 0x800)); - nv_wr32(priv, 0x61019c + (i * 0x10), tmp); + for (i = 0; i < disp->head.nr; i++) { + tmp = nv_rd32(disp, 0x616100 + (i * 0x800)); + nv_wr32(disp, 0x610190 + (i * 0x10), tmp); + tmp = nv_rd32(disp, 0x616104 + (i * 0x800)); + nv_wr32(disp, 0x610194 + (i * 0x10), tmp); + tmp = nv_rd32(disp, 0x616108 + (i * 0x800)); + nv_wr32(disp, 0x610198 + (i * 0x10), tmp); + tmp = nv_rd32(disp, 0x61610c + (i * 0x800)); + nv_wr32(disp, 0x61019c + (i * 0x10), tmp); } /* ... DAC caps */ - for (i = 0; i < priv->dac.nr; i++) { - tmp = nv_rd32(priv, 0x61a000 + (i * 0x800)); - nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp); + for (i = 0; i < disp->dac.nr; i++) { + tmp = nv_rd32(disp, 0x61a000 + (i * 0x800)); + nv_wr32(disp, 0x6101d0 + (i * 0x04), tmp); } /* ... SOR caps */ - for (i = 0; i < priv->sor.nr; i++) { - tmp = nv_rd32(priv, 0x61c000 + (i * 0x800)); - nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp); + for (i = 0; i < disp->sor.nr; i++) { + tmp = nv_rd32(disp, 0x61c000 + (i * 0x800)); + nv_wr32(disp, 0x6101e0 + (i * 0x04), tmp); } /* ... PIOR caps */ - for (i = 0; i < priv->pior.nr; i++) { - tmp = nv_rd32(priv, 0x61e000 + (i * 0x800)); - nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp); + for (i = 0; i < disp->pior.nr; i++) { + tmp = nv_rd32(disp, 0x61e000 + (i * 0x800)); + nv_wr32(disp, 0x6101f0 + (i * 0x04), tmp); } /* steal display away from vbios, or something like that */ - if (nv_rd32(priv, 0x610024) & 0x00000100) { - nv_wr32(priv, 0x610024, 0x00000100); - nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000); - if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) { - nv_error(priv, "timeout acquiring display\n"); + if (nv_rd32(disp, 0x610024) & 0x00000100) { + nv_wr32(disp, 0x610024, 0x00000100); + nv_mask(disp, 0x6194e8, 0x00000001, 0x00000000); + if (!nv_wait(disp, 0x6194e8, 0x00000002, 0x00000000)) { + nv_error(disp, "timeout acquiring display\n"); return -EBUSY; } } /* point at display engine memory area (hash table, objects) */ - nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); + nv_wr32(disp, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ - nv_wr32(priv, 0x61002c, 0x00000370); - nv_wr32(priv, 0x610028, 0x00000000); + nv_wr32(disp, 0x61002c, 0x00000370); + nv_wr32(disp, 0x610028, 0x00000000); return 0; } static int nv50_disp_main_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; /* disable all interrupts */ - nv_wr32(priv, 0x610024, 0x00000000); - nv_wr32(priv, 0x610020, 0x00000000); + nv_wr32(disp, 0x610024, 0x00000000); + nv_wr32(disp, 0x610020, 0x00000000); return nvkm_parent_fini(&base->base, suspend); } @@ -1246,7 +1246,7 @@ nv50_disp_data_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv = (void *)engine; + struct nv50_disp *disp = (void *)engine; struct nvkm_engctx *ectx; int ret = -EBUSY; @@ -1258,13 +1258,13 @@ nv50_disp_data_ctor(struct nvkm_object *parent, } /* allocate display hardware to client */ - mutex_lock(&nv_subdev(priv)->mutex); - if (list_empty(&nv_engine(priv)->contexts)) { + mutex_lock(&nv_subdev(disp)->mutex); + if (list_empty(&nv_engine(disp)->contexts)) { ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x10000, NVOBJ_FLAG_HEAP, &ectx); *pobject = nv_object(ectx); } - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_unlock(&nv_subdev(disp)->mutex); return ret; } @@ -1322,11 +1322,11 @@ nv50_disp_intr_error_code[] = { }; static void -nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) +nv50_disp_intr_error(struct nv50_disp *disp, int chid) { - struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08)); - u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08)); + struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; + u32 data = nv_rd32(disp, 0x610084 + (chid * 0x08)); + u32 addr = nv_rd32(disp, 0x610080 + (chid * 0x08)); u32 code = (addr & 0x00ff0000) >> 16; u32 type = (addr & 0x00007000) >> 12; u32 mthd = (addr & 0x00000ffc); @@ -1341,14 +1341,14 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) if (!ec) snprintf(ecunk, sizeof(ecunk), "UNK%02X", code); - nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n", + nv_error(disp, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n", et ? et->name : etunk, ec ? ec->name : ecunk, chid, mthd, data); if (chid == 0) { switch (mthd) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0, + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 0, impl->mthd.core); break; default: @@ -1358,7 +1358,7 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) if (chid <= 2) { switch (mthd) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1, + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 1, impl->mthd.base); break; default: @@ -1368,7 +1368,7 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) if (chid <= 4) { switch (mthd) { case 0x0080: - nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3, + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 3, impl->mthd.ovly); break; default: @@ -1376,16 +1376,16 @@ nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid) } } - nv_wr32(priv, 0x610020, 0x00010000 << chid); - nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000); + nv_wr32(disp, 0x610020, 0x00010000 << chid); + nv_wr32(disp, 0x610080 + (chid * 0x08), 0x90000000); } static struct nvkm_output * -exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, +exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); struct nvkm_output *outp; u16 mask, type; @@ -1402,7 +1402,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; default: - nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl); + nv_error(disp, "unknown SOR mc 0x%08x\n", ctrl); return NULL; } or -= 4; @@ -1411,9 +1411,9 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, type = 0x0010; mask = 0; switch (ctrl & 0x00000f00) { - case 0x00000000: type |= priv->pior.type[or]; break; + case 0x00000000: type |= disp->pior.type[or]; break; default: - nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl); + nv_error(disp, "unknown PIOR mc 0x%08x\n", ctrl); return NULL; } } @@ -1422,7 +1422,7 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, mask |= 0x0001 << or; mask |= 0x0100 << head; - list_for_each_entry(outp, &priv->base.outp, head) { + list_for_each_entry(outp, &disp->base.outp, head) { if ((outp->info.hasht & 0xff) == type && (outp->info.hashm & mask) == mask) { *data = nvbios_outp_match(bios, outp->info.hasht, @@ -1438,9 +1438,9 @@ exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl, } static struct nvkm_output * -exec_script(struct nv50_disp_priv *priv, int head, int id) +exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); struct nvkm_output *outp; struct nvbios_outp info; u8 ver, hdr, cnt, len; @@ -1449,27 +1449,27 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) int i; /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) - ctrl = nv_rd32(priv, 0x610b5c + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) + ctrl = nv_rd32(disp, 0x610b5c + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { - if (nv_device(priv)->chipset < 0x90 || - nv_device(priv)->chipset == 0x92 || - nv_device(priv)->chipset == 0xa0) { + if (nv_device(disp)->chipset < 0x90 || + nv_device(disp)->chipset == 0x92 || + nv_device(disp)->chipset == 0xa0) { reg = 0x610b74; } else { reg = 0x610798; } - for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) - ctrl = nv_rd32(priv, reg + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) + ctrl = nv_rd32(disp, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) - ctrl = nv_rd32(priv, 0x610b84 + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) + ctrl = nv_rd32(disp, 0x610b84 + (i * 8)); i += 8; } @@ -1477,10 +1477,10 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) return NULL; i--; - outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); if (outp) { struct nvbios_init init = { - .subdev = nv_subdev(priv), + .subdev = nv_subdev(disp), .bios = bios, .offset = info.script[id], .outp = &outp->info, @@ -1495,9 +1495,9 @@ exec_script(struct nv50_disp_priv *priv, int head, int id) } static struct nvkm_output * -exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) +exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; @@ -1507,27 +1507,27 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) int i; /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++) - ctrl = nv_rd32(priv, 0x610b58 + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) + ctrl = nv_rd32(disp, 0x610b58 + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { - if (nv_device(priv)->chipset < 0x90 || - nv_device(priv)->chipset == 0x92 || - nv_device(priv)->chipset == 0xa0) { + if (nv_device(disp)->chipset < 0x90 || + nv_device(disp)->chipset == 0x92 || + nv_device(disp)->chipset == 0xa0) { reg = 0x610b70; } else { reg = 0x610794; } - for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++) - ctrl = nv_rd32(priv, reg + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) + ctrl = nv_rd32(disp, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++) - ctrl = nv_rd32(priv, 0x610b80 + (i * 8)); + for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) + ctrl = nv_rd32(disp, 0x610b80 + (i * 8)); i += 8; } @@ -1535,7 +1535,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) return NULL; i--; - outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); if (!outp) return NULL; @@ -1547,7 +1547,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) *conf |= 0x0100; break; case DCB_OUTPUT_LVDS: - *conf = priv->sor.lvdsconf; + *conf = disp->sor.lvdsconf; break; case DCB_OUTPUT_DP: *conf = (ctrl & 0x00000f00) >> 8; @@ -1567,7 +1567,7 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { - .subdev = nv_subdev(priv), + .subdev = nv_subdev(disp), .bios = bios, .offset = data, .outp = &outp->info, @@ -1583,15 +1583,15 @@ exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf) } static void -nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) { - exec_script(priv, head, 1); + exec_script(disp, head, 1); } static void -nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) { - struct nvkm_output *outp = exec_script(priv, head, 2); + struct nvkm_output *outp = exec_script(disp, head, 2); /* the binary driver does this outside of the supervisor handling * (after the third supervisor from a detach). we (currently?) @@ -1609,8 +1609,8 @@ nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) if (outp && outp->info.type == DCB_OUTPUT_DP) { struct nvkm_output_dp *outpdp = (void *)outp; struct nvbios_init init = { - .subdev = nv_subdev(priv), - .bios = nvkm_bios(priv), + .subdev = nv_subdev(disp), + .bios = nvkm_bios(disp), .outp = &outp->info, .crtc = head, .offset = outpdp->info.script[4], @@ -1623,29 +1623,29 @@ nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head) } static void -nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) { - struct nvkm_devinit *devinit = nvkm_devinit(priv); - u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; + struct nvkm_devinit *devinit = nvkm_devinit(disp); + u32 pclk = nv_rd32(disp, 0x610ad0 + (head * 0x540)) & 0x3fffff; if (pclk) devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); } static void -nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, +nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, struct dcb_output *outp, u32 pclk) { const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 soff = ( or * 0x800); const u32 loff = (link * 0x080) + soff; - const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8)); + const u32 ctrl = nv_rd32(disp, 0x610794 + (or * 8)); const u32 symbol = 100000; - const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff; - const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff; - const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff; - u32 dpctrl = nv_rd32(priv, 0x61c10c + loff); - u32 clksor = nv_rd32(priv, 0x614300 + soff); + const s32 vactive = nv_rd32(disp, 0x610af8 + (head * 0x540)) & 0xffff; + const s32 vblanke = nv_rd32(disp, 0x610ae8 + (head * 0x540)) & 0xffff; + const s32 vblanks = nv_rd32(disp, 0x610af0 + (head * 0x540)) & 0xffff; + u32 dpctrl = nv_rd32(disp, 0x61c10c + loff); + u32 clksor = nv_rd32(disp, 0x614300 + soff); int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; int TU, VTUi, VTUf, VTUa; u64 link_data_rate, link_ratio, unk; @@ -1661,14 +1661,14 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, value = value * link_bw; do_div(value, pclk); value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value); + nv_mask(disp, 0x61c1e8 + soff, 0x0000ffff, value); /* symbols/vblank - algorithm taken from comments in tegra driver */ value = vblanks - vblanke - 25; value = value * link_bw; do_div(value, pclk); value = value - ((36 / link_nr) + 3) - 1; - nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value); + nv_mask(disp, 0x61c1ec + soff, 0x00ffffff, value); /* watermark / activesym */ if ((ctrl & 0xf0000) == 0x60000) bits = 30; @@ -1733,7 +1733,7 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, } if (!bestTU) { - nv_error(priv, "unable to find suitable dp config\n"); + nv_error(disp, "unable to find suitable dp config\n"); return; } @@ -1744,22 +1744,22 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head, do_div(unk, symbol); unk += 6; - nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2); - nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | + nv_mask(disp, 0x61c10c + loff, 0x000001fc, bestTU << 2); + nv_mask(disp, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | bestVTUf << 16 | bestVTUi << 8 | unk); } static void -nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) { struct nvkm_output *outp; - u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; + u32 pclk = nv_rd32(disp, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 hval, hreg = 0x614200 + (head * 0x800); u32 oval, oreg; u32 mask, conf; - outp = exec_clkcmp(priv, head, 0xff, pclk, &conf); + outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); if (!outp) return; @@ -1786,10 +1786,10 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) u32 ctrl, datarate; if (outp->info.location == 0) { - ctrl = nv_rd32(priv, 0x610794 + soff); + ctrl = nv_rd32(disp, 0x610794 + soff); soff = 1; } else { - ctrl = nv_rd32(priv, 0x610b80 + soff); + ctrl = nv_rd32(disp, 0x610b80 + soff); soff = 2; } @@ -1806,7 +1806,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) ERR("link not trained before attach\n"); } - exec_clkcmp(priv, head, 0, pclk, &conf); + exec_clkcmp(disp, head, 0, pclk, &conf); if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) { oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800; @@ -1816,7 +1816,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) } else if (!outp->info.location) { if (outp->info.type == DCB_OUTPUT_DP) - nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk); + nv50_disp_intr_unk20_2_dp(disp, head, &outp->info, pclk); oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800; oval = (conf & 0x0100) ? 0x00000101 : 0x00000000; hval = 0x00000000; @@ -1828,8 +1828,8 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) mask = 0x00000707; } - nv_mask(priv, hreg, 0x0000000f, hval); - nv_mask(priv, oreg, mask, oval); + nv_mask(disp, hreg, 0x0000000f, hval); + nv_mask(disp, oreg, mask, oval); } /* If programming a TMDS output on a SOR that can also be configured for @@ -1841,10 +1841,10 @@ nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head) * programmed for DisplayPort. */ static void -nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, +nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, struct dcb_output *outp) { - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(disp); const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 loff = (or * 0x800) + (link * 0x80); @@ -1853,109 +1853,106 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, u8 ver, hdr; if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) - nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000); + nv_mask(disp, 0x61c10c + loff, 0x00000001, 0x00000000); } static void -nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head) +nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) { struct nvkm_output *outp; - u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff; + u32 pclk = nv_rd32(disp, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 conf; - outp = exec_clkcmp(priv, head, 1, pclk, &conf); + outp = exec_clkcmp(disp, head, 1, pclk, &conf); if (!outp) return; if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS) - nv50_disp_intr_unk40_0_tmds(priv, &outp->info); + nv50_disp_intr_unk40_0_tmds(disp, &outp->info); } void nv50_disp_intr_supervisor(struct work_struct *work) { - struct nv50_disp_priv *priv = - container_of(work, struct nv50_disp_priv, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass; - u32 super = nv_rd32(priv, 0x610030); + struct nv50_disp *disp = + container_of(work, struct nv50_disp, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; + u32 super = nv_rd32(disp, 0x610030); int head; - nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super); + nv_debug(disp, "supervisor 0x%08x 0x%08x\n", disp->super, super); - if (priv->super & 0x00000010) { - nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core); - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000010) { + nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); + for (head = 0; head < disp->head.nr; head++) { if (!(super & (0x00000020 << head))) continue; if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk10_0(priv, head); + nv50_disp_intr_unk10_0(disp, head); } } else - if (priv->super & 0x00000020) { - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000020) { + for (head = 0; head < disp->head.nr; head++) { if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk20_0(priv, head); + nv50_disp_intr_unk20_0(disp, head); } - for (head = 0; head < priv->head.nr; head++) { + for (head = 0; head < disp->head.nr; head++) { if (!(super & (0x00000200 << head))) continue; - nv50_disp_intr_unk20_1(priv, head); + nv50_disp_intr_unk20_1(disp, head); } - for (head = 0; head < priv->head.nr; head++) { + for (head = 0; head < disp->head.nr; head++) { if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk20_2(priv, head); + nv50_disp_intr_unk20_2(disp, head); } } else - if (priv->super & 0x00000040) { - for (head = 0; head < priv->head.nr; head++) { + if (disp->super & 0x00000040) { + for (head = 0; head < disp->head.nr; head++) { if (!(super & (0x00000080 << head))) continue; - nv50_disp_intr_unk40_0(priv, head); + nv50_disp_intr_unk40_0(disp, head); } } - nv_wr32(priv, 0x610030, 0x80000000); + nv_wr32(disp, 0x610030, 0x80000000); } void nv50_disp_intr(struct nvkm_subdev *subdev) { - struct nv50_disp_priv *priv = (void *)subdev; - u32 intr0 = nv_rd32(priv, 0x610020); - u32 intr1 = nv_rd32(priv, 0x610024); + struct nv50_disp *disp = (void *)subdev; + u32 intr0 = nv_rd32(disp, 0x610020); + u32 intr1 = nv_rd32(disp, 0x610024); while (intr0 & 0x001f0000) { u32 chid = __ffs(intr0 & 0x001f0000) - 16; - nv50_disp_intr_error(priv, chid); + nv50_disp_intr_error(disp, chid); intr0 &= ~(0x00010000 << chid); } while (intr0 & 0x0000001f) { u32 chid = __ffs(intr0 & 0x0000001f); - nv50_disp_chan_uevent_send(priv, chid); + nv50_disp_chan_uevent_send(disp, chid); intr0 &= ~(0x00000001 << chid); } if (intr1 & 0x00000004) { - nvkm_disp_vblank(&priv->base, 0); - nv_wr32(priv, 0x610024, 0x00000004); - intr1 &= ~0x00000004; + nvkm_disp_vblank(&disp->base, 0); + nv_wr32(disp, 0x610024, 0x00000004); } if (intr1 & 0x00000008) { - nvkm_disp_vblank(&priv->base, 1); - nv_wr32(priv, 0x610024, 0x00000008); - intr1 &= ~0x00000008; + nvkm_disp_vblank(&disp->base, 1); + nv_wr32(disp, 0x610024, 0x00000008); } if (intr1 & 0x00000070) { - priv->super = (intr1 & 0x00000070); - schedule_work(&priv->supervisor); - nv_wr32(priv, 0x610024, priv->super); - intr1 &= ~0x00000070; + disp->super = (intr1 & 0x00000070); + schedule_work(&disp->supervisor); + nv_wr32(disp, 0x610024, disp->super); } } @@ -1964,32 +1961,32 @@ nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_priv *priv; + struct nv50_disp *disp; int ret; ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &priv); - *pobject = nv_object(priv); + "display", &disp); + *pobject = nv_object(disp); if (ret) return ret; - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent); + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(priv)->sclass = nv50_disp_main_oclass; - nv_engine(priv)->cclass = &nv50_disp_cclass; - nv_subdev(priv)->intr = nv50_disp_intr; - INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor); - priv->sclass = nv50_disp_sclass; - priv->head.nr = 2; - priv->dac.nr = 3; - priv->sor.nr = 2; - priv->pior.nr = 3; - priv->dac.power = nv50_dac_power; - priv->dac.sense = nv50_dac_sense; - priv->sor.power = nv50_sor_power; - priv->pior.power = nv50_pior_power; + nv_engine(disp)->sclass = nv50_disp_main_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = nv50_disp_intr; + INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); + disp->sclass = nv50_disp_sclass; + disp->head.nr = 2; + disp->dac.nr = 3; + disp->sor.nr = 2; + disp->pior.nr = 3; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->pior.power = nv50_pior_power; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index b9dfa660e7dd0..24d3413defbdd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -5,11 +5,11 @@ struct nvkm_output; struct nvkm_output_dp; #define NV50_DISP_MTHD_ struct nvkm_object *object, \ - struct nv50_disp_priv *priv, void *data, u32 size + struct nv50_disp *disp, void *data, u32 size #define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head #define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp -struct nv50_disp_priv { +struct nv50_disp { struct nvkm_disp base; struct nvkm_oclass *sclass; @@ -102,7 +102,7 @@ void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32); extern const struct nvkm_event_func nv50_disp_chan_uevent; int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32, struct nvkm_notify *); -void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int); +void nv50_disp_chan_uevent_send(struct nv50_disp *, int); extern const struct nvkm_event_func gf110_disp_chan_uevent; @@ -177,7 +177,7 @@ int nv50_disp_main_ctor(struct nvkm_object *, struct nvkm_object *, void nv50_disp_main_dtor(struct nvkm_object *); extern struct nvkm_omthds nv50_disp_main_omthds[]; extern struct nvkm_oclass nv50_disp_cclass; -void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head, +void nv50_disp_mthd_chan(struct nv50_disp *, int debug, int head, const struct nv50_disp_mthd_chan *); void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr(struct nvkm_subdev *); @@ -214,7 +214,7 @@ extern struct nvkm_output_dp_impl nv50_pior_dp_impl; extern struct nvkm_oclass *nv50_disp_outp_sclass[]; extern struct nvkm_output_dp_impl g94_sor_dp_impl; -u32 g94_sor_dp_lane_map(struct nv50_disp_priv *, u8 lane); +u32 g94_sor_dp_lane_map(struct nv50_disp *, u8 lane); int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); extern struct nvkm_oclass *g94_disp_outp_sclass[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 2a1d8871bf82e..94f0b4d2c890e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -162,9 +162,9 @@ nv50_pior_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000); - priv->pior.type[outp->or] = type; + nv_wait(disp, 0x61e004 + soff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); + nv_wait(disp, 0x61e004 + soff, 0x80000000, 0x00000000); + disp->pior.type[outp->or] = type; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index 0b4ecb8375976..b4138acc94de5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -39,14 +39,14 @@ g94_sor_loff(struct nvkm_output_dp *outp) } u32 -g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) +g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) { static const u8 gm100[] = { 0, 8, 16, 24 }; static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ static const u8 g94[] = { 16, 8, 0, 24 }; - if (nv_device(priv)->chipset >= 0x110) + if (nv_device(disp)->chipset >= 0x110) return gm100[lane]; - if (nv_device(priv)->chipset == 0xaf) + if (nv_device(disp)->chipset == 0xaf) return mcp89[lane]; return g94[lane]; } @@ -54,33 +54,33 @@ g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) static int g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 loff = g94_sor_loff(outp); - nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24); + nv_mask(disp, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; } int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (g94_sor_dp_lane_map(priv, i) >> 3); + mask |= 1 << (g94_sor_dp_lane_map(disp, i) >> 3); - nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask); - nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000); - nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61c130 + loff, 0x0000000f, mask); + nv_mask(disp, 0x61c034 + soff, 0x80000000, 0x80000000); + nv_wait(disp, 0x61c034 + soff, 0x80000000, 0x00000000); return 0; } static int g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -92,17 +92,17 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) if (bw > 0x06) clksor |= 0x00040000; - nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor); - nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); + nv_mask(disp, 0x614300 + soff, 0x000c0000, clksor); + nv_mask(disp, 0x61c10c + loff, 0x001f4000, dpctrl); return 0; } static int g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = g94_sor_dp_lane_map(priv, ln); + struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_bios *bios = nvkm_bios(disp); + const u32 shift = g94_sor_dp_lane_map(disp, ln); const u32 loff = g94_sor_loff(outp); u32 addr, data[3]; u8 ver, hdr, cnt, len; @@ -120,14 +120,14 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) if (!addr) return -EINVAL; - data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(priv, 0x61c130 + loff); + data[0] = nv_rd32(disp, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nv_rd32(disp, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nv_rd32(disp, 0x61c130 + loff); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2]); + nv_wr32(disp, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nv_wr32(disp, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nv_wr32(disp, 0x61c130 + loff, data[2]); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c index 1f02b603e19a6..07dbe45996c7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c @@ -39,16 +39,16 @@ gf110_sor_loff(struct nvkm_output_dp *outp) static int gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 loff = gf110_sor_loff(outp); - nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); + nv_mask(disp, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 soff = gf110_sor_soff(outp); const u32 loff = gf110_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -59,8 +59,8 @@ gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) if (ef) dpctrl |= 0x00004000; - nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor); - nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl); + nv_mask(disp, 0x612300 + soff, 0x007c0000, clksor); + nv_mask(disp, 0x61c10c + loff, 0x001f4000, dpctrl); return 0; } @@ -68,9 +68,9 @@ static int gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = g94_sor_dp_lane_map(priv, ln); + struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_bios *bios = nvkm_bios(disp); + const u32 shift = g94_sor_dp_lane_map(disp, ln); const u32 loff = gf110_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -88,16 +88,16 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, if (!addr) return -EINVAL; - data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(priv, 0x61c130 + loff); + data[0] = nv_rd32(disp, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nv_rd32(disp, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nv_rd32(disp, 0x61c130 + loff); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2]); - data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); - nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); + nv_wr32(disp, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nv_wr32(disp, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nv_wr32(disp, 0x61c130 + loff, data[2]); + data[3] = nv_rd32(disp, 0x61c13c + loff) & ~(0x000000ff << shift); + nv_wr32(disp, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index a2706e24f5c1d..3078f4d91972b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -41,17 +41,17 @@ gm204_sor_loff(struct nvkm_output_dp *outp) void gm204_sor_magic(struct nvkm_output *outp) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 soff = outp->or * 0x100; const u32 data = outp->or + 1; if (outp->info.sorconf.link & 1) - nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data); + nv_mask(disp, 0x612308 + soff, 0x0000001f, 0x00000000 | data); if (outp->info.sorconf.link & 2) - nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data); + nv_mask(disp, 0x612388 + soff, 0x0000001f, 0x00000010 | data); } static inline u32 -gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) +gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) { return lane * 0x08; } @@ -59,30 +59,30 @@ gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane) static int gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 soff = gm204_sor_soff(outp); const u32 data = 0x01010101 * pattern; if (outp->base.info.sorconf.link & 1) - nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data); + nv_mask(disp, 0x61c110 + soff, 0x0f0f0f0f, data); else - nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data); + nv_mask(disp, 0x61c12c + soff, 0x0f0f0f0f, data); return 0; } static int gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)nvkm_disp(outp); const u32 soff = gm204_sor_soff(outp); const u32 loff = gm204_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3); + mask |= 1 << (gm204_sor_dp_lane_map(disp, i) >> 3); - nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask); - nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000); - nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61c130 + loff, 0x0000000f, mask); + nv_mask(disp, 0x61c034 + soff, 0x80000000, 0x80000000); + nv_wait(disp, 0x61c034 + soff, 0x80000000, 0x00000000); return 0; } @@ -90,9 +90,9 @@ static int gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp_priv *priv = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(priv); - const u32 shift = gm204_sor_dp_lane_map(priv, ln); + struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_bios *bios = nvkm_bios(disp); + const u32 shift = gm204_sor_dp_lane_map(disp, ln); const u32 loff = gm204_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -111,16 +111,16 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return -EINVAL; ocfg.tx_pu &= 0x0f; - data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(priv, 0x61c130 + loff); + data[0] = nv_rd32(disp, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nv_rd32(disp, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nv_rd32(disp, 0x61c130 + loff); if ((data[2] & 0x00000f00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x00000f00) | (ocfg.tx_pu << 8); - nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(priv, 0x61c130 + loff, data[2]); - data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift); - nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); + nv_wr32(disp, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nv_wr32(disp, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nv_wr32(disp, 0x61c130 + loff, data[2]); + data[3] = nv_rd32(disp, 0x61c13c + loff) & ~(0x000000ff << shift); + nv_wr32(disp, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index b229a311c78ce..74ad5921b230c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -48,9 +48,9 @@ nv50_sor_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); - nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); - nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000); - nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000); + nv_wait(disp, 0x61c004 + soff, 0x80000000, 0x00000000); + nv_mask(disp, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); + nv_wait(disp, 0x61c004 + soff, 0x80000000, 0x00000000); + nv_wait(disp, 0x61c030 + soff, 0x10000000, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 14d9650f47790..0946280a54b01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -156,7 +156,7 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_disp *pdisp = nvkm_disp(parent); + struct nvkm_disp *disp = nvkm_disp(parent); struct nv50_sw_cclass *pclass = (void *)oclass; struct nv50_sw_chan *chan; int ret, i; @@ -166,8 +166,8 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) { - ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank, + for (i = 0; disp && i < disp->vblank.index_nr; i++) { + ret = nvkm_notify_init(NULL, &disp->vblank, pclass->vblank, false, &(struct nvif_notify_head_req_v0) { .head = i, -- GitLab From a317aa21be51f869d5ab0198fad94a4570af9ddb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5347/7006] drm/nouveau/dma: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/dmaobj.h | 2 +- .../drm/nouveau/nvkm/engine/dmaobj/gf100.c | 48 ++++++++-------- .../drm/nouveau/nvkm/engine/dmaobj/gf110.c | 28 +++++----- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c | 56 +++++++++---------- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c | 48 ++++++++-------- 5 files changed, 91 insertions(+), 91 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h index c4fce8afcf831..2c3cc61adb74b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h @@ -12,7 +12,7 @@ struct nvkm_dmaobj { }; struct nvkm_dmaeng { - struct nvkm_engine base; + struct nvkm_engine engine; /* creates a "physical" dma object from a struct nvkm_dmaobj */ int (*bind)(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c index f880e5167e458..db7978ac6acbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c @@ -30,17 +30,17 @@ #include #include -struct gf100_dmaobj_priv { +struct gf100_dmaobj { struct nvkm_dmaobj base; u32 flags0; u32 flags5; }; static int -gf100_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, +gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, struct nvkm_gpuobj **pgpuobj) { - struct gf100_dmaobj_priv *priv = (void *)dmaobj; + struct gf100_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { @@ -57,13 +57,13 @@ gf100_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj)); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 | - upper_32_bits(priv->base.start)); + nv_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); + nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); + nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); + nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | + upper_32_bits(dmaobj->base.start)); nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, priv->flags5); + nv_wo32(*pgpuobj, 0x14, dmaobj->flags5); } return ret; @@ -78,12 +78,12 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct gf100_dma_v0 v0; } *args; - struct gf100_dmaobj_priv *priv; + struct gf100_dmaobj *dmaobj; u32 kind, user, unkn; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); + *pobject = nv_object(dmaobj); if (ret) return ret; args = data; @@ -97,7 +97,7 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, unkn = 0; } else if (size == 0) { - if (priv->base.target != NV_MEM_TARGET_VM) { + if (dmaobj->base.target != NV_MEM_TARGET_VM) { kind = GF100_DMA_V0_KIND_PITCH; user = GF100_DMA_V0_PRIV_US; unkn = 2; @@ -111,39 +111,39 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (user > 2) return -EINVAL; - priv->flags0 |= (kind << 22) | (user << 20); - priv->flags5 |= (unkn << 16); + dmaobj->flags0 |= (kind << 22) | (user << 20); + dmaobj->flags5 |= (unkn << 16); - switch (priv->base.target) { + switch (dmaobj->base.target) { case NV_MEM_TARGET_VM: - priv->flags0 |= 0x00000000; + dmaobj->flags0 |= 0x00000000; break; case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00010000; + dmaobj->flags0 |= 0x00010000; break; case NV_MEM_TARGET_PCI: - priv->flags0 |= 0x00020000; + dmaobj->flags0 |= 0x00020000; break; case NV_MEM_TARGET_PCI_NOSNOOP: - priv->flags0 |= 0x00030000; + dmaobj->flags0 |= 0x00030000; break; default: return -EINVAL; } - switch (priv->base.access) { + switch (dmaobj->base.access) { case NV_MEM_ACCESS_VM: break; case NV_MEM_ACCESS_RO: - priv->flags0 |= 0x00040000; + dmaobj->flags0 |= 0x00040000; break; case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_RW: - priv->flags0 |= 0x00080000; + dmaobj->flags0 |= 0x00080000; break; } - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); + return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c index bf8f0f20976c0..76063249853c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c @@ -30,16 +30,16 @@ #include #include -struct gf110_dmaobj_priv { +struct gf110_dmaobj { struct nvkm_dmaobj base; u32 flags0; }; static int -gf110_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, +gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, struct nvkm_gpuobj **pgpuobj) { - struct gf110_dmaobj_priv *priv = (void *)dmaobj; + struct gf110_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { @@ -63,9 +63,9 @@ gf110_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0); - nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8); - nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8); + nv_wo32(*pgpuobj, 0x00, dmaobj->flags0); + nv_wo32(*pgpuobj, 0x04, dmaobj->base.start >> 8); + nv_wo32(*pgpuobj, 0x08, dmaobj->base.limit >> 8); nv_wo32(*pgpuobj, 0x0c, 0x00000000); nv_wo32(*pgpuobj, 0x10, 0x00000000); nv_wo32(*pgpuobj, 0x14, 0x00000000); @@ -83,12 +83,12 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct gf110_dma_v0 v0; } *args; - struct gf110_dmaobj_priv *priv; + struct gf110_dmaobj *dmaobj; u32 kind, page; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); + *pobject = nv_object(dmaobj); if (ret) return ret; args = data; @@ -101,7 +101,7 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, page = args->v0.page; } else if (size == 0) { - if (priv->base.target != NV_MEM_TARGET_VM) { + if (dmaobj->base.target != NV_MEM_TARGET_VM) { kind = GF110_DMA_V0_KIND_PITCH; page = GF110_DMA_V0_PAGE_SP; } else { @@ -113,11 +113,11 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (page > 1) return -EINVAL; - priv->flags0 = (kind << 20) | (page << 6); + dmaobj->flags0 = (kind << 20) | (page << 6); - switch (priv->base.target) { + switch (dmaobj->base.target) { case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00000009; + dmaobj->flags0 |= 0x00000009; break; case NV_MEM_TARGET_VM: case NV_MEM_TARGET_PCI: @@ -132,7 +132,7 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); + return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c index a6bfd0894f58b..21c5c90b06a8b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c @@ -29,7 +29,7 @@ #include -struct nv04_dmaobj_priv { +struct nv04_dmaobj { struct nvkm_dmaobj base; bool clone; u32 flags0; @@ -37,14 +37,14 @@ struct nv04_dmaobj_priv { }; static int -nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, +nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, struct nvkm_gpuobj **pgpuobj) { - struct nv04_dmaobj_priv *priv = (void *)dmaobj; + struct nv04_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); struct nvkm_gpuobj *gpuobj; - u64 offset = priv->base.start & 0xfffff000; - u64 adjust = priv->base.start & 0x00000fff; - u32 length = priv->base.limit - priv->base.start; + u64 offset = dmaobj->base.start & 0xfffff000; + u64 adjust = dmaobj->base.start & 0x00000fff; + u32 length = dmaobj->base.limit - dmaobj->base.start; int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { @@ -59,10 +59,10 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, } } - if (priv->clone) { + if (dmaobj->clone) { struct nv04_mmu *mmu = nv04_mmu(dmaobj); struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0]; - if (!dmaobj->start) + if (!dmaobj->base.start) return nvkm_gpuobj_dup(parent, pgt, pgpuobj); offset = nv_ro32(pgt, 8 + (offset >> 10)); offset &= 0xfffff000; @@ -71,10 +71,10 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); *pgpuobj = gpuobj; if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20)); + nv_wo32(*pgpuobj, 0x00, dmaobj->flags0 | (adjust << 20)); nv_wo32(*pgpuobj, 0x04, length); - nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset); - nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset); + nv_wo32(*pgpuobj, 0x08, dmaobj->flags2 | offset); + nv_wo32(*pgpuobj, 0x0c, dmaobj->flags2 | offset); } return ret; @@ -87,50 +87,50 @@ nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_dmaeng *dmaeng = (void *)engine; struct nv04_mmu *mmu = nv04_mmu(engine); - struct nv04_dmaobj_priv *priv; + struct nv04_dmaobj *dmaobj; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); + *pobject = nv_object(dmaobj); if (ret || (ret = -ENOSYS, size)) return ret; - if (priv->base.target == NV_MEM_TARGET_VM) { + if (dmaobj->base.target == NV_MEM_TARGET_VM) { if (nv_object(mmu)->oclass == &nv04_mmu_oclass) - priv->clone = true; - priv->base.target = NV_MEM_TARGET_PCI; - priv->base.access = NV_MEM_ACCESS_RW; + dmaobj->clone = true; + dmaobj->base.target = NV_MEM_TARGET_PCI; + dmaobj->base.access = NV_MEM_ACCESS_RW; } - priv->flags0 = nv_mclass(priv); - switch (priv->base.target) { + dmaobj->flags0 = nv_mclass(dmaobj); + switch (dmaobj->base.target) { case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00003000; + dmaobj->flags0 |= 0x00003000; break; case NV_MEM_TARGET_PCI: - priv->flags0 |= 0x00023000; + dmaobj->flags0 |= 0x00023000; break; case NV_MEM_TARGET_PCI_NOSNOOP: - priv->flags0 |= 0x00033000; + dmaobj->flags0 |= 0x00033000; break; default: return -EINVAL; } - switch (priv->base.access) { + switch (dmaobj->base.access) { case NV_MEM_ACCESS_RO: - priv->flags0 |= 0x00004000; + dmaobj->flags0 |= 0x00004000; break; case NV_MEM_ACCESS_WO: - priv->flags0 |= 0x00008000; + dmaobj->flags0 |= 0x00008000; case NV_MEM_ACCESS_RW: - priv->flags2 |= 0x00000002; + dmaobj->flags2 |= 0x00000002; break; default: return -EINVAL; } - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); + return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c index 4d3c828fe0e67..6aa18884184ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c @@ -30,17 +30,17 @@ #include #include -struct nv50_dmaobj_priv { +struct nv50_dmaobj { struct nvkm_dmaobj base; u32 flags0; u32 flags5; }; static int -nv50_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, +nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, struct nvkm_gpuobj **pgpuobj) { - struct nv50_dmaobj_priv *priv = (void *)dmaobj; + struct nv50_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); int ret; if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { @@ -69,13 +69,13 @@ nv50_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj)); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 | - upper_32_bits(priv->base.start)); + nv_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); + nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); + nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); + nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | + upper_32_bits(dmaobj->base.start)); nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, priv->flags5); + nv_wo32(*pgpuobj, 0x14, dmaobj->flags5); } return ret; @@ -90,12 +90,12 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_dma_v0 v0; } *args; - struct nv50_dmaobj_priv *priv; + struct nv50_dmaobj *dmaobj; u32 user, part, comp, kind; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv); - *pobject = nv_object(priv); + ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); + *pobject = nv_object(dmaobj); if (ret) return ret; args = data; @@ -112,7 +112,7 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, kind = args->v0.kind; } else if (size == 0) { - if (priv->base.target != NV_MEM_TARGET_VM) { + if (dmaobj->base.target != NV_MEM_TARGET_VM) { user = NV50_DMA_V0_PRIV_US; part = NV50_DMA_V0_PART_256; comp = NV50_DMA_V0_COMP_NONE; @@ -128,41 +128,41 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (user > 2 || part > 2 || comp > 3 || kind > 0x7f) return -EINVAL; - priv->flags0 = (comp << 29) | (kind << 22) | (user << 20); - priv->flags5 = (part << 16); + dmaobj->flags0 = (comp << 29) | (kind << 22) | (user << 20); + dmaobj->flags5 = (part << 16); - switch (priv->base.target) { + switch (dmaobj->base.target) { case NV_MEM_TARGET_VM: - priv->flags0 |= 0x00000000; + dmaobj->flags0 |= 0x00000000; break; case NV_MEM_TARGET_VRAM: - priv->flags0 |= 0x00010000; + dmaobj->flags0 |= 0x00010000; break; case NV_MEM_TARGET_PCI: - priv->flags0 |= 0x00020000; + dmaobj->flags0 |= 0x00020000; break; case NV_MEM_TARGET_PCI_NOSNOOP: - priv->flags0 |= 0x00030000; + dmaobj->flags0 |= 0x00030000; break; default: return -EINVAL; } - switch (priv->base.access) { + switch (dmaobj->base.access) { case NV_MEM_ACCESS_VM: break; case NV_MEM_ACCESS_RO: - priv->flags0 |= 0x00040000; + dmaobj->flags0 |= 0x00040000; break; case NV_MEM_ACCESS_WO: case NV_MEM_ACCESS_RW: - priv->flags0 |= 0x00080000; + dmaobj->flags0 |= 0x00080000; break; default: return -EINVAL; } - return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject); + return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); } static struct nvkm_ofuncs -- GitLab From 6189f1b0938dc0621c27494031b83ffae566e318 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:07 +1000 Subject: [PATCH 5348/7006] drm/nouveau/fifo: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/fifo.h | 6 +- drivers/gpu/drm/nouveau/nv84_fence.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 58 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 46 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 352 ++++++++-------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 394 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/fifo/gm204.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 316 +++++++------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 38 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 68 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 122 +++--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 112 ++--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 10 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 12 +- 25 files changed, 800 insertions(+), 788 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 9100b800562ef..3e77c924434b3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -68,7 +68,7 @@ struct nvkm_fifo_base { #include struct nvkm_fifo { - struct nvkm_engine base; + struct nvkm_engine engine; struct nvkm_event cevent; /* channel creation event */ struct nvkm_event uevent; /* async user trigger */ @@ -92,9 +92,9 @@ nvkm_fifo(void *obj) #define nvkm_fifo_create(o,e,c,fc,lc,d) \ nvkm_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d) #define nvkm_fifo_init(p) \ - nvkm_engine_init(&(p)->base) + nvkm_engine_init(&(p)->engine) #define nvkm_fifo_fini(p,s) \ - nvkm_engine_fini(&(p)->base, (s)) + nvkm_engine_fini(&(p)->engine, (s)) int nvkm_fifo_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int min, int max, diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index a03db4368696b..76098a58e2faf 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -213,7 +213,7 @@ nv84_fence_destroy(struct nouveau_drm *drm) int nv84_fence_create(struct nouveau_drm *drm) { - struct nvkm_fifo *pfifo = nvxx_fifo(&drm->device); + struct nvkm_fifo *fifo = nvxx_fifo(&drm->device); struct nv84_fence_priv *priv; u32 domain; int ret; @@ -228,7 +228,7 @@ nv84_fence_create(struct nouveau_drm *drm) priv->base.context_new = nv84_fence_context_new; priv->base.context_del = nv84_fence_context_del; - priv->base.contexts = pfifo->max + 1; + priv->base.contexts = fifo->max + 1; priv->base.context_base = fence_context_alloc(priv->base.contexts); priv->base.uevent = true; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 9addf43e07d43..a8fff0e13e195 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -72,7 +72,7 @@ gt215_ce_isr_error_name[] = { void gt215_ce_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_falcon *falcon = (void *)subdev; struct nvkm_object *engctx; @@ -87,7 +87,7 @@ gt215_ce_intr(struct nvkm_subdev *subdev) int chid; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat & 0x00000040) { nv_error(falcon, "DISPATCH_ERROR ["); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index c1f065d8efa4e..442c2a002c634 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -104,7 +104,7 @@ g84_cipher_intr_mask[] = { static void g84_cipher_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_engine *cipher = (void *)subdev; @@ -115,7 +115,7 @@ g84_cipher_intr(struct nvkm_subdev *subdev) int chid; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat) { nv_error(cipher, "%s", ""); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index a85014bb37a77..2b0f497d57a4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -58,7 +58,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, u64 engmask, int len, void **ptr) { struct nvkm_device *device = nv_device(engine); - struct nvkm_fifo *priv = (void *)engine; + struct nvkm_fifo *fifo = (void *)engine; struct nvkm_fifo_chan *chan; struct nvkm_dmaeng *dmaeng; unsigned long flags; @@ -90,39 +90,39 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return ret; /* find a free fifo channel */ - spin_lock_irqsave(&priv->lock, flags); - for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) { - if (!priv->channel[chan->chid]) { - priv->channel[chan->chid] = nv_object(chan); + spin_lock_irqsave(&fifo->lock, flags); + for (chan->chid = fifo->min; chan->chid < fifo->max; chan->chid++) { + if (!fifo->channel[chan->chid]) { + fifo->channel[chan->chid] = nv_object(chan); break; } } - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&fifo->lock, flags); - if (chan->chid == priv->max) { - nv_error(priv, "no free channels\n"); + if (chan->chid == fifo->max) { + nv_error(fifo, "no free channels\n"); return -ENOSPC; } chan->addr = nv_device_resource_start(device, bar) + addr + size * chan->chid; chan->size = size; - nvkm_event_send(&priv->cevent, 1, 0, NULL, 0); + nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); return 0; } void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) { - struct nvkm_fifo *priv = (void *)nv_object(chan)->engine; + struct nvkm_fifo *fifo = (void *)nv_object(chan)->engine; unsigned long flags; if (chan->user) iounmap(chan->user); - spin_lock_irqsave(&priv->lock, flags); - priv->channel[chan->chid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&fifo->lock, flags); + fifo->channel[chan->chid] = NULL; + spin_unlock_irqrestore(&fifo->lock, flags); nvkm_gpuobj_ref(NULL, &chan->pushgpu); nvkm_object_ref(NULL, (struct nvkm_object **)&chan->pushdma); @@ -214,9 +214,9 @@ _nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type, } static int -nvkm_fifo_chid(struct nvkm_fifo *priv, struct nvkm_object *object) +nvkm_fifo_chid(struct nvkm_fifo *fifo, struct nvkm_object *object) { - int engidx = nv_hclass(priv) & 0xff; + int engidx = nv_hclass(fifo) & 0xff; while (object && object->parent) { if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && @@ -243,12 +243,12 @@ nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid) } void -nvkm_fifo_destroy(struct nvkm_fifo *priv) +nvkm_fifo_destroy(struct nvkm_fifo *fifo) { - kfree(priv->channel); - nvkm_event_fini(&priv->uevent); - nvkm_event_fini(&priv->cevent); - nvkm_engine_destroy(&priv->base); + kfree(fifo->channel); + nvkm_event_fini(&fifo->uevent); + nvkm_event_fini(&fifo->cevent); + nvkm_engine_destroy(&fifo->engine); } int @@ -256,26 +256,26 @@ nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int min, int max, int length, void **pobject) { - struct nvkm_fifo *priv; + struct nvkm_fifo *fifo; int ret; ret = nvkm_engine_create_(parent, engine, oclass, true, "PFIFO", "fifo", length, pobject); - priv = *pobject; + fifo = *pobject; if (ret) return ret; - priv->min = min; - priv->max = max; - priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL); - if (!priv->channel) + fifo->min = min; + fifo->max = max; + fifo->channel = kzalloc(sizeof(*fifo->channel) * (max + 1), GFP_KERNEL); + if (!fifo->channel) return -ENOMEM; - ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &priv->cevent); + ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent); if (ret) return ret; - priv->chid = nvkm_fifo_chid; - spin_lock_init(&priv->lock); + fifo->chid = nvkm_fifo_chid; + spin_lock_init(&fifo->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index a04920b3cf84d..bff5867e24ced 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -81,7 +81,7 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_priv *priv = (void *)parent->engine; + struct nv50_fifo *fifo = (void *)parent->engine; struct nv50_fifo_base *base = (void *)parent->parent; struct nv50_fifo_chan *chan = (void *)parent; u32 addr, save, engn; @@ -103,12 +103,12 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn); - nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); - done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff); - nv_wr32(priv, 0x002520, save); + save = nv_mask(fifo, 0x002520, 0x0000003f, 1 << engn); + nv_wr32(fifo, 0x0032fc, nv_gpuobj(base)->addr >> 12); + done = nv_wait_ne(fifo, 0x0032fc, 0xffffffff, 0xffffffff); + nv_wr32(fifo, 0x002520, save); if (!done) { - nv_error(priv, "channel %d [%s] unload timeout\n", + nv_error(fifo, "channel %d [%s] unload timeout\n", chan->base.chid, nvkm_client_name(chan)); if (suspend) return -EBUSY; @@ -309,7 +309,7 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, static int g84_fifo_chan_init(struct nvkm_object *object) { - struct nv50_fifo_priv *priv = (void *)object->engine; + struct nv50_fifo *fifo = (void *)object->engine; struct nv50_fifo_base *base = (void *)object->parent; struct nv50_fifo_chan *chan = (void *)object; struct nvkm_gpuobj *ramfc = base->ramfc; @@ -320,8 +320,8 @@ g84_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); - nv50_fifo_playlist_update(priv); + nv_wr32(fifo, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); + nv50_fifo_playlist_update(fifo); return 0; } @@ -444,34 +444,34 @@ g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_fifo_priv *priv; + struct nv50_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[0]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, + &fifo->playlist[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[1]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, + &fifo->playlist[1]); if (ret) return ret; - ret = nvkm_event_init(&g84_fifo_uevent_func, 1, 1, &priv->base.uevent); + ret = nvkm_event_init(&g84_fifo_uevent_func, 1, 1, &fifo->base.uevent); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &g84_fifo_cclass; - nv_engine(priv)->sclass = g84_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &g84_fifo_cclass; + nv_engine(fifo)->sclass = g84_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index b745252f22612..0a7971a3317ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -35,7 +35,7 @@ #include #include -struct gf100_fifo_priv { +struct gf100_fifo { struct nvkm_fifo base; struct work_struct fault; @@ -74,18 +74,18 @@ struct gf100_fifo_chan { ******************************************************************************/ static void -gf100_fifo_runlist_update(struct gf100_fifo_priv *priv) +gf100_fifo_runlist_update(struct gf100_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_bar *bar = nvkm_bar(fifo); struct nvkm_gpuobj *cur; int i, p; - mutex_lock(&nv_subdev(priv)->mutex); - cur = priv->runlist.mem[priv->runlist.active]; - priv->runlist.active = !priv->runlist.active; + mutex_lock(&nv_subdev(fifo)->mutex); + cur = fifo->runlist.mem[fifo->runlist.active]; + fifo->runlist.active = !fifo->runlist.active; for (i = 0, p = 0; i < 128; i++) { - struct gf100_fifo_chan *chan = (void *)priv->base.channel[i]; + struct gf100_fifo_chan *chan = (void *)fifo->base.channel[i]; if (chan && chan->state == RUNNING) { nv_wo32(cur, p + 0, i); nv_wo32(cur, p + 4, 0x00000004); @@ -94,14 +94,14 @@ gf100_fifo_runlist_update(struct gf100_fifo_priv *priv) } bar->flush(bar); - nv_wr32(priv, 0x002270, cur->addr >> 12); - nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3)); + nv_wr32(fifo, 0x002270, cur->addr >> 12); + nv_wr32(fifo, 0x002274, 0x01f00000 | (p >> 3)); - if (wait_event_timeout(priv->runlist.wait, - !(nv_rd32(priv, 0x00227c) & 0x00100000), + if (wait_event_timeout(fifo->runlist.wait, + !(nv_rd32(fifo, 0x00227c) & 0x00100000), msecs_to_jiffies(2000)) == 0) - nv_error(priv, "runlist update timeout\n"); - mutex_unlock(&nv_subdev(priv)->mutex); + nv_error(fifo, "runlist update timeout\n"); + mutex_unlock(&nv_subdev(fifo)->mutex); } static int @@ -146,7 +146,7 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { struct nvkm_bar *bar = nvkm_bar(parent); - struct gf100_fifo_priv *priv = (void *)parent->engine; + struct gf100_fifo *fifo = (void *)parent->engine; struct gf100_fifo_base *base = (void *)parent->parent; struct gf100_fifo_chan *chan = (void *)parent; u32 addr; @@ -163,9 +163,9 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - nv_wr32(priv, 0x002634, chan->base.chid); - if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { - nv_error(priv, "channel %d [%s] kick timeout\n", + nv_wr32(fifo, 0x002634, chan->base.chid); + if (!nv_wait(fifo, 0x002634, 0xffffffff, chan->base.chid)) { + nv_error(fifo, "channel %d [%s] kick timeout\n", chan->base.chid, nvkm_client_name(chan)); if (suspend) return -EBUSY; @@ -186,7 +186,7 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nv50_channel_gpfifo_v0 v0; } *args = data; struct nvkm_bar *bar = nvkm_bar(parent); - struct gf100_fifo_priv *priv = (void *)engine; + struct gf100_fifo *fifo = (void *)engine; struct gf100_fifo_base *base = (void *)parent; struct gf100_fifo_chan *chan; u64 usermem, ioffset, ilength; @@ -202,7 +202,7 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - priv->user.bar.offset, 0x1000, + fifo->user.bar.offset, 0x1000, args->v0.pushbuf, (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | @@ -225,10 +225,10 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ilength = order_base_2(args->v0.ilength / 8); for (i = 0; i < 0x1000; i += 4) - nv_wo32(priv->user.mem, usermem + i, 0x00000000); + nv_wo32(fifo->user.mem, usermem + i, 0x00000000); - nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem)); - nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem)); + nv_wo32(base, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); + nv_wo32(base, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); nv_wo32(base, 0x10, 0x0000face); nv_wo32(base, 0x30, 0xfffff902); nv_wo32(base, 0x48, lower_32_bits(ioffset)); @@ -251,7 +251,7 @@ static int gf100_fifo_chan_init(struct nvkm_object *object) { struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gf100_fifo_priv *priv = (void *)object->engine; + struct gf100_fifo *fifo = (void *)object->engine; struct gf100_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; int ret; @@ -260,33 +260,33 @@ gf100_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); + nv_wr32(fifo, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001); - gf100_fifo_runlist_update(priv); + nv_wr32(fifo, 0x003004 + (chid * 8), 0x001f0001); + gf100_fifo_runlist_update(fifo); } return 0; } -static void gf100_fifo_intr_engine(struct gf100_fifo_priv *priv); +static void gf100_fifo_intr_engine(struct gf100_fifo *fifo); static int gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend) { - struct gf100_fifo_priv *priv = (void *)object->engine; + struct gf100_fifo *fifo = (void *)object->engine; struct gf100_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000); - gf100_fifo_runlist_update(priv); + nv_mask(fifo, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + gf100_fifo_runlist_update(fifo); } - gf100_fifo_intr_engine(priv); + gf100_fifo_intr_engine(fifo); - nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000); + nv_wr32(fifo, 0x003000 + (chid * 8), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -371,7 +371,7 @@ gf100_fifo_cclass = { ******************************************************************************/ static inline int -gf100_fifo_engidx(struct gf100_fifo_priv *priv, u32 engn) +gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn) { switch (engn) { case NVDEV_ENGINE_GR : engn = 0; break; @@ -388,7 +388,7 @@ gf100_fifo_engidx(struct gf100_fifo_priv *priv, u32 engn) } static inline struct nvkm_engine * -gf100_fifo_engine(struct gf100_fifo_priv *priv, u32 engn) +gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn) { switch (engn) { case 0: engn = NVDEV_ENGINE_GR; break; @@ -401,69 +401,69 @@ gf100_fifo_engine(struct gf100_fifo_priv *priv, u32 engn) return NULL; } - return nvkm_engine(priv, engn); + return nvkm_engine(fifo, engn); } static void gf100_fifo_recover_work(struct work_struct *work) { - struct gf100_fifo_priv *priv = container_of(work, typeof(*priv), fault); + struct gf100_fifo *fifo = container_of(work, typeof(*fifo), fault); struct nvkm_object *engine; unsigned long flags; u32 engn, engm = 0; u64 mask, todo; - spin_lock_irqsave(&priv->base.lock, flags); - mask = priv->mask; - priv->mask = 0ULL; - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); + mask = fifo->mask; + fifo->mask = 0ULL; + spin_unlock_irqrestore(&fifo->base.lock, flags); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) - engm |= 1 << gf100_fifo_engidx(priv, engn); - nv_mask(priv, 0x002630, engm, engm); + engm |= 1 << gf100_fifo_engidx(fifo, engn); + nv_mask(fifo, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = (void *)nvkm_engine(priv, engn))) { + if ((engine = (void *)nvkm_engine(fifo, engn))) { nv_ofuncs(engine)->fini(engine, false); WARN_ON(nv_ofuncs(engine)->init(engine)); } } - gf100_fifo_runlist_update(priv); - nv_wr32(priv, 0x00262c, engm); - nv_mask(priv, 0x002630, engm, 0x00000000); + gf100_fifo_runlist_update(fifo); + nv_wr32(fifo, 0x00262c, engm); + nv_mask(fifo, 0x002630, engm, 0x00000000); } static void -gf100_fifo_recover(struct gf100_fifo_priv *priv, struct nvkm_engine *engine, +gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, struct gf100_fifo_chan *chan) { u32 chid = chan->base.chid; unsigned long flags; - nv_error(priv, "%s engine fault on channel %d, recovering...\n", + nv_error(fifo, "%s engine fault on channel %d, recovering...\n", nv_subdev(engine)->name, chid); - nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); + nv_mask(fifo, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); chan->state = KILLED; - spin_lock_irqsave(&priv->base.lock, flags); - priv->mask |= 1ULL << nv_engidx(engine); - spin_unlock_irqrestore(&priv->base.lock, flags); - schedule_work(&priv->fault); + spin_lock_irqsave(&fifo->base.lock, flags); + fifo->mask |= 1ULL << nv_engidx(engine); + spin_unlock_irqrestore(&fifo->base.lock, flags); + schedule_work(&fifo->fault); } static int -gf100_fifo_swmthd(struct gf100_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +gf100_fifo_swmthd(struct gf100_fifo *fifo, u32 chid, u32 mthd, u32 data) { struct gf100_fifo_chan *chan = NULL; struct nvkm_handle *bind; unsigned long flags; int ret = -EINVAL; - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; + spin_lock_irqsave(&fifo->base.lock, flags); + if (likely(chid >= fifo->base.min && chid <= fifo->base.max)) + chan = (void *)fifo->base.channel[chid]; if (unlikely(!chan)) goto out; @@ -475,7 +475,7 @@ gf100_fifo_swmthd(struct gf100_fifo_priv *priv, u32 chid, u32 mthd, u32 data) } out: - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_unlock_irqrestore(&fifo->base.lock, flags); return ret; } @@ -486,14 +486,14 @@ gf100_fifo_sched_reason[] = { }; static void -gf100_fifo_intr_sched_ctxsw(struct gf100_fifo_priv *priv) +gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) { struct nvkm_engine *engine; struct gf100_fifo_chan *chan; u32 engn; for (engn = 0; engn < 6; engn++) { - u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 stat = nv_rd32(fifo, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 save = (stat & 0x00100000); /* maybe? */ u32 unk0 = (stat & 0x00040000); @@ -502,19 +502,19 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo_priv *priv) (void)save; if (busy && unk0 && unk1) { - if (!(chan = (void *)priv->base.channel[chid])) + if (!(chan = (void *)fifo->base.channel[chid])) continue; - if (!(engine = gf100_fifo_engine(priv, engn))) + if (!(engine = gf100_fifo_engine(fifo, engn))) continue; - gf100_fifo_recover(priv, engine, chan); + gf100_fifo_recover(fifo, engine, chan); } } } static void -gf100_fifo_intr_sched(struct gf100_fifo_priv *priv) +gf100_fifo_intr_sched(struct gf100_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x00254c); + u32 intr = nv_rd32(fifo, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; char enunk[6] = ""; @@ -523,11 +523,11 @@ gf100_fifo_intr_sched(struct gf100_fifo_priv *priv) if (!en) snprintf(enunk, sizeof(enunk), "UNK%02x", code); - nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + nv_error(fifo, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); switch (code) { case 0x0a: - gf100_fifo_intr_sched_ctxsw(priv); + gf100_fifo_intr_sched_ctxsw(fifo); break; default: break; @@ -594,12 +594,12 @@ gf100_fifo_fault_gpcclient[] = { }; static void -gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit) +gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) { - u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); - u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); - u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); - u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 inst = nv_rd32(fifo, 0x002800 + (unit * 0x10)); + u32 valo = nv_rd32(fifo, 0x002804 + (unit * 0x10)); + u32 vahi = nv_rd32(fifo, 0x002808 + (unit * 0x10)); + u32 stat = nv_rd32(fifo, 0x00280c + (unit * 0x10)); u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; u32 write = (stat & 0x00000080); @@ -621,16 +621,16 @@ gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit) if (eu) { switch (eu->data2) { case NVDEV_SUBDEV_BAR: - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + nv_mask(fifo, 0x001704, 0x00000000, 0x00000000); break; case NVDEV_SUBDEV_INSTMEM: - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + nv_mask(fifo, 0x001714, 0x00000000, 0x00000000); break; case NVDEV_ENGINE_IFB: - nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + nv_mask(fifo, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_engine(priv, eu->data2); + engine = nvkm_engine(fifo, eu->data2); if (engine) engctx = nvkm_engctx_get(engine, inst); break; @@ -649,7 +649,7 @@ gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit) if (!ec) snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); - nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " + nv_error(fifo, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " "channel 0x%010llx [%s]\n", write ? "write" : "read", (u64)vahi << 32 | valo, er ? er->name : erunk, eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", @@ -660,7 +660,7 @@ gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit) while (object) { switch (nv_mclass(object)) { case FERMI_CHANNEL_GPFIFO: - gf100_fifo_recover(priv, engine, (void *)object); + gf100_fifo_recover(fifo, engine, (void *)object); break; } object = object->parent; @@ -678,82 +678,82 @@ gf100_fifo_pbdma_intr[] = { }; static void -gf100_fifo_intr_pbdma(struct gf100_fifo_priv *priv, int unit) +gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) { - u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)); - u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f; + u32 stat = nv_rd32(fifo, 0x040108 + (unit * 0x2000)); + u32 addr = nv_rd32(fifo, 0x0400c0 + (unit * 0x2000)); + u32 data = nv_rd32(fifo, 0x0400c4 + (unit * 0x2000)); + u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0x7f; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; if (stat & 0x00800000) { - if (!gf100_fifo_swmthd(priv, chid, mthd, data)) + if (!gf100_fifo_swmthd(fifo, chid, mthd, data)) show &= ~0x00800000; } if (show) { - nv_error(priv, "PBDMA%d:", unit); + nv_error(fifo, "PBDMA%d:", unit); nvkm_bitfield_print(gf100_fifo_pbdma_intr, show); pr_cont("\n"); - nv_error(priv, + nv_error(fifo, "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", unit, chid, - nvkm_client_name_for_fifo_chid(&priv->base, chid), + nvkm_client_name_for_fifo_chid(&fifo->base, chid), subc, mthd, data); } - nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); - nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); + nv_wr32(fifo, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(fifo, 0x040108 + (unit * 0x2000), stat); } static void -gf100_fifo_intr_runlist(struct gf100_fifo_priv *priv) +gf100_fifo_intr_runlist(struct gf100_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x002a00); + u32 intr = nv_rd32(fifo, 0x002a00); if (intr & 0x10000000) { - wake_up(&priv->runlist.wait); - nv_wr32(priv, 0x002a00, 0x10000000); + wake_up(&fifo->runlist.wait); + nv_wr32(fifo, 0x002a00, 0x10000000); intr &= ~0x10000000; } if (intr) { - nv_error(priv, "RUNLIST 0x%08x\n", intr); - nv_wr32(priv, 0x002a00, intr); + nv_error(fifo, "RUNLIST 0x%08x\n", intr); + nv_wr32(fifo, 0x002a00, intr); } } static void -gf100_fifo_intr_engine_unit(struct gf100_fifo_priv *priv, int engn) +gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) { - u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04)); - u32 inte = nv_rd32(priv, 0x002628); + u32 intr = nv_rd32(fifo, 0x0025a8 + (engn * 0x04)); + u32 inte = nv_rd32(fifo, 0x002628); u32 unkn; - nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr); + nv_wr32(fifo, 0x0025a8 + (engn * 0x04), intr); for (unkn = 0; unkn < 8; unkn++) { u32 ints = (intr >> (unkn * 0x04)) & inte; if (ints & 0x1) { - nvkm_fifo_uevent(&priv->base); + nvkm_fifo_uevent(&fifo->base); ints &= ~1; } if (ints) { - nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints); - nv_mask(priv, 0x002628, ints, 0); + nv_error(fifo, "ENGINE %d %d %01x", engn, unkn, ints); + nv_mask(fifo, 0x002628, ints, 0); } } } static void -gf100_fifo_intr_engine(struct gf100_fifo_priv *priv) +gf100_fifo_intr_engine(struct gf100_fifo *fifo) { - u32 mask = nv_rd32(priv, 0x0025a4); + u32 mask = nv_rd32(fifo, 0x0025a4); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_engine_unit(priv, unit); + gf100_fifo_intr_engine_unit(fifo, unit); mask &= ~(1 << unit); } } @@ -761,73 +761,73 @@ gf100_fifo_intr_engine(struct gf100_fifo_priv *priv) static void gf100_fifo_intr(struct nvkm_subdev *subdev) { - struct gf100_fifo_priv *priv = (void *)subdev; - u32 mask = nv_rd32(priv, 0x002140); - u32 stat = nv_rd32(priv, 0x002100) & mask; + struct gf100_fifo *fifo = (void *)subdev; + u32 mask = nv_rd32(fifo, 0x002140); + u32 stat = nv_rd32(fifo, 0x002100) & mask; if (stat & 0x00000001) { - u32 intr = nv_rd32(priv, 0x00252c); - nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr); - nv_wr32(priv, 0x002100, 0x00000001); + u32 intr = nv_rd32(fifo, 0x00252c); + nv_warn(fifo, "INTR 0x00000001: 0x%08x\n", intr); + nv_wr32(fifo, 0x002100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000100) { - gf100_fifo_intr_sched(priv); - nv_wr32(priv, 0x002100, 0x00000100); + gf100_fifo_intr_sched(fifo); + nv_wr32(fifo, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x00010000) { - u32 intr = nv_rd32(priv, 0x00256c); - nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr); - nv_wr32(priv, 0x002100, 0x00010000); + u32 intr = nv_rd32(fifo, 0x00256c); + nv_warn(fifo, "INTR 0x00010000: 0x%08x\n", intr); + nv_wr32(fifo, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x01000000) { - u32 intr = nv_rd32(priv, 0x00258c); - nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr); - nv_wr32(priv, 0x002100, 0x01000000); + u32 intr = nv_rd32(fifo, 0x00258c); + nv_warn(fifo, "INTR 0x01000000: 0x%08x\n", intr); + nv_wr32(fifo, 0x002100, 0x01000000); stat &= ~0x01000000; } if (stat & 0x10000000) { - u32 mask = nv_rd32(priv, 0x00259c); + u32 mask = nv_rd32(fifo, 0x00259c); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_fault(priv, unit); - nv_wr32(priv, 0x00259c, (1 << unit)); + gf100_fifo_intr_fault(fifo, unit); + nv_wr32(fifo, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nv_rd32(priv, 0x0025a0); + u32 mask = nv_rd32(fifo, 0x0025a0); while (mask) { u32 unit = __ffs(mask); - gf100_fifo_intr_pbdma(priv, unit); - nv_wr32(priv, 0x0025a0, (1 << unit)); + gf100_fifo_intr_pbdma(fifo, unit); + nv_wr32(fifo, 0x0025a0, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x20000000; } if (stat & 0x40000000) { - gf100_fifo_intr_runlist(priv); + gf100_fifo_intr_runlist(fifo); stat &= ~0x40000000; } if (stat & 0x80000000) { - gf100_fifo_intr_engine(priv); + gf100_fifo_intr_engine(fifo); stat &= ~0x80000000; } if (stat) { - nv_error(priv, "INTR 0x%08x\n", stat); - nv_mask(priv, 0x002140, stat, 0x00000000); - nv_wr32(priv, 0x002100, stat); + nv_error(fifo, "INTR 0x%08x\n", stat); + nv_mask(fifo, 0x002140, stat, 0x00000000); + nv_wr32(fifo, 0x002100, stat); } } @@ -857,101 +857,101 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_fifo_priv *priv; + struct gf100_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 127, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 0, 127, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - INIT_WORK(&priv->fault, gf100_fifo_recover_work); + INIT_WORK(&fifo->fault, gf100_fifo_recover_work); - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->runlist.mem[0]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x1000, 0x1000, 0, + &fifo->runlist.mem[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0, - &priv->runlist.mem[1]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x1000, 0x1000, 0, + &fifo->runlist.mem[1]); if (ret) return ret; - init_waitqueue_head(&priv->runlist.wait); + init_waitqueue_head(&fifo->runlist.wait); - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0, - &priv->user.mem); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 0x1000, 0x1000, 0, + &fifo->user.mem); if (ret) return ret; - ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); + ret = nvkm_gpuobj_map(fifo->user.mem, NV_MEM_ACCESS_RW, + &fifo->user.bar); if (ret) return ret; - ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &priv->base.uevent); + ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &fifo->base.uevent); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = gf100_fifo_intr; - nv_engine(priv)->cclass = &gf100_fifo_cclass; - nv_engine(priv)->sclass = gf100_fifo_sclass; + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = gf100_fifo_intr; + nv_engine(fifo)->cclass = &gf100_fifo_cclass; + nv_engine(fifo)->sclass = gf100_fifo_sclass; return 0; } static void gf100_fifo_dtor(struct nvkm_object *object) { - struct gf100_fifo_priv *priv = (void *)object; + struct gf100_fifo *fifo = (void *)object; - nvkm_gpuobj_unmap(&priv->user.bar); - nvkm_gpuobj_ref(NULL, &priv->user.mem); - nvkm_gpuobj_ref(NULL, &priv->runlist.mem[0]); - nvkm_gpuobj_ref(NULL, &priv->runlist.mem[1]); + nvkm_gpuobj_unmap(&fifo->user.bar); + nvkm_gpuobj_ref(NULL, &fifo->user.mem); + nvkm_gpuobj_ref(NULL, &fifo->runlist.mem[0]); + nvkm_gpuobj_ref(NULL, &fifo->runlist.mem[1]); - nvkm_fifo_destroy(&priv->base); + nvkm_fifo_destroy(&fifo->base); } static int gf100_fifo_init(struct nvkm_object *object) { - struct gf100_fifo_priv *priv = (void *)object; + struct gf100_fifo *fifo = (void *)object; int ret, i; - ret = nvkm_fifo_init(&priv->base); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(priv, 0x000204, 0xffffffff); - nv_wr32(priv, 0x002204, 0xffffffff); + nv_wr32(fifo, 0x000204, 0xffffffff); + nv_wr32(fifo, 0x002204, 0xffffffff); - priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204)); - nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); + fifo->spoon_nr = hweight32(nv_rd32(fifo, 0x002204)); + nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* assign engines to PBDMAs */ - if (priv->spoon_nr >= 3) { - nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */ - nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */ - nv_wr32(priv, 0x002210, ~(1 << 1)); /* PMSPP */ - nv_wr32(priv, 0x002214, ~(1 << 1)); /* PMSVLD */ - nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */ - nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */ + if (fifo->spoon_nr >= 3) { + nv_wr32(fifo, 0x002208, ~(1 << 0)); /* PGRAPH */ + nv_wr32(fifo, 0x00220c, ~(1 << 1)); /* PVP */ + nv_wr32(fifo, 0x002210, ~(1 << 1)); /* PMSPP */ + nv_wr32(fifo, 0x002214, ~(1 << 1)); /* PMSVLD */ + nv_wr32(fifo, 0x002218, ~(1 << 2)); /* PCE0 */ + nv_wr32(fifo, 0x00221c, ~(1 << 1)); /* PCE1 */ } /* PBDMA[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + for (i = 0; i < fifo->spoon_nr; i++) { + nv_mask(fifo, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(fifo, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(fifo, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } - nv_mask(priv, 0x002200, 0x00000001, 0x00000001); - nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + nv_mask(fifo, 0x002200, 0x00000001, 0x00000001); + nv_wr32(fifo, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x7fffffff); - nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ + nv_wr32(fifo, 0x002100, 0xffffffff); + nv_wr32(fifo, 0x002140, 0x7fffffff); + nv_wr32(fifo, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index e10f9644140f5..ed8d3820a0442 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -58,7 +58,7 @@ struct gk104_fifo_engn { wait_queue_head_t wait; }; -struct gk104_fifo_priv { +struct gk104_fifo { struct nvkm_fifo base; struct work_struct fault; @@ -93,19 +93,19 @@ struct gk104_fifo_chan { ******************************************************************************/ static void -gk104_fifo_runlist_update(struct gk104_fifo_priv *priv, u32 engine) +gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { - struct nvkm_bar *bar = nvkm_bar(priv); - struct gk104_fifo_engn *engn = &priv->engine[engine]; + struct nvkm_bar *bar = nvkm_bar(fifo); + struct gk104_fifo_engn *engn = &fifo->engine[engine]; struct nvkm_gpuobj *cur; int i, p; - mutex_lock(&nv_subdev(priv)->mutex); + mutex_lock(&nv_subdev(fifo)->mutex); cur = engn->runlist[engn->cur_runlist]; engn->cur_runlist = !engn->cur_runlist; - for (i = 0, p = 0; i < priv->base.max; i++) { - struct gk104_fifo_chan *chan = (void *)priv->base.channel[i]; + for (i = 0, p = 0; i < fifo->base.max; i++) { + struct gk104_fifo_chan *chan = (void *)fifo->base.channel[i]; if (chan && chan->state == RUNNING && chan->engine == engine) { nv_wo32(cur, p + 0, i); nv_wo32(cur, p + 4, 0x00000000); @@ -114,14 +114,14 @@ gk104_fifo_runlist_update(struct gk104_fifo_priv *priv, u32 engine) } bar->flush(bar); - nv_wr32(priv, 0x002270, cur->addr >> 12); - nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3)); + nv_wr32(fifo, 0x002270, cur->addr >> 12); + nv_wr32(fifo, 0x002274, (engine << 20) | (p >> 3)); - if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 + + if (wait_event_timeout(engn->wait, !(nv_rd32(fifo, 0x002284 + (engine * 0x08)) & 0x00100000), msecs_to_jiffies(2000)) == 0) - nv_error(priv, "runlist %d update timeout\n", engine); - mutex_unlock(&nv_subdev(priv)->mutex); + nv_error(fifo, "runlist %d update timeout\n", engine); + mutex_unlock(&nv_subdev(fifo)->mutex); } static int @@ -165,15 +165,31 @@ gk104_fifo_context_attach(struct nvkm_object *parent, return 0; } +static int +gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) +{ + struct nvkm_object *obj = (void *)chan; + struct gk104_fifo *fifo = (void *)obj->engine; + + nv_wr32(fifo, 0x002634, chan->base.chid); + if (!nv_wait(fifo, 0x002634, 0x100000, 0x000000)) { + nv_error(fifo, "channel %d [%s] kick timeout\n", + chan->base.chid, nvkm_client_name(chan)); + return -EBUSY; + } + + return 0; +} + static int gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { struct nvkm_bar *bar = nvkm_bar(parent); - struct gk104_fifo_priv *priv = (void *)parent->engine; struct gk104_fifo_base *base = (void *)parent->parent; struct gk104_fifo_chan *chan = (void *)parent; u32 addr; + int ret; switch (nv_engidx(object->engine)) { case NVDEV_ENGINE_SW : return 0; @@ -188,13 +204,9 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - nv_wr32(priv, 0x002634, chan->base.chid); - if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) { - nv_error(priv, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - return -EBUSY; - } + ret = gk104_fifo_chan_kick(chan); + if (ret && suspend) + return ret; if (addr) { nv_wo32(base, addr + 0x00, 0x00000000); @@ -214,7 +226,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct kepler_channel_gpfifo_a_v0 v0; } *args = data; struct nvkm_bar *bar = nvkm_bar(parent); - struct gk104_fifo_priv *priv = (void *)engine; + struct gk104_fifo *fifo = (void *)engine; struct gk104_fifo_base *base = (void *)parent; struct gk104_fifo_chan *chan; u64 usermem, ioffset, ilength; @@ -239,12 +251,12 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } if (i == FIFO_ENGINE_NR) { - nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine); + nv_error(fifo, "unsupported engines 0x%08x\n", args->v0.engine); return -ENODEV; } ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - priv->user.bar.offset, 0x200, + fifo->user.bar.offset, 0x200, args->v0.pushbuf, fifo_engine[i].mask, &chan); *pobject = nv_object(chan); @@ -262,10 +274,10 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ilength = order_base_2(args->v0.ilength / 8); for (i = 0; i < 0x200; i += 4) - nv_wo32(priv->user.mem, usermem + i, 0x00000000); + nv_wo32(fifo->user.mem, usermem + i, 0x00000000); - nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem)); - nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem)); + nv_wo32(base, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); + nv_wo32(base, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); nv_wo32(base, 0x10, 0x0000face); nv_wo32(base, 0x30, 0xfffff902); nv_wo32(base, 0x48, lower_32_bits(ioffset)); @@ -286,7 +298,7 @@ static int gk104_fifo_chan_init(struct nvkm_object *object) { struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gk104_fifo_priv *priv = (void *)object->engine; + struct gk104_fifo *fifo = (void *)object->engine; struct gk104_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; int ret; @@ -295,13 +307,13 @@ gk104_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); - nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); + nv_mask(fifo, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); + nv_wr32(fifo, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - gk104_fifo_runlist_update(priv, chan->engine); - nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nv_mask(fifo, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + gk104_fifo_runlist_update(fifo, chan->engine); + nv_mask(fifo, 0x800004 + (chid * 8), 0x00000400, 0x00000400); } return 0; @@ -310,16 +322,16 @@ gk104_fifo_chan_init(struct nvkm_object *object) static int gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) { - struct gk104_fifo_priv *priv = (void *)object->engine; + struct gk104_fifo *fifo = (void *)object->engine; struct gk104_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800); - gk104_fifo_runlist_update(priv, chan->engine); + nv_mask(fifo, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + gk104_fifo_runlist_update(fifo, chan->engine); } - nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000); + nv_wr32(fifo, 0x800000 + (chid * 8), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -403,7 +415,7 @@ gk104_fifo_cclass = { ******************************************************************************/ static inline int -gk104_fifo_engidx(struct gk104_fifo_priv *priv, u32 engn) +gk104_fifo_engidx(struct gk104_fifo *fifo, u32 engn) { switch (engn) { case NVDEV_ENGINE_GR : @@ -422,73 +434,73 @@ gk104_fifo_engidx(struct gk104_fifo_priv *priv, u32 engn) } static inline struct nvkm_engine * -gk104_fifo_engine(struct gk104_fifo_priv *priv, u32 engn) +gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn) { if (engn >= ARRAY_SIZE(fifo_engine)) return NULL; - return nvkm_engine(priv, fifo_engine[engn].subdev); + return nvkm_engine(fifo, fifo_engine[engn].subdev); } static void gk104_fifo_recover_work(struct work_struct *work) { - struct gk104_fifo_priv *priv = container_of(work, typeof(*priv), fault); + struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault); struct nvkm_object *engine; unsigned long flags; u32 engn, engm = 0; u64 mask, todo; - spin_lock_irqsave(&priv->base.lock, flags); - mask = priv->mask; - priv->mask = 0ULL; - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); + mask = fifo->mask; + fifo->mask = 0ULL; + spin_unlock_irqrestore(&fifo->base.lock, flags); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) - engm |= 1 << gk104_fifo_engidx(priv, engn); - nv_mask(priv, 0x002630, engm, engm); + engm |= 1 << gk104_fifo_engidx(fifo, engn); + nv_mask(fifo, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = (void *)nvkm_engine(priv, engn))) { + if ((engine = (void *)nvkm_engine(fifo, engn))) { nv_ofuncs(engine)->fini(engine, false); WARN_ON(nv_ofuncs(engine)->init(engine)); } - gk104_fifo_runlist_update(priv, gk104_fifo_engidx(priv, engn)); + gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn)); } - nv_wr32(priv, 0x00262c, engm); - nv_mask(priv, 0x002630, engm, 0x00000000); + nv_wr32(fifo, 0x00262c, engm); + nv_mask(fifo, 0x002630, engm, 0x00000000); } static void -gk104_fifo_recover(struct gk104_fifo_priv *priv, struct nvkm_engine *engine, +gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, struct gk104_fifo_chan *chan) { u32 chid = chan->base.chid; unsigned long flags; - nv_error(priv, "%s engine fault on channel %d, recovering...\n", + nv_error(fifo, "%s engine fault on channel %d, recovering...\n", nv_subdev(engine)->name, chid); - nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); + nv_mask(fifo, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); chan->state = KILLED; - spin_lock_irqsave(&priv->base.lock, flags); - priv->mask |= 1ULL << nv_engidx(engine); - spin_unlock_irqrestore(&priv->base.lock, flags); - schedule_work(&priv->fault); + spin_lock_irqsave(&fifo->base.lock, flags); + fifo->mask |= 1ULL << nv_engidx(engine); + spin_unlock_irqrestore(&fifo->base.lock, flags); + schedule_work(&fifo->fault); } static int -gk104_fifo_swmthd(struct gk104_fifo_priv *priv, u32 chid, u32 mthd, u32 data) +gk104_fifo_swmthd(struct gk104_fifo *fifo, u32 chid, u32 mthd, u32 data) { struct gk104_fifo_chan *chan = NULL; struct nvkm_handle *bind; unsigned long flags; int ret = -EINVAL; - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; + spin_lock_irqsave(&fifo->base.lock, flags); + if (likely(chid >= fifo->base.min && chid <= fifo->base.max)) + chan = (void *)fifo->base.channel[chid]; if (unlikely(!chan)) goto out; @@ -500,7 +512,7 @@ gk104_fifo_swmthd(struct gk104_fifo_priv *priv, u32 chid, u32 mthd, u32 data) } out: - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_unlock_irqrestore(&fifo->base.lock, flags); return ret; } @@ -516,9 +528,9 @@ gk104_fifo_bind_reason[] = { }; static void -gk104_fifo_intr_bind(struct gk104_fifo_priv *priv) +gk104_fifo_intr_bind(struct gk104_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x00252c); + u32 intr = nv_rd32(fifo, 0x00252c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; char enunk[6] = ""; @@ -527,7 +539,7 @@ gk104_fifo_intr_bind(struct gk104_fifo_priv *priv) if (!en) snprintf(enunk, sizeof(enunk), "UNK%02x", code); - nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk); + nv_error(fifo, "BIND_ERROR [ %s ]\n", en ? en->name : enunk); } static const struct nvkm_enum @@ -537,14 +549,14 @@ gk104_fifo_sched_reason[] = { }; static void -gk104_fifo_intr_sched_ctxsw(struct gk104_fifo_priv *priv) +gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) { struct nvkm_engine *engine; struct gk104_fifo_chan *chan; u32 engn; for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { - u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04)); + u32 stat = nv_rd32(fifo, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 next = (stat & 0x07ff0000) >> 16; u32 chsw = (stat & 0x00008000); @@ -555,19 +567,19 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo_priv *priv) (void)save; if (busy && chsw) { - if (!(chan = (void *)priv->base.channel[chid])) + if (!(chan = (void *)fifo->base.channel[chid])) continue; - if (!(engine = gk104_fifo_engine(priv, engn))) + if (!(engine = gk104_fifo_engine(fifo, engn))) continue; - gk104_fifo_recover(priv, engine, chan); + gk104_fifo_recover(fifo, engine, chan); } } } static void -gk104_fifo_intr_sched(struct gk104_fifo_priv *priv) +gk104_fifo_intr_sched(struct gk104_fifo *fifo) { - u32 intr = nv_rd32(priv, 0x00254c); + u32 intr = nv_rd32(fifo, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; char enunk[6] = ""; @@ -576,11 +588,11 @@ gk104_fifo_intr_sched(struct gk104_fifo_priv *priv) if (!en) snprintf(enunk, sizeof(enunk), "UNK%02x", code); - nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + nv_error(fifo, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); switch (code) { case 0x0a: - gk104_fifo_intr_sched_ctxsw(priv); + gk104_fifo_intr_sched_ctxsw(fifo); break; default: break; @@ -588,18 +600,18 @@ gk104_fifo_intr_sched(struct gk104_fifo_priv *priv) } static void -gk104_fifo_intr_chsw(struct gk104_fifo_priv *priv) +gk104_fifo_intr_chsw(struct gk104_fifo *fifo) { - u32 stat = nv_rd32(priv, 0x00256c); - nv_error(priv, "CHSW_ERROR 0x%08x\n", stat); - nv_wr32(priv, 0x00256c, stat); + u32 stat = nv_rd32(fifo, 0x00256c); + nv_error(fifo, "CHSW_ERROR 0x%08x\n", stat); + nv_wr32(fifo, 0x00256c, stat); } static void -gk104_fifo_intr_dropped_fault(struct gk104_fifo_priv *priv) +gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo) { - u32 stat = nv_rd32(priv, 0x00259c); - nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat); + u32 stat = nv_rd32(fifo, 0x00259c); + nv_error(fifo, "DROPPED_MMU_FAULT 0x%08x\n", stat); } static const struct nvkm_enum @@ -708,12 +720,12 @@ gk104_fifo_fault_gpcclient[] = { }; static void -gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit) +gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) { - u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10)); - u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10)); - u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10)); - u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10)); + u32 inst = nv_rd32(fifo, 0x002800 + (unit * 0x10)); + u32 valo = nv_rd32(fifo, 0x002804 + (unit * 0x10)); + u32 vahi = nv_rd32(fifo, 0x002808 + (unit * 0x10)); + u32 stat = nv_rd32(fifo, 0x00280c + (unit * 0x10)); u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; u32 write = (stat & 0x00000080); @@ -735,16 +747,16 @@ gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit) if (eu) { switch (eu->data2) { case NVDEV_SUBDEV_BAR: - nv_mask(priv, 0x001704, 0x00000000, 0x00000000); + nv_mask(fifo, 0x001704, 0x00000000, 0x00000000); break; case NVDEV_SUBDEV_INSTMEM: - nv_mask(priv, 0x001714, 0x00000000, 0x00000000); + nv_mask(fifo, 0x001714, 0x00000000, 0x00000000); break; case NVDEV_ENGINE_IFB: - nv_mask(priv, 0x001718, 0x00000000, 0x00000000); + nv_mask(fifo, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_engine(priv, eu->data2); + engine = nvkm_engine(fifo, eu->data2); if (engine) engctx = nvkm_engctx_get(engine, inst); break; @@ -763,7 +775,7 @@ gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit) if (!ec) snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); - nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " + nv_error(fifo, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " "channel 0x%010llx [%s]\n", write ? "write" : "read", (u64)vahi << 32 | valo, er ? er->name : erunk, eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", @@ -775,7 +787,7 @@ gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit) switch (nv_mclass(object)) { case KEPLER_CHANNEL_GPFIFO_A: case MAXWELL_CHANNEL_GPFIFO_A: - gk104_fifo_recover(priv, engine, (void *)object); + gk104_fifo_recover(fifo, engine, (void *)object); break; } object = object->parent; @@ -819,35 +831,35 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { }; static void -gk104_fifo_intr_pbdma_0(struct gk104_fifo_priv *priv, int unit) +gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) { - u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000)); - u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask; - u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff; + u32 mask = nv_rd32(fifo, 0x04010c + (unit * 0x2000)); + u32 stat = nv_rd32(fifo, 0x040108 + (unit * 0x2000)) & mask; + u32 addr = nv_rd32(fifo, 0x0400c0 + (unit * 0x2000)); + u32 data = nv_rd32(fifo, 0x0400c4 + (unit * 0x2000)); + u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0xfff; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; if (stat & 0x00800000) { - if (!gk104_fifo_swmthd(priv, chid, mthd, data)) + if (!gk104_fifo_swmthd(fifo, chid, mthd, data)) show &= ~0x00800000; - nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008); + nv_wr32(fifo, 0x0400c0 + (unit * 0x2000), 0x80600008); } if (show) { - nv_error(priv, "PBDMA%d:", unit); + nv_error(fifo, "PBDMA%d:", unit); nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show); pr_cont("\n"); - nv_error(priv, + nv_error(fifo, "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", unit, chid, - nvkm_client_name_for_fifo_chid(&priv->base, chid), + nvkm_client_name_for_fifo_chid(&fifo->base, chid), subc, mthd, data); } - nv_wr32(priv, 0x040108 + (unit * 0x2000), stat); + nv_wr32(fifo, 0x040108 + (unit * 0x2000), stat); } static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { @@ -860,129 +872,129 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { }; static void -gk104_fifo_intr_pbdma_1(struct gk104_fifo_priv *priv, int unit) +gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit) { - u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000)); - u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask; - u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff; + u32 mask = nv_rd32(fifo, 0x04014c + (unit * 0x2000)); + u32 stat = nv_rd32(fifo, 0x040148 + (unit * 0x2000)) & mask; + u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0xfff; if (stat) { - nv_error(priv, "PBDMA%d:", unit); + nv_error(fifo, "PBDMA%d:", unit); nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat); pr_cont("\n"); - nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid, - nv_rd32(priv, 0x040150 + (unit * 0x2000)), - nv_rd32(priv, 0x040154 + (unit * 0x2000))); + nv_error(fifo, "PBDMA%d: ch %d %08x %08x\n", unit, chid, + nv_rd32(fifo, 0x040150 + (unit * 0x2000)), + nv_rd32(fifo, 0x040154 + (unit * 0x2000))); } - nv_wr32(priv, 0x040148 + (unit * 0x2000), stat); + nv_wr32(fifo, 0x040148 + (unit * 0x2000), stat); } static void -gk104_fifo_intr_runlist(struct gk104_fifo_priv *priv) +gk104_fifo_intr_runlist(struct gk104_fifo *fifo) { - u32 mask = nv_rd32(priv, 0x002a00); + u32 mask = nv_rd32(fifo, 0x002a00); while (mask) { u32 engn = __ffs(mask); - wake_up(&priv->engine[engn].wait); - nv_wr32(priv, 0x002a00, 1 << engn); + wake_up(&fifo->engine[engn].wait); + nv_wr32(fifo, 0x002a00, 1 << engn); mask &= ~(1 << engn); } } static void -gk104_fifo_intr_engine(struct gk104_fifo_priv *priv) +gk104_fifo_intr_engine(struct gk104_fifo *fifo) { - nvkm_fifo_uevent(&priv->base); + nvkm_fifo_uevent(&fifo->base); } static void gk104_fifo_intr(struct nvkm_subdev *subdev) { - struct gk104_fifo_priv *priv = (void *)subdev; - u32 mask = nv_rd32(priv, 0x002140); - u32 stat = nv_rd32(priv, 0x002100) & mask; + struct gk104_fifo *fifo = (void *)subdev; + u32 mask = nv_rd32(fifo, 0x002140); + u32 stat = nv_rd32(fifo, 0x002100) & mask; if (stat & 0x00000001) { - gk104_fifo_intr_bind(priv); - nv_wr32(priv, 0x002100, 0x00000001); + gk104_fifo_intr_bind(fifo); + nv_wr32(fifo, 0x002100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000010) { - nv_error(priv, "PIO_ERROR\n"); - nv_wr32(priv, 0x002100, 0x00000010); + nv_error(fifo, "PIO_ERROR\n"); + nv_wr32(fifo, 0x002100, 0x00000010); stat &= ~0x00000010; } if (stat & 0x00000100) { - gk104_fifo_intr_sched(priv); - nv_wr32(priv, 0x002100, 0x00000100); + gk104_fifo_intr_sched(fifo); + nv_wr32(fifo, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x00010000) { - gk104_fifo_intr_chsw(priv); - nv_wr32(priv, 0x002100, 0x00010000); + gk104_fifo_intr_chsw(fifo); + nv_wr32(fifo, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x00800000) { - nv_error(priv, "FB_FLUSH_TIMEOUT\n"); - nv_wr32(priv, 0x002100, 0x00800000); + nv_error(fifo, "FB_FLUSH_TIMEOUT\n"); + nv_wr32(fifo, 0x002100, 0x00800000); stat &= ~0x00800000; } if (stat & 0x01000000) { - nv_error(priv, "LB_ERROR\n"); - nv_wr32(priv, 0x002100, 0x01000000); + nv_error(fifo, "LB_ERROR\n"); + nv_wr32(fifo, 0x002100, 0x01000000); stat &= ~0x01000000; } if (stat & 0x08000000) { - gk104_fifo_intr_dropped_fault(priv); - nv_wr32(priv, 0x002100, 0x08000000); + gk104_fifo_intr_dropped_fault(fifo); + nv_wr32(fifo, 0x002100, 0x08000000); stat &= ~0x08000000; } if (stat & 0x10000000) { - u32 mask = nv_rd32(priv, 0x00259c); + u32 mask = nv_rd32(fifo, 0x00259c); while (mask) { u32 unit = __ffs(mask); - gk104_fifo_intr_fault(priv, unit); - nv_wr32(priv, 0x00259c, (1 << unit)); + gk104_fifo_intr_fault(fifo, unit); + nv_wr32(fifo, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nv_rd32(priv, 0x0025a0); + u32 mask = nv_rd32(fifo, 0x0025a0); while (mask) { u32 unit = __ffs(mask); - gk104_fifo_intr_pbdma_0(priv, unit); - gk104_fifo_intr_pbdma_1(priv, unit); - nv_wr32(priv, 0x0025a0, (1 << unit)); + gk104_fifo_intr_pbdma_0(fifo, unit); + gk104_fifo_intr_pbdma_1(fifo, unit); + nv_wr32(fifo, 0x0025a0, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x20000000; } if (stat & 0x40000000) { - gk104_fifo_intr_runlist(priv); + gk104_fifo_intr_runlist(fifo); stat &= ~0x40000000; } if (stat & 0x80000000) { - nv_wr32(priv, 0x002100, 0x80000000); - gk104_fifo_intr_engine(priv); + nv_wr32(fifo, 0x002100, 0x80000000); + gk104_fifo_intr_engine(fifo); stat &= ~0x80000000; } if (stat) { - nv_error(priv, "INTR 0x%08x\n", stat); - nv_mask(priv, 0x002140, stat, 0x00000000); - nv_wr32(priv, 0x002100, stat); + nv_error(fifo, "INTR 0x%08x\n", stat); + nv_mask(fifo, 0x002140, stat, 0x00000000); + nv_wr32(fifo, 0x002100, stat); } } @@ -1010,68 +1022,68 @@ gk104_fifo_uevent_func = { int gk104_fifo_fini(struct nvkm_object *object, bool suspend) { - struct gk104_fifo_priv *priv = (void *)object; + struct gk104_fifo *fifo = (void *)object; int ret; - ret = nvkm_fifo_fini(&priv->base, suspend); + ret = nvkm_fifo_fini(&fifo->base, suspend); if (ret) return ret; /* allow mmu fault interrupts, even when we're not using fifo */ - nv_mask(priv, 0x002140, 0x10000000, 0x10000000); + nv_mask(fifo, 0x002140, 0x10000000, 0x10000000); return 0; } int gk104_fifo_init(struct nvkm_object *object) { - struct gk104_fifo_priv *priv = (void *)object; + struct gk104_fifo *fifo = (void *)object; int ret, i; - ret = nvkm_fifo_init(&priv->base); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; /* enable all available PBDMA units */ - nv_wr32(priv, 0x000204, 0xffffffff); - priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204)); - nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr); + nv_wr32(fifo, 0x000204, 0xffffffff); + fifo->spoon_nr = hweight32(nv_rd32(fifo, 0x000204)); + nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* PBDMA[n] */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + for (i = 0; i < fifo->spoon_nr; i++) { + nv_mask(fifo, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nv_wr32(fifo, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(fifo, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } /* PBDMA[n].HCE */ - for (i = 0; i < priv->spoon_nr; i++) { - nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ + for (i = 0; i < fifo->spoon_nr; i++) { + nv_wr32(fifo, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ + nv_wr32(fifo, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ } - nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12); + nv_wr32(fifo, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0x7fffffff); + nv_wr32(fifo, 0x002100, 0xffffffff); + nv_wr32(fifo, 0x002140, 0x7fffffff); return 0; } void gk104_fifo_dtor(struct nvkm_object *object) { - struct gk104_fifo_priv *priv = (void *)object; + struct gk104_fifo *fifo = (void *)object; int i; - nvkm_gpuobj_unmap(&priv->user.bar); - nvkm_gpuobj_ref(NULL, &priv->user.mem); + nvkm_gpuobj_unmap(&fifo->user.bar); + nvkm_gpuobj_ref(NULL, &fifo->user.mem); for (i = 0; i < FIFO_ENGINE_NR; i++) { - nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[1]); - nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[0]); + nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[1]); + nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[0]); } - nvkm_fifo_destroy(&priv->base); + nvkm_fifo_destroy(&fifo->base); } int @@ -1080,49 +1092,49 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct gk104_fifo_impl *impl = (void *)oclass; - struct gk104_fifo_priv *priv; + struct gk104_fifo *fifo; int ret, i; ret = nvkm_fifo_create(parent, engine, oclass, 0, - impl->channels - 1, &priv); - *pobject = nv_object(priv); + impl->channels - 1, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - INIT_WORK(&priv->fault, gk104_fifo_recover_work); + INIT_WORK(&fifo->fault, gk104_fifo_recover_work); for (i = 0; i < FIFO_ENGINE_NR; i++) { - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, - 0, &priv->engine[i].runlist[0]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000, + 0, &fifo->engine[i].runlist[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000, - 0, &priv->engine[i].runlist[1]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000, + 0, &fifo->engine[i].runlist[1]); if (ret) return ret; - init_waitqueue_head(&priv->engine[i].wait); + init_waitqueue_head(&fifo->engine[i].wait); } - ret = nvkm_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, impl->channels * 0x200, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &fifo->user.mem); if (ret) return ret; - ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW, - &priv->user.bar); + ret = nvkm_gpuobj_map(fifo->user.mem, NV_MEM_ACCESS_RW, + &fifo->user.bar); if (ret) return ret; - ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &priv->base.uevent); + ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &fifo->base.uevent); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = gk104_fifo_intr; - nv_engine(priv)->cclass = &gk104_fifo_cclass; - nv_engine(priv)->sclass = gk104_fifo_sclass; + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = gk104_fifo_intr; + nv_engine(fifo)->cclass = &gk104_fifo_cclass; + nv_engine(fifo)->sclass = gk104_fifo_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c index 7596587b0e7c1..6a93b911e8a8b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c @@ -38,8 +38,8 @@ gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, { int ret = gk104_fifo_ctor(parent, engine, oclass, data, size, pobject); if (ret == 0) { - struct gk104_fifo_priv *priv = (void *)*pobject; - nv_engine(priv)->sclass = gm204_fifo_sclass; + struct gk104_fifo *fifo = (void *)*pobject; + nv_engine(fifo)->sclass = gm204_fifo_sclass; } return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index bdf635f9ab5f2..91a2080bdaf97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -54,7 +54,7 @@ int nv04_fifo_object_attach(struct nvkm_object *parent, struct nvkm_object *object, u32 handle) { - struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; u32 context, chid = chan->base.chid; int ret; @@ -82,19 +82,19 @@ nv04_fifo_object_attach(struct nvkm_object *parent, context |= 0x80000000; /* valid */ context |= chid << 24; - mutex_lock(&nv_subdev(priv)->mutex); - ret = nvkm_ramht_insert(priv->ramht, chid, handle, context); - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_lock(&nv_subdev(fifo)->mutex); + ret = nvkm_ramht_insert(fifo->ramht, chid, handle, context); + mutex_unlock(&nv_subdev(fifo)->mutex); return ret; } void nv04_fifo_object_detach(struct nvkm_object *parent, int cookie) { - struct nv04_fifo_priv *priv = (void *)parent->engine; - mutex_lock(&nv_subdev(priv)->mutex); - nvkm_ramht_remove(priv->ramht, cookie); - mutex_unlock(&nv_subdev(priv)->mutex); + struct nv04_fifo *fifo = (void *)parent->engine; + mutex_lock(&nv_subdev(fifo)->mutex); + nvkm_ramht_remove(fifo->ramht, cookie); + mutex_unlock(&nv_subdev(fifo)->mutex); } int @@ -114,7 +114,7 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo *fifo = (void *)engine; struct nv04_fifo_chan *chan; int ret; @@ -142,10 +142,10 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x10, + nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); + nv_wo32(fifo->ramfc, chan->ramfc + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN @@ -158,12 +158,12 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, void nv04_fifo_chan_dtor(struct nvkm_object *object) { - struct nv04_fifo_priv *priv = (void *)object->engine; + struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; - struct ramfc_desc *c = priv->ramfc_desc; + struct ramfc_desc *c = fifo->ramfc_desc; do { - nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000); + nv_wo32(fifo->ramfc, chan->ramfc + c->ctxp, 0x00000000); } while ((++c)->bits); nvkm_fifo_channel_destroy(&chan->base); @@ -172,7 +172,7 @@ nv04_fifo_chan_dtor(struct nvkm_object *object) int nv04_fifo_chan_init(struct nvkm_object *object) { - struct nv04_fifo_priv *priv = (void *)object->engine; + struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; u32 mask = 1 << chan->base.chid; unsigned long flags; @@ -182,59 +182,59 @@ nv04_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - spin_lock_irqsave(&priv->base.lock, flags); - nv_mask(priv, NV04_PFIFO_MODE, mask, mask); - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); + nv_mask(fifo, NV04_PFIFO_MODE, mask, mask); + spin_unlock_irqrestore(&fifo->base.lock, flags); return 0; } int nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv04_fifo_priv *priv = (void *)object->engine; + struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *fctx = priv->ramfc; + struct nvkm_gpuobj *fctx = fifo->ramfc; struct ramfc_desc *c; unsigned long flags; u32 data = chan->ramfc; u32 chid; /* prevent fifo context switches */ - spin_lock_irqsave(&priv->base.lock, flags); - nv_wr32(priv, NV03_PFIFO_CACHES, 0); + spin_lock_irqsave(&fifo->base.lock, flags); + nv_wr32(fifo, NV03_PFIFO_CACHES, 0); /* if this channel is active, replace it with a null context */ - chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; + chid = nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; if (chid == chan->base.chid) { - nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0); - nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + nv_mask(fifo, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 0); + nv_mask(fifo, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); - c = priv->ramfc_desc; + c = fifo->ramfc_desc; do { u32 rm = ((1ULL << c->bits) - 1) << c->regs; u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; - u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs; + u32 rv = (nv_rd32(fifo, c->regp) & rm) >> c->regs; u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm); nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); } while ((++c)->bits); - c = priv->ramfc_desc; + c = fifo->ramfc_desc; do { - nv_wr32(priv, c->regp, 0x00000000); + nv_wr32(fifo, c->regp, 0x00000000); } while ((++c)->bits); - nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(fifo, NV03_PFIFO_CACHE1_GET, 0); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUT, 0); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); } /* restore normal operation, after disabling dma mode */ - nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); - spin_unlock_irqrestore(&priv->base.lock, flags); + nv_mask(fifo, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); + nv_wr32(fifo, NV03_PFIFO_CACHES, 1); + spin_unlock_irqrestore(&fifo->base.lock, flags); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -297,17 +297,17 @@ nv04_fifo_cclass = { ******************************************************************************/ void -nv04_fifo_pause(struct nvkm_fifo *pfifo, unsigned long *pflags) -__acquires(priv->base.lock) +nv04_fifo_pause(struct nvkm_fifo *obj, unsigned long *pflags) +__acquires(fifo->base.lock) { - struct nv04_fifo_priv *priv = (void *)pfifo; + struct nv04_fifo *fifo = container_of(obj, typeof(*fifo), base); unsigned long flags; - spin_lock_irqsave(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); *pflags = flags; - nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000); - nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); + nv_wr32(fifo, NV03_PFIFO_CACHES, 0x00000000); + nv_mask(fifo, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); /* in some cases the puller may be left in an inconsistent state * if you try to stop it while it's busy translating handles. @@ -318,28 +318,28 @@ __acquires(priv->base.lock) * to avoid this, we invalidate the most recently calculated * instance. */ - if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0, + if (!nv_wait(fifo, NV04_PFIFO_CACHE1_PULL0, NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000)) - nv_warn(priv, "timeout idling puller\n"); + nv_warn(fifo, "timeout idling puller\n"); - if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) & + if (nv_rd32(fifo, NV04_PFIFO_CACHE1_PULL0) & NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) - nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + nv_wr32(fifo, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000); + nv_wr32(fifo, NV04_PFIFO_CACHE1_HASH, 0x00000000); } void -nv04_fifo_start(struct nvkm_fifo *pfifo, unsigned long *pflags) -__releases(priv->base.lock) +nv04_fifo_start(struct nvkm_fifo *obj, unsigned long *pflags) +__releases(fifo->base.lock) { - struct nv04_fifo_priv *priv = (void *)pfifo; + struct nv04_fifo *fifo = container_of(obj, typeof(*fifo), base); unsigned long flags = *pflags; - nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); - nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001); + nv_mask(fifo, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); + nv_wr32(fifo, NV03_PFIFO_CACHES, 0x00000001); - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_unlock_irqrestore(&fifo->base.lock, flags); } static const char * @@ -353,7 +353,7 @@ nv_dma_state_err(u32 state) } static bool -nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) +nv04_fifo_swmthd(struct nv04_fifo *fifo, u32 chid, u32 addr, u32 data) { struct nv04_fifo_chan *chan = NULL; struct nvkm_handle *bind; @@ -363,9 +363,9 @@ nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) unsigned long flags; u32 engine; - spin_lock_irqsave(&priv->base.lock, flags); - if (likely(chid >= priv->base.min && chid <= priv->base.max)) - chan = (void *)priv->base.channel[chid]; + spin_lock_irqsave(&fifo->base.lock, flags); + if (likely(chid >= fifo->base.min && chid <= fifo->base.max)) + chan = (void *)fifo->base.channel[chid]; if (unlikely(!chan)) goto out; @@ -380,13 +380,13 @@ nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) chan->subc[subc] = data; handled = true; - nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0); + nv_mask(fifo, NV04_PFIFO_CACHE1_ENGINE, engine, 0); } nvkm_namedb_put(bind); break; default: - engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE); + engine = nv_rd32(fifo, NV04_PFIFO_CACHE1_ENGINE); if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) break; @@ -400,13 +400,13 @@ nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data) } out: - spin_unlock_irqrestore(&priv->base.lock, flags); + spin_unlock_irqrestore(&fifo->base.lock, flags); return handled; } static void nv04_fifo_cache_error(struct nvkm_device *device, - struct nv04_fifo_priv *priv, u32 chid, u32 get) + struct nv04_fifo *fifo, u32 chid, u32 get) { u32 mthd, data; int ptr; @@ -419,139 +419,139 @@ nv04_fifo_cache_error(struct nvkm_device *device, ptr = (get & 0x7ff) >> 2; if (device->card_type < NV_40) { - mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr)); + mthd = nv_rd32(fifo, NV04_PFIFO_CACHE1_METHOD(ptr)); + data = nv_rd32(fifo, NV04_PFIFO_CACHE1_DATA(ptr)); } else { - mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr)); + mthd = nv_rd32(fifo, NV40_PFIFO_CACHE1_METHOD(ptr)); + data = nv_rd32(fifo, NV40_PFIFO_CACHE1_DATA(ptr)); } - if (!nv04_fifo_swmthd(priv, chid, mthd, data)) { + if (!nv04_fifo_swmthd(fifo, chid, mthd, data)) { const char *client_name = - nvkm_client_name_for_fifo_chid(&priv->base, chid); - nv_error(priv, + nvkm_client_name_for_fifo_chid(&fifo->base, chid); + nv_error(fifo, "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc, data); } - nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0); - nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + nv_wr32(fifo, NV04_PFIFO_CACHE1_DMA_PUSH, 0); + nv_wr32(fifo, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1); - nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, + nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH0) & ~1); + nv_wr32(fifo, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, + nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH0) | 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_HASH, 0); - nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, - nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_DMA_PUSH, + nv_rd32(fifo, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); } static void nv04_fifo_dma_pusher(struct nvkm_device *device, - struct nv04_fifo_priv *priv, u32 chid) + struct nv04_fifo *fifo, u32 chid) { const char *client_name; - u32 dma_get = nv_rd32(priv, 0x003244); - u32 dma_put = nv_rd32(priv, 0x003240); - u32 push = nv_rd32(priv, 0x003220); - u32 state = nv_rd32(priv, 0x003228); + u32 dma_get = nv_rd32(fifo, 0x003244); + u32 dma_put = nv_rd32(fifo, 0x003240); + u32 push = nv_rd32(fifo, 0x003220); + u32 state = nv_rd32(fifo, 0x003228); - client_name = nvkm_client_name_for_fifo_chid(&priv->base, chid); + client_name = nvkm_client_name_for_fifo_chid(&fifo->base, chid); if (device->card_type == NV_50) { - u32 ho_get = nv_rd32(priv, 0x003328); - u32 ho_put = nv_rd32(priv, 0x003320); - u32 ib_get = nv_rd32(priv, 0x003334); - u32 ib_put = nv_rd32(priv, 0x003330); + u32 ho_get = nv_rd32(fifo, 0x003328); + u32 ho_put = nv_rd32(fifo, 0x003320); + u32 ib_get = nv_rd32(fifo, 0x003334); + u32 ib_put = nv_rd32(fifo, 0x003330); - nv_error(priv, + nv_error(fifo, "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", chid, client_name, ho_get, dma_get, ho_put, dma_put, ib_get, ib_put, state, nv_dma_state_err(state), push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ - nv_wr32(priv, 0x003364, 0x00000000); + nv_wr32(fifo, 0x003364, 0x00000000); if (dma_get != dma_put || ho_get != ho_put) { - nv_wr32(priv, 0x003244, dma_put); - nv_wr32(priv, 0x003328, ho_put); + nv_wr32(fifo, 0x003244, dma_put); + nv_wr32(fifo, 0x003328, ho_put); } else if (ib_get != ib_put) - nv_wr32(priv, 0x003334, ib_put); + nv_wr32(fifo, 0x003334, ib_put); } else { - nv_error(priv, + nv_error(fifo, "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", chid, client_name, dma_get, dma_put, state, nv_dma_state_err(state), push); if (dma_get != dma_put) - nv_wr32(priv, 0x003244, dma_put); + nv_wr32(fifo, 0x003244, dma_put); } - nv_wr32(priv, 0x003228, 0x00000000); - nv_wr32(priv, 0x003220, 0x00000001); - nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); + nv_wr32(fifo, 0x003228, 0x00000000); + nv_wr32(fifo, 0x003220, 0x00000001); + nv_wr32(fifo, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); } void nv04_fifo_intr(struct nvkm_subdev *subdev) { struct nvkm_device *device = nv_device(subdev); - struct nv04_fifo_priv *priv = (void *)subdev; - u32 mask = nv_rd32(priv, NV03_PFIFO_INTR_EN_0); - u32 stat = nv_rd32(priv, NV03_PFIFO_INTR_0) & mask; + struct nv04_fifo *fifo = (void *)subdev; + u32 mask = nv_rd32(fifo, NV03_PFIFO_INTR_EN_0); + u32 stat = nv_rd32(fifo, NV03_PFIFO_INTR_0) & mask; u32 reassign, chid, get, sem; - reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1; - nv_wr32(priv, NV03_PFIFO_CACHES, 0); + reassign = nv_rd32(fifo, NV03_PFIFO_CACHES) & 1; + nv_wr32(fifo, NV03_PFIFO_CACHES, 0); - chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max; - get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET); + chid = nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; + get = nv_rd32(fifo, NV03_PFIFO_CACHE1_GET); if (stat & NV_PFIFO_INTR_CACHE_ERROR) { - nv04_fifo_cache_error(device, priv, chid, get); + nv04_fifo_cache_error(device, fifo, chid, get); stat &= ~NV_PFIFO_INTR_CACHE_ERROR; } if (stat & NV_PFIFO_INTR_DMA_PUSHER) { - nv04_fifo_dma_pusher(device, priv, chid); + nv04_fifo_dma_pusher(device, fifo, chid); stat &= ~NV_PFIFO_INTR_DMA_PUSHER; } if (stat & NV_PFIFO_INTR_SEMAPHORE) { stat &= ~NV_PFIFO_INTR_SEMAPHORE; - nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); + nv_wr32(fifo, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); - sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE); - nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + sem = nv_rd32(fifo, NV10_PFIFO_CACHE1_SEMAPHORE); + nv_wr32(fifo, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); - nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(fifo, NV03_PFIFO_CACHE1_GET, get + 4); + nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); } if (device->card_type == NV_50) { if (stat & 0x00000010) { stat &= ~0x00000010; - nv_wr32(priv, 0x002100, 0x00000010); + nv_wr32(fifo, 0x002100, 0x00000010); } if (stat & 0x40000000) { - nv_wr32(priv, 0x002100, 0x40000000); - nvkm_fifo_uevent(&priv->base); + nv_wr32(fifo, 0x002100, 0x40000000); + nvkm_fifo_uevent(&fifo->base); stat &= ~0x40000000; } } if (stat) { - nv_warn(priv, "unknown intr 0x%08x\n", stat); - nv_mask(priv, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); - nv_wr32(priv, NV03_PFIFO_INTR_0, stat); + nv_warn(fifo, "unknown intr 0x%08x\n", stat); + nv_mask(fifo, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); + nv_wr32(fifo, NV03_PFIFO_INTR_0, stat); } - nv_wr32(priv, NV03_PFIFO_CACHES, reassign); + nv_wr32(fifo, NV03_PFIFO_CACHES, reassign); } static int @@ -560,65 +560,65 @@ nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv04_instmem *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; + struct nv04_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv04_fifo_cclass; - nv_engine(priv)->sclass = nv04_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv04_ramfc; + nvkm_ramht_ref(imem->ramht, &fifo->ramht); + nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); + nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv04_fifo_cclass; + nv_engine(fifo)->sclass = nv04_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv04_ramfc; return 0; } void nv04_fifo_dtor(struct nvkm_object *object) { - struct nv04_fifo_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->ramfc); - nvkm_gpuobj_ref(NULL, &priv->ramro); - nvkm_ramht_ref(NULL, &priv->ramht); - nvkm_fifo_destroy(&priv->base); + struct nv04_fifo *fifo = (void *)object; + nvkm_gpuobj_ref(NULL, &fifo->ramfc); + nvkm_gpuobj_ref(NULL, &fifo->ramro); + nvkm_ramht_ref(NULL, &fifo->ramht); + nvkm_fifo_destroy(&fifo->base); } int nv04_fifo_init(struct nvkm_object *object) { - struct nv04_fifo_priv *priv = (void *)object; + struct nv04_fifo *fifo = (void *)object; int ret; - ret = nvkm_fifo_init(&priv->base); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + nv_wr32(fifo, NV04_PFIFO_DELAY_0, 0x000000ff); + nv_wr32(fifo, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((priv->ramht->bits - 9) << 16) | - (priv->ramht->gpuobj.addr >> 8)); - nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8); + nv_wr32(fifo, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((fifo->ramht->bits - 9) << 16) | + (fifo->ramht->gpuobj.addr >> 8)); + nv_wr32(fifo, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); + nv_wr32(fifo, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nv_wr32(fifo, NV03_PFIFO_INTR_0, 0xffffffff); + nv_wr32(fifo, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(fifo, NV03_PFIFO_CACHES, 1); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h index e0e0c47cb4ca6..cb4ec7bd7c51d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h @@ -139,7 +139,7 @@ struct ramfc_desc { unsigned regp; }; -struct nv04_fifo_priv { +struct nv04_fifo { struct nvkm_fifo base; struct ramfc_desc *ramfc_desc; struct nvkm_ramht *ramht; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 3537accc927bf..7c31c31edd9a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -58,7 +58,7 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo *fifo = (void *)engine; struct nv04_fifo_chan *chan; int ret; @@ -86,10 +86,10 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x14, + nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nv_wo32(fifo->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN @@ -144,25 +144,25 @@ nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv04_instmem *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; + struct nv04_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv10_fifo_cclass; - nv_engine(priv)->sclass = nv10_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv10_ramfc; + nvkm_ramht_ref(imem->ramht, &fifo->ramht); + nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); + nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv10_fifo_cclass; + nv_engine(fifo)->sclass = nv10_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv10_ramfc; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index e9c88da81f107..6f8787fbacc00 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -63,7 +63,7 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo *fifo = (void *)engine; struct nv04_fifo_chan *chan; int ret; @@ -93,10 +93,10 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 64; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x14, + nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nv_wo32(fifo->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN @@ -151,55 +151,55 @@ nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv04_instmem *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; + struct nv04_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv17_fifo_cclass; - nv_engine(priv)->sclass = nv17_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv17_ramfc; + nvkm_ramht_ref(imem->ramht, &fifo->ramht); + nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); + nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv17_fifo_cclass; + nv_engine(fifo)->sclass = nv17_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv17_ramfc; return 0; } static int nv17_fifo_init(struct nvkm_object *object) { - struct nv04_fifo_priv *priv = (void *)object; + struct nv04_fifo *fifo = (void *)object; int ret; - ret = nvkm_fifo_init(&priv->base); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + nv_wr32(fifo, NV04_PFIFO_DELAY_0, 0x000000ff); + nv_wr32(fifo, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((priv->ramht->bits - 9) << 16) | - (priv->ramht->gpuobj.addr >> 8)); - nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); - nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000); + nv_wr32(fifo, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((fifo->ramht->bits - 9) << 16) | + (fifo->ramht->gpuobj.addr >> 8)); + nv_wr32(fifo, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); + nv_wr32(fifo, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8 | 0x00010000); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nv_wr32(fifo, NV03_PFIFO_INTR_0, 0xffffffff); + nv_wr32(fifo, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(fifo, NV03_PFIFO_CACHES, 1); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index f9456a5c762c3..4c1ed3f29e6bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -67,7 +67,7 @@ static int nv40_fifo_object_attach(struct nvkm_object *parent, struct nvkm_object *object, u32 handle) { - struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; u32 context, chid = chan->base.chid; int ret; @@ -94,16 +94,16 @@ nv40_fifo_object_attach(struct nvkm_object *parent, context |= chid << 23; - mutex_lock(&nv_subdev(priv)->mutex); - ret = nvkm_ramht_insert(priv->ramht, chid, handle, context); - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_lock(&nv_subdev(fifo)->mutex); + ret = nvkm_ramht_insert(fifo->ramht, chid, handle, context); + mutex_unlock(&nv_subdev(fifo)->mutex); return ret; } static int nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) { - struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; unsigned long flags; u32 reg, ctx; @@ -123,16 +123,16 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) return -EINVAL; } - spin_lock_irqsave(&priv->base.lock, flags); + spin_lock_irqsave(&fifo->base.lock, flags); nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; - nv_mask(priv, 0x002500, 0x00000001, 0x00000000); + nv_mask(fifo, 0x002500, 0x00000001, 0x00000000); - if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) - nv_wr32(priv, reg, nv_engctx(engctx)->addr); - nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + if ((nv_rd32(fifo, 0x003204) & fifo->base.max) == chan->base.chid) + nv_wr32(fifo, reg, nv_engctx(engctx)->addr); + nv_wo32(fifo->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); - nv_mask(priv, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->base.lock, flags); + nv_mask(fifo, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&fifo->base.lock, flags); return 0; } @@ -140,7 +140,7 @@ static int nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *engctx) { - struct nv04_fifo_priv *priv = (void *)parent->engine; + struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; unsigned long flags; u32 reg, ctx; @@ -160,15 +160,15 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - spin_lock_irqsave(&priv->base.lock, flags); - nv_mask(priv, 0x002500, 0x00000001, 0x00000000); + spin_lock_irqsave(&fifo->base.lock, flags); + nv_mask(fifo, 0x002500, 0x00000001, 0x00000000); - if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid) - nv_wr32(priv, reg, 0x00000000); - nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000); + if ((nv_rd32(fifo, 0x003204) & fifo->base.max) == chan->base.chid) + nv_wr32(fifo, reg, 0x00000000); + nv_wo32(fifo->ramfc, chan->ramfc + ctx, 0x00000000); - nv_mask(priv, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->base.lock, flags); + nv_mask(fifo, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&fifo->base.lock, flags); return 0; } @@ -180,7 +180,7 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo_priv *priv = (void *)engine; + struct nv04_fifo *fifo = (void *)engine; struct nv04_fifo_chan *chan; int ret; @@ -210,17 +210,17 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_parent(chan)->object_detach = nv04_fifo_object_detach; chan->ramfc = chan->base.chid * 128; - nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 | + nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nv_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nv_wo32(fifo->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + nv_wo32(fifo->ramfc, chan->ramfc + 0x3c, 0x0001ffff); return 0; } @@ -269,77 +269,77 @@ nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv04_instmem *imem = nv04_instmem(parent); - struct nv04_fifo_priv *priv; + struct nv04_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &priv->ramht); - nvkm_gpuobj_ref(imem->ramro, &priv->ramro); - nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc); - - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv40_fifo_cclass; - nv_engine(priv)->sclass = nv40_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; - priv->ramfc_desc = nv40_ramfc; + nvkm_ramht_ref(imem->ramht, &fifo->ramht); + nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); + nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv40_fifo_cclass; + nv_engine(fifo)->sclass = nv40_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv40_ramfc; return 0; } static int nv40_fifo_init(struct nvkm_object *object) { - struct nv04_fifo_priv *priv = (void *)object; + struct nv04_fifo *fifo = (void *)object; struct nvkm_fb *fb = nvkm_fb(object); int ret; - ret = nvkm_fifo_init(&priv->base); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(priv, 0x002040, 0x000000ff); - nv_wr32(priv, 0x002044, 0x2101ffff); - nv_wr32(priv, 0x002058, 0x00000001); + nv_wr32(fifo, 0x002040, 0x000000ff); + nv_wr32(fifo, 0x002044, 0x2101ffff); + nv_wr32(fifo, 0x002058, 0x00000001); - nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((priv->ramht->bits - 9) << 16) | - (priv->ramht->gpuobj.addr >> 8)); - nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8); + nv_wr32(fifo, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + ((fifo->ramht->bits - 9) << 16) | + (fifo->ramht->gpuobj.addr >> 8)); + nv_wr32(fifo, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); - switch (nv_device(priv)->chipset) { + switch (nv_device(fifo)->chipset) { case 0x47: case 0x49: case 0x4b: - nv_wr32(priv, 0x002230, 0x00000001); + nv_wr32(fifo, 0x002230, 0x00000001); case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: case 0x48: - nv_wr32(priv, 0x002220, 0x00030002); + nv_wr32(fifo, 0x002220, 0x00030002); break; default: - nv_wr32(priv, 0x002230, 0x00000000); - nv_wr32(priv, 0x002220, ((fb->ram->size - 512 * 1024 + - priv->ramfc->addr) >> 16) | + nv_wr32(fifo, 0x002230, 0x00000000); + nv_wr32(fifo, 0x002220, ((fb->ram->size - 512 * 1024 + + fifo->ramfc->addr) >> 16) | 0x00030000); break; } - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nv_wr32(fifo, NV03_PFIFO_INTR_0, 0xffffffff); + nv_wr32(fifo, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(priv, NV03_PFIFO_CACHES, 1); + nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); + nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); + nv_wr32(fifo, NV03_PFIFO_CACHES, 1); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index f25f0fd0655d5..a36f7efc46588 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -39,33 +39,33 @@ ******************************************************************************/ static void -nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv) +nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_bar *bar = nvkm_bar(fifo); struct nvkm_gpuobj *cur; int i, p; - cur = priv->playlist[priv->cur_playlist]; - priv->cur_playlist = !priv->cur_playlist; + cur = fifo->playlist[fifo->cur_playlist]; + fifo->cur_playlist = !fifo->cur_playlist; - for (i = priv->base.min, p = 0; i < priv->base.max; i++) { - if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000) + for (i = fifo->base.min, p = 0; i < fifo->base.max; i++) { + if (nv_rd32(fifo, 0x002600 + (i * 4)) & 0x80000000) nv_wo32(cur, p++ * 4, i); } bar->flush(bar); - nv_wr32(priv, 0x0032f4, cur->addr >> 12); - nv_wr32(priv, 0x0032ec, p); - nv_wr32(priv, 0x002500, 0x00000101); + nv_wr32(fifo, 0x0032f4, cur->addr >> 12); + nv_wr32(fifo, 0x0032ec, p); + nv_wr32(fifo, 0x002500, 0x00000101); } void -nv50_fifo_playlist_update(struct nv50_fifo_priv *priv) +nv50_fifo_playlist_update(struct nv50_fifo *fifo) { - mutex_lock(&nv_subdev(priv)->mutex); - nv50_fifo_playlist_update_locked(priv); - mutex_unlock(&nv_subdev(priv)->mutex); + mutex_lock(&nv_subdev(fifo)->mutex); + nv50_fifo_playlist_update_locked(fifo); + mutex_unlock(&nv_subdev(fifo)->mutex); } static int @@ -103,7 +103,7 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { struct nvkm_bar *bar = nvkm_bar(parent); - struct nv50_fifo_priv *priv = (void *)parent->engine; + struct nv50_fifo *fifo = (void *)parent->engine; struct nv50_fifo_base *base = (void *)parent->parent; struct nv50_fifo_chan *chan = (void *)parent; u32 addr, me; @@ -129,17 +129,17 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, * there's also a "ignore these engines" bitmask reg we can use * if we hit the issue there.. */ - me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001); + me = nv_mask(fifo, 0x00b860, 0x00000001, 0x00000001); /* do the kickoff... */ - nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12); - if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) { - nv_error(priv, "channel %d [%s] unload timeout\n", + nv_wr32(fifo, 0x0032fc, nv_gpuobj(base)->addr >> 12); + if (!nv_wait_ne(fifo, 0x0032fc, 0xffffffff, 0xffffffff)) { + nv_error(fifo, "channel %d [%s] unload timeout\n", chan->base.chid, nvkm_client_name(chan)); if (suspend) ret = -EBUSY; } - nv_wr32(priv, 0x00b860, me); + nv_wr32(fifo, 0x00b860, me); if (ret == 0) { nv_wo32(base->eng, addr + 0x00, 0x00000000); @@ -320,7 +320,7 @@ nv50_fifo_chan_dtor(struct nvkm_object *object) static int nv50_fifo_chan_init(struct nvkm_object *object) { - struct nv50_fifo_priv *priv = (void *)object->engine; + struct nv50_fifo *fifo = (void *)object->engine; struct nv50_fifo_base *base = (void *)object->parent; struct nv50_fifo_chan *chan = (void *)object; struct nvkm_gpuobj *ramfc = base->ramfc; @@ -331,22 +331,22 @@ nv50_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); - nv50_fifo_playlist_update(priv); + nv_wr32(fifo, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); + nv50_fifo_playlist_update(fifo); return 0; } int nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv50_fifo_priv *priv = (void *)object->engine; + struct nv50_fifo *fifo = (void *)object->engine; struct nv50_fifo_chan *chan = (void *)object; u32 chid = chan->base.chid; /* remove channel from playlist, fifo will unload context */ - nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000); - nv50_fifo_playlist_update(priv); - nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000); + nv_mask(fifo, 0x002600 + (chid * 4), 0x80000000, 0x00000000); + nv50_fifo_playlist_update(fifo); + nv_wr32(fifo, 0x002600 + (chid * 4), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -456,69 +456,69 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_fifo_priv *priv; + struct nv50_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv); - *pobject = nv_object(priv); + ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &fifo); + *pobject = nv_object(fifo); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[0]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, + &fifo->playlist[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0, - &priv->playlist[1]); + ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, + &fifo->playlist[1]); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000100; - nv_subdev(priv)->intr = nv04_fifo_intr; - nv_engine(priv)->cclass = &nv50_fifo_cclass; - nv_engine(priv)->sclass = nv50_fifo_sclass; - priv->base.pause = nv04_fifo_pause; - priv->base.start = nv04_fifo_start; + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv50_fifo_cclass; + nv_engine(fifo)->sclass = nv50_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; return 0; } void nv50_fifo_dtor(struct nvkm_object *object) { - struct nv50_fifo_priv *priv = (void *)object; + struct nv50_fifo *fifo = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->playlist[1]); - nvkm_gpuobj_ref(NULL, &priv->playlist[0]); + nvkm_gpuobj_ref(NULL, &fifo->playlist[1]); + nvkm_gpuobj_ref(NULL, &fifo->playlist[0]); - nvkm_fifo_destroy(&priv->base); + nvkm_fifo_destroy(&fifo->base); } int nv50_fifo_init(struct nvkm_object *object) { - struct nv50_fifo_priv *priv = (void *)object; + struct nv50_fifo *fifo = (void *)object; int ret, i; - ret = nvkm_fifo_init(&priv->base); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_mask(priv, 0x000200, 0x00000100, 0x00000000); - nv_mask(priv, 0x000200, 0x00000100, 0x00000100); - nv_wr32(priv, 0x00250c, 0x6f3cfc34); - nv_wr32(priv, 0x002044, 0x01003fff); + nv_mask(fifo, 0x000200, 0x00000100, 0x00000000); + nv_mask(fifo, 0x000200, 0x00000100, 0x00000100); + nv_wr32(fifo, 0x00250c, 0x6f3cfc34); + nv_wr32(fifo, 0x002044, 0x01003fff); - nv_wr32(priv, 0x002100, 0xffffffff); - nv_wr32(priv, 0x002140, 0xbfffffff); + nv_wr32(fifo, 0x002100, 0xffffffff); + nv_wr32(fifo, 0x002140, 0xbfffffff); for (i = 0; i < 128; i++) - nv_wr32(priv, 0x002600 + (i * 4), 0x00000000); - nv50_fifo_playlist_update_locked(priv); + nv_wr32(fifo, 0x002600 + (i * 4), 0x00000000); + nv50_fifo_playlist_update_locked(fifo); - nv_wr32(priv, 0x003200, 0x00000001); - nv_wr32(priv, 0x003250, 0x00000001); - nv_wr32(priv, 0x002500, 0x00000001); + nv_wr32(fifo, 0x003200, 0x00000001); + nv_wr32(fifo, 0x003250, 0x00000001); + nv_wr32(fifo, 0x002500, 0x00000001); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h index 09ed93c665671..722fcce7070ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h @@ -2,7 +2,7 @@ #define __NV50_FIFO_H__ #include -struct nv50_fifo_priv { +struct nv50_fifo { struct nvkm_fifo base; struct nvkm_gpuobj *playlist[2]; int cur_playlist; @@ -23,7 +23,7 @@ struct nv50_fifo_chan { struct nvkm_ramht *ramht; }; -void nv50_fifo_playlist_update(struct nv50_fifo_priv *); +void nv50_fifo_playlist_update(struct nv50_fifo *); void nv50_fifo_object_detach(struct nvkm_object *, int); void nv50_fifo_chan_dtor(struct nvkm_object *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 1ca9385f5479c..b0b5fadfc550c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1121,7 +1121,7 @@ gf100_gr_ctxctl_isr(struct gf100_gr_priv *priv) static void gf100_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; @@ -1142,7 +1142,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) class = 0x0000; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat & 0x00000001) { /* diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 535f5930c40b1..57f05c86a5913 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -1119,18 +1119,18 @@ static void nv10_gr_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *pfifo = nvkm_fifo(engine); + struct nvkm_fifo *fifo = nvkm_fifo(engine); struct nv10_gr_priv *priv = (void *)engine; unsigned long flags; - pfifo->pause(pfifo, &flags); + fifo->pause(fifo, &flags); nv04_gr_idle(priv); nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit); nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch); nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr); - pfifo->start(pfifo, &flags); + fifo->start(fifo, &flags); } const struct nvkm_bitfield nv10_gr_intr_name[] = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 0aa4cc9f74e1b..14a83f2a8127b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -157,11 +157,11 @@ void nv20_gr_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *pfifo = nvkm_fifo(engine); + struct nvkm_fifo *fifo = nvkm_fifo(engine); struct nv20_gr_priv *priv = (void *)engine; unsigned long flags; - pfifo->pause(pfifo, &flags); + fifo->pause(fifo, &flags); nv04_gr_idle(priv); nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); @@ -181,7 +181,7 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp); } - pfifo->start(pfifo, &flags); + fifo->start(fifo, &flags); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index ed05c6d7875b4..c0a1751a1e88c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -206,11 +206,11 @@ static void nv40_gr_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *pfifo = nvkm_fifo(engine); + struct nvkm_fifo *fifo = nvkm_fifo(engine); struct nv40_gr_priv *priv = (void *)engine; unsigned long flags; - pfifo->pause(pfifo, &flags); + fifo->pause(fifo, &flags); nv04_gr_idle(priv); switch (nv_device(priv)->chipset) { @@ -277,13 +277,13 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) break; } - pfifo->start(pfifo, &flags); + fifo->start(fifo, &flags); } static void nv40_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle = NULL; @@ -301,7 +301,7 @@ nv40_gr_intr(struct nvkm_subdev *subdev) int chid; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat & NV_PGRAPH_INTR_ERROR) { if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index f18b75b883ac8..e232cb8e2f9e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -782,7 +782,7 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, static void nv50_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle = NULL; @@ -798,7 +798,7 @@ nv50_gr_intr(struct nvkm_subdev *subdev) int chid; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat & 0x00000010) { handle = nvkm_handle_get_class(engctx, class); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 891004157ea84..4199684a4b28a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -194,7 +194,7 @@ void nv31_mpeg_intr(struct nvkm_subdev *subdev) { struct nv31_mpeg_priv *priv = (void *)subdev; - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_handle *handle; struct nvkm_object *engctx; u32 stat = nv_rd32(priv, 0x00b100); @@ -227,7 +227,7 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) if (show) { nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", - pfifo->chid(pfifo, engctx), + fifo->chid(fifo, engctx), nvkm_client_name(engctx), stat, type, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 4720ac8844688..aeed7f850f657 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -93,7 +93,7 @@ nv44_mpeg_cclass = { static void nv44_mpeg_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; @@ -107,7 +107,7 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) int chid; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat & 0x01000000) { /* happens on initial binding of the object */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index 9d5c1b8b1f8c3..a598d6dbff46a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -75,7 +75,7 @@ static const struct nvkm_enum g98_sec_isr_error_name[] = { static void g98_sec_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *pfifo = nvkm_fifo(subdev); + struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct g98_sec_priv *priv = (void *)subdev; @@ -90,7 +90,7 @@ g98_sec_intr(struct nvkm_subdev *subdev) int chid; engctx = nvkm_engctx_get(engine, inst); - chid = pfifo->chid(pfifo, engctx); + chid = fifo->chid(fifo, engctx); if (stat & 0x00000040) { nv_error(priv, "DISPATCH_ERROR ["); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 5dc637840a651..e17135a1ec839 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -297,7 +297,7 @@ calc_host(struct gt215_clk *clk, struct nvkm_cstate *cstate) int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) { - struct nvkm_fifo *pfifo = nvkm_fifo(clk); + struct nvkm_fifo *fifo = nvkm_fifo(clk); /* halt and idle execution engines */ nv_mask(clk, 0x020060, 0x00070000, 0x00000000); @@ -306,8 +306,8 @@ gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) return -EBUSY; - if (pfifo) - pfifo->pause(pfifo, flags); + if (fifo) + fifo->pause(fifo, flags); if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) return -EIO; @@ -320,10 +320,10 @@ gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) { - struct nvkm_fifo *pfifo = nvkm_fifo(clk); + struct nvkm_fifo *fifo = nvkm_fifo(clk); - if (pfifo && flags) - pfifo->start(pfifo, flags); + if (fifo && flags) + fifo->start(fifo, flags); nv_mask(clk, 0x002504, 0x00000001, 0x00000000); nv_mask(clk, 0x020060, 0x00070000, 0x00040000); -- GitLab From bfee3f3d97db88bfb732735eb4955ad3381ac758 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5349/7006] drm/nouveau/gr: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/gr.h | 8 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild | 35 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 214 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h | 42 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c | 26 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c | 60 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c | 104 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c | 42 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c | 90 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c | 90 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c | 60 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 928 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 20 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 162 +-- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 150 +-- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 164 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c | 170 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c | 26 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 192 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 478 ++++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 222 ++--- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 20 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 20 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 114 +-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 20 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 20 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 264 +++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 440 +++++---- 30 files changed, 2092 insertions(+), 2095 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index c772497cac3e2..74bf2fe9a3ca3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -24,7 +24,7 @@ struct nvkm_gr_chan { #include struct nvkm_gr { - struct nvkm_engine base; + struct nvkm_engine engine; /* Returns chipset-specific counts of units packed into an u64. */ @@ -40,11 +40,11 @@ nvkm_gr(void *obj) #define nvkm_gr_create(p,e,c,y,d) \ nvkm_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d)) #define nvkm_gr_destroy(d) \ - nvkm_engine_destroy(&(d)->base) + nvkm_engine_destroy(&(d)->engine) #define nvkm_gr_init(d) \ - nvkm_engine_init(&(d)->base) + nvkm_engine_init(&(d)->engine) #define nvkm_gr_fini(d,s) \ - nvkm_engine_fini(&(d)->base, (s)) + nvkm_engine_fini(&(d)->engine, (s)) #define _nvkm_gr_dtor _nvkm_engine_dtor #define _nvkm_gr_init _nvkm_engine_init diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index e91b4dfc0bf3c..cbdab5a686aff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -1,20 +1,3 @@ -nvkm-y += nvkm/engine/gr/ctxnv40.o -nvkm-y += nvkm/engine/gr/ctxnv50.o -nvkm-y += nvkm/engine/gr/ctxgf100.o -nvkm-y += nvkm/engine/gr/ctxgf108.o -nvkm-y += nvkm/engine/gr/ctxgf104.o -nvkm-y += nvkm/engine/gr/ctxgf110.o -nvkm-y += nvkm/engine/gr/ctxgf117.o -nvkm-y += nvkm/engine/gr/ctxgf119.o -nvkm-y += nvkm/engine/gr/ctxgk104.o -nvkm-y += nvkm/engine/gr/ctxgk20a.o -nvkm-y += nvkm/engine/gr/ctxgk110.o -nvkm-y += nvkm/engine/gr/ctxgk110b.o -nvkm-y += nvkm/engine/gr/ctxgk208.o -nvkm-y += nvkm/engine/gr/ctxgm107.o -nvkm-y += nvkm/engine/gr/ctxgm204.o -nvkm-y += nvkm/engine/gr/ctxgm206.o -nvkm-y += nvkm/engine/gr/ctxgm20b.o nvkm-y += nvkm/engine/gr/nv04.o nvkm-y += nvkm/engine/gr/nv10.o nvkm-y += nvkm/engine/gr/nv20.o @@ -40,3 +23,21 @@ nvkm-y += nvkm/engine/gr/gm107.o nvkm-y += nvkm/engine/gr/gm204.o nvkm-y += nvkm/engine/gr/gm206.o nvkm-y += nvkm/engine/gr/gm20b.o + +nvkm-y += nvkm/engine/gr/ctxnv40.o +nvkm-y += nvkm/engine/gr/ctxnv50.o +nvkm-y += nvkm/engine/gr/ctxgf100.o +nvkm-y += nvkm/engine/gr/ctxgf108.o +nvkm-y += nvkm/engine/gr/ctxgf104.o +nvkm-y += nvkm/engine/gr/ctxgf110.o +nvkm-y += nvkm/engine/gr/ctxgf117.o +nvkm-y += nvkm/engine/gr/ctxgf119.o +nvkm-y += nvkm/engine/gr/ctxgk104.o +nvkm-y += nvkm/engine/gr/ctxgk20a.o +nvkm-y += nvkm/engine/gr/ctxgk110.o +nvkm-y += nvkm/engine/gr/ctxgk110b.o +nvkm-y += nvkm/engine/gr/ctxgk208.o +nvkm-y += nvkm/engine/gr/ctxgm107.o +nvkm-y += nvkm/engine/gr/ctxgm204.o +nvkm-y += nvkm/engine/gr/ctxgm206.o +nvkm-y += nvkm/engine/gr/ctxgm20b.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 57e2c5b131238..22bc4dbd46dfc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1021,13 +1021,13 @@ gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, return; } - nv_wr32(info->priv, addr, data); + nv_wr32(info->gr, addr, data); } void gf100_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); @@ -1040,7 +1040,7 @@ gf100_grctx_generate_bundle(struct gf100_grctx *info) void gf100_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); @@ -1053,13 +1053,13 @@ gf100_grctx_generate_pagepool(struct gf100_grctx *info) void gf100_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(gr); const u32 attrib = impl->attrib_nr; const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); int gpc, tpc; u32 bo = 0; @@ -1067,8 +1067,8 @@ gf100_grctx_generate_attrib(struct gf100_grctx *info) mmio_refn(info, 0x419848, 0x10000000, s, b); mmio_wr32(info, 0x405830, (attrib << 16)); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { const u32 o = TPC_UNIT(gpc, tpc, 0x0520); mmio_skip(info, o, (attrib << 16) | ++bo); mmio_wr32(info, o, (attrib << 16) | --bo); @@ -1078,67 +1078,67 @@ gf100_grctx_generate_attrib(struct gf100_grctx *info) } void -gf100_grctx_generate_unkn(struct gf100_gr_priv *priv) +gf100_grctx_generate_unkn(struct gf100_gr *gr) { } void -gf100_grctx_generate_tpcid(struct gf100_gr_priv *priv) +gf100_grctx_generate_tpcid(struct gf100_gr *gr) { int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tpc < priv->tpc_nr[gpc]) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + if (tpc < gr->tpc_nr[gpc]) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x698), id); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x4e8), id); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x088), id); id++; } - nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); } } } void -gf100_grctx_generate_r406028(struct gf100_gr_priv *priv) +gf100_grctx_generate_r406028(struct gf100_gr *gr) { u32 tmp[GPC_MAX / 8] = {}, i = 0; - for (i = 0; i < priv->gpc_nr; i++) - tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4); + for (i = 0; i < gr->gpc_nr; i++) + tmp[i / 8] |= gr->tpc_nr[i] << ((i % 8) * 4); for (i = 0; i < 4; i++) { - nv_wr32(priv, 0x406028 + (i * 4), tmp[i]); - nv_wr32(priv, 0x405870 + (i * 4), tmp[i]); + nv_wr32(gr, 0x406028 + (i * 4), tmp[i]); + nv_wr32(gr, 0x405870 + (i * 4), tmp[i]); } } void -gf100_grctx_generate_r4060a8(struct gf100_gr_priv *priv) +gf100_grctx_generate_r4060a8(struct gf100_gr *gr) { u8 tpcnr[GPC_MAX], data[TPC_MAX]; int gpc, tpc, i; - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); memset(data, 0x1f, sizeof(data)); gpc = -1; - for (tpc = 0; tpc < priv->tpc_total; tpc++) { + for (tpc = 0; tpc < gr->tpc_total; tpc++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; data[tpc] = gpc; } for (i = 0; i < 4; i++) - nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + nv_wr32(gr, 0x4060a8 + (i * 4), ((u32 *)data)[i]); } void -gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) +gf100_grctx_generate_r418bb8(struct gf100_gr *gr) { u32 data[6] = {}, data2[2] = {}; u8 tpcnr[GPC_MAX]; @@ -1146,12 +1146,12 @@ gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) int gpc, tpc, i; /* calculate first set of magics */ - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); gpc = -1; - for (tpc = 0; tpc < priv->tpc_total; tpc++) { + for (tpc = 0; tpc < gr->tpc_total; tpc++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; @@ -1163,7 +1163,7 @@ gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) /* and the second... */ shift = 0; - ntpcv = priv->tpc_total; + ntpcv = gr->tpc_total; while (!(ntpcv & (1 << 4))) { ntpcv <<= 1; shift++; @@ -1176,95 +1176,95 @@ gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nv_wr32(gr, 0x418bb8, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x418b08 + (i * 4), data[i]); + nv_wr32(gr, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) | - priv->magic_not_rop_nr | data2[0]); - nv_wr32(priv, 0x419be4, data2[1]); + nv_wr32(gr, 0x419bd0, (gr->tpc_total << 8) | + gr->magic_not_rop_nr | data2[0]); + nv_wr32(gr, 0x419be4, data2[1]); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x419b00 + (i * 4), data[i]); + nv_wr32(gr, 0x419b00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nv_wr32(gr, 0x4078bc, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x40780c + (i * 4), data[i]); + nv_wr32(gr, 0x40780c + (i * 4), data[i]); } void -gf100_grctx_generate_r406800(struct gf100_gr_priv *priv) +gf100_grctx_generate_r406800(struct gf100_gr *gr) { u64 tpc_mask = 0, tpc_set = 0; u8 tpcnr[GPC_MAX]; int gpc, tpc; int i, a, b; - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) - tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) + tpc_mask |= ((1ULL << gr->tpc_nr[gpc]) - 1) << (gpc * 8); for (i = 0, gpc = -1, b = -1; i < 32; i++) { - a = (i * (priv->tpc_total - 1)) / 32; + a = (i * (gr->tpc_total - 1)) / 32; if (a != b) { b = a; do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; tpc_set |= 1ULL << ((gpc * 8) + tpc); } - nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); - nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask)); - if (priv->gpc_nr > 4) { - nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set)); - nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask)); + nv_wr32(gr, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); + nv_wr32(gr, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask)); + if (gr->gpc_nr > 4) { + nv_wr32(gr, 0x406804 + (i * 0x20), upper_32_bits(tpc_set)); + nv_wr32(gr, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask)); } } } void -gf100_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, oclass->hub); + gf100_gr_mmio(gr, oclass->gpc); + gf100_gr_mmio(gr, oclass->zcull); + gf100_gr_mmio(gr, oclass->tpc); + gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nv_wr32(gr, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); oclass->attrib(info); - oclass->unkn(priv); - - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gf100_grctx_generate_r4060a8(priv); - gf100_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); - - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + oclass->unkn(gr); + + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gf100_grctx_generate_r4060a8(gr); + gf100_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); + + gf100_gr_icmd(gr, oclass->icmd); + nv_wr32(gr, 0x404154, 0x00000400); + gf100_gr_mthd(gr, oclass->mthd); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); } int -gf100_grctx_generate(struct gf100_gr_priv *priv) +gf100_grctx_generate(struct gf100_gr *gr) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; - struct nvkm_bar *bar = nvkm_bar(priv); + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + struct nvkm_bar *bar = nvkm_bar(gr); struct nvkm_gpuobj *chan; struct gf100_grctx info; int ret, i; @@ -1272,10 +1272,10 @@ gf100_grctx_generate(struct gf100_gr_priv *priv) /* allocate memory to for a "channel", which we'll use to generate * the default context values */ - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size, + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x80000 + gr->size, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan); if (ret) { - nv_error(priv, "failed to allocate channel memory, %d\n", ret); + nv_error(gr, "failed to allocate channel memory, %d\n", ret); return ret; } @@ -1302,24 +1302,24 @@ gf100_grctx_generate(struct gf100_gr_priv *priv) bar->flush(bar); - nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8); - nv_wr32(priv, 0x100cbc, 0x80000001); - nv_wait(priv, 0x100c80, 0x00008000, 0x00008000); + nv_wr32(gr, 0x100cb8, (chan->addr + 0x1000) >> 8); + nv_wr32(gr, 0x100cbc, 0x80000001); + nv_wait(gr, 0x100c80, 0x00008000, 0x00008000); /* setup default state for mmio list construction */ - info.priv = priv; - info.data = priv->mmio_data; - info.mmio = priv->mmio_list; + info.gr = gr; + info.data = gr->mmio_data; + info.mmio = gr->mmio_list; info.addr = 0x2000 + (i * 8); info.buffer_nr = 0; /* make channel current */ - if (priv->firmware) { - nv_wr32(priv, 0x409840, 0x00000030); - nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12); - nv_wr32(priv, 0x409504, 0x00000003); - if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010)) - nv_error(priv, "load_ctx timeout\n"); + if (gr->firmware) { + nv_wr32(gr, 0x409840, 0x00000030); + nv_wr32(gr, 0x409500, 0x80000000 | chan->addr >> 12); + nv_wr32(gr, 0x409504, 0x00000003); + if (!nv_wait(gr, 0x409800, 0x00000010, 0x00000010)) + nv_error(gr, "load_ctx timeout\n"); nv_wo32(chan, 0x8001c, 1); nv_wo32(chan, 0x80020, 0); @@ -1327,30 +1327,30 @@ gf100_grctx_generate(struct gf100_gr_priv *priv) nv_wo32(chan, 0x8002c, 0); bar->flush(bar); } else { - nv_wr32(priv, 0x409840, 0x80000000); - nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12); - nv_wr32(priv, 0x409504, 0x00000001); - if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) - nv_error(priv, "HUB_SET_CHAN timeout\n"); + nv_wr32(gr, 0x409840, 0x80000000); + nv_wr32(gr, 0x409500, 0x80000000 | chan->addr >> 12); + nv_wr32(gr, 0x409504, 0x00000001); + if (!nv_wait(gr, 0x409800, 0x80000000, 0x80000000)) + nv_error(gr, "HUB_SET_CHAN timeout\n"); } - oclass->main(priv, &info); + oclass->main(gr, &info); /* trigger a context unload by unsetting the "next channel valid" bit * and faking a context switch interrupt */ - nv_mask(priv, 0x409b04, 0x80000000, 0x00000000); - nv_wr32(priv, 0x409000, 0x00000100); - if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) { - nv_error(priv, "grctx template channel unload timeout\n"); + nv_mask(gr, 0x409b04, 0x80000000, 0x00000000); + nv_wr32(gr, 0x409000, 0x00000100); + if (!nv_wait(gr, 0x409b00, 0x80000000, 0x00000000)) { + nv_error(gr, "grctx template channel unload timeout\n"); ret = -EBUSY; goto done; } - priv->data = kmalloc(priv->size, GFP_KERNEL); - if (priv->data) { - for (i = 0; i < priv->size; i += 4) - priv->data[i / 4] = nv_ro32(chan, 0x80000 + i); + gr->data = kmalloc(gr->size, GFP_KERNEL); + if (gr->data) { + for (i = 0; i < gr->size; i += 4) + gr->data[i / 4] = nv_ro32(chan, 0x80000 + i); ret = 0; } else { ret = -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index f89ab3706cf31..a555835b57893 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -3,7 +3,7 @@ #include "gf100.h" struct gf100_grctx { - struct gf100_gr_priv *priv; + struct gf100_gr *gr; struct gf100_gr_data *data; struct gf100_gr_mmio *mmio; int buffer_nr; @@ -22,9 +22,9 @@ void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int) struct gf100_grctx_oclass { struct nvkm_oclass base; /* main context generation function */ - void (*main)(struct gf100_gr_priv *, struct gf100_grctx *); + void (*main)(struct gf100_gr *, struct gf100_grctx *); /* context-specific modify-on-first-load list generation function */ - void (*unkn)(struct gf100_gr_priv *); + void (*unkn)(struct gf100_gr *); /* mmio context data */ const struct gf100_gr_pack *hub; const struct gf100_gr_pack *gpc; @@ -51,27 +51,27 @@ struct gf100_grctx_oclass { }; static inline const struct gf100_grctx_oclass * -gf100_grctx_impl(struct gf100_gr_priv *priv) +gf100_grctx_impl(struct gf100_gr *gr) { - return (void *)nv_engine(priv)->cclass; + return (void *)nv_engine(gr)->cclass; } extern struct nvkm_oclass *gf100_grctx_oclass; -int gf100_grctx_generate(struct gf100_gr_priv *); -void gf100_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); +int gf100_grctx_generate(struct gf100_gr *); +void gf100_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gf100_grctx_generate_bundle(struct gf100_grctx *); void gf100_grctx_generate_pagepool(struct gf100_grctx *); void gf100_grctx_generate_attrib(struct gf100_grctx *); -void gf100_grctx_generate_unkn(struct gf100_gr_priv *); -void gf100_grctx_generate_tpcid(struct gf100_gr_priv *); -void gf100_grctx_generate_r406028(struct gf100_gr_priv *); -void gf100_grctx_generate_r4060a8(struct gf100_gr_priv *); -void gf100_grctx_generate_r418bb8(struct gf100_gr_priv *); -void gf100_grctx_generate_r406800(struct gf100_gr_priv *); +void gf100_grctx_generate_unkn(struct gf100_gr *); +void gf100_grctx_generate_tpcid(struct gf100_gr *); +void gf100_grctx_generate_r406028(struct gf100_gr *); +void gf100_grctx_generate_r4060a8(struct gf100_gr *); +void gf100_grctx_generate_r418bb8(struct gf100_gr *); +void gf100_grctx_generate_r406800(struct gf100_gr *); extern struct nvkm_oclass *gf108_grctx_oclass; void gf108_grctx_generate_attrib(struct gf100_grctx *); -void gf108_grctx_generate_unkn(struct gf100_gr_priv *); +void gf108_grctx_generate_unkn(struct gf100_gr *); extern struct nvkm_oclass *gf104_grctx_oclass; extern struct nvkm_oclass *gf110_grctx_oclass; @@ -83,12 +83,12 @@ extern struct nvkm_oclass *gf119_grctx_oclass; extern struct nvkm_oclass *gk104_grctx_oclass; extern struct nvkm_oclass *gk20a_grctx_oclass; -void gk104_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); +void gk104_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gk104_grctx_generate_bundle(struct gf100_grctx *); void gk104_grctx_generate_pagepool(struct gf100_grctx *); -void gk104_grctx_generate_unkn(struct gf100_gr_priv *); -void gk104_grctx_generate_r418bb8(struct gf100_gr_priv *); -void gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *); +void gk104_grctx_generate_unkn(struct gf100_gr *); +void gk104_grctx_generate_r418bb8(struct gf100_gr *); +void gk104_grctx_generate_rop_active_fbps(struct gf100_gr *); void gm107_grctx_generate_bundle(struct gf100_grctx *); @@ -105,9 +105,9 @@ void gm107_grctx_generate_pagepool(struct gf100_grctx *); void gm107_grctx_generate_attrib(struct gf100_grctx *); extern struct nvkm_oclass *gm204_grctx_oclass; -void gm204_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *); -void gm204_grctx_generate_tpcid(struct gf100_gr_priv *); -void gm204_grctx_generate_405b60(struct gf100_gr_priv *); +void gm204_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); +void gm204_grctx_generate_tpcid(struct gf100_gr *); +void gm204_grctx_generate_405b60(struct gf100_gr *); extern struct nvkm_oclass *gm206_grctx_oclass; extern struct nvkm_oclass *gm20b_grctx_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c index 87c844a5f34b4..d810a0b97b762 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c @@ -730,18 +730,18 @@ gf108_grctx_pack_tpc[] = { void gf108_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(gr); const u32 alpha = impl->alpha_nr; const u32 beta = impl->attrib_nr; const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + u32 ao = bo + impl->attrib_nr_max * gr->tpc_total; int gpc, tpc; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -749,8 +749,8 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info) mmio_wr32(info, 0x405830, (beta << 16) | alpha); mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { const u32 a = alpha; const u32 b = beta; const u32 t = timeslice_mode; @@ -765,14 +765,14 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info) } void -gf108_grctx_generate_unkn(struct gf100_gr_priv *priv) +gf108_grctx_generate_unkn(struct gf100_gr *gr) { - nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001); - nv_mask(priv, 0x41980c, 0x00000010, 0x00000010); - nv_mask(priv, 0x419814, 0x00000004, 0x00000004); - nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000); - nv_mask(priv, 0x405800, 0x08000000, 0x08000000); - nv_mask(priv, 0x419c00, 0x00000008, 0x00000008); + nv_mask(gr, 0x418c6c, 0x00000001, 0x00000001); + nv_mask(gr, 0x41980c, 0x00000010, 0x00000010); + nv_mask(gr, 0x419814, 0x00000004, 0x00000004); + nv_mask(gr, 0x4064c0, 0x80000000, 0x80000000); + nv_mask(gr, 0x405800, 0x08000000, 0x08000000); + nv_mask(gr, 0x419c00, 0x00000008, 0x00000008); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index 9bbe2c97552e0..7970b9d4b908e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -182,18 +182,18 @@ gf117_grctx_pack_ppc[] = { void gf117_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(gr); const u32 alpha = impl->alpha_nr; const u32 beta = impl->attrib_nr; const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + u32 ao = bo + impl->attrib_nr_max * gr->tpc_total; int gpc, ppc; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -201,55 +201,55 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info) mmio_wr32(info, 0x405830, (beta << 16) | alpha); mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) { - const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc]; - const u32 b = beta * priv->ppc_tpc_nr[gpc][ppc]; + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) { + const u32 a = alpha * gr->ppc_tpc_nr[gpc][ppc]; + const u32 b = beta * gr->ppc_tpc_nr[gpc][ppc]; const u32 t = timeslice_mode; const u32 o = PPC_UNIT(gpc, ppc, 0); mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo); mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo); - bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + bo += impl->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, o + 0xe4, (a << 16) | ao); - ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + ao += impl->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; } } } void -gf117_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int i; - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, oclass->hub); + gf100_gr_mmio(gr, oclass->gpc); + gf100_gr_mmio(gr, oclass->zcull); + gf100_gr_mmio(gr, oclass->tpc); + gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nv_wr32(gr, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); oclass->attrib(info); - oclass->unkn(priv); + oclass->unkn(gr); - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gf100_grctx_generate_r4060a8(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gf100_grctx_generate_r4060a8(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + gf100_gr_icmd(gr, oclass->icmd); + nv_wr32(gr, 0x404154, 0x00000400); + gf100_gr_mthd(gr, oclass->mthd); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index b12f6a9fd9266..7b2a96c6e4966 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -843,7 +843,7 @@ gk104_grctx_pack_ppc[] = { void gk104_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, impl->bundle_size / 0x20); const u32 token_limit = impl->bundle_token_limit; @@ -860,7 +860,7 @@ gk104_grctx_generate_bundle(struct gf100_grctx *info) void gk104_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); @@ -872,18 +872,18 @@ gk104_grctx_generate_pagepool(struct gf100_grctx *info) } void -gk104_grctx_generate_unkn(struct gf100_gr_priv *priv) +gk104_grctx_generate_unkn(struct gf100_gr *gr) { - nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001); - nv_mask(priv, 0x41980c, 0x00000010, 0x00000010); - nv_mask(priv, 0x41be08, 0x00000004, 0x00000004); - nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000); - nv_mask(priv, 0x405800, 0x08000000, 0x08000000); - nv_mask(priv, 0x419c00, 0x00000008, 0x00000008); + nv_mask(gr, 0x418c6c, 0x00000001, 0x00000001); + nv_mask(gr, 0x41980c, 0x00000010, 0x00000010); + nv_mask(gr, 0x41be08, 0x00000004, 0x00000004); + nv_mask(gr, 0x4064c0, 0x80000000, 0x80000000); + nv_mask(gr, 0x405800, 0x08000000, 0x08000000); + nv_mask(gr, 0x419c00, 0x00000008, 0x00000008); } void -gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) +gk104_grctx_generate_r418bb8(struct gf100_gr *gr) { u32 data[6] = {}, data2[2] = {}; u8 tpcnr[GPC_MAX]; @@ -891,12 +891,12 @@ gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) int gpc, tpc, i; /* calculate first set of magics */ - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); gpc = -1; - for (tpc = 0; tpc < priv->tpc_total; tpc++) { + for (tpc = 0; tpc < gr->tpc_total; tpc++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); tpcnr[gpc]--; @@ -908,7 +908,7 @@ gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) /* and the second... */ shift = 0; - ntpcv = priv->tpc_total; + ntpcv = gr->tpc_total; while (!(ntpcv & (1 << 4))) { ntpcv <<= 1; shift++; @@ -921,73 +921,73 @@ gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nv_wr32(gr, 0x418bb8, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x418b08 + (i * 4), data[i]); + nv_wr32(gr, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) | - priv->magic_not_rop_nr | data2[0]); - nv_wr32(priv, 0x41bfe4, data2[1]); + nv_wr32(gr, 0x41bfd0, (gr->tpc_total << 8) | + gr->magic_not_rop_nr | data2[0]); + nv_wr32(gr, 0x41bfe4, data2[1]); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x41bf00 + (i * 4), data[i]); + nv_wr32(gr, 0x41bf00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) | - priv->magic_not_rop_nr); + nv_wr32(gr, 0x4078bc, (gr->tpc_total << 8) | + gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(priv, 0x40780c + (i * 4), data[i]); + nv_wr32(gr, 0x40780c + (i * 4), data[i]); } void -gk104_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv) +gk104_grctx_generate_rop_active_fbps(struct gf100_gr *gr) { - const u32 fbp_count = nv_rd32(priv, 0x120074); - nv_mask(priv, 0x408850, 0x0000000f, fbp_count); /* zrop */ - nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */ + const u32 fbp_count = nv_rd32(gr, 0x120074); + nv_mask(gr, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nv_mask(gr, 0x408958, 0x0000000f, fbp_count); /* crop */ } void -gk104_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int i; - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, oclass->hub); + gf100_gr_mmio(gr, oclass->gpc); + gf100_gr_mmio(gr, oclass->zcull); + gf100_gr_mmio(gr, oclass->tpc); + gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nv_wr32(gr, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); oclass->attrib(info); - oclass->unkn(priv); + oclass->unkn(gr); - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); - gk104_grctx_generate_rop_active_fbps(priv); - nv_mask(priv, 0x419f78, 0x00000001, 0x00000000); + nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + gk104_grctx_generate_rop_active_fbps(gr); + nv_mask(gr, 0x419f78, 0x00000001, 0x00000000); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + gf100_gr_icmd(gr, oclass->icmd); + nv_wr32(gr, 0x404154, 0x00000400); + gf100_gr_mthd(gr, oclass->mthd); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); - nv_mask(priv, 0x418800, 0x00200000, 0x00200000); - nv_mask(priv, 0x41be10, 0x00800000, 0x00800000); + nv_mask(gr, 0x418800, 0x00200000, 0x00200000); + nv_mask(gr, 0x41be10, 0x00800000, 0x00800000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index 3fe080e31a861..91e4aacfdec7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -26,46 +26,46 @@ #include static void -gk20a_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int idle_timeout_save; int i; - gf100_gr_mmio(priv, priv->fuc_sw_ctx); + gf100_gr_mmio(gr, gr->fuc_sw_ctx); - gf100_gr_wait_idle(priv); + gf100_gr_wait_idle(gr); - idle_timeout_save = nv_rd32(priv, 0x404154); - nv_wr32(priv, 0x404154, 0x00000000); + idle_timeout_save = nv_rd32(gr, 0x404154); + nv_wr32(gr, 0x404154, 0x00000000); oclass->attrib(info); - oclass->unkn(priv); + oclass->unkn(gr); - gf100_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gf100_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); - gk104_grctx_generate_rop_active_fbps(priv); + gk104_grctx_generate_rop_active_fbps(gr); - nv_mask(priv, 0x5044b0, 0x8000000, 0x8000000); + nv_mask(gr, 0x5044b0, 0x8000000, 0x8000000); - gf100_gr_wait_idle(priv); + gf100_gr_wait_idle(gr); - nv_wr32(priv, 0x404154, idle_timeout_save); - gf100_gr_wait_idle(priv); + nv_wr32(gr, 0x404154, idle_timeout_save); + gf100_gr_wait_idle(gr); - gf100_gr_mthd(priv, priv->fuc_method); - gf100_gr_wait_idle(priv); + gf100_gr_mthd(gr, gr->fuc_method); + gf100_gr_wait_idle(gr); - gf100_gr_icmd(priv, priv->fuc_bundle); + gf100_gr_icmd(gr, gr->fuc_bundle); oclass->pagepool(info); oclass->bundle(info); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index 6bf2fd1a05ba8..0d908a1231709 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -863,7 +863,7 @@ gm107_grctx_pack_ppc[] = { void gm107_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, impl->bundle_size / 0x20); const u32 token_limit = impl->bundle_token_limit; @@ -880,7 +880,7 @@ gm107_grctx_generate_bundle(struct gf100_grctx *info) void gm107_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv); + const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); @@ -895,17 +895,17 @@ gm107_grctx_generate_pagepool(struct gf100_grctx *info) void gm107_grctx_generate_attrib(struct gf100_grctx *info) { - struct gf100_gr_priv *priv = info->priv; - const struct gf100_grctx_oclass *impl = (void *)gf100_grctx_impl(priv); + struct gf100_gr *gr = info->gr; + const struct gf100_grctx_oclass *impl = (void *)gf100_grctx_impl(gr); const u32 alpha = impl->alpha_nr; const u32 attrib = impl->attrib_nr; const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; - const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access); + const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * priv->tpc_total; + u32 ao = bo + impl->attrib_nr_max * gr->tpc_total; int gpc, ppc, n = 0; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -914,84 +914,84 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info) mmio_wr32(info, 0x405830, (attrib << 16) | alpha); mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) { - const u32 as = alpha * priv->ppc_tpc_nr[gpc][ppc]; - const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc]; + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++, n++) { + const u32 as = alpha * gr->ppc_tpc_nr[gpc][ppc]; + const u32 bs = attrib * gr->ppc_tpc_nr[gpc][ppc]; const u32 u = 0x418ea0 + (n * 0x04); const u32 o = PPC_UNIT(gpc, ppc, 0); mmio_wr32(info, o + 0xc0, bs); mmio_wr32(info, o + 0xf4, bo); - bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + bo += impl->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, o + 0xe4, as); mmio_wr32(info, o + 0xf8, ao); - ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc]; + ao += impl->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, u, ((bs / 3 /*XXX*/) << 16) | bs); } } } void -gm107_grctx_generate_tpcid(struct gf100_gr_priv *priv) +gm107_grctx_generate_tpcid(struct gf100_gr *gr) { int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tpc < priv->tpc_nr[gpc]) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + if (tpc < gr->tpc_nr[gpc]) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x698), id); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x088), id); id++; } - nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); } } } static void -gm107_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int i; - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, oclass->hub); + gf100_gr_mmio(gr, oclass->gpc); + gf100_gr_mmio(gr, oclass->zcull); + gf100_gr_mmio(gr, oclass->tpc); + gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nv_wr32(gr, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); oclass->attrib(info); - oclass->unkn(priv); + oclass->unkn(gr); - gm107_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); - gf100_grctx_generate_r406800(priv); + gm107_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); + gf100_grctx_generate_r406800(gr); - nv_wr32(priv, 0x4064d0, 0x00000001); + nv_wr32(gr, 0x4064d0, 0x00000001); for (i = 1; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x406500, 0x00000001); + nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(gr, 0x406500, 0x00000001); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); - gk104_grctx_generate_rop_active_fbps(priv); + gk104_grctx_generate_rop_active_fbps(gr); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000400); - gf100_gr_mthd(priv, oclass->mthd); + gf100_gr_icmd(gr, oclass->icmd); + nv_wr32(gr, 0x404154, 0x00000400); + gf100_gr_mthd(gr, oclass->mthd); - nv_mask(priv, 0x419e00, 0x00808080, 0x00808080); - nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000); - nv_mask(priv, 0x419f80, 0x80000000, 0x80000000); - nv_mask(priv, 0x419f88, 0x80000000, 0x80000000); + nv_mask(gr, 0x419e00, 0x00808080, 0x00808080); + nv_mask(gr, 0x419ccc, 0x80000000, 0x80000000); + nv_mask(gr, 0x419f80, 0x80000000, 0x80000000); + nv_mask(gr, 0x419f88, 0x80000000, 0x80000000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c index efc76bfae8960..93f38bdfd0cc8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c @@ -919,16 +919,16 @@ gm204_grctx_pack_ppc[] = { ******************************************************************************/ void -gm204_grctx_generate_tpcid(struct gf100_gr_priv *priv) +gm204_grctx_generate_tpcid(struct gf100_gr *gr) { int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - if (tpc < priv->tpc_nr[gpc]) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + if (tpc < gr->tpc_nr[gpc]) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x698), id); + nv_wr32(gr, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x088), id); id++; } } @@ -936,88 +936,88 @@ gm204_grctx_generate_tpcid(struct gf100_gr_priv *priv) } static void -gm204_grctx_generate_rop_active_fbps(struct gf100_gr_priv *priv) +gm204_grctx_generate_rop_active_fbps(struct gf100_gr *gr) { - const u32 fbp_count = nv_rd32(priv, 0x12006c); - nv_mask(priv, 0x408850, 0x0000000f, fbp_count); /* zrop */ - nv_mask(priv, 0x408958, 0x0000000f, fbp_count); /* crop */ + const u32 fbp_count = nv_rd32(gr, 0x12006c); + nv_mask(gr, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nv_mask(gr, 0x408958, 0x0000000f, fbp_count); /* crop */ } void -gm204_grctx_generate_405b60(struct gf100_gr_priv *priv) +gm204_grctx_generate_405b60(struct gf100_gr *gr) { - const u32 dist_nr = DIV_ROUND_UP(priv->tpc_total, 4); - u32 dist[TPC_MAX] = {}; + const u32 dist_nr = DIV_ROUND_UP(gr->tpc_total, 4); + u32 dist[TPC_MAX / 4] = {}; u32 gpcs[GPC_MAX] = {}; u8 tpcnr[GPC_MAX]; int tpc, gpc, i; - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); /* won't result in the same distribution as the binary driver where * some of the gpcs have more tpcs than others, but this shall do * for the moment. the code for earlier gpus has this issue too. */ - for (gpc = -1, i = 0; i < priv->tpc_total; i++) { + for (gpc = -1, i = 0; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while(!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; dist[i / 4] |= ((gpc << 4) | tpc) << ((i % 4) * 8); gpcs[gpc] |= i << (tpc * 8); } for (i = 0; i < dist_nr; i++) - nv_wr32(priv, 0x405b60 + (i * 4), dist[i]); - for (i = 0; i < priv->gpc_nr; i++) - nv_wr32(priv, 0x405ba0 + (i * 4), gpcs[i]); + nv_wr32(gr, 0x405b60 + (i * 4), dist[i]); + for (i = 0; i < gr->gpc_nr; i++) + nv_wr32(gr, 0x405ba0 + (i * 4), gpcs[i]); } void -gm204_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; u32 tmp; int i; - gf100_gr_mmio(priv, oclass->hub); - gf100_gr_mmio(priv, oclass->gpc); - gf100_gr_mmio(priv, oclass->zcull); - gf100_gr_mmio(priv, oclass->tpc); - gf100_gr_mmio(priv, oclass->ppc); + gf100_gr_mmio(gr, oclass->hub); + gf100_gr_mmio(gr, oclass->gpc); + gf100_gr_mmio(gr, oclass->zcull); + gf100_gr_mmio(gr, oclass->tpc); + gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(priv, 0x404154, 0x00000000); + nv_wr32(gr, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); oclass->attrib(info); - oclass->unkn(priv); + oclass->unkn(gr); - gm204_grctx_generate_tpcid(priv); - gf100_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); + gm204_grctx_generate_tpcid(gr); + gf100_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x406500, 0x00000000); + nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(gr, 0x406500, 0x00000000); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); - gm204_grctx_generate_rop_active_fbps(priv); + gm204_grctx_generate_rop_active_fbps(gr); - for (tmp = 0, i = 0; i < priv->gpc_nr; i++) - tmp |= ((1 << priv->tpc_nr[i]) - 1) << (i * 4); - nv_wr32(priv, 0x4041c4, tmp); + for (tmp = 0, i = 0; i < gr->gpc_nr; i++) + tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 4); + nv_wr32(gr, 0x4041c4, tmp); - gm204_grctx_generate_405b60(priv); + gm204_grctx_generate_405b60(gr); - gf100_gr_icmd(priv, oclass->icmd); - nv_wr32(priv, 0x404154, 0x00000800); - gf100_gr_mthd(priv, oclass->mthd); + gf100_gr_icmd(gr, oclass->icmd); + nv_wr32(gr, 0x404154, 0x00000800); + gf100_gr_mthd(gr, oclass->mthd); - nv_mask(priv, 0x418e94, 0xffffffff, 0xc4230000); - nv_mask(priv, 0x418e4c, 0xffffffff, 0x70000000); + nv_mask(gr, 0x418e94, 0xffffffff, 0xc4230000); + nv_mask(gr, 0x418e4c, 0xffffffff, 0x70000000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c index c011bf327276d..c44b2e157ec2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c @@ -22,63 +22,63 @@ #include "ctxgf100.h" static void -gm20b_grctx_generate_r406028(struct gf100_gr_priv *priv) +gm20b_grctx_generate_r406028(struct gf100_gr *gr) { u32 tpc_per_gpc = 0; int i; - for (i = 0; i < priv->gpc_nr; i++) - tpc_per_gpc |= priv->tpc_nr[i] << (4 * i); + for (i = 0; i < gr->gpc_nr; i++) + tpc_per_gpc |= gr->tpc_nr[i] << (4 * i); - nv_wr32(priv, 0x406028, tpc_per_gpc); - nv_wr32(priv, 0x405870, tpc_per_gpc); + nv_wr32(gr, 0x406028, tpc_per_gpc); + nv_wr32(gr, 0x405870, tpc_per_gpc); } static void -gm20b_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info) +gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass; + struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int idle_timeout_save; int i, tmp; - gf100_gr_mmio(priv, priv->fuc_sw_ctx); + gf100_gr_mmio(gr, gr->fuc_sw_ctx); - gf100_gr_wait_idle(priv); + gf100_gr_wait_idle(gr); - idle_timeout_save = nv_rd32(priv, 0x404154); - nv_wr32(priv, 0x404154, 0x00000000); + idle_timeout_save = nv_rd32(gr, 0x404154); + nv_wr32(gr, 0x404154, 0x00000000); oclass->attrib(info); - oclass->unkn(priv); + oclass->unkn(gr); - gm204_grctx_generate_tpcid(priv); - gm20b_grctx_generate_r406028(priv); - gk104_grctx_generate_r418bb8(priv); + gm204_grctx_generate_tpcid(gr); + gm20b_grctx_generate_r406028(gr); + gk104_grctx_generate_r418bb8(gr); for (i = 0; i < 8; i++) - nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000); + nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr); + nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); - gk104_grctx_generate_rop_active_fbps(priv); - nv_wr32(priv, 0x408908, nv_rd32(priv, 0x410108) | 0x80000000); + gk104_grctx_generate_rop_active_fbps(gr); + nv_wr32(gr, 0x408908, nv_rd32(gr, 0x410108) | 0x80000000); - for (tmp = 0, i = 0; i < priv->gpc_nr; i++) - tmp |= ((1 << priv->tpc_nr[i]) - 1) << (i * 4); - nv_wr32(priv, 0x4041c4, tmp); + for (tmp = 0, i = 0; i < gr->gpc_nr; i++) + tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 4); + nv_wr32(gr, 0x4041c4, tmp); - gm204_grctx_generate_405b60(priv); + gm204_grctx_generate_405b60(gr); - gf100_gr_wait_idle(priv); + gf100_gr_wait_idle(gr); - nv_wr32(priv, 0x404154, idle_timeout_save); - gf100_gr_wait_idle(priv); + nv_wr32(gr, 0x404154, idle_timeout_save); + gf100_gr_wait_idle(gr); - gf100_gr_mthd(priv, priv->fuc_method); - gf100_gr_wait_idle(priv); + gf100_gr_mthd(gr, gr->fuc_method); + gf100_gr_wait_idle(gr); - gf100_gr_icmd(priv, priv->fuc_bundle); + gf100_gr_icmd(gr, gr->fuc_bundle); oclass->pagepool(info); oclass->bundle(info); } @@ -107,4 +107,4 @@ gm20b_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x400, .alpha_nr_max = 0xc00, .alpha_nr = 0x800, -}.base; \ No newline at end of file +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index b0b5fadfc550c..c1b84a687f763 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -41,35 +41,35 @@ ******************************************************************************/ static void -gf100_gr_zbc_clear_color(struct gf100_gr_priv *priv, int zbc) +gf100_gr_zbc_clear_color(struct gf100_gr *gr, int zbc) { - if (priv->zbc_color[zbc].format) { - nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]); - nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]); - nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]); - nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]); - } - nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format); - nv_wr32(priv, 0x405820, zbc); - nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ + if (gr->zbc_color[zbc].format) { + nv_wr32(gr, 0x405804, gr->zbc_color[zbc].ds[0]); + nv_wr32(gr, 0x405808, gr->zbc_color[zbc].ds[1]); + nv_wr32(gr, 0x40580c, gr->zbc_color[zbc].ds[2]); + nv_wr32(gr, 0x405810, gr->zbc_color[zbc].ds[3]); + } + nv_wr32(gr, 0x405814, gr->zbc_color[zbc].format); + nv_wr32(gr, 0x405820, zbc); + nv_wr32(gr, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ } static int -gf100_gr_zbc_color_get(struct gf100_gr_priv *priv, int format, +gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, const u32 ds[4], const u32 l2[4]) { - struct nvkm_ltc *ltc = nvkm_ltc(priv); + struct nvkm_ltc *ltc = nvkm_ltc(gr); int zbc = -ENOSPC, i; for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { - if (priv->zbc_color[i].format) { - if (priv->zbc_color[i].format != format) + if (gr->zbc_color[i].format) { + if (gr->zbc_color[i].format != format) continue; - if (memcmp(priv->zbc_color[i].ds, ds, sizeof( - priv->zbc_color[i].ds))) + if (memcmp(gr->zbc_color[i].ds, ds, sizeof( + gr->zbc_color[i].ds))) continue; - if (memcmp(priv->zbc_color[i].l2, l2, sizeof( - priv->zbc_color[i].l2))) { + if (memcmp(gr->zbc_color[i].l2, l2, sizeof( + gr->zbc_color[i].l2))) { WARN_ON(1); return -EINVAL; } @@ -82,38 +82,38 @@ gf100_gr_zbc_color_get(struct gf100_gr_priv *priv, int format, if (zbc < 0) return zbc; - memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds)); - memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2)); - priv->zbc_color[zbc].format = format; + memcpy(gr->zbc_color[zbc].ds, ds, sizeof(gr->zbc_color[zbc].ds)); + memcpy(gr->zbc_color[zbc].l2, l2, sizeof(gr->zbc_color[zbc].l2)); + gr->zbc_color[zbc].format = format; ltc->zbc_color_get(ltc, zbc, l2); - gf100_gr_zbc_clear_color(priv, zbc); + gf100_gr_zbc_clear_color(gr, zbc); return zbc; } static void -gf100_gr_zbc_clear_depth(struct gf100_gr_priv *priv, int zbc) +gf100_gr_zbc_clear_depth(struct gf100_gr *gr, int zbc) { - if (priv->zbc_depth[zbc].format) - nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds); - nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format); - nv_wr32(priv, 0x405820, zbc); - nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ + if (gr->zbc_depth[zbc].format) + nv_wr32(gr, 0x405818, gr->zbc_depth[zbc].ds); + nv_wr32(gr, 0x40581c, gr->zbc_depth[zbc].format); + nv_wr32(gr, 0x405820, zbc); + nv_wr32(gr, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ } static int -gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format, +gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, const u32 ds, const u32 l2) { - struct nvkm_ltc *ltc = nvkm_ltc(priv); + struct nvkm_ltc *ltc = nvkm_ltc(gr); int zbc = -ENOSPC, i; for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { - if (priv->zbc_depth[i].format) { - if (priv->zbc_depth[i].format != format) + if (gr->zbc_depth[i].format) { + if (gr->zbc_depth[i].format != format) continue; - if (priv->zbc_depth[i].ds != ds) + if (gr->zbc_depth[i].ds != ds) continue; - if (priv->zbc_depth[i].l2 != l2) { + if (gr->zbc_depth[i].l2 != l2) { WARN_ON(1); return -EINVAL; } @@ -126,11 +126,11 @@ gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format, if (zbc < 0) return zbc; - priv->zbc_depth[zbc].format = format; - priv->zbc_depth[zbc].ds = ds; - priv->zbc_depth[zbc].l2 = l2; + gr->zbc_depth[zbc].format = format; + gr->zbc_depth[zbc].ds = ds; + gr->zbc_depth[zbc].l2 = l2; ltc->zbc_depth_get(ltc, zbc, l2); - gf100_gr_zbc_clear_depth(priv, zbc); + gf100_gr_zbc_clear_depth(gr, zbc); return zbc; } @@ -141,7 +141,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format, static int gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) { - struct gf100_gr_priv *priv = (void *)object->engine; + struct gf100_gr *gr = (void *)object->engine; union { struct fermi_a_zbc_color_v0 v0; } *args = data; @@ -168,7 +168,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8: case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10: case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11: - ret = gf100_gr_zbc_color_get(priv, args->v0.format, + ret = gf100_gr_zbc_color_get(gr, args->v0.format, args->v0.ds, args->v0.l2); if (ret >= 0) { @@ -187,7 +187,7 @@ gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size) static int gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size) { - struct gf100_gr_priv *priv = (void *)object->engine; + struct gf100_gr *gr = (void *)object->engine; union { struct fermi_a_zbc_depth_v0 v0; } *args = data; @@ -196,7 +196,7 @@ gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size) if (nvif_unpack(args->v0, 0, 0, false)) { switch (args->v0.format) { case FERMI_A_ZBC_DEPTH_V0_FMT_FP32: - ret = gf100_gr_zbc_depth_get(priv, args->v0.format, + ret = gf100_gr_zbc_depth_get(gr, args->v0.format, args->v0.ds, args->v0.l2); return (ret >= 0) ? 0 : -ENOSPC; @@ -235,11 +235,11 @@ static int gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd, void *pdata, u32 size) { - struct gf100_gr_priv *priv = (void *)object->engine; + struct gf100_gr *gr = (void *)object->engine; if (size >= sizeof(u32)) { u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000; - nv_wr32(priv, 0x419e44, data); - nv_wr32(priv, 0x419e4c, data); + nv_wr32(gr, 0x419e44, data); + nv_wr32(gr, 0x419e4c, data); return 0; } return -EINVAL; @@ -276,15 +276,15 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_vm *vm = nvkm_client(parent)->vm; - struct gf100_gr_priv *priv = (void *)engine; - struct gf100_gr_data *data = priv->mmio_data; - struct gf100_gr_mmio *mmio = priv->mmio_list; + struct gf100_gr *gr = (void *)engine; + struct gf100_gr_data *data = gr->mmio_data; + struct gf100_gr_mmio *mmio = gr->mmio_list; struct gf100_gr_chan *chan; int ret, i; /* allocate memory for context, and fill with default values */ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, - priv->size, 0x100, + gr->size, 0x100, NVOBJ_FLAG_ZERO_ALLOC, &chan); *pobject = nv_object(chan); if (ret) @@ -306,7 +306,7 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* allocate buffers referenced by mmio list */ - for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) { + for (i = 0; data->size && i < ARRAY_SIZE(gr->mmio_data); i++) { ret = nvkm_gpuobj_new(nv_object(chan), NULL, data->size, data->align, 0, &chan->data[i].mem); if (ret) @@ -321,7 +321,7 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } /* finally, fill in the mmio list and point the context at it */ - for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) { + for (i = 0; mmio->addr && i < ARRAY_SIZE(gr->mmio_list); i++) { u32 addr = mmio->addr; u32 data = mmio->data; @@ -335,10 +335,10 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mmio++; } - for (i = 0; i < priv->size; i += 4) - nv_wo32(chan, i, priv->data[i / 4]); + for (i = 0; i < gr->size; i += 4) + nv_wo32(chan, i, gr->data[i / 4]); - if (!priv->firmware) { + if (!gr->firmware) { nv_wo32(chan, 0x00, chan->mmio_nr / 2); nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8); } else { @@ -634,7 +634,7 @@ gf100_gr_pack_mmio[] = { ******************************************************************************/ void -gf100_gr_zbc_init(struct gf100_gr_priv *priv) +gf100_gr_zbc_init(struct gf100_gr *gr) { const u32 zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; @@ -644,22 +644,22 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv) 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; - struct nvkm_ltc *ltc = nvkm_ltc(priv); + struct nvkm_ltc *ltc = nvkm_ltc(gr); int index; - if (!priv->zbc_color[0].format) { - gf100_gr_zbc_color_get(priv, 1, & zero[0], &zero[4]); - gf100_gr_zbc_color_get(priv, 2, & one[0], &one[4]); - gf100_gr_zbc_color_get(priv, 4, &f32_0[0], &f32_0[4]); - gf100_gr_zbc_color_get(priv, 4, &f32_1[0], &f32_1[4]); - gf100_gr_zbc_depth_get(priv, 1, 0x00000000, 0x00000000); - gf100_gr_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000); + if (!gr->zbc_color[0].format) { + gf100_gr_zbc_color_get(gr, 1, & zero[0], &zero[4]); + gf100_gr_zbc_color_get(gr, 2, & one[0], &one[4]); + gf100_gr_zbc_color_get(gr, 4, &f32_0[0], &f32_0[4]); + gf100_gr_zbc_color_get(gr, 4, &f32_1[0], &f32_1[4]); + gf100_gr_zbc_depth_get(gr, 1, 0x00000000, 0x00000000); + gf100_gr_zbc_depth_get(gr, 1, 0x3f800000, 0x3f800000); } for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) - gf100_gr_zbc_clear_color(priv, index); + gf100_gr_zbc_clear_color(gr, index); for (index = ltc->zbc_min; index <= ltc->zbc_max; index++) - gf100_gr_zbc_clear_depth(priv, index); + gf100_gr_zbc_clear_depth(gr, index); } /** @@ -668,7 +668,7 @@ gf100_gr_zbc_init(struct gf100_gr_priv *priv) * progress. */ int -gf100_gr_wait_idle(struct gf100_gr_priv *priv) +gf100_gr_wait_idle(struct gf100_gr *gr) { unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000); bool gr_enabled, ctxsw_active, gr_busy; @@ -678,23 +678,23 @@ gf100_gr_wait_idle(struct gf100_gr_priv *priv) * required to make sure FIFO_ENGINE_STATUS (0x2640) is * up-to-date */ - nv_rd32(priv, 0x400700); + nv_rd32(gr, 0x400700); - gr_enabled = nv_rd32(priv, 0x200) & 0x1000; - ctxsw_active = nv_rd32(priv, 0x2640) & 0x8000; - gr_busy = nv_rd32(priv, 0x40060c) & 0x1; + gr_enabled = nv_rd32(gr, 0x200) & 0x1000; + ctxsw_active = nv_rd32(gr, 0x2640) & 0x8000; + gr_busy = nv_rd32(gr, 0x40060c) & 0x1; if (!gr_enabled || (!gr_busy && !ctxsw_active)) return 0; } while (time_before(jiffies, end_jiffies)); - nv_error(priv, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", + nv_error(gr, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", gr_enabled, ctxsw_active, gr_busy); return -EAGAIN; } void -gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) +gf100_gr_mmio(struct gf100_gr *gr, const struct gf100_gr_pack *p) { const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; @@ -703,48 +703,48 @@ gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) u32 next = init->addr + init->count * init->pitch; u32 addr = init->addr; while (addr < next) { - nv_wr32(priv, addr, init->data); + nv_wr32(gr, addr, init->data); addr += init->pitch; } } } void -gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) +gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) { const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; u32 data = 0; - nv_wr32(priv, 0x400208, 0x80000000); + nv_wr32(gr, 0x400208, 0x80000000); pack_for_each_init(init, pack, p) { u32 next = init->addr + init->count * init->pitch; u32 addr = init->addr; if ((pack == p && init == p->init) || data != init->data) { - nv_wr32(priv, 0x400204, init->data); + nv_wr32(gr, 0x400204, init->data); data = init->data; } while (addr < next) { - nv_wr32(priv, 0x400200, addr); + nv_wr32(gr, 0x400200, addr); /** * Wait for GR to go idle after submitting a * GO_IDLE bundle */ if ((addr & 0xffff) == 0xe100) - gf100_gr_wait_idle(priv); - nv_wait(priv, 0x400700, 0x00000004, 0x00000000); + gf100_gr_wait_idle(gr); + nv_wait(gr, 0x400700, 0x00000004, 0x00000000); addr += init->pitch; } } - nv_wr32(priv, 0x400208, 0x00000000); + nv_wr32(gr, 0x400208, 0x00000000); } void -gf100_gr_mthd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) +gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p) { const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; @@ -756,26 +756,26 @@ gf100_gr_mthd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p) u32 addr = init->addr; if ((pack == p && init == p->init) || data != init->data) { - nv_wr32(priv, 0x40448c, init->data); + nv_wr32(gr, 0x40448c, init->data); data = init->data; } while (addr < next) { - nv_wr32(priv, 0x404488, ctrl | (addr << 14)); + nv_wr32(gr, 0x404488, ctrl | (addr << 14)); addr += init->pitch; } } } u64 -gf100_gr_units(struct nvkm_gr *gr) +gf100_gr_units(struct nvkm_gr *obj) { - struct gf100_gr_priv *priv = (void *)gr; + struct gf100_gr *gr = container_of(obj, typeof(*gr), base); u64 cfg; - cfg = (u32)priv->gpc_nr; - cfg |= (u32)priv->tpc_total << 8; - cfg |= (u64)priv->rop_nr << 32; + cfg = (u32)gr->gpc_nr; + cfg |= (u32)gr->tpc_total << 8; + cfg |= (u64)gr->rop_nr << 32; return cfg; } @@ -806,17 +806,17 @@ static const struct nvkm_enum gf100_gpc_rop_error[] = { }; static void -gf100_gr_trap_gpc_rop(struct gf100_gr_priv *priv, int gpc) +gf100_gr_trap_gpc_rop(struct gf100_gr *gr, int gpc) { u32 trap[4]; int i; - trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420)); - trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434)); - trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438)); - trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c)); + trap[0] = nv_rd32(gr, GPC_UNIT(gpc, 0x0420)); + trap[1] = nv_rd32(gr, GPC_UNIT(gpc, 0x0434)); + trap[2] = nv_rd32(gr, GPC_UNIT(gpc, 0x0438)); + trap[3] = nv_rd32(gr, GPC_UNIT(gpc, 0x043c)); - nv_error(priv, "GPC%d/PROP trap:", gpc); + nv_error(gr, "GPC%d/PROP trap:", gpc); for (i = 0; i <= 29; ++i) { if (!(trap[0] & (1 << i))) continue; @@ -825,10 +825,10 @@ gf100_gr_trap_gpc_rop(struct gf100_gr_priv *priv, int gpc) } pr_cont("\n"); - nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n", + nv_error(gr, "x = %u, y = %u, format = %x, storage type = %x\n", trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f, trap[3] & 0xff); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); } static const struct nvkm_enum gf100_mp_warp_error[] = { @@ -851,12 +851,12 @@ static const struct nvkm_bitfield gf100_mp_global_error[] = { }; static void -gf100_gr_trap_mp(struct gf100_gr_priv *priv, int gpc, int tpc) +gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) { - u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648)); - u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650)); + u32 werr = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x648)); + u32 gerr = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x650)); - nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc); + nv_error(gr, "GPC%i/TPC%i/MP trap:", gpc, tpc); nvkm_bitfield_print(gf100_mp_global_error, gerr); if (werr) { pr_cont(" "); @@ -864,150 +864,150 @@ gf100_gr_trap_mp(struct gf100_gr_priv *priv, int gpc, int tpc) } pr_cont("\n"); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x650), gerr); } static void -gf100_gr_trap_tpc(struct gf100_gr_priv *priv, int gpc, int tpc) +gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) { - u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508)); + u32 stat = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x0508)); if (stat & 0x00000001) { - u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224)); - nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); + u32 trap = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x0224)); + nv_error(gr, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); stat &= ~0x00000001; } if (stat & 0x00000002) { - gf100_gr_trap_mp(priv, gpc, tpc); + gf100_gr_trap_mp(gr, gpc, tpc); stat &= ~0x00000002; } if (stat & 0x00000004) { - u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084)); - nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); + u32 trap = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x0084)); + nv_error(gr, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { - u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c)); - nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); + u32 trap = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x048c)); + nv_error(gr, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); stat &= ~0x00000008; } if (stat) { - nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat); + nv_error(gr, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat); } } static void -gf100_gr_trap_gpc(struct gf100_gr_priv *priv, int gpc) +gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) { - u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90)); + u32 stat = nv_rd32(gr, GPC_UNIT(gpc, 0x2c90)); int tpc; if (stat & 0x00000001) { - gf100_gr_trap_gpc_rop(priv, gpc); + gf100_gr_trap_gpc_rop(gr, gpc); stat &= ~0x00000001; } if (stat & 0x00000002) { - u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900)); - nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); + u32 trap = nv_rd32(gr, GPC_UNIT(gpc, 0x0900)); + nv_error(gr, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); + nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); stat &= ~0x00000002; } if (stat & 0x00000004) { - u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028)); - nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); + u32 trap = nv_rd32(gr, GPC_UNIT(gpc, 0x1028)); + nv_error(gr, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); + nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { - u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824)); - nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); + u32 trap = nv_rd32(gr, GPC_UNIT(gpc, 0x0824)); + nv_error(gr, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); + nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); stat &= ~0x00000009; } - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { u32 mask = 0x00010000 << tpc; if (stat & mask) { - gf100_gr_trap_tpc(priv, gpc, tpc); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask); + gf100_gr_trap_tpc(gr, gpc, tpc); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), mask); stat &= ~mask; } } if (stat) { - nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat); + nv_error(gr, "GPC%d/0x%08x: unknown\n", gpc, stat); } } static void -gf100_gr_trap_intr(struct gf100_gr_priv *priv) +gf100_gr_trap_intr(struct gf100_gr *gr) { - u32 trap = nv_rd32(priv, 0x400108); + u32 trap = nv_rd32(gr, 0x400108); int rop, gpc, i; if (trap & 0x00000001) { - u32 stat = nv_rd32(priv, 0x404000); - nv_error(priv, "DISPATCH 0x%08x\n", stat); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000001); + u32 stat = nv_rd32(gr, 0x404000); + nv_error(gr, "DISPATCH 0x%08x\n", stat); + nv_wr32(gr, 0x404000, 0xc0000000); + nv_wr32(gr, 0x400108, 0x00000001); trap &= ~0x00000001; } if (trap & 0x00000002) { - u32 stat = nv_rd32(priv, 0x404600); - nv_error(priv, "M2MF 0x%08x\n", stat); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000002); + u32 stat = nv_rd32(gr, 0x404600); + nv_error(gr, "M2MF 0x%08x\n", stat); + nv_wr32(gr, 0x404600, 0xc0000000); + nv_wr32(gr, 0x400108, 0x00000002); trap &= ~0x00000002; } if (trap & 0x00000008) { - u32 stat = nv_rd32(priv, 0x408030); - nv_error(priv, "CCACHE 0x%08x\n", stat); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000008); + u32 stat = nv_rd32(gr, 0x408030); + nv_error(gr, "CCACHE 0x%08x\n", stat); + nv_wr32(gr, 0x408030, 0xc0000000); + nv_wr32(gr, 0x400108, 0x00000008); trap &= ~0x00000008; } if (trap & 0x00000010) { - u32 stat = nv_rd32(priv, 0x405840); - nv_error(priv, "SHADER 0x%08x\n", stat); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000010); + u32 stat = nv_rd32(gr, 0x405840); + nv_error(gr, "SHADER 0x%08x\n", stat); + nv_wr32(gr, 0x405840, 0xc0000000); + nv_wr32(gr, 0x400108, 0x00000010); trap &= ~0x00000010; } if (trap & 0x00000040) { - u32 stat = nv_rd32(priv, 0x40601c); - nv_error(priv, "UNK6 0x%08x\n", stat); - nv_wr32(priv, 0x40601c, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000040); + u32 stat = nv_rd32(gr, 0x40601c); + nv_error(gr, "UNK6 0x%08x\n", stat); + nv_wr32(gr, 0x40601c, 0xc0000000); + nv_wr32(gr, 0x400108, 0x00000040); trap &= ~0x00000040; } if (trap & 0x00000080) { - u32 stat = nv_rd32(priv, 0x404490); - nv_error(priv, "MACRO 0x%08x\n", stat); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x400108, 0x00000080); + u32 stat = nv_rd32(gr, 0x404490); + nv_error(gr, "MACRO 0x%08x\n", stat); + nv_wr32(gr, 0x404490, 0xc0000000); + nv_wr32(gr, 0x400108, 0x00000080); trap &= ~0x00000080; } if (trap & 0x00000100) { - u32 stat = nv_rd32(priv, 0x407020); + u32 stat = nv_rd32(gr, 0x407020); - nv_error(priv, "SKED:"); + nv_error(gr, "SKED:"); for (i = 0; i <= 29; ++i) { if (!(stat & (1 << i))) continue; @@ -1017,104 +1017,104 @@ gf100_gr_trap_intr(struct gf100_gr_priv *priv) pr_cont("\n"); if (stat & 0x3fffffff) - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x400108, 0x00000100); + nv_wr32(gr, 0x407020, 0x40000000); + nv_wr32(gr, 0x400108, 0x00000100); trap &= ~0x00000100; } if (trap & 0x01000000) { - u32 stat = nv_rd32(priv, 0x400118); - for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) { + u32 stat = nv_rd32(gr, 0x400118); + for (gpc = 0; stat && gpc < gr->gpc_nr; gpc++) { u32 mask = 0x00000001 << gpc; if (stat & mask) { - gf100_gr_trap_gpc(priv, gpc); - nv_wr32(priv, 0x400118, mask); + gf100_gr_trap_gpc(gr, gpc); + nv_wr32(gr, 0x400118, mask); stat &= ~mask; } } - nv_wr32(priv, 0x400108, 0x01000000); + nv_wr32(gr, 0x400108, 0x01000000); trap &= ~0x01000000; } if (trap & 0x02000000) { - for (rop = 0; rop < priv->rop_nr; rop++) { - u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070)); - u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144)); - nv_error(priv, "ROP%d 0x%08x 0x%08x\n", + for (rop = 0; rop < gr->rop_nr; rop++) { + u32 statz = nv_rd32(gr, ROP_UNIT(rop, 0x070)); + u32 statc = nv_rd32(gr, ROP_UNIT(rop, 0x144)); + nv_error(gr, "ROP%d 0x%08x 0x%08x\n", rop, statz, statc); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); + nv_wr32(gr, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(gr, ROP_UNIT(rop, 0x144), 0xc0000000); } - nv_wr32(priv, 0x400108, 0x02000000); + nv_wr32(gr, 0x400108, 0x02000000); trap &= ~0x02000000; } if (trap) { - nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap); - nv_wr32(priv, 0x400108, trap); + nv_error(gr, "TRAP UNHANDLED 0x%08x\n", trap); + nv_wr32(gr, 0x400108, trap); } } static void -gf100_gr_ctxctl_debug_unit(struct gf100_gr_priv *priv, u32 base) +gf100_gr_ctxctl_debug_unit(struct gf100_gr *gr, u32 base) { - nv_error(priv, "%06x - done 0x%08x\n", base, - nv_rd32(priv, base + 0x400)); - nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804), - nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c)); - nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814), - nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c)); + nv_error(gr, "%06x - done 0x%08x\n", base, + nv_rd32(gr, base + 0x400)); + nv_error(gr, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, + nv_rd32(gr, base + 0x800), nv_rd32(gr, base + 0x804), + nv_rd32(gr, base + 0x808), nv_rd32(gr, base + 0x80c)); + nv_error(gr, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, + nv_rd32(gr, base + 0x810), nv_rd32(gr, base + 0x814), + nv_rd32(gr, base + 0x818), nv_rd32(gr, base + 0x81c)); } void -gf100_gr_ctxctl_debug(struct gf100_gr_priv *priv) +gf100_gr_ctxctl_debug(struct gf100_gr *gr) { - u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff; + u32 gpcnr = nv_rd32(gr, 0x409604) & 0xffff; u32 gpc; - gf100_gr_ctxctl_debug_unit(priv, 0x409000); + gf100_gr_ctxctl_debug_unit(gr, 0x409000); for (gpc = 0; gpc < gpcnr; gpc++) - gf100_gr_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000)); + gf100_gr_ctxctl_debug_unit(gr, 0x502000 + (gpc * 0x8000)); } static void -gf100_gr_ctxctl_isr(struct gf100_gr_priv *priv) +gf100_gr_ctxctl_isr(struct gf100_gr *gr) { - u32 stat = nv_rd32(priv, 0x409c18); + u32 stat = nv_rd32(gr, 0x409c18); if (stat & 0x00000001) { - u32 code = nv_rd32(priv, 0x409814); + u32 code = nv_rd32(gr, 0x409814); if (code == E_BAD_FWMTHD) { - u32 class = nv_rd32(priv, 0x409808); - u32 addr = nv_rd32(priv, 0x40980c); + u32 class = nv_rd32(gr, 0x409808); + u32 addr = nv_rd32(gr, 0x40980c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); - u32 data = nv_rd32(priv, 0x409810); + u32 data = nv_rd32(gr, 0x409810); - nv_error(priv, "FECS MTHD subc %d class 0x%04x " + nv_error(gr, "FECS MTHD subc %d class 0x%04x " "mthd 0x%04x data 0x%08x\n", subc, class, mthd, data); - nv_wr32(priv, 0x409c20, 0x00000001); + nv_wr32(gr, 0x409c20, 0x00000001); stat &= ~0x00000001; } else { - nv_error(priv, "FECS ucode error %d\n", code); + nv_error(gr, "FECS ucode error %d\n", code); } } if (stat & 0x00080000) { - nv_error(priv, "FECS watchdog timeout\n"); - gf100_gr_ctxctl_debug(priv); - nv_wr32(priv, 0x409c20, 0x00080000); + nv_error(gr, "FECS watchdog timeout\n"); + gf100_gr_ctxctl_debug(gr); + nv_wr32(gr, 0x409c20, 0x00080000); stat &= ~0x00080000; } if (stat) { - nv_error(priv, "FECS 0x%08x\n", stat); - gf100_gr_ctxctl_debug(priv); - nv_wr32(priv, 0x409c20, stat); + nv_error(gr, "FECS 0x%08x\n", stat); + gf100_gr_ctxctl_debug(gr); + nv_wr32(gr, 0x409c20, stat); } } @@ -1125,19 +1125,19 @@ gf100_gr_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; - struct gf100_gr_priv *priv = (void *)subdev; - u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff; - u32 stat = nv_rd32(priv, 0x400100); - u32 addr = nv_rd32(priv, 0x400704); + struct gf100_gr *gr = (void *)subdev; + u64 inst = nv_rd32(gr, 0x409b00) & 0x0fffffff; + u32 stat = nv_rd32(gr, 0x400100); + u32 addr = nv_rd32(gr, 0x400704); u32 mthd = (addr & 0x00003ffc); u32 subc = (addr & 0x00070000) >> 16; - u32 data = nv_rd32(priv, 0x400708); - u32 code = nv_rd32(priv, 0x400110); + u32 data = nv_rd32(gr, 0x400708); + u32 code = nv_rd32(gr, 0x400110); u32 class; int chid; - if (nv_device(priv)->card_type < NV_E0 || subc < 4) - class = nv_rd32(priv, 0x404200 + (subc * 4)); + if (nv_device(gr)->card_type < NV_E0 || subc < 4) + class = nv_rd32(gr, 0x404200 + (subc * 4)); else class = 0x0000; @@ -1149,89 +1149,89 @@ gf100_gr_intr(struct nvkm_subdev *subdev) * notifier interrupt, only needed for cyclestats * can be safely ignored */ - nv_wr32(priv, 0x400100, 0x00000001); + nv_wr32(gr, 0x400100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000010) { handle = nvkm_handle_get_class(engctx, class); if (!handle || nv_call(handle->object, mthd, data)) { - nv_error(priv, + nv_error(gr, "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst << 12, nvkm_client_name(engctx), subc, class, mthd, data); } nvkm_handle_put(handle); - nv_wr32(priv, 0x400100, 0x00000010); + nv_wr32(gr, 0x400100, 0x00000010); stat &= ~0x00000010; } if (stat & 0x00000020) { - nv_error(priv, + nv_error(gr, "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst << 12, nvkm_client_name(engctx), subc, class, mthd, data); - nv_wr32(priv, 0x400100, 0x00000020); + nv_wr32(gr, 0x400100, 0x00000020); stat &= ~0x00000020; } if (stat & 0x00100000) { - nv_error(priv, "DATA_ERROR ["); + nv_error(gr, "DATA_ERROR ["); nvkm_enum_print(nv50_data_error_names, code); pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst << 12, nvkm_client_name(engctx), subc, class, mthd, data); - nv_wr32(priv, 0x400100, 0x00100000); + nv_wr32(gr, 0x400100, 0x00100000); stat &= ~0x00100000; } if (stat & 0x00200000) { - nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, + nv_error(gr, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, nvkm_client_name(engctx)); - gf100_gr_trap_intr(priv); - nv_wr32(priv, 0x400100, 0x00200000); + gf100_gr_trap_intr(gr); + nv_wr32(gr, 0x400100, 0x00200000); stat &= ~0x00200000; } if (stat & 0x00080000) { - gf100_gr_ctxctl_isr(priv); - nv_wr32(priv, 0x400100, 0x00080000); + gf100_gr_ctxctl_isr(gr); + nv_wr32(gr, 0x400100, 0x00080000); stat &= ~0x00080000; } if (stat) { - nv_error(priv, "unknown stat 0x%08x\n", stat); - nv_wr32(priv, 0x400100, stat); + nv_error(gr, "unknown stat 0x%08x\n", stat); + nv_wr32(gr, 0x400100, stat); } - nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(gr, 0x400500, 0x00010001); nvkm_engctx_put(engctx); } void -gf100_gr_init_fw(struct gf100_gr_priv *priv, u32 fuc_base, +gf100_gr_init_fw(struct gf100_gr *gr, u32 fuc_base, struct gf100_gr_fuc *code, struct gf100_gr_fuc *data) { int i; - nv_wr32(priv, fuc_base + 0x01c0, 0x01000000); + nv_wr32(gr, fuc_base + 0x01c0, 0x01000000); for (i = 0; i < data->size / 4; i++) - nv_wr32(priv, fuc_base + 0x01c4, data->data[i]); + nv_wr32(gr, fuc_base + 0x01c4, data->data[i]); - nv_wr32(priv, fuc_base + 0x0180, 0x01000000); + nv_wr32(gr, fuc_base + 0x0180, 0x01000000); for (i = 0; i < code->size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(priv, fuc_base + 0x0188, i >> 6); - nv_wr32(priv, fuc_base + 0x0184, code->data[i]); + nv_wr32(gr, fuc_base + 0x0188, i >> 6); + nv_wr32(gr, fuc_base + 0x0184, code->data[i]); } /* code must be padded to 0x40 words */ for (; i & 0x3f; i++) - nv_wr32(priv, fuc_base + 0x0184, 0); + nv_wr32(gr, fuc_base + 0x0184, 0); } static void -gf100_gr_init_csdata(struct gf100_gr_priv *priv, +gf100_gr_init_csdata(struct gf100_gr *gr, const struct gf100_gr_pack *pack, u32 falcon, u32 starstar, u32 base) { @@ -1240,12 +1240,12 @@ gf100_gr_init_csdata(struct gf100_gr_priv *priv, u32 addr = ~0, prev = ~0, xfer = 0; u32 star, temp; - nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar); - star = nv_rd32(priv, falcon + 0x01c4); - temp = nv_rd32(priv, falcon + 0x01c4); + nv_wr32(gr, falcon + 0x01c0, 0x02000000 + starstar); + star = nv_rd32(gr, falcon + 0x01c4); + temp = nv_rd32(gr, falcon + 0x01c4); if (temp > star) star = temp; - nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star); + nv_wr32(gr, falcon + 0x01c0, 0x01000000 + star); pack_for_each_init(init, iter, pack) { u32 head = init->addr - base; @@ -1254,7 +1254,7 @@ gf100_gr_init_csdata(struct gf100_gr_priv *priv, if (head != prev + 4 || xfer >= 32) { if (xfer) { u32 data = ((--xfer << 26) | addr); - nv_wr32(priv, falcon + 0x01c4, data); + nv_wr32(gr, falcon + 0x01c4, data); star += 4; } addr = head; @@ -1266,101 +1266,101 @@ gf100_gr_init_csdata(struct gf100_gr_priv *priv, } } - nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr); - nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar); - nv_wr32(priv, falcon + 0x01c4, star + 4); + nv_wr32(gr, falcon + 0x01c4, (--xfer << 26) | addr); + nv_wr32(gr, falcon + 0x01c0, 0x01000004 + starstar); + nv_wr32(gr, falcon + 0x01c4, star + 4); } int -gf100_gr_init_ctxctl(struct gf100_gr_priv *priv) +gf100_gr_init_ctxctl(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)nv_object(priv)->oclass; - struct gf100_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass; + struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass; + struct gf100_grctx_oclass *cclass = (void *)nv_engine(gr)->cclass; int i; - if (priv->firmware) { + if (gr->firmware) { /* load fuc microcode */ - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); - gf100_gr_init_fw(priv, 0x409000, &priv->fuc409c, - &priv->fuc409d); - gf100_gr_init_fw(priv, 0x41a000, &priv->fuc41ac, - &priv->fuc41ad); - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, + &gr->fuc409d); + gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, + &gr->fuc41ad); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); /* start both of them running */ - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x41a10c, 0x00000000); - nv_wr32(priv, 0x40910c, 0x00000000); - nv_wr32(priv, 0x41a100, 0x00000002); - nv_wr32(priv, 0x409100, 0x00000002); - if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001)) - nv_warn(priv, "0x409800 wait failed\n"); - - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x7fffffff); - nv_wr32(priv, 0x409504, 0x00000021); - - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x00000000); - nv_wr32(priv, 0x409504, 0x00000010); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x10 timeout\n"); + nv_wr32(gr, 0x409840, 0xffffffff); + nv_wr32(gr, 0x41a10c, 0x00000000); + nv_wr32(gr, 0x40910c, 0x00000000); + nv_wr32(gr, 0x41a100, 0x00000002); + nv_wr32(gr, 0x409100, 0x00000002); + if (!nv_wait(gr, 0x409800, 0x00000001, 0x00000001)) + nv_warn(gr, "0x409800 wait failed\n"); + + nv_wr32(gr, 0x409840, 0xffffffff); + nv_wr32(gr, 0x409500, 0x7fffffff); + nv_wr32(gr, 0x409504, 0x00000021); + + nv_wr32(gr, 0x409840, 0xffffffff); + nv_wr32(gr, 0x409500, 0x00000000); + nv_wr32(gr, 0x409504, 0x00000010); + if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(gr, "fuc09 req 0x10 timeout\n"); return -EBUSY; } - priv->size = nv_rd32(priv, 0x409800); + gr->size = nv_rd32(gr, 0x409800); - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x00000000); - nv_wr32(priv, 0x409504, 0x00000016); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x16 timeout\n"); + nv_wr32(gr, 0x409840, 0xffffffff); + nv_wr32(gr, 0x409500, 0x00000000); + nv_wr32(gr, 0x409504, 0x00000016); + if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(gr, "fuc09 req 0x16 timeout\n"); return -EBUSY; } - nv_wr32(priv, 0x409840, 0xffffffff); - nv_wr32(priv, 0x409500, 0x00000000); - nv_wr32(priv, 0x409504, 0x00000025); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x25 timeout\n"); + nv_wr32(gr, 0x409840, 0xffffffff); + nv_wr32(gr, 0x409500, 0x00000000); + nv_wr32(gr, 0x409504, 0x00000025); + if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(gr, "fuc09 req 0x25 timeout\n"); return -EBUSY; } - if (nv_device(priv)->chipset >= 0xe0) { - nv_wr32(priv, 0x409800, 0x00000000); - nv_wr32(priv, 0x409500, 0x00000001); - nv_wr32(priv, 0x409504, 0x00000030); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x30 timeout\n"); + if (nv_device(gr)->chipset >= 0xe0) { + nv_wr32(gr, 0x409800, 0x00000000); + nv_wr32(gr, 0x409500, 0x00000001); + nv_wr32(gr, 0x409504, 0x00000030); + if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(gr, "fuc09 req 0x30 timeout\n"); return -EBUSY; } - nv_wr32(priv, 0x409810, 0xb00095c8); - nv_wr32(priv, 0x409800, 0x00000000); - nv_wr32(priv, 0x409500, 0x00000001); - nv_wr32(priv, 0x409504, 0x00000031); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x31 timeout\n"); + nv_wr32(gr, 0x409810, 0xb00095c8); + nv_wr32(gr, 0x409800, 0x00000000); + nv_wr32(gr, 0x409500, 0x00000001); + nv_wr32(gr, 0x409504, 0x00000031); + if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(gr, "fuc09 req 0x31 timeout\n"); return -EBUSY; } - nv_wr32(priv, 0x409810, 0x00080420); - nv_wr32(priv, 0x409800, 0x00000000); - nv_wr32(priv, 0x409500, 0x00000001); - nv_wr32(priv, 0x409504, 0x00000032); - if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(priv, "fuc09 req 0x32 timeout\n"); + nv_wr32(gr, 0x409810, 0x00080420); + nv_wr32(gr, 0x409800, 0x00000000); + nv_wr32(gr, 0x409500, 0x00000001); + nv_wr32(gr, 0x409504, 0x00000032); + if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { + nv_error(gr, "fuc09 req 0x32 timeout\n"); return -EBUSY; } - nv_wr32(priv, 0x409614, 0x00000070); - nv_wr32(priv, 0x409614, 0x00000770); - nv_wr32(priv, 0x40802c, 0x00000001); + nv_wr32(gr, 0x409614, 0x00000070); + nv_wr32(gr, 0x409614, 0x00000770); + nv_wr32(gr, 0x40802c, 0x00000001); } - if (priv->data == NULL) { - int ret = gf100_grctx_generate(priv); + if (gr->data == NULL) { + int ret = gf100_grctx_generate(gr); if (ret) { - nv_error(priv, "failed to construct context\n"); + nv_error(gr, "failed to construct context\n"); return ret; } } @@ -1372,51 +1372,51 @@ gf100_gr_init_ctxctl(struct gf100_gr_priv *priv) } /* load HUB microcode */ - nvkm_mc(priv)->unk260(nvkm_mc(priv), 0); - nv_wr32(priv, 0x4091c0, 0x01000000); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + nv_wr32(gr, 0x4091c0, 0x01000000); for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) - nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]); + nv_wr32(gr, 0x4091c4, oclass->fecs.ucode->data.data[i]); - nv_wr32(priv, 0x409180, 0x01000000); + nv_wr32(gr, 0x409180, 0x01000000); for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(priv, 0x409188, i >> 6); - nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]); + nv_wr32(gr, 0x409188, i >> 6); + nv_wr32(gr, 0x409184, oclass->fecs.ucode->code.data[i]); } /* load GPC microcode */ - nv_wr32(priv, 0x41a1c0, 0x01000000); + nv_wr32(gr, 0x41a1c0, 0x01000000); for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) - nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); + nv_wr32(gr, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); - nv_wr32(priv, 0x41a180, 0x01000000); + nv_wr32(gr, 0x41a180, 0x01000000); for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(priv, 0x41a188, i >> 6); - nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]); + nv_wr32(gr, 0x41a188, i >> 6); + nv_wr32(gr, 0x41a184, oclass->gpccs.ucode->code.data[i]); } - nvkm_mc(priv)->unk260(nvkm_mc(priv), 1); + nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); /* load register lists */ - gf100_gr_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000); - gf100_gr_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000); - gf100_gr_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800); - gf100_gr_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00); + gf100_gr_init_csdata(gr, cclass->hub, 0x409000, 0x000, 0x000000); + gf100_gr_init_csdata(gr, cclass->gpc, 0x41a000, 0x000, 0x418000); + gf100_gr_init_csdata(gr, cclass->tpc, 0x41a000, 0x004, 0x419800); + gf100_gr_init_csdata(gr, cclass->ppc, 0x41a000, 0x008, 0x41be00); /* start HUB ucode running, it'll init the GPCs */ - nv_wr32(priv, 0x40910c, 0x00000000); - nv_wr32(priv, 0x409100, 0x00000002); - if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) { - nv_error(priv, "HUB_INIT timed out\n"); - gf100_gr_ctxctl_debug(priv); + nv_wr32(gr, 0x40910c, 0x00000000); + nv_wr32(gr, 0x409100, 0x00000002); + if (!nv_wait(gr, 0x409800, 0x80000000, 0x80000000)) { + nv_error(gr, "HUB_INIT timed out\n"); + gf100_gr_ctxctl_debug(gr); return -EBUSY; } - priv->size = nv_rd32(priv, 0x409804); - if (priv->data == NULL) { - int ret = gf100_grctx_generate(priv); + gr->size = nv_rd32(gr, 0x409804); + if (gr->data == NULL) { + int ret = gf100_grctx_generate(gr); if (ret) { - nv_error(priv, "failed to construct context\n"); + nv_error(gr, "failed to construct context\n"); return ret; } } @@ -1428,112 +1428,112 @@ int gf100_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct gf100_gr *gr = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; int ret, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + nv_wr32(gr, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x08a4), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0888), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x088c), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0890), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0894), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); + nv_wr32(gr, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); - gf100_gr_mmio(priv, oclass->mmio); + gf100_gr_mmio(gr, oclass->mmio); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); + nv_wr32(gr, GPC_BCAST(0x0980), data[0]); + nv_wr32(gr, GPC_BCAST(0x0984), data[1]); + nv_wr32(gr, GPC_BCAST(0x0988), data[2]); + nv_wr32(gr, GPC_BCAST(0x098c), data[3]); - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); } - if (nv_device(priv)->chipset != 0xd7) - nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918); + if (nv_device(gr)->chipset != 0xd7) + nv_wr32(gr, GPC_BCAST(0x1bd4), magicgpc918); else - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - - nv_wr32(priv, 0x400500, 0x00010001); - - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - - nv_wr32(priv, 0x409c24, 0x000f0000); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x40601c, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); + + nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + + nv_wr32(gr, 0x400500, 0x00010001); + + nv_wr32(gr, 0x400100, 0xffffffff); + nv_wr32(gr, 0x40013c, 0xffffffff); + + nv_wr32(gr, 0x409c24, 0x000f0000); + nv_wr32(gr, 0x404000, 0xc0000000); + nv_wr32(gr, 0x404600, 0xc0000000); + nv_wr32(gr, 0x408030, 0xc0000000); + nv_wr32(gr, 0x40601c, 0xc0000000); + nv_wr32(gr, 0x404490, 0xc0000000); + nv_wr32(gr, 0x406018, 0xc0000000); + nv_wr32(gr, 0x405840, 0xc0000000); + nv_wr32(gr, 0x405844, 0x00ffffff); + nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); + nv_mask(gr, 0x419eb4, 0x00001000, 0x00001000); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nv_wr32(gr, ROP_UNIT(rop, 0x144), 0xc0000000); + nv_wr32(gr, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(gr, 0x400108, 0xffffffff); + nv_wr32(gr, 0x400138, 0xffffffff); + nv_wr32(gr, 0x400118, 0xffffffff); + nv_wr32(gr, 0x400130, 0xffffffff); + nv_wr32(gr, 0x40011c, 0xffffffff); + nv_wr32(gr, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x34ce3464); + nv_wr32(gr, 0x400054, 0x34ce3464); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gf100_gr_init_ctxctl(priv); + return gf100_gr_init_ctxctl(gr); } void @@ -1544,10 +1544,10 @@ gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc) } int -gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname, +gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, struct gf100_gr_fuc *fuc) { - struct nvkm_device *device = nv_device(priv); + struct nvkm_device *device = nv_device(gr); const struct firmware *fw; char f[64]; char cname[16]; @@ -1566,7 +1566,7 @@ gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname, snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { - nv_error(priv, "failed to load %s\n", fwname); + nv_error(gr, "failed to load %s\n", fwname); return ret; } @@ -1579,19 +1579,19 @@ gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname, void gf100_gr_dtor(struct nvkm_object *object) { - struct gf100_gr_priv *priv = (void *)object; + struct gf100_gr *gr = (void *)object; - kfree(priv->data); + kfree(gr->data); - gf100_gr_dtor_fw(&priv->fuc409c); - gf100_gr_dtor_fw(&priv->fuc409d); - gf100_gr_dtor_fw(&priv->fuc41ac); - gf100_gr_dtor_fw(&priv->fuc41ad); + gf100_gr_dtor_fw(&gr->fuc409c); + gf100_gr_dtor_fw(&gr->fuc409d); + gf100_gr_dtor_fw(&gr->fuc41ac); + gf100_gr_dtor_fw(&gr->fuc41ad); - nvkm_gpuobj_ref(NULL, &priv->unk4188b8); - nvkm_gpuobj_ref(NULL, &priv->unk4188b4); + nvkm_gpuobj_ref(NULL, &gr->unk4188b8); + nvkm_gpuobj_ref(NULL, &gr->unk4188b4); - nvkm_gr_destroy(&priv->base); + nvkm_gr_destroy(&gr->base); } int @@ -1601,7 +1601,7 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, { struct gf100_gr_oclass *oclass = (void *)bclass; struct nvkm_device *device = nv_device(parent); - struct gf100_gr_priv *priv; + struct gf100_gr *gr; bool use_ext_fw, enable; int ret, i, j; @@ -1609,94 +1609,94 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, oclass->fecs.ucode == NULL); enable = use_ext_fw || oclass->fecs.ucode != NULL; - ret = nvkm_gr_create(parent, engine, bclass, enable, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, bclass, enable, &gr); + *pobject = nv_object(gr); if (ret) return ret; - nv_subdev(priv)->unit = 0x08001000; - nv_subdev(priv)->intr = gf100_gr_intr; + nv_subdev(gr)->unit = 0x08001000; + nv_subdev(gr)->intr = gf100_gr_intr; - priv->base.units = gf100_gr_units; + gr->base.units = gf100_gr_units; if (use_ext_fw) { - nv_info(priv, "using external firmware\n"); - if (gf100_gr_ctor_fw(priv, "fecs_inst", &priv->fuc409c) || - gf100_gr_ctor_fw(priv, "fecs_data", &priv->fuc409d) || - gf100_gr_ctor_fw(priv, "gpccs_inst", &priv->fuc41ac) || - gf100_gr_ctor_fw(priv, "gpccs_data", &priv->fuc41ad)) + nv_info(gr, "using external firmware\n"); + if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) || + gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) || + gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) || + gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad)) return -ENODEV; - priv->firmware = true; + gr->firmware = true; } - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0, - &priv->unk4188b4); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x1000, 256, 0, + &gr->unk4188b4); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0, - &priv->unk4188b8); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x1000, 256, 0, + &gr->unk4188b8); if (ret) return ret; for (i = 0; i < 0x1000; i += 4) { - nv_wo32(priv->unk4188b4, i, 0x00000010); - nv_wo32(priv->unk4188b8, i, 0x00000010); - } - - priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16; - priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f; - for (i = 0; i < priv->gpc_nr; i++) { - priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608)); - priv->tpc_total += priv->tpc_nr[i]; - priv->ppc_nr[i] = oclass->ppc_nr; - for (j = 0; j < priv->ppc_nr[i]; j++) { - u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4))); - priv->ppc_tpc_nr[i][j] = hweight8(mask); + nv_wo32(gr->unk4188b4, i, 0x00000010); + nv_wo32(gr->unk4188b8, i, 0x00000010); + } + + gr->rop_nr = (nv_rd32(gr, 0x409604) & 0x001f0000) >> 16; + gr->gpc_nr = nv_rd32(gr, 0x409604) & 0x0000001f; + for (i = 0; i < gr->gpc_nr; i++) { + gr->tpc_nr[i] = nv_rd32(gr, GPC_UNIT(i, 0x2608)); + gr->tpc_total += gr->tpc_nr[i]; + gr->ppc_nr[i] = oclass->ppc_nr; + for (j = 0; j < gr->ppc_nr[i]; j++) { + u8 mask = nv_rd32(gr, GPC_UNIT(i, 0x0c30 + (j * 4))); + gr->ppc_tpc_nr[i][j] = hweight8(mask); } } /*XXX: these need figuring out... though it might not even matter */ - switch (nv_device(priv)->chipset) { + switch (nv_device(gr)->chipset) { case 0xc0: - if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ - priv->magic_not_rop_nr = 0x07; + if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ + gr->magic_not_rop_nr = 0x07; } else - if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ - priv->magic_not_rop_nr = 0x05; + if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ + gr->magic_not_rop_nr = 0x05; } else - if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ - priv->magic_not_rop_nr = 0x06; + if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ + gr->magic_not_rop_nr = 0x06; } break; case 0xc3: /* 450, 4/0/0/0, 2 */ - priv->magic_not_rop_nr = 0x03; + gr->magic_not_rop_nr = 0x03; break; case 0xc4: /* 460, 3/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x01; + gr->magic_not_rop_nr = 0x01; break; case 0xc1: /* 2/0/0/0, 1 */ - priv->magic_not_rop_nr = 0x01; + gr->magic_not_rop_nr = 0x01; break; case 0xc8: /* 4/4/3/4, 5 */ - priv->magic_not_rop_nr = 0x06; + gr->magic_not_rop_nr = 0x06; break; case 0xce: /* 4/4/0/0, 4 */ - priv->magic_not_rop_nr = 0x03; + gr->magic_not_rop_nr = 0x03; break; case 0xcf: /* 4/0/0/0, 3 */ - priv->magic_not_rop_nr = 0x03; + gr->magic_not_rop_nr = 0x03; break; case 0xd7: case 0xd9: /* 1/0/0/0, 1 */ case 0xea: /* gk20a */ case 0x12b: /* gm20b */ - priv->magic_not_rop_nr = 0x01; + gr->magic_not_rop_nr = 0x01; break; } - nv_engine(priv)->cclass = *oclass->cclass; - nv_engine(priv)->sclass = oclass->sclass; + nv_engine(gr)->cclass = *oclass->cclass; + nv_engine(gr)->sclass = oclass->sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index f185f034d1ea9..b23bc32536fe9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -67,7 +67,7 @@ struct gf100_gr_zbc_depth { u32 l2; }; -struct gf100_gr_priv { +struct gf100_gr { struct nvkm_gr base; struct gf100_gr_fuc fuc409c; @@ -123,10 +123,10 @@ int gf100_gr_context_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_object **); void gf100_gr_context_dtor(struct nvkm_object *); -void gf100_gr_ctxctl_debug(struct gf100_gr_priv *); +void gf100_gr_ctxctl_debug(struct gf100_gr *); void gf100_gr_dtor_fw(struct gf100_gr_fuc *); -int gf100_gr_ctor_fw(struct gf100_gr_priv *, const char *, +int gf100_gr_ctor_fw(struct gf100_gr *, const char *, struct gf100_gr_fuc *); u64 gf100_gr_units(struct nvkm_gr *); int gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *, @@ -134,7 +134,7 @@ int gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_object **); void gf100_gr_dtor(struct nvkm_object *); int gf100_gr_init(struct nvkm_object *); -void gf100_gr_zbc_init(struct gf100_gr_priv *); +void gf100_gr_zbc_init(struct gf100_gr *); int gk104_gr_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *data, u32 size, @@ -199,11 +199,11 @@ struct gf100_gr_oclass { int ppc_nr; }; -int gf100_gr_wait_idle(struct gf100_gr_priv *); -void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *); -void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *); -void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *); -int gf100_gr_init_ctxctl(struct gf100_gr_priv *); +int gf100_gr_wait_idle(struct gf100_gr *); +void gf100_gr_mmio(struct gf100_gr *, const struct gf100_gr_pack *); +void gf100_gr_icmd(struct gf100_gr *, const struct gf100_gr_pack *); +void gf100_gr_mthd(struct gf100_gr *, const struct gf100_gr_pack *); +int gf100_gr_init_ctxctl(struct gf100_gr *); /* register init value lists */ @@ -279,7 +279,7 @@ extern const struct gf100_gr_init gm107_gr_init_tex_0[]; extern const struct gf100_gr_init gm107_gr_init_l1c_0[]; extern const struct gf100_gr_init gm107_gr_init_wwdx_0[]; extern const struct gf100_gr_init gm107_gr_init_cbm_0[]; -void gm107_gr_init_bios(struct gf100_gr_priv *); +void gm107_gr_init_bios(struct gf100_gr *); extern const struct gf100_gr_pack gm204_gr_pack_mmio[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index 46f7844eca704..9f83122dc1a8d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -196,9 +196,9 @@ int gk104_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - struct nvkm_pmu *pmu = nvkm_pmu(priv); - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct gf100_gr *gr = (void *)object; + struct nvkm_pmu *pmu = nvkm_pmu(gr); + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; @@ -207,107 +207,107 @@ gk104_gr_init(struct nvkm_object *object) if (pmu) pmu->pgob(pmu, false); - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + nv_wr32(gr, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x08a4), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0888), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x088c), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0890), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0894), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); + nv_wr32(gr, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); - gf100_gr_mmio(priv, oclass->mmio); + gf100_gr_mmio(gr, oclass->mmio); - nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + nv_wr32(gr, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x0980), data[0]); + nv_wr32(gr, GPC_BCAST(0x0984), data[1]); + nv_wr32(gr, GPC_BCAST(0x0988), data[2]); + nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - - nv_wr32(priv, 0x400500, 0x00010001); - - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - - nv_wr32(priv, 0x409ffc, 0x00000000); - nv_wr32(priv, 0x409c14, 0x00003e3e); - nv_wr32(priv, 0x409c24, 0x000f0001); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + + nv_wr32(gr, 0x400500, 0x00010001); + + nv_wr32(gr, 0x400100, 0xffffffff); + nv_wr32(gr, 0x40013c, 0xffffffff); + + nv_wr32(gr, 0x409ffc, 0x00000000); + nv_wr32(gr, 0x409c14, 0x00003e3e); + nv_wr32(gr, 0x409c24, 0x000f0001); + nv_wr32(gr, 0x404000, 0xc0000000); + nv_wr32(gr, 0x404600, 0xc0000000); + nv_wr32(gr, 0x408030, 0xc0000000); + nv_wr32(gr, 0x404490, 0xc0000000); + nv_wr32(gr, 0x406018, 0xc0000000); + nv_wr32(gr, 0x407020, 0x40000000); + nv_wr32(gr, 0x405840, 0xc0000000); + nv_wr32(gr, 0x405844, 0x00ffffff); + nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); + nv_mask(gr, 0x419eb4, 0x00001000, 0x00001000); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x3038), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nv_wr32(gr, ROP_UNIT(rop, 0x144), 0xc0000000); + nv_wr32(gr, ROP_UNIT(rop, 0x070), 0xc0000000); + nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(gr, 0x400108, 0xffffffff); + nv_wr32(gr, 0x400138, 0xffffffff); + nv_wr32(gr, 0x400118, 0xffffffff); + nv_wr32(gr, 0x400130, 0xffffffff); + nv_wr32(gr, 0x40011c, 0xffffffff); + nv_wr32(gr, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x34ce3464); + nv_wr32(gr, 0x400054, 0x34ce3464); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gf100_gr_init_ctxctl(priv); + return gf100_gr_init_ctxctl(gr); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index fc4a910b24982..9816303ad7164 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -160,46 +160,46 @@ gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { int err; - struct gf100_gr_priv *priv; + struct gf100_gr *gr; struct gf100_gr_fuc fuc; err = gf100_gr_ctor(parent, engine, oclass, data, size, pobject); if (err) return err; - priv = (void *)*pobject; + gr = (void *)*pobject; - err = gf100_gr_ctor_fw(priv, "sw_nonctx", &fuc); + err = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc); if (err) return err; - priv->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc); + gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc); gf100_gr_dtor_fw(&fuc); - if (IS_ERR(priv->fuc_sw_nonctx)) - return PTR_ERR(priv->fuc_sw_nonctx); + if (IS_ERR(gr->fuc_sw_nonctx)) + return PTR_ERR(gr->fuc_sw_nonctx); - err = gf100_gr_ctor_fw(priv, "sw_ctx", &fuc); + err = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc); if (err) return err; - priv->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc); + gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc); gf100_gr_dtor_fw(&fuc); - if (IS_ERR(priv->fuc_sw_ctx)) - return PTR_ERR(priv->fuc_sw_ctx); + if (IS_ERR(gr->fuc_sw_ctx)) + return PTR_ERR(gr->fuc_sw_ctx); - err = gf100_gr_ctor_fw(priv, "sw_bundle_init", &fuc); + err = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc); if (err) return err; - priv->fuc_bundle = gk20a_gr_av_to_init(&fuc); + gr->fuc_bundle = gk20a_gr_av_to_init(&fuc); gf100_gr_dtor_fw(&fuc); - if (IS_ERR(priv->fuc_bundle)) - return PTR_ERR(priv->fuc_bundle); + if (IS_ERR(gr->fuc_bundle)) + return PTR_ERR(gr->fuc_bundle); - err = gf100_gr_ctor_fw(priv, "sw_method_init", &fuc); + err = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc); if (err) return err; - priv->fuc_method = gk20a_gr_av_to_method(&fuc); + gr->fuc_method = gk20a_gr_av_to_method(&fuc); gf100_gr_dtor_fw(&fuc); - if (IS_ERR(priv->fuc_method)) - return PTR_ERR(priv->fuc_method); + if (IS_ERR(gr->fuc_method)) + return PTR_ERR(gr->fuc_method); return 0; } @@ -207,26 +207,26 @@ gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, void gk20a_gr_dtor(struct nvkm_object *object) { - struct gf100_gr_priv *priv = (void *)object; + struct gf100_gr *gr = (void *)object; - gk20a_gr_init_dtor(priv->fuc_method); - gk20a_gr_init_dtor(priv->fuc_bundle); - gk20a_gr_init_dtor(priv->fuc_sw_ctx); - gk20a_gr_init_dtor(priv->fuc_sw_nonctx); + gk20a_gr_init_dtor(gr->fuc_method); + gk20a_gr_init_dtor(gr->fuc_bundle); + gk20a_gr_init_dtor(gr->fuc_sw_ctx); + gk20a_gr_init_dtor(gr->fuc_sw_nonctx); gf100_gr_dtor(object); } static int -gk20a_gr_wait_mem_scrubbing(struct gf100_gr_priv *priv) +gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) { - if (!nv_wait(priv, 0x40910c, 0x6, 0x0)) { - nv_error(priv, "FECS mem scrubbing timeout\n"); + if (!nv_wait(gr, 0x40910c, 0x6, 0x0)) { + nv_error(gr, "FECS mem scrubbing timeout\n"); return -ETIMEDOUT; } - if (!nv_wait(priv, 0x41a10c, 0x6, 0x0)) { - nv_error(priv, "GPCCS mem scrubbing timeout\n"); + if (!nv_wait(gr, 0x41a10c, 0x6, 0x0)) { + nv_error(gr, "GPCCS mem scrubbing timeout\n"); return -ETIMEDOUT; } @@ -234,109 +234,109 @@ gk20a_gr_wait_mem_scrubbing(struct gf100_gr_priv *priv) } static void -gk20a_gr_set_hww_esr_report_mask(struct gf100_gr_priv *priv) +gk20a_gr_set_hww_esr_report_mask(struct gf100_gr *gr) { - nv_wr32(priv, 0x419e44, 0x1ffffe); - nv_wr32(priv, 0x419e4c, 0x7f); + nv_wr32(gr, 0x419e44, 0x1ffffe); + nv_wr32(gr, 0x419e4c, 0x7f); } int gk20a_gr_init(struct nvkm_object *object) { struct gk20a_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct gf100_gr *gr = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc; int ret, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; /* Clear SCC RAM */ - nv_wr32(priv, 0x40802c, 0x1); + nv_wr32(gr, 0x40802c, 0x1); - gf100_gr_mmio(priv, priv->fuc_sw_nonctx); + gf100_gr_mmio(gr, gr->fuc_sw_nonctx); - ret = gk20a_gr_wait_mem_scrubbing(priv); + ret = gk20a_gr_wait_mem_scrubbing(gr); if (ret) return ret; - ret = gf100_gr_wait_idle(priv); + ret = gf100_gr_wait_idle(gr); if (ret) return ret; /* MMU debug buffer */ - nv_wr32(priv, 0x100cc8, priv->unk4188b4->addr >> 8); - nv_wr32(priv, 0x100ccc, priv->unk4188b8->addr >> 8); + nv_wr32(gr, 0x100cc8, gr->unk4188b4->addr >> 8); + nv_wr32(gr, 0x100ccc, gr->unk4188b8->addr >> 8); if (oclass->init_gpc_mmu) - oclass->init_gpc_mmu(priv); + oclass->init_gpc_mmu(gr); /* Set the PE as stream master */ - nv_mask(priv, 0x503018, 0x1, 0x1); + nv_mask(gr, 0x503018, 0x1, 0x1); /* Zcull init */ memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x0980), data[0]); + nv_wr32(gr, GPC_BCAST(0x0984), data[1]); + nv_wr32(gr, GPC_BCAST(0x0988), data[2]); + nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); /* Enable FIFO access */ - nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(gr, 0x400500, 0x00010001); /* Enable interrupts */ - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); + nv_wr32(gr, 0x400100, 0xffffffff); + nv_wr32(gr, 0x40013c, 0xffffffff); /* Enable FECS error interrupts */ - nv_wr32(priv, 0x409c24, 0x000f0000); + nv_wr32(gr, 0x409c24, 0x000f0000); /* Enable hardware warning exceptions */ - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); + nv_wr32(gr, 0x404000, 0xc0000000); + nv_wr32(gr, 0x404600, 0xc0000000); if (oclass->set_hww_esr_report_mask) - oclass->set_hww_esr_report_mask(priv); + oclass->set_hww_esr_report_mask(gr); /* Enable TPC exceptions per GPC */ - nv_wr32(priv, 0x419d0c, 0x2); - nv_wr32(priv, 0x41ac94, (((1 << priv->tpc_total) - 1) & 0xff) << 16); + nv_wr32(gr, 0x419d0c, 0x2); + nv_wr32(gr, 0x41ac94, (((1 << gr->tpc_total) - 1) & 0xff) << 16); /* Reset and enable all exceptions */ - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(gr, 0x400108, 0xffffffff); + nv_wr32(gr, 0x400138, 0xffffffff); + nv_wr32(gr, 0x400118, 0xffffffff); + nv_wr32(gr, 0x400130, 0xffffffff); + nv_wr32(gr, 0x40011c, 0xffffffff); + nv_wr32(gr, 0x400134, 0xffffffff); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gf100_gr_init_ctxctl(priv); + return gf100_gr_init_ctxctl(gr); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h index b36958505a81f..411099d222d43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h @@ -28,8 +28,8 @@ struct gk20a_gr_oclass { struct gf100_gr_oclass gf100; - void (*init_gpc_mmu)(struct gf100_gr_priv *); - void (*set_hww_esr_report_mask)(struct gf100_gr_priv *); + void (*init_gpc_mmu)(struct gf100_gr *); + void (*set_hww_esr_report_mask)(struct gf100_gr *); }; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index a5ebd459bc24b..5e9560f6ac0e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -292,7 +292,7 @@ gm107_gr_pack_mmio[] = { ******************************************************************************/ void -gm107_gr_init_bios(struct gf100_gr_priv *priv) +gm107_gr_init_bios(struct gf100_gr *gr) { static const struct { u32 ctrl; @@ -304,7 +304,7 @@ gm107_gr_init_bios(struct gf100_gr_priv *priv) { 0x419af0, 0x419af4 }, { 0x419af8, 0x419afc }, }; - struct nvkm_bios *bios = nvkm_bios(priv); + struct nvkm_bios *bios = nvkm_bios(gr); struct nvbios_P0260E infoE; struct nvbios_P0260X infoX; int E = -1, X; @@ -312,9 +312,9 @@ gm107_gr_init_bios(struct gf100_gr_priv *priv) while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) { if (X = -1, E < ARRAY_SIZE(regs)) { - nv_wr32(priv, regs[E].ctrl, infoE.data); + nv_wr32(gr, regs[E].ctrl, infoE.data); while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX)) - nv_wr32(priv, regs[E].data, infoX.data); + nv_wr32(gr, regs[E].data, infoX.data); } } } @@ -323,113 +323,113 @@ int gm107_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct gf100_gr *gr = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; int ret, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8); - nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8); + nv_wr32(gr, GPC_BCAST(0x0880), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0890), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x0894), 0x00000000); + nv_wr32(gr, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); + nv_wr32(gr, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); - gf100_gr_mmio(priv, oclass->mmio); + gf100_gr_mmio(gr, oclass->mmio); - gm107_gr_init_bios(priv); + gm107_gr_init_bios(gr); - nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + nv_wr32(gr, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x0980), data[0]); + nv_wr32(gr, GPC_BCAST(0x0984), data[1]); + nv_wr32(gr, GPC_BCAST(0x0988), data[2]); + nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - - nv_wr32(priv, 0x400500, 0x00010001); - - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - nv_wr32(priv, 0x400124, 0x00000002); - nv_wr32(priv, 0x409c24, 0x000e0000); - - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++) - nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + + nv_wr32(gr, 0x400500, 0x00010001); + + nv_wr32(gr, 0x400100, 0xffffffff); + nv_wr32(gr, 0x40013c, 0xffffffff); + nv_wr32(gr, 0x400124, 0x00000002); + nv_wr32(gr, 0x409c24, 0x000e0000); + + nv_wr32(gr, 0x404000, 0xc0000000); + nv_wr32(gr, 0x404600, 0xc0000000); + nv_wr32(gr, 0x408030, 0xc0000000); + nv_wr32(gr, 0x404490, 0xc0000000); + nv_wr32(gr, 0x406018, 0xc0000000); + nv_wr32(gr, 0x407020, 0x40000000); + nv_wr32(gr, 0x405840, 0xc0000000); + nv_wr32(gr, 0x405844, 0x00ffffff); + nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < 2 /* gr->ppc_nr[gpc] */; ppc++) + nv_wr32(gr, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nv_wr32(gr, ROP_UNIT(rop, 0x144), 0x40000000); + nv_wr32(gr, ROP_UNIT(rop, 0x070), 0x40000000); + nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(gr, 0x400108, 0xffffffff); + nv_wr32(gr, 0x400138, 0xffffffff); + nv_wr32(gr, 0x400118, 0xffffffff); + nv_wr32(gr, 0x400130, 0xffffffff); + nv_wr32(gr, 0x40011c, 0xffffffff); + nv_wr32(gr, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x2c350f63); + nv_wr32(gr, 0x400054, 0x2c350f63); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gf100_gr_init_ctxctl(priv); + return gf100_gr_init_ctxctl(gr); } #include "fuc/hubgm107.fuc5.h" diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index fdb1dcf16a595..4cc60edafaef8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -243,7 +243,7 @@ gm204_gr_data[] = { ******************************************************************************/ static int -gm204_gr_init_ctxctl(struct gf100_gr_priv *priv) +gm204_gr_init_ctxctl(struct gf100_gr *gr) { return 0; } @@ -252,122 +252,122 @@ int gm204_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr_priv *priv = (void *)object; - const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total); + struct gf100_gr *gr = (void *)object; + const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; int ret, i; u32 tmp; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - tmp = nv_rd32(priv, 0x100c80); /*XXX: mask? */ - nv_wr32(priv, 0x418880, 0x00001000 | (tmp & 0x00000fff)); - nv_wr32(priv, 0x418890, 0x00000000); - nv_wr32(priv, 0x418894, 0x00000000); - nv_wr32(priv, 0x4188b4, priv->unk4188b4->addr >> 8); - nv_wr32(priv, 0x4188b8, priv->unk4188b8->addr >> 8); - nv_mask(priv, 0x4188b0, 0x00040000, 0x00040000); + tmp = nv_rd32(gr, 0x100c80); /*XXX: mask? */ + nv_wr32(gr, 0x418880, 0x00001000 | (tmp & 0x00000fff)); + nv_wr32(gr, 0x418890, 0x00000000); + nv_wr32(gr, 0x418894, 0x00000000); + nv_wr32(gr, 0x4188b4, gr->unk4188b4->addr >> 8); + nv_wr32(gr, 0x4188b8, gr->unk4188b8->addr >> 8); + nv_mask(gr, 0x4188b0, 0x00040000, 0x00040000); /*XXX: belongs in fb */ - nv_wr32(priv, 0x100cc8, priv->unk4188b4->addr >> 8); - nv_wr32(priv, 0x100ccc, priv->unk4188b8->addr >> 8); - nv_mask(priv, 0x100cc4, 0x00040000, 0x00040000); + nv_wr32(gr, 0x100cc8, gr->unk4188b4->addr >> 8); + nv_wr32(gr, 0x100ccc, gr->unk4188b8->addr >> 8); + nv_mask(gr, 0x100cc4, 0x00040000, 0x00040000); - gf100_gr_mmio(priv, oclass->mmio); + gf100_gr_mmio(gr, oclass->mmio); - gm107_gr_init_bios(priv); + gm107_gr_init_bios(gr); - nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001); + nv_wr32(gr, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); - memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr)); - for (i = 0, gpc = -1; i < priv->tpc_total; i++) { + memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); + for (i = 0, gpc = -1; i < gr->tpc_total; i++) { do { - gpc = (gpc + 1) % priv->gpc_nr; + gpc = (gpc + 1) % gr->gpc_nr; } while (!tpcnr[gpc]); - tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--; + tpc = gr->tpc_nr[gpc] - tpcnr[gpc]--; data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(priv, GPC_BCAST(0x0980), data[0]); - nv_wr32(priv, GPC_BCAST(0x0984), data[1]); - nv_wr32(priv, GPC_BCAST(0x0988), data[2]); - nv_wr32(priv, GPC_BCAST(0x098c), data[3]); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - nv_wr32(priv, GPC_UNIT(gpc, 0x0914), - priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]); - nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 | - priv->tpc_total); - nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x0980), data[0]); + nv_wr32(gr, GPC_BCAST(0x0984), data[1]); + nv_wr32(gr, GPC_BCAST(0x0988), data[2]); + nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800)); - nv_wr32(priv, GPC_BCAST(0x033c), nv_rd32(priv, 0x100804)); - - nv_wr32(priv, 0x400500, 0x00010001); - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - nv_wr32(priv, 0x400124, 0x00000002); - nv_wr32(priv, 0x409c24, 0x000e0000); - nv_wr32(priv, 0x405848, 0xc0000000); - nv_wr32(priv, 0x40584c, 0x00000001); - nv_wr32(priv, 0x404000, 0xc0000000); - nv_wr32(priv, 0x404600, 0xc0000000); - nv_wr32(priv, 0x408030, 0xc0000000); - nv_wr32(priv, 0x404490, 0xc0000000); - nv_wr32(priv, 0x406018, 0xc0000000); - nv_wr32(priv, 0x407020, 0x40000000); - nv_wr32(priv, 0x405840, 0xc0000000); - nv_wr32(priv, 0x405844, 0x00ffffff); - nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008); - - for (gpc = 0; gpc < priv->gpc_nr; gpc++) { - for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) - nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000); - for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) { - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); - nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); + nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + nv_wr32(gr, GPC_BCAST(0x033c), nv_rd32(gr, 0x100804)); + + nv_wr32(gr, 0x400500, 0x00010001); + nv_wr32(gr, 0x400100, 0xffffffff); + nv_wr32(gr, 0x40013c, 0xffffffff); + nv_wr32(gr, 0x400124, 0x00000002); + nv_wr32(gr, 0x409c24, 0x000e0000); + nv_wr32(gr, 0x405848, 0xc0000000); + nv_wr32(gr, 0x40584c, 0x00000001); + nv_wr32(gr, 0x404000, 0xc0000000); + nv_wr32(gr, 0x404600, 0xc0000000); + nv_wr32(gr, 0x408030, 0xc0000000); + nv_wr32(gr, 0x404490, 0xc0000000); + nv_wr32(gr, 0x406018, 0xc0000000); + nv_wr32(gr, 0x407020, 0x40000000); + nv_wr32(gr, 0x405840, 0xc0000000); + nv_wr32(gr, 0x405844, 0x00ffffff); + nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); + + for (gpc = 0; gpc < gr->gpc_nr; gpc++) { + for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) + nv_wr32(gr, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } - nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } - for (rop = 0; rop < priv->rop_nr; rop++) { - nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000); - nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff); + for (rop = 0; rop < gr->rop_nr; rop++) { + nv_wr32(gr, ROP_UNIT(rop, 0x144), 0x40000000); + nv_wr32(gr, ROP_UNIT(rop, 0x070), 0x40000000); + nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); + nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400118, 0xffffffff); - nv_wr32(priv, 0x400130, 0xffffffff); - nv_wr32(priv, 0x40011c, 0xffffffff); - nv_wr32(priv, 0x400134, 0xffffffff); + nv_wr32(gr, 0x400108, 0xffffffff); + nv_wr32(gr, 0x400138, 0xffffffff); + nv_wr32(gr, 0x400118, 0xffffffff); + nv_wr32(gr, 0x400130, 0xffffffff); + nv_wr32(gr, 0x40011c, 0xffffffff); + nv_wr32(gr, 0x400134, 0xffffffff); - nv_wr32(priv, 0x400054, 0x2c350f63); + nv_wr32(gr, 0x400054, 0x2c350f63); - gf100_gr_zbc_init(priv); + gf100_gr_zbc_init(gr); - return gm204_gr_init_ctxctl(priv); + return gm204_gr_init_ctxctl(gr); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c index 897628062d589..6b9c84f8f12de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -35,34 +35,34 @@ gm20b_gr_sclass[] = { }; static void -gm20b_gr_init_gpc_mmu(struct gf100_gr_priv *priv) +gm20b_gr_init_gpc_mmu(struct gf100_gr *gr) { u32 val; /* TODO this needs to be removed once secure boot works */ if (1) { - nv_wr32(priv, 0x100ce4, 0xffffffff); + nv_wr32(gr, 0x100ce4, 0xffffffff); } /* TODO update once secure boot works */ - val = nv_rd32(priv, 0x100c80); + val = nv_rd32(gr, 0x100c80); val &= 0xf000087f; - nv_wr32(priv, 0x418880, val); - nv_wr32(priv, 0x418890, 0); - nv_wr32(priv, 0x418894, 0); + nv_wr32(gr, 0x418880, val); + nv_wr32(gr, 0x418890, 0); + nv_wr32(gr, 0x418894, 0); - nv_wr32(priv, 0x4188b0, nv_rd32(priv, 0x100cc4)); - nv_wr32(priv, 0x4188b4, nv_rd32(priv, 0x100cc8)); - nv_wr32(priv, 0x4188b8, nv_rd32(priv, 0x100ccc)); + nv_wr32(gr, 0x4188b0, nv_rd32(gr, 0x100cc4)); + nv_wr32(gr, 0x4188b4, nv_rd32(gr, 0x100cc8)); + nv_wr32(gr, 0x4188b8, nv_rd32(gr, 0x100ccc)); - nv_wr32(priv, 0x4188ac, nv_rd32(priv, 0x100800)); + nv_wr32(gr, 0x4188ac, nv_rd32(gr, 0x100800)); } static void -gm20b_gr_set_hww_esr_report_mask(struct gf100_gr_priv *priv) +gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr) { - nv_wr32(priv, 0x419e44, 0xdffffe); - nv_wr32(priv, 0x419e4c, 0x5); + nv_wr32(gr, 0x419e44, 0xdffffe); + nv_wr32(gr, 0x419e4c, 0x5); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 81abe6fb38724..e161abe88fb8a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -345,7 +345,7 @@ nv04_gr_ctx_regs[] = { NV04_PGRAPH_DEBUG_3 }; -struct nv04_gr_priv { +struct nv04_gr { struct nvkm_gr base; struct nv04_gr_chan *chan[16]; spinlock_t lock; @@ -358,8 +358,8 @@ struct nv04_gr_chan { }; -static inline struct nv04_gr_priv * -nv04_gr_priv(struct nv04_gr_chan *chan) +static inline struct nv04_gr * +nv04_gr(struct nv04_gr_chan *chan) { return (void *)nv_object(chan)->engine; } @@ -445,8 +445,8 @@ nv04_gr_priv(struct nv04_gr_chan *chan) static void nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value) { - struct nv04_gr_priv *priv = (void *)object->engine; - int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; + struct nv04_gr *gr = (void *)object->engine; + int subc = (nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; u32 tmp; tmp = nv_ro32(object, 0x00); @@ -454,8 +454,8 @@ nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value) tmp |= value; nv_wo32(object, 0x00, tmp); - nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp); - nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); + nv_wr32(gr, NV04_PGRAPH_CTX_SWITCH1, tmp); + nv_wr32(gr, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); } static void @@ -527,7 +527,7 @@ static int nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, void *args, u32 size) { - struct nv04_gr_priv *priv = (void *)object->engine; + struct nv04_gr *gr = (void *)object->engine; u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; @@ -539,8 +539,8 @@ nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(priv, 0x40053c, min); - nv_wr32(priv, 0x400544, max); + nv_wr32(gr, 0x40053c, min); + nv_wr32(gr, 0x400544, max); return 0; } @@ -548,7 +548,7 @@ static int nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, void *args, u32 size) { - struct nv04_gr_priv *priv = (void *)object->engine; + struct nv04_gr *gr = (void *)object->engine; u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; @@ -560,8 +560,8 @@ nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(priv, 0x400540, min); - nv_wr32(priv, 0x400548, max); + nv_wr32(gr, 0x400540, min); + nv_wr32(gr, 0x400548, max); return 0; } @@ -1031,13 +1031,13 @@ nv04_gr_sclass[] = { ******************************************************************************/ static struct nv04_gr_chan * -nv04_gr_channel(struct nv04_gr_priv *priv) +nv04_gr_channel(struct nv04_gr *gr) { struct nv04_gr_chan *chan = NULL; - if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { - int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24; - if (chid < ARRAY_SIZE(priv->chan)) - chan = priv->chan[chid]; + if (nv_rd32(gr, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { + int chid = nv_rd32(gr, NV04_PGRAPH_CTX_USER) >> 24; + if (chid < ARRAY_SIZE(gr->chan)) + chan = gr->chan[chid]; } return chan; } @@ -1045,55 +1045,55 @@ nv04_gr_channel(struct nv04_gr_priv *priv) static int nv04_gr_load_context(struct nv04_gr_chan *chan, int chid) { - struct nv04_gr_priv *priv = nv04_gr_priv(chan); + struct nv04_gr *gr = nv04_gr(chan); int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) - nv_wr32(priv, nv04_gr_ctx_regs[i], chan->nv04[i]); + nv_wr32(gr, nv04_gr_ctx_regs[i], chan->nv04[i]); - nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100); - nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); - nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); + nv_wr32(gr, NV04_PGRAPH_CTX_CONTROL, 0x10010100); + nv_mask(gr, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nv_mask(gr, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); return 0; } static int nv04_gr_unload_context(struct nv04_gr_chan *chan) { - struct nv04_gr_priv *priv = nv04_gr_priv(chan); + struct nv04_gr *gr = nv04_gr(chan); int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) - chan->nv04[i] = nv_rd32(priv, nv04_gr_ctx_regs[i]); + chan->nv04[i] = nv_rd32(gr, nv04_gr_ctx_regs[i]); - nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000); - nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + nv_wr32(gr, NV04_PGRAPH_CTX_CONTROL, 0x10000000); + nv_mask(gr, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); return 0; } static void -nv04_gr_context_switch(struct nv04_gr_priv *priv) +nv04_gr_context_switch(struct nv04_gr *gr) { struct nv04_gr_chan *prev = NULL; struct nv04_gr_chan *next = NULL; unsigned long flags; int chid; - spin_lock_irqsave(&priv->lock, flags); - nv04_gr_idle(priv); + spin_lock_irqsave(&gr->lock, flags); + nv04_gr_idle(gr); /* If previous context is valid, we need to save it */ - prev = nv04_gr_channel(priv); + prev = nv04_gr_channel(gr); if (prev) nv04_gr_unload_context(prev); /* load context for next channel */ - chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; - next = priv->chan[chid]; + chid = (nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; + next = gr->chan[chid]; if (next) nv04_gr_load_context(next, chid); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); } static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg) @@ -1115,7 +1115,7 @@ nv04_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object **pobject) { struct nvkm_fifo_chan *fifo = (void *)parent; - struct nv04_gr_priv *priv = (void *)engine; + struct nv04_gr *gr = (void *)engine; struct nv04_gr_chan *chan; unsigned long flags; int ret; @@ -1125,33 +1125,33 @@ nv04_gr_context_ctor(struct nvkm_object *parent, if (ret) return ret; - spin_lock_irqsave(&priv->lock, flags); - if (priv->chan[fifo->chid]) { - *pobject = nv_object(priv->chan[fifo->chid]); + spin_lock_irqsave(&gr->lock, flags); + if (gr->chan[fifo->chid]) { + *pobject = nv_object(gr->chan[fifo->chid]); atomic_inc(&(*pobject)->refcount); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); nvkm_object_destroy(&chan->base); return 1; } *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; - priv->chan[fifo->chid] = chan; + gr->chan[fifo->chid] = chan; chan->chid = fifo->chid; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); return 0; } static void nv04_gr_context_dtor(struct nvkm_object *object) { - struct nv04_gr_priv *priv = (void *)object->engine; + struct nv04_gr *gr = (void *)object->engine; struct nv04_gr_chan *chan = (void *)object; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - priv->chan[chan->chid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&gr->lock, flags); nvkm_object_destroy(&chan->base); } @@ -1159,16 +1159,16 @@ nv04_gr_context_dtor(struct nvkm_object *object) static int nv04_gr_context_fini(struct nvkm_object *object, bool suspend) { - struct nv04_gr_priv *priv = (void *)object->engine; + struct nv04_gr *gr = (void *)object->engine; struct nv04_gr_chan *chan = (void *)object; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (nv04_gr_channel(priv) == chan) + spin_lock_irqsave(&gr->lock, flags); + nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv04_gr_channel(gr) == chan) nv04_gr_unload_context(chan); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->lock, flags); + nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); return nvkm_object_fini(&chan->base, suspend); } @@ -1248,28 +1248,28 @@ nv04_gr_nsource[] = { static void nv04_gr_intr(struct nvkm_subdev *subdev) { - struct nv04_gr_priv *priv = (void *)subdev; + struct nv04_gr *gr = (void *)subdev; struct nv04_gr_chan *chan = NULL; struct nvkm_namedb *namedb = NULL; struct nvkm_handle *handle = NULL; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x0f000000) >> 24; u32 subc = (addr & 0x0000e000) >> 13; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff; - u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4; + u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(gr, 0x400180 + subc * 4) & 0xff; + u32 inst = (nv_rd32(gr, 0x40016c) & 0xffff) << 4; u32 show = stat; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - chan = priv->chan[chid]; + spin_lock_irqsave(&gr->lock, flags); + chan = gr->chan[chid]; if (chan) namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); if (stat & NV_PGRAPH_INTR_NOTIFY) { if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { @@ -1280,24 +1280,24 @@ nv04_gr_intr(struct nvkm_subdev *subdev) } if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + nv_wr32(gr, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv04_gr_context_switch(priv); + nv04_gr_context_switch(gr); } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nv_wr32(gr, NV03_PGRAPH_INTR, stat); + nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); + nv_error(gr, "%s", ""); nvkm_bitfield_print(nv04_gr_intr_name, show); pr_cont(" nsource:"); nvkm_bitfield_print(nv04_gr_nsource, nsource); pr_cont(" nstatus:"); nvkm_bitfield_print(nv04_gr_nstatus, nstatus); pr_cont("\n"); - nv_error(priv, + nv_error(gr, "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, nvkm_client_name(chan), subc, class, mthd, data); @@ -1311,19 +1311,19 @@ nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_gr_priv *priv; + struct nv04_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv04_gr_intr; - nv_engine(priv)->cclass = &nv04_gr_cclass; - nv_engine(priv)->sclass = nv04_gr_sclass; - spin_lock_init(&priv->lock); + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv04_gr_intr; + nv_engine(gr)->cclass = &nv04_gr_cclass; + nv_engine(gr)->sclass = nv04_gr_sclass; + spin_lock_init(&gr->lock); return 0; } @@ -1331,41 +1331,41 @@ static int nv04_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nv04_gr_priv *priv = (void *)engine; + struct nv04_gr *gr = (void *)engine; int ret; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; /* Enable PGRAPH interrupts */ - nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(priv, NV04_PGRAPH_VALID1, 0); - nv_wr32(priv, NV04_PGRAPH_VALID2, 0); - /*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000); + nv_wr32(gr, NV03_PGRAPH_INTR, 0xFFFFFFFF); + nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nv_wr32(gr, NV04_PGRAPH_VALID1, 0); + nv_wr32(gr, NV04_PGRAPH_VALID2, 0); + /*nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x000001FF); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x1231c000); /*1231C000 blob, 001 haiku*/ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100); + nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x72111100); /*0x72111100 blob , 01 haiku*/ - /*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071); + /*nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ + nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x11d5f071); /*haiku same*/ - /*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); + /*nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ + nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); /*haiku and blob 10d4*/ - nv_wr32(priv, NV04_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL , 0x10000100); - nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + nv_wr32(gr, NV04_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(gr, NV04_PGRAPH_CTX_CONTROL , 0x10000100); + nv_mask(gr, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); /* These don't belong here, they're part of a per-channel context */ - nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); + nv_wr32(gr, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); + nv_wr32(gr, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 57f05c86a5913..af33514456a4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -385,7 +385,7 @@ static int nv17_gr_ctx_regs[] = { 0x00400a04, }; -struct nv10_gr_priv { +struct nv10_gr { struct nvkm_gr base; struct nv10_gr_chan *chan[32]; spinlock_t lock; @@ -401,8 +401,8 @@ struct nv10_gr_chan { }; -static inline struct nv10_gr_priv * -nv10_gr_priv(struct nv10_gr_chan *chan) +static inline struct nv10_gr * +nv10_gr(struct nv10_gr_chan *chan) { return (void *)nv_object(chan)->engine; } @@ -411,20 +411,20 @@ nv10_gr_priv(struct nv10_gr_chan *chan) * Graphics object classes ******************************************************************************/ -#define PIPE_SAVE(priv, state, addr) \ +#define PIPE_SAVE(gr, state, addr) \ do { \ int __i; \ - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \ + state[__i] = nv_rd32(gr, NV10_PGRAPH_PIPE_DATA); \ } while (0) -#define PIPE_RESTORE(priv, state, addr) \ +#define PIPE_RESTORE(gr, state, addr) \ do { \ int __i; \ - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \ + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, state[__i]); \ } while (0) static struct nvkm_oclass @@ -478,7 +478,7 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nv10_gr_chan *chan = (void *)object->parent; - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe = &chan->pipe_state; u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; u32 xfmode0, xfmode1; @@ -490,62 +490,62 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, if (mthd != 0x1644) return 0; - nv04_gr_idle(priv); + nv04_gr_idle(gr); - PIPE_SAVE(priv, pipe_0x0040, 0x0040); - PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200); + PIPE_SAVE(gr, pipe_0x0040, 0x0040); + PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200); - PIPE_RESTORE(priv, chan->lma_window, 0x6790); + PIPE_RESTORE(gr, chan->lma_window, 0x6790); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1); + xfmode0 = nv_rd32(gr, NV10_PGRAPH_XFMODE0); + xfmode1 = nv_rd32(gr, NV10_PGRAPH_XFMODE1); - PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(priv, pipe_0x64c0, 0x64c0); - PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0); - PIPE_SAVE(priv, pipe_0x6a80, 0x6a80); + PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(gr, pipe_0x64c0, 0x64c0); + PIPE_SAVE(gr, pipe_0x6ab0, 0x6ab0); + PIPE_SAVE(gr, pipe_0x6a80, 0x6a80); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + nv_wr32(gr, NV10_PGRAPH_XFMODE0, 0x10000000); + nv_wr32(gr, NV10_PGRAPH_XFMODE1, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000008); - PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200); + PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - PIPE_RESTORE(priv, pipe_0x0040, 0x0040); + PIPE_RESTORE(gr, pipe_0x0040, 0x0040); - nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1); + nv_wr32(gr, NV10_PGRAPH_XFMODE0, xfmode0); + nv_wr32(gr, NV10_PGRAPH_XFMODE1, xfmode1); - PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0); - PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0); - PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80); - PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400); + PIPE_RESTORE(gr, pipe_0x64c0, 0x64c0); + PIPE_RESTORE(gr, pipe_0x6ab0, 0x6ab0); + PIPE_RESTORE(gr, pipe_0x6a80, 0x6a80); + PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv04_gr_idle(priv); + nv04_gr_idle(gr); return 0; } @@ -555,12 +555,12 @@ nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nv10_gr_chan *chan = (void *)object->parent; - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); - nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000); + nv_mask(gr, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); + nv_mask(gr, 0x4006b0, 0x08000000, 0x08000000); return 0; } @@ -602,13 +602,13 @@ nv17_gr_sclass[] = { ******************************************************************************/ static struct nv10_gr_chan * -nv10_gr_channel(struct nv10_gr_priv *priv) +nv10_gr_channel(struct nv10_gr *gr) { struct nv10_gr_chan *chan = NULL; - if (nv_rd32(priv, 0x400144) & 0x00010000) { - int chid = nv_rd32(priv, 0x400148) >> 24; - if (chid < ARRAY_SIZE(priv->chan)) - chan = priv->chan[chid]; + if (nv_rd32(gr, 0x400144) & 0x00010000) { + int chid = nv_rd32(gr, 0x400148) >> 24; + if (chid < ARRAY_SIZE(gr->chan)) + chan = gr->chan[chid]; } return chan; } @@ -616,75 +616,75 @@ nv10_gr_channel(struct nv10_gr_priv *priv) static void nv10_gr_save_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe = &chan->pipe_state; - PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200); - PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400); - PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800); - PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00); - PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000); - PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400); - PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800); - PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040); - PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000); + PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200); + PIPE_SAVE(gr, pipe->pipe_0x6400, 0x6400); + PIPE_SAVE(gr, pipe->pipe_0x6800, 0x6800); + PIPE_SAVE(gr, pipe->pipe_0x6c00, 0x6c00); + PIPE_SAVE(gr, pipe->pipe_0x7000, 0x7000); + PIPE_SAVE(gr, pipe->pipe_0x7400, 0x7400); + PIPE_SAVE(gr, pipe->pipe_0x7800, 0x7800); + PIPE_SAVE(gr, pipe->pipe_0x0040, 0x0040); + PIPE_SAVE(gr, pipe->pipe_0x0000, 0x0000); } static void nv10_gr_load_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe = &chan->pipe_state; u32 xfmode0, xfmode1; int i; - nv04_gr_idle(priv); + nv04_gr_idle(gr); /* XXX check haiku comments */ - xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1); - nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + xfmode0 = nv_rd32(gr, NV10_PGRAPH_XFMODE0); + xfmode1 = nv_rd32(gr, NV10_PGRAPH_XFMODE1); + nv_wr32(gr, NV10_PGRAPH_XFMODE0, 0x10000000); + nv_wr32(gr, NV10_PGRAPH_XFMODE1, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000008); - PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200); - nv04_gr_idle(priv); + PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); + nv04_gr_idle(gr); /* restore XFMODE */ - nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1); - PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400); - PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800); - PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00); - PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000); - PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400); - PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800); - PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400); - PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000); - PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040); - nv04_gr_idle(priv); + nv_wr32(gr, NV10_PGRAPH_XFMODE0, xfmode0); + nv_wr32(gr, NV10_PGRAPH_XFMODE1, xfmode1); + PIPE_RESTORE(gr, pipe->pipe_0x6400, 0x6400); + PIPE_RESTORE(gr, pipe->pipe_0x6800, 0x6800); + PIPE_RESTORE(gr, pipe->pipe_0x6c00, 0x6c00); + PIPE_RESTORE(gr, pipe->pipe_0x7000, 0x7000); + PIPE_RESTORE(gr, pipe->pipe_0x7400, 0x7400); + PIPE_RESTORE(gr, pipe->pipe_0x7800, 0x7800); + PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400); + PIPE_RESTORE(gr, pipe->pipe_0x0000, 0x0000); + PIPE_RESTORE(gr, pipe->pipe_0x0040, 0x0040); + nv04_gr_idle(gr); } static void nv10_gr_create_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe_state = &chan->pipe_state; u32 *pipe_state_addr; int i; @@ -697,7 +697,7 @@ nv10_gr_create_pipe(struct nv10_gr_chan *chan) u32 *__end_addr = pipe_state->pipe_##addr + \ ARRAY_SIZE(pipe_state->pipe_##addr); \ if (pipe_state_addr != __end_addr) \ - nv_error(priv, "incomplete pipe init for 0x%x : %p/%p\n", \ + nv_error(gr, "incomplete pipe init for 0x%x : %p/%p\n", \ addr, pipe_state_addr, __end_addr); \ } while (0) #define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value @@ -837,33 +837,33 @@ nv10_gr_create_pipe(struct nv10_gr_chan *chan) } static int -nv10_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg) +nv10_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) { int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) { if (nv10_gr_ctx_regs[i] == reg) return i; } - nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg); + nv_error(gr, "unknow offset nv10_ctx_regs %d\n", reg); return -1; } static int -nv17_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg) +nv17_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) { int i; for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) { if (nv17_gr_ctx_regs[i] == reg) return i; } - nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg); + nv_error(gr, "unknow offset nv17_ctx_regs %d\n", reg); return -1; } static void nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; u32 ctx_user, ctx_switch[5]; int i, subchan = -1; @@ -875,7 +875,7 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) /* Look for a celsius object */ for (i = 0; i < 8; i++) { - int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; + int class = nv_rd32(gr, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; if (class == 0x56 || class == 0x96 || class == 0x99) { subchan = i; @@ -887,131 +887,131 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) return; /* Save the current ctx object */ - ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER); + ctx_user = nv_rd32(gr, NV10_PGRAPH_CTX_USER); for (i = 0; i < 5; i++) - ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i)); + ctx_switch[i] = nv_rd32(gr, NV10_PGRAPH_CTX_SWITCH(i)); /* Save the FIFO state */ - st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2); - st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL); - st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH); - fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR); + st2 = nv_rd32(gr, NV10_PGRAPH_FFINTFC_ST2); + st2_dl = nv_rd32(gr, NV10_PGRAPH_FFINTFC_ST2_DL); + st2_dh = nv_rd32(gr, NV10_PGRAPH_FFINTFC_ST2_DH); + fifo_ptr = nv_rd32(gr, NV10_PGRAPH_FFINTFC_FIFO_PTR); for (i = 0; i < ARRAY_SIZE(fifo); i++) - fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i); + fifo[i] = nv_rd32(gr, 0x4007a0 + 4 * i); /* Switch to the celsius subchannel */ for (i = 0; i < 5; i++) - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), - nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i))); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(i), + nv_rd32(gr, NV10_PGRAPH_CTX_CACHE(subchan, i))); + nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); /* Inject NV10TCL_DMA_VTXBUF */ - nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, + nv_wr32(gr, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2, 0x2c000000 | chid << 20 | subchan << 16 | 0x18c); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst); - nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nv_mask(gr, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); + nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); /* Restore the FIFO state */ for (i = 0; i < ARRAY_SIZE(fifo); i++) - nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]); + nv_wr32(gr, 0x4007a0 + 4 * i, fifo[i]); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2, st2); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); /* Restore the current ctx object */ for (i = 0; i < 5; i++) - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); - nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); + nv_wr32(gr, NV10_PGRAPH_CTX_USER, ctx_user); } static int nv10_gr_load_context(struct nv10_gr_chan *chan, int chid) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); u32 inst; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) - nv_wr32(priv, nv10_gr_ctx_regs[i], chan->nv10[i]); + nv_wr32(gr, nv10_gr_ctx_regs[i], chan->nv10[i]); - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { + if (nv_device(gr)->card_type >= NV_11 && + nv_device(gr)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) - nv_wr32(priv, nv17_gr_ctx_regs[i], chan->nv17[i]); + nv_wr32(gr, nv17_gr_ctx_regs[i], chan->nv17[i]); } nv10_gr_load_pipe(chan); - inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; + inst = nv_rd32(gr, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; nv10_gr_load_dma_vtxbuf(chan, chid, inst); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); - nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nv_mask(gr, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); return 0; } static int nv10_gr_unload_context(struct nv10_gr_chan *chan) { - struct nv10_gr_priv *priv = nv10_gr_priv(chan); + struct nv10_gr *gr = nv10_gr(chan); int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) - chan->nv10[i] = nv_rd32(priv, nv10_gr_ctx_regs[i]); + chan->nv10[i] = nv_rd32(gr, nv10_gr_ctx_regs[i]); - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { + if (nv_device(gr)->card_type >= NV_11 && + nv_device(gr)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) - chan->nv17[i] = nv_rd32(priv, nv17_gr_ctx_regs[i]); + chan->nv17[i] = nv_rd32(gr, nv17_gr_ctx_regs[i]); } nv10_gr_save_pipe(chan); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000000); + nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); return 0; } static void -nv10_gr_context_switch(struct nv10_gr_priv *priv) +nv10_gr_context_switch(struct nv10_gr *gr) { struct nv10_gr_chan *prev = NULL; struct nv10_gr_chan *next = NULL; unsigned long flags; int chid; - spin_lock_irqsave(&priv->lock, flags); - nv04_gr_idle(priv); + spin_lock_irqsave(&gr->lock, flags); + nv04_gr_idle(gr); /* If previous context is valid, we need to save it */ - prev = nv10_gr_channel(priv); + prev = nv10_gr_channel(gr); if (prev) nv10_gr_unload_context(prev); /* load context for next channel */ - chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; - next = priv->chan[chid]; + chid = (nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + next = gr->chan[chid]; if (next) nv10_gr_load_context(next, chid); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); } #define NV_WRITE_CTX(reg, val) do { \ - int offset = nv10_gr_ctx_regs_find_offset(priv, reg); \ + int offset = nv10_gr_ctx_regs_find_offset(gr, reg); \ if (offset > 0) \ chan->nv10[offset] = val; \ } while (0) #define NV17_WRITE_CTX(reg, val) do { \ - int offset = nv17_gr_ctx_regs_find_offset(priv, reg); \ + int offset = nv17_gr_ctx_regs_find_offset(gr, reg); \ if (offset > 0) \ chan->nv17[offset] = val; \ } while (0) @@ -1022,7 +1022,7 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_fifo_chan *fifo = (void *)parent; - struct nv10_gr_priv *priv = (void *)engine; + struct nv10_gr *gr = (void *)engine; struct nv10_gr_chan *chan; unsigned long flags; int ret; @@ -1032,11 +1032,11 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - spin_lock_irqsave(&priv->lock, flags); - if (priv->chan[fifo->chid]) { - *pobject = nv_object(priv->chan[fifo->chid]); + spin_lock_irqsave(&gr->lock, flags); + if (gr->chan[fifo->chid]) { + *pobject = nv_object(gr->chan[fifo->chid]); atomic_inc(&(*pobject)->refcount); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); nvkm_object_destroy(&chan->base); return 1; } @@ -1048,12 +1048,12 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, NV_WRITE_CTX(0x00400e14, 0x00001000); NV_WRITE_CTX(0x00400e30, 0x00080008); NV_WRITE_CTX(0x00400e34, 0x00080008); - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { + if (nv_device(gr)->card_type >= NV_11 && + nv_device(gr)->chipset >= 0x17) { /* is it really needed ??? */ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, - nv_rd32(priv, NV10_PGRAPH_DEBUG_4)); - NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0)); + nv_rd32(gr, NV10_PGRAPH_DEBUG_4)); + NV17_WRITE_CTX(0x004006b0, nv_rd32(gr, 0x004006b0)); NV17_WRITE_CTX(0x00400eac, 0x0fff0000); NV17_WRITE_CTX(0x00400eb0, 0x0fff0000); NV17_WRITE_CTX(0x00400ec0, 0x00000080); @@ -1063,22 +1063,22 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv10_gr_create_pipe(chan); - priv->chan[fifo->chid] = chan; + gr->chan[fifo->chid] = chan; chan->chid = fifo->chid; - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); return 0; } static void nv10_gr_context_dtor(struct nvkm_object *object) { - struct nv10_gr_priv *priv = (void *)object->engine; + struct nv10_gr *gr = (void *)object->engine; struct nv10_gr_chan *chan = (void *)object; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - priv->chan[chan->chid] = NULL; - spin_unlock_irqrestore(&priv->lock, flags); + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&gr->lock, flags); nvkm_object_destroy(&chan->base); } @@ -1086,16 +1086,16 @@ nv10_gr_context_dtor(struct nvkm_object *object) static int nv10_gr_context_fini(struct nvkm_object *object, bool suspend) { - struct nv10_gr_priv *priv = (void *)object->engine; + struct nv10_gr *gr = (void *)object->engine; struct nv10_gr_chan *chan = (void *)object; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (nv10_gr_channel(priv) == chan) + spin_lock_irqsave(&gr->lock, flags); + nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv10_gr_channel(gr) == chan) nv10_gr_unload_context(chan); - nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->lock, flags); + nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); return nvkm_object_fini(&chan->base, suspend); } @@ -1120,15 +1120,15 @@ nv10_gr_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; struct nvkm_fifo *fifo = nvkm_fifo(engine); - struct nv10_gr_priv *priv = (void *)engine; + struct nv10_gr *gr = (void *)engine; unsigned long flags; fifo->pause(fifo, &flags); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr); + nv_wr32(gr, NV10_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(gr, NV10_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(gr, NV10_PGRAPH_TILE(i), tile->addr); fifo->start(fifo, &flags); } @@ -1150,27 +1150,27 @@ const struct nvkm_bitfield nv10_gr_nstatus[] = { static void nv10_gr_intr(struct nvkm_subdev *subdev) { - struct nv10_gr_priv *priv = (void *)subdev; + struct nv10_gr *gr = (void *)subdev; struct nv10_gr_chan *chan = NULL; struct nvkm_namedb *namedb = NULL; struct nvkm_handle *handle = NULL; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x01f00000) >> 20; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff; + u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(gr, 0x400160 + subc * 4) & 0xfff; u32 show = stat; unsigned long flags; - spin_lock_irqsave(&priv->lock, flags); - chan = priv->chan[chid]; + spin_lock_irqsave(&gr->lock, flags); + chan = gr->chan[chid]; if (chan) namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); - spin_unlock_irqrestore(&priv->lock, flags); + spin_unlock_irqrestore(&gr->lock, flags); if (stat & NV_PGRAPH_INTR_ERROR) { if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { @@ -1181,24 +1181,24 @@ nv10_gr_intr(struct nvkm_subdev *subdev) } if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + nv_wr32(gr, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; - nv10_gr_context_switch(priv); + nv10_gr_context_switch(gr); } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nv_wr32(gr, NV03_PGRAPH_INTR, stat); + nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); + nv_error(gr, "%s", ""); nvkm_bitfield_print(nv10_gr_intr_name, show); pr_cont(" nsource:"); nvkm_bitfield_print(nv04_gr_nsource, nsource); pr_cont(" nstatus:"); nvkm_bitfield_print(nv10_gr_nstatus, nstatus); pr_cont("\n"); - nv_error(priv, + nv_error(gr, "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, nvkm_client_name(chan), subc, class, mthd, data); @@ -1212,37 +1212,37 @@ nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv10_gr_priv *priv; + struct nv10_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv10_gr_intr; - nv_engine(priv)->cclass = &nv10_gr_cclass; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv10_gr_intr; + nv_engine(gr)->cclass = &nv10_gr_cclass; - if (nv_device(priv)->chipset <= 0x10) - nv_engine(priv)->sclass = nv10_gr_sclass; + if (nv_device(gr)->chipset <= 0x10) + nv_engine(gr)->sclass = nv10_gr_sclass; else - if (nv_device(priv)->chipset < 0x17 || - nv_device(priv)->card_type < NV_11) - nv_engine(priv)->sclass = nv15_gr_sclass; + if (nv_device(gr)->chipset < 0x17 || + nv_device(gr)->card_type < NV_11) + nv_engine(gr)->sclass = nv15_gr_sclass; else - nv_engine(priv)->sclass = nv17_gr_sclass; + nv_engine(gr)->sclass = nv17_gr_sclass; - nv_engine(priv)->tile_prog = nv10_gr_tile_prog; - spin_lock_init(&priv->lock); + nv_engine(gr)->tile_prog = nv10_gr_tile_prog; + spin_lock_init(&gr->lock); return 0; } static void nv10_gr_dtor(struct nvkm_object *object) { - struct nv10_gr_priv *priv = (void *)object; - nvkm_gr_destroy(&priv->base); + struct nv10_gr *gr = (void *)object; + nvkm_gr_destroy(&gr->base); } static int @@ -1250,56 +1250,56 @@ nv10_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nvkm_fb *fb = nvkm_fb(object); - struct nv10_gr_priv *priv = (void *)engine; + struct nv10_gr *gr = (void *)engine; int ret, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700); - /* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ - nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); - - if (nv_device(priv)->card_type >= NV_11 && - nv_device(priv)->chipset >= 0x17) { - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000); - nv_wr32(priv, 0x400a10, 0x03ff3fb6); - nv_wr32(priv, 0x400838, 0x002f8684); - nv_wr32(priv, 0x40083c, 0x00115f3f); - nv_wr32(priv, 0x4006b0, 0x40000020); + nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x00118700); + /* nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ + nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); + nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); + + if (nv_device(gr)->card_type >= NV_11 && + nv_device(gr)->chipset >= 0x17) { + nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x1f000000); + nv_wr32(gr, 0x400a10, 0x03ff3fb6); + nv_wr32(gr, 0x400838, 0x002f8684); + nv_wr32(gr, 0x40083c, 0x00115f3f); + nv_wr32(gr, 0x4006b0, 0x40000020); } else { - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00000000); } /* Turn all the tiling regions off. */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); - nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); + nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); + nv_wr32(gr, NV10_PGRAPH_STATE, 0xFFFFFFFF); - nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); + nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); return 0; } static int nv10_gr_fini(struct nvkm_object *object, bool suspend) { - struct nv10_gr_priv *priv = (void *)object; - return nvkm_gr_fini(&priv->base, suspend); + struct nv10_gr *gr = (void *)object; + return nvkm_gr_fini(&gr->base, suspend); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 14a83f2a8127b..3e5428552cb2a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -101,7 +101,7 @@ nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int nv20_gr_context_init(struct nvkm_object *object) { - struct nv20_gr_priv *priv = (void *)object->engine; + struct nv20_gr *gr = (void *)object->engine; struct nv20_gr_chan *chan = (void *)object; int ret; @@ -109,30 +109,30 @@ nv20_gr_context_init(struct nvkm_object *object) if (ret) return ret; - nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + nv_wo32(gr->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); return 0; } int nv20_gr_context_fini(struct nvkm_object *object, bool suspend) { - struct nv20_gr_priv *priv = (void *)object->engine; + struct nv20_gr *gr = (void *)object->engine; struct nv20_gr_chan *chan = (void *)object; int chid = -1; - nv_mask(priv, 0x400720, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x400144) & 0x00010000) - chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24; + nv_mask(gr, 0x400720, 0x00000001, 0x00000000); + if (nv_rd32(gr, 0x400144) & 0x00010000) + chid = (nv_rd32(gr, 0x400148) & 0x1f000000) >> 24; if (chan->chid == chid) { - nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4); - nv_wr32(priv, 0x400788, 0x00000002); - nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); - nv_wr32(priv, 0x400144, 0x10000000); - nv_mask(priv, 0x400148, 0xff000000, 0x1f000000); + nv_wr32(gr, 0x400784, nv_gpuobj(chan)->addr >> 4); + nv_wr32(gr, 0x400788, 0x00000002); + nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); + nv_wr32(gr, 0x400144, 0x10000000); + nv_mask(gr, 0x400148, 0xff000000, 0x1f000000); } - nv_mask(priv, 0x400720, 0x00000001, 0x00000001); + nv_mask(gr, 0x400720, 0x00000001, 0x00000001); - nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000); + nv_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); return nvkm_gr_context_fini(&chan->base, suspend); } @@ -158,27 +158,27 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; struct nvkm_fifo *fifo = nvkm_fifo(engine); - struct nv20_gr_priv *priv = (void *)engine; + struct nv20_gr *gr = (void *)engine; unsigned long flags; fifo->pause(fifo, &flags); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(gr, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(gr, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(gr, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->limit); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->pitch); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->addr); if (nv_device(engine)->chipset != 0x34) { - nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp); + nv_wr32(gr, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->zcomp); } fifo->start(fifo, &flags); @@ -190,16 +190,16 @@ nv20_gr_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; - struct nv20_gr_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + struct nv20_gr *gr = (void *)subdev; + u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); + u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x01f00000) >> 20; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff; + u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(gr, 0x400160 + subc * 4) & 0xfff; u32 show = stat; engctx = nvkm_engctx_get(engine, chid); @@ -212,18 +212,18 @@ nv20_gr_intr(struct nvkm_subdev *subdev) } } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nv_wr32(gr, NV03_PGRAPH_INTR, stat); + nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); + nv_error(gr, "%s", ""); nvkm_bitfield_print(nv10_gr_intr_name, show); pr_cont(" nsource:"); nvkm_bitfield_print(nv04_gr_nsource, nsource); pr_cont(" nstatus:"); nvkm_bitfield_print(nv10_gr_nstatus, nstatus); pr_cont("\n"); - nv_error(priv, + nv_error(gr, "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, nvkm_client_name(engctx), subc, class, mthd, data); @@ -237,129 +237,129 @@ nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv20_gr_priv *priv; + struct nv20_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv20_gr_cclass; - nv_engine(priv)->sclass = nv20_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv20_gr_intr; + nv_engine(gr)->cclass = &nv20_gr_cclass; + nv_engine(gr)->sclass = nv20_gr_sclass; + nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } void nv20_gr_dtor(struct nvkm_object *object) { - struct nv20_gr_priv *priv = (void *)object; - nvkm_gpuobj_ref(NULL, &priv->ctxtab); - nvkm_gr_destroy(&priv->base); + struct nv20_gr *gr = (void *)object; + nvkm_gpuobj_ref(NULL, &gr->ctxtab); + nvkm_gr_destroy(&gr->base); } int nv20_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nv20_gr_priv *priv = (void *)engine; + struct nv20_gr *gr = (void *)engine; struct nvkm_fb *fb = nvkm_fb(object); u32 tmp, vramsz; int ret, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); + nv_wr32(gr, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); - if (nv_device(priv)->chipset == 0x20) { - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000); + if (nv_device(gr)->chipset == 0x20) { + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x003d0000); for (i = 0; i < 15; i++) - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000); - nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, 0x00000000); + nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); } else { - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x02c80000); for (i = 0; i < 32; i++) - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000); - nv_wait(priv, 0x400700, 0xffffffff, 0x00000000); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, 0x00000000); + nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); } - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000); - nv_wr32(priv, 0x40009C , 0x00000040); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x00118700); + nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ + nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00000000); + nv_wr32(gr, 0x40009C , 0x00000040); - if (nv_device(priv)->chipset >= 0x25) { - nv_wr32(priv, 0x400890, 0x00a8cfff); - nv_wr32(priv, 0x400610, 0x304B1FB6); - nv_wr32(priv, 0x400B80, 0x1cbd3883); - nv_wr32(priv, 0x400B84, 0x44000000); - nv_wr32(priv, 0x400098, 0x40000080); - nv_wr32(priv, 0x400B88, 0x000000ff); + if (nv_device(gr)->chipset >= 0x25) { + nv_wr32(gr, 0x400890, 0x00a8cfff); + nv_wr32(gr, 0x400610, 0x304B1FB6); + nv_wr32(gr, 0x400B80, 0x1cbd3883); + nv_wr32(gr, 0x400B84, 0x44000000); + nv_wr32(gr, 0x400098, 0x40000080); + nv_wr32(gr, 0x400B88, 0x000000ff); } else { - nv_wr32(priv, 0x400880, 0x0008c7df); - nv_wr32(priv, 0x400094, 0x00000005); - nv_wr32(priv, 0x400B80, 0x45eae20e); - nv_wr32(priv, 0x400B84, 0x24000000); - nv_wr32(priv, 0x400098, 0x00000040); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030); + nv_wr32(gr, 0x400880, 0x0008c7df); + nv_wr32(gr, 0x400094, 0x00000005); + nv_wr32(gr, 0x400B80, 0x45eae20e); + nv_wr32(gr, 0x400B84, 0x24000000); + nv_wr32(gr, 0x400098, 0x00000040); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00E00038); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000030); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00E10038); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000030); } /* Turn all the tiling regions off. */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); - nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324)); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324)); + nv_wr32(gr, 0x4009a0, nv_rd32(gr, 0x100324)); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA, nv_rd32(gr, 0x100324)); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(gr, NV10_PGRAPH_STATE , 0xFFFFFFFF); - tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00; - nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); - tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100; - nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp); + tmp = nv_rd32(gr, NV10_PGRAPH_SURFACE) & 0x0007ff00; + nv_wr32(gr, NV10_PGRAPH_SURFACE, tmp); + tmp = nv_rd32(gr, NV10_PGRAPH_SURFACE) | 0x00020100; + nv_wr32(gr, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; - nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200)); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x400820, 0); - nv_wr32(priv, 0x400824, 0); - nv_wr32(priv, 0x400864, vramsz - 1); - nv_wr32(priv, 0x400868, vramsz - 1); + vramsz = nv_device_resource_len(nv_device(gr), 1) - 1; + nv_wr32(gr, 0x4009A4, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x4009A8, nv_rd32(gr, 0x100204)); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , nv_rd32(gr, 0x100200)); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , nv_rd32(gr, 0x100204)); + nv_wr32(gr, 0x400820, 0); + nv_wr32(gr, 0x400824, 0); + nv_wr32(gr, 0x400864, vramsz - 1); + nv_wr32(gr, 0x400868, vramsz - 1); /* interesting.. the below overwrites some of the tile setup above.. */ - nv_wr32(priv, 0x400B20, 0x00000000); - nv_wr32(priv, 0x400B04, 0xFFFFFFFF); + nv_wr32(gr, 0x400B20, 0x00000000); + nv_wr32(gr, 0x400B04, 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); - nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); + nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); + nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); + nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); + nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h index ac4dc048fed18..06dfe4bd50b13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h @@ -2,7 +2,7 @@ #define __NV20_GR_H__ #include -struct nv20_gr_priv { +struct nv20_gr { struct nvkm_gr base; struct nvkm_gpuobj *ctxtab; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index bc362519cebba..50bad48a3eab3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -125,24 +125,24 @@ nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv20_gr_priv *priv; + struct nv20_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv25_gr_cclass; - nv_engine(priv)->sclass = nv25_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv20_gr_intr; + nv_engine(gr)->cclass = &nv25_gr_cclass; + nv_engine(gr)->sclass = nv25_gr_sclass; + nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index 22a5096e283dc..5c8ae50ee8e76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -92,24 +92,24 @@ nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv20_gr_priv *priv; + struct nv20_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv2a_gr_cclass; - nv_engine(priv)->sclass = nv25_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv20_gr_intr; + nv_engine(gr)->cclass = &nv2a_gr_cclass; + nv_engine(gr)->sclass = nv25_gr_sclass; + nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 0214e8a91dac9..dea1cb907318b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -127,24 +127,24 @@ nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv20_gr_priv *priv; + struct nv20_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv30_gr_cclass; - nv_engine(priv)->sclass = nv30_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv20_gr_intr; + nv_engine(gr)->cclass = &nv30_gr_cclass; + nv_engine(gr)->sclass = nv30_gr_sclass; + nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } @@ -152,68 +152,68 @@ int nv30_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nv20_gr_priv *priv = (void *)engine; + struct nv20_gr *gr = (void *)engine; struct nvkm_fb *fb = nvkm_fb(object); int ret, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4); - - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(priv, 0x400890, 0x01b463ff); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475); - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); - nv_wr32(priv, 0x400B80, 0x1003d888); - nv_wr32(priv, 0x400B84, 0x0c000000); - nv_wr32(priv, 0x400098, 0x00000000); - nv_wr32(priv, 0x40009C, 0x0005ad00); - nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ - nv_wr32(priv, 0x4000a0, 0x00000000); - nv_wr32(priv, 0x4000a4, 0x00000008); - nv_wr32(priv, 0x4008a8, 0xb784a400); - nv_wr32(priv, 0x400ba0, 0x002f8685); - nv_wr32(priv, 0x400ba4, 0x00231f3f); - nv_wr32(priv, 0x4008a4, 0x40000020); - - if (nv_device(priv)->chipset == 0x34) { - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032); - nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004); - nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002); + nv_wr32(gr, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); + + nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nv_wr32(gr, 0x400890, 0x01b463ff); + nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xf2de0475); + nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00008000); + nv_wr32(gr, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); + nv_wr32(gr, 0x400B80, 0x1003d888); + nv_wr32(gr, 0x400B84, 0x0c000000); + nv_wr32(gr, 0x400098, 0x00000000); + nv_wr32(gr, 0x40009C, 0x0005ad00); + nv_wr32(gr, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ + nv_wr32(gr, 0x4000a0, 0x00000000); + nv_wr32(gr, 0x4000a4, 0x00000008); + nv_wr32(gr, 0x4008a8, 0xb784a400); + nv_wr32(gr, 0x400ba0, 0x002f8685); + nv_wr32(gr, 0x400ba4, 0x00231f3f); + nv_wr32(gr, 0x4008a4, 0x40000020); + + if (nv_device(gr)->chipset == 0x34) { + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00200201); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000008); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000032); + nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00E00004); + nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000002); } - nv_wr32(priv, 0x4000c0, 0x00000016); + nv_wr32(gr, 0x4000c0, 0x00000016); /* Turn all the tiling regions off. */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(priv, 0x0040075c , 0x00000001); + nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nv_wr32(gr, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(gr, 0x0040075c , 0x00000001); /* begin RAM config */ - /* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */ - nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); - if (nv_device(priv)->chipset != 0x34) { - nv_wr32(priv, 0x400750, 0x00EA0000); - nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x400750, 0x00EA0004); - nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204)); + /* vramsz = pci_resource_len(gr->dev->pdev, 1) - 1; */ + nv_wr32(gr, 0x4009A4, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x4009A8, nv_rd32(gr, 0x100204)); + if (nv_device(gr)->chipset != 0x34) { + nv_wr32(gr, 0x400750, 0x00EA0000); + nv_wr32(gr, 0x400754, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x400750, 0x00EA0004); + nv_wr32(gr, 0x400754, nv_rd32(gr, 0x100204)); } return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 985b7f3306ae0..e17eb0b132770 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -126,24 +126,24 @@ nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv20_gr_priv *priv; + struct nv20_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv34_gr_cclass; - nv_engine(priv)->sclass = nv34_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv20_gr_intr; + nv_engine(gr)->cclass = &nv34_gr_cclass; + nv_engine(gr)->sclass = nv34_gr_sclass; + nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 707625f19ff59..35ba75130f930 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -126,24 +126,24 @@ nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv20_gr_priv *priv; + struct nv20_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab); + ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, + NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv20_gr_intr; - nv_engine(priv)->cclass = &nv35_gr_cclass; - nv_engine(priv)->sclass = nv35_gr_sclass; - nv_engine(priv)->tile_prog = nv20_gr_tile_prog; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv20_gr_intr; + nv_engine(gr)->cclass = &nv35_gr_cclass; + nv_engine(gr)->sclass = nv35_gr_sclass; + nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index c0a1751a1e88c..3c2df9d29ff34 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -30,7 +30,7 @@ #include #include -struct nv40_gr_priv { +struct nv40_gr { struct nvkm_gr base; u32 size; }; @@ -42,9 +42,7 @@ struct nv40_gr_chan { static u64 nv40_gr_units(struct nvkm_gr *gr) { - struct nv40_gr_priv *priv = (void *)gr; - - return nv_rd32(priv, 0x1540); + return nv_rd32(gr, 0x1540); } /******************************************************************************* @@ -137,17 +135,17 @@ nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv40_gr_priv *priv = (void *)engine; + struct nv40_gr *gr = (void *)engine; struct nv40_gr_chan *chan; int ret; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size, + ret = nvkm_gr_context_create(parent, engine, oclass, NULL, gr->size, 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); *pobject = nv_object(chan); if (ret) return ret; - nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan)); + nv40_grctx_fill(nv_device(gr), nv_gpuobj(chan)); nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4); return 0; } @@ -155,33 +153,33 @@ nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, static int nv40_gr_context_fini(struct nvkm_object *object, bool suspend) { - struct nv40_gr_priv *priv = (void *)object->engine; + struct nv40_gr *gr = (void *)object->engine; struct nv40_gr_chan *chan = (void *)object; u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; int ret = 0; - nv_mask(priv, 0x400720, 0x00000001, 0x00000000); + nv_mask(gr, 0x400720, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x40032c) == inst) { + if (nv_rd32(gr, 0x40032c) == inst) { if (suspend) { - nv_wr32(priv, 0x400720, 0x00000000); - nv_wr32(priv, 0x400784, inst); - nv_mask(priv, 0x400310, 0x00000020, 0x00000020); - nv_mask(priv, 0x400304, 0x00000001, 0x00000001); - if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) { - u32 insn = nv_rd32(priv, 0x400308); - nv_warn(priv, "ctxprog timeout 0x%08x\n", insn); + nv_wr32(gr, 0x400720, 0x00000000); + nv_wr32(gr, 0x400784, inst); + nv_mask(gr, 0x400310, 0x00000020, 0x00000020); + nv_mask(gr, 0x400304, 0x00000001, 0x00000001); + if (!nv_wait(gr, 0x400300, 0x00000001, 0x00000000)) { + u32 insn = nv_rd32(gr, 0x400308); + nv_warn(gr, "ctxprog timeout 0x%08x\n", insn); ret = -EBUSY; } } - nv_mask(priv, 0x40032c, 0x01000000, 0x00000000); + nv_mask(gr, 0x40032c, 0x01000000, 0x00000000); } - if (nv_rd32(priv, 0x400330) == inst) - nv_mask(priv, 0x400330, 0x01000000, 0x00000000); + if (nv_rd32(gr, 0x400330) == inst) + nv_mask(gr, 0x400330, 0x01000000, 0x00000000); - nv_mask(priv, 0x400720, 0x00000001, 0x00000001); + nv_mask(gr, 0x400720, 0x00000001, 0x00000001); return ret; } @@ -207,36 +205,36 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; struct nvkm_fifo *fifo = nvkm_fifo(engine); - struct nv40_gr_priv *priv = (void *)engine; + struct nv40_gr *gr = (void *)engine; unsigned long flags; fifo->pause(fifo, &flags); - nv04_gr_idle(priv); + nv04_gr_idle(gr); - switch (nv_device(priv)->chipset) { + switch (nv_device(gr)->chipset) { case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: case 0x4e: - nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr); - switch (nv_device(priv)->chipset) { + nv_wr32(gr, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(gr, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(gr, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(gr, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(gr, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(gr, NV40_PGRAPH_TILE1(i), tile->addr); + switch (nv_device(gr)->chipset) { case 0x40: case 0x45: - nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp); + nv_wr32(gr, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nv_wr32(gr, NV40_PGRAPH_ZCOMP1(i), tile->zcomp); break; case 0x41: case 0x42: case 0x43: - nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp); - nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp); + nv_wr32(gr, NV41_PGRAPH_ZCOMP0(i), tile->zcomp); + nv_wr32(gr, NV41_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: break; @@ -244,9 +242,9 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) break; case 0x44: case 0x4a: - nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr); + nv_wr32(gr, NV20_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(gr, NV20_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(gr, NV20_PGRAPH_TILE(i), tile->addr); break; case 0x46: case 0x4c: @@ -256,18 +254,18 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) case 0x63: case 0x67: case 0x68: - nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr); - nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr); - switch (nv_device(priv)->chipset) { + nv_wr32(gr, NV47_PGRAPH_TSIZE(i), tile->pitch); + nv_wr32(gr, NV47_PGRAPH_TLIMIT(i), tile->limit); + nv_wr32(gr, NV47_PGRAPH_TILE(i), tile->addr); + nv_wr32(gr, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nv_wr32(gr, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nv_wr32(gr, NV40_PGRAPH_TILE1(i), tile->addr); + switch (nv_device(gr)->chipset) { case 0x47: case 0x49: case 0x4b: - nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); - nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); + nv_wr32(gr, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); + nv_wr32(gr, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: break; @@ -287,16 +285,16 @@ nv40_gr_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle = NULL; - struct nv40_gr_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS); - u32 inst = nv_rd32(priv, 0x40032c) & 0x000fffff; - u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR); + struct nv40_gr *gr = (void *)subdev; + u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); + u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); + u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); + u32 inst = nv_rd32(gr, 0x40032c) & 0x000fffff; + u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff; + u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nv_rd32(gr, 0x400160 + subc * 4) & 0xffff; u32 show = stat; int chid; @@ -312,22 +310,22 @@ nv40_gr_intr(struct nvkm_subdev *subdev) } if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { - nv_mask(priv, 0x402000, 0, 0); + nv_mask(gr, 0x402000, 0, 0); } } - nv_wr32(priv, NV03_PGRAPH_INTR, stat); - nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001); + nv_wr32(gr, NV03_PGRAPH_INTR, stat); + nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(priv, "%s", ""); + nv_error(gr, "%s", ""); nvkm_bitfield_print(nv10_gr_intr_name, show); pr_cont(" nsource:"); nvkm_bitfield_print(nv04_gr_nsource, nsource); pr_cont(" nstatus:"); nvkm_bitfield_print(nv10_gr_nstatus, nstatus); pr_cont("\n"); - nv_error(priv, + nv_error(gr, "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst << 4, nvkm_client_name(engctx), subc, class, mthd, data); @@ -341,24 +339,24 @@ nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv40_gr_priv *priv; + struct nv40_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - nv_subdev(priv)->unit = 0x00001000; - nv_subdev(priv)->intr = nv40_gr_intr; - nv_engine(priv)->cclass = &nv40_gr_cclass; - if (nv44_gr_class(priv)) - nv_engine(priv)->sclass = nv44_gr_sclass; + nv_subdev(gr)->unit = 0x00001000; + nv_subdev(gr)->intr = nv40_gr_intr; + nv_engine(gr)->cclass = &nv40_gr_cclass; + if (nv44_gr_class(gr)) + nv_engine(gr)->sclass = nv44_gr_sclass; else - nv_engine(priv)->sclass = nv40_gr_sclass; - nv_engine(priv)->tile_prog = nv40_gr_tile_prog; + nv_engine(gr)->sclass = nv40_gr_sclass; + nv_engine(gr)->tile_prog = nv40_gr_tile_prog; - priv->base.units = nv40_gr_units; + gr->base.units = nv40_gr_units; return 0; } @@ -367,103 +365,103 @@ nv40_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nvkm_fb *fb = nvkm_fb(object); - struct nv40_gr_priv *priv = (void *)engine; + struct nv40_gr *gr = (void *)engine; int ret, i, j; u32 vramsz; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; /* generate and upload context program */ - ret = nv40_grctx_init(nv_device(priv), &priv->size); + ret = nv40_grctx_init(nv_device(gr), &gr->size); if (ret) return ret; /* No context present currently */ - nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + nv_wr32(gr, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); - nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); + nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nv_wr32(gr, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055); - nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); + nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xe0de8055); + nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00008000); + nv_wr32(gr, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); - nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nv_wr32(gr, NV10_PGRAPH_STATE , 0xFFFFFFFF); - j = nv_rd32(priv, 0x1540) & 0xff; + j = nv_rd32(gr, 0x1540) & 0xff; if (j) { for (i = 0; !(j & 1); j >>= 1, i++) ; - nv_wr32(priv, 0x405000, i); + nv_wr32(gr, 0x405000, i); } - if (nv_device(priv)->chipset == 0x40) { - nv_wr32(priv, 0x4009b0, 0x83280fff); - nv_wr32(priv, 0x4009b4, 0x000000a0); + if (nv_device(gr)->chipset == 0x40) { + nv_wr32(gr, 0x4009b0, 0x83280fff); + nv_wr32(gr, 0x4009b4, 0x000000a0); } else { - nv_wr32(priv, 0x400820, 0x83280eff); - nv_wr32(priv, 0x400824, 0x000000a0); + nv_wr32(gr, 0x400820, 0x83280eff); + nv_wr32(gr, 0x400824, 0x000000a0); } - switch (nv_device(priv)->chipset) { + switch (nv_device(gr)->chipset) { case 0x40: case 0x45: - nv_wr32(priv, 0x4009b8, 0x0078e366); - nv_wr32(priv, 0x4009bc, 0x0000014c); + nv_wr32(gr, 0x4009b8, 0x0078e366); + nv_wr32(gr, 0x4009bc, 0x0000014c); break; case 0x41: case 0x42: /* pciid also 0x00Cx */ /* case 0x0120: XXX (pciid) */ - nv_wr32(priv, 0x400828, 0x007596ff); - nv_wr32(priv, 0x40082c, 0x00000108); + nv_wr32(gr, 0x400828, 0x007596ff); + nv_wr32(gr, 0x40082c, 0x00000108); break; case 0x43: - nv_wr32(priv, 0x400828, 0x0072cb77); - nv_wr32(priv, 0x40082c, 0x00000108); + nv_wr32(gr, 0x400828, 0x0072cb77); + nv_wr32(gr, 0x40082c, 0x00000108); break; case 0x44: case 0x46: /* G72 */ case 0x4a: case 0x4c: /* G7x-based C51 */ case 0x4e: - nv_wr32(priv, 0x400860, 0); - nv_wr32(priv, 0x400864, 0); + nv_wr32(gr, 0x400860, 0); + nv_wr32(gr, 0x400864, 0); break; case 0x47: /* G70 */ case 0x49: /* G71 */ case 0x4b: /* G73 */ - nv_wr32(priv, 0x400828, 0x07830610); - nv_wr32(priv, 0x40082c, 0x0000016A); + nv_wr32(gr, 0x400828, 0x07830610); + nv_wr32(gr, 0x40082c, 0x0000016A); break; default: break; } - nv_wr32(priv, 0x400b38, 0x2ffff800); - nv_wr32(priv, 0x400b3c, 0x00006000); + nv_wr32(gr, 0x400b38, 0x2ffff800); + nv_wr32(gr, 0x400b3c, 0x00006000); /* Tiling related stuff. */ - switch (nv_device(priv)->chipset) { + switch (nv_device(gr)->chipset) { case 0x44: case 0x4a: - nv_wr32(priv, 0x400bc4, 0x1003d888); - nv_wr32(priv, 0x400bbc, 0xb7a7b500); + nv_wr32(gr, 0x400bc4, 0x1003d888); + nv_wr32(gr, 0x400bbc, 0xb7a7b500); break; case 0x46: - nv_wr32(priv, 0x400bc4, 0x0000e024); - nv_wr32(priv, 0x400bbc, 0xb7a7b520); + nv_wr32(gr, 0x400bc4, 0x0000e024); + nv_wr32(gr, 0x400bbc, 0xb7a7b520); break; case 0x4c: case 0x4e: case 0x67: - nv_wr32(priv, 0x400bc4, 0x1003d888); - nv_wr32(priv, 0x400bbc, 0xb7a7b540); + nv_wr32(gr, 0x400bc4, 0x1003d888); + nv_wr32(gr, 0x400bbc, 0xb7a7b540); break; default: break; @@ -474,20 +472,20 @@ nv40_gr_init(struct nvkm_object *object) engine->tile_prog(engine, i); /* begin RAM config */ - vramsz = nv_device_resource_len(nv_device(priv), 0) - 1; - switch (nv_device(priv)->chipset) { + vramsz = nv_device_resource_len(nv_device(gr), 1) - 1; + switch (nv_device(gr)->chipset) { case 0x40: - nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x400820, 0); - nv_wr32(priv, 0x400824, 0); - nv_wr32(priv, 0x400864, vramsz); - nv_wr32(priv, 0x400868, vramsz); + nv_wr32(gr, 0x4009A4, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x4009A8, nv_rd32(gr, 0x100204)); + nv_wr32(gr, 0x4069A4, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x4069A8, nv_rd32(gr, 0x100204)); + nv_wr32(gr, 0x400820, 0); + nv_wr32(gr, 0x400824, 0); + nv_wr32(gr, 0x400864, vramsz); + nv_wr32(gr, 0x400868, vramsz); break; default: - switch (nv_device(priv)->chipset) { + switch (nv_device(gr)->chipset) { case 0x41: case 0x42: case 0x43: @@ -495,20 +493,20 @@ nv40_gr_init(struct nvkm_object *object) case 0x4e: case 0x44: case 0x4a: - nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204)); + nv_wr32(gr, 0x4009F0, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x4009F4, nv_rd32(gr, 0x100204)); break; default: - nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204)); + nv_wr32(gr, 0x400DF0, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x400DF4, nv_rd32(gr, 0x100204)); break; } - nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200)); - nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204)); - nv_wr32(priv, 0x400840, 0); - nv_wr32(priv, 0x400844, 0); - nv_wr32(priv, 0x4008A0, vramsz); - nv_wr32(priv, 0x4008A4, vramsz); + nv_wr32(gr, 0x4069F0, nv_rd32(gr, 0x100200)); + nv_wr32(gr, 0x4069F4, nv_rd32(gr, 0x100204)); + nv_wr32(gr, 0x400840, 0); + nv_wr32(gr, 0x400844, 0); + nv_wr32(gr, 0x4008A0, vramsz); + nv_wr32(gr, 0x4008A4, vramsz); break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index e232cb8e2f9e9..70be675b19280 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -28,7 +28,7 @@ #include #include -struct nv50_gr_priv { +struct nv50_gr { struct nvkm_gr base; spinlock_t lock; u32 size; @@ -41,9 +41,7 @@ struct nv50_gr_chan { static u64 nv50_gr_units(struct nvkm_gr *gr) { - struct nv50_gr_priv *priv = (void *)gr; - - return nv_rd32(priv, 0x1540); + return nv_rd32(gr, 0x1540); } /******************************************************************************* @@ -142,17 +140,17 @@ nv50_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_gr_priv *priv = (void *)engine; + struct nv50_gr *gr = (void *)engine; struct nv50_gr_chan *chan; int ret; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size, + ret = nvkm_gr_context_create(parent, engine, oclass, NULL, gr->size, 0, NVOBJ_FLAG_ZERO_ALLOC, &chan); *pobject = nv_object(chan); if (ret) return ret; - nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan)); + nv50_grctx_fill(nv_device(gr), nv_gpuobj(chan)); return 0; } @@ -173,7 +171,7 @@ nv50_gr_cclass = { * PGRAPH engine/subdev functions ******************************************************************************/ -static const struct nvkm_bitfield nv50_pgr_status[] = { +static const struct nvkm_bitfield nv50_gr_status[] = { { 0x00000001, "BUSY" }, /* set when any bit is set */ { 0x00000002, "DISPATCH" }, { 0x00000004, "UNK2" }, @@ -202,27 +200,27 @@ static const struct nvkm_bitfield nv50_pgr_status[] = { {} }; -static const char *const nv50_pgr_vstatus_0[] = { +static const char *const nv50_gr_vstatus_0[] = { "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP", NULL }; -static const char *const nv50_pgr_vstatus_1[] = { +static const char *const nv50_gr_vstatus_1[] = { "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL }; -static const char *const nv50_pgr_vstatus_2[] = { +static const char *const nv50_gr_vstatus_2[] = { "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK", "ROP", NULL }; static void -nvkm_pgr_vstatus_print(struct nv50_gr_priv *priv, int r, +nvkm_gr_vstatus_print(struct nv50_gr *gr, int r, const char *const units[], u32 status) { int i; - nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status); + nv_error(gr, "PGRAPH_VSTATUS%d: 0x%08x", r, status); for (i = 0; units[i] && status; i++) { if ((status & 7) == 1) @@ -238,30 +236,30 @@ static int g84_gr_tlb_flush(struct nvkm_engine *engine) { struct nvkm_timer *tmr = nvkm_timer(engine); - struct nv50_gr_priv *priv = (void *)engine; + struct nv50_gr *gr = (void *)engine; bool idle, timeout = false; unsigned long flags; u64 start; u32 tmp; - spin_lock_irqsave(&priv->lock, flags); - nv_mask(priv, 0x400500, 0x00000001, 0x00000000); + spin_lock_irqsave(&gr->lock, flags); + nv_mask(gr, 0x400500, 0x00000001, 0x00000000); start = tmr->read(tmr); do { idle = true; - for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) { + for (tmp = nv_rd32(gr, 0x400380); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) { + for (tmp = nv_rd32(gr, 0x400384); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) { + for (tmp = nv_rd32(gr, 0x400388); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } @@ -269,27 +267,27 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) !(timeout = tmr->read(tmr) - start > 2000000000)); if (timeout) { - nv_error(priv, "PGRAPH TLB flush idle timeout fail\n"); + nv_error(gr, "PGRAPH TLB flush idle timeout fail\n"); - tmp = nv_rd32(priv, 0x400700); - nv_error(priv, "PGRAPH_STATUS : 0x%08x", tmp); - nvkm_bitfield_print(nv50_pgr_status, tmp); + tmp = nv_rd32(gr, 0x400700); + nv_error(gr, "PGRAPH_STATUS : 0x%08x", tmp); + nvkm_bitfield_print(nv50_gr_status, tmp); pr_cont("\n"); - nvkm_pgr_vstatus_print(priv, 0, nv50_pgr_vstatus_0, - nv_rd32(priv, 0x400380)); - nvkm_pgr_vstatus_print(priv, 1, nv50_pgr_vstatus_1, - nv_rd32(priv, 0x400384)); - nvkm_pgr_vstatus_print(priv, 2, nv50_pgr_vstatus_2, - nv_rd32(priv, 0x400388)); + nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0, + nv_rd32(gr, 0x400380)); + nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1, + nv_rd32(gr, 0x400384)); + nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2, + nv_rd32(gr, 0x400388)); } - nv_wr32(priv, 0x100c80, 0x00000001); - if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) - nv_error(priv, "vm flush timeout\n"); - nv_mask(priv, 0x400500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&priv->lock, flags); + nv_wr32(gr, 0x100c80, 0x00000001); + if (!nv_wait(gr, 0x100c80, 0x00000001, 0x00000000)) + nv_error(gr, "vm flush timeout\n"); + nv_mask(gr, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); return timeout ? -EBUSY : 0; } @@ -426,111 +424,111 @@ static const struct nvkm_bitfield nv50_gr_trap_prop[] = { }; static void -nv50_priv_prop_trap(struct nv50_gr_priv *priv, +nv50_gr_prop_trap(struct nv50_gr *gr, u32 ustatus_addr, u32 ustatus, u32 tp) { - u32 e0c = nv_rd32(priv, ustatus_addr + 0x04); - u32 e10 = nv_rd32(priv, ustatus_addr + 0x08); - u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c); - u32 e18 = nv_rd32(priv, ustatus_addr + 0x10); - u32 e1c = nv_rd32(priv, ustatus_addr + 0x14); - u32 e20 = nv_rd32(priv, ustatus_addr + 0x18); - u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c); + u32 e0c = nv_rd32(gr, ustatus_addr + 0x04); + u32 e10 = nv_rd32(gr, ustatus_addr + 0x08); + u32 e14 = nv_rd32(gr, ustatus_addr + 0x0c); + u32 e18 = nv_rd32(gr, ustatus_addr + 0x10); + u32 e1c = nv_rd32(gr, ustatus_addr + 0x14); + u32 e20 = nv_rd32(gr, ustatus_addr + 0x18); + u32 e24 = nv_rd32(gr, ustatus_addr + 0x1c); /* CUDA memory: l[], g[] or stack. */ if (ustatus & 0x00000080) { if (e18 & 0x80000000) { /* g[] read fault? */ - nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", + nv_error(gr, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", tp, e14, e10 | ((e18 >> 24) & 0x1f)); e18 &= ~0x1f000000; } else if (e18 & 0xc) { /* g[] write fault? */ - nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", + nv_error(gr, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", tp, e14, e10 | ((e18 >> 7) & 0x1f)); e18 &= ~0x00000f80; } else { - nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", + nv_error(gr, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", tp, e14, e10); } ustatus &= ~0x00000080; } if (ustatus) { - nv_error(priv, "TRAP_PROP - TP %d -", tp); + nv_error(gr, "TRAP_PROP - TP %d -", tp); nvkm_bitfield_print(nv50_gr_trap_prop, ustatus); pr_cont(" - Address %02x%08x\n", e14, e10); } - nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + nv_error(gr, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", tp, e0c, e18, e1c, e20, e24); } static void -nv50_priv_mp_trap(struct nv50_gr_priv *priv, int tpid, int display) +nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) { - u32 units = nv_rd32(priv, 0x1540); + u32 units = nv_rd32(gr, 0x1540); u32 addr, mp10, status, pc, oplow, ophigh; int i; int mps = 0; for (i = 0; i < 4; i++) { if (!(units & 1 << (i+24))) continue; - if (nv_device(priv)->chipset < 0xa0) + if (nv_device(gr)->chipset < 0xa0) addr = 0x408200 + (tpid << 12) + (i << 7); else addr = 0x408100 + (tpid << 11) + (i << 7); - mp10 = nv_rd32(priv, addr + 0x10); - status = nv_rd32(priv, addr + 0x14); + mp10 = nv_rd32(gr, addr + 0x10); + status = nv_rd32(gr, addr + 0x14); if (!status) continue; if (display) { - nv_rd32(priv, addr + 0x20); - pc = nv_rd32(priv, addr + 0x24); - oplow = nv_rd32(priv, addr + 0x70); - ophigh = nv_rd32(priv, addr + 0x74); - nv_error(priv, "TRAP_MP_EXEC - " + nv_rd32(gr, addr + 0x20); + pc = nv_rd32(gr, addr + 0x24); + oplow = nv_rd32(gr, addr + 0x70); + ophigh = nv_rd32(gr, addr + 0x74); + nv_error(gr, "TRAP_MP_EXEC - " "TP %d MP %d:", tpid, i); nvkm_bitfield_print(nv50_mp_exec_errors, status); pr_cont(" at %06x warp %d, opcode %08x %08x\n", pc&0xffffff, pc >> 24, oplow, ophigh); } - nv_wr32(priv, addr + 0x10, mp10); - nv_wr32(priv, addr + 0x14, 0); + nv_wr32(gr, addr + 0x10, mp10); + nv_wr32(gr, addr + 0x14, 0); mps++; } if (!mps && display) - nv_error(priv, "TRAP_MP_EXEC - TP %d: " + nv_error(gr, "TRAP_MP_EXEC - TP %d: " "No MPs claiming errors?\n", tpid); } static void -nv50_priv_tp_trap(struct nv50_gr_priv *priv, int type, u32 ustatus_old, +nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, u32 ustatus_new, int display, const char *name) { int tps = 0; - u32 units = nv_rd32(priv, 0x1540); + u32 units = nv_rd32(gr, 0x1540); int i, r; u32 ustatus_addr, ustatus; for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; - if (nv_device(priv)->chipset < 0xa0) + if (nv_device(gr)->chipset < 0xa0) ustatus_addr = ustatus_old + (i << 12); else ustatus_addr = ustatus_new + (i << 11); - ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff; + ustatus = nv_rd32(gr, ustatus_addr) & 0x7fffffff; if (!ustatus) continue; tps++; switch (type) { case 6: /* texture error... unknown for now */ if (display) { - nv_error(priv, "magic set %d:\n", i); + nv_error(gr, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) - nv_error(priv, "\t0x%08x: 0x%08x\n", r, - nv_rd32(priv, r)); + nv_error(gr, "\t0x%08x: 0x%08x\n", r, + nv_rd32(gr, r)); if (ustatus) { - nv_error(priv, "%s - TP%d:", name, i); + nv_error(gr, "%s - TP%d:", name, i); nvkm_bitfield_print(nv50_tex_traps, ustatus); pr_cont("\n"); @@ -540,11 +538,11 @@ nv50_priv_tp_trap(struct nv50_gr_priv *priv, int type, u32 ustatus_old, break; case 7: /* MP error */ if (ustatus & 0x04030000) { - nv50_priv_mp_trap(priv, i, display); + nv50_gr_mp_trap(gr, i, display); ustatus &= ~0x04030000; } if (ustatus && display) { - nv_error(priv, "%s - TP%d:", name, i); + nv_error(gr, "%s - TP%d:", name, i); nvkm_bitfield_print(nv50_mpc_traps, ustatus); pr_cont("\n"); ustatus = 0; @@ -552,31 +550,31 @@ nv50_priv_tp_trap(struct nv50_gr_priv *priv, int type, u32 ustatus_old, break; case 8: /* PROP error */ if (display) - nv50_priv_prop_trap( - priv, ustatus_addr, ustatus, i); + nv50_gr_prop_trap( + gr, ustatus_addr, ustatus, i); ustatus = 0; break; } if (ustatus) { if (display) - nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + nv_error(gr, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); } - nv_wr32(priv, ustatus_addr, 0xc0000000); + nv_wr32(gr, ustatus_addr, 0xc0000000); } if (!tps && display) - nv_warn(priv, "%s - No TPs claiming errors?\n", name); + nv_warn(gr, "%s - No TPs claiming errors?\n", name); } static int -nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, +nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, int chid, u64 inst, struct nvkm_object *engctx) { - u32 status = nv_rd32(priv, 0x400108); + u32 status = nv_rd32(gr, 0x400108); u32 ustatus; if (!status && display) { - nv_error(priv, "TRAP: no units reporting traps?\n"); + nv_error(gr, "TRAP: no units reporting traps?\n"); return 1; } @@ -584,71 +582,71 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, * COND, QUERY. If you get a trap from it, the command is still stuck * in DISPATCH and you need to do something about it. */ if (status & 0x001) { - ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff; + ustatus = nv_rd32(gr, 0x400804) & 0x7fffffff; if (!ustatus && display) { - nv_error(priv, "TRAP_DISPATCH - no ustatus?\n"); + nv_error(gr, "TRAP_DISPATCH - no ustatus?\n"); } - nv_wr32(priv, 0x400500, 0x00000000); + nv_wr32(gr, 0x400500, 0x00000000); /* Known to be triggered by screwed up NOTIFY and COND... */ if (ustatus & 0x00000001) { - u32 addr = nv_rd32(priv, 0x400808); + u32 addr = nv_rd32(gr, 0x400808); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 datal = nv_rd32(priv, 0x40080c); - u32 datah = nv_rd32(priv, 0x400810); - u32 class = nv_rd32(priv, 0x400814); - u32 r848 = nv_rd32(priv, 0x400848); + u32 datal = nv_rd32(gr, 0x40080c); + u32 datah = nv_rd32(gr, 0x400810); + u32 class = nv_rd32(gr, 0x400814); + u32 r848 = nv_rd32(gr, 0x400848); - nv_error(priv, "TRAP DISPATCH_FAULT\n"); + nv_error(gr, "TRAP DISPATCH_FAULT\n"); if (display && (addr & 0x80000000)) { - nv_error(priv, + nv_error(gr, "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n", chid, inst, nvkm_client_name(engctx), subc, class, mthd, datah, datal, addr, r848); } else if (display) { - nv_error(priv, "no stuck command?\n"); + nv_error(gr, "no stuck command?\n"); } - nv_wr32(priv, 0x400808, 0); - nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3); - nv_wr32(priv, 0x400848, 0); + nv_wr32(gr, 0x400808, 0); + nv_wr32(gr, 0x4008e8, nv_rd32(gr, 0x4008e8) & 3); + nv_wr32(gr, 0x400848, 0); ustatus &= ~0x00000001; } if (ustatus & 0x00000002) { - u32 addr = nv_rd32(priv, 0x40084c); + u32 addr = nv_rd32(gr, 0x40084c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, 0x40085c); - u32 class = nv_rd32(priv, 0x400814); + u32 data = nv_rd32(gr, 0x40085c); + u32 class = nv_rd32(gr, 0x400814); - nv_error(priv, "TRAP DISPATCH_QUERY\n"); + nv_error(gr, "TRAP DISPATCH_QUERY\n"); if (display && (addr & 0x80000000)) { - nv_error(priv, + nv_error(gr, "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n", chid, inst, nvkm_client_name(engctx), subc, class, mthd, data, addr); } else if (display) { - nv_error(priv, "no stuck command?\n"); + nv_error(gr, "no stuck command?\n"); } - nv_wr32(priv, 0x40084c, 0); + nv_wr32(gr, 0x40084c, 0); ustatus &= ~0x00000002; } if (ustatus && display) { - nv_error(priv, "TRAP_DISPATCH (unknown " + nv_error(gr, "TRAP_DISPATCH (unknown " "0x%08x)\n", ustatus); } - nv_wr32(priv, 0x400804, 0xc0000000); - nv_wr32(priv, 0x400108, 0x001); + nv_wr32(gr, 0x400804, 0xc0000000); + nv_wr32(gr, 0x400108, 0x001); status &= ~0x001; if (!status) return 0; @@ -656,81 +654,81 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, /* M2MF: Memory to memory copy engine. */ if (status & 0x002) { - u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff; + u32 ustatus = nv_rd32(gr, 0x406800) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_M2MF"); + nv_error(gr, "TRAP_M2MF"); nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus); pr_cont("\n"); - nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n", - nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808), - nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810)); + nv_error(gr, "TRAP_M2MF %08x %08x %08x %08x\n", + nv_rd32(gr, 0x406804), nv_rd32(gr, 0x406808), + nv_rd32(gr, 0x40680c), nv_rd32(gr, 0x406810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(priv, 0x400040, 2); - nv_wr32(priv, 0x400040, 0); - nv_wr32(priv, 0x406800, 0xc0000000); - nv_wr32(priv, 0x400108, 0x002); + nv_wr32(gr, 0x400040, 2); + nv_wr32(gr, 0x400040, 0); + nv_wr32(gr, 0x406800, 0xc0000000); + nv_wr32(gr, 0x400108, 0x002); status &= ~0x002; } /* VFETCH: Fetches data from vertex buffers. */ if (status & 0x004) { - u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff; + u32 ustatus = nv_rd32(gr, 0x400c04) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_VFETCH"); + nv_error(gr, "TRAP_VFETCH"); nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus); pr_cont("\n"); - nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n", - nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08), - nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10)); + nv_error(gr, "TRAP_VFETCH %08x %08x %08x %08x\n", + nv_rd32(gr, 0x400c00), nv_rd32(gr, 0x400c08), + nv_rd32(gr, 0x400c0c), nv_rd32(gr, 0x400c10)); } - nv_wr32(priv, 0x400c04, 0xc0000000); - nv_wr32(priv, 0x400108, 0x004); + nv_wr32(gr, 0x400c04, 0xc0000000); + nv_wr32(gr, 0x400108, 0x004); status &= ~0x004; } /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ if (status & 0x008) { - ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff; + ustatus = nv_rd32(gr, 0x401800) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_STRMOUT"); + nv_error(gr, "TRAP_STRMOUT"); nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus); pr_cont("\n"); - nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n", - nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808), - nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810)); + nv_error(gr, "TRAP_STRMOUT %08x %08x %08x %08x\n", + nv_rd32(gr, 0x401804), nv_rd32(gr, 0x401808), + nv_rd32(gr, 0x40180c), nv_rd32(gr, 0x401810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(priv, 0x400040, 0x80); - nv_wr32(priv, 0x400040, 0); - nv_wr32(priv, 0x401800, 0xc0000000); - nv_wr32(priv, 0x400108, 0x008); + nv_wr32(gr, 0x400040, 0x80); + nv_wr32(gr, 0x400040, 0); + nv_wr32(gr, 0x401800, 0xc0000000); + nv_wr32(gr, 0x400108, 0x008); status &= ~0x008; } /* CCACHE: Handles code and c[] caches and fills them. */ if (status & 0x010) { - ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff; + ustatus = nv_rd32(gr, 0x405018) & 0x7fffffff; if (display) { - nv_error(priv, "TRAP_CCACHE"); + nv_error(gr, "TRAP_CCACHE"); nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus); pr_cont("\n"); - nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x" + nv_error(gr, "TRAP_CCACHE %08x %08x %08x %08x" " %08x %08x %08x\n", - nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004), - nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c), - nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014), - nv_rd32(priv, 0x40501c)); + nv_rd32(gr, 0x405000), nv_rd32(gr, 0x405004), + nv_rd32(gr, 0x405008), nv_rd32(gr, 0x40500c), + nv_rd32(gr, 0x405010), nv_rd32(gr, 0x405014), + nv_rd32(gr, 0x40501c)); } - nv_wr32(priv, 0x405018, 0xc0000000); - nv_wr32(priv, 0x400108, 0x010); + nv_wr32(gr, 0x405018, 0xc0000000); + nv_wr32(gr, 0x400108, 0x010); status &= ~0x010; } @@ -738,42 +736,42 @@ nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display, * remaining, so try to handle it anyway. Perhaps related to that * unknown DMA slot on tesla? */ if (status & 0x20) { - ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff; + ustatus = nv_rd32(gr, 0x402000) & 0x7fffffff; if (display) - nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus); - nv_wr32(priv, 0x402000, 0xc0000000); + nv_error(gr, "TRAP_UNKC04 0x%08x\n", ustatus); + nv_wr32(gr, 0x402000, 0xc0000000); /* no status modifiction on purpose */ } /* TEXTURE: CUDA texturing units */ if (status & 0x040) { - nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display, + nv50_gr_tp_trap(gr, 6, 0x408900, 0x408600, display, "TRAP_TEXTURE"); - nv_wr32(priv, 0x400108, 0x040); + nv_wr32(gr, 0x400108, 0x040); status &= ~0x040; } /* MP: CUDA execution engines. */ if (status & 0x080) { - nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display, + nv50_gr_tp_trap(gr, 7, 0x408314, 0x40831c, display, "TRAP_MP"); - nv_wr32(priv, 0x400108, 0x080); + nv_wr32(gr, 0x400108, 0x080); status &= ~0x080; } /* PROP: Handles TP-initiated uncached memory accesses: * l[], g[], stack, 2d surfaces, render targets. */ if (status & 0x100) { - nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display, + nv50_gr_tp_trap(gr, 8, 0x408e08, 0x408708, display, "TRAP_PROP"); - nv_wr32(priv, 0x400108, 0x100); + nv_wr32(gr, 0x400108, 0x100); status &= ~0x100; } if (status) { if (display) - nv_error(priv, "TRAP: unknown 0x%08x\n", status); - nv_wr32(priv, 0x400108, status); + nv_error(gr, "TRAP: unknown 0x%08x\n", status); + nv_wr32(gr, 0x400108, status); } return 1; @@ -786,14 +784,14 @@ nv50_gr_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle = NULL; - struct nv50_gr_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x400100); - u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff; - u32 addr = nv_rd32(priv, 0x400704); + struct nv50_gr *gr = (void *)subdev; + u32 stat = nv_rd32(gr, 0x400100); + u32 inst = nv_rd32(gr, 0x40032c) & 0x0fffffff; + u32 addr = nv_rd32(gr, 0x400704); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(priv, 0x400708); - u32 class = nv_rd32(priv, 0x400814); + u32 data = nv_rd32(gr, 0x400708); + u32 class = nv_rd32(gr, 0x400814); u32 show = stat, show_bitfield = stat; int chid; @@ -808,38 +806,38 @@ nv50_gr_intr(struct nvkm_subdev *subdev) } if (show & 0x00100000) { - u32 ecode = nv_rd32(priv, 0x400110); - nv_error(priv, "DATA_ERROR "); + u32 ecode = nv_rd32(gr, 0x400110); + nv_error(gr, "DATA_ERROR "); nvkm_enum_print(nv50_data_error_names, ecode); pr_cont("\n"); show_bitfield &= ~0x00100000; } if (stat & 0x00200000) { - if (!nv50_gr_trap_handler(priv, show, chid, (u64)inst << 12, + if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12, engctx)) show &= ~0x00200000; show_bitfield &= ~0x00200000; } - nv_wr32(priv, 0x400100, stat); - nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(gr, 0x400100, stat); + nv_wr32(gr, 0x400500, 0x00010001); if (show) { show &= show_bitfield; if (show) { - nv_error(priv, "%s", ""); + nv_error(gr, "%s", ""); nvkm_bitfield_print(nv50_gr_intr_name, show); pr_cont("\n"); } - nv_error(priv, + nv_error(gr, "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, (u64)inst << 12, nvkm_client_name(engctx), subc, class, mthd, data); } - if (nv_rd32(priv, 0x400824) & (1 << 31)) - nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31)); + if (nv_rd32(gr, 0x400824) & (1 << 31)) + nv_wr32(gr, 0x400824, nv_rd32(gr, 0x400824) & ~(1 << 31)); nvkm_engctx_put(engctx); } @@ -849,23 +847,23 @@ nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_gr_priv *priv; + struct nv50_gr *gr; int ret; - ret = nvkm_gr_create(parent, engine, oclass, true, &priv); - *pobject = nv_object(priv); + ret = nvkm_gr_create(parent, engine, oclass, true, &gr); + *pobject = nv_object(gr); if (ret) return ret; - nv_subdev(priv)->unit = 0x00201000; - nv_subdev(priv)->intr = nv50_gr_intr; - nv_engine(priv)->cclass = &nv50_gr_cclass; + nv_subdev(gr)->unit = 0x00201000; + nv_subdev(gr)->intr = nv50_gr_intr; + nv_engine(gr)->cclass = &nv50_gr_cclass; - priv->base.units = nv50_gr_units; + gr->base.units = nv50_gr_units; - switch (nv_device(priv)->chipset) { + switch (nv_device(gr)->chipset) { case 0x50: - nv_engine(priv)->sclass = nv50_gr_sclass; + nv_engine(gr)->sclass = nv50_gr_sclass; break; case 0x84: case 0x86: @@ -873,104 +871,104 @@ nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, case 0x94: case 0x96: case 0x98: - nv_engine(priv)->sclass = g84_gr_sclass; + nv_engine(gr)->sclass = g84_gr_sclass; break; case 0xa0: case 0xaa: case 0xac: - nv_engine(priv)->sclass = gt200_gr_sclass; + nv_engine(gr)->sclass = gt200_gr_sclass; break; case 0xa3: case 0xa5: case 0xa8: - nv_engine(priv)->sclass = gt215_gr_sclass; + nv_engine(gr)->sclass = gt215_gr_sclass; break; case 0xaf: - nv_engine(priv)->sclass = mcp89_gr_sclass; + nv_engine(gr)->sclass = mcp89_gr_sclass; break; } /* unfortunate hw bug workaround... */ - if (nv_device(priv)->chipset != 0x50 && - nv_device(priv)->chipset != 0xac) - nv_engine(priv)->tlb_flush = g84_gr_tlb_flush; + if (nv_device(gr)->chipset != 0x50 && + nv_device(gr)->chipset != 0xac) + nv_engine(gr)->tlb_flush = g84_gr_tlb_flush; - spin_lock_init(&priv->lock); + spin_lock_init(&gr->lock); return 0; } static int nv50_gr_init(struct nvkm_object *object) { - struct nv50_gr_priv *priv = (void *)object; + struct nv50_gr *gr = (void *)object; int ret, units, i; - ret = nvkm_gr_init(&priv->base); + ret = nvkm_gr_init(&gr->base); if (ret) return ret; /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */ - nv_wr32(priv, 0x40008c, 0x00000004); + nv_wr32(gr, 0x40008c, 0x00000004); /* reset/enable traps and interrupts */ - nv_wr32(priv, 0x400804, 0xc0000000); - nv_wr32(priv, 0x406800, 0xc0000000); - nv_wr32(priv, 0x400c04, 0xc0000000); - nv_wr32(priv, 0x401800, 0xc0000000); - nv_wr32(priv, 0x405018, 0xc0000000); - nv_wr32(priv, 0x402000, 0xc0000000); - - units = nv_rd32(priv, 0x001540); + nv_wr32(gr, 0x400804, 0xc0000000); + nv_wr32(gr, 0x406800, 0xc0000000); + nv_wr32(gr, 0x400c04, 0xc0000000); + nv_wr32(gr, 0x401800, 0xc0000000); + nv_wr32(gr, 0x405018, 0xc0000000); + nv_wr32(gr, 0x402000, 0xc0000000); + + units = nv_rd32(gr, 0x001540); for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; - if (nv_device(priv)->chipset < 0xa0) { - nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000); - nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000); - nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000); + if (nv_device(gr)->chipset < 0xa0) { + nv_wr32(gr, 0x408900 + (i << 12), 0xc0000000); + nv_wr32(gr, 0x408e08 + (i << 12), 0xc0000000); + nv_wr32(gr, 0x408314 + (i << 12), 0xc0000000); } else { - nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000); - nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000); - nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000); + nv_wr32(gr, 0x408600 + (i << 11), 0xc0000000); + nv_wr32(gr, 0x408708 + (i << 11), 0xc0000000); + nv_wr32(gr, 0x40831c + (i << 11), 0xc0000000); } } - nv_wr32(priv, 0x400108, 0xffffffff); - nv_wr32(priv, 0x400138, 0xffffffff); - nv_wr32(priv, 0x400100, 0xffffffff); - nv_wr32(priv, 0x40013c, 0xffffffff); - nv_wr32(priv, 0x400500, 0x00010001); + nv_wr32(gr, 0x400108, 0xffffffff); + nv_wr32(gr, 0x400138, 0xffffffff); + nv_wr32(gr, 0x400100, 0xffffffff); + nv_wr32(gr, 0x40013c, 0xffffffff); + nv_wr32(gr, 0x400500, 0x00010001); /* upload context program, initialise ctxctl defaults */ - ret = nv50_grctx_init(nv_device(priv), &priv->size); + ret = nv50_grctx_init(nv_device(gr), &gr->size); if (ret) return ret; - nv_wr32(priv, 0x400824, 0x00000000); - nv_wr32(priv, 0x400828, 0x00000000); - nv_wr32(priv, 0x40082c, 0x00000000); - nv_wr32(priv, 0x400830, 0x00000000); - nv_wr32(priv, 0x40032c, 0x00000000); - nv_wr32(priv, 0x400330, 0x00000000); + nv_wr32(gr, 0x400824, 0x00000000); + nv_wr32(gr, 0x400828, 0x00000000); + nv_wr32(gr, 0x40082c, 0x00000000); + nv_wr32(gr, 0x400830, 0x00000000); + nv_wr32(gr, 0x40032c, 0x00000000); + nv_wr32(gr, 0x400330, 0x00000000); /* some unknown zcull magic */ - switch (nv_device(priv)->chipset & 0xf0) { + switch (nv_device(gr)->chipset & 0xf0) { case 0x50: case 0x80: case 0x90: - nv_wr32(priv, 0x402ca8, 0x00000800); + nv_wr32(gr, 0x402ca8, 0x00000800); break; case 0xa0: default: - if (nv_device(priv)->chipset == 0xa0 || - nv_device(priv)->chipset == 0xaa || - nv_device(priv)->chipset == 0xac) { - nv_wr32(priv, 0x402ca8, 0x00000802); + if (nv_device(gr)->chipset == 0xa0 || + nv_device(gr)->chipset == 0xaa || + nv_device(gr)->chipset == 0xac) { + nv_wr32(gr, 0x402ca8, 0x00000802); } else { - nv_wr32(priv, 0x402cc0, 0x00000000); - nv_wr32(priv, 0x402ca8, 0x00000002); + nv_wr32(gr, 0x402cc0, 0x00000000); + nv_wr32(gr, 0x402ca8, 0x00000002); } break; @@ -978,10 +976,10 @@ nv50_gr_init(struct nvkm_object *object) /* zero out zcull regions */ for (i = 0; i < 8; i++) { - nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000); - nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000); - nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000); - nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000); + nv_wr32(gr, 0x402c20 + (i * 0x10), 0x00000000); + nv_wr32(gr, 0x402c24 + (i * 0x10), 0x00000000); + nv_wr32(gr, 0x402c28 + (i * 0x10), 0x00000000); + nv_wr32(gr, 0x402c2c + (i * 0x10), 0x00000000); } return 0; } -- GitLab From b19de4f3d787947224e89447505dd3c99b304d7b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5350/7006] drm/nouveau/mpeg: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/mpeg.h | 8 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/g84.c | 18 ++- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 112 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 44 +++---- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 60 +++++----- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 78 ++++++------ 7 files changed, 155 insertions(+), 167 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h index 4e500b398064d..24cfd93f65d5f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h @@ -24,17 +24,17 @@ struct nvkm_mpeg_chan { #include struct nvkm_mpeg { - struct nvkm_engine base; + struct nvkm_engine engine; }; #define nvkm_mpeg_create(p,e,c,d) \ nvkm_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d)) #define nvkm_mpeg_destroy(d) \ - nvkm_engine_destroy(&(d)->base) + nvkm_engine_destroy(&(d)->engine) #define nvkm_mpeg_init(d) \ - nvkm_engine_init(&(d)->base) + nvkm_engine_init(&(d)->engine) #define nvkm_mpeg_fini(d,s) \ - nvkm_engine_fini(&(d)->base, (s)) + nvkm_engine_fini(&(d)->engine, (s)) #define _nvkm_mpeg_dtor _nvkm_engine_dtor #define _nvkm_mpeg_init _nvkm_engine_init diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c index 0df889fa2611f..cdcca3ab4332b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c @@ -23,10 +23,6 @@ */ #include -struct g84_mpeg_priv { - struct nvkm_mpeg base; -}; - struct g84_mpeg_chan { struct nvkm_mpeg_chan base; }; @@ -67,18 +63,18 @@ g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g84_mpeg_priv *priv; + struct nvkm_mpeg *mpeg; int ret; - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); + *pobject = nv_object(mpeg); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv50_mpeg_intr; - nv_engine(priv)->cclass = &g84_mpeg_cclass; - nv_engine(priv)->sclass = g84_mpeg_sclass; + nv_subdev(mpeg)->unit = 0x00000002; + nv_subdev(mpeg)->intr = nv50_mpeg_intr; + nv_engine(mpeg)->cclass = &g84_mpeg_cclass; + nv_engine(mpeg)->sclass = g84_mpeg_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 4199684a4b28a..34dd5f6ac247b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -60,7 +60,7 @@ static int nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) { struct nvkm_instmem *imem = nvkm_instmem(object); - struct nv31_mpeg_priv *priv = (void *)object->engine; + struct nv31_mpeg *mpeg = (void *)object->engine; u32 inst = *(u32 *)arg << 4; u32 dma0 = nv_ro32(imem, inst + 0); u32 dma1 = nv_ro32(imem, inst + 4); @@ -74,22 +74,22 @@ nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); - nv_wr32(priv, 0x00b334, base); - nv_wr32(priv, 0x00b324, size); + nv_mask(mpeg, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); + nv_wr32(mpeg, 0x00b334, base); + nv_wr32(mpeg, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); - nv_wr32(priv, 0x00b360, base); - nv_wr32(priv, 0x00b364, size); + nv_mask(mpeg, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); + nv_wr32(mpeg, 0x00b360, base); + nv_wr32(mpeg, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) return -EINVAL; - nv_wr32(priv, 0x00b370, base); - nv_wr32(priv, 0x00b374, size); + nv_wr32(mpeg, 0x00b370, base); + nv_wr32(mpeg, 0x00b374, size); } return 0; @@ -129,7 +129,7 @@ nv31_mpeg_context_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv31_mpeg_priv *priv = (void *)engine; + struct nv31_mpeg *mpeg = (void *)engine; struct nv31_mpeg_chan *chan; unsigned long flags; int ret; @@ -139,28 +139,28 @@ nv31_mpeg_context_ctor(struct nvkm_object *parent, if (ret) return ret; - spin_lock_irqsave(&nv_engine(priv)->lock, flags); - if (priv->chan) { - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); + spin_lock_irqsave(&nv_engine(mpeg)->lock, flags); + if (mpeg->chan) { + spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); nvkm_object_destroy(&chan->base); *pobject = NULL; return -EBUSY; } - priv->chan = chan; - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); + mpeg->chan = chan; + spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); return 0; } static void nv31_mpeg_context_dtor(struct nvkm_object *object) { - struct nv31_mpeg_priv *priv = (void *)object->engine; + struct nv31_mpeg *mpeg = (void *)object->engine; struct nv31_mpeg_chan *chan = (void *)object; unsigned long flags; - spin_lock_irqsave(&nv_engine(priv)->lock, flags); - priv->chan = NULL; - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); + spin_lock_irqsave(&nv_engine(mpeg)->lock, flags); + mpeg->chan = NULL; + spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); nvkm_object_destroy(&chan->base); } @@ -183,34 +183,34 @@ void nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i) { struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nv31_mpeg_priv *priv = (void *)engine; + struct nv31_mpeg *mpeg = (void *)engine; - nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch); - nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit); - nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr); + nv_wr32(mpeg, 0x00b008 + (i * 0x10), tile->pitch); + nv_wr32(mpeg, 0x00b004 + (i * 0x10), tile->limit); + nv_wr32(mpeg, 0x00b000 + (i * 0x10), tile->addr); } void nv31_mpeg_intr(struct nvkm_subdev *subdev) { - struct nv31_mpeg_priv *priv = (void *)subdev; + struct nv31_mpeg *mpeg = (void *)subdev; struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_handle *handle; struct nvkm_object *engctx; - u32 stat = nv_rd32(priv, 0x00b100); - u32 type = nv_rd32(priv, 0x00b230); - u32 mthd = nv_rd32(priv, 0x00b234); - u32 data = nv_rd32(priv, 0x00b238); + u32 stat = nv_rd32(mpeg, 0x00b100); + u32 type = nv_rd32(mpeg, 0x00b230); + u32 mthd = nv_rd32(mpeg, 0x00b234); + u32 data = nv_rd32(mpeg, 0x00b238); u32 show = stat; unsigned long flags; - spin_lock_irqsave(&nv_engine(priv)->lock, flags); - engctx = nv_object(priv->chan); + spin_lock_irqsave(&nv_engine(mpeg)->lock, flags); + engctx = nv_object(mpeg->chan); if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); + nv_mask(mpeg, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } @@ -222,16 +222,16 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) } } - nv_wr32(priv, 0x00b100, stat); - nv_wr32(priv, 0x00b230, 0x00000001); + nv_wr32(mpeg, 0x00b100, stat); + nv_wr32(mpeg, 0x00b230, 0x00000001); if (show) { - nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", + nv_error(mpeg, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", fifo->chid(fifo, engctx), nvkm_client_name(engctx), stat, type, mthd, data); } - spin_unlock_irqrestore(&nv_engine(priv)->lock, flags); + spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); } static int @@ -239,19 +239,19 @@ nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv31_mpeg_priv *priv; + struct nv31_mpeg *mpeg; int ret; - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); + *pobject = nv_object(mpeg); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv31_mpeg_intr; - nv_engine(priv)->cclass = &nv31_mpeg_cclass; - nv_engine(priv)->sclass = nv31_mpeg_sclass; - nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; + nv_subdev(mpeg)->unit = 0x00000002; + nv_subdev(mpeg)->intr = nv31_mpeg_intr; + nv_engine(mpeg)->cclass = &nv31_mpeg_cclass; + nv_engine(mpeg)->sclass = nv31_mpeg_sclass; + nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; return 0; } @@ -259,33 +259,33 @@ int nv31_mpeg_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nv31_mpeg_priv *priv = (void *)object; + struct nv31_mpeg *mpeg = (void *)object; struct nvkm_fb *fb = nvkm_fb(object); int ret, i; - ret = nvkm_mpeg_init(&priv->base); + ret = nvkm_mpeg_init(&mpeg->base); if (ret) return ret; /* VPE init */ - nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nv_wr32(mpeg, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nv_wr32(mpeg, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); /* PMPEG init */ - nv_wr32(priv, 0x00b32c, 0x00000000); - nv_wr32(priv, 0x00b314, 0x00000100); - nv_wr32(priv, 0x00b220, 0x00000031); - nv_wr32(priv, 0x00b300, 0x02001ec1); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + nv_wr32(mpeg, 0x00b32c, 0x00000000); + nv_wr32(mpeg, 0x00b314, 0x00000100); + nv_wr32(mpeg, 0x00b220, 0x00000031); + nv_wr32(mpeg, 0x00b300, 0x02001ec1); + nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000001); - nv_wr32(priv, 0x00b100, 0xffffffff); - nv_wr32(priv, 0x00b140, 0xffffffff); + nv_wr32(mpeg, 0x00b100, 0xffffffff); + nv_wr32(mpeg, 0x00b140, 0xffffffff); - if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { - nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); + if (!nv_wait(mpeg, 0x00b200, 0x00000001, 0x00000000)) { + nv_error(mpeg, "timeout 0x%08x\n", nv_rd32(mpeg, 0x00b200)); return -EBUSY; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h index 782b796d74588..022a98e622dee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h @@ -6,7 +6,7 @@ struct nv31_mpeg_chan { struct nvkm_object base; }; -struct nv31_mpeg_priv { +struct nv31_mpeg { struct nvkm_mpeg base; struct nv31_mpeg_chan *chan; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 9508bf9e140f0..c87156a514ddf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -33,7 +33,7 @@ static int nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) { struct nvkm_instmem *imem = nvkm_instmem(object); - struct nv31_mpeg_priv *priv = (void *)object->engine; + struct nv31_mpeg *mpeg = (void *)object->engine; u32 inst = *(u32 *)arg << 4; u32 dma0 = nv_ro32(imem, inst + 0); u32 dma1 = nv_ro32(imem, inst + 4); @@ -47,22 +47,22 @@ nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000)); - nv_wr32(priv, 0x00b334, base); - nv_wr32(priv, 0x00b324, size); + nv_mask(mpeg, 0x00b300, 0x00030000, (dma0 & 0x00030000)); + nv_wr32(mpeg, 0x00b334, base); + nv_wr32(mpeg, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); - nv_wr32(priv, 0x00b360, base); - nv_wr32(priv, 0x00b364, size); + nv_mask(mpeg, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); + nv_wr32(mpeg, 0x00b360, base); + nv_wr32(mpeg, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) return -EINVAL; - nv_wr32(priv, 0x00b370, base); - nv_wr32(priv, 0x00b374, size); + nv_wr32(mpeg, 0x00b370, base); + nv_wr32(mpeg, 0x00b374, size); } return 0; @@ -89,15 +89,15 @@ nv40_mpeg_sclass[] = { static void nv40_mpeg_intr(struct nvkm_subdev *subdev) { - struct nv31_mpeg_priv *priv = (void *)subdev; + struct nv31_mpeg *mpeg = (void *)subdev; u32 stat; - if ((stat = nv_rd32(priv, 0x00b100))) + if ((stat = nv_rd32(mpeg, 0x00b100))) nv31_mpeg_intr(subdev); - if ((stat = nv_rd32(priv, 0x00b800))) { - nv_error(priv, "PMSRCH 0x%08x\n", stat); - nv_wr32(priv, 0x00b800, stat); + if ((stat = nv_rd32(mpeg, 0x00b800))) { + nv_error(mpeg, "PMSRCH 0x%08x\n", stat); + nv_wr32(mpeg, 0x00b800, stat); } } @@ -106,19 +106,19 @@ nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv31_mpeg_priv *priv; + struct nv31_mpeg *mpeg; int ret; - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); + *pobject = nv_object(mpeg); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv40_mpeg_intr; - nv_engine(priv)->cclass = &nv31_mpeg_cclass; - nv_engine(priv)->sclass = nv40_mpeg_sclass; - nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; + nv_subdev(mpeg)->unit = 0x00000002; + nv_subdev(mpeg)->intr = nv40_mpeg_intr; + nv_engine(mpeg)->cclass = &nv31_mpeg_cclass; + nv_engine(mpeg)->sclass = nv40_mpeg_sclass; + nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index aeed7f850f657..f494328c74e30 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -27,10 +27,6 @@ #include #include -struct nv44_mpeg_priv { - struct nvkm_mpeg base; -}; - struct nv44_mpeg_chan { struct nvkm_mpeg_chan base; }; @@ -62,14 +58,14 @@ static int nv44_mpeg_context_fini(struct nvkm_object *object, bool suspend) { - struct nv44_mpeg_priv *priv = (void *)object->engine; + struct nvkm_mpeg *mpeg = (void *)object->engine; struct nv44_mpeg_chan *chan = (void *)object; u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000); - if (nv_rd32(priv, 0x00b318) == inst) - nv_mask(priv, 0x00b318, 0x80000000, 0x00000000); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000000); + if (nv_rd32(mpeg, 0x00b318) == inst) + nv_mask(mpeg, 0x00b318, 0x80000000, 0x00000000); + nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000001); return 0; } @@ -97,12 +93,12 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; - struct nv44_mpeg_priv *priv = (void *)subdev; - u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff; - u32 stat = nv_rd32(priv, 0x00b100); - u32 type = nv_rd32(priv, 0x00b230); - u32 mthd = nv_rd32(priv, 0x00b234); - u32 data = nv_rd32(priv, 0x00b238); + struct nvkm_mpeg *mpeg = (void *)subdev; + u32 inst = nv_rd32(mpeg, 0x00b318) & 0x000fffff; + u32 stat = nv_rd32(mpeg, 0x00b100); + u32 type = nv_rd32(mpeg, 0x00b230); + u32 mthd = nv_rd32(mpeg, 0x00b234); + u32 data = nv_rd32(mpeg, 0x00b238); u32 show = stat; int chid; @@ -112,7 +108,7 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(priv, 0x00b308, 0x00000000, 0x00000000); + nv_mask(mpeg, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } @@ -124,11 +120,11 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) } } - nv_wr32(priv, 0x00b100, stat); - nv_wr32(priv, 0x00b230, 0x00000001); + nv_wr32(mpeg, 0x00b100, stat); + nv_wr32(mpeg, 0x00b230, 0x00000001); if (show) { - nv_error(priv, + nv_error(mpeg, "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n", chid, inst << 4, nvkm_client_name(engctx), stat, type, mthd, data); @@ -140,15 +136,15 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) static void nv44_mpeg_me_intr(struct nvkm_subdev *subdev) { - struct nv44_mpeg_priv *priv = (void *)subdev; + struct nvkm_mpeg *mpeg = (void *)subdev; u32 stat; - if ((stat = nv_rd32(priv, 0x00b100))) + if ((stat = nv_rd32(mpeg, 0x00b100))) nv44_mpeg_intr(subdev); - if ((stat = nv_rd32(priv, 0x00b800))) { - nv_error(priv, "PMSRCH 0x%08x\n", stat); - nv_wr32(priv, 0x00b800, stat); + if ((stat = nv_rd32(mpeg, 0x00b800))) { + nv_error(mpeg, "PMSRCH 0x%08x\n", stat); + nv_wr32(mpeg, 0x00b800, stat); } } @@ -157,19 +153,19 @@ nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv44_mpeg_priv *priv; + struct nvkm_mpeg *mpeg; int ret; - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); + *pobject = nv_object(mpeg); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nv44_mpeg_me_intr; - nv_engine(priv)->cclass = &nv44_mpeg_cclass; - nv_engine(priv)->sclass = nv40_mpeg_sclass; - nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog; + nv_subdev(mpeg)->unit = 0x00000002; + nv_subdev(mpeg)->intr = nv44_mpeg_me_intr; + nv_engine(mpeg)->cclass = &nv44_mpeg_cclass; + nv_engine(mpeg)->sclass = nv40_mpeg_sclass; + nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index b3463f3739ce7..f908fa0932666 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -26,10 +26,6 @@ #include #include -struct nv50_mpeg_priv { - struct nvkm_mpeg base; -}; - struct nv50_mpeg_chan { struct nvkm_mpeg_chan base; }; @@ -122,42 +118,42 @@ nv50_mpeg_cclass = { void nv50_mpeg_intr(struct nvkm_subdev *subdev) { - struct nv50_mpeg_priv *priv = (void *)subdev; - u32 stat = nv_rd32(priv, 0x00b100); - u32 type = nv_rd32(priv, 0x00b230); - u32 mthd = nv_rd32(priv, 0x00b234); - u32 data = nv_rd32(priv, 0x00b238); + struct nvkm_mpeg *mpeg = (void *)subdev; + u32 stat = nv_rd32(mpeg, 0x00b100); + u32 type = nv_rd32(mpeg, 0x00b230); + u32 mthd = nv_rd32(mpeg, 0x00b234); + u32 data = nv_rd32(mpeg, 0x00b238); u32 show = stat; if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_wr32(priv, 0x00b308, 0x00000100); + nv_wr32(mpeg, 0x00b308, 0x00000100); show &= ~0x01000000; } } if (show) { - nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n", + nv_info(mpeg, "0x%08x 0x%08x 0x%08x 0x%08x\n", stat, type, mthd, data); } - nv_wr32(priv, 0x00b100, stat); - nv_wr32(priv, 0x00b230, 0x00000001); + nv_wr32(mpeg, 0x00b100, stat); + nv_wr32(mpeg, 0x00b230, 0x00000001); } static void nv50_vpe_intr(struct nvkm_subdev *subdev) { - struct nv50_mpeg_priv *priv = (void *)subdev; + struct nvkm_mpeg *mpeg = (void *)subdev; - if (nv_rd32(priv, 0x00b100)) + if (nv_rd32(mpeg, 0x00b100)) nv50_mpeg_intr(subdev); - if (nv_rd32(priv, 0x00b800)) { - u32 stat = nv_rd32(priv, 0x00b800); - nv_info(priv, "PMSRCH: 0x%08x\n", stat); - nv_wr32(priv, 0xb800, stat); + if (nv_rd32(mpeg, 0x00b800)) { + u32 stat = nv_rd32(mpeg, 0x00b800); + nv_info(mpeg, "PMSRCH: 0x%08x\n", stat); + nv_wr32(mpeg, 0xb800, stat); } } @@ -166,47 +162,47 @@ nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_mpeg_priv *priv; + struct nvkm_mpeg *mpeg; int ret; - ret = nvkm_mpeg_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); + *pobject = nv_object(mpeg); if (ret) return ret; - nv_subdev(priv)->unit = 0x00400002; - nv_subdev(priv)->intr = nv50_vpe_intr; - nv_engine(priv)->cclass = &nv50_mpeg_cclass; - nv_engine(priv)->sclass = nv50_mpeg_sclass; + nv_subdev(mpeg)->unit = 0x00400002; + nv_subdev(mpeg)->intr = nv50_vpe_intr; + nv_engine(mpeg)->cclass = &nv50_mpeg_cclass; + nv_engine(mpeg)->sclass = nv50_mpeg_sclass; return 0; } int nv50_mpeg_init(struct nvkm_object *object) { - struct nv50_mpeg_priv *priv = (void *)object; + struct nvkm_mpeg *mpeg = (void *)object; int ret; - ret = nvkm_mpeg_init(&priv->base); + ret = nvkm_mpeg_init(mpeg); if (ret) return ret; - nv_wr32(priv, 0x00b32c, 0x00000000); - nv_wr32(priv, 0x00b314, 0x00000100); - nv_wr32(priv, 0x00b0e0, 0x0000001a); + nv_wr32(mpeg, 0x00b32c, 0x00000000); + nv_wr32(mpeg, 0x00b314, 0x00000100); + nv_wr32(mpeg, 0x00b0e0, 0x0000001a); - nv_wr32(priv, 0x00b220, 0x00000044); - nv_wr32(priv, 0x00b300, 0x00801ec1); - nv_wr32(priv, 0x00b390, 0x00000000); - nv_wr32(priv, 0x00b394, 0x00000000); - nv_wr32(priv, 0x00b398, 0x00000000); - nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001); + nv_wr32(mpeg, 0x00b220, 0x00000044); + nv_wr32(mpeg, 0x00b300, 0x00801ec1); + nv_wr32(mpeg, 0x00b390, 0x00000000); + nv_wr32(mpeg, 0x00b394, 0x00000000); + nv_wr32(mpeg, 0x00b398, 0x00000000); + nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000001); - nv_wr32(priv, 0x00b100, 0xffffffff); - nv_wr32(priv, 0x00b140, 0xffffffff); + nv_wr32(mpeg, 0x00b100, 0xffffffff); + nv_wr32(mpeg, 0x00b140, 0xffffffff); - if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) { - nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200)); + if (!nv_wait(mpeg, 0x00b200, 0x00000001, 0x00000000)) { + nv_error(mpeg, "timeout 0x%08x\n", nv_rd32(mpeg, 0x00b200)); return -EBUSY; } -- GitLab From 11271f9f8ff3755bf9a413d157dc7cb7c36856b1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5351/7006] drm/nouveau/mspdec: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/falcon.h | 8 +++--- .../gpu/drm/nouveau/nvkm/engine/mspdec/g98.c | 24 +++++++---------- .../drm/nouveau/nvkm/engine/mspdec/gf100.c | 26 ++++++++----------- .../drm/nouveau/nvkm/engine/mspdec/gk104.c | 26 ++++++++----------- 4 files changed, 36 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index 2a27646ed770f..7532cd785c883 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -59,12 +59,12 @@ struct nvkm_falcon { #define nvkm_falcon_destroy(p) \ nvkm_engine_destroy(&(p)->engine) #define nvkm_falcon_init(p) ({ \ - struct nvkm_falcon *falcon = (p); \ - _nvkm_falcon_init(nv_object(falcon)); \ + struct nvkm_falcon *_falcon = (p); \ + _nvkm_falcon_init(nv_object(_falcon)); \ }) #define nvkm_falcon_fini(p,s) ({ \ - struct nvkm_falcon *falcon = (p); \ - _nvkm_falcon_fini(nv_object(falcon), (s)); \ + struct nvkm_falcon *_falcon = (p); \ + _nvkm_falcon_fini(nv_object(_falcon), (s)); \ }) int nvkm_falcon_create_(struct nvkm_object *, struct nvkm_object *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index 2174577793a41..55ffb3f1f36ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -24,10 +24,6 @@ #include #include -struct g98_mspdec_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSPDEC object classes ******************************************************************************/ @@ -63,15 +59,15 @@ g98_mspdec_cclass = { static int g98_mspdec_init(struct nvkm_object *object) { - struct g98_mspdec_priv *priv = (void *)object; + struct nvkm_falcon *mspdec = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(mspdec); if (ret) return ret; - nv_wr32(priv, 0x085010, 0x0000ffd2); - nv_wr32(priv, 0x08501c, 0x0000fff2); + nv_wr32(mspdec, 0x085010, 0x0000ffd2); + nv_wr32(mspdec, 0x08501c, 0x0000fff2); return 0; } @@ -80,18 +76,18 @@ g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g98_mspdec_priv *priv; + struct nvkm_falcon *mspdec; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &priv); - *pobject = nv_object(priv); + "PMSPDEC", "mspdec", &mspdec); + *pobject = nv_object(mspdec); if (ret) return ret; - nv_subdev(priv)->unit = 0x01020000; - nv_engine(priv)->cclass = &g98_mspdec_cclass; - nv_engine(priv)->sclass = g98_mspdec_sclass; + nv_subdev(mspdec)->unit = 0x01020000; + nv_engine(mspdec)->cclass = &g98_mspdec_cclass; + nv_engine(mspdec)->sclass = g98_mspdec_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index c814a5f65eb0f..7c5d01dcf92ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -24,10 +24,6 @@ #include #include -struct gf100_mspdec_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSPDEC object classes ******************************************************************************/ @@ -62,15 +58,15 @@ gf100_mspdec_cclass = { static int gf100_mspdec_init(struct nvkm_object *object) { - struct gf100_mspdec_priv *priv = (void *)object; + struct nvkm_falcon *mspdec = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(mspdec); if (ret) return ret; - nv_wr32(priv, 0x085010, 0x0000fff2); - nv_wr32(priv, 0x08501c, 0x0000fff2); + nv_wr32(mspdec, 0x085010, 0x0000fff2); + nv_wr32(mspdec, 0x08501c, 0x0000fff2); return 0; } @@ -79,19 +75,19 @@ gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_mspdec_priv *priv; + struct nvkm_falcon *mspdec; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &priv); - *pobject = nv_object(priv); + "PMSPDEC", "mspdec", &mspdec); + *pobject = nv_object(mspdec); if (ret) return ret; - nv_subdev(priv)->unit = 0x00020000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gf100_mspdec_cclass; - nv_engine(priv)->sclass = gf100_mspdec_sclass; + nv_subdev(mspdec)->unit = 0x00020000; + nv_subdev(mspdec)->intr = nvkm_falcon_intr; + nv_engine(mspdec)->cclass = &gf100_mspdec_cclass; + nv_engine(mspdec)->sclass = gf100_mspdec_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index 979920650dbd5..60755185e88e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -24,10 +24,6 @@ #include #include -struct gk104_mspdec_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSPDEC object classes ******************************************************************************/ @@ -62,15 +58,15 @@ gk104_mspdec_cclass = { static int gk104_mspdec_init(struct nvkm_object *object) { - struct gk104_mspdec_priv *priv = (void *)object; + struct nvkm_falcon *falcon = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(falcon); if (ret) return ret; - nv_wr32(priv, 0x085010, 0x0000fff2); - nv_wr32(priv, 0x08501c, 0x0000fff2); + nv_wr32(falcon, 0x085010, 0x0000fff2); + nv_wr32(falcon, 0x08501c, 0x0000fff2); return 0; } @@ -79,19 +75,19 @@ gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_mspdec_priv *priv; + struct nvkm_falcon *falcon; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &priv); - *pobject = nv_object(priv); + "PMSPDEC", "mspdec", &falcon); + *pobject = nv_object(falcon); if (ret) return ret; - nv_subdev(priv)->unit = 0x00020000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gk104_mspdec_cclass; - nv_engine(priv)->sclass = gk104_mspdec_sclass; + nv_subdev(falcon)->unit = 0x00020000; + nv_subdev(falcon)->intr = nvkm_falcon_intr; + nv_engine(falcon)->cclass = &gk104_mspdec_cclass; + nv_engine(falcon)->sclass = gk104_mspdec_sclass; return 0; } -- GitLab From fd507a53abda54697bcae2f60cfaf41932634d68 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5352/7006] drm/nouveau/msppp: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/msppp/g98.c | 24 +++++++---------- .../gpu/drm/nouveau/nvkm/engine/msppp/gf100.c | 26 ++++++++----------- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index 7a602a2dec948..04a4d52ff7efa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -24,10 +24,6 @@ #include #include -struct g98_msppp_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSPPP object classes ******************************************************************************/ @@ -63,15 +59,15 @@ g98_msppp_cclass = { static int g98_msppp_init(struct nvkm_object *object) { - struct g98_msppp_priv *priv = (void *)object; + struct nvkm_falcon *msppp = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(msppp); if (ret) return ret; - nv_wr32(priv, 0x086010, 0x0000ffd2); - nv_wr32(priv, 0x08601c, 0x0000fff2); + nv_wr32(msppp, 0x086010, 0x0000ffd2); + nv_wr32(msppp, 0x08601c, 0x0000fff2); return 0; } @@ -80,18 +76,18 @@ g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g98_msppp_priv *priv; + struct nvkm_falcon *msppp; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true, - "PMSPPP", "msppp", &priv); - *pobject = nv_object(priv); + "PMSPPP", "msppp", &msppp); + *pobject = nv_object(msppp); if (ret) return ret; - nv_subdev(priv)->unit = 0x00400002; - nv_engine(priv)->cclass = &g98_msppp_cclass; - nv_engine(priv)->sclass = g98_msppp_sclass; + nv_subdev(msppp)->unit = 0x00400002; + nv_engine(msppp)->cclass = &g98_msppp_cclass; + nv_engine(msppp)->sclass = g98_msppp_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index 6047baee1f752..5e1fe3b1a1966 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -24,10 +24,6 @@ #include #include -struct gf100_msppp_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSPPP object classes ******************************************************************************/ @@ -62,15 +58,15 @@ gf100_msppp_cclass = { static int gf100_msppp_init(struct nvkm_object *object) { - struct gf100_msppp_priv *priv = (void *)object; + struct nvkm_falcon *msppp = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(msppp); if (ret) return ret; - nv_wr32(priv, 0x086010, 0x0000fff2); - nv_wr32(priv, 0x08601c, 0x0000fff2); + nv_wr32(msppp, 0x086010, 0x0000fff2); + nv_wr32(msppp, 0x08601c, 0x0000fff2); return 0; } @@ -79,19 +75,19 @@ gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_msppp_priv *priv; + struct nvkm_falcon *msppp; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true, - "PMSPPP", "msppp", &priv); - *pobject = nv_object(priv); + "PMSPPP", "msppp", &msppp); + *pobject = nv_object(msppp); if (ret) return ret; - nv_subdev(priv)->unit = 0x00000002; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gf100_msppp_cclass; - nv_engine(priv)->sclass = gf100_msppp_sclass; + nv_subdev(msppp)->unit = 0x00000002; + nv_subdev(msppp)->intr = nvkm_falcon_intr; + nv_engine(msppp)->cclass = &gf100_msppp_cclass; + nv_engine(msppp)->sclass = gf100_msppp_sclass; return 0; } -- GitLab From 74137ffcd1dfd6537bbfdd1d1149942412280e9e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5353/7006] drm/nouveau/msvld: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/msvld/g98.c | 24 +++++++---------- .../gpu/drm/nouveau/nvkm/engine/msvld/gf100.c | 26 ++++++++----------- .../gpu/drm/nouveau/nvkm/engine/msvld/gk104.c | 26 ++++++++----------- 3 files changed, 32 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index c8a6b4ef52a1a..055bc2141f6bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -24,10 +24,6 @@ #include #include -struct g98_msvld_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSVLD object classes ******************************************************************************/ @@ -64,15 +60,15 @@ g98_msvld_cclass = { static int g98_msvld_init(struct nvkm_object *object) { - struct g98_msvld_priv *priv = (void *)object; + struct nvkm_falcon *msvld = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(msvld); if (ret) return ret; - nv_wr32(priv, 0x084010, 0x0000ffd2); - nv_wr32(priv, 0x08401c, 0x0000fff2); + nv_wr32(msvld, 0x084010, 0x0000ffd2); + nv_wr32(msvld, 0x08401c, 0x0000fff2); return 0; } @@ -81,18 +77,18 @@ g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g98_msvld_priv *priv; + struct nvkm_falcon *msvld; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &priv); - *pobject = nv_object(priv); + "PMSVLD", "msvld", &msvld); + *pobject = nv_object(msvld); if (ret) return ret; - nv_subdev(priv)->unit = 0x04008000; - nv_engine(priv)->cclass = &g98_msvld_cclass; - nv_engine(priv)->sclass = g98_msvld_sclass; + nv_subdev(msvld)->unit = 0x04008000; + nv_engine(msvld)->cclass = &g98_msvld_cclass; + nv_engine(msvld)->sclass = g98_msvld_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index b8d1e0f521ef8..0730198daea79 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -24,10 +24,6 @@ #include #include -struct gf100_msvld_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSVLD object classes ******************************************************************************/ @@ -62,15 +58,15 @@ gf100_msvld_cclass = { static int gf100_msvld_init(struct nvkm_object *object) { - struct gf100_msvld_priv *priv = (void *)object; + struct nvkm_falcon *msvld = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(msvld); if (ret) return ret; - nv_wr32(priv, 0x084010, 0x0000fff2); - nv_wr32(priv, 0x08401c, 0x0000fff2); + nv_wr32(msvld, 0x084010, 0x0000fff2); + nv_wr32(msvld, 0x08401c, 0x0000fff2); return 0; } @@ -79,19 +75,19 @@ gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_msvld_priv *priv; + struct nvkm_falcon *msvld; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &priv); - *pobject = nv_object(priv); + "PMSVLD", "msvld", &msvld); + *pobject = nv_object(msvld); if (ret) return ret; - nv_subdev(priv)->unit = 0x00008000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gf100_msvld_cclass; - nv_engine(priv)->sclass = gf100_msvld_sclass; + nv_subdev(msvld)->unit = 0x00008000; + nv_subdev(msvld)->intr = nvkm_falcon_intr; + nv_engine(msvld)->cclass = &gf100_msvld_cclass; + nv_engine(msvld)->sclass = gf100_msvld_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index a0b0927834df3..e19ebfdaae6a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -24,10 +24,6 @@ #include #include -struct gk104_msvld_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * MSVLD object classes ******************************************************************************/ @@ -62,15 +58,15 @@ gk104_msvld_cclass = { static int gk104_msvld_init(struct nvkm_object *object) { - struct gk104_msvld_priv *priv = (void *)object; + struct nvkm_falcon *msvld = (void *)object; int ret; - ret = nvkm_falcon_init(&priv->base); + ret = nvkm_falcon_init(msvld); if (ret) return ret; - nv_wr32(priv, 0x084010, 0x0000fff2); - nv_wr32(priv, 0x08401c, 0x0000fff2); + nv_wr32(msvld, 0x084010, 0x0000fff2); + nv_wr32(msvld, 0x08401c, 0x0000fff2); return 0; } @@ -79,19 +75,19 @@ gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gk104_msvld_priv *priv; + struct nvkm_falcon *msvld; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &priv); - *pobject = nv_object(priv); + "PMSVLD", "msvld", &msvld); + *pobject = nv_object(msvld); if (ret) return ret; - nv_subdev(priv)->unit = 0x00008000; - nv_subdev(priv)->intr = nvkm_falcon_intr; - nv_engine(priv)->cclass = &gk104_msvld_cclass; - nv_engine(priv)->sclass = gk104_msvld_sclass; + nv_subdev(msvld)->unit = 0x00008000; + nv_subdev(msvld)->intr = nvkm_falcon_intr; + nv_engine(msvld)->cclass = &gk104_msvld_cclass; + nv_engine(msvld)->sclass = gk104_msvld_sclass; return 0; } -- GitLab From 8c1aeaa13954585e8482866457abacb5c094db35 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5354/7006] drm/nouveau/pm: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 151 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 67 ++++---- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.h | 4 - .../gpu/drm/nouveau/nvkm/engine/pm/gk110.c | 10 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 43 +++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h | 2 +- 7 files changed, 135 insertions(+), 144 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index c4c704bc10c63..f13f8e6fc017c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -5,7 +5,7 @@ struct nvkm_perfdom; struct nvkm_perfctr; struct nvkm_pm { - struct nvkm_engine base; + struct nvkm_engine engine; struct nvkm_perfctx *context; void *profile_data; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 8741201d4236e..6803ad9ebe6f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -31,12 +31,12 @@ #include static u8 -nvkm_pm_count_perfdom(struct nvkm_pm *ppm) +nvkm_pm_count_perfdom(struct nvkm_pm *pm) { struct nvkm_perfdom *dom; u8 domain_nr = 0; - list_for_each_entry(dom, &ppm->domains, head) + list_for_each_entry(dom, &pm->domains, head) domain_nr++; return domain_nr; } @@ -57,12 +57,12 @@ nvkm_perfdom_count_perfsig(struct nvkm_perfdom *dom) } static struct nvkm_perfdom * -nvkm_perfdom_find(struct nvkm_pm *ppm, int di) +nvkm_perfdom_find(struct nvkm_pm *pm, int di) { struct nvkm_perfdom *dom; int tmp = 0; - list_for_each_entry(dom, &ppm->domains, head) { + list_for_each_entry(dom, &pm->domains, head) { if (tmp++ == di) return dom; } @@ -70,13 +70,12 @@ nvkm_perfdom_find(struct nvkm_pm *ppm, int di) } struct nvkm_perfsig * -nvkm_perfsig_find(struct nvkm_pm *ppm, uint8_t di, uint8_t si, - struct nvkm_perfdom **pdom) +nvkm_perfsig_find(struct nvkm_pm *pm, u8 di, u8 si, struct nvkm_perfdom **pdom) { struct nvkm_perfdom *dom = *pdom; if (dom == NULL) { - dom = nvkm_perfdom_find(ppm, di); + dom = nvkm_perfdom_find(pm, di); if (dom == NULL) return NULL; *pdom = dom; @@ -100,7 +99,7 @@ nvkm_perfsig_count_perfsrc(struct nvkm_perfsig *sig) } static struct nvkm_perfsrc * -nvkm_perfsrc_find(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, int si) +nvkm_perfsrc_find(struct nvkm_pm *pm, struct nvkm_perfsig *sig, int si) { struct nvkm_perfsrc *src; bool found = false; @@ -115,7 +114,7 @@ nvkm_perfsrc_find(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, int si) } if (found) { - list_for_each_entry(src, &ppm->sources, head) { + list_for_each_entry(src, &pm->sources, head) { if (tmp++ == si) return src; } @@ -125,7 +124,7 @@ nvkm_perfsrc_find(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, int si) } static int -nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) +nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) { struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; @@ -135,12 +134,12 @@ nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) for (i = 0; i < 4; i++) { for (j = 0; j < 8 && ctr->source[i][j]; j++) { - sig = nvkm_perfsig_find(ppm, ctr->domain, + sig = nvkm_perfsig_find(pm, ctr->domain, ctr->signal[i], &dom); if (!sig) return -EINVAL; - src = nvkm_perfsrc_find(ppm, sig, ctr->source[i][j]); + src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]); if (!src) return -EINVAL; @@ -152,8 +151,8 @@ nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) value |= ((ctr->source[i][j] >> 32) << src->shift); /* enable the source */ - nv_mask(ppm, src->addr, mask, value); - nv_debug(ppm, "enabled source 0x%08x 0x%08x 0x%08x\n", + nv_mask(pm, src->addr, mask, value); + nv_debug(pm, "enabled source 0x%08x 0x%08x 0x%08x\n", src->addr, mask, value); } } @@ -161,7 +160,7 @@ nvkm_perfsrc_enable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) } static int -nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) +nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) { struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; @@ -171,12 +170,12 @@ nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) for (i = 0; i < 4; i++) { for (j = 0; j < 8 && ctr->source[i][j]; j++) { - sig = nvkm_perfsig_find(ppm, ctr->domain, + sig = nvkm_perfsig_find(pm, ctr->domain, ctr->signal[i], &dom); if (!sig) return -EINVAL; - src = nvkm_perfsrc_find(ppm, sig, ctr->source[i][j]); + src = nvkm_perfsrc_find(pm, sig, ctr->source[i][j]); if (!src) return -EINVAL; @@ -187,8 +186,8 @@ nvkm_perfsrc_disable(struct nvkm_pm *ppm, struct nvkm_perfctr *ctr) mask |= (src->mask << src->shift); /* disable the source */ - nv_mask(ppm, src->addr, mask, 0); - nv_debug(ppm, "disabled source 0x%08x 0x%08x\n", + nv_mask(pm, src->addr, mask, 0); + nv_debug(pm, "disabled source 0x%08x 0x%08x\n", src->addr, mask); } } @@ -204,7 +203,7 @@ nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) union { struct nvif_perfdom_init none; } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom = (void *)object; int ret, i; @@ -216,15 +215,15 @@ nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) for (i = 0; i < 4; i++) { if (dom->ctr[i]) { - dom->func->init(ppm, dom, dom->ctr[i]); + dom->func->init(pm, dom, dom->ctr[i]); /* enable sources */ - nvkm_perfsrc_enable(ppm, dom->ctr[i]); + nvkm_perfsrc_enable(pm, dom->ctr[i]); } } /* start next batch of counters for sampling */ - dom->func->next(ppm, dom); + dom->func->next(pm, dom); return 0; } @@ -234,7 +233,7 @@ nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size) union { struct nvif_perfdom_sample none; } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom; int ret; @@ -243,11 +242,11 @@ nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size) nv_ioctl(object, "perfdom sample\n"); } else return ret; - ppm->sequence++; + pm->sequence++; /* sample previous batch of counters */ - list_for_each_entry(dom, &ppm->domains, head) - dom->func->next(ppm, dom); + list_for_each_entry(dom, &pm->domains, head) + dom->func->next(pm, dom); return 0; } @@ -258,7 +257,7 @@ nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size) union { struct nvif_perfdom_read_v0 v0; } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom = (void *)object; int ret, i; @@ -270,7 +269,7 @@ nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size) for (i = 0; i < 4; i++) { if (dom->ctr[i]) - dom->func->read(ppm, dom, dom->ctr[i]); + dom->func->read(pm, dom, dom->ctr[i]); } if (!dom->clk) @@ -302,14 +301,14 @@ nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) static void nvkm_perfdom_dtor(struct nvkm_object *object) { - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom = (void *)object; int i; for (i = 0; i < 4; i++) { struct nvkm_perfctr *ctr = dom->ctr[i]; if (ctr) { - nvkm_perfsrc_disable(ppm, ctr); + nvkm_perfsrc_disable(pm, ctr); if (ctr->head.next) list_del(&ctr->head); } @@ -319,9 +318,9 @@ nvkm_perfdom_dtor(struct nvkm_object *object) } static int -nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, uint8_t domain, - struct nvkm_perfsig *signal[4], uint64_t source[4][8], - uint16_t logic_op, struct nvkm_perfctr **pctr) +nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, u8 domain, + struct nvkm_perfsig *signal[4], u64 source[4][8], + u16 logic_op, struct nvkm_perfctr **pctr) { struct nvkm_perfctr *ctr; int i, j; @@ -356,7 +355,7 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nvif_perfdom_v0 v0; } *args = data; - struct nvkm_pm *ppm = (void *)engine; + struct nvkm_pm *pm = (void *)engine; struct nvkm_perfdom *sdom = NULL; struct nvkm_perfctr *ctr[4] = {}; struct nvkm_perfdom *dom; @@ -375,7 +374,7 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, u64 src[4][8] = {}; for (s = 0; s < ARRAY_SIZE(args->v0.ctr[c].signal); s++) { - sig[s] = nvkm_perfsig_find(ppm, args->v0.domain, + sig[s] = nvkm_perfsig_find(pm, args->v0.domain, args->v0.ctr[c].signal[s], &sdom); if (args->v0.ctr[c].signal[s] && !sig[s]) @@ -383,7 +382,7 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (m = 0; m < 8; m++) { src[s][m] = args->v0.ctr[c].source[s][m]; - if (src[s][m] && !nvkm_perfsrc_find(ppm, sig[s], + if (src[s][m] && !nvkm_perfsrc_find(pm, sig[s], src[s][m])) return -EINVAL; } @@ -429,7 +428,7 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) union { struct nvif_perfmon_query_domain_v0 v0; } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom; u8 domain_nr; int di, ret; @@ -442,12 +441,12 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) } else return ret; - domain_nr = nvkm_pm_count_perfdom(ppm); + domain_nr = nvkm_pm_count_perfdom(pm); if (di >= (int)domain_nr) return -EINVAL; if (di >= 0) { - dom = nvkm_perfdom_find(ppm, di); + dom = nvkm_perfdom_find(pm, di); if (dom == NULL) return -EINVAL; @@ -476,7 +475,7 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) struct nvif_perfmon_query_signal_v0 v0; } *args = data; struct nvkm_device *device = nv_device(object); - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom; struct nvkm_perfsig *sig; const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); @@ -492,7 +491,7 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) } else return ret; - dom = nvkm_perfdom_find(ppm, args->v0.domain); + dom = nvkm_perfdom_find(pm, args->v0.domain); if (dom == NULL || si >= (int)dom->signal_nr) return -EINVAL; @@ -527,7 +526,7 @@ nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) union { struct nvif_perfmon_query_source_v0 v0; } *args = data; - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; @@ -544,7 +543,7 @@ nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) } else return ret; - sig = nvkm_perfsig_find(ppm, args->v0.domain, args->v0.signal, &dom); + sig = nvkm_perfsig_find(pm, args->v0.domain, args->v0.signal, &dom); if (!sig) return -EINVAL; @@ -553,7 +552,7 @@ nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) return -EINVAL; if (si >= 0) { - src = nvkm_perfsrc_find(ppm, sig, sig->source[si]); + src = nvkm_perfsrc_find(pm, sig, sig->source[si]); if (!src) return -EINVAL; @@ -631,14 +630,14 @@ nvkm_pm_sclass[] = { static void nvkm_perfctx_dtor(struct nvkm_object *object) { - struct nvkm_pm *ppm = (void *)object->engine; + struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfctx *ctx = (void *)object; - mutex_lock(&nv_subdev(ppm)->mutex); + mutex_lock(&nv_subdev(pm)->mutex); nvkm_engctx_destroy(&ctx->base); - if (ppm->context == ctx) - ppm->context = NULL; - mutex_unlock(&nv_subdev(ppm)->mutex); + if (pm->context == ctx) + pm->context = NULL; + mutex_unlock(&nv_subdev(pm)->mutex); } static int @@ -646,7 +645,7 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_pm *ppm = (void *)engine; + struct nvkm_pm *pm = (void *)engine; struct nvkm_perfctx *ctx; int ret; @@ -662,12 +661,12 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - mutex_lock(&nv_subdev(ppm)->mutex); - if (ppm->context == NULL) - ppm->context = ctx; - if (ctx != ppm->context) + mutex_lock(&nv_subdev(pm)->mutex); + if (pm->context == NULL) + pm->context = ctx; + if (ctx != pm->context) ret = -EBUSY; - mutex_unlock(&nv_subdev(ppm)->mutex); + mutex_unlock(&nv_subdev(pm)->mutex); return ret; } @@ -687,7 +686,7 @@ nvkm_pm_cclass = { * PPM engine/subdev functions ******************************************************************************/ int -nvkm_perfsrc_new(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, +nvkm_perfsrc_new(struct nvkm_pm *pm, struct nvkm_perfsig *sig, const struct nvkm_specsrc *spec) { const struct nvkm_specsrc *ssrc; @@ -708,7 +707,7 @@ nvkm_perfsrc_new(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, u8 source_id = 0; u32 len; - list_for_each_entry(src, &ppm->sources, head) { + list_for_each_entry(src, &pm->sources, head) { if (src->addr == ssrc->addr && src->shift == smux->shift) { found = true; @@ -730,12 +729,14 @@ nvkm_perfsrc_new(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, len = strlen(ssrc->name) + strlen(smux->name) + 2; src->name = kzalloc(len, GFP_KERNEL); - if (!src->name) + if (!src->name) { + kfree(src); return -ENOMEM; + } snprintf(src->name, len, "%s_%s", ssrc->name, smux->name); - list_add_tail(&src->head, &ppm->sources); + list_add_tail(&src->head, &pm->sources); } sig->source[source_nr++] = source_id + 1; @@ -748,7 +749,7 @@ nvkm_perfsrc_new(struct nvkm_pm *ppm, struct nvkm_perfsig *sig, } int -nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, +nvkm_perfdom_new(struct nvkm_pm *pm, const char *name, u32 mask, u32 base, u32 size_unit, u32 size_domain, const struct nvkm_specdom *spec) { @@ -778,7 +779,7 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, "%s/%02x", name, (int)(sdom - spec)); } - list_add_tail(&dom->head, &ppm->domains); + list_add_tail(&dom->head, &pm->domains); INIT_LIST_HEAD(&dom->list); dom->func = sdom->func; dom->addr = addr; @@ -789,7 +790,7 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, struct nvkm_perfsig *sig = &dom->signal[ssig->signal]; sig->name = ssig->name; - ret = nvkm_perfsrc_new(ppm, sig, ssig->source); + ret = nvkm_perfsrc_new(pm, sig, ssig->source); if (ret) return ret; ssig++; @@ -807,52 +808,52 @@ nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask, int _nvkm_pm_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_pm *ppm = (void *)object; - return nvkm_engine_fini(&ppm->base, suspend); + struct nvkm_pm *pm = (void *)object; + return nvkm_engine_fini(&pm->engine, suspend); } int _nvkm_pm_init(struct nvkm_object *object) { - struct nvkm_pm *ppm = (void *)object; - return nvkm_engine_init(&ppm->base); + struct nvkm_pm *pm = (void *)object; + return nvkm_engine_init(&pm->engine); } void _nvkm_pm_dtor(struct nvkm_object *object) { - struct nvkm_pm *ppm = (void *)object; + struct nvkm_pm *pm = (void *)object; struct nvkm_perfdom *dom, *next_dom; struct nvkm_perfsrc *src, *next_src; - list_for_each_entry_safe(dom, next_dom, &ppm->domains, head) { + list_for_each_entry_safe(dom, next_dom, &pm->domains, head) { list_del(&dom->head); kfree(dom); } - list_for_each_entry_safe(src, next_src, &ppm->sources, head) { + list_for_each_entry_safe(src, next_src, &pm->sources, head) { list_del(&src->head); kfree(src->name); kfree(src); } - nvkm_engine_destroy(&ppm->base); + nvkm_engine_destroy(&pm->engine); } int nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_pm *ppm; + struct nvkm_pm *pm; int ret; ret = nvkm_engine_create_(parent, engine, oclass, true, "PPM", "pm", length, pobject); - ppm = *pobject; + pm = *pobject; if (ret) return ret; - INIT_LIST_HEAD(&ppm->domains); - INIT_LIST_HEAD(&ppm->sources); + INIT_LIST_HEAD(&pm->domains); + INIT_LIST_HEAD(&pm->sources); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 887d2dfeaa3cf..cb3f52d2f24be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -125,10 +125,9 @@ gf100_pm_part[] = { }; static void -gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct gf100_pm_priv *priv = (void *)ppm; struct gf100_pm_cntr *cntr = (void *)ctr; u32 log = ctr->logic_op; u32 src = 0x00000000; @@ -137,34 +136,32 @@ gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, for (i = 0; i < 4; i++) src |= ctr->signal[i] << (i * 8); - nv_wr32(priv, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); - nv_wr32(priv, dom->addr + 0x100, 0x00000000); - nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); - nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); + nv_wr32(pm, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); + nv_wr32(pm, dom->addr + 0x100, 0x00000000); + nv_wr32(pm, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); + nv_wr32(pm, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); } static void -gf100_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +gf100_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct gf100_pm_priv *priv = (void *)ppm; struct gf100_pm_cntr *cntr = (void *)ctr; switch (cntr->base.slot) { - case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break; - case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break; - case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break; - case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break; + case 0: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x08c); break; + case 1: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x088); break; + case 2: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x080); break; + case 3: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x090); break; } - dom->clk = nv_rd32(priv, dom->addr + 0x070); + dom->clk = nv_rd32(pm, dom->addr + 0x070); } static void -gf100_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom) +gf100_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { - struct gf100_pm_priv *priv = (void *)ppm; - nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); - nv_wr32(priv, dom->addr + 0x0ec, 0x00000011); + nv_wr32(pm, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); + nv_wr32(pm, dom->addr + 0x0ec, 0x00000011); } const struct nvkm_funcdom @@ -177,10 +174,10 @@ gf100_perfctr_func = { int gf100_pm_fini(struct nvkm_object *object, bool suspend) { - struct gf100_pm_priv *priv = (void *)object; - nv_mask(priv, 0x000200, 0x10000000, 0x00000000); - nv_mask(priv, 0x000200, 0x10000000, 0x10000000); - return nvkm_pm_fini(&priv->base, suspend); + struct nvkm_pm *pm = (void *)object; + nv_mask(pm, 0x000200, 0x10000000, 0x00000000); + nv_mask(pm, 0x000200, 0x10000000, 0x10000000); + return nvkm_pm_fini(pm, suspend); } int @@ -189,43 +186,43 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct gf100_pm_oclass *mclass = (void *)oclass; - struct gf100_pm_priv *priv; + struct nvkm_pm *pm; u32 mask; int ret; - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_pm_create(parent, engine, oclass, &pm); + *pobject = nv_object(pm); if (ret) return ret; /* HUB */ - ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200, + ret = nvkm_perfdom_new(pm, "hub", 0, 0x1b0000, 0, 0x200, mclass->doms_hub); if (ret) return ret; /* GPC */ - mask = (1 << nv_rd32(priv, 0x022430)) - 1; - mask &= ~nv_rd32(priv, 0x022504); - mask &= ~nv_rd32(priv, 0x022584); + mask = (1 << nv_rd32(pm, 0x022430)) - 1; + mask &= ~nv_rd32(pm, 0x022504); + mask &= ~nv_rd32(pm, 0x022584); - ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000, + ret = nvkm_perfdom_new(pm, "gpc", mask, 0x180000, 0x1000, 0x200, mclass->doms_gpc); if (ret) return ret; /* PART */ - mask = (1 << nv_rd32(priv, 0x022438)) - 1; - mask &= ~nv_rd32(priv, 0x022548); - mask &= ~nv_rd32(priv, 0x0225c8); + mask = (1 << nv_rd32(pm, 0x022438)) - 1; + mask &= ~nv_rd32(pm, 0x022548); + mask &= ~nv_rd32(pm, 0x0225c8); - ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000, + ret = nvkm_perfdom_new(pm, "part", mask, 0x1a0000, 0x1000, 0x200, mclass->doms_part); if (ret) return ret; - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; + nv_engine(pm)->cclass = &nvkm_pm_cclass; + nv_engine(pm)->sclass = nvkm_pm_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index 3a3a901e59296..de61622218232 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -9,10 +9,6 @@ struct gf100_pm_oclass { const struct nvkm_specdom *doms_part; }; -struct gf100_pm_priv { - struct nvkm_pm base; -}; - int gf100_pm_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **pobject); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c index 8373cd87a7d6a..3177ba4d2f571 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c @@ -28,16 +28,16 @@ gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct gf100_pm_priv *priv; + struct nvkm_pm *pm; int ret; - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_pm_create(parent, engine, oclass, &pm); + *pobject = nv_object(pm); if (ret) return ret; - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; + nv_engine(pm)->cclass = &nvkm_pm_cclass; + nv_engine(pm)->sclass = nvkm_pm_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index 5a87f3a1b947d..a447eac24f3bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -24,10 +24,9 @@ #include "nv40.h" static void -nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +nv40_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct nv40_pm_priv *priv = (void *)ppm; struct nv40_pm_cntr *cntr = (void *)ctr; u32 log = ctr->logic_op; u32 src = 0x00000000; @@ -36,34 +35,32 @@ nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, for (i = 0; i < 4; i++) src |= ctr->signal[i] << (i * 8); - nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); - nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); - nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); + nv_wr32(pm, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); + nv_wr32(pm, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); + nv_wr32(pm, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); } static void -nv40_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom, +nv40_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { - struct nv40_pm_priv *priv = (void *)ppm; struct nv40_pm_cntr *cntr = (void *)ctr; switch (cntr->base.slot) { - case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break; - case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break; - case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break; - case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break; + case 0: cntr->base.ctr = nv_rd32(pm, 0x00a700 + dom->addr); break; + case 1: cntr->base.ctr = nv_rd32(pm, 0x00a6c0 + dom->addr); break; + case 2: cntr->base.ctr = nv_rd32(pm, 0x00a680 + dom->addr); break; + case 3: cntr->base.ctr = nv_rd32(pm, 0x00a740 + dom->addr); break; } - dom->clk = nv_rd32(priv, 0x00a600 + dom->addr); + dom->clk = nv_rd32(pm, 0x00a600 + dom->addr); } static void -nv40_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom) +nv40_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { - struct nv40_pm_priv *priv = (void *)ppm; - if (priv->sequence != ppm->sequence) { - nv_wr32(priv, 0x400084, 0x00000020); - priv->sequence = ppm->sequence; + if (pm->sequence != pm->sequence) { + nv_wr32(pm, 0x400084, 0x00000020); + pm->sequence = pm->sequence; } } @@ -100,20 +97,20 @@ nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv40_pm_oclass *mclass = (void *)oclass; - struct nv40_pm_priv *priv; + struct nv40_pm *pm; int ret; - ret = nvkm_pm_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_pm_create(parent, engine, oclass, &pm); + *pobject = nv_object(pm); if (ret) return ret; - ret = nvkm_perfdom_new(&priv->base, "pc", 0, 0, 0, 4, mclass->doms); + ret = nvkm_perfdom_new(&pm->base, "pc", 0, 0, 0, 4, mclass->doms); if (ret) return ret; - nv_engine(priv)->cclass = &nvkm_pm_cclass; - nv_engine(priv)->sclass = nvkm_pm_sclass; + nv_engine(pm)->cclass = &nvkm_pm_cclass; + nv_engine(pm)->sclass = nvkm_pm_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h index 2338e150420e7..08287527615cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h @@ -7,7 +7,7 @@ struct nv40_pm_oclass { const struct nvkm_specdom *doms; }; -struct nv40_pm_priv { +struct nv40_pm { struct nvkm_pm base; u32 sequence; }; -- GitLab From c0e297dc61f8d4453e07afbea1fa8d0e67cd4a34 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5355/7006] drm/nouveau/sec: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s | 6 +-- .../nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 48 +++++++++---------- 3 files changed, 27 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s index 06ee06071104a..66b147bd58ebb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s @@ -1,5 +1,5 @@ /* - * fuc microcode for g98 psec engine + * fuc microcode for g98 sec engine * Copyright (C) 2010 Marcin Kościelnicki * * This program is free software; you can redistribute it and/or modify @@ -17,7 +17,7 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -.section #g98_psec_data +.section #g98_sec_data ctx_dma: ctx_dma_query: .b32 0 @@ -94,7 +94,7 @@ sec_dtable: .align 0x100 -.section #g98_psec_code +.section #g98_sec_code // $r0 is always set to 0 in our code - this allows some space savings. clear b32 $r0 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h index 5d65c4fbb0879..eca62221f2993 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h @@ -1,4 +1,4 @@ -uint32_t g98_psec_data[] = { +uint32_t g98_sec_data[] = { /* 0x0000: ctx_dma */ /* 0x0000: ctx_dma_query */ 0x00000000, @@ -150,7 +150,7 @@ uint32_t g98_psec_data[] = { 0x00000000, }; -uint32_t g98_psec_code[] = { +uint32_t g98_sec_code[] = { 0x17f004bd, 0x0010fe35, 0xf10004fe, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index a598d6dbff46a..1de94ec18a787 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -29,10 +29,6 @@ #include #include -struct g98_sec_priv { - struct nvkm_falcon base; -}; - /******************************************************************************* * Crypt object classes ******************************************************************************/ @@ -78,33 +74,33 @@ g98_sec_intr(struct nvkm_subdev *subdev) struct nvkm_fifo *fifo = nvkm_fifo(subdev); struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; - struct g98_sec_priv *priv = (void *)subdev; - u32 disp = nv_rd32(priv, 0x08701c); - u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16); - u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff; - u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff; - u32 addr = nv_rd32(priv, 0x087040) >> 16; + struct nvkm_falcon *sec = (void *)subdev; + u32 disp = nv_rd32(sec, 0x08701c); + u32 stat = nv_rd32(sec, 0x087008) & disp & ~(disp >> 16); + u32 inst = nv_rd32(sec, 0x087050) & 0x3fffffff; + u32 ssta = nv_rd32(sec, 0x087040) & 0x0000ffff; + u32 addr = nv_rd32(sec, 0x087040) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_rd32(priv, 0x087044); + u32 data = nv_rd32(sec, 0x087044); int chid; engctx = nvkm_engctx_get(engine, inst); chid = fifo->chid(fifo, engctx); if (stat & 0x00000040) { - nv_error(priv, "DISPATCH_ERROR ["); + nv_error(sec, "DISPATCH_ERROR ["); nvkm_enum_print(g98_sec_isr_error_name, ssta); pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", chid, (u64)inst << 12, nvkm_client_name(engctx), subc, mthd, data); - nv_wr32(priv, 0x087004, 0x00000040); + nv_wr32(sec, 0x087004, 0x00000040); stat &= ~0x00000040; } if (stat) { - nv_error(priv, "unhandled intr 0x%08x\n", stat); - nv_wr32(priv, 0x087004, stat); + nv_error(sec, "unhandled intr 0x%08x\n", stat); + nv_wr32(sec, 0x087004, stat); } nvkm_engctx_put(engctx); @@ -115,23 +111,23 @@ g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct g98_sec_priv *priv; + struct nvkm_falcon *sec; int ret; ret = nvkm_falcon_create(parent, engine, oclass, 0x087000, true, - "PSEC", "sec", &priv); - *pobject = nv_object(priv); + "PSEC", "sec", &sec); + *pobject = nv_object(sec); if (ret) return ret; - nv_subdev(priv)->unit = 0x00004000; - nv_subdev(priv)->intr = g98_sec_intr; - nv_engine(priv)->cclass = &g98_sec_cclass; - nv_engine(priv)->sclass = g98_sec_sclass; - nv_falcon(priv)->code.data = g98_psec_code; - nv_falcon(priv)->code.size = sizeof(g98_psec_code); - nv_falcon(priv)->data.data = g98_psec_data; - nv_falcon(priv)->data.size = sizeof(g98_psec_data); + nv_subdev(sec)->unit = 0x00004000; + nv_subdev(sec)->intr = g98_sec_intr; + nv_engine(sec)->cclass = &g98_sec_cclass; + nv_engine(sec)->sclass = g98_sec_sclass; + nv_falcon(sec)->code.data = g98_sec_code; + nv_falcon(sec)->code.size = sizeof(g98_sec_code); + nv_falcon(sec)->data.data = g98_sec_data; + nv_falcon(sec)->data.size = sizeof(g98_sec_data); return 0; } -- GitLab From 226dcefe706ff8854bca1bb75ae7bfd2fe3296c5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5356/7006] drm/nouveau/sw: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/sw.h | 8 ++--- .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 20 ++++++------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 28 +++++++---------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c | 28 +++++++---------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 30 +++++++++---------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h | 4 --- 6 files changed, 49 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h index a529013c92ab5..c46e5595573b5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h @@ -25,17 +25,17 @@ struct nvkm_sw_chan { #include struct nvkm_sw { - struct nvkm_engine base; + struct nvkm_engine engine; }; #define nvkm_sw_create(p,e,c,d) \ nvkm_engine_create((p), (e), (c), true, "SW", "software", (d)) #define nvkm_sw_destroy(d) \ - nvkm_engine_destroy(&(d)->base) + nvkm_engine_destroy(&(d)->engine) #define nvkm_sw_init(d) \ - nvkm_engine_init(&(d)->base) + nvkm_engine_init(&(d)->engine) #define nvkm_sw_fini(d,s) \ - nvkm_engine_fini(&(d)->base, (s)) + nvkm_engine_fini(&(d)->engine, (s)) #define _nvkm_sw_dtor _nvkm_engine_dtor #define _nvkm_sw_init _nvkm_engine_init diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 533d5d8ed3634..b35b45931cbd8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -50,20 +50,20 @@ gf100_sw_mthd_mp_control(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine; + struct nvkm_sw *sw = (void *)nv_object(chan)->engine; u32 data = *(u32 *)args; switch (mthd) { case 0x600: - nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */ + nv_wr32(sw, 0x419e00, data); /* MP.PM_UNK000 */ break; case 0x644: if (data & ~0x1ffffe) return -EINVAL; - nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ + nv_wr32(sw, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ break; case 0x6ac: - nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */ + nv_wr32(sw, 0x419eac, data); /* MP.PM_UNK0AC */ break; default: return -EINVAL; @@ -99,14 +99,14 @@ gf100_sw_vblsem_release(struct nvkm_notify *notify) { struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); - struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_sw *sw = (void *)nv_object(chan)->engine; + struct nvkm_bar *bar = nvkm_bar(sw); - nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel); + nv_wr32(sw, 0x001718, 0x80000000 | chan->vblank.channel); bar->flush(bar); - nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset)); - nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset)); - nv_wr32(priv, 0x060014, chan->vblank.value); + nv_wr32(sw, 0x06000c, upper_32_bits(chan->vblank.offset)); + nv_wr32(sw, 0x060010, lower_32_bits(chan->vblank.offset)); + nv_wr32(sw, 0x060014, chan->vblank.value); return NVKM_NOTIFY_DROP; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index 897024421d363..f1bb1e6f35a1b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -24,14 +24,6 @@ #include #include -struct nv04_sw_priv { - struct nvkm_sw base; -}; - -struct nv04_sw_chan { - struct nvkm_sw_chan base; -}; - /******************************************************************************* * software object classes ******************************************************************************/ @@ -48,9 +40,9 @@ nv04_sw_set_ref(struct nvkm_object *object, u32 mthd, void *data, u32 size) static int nv04_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) { - struct nv04_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); + struct nvkm_sw_chan *chan = (void *)nv_engctx(object->parent); + if (chan->flip) + return chan->flip(chan->flip_data); return -EINVAL; } @@ -76,7 +68,7 @@ nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_sw_chan *chan; + struct nvkm_sw_chan *chan; int ret; ret = nvkm_sw_context_create(parent, engine, oclass, &chan); @@ -113,17 +105,17 @@ nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_sw_priv *priv; + struct nvkm_sw *sw; int ret; - ret = nvkm_sw_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_sw_create(parent, engine, oclass, &sw); + *pobject = nv_object(sw); if (ret) return ret; - nv_engine(priv)->cclass = &nv04_sw_cclass; - nv_engine(priv)->sclass = nv04_sw_sclass; - nv_subdev(priv)->intr = nv04_sw_intr; + nv_engine(sw)->cclass = &nv04_sw_cclass; + nv_engine(sw)->sclass = nv04_sw_sclass; + nv_subdev(sw)->intr = nv04_sw_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index c61153a3fb8ba..1288142437b76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -23,14 +23,6 @@ */ #include -struct nv10_sw_priv { - struct nvkm_sw base; -}; - -struct nv10_sw_chan { - struct nvkm_sw_chan base; -}; - /******************************************************************************* * software object classes ******************************************************************************/ @@ -38,9 +30,9 @@ struct nv10_sw_chan { static int nv10_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) { - struct nv10_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); + struct nvkm_sw_chan *chan = (void *)nv_engctx(object->parent); + if (chan->flip) + return chan->flip(chan->flip_data); return -EINVAL; } @@ -65,7 +57,7 @@ nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv10_sw_chan *chan; + struct nvkm_sw_chan *chan; int ret; ret = nvkm_sw_context_create(parent, engine, oclass, &chan); @@ -96,17 +88,17 @@ nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv10_sw_priv *priv; + struct nvkm_sw *sw; int ret; - ret = nvkm_sw_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_sw_create(parent, engine, oclass, &sw); + *pobject = nv_object(sw); if (ret) return ret; - nv_engine(priv)->cclass = &nv10_sw_cclass; - nv_engine(priv)->sclass = nv10_sw_sclass; - nv_subdev(priv)->intr = nv04_sw_intr; + nv_engine(sw)->cclass = &nv10_sw_cclass; + nv_engine(sw)->sclass = nv10_sw_sclass; + nv_subdev(sw)->intr = nv04_sw_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 0946280a54b01..af2c1afaae552 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -121,19 +121,19 @@ nv50_sw_vblsem_release(struct nvkm_notify *notify) { struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); - struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine; - struct nvkm_bar *bar = nvkm_bar(priv); + struct nvkm_sw *sw = (void *)nv_object(chan)->engine; + struct nvkm_bar *bar = nvkm_bar(sw); - nv_wr32(priv, 0x001704, chan->vblank.channel); - nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma); + nv_wr32(sw, 0x001704, chan->vblank.channel); + nv_wr32(sw, 0x001710, 0x80000000 | chan->vblank.ctxdma); bar->flush(bar); - if (nv_device(priv)->chipset == 0x50) { - nv_wr32(priv, 0x001570, chan->vblank.offset); - nv_wr32(priv, 0x001574, chan->vblank.value); + if (nv_device(sw)->chipset == 0x50) { + nv_wr32(sw, 0x001570, chan->vblank.offset); + nv_wr32(sw, 0x001574, chan->vblank.value); } else { - nv_wr32(priv, 0x060010, chan->vblank.offset); - nv_wr32(priv, 0x060014, chan->vblank.value); + nv_wr32(sw, 0x060010, chan->vblank.offset); + nv_wr32(sw, 0x060014, chan->vblank.value); } return NVKM_NOTIFY_DROP; @@ -205,17 +205,17 @@ nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv50_sw_oclass *pclass = (void *)oclass; - struct nv50_sw_priv *priv; + struct nvkm_sw *sw; int ret; - ret = nvkm_sw_create(parent, engine, oclass, &priv); - *pobject = nv_object(priv); + ret = nvkm_sw_create(parent, engine, oclass, &sw); + *pobject = nv_object(sw); if (ret) return ret; - nv_engine(priv)->cclass = pclass->cclass; - nv_engine(priv)->sclass = pclass->sclass; - nv_subdev(priv)->intr = nv04_sw_intr; + nv_engine(sw)->cclass = pclass->cclass; + nv_engine(sw)->sclass = pclass->sclass; + nv_subdev(sw)->intr = nv04_sw_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index d8adc11084671..1c9101bff8945 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -9,10 +9,6 @@ struct nv50_sw_oclass { struct nvkm_oclass *sclass; }; -struct nv50_sw_priv { - struct nvkm_sw base; -}; - int nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); -- GitLab From 8699745a2bc143eee429c556d631e8e5be5dc009 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5357/7006] drm/nouveau/vp: cosmetic changes This is purely preparation for upcoming commits, there should be no code changes here. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c index 45f4e186befc1..703ddcfb207b0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c @@ -62,20 +62,20 @@ g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_xtensa *priv; + struct nvkm_xtensa *vp; int ret; ret = nvkm_xtensa_create(parent, engine, oclass, 0xf000, true, - "PVP", "vp", &priv); - *pobject = nv_object(priv); + "PVP", "vp", &vp); + *pobject = nv_object(vp); if (ret) return ret; - nv_subdev(priv)->unit = 0x01020000; - nv_engine(priv)->cclass = &g84_vp_cclass; - nv_engine(priv)->sclass = g84_vp_sclass; - priv->fifo_val = 0x111; - priv->unkd28 = 0x9c544; + nv_subdev(vp)->unit = 0x01020000; + nv_engine(vp)->cclass = &g84_vp_cclass; + nv_engine(vp)->sclass = g84_vp_sclass; + vp->fifo_val = 0x111; + vp->unkd28 = 0x9c544; return 0; } -- GitLab From dd64694208d7c902ba7a5bcd2bf012c1087ba0f0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5358/7006] drm/nouveau/device: type-safe register accessor macros These require an explit struct nvkm_device pointer, unlike the previous macros which take a void *, and assume it's any old nvkm_subdev. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 4ae876096c7d1..167a0dd94fe28 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -147,6 +147,20 @@ struct nvkm_device { struct nvkm_device *nvkm_device_find(u64 name); int nvkm_device_list(u64 *name, int size); +/* privileged register interface accessor macros */ +#define nvkm_rd08(d,a) ioread8((d)->engine.subdev.mmio + (a)) +#define nvkm_rd16(d,a) ioread16_native((d)->engine.subdev.mmio + (a)) +#define nvkm_rd32(d,a) ioread32_native((d)->engine.subdev.mmio + (a)) +#define nvkm_wr08(d,a,v) iowrite8((v), (d)->engine.subdev.mmio + (a)) +#define nvkm_wr16(d,a,v) iowrite16_native((v), (d)->engine.subdev.mmio + (a)) +#define nvkm_wr32(d,a,v) iowrite32_native((v), (d)->engine.subdev.mmio + (a)) +#define nvkm_mask(d,a,m,v) ({ \ + struct nvkm_device *_device = (d); \ + u32 _addr = (a), _temp = nvkm_rd32(_device, _addr); \ + nvkm_wr32(_device, _addr, (_temp & ~(m)) | (v)); \ + _temp; \ +}) + struct nvkm_device *nv_device(void *obj); static inline bool -- GitLab From 94bab102233e30d08fcb33a424ec56520b22eb1b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5359/7006] drm/nouveau/core: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index b96cb2cca55e3..fd1a94c5bf385 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -64,9 +64,11 @@ _nvkm_subdev_init(struct nvkm_object *object) int nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) { + struct nvkm_device *device = subdev->device; + if (subdev->unit) { - nv_mask(subdev, 0x000200, subdev->unit, 0x00000000); - nv_mask(subdev, 0x000200, subdev->unit, subdev->unit); + nvkm_mask(device, 0x000200, subdev->unit, 0x00000000); + nvkm_mask(device, 0x000200, subdev->unit, subdev->unit); } return nvkm_object_fini(&subdev->object, suspend); -- GitLab From 9155c16214631e064d0d1edcd60a62347f823c80 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5360/7006] drm/nouveau/bar: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 9 ++++---- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 23 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 5f091d2c560b9..09e36b64d889d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -190,18 +190,19 @@ int gf100_bar_init(struct nvkm_object *object) { struct gf100_bar *bar = (void *)object; + struct nvkm_device *device = bar->base.subdev.device; int ret; ret = nvkm_bar_init(&bar->base); if (ret) return ret; - nv_mask(bar, 0x000200, 0x00000100, 0x00000000); - nv_mask(bar, 0x000200, 0x00000100, 0x00000100); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); - nv_wr32(bar, 0x001704, 0x80000000 | bar->bar[1].mem->addr >> 12); + nvkm_wr32(device, 0x001704, 0x80000000 | bar->bar[1].mem->addr >> 12); if (bar->bar[0].mem) - nv_wr32(bar, 0x001714, + nvkm_wr32(device, 0x001714, 0xc0000000 | bar->bar[0].mem->addr >> 12); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 07f6b2a7d3c4e..dcfb11895a61b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -81,9 +81,10 @@ static void nv50_bar_flush(struct nvkm_bar *obj) { struct nv50_bar *bar = container_of(obj, typeof(*bar), base); + struct nvkm_device *device = bar->base.subdev.device; unsigned long flags; spin_lock_irqsave(&bar->lock, flags); - nv_wr32(bar, 0x00330c, 0x00000001); + nvkm_wr32(device, 0x00330c, 0x00000001); if (!nv_wait(bar, 0x00330c, 0x00000002, 0x00000000)) nv_warn(bar, "flush timeout\n"); spin_unlock_irqrestore(&bar->lock, flags); @@ -93,9 +94,10 @@ void g84_bar_flush(struct nvkm_bar *obj) { struct nv50_bar *bar = container_of(obj, typeof(*bar), base); + struct nvkm_device *device = bar->base.subdev.device; unsigned long flags; spin_lock_irqsave(&bar->lock, flags); - nv_wr32(bar, 0x070000, 0x00000001); + nvkm_wr32(device, 0x070000, 0x00000001); if (!nv_wait(bar, 0x070000, 0x00000002, 0x00000000)) nv_warn(bar, "flush timeout\n"); spin_unlock_irqrestore(&bar->lock, flags); @@ -228,26 +230,27 @@ static int nv50_bar_init(struct nvkm_object *object) { struct nv50_bar *bar = (void *)object; + struct nvkm_device *device = bar->base.subdev.device; int ret, i; ret = nvkm_bar_init(&bar->base); if (ret) return ret; - nv_mask(bar, 0x000200, 0x00000100, 0x00000000); - nv_mask(bar, 0x000200, 0x00000100, 0x00000100); - nv_wr32(bar, 0x100c80, 0x00060001); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x100c80, 0x00060001); if (!nv_wait(bar, 0x100c80, 0x00000001, 0x00000000)) { nv_error(bar, "vm flush timeout\n"); return -EBUSY; } - nv_wr32(bar, 0x001704, 0x00000000 | bar->mem->addr >> 12); - nv_wr32(bar, 0x001704, 0x40000000 | bar->mem->addr >> 12); - nv_wr32(bar, 0x001708, 0x80000000 | bar->bar1->node->offset >> 4); - nv_wr32(bar, 0x00170c, 0x80000000 | bar->bar3->node->offset >> 4); + nvkm_wr32(device, 0x001704, 0x00000000 | bar->mem->addr >> 12); + nvkm_wr32(device, 0x001704, 0x40000000 | bar->mem->addr >> 12); + nvkm_wr32(device, 0x001708, 0x80000000 | bar->bar1->node->offset >> 4); + nvkm_wr32(device, 0x00170c, 0x80000000 | bar->bar3->node->offset >> 4); for (i = 0; i < 8; i++) - nv_wr32(bar, 0x001900 + (i * 4), 0x00000000); + nvkm_wr32(device, 0x001900 + (i * 4), 0x00000000); return 0; } -- GitLab From d8f266a353cb397aa792b59d5aa16ea09579f9ac Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5361/7006] drm/nouveau/bios: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 11 +++++--- .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 7 +++--- .../gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c | 2 +- .../nouveau/nvkm/subdev/bios/shadowramin.c | 25 +++++++++++-------- .../drm/nouveau/nvkm/subdev/bios/shadowrom.c | 23 +++++++++-------- 5 files changed, 38 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 045b7ddb4d665..64d7b482674d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -180,27 +180,30 @@ init_nvreg(struct nvbios_init *init, u32 reg) static u32 init_rd32(struct nvbios_init *init, u32 reg) { + struct nvkm_device *device = init->bios->subdev.device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) - return nv_rd32(init->subdev, reg); + return nvkm_rd32(device, reg); return 0x00000000; } static void init_wr32(struct nvbios_init *init, u32 reg, u32 val) { + struct nvkm_device *device = init->bios->subdev.device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) - nv_wr32(init->subdev, reg, val); + nvkm_wr32(device, reg, val); } static u32 init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val) { + struct nvkm_device *device = init->bios->subdev.device; reg = init_nvreg(init, reg); if (reg != ~0 && init_exec(init)) { - u32 tmp = nv_rd32(init->subdev, reg); - nv_wr32(init->subdev, reg, (tmp & ~mask) | val); + u32 tmp = nvkm_rd32(device, reg); + nvkm_wr32(device, reg, (tmp & ~mask) | val); return tmp; } return 0x00000000; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index ac48ccc5d2c43..d26d89abf7eb0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -221,6 +221,7 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) int nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) { + struct nvkm_device *device = bios->subdev.device; u8 ver, len; u32 reg = type; u16 data; @@ -360,9 +361,9 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) } if (!info->refclk) { - info->refclk = nv_device(bios)->crystal; + info->refclk = device->crystal; if (bios->version.chip == 0x51) { - u32 sel_clk = nv_rd32(bios, 0x680524); + u32 sel_clk = nvkm_rd32(device, 0x680524); if ((info->reg == 0x680508 && sel_clk & 0x20) || (info->reg == 0x680520 && sel_clk & 0x80)) { if (nv_rdvgac(bios, 0, 0x27) < 0xa3) @@ -392,7 +393,7 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) info->vco1.max_n = 0xff; info->vco1.min_m = 0x1; - if (nv_device(bios)->crystal == 13500) { + if (device->crystal == 13500) { /* nv05 does this, nv11 doesn't, nv10 unknown */ if (bios->version.chip < 0x11) info->vco1.min_m = 0x7; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c index a17b221119b23..35a808708126a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c @@ -29,7 +29,7 @@ static u8 nvbios_ramcfg_strap(struct nvkm_subdev *subdev) { - return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2; + return (nvkm_rd32(subdev->device, 0x101000) & 0x0000003c) >> 2; } u8 diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c index c2c31ba59868d..9d0e206aef5e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c @@ -30,10 +30,11 @@ struct priv { static u32 pramin_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { + struct nvkm_device *device = bios->subdev.device; u32 i; if (offset + length <= 0x00100000) { for (i = offset; i < offset + length; i += 4) - *(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i); + *(u32 *)&bios->data[i] = nvkm_rd32(device, 0x700000 + i); return length; } return 0; @@ -44,7 +45,8 @@ pramin_fini(void *data) { struct priv *priv = data; if (priv) { - nv_wr32(priv->bios, 0x001700, priv->bar0); + struct nvkm_device *device = priv->bios->subdev.device; + nvkm_wr32(device, 0x001700, priv->bar0); kfree(priv); } } @@ -52,19 +54,20 @@ pramin_fini(void *data) static void * pramin_init(struct nvkm_bios *bios, const char *name) { + struct nvkm_device *device = bios->subdev.device; struct priv *priv = NULL; u64 addr = 0; /* PRAMIN always potentially available prior to nv50 */ - if (nv_device(bios)->card_type < NV_50) + if (device->card_type < NV_50) return NULL; /* we can't get the bios image pointer without PDISP */ - if (nv_device(bios)->card_type >= GM100) - addr = nv_rd32(bios, 0x021c04); + if (device->card_type >= GM100) + addr = nvkm_rd32(device, 0x021c04); else - if (nv_device(bios)->card_type >= NV_C0) - addr = nv_rd32(bios, 0x022500); + if (device->card_type >= NV_C0) + addr = nvkm_rd32(device, 0x022500); if (addr & 0x00000001) { nv_debug(bios, "... display disabled\n"); return ERR_PTR(-ENODEV); @@ -74,7 +77,7 @@ pramin_init(struct nvkm_bios *bios, const char *name) * important as we don't want to be touching vram on an * uninitialised board */ - addr = nv_rd32(bios, 0x619f04); + addr = nvkm_rd32(device, 0x619f04); if (!(addr & 0x00000008)) { nv_debug(bios, "... not enabled\n"); return ERR_PTR(-ENODEV); @@ -87,7 +90,7 @@ pramin_init(struct nvkm_bios *bios, const char *name) /* some alternate method inherited from xf86-video-nv... */ addr = (addr & 0xffffff00) << 8; if (!addr) { - addr = (u64)nv_rd32(bios, 0x001700) << 16; + addr = (u64)nvkm_rd32(device, 0x001700) << 16; addr += 0xf0000; } @@ -98,8 +101,8 @@ pramin_init(struct nvkm_bios *bios, const char *name) } priv->bios = bios; - priv->bar0 = nv_rd32(bios, 0x001700); - nv_wr32(bios, 0x001700, addr >> 16); + priv->bar0 = nvkm_rd32(device, 0x001700); + nvkm_wr32(device, 0x001700, addr >> 16); return priv; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c index cd0b06fbc3c2e..be116f35c4bc5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c @@ -25,10 +25,11 @@ static u32 prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { + struct nvkm_device *device = data; u32 i; if (offset + length <= 0x00100000) { for (i = offset; i < offset + length; i += 4) - *(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i); + *(u32 *)&bios->data[i] = nvkm_rd32(device, 0x300000 + i); return length; } return 0; @@ -37,25 +38,25 @@ prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void prom_fini(void *data) { - struct nvkm_bios *bios = data; - if (nv_device(bios)->card_type < NV_50) - nv_mask(bios, 0x001850, 0x00000001, 0x00000001); + struct nvkm_device *device = data; + if (device->card_type < NV_50) + nvkm_mask(device, 0x001850, 0x00000001, 0x00000001); else - nv_mask(bios, 0x088050, 0x00000001, 0x00000001); + nvkm_mask(device, 0x088050, 0x00000001, 0x00000001); } static void * prom_init(struct nvkm_bios *bios, const char *name) { - if (nv_device(bios)->card_type < NV_50) { - if (nv_device(bios)->card_type == NV_40 && - nv_device(bios)->chipset >= 0x4c) + struct nvkm_device *device = bios->subdev.device; + if (device->card_type < NV_50) { + if (device->card_type == NV_40 && device->chipset >= 0x4c) return ERR_PTR(-ENODEV); - nv_mask(bios, 0x001850, 0x00000001, 0x00000000); + nvkm_mask(device, 0x001850, 0x00000001, 0x00000000); } else { - nv_mask(bios, 0x088050, 0x00000001, 0x00000000); + nvkm_mask(device, 0x088050, 0x00000001, 0x00000000); } - return bios; + return device; } const struct nvbios_source -- GitLab From 14caba447c9a22ceb0400e964f585e5ffff5f0b8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5362/7006] drm/nouveau/bus: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c | 13 +++++---- .../gpu/drm/nouveau/nvkm/subdev/bus/gf100.c | 18 +++++++----- .../gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h | 3 +- .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.c | 14 +++++---- .../gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 20 +++++++------ .../gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 29 ++++++++++--------- 6 files changed, 54 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c index ae924dda7b3d2..b23475bbf3ad9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c @@ -29,15 +29,16 @@ static int g94_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) { + struct nvkm_device *device = bus->subdev.device; int i; - nv_mask(bus, 0x001098, 0x00000008, 0x00000000); - nv_wr32(bus, 0x001304, 0x00000000); - nv_wr32(bus, 0x001318, 0x00000000); + nvkm_mask(device, 0x001098, 0x00000008, 0x00000000); + nvkm_wr32(device, 0x001304, 0x00000000); + nvkm_wr32(device, 0x001318, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(bus, 0x080000 + (i * 4), data[i]); - nv_mask(bus, 0x001098, 0x00000018, 0x00000018); - nv_wr32(bus, 0x00130c, 0x00000001); + nvkm_wr32(device, 0x080000 + (i * 4), data[i]); + nvkm_mask(device, 0x001098, 0x00000018, 0x00000018); + nvkm_wr32(device, 0x00130c, 0x00000001); return nv_wait(bus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c index d46ecd8e754fb..d7e92d049c84f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c @@ -28,11 +28,12 @@ static void gf100_bus_intr(struct nvkm_subdev *subdev) { struct nvkm_bus *bus = nvkm_bus(subdev); - u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); + struct nvkm_device *device = bus->subdev.device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x0000000e) { - u32 addr = nv_rd32(bus, 0x009084); - u32 data = nv_rd32(bus, 0x009088); + u32 addr = nvkm_rd32(device, 0x009084); + u32 data = nvkm_rd32(device, 0x009088); nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", (addr & 0x00000002) ? "write" : "read", data, @@ -41,14 +42,14 @@ gf100_bus_intr(struct nvkm_subdev *subdev) (stat & 0x00000004) ? "IBUS " : "", (stat & 0x00000008) ? "TIMEOUT " : ""); - nv_wr32(bus, 0x009084, 0x00000000); - nv_wr32(bus, 0x001100, (stat & 0x0000000e)); + nvkm_wr32(device, 0x009084, 0x00000000); + nvkm_wr32(device, 0x001100, (stat & 0x0000000e)); stat &= ~0x0000000e; } if (stat) { nv_error(bus, "unknown intr 0x%08x\n", stat); - nv_mask(bus, 0x001140, stat, 0x00000000); + nvkm_mask(device, 0x001140, stat, 0x00000000); } } @@ -56,14 +57,15 @@ static int gf100_bus_init(struct nvkm_object *object) { struct nvkm_bus *bus = (void *)object; + struct nvkm_device *device = bus->subdev.device; int ret; ret = nvkm_bus_init(bus); if (ret) return ret; - nv_wr32(bus, 0x001100, 0xffffffff); - nv_wr32(bus, 0x001140, 0x0000000e); + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x0000000e); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h index 4ce54d4f2e731..6f498cd4b82f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h @@ -85,8 +85,9 @@ hwsq_exec(struct hwsq *ram, bool exec) static inline u32 hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg) { + struct nvkm_device *device = ram->subdev->device; if (reg->sequence != ram->sequence) - reg->data = nv_rd32(ram->subdev, reg->addr); + reg->data = nvkm_rd32(device, reg->addr); return reg->data; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c index 2066d38d12ded..1f6873a76e76c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c @@ -28,12 +28,13 @@ static void nv04_bus_intr(struct nvkm_subdev *subdev) { struct nvkm_bus *bus = nvkm_bus(subdev); - u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); + struct nvkm_device *device = bus->subdev.device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x00000001) { nv_error(bus, "BUS ERROR\n"); stat &= ~0x00000001; - nv_wr32(bus, 0x001100, 0x00000001); + nvkm_wr32(device, 0x001100, 0x00000001); } if (stat & 0x00000110) { @@ -41,12 +42,12 @@ nv04_bus_intr(struct nvkm_subdev *subdev) if (subdev && subdev->intr) subdev->intr(subdev); stat &= ~0x00000110; - nv_wr32(bus, 0x001100, 0x00000110); + nvkm_wr32(device, 0x001100, 0x00000110); } if (stat) { nv_error(bus, "unknown intr 0x%08x\n", stat); - nv_mask(bus, 0x001140, stat, 0x00000000); + nvkm_mask(device, 0x001140, stat, 0x00000000); } } @@ -54,9 +55,10 @@ static int nv04_bus_init(struct nvkm_object *object) { struct nvkm_bus *bus = (void *)object; + struct nvkm_device *device = bus->subdev.device; - nv_wr32(bus, 0x001100, 0xffffffff); - nv_wr32(bus, 0x001140, 0x00000111); + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x00000111); return nvkm_bus_init(bus); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c index 7565d2f047e7d..e8ee4cd7c025e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c @@ -28,8 +28,9 @@ static void nv31_bus_intr(struct nvkm_subdev *subdev) { struct nvkm_bus *bus = nvkm_bus(subdev); - u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); - u32 gpio = nv_rd32(bus, 0x001104) & nv_rd32(bus, 0x001144); + struct nvkm_device *device = bus->subdev.device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); + u32 gpio = nvkm_rd32(device, 0x001104) & nvkm_rd32(device, 0x001144); if (gpio) { subdev = nvkm_subdev(bus, NVDEV_SUBDEV_GPIO); @@ -38,15 +39,15 @@ nv31_bus_intr(struct nvkm_subdev *subdev) } if (stat & 0x00000008) { /* NV41- */ - u32 addr = nv_rd32(bus, 0x009084); - u32 data = nv_rd32(bus, 0x009088); + u32 addr = nvkm_rd32(device, 0x009084); + u32 data = nvkm_rd32(device, 0x009088); nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", (addr & 0x00000002) ? "write" : "read", data, (addr & 0x00fffffc)); stat &= ~0x00000008; - nv_wr32(bus, 0x001100, 0x00000008); + nvkm_wr32(device, 0x001100, 0x00000008); } if (stat & 0x00070000) { @@ -54,12 +55,12 @@ nv31_bus_intr(struct nvkm_subdev *subdev) if (subdev && subdev->intr) subdev->intr(subdev); stat &= ~0x00070000; - nv_wr32(bus, 0x001100, 0x00070000); + nvkm_wr32(device, 0x001100, 0x00070000); } if (stat) { nv_error(bus, "unknown intr 0x%08x\n", stat); - nv_mask(bus, 0x001140, stat, 0x00000000); + nvkm_mask(device, 0x001140, stat, 0x00000000); } } @@ -67,14 +68,15 @@ static int nv31_bus_init(struct nvkm_object *object) { struct nvkm_bus *bus = (void *)object; + struct nvkm_device *device = bus->subdev.device; int ret; ret = nvkm_bus_init(bus); if (ret) return ret; - nv_wr32(bus, 0x001100, 0xffffffff); - nv_wr32(bus, 0x001140, 0x00070008); + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x00070008); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index f6a55b831ea2d..69d55b435c6c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -29,14 +29,15 @@ static int nv50_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) { + struct nvkm_device *device = bus->subdev.device; int i; - nv_mask(bus, 0x001098, 0x00000008, 0x00000000); - nv_wr32(bus, 0x001304, 0x00000000); + nvkm_mask(device, 0x001098, 0x00000008, 0x00000000); + nvkm_wr32(device, 0x001304, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(bus, 0x001400 + (i * 4), data[i]); - nv_mask(bus, 0x001098, 0x00000018, 0x00000018); - nv_wr32(bus, 0x00130c, 0x00000003); + nvkm_wr32(device, 0x001400 + (i * 4), data[i]); + nvkm_mask(device, 0x001098, 0x00000018, 0x00000018); + nvkm_wr32(device, 0x00130c, 0x00000003); return nv_wait(bus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; } @@ -45,18 +46,19 @@ void nv50_bus_intr(struct nvkm_subdev *subdev) { struct nvkm_bus *bus = nvkm_bus(subdev); - u32 stat = nv_rd32(bus, 0x001100) & nv_rd32(bus, 0x001140); + struct nvkm_device *device = bus->subdev.device; + u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x00000008) { - u32 addr = nv_rd32(bus, 0x009084); - u32 data = nv_rd32(bus, 0x009088); + u32 addr = nvkm_rd32(device, 0x009084); + u32 data = nvkm_rd32(device, 0x009088); nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", (addr & 0x00000002) ? "write" : "read", data, (addr & 0x00fffffc)); stat &= ~0x00000008; - nv_wr32(bus, 0x001100, 0x00000008); + nvkm_wr32(device, 0x001100, 0x00000008); } if (stat & 0x00010000) { @@ -64,12 +66,12 @@ nv50_bus_intr(struct nvkm_subdev *subdev) if (subdev && subdev->intr) subdev->intr(subdev); stat &= ~0x00010000; - nv_wr32(bus, 0x001100, 0x00010000); + nvkm_wr32(device, 0x001100, 0x00010000); } if (stat) { nv_error(bus, "unknown intr 0x%08x\n", stat); - nv_mask(bus, 0x001140, stat, 0); + nvkm_mask(device, 0x001140, stat, 0); } } @@ -77,14 +79,15 @@ int nv50_bus_init(struct nvkm_object *object) { struct nvkm_bus *bus = (void *)object; + struct nvkm_device *device = bus->subdev.device; int ret; ret = nvkm_bus_init(bus); if (ret) return ret; - nv_wr32(bus, 0x001100, 0xffffffff); - nv_wr32(bus, 0x001140, 0x00010008); + nvkm_wr32(device, 0x001100, 0xffffffff); + nvkm_wr32(device, 0x001140, 0x00010008); return 0; } -- GitLab From 822ad79fa40070fc36cae2ad929ab0c409919080 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:08 +1000 Subject: [PATCH 5363/7006] drm/nouveau/clk: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 51 ++++++----- .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 66 ++++++++------ .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 78 ++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 89 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 54 +++++------ .../gpu/drm/nouveau/nvkm/subdev/clk/nv40.c | 24 ++--- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 53 ++++++----- 7 files changed, 234 insertions(+), 181 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 99cfa09b21598..f7aac3702c234 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -47,7 +47,8 @@ static u32 read_div(struct gf100_clk *, int, u32, u32); static u32 read_vco(struct gf100_clk *clk, u32 dsrc) { - u32 ssrc = nv_rd32(clk, dsrc); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc); if (!(ssrc & 0x00000100)) return clk->base.read(&clk->base, nv_clk_src_sppll0); return clk->base.read(&clk->base, nv_clk_src_sppll1); @@ -56,8 +57,9 @@ read_vco(struct gf100_clk *clk, u32 dsrc) static u32 read_pll(struct gf100_clk *clk, u32 pll) { - u32 ctrl = nv_rd32(clk, pll + 0x00); - u32 coef = nv_rd32(clk, pll + 0x04); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, pll + 0x00); + u32 coef = nvkm_rd32(device, pll + 0x04); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -69,7 +71,7 @@ read_pll(struct gf100_clk *clk, u32 pll) switch (pll) { case 0x00e800: case 0x00e820: - sclk = nv_device(clk)->crystal; + sclk = device->crystal; P = 1; break; case 0x132000: @@ -94,13 +96,14 @@ read_pll(struct gf100_clk *clk, u32 pll) static u32 read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(clk, dsrc + (doff * 4)); - u32 sctl = nv_rd32(clk, dctl + (doff * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4)); + u32 sctl = nvkm_rd32(device, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(clk)->crystal; + return device->crystal; return 108000; case 2: return 100000; @@ -120,8 +123,9 @@ read_div(struct gf100_clk *clk, int doff, u32 dsrc, u32 dctl) static u32 read_clk(struct gf100_clk *clk, int idx) { - u32 sctl = nv_rd32(clk, 0x137250 + (idx * 4)); - u32 ssel = nv_rd32(clk, 0x137100); + struct nvkm_device *device = clk->base.subdev.device; + u32 sctl = nvkm_rd32(device, 0x137250 + (idx * 4)); + u32 ssel = nvkm_rd32(device, 0x137100); u32 sclk, sdiv; if (ssel & (1 << idx)) { @@ -145,7 +149,7 @@ static int gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gf100_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = nv_device(clk); + struct nvkm_device *device = clk->base.subdev.device; switch (src) { case nv_clk_src_crystal: @@ -166,7 +170,7 @@ gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case nv_clk_src_mdiv: return read_div(clk, 0, 0x137300, 0x137310); case nv_clk_src_mem: - if (nv_rd32(clk, 0x1373f0) & 0x00000002) + if (nvkm_rd32(device, 0x1373f0) & 0x00000002) return clk->base.read(&clk->base, nv_clk_src_mpll); return clk->base.read(&clk->base, nv_clk_src_mdiv); @@ -329,16 +333,18 @@ static void gf100_clk_prog_0(struct gf100_clk *clk, int idx) { struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (idx < 7 && !info->ssel) { - nv_mask(clk, 0x1371d0 + (idx * 0x04), 0x80003f3f, info->ddiv); - nv_wr32(clk, 0x137160 + (idx * 0x04), info->dsrc); + nvkm_mask(device, 0x1371d0 + (idx * 0x04), 0x80003f3f, info->ddiv); + nvkm_wr32(device, 0x137160 + (idx * 0x04), info->dsrc); } } static void gf100_clk_prog_1(struct gf100_clk *clk, int idx) { - nv_mask(clk, 0x137100, (1 << idx), 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137100, (1 << idx), 0x00000000); nv_wait(clk, 0x137100, (1 << idx), 0x00000000); } @@ -346,15 +352,16 @@ static void gf100_clk_prog_2(struct gf100_clk *clk, int idx) { struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; const u32 addr = 0x137000 + (idx * 0x20); if (idx <= 7) { - nv_mask(clk, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(clk, addr + 0x00, 0x00000001, 0x00000000); + nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000000); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000000); if (info->coef) { - nv_wr32(clk, addr + 0x04, info->coef); - nv_mask(clk, addr + 0x00, 0x00000001, 0x00000001); + nvkm_wr32(device, addr + 0x04, info->coef); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); nv_wait(clk, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(clk, addr + 0x00, 0x00020004, 0x00000004); + nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); } } } @@ -363,8 +370,9 @@ static void gf100_clk_prog_3(struct gf100_clk *clk, int idx) { struct gf100_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { - nv_mask(clk, 0x137100, (1 << idx), info->ssel); + nvkm_mask(device, 0x137100, (1 << idx), info->ssel); nv_wait(clk, 0x137100, (1 << idx), info->ssel); } } @@ -373,7 +381,8 @@ static void gf100_clk_prog_4(struct gf100_clk *clk, int idx) { struct gf100_clk_info *info = &clk->eng[idx]; - nv_mask(clk, 0x137250 + (idx * 0x04), 0x00003f3f, info->mdiv); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137250 + (idx * 0x04), 0x00003f3f, info->mdiv); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index 7723e9379ab8d..d2b7d6ec1c2b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -48,7 +48,8 @@ static u32 read_pll(struct gk104_clk *, u32); static u32 read_vco(struct gk104_clk *clk, u32 dsrc) { - u32 ssrc = nv_rd32(clk, dsrc); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc); if (!(ssrc & 0x00000100)) return read_pll(clk, 0x00e800); return read_pll(clk, 0x00e820); @@ -57,8 +58,9 @@ read_vco(struct gk104_clk *clk, u32 dsrc) static u32 read_pll(struct gk104_clk *clk, u32 pll) { - u32 ctrl = nv_rd32(clk, pll + 0x00); - u32 coef = nv_rd32(clk, pll + 0x04); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, pll + 0x00); + u32 coef = nvkm_rd32(device, pll + 0x04); u32 P = (coef & 0x003f0000) >> 16; u32 N = (coef & 0x0000ff00) >> 8; u32 M = (coef & 0x000000ff) >> 0; @@ -71,7 +73,7 @@ read_pll(struct gk104_clk *clk, u32 pll) switch (pll) { case 0x00e800: case 0x00e820: - sclk = nv_device(clk)->crystal; + sclk = device->crystal; P = 1; break; case 0x132000: @@ -80,7 +82,7 @@ read_pll(struct gk104_clk *clk, u32 pll) break; case 0x132020: sclk = read_div(clk, 0, 0x137320, 0x137330); - fN = nv_rd32(clk, pll + 0x10) >> 16; + fN = nvkm_rd32(device, pll + 0x10) >> 16; break; case 0x137000: case 0x137020: @@ -102,13 +104,14 @@ read_pll(struct gk104_clk *clk, u32 pll) static u32 read_div(struct gk104_clk *clk, int doff, u32 dsrc, u32 dctl) { - u32 ssrc = nv_rd32(clk, dsrc + (doff * 4)); - u32 sctl = nv_rd32(clk, dctl + (doff * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 ssrc = nvkm_rd32(device, dsrc + (doff * 4)); + u32 sctl = nvkm_rd32(device, dctl + (doff * 4)); switch (ssrc & 0x00000003) { case 0: if ((ssrc & 0x00030000) != 0x00030000) - return nv_device(clk)->crystal; + return device->crystal; return 108000; case 2: return 100000; @@ -128,7 +131,8 @@ read_div(struct gk104_clk *clk, int doff, u32 dsrc, u32 dctl) static u32 read_mem(struct gk104_clk *clk) { - switch (nv_rd32(clk, 0x1373f4) & 0x0000000f) { + struct nvkm_device *device = clk->base.subdev.device; + switch (nvkm_rd32(device, 0x1373f4) & 0x0000000f) { case 1: return read_pll(clk, 0x132020); case 2: return read_pll(clk, 0x132000); default: @@ -139,11 +143,12 @@ read_mem(struct gk104_clk *clk) static u32 read_clk(struct gk104_clk *clk, int idx) { - u32 sctl = nv_rd32(clk, 0x137250 + (idx * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 sctl = nvkm_rd32(device, 0x137250 + (idx * 4)); u32 sclk, sdiv; if (idx < 7) { - u32 ssel = nv_rd32(clk, 0x137100); + u32 ssel = nvkm_rd32(device, 0x137100); if (ssel & (1 << idx)) { sclk = read_pll(clk, 0x137000 + (idx * 0x20)); sdiv = 1; @@ -152,7 +157,7 @@ read_clk(struct gk104_clk *clk, int idx) sdiv = 0; } } else { - u32 ssrc = nv_rd32(clk, 0x137160 + (idx * 0x04)); + u32 ssrc = nvkm_rd32(device, 0x137160 + (idx * 0x04)); if ((ssrc & 0x00000003) == 0x00000003) { sclk = read_div(clk, idx, 0x137160, 0x1371d0); if (ssrc & 0x00000100) { @@ -183,7 +188,7 @@ static int gk104_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gk104_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = nv_device(clk); + struct nvkm_device *device = clk->base.subdev.device; switch (src) { case nv_clk_src_crystal: @@ -349,37 +354,41 @@ static void gk104_clk_prog_0(struct gk104_clk *clk, int idx) { struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (!info->ssel) { - nv_mask(clk, 0x1371d0 + (idx * 0x04), 0x8000003f, info->ddiv); - nv_wr32(clk, 0x137160 + (idx * 0x04), info->dsrc); + nvkm_mask(device, 0x1371d0 + (idx * 0x04), 0x8000003f, info->ddiv); + nvkm_wr32(device, 0x137160 + (idx * 0x04), info->dsrc); } } static void gk104_clk_prog_1_0(struct gk104_clk *clk, int idx) { - nv_mask(clk, 0x137100, (1 << idx), 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137100, (1 << idx), 0x00000000); nv_wait(clk, 0x137100, (1 << idx), 0x00000000); } static void gk104_clk_prog_1_1(struct gk104_clk *clk, int idx) { - nv_mask(clk, 0x137160 + (idx * 0x04), 0x00000100, 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x137160 + (idx * 0x04), 0x00000100, 0x00000000); } static void gk104_clk_prog_2(struct gk104_clk *clk, int idx) { struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; const u32 addr = 0x137000 + (idx * 0x20); - nv_mask(clk, addr + 0x00, 0x00000004, 0x00000000); - nv_mask(clk, addr + 0x00, 0x00000001, 0x00000000); + nvkm_mask(device, addr + 0x00, 0x00000004, 0x00000000); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000000); if (info->coef) { - nv_wr32(clk, addr + 0x04, info->coef); - nv_mask(clk, addr + 0x00, 0x00000001, 0x00000001); + nvkm_wr32(device, addr + 0x04, info->coef); + nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); nv_wait(clk, addr + 0x00, 0x00020000, 0x00020000); - nv_mask(clk, addr + 0x00, 0x00020004, 0x00000004); + nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); } } @@ -387,18 +396,20 @@ static void gk104_clk_prog_3(struct gk104_clk *clk, int idx) { struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) - nv_mask(clk, 0x137250 + (idx * 0x04), 0x00003f00, info->mdiv); + nvkm_mask(device, 0x137250 + (idx * 0x04), 0x00003f00, info->mdiv); else - nv_mask(clk, 0x137250 + (idx * 0x04), 0x0000003f, info->mdiv); + nvkm_mask(device, 0x137250 + (idx * 0x04), 0x0000003f, info->mdiv); } static void gk104_clk_prog_4_0(struct gk104_clk *clk, int idx) { struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { - nv_mask(clk, 0x137100, (1 << idx), info->ssel); + nvkm_mask(device, 0x137100, (1 << idx), info->ssel); nv_wait(clk, 0x137100, (1 << idx), info->ssel); } } @@ -407,9 +418,10 @@ static void gk104_clk_prog_4_1(struct gk104_clk *clk, int idx) { struct gk104_clk_info *info = &clk->eng[idx]; + struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { - nv_mask(clk, 0x137160 + (idx * 0x04), 0x40000000, 0x40000000); - nv_mask(clk, 0x137160 + (idx * 0x04), 0x00000100, 0x00000100); + nvkm_mask(device, 0x137160 + (idx * 0x04), 0x40000000, 0x40000000); + nvkm_mask(device, 0x137160 + (idx * 0x04), 0x00000100, 0x00000100); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 2019368775dac..6d36d094b8f2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -126,9 +126,10 @@ struct gk20a_clk { static void gk20a_pllg_read_mnp(struct gk20a_clk *clk) { + struct nvkm_device *device = clk->base.subdev.device; u32 val; - val = nv_rd32(clk, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); clk->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); clk->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH); clk->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); @@ -265,51 +266,52 @@ found_match: static int gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) { + struct nvkm_device *device = clk->base.subdev.device; u32 val; int ramp_timeout; /* get old coefficients */ - val = nv_rd32(clk, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); /* do nothing if NDIV is the same */ if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH))) return 0; /* setup */ - nv_mask(clk, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, + nvkm_mask(device, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT, 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT); - nv_mask(clk, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, + nvkm_mask(device, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT, 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT); /* pll slowdown mode */ - nv_mask(clk, GPCPLL_NDIV_SLOWDOWN, + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT), BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT)); /* new ndiv ready for ramp */ - val = nv_rd32(clk, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT); val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT; udelay(1); - nv_wr32(clk, GPCPLL_COEFF, val); + nvkm_wr32(device, GPCPLL_COEFF, val); /* dynamic ramp to new ndiv */ - val = nv_rd32(clk, GPCPLL_NDIV_SLOWDOWN); + val = nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT; udelay(1); - nv_wr32(clk, GPCPLL_NDIV_SLOWDOWN, val); + nvkm_wr32(device, GPCPLL_NDIV_SLOWDOWN, val); for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) { udelay(1); - val = nv_rd32(clk, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); + val = nvkm_rd32(device, GPC_BCAST_NDIV_SLOWDOWN_DEBUG); if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK) break; } /* exit slowdown mode */ - nv_mask(clk, GPCPLL_NDIV_SLOWDOWN, + nvkm_mask(device, GPCPLL_NDIV_SLOWDOWN, BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) | BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0); - nv_rd32(clk, GPCPLL_NDIV_SLOWDOWN); + nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); if (ramp_timeout <= 0) { nv_error(clk, "gpcpll dynamic ramp timeout\n"); @@ -322,30 +324,33 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) static void _gk20a_pllg_enable(struct gk20a_clk *clk) { - nv_mask(clk, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); - nv_rd32(clk, GPCPLL_CFG); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE); + nvkm_rd32(device, GPCPLL_CFG); } static void _gk20a_pllg_disable(struct gk20a_clk *clk) { - nv_mask(clk, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); - nv_rd32(clk, GPCPLL_CFG); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0); + nvkm_rd32(device, GPCPLL_CFG); } static int _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) { + struct nvkm_device *device = clk->base.subdev.device; u32 val, cfg; u32 m_old, pl_old, n_lo; /* get old coefficients */ - val = nv_rd32(clk, GPCPLL_COEFF); + val = nvkm_rd32(device, GPCPLL_COEFF); m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH); /* do NDIV slide if there is no change in M and PL */ - cfg = nv_rd32(clk, GPCPLL_CFG); + cfg = nvkm_rd32(device, GPCPLL_CFG); if (allow_slide && clk->m == m_old && clk->pl == pl_old && (cfg & GPCPLL_CFG_ENABLE)) { return gk20a_pllg_slide(clk, clk->n); @@ -362,21 +367,21 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) } /* split FO-to-bypass jump in halfs by setting out divider 1:2 */ - nv_mask(clk, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK, 0x2 << GPC2CLK_OUT_VCODIV_SHIFT); /* put PLL in bypass before programming it */ - val = nv_rd32(clk, SEL_VCO); + val = nvkm_rd32(device, SEL_VCO); val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); udelay(2); - nv_wr32(clk, SEL_VCO, val); + nvkm_wr32(device, SEL_VCO, val); /* get out from IDDQ */ - val = nv_rd32(clk, GPCPLL_CFG); + val = nvkm_rd32(device, GPCPLL_CFG); if (val & GPCPLL_CFG_IDDQ) { val &= ~GPCPLL_CFG_IDDQ; - nv_wr32(clk, GPCPLL_CFG, val); - nv_rd32(clk, GPCPLL_CFG); + nvkm_wr32(device, GPCPLL_CFG, val); + nvkm_rd32(device, GPCPLL_CFG); udelay(2); } @@ -390,14 +395,14 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) val = clk->m << GPCPLL_COEFF_M_SHIFT; val |= (allow_slide ? n_lo : clk->n) << GPCPLL_COEFF_N_SHIFT; val |= clk->pl << GPCPLL_COEFF_P_SHIFT; - nv_wr32(clk, GPCPLL_COEFF, val); + nvkm_wr32(device, GPCPLL_COEFF, val); _gk20a_pllg_enable(clk); - val = nv_rd32(clk, GPCPLL_CFG); + val = nvkm_rd32(device, GPCPLL_CFG); if (val & GPCPLL_CFG_LOCK_DET_OFF) { val &= ~GPCPLL_CFG_LOCK_DET_OFF; - nv_wr32(clk, GPCPLL_CFG, val); + nvkm_wr32(device, GPCPLL_CFG, val); } if (!nvkm_timer_wait_eq(clk, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, @@ -407,13 +412,13 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) } /* switch to VCO mode */ - nv_mask(clk, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); + nvkm_mask(device, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); /* restore out divider 1:1 */ - val = nv_rd32(clk, GPC2CLK_OUT); + val = nvkm_rd32(device, GPC2CLK_OUT); val &= ~GPC2CLK_OUT_VCODIV_MASK; udelay(2); - nv_wr32(clk, GPC2CLK_OUT, val); + nvkm_wr32(device, GPC2CLK_OUT, val); /* slide up to new NDIV */ return allow_slide ? gk20a_pllg_slide(clk, clk->n) : 0; @@ -434,14 +439,15 @@ gk20a_pllg_program_mnp(struct gk20a_clk *clk) static void gk20a_pllg_disable(struct gk20a_clk *clk) { + struct nvkm_device *device = clk->base.subdev.device; u32 val; /* slide to VCO min */ - val = nv_rd32(clk, GPCPLL_CFG); + val = nvkm_rd32(device, GPCPLL_CFG); if (val & GPCPLL_CFG_ENABLE) { u32 coeff, m, n_lo; - coeff = nv_rd32(clk, GPCPLL_COEFF); + coeff = nvkm_rd32(device, GPCPLL_COEFF); m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH); n_lo = DIV_ROUND_UP(m * clk->params->min_vco, clk->parent_rate / MHZ); @@ -449,7 +455,7 @@ gk20a_pllg_disable(struct gk20a_clk *clk) } /* put PLL in bypass before disabling it */ - nv_mask(clk, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); + nvkm_mask(device, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0); _gk20a_pllg_disable(clk); } @@ -561,10 +567,11 @@ static int gk20a_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); + struct nvkm_device *device = clk->base.subdev.device; switch (src) { case nv_clk_src_crystal: - return nv_device(clk)->crystal; + return device->crystal; case nv_clk_src_gpc: gk20a_pllg_read_mnp(clk); return gk20a_pllg_calc_rate(clk) / GK20A_CLK_GPC_MDIV; @@ -613,9 +620,10 @@ static int gk20a_clk_init(struct nvkm_object *object) { struct gk20a_clk *clk = (void *)object; + struct nvkm_device *device = clk->base.subdev.device; int ret; - nv_mask(clk, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); + nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); ret = nvkm_clk_init(&clk->base); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index e17135a1ec839..364c9b0df728a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -41,11 +41,12 @@ static u32 read_pll(struct gt215_clk *, int, u32); static u32 read_vco(struct gt215_clk *clk, int idx) { - u32 sctl = nv_rd32(clk, 0x4120 + (idx * 4)); + struct nvkm_device *device = clk->base.subdev.device; + u32 sctl = nvkm_rd32(device, 0x4120 + (idx * 4)); switch (sctl & 0x00000030) { case 0x00000000: - return nv_device(clk)->crystal; + return device->crystal; case 0x00000020: return read_pll(clk, 0x41, 0x00e820); case 0x00000030: @@ -58,19 +59,20 @@ read_vco(struct gt215_clk *clk, int idx) static u32 read_clk(struct gt215_clk *clk, int idx, bool ignore_en) { + struct nvkm_device *device = clk->base.subdev.device; u32 sctl, sdiv, sclk; /* refclk for the 0xe8xx plls is a fixed frequency */ if (idx >= 0x40) { - if (nv_device(clk)->chipset == 0xaf) { + if (device->chipset == 0xaf) { /* no joke.. seriously.. sigh.. */ - return nv_rd32(clk, 0x00471c) * 1000; + return nvkm_rd32(device, 0x00471c) * 1000; } - return nv_device(clk)->crystal; + return device->crystal; } - sctl = nv_rd32(clk, 0x4120 + (idx * 4)); + sctl = nvkm_rd32(device, 0x4120 + (idx * 4)); if (!ignore_en && !(sctl & 0x00000100)) return 0; @@ -82,7 +84,7 @@ read_clk(struct gt215_clk *clk, int idx, bool ignore_en) switch (sctl & 0x00003000) { case 0x00000000: if (!(sctl & 0x00000200)) - return nv_device(clk)->crystal; + return device->crystal; return 0; case 0x00002000: if (sctl & 0x00000040) @@ -104,12 +106,13 @@ read_clk(struct gt215_clk *clk, int idx, bool ignore_en) static u32 read_pll(struct gt215_clk *clk, int idx, u32 pll) { - u32 ctrl = nv_rd32(clk, pll + 0); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, pll + 0); u32 sclk = 0, P = 1, N = 1, M = 1; if (!(ctrl & 0x00000008)) { if (ctrl & 0x00000001) { - u32 coef = nv_rd32(clk, pll + 4); + u32 coef = nvkm_rd32(device, pll + 4); M = (coef & 0x000000ff) >> 0; N = (coef & 0x0000ff00) >> 8; P = (coef & 0x003f0000) >> 16; @@ -136,11 +139,12 @@ static int gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct nvkm_device *device = clk->base.subdev.device; u32 hsrc; switch (src) { case nv_clk_src_crystal: - return nv_device(clk)->crystal; + return device->crystal; case nv_clk_src_core: case nv_clk_src_core_intm: return read_pll(clk, 0x00, 0x4200); @@ -155,7 +159,7 @@ gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case nv_clk_src_daemon: return read_clk(clk, 0x25, false); case nv_clk_src_host: - hsrc = (nv_rd32(clk, 0xc040) & 0x30000000) >> 28; + hsrc = (nvkm_rd32(device, 0xc040) & 0x30000000) >> 28; switch (hsrc) { case 0: return read_clk(clk, 0x1d, false); @@ -297,11 +301,12 @@ calc_host(struct gt215_clk *clk, struct nvkm_cstate *cstate) int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) { + struct nvkm_device *device = clk->subdev.device; struct nvkm_fifo *fifo = nvkm_fifo(clk); /* halt and idle execution engines */ - nv_mask(clk, 0x020060, 0x00070000, 0x00000000); - nv_mask(clk, 0x002504, 0x00000001, 0x00000001); + nvkm_mask(device, 0x020060, 0x00070000, 0x00000000); + nvkm_mask(device, 0x002504, 0x00000001, 0x00000001); /* Wait until the interrupt handler is finished */ if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) return -EBUSY; @@ -320,26 +325,29 @@ gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) { + struct nvkm_device *device = clk->subdev.device; struct nvkm_fifo *fifo = nvkm_fifo(clk); if (fifo && flags) fifo->start(fifo, flags); - nv_mask(clk, 0x002504, 0x00000001, 0x00000000); - nv_mask(clk, 0x020060, 0x00070000, 0x00040000); + nvkm_mask(device, 0x002504, 0x00000001, 0x00000000); + nvkm_mask(device, 0x020060, 0x00070000, 0x00040000); } static void disable_clk_src(struct gt215_clk *clk, u32 src) { - nv_mask(clk, src, 0x00000100, 0x00000000); - nv_mask(clk, src, 0x00000001, 0x00000000); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, src, 0x00000100, 0x00000000); + nvkm_mask(device, src, 0x00000001, 0x00000000); } static void prog_pll(struct gt215_clk *clk, int idx, u32 pll, int dom) { struct gt215_clk_info *info = &clk->eng[dom]; + struct nvkm_device *device = clk->base.subdev.device; const u32 src0 = 0x004120 + (idx * 4); const u32 src1 = 0x004160 + (idx * 4); const u32 ctrl = pll + 0; @@ -348,30 +356,30 @@ prog_pll(struct gt215_clk *clk, int idx, u32 pll, int dom) if (info->pll) { /* Always start from a non-PLL clock */ - bypass = nv_rd32(clk, ctrl) & 0x00000008; + bypass = nvkm_rd32(device, ctrl) & 0x00000008; if (!bypass) { - nv_mask(clk, src1, 0x00000101, 0x00000101); - nv_mask(clk, ctrl, 0x00000008, 0x00000008); + nvkm_mask(device, src1, 0x00000101, 0x00000101); + nvkm_mask(device, ctrl, 0x00000008, 0x00000008); udelay(20); } - nv_mask(clk, src0, 0x003f3141, 0x00000101 | info->clk); - nv_wr32(clk, coef, info->pll); - nv_mask(clk, ctrl, 0x00000015, 0x00000015); - nv_mask(clk, ctrl, 0x00000010, 0x00000000); + nvkm_mask(device, src0, 0x003f3141, 0x00000101 | info->clk); + nvkm_wr32(device, coef, info->pll); + nvkm_mask(device, ctrl, 0x00000015, 0x00000015); + nvkm_mask(device, ctrl, 0x00000010, 0x00000000); if (!nv_wait(clk, ctrl, 0x00020000, 0x00020000)) { - nv_mask(clk, ctrl, 0x00000010, 0x00000010); - nv_mask(clk, src0, 0x00000101, 0x00000000); + nvkm_mask(device, ctrl, 0x00000010, 0x00000010); + nvkm_mask(device, src0, 0x00000101, 0x00000000); return; } - nv_mask(clk, ctrl, 0x00000010, 0x00000010); - nv_mask(clk, ctrl, 0x00000008, 0x00000000); + nvkm_mask(device, ctrl, 0x00000010, 0x00000010); + nvkm_mask(device, ctrl, 0x00000008, 0x00000000); disable_clk_src(clk, src1); } else { - nv_mask(clk, src1, 0x003f3141, 0x00000101 | info->clk); - nv_mask(clk, ctrl, 0x00000018, 0x00000018); + nvkm_mask(device, src1, 0x003f3141, 0x00000101 | info->clk); + nvkm_mask(device, ctrl, 0x00000018, 0x00000018); udelay(20); - nv_mask(clk, ctrl, 0x00000001, 0x00000000); + nvkm_mask(device, ctrl, 0x00000001, 0x00000000); disable_clk_src(clk, src0); } } @@ -380,26 +388,28 @@ static void prog_clk(struct gt215_clk *clk, int idx, int dom) { struct gt215_clk_info *info = &clk->eng[dom]; - nv_mask(clk, 0x004120 + (idx * 4), 0x003f3141, 0x00000101 | info->clk); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x004120 + (idx * 4), 0x003f3141, 0x00000101 | info->clk); } static void prog_host(struct gt215_clk *clk) { struct gt215_clk_info *info = &clk->eng[nv_clk_src_host]; - u32 hsrc = (nv_rd32(clk, 0xc040)); + struct nvkm_device *device = clk->base.subdev.device; + u32 hsrc = (nvkm_rd32(device, 0xc040)); switch (info->host_out) { case NVA3_HOST_277: if ((hsrc & 0x30000000) == 0) { - nv_wr32(clk, 0xc040, hsrc | 0x20000000); + nvkm_wr32(device, 0xc040, hsrc | 0x20000000); disable_clk_src(clk, 0x4194); } break; case NVA3_HOST_CLK: prog_clk(clk, 0x1d, nv_clk_src_host); if ((hsrc & 0x30000000) >= 0x20000000) { - nv_wr32(clk, 0xc040, hsrc & ~0x30000000); + nvkm_wr32(device, 0xc040, hsrc & ~0x30000000); } break; default: @@ -407,22 +417,23 @@ prog_host(struct gt215_clk *clk) } /* This seems to be a clock gating factor on idle, always set to 64 */ - nv_wr32(clk, 0xc044, 0x3e); + nvkm_wr32(device, 0xc044, 0x3e); } static void prog_core(struct gt215_clk *clk, int dom) { struct gt215_clk_info *info = &clk->eng[dom]; - u32 fb_delay = nv_rd32(clk, 0x10002c); + struct nvkm_device *device = clk->base.subdev.device; + u32 fb_delay = nvkm_rd32(device, 0x10002c); if (fb_delay < info->fb_delay) - nv_wr32(clk, 0x10002c, info->fb_delay); + nvkm_wr32(device, 0x10002c, info->fb_delay); prog_pll(clk, 0x00, 0x004200, dom); if (fb_delay > info->fb_delay) - nv_wr32(clk, 0x10002c, info->fb_delay); + nvkm_wr32(device, 0x10002c, info->fb_delay); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index 7203bb3e0a9a4..9d7c118e97845 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -40,14 +40,16 @@ struct mcp77_clk { static u32 read_div(struct mcp77_clk *clk) { - return nv_rd32(clk, 0x004600); + struct nvkm_device *device = clk->base.subdev.device; + return nvkm_rd32(device, 0x004600); } static u32 read_pll(struct mcp77_clk *clk, u32 base) { - u32 ctrl = nv_rd32(clk, base + 0); - u32 coef = nv_rd32(clk, base + 4); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, base + 0); + u32 coef = nvkm_rd32(device, base + 4); u32 ref = clk->base.read(&clk->base, nv_clk_src_href); u32 post_div = 0; u32 clock = 0; @@ -55,10 +57,10 @@ read_pll(struct mcp77_clk *clk, u32 base) switch (base){ case 0x4020: - post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16); + post_div = 1 << ((nvkm_rd32(device, 0x4070) & 0x000f0000) >> 16); break; case 0x4028: - post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16; + post_div = (nvkm_rd32(device, 0x4040) & 0x000f0000) >> 16; break; default: break; @@ -78,12 +80,13 @@ static int mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); - u32 mast = nv_rd32(clk, 0x00c054); + struct nvkm_device *device = clk->base.subdev.device; + u32 mast = nvkm_rd32(device, 0x00c054); u32 P = 0; switch (src) { case nv_clk_src_crystal: - return nv_device(clk)->crystal; + return device->crystal; case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclkm4: @@ -99,7 +102,7 @@ mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) } break; case nv_clk_src_core: - P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; @@ -122,7 +125,7 @@ mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) default: return 0; } case nv_clk_src_shader: - P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004020) & 0x00070000) >> 16; switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000040) @@ -293,6 +296,7 @@ static int mcp77_clk_prog(struct nvkm_clk *obj) { struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); + struct nvkm_device *device = clk->base.subdev.device; u32 pllmask = 0, mast; unsigned long flags; unsigned long *f = &flags; @@ -303,19 +307,19 @@ mcp77_clk_prog(struct nvkm_clk *obj) goto out; /* First switch to safe clocks: href */ - mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640); + mast = nvkm_mask(device, 0xc054, 0x03400e70, 0x03400640); mast &= ~0x00400e73; mast |= 0x03000000; switch (clk->csrc) { case nv_clk_src_hclkm4: - nv_mask(clk, 0x4028, 0x00070000, clk->cctrl); + nvkm_mask(device, 0x4028, 0x00070000, clk->cctrl); mast |= 0x00000002; break; case nv_clk_src_core: - nv_wr32(clk, 0x402c, clk->ccoef); - nv_wr32(clk, 0x4028, 0x80000000 | clk->cctrl); - nv_wr32(clk, 0x4040, clk->cpost); + nvkm_wr32(device, 0x402c, clk->ccoef); + nvkm_wr32(device, 0x4028, 0x80000000 | clk->cctrl); + nvkm_wr32(device, 0x4040, clk->cpost); pllmask |= (0x3 << 8); mast |= 0x00000003; break; @@ -326,17 +330,17 @@ mcp77_clk_prog(struct nvkm_clk *obj) switch (clk->ssrc) { case nv_clk_src_href: - nv_mask(clk, 0x4020, 0x00070000, 0x00000000); + nvkm_mask(device, 0x4020, 0x00070000, 0x00000000); /* mast |= 0x00000000; */ break; case nv_clk_src_core: - nv_mask(clk, 0x4020, 0x00070000, clk->sctrl); + nvkm_mask(device, 0x4020, 0x00070000, clk->sctrl); mast |= 0x00000020; break; case nv_clk_src_shader: - nv_wr32(clk, 0x4024, clk->scoef); - nv_wr32(clk, 0x4020, 0x80000000 | clk->sctrl); - nv_wr32(clk, 0x4070, clk->spost); + nvkm_wr32(device, 0x4024, clk->scoef); + nvkm_wr32(device, 0x4020, 0x80000000 | clk->sctrl); + nvkm_wr32(device, 0x4070, clk->spost); pllmask |= (0x3 << 12); mast |= 0x00000030; break; @@ -354,21 +358,21 @@ mcp77_clk_prog(struct nvkm_clk *obj) case nv_clk_src_cclk: mast |= 0x00400000; default: - nv_wr32(clk, 0x4600, clk->vdiv); + nvkm_wr32(device, 0x4600, clk->vdiv); } - nv_wr32(clk, 0xc054, mast); + nvkm_wr32(device, 0xc054, mast); resume: /* Disable some PLLs and dividers when unused */ if (clk->csrc != nv_clk_src_core) { - nv_wr32(clk, 0x4040, 0x00000000); - nv_mask(clk, 0x4028, 0x80000000, 0x00000000); + nvkm_wr32(device, 0x4040, 0x00000000); + nvkm_mask(device, 0x4028, 0x80000000, 0x00000000); } if (clk->ssrc != nv_clk_src_shader) { - nv_wr32(clk, 0x4070, 0x00000000); - nv_mask(clk, 0x4020, 0x80000000, 0x00000000); + nvkm_wr32(device, 0x4070, 0x00000000); + nvkm_mask(device, 0x4020, 0x80000000, 0x00000000); } out: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index eb4a8affd0ecc..32d59f40f5d38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -48,7 +48,8 @@ nv40_domain[] = { static u32 read_pll_1(struct nv40_clk *clk, u32 reg) { - u32 ctrl = nv_rd32(clk, reg + 0x00); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, reg + 0x00); int P = (ctrl & 0x00070000) >> 16; int N = (ctrl & 0x0000ff00) >> 8; int M = (ctrl & 0x000000ff) >> 0; @@ -63,8 +64,9 @@ read_pll_1(struct nv40_clk *clk, u32 reg) static u32 read_pll_2(struct nv40_clk *clk, u32 reg) { - u32 ctrl = nv_rd32(clk, reg + 0x00); - u32 coef = nv_rd32(clk, reg + 0x04); + struct nvkm_device *device = clk->base.subdev.device; + u32 ctrl = nvkm_rd32(device, reg + 0x00); + u32 coef = nvkm_rd32(device, reg + 0x04); int N2 = (coef & 0xff000000) >> 24; int M2 = (coef & 0x00ff0000) >> 16; int N1 = (coef & 0x0000ff00) >> 8; @@ -104,11 +106,12 @@ static int nv40_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct nv40_clk *clk = container_of(obj, typeof(*clk), base); - u32 mast = nv_rd32(clk, 0x00c040); + struct nvkm_device *device = clk->base.subdev.device; + u32 mast = nvkm_rd32(device, 0x00c040); switch (src) { case nv_clk_src_crystal: - return nv_device(clk)->crystal; + return device->crystal; case nv_clk_src_href: return 100000; /*XXX: PCIE/AGP differ*/ case nv_clk_src_core: @@ -191,12 +194,13 @@ static int nv40_clk_prog(struct nvkm_clk *obj) { struct nv40_clk *clk = container_of(obj, typeof(*clk), base); - nv_mask(clk, 0x00c040, 0x00000333, 0x00000000); - nv_wr32(clk, 0x004004, clk->npll_coef); - nv_mask(clk, 0x004000, 0xc0070100, clk->npll_ctrl); - nv_mask(clk, 0x004008, 0xc007ffff, clk->spll); + struct nvkm_device *device = clk->base.subdev.device; + nvkm_mask(device, 0x00c040, 0x00000333, 0x00000000); + nvkm_wr32(device, 0x004004, clk->npll_coef); + nvkm_mask(device, 0x004000, 0xc0070100, clk->npll_ctrl); + nvkm_mask(device, 0x004008, 0xc007ffff, clk->spll); mdelay(5); - nv_mask(clk, 0x00c040, 0x00000333, clk->ctrl); + nvkm_mask(device, 0x00c040, 0x00000333, clk->ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 2b44ff4449094..0d17de6f90e81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -31,17 +31,18 @@ static u32 read_div(struct nv50_clk *clk) { - switch (nv_device(clk)->chipset) { + struct nvkm_device *device = clk->base.subdev.device; + switch (device->chipset) { case 0x50: /* it exists, but only has bit 31, not the dividers.. */ case 0x84: case 0x86: case 0x98: case 0xa0: - return nv_rd32(clk, 0x004700); + return nvkm_rd32(device, 0x004700); case 0x92: case 0x94: case 0x96: - return nv_rd32(clk, 0x004800); + return nvkm_rd32(device, 0x004800); default: return 0x00000000; } @@ -50,11 +51,12 @@ read_div(struct nv50_clk *clk) static u32 read_pll_src(struct nv50_clk *clk, u32 base) { + struct nvkm_device *device = clk->base.subdev.device; u32 coef, ref = clk->base.read(&clk->base, nv_clk_src_crystal); - u32 rsel = nv_rd32(clk, 0x00e18c); + u32 rsel = nvkm_rd32(device, 0x00e18c); int P, N, M, id; - switch (nv_device(clk)->chipset) { + switch (device->chipset) { case 0x50: case 0xa0: switch (base) { @@ -67,7 +69,7 @@ read_pll_src(struct nv50_clk *clk, u32 base) return 0; } - coef = nv_rd32(clk, 0x00e81c + (id * 0x0c)); + coef = nvkm_rd32(device, 0x00e81c + (id * 0x0c)); ref *= (coef & 0x01000000) ? 2 : 4; P = (coef & 0x00070000) >> 16; N = ((coef & 0x0000ff00) >> 8) + 1; @@ -76,7 +78,7 @@ read_pll_src(struct nv50_clk *clk, u32 base) case 0x84: case 0x86: case 0x92: - coef = nv_rd32(clk, 0x00e81c); + coef = nvkm_rd32(device, 0x00e81c); P = (coef & 0x00070000) >> 16; N = (coef & 0x0000ff00) >> 8; M = (coef & 0x000000ff) >> 0; @@ -84,7 +86,7 @@ read_pll_src(struct nv50_clk *clk, u32 base) case 0x94: case 0x96: case 0x98: - rsel = nv_rd32(clk, 0x00c050); + rsel = nvkm_rd32(device, 0x00c050); switch (base) { case 0x4020: rsel = (rsel & 0x00000003) >> 0; break; case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break; @@ -102,8 +104,8 @@ read_pll_src(struct nv50_clk *clk, u32 base) case 3: id = 0; break; } - coef = nv_rd32(clk, 0x00e81c + (id * 0x28)); - P = (nv_rd32(clk, 0x00e824 + (id * 0x28)) >> 16) & 7; + coef = nvkm_rd32(device, 0x00e81c + (id * 0x28)); + P = (nvkm_rd32(device, 0x00e824 + (id * 0x28)) >> 16) & 7; P += (coef & 0x00070000) >> 16; N = (coef & 0x0000ff00) >> 8; M = (coef & 0x000000ff) >> 0; @@ -121,7 +123,8 @@ read_pll_src(struct nv50_clk *clk, u32 base) static u32 read_pll_ref(struct nv50_clk *clk, u32 base) { - u32 src, mast = nv_rd32(clk, 0x00c040); + struct nvkm_device *device = clk->base.subdev.device; + u32 src, mast = nvkm_rd32(device, 0x00c040); switch (base) { case 0x004028: @@ -152,16 +155,17 @@ read_pll_ref(struct nv50_clk *clk, u32 base) static u32 read_pll(struct nv50_clk *clk, u32 base) { - u32 mast = nv_rd32(clk, 0x00c040); - u32 ctrl = nv_rd32(clk, base + 0); - u32 coef = nv_rd32(clk, base + 4); + struct nvkm_device *device = clk->base.subdev.device; + u32 mast = nvkm_rd32(device, 0x00c040); + u32 ctrl = nvkm_rd32(device, base + 0); + u32 coef = nvkm_rd32(device, base + 4); u32 ref = read_pll_ref(clk, base); u32 freq = 0; int N1, N2, M1, M2; if (base == 0x004028 && (mast & 0x00100000)) { /* wtf, appears to only disable post-divider on gt200 */ - if (nv_device(clk)->chipset != 0xa0) + if (device->chipset != 0xa0) return clk->base.read(&clk->base, nv_clk_src_dom6); } @@ -186,12 +190,13 @@ static int nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct nv50_clk *clk = container_of(obj, typeof(*clk), base); - u32 mast = nv_rd32(clk, 0x00c040); + struct nvkm_device *device = clk->base.subdev.device; + u32 mast = nvkm_rd32(device, 0x00c040); u32 P = 0; switch (src) { case nv_clk_src_crystal: - return nv_device(clk)->crystal; + return device->crystal; case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclk: @@ -210,7 +215,7 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) break; case nv_clk_src_core: if (!(mast & 0x00100000)) - P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000001: return clk->base.read(&clk->base, nv_clk_src_dom6); @@ -219,7 +224,7 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) } break; case nv_clk_src_shader: - P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16; + P = (nvkm_rd32(device, 0x004020) & 0x00070000) >> 16; switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000080) @@ -231,8 +236,8 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) } break; case nv_clk_src_mem: - P = (nv_rd32(clk, 0x004008) & 0x00070000) >> 16; - if (nv_rd32(clk, 0x004008) & 0x00000200) { + P = (nvkm_rd32(device, 0x004008) & 0x00070000) >> 16; + if (nvkm_rd32(device, 0x004008) & 0x00000200) { switch (mast & 0x0000c000) { case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; @@ -246,7 +251,7 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) break; case nv_clk_src_vdec: P = (read_div(clk) & 0x00000700) >> 8; - switch (nv_device(clk)->chipset) { + switch (device->chipset) { case 0x84: case 0x86: case 0x92: @@ -255,7 +260,7 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case 0xa0: switch (mast & 0x00000c00) { case 0x00000000: - if (nv_device(clk)->chipset == 0xa0) /* wtf?? */ + if (device->chipset == 0xa0) /* wtf?? */ return clk->base.read(&clk->base, nv_clk_src_core) >> P; return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000400: @@ -283,7 +288,7 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) } break; case nv_clk_src_dom6: - switch (nv_device(clk)->chipset) { + switch (device->chipset) { case 0x50: case 0xa0: return read_pll(clk, 0x00e810) >> 2; -- GitLab From 8ac3f64f75b6b7dbe5917e5c65344915415f58e1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5364/7006] drm/nouveau/devinit: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/devinit/g84.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/devinit/g98.c | 8 +- .../drm/nouveau/nvkm/subdev/devinit/gf100.c | 22 +-- .../drm/nouveau/nvkm/subdev/devinit/gm107.c | 8 +- .../drm/nouveau/nvkm/subdev/devinit/gm204.c | 47 ++++--- .../drm/nouveau/nvkm/subdev/devinit/gt215.c | 33 ++--- .../drm/nouveau/nvkm/subdev/devinit/mcp89.c | 8 +- .../drm/nouveau/nvkm/subdev/devinit/nv04.c | 125 +++++++++--------- .../drm/nouveau/nvkm/subdev/devinit/nv05.c | 34 ++--- .../drm/nouveau/nvkm/subdev/devinit/nv10.c | 17 ++- .../drm/nouveau/nvkm/subdev/devinit/nv20.c | 10 +- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 40 +++--- 12 files changed, 185 insertions(+), 175 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c index 69f28feda861e..d70e1dd654e0f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c @@ -27,11 +27,11 @@ #include static u64 -g84_devinit_disable(struct nvkm_devinit *devinit) +g84_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r001540 = nv_rd32(init, 0x001540); - u32 r00154c = nv_rd32(init, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c index 06a269c0ac057..6af12fd868d9e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c @@ -27,11 +27,11 @@ #include static u64 -g98_devinit_disable(struct nvkm_devinit *devinit) +g98_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r001540 = nv_rd32(init, 0x001540); - u32 r00154c = nv_rd32(init, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index b6eb2540fcbd1..438a58e8be5ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -29,19 +29,19 @@ #include int -gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) +gf100_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { - struct nv50_devinit *init = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; struct nvbios_pll info; int N, fN, M, P; int ret; - ret = nvbios_pll_parse(bios, type, &info); + ret = nvbios_pll_parse(device->bios, type, &info); if (ret) return ret; - ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P); + ret = gt215_pll_calc(subdev, &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; @@ -50,9 +50,9 @@ gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) case PLL_VPLL1: case PLL_VPLL2: case PLL_VPLL3: - nv_mask(init, info.reg + 0x0c, 0x00000000, 0x00000100); - nv_wr32(init, info.reg + 0x04, (P << 16) | (N << 8) | M); - nv_wr32(init, info.reg + 0x10, fN << 16); + nvkm_mask(device, info.reg + 0x0c, 0x00000000, 0x00000100); + nvkm_wr32(device, info.reg + 0x04, (P << 16) | (N << 8) | M); + nvkm_wr32(device, info.reg + 0x10, fN << 16); break; default: nv_warn(init, "0x%08x/%dKhz unimplemented\n", type, freq); @@ -64,10 +64,10 @@ gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } static u64 -gf100_devinit_disable(struct nvkm_devinit *devinit) +gf100_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r022500 = nv_rd32(init, 0x022500); + struct nvkm_device *device = init->subdev.device; + u32 r022500 = nvkm_rd32(device, 0x022500); u64 disable = 0ULL; if (r022500 & 0x00000001) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c index 16150177f6c6f..6c82c4afe0110 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c @@ -27,11 +27,11 @@ #include u64 -gm107_devinit_disable(struct nvkm_devinit *devinit) +gm107_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r021c00 = nv_rd32(init, 0x021c00); - u32 r021c04 = nv_rd32(init, 0x021c04); + struct nvkm_device *device = init->subdev.device; + u32 r021c00 = nvkm_rd32(device, 0x021c00); + u32 r021c04 = nvkm_rd32(device, 0x021c04); u64 disable = 0ULL; if (r021c00 & 0x00000001) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c index 3c513be9817fc..cc3263889084e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c @@ -30,18 +30,19 @@ static void pmu_code(struct nv50_devinit *init, u32 pmu, u32 img, u32 len, bool sec) { - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_device *device = init->base.subdev.device; + struct nvkm_bios *bios = device->bios; int i; - nv_wr32(init, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu); + nvkm_wr32(device, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu); for (i = 0; i < len; i += 4) { if ((i & 0xff) == 0) - nv_wr32(init, 0x10a188, (pmu + i) >> 8); - nv_wr32(init, 0x10a184, nv_ro32(bios, img + i)); + nvkm_wr32(device, 0x10a188, (pmu + i) >> 8); + nvkm_wr32(device, 0x10a184, nv_ro32(bios, img + i)); } while (i & 0xff) { - nv_wr32(init, 0x10a184, 0x00000000); + nvkm_wr32(device, 0x10a184, 0x00000000); i += 4; } } @@ -49,28 +50,31 @@ pmu_code(struct nv50_devinit *init, u32 pmu, u32 img, u32 len, bool sec) static void pmu_data(struct nv50_devinit *init, u32 pmu, u32 img, u32 len) { - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_device *device = init->base.subdev.device; + struct nvkm_bios *bios = device->bios; int i; - nv_wr32(init, 0x10a1c0, 0x01000000 | pmu); + nvkm_wr32(device, 0x10a1c0, 0x01000000 | pmu); for (i = 0; i < len; i += 4) - nv_wr32(init, 0x10a1c4, nv_ro32(bios, img + i)); + nvkm_wr32(device, 0x10a1c4, nv_ro32(bios, img + i)); } static u32 pmu_args(struct nv50_devinit *init, u32 argp, u32 argi) { - nv_wr32(init, 0x10a1c0, argp); - nv_wr32(init, 0x10a1c0, nv_rd32(init, 0x10a1c4) + argi); - return nv_rd32(init, 0x10a1c4); + struct nvkm_device *device = init->base.subdev.device; + nvkm_wr32(device, 0x10a1c0, argp); + nvkm_wr32(device, 0x10a1c0, nvkm_rd32(device, 0x10a1c4) + argi); + return nvkm_rd32(device, 0x10a1c4); } static void pmu_exec(struct nv50_devinit *init, u32 init_addr) { - nv_wr32(init, 0x10a104, init_addr); - nv_wr32(init, 0x10a10c, 0x00000000); - nv_wr32(init, 0x10a100, 0x00000002); + struct nvkm_device *device = init->base.subdev.device; + nvkm_wr32(device, 0x10a104, init_addr); + nvkm_wr32(device, 0x10a10c, 0x00000000); + nvkm_wr32(device, 0x10a100, 0x00000002); } static int @@ -105,7 +109,8 @@ static int gm204_devinit_post(struct nvkm_subdev *subdev, bool post) { struct nv50_devinit *init = (void *)nvkm_devinit(subdev); - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_device *device = init->base.subdev.device; + struct nvkm_bios *bios = device->bios; struct bit_entry bit_I; u32 exec, args; int ret; @@ -118,10 +123,10 @@ gm204_devinit_post(struct nvkm_subdev *subdev, bool post) /* reset PMU and load init table parser ucode */ if (post) { - nv_mask(init, 0x000200, 0x00002000, 0x00000000); - nv_mask(init, 0x000200, 0x00002000, 0x00002000); - nv_rd32(init, 0x000200); - while (nv_rd32(init, 0x10a10c) & 0x00000006) { + nvkm_mask(device, 0x000200, 0x00002000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00002000, 0x00002000); + nvkm_rd32(device, 0x000200); + while (nvkm_rd32(device, 0x10a10c) & 0x00000006) { } } @@ -147,9 +152,9 @@ gm204_devinit_post(struct nvkm_subdev *subdev, bool post) /* execute init tables */ if (post) { - nv_wr32(init, 0x10a040, 0x00005000); + nvkm_wr32(device, 0x10a040, 0x00005000); pmu_exec(init, exec); - while (!(nv_rd32(init, 0x10a040) & 0x00002000)) { + while (!(nvkm_rd32(device, 0x10a040) & 0x00002000)) { } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c index ffe3828c23c8c..052fe7e1f25b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c @@ -29,29 +29,29 @@ #include int -gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) +gt215_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { - struct nv50_devinit *init = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; struct nvbios_pll info; int N, fN, M, P; int ret; - ret = nvbios_pll_parse(bios, type, &info); + ret = nvbios_pll_parse(device->bios, type, &info); if (ret) return ret; - ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P); + ret = gt215_pll_calc(subdev, &info, freq, &N, &fN, &M, &P); if (ret < 0) return ret; switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: - nv_wr32(init, info.reg + 0, 0x50000610); - nv_mask(init, info.reg + 4, 0x003fffff, - (P << 16) | (M << 8) | N); - nv_wr32(init, info.reg + 8, fN); + nvkm_wr32(device, info.reg + 0, 0x50000610); + nvkm_mask(device, info.reg + 4, 0x003fffff, + (P << 16) | (M << 8) | N); + nvkm_wr32(device, info.reg + 8, fN); break; default: nv_warn(init, "0x%08x/%dKhz unimplemented\n", type, freq); @@ -63,11 +63,11 @@ gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } static u64 -gt215_devinit_disable(struct nvkm_devinit *devinit) +gt215_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r001540 = nv_rd32(init, 0x001540); - u32 r00154c = nv_rd32(init, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { @@ -99,9 +99,10 @@ gt215_devinit_mmio_part[] = { }; static u32 -gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) +gt215_devinit_mmio(struct nvkm_devinit *obj, u32 addr) { - struct nv50_devinit *init = (void *)devinit; + struct nv50_devinit *init = container_of(obj, typeof(*init), base); + struct nvkm_device *device = init->base.subdev.device; u32 *mmio = gt215_devinit_mmio_part; /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP @@ -123,7 +124,7 @@ gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr) if (addr >= mmio[0] && addr <= mmio[1]) { u32 part = (addr / mmio[2]) & 7; if (!init->r001540) - init->r001540 = nv_rd32(init, 0x001540); + init->r001540 = nvkm_rd32(device, 0x001540); if (part >= hweight8((init->r001540 >> 16) & 0xff)) return ~0; return addr; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c index 27085758b67b6..e342b5c8dc2ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c @@ -27,11 +27,11 @@ #include static u64 -mcp89_devinit_disable(struct nvkm_devinit *devinit) +mcp89_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r001540 = nv_rd32(init, 0x001540); - u32 r00154c = nv_rd32(init, 0x00154c); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); + u32 r00154c = nvkm_rd32(device, 0x00154c); u64 disable = 0; if (!(r001540 & 0x40000000)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 28cb38160ce1f..8e2992038f9f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -33,15 +33,15 @@ #include static void -nv04_devinit_meminit(struct nvkm_devinit *devinit) +nv04_devinit_meminit(struct nvkm_devinit *init) { - struct nv04_devinit *init = (void *)devinit; + struct nvkm_device *device = init->subdev.device; u32 patt = 0xdeadbeef; struct io_mapping *fb; int i; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(init)); + fb = fbmem_init(device); if (!fb) { nv_error(init, "failed to map fb\n"); return; @@ -49,9 +49,9 @@ nv04_devinit_meminit(struct nvkm_devinit *devinit) /* Sequencer and refresh off */ nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) | 0x20); - nv_mask(init, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); + nvkm_mask(device, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); - nv_mask(init, NV04_PFB_BOOT_0, ~0, + nvkm_mask(device, NV04_PFB_BOOT_0, ~0, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB | NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT); @@ -62,48 +62,48 @@ nv04_devinit_meminit(struct nvkm_devinit *devinit) fbmem_poke(fb, 0x400000, patt + 1); if (fbmem_peek(fb, 0) == patt + 1) { - nv_mask(init, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT); - nv_mask(init, NV04_PFB_DEBUG_0, + nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff)) - nv_mask(init, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); } else if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) { - nv_mask(init, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128 | NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); } else if (fbmem_peek(fb, 0) != patt) { if (fbmem_readback(fb, 0x800000, patt)) - nv_mask(init, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); else - nv_mask(init, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); - nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE, NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT); } else if (!fbmem_readback(fb, 0x800000, patt)) { - nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); } /* Refresh on, sequencer on */ - nv_mask(init, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) & ~0x20); fbmem_fini(fb); } @@ -139,11 +139,12 @@ powerctrl_1_shift(int chip_version, int reg) } void -setPLL_single(struct nvkm_devinit *devinit, u32 reg, +setPLL_single(struct nvkm_devinit *init, u32 reg, struct nvkm_pll_vals *pv) { - int chip_version = nvkm_bios(devinit)->version.chip; - uint32_t oldpll = nv_rd32(devinit, reg); + struct nvkm_device *device = init->subdev.device; + int chip_version = device->bios->version.chip; + uint32_t oldpll = nvkm_rd32(device, reg); int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff; uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1; uint32_t saved_powerctrl_1 = 0; @@ -153,30 +154,30 @@ setPLL_single(struct nvkm_devinit *devinit, u32 reg, return; /* already set */ if (shift_powerctrl_1 >= 0) { - saved_powerctrl_1 = nv_rd32(devinit, 0x001584); - nv_wr32(devinit, 0x001584, + saved_powerctrl_1 = nvkm_rd32(device, 0x001584); + nvkm_wr32(device, 0x001584, (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | 1 << shift_powerctrl_1); } if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1)) /* upclock -- write new post divider first */ - nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff)); + nvkm_wr32(device, reg, pv->log2P << 16 | (oldpll & 0xffff)); else /* downclock -- write new NM first */ - nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1); + nvkm_wr32(device, reg, (oldpll & 0xffff0000) | pv->NM1); if ((chip_version < 0x17 || chip_version == 0x1a) && chip_version != 0x11) /* wait a bit on older chips */ msleep(64); - nv_rd32(devinit, reg); + nvkm_rd32(device, reg); /* then write the other half as well */ - nv_wr32(devinit, reg, pll); + nvkm_wr32(device, reg, pll); if (shift_powerctrl_1 >= 0) - nv_wr32(devinit, 0x001584, saved_powerctrl_1); + nvkm_wr32(device, 0x001584, saved_powerctrl_1); } static uint32_t @@ -193,14 +194,15 @@ new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580) } void -setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, +setPLL_double_highregs(struct nvkm_devinit *init, u32 reg1, struct nvkm_pll_vals *pv) { - int chip_version = nvkm_bios(devinit)->version.chip; + struct nvkm_device *device = init->subdev.device; + int chip_version = device->bios->version.chip; bool nv3035 = chip_version == 0x30 || chip_version == 0x35; uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70); - uint32_t oldpll1 = nv_rd32(devinit, reg1); - uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0; + uint32_t oldpll1 = nvkm_rd32(device, reg1); + uint32_t oldpll2 = !nv3035 ? nvkm_rd32(device, reg2) : 0; uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1; uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2; uint32_t oldramdac580 = 0, ramdac580 = 0; @@ -215,7 +217,7 @@ setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, pll2 = 0; } if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */ - oldramdac580 = nv_rd32(devinit, 0x680580); + oldramdac580 = nvkm_rd32(device, 0x680580); ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580); if (oldramdac580 != ramdac580) oldpll1 = ~0; /* force mismatch */ @@ -231,8 +233,8 @@ setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, return; /* already set */ if (shift_powerctrl_1 >= 0) { - saved_powerctrl_1 = nv_rd32(devinit, 0x001584); - nv_wr32(devinit, 0x001584, + saved_powerctrl_1 = nvkm_rd32(device, 0x001584); + nvkm_wr32(device, 0x001584, (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) | 1 << shift_powerctrl_1); } @@ -251,26 +253,26 @@ setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1, shift_c040 += 2; } - savedc040 = nv_rd32(devinit, 0xc040); + savedc040 = nvkm_rd32(device, 0xc040); if (shift_c040 != 14) - nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040)); + nvkm_wr32(device, 0xc040, savedc040 & ~(3 << shift_c040)); } if (oldramdac580 != ramdac580) - nv_wr32(devinit, 0x680580, ramdac580); + nvkm_wr32(device, 0x680580, ramdac580); if (!nv3035) - nv_wr32(devinit, reg2, pll2); - nv_wr32(devinit, reg1, pll1); + nvkm_wr32(device, reg2, pll2); + nvkm_wr32(device, reg1, pll1); if (shift_powerctrl_1 >= 0) - nv_wr32(devinit, 0x001584, saved_powerctrl_1); + nvkm_wr32(device, 0x001584, saved_powerctrl_1); if (chip_version >= 0x40) - nv_wr32(devinit, 0xc040, savedc040); + nvkm_wr32(device, 0xc040, savedc040); } void -setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, +setPLL_double_lowregs(struct nvkm_devinit *init, u32 NMNMreg, struct nvkm_pll_vals *pv) { /* When setting PLLs, there is a merry game of disabling and enabling @@ -280,10 +282,10 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, * combined herein. Without luck it deviates from each card's formula * so as to not work on any :) */ - + struct nvkm_device *device = init->subdev.device; uint32_t Preg = NMNMreg - 4; bool mpll = Preg == 0x4020; - uint32_t oldPval = nv_rd32(devinit, Preg); + uint32_t oldPval = nvkm_rd32(device, Preg); uint32_t NMNM = pv->NM2 << 16 | pv->NM1; uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) | 0xc << 28 | pv->log2P << 16; @@ -292,7 +294,7 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, uint32_t maskc040 = ~(3 << 14), savedc040; bool single_stage = !pv->NM2 || pv->N2 == pv->M2; - if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) + if (nvkm_rd32(device, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval) return; if (Preg == 0x4000) @@ -304,7 +306,7 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, struct nvbios_pll info; uint8_t Pval2; - if (nvbios_pll_parse(nvkm_bios(devinit), Preg, &info)) + if (nvbios_pll_parse(device->bios, Preg, &info)) return; Pval2 = pv->log2P + info.bias_p; @@ -312,40 +314,40 @@ setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg, Pval2 = info.max_p; Pval |= 1 << 28 | Pval2 << 20; - saved4600 = nv_rd32(devinit, 0x4600); - nv_wr32(devinit, 0x4600, saved4600 | 8 << 28); + saved4600 = nvkm_rd32(device, 0x4600); + nvkm_wr32(device, 0x4600, saved4600 | 8 << 28); } if (single_stage) Pval |= mpll ? 1 << 12 : 1 << 8; - nv_wr32(devinit, Preg, oldPval | 1 << 28); - nv_wr32(devinit, Preg, Pval & ~(4 << 28)); + nvkm_wr32(device, Preg, oldPval | 1 << 28); + nvkm_wr32(device, Preg, Pval & ~(4 << 28)); if (mpll) { Pval |= 8 << 20; - nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28)); - nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28)); + nvkm_wr32(device, 0x4020, Pval & ~(0xc << 28)); + nvkm_wr32(device, 0x4038, Pval & ~(0xc << 28)); } - savedc040 = nv_rd32(devinit, 0xc040); - nv_wr32(devinit, 0xc040, savedc040 & maskc040); + savedc040 = nvkm_rd32(device, 0xc040); + nvkm_wr32(device, 0xc040, savedc040 & maskc040); - nv_wr32(devinit, NMNMreg, NMNM); + nvkm_wr32(device, NMNMreg, NMNM); if (NMNMreg == 0x4024) - nv_wr32(devinit, 0x403c, NMNM); + nvkm_wr32(device, 0x403c, NMNM); - nv_wr32(devinit, Preg, Pval); + nvkm_wr32(device, Preg, Pval); if (mpll) { Pval &= ~(8 << 20); - nv_wr32(devinit, 0x4020, Pval); - nv_wr32(devinit, 0x4038, Pval); - nv_wr32(devinit, 0x4600, saved4600); + nvkm_wr32(device, 0x4020, Pval); + nvkm_wr32(device, 0x4038, Pval); + nvkm_wr32(device, 0x4600, saved4600); } - nv_wr32(devinit, 0xc040, savedc040); + nvkm_wr32(device, 0xc040, savedc040); if (mpll) { - nv_wr32(devinit, 0x4020, Pval & ~(1 << 28)); - nv_wr32(devinit, 0x4038, Pval & ~(1 << 28)); + nvkm_wr32(device, 0x4020, Pval & ~(1 << 28)); + nvkm_wr32(device, 0x4038, Pval & ~(1 << 28)); } } @@ -391,10 +393,11 @@ int nv04_devinit_fini(struct nvkm_object *object, bool suspend) { struct nv04_devinit *init = (void *)object; + struct nvkm_device *device = init->base.subdev.device; int ret; /* make i2c busses accessible */ - nv_mask(init, 0x000200, 0x00000001, 0x00000001); + nvkm_mask(device, 0x000200, 0x00000001, 0x00000001); ret = nvkm_devinit_fini(&init->base, suspend); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index 2659b9c37df4b..3fb789b5050ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -32,7 +32,7 @@ #include static void -nv05_devinit_meminit(struct nvkm_devinit *devinit) +nv05_devinit_meminit(struct nvkm_devinit *init) { static const u8 default_config_tab[][2] = { { 0x24, 0x00 }, @@ -44,8 +44,8 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) { 0x06, 0x00 }, { 0x00, 0x00 } }; - struct nv04_devinit *init = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_device *device = init->subdev.device; + struct nvkm_bios *bios = device->bios; struct io_mapping *fb; u32 patt = 0xdeadbeef; u16 data; @@ -53,13 +53,13 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) int i, v; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(init)); + fb = fbmem_init(device); if (!fb) { nv_error(init, "failed to map fb\n"); return; } - strap = (nv_rd32(init, 0x101000) & 0x0000003c) >> 2; + strap = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; if ((data = bmp_mem_init_table(bios))) { ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0); ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1); @@ -71,52 +71,52 @@ nv05_devinit_meminit(struct nvkm_devinit *devinit) /* Sequencer off */ nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) | 0x20); - if (nv_rd32(init, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) + if (nvkm_rd32(device, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) goto out; - nv_mask(init, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); + nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); /* If present load the hardcoded scrambling table */ if (data) { for (i = 0, data += 0x10; i < 8; i++, data += 4) { u32 scramble = nv_ro32(bios, data); - nv_wr32(init, NV04_PFB_SCRAMBLE(i), scramble); + nvkm_wr32(device, NV04_PFB_SCRAMBLE(i), scramble); } } /* Set memory type/width/length defaults depending on the straps */ - nv_mask(init, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); + nvkm_mask(device, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]); if (ramcfg[1] & 0x80) - nv_mask(init, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); + nvkm_mask(device, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE); - nv_mask(init, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); - nv_mask(init, NV04_PFB_CFG1, 0, 1); + nvkm_mask(device, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20); + nvkm_mask(device, NV04_PFB_CFG1, 0, 1); /* Probe memory bus width */ for (i = 0; i < 4; i++) fbmem_poke(fb, 4 * i, patt); if (fbmem_peek(fb, 0xc) != patt) - nv_mask(init, NV04_PFB_BOOT_0, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_WIDTH_128, 0); /* Probe memory length */ - v = nv_rd32(init, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; + v = nvkm_rd32(device, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT; if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB && (!fbmem_readback(fb, 0x1000000, ++patt) || !fbmem_readback(fb, 0, ++patt))) - nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_16MB); if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB && !fbmem_readback(fb, 0x800000, ++patt)) - nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_8MB); if (!fbmem_readback(fb, 0x400000, ++patt)) - nv_mask(init, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, + nvkm_mask(device, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT, NV04_PFB_BOOT_0_RAM_AMOUNT_4MB); out: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c index bbf791eaa0ab7..f0d47d1ce2a13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c @@ -30,33 +30,32 @@ #include static void -nv10_devinit_meminit(struct nvkm_devinit *devinit) +nv10_devinit_meminit(struct nvkm_devinit *init) { - struct nv04_devinit *init = (void *)devinit; + struct nvkm_device *device = init->subdev.device; static const int mem_width[] = { 0x10, 0x00, 0x20 }; int mem_width_count; uint32_t patt = 0xdeadbeef; struct io_mapping *fb; int i, j, k; - if (nv_device(init)->card_type >= NV_11 && - nv_device(init)->chipset >= 0x17) + if (device->card_type >= NV_11 && device->chipset >= 0x17) mem_width_count = 3; else mem_width_count = 2; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(init)); + fb = fbmem_init(device); if (!fb) { nv_error(init, "failed to map fb\n"); return; } - nv_wr32(init, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + nvkm_wr32(device, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Probe memory bus width */ for (i = 0; i < mem_width_count; i++) { - nv_mask(init, NV04_PFB_CFG0, 0x30, mem_width[i]); + nvkm_mask(device, NV04_PFB_CFG0, 0x30, mem_width[i]); for (j = 0; j < 4; j++) { for (k = 0; k < 4; k++) @@ -75,7 +74,7 @@ mem_width_found: /* Probe amount of installed memory */ for (i = 0; i < 4; i++) { - int off = nv_rd32(init, 0x10020c) - 0x100000; + int off = nvkm_rd32(device, 0x10020c) - 0x100000; fbmem_poke(fb, off, patt); fbmem_poke(fb, 0, 0); @@ -90,7 +89,7 @@ mem_width_found: } /* IC missing - disable the upper half memory space. */ - nv_mask(init, NV04_PFB_CFG0, 0x1000, 0); + nvkm_mask(device, NV04_PFB_CFG0, 0x1000, 0); amount_found: fbmem_fini(fb); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c index 50f9849cdfb59..29ea11f8482d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c @@ -45,19 +45,19 @@ nv20_devinit_meminit(struct nvkm_devinit *devinit) return; } - nv_wr32(init, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); + nvkm_wr32(device, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1); /* Allow full addressing */ - nv_mask(init, NV04_PFB_CFG0, 0, mask); + nvkm_mask(device, NV04_PFB_CFG0, 0, mask); - amount = nv_rd32(init, 0x10020c); + amount = nvkm_rd32(device, 0x10020c); for (off = amount; off > 0x2000000; off -= 0x2000000) fbmem_poke(fb, off - 4, off); - amount = nv_rd32(init, 0x10020c); + amount = nvkm_rd32(device, 0x10020c); if (amount != fbmem_peek(fb, amount - 4)) /* IC missing - disable the upper half memory space. */ - nv_mask(init, NV04_PFB_CFG0, mask, 0); + nvkm_mask(device, NV04_PFB_CFG0, mask, 0); fbmem_fini(fb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index 8e9633096bece..2533e96be7dfc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -33,43 +33,45 @@ #include int -nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) +nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) { - struct nv50_devinit *init = (void *)devinit; - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct nvbios_pll info; int N1, M1, N2, M2, P; int ret; ret = nvbios_pll_parse(bios, type, &info); if (ret) { - nv_error(devinit, "failed to retrieve pll data, %d\n", ret); + nv_error(subdev, "failed to retrieve pll data, %d\n", ret); return ret; } - ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P); + ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) { - nv_error(devinit, "failed pll calculation\n"); + nv_error(subdev, "failed pll calculation\n"); return ret; } switch (info.type) { case PLL_VPLL0: case PLL_VPLL1: - nv_wr32(init, info.reg + 0, 0x10000611); - nv_mask(init, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); - nv_mask(init, info.reg + 8, 0x7fff00ff, (P << 28) | - (M2 << 16) | N2); + nvkm_wr32(device, info.reg + 0, 0x10000611); + nvkm_mask(device, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1); + nvkm_mask(device, info.reg + 8, 0x7fff00ff, (P << 28) | + (M2 << 16) | N2); break; case PLL_MEMORY: - nv_mask(init, info.reg + 0, 0x01ff0000, (P << 22) | - (info.bias_p << 19) | - (P << 16)); - nv_wr32(init, info.reg + 4, (N1 << 8) | M1); + nvkm_mask(device, info.reg + 0, 0x01ff0000, + (P << 22) | + (info.bias_p << 19) | + (P << 16)); + nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); break; default: - nv_mask(init, info.reg + 0, 0x00070000, (P << 16)); - nv_wr32(init, info.reg + 4, (N1 << 8) | M1); + nvkm_mask(device, info.reg + 0, 0x00070000, (P << 16)); + nvkm_wr32(device, info.reg + 4, (N1 << 8) | M1); break; } @@ -77,10 +79,10 @@ nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } static u64 -nv50_devinit_disable(struct nvkm_devinit *devinit) +nv50_devinit_disable(struct nvkm_devinit *init) { - struct nv50_devinit *init = (void *)devinit; - u32 r001540 = nv_rd32(init, 0x001540); + struct nvkm_device *device = init->subdev.device; + u32 r001540 = nvkm_rd32(device, 0x001540); u64 disable = 0ULL; if (!(r001540 & 0x40000000)) -- GitLab From 6758745b2821bddcec1aae0c4cffaa9608aeda59 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5365/7006] drm/nouveau/fb: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 8 ++- .../gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c | 9 +-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c | 11 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c | 13 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c | 14 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c | 14 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 13 ++-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h | 4 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 51 +++++++------- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 61 +++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 66 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c | 18 ++--- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c | 9 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 64 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c | 9 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c | 9 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 31 +++++---- 25 files changed, 236 insertions(+), 196 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 8bd560d61bd8c..be18420572268 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -29,7 +29,8 @@ int nvkm_fb_bios_memtype(struct nvkm_bios *bios) { - const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2; + struct nvkm_device *device = bios->subdev.device; + const u8 ramcfg = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; struct nvbios_M0203E M0203E; u8 ver, hdr; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index db6bbb4391762..0c80d94985808 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -35,8 +35,9 @@ gf100_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) static void gf100_fb_intr(struct nvkm_subdev *subdev) { + struct nvkm_device *device = subdev->device; struct gf100_fb *fb = (void *)subdev; - u32 intr = nv_rd32(fb, 0x000100); + u32 intr = nvkm_rd32(device, 0x000100); if (intr & 0x08000000) nv_debug(fb, "PFFB intr\n"); if (intr & 0x00002000) @@ -47,6 +48,7 @@ int gf100_fb_init(struct nvkm_object *object) { struct gf100_fb *fb = (void *)object; + struct nvkm_device *device = fb->base.subdev.device; int ret; ret = nvkm_fb_init(&fb->base); @@ -54,9 +56,9 @@ gf100_fb_init(struct nvkm_object *object) return ret; if (fb->r100c10_page) - nv_wr32(fb, 0x100c10, fb->r100c10 >> 8); + nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); - nv_mask(fb, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index 91c0409312cf1..24cbe90afec16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -25,13 +25,14 @@ static int gk20a_fb_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object; + struct nvkm_device *device = fb->subdev.device; int ret; ret = nvkm_fb_init(fb); if (ret) return ret; - nv_mask(fb, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ + nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c index 9e55308c99456..7fb578fb8a571 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c @@ -37,6 +37,7 @@ static int nv04_fb_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object; + struct nvkm_device *device = fb->subdev.device; int ret; ret = nvkm_fb_init(fb); @@ -47,7 +48,7 @@ nv04_fb_init(struct nvkm_object *object) * nvidia reading PFB_CFG_0, then writing back its original value. * (which was 0x701114 in this case) */ - nv_wr32(fb, NV04_PFB_CFG0, 0x1114); + nvkm_wr32(device, NV04_PFB_CFG0, 0x1114); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c index b657ddc1e0132..a52cc6c718c21 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c @@ -46,10 +46,11 @@ nv10_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) void nv10_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(fb, 0x100244 + (i * 0x10), tile->limit); - nv_wr32(fb, 0x100248 + (i * 0x10), tile->pitch); - nv_wr32(fb, 0x100240 + (i * 0x10), tile->addr); - nv_rd32(fb, 0x100240 + (i * 0x10)); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100244 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100248 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100240 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100240 + (i * 0x10)); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c index b1b50a41f161b..f1f3fe5ad46ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c @@ -68,11 +68,12 @@ nv20_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) void nv20_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(fb, 0x100244 + (i * 0x10), tile->limit); - nv_wr32(fb, 0x100248 + (i * 0x10), tile->pitch); - nv_wr32(fb, 0x100240 + (i * 0x10), tile->addr); - nv_rd32(fb, 0x100240 + (i * 0x10)); - nv_wr32(fb, 0x100300 + (i * 0x04), tile->zcomp); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100244 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100248 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100240 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100240 + (i * 0x10)); + nvkm_wr32(device, 0x100300 + (i * 0x04), tile->zcomp); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c index 40c3962848155..3a6da4ee407ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c @@ -66,7 +66,8 @@ calc_bias(struct nvkm_fb *fb, int k, int i, int j) { struct nvkm_device *device = nv_device(fb); int b = (device->chipset > 0x30 ? - nv_rd32(fb, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : + nvkm_rd32(device, 0x122c + 0x10 * k + 0x4 * j) >> + (4 * (i ^ 1)) : 0) & 0xf; return 2 * (b & 0x8 ? b - 0x10 : b); @@ -103,16 +104,16 @@ nv30_fb_init(struct nvkm_object *object) device->chipset == 0x35) { /* Related to ROP count */ int n = (device->chipset == 0x31 ? 2 : 4); - int l = nv_rd32(fb, 0x1003d0); + int l = nvkm_rd32(device, 0x1003d0); for (i = 0; i < n; i++) { for (j = 0; j < 3; j++) - nv_wr32(fb, 0x10037c + 0xc * i + 0x4 * j, - calc_ref(fb, l, 0, j)); + nvkm_wr32(device, 0x10037c + 0xc * i + 0x4 * j, + calc_ref(fb, l, 0, j)); for (j = 0; j < 2; j++) - nv_wr32(fb, 0x1003ac + 0x8 * i + 0x4 * j, - calc_ref(fb, l, 1, j)); + nvkm_wr32(device, 0x1003ac + 0x8 * i + 0x4 * j, + calc_ref(fb, l, 1, j)); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c index fe4ae2d7bfcbf..fa02bcba36ca3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c @@ -46,13 +46,14 @@ static int nv40_fb_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object; + struct nvkm_device *device = fb->subdev.device; int ret; ret = nvkm_fb_init(fb); if (ret) return ret; - nv_mask(fb, 0x10033c, 0x00008000, 0x00000000); + nvkm_mask(device, 0x10033c, 0x00008000, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c index ba0e6e327b6cf..568810536d6f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c @@ -28,24 +28,26 @@ void nv41_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(fb, 0x100604 + (i * 0x10), tile->limit); - nv_wr32(fb, 0x100608 + (i * 0x10), tile->pitch); - nv_wr32(fb, 0x100600 + (i * 0x10), tile->addr); - nv_rd32(fb, 0x100600 + (i * 0x10)); - nv_wr32(fb, 0x100700 + (i * 0x04), tile->zcomp); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100604 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100608 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100600 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100600 + (i * 0x10)); + nvkm_wr32(device, 0x100700 + (i * 0x04), tile->zcomp); } int nv41_fb_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object; + struct nvkm_device *device = fb->subdev.device; int ret; ret = nvkm_fb_init(fb); if (ret) return ret; - nv_wr32(fb, 0x100800, 0x00000001); + nvkm_wr32(device, 0x100800, 0x00000001); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c index d6b917f709102..9b76716982e68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c @@ -38,24 +38,26 @@ nv44_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, void nv44_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) { - nv_wr32(fb, 0x100604 + (i * 0x10), tile->limit); - nv_wr32(fb, 0x100608 + (i * 0x10), tile->pitch); - nv_wr32(fb, 0x100600 + (i * 0x10), tile->addr); - nv_rd32(fb, 0x100600 + (i * 0x10)); + struct nvkm_device *device = fb->subdev.device; + nvkm_wr32(device, 0x100604 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x100608 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x100600 + (i * 0x10), tile->addr); + nvkm_rd32(device, 0x100600 + (i * 0x10)); } int nv44_fb_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object; + struct nvkm_device *device = fb->subdev.device; int ret; ret = nvkm_fb_init(fb); if (ret) return ret; - nv_wr32(fb, 0x100850, 0x80000000); - nv_wr32(fb, 0x100800, 0x00000001); + nvkm_wr32(device, 0x100850, 0x80000000); + nvkm_wr32(device, 0x100800, 0x00000001); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 093d2a0ae152e..047e34ac86af6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -153,16 +153,16 @@ nv50_fb_intr(struct nvkm_subdev *subdev) u8 st0, st1, st2, st3; int i; - idx = nv_rd32(fb, 0x100c90); + idx = nvkm_rd32(device, 0x100c90); if (!(idx & 0x80000000)) return; idx &= 0x00ffffff; for (i = 0; i < 6; i++) { - nv_wr32(fb, 0x100c90, idx | i << 24); - trap[i] = nv_rd32(fb, 0x100c94); + nvkm_wr32(device, 0x100c90, idx | i << 24); + trap[i] = nvkm_rd32(device, 0x100c94); } - nv_wr32(fb, 0x100c90, idx | 0x80000000); + nvkm_wr32(device, 0x100c90, idx | 0x80000000); /* decode status bits into something more useful */ if (device->chipset < 0xa3 || @@ -286,6 +286,7 @@ nv50_fb_init(struct nvkm_object *object) { struct nv50_fb_impl *impl = (void *)object->oclass; struct nv50_fb *fb = (void *)object; + struct nvkm_device *device = fb->base.subdev.device; int ret; ret = nvkm_fb_init(&fb->base); @@ -296,11 +297,11 @@ nv50_fb_init(struct nvkm_object *object) * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) * cause IOMMU "read from address 0" errors (rh#561267) */ - nv_wr32(fb, 0x100c08, fb->r100c08 >> 8); + nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8); /* This is needed to get meaningful information from 100c90 * on traps. No idea what these values mean exactly. */ - nv_wr32(fb, 0x100c90, impl->trap); + nvkm_wr32(device, 0x100c90, impl->trap); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h index 72ffb3a4a5d72..60d8ed4b78b2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h @@ -1,5 +1,6 @@ #ifndef __NVKM_FBRAM_FUC_H__ #define __NVKM_FBRAM_FUC_H__ +#include #include struct ramfuc { @@ -82,8 +83,9 @@ ramfuc_exec(struct ramfuc *ram, bool exec) static inline u32 ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg) { + struct nvkm_device *device = ram->fb->subdev.device; if (reg->sequence != ram->sequence) - reg->data = nv_rd32(ram->fb, reg->addr); + reg->data = nvkm_rd32(device, reg->addr); return reg->data; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index ad1ce222b28f0..6450799986c69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -108,8 +108,9 @@ gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) { struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc); struct nvkm_fb *fb = nvkm_fb(ram); - u32 part = nv_rd32(fb, 0x022438), i; - u32 mask = nv_rd32(fb, 0x022554); + struct nvkm_device *device = fb->subdev.device; + u32 part = nvkm_rd32(device, 0x022438), i; + u32 mask = nvkm_rd32(device, 0x022554); u32 addr = 0x110974; ram_wr32(fuc, 0x10f910, magic); @@ -507,13 +508,14 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, void **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_ram *ram; const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - u32 parts = nv_rd32(fb, 0x022438); - u32 pmask = nv_rd32(fb, maskaddr); - u32 bsize = nv_rd32(fb, 0x10f20c); + u32 parts = nvkm_rd32(device, 0x022438); + u32 pmask = nvkm_rd32(device, maskaddr); + u32 bsize = nvkm_rd32(device, 0x10f20c); u32 offset, length; bool uniform = true; int ret, part; @@ -523,24 +525,24 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_debug(fb, "0x100800: 0x%08x\n", nv_rd32(fb, 0x100800)); + nv_debug(fb, "0x100800: 0x%08x\n", nvkm_rd32(device, 0x100800)); nv_debug(fb, "parts 0x%08x mask 0x%08x\n", parts, pmask); ram->type = nvkm_fb_bios_memtype(bios); - ram->ranks = (nv_rd32(fb, 0x10f200) & 0x00000004) ? 2 : 1; + ram->ranks = (nvkm_rd32(device, 0x10f200) & 0x00000004) ? 2 : 1; /* read amount of vram attached to each memory controller */ for (part = 0; part < parts; part++) { if (!(pmask & (1 << part))) { - u32 psize = nv_rd32(fb, 0x11020c + (part * 0x1000)); - if (psize != bsize) { - if (psize < bsize) - bsize = psize; + u32 size = nvkm_rd32(device, 0x11020c + (part * 0x1000)); + if (size != bsize) { + if (size < bsize) + bsize = size; uniform = false; } - nv_debug(fb, "%d: mem_amount 0x%08x\n", part, psize); - ram->size += (u64)psize << 20; + nv_debug(fb, "%d: mem_amount 0x%08x\n", part, size); + ram->size += (u64)size << 20; } } @@ -577,6 +579,7 @@ static int gf100_ram_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object->parent; + struct nvkm_device *device = fb->subdev.device; struct gf100_ram *ram = (void *)object; int ret, i; @@ -601,16 +604,16 @@ gf100_ram_init(struct nvkm_object *object) }; for (i = 0; i < 0x30; i++) { - nv_wr32(fb, 0x10f968, 0x00000000 | (i << 8)); - nv_wr32(fb, 0x10f96c, 0x00000000 | (i << 8)); - nv_wr32(fb, 0x10f920, 0x00000100 | train0[i % 12]); - nv_wr32(fb, 0x10f924, 0x00000100 | train0[i % 12]); - nv_wr32(fb, 0x10f918, train1[i % 12]); - nv_wr32(fb, 0x10f91c, train1[i % 12]); - nv_wr32(fb, 0x10f920, 0x00000000 | train0[i % 12]); - nv_wr32(fb, 0x10f924, 0x00000000 | train0[i % 12]); - nv_wr32(fb, 0x10f918, train1[i % 12]); - nv_wr32(fb, 0x10f91c, train1[i % 12]); + nvkm_wr32(device, 0x10f968, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f96c, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f920, 0x00000100 | train0[i % 12]); + nvkm_wr32(device, 0x10f924, 0x00000100 | train0[i % 12]); + nvkm_wr32(device, 0x10f918, train1[i % 12]); + nvkm_wr32(device, 0x10f91c, train1[i % 12]); + nvkm_wr32(device, 0x10f920, 0x00000000 | train0[i % 12]); + nvkm_wr32(device, 0x10f924, 0x00000000 | train0[i % 12]); + nvkm_wr32(device, 0x10f918, train1[i % 12]); + nvkm_wr32(device, 0x10f91c, train1[i % 12]); } } break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index e9f3ee344a17c..5d6ae5c9bf4bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -228,8 +228,9 @@ static void gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, u32 _mask, u32 _data, u32 _copy) { - struct gk104_fb *fb = (void *)nvkm_fb(ram); + struct nvkm_fb *fb = nvkm_fb(ram); struct ramfuc *fuc = &ram->fuc.base; + struct nvkm_device *device = fb->subdev.device; u32 addr = 0x110000 + (reg->addr & 0xfff); u32 mask = _mask | _copy; u32 data = (_data & _mask) | (reg->data & _copy); @@ -237,7 +238,7 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, for (i = 0; i < 16; i++, addr += 0x1000) { if (ram->pnuts & (1 << i)) { - u32 prev = nv_rd32(fb, addr); + u32 prev = nvkm_rd32(device, addr); u32 next = (prev & ~mask) | data; nvkm_memx_wr32(fuc->memx, addr, next); } @@ -1067,6 +1068,7 @@ gk104_ram_calc(struct nvkm_fb *fb, u32 freq) static void gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) { + struct nvkm_device *device = fb->subdev.device; struct gk104_ram *ram = (void *)fb->ram; struct nvkm_ram_data *cfg; u32 mhz = freq / 1000; @@ -1089,31 +1091,31 @@ gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) data |= cfg->bios.rammap_11_09_01ff; mask |= 0x000001ff; } - nv_mask(fb, 0x10f468, mask, data); + nvkm_mask(device, 0x10f468, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) { data |= cfg->bios.rammap_11_0a_0400; mask |= 0x00000001; } - nv_mask(fb, 0x10f420, mask, data); + nvkm_mask(device, 0x10f420, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) { data |= cfg->bios.rammap_11_0a_0800; mask |= 0x00000001; } - nv_mask(fb, 0x10f430, mask, data); + nvkm_mask(device, 0x10f430, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) { data |= cfg->bios.rammap_11_0b_01f0; mask |= 0x0000001f; } - nv_mask(fb, 0x10f400, mask, data); + nvkm_mask(device, 0x10f400, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) { data |= cfg->bios.rammap_11_0b_0200 << 9; mask |= 0x00000200; } - nv_mask(fb, 0x10f410, mask, data); + nvkm_mask(device, 0x10f410, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0d) { data |= cfg->bios.rammap_11_0d << 16; @@ -1123,7 +1125,7 @@ gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) data |= cfg->bios.rammap_11_0f << 8; mask |= 0x0000ff00; } - nv_mask(fb, 0x10f440, mask, data); + nvkm_mask(device, 0x10f440, mask, data); if (mask = 0, data = 0, ram->diff.rammap_11_0e) { data |= cfg->bios.rammap_11_0e << 8; @@ -1137,7 +1139,7 @@ gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) data |= cfg->bios.rammap_11_0b_0400 << 5; mask |= 0x00000020; } - nv_mask(fb, 0x10f444, mask, data); + nvkm_mask(device, 0x10f444, mask, data); } static int @@ -1245,6 +1247,7 @@ gk104_ram_train_type(struct nvkm_fb *fb, int i, u8 ramcfg, static int gk104_ram_train_init_0(struct nvkm_fb *fb, struct gk104_ram_train *train) { + struct nvkm_device *device = fb->subdev.device; int i, j; if ((train->mask & 0x03d3) != 0x03d3) { @@ -1254,22 +1257,22 @@ gk104_ram_train_init_0(struct nvkm_fb *fb, struct gk104_ram_train *train) for (i = 0; i < 0x30; i++) { for (j = 0; j < 8; j += 4) { - nv_wr32(fb, 0x10f968 + j, 0x00000000 | (i << 8)); - nv_wr32(fb, 0x10f920 + j, 0x00000000 | + nvkm_wr32(device, 0x10f968 + j, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f920 + j, 0x00000000 | train->type08.data[i] << 4 | train->type06.data[i]); - nv_wr32(fb, 0x10f918 + j, train->type00.data[i]); - nv_wr32(fb, 0x10f920 + j, 0x00000100 | + nvkm_wr32(device, 0x10f918 + j, train->type00.data[i]); + nvkm_wr32(device, 0x10f920 + j, 0x00000100 | train->type09.data[i] << 4 | train->type07.data[i]); - nv_wr32(fb, 0x10f918 + j, train->type01.data[i]); + nvkm_wr32(device, 0x10f918 + j, train->type01.data[i]); } } for (j = 0; j < 8; j += 4) { for (i = 0; i < 0x100; i++) { - nv_wr32(fb, 0x10f968 + j, i); - nv_wr32(fb, 0x10f900 + j, train->type04.data[i]); + nvkm_wr32(device, 0x10f968 + j, i); + nvkm_wr32(device, 0x10f900 + j, train->type04.data[i]); } } @@ -1310,7 +1313,8 @@ gk104_ram_init(struct nvkm_object *object) { struct nvkm_fb *fb = (void *)object->parent; struct gk104_ram *ram = (void *)object; - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; u8 ver, hdr, cnt, len, snr, ssz; u32 data, save; int ret, i; @@ -1336,10 +1340,10 @@ gk104_ram_init(struct nvkm_object *object) cnt = nv_ro08(bios, data + 0x14); /* guess at count */ data = nv_ro32(bios, data + 0x10); /* guess u32... */ - save = nv_rd32(fb, 0x10f65c) & 0x000000f0; + save = nvkm_rd32(device, 0x10f65c) & 0x000000f0; for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) { - nv_mask(fb, 0x10f65c, 0x000000f0, i << 4); + nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4); nvbios_exec(&(struct nvbios_init) { .subdev = nv_subdev(fb), .bios = bios, @@ -1348,10 +1352,10 @@ gk104_ram_init(struct nvkm_object *object) }); } } - nv_mask(fb, 0x10f65c, 0x000000f0, save); - nv_mask(fb, 0x10f584, 0x11000000, 0x00000000); - nv_wr32(fb, 0x10ecc0, 0xffffffff); - nv_mask(fb, 0x10f160, 0x00000010, 0x00000010); + nvkm_mask(device, 0x10f65c, 0x000000f0, save); + nvkm_mask(device, 0x10f584, 0x11000000, 0x00000000); + nvkm_wr32(device, 0x10ecc0, 0xffffffff); + nvkm_mask(device, 0x10f160, 0x00000010, 0x00000010); return gk104_ram_train_init(fb); } @@ -1445,8 +1449,9 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_bios *bios = nvkm_bios(fb); - struct nvkm_gpio *gpio = nvkm_gpio(fb); + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_gpio *gpio = device->gpio; struct dcb_gpio_func func; struct gk104_ram *ram; int ret, i; @@ -1477,12 +1482,12 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * already without having to treat some of them differently to * the others.... */ - ram->parts = nv_rd32(fb, 0x022438); - ram->pmask = nv_rd32(fb, 0x022554); + ram->parts = nvkm_rd32(device, 0x022438); + ram->pmask = nvkm_rd32(device, 0x022554); ram->pnuts = 0; for (i = 0, tmp = 0; i < ram->parts; i++) { if (!(ram->pmask & (1 << i))) { - u32 cfg1 = nv_rd32(fb, 0x110204 + (i * 0x1000)); + u32 cfg1 = nvkm_rd32(device, 0x110204 + (i * 0x1000)); if (tmp && tmp != cfg1) { ram->pnuts |= (1 << i); continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 2195e4be68eba..dc1dd03b6f597 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -198,12 +198,12 @@ gt215_link_train(struct nvkm_fb *fb) goto out; /* Do this *after* calc, eliminates write in script */ - nv_wr32(fb, 0x111400, 0x00000000); + nvkm_wr32(device, 0x111400, 0x00000000); /* XXX: Magic writes that improve train reliability? */ - nv_mask(fb, 0x100674, 0x0000ffff, 0x00000000); - nv_mask(fb, 0x1005e4, 0x0000ffff, 0x00000000); - nv_mask(fb, 0x100b0c, 0x000000ff, 0x00000000); - nv_wr32(fb, 0x100c04, 0x00000400); + nvkm_mask(device, 0x100674, 0x0000ffff, 0x00000000); + nvkm_mask(device, 0x1005e4, 0x0000ffff, 0x00000000); + nvkm_mask(device, 0x100b0c, 0x000000ff, 0x00000000); + nvkm_wr32(device, 0x100c04, 0x00000400); /* Now the training script */ r1700 = ram_rd32(fuc, 0x001700); @@ -240,8 +240,8 @@ gt215_link_train(struct nvkm_fb *fb) ram_exec(fuc, true); /* Post-processing, avoids flicker */ - nv_mask(fb, 0x616308, 0x10, 0x10); - nv_mask(fb, 0x616b08, 0x10, 0x10); + nvkm_mask(device, 0x616308, 0x10, 0x10); + nvkm_mask(device, 0x616b08, 0x10, 0x10); gt215_clk_post(clk, f); @@ -279,7 +279,8 @@ gt215_link_train_init(struct nvkm_fb *fb) 0x33333333, 0x55555555, 0x77777777, 0x66666666, 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, }; - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; struct gt215_ram *ram = (void *)fb->ram; struct gt215_ltrain *train = &ram->ltrain; struct nvkm_mem *mem; @@ -306,32 +307,32 @@ gt215_link_train_init(struct nvkm_fb *fb) mem = ram->ltrain.mem; - nv_wr32(fb, 0x100538, 0x10000000 | (mem->offset >> 16)); - nv_wr32(fb, 0x1005a8, 0x0000ffff); - nv_mask(fb, 0x10f800, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x100538, 0x10000000 | (mem->offset >> 16)); + nvkm_wr32(device, 0x1005a8, 0x0000ffff); + nvkm_mask(device, 0x10f800, 0x00000001, 0x00000001); for (i = 0; i < 0x30; i++) { - nv_wr32(fb, 0x10f8c0, (i << 8) | i); - nv_wr32(fb, 0x10f900, pattern[i % 16]); + nvkm_wr32(device, 0x10f8c0, (i << 8) | i); + nvkm_wr32(device, 0x10f900, pattern[i % 16]); } for (i = 0; i < 0x30; i++) { - nv_wr32(fb, 0x10f8e0, (i << 8) | i); - nv_wr32(fb, 0x10f920, pattern[i % 16]); + nvkm_wr32(device, 0x10f8e0, (i << 8) | i); + nvkm_wr32(device, 0x10f920, pattern[i % 16]); } /* And upload the pattern */ - r001700 = nv_rd32(fb, 0x1700); - nv_wr32(fb, 0x1700, mem->offset >> 16); + r001700 = nvkm_rd32(device, 0x1700); + nvkm_wr32(device, 0x1700, mem->offset >> 16); for (i = 0; i < 16; i++) - nv_wr32(fb, 0x700000 + (i << 2), pattern[i]); + nvkm_wr32(device, 0x700000 + (i << 2), pattern[i]); for (i = 0; i < 16; i++) - nv_wr32(fb, 0x700100 + (i << 2), pattern[i]); - nv_wr32(fb, 0x1700, r001700); + nvkm_wr32(device, 0x700100 + (i << 2), pattern[i]); + nvkm_wr32(device, 0x1700, r001700); - train->r_100720 = nv_rd32(fb, 0x100720); - train->r_1111e0 = nv_rd32(fb, 0x1111e0); - train->r_111400 = nv_rd32(fb, 0x111400); + train->r_100720 = nvkm_rd32(device, 0x100720); + train->r_1111e0 = nvkm_rd32(device, 0x1111e0); + train->r_111400 = nvkm_rd32(device, 0x111400); return 0; } @@ -351,15 +352,16 @@ gt215_link_train_fini(struct nvkm_fb *fb) static int gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) { + struct nvkm_device *device = fb->subdev.device; struct gt215_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; int tUNK_base, tUNK_40_0, prevCL; u32 cur2, cur3, cur7, cur8; - cur2 = nv_rd32(fb, 0x100228); - cur3 = nv_rd32(fb, 0x10022c); - cur7 = nv_rd32(fb, 0x10023c); - cur8 = nv_rd32(fb, 0x100240); + cur2 = nvkm_rd32(device, 0x100228); + cur3 = nvkm_rd32(device, 0x10022c); + cur7 = nvkm_rd32(device, 0x10023c); + cur8 = nvkm_rd32(device, 0x100240); switch ((!T(CWL)) * ram->base.type) { @@ -864,16 +866,16 @@ gt215_ram_prog(struct nvkm_fb *fb) bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true); if (exec) { - nv_mask(fb, 0x001534, 0x2, 0x2); + nvkm_mask(device, 0x001534, 0x2, 0x2); ram_exec(fuc, true); /* Post-processing, avoids flicker */ - nv_mask(fb, 0x002504, 0x1, 0x0); - nv_mask(fb, 0x001534, 0x2, 0x0); + nvkm_mask(device, 0x002504, 0x1, 0x0); + nvkm_mask(device, 0x001534, 0x2, 0x0); - nv_mask(fb, 0x616308, 0x10, 0x10); - nv_mask(fb, 0x616b08, 0x10, 0x10); + nvkm_mask(device, 0x616308, 0x10, 0x10); + nvkm_mask(device, 0x616b08, 0x10, 0x10); } else { ram_exec(fuc, false); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c index 7f378788d3e51..e1d82ab25dbc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c @@ -36,6 +36,7 @@ mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, u32 rsvd_head = ( 256 * 1024); /* vga memory */ u32 rsvd_tail = (1024 * 1024); /* vbios etc */ struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_device *device = fb->subdev.device; struct mcp77_ram *ram; int ret; @@ -45,8 +46,8 @@ mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; ram->base.type = NV_MEM_TYPE_STOLEN; - ram->base.stolen = (u64)nv_rd32(fb, 0x100e10) << 12; - ram->base.size = (u64)nv_rd32(fb, 0x100e14) << 12; + ram->base.stolen = (u64)nvkm_rd32(device, 0x100e10) << 12; + ram->base.size = (u64)nvkm_rd32(device, 0x100e14) << 12; rsvd_tail += 0x1000; ram->poller_base = ram->base.size - rsvd_tail; @@ -66,6 +67,7 @@ static int mcp77_ram_init(struct nvkm_object *object) { struct nvkm_fb *fb = nvkm_fb(object); + struct nvkm_device *device = fb->subdev.device; struct mcp77_ram *ram = (void *)object; int ret; u64 dniso, hostnb, flush; @@ -81,12 +83,12 @@ mcp77_ram_init(struct nvkm_object *object) /* Enable NISO poller for various clients and set their associated * read address, only for MCP77/78 and MCP79/7A. (fd#25701) */ - nv_wr32(fb, 0x100c18, dniso); - nv_mask(fb, 0x100c14, 0x00000000, 0x00000001); - nv_wr32(fb, 0x100c1c, hostnb); - nv_mask(fb, 0x100c14, 0x00000000, 0x00000002); - nv_wr32(fb, 0x100c24, flush); - nv_mask(fb, 0x100c14, 0x00000000, 0x00010000); + nvkm_wr32(device, 0x100c18, dniso); + nvkm_mask(device, 0x100c14, 0x00000000, 0x00000001); + nvkm_wr32(device, 0x100c1c, hostnb); + nvkm_mask(device, 0x100c14, 0x00000000, 0x00000002); + nvkm_wr32(device, 0x100c24, flush); + nvkm_mask(device, 0x100c14, 0x00000000, 0x00010000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c index 12311c56c4a7c..db9c29dfabeac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c @@ -31,7 +31,8 @@ nv04_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; - u32 boot0 = nv_rd32(fb, NV04_PFB_BOOT_0); + struct nvkm_device *device = fb->subdev.device; + u32 boot0 = nvkm_rd32(device, NV04_PFB_BOOT_0); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c index 0999ac2e47715..76cc560e1de38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c @@ -30,7 +30,8 @@ nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; - u32 cfg0 = nv_rd32(fb, 0x100200); + struct nvkm_device *device = fb->subdev.device; + u32 cfg0 = nvkm_rd32(device, 0x100200); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -43,7 +44,7 @@ nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, else ram->type = NV_MEM_TYPE_SDRAM; - ram->size = nv_rd32(fb, 0x10020c) & 0xff000000; + ram->size = nvkm_rd32(device, 0x10020c) & 0xff000000; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c index 929fa1678444f..017f82e5b61e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c @@ -30,7 +30,8 @@ nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; - u32 pbus1218 = nv_rd32(fb, 0x001218); + struct nvkm_device *device = fb->subdev.device; + u32 pbus1218 = nvkm_rd32(device, 0x001218); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -44,9 +45,9 @@ nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break; } - ram->size = (nv_rd32(fb, 0x10020c) & 0xff000000); - ram->parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; - ram->tags = nv_rd32(fb, 0x100320); + ram->size = (nvkm_rd32(device, 0x10020c) & 0xff000000); + ram->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; + ram->tags = nvkm_rd32(device, 0x100320); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index bf795846bd8ed..54d8cb55ad95e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -66,7 +66,8 @@ nv40_ram_calc(struct nvkm_fb *fb, u32 freq) int nv40_ram_prog(struct nvkm_fb *fb) { - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; struct nv40_ram *ram = (void *)fb->ram; struct bit_entry M; u32 crtc_mask = 0; @@ -75,12 +76,12 @@ nv40_ram_prog(struct nvkm_fb *fb) /* determine which CRTCs are active, fetch VGA_SR1 for each */ for (i = 0; i < 2; i++) { - u32 vbl = nv_rd32(fb, 0x600808 + (i * 0x2000)); + u32 vbl = nvkm_rd32(device, 0x600808 + (i * 0x2000)); u32 cnt = 0; do { - if (vbl != nv_rd32(fb, 0x600808 + (i * 0x2000))) { - nv_wr08(fb, 0x0c03c4 + (i * 0x2000), 0x01); - sr1[i] = nv_rd08(fb, 0x0c03c5 + (i * 0x2000)); + if (vbl != nvkm_rd32(device, 0x600808 + (i * 0x2000))) { + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); + sr1[i] = nvkm_rd08(device, 0x0c03c5 + (i * 0x2000)); if (!(sr1[i] & 0x20)) crtc_mask |= (1 << i); break; @@ -95,45 +96,45 @@ nv40_ram_prog(struct nvkm_fb *fb) continue; nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(fb, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(fb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); + nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); } /* prepare ram for reclocking */ - nv_wr32(fb, 0x1002d4, 0x00000001); /* precharge */ - nv_wr32(fb, 0x1002d0, 0x00000001); /* refresh */ - nv_wr32(fb, 0x1002d0, 0x00000001); /* refresh */ - nv_mask(fb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ - nv_wr32(fb, 0x1002dc, 0x00000001); /* enable self-refresh */ + nvkm_wr32(device, 0x1002d4, 0x00000001); /* precharge */ + nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */ + nvkm_wr32(device, 0x1002d0, 0x00000001); /* refresh */ + nvkm_mask(device, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */ + nvkm_wr32(device, 0x1002dc, 0x00000001); /* enable self-refresh */ /* change the PLL of each memory partition */ - nv_mask(fb, 0x00c040, 0x0000c000, 0x00000000); - switch (nv_device(fb)->chipset) { + nvkm_mask(device, 0x00c040, 0x0000c000, 0x00000000); + switch (device->chipset) { case 0x40: case 0x45: case 0x41: case 0x42: case 0x47: - nv_mask(fb, 0x004044, 0xc0771100, ram->ctrl); - nv_mask(fb, 0x00402c, 0xc0771100, ram->ctrl); - nv_wr32(fb, 0x004048, ram->coef); - nv_wr32(fb, 0x004030, ram->coef); + nvkm_mask(device, 0x004044, 0xc0771100, ram->ctrl); + nvkm_mask(device, 0x00402c, 0xc0771100, ram->ctrl); + nvkm_wr32(device, 0x004048, ram->coef); + nvkm_wr32(device, 0x004030, ram->coef); case 0x43: case 0x49: case 0x4b: - nv_mask(fb, 0x004038, 0xc0771100, ram->ctrl); - nv_wr32(fb, 0x00403c, ram->coef); + nvkm_mask(device, 0x004038, 0xc0771100, ram->ctrl); + nvkm_wr32(device, 0x00403c, ram->coef); default: - nv_mask(fb, 0x004020, 0xc0771100, ram->ctrl); - nv_wr32(fb, 0x004024, ram->coef); + nvkm_mask(device, 0x004020, 0xc0771100, ram->ctrl); + nvkm_wr32(device, 0x004024, ram->coef); break; } udelay(100); - nv_mask(fb, 0x00c040, 0x0000c000, 0x0000c000); + nvkm_mask(device, 0x00c040, 0x0000c000, 0x0000c000); /* re-enable normal operation of memory controller */ - nv_wr32(fb, 0x1002dc, 0x00000000); - nv_mask(fb, 0x100210, 0x80000000, 0x80000000); + nvkm_wr32(device, 0x1002dc, 0x00000000); + nvkm_mask(device, 0x100210, 0x80000000, 0x80000000); udelay(100); /* execute memory reset script from vbios */ @@ -155,8 +156,8 @@ nv40_ram_prog(struct nvkm_fb *fb) if (!(crtc_mask & (1 << i))) continue; nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); - nv_wr08(fb, 0x0c03c4 + (i * 0x2000), 0x01); - nv_wr08(fb, 0x0c03c5 + (i * 0x2000), sr1[i]); + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); + nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]); } return 0; @@ -174,7 +175,8 @@ nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 pbus1218 = nv_rd32(fb, 0x001218); + struct nvkm_device *device = fb->subdev.device; + u32 pbus1218 = nvkm_rd32(device, 0x001218); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -189,9 +191,9 @@ nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break; } - ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(fb, 0x100320); + ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; + ram->base.parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; + ram->base.tags = nvkm_rd32(device, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c index ba0bca729012e..9ebfb0d8fdd7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c @@ -30,7 +30,8 @@ nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 fb474 = nv_rd32(fb, 0x100474); + struct nvkm_device *device = fb->subdev.device; + u32 fb474 = nvkm_rd32(device, 0x100474); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -45,9 +46,9 @@ nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (fb474 & 0x00000001) ram->base.type = NV_MEM_TYPE_DDR1; - ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(fb, 0x100320); + ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; + ram->base.parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; + ram->base.tags = nvkm_rd32(device, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c index ef84bafad5466..ac0ba6deb576d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c @@ -30,7 +30,8 @@ nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 fb474 = nv_rd32(fb, 0x100474); + struct nvkm_device *device = fb->subdev.device; + u32 fb474 = nvkm_rd32(device, 0x100474); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -45,7 +46,7 @@ nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (fb474 & 0x00000001) ram->base.type = NV_MEM_TYPE_DDR1; - ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; + ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c index 75c62115260e6..4a19da6a26bae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c @@ -30,7 +30,8 @@ nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; - u32 fb914 = nv_rd32(fb, 0x100914); + struct nvkm_device *device = fb->subdev.device; + u32 fb914 = nvkm_rd32(device, 0x100914); int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -45,9 +46,9 @@ nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00000003: break; } - ram->base.size = nv_rd32(fb, 0x10020c) & 0xff000000; - ram->base.parts = (nv_rd32(fb, 0x100200) & 0x00000003) + 1; - ram->base.tags = nv_rd32(fb, 0x100320); + ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; + ram->base.parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; + ram->base.tags = nvkm_rd32(device, 0x100320); ram->base.calc = nv40_ram_calc; ram->base.prog = nv40_ram_prog; ram->base.tidy = nv40_ram_tidy; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c index 0eef65933ae77..1778b3c7c8975 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c @@ -30,6 +30,7 @@ nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_ram *ram; + struct nvkm_device *device = fb->subdev.device; int ret; ret = nvkm_ram_create(parent, engine, oclass, &ram); @@ -37,7 +38,7 @@ nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ram->size = nv_rd32(fb, 0x10020c) & 0xff000000; + ram->size = nvkm_rd32(device, 0x10020c) & 0xff000000; ram->type = NV_MEM_TYPE_STOLEN; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 49e21cf57e226..6ea0d52cd89cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -68,15 +68,16 @@ struct nv50_ram { static int nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) { + struct nvkm_device *device = fb->subdev.device; struct nv50_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; u32 cur2, cur4, cur7, cur8; u8 unkt3b; - cur2 = nv_rd32(fb, 0x100228); - cur4 = nv_rd32(fb, 0x100230); - cur7 = nv_rd32(fb, 0x10023c); - cur8 = nv_rd32(fb, 0x100240); + cur2 = nvkm_rd32(device, 0x100228); + cur4 = nvkm_rd32(device, 0x100230); + cur7 = nvkm_rd32(device, 0x10023c); + cur8 = nvkm_rd32(device, 0x100240); switch ((!T(CWL)) * ram->base.type) { case NV_MEM_TYPE_DDR2: @@ -493,15 +494,16 @@ nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, static u32 nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) { + struct nvkm_device *device = fb->subdev.device; int colbits, rowbitsa, rowbitsb, banks; u64 rowsize, predicted; u32 r0, r4, rt, rblock_size; - r0 = nv_rd32(fb, 0x100200); - r4 = nv_rd32(fb, 0x100204); - rt = nv_rd32(fb, 0x100250); + r0 = nvkm_rd32(device, 0x100200); + r4 = nvkm_rd32(device, 0x100204); + rt = nvkm_rd32(device, 0x100250); nv_debug(fb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", - r0, r4, rt, nv_rd32(fb, 0x001540)); + r0, r4, rt, nvkm_rd32(device, 0x001540)); colbits = (r4 & 0x0000f000) >> 12; rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; @@ -532,8 +534,9 @@ nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, { const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - struct nvkm_bios *bios = nvkm_bios(parent); struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_device *device = fb->subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_ram *ram; int ret; @@ -542,13 +545,13 @@ nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ram->size = nv_rd32(fb, 0x10020c); + ram->size = nvkm_rd32(device, 0x10020c); ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); - ram->part_mask = (nv_rd32(fb, 0x001540) & 0x00ff0000) >> 16; + ram->part_mask = (nvkm_rd32(device, 0x001540) & 0x00ff0000) >> 16; ram->parts = hweight8(ram->part_mask); - switch (nv_rd32(fb, 0x100714) & 0x00000007) { + switch (nvkm_rd32(device, 0x100714) & 0x00000007) { case 0: ram->type = NV_MEM_TYPE_DDR1; break; case 1: if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) @@ -569,8 +572,8 @@ nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ram->ranks = (nv_rd32(fb, 0x100200) & 0x4) ? 2 : 1; - ram->tags = nv_rd32(fb, 0x100320); + ram->ranks = (nvkm_rd32(device, 0x100200) & 0x4) ? 2 : 1; + ram->tags = nvkm_rd32(device, 0x100320); ram->get = nv50_ram_get; ram->put = nv50_ram_put; return 0; -- GitLab From 2bdb4995fd9629840ed80305f2a9f046071881d7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5366/7006] drm/nouveau/fuse: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c | 11 ++++++----- drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c | 3 ++- drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c index 8f0eeb952e7aa..e9d4324240713 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c @@ -33,16 +33,17 @@ static u32 gf100_fuse_rd32(struct nvkm_object *object, u64 addr) { struct gf100_fuse *fuse = (void *)object; + struct nvkm_device *device = fuse->base.subdev.device; unsigned long flags; u32 fuse_enable, unk, val; /* racy if another part of nvkm start writing to these regs */ spin_lock_irqsave(&fuse->fuse_enable_lock, flags); - fuse_enable = nv_mask(fuse, 0x22400, 0x800, 0x800); - unk = nv_mask(fuse, 0x21000, 0x1, 0x1); - val = nv_rd32(fuse, 0x21100 + addr); - nv_wr32(fuse, 0x21000, unk); - nv_wr32(fuse, 0x22400, fuse_enable); + fuse_enable = nvkm_mask(device, 0x22400, 0x800, 0x800); + unk = nvkm_mask(device, 0x21000, 0x1, 0x1); + val = nvkm_rd32(device, 0x21100 + addr); + nvkm_wr32(device, 0x21000, unk); + nvkm_wr32(device, 0x22400, fuse_enable); spin_unlock_irqrestore(&fuse->fuse_enable_lock, flags); return val; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c index e669b648e8fa8..94594ac9990b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c @@ -27,7 +27,8 @@ static u32 gm107_fuse_rd32(struct nvkm_object *object, u64 addr) { struct nvkm_fuse *fuse = (void *)object; - return nv_rd32(fuse, 0x21100 + addr); + struct nvkm_device *device = fuse->subdev.device; + return nvkm_rd32(device, 0x21100 + addr); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c index ac9d5fd3e8d1b..c47abfa98809e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c @@ -33,14 +33,15 @@ static u32 nv50_fuse_rd32(struct nvkm_object *object, u64 addr) { struct nv50_fuse *fuse = (void *)object; + struct nvkm_device *device = fuse->base.subdev.device; unsigned long flags; u32 fuse_enable, val; /* racy if another part of nvkm start writing to this reg */ spin_lock_irqsave(&fuse->fuse_enable_lock, flags); - fuse_enable = nv_mask(fuse, 0x1084, 0x800, 0x800); - val = nv_rd32(fuse, 0x21000 + addr); - nv_wr32(fuse, 0x1084, fuse_enable); + fuse_enable = nvkm_mask(device, 0x1084, 0x800, 0x800); + val = nvkm_rd32(device, 0x21000 + addr); + nvkm_wr32(device, 0x1084, fuse_enable); spin_unlock_irqrestore(&fuse->fuse_enable_lock, flags); return val; } -- GitLab From 4de93a086eb0315f0bd8e1d6da40186842670b57 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5367/7006] drm/nouveau/gpio: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/gpio/g94.c | 22 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c | 15 +++++++----- .../gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c | 22 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c | 22 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c | 23 +++++++++++-------- 5 files changed, 60 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c index 12b3e01fca8e9..939f6b953ddde 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c @@ -26,21 +26,23 @@ void g94_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr0 = nv_rd32(gpio, 0x00e054); - u32 intr1 = nv_rd32(gpio, 0x00e074); - u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0; - u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1; + struct nvkm_device *device = gpio->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x00e054); + u32 intr1 = nvkm_rd32(device, 0x00e074); + u32 stat0 = nvkm_rd32(device, 0x00e050) & intr0; + u32 stat1 = nvkm_rd32(device, 0x00e070) & intr1; *lo = (stat1 & 0xffff0000) | (stat0 >> 16); *hi = (stat1 << 16) | (stat0 & 0x0000ffff); - nv_wr32(gpio, 0x00e054, intr0); - nv_wr32(gpio, 0x00e074, intr1); + nvkm_wr32(device, 0x00e054, intr0); + nvkm_wr32(device, 0x00e074, intr1); } void g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte0 = nv_rd32(gpio, 0x00e050); - u32 inte1 = nv_rd32(gpio, 0x00e070); + struct nvkm_device *device = gpio->subdev.device; + u32 inte0 = nvkm_rd32(device, 0x00e050); + u32 inte1 = nvkm_rd32(device, 0x00e070); if (type & NVKM_GPIO_LO) inte0 = (inte0 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) @@ -51,8 +53,8 @@ g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) inte1 = (inte1 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte1 = (inte1 & ~mask) | data; - nv_wr32(gpio, 0x00e050, inte0); - nv_wr32(gpio, 0x00e070, inte1); + nvkm_wr32(device, 0x00e050, inte0); + nvkm_wr32(device, 0x00e070, inte1); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c index 2c3bb255d1f8d..a2c019bb7443a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c @@ -26,7 +26,8 @@ void gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) { - struct nvkm_bios *bios = nvkm_bios(gpio); + struct nvkm_device *device = gpio->subdev.device; + struct nvkm_bios *bios = device->bios; u8 ver, len; u16 entry; int ent = -1; @@ -45,25 +46,27 @@ gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0); + nvkm_mask(device, 0x00d610 + (line * 4), 0xff, unk0); if (unk1--) - nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line); + nvkm_mask(device, 0x00d740 + (unk1 * 4), 0xff, line); } } int gf110_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { + struct nvkm_device *device = gpio->subdev.device; u32 data = ((dir ^ 1) << 13) | (out << 12); - nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data); - nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */ + nvkm_mask(device, 0x00d610 + (line * 4), 0x00003000, data); + nvkm_mask(device, 0x00d604, 0x00000001, 0x00000001); /* update? */ return 0; } int gf110_gpio_sense(struct nvkm_gpio *gpio, int line) { - return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000); + struct nvkm_device *device = gpio->subdev.device; + return !!(nvkm_rd32(device, 0x00d610 + (line * 4)) & 0x00004000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c index 42fd2faaaa4f4..e8e433cff17d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c @@ -26,21 +26,23 @@ static void gk104_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr0 = nv_rd32(gpio, 0x00dc00); - u32 intr1 = nv_rd32(gpio, 0x00dc80); - u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0; - u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1; + struct nvkm_device *device = gpio->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x00dc00); + u32 intr1 = nvkm_rd32(device, 0x00dc80); + u32 stat0 = nvkm_rd32(device, 0x00dc08) & intr0; + u32 stat1 = nvkm_rd32(device, 0x00dc88) & intr1; *lo = (stat1 & 0xffff0000) | (stat0 >> 16); *hi = (stat1 << 16) | (stat0 & 0x0000ffff); - nv_wr32(gpio, 0x00dc00, intr0); - nv_wr32(gpio, 0x00dc80, intr1); + nvkm_wr32(device, 0x00dc00, intr0); + nvkm_wr32(device, 0x00dc80, intr1); } void gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte0 = nv_rd32(gpio, 0x00dc08); - u32 inte1 = nv_rd32(gpio, 0x00dc88); + struct nvkm_device *device = gpio->subdev.device; + u32 inte0 = nvkm_rd32(device, 0x00dc08); + u32 inte1 = nvkm_rd32(device, 0x00dc88); if (type & NVKM_GPIO_LO) inte0 = (inte0 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) @@ -51,8 +53,8 @@ gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) inte1 = (inte1 & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte1 = (inte1 & ~mask) | data; - nv_wr32(gpio, 0x00dc08, inte0); - nv_wr32(gpio, 0x00dc88, inte1); + nvkm_wr32(device, 0x00dc08, inte0); + nvkm_wr32(device, 0x00dc88, inte1); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c index 2b295154247ee..b88cabcc28d7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c @@ -28,19 +28,20 @@ static int nv10_gpio_sense(struct nvkm_gpio *gpio, int line) { + struct nvkm_device *device = gpio->subdev.device; if (line < 2) { line = line * 16; - line = nv_rd32(gpio, 0x600818) >> line; + line = nvkm_rd32(device, 0x600818) >> line; return !!(line & 0x0100); } else if (line < 10) { line = (line - 2) * 4; - line = nv_rd32(gpio, 0x60081c) >> line; + line = nvkm_rd32(device, 0x60081c) >> line; return !!(line & 0x04); } else if (line < 14) { line = (line - 10) * 4; - line = nv_rd32(gpio, 0x600850) >> line; + line = nvkm_rd32(device, 0x600850) >> line; return !!(line & 0x04); } @@ -50,6 +51,7 @@ nv10_gpio_sense(struct nvkm_gpio *gpio, int line) static int nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { + struct nvkm_device *device = gpio->subdev.device; u32 reg, mask, data; if (line < 2) { @@ -73,29 +75,31 @@ nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) return -EINVAL; } - nv_mask(gpio, reg, mask << line, data << line); + nvkm_mask(device, reg, mask << line, data << line); return 0; } static void nv10_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr = nv_rd32(gpio, 0x001104); - u32 stat = nv_rd32(gpio, 0x001144) & intr; + struct nvkm_device *device = gpio->subdev.device; + u32 intr = nvkm_rd32(device, 0x001104); + u32 stat = nvkm_rd32(device, 0x001144) & intr; *lo = (stat & 0xffff0000) >> 16; *hi = (stat & 0x0000ffff); - nv_wr32(gpio, 0x001104, intr); + nvkm_wr32(device, 0x001104, intr); } static void nv10_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte = nv_rd32(gpio, 0x001144); + struct nvkm_device *device = gpio->subdev.device; + u32 inte = nvkm_rd32(device, 0x001144); if (type & NVKM_GPIO_LO) inte = (inte & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte = (inte & ~mask) | data; - nv_wr32(gpio, 0x001144, inte); + nvkm_wr32(device, 0x001144, inte); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c index 6a031035bd276..ca2d866a3c32d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c @@ -26,7 +26,8 @@ void nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) { - struct nvkm_bios *bios = nvkm_bios(gpio); + struct nvkm_device *device = gpio->subdev.device; + struct nvkm_bios *bios = device->bios; u8 ver, len; u16 entry; int ent = -1; @@ -49,7 +50,7 @@ nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) gpio->set(gpio, 0, func, line, defs); - nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh); + nvkm_mask(device, reg, 0x00010001 << lsh, val << lsh); } } @@ -69,45 +70,49 @@ nv50_gpio_location(int line, u32 *reg, u32 *shift) int nv50_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { + struct nvkm_device *device = gpio->subdev.device; u32 reg, shift; if (nv50_gpio_location(line, ®, &shift)) return -EINVAL; - nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift); + nvkm_mask(device, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift); return 0; } int nv50_gpio_sense(struct nvkm_gpio *gpio, int line) { + struct nvkm_device *device = gpio->subdev.device; u32 reg, shift; if (nv50_gpio_location(line, ®, &shift)) return -EINVAL; - return !!(nv_rd32(gpio, reg) & (4 << shift)); + return !!(nvkm_rd32(device, reg) & (4 << shift)); } static void nv50_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo) { - u32 intr = nv_rd32(gpio, 0x00e054); - u32 stat = nv_rd32(gpio, 0x00e050) & intr; + struct nvkm_device *device = gpio->subdev.device; + u32 intr = nvkm_rd32(device, 0x00e054); + u32 stat = nvkm_rd32(device, 0x00e050) & intr; *lo = (stat & 0xffff0000) >> 16; *hi = (stat & 0x0000ffff); - nv_wr32(gpio, 0x00e054, intr); + nvkm_wr32(device, 0x00e054, intr); } static void nv50_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) { - u32 inte = nv_rd32(gpio, 0x00e050); + struct nvkm_device *device = gpio->subdev.device; + u32 inte = nvkm_rd32(device, 0x00e050); if (type & NVKM_GPIO_LO) inte = (inte & ~(mask << 16)) | (data << 16); if (type & NVKM_GPIO_HI) inte = (inte & ~mask) | data; - nv_wr32(gpio, 0x00e050, inte); + nvkm_wr32(device, 0x00e050, inte); } struct nvkm_oclass * -- GitLab From 6f2274991043a3db2ab84b5d9462a085d38f1fb1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5368/7006] drm/nouveau/i2c: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c | 59 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c | 12 ++-- .../gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c | 47 ++++++++------- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c | 12 ++-- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c | 15 +++-- .../gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c | 10 ++-- .../drm/nouveau/nvkm/subdev/i2c/padgm204.c | 10 ++-- 8 files changed, 98 insertions(+), 73 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c index be936479ff95c..17cb172a4a0a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c @@ -26,21 +26,23 @@ void g94_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) { - u32 intr = nv_rd32(i2c, 0x00e06c); - u32 stat = nv_rd32(i2c, 0x00e068) & intr, i; + struct nvkm_device *device = i2c->subdev.device; + u32 intr = nvkm_rd32(device, 0x00e06c); + u32 stat = nvkm_rd32(device, 0x00e068) & intr, i; for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { if ((stat & (1 << (i * 4)))) *hi |= 1 << i; if ((stat & (2 << (i * 4)))) *lo |= 1 << i; if ((stat & (4 << (i * 4)))) *rq |= 1 << i; if ((stat & (8 << (i * 4)))) *tx |= 1 << i; } - nv_wr32(i2c, 0x00e06c, intr); + nvkm_wr32(device, 0x00e06c, intr); } void g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) { - u32 temp = nv_rd32(i2c, 0x00e068), i; + struct nvkm_device *device = i2c->subdev.device; + u32 temp = nvkm_rd32(device, 0x00e068), i; for (i = 0; i < 8; i++) { if (mask & (1 << i)) { if (!(data & (1 << i))) { @@ -50,21 +52,23 @@ g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) temp |= type << (i * 4); } } - nv_wr32(i2c, 0x00e068, temp); + nvkm_wr32(device, 0x00e068, temp); } -#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_DBG(fmt, args...) nv_debug(i2c, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_ERR(fmt, args...) nv_error(i2c, "AUXCH(%d): " fmt, ch, ##args) static void -auxch_fini(struct nvkm_i2c *aux, int ch) +auxch_fini(struct nvkm_i2c *i2c, int ch) { - nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); + struct nvkm_device *device = i2c->subdev.device; + nvkm_mask(device, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); } static int -auxch_init(struct nvkm_i2c *aux, int ch) +auxch_init(struct nvkm_i2c *i2c, int ch) { + struct nvkm_device *device = i2c->subdev.device; const u32 unksel = 1; /* nfi which to use, or if it matters.. */ const u32 ureq = unksel ? 0x00100000 : 0x00200000; const u32 urep = unksel ? 0x01000000 : 0x02000000; @@ -73,7 +77,7 @@ auxch_init(struct nvkm_i2c *aux, int ch) /* wait up to 1ms for any previous transaction to be done... */ timeout = 1000; do { - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("begin idle timeout 0x%08x\n", ctrl); @@ -82,14 +86,14 @@ auxch_init(struct nvkm_i2c *aux, int ch) } while (ctrl & 0x03010000); /* set some magic, and wait up to 1ms for it to appear */ - nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); + nvkm_mask(device, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); timeout = 1000; do { - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("magic wait 0x%08x\n", ctrl); - auxch_fini(aux, ch); + auxch_fini(i2c, ch); return -EBUSY; } } while ((ctrl & 0x03000000) != urep); @@ -101,7 +105,8 @@ int g94_aux(struct nvkm_i2c_port *base, bool retry, u8 type, u32 addr, u8 *data, u8 size) { - struct nvkm_i2c *aux = nvkm_i2c(base); + struct nvkm_i2c *i2c = nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; u32 ctrl, stat, timeout, retries; u32 xbuf[4] = {}; @@ -110,11 +115,11 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, AUX_DBG("%d: 0x%08x %d\n", type, addr, size); - ret = auxch_init(aux, ch); + ret = auxch_init(i2c, ch); if (ret < 0) goto out; - stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50)); + stat = nvkm_rd32(device, 0x00e4e8 + (ch * 0x50)); if (!(stat & 0x10000000)) { AUX_DBG("sink not detected\n"); ret = -ENXIO; @@ -125,30 +130,30 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, memcpy(xbuf, data, size); for (i = 0; i < 16; i += 4) { AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); - nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); + nvkm_wr32(device, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); } } - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); ctrl &= ~0x0001f0ff; ctrl |= type << 12; ctrl |= size - 1; - nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr); + nvkm_wr32(device, 0x00e4e0 + (ch * 0x50), addr); /* (maybe) retry transaction a number of times on failure... */ for (retries = 0; !ret && retries < 32; retries++) { /* reset, and delay a while if this is a retry */ - nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); - nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); + nvkm_wr32(device, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); + nvkm_wr32(device, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); if (retries) udelay(400); /* transaction request, wait up to 1ms for it to complete */ - nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); + nvkm_wr32(device, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); timeout = 1000; do { - ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("tx req timeout 0x%08x\n", ctrl); @@ -159,7 +164,7 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, ret = 1; /* read status, and check if transaction completed ok */ - stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0); + stat = nvkm_mask(device, 0x00e4e8 + (ch * 0x50), 0, 0); if ((stat & 0x000f0000) == 0x00080000 || (stat & 0x000f0000) == 0x00020000) ret = retry ? 0 : 1; @@ -173,14 +178,14 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, if (type & 1) { for (i = 0; i < 16; i += 4) { - xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i); + xbuf[i / 4] = nvkm_rd32(device, 0x00e4d0 + (ch * 0x50) + i); AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); } memcpy(data, xbuf, size); } out: - auxch_fini(aux, ch); + auxch_fini(i2c, ch); return ret < 0 ? ret : (stat & 0x000f0000) >> 16; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c index bf86502012631..6795e5c28b064 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c @@ -27,16 +27,18 @@ static int gf110_i2c_sense_scl(struct nvkm_i2c_port *base) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(i2c, port->addr) & 0x00000010); + return !!(nvkm_rd32(device, port->addr) & 0x00000010); } static int gf110_i2c_sense_sda(struct nvkm_i2c_port *base) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(i2c, port->addr) & 0x00000020); + return !!(nvkm_rd32(device, port->addr) & 0x00000020); } static const struct nvkm_i2c_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c index 1a464903a9927..9573fdb769b53 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c @@ -26,21 +26,23 @@ void gk104_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) { - u32 intr = nv_rd32(i2c, 0x00dc60); - u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i; + struct nvkm_device *device = i2c->subdev.device; + u32 intr = nvkm_rd32(device, 0x00dc60); + u32 stat = nvkm_rd32(device, 0x00dc68) & intr, i; for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) { if ((stat & (1 << (i * 4)))) *hi |= 1 << i; if ((stat & (2 << (i * 4)))) *lo |= 1 << i; if ((stat & (4 << (i * 4)))) *rq |= 1 << i; if ((stat & (8 << (i * 4)))) *tx |= 1 << i; } - nv_wr32(i2c, 0x00dc60, intr); + nvkm_wr32(device, 0x00dc60, intr); } void gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) { - u32 temp = nv_rd32(i2c, 0x00dc68), i; + struct nvkm_device *device = i2c->subdev.device; + u32 temp = nvkm_rd32(device, 0x00dc68), i; for (i = 0; i < 8; i++) { if (mask & (1 << i)) { if (!(data & (1 << i))) { @@ -50,7 +52,7 @@ gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) temp |= type << (i * 4); } } - nv_wr32(i2c, 0x00dc68, temp); + nvkm_wr32(device, 0x00dc68, temp); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c index ece2529f8f868..61c760534ab83 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c @@ -23,18 +23,20 @@ */ #include "nv50.h" -#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_DBG(fmt, args...) nv_debug(i2c, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_ERR(fmt, args...) nv_error(i2c, "AUXCH(%d): " fmt, ch, ##args) static void -auxch_fini(struct nvkm_i2c *aux, int ch) +auxch_fini(struct nvkm_i2c *i2c, int ch) { - nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000); + struct nvkm_device *device = i2c->subdev.device; + nvkm_mask(device, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000); } static int -auxch_init(struct nvkm_i2c *aux, int ch) +auxch_init(struct nvkm_i2c *i2c, int ch) { + struct nvkm_device *device = i2c->subdev.device; const u32 unksel = 1; /* nfi which to use, or if it matters.. */ const u32 ureq = unksel ? 0x00100000 : 0x00200000; const u32 urep = unksel ? 0x01000000 : 0x02000000; @@ -43,7 +45,7 @@ auxch_init(struct nvkm_i2c *aux, int ch) /* wait up to 1ms for any previous transaction to be done... */ timeout = 1000; do { - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("begin idle timeout 0x%08x\n", ctrl); @@ -52,14 +54,14 @@ auxch_init(struct nvkm_i2c *aux, int ch) } while (ctrl & 0x03010000); /* set some magic, and wait up to 1ms for it to appear */ - nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq); + nvkm_mask(device, 0x00d954 + (ch * 0x50), 0x00300000, ureq); timeout = 1000; do { - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("magic wait 0x%08x\n", ctrl); - auxch_fini(aux, ch); + auxch_fini(i2c, ch); return -EBUSY; } } while ((ctrl & 0x03000000) != urep); @@ -71,7 +73,8 @@ int gm204_aux(struct nvkm_i2c_port *base, bool retry, u8 type, u32 addr, u8 *data, u8 size) { - struct nvkm_i2c *aux = nvkm_i2c(base); + struct nvkm_i2c *i2c = nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; u32 ctrl, stat, timeout, retries; u32 xbuf[4] = {}; @@ -80,11 +83,11 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, AUX_DBG("%d: 0x%08x %d\n", type, addr, size); - ret = auxch_init(aux, ch); + ret = auxch_init(i2c, ch); if (ret < 0) goto out; - stat = nv_rd32(aux, 0x00d958 + (ch * 0x50)); + stat = nvkm_rd32(device, 0x00d958 + (ch * 0x50)); if (!(stat & 0x10000000)) { AUX_DBG("sink not detected\n"); ret = -ENXIO; @@ -95,30 +98,30 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, memcpy(xbuf, data, size); for (i = 0; i < 16; i += 4) { AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); - nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]); + nvkm_wr32(device, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]); } } - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); ctrl &= ~0x0001f0ff; ctrl |= type << 12; ctrl |= size - 1; - nv_wr32(aux, 0x00d950 + (ch * 0x50), addr); + nvkm_wr32(device, 0x00d950 + (ch * 0x50), addr); /* (maybe) retry transaction a number of times on failure... */ for (retries = 0; !ret && retries < 32; retries++) { /* reset, and delay a while if this is a retry */ - nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl); - nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl); + nvkm_wr32(device, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl); + nvkm_wr32(device, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl); if (retries) udelay(400); /* transaction request, wait up to 1ms for it to complete */ - nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl); + nvkm_wr32(device, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl); timeout = 1000; do { - ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50)); + ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); udelay(1); if (!timeout--) { AUX_ERR("tx req timeout 0x%08x\n", ctrl); @@ -129,7 +132,7 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, ret = 1; /* read status, and check if transaction completed ok */ - stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0); + stat = nvkm_mask(device, 0x00d958 + (ch * 0x50), 0, 0); if ((stat & 0x000f0000) == 0x00080000 || (stat & 0x000f0000) == 0x00020000) ret = retry ? 0 : 1; @@ -143,14 +146,14 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, if (type & 1) { for (i = 0; i < 16; i += 4) { - xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i); + xbuf[i / 4] = nvkm_rd32(device, 0x00d940 + (ch * 0x50) + i); AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); } memcpy(data, xbuf, size); } out: - auxch_fini(aux, ch); + auxch_fini(i2c, ch); return ret < 0 ? ret : (stat & 0x000f0000) >> 16; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c index ba3116f686fa1..24edcdbca3de2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c @@ -34,32 +34,36 @@ static void nv4e_i2c_drive_scl(struct nvkm_i2c_port *base, int state) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv4e_i2c_port *port = (void *)base; - nv_mask(i2c, port->addr, 0x2f, state ? 0x21 : 0x01); + nvkm_mask(device, port->addr, 0x2f, state ? 0x21 : 0x01); } static void nv4e_i2c_drive_sda(struct nvkm_i2c_port *base, int state) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv4e_i2c_port *port = (void *)base; - nv_mask(i2c, port->addr, 0x1f, state ? 0x11 : 0x01); + nvkm_mask(device, port->addr, 0x1f, state ? 0x11 : 0x01); } static int nv4e_i2c_sense_scl(struct nvkm_i2c_port *base) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv4e_i2c_port *port = (void *)base; - return !!(nv_rd32(i2c, port->addr) & 0x00040000); + return !!(nvkm_rd32(device, port->addr) & 0x00040000); } static int nv4e_i2c_sense_sda(struct nvkm_i2c_port *base) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv4e_i2c_port *port = (void *)base; - return !!(nv_rd32(i2c, port->addr) & 0x00080000); + return !!(nvkm_rd32(device, port->addr) & 0x00080000); } static const struct nvkm_i2c_func diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c index 21f24864a6d2c..6c04fe0088370 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c @@ -27,36 +27,40 @@ void nv50_i2c_drive_scl(struct nvkm_i2c_port *base, int state) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; if (state) port->state |= 0x01; else port->state &= 0xfe; - nv_wr32(i2c, port->addr, port->state); + nvkm_wr32(device, port->addr, port->state); } void nv50_i2c_drive_sda(struct nvkm_i2c_port *base, int state) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; if (state) port->state |= 0x02; else port->state &= 0xfd; - nv_wr32(i2c, port->addr, port->state); + nvkm_wr32(device, port->addr, port->state); } int nv50_i2c_sense_scl(struct nvkm_i2c_port *base) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(i2c, port->addr) & 0x00000001); + return !!(nvkm_rd32(device, port->addr) & 0x00000001); } int nv50_i2c_sense_sda(struct nvkm_i2c_port *base) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)base; - return !!(nv_rd32(i2c, port->addr) & 0x00000002); + return !!(nvkm_rd32(device, port->addr) & 0x00000002); } static const struct nvkm_i2c_func @@ -101,8 +105,9 @@ int nv50_i2c_port_init(struct nvkm_object *object) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); + struct nvkm_device *device = i2c->subdev.device; struct nv50_i2c_port *port = (void *)object; - nv_wr32(i2c, port->addr, port->state); + nvkm_wr32(device, port->addr, port->state); return nvkm_i2c_port_init(&port->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c index e9832f7a7e38e..2e5f6da97f094 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c @@ -32,8 +32,9 @@ static int g94_i2c_pad_fini(struct nvkm_object *object, bool suspend) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); + struct nvkm_device *device = i2c->subdev.device; struct g94_i2c_pad *pad = (void *)object; - nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001); + nvkm_mask(device, 0x00e50c + pad->addr, 0x00000001, 0x00000001); return nvkm_i2c_pad_fini(&pad->base, suspend); } @@ -41,19 +42,20 @@ static int g94_i2c_pad_init(struct nvkm_object *object) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); + struct nvkm_device *device = i2c->subdev.device; struct g94_i2c_pad *pad = (void *)object; switch (nv_oclass(pad->base.next)->handle) { case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): - nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002); + nvkm_mask(device, 0x00e500 + pad->addr, 0x0000c003, 0x00000002); break; case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): default: - nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001); + nvkm_mask(device, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001); break; } - nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000); + nvkm_mask(device, 0x00e50c + pad->addr, 0x00000001, 0x00000000); return nvkm_i2c_pad_init(&pad->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c index be590405444d2..fa43046575bd9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c @@ -32,8 +32,9 @@ static int gm204_i2c_pad_fini(struct nvkm_object *object, bool suspend) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); + struct nvkm_device *device = i2c->subdev.device; struct gm204_i2c_pad *pad = (void *)object; - nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001); + nvkm_mask(device, 0x00d97c + pad->addr, 0x00000001, 0x00000001); return nvkm_i2c_pad_fini(&pad->base, suspend); } @@ -41,19 +42,20 @@ static int gm204_i2c_pad_init(struct nvkm_object *object) { struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); + struct nvkm_device *device = i2c->subdev.device; struct gm204_i2c_pad *pad = (void *)object; switch (nv_oclass(pad->base.next)->handle) { case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): - nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002); + nvkm_mask(device, 0x00d970 + pad->addr, 0x0000c003, 0x00000002); break; case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): default: - nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001); + nvkm_mask(device, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001); break; } - nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000); + nvkm_mask(device, 0x00d97c + pad->addr, 0x00000001, 0x00000000); return nvkm_i2c_pad_init(&pad->base); } -- GitLab From fef5cc0f258d68d3a9ead1058461bf5f2e2796da Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5369/7006] drm/nouveau/ibus: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c | 38 +++++++------ .../gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c | 53 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c | 24 +++++---- 3 files changed, 63 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c index d4c175dfc797e..5f7652942b2af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c @@ -26,42 +26,46 @@ static void gf100_ibus_intr_hub(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(ibus, 0x122120 + (i * 0x0400)); - u32 data = nv_rd32(ibus, 0x122124 + (i * 0x0400)); - u32 stat = nv_rd32(ibus, 0x122128 + (i * 0x0400)); + struct nvkm_device *device = ibus->subdev.device; + u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0400)); + u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0400)); + u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0400)); nv_error(ibus, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(ibus, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); + nvkm_mask(device, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); } static void gf100_ibus_intr_rop(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(ibus, 0x124120 + (i * 0x0400)); - u32 data = nv_rd32(ibus, 0x124124 + (i * 0x0400)); - u32 stat = nv_rd32(ibus, 0x124128 + (i * 0x0400)); + struct nvkm_device *device = ibus->subdev.device; + u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0400)); + u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0400)); + u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0400)); nv_error(ibus, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(ibus, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); + nvkm_mask(device, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); } static void gf100_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(ibus, 0x128120 + (i * 0x0400)); - u32 data = nv_rd32(ibus, 0x128124 + (i * 0x0400)); - u32 stat = nv_rd32(ibus, 0x128128 + (i * 0x0400)); + struct nvkm_device *device = ibus->subdev.device; + u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0400)); + u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0400)); + u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0400)); nv_error(ibus, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(ibus, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); + nvkm_mask(device, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); } static void gf100_ibus_intr(struct nvkm_subdev *subdev) { struct nvkm_ibus *ibus = (void *)subdev; - u32 intr0 = nv_rd32(ibus, 0x121c58); - u32 intr1 = nv_rd32(ibus, 0x121c5c); - u32 hubnr = nv_rd32(ibus, 0x121c70); - u32 ropnr = nv_rd32(ibus, 0x121c74); - u32 gpcnr = nv_rd32(ibus, 0x121c78); + struct nvkm_device *device = ibus->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x121c58); + u32 intr1 = nvkm_rd32(device, 0x121c5c); + u32 hubnr = nvkm_rd32(device, 0x121c70); + u32 ropnr = nvkm_rd32(device, 0x121c74); + u32 gpcnr = nvkm_rd32(device, 0x121c78); u32 i; for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c index 4107d9d25a04a..53dd1ba389d74 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c @@ -26,42 +26,46 @@ static void gk104_ibus_intr_hub(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(ibus, 0x122120 + (i * 0x0800)); - u32 data = nv_rd32(ibus, 0x122124 + (i * 0x0800)); - u32 stat = nv_rd32(ibus, 0x122128 + (i * 0x0800)); + struct nvkm_device *device = ibus->subdev.device; + u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0800)); + u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0800)); + u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0800)); nv_error(ibus, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(ibus, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); + nvkm_mask(device, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); } static void gk104_ibus_intr_rop(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(ibus, 0x124120 + (i * 0x0800)); - u32 data = nv_rd32(ibus, 0x124124 + (i * 0x0800)); - u32 stat = nv_rd32(ibus, 0x124128 + (i * 0x0800)); + struct nvkm_device *device = ibus->subdev.device; + u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0800)); + u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0800)); + u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0800)); nv_error(ibus, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(ibus, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); + nvkm_mask(device, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); } static void gk104_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) { - u32 addr = nv_rd32(ibus, 0x128120 + (i * 0x0800)); - u32 data = nv_rd32(ibus, 0x128124 + (i * 0x0800)); - u32 stat = nv_rd32(ibus, 0x128128 + (i * 0x0800)); + struct nvkm_device *device = ibus->subdev.device; + u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0800)); + u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0800)); + u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0800)); nv_error(ibus, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); - nv_mask(ibus, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); + nvkm_mask(device, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); } static void gk104_ibus_intr(struct nvkm_subdev *subdev) { struct nvkm_ibus *ibus = (void *)subdev; - u32 intr0 = nv_rd32(ibus, 0x120058); - u32 intr1 = nv_rd32(ibus, 0x12005c); - u32 hubnr = nv_rd32(ibus, 0x120070); - u32 ropnr = nv_rd32(ibus, 0x120074); - u32 gpcnr = nv_rd32(ibus, 0x120078); + struct nvkm_device *device = ibus->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x120058); + u32 intr1 = nvkm_rd32(device, 0x12005c); + u32 hubnr = nvkm_rd32(device, 0x120070); + u32 ropnr = nvkm_rd32(device, 0x120074); + u32 gpcnr = nvkm_rd32(device, 0x120078); u32 i; for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) { @@ -93,15 +97,16 @@ static int gk104_ibus_init(struct nvkm_object *object) { struct nvkm_ibus *ibus = (void *)object; + struct nvkm_device *device = ibus->subdev.device; int ret = nvkm_ibus_init(ibus); if (ret == 0) { - nv_mask(ibus, 0x122318, 0x0003ffff, 0x00001000); - nv_mask(ibus, 0x12231c, 0x0003ffff, 0x00000200); - nv_mask(ibus, 0x122310, 0x0003ffff, 0x00000800); - nv_mask(ibus, 0x122348, 0x0003ffff, 0x00000100); - nv_mask(ibus, 0x1223b0, 0x0003ffff, 0x00000fff); - nv_mask(ibus, 0x122348, 0x0003ffff, 0x00000200); - nv_mask(ibus, 0x122358, 0x0003ffff, 0x00002880); + nvkm_mask(device, 0x122318, 0x0003ffff, 0x00001000); + nvkm_mask(device, 0x12231c, 0x0003ffff, 0x00000200); + nvkm_mask(device, 0x122310, 0x0003ffff, 0x00000800); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000100); + nvkm_mask(device, 0x1223b0, 0x0003ffff, 0x00000fff); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000200); + nvkm_mask(device, 0x122358, 0x0003ffff, 0x00002880); } return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index 7bdedc53e1b44..1b676aaecc889 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -25,30 +25,32 @@ static void gk20a_ibus_init_ibus_ring(struct nvkm_ibus *ibus) { - nv_mask(ibus, 0x137250, 0x3f, 0); + struct nvkm_device *device = ibus->subdev.device; + nvkm_mask(device, 0x137250, 0x3f, 0); - nv_mask(ibus, 0x000200, 0x20, 0); + nvkm_mask(device, 0x000200, 0x20, 0); usleep_range(20, 30); - nv_mask(ibus, 0x000200, 0x20, 0x20); + nvkm_mask(device, 0x000200, 0x20, 0x20); - nv_wr32(ibus, 0x12004c, 0x4); - nv_wr32(ibus, 0x122204, 0x2); - nv_rd32(ibus, 0x122204); + nvkm_wr32(device, 0x12004c, 0x4); + nvkm_wr32(device, 0x122204, 0x2); + nvkm_rd32(device, 0x122204); /* * Bug: increase clock timeout to avoid operation failure at high * gpcclk rate. */ - nv_wr32(ibus, 0x122354, 0x800); - nv_wr32(ibus, 0x128328, 0x800); - nv_wr32(ibus, 0x124320, 0x800); + nvkm_wr32(device, 0x122354, 0x800); + nvkm_wr32(device, 0x128328, 0x800); + nvkm_wr32(device, 0x124320, 0x800); } static void gk20a_ibus_intr(struct nvkm_subdev *subdev) { struct nvkm_ibus *ibus = (void *)subdev; - u32 status0 = nv_rd32(ibus, 0x120058); + struct nvkm_device *device = ibus->subdev.device; + u32 status0 = nvkm_rd32(device, 0x120058); if (status0 & 0x7) { nv_debug(ibus, "resetting ibus ring\n"); @@ -56,7 +58,7 @@ gk20a_ibus_intr(struct nvkm_subdev *subdev) } /* Acknowledge interrupt */ - nv_mask(ibus, 0x12004c, 0x2, 0x2); + nvkm_mask(device, 0x12004c, 0x2, 0x2); if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00)) nv_warn(ibus, "timeout waiting for ringmaster ack\n"); -- GitLab From d5c5bcf693e7c72f2f853066858f3d40a42ba942 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5370/7006] drm/nouveau/imem: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c | 10 ++++++---- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c | 6 ++++-- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c | 10 ++++++---- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index abc41c0a4ad83..e2e400e35bc8b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -107,6 +107,7 @@ gk20a_instobj_rd32(struct nvkm_object *object, u64 offset) { struct gk20a_instmem *imem = (void *)nvkm_instmem(object); struct gk20a_instobj *node = (void *)object; + struct nvkm_device *device = imem->base.subdev.device; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; @@ -114,10 +115,10 @@ gk20a_instobj_rd32(struct nvkm_object *object, u64 offset) spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { - nv_wr32(imem, 0x001700, base >> 16); + nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } - data = nv_rd32(imem, 0x700000 + addr); + data = nvkm_rd32(device, 0x700000 + addr); spin_unlock_irqrestore(&imem->lock, flags); return data; } @@ -127,16 +128,17 @@ gk20a_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) { struct gk20a_instmem *imem = (void *)nvkm_instmem(object); struct gk20a_instobj *node = (void *)object; + struct nvkm_device *device = imem->base.subdev.device; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { - nv_wr32(imem, 0x001700, base >> 16); + nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } - nv_wr32(imem, 0x700000 + addr, data); + nvkm_wr32(device, 0x700000 + addr, data); spin_unlock_irqrestore(&imem->lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 23084f18199ec..6410cc1fd419c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -105,13 +105,15 @@ nv04_instobj_oclass = { static u32 nv04_instmem_rd32(struct nvkm_object *object, u64 addr) { - return nv_rd32(object, 0x700000 + addr); + struct nvkm_instmem *imem = (void *)object; + return nvkm_rd32(imem->subdev.device, 0x700000 + addr); } static void nv04_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) { - return nv_wr32(object, 0x700000 + addr, data); + struct nvkm_instmem *imem = (void *)object; + nvkm_wr32(imem->subdev.device, 0x700000 + addr, data); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index d6827b377bd95..fe00881bda650 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -75,7 +75,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * to fit graphics contexts for every channel, the magics come * from engine/gr/nv40.c */ - vs = hweight8((nv_rd32(imem, 0x001540) & 0x0000ff00) >> 8); + vs = hweight8((nvkm_rd32(device, 0x001540) & 0x0000ff00) >> 8); if (device->chipset == 0x40) imem->base.reserved = 0x6aa0 * vs; else if (device->chipset < 0x43) imem->base.reserved = 0x4f00 * vs; else if (nv44_gr_class(imem)) imem->base.reserved = 0x4980 * vs; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 6c83c5797e322..339dd19e0e451 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -45,6 +45,7 @@ nv50_instobj_rd32(struct nvkm_object *object, u64 offset) { struct nv50_instmem *imem = (void *)nvkm_instmem(object); struct nv50_instobj *node = (void *)object; + struct nvkm_device *device = imem->base.subdev.device; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; @@ -52,10 +53,10 @@ nv50_instobj_rd32(struct nvkm_object *object, u64 offset) spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { - nv_wr32(imem, 0x001700, base >> 16); + nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } - data = nv_rd32(imem, 0x700000 + addr); + data = nvkm_rd32(device, 0x700000 + addr); spin_unlock_irqrestore(&imem->lock, flags); return data; } @@ -65,16 +66,17 @@ nv50_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) { struct nv50_instmem *imem = (void *)nvkm_instmem(object); struct nv50_instobj *node = (void *)object; + struct nvkm_device *device = imem->base.subdev.device; unsigned long flags; u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { - nv_wr32(imem, 0x001700, base >> 16); + nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } - nv_wr32(imem, 0x700000 + addr, data); + nvkm_wr32(device, 0x700000 + addr, data); spin_unlock_irqrestore(&imem->lock, flags); } -- GitLab From 99336ed363f49f484b4d93600c4dfec1f2ebb84a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5371/7006] drm/nouveau/ltc: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 51 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c | 11 ++-- .../gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 49 ++++++++++-------- 3 files changed, 63 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index b56e63f507d38..df60ee264b954 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -30,9 +30,10 @@ void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) { - nv_wr32(ltc, 0x17e8cc, start); - nv_wr32(ltc, 0x17e8d0, limit); - nv_wr32(ltc, 0x17e8c8, 0x00000004); + struct nvkm_device *device = ltc->base.subdev.device; + nvkm_wr32(device, 0x17e8cc, start); + nvkm_wr32(device, 0x17e8d0, limit); + nvkm_wr32(device, 0x17e8c8, 0x00000004); } void @@ -48,18 +49,20 @@ gf100_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) { - nv_mask(ltc, 0x17ea44, 0x0000000f, i); - nv_wr32(ltc, 0x17ea48, color[0]); - nv_wr32(ltc, 0x17ea4c, color[1]); - nv_wr32(ltc, 0x17ea50, color[2]); - nv_wr32(ltc, 0x17ea54, color[3]); + struct nvkm_device *device = ltc->base.subdev.device; + nvkm_mask(device, 0x17ea44, 0x0000000f, i); + nvkm_wr32(device, 0x17ea48, color[0]); + nvkm_wr32(device, 0x17ea4c, color[1]); + nvkm_wr32(device, 0x17ea50, color[2]); + nvkm_wr32(device, 0x17ea54, color[3]); } void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) { - nv_mask(ltc, 0x17ea44, 0x0000000f, i); - nv_wr32(ltc, 0x17ea58, depth); + struct nvkm_device *device = ltc->base.subdev.device; + nvkm_mask(device, 0x17ea44, 0x0000000f, i); + nvkm_wr32(device, 0x17ea58, depth); } static const struct nvkm_bitfield @@ -83,8 +86,9 @@ gf100_ltc_lts_intr_name[] = { static void gf100_ltc_lts_intr(struct nvkm_ltc_priv *ltc, int c, int s) { + struct nvkm_device *device = ltc->base.subdev.device; u32 base = 0x141000 + (c * 0x2000) + (s * 0x400); - u32 intr = nv_rd32(ltc, base + 0x020); + u32 intr = nvkm_rd32(device, base + 0x020); u32 stat = intr & 0x0000ffff; if (stat) { @@ -93,16 +97,17 @@ gf100_ltc_lts_intr(struct nvkm_ltc_priv *ltc, int c, int s) pr_cont("\n"); } - nv_wr32(ltc, base + 0x020, intr); + nvkm_wr32(device, base + 0x020, intr); } void gf100_ltc_intr(struct nvkm_subdev *subdev) { struct nvkm_ltc_priv *ltc = (void *)subdev; + struct nvkm_device *device = ltc->base.subdev.device; u32 mask; - mask = nv_rd32(ltc, 0x00017c); + mask = nvkm_rd32(device, 0x00017c); while (mask) { u32 s, c = __ffs(mask); for (s = 0; s < ltc->lts_nr; s++) @@ -115,17 +120,18 @@ static int gf100_ltc_init(struct nvkm_object *object) { struct nvkm_ltc_priv *ltc = (void *)object; - u32 lpg128 = !(nv_rd32(ltc, 0x100c80) & 0x00000001); + struct nvkm_device *device = ltc->base.subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); int ret; ret = nvkm_ltc_init(ltc); if (ret) return ret; - nv_mask(ltc, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nv_wr32(ltc, 0x17e8d8, ltc->ltc_nr); - nv_wr32(ltc, 0x17e8d4, ltc->tag_base); - nv_mask(ltc, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + nvkm_mask(device, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); + nvkm_wr32(device, 0x17e8d4, ltc->tag_base); + nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; } @@ -200,7 +206,8 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_fb *fb = device->fb; struct nvkm_ltc_priv *ltc; u32 parts, mask; int ret, i; @@ -210,13 +217,13 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - parts = nv_rd32(ltc, 0x022438); - mask = nv_rd32(ltc, 0x022554); + parts = nvkm_rd32(device, 0x022438); + mask = nvkm_rd32(device, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) ltc->ltc_nr++; } - ltc->lts_nr = nv_rd32(ltc, 0x17e8dc) >> 28; + ltc->lts_nr = nvkm_rd32(device, 0x17e8dc) >> 28; ret = gf100_ltc_init_tag_ram(fb, ltc); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c index c83a49dd1cb32..a1f97d2ec36f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c @@ -27,17 +27,18 @@ static int gk104_ltc_init(struct nvkm_object *object) { struct nvkm_ltc_priv *ltc = (void *)object; - u32 lpg128 = !(nv_rd32(ltc, 0x100c80) & 0x00000001); + struct nvkm_device *device = ltc->base.subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); int ret; ret = nvkm_ltc_init(ltc); if (ret) return ret; - nv_wr32(ltc, 0x17e8d8, ltc->ltc_nr); - nv_wr32(ltc, 0x17e000, ltc->ltc_nr); - nv_wr32(ltc, 0x17e8d4, ltc->tag_base); - nv_mask(ltc, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); + nvkm_wr32(device, 0x17e000, ltc->ltc_nr); + nvkm_wr32(device, 0x17e8d4, ltc->tag_base); + nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index fc4697cfe68d2..3f009bb76226d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -29,9 +29,10 @@ static void gm107_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) { - nv_wr32(ltc, 0x17e270, start); - nv_wr32(ltc, 0x17e274, limit); - nv_wr32(ltc, 0x17e26c, 0x00000004); + struct nvkm_device *device = ltc->base.subdev.device; + nvkm_wr32(device, 0x17e270, start); + nvkm_wr32(device, 0x17e274, limit); + nvkm_wr32(device, 0x17e26c, 0x00000004); } static void @@ -47,29 +48,32 @@ gm107_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) static void gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) { - nv_mask(ltc, 0x17e338, 0x0000000f, i); - nv_wr32(ltc, 0x17e33c, color[0]); - nv_wr32(ltc, 0x17e340, color[1]); - nv_wr32(ltc, 0x17e344, color[2]); - nv_wr32(ltc, 0x17e348, color[3]); + struct nvkm_device *device = ltc->base.subdev.device; + nvkm_mask(device, 0x17e338, 0x0000000f, i); + nvkm_wr32(device, 0x17e33c, color[0]); + nvkm_wr32(device, 0x17e340, color[1]); + nvkm_wr32(device, 0x17e344, color[2]); + nvkm_wr32(device, 0x17e348, color[3]); } static void gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) { - nv_mask(ltc, 0x17e338, 0x0000000f, i); - nv_wr32(ltc, 0x17e34c, depth); + struct nvkm_device *device = ltc->base.subdev.device; + nvkm_mask(device, 0x17e338, 0x0000000f, i); + nvkm_wr32(device, 0x17e34c, depth); } static void gm107_ltc_lts_isr(struct nvkm_ltc_priv *ltc, int c, int s) { + struct nvkm_device *device = ltc->base.subdev.device; u32 base = 0x140000 + (c * 0x2000) + (s * 0x400); - u32 stat = nv_rd32(ltc, base + 0x00c); + u32 stat = nvkm_rd32(device, base + 0x00c); if (stat) { nv_info(ltc, "LTC%d_LTS%d: 0x%08x\n", c, s, stat); - nv_wr32(ltc, base + 0x00c, stat); + nvkm_wr32(device, base + 0x00c, stat); } } @@ -77,9 +81,10 @@ static void gm107_ltc_intr(struct nvkm_subdev *subdev) { struct nvkm_ltc_priv *ltc = (void *)subdev; + struct nvkm_device *device = ltc->base.subdev.device; u32 mask; - mask = nv_rd32(ltc, 0x00017c); + mask = nvkm_rd32(device, 0x00017c); while (mask) { u32 s, c = __ffs(mask); for (s = 0; s < ltc->lts_nr; s++) @@ -92,16 +97,17 @@ static int gm107_ltc_init(struct nvkm_object *object) { struct nvkm_ltc_priv *ltc = (void *)object; - u32 lpg128 = !(nv_rd32(ltc, 0x100c80) & 0x00000001); + struct nvkm_device *device = ltc->base.subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); int ret; ret = nvkm_ltc_init(ltc); if (ret) return ret; - nv_wr32(ltc, 0x17e27c, ltc->ltc_nr); - nv_wr32(ltc, 0x17e278, ltc->tag_base); - nv_mask(ltc, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); + nvkm_wr32(device, 0x17e27c, ltc->ltc_nr); + nvkm_wr32(device, 0x17e278, ltc->tag_base); + nvkm_mask(device, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); return 0; } @@ -110,7 +116,8 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_fb *fb = device->fb; struct nvkm_ltc_priv *ltc; u32 parts, mask; int ret, i; @@ -120,13 +127,13 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - parts = nv_rd32(ltc, 0x022438); - mask = nv_rd32(ltc, 0x021c14); + parts = nvkm_rd32(device, 0x022438); + mask = nvkm_rd32(device, 0x021c14); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) ltc->ltc_nr++; } - ltc->lts_nr = nv_rd32(ltc, 0x17e280) >> 28; + ltc->lts_nr = nvkm_rd32(device, 0x17e280) >> 28; ret = gf100_ltc_init_tag_ram(fb, ltc); if (ret) -- GitLab From 25e3a463fc1bd39c01cc6d19d2c8b4c4725699b9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5372/7006] drm/nouveau/mc: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 20 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c | 13 ++++++------ drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 5 +++-- 6 files changed, 28 insertions(+), 21 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 3aa6efcf6725b..80c3c5062e91f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -36,7 +36,8 @@ nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) static inline u32 nvkm_mc_intr_mask(struct nvkm_mc *mc) { - u32 intr = nv_rd32(mc, 0x000100); + struct nvkm_device *device = mc->subdev.device; + u32 intr = nvkm_rd32(device, 0x000100); if (intr == 0xffffffff) /* likely fallen off the bus */ intr = 0x00000000; return intr; @@ -46,13 +47,14 @@ static irqreturn_t nvkm_mc_intr(int irq, void *arg) { struct nvkm_mc *mc = arg; + struct nvkm_device *device = mc->subdev.device; const struct nvkm_mc_oclass *oclass = (void *)nv_object(mc)->oclass; const struct nvkm_mc_intr *map = oclass->intr; struct nvkm_subdev *unit; u32 intr; - nv_wr32(mc, 0x000140, 0x00000000); - nv_rd32(mc, 0x000140); + nvkm_wr32(device, 0x000140, 0x00000000); + nvkm_rd32(device, 0x000140); intr = nvkm_mc_intr_mask(mc); if (mc->use_msi) oclass->msi_rearm(mc); @@ -73,7 +75,7 @@ nvkm_mc_intr(int irq, void *arg) nv_error(mc, "unknown intr 0x%08x\n", stat); } - nv_wr32(mc, 0x000140, 0x00000001); + nvkm_wr32(device, 0x000140, 0x00000001); return intr ? IRQ_HANDLED : IRQ_NONE; } @@ -81,7 +83,8 @@ int _nvkm_mc_fini(struct nvkm_object *object, bool suspend) { struct nvkm_mc *mc = (void *)object; - nv_wr32(mc, 0x000140, 0x00000000); + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000000); return nvkm_subdev_fini(&mc->subdev, suspend); } @@ -89,18 +92,19 @@ int _nvkm_mc_init(struct nvkm_object *object) { struct nvkm_mc *mc = (void *)object; + struct nvkm_device *device = mc->subdev.device; int ret = nvkm_subdev_init(&mc->subdev); if (ret) return ret; - nv_wr32(mc, 0x000140, 0x00000001); + nvkm_wr32(device, 0x000140, 0x00000001); return 0; } void _nvkm_mc_dtor(struct nvkm_object *object) { - struct nvkm_device *device = nv_device(object); struct nvkm_mc *mc = (void *)object; + struct nvkm_device *device = mc->subdev.device; free_irq(mc->irq, mc); if (mc->use_msi) pci_disable_msi(device->pdev); @@ -112,7 +116,7 @@ nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *bclass, int length, void **pobject) { const struct nvkm_mc_oclass *oclass = (void *)bclass; - struct nvkm_device *device = nv_device(parent); + struct nvkm_device *device = (void *)parent; struct nvkm_mc *mc; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index a2c4dbe64eebb..f6989cc802c40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -51,13 +51,13 @@ gf100_mc_intr[] = { static void gf100_mc_msi_rearm(struct nvkm_mc *mc) { - nv_wr32(mc, 0x088704, 0x00000000); + nvkm_wr32(mc->subdev.device, 0x088704, 0x00000000); } void gf100_mc_unk260(struct nvkm_mc *mc, u32 data) { - nv_wr32(mc, 0x000260, data); + nvkm_wr32(mc->subdev.device, 0x000260, data); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index 84670aac664f9..6e2fb94b6f848 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -42,9 +42,10 @@ int nv04_mc_init(struct nvkm_object *object) { struct nvkm_mc *mc = (void *)object; + struct nvkm_device *device = mc->subdev.device; - nv_wr32(mc, 0x000200, 0xffffffff); /* everything enabled */ - nv_wr32(mc, 0x001850, 0x00000001); /* disable rom access */ + nvkm_wr32(device, 0x000200, 0xffffffff); /* everything enabled */ + nvkm_wr32(device, 0x001850, 0x00000001); /* disable rom access */ return nvkm_mc_init(mc); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c index 80431b51bf620..8b46ee26440df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c @@ -26,7 +26,7 @@ void nv40_mc_msi_rearm(struct nvkm_mc *mc) { - nv_wr08(mc, 0x088068, 0xff); + nvkm_wr08(mc->subdev.device, 0x088068, 0xff); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 63c2d6603f9c7..36b3caaa088e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -27,14 +27,15 @@ int nv44_mc_init(struct nvkm_object *object) { struct nvkm_mc *mc = (void *)object; - u32 tmp = nv_rd32(mc, 0x10020c); + struct nvkm_device *device = mc->subdev.device; + u32 tmp = nvkm_rd32(device, 0x10020c); - nv_wr32(mc, 0x000200, 0xffffffff); /* everything enabled */ + nvkm_wr32(device, 0x000200, 0xffffffff); /* everything enabled */ - nv_wr32(mc, 0x001700, tmp); - nv_wr32(mc, 0x001704, 0); - nv_wr32(mc, 0x001708, 0); - nv_wr32(mc, 0x00170c, tmp); + nvkm_wr32(device, 0x001700, tmp); + nvkm_wr32(device, 0x001704, 0); + nvkm_wr32(device, 0x001708, 0); + nvkm_wr32(device, 0x00170c, tmp); return nvkm_mc_init(mc); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 4387e686ff6b5..4ef1c735a5425 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -44,7 +44,7 @@ nv50_mc_intr[] = { static void nv50_mc_msi_rearm(struct nvkm_mc *mc) { - struct nvkm_device *device = nv_device(mc); + struct nvkm_device *device = mc->subdev.device; pci_write_config_byte(device->pdev, 0x68, 0xff); } @@ -52,7 +52,8 @@ int nv50_mc_init(struct nvkm_object *object) { struct nvkm_mc *mc = (void *)object; - nv_wr32(mc, 0x000200, 0xffffffff); /* everything on */ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000200, 0xffffffff); /* everything on */ return nvkm_mc_init(mc); } -- GitLab From 83f56106ead017a07868176279746d73bc7a7060 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5373/7006] drm/nouveau/mmu: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 11 ++++---- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 14 ++++++---- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 28 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 5 ++-- 4 files changed, 32 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 982f7c7079343..3551b55a5646c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -154,7 +154,8 @@ static void gf100_vm_flush(struct nvkm_vm *vm) { struct nvkm_mmu *mmu = (void *)vm->mmu; - struct nvkm_bar *bar = nvkm_bar(mmu); + struct nvkm_device *device = mmu->subdev.device; + struct nvkm_bar *bar = device->bar; struct nvkm_vm_pgd *vpgd; u32 type; @@ -171,16 +172,16 @@ gf100_vm_flush(struct nvkm_vm *vm) */ if (!nv_wait_ne(mmu, 0x100c80, 0x00ff0000, 0x00000000)) { nv_error(mmu, "vm timeout 0: 0x%08x %d\n", - nv_rd32(mmu, 0x100c80), type); + nvkm_rd32(device, 0x100c80), type); } - nv_wr32(mmu, 0x100cb8, vpgd->obj->addr >> 8); - nv_wr32(mmu, 0x100cbc, 0x80000000 | type); + nvkm_wr32(device, 0x100cb8, vpgd->obj->addr >> 8); + nvkm_wr32(device, 0x100cbc, 0x80000000 | type); /* wait for flush to be queued? */ if (!nv_wait(mmu, 0x100c80, 0x00008000, 0x00008000)) { nv_error(mmu, "vm timeout 1: 0x%08x %d\n", - nv_rd32(mmu, 0x100c80), type); + nvkm_rd32(device, 0x100c80), type); } } mutex_unlock(&nv_subdev(mmu)->mutex); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 17b2b3979da43..609c6a69b60aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -65,14 +65,15 @@ static void nv41_vm_flush(struct nvkm_vm *vm) { struct nv04_mmu *mmu = (void *)vm->mmu; + struct nvkm_device *device = mmu->base.subdev.device; mutex_lock(&nv_subdev(mmu)->mutex); - nv_wr32(mmu, 0x100810, 0x00000022); + nvkm_wr32(device, 0x100810, 0x00000022); if (!nv_wait(mmu, 0x100810, 0x00000020, 0x00000020)) { nv_warn(mmu, "flush timeout, 0x%08x\n", - nv_rd32(mmu, 0x100810)); + nvkm_rd32(device, 0x100810)); } - nv_wr32(mmu, 0x100810, 0x00000000); + nvkm_wr32(device, 0x100810, 0x00000000); mutex_unlock(&nv_subdev(mmu)->mutex); } @@ -131,6 +132,7 @@ static int nv41_mmu_init(struct nvkm_object *object) { struct nv04_mmu *mmu = (void *)object; + struct nvkm_device *device = mmu->base.subdev.device; struct nvkm_gpuobj *dma = mmu->vm->pgt[0].obj[0]; int ret; @@ -138,9 +140,9 @@ nv41_mmu_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(mmu, 0x100800, dma->addr | 0x00000002); - nv_mask(mmu, 0x10008c, 0x00000100, 0x00000100); - nv_wr32(mmu, 0x100820, 0x00000000); + nvkm_wr32(device, 0x100800, dma->addr | 0x00000002); + nvkm_mask(device, 0x10008c, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x100820, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 860654fee3876..371f627e17dbd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -140,11 +140,12 @@ static void nv44_vm_flush(struct nvkm_vm *vm) { struct nv04_mmu *mmu = (void *)vm->mmu; - nv_wr32(mmu, 0x100814, mmu->base.limit - NV44_GART_PAGE); - nv_wr32(mmu, 0x100808, 0x00000020); + struct nvkm_device *device = mmu->base.subdev.device; + nvkm_wr32(device, 0x100814, mmu->base.limit - NV44_GART_PAGE); + nvkm_wr32(device, 0x100808, 0x00000020); if (!nv_wait(mmu, 0x100808, 0x00000001, 0x00000001)) - nv_error(mmu, "timeout: 0x%08x\n", nv_rd32(mmu, 0x100808)); - nv_wr32(mmu, 0x100808, 0x00000000); + nv_error(mmu, "timeout: 0x%08x\n", nvkm_rd32(device, 0x100808)); + nvkm_wr32(device, 0x100808, 0x00000000); } /******************************************************************************* @@ -208,6 +209,7 @@ static int nv44_mmu_init(struct nvkm_object *object) { struct nv04_mmu *mmu = (void *)object; + struct nvkm_device *device = mmu->base.subdev.device; struct nvkm_gpuobj *gart = mmu->vm->pgt[0].obj[0]; u32 addr; int ret; @@ -220,17 +222,17 @@ nv44_mmu_init(struct nvkm_object *object) * allocated on 512KiB alignment, and not exceed a total size * of 512KiB for this to work correctly */ - addr = nv_rd32(mmu, 0x10020c); + addr = nvkm_rd32(device, 0x10020c); addr -= ((gart->addr >> 19) + 1) << 19; - nv_wr32(mmu, 0x100850, 0x80000000); - nv_wr32(mmu, 0x100818, mmu->null); - nv_wr32(mmu, 0x100804, NV44_GART_SIZE); - nv_wr32(mmu, 0x100850, 0x00008000); - nv_mask(mmu, 0x10008c, 0x00000200, 0x00000200); - nv_wr32(mmu, 0x100820, 0x00000000); - nv_wr32(mmu, 0x10082c, 0x00000001); - nv_wr32(mmu, 0x100800, addr | 0x00000010); + nvkm_wr32(device, 0x100850, 0x80000000); + nvkm_wr32(device, 0x100818, mmu->null); + nvkm_wr32(device, 0x100804, NV44_GART_SIZE); + nvkm_wr32(device, 0x100850, 0x00008000); + nvkm_mask(device, 0x10008c, 0x00000200, 0x00000200); + nvkm_wr32(device, 0x100820, 0x00000000); + nvkm_wr32(device, 0x10082c, 0x00000001); + nvkm_wr32(device, 0x100800, addr | 0x00000010); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index 75c6a07e2dd54..1d7e1aa7e7d3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -146,7 +146,8 @@ static void nv50_vm_flush(struct nvkm_vm *vm) { struct nvkm_mmu *mmu = (void *)vm->mmu; - struct nvkm_bar *bar = nvkm_bar(mmu); + struct nvkm_device *device = mmu->subdev.device; + struct nvkm_bar *bar = device->bar; struct nvkm_engine *engine; int i, vme; @@ -180,7 +181,7 @@ nv50_vm_flush(struct nvkm_vm *vm) continue; } - nv_wr32(mmu, 0x100c80, (vme << 16) | 1); + nvkm_wr32(device, 0x100c80, (vme << 16) | 1); if (!nv_wait(mmu, 0x100c80, 0x00000001, 0x00000000)) nv_error(mmu, "vm flush timeout: engine %d\n", vme); } -- GitLab From bef002e87f1accc12a7fc7c98b80354c136c199e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5374/7006] drm/nouveau/pmu: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 107 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 64 +++++------ .../gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c | 29 ++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 17 +-- .../gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/memx.c | 31 ++--- 6 files changed, 133 insertions(+), 120 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index e0fbf5aaeeebd..b754b65f2c36f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -37,11 +37,12 @@ static int nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], u32 process, u32 message, u32 data0, u32 data1) { - struct nvkm_subdev *subdev = nv_subdev(pmu); + struct nvkm_subdev *subdev = &pmu->subdev; + struct nvkm_device *device = subdev->device; u32 addr; /* wait for a free slot in the fifo */ - addr = nv_rd32(pmu, 0x10a4a0); + addr = nvkm_rd32(device, 0x10a4a0); if (!nv_wait_ne(pmu, 0x10a4b0, 0xffffffff, addr ^ 8)) return -EBUSY; @@ -57,20 +58,20 @@ nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], /* acquire data segment access */ do { - nv_wr32(pmu, 0x10a580, 0x00000001); - } while (nv_rd32(pmu, 0x10a580) != 0x00000001); + nvkm_wr32(device, 0x10a580, 0x00000001); + } while (nvkm_rd32(device, 0x10a580) != 0x00000001); /* write the packet */ - nv_wr32(pmu, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) + + nvkm_wr32(device, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) + pmu->send.base)); - nv_wr32(pmu, 0x10a1c4, process); - nv_wr32(pmu, 0x10a1c4, message); - nv_wr32(pmu, 0x10a1c4, data0); - nv_wr32(pmu, 0x10a1c4, data1); - nv_wr32(pmu, 0x10a4a0, (addr + 1) & 0x0f); + nvkm_wr32(device, 0x10a1c4, process); + nvkm_wr32(device, 0x10a1c4, message); + nvkm_wr32(device, 0x10a1c4, data0); + nvkm_wr32(device, 0x10a1c4, data1); + nvkm_wr32(device, 0x10a4a0, (addr + 1) & 0x0f); /* release data segment access */ - nv_wr32(pmu, 0x10a580, 0x00000000); + nvkm_wr32(device, 0x10a580, 0x00000000); /* wait for reply, if requested */ if (reply) { @@ -87,29 +88,30 @@ static void nvkm_pmu_recv(struct work_struct *work) { struct nvkm_pmu *pmu = container_of(work, struct nvkm_pmu, recv.work); + struct nvkm_device *device = pmu->subdev.device; u32 process, message, data0, data1; /* nothing to do if GET == PUT */ - u32 addr = nv_rd32(pmu, 0x10a4cc); - if (addr == nv_rd32(pmu, 0x10a4c8)) + u32 addr = nvkm_rd32(device, 0x10a4cc); + if (addr == nvkm_rd32(device, 0x10a4c8)) return; /* acquire data segment access */ do { - nv_wr32(pmu, 0x10a580, 0x00000002); - } while (nv_rd32(pmu, 0x10a580) != 0x00000002); + nvkm_wr32(device, 0x10a580, 0x00000002); + } while (nvkm_rd32(device, 0x10a580) != 0x00000002); /* read the packet */ - nv_wr32(pmu, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) + + nvkm_wr32(device, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) + pmu->recv.base)); - process = nv_rd32(pmu, 0x10a1c4); - message = nv_rd32(pmu, 0x10a1c4); - data0 = nv_rd32(pmu, 0x10a1c4); - data1 = nv_rd32(pmu, 0x10a1c4); - nv_wr32(pmu, 0x10a4cc, (addr + 1) & 0x0f); + process = nvkm_rd32(device, 0x10a1c4); + message = nvkm_rd32(device, 0x10a1c4); + data0 = nvkm_rd32(device, 0x10a1c4); + data1 = nvkm_rd32(device, 0x10a1c4); + nvkm_wr32(device, 0x10a4cc, (addr + 1) & 0x0f); /* release data segment access */ - nv_wr32(pmu, 0x10a580, 0x00000000); + nvkm_wr32(device, 0x10a580, 0x00000000); /* wake process if it's waiting on a synchronous reply */ if (pmu->recv.process) { @@ -137,36 +139,37 @@ nvkm_pmu_recv(struct work_struct *work) static void nvkm_pmu_intr(struct nvkm_subdev *subdev) { - struct nvkm_pmu *pmu = (void *)subdev; - u32 disp = nv_rd32(pmu, 0x10a01c); - u32 intr = nv_rd32(pmu, 0x10a008) & disp & ~(disp >> 16); + struct nvkm_pmu *pmu = container_of(subdev, typeof(*pmu), subdev); + struct nvkm_device *device = pmu->subdev.device; + u32 disp = nvkm_rd32(device, 0x10a01c); + u32 intr = nvkm_rd32(device, 0x10a008) & disp & ~(disp >> 16); if (intr & 0x00000020) { - u32 stat = nv_rd32(pmu, 0x10a16c); + u32 stat = nvkm_rd32(device, 0x10a16c); if (stat & 0x80000000) { nv_error(pmu, "UAS fault at 0x%06x addr 0x%08x\n", - stat & 0x00ffffff, nv_rd32(pmu, 0x10a168)); - nv_wr32(pmu, 0x10a16c, 0x00000000); + stat & 0x00ffffff, nvkm_rd32(device, 0x10a168)); + nvkm_wr32(device, 0x10a16c, 0x00000000); intr &= ~0x00000020; } } if (intr & 0x00000040) { schedule_work(&pmu->recv.work); - nv_wr32(pmu, 0x10a004, 0x00000040); + nvkm_wr32(device, 0x10a004, 0x00000040); intr &= ~0x00000040; } if (intr & 0x00000080) { - nv_info(pmu, "wr32 0x%06x 0x%08x\n", nv_rd32(pmu, 0x10a7a0), - nv_rd32(pmu, 0x10a7a4)); - nv_wr32(pmu, 0x10a004, 0x00000080); + nv_info(pmu, "wr32 0x%06x 0x%08x\n", nvkm_rd32(device, 0x10a7a0), + nvkm_rd32(device, 0x10a7a4)); + nvkm_wr32(device, 0x10a004, 0x00000080); intr &= ~0x00000080; } if (intr) { nv_error(pmu, "intr 0x%08x\n", intr); - nv_wr32(pmu, 0x10a004, intr); + nvkm_wr32(device, 0x10a004, intr); } } @@ -174,8 +177,9 @@ int _nvkm_pmu_fini(struct nvkm_object *object, bool suspend) { struct nvkm_pmu *pmu = (void *)object; + struct nvkm_device *device = pmu->subdev.device; - nv_wr32(pmu, 0x10a014, 0x00000060); + nvkm_wr32(device, 0x10a014, 0x00000060); flush_work(&pmu->recv.work); return nvkm_subdev_fini(&pmu->subdev, suspend); @@ -186,6 +190,7 @@ _nvkm_pmu_init(struct nvkm_object *object) { const struct nvkm_pmu_impl *impl = (void *)object->oclass; struct nvkm_pmu *pmu = (void *)object; + struct nvkm_device *device = pmu->subdev.device; int ret, i; ret = nvkm_subdev_init(&pmu->subdev); @@ -197,44 +202,44 @@ _nvkm_pmu_init(struct nvkm_object *object) pmu->pgob = nvkm_pmu_pgob; /* prevent previous ucode from running, wait for idle, reset */ - nv_wr32(pmu, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ + nvkm_wr32(device, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ nv_wait(pmu, 0x10a04c, 0xffffffff, 0x00000000); - nv_mask(pmu, 0x000200, 0x00002000, 0x00000000); - nv_mask(pmu, 0x000200, 0x00002000, 0x00002000); - nv_rd32(pmu, 0x000200); + nvkm_mask(device, 0x000200, 0x00002000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00002000, 0x00002000); + nvkm_rd32(device, 0x000200); nv_wait(pmu, 0x10a10c, 0x00000006, 0x00000000); /* upload data segment */ - nv_wr32(pmu, 0x10a1c0, 0x01000000); + nvkm_wr32(device, 0x10a1c0, 0x01000000); for (i = 0; i < impl->data.size / 4; i++) - nv_wr32(pmu, 0x10a1c4, impl->data.data[i]); + nvkm_wr32(device, 0x10a1c4, impl->data.data[i]); /* upload code segment */ - nv_wr32(pmu, 0x10a180, 0x01000000); + nvkm_wr32(device, 0x10a180, 0x01000000); for (i = 0; i < impl->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(pmu, 0x10a188, i >> 6); - nv_wr32(pmu, 0x10a184, impl->code.data[i]); + nvkm_wr32(device, 0x10a188, i >> 6); + nvkm_wr32(device, 0x10a184, impl->code.data[i]); } /* start it running */ - nv_wr32(pmu, 0x10a10c, 0x00000000); - nv_wr32(pmu, 0x10a104, 0x00000000); - nv_wr32(pmu, 0x10a100, 0x00000002); + nvkm_wr32(device, 0x10a10c, 0x00000000); + nvkm_wr32(device, 0x10a104, 0x00000000); + nvkm_wr32(device, 0x10a100, 0x00000002); /* wait for valid host->pmu ring configuration */ if (!nv_wait_ne(pmu, 0x10a4d0, 0xffffffff, 0x00000000)) return -EBUSY; - pmu->send.base = nv_rd32(pmu, 0x10a4d0) & 0x0000ffff; - pmu->send.size = nv_rd32(pmu, 0x10a4d0) >> 16; + pmu->send.base = nvkm_rd32(device, 0x10a4d0) & 0x0000ffff; + pmu->send.size = nvkm_rd32(device, 0x10a4d0) >> 16; /* wait for valid pmu->host ring configuration */ if (!nv_wait_ne(pmu, 0x10a4dc, 0xffffffff, 0x00000000)) return -EBUSY; - pmu->recv.base = nv_rd32(pmu, 0x10a4dc) & 0x0000ffff; - pmu->recv.size = nv_rd32(pmu, 0x10a4dc) >> 16; + pmu->recv.base = nvkm_rd32(device, 0x10a4dc) & 0x0000ffff; + pmu->recv.size = nvkm_rd32(device, 0x10a4dc) >> 16; - nv_wr32(pmu, 0x10a010, 0x000000e0); + nvkm_wr32(device, 0x10a010, 0x000000e0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 1e9f1d0f7a7d9..a6d6162a36186 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -31,49 +31,49 @@ #include static void -magic_(struct nvkm_pmu *pmu, u32 ctrl, int size) +magic_(struct nvkm_device *device, u32 ctrl, int size) { - nv_wr32(pmu, 0x00c800, 0x00000000); - nv_wr32(pmu, 0x00c808, 0x00000000); - nv_wr32(pmu, 0x00c800, ctrl); - if (nv_wait(pmu, 0x00c800, 0x40000000, 0x40000000)) { + nvkm_wr32(device, 0x00c800, 0x00000000); + nvkm_wr32(device, 0x00c808, 0x00000000); + nvkm_wr32(device, 0x00c800, ctrl); + if (nv_wait(device, 0x00c800, 0x40000000, 0x40000000)) { while (size--) - nv_wr32(pmu, 0x00c804, 0x00000000); + nvkm_wr32(device, 0x00c804, 0x00000000); } - nv_wr32(pmu, 0x00c800, 0x00000000); + nvkm_wr32(device, 0x00c800, 0x00000000); } static void -magic(struct nvkm_pmu *pmu, u32 ctrl) +magic(struct nvkm_device *device, u32 ctrl) { - magic_(pmu, 0x8000a41f | ctrl, 6); - magic_(pmu, 0x80000421 | ctrl, 1); + magic_(device, 0x8000a41f | ctrl, 6); + magic_(device, 0x80000421 | ctrl, 1); } static void gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { - struct nvkm_device *device = nv_device(pmu); + struct nvkm_device *device = pmu->subdev.device; - nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); - nv_rd32(pmu, 0x000200); - nv_mask(pmu, 0x000200, 0x08000000, 0x08000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00000000); + nvkm_rd32(device, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x08000000); msleep(50); - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000002); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000); + nvkm_mask(device, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000); msleep(50); - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x000200, 0x08000000, 0x00000000); - nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); - nv_rd32(pmu, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00001000); + nvkm_rd32(device, 0x000200); if (nv_device_match(device, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ || nv_device_match(device, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ @@ -81,18 +81,18 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nv_info(pmu, "hw bug workaround enabled\n"); switch (device->chipset) { case 0xe4: - magic(pmu, 0x04000000); - magic(pmu, 0x06000000); - magic(pmu, 0x0c000000); - magic(pmu, 0x0e000000); + magic(device, 0x04000000); + magic(device, 0x06000000); + magic(device, 0x0c000000); + magic(device, 0x0e000000); break; case 0xe6: - magic(pmu, 0x02000000); - magic(pmu, 0x04000000); - magic(pmu, 0x0a000000); + magic(device, 0x02000000); + magic(device, 0x04000000); + magic(device, 0x0a000000); break; case 0xe7: - magic(pmu, 0x02000000); + magic(device, 0x02000000); break; default: break; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c index 89bb94b0af8bc..37ab487d60aa0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c @@ -31,6 +31,7 @@ void gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { + struct nvkm_device *device = pmu->subdev.device; static const struct { u32 addr; u32 data; @@ -54,28 +55,28 @@ gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable) }; int i; - nv_mask(pmu, 0x000200, 0x00001000, 0x00000000); - nv_rd32(pmu, 0x000200); - nv_mask(pmu, 0x000200, 0x08000000, 0x08000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00000000); + nvkm_rd32(device, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x08000000); msleep(50); - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000002); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x0206b4, 0x00000000, 0x00000000); + nvkm_mask(device, 0x0206b4, 0x00000000, 0x00000000); for (i = 0; i < ARRAY_SIZE(magic); i++) { - nv_wr32(pmu, magic[i].addr, magic[i].data); + nvkm_wr32(device, magic[i].addr, magic[i].data); nv_wait(pmu, magic[i].addr, 0x80000000, 0x00000000); } - nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001); - nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000000); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x10a78c, 0x00000001, 0x00000000); - nv_mask(pmu, 0x000200, 0x08000000, 0x00000000); - nv_mask(pmu, 0x000200, 0x00001000, 0x00001000); - nv_rd32(pmu, 0x000200); + nvkm_mask(device, 0x000200, 0x08000000, 0x00000000); + nvkm_mask(device, 0x000200, 0x00001000, 0x00001000); + nvkm_rd32(device, 0x000200); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 069e9dacc6d3f..20087d53fb9c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -98,16 +98,18 @@ static int gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu *pmu, struct gk20a_pmu_dvfs_dev_status *status) { - status->busy = nv_rd32(pmu, 0x10a508 + (BUSY_SLOT * 0x10)); - status->total= nv_rd32(pmu, 0x10a508 + (CLK_SLOT * 0x10)); + struct nvkm_device *device = pmu->base.subdev.device; + status->busy = nvkm_rd32(device, 0x10a508 + (BUSY_SLOT * 0x10)); + status->total= nvkm_rd32(device, 0x10a508 + (CLK_SLOT * 0x10)); return 0; } static void gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu *pmu) { - nv_wr32(pmu, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000); - nv_wr32(pmu, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000); + struct nvkm_device *device = pmu->base.subdev.device; + nvkm_wr32(device, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000); + nvkm_wr32(device, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000); } static void @@ -173,6 +175,7 @@ static int gk20a_pmu_init(struct nvkm_object *object) { struct gk20a_pmu *pmu = (void *)object; + struct nvkm_device *device = pmu->base.subdev.device; int ret; ret = nvkm_subdev_init(&pmu->base.subdev); @@ -182,9 +185,9 @@ gk20a_pmu_init(struct nvkm_object *object) pmu->base.pgob = nvkm_pmu_pgob; /* init pwr perf counter */ - nv_wr32(pmu, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001); - nv_wr32(pmu, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); - nv_wr32(pmu, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); + nvkm_wr32(device, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001); + nvkm_wr32(device, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); + nvkm_wr32(device, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); nvkm_timer_alarm(pmu, 2000000000, &pmu->alarm); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index 30aaeb21de417..223f9fb9f44f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -28,8 +28,9 @@ static int gt215_pmu_init(struct nvkm_object *object) { struct nvkm_pmu *pmu = (void *)object; - nv_mask(pmu, 0x022210, 0x00000001, 0x00000000); - nv_mask(pmu, 0x022210, 0x00000001, 0x00000001); + struct nvkm_device *device = pmu->subdev.device; + nvkm_mask(device, 0x022210, 0x00000001, 0x00000000); + nvkm_mask(device, 0x022210, 0x00000001, 0x00000001); return nvkm_pmu_init(pmu); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index 8e69bc75e5716..8469698847964 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -16,13 +16,13 @@ struct nvkm_memx { static void memx_out(struct nvkm_memx *memx) { - struct nvkm_pmu *pmu = memx->pmu; + struct nvkm_device *device = memx->pmu->subdev.device; int i; if (memx->c.mthd) { - nv_wr32(pmu, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); + nvkm_wr32(device, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd); for (i = 0; i < memx->c.size; i++) - nv_wr32(pmu, 0x10a1c4, memx->c.data[i]); + nvkm_wr32(device, 0x10a1c4, memx->c.data[i]); memx->c.mthd = 0; memx->c.size = 0; } @@ -42,6 +42,7 @@ memx_cmd(struct nvkm_memx *memx, u32 mthd, u32 size, u32 data[]) int nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx) { + struct nvkm_device *device = pmu->subdev.device; struct nvkm_memx *memx; u32 reply[2]; int ret; @@ -60,9 +61,9 @@ nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx) /* acquire data segment access */ do { - nv_wr32(pmu, 0x10a580, 0x00000003); - } while (nv_rd32(pmu, 0x10a580) != 0x00000003); - nv_wr32(pmu, 0x10a1c0, 0x01000000 | memx->base); + nvkm_wr32(device, 0x10a580, 0x00000003); + } while (nvkm_rd32(device, 0x10a580) != 0x00000003); + nvkm_wr32(device, 0x10a1c0, 0x01000000 | memx->base); return 0; } @@ -71,14 +72,15 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) { struct nvkm_memx *memx = *pmemx; struct nvkm_pmu *pmu = memx->pmu; + struct nvkm_device *device = pmu->subdev.device; u32 finish, reply[2]; /* flush the cache... */ memx_out(memx); /* release data segment access */ - finish = nv_rd32(pmu, 0x10a1c0) & 0x00ffffff; - nv_wr32(pmu, 0x10a580, 0x00000000); + finish = nvkm_rd32(device, 0x10a1c0) & 0x00ffffff; + nvkm_wr32(device, 0x10a580, 0x00000000); /* call MEMX process to execute the script, and wait for reply */ if (exec) { @@ -120,16 +122,16 @@ nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec) void nvkm_memx_wait_vblank(struct nvkm_memx *memx) { - struct nvkm_pmu *pmu = memx->pmu; + struct nvkm_device *device = memx->pmu->subdev.device; u32 heads, x, y, px = 0; int i, head_sync; - if (nv_device(pmu)->chipset < 0xd0) { - heads = nv_rd32(pmu, 0x610050); + if (device->chipset < 0xd0) { + heads = nvkm_rd32(device, 0x610050); for (i = 0; i < 2; i++) { /* Heuristic: sync to head with biggest resolution */ if (heads & (2 << (i << 3))) { - x = nv_rd32(pmu, 0x610b40 + (0x540 * i)); + x = nvkm_rd32(device, 0x610b40 + (0x540 * i)); y = (x & 0xffff0000) >> 16; x &= 0x0000ffff; if ((x * y) > px) { @@ -160,6 +162,7 @@ nvkm_memx_train(struct nvkm_memx *memx) int nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) { + struct nvkm_device *device = pmu->subdev.device; u32 reply[2], base, size, i; int ret; @@ -174,10 +177,10 @@ nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) return -ENOMEM; /* read the packet */ - nv_wr32(pmu, 0x10a1c0, 0x02000000 | base); + nvkm_wr32(device, 0x10a1c0, 0x02000000 | base); for (i = 0; i < size; i++) - res[i] = nv_rd32(pmu, 0x10a1c4); + res[i] = nvkm_rd32(device, 0x10a1c4); return 0; } -- GitLab From 5718ea3257f5fb945a8625dd17d0d753c9dbec34 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5375/7006] drm/nouveau/therm: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 44 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/therm/gf110.c | 42 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/therm/gm107.c | 12 ++--- .../gpu/drm/nouveau/nvkm/subdev/therm/gt215.c | 16 ++++--- .../gpu/drm/nouveau/nvkm/subdev/therm/nv40.c | 44 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/therm/nv50.c | 34 +++++++------- 6 files changed, 110 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index 555722900bb38..50d198b610872 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -29,10 +29,11 @@ int g84_temp_get(struct nvkm_therm *therm) { + struct nvkm_device *device = therm->subdev.device; struct nvkm_fuse *fuse = nvkm_fuse(therm); if (nv_ro32(fuse, 0x1a8) == 1) - return nv_rd32(therm, 0x20400); + return nvkm_rd32(device, 0x20400); else return -ENODEV; } @@ -40,12 +41,13 @@ g84_temp_get(struct nvkm_therm *therm) void g84_sensor_setup(struct nvkm_therm *therm) { + struct nvkm_device *device = therm->subdev.device; struct nvkm_fuse *fuse = nvkm_fuse(therm); /* enable temperature reading for cards with insane defaults */ if (nv_ro32(fuse, 0x1a8) == 1) { - nv_mask(therm, 0x20008, 0x80008000, 0x80000000); - nv_mask(therm, 0x2000c, 0x80000003, 0x00000000); + nvkm_mask(device, 0x20008, 0x80008000, 0x80000000); + nvkm_mask(device, 0x2000c, 0x80000003, 0x00000000); mdelay(20); /* wait for the temperature to stabilize */ } } @@ -54,26 +56,27 @@ static void g84_therm_program_alarms(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_device *device = therm->base.subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; unsigned long flags; spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); /* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */ - nv_wr32(therm, 0x20000, 0x000003ff); + nvkm_wr32(device, 0x20000, 0x000003ff); /* shutdown: The computer should be shutdown when reached */ - nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis); - nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp); + nvkm_wr32(device, 0x20484, sensor->thrs_shutdown.hysteresis); + nvkm_wr32(device, 0x20480, sensor->thrs_shutdown.temp); /* THRS_1 : fan boost*/ - nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp); + nvkm_wr32(device, 0x204c4, sensor->thrs_fan_boost.temp); /* THRS_2 : critical */ - nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp); + nvkm_wr32(device, 0x204c0, sensor->thrs_critical.temp); /* THRS_4 : down clock */ - nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp); + nvkm_wr32(device, 0x20414, sensor->thrs_down_clock.temp); spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); nv_debug(therm, @@ -93,19 +96,20 @@ g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm, const struct nvbios_therm_threshold *thrs, enum nvkm_therm_thrs thrs_name) { + struct nvkm_device *device = therm->subdev.device; enum nvkm_therm_thrs_direction direction; enum nvkm_therm_thrs_state prev_state, new_state; int temp, cur; prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name); - temp = nv_rd32(therm, thrs_reg); + temp = nvkm_rd32(device, thrs_reg); /* program the next threshold */ if (temp == thrs->temp) { - nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis); + nvkm_wr32(device, thrs_reg, thrs->temp - thrs->hysteresis); new_state = NVKM_THERM_THRS_HIGHER; } else { - nv_wr32(therm, thrs_reg, thrs->temp); + nvkm_wr32(device, thrs_reg, thrs->temp); new_state = NVKM_THERM_THRS_LOWER; } @@ -134,13 +138,14 @@ static void g84_therm_intr(struct nvkm_subdev *subdev) { struct nvkm_therm_priv *therm = (void *)subdev; + struct nvkm_device *device = therm->base.subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; unsigned long flags; uint32_t intr; spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); - intr = nv_rd32(therm, 0x20100) & 0x3ff; + intr = nvkm_rd32(device, 0x20100) & 0x3ff; /* THRS_4: downclock */ if (intr & 0x002) { @@ -178,8 +183,8 @@ g84_therm_intr(struct nvkm_subdev *subdev) nv_error(therm, "unhandled intr 0x%08x\n", intr); /* ACK everything */ - nv_wr32(therm, 0x20100, 0xffffffff); - nv_wr32(therm, 0x1100, 0x10000); /* PBUS */ + nvkm_wr32(device, 0x20100, 0xffffffff); + nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */ spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); } @@ -239,12 +244,15 @@ g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int g84_therm_fini(struct nvkm_object *object, bool suspend) { + struct nvkm_therm *therm = (void *)object; + struct nvkm_device *device = therm->subdev.device; + /* Disable PTherm IRQs */ - nv_wr32(object, 0x20000, 0x00000000); + nvkm_wr32(device, 0x20000, 0x00000000); /* ACK all PTherm IRQs */ - nv_wr32(object, 0x20100, 0xffffffff); - nv_wr32(object, 0x1100, 0x10000); /* PBUS */ + nvkm_wr32(device, 0x20100, 0xffffffff); + nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */ return _nvkm_therm_fini(object, suspend); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c index 4a2a2de9ef0b8..9686250e5a02b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c @@ -26,7 +26,8 @@ static int pwm_info(struct nvkm_therm *therm, int line) { - u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04)); + struct nvkm_device *device = therm->subdev.device; + u32 gpio = nvkm_rd32(device, 0x00d610 + (line * 0x04)); switch (gpio & 0x000000c0) { case 0x00000000: /* normal mode, possibly pwm forced off by us */ @@ -50,12 +51,13 @@ pwm_info(struct nvkm_therm *therm, int line) static int gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { + struct nvkm_device *device = therm->subdev.device; u32 data = enable ? 0x00000040 : 0x00000000; int indx = pwm_info(therm, line); if (indx < 0) return indx; else if (indx < 2) - nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data); + nvkm_mask(device, 0x00d610 + (line * 0x04), 0x000000c0, data); /* nothing to do for indx == 2, it seems hardwired to PTHERM */ return 0; } @@ -63,18 +65,19 @@ gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) static int gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { + struct nvkm_device *device = therm->subdev.device; int indx = pwm_info(therm, line); if (indx < 0) return indx; else if (indx < 2) { - if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) { - *divs = nv_rd32(therm, 0x00e114 + (indx * 8)); - *duty = nv_rd32(therm, 0x00e118 + (indx * 8)); + if (nvkm_rd32(device, 0x00d610 + (line * 0x04)) & 0x00000040) { + *divs = nvkm_rd32(device, 0x00e114 + (indx * 8)); + *duty = nvkm_rd32(device, 0x00e118 + (indx * 8)); return 0; } } else if (indx == 2) { - *divs = nv_rd32(therm, 0x0200d8) & 0x1fff; - *duty = nv_rd32(therm, 0x0200dc) & 0x1fff; + *divs = nvkm_rd32(device, 0x0200d8) & 0x1fff; + *duty = nvkm_rd32(device, 0x0200dc) & 0x1fff; return 0; } @@ -84,15 +87,16 @@ gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) static int gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { + struct nvkm_device *device = therm->subdev.device; int indx = pwm_info(therm, line); if (indx < 0) return indx; else if (indx < 2) { - nv_wr32(therm, 0x00e114 + (indx * 8), divs); - nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000); + nvkm_wr32(device, 0x00e114 + (indx * 8), divs); + nvkm_wr32(device, 0x00e118 + (indx * 8), duty | 0x80000000); } else if (indx == 2) { - nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */ - nv_wr32(therm, 0x0200dc, duty | 0x40000000); + nvkm_mask(device, 0x0200d8, 0x1fff, divs); /* keep the high bits */ + nvkm_wr32(device, 0x0200dc, duty | 0x40000000); } return 0; } @@ -100,19 +104,21 @@ gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) static int gf110_fan_pwm_clock(struct nvkm_therm *therm, int line) { + struct nvkm_device *device = therm->subdev.device; int indx = pwm_info(therm, line); if (indx < 0) return 0; else if (indx < 2) - return (nv_device(therm)->crystal * 1000) / 20; + return (device->crystal * 1000) / 20; else - return nv_device(therm)->crystal * 1000 / 10; + return device->crystal * 1000 / 10; } int gf110_therm_init(struct nvkm_object *object) { struct nvkm_therm_priv *therm = (void *)object; + struct nvkm_device *device = therm->base.subdev.device; int ret; ret = nvkm_therm_init(&therm->base); @@ -120,13 +126,13 @@ gf110_therm_init(struct nvkm_object *object) return ret; /* enable fan tach, count revolutions per-second */ - nv_mask(therm, 0x00e720, 0x00000003, 0x00000002); + nvkm_mask(device, 0x00e720, 0x00000003, 0x00000002); if (therm->fan->tach.func != DCB_GPIO_UNUSED) { - nv_mask(therm, 0x00d79c, 0x000000ff, therm->fan->tach.line); - nv_wr32(therm, 0x00e724, nv_device(therm)->crystal * 1000); - nv_mask(therm, 0x00e720, 0x00000001, 0x00000001); + nvkm_mask(device, 0x00d79c, 0x000000ff, therm->fan->tach.line); + nvkm_wr32(device, 0x00e724, nv_device(therm)->crystal * 1000); + nvkm_mask(device, 0x00e720, 0x00000001, 0x00000001); } - nv_mask(therm, 0x00e720, 0x00000002, 0x00000000); + nvkm_mask(device, 0x00e720, 0x00000002, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c index f2271f3e5990f..bd17e631e2db2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c @@ -33,23 +33,25 @@ gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) static int gm107_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { - *divs = nv_rd32(therm, 0x10eb20) & 0x1fff; - *duty = nv_rd32(therm, 0x10eb24) & 0x1fff; + struct nvkm_device *device = therm->subdev.device; + *divs = nvkm_rd32(device, 0x10eb20) & 0x1fff; + *duty = nvkm_rd32(device, 0x10eb24) & 0x1fff; return 0; } static int gm107_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { - nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */ - nv_wr32(therm, 0x10eb14, duty | 0x80000000); + struct nvkm_device *device = therm->subdev.device; + nvkm_mask(device, 0x10eb10, 0x1fff, divs); /* keep the high bits */ + nvkm_wr32(device, 0x10eb14, duty | 0x80000000); return 0; } static int gm107_fan_pwm_clock(struct nvkm_therm *therm, int line) { - return nv_device(therm)->crystal * 1000; + return therm->subdev.device->crystal * 1000; } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c index e6ba6e26da79a..8814d8511ea50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c @@ -28,8 +28,9 @@ int gt215_therm_fan_sense(struct nvkm_therm *therm) { - u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff; - u32 ctrl = nv_rd32(therm, 0x00e720); + struct nvkm_device *device = therm->subdev.device; + u32 tach = nvkm_rd32(device, 0x00e728) & 0x0000ffff; + u32 ctrl = nvkm_rd32(device, 0x00e720); if (ctrl & 0x00000001) return tach * 60 / 2; return -ENODEV; @@ -39,6 +40,7 @@ static int gt215_therm_init(struct nvkm_object *object) { struct nvkm_therm_priv *therm = (void *)object; + struct nvkm_device *device = therm->base.subdev.device; struct dcb_gpio_func *tach = &therm->fan->tach; int ret; @@ -49,13 +51,13 @@ gt215_therm_init(struct nvkm_object *object) g84_sensor_setup(&therm->base); /* enable fan tach, count revolutions per-second */ - nv_mask(therm, 0x00e720, 0x00000003, 0x00000002); + nvkm_mask(device, 0x00e720, 0x00000003, 0x00000002); if (tach->func != DCB_GPIO_UNUSED) { - nv_wr32(therm, 0x00e724, nv_device(therm)->crystal * 1000); - nv_mask(therm, 0x00e720, 0x001f0000, tach->line << 16); - nv_mask(therm, 0x00e720, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x00e724, nv_device(therm)->crystal * 1000); + nvkm_mask(device, 0x00e720, 0x001f0000, tach->line << 16); + nvkm_mask(device, 0x00e720, 0x00000001, 0x00000001); } - nv_mask(therm, 0x00e720, 0x00000002, 0x00000000); + nvkm_mask(device, 0x00e720, 0x00000002, 0x00000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c index e66672dce7ca4..da5e9591fe3b4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c @@ -55,18 +55,19 @@ nv40_sensor_style(struct nvkm_therm *therm) static int nv40_sensor_setup(struct nvkm_therm *therm) { + struct nvkm_device *device = therm->subdev.device; enum nv40_sensor_style style = nv40_sensor_style(therm); /* enable ADC readout and disable the ALARM threshold */ if (style == NEW_STYLE) { - nv_mask(therm, 0x15b8, 0x80000000, 0); - nv_wr32(therm, 0x15b0, 0x80003fff); + nvkm_mask(device, 0x15b8, 0x80000000, 0); + nvkm_wr32(device, 0x15b0, 0x80003fff); mdelay(20); /* wait for the temperature to stabilize */ - return nv_rd32(therm, 0x15b4) & 0x3fff; + return nvkm_rd32(device, 0x15b4) & 0x3fff; } else if (style == OLD_STYLE) { - nv_wr32(therm, 0x15b0, 0xff); + nvkm_wr32(device, 0x15b0, 0xff); mdelay(20); /* wait for the temperature to stabilize */ - return nv_rd32(therm, 0x15b4) & 0xff; + return nvkm_rd32(device, 0x15b4) & 0xff; } else return -ENODEV; } @@ -75,16 +76,17 @@ static int nv40_temp_get(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_device *device = therm->base.subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; enum nv40_sensor_style style = nv40_sensor_style(&therm->base); int core_temp; if (style == NEW_STYLE) { - nv_wr32(therm, 0x15b0, 0x80003fff); - core_temp = nv_rd32(therm, 0x15b4) & 0x3fff; + nvkm_wr32(device, 0x15b0, 0x80003fff); + core_temp = nvkm_rd32(device, 0x15b4) & 0x3fff; } else if (style == OLD_STYLE) { - nv_wr32(therm, 0x15b0, 0xff); - core_temp = nv_rd32(therm, 0x15b4) & 0xff; + nvkm_wr32(device, 0x15b0, 0xff); + core_temp = nvkm_rd32(device, 0x15b4) & 0xff; } else return -ENODEV; @@ -107,9 +109,10 @@ nv40_temp_get(struct nvkm_therm *obj) static int nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { + struct nvkm_device *device = therm->subdev.device; u32 mask = enable ? 0x80000000 : 0x0000000; - if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask); - else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask); + if (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask); + else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask); else { nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; @@ -120,8 +123,9 @@ nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) static int nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { + struct nvkm_device *device = therm->subdev.device; if (line == 2) { - u32 reg = nv_rd32(therm, 0x0010f0); + u32 reg = nvkm_rd32(device, 0x0010f0); if (reg & 0x80000000) { *duty = (reg & 0x7fff0000) >> 16; *divs = (reg & 0x00007fff); @@ -129,9 +133,9 @@ nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) } } else if (line == 9) { - u32 reg = nv_rd32(therm, 0x0015f4); + u32 reg = nvkm_rd32(device, 0x0015f4); if (reg & 0x80000000) { - *divs = nv_rd32(therm, 0x0015f8); + *divs = nvkm_rd32(device, 0x0015f8); *duty = (reg & 0x7fffffff); return 0; } @@ -146,12 +150,13 @@ nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) static int nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { + struct nvkm_device *device = therm->subdev.device; if (line == 2) { - nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); + nvkm_mask(device, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); } else if (line == 9) { - nv_wr32(therm, 0x0015f8, divs); - nv_mask(therm, 0x0015f4, 0x7fffffff, duty); + nvkm_wr32(device, 0x0015f8, divs); + nvkm_mask(device, 0x0015f4, 0x7fffffff, duty); } else { nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; @@ -164,12 +169,13 @@ void nv40_therm_intr(struct nvkm_subdev *subdev) { struct nvkm_therm *therm = nvkm_therm(subdev); - uint32_t stat = nv_rd32(therm, 0x1100); + struct nvkm_device *device = therm->subdev.device; + uint32_t stat = nvkm_rd32(device, 0x1100); /* traitement */ /* ack all IRQs */ - nv_wr32(therm, 0x1100, 0x70000); + nvkm_wr32(device, 0x1100, 0x70000); nv_error(therm, "THERM received an IRQ: stat = %x\n", stat); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c index f57bac1156285..d786ae7625040 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c @@ -52,23 +52,25 @@ pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) int nv50_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { + struct nvkm_device *device = therm->subdev.device; u32 data = enable ? 0x00000001 : 0x00000000; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret == 0) - nv_mask(therm, ctrl, 0x00010001 << line, data << line); + nvkm_mask(device, ctrl, 0x00010001 << line, data << line); return ret; } int nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { + struct nvkm_device *device = therm->subdev.device; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret) return ret; - if (nv_rd32(therm, ctrl) & (1 << line)) { - *divs = nv_rd32(therm, 0x00e114 + (id * 8)); - *duty = nv_rd32(therm, 0x00e118 + (id * 8)); + if (nvkm_rd32(device, ctrl) & (1 << line)) { + *divs = nvkm_rd32(device, 0x00e114 + (id * 8)); + *duty = nvkm_rd32(device, 0x00e118 + (id * 8)); return 0; } @@ -78,36 +80,36 @@ nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) int nv50_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { + struct nvkm_device *device = therm->subdev.device; int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id); if (ret) return ret; - nv_wr32(therm, 0x00e114 + (id * 8), divs); - nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000); + nvkm_wr32(device, 0x00e114 + (id * 8), divs); + nvkm_wr32(device, 0x00e118 + (id * 8), duty | 0x80000000); return 0; } int nv50_fan_pwm_clock(struct nvkm_therm *therm, int line) { - int chipset = nv_device(therm)->chipset; - int crystal = nv_device(therm)->crystal; + struct nvkm_device *device = therm->subdev.device; int pwm_clock; /* determine the PWM source clock */ - if (chipset > 0x50 && chipset < 0x94) { - u8 pwm_div = nv_rd32(therm, 0x410c); - if (nv_rd32(therm, 0xc040) & 0x800000) { + if (device->chipset > 0x50 && device->chipset < 0x94) { + u8 pwm_div = nvkm_rd32(device, 0x410c); + if (nvkm_rd32(device, 0xc040) & 0x800000) { /* Use the HOST clock (100 MHz) * Where does this constant(2.4) comes from? */ pwm_clock = (100000000 >> pwm_div) * 10 / 24; } else { /* Where does this constant(20) comes from? */ - pwm_clock = (crystal * 1000) >> pwm_div; + pwm_clock = (device->crystal * 1000) >> pwm_div; pwm_clock /= 20; } } else { - pwm_clock = (crystal * 1000) / 20; + pwm_clock = (device->crystal * 1000) / 20; } return pwm_clock; @@ -116,7 +118,8 @@ nv50_fan_pwm_clock(struct nvkm_therm *therm, int line) static void nv50_sensor_setup(struct nvkm_therm *therm) { - nv_mask(therm, 0x20010, 0x40000000, 0x0); + struct nvkm_device *device = therm->subdev.device; + nvkm_mask(device, 0x20010, 0x40000000, 0x0); mdelay(20); /* wait for the temperature to stabilize */ } @@ -124,10 +127,11 @@ static int nv50_temp_get(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_device *device = therm->base.subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; int core_temp; - core_temp = nv_rd32(therm, 0x20014) & 0x3fff; + core_temp = nvkm_rd32(device, 0x20014) & 0x3fff; /* if the slope or the offset is unset, do no use the sensor */ if (!sensor->slope_div || !sensor->slope_mult || -- GitLab From c44c049f28dbebfb95aca3847fd4996ca3503b0c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5376/7006] drm/nouveau/tmr: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/timer/base.c | 6 ++- .../gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 48 ++++++++++--------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index 216f44f9ca7a0..c59b2353683b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -27,12 +27,13 @@ bool nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) { struct nvkm_timer *ptimer = nvkm_timer(obj); + struct nvkm_device *device = ptimer->subdev.device; u64 time0; time0 = ptimer->read(ptimer); do { if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nv_rd32(obj, addr) & mask) == data) + if ((nvkm_rd32(device, addr) & mask) == data) return true; } else { if ((nv_ro32(obj, addr) & mask) == data) @@ -47,12 +48,13 @@ bool nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) { struct nvkm_timer *ptimer = nvkm_timer(obj); + struct nvkm_device *device = ptimer->subdev.device; u64 time0; time0 = ptimer->read(ptimer); do { if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nv_rd32(obj, addr) & mask) != data) + if ((nvkm_rd32(device, addr) & mask) != data) return true; } else { if ((nv_ro32(obj, addr) & mask) != data) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c index 16965325dbfdb..b7d6c26262a31 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c @@ -27,6 +27,7 @@ static int gk20a_timer_init(struct nvkm_object *object) { struct nv04_timer *tmr = (void *)object; + struct nvkm_device *device = tmr->base.subdev.device; u32 hi = upper_32_bits(tmr->suspend_time); u32 lo = lower_32_bits(tmr->suspend_time); int ret; @@ -39,8 +40,8 @@ gk20a_timer_init(struct nvkm_object *object) nv_debug(tmr, "time high : 0x%08x\n", hi); /* restore the time before suspend */ - nv_wr32(tmr, NV04_PTIMER_TIME_1, hi); - nv_wr32(tmr, NV04_PTIMER_TIME_0, lo); + nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); + nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index c9b3eb8c8e071..0ef69ddaf4ed5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -26,12 +26,13 @@ static u64 nv04_timer_read(struct nvkm_timer *tmr) { + struct nvkm_device *device = tmr->subdev.device; u32 hi, lo; do { - hi = nv_rd32(tmr, NV04_PTIMER_TIME_1); - lo = nv_rd32(tmr, NV04_PTIMER_TIME_0); - } while (hi != nv_rd32(tmr, NV04_PTIMER_TIME_1)); + hi = nvkm_rd32(device, NV04_PTIMER_TIME_1); + lo = nvkm_rd32(device, NV04_PTIMER_TIME_0); + } while (hi != nvkm_rd32(device, NV04_PTIMER_TIME_1)); return ((u64)hi << 32 | lo); } @@ -40,6 +41,7 @@ static void nv04_timer_alarm_trigger(struct nvkm_timer *obj) { struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); + struct nvkm_device *device = tmr->base.subdev.device; struct nvkm_alarm *alarm, *atemp; unsigned long flags; LIST_HEAD(exec); @@ -54,10 +56,10 @@ nv04_timer_alarm_trigger(struct nvkm_timer *obj) /* reschedule interrupt for next alarm time */ if (!list_empty(&tmr->alarms)) { alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); - nv_wr32(tmr, NV04_PTIMER_ALARM_0, alarm->timestamp); - nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000001); + nvkm_wr32(device, NV04_PTIMER_ALARM_0, alarm->timestamp); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); } else { - nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000000); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); } spin_unlock_irqrestore(&tmr->lock, flags); @@ -109,17 +111,18 @@ static void nv04_timer_intr(struct nvkm_subdev *subdev) { struct nv04_timer *tmr = (void *)subdev; - u32 stat = nv_rd32(tmr, NV04_PTIMER_INTR_0); + struct nvkm_device *device = tmr->base.subdev.device; + u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0); if (stat & 0x00000001) { nv04_timer_alarm_trigger(&tmr->base); - nv_wr32(tmr, NV04_PTIMER_INTR_0, 0x00000001); + nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001); stat &= ~0x00000001; } if (stat) { nv_error(tmr, "unknown stat 0x%08x\n", stat); - nv_wr32(tmr, NV04_PTIMER_INTR_0, stat); + nvkm_wr32(device, NV04_PTIMER_INTR_0, stat); } } @@ -127,17 +130,18 @@ int nv04_timer_fini(struct nvkm_object *object, bool suspend) { struct nv04_timer *tmr = (void *)object; + struct nvkm_device *device = tmr->base.subdev.device; if (suspend) tmr->suspend_time = nv04_timer_read(&tmr->base); - nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000000); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); return nvkm_timer_fini(&tmr->base, suspend); } static int nv04_timer_init(struct nvkm_object *object) { - struct nvkm_device *device = nv_device(object); struct nv04_timer *tmr = (void *)object; + struct nvkm_device *device = tmr->base.subdev.device; u32 m = 1, f, n, d, lo, hi; int ret; @@ -166,15 +170,15 @@ nv04_timer_init(struct nvkm_object *object) m++; } - nv_wr32(tmr, 0x009220, m - 1); + nvkm_wr32(device, 0x009220, m - 1); } if (!n) { nv_warn(tmr, "unknown input clock freq\n"); - if (!nv_rd32(tmr, NV04_PTIMER_NUMERATOR) || - !nv_rd32(tmr, NV04_PTIMER_DENOMINATOR)) { - nv_wr32(tmr, NV04_PTIMER_NUMERATOR, 1); - nv_wr32(tmr, NV04_PTIMER_DENOMINATOR, 1); + if (!nvkm_rd32(device, NV04_PTIMER_NUMERATOR) || + !nvkm_rd32(device, NV04_PTIMER_DENOMINATOR)) { + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, 1); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, 1); } return 0; } @@ -207,12 +211,12 @@ nv04_timer_init(struct nvkm_object *object) nv_debug(tmr, "time low : 0x%08x\n", lo); nv_debug(tmr, "time high : 0x%08x\n", hi); - nv_wr32(tmr, NV04_PTIMER_NUMERATOR, n); - nv_wr32(tmr, NV04_PTIMER_DENOMINATOR, d); - nv_wr32(tmr, NV04_PTIMER_INTR_0, 0xffffffff); - nv_wr32(tmr, NV04_PTIMER_INTR_EN_0, 0x00000000); - nv_wr32(tmr, NV04_PTIMER_TIME_1, hi); - nv_wr32(tmr, NV04_PTIMER_TIME_0, lo); + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); + nvkm_wr32(device, NV04_PTIMER_INTR_0, 0xffffffff); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); + nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); + nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); return 0; } -- GitLab From 96975248ee45cd50101b4bdf0eaf8c2d9e6cfa73 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5377/7006] drm/nouveau/falcon: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 90175ab62e542..03ff19a68985e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -46,14 +46,14 @@ u32 _nvkm_falcon_rd32(struct nvkm_object *object, u64 addr) { struct nvkm_falcon *falcon = (void *)object; - return nv_rd32(falcon, falcon->addr + addr); + return nvkm_rd32(falcon->engine.subdev.device, falcon->addr + addr); } void _nvkm_falcon_wr32(struct nvkm_object *object, u64 addr, u32 data) { struct nvkm_falcon *falcon = (void *)object; - nv_wr32(falcon, falcon->addr + addr, data); + nvkm_wr32(falcon->engine.subdev.device, falcon->addr + addr, data); } static void * -- GitLab From 2ef770f743c55ee2e7efb8e750c6e2d2eae9f74e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5378/7006] drm/nouveau/xtensa: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index 7cc33836aadde..f7ffe09816b5e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -27,14 +27,14 @@ u32 _nvkm_xtensa_rd32(struct nvkm_object *object, u64 addr) { struct nvkm_xtensa *xtensa = (void *)object; - return nv_rd32(xtensa, xtensa->addr + addr); + return nvkm_rd32(xtensa->engine.subdev.device, xtensa->addr + addr); } void _nvkm_xtensa_wr32(struct nvkm_object *object, u64 addr, u32 data) { struct nvkm_xtensa *xtensa = (void *)object; - nv_wr32(xtensa, xtensa->addr + addr, data); + nvkm_wr32(xtensa->engine.subdev.device, xtensa->addr + addr, data); } int @@ -55,6 +55,7 @@ void _nvkm_xtensa_intr(struct nvkm_subdev *subdev) { struct nvkm_xtensa *xtensa = (void *)subdev; + struct nvkm_device *device = xtensa->engine.subdev.device; u32 unk104 = nv_ro32(xtensa, 0xd04); u32 intr = nv_ro32(xtensa, 0xc20); u32 chan = nv_ro32(xtensa, 0xc28); @@ -66,7 +67,7 @@ _nvkm_xtensa_intr(struct nvkm_subdev *subdev) intr = nv_ro32(xtensa, 0xc20); if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) { nv_debug(xtensa, "Enabling FIFO_CTRL\n"); - nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val); + nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->fifo_val); } } @@ -146,7 +147,7 @@ _nvkm_xtensa_init(struct nvkm_object *object) nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */ nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */ - tmp = nv_rd32(xtensa, 0x0); + tmp = nvkm_rd32(device, 0x0); nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */ nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */ -- GitLab From 29e9f51094316879c4602795167e9635e18a3c8b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5379/7006] drm/nouveau/ce: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index 1abf22f87c710..2237a44a53706 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -62,13 +62,14 @@ gk104_ce_cclass = { static void gk104_ce_intr(struct nvkm_subdev *subdev) { + struct nvkm_device *device = subdev->device; const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; struct nvkm_engine *ce = (void *)subdev; - u32 stat = nv_rd32(ce, 0x104908 + (idx * 0x1000)); + u32 stat = nvkm_rd32(device, 0x104908 + (idx * 0x1000)); if (stat) { nv_warn(ce, "unhandled intr 0x%08x\n", stat); - nv_wr32(ce, 0x104908 + (idx * 0x1000), stat); + nvkm_wr32(device, 0x104908 + (idx * 0x1000), stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index 3fd896a92978d..698deddd51f5f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -62,13 +62,14 @@ gm204_ce_cclass = { static void gm204_ce_intr(struct nvkm_subdev *subdev) { + struct nvkm_device *device = subdev->device; const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; struct nvkm_engine *ce = (void *)subdev; - u32 stat = nv_rd32(ce, 0x104908 + (idx * 0x1000)); + u32 stat = nvkm_rd32(device, 0x104908 + (idx * 0x1000)); if (stat) { nv_warn(ce, "unhandled intr 0x%08x\n", stat); - nv_wr32(ce, 0x104908 + (idx * 0x1000), stat); + nvkm_wr32(device, 0x104908 + (idx * 0x1000), stat); } } -- GitLab From b958bf916d34f35639048361f7d87334770ebf4d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:09 +1000 Subject: [PATCH 5380/7006] drm/nouveau/cipher: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 442c2a002c634..b6b05a7dcae91 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -108,10 +108,11 @@ g84_cipher_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_engine *cipher = (void *)subdev; - u32 stat = nv_rd32(cipher, 0x102130); - u32 mthd = nv_rd32(cipher, 0x102190); - u32 data = nv_rd32(cipher, 0x102194); - u32 inst = nv_rd32(cipher, 0x102188) & 0x7fffffff; + struct nvkm_device *device = cipher->subdev.device; + u32 stat = nvkm_rd32(device, 0x102130); + u32 mthd = nvkm_rd32(device, 0x102190); + u32 data = nvkm_rd32(device, 0x102194); + u32 inst = nvkm_rd32(device, 0x102188) & 0x7fffffff; int chid; engctx = nvkm_engctx_get(engine, inst); @@ -125,8 +126,8 @@ g84_cipher_intr(struct nvkm_subdev *subdev) mthd, data); } - nv_wr32(cipher, 0x102130, stat); - nv_wr32(cipher, 0x10200c, 0x10); + nvkm_wr32(device, 0x102130, stat); + nvkm_wr32(device, 0x10200c, 0x10); nvkm_engctx_put(engctx); } @@ -156,15 +157,16 @@ static int g84_cipher_init(struct nvkm_object *object) { struct nvkm_engine *cipher = (void *)object; + struct nvkm_device *device = cipher->subdev.device; int ret; ret = nvkm_engine_init(cipher); if (ret) return ret; - nv_wr32(cipher, 0x102130, 0xffffffff); - nv_wr32(cipher, 0x102140, 0xffffffbf); - nv_wr32(cipher, 0x10200c, 0x00000010); + nvkm_wr32(device, 0x102130, 0xffffffff); + nvkm_wr32(device, 0x102140, 0xffffffbf); + nvkm_wr32(device, 0x10200c, 0x00000010); return 0; } -- GitLab From f9793bb7ed4d83c1b72661c1cca2949a343df231 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5381/7006] drm/nouveau/device: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 106ec87749a4f..35047437cf4c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -164,37 +164,37 @@ nvkm_devobj_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) static u8 nvkm_devobj_rd08(struct nvkm_object *object, u64 addr) { - return nv_rd08(object->engine, addr); + return nvkm_rd08(object->engine->subdev.device, addr); } static u16 nvkm_devobj_rd16(struct nvkm_object *object, u64 addr) { - return nv_rd16(object->engine, addr); + return nvkm_rd16(object->engine->subdev.device, addr); } static u32 nvkm_devobj_rd32(struct nvkm_object *object, u64 addr) { - return nv_rd32(object->engine, addr); + return nvkm_rd32(object->engine->subdev.device, addr); } static void nvkm_devobj_wr08(struct nvkm_object *object, u64 addr, u8 data) { - nv_wr08(object->engine, addr, data); + nvkm_wr08(object->engine->subdev.device, addr, data); } static void nvkm_devobj_wr16(struct nvkm_object *object, u64 addr, u16 data) { - nv_wr16(object->engine, addr, data); + nvkm_wr16(object->engine->subdev.device, addr, data); } static void nvkm_devobj_wr32(struct nvkm_object *object, u64 addr, u32 data) { - nv_wr32(object->engine, addr, data); + nvkm_wr32(object->engine->subdev.device, addr, data); } static int -- GitLab From 2fde1f1c343030d169945aa67a0e485b568f1393 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5382/7006] drm/nouveau/disp: switch to device pri macros Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 12 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 233 ++++++++-------- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm204.c | 3 +- .../drm/nouveau/nvkm/engine/disp/hdagf110.c | 15 +- .../drm/nouveau/nvkm/engine/disp/hdagt215.c | 13 +- .../drm/nouveau/nvkm/engine/disp/hdmig84.c | 45 ++-- .../drm/nouveau/nvkm/engine/disp/hdmigf110.c | 29 +- .../drm/nouveau/nvkm/engine/disp/hdmigk104.c | 31 +-- .../drm/nouveau/nvkm/engine/disp/hdmigt215.c | 45 ++-- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 30 ++- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 252 ++++++++++-------- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 28 +- .../drm/nouveau/nvkm/engine/disp/sorgf110.c | 27 +- .../drm/nouveau/nvkm/engine/disp/sorgm204.c | 34 +-- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/disp/vga.c | 25 +- 20 files changed, 457 insertions(+), 380 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index f64dec917f85e..acc9fbb4ae045 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -33,6 +33,7 @@ int nv50_dac_power(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 doff = outp->or * 0x800; union { struct nv50_disp_dac_pwr_v0 v0; @@ -54,7 +55,7 @@ nv50_dac_power(NV50_DISP_MTHD_V1) return ret; nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_mask(disp, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); + nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); return 0; } @@ -62,6 +63,7 @@ nv50_dac_power(NV50_DISP_MTHD_V1) int nv50_dac_sense(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_dac_load_v0 v0; } *args = data; @@ -79,15 +81,15 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) } else return ret; - nv_mask(disp, 0x61a004 + doff, 0x807f0000, 0x80150000); + nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80150000); nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); - nv_wr32(disp, 0x61a00c + doff, 0x00100000 | loadval); + nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval); mdelay(9); udelay(500); - loadval = nv_mask(disp, 0x61a00c + doff, 0xffffffff, 0x00000000); + loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000); - nv_mask(disp, 0x61a004 + doff, 0x807f0000, 0x80550000); + nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80550000); nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); nv_debug(disp, "DAC%d sense: 0x%08x\n", outp->or, loadval); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index 3301fedfe768c..293b41bd24682 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -47,16 +47,18 @@ static void gf110_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) { struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - nv_mask(disp, 0x610090, 0x00000001 << index, 0x00000000 << index); - nv_wr32(disp, 0x61008c, 0x00000001 << index); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000000 << index); + nvkm_wr32(device, 0x61008c, 0x00000001 << index); } static void gf110_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) { struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - nv_wr32(disp, 0x61008c, 0x00000001 << index); - nv_mask(disp, 0x610090, 0x00000001 << index, 0x00000001 << index); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x61008c, 0x00000001 << index); + nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000001 << index); } const struct nvkm_event_func @@ -93,6 +95,7 @@ gf110_disp_dmac_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = dmac->base.chid; int ret; @@ -101,20 +104,20 @@ gf110_disp_dmac_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* initialise channel for dma command submission */ - nv_wr32(disp, 0x610494 + (chid * 0x0010), dmac->push); - nv_wr32(disp, 0x610498 + (chid * 0x0010), 0x00010000); - nv_wr32(disp, 0x61049c + (chid * 0x0010), 0x00000001); - nv_mask(disp, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); - nv_wr32(disp, 0x640000 + (chid * 0x1000), 0x00000000); - nv_wr32(disp, 0x610490 + (chid * 0x0010), 0x00000013); + nvkm_wr32(device, 0x610494 + (chid * 0x0010), dmac->push); + nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); /* wait for it to go inactive */ if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) { nv_error(dmac, "init: 0x%08x\n", - nv_rd32(disp, 0x610490 + (chid * 0x10))); + nvkm_rd32(device, 0x610490 + (chid * 0x10))); return -EBUSY; } @@ -126,21 +129,22 @@ gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = dmac->base.chid; /* deactivate channel */ - nv_mask(disp, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); - nv_mask(disp, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) { nv_error(dmac, "fini: 0x%08x\n", - nv_rd32(disp, 0x610490 + (chid * 0x10))); + nvkm_rd32(device, 0x610490 + (chid * 0x10))); if (suspend) return -EBUSY; } /* disable error reporting and completion notification */ - nv_mask(disp, 0x610090, 0x00000001 << chid, 0x00000000); - nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); return nv50_disp_chan_fini(&dmac->base, suspend); } @@ -294,6 +298,7 @@ gf110_disp_core_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int ret; ret = nv50_disp_chan_init(&mast->base); @@ -301,19 +306,19 @@ gf110_disp_core_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(disp, 0x6100a0, 0x00000001, 0x00000001); + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000001); /* initialise channel for dma command submission */ - nv_wr32(disp, 0x610494, mast->push); - nv_wr32(disp, 0x610498, 0x00010000); - nv_wr32(disp, 0x61049c, 0x00000001); - nv_mask(disp, 0x610490, 0x00000010, 0x00000010); - nv_wr32(disp, 0x640000, 0x00000000); - nv_wr32(disp, 0x610490, 0x01000013); + nvkm_wr32(device, 0x610494, mast->push); + nvkm_wr32(device, 0x610498, 0x00010000); + nvkm_wr32(device, 0x61049c, 0x00000001); + nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610490, 0x01000013); /* wait for it to go inactive */ if (!nv_wait(disp, 0x610490, 0x80000000, 0x00000000)) { - nv_error(mast, "init: 0x%08x\n", nv_rd32(disp, 0x610490)); + nv_error(mast, "init: 0x%08x\n", nvkm_rd32(device, 0x610490)); return -EBUSY; } @@ -325,19 +330,20 @@ gf110_disp_core_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; /* deactivate channel */ - nv_mask(disp, 0x610490, 0x00000010, 0x00000000); - nv_mask(disp, 0x610490, 0x00000003, 0x00000000); + nvkm_mask(device, 0x610490, 0x00000010, 0x00000000); + nvkm_mask(device, 0x610490, 0x00000003, 0x00000000); if (!nv_wait(disp, 0x610490, 0x001e0000, 0x00000000)) { - nv_error(mast, "fini: 0x%08x\n", nv_rd32(disp, 0x610490)); + nv_error(mast, "fini: 0x%08x\n", nvkm_rd32(device, 0x610490)); if (suspend) return -EBUSY; } /* disable error reporting and completion notification */ - nv_mask(disp, 0x610090, 0x00000001, 0x00000000); - nv_mask(disp, 0x6100a0, 0x00000001, 0x00000000); + nvkm_mask(device, 0x610090, 0x00000001, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); } @@ -541,6 +547,7 @@ gf110_disp_pioc_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = pioc->base.chid; int ret; @@ -549,13 +556,13 @@ gf110_disp_pioc_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* activate channel */ - nv_wr32(disp, 0x610490 + (chid * 0x10), 0x00000001); + nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001); if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) { nv_error(pioc, "init: 0x%08x\n", - nv_rd32(disp, 0x610490 + (chid * 0x10))); + nvkm_rd32(device, 0x610490 + (chid * 0x10))); return -EBUSY; } @@ -567,19 +574,20 @@ gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = pioc->base.chid; - nv_mask(disp, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); + nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) { nv_error(pioc, "timeout: 0x%08x\n", - nv_rd32(disp, 0x610490 + (chid * 0x10))); + nvkm_rd32(device, 0x610490 + (chid * 0x10))); if (suspend) return -EBUSY; } /* disable error reporting and completion notification */ - nv_mask(disp, 0x610090, 0x00000001 << chid, 0x00000000); - nv_mask(disp, 0x6100a0, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); return nv50_disp_chan_fini(&pioc->base, suspend); } @@ -625,9 +633,10 @@ gf110_disp_curs_ofuncs = { int gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) { - const u32 total = nv_rd32(disp, 0x640414 + (head * 0x300)); - const u32 blanke = nv_rd32(disp, 0x64041c + (head * 0x300)); - const u32 blanks = nv_rd32(disp, 0x640420 + (head * 0x300)); + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300)); + const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300)); + const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300)); union { struct nv04_disp_scanoutpos_v0 v0; } *args = data; @@ -644,10 +653,10 @@ gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) args->v0.htotal = ( total & 0x0000ffff); args->v0.time[0] = ktime_to_ns(ktime_get()); args->v0.vline = /* vline read locks hline */ - nv_rd32(disp, 0x616340 + (head * 0x800)) & 0xffff; + nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = - nv_rd32(disp, 0x616344 + (head * 0x800)) & 0xffff; + nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; } else return ret; @@ -659,6 +668,7 @@ gf110_disp_main_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int ret, i; u32 tmp; @@ -673,30 +683,30 @@ gf110_disp_main_init(struct nvkm_object *object) /* ... CRTC caps */ for (i = 0; i < disp->head.nr; i++) { - tmp = nv_rd32(disp, 0x616104 + (i * 0x800)); - nv_wr32(disp, 0x6101b4 + (i * 0x800), tmp); - tmp = nv_rd32(disp, 0x616108 + (i * 0x800)); - nv_wr32(disp, 0x6101b8 + (i * 0x800), tmp); - tmp = nv_rd32(disp, 0x61610c + (i * 0x800)); - nv_wr32(disp, 0x6101bc + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); + nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); + nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); + nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); } /* ... DAC caps */ for (i = 0; i < disp->dac.nr; i++) { - tmp = nv_rd32(disp, 0x61a000 + (i * 0x800)); - nv_wr32(disp, 0x6101c0 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); + nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp); } /* ... SOR caps */ for (i = 0; i < disp->sor.nr; i++) { - tmp = nv_rd32(disp, 0x61c000 + (i * 0x800)); - nv_wr32(disp, 0x6301c4 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); + nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp); } /* steal display away from vbios, or something like that */ - if (nv_rd32(disp, 0x6100ac) & 0x00000100) { - nv_wr32(disp, 0x6100ac, 0x00000100); - nv_mask(disp, 0x6194e8, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x6100ac) & 0x00000100) { + nvkm_wr32(device, 0x6100ac, 0x00000100); + nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); if (!nv_wait(disp, 0x6194e8, 0x00000002, 0x00000000)) { nv_error(disp, "timeout acquiring display\n"); return -EBUSY; @@ -704,12 +714,12 @@ gf110_disp_main_init(struct nvkm_object *object) } /* point at display engine memory area (hash table, objects) */ - nv_wr32(disp, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); + nvkm_wr32(device, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ - nv_wr32(disp, 0x610090, 0x00000000); - nv_wr32(disp, 0x6100a0, 0x00000000); - nv_wr32(disp, 0x6100b0, 0x00000307); + nvkm_wr32(device, 0x610090, 0x00000000); + nvkm_wr32(device, 0x6100a0, 0x00000000); + nvkm_wr32(device, 0x6100b0, 0x00000307); /* disable underflow reporting, preventing an intermittent issue * on some gk104 boards where the production vbios left this @@ -718,7 +728,7 @@ gf110_disp_main_init(struct nvkm_object *object) * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt */ for (i = 0; i < disp->head.nr; i++) - nv_mask(disp, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); return 0; } @@ -728,9 +738,10 @@ gf110_disp_main_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; /* disable all interrupts */ - nv_wr32(disp, 0x6100b0, 0x00000000); + nvkm_wr32(device, 0x6100b0, 0x00000000); return nvkm_parent_fini(&base->base, suspend); } @@ -769,14 +780,16 @@ static void gf110_disp_vblank_init(struct nvkm_event *event, int type, int head) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); } static void gf110_disp_vblank_fini(struct nvkm_event *event, int type, int head) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); } const struct nvkm_event_func @@ -835,7 +848,8 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, static struct nvkm_output * exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info; u8 ver, hdr, cnt, len; @@ -843,7 +857,7 @@ exec_script(struct nv50_disp *disp, int head, int id) int or; for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nv_rd32(disp, 0x640180 + (or * 0x20)); + ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20)); if (ctrl & (1 << head)) break; } @@ -871,7 +885,8 @@ exec_script(struct nv50_disp *disp, int head, int id) static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; @@ -880,7 +895,7 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) int or; for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nv_rd32(disp, 0x660180 + (or * 0x20)); + ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20)); if (ctrl & (1 << head)) break; } @@ -961,32 +976,34 @@ gf110_disp_intr_unk2_0(struct nv50_disp *disp, int head) static void gf110_disp_intr_unk2_1(struct nv50_disp *disp, int head) { - struct nvkm_devinit *devinit = nvkm_devinit(disp); - u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_devinit *devinit = device->devinit; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; if (pclk) devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); - nv_wr32(disp, 0x612200 + (head * 0x800), 0x00000000); + nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); } static void gf110_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, struct dcb_output *outp) { + struct nvkm_device *device = disp->base.engine.subdev.device; const int or = ffs(outp->or) - 1; - const u32 ctrl = nv_rd32(disp, 0x660200 + (or * 0x020)); - const u32 conf = nv_rd32(disp, 0x660404 + (head * 0x300)); - const s32 vactive = nv_rd32(disp, 0x660414 + (head * 0x300)) & 0xffff; - const s32 vblanke = nv_rd32(disp, 0x66041c + (head * 0x300)) & 0xffff; - const s32 vblanks = nv_rd32(disp, 0x660420 + (head * 0x300)) & 0xffff; - const u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; + const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020)); + const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300)); + const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff; + const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff; + const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff; + const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; const u32 hoff = (head * 0x800); const u32 soff = ( or * 0x800); const u32 loff = (link * 0x080) + soff; const u32 symbol = 100000; const u32 TU = 64; - u32 dpctrl = nv_rd32(disp, 0x61c10c + loff); - u32 clksor = nv_rd32(disp, 0x612300 + soff); + u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); + u32 clksor = nvkm_rd32(device, 0x612300 + soff); u32 datarate, link_nr, link_bw, bits; u64 ratio, value; @@ -999,14 +1016,14 @@ gf110_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, value = value * link_bw; do_div(value, pclk); value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nv_mask(disp, 0x616620 + hoff, 0x0000ffff, value); + nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value); /* symbols/vblank - algorithm taken from comments in tegra driver */ value = vblanks - vblanke - 25; value = value * link_bw; do_div(value, pclk); value = value - ((36 / link_nr) + 3) - 1; - nv_mask(disp, 0x616624 + hoff, 0x00ffffff, value); + nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value); /* watermark */ if ((conf & 0x3c0) == 0x180) bits = 30; @@ -1026,14 +1043,15 @@ gf110_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, value += 5; value |= 0x08000000; - nv_wr32(disp, 0x616610 + hoff, value); + nvkm_wr32(device, 0x616610 + hoff, value); } static void gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) { + struct nvkm_device *device = disp->base.engine.subdev.device; struct nvkm_output *outp; - u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; u32 conf, addr, data; outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); @@ -1042,7 +1060,7 @@ gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) /* see note in nv50_disp_intr_unk20_2() */ if (outp->info.type == DCB_OUTPUT_DP) { - u32 sync = nv_rd32(disp, 0x660404 + (head * 0x300)); + u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300)); switch ((sync & 0x000003c0) >> 6) { case 6: pclk = pclk * 30; break; case 5: pclk = pclk * 24; break; @@ -1069,7 +1087,7 @@ gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) data = (conf & 0x0100) ? 0x00000101 : 0x00000000; switch (outp->info.type) { case DCB_OUTPUT_TMDS: - nv_mask(disp, addr, 0x007c0000, 0x00280000); + nvkm_mask(device, addr, 0x007c0000, 0x00280000); break; case DCB_OUTPUT_DP: gf110_disp_intr_unk2_2_tu(disp, head, &outp->info); @@ -1079,13 +1097,14 @@ gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) } } - nv_mask(disp, addr, 0x00000707, data); + nvkm_mask(device, addr, 0x00000707, data); } static void gf110_disp_intr_unk4_0(struct nv50_disp *disp, int head) { - u32 pclk = nv_rd32(disp, 0x660450 + (head * 0x300)) / 1000; + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; u32 conf; exec_clkcmp(disp, head, 1, pclk, &conf); @@ -1097,12 +1116,13 @@ gf110_disp_intr_supervisor(struct work_struct *work) struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; + struct nvkm_device *device = disp->base.engine.subdev.device; u32 mask[4]; int head; nv_debug(disp, "supervisor %d\n", ffs(disp->super)); for (head = 0; head < disp->head.nr; head++) { - mask[head] = nv_rd32(disp, 0x6101d4 + (head * 0x800)); + mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); nv_debug(disp, "head %d: 0x%08x\n", head, mask[head]); } @@ -1145,17 +1165,18 @@ gf110_disp_intr_supervisor(struct work_struct *work) } for (head = 0; head < disp->head.nr; head++) - nv_wr32(disp, 0x6101d4 + (head * 0x800), 0x00000000); - nv_wr32(disp, 0x6101d0, 0x80000000); + nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); + nvkm_wr32(device, 0x6101d0, 0x80000000); } static void gf110_disp_intr_error(struct nv50_disp *disp, int chid) { const struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - u32 mthd = nv_rd32(disp, 0x6101f0 + (chid * 12)); - u32 data = nv_rd32(disp, 0x6101f4 + (chid * 12)); - u32 unkn = nv_rd32(disp, 0x6101f8 + (chid * 12)); + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12)); + u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12)); + u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12)); nv_error(disp, "chid %d mthd 0x%04x data 0x%08x " "0x%08x 0x%08x\n", @@ -1192,29 +1213,30 @@ gf110_disp_intr_error(struct nv50_disp *disp, int chid) } } - nv_wr32(disp, 0x61009c, (1 << chid)); - nv_wr32(disp, 0x6101f0 + (chid * 12), 0x90000000); + nvkm_wr32(device, 0x61009c, (1 << chid)); + nvkm_wr32(device, 0x6101f0 + (chid * 12), 0x90000000); } void gf110_disp_intr(struct nvkm_subdev *subdev) { struct nv50_disp *disp = (void *)subdev; - u32 intr = nv_rd32(disp, 0x610088); + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 intr = nvkm_rd32(device, 0x610088); int i; if (intr & 0x00000001) { - u32 stat = nv_rd32(disp, 0x61008c); + u32 stat = nvkm_rd32(device, 0x61008c); while (stat) { int chid = __ffs(stat); stat &= ~(1 << chid); nv50_disp_chan_uevent_send(disp, chid); - nv_wr32(disp, 0x61008c, 1 << chid); + nvkm_wr32(device, 0x61008c, 1 << chid); } intr &= ~0x00000001; } if (intr & 0x00000002) { - u32 stat = nv_rd32(disp, 0x61009c); + u32 stat = nvkm_rd32(device, 0x61009c); int chid = ffs(stat) - 1; if (chid >= 0) gf110_disp_intr_error(disp, chid); @@ -1222,17 +1244,17 @@ gf110_disp_intr(struct nvkm_subdev *subdev) } if (intr & 0x00100000) { - u32 stat = nv_rd32(disp, 0x6100ac); + u32 stat = nvkm_rd32(device, 0x6100ac); if (stat & 0x00000007) { disp->super = (stat & 0x00000007); schedule_work(&disp->supervisor); - nv_wr32(disp, 0x6100ac, disp->super); + nvkm_wr32(device, 0x6100ac, disp->super); stat &= ~0x00000007; } if (stat) { nv_info(disp, "unknown intr24 0x%08x\n", stat); - nv_wr32(disp, 0x6100ac, stat); + nvkm_wr32(device, 0x6100ac, stat); } intr &= ~0x00100000; @@ -1241,11 +1263,11 @@ gf110_disp_intr(struct nvkm_subdev *subdev) for (i = 0; i < disp->head.nr; i++) { u32 mask = 0x01000000 << i; if (mask & intr) { - u32 stat = nv_rd32(disp, 0x6100bc + (i * 0x800)); + u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); if (stat & 0x00000001) nvkm_disp_vblank(&disp->base, i); - nv_mask(disp, 0x6100bc + (i * 0x800), 0, 0); - nv_rd32(disp, 0x6100c0 + (i * 0x800)); + nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); + nvkm_rd32(device, 0x6100c0 + (i * 0x800)); } } } @@ -1255,8 +1277,9 @@ gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_disp *disp; - int heads = nv_rd32(parent, 0x022448); + int heads = nvkm_rd32(device, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index ccb5bfad9ec8a..baf2c2832c409 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -219,8 +219,9 @@ gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_disp *disp; - int heads = nv_rd32(parent, 0x022448); + int heads = nvkm_rd32(device, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index f4372fb382463..ee51b4f22aaa0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -54,8 +54,9 @@ gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_disp *disp; - int heads = nv_rd32(parent, 0x022448); + int heads = nvkm_rd32(device, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 558c38736f55a..13a02ac2ffa76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -54,8 +54,9 @@ gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_disp *disp; - int heads = nv_rd32(parent, 0x022448); + int heads = nvkm_rd32(device, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index a56ef7bd6623f..89d9839ecf656 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -55,8 +55,9 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_disp *disp; - int heads = nv_rd32(parent, 0x022448); + int heads = nvkm_rd32(device, 0x022448); int ret; ret = nvkm_disp_create(parent, engine, oclass, heads, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c index fe07d7cb4dd7a..a04ef426840de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c @@ -35,6 +35,7 @@ int gf110_hda_eld(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_sor_hda_eld_v0 v0; } *args = data; @@ -52,21 +53,21 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(disp, 0x616618 + hoff, 0x8000000c, 0x80000001); + nvkm_mask(device, 0x616618 + hoff, 0x8000000c, 0x80000001); nv_wait(disp, 0x616618 + hoff, 0x80000000, 0x00000000); } - nv_mask(disp, 0x616548 + hoff, 0x00000070, 0x00000000); + nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000); for (i = 0; i < size; i++) - nv_wr32(disp, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); + nvkm_wr32(device, 0x10ec00 + soff, (i << 8) | args->v0.data[i]); for (; i < 0x60; i++) - nv_wr32(disp, 0x10ec00 + soff, (i << 8)); - nv_mask(disp, 0x10ec10 + soff, 0x80000003, 0x80000003); + nvkm_wr32(device, 0x10ec00 + soff, (i << 8)); + nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000003); } else { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(disp, 0x616618 + hoff, 0x80000001, 0x80000000); + nvkm_mask(device, 0x616618 + hoff, 0x80000001, 0x80000000); nv_wait(disp, 0x616618 + hoff, 0x80000000, 0x00000000); } - nv_mask(disp, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); + nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index 67d3cf99e0b54..c2ae112225fcc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -33,6 +33,7 @@ int gt215_hda_eld(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_sor_hda_eld_v0 v0; } *args = data; @@ -49,20 +50,20 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(disp, 0x61c1e0 + soff, 0x8000000d, 0x80000001); + nvkm_mask(device, 0x61c1e0 + soff, 0x8000000d, 0x80000001); nv_wait(disp, 0x61c1e0 + soff, 0x80000000, 0x00000000); } for (i = 0; i < size; i++) - nv_wr32(disp, 0x61c440 + soff, (i << 8) | args->v0.data[0]); + nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]); for (; i < 0x60; i++) - nv_wr32(disp, 0x61c440 + soff, (i << 8)); - nv_mask(disp, 0x61c448 + soff, 0x80000003, 0x80000003); + nvkm_wr32(device, 0x61c440 + soff, (i << 8)); + nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000003); } else { if (outp->info.type == DCB_OUTPUT_DP) { - nv_mask(disp, 0x61c1e0 + soff, 0x80000001, 0x80000000); + nvkm_mask(device, 0x61c1e0 + soff, 0x80000001, 0x80000000); nv_wait(disp, 0x61c1e0 + soff, 0x80000000, 0x00000000); } - nv_mask(disp, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); + nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index 0c282a4d31a88..da7f001f918c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -31,6 +31,7 @@ int g84_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); union { struct nv50_disp_sor_hdmi_pwr_v0 v0; @@ -54,38 +55,38 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(disp, 0x6165a4 + hoff, 0x40000000, 0x00000000); - nv_mask(disp, 0x616520 + hoff, 0x00000001, 0x00000000); - nv_mask(disp, 0x616500 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x6165a4 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(disp, 0x616520 + hoff, 0x00000001, 0x00000000); - nv_wr32(disp, 0x616528 + hoff, 0x000d0282); - nv_wr32(disp, 0x61652c + hoff, 0x0000006f); - nv_wr32(disp, 0x616530 + hoff, 0x00000000); - nv_wr32(disp, 0x616534 + hoff, 0x00000000); - nv_wr32(disp, 0x616538 + hoff, 0x00000000); - nv_mask(disp, 0x616520 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x616528 + hoff, 0x000d0282); + nvkm_wr32(device, 0x61652c + hoff, 0x0000006f); + nvkm_wr32(device, 0x616530 + hoff, 0x00000000); + nvkm_wr32(device, 0x616534 + hoff, 0x00000000); + nvkm_wr32(device, 0x616538 + hoff, 0x00000000); + nvkm_mask(device, 0x616520 + hoff, 0x00000001, 0x00000001); /* Audio InfoFrame */ - nv_mask(disp, 0x616500 + hoff, 0x00000001, 0x00000000); - nv_wr32(disp, 0x616508 + hoff, 0x000a0184); - nv_wr32(disp, 0x61650c + hoff, 0x00000071); - nv_wr32(disp, 0x616510 + hoff, 0x00000000); - nv_mask(disp, 0x616500 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x616508 + hoff, 0x000a0184); + nvkm_wr32(device, 0x61650c + hoff, 0x00000071); + nvkm_wr32(device, 0x616510 + hoff, 0x00000000); + nvkm_mask(device, 0x616500 + hoff, 0x00000001, 0x00000001); - nv_mask(disp, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ - nv_mask(disp, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ - nv_mask(disp, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + nvkm_mask(device, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nvkm_mask(device, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nvkm_mask(device, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ /* ??? */ - nv_mask(disp, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ - nv_mask(disp, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ - nv_mask(disp, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ + nvkm_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(disp, 0x6165a4 + hoff, 0x5f1f007f, ctrl); + nvkm_mask(device, 0x6165a4 + hoff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c index 5dcbc8e50d815..1a474be0504b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c @@ -31,6 +31,7 @@ int gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); union { struct nv50_disp_sor_hdmi_pwr_v0 v0; @@ -53,27 +54,27 @@ gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(disp, 0x616798 + hoff, 0x40000000, 0x00000000); - nv_mask(disp, 0x6167a4 + hoff, 0x00000001, 0x00000000); - nv_mask(disp, 0x616714 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(disp, 0x616714 + hoff, 0x00000001, 0x00000000); - nv_wr32(disp, 0x61671c + hoff, 0x000d0282); - nv_wr32(disp, 0x616720 + hoff, 0x0000006f); - nv_wr32(disp, 0x616724 + hoff, 0x00000000); - nv_wr32(disp, 0x616728 + hoff, 0x00000000); - nv_wr32(disp, 0x61672c + hoff, 0x00000000); - nv_mask(disp, 0x616714 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x61671c + hoff, 0x000d0282); + nvkm_wr32(device, 0x616720 + hoff, 0x0000006f); + nvkm_wr32(device, 0x616724 + hoff, 0x00000000); + nvkm_wr32(device, 0x616728 + hoff, 0x00000000); + nvkm_wr32(device, 0x61672c + hoff, 0x00000000); + nvkm_mask(device, 0x616714 + hoff, 0x00000001, 0x00000001); /* ??? InfoFrame? */ - nv_mask(disp, 0x6167a4 + hoff, 0x00000001, 0x00000000); - nv_wr32(disp, 0x6167ac + hoff, 0x00000010); - nv_mask(disp, 0x6167a4 + hoff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x6167ac + hoff, 0x00000010); + nvkm_mask(device, 0x6167a4 + hoff, 0x00000001, 0x00000001); /* HDMI_CTRL */ - nv_mask(disp, 0x616798 + hoff, 0x401f007f, ctrl); + nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index 719d21e85301b..b1a69bd93d964 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -31,6 +31,7 @@ int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); const u32 hdmi = (head * 0x400); union { @@ -54,30 +55,30 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(disp, 0x616798 + hoff, 0x40000000, 0x00000000); - nv_mask(disp, 0x6900c0 + hdmi, 0x00000001, 0x00000000); - nv_mask(disp, 0x690000 + hdmi, 0x00000001, 0x00000000); + nvkm_mask(device, 0x616798 + hoff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(disp, 0x690000 + hdmi, 0x00000001, 0x00000000); - nv_wr32(disp, 0x690008 + hdmi, 0x000d0282); - nv_wr32(disp, 0x69000c + hdmi, 0x0000006f); - nv_wr32(disp, 0x690010 + hdmi, 0x00000000); - nv_wr32(disp, 0x690014 + hdmi, 0x00000000); - nv_wr32(disp, 0x690018 + hdmi, 0x00000000); - nv_mask(disp, 0x690000 + hdmi, 0x00000001, 0x00000001); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x690008 + hdmi, 0x000d0282); + nvkm_wr32(device, 0x69000c + hdmi, 0x0000006f); + nvkm_wr32(device, 0x690010 + hdmi, 0x00000000); + nvkm_wr32(device, 0x690014 + hdmi, 0x00000000); + nvkm_wr32(device, 0x690018 + hdmi, 0x00000000); + nvkm_mask(device, 0x690000 + hdmi, 0x00000001, 0x00000001); /* ??? InfoFrame? */ - nv_mask(disp, 0x6900c0 + hdmi, 0x00000001, 0x00000000); - nv_wr32(disp, 0x6900cc + hdmi, 0x00000010); - nv_mask(disp, 0x6900c0 + hdmi, 0x00000001, 0x00000001); + nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x6900cc + hdmi, 0x00000010); + nvkm_mask(device, 0x6900c0 + hdmi, 0x00000001, 0x00000001); /* ??? */ - nv_wr32(disp, 0x690080 + hdmi, 0x82000000); + nvkm_wr32(device, 0x690080 + hdmi, 0x82000000); /* HDMI_CTRL */ - nv_mask(disp, 0x616798 + hoff, 0x401f007f, ctrl); + nvkm_mask(device, 0x616798 + hoff, 0x401f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index dde989158153f..353dde956fd15 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -32,6 +32,7 @@ int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = outp->or * 0x800; union { struct nv50_disp_sor_hdmi_pwr_v0 v0; @@ -55,38 +56,38 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) return ret; if (!(ctrl & 0x40000000)) { - nv_mask(disp, 0x61c5a4 + soff, 0x40000000, 0x00000000); - nv_mask(disp, 0x61c520 + soff, 0x00000001, 0x00000000); - nv_mask(disp, 0x61c500 + soff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x61c5a4 + soff, 0x40000000, 0x00000000); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); return 0; } /* AVI InfoFrame */ - nv_mask(disp, 0x61c520 + soff, 0x00000001, 0x00000000); - nv_wr32(disp, 0x61c528 + soff, 0x000d0282); - nv_wr32(disp, 0x61c52c + soff, 0x0000006f); - nv_wr32(disp, 0x61c530 + soff, 0x00000000); - nv_wr32(disp, 0x61c534 + soff, 0x00000000); - nv_wr32(disp, 0x61c538 + soff, 0x00000000); - nv_mask(disp, 0x61c520 + soff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x61c528 + soff, 0x000d0282); + nvkm_wr32(device, 0x61c52c + soff, 0x0000006f); + nvkm_wr32(device, 0x61c530 + soff, 0x00000000); + nvkm_wr32(device, 0x61c534 + soff, 0x00000000); + nvkm_wr32(device, 0x61c538 + soff, 0x00000000); + nvkm_mask(device, 0x61c520 + soff, 0x00000001, 0x00000001); /* Audio InfoFrame */ - nv_mask(disp, 0x61c500 + soff, 0x00000001, 0x00000000); - nv_wr32(disp, 0x61c508 + soff, 0x000a0184); - nv_wr32(disp, 0x61c50c + soff, 0x00000071); - nv_wr32(disp, 0x61c510 + soff, 0x00000000); - nv_mask(disp, 0x61c500 + soff, 0x00000001, 0x00000001); + nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000000); + nvkm_wr32(device, 0x61c508 + soff, 0x000a0184); + nvkm_wr32(device, 0x61c50c + soff, 0x00000071); + nvkm_wr32(device, 0x61c510 + soff, 0x00000000); + nvkm_mask(device, 0x61c500 + soff, 0x00000001, 0x00000001); - nv_mask(disp, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ - nv_mask(disp, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ - nv_mask(disp, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ + nvkm_mask(device, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */ + nvkm_mask(device, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */ + nvkm_mask(device, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */ /* ??? */ - nv_mask(disp, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ - nv_mask(disp, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ - nv_mask(disp, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00100000); /* RESETF */ + nvkm_mask(device, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */ + nvkm_mask(device, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */ /* HDMI_CTRL */ - nv_mask(disp, 0x61c5a4 + soff, 0x5f1f007f, ctrl); + nvkm_mask(device, 0x61c5a4 + soff, 0x5f1f007f, ctrl); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 81359d25afce8..859c06ee6fc21 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -32,6 +32,7 @@ static int nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, void *data, u32 size, int head) { + struct nvkm_device *device = disp->engine.subdev.device; const u32 hoff = head * 0x2000; union { struct nv04_disp_scanoutpos_v0 v0; @@ -42,12 +43,12 @@ nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, nv_ioctl(object, "disp scanoutpos size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); - args->v0.vblanks = nv_rd32(disp, 0x680800 + hoff) & 0xffff; - args->v0.vtotal = nv_rd32(disp, 0x680804 + hoff) & 0xffff; + args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff; + args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff; args->v0.vblanke = args->v0.vtotal - 1; - args->v0.hblanks = nv_rd32(disp, 0x680820 + hoff) & 0xffff; - args->v0.htotal = nv_rd32(disp, 0x680824 + hoff) & 0xffff; + args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff; + args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff; args->v0.hblanke = args->v0.htotal - 1; /* @@ -59,7 +60,7 @@ nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, return -ENOTSUPP; args->v0.time[0] = ktime_to_ns(ktime_get()); - line = nv_rd32(disp, 0x600868 + hoff); + line = nvkm_rd32(device, 0x600868 + hoff); args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = (line & 0xffff0000) >> 16; args->v0.vline = (line & 0x0000ffff); @@ -124,14 +125,16 @@ static void nv04_disp_vblank_init(struct nvkm_event *event, int type, int head) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000001); } static void nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000000); } static const struct nvkm_event_func @@ -145,26 +148,27 @@ static void nv04_disp_intr(struct nvkm_subdev *subdev) { struct nvkm_disp *disp = (void *)subdev; - u32 crtc0 = nv_rd32(disp, 0x600100); - u32 crtc1 = nv_rd32(disp, 0x602100); + struct nvkm_device *device = disp->engine.subdev.device; + u32 crtc0 = nvkm_rd32(device, 0x600100); + u32 crtc1 = nvkm_rd32(device, 0x602100); u32 pvideo; if (crtc0 & 0x00000001) { nvkm_disp_vblank(disp, 0); - nv_wr32(disp, 0x600100, 0x00000001); + nvkm_wr32(device, 0x600100, 0x00000001); } if (crtc1 & 0x00000001) { nvkm_disp_vblank(disp, 1); - nv_wr32(disp, 0x602100, 0x00000001); + nvkm_wr32(device, 0x602100, 0x00000001); } if (nv_device(disp)->chipset >= 0x10 && nv_device(disp)->chipset <= 0x40) { - pvideo = nv_rd32(disp, 0x8100); + pvideo = nvkm_rd32(device, 0x8100); if (pvideo & ~0x11) nv_info(disp, "PVIDEO intr: %08x\n", pvideo); - nv_wr32(disp, 0x8100, pvideo); + nvkm_wr32(device, 0x8100, pvideo); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 9551cfe5622a7..a57b7d0c4445b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -89,16 +89,18 @@ static void nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) { struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - nv_mask(disp, 0x610028, 0x00000001 << index, 0x00000000 << index); - nv_wr32(disp, 0x610020, 0x00000001 << index); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000000 << index); + nvkm_wr32(device, 0x610020, 0x00000001 << index); } static void nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) { struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - nv_wr32(disp, 0x610020, 0x00000001 << index); - nv_mask(disp, 0x610028, 0x00000001 << index, 0x00000001 << index); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x610020, 0x00000001 << index); + nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index); } void @@ -165,17 +167,17 @@ nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) u32 nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) { - struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_chan *chan = (void *)object; - return nv_rd32(disp, 0x640000 + (chan->chid * 0x1000) + addr); + struct nvkm_device *device = object->engine->subdev.device; + return nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); } void nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_chan *chan = (void *)object; - nv_wr32(disp, 0x640000 + (chan->chid * 0x1000) + addr, data); + struct nvkm_device *device = object->engine->subdev.device; + nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); } /******************************************************************************* @@ -257,6 +259,7 @@ nv50_disp_dmac_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = dmac->base.chid; int ret; @@ -265,20 +268,20 @@ nv50_disp_dmac_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(disp, 0x610028, 0x00010000 << chid, 0x00010000 << chid); + nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid); /* initialise channel for dma command submission */ - nv_wr32(disp, 0x610204 + (chid * 0x0010), dmac->push); - nv_wr32(disp, 0x610208 + (chid * 0x0010), 0x00010000); - nv_wr32(disp, 0x61020c + (chid * 0x0010), chid); - nv_mask(disp, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); - nv_wr32(disp, 0x640000 + (chid * 0x1000), 0x00000000); - nv_wr32(disp, 0x610200 + (chid * 0x0010), 0x00000013); + nvkm_wr32(device, 0x610204 + (chid * 0x0010), dmac->push); + nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013); /* wait for it to go inactive */ if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) { nv_error(dmac, "init timeout, 0x%08x\n", - nv_rd32(disp, 0x610200 + (chid * 0x10))); + nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -290,20 +293,21 @@ nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = dmac->base.chid; /* deactivate channel */ - nv_mask(disp, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); - nv_mask(disp, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) { nv_error(dmac, "fini timeout, 0x%08x\n", - nv_rd32(disp, 0x610200 + (chid * 0x10))); + nvkm_rd32(device, 0x610200 + (chid * 0x10))); if (suspend) return -EBUSY; } /* disable error reporting and completion notifications */ - nv_mask(disp, 0x610028, 0x00010001 << chid, 0x00000000 << chid); + nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid); return nv50_disp_chan_fini(&dmac->base, suspend); } @@ -316,13 +320,14 @@ static void nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, const struct nv50_disp_mthd_list *list, int inst) { + struct nvkm_device *device = disp->base.engine.subdev.device; struct nvkm_object *object = nv_object(disp); int i; for (i = 0; list->data[i].mthd; i++) { if (list->data[i].addr) { - u32 next = nv_rd32(disp, list->data[i].addr + base + 0); - u32 prev = nv_rd32(disp, list->data[i].addr + base + c); + u32 next = nvkm_rd32(device, list->data[i].addr + base + 0); + u32 prev = nvkm_rd32(device, list->data[i].addr + base + c); u32 mthd = list->data[i].mthd + (list->mthd * inst); const char *name = list->data[i].name; char mods[16]; @@ -517,6 +522,7 @@ nv50_disp_core_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int ret; ret = nv50_disp_chan_init(&mast->base); @@ -524,25 +530,25 @@ nv50_disp_core_init(struct nvkm_object *object) return ret; /* enable error reporting */ - nv_mask(disp, 0x610028, 0x00010000, 0x00010000); + nvkm_mask(device, 0x610028, 0x00010000, 0x00010000); /* attempt to unstick channel from some unknown state */ - if ((nv_rd32(disp, 0x610200) & 0x009f0000) == 0x00020000) - nv_mask(disp, 0x610200, 0x00800000, 0x00800000); - if ((nv_rd32(disp, 0x610200) & 0x003f0000) == 0x00030000) - nv_mask(disp, 0x610200, 0x00600000, 0x00600000); + if ((nvkm_rd32(device, 0x610200) & 0x009f0000) == 0x00020000) + nvkm_mask(device, 0x610200, 0x00800000, 0x00800000); + if ((nvkm_rd32(device, 0x610200) & 0x003f0000) == 0x00030000) + nvkm_mask(device, 0x610200, 0x00600000, 0x00600000); /* initialise channel for dma command submission */ - nv_wr32(disp, 0x610204, mast->push); - nv_wr32(disp, 0x610208, 0x00010000); - nv_wr32(disp, 0x61020c, 0x00000000); - nv_mask(disp, 0x610200, 0x00000010, 0x00000010); - nv_wr32(disp, 0x640000, 0x00000000); - nv_wr32(disp, 0x610200, 0x01000013); + nvkm_wr32(device, 0x610204, mast->push); + nvkm_wr32(device, 0x610208, 0x00010000); + nvkm_wr32(device, 0x61020c, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610200, 0x01000013); /* wait for it to go inactive */ if (!nv_wait(disp, 0x610200, 0x80000000, 0x00000000)) { - nv_error(mast, "init: 0x%08x\n", nv_rd32(disp, 0x610200)); + nv_error(mast, "init: 0x%08x\n", nvkm_rd32(device, 0x610200)); return -EBUSY; } @@ -554,18 +560,19 @@ nv50_disp_core_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; /* deactivate channel */ - nv_mask(disp, 0x610200, 0x00000010, 0x00000000); - nv_mask(disp, 0x610200, 0x00000003, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000010, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000003, 0x00000000); if (!nv_wait(disp, 0x610200, 0x001e0000, 0x00000000)) { - nv_error(mast, "fini: 0x%08x\n", nv_rd32(disp, 0x610200)); + nv_error(mast, "fini: 0x%08x\n", nvkm_rd32(device, 0x610200)); if (suspend) return -EBUSY; } /* disable error reporting and completion notifications */ - nv_mask(disp, 0x610028, 0x00010001, 0x00000000); + nvkm_mask(device, 0x610028, 0x00010001, 0x00000000); return nv50_disp_chan_fini(&mast->base, suspend); } @@ -803,6 +810,7 @@ nv50_disp_pioc_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = pioc->base.chid; int ret; @@ -810,17 +818,17 @@ nv50_disp_pioc_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(disp, 0x610200 + (chid * 0x10), 0x00002000); + nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) { nv_error(pioc, "timeout0: 0x%08x\n", - nv_rd32(disp, 0x610200 + (chid * 0x10))); + nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } - nv_wr32(disp, 0x610200 + (chid * 0x10), 0x00000001); + nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001); if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) { nv_error(pioc, "timeout1: 0x%08x\n", - nv_rd32(disp, 0x610200 + (chid * 0x10))); + nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -832,12 +840,13 @@ nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int chid = pioc->base.chid; - nv_mask(disp, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); + nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) { nv_error(pioc, "timeout: 0x%08x\n", - nv_rd32(disp, 0x610200 + (chid * 0x10))); + nvkm_rd32(device, 0x610200 + (chid * 0x10))); if (suspend) return -EBUSY; } @@ -948,9 +957,10 @@ nv50_disp_curs_ofuncs = { int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) { - const u32 blanke = nv_rd32(disp, 0x610aec + (head * 0x540)); - const u32 blanks = nv_rd32(disp, 0x610af4 + (head * 0x540)); - const u32 total = nv_rd32(disp, 0x610afc + (head * 0x540)); + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540)); + const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540)); + const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540)); union { struct nv04_disp_scanoutpos_v0 v0; } *args = data; @@ -967,10 +977,10 @@ nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) args->v0.htotal = ( total & 0x0000ffff); args->v0.time[0] = ktime_to_ns(ktime_get()); args->v0.vline = /* vline read locks hline */ - nv_rd32(disp, 0x616340 + (head * 0x800)) & 0xffff; + nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; args->v0.time[1] = ktime_to_ns(ktime_get()); args->v0.hline = - nv_rd32(disp, 0x616344 + (head * 0x800)) & 0xffff; + nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; } else return ret; @@ -1133,6 +1143,7 @@ nv50_disp_main_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; int ret, i; u32 tmp; @@ -1144,43 +1155,43 @@ nv50_disp_main_init(struct nvkm_object *object) * another appear to inform EVO of the display capabilities or * something similar. NFI what the 0x614004 caps are for.. */ - tmp = nv_rd32(disp, 0x614004); - nv_wr32(disp, 0x610184, tmp); + tmp = nvkm_rd32(device, 0x614004); + nvkm_wr32(device, 0x610184, tmp); /* ... CRTC caps */ for (i = 0; i < disp->head.nr; i++) { - tmp = nv_rd32(disp, 0x616100 + (i * 0x800)); - nv_wr32(disp, 0x610190 + (i * 0x10), tmp); - tmp = nv_rd32(disp, 0x616104 + (i * 0x800)); - nv_wr32(disp, 0x610194 + (i * 0x10), tmp); - tmp = nv_rd32(disp, 0x616108 + (i * 0x800)); - nv_wr32(disp, 0x610198 + (i * 0x10), tmp); - tmp = nv_rd32(disp, 0x61610c + (i * 0x800)); - nv_wr32(disp, 0x61019c + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); + nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); + nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); + nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); + nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); } /* ... DAC caps */ for (i = 0; i < disp->dac.nr; i++) { - tmp = nv_rd32(disp, 0x61a000 + (i * 0x800)); - nv_wr32(disp, 0x6101d0 + (i * 0x04), tmp); + tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); + nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp); } /* ... SOR caps */ for (i = 0; i < disp->sor.nr; i++) { - tmp = nv_rd32(disp, 0x61c000 + (i * 0x800)); - nv_wr32(disp, 0x6101e0 + (i * 0x04), tmp); + tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); + nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp); } /* ... PIOR caps */ for (i = 0; i < disp->pior.nr; i++) { - tmp = nv_rd32(disp, 0x61e000 + (i * 0x800)); - nv_wr32(disp, 0x6101f0 + (i * 0x04), tmp); + tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800)); + nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp); } /* steal display away from vbios, or something like that */ - if (nv_rd32(disp, 0x610024) & 0x00000100) { - nv_wr32(disp, 0x610024, 0x00000100); - nv_mask(disp, 0x6194e8, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x610024) & 0x00000100) { + nvkm_wr32(device, 0x610024, 0x00000100); + nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); if (!nv_wait(disp, 0x6194e8, 0x00000002, 0x00000000)) { nv_error(disp, "timeout acquiring display\n"); return -EBUSY; @@ -1188,11 +1199,11 @@ nv50_disp_main_init(struct nvkm_object *object) } /* point at display engine memory area (hash table, objects) */ - nv_wr32(disp, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); + nvkm_wr32(device, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ - nv_wr32(disp, 0x61002c, 0x00000370); - nv_wr32(disp, 0x610028, 0x00000000); + nvkm_wr32(device, 0x61002c, 0x00000370); + nvkm_wr32(device, 0x610028, 0x00000000); return 0; } @@ -1201,10 +1212,11 @@ nv50_disp_main_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_base *base = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; /* disable all interrupts */ - nv_wr32(disp, 0x610024, 0x00000000); - nv_wr32(disp, 0x610020, 0x00000000); + nvkm_wr32(device, 0x610024, 0x00000000); + nvkm_wr32(device, 0x610020, 0x00000000); return nvkm_parent_fini(&base->base, suspend); } @@ -1289,14 +1301,16 @@ static void nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x61002c, (4 << head), 0); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head), 0); } static void nv50_disp_vblank_init(struct nvkm_event *event, int type, int head) { struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - nv_mask(disp, 0x61002c, (4 << head), (4 << head)); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); } const struct nvkm_event_func @@ -1325,8 +1339,9 @@ static void nv50_disp_intr_error(struct nv50_disp *disp, int chid) { struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - u32 data = nv_rd32(disp, 0x610084 + (chid * 0x08)); - u32 addr = nv_rd32(disp, 0x610080 + (chid * 0x08)); + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); + u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08)); u32 code = (addr & 0x00ff0000) >> 16; u32 type = (addr & 0x00007000) >> 12; u32 mthd = (addr & 0x00000ffc); @@ -1376,8 +1391,8 @@ nv50_disp_intr_error(struct nv50_disp *disp, int chid) } } - nv_wr32(disp, 0x610020, 0x00010000 << chid); - nv_wr32(disp, 0x610080 + (chid * 0x08), 0x90000000); + nvkm_wr32(device, 0x610020, 0x00010000 << chid); + nvkm_wr32(device, 0x610080 + (chid * 0x08), 0x90000000); } static struct nvkm_output * @@ -1440,7 +1455,8 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, static struct nvkm_output * exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info; u8 ver, hdr, cnt, len; @@ -1450,7 +1466,7 @@ exec_script(struct nv50_disp *disp, int head, int id) /* DAC */ for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) - ctrl = nv_rd32(disp, 0x610b5c + (i * 8)); + ctrl = nvkm_rd32(device, 0x610b5c + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { @@ -1462,14 +1478,14 @@ exec_script(struct nv50_disp *disp, int head, int id) reg = 0x610798; } for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) - ctrl = nv_rd32(disp, reg + (i * 8)); + ctrl = nvkm_rd32(device, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) - ctrl = nv_rd32(disp, 0x610b84 + (i * 8)); + ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); i += 8; } @@ -1497,7 +1513,8 @@ exec_script(struct nv50_disp *disp, int head, int id) static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info1; struct nvbios_ocfg info2; @@ -1508,7 +1525,7 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) /* DAC */ for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) - ctrl = nv_rd32(disp, 0x610b58 + (i * 8)); + ctrl = nvkm_rd32(device, 0x610b58 + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { @@ -1520,14 +1537,14 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) reg = 0x610794; } for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) - ctrl = nv_rd32(disp, reg + (i * 8)); + ctrl = nvkm_rd32(device, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) - ctrl = nv_rd32(disp, 0x610b80 + (i * 8)); + ctrl = nvkm_rd32(device, 0x610b80 + (i * 8)); i += 8; } @@ -1625,8 +1642,9 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) static void nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) { - struct nvkm_devinit *devinit = nvkm_devinit(disp); - u32 pclk = nv_rd32(disp, 0x610ad0 + (head * 0x540)) & 0x3fffff; + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_devinit *devinit = device->devinit; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; if (pclk) devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); } @@ -1635,17 +1653,18 @@ static void nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, struct dcb_output *outp, u32 pclk) { + struct nvkm_device *device = disp->base.engine.subdev.device; const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 soff = ( or * 0x800); const u32 loff = (link * 0x080) + soff; - const u32 ctrl = nv_rd32(disp, 0x610794 + (or * 8)); + const u32 ctrl = nvkm_rd32(device, 0x610794 + (or * 8)); const u32 symbol = 100000; - const s32 vactive = nv_rd32(disp, 0x610af8 + (head * 0x540)) & 0xffff; - const s32 vblanke = nv_rd32(disp, 0x610ae8 + (head * 0x540)) & 0xffff; - const s32 vblanks = nv_rd32(disp, 0x610af0 + (head * 0x540)) & 0xffff; - u32 dpctrl = nv_rd32(disp, 0x61c10c + loff); - u32 clksor = nv_rd32(disp, 0x614300 + soff); + const s32 vactive = nvkm_rd32(device, 0x610af8 + (head * 0x540)) & 0xffff; + const s32 vblanke = nvkm_rd32(device, 0x610ae8 + (head * 0x540)) & 0xffff; + const s32 vblanks = nvkm_rd32(device, 0x610af0 + (head * 0x540)) & 0xffff; + u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); + u32 clksor = nvkm_rd32(device, 0x614300 + soff); int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0; int TU, VTUi, VTUf, VTUa; u64 link_data_rate, link_ratio, unk; @@ -1661,14 +1680,14 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, value = value * link_bw; do_div(value, pclk); value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nv_mask(disp, 0x61c1e8 + soff, 0x0000ffff, value); + nvkm_mask(device, 0x61c1e8 + soff, 0x0000ffff, value); /* symbols/vblank - algorithm taken from comments in tegra driver */ value = vblanks - vblanke - 25; value = value * link_bw; do_div(value, pclk); value = value - ((36 / link_nr) + 3) - 1; - nv_mask(disp, 0x61c1ec + soff, 0x00ffffff, value); + nvkm_mask(device, 0x61c1ec + soff, 0x00ffffff, value); /* watermark / activesym */ if ((ctrl & 0xf0000) == 0x60000) bits = 30; @@ -1744,8 +1763,8 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, do_div(unk, symbol); unk += 6; - nv_mask(disp, 0x61c10c + loff, 0x000001fc, bestTU << 2); - nv_mask(disp, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | + nvkm_mask(device, 0x61c10c + loff, 0x000001fc, bestTU << 2); + nvkm_mask(device, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 | bestVTUf << 16 | bestVTUi << 8 | unk); } @@ -1753,8 +1772,9 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, static void nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) { + struct nvkm_device *device = disp->base.engine.subdev.device; struct nvkm_output *outp; - u32 pclk = nv_rd32(disp, 0x610ad0 + (head * 0x540)) & 0x3fffff; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 hval, hreg = 0x614200 + (head * 0x800); u32 oval, oreg; u32 mask, conf; @@ -1786,10 +1806,10 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) u32 ctrl, datarate; if (outp->info.location == 0) { - ctrl = nv_rd32(disp, 0x610794 + soff); + ctrl = nvkm_rd32(device, 0x610794 + soff); soff = 1; } else { - ctrl = nv_rd32(disp, 0x610b80 + soff); + ctrl = nvkm_rd32(device, 0x610b80 + soff); soff = 2; } @@ -1828,8 +1848,8 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) mask = 0x00000707; } - nv_mask(disp, hreg, 0x0000000f, hval); - nv_mask(disp, oreg, mask, oval); + nvkm_mask(device, hreg, 0x0000000f, hval); + nvkm_mask(device, oreg, mask, oval); } /* If programming a TMDS output on a SOR that can also be configured for @@ -1844,7 +1864,8 @@ static void nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, struct dcb_output *outp) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 loff = (or * 0x800) + (link * 0x80); @@ -1853,14 +1874,15 @@ nv50_disp_intr_unk40_0_tmds(struct nv50_disp *disp, u8 ver, hdr; if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match)) - nv_mask(disp, 0x61c10c + loff, 0x00000001, 0x00000000); + nvkm_mask(device, 0x61c10c + loff, 0x00000001, 0x00000000); } static void nv50_disp_intr_unk40_0(struct nv50_disp *disp, int head) { + struct nvkm_device *device = disp->base.engine.subdev.device; struct nvkm_output *outp; - u32 pclk = nv_rd32(disp, 0x610ad0 + (head * 0x540)) & 0x3fffff; + u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; u32 conf; outp = exec_clkcmp(disp, head, 1, pclk, &conf); @@ -1877,7 +1899,8 @@ nv50_disp_intr_supervisor(struct work_struct *work) struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - u32 super = nv_rd32(disp, 0x610030); + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 super = nvkm_rd32(device, 0x610030); int head; nv_debug(disp, "supervisor 0x%08x 0x%08x\n", disp->super, super); @@ -1917,15 +1940,16 @@ nv50_disp_intr_supervisor(struct work_struct *work) } } - nv_wr32(disp, 0x610030, 0x80000000); + nvkm_wr32(device, 0x610030, 0x80000000); } void nv50_disp_intr(struct nvkm_subdev *subdev) { struct nv50_disp *disp = (void *)subdev; - u32 intr0 = nv_rd32(disp, 0x610020); - u32 intr1 = nv_rd32(disp, 0x610024); + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 intr0 = nvkm_rd32(device, 0x610020); + u32 intr1 = nvkm_rd32(device, 0x610024); while (intr0 & 0x001f0000) { u32 chid = __ffs(intr0 & 0x001f0000) - 16; @@ -1941,18 +1965,18 @@ nv50_disp_intr(struct nvkm_subdev *subdev) if (intr1 & 0x00000004) { nvkm_disp_vblank(&disp->base, 0); - nv_wr32(disp, 0x610024, 0x00000004); + nvkm_wr32(device, 0x610024, 0x00000004); } if (intr1 & 0x00000008) { nvkm_disp_vblank(&disp->base, 1); - nv_wr32(disp, 0x610024, 0x00000008); + nvkm_wr32(device, 0x610024, 0x00000008); } if (intr1 & 0x00000070) { disp->super = (intr1 & 0x00000070); schedule_work(&disp->supervisor); - nv_wr32(disp, 0x610024, disp->super); + nvkm_wr32(device, 0x610024, disp->super); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 94f0b4d2c890e..d93d5945a2d80 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -144,6 +144,7 @@ nv50_pior_dp_impl = { int nv50_pior_power(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = outp->or * 0x800; union { struct nv50_disp_pior_pwr_v0 v0; @@ -163,7 +164,7 @@ nv50_pior_power(NV50_DISP_MTHD_V1) return ret; nv_wait(disp, 0x61e004 + soff, 0x80000000, 0x00000000); - nv_mask(disp, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); + nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); nv_wait(disp, 0x61e004 + soff, 0x80000000, 0x00000000); disp->pior.type[outp->or] = type; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index b4138acc94de5..ed4d13222d9d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -55,8 +55,9 @@ static int g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 loff = g94_sor_loff(outp); - nv_mask(disp, 0x61c10c + loff, 0x0f000000, pattern << 24); + nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; } @@ -64,6 +65,7 @@ int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 mask = 0, i; @@ -71,8 +73,8 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) for (i = 0; i < nr; i++) mask |= 1 << (g94_sor_dp_lane_map(disp, i) >> 3); - nv_mask(disp, 0x61c130 + loff, 0x0000000f, mask); - nv_mask(disp, 0x61c034 + soff, 0x80000000, 0x80000000); + nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); + nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); nv_wait(disp, 0x61c034 + soff, 0x80000000, 0x00000000); return 0; } @@ -81,6 +83,7 @@ static int g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -92,8 +95,8 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) if (bw > 0x06) clksor |= 0x00040000; - nv_mask(disp, 0x614300 + soff, 0x000c0000, clksor); - nv_mask(disp, 0x61c10c + loff, 0x001f4000, dpctrl); + nvkm_mask(device, 0x614300 + soff, 0x000c0000, clksor); + nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl); return 0; } @@ -101,7 +104,8 @@ static int g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; const u32 shift = g94_sor_dp_lane_map(disp, ln); const u32 loff = g94_sor_loff(outp); u32 addr, data[3]; @@ -120,14 +124,14 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) if (!addr) return -EINVAL; - data[0] = nv_rd32(disp, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(disp, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(disp, 0x61c130 + loff); + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(disp, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(disp, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(disp, 0x61c130 + loff, data[2]); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c index 07dbe45996c7d..696bc64693772 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c @@ -40,8 +40,9 @@ static int gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 loff = gf110_sor_loff(outp); - nv_mask(disp, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); + nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } @@ -49,6 +50,7 @@ int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = gf110_sor_soff(outp); const u32 loff = gf110_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -59,8 +61,8 @@ gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) if (ef) dpctrl |= 0x00004000; - nv_mask(disp, 0x612300 + soff, 0x007c0000, clksor); - nv_mask(disp, 0x61c10c + loff, 0x001f4000, dpctrl); + nvkm_mask(device, 0x612300 + soff, 0x007c0000, clksor); + nvkm_mask(device, 0x61c10c + loff, 0x001f4000, dpctrl); return 0; } @@ -69,7 +71,8 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; const u32 shift = g94_sor_dp_lane_map(disp, ln); const u32 loff = gf110_sor_loff(outp); u32 addr, data[4]; @@ -88,16 +91,16 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, if (!addr) return -EINVAL; - data[0] = nv_rd32(disp, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(disp, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(disp, 0x61c130 + loff); + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8); - nv_wr32(disp, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(disp, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(disp, 0x61c130 + loff, data[2]); - data[3] = nv_rd32(disp, 0x61c13c + loff) & ~(0x000000ff << shift); - nv_wr32(disp, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); + data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift); + nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 3078f4d91972b..4c61702ede8af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -42,12 +42,13 @@ void gm204_sor_magic(struct nvkm_output *outp) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = outp->or * 0x100; const u32 data = outp->or + 1; if (outp->info.sorconf.link & 1) - nv_mask(disp, 0x612308 + soff, 0x0000001f, 0x00000000 | data); + nvkm_mask(device, 0x612308 + soff, 0x0000001f, 0x00000000 | data); if (outp->info.sorconf.link & 2) - nv_mask(disp, 0x612388 + soff, 0x0000001f, 0x00000010 | data); + nvkm_mask(device, 0x612388 + soff, 0x0000001f, 0x00000010 | data); } static inline u32 @@ -60,12 +61,13 @@ static int gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 data = 0x01010101 * pattern; if (outp->base.info.sorconf.link & 1) - nv_mask(disp, 0x61c110 + soff, 0x0f0f0f0f, data); + nvkm_mask(device, 0x61c110 + soff, 0x0f0f0f0f, data); else - nv_mask(disp, 0x61c12c + soff, 0x0f0f0f0f, data); + nvkm_mask(device, 0x61c12c + soff, 0x0f0f0f0f, data); return 0; } @@ -73,6 +75,7 @@ static int gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nvkm_device *device = disp->base.engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 loff = gm204_sor_loff(outp); u32 mask = 0, i; @@ -80,8 +83,8 @@ gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) for (i = 0; i < nr; i++) mask |= 1 << (gm204_sor_dp_lane_map(disp, i) >> 3); - nv_mask(disp, 0x61c130 + loff, 0x0000000f, mask); - nv_mask(disp, 0x61c034 + soff, 0x80000000, 0x80000000); + nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); + nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); nv_wait(disp, 0x61c034 + soff, 0x80000000, 0x00000000); return 0; } @@ -91,7 +94,8 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; const u32 shift = gm204_sor_dp_lane_map(disp, ln); const u32 loff = gm204_sor_loff(outp); u32 addr, data[4]; @@ -111,16 +115,16 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return -EINVAL; ocfg.tx_pu &= 0x0f; - data[0] = nv_rd32(disp, 0x61c118 + loff) & ~(0x000000ff << shift); - data[1] = nv_rd32(disp, 0x61c120 + loff) & ~(0x000000ff << shift); - data[2] = nv_rd32(disp, 0x61c130 + loff); + data[0] = nvkm_rd32(device, 0x61c118 + loff) & ~(0x000000ff << shift); + data[1] = nvkm_rd32(device, 0x61c120 + loff) & ~(0x000000ff << shift); + data[2] = nvkm_rd32(device, 0x61c130 + loff); if ((data[2] & 0x00000f00) < (ocfg.tx_pu << 8) || ln == 0) data[2] = (data[2] & ~0x00000f00) | (ocfg.tx_pu << 8); - nv_wr32(disp, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); - nv_wr32(disp, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); - nv_wr32(disp, 0x61c130 + loff, data[2]); - data[3] = nv_rd32(disp, 0x61c13c + loff) & ~(0x000000ff << shift); - nv_wr32(disp, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); + nvkm_wr32(device, 0x61c118 + loff, data[0] | (ocfg.dc << shift)); + nvkm_wr32(device, 0x61c120 + loff, data[1] | (ocfg.pe << shift)); + nvkm_wr32(device, 0x61c130 + loff, data[2]); + data[3] = nvkm_rd32(device, 0x61c13c + loff) & ~(0x000000ff << shift); + nvkm_wr32(device, 0x61c13c + loff, data[3] | (ocfg.pc << shift)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 74ad5921b230c..bf61ce7bac113 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -33,6 +33,7 @@ int nv50_sor_power(NV50_DISP_MTHD_V1) { + struct nvkm_device *device = disp->base.engine.subdev.device; union { struct nv50_disp_sor_pwr_v0 v0; } *args = data; @@ -49,7 +50,7 @@ nv50_sor_power(NV50_DISP_MTHD_V1) return ret; nv_wait(disp, 0x61c004 + soff, 0x80000000, 0x00000000); - nv_mask(disp, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); + nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); nv_wait(disp, 0x61c004 + soff, 0x80000000, 0x00000000); nv_wait(disp, 0x61c030 + soff, 0x10000000, 0x00000000); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c index c91d73bc9c9bd..9f933ac7e8709 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c @@ -29,19 +29,19 @@ nv_rdport(void *obj, int head, u16 port) struct nvkm_device *device = nv_device(obj); if (device->card_type >= NV_50) - return nv_rd08(obj, 0x601000 + port); + return nvkm_rd08(device, 0x601000 + port); if (port == 0x03c0 || port == 0x03c1 || /* AR */ port == 0x03c2 || port == 0x03da || /* INP0 */ port == 0x03d4 || port == 0x03d5) /* CR */ - return nv_rd08(obj, 0x601000 + (head * 0x2000) + port); + return nvkm_rd08(device, 0x601000 + (head * 0x2000) + port); if (port == 0x03c2 || port == 0x03cc || /* MISC */ port == 0x03c4 || port == 0x03c5 || /* SR */ port == 0x03ce || port == 0x03cf) { /* GR */ if (device->card_type < NV_40) head = 0; /* CR44 selects head */ - return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port); + return nvkm_rd08(device, 0x0c0000 + (head * 0x2000) + port); } nv_error(obj, "unknown vga port 0x%04x\n", port); @@ -54,19 +54,19 @@ nv_wrport(void *obj, int head, u16 port, u8 data) struct nvkm_device *device = nv_device(obj); if (device->card_type >= NV_50) - nv_wr08(obj, 0x601000 + port, data); + nvkm_wr08(device, 0x601000 + port, data); else if (port == 0x03c0 || port == 0x03c1 || /* AR */ port == 0x03c2 || port == 0x03da || /* INP0 */ port == 0x03d4 || port == 0x03d5) /* CR */ - nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data); + nvkm_wr08(device, 0x601000 + (head * 0x2000) + port, data); else if (port == 0x03c2 || port == 0x03cc || /* MISC */ port == 0x03c4 || port == 0x03c5 || /* SR */ port == 0x03ce || port == 0x03cf) { /* GR */ if (device->card_type < NV_40) head = 0; /* CR44 selects head */ - nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data); + nvkm_wr08(device, 0x0c0000 + (head * 0x2000) + port, data); } else nv_error(obj, "unknown vga port 0x%04x\n", port); } @@ -135,16 +135,16 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) bool nv_lockvgac(void *obj, bool lock) { - struct nvkm_device *dev = nv_device(obj); + struct nvkm_device *device = nv_device(obj); bool locked = !nv_rdvgac(obj, 0, 0x1f); u8 data = lock ? 0x99 : 0x57; - if (dev->card_type < NV_50) + if (device->card_type < NV_50) nv_wrvgac(obj, 0, 0x1f, data); else nv_wrvgac(obj, 0, 0x3f, data); - if (dev->chipset == 0x11) { - if (!(nv_rd32(obj, 0x001084) & 0x10000000)) + if (device->chipset == 0x11) { + if (!(nvkm_rd32(device, 0x001084) & 0x10000000)) nv_wrvgac(obj, 1, 0x1f, data); } return locked; @@ -171,9 +171,10 @@ nv_lockvgac(void *obj, bool lock) u8 nv_rdvgaowner(void *obj) { - if (nv_device(obj)->card_type < NV_50) { + struct nvkm_device *device = nv_device(obj); + if (device->card_type < NV_50) { if (nv_device(obj)->chipset == 0x11) { - u32 tied = nv_rd32(obj, 0x001084) & 0x10000000; + u32 tied = nvkm_rd32(device, 0x001084) & 0x10000000; if (tied == 0) { u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80; u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01; -- GitLab From 8774440390cdfe37c5d003f850847c9fd67cdf61 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5383/7006] drm/nouveau/fifo: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 18 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 159 ++++++++-------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 164 +++++++++-------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 170 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 23 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 51 +++--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 49 ++--- 7 files changed, 345 insertions(+), 289 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index bff5867e24ced..dfc27a0d2ac29 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -80,10 +80,11 @@ static int g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo *fifo = (void *)parent->engine; struct nv50_fifo_base *base = (void *)parent->parent; struct nv50_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; u32 addr, save, engn; bool done; @@ -103,10 +104,10 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - save = nv_mask(fifo, 0x002520, 0x0000003f, 1 << engn); - nv_wr32(fifo, 0x0032fc, nv_gpuobj(base)->addr >> 12); + save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); + nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); done = nv_wait_ne(fifo, 0x0032fc, 0xffffffff, 0xffffffff); - nv_wr32(fifo, 0x002520, save); + nvkm_wr32(device, 0x002520, save); if (!done) { nv_error(fifo, "channel %d [%s] unload timeout\n", chan->base.chid, nvkm_client_name(chan)); @@ -313,6 +314,7 @@ g84_fifo_chan_init(struct nvkm_object *object) struct nv50_fifo_base *base = (void *)object->parent; struct nv50_fifo_chan *chan = (void *)object; struct nvkm_gpuobj *ramfc = base->ramfc; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; int ret; @@ -320,7 +322,7 @@ g84_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(fifo, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); nv50_fifo_playlist_update(fifo); return 0; } @@ -422,14 +424,16 @@ static void g84_fifo_uevent_init(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x40000000, 0x40000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x40000000, 0x40000000); } static void g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x40000000, 0x00000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x40000000, 0x00000000); } static const struct nvkm_event_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 0a7971a3317ca..f714bda4230f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -76,7 +76,8 @@ struct gf100_fifo_chan { static void gf100_fifo_runlist_update(struct gf100_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(fifo); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -94,11 +95,11 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) } bar->flush(bar); - nv_wr32(fifo, 0x002270, cur->addr >> 12); - nv_wr32(fifo, 0x002274, 0x01f00000 | (p >> 3)); + nvkm_wr32(device, 0x002270, cur->addr >> 12); + nvkm_wr32(device, 0x002274, 0x01f00000 | (p >> 3)); if (wait_event_timeout(fifo->runlist.wait, - !(nv_rd32(fifo, 0x00227c) & 0x00100000), + !(nvkm_rd32(device, 0x00227c) & 0x00100000), msecs_to_jiffies(2000)) == 0) nv_error(fifo, "runlist update timeout\n"); mutex_unlock(&nv_subdev(fifo)->mutex); @@ -145,10 +146,11 @@ static int gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct gf100_fifo *fifo = (void *)parent->engine; struct gf100_fifo_base *base = (void *)parent->parent; struct gf100_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; u32 addr; switch (nv_engidx(object->engine)) { @@ -163,7 +165,7 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EINVAL; } - nv_wr32(fifo, 0x002634, chan->base.chid); + nvkm_wr32(device, 0x002634, chan->base.chid); if (!nv_wait(fifo, 0x002634, 0xffffffff, chan->base.chid)) { nv_error(fifo, "channel %d [%s] kick timeout\n", chan->base.chid, nvkm_client_name(chan)); @@ -253,6 +255,7 @@ gf100_fifo_chan_init(struct nvkm_object *object) struct nvkm_gpuobj *base = nv_gpuobj(object->parent); struct gf100_fifo *fifo = (void *)object->engine; struct gf100_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; int ret; @@ -260,10 +263,10 @@ gf100_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(fifo, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); + nvkm_wr32(device, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nv_wr32(fifo, 0x003004 + (chid * 8), 0x001f0001); + nvkm_wr32(device, 0x003004 + (chid * 8), 0x001f0001); gf100_fifo_runlist_update(fifo); } @@ -277,16 +280,17 @@ gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend) { struct gf100_fifo *fifo = (void *)object->engine; struct gf100_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nv_mask(fifo, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + nvkm_mask(device, 0x003004 + (chid * 8), 0x00000001, 0x00000000); gf100_fifo_runlist_update(fifo); } gf100_fifo_intr_engine(fifo); - nv_wr32(fifo, 0x003000 + (chid * 8), 0x00000000); + nvkm_wr32(device, 0x003000 + (chid * 8), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -408,6 +412,7 @@ static void gf100_fifo_recover_work(struct work_struct *work) { struct gf100_fifo *fifo = container_of(work, typeof(*fifo), fault); + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_object *engine; unsigned long flags; u32 engn, engm = 0; @@ -420,7 +425,7 @@ gf100_fifo_recover_work(struct work_struct *work) for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) engm |= 1 << gf100_fifo_engidx(fifo, engn); - nv_mask(fifo, 0x002630, engm, engm); + nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { if ((engine = (void *)nvkm_engine(fifo, engn))) { @@ -430,21 +435,22 @@ gf100_fifo_recover_work(struct work_struct *work) } gf100_fifo_runlist_update(fifo); - nv_wr32(fifo, 0x00262c, engm); - nv_mask(fifo, 0x002630, engm, 0x00000000); + nvkm_wr32(device, 0x00262c, engm); + nvkm_mask(device, 0x002630, engm, 0x00000000); } static void gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, struct gf100_fifo_chan *chan) { + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; unsigned long flags; nv_error(fifo, "%s engine fault on channel %d, recovering...\n", nv_subdev(engine)->name, chid); - nv_mask(fifo, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); + nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); chan->state = KILLED; spin_lock_irqsave(&fifo->base.lock, flags); @@ -488,12 +494,13 @@ gf100_fifo_sched_reason[] = { static void gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) { + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; struct gf100_fifo_chan *chan; u32 engn; for (engn = 0; engn < 6; engn++) { - u32 stat = nv_rd32(fifo, 0x002640 + (engn * 0x04)); + u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 save = (stat & 0x00100000); /* maybe? */ u32 unk0 = (stat & 0x00040000); @@ -514,7 +521,8 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) static void gf100_fifo_intr_sched(struct gf100_fifo *fifo) { - u32 intr = nv_rd32(fifo, 0x00254c); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; char enunk[6] = ""; @@ -596,10 +604,11 @@ gf100_fifo_fault_gpcclient[] = { static void gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) { - u32 inst = nv_rd32(fifo, 0x002800 + (unit * 0x10)); - u32 valo = nv_rd32(fifo, 0x002804 + (unit * 0x10)); - u32 vahi = nv_rd32(fifo, 0x002808 + (unit * 0x10)); - u32 stat = nv_rd32(fifo, 0x00280c + (unit * 0x10)); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); + u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); + u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); + u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10)); u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; u32 write = (stat & 0x00000080); @@ -621,13 +630,13 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) if (eu) { switch (eu->data2) { case NVDEV_SUBDEV_BAR: - nv_mask(fifo, 0x001704, 0x00000000, 0x00000000); + nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); break; case NVDEV_SUBDEV_INSTMEM: - nv_mask(fifo, 0x001714, 0x00000000, 0x00000000); + nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); break; case NVDEV_ENGINE_IFB: - nv_mask(fifo, 0x001718, 0x00000000, 0x00000000); + nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: engine = nvkm_engine(fifo, eu->data2); @@ -680,10 +689,11 @@ gf100_fifo_pbdma_intr[] = { static void gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) { - u32 stat = nv_rd32(fifo, 0x040108 + (unit * 0x2000)); - u32 addr = nv_rd32(fifo, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(fifo, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0x7f; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)); + u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); + u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); + u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; @@ -704,35 +714,37 @@ gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) subc, mthd, data); } - nv_wr32(fifo, 0x0400c0 + (unit * 0x2000), 0x80600008); - nv_wr32(fifo, 0x040108 + (unit * 0x2000), stat); + nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); + nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); } static void gf100_fifo_intr_runlist(struct gf100_fifo *fifo) { - u32 intr = nv_rd32(fifo, 0x002a00); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 intr = nvkm_rd32(device, 0x002a00); if (intr & 0x10000000) { wake_up(&fifo->runlist.wait); - nv_wr32(fifo, 0x002a00, 0x10000000); + nvkm_wr32(device, 0x002a00, 0x10000000); intr &= ~0x10000000; } if (intr) { nv_error(fifo, "RUNLIST 0x%08x\n", intr); - nv_wr32(fifo, 0x002a00, intr); + nvkm_wr32(device, 0x002a00, intr); } } static void gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) { - u32 intr = nv_rd32(fifo, 0x0025a8 + (engn * 0x04)); - u32 inte = nv_rd32(fifo, 0x002628); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04)); + u32 inte = nvkm_rd32(device, 0x002628); u32 unkn; - nv_wr32(fifo, 0x0025a8 + (engn * 0x04), intr); + nvkm_wr32(device, 0x0025a8 + (engn * 0x04), intr); for (unkn = 0; unkn < 8; unkn++) { u32 ints = (intr >> (unkn * 0x04)) & inte; @@ -742,7 +754,7 @@ gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) } if (ints) { nv_error(fifo, "ENGINE %d %d %01x", engn, unkn, ints); - nv_mask(fifo, 0x002628, ints, 0); + nvkm_mask(device, 0x002628, ints, 0); } } } @@ -750,7 +762,8 @@ gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) static void gf100_fifo_intr_engine(struct gf100_fifo *fifo) { - u32 mask = nv_rd32(fifo, 0x0025a4); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x0025a4); while (mask) { u32 unit = __ffs(mask); gf100_fifo_intr_engine_unit(fifo, unit); @@ -762,53 +775,54 @@ static void gf100_fifo_intr(struct nvkm_subdev *subdev) { struct gf100_fifo *fifo = (void *)subdev; - u32 mask = nv_rd32(fifo, 0x002140); - u32 stat = nv_rd32(fifo, 0x002100) & mask; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x002140); + u32 stat = nvkm_rd32(device, 0x002100) & mask; if (stat & 0x00000001) { - u32 intr = nv_rd32(fifo, 0x00252c); + u32 intr = nvkm_rd32(device, 0x00252c); nv_warn(fifo, "INTR 0x00000001: 0x%08x\n", intr); - nv_wr32(fifo, 0x002100, 0x00000001); + nvkm_wr32(device, 0x002100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000100) { gf100_fifo_intr_sched(fifo); - nv_wr32(fifo, 0x002100, 0x00000100); + nvkm_wr32(device, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x00010000) { - u32 intr = nv_rd32(fifo, 0x00256c); + u32 intr = nvkm_rd32(device, 0x00256c); nv_warn(fifo, "INTR 0x00010000: 0x%08x\n", intr); - nv_wr32(fifo, 0x002100, 0x00010000); + nvkm_wr32(device, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x01000000) { - u32 intr = nv_rd32(fifo, 0x00258c); + u32 intr = nvkm_rd32(device, 0x00258c); nv_warn(fifo, "INTR 0x01000000: 0x%08x\n", intr); - nv_wr32(fifo, 0x002100, 0x01000000); + nvkm_wr32(device, 0x002100, 0x01000000); stat &= ~0x01000000; } if (stat & 0x10000000) { - u32 mask = nv_rd32(fifo, 0x00259c); + u32 mask = nvkm_rd32(device, 0x00259c); while (mask) { u32 unit = __ffs(mask); gf100_fifo_intr_fault(fifo, unit); - nv_wr32(fifo, 0x00259c, (1 << unit)); + nvkm_wr32(device, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nv_rd32(fifo, 0x0025a0); + u32 mask = nvkm_rd32(device, 0x0025a0); while (mask) { u32 unit = __ffs(mask); gf100_fifo_intr_pbdma(fifo, unit); - nv_wr32(fifo, 0x0025a0, (1 << unit)); + nvkm_wr32(device, 0x0025a0, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x20000000; @@ -826,8 +840,8 @@ gf100_fifo_intr(struct nvkm_subdev *subdev) if (stat) { nv_error(fifo, "INTR 0x%08x\n", stat); - nv_mask(fifo, 0x002140, stat, 0x00000000); - nv_wr32(fifo, 0x002100, stat); + nvkm_mask(device, 0x002140, stat, 0x00000000); + nvkm_wr32(device, 0x002100, stat); } } @@ -835,14 +849,16 @@ static void gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x80000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); } static void gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x00000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); } static const struct nvkm_event_func @@ -917,41 +933,42 @@ static int gf100_fifo_init(struct nvkm_object *object) { struct gf100_fifo *fifo = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret, i; ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(fifo, 0x000204, 0xffffffff); - nv_wr32(fifo, 0x002204, 0xffffffff); + nvkm_wr32(device, 0x000204, 0xffffffff); + nvkm_wr32(device, 0x002204, 0xffffffff); - fifo->spoon_nr = hweight32(nv_rd32(fifo, 0x002204)); + fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204)); nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* assign engines to PBDMAs */ if (fifo->spoon_nr >= 3) { - nv_wr32(fifo, 0x002208, ~(1 << 0)); /* PGRAPH */ - nv_wr32(fifo, 0x00220c, ~(1 << 1)); /* PVP */ - nv_wr32(fifo, 0x002210, ~(1 << 1)); /* PMSPP */ - nv_wr32(fifo, 0x002214, ~(1 << 1)); /* PMSVLD */ - nv_wr32(fifo, 0x002218, ~(1 << 2)); /* PCE0 */ - nv_wr32(fifo, 0x00221c, ~(1 << 1)); /* PCE1 */ + nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */ + nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */ + nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */ + nvkm_wr32(device, 0x002214, ~(1 << 1)); /* PMSVLD */ + nvkm_wr32(device, 0x002218, ~(1 << 2)); /* PCE0 */ + nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */ } /* PBDMA[n] */ for (i = 0; i < fifo->spoon_nr; i++) { - nv_mask(fifo, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(fifo, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(fifo, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } - nv_mask(fifo, 0x002200, 0x00000001, 0x00000001); - nv_wr32(fifo, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); + nvkm_mask(device, 0x002200, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - nv_wr32(fifo, 0x002100, 0xffffffff); - nv_wr32(fifo, 0x002140, 0x7fffffff); - nv_wr32(fifo, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0x7fffffff); + nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index ed8d3820a0442..cec1281dbd122 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -95,8 +95,9 @@ struct gk104_fifo_chan { static void gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { - struct nvkm_bar *bar = nvkm_bar(fifo); struct gk104_fifo_engn *engn = &fifo->engine[engine]; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -114,10 +115,10 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) } bar->flush(bar); - nv_wr32(fifo, 0x002270, cur->addr >> 12); - nv_wr32(fifo, 0x002274, (engine << 20) | (p >> 3)); + nvkm_wr32(device, 0x002270, cur->addr >> 12); + nvkm_wr32(device, 0x002274, (engine << 20) | (p >> 3)); - if (wait_event_timeout(engn->wait, !(nv_rd32(fifo, 0x002284 + + if (wait_event_timeout(engn->wait, !(nvkm_rd32(device, 0x002284 + (engine * 0x08)) & 0x00100000), msecs_to_jiffies(2000)) == 0) nv_error(fifo, "runlist %d update timeout\n", engine); @@ -170,8 +171,9 @@ gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) { struct nvkm_object *obj = (void *)chan; struct gk104_fifo *fifo = (void *)obj->engine; + struct nvkm_device *device = fifo->base.engine.subdev.device; - nv_wr32(fifo, 0x002634, chan->base.chid); + nvkm_wr32(device, 0x002634, chan->base.chid); if (!nv_wait(fifo, 0x002634, 0x100000, 0x000000)) { nv_error(fifo, "channel %d [%s] kick timeout\n", chan->base.chid, nvkm_client_name(chan)); @@ -300,6 +302,7 @@ gk104_fifo_chan_init(struct nvkm_object *object) struct nvkm_gpuobj *base = nv_gpuobj(object->parent); struct gk104_fifo *fifo = (void *)object->engine; struct gk104_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; int ret; @@ -307,13 +310,13 @@ gk104_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_mask(fifo, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); - nv_wr32(fifo, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); + nvkm_mask(device, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); + nvkm_wr32(device, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nv_mask(fifo, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); gk104_fifo_runlist_update(fifo, chan->engine); - nv_mask(fifo, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); } return 0; @@ -324,14 +327,15 @@ gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) { struct gk104_fifo *fifo = (void *)object->engine; struct gk104_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nv_mask(fifo, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + nvkm_mask(device, 0x800004 + (chid * 8), 0x00000800, 0x00000800); gk104_fifo_runlist_update(fifo, chan->engine); } - nv_wr32(fifo, 0x800000 + (chid * 8), 0x00000000); + nvkm_wr32(device, 0x800000 + (chid * 8), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -445,6 +449,7 @@ static void gk104_fifo_recover_work(struct work_struct *work) { struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault); + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_object *engine; unsigned long flags; u32 engn, engm = 0; @@ -457,7 +462,7 @@ gk104_fifo_recover_work(struct work_struct *work) for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) engm |= 1 << gk104_fifo_engidx(fifo, engn); - nv_mask(fifo, 0x002630, engm, engm); + nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { if ((engine = (void *)nvkm_engine(fifo, engn))) { @@ -467,21 +472,22 @@ gk104_fifo_recover_work(struct work_struct *work) gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn)); } - nv_wr32(fifo, 0x00262c, engm); - nv_mask(fifo, 0x002630, engm, 0x00000000); + nvkm_wr32(device, 0x00262c, engm); + nvkm_mask(device, 0x002630, engm, 0x00000000); } static void gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, struct gk104_fifo_chan *chan) { + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; unsigned long flags; nv_error(fifo, "%s engine fault on channel %d, recovering...\n", nv_subdev(engine)->name, chid); - nv_mask(fifo, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); + nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); chan->state = KILLED; spin_lock_irqsave(&fifo->base.lock, flags); @@ -530,7 +536,8 @@ gk104_fifo_bind_reason[] = { static void gk104_fifo_intr_bind(struct gk104_fifo *fifo) { - u32 intr = nv_rd32(fifo, 0x00252c); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 intr = nvkm_rd32(device, 0x00252c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; char enunk[6] = ""; @@ -551,12 +558,13 @@ gk104_fifo_sched_reason[] = { static void gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) { + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; struct gk104_fifo_chan *chan; u32 engn; for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { - u32 stat = nv_rd32(fifo, 0x002640 + (engn * 0x04)); + u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 next = (stat & 0x07ff0000) >> 16; u32 chsw = (stat & 0x00008000); @@ -579,7 +587,8 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) static void gk104_fifo_intr_sched(struct gk104_fifo *fifo) { - u32 intr = nv_rd32(fifo, 0x00254c); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; char enunk[6] = ""; @@ -602,15 +611,17 @@ gk104_fifo_intr_sched(struct gk104_fifo *fifo) static void gk104_fifo_intr_chsw(struct gk104_fifo *fifo) { - u32 stat = nv_rd32(fifo, 0x00256c); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, 0x00256c); nv_error(fifo, "CHSW_ERROR 0x%08x\n", stat); - nv_wr32(fifo, 0x00256c, stat); + nvkm_wr32(device, 0x00256c, stat); } static void gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo) { - u32 stat = nv_rd32(fifo, 0x00259c); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, 0x00259c); nv_error(fifo, "DROPPED_MMU_FAULT 0x%08x\n", stat); } @@ -722,10 +733,11 @@ gk104_fifo_fault_gpcclient[] = { static void gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) { - u32 inst = nv_rd32(fifo, 0x002800 + (unit * 0x10)); - u32 valo = nv_rd32(fifo, 0x002804 + (unit * 0x10)); - u32 vahi = nv_rd32(fifo, 0x002808 + (unit * 0x10)); - u32 stat = nv_rd32(fifo, 0x00280c + (unit * 0x10)); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); + u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); + u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); + u32 stat = nvkm_rd32(device, 0x00280c + (unit * 0x10)); u32 gpc = (stat & 0x1f000000) >> 24; u32 client = (stat & 0x00001f00) >> 8; u32 write = (stat & 0x00000080); @@ -747,13 +759,13 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) if (eu) { switch (eu->data2) { case NVDEV_SUBDEV_BAR: - nv_mask(fifo, 0x001704, 0x00000000, 0x00000000); + nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); break; case NVDEV_SUBDEV_INSTMEM: - nv_mask(fifo, 0x001714, 0x00000000, 0x00000000); + nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); break; case NVDEV_ENGINE_IFB: - nv_mask(fifo, 0x001718, 0x00000000, 0x00000000); + nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: engine = nvkm_engine(fifo, eu->data2); @@ -833,11 +845,12 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { static void gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) { - u32 mask = nv_rd32(fifo, 0x04010c + (unit * 0x2000)); - u32 stat = nv_rd32(fifo, 0x040108 + (unit * 0x2000)) & mask; - u32 addr = nv_rd32(fifo, 0x0400c0 + (unit * 0x2000)); - u32 data = nv_rd32(fifo, 0x0400c4 + (unit * 0x2000)); - u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0xfff; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x04010c + (unit * 0x2000)); + u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)) & mask; + u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); + u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); + u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; @@ -845,7 +858,7 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) if (stat & 0x00800000) { if (!gk104_fifo_swmthd(fifo, chid, mthd, data)) show &= ~0x00800000; - nv_wr32(fifo, 0x0400c0 + (unit * 0x2000), 0x80600008); + nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); } if (show) { @@ -859,7 +872,7 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) subc, mthd, data); } - nv_wr32(fifo, 0x040108 + (unit * 0x2000), stat); + nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); } static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { @@ -874,30 +887,32 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { static void gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit) { - u32 mask = nv_rd32(fifo, 0x04014c + (unit * 0x2000)); - u32 stat = nv_rd32(fifo, 0x040148 + (unit * 0x2000)) & mask; - u32 chid = nv_rd32(fifo, 0x040120 + (unit * 0x2000)) & 0xfff; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x04014c + (unit * 0x2000)); + u32 stat = nvkm_rd32(device, 0x040148 + (unit * 0x2000)) & mask; + u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; if (stat) { nv_error(fifo, "PBDMA%d:", unit); nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat); pr_cont("\n"); nv_error(fifo, "PBDMA%d: ch %d %08x %08x\n", unit, chid, - nv_rd32(fifo, 0x040150 + (unit * 0x2000)), - nv_rd32(fifo, 0x040154 + (unit * 0x2000))); + nvkm_rd32(device, 0x040150 + (unit * 0x2000)), + nvkm_rd32(device, 0x040154 + (unit * 0x2000))); } - nv_wr32(fifo, 0x040148 + (unit * 0x2000), stat); + nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat); } static void gk104_fifo_intr_runlist(struct gk104_fifo *fifo) { - u32 mask = nv_rd32(fifo, 0x002a00); + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x002a00); while (mask) { u32 engn = __ffs(mask); wake_up(&fifo->engine[engn].wait); - nv_wr32(fifo, 0x002a00, 1 << engn); + nvkm_wr32(device, 0x002a00, 1 << engn); mask &= ~(1 << engn); } } @@ -912,69 +927,70 @@ static void gk104_fifo_intr(struct nvkm_subdev *subdev) { struct gk104_fifo *fifo = (void *)subdev; - u32 mask = nv_rd32(fifo, 0x002140); - u32 stat = nv_rd32(fifo, 0x002100) & mask; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = nvkm_rd32(device, 0x002140); + u32 stat = nvkm_rd32(device, 0x002100) & mask; if (stat & 0x00000001) { gk104_fifo_intr_bind(fifo); - nv_wr32(fifo, 0x002100, 0x00000001); + nvkm_wr32(device, 0x002100, 0x00000001); stat &= ~0x00000001; } if (stat & 0x00000010) { nv_error(fifo, "PIO_ERROR\n"); - nv_wr32(fifo, 0x002100, 0x00000010); + nvkm_wr32(device, 0x002100, 0x00000010); stat &= ~0x00000010; } if (stat & 0x00000100) { gk104_fifo_intr_sched(fifo); - nv_wr32(fifo, 0x002100, 0x00000100); + nvkm_wr32(device, 0x002100, 0x00000100); stat &= ~0x00000100; } if (stat & 0x00010000) { gk104_fifo_intr_chsw(fifo); - nv_wr32(fifo, 0x002100, 0x00010000); + nvkm_wr32(device, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x00800000) { nv_error(fifo, "FB_FLUSH_TIMEOUT\n"); - nv_wr32(fifo, 0x002100, 0x00800000); + nvkm_wr32(device, 0x002100, 0x00800000); stat &= ~0x00800000; } if (stat & 0x01000000) { nv_error(fifo, "LB_ERROR\n"); - nv_wr32(fifo, 0x002100, 0x01000000); + nvkm_wr32(device, 0x002100, 0x01000000); stat &= ~0x01000000; } if (stat & 0x08000000) { gk104_fifo_intr_dropped_fault(fifo); - nv_wr32(fifo, 0x002100, 0x08000000); + nvkm_wr32(device, 0x002100, 0x08000000); stat &= ~0x08000000; } if (stat & 0x10000000) { - u32 mask = nv_rd32(fifo, 0x00259c); + u32 mask = nvkm_rd32(device, 0x00259c); while (mask) { u32 unit = __ffs(mask); gk104_fifo_intr_fault(fifo, unit); - nv_wr32(fifo, 0x00259c, (1 << unit)); + nvkm_wr32(device, 0x00259c, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x10000000; } if (stat & 0x20000000) { - u32 mask = nv_rd32(fifo, 0x0025a0); + u32 mask = nvkm_rd32(device, 0x0025a0); while (mask) { u32 unit = __ffs(mask); gk104_fifo_intr_pbdma_0(fifo, unit); gk104_fifo_intr_pbdma_1(fifo, unit); - nv_wr32(fifo, 0x0025a0, (1 << unit)); + nvkm_wr32(device, 0x0025a0, (1 << unit)); mask &= ~(1 << unit); } stat &= ~0x20000000; @@ -986,15 +1002,15 @@ gk104_fifo_intr(struct nvkm_subdev *subdev) } if (stat & 0x80000000) { - nv_wr32(fifo, 0x002100, 0x80000000); + nvkm_wr32(device, 0x002100, 0x80000000); gk104_fifo_intr_engine(fifo); stat &= ~0x80000000; } if (stat) { nv_error(fifo, "INTR 0x%08x\n", stat); - nv_mask(fifo, 0x002140, stat, 0x00000000); - nv_wr32(fifo, 0x002100, stat); + nvkm_mask(device, 0x002140, stat, 0x00000000); + nvkm_wr32(device, 0x002100, stat); } } @@ -1002,14 +1018,16 @@ static void gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x80000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); } static void gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - nv_mask(fifo, 0x002140, 0x80000000, 0x00000000); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); } static const struct nvkm_event_func @@ -1023,6 +1041,7 @@ int gk104_fifo_fini(struct nvkm_object *object, bool suspend) { struct gk104_fifo *fifo = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; ret = nvkm_fifo_fini(&fifo->base, suspend); @@ -1030,7 +1049,7 @@ gk104_fifo_fini(struct nvkm_object *object, bool suspend) return ret; /* allow mmu fault interrupts, even when we're not using fifo */ - nv_mask(fifo, 0x002140, 0x10000000, 0x10000000); + nvkm_mask(device, 0x002140, 0x10000000, 0x10000000); return 0; } @@ -1038,6 +1057,7 @@ int gk104_fifo_init(struct nvkm_object *object) { struct gk104_fifo *fifo = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret, i; ret = nvkm_fifo_init(&fifo->base); @@ -1045,27 +1065,27 @@ gk104_fifo_init(struct nvkm_object *object) return ret; /* enable all available PBDMA units */ - nv_wr32(fifo, 0x000204, 0xffffffff); - fifo->spoon_nr = hweight32(nv_rd32(fifo, 0x000204)); + nvkm_wr32(device, 0x000204, 0xffffffff); + fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x000204)); nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* PBDMA[n] */ for (i = 0; i < fifo->spoon_nr; i++) { - nv_mask(fifo, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nv_wr32(fifo, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(fifo, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ } /* PBDMA[n].HCE */ for (i = 0; i < fifo->spoon_nr; i++) { - nv_wr32(fifo, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ - nv_wr32(fifo, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ + nvkm_wr32(device, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */ } - nv_wr32(fifo, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - nv_wr32(fifo, 0x002100, 0xffffffff); - nv_wr32(fifo, 0x002140, 0x7fffffff); + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0x7fffffff); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 91a2080bdaf97..6339b473feb0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -174,6 +174,7 @@ nv04_fifo_chan_init(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 mask = 1 << chan->base.chid; unsigned long flags; int ret; @@ -183,7 +184,7 @@ nv04_fifo_chan_init(struct nvkm_object *object) return ret; spin_lock_irqsave(&fifo->base.lock, flags); - nv_mask(fifo, NV04_PFIFO_MODE, mask, mask); + nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); spin_unlock_irqrestore(&fifo->base.lock, flags); return 0; } @@ -194,6 +195,7 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; struct nvkm_gpuobj *fctx = fifo->ramfc; + struct nvkm_device *device = fifo->base.engine.subdev.device; struct ramfc_desc *c; unsigned long flags; u32 data = chan->ramfc; @@ -201,39 +203,39 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) /* prevent fifo context switches */ spin_lock_irqsave(&fifo->base.lock, flags); - nv_wr32(fifo, NV03_PFIFO_CACHES, 0); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0); /* if this channel is active, replace it with a null context */ - chid = nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; if (chid == chan->base.chid) { - nv_mask(fifo, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 0); - nv_mask(fifo, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); c = fifo->ramfc_desc; do { u32 rm = ((1ULL << c->bits) - 1) << c->regs; u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; - u32 rv = (nv_rd32(fifo, c->regp) & rm) >> c->regs; + u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm); nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); } while ((++c)->bits); c = fifo->ramfc_desc; do { - nv_wr32(fifo, c->regp, 0x00000000); + nvkm_wr32(device, c->regp, 0x00000000); } while ((++c)->bits); - nv_wr32(fifo, NV03_PFIFO_CACHE1_GET, 0); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUT, 0); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); } /* restore normal operation, after disabling dma mode */ - nv_mask(fifo, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); - nv_wr32(fifo, NV03_PFIFO_CACHES, 1); + nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); spin_unlock_irqrestore(&fifo->base.lock, flags); return nvkm_fifo_channel_fini(&chan->base, suspend); @@ -301,13 +303,14 @@ nv04_fifo_pause(struct nvkm_fifo *obj, unsigned long *pflags) __acquires(fifo->base.lock) { struct nv04_fifo *fifo = container_of(obj, typeof(*fifo), base); + struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags; spin_lock_irqsave(&fifo->base.lock, flags); *pflags = flags; - nv_wr32(fifo, NV03_PFIFO_CACHES, 0x00000000); - nv_mask(fifo, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000000); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000); /* in some cases the puller may be left in an inconsistent state * if you try to stop it while it's busy translating handles. @@ -322,11 +325,11 @@ __acquires(fifo->base.lock) NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000)) nv_warn(fifo, "timeout idling puller\n"); - if (nv_rd32(fifo, NV04_PFIFO_CACHE1_PULL0) & + if (nvkm_rd32(device, NV04_PFIFO_CACHE1_PULL0) & NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) - nv_wr32(fifo, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + nvkm_wr32(device, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(fifo, NV04_PFIFO_CACHE1_HASH, 0x00000000); + nvkm_wr32(device, NV04_PFIFO_CACHE1_HASH, 0x00000000); } void @@ -334,10 +337,11 @@ nv04_fifo_start(struct nvkm_fifo *obj, unsigned long *pflags) __releases(fifo->base.lock) { struct nv04_fifo *fifo = container_of(obj, typeof(*fifo), base); + struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags = *pflags; - nv_mask(fifo, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); - nv_wr32(fifo, NV03_PFIFO_CACHES, 0x00000001); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); } @@ -355,6 +359,7 @@ nv_dma_state_err(u32 state) static bool nv04_fifo_swmthd(struct nv04_fifo *fifo, u32 chid, u32 addr, u32 data) { + struct nvkm_device *device = fifo->base.engine.subdev.device; struct nv04_fifo_chan *chan = NULL; struct nvkm_handle *bind; const int subc = (addr >> 13) & 0x7; @@ -380,13 +385,13 @@ nv04_fifo_swmthd(struct nv04_fifo *fifo, u32 chid, u32 addr, u32 data) chan->subc[subc] = data; handled = true; - nv_mask(fifo, NV04_PFIFO_CACHE1_ENGINE, engine, 0); + nvkm_mask(device, NV04_PFIFO_CACHE1_ENGINE, engine, 0); } nvkm_namedb_put(bind); break; default: - engine = nv_rd32(fifo, NV04_PFIFO_CACHE1_ENGINE); + engine = nvkm_rd32(device, NV04_PFIFO_CACHE1_ENGINE); if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) break; @@ -419,11 +424,11 @@ nv04_fifo_cache_error(struct nvkm_device *device, ptr = (get & 0x7ff) >> 2; if (device->card_type < NV_40) { - mthd = nv_rd32(fifo, NV04_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(fifo, NV04_PFIFO_CACHE1_DATA(ptr)); + mthd = nvkm_rd32(device, NV04_PFIFO_CACHE1_METHOD(ptr)); + data = nvkm_rd32(device, NV04_PFIFO_CACHE1_DATA(ptr)); } else { - mthd = nv_rd32(fifo, NV40_PFIFO_CACHE1_METHOD(ptr)); - data = nv_rd32(fifo, NV40_PFIFO_CACHE1_DATA(ptr)); + mthd = nvkm_rd32(device, NV40_PFIFO_CACHE1_METHOD(ptr)); + data = nvkm_rd32(device, NV40_PFIFO_CACHE1_DATA(ptr)); } if (!nv04_fifo_swmthd(fifo, chid, mthd, data)) { @@ -435,19 +440,19 @@ nv04_fifo_cache_error(struct nvkm_device *device, data); } - nv_wr32(fifo, NV04_PFIFO_CACHE1_DMA_PUSH, 0); - nv_wr32(fifo, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); + nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0); + nvkm_wr32(device, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH0) & ~1); - nv_wr32(fifo, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, - nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH0) | 1); - nv_wr32(fifo, NV04_PFIFO_CACHE1_HASH, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, + nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH0) & ~1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, get + 4); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, + nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH0) | 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_HASH, 0); - nv_wr32(fifo, NV04_PFIFO_CACHE1_DMA_PUSH, - nv_rd32(fifo, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); - nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, + nvkm_rd32(device, NV04_PFIFO_CACHE1_DMA_PUSH) | 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); } static void @@ -455,18 +460,18 @@ nv04_fifo_dma_pusher(struct nvkm_device *device, struct nv04_fifo *fifo, u32 chid) { const char *client_name; - u32 dma_get = nv_rd32(fifo, 0x003244); - u32 dma_put = nv_rd32(fifo, 0x003240); - u32 push = nv_rd32(fifo, 0x003220); - u32 state = nv_rd32(fifo, 0x003228); + u32 dma_get = nvkm_rd32(device, 0x003244); + u32 dma_put = nvkm_rd32(device, 0x003240); + u32 push = nvkm_rd32(device, 0x003220); + u32 state = nvkm_rd32(device, 0x003228); client_name = nvkm_client_name_for_fifo_chid(&fifo->base, chid); if (device->card_type == NV_50) { - u32 ho_get = nv_rd32(fifo, 0x003328); - u32 ho_put = nv_rd32(fifo, 0x003320); - u32 ib_get = nv_rd32(fifo, 0x003334); - u32 ib_put = nv_rd32(fifo, 0x003330); + u32 ho_get = nvkm_rd32(device, 0x003328); + u32 ho_put = nvkm_rd32(device, 0x003320); + u32 ib_get = nvkm_rd32(device, 0x003334); + u32 ib_put = nvkm_rd32(device, 0x003330); nv_error(fifo, "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", @@ -474,13 +479,13 @@ nv04_fifo_dma_pusher(struct nvkm_device *device, ib_get, ib_put, state, nv_dma_state_err(state), push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ - nv_wr32(fifo, 0x003364, 0x00000000); + nvkm_wr32(device, 0x003364, 0x00000000); if (dma_get != dma_put || ho_get != ho_put) { - nv_wr32(fifo, 0x003244, dma_put); - nv_wr32(fifo, 0x003328, ho_put); + nvkm_wr32(device, 0x003244, dma_put); + nvkm_wr32(device, 0x003328, ho_put); } else if (ib_get != ib_put) - nv_wr32(fifo, 0x003334, ib_put); + nvkm_wr32(device, 0x003334, ib_put); } else { nv_error(fifo, "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", @@ -488,12 +493,12 @@ nv04_fifo_dma_pusher(struct nvkm_device *device, nv_dma_state_err(state), push); if (dma_get != dma_put) - nv_wr32(fifo, 0x003244, dma_put); + nvkm_wr32(device, 0x003244, dma_put); } - nv_wr32(fifo, 0x003228, 0x00000000); - nv_wr32(fifo, 0x003220, 0x00000001); - nv_wr32(fifo, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); + nvkm_wr32(device, 0x003228, 0x00000000); + nvkm_wr32(device, 0x003220, 0x00000001); + nvkm_wr32(device, 0x002100, NV_PFIFO_INTR_DMA_PUSHER); } void @@ -501,15 +506,15 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) { struct nvkm_device *device = nv_device(subdev); struct nv04_fifo *fifo = (void *)subdev; - u32 mask = nv_rd32(fifo, NV03_PFIFO_INTR_EN_0); - u32 stat = nv_rd32(fifo, NV03_PFIFO_INTR_0) & mask; + u32 mask = nvkm_rd32(device, NV03_PFIFO_INTR_EN_0); + u32 stat = nvkm_rd32(device, NV03_PFIFO_INTR_0) & mask; u32 reassign, chid, get, sem; - reassign = nv_rd32(fifo, NV03_PFIFO_CACHES) & 1; - nv_wr32(fifo, NV03_PFIFO_CACHES, 0); + reassign = nvkm_rd32(device, NV03_PFIFO_CACHES) & 1; + nvkm_wr32(device, NV03_PFIFO_CACHES, 0); - chid = nv_rd32(fifo, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; - get = nv_rd32(fifo, NV03_PFIFO_CACHE1_GET); + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; + get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET); if (stat & NV_PFIFO_INTR_CACHE_ERROR) { nv04_fifo_cache_error(device, fifo, chid, get); @@ -523,23 +528,23 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) if (stat & NV_PFIFO_INTR_SEMAPHORE) { stat &= ~NV_PFIFO_INTR_SEMAPHORE; - nv_wr32(fifo, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); + nvkm_wr32(device, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_SEMAPHORE); - sem = nv_rd32(fifo, NV10_PFIFO_CACHE1_SEMAPHORE); - nv_wr32(fifo, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); + sem = nvkm_rd32(device, NV10_PFIFO_CACHE1_SEMAPHORE); + nvkm_wr32(device, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1); - nv_wr32(fifo, NV03_PFIFO_CACHE1_GET, get + 4); - nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, get + 4); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); } if (device->card_type == NV_50) { if (stat & 0x00000010) { stat &= ~0x00000010; - nv_wr32(fifo, 0x002100, 0x00000010); + nvkm_wr32(device, 0x002100, 0x00000010); } if (stat & 0x40000000) { - nv_wr32(fifo, 0x002100, 0x40000000); + nvkm_wr32(device, 0x002100, 0x40000000); nvkm_fifo_uevent(&fifo->base); stat &= ~0x40000000; } @@ -547,11 +552,11 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) if (stat) { nv_warn(fifo, "unknown intr 0x%08x\n", stat); - nv_mask(fifo, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); - nv_wr32(fifo, NV03_PFIFO_INTR_0, stat); + nvkm_mask(device, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); + nvkm_wr32(device, NV03_PFIFO_INTR_0, stat); } - nv_wr32(fifo, NV03_PFIFO_CACHES, reassign); + nvkm_wr32(device, NV03_PFIFO_CACHES, reassign); } static int @@ -596,29 +601,30 @@ int nv04_fifo_init(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(fifo, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(fifo, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + nvkm_wr32(device, NV04_PFIFO_DELAY_0, 0x000000ff); + nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - nv_wr32(fifo, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | ((fifo->ramht->bits - 9) << 16) | (fifo->ramht->gpuobj.addr >> 8)); - nv_wr32(fifo, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); - nv_wr32(fifo, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(fifo, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(fifo, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(fifo, NV03_PFIFO_CACHES, 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 6f8787fbacc00..6a57df6f78c44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -177,29 +177,30 @@ static int nv17_fifo_init(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(fifo, NV04_PFIFO_DELAY_0, 0x000000ff); - nv_wr32(fifo, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); + nvkm_wr32(device, NV04_PFIFO_DELAY_0, 0x000000ff); + nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); - nv_wr32(fifo, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | ((fifo->ramht->bits - 9) << 16) | (fifo->ramht->gpuobj.addr >> 8)); - nv_wr32(fifo, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); - nv_wr32(fifo, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8 | 0x00010000); + nvkm_wr32(device, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8 | 0x00010000); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(fifo, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(fifo, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(fifo, NV03_PFIFO_CACHES, 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 4c1ed3f29e6bf..7f9eb1018814f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -105,6 +105,7 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) { struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags; u32 reg, ctx; @@ -125,13 +126,13 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) spin_lock_irqsave(&fifo->base.lock, flags); nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; - nv_mask(fifo, 0x002500, 0x00000001, 0x00000000); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - if ((nv_rd32(fifo, 0x003204) & fifo->base.max) == chan->base.chid) - nv_wr32(fifo, reg, nv_engctx(engctx)->addr); + if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) + nvkm_wr32(device, reg, nv_engctx(engctx)->addr); nv_wo32(fifo->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); - nv_mask(fifo, 0x002500, 0x00000001, 0x00000001); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); return 0; } @@ -142,6 +143,7 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, { struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags; u32 reg, ctx; @@ -161,13 +163,13 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, } spin_lock_irqsave(&fifo->base.lock, flags); - nv_mask(fifo, 0x002500, 0x00000001, 0x00000000); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - if ((nv_rd32(fifo, 0x003204) & fifo->base.max) == chan->base.chid) - nv_wr32(fifo, reg, 0x00000000); + if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) + nvkm_wr32(device, reg, 0x00000000); nv_wo32(fifo->ramfc, chan->ramfc + ctx, 0x00000000); - nv_mask(fifo, 0x002500, 0x00000001, 0x00000001); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); return 0; } @@ -295,51 +297,52 @@ static int nv40_fifo_init(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object; - struct nvkm_fb *fb = nvkm_fb(object); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; int ret; ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_wr32(fifo, 0x002040, 0x000000ff); - nv_wr32(fifo, 0x002044, 0x2101ffff); - nv_wr32(fifo, 0x002058, 0x00000001); + nvkm_wr32(device, 0x002040, 0x000000ff); + nvkm_wr32(device, 0x002044, 0x2101ffff); + nvkm_wr32(device, 0x002058, 0x00000001); - nv_wr32(fifo, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | + nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | ((fifo->ramht->bits - 9) << 16) | (fifo->ramht->gpuobj.addr >> 8)); - nv_wr32(fifo, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); switch (nv_device(fifo)->chipset) { case 0x47: case 0x49: case 0x4b: - nv_wr32(fifo, 0x002230, 0x00000001); + nvkm_wr32(device, 0x002230, 0x00000001); case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: case 0x48: - nv_wr32(fifo, 0x002220, 0x00030002); + nvkm_wr32(device, 0x002220, 0x00030002); break; default: - nv_wr32(fifo, 0x002230, 0x00000000); - nv_wr32(fifo, 0x002220, ((fb->ram->size - 512 * 1024 + + nvkm_wr32(device, 0x002230, 0x00000000); + nvkm_wr32(device, 0x002220, ((fb->ram->size - 512 * 1024 + fifo->ramfc->addr) >> 16) | 0x00030000); break; } - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nv_wr32(fifo, NV03_PFIFO_INTR_0, 0xffffffff); - nv_wr32(fifo, NV03_PFIFO_INTR_EN_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); + nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); - nv_wr32(fifo, NV03_PFIFO_CACHE1_PUSH0, 1); - nv_wr32(fifo, NV04_PFIFO_CACHE1_PULL0, 1); - nv_wr32(fifo, NV03_PFIFO_CACHES, 1); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index a36f7efc46588..3a868f9c0a39b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -41,7 +41,8 @@ static void nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) { - struct nvkm_bar *bar = nvkm_bar(fifo); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -49,15 +50,15 @@ nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) fifo->cur_playlist = !fifo->cur_playlist; for (i = fifo->base.min, p = 0; i < fifo->base.max; i++) { - if (nv_rd32(fifo, 0x002600 + (i * 4)) & 0x80000000) + if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000) nv_wo32(cur, p++ * 4, i); } bar->flush(bar); - nv_wr32(fifo, 0x0032f4, cur->addr >> 12); - nv_wr32(fifo, 0x0032ec, p); - nv_wr32(fifo, 0x002500, 0x00000101); + nvkm_wr32(device, 0x0032f4, cur->addr >> 12); + nvkm_wr32(device, 0x0032ec, p); + nvkm_wr32(device, 0x002500, 0x00000101); } void @@ -102,10 +103,11 @@ static int nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo *fifo = (void *)parent->engine; struct nv50_fifo_base *base = (void *)parent->parent; struct nv50_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; u32 addr, me; int ret = 0; @@ -129,17 +131,17 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, * there's also a "ignore these engines" bitmask reg we can use * if we hit the issue there.. */ - me = nv_mask(fifo, 0x00b860, 0x00000001, 0x00000001); + me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); /* do the kickoff... */ - nv_wr32(fifo, 0x0032fc, nv_gpuobj(base)->addr >> 12); + nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); if (!nv_wait_ne(fifo, 0x0032fc, 0xffffffff, 0xffffffff)) { nv_error(fifo, "channel %d [%s] unload timeout\n", chan->base.chid, nvkm_client_name(chan)); if (suspend) ret = -EBUSY; } - nv_wr32(fifo, 0x00b860, me); + nvkm_wr32(device, 0x00b860, me); if (ret == 0) { nv_wo32(base->eng, addr + 0x00, 0x00000000); @@ -324,6 +326,7 @@ nv50_fifo_chan_init(struct nvkm_object *object) struct nv50_fifo_base *base = (void *)object->parent; struct nv50_fifo_chan *chan = (void *)object; struct nvkm_gpuobj *ramfc = base->ramfc; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; int ret; @@ -331,7 +334,7 @@ nv50_fifo_chan_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(fifo, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); nv50_fifo_playlist_update(fifo); return 0; } @@ -341,12 +344,13 @@ nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) { struct nv50_fifo *fifo = (void *)object->engine; struct nv50_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; /* remove channel from playlist, fifo will unload context */ - nv_mask(fifo, 0x002600 + (chid * 4), 0x80000000, 0x00000000); + nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000); nv50_fifo_playlist_update(fifo); - nv_wr32(fifo, 0x002600 + (chid * 4), 0x00000000); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000); return nvkm_fifo_channel_fini(&chan->base, suspend); } @@ -498,27 +502,28 @@ int nv50_fifo_init(struct nvkm_object *object) { struct nv50_fifo *fifo = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret, i; ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - nv_mask(fifo, 0x000200, 0x00000100, 0x00000000); - nv_mask(fifo, 0x000200, 0x00000100, 0x00000100); - nv_wr32(fifo, 0x00250c, 0x6f3cfc34); - nv_wr32(fifo, 0x002044, 0x01003fff); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x00250c, 0x6f3cfc34); + nvkm_wr32(device, 0x002044, 0x01003fff); - nv_wr32(fifo, 0x002100, 0xffffffff); - nv_wr32(fifo, 0x002140, 0xbfffffff); + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0xbfffffff); for (i = 0; i < 128; i++) - nv_wr32(fifo, 0x002600 + (i * 4), 0x00000000); + nvkm_wr32(device, 0x002600 + (i * 4), 0x00000000); nv50_fifo_playlist_update_locked(fifo); - nv_wr32(fifo, 0x003200, 0x00000001); - nv_wr32(fifo, 0x003250, 0x00000001); - nv_wr32(fifo, 0x002500, 0x00000001); + nvkm_wr32(device, 0x003200, 0x00000001); + nvkm_wr32(device, 0x003250, 0x00000001); + nvkm_wr32(device, 0x002500, 0x00000001); return 0; } -- GitLab From 276836d46e535c8ca299a1ea8302879dbdd3e93a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5384/7006] drm/nouveau/gr: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 76 +-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c | 13 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c | 7 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c | 50 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c | 13 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c | 32 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c | 36 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c | 20 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 480 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 121 ++--- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 62 +-- .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 118 ++--- .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c | 129 ++--- .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c | 24 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 107 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 248 ++++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 172 ++++--- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 85 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 202 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 261 +++++----- 22 files changed, 1181 insertions(+), 1089 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 22bc4dbd46dfc..43b393f4cd4de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1005,6 +1005,7 @@ void gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, int shift, int buffer) { + struct nvkm_device *device = info->gr->base.engine.subdev.device; if (info->data) { if (shift >= 0) { info->mmio->addr = addr; @@ -1021,7 +1022,7 @@ gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, return; } - nv_wr32(info->gr, addr, data); + nvkm_wr32(device, addr, data); } void @@ -1085,20 +1086,21 @@ gf100_grctx_generate_unkn(struct gf100_gr *gr) void gf100_grctx_generate_tpcid(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { for (gpc = 0; gpc < gr->gpc_nr; gpc++) { if (tpc < gr->tpc_nr[gpc]) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x4e8), id); - nv_wr32(gr, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x088), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x698), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x4e8), id); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), id); id++; } - nv_wr32(gr, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); } } } @@ -1106,18 +1108,20 @@ gf100_grctx_generate_tpcid(struct gf100_gr *gr) void gf100_grctx_generate_r406028(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 tmp[GPC_MAX / 8] = {}, i = 0; for (i = 0; i < gr->gpc_nr; i++) tmp[i / 8] |= gr->tpc_nr[i] << ((i % 8) * 4); for (i = 0; i < 4; i++) { - nv_wr32(gr, 0x406028 + (i * 4), tmp[i]); - nv_wr32(gr, 0x405870 + (i * 4), tmp[i]); + nvkm_wr32(device, 0x406028 + (i * 4), tmp[i]); + nvkm_wr32(device, 0x405870 + (i * 4), tmp[i]); } } void gf100_grctx_generate_r4060a8(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u8 tpcnr[GPC_MAX], data[TPC_MAX]; int gpc, tpc, i; @@ -1134,12 +1138,13 @@ gf100_grctx_generate_r4060a8(struct gf100_gr *gr) } for (i = 0; i < 4; i++) - nv_wr32(gr, 0x4060a8 + (i * 4), ((u32 *)data)[i]); + nvkm_wr32(device, 0x4060a8 + (i * 4), ((u32 *)data)[i]); } void gf100_grctx_generate_r418bb8(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 data[6] = {}, data2[2] = {}; u8 tpcnr[GPC_MAX]; u8 shift, ntpcv; @@ -1176,28 +1181,29 @@ gf100_grctx_generate_r418bb8(struct gf100_gr *gr) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(gr, 0x418bb8, (gr->tpc_total << 8) | + nvkm_wr32(device, 0x418bb8, (gr->tpc_total << 8) | gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(gr, 0x418b08 + (i * 4), data[i]); + nvkm_wr32(device, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(gr, 0x419bd0, (gr->tpc_total << 8) | + nvkm_wr32(device, 0x419bd0, (gr->tpc_total << 8) | gr->magic_not_rop_nr | data2[0]); - nv_wr32(gr, 0x419be4, data2[1]); + nvkm_wr32(device, 0x419be4, data2[1]); for (i = 0; i < 6; i++) - nv_wr32(gr, 0x419b00 + (i * 4), data[i]); + nvkm_wr32(device, 0x419b00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(gr, 0x4078bc, (gr->tpc_total << 8) | + nvkm_wr32(device, 0x4078bc, (gr->tpc_total << 8) | gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(gr, 0x40780c + (i * 4), data[i]); + nvkm_wr32(device, 0x40780c + (i * 4), data[i]); } void gf100_grctx_generate_r406800(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u64 tpc_mask = 0, tpc_set = 0; u8 tpcnr[GPC_MAX]; int gpc, tpc; @@ -1219,11 +1225,11 @@ gf100_grctx_generate_r406800(struct gf100_gr *gr) tpc_set |= 1ULL << ((gpc * 8) + tpc); } - nv_wr32(gr, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); - nv_wr32(gr, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask)); + nvkm_wr32(device, 0x406800 + (i * 0x20), lower_32_bits(tpc_set)); + nvkm_wr32(device, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask)); if (gr->gpc_nr > 4) { - nv_wr32(gr, 0x406804 + (i * 0x20), upper_32_bits(tpc_set)); - nv_wr32(gr, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask)); + nvkm_wr32(device, 0x406804 + (i * 0x20), upper_32_bits(tpc_set)); + nvkm_wr32(device, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask)); } } } @@ -1231,6 +1237,7 @@ gf100_grctx_generate_r406800(struct gf100_gr *gr) void gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); @@ -1241,7 +1248,7 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_mmio(gr, oclass->tpc); gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(gr, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); @@ -1255,7 +1262,7 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_grctx_generate_r406800(gr); gf100_gr_icmd(gr, oclass->icmd); - nv_wr32(gr, 0x404154, 0x00000400); + nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, oclass->mthd); nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); } @@ -1264,7 +1271,8 @@ int gf100_grctx_generate(struct gf100_gr *gr) { struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; - struct nvkm_bar *bar = nvkm_bar(gr); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *chan; struct gf100_grctx info; int ret, i; @@ -1302,8 +1310,8 @@ gf100_grctx_generate(struct gf100_gr *gr) bar->flush(bar); - nv_wr32(gr, 0x100cb8, (chan->addr + 0x1000) >> 8); - nv_wr32(gr, 0x100cbc, 0x80000001); + nvkm_wr32(device, 0x100cb8, (chan->addr + 0x1000) >> 8); + nvkm_wr32(device, 0x100cbc, 0x80000001); nv_wait(gr, 0x100c80, 0x00008000, 0x00008000); /* setup default state for mmio list construction */ @@ -1315,9 +1323,9 @@ gf100_grctx_generate(struct gf100_gr *gr) /* make channel current */ if (gr->firmware) { - nv_wr32(gr, 0x409840, 0x00000030); - nv_wr32(gr, 0x409500, 0x80000000 | chan->addr >> 12); - nv_wr32(gr, 0x409504, 0x00000003); + nvkm_wr32(device, 0x409840, 0x00000030); + nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); + nvkm_wr32(device, 0x409504, 0x00000003); if (!nv_wait(gr, 0x409800, 0x00000010, 0x00000010)) nv_error(gr, "load_ctx timeout\n"); @@ -1327,9 +1335,9 @@ gf100_grctx_generate(struct gf100_gr *gr) nv_wo32(chan, 0x8002c, 0); bar->flush(bar); } else { - nv_wr32(gr, 0x409840, 0x80000000); - nv_wr32(gr, 0x409500, 0x80000000 | chan->addr >> 12); - nv_wr32(gr, 0x409504, 0x00000001); + nvkm_wr32(device, 0x409840, 0x80000000); + nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); + nvkm_wr32(device, 0x409504, 0x00000001); if (!nv_wait(gr, 0x409800, 0x80000000, 0x80000000)) nv_error(gr, "HUB_SET_CHAN timeout\n"); } @@ -1339,8 +1347,8 @@ gf100_grctx_generate(struct gf100_gr *gr) /* trigger a context unload by unsetting the "next channel valid" bit * and faking a context switch interrupt */ - nv_mask(gr, 0x409b04, 0x80000000, 0x00000000); - nv_wr32(gr, 0x409000, 0x00000100); + nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000); + nvkm_wr32(device, 0x409000, 0x00000100); if (!nv_wait(gr, 0x409b00, 0x80000000, 0x00000000)) { nv_error(gr, "grctx template channel unload timeout\n"); ret = -EBUSY; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c index d810a0b97b762..caccfed4ac7c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c @@ -767,12 +767,13 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info) void gf108_grctx_generate_unkn(struct gf100_gr *gr) { - nv_mask(gr, 0x418c6c, 0x00000001, 0x00000001); - nv_mask(gr, 0x41980c, 0x00000010, 0x00000010); - nv_mask(gr, 0x419814, 0x00000004, 0x00000004); - nv_mask(gr, 0x4064c0, 0x80000000, 0x80000000); - nv_mask(gr, 0x405800, 0x08000000, 0x08000000); - nv_mask(gr, 0x419c00, 0x00000008, 0x00000008); + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_mask(device, 0x418c6c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x41980c, 0x00000010, 0x00000010); + nvkm_mask(device, 0x419814, 0x00000004, 0x00000004); + nvkm_mask(device, 0x4064c0, 0x80000000, 0x80000000); + nvkm_mask(device, 0x405800, 0x08000000, 0x08000000); + nvkm_mask(device, 0x419c00, 0x00000008, 0x00000008); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index 7970b9d4b908e..78f6be2e92db8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -219,6 +219,7 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info) void gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int i; @@ -230,7 +231,7 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_mmio(gr, oclass->tpc); gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(gr, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); @@ -244,10 +245,10 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); gf100_gr_icmd(gr, oclass->icmd); - nv_wr32(gr, 0x404154, 0x00000400); + nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, oclass->mthd); nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index 7b2a96c6e4966..0365acaf8c70b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -874,17 +874,19 @@ gk104_grctx_generate_pagepool(struct gf100_grctx *info) void gk104_grctx_generate_unkn(struct gf100_gr *gr) { - nv_mask(gr, 0x418c6c, 0x00000001, 0x00000001); - nv_mask(gr, 0x41980c, 0x00000010, 0x00000010); - nv_mask(gr, 0x41be08, 0x00000004, 0x00000004); - nv_mask(gr, 0x4064c0, 0x80000000, 0x80000000); - nv_mask(gr, 0x405800, 0x08000000, 0x08000000); - nv_mask(gr, 0x419c00, 0x00000008, 0x00000008); + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_mask(device, 0x418c6c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x41980c, 0x00000010, 0x00000010); + nvkm_mask(device, 0x41be08, 0x00000004, 0x00000004); + nvkm_mask(device, 0x4064c0, 0x80000000, 0x80000000); + nvkm_mask(device, 0x405800, 0x08000000, 0x08000000); + nvkm_mask(device, 0x419c00, 0x00000008, 0x00000008); } void gk104_grctx_generate_r418bb8(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 data[6] = {}, data2[2] = {}; u8 tpcnr[GPC_MAX]; u8 shift, ntpcv; @@ -921,36 +923,38 @@ gk104_grctx_generate_r418bb8(struct gf100_gr *gr) data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5); /* GPC_BROADCAST */ - nv_wr32(gr, 0x418bb8, (gr->tpc_total << 8) | + nvkm_wr32(device, 0x418bb8, (gr->tpc_total << 8) | gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(gr, 0x418b08 + (i * 4), data[i]); + nvkm_wr32(device, 0x418b08 + (i * 4), data[i]); /* GPC_BROADCAST.TP_BROADCAST */ - nv_wr32(gr, 0x41bfd0, (gr->tpc_total << 8) | + nvkm_wr32(device, 0x41bfd0, (gr->tpc_total << 8) | gr->magic_not_rop_nr | data2[0]); - nv_wr32(gr, 0x41bfe4, data2[1]); + nvkm_wr32(device, 0x41bfe4, data2[1]); for (i = 0; i < 6; i++) - nv_wr32(gr, 0x41bf00 + (i * 4), data[i]); + nvkm_wr32(device, 0x41bf00 + (i * 4), data[i]); /* UNK78xx */ - nv_wr32(gr, 0x4078bc, (gr->tpc_total << 8) | + nvkm_wr32(device, 0x4078bc, (gr->tpc_total << 8) | gr->magic_not_rop_nr); for (i = 0; i < 6; i++) - nv_wr32(gr, 0x40780c + (i * 4), data[i]); + nvkm_wr32(device, 0x40780c + (i * 4), data[i]); } void gk104_grctx_generate_rop_active_fbps(struct gf100_gr *gr) { - const u32 fbp_count = nv_rd32(gr, 0x120074); - nv_mask(gr, 0x408850, 0x0000000f, fbp_count); /* zrop */ - nv_mask(gr, 0x408958, 0x0000000f, fbp_count); /* crop */ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 fbp_count = nvkm_rd32(device, 0x120074); + nvkm_mask(device, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nvkm_mask(device, 0x408958, 0x0000000f, fbp_count); /* crop */ } void gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int i; @@ -962,7 +966,7 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_mmio(gr, oclass->tpc); gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(gr, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); @@ -975,19 +979,19 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); gk104_grctx_generate_rop_active_fbps(gr); - nv_mask(gr, 0x419f78, 0x00000001, 0x00000000); + nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000); gf100_gr_icmd(gr, oclass->icmd); - nv_wr32(gr, 0x404154, 0x00000400); + nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, oclass->mthd); nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); - nv_mask(gr, 0x418800, 0x00200000, 0x00200000); - nv_mask(gr, 0x41be10, 0x00800000, 0x00800000); + nvkm_mask(device, 0x418800, 0x00200000, 0x00200000); + nvkm_mask(device, 0x41be10, 0x00800000, 0x00800000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index 91e4aacfdec7e..252bcc331a5a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -28,6 +28,7 @@ static void gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int idle_timeout_save; int i; @@ -36,8 +37,8 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); - idle_timeout_save = nv_rd32(gr, 0x404154); - nv_wr32(gr, 0x404154, 0x00000000); + idle_timeout_save = nvkm_rd32(device, 0x404154); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->attrib(info); @@ -49,17 +50,17 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_grctx_generate_r406800(gr); for (i = 0; i < 8; i++) - nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); gk104_grctx_generate_rop_active_fbps(gr); - nv_mask(gr, 0x5044b0, 0x8000000, 0x8000000); + nvkm_mask(device, 0x5044b0, 0x8000000, 0x8000000); gf100_gr_wait_idle(gr); - nv_wr32(gr, 0x404154, idle_timeout_save); + nvkm_wr32(device, 0x404154, idle_timeout_save); gf100_gr_wait_idle(gr); gf100_gr_mthd(gr, gr->fuc_method); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index 0d908a1231709..9c361ee21fbff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -934,19 +934,20 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info) void gm107_grctx_generate_tpcid(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { for (gpc = 0; gpc < gr->gpc_nr; gpc++) { if (tpc < gr->tpc_nr[gpc]) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(gr, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x088), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x698), id); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), id); id++; } - nv_wr32(gr, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c08), gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c8c), gr->tpc_nr[gpc]); } } } @@ -954,6 +955,7 @@ gm107_grctx_generate_tpcid(struct gf100_gr *gr) static void gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int i; @@ -963,7 +965,7 @@ gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_mmio(gr, oclass->tpc); gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(gr, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); @@ -975,23 +977,23 @@ gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gk104_grctx_generate_r418bb8(gr); gf100_grctx_generate_r406800(gr); - nv_wr32(gr, 0x4064d0, 0x00000001); + nvkm_wr32(device, 0x4064d0, 0x00000001); for (i = 1; i < 8; i++) - nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(gr, 0x406500, 0x00000001); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x406500, 0x00000001); - nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); gk104_grctx_generate_rop_active_fbps(gr); gf100_gr_icmd(gr, oclass->icmd); - nv_wr32(gr, 0x404154, 0x00000400); + nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, oclass->mthd); - nv_mask(gr, 0x419e00, 0x00808080, 0x00808080); - nv_mask(gr, 0x419ccc, 0x80000000, 0x80000000); - nv_mask(gr, 0x419f80, 0x80000000, 0x80000000); - nv_mask(gr, 0x419f88, 0x80000000, 0x80000000); + nvkm_mask(device, 0x419e00, 0x00808080, 0x00808080); + nvkm_mask(device, 0x419ccc, 0x80000000, 0x80000000); + nvkm_mask(device, 0x419f80, 0x80000000, 0x80000000); + nvkm_mask(device, 0x419f88, 0x80000000, 0x80000000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c index 93f38bdfd0cc8..f8c2432b7d7af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c @@ -921,14 +921,15 @@ gm204_grctx_pack_ppc[] = { void gm204_grctx_generate_tpcid(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; int gpc, tpc, id; for (tpc = 0, id = 0; tpc < 4; tpc++) { for (gpc = 0; gpc < gr->gpc_nr; gpc++) { if (tpc < gr->tpc_nr[gpc]) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x698), id); - nv_wr32(gr, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x088), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x698), id); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x088), id); id++; } } @@ -938,14 +939,16 @@ gm204_grctx_generate_tpcid(struct gf100_gr *gr) static void gm204_grctx_generate_rop_active_fbps(struct gf100_gr *gr) { - const u32 fbp_count = nv_rd32(gr, 0x12006c); - nv_mask(gr, 0x408850, 0x0000000f, fbp_count); /* zrop */ - nv_mask(gr, 0x408958, 0x0000000f, fbp_count); /* crop */ + struct nvkm_device *device = gr->base.engine.subdev.device; + const u32 fbp_count = nvkm_rd32(device, 0x12006c); + nvkm_mask(device, 0x408850, 0x0000000f, fbp_count); /* zrop */ + nvkm_mask(device, 0x408958, 0x0000000f, fbp_count); /* crop */ } void gm204_grctx_generate_405b60(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; const u32 dist_nr = DIV_ROUND_UP(gr->tpc_total, 4); u32 dist[TPC_MAX / 4] = {}; u32 gpcs[GPC_MAX] = {}; @@ -969,14 +972,15 @@ gm204_grctx_generate_405b60(struct gf100_gr *gr) } for (i = 0; i < dist_nr; i++) - nv_wr32(gr, 0x405b60 + (i * 4), dist[i]); + nvkm_wr32(device, 0x405b60 + (i * 4), dist[i]); for (i = 0; i < gr->gpc_nr; i++) - nv_wr32(gr, 0x405ba0 + (i * 4), gpcs[i]); + nvkm_wr32(device, 0x405ba0 + (i * 4), gpcs[i]); } void gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; u32 tmp; int i; @@ -987,7 +991,7 @@ gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_mmio(gr, oclass->tpc); gf100_gr_mmio(gr, oclass->ppc); - nv_wr32(gr, 0x404154, 0x00000000); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->bundle(info); oclass->pagepool(info); @@ -999,25 +1003,25 @@ gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gk104_grctx_generate_r418bb8(gr); for (i = 0; i < 8; i++) - nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(gr, 0x406500, 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x406500, 0x00000000); - nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); gm204_grctx_generate_rop_active_fbps(gr); for (tmp = 0, i = 0; i < gr->gpc_nr; i++) tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 4); - nv_wr32(gr, 0x4041c4, tmp); + nvkm_wr32(device, 0x4041c4, tmp); gm204_grctx_generate_405b60(gr); gf100_gr_icmd(gr, oclass->icmd); - nv_wr32(gr, 0x404154, 0x00000800); + nvkm_wr32(device, 0x404154, 0x00000800); gf100_gr_mthd(gr, oclass->mthd); - nv_mask(gr, 0x418e94, 0xffffffff, 0xc4230000); - nv_mask(gr, 0x418e4c, 0xffffffff, 0x70000000); + nvkm_mask(device, 0x418e94, 0xffffffff, 0xc4230000); + nvkm_mask(device, 0x418e4c, 0xffffffff, 0x70000000); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c index c44b2e157ec2c..5f5affc55fe0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c @@ -24,19 +24,21 @@ static void gm20b_grctx_generate_r406028(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 tpc_per_gpc = 0; int i; for (i = 0; i < gr->gpc_nr; i++) tpc_per_gpc |= gr->tpc_nr[i] << (4 * i); - nv_wr32(gr, 0x406028, tpc_per_gpc); - nv_wr32(gr, 0x405870, tpc_per_gpc); + nvkm_wr32(device, 0x406028, tpc_per_gpc); + nvkm_wr32(device, 0x405870, tpc_per_gpc); } static void gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; int idle_timeout_save; int i, tmp; @@ -45,8 +47,8 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); - idle_timeout_save = nv_rd32(gr, 0x404154); - nv_wr32(gr, 0x404154, 0x00000000); + idle_timeout_save = nvkm_rd32(device, 0x404154); + nvkm_wr32(device, 0x404154, 0x00000000); oclass->attrib(info); @@ -57,22 +59,22 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gk104_grctx_generate_r418bb8(gr); for (i = 0; i < 8; i++) - nv_wr32(gr, 0x4064d0 + (i * 0x04), 0x00000000); + nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); - nv_wr32(gr, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); + nvkm_wr32(device, 0x405b00, (gr->tpc_total << 8) | gr->gpc_nr); gk104_grctx_generate_rop_active_fbps(gr); - nv_wr32(gr, 0x408908, nv_rd32(gr, 0x410108) | 0x80000000); + nvkm_wr32(device, 0x408908, nvkm_rd32(device, 0x410108) | 0x80000000); for (tmp = 0, i = 0; i < gr->gpc_nr; i++) tmp |= ((1 << gr->tpc_nr[i]) - 1) << (i * 4); - nv_wr32(gr, 0x4041c4, tmp); + nvkm_wr32(device, 0x4041c4, tmp); gm204_grctx_generate_405b60(gr); gf100_gr_wait_idle(gr); - nv_wr32(gr, 0x404154, idle_timeout_save); + nvkm_wr32(device, 0x404154, idle_timeout_save); gf100_gr_wait_idle(gr); gf100_gr_mthd(gr, gr->fuc_method); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c index a3b0b366f5829..0c717084b44fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c @@ -683,9 +683,9 @@ nv40_grctx_init(struct nvkm_device *device, u32 *size) nv40_grctx_generate(&ctx); - nv_wr32(device, 0x400324, 0); + nvkm_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(device, 0x400328, ctxprog[i]); + nvkm_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; kfree(ctxprog); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index a9a4e0e3f2cb7..e76bf4a217dc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -276,9 +276,9 @@ nv50_grctx_init(struct nvkm_device *device, u32 *size) return -ENOMEM; nv50_grctx_generate(&ctx); - nv_wr32(device, 0x400324, 0); + nvkm_wr32(device, 0x400324, 0); for (i = 0; i < ctx.ctxprog_len; i++) - nv_wr32(device, 0x400328, ctxprog[i]); + nvkm_wr32(device, 0x400328, ctxprog[i]); *size = ctx.ctxvals_pos * 4; kfree(ctxprog); return 0; @@ -298,7 +298,7 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) struct nvkm_device *device = ctx->device; int i, j; int offset, base; - u32 units = nv_rd32 (ctx->device, 0x1540); + u32 units = nvkm_rd32(device, 0x1540); /* 0800: DISPATCH */ cp_ctx(ctx, 0x400808, 7); @@ -1189,7 +1189,7 @@ nv50_gr_construct_xfer1(struct nvkm_grctx *ctx) int i; int offset; int size = 0; - u32 units = nv_rd32 (ctx->device, 0x1540); + u32 units = nvkm_rd32(device, 0x1540); offset = (ctx->ctxvals_pos+0x3f)&~0x3f; ctx->ctxvals_base = offset; @@ -3272,7 +3272,7 @@ nv50_gr_construct_xfer2(struct nvkm_grctx *ctx) struct nvkm_device *device = ctx->device; int i; u32 offset; - u32 units = nv_rd32 (ctx->device, 0x1540); + u32 units = nvkm_rd32(device, 0x1540); int size = 0; offset = (ctx->ctxvals_pos+0x3f)&~0x3f; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index c1b84a687f763..b692e8e2b9822 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -43,15 +43,16 @@ static void gf100_gr_zbc_clear_color(struct gf100_gr *gr, int zbc) { + struct nvkm_device *device = gr->base.engine.subdev.device; if (gr->zbc_color[zbc].format) { - nv_wr32(gr, 0x405804, gr->zbc_color[zbc].ds[0]); - nv_wr32(gr, 0x405808, gr->zbc_color[zbc].ds[1]); - nv_wr32(gr, 0x40580c, gr->zbc_color[zbc].ds[2]); - nv_wr32(gr, 0x405810, gr->zbc_color[zbc].ds[3]); - } - nv_wr32(gr, 0x405814, gr->zbc_color[zbc].format); - nv_wr32(gr, 0x405820, zbc); - nv_wr32(gr, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ + nvkm_wr32(device, 0x405804, gr->zbc_color[zbc].ds[0]); + nvkm_wr32(device, 0x405808, gr->zbc_color[zbc].ds[1]); + nvkm_wr32(device, 0x40580c, gr->zbc_color[zbc].ds[2]); + nvkm_wr32(device, 0x405810, gr->zbc_color[zbc].ds[3]); + } + nvkm_wr32(device, 0x405814, gr->zbc_color[zbc].format); + nvkm_wr32(device, 0x405820, zbc); + nvkm_wr32(device, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */ } static int @@ -93,11 +94,12 @@ gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, static void gf100_gr_zbc_clear_depth(struct gf100_gr *gr, int zbc) { + struct nvkm_device *device = gr->base.engine.subdev.device; if (gr->zbc_depth[zbc].format) - nv_wr32(gr, 0x405818, gr->zbc_depth[zbc].ds); - nv_wr32(gr, 0x40581c, gr->zbc_depth[zbc].format); - nv_wr32(gr, 0x405820, zbc); - nv_wr32(gr, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ + nvkm_wr32(device, 0x405818, gr->zbc_depth[zbc].ds); + nvkm_wr32(device, 0x40581c, gr->zbc_depth[zbc].format); + nvkm_wr32(device, 0x405820, zbc); + nvkm_wr32(device, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */ } static int @@ -236,10 +238,11 @@ gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd, void *pdata, u32 size) { struct gf100_gr *gr = (void *)object->engine; + struct nvkm_device *device = gr->base.engine.subdev.device; if (size >= sizeof(u32)) { u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000; - nv_wr32(gr, 0x419e44, data); - nv_wr32(gr, 0x419e4c, data); + nvkm_wr32(device, 0x419e44, data); + nvkm_wr32(device, 0x419e4c, data); return 0; } return -EINVAL; @@ -670,6 +673,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr) int gf100_gr_wait_idle(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000); bool gr_enabled, ctxsw_active, gr_busy; @@ -678,11 +682,11 @@ gf100_gr_wait_idle(struct gf100_gr *gr) * required to make sure FIFO_ENGINE_STATUS (0x2640) is * up-to-date */ - nv_rd32(gr, 0x400700); + nvkm_rd32(device, 0x400700); - gr_enabled = nv_rd32(gr, 0x200) & 0x1000; - ctxsw_active = nv_rd32(gr, 0x2640) & 0x8000; - gr_busy = nv_rd32(gr, 0x40060c) & 0x1; + gr_enabled = nvkm_rd32(device, 0x200) & 0x1000; + ctxsw_active = nvkm_rd32(device, 0x2640) & 0x8000; + gr_busy = nvkm_rd32(device, 0x40060c) & 0x1; if (!gr_enabled || (!gr_busy && !ctxsw_active)) return 0; @@ -696,6 +700,7 @@ gf100_gr_wait_idle(struct gf100_gr *gr) void gf100_gr_mmio(struct gf100_gr *gr, const struct gf100_gr_pack *p) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; @@ -703,7 +708,7 @@ gf100_gr_mmio(struct gf100_gr *gr, const struct gf100_gr_pack *p) u32 next = init->addr + init->count * init->pitch; u32 addr = init->addr; while (addr < next) { - nv_wr32(gr, addr, init->data); + nvkm_wr32(device, addr, init->data); addr += init->pitch; } } @@ -712,23 +717,24 @@ gf100_gr_mmio(struct gf100_gr *gr, const struct gf100_gr_pack *p) void gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; u32 data = 0; - nv_wr32(gr, 0x400208, 0x80000000); + nvkm_wr32(device, 0x400208, 0x80000000); pack_for_each_init(init, pack, p) { u32 next = init->addr + init->count * init->pitch; u32 addr = init->addr; if ((pack == p && init == p->init) || data != init->data) { - nv_wr32(gr, 0x400204, init->data); + nvkm_wr32(device, 0x400204, init->data); data = init->data; } while (addr < next) { - nv_wr32(gr, 0x400200, addr); + nvkm_wr32(device, 0x400200, addr); /** * Wait for GR to go idle after submitting a * GO_IDLE bundle @@ -740,12 +746,13 @@ gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) } } - nv_wr32(gr, 0x400208, 0x00000000); + nvkm_wr32(device, 0x400208, 0x00000000); } void gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *pack; const struct gf100_gr_init *init; u32 data = 0; @@ -756,12 +763,12 @@ gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p) u32 addr = init->addr; if ((pack == p && init == p->init) || data != init->data) { - nv_wr32(gr, 0x40448c, init->data); + nvkm_wr32(device, 0x40448c, init->data); data = init->data; } while (addr < next) { - nv_wr32(gr, 0x404488, ctrl | (addr << 14)); + nvkm_wr32(device, 0x404488, ctrl | (addr << 14)); addr += init->pitch; } } @@ -808,13 +815,14 @@ static const struct nvkm_enum gf100_gpc_rop_error[] = { static void gf100_gr_trap_gpc_rop(struct gf100_gr *gr, int gpc) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 trap[4]; int i; - trap[0] = nv_rd32(gr, GPC_UNIT(gpc, 0x0420)); - trap[1] = nv_rd32(gr, GPC_UNIT(gpc, 0x0434)); - trap[2] = nv_rd32(gr, GPC_UNIT(gpc, 0x0438)); - trap[3] = nv_rd32(gr, GPC_UNIT(gpc, 0x043c)); + trap[0] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0420)); + trap[1] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0434)); + trap[2] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0438)); + trap[3] = nvkm_rd32(device, GPC_UNIT(gpc, 0x043c)); nv_error(gr, "GPC%d/PROP trap:", gpc); for (i = 0; i <= 29; ++i) { @@ -828,7 +836,7 @@ gf100_gr_trap_gpc_rop(struct gf100_gr *gr, int gpc) nv_error(gr, "x = %u, y = %u, format = %x, storage type = %x\n", trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f, trap[3] & 0xff); - nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); } static const struct nvkm_enum gf100_mp_warp_error[] = { @@ -853,8 +861,9 @@ static const struct nvkm_bitfield gf100_mp_global_error[] = { static void gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) { - u32 werr = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x648)); - u32 gerr = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x650)); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 werr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x648)); + u32 gerr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x650)); nv_error(gr, "GPC%i/TPC%i/MP trap:", gpc, tpc); nvkm_bitfield_print(gf100_mp_global_error, gerr); @@ -864,19 +873,20 @@ gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) } pr_cont("\n"); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x650), gerr); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x650), gerr); } static void gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) { - u32 stat = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x0508)); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0508)); if (stat & 0x00000001) { - u32 trap = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x0224)); + u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0224)); nv_error(gr, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); stat &= ~0x00000001; } @@ -886,16 +896,16 @@ gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) } if (stat & 0x00000004) { - u32 trap = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x0084)); + u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0084)); nv_error(gr, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { - u32 trap = nv_rd32(gr, TPC_UNIT(gpc, tpc, 0x048c)); + u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x048c)); nv_error(gr, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); stat &= ~0x00000008; } @@ -907,7 +917,8 @@ gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) static void gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) { - u32 stat = nv_rd32(gr, GPC_UNIT(gpc, 0x2c90)); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, GPC_UNIT(gpc, 0x2c90)); int tpc; if (stat & 0x00000001) { @@ -916,23 +927,23 @@ gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) } if (stat & 0x00000002) { - u32 trap = nv_rd32(gr, GPC_UNIT(gpc, 0x0900)); + u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0900)); nv_error(gr, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); - nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); stat &= ~0x00000002; } if (stat & 0x00000004) { - u32 trap = nv_rd32(gr, GPC_UNIT(gpc, 0x1028)); + u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x1028)); nv_error(gr, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); - nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { - u32 trap = nv_rd32(gr, GPC_UNIT(gpc, 0x0824)); + u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0824)); nv_error(gr, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); - nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); stat &= ~0x00000009; } @@ -940,7 +951,7 @@ gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) u32 mask = 0x00010000 << tpc; if (stat & mask) { gf100_gr_trap_tpc(gr, gpc, tpc); - nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), mask); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), mask); stat &= ~mask; } } @@ -953,59 +964,60 @@ gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) static void gf100_gr_trap_intr(struct gf100_gr *gr) { - u32 trap = nv_rd32(gr, 0x400108); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 trap = nvkm_rd32(device, 0x400108); int rop, gpc, i; if (trap & 0x00000001) { - u32 stat = nv_rd32(gr, 0x404000); + u32 stat = nvkm_rd32(device, 0x404000); nv_error(gr, "DISPATCH 0x%08x\n", stat); - nv_wr32(gr, 0x404000, 0xc0000000); - nv_wr32(gr, 0x400108, 0x00000001); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000001); trap &= ~0x00000001; } if (trap & 0x00000002) { - u32 stat = nv_rd32(gr, 0x404600); + u32 stat = nvkm_rd32(device, 0x404600); nv_error(gr, "M2MF 0x%08x\n", stat); - nv_wr32(gr, 0x404600, 0xc0000000); - nv_wr32(gr, 0x400108, 0x00000002); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000002); trap &= ~0x00000002; } if (trap & 0x00000008) { - u32 stat = nv_rd32(gr, 0x408030); + u32 stat = nvkm_rd32(device, 0x408030); nv_error(gr, "CCACHE 0x%08x\n", stat); - nv_wr32(gr, 0x408030, 0xc0000000); - nv_wr32(gr, 0x400108, 0x00000008); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000008); trap &= ~0x00000008; } if (trap & 0x00000010) { - u32 stat = nv_rd32(gr, 0x405840); + u32 stat = nvkm_rd32(device, 0x405840); nv_error(gr, "SHADER 0x%08x\n", stat); - nv_wr32(gr, 0x405840, 0xc0000000); - nv_wr32(gr, 0x400108, 0x00000010); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000010); trap &= ~0x00000010; } if (trap & 0x00000040) { - u32 stat = nv_rd32(gr, 0x40601c); + u32 stat = nvkm_rd32(device, 0x40601c); nv_error(gr, "UNK6 0x%08x\n", stat); - nv_wr32(gr, 0x40601c, 0xc0000000); - nv_wr32(gr, 0x400108, 0x00000040); + nvkm_wr32(device, 0x40601c, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000040); trap &= ~0x00000040; } if (trap & 0x00000080) { - u32 stat = nv_rd32(gr, 0x404490); + u32 stat = nvkm_rd32(device, 0x404490); nv_error(gr, "MACRO 0x%08x\n", stat); - nv_wr32(gr, 0x404490, 0xc0000000); - nv_wr32(gr, 0x400108, 0x00000080); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x00000080); trap &= ~0x00000080; } if (trap & 0x00000100) { - u32 stat = nv_rd32(gr, 0x407020); + u32 stat = nvkm_rd32(device, 0x407020); nv_error(gr, "SKED:"); for (i = 0; i <= 29; ++i) { @@ -1017,61 +1029,63 @@ gf100_gr_trap_intr(struct gf100_gr *gr) pr_cont("\n"); if (stat & 0x3fffffff) - nv_wr32(gr, 0x407020, 0x40000000); - nv_wr32(gr, 0x400108, 0x00000100); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x400108, 0x00000100); trap &= ~0x00000100; } if (trap & 0x01000000) { - u32 stat = nv_rd32(gr, 0x400118); + u32 stat = nvkm_rd32(device, 0x400118); for (gpc = 0; stat && gpc < gr->gpc_nr; gpc++) { u32 mask = 0x00000001 << gpc; if (stat & mask) { gf100_gr_trap_gpc(gr, gpc); - nv_wr32(gr, 0x400118, mask); + nvkm_wr32(device, 0x400118, mask); stat &= ~mask; } } - nv_wr32(gr, 0x400108, 0x01000000); + nvkm_wr32(device, 0x400108, 0x01000000); trap &= ~0x01000000; } if (trap & 0x02000000) { for (rop = 0; rop < gr->rop_nr; rop++) { - u32 statz = nv_rd32(gr, ROP_UNIT(rop, 0x070)); - u32 statc = nv_rd32(gr, ROP_UNIT(rop, 0x144)); + u32 statz = nvkm_rd32(device, ROP_UNIT(rop, 0x070)); + u32 statc = nvkm_rd32(device, ROP_UNIT(rop, 0x144)); nv_error(gr, "ROP%d 0x%08x 0x%08x\n", rop, statz, statc); - nv_wr32(gr, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(gr, ROP_UNIT(rop, 0x144), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); } - nv_wr32(gr, 0x400108, 0x02000000); + nvkm_wr32(device, 0x400108, 0x02000000); trap &= ~0x02000000; } if (trap) { nv_error(gr, "TRAP UNHANDLED 0x%08x\n", trap); - nv_wr32(gr, 0x400108, trap); + nvkm_wr32(device, 0x400108, trap); } } static void gf100_gr_ctxctl_debug_unit(struct gf100_gr *gr, u32 base) { + struct nvkm_device *device = gr->base.engine.subdev.device; nv_error(gr, "%06x - done 0x%08x\n", base, - nv_rd32(gr, base + 0x400)); + nvkm_rd32(device, base + 0x400)); nv_error(gr, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(gr, base + 0x800), nv_rd32(gr, base + 0x804), - nv_rd32(gr, base + 0x808), nv_rd32(gr, base + 0x80c)); + nvkm_rd32(device, base + 0x800), nvkm_rd32(device, base + 0x804), + nvkm_rd32(device, base + 0x808), nvkm_rd32(device, base + 0x80c)); nv_error(gr, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nv_rd32(gr, base + 0x810), nv_rd32(gr, base + 0x814), - nv_rd32(gr, base + 0x818), nv_rd32(gr, base + 0x81c)); + nvkm_rd32(device, base + 0x810), nvkm_rd32(device, base + 0x814), + nvkm_rd32(device, base + 0x818), nvkm_rd32(device, base + 0x81c)); } void gf100_gr_ctxctl_debug(struct gf100_gr *gr) { - u32 gpcnr = nv_rd32(gr, 0x409604) & 0xffff; + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 gpcnr = nvkm_rd32(device, 0x409604) & 0xffff; u32 gpc; gf100_gr_ctxctl_debug_unit(gr, 0x409000); @@ -1082,22 +1096,23 @@ gf100_gr_ctxctl_debug(struct gf100_gr *gr) static void gf100_gr_ctxctl_isr(struct gf100_gr *gr) { - u32 stat = nv_rd32(gr, 0x409c18); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, 0x409c18); if (stat & 0x00000001) { - u32 code = nv_rd32(gr, 0x409814); + u32 code = nvkm_rd32(device, 0x409814); if (code == E_BAD_FWMTHD) { - u32 class = nv_rd32(gr, 0x409808); - u32 addr = nv_rd32(gr, 0x40980c); + u32 class = nvkm_rd32(device, 0x409808); + u32 addr = nvkm_rd32(device, 0x40980c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); - u32 data = nv_rd32(gr, 0x409810); + u32 data = nvkm_rd32(device, 0x409810); nv_error(gr, "FECS MTHD subc %d class 0x%04x " "mthd 0x%04x data 0x%08x\n", subc, class, mthd, data); - nv_wr32(gr, 0x409c20, 0x00000001); + nvkm_wr32(device, 0x409c20, 0x00000001); stat &= ~0x00000001; } else { nv_error(gr, "FECS ucode error %d\n", code); @@ -1107,37 +1122,38 @@ gf100_gr_ctxctl_isr(struct gf100_gr *gr) if (stat & 0x00080000) { nv_error(gr, "FECS watchdog timeout\n"); gf100_gr_ctxctl_debug(gr); - nv_wr32(gr, 0x409c20, 0x00080000); + nvkm_wr32(device, 0x409c20, 0x00080000); stat &= ~0x00080000; } if (stat) { nv_error(gr, "FECS 0x%08x\n", stat); gf100_gr_ctxctl_debug(gr); - nv_wr32(gr, 0x409c20, stat); + nvkm_wr32(device, 0x409c20, stat); } } static void gf100_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); + struct gf100_gr *gr = (void *)subdev; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; - struct gf100_gr *gr = (void *)subdev; - u64 inst = nv_rd32(gr, 0x409b00) & 0x0fffffff; - u32 stat = nv_rd32(gr, 0x400100); - u32 addr = nv_rd32(gr, 0x400704); + u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff; + u32 stat = nvkm_rd32(device, 0x400100); + u32 addr = nvkm_rd32(device, 0x400704); u32 mthd = (addr & 0x00003ffc); u32 subc = (addr & 0x00070000) >> 16; - u32 data = nv_rd32(gr, 0x400708); - u32 code = nv_rd32(gr, 0x400110); + u32 data = nvkm_rd32(device, 0x400708); + u32 code = nvkm_rd32(device, 0x400110); u32 class; int chid; if (nv_device(gr)->card_type < NV_E0 || subc < 4) - class = nv_rd32(gr, 0x404200 + (subc * 4)); + class = nvkm_rd32(device, 0x404200 + (subc * 4)); else class = 0x0000; @@ -1149,7 +1165,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) * notifier interrupt, only needed for cyclestats * can be safely ignored */ - nv_wr32(gr, 0x400100, 0x00000001); + nvkm_wr32(device, 0x400100, 0x00000001); stat &= ~0x00000001; } @@ -1162,7 +1178,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) subc, class, mthd, data); } nvkm_handle_put(handle); - nv_wr32(gr, 0x400100, 0x00000010); + nvkm_wr32(device, 0x400100, 0x00000010); stat &= ~0x00000010; } @@ -1171,7 +1187,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst << 12, nvkm_client_name(engctx), subc, class, mthd, data); - nv_wr32(gr, 0x400100, 0x00000020); + nvkm_wr32(device, 0x400100, 0x00000020); stat &= ~0x00000020; } @@ -1181,7 +1197,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", chid, inst << 12, nvkm_client_name(engctx), subc, class, mthd, data); - nv_wr32(gr, 0x400100, 0x00100000); + nvkm_wr32(device, 0x400100, 0x00100000); stat &= ~0x00100000; } @@ -1189,22 +1205,22 @@ gf100_gr_intr(struct nvkm_subdev *subdev) nv_error(gr, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, nvkm_client_name(engctx)); gf100_gr_trap_intr(gr); - nv_wr32(gr, 0x400100, 0x00200000); + nvkm_wr32(device, 0x400100, 0x00200000); stat &= ~0x00200000; } if (stat & 0x00080000) { gf100_gr_ctxctl_isr(gr); - nv_wr32(gr, 0x400100, 0x00080000); + nvkm_wr32(device, 0x400100, 0x00080000); stat &= ~0x00080000; } if (stat) { nv_error(gr, "unknown stat 0x%08x\n", stat); - nv_wr32(gr, 0x400100, stat); + nvkm_wr32(device, 0x400100, stat); } - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400500, 0x00010001); nvkm_engctx_put(engctx); } @@ -1212,22 +1228,23 @@ void gf100_gr_init_fw(struct gf100_gr *gr, u32 fuc_base, struct gf100_gr_fuc *code, struct gf100_gr_fuc *data) { + struct nvkm_device *device = gr->base.engine.subdev.device; int i; - nv_wr32(gr, fuc_base + 0x01c0, 0x01000000); + nvkm_wr32(device, fuc_base + 0x01c0, 0x01000000); for (i = 0; i < data->size / 4; i++) - nv_wr32(gr, fuc_base + 0x01c4, data->data[i]); + nvkm_wr32(device, fuc_base + 0x01c4, data->data[i]); - nv_wr32(gr, fuc_base + 0x0180, 0x01000000); + nvkm_wr32(device, fuc_base + 0x0180, 0x01000000); for (i = 0; i < code->size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(gr, fuc_base + 0x0188, i >> 6); - nv_wr32(gr, fuc_base + 0x0184, code->data[i]); + nvkm_wr32(device, fuc_base + 0x0188, i >> 6); + nvkm_wr32(device, fuc_base + 0x0184, code->data[i]); } /* code must be padded to 0x40 words */ for (; i & 0x3f; i++) - nv_wr32(gr, fuc_base + 0x0184, 0); + nvkm_wr32(device, fuc_base + 0x0184, 0); } static void @@ -1235,17 +1252,18 @@ gf100_gr_init_csdata(struct gf100_gr *gr, const struct gf100_gr_pack *pack, u32 falcon, u32 starstar, u32 base) { + struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_gr_pack *iter; const struct gf100_gr_init *init; u32 addr = ~0, prev = ~0, xfer = 0; u32 star, temp; - nv_wr32(gr, falcon + 0x01c0, 0x02000000 + starstar); - star = nv_rd32(gr, falcon + 0x01c4); - temp = nv_rd32(gr, falcon + 0x01c4); + nvkm_wr32(device, falcon + 0x01c0, 0x02000000 + starstar); + star = nvkm_rd32(device, falcon + 0x01c4); + temp = nvkm_rd32(device, falcon + 0x01c4); if (temp > star) star = temp; - nv_wr32(gr, falcon + 0x01c0, 0x01000000 + star); + nvkm_wr32(device, falcon + 0x01c0, 0x01000000 + star); pack_for_each_init(init, iter, pack) { u32 head = init->addr - base; @@ -1254,7 +1272,7 @@ gf100_gr_init_csdata(struct gf100_gr *gr, if (head != prev + 4 || xfer >= 32) { if (xfer) { u32 data = ((--xfer << 26) | addr); - nv_wr32(gr, falcon + 0x01c4, data); + nvkm_wr32(device, falcon + 0x01c4, data); star += 4; } addr = head; @@ -1266,14 +1284,15 @@ gf100_gr_init_csdata(struct gf100_gr *gr, } } - nv_wr32(gr, falcon + 0x01c4, (--xfer << 26) | addr); - nv_wr32(gr, falcon + 0x01c0, 0x01000004 + starstar); - nv_wr32(gr, falcon + 0x01c4, star + 4); + nvkm_wr32(device, falcon + 0x01c4, (--xfer << 26) | addr); + nvkm_wr32(device, falcon + 0x01c0, 0x01000004 + starstar); + nvkm_wr32(device, falcon + 0x01c4, star + 4); } int gf100_gr_init_ctxctl(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass; struct gf100_grctx_oclass *cclass = (void *)nv_engine(gr)->cclass; int i; @@ -1288,73 +1307,73 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); /* start both of them running */ - nv_wr32(gr, 0x409840, 0xffffffff); - nv_wr32(gr, 0x41a10c, 0x00000000); - nv_wr32(gr, 0x40910c, 0x00000000); - nv_wr32(gr, 0x41a100, 0x00000002); - nv_wr32(gr, 0x409100, 0x00000002); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x41a10c, 0x00000000); + nvkm_wr32(device, 0x40910c, 0x00000000); + nvkm_wr32(device, 0x41a100, 0x00000002); + nvkm_wr32(device, 0x409100, 0x00000002); if (!nv_wait(gr, 0x409800, 0x00000001, 0x00000001)) nv_warn(gr, "0x409800 wait failed\n"); - nv_wr32(gr, 0x409840, 0xffffffff); - nv_wr32(gr, 0x409500, 0x7fffffff); - nv_wr32(gr, 0x409504, 0x00000021); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x7fffffff); + nvkm_wr32(device, 0x409504, 0x00000021); - nv_wr32(gr, 0x409840, 0xffffffff); - nv_wr32(gr, 0x409500, 0x00000000); - nv_wr32(gr, 0x409504, 0x00000010); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x00000000); + nvkm_wr32(device, 0x409504, 0x00000010); if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { nv_error(gr, "fuc09 req 0x10 timeout\n"); return -EBUSY; } - gr->size = nv_rd32(gr, 0x409800); + gr->size = nvkm_rd32(device, 0x409800); - nv_wr32(gr, 0x409840, 0xffffffff); - nv_wr32(gr, 0x409500, 0x00000000); - nv_wr32(gr, 0x409504, 0x00000016); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x00000000); + nvkm_wr32(device, 0x409504, 0x00000016); if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { nv_error(gr, "fuc09 req 0x16 timeout\n"); return -EBUSY; } - nv_wr32(gr, 0x409840, 0xffffffff); - nv_wr32(gr, 0x409500, 0x00000000); - nv_wr32(gr, 0x409504, 0x00000025); + nvkm_wr32(device, 0x409840, 0xffffffff); + nvkm_wr32(device, 0x409500, 0x00000000); + nvkm_wr32(device, 0x409504, 0x00000025); if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { nv_error(gr, "fuc09 req 0x25 timeout\n"); return -EBUSY; } if (nv_device(gr)->chipset >= 0xe0) { - nv_wr32(gr, 0x409800, 0x00000000); - nv_wr32(gr, 0x409500, 0x00000001); - nv_wr32(gr, 0x409504, 0x00000030); + nvkm_wr32(device, 0x409800, 0x00000000); + nvkm_wr32(device, 0x409500, 0x00000001); + nvkm_wr32(device, 0x409504, 0x00000030); if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { nv_error(gr, "fuc09 req 0x30 timeout\n"); return -EBUSY; } - nv_wr32(gr, 0x409810, 0xb00095c8); - nv_wr32(gr, 0x409800, 0x00000000); - nv_wr32(gr, 0x409500, 0x00000001); - nv_wr32(gr, 0x409504, 0x00000031); + nvkm_wr32(device, 0x409810, 0xb00095c8); + nvkm_wr32(device, 0x409800, 0x00000000); + nvkm_wr32(device, 0x409500, 0x00000001); + nvkm_wr32(device, 0x409504, 0x00000031); if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { nv_error(gr, "fuc09 req 0x31 timeout\n"); return -EBUSY; } - nv_wr32(gr, 0x409810, 0x00080420); - nv_wr32(gr, 0x409800, 0x00000000); - nv_wr32(gr, 0x409500, 0x00000001); - nv_wr32(gr, 0x409504, 0x00000032); + nvkm_wr32(device, 0x409810, 0x00080420); + nvkm_wr32(device, 0x409800, 0x00000000); + nvkm_wr32(device, 0x409500, 0x00000001); + nvkm_wr32(device, 0x409504, 0x00000032); if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { nv_error(gr, "fuc09 req 0x32 timeout\n"); return -EBUSY; } - nv_wr32(gr, 0x409614, 0x00000070); - nv_wr32(gr, 0x409614, 0x00000770); - nv_wr32(gr, 0x40802c, 0x00000001); + nvkm_wr32(device, 0x409614, 0x00000070); + nvkm_wr32(device, 0x409614, 0x00000770); + nvkm_wr32(device, 0x40802c, 0x00000001); } if (gr->data == NULL) { @@ -1373,27 +1392,27 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) /* load HUB microcode */ nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - nv_wr32(gr, 0x4091c0, 0x01000000); + nvkm_wr32(device, 0x4091c0, 0x01000000); for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) - nv_wr32(gr, 0x4091c4, oclass->fecs.ucode->data.data[i]); + nvkm_wr32(device, 0x4091c4, oclass->fecs.ucode->data.data[i]); - nv_wr32(gr, 0x409180, 0x01000000); + nvkm_wr32(device, 0x409180, 0x01000000); for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(gr, 0x409188, i >> 6); - nv_wr32(gr, 0x409184, oclass->fecs.ucode->code.data[i]); + nvkm_wr32(device, 0x409188, i >> 6); + nvkm_wr32(device, 0x409184, oclass->fecs.ucode->code.data[i]); } /* load GPC microcode */ - nv_wr32(gr, 0x41a1c0, 0x01000000); + nvkm_wr32(device, 0x41a1c0, 0x01000000); for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) - nv_wr32(gr, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); + nvkm_wr32(device, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); - nv_wr32(gr, 0x41a180, 0x01000000); + nvkm_wr32(device, 0x41a180, 0x01000000); for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wr32(gr, 0x41a188, i >> 6); - nv_wr32(gr, 0x41a184, oclass->gpccs.ucode->code.data[i]); + nvkm_wr32(device, 0x41a188, i >> 6); + nvkm_wr32(device, 0x41a184, oclass->gpccs.ucode->code.data[i]); } nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); @@ -1404,15 +1423,15 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) gf100_gr_init_csdata(gr, cclass->ppc, 0x41a000, 0x008, 0x41be00); /* start HUB ucode running, it'll init the GPCs */ - nv_wr32(gr, 0x40910c, 0x00000000); - nv_wr32(gr, 0x409100, 0x00000002); + nvkm_wr32(device, 0x40910c, 0x00000000); + nvkm_wr32(device, 0x409100, 0x00000002); if (!nv_wait(gr, 0x409800, 0x80000000, 0x80000000)) { nv_error(gr, "HUB_INIT timed out\n"); gf100_gr_ctxctl_debug(gr); return -EBUSY; } - gr->size = nv_rd32(gr, 0x409804); + gr->size = nvkm_rd32(device, 0x409804); if (gr->data == NULL) { int ret = gf100_grctx_generate(gr); if (ret) { @@ -1427,8 +1446,9 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) int gf100_gr_init(struct nvkm_object *object) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr *gr = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct gf100_gr_oclass *oclass = (void *)object->oclass; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; @@ -1439,14 +1459,14 @@ gf100_gr_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(gr, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x08a4), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0888), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x088c), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); - nv_wr32(gr, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0888), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); gf100_gr_mmio(gr, oclass->mmio); @@ -1460,76 +1480,76 @@ gf100_gr_init(struct nvkm_object *object) data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(gr, GPC_BCAST(0x0980), data[0]); - nv_wr32(gr, GPC_BCAST(0x0984), data[1]); - nv_wr32(gr, GPC_BCAST(0x0988), data[2]); - nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | gr->tpc_total); - nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } if (nv_device(gr)->chipset != 0xd7) - nv_wr32(gr, GPC_BCAST(0x1bd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x1bd4), magicgpc918); else - nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400500, 0x00010001); - nv_wr32(gr, 0x400100, 0xffffffff); - nv_wr32(gr, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); - nv_wr32(gr, 0x409c24, 0x000f0000); - nv_wr32(gr, 0x404000, 0xc0000000); - nv_wr32(gr, 0x404600, 0xc0000000); - nv_wr32(gr, 0x408030, 0xc0000000); - nv_wr32(gr, 0x40601c, 0xc0000000); - nv_wr32(gr, 0x404490, 0xc0000000); - nv_wr32(gr, 0x406018, 0xc0000000); - nv_wr32(gr, 0x405840, 0xc0000000); - nv_wr32(gr, 0x405844, 0x00ffffff); - nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(gr, 0x419eb4, 0x00001000, 0x00001000); + nvkm_wr32(device, 0x409c24, 0x000f0000); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x40601c, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + nvkm_mask(device, 0x419eb4, 0x00001000, 0x00001000); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } for (rop = 0; rop < gr->rop_nr; rop++) { - nv_wr32(gr, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(gr, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(gr, 0x400108, 0xffffffff); - nv_wr32(gr, 0x400138, 0xffffffff); - nv_wr32(gr, 0x400118, 0xffffffff); - nv_wr32(gr, 0x400130, 0xffffffff); - nv_wr32(gr, 0x40011c, 0xffffffff); - nv_wr32(gr, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(gr, 0x400054, 0x34ce3464); + nvkm_wr32(device, 0x400054, 0x34ce3464); gf100_gr_zbc_init(gr); @@ -1644,14 +1664,14 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_wo32(gr->unk4188b8, i, 0x00000010); } - gr->rop_nr = (nv_rd32(gr, 0x409604) & 0x001f0000) >> 16; - gr->gpc_nr = nv_rd32(gr, 0x409604) & 0x0000001f; + gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16; + gr->gpc_nr = nvkm_rd32(device, 0x409604) & 0x0000001f; for (i = 0; i < gr->gpc_nr; i++) { - gr->tpc_nr[i] = nv_rd32(gr, GPC_UNIT(i, 0x2608)); + gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608)); gr->tpc_total += gr->tpc_nr[i]; gr->ppc_nr[i] = oclass->ppc_nr; for (j = 0; j < gr->ppc_nr[i]; j++) { - u8 mask = nv_rd32(gr, GPC_UNIT(i, 0x0c30 + (j * 4))); + u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); gr->ppc_tpc_nr[i][j] = hweight8(mask); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index 9f83122dc1a8d..89bb101615544 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -197,7 +197,8 @@ gk104_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr *gr = (void *)object; - struct nvkm_pmu *pmu = nvkm_pmu(gr); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_pmu *pmu = device->pmu; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; @@ -211,18 +212,18 @@ gk104_gr_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(gr, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x08a4), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0888), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x088c), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); - nv_wr32(gr, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0888), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); gf100_gr_mmio(gr, oclass->mmio); - nv_wr32(gr, GPC_UNIT(0, 0x3018), 0x00000001); + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); @@ -235,75 +236,75 @@ gk104_gr_init(struct nvkm_object *object) data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(gr, GPC_BCAST(0x0980), data[0]); - nv_wr32(gr, GPC_BCAST(0x0984), data[1]); - nv_wr32(gr, GPC_BCAST(0x0988), data[2]); - nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | gr->tpc_total); - nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400500, 0x00010001); - nv_wr32(gr, 0x400100, 0xffffffff); - nv_wr32(gr, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); - nv_wr32(gr, 0x409ffc, 0x00000000); - nv_wr32(gr, 0x409c14, 0x00003e3e); - nv_wr32(gr, 0x409c24, 0x000f0001); - nv_wr32(gr, 0x404000, 0xc0000000); - nv_wr32(gr, 0x404600, 0xc0000000); - nv_wr32(gr, 0x408030, 0xc0000000); - nv_wr32(gr, 0x404490, 0xc0000000); - nv_wr32(gr, 0x406018, 0xc0000000); - nv_wr32(gr, 0x407020, 0x40000000); - nv_wr32(gr, 0x405840, 0xc0000000); - nv_wr32(gr, 0x405844, 0x00ffffff); - nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); - nv_mask(gr, 0x419eb4, 0x00001000, 0x00001000); + nvkm_wr32(device, 0x409ffc, 0x00000000); + nvkm_wr32(device, 0x409c14, 0x00003e3e); + nvkm_wr32(device, 0x409c24, 0x000f0001); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); + nvkm_mask(device, 0x419eb4, 0x00001000, 0x00001000); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x3038), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x3038), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f); } - nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } for (rop = 0; rop < gr->rop_nr; rop++) { - nv_wr32(gr, ROP_UNIT(rop, 0x144), 0xc0000000); - nv_wr32(gr, ROP_UNIT(rop, 0x070), 0xc0000000); - nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(gr, 0x400108, 0xffffffff); - nv_wr32(gr, 0x400138, 0xffffffff); - nv_wr32(gr, 0x400118, 0xffffffff); - nv_wr32(gr, 0x400130, 0xffffffff); - nv_wr32(gr, 0x40011c, 0xffffffff); - nv_wr32(gr, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(gr, 0x400054, 0x34ce3464); + nvkm_wr32(device, 0x400054, 0x34ce3464); gf100_gr_zbc_init(gr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index 9816303ad7164..12b34c7a14778 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -236,8 +236,9 @@ gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) static void gk20a_gr_set_hww_esr_report_mask(struct gf100_gr *gr) { - nv_wr32(gr, 0x419e44, 0x1ffffe); - nv_wr32(gr, 0x419e4c, 0x7f); + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_wr32(device, 0x419e44, 0x1ffffe); + nvkm_wr32(device, 0x419e4c, 0x7f); } int @@ -245,6 +246,7 @@ gk20a_gr_init(struct nvkm_object *object) { struct gk20a_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr *gr = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; @@ -256,7 +258,7 @@ gk20a_gr_init(struct nvkm_object *object) return ret; /* Clear SCC RAM */ - nv_wr32(gr, 0x40802c, 0x1); + nvkm_wr32(device, 0x40802c, 0x1); gf100_gr_mmio(gr, gr->fuc_sw_nonctx); @@ -269,14 +271,14 @@ gk20a_gr_init(struct nvkm_object *object) return ret; /* MMU debug buffer */ - nv_wr32(gr, 0x100cc8, gr->unk4188b4->addr >> 8); - nv_wr32(gr, 0x100ccc, gr->unk4188b8->addr >> 8); + nvkm_wr32(device, 0x100cc8, gr->unk4188b4->addr >> 8); + nvkm_wr32(device, 0x100ccc, gr->unk4188b8->addr >> 8); if (oclass->init_gpc_mmu) oclass->init_gpc_mmu(gr); /* Set the PE as stream master */ - nv_mask(gr, 0x503018, 0x1, 0x1); + nvkm_mask(device, 0x503018, 0x1, 0x1); /* Zcull init */ memset(data, 0x00, sizeof(data)); @@ -290,49 +292,49 @@ gk20a_gr_init(struct nvkm_object *object) data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(gr, GPC_BCAST(0x0980), data[0]); - nv_wr32(gr, GPC_BCAST(0x0984), data[1]); - nv_wr32(gr, GPC_BCAST(0x0988), data[2]); - nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x0914), - gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | - gr->tpc_total); - nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), + gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | + gr->tpc_total); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); /* Enable FIFO access */ - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400500, 0x00010001); /* Enable interrupts */ - nv_wr32(gr, 0x400100, 0xffffffff); - nv_wr32(gr, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); /* Enable FECS error interrupts */ - nv_wr32(gr, 0x409c24, 0x000f0000); + nvkm_wr32(device, 0x409c24, 0x000f0000); /* Enable hardware warning exceptions */ - nv_wr32(gr, 0x404000, 0xc0000000); - nv_wr32(gr, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); if (oclass->set_hww_esr_report_mask) oclass->set_hww_esr_report_mask(gr); /* Enable TPC exceptions per GPC */ - nv_wr32(gr, 0x419d0c, 0x2); - nv_wr32(gr, 0x41ac94, (((1 << gr->tpc_total) - 1) & 0xff) << 16); + nvkm_wr32(device, 0x419d0c, 0x2); + nvkm_wr32(device, 0x41ac94, (((1 << gr->tpc_total) - 1) & 0xff) << 16); /* Reset and enable all exceptions */ - nv_wr32(gr, 0x400108, 0xffffffff); - nv_wr32(gr, 0x400138, 0xffffffff); - nv_wr32(gr, 0x400118, 0xffffffff); - nv_wr32(gr, 0x400130, 0xffffffff); - nv_wr32(gr, 0x40011c, 0xffffffff); - nv_wr32(gr, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); gf100_gr_zbc_init(gr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index 5e9560f6ac0e5..1e451a9e22903 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -304,7 +304,8 @@ gm107_gr_init_bios(struct gf100_gr *gr) { 0x419af0, 0x419af4 }, { 0x419af8, 0x419afc }, }; - struct nvkm_bios *bios = nvkm_bios(gr); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvbios_P0260E infoE; struct nvbios_P0260X infoX; int E = -1, X; @@ -312,9 +313,9 @@ gm107_gr_init_bios(struct gf100_gr *gr) while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) { if (X = -1, E < ARRAY_SIZE(regs)) { - nv_wr32(gr, regs[E].ctrl, infoE.data); + nvkm_wr32(device, regs[E].ctrl, infoE.data); while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX)) - nv_wr32(gr, regs[E].data, infoX.data); + nvkm_wr32(device, regs[E].data, infoX.data); } } } @@ -324,6 +325,7 @@ gm107_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr *gr = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; @@ -334,17 +336,17 @@ gm107_gr_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(gr, GPC_BCAST(0x0880), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0890), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x0894), 0x00000000); - nv_wr32(gr, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); - nv_wr32(gr, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); + nvkm_wr32(device, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); gf100_gr_mmio(gr, oclass->mmio); gm107_gr_init_bios(gr); - nv_wr32(gr, GPC_UNIT(0, 0x3018), 0x00000001); + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); @@ -357,75 +359,75 @@ gm107_gr_init(struct nvkm_object *object) data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(gr, GPC_BCAST(0x0980), data[0]); - nv_wr32(gr, GPC_BCAST(0x0984), data[1]); - nv_wr32(gr, GPC_BCAST(0x0988), data[2]); - nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | gr->tpc_total); - nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400500, 0x00010001); - nv_wr32(gr, 0x400100, 0xffffffff); - nv_wr32(gr, 0x40013c, 0xffffffff); - nv_wr32(gr, 0x400124, 0x00000002); - nv_wr32(gr, 0x409c24, 0x000e0000); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400124, 0x00000002); + nvkm_wr32(device, 0x409c24, 0x000e0000); - nv_wr32(gr, 0x404000, 0xc0000000); - nv_wr32(gr, 0x404600, 0xc0000000); - nv_wr32(gr, 0x408030, 0xc0000000); - nv_wr32(gr, 0x404490, 0xc0000000); - nv_wr32(gr, 0x406018, 0xc0000000); - nv_wr32(gr, 0x407020, 0x40000000); - nv_wr32(gr, 0x405840, 0xc0000000); - nv_wr32(gr, 0x405844, 0x00ffffff); - nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { for (ppc = 0; ppc < 2 /* gr->ppc_nr[gpc] */; ppc++) - nv_wr32(gr, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nvkm_wr32(device, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } - nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } for (rop = 0; rop < gr->rop_nr; rop++) { - nv_wr32(gr, ROP_UNIT(rop, 0x144), 0x40000000); - nv_wr32(gr, ROP_UNIT(rop, 0x070), 0x40000000); - nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(gr, 0x400108, 0xffffffff); - nv_wr32(gr, 0x400138, 0xffffffff); - nv_wr32(gr, 0x400118, 0xffffffff); - nv_wr32(gr, 0x400130, 0xffffffff); - nv_wr32(gr, 0x40011c, 0xffffffff); - nv_wr32(gr, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(gr, 0x400054, 0x2c350f63); + nvkm_wr32(device, 0x400054, 0x2c350f63); gf100_gr_zbc_init(gr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index 4cc60edafaef8..c3d2343d41d3b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -253,6 +253,7 @@ gm204_gr_init(struct nvkm_object *object) { struct gf100_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr *gr = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; @@ -264,24 +265,24 @@ gm204_gr_init(struct nvkm_object *object) if (ret) return ret; - tmp = nv_rd32(gr, 0x100c80); /*XXX: mask? */ - nv_wr32(gr, 0x418880, 0x00001000 | (tmp & 0x00000fff)); - nv_wr32(gr, 0x418890, 0x00000000); - nv_wr32(gr, 0x418894, 0x00000000); - nv_wr32(gr, 0x4188b4, gr->unk4188b4->addr >> 8); - nv_wr32(gr, 0x4188b8, gr->unk4188b8->addr >> 8); - nv_mask(gr, 0x4188b0, 0x00040000, 0x00040000); + tmp = nvkm_rd32(device, 0x100c80); /*XXX: mask? */ + nvkm_wr32(device, 0x418880, 0x00001000 | (tmp & 0x00000fff)); + nvkm_wr32(device, 0x418890, 0x00000000); + nvkm_wr32(device, 0x418894, 0x00000000); + nvkm_wr32(device, 0x4188b4, gr->unk4188b4->addr >> 8); + nvkm_wr32(device, 0x4188b8, gr->unk4188b8->addr >> 8); + nvkm_mask(device, 0x4188b0, 0x00040000, 0x00040000); /*XXX: belongs in fb */ - nv_wr32(gr, 0x100cc8, gr->unk4188b4->addr >> 8); - nv_wr32(gr, 0x100ccc, gr->unk4188b8->addr >> 8); - nv_mask(gr, 0x100cc4, 0x00040000, 0x00040000); + nvkm_wr32(device, 0x100cc8, gr->unk4188b4->addr >> 8); + nvkm_wr32(device, 0x100ccc, gr->unk4188b8->addr >> 8); + nvkm_mask(device, 0x100cc4, 0x00040000, 0x00040000); gf100_gr_mmio(gr, oclass->mmio); gm107_gr_init_bios(gr); - nv_wr32(gr, GPC_UNIT(0, 0x3018), 0x00000001); + nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); memset(data, 0x00, sizeof(data)); memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); @@ -294,76 +295,76 @@ gm204_gr_init(struct nvkm_object *object) data[i / 8] |= tpc << ((i % 8) * 4); } - nv_wr32(gr, GPC_BCAST(0x0980), data[0]); - nv_wr32(gr, GPC_BCAST(0x0984), data[1]); - nv_wr32(gr, GPC_BCAST(0x0988), data[2]); - nv_wr32(gr, GPC_BCAST(0x098c), data[3]); + nvkm_wr32(device, GPC_BCAST(0x0980), data[0]); + nvkm_wr32(device, GPC_BCAST(0x0984), data[1]); + nvkm_wr32(device, GPC_BCAST(0x0988), data[2]); + nvkm_wr32(device, GPC_BCAST(0x098c), data[3]); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { - nv_wr32(gr, GPC_UNIT(gpc, 0x0914), + nvkm_wr32(device, GPC_UNIT(gpc, 0x0914), gr->magic_not_rop_nr << 8 | gr->tpc_nr[gpc]); - nv_wr32(gr, GPC_UNIT(gpc, 0x0910), 0x00040000 | + nvkm_wr32(device, GPC_UNIT(gpc, 0x0910), 0x00040000 | gr->tpc_total); - nv_wr32(gr, GPC_UNIT(gpc, 0x0918), magicgpc918); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - nv_wr32(gr, GPC_BCAST(0x3fd4), magicgpc918); - nv_wr32(gr, GPC_BCAST(0x08ac), nv_rd32(gr, 0x100800)); - nv_wr32(gr, GPC_BCAST(0x033c), nv_rd32(gr, 0x100804)); - - nv_wr32(gr, 0x400500, 0x00010001); - nv_wr32(gr, 0x400100, 0xffffffff); - nv_wr32(gr, 0x40013c, 0xffffffff); - nv_wr32(gr, 0x400124, 0x00000002); - nv_wr32(gr, 0x409c24, 0x000e0000); - nv_wr32(gr, 0x405848, 0xc0000000); - nv_wr32(gr, 0x40584c, 0x00000001); - nv_wr32(gr, 0x404000, 0xc0000000); - nv_wr32(gr, 0x404600, 0xc0000000); - nv_wr32(gr, 0x408030, 0xc0000000); - nv_wr32(gr, 0x404490, 0xc0000000); - nv_wr32(gr, 0x406018, 0xc0000000); - nv_wr32(gr, 0x407020, 0x40000000); - nv_wr32(gr, 0x405840, 0xc0000000); - nv_wr32(gr, 0x405844, 0x00ffffff); - nv_mask(gr, 0x419cc0, 0x00000008, 0x00000008); + nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); + nvkm_wr32(device, GPC_BCAST(0x08ac), nvkm_rd32(device, 0x100800)); + nvkm_wr32(device, GPC_BCAST(0x033c), nvkm_rd32(device, 0x100804)); + + nvkm_wr32(device, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400124, 0x00000002); + nvkm_wr32(device, 0x409c24, 0x000e0000); + nvkm_wr32(device, 0x405848, 0xc0000000); + nvkm_wr32(device, 0x40584c, 0x00000001); + nvkm_wr32(device, 0x404000, 0xc0000000); + nvkm_wr32(device, 0x404600, 0xc0000000); + nvkm_wr32(device, 0x408030, 0xc0000000); + nvkm_wr32(device, 0x404490, 0xc0000000); + nvkm_wr32(device, 0x406018, 0xc0000000); + nvkm_wr32(device, 0x407020, 0x40000000); + nvkm_wr32(device, 0x405840, 0xc0000000); + nvkm_wr32(device, 0x405844, 0x00ffffff); + nvkm_mask(device, 0x419cc0, 0x00000008, 0x00000008); for (gpc = 0; gpc < gr->gpc_nr; gpc++) { for (ppc = 0; ppc < gr->ppc_nr[gpc]; ppc++) - nv_wr32(gr, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0420), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0900), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x1028), 0xc0000000); - nv_wr32(gr, GPC_UNIT(gpc, 0x0824), 0xc0000000); + nvkm_wr32(device, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); + nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); for (tpc = 0; tpc < gr->tpc_nr[gpc]; tpc++) { - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); - nv_wr32(gr, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe); + nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005); } - nv_wr32(gr, GPC_UNIT(gpc, 0x2c90), 0xffffffff); - nv_wr32(gr, GPC_UNIT(gpc, 0x2c94), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c90), 0xffffffff); + nvkm_wr32(device, GPC_UNIT(gpc, 0x2c94), 0xffffffff); } for (rop = 0; rop < gr->rop_nr; rop++) { - nv_wr32(gr, ROP_UNIT(rop, 0x144), 0x40000000); - nv_wr32(gr, ROP_UNIT(rop, 0x070), 0x40000000); - nv_wr32(gr, ROP_UNIT(rop, 0x204), 0xffffffff); - nv_wr32(gr, ROP_UNIT(rop, 0x208), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0x40000000); + nvkm_wr32(device, ROP_UNIT(rop, 0x204), 0xffffffff); + nvkm_wr32(device, ROP_UNIT(rop, 0x208), 0xffffffff); } - nv_wr32(gr, 0x400108, 0xffffffff); - nv_wr32(gr, 0x400138, 0xffffffff); - nv_wr32(gr, 0x400118, 0xffffffff); - nv_wr32(gr, 0x400130, 0xffffffff); - nv_wr32(gr, 0x40011c, 0xffffffff); - nv_wr32(gr, 0x400134, 0xffffffff); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400118, 0xffffffff); + nvkm_wr32(device, 0x400130, 0xffffffff); + nvkm_wr32(device, 0x40011c, 0xffffffff); + nvkm_wr32(device, 0x400134, 0xffffffff); - nv_wr32(gr, 0x400054, 0x2c350f63); + nvkm_wr32(device, 0x400054, 0x2c350f63); gf100_gr_zbc_init(gr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c index 6b9c84f8f12de..719ebfb6e6404 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -37,32 +37,34 @@ gm20b_gr_sclass[] = { static void gm20b_gr_init_gpc_mmu(struct gf100_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; u32 val; /* TODO this needs to be removed once secure boot works */ if (1) { - nv_wr32(gr, 0x100ce4, 0xffffffff); + nvkm_wr32(device, 0x100ce4, 0xffffffff); } /* TODO update once secure boot works */ - val = nv_rd32(gr, 0x100c80); + val = nvkm_rd32(device, 0x100c80); val &= 0xf000087f; - nv_wr32(gr, 0x418880, val); - nv_wr32(gr, 0x418890, 0); - nv_wr32(gr, 0x418894, 0); + nvkm_wr32(device, 0x418880, val); + nvkm_wr32(device, 0x418890, 0); + nvkm_wr32(device, 0x418894, 0); - nv_wr32(gr, 0x4188b0, nv_rd32(gr, 0x100cc4)); - nv_wr32(gr, 0x4188b4, nv_rd32(gr, 0x100cc8)); - nv_wr32(gr, 0x4188b8, nv_rd32(gr, 0x100ccc)); + nvkm_wr32(device, 0x4188b0, nvkm_rd32(device, 0x100cc4)); + nvkm_wr32(device, 0x4188b4, nvkm_rd32(device, 0x100cc8)); + nvkm_wr32(device, 0x4188b8, nvkm_rd32(device, 0x100ccc)); - nv_wr32(gr, 0x4188ac, nv_rd32(gr, 0x100800)); + nvkm_wr32(device, 0x4188ac, nvkm_rd32(device, 0x100800)); } static void gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr) { - nv_wr32(gr, 0x419e44, 0xdffffe); - nv_wr32(gr, 0x419e4c, 0x5); + struct nvkm_device *device = gr->base.engine.subdev.device; + nvkm_wr32(device, 0x419e44, 0xdffffe); + nvkm_wr32(device, 0x419e4c, 0x5); } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index e161abe88fb8a..d1792ef62712c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -446,7 +446,8 @@ static void nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value) { struct nv04_gr *gr = (void *)object->engine; - int subc = (nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; + struct nvkm_device *device = gr->base.engine.subdev.device; + int subc = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; u32 tmp; tmp = nv_ro32(object, 0x00); @@ -454,8 +455,8 @@ nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value) tmp |= value; nv_wo32(object, 0x00, tmp); - nv_wr32(gr, NV04_PGRAPH_CTX_SWITCH1, tmp); - nv_wr32(gr, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); + nvkm_wr32(device, NV04_PGRAPH_CTX_SWITCH1, tmp); + nvkm_wr32(device, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); } static void @@ -528,6 +529,7 @@ nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nv04_gr *gr = (void *)object->engine; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; @@ -539,8 +541,8 @@ nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(gr, 0x40053c, min); - nv_wr32(gr, 0x400544, max); + nvkm_wr32(device, 0x40053c, min); + nvkm_wr32(device, 0x400544, max); return 0; } @@ -549,6 +551,7 @@ nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nv04_gr *gr = (void *)object->engine; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; @@ -560,8 +563,8 @@ nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, w |= 0xffff0000; max = min + w; max &= 0x3ffff; - nv_wr32(gr, 0x400540, min); - nv_wr32(gr, 0x400548, max); + nvkm_wr32(device, 0x400540, min); + nvkm_wr32(device, 0x400548, max); return 0; } @@ -1033,9 +1036,10 @@ nv04_gr_sclass[] = { static struct nv04_gr_chan * nv04_gr_channel(struct nv04_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv04_gr_chan *chan = NULL; - if (nv_rd32(gr, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { - int chid = nv_rd32(gr, NV04_PGRAPH_CTX_USER) >> 24; + if (nvkm_rd32(device, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) { + int chid = nvkm_rd32(device, NV04_PGRAPH_CTX_USER) >> 24; if (chid < ARRAY_SIZE(gr->chan)) chan = gr->chan[chid]; } @@ -1046,14 +1050,15 @@ static int nv04_gr_load_context(struct nv04_gr_chan *chan, int chid) { struct nv04_gr *gr = nv04_gr(chan); + struct nvkm_device *device = gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) - nv_wr32(gr, nv04_gr_ctx_regs[i], chan->nv04[i]); + nvkm_wr32(device, nv04_gr_ctx_regs[i], chan->nv04[i]); - nv_wr32(gr, NV04_PGRAPH_CTX_CONTROL, 0x10010100); - nv_mask(gr, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); - nv_mask(gr, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL, 0x10010100); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nvkm_mask(device, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000); return 0; } @@ -1061,19 +1066,21 @@ static int nv04_gr_unload_context(struct nv04_gr_chan *chan) { struct nv04_gr *gr = nv04_gr(chan); + struct nvkm_device *device = gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) - chan->nv04[i] = nv_rd32(gr, nv04_gr_ctx_regs[i]); + chan->nv04[i] = nvkm_rd32(device, nv04_gr_ctx_regs[i]); - nv_wr32(gr, NV04_PGRAPH_CTX_CONTROL, 0x10000000); - nv_mask(gr, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL, 0x10000000); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); return 0; } static void nv04_gr_context_switch(struct nv04_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv04_gr_chan *prev = NULL; struct nv04_gr_chan *next = NULL; unsigned long flags; @@ -1088,7 +1095,7 @@ nv04_gr_context_switch(struct nv04_gr *gr) nv04_gr_unload_context(prev); /* load context for next channel */ - chid = (nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; + chid = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f; next = gr->chan[chid]; if (next) nv04_gr_load_context(next, chid); @@ -1161,13 +1168,14 @@ nv04_gr_context_fini(struct nvkm_object *object, bool suspend) { struct nv04_gr *gr = (void *)object->engine; struct nv04_gr_chan *chan = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); - nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); if (nv04_gr_channel(gr) == chan) nv04_gr_unload_context(chan); - nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); return nvkm_object_fini(&chan->base, suspend); @@ -1192,6 +1200,7 @@ bool nv04_gr_idle(void *obj) { struct nvkm_gr *gr = nvkm_gr(obj); + struct nvkm_device *device = gr->engine.subdev.device; u32 mask = 0xffffffff; if (nv_device(obj)->card_type == NV_40) @@ -1199,7 +1208,7 @@ nv04_gr_idle(void *obj) if (!nv_wait(gr, NV04_PGRAPH_STATUS, mask, 0)) { nv_error(gr, "idle timed out with status 0x%08x\n", - nv_rd32(gr, NV04_PGRAPH_STATUS)); + nvkm_rd32(device, NV04_PGRAPH_STATUS)); return false; } @@ -1252,16 +1261,17 @@ nv04_gr_intr(struct nvkm_subdev *subdev) struct nv04_gr_chan *chan = NULL; struct nvkm_namedb *namedb = NULL; struct nvkm_handle *handle = NULL; - u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x0f000000) >> 24; u32 subc = (addr & 0x0000e000) >> 13; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(gr, 0x400180 + subc * 4) & 0xff; - u32 inst = (nv_rd32(gr, 0x40016c) & 0xffff) << 4; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400180 + subc * 4) & 0xff; + u32 inst = (nvkm_rd32(device, 0x40016c) & 0xffff) << 4; u32 show = stat; unsigned long flags; @@ -1280,14 +1290,14 @@ nv04_gr_intr(struct nvkm_subdev *subdev) } if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(gr, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + nvkm_wr32(device, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; nv04_gr_context_switch(gr); } - nv_wr32(gr, NV03_PGRAPH_INTR, stat); - nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { nv_error(gr, "%s", ""); @@ -1332,6 +1342,7 @@ nv04_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv04_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; int ret; ret = nvkm_gr_init(&gr->base); @@ -1339,33 +1350,33 @@ nv04_gr_init(struct nvkm_object *object) return ret; /* Enable PGRAPH interrupts */ - nv_wr32(gr, NV03_PGRAPH_INTR, 0xFFFFFFFF); - nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(gr, NV04_PGRAPH_VALID1, 0); - nv_wr32(gr, NV04_PGRAPH_VALID2, 0); - /*nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x000001FF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x1231c000); + nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nvkm_wr32(device, NV04_PGRAPH_VALID1, 0); + nvkm_wr32(device, NV04_PGRAPH_VALID2, 0); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000); /*1231C000 blob, 001 haiku*/ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ - nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x72111100); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100); /*0x72111100 blob , 01 haiku*/ - /*nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ - nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x11d5f071); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071); /*haiku same*/ - /*nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ - nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); /*haiku and blob 10d4*/ - nv_wr32(gr, NV04_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_CTX_CONTROL , 0x10000100); - nv_mask(gr, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + nvkm_wr32(device, NV04_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL , 0x10000100); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); /* These don't belong here, they're part of a per-channel context */ - nv_wr32(gr, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); - nv_wr32(gr, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index af33514456a4e..6b3ee956ced45 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -414,17 +414,17 @@ nv10_gr(struct nv10_gr_chan *chan) #define PIPE_SAVE(gr, state, addr) \ do { \ int __i; \ - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - state[__i] = nv_rd32(gr, NV10_PGRAPH_PIPE_DATA); \ + state[__i] = nvkm_rd32(device, NV10_PGRAPH_PIPE_DATA); \ } while (0) #define PIPE_RESTORE(gr, state, addr) \ do { \ int __i; \ - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, addr); \ + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, addr); \ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \ - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, state[__i]); \ + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, state[__i]); \ } while (0) static struct nvkm_oclass @@ -480,6 +480,7 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, struct nv10_gr_chan *chan = (void *)object->parent; struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe = &chan->pipe_state; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; u32 xfmode0, xfmode1; u32 data = *(u32 *)args; @@ -499,8 +500,8 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, nv04_gr_idle(gr); - xfmode0 = nv_rd32(gr, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(gr, NV10_PGRAPH_XFMODE1); + xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0); + xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1); PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400); PIPE_SAVE(gr, pipe_0x64c0, 0x64c0); @@ -509,24 +510,24 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, nv04_gr_idle(gr); - nv_wr32(gr, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(gr, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, 0x10000000); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008); PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); @@ -534,16 +535,16 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, PIPE_RESTORE(gr, pipe_0x0040, 0x0040); - nv_wr32(gr, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(gr, NV10_PGRAPH_XFMODE1, xfmode1); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1); PIPE_RESTORE(gr, pipe_0x64c0, 0x64c0); PIPE_RESTORE(gr, pipe_0x6ab0, 0x6ab0); PIPE_RESTORE(gr, pipe_0x6a80, 0x6a80); PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); nv04_gr_idle(gr); @@ -556,11 +557,12 @@ nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd, { struct nv10_gr_chan *chan = (void *)object->parent; struct nv10_gr *gr = nv10_gr(chan); + struct nvkm_device *device = gr->base.engine.subdev.device; nv04_gr_idle(gr); - nv_mask(gr, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); - nv_mask(gr, 0x4006b0, 0x08000000, 0x08000000); + nvkm_mask(device, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); + nvkm_mask(device, 0x4006b0, 0x08000000, 0x08000000); return 0; } @@ -604,9 +606,10 @@ nv17_gr_sclass[] = { static struct nv10_gr_chan * nv10_gr_channel(struct nv10_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv10_gr_chan *chan = NULL; - if (nv_rd32(gr, 0x400144) & 0x00010000) { - int chid = nv_rd32(gr, 0x400148) >> 24; + if (nvkm_rd32(device, 0x400144) & 0x00010000) { + int chid = nvkm_rd32(device, 0x400148) >> 24; if (chid < ARRAY_SIZE(gr->chan)) chan = gr->chan[chid]; } @@ -618,6 +621,7 @@ nv10_gr_save_pipe(struct nv10_gr_chan *chan) { struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe = &chan->pipe_state; + struct nvkm_device *device = gr->base.engine.subdev.device; PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400); PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200); @@ -636,39 +640,40 @@ nv10_gr_load_pipe(struct nv10_gr_chan *chan) { struct nv10_gr *gr = nv10_gr(chan); struct pipe_state *pipe = &chan->pipe_state; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 xfmode0, xfmode1; int i; nv04_gr_idle(gr); /* XXX check haiku comments */ - xfmode0 = nv_rd32(gr, NV10_PGRAPH_XFMODE0); - xfmode1 = nv_rd32(gr, NV10_PGRAPH_XFMODE1); - nv_wr32(gr, NV10_PGRAPH_XFMODE0, 0x10000000); - nv_wr32(gr, NV10_PGRAPH_XFMODE1, 0x00000000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); + xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0); + xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, 0x10000000); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0); for (i = 0; i < 4; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); for (i = 0; i < 4; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0); for (i = 0; i < 3; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x3f800000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x3f800000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80); for (i = 0; i < 3; i++) - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); - nv_wr32(gr, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); - nv_wr32(gr, NV10_PGRAPH_PIPE_DATA, 0x00000008); + nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); + nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008); PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); nv04_gr_idle(gr); /* restore XFMODE */ - nv_wr32(gr, NV10_PGRAPH_XFMODE0, xfmode0); - nv_wr32(gr, NV10_PGRAPH_XFMODE1, xfmode1); + nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0); + nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1); PIPE_RESTORE(gr, pipe->pipe_0x6400, 0x6400); PIPE_RESTORE(gr, pipe->pipe_0x6800, 0x6800); PIPE_RESTORE(gr, pipe->pipe_0x6c00, 0x6c00); @@ -864,6 +869,7 @@ static void nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) { struct nv10_gr *gr = nv10_gr(chan); + struct nvkm_device *device = gr->base.engine.subdev.device; u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; u32 ctx_user, ctx_switch[5]; int i, subchan = -1; @@ -875,7 +881,7 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) /* Look for a celsius object */ for (i = 0; i < 8; i++) { - int class = nv_rd32(gr, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; + int class = nvkm_rd32(device, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff; if (class == 0x56 || class == 0x96 || class == 0x99) { subchan = i; @@ -887,73 +893,74 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) return; /* Save the current ctx object */ - ctx_user = nv_rd32(gr, NV10_PGRAPH_CTX_USER); + ctx_user = nvkm_rd32(device, NV10_PGRAPH_CTX_USER); for (i = 0; i < 5; i++) - ctx_switch[i] = nv_rd32(gr, NV10_PGRAPH_CTX_SWITCH(i)); + ctx_switch[i] = nvkm_rd32(device, NV10_PGRAPH_CTX_SWITCH(i)); /* Save the FIFO state */ - st2 = nv_rd32(gr, NV10_PGRAPH_FFINTFC_ST2); - st2_dl = nv_rd32(gr, NV10_PGRAPH_FFINTFC_ST2_DL); - st2_dh = nv_rd32(gr, NV10_PGRAPH_FFINTFC_ST2_DH); - fifo_ptr = nv_rd32(gr, NV10_PGRAPH_FFINTFC_FIFO_PTR); + st2 = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2); + st2_dl = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2_DL); + st2_dh = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_ST2_DH); + fifo_ptr = nvkm_rd32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR); for (i = 0; i < ARRAY_SIZE(fifo); i++) - fifo[i] = nv_rd32(gr, 0x4007a0 + 4 * i); + fifo[i] = nvkm_rd32(device, 0x4007a0 + 4 * i); /* Switch to the celsius subchannel */ for (i = 0; i < 5; i++) - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(i), - nv_rd32(gr, NV10_PGRAPH_CTX_CACHE(subchan, i))); - nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(i), + nvkm_rd32(device, NV10_PGRAPH_CTX_CACHE(subchan, i))); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13); /* Inject NV10TCL_DMA_VTXBUF */ - nv_wr32(gr, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2, + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, 0x2c000000 | chid << 20 | subchan << 16 | 0x18c); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2_DL, inst); - nv_mask(gr, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); - nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DL, inst); + nvkm_mask(device, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); /* Restore the FIFO state */ for (i = 0; i < ARRAY_SIZE(fifo); i++) - nv_wr32(gr, 0x4007a0 + 4 * i, fifo[i]); + nvkm_wr32(device, 0x4007a0 + 4 * i, fifo[i]); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2, st2); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, st2); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh); /* Restore the current ctx object */ for (i = 0; i < 5; i++) - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); - nv_wr32(gr, NV10_PGRAPH_CTX_USER, ctx_user); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]); + nvkm_wr32(device, NV10_PGRAPH_CTX_USER, ctx_user); } static int nv10_gr_load_context(struct nv10_gr_chan *chan, int chid) { struct nv10_gr *gr = nv10_gr(chan); + struct nvkm_device *device = gr->base.engine.subdev.device; u32 inst; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) - nv_wr32(gr, nv10_gr_ctx_regs[i], chan->nv10[i]); + nvkm_wr32(device, nv10_gr_ctx_regs[i], chan->nv10[i]); if (nv_device(gr)->card_type >= NV_11 && nv_device(gr)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) - nv_wr32(gr, nv17_gr_ctx_regs[i], chan->nv17[i]); + nvkm_wr32(device, nv17_gr_ctx_regs[i], chan->nv17[i]); } nv10_gr_load_pipe(chan); - inst = nv_rd32(gr, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; + inst = nvkm_rd32(device, NV10_PGRAPH_GLOBALSTATE1) & 0xffff; nv10_gr_load_dma_vtxbuf(chan, chid, inst); - nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); - nv_mask(gr, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24); + nvkm_mask(device, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000); return 0; } @@ -961,27 +968,29 @@ static int nv10_gr_unload_context(struct nv10_gr_chan *chan) { struct nv10_gr *gr = nv10_gr(chan); + struct nvkm_device *device = gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) - chan->nv10[i] = nv_rd32(gr, nv10_gr_ctx_regs[i]); + chan->nv10[i] = nvkm_rd32(device, nv10_gr_ctx_regs[i]); if (nv_device(gr)->card_type >= NV_11 && nv_device(gr)->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) - chan->nv17[i] = nv_rd32(gr, nv17_gr_ctx_regs[i]); + chan->nv17[i] = nvkm_rd32(device, nv17_gr_ctx_regs[i]); } nv10_gr_save_pipe(chan); - nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000000); - nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000000); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); return 0; } static void nv10_gr_context_switch(struct nv10_gr *gr) { + struct nvkm_device *device = gr->base.engine.subdev.device; struct nv10_gr_chan *prev = NULL; struct nv10_gr_chan *next = NULL; unsigned long flags; @@ -996,7 +1005,7 @@ nv10_gr_context_switch(struct nv10_gr *gr) nv10_gr_unload_context(prev); /* load context for next channel */ - chid = (nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; + chid = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f; next = gr->chan[chid]; if (next) nv10_gr_load_context(next, chid); @@ -1024,6 +1033,7 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_fifo_chan *fifo = (void *)parent; struct nv10_gr *gr = (void *)engine; struct nv10_gr_chan *chan; + struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; int ret; @@ -1052,8 +1062,8 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_device(gr)->chipset >= 0x17) { /* is it really needed ??? */ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, - nv_rd32(gr, NV10_PGRAPH_DEBUG_4)); - NV17_WRITE_CTX(0x004006b0, nv_rd32(gr, 0x004006b0)); + nvkm_rd32(device, NV10_PGRAPH_DEBUG_4)); + NV17_WRITE_CTX(0x004006b0, nvkm_rd32(device, 0x004006b0)); NV17_WRITE_CTX(0x00400eac, 0x0fff0000); NV17_WRITE_CTX(0x00400eb0, 0x0fff0000); NV17_WRITE_CTX(0x00400ec0, 0x00000080); @@ -1088,13 +1098,14 @@ nv10_gr_context_fini(struct nvkm_object *object, bool suspend) { struct nv10_gr *gr = (void *)object->engine; struct nv10_gr_chan *chan = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); - nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); if (nv10_gr_channel(gr) == chan) nv10_gr_unload_context(chan); - nv_mask(gr, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); return nvkm_object_fini(&chan->base, suspend); @@ -1118,17 +1129,18 @@ nv10_gr_cclass = { static void nv10_gr_tile_prog(struct nvkm_engine *engine, int i) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *fifo = nvkm_fifo(engine); struct nv10_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; fifo->pause(fifo, &flags); nv04_gr_idle(gr); - nv_wr32(gr, NV10_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(gr, NV10_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(gr, NV10_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV10_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV10_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV10_PGRAPH_TILE(i), tile->addr); fifo->start(fifo, &flags); } @@ -1154,15 +1166,16 @@ nv10_gr_intr(struct nvkm_subdev *subdev) struct nv10_gr_chan *chan = NULL; struct nvkm_namedb *namedb = NULL; struct nvkm_handle *handle = NULL; - u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x01f00000) >> 20; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(gr, 0x400160 + subc * 4) & 0xfff; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; unsigned long flags; @@ -1181,14 +1194,14 @@ nv10_gr_intr(struct nvkm_subdev *subdev) } if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) { - nv_wr32(gr, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); + nvkm_wr32(device, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH); stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH; nv10_gr_context_switch(gr); } - nv_wr32(gr, NV03_PGRAPH_INTR, stat); - nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { nv_error(gr, "%s", ""); @@ -1249,49 +1262,50 @@ static int nv10_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nvkm_fb *fb = nvkm_fb(object); struct nv10_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; int ret, i; ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x00118700); - /* nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ - nv_wr32(gr, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); - nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x00118700); + /* nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); if (nv_device(gr)->card_type >= NV_11 && nv_device(gr)->chipset >= 0x17) { - nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x1f000000); - nv_wr32(gr, 0x400a10, 0x03ff3fb6); - nv_wr32(gr, 0x400838, 0x002f8684); - nv_wr32(gr, 0x40083c, 0x00115f3f); - nv_wr32(gr, 0x4006b0, 0x40000020); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x1f000000); + nvkm_wr32(device, 0x400a10, 0x03ff3fb6); + nvkm_wr32(device, 0x400838, 0x002f8684); + nvkm_wr32(device, 0x40083c, 0x00115f3f); + nvkm_wr32(device, 0x4006b0, 0x40000020); } else { - nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000); } /* Turn all the tiling regions off. */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); - nv_wr32(gr, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); - nv_wr32(gr, NV10_PGRAPH_STATE, 0xFFFFFFFF); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_STATE, 0xFFFFFFFF); - nv_mask(gr, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); - nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(gr, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); + nvkm_mask(device, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nvkm_wr32(device, NV10_PGRAPH_FFINTFC_ST2, 0x08000000); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 3e5428552cb2a..8e264f79c0df9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -118,19 +118,20 @@ nv20_gr_context_fini(struct nvkm_object *object, bool suspend) { struct nv20_gr *gr = (void *)object->engine; struct nv20_gr_chan *chan = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; int chid = -1; - nv_mask(gr, 0x400720, 0x00000001, 0x00000000); - if (nv_rd32(gr, 0x400144) & 0x00010000) - chid = (nv_rd32(gr, 0x400148) & 0x1f000000) >> 24; + nvkm_mask(device, 0x400720, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x400144) & 0x00010000) + chid = (nvkm_rd32(device, 0x400148) & 0x1f000000) >> 24; if (chan->chid == chid) { - nv_wr32(gr, 0x400784, nv_gpuobj(chan)->addr >> 4); - nv_wr32(gr, 0x400788, 0x00000002); + nvkm_wr32(device, 0x400784, nv_gpuobj(chan)->addr >> 4); + nvkm_wr32(device, 0x400788, 0x00000002); nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); - nv_wr32(gr, 0x400144, 0x10000000); - nv_mask(gr, 0x400148, 0xff000000, 0x1f000000); + nvkm_wr32(device, 0x400144, 0x10000000); + nvkm_mask(device, 0x400148, 0xff000000, 0x1f000000); } - nv_mask(gr, 0x400720, 0x00000001, 0x00000001); + nvkm_mask(device, 0x400720, 0x00000001, 0x00000001); nv_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); return nvkm_gr_context_fini(&chan->base, suspend); @@ -156,29 +157,30 @@ nv20_gr_cclass = { void nv20_gr_tile_prog(struct nvkm_engine *engine, int i) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *fifo = nvkm_fifo(engine); struct nv20_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; fifo->pause(fifo, &flags); nv04_gr_idle(gr); - nv_wr32(gr, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(gr, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(gr, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->limit); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->pitch); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->addr); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->limit); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->pitch); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->addr); if (nv_device(engine)->chipset != 0x34) { - nv_wr32(gr, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, tile->zcomp); + nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->zcomp); } fifo->start(fifo, &flags); @@ -191,15 +193,16 @@ nv20_gr_intr(struct nvkm_subdev *subdev) struct nvkm_object *engctx; struct nvkm_handle *handle; struct nv20_gr *gr = (void *)subdev; - u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); - u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 chid = (addr & 0x01f00000) >> 20; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(gr, 0x400160 + subc * 4) & 0xfff; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; engctx = nvkm_engctx_get(engine, chid); @@ -212,8 +215,8 @@ nv20_gr_intr(struct nvkm_subdev *subdev) } } - nv_wr32(gr, NV03_PGRAPH_INTR, stat); - nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { nv_error(gr, "%s", ""); @@ -271,7 +274,8 @@ nv20_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv20_gr *gr = (void *)engine; - struct nvkm_fb *fb = nvkm_fb(object); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; u32 tmp, vramsz; int ret, i; @@ -279,87 +283,87 @@ nv20_gr_init(struct nvkm_object *object) if (ret) return ret; - nv_wr32(gr, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); + nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); if (nv_device(gr)->chipset == 0x20) { - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x003d0000); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x003d0000); for (i = 0; i < 15; i++) - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); } else { - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x02c80000); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x02c80000); for (i = 0; i < 32; i++) - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, 0x00000000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); } - nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x00118700); - nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ - nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00000000); - nv_wr32(gr, 0x40009C , 0x00000040); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x00118700); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */ + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000); + nvkm_wr32(device, 0x40009C , 0x00000040); if (nv_device(gr)->chipset >= 0x25) { - nv_wr32(gr, 0x400890, 0x00a8cfff); - nv_wr32(gr, 0x400610, 0x304B1FB6); - nv_wr32(gr, 0x400B80, 0x1cbd3883); - nv_wr32(gr, 0x400B84, 0x44000000); - nv_wr32(gr, 0x400098, 0x40000080); - nv_wr32(gr, 0x400B88, 0x000000ff); + nvkm_wr32(device, 0x400890, 0x00a8cfff); + nvkm_wr32(device, 0x400610, 0x304B1FB6); + nvkm_wr32(device, 0x400B80, 0x1cbd3883); + nvkm_wr32(device, 0x400B84, 0x44000000); + nvkm_wr32(device, 0x400098, 0x40000080); + nvkm_wr32(device, 0x400B88, 0x000000ff); } else { - nv_wr32(gr, 0x400880, 0x0008c7df); - nv_wr32(gr, 0x400094, 0x00000005); - nv_wr32(gr, 0x400B80, 0x45eae20e); - nv_wr32(gr, 0x400B84, 0x24000000); - nv_wr32(gr, 0x400098, 0x00000040); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00E00038); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000030); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00E10038); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000030); + nvkm_wr32(device, 0x400880, 0x0008c7df); + nvkm_wr32(device, 0x400094, 0x00000005); + nvkm_wr32(device, 0x400B80, 0x45eae20e); + nvkm_wr32(device, 0x400B84, 0x24000000); + nvkm_wr32(device, 0x400098, 0x00000040); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00E00038); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000030); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00E10038); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000030); } /* Turn all the tiling regions off. */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); - nv_wr32(gr, 0x4009a0, nv_rd32(gr, 0x100324)); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA, nv_rd32(gr, 0x100324)); + nvkm_wr32(device, 0x4009a0, nvkm_rd32(device, 0x100324)); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, nvkm_rd32(device, 0x100324)); - nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(gr, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); - tmp = nv_rd32(gr, NV10_PGRAPH_SURFACE) & 0x0007ff00; - nv_wr32(gr, NV10_PGRAPH_SURFACE, tmp); - tmp = nv_rd32(gr, NV10_PGRAPH_SURFACE) | 0x00020100; - nv_wr32(gr, NV10_PGRAPH_SURFACE, tmp); + tmp = nvkm_rd32(device, NV10_PGRAPH_SURFACE) & 0x0007ff00; + nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp); + tmp = nvkm_rd32(device, NV10_PGRAPH_SURFACE) | 0x00020100; + nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ vramsz = nv_device_resource_len(nv_device(gr), 1) - 1; - nv_wr32(gr, 0x4009A4, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x4009A8, nv_rd32(gr, 0x100204)); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , nv_rd32(gr, 0x100200)); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , nv_rd32(gr, 0x100204)); - nv_wr32(gr, 0x400820, 0); - nv_wr32(gr, 0x400824, 0); - nv_wr32(gr, 0x400864, vramsz - 1); - nv_wr32(gr, 0x400868, vramsz - 1); + nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x400820, 0); + nvkm_wr32(device, 0x400824, 0); + nvkm_wr32(device, 0x400864, vramsz - 1); + nvkm_wr32(device, 0x400868, vramsz - 1); /* interesting.. the below overwrites some of the tile setup above.. */ - nv_wr32(gr, 0x400B20, 0x00000000); - nv_wr32(gr, 0x400B04, 0xFFFFFFFF); + nvkm_wr32(device, 0x400B20, 0x00000000); + nvkm_wr32(device, 0x400B04, 0xFFFFFFFF); - nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); - nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); - nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); - nv_wr32(gr, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_XMIN, 0); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_YMIN, 0); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff); + nvkm_wr32(device, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index dea1cb907318b..8be77b4f15ad6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -153,67 +153,68 @@ nv30_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv20_gr *gr = (void *)engine; - struct nvkm_fb *fb = nvkm_fb(object); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; int ret, i; ret = nvkm_gr_init(&gr->base); if (ret) return ret; - nv_wr32(gr, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); - - nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(gr, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(gr, 0x400890, 0x01b463ff); - nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xf2de0475); - nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(gr, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); - nv_wr32(gr, 0x400B80, 0x1003d888); - nv_wr32(gr, 0x400B84, 0x0c000000); - nv_wr32(gr, 0x400098, 0x00000000); - nv_wr32(gr, 0x40009C, 0x0005ad00); - nv_wr32(gr, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ - nv_wr32(gr, 0x4000a0, 0x00000000); - nv_wr32(gr, 0x4000a4, 0x00000008); - nv_wr32(gr, 0x4008a8, 0xb784a400); - nv_wr32(gr, 0x400ba0, 0x002f8685); - nv_wr32(gr, 0x400ba4, 0x00231f3f); - nv_wr32(gr, 0x4008a4, 0x40000020); + nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); + + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nvkm_wr32(device, 0x400890, 0x01b463ff); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf2de0475); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00008000); + nvkm_wr32(device, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6); + nvkm_wr32(device, 0x400B80, 0x1003d888); + nvkm_wr32(device, 0x400B84, 0x0c000000); + nvkm_wr32(device, 0x400098, 0x00000000); + nvkm_wr32(device, 0x40009C, 0x0005ad00); + nvkm_wr32(device, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */ + nvkm_wr32(device, 0x4000a0, 0x00000000); + nvkm_wr32(device, 0x4000a4, 0x00000008); + nvkm_wr32(device, 0x4008a8, 0xb784a400); + nvkm_wr32(device, 0x400ba0, 0x002f8685); + nvkm_wr32(device, 0x400ba4, 0x00231f3f); + nvkm_wr32(device, 0x4008a4, 0x40000020); if (nv_device(gr)->chipset == 0x34) { - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00200201); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000008); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000032); - nv_wr32(gr, NV10_PGRAPH_RDI_INDEX, 0x00E00004); - nv_wr32(gr, NV10_PGRAPH_RDI_DATA , 0x00000002); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00200201); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000008); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000032); + nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00E00004); + nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000002); } - nv_wr32(gr, 0x4000c0, 0x00000016); + nvkm_wr32(device, 0x4000c0, 0x00000016); /* Turn all the tiling regions off. */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); - nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10000100); - nv_wr32(gr, NV10_PGRAPH_STATE , 0xFFFFFFFF); - nv_wr32(gr, 0x0040075c , 0x00000001); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); + nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, 0x0040075c , 0x00000001); /* begin RAM config */ /* vramsz = pci_resource_len(gr->dev->pdev, 1) - 1; */ - nv_wr32(gr, 0x4009A4, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x4009A8, nv_rd32(gr, 0x100204)); + nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); if (nv_device(gr)->chipset != 0x34) { - nv_wr32(gr, 0x400750, 0x00EA0000); - nv_wr32(gr, 0x400754, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x400750, 0x00EA0004); - nv_wr32(gr, 0x400754, nv_rd32(gr, 0x100204)); + nvkm_wr32(device, 0x400750, 0x00EA0000); + nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x400750, 0x00EA0004); + nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100204)); } return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 3c2df9d29ff34..edcaa65b1e092 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -42,7 +42,7 @@ struct nv40_gr_chan { static u64 nv40_gr_units(struct nvkm_gr *gr) { - return nv_rd32(gr, 0x1540); + return nvkm_rd32(gr->engine.subdev.device, 0x1540); } /******************************************************************************* @@ -155,31 +155,32 @@ nv40_gr_context_fini(struct nvkm_object *object, bool suspend) { struct nv40_gr *gr = (void *)object->engine; struct nv40_gr_chan *chan = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; int ret = 0; - nv_mask(gr, 0x400720, 0x00000001, 0x00000000); + nvkm_mask(device, 0x400720, 0x00000001, 0x00000000); - if (nv_rd32(gr, 0x40032c) == inst) { + if (nvkm_rd32(device, 0x40032c) == inst) { if (suspend) { - nv_wr32(gr, 0x400720, 0x00000000); - nv_wr32(gr, 0x400784, inst); - nv_mask(gr, 0x400310, 0x00000020, 0x00000020); - nv_mask(gr, 0x400304, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x400720, 0x00000000); + nvkm_wr32(device, 0x400784, inst); + nvkm_mask(device, 0x400310, 0x00000020, 0x00000020); + nvkm_mask(device, 0x400304, 0x00000001, 0x00000001); if (!nv_wait(gr, 0x400300, 0x00000001, 0x00000000)) { - u32 insn = nv_rd32(gr, 0x400308); + u32 insn = nvkm_rd32(device, 0x400308); nv_warn(gr, "ctxprog timeout 0x%08x\n", insn); ret = -EBUSY; } } - nv_mask(gr, 0x40032c, 0x01000000, 0x00000000); + nvkm_mask(device, 0x40032c, 0x01000000, 0x00000000); } - if (nv_rd32(gr, 0x400330) == inst) - nv_mask(gr, 0x400330, 0x01000000, 0x00000000); + if (nvkm_rd32(device, 0x400330) == inst) + nvkm_mask(device, 0x400330, 0x01000000, 0x00000000); - nv_mask(gr, 0x400720, 0x00000001, 0x00000001); + nvkm_mask(device, 0x400720, 0x00000001, 0x00000001); return ret; } @@ -203,9 +204,10 @@ nv40_gr_cclass = { static void nv40_gr_tile_prog(struct nvkm_engine *engine, int i) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; - struct nvkm_fifo *fifo = nvkm_fifo(engine); struct nv40_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; fifo->pause(fifo, &flags); @@ -218,23 +220,23 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) case 0x43: case 0x45: case 0x4e: - nv_wr32(gr, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(gr, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(gr, NV20_PGRAPH_TILE(i), tile->addr); - nv_wr32(gr, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(gr, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(gr, NV40_PGRAPH_TILE1(i), tile->addr); + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); switch (nv_device(gr)->chipset) { case 0x40: case 0x45: - nv_wr32(gr, NV20_PGRAPH_ZCOMP(i), tile->zcomp); - nv_wr32(gr, NV40_PGRAPH_ZCOMP1(i), tile->zcomp); + nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp); + nvkm_wr32(device, NV40_PGRAPH_ZCOMP1(i), tile->zcomp); break; case 0x41: case 0x42: case 0x43: - nv_wr32(gr, NV41_PGRAPH_ZCOMP0(i), tile->zcomp); - nv_wr32(gr, NV41_PGRAPH_ZCOMP1(i), tile->zcomp); + nvkm_wr32(device, NV41_PGRAPH_ZCOMP0(i), tile->zcomp); + nvkm_wr32(device, NV41_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: break; @@ -242,9 +244,9 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) break; case 0x44: case 0x4a: - nv_wr32(gr, NV20_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(gr, NV20_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(gr, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); break; case 0x46: case 0x4c: @@ -254,18 +256,18 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) case 0x63: case 0x67: case 0x68: - nv_wr32(gr, NV47_PGRAPH_TSIZE(i), tile->pitch); - nv_wr32(gr, NV47_PGRAPH_TLIMIT(i), tile->limit); - nv_wr32(gr, NV47_PGRAPH_TILE(i), tile->addr); - nv_wr32(gr, NV40_PGRAPH_TSIZE1(i), tile->pitch); - nv_wr32(gr, NV40_PGRAPH_TLIMIT1(i), tile->limit); - nv_wr32(gr, NV40_PGRAPH_TILE1(i), tile->addr); + nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); switch (nv_device(gr)->chipset) { case 0x47: case 0x49: case 0x4b: - nv_wr32(gr, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); - nv_wr32(gr, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); + nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); + nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: break; @@ -286,15 +288,16 @@ nv40_gr_intr(struct nvkm_subdev *subdev) struct nvkm_object *engctx; struct nvkm_handle *handle = NULL; struct nv40_gr *gr = (void *)subdev; - u32 stat = nv_rd32(gr, NV03_PGRAPH_INTR); - u32 nsource = nv_rd32(gr, NV03_PGRAPH_NSOURCE); - u32 nstatus = nv_rd32(gr, NV03_PGRAPH_NSTATUS); - u32 inst = nv_rd32(gr, 0x40032c) & 0x000fffff; - u32 addr = nv_rd32(gr, NV04_PGRAPH_TRAPPED_ADDR); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); + u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); + u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); + u32 inst = nvkm_rd32(device, 0x40032c) & 0x000fffff; + u32 addr = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(gr, NV04_PGRAPH_TRAPPED_DATA); - u32 class = nv_rd32(gr, 0x400160 + subc * 4) & 0xffff; + u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); + u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xffff; u32 show = stat; int chid; @@ -310,12 +313,12 @@ nv40_gr_intr(struct nvkm_subdev *subdev) } if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { - nv_mask(gr, 0x402000, 0, 0); + nvkm_mask(device, 0x402000, 0, 0); } } - nv_wr32(gr, NV03_PGRAPH_INTR, stat); - nv_wr32(gr, NV04_PGRAPH_FIFO, 0x00000001); + nvkm_wr32(device, NV03_PGRAPH_INTR, stat); + nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { nv_error(gr, "%s", ""); @@ -364,8 +367,9 @@ static int nv40_gr_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); - struct nvkm_fb *fb = nvkm_fb(object); struct nv40_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; int ret, i, j; u32 vramsz; @@ -379,89 +383,89 @@ nv40_gr_init(struct nvkm_object *object) return ret; /* No context present currently */ - nv_wr32(gr, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); + nvkm_wr32(device, NV40_PGRAPH_CTXCTL_CUR, 0x00000000); - nv_wr32(gr, NV03_PGRAPH_INTR , 0xFFFFFFFF); - nv_wr32(gr, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); + nvkm_wr32(device, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); - nv_wr32(gr, NV04_PGRAPH_DEBUG_0, 0x00000000); - nv_wr32(gr, NV04_PGRAPH_DEBUG_1, 0x401287c0); - nv_wr32(gr, NV04_PGRAPH_DEBUG_3, 0xe0de8055); - nv_wr32(gr, NV10_PGRAPH_DEBUG_4, 0x00008000); - nv_wr32(gr, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x401287c0); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xe0de8055); + nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00008000); + nvkm_wr32(device, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f); - nv_wr32(gr, NV10_PGRAPH_CTX_CONTROL, 0x10010100); - nv_wr32(gr, NV10_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10010100); + nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); - j = nv_rd32(gr, 0x1540) & 0xff; + j = nvkm_rd32(device, 0x1540) & 0xff; if (j) { for (i = 0; !(j & 1); j >>= 1, i++) ; - nv_wr32(gr, 0x405000, i); + nvkm_wr32(device, 0x405000, i); } if (nv_device(gr)->chipset == 0x40) { - nv_wr32(gr, 0x4009b0, 0x83280fff); - nv_wr32(gr, 0x4009b4, 0x000000a0); + nvkm_wr32(device, 0x4009b0, 0x83280fff); + nvkm_wr32(device, 0x4009b4, 0x000000a0); } else { - nv_wr32(gr, 0x400820, 0x83280eff); - nv_wr32(gr, 0x400824, 0x000000a0); + nvkm_wr32(device, 0x400820, 0x83280eff); + nvkm_wr32(device, 0x400824, 0x000000a0); } switch (nv_device(gr)->chipset) { case 0x40: case 0x45: - nv_wr32(gr, 0x4009b8, 0x0078e366); - nv_wr32(gr, 0x4009bc, 0x0000014c); + nvkm_wr32(device, 0x4009b8, 0x0078e366); + nvkm_wr32(device, 0x4009bc, 0x0000014c); break; case 0x41: case 0x42: /* pciid also 0x00Cx */ /* case 0x0120: XXX (pciid) */ - nv_wr32(gr, 0x400828, 0x007596ff); - nv_wr32(gr, 0x40082c, 0x00000108); + nvkm_wr32(device, 0x400828, 0x007596ff); + nvkm_wr32(device, 0x40082c, 0x00000108); break; case 0x43: - nv_wr32(gr, 0x400828, 0x0072cb77); - nv_wr32(gr, 0x40082c, 0x00000108); + nvkm_wr32(device, 0x400828, 0x0072cb77); + nvkm_wr32(device, 0x40082c, 0x00000108); break; case 0x44: case 0x46: /* G72 */ case 0x4a: case 0x4c: /* G7x-based C51 */ case 0x4e: - nv_wr32(gr, 0x400860, 0); - nv_wr32(gr, 0x400864, 0); + nvkm_wr32(device, 0x400860, 0); + nvkm_wr32(device, 0x400864, 0); break; case 0x47: /* G70 */ case 0x49: /* G71 */ case 0x4b: /* G73 */ - nv_wr32(gr, 0x400828, 0x07830610); - nv_wr32(gr, 0x40082c, 0x0000016A); + nvkm_wr32(device, 0x400828, 0x07830610); + nvkm_wr32(device, 0x40082c, 0x0000016A); break; default: break; } - nv_wr32(gr, 0x400b38, 0x2ffff800); - nv_wr32(gr, 0x400b3c, 0x00006000); + nvkm_wr32(device, 0x400b38, 0x2ffff800); + nvkm_wr32(device, 0x400b3c, 0x00006000); /* Tiling related stuff. */ switch (nv_device(gr)->chipset) { case 0x44: case 0x4a: - nv_wr32(gr, 0x400bc4, 0x1003d888); - nv_wr32(gr, 0x400bbc, 0xb7a7b500); + nvkm_wr32(device, 0x400bc4, 0x1003d888); + nvkm_wr32(device, 0x400bbc, 0xb7a7b500); break; case 0x46: - nv_wr32(gr, 0x400bc4, 0x0000e024); - nv_wr32(gr, 0x400bbc, 0xb7a7b520); + nvkm_wr32(device, 0x400bc4, 0x0000e024); + nvkm_wr32(device, 0x400bbc, 0xb7a7b520); break; case 0x4c: case 0x4e: case 0x67: - nv_wr32(gr, 0x400bc4, 0x1003d888); - nv_wr32(gr, 0x400bbc, 0xb7a7b540); + nvkm_wr32(device, 0x400bc4, 0x1003d888); + nvkm_wr32(device, 0x400bbc, 0xb7a7b540); break; default: break; @@ -475,14 +479,14 @@ nv40_gr_init(struct nvkm_object *object) vramsz = nv_device_resource_len(nv_device(gr), 1) - 1; switch (nv_device(gr)->chipset) { case 0x40: - nv_wr32(gr, 0x4009A4, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x4009A8, nv_rd32(gr, 0x100204)); - nv_wr32(gr, 0x4069A4, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x4069A8, nv_rd32(gr, 0x100204)); - nv_wr32(gr, 0x400820, 0); - nv_wr32(gr, 0x400824, 0); - nv_wr32(gr, 0x400864, vramsz); - nv_wr32(gr, 0x400868, vramsz); + nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x4069A4, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4069A8, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x400820, 0); + nvkm_wr32(device, 0x400824, 0); + nvkm_wr32(device, 0x400864, vramsz); + nvkm_wr32(device, 0x400868, vramsz); break; default: switch (nv_device(gr)->chipset) { @@ -493,20 +497,20 @@ nv40_gr_init(struct nvkm_object *object) case 0x4e: case 0x44: case 0x4a: - nv_wr32(gr, 0x4009F0, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x4009F4, nv_rd32(gr, 0x100204)); + nvkm_wr32(device, 0x4009F0, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4009F4, nvkm_rd32(device, 0x100204)); break; default: - nv_wr32(gr, 0x400DF0, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x400DF4, nv_rd32(gr, 0x100204)); + nvkm_wr32(device, 0x400DF0, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x400DF4, nvkm_rd32(device, 0x100204)); break; } - nv_wr32(gr, 0x4069F0, nv_rd32(gr, 0x100200)); - nv_wr32(gr, 0x4069F4, nv_rd32(gr, 0x100204)); - nv_wr32(gr, 0x400840, 0); - nv_wr32(gr, 0x400844, 0); - nv_wr32(gr, 0x4008A0, vramsz); - nv_wr32(gr, 0x4008A4, vramsz); + nvkm_wr32(device, 0x4069F0, nvkm_rd32(device, 0x100200)); + nvkm_wr32(device, 0x4069F4, nvkm_rd32(device, 0x100204)); + nvkm_wr32(device, 0x400840, 0); + nvkm_wr32(device, 0x400844, 0); + nvkm_wr32(device, 0x4008A0, vramsz); + nvkm_wr32(device, 0x4008A4, vramsz); break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 70be675b19280..ade34d8a4ea04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -41,7 +41,7 @@ struct nv50_gr_chan { static u64 nv50_gr_units(struct nvkm_gr *gr) { - return nv_rd32(gr, 0x1540); + return nvkm_rd32(gr->engine.subdev.device, 0x1540); } /******************************************************************************* @@ -235,31 +235,32 @@ nvkm_gr_vstatus_print(struct nv50_gr *gr, int r, static int g84_gr_tlb_flush(struct nvkm_engine *engine) { - struct nvkm_timer *tmr = nvkm_timer(engine); struct nv50_gr *gr = (void *)engine; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_timer *tmr = device->timer; bool idle, timeout = false; unsigned long flags; u64 start; u32 tmp; spin_lock_irqsave(&gr->lock, flags); - nv_mask(gr, 0x400500, 0x00000001, 0x00000000); + nvkm_mask(device, 0x400500, 0x00000001, 0x00000000); start = tmr->read(tmr); do { idle = true; - for (tmp = nv_rd32(gr, 0x400380); tmp && idle; tmp >>= 3) { + for (tmp = nvkm_rd32(device, 0x400380); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - for (tmp = nv_rd32(gr, 0x400384); tmp && idle; tmp >>= 3) { + for (tmp = nvkm_rd32(device, 0x400384); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } - for (tmp = nv_rd32(gr, 0x400388); tmp && idle; tmp >>= 3) { + for (tmp = nvkm_rd32(device, 0x400388); tmp && idle; tmp >>= 3) { if ((tmp & 7) == 1) idle = false; } @@ -269,24 +270,24 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) if (timeout) { nv_error(gr, "PGRAPH TLB flush idle timeout fail\n"); - tmp = nv_rd32(gr, 0x400700); + tmp = nvkm_rd32(device, 0x400700); nv_error(gr, "PGRAPH_STATUS : 0x%08x", tmp); nvkm_bitfield_print(nv50_gr_status, tmp); pr_cont("\n"); nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0, - nv_rd32(gr, 0x400380)); + nvkm_rd32(device, 0x400380)); nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1, - nv_rd32(gr, 0x400384)); + nvkm_rd32(device, 0x400384)); nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2, - nv_rd32(gr, 0x400388)); + nvkm_rd32(device, 0x400388)); } - nv_wr32(gr, 0x100c80, 0x00000001); + nvkm_wr32(device, 0x100c80, 0x00000001); if (!nv_wait(gr, 0x100c80, 0x00000001, 0x00000000)) nv_error(gr, "vm flush timeout\n"); - nv_mask(gr, 0x400500, 0x00000001, 0x00000001); + nvkm_mask(device, 0x400500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); return timeout ? -EBUSY : 0; } @@ -427,13 +428,14 @@ static void nv50_gr_prop_trap(struct nv50_gr *gr, u32 ustatus_addr, u32 ustatus, u32 tp) { - u32 e0c = nv_rd32(gr, ustatus_addr + 0x04); - u32 e10 = nv_rd32(gr, ustatus_addr + 0x08); - u32 e14 = nv_rd32(gr, ustatus_addr + 0x0c); - u32 e18 = nv_rd32(gr, ustatus_addr + 0x10); - u32 e1c = nv_rd32(gr, ustatus_addr + 0x14); - u32 e20 = nv_rd32(gr, ustatus_addr + 0x18); - u32 e24 = nv_rd32(gr, ustatus_addr + 0x1c); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 e0c = nvkm_rd32(device, ustatus_addr + 0x04); + u32 e10 = nvkm_rd32(device, ustatus_addr + 0x08); + u32 e14 = nvkm_rd32(device, ustatus_addr + 0x0c); + u32 e18 = nvkm_rd32(device, ustatus_addr + 0x10); + u32 e1c = nvkm_rd32(device, ustatus_addr + 0x14); + u32 e20 = nvkm_rd32(device, ustatus_addr + 0x18); + u32 e24 = nvkm_rd32(device, ustatus_addr + 0x1c); /* CUDA memory: l[], g[] or stack. */ if (ustatus & 0x00000080) { @@ -465,7 +467,8 @@ nv50_gr_prop_trap(struct nv50_gr *gr, static void nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) { - u32 units = nv_rd32(gr, 0x1540); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 units = nvkm_rd32(device, 0x1540); u32 addr, mp10, status, pc, oplow, ophigh; int i; int mps = 0; @@ -476,15 +479,15 @@ nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) addr = 0x408200 + (tpid << 12) + (i << 7); else addr = 0x408100 + (tpid << 11) + (i << 7); - mp10 = nv_rd32(gr, addr + 0x10); - status = nv_rd32(gr, addr + 0x14); + mp10 = nvkm_rd32(device, addr + 0x10); + status = nvkm_rd32(device, addr + 0x14); if (!status) continue; if (display) { - nv_rd32(gr, addr + 0x20); - pc = nv_rd32(gr, addr + 0x24); - oplow = nv_rd32(gr, addr + 0x70); - ophigh = nv_rd32(gr, addr + 0x74); + nvkm_rd32(device, addr + 0x20); + pc = nvkm_rd32(device, addr + 0x24); + oplow = nvkm_rd32(device, addr + 0x70); + ophigh = nvkm_rd32(device, addr + 0x74); nv_error(gr, "TRAP_MP_EXEC - " "TP %d MP %d:", tpid, i); nvkm_bitfield_print(nv50_mp_exec_errors, status); @@ -492,8 +495,8 @@ nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) pc&0xffffff, pc >> 24, oplow, ophigh); } - nv_wr32(gr, addr + 0x10, mp10); - nv_wr32(gr, addr + 0x14, 0); + nvkm_wr32(device, addr + 0x10, mp10); + nvkm_wr32(device, addr + 0x14, 0); mps++; } if (!mps && display) @@ -505,8 +508,9 @@ static void nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, u32 ustatus_new, int display, const char *name) { + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 units = nvkm_rd32(device, 0x1540); int tps = 0; - u32 units = nv_rd32(gr, 0x1540); int i, r; u32 ustatus_addr, ustatus; for (i = 0; i < 16; i++) { @@ -516,7 +520,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, ustatus_addr = ustatus_old + (i << 12); else ustatus_addr = ustatus_new + (i << 11); - ustatus = nv_rd32(gr, ustatus_addr) & 0x7fffffff; + ustatus = nvkm_rd32(device, ustatus_addr) & 0x7fffffff; if (!ustatus) continue; tps++; @@ -526,7 +530,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, nv_error(gr, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) nv_error(gr, "\t0x%08x: 0x%08x\n", r, - nv_rd32(gr, r)); + nvkm_rd32(device, r)); if (ustatus) { nv_error(gr, "%s - TP%d:", name, i); nvkm_bitfield_print(nv50_tex_traps, @@ -559,7 +563,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, if (display) nv_error(gr, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); } - nv_wr32(gr, ustatus_addr, 0xc0000000); + nvkm_wr32(device, ustatus_addr, 0xc0000000); } if (!tps && display) @@ -570,7 +574,8 @@ static int nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, int chid, u64 inst, struct nvkm_object *engctx) { - u32 status = nv_rd32(gr, 0x400108); + struct nvkm_device *device = gr->base.engine.subdev.device; + u32 status = nvkm_rd32(device, 0x400108); u32 ustatus; if (!status && display) { @@ -582,22 +587,22 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, * COND, QUERY. If you get a trap from it, the command is still stuck * in DISPATCH and you need to do something about it. */ if (status & 0x001) { - ustatus = nv_rd32(gr, 0x400804) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x400804) & 0x7fffffff; if (!ustatus && display) { nv_error(gr, "TRAP_DISPATCH - no ustatus?\n"); } - nv_wr32(gr, 0x400500, 0x00000000); + nvkm_wr32(device, 0x400500, 0x00000000); /* Known to be triggered by screwed up NOTIFY and COND... */ if (ustatus & 0x00000001) { - u32 addr = nv_rd32(gr, 0x400808); + u32 addr = nvkm_rd32(device, 0x400808); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 datal = nv_rd32(gr, 0x40080c); - u32 datah = nv_rd32(gr, 0x400810); - u32 class = nv_rd32(gr, 0x400814); - u32 r848 = nv_rd32(gr, 0x400848); + u32 datal = nvkm_rd32(device, 0x40080c); + u32 datah = nvkm_rd32(device, 0x400810); + u32 class = nvkm_rd32(device, 0x400814); + u32 r848 = nvkm_rd32(device, 0x400848); nv_error(gr, "TRAP DISPATCH_FAULT\n"); if (display && (addr & 0x80000000)) { @@ -611,18 +616,18 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, nv_error(gr, "no stuck command?\n"); } - nv_wr32(gr, 0x400808, 0); - nv_wr32(gr, 0x4008e8, nv_rd32(gr, 0x4008e8) & 3); - nv_wr32(gr, 0x400848, 0); + nvkm_wr32(device, 0x400808, 0); + nvkm_wr32(device, 0x4008e8, nvkm_rd32(device, 0x4008e8) & 3); + nvkm_wr32(device, 0x400848, 0); ustatus &= ~0x00000001; } if (ustatus & 0x00000002) { - u32 addr = nv_rd32(gr, 0x40084c); + u32 addr = nvkm_rd32(device, 0x40084c); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(gr, 0x40085c); - u32 class = nv_rd32(gr, 0x400814); + u32 data = nvkm_rd32(device, 0x40085c); + u32 class = nvkm_rd32(device, 0x400814); nv_error(gr, "TRAP DISPATCH_QUERY\n"); if (display && (addr & 0x80000000)) { @@ -636,7 +641,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, nv_error(gr, "no stuck command?\n"); } - nv_wr32(gr, 0x40084c, 0); + nvkm_wr32(device, 0x40084c, 0); ustatus &= ~0x00000002; } @@ -645,8 +650,8 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, "0x%08x)\n", ustatus); } - nv_wr32(gr, 0x400804, 0xc0000000); - nv_wr32(gr, 0x400108, 0x001); + nvkm_wr32(device, 0x400804, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x001); status &= ~0x001; if (!status) return 0; @@ -654,81 +659,81 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, /* M2MF: Memory to memory copy engine. */ if (status & 0x002) { - u32 ustatus = nv_rd32(gr, 0x406800) & 0x7fffffff; + u32 ustatus = nvkm_rd32(device, 0x406800) & 0x7fffffff; if (display) { nv_error(gr, "TRAP_M2MF"); nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus); pr_cont("\n"); nv_error(gr, "TRAP_M2MF %08x %08x %08x %08x\n", - nv_rd32(gr, 0x406804), nv_rd32(gr, 0x406808), - nv_rd32(gr, 0x40680c), nv_rd32(gr, 0x406810)); + nvkm_rd32(device, 0x406804), nvkm_rd32(device, 0x406808), + nvkm_rd32(device, 0x40680c), nvkm_rd32(device, 0x406810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(gr, 0x400040, 2); - nv_wr32(gr, 0x400040, 0); - nv_wr32(gr, 0x406800, 0xc0000000); - nv_wr32(gr, 0x400108, 0x002); + nvkm_wr32(device, 0x400040, 2); + nvkm_wr32(device, 0x400040, 0); + nvkm_wr32(device, 0x406800, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x002); status &= ~0x002; } /* VFETCH: Fetches data from vertex buffers. */ if (status & 0x004) { - u32 ustatus = nv_rd32(gr, 0x400c04) & 0x7fffffff; + u32 ustatus = nvkm_rd32(device, 0x400c04) & 0x7fffffff; if (display) { nv_error(gr, "TRAP_VFETCH"); nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus); pr_cont("\n"); nv_error(gr, "TRAP_VFETCH %08x %08x %08x %08x\n", - nv_rd32(gr, 0x400c00), nv_rd32(gr, 0x400c08), - nv_rd32(gr, 0x400c0c), nv_rd32(gr, 0x400c10)); + nvkm_rd32(device, 0x400c00), nvkm_rd32(device, 0x400c08), + nvkm_rd32(device, 0x400c0c), nvkm_rd32(device, 0x400c10)); } - nv_wr32(gr, 0x400c04, 0xc0000000); - nv_wr32(gr, 0x400108, 0x004); + nvkm_wr32(device, 0x400c04, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x004); status &= ~0x004; } /* STRMOUT: DirectX streamout / OpenGL transform feedback. */ if (status & 0x008) { - ustatus = nv_rd32(gr, 0x401800) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x401800) & 0x7fffffff; if (display) { nv_error(gr, "TRAP_STRMOUT"); nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus); pr_cont("\n"); nv_error(gr, "TRAP_STRMOUT %08x %08x %08x %08x\n", - nv_rd32(gr, 0x401804), nv_rd32(gr, 0x401808), - nv_rd32(gr, 0x40180c), nv_rd32(gr, 0x401810)); + nvkm_rd32(device, 0x401804), nvkm_rd32(device, 0x401808), + nvkm_rd32(device, 0x40180c), nvkm_rd32(device, 0x401810)); } /* No sane way found yet -- just reset the bugger. */ - nv_wr32(gr, 0x400040, 0x80); - nv_wr32(gr, 0x400040, 0); - nv_wr32(gr, 0x401800, 0xc0000000); - nv_wr32(gr, 0x400108, 0x008); + nvkm_wr32(device, 0x400040, 0x80); + nvkm_wr32(device, 0x400040, 0); + nvkm_wr32(device, 0x401800, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x008); status &= ~0x008; } /* CCACHE: Handles code and c[] caches and fills them. */ if (status & 0x010) { - ustatus = nv_rd32(gr, 0x405018) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x405018) & 0x7fffffff; if (display) { nv_error(gr, "TRAP_CCACHE"); nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus); pr_cont("\n"); nv_error(gr, "TRAP_CCACHE %08x %08x %08x %08x" " %08x %08x %08x\n", - nv_rd32(gr, 0x405000), nv_rd32(gr, 0x405004), - nv_rd32(gr, 0x405008), nv_rd32(gr, 0x40500c), - nv_rd32(gr, 0x405010), nv_rd32(gr, 0x405014), - nv_rd32(gr, 0x40501c)); + nvkm_rd32(device, 0x405000), nvkm_rd32(device, 0x405004), + nvkm_rd32(device, 0x405008), nvkm_rd32(device, 0x40500c), + nvkm_rd32(device, 0x405010), nvkm_rd32(device, 0x405014), + nvkm_rd32(device, 0x40501c)); } - nv_wr32(gr, 0x405018, 0xc0000000); - nv_wr32(gr, 0x400108, 0x010); + nvkm_wr32(device, 0x405018, 0xc0000000); + nvkm_wr32(device, 0x400108, 0x010); status &= ~0x010; } @@ -736,10 +741,10 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, * remaining, so try to handle it anyway. Perhaps related to that * unknown DMA slot on tesla? */ if (status & 0x20) { - ustatus = nv_rd32(gr, 0x402000) & 0x7fffffff; + ustatus = nvkm_rd32(device, 0x402000) & 0x7fffffff; if (display) nv_error(gr, "TRAP_UNKC04 0x%08x\n", ustatus); - nv_wr32(gr, 0x402000, 0xc0000000); + nvkm_wr32(device, 0x402000, 0xc0000000); /* no status modifiction on purpose */ } @@ -747,7 +752,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x040) { nv50_gr_tp_trap(gr, 6, 0x408900, 0x408600, display, "TRAP_TEXTURE"); - nv_wr32(gr, 0x400108, 0x040); + nvkm_wr32(device, 0x400108, 0x040); status &= ~0x040; } @@ -755,7 +760,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x080) { nv50_gr_tp_trap(gr, 7, 0x408314, 0x40831c, display, "TRAP_MP"); - nv_wr32(gr, 0x400108, 0x080); + nvkm_wr32(device, 0x400108, 0x080); status &= ~0x080; } @@ -764,14 +769,14 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x100) { nv50_gr_tp_trap(gr, 8, 0x408e08, 0x408708, display, "TRAP_PROP"); - nv_wr32(gr, 0x400108, 0x100); + nvkm_wr32(device, 0x400108, 0x100); status &= ~0x100; } if (status) { if (display) nv_error(gr, "TRAP: unknown 0x%08x\n", status); - nv_wr32(gr, 0x400108, status); + nvkm_wr32(device, 0x400108, status); } return 1; @@ -780,18 +785,19 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, static void nv50_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); + struct nv50_gr *gr = (void *)subdev; + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle = NULL; - struct nv50_gr *gr = (void *)subdev; - u32 stat = nv_rd32(gr, 0x400100); - u32 inst = nv_rd32(gr, 0x40032c) & 0x0fffffff; - u32 addr = nv_rd32(gr, 0x400704); + u32 stat = nvkm_rd32(device, 0x400100); + u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff; + u32 addr = nvkm_rd32(device, 0x400704); u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00001ffc); - u32 data = nv_rd32(gr, 0x400708); - u32 class = nv_rd32(gr, 0x400814); + u32 data = nvkm_rd32(device, 0x400708); + u32 class = nvkm_rd32(device, 0x400814); u32 show = stat, show_bitfield = stat; int chid; @@ -806,7 +812,7 @@ nv50_gr_intr(struct nvkm_subdev *subdev) } if (show & 0x00100000) { - u32 ecode = nv_rd32(gr, 0x400110); + u32 ecode = nvkm_rd32(device, 0x400110); nv_error(gr, "DATA_ERROR "); nvkm_enum_print(nv50_data_error_names, ecode); pr_cont("\n"); @@ -820,8 +826,8 @@ nv50_gr_intr(struct nvkm_subdev *subdev) show_bitfield &= ~0x00200000; } - nv_wr32(gr, 0x400100, stat); - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400100, stat); + nvkm_wr32(device, 0x400500, 0x00010001); if (show) { show &= show_bitfield; @@ -836,8 +842,8 @@ nv50_gr_intr(struct nvkm_subdev *subdev) subc, class, mthd, data); } - if (nv_rd32(gr, 0x400824) & (1 << 31)) - nv_wr32(gr, 0x400824, nv_rd32(gr, 0x400824) & ~(1 << 31)); + if (nvkm_rd32(device, 0x400824) & (1 << 31)) + nvkm_wr32(device, 0x400824, nvkm_rd32(device, 0x400824) & ~(1 << 31)); nvkm_engctx_put(engctx); } @@ -902,6 +908,7 @@ static int nv50_gr_init(struct nvkm_object *object) { struct nv50_gr *gr = (void *)object; + struct nvkm_device *device = gr->base.engine.subdev.device; int ret, units, i; ret = nvkm_gr_init(&gr->base); @@ -909,66 +916,66 @@ nv50_gr_init(struct nvkm_object *object) return ret; /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */ - nv_wr32(gr, 0x40008c, 0x00000004); + nvkm_wr32(device, 0x40008c, 0x00000004); /* reset/enable traps and interrupts */ - nv_wr32(gr, 0x400804, 0xc0000000); - nv_wr32(gr, 0x406800, 0xc0000000); - nv_wr32(gr, 0x400c04, 0xc0000000); - nv_wr32(gr, 0x401800, 0xc0000000); - nv_wr32(gr, 0x405018, 0xc0000000); - nv_wr32(gr, 0x402000, 0xc0000000); - - units = nv_rd32(gr, 0x001540); + nvkm_wr32(device, 0x400804, 0xc0000000); + nvkm_wr32(device, 0x406800, 0xc0000000); + nvkm_wr32(device, 0x400c04, 0xc0000000); + nvkm_wr32(device, 0x401800, 0xc0000000); + nvkm_wr32(device, 0x405018, 0xc0000000); + nvkm_wr32(device, 0x402000, 0xc0000000); + + units = nvkm_rd32(device, 0x001540); for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; if (nv_device(gr)->chipset < 0xa0) { - nv_wr32(gr, 0x408900 + (i << 12), 0xc0000000); - nv_wr32(gr, 0x408e08 + (i << 12), 0xc0000000); - nv_wr32(gr, 0x408314 + (i << 12), 0xc0000000); + nvkm_wr32(device, 0x408900 + (i << 12), 0xc0000000); + nvkm_wr32(device, 0x408e08 + (i << 12), 0xc0000000); + nvkm_wr32(device, 0x408314 + (i << 12), 0xc0000000); } else { - nv_wr32(gr, 0x408600 + (i << 11), 0xc0000000); - nv_wr32(gr, 0x408708 + (i << 11), 0xc0000000); - nv_wr32(gr, 0x40831c + (i << 11), 0xc0000000); + nvkm_wr32(device, 0x408600 + (i << 11), 0xc0000000); + nvkm_wr32(device, 0x408708 + (i << 11), 0xc0000000); + nvkm_wr32(device, 0x40831c + (i << 11), 0xc0000000); } } - nv_wr32(gr, 0x400108, 0xffffffff); - nv_wr32(gr, 0x400138, 0xffffffff); - nv_wr32(gr, 0x400100, 0xffffffff); - nv_wr32(gr, 0x40013c, 0xffffffff); - nv_wr32(gr, 0x400500, 0x00010001); + nvkm_wr32(device, 0x400108, 0xffffffff); + nvkm_wr32(device, 0x400138, 0xffffffff); + nvkm_wr32(device, 0x400100, 0xffffffff); + nvkm_wr32(device, 0x40013c, 0xffffffff); + nvkm_wr32(device, 0x400500, 0x00010001); /* upload context program, initialise ctxctl defaults */ ret = nv50_grctx_init(nv_device(gr), &gr->size); if (ret) return ret; - nv_wr32(gr, 0x400824, 0x00000000); - nv_wr32(gr, 0x400828, 0x00000000); - nv_wr32(gr, 0x40082c, 0x00000000); - nv_wr32(gr, 0x400830, 0x00000000); - nv_wr32(gr, 0x40032c, 0x00000000); - nv_wr32(gr, 0x400330, 0x00000000); + nvkm_wr32(device, 0x400824, 0x00000000); + nvkm_wr32(device, 0x400828, 0x00000000); + nvkm_wr32(device, 0x40082c, 0x00000000); + nvkm_wr32(device, 0x400830, 0x00000000); + nvkm_wr32(device, 0x40032c, 0x00000000); + nvkm_wr32(device, 0x400330, 0x00000000); /* some unknown zcull magic */ switch (nv_device(gr)->chipset & 0xf0) { case 0x50: case 0x80: case 0x90: - nv_wr32(gr, 0x402ca8, 0x00000800); + nvkm_wr32(device, 0x402ca8, 0x00000800); break; case 0xa0: default: if (nv_device(gr)->chipset == 0xa0 || nv_device(gr)->chipset == 0xaa || nv_device(gr)->chipset == 0xac) { - nv_wr32(gr, 0x402ca8, 0x00000802); + nvkm_wr32(device, 0x402ca8, 0x00000802); } else { - nv_wr32(gr, 0x402cc0, 0x00000000); - nv_wr32(gr, 0x402ca8, 0x00000002); + nvkm_wr32(device, 0x402cc0, 0x00000000); + nvkm_wr32(device, 0x402ca8, 0x00000002); } break; @@ -976,10 +983,10 @@ nv50_gr_init(struct nvkm_object *object) /* zero out zcull regions */ for (i = 0; i < 8; i++) { - nv_wr32(gr, 0x402c20 + (i * 0x10), 0x00000000); - nv_wr32(gr, 0x402c24 + (i * 0x10), 0x00000000); - nv_wr32(gr, 0x402c28 + (i * 0x10), 0x00000000); - nv_wr32(gr, 0x402c2c + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c20 + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c24 + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c28 + (i * 0x10), 0x00000000); + nvkm_wr32(device, 0x402c2c + (i * 0x10), 0x00000000); } return 0; } -- GitLab From 636e37aa978b4904189710b5b501299bd7404ad5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5385/7006] drm/nouveau/mpeg: switch to device pri macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 68 ++++++++++--------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 26 +++---- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 37 +++++----- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 49 ++++++------- 4 files changed, 96 insertions(+), 84 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 34dd5f6ac247b..2b86575ddcde9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -59,8 +59,9 @@ nv31_mpeg_object_ctor(struct nvkm_object *parent, static int nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) { - struct nvkm_instmem *imem = nvkm_instmem(object); struct nv31_mpeg *mpeg = (void *)object->engine; + struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; u32 inst = *(u32 *)arg << 4; u32 dma0 = nv_ro32(imem, inst + 0); u32 dma1 = nv_ro32(imem, inst + 4); @@ -74,22 +75,22 @@ nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(mpeg, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); - nv_wr32(mpeg, 0x00b334, base); - nv_wr32(mpeg, 0x00b324, size); + nvkm_mask(device, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); + nvkm_wr32(device, 0x00b334, base); + nvkm_wr32(device, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(mpeg, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); - nv_wr32(mpeg, 0x00b360, base); - nv_wr32(mpeg, 0x00b364, size); + nvkm_mask(device, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); + nvkm_wr32(device, 0x00b360, base); + nvkm_wr32(device, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) return -EINVAL; - nv_wr32(mpeg, 0x00b370, base); - nv_wr32(mpeg, 0x00b374, size); + nvkm_wr32(device, 0x00b370, base); + nvkm_wr32(device, 0x00b374, size); } return 0; @@ -182,25 +183,27 @@ nv31_mpeg_cclass = { void nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i) { - struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i]; struct nv31_mpeg *mpeg = (void *)engine; + struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; - nv_wr32(mpeg, 0x00b008 + (i * 0x10), tile->pitch); - nv_wr32(mpeg, 0x00b004 + (i * 0x10), tile->limit); - nv_wr32(mpeg, 0x00b000 + (i * 0x10), tile->addr); + nvkm_wr32(device, 0x00b008 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x00b004 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x00b000 + (i * 0x10), tile->addr); } void nv31_mpeg_intr(struct nvkm_subdev *subdev) { struct nv31_mpeg *mpeg = (void *)subdev; - struct nvkm_fifo *fifo = nvkm_fifo(subdev); + struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; struct nvkm_handle *handle; struct nvkm_object *engctx; - u32 stat = nv_rd32(mpeg, 0x00b100); - u32 type = nv_rd32(mpeg, 0x00b230); - u32 mthd = nv_rd32(mpeg, 0x00b234); - u32 data = nv_rd32(mpeg, 0x00b238); + u32 stat = nvkm_rd32(device, 0x00b100); + u32 type = nvkm_rd32(device, 0x00b230); + u32 mthd = nvkm_rd32(device, 0x00b234); + u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; unsigned long flags; @@ -210,7 +213,7 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(mpeg, 0x00b308, 0x00000000, 0x00000000); + nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } @@ -222,8 +225,8 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) } } - nv_wr32(mpeg, 0x00b100, stat); - nv_wr32(mpeg, 0x00b230, 0x00000001); + nvkm_wr32(device, 0x00b100, stat); + nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { nv_error(mpeg, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", @@ -260,7 +263,8 @@ nv31_mpeg_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv31_mpeg *mpeg = (void *)object; - struct nvkm_fb *fb = nvkm_fb(object); + struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_fb *fb = device->fb; int ret, i; ret = nvkm_mpeg_init(&mpeg->base); @@ -268,24 +272,24 @@ nv31_mpeg_init(struct nvkm_object *object) return ret; /* VPE init */ - nv_wr32(mpeg, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - nv_wr32(mpeg, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nvkm_wr32(device, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ + nvkm_wr32(device, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ for (i = 0; i < fb->tile.regions; i++) engine->tile_prog(engine, i); /* PMPEG init */ - nv_wr32(mpeg, 0x00b32c, 0x00000000); - nv_wr32(mpeg, 0x00b314, 0x00000100); - nv_wr32(mpeg, 0x00b220, 0x00000031); - nv_wr32(mpeg, 0x00b300, 0x02001ec1); - nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x00b32c, 0x00000000); + nvkm_wr32(device, 0x00b314, 0x00000100); + nvkm_wr32(device, 0x00b220, 0x00000031); + nvkm_wr32(device, 0x00b300, 0x02001ec1); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); - nv_wr32(mpeg, 0x00b100, 0xffffffff); - nv_wr32(mpeg, 0x00b140, 0xffffffff); + nvkm_wr32(device, 0x00b100, 0xffffffff); + nvkm_wr32(device, 0x00b140, 0xffffffff); if (!nv_wait(mpeg, 0x00b200, 0x00000001, 0x00000000)) { - nv_error(mpeg, "timeout 0x%08x\n", nv_rd32(mpeg, 0x00b200)); + nv_error(mpeg, "timeout 0x%08x\n", nvkm_rd32(device, 0x00b200)); return -EBUSY; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index c87156a514ddf..08da34bf7931b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -32,8 +32,9 @@ static int nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) { - struct nvkm_instmem *imem = nvkm_instmem(object); struct nv31_mpeg *mpeg = (void *)object->engine; + struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; u32 inst = *(u32 *)arg << 4; u32 dma0 = nv_ro32(imem, inst + 0); u32 dma1 = nv_ro32(imem, inst + 4); @@ -47,22 +48,22 @@ nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) if (mthd == 0x0190) { /* DMA_CMD */ - nv_mask(mpeg, 0x00b300, 0x00030000, (dma0 & 0x00030000)); - nv_wr32(mpeg, 0x00b334, base); - nv_wr32(mpeg, 0x00b324, size); + nvkm_mask(device, 0x00b300, 0x00030000, (dma0 & 0x00030000)); + nvkm_wr32(device, 0x00b334, base); + nvkm_wr32(device, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nv_mask(mpeg, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); - nv_wr32(mpeg, 0x00b360, base); - nv_wr32(mpeg, 0x00b364, size); + nvkm_mask(device, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2); + nvkm_wr32(device, 0x00b360, base); + nvkm_wr32(device, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) return -EINVAL; - nv_wr32(mpeg, 0x00b370, base); - nv_wr32(mpeg, 0x00b374, size); + nvkm_wr32(device, 0x00b370, base); + nvkm_wr32(device, 0x00b374, size); } return 0; @@ -90,14 +91,15 @@ static void nv40_mpeg_intr(struct nvkm_subdev *subdev) { struct nv31_mpeg *mpeg = (void *)subdev; + struct nvkm_device *device = mpeg->base.engine.subdev.device; u32 stat; - if ((stat = nv_rd32(mpeg, 0x00b100))) + if ((stat = nvkm_rd32(device, 0x00b100))) nv31_mpeg_intr(subdev); - if ((stat = nv_rd32(mpeg, 0x00b800))) { + if ((stat = nvkm_rd32(device, 0x00b800))) { nv_error(mpeg, "PMSRCH 0x%08x\n", stat); - nv_wr32(mpeg, 0x00b800, stat); + nvkm_wr32(device, 0x00b800, stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index f494328c74e30..cbf98b306d71b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -60,12 +60,13 @@ nv44_mpeg_context_fini(struct nvkm_object *object, bool suspend) struct nvkm_mpeg *mpeg = (void *)object->engine; struct nv44_mpeg_chan *chan = (void *)object; + struct nvkm_device *device = mpeg->engine.subdev.device; u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; - nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000000); - if (nv_rd32(mpeg, 0x00b318) == inst) - nv_mask(mpeg, 0x00b318, 0x80000000, 0x00000000); - nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000001); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x00b318) == inst) + nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); return 0; } @@ -89,16 +90,17 @@ nv44_mpeg_cclass = { static void nv44_mpeg_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); + struct nvkm_mpeg *mpeg = (void *)subdev; + struct nvkm_device *device = mpeg->engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; struct nvkm_handle *handle; - struct nvkm_mpeg *mpeg = (void *)subdev; - u32 inst = nv_rd32(mpeg, 0x00b318) & 0x000fffff; - u32 stat = nv_rd32(mpeg, 0x00b100); - u32 type = nv_rd32(mpeg, 0x00b230); - u32 mthd = nv_rd32(mpeg, 0x00b234); - u32 data = nv_rd32(mpeg, 0x00b238); + u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff; + u32 stat = nvkm_rd32(device, 0x00b100); + u32 type = nvkm_rd32(device, 0x00b230); + u32 mthd = nvkm_rd32(device, 0x00b234); + u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; int chid; @@ -108,7 +110,7 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_mask(mpeg, 0x00b308, 0x00000000, 0x00000000); + nvkm_mask(device, 0x00b308, 0x00000000, 0x00000000); show &= ~0x01000000; } @@ -120,8 +122,8 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) } } - nv_wr32(mpeg, 0x00b100, stat); - nv_wr32(mpeg, 0x00b230, 0x00000001); + nvkm_wr32(device, 0x00b100, stat); + nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { nv_error(mpeg, @@ -137,14 +139,15 @@ static void nv44_mpeg_me_intr(struct nvkm_subdev *subdev) { struct nvkm_mpeg *mpeg = (void *)subdev; + struct nvkm_device *device = mpeg->engine.subdev.device; u32 stat; - if ((stat = nv_rd32(mpeg, 0x00b100))) + if ((stat = nvkm_rd32(device, 0x00b100))) nv44_mpeg_intr(subdev); - if ((stat = nv_rd32(mpeg, 0x00b800))) { + if ((stat = nvkm_rd32(device, 0x00b800))) { nv_error(mpeg, "PMSRCH 0x%08x\n", stat); - nv_wr32(mpeg, 0x00b800, stat); + nvkm_wr32(device, 0x00b800, stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index f908fa0932666..f83c78fa18a10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -119,16 +119,17 @@ void nv50_mpeg_intr(struct nvkm_subdev *subdev) { struct nvkm_mpeg *mpeg = (void *)subdev; - u32 stat = nv_rd32(mpeg, 0x00b100); - u32 type = nv_rd32(mpeg, 0x00b230); - u32 mthd = nv_rd32(mpeg, 0x00b234); - u32 data = nv_rd32(mpeg, 0x00b238); + struct nvkm_device *device = mpeg->engine.subdev.device; + u32 stat = nvkm_rd32(device, 0x00b100); + u32 type = nvkm_rd32(device, 0x00b230); + u32 mthd = nvkm_rd32(device, 0x00b234); + u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; if (stat & 0x01000000) { /* happens on initial binding of the object */ if (type == 0x00000020 && mthd == 0x0000) { - nv_wr32(mpeg, 0x00b308, 0x00000100); + nvkm_wr32(device, 0x00b308, 0x00000100); show &= ~0x01000000; } } @@ -138,22 +139,23 @@ nv50_mpeg_intr(struct nvkm_subdev *subdev) stat, type, mthd, data); } - nv_wr32(mpeg, 0x00b100, stat); - nv_wr32(mpeg, 0x00b230, 0x00000001); + nvkm_wr32(device, 0x00b100, stat); + nvkm_wr32(device, 0x00b230, 0x00000001); } static void nv50_vpe_intr(struct nvkm_subdev *subdev) { struct nvkm_mpeg *mpeg = (void *)subdev; + struct nvkm_device *device = mpeg->engine.subdev.device; - if (nv_rd32(mpeg, 0x00b100)) + if (nvkm_rd32(device, 0x00b100)) nv50_mpeg_intr(subdev); - if (nv_rd32(mpeg, 0x00b800)) { - u32 stat = nv_rd32(mpeg, 0x00b800); + if (nvkm_rd32(device, 0x00b800)) { + u32 stat = nvkm_rd32(device, 0x00b800); nv_info(mpeg, "PMSRCH: 0x%08x\n", stat); - nv_wr32(mpeg, 0xb800, stat); + nvkm_wr32(device, 0xb800, stat); } } @@ -181,28 +183,29 @@ int nv50_mpeg_init(struct nvkm_object *object) { struct nvkm_mpeg *mpeg = (void *)object; + struct nvkm_device *device = mpeg->engine.subdev.device; int ret; ret = nvkm_mpeg_init(mpeg); if (ret) return ret; - nv_wr32(mpeg, 0x00b32c, 0x00000000); - nv_wr32(mpeg, 0x00b314, 0x00000100); - nv_wr32(mpeg, 0x00b0e0, 0x0000001a); + nvkm_wr32(device, 0x00b32c, 0x00000000); + nvkm_wr32(device, 0x00b314, 0x00000100); + nvkm_wr32(device, 0x00b0e0, 0x0000001a); - nv_wr32(mpeg, 0x00b220, 0x00000044); - nv_wr32(mpeg, 0x00b300, 0x00801ec1); - nv_wr32(mpeg, 0x00b390, 0x00000000); - nv_wr32(mpeg, 0x00b394, 0x00000000); - nv_wr32(mpeg, 0x00b398, 0x00000000); - nv_mask(mpeg, 0x00b32c, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x00b220, 0x00000044); + nvkm_wr32(device, 0x00b300, 0x00801ec1); + nvkm_wr32(device, 0x00b390, 0x00000000); + nvkm_wr32(device, 0x00b394, 0x00000000); + nvkm_wr32(device, 0x00b398, 0x00000000); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); - nv_wr32(mpeg, 0x00b100, 0xffffffff); - nv_wr32(mpeg, 0x00b140, 0xffffffff); + nvkm_wr32(device, 0x00b100, 0xffffffff); + nvkm_wr32(device, 0x00b140, 0xffffffff); if (!nv_wait(mpeg, 0x00b200, 0x00000001, 0x00000000)) { - nv_error(mpeg, "timeout 0x%08x\n", nv_rd32(mpeg, 0x00b200)); + nv_error(mpeg, "timeout 0x%08x\n", nvkm_rd32(device, 0x00b200)); return -EBUSY; } -- GitLab From 54118c74fb4b4fdb032a6c4dfc59bb856bc6fc48 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5386/7006] drm/nouveau/mspdec: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c | 9 +++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index 55ffb3f1f36ce..f83d020f05de5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -60,14 +60,15 @@ static int g98_mspdec_init(struct nvkm_object *object) { struct nvkm_falcon *mspdec = (void *)object; + struct nvkm_device *device = mspdec->engine.subdev.device; int ret; ret = nvkm_falcon_init(mspdec); if (ret) return ret; - nv_wr32(mspdec, 0x085010, 0x0000ffd2); - nv_wr32(mspdec, 0x08501c, 0x0000fff2); + nvkm_wr32(device, 0x085010, 0x0000ffd2); + nvkm_wr32(device, 0x08501c, 0x0000fff2); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index 7c5d01dcf92ef..9bbeede03e068 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -59,14 +59,15 @@ static int gf100_mspdec_init(struct nvkm_object *object) { struct nvkm_falcon *mspdec = (void *)object; + struct nvkm_device *device = mspdec->engine.subdev.device; int ret; ret = nvkm_falcon_init(mspdec); if (ret) return ret; - nv_wr32(mspdec, 0x085010, 0x0000fff2); - nv_wr32(mspdec, 0x08501c, 0x0000fff2); + nvkm_wr32(device, 0x085010, 0x0000fff2); + nvkm_wr32(device, 0x08501c, 0x0000fff2); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index 60755185e88e4..fb742b442ce98 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -58,15 +58,16 @@ gk104_mspdec_cclass = { static int gk104_mspdec_init(struct nvkm_object *object) { - struct nvkm_falcon *falcon = (void *)object; + struct nvkm_falcon *mspdec = (void *)object; + struct nvkm_device *device = mspdec->engine.subdev.device; int ret; - ret = nvkm_falcon_init(falcon); + ret = nvkm_falcon_init(mspdec); if (ret) return ret; - nv_wr32(falcon, 0x085010, 0x0000fff2); - nv_wr32(falcon, 0x08501c, 0x0000fff2); + nvkm_wr32(device, 0x085010, 0x0000fff2); + nvkm_wr32(device, 0x08501c, 0x0000fff2); return 0; } -- GitLab From 320ca25131758a445e351f701daf91d8aa5be096 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5387/7006] drm/nouveau/msppp: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index 04a4d52ff7efa..d681fe63b1bce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -60,14 +60,15 @@ static int g98_msppp_init(struct nvkm_object *object) { struct nvkm_falcon *msppp = (void *)object; + struct nvkm_device *device = msppp->engine.subdev.device; int ret; ret = nvkm_falcon_init(msppp); if (ret) return ret; - nv_wr32(msppp, 0x086010, 0x0000ffd2); - nv_wr32(msppp, 0x08601c, 0x0000fff2); + nvkm_wr32(device, 0x086010, 0x0000ffd2); + nvkm_wr32(device, 0x08601c, 0x0000fff2); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index 5e1fe3b1a1966..7e61f092ef4ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -59,14 +59,15 @@ static int gf100_msppp_init(struct nvkm_object *object) { struct nvkm_falcon *msppp = (void *)object; + struct nvkm_device *device = msppp->engine.subdev.device; int ret; ret = nvkm_falcon_init(msppp); if (ret) return ret; - nv_wr32(msppp, 0x086010, 0x0000fff2); - nv_wr32(msppp, 0x08601c, 0x0000fff2); + nvkm_wr32(device, 0x086010, 0x0000fff2); + nvkm_wr32(device, 0x08601c, 0x0000fff2); return 0; } -- GitLab From f2d85ad1a63130ba31434d042b6c76f24f6b9673 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5388/7006] drm/nouveau/msvld: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index 055bc2141f6bc..c7d981cad8226 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -61,14 +61,15 @@ static int g98_msvld_init(struct nvkm_object *object) { struct nvkm_falcon *msvld = (void *)object; + struct nvkm_device *device = msvld->engine.subdev.device; int ret; ret = nvkm_falcon_init(msvld); if (ret) return ret; - nv_wr32(msvld, 0x084010, 0x0000ffd2); - nv_wr32(msvld, 0x08401c, 0x0000fff2); + nvkm_wr32(device, 0x084010, 0x0000ffd2); + nvkm_wr32(device, 0x08401c, 0x0000fff2); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index 0730198daea79..156ebcf22a27f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -59,14 +59,15 @@ static int gf100_msvld_init(struct nvkm_object *object) { struct nvkm_falcon *msvld = (void *)object; + struct nvkm_device *device = msvld->engine.subdev.device; int ret; ret = nvkm_falcon_init(msvld); if (ret) return ret; - nv_wr32(msvld, 0x084010, 0x0000fff2); - nv_wr32(msvld, 0x08401c, 0x0000fff2); + nvkm_wr32(device, 0x084010, 0x0000fff2); + nvkm_wr32(device, 0x08401c, 0x0000fff2); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index e19ebfdaae6a3..870e61465b07f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -59,14 +59,15 @@ static int gk104_msvld_init(struct nvkm_object *object) { struct nvkm_falcon *msvld = (void *)object; + struct nvkm_device *device = msvld->engine.subdev.device; int ret; ret = nvkm_falcon_init(msvld); if (ret) return ret; - nv_wr32(msvld, 0x084010, 0x0000fff2); - nv_wr32(msvld, 0x08401c, 0x0000fff2); + nvkm_wr32(device, 0x084010, 0x0000fff2); + nvkm_wr32(device, 0x08401c, 0x0000fff2); return 0; } -- GitLab From 846e831d953fd01cb78b9ed92495baee142bed37 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5389/7006] drm/nouveau/pm: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 6 ++- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 43 +++++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 21 +++++---- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 6803ad9ebe6f5..fde6a6013c491 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -126,6 +126,7 @@ nvkm_perfsrc_find(struct nvkm_pm *pm, struct nvkm_perfsig *sig, int si) static int nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) { + struct nvkm_device *device = pm->engine.subdev.device; struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; @@ -151,7 +152,7 @@ nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) value |= ((ctr->source[i][j] >> 32) << src->shift); /* enable the source */ - nv_mask(pm, src->addr, mask, value); + nvkm_mask(device, src->addr, mask, value); nv_debug(pm, "enabled source 0x%08x 0x%08x 0x%08x\n", src->addr, mask, value); } @@ -162,6 +163,7 @@ nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) static int nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) { + struct nvkm_device *device = pm->engine.subdev.device; struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; @@ -186,7 +188,7 @@ nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) mask |= (src->mask << src->shift); /* disable the source */ - nv_mask(pm, src->addr, mask, 0); + nvkm_mask(device, src->addr, mask, 0); nv_debug(pm, "disabled source 0x%08x 0x%08x\n", src->addr, mask); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index cb3f52d2f24be..75a9e6286101d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -128,6 +128,7 @@ static void gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { + struct nvkm_device *device = pm->engine.subdev.device; struct gf100_pm_cntr *cntr = (void *)ctr; u32 log = ctr->logic_op; u32 src = 0x00000000; @@ -136,32 +137,34 @@ gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, for (i = 0; i < 4; i++) src |= ctr->signal[i] << (i * 8); - nv_wr32(pm, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); - nv_wr32(pm, dom->addr + 0x100, 0x00000000); - nv_wr32(pm, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); - nv_wr32(pm, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); + nvkm_wr32(device, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); + nvkm_wr32(device, dom->addr + 0x100, 0x00000000); + nvkm_wr32(device, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); + nvkm_wr32(device, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); } static void gf100_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { + struct nvkm_device *device = pm->engine.subdev.device; struct gf100_pm_cntr *cntr = (void *)ctr; switch (cntr->base.slot) { - case 0: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x08c); break; - case 1: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x088); break; - case 2: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x080); break; - case 3: cntr->base.ctr = nv_rd32(pm, dom->addr + 0x090); break; + case 0: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x08c); break; + case 1: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x088); break; + case 2: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x080); break; + case 3: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x090); break; } - dom->clk = nv_rd32(pm, dom->addr + 0x070); + dom->clk = nvkm_rd32(device, dom->addr + 0x070); } static void gf100_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { - nv_wr32(pm, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); - nv_wr32(pm, dom->addr + 0x0ec, 0x00000011); + struct nvkm_device *device = pm->engine.subdev.device; + nvkm_wr32(device, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27); + nvkm_wr32(device, dom->addr + 0x0ec, 0x00000011); } const struct nvkm_funcdom @@ -175,8 +178,9 @@ int gf100_pm_fini(struct nvkm_object *object, bool suspend) { struct nvkm_pm *pm = (void *)object; - nv_mask(pm, 0x000200, 0x10000000, 0x00000000); - nv_mask(pm, 0x000200, 0x10000000, 0x10000000); + struct nvkm_device *device = pm->engine.subdev.device; + nvkm_mask(device, 0x000200, 0x10000000, 0x00000000); + nvkm_mask(device, 0x000200, 0x10000000, 0x10000000); return nvkm_pm_fini(pm, suspend); } @@ -186,6 +190,7 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct gf100_pm_oclass *mclass = (void *)oclass; + struct nvkm_device *device = (void *)parent; struct nvkm_pm *pm; u32 mask; int ret; @@ -202,9 +207,9 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* GPC */ - mask = (1 << nv_rd32(pm, 0x022430)) - 1; - mask &= ~nv_rd32(pm, 0x022504); - mask &= ~nv_rd32(pm, 0x022584); + mask = (1 << nvkm_rd32(device, 0x022430)) - 1; + mask &= ~nvkm_rd32(device, 0x022504); + mask &= ~nvkm_rd32(device, 0x022584); ret = nvkm_perfdom_new(pm, "gpc", mask, 0x180000, 0x1000, 0x200, mclass->doms_gpc); @@ -212,9 +217,9 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* PART */ - mask = (1 << nv_rd32(pm, 0x022438)) - 1; - mask &= ~nv_rd32(pm, 0x022548); - mask &= ~nv_rd32(pm, 0x0225c8); + mask = (1 << nvkm_rd32(device, 0x022438)) - 1; + mask &= ~nvkm_rd32(device, 0x022548); + mask &= ~nvkm_rd32(device, 0x0225c8); ret = nvkm_perfdom_new(pm, "part", mask, 0x1a0000, 0x1000, 0x200, mclass->doms_part); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index a447eac24f3bf..b37c024f07838 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -27,6 +27,7 @@ static void nv40_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { + struct nvkm_device *device = pm->engine.subdev.device; struct nv40_pm_cntr *cntr = (void *)ctr; u32 log = ctr->logic_op; u32 src = 0x00000000; @@ -35,31 +36,33 @@ nv40_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, for (i = 0; i < 4; i++) src |= ctr->signal[i] << (i * 8); - nv_wr32(pm, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); - nv_wr32(pm, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); - nv_wr32(pm, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); + nvkm_wr32(device, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); + nvkm_wr32(device, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); + nvkm_wr32(device, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); } static void nv40_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { + struct nvkm_device *device = pm->engine.subdev.device; struct nv40_pm_cntr *cntr = (void *)ctr; switch (cntr->base.slot) { - case 0: cntr->base.ctr = nv_rd32(pm, 0x00a700 + dom->addr); break; - case 1: cntr->base.ctr = nv_rd32(pm, 0x00a6c0 + dom->addr); break; - case 2: cntr->base.ctr = nv_rd32(pm, 0x00a680 + dom->addr); break; - case 3: cntr->base.ctr = nv_rd32(pm, 0x00a740 + dom->addr); break; + case 0: cntr->base.ctr = nvkm_rd32(device, 0x00a700 + dom->addr); break; + case 1: cntr->base.ctr = nvkm_rd32(device, 0x00a6c0 + dom->addr); break; + case 2: cntr->base.ctr = nvkm_rd32(device, 0x00a680 + dom->addr); break; + case 3: cntr->base.ctr = nvkm_rd32(device, 0x00a740 + dom->addr); break; } - dom->clk = nv_rd32(pm, 0x00a600 + dom->addr); + dom->clk = nvkm_rd32(device, 0x00a600 + dom->addr); } static void nv40_perfctr_next(struct nvkm_pm *pm, struct nvkm_perfdom *dom) { + struct nvkm_device *device = pm->engine.subdev.device; if (pm->sequence != pm->sequence) { - nv_wr32(pm, 0x400084, 0x00000020); + nvkm_wr32(device, 0x400084, 0x00000020); pm->sequence = pm->sequence; } } -- GitLab From b8ad561e5541e6e6fe5c60ef33fec50ec211c92b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5390/7006] drm/nouveau/sec: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index 1de94ec18a787..a1096f0e40814 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -71,18 +71,19 @@ static const struct nvkm_enum g98_sec_isr_error_name[] = { static void g98_sec_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); + struct nvkm_falcon *sec = (void *)subdev; + struct nvkm_device *device = sec->engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_object *engctx; - struct nvkm_falcon *sec = (void *)subdev; - u32 disp = nv_rd32(sec, 0x08701c); - u32 stat = nv_rd32(sec, 0x087008) & disp & ~(disp >> 16); - u32 inst = nv_rd32(sec, 0x087050) & 0x3fffffff; - u32 ssta = nv_rd32(sec, 0x087040) & 0x0000ffff; - u32 addr = nv_rd32(sec, 0x087040) >> 16; + u32 disp = nvkm_rd32(device, 0x08701c); + u32 stat = nvkm_rd32(device, 0x087008) & disp & ~(disp >> 16); + u32 inst = nvkm_rd32(device, 0x087050) & 0x3fffffff; + u32 ssta = nvkm_rd32(device, 0x087040) & 0x0000ffff; + u32 addr = nvkm_rd32(device, 0x087040) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_rd32(sec, 0x087044); + u32 data = nvkm_rd32(device, 0x087044); int chid; engctx = nvkm_engctx_get(engine, inst); @@ -94,13 +95,13 @@ g98_sec_intr(struct nvkm_subdev *subdev) pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", chid, (u64)inst << 12, nvkm_client_name(engctx), subc, mthd, data); - nv_wr32(sec, 0x087004, 0x00000040); + nvkm_wr32(device, 0x087004, 0x00000040); stat &= ~0x00000040; } if (stat) { nv_error(sec, "unhandled intr 0x%08x\n", stat); - nv_wr32(sec, 0x087004, stat); + nvkm_wr32(device, 0x087004, stat); } nvkm_engctx_put(engctx); -- GitLab From 01d64afc2e3238cf1658184427fa2563963c8708 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5391/7006] drm/nouveau/sw: switch to device pri macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 18 ++++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 15 ++++++++------- 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index b35b45931cbd8..eade9e30e1429 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -51,19 +51,20 @@ gf100_sw_mthd_mp_control(struct nvkm_object *object, u32 mthd, { struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); struct nvkm_sw *sw = (void *)nv_object(chan)->engine; + struct nvkm_device *device = sw->engine.subdev.device; u32 data = *(u32 *)args; switch (mthd) { case 0x600: - nv_wr32(sw, 0x419e00, data); /* MP.PM_UNK000 */ + nvkm_wr32(device, 0x419e00, data); /* MP.PM_UNK000 */ break; case 0x644: if (data & ~0x1ffffe) return -EINVAL; - nv_wr32(sw, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ + nvkm_wr32(device, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ break; case 0x6ac: - nv_wr32(sw, 0x419eac, data); /* MP.PM_UNK0AC */ + nvkm_wr32(device, 0x419eac, data); /* MP.PM_UNK0AC */ break; default: return -EINVAL; @@ -100,13 +101,14 @@ gf100_sw_vblsem_release(struct nvkm_notify *notify) struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); struct nvkm_sw *sw = (void *)nv_object(chan)->engine; - struct nvkm_bar *bar = nvkm_bar(sw); + struct nvkm_device *device = sw->engine.subdev.device; + struct nvkm_bar *bar = device->bar; - nv_wr32(sw, 0x001718, 0x80000000 | chan->vblank.channel); + nvkm_wr32(device, 0x001718, 0x80000000 | chan->vblank.channel); bar->flush(bar); - nv_wr32(sw, 0x06000c, upper_32_bits(chan->vblank.offset)); - nv_wr32(sw, 0x060010, lower_32_bits(chan->vblank.offset)); - nv_wr32(sw, 0x060014, chan->vblank.value); + nvkm_wr32(device, 0x06000c, upper_32_bits(chan->vblank.offset)); + nvkm_wr32(device, 0x060010, lower_32_bits(chan->vblank.offset)); + nvkm_wr32(device, 0x060014, chan->vblank.value); return NVKM_NOTIFY_DROP; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index f1bb1e6f35a1b..3bdab840ebf84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -97,7 +97,7 @@ nv04_sw_cclass = { void nv04_sw_intr(struct nvkm_subdev *subdev) { - nv_mask(subdev, 0x000100, 0x80000000, 0x00000000); + nvkm_mask(subdev->device, 0x000100, 0x80000000, 0x00000000); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index af2c1afaae552..ab3175af88fed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -122,18 +122,19 @@ nv50_sw_vblsem_release(struct nvkm_notify *notify) struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); struct nvkm_sw *sw = (void *)nv_object(chan)->engine; - struct nvkm_bar *bar = nvkm_bar(sw); + struct nvkm_device *device = sw->engine.subdev.device; + struct nvkm_bar *bar = device->bar; - nv_wr32(sw, 0x001704, chan->vblank.channel); - nv_wr32(sw, 0x001710, 0x80000000 | chan->vblank.ctxdma); + nvkm_wr32(device, 0x001704, chan->vblank.channel); + nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma); bar->flush(bar); if (nv_device(sw)->chipset == 0x50) { - nv_wr32(sw, 0x001570, chan->vblank.offset); - nv_wr32(sw, 0x001574, chan->vblank.value); + nvkm_wr32(device, 0x001570, chan->vblank.offset); + nvkm_wr32(device, 0x001574, chan->vblank.value); } else { - nv_wr32(sw, 0x060010, chan->vblank.offset); - nv_wr32(sw, 0x060014, chan->vblank.value); + nvkm_wr32(device, 0x060010, chan->vblank.offset); + nvkm_wr32(device, 0x060014, chan->vblank.value); } return NVKM_NOTIFY_DROP; -- GitLab From 2ebfa1bc6ff1a7cded8b662f507d34574ffcc2c6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5392/7006] drm/nouveau/kms/nv04: fix incorrect use of register accessors Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/dfp.c | 8 +-- .../drm/nouveau/include/nvkm/core/device.h | 14 +++-- .../drm/nouveau/include/nvkm/core/subdev.h | 60 ------------------- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 1 - .../gpu/drm/nouveau/nvkm/engine/device/base.c | 11 ++-- 5 files changed, 17 insertions(+), 77 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 7cfb0cbc9b6e9..61b49c1d5303f 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -493,11 +493,11 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) if (dev->pdev->device == 0x0174 || dev->pdev->device == 0x0179 || dev->pdev->device == 0x0189 || dev->pdev->device == 0x0329) { if (mode == DRM_MODE_DPMS_ON) { - nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 1 << 31); - nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 1); + nvif_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 1 << 31); + nvif_mask(device, NV_PCRTC_GPIO_EXT, 3, 1); } else { - nv_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0); - nv_mask(device, NV_PCRTC_GPIO_EXT, 3, 0); + nvif_mask(device, NV_PBUS_DEBUG_DUALHEAD_CTL, 1 << 31, 0); + nvif_mask(device, NV_PCRTC_GPIO_EXT, 3, 0); } } #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 167a0dd94fe28..14f7d197e479c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -72,6 +72,8 @@ struct nvkm_device { struct device *dev; u64 handle; + void __iomem *pri; + struct nvkm_event event; const char *cfgopt; @@ -148,12 +150,12 @@ struct nvkm_device *nvkm_device_find(u64 name); int nvkm_device_list(u64 *name, int size); /* privileged register interface accessor macros */ -#define nvkm_rd08(d,a) ioread8((d)->engine.subdev.mmio + (a)) -#define nvkm_rd16(d,a) ioread16_native((d)->engine.subdev.mmio + (a)) -#define nvkm_rd32(d,a) ioread32_native((d)->engine.subdev.mmio + (a)) -#define nvkm_wr08(d,a,v) iowrite8((v), (d)->engine.subdev.mmio + (a)) -#define nvkm_wr16(d,a,v) iowrite16_native((v), (d)->engine.subdev.mmio + (a)) -#define nvkm_wr32(d,a,v) iowrite32_native((v), (d)->engine.subdev.mmio + (a)) +#define nvkm_rd08(d,a) ioread8((d)->pri + (a)) +#define nvkm_rd16(d,a) ioread16_native((d)->pri + (a)) +#define nvkm_rd32(d,a) ioread32_native((d)->pri + (a)) +#define nvkm_wr08(d,a,v) iowrite8((v), (d)->pri + (a)) +#define nvkm_wr16(d,a,v) iowrite16_native((v), (d)->pri + (a)) +#define nvkm_wr32(d,a,v) iowrite32_native((v), (d)->pri + (a)) #define nvkm_mask(d,a,m,v) ({ \ struct nvkm_device *_device = (d); \ u32 _addr = (a), _temp = nvkm_rd32(_device, _addr); \ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index d2dac06f2b8bd..ad516cf24f6cd 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -12,7 +12,6 @@ struct nvkm_subdev { struct mutex mutex; const char *name; - void __iomem *mmio; u32 debug; u32 unit; @@ -60,64 +59,5 @@ int _nvkm_subdev_fini(struct nvkm_object *, bool suspend); } \ } while(0) -static inline u8 -nv_rd08(void *obj, u32 addr) -{ - struct nvkm_subdev *subdev = nv_subdev(obj); - u8 data = ioread8(subdev->mmio + addr); - nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data); - return data; -} - -static inline u16 -nv_rd16(void *obj, u32 addr) -{ - struct nvkm_subdev *subdev = nv_subdev(obj); - u16 data = ioread16_native(subdev->mmio + addr); - nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data); - return data; -} - -static inline u32 -nv_rd32(void *obj, u32 addr) -{ - struct nvkm_subdev *subdev = nv_subdev(obj); - u32 data = ioread32_native(subdev->mmio + addr); - nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data); - return data; -} - -static inline void -nv_wr08(void *obj, u32 addr, u8 data) -{ - struct nvkm_subdev *subdev = nv_subdev(obj); - nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data); - iowrite8(data, subdev->mmio + addr); -} - -static inline void -nv_wr16(void *obj, u32 addr, u16 data) -{ - struct nvkm_subdev *subdev = nv_subdev(obj); - nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data); - iowrite16_native(data, subdev->mmio + addr); -} - -static inline void -nv_wr32(void *obj, u32 addr, u32 data) -{ - struct nvkm_subdev *subdev = nv_subdev(obj); - nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data); - iowrite32_native(data, subdev->mmio + addr); -} - -static inline u32 -nv_mask(void *obj, u32 addr, u32 mask, u32 data) -{ - u32 temp = nv_rd32(obj, addr); - nv_wr32(obj, addr, (temp & ~mask) | data); - return temp; -} - #include #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index fd1a94c5bf385..dd2cf44bd6a11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -115,7 +115,6 @@ nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (parent) { struct nvkm_device *device = nv_device(parent); subdev->debug = nvkm_dbgopt(device->dbgopt, subname); - subdev->mmio = nv_subdev(device)->mmio; subdev->device = device; } else { subdev->device = nv_device(subdev); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 35047437cf4c4..bced8ea58f455 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -444,10 +444,9 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass; } - if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && - !nv_subdev(device)->mmio) { - nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size); - if (!nv_subdev(device)->mmio) { + if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && !device->pri) { + device->pri = ioremap(mmio_base, mmio_size); + if (!device->pri) { nv_error(device, "unable to map device registers\n"); return -ENOMEM; } @@ -684,8 +683,8 @@ nvkm_device_dtor(struct nvkm_object *object) list_del(&device->head); mutex_unlock(&nv_devices_mutex); - if (nv_subdev(device)->mmio) - iounmap(nv_subdev(device)->mmio); + if (device->pri) + iounmap(device->pri); nvkm_engine_destroy(&device->engine); } -- GitLab From 56f67dc19623b6cd4db57ee07d6f0cad32bcd5af Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5393/7006] drm/nouveau/tmr: type-safe PTIMER-based delay/wait macros These require an explicit struct nvkm_device pointer, unlike the previous macros which take a void *, and work for (almost) anything derived from nvkm_object by using some heuristics. These macros are more general than the previous ones, and can be used to handle PTIMER-based busy-waits (will be used in later devinit fixes) as well as more complicated wait conditions. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 22 +++++++ .../drm/nouveau/include/nvkm/subdev/timer.h | 57 ++++++++++++++++++- drivers/gpu/drm/nouveau/nouveau_abi16.c | 3 +- drivers/gpu/drm/nouveau/nvif/device.c | 6 ++ .../gpu/drm/nouveau/nvkm/subdev/timer/base.c | 57 ------------------- 5 files changed, 83 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 88553a741ab7f..8bd60dd3b1615 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -25,6 +25,28 @@ void nvif_device_fini(struct nvif_device *); int nvif_device_new(struct nvif_object *, u32 handle, u32 oclass, void *, u32, struct nvif_device **); void nvif_device_ref(struct nvif_device *, struct nvif_device **); +u64 nvif_device_time(struct nvif_device *); + +/* Delay based on GPU time (ie. PTIMER). + * + * Will return -ETIMEDOUT unless the loop was terminated with 'break', + * where it will return the number of nanoseconds taken instead. + */ +#define nvif_nsec(d,n,cond...) ({ \ + struct nvif_device *_device = (d); \ + u64 _nsecs = (n), _time0 = nvif_device_time(_device); \ + s64 _taken = 0; \ + \ + do { \ + cond \ + } while (_taken = nvif_device_time(_device) - _time0, _taken < _nsecs);\ + \ + if (_taken >= _nsecs) \ + _taken = -ETIMEDOUT; \ + _taken; \ +}) +#define nvif_usec(d,u,cond...) nvif_nsec((d), (u) * 1000, ##cond) +#define nvif_msec(d,m,cond...) nvif_usec((d), (m) * 1000, ##cond) /*XXX*/ #include diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index 2c27ce6919390..b26ae6fa5ba7c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -16,12 +16,63 @@ nvkm_alarm_init(struct nvkm_alarm *alarm, alarm->func = func; } -bool nvkm_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data); -bool nvkm_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data); -bool nvkm_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data); void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *); void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *); +/* Delay based on GPU time (ie. PTIMER). + * + * Will return -ETIMEDOUT unless the loop was terminated with 'break', + * where it will return the number of nanoseconds taken instead. + * + * NVKM_DELAY can be passed for 'cond' to disable the timeout warning, + * which is useful for unconditional delay loops. + */ +#define NVKM_DELAY _warn = false; +#define nvkm_nsec(d,n,cond...) ({ \ + struct nvkm_device *_device = (d); \ + struct nvkm_timer *_tmr = _device->timer; \ + u64 _nsecs = (n), _time0 = _tmr->read(_tmr); \ + s64 _taken = 0; \ + bool _warn = true; \ + \ + do { \ + cond \ + } while (_taken = _tmr->read(_tmr) - _time0, _taken < _nsecs); \ + \ + if (_taken >= _nsecs) { \ + if (_warn) { \ + dev_warn(_device->dev, "timeout at %s:%d/%s()!\n", \ + __FILE__, __LINE__, __func__); \ + } \ + _taken = -ETIMEDOUT; \ + } \ + _taken; \ +}) +#define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond) +#define nvkm_msec(d,m,cond...) nvkm_usec((d), (m) * 1000, ##cond) + +#define nvkm_timer_wait_eq(o,n,a,m,v) ({ \ + struct nvkm_device *__device = nv_device(o); \ + nvkm_nsec(__device, (n), \ + if ((nvkm_rd32(__device, (a)) & (m)) == (v)) \ + break; \ + ) >= 0; \ +}) +#define nvkm_timer_wait_ne(o,n,a,m,v) ({ \ + struct nvkm_device *__device = nv_device(o); \ + nvkm_nsec(__device, (n), \ + if ((nvkm_rd32(__device, (a)) & (m)) != (v)) \ + break; \ + ) >= 0; \ +}) +#define nvkm_timer_wait_cb(o,n,c,d) ({ \ + struct nvkm_device *__device = nv_device(o); \ + nvkm_nsec(__device, (n), \ + if (c(d)) \ + break; \ + ) >= 0; \ +}) + #define NV_WAIT_DEFAULT 2000000000ULL #define nv_wait(o,a,m,v) \ nvkm_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v)) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 1bdde99155a0b..c2ba0cc1521f6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -164,7 +164,6 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) struct nouveau_cli *cli = nouveau_cli(file_priv); struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; - struct nvkm_timer *tmr = nvxx_timer(device); struct nvkm_gr *gr = nvxx_gr(device); struct drm_nouveau_getparam *getparam = data; @@ -206,7 +205,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = 0; /* deprecated */ break; case NOUVEAU_GETPARAM_PTIMER_TIME: - getparam->value = tmr->read(tmr); + getparam->value = nvif_device_time(device); break; case NOUVEAU_GETPARAM_HAS_BO_USAGE: getparam->value = 1; diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c index 6f72244c52cd8..837442c69a5d2 100644 --- a/drivers/gpu/drm/nouveau/nvif/device.c +++ b/drivers/gpu/drm/nouveau/nvif/device.c @@ -24,6 +24,12 @@ #include +u64 +nvif_device_time(struct nvif_device *device) +{ + return nvxx_timer(device)->read(nvxx_timer(device)); +} + void nvif_device_fini(struct nvif_device *device) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index c59b2353683b8..4c34e2bd0487d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -23,63 +23,6 @@ */ #include -bool -nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) -{ - struct nvkm_timer *ptimer = nvkm_timer(obj); - struct nvkm_device *device = ptimer->subdev.device; - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nvkm_rd32(device, addr) & mask) == data) - return true; - } else { - if ((nv_ro32(obj, addr) & mask) == data) - return true; - } - } while (ptimer->read(ptimer) - time0 < nsec); - - return false; -} - -bool -nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data) -{ - struct nvkm_timer *ptimer = nvkm_timer(obj); - struct nvkm_device *device = ptimer->subdev.device; - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (nv_iclass(obj, NV_SUBDEV_CLASS)) { - if ((nvkm_rd32(device, addr) & mask) != data) - return true; - } else { - if ((nv_ro32(obj, addr) & mask) != data) - return true; - } - } while (ptimer->read(ptimer) - time0 < nsec); - - return false; -} - -bool -nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data) -{ - struct nvkm_timer *ptimer = nvkm_timer(obj); - u64 time0; - - time0 = ptimer->read(ptimer); - do { - if (func(data) == true) - return true; - } while (ptimer->read(ptimer) - time0 < nsec); - - return false; -} - void nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm) { -- GitLab From 4dd308f446c31e8f4a2b5033ba2de6f53f015114 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:10 +1000 Subject: [PATCH 5394/7006] drm/nouveau/bar: switch to new-style timer macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index dcfb11895a61b..a47d64d3b0fd3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -85,8 +85,10 @@ nv50_bar_flush(struct nvkm_bar *obj) unsigned long flags; spin_lock_irqsave(&bar->lock, flags); nvkm_wr32(device, 0x00330c, 0x00000001); - if (!nv_wait(bar, 0x00330c, 0x00000002, 0x00000000)) - nv_warn(bar, "flush timeout\n"); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00330c) & 0x00000002)) + break; + ); spin_unlock_irqrestore(&bar->lock, flags); } @@ -98,8 +100,10 @@ g84_bar_flush(struct nvkm_bar *obj) unsigned long flags; spin_lock_irqsave(&bar->lock, flags); nvkm_wr32(device, 0x070000, 0x00000001); - if (!nv_wait(bar, 0x070000, 0x00000002, 0x00000000)) - nv_warn(bar, "flush timeout\n"); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x070000) & 0x00000002)) + break; + ); spin_unlock_irqrestore(&bar->lock, flags); } @@ -240,10 +244,11 @@ nv50_bar_init(struct nvkm_object *object) nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); nvkm_wr32(device, 0x100c80, 0x00060001); - if (!nv_wait(bar, 0x100c80, 0x00000001, 0x00000000)) { - nv_error(bar, "vm flush timeout\n"); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ) < 0) return -EBUSY; - } nvkm_wr32(device, 0x001704, 0x00000000 | bar->mem->addr >> 12); nvkm_wr32(device, 0x001704, 0x40000000 | bar->mem->addr >> 12); -- GitLab From 4f31c84ebafd7b3940c2fe109fe173c62d097080 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5395/7006] drm/nouveau/bus: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c | 8 +++++++- drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c index b23475bbf3ad9..10ac729a4d903 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c @@ -40,7 +40,13 @@ g94_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) nvkm_mask(device, 0x001098, 0x00000018, 0x00000018); nvkm_wr32(device, 0x00130c, 0x00000001); - return nv_wait(bus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x001308) & 0x00000100)) + break; + ) < 0) + return -ETIMEDOUT; + + return 0; } struct nvkm_oclass * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index 69d55b435c6c4..1a9be08604f5c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -39,7 +39,13 @@ nv50_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) nvkm_mask(device, 0x001098, 0x00000018, 0x00000018); nvkm_wr32(device, 0x00130c, 0x00000003); - return nv_wait(bus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT; + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x001308) & 0x00000100)) + break; + ) < 0) + return -ETIMEDOUT; + + return 0; } void -- GitLab From 6979c6303a4abf263753cd9d577d79f05c6e8c47 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5396/7006] drm/nouveau/clk: switch to new-style timer macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 16 ++++++++++--- .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 16 ++++++++++--- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 8 +++---- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 24 +++++++++++++++---- .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 8 ++++--- 5 files changed, 54 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index f7aac3702c234..c90f7d68f412e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -345,7 +345,10 @@ gf100_clk_prog_1(struct gf100_clk *clk, int idx) { struct nvkm_device *device = clk->base.subdev.device; nvkm_mask(device, 0x137100, (1 << idx), 0x00000000); - nv_wait(clk, 0x137100, (1 << idx), 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x137100) & (1 << idx))) + break; + ); } static void @@ -360,7 +363,10 @@ gf100_clk_prog_2(struct gf100_clk *clk, int idx) if (info->coef) { nvkm_wr32(device, addr + 0x04, info->coef); nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(clk, addr + 0x00, 0x00020000, 0x00020000); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, addr + 0x00) & 0x00020000) + break; + ); nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); } } @@ -373,7 +379,11 @@ gf100_clk_prog_3(struct gf100_clk *clk, int idx) struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { nvkm_mask(device, 0x137100, (1 << idx), info->ssel); - nv_wait(clk, 0x137100, (1 << idx), info->ssel); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x137100) & (1 << idx); + if (tmp == info->ssel) + break; + ); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index d2b7d6ec1c2b5..ad166aaf609bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -366,7 +366,10 @@ gk104_clk_prog_1_0(struct gk104_clk *clk, int idx) { struct nvkm_device *device = clk->base.subdev.device; nvkm_mask(device, 0x137100, (1 << idx), 0x00000000); - nv_wait(clk, 0x137100, (1 << idx), 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x137100) & (1 << idx))) + break; + ); } static void @@ -387,7 +390,10 @@ gk104_clk_prog_2(struct gk104_clk *clk, int idx) if (info->coef) { nvkm_wr32(device, addr + 0x04, info->coef); nvkm_mask(device, addr + 0x00, 0x00000001, 0x00000001); - nv_wait(clk, addr + 0x00, 0x00020000, 0x00020000); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, addr + 0x00) & 0x00020000) + break; + ); nvkm_mask(device, addr + 0x00, 0x00020004, 0x00000004); } } @@ -410,7 +416,11 @@ gk104_clk_prog_4_0(struct gk104_clk *clk, int idx) struct nvkm_device *device = clk->base.subdev.device; if (info->ssel) { nvkm_mask(device, 0x137100, (1 << idx), info->ssel); - nv_wait(clk, 0x137100, (1 << idx), info->ssel); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x137100) & (1 << idx); + if (tmp == info->ssel) + break; + ); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 6d36d094b8f2e..49659bce68e36 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -405,11 +405,11 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) nvkm_wr32(device, GPCPLL_CFG, val); } - if (!nvkm_timer_wait_eq(clk, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK, - GPCPLL_CFG_LOCK)) { - nv_error(clk, "%s: timeout waiting for pllg lock\n", __func__); + if (nvkm_usec(device, 300, + if (nvkm_rd32(device, GPCPLL_CFG) & GPCPLL_CFG_LOCK) + break; + ) < 0) return -ETIMEDOUT; - } /* switch to VCO mode */ nvkm_mask(device, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT)); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 364c9b0df728a..6992cbb8c2d84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -302,21 +302,32 @@ int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) { struct nvkm_device *device = clk->subdev.device; - struct nvkm_fifo *fifo = nvkm_fifo(clk); + struct nvkm_fifo *fifo = device->fifo; /* halt and idle execution engines */ nvkm_mask(device, 0x020060, 0x00070000, 0x00000000); nvkm_mask(device, 0x002504, 0x00000001, 0x00000001); /* Wait until the interrupt handler is finished */ - if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000)) + if (nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x000100)) + break; + ) < 0) return -EBUSY; if (fifo) fifo->pause(fifo, flags); - if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010)) + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x002504) & 0x00000010) + break; + ) < 0) return -EIO; - if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f)) + + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x002504) & 0x0000003f; + if (tmp == 0x0000003f) + break; + ) < 0) return -EIO; return 0; @@ -367,7 +378,10 @@ prog_pll(struct gt215_clk *clk, int idx, u32 pll, int dom) nvkm_wr32(device, coef, info->pll); nvkm_mask(device, ctrl, 0x00000015, 0x00000015); nvkm_mask(device, ctrl, 0x00000010, 0x00000000); - if (!nv_wait(clk, ctrl, 0x00020000, 0x00020000)) { + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, ctrl) & 0x00020000) + break; + ) < 0) { nvkm_mask(device, ctrl, 0x00000010, 0x00000010); nvkm_mask(device, src0, 0x00000101, 0x00000000); return; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index 9d7c118e97845..05d2a1bc55cf3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -349,10 +349,12 @@ mcp77_clk_prog(struct nvkm_clk *obj) goto resume; } - if (!nv_wait(clk, 0x004080, pllmask, pllmask)) { - nv_warn(clk,"Reclocking failed: unstable PLLs\n"); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x004080) & pllmask; + if (tmp == pllmask) + break; + ) < 0) goto resume; - } switch (clk->vsrc) { case nv_clk_src_cclk: -- GitLab From cf07d861ce3c4bfd9d45f9e66f30cbfb56dca3a0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5397/7006] drm/nouveau/fb: switch to new-style timer macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 54d8cb55ad95e..56bdfeeab8e79 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -94,8 +94,19 @@ nv40_ram_prog(struct nvkm_fb *fb) for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) continue; - nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000); - nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000)); + if (!(tmp & 0x00010000)) + break; + ); + + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000)); + if ( (tmp & 0x00010000)) + break; + ); + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20); } @@ -155,7 +166,13 @@ nv40_ram_prog(struct nvkm_fb *fb) for (i = 0; i < 2; i++) { if (!(crtc_mask & (1 << i))) continue; - nv_wait(fb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000); + + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x600808 + (i * 0x2000)); + if ( (tmp & 0x00010000)) + break; + ); + nvkm_wr08(device, 0x0c03c4 + (i * 0x2000), 0x01); nvkm_wr08(device, 0x0c03c5 + (i * 0x2000), sr1[i]); } -- GitLab From 63bb5c390bf2f975f0936b6523af6784af811b49 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5398/7006] drm/nouveau/ibus: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index 1b676aaecc889..611fc7165469b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -59,9 +59,10 @@ gk20a_ibus_intr(struct nvkm_subdev *subdev) /* Acknowledge interrupt */ nvkm_mask(device, 0x12004c, 0x2, 0x2); - - if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00)) - nv_warn(ibus, "timeout waiting for ringmaster ack\n"); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x12004c) & 0x0000003f)) + break; + ); } static int -- GitLab From 1302bcbb8229b0575401be87765277629330384a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5399/7006] drm/nouveau/ltc: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 10 ++++++++-- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 10 ++++++++-- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index df60ee264b954..7e60a1393fc8d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -39,10 +39,16 @@ gf100_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) { + struct nvkm_device *device = ltc->base.subdev.device; int c, s; for (c = 0; c < ltc->ltc_nr; c++) { - for (s = 0; s < ltc->lts_nr; s++) - nv_wait(ltc, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0); + for (s = 0; s < ltc->lts_nr; s++) { + const u32 addr = 0x1410c8 + (c * 0x2000) + (s * 0x400); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, addr)) + break; + ); + } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 3f009bb76226d..438085e978ec4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -38,10 +38,16 @@ gm107_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) static void gm107_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) { + struct nvkm_device *device = ltc->base.subdev.device; int c, s; for (c = 0; c < ltc->ltc_nr; c++) { - for (s = 0; s < ltc->lts_nr; s++) - nv_wait(ltc, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0); + for (s = 0; s < ltc->lts_nr; s++) { + const u32 addr = 0x14046c + (c * 0x2000) + (s * 0x200); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, addr)) + break; + ); + } } } -- GitLab From 909604d444eb26ed37860268cfc6a68d4a5f28cb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5400/7006] drm/nouveau/mmu: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 16 ++++++++-------- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 6 ++++-- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 5 ++++- 4 files changed, 20 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 3551b55a5646c..f0b6f590ec764 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -170,19 +170,19 @@ gf100_vm_flush(struct nvkm_vm *vm) /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases */ - if (!nv_wait_ne(mmu, 0x100c80, 0x00ff0000, 0x00000000)) { - nv_error(mmu, "vm timeout 0: 0x%08x %d\n", - nvkm_rd32(device, 0x100c80), type); - } + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100c80) & 0x00ff0000) + break; + ); nvkm_wr32(device, 0x100cb8, vpgd->obj->addr >> 8); nvkm_wr32(device, 0x100cbc, 0x80000000 | type); /* wait for flush to be queued? */ - if (!nv_wait(mmu, 0x100c80, 0x00008000, 0x00008000)) { - nv_error(mmu, "vm timeout 1: 0x%08x %d\n", - nvkm_rd32(device, 0x100c80), type); - } + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100c80) & 0x00008000) + break; + ); } mutex_unlock(&nv_subdev(mmu)->mutex); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 609c6a69b60aa..378cd1d363aec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -69,10 +69,10 @@ nv41_vm_flush(struct nvkm_vm *vm) mutex_lock(&nv_subdev(mmu)->mutex); nvkm_wr32(device, 0x100810, 0x00000022); - if (!nv_wait(mmu, 0x100810, 0x00000020, 0x00000020)) { - nv_warn(mmu, "flush timeout, 0x%08x\n", - nvkm_rd32(device, 0x100810)); - } + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100810) & 0x00000020) + break; + ); nvkm_wr32(device, 0x100810, 0x00000000); mutex_unlock(&nv_subdev(mmu)->mutex); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 371f627e17dbd..64203abaaee72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -143,8 +143,10 @@ nv44_vm_flush(struct nvkm_vm *vm) struct nvkm_device *device = mmu->base.subdev.device; nvkm_wr32(device, 0x100814, mmu->base.limit - NV44_GART_PAGE); nvkm_wr32(device, 0x100808, 0x00000020); - if (!nv_wait(mmu, 0x100808, 0x00000001, 0x00000001)) - nv_error(mmu, "timeout: 0x%08x\n", nvkm_rd32(device, 0x100808)); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100808) & 0x00000001) + break; + ); nvkm_wr32(device, 0x100808, 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index 1d7e1aa7e7d3d..45b5b5ac3e9bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -182,7 +182,10 @@ nv50_vm_flush(struct nvkm_vm *vm) } nvkm_wr32(device, 0x100c80, (vme << 16) | 1); - if (!nv_wait(mmu, 0x100c80, 0x00000001, 0x00000000)) + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ) < 0) nv_error(mmu, "vm flush timeout: engine %d\n", vme); } mutex_unlock(&nv_subdev(mmu)->mutex); -- GitLab From dd4bb3eccc806e78baee3009aa466466daae0f29 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5401/7006] drm/nouveau/pmu: switch to new-style timer macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 26 +++++++++++++++---- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 11 +++++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c | 5 +++- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index b754b65f2c36f..29c692c661da3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -43,7 +43,11 @@ nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], /* wait for a free slot in the fifo */ addr = nvkm_rd32(device, 0x10a4a0); - if (!nv_wait_ne(pmu, 0x10a4b0, 0xffffffff, addr ^ 8)) + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x10a4b0); + if (tmp != (addr ^ 8)) + break; + ) < 0) return -EBUSY; /* we currently only support a single process at a time waiting @@ -203,11 +207,17 @@ _nvkm_pmu_init(struct nvkm_object *object) /* prevent previous ucode from running, wait for idle, reset */ nvkm_wr32(device, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ - nv_wait(pmu, 0x10a04c, 0xffffffff, 0x00000000); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x10a04c)) + break; + ); nvkm_mask(device, 0x000200, 0x00002000, 0x00000000); nvkm_mask(device, 0x000200, 0x00002000, 0x00002000); nvkm_rd32(device, 0x000200); - nv_wait(pmu, 0x10a10c, 0x00000006, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x10a10c) & 0x00000006)) + break; + ); /* upload data segment */ nvkm_wr32(device, 0x10a1c0, 0x01000000); @@ -228,13 +238,19 @@ _nvkm_pmu_init(struct nvkm_object *object) nvkm_wr32(device, 0x10a100, 0x00000002); /* wait for valid host->pmu ring configuration */ - if (!nv_wait_ne(pmu, 0x10a4d0, 0xffffffff, 0x00000000)) + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x10a4d0)) + break; + ) < 0) return -EBUSY; pmu->send.base = nvkm_rd32(device, 0x10a4d0) & 0x0000ffff; pmu->send.size = nvkm_rd32(device, 0x10a4d0) >> 16; /* wait for valid pmu->host ring configuration */ - if (!nv_wait_ne(pmu, 0x10a4dc, 0xffffffff, 0x00000000)) + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x10a4dc)) + break; + ) < 0) return -EBUSY; pmu->recv.base = nvkm_rd32(device, 0x10a4dc) & 0x0000ffff; pmu->recv.size = nvkm_rd32(device, 0x10a4dc) >> 16; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index a6d6162a36186..469177e34563c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -36,10 +36,13 @@ magic_(struct nvkm_device *device, u32 ctrl, int size) nvkm_wr32(device, 0x00c800, 0x00000000); nvkm_wr32(device, 0x00c808, 0x00000000); nvkm_wr32(device, 0x00c800, ctrl); - if (nv_wait(device, 0x00c800, 0x40000000, 0x40000000)) { - while (size--) - nvkm_wr32(device, 0x00c804, 0x00000000); - } + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x00c800) & 0x40000000) { + while (size--) + nvkm_wr32(device, 0x00c804, 0x00000000); + break; + } + ); nvkm_wr32(device, 0x00c800, 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c index 37ab487d60aa0..162c007d49c8f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c @@ -67,7 +67,10 @@ gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nvkm_mask(device, 0x0206b4, 0x00000000, 0x00000000); for (i = 0; i < ARRAY_SIZE(magic); i++) { nvkm_wr32(device, magic[i].addr, magic[i].data); - nv_wait(pmu, magic[i].addr, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, magic[i].addr) & 0x80000000)) + break; + ); } nvkm_mask(device, 0x10a78c, 0x00000002, 0x00000000); -- GitLab From 6ed5c1682425e29913785977cccca67ff3dec5f1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5402/7006] drm/nouveau/falcon: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 03ff19a68985e..408d9c7d5e908 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -102,10 +102,17 @@ _nvkm_falcon_init(struct nvkm_object *object) /* wait for 'uc halted' to be signalled before continuing */ if (falcon->secret && falcon->version < 4) { - if (!falcon->version) - nv_wait(falcon, 0x008, 0x00000010, 0x00000010); - else - nv_wait(falcon, 0x180, 0x80000000, 0); + if (!falcon->version) { + nvkm_msec(device, 2000, + if (nv_ro32(falcon, 0x008) & 0x00000010) + break; + ); + } else { + nvkm_msec(device, 2000, + if (!(nv_ro32(falcon, 0x180) & 0x80000000)) + break; + ); + } nv_wo32(falcon, 0x004, 0x00000010); } -- GitLab From 3a020b4dfc3a6c79f144b2c6786d86b33cda64d9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5403/7006] drm/nouveau/disp: switch to new-style timer macros Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 20 +++++++-- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 38 ++++++++++++---- .../drm/nouveau/nvkm/engine/disp/hdagf110.c | 12 +++++- .../drm/nouveau/nvkm/engine/disp/hdagt215.c | 12 +++++- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 43 ++++++++++++++----- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 10 ++++- .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 5 ++- .../drm/nouveau/nvkm/engine/disp/sorgm204.c | 5 ++- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 16 +++++-- 9 files changed, 127 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index acc9fbb4ae045..7139ff6b17648 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -54,9 +54,15 @@ nv50_dac_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); nvkm_mask(device, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat); - nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); return 0; } @@ -82,7 +88,10 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) return ret; nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80150000); - nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); nvkm_wr32(device, 0x61a00c + doff, 0x00100000 | loadval); mdelay(9); @@ -90,7 +99,10 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) loadval = nvkm_mask(device, 0x61a00c + doff, 0xffffffff, 0x00000000); nvkm_mask(device, 0x61a004 + doff, 0x807f0000, 0x80550000); - nv_wait(disp, 0x61a004 + doff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61a004 + doff) & 0x80000000)) + break; + ); nv_debug(disp, "DAC%d sense: 0x%08x\n", outp->or, loadval); if (!(loadval & 0x80000000)) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index 293b41bd24682..ef728c969ecb9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -115,7 +115,10 @@ gf110_disp_dmac_init(struct nvkm_object *object) nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); /* wait for it to go inactive */ - if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { nv_error(dmac, "init: 0x%08x\n", nvkm_rd32(device, 0x610490 + (chid * 0x10))); return -EBUSY; @@ -135,7 +138,10 @@ gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) /* deactivate channel */ nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); - if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000)) + break; + ) < 0) { nv_error(dmac, "fini: 0x%08x\n", nvkm_rd32(device, 0x610490 + (chid * 0x10))); if (suspend) @@ -317,7 +323,10 @@ gf110_disp_core_init(struct nvkm_object *object) nvkm_wr32(device, 0x610490, 0x01000013); /* wait for it to go inactive */ - if (!nv_wait(disp, 0x610490, 0x80000000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) + break; + ) < 0) { nv_error(mast, "init: 0x%08x\n", nvkm_rd32(device, 0x610490)); return -EBUSY; } @@ -335,7 +344,10 @@ gf110_disp_core_fini(struct nvkm_object *object, bool suspend) /* deactivate channel */ nvkm_mask(device, 0x610490, 0x00000010, 0x00000000); nvkm_mask(device, 0x610490, 0x00000003, 0x00000000); - if (!nv_wait(disp, 0x610490, 0x001e0000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x001e0000)) + break; + ) < 0) { nv_error(mast, "fini: 0x%08x\n", nvkm_rd32(device, 0x610490)); if (suspend) return -EBUSY; @@ -560,7 +572,11 @@ gf110_disp_pioc_init(struct nvkm_object *object) /* activate channel */ nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001); - if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) { + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x610490 + (chid * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { nv_error(pioc, "init: 0x%08x\n", nvkm_rd32(device, 0x610490 + (chid * 0x10))); return -EBUSY; @@ -578,7 +594,10 @@ gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) int chid = pioc->base.chid; nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); - if (!nv_wait(disp, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { nv_error(pioc, "timeout: 0x%08x\n", nvkm_rd32(device, 0x610490 + (chid * 0x10))); if (suspend) @@ -707,10 +726,11 @@ gf110_disp_main_init(struct nvkm_object *object) if (nvkm_rd32(device, 0x6100ac) & 0x00000100) { nvkm_wr32(device, 0x6100ac, 0x00000100); nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); - if (!nv_wait(disp, 0x6194e8, 0x00000002, 0x00000000)) { - nv_error(disp, "timeout acquiring display\n"); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) + break; + ) < 0) return -EBUSY; - } } /* point at display engine memory area (hash table, objects) */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c index a04ef426840de..2d8f68792d802 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c @@ -54,7 +54,11 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { nvkm_mask(device, 0x616618 + hoff, 0x8000000c, 0x80000001); - nv_wait(disp, 0x616618 + hoff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x616618 + hoff); + if (!(tmp & 0x80000000)) + break; + ); } nvkm_mask(device, 0x616548 + hoff, 0x00000070, 0x00000000); for (i = 0; i < size; i++) @@ -65,7 +69,11 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) } else { if (outp->info.type == DCB_OUTPUT_DP) { nvkm_mask(device, 0x616618 + hoff, 0x80000001, 0x80000000); - nv_wait(disp, 0x616618 + hoff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x616618 + hoff); + if (!(tmp & 0x80000000)) + break; + ); } nvkm_mask(device, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index c2ae112225fcc..0aba48c586ee7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -51,7 +51,11 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) if (size && args->v0.data[0]) { if (outp->info.type == DCB_OUTPUT_DP) { nvkm_mask(device, 0x61c1e0 + soff, 0x8000000d, 0x80000001); - nv_wait(disp, 0x61c1e0 + soff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); + if (!(tmp & 0x80000000)) + break; + ); } for (i = 0; i < size; i++) nvkm_wr32(device, 0x61c440 + soff, (i << 8) | args->v0.data[0]); @@ -61,7 +65,11 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) } else { if (outp->info.type == DCB_OUTPUT_DP) { nvkm_mask(device, 0x61c1e0 + soff, 0x80000001, 0x80000000); - nv_wait(disp, 0x61c1e0 + soff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x61c1e0 + soff); + if (!(tmp & 0x80000000)) + break; + ); } nvkm_mask(device, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index a57b7d0c4445b..0cf02347178d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -279,7 +279,10 @@ nv50_disp_dmac_init(struct nvkm_object *object) nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013); /* wait for it to go inactive */ - if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { nv_error(dmac, "init timeout, 0x%08x\n", nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; @@ -299,7 +302,10 @@ nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) /* deactivate channel */ nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); - if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000)) + break; + ) < 0) { nv_error(dmac, "fini timeout, 0x%08x\n", nvkm_rd32(device, 0x610200 + (chid * 0x10))); if (suspend) @@ -547,7 +553,10 @@ nv50_disp_core_init(struct nvkm_object *object) nvkm_wr32(device, 0x610200, 0x01000013); /* wait for it to go inactive */ - if (!nv_wait(disp, 0x610200, 0x80000000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200) & 0x80000000)) + break; + ) < 0) { nv_error(mast, "init: 0x%08x\n", nvkm_rd32(device, 0x610200)); return -EBUSY; } @@ -565,7 +574,10 @@ nv50_disp_core_fini(struct nvkm_object *object, bool suspend) /* deactivate channel */ nvkm_mask(device, 0x610200, 0x00000010, 0x00000000); nvkm_mask(device, 0x610200, 0x00000003, 0x00000000); - if (!nv_wait(disp, 0x610200, 0x001e0000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200) & 0x001e0000)) + break; + ) < 0) { nv_error(mast, "fini: 0x%08x\n", nvkm_rd32(device, 0x610200)); if (suspend) return -EBUSY; @@ -819,14 +831,21 @@ nv50_disp_pioc_init(struct nvkm_object *object) return ret; nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); - if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { nv_error(pioc, "timeout0: 0x%08x\n", nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001); - if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) { + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x610200 + (chid * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { nv_error(pioc, "timeout1: 0x%08x\n", nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; @@ -844,7 +863,10 @@ nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) int chid = pioc->base.chid; nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); - if (!nv_wait(disp, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { nv_error(pioc, "timeout: 0x%08x\n", nvkm_rd32(device, 0x610200 + (chid * 0x10))); if (suspend) @@ -1192,10 +1214,11 @@ nv50_disp_main_init(struct nvkm_object *object) if (nvkm_rd32(device, 0x610024) & 0x00000100) { nvkm_wr32(device, 0x610024, 0x00000100); nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); - if (!nv_wait(disp, 0x6194e8, 0x00000002, 0x00000000)) { - nv_error(disp, "timeout acquiring display\n"); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) + break; + ) < 0) return -EBUSY; - } } /* point at display engine memory area (hash table, objects) */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index d93d5945a2d80..ac0dd18b98c18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -163,9 +163,15 @@ nv50_pior_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(disp, 0x61e004 + soff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nv_wait(disp, 0x61e004 + soff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); disp->pior.type[outp->or] = type; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index ed4d13222d9d9..d921efe7e7316 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -75,7 +75,10 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); - nv_wait(disp, 0x61c034 + soff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) + break; + ); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 4c61702ede8af..8792dcf4a4687 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -85,7 +85,10 @@ gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); - nv_wait(disp, 0x61c034 + soff, 0x80000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c034 + soff) & 0x80000000)) + break; + ); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index bf61ce7bac113..6cb60572eaa5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -49,9 +49,19 @@ nv50_sor_power(NV50_DISP_MTHD_V1) } else return ret; - nv_wait(disp, 0x61c004 + soff, 0x80000000, 0x00000000); + + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) + break; + ); nvkm_mask(device, 0x61c004 + soff, 0x80000001, 0x80000000 | stat); - nv_wait(disp, 0x61c004 + soff, 0x80000000, 0x00000000); - nv_wait(disp, 0x61c030 + soff, 0x10000000, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c004 + soff) & 0x80000000)) + break; + ); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61c030 + soff) & 0x10000000)) + break; + ); return 0; } -- GitLab From af3082b3c621e75371dc6d11fac5a2dc2b19b1bc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5404/7006] drm/nouveau/fifo: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 5 ++++- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 5 ++++- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 5 ++++- drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 8 +++++--- drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 5 ++++- 5 files changed, 21 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index dfc27a0d2ac29..b2da05d2f76d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -106,7 +106,10 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); - done = nv_wait_ne(fifo, 0x0032fc, 0xffffffff, 0xffffffff); + done = nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ) >= 0; nvkm_wr32(device, 0x002520, save); if (!done) { nv_error(fifo, "channel %d [%s] unload timeout\n", diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index f714bda4230f6..503ea80883452 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -166,7 +166,10 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, } nvkm_wr32(device, 0x002634, chan->base.chid); - if (!nv_wait(fifo, 0x002634, 0xffffffff, chan->base.chid)) { + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x002634) == chan->base.chid) + break; + ) < 0) { nv_error(fifo, "channel %d [%s] kick timeout\n", chan->base.chid, nvkm_client_name(chan)); if (suspend) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index cec1281dbd122..cc81511298883 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -174,7 +174,10 @@ gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) struct nvkm_device *device = fifo->base.engine.subdev.device; nvkm_wr32(device, 0x002634, chan->base.chid); - if (!nv_wait(fifo, 0x002634, 0x100000, 0x000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) + break; + ) < 0) { nv_error(fifo, "channel %d [%s] kick timeout\n", chan->base.chid, nvkm_client_name(chan)); return -EBUSY; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 6339b473feb0a..214bf122b19c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -321,9 +321,11 @@ __acquires(fifo->base.lock) * to avoid this, we invalidate the most recently calculated * instance. */ - if (!nv_wait(fifo, NV04_PFIFO_CACHE1_PULL0, - NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000)) - nv_warn(fifo, "timeout idling puller\n"); + nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, NV04_PFIFO_CACHE1_PULL0); + if (!(tmp & NV04_PFIFO_CACHE1_PULL0_HASH_BUSY)) + break; + ); if (nvkm_rd32(device, NV04_PFIFO_CACHE1_PULL0) & NV04_PFIFO_CACHE1_PULL0_HASH_FAILED) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 3a868f9c0a39b..e0188a674974a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -135,7 +135,10 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, /* do the kickoff... */ nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); - if (!nv_wait_ne(fifo, 0x0032fc, 0xffffffff, 0xffffffff)) { + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ) < 0) { nv_error(fifo, "channel %d [%s] unload timeout\n", chan->base.chid, nvkm_client_name(chan)); if (suspend) -- GitLab From c4584adc37720b65ae44a84c660d47b3ebcf7dfb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5405/7006] drm/nouveau/gr: switch to new-style timer macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 23 ++++--- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 61 +++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 12 +++- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 15 ++++- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 6 +- 7 files changed, 87 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 43b393f4cd4de..ccce293191a4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1312,7 +1312,10 @@ gf100_grctx_generate(struct gf100_gr *gr) nvkm_wr32(device, 0x100cb8, (chan->addr + 0x1000) >> 8); nvkm_wr32(device, 0x100cbc, 0x80000001); - nv_wait(gr, 0x100c80, 0x00008000, 0x00008000); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x100c80) & 0x00008000) + break; + ); /* setup default state for mmio list construction */ info.gr = gr; @@ -1326,8 +1329,10 @@ gf100_grctx_generate(struct gf100_gr *gr) nvkm_wr32(device, 0x409840, 0x00000030); nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); nvkm_wr32(device, 0x409504, 0x00000003); - if (!nv_wait(gr, 0x409800, 0x00000010, 0x00000010)) - nv_error(gr, "load_ctx timeout\n"); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x00000010) + break; + ); nv_wo32(chan, 0x8001c, 1); nv_wo32(chan, 0x80020, 0); @@ -1338,8 +1343,10 @@ gf100_grctx_generate(struct gf100_gr *gr) nvkm_wr32(device, 0x409840, 0x80000000); nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); nvkm_wr32(device, 0x409504, 0x00000001); - if (!nv_wait(gr, 0x409800, 0x80000000, 0x80000000)) - nv_error(gr, "HUB_SET_CHAN timeout\n"); + nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x80000000) + break; + ); } oclass->main(gr, &info); @@ -1349,8 +1356,10 @@ gf100_grctx_generate(struct gf100_gr *gr) */ nvkm_mask(device, 0x409b04, 0x80000000, 0x00000000); nvkm_wr32(device, 0x409000, 0x00000100); - if (!nv_wait(gr, 0x409b00, 0x80000000, 0x00000000)) { - nv_error(gr, "grctx template channel unload timeout\n"); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x409b00) & 0x80000000)) + break; + ) < 0) { ret = -EBUSY; goto done; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index b692e8e2b9822..4bfec3aa0deef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -741,7 +741,10 @@ gf100_gr_icmd(struct gf100_gr *gr, const struct gf100_gr_pack *p) */ if ((addr & 0xffff) == 0xe100) gf100_gr_wait_idle(gr); - nv_wait(gr, 0x400700, 0x00000004, 0x00000000); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x400700) & 0x00000004)) + break; + ); addr += init->pitch; } } @@ -1312,8 +1315,11 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) nvkm_wr32(device, 0x40910c, 0x00000000); nvkm_wr32(device, 0x41a100, 0x00000002); nvkm_wr32(device, 0x409100, 0x00000002); - if (!nv_wait(gr, 0x409800, 0x00000001, 0x00000001)) - nv_warn(gr, "0x409800 wait failed\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x00000001) + break; + ) < 0) + return -EBUSY; nvkm_wr32(device, 0x409840, 0xffffffff); nvkm_wr32(device, 0x409500, 0x7fffffff); @@ -1322,54 +1328,59 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) nvkm_wr32(device, 0x409840, 0xffffffff); nvkm_wr32(device, 0x409500, 0x00000000); nvkm_wr32(device, 0x409504, 0x00000010); - if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(gr, "fuc09 req 0x10 timeout\n"); + if (nvkm_msec(device, 2000, + if ((gr->size = nvkm_rd32(device, 0x409800))) + break; + ) < 0) return -EBUSY; - } - gr->size = nvkm_rd32(device, 0x409800); nvkm_wr32(device, 0x409840, 0xffffffff); nvkm_wr32(device, 0x409500, 0x00000000); nvkm_wr32(device, 0x409504, 0x00000016); - if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(gr, "fuc09 req 0x16 timeout\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } nvkm_wr32(device, 0x409840, 0xffffffff); nvkm_wr32(device, 0x409500, 0x00000000); nvkm_wr32(device, 0x409504, 0x00000025); - if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(gr, "fuc09 req 0x25 timeout\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } if (nv_device(gr)->chipset >= 0xe0) { nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000001); nvkm_wr32(device, 0x409504, 0x00000030); - if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(gr, "fuc09 req 0x30 timeout\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } nvkm_wr32(device, 0x409810, 0xb00095c8); nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000001); nvkm_wr32(device, 0x409504, 0x00000031); - if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(gr, "fuc09 req 0x31 timeout\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } nvkm_wr32(device, 0x409810, 0x00080420); nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000001); nvkm_wr32(device, 0x409504, 0x00000032); - if (!nv_wait_ne(gr, 0x409800, 0xffffffff, 0x00000000)) { - nv_error(gr, "fuc09 req 0x32 timeout\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800)) + break; + ) < 0) return -EBUSY; - } nvkm_wr32(device, 0x409614, 0x00000070); nvkm_wr32(device, 0x409614, 0x00000770); @@ -1425,8 +1436,10 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) /* start HUB ucode running, it'll init the GPCs */ nvkm_wr32(device, 0x40910c, 0x00000000); nvkm_wr32(device, 0x409100, 0x00000002); - if (!nv_wait(gr, 0x409800, 0x80000000, 0x80000000)) { - nv_error(gr, "HUB_INIT timed out\n"); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x409800) & 0x80000000) + break; + ) < 0) { gf100_gr_ctxctl_debug(gr); return -EBUSY; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index 12b34c7a14778..ed944aa6b81b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -220,12 +220,20 @@ gk20a_gr_dtor(struct nvkm_object *object) static int gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) { - if (!nv_wait(gr, 0x40910c, 0x6, 0x0)) { + struct nvkm_device *device = gr->base.engine.subdev.device; + + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x40910c) & 0x00000006)) + break; + ) < 0) { nv_error(gr, "FECS mem scrubbing timeout\n"); return -ETIMEDOUT; } - if (!nv_wait(gr, 0x41a10c, 0x6, 0x0)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x41a10c) & 0x00000006)) + break; + ) < 0) { nv_error(gr, "GPCCS mem scrubbing timeout\n"); return -ETIMEDOUT; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index d1792ef62712c..33f3b8219213a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1206,7 +1206,10 @@ nv04_gr_idle(void *obj) if (nv_device(obj)->card_type == NV_40) mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL; - if (!nv_wait(gr, NV04_PGRAPH_STATUS, mask, 0)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, NV04_PGRAPH_STATUS) & mask)) + break; + ) < 0) { nv_error(gr, "idle timed out with status 0x%08x\n", nvkm_rd32(device, NV04_PGRAPH_STATUS)); return false; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 8e264f79c0df9..21aff9b5ed408 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -127,7 +127,10 @@ nv20_gr_context_fini(struct nvkm_object *object, bool suspend) if (chan->chid == chid) { nvkm_wr32(device, 0x400784, nv_gpuobj(chan)->addr >> 4); nvkm_wr32(device, 0x400788, 0x00000002); - nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x400700)) + break; + ); nvkm_wr32(device, 0x400144, 0x10000000); nvkm_mask(device, 0x400148, 0xff000000, 0x1f000000); } @@ -289,12 +292,18 @@ nv20_gr_init(struct nvkm_object *object) nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x003d0000); for (i = 0; i < 15; i++) nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); - nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x400700)) + break; + ); } else { nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x02c80000); for (i = 0; i < 32; i++) nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); - nv_wait(gr, 0x400700, 0xffffffff, 0x00000000); + nvkm_msec(device, 2000, + if (!nvkm_rd32(device, 0x400700)) + break; + ); } nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index edcaa65b1e092..7455049ff1780 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -167,7 +167,10 @@ nv40_gr_context_fini(struct nvkm_object *object, bool suspend) nvkm_wr32(device, 0x400784, inst); nvkm_mask(device, 0x400310, 0x00000020, 0x00000020); nvkm_mask(device, 0x400304, 0x00000001, 0x00000001); - if (!nv_wait(gr, 0x400300, 0x00000001, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x400300) & 0x00000001)) + break; + ) < 0) { u32 insn = nvkm_rd32(device, 0x400308); nv_warn(gr, "ctxprog timeout 0x%08x\n", insn); ret = -EBUSY; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index ade34d8a4ea04..3b482bcc22d08 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -285,8 +285,10 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) nvkm_wr32(device, 0x100c80, 0x00000001); - if (!nv_wait(gr, 0x100c80, 0x00000001, 0x00000000)) - nv_error(gr, "vm flush timeout\n"); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ); nvkm_mask(device, 0x400500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); return timeout ? -EBUSY : 0; -- GitLab From 37eabb030c03539996bff662e4adb078a7f8b2a6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5406/7006] drm/nouveau/mpeg: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 5 ++++- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 2b86575ddcde9..4ea554e81a296 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -288,7 +288,10 @@ nv31_mpeg_init(struct nvkm_object *object) nvkm_wr32(device, 0x00b100, 0xffffffff); nvkm_wr32(device, 0x00b140, 0xffffffff); - if (!nv_wait(mpeg, 0x00b200, 0x00000001, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) + break; + ) < 0) { nv_error(mpeg, "timeout 0x%08x\n", nvkm_rd32(device, 0x00b200)); return -EBUSY; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index f83c78fa18a10..586ff06705bab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -204,7 +204,10 @@ nv50_mpeg_init(struct nvkm_object *object) nvkm_wr32(device, 0x00b100, 0xffffffff); nvkm_wr32(device, 0x00b140, 0xffffffff); - if (!nv_wait(mpeg, 0x00b200, 0x00000001, 0x00000000)) { + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) + break; + ) < 0) { nv_error(mpeg, "timeout 0x%08x\n", nvkm_rd32(device, 0x00b200)); return -EBUSY; } -- GitLab From 5444204036b2e3a4aeeef6265897df3a9976bf97 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5407/7006] drm/nouveau: switch to new-style timer macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/dac.c | 24 ++++++++------- drivers/gpu/drm/nouveau/dispnv04/hw.c | 11 +++++-- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 -- .../drm/nouveau/include/nvkm/subdev/timer.h | 30 ------------------- drivers/gpu/drm/nouveau/nv50_display.c | 16 ++++++++-- 5 files changed, 35 insertions(+), 48 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index 2408728942b54..81c1efb8b3b6b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -66,7 +66,6 @@ int nv04_dac_output_offset(struct drm_encoder *encoder) static int sample_load_twice(struct drm_device *dev, bool sense[2]) { struct nvif_device *device = &nouveau_drm(dev)->device; - struct nvkm_timer *tmr = nvxx_timer(device); int i; for (i = 0; i < 2; i++) { @@ -80,17 +79,22 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2]) * use a 10ms timeout (guards against crtc being inactive, in * which case blank state would never change) */ - if (!nvkm_timer_wait_eq(tmr, 10000000, - NV_PRMCIO_INP0__COLOR, - 0x00000001, 0x00000000)) + if (nvif_msec(device, 10, + if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) + break; + ) < 0) return -EBUSY; - if (!nvkm_timer_wait_eq(tmr, 10000000, - NV_PRMCIO_INP0__COLOR, - 0x00000001, 0x00000001)) + + if (nvif_msec(device, 10, + if ( (nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) + break; + ) < 0) return -EBUSY; - if (!nvkm_timer_wait_eq(tmr, 10000000, - NV_PRMCIO_INP0__COLOR, - 0x00000001, 0x00000000)) + + if (nvif_msec(device, 10, + if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) + break; + ) < 0) return -EBUSY; udelay(100); diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c index e0d196e67000e..5039bb5305232 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.c +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c @@ -661,7 +661,6 @@ nv_load_state_ext(struct drm_device *dev, int head, { struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_device *device = &drm->device; - struct nvkm_timer *tmr = nvxx_timer(device); struct nv04_crtc_reg *regp = &state->crtc_reg[head]; uint32_t reg900; int i; @@ -741,8 +740,14 @@ nv_load_state_ext(struct drm_device *dev, int head, if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) { /* Not waiting for vertical retrace before modifying CRE_53/CRE_54 causes lockups. */ - nvkm_timer_wait_eq(tmr, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8); - nvkm_timer_wait_eq(tmr, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0); + nvif_msec(device, 650, + if ( (nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 8)) + break; + ); + nvif_msec(device, 650, + if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 8)) + break; + ); } wr_cio_state(dev, head, regp, NV_CIO_CRE_42); diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 8bd60dd3b1615..077651f9b7e9d 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -68,8 +68,6 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_clk(a) nvkm_clk(nvxx_device(a)) #define nvxx_i2c(a) nvkm_i2c(nvxx_device(a)) #define nvxx_timer(a) nvkm_timer(nvxx_device(a)) -#define nvxx_wait(a,b,c,d) nv_wait(nvxx_timer(a), (b), (c), (d)) -#define nvxx_wait_cb(a,b,c) nv_wait_cb(nvxx_timer(a), (b), (c)) #define nvxx_therm(a) nvkm_therm(nvxx_device(a)) #include diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index b26ae6fa5ba7c..4ae73689488bd 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -51,36 +51,6 @@ void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *); #define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond) #define nvkm_msec(d,m,cond...) nvkm_usec((d), (m) * 1000, ##cond) -#define nvkm_timer_wait_eq(o,n,a,m,v) ({ \ - struct nvkm_device *__device = nv_device(o); \ - nvkm_nsec(__device, (n), \ - if ((nvkm_rd32(__device, (a)) & (m)) == (v)) \ - break; \ - ) >= 0; \ -}) -#define nvkm_timer_wait_ne(o,n,a,m,v) ({ \ - struct nvkm_device *__device = nv_device(o); \ - nvkm_nsec(__device, (n), \ - if ((nvkm_rd32(__device, (a)) & (m)) != (v)) \ - break; \ - ) >= 0; \ -}) -#define nvkm_timer_wait_cb(o,n,c,d) ({ \ - struct nvkm_device *__device = nv_device(o); \ - nvkm_nsec(__device, (n), \ - if (c(d)) \ - break; \ - ) >= 0; \ -}) - -#define NV_WAIT_DEFAULT 2000000000ULL -#define nv_wait(o,a,m,v) \ - nvkm_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v)) -#define nv_wait_ne(o,a,m,v) \ - nvkm_timer_wait_ne((o), NV_WAIT_DEFAULT, (a), (m), (v)) -#define nv_wait_cb(o,c,d) \ - nvkm_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d)) - struct nvkm_timer { struct nvkm_subdev subdev; u64 (*read)(struct nvkm_timer *); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 981342d142ff6..41425f2fda82a 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -413,6 +413,7 @@ static u32 * evo_wait(void *evoc, int nr) { struct nv50_dmac *dmac = evoc; + struct nvif_device *device = nvif_device(&dmac->base.user); u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4; mutex_lock(&dmac->lock); @@ -420,7 +421,10 @@ evo_wait(void *evoc, int nr) dmac->ptr[put] = 0x20000000; nvif_wr32(&dmac->base.user, 0x0000, 0x00000000); - if (!nvxx_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) { + if (nvif_msec(device, 2000, + if (!nvif_rd32(&dmac->base.user, 0x0004)) + break; + ) < 0) { mutex_unlock(&dmac->lock); nv_error(nvxx_object(&dmac->base.user), "channel stalled\n"); return NULL; @@ -480,7 +484,10 @@ evo_sync(struct drm_device *dev) evo_data(push, 0x00000000); evo_data(push, 0x00000000); evo_kick(push, mast); - if (nv_wait_cb(nvxx_device(device), evo_sync_wait, disp->sync)) + if (nvif_msec(device, 2000, + if (evo_sync_wait(disp->sync)) + break; + ) >= 0) return 0; } @@ -535,7 +542,10 @@ nv50_display_flip_stop(struct drm_crtc *crtc) evo_kick(push, flip.chan); } - nv_wait_cb(nvxx_device(device), nv50_display_flip_wait, &flip); + nvif_msec(device, 2000, + if (nv50_display_flip_wait(&flip)) + break; + ); } int -- GitLab From 6594363b9f765e569feb6222d7d07e19db3fa460 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5408/7006] drm/nouveau/core: type-safe printk macros These require an explicit pointers to nvkm_object/nvkm_subdev/nvkm_device, depending on which macros are used. This is unlike the previous macros which take a void *, and work for anything derived from nvkm_object (by way of some awful heuristics). The output will be a bit confused until everything has been transitioned, as the logging format used is a more standard style that previously. In addition, usage of pr_cont(), which doesn't work correctly with the dev_*() printk functions (and was potentially racy to begin with), will be replaced. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/client.h | 12 ++++++++++++ .../drm/nouveau/include/nvkm/core/device.h | 15 +++++++++++++++ .../gpu/drm/nouveau/include/nvkm/core/enum.h | 1 + .../drm/nouveau/include/nvkm/core/subdev.h | 19 ++++++++++++++----- drivers/gpu/drm/nouveau/nvkm/core/enum.c | 17 +++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 1 + 6 files changed, 60 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index a35b382445022..bcd2a35836516 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -52,4 +52,16 @@ int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *, int nvkm_client_notify_del(struct nvkm_client *, int index); int nvkm_client_notify_get(struct nvkm_client *, int index); int nvkm_client_notify_put(struct nvkm_client *, int index); + +/* logging for client-facing objects */ +#define nvif_printk(o,l,p,f,a...) do { \ + struct nvkm_object *_object = (o); \ + struct nvkm_client *_client = nvkm_client(_object); \ + if (_client->debug >= NV_DBG_##l) \ + printk(KERN_##p "nouveau: %s: "f, _client->name, ##a); \ +} while(0) +#define nvif_error(o,f,a...) nvif_printk((o), ERROR, ERR, f, ##a) +#define nvif_debug(o,f,a...) nvif_printk((o), DEBUG, INFO, f, ##a) +#define nvif_trace(o,f,a...) nvif_printk((o), TRACE, INFO, f, ##a) +#define nvif_ioctl(o,f,a...) nvif_trace((o), "ioctl: "f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 14f7d197e479c..ffff6fd5a3482 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -214,4 +214,19 @@ enum nv_bus_type { int nvkm_device_create_(void *, enum nv_bus_type type, u64 name, const char *sname, const char *cfg, const char *dbg, int, void **); + +/* device logging */ +#define nvdev_printk_(d,l,p,f,a...) do { \ + struct nvkm_device *_device = (d); \ + if (_device->engine.subdev.debug >= (l)) \ + dev_##p(_device->dev, f, ##a); \ +} while(0) +#define nvdev_printk(d,l,p,f,a...) nvdev_printk_((d), NV_DBG_##l, p, f, ##a) +#define nvdev_fatal(d,f,a...) nvdev_printk((d), FATAL, crit, f, ##a) +#define nvdev_error(d,f,a...) nvdev_printk((d), ERROR, err, f, ##a) +#define nvdev_warn(d,f,a...) nvdev_printk((d), WARN, notice, f, ##a) +#define nvdev_info(d,f,a...) nvdev_printk((d), INFO, info, f, ##a) +#define nvdev_debug(d,f,a...) nvdev_printk((d), DEBUG, info, f, ##a) +#define nvdev_trace(d,f,a...) nvdev_printk((d), TRACE, info, f, ##a) +#define nvdev_spam(d,f,a...) nvdev_printk((d), SPAM, dbg, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h index e76f76f115e9e..573b1eef4b396 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h @@ -18,4 +18,5 @@ struct nvkm_bitfield { }; void nvkm_bitfield_print(const struct nvkm_bitfield *, u32 value); +void nvkm_snprintbf(char *, int, const struct nvkm_bitfield *, u32 value); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index ad516cf24f6cd..e146f2758b079 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -11,7 +11,7 @@ struct nvkm_subdev { struct nvkm_device *device; struct mutex mutex; - const char *name; + const char *name, *sname; u32 debug; u32 unit; @@ -53,11 +53,20 @@ void _nvkm_subdev_dtor(struct nvkm_object *); int _nvkm_subdev_init(struct nvkm_object *); int _nvkm_subdev_fini(struct nvkm_object *, bool suspend); -#define s_printk(s,l,f,a...) do { \ - if ((s)->debug >= OS_DBG_##l) { \ - nv_printk((s)->base.parent, (s)->name, l, f, ##a); \ - } \ +/* subdev logging */ +#define nvkm_printk_(s,l,p,f,a...) do { \ + struct nvkm_subdev *_subdev = (s); \ + if (_subdev->debug >= (l)) \ + dev_##p(_subdev->device->dev, "%s: "f, _subdev->sname, ##a); \ } while(0) +#define nvkm_printk(s,l,p,f,a...) nvkm_printk_((s), NV_DBG_##l, p, f, ##a) +#define nvkm_fatal(s,f,a...) nvkm_printk((s), FATAL, crit, f, ##a) +#define nvkm_error(s,f,a...) nvkm_printk((s), ERROR, err, f, ##a) +#define nvkm_warn(s,f,a...) nvkm_printk((s), WARN, notice, f, ##a) +#define nvkm_info(s,f,a...) nvkm_printk((s), INFO, info, f, ##a) +#define nvkm_debug(s,f,a...) nvkm_printk((s), DEBUG, info, f, ##a) +#define nvkm_trace(s,f,a...) nvkm_printk((s), TRACE, info, f, ##a) +#define nvkm_spam(s,f,a...) nvkm_printk((s), SPAM, dbg, f, ##a) #include #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/enum.c b/drivers/gpu/drm/nouveau/nvkm/core/enum.c index 4f92bfc13d6bd..2cfaec4061940 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/enum.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/enum.c @@ -64,3 +64,20 @@ nvkm_bitfield_print(const struct nvkm_bitfield *bf, u32 value) if (value) pr_cont(" (unknown bits 0x%08x)", value); } + +void +nvkm_snprintbf(char *data, int size, const struct nvkm_bitfield *bf, u32 value) +{ + bool space = false; + while (size >= 1 && bf->name) { + if (value & bf->mask) { + int this = snprintf(data, size, "%s%s", + space ? " " : "", bf->name); + size -= this; + data += this; + space = true; + } + bf++; + } + data[0] = '\0'; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index dd2cf44bd6a11..476add5a4aea2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -111,6 +111,7 @@ nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine, __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key); subdev->name = subname; + subdev->sname = sysname; if (parent) { struct nvkm_device *device = nv_device(parent); -- GitLab From 0df18e6d52fab22e841e734c384c86f3b7b762b8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5409/7006] drm/nouveau/bar: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 664a1789500ae..0cdb49e983ab9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -55,7 +55,7 @@ nvkm_barobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, barobj->iomem = ioremap(nv_device_resource_start(device, 3) + (u32)barobj->vma.offset, mem->size << 12); if (!barobj->iomem) { - nv_warn(bar, "PRAMIN ioremap failed\n"); + nvkm_warn(&bar->subdev, "PRAMIN ioremap failed\n"); return -ENOMEM; } -- GitLab From 60b29d2071795d322221cfcfe377e6778b09ca90 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5410/7006] drm/nouveau/bios: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bios/M0203.c | 5 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/base.c | 15 +++++----- .../gpu/drm/nouveau/nvkm/subdev/bios/dcb.c | 11 +++---- .../gpu/drm/nouveau/nvkm/subdev/bios/i2c.c | 5 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/image.c | 5 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 9 +++--- .../gpu/drm/nouveau/nvkm/subdev/bios/mxm.c | 13 +++++---- .../gpu/drm/nouveau/nvkm/subdev/bios/npde.c | 5 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/pcir.c | 5 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 5 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 29 +++++++++++-------- .../nouveau/nvkm/subdev/bios/shadowramin.c | 11 +++---- .../gpu/drm/nouveau/nvkm/subdev/bios/therm.c | 6 ++-- 13 files changed, 70 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c index 08eb03fbc203b..941db974f897d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c @@ -103,12 +103,13 @@ u32 nvbios_M0203Em(struct nvkm_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr, struct nvbios_M0203E *info) { + struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_M0203T M0203T; u8 cnt, len, idx = 0xff; u32 data; if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) { - nv_warn(bios, "M0203T not found\n"); + nvkm_warn(subdev, "M0203T not found\n"); return 0x00000000; } @@ -119,7 +120,7 @@ nvbios_M0203Em(struct nvkm_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr, continue; return data; default: - nv_warn(bios, "M0203T type %02x\n", M0203T.type); + nvkm_warn(subdev, "M0203T type %02x\n", M0203T.type); return 0x00000000; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index 0cd9ab4ed8eec..3a01544200cd3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -134,15 +134,15 @@ nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, bios->bmp_offset = nvbios_findstr(bios->data, bios->size, "\xff\x7f""NV\0", 5); if (bios->bmp_offset) { - nv_info(bios, "BMP version %x.%x\n", - bmp_version(bios) >> 8, - bmp_version(bios) & 0xff); + nvkm_debug(&bios->subdev, "BMP version %x.%x\n", + bmp_version(bios) >> 8, + bmp_version(bios) & 0xff); } bios->bit_offset = nvbios_findstr(bios->data, bios->size, "\xff\xb8""BIT", 5); if (bios->bit_offset) - nv_info(bios, "BIT signature found\n"); + nvkm_debug(&bios->subdev, "BIT signature found\n"); /* determine the vbios version number */ if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) { @@ -159,10 +159,9 @@ nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10); } - nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n", - bios->version.major, bios->version.chip, - bios->version.minor, bios->version.micro, bios->version.patch); - + nvkm_info(&bios->subdev, "version %02x.%02x.%02x.%02x.%02x\n", + bios->version.major, bios->version.chip, + bios->version.minor, bios->version.micro, bios->version.patch); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c index 1463571717574..85976ebcb06ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c @@ -27,20 +27,21 @@ u16 dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { - struct nvkm_device *device = nv_device(bios); + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; u16 dcb = 0x0000; if (device->card_type > NV_04) dcb = nv_ro16(bios, 0x36); if (!dcb) { - nv_warn(bios, "DCB table not found\n"); + nvkm_warn(subdev, "DCB table not found\n"); return dcb; } *ver = nv_ro08(bios, dcb); if (*ver >= 0x42) { - nv_warn(bios, "DCB version 0x%02x unknown\n", *ver); + nvkm_warn(subdev, "DCB version 0x%02x unknown\n", *ver); return 0x0000; } else if (*ver >= 0x30) { @@ -86,11 +87,11 @@ dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) * * v1.1 (NV5+, maybe some NV4) is entirely unhelpful */ - nv_warn(bios, "DCB contains no useful data\n"); + nvkm_debug(subdev, "DCB contains no useful data\n"); return 0x0000; } - nv_warn(bios, "DCB header validation failed\n"); + nvkm_warn(subdev, "DCB header validation failed\n"); return 0x0000; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c index c4e1f085ee10b..d1dde7abfb24a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c @@ -38,7 +38,7 @@ dcb_i2c_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } if (i2c && *ver >= 0x42) { - nv_warn(bios, "ccb %02x not supported\n", *ver); + nvkm_warn(&bios->subdev, "ccb %02x not supported\n", *ver); return 0x0000; } @@ -70,6 +70,7 @@ dcb_i2c_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len) int dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) { + struct nvkm_subdev *subdev = &bios->subdev; u8 ver, len; u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); if (ent) { @@ -126,7 +127,7 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) case DCB_I2C_UNUSED: return 0; default: - nv_warn(bios, "unknown i2c type %d\n", info->type); + nvkm_warn(subdev, "unknown i2c type %d\n", info->type); info->type = DCB_I2C_UNUSED; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c index 1815540a0e8b3..4560bb3baa5c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c @@ -29,6 +29,7 @@ static bool nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image) { + struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_pcirT pcir; struct nvbios_npdeT npde; u8 ver; @@ -41,8 +42,8 @@ nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image) case 0x4e56: /* NV */ break; default: - nv_debug(bios, "%08x: ROM signature (%04x) unknown\n", - image->base, data); + nvkm_debug(subdev, "%08x: ROM signature (%04x) unknown\n", + image->base, data); return false; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 64d7b482674d8..b03076e9a0eff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -37,11 +37,12 @@ #include #define bioslog(lvl, fmt, args...) do { \ - nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset, \ - init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args); \ + nvkm_printk(init->subdev, lvl, info, "0x%04x[%c]: "fmt, \ + init->offset, init_exec(init) ? \ + '0' + (init->nested - 1) : ' ', ##args); \ } while(0) #define cont(fmt, args...) do { \ - if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE) \ + if (init->subdev->debug >= NV_DBG_TRACE) \ printk(fmt, ##args); \ } while(0) #define trace(fmt, args...) bioslog(TRACE, fmt, ##args) @@ -2292,7 +2293,7 @@ nvbios_init(struct nvkm_subdev *subdev, bool execute) u16 data; if (execute) - nv_info(bios, "running init tables\n"); + nvkm_debug(subdev, "running init tables\n"); while (!ret && (data = (init_script(bios, ++i)))) { struct nvbios_init init = { .subdev = subdev, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c index c4087df4f85ea..a0d7505eeed77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c @@ -28,17 +28,18 @@ u16 mxm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr) { + struct nvkm_subdev *subdev = &bios->subdev; struct bit_entry x; if (bit_entry(bios, 'x', &x)) { - nv_debug(bios, "BIT 'x' table not present\n"); + nvkm_debug(subdev, "BIT 'x' table not present\n"); return 0x0000; } *ver = x.version; *hdr = x.length; if (*ver != 1 || *hdr < 3) { - nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr); + nvkm_warn(subdev, "BIT 'x' table %d/%d unknown\n", *ver, *hdr); return 0x0000; } @@ -73,6 +74,7 @@ static u8 g98_sor_map[16] = { u8 mxm_sor_map(struct nvkm_bios *bios, u8 conn) { + struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 6) { @@ -89,7 +91,7 @@ mxm_sor_map(struct nvkm_bios *bios, u8 conn) return 0x00; } - nv_warn(bios, "unknown sor map v%02x\n", ver); + nvkm_warn(subdev, "unknown sor map v%02x\n", ver); } } @@ -102,13 +104,14 @@ mxm_sor_map(struct nvkm_bios *bios, u8 conn) if (bios->version.chip == 0x98) return g98_sor_map[conn]; - nv_warn(bios, "missing sor map\n"); + nvkm_warn(subdev, "missing sor map\n"); return 0x00; } u8 mxm_ddc_map(struct nvkm_bios *bios, u8 port) { + struct nvkm_subdev *subdev = &bios->subdev; u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 8) { @@ -125,7 +128,7 @@ mxm_ddc_map(struct nvkm_bios *bios, u8 port) return 0x00; } - nv_warn(bios, "unknown ddc map v%02x\n", ver); + nvkm_warn(subdev, "unknown ddc map v%02x\n", ver); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c index fd7dd718b2bf1..040c03a8b4f36 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c @@ -36,8 +36,9 @@ nvbios_npdeTe(struct nvkm_bios *bios, u32 base) case 0x4544504e: /* NPDE */ break; default: - nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n", - data, nv_ro32(bios, data + 0x00)); + nvkm_debug(&bios->subdev, + "%08x: NPDE signature (%08x) unknown\n", + data, nv_ro32(bios, data + 0x00)); data = 0; break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c index df5978753ae85..5e4979f98423d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c @@ -38,8 +38,9 @@ nvbios_pcirTe(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr) *ver = nv_ro08(bios, data + 0x0c); break; default: - nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n", - data, nv_ro32(bios, data + 0x00)); + nvkm_debug(&bios->subdev, + "%08x: PCIR signature (%08x) unknown\n", + data, nv_ro32(bios, data + 0x00)); data = 0; break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index d26d89abf7eb0..44088a809f680 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -221,7 +221,8 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) int nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) { - struct nvkm_device *device = bios->subdev.device; + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; u8 ver, len; u32 reg = type; u16 data; @@ -356,7 +357,7 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) info->max_p = nv_ro08(bios, data + 13); break; default: - nv_error(bios, "unknown pll limits version 0x%02x\n", ver); + nvkm_error(subdev, "unknown pll limits version 0x%02x\n", ver); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index c64a5484c9c81..aad482fe7601c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -90,25 +90,27 @@ shadow_class = { static int shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd) { + struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_image image; int score = 1; if (!nvbios_image(bios, idx, &image)) { - nv_debug(bios, "image %d invalid\n", idx); + nvkm_debug(subdev, "image %d invalid\n", idx); return 0; } - nv_debug(bios, "%08x: type %02x, %d bytes\n", - image.base, image.type, image.size); + nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", + image.base, image.type, image.size); if (!shadow_fetch(bios, image.size)) { - nv_debug(bios, "%08x: fetch failed\n", image.base); + nvkm_debug(subdev, "%08x: fetch failed\n", image.base); return 0; } switch (image.type) { case 0x00: if (nvbios_checksum(&bios->data[image.base], image.size)) { - nv_debug(bios, "%08x: checksum failed\n", image.base); + nvkm_debug(subdev, "%08x: checksum failed\n", + image.base); if (mthd->func->rw) score += 1; score += 1; @@ -142,8 +144,9 @@ static int shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name) { const struct nvbios_source *func = mthd->func; + struct nvkm_subdev *subdev = &bios->subdev; if (func->name) { - nv_debug(bios, "trying %s...\n", name ? name : func->name); + nvkm_debug(subdev, "trying %s...\n", name ? name : func->name); if (func->init) { mthd->data = func->init(bios, name); if (IS_ERR(mthd->data)) { @@ -154,7 +157,7 @@ shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name) mthd->score = shadow_score(bios, mthd); if (func->fini) func->fini(mthd->data); - nv_debug(bios, "scored %d\n", mthd->score); + nvkm_debug(subdev, "scored %d\n", mthd->score); mthd->data = bios->data; mthd->size = bios->size; bios->data = NULL; @@ -197,6 +200,8 @@ shadow_fw = { int nvbios_shadow(struct nvkm_bios *bios) { + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; struct shadow mthds[] = { { shadow_class, 0, &nvbios_of }, { shadow_class, 0, &nvbios_ramin }, @@ -212,7 +217,7 @@ nvbios_shadow(struct nvkm_bios *bios) int optlen; /* handle user-specified bios source */ - optarg = nvkm_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen); + optarg = nvkm_stropt(device->cfgopt, "NvBios", &optlen); source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL; if (source) { /* try to match one of the built-in methods */ @@ -233,7 +238,7 @@ nvbios_shadow(struct nvkm_bios *bios) } if (!best->score) { - nv_error(bios, "%s invalid\n", source); + nvkm_error(subdev, "%s invalid\n", source); kfree(source); source = NULL; } @@ -258,12 +263,12 @@ nvbios_shadow(struct nvkm_bios *bios) } if (!best->score) { - nv_fatal(bios, "unable to locate usable image\n"); + nvkm_error(subdev, "unable to locate usable image\n"); return -EINVAL; } - nv_info(bios, "using image from %s\n", best->func ? - best->func->name : source); + nvkm_debug(subdev, "using image from %s\n", best->func ? + best->func->name : source); bios->data = best->data; bios->size = best->size; kfree(source); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c index 9d0e206aef5e6..0f537c22804cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c @@ -54,7 +54,8 @@ pramin_fini(void *data) static void * pramin_init(struct nvkm_bios *bios, const char *name) { - struct nvkm_device *device = bios->subdev.device; + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; struct priv *priv = NULL; u64 addr = 0; @@ -69,7 +70,7 @@ pramin_init(struct nvkm_bios *bios, const char *name) if (device->card_type >= NV_C0) addr = nvkm_rd32(device, 0x022500); if (addr & 0x00000001) { - nv_debug(bios, "... display disabled\n"); + nvkm_debug(subdev, "... display disabled\n"); return ERR_PTR(-ENODEV); } @@ -79,11 +80,11 @@ pramin_init(struct nvkm_bios *bios, const char *name) */ addr = nvkm_rd32(device, 0x619f04); if (!(addr & 0x00000008)) { - nv_debug(bios, "... not enabled\n"); + nvkm_debug(subdev, "... not enabled\n"); return ERR_PTR(-ENODEV); } if ( (addr & 0x00000003) != 1) { - nv_debug(bios, "... not in vram\n"); + nvkm_debug(subdev, "... not in vram\n"); return ERR_PTR(-ENODEV); } @@ -96,7 +97,7 @@ pramin_init(struct nvkm_bios *bios, const char *name) /* modify bar0 PRAMIN window to cover the bios image */ if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) { - nv_error(bios, "... out of memory\n"); + nvkm_error(subdev, "... out of memory\n"); return ERR_PTR(-ENOMEM); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c index 8fbb8917b0e22..5a21d01a27fed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c @@ -37,9 +37,9 @@ therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) else if (bit_P.version == 2) therm = nv_ro16(bios, bit_P.offset + 16); else - nv_error(bios, - "unknown offset for thermal in BIT P %d\n", - bit_P.version); + nvkm_error(&bios->subdev, + "unknown offset for thermal in BIT P %d\n", + bit_P.version); } /* exit now if we haven't found the thermal table */ -- GitLab From a699a85addc747068a9ac1b2046f4313eb499bc2 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:11 +1000 Subject: [PATCH 5411/7006] drm/nouveau/bus: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bus/gf100.c | 18 ++++++------- .../gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c | 17 ++++++------ .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.c | 15 ++++++----- .../gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 26 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 18 ++++++------- 5 files changed, 49 insertions(+), 45 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c index d7e92d049c84f..1e437c7d91b0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c @@ -27,20 +27,20 @@ static void gf100_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *bus = nvkm_bus(subdev); - struct nvkm_device *device = bus->subdev.device; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x0000000e) { u32 addr = nvkm_rd32(device, 0x009084); u32 data = nvkm_rd32(device, 0x009088); - nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n", - (addr & 0x00000002) ? "write" : "read", data, - (addr & 0x00fffffc), - (stat & 0x00000002) ? "!ENGINE " : "", - (stat & 0x00000004) ? "IBUS " : "", - (stat & 0x00000008) ? "TIMEOUT " : ""); + nvkm_error(subdev, + "MMIO %s of %08x FAULT at %06x [ %s%s%s]\n", + (addr & 0x00000002) ? "write" : "read", data, + (addr & 0x00fffffc), + (stat & 0x00000002) ? "!ENGINE " : "", + (stat & 0x00000004) ? "IBUS " : "", + (stat & 0x00000008) ? "TIMEOUT " : ""); nvkm_wr32(device, 0x009084, 0x00000000); nvkm_wr32(device, 0x001100, (stat & 0x0000000e)); @@ -48,7 +48,7 @@ gf100_bus_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_error(bus, "unknown intr 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_mask(device, 0x001140, stat, 0x00000000); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c index 90549602b6576..88b6bb433c8db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c @@ -64,20 +64,21 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) int ret = 0, i; if (hwsq) { struct nvkm_bus *bus = hwsq->bus; + struct nvkm_subdev *subdev = &bus->subdev; hwsq->c.size = (hwsq->c.size + 4) / 4; if (hwsq->c.size <= bus->hwsq_size) { if (exec) ret = bus->hwsq_exec(bus, (u32 *)hwsq->c.data, - hwsq->c.size); + hwsq->c.size); if (ret) - nv_error(bus, "hwsq exec failed: %d\n", ret); + nvkm_error(subdev, "hwsq exec failed: %d\n", ret); } else { - nv_error(bus, "hwsq ucode too large\n"); + nvkm_error(subdev, "hwsq ucode too large\n"); ret = -ENOSPC; } for (i = 0; ret && i < hwsq->c.size; i++) - nv_error(bus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]); + nvkm_error(subdev, "\t%08x\n", ((u32 *)hwsq->c.data)[i]); *phwsq = NULL; kfree(hwsq); @@ -88,7 +89,7 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) void nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) { - nv_debug(hwsq->bus, "R[%06x] = 0x%08x\n", addr, data); + nvkm_debug(&hwsq->bus->subdev, "R[%06x] = %08x\n", addr, data); if (hwsq->data != data) { if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) { @@ -113,7 +114,7 @@ nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) void nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) { - nv_debug(hwsq->bus, " FLAG[%02x] = %d\n", flag, data); + nvkm_debug(&hwsq->bus->subdev, " FLAG[%02x] = %d\n", flag, data); flag += 0x80; if (data >= 0) flag += 0x20; @@ -125,7 +126,7 @@ nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) void nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data) { - nv_debug(hwsq->bus, " WAIT[%02x] = %d\n", flag, data); + nvkm_debug(&hwsq->bus->subdev, " WAIT[%02x] = %d\n", flag, data); hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data }); } @@ -138,6 +139,6 @@ nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec) shift++; } - nv_debug(hwsq->bus, " DELAY = %d ns\n", nsec); + nvkm_debug(&hwsq->bus->subdev, " DELAY = %d ns\n", nsec); hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec }); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c index 1f6873a76e76c..3b57f50db4dec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c @@ -24,29 +24,30 @@ */ #include "nv04.h" +#include + static void nv04_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *bus = nvkm_bus(subdev); - struct nvkm_device *device = bus->subdev.device; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x00000001) { - nv_error(bus, "BUS ERROR\n"); + nvkm_error(subdev, "BUS ERROR\n"); stat &= ~0x00000001; nvkm_wr32(device, 0x001100, 0x00000001); } if (stat & 0x00000110) { - subdev = nvkm_subdev(subdev, NVDEV_SUBDEV_GPIO); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_gpio *gpio = device->gpio; + if (gpio && gpio->subdev.intr) + gpio->subdev.intr(&gpio->subdev); stat &= ~0x00000110; nvkm_wr32(device, 0x001100, 0x00000110); } if (stat) { - nv_error(bus, "unknown intr 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_mask(device, 0x001140, stat, 0x00000000); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c index e8ee4cd7c025e..e99d7a20f90ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c @@ -24,42 +24,44 @@ */ #include "nv04.h" +#include +#include + static void nv31_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *bus = nvkm_bus(subdev); - struct nvkm_device *device = bus->subdev.device; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); u32 gpio = nvkm_rd32(device, 0x001104) & nvkm_rd32(device, 0x001144); if (gpio) { - subdev = nvkm_subdev(bus, NVDEV_SUBDEV_GPIO); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_gpio *gpio = device->gpio; + if (gpio && gpio->subdev.intr) + gpio->subdev.intr(&gpio->subdev); } if (stat & 0x00000008) { /* NV41- */ u32 addr = nvkm_rd32(device, 0x009084); u32 data = nvkm_rd32(device, 0x009088); - nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", - (addr & 0x00000002) ? "write" : "read", data, - (addr & 0x00fffffc)); + nvkm_error(subdev, "MMIO %s of %08x FAULT at %06x\n", + (addr & 0x00000002) ? "write" : "read", data, + (addr & 0x00fffffc)); stat &= ~0x00000008; nvkm_wr32(device, 0x001100, 0x00000008); } if (stat & 0x00070000) { - subdev = nvkm_subdev(bus, NVDEV_SUBDEV_THERM); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_therm *therm = device->therm; + if (therm && therm->subdev.intr) + therm->subdev.intr(&therm->subdev); stat &= ~0x00070000; nvkm_wr32(device, 0x001100, 0x00070000); } if (stat) { - nv_error(bus, "unknown intr 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_mask(device, 0x001140, stat, 0x00000000); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index 1a9be08604f5c..47d1e436bd44f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -24,6 +24,7 @@ */ #include "nv04.h" +#include #include static int @@ -51,32 +52,31 @@ nv50_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) void nv50_bus_intr(struct nvkm_subdev *subdev) { - struct nvkm_bus *bus = nvkm_bus(subdev); - struct nvkm_device *device = bus->subdev.device; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); if (stat & 0x00000008) { u32 addr = nvkm_rd32(device, 0x009084); u32 data = nvkm_rd32(device, 0x009088); - nv_error(bus, "MMIO %s of 0x%08x FAULT at 0x%06x\n", - (addr & 0x00000002) ? "write" : "read", data, - (addr & 0x00fffffc)); + nvkm_error(subdev, "MMIO %s of %08x FAULT at %06x\n", + (addr & 0x00000002) ? "write" : "read", data, + (addr & 0x00fffffc)); stat &= ~0x00000008; nvkm_wr32(device, 0x001100, 0x00000008); } if (stat & 0x00010000) { - subdev = nvkm_subdev(bus, NVDEV_SUBDEV_THERM); - if (subdev && subdev->intr) - subdev->intr(subdev); + struct nvkm_therm *therm = device->therm; + if (therm && therm->subdev.intr) + therm->subdev.intr(&therm->subdev); stat &= ~0x00010000; nvkm_wr32(device, 0x001100, 0x00010000); } if (stat) { - nv_error(bus, "unknown intr 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_mask(device, 0x001140, stat, 0); } } -- GitLab From b907649e7be734a4911f83b67a14e3425fa8a2a1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5412/7006] drm/nouveau/clk: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 42 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 5 ++- .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 5 ++- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 40 +++++++++++------- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 7 ++-- .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 37 ++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/clk/nv40.c | 5 ++- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 17 ++++---- .../drm/nouveau/nvkm/subdev/clk/pllgt215.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c | 2 +- 10 files changed, 93 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index d54d84aaf763c..a05ec57150c65 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -76,8 +76,10 @@ nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, static int nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) { - struct nvkm_therm *therm = nvkm_therm(clk); - struct nvkm_volt *volt = nvkm_volt(clk); + struct nvkm_subdev *subdev = &clk->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_therm *therm = device->therm; + struct nvkm_volt *volt = device->volt; struct nvkm_cstate *cstate; int ret; @@ -90,7 +92,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) if (therm) { ret = nvkm_therm_cstate(therm, pstate->fanspeed, +1); if (ret && ret != -ENODEV) { - nv_error(clk, "failed to raise fan speed: %d\n", ret); + nvkm_error(subdev, "failed to raise fan speed: %d\n", ret); return ret; } } @@ -98,7 +100,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) if (volt) { ret = volt->set_id(volt, cstate->voltage, +1); if (ret && ret != -ENODEV) { - nv_error(clk, "failed to raise voltage: %d\n", ret); + nvkm_error(subdev, "failed to raise voltage: %d\n", ret); return ret; } } @@ -112,13 +114,13 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) if (volt) { ret = volt->set_id(volt, cstate->voltage, -1); if (ret && ret != -ENODEV) - nv_error(clk, "failed to lower voltage: %d\n", ret); + nvkm_error(subdev, "failed to lower voltage: %d\n", ret); } if (therm) { ret = nvkm_therm_cstate(therm, pstate->fanspeed, -1); if (ret && ret != -ENODEV) - nv_error(clk, "failed to lower fan speed: %d\n", ret); + nvkm_error(subdev, "failed to lower fan speed: %d\n", ret); } return ret; @@ -171,7 +173,8 @@ nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) static int nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) { - struct nvkm_fb *fb = nvkm_fb(clk); + struct nvkm_subdev *subdev = &clk->subdev; + struct nvkm_fb *fb = subdev->device->fb; struct nvkm_pstate *pstate; int ret, idx = 0; @@ -180,7 +183,7 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) break; } - nv_debug(clk, "setting performance state %d\n", pstatei); + nvkm_debug(subdev, "setting performance state %d\n", pstatei); clk->pstate = pstatei; if (fb->ram && fb->ram->calc) { @@ -200,15 +203,16 @@ static void nvkm_pstate_work(struct work_struct *work) { struct nvkm_clk *clk = container_of(work, typeof(*clk), work); + struct nvkm_subdev *subdev = &clk->subdev; int pstate; if (!atomic_xchg(&clk->waiting, 0)) return; clk->pwrsrc = power_supply_is_system_supplied(); - nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n", - clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, - clk->astate, clk->tstate, clk->dstate); + nvkm_trace(subdev, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n", + clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc, + clk->astate, clk->tstate, clk->dstate); pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc; if (clk->state_nr && pstate != -1) { @@ -219,12 +223,12 @@ nvkm_pstate_work(struct work_struct *work) pstate = clk->pstate = -1; } - nv_trace(clk, "-> %d\n", pstate); + nvkm_trace(subdev, "-> %d\n", pstate); if (pstate != clk->pstate) { int ret = nvkm_pstate_prog(clk, pstate); if (ret) { - nv_error(clk, "error setting pstate %d: %d\n", - pstate, ret); + nvkm_error(subdev, "error setting pstate %d: %d\n", + pstate, ret); } } @@ -247,6 +251,7 @@ nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) { struct nvkm_domain *clock = clk->domains - 1; struct nvkm_cstate *cstate; + struct nvkm_subdev *subdev = &clk->subdev; char info[3][32] = { "", "", "" }; char name[4] = "--"; int i = -1; @@ -260,12 +265,12 @@ nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) if (hi == 0) continue; - nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo); + nvkm_debug(subdev, "%02x: %10d KHz\n", clock->name, lo); list_for_each_entry(cstate, &pstate->list, head) { u32 freq = cstate->domain[clock->name]; lo = min(lo, freq); hi = max(hi, freq); - nv_debug(clk, "%10d KHz\n", freq); + nvkm_debug(subdev, "%10d KHz\n", freq); } if (clock->mname && ++i < ARRAY_SIZE(info)) { @@ -281,7 +286,7 @@ nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) } } - nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]); + nvkm_debug(subdev, "%s: %s %s %s\n", name, info[0], info[1], info[2]); } static void @@ -481,6 +486,7 @@ int _nvkm_clk_init(struct nvkm_object *object) { struct nvkm_clk *clk = (void *)object; + struct nvkm_subdev *subdev = &clk->subdev; struct nvkm_domain *clock = clk->domains; int ret; @@ -495,7 +501,7 @@ _nvkm_clk_init(struct nvkm_object *object) while (clock->name != nv_clk_src_max) { ret = clk->read(clk, clock->name); if (ret < 0) { - nv_error(clk, "%02x freq unknown\n", clock->name); + nvkm_error(subdev, "%02x freq unknown\n", clock->name); return ret; } clk->bstate.base.domain[clock->name] = ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index c90f7d68f412e..6c3090898e365 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -149,7 +149,8 @@ static int gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gf100_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; switch (src) { case nv_clk_src_crystal: @@ -191,7 +192,7 @@ gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case nv_clk_src_vdec: return read_clk(clk, 0x0e); default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index ad166aaf609bd..7ca88da8a69be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -188,7 +188,8 @@ static int gk104_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gk104_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; switch (src) { case nv_clk_src_crystal: @@ -212,7 +213,7 @@ gk104_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case nv_clk_src_vdec: return read_clk(clk, 0x0e); default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 49659bce68e36..2d10dc17238d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -151,6 +151,7 @@ gk20a_pllg_calc_rate(struct gk20a_clk *clk) static int gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) { + struct nvkm_subdev *subdev = &clk->base.subdev; u32 target_clk_f, ref_clk_f, target_freq; u32 min_vco_f, max_vco_f; u32 low_pl, high_pl, best_pl; @@ -198,8 +199,8 @@ gk20a_pllg_calc_mnp(struct gk20a_clk *clk, unsigned long rate) } } - nv_debug(clk, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, - pl_to_div[low_pl], high_pl, pl_to_div[high_pl]); + nvkm_debug(subdev, "low_PL %d(div%d), high_PL %d(div%d)", low_pl, + pl_to_div[low_pl], high_pl, pl_to_div[high_pl]); /* Select lowest possible VCO */ for (pl = low_pl; pl <= high_pl; pl++) { @@ -249,8 +250,9 @@ found_match: WARN_ON(best_delta == ~0); if (best_delta != 0) - nv_debug(clk, "no best match for target @ %dMHz on gpc_pll", - target_clk_f); + nvkm_debug(subdev, + "no best match for target @ %dMHz on gpc_pll", + target_clk_f); clk->m = best_m; clk->n = best_n; @@ -258,15 +260,17 @@ found_match: target_freq = gk20a_pllg_calc_rate(clk) / MHZ; - nv_debug(clk, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", - target_freq, clk->m, clk->n, clk->pl, pl_to_div[clk->pl]); + nvkm_debug(subdev, + "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n", + target_freq, clk->m, clk->n, clk->pl, pl_to_div[clk->pl]); return 0; } static int gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) { - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 val; int ramp_timeout; @@ -314,7 +318,7 @@ gk20a_pllg_slide(struct gk20a_clk *clk, u32 n) nvkm_rd32(device, GPCPLL_NDIV_SLOWDOWN); if (ramp_timeout <= 0) { - nv_error(clk, "gpcpll dynamic ramp timeout\n"); + nvkm_error(subdev, "gpcpll dynamic ramp timeout\n"); return -ETIMEDOUT; } @@ -340,7 +344,8 @@ _gk20a_pllg_disable(struct gk20a_clk *clk) static int _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) { - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 val, cfg; u32 m_old, pl_old, n_lo; @@ -387,8 +392,8 @@ _gk20a_pllg_program_mnp(struct gk20a_clk *clk, bool allow_slide) _gk20a_pllg_disable(clk); - nv_debug(clk, "%s: m=%d n=%d pl=%d\n", __func__, clk->m, clk->n, - clk->pl); + nvkm_debug(subdev, "%s: m=%d n=%d pl=%d\n", __func__, + clk->m, clk->n, clk->pl); n_lo = DIV_ROUND_UP(clk->m * clk->params->min_vco, clk->parent_rate / MHZ); @@ -567,7 +572,8 @@ static int gk20a_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; switch (src) { case nv_clk_src_crystal: @@ -576,7 +582,7 @@ gk20a_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) gk20a_pllg_read_mnp(clk); return gk20a_pllg_calc_rate(clk) / GK20A_CLK_GPC_MDIV; default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } } @@ -620,7 +626,8 @@ static int gk20a_clk_init(struct nvkm_object *object) { struct gk20a_clk *clk = (void *)object; - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; int ret; nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); @@ -631,7 +638,7 @@ gk20a_clk_init(struct nvkm_object *object) ret = gk20a_clk_prog(&clk->base); if (ret) { - nv_error(clk, "cannot initialize clock\n"); + nvkm_error(subdev, "cannot initialize clock\n"); return ret; } @@ -665,7 +672,8 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, plat = nv_device_to_platform(nv_device(parent)); clk->parent_rate = clk_get_rate(plat->gpu->clk); - nv_info(clk, "parent clock rate: %d Mhz\n", clk->parent_rate / MHZ); + nvkm_info(&clk->base.subdev, "parent clock rate: %d Mhz\n", + clk->parent_rate / MHZ); clk->base.read = gk20a_clk_read; clk->base.calc = gk20a_clk_calc; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 6992cbb8c2d84..4a88bbd814b76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -139,7 +139,8 @@ static int gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct gt215_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 hsrc; switch (src) { @@ -167,11 +168,11 @@ gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case 3: return 277000; default: - nv_error(clk, "unknown HOST clock source %d\n", hsrc); + nvkm_error(subdev, "unknown HOST clock source %d\n", hsrc); return -EINVAL; } default: - nv_error(clk, "invalid clock source %d\n", src); + nvkm_error(subdev, "invalid clock source %d\n", src); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index 05d2a1bc55cf3..31e8fa02ba749 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -80,7 +80,8 @@ static int mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 mast = nvkm_rd32(device, 0x00c054); u32 P = 0; @@ -155,7 +156,7 @@ mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) break; } - nv_debug(clk, "unknown clock source %d 0x%08x\n", src, mast); + nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast); return 0; } @@ -204,6 +205,7 @@ mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; + struct nvkm_subdev *subdev = &clk->base.subdev; u32 out = 0, clock = 0; int N, M, P1, P2 = 0; int divs = 0; @@ -267,27 +269,27 @@ mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) } /* Print strategy! */ - nv_debug(clk, "nvpll: %08x %08x %08x\n", - clk->ccoef, clk->cpost, clk->cctrl); - nv_debug(clk, " spll: %08x %08x %08x\n", - clk->scoef, clk->spost, clk->sctrl); - nv_debug(clk, " vdiv: %08x\n", clk->vdiv); + nvkm_debug(subdev, "nvpll: %08x %08x %08x\n", + clk->ccoef, clk->cpost, clk->cctrl); + nvkm_debug(subdev, " spll: %08x %08x %08x\n", + clk->scoef, clk->spost, clk->sctrl); + nvkm_debug(subdev, " vdiv: %08x\n", clk->vdiv); if (clk->csrc == nv_clk_src_hclkm4) - nv_debug(clk, "core: hrefm4\n"); + nvkm_debug(subdev, "core: hrefm4\n"); else - nv_debug(clk, "core: nvpll\n"); + nvkm_debug(subdev, "core: nvpll\n"); if (clk->ssrc == nv_clk_src_hclkm4) - nv_debug(clk, "shader: hrefm4\n"); + nvkm_debug(subdev, "shader: hrefm4\n"); else if (clk->ssrc == nv_clk_src_core) - nv_debug(clk, "shader: nvpll\n"); + nvkm_debug(subdev, "shader: nvpll\n"); else - nv_debug(clk, "shader: spll\n"); + nvkm_debug(subdev, "shader: spll\n"); if (clk->vsrc == nv_clk_src_hclkm4) - nv_debug(clk, "vdec: 500MHz\n"); + nvkm_debug(subdev, "vdec: 500MHz\n"); else - nv_debug(clk, "vdec: core\n"); + nvkm_debug(subdev, "vdec: core\n"); return 0; } @@ -296,7 +298,8 @@ static int mcp77_clk_prog(struct nvkm_clk *obj) { struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 pllmask = 0, mast; unsigned long flags; unsigned long *f = &flags; @@ -324,7 +327,7 @@ mcp77_clk_prog(struct nvkm_clk *obj) mast |= 0x00000003; break; default: - nv_warn(clk,"Reclocking failed: unknown core clock\n"); + nvkm_warn(subdev, "Reclocking failed: unknown core clock\n"); goto resume; } @@ -345,7 +348,7 @@ mcp77_clk_prog(struct nvkm_clk *obj) mast |= 0x00000030; break; default: - nv_warn(clk,"Reclocking failed: unknown sclk clock\n"); + nvkm_warn(subdev, "Reclocking failed: unknown sclk clock\n"); goto resume; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index 32d59f40f5d38..1aabc5af45ec8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -106,7 +106,8 @@ static int nv40_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct nv40_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 mast = nvkm_rd32(device, 0x00c040); switch (src) { @@ -124,7 +125,7 @@ nv40_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) break; } - nv_debug(clk, "unknown clock source %d 0x%08x\n", src, mast); + nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 0d17de6f90e81..369b8f45902fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -51,7 +51,8 @@ read_div(struct nv50_clk *clk) static u32 read_pll_src(struct nv50_clk *clk, u32 base) { - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 coef, ref = clk->base.read(&clk->base, nv_clk_src_crystal); u32 rsel = nvkm_rd32(device, 0x00e18c); int P, N, M, id; @@ -65,7 +66,7 @@ read_pll_src(struct nv50_clk *clk, u32 base) case 0x4008: id = !!(rsel & 0x00000008); break; case 0x4030: id = 0; break; default: - nv_error(clk, "ref: bad pll 0x%06x\n", base); + nvkm_error(subdev, "ref: bad pll %06x\n", base); return 0; } @@ -93,7 +94,7 @@ read_pll_src(struct nv50_clk *clk, u32 base) case 0x4028: rsel = (rsel & 0x00001800) >> 11; break; case 0x4030: rsel = 3; break; default: - nv_error(clk, "ref: bad pll 0x%06x\n", base); + nvkm_error(subdev, "ref: bad pll %06x\n", base); return 0; } @@ -123,7 +124,8 @@ read_pll_src(struct nv50_clk *clk, u32 base) static u32 read_pll_ref(struct nv50_clk *clk, u32 base) { - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 src, mast = nvkm_rd32(device, 0x00c040); switch (base) { @@ -142,7 +144,7 @@ read_pll_ref(struct nv50_clk *clk, u32 base) case 0x00e810: return clk->base.read(&clk->base, nv_clk_src_crystal); default: - nv_error(clk, "bad pll 0x%06x\n", base); + nvkm_error(subdev, "bad pll %06x\n", base); return 0; } @@ -190,7 +192,8 @@ static int nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) { struct nv50_clk *clk = container_of(obj, typeof(*clk), base); - struct nvkm_device *device = clk->base.subdev.device; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; u32 mast = nvkm_rd32(device, 0x00c040); u32 P = 0; @@ -314,7 +317,7 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) break; } - nv_debug(clk, "unknown clock source %d 0x%08x\n", src, mast); + nvkm_debug(subdev, "unknown clock source %d %08x\n", src, mast); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c index 783a3e78d632b..c6fccd600db4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c @@ -79,7 +79,7 @@ gt215_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, } if (unlikely(best_err == ~0)) { - nv_error(subdev, "unable to find matching pll values\n"); + nvkm_error(subdev, "unable to find matching pll values\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c index f2292895a1a8f..2050d1486641d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c @@ -240,6 +240,6 @@ nv04_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, u32 freq, } if (!ret) - nv_error(subdev, "unable to compute acceptable pll values\n"); + nvkm_error(subdev, "unable to compute acceptable pll values\n"); return ret; } -- GitLab From aa860e4bbe16d5756d6845022a6e94d6cb200df9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5413/7006] drm/nouveau/devinit: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c | 9 +++++---- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c | 8 +++++--- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c | 5 +++-- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c | 12 +++++++----- 8 files changed, 29 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index 438a58e8be5ba..58f75c33f555e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -55,7 +55,7 @@ gf100_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) nvkm_wr32(device, info.reg + 0x10, fN << 16); break; default: - nv_warn(init, "0x%08x/%dKhz unimplemented\n", type, freq); + nvkm_warn(subdev, "%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c index cc3263889084e..32d04fe606c1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c @@ -81,11 +81,12 @@ static int pmu_load(struct nv50_devinit *init, u8 type, bool post, u32 *init_addr_pmu, u32 *args_addr_pmu) { - struct nvkm_bios *bios = nvkm_bios(init); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pmuR pmu; if (!nvbios_pmuRm(bios, type, &pmu)) { - nv_error(init, "VBIOS PMU fuc %02x not found\n", type); + nvkm_error(subdev, "VBIOS PMU fuc %02x not found\n", type); return -EINVAL; } @@ -109,7 +110,7 @@ static int gm204_devinit_post(struct nvkm_subdev *subdev, bool post) { struct nv50_devinit *init = (void *)nvkm_devinit(subdev); - struct nvkm_device *device = init->base.subdev.device; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct bit_entry bit_I; u32 exec, args; @@ -117,7 +118,7 @@ gm204_devinit_post(struct nvkm_subdev *subdev, bool post) if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 || bit_I.length < 0x1c) { - nv_error(init, "VBIOS PMU init data not found\n"); + nvkm_error(subdev, "VBIOS PMU init data not found\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c index 052fe7e1f25b5..145a1c7ba39c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c @@ -54,7 +54,7 @@ gt215_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) nvkm_wr32(device, info.reg + 8, fN); break; default: - nv_warn(init, "0x%08x/%dKhz unimplemented\n", type, freq); + nvkm_warn(subdev, "%08x/%dKhz unimplemented\n", type, freq); ret = -EINVAL; break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 8e2992038f9f0..5158ea62f65ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -35,7 +35,8 @@ static void nv04_devinit_meminit(struct nvkm_devinit *init) { - struct nvkm_device *device = init->subdev.device; + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; u32 patt = 0xdeadbeef; struct io_mapping *fb; int i; @@ -43,7 +44,7 @@ nv04_devinit_meminit(struct nvkm_devinit *init) /* Map the framebuffer aperture */ fb = fbmem_init(device); if (!fb) { - nv_error(init, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } @@ -414,6 +415,7 @@ int nv04_devinit_init(struct nvkm_object *object) { struct nv04_devinit *init = (void *)object; + struct nvkm_subdev *subdev = &init->base.subdev; if (!init->base.post) { u32 htotal = nv_rdvgac(init, 0, 0x06); @@ -422,7 +424,7 @@ nv04_devinit_init(struct nvkm_object *object) htotal |= (nv_rdvgac(init, 0, 0x25) & 0x01) << 10; htotal |= (nv_rdvgac(init, 0, 0x41) & 0x01) << 11; if (!htotal) { - nv_info(init, "adaptor not initialised\n"); + nvkm_debug(subdev, "adaptor not initialised\n"); init->base.post = true; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index 3fb789b5050ed..fc3b0f4a54e25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -44,7 +44,8 @@ nv05_devinit_meminit(struct nvkm_devinit *init) { 0x06, 0x00 }, { 0x00, 0x00 } }; - struct nvkm_device *device = init->subdev.device; + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct io_mapping *fb; u32 patt = 0xdeadbeef; @@ -55,7 +56,7 @@ nv05_devinit_meminit(struct nvkm_devinit *init) /* Map the framebuffer aperture */ fb = fbmem_init(device); if (!fb) { - nv_error(init, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c index f0d47d1ce2a13..5f54906d45b76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c @@ -32,7 +32,8 @@ static void nv10_devinit_meminit(struct nvkm_devinit *init) { - struct nvkm_device *device = init->subdev.device; + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; static const int mem_width[] = { 0x10, 0x00, 0x20 }; int mem_width_count; uint32_t patt = 0xdeadbeef; @@ -47,7 +48,7 @@ nv10_devinit_meminit(struct nvkm_devinit *init) /* Map the framebuffer aperture */ fb = fbmem_init(device); if (!fb) { - nv_error(init, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c index 29ea11f8482d6..1ea129c446745 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c @@ -30,10 +30,10 @@ #include static void -nv20_devinit_meminit(struct nvkm_devinit *devinit) +nv20_devinit_meminit(struct nvkm_devinit *init) { - struct nv04_devinit *init = (void *)devinit; - struct nvkm_device *device = nv_device(init); + struct nvkm_subdev *subdev = &init->subdev; + struct nvkm_device *device = subdev->device; uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900); uint32_t amount, off; struct io_mapping *fb; @@ -41,7 +41,7 @@ nv20_devinit_meminit(struct nvkm_devinit *devinit) /* Map the framebuffer aperture */ fb = fbmem_init(nv_device(init)); if (!fb) { - nv_error(init, "failed to map fb\n"); + nvkm_error(subdev, "failed to map fb\n"); return; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index 2533e96be7dfc..548b3fe09cbfa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -44,13 +44,13 @@ nv50_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 freq) ret = nvbios_pll_parse(bios, type, &info); if (ret) { - nv_error(subdev, "failed to retrieve pll data, %d\n", ret); + nvkm_error(subdev, "failed to retrieve pll data, %d\n", ret); return ret; } ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) { - nv_error(subdev, "failed pll calculation\n"); + nvkm_error(subdev, "failed pll calculation\n"); return ret; } @@ -94,9 +94,11 @@ nv50_devinit_disable(struct nvkm_devinit *init) int nv50_devinit_init(struct nvkm_object *object) { - struct nvkm_bios *bios = nvkm_bios(object); - struct nvkm_ibus *ibus = nvkm_ibus(object); struct nv50_devinit *init = (void *)object; + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_subdev *ibus = device->ibus; struct nvbios_outp info; struct dcb_output outp; u8 ver = 0xff, hdr, cnt, len; @@ -105,7 +107,7 @@ nv50_devinit_init(struct nvkm_object *object) if (!init->base.post) { if (!nv_rdvgac(init, 0, 0x00) && !nv_rdvgac(init, 0, 0x1a)) { - nv_info(init, "adaptor not initialised\n"); + nvkm_debug(subdev, "adaptor not initialised\n"); init->base.post = true; } } -- GitLab From 3ecd329b6445efdcad26e94edd57f0fd5ccd080b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5414/7006] drm/nouveau/fb: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 18 ++++--- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 52 +++++++------------ .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 37 +++++++------ .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 23 ++++---- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 45 +++++++++------- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 41 ++++++++------- 9 files changed, 116 insertions(+), 112 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index be18420572268..f0a5d197e7a0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -29,7 +29,8 @@ int nvkm_fb_bios_memtype(struct nvkm_bios *bios) { - struct nvkm_device *device = bios->subdev.device; + struct nvkm_subdev *subdev = &bios->subdev; + struct nvkm_device *device = subdev->device; const u8 ramcfg = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; struct nvbios_M0203E M0203E; u8 ver, hdr; @@ -41,12 +42,12 @@ nvkm_fb_bios_memtype(struct nvkm_bios *bios) case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3; case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5; default: - nv_warn(bios, "M0203E type %02x\n", M0203E.type); + nvkm_warn(subdev, "M0203E type %02x\n", M0203E.type); return NV_MEM_TYPE_UNKNOWN; } } - nv_warn(bios, "M0203E not matched!\n"); + nvkm_warn(subdev, "M0203E not matched!\n"); return NV_MEM_TYPE_UNKNOWN; } @@ -111,7 +112,7 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, { struct nvkm_fb_impl *impl = (void *)oclass; static const char *name[] = { - [NV_MEM_TYPE_UNKNOWN] = "unknown", + [NV_MEM_TYPE_UNKNOWN] = "of unknown memory type", [NV_MEM_TYPE_STOLEN ] = "stolen system memory", [NV_MEM_TYPE_SGRAM ] = "SGRAM", [NV_MEM_TYPE_SDRAM ] = "SDRAM", @@ -140,7 +141,7 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, ret = nvkm_object_ctor(nv_object(fb), NULL, impl->ram, NULL, 0, &ram); if (ret) { - nv_fatal(fb, "error detecting memory configuration!!\n"); + nvkm_error(&fb->subdev, "vram init failed, %d\n", ret); return ret; } @@ -157,10 +158,11 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, ++fb->ram->tags : 0, 1); if (ret) return ret; + + nvkm_debug(&fb->subdev, "%d compression tags\n", fb->ram->tags); } - nv_info(fb, "RAM type: %s\n", name[fb->ram->type]); - nv_info(fb, "RAM size: %d MiB\n", (int)(fb->ram->size >> 20)); - nv_info(fb, " ZCOMP: %d tags\n", fb->ram->tags); + nvkm_info(&fb->subdev, "%d MiB %s\n", (int)(fb->ram->size >> 20), + name[fb->ram->type]); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index 0c80d94985808..1ac7d746e4761 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -36,12 +36,11 @@ static void gf100_fb_intr(struct nvkm_subdev *subdev) { struct nvkm_device *device = subdev->device; - struct gf100_fb *fb = (void *)subdev; u32 intr = nvkm_rd32(device, 0x000100); if (intr & 0x08000000) - nv_debug(fb, "PFFB intr\n"); + nvkm_debug(subdev, "PFFB intr\n"); if (intr & 0x00002000) - nv_debug(fb, "PBFB intr\n"); + nvkm_debug(subdev, "PBFB intr\n"); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 047e34ac86af6..1397e715dc14e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -144,10 +144,10 @@ static const struct nvkm_enum vm_fault[] = { static void nv50_fb_intr(struct nvkm_subdev *subdev) { - struct nvkm_device *device = nv_device(subdev); - struct nvkm_engine *engine; struct nv50_fb *fb = (void *)subdev; - const struct nvkm_enum *en, *cl; + struct nvkm_device *device = fb->base.subdev.device; + struct nvkm_engine *engine; + const struct nvkm_enum *en, *re, *cl, *sc; struct nvkm_object *engctx = NULL; u32 trap[6], idx, chan; u8 st0, st1, st2, st3; @@ -203,38 +203,22 @@ nv50_fb_intr(struct nvkm_subdev *subdev) en = orig_en; } - nv_error(fb, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ", - (trap[5] & 0x00000100) ? "read" : "write", - trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan, - nvkm_client_name(engctx)); + re = nvkm_enum_find(vm_fault , st1); + cl = nvkm_enum_find(vm_client, st2); + if (cl && cl->data) sc = nvkm_enum_find(cl->data, st3); + else if (en && en->data) sc = nvkm_enum_find(en->data, st3); + else sc = NULL; + + nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel " + "%08x [%s] engine %02x [%s] client %02x [%s] " + "subclient %02x [%s] reason %08x [%s]\n", + (trap[5] & 0x00000100) ? "read" : "write", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan, + nvkm_client_name(engctx), st0, en ? en->name : "", + st2, cl ? cl->name : "", st3, sc ? sc->name : "", + st1, re ? re->name : ""); nvkm_engctx_put(engctx); - - if (en) - pr_cont("%s/", en->name); - else - pr_cont("%02x/", st0); - - cl = nvkm_enum_find(vm_client, st2); - if (cl) - pr_cont("%s/", cl->name); - else - pr_cont("%02x/", st2); - - if (cl && cl->data) cl = nvkm_enum_find(cl->data, st3); - else if (en && en->data) cl = nvkm_enum_find(en->data, st3); - else cl = NULL; - if (cl) - pr_cont("%s", cl->name); - else - pr_cont("%02x", st3); - - pr_cont(" reason: "); - en = nvkm_enum_find(vm_fault, st1); - if (en) - pr_cont("%s\n", en->name); - else - pr_cont("0x%08x\n", st1); } int @@ -259,7 +243,7 @@ nv50_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (dma_mapping_error(nv_device_base(device), fb->r100c08)) return -EFAULT; } else { - nv_warn(fb, "failed 0x100c08 page alloc\n"); + nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n"); } nv_subdev(fb)->intr = nv50_fb_intr; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 6450799986c69..f998bbcd44ac2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -126,8 +126,10 @@ gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) static int gf100_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_clk *clk = nvkm_clk(fb); - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_clk *clk = device->clk; + struct nvkm_bios *bios = device->bios; struct gf100_ram *ram = (void *)fb->ram; struct gf100_ramfuc *fuc = &ram->fuc; struct nvbios_ramcfg cfg; @@ -145,20 +147,20 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size, &cnt, &ramcfg.size, &cfg); if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) { - nv_error(fb, "invalid/missing rammap entry\n"); + nvkm_error(subdev, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(fb)); if (strap >= cnt) { - nv_error(fb, "invalid ramcfg strap\n"); + nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; } ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size); if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) { - nv_error(fb, "invalid/missing ramcfg entry\n"); + nvkm_error(subdev, "invalid/missing ramcfg entry\n"); return -EINVAL; } @@ -168,7 +170,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, &cnt, &len); if (!timing.data || ver != 0x10 || timing.size < 0x19) { - nv_error(fb, "invalid/missing timing entry\n"); + nvkm_error(subdev, "invalid/missing timing entry\n"); return -EINVAL; } } else { @@ -213,7 +215,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) ret = gt215_pll_calc(nv_subdev(fb), &ram->refpll, ram->mempll.refclk, &N1, NULL, &M1, &P); if (ret <= 0) { - nv_error(fb, "unable to calc refpll\n"); + nvkm_error(subdev, "unable to calc refpll\n"); return ret ? ret : -ERANGE; } @@ -228,7 +230,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) ret = gt215_pll_calc(nv_subdev(fb), &ram->mempll, freq, &N1, NULL, &M1, &P); if (ret <= 0) { - nv_error(fb, "unable to calc refpll\n"); + nvkm_error(subdev, "unable to calc refpll\n"); return ret ? ret : -ERANGE; } @@ -508,7 +510,8 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, void **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_device *device = fb->subdev.device; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_ram *ram; const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ @@ -525,8 +528,8 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_debug(fb, "0x100800: 0x%08x\n", nvkm_rd32(device, 0x100800)); - nv_debug(fb, "parts 0x%08x mask 0x%08x\n", parts, pmask); + nvkm_debug(subdev, "100800: %08x\n", nvkm_rd32(device, 0x100800)); + nvkm_debug(subdev, "parts %08x mask %08x\n", parts, pmask); ram->type = nvkm_fb_bios_memtype(bios); ram->ranks = (nvkm_rd32(device, 0x10f200) & 0x00000004) ? 2 : 1; @@ -541,7 +544,7 @@ gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, uniform = false; } - nv_debug(fb, "%d: mem_amount 0x%08x\n", part, size); + nvkm_debug(subdev, "%d: size %08x\n", part, size); ram->size += (u64)size << 20; } } @@ -628,7 +631,9 @@ gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_bios *bios = nvkm_bios(parent); + struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct gf100_ram *ram; int ret; @@ -639,13 +644,13 @@ gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll); if (ret) { - nv_error(ram, "mclk refpll data not found\n"); + nvkm_error(subdev, "mclk refpll data not found\n"); return ret; } ret = nvbios_pll_parse(bios, 0x04, &ram->mempll); if (ret) { - nv_error(ram, "mclk pll data not found\n"); + nvkm_error(subdev, "mclk pll data not found\n"); return ret; } @@ -656,7 +661,7 @@ gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->base.tidy = gf100_ram_tidy; break; default: - nv_warn(ram, "reclocking of this ram type unsupported\n"); + nvkm_warn(subdev, "reclocking of this ram type unsupported\n"); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 5d6ae5c9bf4bb..827daa9f3e036 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -941,7 +941,7 @@ gk104_ram_calc_data(struct nvkm_fb *fb, u32 khz, struct nvkm_ram_data *data) } } - nv_error(ram, "ramcfg data for %dMHz not found\n", mhz); + nvkm_error(&fb->subdev, "ramcfg data for %dMHz not found\n", mhz); return -EINVAL; } @@ -950,6 +950,7 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) { struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; + struct nvkm_subdev *subdev = &fb->subdev; int refclk, i; int ret; @@ -977,7 +978,7 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) &ram->fN1, &ram->M1, &ram->P1); fuc->mempll.refclk = ret; if (ret <= 0) { - nv_error(fb, "unable to calc refpll\n"); + nvkm_error(subdev, "unable to calc refpll\n"); return -EINVAL; } @@ -993,7 +994,7 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) ret = gt215_pll_calc(nv_subdev(fb), &fuc->mempll, next->freq, &ram->N2, NULL, &ram->M2, &ram->P2); if (ret <= 0) { - nv_error(fb, "unable to calc mempll\n"); + nvkm_error(subdev, "unable to calc mempll\n"); return -EINVAL; } } @@ -1247,11 +1248,12 @@ gk104_ram_train_type(struct nvkm_fb *fb, int i, u8 ramcfg, static int gk104_ram_train_init_0(struct nvkm_fb *fb, struct gk104_ram_train *train) { - struct nvkm_device *device = fb->subdev.device; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; int i, j; if ((train->mask & 0x03d3) != 0x03d3) { - nv_warn(fb, "missing link training data\n"); + nvkm_warn(subdev, "missing link training data\n"); return -EINVAL; } @@ -1449,7 +1451,8 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_device *device = fb->subdev.device; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_gpio *gpio = device->gpio; struct dcb_gpio_func func; @@ -1473,7 +1476,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->base.tidy = gk104_ram_tidy; break; default: - nv_warn(fb, "reclocking of this RAM type is unsupported\n"); + nvkm_warn(subdev, "reclocking of this RAM type is unsupported\n"); break; } @@ -1510,7 +1513,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (i = 0; !ret; i++) { ret = gk104_ram_ctor_data(ram, ramcfg, i); if (ret && ret != -ENOENT) { - nv_error(fb, "failed to parse ramcfg data\n"); + nvkm_error(subdev, "failed to parse ramcfg data\n"); return ret; } } @@ -1518,13 +1521,13 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* parse bios data for both pll's */ ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll); if (ret) { - nv_error(fb, "mclk refpll data not found\n"); + nvkm_error(subdev, "mclk refpll data not found\n"); return ret; } ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll); if (ret) { - nv_error(fb, "mclk pll data not found\n"); + nvkm_error(subdev, "mclk pll data not found\n"); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index dc1dd03b6f597..660079bb4cd43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -155,12 +155,13 @@ gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) int gt215_link_train(struct nvkm_fb *fb) { - struct nvkm_bios *bios = nvkm_bios(fb); struct gt215_ram *ram = (void *)fb->ram; - struct nvkm_clk *clk = nvkm_clk(fb); struct gt215_ltrain *train = &ram->ltrain; - struct nvkm_device *device = nv_device(fb); struct gt215_ramfuc *fuc = &ram->fuc; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvkm_clk *clk = device->clk; u32 *result, r1700; int ret, i; struct nvbios_M0205T M0205T = { 0 }; @@ -247,11 +248,11 @@ gt215_link_train(struct nvkm_fb *fb) ram_train_result(fb, result, 64); for (i = 0; i < 64; i++) - nv_debug(fb, "Train: %08x", result[i]); + nvkm_debug(subdev, "Train: %08x", result[i]); gt215_link_train_calc(result, train); - nv_debug(fb, "Train: %08x %08x %08x", train->r_100720, - train->r_1111e0, train->r_111400); + nvkm_debug(subdev, "Train: %08x %08x %08x", train->r_100720, + train->r_1111e0, train->r_111400); kfree(result); @@ -352,9 +353,10 @@ gt215_link_train_fini(struct nvkm_fb *fb) static int gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) { - struct nvkm_device *device = fb->subdev.device; struct gt215_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; int tUNK_base, tUNK_40_0, prevCL; u32 cur2, cur3, cur7, cur8; @@ -416,11 +418,11 @@ gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) break; } - nv_debug(fb, "Entry: 220: %08x %08x %08x %08x\n", - timing[0], timing[1], timing[2], timing[3]); - nv_debug(fb, " 230: %08x %08x %08x %08x\n", - timing[4], timing[5], timing[6], timing[7]); - nv_debug(fb, " 240: %08x\n", timing[8]); + nvkm_debug(subdev, "Entry: 220: %08x %08x %08x %08x\n", + timing[0], timing[1], timing[2], timing[3]); + nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n", + timing[4], timing[5], timing[6], timing[7]); + nvkm_debug(subdev, " 240: %08x\n", timing[8]); return 0; } #undef T @@ -493,10 +495,12 @@ gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) static int gt215_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(fb); struct gt215_ram *ram = (void *)fb->ram; struct gt215_ramfuc *fuc = &ram->fuc; struct gt215_ltrain *train = &ram->ltrain; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; struct gt215_clk_info mclk; struct nvkm_ram_data *next; u8 ver, hdr, cnt, len, strap; @@ -518,21 +522,21 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x05) { - nv_error(fb, "invalid/missing rammap entry\n"); + nvkm_error(subdev, "invalid/missing rammap entry\n"); return -EINVAL; } /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(fb)); if (strap >= cnt) { - nv_error(fb, "invalid ramcfg strap\n"); + nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; } data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap, &ver, &hdr, &next->bios); if (!data || ver != 0x10 || hdr < 0x09) { - nv_error(fb, "invalid/missing ramcfg entry\n"); + nvkm_error(subdev, "invalid/missing ramcfg entry\n"); return -EINVAL; } @@ -542,14 +546,14 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x17) { - nv_error(fb, "invalid/missing timing entry\n"); + nvkm_error(subdev, "invalid/missing timing entry\n"); return -EINVAL; } } ret = gt215_pll_info(nvkm_clk(fb), 0x12, 0x4000, freq, &mclk); if (ret < 0) { - nv_error(fb, "failed mclk calculation\n"); + nvkm_error(subdev, "failed mclk calculation\n"); return ret; } @@ -922,7 +926,8 @@ gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_gpio *gpio = nvkm_gpio(fb); + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_gpio *gpio = subdev->device->gpio; struct dcb_gpio_func func; struct gt215_ram *ram; int ret, i; @@ -942,7 +947,7 @@ gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->base.tidy = gt215_ram_tidy; break; default: - nv_warn(ram, "reclocking of this ram type unsupported\n"); + nvkm_warn(subdev, "reclocking of this ram type unsupported\n"); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c index 98b14b03d743c..6bbdf817471f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c @@ -36,7 +36,7 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); if (!bridge) { - nv_fatal(fb, "no bridge device\n"); + nvkm_error(&fb->subdev, "no bridge device\n"); return -ENODEV; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 56bdfeeab8e79..5a5b335d61bf1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -33,7 +33,8 @@ int nv40_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nv40_ram *ram = (void *)fb->ram; struct nvbios_pll pll; int N1, M1, N2, M2; @@ -41,7 +42,7 @@ nv40_ram_calc(struct nvkm_fb *fb, u32 freq) ret = nvbios_pll_parse(bios, 0x04, &pll); if (ret) { - nv_error(fb, "mclk pll data not found\n"); + nvkm_error(subdev, "mclk pll data not found\n"); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 6ea0d52cd89cc..1c38fb4d9c1f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -68,9 +68,10 @@ struct nv50_ram { static int nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) { - struct nvkm_device *device = fb->subdev.device; struct nv50_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; u32 cur2, cur4, cur7, cur8; u8 unkt3b; @@ -134,11 +135,11 @@ nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) timing[8] |= (T(CL) - 2); } - nv_debug(fb, " 220: %08x %08x %08x %08x\n", - timing[0], timing[1], timing[2], timing[3]); - nv_debug(fb, " 230: %08x %08x %08x %08x\n", - timing[4], timing[5], timing[6], timing[7]); - nv_debug(fb, " 240: %08x\n", timing[8]); + nvkm_debug(subdev, " 220: %08x %08x %08x %08x\n", + timing[0], timing[1], timing[2], timing[3]); + nvkm_debug(subdev, " 230: %08x %08x %08x %08x\n", + timing[4], timing[5], timing[6], timing[7]); + nvkm_debug(subdev, " 240: %08x\n", timing[8]); return 0; } #undef T @@ -154,9 +155,10 @@ nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq) static int nv50_ram_calc(struct nvkm_fb *fb, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(fb); struct nv50_ram *ram = (void *)fb->ram; struct nv50_ramseq *hwsq = &ram->hwsq; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_perfE perfE; struct nvbios_pll mpll; struct nvkm_ram_data *next; @@ -178,7 +180,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) &size, &perfE); if (!data || (ver < 0x25 || ver >= 0x40) || (size < 2)) { - nv_error(fb, "invalid/missing perftab entry\n"); + nvkm_error(subdev, "invalid/missing perftab entry\n"); return -EINVAL; } } while (perfE.memory < freq); @@ -188,14 +190,14 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) /* locate specific data set for the attached memory */ strap = nvbios_ramcfg_index(nv_subdev(fb)); if (strap >= cnt) { - nv_error(fb, "invalid ramcfg strap\n"); + nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; } data = nvbios_rammapSp_from_perf(bios, data + hdr, size, strap, &next->bios); if (!data) { - nv_error(fb, "invalid/missing rammap entry "); + nvkm_error(subdev, "invalid/missing rammap entry "); return -EINVAL; } @@ -204,7 +206,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) data = nvbios_timingEp(bios, next->bios.ramcfg_timing, &ver, &hdr, &cnt, &len, &next->bios); if (!data || ver != 0x10 || hdr < 0x12) { - nv_error(fb, "invalid/missing timing entry " + nvkm_error(subdev, "invalid/missing timing entry " "%02x %04x %02x %02x\n", strap, data, ver, hdr); return -EINVAL; @@ -494,7 +496,8 @@ nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, static u32 nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) { - struct nvkm_device *device = fb->subdev.device; + struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_device *device = subdev->device; int colbits, rowbitsa, rowbitsb, banks; u64 rowsize, predicted; u32 r0, r4, rt, rblock_size; @@ -502,8 +505,8 @@ nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) r0 = nvkm_rd32(device, 0x100200); r4 = nvkm_rd32(device, 0x100204); rt = nvkm_rd32(device, 0x100250); - nv_debug(fb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", - r0, r4, rt, nvkm_rd32(device, 0x001540)); + nvkm_debug(subdev, "memcfg %08x %08x %08x %08x\n", + r0, r4, rt, nvkm_rd32(device, 0x001540)); colbits = (r4 & 0x0000f000) >> 12; rowbitsa = ((r4 & 0x000f0000) >> 16) + 8; @@ -516,15 +519,15 @@ nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) predicted += rowsize << rowbitsb; if (predicted != ram->size) { - nv_warn(fb, "memory controller reports %d MiB VRAM\n", - (u32)(ram->size >> 20)); + nvkm_warn(subdev, "memory controller reports %d MiB VRAM\n", + (u32)(ram->size >> 20)); } rblock_size = rowsize; if (rt & 1) rblock_size *= 3; - nv_debug(fb, "rblock %d bytes\n", rblock_size); + nvkm_debug(subdev, "rblock %d bytes\n", rblock_size); return rblock_size; } @@ -584,6 +587,8 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 datasize, struct nvkm_object **pobject) { + struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_subdev *subdev = &fb->subdev; struct nv50_ram *ram; int ret, i; @@ -600,7 +605,7 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, break; case NV_MEM_TYPE_DDR2: default: - nv_warn(ram, "reclocking of this ram type unsupported\n"); + nvkm_warn(subdev, "reclocking of this ram type unsupported\n"); return 0; } -- GitLab From 1cb57d25b6b62b39f07c4ff4370c2c48803000e9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5415/7006] drm/nouveau/i2c: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c | 8 +++++--- .../gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 17 +++++++++------- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c | 20 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c | 20 ++++++++++--------- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h | 8 +++++--- .../gpu/drm/nouveau/nvkm/subdev/i2c/port.h | 5 +++-- 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c index d17dd1cf3c34e..7b195393d15c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c @@ -32,11 +32,13 @@ struct anx9805_i2c_port { static int anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh) { + struct nvkm_i2c *i2c = nvkm_i2c(port); + struct nvkm_subdev *subdev = &i2c->subdev; struct anx9805_i2c_port *chan = (void *)port; struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; u8 tmp, i; - DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh); + DBG("ANX9805 train %d %02x %d\n", link_nr, link_bw, enh); nv_wri2cr(mast, chan->addr, 0xa0, link_bw); nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); @@ -47,13 +49,13 @@ anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh) while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { mdelay(5); if (i++ == 100) { - nv_error(port, "link training timed out\n"); + nvkm_error(subdev, "link training timed out\n"); return -ETIMEDOUT; } } if (tmp & 0x70) { - nv_error(port, "link training failed: 0x%02x\n", tmp); + nvkm_error(subdev, "link training failed: %02x\n", tmp); return -EIO; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 187af1183f2d3..3496dfd93264c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -282,31 +282,34 @@ nvkm_i2c_identify(struct nvkm_i2c *i2c, int index, const char *what, bool (*match)(struct nvkm_i2c_port *, struct i2c_board_info *, void *), void *data) { + struct nvkm_subdev *subdev = &i2c->subdev; struct nvkm_i2c_port *port = nvkm_i2c_find(i2c, index); int i; if (!port) { - nv_debug(i2c, "no bus when probing %s on %d\n", what, index); + nvkm_debug(subdev, "no bus when probing %s on %d\n", + what, index); return -ENODEV; } - nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index); + nvkm_debug(subdev, "probing %ss on bus: %d\n", what, port->index); for (i = 0; info[i].dev.addr; i++) { u8 orig_udelay = 0; if ((port->adapter.algo == &i2c_bit_algo) && (info[i].udelay != 0)) { struct i2c_algo_bit_data *algo = port->adapter.algo_data; - nv_debug(i2c, "using custom udelay %d instead of %d\n", - info[i].udelay, algo->udelay); + nvkm_debug(subdev, + "using custom udelay %d instead of %d\n", + info[i].udelay, algo->udelay); orig_udelay = algo->udelay; algo->udelay = info[i].udelay; } if (nv_probe_i2c(port, info[i].dev.addr) && (!match || match(port, &info[i].dev, data))) { - nv_info(i2c, "detected %s: %s\n", what, - info[i].dev.type); + nvkm_info(subdev, "detected %s: %s\n", what, + info[i].dev.type); return i; } @@ -316,7 +319,7 @@ nvkm_i2c_identify(struct nvkm_i2c *i2c, int index, const char *what, } } - nv_debug(i2c, "no devices found.\n"); + nvkm_debug(subdev, "no devices found.\n"); return -ENODEV; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c index 17cb172a4a0a3..acbfbe0a7ea91 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c @@ -55,8 +55,10 @@ g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00e068, temp); } -#define AUX_DBG(fmt, args...) nv_debug(i2c, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) nv_error(i2c, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_DBG(fmt, args...) \ + nvkm_debug(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_ERR(fmt, args...) \ + nvkm_error(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) static void auxch_fini(struct nvkm_i2c *i2c, int ch) @@ -80,7 +82,7 @@ auxch_init(struct nvkm_i2c *i2c, int ch) ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { - AUX_ERR("begin idle timeout 0x%08x\n", ctrl); + AUX_ERR("begin idle timeout %08x\n", ctrl); return -EBUSY; } } while (ctrl & 0x03010000); @@ -92,7 +94,7 @@ auxch_init(struct nvkm_i2c *i2c, int ch) ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { - AUX_ERR("magic wait 0x%08x\n", ctrl); + AUX_ERR("magic wait %08x\n", ctrl); auxch_fini(i2c, ch); return -EBUSY; } @@ -113,7 +115,7 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, int ch = port->addr; int ret, i; - AUX_DBG("%d: 0x%08x %d\n", type, addr, size); + AUX_DBG("%d: %08x %d\n", type, addr, size); ret = auxch_init(i2c, ch); if (ret < 0) @@ -129,7 +131,7 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, if (!(type & 1)) { memcpy(xbuf, data, size); for (i = 0; i < 16; i += 4) { - AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); + AUX_DBG("wr %08x\n", xbuf[i / 4]); nvkm_wr32(device, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); } } @@ -156,7 +158,7 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); udelay(1); if (!timeout--) { - AUX_ERR("tx req timeout 0x%08x\n", ctrl); + AUX_ERR("tx req timeout %08x\n", ctrl); ret = -EIO; goto out; } @@ -173,13 +175,13 @@ g94_aux(struct nvkm_i2c_port *base, bool retry, if ((stat & 0x00000e00)) ret = -EIO; - AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); + AUX_DBG("%02d %08x %08x\n", retries, ctrl, stat); } if (type & 1) { for (i = 0; i < 16; i += 4) { xbuf[i / 4] = nvkm_rd32(device, 0x00e4d0 + (ch * 0x50) + i); - AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); + AUX_DBG("rd %08x\n", xbuf[i / 4]); } memcpy(data, xbuf, size); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c index 61c760534ab83..f027aedb7361a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c @@ -23,8 +23,10 @@ */ #include "nv50.h" -#define AUX_DBG(fmt, args...) nv_debug(i2c, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) nv_error(i2c, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_DBG(fmt, args...) \ + nvkm_debug(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) +#define AUX_ERR(fmt, args...) \ + nvkm_error(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) static void auxch_fini(struct nvkm_i2c *i2c, int ch) @@ -48,7 +50,7 @@ auxch_init(struct nvkm_i2c *i2c, int ch) ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); udelay(1); if (!timeout--) { - AUX_ERR("begin idle timeout 0x%08x\n", ctrl); + AUX_ERR("begin idle timeout %08x\n", ctrl); return -EBUSY; } } while (ctrl & 0x03010000); @@ -60,7 +62,7 @@ auxch_init(struct nvkm_i2c *i2c, int ch) ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); udelay(1); if (!timeout--) { - AUX_ERR("magic wait 0x%08x\n", ctrl); + AUX_ERR("magic wait %08x\n", ctrl); auxch_fini(i2c, ch); return -EBUSY; } @@ -81,7 +83,7 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, int ch = port->addr; int ret, i; - AUX_DBG("%d: 0x%08x %d\n", type, addr, size); + AUX_DBG("%d: %08x %d\n", type, addr, size); ret = auxch_init(i2c, ch); if (ret < 0) @@ -97,7 +99,7 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, if (!(type & 1)) { memcpy(xbuf, data, size); for (i = 0; i < 16; i += 4) { - AUX_DBG("wr 0x%08x\n", xbuf[i / 4]); + AUX_DBG("wr %08x\n", xbuf[i / 4]); nvkm_wr32(device, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]); } } @@ -124,7 +126,7 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); udelay(1); if (!timeout--) { - AUX_ERR("tx req timeout 0x%08x\n", ctrl); + AUX_ERR("tx req timeout %08x\n", ctrl); ret = -EIO; goto out; } @@ -141,13 +143,13 @@ gm204_aux(struct nvkm_i2c_port *base, bool retry, if ((stat & 0x00000e00)) ret = -EIO; - AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat); + AUX_DBG("%02d %08x %08x\n", retries, ctrl, stat); } if (type & 1) { for (i = 0; i < 16; i += 4) { xbuf[i / 4] = nvkm_rd32(device, 0x00d940 + (ch * 0x50) + i); - AUX_DBG("rd 0x%08x\n", xbuf[i / 4]); + AUX_DBG("rd %08x\n", xbuf[i / 4]); } memcpy(data, xbuf, size); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h index f3422cc6f8db0..577b18ecf5c67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h @@ -46,9 +46,11 @@ int _nvkm_i2c_pad_fini(struct nvkm_object *, bool); #ifndef MSG #define MSG(l,f,a...) do { \ struct nvkm_i2c_pad *_pad = (void *)pad; \ - nv_##l(_pad, "PAD:%c:%02x: "f, \ - _pad->index >= 0x100 ? 'X' : 'S', \ - _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \ + struct nvkm_i2c *_i2c = nvkm_i2c(_pad); \ + nvkm_##l(&_i2c->subdev, "PAD:%c:%02x: "f, \ + _pad->index >= 0x100 ? 'X' : 'S', \ + _pad->index >= 0x100 ? \ + _pad->index - 0x100 : _pad->index, ##a); \ } while(0) #define DBG(f,a...) MSG(debug, f, ##a) #define ERR(f,a...) MSG(error, f, ##a) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h index 586f53dad813e..ac6be72633478 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h @@ -4,8 +4,9 @@ #ifndef MSG #define MSG(l,f,a...) do { \ - struct nvkm_i2c_port *_port = (void *)port; \ - nv_##l(_port, "PORT:%02x: "f, _port->index, ##a); \ + struct nvkm_i2c_port *_port = (void *)port; \ + struct nvkm_i2c *_i2c = nvkm_i2c(_port); \ + nvkm_##l(&_i2c->subdev, "PORT:%02x: "f, _port->index, ##a); \ } while(0) #define DBG(f,a...) MSG(debug, f, ##a) #define ERR(f,a...) MSG(error, f, ##a) -- GitLab From 18019e95de4ffdfb020d61197b8da2af1a442c8e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5416/7006] drm/nouveau/ibus: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c | 15 +++++++++------ drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c | 15 +++++++++------ drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c | 2 +- 3 files changed, 19 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c index 5f7652942b2af..6708fbafebaed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c @@ -26,33 +26,36 @@ static void gf100_ibus_intr_hub(struct nvkm_ibus *ibus, int i) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_subdev *subdev = &ibus->subdev; + struct nvkm_device *device = subdev->device; u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0400)); u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0400)); u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0400)); - nv_error(ibus, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nvkm_error(subdev, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); } static void gf100_ibus_intr_rop(struct nvkm_ibus *ibus, int i) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_subdev *subdev = &ibus->subdev; + struct nvkm_device *device = subdev->device; u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0400)); u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0400)); u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0400)); - nv_error(ibus, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nvkm_error(subdev, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); } static void gf100_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_subdev *subdev = &ibus->subdev; + struct nvkm_device *device = subdev->device; u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0400)); u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0400)); u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0400)); - nv_error(ibus, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nvkm_error(subdev, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c index 53dd1ba389d74..0ac0bbaa9d2ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c @@ -26,33 +26,36 @@ static void gk104_ibus_intr_hub(struct nvkm_ibus *ibus, int i) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_subdev *subdev = &ibus->subdev; + struct nvkm_device *device = subdev->device; u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0800)); u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0800)); u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0800)); - nv_error(ibus, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nvkm_error(subdev, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); } static void gk104_ibus_intr_rop(struct nvkm_ibus *ibus, int i) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_subdev *subdev = &ibus->subdev; + struct nvkm_device *device = subdev->device; u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0800)); u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0800)); u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0800)); - nv_error(ibus, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nvkm_error(subdev, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); } static void gk104_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_subdev *subdev = &ibus->subdev; + struct nvkm_device *device = subdev->device; u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0800)); u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0800)); u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0800)); - nv_error(ibus, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat); + nvkm_error(subdev, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index 611fc7165469b..1b76423439571 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -53,7 +53,7 @@ gk20a_ibus_intr(struct nvkm_subdev *subdev) u32 status0 = nvkm_rd32(device, 0x120058); if (status0 & 0x7) { - nv_debug(ibus, "resetting ibus ring\n"); + nvkm_debug(subdev, "resetting ibus ring\n"); gk20a_ibus_init_ibus_ring(ibus); } -- GitLab From 00c5550710184bad189d2cfe6b1880c0e9331bae Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5417/7006] drm/nouveau/imem: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 26 +++++++++++-------- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 4 +-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index e2e400e35bc8b..f5642698406ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -207,6 +207,7 @@ gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, { struct gk20a_instobj_dma *node; struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); + struct nvkm_subdev *subdev = &imem->base.subdev; struct device *dev = nv_device_base(nv_device(parent)); int ret; @@ -220,14 +221,15 @@ gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, &node->handle, GFP_KERNEL, &imem->attrs); if (!node->cpuaddr) { - nv_error(imem, "cannot allocate DMA memory\n"); + nvkm_error(subdev, "cannot allocate DMA memory\n"); return -ENOMEM; } /* alignment check */ if (unlikely(node->handle & (align - 1))) - nv_warn(imem, "memory not aligned as requested: %pad (0x%x)\n", - &node->handle, align); + nvkm_warn(subdev, + "memory not aligned as requested: %pad (0x%x)\n", + &node->handle, align); /* present memory for being mapped using small pages */ node->r.type = 12; @@ -249,6 +251,7 @@ gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, { struct gk20a_instobj_iommu *node; struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); + struct nvkm_subdev *subdev = &imem->base.subdev; struct nvkm_mm_node *r; int ret; int i; @@ -277,7 +280,7 @@ gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, align >> imem->iommu_pgshift, &r); mutex_unlock(imem->mm_mutex); if (ret) { - nv_error(imem, "virtual space is full!\n"); + nvkm_error(subdev, "virtual space is full!\n"); goto free_pages; } @@ -289,7 +292,7 @@ gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, ret = iommu_map(imem->domain, offset, page_to_phys(p), PAGE_SIZE, IOMMU_READ | IOMMU_WRITE); if (ret < 0) { - nv_error(imem, "IOMMU mapping failure: %d\n", ret); + nvkm_error(subdev, "IOMMU mapping failure: %d\n", ret); while (i-- > 0) { offset -= PAGE_SIZE; @@ -329,11 +332,12 @@ gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_instobj_args *args = data; struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); struct gk20a_instobj *node; + struct nvkm_subdev *subdev = &imem->base.subdev; u32 size, align; int ret; - nv_debug(parent, "%s (%s): size: %x align: %x\n", __func__, - imem->domain ? "IOMMU" : "DMA", args->size, args->align); + nvkm_debug(subdev, "%s (%s): size: %x align: %x\n", __func__, + imem->domain ? "IOMMU" : "DMA", args->size, args->align); /* Round size and align to page bounds */ size = max(roundup(args->size, PAGE_SIZE), PAGE_SIZE); @@ -359,8 +363,8 @@ gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, node->base.addr = node->mem->offset; node->base.size = size; - nv_debug(parent, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n", - size, align, node->mem->offset); + nvkm_debug(subdev, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n", + size, align, node->mem->offset); return 0; } @@ -410,7 +414,7 @@ gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, imem->iommu_pgshift = plat->gpu->iommu.pgshift; imem->mm_mutex = &plat->gpu->iommu.mutex; - nv_info(imem, "using IOMMU\n"); + nvkm_info(&imem->base.subdev, "using IOMMU\n"); } else { init_dma_attrs(&imem->attrs); /* @@ -422,7 +426,7 @@ gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, dma_set_attr(DMA_ATTR_WRITE_COMBINE, &imem->attrs); dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &imem->attrs); - nv_info(imem, "using DMA API\n"); + nvkm_info(&imem->base.subdev, "using DMA API\n"); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index fe00881bda650..c194a28b79719 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -49,7 +49,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_device *device = nv_device(parent); + struct nvkm_device *device = (void *)parent; struct nv04_instmem *imem; int ret, bar, vs; @@ -67,7 +67,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, imem->iomem = ioremap(nv_device_resource_start(device, bar), nv_device_resource_len(device, bar)); if (!imem->iomem) { - nv_error(imem, "unable to map PRAMIN BAR\n"); + nvkm_error(&imem->base.subdev, "unable to map PRAMIN BAR\n"); return -EFAULT; } -- GitLab From 59e1a2f1a665c6defc0050060846ed3d89291e8c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5418/7006] drm/nouveau/ltc: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 9 +++++---- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 5 +++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index 7e60a1393fc8d..22712cdc01b32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -92,15 +92,16 @@ gf100_ltc_lts_intr_name[] = { static void gf100_ltc_lts_intr(struct nvkm_ltc_priv *ltc, int c, int s) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_subdev *subdev = <c->base.subdev; + struct nvkm_device *device = subdev->device; u32 base = 0x141000 + (c * 0x2000) + (s * 0x400); u32 intr = nvkm_rd32(device, base + 0x020); u32 stat = intr & 0x0000ffff; + char msg[128]; if (stat) { - nv_info(ltc, "LTC%d_LTS%d:", c, s); - nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat); - pr_cont("\n"); + nvkm_snprintbf(msg, sizeof(msg), gf100_ltc_lts_intr_name, stat); + nvkm_error(subdev, "LTC%d_LTS%d: %08x [%s]\n", c, s, stat, msg); } nvkm_wr32(device, base + 0x020, intr); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 438085e978ec4..222f37e50a951 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -73,12 +73,13 @@ gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) static void gm107_ltc_lts_isr(struct nvkm_ltc_priv *ltc, int c, int s) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_subdev *subdev = <c->base.subdev; + struct nvkm_device *device = subdev->device; u32 base = 0x140000 + (c * 0x2000) + (s * 0x400); u32 stat = nvkm_rd32(device, base + 0x00c); if (stat) { - nv_info(ltc, "LTC%d_LTS%d: 0x%08x\n", c, s, stat); + nvkm_error(subdev, "LTC%d_LTS%d: %08x\n", c, s, stat); nvkm_wr32(device, base + 0x00c, stat); } } -- GitLab From c47a48a544ba47eb26ff922203fa0f99c0306907 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5419/7006] drm/nouveau/mc: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 80c3c5062e91f..babd6d8725f0f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -47,7 +47,8 @@ static irqreturn_t nvkm_mc_intr(int irq, void *arg) { struct nvkm_mc *mc = arg; - struct nvkm_device *device = mc->subdev.device; + struct nvkm_subdev *subdev = &mc->subdev; + struct nvkm_device *device = subdev->device; const struct nvkm_mc_oclass *oclass = (void *)nv_object(mc)->oclass; const struct nvkm_mc_intr *map = oclass->intr; struct nvkm_subdev *unit; @@ -72,7 +73,7 @@ nvkm_mc_intr(int irq, void *arg) } if (stat) - nv_error(mc, "unknown intr 0x%08x\n", stat); + nvkm_error(subdev, "unknown intr %08x\n", stat); } nvkm_wr32(device, 0x000140, 0x00000001); @@ -151,7 +152,7 @@ nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (mc->use_msi && oclass->msi_rearm) { mc->use_msi = pci_enable_msi(device->pdev) == 0; if (mc->use_msi) { - nv_info(mc, "MSI interrupts enabled\n"); + nvkm_debug(&mc->subdev, "MSI enabled\n"); oclass->msi_rearm(mc); } } else { -- GitLab From 85ae830f5ac177244892b934953106d11cd5a679 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5420/7006] drm/nouveau/mmu: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 64203abaaee72..76e1a657dfc94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -187,7 +187,7 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mmu->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &mmu->null); if (!mmu->nullp) { - nv_warn(mmu, "unable to allocate dummy pages\n"); + nvkm_warn(&mmu->base.subdev, "unable to allocate dummy pages\n"); mmu->null = 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index 45b5b5ac3e9bd..0216c881fa387 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -146,14 +146,15 @@ static void nv50_vm_flush(struct nvkm_vm *vm) { struct nvkm_mmu *mmu = (void *)vm->mmu; - struct nvkm_device *device = mmu->subdev.device; + struct nvkm_subdev *subdev = &mmu->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; struct nvkm_engine *engine; int i, vme; bar->flush(bar); - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&subdev->mutex); for (i = 0; i < NVDEV_SUBDEV_NR; i++) { if (!atomic_read(&vm->engref[i])) continue; @@ -186,9 +187,9 @@ nv50_vm_flush(struct nvkm_vm *vm) if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) break; ) < 0) - nv_error(mmu, "vm flush timeout: engine %d\n", vme); + nvkm_error(subdev, "vm flush timeout: engine %d\n", vme); } - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&subdev->mutex); } static int -- GitLab From 27cc60a17512055c63f05a27eb6687051ade5257 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5421/7006] drm/nouveau/mxm: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 34 +++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c | 26 +++++++------- .../gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c | 12 ++++--- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 7ecacf60f5417..6c274c803435d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -78,7 +78,8 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) static bool mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) { - struct nvkm_device *device = nv_device(mxm); + struct nvkm_subdev *subdev = &mxm->subdev; + struct nvkm_device *device = subdev->device; static char muid[] = { 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C, 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65 @@ -105,7 +106,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) rev = (version & 0xf0) << 4 | (version & 0x0f); obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4); if (!obj) { - nv_debug(mxm, "DSM MXMS failed\n"); + nvkm_debug(subdev, "DSM MXMS failed\n"); return false; } @@ -113,7 +114,8 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) mxm->mxms = kmemdup(obj->buffer.pointer, obj->buffer.length, GFP_KERNEL); } else if (obj->type == ACPI_TYPE_INTEGER) { - nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value); + nvkm_debug(subdev, "DSM MXMS returned 0x%llx\n", + obj->integer.value); } ACPI_FREE(obj); @@ -128,6 +130,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) static u8 wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version) { + struct nvkm_subdev *subdev = &mxm->subdev; u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 }; struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args }; struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -136,18 +139,18 @@ wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version) status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn); if (ACPI_FAILURE(status)) { - nv_debug(mxm, "WMMX MXMI returned %d\n", status); + nvkm_debug(subdev, "WMMX MXMI returned %d\n", status); return 0x00; } obj = retn.pointer; if (obj->type == ACPI_TYPE_INTEGER) { version = obj->integer.value; - nv_debug(mxm, "WMMX MXMI version %d.%d\n", - (version >> 4), version & 0x0f); + nvkm_debug(subdev, "WMMX MXMI version %d.%d\n", + (version >> 4), version & 0x0f); } else { version = 0; - nv_debug(mxm, "WMMX MXMI returned non-integer\n"); + nvkm_debug(subdev, "WMMX MXMI returned non-integer\n"); } kfree(obj); @@ -157,6 +160,7 @@ wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version) static bool mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version) { + struct nvkm_subdev *subdev = &mxm->subdev; u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 }; struct acpi_buffer args = { sizeof(mxms_args), mxms_args }; struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL }; @@ -164,7 +168,7 @@ mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version) acpi_status status; if (!wmi_has_guid(WMI_WMMX_GUID)) { - nv_debug(mxm, "WMMX GUID not found\n"); + nvkm_debug(subdev, "WMMX GUID not found\n"); return false; } @@ -176,7 +180,7 @@ mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version) status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn); if (ACPI_FAILURE(status)) { - nv_debug(mxm, "WMMX MXMS returned %d\n", status); + nvkm_debug(subdev, "WMMX MXMS returned %d\n", status); return false; } @@ -210,7 +214,7 @@ mxm_shadow(struct nvkm_mxm *mxm, u8 version) { struct mxm_shadow_h *shadow = _mxm_shadow; do { - nv_debug(mxm, "checking %s\n", shadow->name); + nvkm_debug(&mxm->subdev, "checking %s\n", shadow->name); if (shadow->exec(mxm, version)) { if (mxms_valid(mxm)) return 0; @@ -240,14 +244,14 @@ nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, data = mxm_table(bios, &ver, &len); if (!data || !(ver = nv_ro08(bios, data))) { - nv_debug(mxm, "no VBIOS data, nothing to do\n"); + nvkm_debug(&mxm->subdev, "no VBIOS data, nothing to do\n"); return 0; } - nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f); + nvkm_info(&mxm->subdev, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f); if (mxm_shadow(mxm, ver)) { - nv_info(mxm, "failed to locate valid SIS\n"); + nvkm_warn(&mxm->subdev, "failed to locate valid SIS\n"); #if 0 /* we should, perhaps, fall back to some kind of limited * mode here if the x86 vbios hasn't already done the @@ -260,8 +264,8 @@ nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, #endif } - nv_info(mxm, "MXMS Version %d.%d\n", - mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff); + nvkm_debug(&mxm->subdev, "MXMS Version %d.%d\n", + mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff); mxms_foreach(mxm, 0, NULL, NULL); if (nvkm_boolopt(device->cfgopt, "NvMXMDCB", true)) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c index a9b1d63fed585..1b3f5e32c7381 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c @@ -47,7 +47,7 @@ mxms_version(struct nvkm_mxm *mxm) break; } - nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]); + nvkm_debug(&mxm->subdev, "unknown version %d.%d\n", mxms[4], mxms[5]); return 0x0000; } @@ -71,7 +71,7 @@ mxms_checksum(struct nvkm_mxm *mxm) while (size--) sum += *mxms++; if (sum) { - nv_debug(mxm, "checksum invalid\n"); + nvkm_debug(&mxm->subdev, "checksum invalid\n"); return false; } return true; @@ -82,7 +82,7 @@ mxms_valid(struct nvkm_mxm *mxm) { u8 *mxms = mxms_data(mxm); if (*(u32 *)mxms != 0x5f4d584d) { - nv_debug(mxm, "signature invalid\n"); + nvkm_debug(&mxm->subdev, "signature invalid\n"); return false; } @@ -96,6 +96,7 @@ bool mxms_foreach(struct nvkm_mxm *mxm, u8 types, bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info) { + struct nvkm_subdev *subdev = &mxm->subdev; u8 *mxms = mxms_data(mxm); u8 *desc = mxms + mxms_headerlen(mxm); u8 *fini = desc + mxms_structlen(mxm) - 1; @@ -140,29 +141,28 @@ mxms_foreach(struct nvkm_mxm *mxm, u8 types, entries = desc[1] & 0x07; break; default: - nv_debug(mxm, "unknown descriptor type %d\n", type); + nvkm_debug(subdev, "unknown descriptor type %d\n", type); return false; } if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) { - static const char * mxms_desc_name[] = { + static const char * mxms_desc[] = { "ODS", "SCCS", "TS", "IPS", "GSD", "VSS", "BCS", "FCS", }; u8 *dump = desc; + char data[32], *ptr; int i, j; - nv_debug(mxm, "%4s: ", mxms_desc_name[type]); - for (j = headerlen - 1; j >= 0; j--) - pr_cont("%02x", dump[j]); - pr_cont("\n"); + for (j = headerlen - 1, ptr = data; j >= 0; j--) + ptr += sprintf(ptr, "%02x", dump[j]); dump += headerlen; + nvkm_debug(subdev, "%4s: %s\n", mxms_desc[type], data); for (i = 0; i < entries; i++, dump += recordlen) { - nv_debug(mxm, " "); - for (j = recordlen - 1; j >= 0; j--) - pr_cont("%02x", dump[j]); - pr_cont("\n"); + for (j = recordlen - 1, ptr = data; j >= 0; j--) + ptr += sprintf(ptr, "%02x", dump[j]); + nvkm_debug(subdev, " %s\n", data); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c index 0add310c3fbbc..9bf77b26ef585 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c @@ -103,8 +103,8 @@ mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb) * if one isn't found, disable it. */ if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) { - nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n", - idx, ctx.outp[0], ctx.outp[1]); + nvkm_debug(&mxm->subdev, "disable %d: %08x %08x\n", + idx, ctx.outp[0], ctx.outp[1]); ctx.outp[0] |= 0x0000000f; return 0; } @@ -176,20 +176,22 @@ mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb) static bool mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info) { + struct nvkm_subdev *subdev = &mxm->subdev; u64 desc = *(u64 *)data; if ((desc & 0xf0) != 0xf0) - nv_info(mxm, "unmatched output device 0x%016llx\n", desc); + nvkm_info(subdev, "unmatched output device %016llx\n", desc); return true; } static void mxm_dcb_sanitise(struct nvkm_mxm *mxm) { - struct nvkm_bios *bios = nvkm_bios(mxm); + struct nvkm_subdev *subdev = &mxm->subdev; + struct nvkm_bios *bios = subdev->device->bios; u8 ver, hdr, cnt, len; u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len); if (dcb == 0x0000 || ver != 0x40) { - nv_debug(mxm, "unsupported DCB version\n"); + nvkm_debug(subdev, "unsupported DCB version\n"); return; } -- GitLab From c19e329d663715014b367c4fedb217e0378342bf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5422/7006] drm/nouveau/pmu: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 27 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 19 +++++++------ .../gpu/drm/nouveau/nvkm/subdev/pmu/memx.c | 28 ++++++++++--------- 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index 29c692c661da3..2479940179658 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -92,7 +92,8 @@ static void nvkm_pmu_recv(struct work_struct *work) { struct nvkm_pmu *pmu = container_of(work, struct nvkm_pmu, recv.work); - struct nvkm_device *device = pmu->subdev.device; + struct nvkm_subdev *subdev = &pmu->subdev; + struct nvkm_device *device = subdev->device; u32 process, message, data0, data1; /* nothing to do if GET == PUT */ @@ -132,12 +133,12 @@ nvkm_pmu_recv(struct work_struct *work) /* right now there's no other expected responses from the engine, * so assume that any unexpected message is an error. */ - nv_warn(pmu, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n", - (char)((process & 0x000000ff) >> 0), - (char)((process & 0x0000ff00) >> 8), - (char)((process & 0x00ff0000) >> 16), - (char)((process & 0xff000000) >> 24), - process, message, data0, data1); + nvkm_warn(subdev, "%c%c%c%c %08x %08x %08x %08x\n", + (char)((process & 0x000000ff) >> 0), + (char)((process & 0x0000ff00) >> 8), + (char)((process & 0x00ff0000) >> 16), + (char)((process & 0xff000000) >> 24), + process, message, data0, data1); } static void @@ -151,8 +152,9 @@ nvkm_pmu_intr(struct nvkm_subdev *subdev) if (intr & 0x00000020) { u32 stat = nvkm_rd32(device, 0x10a16c); if (stat & 0x80000000) { - nv_error(pmu, "UAS fault at 0x%06x addr 0x%08x\n", - stat & 0x00ffffff, nvkm_rd32(device, 0x10a168)); + nvkm_error(subdev, "UAS fault at %06x addr %08x\n", + stat & 0x00ffffff, + nvkm_rd32(device, 0x10a168)); nvkm_wr32(device, 0x10a16c, 0x00000000); intr &= ~0x00000020; } @@ -165,14 +167,15 @@ nvkm_pmu_intr(struct nvkm_subdev *subdev) } if (intr & 0x00000080) { - nv_info(pmu, "wr32 0x%06x 0x%08x\n", nvkm_rd32(device, 0x10a7a0), - nvkm_rd32(device, 0x10a7a4)); + nvkm_info(subdev, "wr32 %06x %08x\n", + nvkm_rd32(device, 0x10a7a0), + nvkm_rd32(device, 0x10a7a4)); nvkm_wr32(device, 0x10a004, 0x00000080); intr &= ~0x00000080; } if (intr) { - nv_error(pmu, "intr 0x%08x\n", intr); + nvkm_error(subdev, "intr %08x\n", intr); nvkm_wr32(device, 0x10a004, intr); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 469177e34563c..bea2833142402 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -81,7 +81,7 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) if (nv_device_match(device, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ || nv_device_match(device, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ || nvkm_boolopt(device->cfgopt, "War00C800_0", false)) { - nv_info(pmu, "hw bug workaround enabled\n"); + nvkm_info(&pmu->subdev, "hw bug workaround enabled\n"); switch (device->chipset) { case 0xe4: magic(device, 0x04000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 20087d53fb9c2..1003013666a94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -84,7 +84,8 @@ gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu *pmu, level = min(clk->state_nr - 1, level); } - nv_trace(pmu, "cur level = %d, new level = %d\n", cur_level, level); + nvkm_trace(&pmu->base.subdev, "cur level = %d, new level = %d\n", + cur_level, level); *state = level; @@ -119,8 +120,10 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) container_of(alarm, struct gk20a_pmu, alarm); struct gk20a_pmu_dvfs_data *data = pmu->data; struct gk20a_pmu_dvfs_dev_status status; - struct nvkm_clk *clk = nvkm_clk(pmu); - struct nvkm_volt *volt = nvkm_volt(pmu); + struct nvkm_subdev *subdev = &pmu->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_clk *clk = device->clk; + struct nvkm_volt *volt = device->volt; u32 utilization = 0; int state, ret; @@ -133,7 +136,7 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) ret = gk20a_pmu_dvfs_get_dev_status(pmu, &status); if (ret) { - nv_warn(pmu, "failed to get device status\n"); + nvkm_warn(subdev, "failed to get device status\n"); goto resched; } @@ -142,17 +145,17 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) data->avg_load = (data->p_smooth * data->avg_load) + utilization; data->avg_load /= data->p_smooth + 1; - nv_trace(pmu, "utilization = %d %%, avg_load = %d %%\n", - utilization, data->avg_load); + nvkm_trace(subdev, "utilization = %d %%, avg_load = %d %%\n", + utilization, data->avg_load); ret = gk20a_pmu_dvfs_get_cur_state(pmu, &state); if (ret) { - nv_warn(pmu, "failed to get current state\n"); + nvkm_warn(subdev, "failed to get current state\n"); goto resched; } if (gk20a_pmu_dvfs_get_target_state(pmu, &state, data->avg_load)) { - nv_trace(pmu, "set new state to %d\n", state); + nvkm_trace(subdev, "set new state to %d\n", state); gk20a_pmu_dvfs_target(pmu, &state); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index 8469698847964..556aefe3614f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -72,7 +72,8 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) { struct nvkm_memx *memx = *pmemx; struct nvkm_pmu *pmu = memx->pmu; - struct nvkm_device *device = pmu->subdev.device; + struct nvkm_subdev *subdev = &pmu->subdev; + struct nvkm_device *device = subdev->device; u32 finish, reply[2]; /* flush the cache... */ @@ -88,8 +89,8 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) memx->base, finish); } - nv_debug(memx->pmu, "Exec took %uns, PMU_IN %08x\n", - reply[0], reply[1]); + nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", + reply[0], reply[1]); kfree(memx); return 0; } @@ -97,7 +98,7 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) void nvkm_memx_wr32(struct nvkm_memx *memx, u32 addr, u32 data) { - nv_debug(memx->pmu, "R[%06x] = 0x%08x\n", addr, data); + nvkm_debug(&memx->pmu->subdev, "R[%06x] = %08x\n", addr, data); memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data }); } @@ -105,8 +106,8 @@ void nvkm_memx_wait(struct nvkm_memx *memx, u32 addr, u32 mask, u32 data, u32 nsec) { - nv_debug(memx->pmu, "R[%06x] & 0x%08x == 0x%08x, %d us\n", - addr, mask, data, nsec); + nvkm_debug(&memx->pmu->subdev, "R[%06x] & %08x == %08x, %d us\n", + addr, mask, data, nsec); memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec }); memx_out(memx); /* fuc can't handle multiple */ } @@ -114,7 +115,7 @@ nvkm_memx_wait(struct nvkm_memx *memx, void nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec) { - nv_debug(memx->pmu, " DELAY = %d ns\n", nsec); + nvkm_debug(&memx->pmu->subdev, " DELAY = %d ns\n", nsec); memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec }); memx_out(memx); /* fuc can't handle multiple */ } @@ -122,7 +123,8 @@ nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec) void nvkm_memx_wait_vblank(struct nvkm_memx *memx) { - struct nvkm_device *device = memx->pmu->subdev.device; + struct nvkm_subdev *subdev = &memx->pmu->subdev; + struct nvkm_device *device = subdev->device; u32 heads, x, y, px = 0; int i, head_sync; @@ -143,11 +145,11 @@ nvkm_memx_wait_vblank(struct nvkm_memx *memx) } if (px == 0) { - nv_debug(memx->pmu, "WAIT VBLANK !NO ACTIVE HEAD\n"); + nvkm_debug(subdev, "WAIT VBLANK !NO ACTIVE HEAD\n"); return; } - nv_debug(memx->pmu, "WAIT VBLANK HEAD%d\n", head_sync); + nvkm_debug(subdev, "WAIT VBLANK HEAD%d\n", head_sync); memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync }); memx_out(memx); /* fuc can't handle multiple */ } @@ -155,7 +157,7 @@ nvkm_memx_wait_vblank(struct nvkm_memx *memx) void nvkm_memx_train(struct nvkm_memx *memx) { - nv_debug(memx->pmu, " MEM TRAIN\n"); + nvkm_debug(&memx->pmu->subdev, " MEM TRAIN\n"); memx_cmd(memx, MEMX_TRAIN, 0, NULL); } @@ -188,14 +190,14 @@ nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) void nvkm_memx_block(struct nvkm_memx *memx) { - nv_debug(memx->pmu, " HOST BLOCKED\n"); + nvkm_debug(&memx->pmu->subdev, " HOST BLOCKED\n"); memx_cmd(memx, MEMX_ENTER, 0, NULL); } void nvkm_memx_unblock(struct nvkm_memx *memx) { - nv_debug(memx->pmu, " HOST UNBLOCKED\n"); + nvkm_debug(&memx->pmu->subdev, " HOST UNBLOCKED\n"); memx_cmd(memx, MEMX_LEAVE, 0, NULL); } #endif -- GitLab From b3c418bb48228a206a8c421adaf269cdc83c3c52 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5423/7006] drm/nouveau/therm: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/therm/base.c | 13 +++++--- .../gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 21 ++++++------ .../gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 22 +++++++------ .../gpu/drm/nouveau/nvkm/subdev/therm/gf110.c | 5 +-- .../gpu/drm/nouveau/nvkm/subdev/therm/ic.c | 8 ++--- .../gpu/drm/nouveau/nvkm/subdev/therm/nv40.c | 17 ++++++---- .../gpu/drm/nouveau/nvkm/subdev/therm/nv50.c | 4 ++- .../gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 32 +++++++++++-------- 8 files changed, 72 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index 87c20d197102b..18fa0443b6d3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -83,7 +83,8 @@ static void nvkm_therm_update(struct nvkm_therm *obj, int mode) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *tmr = nvkm_timer(therm); + struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_timer *tmr = subdev->device->timer; unsigned long flags; bool immd = true; bool poll = true; @@ -129,7 +130,7 @@ nvkm_therm_update(struct nvkm_therm *obj, int mode) spin_unlock_irqrestore(&therm->lock, flags); if (duty >= 0) { - nv_debug(therm, "FAN target request: %d%%\n", duty); + nvkm_debug(subdev, "FAN target request: %d%%\n", duty); nvkm_therm_fan_set(&therm->base, immd, duty); } } @@ -138,9 +139,10 @@ int nvkm_therm_cstate(struct nvkm_therm *obj, int fan, int dir) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_subdev *subdev = &therm->base.subdev; if (!dir || (dir < 0 && fan < therm->cstate) || (dir > 0 && fan > therm->cstate)) { - nv_debug(therm, "default fan speed -> %d%%\n", fan); + nvkm_debug(subdev, "default fan speed -> %d%%\n", fan); therm->cstate = fan; nvkm_therm_update(&therm->base, -1); } @@ -159,7 +161,8 @@ int nvkm_therm_fan_mode(struct nvkm_therm *obj, int mode) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = nv_device(therm); + struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_device *device = subdev->device; static const char *name[] = { "disabled", "manual", @@ -181,7 +184,7 @@ nvkm_therm_fan_mode(struct nvkm_therm *obj, int mode) if (therm->mode == mode) return 0; - nv_info(therm, "fan management: %s\n", name[mode]); + nvkm_debug(subdev, "fan management: %s\n", name[mode]); nvkm_therm_update(&therm->base, mode); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index 83ebf366a221a..43fff761a1777 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -32,7 +32,8 @@ static int nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) { struct nvkm_therm_priv *therm = (void *)fan->parent; - struct nvkm_timer *tmr = nvkm_timer(therm); + struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_timer *tmr = subdev->device->timer; unsigned long flags; int ret = 0; int duty; @@ -44,7 +45,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) target = max_t(u8, target, fan->bios.min_duty); target = min_t(u8, target, fan->bios.max_duty); if (fan->percent != target) { - nv_debug(therm, "FAN target: %d\n", target); + nvkm_debug(subdev, "FAN target: %d\n", target); fan->percent = target; } @@ -69,7 +70,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) duty = target; } - nv_debug(therm, "FAN update: %d\n", duty); + nvkm_debug(subdev, "FAN update: %d\n", duty); ret = fan->set(&therm->base, duty); if (ret) { spin_unlock_irqrestore(&fan->lock, flags); @@ -228,8 +229,10 @@ int nvkm_therm_fan_ctor(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_gpio *gpio = nvkm_gpio(therm); - struct nvkm_bios *bios = nvkm_bios(therm); + struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_gpio *gpio = device->gpio; + struct nvkm_bios *bios = device->bios; struct dcb_gpio_func func; int ret; @@ -238,7 +241,7 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) if (ret == 0) { /* FIXME: is this really the place to perform such checks ? */ if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { - nv_debug(therm, "GPIO_FAN is in input mode\n"); + nvkm_debug(subdev, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { ret = nvkm_fanpwm_create(&therm->base, &func); @@ -254,7 +257,7 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) return ret; } - nv_info(therm, "FAN control: %s\n", therm->fan->type); + nvkm_debug(subdev, "FAN control: %s\n", therm->fan->type); /* read the current speed, it is useful when resuming */ therm->fan->percent = nvkm_therm_fan_get(&therm->base); @@ -273,9 +276,9 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) nvkm_therm_fan_set_defaults(&therm->base); nvbios_perf_fan_parse(bios, &therm->fan->perf); if (!nvbios_fan_parse(bios, &therm->fan->bios)) { - nv_debug(therm, "parsing the fan table failed\n"); + nvkm_debug(subdev, "parsing the fan table failed\n"); if (nvbios_therm_fan_parse(bios, &therm->fan->bios)) - nv_error(therm, "parsing both fan tables failed\n"); + nvkm_error(subdev, "parsing both fan tables failed\n"); } nvkm_therm_fan_safety_checks(&therm->base); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index 50d198b610872..a1da856d5103e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -56,8 +56,9 @@ static void g84_therm_program_alarms(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = therm->base.subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; + struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_device *device = subdev->device; unsigned long flags; spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); @@ -79,13 +80,16 @@ g84_therm_program_alarms(struct nvkm_therm *obj) nvkm_wr32(device, 0x20414, sensor->thrs_down_clock.temp); spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); - nv_debug(therm, - "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", - sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, - sensor->thrs_down_clock.temp, - sensor->thrs_down_clock.hysteresis, - sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, - sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); + nvkm_debug(subdev, + "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", + sensor->thrs_fan_boost.temp, + sensor->thrs_fan_boost.hysteresis, + sensor->thrs_down_clock.temp, + sensor->thrs_down_clock.hysteresis, + sensor->thrs_critical.temp, + sensor->thrs_critical.hysteresis, + sensor->thrs_shutdown.temp, + sensor->thrs_shutdown.hysteresis); } @@ -180,7 +184,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) } if (intr) - nv_error(therm, "unhandled intr 0x%08x\n", intr); + nvkm_error(subdev, "intr %08x\n", intr); /* ACK everything */ nvkm_wr32(device, 0x20100, 0xffffffff); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c index 9686250e5a02b..4d017f62d7e4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c @@ -26,7 +26,8 @@ static int pwm_info(struct nvkm_therm *therm, int line) { - struct nvkm_device *device = therm->subdev.device; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; u32 gpio = nvkm_rd32(device, 0x00d610 + (line * 0x04)); switch (gpio & 0x000000c0) { @@ -44,7 +45,7 @@ pwm_info(struct nvkm_therm *therm, int line) break; } - nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio); + nvkm_error(subdev, "GPIO %d unknown PWM: %08x\n", line, gpio); return -ENODEV; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c index f62198aa29690..f2b0165c6d96c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c @@ -46,10 +46,10 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c, return false; } - nv_info(therm, - "Found an %s at address 0x%x (controlled by lm_sensors, " - "temp offset %+i C)\n", - info->type, info->addr, sensor->offset_constant); + nvkm_debug(&therm->base.subdev, + "Found an %s at address 0x%x (controlled by lm_sensors, " + "temp offset %+i C)\n", + info->type, info->addr, sensor->offset_constant); therm->ic = client; return true; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c index da5e9591fe3b4..f2dd7520eff44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c @@ -109,12 +109,13 @@ nv40_temp_get(struct nvkm_therm *obj) static int nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { - struct nvkm_device *device = therm->subdev.device; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; u32 mask = enable ? 0x80000000 : 0x0000000; if (line == 2) nvkm_mask(device, 0x0010f0, 0x80000000, mask); else if (line == 9) nvkm_mask(device, 0x0015f4, 0x80000000, mask); else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } return 0; @@ -123,7 +124,8 @@ nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) static int nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { - struct nvkm_device *device = therm->subdev.device; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; if (line == 2) { u32 reg = nvkm_rd32(device, 0x0010f0); if (reg & 0x80000000) { @@ -140,7 +142,7 @@ nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) return 0; } } else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } @@ -150,7 +152,8 @@ nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) static int nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { - struct nvkm_device *device = therm->subdev.device; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; if (line == 2) { nvkm_mask(device, 0x0010f0, 0x7fff7fff, (duty << 16) | divs); } else @@ -158,7 +161,7 @@ nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) nvkm_wr32(device, 0x0015f8, divs); nvkm_mask(device, 0x0015f4, 0x7fffffff, duty); } else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", line); return -ENODEV; } @@ -177,7 +180,7 @@ nv40_therm_intr(struct nvkm_subdev *subdev) /* ack all IRQs */ nvkm_wr32(device, 0x1100, 0x70000); - nv_error(therm, "THERM received an IRQ: stat = %x\n", stat); + nvkm_error(subdev, "THERM received an IRQ: stat = %x\n", stat); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c index d786ae7625040..787f3cf19747c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c @@ -27,6 +27,8 @@ static int pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) { + struct nvkm_subdev *subdev = &therm->subdev; + if (*line == 0x04) { *ctrl = 0x00e100; *line = 4; @@ -42,7 +44,7 @@ pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx) *line = 0; *indx = 0; } else { - nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line); + nvkm_error(subdev, "unknown pwm ctrl for gpio %d\n", *line); return -ENODEV; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index 41628de3bf6ce..b346f3a0ff119 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -88,6 +88,7 @@ nvkm_therm_sensor_event(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_direction dir) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_subdev *subdev = &therm->base.subdev; bool active; const char *thresolds[] = { "fanboost", "downclock", "critical", "shutdown" @@ -98,11 +99,12 @@ nvkm_therm_sensor_event(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs, return; if (dir == NVKM_THERM_THRS_FALLING) - nv_info(therm, "temperature (%i C) went below the '%s' threshold\n", - temperature, thresolds[thrs]); + nvkm_info(subdev, + "temperature (%i C) went below the '%s' threshold\n", + temperature, thresolds[thrs]); else - nv_info(therm, "temperature (%i C) hit the '%s' threshold\n", - temperature, thresolds[thrs]); + nvkm_info(subdev, "temperature (%i C) hit the '%s' threshold\n", + temperature, thresolds[thrs]); active = (dir == NVKM_THERM_THRS_RISING); switch (thrs) { @@ -200,13 +202,16 @@ nvkm_therm_program_alarms_polling(struct nvkm_therm *obj) struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvbios_therm_sensor *sensor = &therm->bios_sensor; - nv_debug(therm, - "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", - sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, - sensor->thrs_down_clock.temp, - sensor->thrs_down_clock.hysteresis, - sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis, - sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis); + nvkm_debug(&therm->base.subdev, + "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", + sensor->thrs_fan_boost.temp, + sensor->thrs_fan_boost.hysteresis, + sensor->thrs_down_clock.temp, + sensor->thrs_down_clock.hysteresis, + sensor->thrs_critical.temp, + sensor->thrs_critical.hysteresis, + sensor->thrs_shutdown.temp, + sensor->thrs_shutdown.hysteresis); alarm_timer_callback(&therm->sensor.therm_poll_alarm); } @@ -238,13 +243,14 @@ nvkm_therm_sensor_preinit(struct nvkm_therm *therm) if (therm->temp_get(therm) < 0) sensor_avail = "no"; - nv_info(therm, "internal sensor: %s\n", sensor_avail); + nvkm_debug(&therm->subdev, "internal sensor: %s\n", sensor_avail); } int nvkm_therm_sensor_ctor(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); + struct nvkm_subdev *subdev = &therm->base.subdev; struct nvkm_bios *bios = nvkm_bios(therm); nvkm_alarm_init(&therm->sensor.therm_poll_alarm, alarm_timer_callback); @@ -252,7 +258,7 @@ nvkm_therm_sensor_ctor(struct nvkm_therm *obj) nvkm_therm_temp_set_defaults(&therm->base); if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, &therm->bios_sensor)) - nv_error(therm, "nvbios_therm_sensor_parse failed\n"); + nvkm_error(subdev, "nvbios_therm_sensor_parse failed\n"); nvkm_therm_temp_safety_checks(&therm->base); return 0; -- GitLab From 9d7b9d9f1140e56ad14111fd9576e7333412dc12 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5424/7006] drm/nouveau/tmr: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c | 7 ++++--- .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 21 ++++++++++--------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c index b7d6c26262a31..46bfa10b5b97c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c @@ -27,7 +27,8 @@ static int gk20a_timer_init(struct nvkm_object *object) { struct nv04_timer *tmr = (void *)object; - struct nvkm_device *device = tmr->base.subdev.device; + struct nvkm_subdev *subdev = &tmr->base.subdev; + struct nvkm_device *device = subdev->device; u32 hi = upper_32_bits(tmr->suspend_time); u32 lo = lower_32_bits(tmr->suspend_time); int ret; @@ -36,8 +37,8 @@ gk20a_timer_init(struct nvkm_object *object) if (ret) return ret; - nv_debug(tmr, "time low : 0x%08x\n", lo); - nv_debug(tmr, "time high : 0x%08x\n", hi); + nvkm_debug(subdev, "time low : %08x\n", lo); + nvkm_debug(subdev, "time high : %08x\n", hi); /* restore the time before suspend */ nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index 0ef69ddaf4ed5..8d45753f65acb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -121,7 +121,7 @@ nv04_timer_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_error(tmr, "unknown stat 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_wr32(device, NV04_PTIMER_INTR_0, stat); } } @@ -141,7 +141,8 @@ static int nv04_timer_init(struct nvkm_object *object) { struct nv04_timer *tmr = (void *)object; - struct nvkm_device *device = tmr->base.subdev.device; + struct nvkm_subdev *subdev = &tmr->base.subdev; + struct nvkm_device *device = subdev->device; u32 m = 1, f, n, d, lo, hi; int ret; @@ -174,7 +175,7 @@ nv04_timer_init(struct nvkm_object *object) } if (!n) { - nv_warn(tmr, "unknown input clock freq\n"); + nvkm_warn(subdev, "unknown input clock freq\n"); if (!nvkm_rd32(device, NV04_PTIMER_NUMERATOR) || !nvkm_rd32(device, NV04_PTIMER_DENOMINATOR)) { nvkm_wr32(device, NV04_PTIMER_NUMERATOR, 1); @@ -203,13 +204,13 @@ nv04_timer_init(struct nvkm_object *object) lo = tmr->suspend_time; hi = (tmr->suspend_time >> 32); - nv_debug(tmr, "input frequency : %dHz\n", f); - nv_debug(tmr, "input multiplier: %d\n", m); - nv_debug(tmr, "numerator : 0x%08x\n", n); - nv_debug(tmr, "denominator : 0x%08x\n", d); - nv_debug(tmr, "timer frequency : %dHz\n", (f * m) * d / n); - nv_debug(tmr, "time low : 0x%08x\n", lo); - nv_debug(tmr, "time high : 0x%08x\n", hi); + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "input multiplier: %d\n", m); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", (f * m) * d / n); + nvkm_debug(subdev, "time low : %08x\n", lo); + nvkm_debug(subdev, "time high : %08x\n", hi); nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); -- GitLab From 185eda33394af09dbb0c9d330811718e84c0b070 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5425/7006] drm/nouveau/volt: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c | 15 +++++++++------ .../gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 17 ++++++++++------- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c | 5 +++-- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 53a173694fb4c..67650a351a96a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -46,12 +46,13 @@ nvkm_volt_get(struct nvkm_volt *volt) static int nvkm_volt_set(struct nvkm_volt *volt, u32 uv) { + struct nvkm_subdev *subdev = &volt->subdev; if (volt->vid_set) { int i, ret = -EINVAL; for (i = 0; i < volt->vid_nr; i++) { if (volt->vid[i].uv == uv) { ret = volt->vid_set(volt, volt->vid[i].vid); - nv_debug(volt, "set %duv: %d\n", uv, ret); + nvkm_debug(subdev, "set %duv: %d\n", uv, ret); break; } } @@ -138,6 +139,7 @@ int _nvkm_volt_init(struct nvkm_object *object) { struct nvkm_volt *volt = (void *)object; + struct nvkm_subdev *subdev = &volt->subdev; int ret; ret = nvkm_subdev_init(&volt->subdev); @@ -147,11 +149,11 @@ _nvkm_volt_init(struct nvkm_object *object) ret = volt->get(volt); if (ret < 0) { if (ret != -ENODEV) - nv_debug(volt, "current voltage unknown\n"); + nvkm_debug(subdev, "current voltage unknown\n"); return 0; } - nv_info(volt, "GPU voltage: %duv\n", ret); + nvkm_debug(subdev, "current voltage: %duv\n", ret); return 0; } @@ -166,7 +168,8 @@ int nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_bios *bios = nvkm_bios(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_bios *bios = device->bios; struct nvkm_volt *volt; int ret, i; @@ -186,8 +189,8 @@ nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (volt->vid_nr) { for (i = 0; i < volt->vid_nr; i++) { - nv_debug(volt, "VID %02x: %duv\n", - volt->vid[i].vid, volt->vid[i].uv); + nvkm_debug(&volt->subdev, "VID %02x: %duv\n", + volt->vid[i].vid, volt->vid[i].uv); } /*XXX: this is an assumption.. there probably exists boards diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 2be1aa39602fa..d86f4eaba04c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -119,8 +119,9 @@ static int gk20a_volt_vid_set(struct nvkm_volt *obj, u8 vid) { struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); + struct nvkm_subdev *subdev = &volt->base.subdev; - nv_debug(volt, "set voltage as %duv\n", volt->base.vid[vid].uv); + nvkm_debug(subdev, "set voltage as %duv\n", volt->base.vid[vid].uv); return regulator_set_voltage(volt->vdd, volt->base.vid[vid].uv, 1200000); } @@ -128,12 +129,13 @@ static int gk20a_volt_set_id(struct nvkm_volt *obj, u8 id, int condition) { struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); + struct nvkm_subdev *subdev = &volt->base.subdev; int prev_uv = regulator_get_voltage(volt->vdd); int target_uv = volt->base.vid[id].uv; int ret; - nv_debug(volt, "prev=%d, target=%d, condition=%d\n", - prev_uv, target_uv, condition); + nvkm_debug(subdev, "prev=%d, target=%d, condition=%d\n", + prev_uv, target_uv, condition); if (!condition || (condition < 0 && target_uv < prev_uv) || (condition > 0 && target_uv > prev_uv)) { @@ -162,7 +164,7 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, plat = nv_device_to_platform(nv_device(parent)); uv = regulator_get_voltage(plat->gpu->vdd); - nv_info(volt, "The default voltage is %duV\n", uv); + nvkm_info(&volt->base.subdev, "The default voltage is %duV\n", uv); volt->vdd = plat->gpu->vdd; volt->base.vid_get = gk20a_volt_vid_get; @@ -170,14 +172,15 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, volt->base.set_id = gk20a_volt_set_id; volt->base.vid_nr = ARRAY_SIZE(gk20a_cvb_coef); - nv_debug(volt, "%s - vid_nr = %d\n", __func__, volt->base.vid_nr); + nvkm_debug(&volt->base.subdev, "%s - vid_nr = %d\n", __func__, + volt->base.vid_nr); for (i = 0; i < volt->base.vid_nr; i++) { volt->base.vid[i].vid = i; volt->base.vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], plat->gpu_speedo); - nv_debug(volt, "%2d: vid=%d, uv=%d\n", i, - volt->base.vid[i].vid, volt->base.vid[i].uv); + nvkm_debug(&volt->base.subdev, "%2d: vid=%d, uv=%d\n", i, + volt->base.vid[i].vid, volt->base.vid[i].uv); } return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c index b778deb32d939..33388378aa6d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c @@ -70,7 +70,8 @@ nvkm_voltgpio_set(struct nvkm_volt *volt, u8 vid) int nvkm_voltgpio_init(struct nvkm_volt *volt) { - struct nvkm_gpio *gpio = nvkm_gpio(volt); + struct nvkm_subdev *subdev = &volt->subdev; + struct nvkm_gpio *gpio = subdev->device->gpio; struct dcb_gpio_func func; int i; @@ -86,7 +87,7 @@ nvkm_voltgpio_init(struct nvkm_volt *volt) if (ret) { if (ret != -ENOENT) return ret; - nv_debug(volt, "VID bit %d has no GPIO\n", i); + nvkm_debug(subdev, "VID bit %d has no GPIO\n", i); volt->vid_mask &= ~(1 << i); } } -- GitLab From 64b5ce1fe9ab0949c6387f5df57aaf0527567e08 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5426/7006] drm/nouveau/falcon: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 27 ++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 408d9c7d5e908..e0e76756a1277 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -31,13 +31,13 @@ nvkm_falcon_intr(struct nvkm_subdev *subdev) u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); if (intr & 0x00000010) { - nv_debug(falcon, "ucode halted\n"); + nvkm_debug(subdev, "ucode halted\n"); nv_wo32(falcon, 0x004, 0x00000010); intr &= ~0x00000010; } if (intr) { - nv_error(falcon, "unhandled intr 0x%08x\n", intr); + nvkm_error(subdev, "intr %08x\n", intr); nv_wo32(falcon, 0x004, intr); } } @@ -69,8 +69,9 @@ vmemdup(const void *src, size_t len) int _nvkm_falcon_init(struct nvkm_object *object) { - struct nvkm_device *device = nv_device(object); struct nvkm_falcon *falcon = (void *)object; + struct nvkm_subdev *subdev = &falcon->engine.subdev; + struct nvkm_device *device = subdev->device; const struct firmware *fw; char name[32] = "internal"; int ret, i; @@ -95,10 +96,10 @@ _nvkm_falcon_init(struct nvkm_object *object) falcon->code.limit = (caps & 0x000001ff) << 8; falcon->data.limit = (caps & 0x0003fe00) >> 1; - nv_debug(falcon, "falcon version: %d\n", falcon->version); - nv_debug(falcon, "secret level: %d\n", falcon->secret); - nv_debug(falcon, "code limit: %d\n", falcon->code.limit); - nv_debug(falcon, "data limit: %d\n", falcon->data.limit); + nvkm_debug(subdev, "falcon version: %d\n", falcon->version); + nvkm_debug(subdev, "secret level: %d\n", falcon->secret); + nvkm_debug(subdev, "code limit: %d\n", falcon->code.limit); + nvkm_debug(subdev, "data limit: %d\n", falcon->data.limit); /* wait for 'uc halted' to be signalled before continuing */ if (falcon->secret && falcon->version < 4) { @@ -147,7 +148,7 @@ _nvkm_falcon_init(struct nvkm_object *object) ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { - nv_error(falcon, "unable to load firmware data\n"); + nvkm_error(subdev, "unable to load firmware data\n"); return ret; } @@ -162,7 +163,7 @@ _nvkm_falcon_init(struct nvkm_object *object) ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { - nv_error(falcon, "unable to load firmware code\n"); + nvkm_error(subdev, "unable to load firmware code\n"); return ret; } @@ -173,15 +174,15 @@ _nvkm_falcon_init(struct nvkm_object *object) return -ENOMEM; } - nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ? - "static code/data segments" : "self-bootstrapping"); + nvkm_debug(subdev, "firmware: %s (%s)\n", name, falcon->data.data ? + "static code/data segments" : "self-bootstrapping"); /* ensure any "self-bootstrapping" firmware image is in vram */ if (!falcon->data.data && !falcon->core) { ret = nvkm_gpuobj_new(object->parent, NULL, falcon->code.size, 256, 0, &falcon->core); if (ret) { - nv_error(falcon, "core allocation failed, %d\n", ret); + nvkm_error(subdev, "core allocation failed, %d\n", ret); return ret; } @@ -202,7 +203,7 @@ _nvkm_falcon_init(struct nvkm_object *object) } else { if (falcon->code.size > falcon->code.limit || falcon->data.size > falcon->data.limit) { - nv_error(falcon, "ucode exceeds falcon limit(s)\n"); + nvkm_error(subdev, "ucode exceeds falcon limit(s)\n"); return -EINVAL; } -- GitLab From 7108bfe4086862fa29ba1cf82f4dee66be314619 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5427/7006] drm/nouveau/xtensa: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index f7ffe09816b5e..027660c359795 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -62,11 +62,11 @@ _nvkm_xtensa_intr(struct nvkm_subdev *subdev) u32 unk10c = nv_ro32(xtensa, 0xd0c); if (intr & 0x10) - nv_warn(xtensa, "Watchdog interrupt, engine hung.\n"); + nvkm_warn(subdev, "Watchdog interrupt, engine hung.\n"); nv_wo32(xtensa, 0xc20, intr); intr = nv_ro32(xtensa, 0xc20); if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) { - nv_debug(xtensa, "Enabling FIFO_CTRL\n"); + nvkm_debug(subdev, "Enabling FIFO_CTRL\n"); nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->fifo_val); } } @@ -94,8 +94,9 @@ nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine, int _nvkm_xtensa_init(struct nvkm_object *object) { - struct nvkm_device *device = nv_device(object); struct nvkm_xtensa *xtensa = (void *)object; + struct nvkm_subdev *subdev = &xtensa->engine.subdev; + struct nvkm_device *device = subdev->device; const struct firmware *fw; char name[32]; int i, ret; @@ -111,12 +112,12 @@ _nvkm_xtensa_init(struct nvkm_object *object) ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { - nv_warn(xtensa, "unable to load firmware %s\n", name); + nvkm_warn(subdev, "unable to load firmware %s\n", name); return ret; } if (fw->size > 0x40000) { - nv_warn(xtensa, "firmware %s too large\n", name); + nvkm_warn(subdev, "firmware %s too large\n", name); release_firmware(fw); return -EINVAL; } @@ -128,8 +129,8 @@ _nvkm_xtensa_init(struct nvkm_object *object) return ret; } - nv_debug(xtensa, "Loading firmware to address: 0x%llx\n", - xtensa->gpu_fw->addr); + nvkm_debug(subdev, "Loading firmware to address: %010llx\n", + xtensa->gpu_fw->addr); for (i = 0; i < fw->size / 4; i++) nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); -- GitLab From 1eed206fa29a98df728dd6e67ac02e135645029f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5428/7006] drm/nouveau/ce: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c | 3 +-- drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c | 3 +-- drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 14 ++++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index 2237a44a53706..8fad0ef13bd06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -64,11 +64,10 @@ gk104_ce_intr(struct nvkm_subdev *subdev) { struct nvkm_device *device = subdev->device; const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - struct nvkm_engine *ce = (void *)subdev; u32 stat = nvkm_rd32(device, 0x104908 + (idx * 0x1000)); if (stat) { - nv_warn(ce, "unhandled intr 0x%08x\n", stat); + nvkm_warn(subdev, "intr %08x\n", stat); nvkm_wr32(device, 0x104908 + (idx * 0x1000), stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index 698deddd51f5f..23dc90769b1ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -64,11 +64,10 @@ gm204_ce_intr(struct nvkm_subdev *subdev) { struct nvkm_device *device = subdev->device; const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - struct nvkm_engine *ce = (void *)subdev; u32 stat = nvkm_rd32(device, 0x104908 + (idx * 0x1000)); if (stat) { - nv_warn(ce, "unhandled intr 0x%08x\n", stat); + nvkm_warn(subdev, "intr %08x\n", stat); nvkm_wr32(device, 0x104908 + (idx * 0x1000), stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index a8fff0e13e195..49aeeb74990a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -76,6 +76,7 @@ gt215_ce_intr(struct nvkm_subdev *subdev) struct nvkm_engine *engine = nv_engine(subdev); struct nvkm_falcon *falcon = (void *)subdev; struct nvkm_object *engctx; + const struct nvkm_enum *en; u32 dispatch = nv_ro32(falcon, 0x01c); u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff; @@ -90,17 +91,18 @@ gt215_ce_intr(struct nvkm_subdev *subdev) chid = fifo->chid(fifo, engctx); if (stat & 0x00000040) { - nv_error(falcon, "DISPATCH_ERROR ["); - nvkm_enum_print(gt215_ce_isr_error_name, ssta); - pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, - mthd, data); + en = nvkm_enum_find(gt215_ce_isr_error_name, ssta); + nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] " + "ch %d [%010llx %s] subc %d " + "mthd %04x data %08x\n", + ssta, en ? en->name : "", chid, inst << 12, + nvkm_client_name(engctx), subc, mthd, data); nv_wo32(falcon, 0x004, 0x00000040); stat &= ~0x00000040; } if (stat) { - nv_error(falcon, "unhandled intr 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nv_wo32(falcon, 0x004, stat); } -- GitLab From 65850a3b407b065f4b0db0264796d2981feb85aa Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:12 +1000 Subject: [PATCH 5429/7006] drm/nouveau/cipher: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index b6b05a7dcae91..ddc240d25d817 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -113,17 +113,18 @@ g84_cipher_intr(struct nvkm_subdev *subdev) u32 mthd = nvkm_rd32(device, 0x102190); u32 data = nvkm_rd32(device, 0x102194); u32 inst = nvkm_rd32(device, 0x102188) & 0x7fffffff; + char msg[128]; int chid; engctx = nvkm_engctx_get(engine, inst); chid = fifo->chid(fifo, engctx); if (stat) { - nv_error(cipher, "%s", ""); - nvkm_bitfield_print(g84_cipher_intr_mask, stat); - pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n", - chid, (u64)inst << 12, nvkm_client_name(engctx), - mthd, data); + nvkm_snprintbf(msg, sizeof(msg), g84_cipher_intr_mask, stat); + nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] " + "mthd %04x data %08x\n", + stat, msg, chid, (u64)inst << 12, + nvkm_client_name(engctx), mthd, data); } nvkm_wr32(device, 0x102130, stat); -- GitLab From e37f543370b86de9eefd86896adb171b7c45a451 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5430/7006] drm/nouveau/device: switch to dev_printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 11 +++-------- drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c | 1 - 10 files changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index bced8ea58f455..c58ea4f44c702 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -414,14 +414,11 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } if (ret) { - nv_error(device, "unknown chipset, 0x%08x\n", boot0); + nvdev_error(device, "unknown chipset (%08x)\n", boot0); return ret; } - nv_info(device, "BOOT0 : 0x%08x\n", boot0); - nv_info(device, "Chipset: %s (NV%02X)\n", - device->cname, device->chipset); - nv_info(device, "Family : NV%02X\n", device->card_type); + nvdev_info(device, "NVIDIA %s (%08x)\n", device->cname, boot0); /* determine frequency of timing crystal */ if ( device->card_type <= NV_10 || device->chipset < 0x17 || @@ -436,8 +433,6 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, case 0x00400000: device->crystal = 27000; break; case 0x00400040: device->crystal = 25000; break; } - - nv_debug(device, "crystal freq: %dKHz\n", device->crystal); } else if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) { device->cname = "NULL"; @@ -447,7 +442,7 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && !device->pri) { device->pri = ioremap(mmio_base, mmio_size); if (!device->pri) { - nv_error(device, "unable to map device registers\n"); + nvdev_error(device, "unable to map PRI\n"); return -ENOMEM; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 65b151da83178..d8ddd228491ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -350,7 +350,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; default: - nv_fatal(device, "unknown Fermi chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 2b1fce20445b9..4e0d309443599 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -318,7 +318,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; default: - nv_fatal(device, "unknown Kepler chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index a51b3ce50f364..cd979543cdff2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -202,7 +202,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; break; default: - nv_fatal(device, "unknown Maxwell chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 5a2ae043b478c..ec357da766e5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -81,7 +81,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: - nv_fatal(device, "unknown RIVA chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 94a1ca45e94a7..37997e848d295 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -196,7 +196,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: - nv_fatal(device, "unknown Celsius chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index d5ec8937df68d..a0d414dcc1fd1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -123,7 +123,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: - nv_fatal(device, "unknown Kelvin chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index dda09621e8981..ea1739739e5f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -145,7 +145,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: - nv_fatal(device, "unknown Rankine chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index b4ad791b48519..9c7aa8d0ebd4c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -419,7 +419,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; default: - nv_fatal(device, "unknown Curie chipset\n"); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index a2627ec67c116..3c97dba02fc4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -470,7 +470,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; default: - nv_fatal(device, "unknown Tesla chipset\n"); return -EINVAL; } -- GitLab From 84407824e97d87161f5ef09ba43a1ac6ec10f479 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5431/7006] drm/nouveau/disp: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/disp/conn.h | 4 +- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 74 ++++++++------- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 93 ++++++++++--------- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/vga.c | 10 +- 7 files changed, 102 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index c87a061f7f7d8..7789f70e556a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -49,8 +49,8 @@ struct nvkm_connector_impl { #ifndef MSG #define MSG(l,f,a...) do { \ struct nvkm_connector *_conn = (void *)conn; \ - nv_##l(_conn, "%02x:%02x%02x: "f, _conn->index, \ - _conn->info.location, _conn->info.type, ##a); \ + nvkm_##l(&nvkm_disp(_conn)->engine.subdev, "%02x:%02x%02x: "f, _conn->index, \ + _conn->info.location, _conn->info.type, ##a); \ } while(0) #define DBG(f,a...) MSG(debug, f, ##a) #define ERR(f,a...) MSG(error, f, ##a) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index 7139ff6b17648..e88f5f2f87e7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -69,7 +69,8 @@ nv50_dac_power(NV50_DISP_MTHD_V1) int nv50_dac_sense(NV50_DISP_MTHD_V1) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; union { struct nv50_disp_dac_load_v0 v0; } *args = data; @@ -104,7 +105,7 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) break; ); - nv_debug(disp, "DAC%d sense: 0x%08x\n", outp->or, loadval); + nvkm_debug(subdev, "DAC%d sense: %08x\n", outp->or, loadval); if (!(loadval & 0x80000000)) return -ETIMEDOUT; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index ef728c969ecb9..ef16d92cb7a30 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -95,7 +95,8 @@ gf110_disp_dmac_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = dmac->base.chid; int ret; @@ -119,8 +120,8 @@ gf110_disp_dmac_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) break; ) < 0) { - nv_error(dmac, "init: 0x%08x\n", - nvkm_rd32(device, 0x610490 + (chid * 0x10))); + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); return -EBUSY; } @@ -132,7 +133,8 @@ gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = dmac->base.chid; /* deactivate channel */ @@ -142,8 +144,8 @@ gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000)) break; ) < 0) { - nv_error(dmac, "fini: 0x%08x\n", - nvkm_rd32(device, 0x610490 + (chid * 0x10))); + nvkm_error(subdev, "ch %d fini: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); if (suspend) return -EBUSY; } @@ -304,7 +306,8 @@ gf110_disp_core_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int ret; ret = nv50_disp_chan_init(&mast->base); @@ -327,7 +330,8 @@ gf110_disp_core_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) break; ) < 0) { - nv_error(mast, "init: 0x%08x\n", nvkm_rd32(device, 0x610490)); + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610490)); return -EBUSY; } @@ -339,7 +343,8 @@ gf110_disp_core_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; /* deactivate channel */ nvkm_mask(device, 0x610490, 0x00000010, 0x00000000); @@ -348,7 +353,8 @@ gf110_disp_core_fini(struct nvkm_object *object, bool suspend) if (!(nvkm_rd32(device, 0x610490) & 0x001e0000)) break; ) < 0) { - nv_error(mast, "fini: 0x%08x\n", nvkm_rd32(device, 0x610490)); + nvkm_error(subdev, "core fini: %08x\n", + nvkm_rd32(device, 0x610490)); if (suspend) return -EBUSY; } @@ -559,7 +565,8 @@ gf110_disp_pioc_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = pioc->base.chid; int ret; @@ -577,8 +584,8 @@ gf110_disp_pioc_init(struct nvkm_object *object) if ((tmp & 0x00030000) == 0x00010000) break; ) < 0) { - nv_error(pioc, "init: 0x%08x\n", - nvkm_rd32(device, 0x610490 + (chid * 0x10))); + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); return -EBUSY; } @@ -590,7 +597,8 @@ gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = pioc->base.chid; nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); @@ -598,8 +606,8 @@ gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000)) break; ) < 0) { - nv_error(pioc, "timeout: 0x%08x\n", - nvkm_rd32(device, 0x610490 + (chid * 0x10))); + nvkm_error(subdev, "ch %d fini: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); if (suspend) return -EBUSY; } @@ -824,7 +832,8 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvkm_output *outp; u16 mask, type; @@ -841,7 +850,7 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; default: - nv_error(disp, "unknown SOR mc 0x%08x\n", ctrl); + nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); return NULL; } } @@ -1136,14 +1145,15 @@ gf110_disp_intr_supervisor(struct work_struct *work) struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask[4]; int head; - nv_debug(disp, "supervisor %d\n", ffs(disp->super)); + nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); for (head = 0; head < disp->head.nr; head++) { mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); - nv_debug(disp, "head %d: 0x%08x\n", head, mask[head]); + nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); } if (disp->super & 0x00000001) { @@ -1151,7 +1161,7 @@ gf110_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(disp, "supervisor 1.0 - head %d\n", head); + nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); gf110_disp_intr_unk1_0(disp, head); } } else @@ -1159,19 +1169,19 @@ gf110_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(disp, "supervisor 2.0 - head %d\n", head); + nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); gf110_disp_intr_unk2_0(disp, head); } for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00010000)) continue; - nv_debug(disp, "supervisor 2.1 - head %d\n", head); + nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); gf110_disp_intr_unk2_1(disp, head); } for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(disp, "supervisor 2.2 - head %d\n", head); + nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); gf110_disp_intr_unk2_2(disp, head); } } else @@ -1179,7 +1189,7 @@ gf110_disp_intr_supervisor(struct work_struct *work) for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; - nv_debug(disp, "supervisor 3.0 - head %d\n", head); + nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); gf110_disp_intr_unk4_0(disp, head); } } @@ -1193,14 +1203,14 @@ static void gf110_disp_intr_error(struct nv50_disp *disp, int chid) { const struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12)); u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12)); u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12)); - nv_error(disp, "chid %d mthd 0x%04x data 0x%08x " - "0x%08x 0x%08x\n", - chid, (mthd & 0x0000ffc), data, mthd, unkn); + nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); if (chid == 0) { switch (mthd & 0xffc) { @@ -1241,7 +1251,7 @@ void gf110_disp_intr(struct nvkm_subdev *subdev) { struct nv50_disp *disp = (void *)subdev; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x610088); int i; @@ -1273,7 +1283,7 @@ gf110_disp_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_info(disp, "unknown intr24 0x%08x\n", stat); + nvkm_warn(subdev, "intr24 %08x\n", stat); nvkm_wr32(device, 0x6100ac, stat); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 859c06ee6fc21..3a7ec28aea7c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -167,7 +167,7 @@ nv04_disp_intr(struct nvkm_subdev *subdev) nv_device(disp)->chipset <= 0x40) { pvideo = nvkm_rd32(device, 0x8100); if (pvideo & ~0x11) - nv_info(disp, "PVIDEO intr: %08x\n", pvideo); + nvkm_info(subdev, "PVIDEO intr: %08x\n", pvideo); nvkm_wr32(device, 0x8100, pvideo); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 0cf02347178d2..f485d78290042 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -259,7 +259,8 @@ nv50_disp_dmac_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = dmac->base.chid; int ret; @@ -283,8 +284,8 @@ nv50_disp_dmac_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000)) break; ) < 0) { - nv_error(dmac, "init timeout, 0x%08x\n", - nvkm_rd32(device, 0x610200 + (chid * 0x10))); + nvkm_error(subdev, "ch %d init timeout, %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -296,7 +297,8 @@ nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = dmac->base.chid; /* deactivate channel */ @@ -306,8 +308,8 @@ nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000)) break; ) < 0) { - nv_error(dmac, "fini timeout, 0x%08x\n", - nvkm_rd32(device, 0x610200 + (chid * 0x10))); + nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); if (suspend) return -EBUSY; } @@ -326,8 +328,8 @@ static void nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, const struct nv50_disp_mthd_list *list, int inst) { - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_object *object = nv_object(disp); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int i; for (i = 0; list->data[i].mthd; i++) { @@ -339,13 +341,14 @@ nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, char mods[16]; if (prev != next) - snprintf(mods, sizeof(mods), "-> 0x%08x", next); + snprintf(mods, sizeof(mods), "-> %08x", next); else snprintf(mods, sizeof(mods), "%13c", ' '); - nv_printk_(object, debug, "\t0x%04x: 0x%08x %s%s%s\n", - mthd, prev, mods, name ? " // " : "", - name ? name : ""); + nvkm_printk_(subdev, debug, info, + "\t%04x: %08x %s%s%s\n", + mthd, prev, mods, name ? " // " : "", + name ? name : ""); } } } @@ -357,6 +360,7 @@ nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, struct nvkm_object *object = nv_object(disp); const struct nv50_disp_impl *impl = (void *)object->oclass; const struct nv50_disp_mthd_list *list; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; int i, j; if (debug > nv_subdev(disp)->debug) @@ -381,7 +385,7 @@ nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, sname = sname_; } - nv_printk_(object, debug, "%s%s:\n", cname, sname); + nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname); nv50_disp_mthd_list(disp, debug, base, impl->mthd.prev, list, j); } @@ -528,7 +532,8 @@ nv50_disp_core_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int ret; ret = nv50_disp_chan_init(&mast->base); @@ -557,7 +562,8 @@ nv50_disp_core_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x610200) & 0x80000000)) break; ) < 0) { - nv_error(mast, "init: 0x%08x\n", nvkm_rd32(device, 0x610200)); + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610200)); return -EBUSY; } @@ -569,7 +575,8 @@ nv50_disp_core_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; /* deactivate channel */ nvkm_mask(device, 0x610200, 0x00000010, 0x00000000); @@ -578,7 +585,8 @@ nv50_disp_core_fini(struct nvkm_object *object, bool suspend) if (!(nvkm_rd32(device, 0x610200) & 0x001e0000)) break; ) < 0) { - nv_error(mast, "fini: 0x%08x\n", nvkm_rd32(device, 0x610200)); + nvkm_error(subdev, "core fini: %08x\n", + nvkm_rd32(device, 0x610200)); if (suspend) return -EBUSY; } @@ -822,7 +830,8 @@ nv50_disp_pioc_init(struct nvkm_object *object) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = pioc->base.chid; int ret; @@ -835,8 +844,8 @@ nv50_disp_pioc_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) break; ) < 0) { - nv_error(pioc, "timeout0: 0x%08x\n", - nvkm_rd32(device, 0x610200 + (chid * 0x10))); + nvkm_error(subdev, "ch %d timeout0: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -846,8 +855,8 @@ nv50_disp_pioc_init(struct nvkm_object *object) if ((tmp & 0x00030000) == 0x00010000) break; ) < 0) { - nv_error(pioc, "timeout1: 0x%08x\n", - nvkm_rd32(device, 0x610200 + (chid * 0x10))); + nvkm_error(subdev, "ch %d timeout1: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); return -EBUSY; } @@ -859,7 +868,8 @@ nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) { struct nv50_disp *disp = (void *)object->engine; struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; int chid = pioc->base.chid; nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); @@ -867,8 +877,8 @@ nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) break; ) < 0) { - nv_error(pioc, "timeout: 0x%08x\n", - nvkm_rd32(device, 0x610200 + (chid * 0x10))); + nvkm_error(subdev, "ch %d timeout: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); if (suspend) return -EBUSY; } @@ -1362,26 +1372,22 @@ static void nv50_disp_intr_error(struct nv50_disp *disp, int chid) { struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); u32 addr = nvkm_rd32(device, 0x610080 + (chid * 0x08)); u32 code = (addr & 0x00ff0000) >> 16; u32 type = (addr & 0x00007000) >> 12; u32 mthd = (addr & 0x00000ffc); const struct nvkm_enum *ec, *et; - char ecunk[6], etunk[6]; et = nvkm_enum_find(nv50_disp_intr_error_type, type); - if (!et) - snprintf(etunk, sizeof(etunk), "UNK%02X", type); - ec = nvkm_enum_find(nv50_disp_intr_error_code, code); - if (!ec) - snprintf(ecunk, sizeof(ecunk), "UNK%02X", code); - nv_error(disp, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n", - et ? et->name : etunk, ec ? ec->name : ecunk, - chid, mthd, data); + nvkm_error(subdev, + "ERROR %d [%s] %02x [%s] chid %d mthd %04x data %08x\n", + type, et ? et->name : "", code, ec ? ec->name : "", + chid, mthd, data); if (chid == 0) { switch (mthd) { @@ -1423,7 +1429,8 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info) { - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvkm_output *outp; u16 mask, type; @@ -1440,7 +1447,7 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; default: - nv_error(disp, "unknown SOR mc 0x%08x\n", ctrl); + nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); return NULL; } or -= 4; @@ -1451,7 +1458,7 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, switch (ctrl & 0x00000f00) { case 0x00000000: type |= disp->pior.type[or]; break; default: - nv_error(disp, "unknown PIOR mc 0x%08x\n", ctrl); + nvkm_error(subdev, "unknown PIOR mc %08x\n", ctrl); return NULL; } } @@ -1676,7 +1683,8 @@ static void nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, struct dcb_output *outp, u32 pclk) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; const int link = !(outp->sorconf.link & 1); const int or = ffs(outp->or) - 1; const u32 soff = ( or * 0x800); @@ -1775,7 +1783,7 @@ nv50_disp_intr_unk20_2_dp(struct nv50_disp *disp, int head, } if (!bestTU) { - nv_error(disp, "unable to find suitable dp config\n"); + nvkm_error(subdev, "unable to find suitable dp config\n"); return; } @@ -1922,11 +1930,12 @@ nv50_disp_intr_supervisor(struct work_struct *work) struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 super = nvkm_rd32(device, 0x610030); int head; - nv_debug(disp, "supervisor 0x%08x 0x%08x\n", disp->super, super); + nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); if (disp->super & 0x00000010) { nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index d9253d26c31b6..6b85408541b6d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -52,7 +52,7 @@ struct nvkm_output_impl { #ifndef MSG #define MSG(l,f,a...) do { \ struct nvkm_output *_outp = (void *)outp; \ - nv_##l(_outp, "%02x:%04x:%04x: "f, _outp->index, \ + nvkm_##l(&nvkm_disp(_outp)->engine.subdev, "%02x:%04x:%04x: "f, _outp->index, \ _outp->info.hasht, _outp->info.hashm, ##a); \ } while(0) #define DBG(f,a...) MSG(debug, f, ##a) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c index 9f933ac7e8709..39796449de23a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c @@ -44,7 +44,6 @@ nv_rdport(void *obj, int head, u16 port) return nvkm_rd08(device, 0x0c0000 + (head * 0x2000) + port); } - nv_error(obj, "unknown vga port 0x%04x\n", port); return 0x00; } @@ -67,8 +66,7 @@ nv_wrport(void *obj, int head, u16 port, u8 data) if (device->card_type < NV_40) head = 0; /* CR44 selects head */ nvkm_wr08(device, 0x0c0000 + (head * 0x2000) + port, data); - } else - nv_error(obj, "unknown vga port 0x%04x\n", port); + } } u8 @@ -119,7 +117,6 @@ nv_rdvgai(void *obj, int head, u16 port, u8 index) if (port == 0x03c4) return nv_rdvgas(obj, head, index); if (port == 0x03ce) return nv_rdvgag(obj, head, index); if (port == 0x03d4) return nv_rdvgac(obj, head, index); - nv_error(obj, "unknown indexed vga port 0x%04x\n", port); return 0x00; } @@ -129,7 +126,6 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) if (port == 0x03c4) nv_wrvgas(obj, head, index, value); else if (port == 0x03ce) nv_wrvgag(obj, head, index, value); else if (port == 0x03d4) nv_wrvgac(obj, head, index, value); - else nv_error(obj, "unknown indexed vga port 0x%04x\n", port); } bool @@ -192,7 +188,6 @@ nv_rdvgaowner(void *obj) return nv_rdvgac(obj, 0, 0x44); } - nv_error(obj, "rdvgaowner after nv4x\n"); return 0x00; } @@ -213,6 +208,5 @@ nv_wrvgaowner(void *obj, u8 select) nv_wrvgac(obj, 0, 0x2e, owner); nv_wrvgac(obj, 0, 0x2e, owner); } - } else - nv_error(obj, "wrvgaowner after nv4x\n"); + } } -- GitLab From e5c5e4f5d319799fe67dc67531e41ba0b7ed15e6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5432/7006] drm/nouveau/fifo: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 7 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 114 +++++++------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 148 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 46 +++--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 7 +- 6 files changed, 162 insertions(+), 165 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 2b0f497d57a4d..e298aef71918c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -57,10 +57,11 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, int bar, u32 addr, u32 size, u32 pushbuf, u64 engmask, int len, void **ptr) { - struct nvkm_device *device = nv_device(engine); struct nvkm_fifo *fifo = (void *)engine; struct nvkm_fifo_chan *chan; struct nvkm_dmaeng *dmaeng; + struct nvkm_subdev *subdev = &fifo->engine.subdev; + struct nvkm_device *device = subdev->device; unsigned long flags; int ret; @@ -100,7 +101,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, spin_unlock_irqrestore(&fifo->lock, flags); if (chan->chid == fifo->max) { - nv_error(fifo, "no free channels\n"); + nvkm_error(subdev, "no free channels\n"); return -ENOSPC; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index b2da05d2f76d8..5667e695ac516 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -83,7 +83,8 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nv50_fifo *fifo = (void *)parent->engine; struct nv50_fifo_base *base = (void *)parent->parent; struct nv50_fifo_chan *chan = (void *)parent; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; u32 addr, save, engn; bool done; @@ -112,8 +113,8 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, ) >= 0; nvkm_wr32(device, 0x002520, save); if (!done) { - nv_error(fifo, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); + nvkm_error(subdev, "channel %d [%s] unload timeout\n", + chan->base.chid, nvkm_client_name(chan)); if (suspend) return -EBUSY; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 503ea80883452..e438e9fee2066 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -76,7 +76,8 @@ struct gf100_fifo_chan { static void gf100_fifo_runlist_update(struct gf100_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -101,7 +102,7 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) if (wait_event_timeout(fifo->runlist.wait, !(nvkm_rd32(device, 0x00227c) & 0x00100000), msecs_to_jiffies(2000)) == 0) - nv_error(fifo, "runlist update timeout\n"); + nvkm_error(subdev, "runlist update timeout\n"); mutex_unlock(&nv_subdev(fifo)->mutex); } @@ -149,7 +150,8 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct gf100_fifo *fifo = (void *)parent->engine; struct gf100_fifo_base *base = (void *)parent->parent; struct gf100_fifo_chan *chan = (void *)parent; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; u32 addr; @@ -170,8 +172,8 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, if (nvkm_rd32(device, 0x002634) == chan->base.chid) break; ) < 0) { - nv_error(fifo, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); + nvkm_error(subdev, "channel %d [%s] kick timeout\n", + chan->base.chid, nvkm_client_name(chan)); if (suspend) return -EBUSY; } @@ -446,12 +448,13 @@ static void gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, struct gf100_fifo_chan *chan) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; unsigned long flags; - nv_error(fifo, "%s engine fault on channel %d, recovering...\n", - nv_subdev(engine)->name, chid); + nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", + engine->subdev.name, chid); nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); chan->state = KILLED; @@ -524,17 +527,15 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) static void gf100_fifo_intr_sched(struct gf100_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; const struct nvkm_enum *en; - char enunk[6] = ""; en = nvkm_enum_find(gf100_fifo_sched_reason, code); - if (!en) - snprintf(enunk, sizeof(enunk), "UNK%02x", code); - nv_error(fifo, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : ""); switch (code) { case 0x0a: @@ -607,7 +608,8 @@ gf100_fifo_fault_gpcclient[] = { static void gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); @@ -620,16 +622,17 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) struct nvkm_object *engctx = NULL, *object; struct nvkm_engine *engine = NULL; const struct nvkm_enum *er, *eu, *ec; - char erunk[6] = ""; - char euunk[6] = ""; - char ecunk[6] = ""; - char gpcid[3] = ""; + char gpcid[8] = ""; er = nvkm_enum_find(gf100_fifo_fault_reason, reason); - if (!er) - snprintf(erunk, sizeof(erunk), "UNK%02X", reason); - eu = nvkm_enum_find(gf100_fifo_fault_engine, unit); + if (hub) { + ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client); + } else { + ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); + } + if (eu) { switch (eu->data2) { case NVDEV_SUBDEV_BAR: @@ -647,26 +650,15 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) engctx = nvkm_engctx_get(engine, inst); break; } - } else { - snprintf(euunk, sizeof(euunk), "UNK%02x", unit); - } - - if (hub) { - ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client); - } else { - ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client); - snprintf(gpcid, sizeof(gpcid), "%d", gpc); } - if (!ec) - snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); - - nv_error(fifo, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " - "channel 0x%010llx [%s]\n", write ? "write" : "read", - (u64)vahi << 32 | valo, er ? er->name : erunk, - eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", - ec ? ec->name : ecunk, (u64)inst << 12, - nvkm_client_name(engctx)); + nvkm_error(subdev, + "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " + "reason %02x [%s] on channel %d [%010llx %s]\n", + write ? "write" : "read", (u64)vahi << 32 | valo, + unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", + reason, er ? er->name : "", -1, (u64)inst << 12, + nvkm_client_name(engctx)); object = engctx; while (object) { @@ -692,14 +684,16 @@ gf100_fifo_pbdma_intr[] = { static void gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)); u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); u32 data = nvkm_rd32(device, 0x0400c4 + (unit * 0x2000)); u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); - u32 show = stat; + u32 show= stat; + char msg[128]; if (stat & 0x00800000) { if (!gf100_fifo_swmthd(fifo, chid, mthd, data)) @@ -707,14 +701,12 @@ gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) } if (show) { - nv_error(fifo, "PBDMA%d:", unit); - nvkm_bitfield_print(gf100_fifo_pbdma_intr, show); - pr_cont("\n"); - nv_error(fifo, - "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, - nvkm_client_name_for_fifo_chid(&fifo->base, chid), - subc, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), gf100_fifo_pbdma_intr, show); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%s] subc %d " + "mthd %04x data %08x\n", + unit, show, msg, chid, + nvkm_client_name_for_fifo_chid(&fifo->base, chid), + subc, mthd, data); } nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); @@ -724,7 +716,8 @@ gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) static void gf100_fifo_intr_runlist(struct gf100_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x002a00); if (intr & 0x10000000) { @@ -734,7 +727,7 @@ gf100_fifo_intr_runlist(struct gf100_fifo *fifo) } if (intr) { - nv_error(fifo, "RUNLIST 0x%08x\n", intr); + nvkm_error(subdev, "RUNLIST %08x\n", intr); nvkm_wr32(device, 0x002a00, intr); } } @@ -742,7 +735,8 @@ gf100_fifo_intr_runlist(struct gf100_fifo *fifo) static void gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x0025a8 + (engn * 0x04)); u32 inte = nvkm_rd32(device, 0x002628); u32 unkn; @@ -756,7 +750,8 @@ gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) ints &= ~1; } if (ints) { - nv_error(fifo, "ENGINE %d %d %01x", engn, unkn, ints); + nvkm_error(subdev, "ENGINE %d %d %01x", + engn, unkn, ints); nvkm_mask(device, 0x002628, ints, 0); } } @@ -784,7 +779,7 @@ gf100_fifo_intr(struct nvkm_subdev *subdev) if (stat & 0x00000001) { u32 intr = nvkm_rd32(device, 0x00252c); - nv_warn(fifo, "INTR 0x00000001: 0x%08x\n", intr); + nvkm_warn(subdev, "INTR 00000001: %08x\n", intr); nvkm_wr32(device, 0x002100, 0x00000001); stat &= ~0x00000001; } @@ -797,14 +792,14 @@ gf100_fifo_intr(struct nvkm_subdev *subdev) if (stat & 0x00010000) { u32 intr = nvkm_rd32(device, 0x00256c); - nv_warn(fifo, "INTR 0x00010000: 0x%08x\n", intr); + nvkm_warn(subdev, "INTR 00010000: %08x\n", intr); nvkm_wr32(device, 0x002100, 0x00010000); stat &= ~0x00010000; } if (stat & 0x01000000) { u32 intr = nvkm_rd32(device, 0x00258c); - nv_warn(fifo, "INTR 0x01000000: 0x%08x\n", intr); + nvkm_warn(subdev, "INTR 01000000: %08x\n", intr); nvkm_wr32(device, 0x002100, 0x01000000); stat &= ~0x01000000; } @@ -842,7 +837,7 @@ gf100_fifo_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_error(fifo, "INTR 0x%08x\n", stat); + nvkm_error(subdev, "INTR %08x\n", stat); nvkm_mask(device, 0x002140, stat, 0x00000000); nvkm_wr32(device, 0x002100, stat); } @@ -936,7 +931,8 @@ static int gf100_fifo_init(struct nvkm_object *object) { struct gf100_fifo *fifo = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; int ret, i; ret = nvkm_fifo_init(&fifo->base); @@ -947,7 +943,7 @@ gf100_fifo_init(struct nvkm_object *object) nvkm_wr32(device, 0x002204, 0xffffffff); fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204)); - nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr); + nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* assign engines to PBDMAs */ if (fifo->spoon_nr >= 3) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index cc81511298883..258a1deb11056 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -96,7 +96,8 @@ static void gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { struct gk104_fifo_engn *engn = &fifo->engine[engine]; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -121,7 +122,7 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) if (wait_event_timeout(engn->wait, !(nvkm_rd32(device, 0x002284 + (engine * 0x08)) & 0x00100000), msecs_to_jiffies(2000)) == 0) - nv_error(fifo, "runlist %d update timeout\n", engine); + nvkm_error(subdev, "runlist %d update timeout\n", engine); mutex_unlock(&nv_subdev(fifo)->mutex); } @@ -171,15 +172,16 @@ gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) { struct nvkm_object *obj = (void *)chan; struct gk104_fifo *fifo = (void *)obj->engine; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; nvkm_wr32(device, 0x002634, chan->base.chid); if (nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) break; ) < 0) { - nv_error(fifo, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); + nvkm_error(subdev, "channel %d [%s] kick timeout\n", + chan->base.chid, nvkm_client_name(chan)); return -EBUSY; } @@ -234,6 +236,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct gk104_fifo *fifo = (void *)engine; struct gk104_fifo_base *base = (void *)parent; struct gk104_fifo_chan *chan; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; u64 usermem, ioffset, ilength; int ret, i; @@ -256,7 +259,8 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } if (i == FIFO_ENGINE_NR) { - nv_error(fifo, "unsupported engines 0x%08x\n", args->v0.engine); + nvkm_error(subdev, "unsupported engines %08x\n", + args->v0.engine); return -ENODEV; } @@ -483,12 +487,13 @@ static void gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, struct gk104_fifo_chan *chan) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; unsigned long flags; - nv_error(fifo, "%s engine fault on channel %d, recovering...\n", - nv_subdev(engine)->name, chid); + nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", + nv_subdev(engine)->name, chid); nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); chan->state = KILLED; @@ -539,17 +544,14 @@ gk104_fifo_bind_reason[] = { static void gk104_fifo_intr_bind(struct gk104_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x00252c); u32 code = intr & 0x000000ff; - const struct nvkm_enum *en; - char enunk[6] = ""; + const struct nvkm_enum *en = + nvkm_enum_find(gk104_fifo_bind_reason, code); - en = nvkm_enum_find(gk104_fifo_bind_reason, code); - if (!en) - snprintf(enunk, sizeof(enunk), "UNK%02x", code); - - nv_error(fifo, "BIND_ERROR [ %s ]\n", en ? en->name : enunk); + nvkm_error(subdev, "BIND_ERROR %02x [%s]\n", code, en ? en->name : ""); } static const struct nvkm_enum @@ -590,17 +592,14 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) static void gk104_fifo_intr_sched(struct gk104_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x00254c); u32 code = intr & 0x000000ff; - const struct nvkm_enum *en; - char enunk[6] = ""; - - en = nvkm_enum_find(gk104_fifo_sched_reason, code); - if (!en) - snprintf(enunk, sizeof(enunk), "UNK%02x", code); + const struct nvkm_enum *en = + nvkm_enum_find(gk104_fifo_sched_reason, code); - nv_error(fifo, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk); + nvkm_error(subdev, "SCHED_ERROR %02x [%s]\n", code, en ? en->name : ""); switch (code) { case 0x0a: @@ -614,18 +613,20 @@ gk104_fifo_intr_sched(struct gk104_fifo *fifo) static void gk104_fifo_intr_chsw(struct gk104_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x00256c); - nv_error(fifo, "CHSW_ERROR 0x%08x\n", stat); + nvkm_error(subdev, "CHSW_ERROR %08x\n", stat); nvkm_wr32(device, 0x00256c, stat); } static void gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x00259c); - nv_error(fifo, "DROPPED_MMU_FAULT 0x%08x\n", stat); + nvkm_error(subdev, "DROPPED_MMU_FAULT %08x\n", stat); } static const struct nvkm_enum @@ -736,7 +737,8 @@ gk104_fifo_fault_gpcclient[] = { static void gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 inst = nvkm_rd32(device, 0x002800 + (unit * 0x10)); u32 valo = nvkm_rd32(device, 0x002804 + (unit * 0x10)); u32 vahi = nvkm_rd32(device, 0x002808 + (unit * 0x10)); @@ -749,16 +751,17 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) struct nvkm_object *engctx = NULL, *object; struct nvkm_engine *engine = NULL; const struct nvkm_enum *er, *eu, *ec; - char erunk[6] = ""; - char euunk[6] = ""; - char ecunk[6] = ""; - char gpcid[3] = ""; + char gpcid[8] = ""; er = nvkm_enum_find(gk104_fifo_fault_reason, reason); - if (!er) - snprintf(erunk, sizeof(erunk), "UNK%02X", reason); - eu = nvkm_enum_find(gk104_fifo_fault_engine, unit); + if (hub) { + ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client); + } else { + ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client); + snprintf(gpcid, sizeof(gpcid), "GPC%d/", gpc); + } + if (eu) { switch (eu->data2) { case NVDEV_SUBDEV_BAR: @@ -776,26 +779,15 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) engctx = nvkm_engctx_get(engine, inst); break; } - } else { - snprintf(euunk, sizeof(euunk), "UNK%02x", unit); - } - - if (hub) { - ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client); - } else { - ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client); - snprintf(gpcid, sizeof(gpcid), "%d", gpc); } - if (!ec) - snprintf(ecunk, sizeof(ecunk), "UNK%02x", client); - - nv_error(fifo, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on " - "channel 0x%010llx [%s]\n", write ? "write" : "read", - (u64)vahi << 32 | valo, er ? er->name : erunk, - eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/", - ec ? ec->name : ecunk, (u64)inst << 12, - nvkm_client_name(engctx)); + nvkm_error(subdev, + "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " + "reason %02x [%s] on channel %d [%010llx %s]\n", + write ? "write" : "read", (u64)vahi << 32 | valo, + unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", + reason, er ? er->name : "", -1, (u64)inst << 12, + nvkm_client_name(engctx)); object = engctx; while (object) { @@ -848,7 +840,8 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { static void gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, 0x04010c + (unit * 0x2000)); u32 stat = nvkm_rd32(device, 0x040108 + (unit * 0x2000)) & mask; u32 addr = nvkm_rd32(device, 0x0400c0 + (unit * 0x2000)); @@ -857,6 +850,7 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; + char msg[128]; if (stat & 0x00800000) { if (!gk104_fifo_swmthd(fifo, chid, mthd, data)) @@ -865,14 +859,12 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) } if (show) { - nv_error(fifo, "PBDMA%d:", unit); - nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show); - pr_cont("\n"); - nv_error(fifo, - "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", - unit, chid, - nvkm_client_name_for_fifo_chid(&fifo->base, chid), - subc, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_0, show); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%s] subc %d " + "mthd %04x data %08x\n", + unit, show, msg, chid, + nvkm_client_name_for_fifo_chid(&fifo->base, chid), + subc, mthd, data); } nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); @@ -890,18 +882,19 @@ static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = { static void gk104_fifo_intr_pbdma_1(struct gk104_fifo *fifo, int unit) { - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, 0x04014c + (unit * 0x2000)); u32 stat = nvkm_rd32(device, 0x040148 + (unit * 0x2000)) & mask; u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0xfff; + char msg[128]; if (stat) { - nv_error(fifo, "PBDMA%d:", unit); - nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat); - pr_cont("\n"); - nv_error(fifo, "PBDMA%d: ch %d %08x %08x\n", unit, chid, - nvkm_rd32(device, 0x040150 + (unit * 0x2000)), - nvkm_rd32(device, 0x040154 + (unit * 0x2000))); + nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_1, stat); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d %08x %08x\n", + unit, stat, msg, chid, + nvkm_rd32(device, 0x040150 + (unit * 0x2000)), + nvkm_rd32(device, 0x040154 + (unit * 0x2000))); } nvkm_wr32(device, 0x040148 + (unit * 0x2000), stat); @@ -941,7 +934,7 @@ gk104_fifo_intr(struct nvkm_subdev *subdev) } if (stat & 0x00000010) { - nv_error(fifo, "PIO_ERROR\n"); + nvkm_error(subdev, "PIO_ERROR\n"); nvkm_wr32(device, 0x002100, 0x00000010); stat &= ~0x00000010; } @@ -959,13 +952,13 @@ gk104_fifo_intr(struct nvkm_subdev *subdev) } if (stat & 0x00800000) { - nv_error(fifo, "FB_FLUSH_TIMEOUT\n"); + nvkm_error(subdev, "FB_FLUSH_TIMEOUT\n"); nvkm_wr32(device, 0x002100, 0x00800000); stat &= ~0x00800000; } if (stat & 0x01000000) { - nv_error(fifo, "LB_ERROR\n"); + nvkm_error(subdev, "LB_ERROR\n"); nvkm_wr32(device, 0x002100, 0x01000000); stat &= ~0x01000000; } @@ -1011,7 +1004,7 @@ gk104_fifo_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_error(fifo, "INTR 0x%08x\n", stat); + nvkm_error(subdev, "INTR %08x\n", stat); nvkm_mask(device, 0x002140, stat, 0x00000000); nvkm_wr32(device, 0x002100, stat); } @@ -1060,7 +1053,8 @@ int gk104_fifo_init(struct nvkm_object *object) { struct gk104_fifo *fifo = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; int ret, i; ret = nvkm_fifo_init(&fifo->base); @@ -1070,7 +1064,7 @@ gk104_fifo_init(struct nvkm_object *object) /* enable all available PBDMA units */ nvkm_wr32(device, 0x000204, 0xffffffff); fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x000204)); - nv_debug(fifo, "%d PBDMA unit(s)\n", fifo->spoon_nr); + nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); /* PBDMA[n] */ for (i = 0; i < fifo->spoon_nr; i++) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 214bf122b19c6..61de6fded74bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -412,9 +412,10 @@ out: } static void -nv04_fifo_cache_error(struct nvkm_device *device, - struct nv04_fifo *fifo, u32 chid, u32 get) +nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) { + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mthd, data; int ptr; @@ -436,10 +437,10 @@ nv04_fifo_cache_error(struct nvkm_device *device, if (!nv04_fifo_swmthd(fifo, chid, mthd, data)) { const char *client_name = nvkm_client_name_for_fifo_chid(&fifo->base, chid); - nv_error(fifo, - "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n", - chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc, - data); + nvkm_error(subdev, "CACHE_ERROR - " + "ch %d [%s] subc %d mthd %04x data %08x\n", + chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc, + data); } nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0); @@ -458,14 +459,15 @@ nv04_fifo_cache_error(struct nvkm_device *device, } static void -nv04_fifo_dma_pusher(struct nvkm_device *device, - struct nv04_fifo *fifo, u32 chid) +nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) { - const char *client_name; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 dma_get = nvkm_rd32(device, 0x003244); u32 dma_put = nvkm_rd32(device, 0x003240); u32 push = nvkm_rd32(device, 0x003220); u32 state = nvkm_rd32(device, 0x003228); + const char *client_name; client_name = nvkm_client_name_for_fifo_chid(&fifo->base, chid); @@ -475,10 +477,12 @@ nv04_fifo_dma_pusher(struct nvkm_device *device, u32 ib_get = nvkm_rd32(device, 0x003334); u32 ib_put = nvkm_rd32(device, 0x003330); - nv_error(fifo, - "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", - chid, client_name, ho_get, dma_get, ho_put, dma_put, - ib_get, ib_put, state, nv_dma_state_err(state), push); + nvkm_error(subdev, "DMA_PUSHER - " + "ch %d [%s] get %02x%08x put %02x%08x ib_get %08x " + "ib_put %08x state %08x (err: %s) push %08x\n", + chid, client_name, ho_get, dma_get, ho_put, dma_put, + ib_get, ib_put, state, nv_dma_state_err(state), + push); /* METHOD_COUNT, in DMA_STATE on earlier chipsets */ nvkm_wr32(device, 0x003364, 0x00000000); @@ -489,10 +493,10 @@ nv04_fifo_dma_pusher(struct nvkm_device *device, if (ib_get != ib_put) nvkm_wr32(device, 0x003334, ib_put); } else { - nv_error(fifo, - "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n", - chid, client_name, dma_get, dma_put, state, - nv_dma_state_err(state), push); + nvkm_error(subdev, "DMA_PUSHER - ch %d [%s] get %08x put %08x " + "state %08x (err: %s) push %08x\n", + chid, client_name, dma_get, dma_put, state, + nv_dma_state_err(state), push); if (dma_get != dma_put) nvkm_wr32(device, 0x003244, dma_put); @@ -506,7 +510,7 @@ nv04_fifo_dma_pusher(struct nvkm_device *device, void nv04_fifo_intr(struct nvkm_subdev *subdev) { - struct nvkm_device *device = nv_device(subdev); + struct nvkm_device *device = subdev->device; struct nv04_fifo *fifo = (void *)subdev; u32 mask = nvkm_rd32(device, NV03_PFIFO_INTR_EN_0); u32 stat = nvkm_rd32(device, NV03_PFIFO_INTR_0) & mask; @@ -519,12 +523,12 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET); if (stat & NV_PFIFO_INTR_CACHE_ERROR) { - nv04_fifo_cache_error(device, fifo, chid, get); + nv04_fifo_cache_error(fifo, chid, get); stat &= ~NV_PFIFO_INTR_CACHE_ERROR; } if (stat & NV_PFIFO_INTR_DMA_PUSHER) { - nv04_fifo_dma_pusher(device, fifo, chid); + nv04_fifo_dma_pusher(fifo, chid); stat &= ~NV_PFIFO_INTR_DMA_PUSHER; } @@ -553,7 +557,7 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_warn(fifo, "unknown intr 0x%08x\n", stat); + nvkm_warn(subdev, "intr %08x\n", stat); nvkm_mask(device, NV03_PFIFO_INTR_EN_0, stat, 0x00000000); nvkm_wr32(device, NV03_PFIFO_INTR_0, stat); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index e0188a674974a..41509256bb2e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -106,7 +106,8 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nv50_fifo *fifo = (void *)parent->engine; struct nv50_fifo_base *base = (void *)parent->parent; struct nv50_fifo_chan *chan = (void *)parent; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; u32 addr, me; int ret = 0; @@ -139,8 +140,8 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) break; ) < 0) { - nv_error(fifo, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); + nvkm_error(subdev, "channel %d [%s] unload timeout\n", + chan->base.chid, nvkm_client_name(chan)); if (suspend) ret = -EBUSY; } -- GitLab From 109c2f2f1c42c16a4b265e796dee6ae4ada78417 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5433/7006] drm/nouveau/gr: switch to subdev printk macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/core/enum.h | 1 - drivers/gpu/drm/nouveau/nvkm/core/enum.c | 16 - .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 233 ++++++++------- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 7 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 27 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 29 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 20 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 26 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 277 ++++++++++-------- 10 files changed, 339 insertions(+), 302 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h index 573b1eef4b396..a5d4c65bbbc20 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h @@ -17,6 +17,5 @@ struct nvkm_bitfield { const char *name; }; -void nvkm_bitfield_print(const struct nvkm_bitfield *, u32 value); void nvkm_snprintbf(char *, int, const struct nvkm_bitfield *, u32 value); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/enum.c b/drivers/gpu/drm/nouveau/nvkm/core/enum.c index 2cfaec4061940..64bdbd04a73ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/enum.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/enum.c @@ -49,22 +49,6 @@ nvkm_enum_print(const struct nvkm_enum *en, u32 value) return en; } -void -nvkm_bitfield_print(const struct nvkm_bitfield *bf, u32 value) -{ - while (bf->name) { - if (value & bf->mask) { - pr_cont(" %s", bf->name); - value &= ~bf->mask; - } - - bf++; - } - - if (value) - pr_cont(" (unknown bits 0x%08x)", value); -} - void nvkm_snprintbf(char *data, int size, const struct nvkm_bitfield *bf, u32 value) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index ccce293191a4a..7854baff33747 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1271,7 +1271,8 @@ int gf100_grctx_generate(struct gf100_gr *gr) { struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *chan; struct gf100_grctx info; @@ -1283,7 +1284,7 @@ gf100_grctx_generate(struct gf100_gr *gr) ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x80000 + gr->size, 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan); if (ret) { - nv_error(gr, "failed to allocate channel memory, %d\n", ret); + nvkm_error(subdev, "failed to allocate chan memory, %d\n", ret); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 4bfec3aa0deef..a27daf986ed76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -673,7 +673,8 @@ gf100_gr_zbc_init(struct gf100_gr *gr) int gf100_gr_wait_idle(struct gf100_gr *gr) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; unsigned long end_jiffies = jiffies + msecs_to_jiffies(2000); bool gr_enabled, ctxsw_active, gr_busy; @@ -692,8 +693,9 @@ gf100_gr_wait_idle(struct gf100_gr *gr) return 0; } while (time_before(jiffies, end_jiffies)); - nv_error(gr, "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", - gr_enabled, ctxsw_active, gr_busy); + nvkm_error(subdev, + "wait for idle timeout (en: %d, ctxsw: %d, busy: %d)\n", + gr_enabled, ctxsw_active, gr_busy); return -EAGAIN; } @@ -790,55 +792,50 @@ gf100_gr_units(struct nvkm_gr *obj) return cfg; } -static const struct nvkm_enum gk104_sked_error[] = { - { 7, "CONSTANT_BUFFER_SIZE" }, - { 9, "LOCAL_MEMORY_SIZE_POS" }, - { 10, "LOCAL_MEMORY_SIZE_NEG" }, - { 11, "WARP_CSTACK_SIZE" }, - { 12, "TOTAL_TEMP_SIZE" }, - { 13, "REGISTER_COUNT" }, - { 18, "TOTAL_THREADS" }, - { 20, "PROGRAM_OFFSET" }, - { 21, "SHARED_MEMORY_SIZE" }, - { 25, "SHARED_CONFIG_TOO_SMALL" }, - { 26, "TOTAL_REGISTER_COUNT" }, +static const struct nvkm_bitfield gk104_sked_error[] = { + { 0x00000080, "CONSTANT_BUFFER_SIZE" }, + { 0x00000200, "LOCAL_MEMORY_SIZE_POS" }, + { 0x00000400, "LOCAL_MEMORY_SIZE_NEG" }, + { 0x00000800, "WARP_CSTACK_SIZE" }, + { 0x00001000, "TOTAL_TEMP_SIZE" }, + { 0x00002000, "REGISTER_COUNT" }, + { 0x00040000, "TOTAL_THREADS" }, + { 0x00100000, "PROGRAM_OFFSET" }, + { 0x00200000, "SHARED_MEMORY_SIZE" }, + { 0x02000000, "SHARED_CONFIG_TOO_SMALL" }, + { 0x04000000, "TOTAL_REGISTER_COUNT" }, {} }; -static const struct nvkm_enum gf100_gpc_rop_error[] = { - { 1, "RT_PITCH_OVERRUN" }, - { 4, "RT_WIDTH_OVERRUN" }, - { 5, "RT_HEIGHT_OVERRUN" }, - { 7, "ZETA_STORAGE_TYPE_MISMATCH" }, - { 8, "RT_STORAGE_TYPE_MISMATCH" }, - { 10, "RT_LINEAR_MISMATCH" }, +static const struct nvkm_bitfield gf100_gpc_rop_error[] = { + { 0x00000002, "RT_PITCH_OVERRUN" }, + { 0x00000010, "RT_WIDTH_OVERRUN" }, + { 0x00000020, "RT_HEIGHT_OVERRUN" }, + { 0x00000080, "ZETA_STORAGE_TYPE_MISMATCH" }, + { 0x00000100, "RT_STORAGE_TYPE_MISMATCH" }, + { 0x00000400, "RT_LINEAR_MISMATCH" }, {} }; static void gf100_gr_trap_gpc_rop(struct gf100_gr *gr, int gpc) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + char error[128]; u32 trap[4]; - int i; - trap[0] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0420)); + trap[0] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0420)) & 0x3fffffff; trap[1] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0434)); trap[2] = nvkm_rd32(device, GPC_UNIT(gpc, 0x0438)); trap[3] = nvkm_rd32(device, GPC_UNIT(gpc, 0x043c)); - nv_error(gr, "GPC%d/PROP trap:", gpc); - for (i = 0; i <= 29; ++i) { - if (!(trap[0] & (1 << i))) - continue; - pr_cont(" "); - nvkm_enum_print(gf100_gpc_rop_error, i); - } - pr_cont("\n"); + nvkm_snprintbf(error, sizeof(error), gf100_gpc_rop_error, trap[0]); - nv_error(gr, "x = %u, y = %u, format = %x, storage type = %x\n", - trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f, - trap[3] & 0xff); + nvkm_error(subdev, "GPC%d/PROP trap: %08x [%s] x = %u, y = %u, " + "format = %x, storage type = %x\n", + gpc, trap[0], error, trap[1] & 0xffff, trap[1] >> 16, + (trap[2] >> 8) & 0x3f, trap[3] & 0xff); nvkm_wr32(device, GPC_UNIT(gpc, 0x0420), 0xc0000000); } @@ -864,17 +861,19 @@ static const struct nvkm_bitfield gf100_mp_global_error[] = { static void gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 werr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x648)); u32 gerr = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x650)); + const struct nvkm_enum *warp; + char glob[128]; - nv_error(gr, "GPC%i/TPC%i/MP trap:", gpc, tpc); - nvkm_bitfield_print(gf100_mp_global_error, gerr); - if (werr) { - pr_cont(" "); - nvkm_enum_print(gf100_mp_warp_error, werr & 0xffff); - } - pr_cont("\n"); + nvkm_snprintbf(glob, sizeof(glob), gf100_mp_global_error, gerr); + warp = nvkm_enum_find(gf100_mp_warp_error, werr & 0xffff); + + nvkm_error(subdev, "GPC%i/TPC%i/MP trap: " + "global %08x [%s] warp %04x [%s]\n", + gpc, tpc, gerr, glob, werr, warp ? warp->name : ""); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x648), 0x00000000); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x650), gerr); @@ -883,12 +882,13 @@ gf100_gr_trap_mp(struct gf100_gr *gr, int gpc, int tpc) static void gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0508)); if (stat & 0x00000001) { u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0224)); - nv_error(gr, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap); + nvkm_error(subdev, "GPC%d/TPC%d/TEX: %08x\n", gpc, tpc, trap); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000); stat &= ~0x00000001; } @@ -900,27 +900,28 @@ gf100_gr_trap_tpc(struct gf100_gr *gr, int gpc, int tpc) if (stat & 0x00000004) { u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x0084)); - nv_error(gr, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap); + nvkm_error(subdev, "GPC%d/TPC%d/POLY: %08x\n", gpc, tpc, trap); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { u32 trap = nvkm_rd32(device, TPC_UNIT(gpc, tpc, 0x048c)); - nv_error(gr, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap); + nvkm_error(subdev, "GPC%d/TPC%d/L1C: %08x\n", gpc, tpc, trap); nvkm_wr32(device, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000); stat &= ~0x00000008; } if (stat) { - nv_error(gr, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat); + nvkm_error(subdev, "GPC%d/TPC%d/%08x: unknown\n", gpc, tpc, stat); } } static void gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, GPC_UNIT(gpc, 0x2c90)); int tpc; @@ -931,21 +932,21 @@ gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) if (stat & 0x00000002) { u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0900)); - nv_error(gr, "GPC%d/ZCULL: 0x%08x\n", gpc, trap); + nvkm_error(subdev, "GPC%d/ZCULL: %08x\n", gpc, trap); nvkm_wr32(device, GPC_UNIT(gpc, 0x0900), 0xc0000000); stat &= ~0x00000002; } if (stat & 0x00000004) { u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x1028)); - nv_error(gr, "GPC%d/CCACHE: 0x%08x\n", gpc, trap); + nvkm_error(subdev, "GPC%d/CCACHE: %08x\n", gpc, trap); nvkm_wr32(device, GPC_UNIT(gpc, 0x1028), 0xc0000000); stat &= ~0x00000004; } if (stat & 0x00000008) { u32 trap = nvkm_rd32(device, GPC_UNIT(gpc, 0x0824)); - nv_error(gr, "GPC%d/ESETUP: 0x%08x\n", gpc, trap); + nvkm_error(subdev, "GPC%d/ESETUP: %08x\n", gpc, trap); nvkm_wr32(device, GPC_UNIT(gpc, 0x0824), 0xc0000000); stat &= ~0x00000009; } @@ -960,20 +961,21 @@ gf100_gr_trap_gpc(struct gf100_gr *gr, int gpc) } if (stat) { - nv_error(gr, "GPC%d/0x%08x: unknown\n", gpc, stat); + nvkm_error(subdev, "GPC%d/%08x: unknown\n", gpc, stat); } } static void gf100_gr_trap_intr(struct gf100_gr *gr) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 trap = nvkm_rd32(device, 0x400108); - int rop, gpc, i; + int rop, gpc; if (trap & 0x00000001) { u32 stat = nvkm_rd32(device, 0x404000); - nv_error(gr, "DISPATCH 0x%08x\n", stat); + nvkm_error(subdev, "DISPATCH %08x\n", stat); nvkm_wr32(device, 0x404000, 0xc0000000); nvkm_wr32(device, 0x400108, 0x00000001); trap &= ~0x00000001; @@ -981,7 +983,7 @@ gf100_gr_trap_intr(struct gf100_gr *gr) if (trap & 0x00000002) { u32 stat = nvkm_rd32(device, 0x404600); - nv_error(gr, "M2MF 0x%08x\n", stat); + nvkm_error(subdev, "M2MF %08x\n", stat); nvkm_wr32(device, 0x404600, 0xc0000000); nvkm_wr32(device, 0x400108, 0x00000002); trap &= ~0x00000002; @@ -989,7 +991,7 @@ gf100_gr_trap_intr(struct gf100_gr *gr) if (trap & 0x00000008) { u32 stat = nvkm_rd32(device, 0x408030); - nv_error(gr, "CCACHE 0x%08x\n", stat); + nvkm_error(subdev, "CCACHE %08x\n", stat); nvkm_wr32(device, 0x408030, 0xc0000000); nvkm_wr32(device, 0x400108, 0x00000008); trap &= ~0x00000008; @@ -997,7 +999,7 @@ gf100_gr_trap_intr(struct gf100_gr *gr) if (trap & 0x00000010) { u32 stat = nvkm_rd32(device, 0x405840); - nv_error(gr, "SHADER 0x%08x\n", stat); + nvkm_error(subdev, "SHADER %08x\n", stat); nvkm_wr32(device, 0x405840, 0xc0000000); nvkm_wr32(device, 0x400108, 0x00000010); trap &= ~0x00000010; @@ -1005,7 +1007,7 @@ gf100_gr_trap_intr(struct gf100_gr *gr) if (trap & 0x00000040) { u32 stat = nvkm_rd32(device, 0x40601c); - nv_error(gr, "UNK6 0x%08x\n", stat); + nvkm_error(subdev, "UNK6 %08x\n", stat); nvkm_wr32(device, 0x40601c, 0xc0000000); nvkm_wr32(device, 0x400108, 0x00000040); trap &= ~0x00000040; @@ -1013,25 +1015,20 @@ gf100_gr_trap_intr(struct gf100_gr *gr) if (trap & 0x00000080) { u32 stat = nvkm_rd32(device, 0x404490); - nv_error(gr, "MACRO 0x%08x\n", stat); + nvkm_error(subdev, "MACRO %08x\n", stat); nvkm_wr32(device, 0x404490, 0xc0000000); nvkm_wr32(device, 0x400108, 0x00000080); trap &= ~0x00000080; } if (trap & 0x00000100) { - u32 stat = nvkm_rd32(device, 0x407020); + u32 stat = nvkm_rd32(device, 0x407020) & 0x3fffffff; + char sked[128]; - nv_error(gr, "SKED:"); - for (i = 0; i <= 29; ++i) { - if (!(stat & (1 << i))) - continue; - pr_cont(" "); - nvkm_enum_print(gk104_sked_error, i); - } - pr_cont("\n"); + nvkm_snprintbf(sked, sizeof(sked), gk104_sked_error, stat); + nvkm_error(subdev, "SKED: %08x [%s]\n", stat, sked); - if (stat & 0x3fffffff) + if (stat) nvkm_wr32(device, 0x407020, 0x40000000); nvkm_wr32(device, 0x400108, 0x00000100); trap &= ~0x00000100; @@ -1055,7 +1052,7 @@ gf100_gr_trap_intr(struct gf100_gr *gr) for (rop = 0; rop < gr->rop_nr; rop++) { u32 statz = nvkm_rd32(device, ROP_UNIT(rop, 0x070)); u32 statc = nvkm_rd32(device, ROP_UNIT(rop, 0x144)); - nv_error(gr, "ROP%d 0x%08x 0x%08x\n", + nvkm_error(subdev, "ROP%d %08x %08x\n", rop, statz, statc); nvkm_wr32(device, ROP_UNIT(rop, 0x070), 0xc0000000); nvkm_wr32(device, ROP_UNIT(rop, 0x144), 0xc0000000); @@ -1065,7 +1062,7 @@ gf100_gr_trap_intr(struct gf100_gr *gr) } if (trap) { - nv_error(gr, "TRAP UNHANDLED 0x%08x\n", trap); + nvkm_error(subdev, "TRAP UNHANDLED %08x\n", trap); nvkm_wr32(device, 0x400108, trap); } } @@ -1073,15 +1070,20 @@ gf100_gr_trap_intr(struct gf100_gr *gr) static void gf100_gr_ctxctl_debug_unit(struct gf100_gr *gr, u32 base) { - struct nvkm_device *device = gr->base.engine.subdev.device; - nv_error(gr, "%06x - done 0x%08x\n", base, - nvkm_rd32(device, base + 0x400)); - nv_error(gr, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nvkm_rd32(device, base + 0x800), nvkm_rd32(device, base + 0x804), - nvkm_rd32(device, base + 0x808), nvkm_rd32(device, base + 0x80c)); - nv_error(gr, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base, - nvkm_rd32(device, base + 0x810), nvkm_rd32(device, base + 0x814), - nvkm_rd32(device, base + 0x818), nvkm_rd32(device, base + 0x81c)); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + nvkm_error(subdev, "%06x - done %08x\n", base, + nvkm_rd32(device, base + 0x400)); + nvkm_error(subdev, "%06x - stat %08x %08x %08x %08x\n", base, + nvkm_rd32(device, base + 0x800), + nvkm_rd32(device, base + 0x804), + nvkm_rd32(device, base + 0x808), + nvkm_rd32(device, base + 0x80c)); + nvkm_error(subdev, "%06x - stat %08x %08x %08x %08x\n", base, + nvkm_rd32(device, base + 0x810), + nvkm_rd32(device, base + 0x814), + nvkm_rd32(device, base + 0x818), + nvkm_rd32(device, base + 0x81c)); } void @@ -1099,7 +1101,8 @@ gf100_gr_ctxctl_debug(struct gf100_gr *gr) static void gf100_gr_ctxctl_isr(struct gf100_gr *gr) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x409c18); if (stat & 0x00000001) { @@ -1111,26 +1114,26 @@ gf100_gr_ctxctl_isr(struct gf100_gr *gr) u32 mthd = (addr & 0x00003ffc); u32 data = nvkm_rd32(device, 0x409810); - nv_error(gr, "FECS MTHD subc %d class 0x%04x " - "mthd 0x%04x data 0x%08x\n", - subc, class, mthd, data); + nvkm_error(subdev, "FECS MTHD subc %d class %04x " + "mthd %04x data %08x\n", + subc, class, mthd, data); nvkm_wr32(device, 0x409c20, 0x00000001); stat &= ~0x00000001; } else { - nv_error(gr, "FECS ucode error %d\n", code); + nvkm_error(subdev, "FECS ucode error %d\n", code); } } if (stat & 0x00080000) { - nv_error(gr, "FECS watchdog timeout\n"); + nvkm_error(subdev, "FECS watchdog timeout\n"); gf100_gr_ctxctl_debug(gr); nvkm_wr32(device, 0x409c20, 0x00080000); stat &= ~0x00080000; } if (stat) { - nv_error(gr, "FECS 0x%08x\n", stat); + nvkm_error(subdev, "FECS %08x\n", stat); gf100_gr_ctxctl_debug(gr); nvkm_wr32(device, 0x409c20, stat); } @@ -1175,10 +1178,10 @@ gf100_gr_intr(struct nvkm_subdev *subdev) if (stat & 0x00000010) { handle = nvkm_handle_get_class(engctx, class); if (!handle || nv_call(handle->object, mthd, data)) { - nv_error(gr, - "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), - subc, class, mthd, data); + nvkm_error(subdev, "ILLEGAL_MTHD ch %d [%010llx %s] " + "subc %d class %04x mthd %04x data %08x\n", + chid, inst << 12, nvkm_client_name(engctx), + subc, class, mthd, data); } nvkm_handle_put(handle); nvkm_wr32(device, 0x400100, 0x00000010); @@ -1186,27 +1189,29 @@ gf100_gr_intr(struct nvkm_subdev *subdev) } if (stat & 0x00000020) { - nv_error(gr, - "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, - class, mthd, data); + nvkm_error(subdev, "ILLEGAL_CLASS ch %d [%010llx %s] " + "subc %d class %04x mthd %04x data %08x\n", + chid, inst << 12, nvkm_client_name(engctx), subc, + class, mthd, data); nvkm_wr32(device, 0x400100, 0x00000020); stat &= ~0x00000020; } if (stat & 0x00100000) { - nv_error(gr, "DATA_ERROR ["); - nvkm_enum_print(nv50_data_error_names, code); - pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, - class, mthd, data); + const struct nvkm_enum *en = + nvkm_enum_find(nv50_data_error_names, code); + nvkm_error(subdev, "DATA_ERROR %08x [%s] ch %d [%010llx %s] " + "subc %d class %04x mthd %04x data %08x\n", + code, en ? en->name : "", chid, inst << 12, + nvkm_client_name(engctx), subc, class, mthd, data); nvkm_wr32(device, 0x400100, 0x00100000); stat &= ~0x00100000; } if (stat & 0x00200000) { - nv_error(gr, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12, - nvkm_client_name(engctx)); + nvkm_error(subdev, "TRAP ch %d [%010llx %s]\n", + chid, inst << 12, + nvkm_client_name(engctx)); gf100_gr_trap_intr(gr); nvkm_wr32(device, 0x400100, 0x00200000); stat &= ~0x00200000; @@ -1219,7 +1224,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) } if (stat) { - nv_error(gr, "unknown stat 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_wr32(device, 0x400100, stat); } @@ -1295,7 +1300,8 @@ gf100_gr_init_csdata(struct gf100_gr *gr, int gf100_gr_init_ctxctl(struct gf100_gr *gr) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass; struct gf100_grctx_oclass *cclass = (void *)nv_engine(gr)->cclass; int i; @@ -1390,7 +1396,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) if (gr->data == NULL) { int ret = gf100_grctx_generate(gr); if (ret) { - nv_error(gr, "failed to construct context\n"); + nvkm_error(subdev, "failed to construct context\n"); return ret; } } @@ -1448,7 +1454,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) if (gr->data == NULL) { int ret = gf100_grctx_generate(gr); if (ret) { - nv_error(gr, "failed to construct context\n"); + nvkm_error(subdev, "failed to construct context\n"); return ret; } } @@ -1580,7 +1586,8 @@ int gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, struct gf100_gr_fuc *fuc) { - struct nvkm_device *device = nv_device(gr); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; const struct firmware *fw; char f[64]; char cname[16]; @@ -1599,7 +1606,7 @@ gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); ret = request_firmware(&fw, f, nv_device_base(device)); if (ret) { - nv_error(gr, "failed to load %s\n", fwname); + nvkm_error(subdev, "failed to load %s\n", fwname); return ret; } @@ -1633,7 +1640,7 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct gf100_gr_oclass *oclass = (void *)bclass; - struct nvkm_device *device = nv_device(parent); + struct nvkm_device *device = (void *)parent; struct gf100_gr *gr; bool use_ext_fw, enable; int ret, i, j; @@ -1653,7 +1660,7 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, gr->base.units = gf100_gr_units; if (use_ext_fw) { - nv_info(gr, "using external firmware\n"); + nvkm_info(&gr->base.engine.subdev, "using external firmware\n"); if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) || gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) || gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) || diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index ed944aa6b81b1..6cb8ff3fb68a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -220,13 +220,14 @@ gk20a_gr_dtor(struct nvkm_object *object) static int gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; if (nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x40910c) & 0x00000006)) break; ) < 0) { - nv_error(gr, "FECS mem scrubbing timeout\n"); + nvkm_error(subdev, "FECS mem scrubbing timeout\n"); return -ETIMEDOUT; } @@ -234,7 +235,7 @@ gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) if (!(nvkm_rd32(device, 0x41a10c) & 0x00000006)) break; ) < 0) { - nv_error(gr, "GPCCS mem scrubbing timeout\n"); + nvkm_error(subdev, "GPCCS mem scrubbing timeout\n"); return -ETIMEDOUT; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 33f3b8219213a..a445712973f6a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1200,7 +1200,8 @@ bool nv04_gr_idle(void *obj) { struct nvkm_gr *gr = nvkm_gr(obj); - struct nvkm_device *device = gr->engine.subdev.device; + struct nvkm_subdev *subdev = &gr->engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask = 0xffffffff; if (nv_device(obj)->card_type == NV_40) @@ -1210,8 +1211,8 @@ nv04_gr_idle(void *obj) if (!(nvkm_rd32(device, NV04_PGRAPH_STATUS) & mask)) break; ) < 0) { - nv_error(gr, "idle timed out with status 0x%08x\n", - nvkm_rd32(device, NV04_PGRAPH_STATUS)); + nvkm_error(subdev, "idle timed out with status %08x\n", + nvkm_rd32(device, NV04_PGRAPH_STATUS)); return false; } @@ -1276,6 +1277,7 @@ nv04_gr_intr(struct nvkm_subdev *subdev) u32 class = nvkm_rd32(device, 0x400180 + subc * 4) & 0xff; u32 inst = (nvkm_rd32(device, 0x40016c) & 0xffff) << 4; u32 show = stat; + char msg[128], src[128], sta[128]; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); @@ -1303,17 +1305,14 @@ nv04_gr_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(gr, "%s", ""); - nvkm_bitfield_print(nv04_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv04_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(gr, - "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, nvkm_client_name(chan), subc, class, mthd, - data); + nvkm_snprintbf(msg, sizeof(msg), nv04_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv04_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + nvkm_client_name(chan), subc, class, mthd, data); } nvkm_namedb_put(handle); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 6b3ee956ced45..94f7dc794d2f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -690,6 +690,7 @@ static void nv10_gr_create_pipe(struct nv10_gr_chan *chan) { struct nv10_gr *gr = nv10_gr(chan); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct pipe_state *pipe_state = &chan->pipe_state; u32 *pipe_state_addr; int i; @@ -702,7 +703,7 @@ nv10_gr_create_pipe(struct nv10_gr_chan *chan) u32 *__end_addr = pipe_state->pipe_##addr + \ ARRAY_SIZE(pipe_state->pipe_##addr); \ if (pipe_state_addr != __end_addr) \ - nv_error(gr, "incomplete pipe init for 0x%x : %p/%p\n", \ + nvkm_error(subdev, "incomplete pipe init for 0x%x : %p/%p\n", \ addr, pipe_state_addr, __end_addr); \ } while (0) #define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value @@ -844,24 +845,26 @@ nv10_gr_create_pipe(struct nv10_gr_chan *chan) static int nv10_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; int i; for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) { if (nv10_gr_ctx_regs[i] == reg) return i; } - nv_error(gr, "unknow offset nv10_ctx_regs %d\n", reg); + nvkm_error(subdev, "unknow offset nv10_ctx_regs %d\n", reg); return -1; } static int nv17_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; int i; for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) { if (nv17_gr_ctx_regs[i] == reg) return i; } - nv_error(gr, "unknow offset nv17_ctx_regs %d\n", reg); + nvkm_error(subdev, "unknow offset nv17_ctx_regs %d\n", reg); return -1; } @@ -1177,6 +1180,7 @@ nv10_gr_intr(struct nvkm_subdev *subdev) u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; + char msg[128], src[128], sta[128]; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); @@ -1204,17 +1208,14 @@ nv10_gr_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(gr, "%s", ""); - nvkm_bitfield_print(nv10_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv10_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(gr, - "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, nvkm_client_name(chan), subc, class, mthd, - data); + nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + nvkm_client_name(chan), subc, class, mthd, data); } nvkm_namedb_put(handle); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 21aff9b5ed408..dab64540e69f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -207,6 +207,7 @@ nv20_gr_intr(struct nvkm_subdev *subdev) u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; + char msg[128], src[128], sta[128]; engctx = nvkm_engctx_get(engine, chid); if (stat & NV_PGRAPH_INTR_ERROR) { @@ -222,17 +223,14 @@ nv20_gr_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(gr, "%s", ""); - nvkm_bitfield_print(nv10_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv10_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(gr, - "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, nvkm_client_name(engctx), subc, class, mthd, - data); + nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + nvkm_client_name(engctx), subc, class, mthd, data); } nvkm_engctx_put(engctx); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 7455049ff1780..10ffb676e55ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -155,7 +155,8 @@ nv40_gr_context_fini(struct nvkm_object *object, bool suspend) { struct nv40_gr *gr = (void *)object->engine; struct nv40_gr_chan *chan = (void *)object; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; int ret = 0; @@ -172,7 +173,7 @@ nv40_gr_context_fini(struct nvkm_object *object, bool suspend) break; ) < 0) { u32 insn = nvkm_rd32(device, 0x400308); - nv_warn(gr, "ctxprog timeout 0x%08x\n", insn); + nvkm_warn(subdev, "ctxprog timeout %08x\n", insn); ret = -EBUSY; } } @@ -302,6 +303,7 @@ nv40_gr_intr(struct nvkm_subdev *subdev) u32 data = nvkm_rd32(device, NV04_PGRAPH_TRAPPED_DATA); u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xffff; u32 show = stat; + char msg[128], src[128], sta[128]; int chid; engctx = nvkm_engctx_get(engine, inst); @@ -324,17 +326,15 @@ nv40_gr_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); if (show) { - nv_error(gr, "%s", ""); - nvkm_bitfield_print(nv10_gr_intr_name, show); - pr_cont(" nsource:"); - nvkm_bitfield_print(nv04_gr_nsource, nsource); - pr_cont(" nstatus:"); - nvkm_bitfield_print(nv10_gr_nstatus, nstatus); - pr_cont("\n"); - nv_error(gr, - "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, inst << 4, nvkm_client_name(engctx), subc, - class, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), nv10_gr_intr_name, show); + nvkm_snprintbf(src, sizeof(src), nv04_gr_nsource, nsource); + nvkm_snprintbf(sta, sizeof(sta), nv10_gr_nstatus, nstatus); + nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " + "nstatus %08x [%s] ch %d [%08x %s] subc %d " + "class %04x mthd %04x data %08x\n", + show, msg, nsource, src, nstatus, sta, chid, + inst << 4, nvkm_client_name(engctx), subc, + class, mthd, data); } nvkm_engctx_put(engctx); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 3b482bcc22d08..4ea7f09387693 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -200,46 +200,71 @@ static const struct nvkm_bitfield nv50_gr_status[] = { {} }; -static const char *const nv50_gr_vstatus_0[] = { - "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP", - NULL +static const struct nvkm_bitfield +nv50_gr_vstatus_0[] = { + { 0x01, "VFETCH" }, + { 0x02, "CCACHE" }, + { 0x04, "PREGEOM" }, + { 0x08, "POSTGEOM" }, + { 0x10, "VATTR" }, + { 0x20, "STRMOUT" }, + { 0x40, "VCLIP" }, + {} }; -static const char *const nv50_gr_vstatus_1[] = { - "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL +static const struct nvkm_bitfield +nv50_gr_vstatus_1[] = { + { 0x01, "TPC_RAST" }, + { 0x02, "TPC_PROP" }, + { 0x04, "TPC_TEX" }, + { 0x08, "TPC_GEOM" }, + { 0x10, "TPC_MP" }, + {} }; -static const char *const nv50_gr_vstatus_2[] = { - "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK", - "ROP", NULL +static const struct nvkm_bitfield +nv50_gr_vstatus_2[] = { + { 0x01, "RATTR" }, + { 0x02, "APLANE" }, + { 0x04, "TRAST" }, + { 0x08, "CLIPID" }, + { 0x10, "ZCULL" }, + { 0x20, "ENG2D" }, + { 0x40, "RMASK" }, + { 0x80, "ROP" }, + {} }; static void nvkm_gr_vstatus_print(struct nv50_gr *gr, int r, - const char *const units[], u32 status) + const struct nvkm_bitfield *units, u32 status) { + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + u32 stat = status; + u8 mask = 0x00; + char msg[64]; int i; - nv_error(gr, "PGRAPH_VSTATUS%d: 0x%08x", r, status); - - for (i = 0; units[i] && status; i++) { + for (i = 0; units[i].name && status; i++) { if ((status & 7) == 1) - pr_cont(" %s", units[i]); + mask |= (1 << i); status >>= 3; } - if (status) - pr_cont(" (invalid: 0x%x)", status); - pr_cont("\n"); + + nvkm_snprintbf(msg, sizeof(msg), units, mask); + nvkm_error(subdev, "PGRAPH_VSTATUS%d: %08x [%s]\n", r, stat, msg); } static int g84_gr_tlb_flush(struct nvkm_engine *engine) { struct nv50_gr *gr = (void *)engine; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_timer *tmr = device->timer; bool idle, timeout = false; unsigned long flags; + char status[128]; u64 start; u32 tmp; @@ -268,12 +293,11 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) !(timeout = tmr->read(tmr) - start > 2000000000)); if (timeout) { - nv_error(gr, "PGRAPH TLB flush idle timeout fail\n"); + nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n"); tmp = nvkm_rd32(device, 0x400700); - nv_error(gr, "PGRAPH_STATUS : 0x%08x", tmp); - nvkm_bitfield_print(nv50_gr_status, tmp); - pr_cont("\n"); + nvkm_snprintbf(status, sizeof(status), nv50_gr_status, tmp); + nvkm_error(subdev, "PGRAPH_STATUS %08x [%s]\n", tmp, status); nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0, nvkm_rd32(device, 0x400380)); @@ -427,10 +451,10 @@ static const struct nvkm_bitfield nv50_gr_trap_prop[] = { }; static void -nv50_gr_prop_trap(struct nv50_gr *gr, - u32 ustatus_addr, u32 ustatus, u32 tp) +nv50_gr_prop_trap(struct nv50_gr *gr, u32 ustatus_addr, u32 ustatus, u32 tp) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 e0c = nvkm_rd32(device, ustatus_addr + 0x04); u32 e10 = nvkm_rd32(device, ustatus_addr + 0x08); u32 e14 = nvkm_rd32(device, ustatus_addr + 0x0c); @@ -438,40 +462,44 @@ nv50_gr_prop_trap(struct nv50_gr *gr, u32 e1c = nvkm_rd32(device, ustatus_addr + 0x14); u32 e20 = nvkm_rd32(device, ustatus_addr + 0x18); u32 e24 = nvkm_rd32(device, ustatus_addr + 0x1c); + char msg[128]; /* CUDA memory: l[], g[] or stack. */ if (ustatus & 0x00000080) { if (e18 & 0x80000000) { /* g[] read fault? */ - nv_error(gr, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n", tp, e14, e10 | ((e18 >> 24) & 0x1f)); e18 &= ~0x1f000000; } else if (e18 & 0xc) { /* g[] write fault? */ - nv_error(gr, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n", tp, e14, e10 | ((e18 >> 7) & 0x1f)); e18 &= ~0x00000f80; } else { - nv_error(gr, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n", tp, e14, e10); } ustatus &= ~0x00000080; } if (ustatus) { - nv_error(gr, "TRAP_PROP - TP %d -", tp); - nvkm_bitfield_print(nv50_gr_trap_prop, ustatus); - pr_cont(" - Address %02x%08x\n", e14, e10); + nvkm_snprintbf(msg, sizeof(msg), nv50_gr_trap_prop, ustatus); + nvkm_error(subdev, "TRAP_PROP - TP %d - %08x [%s] - " + "Address %02x%08x\n", + tp, ustatus, msg, e14, e10); } - nv_error(gr, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", + nvkm_error(subdev, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n", tp, e0c, e18, e1c, e20, e24); } static void nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 units = nvkm_rd32(device, 0x1540); u32 addr, mp10, status, pc, oplow, ophigh; + char msg[128]; int i; int mps = 0; for (i = 0; i < 4; i++) { @@ -490,19 +518,20 @@ nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) pc = nvkm_rd32(device, addr + 0x24); oplow = nvkm_rd32(device, addr + 0x70); ophigh = nvkm_rd32(device, addr + 0x74); - nv_error(gr, "TRAP_MP_EXEC - " - "TP %d MP %d:", tpid, i); - nvkm_bitfield_print(nv50_mp_exec_errors, status); - pr_cont(" at %06x warp %d, opcode %08x %08x\n", - pc&0xffffff, pc >> 24, - oplow, ophigh); + nvkm_snprintbf(msg, sizeof(msg), + nv50_mp_exec_errors, status); + nvkm_error(subdev, "TRAP_MP_EXEC - TP %d MP %d: " + "%08x [%s] at %06x warp %d, " + "opcode %08x %08x\n", + tpid, i, status, msg, pc & 0xffffff, + pc >> 24, oplow, ophigh); } nvkm_wr32(device, addr + 0x10, mp10); nvkm_wr32(device, addr + 0x14, 0); mps++; } if (!mps && display) - nv_error(gr, "TRAP_MP_EXEC - TP %d: " + nvkm_error(subdev, "TRAP_MP_EXEC - TP %d: " "No MPs claiming errors?\n", tpid); } @@ -510,10 +539,12 @@ static void nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, u32 ustatus_new, int display, const char *name) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 units = nvkm_rd32(device, 0x1540); int tps = 0; int i, r; + char msg[128]; u32 ustatus_addr, ustatus; for (i = 0; i < 16; i++) { if (!(units & (1 << i))) @@ -529,15 +560,16 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, switch (type) { case 6: /* texture error... unknown for now */ if (display) { - nv_error(gr, "magic set %d:\n", i); + nvkm_error(subdev, "magic set %d:\n", i); for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4) - nv_error(gr, "\t0x%08x: 0x%08x\n", r, - nvkm_rd32(device, r)); + nvkm_error(subdev, "\t%08x: %08x\n", r, + nvkm_rd32(device, r)); if (ustatus) { - nv_error(gr, "%s - TP%d:", name, i); - nvkm_bitfield_print(nv50_tex_traps, - ustatus); - pr_cont("\n"); + nvkm_snprintbf(msg, sizeof(msg), + nv50_tex_traps, ustatus); + nvkm_error(subdev, + "%s - TP%d: %08x [%s]\n", + name, i, ustatus, msg); ustatus = 0; } } @@ -548,9 +580,10 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, ustatus &= ~0x04030000; } if (ustatus && display) { - nv_error(gr, "%s - TP%d:", name, i); - nvkm_bitfield_print(nv50_mpc_traps, ustatus); - pr_cont("\n"); + nvkm_snprintbf(msg, sizeof(msg), + nv50_mpc_traps, ustatus); + nvkm_error(subdev, "%s - TP%d: %08x [%s]\n", + name, i, ustatus, msg); ustatus = 0; } break; @@ -563,25 +596,27 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, } if (ustatus) { if (display) - nv_error(gr, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus); + nvkm_error(subdev, "%s - TP%d: Unhandled ustatus %08x\n", name, i, ustatus); } nvkm_wr32(device, ustatus_addr, 0xc0000000); } if (!tps && display) - nv_warn(gr, "%s - No TPs claiming errors?\n", name); + nvkm_warn(subdev, "%s - No TPs claiming errors?\n", name); } static int nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, int chid, u64 inst, struct nvkm_object *engctx) { - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 status = nvkm_rd32(device, 0x400108); u32 ustatus; + char msg[128]; if (!status && display) { - nv_error(gr, "TRAP: no units reporting traps?\n"); + nvkm_error(subdev, "TRAP: no units reporting traps?\n"); return 1; } @@ -591,7 +626,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x001) { ustatus = nvkm_rd32(device, 0x400804) & 0x7fffffff; if (!ustatus && display) { - nv_error(gr, "TRAP_DISPATCH - no ustatus?\n"); + nvkm_error(subdev, "TRAP_DISPATCH - no ustatus?\n"); } nvkm_wr32(device, 0x400500, 0x00000000); @@ -606,16 +641,19 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, u32 class = nvkm_rd32(device, 0x400814); u32 r848 = nvkm_rd32(device, 0x400848); - nv_error(gr, "TRAP DISPATCH_FAULT\n"); + nvkm_error(subdev, "TRAP DISPATCH_FAULT\n"); if (display && (addr & 0x80000000)) { - nv_error(gr, - "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n", - chid, inst, - nvkm_client_name(engctx), subc, - class, mthd, datah, datal, addr, r848); + nvkm_error(subdev, + "ch %d [%010llx %s] subc %d " + "class %04x mthd %04x data %08x%08x " + "400808 %08x 400848 %08x\n", + chid, inst, + nvkm_client_name(engctx), + subc, class, mthd, + datah, datal, addr, r848); } else if (display) { - nv_error(gr, "no stuck command?\n"); + nvkm_error(subdev, "no stuck command?\n"); } nvkm_wr32(device, 0x400808, 0); @@ -631,16 +669,17 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, u32 data = nvkm_rd32(device, 0x40085c); u32 class = nvkm_rd32(device, 0x400814); - nv_error(gr, "TRAP DISPATCH_QUERY\n"); + nvkm_error(subdev, "TRAP DISPATCH_QUERY\n"); if (display && (addr & 0x80000000)) { - nv_error(gr, - "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n", - chid, inst, - nvkm_client_name(engctx), subc, - class, mthd, data, addr); + nvkm_error(subdev, + "ch %d [%010llx %s] subc %d " + "class %04x mthd %04x data %08x " + "40084c %08x\n", chid, inst, + nvkm_client_name(engctx), subc, + class, mthd, data, addr); } else if (display) { - nv_error(gr, "no stuck command?\n"); + nvkm_error(subdev, "no stuck command?\n"); } nvkm_wr32(device, 0x40084c, 0); @@ -648,8 +687,8 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, } if (ustatus && display) { - nv_error(gr, "TRAP_DISPATCH (unknown " - "0x%08x)\n", ustatus); + nvkm_error(subdev, "TRAP_DISPATCH " + "(unknown %08x)\n", ustatus); } nvkm_wr32(device, 0x400804, 0xc0000000); @@ -663,13 +702,15 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x002) { u32 ustatus = nvkm_rd32(device, 0x406800) & 0x7fffffff; if (display) { - nv_error(gr, "TRAP_M2MF"); - nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus); - pr_cont("\n"); - nv_error(gr, "TRAP_M2MF %08x %08x %08x %08x\n", - nvkm_rd32(device, 0x406804), nvkm_rd32(device, 0x406808), - nvkm_rd32(device, 0x40680c), nvkm_rd32(device, 0x406810)); - + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_m2mf, ustatus); + nvkm_error(subdev, "TRAP_M2MF %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_M2MF %08x %08x %08x %08x\n", + nvkm_rd32(device, 0x406804), + nvkm_rd32(device, 0x406808), + nvkm_rd32(device, 0x40680c), + nvkm_rd32(device, 0x406810)); } /* No sane way found yet -- just reset the bugger. */ @@ -684,12 +725,15 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x004) { u32 ustatus = nvkm_rd32(device, 0x400c04) & 0x7fffffff; if (display) { - nv_error(gr, "TRAP_VFETCH"); - nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus); - pr_cont("\n"); - nv_error(gr, "TRAP_VFETCH %08x %08x %08x %08x\n", - nvkm_rd32(device, 0x400c00), nvkm_rd32(device, 0x400c08), - nvkm_rd32(device, 0x400c0c), nvkm_rd32(device, 0x400c10)); + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_vfetch, ustatus); + nvkm_error(subdev, "TRAP_VFETCH %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_VFETCH %08x %08x %08x %08x\n", + nvkm_rd32(device, 0x400c00), + nvkm_rd32(device, 0x400c08), + nvkm_rd32(device, 0x400c0c), + nvkm_rd32(device, 0x400c10)); } nvkm_wr32(device, 0x400c04, 0xc0000000); @@ -701,13 +745,15 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x008) { ustatus = nvkm_rd32(device, 0x401800) & 0x7fffffff; if (display) { - nv_error(gr, "TRAP_STRMOUT"); - nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus); - pr_cont("\n"); - nv_error(gr, "TRAP_STRMOUT %08x %08x %08x %08x\n", - nvkm_rd32(device, 0x401804), nvkm_rd32(device, 0x401808), - nvkm_rd32(device, 0x40180c), nvkm_rd32(device, 0x401810)); - + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_strmout, ustatus); + nvkm_error(subdev, "TRAP_STRMOUT %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_STRMOUT %08x %08x %08x %08x\n", + nvkm_rd32(device, 0x401804), + nvkm_rd32(device, 0x401808), + nvkm_rd32(device, 0x40180c), + nvkm_rd32(device, 0x401810)); } /* No sane way found yet -- just reset the bugger. */ @@ -722,16 +768,19 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x010) { ustatus = nvkm_rd32(device, 0x405018) & 0x7fffffff; if (display) { - nv_error(gr, "TRAP_CCACHE"); - nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus); - pr_cont("\n"); - nv_error(gr, "TRAP_CCACHE %08x %08x %08x %08x" - " %08x %08x %08x\n", - nvkm_rd32(device, 0x405000), nvkm_rd32(device, 0x405004), - nvkm_rd32(device, 0x405008), nvkm_rd32(device, 0x40500c), - nvkm_rd32(device, 0x405010), nvkm_rd32(device, 0x405014), - nvkm_rd32(device, 0x40501c)); - + nvkm_snprintbf(msg, sizeof(msg), + nv50_gr_trap_ccache, ustatus); + nvkm_error(subdev, "TRAP_CCACHE %08x [%s]\n", + ustatus, msg); + nvkm_error(subdev, "TRAP_CCACHE %08x %08x %08x %08x " + "%08x %08x %08x\n", + nvkm_rd32(device, 0x405000), + nvkm_rd32(device, 0x405004), + nvkm_rd32(device, 0x405008), + nvkm_rd32(device, 0x40500c), + nvkm_rd32(device, 0x405010), + nvkm_rd32(device, 0x405014), + nvkm_rd32(device, 0x40501c)); } nvkm_wr32(device, 0x405018, 0xc0000000); @@ -745,7 +794,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status & 0x20) { ustatus = nvkm_rd32(device, 0x402000) & 0x7fffffff; if (display) - nv_error(gr, "TRAP_UNKC04 0x%08x\n", ustatus); + nvkm_error(subdev, "TRAP_UNKC04 %08x\n", ustatus); nvkm_wr32(device, 0x402000, 0xc0000000); /* no status modifiction on purpose */ } @@ -777,7 +826,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, if (status) { if (display) - nv_error(gr, "TRAP: unknown 0x%08x\n", status); + nvkm_error(subdev, "TRAP: unknown %08x\n", status); nvkm_wr32(device, 0x400108, status); } @@ -801,6 +850,8 @@ nv50_gr_intr(struct nvkm_subdev *subdev) u32 data = nvkm_rd32(device, 0x400708); u32 class = nvkm_rd32(device, 0x400814); u32 show = stat, show_bitfield = stat; + const struct nvkm_enum *en; + char msg[128]; int chid; engctx = nvkm_engctx_get(engine, inst); @@ -815,9 +866,9 @@ nv50_gr_intr(struct nvkm_subdev *subdev) if (show & 0x00100000) { u32 ecode = nvkm_rd32(device, 0x400110); - nv_error(gr, "DATA_ERROR "); - nvkm_enum_print(nv50_data_error_names, ecode); - pr_cont("\n"); + en = nvkm_enum_find(nv50_data_error_names, ecode); + nvkm_error(subdev, "DATA_ERROR %08x [%s]\n", + ecode, en ? en->name : ""); show_bitfield &= ~0x00100000; } @@ -833,15 +884,11 @@ nv50_gr_intr(struct nvkm_subdev *subdev) if (show) { show &= show_bitfield; - if (show) { - nv_error(gr, "%s", ""); - nvkm_bitfield_print(nv50_gr_intr_name, show); - pr_cont("\n"); - } - nv_error(gr, - "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n", - chid, (u64)inst << 12, nvkm_client_name(engctx), - subc, class, mthd, data); + nvkm_snprintbf(msg, sizeof(msg), nv50_gr_intr_name, show); + nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] subc %d " + "class %04x mthd %04x data %08x\n", + stat, msg, chid, (u64)inst << 12, + nvkm_client_name(engctx), subc, class, mthd, data); } if (nvkm_rd32(device, 0x400824) & (1 << 31)) -- GitLab From b835c09bc6b87318fd06bfcb9ac4bb59eaa48f57 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5434/7006] drm/nouveau/mpeg: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 12 +++++++----- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 15 ++++++++------- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 4ea554e81a296..4ece5c0654128 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -229,9 +229,9 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { - nv_error(mpeg, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n", - fifo->chid(fifo, engctx), - nvkm_client_name(engctx), stat, type, mthd, data); + nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", + fifo->chid(fifo, engctx), + nvkm_client_name(engctx), stat, type, mthd, data); } spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); @@ -263,7 +263,8 @@ nv31_mpeg_init(struct nvkm_object *object) { struct nvkm_engine *engine = nv_engine(object); struct nv31_mpeg *mpeg = (void *)object; - struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_subdev *subdev = &mpeg->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fb *fb = device->fb; int ret, i; @@ -292,7 +293,8 @@ nv31_mpeg_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) break; ) < 0) { - nv_error(mpeg, "timeout 0x%08x\n", nvkm_rd32(device, 0x00b200)); + nvkm_error(subdev, "timeout %08x\n", + nvkm_rd32(device, 0x00b200)); return -EBUSY; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 08da34bf7931b..47ae1d890a7f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -98,7 +98,7 @@ nv40_mpeg_intr(struct nvkm_subdev *subdev) nv31_mpeg_intr(subdev); if ((stat = nvkm_rd32(device, 0x00b800))) { - nv_error(mpeg, "PMSRCH 0x%08x\n", stat); + nvkm_error(subdev, "PMSRCH %08x\n", stat); nvkm_wr32(device, 0x00b800, stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index cbf98b306d71b..9bd5fc185ea2f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -126,10 +126,10 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { - nv_error(mpeg, - "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n", - chid, inst << 4, nvkm_client_name(engctx), stat, - type, mthd, data); + nvkm_error(subdev, + "ch %d [%08x %s] %08x %08x %08x %08x\n", + chid, inst << 4, nvkm_client_name(engctx), stat, + type, mthd, data); } nvkm_engctx_put(engctx); @@ -146,7 +146,7 @@ nv44_mpeg_me_intr(struct nvkm_subdev *subdev) nv44_mpeg_intr(subdev); if ((stat = nvkm_rd32(device, 0x00b800))) { - nv_error(mpeg, "PMSRCH 0x%08x\n", stat); + nvkm_error(subdev, "PMSRCH %08x\n", stat); nvkm_wr32(device, 0x00b800, stat); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index 586ff06705bab..0a4ada7b3a279 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -135,8 +135,8 @@ nv50_mpeg_intr(struct nvkm_subdev *subdev) } if (show) { - nv_info(mpeg, "0x%08x 0x%08x 0x%08x 0x%08x\n", - stat, type, mthd, data); + nvkm_info(subdev, "%08x %08x %08x %08x\n", + stat, type, mthd, data); } nvkm_wr32(device, 0x00b100, stat); @@ -146,15 +146,14 @@ nv50_mpeg_intr(struct nvkm_subdev *subdev) static void nv50_vpe_intr(struct nvkm_subdev *subdev) { - struct nvkm_mpeg *mpeg = (void *)subdev; - struct nvkm_device *device = mpeg->engine.subdev.device; + struct nvkm_device *device = subdev->device; if (nvkm_rd32(device, 0x00b100)) nv50_mpeg_intr(subdev); if (nvkm_rd32(device, 0x00b800)) { u32 stat = nvkm_rd32(device, 0x00b800); - nv_info(mpeg, "PMSRCH: 0x%08x\n", stat); + nvkm_info(subdev, "PMSRCH: %08x\n", stat); nvkm_wr32(device, 0xb800, stat); } } @@ -183,7 +182,8 @@ int nv50_mpeg_init(struct nvkm_object *object) { struct nvkm_mpeg *mpeg = (void *)object; - struct nvkm_device *device = mpeg->engine.subdev.device; + struct nvkm_subdev *subdev = &mpeg->engine.subdev; + struct nvkm_device *device = subdev->device; int ret; ret = nvkm_mpeg_init(mpeg); @@ -208,7 +208,8 @@ nv50_mpeg_init(struct nvkm_object *object) if (!(nvkm_rd32(device, 0x00b200) & 0x00000001)) break; ) < 0) { - nv_error(mpeg, "timeout 0x%08x\n", nvkm_rd32(device, 0x00b200)); + nvkm_error(subdev, "timeout %08x\n", + nvkm_rd32(device, 0x00b200)); return -EBUSY; } -- GitLab From 476901ff6c611620daab3af6cea940be91d97420 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5435/7006] drm/nouveau/pm: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index fde6a6013c491..365cd823d6bb2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -126,7 +126,8 @@ nvkm_perfsrc_find(struct nvkm_pm *pm, struct nvkm_perfsig *sig, int si) static int nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) { - struct nvkm_device *device = pm->engine.subdev.device; + struct nvkm_subdev *subdev = &pm->engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; @@ -153,8 +154,9 @@ nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) /* enable the source */ nvkm_mask(device, src->addr, mask, value); - nv_debug(pm, "enabled source 0x%08x 0x%08x 0x%08x\n", - src->addr, mask, value); + nvkm_debug(subdev, + "enabled source %08x %08x %08x\n", + src->addr, mask, value); } } return 0; @@ -163,7 +165,8 @@ nvkm_perfsrc_enable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) static int nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) { - struct nvkm_device *device = pm->engine.subdev.device; + struct nvkm_subdev *subdev = &pm->engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; @@ -189,8 +192,8 @@ nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) /* disable the source */ nvkm_mask(device, src->addr, mask, 0); - nv_debug(pm, "disabled source 0x%08x 0x%08x\n", - src->addr, mask); + nvkm_debug(subdev, "disabled source %08x %08x\n", + src->addr, mask); } } return 0; -- GitLab From 9e3911e5b244c01886f25ce1cb453dd9c5334853 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5436/7006] drm/nouveau/sec: switch to subdev printk macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/enum.h | 1 - drivers/gpu/drm/nouveau/nvkm/core/enum.c | 11 ----------- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 14 ++++++++------ 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h index a5d4c65bbbc20..40429a82f7922 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h @@ -10,7 +10,6 @@ struct nvkm_enum { }; const struct nvkm_enum *nvkm_enum_find(const struct nvkm_enum *, u32 value); -const struct nvkm_enum *nvkm_enum_print(const struct nvkm_enum *, u32 value); struct nvkm_bitfield { u32 mask; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/enum.c b/drivers/gpu/drm/nouveau/nvkm/core/enum.c index 64bdbd04a73ab..b9581feb24ccb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/enum.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/enum.c @@ -38,17 +38,6 @@ nvkm_enum_find(const struct nvkm_enum *en, u32 value) return NULL; } -const struct nvkm_enum * -nvkm_enum_print(const struct nvkm_enum *en, u32 value) -{ - en = nvkm_enum_find(en, value); - if (en) - pr_cont("%s", en->name); - else - pr_cont("(unknown enum 0x%08x)", value); - return en; -} - void nvkm_snprintbf(char *data, int size, const struct nvkm_bitfield *bf, u32 value) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index a1096f0e40814..b60719092154c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -84,23 +84,25 @@ g98_sec_intr(struct nvkm_subdev *subdev) u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; u32 data = nvkm_rd32(device, 0x087044); + const struct nvkm_enum *en; int chid; engctx = nvkm_engctx_get(engine, inst); chid = fifo->chid(fifo, engctx); if (stat & 0x00000040) { - nv_error(sec, "DISPATCH_ERROR ["); - nvkm_enum_print(g98_sec_isr_error_name, ssta); - pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n", - chid, (u64)inst << 12, nvkm_client_name(engctx), - subc, mthd, data); + en = nvkm_enum_find(g98_sec_isr_error_name, ssta); + nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] " + "ch %d [%010llx %s] subc %d " + "mthd %04x data %08x\n", ssta, + en ? en->name : "", chid, (u64)inst << 12, + nvkm_client_name(engctx), subc, mthd, data); nvkm_wr32(device, 0x087004, 0x00000040); stat &= ~0x00000040; } if (stat) { - nv_error(sec, "unhandled intr 0x%08x\n", stat); + nvkm_error(subdev, "intr %08x\n", stat); nvkm_wr32(device, 0x087004, stat); } -- GitLab From 9ad97ede4b1b257ccc867d5a1e865049e1f09166 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5437/7006] drm/nouveau: use dev_* for logging Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bios.c | 7 ++-- drivers/gpu/drm/nouveau/nouveau_chan.c | 8 ++-- drivers/gpu/drm/nouveau/nouveau_drm.c | 18 +++++---- drivers/gpu/drm/nouveau/nouveau_drm.h | 13 +++++-- drivers/gpu/drm/nouveau/nouveau_gem.c | 52 ++++++++++++------------- drivers/gpu/drm/nouveau/nv50_display.c | 2 +- 7 files changed, 55 insertions(+), 47 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index c2ba0cc1521f6..01ffdb37a66b2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -217,7 +217,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = gr->units ? gr->units(gr) : 0; break; default: - NV_PRINTK(debug, cli, "unknown parameter %lld\n", getparam->param); + NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index e9de6e37af56d..c6dbfaf49a11b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1891,11 +1891,12 @@ parse_dcb_table(struct drm_device *dev, struct nvbios *bios) idx = -1; while ((conn = olddcb_conn(dev, ++idx))) { if (conn[0] != 0xff) { - NV_INFO(drm, "DCB conn %02d: ", idx); if (olddcb_conntab(dev)[3] < 4) - pr_cont("%04x\n", ROM16(conn[0])); + NV_INFO(drm, "DCB conn %02d: %04x\n", + idx, ROM16(conn[0])); else - pr_cont("%08x\n", ROM32(conn[0])); + NV_INFO(drm, "DCB conn %02d: %08x\n", + idx, ROM32(conn[0])); } } dcb_fake_connectors(bios); diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 0589babc506eb..694b135e27c95 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -53,7 +53,7 @@ nouveau_channel_idle(struct nouveau_channel *chan) } if (ret) - NV_PRINTK(error, cli, "failed to idle channel 0x%08x [%s]\n", + NV_PRINTK(err, cli, "failed to idle channel 0x%08x [%s]\n", chan->object->handle, nvxx_client(&cli->base)->name); return ret; } @@ -405,17 +405,17 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, ret = nouveau_channel_ind(drm, device, handle, arg0, pchan); if (ret) { - NV_PRINTK(debug, cli, "ib channel create, %d\n", ret); + NV_PRINTK(dbg, cli, "ib channel create, %d\n", ret); ret = nouveau_channel_dma(drm, device, handle, pchan); if (ret) { - NV_PRINTK(debug, cli, "dma channel create, %d\n", ret); + NV_PRINTK(dbg, cli, "dma channel create, %d\n", ret); goto done; } } ret = nouveau_channel_init(*pchan, arg0, arg1); if (ret) { - NV_PRINTK(error, cli, "channel failed to initialise, %d\n", ret); + NV_PRINTK(err, cli, "channel failed to initialise, %d\n", ret); nouveau_channel_del(pchan); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 109b8262dc859..89df4bf1e61be 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -105,14 +105,18 @@ nouveau_name(struct drm_device *dev) } static int -nouveau_cli_create(u64 name, const char *sname, +nouveau_cli_create(struct drm_device *dev, const char *sname, int size, void **pcli) { struct nouveau_cli *cli = *pcli = kzalloc(size, GFP_KERNEL); + int ret; if (cli) { - int ret = nvif_client_init(NULL, NULL, sname, name, - nouveau_config, nouveau_debug, - &cli->base); + snprintf(cli->name, sizeof(cli->name), "%s", sname); + cli->dev = dev; + + ret = nvif_client_init(NULL, NULL, cli->name, nouveau_name(dev), + nouveau_config, nouveau_debug, + &cli->base); if (ret == 0) { mutex_init(&cli->mutex); usif_client_init(cli); @@ -375,8 +379,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) struct nouveau_drm *drm; int ret; - ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm), - (void **)&drm); + ret = nouveau_cli_create(dev, "DRM", sizeof(*drm), (void **)&drm); if (ret) return ret; @@ -826,8 +829,7 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) get_task_comm(tmpname, current); snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid)); - ret = nouveau_cli_create(nouveau_name(dev), name, sizeof(*cli), - (void **)&cli); + ret = nouveau_cli_create(dev, name, sizeof(*cli), (void **)&cli); if (ret) goto out_suspend; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index dd726523ca993..81ef59272ed29 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -88,6 +88,8 @@ struct nouveau_cli { void *abi16; struct list_head objects; struct list_head notifys; + char name[32]; + struct drm_device *dev; }; static inline struct nouveau_cli * @@ -189,13 +191,16 @@ void nouveau_drm_device_remove(struct drm_device *dev); #define NV_PRINTK(l,c,f,a...) do { \ struct nouveau_cli *_cli = (c); \ - nv_##l(_cli->base.base.priv, f, ##a); \ + dev_##l(_cli->dev->dev, "%s: "f, _cli->name, ##a); \ } while(0) -#define NV_FATAL(drm,f,a...) NV_PRINTK(fatal, &(drm)->client, f, ##a) -#define NV_ERROR(drm,f,a...) NV_PRINTK(error, &(drm)->client, f, ##a) +#define NV_FATAL(drm,f,a...) NV_PRINTK(crit, &(drm)->client, f, ##a) +#define NV_ERROR(drm,f,a...) NV_PRINTK(err, &(drm)->client, f, ##a) #define NV_WARN(drm,f,a...) NV_PRINTK(warn, &(drm)->client, f, ##a) #define NV_INFO(drm,f,a...) NV_PRINTK(info, &(drm)->client, f, ##a) -#define NV_DEBUG(drm,f,a...) NV_PRINTK(debug, &(drm)->client, f, ##a) +#define NV_DEBUG(drm,f,a...) do { \ + if (unlikely(drm_debug & DRM_UT_DRIVER)) \ + NV_PRINTK(info, &(drm)->client, f, ##a); \ +} while(0) extern int nouveau_modeset; diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index a747eccbc79fb..dc5845ee2fa0d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -260,7 +260,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, int ret = 0; if (!fb->memtype_valid(fb, req->info.tile_flags)) { - NV_PRINTK(error, cli, "bad page flags: 0x%08x\n", req->info.tile_flags); + NV_PRINTK(err, cli, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; } @@ -376,7 +376,7 @@ validate_init(struct nouveau_channel *chan, struct drm_file *file_priv, ww_acquire_init(&op->ticket, &reservation_ww_class); retry: if (++trycnt > 100000) { - NV_PRINTK(error, cli, "%s failed and gave up.\n", __func__); + NV_PRINTK(err, cli, "%s failed and gave up.\n", __func__); return -EINVAL; } @@ -387,7 +387,7 @@ retry: gem = drm_gem_object_lookup(dev, file_priv, b->handle); if (!gem) { - NV_PRINTK(error, cli, "Unknown handle 0x%08x\n", b->handle); + NV_PRINTK(err, cli, "Unknown handle 0x%08x\n", b->handle); ret = -ENOENT; break; } @@ -399,7 +399,7 @@ retry: } if (nvbo->reserved_by && nvbo->reserved_by == file_priv) { - NV_PRINTK(error, cli, "multiple instances of buffer %d on " + NV_PRINTK(err, cli, "multiple instances of buffer %d on " "validation list\n", b->handle); drm_gem_object_unreference_unlocked(gem); ret = -EINVAL; @@ -420,7 +420,7 @@ retry: } if (unlikely(ret)) { if (ret != -ERESTARTSYS) - NV_PRINTK(error, cli, "fail reserve\n"); + NV_PRINTK(err, cli, "fail reserve\n"); break; } } @@ -438,7 +438,7 @@ retry: if (b->valid_domains & NOUVEAU_GEM_DOMAIN_GART) list_add_tail(&nvbo->entry, &gart_list); else { - NV_PRINTK(error, cli, "invalid valid domains: 0x%08x\n", + NV_PRINTK(err, cli, "invalid valid domains: 0x%08x\n", b->valid_domains); list_add_tail(&nvbo->entry, &both_list); ret = -EINVAL; @@ -476,21 +476,21 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli, b->write_domains, b->valid_domains); if (unlikely(ret)) { - NV_PRINTK(error, cli, "fail set_domain\n"); + NV_PRINTK(err, cli, "fail set_domain\n"); return ret; } ret = nouveau_bo_validate(nvbo, true, false); if (unlikely(ret)) { if (ret != -ERESTARTSYS) - NV_PRINTK(error, cli, "fail ttm_validate\n"); + NV_PRINTK(err, cli, "fail ttm_validate\n"); return ret; } ret = nouveau_fence_sync(nvbo, chan, !!b->write_domains, true); if (unlikely(ret)) { if (ret != -ERESTARTSYS) - NV_PRINTK(error, cli, "fail post-validate sync\n"); + NV_PRINTK(err, cli, "fail post-validate sync\n"); return ret; } @@ -537,14 +537,14 @@ nouveau_gem_pushbuf_validate(struct nouveau_channel *chan, ret = validate_init(chan, file_priv, pbbo, nr_buffers, op); if (unlikely(ret)) { if (ret != -ERESTARTSYS) - NV_PRINTK(error, cli, "validate_init\n"); + NV_PRINTK(err, cli, "validate_init\n"); return ret; } ret = validate_list(chan, cli, &op->list, pbbo, user_buffers); if (unlikely(ret < 0)) { if (ret != -ERESTARTSYS) - NV_PRINTK(error, cli, "validating bo list\n"); + NV_PRINTK(err, cli, "validating bo list\n"); validate_fini(op, NULL, NULL); return ret; } @@ -600,7 +600,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, uint32_t data; if (unlikely(r->bo_index > req->nr_buffers)) { - NV_PRINTK(error, cli, "reloc bo index invalid\n"); + NV_PRINTK(err, cli, "reloc bo index invalid\n"); ret = -EINVAL; break; } @@ -610,7 +610,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, continue; if (unlikely(r->reloc_bo_index > req->nr_buffers)) { - NV_PRINTK(error, cli, "reloc container bo index invalid\n"); + NV_PRINTK(err, cli, "reloc container bo index invalid\n"); ret = -EINVAL; break; } @@ -618,7 +618,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, if (unlikely(r->reloc_bo_offset + 4 > nvbo->bo.mem.num_pages << PAGE_SHIFT)) { - NV_PRINTK(error, cli, "reloc outside of bo\n"); + NV_PRINTK(err, cli, "reloc outside of bo\n"); ret = -EINVAL; break; } @@ -627,7 +627,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ret = ttm_bo_kmap(&nvbo->bo, 0, nvbo->bo.mem.num_pages, &nvbo->kmap); if (ret) { - NV_PRINTK(error, cli, "failed kmap for reloc\n"); + NV_PRINTK(err, cli, "failed kmap for reloc\n"); break; } nvbo->validate_mapped = true; @@ -650,7 +650,7 @@ nouveau_gem_pushbuf_reloc_apply(struct nouveau_cli *cli, ret = ttm_bo_wait(&nvbo->bo, true, false, false); if (ret) { - NV_PRINTK(error, cli, "reloc wait_idle failed: %d\n", ret); + NV_PRINTK(err, cli, "reloc wait_idle failed: %d\n", ret); break; } @@ -696,19 +696,19 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, goto out_next; if (unlikely(req->nr_push > NOUVEAU_GEM_MAX_PUSH)) { - NV_PRINTK(error, cli, "pushbuf push count exceeds limit: %d max %d\n", + NV_PRINTK(err, cli, "pushbuf push count exceeds limit: %d max %d\n", req->nr_push, NOUVEAU_GEM_MAX_PUSH); return nouveau_abi16_put(abi16, -EINVAL); } if (unlikely(req->nr_buffers > NOUVEAU_GEM_MAX_BUFFERS)) { - NV_PRINTK(error, cli, "pushbuf bo count exceeds limit: %d max %d\n", + NV_PRINTK(err, cli, "pushbuf bo count exceeds limit: %d max %d\n", req->nr_buffers, NOUVEAU_GEM_MAX_BUFFERS); return nouveau_abi16_put(abi16, -EINVAL); } if (unlikely(req->nr_relocs > NOUVEAU_GEM_MAX_RELOCS)) { - NV_PRINTK(error, cli, "pushbuf reloc count exceeds limit: %d max %d\n", + NV_PRINTK(err, cli, "pushbuf reloc count exceeds limit: %d max %d\n", req->nr_relocs, NOUVEAU_GEM_MAX_RELOCS); return nouveau_abi16_put(abi16, -EINVAL); } @@ -726,7 +726,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, /* Ensure all push buffers are on validate list */ for (i = 0; i < req->nr_push; i++) { if (push[i].bo_index >= req->nr_buffers) { - NV_PRINTK(error, cli, "push %d buffer not in list\n", i); + NV_PRINTK(err, cli, "push %d buffer not in list\n", i); ret = -EINVAL; goto out_prevalid; } @@ -737,7 +737,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, req->nr_buffers, &op, &do_reloc); if (ret) { if (ret != -ERESTARTSYS) - NV_PRINTK(error, cli, "validate: %d\n", ret); + NV_PRINTK(err, cli, "validate: %d\n", ret); goto out_prevalid; } @@ -745,7 +745,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (do_reloc) { ret = nouveau_gem_pushbuf_reloc_apply(cli, req, bo); if (ret) { - NV_PRINTK(error, cli, "reloc apply: %d\n", ret); + NV_PRINTK(err, cli, "reloc apply: %d\n", ret); goto out; } } @@ -753,7 +753,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (chan->dma.ib_max) { ret = nouveau_dma_wait(chan, req->nr_push + 1, 16); if (ret) { - NV_PRINTK(error, cli, "nv50cal_space: %d\n", ret); + NV_PRINTK(err, cli, "nv50cal_space: %d\n", ret); goto out; } @@ -768,7 +768,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, if (drm->device.info.chipset >= 0x25) { ret = RING_SPACE(chan, req->nr_push * 2); if (ret) { - NV_PRINTK(error, cli, "cal_space: %d\n", ret); + NV_PRINTK(err, cli, "cal_space: %d\n", ret); goto out; } @@ -782,7 +782,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, } else { ret = RING_SPACE(chan, req->nr_push * (2 + NOUVEAU_DMA_SKIPS)); if (ret) { - NV_PRINTK(error, cli, "jmp_space: %d\n", ret); + NV_PRINTK(err, cli, "jmp_space: %d\n", ret); goto out; } @@ -820,7 +820,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, ret = nouveau_fence_new(chan, false, &fence); if (ret) { - NV_PRINTK(error, cli, "error fencing pushbuf: %d\n", ret); + NV_PRINTK(err, cli, "error fencing pushbuf: %d\n", ret); WIND_RING(chan); goto out; } diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 41425f2fda82a..cb41437ce1b72 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -426,7 +426,7 @@ evo_wait(void *evoc, int nr) break; ) < 0) { mutex_unlock(&dmac->lock); - nv_error(nvxx_object(&dmac->base.user), "channel stalled\n"); + printk(KERN_ERR "nouveau: evo channel stalled\n"); return NULL; } -- GitLab From 53003941067534b1071b0f7b71f4700c16d97b28 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5438/7006] drm/nouveau/core: remove last printks Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/client.h | 3 +- .../gpu/drm/nouveau/include/nvkm/core/debug.h | 9 +- .../drm/nouveau/include/nvkm/core/engctx.h | 3 +- .../drm/nouveau/include/nvkm/core/engine.h | 3 +- .../drm/nouveau/include/nvkm/core/gpuobj.h | 3 +- .../drm/nouveau/include/nvkm/core/namedb.h | 3 +- .../drm/nouveau/include/nvkm/core/object.h | 12 +- .../drm/nouveau/include/nvkm/core/parent.h | 3 +- .../drm/nouveau/include/nvkm/core/printk.h | 29 ----- .../drm/nouveau/include/nvkm/core/subdev.h | 3 +- .../drm/nouveau/include/nvkm/subdev/instmem.h | 3 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 3 - drivers/gpu/drm/nouveau/nvkm/core/Kbuild | 1 - drivers/gpu/drm/nouveau/nvkm/core/client.c | 28 ++--- drivers/gpu/drm/nouveau/nvkm/core/engctx.c | 12 +- drivers/gpu/drm/nouveau/nvkm/core/engine.c | 9 +- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 4 +- drivers/gpu/drm/nouveau/nvkm/core/handle.c | 3 +- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 102 ++++++++--------- drivers/gpu/drm/nouveau/nvkm/core/object.c | 92 ++-------------- drivers/gpu/drm/nouveau/nvkm/core/option.c | 2 +- drivers/gpu/drm/nouveau/nvkm/core/printk.c | 103 ------------------ drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 9 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 17 ++- .../gpu/drm/nouveau/nvkm/engine/device/ctrl.c | 22 ++-- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 16 +-- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 5 +- .../drm/nouveau/nvkm/engine/disp/hdagf110.c | 5 +- .../drm/nouveau/nvkm/engine/disp/hdagt215.c | 5 +- .../drm/nouveau/nvkm/engine/disp/hdmig84.c | 10 +- .../drm/nouveau/nvkm/engine/disp/hdmigf110.c | 10 +- .../drm/nouveau/nvkm/engine/disp/hdmigk104.c | 10 +- .../drm/nouveau/nvkm/engine/disp/hdmigt215.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 11 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 69 ++++++------ .../drm/nouveau/nvkm/engine/disp/piornv50.c | 6 +- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/base.c | 10 +- .../drm/nouveau/nvkm/engine/dmaobj/gf100.c | 7 +- .../drm/nouveau/nvkm/engine/dmaobj/gf110.c | 7 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 18 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 18 +-- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 42 +++---- 50 files changed, 294 insertions(+), 514 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/printk.h delete mode 100644 drivers/gpu/drm/nouveau/nvkm/core/printk.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index bcd2a35836516..882ff6ed1e41a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -20,8 +20,7 @@ static inline struct nvkm_client * nv_client(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS))) - nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_CLIENT_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h b/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h index d07cb860b56c5..c59fd4e2ad5e2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h @@ -1,18 +1,11 @@ #ifndef __NVKM_DEBUG_H__ #define __NVKM_DEBUG_H__ -extern int nv_info_debug_level; - #define NV_DBG_FATAL 0 #define NV_DBG_ERROR 1 #define NV_DBG_WARN 2 -#define NV_DBG_INFO nv_info_debug_level +#define NV_DBG_INFO 3 #define NV_DBG_DEBUG 4 #define NV_DBG_TRACE 5 #define NV_DBG_PARANOIA 6 #define NV_DBG_SPAM 7 - -#define NV_DBG_INFO_NORMAL 3 -#define NV_DBG_INFO_SILENT NV_DBG_DEBUG - -#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h index 1bf2e8eb42688..e4bf2982c1902 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h @@ -19,8 +19,7 @@ static inline struct nvkm_engctx * nv_engctx(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS))) - nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_ENGCTX_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 441f843f24909..67e3afcbdd970 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -21,8 +21,7 @@ static inline struct nvkm_engine * nv_engine(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS))) - nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_ENGINE_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index e0187e7abb6ed..aa98520fa2657 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -24,8 +24,7 @@ static inline struct nvkm_gpuobj * nv_gpuobj(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS))) - nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_GPUOBJ_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h index 4cfe16fcde9b2..f880d66bb6e54 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h @@ -13,8 +13,7 @@ static inline struct nvkm_namedb * nv_namedb(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS))) - nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_NAMEDB_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 6e3cd3908400c..e546b0f09a2b6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -1,7 +1,7 @@ #ifndef __NVKM_OBJECT_H__ #define __NVKM_OBJECT_H__ #include -#include +#include #define NV_PARENT_CLASS 0x80000000 #define NV_NAMEDB_CLASS 0x40000000 @@ -32,8 +32,7 @@ nv_object(void *obj) #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA if (likely(obj)) { struct nvkm_object *object = obj; - if (unlikely(object->_magic != NVKM_OBJECT_MAGIC)) - nv_assert("BAD CAST -> NvObject, invalid magic"); + BUG_ON(object->_magic != NVKM_OBJECT_MAGIC); } #endif return obj; @@ -112,7 +111,6 @@ int nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *, void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **); int nvkm_object_inc(struct nvkm_object *); int nvkm_object_dec(struct nvkm_object *, bool suspend); -void nvkm_object_debug(void); static inline int nv_exec(void *obj, u32 mthd, void *data, u32 size) @@ -138,7 +136,6 @@ static inline u8 nv_ro08(void *obj, u64 addr) { u8 data = nv_ofuncs(obj)->rd08(obj, addr); - nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data); return data; } @@ -146,7 +143,6 @@ static inline u16 nv_ro16(void *obj, u64 addr) { u16 data = nv_ofuncs(obj)->rd16(obj, addr); - nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data); return data; } @@ -154,28 +150,24 @@ static inline u32 nv_ro32(void *obj, u64 addr) { u32 data = nv_ofuncs(obj)->rd32(obj, addr); - nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data); return data; } static inline void nv_wo08(void *obj, u64 addr, u8 data) { - nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data); nv_ofuncs(obj)->wr08(obj, addr, data); } static inline void nv_wo16(void *obj, u64 addr, u16 data) { - nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data); nv_ofuncs(obj)->wr16(obj, addr, data); } static inline void nv_wo32(void *obj, u64 addr, u32 data) { - nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data); nv_ofuncs(obj)->wr32(obj, addr, data); } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h index 837e4fe966a5a..57932131b601c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h @@ -27,8 +27,7 @@ static inline struct nvkm_parent * nv_parent(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS)))) - nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj)); + BUG_ON(!(nv_iclass(obj, NV_PARENT_CLASS))); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h b/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h deleted file mode 100644 index 83648177059f3..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef __NVKM_PRINTK_H__ -#define __NVKM_PRINTK_H__ -#include -#include -struct nvkm_object; - -void __printf(3, 4) -nv_printk_(struct nvkm_object *, int, const char *, ...); - -#define nv_printk(o,l,f,a...) do { \ - if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \ - nv_printk_(nv_object(o), NV_DBG_##l, f, ##a); \ -} while(0) - -#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a) -#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a) -#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a) -#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a) -#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a) -#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a) -#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a) -#define nv_ioctl(o,f,a...) nv_trace(nvkm_client(o), "ioctl: "f, ##a) - -#define nv_assert(f,a...) do { \ - if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \ - nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a); \ - BUG_ON(1); \ -} while(0) -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index e146f2758b079..8e762830902d1 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -22,8 +22,7 @@ static inline struct nvkm_subdev * nv_subdev(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS))) - nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_SUBDEV_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index f9812a9e8a8cf..d8941b7bebfca 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -14,8 +14,7 @@ static inline struct nvkm_instobj * nv_memobj(void *obj) { #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!nv_iclass(obj, NV_MEMOBJ_CLASS))) - nv_assert("BAD CAST -> NvMemObj, %08x", nv_hclass(obj)); + BUG_ON(!nv_iclass(obj, NV_MEMOBJ_CLASS)); #endif return obj; } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 89df4bf1e61be..4e6c1803fd37d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -538,7 +538,6 @@ nouveau_drm_device_remove(struct drm_device *dev) drm_put_dev(dev); nvkm_object_ref(NULL, &device); - nvkm_object_debug(); } static void @@ -731,7 +730,6 @@ nouveau_pmops_runtime_suspend(struct device *dev) return -EBUSY; } - nv_debug_level(SILENT); drm_kms_helper_poll_disable(drm_dev); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF); nouveau_switcheroo_optimus_dsm(); @@ -768,7 +766,6 @@ nouveau_pmops_runtime_resume(struct device *dev) nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; - nv_debug_level(NORMAL); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index a2bdb20691132..c4198164bc591 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -12,6 +12,5 @@ nvkm-y += nvkm/core/notify.o nvkm-y += nvkm/core/object.o nvkm-y += nvkm/core/option.o nvkm-y += nvkm/core/parent.o -nvkm-y += nvkm/core/printk.o nvkm-y += nvkm/core/ramht.o nvkm-y += nvkm/core/subdev.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 878a82f8f295e..0c7162fbe06c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -111,11 +111,11 @@ nvkm_client_notify_new(struct nvkm_object *object, if (!notify) return -ENOMEM; - nv_ioctl(client, "notify new size %d\n", size); + nvif_ioctl(object, "notify new size %d\n", size); if (nvif_unpack(req->v0, 0, 0, true)) { - nv_ioctl(client, "notify new vers %d reply %d route %02x " - "token %llx\n", req->v0.version, - req->v0.reply, req->v0.route, req->v0.token); + nvif_ioctl(object, "notify new vers %d reply %d route %02x " + "token %llx\n", req->v0.version, + req->v0.reply, req->v0.route, req->v0.token); notify->version = req->v0.version; notify->size = sizeof(notify->rep.v0); notify->rep.v0.version = req->v0.version; @@ -146,10 +146,10 @@ nvkm_client_mthd_devlist(struct nvkm_object *object, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "client devlist size %d\n", size); + nvif_ioctl(object, "client devlist size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "client devlist vers %d count %d\n", - args->v0.version, args->v0.count); + nvif_ioctl(object, "client devlist vers %d count %d\n", + args->v0.version, args->v0.count); if (size == sizeof(args->v0.device[0]) * args->v0.count) { ret = nvkm_device_list(args->v0.device, args->v0.count); if (ret >= 0) { @@ -233,25 +233,27 @@ nvkm_client_create_(const char *name, u64 devname, const char *cfg, int nvkm_client_init(struct nvkm_client *client) { + struct nvkm_object *object = &client->namedb.parent.object; int ret; - nv_debug(client, "init running\n"); + nvif_trace(object, "init running\n"); ret = nvkm_handle_init(client->root); - nv_debug(client, "init completed with %d\n", ret); + nvif_trace(object, "init completed with %d\n", ret); return ret; } int nvkm_client_fini(struct nvkm_client *client, bool suspend) { + struct nvkm_object *object = &client->namedb.parent.object; const char *name[2] = { "fini", "suspend" }; int ret, i; - nv_debug(client, "%s running\n", name[suspend]); - nv_debug(client, "%s notify\n", name[suspend]); + nvif_trace(object, "%s running\n", name[suspend]); + nvif_trace(object, "%s notify\n", name[suspend]); for (i = 0; i < ARRAY_SIZE(client->notify); i++) nvkm_client_notify_put(client, i); - nv_debug(client, "%s object\n", name[suspend]); + nvif_trace(object, "%s object\n", name[suspend]); ret = nvkm_handle_fini(client->root, suspend); - nv_debug(client, "%s completed with %d\n", name[suspend], ret); + nvif_trace(object, "%s completed with %d\n", name[suspend], ret); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c index fb2acbca75d96..fc2a2cb0a617f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c @@ -143,12 +143,12 @@ nvkm_engctx_init(struct nvkm_engctx *engctx) } if (ret) { - nv_error(parent, "failed to attach %s context, %d\n", - subdev->name, ret); + nvkm_error(pardev, "failed to attach %s context, %d\n", + subdev->name, ret); return ret; } - nv_debug(parent, "attached %s context\n", subdev->name); + nvkm_trace(pardev, "attached %s context\n", subdev->name); return 0; } @@ -170,12 +170,12 @@ nvkm_engctx_fini(struct nvkm_engctx *engctx, bool suspend) } if (ret) { - nv_error(parent, "failed to detach %s context, %d\n", - subdev->name, ret); + nvkm_error(pardev, "failed to detach %s context, %d\n", + subdev->name, ret); return ret; } - nv_debug(parent, "detached %s context\n", subdev->name); + nvkm_trace(pardev, "detached %s context\n", subdev->name); return nvkm_gpuobj_fini(&engctx->gpuobj, suspend); } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index 60820173c6aab..a6294e86d4676 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -55,16 +55,19 @@ nvkm_engine_create_(struct nvkm_object *parent, struct nvkm_object *engobj, if (device->disable_mask & (1ULL << engidx)) { if (!nvkm_boolopt(device->cfgopt, iname, false)) { - nv_debug(engine, "engine disabled by hw/fw\n"); + nvkm_debug(&engine->subdev, + "engine disabled by hw/fw\n"); return -ENODEV; } - nv_warn(engine, "ignoring hw/fw engine disable\n"); + nvkm_warn(&engine->subdev, + "ignoring hw/fw engine disable\n"); } if (!nvkm_boolopt(device->cfgopt, iname, enable)) { if (!enable) - nv_warn(engine, "disabled, %s=1 to enable\n", iname); + nvkm_warn(&engine->subdev, + "disabled, %s=1 to enable\n", iname); return -ENODEV; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index 2eba801aae6f2..c6e5f7a7f0052 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -69,10 +69,8 @@ nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, pargpu = pargpu->parent; } - if (unlikely(pargpu == NULL)) { - nv_error(parent, "no gpuobj heap\n"); + if (WARN_ON(pargpu == NULL)) return -EINVAL; - } addr = nv_gpuobj(pargpu)->addr; heap = &nv_gpuobj(pargpu)->heap; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index dc7ff10ebe7b5..6230eaece64d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -25,9 +25,8 @@ #include #define hprintk(h,l,f,a...) do { \ - struct nvkm_client *c = nvkm_client((h)->object); \ struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \ - nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \ + nvif_printk((h)->object, l, INFO, "0x%08x:0x%08x "f, n, (h)->name, ##a);\ } while(0) int diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 4459ff5f4cb8b..8a0d291d5f5f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -39,9 +39,9 @@ nvkm_ioctl_nop(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "nop size %d\n", size); + nvif_ioctl(object, "nop size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "nop\n"); + nvif_ioctl(object, "nop\n"); } return ret; @@ -57,14 +57,14 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) int ret; if (!nv_iclass(object, NV_PARENT_CLASS)) { - nv_debug(object, "cannot have children (sclass)\n"); + nvif_debug(object, "cannot have children (sclass)\n"); return -ENODEV; } - nv_ioctl(object, "sclass size %d\n", size); + nvif_ioctl(object, "sclass size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "sclass vers %d count %d\n", - args->v0.version, args->v0.count); + nvif_ioctl(object, "sclass vers %d count %d\n", + args->v0.version, args->v0.count); if (size == args->v0.count * sizeof(args->v0.oclass[0])) { ret = nvkm_parent_lclass(object, args->v0.oclass, args->v0.count); @@ -95,20 +95,20 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) u32 _handle, _oclass; int ret; - nv_ioctl(client, "new size %d\n", size); + nvif_ioctl(handle->object, "new size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { _handle = args->v0.handle; _oclass = args->v0.oclass; } else return ret; - nv_ioctl(client, "new vers %d handle %08x class %08x " - "route %02x token %llx\n", - args->v0.version, _handle, _oclass, - args->v0.route, args->v0.token); + nvif_ioctl(handle->object, "new vers %d handle %08x class %08x " + "route %02x token %llx\n", + args->v0.version, _handle, _oclass, + args->v0.route, args->v0.token); if (!nv_iclass(handle->object, NV_PARENT_CLASS)) { - nv_debug(handle->object, "cannot have children (ctor)\n"); + nvif_debug(handle->object, "cannot have children (ctor)\n"); ret = -ENODEV; goto fail_class; } @@ -118,7 +118,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) /* check that parent supports the requested subclass */ ret = nvkm_parent_sclass(&parent->object, _oclass, &engine, &oclass); if (ret) { - nv_debug(parent, "illegal class 0x%04x\n", _oclass); + nvif_debug(&parent->object, "illegal class 0x%04x\n", _oclass); goto fail_class; } @@ -188,9 +188,9 @@ nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "delete size %d\n", size); + nvif_ioctl(object, "delete size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "delete\n"); + nvif_ioctl(object, "delete\n"); nvkm_handle_fini(handle, false); nvkm_handle_destroy(handle); } @@ -208,10 +208,10 @@ nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "mthd size %d\n", size); + nvif_ioctl(object, "mthd size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "mthd vers %d mthd %02x\n", - args->v0.version, args->v0.method); + nvif_ioctl(object, "mthd vers %d mthd %02x\n", + args->v0.version, args->v0.method); if (ret = -ENODEV, ofuncs->mthd) ret = ofuncs->mthd(object, args->v0.method, data, size); } @@ -230,10 +230,10 @@ nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "rd size %d\n", size); + nvif_ioctl(object, "rd size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "rd vers %d size %d addr %016llx\n", - args->v0.version, args->v0.size, args->v0.addr); + nvif_ioctl(object, "rd vers %d size %d addr %016llx\n", + args->v0.version, args->v0.size, args->v0.addr); switch (args->v0.size) { case 1: if (ret = -ENODEV, ofuncs->rd08) { @@ -272,11 +272,12 @@ nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "wr size %d\n", size); + nvif_ioctl(object, "wr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n", - args->v0.version, args->v0.size, args->v0.addr, - args->v0.data); + nvif_ioctl(object, + "wr vers %d size %d addr %016llx data %08x\n", + args->v0.version, args->v0.size, args->v0.addr, + args->v0.data); switch (args->v0.size) { case 1: if (ret = -ENODEV, ofuncs->wr08) { @@ -315,9 +316,9 @@ nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "map size %d\n", size); + nvif_ioctl(object, "map size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "map vers %d\n", args->v0.version); + nvif_ioctl(object, "map vers %d\n", args->v0.version); if (ret = -ENODEV, ofuncs->map) { ret = ofuncs->map(object, &args->v0.handle, &args->v0.length); @@ -336,9 +337,9 @@ nvkm_ioctl_unmap(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "unmap size %d\n", size); + nvif_ioctl(object, "unmap size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "unmap\n"); + nvif_ioctl(object, "unmap\n"); } return ret; @@ -355,10 +356,10 @@ nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size) struct nvkm_event *event; int ret; - nv_ioctl(object, "ntfy new size %d\n", size); + nvif_ioctl(object, "ntfy new size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "ntfy new vers %d event %02x\n", - args->v0.version, args->v0.event); + nvif_ioctl(object, "ntfy new vers %d event %02x\n", + args->v0.version, args->v0.event); if (ret = -ENODEV, ofuncs->ntfy) ret = ofuncs->ntfy(object, args->v0.event, &event); if (ret == 0) { @@ -383,10 +384,10 @@ nvkm_ioctl_ntfy_del(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "ntfy del size %d\n", size); + nvif_ioctl(object, "ntfy del size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "ntfy del vers %d index %d\n", - args->v0.version, args->v0.index); + nvif_ioctl(object, "ntfy del vers %d index %d\n", + args->v0.version, args->v0.index); ret = nvkm_client_notify_del(client, args->v0.index); } @@ -403,10 +404,10 @@ nvkm_ioctl_ntfy_get(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "ntfy get size %d\n", size); + nvif_ioctl(object, "ntfy get size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "ntfy get vers %d index %d\n", - args->v0.version, args->v0.index); + nvif_ioctl(object, "ntfy get vers %d index %d\n", + args->v0.version, args->v0.index); ret = nvkm_client_notify_get(client, args->v0.index); } @@ -423,10 +424,10 @@ nvkm_ioctl_ntfy_put(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "ntfy put size %d\n", size); + nvif_ioctl(object, "ntfy put size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "ntfy put vers %d index %d\n", - args->v0.version, args->v0.index); + nvif_ioctl(object, "ntfy put vers %d index %d\n", + args->v0.version, args->v0.index); ret = nvkm_client_notify_put(client, args->v0.index); } @@ -463,15 +464,15 @@ nvkm_ioctl_path(struct nvkm_handle *parent, u32 type, u32 nr, u32 *path, int ret; while ((object = parent->object), nr--) { - nv_ioctl(object, "path 0x%08x\n", path[nr]); + nvif_ioctl(object, "path 0x%08x\n", path[nr]); if (!nv_iclass(object, NV_PARENT_CLASS)) { - nv_debug(object, "cannot have children (path)\n"); + nvif_debug(object, "cannot have children (path)\n"); return -EINVAL; } if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) || !(handle = nvkm_namedb_get(namedb, path[nr]))) { - nv_debug(object, "handle 0x%08x not found\n", path[nr]); + nvif_debug(object, "handle 0x%08x not found\n", path[nr]); return -ENOENT; } nvkm_namedb_put(handle); @@ -479,7 +480,7 @@ nvkm_ioctl_path(struct nvkm_handle *parent, u32 type, u32 nr, u32 *path, } if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != handle->route) { - nv_ioctl(object, "object route != owner\n"); + nvif_ioctl(object, "object route != owner\n"); return -EACCES; } *route = handle->route; @@ -497,25 +498,26 @@ int nvkm_ioctl(struct nvkm_client *client, bool supervisor, void *data, u32 size, void **hack) { + struct nvkm_object *object = &client->namedb.parent.object; union { struct nvif_ioctl_v0 v0; } *args = data; int ret; client->super = supervisor; - nv_ioctl(client, "size %d\n", size); + nvif_ioctl(object, "size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(client, "vers %d type %02x path %d owner %02x\n", - args->v0.version, args->v0.type, args->v0.path_nr, - args->v0.owner); + nvif_ioctl(object, "vers %d type %02x path %d owner %02x\n", + args->v0.version, args->v0.type, args->v0.path_nr, + args->v0.owner); ret = nvkm_ioctl_path(client->root, args->v0.type, args->v0.path_nr, args->v0.path, data, size, args->v0.owner, &args->v0.route, &args->v0.token); } - nv_ioctl(client, "return %d\n", ret); + nvif_ioctl(object, "return %d\n", ret); if (hack) { *hack = client->data; client->data = NULL; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index 979f3627d395f..b690a3898732e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -24,11 +24,6 @@ #include #include -#ifdef NVKM_OBJECT_MAGIC -static struct list_head _objlist = LIST_HEAD_INIT(_objlist); -static DEFINE_SPINLOCK(_objlist_lock); -#endif - int nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 pclass, @@ -49,9 +44,6 @@ nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, #ifdef NVKM_OBJECT_MAGIC object->_magic = NVKM_OBJECT_MAGIC; - spin_lock(&_objlist_lock); - list_add(&object->list, &_objlist); - spin_unlock(&_objlist_lock); #endif return 0; } @@ -69,11 +61,6 @@ _nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, void nvkm_object_destroy(struct nvkm_object *object) { -#ifdef NVKM_OBJECT_MAGIC - spin_lock(&_objlist_lock); - list_del(&object->list); - spin_unlock(&_objlist_lock); -#endif nvkm_object_ref(NULL, (struct nvkm_object **)&object->engine); nvkm_object_ref(NULL, &object->parent); kfree(object); @@ -111,11 +98,6 @@ nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ret = ofuncs->ctor(parent, engine, oclass, data, size, &object); *pobject = object; if (ret < 0) { - if (ret != -ENODEV) { - nv_error(parent, "failed to create 0x%08x, %d\n", - oclass->handle, ret); - } - if (object) { ofuncs->dtor(object); *pobject = NULL; @@ -125,7 +107,6 @@ nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } if (ret == 0) { - nv_trace(object, "created\n"); atomic_set(&object->refcount, 1); } @@ -135,7 +116,6 @@ nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, static void nvkm_object_dtor(struct nvkm_object *object) { - nv_trace(object, "destroying\n"); nv_ofuncs(object)->dtor(object); } @@ -144,12 +124,10 @@ nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref) { if (obj) { atomic_inc(&obj->refcount); - nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount)); } if (*ref) { int dead = atomic_dec_and_test(&(*ref)->refcount); - nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount)); if (dead) nvkm_object_dtor(*ref); } @@ -163,37 +141,28 @@ nvkm_object_inc(struct nvkm_object *object) int ref = atomic_add_return(1, &object->usecount); int ret; - nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount)); if (ref != 1) return 0; - nv_trace(object, "initialising...\n"); if (object->parent) { ret = nvkm_object_inc(object->parent); - if (ret) { - nv_error(object, "parent failed, %d\n", ret); + if (ret) goto fail_parent; - } } if (object->engine) { mutex_lock(&nv_subdev(object->engine)->mutex); ret = nvkm_object_inc(&object->engine->subdev.object); mutex_unlock(&nv_subdev(object->engine)->mutex); - if (ret) { - nv_error(object, "engine failed, %d\n", ret); + if (ret) goto fail_engine; - } } ret = nv_ofuncs(object)->init(object); atomic_set(&object->usecount, 1); - if (ret) { - nv_error(object, "init failed, %d\n", ret); + if (ret) goto fail_self; - } - nv_trace(object, "initialised\n"); return 0; fail_self: @@ -213,14 +182,8 @@ fail_parent: static int nvkm_object_decf(struct nvkm_object *object) { - int ret; - - nv_trace(object, "stopping...\n"); - - ret = nv_ofuncs(object)->fini(object, false); + nv_ofuncs(object)->fini(object, false); atomic_set(&object->usecount, 0); - if (ret) - nv_warn(object, "failed fini, %d\n", ret); if (object->engine) { mutex_lock(&nv_subdev(object->engine)->mutex); @@ -231,58 +194,44 @@ nvkm_object_decf(struct nvkm_object *object) if (object->parent) nvkm_object_dec(object->parent, false); - nv_trace(object, "stopped\n"); return 0; } static int nvkm_object_decs(struct nvkm_object *object) { - int ret, rret; - - nv_trace(object, "suspending...\n"); + int ret; ret = nv_ofuncs(object)->fini(object, true); atomic_set(&object->usecount, 0); - if (ret) { - nv_error(object, "failed suspend, %d\n", ret); + if (ret) return ret; - } if (object->engine) { mutex_lock(&nv_subdev(object->engine)->mutex); ret = nvkm_object_dec(&object->engine->subdev.object, true); mutex_unlock(&nv_subdev(object->engine)->mutex); - if (ret) { - nv_warn(object, "engine failed suspend, %d\n", ret); + if (ret) goto fail_engine; - } } if (object->parent) { ret = nvkm_object_dec(object->parent, true); - if (ret) { - nv_warn(object, "parent failed suspend, %d\n", ret); + if (ret) goto fail_parent; - } } - nv_trace(object, "suspended\n"); return 0; fail_parent: if (object->engine) { mutex_lock(&nv_subdev(object->engine)->mutex); - rret = nvkm_object_inc(&object->engine->subdev.object); + nvkm_object_inc(&object->engine->subdev.object); mutex_unlock(&nv_subdev(object->engine)->mutex); - if (rret) - nv_fatal(object, "engine failed to reinit, %d\n", rret); } fail_engine: - rret = nv_ofuncs(object)->init(object); - if (rret) - nv_fatal(object, "failed to reinit, %d\n", rret); + nv_ofuncs(object)->init(object); return ret; } @@ -293,8 +242,6 @@ nvkm_object_dec(struct nvkm_object *object, bool suspend) int ref = atomic_add_return(-1, &object->usecount); int ret; - nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount)); - if (ref == 0) { if (suspend) ret = nvkm_object_decs(object); @@ -309,22 +256,3 @@ nvkm_object_dec(struct nvkm_object *object, bool suspend) return 0; } - -void -nvkm_object_debug(void) -{ -#ifdef NVKM_OBJECT_MAGIC - struct nvkm_object *object; - if (!list_empty(&_objlist)) { - nv_fatal(NULL, "*******************************************\n"); - nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n"); - nv_fatal(NULL, "*******************************************\n"); - list_for_each_entry(object, &_objlist, list) { - nv_fatal(object, "%p/%p/%d/%d\n", - object->parent, object->engine, - atomic_read(&object->refcount), - atomic_read(&object->usecount)); - } - } -#endif -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/option.c b/drivers/gpu/drm/nouveau/nvkm/core/option.c index 19d153f8c8fd4..98ebde3b72698 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/option.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/option.c @@ -95,7 +95,7 @@ nvkm_dbgopt(const char *optstr, const char *sub) else if (!strncasecmpz(optstr, "warn", len)) level = NV_DBG_WARN; else if (!strncasecmpz(optstr, "info", len)) - level = NV_DBG_INFO_NORMAL; + level = NV_DBG_INFO; else if (!strncasecmpz(optstr, "debug", len)) level = NV_DBG_DEBUG; else if (!strncasecmpz(optstr, "trace", len)) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/printk.c b/drivers/gpu/drm/nouveau/nvkm/core/printk.c deleted file mode 100644 index 4a220eb916605..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/core/printk.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include -#include -#include - -int nv_info_debug_level = NV_DBG_INFO_NORMAL; - -void -nv_printk_(struct nvkm_object *object, int level, const char *fmt, ...) -{ - static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' }; - const char *pfx; - char mfmt[256]; - va_list args; - - switch (level) { - case NV_DBG_FATAL: - pfx = KERN_CRIT; - break; - case NV_DBG_ERROR: - pfx = KERN_ERR; - break; - case NV_DBG_WARN: - pfx = KERN_WARNING; - break; - case NV_DBG_INFO_NORMAL: - pfx = KERN_INFO; - break; - case NV_DBG_DEBUG: - case NV_DBG_PARANOIA: - case NV_DBG_TRACE: - case NV_DBG_SPAM: - default: - pfx = KERN_DEBUG; - break; - } - - if (object && !nv_iclass(object, NV_CLIENT_CLASS)) { - struct nvkm_object *device; - struct nvkm_object *subdev; - char obuf[64], *ofmt = ""; - - if (object->engine == NULL) { - subdev = object; - while (subdev && !nv_iclass(subdev, NV_SUBDEV_CLASS)) - subdev = subdev->parent; - } else { - subdev = &object->engine->subdev.object; - } - - device = subdev; - if (device->parent) - device = device->parent; - - if (object != subdev) { - snprintf(obuf, sizeof(obuf), "[0x%08x]", - nv_hclass(object)); - ofmt = obuf; - } - - if (level > nv_subdev(subdev)->debug) - return; - - snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx, - name[level], nv_subdev(subdev)->name, - nv_device(device)->name, ofmt, fmt); - } else - if (object && nv_iclass(object, NV_CLIENT_CLASS)) { - if (level > nv_client(object)->debug) - return; - - snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx, - name[level], nv_client(object)->name, fmt); - } else { - snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt); - } - - va_start(args, fmt); - vprintk(mfmt, args); - va_end(args); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 476add5a4aea2..da5ed8c109d9e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -37,11 +37,12 @@ nvkm_subdev(void *obj, int idx) } void -nvkm_subdev_reset(struct nvkm_object *subdev) +nvkm_subdev_reset(struct nvkm_object *obj) { - nv_trace(subdev, "resetting...\n"); - nv_ofuncs(subdev)->fini(subdev, false); - nv_debug(subdev, "reset\n"); + struct nvkm_subdev *subdev = container_of(obj, typeof(*subdev), object); + nvkm_trace(subdev, "resetting...\n"); + nv_ofuncs(subdev)->fini(&subdev->object, false); + nvkm_trace(subdev, "reset\n"); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index c58ea4f44c702..af8f9ccdc8f6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -87,9 +87,9 @@ nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size) } *args = data; int ret; - nv_ioctl(object, "device info size %d\n", size); + nvif_ioctl(object, "device info size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "device info vers %d\n", args->v0.version); + nvif_ioctl(object, "device info vers %d\n", args->v0.version); } else return ret; @@ -294,12 +294,12 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, void __iomem *map; int ret, i, c; - nv_ioctl(parent, "create device size %d\n", size); + nvif_ioctl(parent, "create device size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create device v%d device %016llx " - "disable %016llx debug0 %016llx\n", - args->v0.version, args->v0.device, - args->v0.disable, args->v0.debug0); + nvif_ioctl(parent, "create device v%d device %016llx " + "disable %016llx debug0 %016llx\n", + args->v0.version, args->v0.device, + args->v0.disable, args->v0.debug0); } else return ret; @@ -567,8 +567,7 @@ nv_device(void *obj) device = device->parent; } #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (unlikely(!device)) - nv_assert("BAD CAST -> NvDevice, 0x%08x\n", nv_hclass(obj)); + BUG_ON(!device); #endif return (void *)device; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c index 0b794b13cec3f..c13cd9d46a1ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c @@ -39,10 +39,10 @@ nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size) struct nvkm_clk *clk = nvkm_clk(object); int ret; - nv_ioctl(object, "control pstate info size %d\n", size); + nvif_ioctl(object, "control pstate info size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "control pstate info vers %d\n", - args->v0.version); + nvif_ioctl(object, "control pstate info vers %d\n", + args->v0.version); } else return ret; @@ -77,11 +77,11 @@ nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) u32 lo, hi; int ret; - nv_ioctl(object, "control pstate attr size %d\n", size); + nvif_ioctl(object, "control pstate attr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "control pstate attr vers %d state %d " - "index %d\n", - args->v0.version, args->v0.state, args->v0.index); + nvif_ioctl(object, "control pstate attr vers %d state %d " + "index %d\n", + args->v0.version, args->v0.state, args->v0.index); if (!clk) return -ENODEV; if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) @@ -145,11 +145,11 @@ nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size) struct nvkm_clk *clk = nvkm_clk(object); int ret; - nv_ioctl(object, "control pstate user size %d\n", size); + nvif_ioctl(object, "control pstate user size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "control pstate user vers %d ustate %d " - "pwrsrc %d\n", args->v0.version, - args->v0.ustate, args->v0.pwrsrc); + nvif_ioctl(object, "control pstate user vers %d ustate %d " + "pwrsrc %d\n", args->v0.version, + args->v0.ustate, args->v0.pwrsrc); if (!clk) return -ENODEV; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index e88f5f2f87e7d..ddd4144bee478 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -41,12 +41,12 @@ nv50_dac_power(NV50_DISP_MTHD_V1) u32 stat; int ret; - nv_ioctl(object, "disp dac pwr size %d\n", size); + nvif_ioctl(object, "disp dac pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp dac pwr vers %d state %d data %d " - "vsync %d hsync %d\n", - args->v0.version, args->v0.state, args->v0.data, - args->v0.vsync, args->v0.hsync); + nvif_ioctl(object, "disp dac pwr vers %d state %d data %d " + "vsync %d hsync %d\n", + args->v0.version, args->v0.state, args->v0.data, + args->v0.vsync, args->v0.hsync); stat = 0x00000040 * !args->v0.state; stat |= 0x00000010 * !args->v0.data; stat |= 0x00000004 * !args->v0.vsync; @@ -78,10 +78,10 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) u32 loadval; int ret; - nv_ioctl(object, "disp dac load size %d\n", size); + nvif_ioctl(object, "disp dac load size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp dac load vers %d data %08x\n", - args->v0.version, args->v0.data); + nvif_ioctl(object, "disp dac load vers %d data %08x\n", + args->v0.version, args->v0.data); if (args->v0.data & 0xfff00000) return -EINVAL; loadval = args->v0.data; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index ef16d92cb7a30..bf729966d6a2b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -669,9 +669,10 @@ gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) } *args = data; int ret; - nv_ioctl(object, "disp scanoutpos size %d\n", size); + nvif_ioctl(object, "disp scanoutpos size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); args->v0.vblanke = (blanke & 0xffff0000) >> 16; args->v0.hblanke = (blanke & 0x0000ffff); args->v0.vblanks = (blanks & 0xffff0000) >> 16; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c index 2d8f68792d802..3e940dd0fc2fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c @@ -43,9 +43,10 @@ gf110_hda_eld(NV50_DISP_MTHD_V1) const u32 hoff = head * 0x800; int ret, i; - nv_ioctl(object, "disp sor hda eld size %d\n", size); + nvif_ioctl(object, "disp sor hda eld size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version); + nvif_ioctl(object, "disp sor hda eld vers %d\n", + args->v0.version); if (size > 0x60) return -E2BIG; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c index 0aba48c586ee7..c1590b746f134 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c @@ -40,9 +40,10 @@ gt215_hda_eld(NV50_DISP_MTHD_V1) const u32 soff = outp->or * 0x800; int ret, i; - nv_ioctl(object, "disp sor hda eld size %d\n", size); + nvif_ioctl(object, "disp sor hda eld size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version); + nvif_ioctl(object, "disp sor hda eld vers %d\n", + args->v0.version); if (size > 0x60) return -E2BIG; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c index da7f001f918c6..ee9e800a8f06c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c @@ -39,12 +39,12 @@ g84_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c index 1a474be0504b8..fea4d11a49e56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c @@ -39,12 +39,12 @@ gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c index b1a69bd93d964..110dc19e4f672 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c @@ -40,12 +40,12 @@ gk104_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c index 353dde956fd15..61237dbfa35a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c @@ -40,12 +40,12 @@ gt215_hdmi_ctrl(NV50_DISP_MTHD_V1) u32 ctrl; int ret; - nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size); + nvif_ioctl(object, "disp sor hdmi ctrl size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d " - "max_ac_packet %d rekey %d\n", - args->v0.version, args->v0.state, - args->v0.max_ac_packet, args->v0.rekey); + nvif_ioctl(object, "disp sor hdmi ctrl vers %d state %d " + "max_ac_packet %d rekey %d\n", + args->v0.version, args->v0.state, + args->v0.max_ac_packet, args->v0.rekey); if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f) return -EINVAL; ctrl = 0x40000000 * !!args->v0.state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 3a7ec28aea7c3..d6c0cf0e5a35b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -40,9 +40,10 @@ nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, u32 line; int ret; - nv_ioctl(object, "disp scanoutpos size %d\n", size); + nvif_ioctl(object, "disp scanoutpos size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff; args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff; args->v0.vblanke = args->v0.vtotal - 1; @@ -79,10 +80,10 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) struct nvkm_disp *disp = (void *)object->engine; int head, ret; - nv_ioctl(object, "disp mthd size %d\n", size); + nvif_ioctl(object, "disp mthd size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); + nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); mthd = args->v0.method; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index f485d78290042..b07cb0626e873 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -510,11 +510,11 @@ nv50_disp_core_ctor(struct nvkm_object *parent, struct nv50_disp_dmac *mast; int ret; - nv_ioctl(parent, "create disp core channel dma size %d\n", size); + nvif_ioctl(parent, "create disp core channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp core channel dma vers %d " - "pushbuf %08x\n", - args->v0.version, args->v0.pushbuf); + nvif_ioctl(parent, "create disp core channel dma vers %d " + "pushbuf %08x\n", + args->v0.version, args->v0.pushbuf); } else return ret; @@ -679,11 +679,11 @@ nv50_disp_base_ctor(struct nvkm_object *parent, struct nv50_disp_dmac *dmac; int ret; - nv_ioctl(parent, "create disp base channel dma size %d\n", size); + nvif_ioctl(parent, "create disp base channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp base channel dma vers %d " - "pushbuf %08x head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); + nvif_ioctl(parent, "create disp base channel dma vers %d " + "pushbuf %08x head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; } else @@ -769,11 +769,11 @@ nv50_disp_ovly_ctor(struct nvkm_object *parent, struct nv50_disp_dmac *dmac; int ret; - nv_ioctl(parent, "create disp overlay channel dma size %d\n", size); + nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp overlay channel dma vers %d " - "pushbuf %08x head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); + nvif_ioctl(parent, "create disp overlay channel dma vers %d " + "pushbuf %08x head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; } else @@ -903,10 +903,10 @@ nv50_disp_oimm_ctor(struct nvkm_object *parent, struct nv50_disp_pioc *pioc; int ret; - nv_ioctl(parent, "create disp overlay size %d\n", size); + nvif_ioctl(parent, "create disp overlay size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp overlay vers %d head %d\n", - args->v0.version, args->v0.head); + nvif_ioctl(parent, "create disp overlay vers %d head %d\n", + args->v0.version, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; } else @@ -951,10 +951,10 @@ nv50_disp_curs_ctor(struct nvkm_object *parent, struct nv50_disp_pioc *pioc; int ret; - nv_ioctl(parent, "create disp cursor size %d\n", size); + nvif_ioctl(parent, "create disp cursor size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create disp cursor vers %d head %d\n", - args->v0.version, args->v0.head); + nvif_ioctl(parent, "create disp cursor vers %d head %d\n", + args->v0.version, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; } else @@ -998,9 +998,10 @@ nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) } *args = data; int ret; - nv_ioctl(object, "disp scanoutpos size %d\n", size); + nvif_ioctl(object, "disp scanoutpos size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version); + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); args->v0.vblanke = (blanke & 0xffff0000) >> 16; args->v0.hblanke = (blanke & 0x0000ffff); args->v0.vblanks = (blanks & 0xffff0000) >> 16; @@ -1036,18 +1037,18 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) if (mthd != NV50_DISP_MTHD) return -EINVAL; - nv_ioctl(object, "disp mthd size %d\n", size); + nvif_ioctl(object, "disp mthd size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); + nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); mthd = args->v0.method; head = args->v0.head; } else if (nvif_unpack(args->v1, 1, 1, true)) { - nv_ioctl(object, "disp mthd vers %d mthd %02x " - "type %04x mask %04x\n", - args->v1.version, args->v1.method, - args->v1.hasht, args->v1.hashm); + nvif_ioctl(object, "disp mthd vers %d mthd %02x " + "type %04x mask %04x\n", + args->v1.version, args->v1.method, + args->v1.hasht, args->v1.hashm); mthd = args->v1.method; type = args->v1.hasht; mask = args->v1.hashm; @@ -1096,11 +1097,11 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) union { struct nv50_disp_sor_lvds_script_v0 v0; } *args = data; - nv_ioctl(object, "disp sor lvds script size %d\n", size); + nvif_ioctl(object, "disp sor lvds script size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor lvds script " - "vers %d name %04x\n", - args->v0.version, args->v0.script); + nvif_ioctl(object, "disp sor lvds script " + "vers %d name %04x\n", + args->v0.version, args->v0.script); disp->sor.lvdsconf = args->v0.script; return 0; } else @@ -1112,10 +1113,10 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) union { struct nv50_disp_sor_dp_pwr_v0 v0; } *args = data; - nv_ioctl(object, "disp sor dp pwr size %d\n", size); + nvif_ioctl(object, "disp sor dp pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor dp pwr vers %d state %d\n", - args->v0.version, args->v0.state); + nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n", + args->v0.version, args->v0.state); if (args->v0.state == 0) { nvkm_notify_put(&outpdp->irq); ((struct nvkm_output_dp_impl *)nv_oclass(outp)) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index ac0dd18b98c18..406ba2f493b35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -152,10 +152,10 @@ nv50_pior_power(NV50_DISP_MTHD_V1) u32 ctrl, type; int ret; - nv_ioctl(object, "disp pior pwr size %d\n", size); + nvif_ioctl(object, "disp pior pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); + nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", + args->v0.version, args->v0.state, args->v0.type); if (args->v0.type > 0x0f) return -EINVAL; ctrl = !!args->v0.state; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 6cb60572eaa5b..73ee036c134da 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -41,10 +41,10 @@ nv50_sor_power(NV50_DISP_MTHD_V1) u32 stat; int ret; - nv_ioctl(object, "disp sor pwr size %d\n", size); + nvif_ioctl(object, "disp sor pwr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "disp sor pwr vers %d state %d\n", - args->v0.version, args->v0.state); + nvif_ioctl(object, "disp sor pwr vers %d state %d\n", + args->v0.version, args->v0.state); stat = !!args->v0.state; } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c index b6572f1b69810..f9f38ee49058d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c @@ -75,12 +75,12 @@ nvkm_dmaobj_create_(struct nvkm_object *parent, if (ret) return ret; - nv_ioctl(parent, "create dma size %d\n", *psize); + nvif_ioctl(parent, "create dma size %d\n", *psize); if (nvif_unpack(args->v0, 0, 0, true)) { - nv_ioctl(parent, "create dma vers %d target %d access %d " - "start %016llx limit %016llx\n", - args->v0.version, args->v0.target, args->v0.access, - args->v0.start, args->v0.limit); + nvif_ioctl(parent, "create dma vers %d target %d access %d " + "start %016llx limit %016llx\n", + args->v0.version, args->v0.target, args->v0.access, + args->v0.start, args->v0.limit); dmaobj->target = args->v0.target; dmaobj->access = args->v0.access; dmaobj->start = args->v0.start; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c index db7978ac6acbb..f5dc4f23a1b47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c @@ -88,10 +88,11 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; args = data; - nv_ioctl(parent, "create gf100 dma size %d\n", size); + nvif_ioctl(parent, "create gf100 dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n", - args->v0.version, args->v0.priv, args->v0.kind); + nvif_ioctl(parent, + "create gf100 dma vers %d priv %d kind %02x\n", + args->v0.version, args->v0.priv, args->v0.kind); kind = args->v0.kind; user = args->v0.priv; unkn = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c index 76063249853c1..a3ea461f7f326 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c @@ -93,10 +93,11 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; args = data; - nv_ioctl(parent, "create gf110 dma size %d\n", size); + nvif_ioctl(parent, "create gf110 dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n", - args->v0.version, args->v0.page, args->v0.kind); + nvif_ioctl(parent, + "create gf100 dma vers %d page %d kind %02x\n", + args->v0.version, args->v0.page, args->v0.kind); kind = args->v0.kind; page = args->v0.page; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c index 6aa18884184ee..ba95f549463f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c @@ -100,12 +100,12 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; args = data; - nv_ioctl(parent, "create nv50 dma size %d\n", size); + nvif_ioctl(parent, "create nv50 dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d " - "comp %d kind %02x\n", args->v0.version, - args->v0.priv, args->v0.part, args->v0.comp, - args->v0.kind); + nvif_ioctl(parent, "create nv50 dma vers %d priv %d part %d " + "comp %d kind %02x\n", args->v0.version, + args->v0.priv, args->v0.part, args->v0.comp, + args->v0.kind); user = args->v0.priv; part = args->v0.part; comp = args->v0.comp; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 5667e695ac516..9024dc893218b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -176,11 +176,11 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, struct nv50_fifo_chan *chan; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); + nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); + nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); } else return ret; @@ -250,12 +250,12 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, u64 ioffset, ilength; int ret; - nv_ioctl(parent, "create channel gpfifo size %d\n", size); + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index e438e9fee2066..b043d08a35c9a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -199,12 +199,12 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, u64 usermem, ioffset, ilength; int ret, i; - nv_ioctl(parent, "create channel gpfifo size %d\n", size); + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 258a1deb11056..ce12e4e12b220 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -240,12 +240,12 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, u64 usermem, ioffset, ilength; int ret, i; - nv_ioctl(parent, "create channel gpfifo size %d\n", size); + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x engine %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength, args->v0.engine); + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x engine %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength, args->v0.engine); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 61de6fded74bc..5eca5de292f6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -118,11 +118,11 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, struct nv04_fifo_chan *chan; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); + nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); + nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 7c31c31edd9a1..2c38d6f36fe73 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -62,11 +62,11 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, struct nv04_fifo_chan *chan; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); + nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); + nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 6a57df6f78c44..55857665180c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -67,11 +67,11 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, struct nv04_fifo_chan *chan; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); + nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); + nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 7f9eb1018814f..b6c7af527d6ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -186,11 +186,11 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nv04_fifo_chan *chan; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); + nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); + nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 41509256bb2e1..920b3c91b9edf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -204,11 +204,11 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, struct nv50_fifo_chan *chan; int ret; - nv_ioctl(parent, "create channel dma size %d\n", size); + nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel dma vers %d pushbuf %08x " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); + nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + "offset %016llx\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); } else return ret; @@ -266,12 +266,12 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, u64 ioffset, ilength; int ret; - nv_ioctl(parent, "create channel gpfifo size %d\n", size); + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.ilength); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 365cd823d6bb2..ba1623de8bcb9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -212,9 +212,9 @@ nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) struct nvkm_perfdom *dom = (void *)object; int ret, i; - nv_ioctl(object, "perfdom init size %d\n", size); + nvif_ioctl(object, "perfdom init size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "perfdom init\n"); + nvif_ioctl(object, "perfdom init\n"); } else return ret; @@ -242,9 +242,9 @@ nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size) struct nvkm_perfdom *dom; int ret; - nv_ioctl(object, "perfdom sample size %d\n", size); + nvif_ioctl(object, "perfdom sample size %d\n", size); if (nvif_unvers(args->none)) { - nv_ioctl(object, "perfdom sample\n"); + nvif_ioctl(object, "perfdom sample\n"); } else return ret; pm->sequence++; @@ -266,9 +266,9 @@ nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size) struct nvkm_perfdom *dom = (void *)object; int ret, i; - nv_ioctl(object, "perfdom read size %d\n", size); + nvif_ioctl(object, "perfdom read size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfdom read vers %d\n", args->v0.version); + nvif_ioctl(object, "perfdom read vers %d\n", args->v0.version); } else return ret; @@ -367,10 +367,10 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int c, s, m; int ret; - nv_ioctl(parent, "create perfdom size %d\n", size); + nvif_ioctl(parent, "create perfdom size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n", - args->v0.version, args->v0.domain, args->v0.mode); + nvif_ioctl(parent, "create perfdom vers %d dom %d mode %02x\n", + args->v0.version, args->v0.domain, args->v0.mode); } else return ret; @@ -438,10 +438,10 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) u8 domain_nr; int di, ret; - nv_ioctl(object, "perfmon query domain size %d\n", size); + nvif_ioctl(object, "perfmon query domain size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, "perfmon domain vers %d iter %02x\n", - args->v0.version, args->v0.iter); + nvif_ioctl(object, "perfmon domain vers %d iter %02x\n", + args->v0.version, args->v0.iter); di = (args->v0.iter & 0xff) - 1; } else return ret; @@ -487,11 +487,11 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all); int ret, si; - nv_ioctl(object, "perfmon query signal size %d\n", size); + nvif_ioctl(object, "perfmon query signal size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, - "perfmon query signal vers %d dom %d iter %04x\n", - args->v0.version, args->v0.domain, args->v0.iter); + nvif_ioctl(object, + "perfmon query signal vers %d dom %d iter %04x\n", + args->v0.version, args->v0.domain, args->v0.iter); si = (args->v0.iter & 0xffff) - 1; } else return ret; @@ -538,12 +538,12 @@ nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) u8 source_nr = 0; int si, ret; - nv_ioctl(object, "perfmon query source size %d\n", size); + nvif_ioctl(object, "perfmon query source size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nv_ioctl(object, - "perfmon source vers %d dom %d sig %02x iter %02x\n", - args->v0.version, args->v0.domain, args->v0.signal, - args->v0.iter); + nvif_ioctl(object, + "perfmon source vers %d dom %d sig %02x iter %02x\n", + args->v0.version, args->v0.domain, args->v0.signal, + args->v0.iter); si = (args->v0.iter & 0xff) - 1; } else return ret; -- GitLab From 7f5f518fd70b1b72ca4cf8249ca3306846383ed4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5439/7006] drm/nouveau/bios: remove object accessor functions Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/object.h | 14 - .../drm/nouveau/include/nvkm/subdev/bios.h | 5 + .../nouveau/include/nvkm/subdev/bios/bmp.h | 10 +- .../gpu/drm/nouveau/nvkm/engine/disp/dport.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/bios/M0203.c | 20 +- .../gpu/drm/nouveau/nvkm/subdev/bios/M0205.c | 20 +- .../gpu/drm/nouveau/nvkm/subdev/bios/M0209.c | 26 +- .../gpu/drm/nouveau/nvkm/subdev/bios/P0260.c | 14 +- .../gpu/drm/nouveau/nvkm/subdev/bios/base.c | 80 +--- .../gpu/drm/nouveau/nvkm/subdev/bios/bit.c | 14 +- .../gpu/drm/nouveau/nvkm/subdev/bios/boost.c | 28 +- .../gpu/drm/nouveau/nvkm/subdev/bios/conn.c | 30 +- .../gpu/drm/nouveau/nvkm/subdev/bios/cstep.c | 26 +- .../gpu/drm/nouveau/nvkm/subdev/bios/dcb.c | 32 +- .../gpu/drm/nouveau/nvkm/subdev/bios/disp.c | 36 +- drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c | 78 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/extdev.c | 16 +- .../gpu/drm/nouveau/nvkm/subdev/bios/fan.c | 18 +- .../gpu/drm/nouveau/nvkm/subdev/bios/gpio.c | 30 +- .../gpu/drm/nouveau/nvkm/subdev/bios/i2c.c | 48 +- .../gpu/drm/nouveau/nvkm/subdev/bios/image.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 416 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/bios/mxm.c | 20 +- .../gpu/drm/nouveau/nvkm/subdev/bios/npde.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/bios/pcir.c | 28 +- .../gpu/drm/nouveau/nvkm/subdev/bios/perf.c | 88 ++-- .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 150 +++---- .../gpu/drm/nouveau/nvkm/subdev/bios/pmu.c | 34 +- .../gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c | 10 +- .../gpu/drm/nouveau/nvkm/subdev/bios/rammap.c | 180 ++++---- .../gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 82 +--- .../gpu/drm/nouveau/nvkm/subdev/bios/therm.c | 28 +- .../gpu/drm/nouveau/nvkm/subdev/bios/timing.c | 98 ++--- .../gpu/drm/nouveau/nvkm/subdev/bios/vmap.c | 40 +- .../gpu/drm/nouveau/nvkm/subdev/bios/volt.c | 52 +-- .../gpu/drm/nouveau/nvkm/subdev/bios/xpio.c | 26 +- .../drm/nouveau/nvkm/subdev/devinit/gm204.c | 12 +- .../drm/nouveau/nvkm/subdev/devinit/nv05.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 2 +- 45 files changed, 881 insertions(+), 970 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index e546b0f09a2b6..696fb62e8a0ac 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -178,18 +178,4 @@ nv_mo32(void *obj, u64 addr, u32 mask, u32 data) nv_wo32(obj, addr, (temp & ~mask) | data); return temp; } - -static inline int -nv_memcmp(void *obj, u32 addr, const char *str, u32 len) -{ - unsigned char c1, c2; - - while (len--) { - c1 = nv_ro08(obj, addr++); - c2 = *(str++); - if (c1 != c2) - return c1 - c2; - } - return 0; -} #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h index 0b102c8f69c8f..28600390c6b82 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h @@ -27,6 +27,11 @@ nvkm_bios(void *obj) u8 nvbios_checksum(const u8 *data, int size); u16 nvbios_findstr(const u8 *data, int size, const char *str, int len); +int nvbios_memcmp(struct nvkm_bios *, u32 addr, const char *, u32 len); + +#define nvbios_rd08(b,o) (b)->data[(o)] +#define nvbios_rd16(b,o) get_unaligned_le16(&(b)->data[(o)]) +#define nvbios_rd32(b,o) get_unaligned_le32(&(b)->data[(o)]) extern struct nvkm_oclass nvkm_bios_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h index 4107aa546a21d..3f0c7c4140260 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h @@ -4,8 +4,8 @@ static inline u16 bmp_version(struct nvkm_bios *bios) { if (bios->bmp_offset) { - return nv_ro08(bios, bios->bmp_offset + 5) << 8 | - nv_ro08(bios, bios->bmp_offset + 6); + return nvbios_rd08(bios, bios->bmp_offset + 5) << 8 | + nvbios_rd08(bios, bios->bmp_offset + 6); } return 0x0000; @@ -15,7 +15,7 @@ static inline u16 bmp_mem_init_table(struct nvkm_bios *bios) { if (bmp_version(bios) >= 0x0300) - return nv_ro16(bios, bios->bmp_offset + 24); + return nvbios_rd16(bios, bios->bmp_offset + 24); return 0x0000; } @@ -23,7 +23,7 @@ static inline u16 bmp_sdr_seq_table(struct nvkm_bios *bios) { if (bmp_version(bios) >= 0x0300) - return nv_ro16(bios, bios->bmp_offset + 26); + return nvbios_rd16(bios, bios->bmp_offset + 26); return 0x0000; } @@ -31,7 +31,7 @@ static inline u16 bmp_ddr_seq_table(struct nvkm_bios *bios) { if (bmp_version(bios) >= 0x0300) - return nv_ro16(bios, bios->bmp_offset + 28); + return nvbios_rd16(bios, bios->bmp_offset + 28); return 0x0000; } #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index bc24ae70b4057..5df7eeb56ab3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -69,13 +69,13 @@ dp_set_link_config(struct dp_state *dp) /* set desired link configuration on the source */ if ((lnkcmp = dp->outp->info.lnkcmp)) { if (outp->version < 0x30) { - while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp)) + while ((dp->link_bw / 10) < nvbios_rd16(bios, lnkcmp)) lnkcmp += 4; - init.offset = nv_ro16(bios, lnkcmp + 2); + init.offset = nvbios_rd16(bios, lnkcmp + 2); } else { - while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp)) + while ((dp->link_bw / 27000) < nvbios_rd08(bios, lnkcmp)) lnkcmp += 3; - init.offset = nv_ro16(bios, lnkcmp + 1); + init.offset = nvbios_rd16(bios, lnkcmp + 1); } nvbios_exec(&init); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c index 941db974f897d..43f0ba1fba7d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c @@ -33,14 +33,14 @@ nvbios_M0203Te(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 2 && bit_M.length > 0x04) - data = nv_ro16(bios, bit_M.offset + 0x03); + data = nvbios_rd16(bios, bit_M.offset + 0x03); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); return data; default: break; @@ -59,8 +59,8 @@ nvbios_M0203Tp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->type = nv_ro08(bios, data + 0x04); - info->pointer = nv_ro16(bios, data + 0x05); + info->type = nvbios_rd08(bios, data + 0x04); + info->pointer = nvbios_rd16(bios, data + 0x05); break; default: break; @@ -89,9 +89,9 @@ nvbios_M0203Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->type = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0; - info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4; - info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0; + info->type = (nvbios_rd08(bios, data + 0x00) & 0x0f) >> 0; + info->strap = (nvbios_rd08(bios, data + 0x00) & 0xf0) >> 4; + info->group = (nvbios_rd08(bios, data + 0x01) & 0x0f) >> 0; return data; default: break; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c index e1a8ad5f30665..293a6af1b1d77 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c @@ -34,16 +34,16 @@ nvbios_M0205Te(struct nvkm_bios *bios, if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 2 && bit_M.length > 0x08) - data = nv_ro32(bios, bit_M.offset + 0x05); + data = nvbios_rd32(bios, bit_M.offset + 0x05); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *ssz = nv_ro08(bios, data + 0x03); - *snr = nv_ro08(bios, data + 0x04); - *cnt = nv_ro08(bios, data + 0x05); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *ssz = nvbios_rd08(bios, data + 0x03); + *snr = nvbios_rd08(bios, data + 0x04); + *cnt = nvbios_rd08(bios, data + 0x05); return data; default: break; @@ -63,7 +63,7 @@ nvbios_M0205Tp(struct nvkm_bios *bios, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->freq = nv_ro16(bios, data + 0x06); + info->freq = nvbios_rd16(bios, data + 0x06); break; default: break; @@ -96,7 +96,7 @@ nvbios_M0205Ep(struct nvkm_bios *bios, int idx, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->type = nv_ro08(bios, data + 0x00) & 0x0f; + info->type = nvbios_rd08(bios, data + 0x00) & 0x0f; return data; default: break; @@ -126,7 +126,7 @@ nvbios_M0205Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->data = nv_ro08(bios, data + 0x00); + info->data = nvbios_rd08(bios, data + 0x00); return data; default: break; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c index 3026920c33582..95d49a526472d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c @@ -34,16 +34,16 @@ nvbios_M0209Te(struct nvkm_bios *bios, if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 2 && bit_M.length > 0x0c) - data = nv_ro32(bios, bit_M.offset + 0x09); + data = nvbios_rd32(bios, bit_M.offset + 0x09); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *ssz = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *ssz = nvbios_rd08(bios, data + 0x03); *snr = 1; - *cnt = nv_ro08(bios, data + 0x04); + *cnt = nvbios_rd08(bios, data + 0x04); return data; default: break; @@ -78,12 +78,12 @@ nvbios_M0209Ep(struct nvkm_bios *bios, int idx, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6; - info->bits = nv_ro08(bios, data + 0x00) & 0x3f; - info->modulo = nv_ro08(bios, data + 0x01); - info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; - info->v02_07 = nv_ro08(bios, data + 0x02) & 0x07; - info->v03 = nv_ro08(bios, data + 0x03); + info->v00_40 = (nvbios_rd08(bios, data + 0x00) & 0x40) >> 6; + info->bits = nvbios_rd08(bios, data + 0x00) & 0x3f; + info->modulo = nvbios_rd08(bios, data + 0x01); + info->v02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; + info->v02_07 = nvbios_rd08(bios, data + 0x02) & 0x07; + info->v03 = nvbios_rd08(bios, data + 0x03); return data; default: break; @@ -122,7 +122,7 @@ nvbios_M0209Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr, u32 mask = (1ULL << M0209E.bits) - 1; u16 off = bits / 8; u8 mod = bits % 8; - info->data[i] = nv_ro32(bios, data + off); + info->data[i] = nvbios_rd32(bios, data + off); info->data[i] = info->data[i] >> mod; info->data[i] = info->data[i] & mask; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c index b72edcf849b62..3f7db3eb3ad63 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c @@ -34,15 +34,15 @@ nvbios_P0260Te(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2 && bit_P.length > 0x63) - data = nv_ro32(bios, bit_P.offset + 0x60); + data = nvbios_rd32(bios, bit_P.offset + 0x60); if (data) { - *ver = nv_ro08(bios, data + 0); + *ver = nvbios_rd08(bios, data + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, data + 1); - *cnt = nv_ro08(bios, data + 2); + *hdr = nvbios_rd08(bios, data + 1); + *cnt = nvbios_rd08(bios, data + 2); *len = 4; - *xnr = nv_ro08(bios, data + 3); + *xnr = nvbios_rd08(bios, data + 3); *xsz = 4; return data; default: @@ -72,7 +72,7 @@ nvbios_P0260Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->data = nv_ro32(bios, data); + info->data = nvbios_rd32(bios, data); return data; default: break; @@ -98,7 +98,7 @@ nvbios_P0260Xp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x10: - info->data = nv_ro32(bios, data); + info->data = nvbios_rd32(bios, data); return data; default: break; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index 3a01544200cd3..cc434268d9958 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -52,6 +52,20 @@ nvbios_findstr(const u8 *data, int size, const char *str, int len) return 0; } +int +nvbios_memcmp(struct nvkm_bios *bios, u32 addr, const char *str, u32 len) +{ + unsigned char c1, c2; + + while (len--) { + c1 = nvbios_rd08(bios, addr++); + c2 = *(str++); + if (c1 != c2) + return c1 - c2; + } + return 0; +} + int nvbios_extend(struct nvkm_bios *bios, u32 length) { @@ -69,48 +83,6 @@ nvbios_extend(struct nvkm_bios *bios, u32 length) return 0; } -static u8 -nvkm_bios_rd08(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - return bios->data[addr]; -} - -static u16 -nvkm_bios_rd16(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - return get_unaligned_le16(&bios->data[addr]); -} - -static u32 -nvkm_bios_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - return get_unaligned_le32(&bios->data[addr]); -} - -static void -nvkm_bios_wr08(struct nvkm_object *object, u64 addr, u8 data) -{ - struct nvkm_bios *bios = (void *)object; - bios->data[addr] = data; -} - -static void -nvkm_bios_wr16(struct nvkm_object *object, u64 addr, u16 data) -{ - struct nvkm_bios *bios = (void *)object; - put_unaligned_le16(data, &bios->data[addr]); -} - -static void -nvkm_bios_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_bios *bios = (void *)object; - put_unaligned_le32(data, &bios->data[addr]); -} - static int nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -146,17 +118,17 @@ nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* determine the vbios version number */ if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) { - bios->version.major = nv_ro08(bios, bit_i.offset + 3); - bios->version.chip = nv_ro08(bios, bit_i.offset + 2); - bios->version.minor = nv_ro08(bios, bit_i.offset + 1); - bios->version.micro = nv_ro08(bios, bit_i.offset + 0); - bios->version.patch = nv_ro08(bios, bit_i.offset + 4); + bios->version.major = nvbios_rd08(bios, bit_i.offset + 3); + bios->version.chip = nvbios_rd08(bios, bit_i.offset + 2); + bios->version.minor = nvbios_rd08(bios, bit_i.offset + 1); + bios->version.micro = nvbios_rd08(bios, bit_i.offset + 0); + bios->version.patch = nvbios_rd08(bios, bit_i.offset + 4); } else if (bmp_version(bios)) { - bios->version.major = nv_ro08(bios, bios->bmp_offset + 13); - bios->version.chip = nv_ro08(bios, bios->bmp_offset + 12); - bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11); - bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10); + bios->version.major = nvbios_rd08(bios, bios->bmp_offset + 13); + bios->version.chip = nvbios_rd08(bios, bios->bmp_offset + 12); + bios->version.minor = nvbios_rd08(bios, bios->bmp_offset + 11); + bios->version.micro = nvbios_rd08(bios, bios->bmp_offset + 10); } nvkm_info(&bios->subdev, "version %02x.%02x.%02x.%02x.%02x\n", @@ -195,11 +167,5 @@ nvkm_bios_oclass = { .dtor = nvkm_bios_dtor, .init = nvkm_bios_init, .fini = nvkm_bios_fini, - .rd08 = nvkm_bios_rd08, - .rd16 = nvkm_bios_rd16, - .rd32 = nvkm_bios_rd32, - .wr08 = nvkm_bios_wr08, - .wr16 = nvkm_bios_wr16, - .wr32 = nvkm_bios_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c index eab540496cdfe..070ff33f8d5e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c @@ -28,18 +28,18 @@ int bit_entry(struct nvkm_bios *bios, u8 id, struct bit_entry *bit) { if (likely(bios->bit_offset)) { - u8 entries = nv_ro08(bios, bios->bit_offset + 10); + u8 entries = nvbios_rd08(bios, bios->bit_offset + 10); u32 entry = bios->bit_offset + 12; while (entries--) { - if (nv_ro08(bios, entry + 0) == id) { - bit->id = nv_ro08(bios, entry + 0); - bit->version = nv_ro08(bios, entry + 1); - bit->length = nv_ro16(bios, entry + 2); - bit->offset = nv_ro16(bios, entry + 4); + if (nvbios_rd08(bios, entry + 0) == id) { + bit->id = nvbios_rd08(bios, entry + 0); + bit->version = nvbios_rd08(bios, entry + 1); + bit->length = nvbios_rd16(bios, entry + 2); + bit->offset = nvbios_rd16(bios, entry + 4); return 0; } - entry += nv_ro08(bios, bios->bit_offset + 9); + entry += nvbios_rd08(bios, bios->bit_offset + 9); } return -ENOENT; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c index 12e958533f46c..3756ec91a88d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c @@ -34,17 +34,17 @@ nvbios_boostTe(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - boost = nv_ro16(bios, bit_P.offset + 0x30); + boost = nvbios_rd16(bios, bit_P.offset + 0x30); if (boost) { - *ver = nv_ro08(bios, boost + 0); + *ver = nvbios_rd08(bios, boost + 0); switch (*ver) { case 0x11: - *hdr = nv_ro08(bios, boost + 1); - *cnt = nv_ro08(bios, boost + 5); - *len = nv_ro08(bios, boost + 2); - *snr = nv_ro08(bios, boost + 4); - *ssz = nv_ro08(bios, boost + 3); + *hdr = nvbios_rd08(bios, boost + 1); + *cnt = nvbios_rd08(bios, boost + 5); + *len = nvbios_rd08(bios, boost + 2); + *snr = nvbios_rd08(bios, boost + 4); + *ssz = nvbios_rd08(bios, boost + 3); return boost; default: break; @@ -78,9 +78,9 @@ nvbios_boostEp(struct nvkm_bios *bios, int idx, u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data) { - info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5; - info->min = nv_ro16(bios, data + 0x02) * 1000; - info->max = nv_ro16(bios, data + 0x04) * 1000; + info->pstate = (nvbios_rd16(bios, data + 0x00) & 0x01e0) >> 5; + info->min = nvbios_rd16(bios, data + 0x02) * 1000; + info->max = nvbios_rd16(bios, data + 0x04) * 1000; } return data; } @@ -117,10 +117,10 @@ nvbios_boostSp(struct nvkm_bios *bios, int idx, data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data) { - info->domain = nv_ro08(bios, data + 0x00); - info->percent = nv_ro08(bios, data + 0x01); - info->min = nv_ro16(bios, data + 0x02) * 1000; - info->max = nv_ro16(bios, data + 0x04) * 1000; + info->domain = nvbios_rd08(bios, data + 0x00); + info->percent = nvbios_rd08(bios, data + 0x01); + info->min = nvbios_rd16(bios, data + 0x02) * 1000; + info->max = nvbios_rd16(bios, data + 0x04) * 1000; } return data; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c index 706a1650a4f27..2768234263322 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c @@ -30,12 +30,12 @@ nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u32 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb && *ver >= 0x30 && *hdr >= 0x16) { - u32 data = nv_ro16(bios, dcb + 0x14); + u32 data = nvbios_rd16(bios, dcb + 0x14); if (data) { - *ver = nv_ro08(bios, data + 0); - *hdr = nv_ro08(bios, data + 1); - *cnt = nv_ro08(bios, data + 2); - *len = nv_ro08(bios, data + 3); + *ver = nvbios_rd08(bios, data + 0); + *hdr = nvbios_rd08(bios, data + 1); + *cnt = nvbios_rd08(bios, data + 2); + *len = nvbios_rd08(bios, data + 3); return data; } } @@ -77,18 +77,18 @@ nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, switch (!!data * *ver) { case 0x30: case 0x40: - info->type = nv_ro08(bios, data + 0x00); - info->location = nv_ro08(bios, data + 0x01) & 0x0f; - info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4; - info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6; + info->type = nvbios_rd08(bios, data + 0x00); + info->location = nvbios_rd08(bios, data + 0x01) & 0x0f; + info->hpd = (nvbios_rd08(bios, data + 0x01) & 0x30) >> 4; + info->dp = (nvbios_rd08(bios, data + 0x01) & 0xc0) >> 6; if (*len < 4) return data; - info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2; - info->dp |= nv_ro08(bios, data + 0x02) & 0x0c; - info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4; - info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4; - info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; - info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4; + info->hpd |= (nvbios_rd08(bios, data + 0x02) & 0x03) << 2; + info->dp |= nvbios_rd08(bios, data + 0x02) & 0x0c; + info->di = (nvbios_rd08(bios, data + 0x02) & 0xf0) >> 4; + info->hpd |= (nvbios_rd08(bios, data + 0x03) & 0x07) << 4; + info->sr = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3; + info->lcdid = (nvbios_rd08(bios, data + 0x03) & 0x70) >> 4; return data; default: break; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c index 16f7ad8a4f80f..32e01624a162a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c @@ -34,17 +34,17 @@ nvbios_cstepTe(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - cstep = nv_ro16(bios, bit_P.offset + 0x34); + cstep = nvbios_rd16(bios, bit_P.offset + 0x34); if (cstep) { - *ver = nv_ro08(bios, cstep + 0); + *ver = nvbios_rd08(bios, cstep + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, cstep + 1); - *cnt = nv_ro08(bios, cstep + 3); - *len = nv_ro08(bios, cstep + 2); - *xnr = nv_ro08(bios, cstep + 5); - *xsz = nv_ro08(bios, cstep + 4); + *hdr = nvbios_rd08(bios, cstep + 1); + *cnt = nvbios_rd08(bios, cstep + 3); + *len = nvbios_rd08(bios, cstep + 2); + *xnr = nvbios_rd08(bios, cstep + 5); + *xsz = nvbios_rd08(bios, cstep + 4); return cstep; default: break; @@ -75,8 +75,8 @@ nvbios_cstepEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u16 data = nvbios_cstepEe(bios, idx, ver, hdr); memset(info, 0x00, sizeof(*info)); if (data) { - info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5; - info->index = nv_ro08(bios, data + 0x03); + info->pstate = (nvbios_rd16(bios, data + 0x00) & 0x01e0) >> 5; + info->index = nvbios_rd08(bios, data + 0x03); } return data; } @@ -113,10 +113,10 @@ nvbios_cstepXp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, u16 data = nvbios_cstepXe(bios, idx, ver, hdr); memset(info, 0x00, sizeof(*info)); if (data) { - info->freq = nv_ro16(bios, data + 0x00) * 1000; - info->unkn[0] = nv_ro08(bios, data + 0x02); - info->unkn[1] = nv_ro08(bios, data + 0x03); - info->voltage = nv_ro08(bios, data + 0x04); + info->freq = nvbios_rd16(bios, data + 0x00) * 1000; + info->unkn[0] = nvbios_rd08(bios, data + 0x02); + info->unkn[1] = nvbios_rd08(bios, data + 0x03); + info->voltage = nvbios_rd08(bios, data + 0x04); } return data; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c index 85976ebcb06ae..8304b806f2a64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c @@ -32,29 +32,29 @@ dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) u16 dcb = 0x0000; if (device->card_type > NV_04) - dcb = nv_ro16(bios, 0x36); + dcb = nvbios_rd16(bios, 0x36); if (!dcb) { nvkm_warn(subdev, "DCB table not found\n"); return dcb; } - *ver = nv_ro08(bios, dcb); + *ver = nvbios_rd08(bios, dcb); if (*ver >= 0x42) { nvkm_warn(subdev, "DCB version 0x%02x unknown\n", *ver); return 0x0000; } else if (*ver >= 0x30) { - if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) { - *hdr = nv_ro08(bios, dcb + 1); - *cnt = nv_ro08(bios, dcb + 2); - *len = nv_ro08(bios, dcb + 3); + if (nvbios_rd32(bios, dcb + 6) == 0x4edcbdcb) { + *hdr = nvbios_rd08(bios, dcb + 1); + *cnt = nvbios_rd08(bios, dcb + 2); + *len = nvbios_rd08(bios, dcb + 3); return dcb; } } else if (*ver >= 0x20) { - if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) { - u16 i2c = nv_ro16(bios, dcb + 2); + if (nvbios_rd32(bios, dcb + 4) == 0x4edcbdcb) { + u16 i2c = nvbios_rd16(bios, dcb + 2); *hdr = 8; *cnt = (i2c - dcb) / 8; *len = 8; @@ -62,8 +62,8 @@ dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } } else if (*ver >= 0x15) { - if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) { - u16 i2c = nv_ro16(bios, dcb + 2); + if (!nvbios_memcmp(bios, dcb - 7, "DEV_REC", 7)) { + u16 i2c = nvbios_rd16(bios, dcb + 2); *hdr = 4; *cnt = (i2c - dcb) / 10; *len = 10; @@ -125,7 +125,7 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, memset(outp, 0x00, sizeof(*outp)); if (dcb) { if (*ver >= 0x20) { - u32 conn = nv_ro32(bios, dcb + 0x00); + u32 conn = nvbios_rd32(bios, dcb + 0x00); outp->or = (conn & 0x0f000000) >> 24; outp->location = (conn & 0x00300000) >> 20; outp->bus = (conn & 0x000f0000) >> 16; @@ -139,7 +139,7 @@ dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, } if (*ver >= 0x40) { - u32 conf = nv_ro32(bios, dcb + 0x04); + u32 conf = nvbios_rd32(bios, dcb + 0x04); switch (outp->type) { case DCB_OUTPUT_DP: switch (conf & 0x00e00000) { @@ -213,14 +213,14 @@ dcb_outp_foreach(struct nvkm_bios *bios, void *data, u16 outp; while ((outp = dcb_outp(bios, ++idx, &ver, &len))) { - if (nv_ro32(bios, outp) == 0x00000000) + if (nvbios_rd32(bios, outp) == 0x00000000) break; /* seen on an NV11 with DCB v1.5 */ - if (nv_ro32(bios, outp) == 0xffffffff) + if (nvbios_rd32(bios, outp) == 0xffffffff) break; /* seen on an NV17 with DCB v2.0 */ - if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED) + if (nvbios_rd08(bios, outp) == DCB_OUTPUT_UNUSED) continue; - if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL) + if (nvbios_rd08(bios, outp) == DCB_OUTPUT_EOL) break; ret = exec(bios, data, idx, outp); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c index 262c410b7ee2b..a5e92135cd778 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c @@ -33,17 +33,17 @@ nvbios_disp_table(struct nvkm_bios *bios, if (!bit_entry(bios, 'U', &U)) { if (U.version == 1) { - u16 data = nv_ro16(bios, U.offset); + u16 data = nvbios_rd16(bios, U.offset); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x20: case 0x21: case 0x22: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); - *sub = nv_ro08(bios, data + 0x04); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); + *sub = nvbios_rd08(bios, data + 0x04); return data; default: break; @@ -72,7 +72,7 @@ nvbios_disp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, u8 *sub, { u16 data = nvbios_disp_entry(bios, idx, ver, len, sub); if (data && *len >= 2) { - info->data = nv_ro16(bios, data + 0); + info->data = nvbios_rd16(bios, data + 0); return data; } return 0x0000; @@ -85,7 +85,7 @@ nvbios_outp_entry(struct nvkm_bios *bios, u8 idx, struct nvbios_disp info; u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info); if (data) { - *cnt = nv_ro08(bios, info.data + 0x05); + *cnt = nvbios_rd08(bios, info.data + 0x05); *len = 0x06; data = info.data; } @@ -98,15 +98,15 @@ nvbios_outp_parse(struct nvkm_bios *bios, u8 idx, { u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len); if (data && *hdr >= 0x0a) { - info->type = nv_ro16(bios, data + 0x00); - info->mask = nv_ro32(bios, data + 0x02); + info->type = nvbios_rd16(bios, data + 0x00); + info->mask = nvbios_rd32(bios, data + 0x02); if (*ver <= 0x20) /* match any link */ info->mask |= 0x00c0; - info->script[0] = nv_ro16(bios, data + 0x06); - info->script[1] = nv_ro16(bios, data + 0x08); + info->script[0] = nvbios_rd16(bios, data + 0x06); + info->script[1] = nvbios_rd16(bios, data + 0x08); info->script[2] = 0x0000; if (*hdr >= 0x0c) - info->script[2] = nv_ro16(bios, data + 0x0a); + info->script[2] = nvbios_rd16(bios, data + 0x0a); return data; } return 0x0000; @@ -141,9 +141,9 @@ nvbios_ocfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, { u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len); if (data) { - info->match = nv_ro16(bios, data + 0x00); - info->clkcmp[0] = nv_ro16(bios, data + 0x02); - info->clkcmp[1] = nv_ro16(bios, data + 0x04); + info->match = nvbios_rd16(bios, data + 0x00); + info->clkcmp[0] = nvbios_rd16(bios, data + 0x02); + info->clkcmp[1] = nvbios_rd16(bios, data + 0x04); } return data; } @@ -164,8 +164,8 @@ u16 nvbios_oclk_match(struct nvkm_bios *bios, u16 cmp, u32 khz) { while (cmp) { - if (khz / 10 >= nv_ro16(bios, cmp + 0x00)) - return nv_ro16(bios, cmp + 0x02); + if (khz / 10 >= nvbios_rd16(bios, cmp + 0x00)) + return nvbios_rd16(bios, cmp + 0x02); cmp += 0x04; } return 0x0000; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c index dee047bbfd30d..05332476354ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c @@ -32,17 +32,17 @@ nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'd', &d)) { if (d.version == 1 && d.length >= 2) { - u16 data = nv_ro16(bios, d.offset); + u16 data = nvbios_rd16(bios, d.offset); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); switch (*ver) { case 0x21: case 0x30: case 0x40: case 0x41: - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); return data; default: break; @@ -60,17 +60,17 @@ nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx, { u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { - u16 outp = nv_ro16(bios, data + *hdr + idx * *len); + u16 outp = nvbios_rd16(bios, data + *hdr + idx * *len); switch (*ver * !!outp) { case 0x21: case 0x30: - *hdr = nv_ro08(bios, data + 0x04); - *len = nv_ro08(bios, data + 0x05); - *cnt = nv_ro08(bios, outp + 0x04); + *hdr = nvbios_rd08(bios, data + 0x04); + *len = nvbios_rd08(bios, data + 0x05); + *cnt = nvbios_rd08(bios, outp + 0x04); break; case 0x40: case 0x41: - *hdr = nv_ro08(bios, data + 0x04); + *hdr = nvbios_rd08(bios, data + 0x04); *cnt = 0; *len = 0; break; @@ -91,31 +91,31 @@ nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx, u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); if (data && *ver) { - info->type = nv_ro16(bios, data + 0x00); - info->mask = nv_ro16(bios, data + 0x02); + info->type = nvbios_rd16(bios, data + 0x00); + info->mask = nvbios_rd16(bios, data + 0x02); switch (*ver) { case 0x21: case 0x30: - info->flags = nv_ro08(bios, data + 0x05); - info->script[0] = nv_ro16(bios, data + 0x06); - info->script[1] = nv_ro16(bios, data + 0x08); - info->lnkcmp = nv_ro16(bios, data + 0x0a); + info->flags = nvbios_rd08(bios, data + 0x05); + info->script[0] = nvbios_rd16(bios, data + 0x06); + info->script[1] = nvbios_rd16(bios, data + 0x08); + info->lnkcmp = nvbios_rd16(bios, data + 0x0a); if (*len >= 0x0f) { - info->script[2] = nv_ro16(bios, data + 0x0c); - info->script[3] = nv_ro16(bios, data + 0x0e); + info->script[2] = nvbios_rd16(bios, data + 0x0c); + info->script[3] = nvbios_rd16(bios, data + 0x0e); } if (*len >= 0x11) - info->script[4] = nv_ro16(bios, data + 0x10); + info->script[4] = nvbios_rd16(bios, data + 0x10); break; case 0x40: case 0x41: - info->flags = nv_ro08(bios, data + 0x04); - info->script[0] = nv_ro16(bios, data + 0x05); - info->script[1] = nv_ro16(bios, data + 0x07); - info->lnkcmp = nv_ro16(bios, data + 0x09); - info->script[2] = nv_ro16(bios, data + 0x0b); - info->script[3] = nv_ro16(bios, data + 0x0d); - info->script[4] = nv_ro16(bios, data + 0x0f); + info->flags = nvbios_rd08(bios, data + 0x04); + info->script[0] = nvbios_rd16(bios, data + 0x05); + info->script[1] = nvbios_rd16(bios, data + 0x07); + info->lnkcmp = nvbios_rd16(bios, data + 0x09); + info->script[2] = nvbios_rd16(bios, data + 0x0b); + info->script[3] = nvbios_rd16(bios, data + 0x0d); + info->script[4] = nvbios_rd16(bios, data + 0x0f); break; default: data = 0x0000; @@ -147,9 +147,9 @@ nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx, if (*ver >= 0x40) { outp = nvbios_dp_table(bios, ver, hdr, cnt, len); *hdr = *hdr + (*len * * cnt); - *len = nv_ro08(bios, outp + 0x06); - *cnt = nv_ro08(bios, outp + 0x07) * - nv_ro08(bios, outp + 0x05); + *len = nvbios_rd08(bios, outp + 0x06); + *cnt = nvbios_rd08(bios, outp + 0x07) * + nvbios_rd08(bios, outp + 0x05); } if (idx < *cnt) @@ -168,17 +168,17 @@ nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx, if (data) { switch (*ver) { case 0x21: - info->dc = nv_ro08(bios, data + 0x02); - info->pe = nv_ro08(bios, data + 0x03); - info->tx_pu = nv_ro08(bios, data + 0x04); + info->dc = nvbios_rd08(bios, data + 0x02); + info->pe = nvbios_rd08(bios, data + 0x03); + info->tx_pu = nvbios_rd08(bios, data + 0x04); break; case 0x30: case 0x40: case 0x41: - info->pc = nv_ro08(bios, data + 0x00); - info->dc = nv_ro08(bios, data + 0x01); - info->pe = nv_ro08(bios, data + 0x02); - info->tx_pu = nv_ro08(bios, data + 0x03); + info->pc = nvbios_rd08(bios, data + 0x00); + info->dc = nvbios_rd08(bios, data + 0x01); + info->pe = nvbios_rd08(bios, data + 0x02); + info->tx_pu = nvbios_rd08(bios, data + 0x03); break; default: data = 0x0000; @@ -200,12 +200,12 @@ nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe, const u8 vsoff[] = { 0, 4, 7, 9 }; idx = (pc * 10) + vsoff[vs] + pe; if (*ver >= 0x40 && *hdr >= 0x12) - idx += nv_ro08(bios, outp + 0x11) * 40; + idx += nvbios_rd08(bios, outp + 0x11) * 40; } else { while ((data = nvbios_dpcfg_entry(bios, outp, ++idx, ver, hdr, cnt, len))) { - if (nv_ro08(bios, data + 0x00) == vs && - nv_ro08(bios, data + 0x01) == pe) + if (nvbios_rd08(bios, data + 0x00) == vs && + nvbios_rd08(bios, data + 0x01) == pe) break; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c index a8503a1854c44..c9e6f6ff7c501 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c @@ -35,14 +35,14 @@ extdev_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40)) return 0x0000; - extdev = nv_ro16(bios, dcb + 18); + extdev = nvbios_rd16(bios, dcb + 18); if (!extdev) return 0x0000; - *ver = nv_ro08(bios, extdev + 0); - *hdr = nv_ro08(bios, extdev + 1); - *cnt = nv_ro08(bios, extdev + 2); - *len = nv_ro08(bios, extdev + 3); + *ver = nvbios_rd08(bios, extdev + 0); + *hdr = nvbios_rd08(bios, extdev + 1); + *cnt = nvbios_rd08(bios, extdev + 2); + *len = nvbios_rd08(bios, extdev + 3); return extdev + *hdr; } @@ -60,9 +60,9 @@ static void extdev_parse_entry(struct nvkm_bios *bios, u16 offset, struct nvbios_extdev_func *entry) { - entry->type = nv_ro08(bios, offset + 0); - entry->addr = nv_ro08(bios, offset + 1); - entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1; + entry->type = nvbios_rd08(bios, offset + 0); + entry->addr = nvbios_rd08(bios, offset + 1); + entry->bus = (nvbios_rd08(bios, offset + 2) >> 4) & 1; } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c index 8dba70d9d9a9b..43006db6fd582 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c @@ -33,15 +33,15 @@ nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2 && bit_P.length >= 0x5a) - fan = nv_ro16(bios, bit_P.offset + 0x58); + fan = nvbios_rd16(bios, bit_P.offset + 0x58); if (fan) { - *ver = nv_ro08(bios, fan + 0); + *ver = nvbios_rd08(bios, fan + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, fan + 1); - *len = nv_ro08(bios, fan + 2); - *cnt = nv_ro08(bios, fan + 3); + *hdr = nvbios_rd08(bios, fan + 1); + *len = nvbios_rd08(bios, fan + 2); + *cnt = nvbios_rd08(bios, fan + 3); return fan; default: break; @@ -69,7 +69,7 @@ nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len); if (data) { - u8 type = nv_ro08(bios, data + 0x00); + u8 type = nvbios_rd08(bios, data + 0x00); switch (type) { case 0: fan->type = NVBIOS_THERM_FAN_TOGGLE; @@ -83,10 +83,10 @@ nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) fan->type = NVBIOS_THERM_FAN_UNK; } - fan->min_duty = nv_ro08(bios, data + 0x02); - fan->max_duty = nv_ro08(bios, data + 0x03); + fan->min_duty = nvbios_rd08(bios, data + 0x02); + fan->max_duty = nvbios_rd08(bios, data + 0x03); - fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff; + fan->pwm_freq = nvbios_rd32(bios, data + 0x0b) & 0xffffff; } return data; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c index 8ce154d88f51c..2107b558437a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c @@ -33,22 +33,22 @@ dcb_gpio_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { if (*ver >= 0x30 && *hdr >= 0x0c) - data = nv_ro16(bios, dcb + 0x0a); + data = nvbios_rd16(bios, dcb + 0x0a); else - if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13) - data = nv_ro16(bios, dcb - 0x0f); + if (*ver >= 0x22 && nvbios_rd08(bios, dcb - 1) >= 0x13) + data = nvbios_rd16(bios, dcb - 0x0f); if (data) { - *ver = nv_ro08(bios, data + 0x00); + *ver = nvbios_rd08(bios, data + 0x00); if (*ver < 0x30) { *hdr = 3; - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x01); } else if (*ver <= 0x41) { - *hdr = nv_ro08(bios, data + 0x01); - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x03); + *hdr = nvbios_rd08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x03); } else { data = 0x0000; } @@ -81,7 +81,7 @@ dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, u16 data = dcb_gpio_entry(bios, idx, ent, ver, len); if (data) { if (*ver < 0x40) { - u16 info = nv_ro16(bios, data); + u16 info = nvbios_rd16(bios, data); *gpio = (struct dcb_gpio_func) { .line = (info & 0x001f) >> 0, .func = (info & 0x07e0) >> 5, @@ -91,7 +91,7 @@ dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, }; } else if (*ver < 0x41) { - u32 info = nv_ro32(bios, data); + u32 info = nvbios_rd32(bios, data); *gpio = (struct dcb_gpio_func) { .line = (info & 0x0000001f) >> 0, .func = (info & 0x0000ff00) >> 8, @@ -100,8 +100,8 @@ dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len, .param = !!(info & 0x80000000), }; } else { - u32 info = nv_ro32(bios, data + 0); - u8 info1 = nv_ro32(bios, data + 4); + u32 info = nvbios_rd32(bios, data + 0); + u8 info1 = nvbios_rd32(bios, data + 4); *gpio = (struct dcb_gpio_func) { .line = (info & 0x0000003f) >> 0, .func = (info & 0x0000ff00) >> 8, @@ -131,8 +131,8 @@ dcb_gpio_match(struct nvkm_bios *bios, int idx, u8 func, u8 line, /* DCB 2.2, fixed TVDAC GPIO data */ if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) { if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) { - u8 conf = nv_ro08(bios, data - 5); - u8 addr = nv_ro08(bios, data - 4); + u8 conf = nvbios_rd08(bios, data - 5); + u8 addr = nvbios_rd08(bios, data - 4); if (conf & 0x01) { *gpio = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c index d1dde7abfb24a..7380f01ba731f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c @@ -32,9 +32,9 @@ dcb_i2c_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) u16 dcb = dcb_table(bios, ver, hdr, cnt, len); if (dcb) { if (*ver >= 0x15) - i2c = nv_ro16(bios, dcb + 2); + i2c = nvbios_rd16(bios, dcb + 2); if (*ver >= 0x30) - i2c = nv_ro16(bios, dcb + 4); + i2c = nvbios_rd16(bios, dcb + 4); } if (i2c && *ver >= 0x42) { @@ -43,10 +43,10 @@ dcb_i2c_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) } if (i2c && *ver >= 0x30) { - *ver = nv_ro08(bios, i2c + 0); - *hdr = nv_ro08(bios, i2c + 1); - *cnt = nv_ro08(bios, i2c + 2); - *len = nv_ro08(bios, i2c + 3); + *ver = nvbios_rd08(bios, i2c + 0); + *hdr = nvbios_rd08(bios, i2c + 1); + *cnt = nvbios_rd08(bios, i2c + 2); + *len = nvbios_rd08(bios, i2c + 3); } else { *ver = *ver; /* use DCB version */ *hdr = 0; @@ -75,7 +75,7 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) u16 ent = dcb_i2c_entry(bios, idx, &ver, &len); if (ent) { if (ver >= 0x41) { - u32 ent_value = nv_ro32(bios, ent); + u32 ent_value = nvbios_rd32(bios, ent); u8 i2c_port = (ent_value >> 27) & 0x1f; u8 dpaux_port = (ent_value >> 22) & 0x1f; /* value 0x1f means unused according to DCB 4.x spec */ @@ -85,9 +85,9 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) info->type = DCB_I2C_PMGR; } else if (ver >= 0x30) { - info->type = nv_ro08(bios, ent + 0x03); + info->type = nvbios_rd08(bios, ent + 0x03); } else { - info->type = nv_ro08(bios, ent + 0x03) & 0x07; + info->type = nvbios_rd08(bios, ent + 0x03) & 0x07; if (info->type == 0x07) info->type = DCB_I2C_UNUSED; } @@ -99,27 +99,27 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) switch (info->type) { case DCB_I2C_NV04_BIT: - info->drive = nv_ro08(bios, ent + 0); - info->sense = nv_ro08(bios, ent + 1); + info->drive = nvbios_rd08(bios, ent + 0); + info->sense = nvbios_rd08(bios, ent + 1); return 0; case DCB_I2C_NV4E_BIT: - info->drive = nv_ro08(bios, ent + 1); + info->drive = nvbios_rd08(bios, ent + 1); return 0; case DCB_I2C_NVIO_BIT: - info->drive = nv_ro08(bios, ent + 0) & 0x0f; - if (nv_ro08(bios, ent + 1) & 0x01) - info->share = nv_ro08(bios, ent + 1) >> 1; + info->drive = nvbios_rd08(bios, ent + 0) & 0x0f; + if (nvbios_rd08(bios, ent + 1) & 0x01) + info->share = nvbios_rd08(bios, ent + 1) >> 1; return 0; case DCB_I2C_NVIO_AUX: - info->auxch = nv_ro08(bios, ent + 0) & 0x0f; - if (nv_ro08(bios, ent + 1) & 0x01) + info->auxch = nvbios_rd08(bios, ent + 0) & 0x0f; + if (nvbios_rd08(bios, ent + 1) & 0x01) info->share = info->auxch; return 0; case DCB_I2C_PMGR: - info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0; + info->drive = (nvbios_rd16(bios, ent + 0) & 0x01f) >> 0; if (info->drive == 0x1f) info->drive = DCB_I2C_UNUSED; - info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5; + info->auxch = (nvbios_rd16(bios, ent + 0) & 0x3e0) >> 5; if (info->auxch == 0x1f) info->auxch = DCB_I2C_UNUSED; info->share = info->auxch; @@ -137,21 +137,21 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) /* BMP (from v4.0 has i2c info in the structure, it's in a * fixed location on earlier VBIOS */ - if (nv_ro08(bios, bios->bmp_offset + 5) < 4) + if (nvbios_rd08(bios, bios->bmp_offset + 5) < 4) ent = 0x0048; else ent = 0x0036 + bios->bmp_offset; if (idx == 0) { - info->drive = nv_ro08(bios, ent + 4); + info->drive = nvbios_rd08(bios, ent + 4); if (!info->drive) info->drive = 0x3f; - info->sense = nv_ro08(bios, ent + 5); + info->sense = nvbios_rd08(bios, ent + 5); if (!info->sense) info->sense = 0x3e; } else if (idx == 1) { - info->drive = nv_ro08(bios, ent + 6); + info->drive = nvbios_rd08(bios, ent + 6); if (!info->drive) info->drive = 0x37; - info->sense = nv_ro08(bios, ent + 7); + info->sense = nvbios_rd08(bios, ent + 7); if (!info->sense) info->sense = 0x36; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c index 4560bb3baa5c1..74b14cf093082 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c @@ -36,7 +36,7 @@ nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image) u16 hdr; u32 data; - switch ((data = nv_ro16(bios, image->base + 0x00))) { + switch ((data = nvbios_rd16(bios, image->base + 0x00))) { case 0xaa55: case 0xbb77: case 0x4e56: /* NV */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index b03076e9a0eff..95b6468d5f278 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -374,7 +374,7 @@ init_table_(struct nvbios_init *init, u16 offset, const char *name) u16 len, data = init_table(bios, &len); if (data) { if (len >= offset + 2) { - data = nv_ro16(bios, data + offset); + data = nvbios_rd16(bios, data + offset); if (data) return data; @@ -410,12 +410,12 @@ init_script(struct nvkm_bios *bios, int index) return 0x0000; data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18); - return nv_ro16(bios, data + (index * 2)); + return nvbios_rd16(bios, data + (index * 2)); } data = init_script_table(&init); if (data) - return nv_ro16(bios, data + (index * 2)); + return nvbios_rd16(bios, data + (index * 2)); return 0x0000; } @@ -425,7 +425,7 @@ init_unknown_script(struct nvkm_bios *bios) { u16 len, data = init_table(bios, &len); if (data && len >= 16) - return nv_ro16(bios, data + 14); + return nvbios_rd16(bios, data + 14); return 0x0000; } @@ -457,9 +457,9 @@ init_xlat_(struct nvbios_init *init, u8 index, u8 offset) struct nvkm_bios *bios = init->bios; u16 table = init_xlat_table(init); if (table) { - u16 data = nv_ro16(bios, table + (index * 2)); + u16 data = nvbios_rd16(bios, table + (index * 2)); if (data) - return nv_ro08(bios, data + offset); + return nvbios_rd08(bios, data + offset); warn("xlat table pointer %d invalid\n", index); } return 0x00; @@ -475,9 +475,9 @@ init_condition_met(struct nvbios_init *init, u8 cond) struct nvkm_bios *bios = init->bios; u16 table = init_condition_table(init); if (table) { - u32 reg = nv_ro32(bios, table + (cond * 12) + 0); - u32 msk = nv_ro32(bios, table + (cond * 12) + 4); - u32 val = nv_ro32(bios, table + (cond * 12) + 8); + u32 reg = nvbios_rd32(bios, table + (cond * 12) + 0); + u32 msk = nvbios_rd32(bios, table + (cond * 12) + 4); + u32 val = nvbios_rd32(bios, table + (cond * 12) + 8); trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n", cond, reg, msk, val); return (init_rd32(init, reg) & msk) == val; @@ -491,10 +491,10 @@ init_io_condition_met(struct nvbios_init *init, u8 cond) struct nvkm_bios *bios = init->bios; u16 table = init_io_condition_table(init); if (table) { - u16 port = nv_ro16(bios, table + (cond * 5) + 0); - u8 index = nv_ro08(bios, table + (cond * 5) + 2); - u8 mask = nv_ro08(bios, table + (cond * 5) + 3); - u8 value = nv_ro08(bios, table + (cond * 5) + 4); + u16 port = nvbios_rd16(bios, table + (cond * 5) + 0); + u8 index = nvbios_rd08(bios, table + (cond * 5) + 2); + u8 mask = nvbios_rd08(bios, table + (cond * 5) + 3); + u8 value = nvbios_rd08(bios, table + (cond * 5) + 4); trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n", cond, port, index, mask, value); return (init_rdvgai(init, port, index) & mask) == value; @@ -508,15 +508,15 @@ init_io_flag_condition_met(struct nvbios_init *init, u8 cond) struct nvkm_bios *bios = init->bios; u16 table = init_io_flag_condition_table(init); if (table) { - u16 port = nv_ro16(bios, table + (cond * 9) + 0); - u8 index = nv_ro08(bios, table + (cond * 9) + 2); - u8 mask = nv_ro08(bios, table + (cond * 9) + 3); - u8 shift = nv_ro08(bios, table + (cond * 9) + 4); - u16 data = nv_ro16(bios, table + (cond * 9) + 5); - u8 dmask = nv_ro08(bios, table + (cond * 9) + 7); - u8 value = nv_ro08(bios, table + (cond * 9) + 8); + u16 port = nvbios_rd16(bios, table + (cond * 9) + 0); + u8 index = nvbios_rd08(bios, table + (cond * 9) + 2); + u8 mask = nvbios_rd08(bios, table + (cond * 9) + 3); + u8 shift = nvbios_rd08(bios, table + (cond * 9) + 4); + u16 data = nvbios_rd16(bios, table + (cond * 9) + 5); + u8 dmask = nvbios_rd08(bios, table + (cond * 9) + 7); + u8 value = nvbios_rd08(bios, table + (cond * 9) + 8); u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift; - return (nv_ro08(bios, data + ioval) & dmask) == value; + return (nvbios_rd08(bios, data + ioval) & dmask) == value; } return false; } @@ -576,7 +576,7 @@ init_tmds_reg(struct nvbios_init *init, u8 tmds) static void init_reserved(struct nvbios_init *init) { - u8 opcode = nv_ro08(init->bios, init->offset); + u8 opcode = nvbios_rd08(init->bios, init->offset); u8 length, i; switch (opcode) { @@ -590,7 +590,7 @@ init_reserved(struct nvbios_init *init) trace("RESERVED 0x%02x\t", opcode); for (i = 1; i < length; i++) - cont(" 0x%02x", nv_ro08(init->bios, init->offset + i)); + cont(" 0x%02x", nvbios_rd08(init->bios, init->offset + i)); cont("\n"); init->offset += length; } @@ -614,12 +614,12 @@ static void init_io_restrict_prog(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 shift = nv_ro08(bios, init->offset + 5); - u8 count = nv_ro08(bios, init->offset + 6); - u32 reg = nv_ro32(bios, init->offset + 7); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u8 count = nvbios_rd08(bios, init->offset + 6); + u32 reg = nvbios_rd32(bios, init->offset + 7); u8 conf, i; trace("IO_RESTRICT_PROG\tR[0x%06x] = " @@ -629,7 +629,7 @@ init_io_restrict_prog(struct nvbios_init *init) conf = (init_rdvgai(init, port, index) & mask) >> shift; for (i = 0; i < count; i++) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); if (i == conf) { trace("\t0x%08x *\n", data); @@ -651,7 +651,7 @@ static void init_repeat(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 count = nv_ro08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 1); u16 repeat = init->repeat; trace("REPEAT\t0x%02x\n", count); @@ -677,13 +677,13 @@ static void init_io_restrict_pll(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 shift = nv_ro08(bios, init->offset + 5); - s8 iofc = nv_ro08(bios, init->offset + 6); - u8 count = nv_ro08(bios, init->offset + 7); - u32 reg = nv_ro32(bios, init->offset + 8); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 shift = nvbios_rd08(bios, init->offset + 5); + s8 iofc = nvbios_rd08(bios, init->offset + 6); + u8 count = nvbios_rd08(bios, init->offset + 7); + u32 reg = nvbios_rd32(bios, init->offset + 8); u8 conf, i; trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= " @@ -693,7 +693,7 @@ init_io_restrict_pll(struct nvbios_init *init) conf = (init_rdvgai(init, port, index) & mask) >> shift; for (i = 0; i < count; i++) { - u32 freq = nv_ro16(bios, init->offset) * 10; + u32 freq = nvbios_rd16(bios, init->offset) * 10; if (i == conf) { trace("\t%dkHz *\n", freq); @@ -733,12 +733,12 @@ static void init_copy(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u8 shift = nv_ro08(bios, init->offset + 5); - u8 smask = nv_ro08(bios, init->offset + 6); - u16 port = nv_ro16(bios, init->offset + 7); - u8 index = nv_ro08(bios, init->offset + 9); - u8 mask = nv_ro08(bios, init->offset + 10); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u8 smask = nvbios_rd08(bios, init->offset + 6); + u16 port = nvbios_rd16(bios, init->offset + 7); + u8 index = nvbios_rd08(bios, init->offset + 9); + u8 mask = nvbios_rd08(bios, init->offset + 10); u8 data; trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= " @@ -772,7 +772,7 @@ static void init_io_flag_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); + u8 cond = nvbios_rd08(bios, init->offset + 1); trace("IO_FLAG_CONDITION\t0x%02x\n", cond); init->offset += 2; @@ -790,8 +790,8 @@ init_dp_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; struct nvbios_dpout info; - u8 cond = nv_ro08(bios, init->offset + 1); - u8 unkn = nv_ro08(bios, init->offset + 2); + u8 cond = nvbios_rd08(bios, init->offset + 1); + u8 unkn = nvbios_rd08(bios, init->offset + 2); u8 ver, hdr, cnt, len; u16 data; @@ -837,7 +837,7 @@ static void init_io_mask_or(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 1); u8 or = init_or(init); u8 data; @@ -856,7 +856,7 @@ static void init_io_or(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 1); u8 or = init_or(init); u8 data; @@ -875,8 +875,8 @@ static void init_andn_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask); init->offset += 9; @@ -892,8 +892,8 @@ static void init_or_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask); init->offset += 9; @@ -909,19 +909,19 @@ static void init_idx_addr_latched(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 creg = nv_ro32(bios, init->offset + 1); - u32 dreg = nv_ro32(bios, init->offset + 5); - u32 mask = nv_ro32(bios, init->offset + 9); - u32 data = nv_ro32(bios, init->offset + 13); - u8 count = nv_ro08(bios, init->offset + 17); + u32 creg = nvbios_rd32(bios, init->offset + 1); + u32 dreg = nvbios_rd32(bios, init->offset + 5); + u32 mask = nvbios_rd32(bios, init->offset + 9); + u32 data = nvbios_rd32(bios, init->offset + 13); + u8 count = nvbios_rd08(bios, init->offset + 17); trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg); trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data); init->offset += 18; while (count--) { - u8 iaddr = nv_ro08(bios, init->offset + 0); - u8 idata = nv_ro08(bios, init->offset + 1); + u8 iaddr = nvbios_rd08(bios, init->offset + 0); + u8 idata = nvbios_rd08(bios, init->offset + 1); trace("\t[0x%02x] = 0x%02x\n", iaddr, idata); init->offset += 2; @@ -939,12 +939,12 @@ static void init_io_restrict_pll2(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 shift = nv_ro08(bios, init->offset + 5); - u8 count = nv_ro08(bios, init->offset + 6); - u32 reg = nv_ro32(bios, init->offset + 7); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u8 count = nvbios_rd08(bios, init->offset + 6); + u32 reg = nvbios_rd32(bios, init->offset + 7); u8 conf, i; trace("IO_RESTRICT_PLL2\t" @@ -954,7 +954,7 @@ init_io_restrict_pll2(struct nvbios_init *init) conf = (init_rdvgai(init, port, index) & mask) >> shift; for (i = 0; i < count; i++) { - u32 freq = nv_ro32(bios, init->offset); + u32 freq = nvbios_rd32(bios, init->offset); if (i == conf) { trace("\t%dkHz *\n", freq); init_prog_pll(init, reg, freq); @@ -974,8 +974,8 @@ static void init_pll2(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 freq = nv_ro32(bios, init->offset + 5); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 freq = nvbios_rd32(bios, init->offset + 5); trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq); init->offset += 9; @@ -991,17 +991,17 @@ static void init_i2c_byte(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 count = nv_ro08(bios, init->offset + 3); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 count = nvbios_rd08(bios, init->offset + 3); trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr); init->offset += 4; while (count--) { - u8 reg = nv_ro08(bios, init->offset + 0); - u8 mask = nv_ro08(bios, init->offset + 1); - u8 data = nv_ro08(bios, init->offset + 2); + u8 reg = nvbios_rd08(bios, init->offset + 0); + u8 mask = nvbios_rd08(bios, init->offset + 1); + u8 data = nvbios_rd08(bios, init->offset + 2); int val; trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data); @@ -1022,16 +1022,16 @@ static void init_zm_i2c_byte(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 count = nv_ro08(bios, init->offset + 3); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 count = nvbios_rd08(bios, init->offset + 3); trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr); init->offset += 4; while (count--) { - u8 reg = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 reg = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\t[0x%02x] = 0x%02x\n", reg, data); init->offset += 2; @@ -1048,16 +1048,16 @@ static void init_zm_i2c(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 count = nv_ro08(bios, init->offset + 3); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 count = nvbios_rd08(bios, init->offset + 3); u8 data[256], i; trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr); init->offset += 4; for (i = 0; i < count; i++) { - data[i] = nv_ro08(bios, init->offset); + data[i] = nvbios_rd08(bios, init->offset); trace("\t0x%02x\n", data[i]); init->offset++; } @@ -1082,10 +1082,10 @@ static void init_tmds(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 tmds = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2); - u8 mask = nv_ro08(bios, init->offset + 3); - u8 data = nv_ro08(bios, init->offset + 4); + u8 tmds = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2); + u8 mask = nvbios_rd08(bios, init->offset + 3); + u8 data = nvbios_rd08(bios, init->offset + 4); u32 reg = init_tmds_reg(init, tmds); trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n", @@ -1108,16 +1108,16 @@ static void init_zm_tmds_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 tmds = nv_ro08(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 2); + u8 tmds = nvbios_rd08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 2); u32 reg = init_tmds_reg(init, tmds); trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds); init->offset += 3; while (count--) { - u8 addr = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\t[0x%02x] = 0x%02x\n", addr, data); init->offset += 2; @@ -1135,10 +1135,10 @@ static void init_cr_idx_adr_latch(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 addr0 = nv_ro08(bios, init->offset + 1); - u8 addr1 = nv_ro08(bios, init->offset + 2); - u8 base = nv_ro08(bios, init->offset + 3); - u8 count = nv_ro08(bios, init->offset + 4); + u8 addr0 = nvbios_rd08(bios, init->offset + 1); + u8 addr1 = nvbios_rd08(bios, init->offset + 2); + u8 base = nvbios_rd08(bios, init->offset + 3); + u8 count = nvbios_rd08(bios, init->offset + 4); u8 save0; trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1); @@ -1146,7 +1146,7 @@ init_cr_idx_adr_latch(struct nvbios_init *init) save0 = init_rdvgai(init, 0x03d4, addr0); while (count--) { - u8 data = nv_ro08(bios, init->offset); + u8 data = nvbios_rd08(bios, init->offset); trace("\t\t[0x%02x] = 0x%02x\n", base, data); init->offset += 1; @@ -1165,9 +1165,9 @@ static void init_cr(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 addr = nv_ro08(bios, init->offset + 1); - u8 mask = nv_ro08(bios, init->offset + 2); - u8 data = nv_ro08(bios, init->offset + 3); + u8 addr = nvbios_rd08(bios, init->offset + 1); + u8 mask = nvbios_rd08(bios, init->offset + 2); + u8 data = nvbios_rd08(bios, init->offset + 3); u8 val; trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data); @@ -1185,8 +1185,8 @@ static void init_zm_cr(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 addr = nv_ro08(bios, init->offset + 1); - u8 data = nv_ro08(bios, init->offset + 2); + u8 addr = nvbios_rd08(bios, init->offset + 1); + u8 data = nvbios_rd08(bios, init->offset + 2); trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr, data); init->offset += 3; @@ -1202,14 +1202,14 @@ static void init_zm_cr_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 count = nv_ro08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 1); trace("ZM_CR_GROUP\n"); init->offset += 2; while (count--) { - u8 addr = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\t\tC[0x%02x] = 0x%02x\n", addr, data); init->offset += 2; @@ -1226,8 +1226,8 @@ static void init_condition_time(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); - u8 retry = nv_ro08(bios, init->offset + 2); + u8 cond = nvbios_rd08(bios, init->offset + 1); + u8 retry = nvbios_rd08(bios, init->offset + 2); u8 wait = min((u16)retry * 50, 100); trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry); @@ -1253,7 +1253,7 @@ static void init_ltime(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 msec = nv_ro16(bios, init->offset + 1); + u16 msec = nvbios_rd16(bios, init->offset + 1); trace("LTIME\t0x%04x\n", msec); init->offset += 3; @@ -1270,14 +1270,14 @@ static void init_zm_reg_sequence(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 base = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 base = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("ZM_REG_SEQUENCE\t0x%02x\n", count); init->offset += 6; while (count--) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); trace("\t\tR[0x%06x] = 0x%08x\n", base, data); init->offset += 4; @@ -1295,9 +1295,9 @@ static void init_pll_indirect(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u16 addr = nv_ro16(bios, init->offset + 5); - u32 freq = (u32)nv_ro16(bios, addr) * 1000; + u32 reg = nvbios_rd32(bios, init->offset + 1); + u16 addr = nvbios_rd16(bios, init->offset + 5); + u32 freq = (u32)nvbios_rd16(bios, addr) * 1000; trace("PLL_INDIRECT\tR[0x%06x] =PLL= VBIOS[%04x] = %dkHz\n", reg, addr, freq); @@ -1314,9 +1314,9 @@ static void init_zm_reg_indirect(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u16 addr = nv_ro16(bios, init->offset + 5); - u32 data = nv_ro32(bios, addr); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u16 addr = nvbios_rd16(bios, init->offset + 5); + u32 data = nvbios_rd32(bios, addr); trace("ZM_REG_INDIRECT\tR[0x%06x] = VBIOS[0x%04x] = 0x%08x\n", reg, addr, data); @@ -1333,7 +1333,7 @@ static void init_sub_direct(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 addr = nv_ro16(bios, init->offset + 1); + u16 addr = nvbios_rd16(bios, init->offset + 1); u16 save; trace("SUB_DIRECT\t0x%04x\n", addr); @@ -1359,7 +1359,7 @@ static void init_jump(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 offset = nv_ro16(bios, init->offset + 1); + u16 offset = nvbios_rd16(bios, init->offset + 1); trace("JUMP\t0x%04x\n", offset); @@ -1377,11 +1377,11 @@ static void init_i2c_if(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2); - u8 reg = nv_ro08(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 data = nv_ro08(bios, init->offset + 5); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2); + u8 reg = nvbios_rd08(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 data = nvbios_rd08(bios, init->offset + 5); u8 value; trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n", @@ -1404,12 +1404,12 @@ static void init_copy_nv_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 sreg = nv_ro32(bios, init->offset + 1); - u8 shift = nv_ro08(bios, init->offset + 5); - u32 smask = nv_ro32(bios, init->offset + 6); - u32 sxor = nv_ro32(bios, init->offset + 10); - u32 dreg = nv_ro32(bios, init->offset + 14); - u32 dmask = nv_ro32(bios, init->offset + 18); + u32 sreg = nvbios_rd32(bios, init->offset + 1); + u8 shift = nvbios_rd08(bios, init->offset + 5); + u32 smask = nvbios_rd32(bios, init->offset + 6); + u32 sxor = nvbios_rd32(bios, init->offset + 10); + u32 dreg = nvbios_rd32(bios, init->offset + 14); + u32 dmask = nvbios_rd32(bios, init->offset + 18); u32 data; trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= " @@ -1430,9 +1430,9 @@ static void init_zm_index_io(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro08(bios, init->offset + 3); - u8 data = nv_ro08(bios, init->offset + 4); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 3); + u8 data = nvbios_rd08(bios, init->offset + 4); trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data); init->offset += 5; @@ -1466,9 +1466,9 @@ static void init_reset(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 data1 = nv_ro32(bios, init->offset + 5); - u32 data2 = nv_ro32(bios, init->offset + 9); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 data1 = nvbios_rd32(bios, init->offset + 5); + u32 data2 = nvbios_rd32(bios, init->offset + 9); u32 savepci19; trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2); @@ -1516,14 +1516,14 @@ init_configure_mem(struct nvbios_init *init) mdata = init_configure_mem_clk(init); sdata = bmp_sdr_seq_table(bios); - if (nv_ro08(bios, mdata) & 0x01) + if (nvbios_rd08(bios, mdata) & 0x01) sdata = bmp_ddr_seq_table(bios); mdata += 6; /* skip to data */ data = init_rdvgai(init, 0x03c4, 0x01); init_wrvgai(init, 0x03c4, 0x01, data | 0x20); - for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) { + for (; (addr = nvbios_rd32(bios, sdata)) != 0xffffffff; sdata += 4) { switch (addr) { case 0x10021c: /* CKE_NORMAL */ case 0x1002d0: /* CMD_REFRESH */ @@ -1531,7 +1531,7 @@ init_configure_mem(struct nvbios_init *init) data = 0x00000001; break; default: - data = nv_ro32(bios, mdata); + data = nvbios_rd32(bios, mdata); mdata += 4; if (data == 0xffffffff) continue; @@ -1566,12 +1566,12 @@ init_configure_clk(struct nvbios_init *init) mdata = init_configure_mem_clk(init); /* NVPLL */ - clock = nv_ro16(bios, mdata + 4) * 10; + clock = nvbios_rd16(bios, mdata + 4) * 10; init_prog_pll(init, 0x680500, clock); /* MPLL */ - clock = nv_ro16(bios, mdata + 2) * 10; - if (nv_ro08(bios, mdata) & 0x01) + clock = nvbios_rd16(bios, mdata + 2) * 10; + if (nvbios_rd08(bios, mdata) & 0x01) clock *= 2; init_prog_pll(init, 0x680504, clock); @@ -1612,9 +1612,9 @@ static void init_io(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 mask = nv_ro16(bios, init->offset + 3); - u8 data = nv_ro16(bios, init->offset + 4); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 mask = nvbios_rd16(bios, init->offset + 3); + u8 data = nvbios_rd16(bios, init->offset + 4); u8 value; trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data); @@ -1652,7 +1652,7 @@ static void init_sub(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); + u8 index = nvbios_rd08(bios, init->offset + 1); u16 addr, save; trace("SUB\t0x%02x\n", index); @@ -1679,8 +1679,8 @@ static void init_ram_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 mask = nv_ro08(bios, init->offset + 1); - u8 value = nv_ro08(bios, init->offset + 2); + u8 mask = nvbios_rd08(bios, init->offset + 1); + u8 value = nvbios_rd08(bios, init->offset + 2); trace("RAM_CONDITION\t" "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value); @@ -1698,9 +1698,9 @@ static void init_nv_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); - u32 data = nv_ro32(bios, init->offset + 9); + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); + u32 data = nvbios_rd32(bios, init->offset + 9); trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data); init->offset += 13; @@ -1716,15 +1716,15 @@ static void init_macro(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 macro = nv_ro08(bios, init->offset + 1); + u8 macro = nvbios_rd08(bios, init->offset + 1); u16 table; trace("MACRO\t0x%02x\n", macro); table = init_macro_table(init); if (table) { - u32 addr = nv_ro32(bios, table + (macro * 8) + 0); - u32 data = nv_ro32(bios, table + (macro * 8) + 4); + u32 addr = nvbios_rd32(bios, table + (macro * 8) + 0); + u32 data = nvbios_rd32(bios, table + (macro * 8) + 4); trace("\t\tR[0x%06x] = 0x%08x\n", addr, data); init_wr32(init, addr, data); } @@ -1752,8 +1752,8 @@ static void init_strap_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 mask = nv_ro32(bios, init->offset + 1); - u32 value = nv_ro32(bios, init->offset + 5); + u32 mask = nvbios_rd32(bios, init->offset + 1); + u32 value = nvbios_rd32(bios, init->offset + 5); trace("STRAP_CONDITION\t(R[0x101000] & 0x%08x) == 0x%08x\n", mask, value); init->offset += 9; @@ -1770,7 +1770,7 @@ static void init_time(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 usec = nv_ro16(bios, init->offset + 1); + u16 usec = nvbios_rd16(bios, init->offset + 1); trace("TIME\t0x%04x\n", usec); init->offset += 3; @@ -1791,7 +1791,7 @@ static void init_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); + u8 cond = nvbios_rd08(bios, init->offset + 1); trace("CONDITION\t0x%02x\n", cond); init->offset += 2; @@ -1808,7 +1808,7 @@ static void init_io_condition(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 cond = nv_ro08(bios, init->offset + 1); + u8 cond = nvbios_rd08(bios, init->offset + 1); trace("IO_CONDITION\t0x%02x\n", cond); init->offset += 2; @@ -1825,8 +1825,8 @@ static void init_zm_reg16(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u16 data = nv_ro16(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u16 data = nvbios_rd16(bios, init->offset + 5); trace("ZM_REG\tR[0x%06x] = 0x%04x\n", addr, data); init->offset += 7; @@ -1842,10 +1842,10 @@ static void init_index_io(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u16 port = nv_ro16(bios, init->offset + 1); - u8 index = nv_ro16(bios, init->offset + 3); - u8 mask = nv_ro08(bios, init->offset + 4); - u8 data = nv_ro08(bios, init->offset + 5); + u16 port = nvbios_rd16(bios, init->offset + 1); + u8 index = nvbios_rd16(bios, init->offset + 3); + u8 mask = nvbios_rd08(bios, init->offset + 4); + u8 data = nvbios_rd08(bios, init->offset + 5); u8 value; trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n", @@ -1864,8 +1864,8 @@ static void init_pll(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 reg = nv_ro32(bios, init->offset + 1); - u32 freq = nv_ro16(bios, init->offset + 5) * 10; + u32 reg = nvbios_rd32(bios, init->offset + 1); + u32 freq = nvbios_rd16(bios, init->offset + 5) * 10; trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq); init->offset += 7; @@ -1881,8 +1881,8 @@ static void init_zm_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u32 data = nv_ro32(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u32 data = nvbios_rd32(bios, init->offset + 5); trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data); init->offset += 9; @@ -1901,7 +1901,7 @@ static void init_ram_restrict_pll(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 type = nv_ro08(bios, init->offset + 1); + u8 type = nvbios_rd08(bios, init->offset + 1); u8 count = init_ram_restrict_group_count(init); u8 strap = init_ram_restrict(init); u8 cconf; @@ -1910,7 +1910,7 @@ init_ram_restrict_pll(struct nvbios_init *init) init->offset += 2; for (cconf = 0; cconf < count; cconf++) { - u32 freq = nv_ro32(bios, init->offset); + u32 freq = nvbios_rd32(bios, init->offset); if (cconf == strap) { trace("%dkHz *\n", freq); @@ -1947,9 +1947,9 @@ static void init_ram_restrict_zm_reg_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 incr = nv_ro08(bios, init->offset + 5); - u8 num = nv_ro08(bios, init->offset + 6); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 incr = nvbios_rd08(bios, init->offset + 5); + u8 num = nvbios_rd08(bios, init->offset + 6); u8 count = init_ram_restrict_group_count(init); u8 index = init_ram_restrict(init); u8 i, j; @@ -1961,7 +1961,7 @@ init_ram_restrict_zm_reg_group(struct nvbios_init *init) for (i = 0; i < num; i++) { trace("\tR[0x%06x] = {\n", addr); for (j = 0; j < count; j++) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); if (j == index) { trace("\t\t0x%08x *\n", data); @@ -1985,8 +1985,8 @@ static void init_copy_zm_reg(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 sreg = nv_ro32(bios, init->offset + 1); - u32 dreg = nv_ro32(bios, init->offset + 5); + u32 sreg = nvbios_rd32(bios, init->offset + 1); + u32 dreg = nvbios_rd32(bios, init->offset + 5); trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg); init->offset += 9; @@ -2002,14 +2002,14 @@ static void init_zm_reg_group(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr); init->offset += 6; while (count--) { - u32 data = nv_ro32(bios, init->offset); + u32 data = nvbios_rd32(bios, init->offset); trace("\t0x%08x\n", data); init_wr32(init, addr, data); init->offset += 4; @@ -2024,13 +2024,13 @@ static void init_xlat(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 saddr = nv_ro32(bios, init->offset + 1); - u8 sshift = nv_ro08(bios, init->offset + 5); - u8 smask = nv_ro08(bios, init->offset + 6); - u8 index = nv_ro08(bios, init->offset + 7); - u32 daddr = nv_ro32(bios, init->offset + 8); - u32 dmask = nv_ro32(bios, init->offset + 12); - u8 shift = nv_ro08(bios, init->offset + 16); + u32 saddr = nvbios_rd32(bios, init->offset + 1); + u8 sshift = nvbios_rd08(bios, init->offset + 5); + u8 smask = nvbios_rd08(bios, init->offset + 6); + u8 index = nvbios_rd08(bios, init->offset + 7); + u32 daddr = nvbios_rd32(bios, init->offset + 8); + u32 dmask = nvbios_rd32(bios, init->offset + 12); + u8 shift = nvbios_rd08(bios, init->offset + 16); u32 data; trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= " @@ -2052,9 +2052,9 @@ static void init_zm_mask_add(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u32 mask = nv_ro32(bios, init->offset + 5); - u32 add = nv_ro32(bios, init->offset + 9); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u32 mask = nvbios_rd32(bios, init->offset + 5); + u32 add = nvbios_rd32(bios, init->offset + 9); u32 data; trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add); @@ -2073,15 +2073,15 @@ static void init_auxch(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count); init->offset += 6; while (count--) { - u8 mask = nv_ro08(bios, init->offset + 0); - u8 data = nv_ro08(bios, init->offset + 1); + u8 mask = nvbios_rd08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 1); trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data); mask = init_rdauxr(init, addr) & mask; init_wrauxr(init, addr, mask | data); @@ -2097,14 +2097,14 @@ static void init_zm_auxch(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u32 addr = nv_ro32(bios, init->offset + 1); - u8 count = nv_ro08(bios, init->offset + 5); + u32 addr = nvbios_rd32(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 5); trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count); init->offset += 6; while (count--) { - u8 data = nv_ro08(bios, init->offset + 0); + u8 data = nvbios_rd08(bios, init->offset + 0); trace("\tAUX[0x%08x] = 0x%02x\n", addr, data); init_wrauxr(init, addr, data); init->offset += 1; @@ -2119,12 +2119,12 @@ static void init_i2c_long_if(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - u8 index = nv_ro08(bios, init->offset + 1); - u8 addr = nv_ro08(bios, init->offset + 2) >> 1; - u8 reglo = nv_ro08(bios, init->offset + 3); - u8 reghi = nv_ro08(bios, init->offset + 4); - u8 mask = nv_ro08(bios, init->offset + 5); - u8 data = nv_ro08(bios, init->offset + 6); + u8 index = nvbios_rd08(bios, init->offset + 1); + u8 addr = nvbios_rd08(bios, init->offset + 2) >> 1; + u8 reglo = nvbios_rd08(bios, init->offset + 3); + u8 reghi = nvbios_rd08(bios, init->offset + 4); + u8 mask = nvbios_rd08(bios, init->offset + 5); + u8 data = nvbios_rd08(bios, init->offset + 6); struct nvkm_i2c_port *port; trace("I2C_LONG_IF\t" @@ -2160,7 +2160,7 @@ init_gpio_ne(struct nvbios_init *init) struct nvkm_bios *bios = init->bios; struct nvkm_gpio *gpio = nvkm_gpio(bios); struct dcb_gpio_func func; - u8 count = nv_ro08(bios, init->offset + 1); + u8 count = nvbios_rd08(bios, init->offset + 1); u8 idx = 0, ver, len; u16 data, i; @@ -2168,13 +2168,13 @@ init_gpio_ne(struct nvbios_init *init) init->offset += 2; for (i = init->offset; i < init->offset + count; i++) - cont("0x%02x ", nv_ro08(bios, i)); + cont("0x%02x ", nvbios_rd08(bios, i)); cont("\n"); while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) { if (func.func != DCB_GPIO_UNUSED) { for (i = init->offset; i < init->offset + count; i++) { - if (func.func == nv_ro08(bios, i)) + if (func.func == nvbios_rd08(bios, i)) break; } @@ -2272,7 +2272,7 @@ nvbios_exec(struct nvbios_init *init) { init->nested++; while (init->offset) { - u8 opcode = nv_ro08(init->bios, init->offset); + u8 opcode = nvbios_rd08(init->bios, init->offset); if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) { error("unknown opcode 0x%02x\n", opcode); return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c index a0d7505eeed77..3ddf0939ded3a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c @@ -78,14 +78,14 @@ mxm_sor_map(struct nvkm_bios *bios, u8 conn) u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 6) { - u16 map = nv_ro16(bios, mxm + 4); + u16 map = nvbios_rd16(bios, mxm + 4); if (map) { - ver = nv_ro08(bios, map); + ver = nvbios_rd08(bios, map); if (ver == 0x10) { - if (conn < nv_ro08(bios, map + 3)) { - map += nv_ro08(bios, map + 1); + if (conn < nvbios_rd08(bios, map + 3)) { + map += nvbios_rd08(bios, map + 1); map += conn; - return nv_ro08(bios, map); + return nvbios_rd08(bios, map); } return 0x00; @@ -115,14 +115,14 @@ mxm_ddc_map(struct nvkm_bios *bios, u8 port) u8 ver, hdr; u16 mxm = mxm_table(bios, &ver, &hdr); if (mxm && hdr >= 8) { - u16 map = nv_ro16(bios, mxm + 6); + u16 map = nvbios_rd16(bios, mxm + 6); if (map) { - ver = nv_ro08(bios, map); + ver = nvbios_rd08(bios, map); if (ver == 0x10) { - if (port < nv_ro08(bios, map + 3)) { - map += nv_ro08(bios, map + 1); + if (port < nvbios_rd08(bios, map + 3)) { + map += nvbios_rd08(bios, map + 1); map += port; - return nv_ro08(bios, map); + return nvbios_rd08(bios, map); } return 0x00; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c index 040c03a8b4f36..955df29635c8b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c @@ -32,13 +32,13 @@ nvbios_npdeTe(struct nvkm_bios *bios, u32 base) u8 ver; u16 hdr; u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir); if (data = (data + hdr + 0x0f) & ~0x0f, data) { - switch (nv_ro32(bios, data + 0x00)) { + switch (nvbios_rd32(bios, data + 0x00)) { case 0x4544504e: /* NPDE */ break; default: nvkm_debug(&bios->subdev, "%08x: NPDE signature (%08x) unknown\n", - data, nv_ro32(bios, data + 0x00)); + data, nvbios_rd32(bios, data + 0x00)); data = 0; break; } @@ -52,8 +52,8 @@ nvbios_npdeTp(struct nvkm_bios *bios, u32 base, struct nvbios_npdeT *info) u32 data = nvbios_npdeTe(bios, base); memset(info, 0x00, sizeof(*info)); if (data) { - info->image_size = nv_ro16(bios, data + 0x08) * 512; - info->last = nv_ro08(bios, data + 0x0a) & 0x80; + info->image_size = nvbios_rd16(bios, data + 0x08) * 512; + info->last = nvbios_rd08(bios, data + 0x0a) & 0x80; } return data; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c index 5e4979f98423d..67cb3aeb2da76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c @@ -27,20 +27,20 @@ u32 nvbios_pcirTe(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr) { - u32 data = nv_ro16(bios, base + 0x18); + u32 data = nvbios_rd16(bios, base + 0x18); if (data) { data += base; - switch (nv_ro32(bios, data + 0x00)) { + switch (nvbios_rd32(bios, data + 0x00)) { case 0x52494350: /* PCIR */ case 0x53494752: /* RGIS */ case 0x5344504e: /* NPDS */ - *hdr = nv_ro16(bios, data + 0x0a); - *ver = nv_ro08(bios, data + 0x0c); + *hdr = nvbios_rd16(bios, data + 0x0a); + *ver = nvbios_rd08(bios, data + 0x0c); break; default: nvkm_debug(&bios->subdev, "%08x: PCIR signature (%08x) unknown\n", - data, nv_ro32(bios, data + 0x00)); + data, nvbios_rd32(bios, data + 0x00)); data = 0; break; } @@ -55,15 +55,15 @@ nvbios_pcirTp(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr, u32 data = nvbios_pcirTe(bios, base, ver, hdr); memset(info, 0x00, sizeof(*info)); if (data) { - info->vendor_id = nv_ro16(bios, data + 0x04); - info->device_id = nv_ro16(bios, data + 0x06); - info->class_code[0] = nv_ro08(bios, data + 0x0d); - info->class_code[1] = nv_ro08(bios, data + 0x0e); - info->class_code[2] = nv_ro08(bios, data + 0x0f); - info->image_size = nv_ro16(bios, data + 0x10) * 512; - info->image_rev = nv_ro16(bios, data + 0x12); - info->image_type = nv_ro08(bios, data + 0x14); - info->last = nv_ro08(bios, data + 0x15) & 0x80; + info->vendor_id = nvbios_rd16(bios, data + 0x04); + info->device_id = nvbios_rd16(bios, data + 0x06); + info->class_code[0] = nvbios_rd08(bios, data + 0x0d); + info->class_code[1] = nvbios_rd08(bios, data + 0x0e); + info->class_code[2] = nvbios_rd08(bios, data + 0x0f); + info->image_size = nvbios_rd16(bios, data + 0x10) * 512; + info->image_rev = nvbios_rd16(bios, data + 0x12); + info->image_type = nvbios_rd08(bios, data + 0x14); + info->last = nvbios_rd08(bios, data + 0x15) & 0x80; } return data; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c index 1e70d0eaed418..9385ae9f34638 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c @@ -34,22 +34,22 @@ nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version <= 2) { - perf = nv_ro16(bios, bit_P.offset + 0); + perf = nvbios_rd16(bios, bit_P.offset + 0); if (perf) { - *ver = nv_ro08(bios, perf + 0); - *hdr = nv_ro08(bios, perf + 1); + *ver = nvbios_rd08(bios, perf + 0); + *hdr = nvbios_rd08(bios, perf + 1); if (*ver >= 0x40 && *ver < 0x41) { - *cnt = nv_ro08(bios, perf + 5); - *len = nv_ro08(bios, perf + 2); - *snr = nv_ro08(bios, perf + 4); - *ssz = nv_ro08(bios, perf + 3); + *cnt = nvbios_rd08(bios, perf + 5); + *len = nvbios_rd08(bios, perf + 2); + *snr = nvbios_rd08(bios, perf + 4); + *ssz = nvbios_rd08(bios, perf + 3); return perf; } else if (*ver >= 0x20 && *ver < 0x40) { - *cnt = nv_ro08(bios, perf + 2); - *len = nv_ro08(bios, perf + 3); - *snr = nv_ro08(bios, perf + 4); - *ssz = nv_ro08(bios, perf + 5); + *cnt = nvbios_rd08(bios, perf + 2); + *len = nvbios_rd08(bios, perf + 3); + *snr = nvbios_rd08(bios, perf + 4); + *ssz = nvbios_rd08(bios, perf + 5); return perf; } } @@ -57,13 +57,13 @@ nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, } if (bios->bmp_offset) { - if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) { - perf = nv_ro16(bios, bios->bmp_offset + 0x94); + if (nvbios_rd08(bios, bios->bmp_offset + 6) >= 0x25) { + perf = nvbios_rd16(bios, bios->bmp_offset + 0x94); if (perf) { - *hdr = nv_ro08(bios, perf + 0); - *ver = nv_ro08(bios, perf + 1); - *cnt = nv_ro08(bios, perf + 2); - *len = nv_ro08(bios, perf + 3); + *hdr = nvbios_rd08(bios, perf + 0); + *ver = nvbios_rd08(bios, perf + 1); + *cnt = nvbios_rd08(bios, perf + 2); + *len = nvbios_rd08(bios, perf + 3); *snr = 0; *ssz = 0; return perf; @@ -96,55 +96,55 @@ nvbios_perfEp(struct nvkm_bios *bios, int idx, { u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len); memset(info, 0x00, sizeof(*info)); - info->pstate = nv_ro08(bios, perf + 0x00); + info->pstate = nvbios_rd08(bios, perf + 0x00); switch (!!perf * *ver) { case 0x12: case 0x13: case 0x14: - info->core = nv_ro32(bios, perf + 0x01) * 10; - info->memory = nv_ro32(bios, perf + 0x05) * 20; - info->fanspeed = nv_ro08(bios, perf + 0x37); + info->core = nvbios_rd32(bios, perf + 0x01) * 10; + info->memory = nvbios_rd32(bios, perf + 0x05) * 20; + info->fanspeed = nvbios_rd08(bios, perf + 0x37); if (*hdr > 0x38) - info->voltage = nv_ro08(bios, perf + 0x38); + info->voltage = nvbios_rd08(bios, perf + 0x38); break; case 0x21: case 0x23: case 0x24: - info->fanspeed = nv_ro08(bios, perf + 0x04); - info->voltage = nv_ro08(bios, perf + 0x05); - info->shader = nv_ro16(bios, perf + 0x06) * 1000; + info->fanspeed = nvbios_rd08(bios, perf + 0x04); + info->voltage = nvbios_rd08(bios, perf + 0x05); + info->shader = nvbios_rd16(bios, perf + 0x06) * 1000; info->core = info->shader + (signed char) - nv_ro08(bios, perf + 0x08) * 1000; + nvbios_rd08(bios, perf + 0x08) * 1000; switch (nv_device(bios)->chipset) { case 0x49: case 0x4b: - info->memory = nv_ro16(bios, perf + 0x0b) * 1000; + info->memory = nvbios_rd16(bios, perf + 0x0b) * 1000; break; default: - info->memory = nv_ro16(bios, perf + 0x0b) * 2000; + info->memory = nvbios_rd16(bios, perf + 0x0b) * 2000; break; } break; case 0x25: - info->fanspeed = nv_ro08(bios, perf + 0x04); - info->voltage = nv_ro08(bios, perf + 0x05); - info->core = nv_ro16(bios, perf + 0x06) * 1000; - info->shader = nv_ro16(bios, perf + 0x0a) * 1000; - info->memory = nv_ro16(bios, perf + 0x0c) * 1000; + info->fanspeed = nvbios_rd08(bios, perf + 0x04); + info->voltage = nvbios_rd08(bios, perf + 0x05); + info->core = nvbios_rd16(bios, perf + 0x06) * 1000; + info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000; + info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000; break; case 0x30: - info->script = nv_ro16(bios, perf + 0x02); + info->script = nvbios_rd16(bios, perf + 0x02); case 0x35: - info->fanspeed = nv_ro08(bios, perf + 0x06); - info->voltage = nv_ro08(bios, perf + 0x07); - info->core = nv_ro16(bios, perf + 0x08) * 1000; - info->shader = nv_ro16(bios, perf + 0x0a) * 1000; - info->memory = nv_ro16(bios, perf + 0x0c) * 1000; - info->vdec = nv_ro16(bios, perf + 0x10) * 1000; - info->disp = nv_ro16(bios, perf + 0x14) * 1000; + info->fanspeed = nvbios_rd08(bios, perf + 0x06); + info->voltage = nvbios_rd08(bios, perf + 0x07); + info->core = nvbios_rd16(bios, perf + 0x08) * 1000; + info->shader = nvbios_rd16(bios, perf + 0x0a) * 1000; + info->memory = nvbios_rd16(bios, perf + 0x0c) * 1000; + info->vdec = nvbios_rd16(bios, perf + 0x10) * 1000; + info->disp = nvbios_rd16(bios, perf + 0x14) * 1000; break; case 0x40: - info->voltage = nv_ro08(bios, perf + 0x02); + info->voltage = nvbios_rd08(bios, perf + 0x02); break; default: return 0x0000; @@ -173,7 +173,7 @@ nvbios_perfSp(struct nvkm_bios *bios, u32 perfE, int idx, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { case 0x40: - info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000; + info->v40.freq = (nvbios_rd16(bios, data + 0x00) & 0x3fff) * 1000; break; default: break; @@ -191,7 +191,7 @@ nvbios_perf_fan_parse(struct nvkm_bios *bios, return -ENODEV; if (ver >= 0x20 && ver < 0x40 && hdr > 6) - fan->pwm_divisor = nv_ro16(bios, perf + 6); + fan->pwm_divisor = nvbios_rd16(bios, perf + 6); else fan->pwm_divisor = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index 44088a809f680..c9c66f8dda2e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -83,20 +83,20 @@ pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) struct bit_entry bit_C; if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) { - u16 data = nv_ro16(bios, bit_C.offset + 8); + u16 data = nvbios_rd16(bios, bit_C.offset + 8); if (data) { - *ver = nv_ro08(bios, data + 0); - *hdr = nv_ro08(bios, data + 1); - *len = nv_ro08(bios, data + 2); - *cnt = nv_ro08(bios, data + 3); + *ver = nvbios_rd08(bios, data + 0); + *hdr = nvbios_rd08(bios, data + 1); + *len = nvbios_rd08(bios, data + 2); + *cnt = nvbios_rd08(bios, data + 3); return data; } } if (bmp_version(bios) >= 0x0524) { - u16 data = nv_ro16(bios, bios->bmp_offset + 142); + u16 data = nvbios_rd16(bios, bios->bmp_offset + 142); if (data) { - *ver = nv_ro08(bios, data + 0); + *ver = nvbios_rd08(bios, data + 0); *hdr = 1; *cnt = 1; *len = 0x18; @@ -145,8 +145,8 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) if (data && *ver >= 0x30) { data += hdr; while (cnt--) { - if (nv_ro32(bios, data + 3) == reg) { - *type = nv_ro08(bios, data + 0); + if (nvbios_rd32(bios, data + 3) == reg) { + *type = nvbios_rd08(bios, data + 0); return data; } data += *len; @@ -160,7 +160,7 @@ pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len) u16 addr = (data += hdr); *type = map->type; while (cnt--) { - if (nv_ro32(bios, data) == map->reg) + if (nvbios_rd32(bios, data) == map->reg) return data; data += *len; } @@ -187,8 +187,8 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) if (data && *ver >= 0x30) { data += hdr; while (cnt--) { - if (nv_ro08(bios, data + 0) == type) { - *reg = nv_ro32(bios, data + 3); + if (nvbios_rd08(bios, data + 0) == type) { + *reg = nvbios_rd32(bios, data + 3); return data; } data += *len; @@ -202,7 +202,7 @@ pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len) u16 addr = (data += hdr); *reg = map->reg; while (cnt--) { - if (nv_ro32(bios, data) == map->reg) + if (nvbios_rd32(bios, data) == map->reg) return data; data += *len; } @@ -246,12 +246,12 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) break; case 0x10: case 0x11: - info->vco1.min_freq = nv_ro32(bios, data + 0); - info->vco1.max_freq = nv_ro32(bios, data + 4); - info->vco2.min_freq = nv_ro32(bios, data + 8); - info->vco2.max_freq = nv_ro32(bios, data + 12); - info->vco1.min_inputfreq = nv_ro32(bios, data + 16); - info->vco2.min_inputfreq = nv_ro32(bios, data + 20); + info->vco1.min_freq = nvbios_rd32(bios, data + 0); + info->vco1.max_freq = nvbios_rd32(bios, data + 4); + info->vco2.min_freq = nvbios_rd32(bios, data + 8); + info->vco2.max_freq = nvbios_rd32(bios, data + 12); + info->vco1.min_inputfreq = nvbios_rd32(bios, data + 16); + info->vco2.min_inputfreq = nvbios_rd32(bios, data + 20); info->vco1.max_inputfreq = INT_MAX; info->vco2.max_inputfreq = INT_MAX; @@ -292,69 +292,69 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) break; case 0x20: case 0x21: - info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000; - info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000; - info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000; - info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000; - info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000; - info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000; - info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000; - info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000; - info->vco1.min_n = nv_ro08(bios, data + 20); - info->vco1.max_n = nv_ro08(bios, data + 21); - info->vco1.min_m = nv_ro08(bios, data + 22); - info->vco1.max_m = nv_ro08(bios, data + 23); - info->vco2.min_n = nv_ro08(bios, data + 24); - info->vco2.max_n = nv_ro08(bios, data + 25); - info->vco2.min_m = nv_ro08(bios, data + 26); - info->vco2.max_m = nv_ro08(bios, data + 27); - - info->max_p = nv_ro08(bios, data + 29); + info->vco1.min_freq = nvbios_rd16(bios, data + 4) * 1000; + info->vco1.max_freq = nvbios_rd16(bios, data + 6) * 1000; + info->vco2.min_freq = nvbios_rd16(bios, data + 8) * 1000; + info->vco2.max_freq = nvbios_rd16(bios, data + 10) * 1000; + info->vco1.min_inputfreq = nvbios_rd16(bios, data + 12) * 1000; + info->vco2.min_inputfreq = nvbios_rd16(bios, data + 14) * 1000; + info->vco1.max_inputfreq = nvbios_rd16(bios, data + 16) * 1000; + info->vco2.max_inputfreq = nvbios_rd16(bios, data + 18) * 1000; + info->vco1.min_n = nvbios_rd08(bios, data + 20); + info->vco1.max_n = nvbios_rd08(bios, data + 21); + info->vco1.min_m = nvbios_rd08(bios, data + 22); + info->vco1.max_m = nvbios_rd08(bios, data + 23); + info->vco2.min_n = nvbios_rd08(bios, data + 24); + info->vco2.max_n = nvbios_rd08(bios, data + 25); + info->vco2.min_m = nvbios_rd08(bios, data + 26); + info->vco2.max_m = nvbios_rd08(bios, data + 27); + + info->max_p = nvbios_rd08(bios, data + 29); info->max_p_usable = info->max_p; if (bios->version.chip < 0x60) info->max_p_usable = 0x6; - info->bias_p = nv_ro08(bios, data + 30); + info->bias_p = nvbios_rd08(bios, data + 30); if (len > 0x22) - info->refclk = nv_ro32(bios, data + 31); + info->refclk = nvbios_rd32(bios, data + 31); break; case 0x30: - data = nv_ro16(bios, data + 1); - - info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; - info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; - info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000; - info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000; - info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000; - info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000; - info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000; - info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000; - info->vco1.min_n = nv_ro08(bios, data + 16); - info->vco1.max_n = nv_ro08(bios, data + 17); - info->vco1.min_m = nv_ro08(bios, data + 18); - info->vco1.max_m = nv_ro08(bios, data + 19); - info->vco2.min_n = nv_ro08(bios, data + 20); - info->vco2.max_n = nv_ro08(bios, data + 21); - info->vco2.min_m = nv_ro08(bios, data + 22); - info->vco2.max_m = nv_ro08(bios, data + 23); - info->max_p_usable = info->max_p = nv_ro08(bios, data + 25); - info->bias_p = nv_ro08(bios, data + 27); - info->refclk = nv_ro32(bios, data + 28); + data = nvbios_rd16(bios, data + 1); + + info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; + info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; + info->vco2.min_freq = nvbios_rd16(bios, data + 4) * 1000; + info->vco2.max_freq = nvbios_rd16(bios, data + 6) * 1000; + info->vco1.min_inputfreq = nvbios_rd16(bios, data + 8) * 1000; + info->vco2.min_inputfreq = nvbios_rd16(bios, data + 10) * 1000; + info->vco1.max_inputfreq = nvbios_rd16(bios, data + 12) * 1000; + info->vco2.max_inputfreq = nvbios_rd16(bios, data + 14) * 1000; + info->vco1.min_n = nvbios_rd08(bios, data + 16); + info->vco1.max_n = nvbios_rd08(bios, data + 17); + info->vco1.min_m = nvbios_rd08(bios, data + 18); + info->vco1.max_m = nvbios_rd08(bios, data + 19); + info->vco2.min_n = nvbios_rd08(bios, data + 20); + info->vco2.max_n = nvbios_rd08(bios, data + 21); + info->vco2.min_m = nvbios_rd08(bios, data + 22); + info->vco2.max_m = nvbios_rd08(bios, data + 23); + info->max_p_usable = info->max_p = nvbios_rd08(bios, data + 25); + info->bias_p = nvbios_rd08(bios, data + 27); + info->refclk = nvbios_rd32(bios, data + 28); break; case 0x40: - info->refclk = nv_ro16(bios, data + 9) * 1000; - data = nv_ro16(bios, data + 1); - - info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000; - info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000; - info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000; - info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000; - info->vco1.min_m = nv_ro08(bios, data + 8); - info->vco1.max_m = nv_ro08(bios, data + 9); - info->vco1.min_n = nv_ro08(bios, data + 10); - info->vco1.max_n = nv_ro08(bios, data + 11); - info->min_p = nv_ro08(bios, data + 12); - info->max_p = nv_ro08(bios, data + 13); + info->refclk = nvbios_rd16(bios, data + 9) * 1000; + data = nvbios_rd16(bios, data + 1); + + info->vco1.min_freq = nvbios_rd16(bios, data + 0) * 1000; + info->vco1.max_freq = nvbios_rd16(bios, data + 2) * 1000; + info->vco1.min_inputfreq = nvbios_rd16(bios, data + 4) * 1000; + info->vco1.max_inputfreq = nvbios_rd16(bios, data + 6) * 1000; + info->vco1.min_m = nvbios_rd08(bios, data + 8); + info->vco1.max_m = nvbios_rd08(bios, data + 9); + info->vco1.min_n = nvbios_rd08(bios, data + 10); + info->vco1.max_n = nvbios_rd08(bios, data + 11); + info->min_p = nvbios_rd08(bios, data + 12); + info->max_p = nvbios_rd08(bios, data + 13); break; default: nvkm_error(subdev, "unknown pll limits version 0x%02x\n", ver); @@ -381,8 +381,8 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) * with an empty limit table (seen on nv18) */ if (!info->vco1.max_freq) { - info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67); - info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71); + info->vco1.max_freq = nvbios_rd32(bios, bios->bmp_offset + 67); + info->vco1.min_freq = nvbios_rd32(bios, bios->bmp_offset + 71); if (bmp_version(bios) < 0x0506) { info->vco1.max_freq = 256000; info->vco1.min_freq = 128000; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c index 20c5ce0cd5735..441ec451b7886 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c @@ -49,12 +49,12 @@ nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'p', &bit_p)) { if (bit_p.version == 2 && bit_p.length >= 4) - data = nv_ro32(bios, bit_p.offset + 0x00); + data = nvbios_rd32(bios, bit_p.offset + 0x00); if ((data = weirdo_pointer(bios, data))) { - *ver = nv_ro08(bios, data + 0x00); /* maybe? */ - *hdr = nv_ro08(bios, data + 0x01); - *len = nv_ro08(bios, data + 0x02); - *cnt = nv_ro08(bios, data + 0x03); + *ver = nvbios_rd08(bios, data + 0x00); /* maybe? */ + *hdr = nvbios_rd08(bios, data + 0x01); + *len = nvbios_rd08(bios, data + 0x02); + *cnt = nvbios_rd08(bios, data + 0x03); } } @@ -95,8 +95,8 @@ nvbios_pmuEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr, memset(info, 0x00, sizeof(*info)); switch (!!data * *ver) { default: - info->type = nv_ro08(bios, data + 0x00); - info->data = nv_ro32(bios, data + 0x02); + info->type = nvbios_rd08(bios, data + 0x00); + info->data = nvbios_rd32(bios, data + 0x02); break; } return data; @@ -112,21 +112,21 @@ nvbios_pmuRm(struct nvkm_bios *bios, u8 type, struct nvbios_pmuR *info) while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) { if ( pmuE.type == type && (data = weirdo_pointer(bios, pmuE.data))) { - info->init_addr_pmu = nv_ro32(bios, data + 0x08); - info->args_addr_pmu = nv_ro32(bios, data + 0x0c); + info->init_addr_pmu = nvbios_rd32(bios, data + 0x08); + info->args_addr_pmu = nvbios_rd32(bios, data + 0x0c); info->boot_addr = data + 0x30; - info->boot_addr_pmu = nv_ro32(bios, data + 0x10) + - nv_ro32(bios, data + 0x18); - info->boot_size = nv_ro32(bios, data + 0x1c) - - nv_ro32(bios, data + 0x18); + info->boot_addr_pmu = nvbios_rd32(bios, data + 0x10) + + nvbios_rd32(bios, data + 0x18); + info->boot_size = nvbios_rd32(bios, data + 0x1c) - + nvbios_rd32(bios, data + 0x18); info->code_addr = info->boot_addr + info->boot_size; info->code_addr_pmu = info->boot_addr_pmu + info->boot_size; - info->code_size = nv_ro32(bios, data + 0x20); + info->code_size = nvbios_rd32(bios, data + 0x20); info->data_addr = data + 0x30 + - nv_ro32(bios, data + 0x24); - info->data_addr_pmu = nv_ro32(bios, data + 0x28); - info->data_size = nv_ro32(bios, data + 0x2c); + nvbios_rd32(bios, data + 0x24); + info->data_addr_pmu = nvbios_rd32(bios, data + 0x28); + info->data_size = nvbios_rd32(bios, data + 0x2c); return true; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c index 35a808708126a..878d08fd0e29c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c @@ -39,9 +39,9 @@ nvbios_ramcfg_count(struct nvkm_bios *bios) if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 1 && bit_M.length >= 5) - return nv_ro08(bios, bit_M.offset + 2); + return nvbios_rd08(bios, bit_M.offset + 2); if (bit_M.version == 2 && bit_M.length >= 3) - return nv_ro08(bios, bit_M.offset + 0); + return nvbios_rd08(bios, bit_M.offset + 0); } return 0x00; @@ -59,7 +59,7 @@ nvbios_ramcfg_index(struct nvkm_subdev *subdev) if (!bit_entry(bios, 'M', &bit_M)) { if (bit_M.version == 1 && bit_M.length >= 5) - xlat = nv_ro16(bios, bit_M.offset + 3); + xlat = nvbios_rd16(bios, bit_M.offset + 3); if (bit_M.version == 2 && bit_M.length >= 3) { /*XXX: is M ever shorter than this? * if not - what is xlat used for now? @@ -68,11 +68,11 @@ nvbios_ramcfg_index(struct nvkm_subdev *subdev) if (bit_M.length >= 7 && nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E)) return M0203E.group; - xlat = nv_ro16(bios, bit_M.offset + 1); + xlat = nvbios_rd16(bios, bit_M.offset + 1); } } if (xlat) - strap = nv_ro08(bios, xlat + strap); + strap = nvbios_rd08(bios, xlat + strap); return strap; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c index 1abd9fe4194ce..f0e1fc74a52e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c @@ -34,18 +34,18 @@ nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - rammap = nv_ro16(bios, bit_P.offset + 4); + rammap = nvbios_rd16(bios, bit_P.offset + 4); if (rammap) { - *ver = nv_ro08(bios, rammap + 0); + *ver = nvbios_rd08(bios, rammap + 0); switch (*ver) { case 0x10: case 0x11: - *hdr = nv_ro08(bios, rammap + 1); - *cnt = nv_ro08(bios, rammap + 5); - *len = nv_ro08(bios, rammap + 2); - *snr = nv_ro08(bios, rammap + 4); - *ssz = nv_ro08(bios, rammap + 3); + *hdr = nvbios_rd08(bios, rammap + 1); + *cnt = nvbios_rd08(bios, rammap + 5); + *len = nvbios_rd08(bios, rammap + 2); + *snr = nvbios_rd08(bios, rammap + 4); + *ssz = nvbios_rd08(bios, rammap + 3); return rammap; default: break; @@ -80,9 +80,9 @@ nvbios_rammapEp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, { memset(p, 0x00, sizeof(*p)); - p->rammap_00_16_20 = (nv_ro08(bios, data + 0x16) & 0x20) >> 5; - p->rammap_00_16_40 = (nv_ro08(bios, data + 0x16) & 0x40) >> 6; - p->rammap_00_17_02 = (nv_ro08(bios, data + 0x17) & 0x02) >> 1; + p->rammap_00_16_20 = (nvbios_rd08(bios, data + 0x16) & 0x20) >> 5; + p->rammap_00_16_40 = (nvbios_rd08(bios, data + 0x16) & 0x40) >> 6; + p->rammap_00_17_02 = (nvbios_rd08(bios, data + 0x17) & 0x02) >> 1; return data; } @@ -97,18 +97,18 @@ nvbios_rammapEp(struct nvkm_bios *bios, int idx, p->rammap_hdr = *hdr; switch (!!data * *ver) { case 0x10: - p->rammap_min = nv_ro16(bios, data + 0x00); - p->rammap_max = nv_ro16(bios, data + 0x02); - p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1; - p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3; + p->rammap_min = nvbios_rd16(bios, data + 0x00); + p->rammap_max = nvbios_rd16(bios, data + 0x02); + p->rammap_10_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1; + p->rammap_10_04_08 = (nvbios_rd08(bios, data + 0x04) & 0x08) >> 3; break; case 0x11: - p->rammap_min = nv_ro16(bios, data + 0x00); - p->rammap_max = nv_ro16(bios, data + 0x02); - p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0; - p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2; - p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4; - temp = nv_ro32(bios, data + 0x09); + p->rammap_min = nvbios_rd16(bios, data + 0x00); + p->rammap_max = nvbios_rd16(bios, data + 0x02); + p->rammap_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0; + p->rammap_11_08_0c = (nvbios_rd08(bios, data + 0x08) & 0x0c) >> 2; + p->rammap_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4; + temp = nvbios_rd32(bios, data + 0x09); p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0; p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9; p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18; @@ -117,10 +117,10 @@ nvbios_rammapEp(struct nvkm_bios *bios, int idx, p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25; p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26; p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27; - p->rammap_11_0d = nv_ro08(bios, data + 0x0d); - p->rammap_11_0e = nv_ro08(bios, data + 0x0e); - p->rammap_11_0f = nv_ro08(bios, data + 0x0f); - p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2; + p->rammap_11_0d = nvbios_rd08(bios, data + 0x0d); + p->rammap_11_0e = nvbios_rd08(bios, data + 0x0e); + p->rammap_11_0f = nvbios_rd08(bios, data + 0x0f); + p->rammap_11_11_0c = (nvbios_rd08(bios, data + 0x11) & 0x0c) >> 2; break; default: data = 0; @@ -165,22 +165,22 @@ nvbios_rammapSp_from_perf(struct nvkm_bios *bios, u32 data, u8 size, int idx, return 0x00000000; p->ramcfg_ver = 0; - p->ramcfg_timing = nv_ro08(bios, data + 0x01); - p->ramcfg_00_03_01 = (nv_ro08(bios, data + 0x03) & 0x01) >> 0; - p->ramcfg_00_03_02 = (nv_ro08(bios, data + 0x03) & 0x02) >> 1; - p->ramcfg_DLLoff = (nv_ro08(bios, data + 0x03) & 0x04) >> 2; - p->ramcfg_00_03_08 = (nv_ro08(bios, data + 0x03) & 0x08) >> 3; - p->ramcfg_RON = (nv_ro08(bios, data + 0x03) & 0x10) >> 3; - p->ramcfg_00_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1; - p->ramcfg_00_04_04 = (nv_ro08(bios, data + 0x04) & 0x04) >> 2; - p->ramcfg_00_04_20 = (nv_ro08(bios, data + 0x04) & 0x20) >> 5; - p->ramcfg_00_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; - p->ramcfg_00_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; - p->ramcfg_00_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0; - p->ramcfg_00_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0; - p->ramcfg_00_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0; - p->ramcfg_00_0a_0f = (nv_ro08(bios, data + 0x0a) & 0x0f) >> 0; - p->ramcfg_00_0a_f0 = (nv_ro08(bios, data + 0x0a) & 0xf0) >> 4; + p->ramcfg_timing = nvbios_rd08(bios, data + 0x01); + p->ramcfg_00_03_01 = (nvbios_rd08(bios, data + 0x03) & 0x01) >> 0; + p->ramcfg_00_03_02 = (nvbios_rd08(bios, data + 0x03) & 0x02) >> 1; + p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x03) & 0x04) >> 2; + p->ramcfg_00_03_08 = (nvbios_rd08(bios, data + 0x03) & 0x08) >> 3; + p->ramcfg_RON = (nvbios_rd08(bios, data + 0x03) & 0x10) >> 3; + p->ramcfg_00_04_02 = (nvbios_rd08(bios, data + 0x04) & 0x02) >> 1; + p->ramcfg_00_04_04 = (nvbios_rd08(bios, data + 0x04) & 0x04) >> 2; + p->ramcfg_00_04_20 = (nvbios_rd08(bios, data + 0x04) & 0x20) >> 5; + p->ramcfg_00_05 = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0; + p->ramcfg_00_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_00_07 = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0; + p->ramcfg_00_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; + p->ramcfg_00_09 = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0; + p->ramcfg_00_0a_0f = (nvbios_rd08(bios, data + 0x0a) & 0x0f) >> 0; + p->ramcfg_00_0a_f0 = (nvbios_rd08(bios, data + 0x0a) & 0xf0) >> 4; return data; } @@ -195,58 +195,58 @@ nvbios_rammapSp(struct nvkm_bios *bios, u32 data, p->ramcfg_hdr = *hdr; switch (!!data * *ver) { case 0x10: - p->ramcfg_timing = nv_ro08(bios, data + 0x01); - p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0; - p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1; - p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2; - p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; - p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; - p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5; - p->ramcfg_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; - p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; - p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0; - p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0; - p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; - p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0; - p->ramcfg_10_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0; - p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0; - p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4; + p->ramcfg_timing = nvbios_rd08(bios, data + 0x01); + p->ramcfg_10_02_01 = (nvbios_rd08(bios, data + 0x02) & 0x01) >> 0; + p->ramcfg_10_02_02 = (nvbios_rd08(bios, data + 0x02) & 0x02) >> 1; + p->ramcfg_10_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; + p->ramcfg_10_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; + p->ramcfg_10_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_10_02_20 = (nvbios_rd08(bios, data + 0x02) & 0x20) >> 5; + p->ramcfg_DLLoff = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_10_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_10_04_01 = (nvbios_rd08(bios, data + 0x04) & 0x01) >> 0; + p->ramcfg_10_05 = (nvbios_rd08(bios, data + 0x05) & 0xff) >> 0; + p->ramcfg_10_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_10_07 = (nvbios_rd08(bios, data + 0x07) & 0xff) >> 0; + p->ramcfg_10_08 = (nvbios_rd08(bios, data + 0x08) & 0xff) >> 0; + p->ramcfg_10_09_0f = (nvbios_rd08(bios, data + 0x09) & 0x0f) >> 0; + p->ramcfg_10_09_f0 = (nvbios_rd08(bios, data + 0x09) & 0xf0) >> 4; break; case 0x11: - p->ramcfg_timing = nv_ro08(bios, data + 0x00); - p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0; - p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1; - p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2; - p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3; - p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4; - p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5; - p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6; - p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7; - p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0; - p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2; - p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3; - p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4; - p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6; - p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7; - p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0; - p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4; - p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6; - p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4; - p->ramcfg_11_04 = (nv_ro08(bios, data + 0x04) & 0xff) >> 0; - p->ramcfg_11_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0; - p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1; - p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2; - p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3; - p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4; - p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6; - p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7; - p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0; - p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1; - p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2; - p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3; - p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4; - p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5; - p->ramcfg_11_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0; + p->ramcfg_timing = nvbios_rd08(bios, data + 0x00); + p->ramcfg_11_01_01 = (nvbios_rd08(bios, data + 0x01) & 0x01) >> 0; + p->ramcfg_11_01_02 = (nvbios_rd08(bios, data + 0x01) & 0x02) >> 1; + p->ramcfg_11_01_04 = (nvbios_rd08(bios, data + 0x01) & 0x04) >> 2; + p->ramcfg_11_01_08 = (nvbios_rd08(bios, data + 0x01) & 0x08) >> 3; + p->ramcfg_11_01_10 = (nvbios_rd08(bios, data + 0x01) & 0x10) >> 4; + p->ramcfg_11_01_20 = (nvbios_rd08(bios, data + 0x01) & 0x20) >> 5; + p->ramcfg_11_01_40 = (nvbios_rd08(bios, data + 0x01) & 0x40) >> 6; + p->ramcfg_11_01_80 = (nvbios_rd08(bios, data + 0x01) & 0x80) >> 7; + p->ramcfg_11_02_03 = (nvbios_rd08(bios, data + 0x02) & 0x03) >> 0; + p->ramcfg_11_02_04 = (nvbios_rd08(bios, data + 0x02) & 0x04) >> 2; + p->ramcfg_11_02_08 = (nvbios_rd08(bios, data + 0x02) & 0x08) >> 3; + p->ramcfg_11_02_10 = (nvbios_rd08(bios, data + 0x02) & 0x10) >> 4; + p->ramcfg_11_02_40 = (nvbios_rd08(bios, data + 0x02) & 0x40) >> 6; + p->ramcfg_11_02_80 = (nvbios_rd08(bios, data + 0x02) & 0x80) >> 7; + p->ramcfg_11_03_0f = (nvbios_rd08(bios, data + 0x03) & 0x0f) >> 0; + p->ramcfg_11_03_30 = (nvbios_rd08(bios, data + 0x03) & 0x30) >> 4; + p->ramcfg_11_03_c0 = (nvbios_rd08(bios, data + 0x03) & 0xc0) >> 6; + p->ramcfg_11_03_f0 = (nvbios_rd08(bios, data + 0x03) & 0xf0) >> 4; + p->ramcfg_11_04 = (nvbios_rd08(bios, data + 0x04) & 0xff) >> 0; + p->ramcfg_11_06 = (nvbios_rd08(bios, data + 0x06) & 0xff) >> 0; + p->ramcfg_11_07_02 = (nvbios_rd08(bios, data + 0x07) & 0x02) >> 1; + p->ramcfg_11_07_04 = (nvbios_rd08(bios, data + 0x07) & 0x04) >> 2; + p->ramcfg_11_07_08 = (nvbios_rd08(bios, data + 0x07) & 0x08) >> 3; + p->ramcfg_11_07_10 = (nvbios_rd08(bios, data + 0x07) & 0x10) >> 4; + p->ramcfg_11_07_40 = (nvbios_rd08(bios, data + 0x07) & 0x40) >> 6; + p->ramcfg_11_07_80 = (nvbios_rd08(bios, data + 0x07) & 0x80) >> 7; + p->ramcfg_11_08_01 = (nvbios_rd08(bios, data + 0x08) & 0x01) >> 0; + p->ramcfg_11_08_02 = (nvbios_rd08(bios, data + 0x08) & 0x02) >> 1; + p->ramcfg_11_08_04 = (nvbios_rd08(bios, data + 0x08) & 0x04) >> 2; + p->ramcfg_11_08_08 = (nvbios_rd08(bios, data + 0x08) & 0x08) >> 3; + p->ramcfg_11_08_10 = (nvbios_rd08(bios, data + 0x08) & 0x10) >> 4; + p->ramcfg_11_08_20 = (nvbios_rd08(bios, data + 0x08) & 0x20) >> 5; + p->ramcfg_11_09 = (nvbios_rd08(bios, data + 0x09) & 0xff) >> 0; break; default: data = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index aad482fe7601c..1bbc49677107b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -28,7 +28,6 @@ #include struct shadow { - struct nvkm_oclass base; u32 skip; const struct nvbios_source *func; void *data; @@ -37,9 +36,8 @@ struct shadow { }; static bool -shadow_fetch(struct nvkm_bios *bios, u32 upto) +shadow_fetch(struct nvkm_bios *bios, struct shadow *mthd, u32 upto) { - struct shadow *mthd = (void *)nv_object(bios)->oclass; const u32 limit = (upto + 3) & ~3; const u32 start = bios->size; void *data = mthd->data; @@ -50,50 +48,18 @@ shadow_fetch(struct nvkm_bios *bios, u32 upto) return bios->size >= limit; } -static u8 -shadow_rd08(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - if (shadow_fetch(bios, addr + 1)) - return bios->data[addr]; - return 0x00; -} - -static u16 -shadow_rd16(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - if (shadow_fetch(bios, addr + 2)) - return get_unaligned_le16(&bios->data[addr]); - return 0x0000; -} - -static u32 -shadow_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_bios *bios = (void *)object; - if (shadow_fetch(bios, addr + 4)) - return get_unaligned_le32(&bios->data[addr]); - return 0x00000000; -} - -static struct nvkm_oclass -shadow_class = { - .handle = NV_SUBDEV(VBIOS, 0x00), - .ofuncs = &(struct nvkm_ofuncs) { - .rd08 = shadow_rd08, - .rd16 = shadow_rd16, - .rd32 = shadow_rd32, - }, -}; - static int -shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd) +shadow_image(struct nvkm_bios *bios, int idx, u32 offset, struct shadow *mthd) { struct nvkm_subdev *subdev = &bios->subdev; struct nvbios_image image; int score = 1; + if (!shadow_fetch(bios, mthd, offset + 0x1000)) { + nvkm_debug(subdev, "%08x: header fetch failed\n", offset); + return 0; + } + if (!nvbios_image(bios, idx, &image)) { nvkm_debug(subdev, "image %d invalid\n", idx); return 0; @@ -101,7 +67,7 @@ shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd) nvkm_debug(subdev, "%08x: type %02x, %d bytes\n", image.base, image.type, image.size); - if (!shadow_fetch(bios, image.size)) { + if (!shadow_fetch(bios, mthd, image.size)) { nvkm_debug(subdev, "%08x: fetch failed\n", image.base); return 0; } @@ -124,22 +90,10 @@ shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd) } if (!image.last) - score += shadow_image(bios, idx + 1, mthd); + score += shadow_image(bios, idx + 1, offset + image.size, mthd); return score; } -static int -shadow_score(struct nvkm_bios *bios, struct shadow *mthd) -{ - struct nvkm_oclass *oclass = nv_object(bios)->oclass; - int score; - nv_object(bios)->oclass = &mthd->base; - score = shadow_image(bios, 0, mthd); - nv_object(bios)->oclass = oclass; - return score; - -} - static int shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name) { @@ -154,7 +108,7 @@ shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name) return 0; } } - mthd->score = shadow_score(bios, mthd); + mthd->score = shadow_image(bios, 0, 0, mthd); if (func->fini) func->fini(mthd->data); nvkm_debug(subdev, "scored %d\n", mthd->score); @@ -203,14 +157,14 @@ nvbios_shadow(struct nvkm_bios *bios) struct nvkm_subdev *subdev = &bios->subdev; struct nvkm_device *device = subdev->device; struct shadow mthds[] = { - { shadow_class, 0, &nvbios_of }, - { shadow_class, 0, &nvbios_ramin }, - { shadow_class, 0, &nvbios_rom }, - { shadow_class, 0, &nvbios_acpi_fast }, - { shadow_class, 4, &nvbios_acpi_slow }, - { shadow_class, 1, &nvbios_pcirom }, - { shadow_class, 1, &nvbios_platform }, - { shadow_class } + { 0, &nvbios_of }, + { 0, &nvbios_ramin }, + { 0, &nvbios_rom }, + { 0, &nvbios_acpi_fast }, + { 4, &nvbios_acpi_slow }, + { 1, &nvbios_pcirom }, + { 1, &nvbios_platform }, + {} }, *mthd, *best = NULL; const char *optarg; char *source; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c index 5a21d01a27fed..4039ec594b26c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c @@ -33,9 +33,9 @@ therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 1) - therm = nv_ro16(bios, bit_P.offset + 12); + therm = nvbios_rd16(bios, bit_P.offset + 12); else if (bit_P.version == 2) - therm = nv_ro16(bios, bit_P.offset + 16); + therm = nvbios_rd16(bios, bit_P.offset + 16); else nvkm_error(&bios->subdev, "unknown offset for thermal in BIT P %d\n", @@ -46,11 +46,11 @@ therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt) if (!therm) return 0x0000; - *ver = nv_ro08(bios, therm + 0); - *hdr = nv_ro08(bios, therm + 1); - *len = nv_ro08(bios, therm + 2); - *cnt = nv_ro08(bios, therm + 3); - return therm + nv_ro08(bios, therm + 1); + *ver = nvbios_rd08(bios, therm + 0); + *hdr = nvbios_rd08(bios, therm + 1); + *len = nvbios_rd08(bios, therm + 2); + *cnt = nvbios_rd08(bios, therm + 3); + return therm + nvbios_rd08(bios, therm + 1); } static u16 @@ -81,9 +81,9 @@ nvbios_therm_sensor_parse(struct nvkm_bios *bios, sensor_section = -1; i = 0; while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { - s16 value = nv_ro16(bios, entry + 1); + s16 value = nvbios_rd16(bios, entry + 1); - switch (nv_ro08(bios, entry + 0)) { + switch (nvbios_rd08(bios, entry + 0)) { case 0x0: thrs_section = value; if (value > 0) @@ -92,7 +92,7 @@ nvbios_therm_sensor_parse(struct nvkm_bios *bios, case 0x01: sensor_section++; if (sensor_section == 0) { - offset = ((s8) nv_ro08(bios, entry + 2)) / 2; + offset = ((s8) nvbios_rd08(bios, entry + 2)) / 2; sensor->offset_constant = offset; } break; @@ -163,9 +163,9 @@ nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) fan->nr_fan_trip = 0; fan->fan_mode = NVBIOS_THERM_FAN_OTHER; while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) { - s16 value = nv_ro16(bios, entry + 1); + s16 value = nvbios_rd16(bios, entry + 1); - switch (nv_ro08(bios, entry + 0)) { + switch (nvbios_rd08(bios, entry + 0)) { case 0x22: fan->min_duty = value & 0xff; fan->max_duty = (value & 0xff00) >> 8; @@ -196,8 +196,8 @@ nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) case 0x46: if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR) fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; - fan->linear_min_temp = nv_ro08(bios, entry + 1); - fan->linear_max_temp = nv_ro08(bios, entry + 2); + fan->linear_min_temp = nvbios_rd08(bios, entry + 1); + fan->linear_max_temp = nvbios_rd08(bios, entry + 2); break; } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c index bacd43321826f..99f6432ac0af5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c @@ -34,27 +34,27 @@ nvbios_timingTe(struct nvkm_bios *bios, if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 1) - timing = nv_ro16(bios, bit_P.offset + 4); + timing = nvbios_rd16(bios, bit_P.offset + 4); else if (bit_P.version == 2) - timing = nv_ro16(bios, bit_P.offset + 8); + timing = nvbios_rd16(bios, bit_P.offset + 8); if (timing) { - *ver = nv_ro08(bios, timing + 0); + *ver = nvbios_rd08(bios, timing + 0); switch (*ver) { case 0x10: - *hdr = nv_ro08(bios, timing + 1); - *cnt = nv_ro08(bios, timing + 2); - *len = nv_ro08(bios, timing + 3); + *hdr = nvbios_rd08(bios, timing + 1); + *cnt = nvbios_rd08(bios, timing + 2); + *len = nvbios_rd08(bios, timing + 3); *snr = 0; *ssz = 0; return timing; case 0x20: - *hdr = nv_ro08(bios, timing + 1); - *cnt = nv_ro08(bios, timing + 5); - *len = nv_ro08(bios, timing + 2); - *snr = nv_ro08(bios, timing + 4); - *ssz = nv_ro08(bios, timing + 3); + *hdr = nvbios_rd08(bios, timing + 1); + *cnt = nvbios_rd08(bios, timing + 5); + *len = nvbios_rd08(bios, timing + 2); + *snr = nvbios_rd08(bios, timing + 4); + *ssz = nvbios_rd08(bios, timing + 3); return timing; default: break; @@ -90,20 +90,20 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, p->timing_hdr = *hdr; switch (!!data * *ver) { case 0x10: - p->timing_10_WR = nv_ro08(bios, data + 0x00); - p->timing_10_WTR = nv_ro08(bios, data + 0x01); - p->timing_10_CL = nv_ro08(bios, data + 0x02); - p->timing_10_RC = nv_ro08(bios, data + 0x03); - p->timing_10_RFC = nv_ro08(bios, data + 0x05); - p->timing_10_RAS = nv_ro08(bios, data + 0x07); - p->timing_10_RP = nv_ro08(bios, data + 0x09); - p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a); - p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b); - p->timing_10_RRD = nv_ro08(bios, data + 0x0c); - p->timing_10_13 = nv_ro08(bios, data + 0x0d); - p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07; + p->timing_10_WR = nvbios_rd08(bios, data + 0x00); + p->timing_10_WTR = nvbios_rd08(bios, data + 0x01); + p->timing_10_CL = nvbios_rd08(bios, data + 0x02); + p->timing_10_RC = nvbios_rd08(bios, data + 0x03); + p->timing_10_RFC = nvbios_rd08(bios, data + 0x05); + p->timing_10_RAS = nvbios_rd08(bios, data + 0x07); + p->timing_10_RP = nvbios_rd08(bios, data + 0x09); + p->timing_10_RCDRD = nvbios_rd08(bios, data + 0x0a); + p->timing_10_RCDWR = nvbios_rd08(bios, data + 0x0b); + p->timing_10_RRD = nvbios_rd08(bios, data + 0x0c); + p->timing_10_13 = nvbios_rd08(bios, data + 0x0d); + p->timing_10_ODT = nvbios_rd08(bios, data + 0x0e) & 0x07; if (p->ramcfg_ver >= 0x10) - p->ramcfg_RON = nv_ro08(bios, data + 0x0e) & 0x07; + p->ramcfg_RON = nvbios_rd08(bios, data + 0x0e) & 0x07; p->timing_10_24 = 0xff; p->timing_10_21 = 0; @@ -114,45 +114,45 @@ nvbios_timingEp(struct nvkm_bios *bios, int idx, switch (min_t(u8, *hdr, 25)) { case 25: - p->timing_10_24 = nv_ro08(bios, data + 0x18); + p->timing_10_24 = nvbios_rd08(bios, data + 0x18); case 24: case 23: case 22: - p->timing_10_21 = nv_ro08(bios, data + 0x15); + p->timing_10_21 = nvbios_rd08(bios, data + 0x15); case 21: - p->timing_10_20 = nv_ro08(bios, data + 0x14); + p->timing_10_20 = nvbios_rd08(bios, data + 0x14); case 20: - p->timing_10_CWL = nv_ro08(bios, data + 0x13); + p->timing_10_CWL = nvbios_rd08(bios, data + 0x13); case 19: - p->timing_10_18 = nv_ro08(bios, data + 0x12); + p->timing_10_18 = nvbios_rd08(bios, data + 0x12); case 18: case 17: - p->timing_10_16 = nv_ro08(bios, data + 0x10); + p->timing_10_16 = nvbios_rd08(bios, data + 0x10); } break; case 0x20: - p->timing[0] = nv_ro32(bios, data + 0x00); - p->timing[1] = nv_ro32(bios, data + 0x04); - p->timing[2] = nv_ro32(bios, data + 0x08); - p->timing[3] = nv_ro32(bios, data + 0x0c); - p->timing[4] = nv_ro32(bios, data + 0x10); - p->timing[5] = nv_ro32(bios, data + 0x14); - p->timing[6] = nv_ro32(bios, data + 0x18); - p->timing[7] = nv_ro32(bios, data + 0x1c); - p->timing[8] = nv_ro32(bios, data + 0x20); - p->timing[9] = nv_ro32(bios, data + 0x24); - p->timing[10] = nv_ro32(bios, data + 0x28); - p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0; - p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4; - p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6; - p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0; - temp = nv_ro16(bios, data + 0x2c); + p->timing[0] = nvbios_rd32(bios, data + 0x00); + p->timing[1] = nvbios_rd32(bios, data + 0x04); + p->timing[2] = nvbios_rd32(bios, data + 0x08); + p->timing[3] = nvbios_rd32(bios, data + 0x0c); + p->timing[4] = nvbios_rd32(bios, data + 0x10); + p->timing[5] = nvbios_rd32(bios, data + 0x14); + p->timing[6] = nvbios_rd32(bios, data + 0x18); + p->timing[7] = nvbios_rd32(bios, data + 0x1c); + p->timing[8] = nvbios_rd32(bios, data + 0x20); + p->timing[9] = nvbios_rd32(bios, data + 0x24); + p->timing[10] = nvbios_rd32(bios, data + 0x28); + p->timing_20_2e_03 = (nvbios_rd08(bios, data + 0x2e) & 0x03) >> 0; + p->timing_20_2e_30 = (nvbios_rd08(bios, data + 0x2e) & 0x30) >> 4; + p->timing_20_2e_c0 = (nvbios_rd08(bios, data + 0x2e) & 0xc0) >> 6; + p->timing_20_2f_03 = (nvbios_rd08(bios, data + 0x2f) & 0x03) >> 0; + temp = nvbios_rd16(bios, data + 0x2c); p->timing_20_2c_003f = (temp & 0x003f) >> 0; p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6; - p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0; - p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3; - temp = nv_ro16(bios, data + 0x31); + p->timing_20_30_07 = (nvbios_rd08(bios, data + 0x30) & 0x07) >> 0; + p->timing_20_30_f8 = (nvbios_rd08(bios, data + 0x30) & 0xf8) >> 3; + temp = nvbios_rd16(bios, data + 0x31); p->timing_20_31_0007 = (temp & 0x0007) >> 0; p->timing_20_31_0078 = (temp & 0x0078) >> 3; p->timing_20_31_0780 = (temp & 0x0780) >> 7; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c index e95b69faa82e7..2f13db745948a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c @@ -33,15 +33,15 @@ nvbios_vmap_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) { - vmap = nv_ro16(bios, bit_P.offset + 0x20); + vmap = nvbios_rd16(bios, bit_P.offset + 0x20); if (vmap) { - *ver = nv_ro08(bios, vmap + 0); + *ver = nvbios_rd08(bios, vmap + 0); switch (*ver) { case 0x10: case 0x20: - *hdr = nv_ro08(bios, vmap + 1); - *cnt = nv_ro08(bios, vmap + 3); - *len = nv_ro08(bios, vmap + 2); + *hdr = nvbios_rd08(bios, vmap + 1); + *cnt = nvbios_rd08(bios, vmap + 3); + *len = nvbios_rd08(bios, vmap + 2); return vmap; default: break; @@ -88,23 +88,23 @@ nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, switch (!!vmap * *ver) { case 0x10: info->link = 0xff; - info->min = nv_ro32(bios, vmap + 0x00); - info->max = nv_ro32(bios, vmap + 0x04); - info->arg[0] = nv_ro32(bios, vmap + 0x08); - info->arg[1] = nv_ro32(bios, vmap + 0x0c); - info->arg[2] = nv_ro32(bios, vmap + 0x10); + info->min = nvbios_rd32(bios, vmap + 0x00); + info->max = nvbios_rd32(bios, vmap + 0x04); + info->arg[0] = nvbios_rd32(bios, vmap + 0x08); + info->arg[1] = nvbios_rd32(bios, vmap + 0x0c); + info->arg[2] = nvbios_rd32(bios, vmap + 0x10); break; case 0x20: - info->unk0 = nv_ro08(bios, vmap + 0x00); - info->link = nv_ro08(bios, vmap + 0x01); - info->min = nv_ro32(bios, vmap + 0x02); - info->max = nv_ro32(bios, vmap + 0x06); - info->arg[0] = nv_ro32(bios, vmap + 0x0a); - info->arg[1] = nv_ro32(bios, vmap + 0x0e); - info->arg[2] = nv_ro32(bios, vmap + 0x12); - info->arg[3] = nv_ro32(bios, vmap + 0x16); - info->arg[4] = nv_ro32(bios, vmap + 0x1a); - info->arg[5] = nv_ro32(bios, vmap + 0x1e); + info->unk0 = nvbios_rd08(bios, vmap + 0x00); + info->link = nvbios_rd08(bios, vmap + 0x01); + info->min = nvbios_rd32(bios, vmap + 0x02); + info->max = nvbios_rd32(bios, vmap + 0x06); + info->arg[0] = nvbios_rd32(bios, vmap + 0x0a); + info->arg[1] = nvbios_rd32(bios, vmap + 0x0e); + info->arg[2] = nvbios_rd32(bios, vmap + 0x12); + info->arg[3] = nvbios_rd32(bios, vmap + 0x16); + info->arg[4] = nvbios_rd32(bios, vmap + 0x1a); + info->arg[5] = nvbios_rd32(bios, vmap + 0x1e); break; } return vmap; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c index 8454ab7c4a3db..615804c3887be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c @@ -33,30 +33,30 @@ nvbios_volt_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) if (!bit_entry(bios, 'P', &bit_P)) { if (bit_P.version == 2) - volt = nv_ro16(bios, bit_P.offset + 0x0c); + volt = nvbios_rd16(bios, bit_P.offset + 0x0c); else if (bit_P.version == 1) - volt = nv_ro16(bios, bit_P.offset + 0x10); + volt = nvbios_rd16(bios, bit_P.offset + 0x10); if (volt) { - *ver = nv_ro08(bios, volt + 0); + *ver = nvbios_rd08(bios, volt + 0); switch (*ver) { case 0x12: *hdr = 5; - *cnt = nv_ro08(bios, volt + 2); - *len = nv_ro08(bios, volt + 1); + *cnt = nvbios_rd08(bios, volt + 2); + *len = nvbios_rd08(bios, volt + 1); return volt; case 0x20: - *hdr = nv_ro08(bios, volt + 1); - *cnt = nv_ro08(bios, volt + 2); - *len = nv_ro08(bios, volt + 3); + *hdr = nvbios_rd08(bios, volt + 1); + *cnt = nvbios_rd08(bios, volt + 2); + *len = nvbios_rd08(bios, volt + 3); return volt; case 0x30: case 0x40: case 0x50: - *hdr = nv_ro08(bios, volt + 1); - *cnt = nv_ro08(bios, volt + 3); - *len = nv_ro08(bios, volt + 2); + *hdr = nvbios_rd08(bios, volt + 1); + *cnt = nvbios_rd08(bios, volt + 3); + *len = nvbios_rd08(bios, volt + 2); return volt; } } @@ -73,28 +73,28 @@ nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, memset(info, 0x00, sizeof(*info)); switch (!!volt * *ver) { case 0x12: - info->vidmask = nv_ro08(bios, volt + 0x04); + info->vidmask = nvbios_rd08(bios, volt + 0x04); break; case 0x20: - info->vidmask = nv_ro08(bios, volt + 0x05); + info->vidmask = nvbios_rd08(bios, volt + 0x05); break; case 0x30: - info->vidmask = nv_ro08(bios, volt + 0x04); + info->vidmask = nvbios_rd08(bios, volt + 0x04); break; case 0x40: - info->base = nv_ro32(bios, volt + 0x04); - info->step = nv_ro16(bios, volt + 0x08); - info->vidmask = nv_ro08(bios, volt + 0x0b); + info->base = nvbios_rd32(bios, volt + 0x04); + info->step = nvbios_rd16(bios, volt + 0x08); + info->vidmask = nvbios_rd08(bios, volt + 0x0b); /*XXX*/ info->min = 0; info->max = info->base; break; case 0x50: - info->vidmask = nv_ro08(bios, volt + 0x06); - info->min = nv_ro32(bios, volt + 0x0a); - info->max = nv_ro32(bios, volt + 0x0e); - info->base = nv_ro32(bios, volt + 0x12) & 0x00ffffff; - info->step = nv_ro16(bios, volt + 0x16); + info->vidmask = nvbios_rd08(bios, volt + 0x06); + info->min = nvbios_rd32(bios, volt + 0x0a); + info->max = nvbios_rd32(bios, volt + 0x0e); + info->base = nvbios_rd32(bios, volt + 0x12) & 0x00ffffff; + info->step = nvbios_rd16(bios, volt + 0x16); break; } return volt; @@ -121,12 +121,12 @@ nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len, switch (!!volt * *ver) { case 0x12: case 0x20: - info->voltage = nv_ro08(bios, volt + 0x00) * 10000; - info->vid = nv_ro08(bios, volt + 0x01); + info->voltage = nvbios_rd08(bios, volt + 0x00) * 10000; + info->vid = nvbios_rd08(bios, volt + 0x01); break; case 0x30: - info->voltage = nv_ro08(bios, volt + 0x00) * 10000; - info->vid = nv_ro08(bios, volt + 0x01) >> 2; + info->voltage = nvbios_rd08(bios, volt + 0x00) * 10000; + info->vid = nvbios_rd08(bios, volt + 0x01) >> 2; break; case 0x40: case 0x50: diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c index 63a5e1b5cb3cc..250fc42d86086 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c @@ -30,12 +30,12 @@ dcb_xpiod_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) { u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len); if (data && *ver >= 0x40 && *hdr >= 0x06) { - u16 xpio = nv_ro16(bios, data + 0x04); + u16 xpio = nvbios_rd16(bios, data + 0x04); if (xpio) { - *ver = nv_ro08(bios, data + 0x00); - *hdr = nv_ro08(bios, data + 0x01); - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x03); + *ver = nvbios_rd08(bios, data + 0x00); + *hdr = nvbios_rd08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x03); return xpio; } } @@ -48,12 +48,12 @@ dcb_xpio_table(struct nvkm_bios *bios, u8 idx, { u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len); if (data && idx < *cnt) { - u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len)); + u16 xpio = nvbios_rd16(bios, data + *hdr + (idx * *len)); if (xpio) { - *ver = nv_ro08(bios, data + 0x00); - *hdr = nv_ro08(bios, data + 0x01); - *cnt = nv_ro08(bios, data + 0x02); - *len = nv_ro08(bios, data + 0x03); + *ver = nvbios_rd08(bios, data + 0x00); + *hdr = nvbios_rd08(bios, data + 0x01); + *cnt = nvbios_rd08(bios, data + 0x02); + *len = nvbios_rd08(bios, data + 0x03); return xpio; } } @@ -66,9 +66,9 @@ dcb_xpio_parse(struct nvkm_bios *bios, u8 idx, { u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len); if (data && *len >= 6) { - info->type = nv_ro08(bios, data + 0x04); - info->addr = nv_ro08(bios, data + 0x05); - info->flags = nv_ro08(bios, data + 0x06); + info->type = nvbios_rd08(bios, data + 0x04); + info->addr = nvbios_rd08(bios, data + 0x05); + info->flags = nvbios_rd08(bios, data + 0x06); } return 0x0000; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c index 32d04fe606c1f..c0eb827f5aa3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c @@ -38,7 +38,7 @@ pmu_code(struct nv50_devinit *init, u32 pmu, u32 img, u32 len, bool sec) for (i = 0; i < len; i += 4) { if ((i & 0xff) == 0) nvkm_wr32(device, 0x10a188, (pmu + i) >> 8); - nvkm_wr32(device, 0x10a184, nv_ro32(bios, img + i)); + nvkm_wr32(device, 0x10a184, nvbios_rd32(bios, img + i)); } while (i & 0xff) { @@ -56,7 +56,7 @@ pmu_data(struct nv50_devinit *init, u32 pmu, u32 img, u32 len) nvkm_wr32(device, 0x10a1c0, 0x01000000 | pmu); for (i = 0; i < len; i += 4) - nvkm_wr32(device, 0x10a1c4, nv_ro32(bios, img + i)); + nvkm_wr32(device, 0x10a1c4, nvbios_rd32(bios, img + i)); } static u32 @@ -138,16 +138,16 @@ gm204_devinit_post(struct nvkm_subdev *subdev, bool post) /* upload first chunk of init data */ if (post) { u32 pmu = pmu_args(init, args + 0x08, 0x08); - u32 img = nv_ro16(bios, bit_I.offset + 0x14); - u32 len = nv_ro16(bios, bit_I.offset + 0x16); + u32 img = nvbios_rd16(bios, bit_I.offset + 0x14); + u32 len = nvbios_rd16(bios, bit_I.offset + 0x16); pmu_data(init, pmu, img, len); } /* upload second chunk of init data */ if (post) { u32 pmu = pmu_args(init, args + 0x08, 0x10); - u32 img = nv_ro16(bios, bit_I.offset + 0x18); - u32 len = nv_ro16(bios, bit_I.offset + 0x1a); + u32 img = nvbios_rd16(bios, bit_I.offset + 0x18); + u32 len = nvbios_rd16(bios, bit_I.offset + 0x1a); pmu_data(init, pmu, img, len); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index fc3b0f4a54e25..54de25eea98a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -62,8 +62,8 @@ nv05_devinit_meminit(struct nvkm_devinit *init) strap = (nvkm_rd32(device, 0x101000) & 0x0000003c) >> 2; if ((data = bmp_mem_init_table(bios))) { - ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0); - ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1); + ramcfg[0] = nvbios_rd08(bios, data + 2 * strap + 0); + ramcfg[1] = nvbios_rd08(bios, data + 2 * strap + 1); } else { ramcfg[0] = default_config_tab[strap][0]; ramcfg[1] = default_config_tab[strap][1]; @@ -80,7 +80,7 @@ nv05_devinit_meminit(struct nvkm_devinit *init) /* If present load the hardcoded scrambling table */ if (data) { for (i = 0, data += 0x10; i < 8; i++, data += 4) { - u32 scramble = nv_ro32(bios, data); + u32 scramble = nvbios_rd32(bios, data); nvkm_wr32(device, NV04_PFB_SCRAMBLE(i), scramble); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index f998bbcd44ac2..af7aaabd2bb32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -165,7 +165,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) } /* lookup memory timings, if bios says they're present */ - strap = nv_ro08(bios, ramcfg.data + 0x01); + strap = nvbios_rd08(bios, ramcfg.data + 0x01); if (strap != 0xff) { timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size, &cnt, &len); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 827daa9f3e036..000f45c0f8388 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -1340,8 +1340,8 @@ gk104_ram_init(struct nvkm_object *object) if (!data || hdr < 0x15) return -EINVAL; - cnt = nv_ro08(bios, data + 0x14); /* guess at count */ - data = nv_ro32(bios, data + 0x10); /* guess u32... */ + cnt = nvbios_rd08(bios, data + 0x14); /* guess at count */ + data = nvbios_rd32(bios, data + 0x10); /* guess u32... */ save = nvkm_rd32(device, 0x10f65c) & 0x000000f0; for (i = 0; i < cnt; i++, data += 4) { if (i != save >> 4) { @@ -1349,7 +1349,7 @@ gk104_ram_init(struct nvkm_object *object) nvbios_exec(&(struct nvbios_init) { .subdev = nv_subdev(fb), .bios = bios, - .offset = nv_ro32(bios, data), + .offset = nvbios_rd32(bios, data), .execute = 1, }); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 5a5b335d61bf1..6b2ca3ff83978 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -154,7 +154,7 @@ nv40_ram_prog(struct nvkm_fb *fb) struct nvbios_init init = { .subdev = nv_subdev(fb), .bios = bios, - .offset = nv_ro16(bios, M.offset + 0x00), + .offset = nvbios_rd16(bios, M.offset + 0x00), .execute = 1, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c index a2c019bb7443a..a5aae486ec2b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c @@ -33,7 +33,7 @@ gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) int ent = -1; while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { - u32 data = nv_ro32(bios, entry); + u32 data = nvbios_rd32(bios, entry); u8 line = (data & 0x0000003f); u8 defs = !!(data & 0x00000080); u8 func = (data & 0x0000ff00) >> 8; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c index ca2d866a3c32d..4689836059b93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c @@ -34,7 +34,7 @@ nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) { static const u32 regs[] = { 0xe100, 0xe28c }; - u32 data = nv_ro32(bios, entry); + u32 data = nvbios_rd32(bios, entry); u8 line = (data & 0x0000001f); u8 func = (data & 0x0000ff00) >> 8; u8 defs = !!(data & 0x01000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 3496dfd93264c..6b0f8f0746f51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -176,7 +176,7 @@ nvkm_i2c_find(struct nvkm_i2c *i2c, u8 index) u8 ver, hdr, cnt, len; u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len); if (i2c && ver >= 0x30) { - u8 auxidx = nv_ro08(bios, i2c + 4); + u8 auxidx = nvbios_rd08(bios, i2c + 4); if (index == NV_I2C_DEFAULT(0)) index = (auxidx & 0x0f) >> 0; else diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 6c274c803435d..1818994b14b26 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -243,7 +243,7 @@ nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, return ret; data = mxm_table(bios, &ver, &len); - if (!data || !(ver = nv_ro08(bios, data))) { + if (!data || !(ver = nvbios_rd08(bios, data))) { nvkm_debug(&mxm->subdev, "no VBIOS data, nothing to do\n"); return 0; } -- GitLab From 7e24c1145a9176fb9c9b81b3a0f0703598b1445c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5440/7006] drm/nouveau/fuse: remove object accessor functions Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h | 5 +++++ drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c | 10 +++++++--- drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c | 9 ++++++--- drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c | 10 +++++++--- drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 4 ++-- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h index ebfb6aa2a8559..570a35356ff58 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h @@ -5,6 +5,11 @@ struct nvkm_fuse { struct nvkm_subdev subdev; + const struct nvkm_fuse_func *func; +}; + +struct nvkm_fuse_func { + u32 (*read)(struct nvkm_fuse *, u32 addr); }; static inline struct nvkm_fuse * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c index e9d4324240713..4e94cb94430c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c @@ -30,9 +30,9 @@ struct gf100_fuse { }; static u32 -gf100_fuse_rd32(struct nvkm_object *object, u64 addr) +gf100_fuse_read(struct nvkm_fuse *obj, u32 addr) { - struct gf100_fuse *fuse = (void *)object; + struct gf100_fuse *fuse = container_of(obj, typeof(*fuse), base); struct nvkm_device *device = fuse->base.subdev.device; unsigned long flags; u32 fuse_enable, unk, val; @@ -48,6 +48,10 @@ gf100_fuse_rd32(struct nvkm_object *object, u64 addr) return val; } +static const struct nvkm_fuse_func +gf100_fuse_func = { + .read = gf100_fuse_read, +}; static int gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -63,6 +67,7 @@ gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; spin_lock_init(&fuse->fuse_enable_lock); + fuse->base.func = &gf100_fuse_func; return 0; } @@ -74,6 +79,5 @@ gf100_fuse_oclass = { .dtor = _nvkm_fuse_dtor, .init = _nvkm_fuse_init, .fini = _nvkm_fuse_fini, - .rd32 = gf100_fuse_rd32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c index 94594ac9990b7..bb1101e121488 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c @@ -24,13 +24,16 @@ #include "priv.h" static u32 -gm107_fuse_rd32(struct nvkm_object *object, u64 addr) +gm107_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct nvkm_fuse *fuse = (void *)object; struct nvkm_device *device = fuse->subdev.device; return nvkm_rd32(device, 0x21100 + addr); } +static const struct nvkm_fuse_func +gm107_fuse_func = { + .read = gm107_fuse_read, +}; static int gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -43,6 +46,7 @@ gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ret = nvkm_fuse_create(parent, engine, oclass, &fuse); *pobject = nv_object(fuse); + fuse->func = &gm107_fuse_func; return ret; } @@ -54,6 +58,5 @@ gm107_fuse_oclass = { .dtor = _nvkm_fuse_dtor, .init = _nvkm_fuse_init, .fini = _nvkm_fuse_fini, - .rd32 = gm107_fuse_rd32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c index c47abfa98809e..ee76268ae7026 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c @@ -30,9 +30,9 @@ struct nv50_fuse { }; static u32 -nv50_fuse_rd32(struct nvkm_object *object, u64 addr) +nv50_fuse_read(struct nvkm_fuse *obj, u32 addr) { - struct nv50_fuse *fuse = (void *)object; + struct nv50_fuse *fuse = container_of(obj, typeof(*fuse), base); struct nvkm_device *device = fuse->base.subdev.device; unsigned long flags; u32 fuse_enable, val; @@ -46,6 +46,10 @@ nv50_fuse_rd32(struct nvkm_object *object, u64 addr) return val; } +static const struct nvkm_fuse_func +nv50_fuse_func = { + .read = &nv50_fuse_read, +}; static int nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -61,6 +65,7 @@ nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; spin_lock_init(&fuse->fuse_enable_lock); + fuse->base.func = &nv50_fuse_func; return 0; } @@ -72,6 +77,5 @@ nv50_fuse_oclass = { .dtor = _nvkm_fuse_dtor, .init = _nvkm_fuse_init, .fini = _nvkm_fuse_fini, - .rd32 = nv50_fuse_rd32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index a1da856d5103e..aea79d7201bda 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -32,7 +32,7 @@ g84_temp_get(struct nvkm_therm *therm) struct nvkm_device *device = therm->subdev.device; struct nvkm_fuse *fuse = nvkm_fuse(therm); - if (nv_ro32(fuse, 0x1a8) == 1) + if (fuse->func->read(fuse, 0x1a8) == 1) return nvkm_rd32(device, 0x20400); else return -ENODEV; @@ -45,7 +45,7 @@ g84_sensor_setup(struct nvkm_therm *therm) struct nvkm_fuse *fuse = nvkm_fuse(therm); /* enable temperature reading for cards with insane defaults */ - if (nv_ro32(fuse, 0x1a8) == 1) { + if (fuse->func->read(fuse, 0x1a8) == 1) { nvkm_mask(device, 0x20008, 0x80008000, 0x80000000); nvkm_mask(device, 0x2000c, 0x80000003, 0x00000000); mdelay(20); /* wait for the temperature to stabilize */ -- GitLab From a47474261e77b148480daff855e516dc60e80b48 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5441/7006] drm/nouveau/imem: remove object accessor functions Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/instmem.h | 7 ++++++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 6 ++--- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 6 ++--- .../drm/nouveau/nvkm/subdev/instmem/nv04.c | 24 +++++++++++-------- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 18 +++++++++----- 6 files changed, 40 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index d8941b7bebfca..b6906f436e402 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -26,6 +26,13 @@ struct nvkm_instmem { u32 reserved; int (*alloc)(struct nvkm_instmem *, struct nvkm_object *, u32 size, u32 align, struct nvkm_object **); + + const struct nvkm_instmem_func *func; +}; + +struct nvkm_instmem_func { + u32 (*rd32)(struct nvkm_instmem *, u32 addr); + void (*wr32)(struct nvkm_instmem *, u32 addr, u32 data); }; static inline struct nvkm_instmem * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index a445712973f6a..7295a915949ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -573,7 +573,7 @@ nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size) { struct nvkm_instmem *imem = nvkm_instmem(object); u32 inst = *(u32 *)args << 4; - return nv_ro32(imem, inst); + return imem->func->rd32(imem, inst); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 4ece5c0654128..d4d1abba02f4f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -63,9 +63,9 @@ nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) struct nvkm_device *device = mpeg->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; u32 inst = *(u32 *)arg << 4; - u32 dma0 = nv_ro32(imem, inst + 0); - u32 dma1 = nv_ro32(imem, inst + 4); - u32 dma2 = nv_ro32(imem, inst + 8); + u32 dma0 = imem->func->rd32(imem, inst + 0); + u32 dma1 = imem->func->rd32(imem, inst + 4); + u32 dma2 = imem->func->rd32(imem, inst + 8); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 47ae1d890a7f1..7c009c3aa7f81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -36,9 +36,9 @@ nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) struct nvkm_device *device = mpeg->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; u32 inst = *(u32 *)arg << 4; - u32 dma0 = nv_ro32(imem, inst + 0); - u32 dma1 = nv_ro32(imem, inst + 4); - u32 dma2 = nv_ro32(imem, inst + 8); + u32 dma0 = imem->func->rd32(imem, inst + 0); + u32 dma1 = imem->func->rd32(imem, inst + 4); + u32 dma2 = imem->func->rd32(imem, inst + 8); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 6410cc1fd419c..8ba95f366e2fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -32,17 +32,17 @@ static u32 nv04_instobj_rd32(struct nvkm_object *object, u64 addr) { - struct nv04_instmem *imem = (void *)nvkm_instmem(object); + struct nvkm_instmem *imem = nvkm_instmem(object); struct nv04_instobj *node = (void *)object; - return nv_ro32(imem, node->mem->offset + addr); + return imem->func->rd32(imem, node->mem->offset + addr); } static void nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nv04_instmem *imem = (void *)nvkm_instmem(object); + struct nvkm_instmem *imem = nvkm_instmem(object); struct nv04_instobj *node = (void *)object; - nv_wo32(imem, node->mem->offset + addr, data); + imem->func->wr32(imem, node->mem->offset + addr, data); } static void @@ -103,16 +103,14 @@ nv04_instobj_oclass = { *****************************************************************************/ static u32 -nv04_instmem_rd32(struct nvkm_object *object, u64 addr) +nv04_instmem_rd32(struct nvkm_instmem *imem, u32 addr) { - struct nvkm_instmem *imem = (void *)object; return nvkm_rd32(imem->subdev.device, 0x700000 + addr); } static void -nv04_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) +nv04_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data) { - struct nvkm_instmem *imem = (void *)object; nvkm_wr32(imem->subdev.device, 0x700000 + addr, data); } @@ -130,6 +128,12 @@ nv04_instmem_dtor(struct nvkm_object *object) nvkm_instmem_destroy(&imem->base); } +static const struct nvkm_instmem_func +nv04_instmem_func = { + .rd32 = nv04_instmem_rd32, + .wr32 = nv04_instmem_wr32, +}; + static int nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -143,6 +147,8 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + imem->base.func = &nv04_instmem_func; + /* PRAMIN aperture maps over the end of VRAM, reserve it */ imem->base.reserved = 512 * 1024; @@ -184,8 +190,6 @@ nv04_instmem_oclass = &(struct nvkm_instmem_impl) { .dtor = nv04_instmem_dtor, .init = _nvkm_instmem_init, .fini = _nvkm_instmem_fini, - .rd32 = nv04_instmem_rd32, - .wr32 = nv04_instmem_wr32, }, .instobj = &nv04_instobj_oclass.base, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index c194a28b79719..c645e02615301 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -31,19 +31,25 @@ *****************************************************************************/ static u32 -nv40_instmem_rd32(struct nvkm_object *object, u64 addr) +nv40_instmem_rd32(struct nvkm_instmem *obj, u32 addr) { - struct nv04_instmem *imem = (void *)object; + struct nv04_instmem *imem = container_of(obj, typeof(*imem), base); return ioread32_native(imem->iomem + addr); } static void -nv40_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data) +nv40_instmem_wr32(struct nvkm_instmem *obj, u32 addr, u32 data) { - struct nv04_instmem *imem = (void *)object; + struct nv04_instmem *imem = container_of(obj, typeof(*imem), base); iowrite32_native(data, imem->iomem + addr); } +static const struct nvkm_instmem_func +nv40_instmem_func = { + .rd32 = nv40_instmem_rd32, + .wr32 = nv40_instmem_wr32, +}; + static int nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -58,6 +64,8 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + imem->base.func = &nv40_instmem_func; + /* map bar */ if (nv_device_resource_len(device, 2)) bar = 2; @@ -129,8 +137,6 @@ nv40_instmem_oclass = &(struct nvkm_instmem_impl) { .dtor = nv04_instmem_dtor, .init = _nvkm_instmem_init, .fini = _nvkm_instmem_fini, - .rd32 = nv40_instmem_rd32, - .wr32 = nv40_instmem_wr32, }, .instobj = &nv04_instobj_oclass.base, }.base; -- GitLab From 63902181a7ce9177c476103694cbdf45ee5c0578 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5442/7006] drm/nouveau/falcon: remove object accessor functions Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/falcon.h | 2 - .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 9 +- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 26 +++--- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 85 +++++++++---------- .../gpu/drm/nouveau/nvkm/engine/mspdec/g98.c | 2 - .../drm/nouveau/nvkm/engine/mspdec/gf100.c | 2 - .../drm/nouveau/nvkm/engine/mspdec/gk104.c | 2 - .../gpu/drm/nouveau/nvkm/engine/msppp/g98.c | 2 - .../gpu/drm/nouveau/nvkm/engine/msppp/gf100.c | 2 - .../gpu/drm/nouveau/nvkm/engine/msvld/g98.c | 2 - .../gpu/drm/nouveau/nvkm/engine/msvld/gf100.c | 2 - .../gpu/drm/nouveau/nvkm/engine/msvld/gk104.c | 2 - drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 2 - 13 files changed, 55 insertions(+), 85 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index 7532cd785c883..3ce0ffc8ef869 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -76,6 +76,4 @@ void nvkm_falcon_intr(struct nvkm_subdev *subdev); #define _nvkm_falcon_dtor _nvkm_engine_dtor int _nvkm_falcon_init(struct nvkm_object *); int _nvkm_falcon_fini(struct nvkm_object *, bool); -u32 _nvkm_falcon_rd32(struct nvkm_object *, u64); -void _nvkm_falcon_wr32(struct nvkm_object *, u64, u32); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index bbe07c4d08434..1989f659716c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -75,13 +75,16 @@ static int gf100_ce_init(struct nvkm_object *object) { struct nvkm_falcon *ce = (void *)object; + struct nvkm_device *device = ce->engine.subdev.device; + const int idx = nv_engidx(&ce->engine) - NVDEV_ENGINE_CE0; + u32 base = idx * 0x1000; int ret; ret = nvkm_falcon_init(ce); if (ret) return ret; - nv_wo32(ce, 0x084, nv_engidx(&ce->engine) - NVDEV_ENGINE_CE0); + nvkm_wr32(device, 0x104084 + base, idx); return 0; } @@ -143,8 +146,6 @@ gf100_ce0_oclass = { .dtor = _nvkm_falcon_dtor, .init = gf100_ce_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; @@ -156,7 +157,5 @@ gf100_ce1_oclass = { .dtor = _nvkm_falcon_dtor, .init = gf100_ce_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 49aeeb74990a3..b52acdcaa81e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -72,19 +72,21 @@ gt215_ce_isr_error_name[] = { void gt215_ce_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_falcon *falcon = (void *)subdev; + struct nvkm_falcon *ce = (void *)subdev; + struct nvkm_engine *engine = &ce->engine; + struct nvkm_device *device = engine->subdev.device; + struct nvkm_fifo *fifo = device->fifo; struct nvkm_object *engctx; const struct nvkm_enum *en; - u32 dispatch = nv_ro32(falcon, 0x01c); - u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); - u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff; - u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff; - u32 addr = nv_ro32(falcon, 0x040) >> 16; + const u32 base = (nv_subidx(subdev) - NVDEV_ENGINE_CE0) * 0x1000; + u32 dispatch = nvkm_rd32(device, 0x10401c + base); + u32 stat = nvkm_rd32(device, 0x104008 + base) & dispatch & ~(dispatch >> 16); + u64 inst = nvkm_rd32(device, 0x104050 + base) & 0x3fffffff; + u32 ssta = nvkm_rd32(device, 0x104040 + base) & 0x0000ffff; + u32 addr = nvkm_rd32(device, 0x104040 + base) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; - u32 data = nv_ro32(falcon, 0x044); + u32 data = nvkm_rd32(device, 0x104044 + base); int chid; engctx = nvkm_engctx_get(engine, inst); @@ -97,13 +99,13 @@ gt215_ce_intr(struct nvkm_subdev *subdev) "mthd %04x data %08x\n", ssta, en ? en->name : "", chid, inst << 12, nvkm_client_name(engctx), subc, mthd, data); - nv_wo32(falcon, 0x004, 0x00000040); + nvkm_wr32(device, 0x104004 + base, 0x00000040); stat &= ~0x00000040; } if (stat) { nvkm_error(subdev, "intr %08x\n", stat); - nv_wo32(falcon, 0x004, stat); + nvkm_wr32(device, 0x104004 + base, stat); } nvkm_engctx_put(engctx); @@ -143,7 +145,5 @@ gt215_ce_oclass = { .dtor = _nvkm_falcon_dtor, .init = _nvkm_falcon_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index e0e76756a1277..dcf1782675feb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -27,35 +27,23 @@ void nvkm_falcon_intr(struct nvkm_subdev *subdev) { struct nvkm_falcon *falcon = (void *)subdev; - u32 dispatch = nv_ro32(falcon, 0x01c); - u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16); + struct nvkm_device *device = falcon->engine.subdev.device; + const u32 base = falcon->addr; + u32 dispatch = nvkm_rd32(device, base + 0x01c); + u32 intr = nvkm_rd32(device, base + 0x008) & dispatch & ~(dispatch >> 16); if (intr & 0x00000010) { nvkm_debug(subdev, "ucode halted\n"); - nv_wo32(falcon, 0x004, 0x00000010); + nvkm_wr32(device, base + 0x004, 0x00000010); intr &= ~0x00000010; } if (intr) { nvkm_error(subdev, "intr %08x\n", intr); - nv_wo32(falcon, 0x004, intr); + nvkm_wr32(device, base + 0x004, intr); } } -u32 -_nvkm_falcon_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_falcon *falcon = (void *)object; - return nvkm_rd32(falcon->engine.subdev.device, falcon->addr + addr); -} - -void -_nvkm_falcon_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_falcon *falcon = (void *)object; - nvkm_wr32(falcon->engine.subdev.device, falcon->addr + addr, data); -} - static void * vmemdup(const void *src, size_t len) { @@ -74,6 +62,7 @@ _nvkm_falcon_init(struct nvkm_object *object) struct nvkm_device *device = subdev->device; const struct firmware *fw; char name[32] = "internal"; + const u32 base = falcon->addr; int ret, i; u32 caps; @@ -87,12 +76,12 @@ _nvkm_falcon_init(struct nvkm_object *object) falcon->version = 0; falcon->secret = (falcon->addr == 0x087000) ? 1 : 0; } else { - caps = nv_ro32(falcon, 0x12c); + caps = nvkm_rd32(device, base + 0x12c); falcon->version = (caps & 0x0000000f); falcon->secret = (caps & 0x00000030) >> 4; } - caps = nv_ro32(falcon, 0x108); + caps = nvkm_rd32(device, base + 0x108); falcon->code.limit = (caps & 0x000001ff) << 8; falcon->data.limit = (caps & 0x0003fe00) >> 1; @@ -105,20 +94,20 @@ _nvkm_falcon_init(struct nvkm_object *object) if (falcon->secret && falcon->version < 4) { if (!falcon->version) { nvkm_msec(device, 2000, - if (nv_ro32(falcon, 0x008) & 0x00000010) + if (nvkm_rd32(device, base + 0x008) & 0x00000010) break; ); } else { nvkm_msec(device, 2000, - if (!(nv_ro32(falcon, 0x180) & 0x80000000)) + if (!(nvkm_rd32(device, base + 0x180) & 0x80000000)) break; ); } - nv_wo32(falcon, 0x004, 0x00000010); + nvkm_wr32(device, base + 0x004, 0x00000010); } /* disable all interrupts */ - nv_wo32(falcon, 0x014, 0xffffffff); + nvkm_wr32(device, base + 0x014, 0xffffffff); /* no default ucode provided by the engine implementation, try and * locate a "self-bootstrapping" firmware image for the engine @@ -193,13 +182,13 @@ _nvkm_falcon_init(struct nvkm_object *object) /* upload firmware bootloader (or the full code segments) */ if (falcon->core) { if (device->card_type < NV_C0) - nv_wo32(falcon, 0x618, 0x04000000); + nvkm_wr32(device, base + 0x618, 0x04000000); else - nv_wo32(falcon, 0x618, 0x00000114); - nv_wo32(falcon, 0x11c, 0); - nv_wo32(falcon, 0x110, falcon->core->addr >> 8); - nv_wo32(falcon, 0x114, 0); - nv_wo32(falcon, 0x118, 0x00006610); + nvkm_wr32(device, base + 0x618, 0x00000114); + nvkm_wr32(device, base + 0x11c, 0); + nvkm_wr32(device, base + 0x110, falcon->core->addr >> 8); + nvkm_wr32(device, base + 0x114, 0); + nvkm_wr32(device, base + 0x118, 0x00006610); } else { if (falcon->code.size > falcon->code.limit || falcon->data.size > falcon->data.limit) { @@ -208,39 +197,39 @@ _nvkm_falcon_init(struct nvkm_object *object) } if (falcon->version < 3) { - nv_wo32(falcon, 0xff8, 0x00100000); + nvkm_wr32(device, base + 0xff8, 0x00100000); for (i = 0; i < falcon->code.size / 4; i++) - nv_wo32(falcon, 0xff4, falcon->code.data[i]); + nvkm_wr32(device, base + 0xff4, falcon->code.data[i]); } else { - nv_wo32(falcon, 0x180, 0x01000000); + nvkm_wr32(device, base + 0x180, 0x01000000); for (i = 0; i < falcon->code.size / 4; i++) { if ((i & 0x3f) == 0) - nv_wo32(falcon, 0x188, i >> 6); - nv_wo32(falcon, 0x184, falcon->code.data[i]); + nvkm_wr32(device, base + 0x188, i >> 6); + nvkm_wr32(device, base + 0x184, falcon->code.data[i]); } } } /* upload data segment (if necessary), zeroing the remainder */ if (falcon->version < 3) { - nv_wo32(falcon, 0xff8, 0x00000000); + nvkm_wr32(device, base + 0xff8, 0x00000000); for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) - nv_wo32(falcon, 0xff4, falcon->data.data[i]); + nvkm_wr32(device, base + 0xff4, falcon->data.data[i]); for (; i < falcon->data.limit; i += 4) - nv_wo32(falcon, 0xff4, 0x00000000); + nvkm_wr32(device, base + 0xff4, 0x00000000); } else { - nv_wo32(falcon, 0x1c0, 0x01000000); + nvkm_wr32(device, base + 0x1c0, 0x01000000); for (i = 0; !falcon->core && i < falcon->data.size / 4; i++) - nv_wo32(falcon, 0x1c4, falcon->data.data[i]); + nvkm_wr32(device, base + 0x1c4, falcon->data.data[i]); for (; i < falcon->data.limit / 4; i++) - nv_wo32(falcon, 0x1c4, 0x00000000); + nvkm_wr32(device, base + 0x1c4, 0x00000000); } /* start it running */ - nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */ - nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */ - nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */ - nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */ + nvkm_wr32(device, base + 0x10c, 0x00000001); /* BLOCK_ON_FIFO */ + nvkm_wr32(device, base + 0x104, 0x00000000); /* ENTRY */ + nvkm_wr32(device, base + 0x100, 0x00000002); /* TRIGGER */ + nvkm_wr32(device, base + 0x048, 0x00000003); /* FIFO | CHSW */ return 0; } @@ -248,6 +237,8 @@ int _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) { struct nvkm_falcon *falcon = (void *)object; + struct nvkm_device *device = falcon->engine.subdev.device; + const u32 base = falcon->addr; if (!suspend) { nvkm_gpuobj_ref(NULL, &falcon->core); @@ -258,8 +249,8 @@ _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) } } - nv_mo32(falcon, 0x048, 0x00000003, 0x00000000); - nv_wo32(falcon, 0x014, 0xffffffff); + nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); + nvkm_wr32(device, base + 0x014, 0xffffffff); return nvkm_engine_fini(&falcon->engine, suspend); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index f83d020f05de5..c8a1a1288af6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -100,7 +100,5 @@ g98_mspdec_oclass = { .dtor = _nvkm_falcon_dtor, .init = g98_mspdec_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index 9bbeede03e068..4b759f3e8f51b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -100,7 +100,5 @@ gf100_mspdec_oclass = { .dtor = _nvkm_falcon_dtor, .init = gf100_mspdec_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index fb742b442ce98..ab2923634644e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -100,7 +100,5 @@ gk104_mspdec_oclass = { .dtor = _nvkm_falcon_dtor, .init = gk104_mspdec_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index d681fe63b1bce..80b12ab097814 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -100,7 +100,5 @@ g98_msppp_oclass = { .dtor = _nvkm_falcon_dtor, .init = g98_msppp_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index 7e61f092ef4ab..5f5018bf82809 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -100,7 +100,5 @@ gf100_msppp_oclass = { .dtor = _nvkm_falcon_dtor, .init = gf100_msppp_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index c7d981cad8226..5312cd605dd7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -101,7 +101,5 @@ g98_msvld_oclass = { .dtor = _nvkm_falcon_dtor, .init = g98_msvld_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index 156ebcf22a27f..e5de6db866cfd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -100,7 +100,5 @@ gf100_msvld_oclass = { .dtor = _nvkm_falcon_dtor, .init = gf100_msvld_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index 870e61465b07f..0858765c5201c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -100,7 +100,5 @@ gk104_msvld_oclass = { .dtor = _nvkm_falcon_dtor, .init = gk104_msvld_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index b60719092154c..431bd5aa6c3d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -142,7 +142,5 @@ g98_sec_oclass = { .dtor = _nvkm_falcon_dtor, .init = _nvkm_falcon_init, .fini = _nvkm_falcon_fini, - .rd32 = _nvkm_falcon_rd32, - .wr32 = _nvkm_falcon_wr32, }, }; -- GitLab From 9ccdc76006e3b6ca46c8dbc446bc2e3f6d8d95cb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:13 +1000 Subject: [PATCH 5443/7006] drm/nouveau/xtensa: remove object accessor functions Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/xtensa.h | 2 - drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c | 2 - drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c | 2 - drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 58 ++++++++----------- 4 files changed, 24 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h index bfe49b6f42a4f..5bd4b6e59584c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h @@ -30,6 +30,4 @@ int nvkm_xtensa_create_(struct nvkm_object *, #define _nvkm_xtensa_dtor _nvkm_engine_dtor int _nvkm_xtensa_init(struct nvkm_object *); int _nvkm_xtensa_fini(struct nvkm_object *, bool); -u32 _nvkm_xtensa_rd32(struct nvkm_object *, u64); -void _nvkm_xtensa_wr32(struct nvkm_object *, u64, u32); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c index 6b69d6671173b..0f140bcd8e758 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c @@ -87,7 +87,5 @@ g84_bsp_oclass = { .dtor = _nvkm_xtensa_dtor, .init = _nvkm_xtensa_init, .fini = _nvkm_xtensa_fini, - .rd32 = _nvkm_xtensa_rd32, - .wr32 = _nvkm_xtensa_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c index 703ddcfb207b0..a4ff78a34566a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c @@ -87,7 +87,5 @@ g84_vp_oclass = { .dtor = _nvkm_xtensa_dtor, .init = _nvkm_xtensa_init, .fini = _nvkm_xtensa_fini, - .rd32 = _nvkm_xtensa_rd32, - .wr32 = _nvkm_xtensa_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index 027660c359795..dd5cef1d63302 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -23,20 +23,6 @@ #include -u32 -_nvkm_xtensa_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_xtensa *xtensa = (void *)object; - return nvkm_rd32(xtensa->engine.subdev.device, xtensa->addr + addr); -} - -void -_nvkm_xtensa_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_xtensa *xtensa = (void *)object; - nvkm_wr32(xtensa->engine.subdev.device, xtensa->addr + addr, data); -} - int _nvkm_xtensa_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -56,15 +42,16 @@ _nvkm_xtensa_intr(struct nvkm_subdev *subdev) { struct nvkm_xtensa *xtensa = (void *)subdev; struct nvkm_device *device = xtensa->engine.subdev.device; - u32 unk104 = nv_ro32(xtensa, 0xd04); - u32 intr = nv_ro32(xtensa, 0xc20); - u32 chan = nv_ro32(xtensa, 0xc28); - u32 unk10c = nv_ro32(xtensa, 0xd0c); + const u32 base = xtensa->addr; + u32 unk104 = nvkm_rd32(device, base + 0xd04); + u32 intr = nvkm_rd32(device, base + 0xc20); + u32 chan = nvkm_rd32(device, base + 0xc28); + u32 unk10c = nvkm_rd32(device, base + 0xd0c); if (intr & 0x10) nvkm_warn(subdev, "Watchdog interrupt, engine hung.\n"); - nv_wo32(xtensa, 0xc20, intr); - intr = nv_ro32(xtensa, 0xc20); + nvkm_wr32(device, base + 0xc20, intr); + intr = nvkm_rd32(device, base + 0xc20); if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) { nvkm_debug(subdev, "Enabling FIFO_CTRL\n"); nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->fifo_val); @@ -97,6 +84,7 @@ _nvkm_xtensa_init(struct nvkm_object *object) struct nvkm_xtensa *xtensa = (void *)object; struct nvkm_subdev *subdev = &xtensa->engine.subdev; struct nvkm_device *device = subdev->device; + const u32 base = xtensa->addr; const struct firmware *fw; char name[32]; int i, ret; @@ -137,24 +125,24 @@ _nvkm_xtensa_init(struct nvkm_object *object) release_firmware(fw); } - nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */ - nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */ + nvkm_wr32(device, base + 0xd10, 0x1fffffff); /* ?? */ + nvkm_wr32(device, base + 0xd08, 0x0fffffff); /* ?? */ - nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */ - nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */ - nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */ + nvkm_wr32(device, base + 0xd28, xtensa->unkd28); /* ?? */ + nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ + nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ - nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */ - nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */ - nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */ + nvkm_wr32(device, base + 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */ + nvkm_wr32(device, base + 0xcc4, 0x1c); /* XT_REGION_SETUP */ + nvkm_wr32(device, base + 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */ tmp = nvkm_rd32(device, 0x0); - nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */ + nvkm_wr32(device, base + 0xde0, tmp); /* SCRATCH_H2X */ - nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */ + nvkm_wr32(device, base + 0xce8, 0xf); /* XT_REGION_SETUP */ - nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */ - nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */ + nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ + nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ return 0; } @@ -162,9 +150,11 @@ int _nvkm_xtensa_fini(struct nvkm_object *object, bool suspend) { struct nvkm_xtensa *xtensa = (void *)object; + struct nvkm_device *device = xtensa->engine.subdev.device; + const u32 base = xtensa->addr; - nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */ - nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */ + nvkm_wr32(device, base + 0xd84, 0); /* INTR_EN */ + nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */ if (!suspend) nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw); -- GitLab From 384af9aceaf8ee1e2d3791cc89a32c161d67bb57 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5444/7006] drm/nouveau/gpuobj: type-safe accessor macros These require an explicit struct nvkm_gpuobj pointer, unlike the previous macros which take a void *, and work with any nvkm_object. New semantics require acquiring/releasing a gpuobj before accessing them, which will be made use of in later patches to greatly reduce the overhead of accesses, particularly when a direct mmio mapping of the object is not available (suspend/resume, out of ioremap() space, and on GK20A). Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/core/gpuobj.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index aa98520fa2657..0dd216c055f67 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -60,4 +60,20 @@ int _nvkm_gpuobj_init(struct nvkm_object *); int _nvkm_gpuobj_fini(struct nvkm_object *, bool); u32 _nvkm_gpuobj_rd32(struct nvkm_object *, u64); void _nvkm_gpuobj_wr32(struct nvkm_object *, u64, u32); + +/* accessor macros - kmap()/done() must bracket use of the other accessor + * macros to guarantee correct behaviour across all chipsets + */ +#define nvkm_kmap(o) do { \ + struct nvkm_gpuobj *_gpuobj = (o); \ + (void)_gpuobj; \ +} while(0) +#define nvkm_ro32(o,a) nv_ofuncs(o)->rd32(&(o)->object, (a)) +#define nvkm_wo32(o,a,d) nv_ofuncs(o)->wr32(&(o)->object, (a), (d)) +#define nvkm_mo32(o,a,m,d) ({ \ + u32 _addr = (a), _data = nvkm_ro32((o), _addr); \ + nvkm_wo32((o), _addr, (_data & ~(m)) | (d)); \ + _data; \ +}) +#define nvkm_done(o) nvkm_kmap(o) #endif -- GitLab From 45ea503161af6e94d593a59e8cca8981d0435d5c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5445/7006] drm/nouveau/core: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 8 ++++++-- drivers/gpu/drm/nouveau/nvkm/core/ramht.c | 22 +++++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index c6e5f7a7f0052..f99b446c1e10f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -34,8 +34,10 @@ nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) int i; if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) { + nvkm_kmap(gpuobj); for (i = 0; i < gpuobj->size; i += 4) - nv_wo32(gpuobj, i, 0x00000000); + nvkm_wo32(gpuobj, i, 0x00000000); + nvkm_done(gpuobj); } if (gpuobj->node) @@ -123,8 +125,10 @@ nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, } if (flags & NVOBJ_FLAG_ZERO_ALLOC) { + nvkm_kmap(gpuobj); for (i = 0; i < gpuobj->size; i += 4) - nv_wo32(gpuobj, i, 0x00000000); + nvkm_wo32(gpuobj, i, 0x00000000); + nvkm_done(gpuobj); } return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index ebd4d15479bdb..c61bb0fa93f66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -42,35 +42,43 @@ nvkm_ramht_hash(struct nvkm_ramht *ramht, int chid, u32 handle) int nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context) { + struct nvkm_gpuobj *gpuobj = &ramht->gpuobj; struct nvkm_bar *bar = nvkm_bar(ramht); + int ret = -ENOSPC; u32 co, ho; co = ho = nvkm_ramht_hash(ramht, chid, handle); + nvkm_kmap(gpuobj); do { - if (!nv_ro32(ramht, co + 4)) { - nv_wo32(ramht, co + 0, handle); - nv_wo32(ramht, co + 4, context); + if (!nvkm_ro32(gpuobj, co + 4)) { + nvkm_wo32(gpuobj, co + 0, handle); + nvkm_wo32(gpuobj, co + 4, context); if (bar) bar->flush(bar); - return co; + ret = co; + break; } co += 8; if (co >= nv_gpuobj(ramht)->size) co = 0; } while (co != ho); + nvkm_done(gpuobj); - return -ENOMEM; + return ret; } void nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie) { + struct nvkm_gpuobj *gpuobj = &ramht->gpuobj; struct nvkm_bar *bar = nvkm_bar(ramht); - nv_wo32(ramht, cookie + 0, 0x00000000); - nv_wo32(ramht, cookie + 4, 0x00000000); + nvkm_kmap(gpuobj); + nvkm_wo32(gpuobj, cookie + 0, 0x00000000); + nvkm_wo32(gpuobj, cookie + 4, 0x00000000); if (bar) bar->flush(bar); + nvkm_done(gpuobj); } static struct nvkm_oclass -- GitLab From 1918707556986e9460682845a2bf4055c43a8b65 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5446/7006] drm/nouveau/bar: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 10 +++--- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 32 +++++++++++-------- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 09e36b64d889d..b997d8d128c53 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -122,10 +122,12 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, if (ret) return ret; - nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr)); - nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr)); - nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1)); - nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1)); + nvkm_kmap(bar_vm->mem); + nvkm_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr)); + nvkm_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr)); + nvkm_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1)); + nvkm_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1)); + nvkm_done(bar_vm->mem); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index a47d64d3b0fd3..6909e52a6d8d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -166,13 +166,15 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(bar->bar3, 0x00, 0x7fc00000); - nv_wo32(bar->bar3, 0x04, lower_32_bits(limit)); - nv_wo32(bar->bar3, 0x08, lower_32_bits(start)); - nv_wo32(bar->bar3, 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(bar->bar3, 0x10, 0x00000000); - nv_wo32(bar->bar3, 0x14, 0x00000000); + nvkm_kmap(bar->bar3); + nvkm_wo32(bar->bar3, 0x00, 0x7fc00000); + nvkm_wo32(bar->bar3, 0x04, lower_32_bits(limit)); + nvkm_wo32(bar->bar3, 0x08, lower_32_bits(start)); + nvkm_wo32(bar->bar3, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(bar->bar3, 0x10, 0x00000000); + nvkm_wo32(bar->bar3, 0x14, 0x00000000); + nvkm_done(bar->bar3); /* BAR1 */ start = 0x0000000000ULL; @@ -193,13 +195,15 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(bar->bar1, 0x00, 0x7fc00000); - nv_wo32(bar->bar1, 0x04, lower_32_bits(limit)); - nv_wo32(bar->bar1, 0x08, lower_32_bits(start)); - nv_wo32(bar->bar1, 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(bar->bar1, 0x10, 0x00000000); - nv_wo32(bar->bar1, 0x14, 0x00000000); + nvkm_kmap(bar->bar1); + nvkm_wo32(bar->bar1, 0x00, 0x7fc00000); + nvkm_wo32(bar->bar1, 0x04, lower_32_bits(limit)); + nvkm_wo32(bar->bar1, 0x08, lower_32_bits(start)); + nvkm_wo32(bar->bar1, 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(bar->bar1, 0x10, 0x00000000); + nvkm_wo32(bar->bar1, 0x14, 0x00000000); + nvkm_done(bar->bar1); bar->base.alloc = nvkm_bar_alloc; bar->base.kmap = nv50_bar_kmap; -- GitLab From cd821077aa7f180f83f3a5d60ec47cb75d56fd37 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5447/7006] drm/nouveau/mmu: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 24 ++++++++----- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 14 +++++--- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 8 +++-- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 36 ++++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 24 ++++++++----- 5 files changed, 68 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index f0b6f590ec764..13798fdac1a80 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -79,8 +79,10 @@ gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_gpuobj *pgt[2]) if (pgt[1]) pde[0] = 0x00000001 | (pgt[1]->addr >> 8); - nv_wo32(pgd, (index * 8) + 0, pde[0]); - nv_wo32(pgd, (index * 8) + 4, pde[1]); + nvkm_kmap(pgd); + nvkm_wo32(pgd, (index * 8) + 0, pde[0]); + nvkm_wo32(pgd, (index * 8) + 4, pde[1]); + nvkm_done(pgd); } static inline u64 @@ -114,12 +116,14 @@ gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, ltc->tags_clear(ltc, tag, cnt); } + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte + 0, lower_32_bits(phys)); - nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + nvkm_wo32(pgt, pte + 0, lower_32_bits(phys)); + nvkm_wo32(pgt, pte + 4, upper_32_bits(phys)); phys += next; pte += 8; } + nvkm_done(pgt); } static void @@ -130,24 +134,28 @@ gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, /* compressed storage types are invalid for system memory */ u32 memtype = gf100_pte_storage_type_map[mem->memtype & 0xff]; + nvkm_kmap(pgt); pte <<= 3; while (cnt--) { u64 phys = gf100_vm_addr(vma, *list++, memtype, target); - nv_wo32(pgt, pte + 0, lower_32_bits(phys)); - nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + nvkm_wo32(pgt, pte + 0, lower_32_bits(phys)); + nvkm_wo32(pgt, pte + 4, upper_32_bits(phys)); pte += 8; } + nvkm_done(pgt); } static void gf100_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) { + nvkm_kmap(pgt); pte <<= 3; while (cnt--) { - nv_wo32(pgt, pte + 0, 0x00000000); - nv_wo32(pgt, pte + 4, 0x00000000); + nvkm_wo32(pgt, pte + 0, 0x00000000); + nvkm_wo32(pgt, pte + 4, 0x00000000); pte += 8; } + nvkm_done(pgt); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index 5c66720ed2521..57b13d2a348ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -37,26 +37,30 @@ nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { pte = 0x00008 + (pte * 4); + nvkm_kmap(pgt); while (cnt) { u32 page = PAGE_SIZE / NV04_PDMA_PAGE; u32 phys = (u32)*list++; while (cnt && page--) { - nv_wo32(pgt, pte, phys | 3); + nvkm_wo32(pgt, pte, phys | 3); phys += NV04_PDMA_PAGE; pte += 4; cnt -= 1; } } + nvkm_done(pgt); } static void nv04_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) { pte = 0x00008 + (pte * 4); + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte, 0x00000000); + nvkm_wo32(pgt, pte, 0x00000000); pte += 4; } + nvkm_done(pgt); } static void @@ -118,8 +122,10 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */ - nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1); + nvkm_kmap(dma); + nvkm_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */ + nvkm_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1); + nvkm_done(dma); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 378cd1d363aec..c44f880120abf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -39,26 +39,30 @@ nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { pte = pte * 4; + nvkm_kmap(pgt); while (cnt) { u32 page = PAGE_SIZE / NV41_GART_PAGE; u64 phys = (u64)*list++; while (cnt && page--) { - nv_wo32(pgt, pte, (phys >> 7) | 1); + nvkm_wo32(pgt, pte, (phys >> 7) | 1); phys += NV41_GART_PAGE; pte += 4; cnt -= 1; } } + nvkm_done(pgt); } static void nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) { pte = pte * 4; + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte, 0x00000000); + nvkm_wo32(pgt, pte, 0x00000000); pte += 4; } + nvkm_done(pgt); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 76e1a657dfc94..3be8a796d797b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -41,10 +41,10 @@ nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null, u32 base = (pte << 2) & ~0x0000000f; u32 tmp[4]; - tmp[0] = nv_ro32(pgt, base + 0x0); - tmp[1] = nv_ro32(pgt, base + 0x4); - tmp[2] = nv_ro32(pgt, base + 0x8); - tmp[3] = nv_ro32(pgt, base + 0xc); + tmp[0] = nvkm_ro32(pgt, base + 0x0); + tmp[1] = nvkm_ro32(pgt, base + 0x4); + tmp[2] = nvkm_ro32(pgt, base + 0x8); + tmp[3] = nvkm_ro32(pgt, base + 0xc); while (cnt--) { u32 addr = list ? (*list++ >> 12) : (null >> 12); @@ -74,10 +74,10 @@ nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null, } } - nv_wo32(pgt, base + 0x0, tmp[0]); - nv_wo32(pgt, base + 0x4, tmp[1]); - nv_wo32(pgt, base + 0x8, tmp[2]); - nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000); + nvkm_wo32(pgt, base + 0x0, tmp[0]); + nvkm_wo32(pgt, base + 0x4, tmp[1]); + nvkm_wo32(pgt, base + 0x8, tmp[2]); + nvkm_wo32(pgt, base + 0xc, tmp[3] | 0x40000000); } static void @@ -88,6 +88,7 @@ nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, u32 tmp[4]; int i; + nvkm_kmap(pgt); if (pte & 3) { u32 max = 4 - (pte & 3); u32 part = (cnt > max) ? max : cnt; @@ -100,15 +101,16 @@ nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, while (cnt >= 4) { for (i = 0; i < 4; i++) tmp[i] = *list++ >> 12; - nv_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27); - nv_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22); - nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17); - nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000); + nvkm_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27); + nvkm_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22); + nvkm_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17); + nvkm_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000); cnt -= 4; } if (cnt) nv44_vm_fill(pgt, mmu->null, list, pte, cnt); + nvkm_done(pgt); } static void @@ -116,6 +118,7 @@ nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) { struct nv04_mmu *mmu = (void *)nvkm_mmu(pgt); + nvkm_kmap(pgt); if (pte & 3) { u32 max = 4 - (pte & 3); u32 part = (cnt > max) ? max : cnt; @@ -125,15 +128,16 @@ nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) } while (cnt >= 4) { - nv_wo32(pgt, pte++ * 4, 0x00000000); - nv_wo32(pgt, pte++ * 4, 0x00000000); - nv_wo32(pgt, pte++ * 4, 0x00000000); - nv_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); + nvkm_wo32(pgt, pte++ * 4, 0x00000000); cnt -= 4; } if (cnt) nv44_vm_fill(pgt, mmu->null, NULL, pte, cnt); + nvkm_done(pgt); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index 0216c881fa387..cec41ca80f4b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -53,8 +53,10 @@ nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2]) phys |= 0x20; } - nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); - nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); + nvkm_kmap(pgd); + nvkm_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys)); + nvkm_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys)); + nvkm_done(pgd); } static inline u64 @@ -89,6 +91,7 @@ nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, pte <<= 3; cnt <<= 3; + nvkm_kmap(pgt); while (cnt) { u32 offset_h = upper_32_bits(phys); u32 offset_l = lower_32_bits(phys); @@ -109,12 +112,13 @@ nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } while (block) { - nv_wo32(pgt, pte + 0, offset_l); - nv_wo32(pgt, pte + 4, offset_h); + nvkm_wo32(pgt, pte + 0, offset_l); + nvkm_wo32(pgt, pte + 4, offset_h); pte += 8; block -= 8; } } + nvkm_done(pgt); } static void @@ -123,23 +127,27 @@ nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, { u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2; pte <<= 3; + nvkm_kmap(pgt); while (cnt--) { u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target); - nv_wo32(pgt, pte + 0, lower_32_bits(phys)); - nv_wo32(pgt, pte + 4, upper_32_bits(phys)); + nvkm_wo32(pgt, pte + 0, lower_32_bits(phys)); + nvkm_wo32(pgt, pte + 4, upper_32_bits(phys)); pte += 8; } + nvkm_done(pgt); } static void nv50_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) { pte <<= 3; + nvkm_kmap(pgt); while (cnt--) { - nv_wo32(pgt, pte + 0, 0x00000000); - nv_wo32(pgt, pte + 4, 0x00000000); + nvkm_wo32(pgt, pte + 0, 0x00000000); + nvkm_wo32(pgt, pte + 4, 0x00000000); pte += 8; } + nvkm_done(pgt); } static void -- GitLab From 9cc264a3aac2ca62d8a2e13c8f13c8ef8567550b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5448/7006] drm/nouveau/falcon: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index dcf1782675feb..d2849ece1ba66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -175,8 +175,10 @@ _nvkm_falcon_init(struct nvkm_object *object) return ret; } + nvkm_kmap(falcon->core); for (i = 0; i < falcon->code.size; i += 4) - nv_wo32(falcon->core, i, falcon->code.data[i / 4]); + nvkm_wo32(falcon->core, i, falcon->code.data[i / 4]); + nvkm_done(falcon->core); } /* upload firmware bootloader (or the full code segments) */ -- GitLab From edb1dc51de2f93905f49ba693c1777d6497a5cae Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5449/7006] drm/nouveau/xtensa: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index dd5cef1d63302..974d7a0d7a36b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -120,8 +120,10 @@ _nvkm_xtensa_init(struct nvkm_object *object) nvkm_debug(subdev, "Loading firmware to address: %010llx\n", xtensa->gpu_fw->addr); + nvkm_kmap(xtensa->gpu_fw); for (i = 0; i < fw->size / 4; i++) - nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); + nvkm_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); + nvkm_done(xtensa->gpu_fw); release_firmware(fw); } -- GitLab From 6d06fd68cb8d3c8be819d96bffb0a342d01b5e22 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5450/7006] drm/nouveau/cipher: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index ddc240d25d817..312df6fa57078 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -47,10 +47,12 @@ g84_cipher_object_ctor(struct nvkm_object *parent, if (ret) return ret; - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); + nvkm_kmap(obj); + nvkm_wo32(obj, 0x00, nv_mclass(obj)); + nvkm_wo32(obj, 0x04, 0x00000000); + nvkm_wo32(obj, 0x08, 0x00000000); + nvkm_wo32(obj, 0x0c, 0x00000000); + nvkm_done(obj); return 0; } -- GitLab From 3f532ef1e23395d7abb0eed316dd31123f87f448 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5451/7006] drm/nouveau/dma: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c | 16 +++++++++------- .../gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c | 14 ++++++++------ .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c | 14 +++++++++----- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c | 16 +++++++++------- 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c index f5dc4f23a1b47..499a7c7e024a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c @@ -57,13 +57,15 @@ gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | - upper_32_bits(dmaobj->base.start)); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, dmaobj->flags5); + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); + nvkm_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); + nvkm_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | + upper_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_wo32(*pgpuobj, 0x14, dmaobj->flags5); + nvkm_done(*pgpuobj); } return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c index a3ea461f7f326..a28cf56454e46 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c @@ -63,12 +63,14 @@ gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, dmaobj->flags0); - nv_wo32(*pgpuobj, 0x04, dmaobj->base.start >> 8); - nv_wo32(*pgpuobj, 0x08, dmaobj->base.limit >> 8); - nv_wo32(*pgpuobj, 0x0c, 0x00000000); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, 0x00000000); + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); + nvkm_wo32(*pgpuobj, 0x04, dmaobj->base.start >> 8); + nvkm_wo32(*pgpuobj, 0x08, dmaobj->base.limit >> 8); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_wo32(*pgpuobj, 0x14, 0x00000000); + nvkm_done(*pgpuobj); } return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c index 21c5c90b06a8b..60c962bc0e477 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c @@ -64,17 +64,21 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0]; if (!dmaobj->base.start) return nvkm_gpuobj_dup(parent, pgt, pgpuobj); - offset = nv_ro32(pgt, 8 + (offset >> 10)); + nvkm_kmap(pgt); + offset = nvkm_ro32(pgt, 8 + (offset >> 10)); offset &= 0xfffff000; + nvkm_done(pgt); } ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); *pgpuobj = gpuobj; if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, dmaobj->flags0 | (adjust << 20)); - nv_wo32(*pgpuobj, 0x04, length); - nv_wo32(*pgpuobj, 0x08, dmaobj->flags2 | offset); - nv_wo32(*pgpuobj, 0x0c, dmaobj->flags2 | offset); + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | (adjust << 20)); + nvkm_wo32(*pgpuobj, 0x04, length); + nvkm_wo32(*pgpuobj, 0x08, dmaobj->flags2 | offset); + nvkm_wo32(*pgpuobj, 0x0c, dmaobj->flags2 | offset); + nvkm_done(*pgpuobj); } return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c index ba95f549463f9..3566fa9b3ba97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c @@ -69,13 +69,15 @@ nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); if (ret == 0) { - nv_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); - nv_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); - nv_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); - nv_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | - upper_32_bits(dmaobj->base.start)); - nv_wo32(*pgpuobj, 0x10, 0x00000000); - nv_wo32(*pgpuobj, 0x14, dmaobj->flags5); + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); + nvkm_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); + nvkm_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | + upper_32_bits(dmaobj->base.start)); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_wo32(*pgpuobj, 0x14, dmaobj->flags5); + nvkm_done(*pgpuobj); } return ret; -- GitLab From 5444e770e3991ddb5a9583d622fc18bbf414b551 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5452/7006] drm/nouveau/fifo: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 92 ++++++++++--------- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 71 ++++++++------ .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 67 ++++++++------ .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 18 ++-- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 20 ++-- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 90 ++++++++++-------- 8 files changed, 220 insertions(+), 158 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 9024dc893218b..c4f48112aa059 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -65,14 +65,16 @@ g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) } nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - nv_wo32(base->eng, addr + 0x00, 0x00190000); - nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00190000); + nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); + nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); bar->flush(bar); + nvkm_done(base->eng); return 0; } @@ -119,13 +121,15 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EBUSY; } - nv_wo32(base->eng, addr + 0x00, 0x00000000); - nv_wo32(base->eng, addr + 0x04, 0x00000000); - nv_wo32(base->eng, addr + 0x08, 0x00000000); - nv_wo32(base->eng, addr + 0x0c, 0x00000000); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00000000); + nvkm_wo32(base->eng, addr + 0x04, 0x00000000); + nvkm_wo32(base->eng, addr + 0x08, 0x00000000); + nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); bar->flush(bar); + nvkm_done(base->eng); return 0; } @@ -216,23 +220,25 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nv_parent(chan)->object_attach = g84_fifo_object_attach; nv_parent(chan)->object_detach = nv50_fifo_object_detach; - nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x3c, 0x003f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x4c, 0xffffffff); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); - nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj.node->offset >> 4)); + nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); + nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); bar->flush(bar); + nvkm_done(base->ramfc); return 0; } @@ -294,20 +300,22 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); - nv_wo32(base->ramfc, 0x3c, 0x403f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); - nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj.node->offset >> 4)); + nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); + nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); bar->flush(bar); + nvkm_done(base->ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index b043d08a35c9a..d940d41d1182c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -86,15 +86,17 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) cur = fifo->runlist.mem[fifo->runlist.active]; fifo->runlist.active = !fifo->runlist.active; + nvkm_kmap(cur); for (i = 0, p = 0; i < 128; i++) { struct gf100_fifo_chan *chan = (void *)fifo->base.channel[i]; if (chan && chan->state == RUNNING) { - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000004); + nvkm_wo32(cur, p + 0, i); + nvkm_wo32(cur, p + 4, 0x00000004); p += 8; } } bar->flush(bar); + nvkm_done(cur); nvkm_wr32(device, 0x002270, cur->addr >> 12); nvkm_wr32(device, 0x002274, 0x01f00000 | (p >> 3)); @@ -112,6 +114,7 @@ gf100_fifo_context_attach(struct nvkm_object *parent, { struct nvkm_bar *bar = nvkm_bar(parent); struct gf100_fifo_base *base = (void *)parent->parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; struct nvkm_engctx *ectx = (void *)object; u32 addr; int ret; @@ -137,9 +140,11 @@ gf100_fifo_context_attach(struct nvkm_object *parent, nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; } - nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset)); + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); + nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); bar->flush(bar); + nvkm_done(engn); return 0; } @@ -150,6 +155,7 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct gf100_fifo *fifo = (void *)parent->engine; struct gf100_fifo_base *base = (void *)parent->parent; struct gf100_fifo_chan *chan = (void *)parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; struct nvkm_bar *bar = device->bar; @@ -178,9 +184,11 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, return -EBUSY; } - nv_wo32(base, addr + 0x00, 0x00000000); - nv_wo32(base, addr + 0x04, 0x00000000); + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, 0x00000000); + nvkm_wo32(engn, addr + 0x04, 0x00000000); bar->flush(bar); + nvkm_done(engn); return 0; } @@ -196,6 +204,7 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct gf100_fifo *fifo = (void *)engine; struct gf100_fifo_base *base = (void *)parent; struct gf100_fifo_chan *chan; + struct nvkm_gpuobj *ramfc = &base->base.gpuobj; u64 usermem, ioffset, ilength; int ret, i; @@ -231,26 +240,30 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); + nvkm_kmap(fifo->user.mem); for (i = 0; i < 0x1000; i += 4) - nv_wo32(fifo->user.mem, usermem + i, 0x00000000); - - nv_wo32(base, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); - nv_wo32(base, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); - nv_wo32(base, 0x10, 0x0000face); - nv_wo32(base, 0x30, 0xfffff902); - nv_wo32(base, 0x48, lower_32_bits(ioffset)); - nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base, 0x54, 0x00000002); - nv_wo32(base, 0x84, 0x20400000); - nv_wo32(base, 0x94, 0x30000001); - nv_wo32(base, 0x9c, 0x00000100); - nv_wo32(base, 0xa4, 0x1f1f1f1f); - nv_wo32(base, 0xa8, 0x1f1f1f1f); - nv_wo32(base, 0xac, 0x0000001f); - nv_wo32(base, 0xb8, 0xf8000000); - nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); + nvkm_done(fifo->user.mem); + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); + nvkm_wo32(ramfc, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); + nvkm_wo32(ramfc, 0x10, 0x0000face); + nvkm_wo32(ramfc, 0x30, 0xfffff902); + nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(ramfc, 0x54, 0x00000002); + nvkm_wo32(ramfc, 0x84, 0x20400000); + nvkm_wo32(ramfc, 0x94, 0x30000001); + nvkm_wo32(ramfc, 0x9c, 0x00000100); + nvkm_wo32(ramfc, 0xa4, 0x1f1f1f1f); + nvkm_wo32(ramfc, 0xa8, 0x1f1f1f1f); + nvkm_wo32(ramfc, 0xac, 0x0000001f); + nvkm_wo32(ramfc, 0xb8, 0xf8000000); + nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ bar->flush(bar); + nvkm_done(ramfc); return 0; } @@ -341,10 +354,12 @@ gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0208, 0xffffffff); - nv_wo32(base, 0x020c, 0x000000ff); + nvkm_kmap(&base->base.gpuobj); + nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); + nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); + nvkm_done(&base->base.gpuobj); ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index ce12e4e12b220..9a1ecef248139 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -106,15 +106,17 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) cur = engn->runlist[engn->cur_runlist]; engn->cur_runlist = !engn->cur_runlist; + nvkm_kmap(cur); for (i = 0, p = 0; i < fifo->base.max; i++) { struct gk104_fifo_chan *chan = (void *)fifo->base.channel[i]; if (chan && chan->state == RUNNING && chan->engine == engine) { - nv_wo32(cur, p + 0, i); - nv_wo32(cur, p + 4, 0x00000000); + nvkm_wo32(cur, p + 0, i); + nvkm_wo32(cur, p + 4, 0x00000000); p += 8; } } bar->flush(bar); + nvkm_done(cur); nvkm_wr32(device, 0x002270, cur->addr >> 12); nvkm_wr32(device, 0x002274, (engine << 20) | (p >> 3)); @@ -132,6 +134,7 @@ gk104_fifo_context_attach(struct nvkm_object *parent, { struct nvkm_bar *bar = nvkm_bar(parent); struct gk104_fifo_base *base = (void *)parent->parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; struct nvkm_engctx *ectx = (void *)object; u32 addr; int ret; @@ -161,9 +164,11 @@ gk104_fifo_context_attach(struct nvkm_object *parent, nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; } - nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset)); + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); + nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); bar->flush(bar); + nvkm_done(engn); return 0; } @@ -195,6 +200,7 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_bar *bar = nvkm_bar(parent); struct gk104_fifo_base *base = (void *)parent->parent; struct gk104_fifo_chan *chan = (void *)parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; u32 addr; int ret; @@ -216,9 +222,11 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, return ret; if (addr) { - nv_wo32(base, addr + 0x00, 0x00000000); - nv_wo32(base, addr + 0x04, 0x00000000); + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, 0x00000000); + nvkm_wo32(engn, addr + 0x04, 0x00000000); bar->flush(bar); + nvkm_done(engn); } return 0; @@ -237,6 +245,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct gk104_fifo_base *base = (void *)parent; struct gk104_fifo_chan *chan; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_gpuobj *ramfc = &base->base.gpuobj; u64 usermem, ioffset, ilength; int ret, i; @@ -282,24 +291,28 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); + nvkm_kmap(fifo->user.mem); for (i = 0; i < 0x200; i += 4) - nv_wo32(fifo->user.mem, usermem + i, 0x00000000); - - nv_wo32(base, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); - nv_wo32(base, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); - nv_wo32(base, 0x10, 0x0000face); - nv_wo32(base, 0x30, 0xfffff902); - nv_wo32(base, 0x48, lower_32_bits(ioffset)); - nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base, 0x84, 0x20400000); - nv_wo32(base, 0x94, 0x30000001); - nv_wo32(base, 0x9c, 0x00000100); - nv_wo32(base, 0xac, 0x0000001f); - nv_wo32(base, 0xe8, chan->base.chid); - nv_wo32(base, 0xb8, 0xf8000000); - nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */ - nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); + nvkm_done(fifo->user.mem); + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); + nvkm_wo32(ramfc, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); + nvkm_wo32(ramfc, 0x10, 0x0000face); + nvkm_wo32(ramfc, 0x30, 0xfffff902); + nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(ramfc, 0x84, 0x20400000); + nvkm_wo32(ramfc, 0x94, 0x30000001); + nvkm_wo32(ramfc, 0x9c, 0x00000100); + nvkm_wo32(ramfc, 0xac, 0x0000001f); + nvkm_wo32(ramfc, 0xe8, chan->base.chid); + nvkm_wo32(ramfc, 0xb8, 0xf8000000); + nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ bar->flush(bar); + nvkm_done(ramfc); return 0; } @@ -387,10 +400,12 @@ gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr)); - nv_wo32(base, 0x0208, 0xffffffff); - nv_wo32(base, 0x020c, 0x000000ff); + nvkm_kmap(&base->base.gpuobj); + nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); + nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); + nvkm_done(&base->base.gpuobj); ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 5eca5de292f6f..d5346636b7e35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -142,16 +142,18 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); - nv_wo32(fifo->ramfc, chan->ramfc + 0x10, + nvkm_kmap(fifo->ramfc); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(fifo->ramfc); return 0; } @@ -162,9 +164,11 @@ nv04_fifo_chan_dtor(struct nvkm_object *object) struct nv04_fifo_chan *chan = (void *)object; struct ramfc_desc *c = fifo->ramfc_desc; + nvkm_kmap(fifo->ramfc); do { - nv_wo32(fifo->ramfc, chan->ramfc + c->ctxp, 0x00000000); + nvkm_wo32(fifo->ramfc, chan->ramfc + c->ctxp, 0x00000000); } while ((++c)->bits); + nvkm_done(fifo->ramfc); nvkm_fifo_channel_destroy(&chan->base); } @@ -217,8 +221,8 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) u32 rm = ((1ULL << c->bits) - 1) << c->regs; u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; - u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm); - nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); + u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); + nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); } while ((++c)->bits); c = fifo->ramfc_desc; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 2c38d6f36fe73..5a7b11f926842 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -86,16 +86,18 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(fifo->ramfc, chan->ramfc + 0x14, + nvkm_kmap(fifo->ramfc); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(fifo->ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 55857665180c5..537bb7229e3d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -93,16 +93,18 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 64; - nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(fifo->ramfc, chan->ramfc + 0x14, + nvkm_kmap(fifo->ramfc); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(fifo->ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index b6c7af527d6ac..27f07d1db85f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -130,7 +130,9 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) nvkm_wr32(device, reg, nv_engctx(engctx)->addr); - nv_wo32(fifo->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + nvkm_kmap(fifo->ramfc); + nvkm_wo32(fifo->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + nvkm_done(fifo->ramfc); nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); @@ -167,7 +169,9 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) nvkm_wr32(device, reg, 0x00000000); - nv_wo32(fifo->ramfc, chan->ramfc + ctx, 0x00000000); + nvkm_kmap(fifo->ramfc); + nvkm_wo32(fifo->ramfc, chan->ramfc + ctx, 0x00000000); + nvkm_done(fifo->ramfc); nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); @@ -212,17 +216,19 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_parent(chan)->object_detach = nv04_fifo_object_detach; chan->ramfc = chan->base.chid * 128; - nv_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nv_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nv_wo32(fifo->ramfc, chan->ramfc + 0x18, 0x30000000 | + nvkm_kmap(fifo->ramfc); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nv_wo32(fifo->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + nvkm_wo32(fifo->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + nvkm_done(fifo->ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 920b3c91b9edf..24154778c01e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -49,12 +49,13 @@ nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) cur = fifo->playlist[fifo->cur_playlist]; fifo->cur_playlist = !fifo->cur_playlist; + nvkm_kmap(cur); for (i = fifo->base.min, p = 0; i < fifo->base.max; i++) { if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000) - nv_wo32(cur, p++ * 4, i); + nvkm_wo32(cur, p++ * 4, i); } - bar->flush(bar); + nvkm_done(cur); nvkm_wr32(device, 0x0032f4, cur->addr >> 12); nvkm_wr32(device, 0x0032ec, p); @@ -88,14 +89,17 @@ nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) } nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - nv_wo32(base->eng, addr + 0x00, 0x00190000); - nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nv_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); + + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00190000); + nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); + nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); bar->flush(bar); + nvkm_done(base->eng); return 0; } @@ -148,13 +152,15 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, nvkm_wr32(device, 0x00b860, me); if (ret == 0) { - nv_wo32(base->eng, addr + 0x00, 0x00000000); - nv_wo32(base->eng, addr + 0x04, 0x00000000); - nv_wo32(base->eng, addr + 0x08, 0x00000000); - nv_wo32(base->eng, addr + 0x0c, 0x00000000); - nv_wo32(base->eng, addr + 0x10, 0x00000000); - nv_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00000000); + nvkm_wo32(base->eng, addr + 0x04, 0x00000000); + nvkm_wo32(base->eng, addr + 0x08, 0x00000000); + nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); bar->flush(bar); + nvkm_done(base->eng); } return ret; @@ -234,21 +240,23 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nv_wo32(base->ramfc, 0x3c, 0x003f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x4c, 0xffffffff); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj.node->offset >> 4)); bar->flush(bar); + nvkm_done(base->ramfc); return 0; } @@ -300,18 +308,20 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); - nv_wo32(base->ramfc, 0x3c, 0x403f6078); - nv_wo32(base->ramfc, 0x44, 0x01003fff); - nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nv_wo32(base->ramfc, 0x60, 0x7fffffff); - nv_wo32(base->ramfc, 0x78, 0x00000000); - nv_wo32(base->ramfc, 0x7c, 0x30000001); - nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj.node->offset >> 4)); bar->flush(bar); + nvkm_done(base->ramfc); return 0; } -- GitLab From 142ea05f49b9517929f8b27ee800160e7ebf3a02 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5453/7006] drm/nouveau/gr: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 37 ++++---- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h | 11 ++- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 16 +++- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 47 ++++++---- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 45 +++++---- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 84 +++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 92 ++++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 74 ++++++++------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 88 +++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 86 ++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 86 ++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 16 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 10 +- 14 files changed, 385 insertions(+), 317 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 7854baff33747..f36e0896ae9c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1289,27 +1289,28 @@ gf100_grctx_generate(struct gf100_gr *gr) } /* PGD pointer */ - nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000)); - nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000)); - nv_wo32(chan, 0x0208, 0xffffffff); - nv_wo32(chan, 0x020c, 0x000000ff); + nvkm_kmap(chan); + nvkm_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000)); + nvkm_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000)); + nvkm_wo32(chan, 0x0208, 0xffffffff); + nvkm_wo32(chan, 0x020c, 0x000000ff); /* PGT[0] pointer */ - nv_wo32(chan, 0x1000, 0x00000000); - nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8); + nvkm_wo32(chan, 0x1000, 0x00000000); + nvkm_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8); /* identity-map the whole "channel" into its own vm */ for (i = 0; i < chan->size / 4096; i++) { u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1; - nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr)); - nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr)); + nvkm_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr)); + nvkm_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr)); } /* context pointer (virt) */ - nv_wo32(chan, 0x0210, 0x00080004); - nv_wo32(chan, 0x0214, 0x00000000); - + nvkm_wo32(chan, 0x0210, 0x00080004); + nvkm_wo32(chan, 0x0214, 0x00000000); bar->flush(bar); + nvkm_done(chan); nvkm_wr32(device, 0x100cb8, (chan->addr + 0x1000) >> 8); nvkm_wr32(device, 0x100cbc, 0x80000001); @@ -1335,11 +1336,13 @@ gf100_grctx_generate(struct gf100_gr *gr) break; ); - nv_wo32(chan, 0x8001c, 1); - nv_wo32(chan, 0x80020, 0); - nv_wo32(chan, 0x80028, 0); - nv_wo32(chan, 0x8002c, 0); + nvkm_kmap(chan); + nvkm_wo32(chan, 0x8001c, 1); + nvkm_wo32(chan, 0x80020, 0); + nvkm_wo32(chan, 0x80028, 0); + nvkm_wo32(chan, 0x8002c, 0); bar->flush(bar); + nvkm_done(chan); } else { nvkm_wr32(device, 0x409840, 0x80000000); nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); @@ -1367,8 +1370,10 @@ gf100_grctx_generate(struct gf100_gr *gr) gr->data = kmalloc(gr->size, GFP_KERNEL); if (gr->data) { + nvkm_kmap(chan); for (i = 0; i < gr->size; i += 4) - gr->data[i / 4] = nv_ro32(chan, 0x80000 + i); + gr->data[i / 4] = nvkm_ro32(chan, 0x80000 + i); + nvkm_done(chan); ret = 0; } else { ret = -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c index 0c717084b44fb..8ecdc94e3538b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c @@ -580,16 +580,18 @@ nv40_gr_construct_shader(struct nvkm_grctx *ctx) if (ctx->mode != NVKM_GRCTX_VALS) return; + nvkm_kmap(obj); offset += 0x0280/4; for (i = 0; i < 16; i++, offset += 2) - nv_wo32(obj, offset * 4, 0x3f800000); + nvkm_wo32(obj, offset * 4, 0x3f800000); for (vs = 0; vs < vs_nr; vs++, offset += vs_len) { for (i = 0; i < vs_nr_b0 * 6; i += 6) - nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001); + nvkm_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001); for (i = 0; i < vs_nr_b1 * 4; i += 4) - nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); + nvkm_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); } + nvkm_done(obj); } static void @@ -674,7 +676,7 @@ nv40_grctx_init(struct nvkm_device *device, u32 *size) struct nvkm_grctx ctx = { .device = device, .mode = NVKM_GRCTX_PROG, - .data = ctxprog, + .ucode = ctxprog, .ctxprog_max = 256, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h index 8a89961956af6..6170b21b50ccf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h @@ -9,7 +9,8 @@ struct nvkm_grctx { NVKM_GRCTX_PROG, NVKM_GRCTX_VALS } mode; - void *data; + u32 *ucode; + struct nvkm_gpuobj *data; u32 ctxprog_max; u32 ctxprog_len; @@ -22,7 +23,7 @@ struct nvkm_grctx { static inline void cp_out(struct nvkm_grctx *ctx, u32 inst) { - u32 *ctxprog = ctx->data; + u32 *ctxprog = ctx->ucode; if (ctx->mode != NVKM_GRCTX_PROG) return; @@ -56,7 +57,7 @@ cp_ctx(struct nvkm_grctx *ctx, u32 reg, u32 length) static inline void cp_name(struct nvkm_grctx *ctx, int name) { - u32 *ctxprog = ctx->data; + u32 *ctxprog = ctx->ucode; int i; if (ctx->mode != NVKM_GRCTX_PROG) @@ -124,6 +125,8 @@ gr_def(struct nvkm_grctx *ctx, u32 reg, u32 val) reg = (reg - 0x00400000) / 4; reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base; - nv_wo32(ctx->data, reg * 4, val); + nvkm_kmap(ctx->data); + nvkm_wo32(ctx->data, reg * 4, val); + nvkm_done(ctx->data); } #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index e76bf4a217dc7..69561ee4e1158 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -268,7 +268,7 @@ nv50_grctx_init(struct nvkm_device *device, u32 *size) struct nvkm_grctx ctx = { .device = device, .mode = NVKM_GRCTX_PROG, - .data = ctxprog, + .ucode = ctxprog, .ctxprog_max = 512, }; @@ -783,9 +783,12 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) static void dd_emit(struct nvkm_grctx *ctx, int num, u32 val) { int i; - if (val && ctx->mode == NVKM_GRCTX_VALS) + if (val && ctx->mode == NVKM_GRCTX_VALS) { + nvkm_kmap(ctx->data); for (i = 0; i < num; i++) - nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); + nvkm_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); + nvkm_done(ctx->data); + } ctx->ctxvals_pos += num; } @@ -1155,9 +1158,12 @@ nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx) static void xf_emit(struct nvkm_grctx *ctx, int num, u32 val) { int i; - if (val && ctx->mode == NVKM_GRCTX_VALS) + if (val && ctx->mode == NVKM_GRCTX_VALS) { + nvkm_kmap(ctx->data); for (i = 0; i < num; i++) - nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); + nvkm_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); + nvkm_done(ctx->data); + } ctx->ctxvals_pos += num << 3; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index a27daf986ed76..a7141e08930c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -283,6 +283,7 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct gf100_gr_data *data = gr->mmio_data; struct gf100_gr_mmio *mmio = gr->mmio_list; struct gf100_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; /* allocate memory for context, and fill with default values */ @@ -324,6 +325,7 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } /* finally, fill in the mmio list and point the context at it */ + nvkm_kmap(chan->mmio); for (i = 0; mmio->addr && i < ARRAY_SIZE(gr->mmio_list); i++) { u32 addr = mmio->addr; u32 data = mmio->data; @@ -333,28 +335,32 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, data |= info >> mmio->shift; } - nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); - nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data); + nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, addr); + nvkm_wo32(chan->mmio, chan->mmio_nr++ * 4, data); mmio++; } + nvkm_done(chan->mmio); + image = &chan->base.base.gpuobj; + nvkm_kmap(image); for (i = 0; i < gr->size; i += 4) - nv_wo32(chan, i, gr->data[i / 4]); + nvkm_wo32(image, i, gr->data[i / 4]); if (!gr->firmware) { - nv_wo32(chan, 0x00, chan->mmio_nr / 2); - nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8); + nvkm_wo32(image, 0x00, chan->mmio_nr / 2); + nvkm_wo32(image, 0x04, chan->mmio_vma.offset >> 8); } else { - nv_wo32(chan, 0xf4, 0); - nv_wo32(chan, 0xf8, 0); - nv_wo32(chan, 0x10, chan->mmio_nr / 2); - nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset)); - nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset)); - nv_wo32(chan, 0x1c, 1); - nv_wo32(chan, 0x20, 0); - nv_wo32(chan, 0x28, 0); - nv_wo32(chan, 0x2c, 0); + nvkm_wo32(image, 0xf4, 0); + nvkm_wo32(image, 0xf8, 0); + nvkm_wo32(image, 0x10, chan->mmio_nr / 2); + nvkm_wo32(image, 0x14, lower_32_bits(chan->mmio_vma.offset)); + nvkm_wo32(image, 0x18, upper_32_bits(chan->mmio_vma.offset)); + nvkm_wo32(image, 0x1c, 1); + nvkm_wo32(image, 0x20, 0); + nvkm_wo32(image, 0x28, 0); + nvkm_wo32(image, 0x2c, 0); } + nvkm_done(image); return 0; } @@ -1679,10 +1685,15 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - for (i = 0; i < 0x1000; i += 4) { - nv_wo32(gr->unk4188b4, i, 0x00000010); - nv_wo32(gr->unk4188b8, i, 0x00000010); - } + nvkm_kmap(gr->unk4188b4); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(gr->unk4188b4, i, 0x00000010); + nvkm_done(gr->unk4188b4); + + nvkm_kmap(gr->unk4188b8); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(gr->unk4188b8, i, 0x00000010); + nvkm_done(gr->unk4188b8); gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16; gr->gpc_nr = nvkm_rd32(device, 0x409604) & 0x0000001f; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 7295a915949ee..323f020166da5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -443,36 +443,42 @@ nv04_gr(struct nv04_gr_chan *chan) */ static void -nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value) +nv04_gr_set_ctx1(struct nvkm_object *obj, u32 mask, u32 value) { - struct nv04_gr *gr = (void *)object->engine; + struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object); + struct nv04_gr *gr = (void *)object->object.engine; struct nvkm_device *device = gr->base.engine.subdev.device; int subc = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; u32 tmp; - tmp = nv_ro32(object, 0x00); + nvkm_kmap(object); + tmp = nvkm_ro32(object, 0x00); tmp &= ~mask; tmp |= value; - nv_wo32(object, 0x00, tmp); + nvkm_wo32(object, 0x00, tmp); + nvkm_done(object); nvkm_wr32(device, NV04_PGRAPH_CTX_SWITCH1, tmp); nvkm_wr32(device, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); } static void -nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value) +nv04_gr_set_ctx_val(struct nvkm_object *obj, u32 mask, u32 value) { + struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object); int class, op, valid = 1; u32 tmp, ctx1; - ctx1 = nv_ro32(object, 0x00); + nvkm_kmap(object); + ctx1 = nvkm_ro32(object, 0x00); class = ctx1 & 0xff; op = (ctx1 >> 15) & 7; - tmp = nv_ro32(object, 0x0c); + tmp = nvkm_ro32(object, 0x0c); tmp &= ~mask; tmp |= value; - nv_wo32(object, 0x0c, tmp); + nvkm_wo32(object, 0x0c, tmp); + nvkm_done(object); /* check for valid surf2d/surf_dst/surf_color */ if (!(tmp & 0x02000000)) @@ -504,23 +510,24 @@ nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value) break; } - nv04_gr_set_ctx1(object, 0x01000000, valid << 24); + nv04_gr_set_ctx1(obj, 0x01000000, valid << 24); } static int -nv04_gr_mthd_set_operation(struct nvkm_object *object, u32 mthd, +nv04_gr_mthd_set_operation(struct nvkm_object *obj, u32 mthd, void *args, u32 size) { - u32 class = nv_ro32(object, 0) & 0xff; + struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object); + u32 class = nvkm_ro32(object, 0) & 0xff; u32 data = *(u32 *)args; if (data > 5) return 1; /* Old versions of the objects only accept first three operations. */ if (data > 2 && class < 0x40) return 1; - nv04_gr_set_ctx1(object, 0x00038000, data << 15); + nv04_gr_set_ctx1(obj, 0x00038000, data << 15); /* changing operation changes set of objects needed for validation */ - nv04_gr_set_ctx_val(object, 0, 0); + nv04_gr_set_ctx_val(obj, 0, 0); return 0; } @@ -963,13 +970,15 @@ nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(obj, 0x00, nv_mclass(obj)); + nvkm_kmap(obj); + nvkm_wo32(obj, 0x00, nv_mclass(obj)); #ifdef __BIG_ENDIAN - nv_mo32(obj, 0x00, 0x00080000, 0x00080000); + nvkm_mo32(obj, 0x00, 0x00080000, 0x00080000); #endif - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); + nvkm_wo32(obj, 0x04, 0x00000000); + nvkm_wo32(obj, 0x08, 0x00000000); + nvkm_wo32(obj, 0x0c, 0x00000000); + nvkm_done(obj); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index dab64540e69f1..f4b8eaced1b6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -41,6 +41,7 @@ nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv20_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x37f0, @@ -50,51 +51,54 @@ nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x033c, 0xffff0000); - nv_wo32(chan, 0x03a0, 0x0fff0000); - nv_wo32(chan, 0x03a4, 0x0fff0000); - nv_wo32(chan, 0x047c, 0x00000101); - nv_wo32(chan, 0x0490, 0x00000111); - nv_wo32(chan, 0x04a8, 0x44400000); + image = &chan->base.base.gpuobj; + + nvkm_kmap(image); + nvkm_wo32(image, 0x0000, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(image, 0x033c, 0xffff0000); + nvkm_wo32(image, 0x03a0, 0x0fff0000); + nvkm_wo32(image, 0x03a4, 0x0fff0000); + nvkm_wo32(image, 0x047c, 0x00000101); + nvkm_wo32(image, 0x0490, 0x00000111); + nvkm_wo32(image, 0x04a8, 0x44400000); for (i = 0x04d4; i <= 0x04e0; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(image, i, 0x00030303); for (i = 0x04f4; i <= 0x0500; i += 4) - nv_wo32(chan, i, 0x00080000); + nvkm_wo32(image, i, 0x00080000); for (i = 0x050c; i <= 0x0518; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(image, i, 0x01012000); for (i = 0x051c; i <= 0x0528; i += 4) - nv_wo32(chan, i, 0x000105b8); + nvkm_wo32(image, i, 0x000105b8); for (i = 0x052c; i <= 0x0538; i += 4) - nv_wo32(chan, i, 0x00080008); + nvkm_wo32(image, i, 0x00080008); for (i = 0x055c; i <= 0x0598; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x05a4, 0x4b7fffff); - nv_wo32(chan, 0x05fc, 0x00000001); - nv_wo32(chan, 0x0604, 0x00004000); - nv_wo32(chan, 0x0610, 0x00000001); - nv_wo32(chan, 0x0618, 0x00040000); - nv_wo32(chan, 0x061c, 0x00010000); + nvkm_wo32(image, i, 0x07ff0000); + nvkm_wo32(image, 0x05a4, 0x4b7fffff); + nvkm_wo32(image, 0x05fc, 0x00000001); + nvkm_wo32(image, 0x0604, 0x00004000); + nvkm_wo32(image, 0x0610, 0x00000001); + nvkm_wo32(image, 0x0618, 0x00040000); + nvkm_wo32(image, 0x061c, 0x00010000); for (i = 0x1c1c; i <= 0x248c; i += 16) { - nv_wo32(chan, (i + 0), 0x10700ff9); - nv_wo32(chan, (i + 4), 0x0436086c); - nv_wo32(chan, (i + 8), 0x000c001b); + nvkm_wo32(image, (i + 0), 0x10700ff9); + nvkm_wo32(image, (i + 4), 0x0436086c); + nvkm_wo32(image, (i + 8), 0x000c001b); } - nv_wo32(chan, 0x281c, 0x3f800000); - nv_wo32(chan, 0x2830, 0x3f800000); - nv_wo32(chan, 0x285c, 0x40000000); - nv_wo32(chan, 0x2860, 0x3f800000); - nv_wo32(chan, 0x2864, 0x3f000000); - nv_wo32(chan, 0x286c, 0x40000000); - nv_wo32(chan, 0x2870, 0x3f800000); - nv_wo32(chan, 0x2878, 0xbf800000); - nv_wo32(chan, 0x2880, 0xbf800000); - nv_wo32(chan, 0x34a4, 0x000fe000); - nv_wo32(chan, 0x3530, 0x000003f8); - nv_wo32(chan, 0x3540, 0x002fe000); + nvkm_wo32(image, 0x281c, 0x3f800000); + nvkm_wo32(image, 0x2830, 0x3f800000); + nvkm_wo32(image, 0x285c, 0x40000000); + nvkm_wo32(image, 0x2860, 0x3f800000); + nvkm_wo32(image, 0x2864, 0x3f000000); + nvkm_wo32(image, 0x286c, 0x40000000); + nvkm_wo32(image, 0x2870, 0x3f800000); + nvkm_wo32(image, 0x2878, 0xbf800000); + nvkm_wo32(image, 0x2880, 0xbf800000); + nvkm_wo32(image, 0x34a4, 0x000fe000); + nvkm_wo32(image, 0x3530, 0x000003f8); + nvkm_wo32(image, 0x3540, 0x002fe000); for (i = 0x355c; i <= 0x3578; i += 4) - nv_wo32(chan, i, 0x001c527c); + nvkm_wo32(image, i, 0x001c527c); + nvkm_done(image); return 0; } @@ -109,7 +113,9 @@ nv20_gr_context_init(struct nvkm_object *object) if (ret) return ret; - nv_wo32(gr->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + nvkm_kmap(gr->ctxtab); + nvkm_wo32(gr->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + nvkm_done(gr->ctxtab); return 0; } @@ -136,7 +142,9 @@ nv20_gr_context_fini(struct nvkm_object *object, bool suspend) } nvkm_mask(device, 0x400720, 0x00000001, 0x00000001); - nv_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); + nvkm_kmap(gr->ctxtab); + nvkm_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); + nvkm_done(gr->ctxtab); return nvkm_gr_context_fini(&chan->base, suspend); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index 50bad48a3eab3..1a186bd93f64d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -37,6 +37,7 @@ nv25_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv20_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x3724, @@ -46,60 +47,63 @@ nv25_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; chan->chid = nvkm_fifo_chan(parent)->chid; + image = &chan->base.base.gpuobj; - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x035c, 0xffff0000); - nv_wo32(chan, 0x03c0, 0x0fff0000); - nv_wo32(chan, 0x03c4, 0x0fff0000); - nv_wo32(chan, 0x049c, 0x00000101); - nv_wo32(chan, 0x04b0, 0x00000111); - nv_wo32(chan, 0x04c8, 0x00000080); - nv_wo32(chan, 0x04cc, 0xffff0000); - nv_wo32(chan, 0x04d0, 0x00000001); - nv_wo32(chan, 0x04e4, 0x44400000); - nv_wo32(chan, 0x04fc, 0x4b800000); + nvkm_kmap(image); + nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(image, 0x035c, 0xffff0000); + nvkm_wo32(image, 0x03c0, 0x0fff0000); + nvkm_wo32(image, 0x03c4, 0x0fff0000); + nvkm_wo32(image, 0x049c, 0x00000101); + nvkm_wo32(image, 0x04b0, 0x00000111); + nvkm_wo32(image, 0x04c8, 0x00000080); + nvkm_wo32(image, 0x04cc, 0xffff0000); + nvkm_wo32(image, 0x04d0, 0x00000001); + nvkm_wo32(image, 0x04e4, 0x44400000); + nvkm_wo32(image, 0x04fc, 0x4b800000); for (i = 0x0510; i <= 0x051c; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(image, i, 0x00030303); for (i = 0x0530; i <= 0x053c; i += 4) - nv_wo32(chan, i, 0x00080000); + nvkm_wo32(image, i, 0x00080000); for (i = 0x0548; i <= 0x0554; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(image, i, 0x01012000); for (i = 0x0558; i <= 0x0564; i += 4) - nv_wo32(chan, i, 0x000105b8); + nvkm_wo32(image, i, 0x000105b8); for (i = 0x0568; i <= 0x0574; i += 4) - nv_wo32(chan, i, 0x00080008); + nvkm_wo32(image, i, 0x00080008); for (i = 0x0598; i <= 0x05d4; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x05e0, 0x4b7fffff); - nv_wo32(chan, 0x0620, 0x00000080); - nv_wo32(chan, 0x0624, 0x30201000); - nv_wo32(chan, 0x0628, 0x70605040); - nv_wo32(chan, 0x062c, 0xb0a09080); - nv_wo32(chan, 0x0630, 0xf0e0d0c0); - nv_wo32(chan, 0x0664, 0x00000001); - nv_wo32(chan, 0x066c, 0x00004000); - nv_wo32(chan, 0x0678, 0x00000001); - nv_wo32(chan, 0x0680, 0x00040000); - nv_wo32(chan, 0x0684, 0x00010000); + nvkm_wo32(image, i, 0x07ff0000); + nvkm_wo32(image, 0x05e0, 0x4b7fffff); + nvkm_wo32(image, 0x0620, 0x00000080); + nvkm_wo32(image, 0x0624, 0x30201000); + nvkm_wo32(image, 0x0628, 0x70605040); + nvkm_wo32(image, 0x062c, 0xb0a09080); + nvkm_wo32(image, 0x0630, 0xf0e0d0c0); + nvkm_wo32(image, 0x0664, 0x00000001); + nvkm_wo32(image, 0x066c, 0x00004000); + nvkm_wo32(image, 0x0678, 0x00000001); + nvkm_wo32(image, 0x0680, 0x00040000); + nvkm_wo32(image, 0x0684, 0x00010000); for (i = 0x1b04; i <= 0x2374; i += 16) { - nv_wo32(chan, (i + 0), 0x10700ff9); - nv_wo32(chan, (i + 4), 0x0436086c); - nv_wo32(chan, (i + 8), 0x000c001b); + nvkm_wo32(image, (i + 0), 0x10700ff9); + nvkm_wo32(image, (i + 4), 0x0436086c); + nvkm_wo32(image, (i + 8), 0x000c001b); } - nv_wo32(chan, 0x2704, 0x3f800000); - nv_wo32(chan, 0x2718, 0x3f800000); - nv_wo32(chan, 0x2744, 0x40000000); - nv_wo32(chan, 0x2748, 0x3f800000); - nv_wo32(chan, 0x274c, 0x3f000000); - nv_wo32(chan, 0x2754, 0x40000000); - nv_wo32(chan, 0x2758, 0x3f800000); - nv_wo32(chan, 0x2760, 0xbf800000); - nv_wo32(chan, 0x2768, 0xbf800000); - nv_wo32(chan, 0x308c, 0x000fe000); - nv_wo32(chan, 0x3108, 0x000003f8); - nv_wo32(chan, 0x3468, 0x002fe000); + nvkm_wo32(image, 0x2704, 0x3f800000); + nvkm_wo32(image, 0x2718, 0x3f800000); + nvkm_wo32(image, 0x2744, 0x40000000); + nvkm_wo32(image, 0x2748, 0x3f800000); + nvkm_wo32(image, 0x274c, 0x3f000000); + nvkm_wo32(image, 0x2754, 0x40000000); + nvkm_wo32(image, 0x2758, 0x3f800000); + nvkm_wo32(image, 0x2760, 0xbf800000); + nvkm_wo32(image, 0x2768, 0xbf800000); + nvkm_wo32(image, 0x308c, 0x000fe000); + nvkm_wo32(image, 0x3108, 0x000003f8); + nvkm_wo32(image, 0x3468, 0x002fe000); for (i = 0x3484; i <= 0x34a0; i += 4) - nv_wo32(chan, i, 0x001c527c); + nvkm_wo32(image, i, 0x001c527c); + nvkm_done(image); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index 5c8ae50ee8e76..dfb62dc6b3b88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -13,6 +13,7 @@ nv2a_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv20_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x36b0, @@ -22,51 +23,54 @@ nv2a_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; chan->chid = nvkm_fifo_chan(parent)->chid; + image = &chan->base.base.gpuobj; - nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x033c, 0xffff0000); - nv_wo32(chan, 0x03a0, 0x0fff0000); - nv_wo32(chan, 0x03a4, 0x0fff0000); - nv_wo32(chan, 0x047c, 0x00000101); - nv_wo32(chan, 0x0490, 0x00000111); - nv_wo32(chan, 0x04a8, 0x44400000); + nvkm_kmap(image); + nvkm_wo32(image, 0x0000, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(image, 0x033c, 0xffff0000); + nvkm_wo32(image, 0x03a0, 0x0fff0000); + nvkm_wo32(image, 0x03a4, 0x0fff0000); + nvkm_wo32(image, 0x047c, 0x00000101); + nvkm_wo32(image, 0x0490, 0x00000111); + nvkm_wo32(image, 0x04a8, 0x44400000); for (i = 0x04d4; i <= 0x04e0; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(image, i, 0x00030303); for (i = 0x04f4; i <= 0x0500; i += 4) - nv_wo32(chan, i, 0x00080000); + nvkm_wo32(image, i, 0x00080000); for (i = 0x050c; i <= 0x0518; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(image, i, 0x01012000); for (i = 0x051c; i <= 0x0528; i += 4) - nv_wo32(chan, i, 0x000105b8); + nvkm_wo32(image, i, 0x000105b8); for (i = 0x052c; i <= 0x0538; i += 4) - nv_wo32(chan, i, 0x00080008); + nvkm_wo32(image, i, 0x00080008); for (i = 0x055c; i <= 0x0598; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x05a4, 0x4b7fffff); - nv_wo32(chan, 0x05fc, 0x00000001); - nv_wo32(chan, 0x0604, 0x00004000); - nv_wo32(chan, 0x0610, 0x00000001); - nv_wo32(chan, 0x0618, 0x00040000); - nv_wo32(chan, 0x061c, 0x00010000); + nvkm_wo32(image, i, 0x07ff0000); + nvkm_wo32(image, 0x05a4, 0x4b7fffff); + nvkm_wo32(image, 0x05fc, 0x00000001); + nvkm_wo32(image, 0x0604, 0x00004000); + nvkm_wo32(image, 0x0610, 0x00000001); + nvkm_wo32(image, 0x0618, 0x00040000); + nvkm_wo32(image, 0x061c, 0x00010000); for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */ - nv_wo32(chan, (i + 0), 0x10700ff9); - nv_wo32(chan, (i + 4), 0x0436086c); - nv_wo32(chan, (i + 8), 0x000c001b); + nvkm_wo32(image, (i + 0), 0x10700ff9); + nvkm_wo32(image, (i + 4), 0x0436086c); + nvkm_wo32(image, (i + 8), 0x000c001b); } - nv_wo32(chan, 0x269c, 0x3f800000); - nv_wo32(chan, 0x26b0, 0x3f800000); - nv_wo32(chan, 0x26dc, 0x40000000); - nv_wo32(chan, 0x26e0, 0x3f800000); - nv_wo32(chan, 0x26e4, 0x3f000000); - nv_wo32(chan, 0x26ec, 0x40000000); - nv_wo32(chan, 0x26f0, 0x3f800000); - nv_wo32(chan, 0x26f8, 0xbf800000); - nv_wo32(chan, 0x2700, 0xbf800000); - nv_wo32(chan, 0x3024, 0x000fe000); - nv_wo32(chan, 0x30a0, 0x000003f8); - nv_wo32(chan, 0x33fc, 0x002fe000); + nvkm_wo32(image, 0x269c, 0x3f800000); + nvkm_wo32(image, 0x26b0, 0x3f800000); + nvkm_wo32(image, 0x26dc, 0x40000000); + nvkm_wo32(image, 0x26e0, 0x3f800000); + nvkm_wo32(image, 0x26e4, 0x3f000000); + nvkm_wo32(image, 0x26ec, 0x40000000); + nvkm_wo32(image, 0x26f0, 0x3f800000); + nvkm_wo32(image, 0x26f8, 0xbf800000); + nvkm_wo32(image, 0x2700, 0xbf800000); + nvkm_wo32(image, 0x3024, 0x000fe000); + nvkm_wo32(image, 0x30a0, 0x000003f8); + nvkm_wo32(image, 0x33fc, 0x002fe000); for (i = 0x341c; i <= 0x3438; i += 4) - nv_wo32(chan, i, 0x001c527c); + nvkm_wo32(image, i, 0x001c527c); + nvkm_done(image); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 8be77b4f15ad6..51573736bb480 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -40,6 +40,7 @@ nv30_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv20_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x5f48, @@ -49,59 +50,62 @@ nv30_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; chan->chid = nvkm_fifo_chan(parent)->chid; - - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x0410, 0x00000101); - nv_wo32(chan, 0x0424, 0x00000111); - nv_wo32(chan, 0x0428, 0x00000060); - nv_wo32(chan, 0x0444, 0x00000080); - nv_wo32(chan, 0x0448, 0xffff0000); - nv_wo32(chan, 0x044c, 0x00000001); - nv_wo32(chan, 0x0460, 0x44400000); - nv_wo32(chan, 0x048c, 0xffff0000); + image = &chan->base.base.gpuobj; + + nvkm_kmap(image); + nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(image, 0x0410, 0x00000101); + nvkm_wo32(image, 0x0424, 0x00000111); + nvkm_wo32(image, 0x0428, 0x00000060); + nvkm_wo32(image, 0x0444, 0x00000080); + nvkm_wo32(image, 0x0448, 0xffff0000); + nvkm_wo32(image, 0x044c, 0x00000001); + nvkm_wo32(image, 0x0460, 0x44400000); + nvkm_wo32(image, 0x048c, 0xffff0000); for (i = 0x04e0; i < 0x04e8; i += 4) - nv_wo32(chan, i, 0x0fff0000); - nv_wo32(chan, 0x04ec, 0x00011100); + nvkm_wo32(image, i, 0x0fff0000); + nvkm_wo32(image, 0x04ec, 0x00011100); for (i = 0x0508; i < 0x0548; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x0550, 0x4b7fffff); - nv_wo32(chan, 0x058c, 0x00000080); - nv_wo32(chan, 0x0590, 0x30201000); - nv_wo32(chan, 0x0594, 0x70605040); - nv_wo32(chan, 0x0598, 0xb8a89888); - nv_wo32(chan, 0x059c, 0xf8e8d8c8); - nv_wo32(chan, 0x05b0, 0xb0000000); + nvkm_wo32(image, i, 0x07ff0000); + nvkm_wo32(image, 0x0550, 0x4b7fffff); + nvkm_wo32(image, 0x058c, 0x00000080); + nvkm_wo32(image, 0x0590, 0x30201000); + nvkm_wo32(image, 0x0594, 0x70605040); + nvkm_wo32(image, 0x0598, 0xb8a89888); + nvkm_wo32(image, 0x059c, 0xf8e8d8c8); + nvkm_wo32(image, 0x05b0, 0xb0000000); for (i = 0x0600; i < 0x0640; i += 4) - nv_wo32(chan, i, 0x00010588); + nvkm_wo32(image, i, 0x00010588); for (i = 0x0640; i < 0x0680; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(image, i, 0x00030303); for (i = 0x06c0; i < 0x0700; i += 4) - nv_wo32(chan, i, 0x0008aae4); + nvkm_wo32(image, i, 0x0008aae4); for (i = 0x0700; i < 0x0740; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(image, i, 0x01012000); for (i = 0x0740; i < 0x0780; i += 4) - nv_wo32(chan, i, 0x00080008); - nv_wo32(chan, 0x085c, 0x00040000); - nv_wo32(chan, 0x0860, 0x00010000); + nvkm_wo32(image, i, 0x00080008); + nvkm_wo32(image, 0x085c, 0x00040000); + nvkm_wo32(image, 0x0860, 0x00010000); for (i = 0x0864; i < 0x0874; i += 4) - nv_wo32(chan, i, 0x00040004); + nvkm_wo32(image, i, 0x00040004); for (i = 0x1f18; i <= 0x3088 ; i += 16) { - nv_wo32(chan, i + 0, 0x10700ff9); - nv_wo32(chan, i + 1, 0x0436086c); - nv_wo32(chan, i + 2, 0x000c001b); + nvkm_wo32(image, i + 0, 0x10700ff9); + nvkm_wo32(image, i + 1, 0x0436086c); + nvkm_wo32(image, i + 2, 0x000c001b); } for (i = 0x30b8; i < 0x30c8; i += 4) - nv_wo32(chan, i, 0x0000ffff); - nv_wo32(chan, 0x344c, 0x3f800000); - nv_wo32(chan, 0x3808, 0x3f800000); - nv_wo32(chan, 0x381c, 0x3f800000); - nv_wo32(chan, 0x3848, 0x40000000); - nv_wo32(chan, 0x384c, 0x3f800000); - nv_wo32(chan, 0x3850, 0x3f000000); - nv_wo32(chan, 0x3858, 0x40000000); - nv_wo32(chan, 0x385c, 0x3f800000); - nv_wo32(chan, 0x3864, 0xbf800000); - nv_wo32(chan, 0x386c, 0xbf800000); + nvkm_wo32(image, i, 0x0000ffff); + nvkm_wo32(image, 0x344c, 0x3f800000); + nvkm_wo32(image, 0x3808, 0x3f800000); + nvkm_wo32(image, 0x381c, 0x3f800000); + nvkm_wo32(image, 0x3848, 0x40000000); + nvkm_wo32(image, 0x384c, 0x3f800000); + nvkm_wo32(image, 0x3850, 0x3f000000); + nvkm_wo32(image, 0x3858, 0x40000000); + nvkm_wo32(image, 0x385c, 0x3f800000); + nvkm_wo32(image, 0x3864, 0xbf800000); + nvkm_wo32(image, 0x386c, 0xbf800000); + nvkm_done(image); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index e17eb0b132770..f9d71185ee749 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -39,6 +39,7 @@ nv34_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv20_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x46dc, @@ -48,59 +49,62 @@ nv34_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; chan->chid = nvkm_fifo_chan(parent)->chid; + image = &chan->base.base.gpuobj; - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x040c, 0x01000101); - nv_wo32(chan, 0x0420, 0x00000111); - nv_wo32(chan, 0x0424, 0x00000060); - nv_wo32(chan, 0x0440, 0x00000080); - nv_wo32(chan, 0x0444, 0xffff0000); - nv_wo32(chan, 0x0448, 0x00000001); - nv_wo32(chan, 0x045c, 0x44400000); - nv_wo32(chan, 0x0480, 0xffff0000); + nvkm_kmap(image); + nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(image, 0x040c, 0x01000101); + nvkm_wo32(image, 0x0420, 0x00000111); + nvkm_wo32(image, 0x0424, 0x00000060); + nvkm_wo32(image, 0x0440, 0x00000080); + nvkm_wo32(image, 0x0444, 0xffff0000); + nvkm_wo32(image, 0x0448, 0x00000001); + nvkm_wo32(image, 0x045c, 0x44400000); + nvkm_wo32(image, 0x0480, 0xffff0000); for (i = 0x04d4; i < 0x04dc; i += 4) - nv_wo32(chan, i, 0x0fff0000); - nv_wo32(chan, 0x04e0, 0x00011100); + nvkm_wo32(image, i, 0x0fff0000); + nvkm_wo32(image, 0x04e0, 0x00011100); for (i = 0x04fc; i < 0x053c; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x0544, 0x4b7fffff); - nv_wo32(chan, 0x057c, 0x00000080); - nv_wo32(chan, 0x0580, 0x30201000); - nv_wo32(chan, 0x0584, 0x70605040); - nv_wo32(chan, 0x0588, 0xb8a89888); - nv_wo32(chan, 0x058c, 0xf8e8d8c8); - nv_wo32(chan, 0x05a0, 0xb0000000); + nvkm_wo32(image, i, 0x07ff0000); + nvkm_wo32(image, 0x0544, 0x4b7fffff); + nvkm_wo32(image, 0x057c, 0x00000080); + nvkm_wo32(image, 0x0580, 0x30201000); + nvkm_wo32(image, 0x0584, 0x70605040); + nvkm_wo32(image, 0x0588, 0xb8a89888); + nvkm_wo32(image, 0x058c, 0xf8e8d8c8); + nvkm_wo32(image, 0x05a0, 0xb0000000); for (i = 0x05f0; i < 0x0630; i += 4) - nv_wo32(chan, i, 0x00010588); + nvkm_wo32(image, i, 0x00010588); for (i = 0x0630; i < 0x0670; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(image, i, 0x00030303); for (i = 0x06b0; i < 0x06f0; i += 4) - nv_wo32(chan, i, 0x0008aae4); + nvkm_wo32(image, i, 0x0008aae4); for (i = 0x06f0; i < 0x0730; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(image, i, 0x01012000); for (i = 0x0730; i < 0x0770; i += 4) - nv_wo32(chan, i, 0x00080008); - nv_wo32(chan, 0x0850, 0x00040000); - nv_wo32(chan, 0x0854, 0x00010000); + nvkm_wo32(image, i, 0x00080008); + nvkm_wo32(image, 0x0850, 0x00040000); + nvkm_wo32(image, 0x0854, 0x00010000); for (i = 0x0858; i < 0x0868; i += 4) - nv_wo32(chan, i, 0x00040004); + nvkm_wo32(image, i, 0x00040004); for (i = 0x15ac; i <= 0x271c ; i += 16) { - nv_wo32(chan, i + 0, 0x10700ff9); - nv_wo32(chan, i + 1, 0x0436086c); - nv_wo32(chan, i + 2, 0x000c001b); + nvkm_wo32(image, i + 0, 0x10700ff9); + nvkm_wo32(image, i + 1, 0x0436086c); + nvkm_wo32(image, i + 2, 0x000c001b); } for (i = 0x274c; i < 0x275c; i += 4) - nv_wo32(chan, i, 0x0000ffff); - nv_wo32(chan, 0x2ae0, 0x3f800000); - nv_wo32(chan, 0x2e9c, 0x3f800000); - nv_wo32(chan, 0x2eb0, 0x3f800000); - nv_wo32(chan, 0x2edc, 0x40000000); - nv_wo32(chan, 0x2ee0, 0x3f800000); - nv_wo32(chan, 0x2ee4, 0x3f000000); - nv_wo32(chan, 0x2eec, 0x40000000); - nv_wo32(chan, 0x2ef0, 0x3f800000); - nv_wo32(chan, 0x2ef8, 0xbf800000); - nv_wo32(chan, 0x2f00, 0xbf800000); + nvkm_wo32(image, i, 0x0000ffff); + nvkm_wo32(image, 0x2ae0, 0x3f800000); + nvkm_wo32(image, 0x2e9c, 0x3f800000); + nvkm_wo32(image, 0x2eb0, 0x3f800000); + nvkm_wo32(image, 0x2edc, 0x40000000); + nvkm_wo32(image, 0x2ee0, 0x3f800000); + nvkm_wo32(image, 0x2ee4, 0x3f000000); + nvkm_wo32(image, 0x2eec, 0x40000000); + nvkm_wo32(image, 0x2ef0, 0x3f800000); + nvkm_wo32(image, 0x2ef8, 0xbf800000); + nvkm_wo32(image, 0x2f00, 0xbf800000); + nvkm_done(image); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 35ba75130f930..c6357f2fdb363 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -39,6 +39,7 @@ nv35_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nv20_gr_chan *chan; + struct nvkm_gpuobj *image; int ret, i; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x577c, @@ -48,59 +49,62 @@ nv35_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; chan->chid = nvkm_fifo_chan(parent)->chid; + image = &chan->base.base.gpuobj; - nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24)); - nv_wo32(chan, 0x040c, 0x00000101); - nv_wo32(chan, 0x0420, 0x00000111); - nv_wo32(chan, 0x0424, 0x00000060); - nv_wo32(chan, 0x0440, 0x00000080); - nv_wo32(chan, 0x0444, 0xffff0000); - nv_wo32(chan, 0x0448, 0x00000001); - nv_wo32(chan, 0x045c, 0x44400000); - nv_wo32(chan, 0x0488, 0xffff0000); + nvkm_kmap(image); + nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(image, 0x040c, 0x00000101); + nvkm_wo32(image, 0x0420, 0x00000111); + nvkm_wo32(image, 0x0424, 0x00000060); + nvkm_wo32(image, 0x0440, 0x00000080); + nvkm_wo32(image, 0x0444, 0xffff0000); + nvkm_wo32(image, 0x0448, 0x00000001); + nvkm_wo32(image, 0x045c, 0x44400000); + nvkm_wo32(image, 0x0488, 0xffff0000); for (i = 0x04dc; i < 0x04e4; i += 4) - nv_wo32(chan, i, 0x0fff0000); - nv_wo32(chan, 0x04e8, 0x00011100); + nvkm_wo32(image, i, 0x0fff0000); + nvkm_wo32(image, 0x04e8, 0x00011100); for (i = 0x0504; i < 0x0544; i += 4) - nv_wo32(chan, i, 0x07ff0000); - nv_wo32(chan, 0x054c, 0x4b7fffff); - nv_wo32(chan, 0x0588, 0x00000080); - nv_wo32(chan, 0x058c, 0x30201000); - nv_wo32(chan, 0x0590, 0x70605040); - nv_wo32(chan, 0x0594, 0xb8a89888); - nv_wo32(chan, 0x0598, 0xf8e8d8c8); - nv_wo32(chan, 0x05ac, 0xb0000000); + nvkm_wo32(image, i, 0x07ff0000); + nvkm_wo32(image, 0x054c, 0x4b7fffff); + nvkm_wo32(image, 0x0588, 0x00000080); + nvkm_wo32(image, 0x058c, 0x30201000); + nvkm_wo32(image, 0x0590, 0x70605040); + nvkm_wo32(image, 0x0594, 0xb8a89888); + nvkm_wo32(image, 0x0598, 0xf8e8d8c8); + nvkm_wo32(image, 0x05ac, 0xb0000000); for (i = 0x0604; i < 0x0644; i += 4) - nv_wo32(chan, i, 0x00010588); + nvkm_wo32(image, i, 0x00010588); for (i = 0x0644; i < 0x0684; i += 4) - nv_wo32(chan, i, 0x00030303); + nvkm_wo32(image, i, 0x00030303); for (i = 0x06c4; i < 0x0704; i += 4) - nv_wo32(chan, i, 0x0008aae4); + nvkm_wo32(image, i, 0x0008aae4); for (i = 0x0704; i < 0x0744; i += 4) - nv_wo32(chan, i, 0x01012000); + nvkm_wo32(image, i, 0x01012000); for (i = 0x0744; i < 0x0784; i += 4) - nv_wo32(chan, i, 0x00080008); - nv_wo32(chan, 0x0860, 0x00040000); - nv_wo32(chan, 0x0864, 0x00010000); + nvkm_wo32(image, i, 0x00080008); + nvkm_wo32(image, 0x0860, 0x00040000); + nvkm_wo32(image, 0x0864, 0x00010000); for (i = 0x0868; i < 0x0878; i += 4) - nv_wo32(chan, i, 0x00040004); + nvkm_wo32(image, i, 0x00040004); for (i = 0x1f1c; i <= 0x308c ; i += 16) { - nv_wo32(chan, i + 0, 0x10700ff9); - nv_wo32(chan, i + 4, 0x0436086c); - nv_wo32(chan, i + 8, 0x000c001b); + nvkm_wo32(image, i + 0, 0x10700ff9); + nvkm_wo32(image, i + 4, 0x0436086c); + nvkm_wo32(image, i + 8, 0x000c001b); } for (i = 0x30bc; i < 0x30cc; i += 4) - nv_wo32(chan, i, 0x0000ffff); - nv_wo32(chan, 0x3450, 0x3f800000); - nv_wo32(chan, 0x380c, 0x3f800000); - nv_wo32(chan, 0x3820, 0x3f800000); - nv_wo32(chan, 0x384c, 0x40000000); - nv_wo32(chan, 0x3850, 0x3f800000); - nv_wo32(chan, 0x3854, 0x3f000000); - nv_wo32(chan, 0x385c, 0x40000000); - nv_wo32(chan, 0x3860, 0x3f800000); - nv_wo32(chan, 0x3868, 0xbf800000); - nv_wo32(chan, 0x3870, 0xbf800000); + nvkm_wo32(image, i, 0x0000ffff); + nvkm_wo32(image, 0x3450, 0x3f800000); + nvkm_wo32(image, 0x380c, 0x3f800000); + nvkm_wo32(image, 0x3820, 0x3f800000); + nvkm_wo32(image, 0x384c, 0x40000000); + nvkm_wo32(image, 0x3850, 0x3f800000); + nvkm_wo32(image, 0x3854, 0x3f000000); + nvkm_wo32(image, 0x385c, 0x40000000); + nvkm_wo32(image, 0x3860, 0x3f800000); + nvkm_wo32(image, 0x3868, 0xbf800000); + nvkm_wo32(image, 0x3870, 0xbf800000); + nvkm_done(image); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 10ffb676e55ed..1ebf2edef4d40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -63,14 +63,16 @@ nv40_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); + nvkm_kmap(obj); + nvkm_wo32(obj, 0x00, nv_mclass(obj)); + nvkm_wo32(obj, 0x04, 0x00000000); + nvkm_wo32(obj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN - nv_mo32(obj, 0x08, 0x01000000, 0x01000000); + nvkm_mo32(obj, 0x08, 0x01000000, 0x01000000); #endif - nv_wo32(obj, 0x0c, 0x00000000); - nv_wo32(obj, 0x10, 0x00000000); + nvkm_wo32(obj, 0x0c, 0x00000000); + nvkm_wo32(obj, 0x10, 0x00000000); + nvkm_done(obj); return 0; } @@ -146,7 +148,7 @@ nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv40_grctx_fill(nv_device(gr), nv_gpuobj(chan)); - nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4); + nvkm_wo32(&chan->base.base.gpuobj, 0x00000, nv_gpuobj(chan)->addr >> 4); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 4ea7f09387693..c50cfe4875ef2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -62,10 +62,12 @@ nv50_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); + nvkm_kmap(obj); + nvkm_wo32(obj, 0x00, nv_mclass(obj)); + nvkm_wo32(obj, 0x04, 0x00000000); + nvkm_wo32(obj, 0x08, 0x00000000); + nvkm_wo32(obj, 0x0c, 0x00000000); + nvkm_done(obj); return 0; } -- GitLab From 572fb13db2a9dc5336a4b769d60428bc9cff0af6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5454/7006] drm/nouveau/mpeg: switch to gpuobj accessor macros Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 10 ++++++---- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 4 +++- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 19 +++++++++++++------ 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index d4d1abba02f4f..1586213b0830d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -49,10 +49,12 @@ nv31_mpeg_object_ctor(struct nvkm_object *parent, if (ret) return ret; - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); + nvkm_kmap(obj); + nvkm_wo32(obj, 0x00, nv_mclass(obj)); + nvkm_wo32(obj, 0x04, 0x00000000); + nvkm_wo32(obj, 0x08, 0x00000000); + nvkm_wo32(obj, 0x0c, 0x00000000); + nvkm_done(obj); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 9bd5fc185ea2f..93936671f39b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -50,7 +50,9 @@ nv44_mpeg_context_ctor(struct nvkm_object *parent, if (ret) return ret; - nv_wo32(&chan->base.base, 0x78, 0x02001ec1); + nvkm_kmap(&chan->base.base.gpuobj); + nvkm_wo32(&chan->base.base.gpuobj, 0x78, 0x02001ec1); + nvkm_done(&chan->base.base.gpuobj); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index 0a4ada7b3a279..6af707b5be189 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -49,10 +49,12 @@ nv50_mpeg_object_ctor(struct nvkm_object *parent, if (ret) return ret; - nv_wo32(obj, 0x00, nv_mclass(obj)); - nv_wo32(obj, 0x04, 0x00000000); - nv_wo32(obj, 0x08, 0x00000000); - nv_wo32(obj, 0x0c, 0x00000000); + nvkm_kmap(obj); + nvkm_wo32(obj, 0x00, nv_mclass(obj)); + nvkm_wo32(obj, 0x04, 0x00000000); + nvkm_wo32(obj, 0x08, 0x00000000); + nvkm_wo32(obj, 0x0c, 0x00000000); + nvkm_done(obj); return 0; } @@ -84,6 +86,7 @@ nv50_mpeg_context_ctor(struct nvkm_object *parent, { struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_mpeg_chan *chan; + struct nvkm_gpuobj *image; int ret; ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4, @@ -92,9 +95,13 @@ nv50_mpeg_context_ctor(struct nvkm_object *parent, if (ret) return ret; - nv_wo32(chan, 0x0070, 0x00801ec1); - nv_wo32(chan, 0x007c, 0x0000037c); + image = &chan->base.base.gpuobj; + + nvkm_kmap(image); + nvkm_wo32(image, 0x0070, 0x00801ec1); + nvkm_wo32(image, 0x007c, 0x0000037c); bar->flush(bar); + nvkm_done(image); return 0; } -- GitLab From cfdc4c44b4388bb8e697882cddd966333e4ab7b0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5455/7006] drm/nouveau/core: wrap direct use of object accessor functions Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/object.h | 7 ++ drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 59 ++++++---------- drivers/gpu/drm/nouveau/nvkm/core/object.c | 69 +++++++++++++++++++ 3 files changed, 97 insertions(+), 38 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 696fb62e8a0ac..15caf553501b2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -26,6 +26,13 @@ struct nvkm_object { #endif }; +int nvkm_object_rd08(struct nvkm_object *, u64 addr, u8 *data); +int nvkm_object_rd16(struct nvkm_object *, u64 addr, u16 *data); +int nvkm_object_rd32(struct nvkm_object *, u64 addr, u32 *data); +int nvkm_object_wr08(struct nvkm_object *, u64 addr, u8 data); +int nvkm_object_wr16(struct nvkm_object *, u64 addr, u16 data); +int nvkm_object_wr32(struct nvkm_object *, u64 addr, u32 data); + static inline struct nvkm_object * nv_object(void *obj) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 8a0d291d5f5f0..7434958846f7b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -224,10 +224,14 @@ static int nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size) { struct nvkm_object *object = handle->object; - struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; union { struct nvif_ioctl_rd_v0 v0; } *args = data; + union { + u8 b08; + u16 b16; + u32 b32; + } v; int ret; nvif_ioctl(object, "rd size %d\n", size); @@ -236,22 +240,16 @@ nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size) args->v0.version, args->v0.size, args->v0.addr); switch (args->v0.size) { case 1: - if (ret = -ENODEV, ofuncs->rd08) { - args->v0.data = nv_ro08(object, args->v0.addr); - ret = 0; - } + ret = nvkm_object_rd08(object, args->v0.addr, &v.b08); + args->v0.data = v.b08; break; case 2: - if (ret = -ENODEV, ofuncs->rd16) { - args->v0.data = nv_ro16(object, args->v0.addr); - ret = 0; - } + ret = nvkm_object_rd16(object, args->v0.addr, &v.b16); + args->v0.data = v.b16; break; case 4: - if (ret = -ENODEV, ofuncs->rd32) { - args->v0.data = nv_ro32(object, args->v0.addr); - ret = 0; - } + ret = nvkm_object_rd32(object, args->v0.addr, &v.b32); + args->v0.data = v.b32; break; default: ret = -EINVAL; @@ -266,7 +264,6 @@ static int nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size) { struct nvkm_object *object = handle->object; - struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; union { struct nvif_ioctl_wr_v0 v0; } *args = data; @@ -278,32 +275,18 @@ nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size) "wr vers %d size %d addr %016llx data %08x\n", args->v0.version, args->v0.size, args->v0.addr, args->v0.data); - switch (args->v0.size) { - case 1: - if (ret = -ENODEV, ofuncs->wr08) { - nv_wo08(object, args->v0.addr, args->v0.data); - ret = 0; - } - break; - case 2: - if (ret = -ENODEV, ofuncs->wr16) { - nv_wo16(object, args->v0.addr, args->v0.data); - ret = 0; - } - break; - case 4: - if (ret = -ENODEV, ofuncs->wr32) { - nv_wo32(object, args->v0.addr, args->v0.data); - ret = 0; - } - break; - default: - ret = -EINVAL; - break; - } + } else + return ret; + + switch (args->v0.size) { + case 1: return nvkm_object_wr08(object, args->v0.addr, args->v0.data); + case 2: return nvkm_object_wr16(object, args->v0.addr, args->v0.data); + case 4: return nvkm_object_wr32(object, args->v0.addr, args->v0.data); + default: + break; } - return ret; + return -EINVAL; } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index b690a3898732e..b32a041636a40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -24,6 +24,75 @@ #include #include +int +nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data) +{ + const struct nvkm_oclass *oclass = object->oclass; + if (oclass->ofuncs && oclass->ofuncs->rd08) { + *data = oclass->ofuncs->rd08(object, addr); + return 0; + } + *data = 0x00; + return -ENODEV; +} + +int +nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data) +{ + const struct nvkm_oclass *oclass = object->oclass; + if (oclass->ofuncs && oclass->ofuncs->rd16) { + *data = oclass->ofuncs->rd16(object, addr); + return 0; + } + *data = 0x0000; + return -ENODEV; +} + +int +nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + const struct nvkm_oclass *oclass = object->oclass; + if (oclass->ofuncs && oclass->ofuncs->rd32) { + *data = oclass->ofuncs->rd32(object, addr); + return 0; + } + *data = 0x0000; + return -ENODEV; +} + +int +nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data) +{ + const struct nvkm_oclass *oclass = object->oclass; + if (oclass->ofuncs && oclass->ofuncs->wr08) { + oclass->ofuncs->wr08(object, addr, data); + return 0; + } + return -ENODEV; +} + +int +nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data) +{ + const struct nvkm_oclass *oclass = object->oclass; + if (oclass->ofuncs && oclass->ofuncs->wr16) { + oclass->ofuncs->wr16(object, addr, data); + return 0; + } + return -ENODEV; +} + +int +nvkm_object_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + const struct nvkm_oclass *oclass = object->oclass; + if (oclass->ofuncs && oclass->ofuncs->wr32) { + oclass->ofuncs->wr32(object, addr, data); + return 0; + } + return -ENODEV; +} + int nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 pclass, -- GitLab From 95cf469cc3b266324cd9129f93a2d44b85ea27ed Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5456/7006] drm/nouveau/imem: use object accessor function for suspend/resume Very much not ideal, but this will be improved later. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/object.h | 47 ------------------- .../drm/nouveau/include/nvkm/subdev/instmem.h | 2 +- .../drm/nouveau/nvkm/subdev/instmem/base.c | 14 ++++-- 3 files changed, 10 insertions(+), 53 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 15caf553501b2..04e8a62ade32f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -138,51 +138,4 @@ nv_call(void *obj, u32 mthd, u32 data) { return nv_exec(obj, mthd, &data, sizeof(data)); } - -static inline u8 -nv_ro08(void *obj, u64 addr) -{ - u8 data = nv_ofuncs(obj)->rd08(obj, addr); - return data; -} - -static inline u16 -nv_ro16(void *obj, u64 addr) -{ - u16 data = nv_ofuncs(obj)->rd16(obj, addr); - return data; -} - -static inline u32 -nv_ro32(void *obj, u64 addr) -{ - u32 data = nv_ofuncs(obj)->rd32(obj, addr); - return data; -} - -static inline void -nv_wo08(void *obj, u64 addr, u8 data) -{ - nv_ofuncs(obj)->wr08(obj, addr, data); -} - -static inline void -nv_wo16(void *obj, u64 addr, u16 data) -{ - nv_ofuncs(obj)->wr16(obj, addr, data); -} - -static inline void -nv_wo32(void *obj, u64 addr, u32 data) -{ - nv_ofuncs(obj)->wr32(obj, addr, data); -} - -static inline u32 -nv_mo32(void *obj, u64 addr, u32 mask, u32 data) -{ - u32 temp = nv_ro32(obj, addr); - nv_wo32(obj, addr, (temp & ~mask) | data); - return temp; -} #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index b6906f436e402..7ba3ff27e89ec 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -3,7 +3,7 @@ #include struct nvkm_instobj { - struct nvkm_object base; + struct nvkm_object object; struct list_head head; u32 *suspend; u64 addr; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 43a8f4e19eb6b..4219eb39cf450 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -39,7 +39,7 @@ _nvkm_instobj_dtor(struct nvkm_object *object) list_del(&iobj->head); mutex_unlock(&nv_subdev(imem)->mutex); - return nvkm_object_destroy(&iobj->base); + return nvkm_object_destroy(&iobj->object); } int @@ -92,8 +92,10 @@ _nvkm_instmem_fini(struct nvkm_object *object, bool suspend) break; } - for (i = 0; i < iobj->size; i += 4) - iobj->suspend[i / 4] = nv_ro32(iobj, i); + for (i = 0; i < iobj->size; i += 4) { + nvkm_object_rd32(&iobj->object, i, (u32 *) + &iobj->suspend[i/4]); + } } mutex_unlock(&imem->subdev.mutex); if (ret) @@ -117,8 +119,10 @@ _nvkm_instmem_init(struct nvkm_object *object) mutex_lock(&imem->subdev.mutex); list_for_each_entry(iobj, &imem->list, head) { if (iobj->suspend) { - for (i = 0; i < iobj->size; i += 4) - nv_wo32(iobj, i, iobj->suspend[i / 4]); + for (i = 0; i < iobj->size; i += 4) { + nvkm_object_wr32(&iobj->object, i, *(u32 *) + &iobj->suspend[i/4]); + } vfree(iobj->suspend); iobj->suspend = NULL; } -- GitLab From a8dae9fe0e8ad94de1bb2bfda90d288c1b9eb6e6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5457/7006] drm/nouveau/vga: require nvkm_device pointer in accessor functions Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/vga.h | 26 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/vga.c | 105 ++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 14 ++- .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 2 +- .../drm/nouveau/nvkm/subdev/devinit/base.c | 4 +- .../drm/nouveau/nvkm/subdev/devinit/nv04.c | 21 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv05.c | 4 +- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c | 20 ++-- 9 files changed, 98 insertions(+), 102 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h index 53294f42c690c..ce5636fe2a667 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h @@ -3,26 +3,26 @@ #include /* access to various legacy io ports */ -u8 nv_rdport(void *obj, int head, u16 port); -void nv_wrport(void *obj, int head, u16 port, u8 value); +u8 nvkm_rdport(struct nvkm_device *, int head, u16 port); +void nvkm_wrport(struct nvkm_device *, int head, u16 port, u8 value); /* VGA Sequencer */ -u8 nv_rdvgas(void *obj, int head, u8 index); -void nv_wrvgas(void *obj, int head, u8 index, u8 value); +u8 nvkm_rdvgas(struct nvkm_device *, int head, u8 index); +void nvkm_wrvgas(struct nvkm_device *, int head, u8 index, u8 value); /* VGA Graphics */ -u8 nv_rdvgag(void *obj, int head, u8 index); -void nv_wrvgag(void *obj, int head, u8 index, u8 value); +u8 nvkm_rdvgag(struct nvkm_device *, int head, u8 index); +void nvkm_wrvgag(struct nvkm_device *, int head, u8 index, u8 value); /* VGA CRTC */ -u8 nv_rdvgac(void *obj, int head, u8 index); -void nv_wrvgac(void *obj, int head, u8 index, u8 value); +u8 nvkm_rdvgac(struct nvkm_device *, int head, u8 index); +void nvkm_wrvgac(struct nvkm_device *, int head, u8 index, u8 value); /* VGA indexed port access dispatcher */ -u8 nv_rdvgai(void *obj, int head, u16 port, u8 index); -void nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value); +u8 nvkm_rdvgai(struct nvkm_device *, int head, u16 port, u8 index); +void nvkm_wrvgai(struct nvkm_device *, int head, u16 port, u8 index, u8 value); -bool nv_lockvgac(void *obj, bool lock); -u8 nv_rdvgaowner(void *obj); -void nv_wrvgaowner(void *obj, u8); +bool nvkm_lockvgac(struct nvkm_device *, bool lock); +u8 nvkm_rdvgaowner(struct nvkm_device *); +void nvkm_wrvgaowner(struct nvkm_device *, u8); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c index 39796449de23a..8bff95c6343f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c @@ -24,10 +24,8 @@ #include u8 -nv_rdport(void *obj, int head, u16 port) +nvkm_rdport(struct nvkm_device *device, int head, u16 port) { - struct nvkm_device *device = nv_device(obj); - if (device->card_type >= NV_50) return nvkm_rd08(device, 0x601000 + port); @@ -48,10 +46,8 @@ nv_rdport(void *obj, int head, u16 port) } void -nv_wrport(void *obj, int head, u16 port, u8 data) +nvkm_wrport(struct nvkm_device *device, int head, u16 port, u8 data) { - struct nvkm_device *device = nv_device(obj); - if (device->card_type >= NV_50) nvkm_wr08(device, 0x601000 + port, data); else @@ -70,78 +66,76 @@ nv_wrport(void *obj, int head, u16 port, u8 data) } u8 -nv_rdvgas(void *obj, int head, u8 index) +nvkm_rdvgas(struct nvkm_device *device, int head, u8 index) { - nv_wrport(obj, head, 0x03c4, index); - return nv_rdport(obj, head, 0x03c5); + nvkm_wrport(device, head, 0x03c4, index); + return nvkm_rdport(device, head, 0x03c5); } void -nv_wrvgas(void *obj, int head, u8 index, u8 value) +nvkm_wrvgas(struct nvkm_device *device, int head, u8 index, u8 value) { - nv_wrport(obj, head, 0x03c4, index); - nv_wrport(obj, head, 0x03c5, value); + nvkm_wrport(device, head, 0x03c4, index); + nvkm_wrport(device, head, 0x03c5, value); } u8 -nv_rdvgag(void *obj, int head, u8 index) +nvkm_rdvgag(struct nvkm_device *device, int head, u8 index) { - nv_wrport(obj, head, 0x03ce, index); - return nv_rdport(obj, head, 0x03cf); + nvkm_wrport(device, head, 0x03ce, index); + return nvkm_rdport(device, head, 0x03cf); } void -nv_wrvgag(void *obj, int head, u8 index, u8 value) +nvkm_wrvgag(struct nvkm_device *device, int head, u8 index, u8 value) { - nv_wrport(obj, head, 0x03ce, index); - nv_wrport(obj, head, 0x03cf, value); + nvkm_wrport(device, head, 0x03ce, index); + nvkm_wrport(device, head, 0x03cf, value); } u8 -nv_rdvgac(void *obj, int head, u8 index) +nvkm_rdvgac(struct nvkm_device *device, int head, u8 index) { - nv_wrport(obj, head, 0x03d4, index); - return nv_rdport(obj, head, 0x03d5); + nvkm_wrport(device, head, 0x03d4, index); + return nvkm_rdport(device, head, 0x03d5); } void -nv_wrvgac(void *obj, int head, u8 index, u8 value) +nvkm_wrvgac(struct nvkm_device *device, int head, u8 index, u8 value) { - nv_wrport(obj, head, 0x03d4, index); - nv_wrport(obj, head, 0x03d5, value); + nvkm_wrport(device, head, 0x03d4, index); + nvkm_wrport(device, head, 0x03d5, value); } u8 -nv_rdvgai(void *obj, int head, u16 port, u8 index) +nvkm_rdvgai(struct nvkm_device *device, int head, u16 port, u8 index) { - if (port == 0x03c4) return nv_rdvgas(obj, head, index); - if (port == 0x03ce) return nv_rdvgag(obj, head, index); - if (port == 0x03d4) return nv_rdvgac(obj, head, index); + if (port == 0x03c4) return nvkm_rdvgas(device, head, index); + if (port == 0x03ce) return nvkm_rdvgag(device, head, index); + if (port == 0x03d4) return nvkm_rdvgac(device, head, index); return 0x00; } void -nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value) +nvkm_wrvgai(struct nvkm_device *device, int head, u16 port, u8 index, u8 value) { - if (port == 0x03c4) nv_wrvgas(obj, head, index, value); - else if (port == 0x03ce) nv_wrvgag(obj, head, index, value); - else if (port == 0x03d4) nv_wrvgac(obj, head, index, value); + if (port == 0x03c4) nvkm_wrvgas(device, head, index, value); + else if (port == 0x03ce) nvkm_wrvgag(device, head, index, value); + else if (port == 0x03d4) nvkm_wrvgac(device, head, index, value); } bool -nv_lockvgac(void *obj, bool lock) +nvkm_lockvgac(struct nvkm_device *device, bool lock) { - struct nvkm_device *device = nv_device(obj); - - bool locked = !nv_rdvgac(obj, 0, 0x1f); + bool locked = !nvkm_rdvgac(device, 0, 0x1f); u8 data = lock ? 0x99 : 0x57; if (device->card_type < NV_50) - nv_wrvgac(obj, 0, 0x1f, data); + nvkm_wrvgac(device, 0, 0x1f, data); else - nv_wrvgac(obj, 0, 0x3f, data); + nvkm_wrvgac(device, 0, 0x3f, data); if (device->chipset == 0x11) { if (!(nvkm_rd32(device, 0x001084) & 0x10000000)) - nv_wrvgac(obj, 1, 0x1f, data); + nvkm_wrvgac(device, 1, 0x1f, data); } return locked; } @@ -165,17 +159,16 @@ nv_lockvgac(void *obj, bool lock) * other values are treated as literal values to set */ u8 -nv_rdvgaowner(void *obj) +nvkm_rdvgaowner(struct nvkm_device *device) { - struct nvkm_device *device = nv_device(obj); if (device->card_type < NV_50) { - if (nv_device(obj)->chipset == 0x11) { + if (device->chipset == 0x11) { u32 tied = nvkm_rd32(device, 0x001084) & 0x10000000; if (tied == 0) { - u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80; - u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01; - u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80; - u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01; + u8 slA = nvkm_rdvgac(device, 0, 0x28) & 0x80; + u8 tvA = nvkm_rdvgac(device, 0, 0x33) & 0x01; + u8 slB = nvkm_rdvgac(device, 1, 0x28) & 0x80; + u8 tvB = nvkm_rdvgac(device, 1, 0x33) & 0x01; if (slA && !tvA) return 0x00; if (slB && !tvB) return 0x03; if (slA) return 0x00; @@ -185,28 +178,28 @@ nv_rdvgaowner(void *obj) return 0x04; } - return nv_rdvgac(obj, 0, 0x44); + return nvkm_rdvgac(device, 0, 0x44); } return 0x00; } void -nv_wrvgaowner(void *obj, u8 select) +nvkm_wrvgaowner(struct nvkm_device *device, u8 select) { - if (nv_device(obj)->card_type < NV_50) { + if (device->card_type < NV_50) { u8 owner = (select == 1) ? 3 : select; - if (nv_device(obj)->chipset == 0x11) { + if (device->chipset == 0x11) { /* workaround hw lockup bug */ - nv_rdvgac(obj, 0, 0x1f); - nv_rdvgac(obj, 1, 0x1f); + nvkm_rdvgac(device, 0, 0x1f); + nvkm_rdvgac(device, 1, 0x1f); } - nv_wrvgac(obj, 0, 0x44, owner); + nvkm_wrvgac(device, 0, 0x44, owner); - if (nv_device(obj)->chipset == 0x11) { - nv_wrvgac(obj, 0, 0x2e, owner); - nv_wrvgac(obj, 0, 0x2e, owner); + if (device->chipset == 0x11) { + nvkm_wrvgac(device, 0, 0x2e, owner); + nvkm_wrvgac(device, 0, 0x2e, owner); } } } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 95b6468d5f278..8b175d8cec660 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -214,7 +214,7 @@ static u8 init_rdport(struct nvbios_init *init, u16 port) { if (init_exec(init)) - return nv_rdport(init->subdev, init->crtc, port); + return nvkm_rdport(init->subdev->device, init->crtc, port); return 0x00; } @@ -222,7 +222,7 @@ static void init_wrport(struct nvbios_init *init, u16 port, u8 value) { if (init_exec(init)) - nv_wrport(init->subdev, init->crtc, port, value); + nvkm_wrport(init->subdev->device, init->crtc, port, value); } static u8 @@ -231,7 +231,7 @@ init_rdvgai(struct nvbios_init *init, u16 port, u8 index) struct nvkm_subdev *subdev = init->subdev; if (init_exec(init)) { int head = init->crtc < 0 ? 0 : init->crtc; - return nv_rdvgai(subdev, head, port, index); + return nvkm_rdvgai(subdev->device, head, port, index); } return 0x00; } @@ -239,19 +239,21 @@ init_rdvgai(struct nvbios_init *init, u16 port, u8 index) static void init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) { + struct nvkm_device *device = init->subdev->device; + /* force head 0 for updates to cr44, it only exists on first head */ - if (nv_device(init->subdev)->card_type < NV_50) { + if (device->card_type < NV_50) { if (port == 0x03d4 && index == 0x44) init->crtc = 0; } if (init_exec(init)) { int head = init->crtc < 0 ? 0 : init->crtc; - nv_wrvgai(init->subdev, head, port, index, value); + nvkm_wrvgai(device, head, port, index, value); } /* select head 1 if cr44 write selected it */ - if (nv_device(init->subdev)->card_type < NV_50) { + if (device->card_type < NV_50) { if (port == 0x03d4 && index == 0x44 && value == 3) init->crtc = 1; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index c9c66f8dda2e2..1f5c1332bf255 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -367,7 +367,7 @@ nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info) u32 sel_clk = nvkm_rd32(device, 0x680524); if ((info->reg == 0x680508 && sel_clk & 0x20) || (info->reg == 0x680520 && sel_clk & 0x80)) { - if (nv_rdvgac(bios, 0, 0x27) < 0xa3) + if (nvkm_rdvgac(device, 0, 0x27) < 0xa3) info->refclk = 200000; else info->refclk = 25000; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index 4338e437bcc39..989513fae7d5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -36,7 +36,7 @@ _nvkm_devinit_fini(struct nvkm_object *object, bool suspend) init->post = true; /* unlock the extended vga crtc regs */ - nv_lockvgac(init, false); + nvkm_lockvgac(init->subdev.device, false); return nvkm_subdev_fini(&init->subdev, suspend); } @@ -67,7 +67,7 @@ _nvkm_devinit_dtor(struct nvkm_object *object) struct nvkm_devinit *init = (void *)object; /* lock crtc regs */ - nv_lockvgac(init, true); + nvkm_lockvgac(init->subdev.device, true); nvkm_subdev_destroy(&init->subdev); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 5158ea62f65ad..41d9dbb075a4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -49,7 +49,7 @@ nv04_devinit_meminit(struct nvkm_devinit *init) } /* Sequencer and refresh off */ - nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) | 0x20); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) | 0x20); nvkm_mask(device, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF); nvkm_mask(device, NV04_PFB_BOOT_0, ~0, @@ -105,7 +105,7 @@ nv04_devinit_meminit(struct nvkm_devinit *init) /* Refresh on, sequencer on */ nvkm_mask(device, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0); - nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) & ~0x20); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) & ~0x20); fbmem_fini(fb); } @@ -406,8 +406,8 @@ nv04_devinit_fini(struct nvkm_object *object, bool suspend) /* unslave crtcs */ if (init->owner < 0) - init->owner = nv_rdvgaowner(init); - nv_wrvgaowner(init, 0); + init->owner = nvkm_rdvgaowner(device); + nvkm_wrvgaowner(device, 0); return 0; } @@ -416,13 +416,14 @@ nv04_devinit_init(struct nvkm_object *object) { struct nv04_devinit *init = (void *)object; struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; if (!init->base.post) { - u32 htotal = nv_rdvgac(init, 0, 0x06); - htotal |= (nv_rdvgac(init, 0, 0x07) & 0x01) << 8; - htotal |= (nv_rdvgac(init, 0, 0x07) & 0x20) << 4; - htotal |= (nv_rdvgac(init, 0, 0x25) & 0x01) << 10; - htotal |= (nv_rdvgac(init, 0, 0x41) & 0x01) << 11; + u32 htotal = nvkm_rdvgac(device, 0, 0x06); + htotal |= (nvkm_rdvgac(device, 0, 0x07) & 0x01) << 8; + htotal |= (nvkm_rdvgac(device, 0, 0x07) & 0x20) << 4; + htotal |= (nvkm_rdvgac(device, 0, 0x25) & 0x01) << 10; + htotal |= (nvkm_rdvgac(device, 0, 0x41) & 0x01) << 11; if (!htotal) { nvkm_debug(subdev, "adaptor not initialised\n"); init->base.post = true; @@ -438,7 +439,7 @@ nv04_devinit_dtor(struct nvkm_object *object) struct nv04_devinit *init = (void *)object; /* restore vga owner saved at first init */ - nv_wrvgaowner(init, init->owner); + nvkm_wrvgaowner(init->base.subdev.device, init->owner); nvkm_devinit_destroy(&init->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index 54de25eea98a1..32be8852e0bcc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -70,7 +70,7 @@ nv05_devinit_meminit(struct nvkm_devinit *init) } /* Sequencer off */ - nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) | 0x20); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) | 0x20); if (nvkm_rd32(device, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE) goto out; @@ -122,7 +122,7 @@ nv05_devinit_meminit(struct nvkm_devinit *init) out: /* Sequencer on */ - nv_wrvgas(init, 0, 1, nv_rdvgas(init, 0, 1) & ~0x20); + nvkm_wrvgas(device, 0, 1, nvkm_rdvgas(device, 0, 1) & ~0x20); fbmem_fini(fb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index 548b3fe09cbfa..bbcc3080a478f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -105,8 +105,8 @@ nv50_devinit_init(struct nvkm_object *object) int ret, i = 0; if (!init->base.post) { - if (!nv_rdvgac(init, 0, 0x00) && - !nv_rdvgac(init, 0, 0x1a)) { + if (!nvkm_rdvgac(device, 0, 0x00) && + !nvkm_rdvgac(device, 0, 0x1a)) { nvkm_debug(subdev, "adaptor not initialised\n"); init->base.post = true; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c index 230727847c68b..e76c555d4d0e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c @@ -34,39 +34,39 @@ struct nv04_i2c_port { static void nv04_i2c_drive_scl(struct nvkm_i2c_port *base, int state) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = nvkm_i2c(base)->subdev.device; struct nv04_i2c_port *port = (void *)base; - u8 val = nv_rdvgac(i2c, 0, port->drive); + u8 val = nvkm_rdvgac(device, 0, port->drive); if (state) val |= 0x20; else val &= 0xdf; - nv_wrvgac(i2c, 0, port->drive, val | 0x01); + nvkm_wrvgac(device, 0, port->drive, val | 0x01); } static void nv04_i2c_drive_sda(struct nvkm_i2c_port *base, int state) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = nvkm_i2c(base)->subdev.device; struct nv04_i2c_port *port = (void *)base; - u8 val = nv_rdvgac(i2c, 0, port->drive); + u8 val = nvkm_rdvgac(device, 0, port->drive); if (state) val |= 0x10; else val &= 0xef; - nv_wrvgac(i2c, 0, port->drive, val | 0x01); + nvkm_wrvgac(device, 0, port->drive, val | 0x01); } static int nv04_i2c_sense_scl(struct nvkm_i2c_port *base) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = nvkm_i2c(base)->subdev.device; struct nv04_i2c_port *port = (void *)base; - return !!(nv_rdvgac(i2c, 0, port->sense) & 0x04); + return !!(nvkm_rdvgac(device, 0, port->sense) & 0x04); } static int nv04_i2c_sense_sda(struct nvkm_i2c_port *base) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); + struct nvkm_device *device = nvkm_i2c(base)->subdev.device; struct nv04_i2c_port *port = (void *)base; - return !!(nv_rdvgac(i2c, 0, port->sense) & 0x08); + return !!(nvkm_rdvgac(device, 0, port->sense) & 0x08); } static const struct nvkm_i2c_func -- GitLab From d36a99d2da22bdffebf644e4a5f811e8eff82360 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:14 +1000 Subject: [PATCH 5458/7006] drm/nouveau/fb: transition nvkm_ram away from being based on nvkm_object Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/core/mm.h | 3 +- .../gpu/drm/nouveau/include/nvkm/subdev/fb.h | 63 ++-- drivers/gpu/drm/nouveau/nouveau_ttm.c | 39 +-- drivers/gpu/drm/nouveau/nvkm/core/mm.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 10 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild | 2 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 72 +---- drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.h | 11 - .../gpu/drm/nouveau/nvkm/subdev/fb/gk104.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gm107.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gt215.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c | 7 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c | 5 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h | 14 - drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 3 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h | 8 - drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h | 38 +-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c | 100 ++++++ drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h | 50 +++ .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 295 ++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 170 +++++----- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c | 37 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 186 +++++------ .../gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c | 100 +++--- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c | 51 ++- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c | 36 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c | 34 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c | 46 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c | 91 +++--- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h | 14 + .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c | 46 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c | 41 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c | 46 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c | 34 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c | 204 ++++++------ .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 9 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 18 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/priv.h | 2 +- 59 files changed, 872 insertions(+), 1092 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h b/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h index 096eb1a623eed..d92fd41e4056f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h @@ -27,7 +27,7 @@ struct nvkm_mm { static inline bool nvkm_mm_initialised(struct nvkm_mm *mm) { - return mm->block_size != 0; + return mm->heap_nodes; } int nvkm_mm_init(struct nvkm_mm *, u32 offset, u32 length, u32 block); @@ -37,4 +37,5 @@ int nvkm_mm_head(struct nvkm_mm *, u8 heap, u8 type, u32 size_max, int nvkm_mm_tail(struct nvkm_mm *, u8 heap, u8 type, u32 size_max, u32 size_min, u32 align, struct nvkm_mm_node **); void nvkm_mm_free(struct nvkm_mm *, struct nvkm_mm_node **); +void nvkm_mm_dump(struct nvkm_mm *, const char *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index 344cc99f0dc17..f102cf97bb939 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -18,7 +18,7 @@ #define NV_MEM_TARGET_VM 3 #define NV_MEM_TARGET_GART 4 -#define NV_MEM_TYPE_VM 0x7f +#define NVKM_RAM_TYPE_VM 0x7f #define NV_MEM_COMP_VM 0x03 struct nvkm_mem { @@ -52,9 +52,6 @@ struct nvkm_fb { struct nvkm_ram *ram; - struct nvkm_mm vram; - struct nvkm_mm tags; - struct { struct nvkm_fb_tile region[16]; int regions; @@ -112,36 +109,35 @@ struct nvkm_ram_data { u32 freq; }; +enum nvkm_ram_type { + NVKM_RAM_TYPE_UNKNOWN = 0, + NVKM_RAM_TYPE_STOLEN, + NVKM_RAM_TYPE_SGRAM, + NVKM_RAM_TYPE_SDRAM, + NVKM_RAM_TYPE_DDR1, + NVKM_RAM_TYPE_DDR2, + NVKM_RAM_TYPE_DDR3, + NVKM_RAM_TYPE_GDDR2, + NVKM_RAM_TYPE_GDDR3, + NVKM_RAM_TYPE_GDDR4, + NVKM_RAM_TYPE_GDDR5 +}; + struct nvkm_ram { - struct nvkm_object base; - enum { - NV_MEM_TYPE_UNKNOWN = 0, - NV_MEM_TYPE_STOLEN, - NV_MEM_TYPE_SGRAM, - NV_MEM_TYPE_SDRAM, - NV_MEM_TYPE_DDR1, - NV_MEM_TYPE_DDR2, - NV_MEM_TYPE_DDR3, - NV_MEM_TYPE_GDDR2, - NV_MEM_TYPE_GDDR3, - NV_MEM_TYPE_GDDR4, - NV_MEM_TYPE_GDDR5 - } type; - u64 stolen; + const struct nvkm_ram_func *func; + struct nvkm_fb *fb; + enum nvkm_ram_type type; u64 size; - u32 tags; + +#define NVKM_RAM_MM_SHIFT 12 + struct nvkm_mm vram; + struct nvkm_mm tags; + u64 stolen; int ranks; int parts; int part_mask; - int (*get)(struct nvkm_fb *, u64 size, u32 align, u32 size_nc, - u32 type, struct nvkm_mem **); - void (*put)(struct nvkm_fb *, struct nvkm_mem **); - - int (*calc)(struct nvkm_fb *, u32 freq); - int (*prog)(struct nvkm_fb *); - void (*tidy)(struct nvkm_fb *); u32 freq; u32 mr[16]; u32 mr1_nuts; @@ -151,4 +147,17 @@ struct nvkm_ram { struct nvkm_ram_data xition; struct nvkm_ram_data target; }; + +struct nvkm_ram_func { + void *(*dtor)(struct nvkm_ram *); + int (*init)(struct nvkm_ram *); + + int (*get)(struct nvkm_ram *, u64 size, u32 align, u32 size_nc, + u32 type, struct nvkm_mem **); + void (*put)(struct nvkm_ram *, struct nvkm_mem **); + + int (*calc)(struct nvkm_ram *, u32 freq); + int (*prog)(struct nvkm_ram *); + void (*tidy)(struct nvkm_ram *); +}; #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 44e878b5601a7..d8999f71a7988 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -64,9 +64,9 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nvkm_fb *fb = nvxx_fb(&drm->device); + struct nvkm_ram *ram = nvxx_fb(&drm->device)->ram; nvkm_mem_node_cleanup(mem->mm_node); - fb->ram->put(fb, (struct nvkm_mem **)&mem->mm_node); + ram->func->put(ram, (struct nvkm_mem **)&mem->mm_node); } static int @@ -76,7 +76,7 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem) { struct nouveau_drm *drm = nouveau_bdev(man->bdev); - struct nvkm_fb *fb = nvxx_fb(&drm->device); + struct nvkm_ram *ram = nvxx_fb(&drm->device)->ram; struct nouveau_bo *nvbo = nouveau_bo(bo); struct nvkm_mem *node; u32 size_nc = 0; @@ -88,9 +88,9 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) size_nc = 1 << nvbo->page_shift; - ret = fb->ram->get(fb, mem->num_pages << PAGE_SHIFT, - mem->page_alignment << PAGE_SHIFT, size_nc, - (nvbo->tile_flags >> 8) & 0x3ff, &node); + ret = ram->func->get(ram, mem->num_pages << PAGE_SHIFT, + mem->page_alignment << PAGE_SHIFT, size_nc, + (nvbo->tile_flags >> 8) & 0x3ff, &node); if (ret) { mem->mm_node = NULL; return (ret == -ENOSPC) ? 0 : ret; @@ -103,38 +103,11 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man, return 0; } -static void -nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix) -{ - struct nvkm_fb *fb = man->priv; - struct nvkm_mm *mm = &fb->vram; - struct nvkm_mm_node *r; - u32 total = 0, free = 0; - - mutex_lock(&nv_subdev(fb)->mutex); - list_for_each_entry(r, &mm->nodes, nl_entry) { - printk(KERN_DEBUG "%s %d: 0x%010llx 0x%010llx\n", - prefix, r->type, ((u64)r->offset << 12), - (((u64)r->offset + r->length) << 12)); - - total += r->length; - if (!r->type) - free += r->length; - } - mutex_unlock(&nv_subdev(fb)->mutex); - - printk(KERN_DEBUG "%s total: 0x%010llx free: 0x%010llx\n", - prefix, (u64)total << 12, (u64)free << 12); - printk(KERN_DEBUG "%s block: 0x%08x\n", - prefix, mm->block_size << 12); -} - const struct ttm_mem_type_manager_func nouveau_vram_manager = { nouveau_vram_manager_init, nouveau_vram_manager_fini, nouveau_vram_manager_new, nouveau_vram_manager_del, - nouveau_vram_manager_debug }; static int diff --git a/drivers/gpu/drm/nouveau/nvkm/core/mm.c b/drivers/gpu/drm/nouveau/nvkm/core/mm.c index 7f458dfd56089..09a1eee8fd334 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/mm.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/mm.c @@ -26,7 +26,7 @@ #define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \ list_entry((root)->nl_entry.dir, struct nvkm_mm_node, nl_entry) -static void +void nvkm_mm_dump(struct nvkm_mm *mm, const char *header) { struct nvkm_mm_node *node; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index 69561ee4e1158..5bdb112dc945d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -569,7 +569,7 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) else if (device->chipset < 0xa0) gr_def(ctx, 0x407d08, 0x00390040); else { - if (nvkm_fb(device)->ram->type != NV_MEM_TYPE_GDDR5) + if (nvkm_fb(device)->ram->type != NVKM_RAM_TYPE_GDDR5) gr_def(ctx, 0x407d08, 0x003d0040); else gr_def(ctx, 0x407d08, 0x003c0040); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index a05ec57150c65..cfd1feed99c38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -174,7 +174,7 @@ static int nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) { struct nvkm_subdev *subdev = &clk->subdev; - struct nvkm_fb *fb = subdev->device->fb; + struct nvkm_ram *ram = subdev->device->fb->ram; struct nvkm_pstate *pstate; int ret, idx = 0; @@ -186,14 +186,14 @@ nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei) nvkm_debug(subdev, "setting performance state %d\n", pstatei); clk->pstate = pstatei; - if (fb->ram && fb->ram->calc) { + if (ram && ram->func->calc) { int khz = pstate->base.domain[nv_clk_src_mem]; do { - ret = fb->ram->calc(fb, khz); + ret = ram->func->calc(ram, khz); if (ret == 0) - ret = fb->ram->prog(fb); + ret = ram->func->prog(ram); } while (ret > 0); - fb->ram->tidy(fb); + ram->func->tidy(ram); } return nvkm_cstate_prog(clk, pstate, 0); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild index d6be4c6c5408b..08105701af7e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild @@ -23,6 +23,8 @@ nvkm-y += nvkm/subdev/fb/gf100.o nvkm-y += nvkm/subdev/fb/gk104.o nvkm-y += nvkm/subdev/fb/gk20a.o nvkm-y += nvkm/subdev/fb/gm107.o + +nvkm-y += nvkm/subdev/fb/ram.o nvkm-y += nvkm/subdev/fb/ramnv04.o nvkm-y += nvkm/subdev/fb/ramnv10.o nvkm-y += nvkm/subdev/fb/ramnv1a.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index f0a5d197e7a0a..328381b8f0acf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "ram.h" #include #include @@ -37,32 +38,24 @@ nvkm_fb_bios_memtype(struct nvkm_bios *bios) if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) { switch (M0203E.type) { - case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2; - case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3; - case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3; - case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5; + case M0203E_TYPE_DDR2 : return NVKM_RAM_TYPE_DDR2; + case M0203E_TYPE_DDR3 : return NVKM_RAM_TYPE_DDR3; + case M0203E_TYPE_GDDR3: return NVKM_RAM_TYPE_GDDR3; + case M0203E_TYPE_GDDR5: return NVKM_RAM_TYPE_GDDR5; default: nvkm_warn(subdev, "M0203E type %02x\n", M0203E.type); - return NV_MEM_TYPE_UNKNOWN; + return NVKM_RAM_TYPE_UNKNOWN; } } nvkm_warn(subdev, "M0203E not matched!\n"); - return NV_MEM_TYPE_UNKNOWN; + return NVKM_RAM_TYPE_UNKNOWN; } int _nvkm_fb_fini(struct nvkm_object *object, bool suspend) { struct nvkm_fb *fb = (void *)object; - int ret; - - if (fb->ram) { - ret = nv_ofuncs(fb->ram)->fini(nv_object(fb->ram), suspend); - if (ret && suspend) - return ret; - } - return nvkm_subdev_fini(&fb->subdev, suspend); } @@ -76,11 +69,8 @@ _nvkm_fb_init(struct nvkm_object *object) if (ret) return ret; - if (fb->ram) { - ret = nv_ofuncs(fb->ram)->init(nv_object(fb->ram)); - if (ret) - return ret; - } + if (fb->ram) + nvkm_ram_init(fb->ram); for (i = 0; i < fb->tile.regions; i++) fb->tile.prog(fb, i, &fb->tile.region[i]); @@ -96,13 +86,8 @@ _nvkm_fb_dtor(struct nvkm_object *object) for (i = 0; i < fb->tile.regions; i++) fb->tile.fini(fb, i, &fb->tile.region[i]); - nvkm_mm_fini(&fb->tags); - - if (fb->ram) { - nvkm_mm_fini(&fb->vram); - nvkm_object_ref(NULL, (struct nvkm_object **)&fb->ram); - } + nvkm_ram_del(&fb->ram); nvkm_subdev_destroy(&fb->subdev); } @@ -111,20 +96,6 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { struct nvkm_fb_impl *impl = (void *)oclass; - static const char *name[] = { - [NV_MEM_TYPE_UNKNOWN] = "of unknown memory type", - [NV_MEM_TYPE_STOLEN ] = "stolen system memory", - [NV_MEM_TYPE_SGRAM ] = "SGRAM", - [NV_MEM_TYPE_SDRAM ] = "SDRAM", - [NV_MEM_TYPE_DDR1 ] = "DDR1", - [NV_MEM_TYPE_DDR2 ] = "DDR2", - [NV_MEM_TYPE_DDR3 ] = "DDR3", - [NV_MEM_TYPE_GDDR2 ] = "GDDR2", - [NV_MEM_TYPE_GDDR3 ] = "GDDR3", - [NV_MEM_TYPE_GDDR4 ] = "GDDR4", - [NV_MEM_TYPE_GDDR5 ] = "GDDR5", - }; - struct nvkm_object *ram; struct nvkm_fb *fb; int ret; @@ -136,33 +107,14 @@ nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, fb->memtype_valid = impl->memtype; - if (!impl->ram) + if (!impl->ram_new) return 0; - ret = nvkm_object_ctor(nv_object(fb), NULL, impl->ram, NULL, 0, &ram); + ret = impl->ram_new(fb, &fb->ram); if (ret) { nvkm_error(&fb->subdev, "vram init failed, %d\n", ret); return ret; } - fb->ram = (void *)ram; - - if (!nvkm_mm_initialised(&fb->vram)) { - ret = nvkm_mm_init(&fb->vram, 0, fb->ram->size >> 12, 1); - if (ret) - return ret; - } - - if (!nvkm_mm_initialised(&fb->tags)) { - ret = nvkm_mm_init(&fb->tags, 0, fb->ram->tags ? - ++fb->ram->tags : 0, 1); - if (ret) - return ret; - - nvkm_debug(&fb->subdev, "%d compression tags\n", fb->ram->tags); - } - - nvkm_info(&fb->subdev, "%d MiB %s\n", (int)(fb->ram->size >> 20), - name[fb->ram->type]); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c index 6c968d1e98b33..1fdb6c3493c68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" struct nvkm_oclass * g84_fb_oclass = &(struct nv50_fb_impl) { @@ -33,6 +34,6 @@ g84_fb_oclass = &(struct nv50_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv50_fb_memtype_valid, - .base.ram = &nv50_ram_oclass, + .base.ram_new = nv50_ram_new, .trap = 0x001d07ff, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c index 4465446c80639..79b523aa52aad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c @@ -22,7 +22,7 @@ * Authors: Ben Skeggs * Roy Spliet */ -#include "priv.h" +#include "ram.h" struct ramxlat { int id; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c index f6f9eee1dcd05..24f83b09e6a1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" /* binary driver only executes this path if the condition (a) is true * for any configuration (combination of rammap+ramcfg+timing) that diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index 1ac7d746e4761..b269f8f67eea4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "gf100.h" +#include "ram.h" extern const u8 gf100_pte_storage_type_map[256]; @@ -113,5 +114,5 @@ gf100_fb_oclass = &(struct nvkm_fb_impl) { .fini = _nvkm_fb_fini, }, .memtype = gf100_fb_memtype_valid, - .ram = &gf100_ram_oclass, + .ram_new = gf100_ram_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index add84641cd817..a0f6497d7a3f0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -1,7 +1,6 @@ #ifndef __NVKM_RAM_NVC0_H__ #define __NVKM_RAM_NVC0_H__ #include "priv.h" -#include "nv50.h" struct gf100_fb { struct nvkm_fb base; @@ -15,14 +14,4 @@ int gf100_fb_ctor(struct nvkm_object *, struct nvkm_object *, void gf100_fb_dtor(struct nvkm_object *); int gf100_fb_init(struct nvkm_object *); bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); - -#define gf100_ram_create(p,e,o,m,d) \ - gf100_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d) -int gf100_ram_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32, int, void **); -int gf100_ram_get(struct nvkm_fb *, u64, u32, u32, u32, - struct nvkm_mem **); -void gf100_ram_put(struct nvkm_fb *, struct nvkm_mem **); - -int gk104_ram_init(struct nvkm_object*); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index 1c08317665bb6..6ed6181a7b344 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "gf100.h" +#include "ram.h" struct nvkm_oclass * gk104_fb_oclass = &(struct nvkm_fb_impl) { @@ -33,5 +34,5 @@ gk104_fb_oclass = &(struct nvkm_fb_impl) { .fini = _nvkm_fb_fini, }, .memtype = gf100_fb_memtype_valid, - .ram = &gk104_ram_oclass, + .ram_new = gk104_ram_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index 843f9356b3607..71e3bd50848a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "gf100.h" +#include "ram.h" struct nvkm_oclass * gm107_fb_oclass = &(struct nvkm_fb_impl) { @@ -33,5 +34,5 @@ gm107_fb_oclass = &(struct nvkm_fb_impl) { .fini = _nvkm_fb_fini, }, .memtype = gf100_fb_memtype_valid, - .ram = &gm107_ram_oclass, + .ram_new = gm107_ram_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c index dd9b8a0a3c8e9..425d289d4acc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" struct nvkm_oclass * gt215_fb_oclass = &(struct nv50_fb_impl) { @@ -33,6 +34,6 @@ gt215_fb_oclass = &(struct nv50_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv50_fb_memtype_valid, - .base.ram = >215_ram_oclass, + .base.ram_new = gt215_ram_new, .trap = 0x000d0fff, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c index 7be4a47ef4ad8..3caed0f12a77a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" struct nvkm_oclass * mcp77_fb_oclass = &(struct nv50_fb_impl) { @@ -33,6 +34,6 @@ mcp77_fb_oclass = &(struct nv50_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv50_fb_memtype_valid, - .base.ram = &mcp77_ram_oclass, + .base.ram_new = mcp77_ram_new, .trap = 0x001d07ff, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c index 2d00656faef50..3ff0bf9cefd25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" struct nvkm_oclass * mcp89_fb_oclass = &(struct nv50_fb_impl) { @@ -33,6 +34,6 @@ mcp89_fb_oclass = &(struct nv50_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv50_fb_memtype_valid, - .base.ram = &mcp77_ram_oclass, + .base.ram_new = mcp77_ram_new, .trap = 0x089d1fff, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c index 7fb578fb8a571..8c8b4b35930d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "ram.h" #include "regsnv04.h" bool @@ -84,5 +85,5 @@ nv04_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv04_ram_oclass, + .base.ram_new = nv04_ram_new, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c index a52cc6c718c21..a51c094df579e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" void nv10_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, @@ -63,7 +64,7 @@ nv10_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv10_ram_oclass, + .base.ram_new = nv10_ram_new, .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c index 83bcb73caf0a0..e56b93d593c53 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" struct nvkm_oclass * nv1a_fb_oclass = &(struct nv04_fb_impl) { @@ -35,7 +36,7 @@ nv1a_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv1a_ram_oclass, + .base.ram_new = nv1a_ram_new, .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c index f1f3fe5ad46ae..ada818ac1735e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" void nv20_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, @@ -44,7 +45,7 @@ nv20_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / fb->ram->parts, 0x40); - if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */ else tile->zcomp = 0x04000000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; @@ -62,7 +63,7 @@ nv20_fb_tile_fini(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) tile->limit = 0; tile->pitch = 0; tile->zcomp = 0; - nvkm_mm_free(&fb->tags, &tile->tag); + nvkm_mm_free(&fb->ram->tags, &tile->tag); } void @@ -86,7 +87,7 @@ nv20_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, + .base.ram_new = nv20_ram_new, .tile.regions = 8, .tile.init = nv20_fb_tile_init, .tile.comp = nv20_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c index 90b17004ffb24..31dc7cf3aa0c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" static void nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, @@ -31,7 +32,7 @@ nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / fb->ram->parts, 0x40); - if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */ else tile->zcomp = 0x00200000; /* Z24S8 */ tile->zcomp |= tile->tag->offset; @@ -51,7 +52,7 @@ nv25_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, + .base.ram_new = nv20_ram_new, .tile.regions = 8, .tile.init = nv20_fb_tile_init, .tile.comp = nv25_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c index 3a6da4ee407ae..6bddaac59ad88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" void nv30_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, @@ -50,7 +51,7 @@ nv30_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / fb->ram->parts, 0x40); - if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */ else tile->zcomp |= 0x02000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -130,7 +131,7 @@ nv30_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, + .base.ram_new = nv20_ram_new, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv30_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c index 7de68c6bea749..e4fd94d003aa0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" static void nv35_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, @@ -31,7 +32,7 @@ nv35_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / fb->ram->parts, 0x40); - if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */ else tile->zcomp |= 0x08000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -52,7 +53,7 @@ nv35_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, + .base.ram_new = nv20_ram_new, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv35_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c index b78062fd6a3a6..51b9b4a589309 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" static void nv36_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, @@ -31,7 +32,7 @@ nv36_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, { u32 tiles = DIV_ROUND_UP(size, 0x40); u32 tags = round_up(tiles / fb->ram->parts, 0x40); - if (!nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + if (!nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */ else tile->zcomp |= 0x20000000; /* Z24S8 */ tile->zcomp |= ((tile->tag->offset ) >> 6); @@ -52,7 +53,7 @@ nv36_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv20_ram_oclass, + .base.ram_new = nv20_ram_new, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv36_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c index fa02bcba36ca3..fa1f8047714e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" void nv40_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, @@ -32,7 +33,7 @@ nv40_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, u32 tiles = DIV_ROUND_UP(size, 0x80); u32 tags = round_up(tiles / fb->ram->parts, 0x100); if ( (flags & 2) && - !nvkm_mm_head(&fb->tags, 0, 1, tags, tags, 1, &tile->tag)) { + !nvkm_mm_head(&fb->ram->tags, 0, 1, tags, tags, 1, &tile->tag)) { tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */ tile->zcomp |= ((tile->tag->offset ) >> 8); tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13; @@ -67,7 +68,7 @@ nv40_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv40_ram_oclass, + .base.ram_new = nv40_ram_new, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h deleted file mode 100644 index 602182661820f..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __NVKM_FB_NV40_H__ -#define __NVKM_FB_NV40_H__ -#include "priv.h" - -struct nv40_ram { - struct nvkm_ram base; - u32 ctrl; - u32 coef; -}; - -int nv40_ram_calc(struct nvkm_fb *, u32); -int nv40_ram_prog(struct nvkm_fb *); -void nv40_ram_tidy(struct nvkm_fb *); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c index 568810536d6f9..5e11dd8ab5c66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" void nv41_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) @@ -61,7 +62,7 @@ nv41_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv41_ram_oclass, + .base.ram_new = nv41_ram_new, .tile.regions = 12, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c index 9b76716982e68..ffdf74b698a74 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" static void nv44_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, @@ -71,7 +72,7 @@ nv44_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv44_ram_oclass, + .base.ram_new = nv44_ram_new, .tile.regions = 12, .tile.init = nv44_fb_tile_init, .tile.fini = nv20_fb_tile_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c index 1f8b69d375f90..c9685991042a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" void nv46_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, @@ -49,7 +50,7 @@ nv46_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv44_ram_oclass, + .base.ram_new = nv44_ram_new, .tile.regions = 15, .tile.init = nv46_fb_tile_init, .tile.fini = nv20_fb_tile_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c index d3b3988d1d49e..f150f2df16dc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" struct nvkm_oclass * nv47_fb_oclass = &(struct nv04_fb_impl) { @@ -35,7 +36,7 @@ nv47_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv41_ram_oclass, + .base.ram_new = nv41_ram_new, .tile.regions = 15, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c index 236e36c5054e7..806c7851a1645 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" struct nvkm_oclass * nv49_fb_oclass = &(struct nv04_fb_impl) { @@ -35,7 +36,7 @@ nv49_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv49_ram_oclass, + .base.ram_new = nv49_ram_new, .tile.regions = 15, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c index 1352b6a73fb00..6f24565c97745 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c @@ -24,6 +24,7 @@ * */ #include "nv04.h" +#include "ram.h" struct nvkm_oclass * nv4e_fb_oclass = &(struct nv04_fb_impl) { @@ -35,7 +36,7 @@ nv4e_fb_oclass = &(struct nv04_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv04_fb_memtype_valid, - .base.ram = &nv4e_ram_oclass, + .base.ram_new = nv4e_ram_new, .tile.regions = 12, .tile.init = nv46_fb_tile_init, .tile.fini = nv20_fb_tile_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 1397e715dc14e..072b0c3881df5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" +#include "ram.h" #include #include @@ -299,6 +300,6 @@ nv50_fb_oclass = &(struct nv50_fb_impl) { .fini = _nvkm_fb_fini, }, .base.memtype = nv50_fb_memtype_valid, - .base.ram = &nv50_ram_oclass, + .base.ram_new = nv50_ram_new, .trap = 0x000707ff, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h index 002b95ae419dd..92bfc3b9bb6dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h @@ -19,13 +19,5 @@ struct nv50_fb_impl { u32 trap; }; -#define nv50_ram_create(p,e,o,d) \ - nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d) -int nv50_ram_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -int nv50_ram_get(struct nvkm_fb *, u64 size, u32 align, u32 ncmin, - u32 memtype, struct nvkm_mem **); -void nv50_ram_put(struct nvkm_fb *, struct nvkm_mem **); -void __nv50_ram_put(struct nvkm_fb *, struct nvkm_mem *); extern int nv50_fb_memtype[0x80]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index 74eb9a22705bb..f206152a3e635 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -3,42 +3,6 @@ #include struct nvkm_bios; -#define nvkm_ram_create(p,e,o,d) \ - nvkm_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d) -#define nvkm_ram_destroy(p) \ - nvkm_object_destroy(&(p)->base) -#define nvkm_ram_init(p) \ - nvkm_object_init(&(p)->base) -#define nvkm_ram_fini(p,s) \ - nvkm_object_fini(&(p)->base, (s)) - -#define nvkm_ram_create_(p,e,o,s,d) \ - nvkm_object_create_((p), (e), (o), 0, (s), (void **)d) -#define _nvkm_ram_dtor nvkm_object_destroy -#define _nvkm_ram_init nvkm_object_init -#define _nvkm_ram_fini nvkm_object_fini - -extern struct nvkm_oclass nv04_ram_oclass; -extern struct nvkm_oclass nv10_ram_oclass; -extern struct nvkm_oclass nv1a_ram_oclass; -extern struct nvkm_oclass nv20_ram_oclass; -extern struct nvkm_oclass nv40_ram_oclass; -extern struct nvkm_oclass nv41_ram_oclass; -extern struct nvkm_oclass nv44_ram_oclass; -extern struct nvkm_oclass nv49_ram_oclass; -extern struct nvkm_oclass nv4e_ram_oclass; -extern struct nvkm_oclass nv50_ram_oclass; -extern struct nvkm_oclass gt215_ram_oclass; -extern struct nvkm_oclass mcp77_ram_oclass; -extern struct nvkm_oclass gf100_ram_oclass; -extern struct nvkm_oclass gk104_ram_oclass; -extern struct nvkm_oclass gm107_ram_oclass; - -int nvkm_sddr2_calc(struct nvkm_ram *ram); -int nvkm_sddr3_calc(struct nvkm_ram *ram); -int nvkm_gddr3_calc(struct nvkm_ram *ram); -int nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts); - #define nvkm_fb_create(p,e,c,d) \ nvkm_fb_create_((p), (e), (c), sizeof(**d), (void **)d) #define nvkm_fb_destroy(p) ({ \ @@ -62,7 +26,7 @@ int _nvkm_fb_fini(struct nvkm_object *, bool); struct nvkm_fb_impl { struct nvkm_oclass base; - struct nvkm_oclass *ram; + int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **); bool (*memtype)(struct nvkm_fb *, u32); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c new file mode 100644 index 0000000000000..c17d559dbfbe3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.c @@ -0,0 +1,100 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "ram.h" + +int +nvkm_ram_init(struct nvkm_ram *ram) +{ + if (ram->func->init) + return ram->func->init(ram); + return 0; +} + +void +nvkm_ram_del(struct nvkm_ram **pram) +{ + struct nvkm_ram *ram = *pram; + if (ram && !WARN_ON(!ram->func)) { + if (ram->func->dtor) + *pram = ram->func->dtor(ram); + nvkm_mm_fini(&ram->tags); + nvkm_mm_fini(&ram->vram); + kfree(*pram); + *pram = NULL; + } +} + +int +nvkm_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb, + enum nvkm_ram_type type, u64 size, u32 tags, + struct nvkm_ram *ram) +{ + static const char *name[] = { + [NVKM_RAM_TYPE_UNKNOWN] = "of unknown memory type", + [NVKM_RAM_TYPE_STOLEN ] = "stolen system memory", + [NVKM_RAM_TYPE_SGRAM ] = "SGRAM", + [NVKM_RAM_TYPE_SDRAM ] = "SDRAM", + [NVKM_RAM_TYPE_DDR1 ] = "DDR1", + [NVKM_RAM_TYPE_DDR2 ] = "DDR2", + [NVKM_RAM_TYPE_DDR3 ] = "DDR3", + [NVKM_RAM_TYPE_GDDR2 ] = "GDDR2", + [NVKM_RAM_TYPE_GDDR3 ] = "GDDR3", + [NVKM_RAM_TYPE_GDDR4 ] = "GDDR4", + [NVKM_RAM_TYPE_GDDR5 ] = "GDDR5", + }; + struct nvkm_subdev *subdev = &fb->subdev; + int ret; + + nvkm_info(subdev, "%d MiB %s\n", (int)(size >> 20), name[type]); + ram->func = func; + ram->fb = fb; + ram->type = type; + ram->size = size; + + if (!nvkm_mm_initialised(&ram->vram)) { + ret = nvkm_mm_init(&ram->vram, 0, size >> NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; + } + + if (!nvkm_mm_initialised(&ram->tags)) { + ret = nvkm_mm_init(&ram->tags, 0, tags ? ++tags : 0, 1); + if (ret) + return ret; + + nvkm_debug(subdev, "%d compression tags\n", tags); + } + + return 0; +} + +int +nvkm_ram_new_(const struct nvkm_ram_func *func, struct nvkm_fb *fb, + enum nvkm_ram_type type, u64 size, u32 tags, + struct nvkm_ram **pram) +{ + if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL))) + return -ENOMEM; + return nvkm_ram_ctor(func, fb, type, size, tags, *pram); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h new file mode 100644 index 0000000000000..f816cbf2ced32 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ram.h @@ -0,0 +1,50 @@ +#ifndef __NVKM_FB_RAM_PRIV_H__ +#define __NVKM_FB_RAM_PRIV_H__ +#include "priv.h" + +int nvkm_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, + enum nvkm_ram_type, u64 size, u32 tags, + struct nvkm_ram *); +int nvkm_ram_new_(const struct nvkm_ram_func *, struct nvkm_fb *, + enum nvkm_ram_type, u64 size, u32 tags, + struct nvkm_ram **); +void nvkm_ram_del(struct nvkm_ram **); +int nvkm_ram_init(struct nvkm_ram *); + +extern const struct nvkm_ram_func nv04_ram_func; + +int nv50_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, + struct nvkm_ram *); +int nv50_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); +void nv50_ram_put(struct nvkm_ram *, struct nvkm_mem **); +void __nv50_ram_put(struct nvkm_ram *, struct nvkm_mem *); + +int gf100_ram_ctor(const struct nvkm_ram_func *, struct nvkm_fb *, + u32, struct nvkm_ram *); +int gf100_ram_get(struct nvkm_ram *, u64, u32, u32, u32, struct nvkm_mem **); +void gf100_ram_put(struct nvkm_ram *, struct nvkm_mem **); + +int gk104_ram_init(struct nvkm_ram *ram); + +/* RAM type-specific MR calculation routines */ +int nvkm_sddr2_calc(struct nvkm_ram *); +int nvkm_sddr3_calc(struct nvkm_ram *); +int nvkm_gddr3_calc(struct nvkm_ram *); +int nvkm_gddr5_calc(struct nvkm_ram *, bool nuts); + +int nv04_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv10_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv1a_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv20_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv40_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv41_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv44_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv49_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv4e_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int nv50_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gt215_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int mcp77_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gf100_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gk104_ram_new(struct nvkm_fb *, struct nvkm_ram **); +int gm107_ram_new(struct nvkm_fb *, struct nvkm_ram **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index af7aaabd2bb32..b579e910ef2d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include "gf100.h" +#define gf100_ram(p) container_of((p), struct gf100_ram, base) +#include "ram.h" #include "ramfuc.h" #include @@ -107,7 +108,7 @@ static void gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) { struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc); - struct nvkm_fb *fb = nvkm_fb(ram); + struct nvkm_fb *fb = ram->base.fb; struct nvkm_device *device = fb->subdev.device; u32 part = nvkm_rd32(device, 0x022438), i; u32 mask = nvkm_rd32(device, 0x022554); @@ -124,14 +125,14 @@ gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic) } static int -gf100_ram_calc(struct nvkm_fb *fb, u32 freq) +gf100_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_subdev *subdev = &fb->subdev; + struct gf100_ram *ram = gf100_ram(base); + struct gf100_ramfuc *fuc = &ram->fuc; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; struct nvkm_clk *clk = device->clk; struct nvkm_bios *bios = device->bios; - struct gf100_ram *ram = (void *)fb->ram; - struct gf100_ramfuc *fuc = &ram->fuc; struct nvbios_ramcfg cfg; u8 ver, cnt, len, strap; struct { @@ -152,7 +153,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(fb)); + strap = nvbios_ramcfg_index(subdev); if (strap >= cnt) { nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; @@ -177,7 +178,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) timing.data = 0; } - ret = ram_init(fuc, fb); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -212,8 +213,8 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) if (mode == 1 && from == 0) { /* calculate refpll */ - ret = gt215_pll_calc(nv_subdev(fb), &ram->refpll, - ram->mempll.refclk, &N1, NULL, &M1, &P); + ret = gt215_pll_calc(subdev, &ram->refpll, ram->mempll.refclk, + &N1, NULL, &M1, &P); if (ret <= 0) { nvkm_error(subdev, "unable to calc refpll\n"); return ret ? ret : -ERANGE; @@ -227,7 +228,7 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000); /* calculate mempll */ - ret = gt215_pll_calc(nv_subdev(fb), &ram->mempll, freq, + ret = gt215_pll_calc(subdev, &ram->mempll, freq, &N1, NULL, &M1, &P); if (ret <= 0) { nvkm_error(subdev, "unable to calc refpll\n"); @@ -404,49 +405,48 @@ gf100_ram_calc(struct nvkm_fb *fb, u32 freq) } static int -gf100_ram_prog(struct nvkm_fb *fb) +gf100_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(fb); - struct gf100_ram *ram = (void *)fb->ram; - struct gf100_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); + struct gf100_ram *ram = gf100_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + ram_exec(&ram->fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); return 0; } static void -gf100_ram_tidy(struct nvkm_fb *fb) +gf100_ram_tidy(struct nvkm_ram *base) { - struct gf100_ram *ram = (void *)fb->ram; - struct gf100_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, false); + struct gf100_ram *ram = gf100_ram(base); + ram_exec(&ram->fuc, false); } extern const u8 gf100_pte_storage_type_map[256]; void -gf100_ram_put(struct nvkm_fb *fb, struct nvkm_mem **pmem) +gf100_ram_put(struct nvkm_ram *ram, struct nvkm_mem **pmem) { - struct nvkm_ltc *ltc = nvkm_ltc(fb); + struct nvkm_ltc *ltc = ram->fb->subdev.device->ltc; struct nvkm_mem *mem = *pmem; *pmem = NULL; if (unlikely(mem == NULL)) return; - mutex_lock(&fb->subdev.mutex); + mutex_lock(&ram->fb->subdev.mutex); if (mem->tag) ltc->tags_free(ltc, &mem->tag); - __nv50_ram_put(fb, mem); - mutex_unlock(&fb->subdev.mutex); + __nv50_ram_put(ram, mem); + mutex_unlock(&ram->fb->subdev.mutex); kfree(mem); } int -gf100_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, +gf100_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin, u32 memtype, struct nvkm_mem **pmem) { - struct nvkm_mm *mm = &fb->vram; + struct nvkm_ltc *ltc = ram->fb->subdev.device->ltc; + struct nvkm_mm *mm = &ram->vram; struct nvkm_mm_node *r; struct nvkm_mem *mem; int type = (memtype & 0x0ff); @@ -454,9 +454,9 @@ gf100_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, const bool comp = gf100_pte_storage_type_map[type] != type; int ret; - size >>= 12; - align >>= 12; - ncmin >>= 12; + size >>= NVKM_RAM_MM_SHIFT; + align >>= NVKM_RAM_MM_SHIFT; + ncmin >>= NVKM_RAM_MM_SHIFT; if (!ncmin) ncmin = size; @@ -467,12 +467,10 @@ gf100_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, INIT_LIST_HEAD(&mem->regions); mem->size = size; - mutex_lock(&fb->subdev.mutex); + mutex_lock(&ram->fb->subdev.mutex); if (comp) { - struct nvkm_ltc *ltc = nvkm_ltc(fb); - /* compression only works with lpages */ - if (align == (1 << (17 - 12))) { + if (align == (1 << (17 - NVKM_RAM_MM_SHIFT))) { int n = size >> 5; ltc->tags_alloc(ltc, n, &mem->tag); } @@ -488,157 +486,158 @@ gf100_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, else ret = nvkm_mm_head(mm, 0, 1, size, ncmin, align, &r); if (ret) { - mutex_unlock(&fb->subdev.mutex); - fb->ram->put(fb, &mem); + mutex_unlock(&ram->fb->subdev.mutex); + ram->func->put(ram, &mem); return ret; } list_add_tail(&r->rl_entry, &mem->regions); size -= r->length; } while (size); - mutex_unlock(&fb->subdev.mutex); + mutex_unlock(&ram->fb->subdev.mutex); r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; + mem->offset = (u64)r->offset << NVKM_RAM_MM_SHIFT; *pmem = mem; return 0; } +static int +gf100_ram_init(struct nvkm_ram *base) +{ + static const u8 train0[] = { + 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, + 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, + }; + static const u32 train1[] = { + 0x00000000, 0xffffffff, + 0x55555555, 0xaaaaaaaa, + 0x33333333, 0xcccccccc, + 0xf0f0f0f0, 0x0f0f0f0f, + 0x00ff00ff, 0xff00ff00, + 0x0000ffff, 0xffff0000, + }; + struct gf100_ram *ram = gf100_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + int i; + + switch (ram->base.type) { + case NVKM_RAM_TYPE_GDDR5: + break; + default: + return 0; + } + + /* prepare for ddr link training, and load training patterns */ + for (i = 0; i < 0x30; i++) { + nvkm_wr32(device, 0x10f968, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f96c, 0x00000000 | (i << 8)); + nvkm_wr32(device, 0x10f920, 0x00000100 | train0[i % 12]); + nvkm_wr32(device, 0x10f924, 0x00000100 | train0[i % 12]); + nvkm_wr32(device, 0x10f918, train1[i % 12]); + nvkm_wr32(device, 0x10f91c, train1[i % 12]); + nvkm_wr32(device, 0x10f920, 0x00000000 | train0[i % 12]); + nvkm_wr32(device, 0x10f924, 0x00000000 | train0[i % 12]); + nvkm_wr32(device, 0x10f918, train1[i % 12]); + nvkm_wr32(device, 0x10f91c, train1[i % 12]); + } + + return 0; +} + +static const struct nvkm_ram_func +gf100_ram_func = { + .init = gf100_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, + .calc = gf100_ram_calc, + .prog = gf100_ram_prog, + .tidy = gf100_ram_tidy, +}; + int -gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 maskaddr, int size, - void **pobject) +gf100_ram_ctor(const struct nvkm_ram_func *func, struct nvkm_fb *fb, + u32 maskaddr, struct nvkm_ram *ram) { - struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_subdev *subdev = &fb->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; - struct nvkm_ram *ram; - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ + const u32 rsvd_head = ( 256 * 1024); /* vga memory */ + const u32 rsvd_tail = (1024 * 1024); /* vbios etc */ u32 parts = nvkm_rd32(device, 0x022438); u32 pmask = nvkm_rd32(device, maskaddr); - u32 bsize = nvkm_rd32(device, 0x10f20c); - u32 offset, length; + u64 bsize = (u64)nvkm_rd32(device, 0x10f20c) << 20; + u64 psize, size = 0; + enum nvkm_ram_type type = nvkm_fb_bios_memtype(bios); bool uniform = true; - int ret, part; - - ret = nvkm_ram_create_(parent, engine, oclass, size, pobject); - ram = *pobject; - if (ret) - return ret; + int ret, i; nvkm_debug(subdev, "100800: %08x\n", nvkm_rd32(device, 0x100800)); nvkm_debug(subdev, "parts %08x mask %08x\n", parts, pmask); - ram->type = nvkm_fb_bios_memtype(bios); - ram->ranks = (nvkm_rd32(device, 0x10f200) & 0x00000004) ? 2 : 1; - /* read amount of vram attached to each memory controller */ - for (part = 0; part < parts; part++) { - if (!(pmask & (1 << part))) { - u32 size = nvkm_rd32(device, 0x11020c + (part * 0x1000)); - if (size != bsize) { - if (size < bsize) - bsize = size; - uniform = false; - } - - nvkm_debug(subdev, "%d: size %08x\n", part, size); - ram->size += (u64)size << 20; + for (i = 0; i < parts; i++) { + if (pmask & (1 << i)) + continue; + + psize = (u64)nvkm_rd32(device, 0x11020c + (i * 0x1000)) << 20; + if (psize != bsize) { + if (psize < bsize) + bsize = psize; + uniform = false; } + + nvkm_debug(subdev, "%d: %d MiB\n", i, (u32)(psize >> 20)); + size += psize; } + ret = nvkm_ram_ctor(func, fb, type, size, 0, ram); + if (ret) + return ret; + + nvkm_mm_fini(&ram->vram); + /* if all controllers have the same amount attached, there's no holes */ if (uniform) { - offset = rsvd_head; - length = (ram->size >> 12) - rsvd_head - rsvd_tail; - ret = nvkm_mm_init(&fb->vram, offset, length, 1); + ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); + if (ret) + return ret; } else { /* otherwise, address lowest common amount from 0GiB */ - ret = nvkm_mm_init(&fb->vram, rsvd_head, - (bsize << 8) * parts - rsvd_head, 1); + ret = nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + ((bsize * parts) - rsvd_head) >> + NVKM_RAM_MM_SHIFT, 1); if (ret) return ret; /* and the rest starting from (8GiB + common_size) */ - offset = (0x0200000000ULL >> 12) + (bsize << 8); - length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail; - - ret = nvkm_mm_init(&fb->vram, offset, length, 1); + ret = nvkm_mm_init(&ram->vram, (0x0200000000ULL + bsize) >> + NVKM_RAM_MM_SHIFT, + (size - (bsize * parts) - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); if (ret) - nvkm_mm_fini(&fb->vram); - } - - if (ret) - return ret; - - ram->get = gf100_ram_get; - ram->put = gf100_ram_put; - return 0; -} - -static int -gf100_ram_init(struct nvkm_object *object) -{ - struct nvkm_fb *fb = (void *)object->parent; - struct nvkm_device *device = fb->subdev.device; - struct gf100_ram *ram = (void *)object; - int ret, i; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; - - /* prepare for ddr link training, and load training patterns */ - switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: { - static const u8 train0[] = { - 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc, - 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, - }; - static const u32 train1[] = { - 0x00000000, 0xffffffff, - 0x55555555, 0xaaaaaaaa, - 0x33333333, 0xcccccccc, - 0xf0f0f0f0, 0x0f0f0f0f, - 0x00ff00ff, 0xff00ff00, - 0x0000ffff, 0xffff0000, - }; - - for (i = 0; i < 0x30; i++) { - nvkm_wr32(device, 0x10f968, 0x00000000 | (i << 8)); - nvkm_wr32(device, 0x10f96c, 0x00000000 | (i << 8)); - nvkm_wr32(device, 0x10f920, 0x00000100 | train0[i % 12]); - nvkm_wr32(device, 0x10f924, 0x00000100 | train0[i % 12]); - nvkm_wr32(device, 0x10f918, train1[i % 12]); - nvkm_wr32(device, 0x10f91c, train1[i % 12]); - nvkm_wr32(device, 0x10f920, 0x00000000 | train0[i % 12]); - nvkm_wr32(device, 0x10f924, 0x00000000 | train0[i % 12]); - nvkm_wr32(device, 0x10f918, train1[i % 12]); - nvkm_wr32(device, 0x10f91c, train1[i % 12]); - } - } break; - default: - break; + return ret; } + ram->ranks = (nvkm_rd32(device, 0x10f200) & 0x00000004) ? 2 : 1; return 0; } -static int -gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_subdev *subdev = &fb->subdev; struct nvkm_bios *bios = subdev->device->bios; struct gf100_ram *ram; int ret; - ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = gf100_ram_ctor(&gf100_ram_func, fb, 0x022554, &ram->base); if (ret) return ret; @@ -654,17 +653,6 @@ gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; } - switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: - ram->base.calc = gf100_ram_calc; - ram->base.prog = gf100_ram_prog; - ram->base.tidy = gf100_ram_tidy; - break; - default: - nvkm_warn(subdev, "reclocking of this ram type unsupported\n"); - return 0; - } - ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20); ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24); ram->fuc.r_0x137320 = ramfuc_reg(0x137320); @@ -725,14 +713,3 @@ gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4); return 0; } - -struct nvkm_oclass -gf100_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = gf100_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 000f45c0f8388..28cd633db0f04 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -21,8 +21,9 @@ * * Authors: Ben Skeggs */ +#define gk104_ram(p) container_of((p), struct gk104_ram, base) +#include "ram.h" #include "ramfuc.h" -#include "gf100.h" #include #include @@ -228,7 +229,7 @@ static void gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, u32 _mask, u32 _data, u32 _copy) { - struct nvkm_fb *fb = nvkm_fb(ram); + struct nvkm_fb *fb = ram->base.fb; struct ramfuc *fuc = &ram->fuc.base; struct nvkm_device *device = fb->subdev.device; u32 addr = 0x110000 + (reg->addr & 0xfff); @@ -248,9 +249,8 @@ gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg, gk104_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c)) static int -gk104_ram_calc_gddr5(struct nvkm_fb *fb, u32 freq) +gk104_ram_calc_gddr5(struct gk104_ram *ram, u32 freq) { - struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; struct nvkm_ram_data *next = ram->base.next; int vc = !next->bios.ramcfg_11_02_08; @@ -674,9 +674,8 @@ gk104_ram_calc_gddr5(struct nvkm_fb *fb, u32 freq) ******************************************************************************/ static int -gk104_ram_calc_sddr3(struct nvkm_fb *fb, u32 freq) +gk104_ram_calc_sddr3(struct gk104_ram *ram, u32 freq) { - struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1); const u32 runk0 = ram->fN1 << 16; @@ -926,9 +925,9 @@ gk104_ram_calc_sddr3(struct nvkm_fb *fb, u32 freq) ******************************************************************************/ static int -gk104_ram_calc_data(struct nvkm_fb *fb, u32 khz, struct nvkm_ram_data *data) +gk104_ram_calc_data(struct gk104_ram *ram, u32 khz, struct nvkm_ram_data *data) { - struct gk104_ram *ram = (void *)fb->ram; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_ram_data *cfg; u32 mhz = khz / 1000; @@ -941,20 +940,19 @@ gk104_ram_calc_data(struct nvkm_fb *fb, u32 khz, struct nvkm_ram_data *data) } } - nvkm_error(&fb->subdev, "ramcfg data for %dMHz not found\n", mhz); + nvkm_error(subdev, "ramcfg data for %dMHz not found\n", mhz); return -EINVAL; } static int -gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) +gk104_ram_calc_xits(struct gk104_ram *ram, struct nvkm_ram_data *next) { - struct gk104_ram *ram = (void *)fb->ram; struct gk104_ramfuc *fuc = &ram->fuc; - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; int refclk, i; int ret; - ret = ram_init(fuc, fb); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -974,7 +972,7 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) refclk = fuc->mempll.refclk; /* calculate refpll coefficients */ - ret = gt215_pll_calc(nv_subdev(fb), &fuc->refpll, refclk, &ram->N1, + ret = gt215_pll_calc(subdev, &fuc->refpll, refclk, &ram->N1, &ram->fN1, &ram->M1, &ram->P1); fuc->mempll.refclk = ret; if (ret <= 0) { @@ -991,7 +989,7 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) fuc->mempll.min_p = 1; fuc->mempll.max_p = 2; - ret = gt215_pll_calc(nv_subdev(fb), &fuc->mempll, next->freq, + ret = gt215_pll_calc(subdev, &fuc->mempll, next->freq, &ram->N2, NULL, &ram->M2, &ram->P2); if (ret <= 0) { nvkm_error(subdev, "unable to calc mempll\n"); @@ -1006,15 +1004,15 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) ram->base.freq = next->freq; switch (ram->base.type) { - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: ret = nvkm_sddr3_calc(&ram->base); if (ret == 0) - ret = gk104_ram_calc_sddr3(fb, next->freq); + ret = gk104_ram_calc_sddr3(ram, next->freq); break; - case NV_MEM_TYPE_GDDR5: + case NVKM_RAM_TYPE_GDDR5: ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0); if (ret == 0) - ret = gk104_ram_calc_gddr5(fb, next->freq); + ret = gk104_ram_calc_gddr5(ram, next->freq); break; default: ret = -ENOSYS; @@ -1025,21 +1023,21 @@ gk104_ram_calc_xits(struct nvkm_fb *fb, struct nvkm_ram_data *next) } static int -gk104_ram_calc(struct nvkm_fb *fb, u32 freq) +gk104_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_clk *clk = nvkm_clk(fb); - struct gk104_ram *ram = (void *)fb->ram; + struct gk104_ram *ram = gk104_ram(base); + struct nvkm_clk *clk = ram->base.fb->subdev.device->clk; struct nvkm_ram_data *xits = &ram->base.xition; struct nvkm_ram_data *copy; int ret; if (ram->base.next == NULL) { - ret = gk104_ram_calc_data(fb, clk->read(clk, nv_clk_src_mem), + ret = gk104_ram_calc_data(ram, clk->read(clk, nv_clk_src_mem), &ram->base.former); if (ret) return ret; - ret = gk104_ram_calc_data(fb, freq, &ram->base.target); + ret = gk104_ram_calc_data(ram, freq, &ram->base.target); if (ret) return ret; @@ -1063,14 +1061,13 @@ gk104_ram_calc(struct nvkm_fb *fb, u32 freq) ram->base.next = &ram->base.target; } - return gk104_ram_calc_xits(fb, ram->base.next); + return gk104_ram_calc_xits(ram, ram->base.next); } static void -gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) +gk104_ram_prog_0(struct gk104_ram *ram, u32 freq) { - struct nvkm_device *device = fb->subdev.device; - struct gk104_ram *ram = (void *)fb->ram; + struct nvkm_device *device = ram->base.fb->subdev.device; struct nvkm_ram_data *cfg; u32 mhz = freq / 1000; u32 mask, data; @@ -1144,11 +1141,11 @@ gk104_ram_prog_0(struct nvkm_fb *fb, u32 freq) } static int -gk104_ram_prog(struct nvkm_fb *fb) +gk104_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(fb); - struct gk104_ram *ram = (void *)fb->ram; + struct gk104_ram *ram = gk104_ram(base); struct gk104_ramfuc *fuc = &ram->fuc; + struct nvkm_device *device = ram->base.fb->subdev.device; struct nvkm_ram_data *next = ram->base.next; if (!nvkm_boolopt(device->cfgopt, "NvMemExec", true)) { @@ -1156,20 +1153,19 @@ gk104_ram_prog(struct nvkm_fb *fb) return (ram->base.next == &ram->base.xition); } - gk104_ram_prog_0(fb, 1000); + gk104_ram_prog_0(ram, 1000); ram_exec(fuc, true); - gk104_ram_prog_0(fb, next->freq); + gk104_ram_prog_0(ram, next->freq); return (ram->base.next == &ram->base.xition); } static void -gk104_ram_tidy(struct nvkm_fb *fb) +gk104_ram_tidy(struct nvkm_ram *base) { - struct gk104_ram *ram = (void *)fb->ram; - struct gk104_ramfuc *fuc = &ram->fuc; + struct gk104_ram *ram = gk104_ram(base); ram->base.next = NULL; - ram_exec(fuc, false); + ram_exec(&ram->fuc, false); } struct gk104_ram_train { @@ -1185,10 +1181,10 @@ struct gk104_ram_train { }; static int -gk104_ram_train_type(struct nvkm_fb *fb, int i, u8 ramcfg, +gk104_ram_train_type(struct nvkm_ram *ram, int i, u8 ramcfg, struct gk104_ram_train *train) { - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_bios *bios = ram->fb->subdev.device->bios; struct nvbios_M0205E M0205E; struct nvbios_M0205S M0205S; struct nvbios_M0209E M0209E; @@ -1246,9 +1242,9 @@ gk104_ram_train_type(struct nvkm_fb *fb, int i, u8 ramcfg, } static int -gk104_ram_train_init_0(struct nvkm_fb *fb, struct gk104_ram_train *train) +gk104_ram_train_init_0(struct nvkm_ram *ram, struct gk104_ram_train *train) { - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->fb->subdev; struct nvkm_device *device = subdev->device; int i, j; @@ -1282,9 +1278,9 @@ gk104_ram_train_init_0(struct nvkm_fb *fb, struct gk104_ram_train *train) } static int -gk104_ram_train_init(struct nvkm_fb *fb) +gk104_ram_train_init(struct nvkm_ram *ram) { - u8 ramcfg = nvbios_ramcfg_index(nv_subdev(fb)); + u8 ramcfg = nvbios_ramcfg_index(&ram->fb->subdev); struct gk104_ram_train *train; int ret, i; @@ -1292,14 +1288,14 @@ gk104_ram_train_init(struct nvkm_fb *fb) return -ENOMEM; for (i = 0; i < 0x100; i++) { - ret = gk104_ram_train_type(fb, i, ramcfg, train); + ret = gk104_ram_train_type(ram, i, ramcfg, train); if (ret && ret != -ENOENT) break; } - switch (fb->ram->type) { - case NV_MEM_TYPE_GDDR5: - ret = gk104_ram_train_init_0(fb, train); + switch (ram->type) { + case NVKM_RAM_TYPE_GDDR5: + ret = gk104_ram_train_init_0(ram, train); break; default: ret = 0; @@ -1311,19 +1307,14 @@ gk104_ram_train_init(struct nvkm_fb *fb) } int -gk104_ram_init(struct nvkm_object *object) +gk104_ram_init(struct nvkm_ram *ram) { - struct nvkm_fb *fb = (void *)object->parent; - struct gk104_ram *ram = (void *)object; - struct nvkm_device *device = fb->subdev.device; + struct nvkm_subdev *subdev = &ram->fb->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; u8 ver, hdr, cnt, len, snr, ssz; u32 data, save; - int ret, i; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; + int i; /* run a bunch of tables from rammap table. there's actually * individual pointers for each rammap entry too, but, nvidia @@ -1347,7 +1338,7 @@ gk104_ram_init(struct nvkm_object *object) if (i != save >> 4) { nvkm_mask(device, 0x10f65c, 0x000000f0, i << 4); nvbios_exec(&(struct nvbios_init) { - .subdev = nv_subdev(fb), + .subdev = subdev, .bios = bios, .offset = nvbios_rd32(bios, data), .execute = 1, @@ -1359,14 +1350,13 @@ gk104_ram_init(struct nvkm_object *object) nvkm_wr32(device, 0x10ecc0, 0xffffffff); nvkm_mask(device, 0x10f160, 0x00000010, 0x00000010); - return gk104_ram_train_init(fb); + return gk104_ram_train_init(ram); } static int gk104_ram_ctor_data(struct gk104_ram *ram, u8 ramcfg, int i) { - struct nvkm_fb *fb = (void *)nv_object(ram)->parent; - struct nvkm_bios *bios = nvkm_bios(fb); + struct nvkm_bios *bios = ram->base.fb->subdev.device->bios; struct nvkm_ram_data *cfg; struct nvbios_ramcfg *d = &ram->diff; struct nvbios_ramcfg *p, *n; @@ -1432,25 +1422,33 @@ done: return ret; } -static void -gk104_ram_dtor(struct nvkm_object *object) +static void * +gk104_ram_dtor(struct nvkm_ram *base) { - struct gk104_ram *ram = (void *)object; + struct gk104_ram *ram = gk104_ram(base); struct nvkm_ram_data *cfg, *tmp; list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) { kfree(cfg); } - nvkm_ram_destroy(&ram->base); + return ram; } -static int -gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_ram_func +gk104_ram_func = { + .dtor = gk104_ram_dtor, + .init = gk104_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, + .calc = gk104_ram_calc, + .prog = gk104_ram_prog, + .tidy = gk104_ram_tidy, +}; + +int +gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_subdev *subdev = &fb->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; @@ -1461,25 +1459,16 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, u8 ramcfg = nvbios_ramcfg_index(nv_subdev(fb)); u32 tmp; - ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = gf100_ram_ctor(&gk104_ram_func, fb, 0x022554, &ram->base); if (ret) return ret; INIT_LIST_HEAD(&ram->cfg); - switch (ram->base.type) { - case NV_MEM_TYPE_DDR3: - case NV_MEM_TYPE_GDDR5: - ram->base.calc = gk104_ram_calc; - ram->base.prog = gk104_ram_prog; - ram->base.tidy = gk104_ram_tidy; - break; - default: - nvkm_warn(subdev, "reclocking of this RAM type is unsupported\n"); - break; - } - /* calculate a mask of differently configured memory partitions, * because, of course reclocking wasn't complicated enough * already without having to treat some of them differently to @@ -1596,7 +1585,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914); switch (ram->base.type) { - case NV_MEM_TYPE_GDDR5: + case NVKM_RAM_TYPE_GDDR5: ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); ram->fuc.r_mr[1] = ramfuc_reg(0x10f330); ram->fuc.r_mr[2] = ramfuc_reg(0x10f334); @@ -1608,7 +1597,7 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_mr[8] = ramfuc_reg(0x10f354); ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c); break; - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: ram->fuc.r_mr[0] = ramfuc_reg(0x10f300); ram->fuc.r_mr[2] = ramfuc_reg(0x10f320); break; @@ -1634,14 +1623,3 @@ gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, ram->fuc.r_0x100750 = ramfuc_reg(0x100750); return 0; } - -struct nvkm_oclass -gk104_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ram_ctor, - .dtor = gk104_ram_dtor, - .init = gk104_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c index 40079eb44e703..43d807f6ca718 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c @@ -21,31 +21,20 @@ * * Authors: Ben Skeggs */ -#include "gf100.h" +#include "ram.h" -static int -gm107_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_ram *ram; - int ret; +static const struct nvkm_ram_func +gm107_ram_func = { + .init = gk104_ram_init, + .get = gf100_ram_get, + .put = gf100_ram_put, +}; - ret = gf100_ram_create(parent, engine, oclass, 0x021c14, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; +int +gm107_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) +{ + if (!(*pram = kzalloc(sizeof(**pram), GFP_KERNEL))) + return -ENOMEM; - return 0; + return gf100_ram_ctor(&gm107_ram_func, fb, 0x021c14, *pram); } - -struct nvkm_oclass -gm107_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = gk104_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 660079bb4cd43..2cfedc0e15927 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -22,9 +22,9 @@ * Authors: Ben Skeggs * Roy Spliet */ - +#define gt215_ram(p) container_of((p), struct gt215_ram, base) +#include "ram.h" #include "ramfuc.h" -#include "nv50.h" #include #include @@ -153,12 +153,11 @@ gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train) * Link training for (at least) DDR3 */ int -gt215_link_train(struct nvkm_fb *fb) +gt215_link_train(struct gt215_ram *ram) { - struct gt215_ram *ram = (void *)fb->ram; struct gt215_ltrain *train = &ram->ltrain; struct gt215_ramfuc *fuc = &ram->fuc; - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_clk *clk = device->clk; @@ -194,7 +193,7 @@ gt215_link_train(struct nvkm_fb *fb) goto out; /* First: clock up/down */ - ret = ram->base.calc(fb, (u32) M0205T.freq * 1000); + ret = ram->base.func->calc(&ram->base, (u32) M0205T.freq * 1000); if (ret) goto out; @@ -237,7 +236,7 @@ gt215_link_train(struct nvkm_fb *fb) ram_exec(fuc, true); - ram->base.calc(fb, clk_current); + ram->base.func->calc(&ram->base, clk_current); ram_exec(fuc, true); /* Post-processing, avoids flicker */ @@ -246,7 +245,7 @@ gt215_link_train(struct nvkm_fb *fb) gt215_clk_post(clk, f); - ram_train_result(fb, result, 64); + ram_train_result(ram->base.fb, result, 64); for (i = 0; i < 64; i++) nvkm_debug(subdev, "Train: %08x", result[i]); gt215_link_train_calc(result, train); @@ -272,7 +271,7 @@ out: } int -gt215_link_train_init(struct nvkm_fb *fb) +gt215_link_train_init(struct gt215_ram *ram) { static const u32 pattern[16] = { 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee, @@ -280,10 +279,9 @@ gt215_link_train_init(struct nvkm_fb *fb) 0x33333333, 0x55555555, 0x77777777, 0x66666666, 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb, }; - struct nvkm_device *device = fb->subdev.device; - struct nvkm_bios *bios = device->bios; - struct gt215_ram *ram = (void *)fb->ram; struct gt215_ltrain *train = &ram->ltrain; + struct nvkm_device *device = ram->base.fb->subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_mem *mem; struct nvbios_M0205E M0205E; u8 ver, hdr, cnt, len; @@ -302,7 +300,8 @@ gt215_link_train_init(struct nvkm_fb *fb) train->state = NVA3_TRAIN_ONCE; - ret = fb->ram->get(fb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem); + ret = ram->base.func->get(&ram->base, 0x8000, 0x10000, 0, 0x800, + &ram->ltrain.mem); if (ret) return ret; @@ -338,12 +337,10 @@ gt215_link_train_init(struct nvkm_fb *fb) } void -gt215_link_train_fini(struct nvkm_fb *fb) +gt215_link_train_fini(struct gt215_ram *ram) { - struct gt215_ram *ram = (void *)fb->ram; - if (ram->ltrain.mem) - fb->ram->put(fb, &ram->ltrain.mem); + ram->base.func->put(&ram->base, &ram->ltrain.mem); } /* @@ -351,11 +348,10 @@ gt215_link_train_fini(struct nvkm_fb *fb) */ #define T(t) cfg->timing_10_##t static int -gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) +gt215_ram_timing_calc(struct gt215_ram *ram, u32 *timing) { - struct gt215_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; int tUNK_base, tUNK_40_0, prevCL; u32 cur2, cur3, cur7, cur8; @@ -367,10 +363,10 @@ gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) switch ((!T(CWL)) * ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: T(CWL) = T(CL) - 1; break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; break; } @@ -408,8 +404,8 @@ gt215_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) timing[8] = cur8 & 0xffffff00; switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_DDR2: + case NVKM_RAM_TYPE_GDDR3: tUNK_40_0 = prevCL - (cur8 & 0xff); if (tUNK_40_0 > 0) timing[8] |= T(CL); @@ -493,12 +489,12 @@ gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) } static int -gt215_ram_calc(struct nvkm_fb *fb, u32 freq) +gt215_ram_calc(struct nvkm_ram *base, u32 freq) { - struct gt215_ram *ram = (void *)fb->ram; + struct gt215_ram *ram = gt215_ram(base); struct gt215_ramfuc *fuc = &ram->fuc; struct gt215_ltrain *train = &ram->ltrain; - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct gt215_clk_info mclk; @@ -516,7 +512,7 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) ram->base.next = next; if (ram->ltrain.state == NVA3_TRAIN_ONCE) - gt215_link_train(fb); + gt215_link_train(ram); /* lookup memory config data relevant to the target frequency */ data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len, @@ -527,7 +523,7 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) } /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(fb)); + strap = nvbios_ramcfg_index(subdev); if (strap >= cnt) { nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; @@ -551,15 +547,15 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) } } - ret = gt215_pll_info(nvkm_clk(fb), 0x12, 0x4000, freq, &mclk); + ret = gt215_pll_info(device->clk, 0x12, 0x4000, freq, &mclk); if (ret < 0) { nvkm_error(subdev, "failed mclk calculation\n"); return ret; } - gt215_ram_timing_calc(fb, timing); + gt215_ram_timing_calc(ram, timing); - ret = ram_init(fuc, fb); + ret = ram_init(fuc, ram->base.fb); if (ret) return ret; @@ -569,13 +565,13 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) ram->base.mr[2] = ram_rd32(fuc, mr[2]); switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: ret = nvkm_sddr2_calc(&ram->base); break; - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: ret = nvkm_sddr3_calc(&ram->base); break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: ret = nvkm_gddr3_calc(&ram->base); break; default: @@ -630,7 +626,7 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) ram_nsec(fuc, 2000); if (!next->bios.ramcfg_10_02_10) { - if (ram->base.type == NV_MEM_TYPE_GDDR3) + if (ram->base.type == NVKM_RAM_TYPE_GDDR3) ram_mask(fuc, 0x111100, 0x04020000, 0x00020000); else ram_mask(fuc, 0x111100, 0x04020000, 0x04020000); @@ -638,10 +634,10 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) /* If we're disabling the DLL, do it now */ switch (next->bios.ramcfg_DLLoff * ram->base.type) { - case NV_MEM_TYPE_DDR3: + case NVKM_RAM_TYPE_DDR3: nvkm_sddr3_dll_disable(fuc, ram->base.mr); break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: nvkm_gddr3_dll_disable(fuc, ram->base.mr); break; } @@ -657,7 +653,7 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) ram_wr32(fuc, 0x1002dc, 0x00000001); ram_nsec(fuc, 2000); - if (nv_device(fb)->chipset == 0xa3 && freq <= 500000) + if (device->chipset == 0xa3 && freq <= 500000) ram_mask(fuc, 0x100700, 0x00000006, 0x00000006); /* Fiddle with clocks */ @@ -715,7 +711,7 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) ram_mask(fuc, 0x1007e0, 0x22222222, r100760); } - if (nv_device(fb)->chipset == 0xa3 && freq > 500000) { + if (device->chipset == 0xa3 && freq > 500000) { ram_mask(fuc, 0x100700, 0x00000006, 0x00000000); } @@ -759,11 +755,11 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) if (next->bios.ramcfg_10_02_04) { switch (ram->base.type) { - case NV_MEM_TYPE_DDR3: - if (nv_device(fb)->chipset != 0xa8) + case NVKM_RAM_TYPE_DDR3: + if (device->chipset != 0xa8) r111100 |= 0x00000004; /* no break */ - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: r111100 |= 0x08000000; break; default: @@ -771,12 +767,12 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) } } else { switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: r111100 |= 0x1a800000; unk714 |= 0x00000010; break; - case NV_MEM_TYPE_DDR3: - if (nv_device(fb)->chipset == 0xa8) { + case NVKM_RAM_TYPE_DDR3: + if (device->chipset == 0xa8) { r111100 |= 0x08000000; } else { r111100 &= ~0x00000004; @@ -784,7 +780,7 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) } unk714 |= 0x00000010; break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: r111100 |= 0x30000000; unk714 |= 0x00000020; break; @@ -820,13 +816,13 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) if (!next->bios.ramcfg_DLLoff) nvkm_sddr2_dll_reset(fuc); - if (ram->base.type == NV_MEM_TYPE_GDDR3) { + if (ram->base.type == NVKM_RAM_TYPE_GDDR3) { ram_nsec(fuc, 31000); } else { ram_nsec(fuc, 14000); } - if (ram->base.type == NV_MEM_TYPE_DDR3) { + if (ram->base.type == NVKM_RAM_TYPE_DDR3) { ram_wr32(fuc, 0x100264, 0x1); ram_nsec(fuc, 2000); } @@ -862,11 +858,11 @@ gt215_ram_calc(struct nvkm_fb *fb, u32 freq) } static int -gt215_ram_prog(struct nvkm_fb *fb) +gt215_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(fb); - struct gt215_ram *ram = (void *)fb->ram; + struct gt215_ram *ram = gt215_ram(base); struct gt215_ramfuc *fuc = &ram->fuc; + struct nvkm_device *device = ram->base.fb->subdev.device; bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true); if (exec) { @@ -887,70 +883,56 @@ gt215_ram_prog(struct nvkm_fb *fb) } static void -gt215_ram_tidy(struct nvkm_fb *fb) +gt215_ram_tidy(struct nvkm_ram *base) { - struct gt215_ram *ram = (void *)fb->ram; - struct gt215_ramfuc *fuc = &ram->fuc; - ram_exec(fuc, false); + struct gt215_ram *ram = gt215_ram(base); + ram_exec(&ram->fuc, false); } static int -gt215_ram_init(struct nvkm_object *object) +gt215_ram_init(struct nvkm_ram *base) { - struct nvkm_fb *fb = (void *)object->parent; - struct gt215_ram *ram = (void *)object; - int ret; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; - - gt215_link_train_init(fb); + struct gt215_ram *ram = gt215_ram(base); + gt215_link_train_init(ram); return 0; } -static int -gt215_ram_fini(struct nvkm_object *object, bool suspend) +static void * +gt215_ram_dtor(struct nvkm_ram *base) { - struct nvkm_fb *fb = (void *)object->parent; - - if (!suspend) - gt215_link_train_fini(fb); - - return 0; + struct gt215_ram *ram = gt215_ram(base); + gt215_link_train_fini(ram); + return ram; } -static int -gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 datasize, - struct nvkm_object **pobject) +static const struct nvkm_ram_func +gt215_ram_func = { + .dtor = gt215_ram_dtor, + .init = gt215_ram_init, + .get = nv50_ram_get, + .put = nv50_ram_put, + .calc = gt215_ram_calc, + .prog = gt215_ram_prog, + .tidy = gt215_ram_tidy, +}; + +int +gt215_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_subdev *subdev = &fb->subdev; - struct nvkm_gpio *gpio = subdev->device->gpio; + struct nvkm_gpio *gpio = fb->subdev.device->gpio; struct dcb_gpio_func func; struct gt215_ram *ram; - int ret, i; u32 reg, shift; + int ret, i; + + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; - ret = nv50_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + ret = nv50_ram_ctor(>215_ram_func, fb, &ram->base); if (ret) return ret; - switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: - case NV_MEM_TYPE_DDR3: - case NV_MEM_TYPE_GDDR3: - ram->base.calc = gt215_ram_calc; - ram->base.prog = gt215_ram_prog; - ram->base.tidy = gt215_ram_tidy; - break; - default: - nvkm_warn(subdev, "reclocking of this ram type unsupported\n"); - return 0; - } - ram->fuc.r_0x001610 = ramfuc_reg(0x001610); ram->fuc.r_0x001700 = ramfuc_reg(0x001700); ram->fuc.r_0x002504 = ramfuc_reg(0x002504); @@ -1008,13 +990,3 @@ gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } - -struct nvkm_oclass -gt215_ram_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = gt215_ram_init, - .fini = gt215_ram_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c index e1d82ab25dbc6..0a0e44b755774 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#define mcp77_ram(p) container_of((p), struct mcp77_ram, base) +#include "ram.h" struct mcp77_ram { struct nvkm_ram base; @@ -29,56 +30,13 @@ struct mcp77_ram { }; static int -mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 datasize, - struct nvkm_object **pobject) +mcp77_ram_init(struct nvkm_ram *base) { - u32 rsvd_head = ( 256 * 1024); /* vga memory */ - u32 rsvd_tail = (1024 * 1024); /* vbios etc */ - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_device *device = fb->subdev.device; - struct mcp77_ram *ram; - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(fb); - if (ret) - return ret; - - ram->base.type = NV_MEM_TYPE_STOLEN; - ram->base.stolen = (u64)nvkm_rd32(device, 0x100e10) << 12; - ram->base.size = (u64)nvkm_rd32(device, 0x100e14) << 12; - - rsvd_tail += 0x1000; - ram->poller_base = ram->base.size - rsvd_tail; - - ret = nvkm_mm_init(&fb->vram, rsvd_head >> 12, - (ram->base.size - (rsvd_head + rsvd_tail)) >> 12, - 1); - if (ret) - return ret; - - ram->base.get = nv50_ram_get; - ram->base.put = nv50_ram_put; - return 0; -} - -static int -mcp77_ram_init(struct nvkm_object *object) -{ - struct nvkm_fb *fb = nvkm_fb(object); - struct nvkm_device *device = fb->subdev.device; - struct mcp77_ram *ram = (void *)object; - int ret; - u64 dniso, hostnb, flush; - - ret = nvkm_ram_init(&ram->base); - if (ret) - return ret; - - dniso = ((ram->base.size - (ram->poller_base + 0x00)) >> 5) - 1; - hostnb = ((ram->base.size - (ram->poller_base + 0x20)) >> 5) - 1; - flush = ((ram->base.size - (ram->poller_base + 0x40)) >> 5) - 1; + struct mcp77_ram *ram = mcp77_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + u32 dniso = ((ram->base.size - (ram->poller_base + 0x00)) >> 5) - 1; + u32 hostnb = ((ram->base.size - (ram->poller_base + 0x20)) >> 5) - 1; + u32 flush = ((ram->base.size - (ram->poller_base + 0x40)) >> 5) - 1; /* Enable NISO poller for various clients and set their associated * read address, only for MCP77/78 and MCP79/7A. (fd#25701) @@ -92,12 +50,38 @@ mcp77_ram_init(struct nvkm_object *object) return 0; } -struct nvkm_oclass -mcp77_ram_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = mcp77_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = mcp77_ram_init, - .fini = _nvkm_ram_fini, - }, +static const struct nvkm_ram_func +mcp77_ram_func = { + .init = mcp77_ram_init, + .get = nv50_ram_get, + .put = nv50_ram_put, }; + +int +mcp77_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) +{ + struct nvkm_device *device = fb->subdev.device; + u32 rsvd_head = ( 256 * 1024); /* vga memory */ + u32 rsvd_tail = (1024 * 1024) + 0x1000; /* vbios etc + poller mem */ + u64 base = (u64)nvkm_rd32(device, 0x100e10) << 12; + u64 size = (u64)nvkm_rd32(device, 0x100e14) << 12; + struct mcp77_ram *ram; + int ret; + + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = nvkm_ram_ctor(&mcp77_ram_func, fb, NVKM_RAM_TYPE_STOLEN, + size, 0, &ram->base); + if (ret) + return ret; + + ram->poller_base = size - rsvd_tail; + ram->base.stolen = base; + nvkm_mm_fini(&ram->base.vram); + + return nvkm_mm_init(&ram->base.vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> + NVKM_RAM_MM_SHIFT, 1); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c index db9c29dfabeac..6f053a03d61c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c @@ -21,60 +21,45 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" #include "regsnv04.h" -static int -nv04_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +const struct nvkm_ram_func +nv04_ram_func = { +}; + +int +nv04_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ram *ram; struct nvkm_device *device = fb->subdev.device; u32 boot0 = nvkm_rd32(device, NV04_PFB_BOOT_0); - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; + u64 size; + enum nvkm_ram_type type; if (boot0 & 0x00000100) { - ram->size = ((boot0 >> 12) & 0xf) * 2 + 2; - ram->size *= 1024 * 1024; + size = ((boot0 >> 12) & 0xf) * 2 + 2; + size *= 1024 * 1024; } else { switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) { case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB: - ram->size = 32 * 1024 * 1024; + size = 32 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB: - ram->size = 16 * 1024 * 1024; + size = 16 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB: - ram->size = 8 * 1024 * 1024; + size = 8 * 1024 * 1024; break; case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB: - ram->size = 4 * 1024 * 1024; + size = 4 * 1024 * 1024; break; } } if ((boot0 & 0x00000038) <= 0x10) - ram->type = NV_MEM_TYPE_SGRAM; + type = NVKM_RAM_TYPE_SGRAM; else - ram->type = NV_MEM_TYPE_SDRAM; + type = NVKM_RAM_TYPE_SDRAM; - return 0; + return nvkm_ram_new_(&nv04_ram_func, fb, type, size, 0, pram); } - -struct nvkm_oclass -nv04_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c index 76cc560e1de38..dfd155c98dbb0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c @@ -21,40 +21,20 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ram *ram; struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; u32 cfg0 = nvkm_rd32(device, 0x100200); - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; + enum nvkm_ram_type type; if (cfg0 & 0x00000001) - ram->type = NV_MEM_TYPE_DDR1; + type = NVKM_RAM_TYPE_DDR1; else - ram->type = NV_MEM_TYPE_SDRAM; + type = NVKM_RAM_TYPE_SDRAM; - ram->size = nvkm_rd32(device, 0x10020c) & 0xff000000; - return 0; + return nvkm_ram_new_(&nv04_ram_func, fb, type, size, 0, pram); } - -struct nvkm_oclass -nv10_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c index 6bbdf817471f5..3c6a8710e8127 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c @@ -21,18 +21,13 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv1a_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ram *ram; struct pci_dev *bridge; u32 mem, mib; - int ret; bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1)); if (!bridge) { @@ -40,12 +35,7 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, return -ENODEV; } - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - - if (nv_device(fb)->chipset == 0x1a) { + if (fb->subdev.device->chipset == 0x1a) { pci_read_config_dword(bridge, 0x7c, &mem); mib = ((mem >> 6) & 31) + 1; } else { @@ -53,18 +43,6 @@ nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, mib = ((mem >> 4) & 127) + 1; } - ram->type = NV_MEM_TYPE_STOLEN; - ram->size = mib * 1024 * 1024; - return 0; + return nvkm_ram_new_(&nv04_ram_func, fb, NVKM_RAM_TYPE_STOLEN, + mib * 1024 * 1024, 0, pram); } - -struct nvkm_oclass -nv1a_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv1a_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c index 017f82e5b61e2..747e47c10cc74 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c @@ -21,43 +21,29 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv20_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ram *ram; struct nvkm_device *device = fb->subdev.device; - u32 pbus1218 = nvkm_rd32(device, 0x001218); + u32 pbus1218 = nvkm_rd32(device, 0x001218); + u32 size = (nvkm_rd32(device, 0x10020c) & 0xff000000); + u32 tags = nvkm_rd32(device, 0x100320); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + switch (pbus1218 & 0x00000300) { + case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break; + case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break; + case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break; + case 0x00000300: type = NVKM_RAM_TYPE_GDDR2; break; + } + + ret = nvkm_ram_new_(&nv04_ram_func, fb, type, size, tags, pram); if (ret) return ret; - switch (pbus1218 & 0x00000300) { - case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break; - } - ram->size = (nvkm_rd32(device, 0x10020c) & 0xff000000); - ram->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; - ram->tags = nvkm_rd32(device, 0x100320); + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - -struct nvkm_oclass -nv20_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv20_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c index 6b2ca3ff83978..56f8cffc25604 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" #include #include @@ -30,12 +30,12 @@ #include #include -int -nv40_ram_calc(struct nvkm_fb *fb, u32 freq) +static int +nv40_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nvkm_subdev *subdev = &fb->subdev; + struct nv40_ram *ram = nv40_ram(base); + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_bios *bios = subdev->device->bios; - struct nv40_ram *ram = (void *)fb->ram; struct nvbios_pll pll; int N1, M1, N2, M2; int log2P, ret; @@ -46,8 +46,7 @@ nv40_ram_calc(struct nvkm_fb *fb, u32 freq) return ret; } - ret = nv04_pll_calc(nv_subdev(fb), &pll, freq, - &N1, &M1, &N2, &M2, &log2P); + ret = nv04_pll_calc(subdev, &pll, freq, &N1, &M1, &N2, &M2, &log2P); if (ret < 0) return ret; @@ -64,12 +63,13 @@ nv40_ram_calc(struct nvkm_fb *fb, u32 freq) return 0; } -int -nv40_ram_prog(struct nvkm_fb *fb) +static int +nv40_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = fb->subdev.device; + struct nv40_ram *ram = nv40_ram(base); + struct nvkm_subdev *subdev = &ram->base.fb->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; - struct nv40_ram *ram = (void *)fb->ram; struct bit_entry M; u32 crtc_mask = 0; u8 sr1[2]; @@ -152,7 +152,7 @@ nv40_ram_prog(struct nvkm_fb *fb) /* execute memory reset script from vbios */ if (!bit_entry(bios, 'M', &M)) { struct nvbios_init init = { - .subdev = nv_subdev(fb), + .subdev = subdev, .bios = bios, .offset = nvbios_rd16(bios, M.offset + 0x00), .execute = 1, @@ -181,51 +181,50 @@ nv40_ram_prog(struct nvkm_fb *fb) return 0; } -void -nv40_ram_tidy(struct nvkm_fb *fb) +static void +nv40_ram_tidy(struct nvkm_ram *base) { } -static int -nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_ram_func +nv40_ram_func = { + .calc = nv40_ram_calc, + .prog = nv40_ram_prog, + .tidy = nv40_ram_tidy, +}; + +int +nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type type, u64 size, + u32 tags, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); struct nv40_ram *ram; + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + return nvkm_ram_ctor(&nv40_ram_func, fb, type, size, tags, &ram->base); +} + +int +nv40_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) +{ struct nvkm_device *device = fb->subdev.device; u32 pbus1218 = nvkm_rd32(device, 0x001218); + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 tags = nvkm_rd32(device, 0x100320); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - switch (pbus1218 & 0x00000300) { - case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break; - case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break; - case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break; - case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break; + case 0x00000000: type = NVKM_RAM_TYPE_SDRAM; break; + case 0x00000100: type = NVKM_RAM_TYPE_DDR1 ; break; + case 0x00000200: type = NVKM_RAM_TYPE_GDDR3; break; + case 0x00000300: type = NVKM_RAM_TYPE_DDR2 ; break; } - ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; - ram->base.parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; - ram->base.tags = nvkm_rd32(device, 0x100320); - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; + ret = nv40_ram_new_(fb, type, size, tags, pram); + if (ret) + return ret; + + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - - -struct nvkm_oclass -nv40_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h new file mode 100644 index 0000000000000..8a0524566b486 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.h @@ -0,0 +1,14 @@ +#ifndef __NV40_FB_RAM_H__ +#define __NV40_FB_RAM_H__ +#define nv40_ram(p) container_of((p), struct nv40_ram, base) +#include "ram.h" + +struct nv40_ram { + struct nvkm_ram base; + u32 ctrl; + u32 coef; +}; + +int nv40_ram_new_(struct nvkm_fb *fb, enum nvkm_ram_type, u64, u32, + struct nvkm_ram **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c index 9ebfb0d8fdd7e..114828be292ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c @@ -21,47 +21,29 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -static int -nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv41_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nv40_ram *ram; struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 tags = nvkm_rd32(device, 0x100320); u32 fb474 = nvkm_rd32(device, 0x100474); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - if (fb474 & 0x00000004) - ram->base.type = NV_MEM_TYPE_GDDR3; + type = NVKM_RAM_TYPE_GDDR3; if (fb474 & 0x00000002) - ram->base.type = NV_MEM_TYPE_DDR2; + type = NVKM_RAM_TYPE_DDR2; if (fb474 & 0x00000001) - ram->base.type = NV_MEM_TYPE_DDR1; + type = NVKM_RAM_TYPE_DDR1; - ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; - ram->base.parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; - ram->base.tags = nvkm_rd32(device, 0x100320); - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; + ret = nv40_ram_new_(fb, type, size, tags, pram); + if (ret) + return ret; + + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - -struct nvkm_oclass -nv41_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv41_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c index ac0ba6deb576d..bc56fbf1c788c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c @@ -21,45 +21,22 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -static int -nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv44_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nv40_ram *ram; struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; u32 fb474 = nvkm_rd32(device, 0x100474); - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; if (fb474 & 0x00000004) - ram->base.type = NV_MEM_TYPE_GDDR3; + type = NVKM_RAM_TYPE_GDDR3; if (fb474 & 0x00000002) - ram->base.type = NV_MEM_TYPE_DDR2; + type = NVKM_RAM_TYPE_DDR2; if (fb474 & 0x00000001) - ram->base.type = NV_MEM_TYPE_DDR1; + type = NVKM_RAM_TYPE_DDR1; - ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; - return 0; + return nv40_ram_new_(fb, type, size, 0, pram); } - -struct nvkm_oclass -nv44_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c index 4a19da6a26bae..c01f4b1022b87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c @@ -21,47 +21,29 @@ * * Authors: Ben Skeggs */ -#include "nv40.h" +#include "ramnv40.h" -static int -nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv49_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nv40_ram *ram; struct nvkm_device *device = fb->subdev.device; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + u32 tags = nvkm_rd32(device, 0x100320); u32 fb914 = nvkm_rd32(device, 0x100914); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - switch (fb914 & 0x00000003) { - case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break; - case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break; - case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break; + case 0x00000000: type = NVKM_RAM_TYPE_DDR1 ; break; + case 0x00000001: type = NVKM_RAM_TYPE_DDR2 ; break; + case 0x00000002: type = NVKM_RAM_TYPE_GDDR3; break; case 0x00000003: break; } - ram->base.size = nvkm_rd32(device, 0x10020c) & 0xff000000; - ram->base.parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; - ram->base.tags = nvkm_rd32(device, 0x100320); - ram->base.calc = nv40_ram_calc; - ram->base.prog = nv40_ram_prog; - ram->base.tidy = nv40_ram_tidy; + ret = nv40_ram_new_(fb, type, size, tags, pram); + if (ret) + return ret; + + (*pram)->parts = (nvkm_rd32(device, 0x100200) & 0x00000003) + 1; return 0; } - -struct nvkm_oclass -nv49_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv49_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c index 1778b3c7c8975..fa3c2e06203dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c @@ -21,35 +21,13 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ram.h" -static int -nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv4e_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_ram *ram; struct nvkm_device *device = fb->subdev.device; - int ret; - - ret = nvkm_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); - if (ret) - return ret; - - ram->size = nvkm_rd32(device, 0x10020c) & 0xff000000; - ram->type = NV_MEM_TYPE_STOLEN; - return 0; + u32 size = nvkm_rd32(device, 0x10020c) & 0xff000000; + return nvkm_ram_new_(&nv04_ram_func, fb, NVKM_RAM_TYPE_UNKNOWN, + size, 0, pram); } - -struct nvkm_oclass -nv4e_ram_oclass = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv4e_ram_create, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c index 1c38fb4d9c1f8..9197e0ef5cdb9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c @@ -21,8 +21,10 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#define nv50_ram(p) container_of((p), struct nv50_ram, base) +#include "ram.h" #include "ramseq.h" +#include "nv50.h" #include #include @@ -66,11 +68,10 @@ struct nv50_ram { #define T(t) cfg->timing_10_##t static int -nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) +nv50_ram_timing_calc(struct nv50_ram *ram, u32 *timing) { - struct nv50_ram *ram = (void *)fb->ram; struct nvbios_ramcfg *cfg = &ram->base.target.bios; - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_device *device = subdev->device; u32 cur2, cur4, cur7, cur8; u8 unkt3b; @@ -81,16 +82,16 @@ nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) cur8 = nvkm_rd32(device, 0x100240); switch ((!T(CWL)) * ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: T(CWL) = T(CL) - 1; break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: T(CWL) = ((cur2 & 0xff000000) >> 24) + 1; break; } /* XXX: N=1 is not proper statistics */ - if (nv_device(fb)->chipset == 0xa0) { + if (device->chipset == 0xa0) { unkt3b = 0x19 + ram->base.next->bios.rammap_00_16_40; timing[6] = (0x2d + T(CL) - T(CWL) + ram->base.next->bios.rammap_00_16_40) << 16 | @@ -127,10 +128,11 @@ nv50_ram_timing_calc(struct nvkm_fb *fb, u32 *timing) timing[8] = (cur8 & 0xffffff00); /* XXX: P.version == 1 only has DDR2 and GDDR3? */ - if (fb->ram->type == NV_MEM_TYPE_DDR2) { + if (ram->base.type == NVKM_RAM_TYPE_DDR2) { timing[5] |= (T(CL) + 3) << 8; timing[8] |= (T(CL) - 4); - } else if (fb->ram->type == NV_MEM_TYPE_GDDR3) { + } else + if (ram->base.type == NVKM_RAM_TYPE_GDDR3) { timing[5] |= (T(CL) + 2) << 8; timing[8] |= (T(CL) - 2); } @@ -153,11 +155,11 @@ nvkm_sddr2_dll_reset(struct nv50_ramseq *hwsq) } static int -nv50_ram_calc(struct nvkm_fb *fb, u32 freq) +nv50_ram_calc(struct nvkm_ram *base, u32 freq) { - struct nv50_ram *ram = (void *)fb->ram; + struct nv50_ram *ram = nv50_ram(base); struct nv50_ramseq *hwsq = &ram->hwsq; - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->base.fb->subdev; struct nvkm_bios *bios = subdev->device->bios; struct nvbios_perfE perfE; struct nvbios_pll mpll; @@ -177,7 +179,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) i = 0; do { data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt, - &size, &perfE); + &size, &perfE); if (!data || (ver < 0x25 || ver >= 0x40) || (size < 2)) { nvkm_error(subdev, "invalid/missing perftab entry\n"); @@ -188,7 +190,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) nvbios_rammapEp_from_perf(bios, data, hdr, &next->bios); /* locate specific data set for the attached memory */ - strap = nvbios_ramcfg_index(nv_subdev(fb)); + strap = nvbios_ramcfg_index(subdev); if (strap >= cnt) { nvkm_error(subdev, "invalid ramcfg strap\n"); return -EINVAL; @@ -213,9 +215,9 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) } } - nv50_ram_timing_calc(fb, timing); + nv50_ram_timing_calc(ram, timing); - ret = ram_init(hwsq, nv_subdev(fb)); + ret = ram_init(hwsq, subdev); if (ret) return ret; @@ -225,7 +227,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) ram->base.mr[2] = ram_rd32(hwsq, mr[2]); switch (ram->base.type) { - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: ret = nvkm_gddr3_calc(&ram->base); break; default: @@ -257,7 +259,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) ret = nvbios_pll_parse(bios, 0x004008, &mpll); mpll.vco2.max_freq = 0; if (ret >= 0) { - ret = nv04_pll_calc(nv_subdev(fb), &mpll, freq, + ret = nv04_pll_calc(subdev, &mpll, freq, &N1, &M1, &N2, &M2, &P); if (ret <= 0) ret = -EINVAL; @@ -284,7 +286,7 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) next->bios.rammap_00_16_40 << 14); ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1); ram_mask(hwsq, 0x004008, 0x91ff0000, r004008); - if (nv_device(fb)->chipset >= 0x96) + if (subdev->device->chipset >= 0x96) ram_wr32(hwsq, 0x100da0, r100da0); ram_nsec(hwsq, 64000); /*XXX*/ ram_nsec(hwsq, 32000); /*XXX*/ @@ -298,11 +300,11 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) ram_nsec(hwsq, 12000); switch (ram->base.type) { - case NV_MEM_TYPE_DDR2: + case NVKM_RAM_TYPE_DDR2: ram_nuke(hwsq, mr[0]); /* force update */ ram_mask(hwsq, mr[0], 0x000, 0x000); break; - case NV_MEM_TYPE_GDDR3: + case NVKM_RAM_TYPE_GDDR3: ram_nuke(hwsq, mr[1]); /* force update */ ram_wr32(hwsq, mr[1], ram->base.mr[1]); ram_nuke(hwsq, mr[0]); /* force update */ @@ -382,26 +384,23 @@ nv50_ram_calc(struct nvkm_fb *fb, u32 freq) } static int -nv50_ram_prog(struct nvkm_fb *fb) +nv50_ram_prog(struct nvkm_ram *base) { - struct nvkm_device *device = nv_device(fb); - struct nv50_ram *ram = (void *)fb->ram; - struct nv50_ramseq *hwsq = &ram->hwsq; - - ram_exec(hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); + struct nv50_ram *ram = nv50_ram(base); + struct nvkm_device *device = ram->base.fb->subdev.device; + ram_exec(&ram->hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true)); return 0; } static void -nv50_ram_tidy(struct nvkm_fb *fb) +nv50_ram_tidy(struct nvkm_ram *base) { - struct nv50_ram *ram = (void *)fb->ram; - struct nv50_ramseq *hwsq = &ram->hwsq; - ram_exec(hwsq, false); + struct nv50_ram *ram = nv50_ram(base); + ram_exec(&ram->hwsq, false); } void -__nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem *mem) +__nv50_ram_put(struct nvkm_ram *ram, struct nvkm_mem *mem) { struct nvkm_mm_node *this; @@ -409,14 +408,14 @@ __nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem *mem) this = list_first_entry(&mem->regions, typeof(*this), rl_entry); list_del(&this->rl_entry); - nvkm_mm_free(&fb->vram, &this); + nvkm_mm_free(&ram->vram, &this); } - nvkm_mm_free(&fb->tags, &mem->tag); + nvkm_mm_free(&ram->tags, &mem->tag); } void -nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem **pmem) +nv50_ram_put(struct nvkm_ram *ram, struct nvkm_mem **pmem) { struct nvkm_mem *mem = *pmem; @@ -424,19 +423,19 @@ nv50_ram_put(struct nvkm_fb *fb, struct nvkm_mem **pmem) if (unlikely(mem == NULL)) return; - mutex_lock(&fb->subdev.mutex); - __nv50_ram_put(fb, mem); - mutex_unlock(&fb->subdev.mutex); + mutex_lock(&ram->fb->subdev.mutex); + __nv50_ram_put(ram, mem); + mutex_unlock(&ram->fb->subdev.mutex); kfree(mem); } int -nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, +nv50_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin, u32 memtype, struct nvkm_mem **pmem) { - struct nvkm_mm *heap = &fb->vram; - struct nvkm_mm *tags = &fb->tags; + struct nvkm_mm *heap = &ram->vram; + struct nvkm_mm *tags = &ram->tags; struct nvkm_mm_node *r; struct nvkm_mem *mem; int comp = (memtype & 0x300) >> 8; @@ -444,17 +443,17 @@ nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, int back = (memtype & 0x800); int min, max, ret; - max = (size >> 12); - min = ncmin ? (ncmin >> 12) : max; - align >>= 12; + max = (size >> NVKM_RAM_MM_SHIFT); + min = ncmin ? (ncmin >> NVKM_RAM_MM_SHIFT) : max; + align >>= NVKM_RAM_MM_SHIFT; mem = kzalloc(sizeof(*mem), GFP_KERNEL); if (!mem) return -ENOMEM; - mutex_lock(&fb->subdev.mutex); + mutex_lock(&ram->fb->subdev.mutex); if (comp) { - if (align == 16) { + if (align == (1 << (16 - NVKM_RAM_MM_SHIFT))) { int n = (max >> 4) * comp; ret = nvkm_mm_head(tags, 0, 1, n, n, 1, &mem->tag); @@ -477,26 +476,35 @@ nv50_ram_get(struct nvkm_fb *fb, u64 size, u32 align, u32 ncmin, else ret = nvkm_mm_head(heap, 0, type, max, min, align, &r); if (ret) { - mutex_unlock(&fb->subdev.mutex); - fb->ram->put(fb, &mem); + mutex_unlock(&ram->fb->subdev.mutex); + ram->func->put(ram, &mem); return ret; } list_add_tail(&r->rl_entry, &mem->regions); max -= r->length; } while (max); - mutex_unlock(&fb->subdev.mutex); + mutex_unlock(&ram->fb->subdev.mutex); r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry); - mem->offset = (u64)r->offset << 12; + mem->offset = (u64)r->offset << NVKM_RAM_MM_SHIFT; *pmem = mem; return 0; } +static const struct nvkm_ram_func +nv50_ram_func = { + .get = nv50_ram_get, + .put = nv50_ram_put, + .calc = nv50_ram_calc, + .prog = nv50_ram_prog, + .tidy = nv50_ram_tidy, +}; + static u32 -nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) +nv50_fb_vram_rblock(struct nvkm_ram *ram) { - struct nvkm_subdev *subdev = &fb->subdev; + struct nvkm_subdev *subdev = &ram->fb->subdev; struct nvkm_device *device = subdev->device; int colbits, rowbitsa, rowbitsb, banks; u64 rowsize, predicted; @@ -532,83 +540,63 @@ nv50_fb_vram_rblock(struct nvkm_fb *fb, struct nvkm_ram *ram) } int -nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nv50_ram_ctor(const struct nvkm_ram_func *func, + struct nvkm_fb *fb, struct nvkm_ram *ram) { - const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */ - const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */ - struct nvkm_fb *fb = nvkm_fb(parent); struct nvkm_device *device = fb->subdev.device; struct nvkm_bios *bios = device->bios; - struct nvkm_ram *ram; + const u32 rsvd_head = ( 256 * 1024); /* vga memory */ + const u32 rsvd_tail = (1024 * 1024); /* vbios etc */ + u64 size = nvkm_rd32(device, 0x10020c); + u32 tags = nvkm_rd32(device, 0x100320); + enum nvkm_ram_type type = NVKM_RAM_TYPE_UNKNOWN; int ret; - ret = nvkm_ram_create_(parent, engine, oclass, length, pobject); - ram = *pobject; - if (ret) - return ret; - - ram->size = nvkm_rd32(device, 0x10020c); - ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32); - - ram->part_mask = (nvkm_rd32(device, 0x001540) & 0x00ff0000) >> 16; - ram->parts = hweight8(ram->part_mask); - switch (nvkm_rd32(device, 0x100714) & 0x00000007) { - case 0: ram->type = NV_MEM_TYPE_DDR1; break; + case 0: type = NVKM_RAM_TYPE_DDR1; break; case 1: - if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3) - ram->type = NV_MEM_TYPE_DDR3; + if (nvkm_fb_bios_memtype(bios) == NVKM_RAM_TYPE_DDR3) + type = NVKM_RAM_TYPE_DDR3; else - ram->type = NV_MEM_TYPE_DDR2; + type = NVKM_RAM_TYPE_DDR2; break; - case 2: ram->type = NV_MEM_TYPE_GDDR3; break; - case 3: ram->type = NV_MEM_TYPE_GDDR4; break; - case 4: ram->type = NV_MEM_TYPE_GDDR5; break; + case 2: type = NVKM_RAM_TYPE_GDDR3; break; + case 3: type = NVKM_RAM_TYPE_GDDR4; break; + case 4: type = NVKM_RAM_TYPE_GDDR5; break; default: break; } - ret = nvkm_mm_init(&fb->vram, rsvd_head, (ram->size >> 12) - - (rsvd_head + rsvd_tail), - nv50_fb_vram_rblock(fb, ram) >> 12); + size = (size & 0x000000ff) << 32 | (size & 0xffffff00); + + ret = nvkm_ram_ctor(func, fb, type, size, tags, ram); if (ret) return ret; + ram->part_mask = (nvkm_rd32(device, 0x001540) & 0x00ff0000) >> 16; + ram->parts = hweight8(ram->part_mask); ram->ranks = (nvkm_rd32(device, 0x100200) & 0x4) ? 2 : 1; - ram->tags = nvkm_rd32(device, 0x100320); - ram->get = nv50_ram_get; - ram->put = nv50_ram_put; - return 0; + nvkm_mm_fini(&ram->vram); + + return nvkm_mm_init(&ram->vram, rsvd_head >> NVKM_RAM_MM_SHIFT, + (size - rsvd_head - rsvd_tail) >> NVKM_RAM_MM_SHIFT, + nv50_fb_vram_rblock(ram) >> NVKM_RAM_MM_SHIFT); } -static int -nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 datasize, - struct nvkm_object **pobject) +int +nv50_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) { - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_subdev *subdev = &fb->subdev; struct nv50_ram *ram; int ret, i; - ret = nv50_ram_create(parent, engine, oclass, &ram); - *pobject = nv_object(ram); + if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) + return -ENOMEM; + *pram = &ram->base; + + ret = nv50_ram_ctor(&nv50_ram_func, fb, &ram->base); if (ret) return ret; - switch (ram->base.type) { - case NV_MEM_TYPE_GDDR3: - ram->base.calc = nv50_ram_calc; - ram->base.prog = nv50_ram_prog; - ram->base.tidy = nv50_ram_tidy; - break; - case NV_MEM_TYPE_DDR2: - default: - nvkm_warn(subdev, "reclocking of this ram type unsupported\n"); - return 0; - } - ram->hwsq.r_0x002504 = hwsq_reg(0x002504); ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040); ram->hwsq.r_0x004008 = hwsq_reg(0x004008); @@ -648,13 +636,3 @@ nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } - -struct nvkm_oclass -nv50_ram_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_ram_ctor, - .dtor = _nvkm_ram_dtor, - .init = _nvkm_ram_init, - .fini = _nvkm_ram_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 339dd19e0e451..4f6354df538a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -84,8 +84,8 @@ static void nv50_instobj_dtor(struct nvkm_object *object) { struct nv50_instobj *node = (void *)object; - struct nvkm_fb *fb = nvkm_fb(object); - fb->ram->put(fb, &node->mem); + struct nvkm_ram *ram = nvkm_fb(object)->ram; + ram->func->put(ram, &node->mem); nvkm_instobj_destroy(&node->base); } @@ -94,7 +94,7 @@ nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fb *fb = nvkm_fb(parent); + struct nvkm_ram *ram = nvkm_fb(parent)->ram; struct nvkm_instobj_args *args = data; struct nv50_instobj *node; int ret; @@ -107,7 +107,8 @@ nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = fb->ram->get(fb, args->size, args->align, 0, 0x800, &node->mem); + ret = ram->func->get(ram, args->size, args->align, 0, 0x800, + &node->mem); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index 22712cdc01b32..5cb7604beeb60 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -145,12 +145,12 @@ gf100_ltc_init(struct nvkm_object *object) void gf100_ltc_dtor(struct nvkm_object *object) { - struct nvkm_fb *fb = nvkm_fb(object); struct nvkm_ltc_priv *ltc = (void *)object; + struct nvkm_ram *ram = ltc->base.subdev.device->fb->ram; nvkm_mm_fini(<c->tags); - if (fb->ram) - nvkm_mm_free(&fb->vram, <c->tag_ram); + if (ram) + nvkm_mm_free(&ram->vram, <c->tag_ram); nvkm_ltc_destroy(ltc); } @@ -158,19 +158,20 @@ gf100_ltc_dtor(struct nvkm_object *object) /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ int -gf100_ltc_init_tag_ram(struct nvkm_fb *fb, struct nvkm_ltc_priv *ltc) +gf100_ltc_init_tag_ram(struct nvkm_ltc_priv *ltc) { + struct nvkm_ram *ram = ltc->base.subdev.device->fb->ram; u32 tag_size, tag_margin, tag_align; int ret; /* No VRAM, no tags for now. */ - if (!fb->ram) { + if (!ram) { ltc->num_tags = 0; goto mm_init; } /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */ - ltc->num_tags = (fb->ram->size >> 17) / 4; + ltc->num_tags = (ram->size >> 17) / 4; if (ltc->num_tags > (1 << 17)) ltc->num_tags = 1 << 17; /* we have 17 bits in PTE */ ltc->num_tags = (ltc->num_tags + 63) & ~63; /* round up to 64 */ @@ -190,7 +191,7 @@ gf100_ltc_init_tag_ram(struct nvkm_fb *fb, struct nvkm_ltc_priv *ltc) tag_size += tag_align; tag_size = (tag_size + 0xfff) >> 12; /* round up */ - ret = nvkm_mm_tail(&fb->vram, 1, 1, tag_size, tag_size, 1, + ret = nvkm_mm_tail(&ram->vram, 1, 1, tag_size, tag_size, 1, <c->tag_ram); if (ret) { ltc->num_tags = 0; @@ -214,7 +215,6 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = (void *)parent; - struct nvkm_fb *fb = device->fb; struct nvkm_ltc_priv *ltc; u32 parts, mask; int ret, i; @@ -232,7 +232,7 @@ gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } ltc->lts_nr = nvkm_rd32(device, 0x17e8dc) >> 28; - ret = gf100_ltc_init_tag_ram(fb, ltc); + ret = gf100_ltc_init_tag_ram(ltc); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 222f37e50a951..431acbef6bb7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -124,7 +124,6 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = (void *)parent; - struct nvkm_fb *fb = device->fb; struct nvkm_ltc_priv *ltc; u32 parts, mask; int ret, i; @@ -142,7 +141,7 @@ gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } ltc->lts_nr = nvkm_rd32(device, 0x17e280) >> 28; - ret = gf100_ltc_init_tag_ram(fb, ltc); + ret = gf100_ltc_init_tag_ram(ltc); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h index 09537d7b67837..0544288b0d1d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h @@ -45,7 +45,7 @@ int gf100_ltc_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); void gf100_ltc_dtor(struct nvkm_object *); -int gf100_ltc_init_tag_ram(struct nvkm_fb *, struct nvkm_ltc_priv *); +int gf100_ltc_init_tag_ram(struct nvkm_ltc_priv *); int gf100_ltc_tags_alloc(struct nvkm_ltc *, u32, struct nvkm_mm_node **); void gf100_ltc_tags_free(struct nvkm_ltc *, struct nvkm_mm_node **); -- GitLab From 2aa5eac5163fedf09f2d61992cb5ea4d75bec9db Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5459/7006] drm/nouveau/i2c: transition pad/ports away from being based on nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/dfp.c | 11 +- drivers/gpu/drm/nouveau/dispnv04/disp.c | 4 +- drivers/gpu/drm/nouveau/dispnv04/tvnv04.c | 16 +- .../gpu/drm/nouveau/include/nvkm/subdev/i2c.h | 125 ++-- drivers/gpu/drm/nouveau/nouveau_bios.c | 1 - drivers/gpu/drm/nouveau/nouveau_connector.c | 26 +- drivers/gpu/drm/nouveau/nouveau_dp.c | 17 +- drivers/gpu/drm/nouveau/nouveau_encoder.h | 4 +- drivers/gpu/drm/nouveau/nv50_display.c | 32 +- .../gpu/drm/nouveau/nvkm/engine/disp/dport.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.c | 54 +- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 2 + .../drm/nouveau/nvkm/engine/disp/piornv50.c | 20 +- .../gpu/drm/nouveau/nvkm/subdev/bios/i2c.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 76 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild | 28 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c | 376 +++++----- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c | 151 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h | 30 + .../gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c | 181 +++++ .../drm/nouveau/nvkm/subdev/i2c/auxgm204.c | 181 +++++ .../gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 669 ++++++------------ drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c | 149 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c | 245 +++++++ drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h | 37 + .../drm/nouveau/nvkm/subdev/i2c/busgf119.c | 95 +++ .../gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c | 96 +++ .../gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c | 86 +++ .../gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c | 113 +++ drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c | 221 +----- .../gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c | 75 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c | 7 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c | 191 +---- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c | 91 +-- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c | 87 +-- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c | 107 +-- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h | 28 - drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c | 119 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h | 109 +-- .../gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c | 89 +-- .../drm/nouveau/nvkm/subdev/i2c/padgf119.c | 51 ++ .../drm/nouveau/nvkm/subdev/i2c/padgm204.c | 89 +-- .../gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c | 18 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c | 36 + .../gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c | 36 + .../gpu/drm/nouveau/nvkm/subdev/i2c/port.h | 14 - .../gpu/drm/nouveau/nvkm/subdev/i2c/priv.h | 37 +- .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 16 +- .../gpu/drm/nouveau/nvkm/subdev/therm/ic.c | 32 +- 52 files changed, 2293 insertions(+), 2021 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 61b49c1d5303f..a85e7251e0cbe 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -624,8 +624,8 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) struct dcb_output *dcb = nouveau_encoder(encoder)->dcb; struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->device); - struct nvkm_i2c_port *port = i2c->find(i2c, 2); - struct nvkm_i2c_board_info info[] = { + struct nvkm_i2c_bus *bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI); + struct nvkm_i2c_bus_probe info[] = { { { .type = "sil164", @@ -639,16 +639,15 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder) }; int type; - if (!nv_gf4_disp_arch(dev) || !port || - get_tmds_slave(encoder)) + if (!nv_gf4_disp_arch(dev) || !bus || get_tmds_slave(encoder)) return; - type = i2c->identify(i2c, 2, "TMDS transmitter", info, NULL, NULL); + type = nvkm_i2c_bus_probe(bus, "TMDS transmitter", info, NULL, NULL); if (type < 0) return; drm_i2c_encoder_init(dev, to_encoder_slave(encoder), - &port->adapter, &info[type].dev); + &bus->i2c, &info[type].dev); } static const struct drm_encoder_helper_funcs nv04_lvds_helper_funcs = { diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 4131be5507ab7..018a4480cfc57 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -101,7 +101,9 @@ nv04_display_create(struct drm_device *dev) list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) { struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder); - nv_encoder->i2c = i2c->find(i2c, nv_encoder->dcb->i2c_index); + struct nvkm_i2c_bus *bus = + nvkm_i2c_bus_find(i2c, nv_encoder->dcb->i2c_index); + nv_encoder->i2c = bus ? &bus->i2c : NULL; } /* Save previous state */ diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c index 70e95cf6fd190..5345eb5378a8b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c @@ -35,7 +35,7 @@ #include -static struct nvkm_i2c_board_info nv04_tv_encoder_info[] = { +static struct nvkm_i2c_bus_probe nv04_tv_encoder_info[] = { { { I2C_BOARD_INFO("ch7006", 0x75), @@ -55,9 +55,13 @@ int nv04_tv_identify(struct drm_device *dev, int i2c_index) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->device); - - return i2c->identify(i2c, i2c_index, "TV encoder", - nv04_tv_encoder_info, NULL, NULL); + struct nvkm_i2c_bus *bus = nvkm_i2c_bus_find(i2c, i2c_index); + if (bus) { + return nvkm_i2c_bus_probe(bus, "TV encoder", + nv04_tv_encoder_info, + NULL, NULL); + } + return -ENODEV; } @@ -205,7 +209,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) struct drm_device *dev = connector->dev; struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->device); - struct nvkm_i2c_port *port = i2c->find(i2c, entry->i2c_index); + struct nvkm_i2c_bus *bus = nvkm_i2c_bus_find(i2c, entry->i2c_index); int type, ret; /* Ensure that we can talk to this encoder */ @@ -231,7 +235,7 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry) /* Run the slave-specific initialization */ ret = drm_i2c_encoder_init(dev, to_encoder_slave(encoder), - &port->adapter, + &bus->i2c, &nv04_tv_encoder_info[type].dev); if (ret < 0) goto fail_cleanup; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h index 6b71cb6d59522..ddc7e6e4be60a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h @@ -6,15 +6,6 @@ #include #include -#define NV_I2C_PORT(n) (0x00 + (n)) -#define NV_I2C_AUX(n) (0x10 + (n)) -#define NV_I2C_EXT(n) (0x20 + (n)) -#define NV_I2C_DEFAULT(n) (0x80 + (n)) - -#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n)) -#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8) -#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8) - struct nvkm_i2c_ntfy_req { #define NVKM_I2C_PLUG 0x01 #define NVKM_I2C_UNPLUG 0x02 @@ -29,55 +20,66 @@ struct nvkm_i2c_ntfy_rep { u8 mask; }; -struct nvkm_i2c_port { - struct nvkm_object base; - struct i2c_adapter adapter; - struct mutex mutex; +struct nvkm_i2c_bus_probe { + struct i2c_board_info dev; + u8 udelay; /* set to 0 to use the standard delay */ +}; - struct list_head head; - u8 index; - int aux; +struct nvkm_i2c_bus { + const struct nvkm_i2c_bus_func *func; + struct nvkm_i2c_pad *pad; +#define NVKM_I2C_BUS_CCB(n) /* 'n' is ccb index */ (n) +#define NVKM_I2C_BUS_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x100) +#define NVKM_I2C_BUS_PRI /* ccb primary comm. port */ -1 +#define NVKM_I2C_BUS_SEC /* ccb secondary comm. port */ -2 + int id; - const struct nvkm_i2c_func *func; + struct mutex mutex; + struct list_head head; + struct i2c_adapter i2c; }; -struct nvkm_i2c_func { - void (*drive_scl)(struct nvkm_i2c_port *, int); - void (*drive_sda)(struct nvkm_i2c_port *, int); - int (*sense_scl)(struct nvkm_i2c_port *); - int (*sense_sda)(struct nvkm_i2c_port *); +int nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *); +void nvkm_i2c_bus_release(struct nvkm_i2c_bus *); +int nvkm_i2c_bus_probe(struct nvkm_i2c_bus *, const char *, + struct nvkm_i2c_bus_probe *, + bool (*)(struct nvkm_i2c_bus *, + struct i2c_board_info *, void *), void *); - int (*aux)(struct nvkm_i2c_port *, bool, u8, u32, u8 *, u8); - int (*pattern)(struct nvkm_i2c_port *, int pattern); - int (*lnk_ctl)(struct nvkm_i2c_port *, int nr, int bw, bool enh); - int (*drv_ctl)(struct nvkm_i2c_port *, int lane, int sw, int pe); -}; +struct nvkm_i2c_aux { + const struct nvkm_i2c_aux_func *func; + struct nvkm_i2c_pad *pad; +#define NVKM_I2C_AUX_CCB(n) /* 'n' is ccb index */ (n) +#define NVKM_I2C_AUX_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x100) + int id; -struct nvkm_i2c_board_info { - struct i2c_board_info dev; - u8 udelay; /* set to 0 to use the standard delay */ + struct mutex mutex; + struct list_head head; + struct i2c_adapter i2c; + + u32 intr; }; +void nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *, bool monitor); +int nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *); +void nvkm_i2c_aux_release(struct nvkm_i2c_aux *); +int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 size); +int nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *, int link_nr, int link_bw, + bool enhanced_framing); + struct nvkm_i2c { struct nvkm_subdev subdev; struct nvkm_event event; - struct nvkm_i2c_port *(*find)(struct nvkm_i2c *, u8 index); - struct nvkm_i2c_port *(*find_type)(struct nvkm_i2c *, u16 type); - int (*acquire_pad)(struct nvkm_i2c_port *, unsigned long timeout); - void (*release_pad)(struct nvkm_i2c_port *); - int (*acquire)(struct nvkm_i2c_port *, unsigned long timeout); - void (*release)(struct nvkm_i2c_port *); - int (*identify)(struct nvkm_i2c *, int index, - const char *what, struct nvkm_i2c_board_info *, - bool (*match)(struct nvkm_i2c_port *, - struct i2c_board_info *, void *), - void *); - - wait_queue_head_t wait; - struct list_head ports; + struct list_head pad; + struct list_head bus; + struct list_head aux; }; +struct nvkm_i2c_bus *nvkm_i2c_bus_find(struct nvkm_i2c *, int); +struct nvkm_i2c_aux *nvkm_i2c_aux_find(struct nvkm_i2c *, int); + static inline struct nvkm_i2c * nvkm_i2c(void *obj) { @@ -94,7 +96,7 @@ extern struct nvkm_oclass *gk104_i2c_oclass; extern struct nvkm_oclass *gm204_i2c_oclass; static inline int -nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg) +nvkm_rdi2cr(struct i2c_adapter *adap, u8 addr, u8 reg) { u8 val; struct i2c_msg msgs[] = { @@ -102,7 +104,7 @@ nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg) { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val }, }; - int ret = i2c_transfer(&port->adapter, msgs, 2); + int ret = i2c_transfer(adap, msgs, ARRAY_SIZE(msgs)); if (ret != 2) return -EIO; @@ -110,14 +112,14 @@ nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg) } static inline int -nv_wri2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg, u8 val) +nvkm_wri2cr(struct i2c_adapter *adap, u8 addr, u8 reg, u8 val) { u8 buf[2] = { reg, val }; struct i2c_msg msgs[] = { { .addr = addr, .flags = 0, .len = 2, .buf = buf }, }; - int ret = i2c_transfer(&port->adapter, msgs, 1); + int ret = i2c_transfer(adap, msgs, ARRAY_SIZE(msgs)); if (ret != 1) return -EIO; @@ -125,11 +127,30 @@ nv_wri2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg, u8 val) } static inline bool -nv_probe_i2c(struct nvkm_i2c_port *port, u8 addr) +nvkm_probe_i2c(struct i2c_adapter *adap, u8 addr) +{ + return nvkm_rdi2cr(adap, addr, 0) >= 0; +} + +static inline int +nvkm_rdaux(struct nvkm_i2c_aux *aux, u32 addr, u8 *data, u8 size) { - return nv_rdi2cr(port, addr, 0) >= 0; + int ret = nvkm_i2c_aux_acquire(aux); + if (ret == 0) { + ret = nvkm_i2c_aux_xfer(aux, true, 9, addr, data, size); + nvkm_i2c_aux_release(aux); + } + return ret; } -int nv_rdaux(struct nvkm_i2c_port *, u32 addr, u8 *data, u8 size); -int nv_wraux(struct nvkm_i2c_port *, u32 addr, u8 *data, u8 size); +static inline int +nvkm_wraux(struct nvkm_i2c_aux *aux, u32 addr, u8 *data, u8 size) +{ + int ret = nvkm_i2c_aux_acquire(aux); + if (ret == 0) { + ret = nvkm_i2c_aux_xfer(aux, true, 8, addr, data, size); + nvkm_i2c_aux_release(aux); + } + return ret; +} #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index c6dbfaf49a11b..3199479ac5b3a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -1495,7 +1495,6 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb, break; } link = entry->dpconf.sor.link; - entry->i2c_index += NV_I2C_AUX(0); break; case DCB_OUTPUT_TMDS: if (dcb->version >= 0x40) { diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 1f26eba245d10..054f0f25c8bee 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -148,7 +148,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) break; } else if (nv_encoder->i2c) { - if (nv_probe_i2c(nv_encoder->i2c, 0x50)) + if (nvkm_probe_i2c(nv_encoder->i2c, 0x50)) break; } } @@ -241,7 +241,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) struct nouveau_connector *nv_connector = nouveau_connector(connector); struct nouveau_encoder *nv_encoder = NULL; struct nouveau_encoder *nv_partner; - struct nvkm_i2c_port *i2c; + struct i2c_adapter *i2c; int type; int ret; enum drm_connector_status conn_status = connector_status_disconnected; @@ -259,7 +259,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force) nv_encoder = nouveau_connector_ddc_detect(connector); if (nv_encoder && (i2c = nv_encoder->i2c) != NULL) { - nv_connector->edid = drm_get_edid(connector, &i2c->adapter); + nv_connector->edid = drm_get_edid(connector, i2c); drm_mode_connector_update_edid_property(connector, nv_connector->edid); if (!nv_connector->edid) { @@ -930,11 +930,11 @@ nouveau_connector_dp_dpms(struct drm_connector *connector, int mode) nv_encoder->dcb->type == DCB_OUTPUT_DP) { if (mode == DRM_MODE_DPMS_ON) { u8 data = DP_SET_POWER_D0; - nv_wraux(nv_encoder->i2c, DP_SET_POWER, &data, 1); + nvkm_wraux(nv_encoder->aux, DP_SET_POWER, &data, 1); usleep_range(1000, 2000); } else { u8 data = DP_SET_POWER_D3; - nv_wraux(nv_encoder->i2c, DP_SET_POWER, &data, 1); + nvkm_wraux(nv_encoder->aux, DP_SET_POWER, &data, 1); } } @@ -980,29 +980,29 @@ nouveau_connector_hotplug(struct nvif_notify *notify) } static ssize_t -nouveau_connector_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) +nouveau_connector_aux_xfer(struct drm_dp_aux *obj, struct drm_dp_aux_msg *msg) { struct nouveau_connector *nv_connector = - container_of(aux, typeof(*nv_connector), aux); + container_of(obj, typeof(*nv_connector), aux); struct nouveau_encoder *nv_encoder; - struct nvkm_i2c_port *port; + struct nvkm_i2c_aux *aux; int ret; nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP); - if (!nv_encoder || !(port = nv_encoder->i2c)) + if (!nv_encoder || !(aux = nv_encoder->aux)) return -ENODEV; if (WARN_ON(msg->size > 16)) return -E2BIG; if (msg->size == 0) return msg->size; - ret = nvkm_i2c(port)->acquire(port, 0); + ret = nvkm_i2c_aux_acquire(aux); if (ret) return ret; - ret = port->func->aux(port, false, msg->request, msg->address, - msg->buffer, msg->size); - nvkm_i2c(port)->release(port); + ret = nvkm_i2c_aux_xfer(aux, false, msg->request, msg->address, + msg->buffer, msg->size); + nvkm_i2c_aux_release(aux); if (ret >= 0) { msg->reply = ret; return msg->size; diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c index c3ef30b3a5ec5..e17e15ec7d431 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dp.c +++ b/drivers/gpu/drm/nouveau/nouveau_dp.c @@ -31,8 +31,7 @@ #include "nouveau_crtc.h" static void -nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch, - u8 *dpcd) +nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_aux *aux, u8 *dpcd) { struct nouveau_drm *drm = nouveau_drm(dev); u8 buf[3]; @@ -40,11 +39,11 @@ nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch, if (!(dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT)) return; - if (!nv_rdaux(auxch, DP_SINK_OUI, buf, 3)) + if (!nvkm_rdaux(aux, DP_SINK_OUI, buf, 3)) NV_DEBUG(drm, "Sink OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); - if (!nv_rdaux(auxch, DP_BRANCH_OUI, buf, 3)) + if (!nvkm_rdaux(aux, DP_BRANCH_OUI, buf, 3)) NV_DEBUG(drm, "Branch OUI: %02hx%02hx%02hx\n", buf[0], buf[1], buf[2]); @@ -55,15 +54,15 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder) { struct drm_device *dev = nv_encoder->base.base.dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nvkm_i2c_port *auxch; + struct nvkm_i2c_aux *aux; u8 *dpcd = nv_encoder->dp.dpcd; int ret; - auxch = nv_encoder->i2c; - if (!auxch) + aux = nv_encoder->aux; + if (!aux) return -ENODEV; - ret = nv_rdaux(auxch, DP_DPCD_REV, dpcd, 8); + ret = nvkm_rdaux(aux, DP_DPCD_REV, dpcd, 8); if (ret) return ret; @@ -84,6 +83,6 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder) NV_DEBUG(drm, "maximum: %dx%d\n", nv_encoder->dp.link_nr, nv_encoder->dp.link_bw); - nouveau_dp_probe_oui(dev, auxch, dpcd); + nouveau_dp_probe_oui(dev, aux, dpcd); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h index c57a37e8e1eb9..b37da95105b0f 100644 --- a/drivers/gpu/drm/nouveau/nouveau_encoder.h +++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h @@ -41,7 +41,9 @@ struct nouveau_encoder { struct dcb_output *dcb; int or; - struct nvkm_i2c_port *i2c; + + struct i2c_adapter *i2c; + struct nvkm_i2c_aux *aux; /* different to drm_encoder.crtc, this reflects what's * actually programmed on the hw, not the proposed crtc */ diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index cb41437ce1b72..c56775f5aff39 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -1688,6 +1688,7 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) { struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->device); + struct nvkm_i2c_bus *bus; struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; int type = DRM_MODE_ENCODER_DAC; @@ -1697,7 +1698,10 @@ nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe) return -ENOMEM; nv_encoder->dcb = dcbe; nv_encoder->or = ffs(dcbe->or) - 1; - nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index); + + bus = nvkm_i2c_bus_find(i2c, dcbe->i2c_index); + if (bus) + nv_encoder->i2c = &bus->i2c; encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; @@ -2091,9 +2095,22 @@ nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe) return -ENOMEM; nv_encoder->dcb = dcbe; nv_encoder->or = ffs(dcbe->or) - 1; - nv_encoder->i2c = i2c->find(i2c, dcbe->i2c_index); nv_encoder->last_dpms = DRM_MODE_DPMS_OFF; + if (dcbe->type == DCB_OUTPUT_DP) { + struct nvkm_i2c_aux *aux = + nvkm_i2c_aux_find(i2c, dcbe->i2c_index); + if (aux) { + nv_encoder->i2c = &aux->i2c; + nv_encoder->aux = aux; + } + } else { + struct nvkm_i2c_bus *bus = + nvkm_i2c_bus_find(i2c, dcbe->i2c_index); + if (bus) + nv_encoder->i2c = &bus->i2c; + } + encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; encoder->possible_clones = 0; @@ -2244,18 +2261,22 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) { struct nouveau_drm *drm = nouveau_drm(connector->dev); struct nvkm_i2c *i2c = nvxx_i2c(&drm->device); - struct nvkm_i2c_port *ddc = NULL; + struct nvkm_i2c_bus *bus = NULL; + struct nvkm_i2c_aux *aux = NULL; + struct i2c_adapter *ddc; struct nouveau_encoder *nv_encoder; struct drm_encoder *encoder; int type; switch (dcbe->type) { case DCB_OUTPUT_TMDS: - ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(dcbe->extdev)); + bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_EXT(dcbe->extdev)); + ddc = bus ? &bus->i2c : NULL; type = DRM_MODE_ENCODER_TMDS; break; case DCB_OUTPUT_DP: - ddc = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(dcbe->extdev)); + aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbe->extdev)); + ddc = aux ? &aux->i2c : NULL; type = DRM_MODE_ENCODER_TMDS; break; default: @@ -2268,6 +2289,7 @@ nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe) nv_encoder->dcb = dcbe; nv_encoder->or = ffs(dcbe->or) - 1; nv_encoder->i2c = ddc; + nv_encoder->aux = aux; encoder = to_drm_encoder(nv_encoder); encoder->possible_crtcs = dcbe->heads; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index 5df7eeb56ab3f..d671da6d6ac14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -98,7 +98,7 @@ dp_set_link_config(struct dp_state *dp) if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP) sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN; - return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2); + return nvkm_wraux(outp->aux, DPCD_LC00_LINK_BW_SET, sink, 2); } static void @@ -111,10 +111,10 @@ dp_set_training_pattern(struct dp_state *dp, u8 pattern) DBG("training pattern %d\n", pattern); impl->pattern(outp, pattern); - nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1); + nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; sink_tp |= pattern; - nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1); + nvkm_wraux(outp->aux, DPCD_LC02, &sink_tp, 1); } static int @@ -150,12 +150,12 @@ dp_link_train_commit(struct dp_state *dp, bool pc) impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); } - ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4); + ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4); if (ret) return ret; if (pc) { - ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2); + ret = nvkm_wraux(outp->aux, DPCD_LC0F, dp->pc2conf, 2); if (ret) return ret; } @@ -174,12 +174,12 @@ dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) else udelay(delay); - ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6); + ret = nvkm_rdaux(outp->aux, DPCD_LS02, dp->stat, 6); if (ret) return ret; if (pc) { - ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1); + ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1); if (ret) dp->pc2stat = 0x00; DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 9224bcbf01592..88a990ec70251 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -86,11 +86,7 @@ nvkm_output_create_(struct nvkm_object *parent, dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, dcbE->bus, dcbE->heads); - if (outp->info.type != DCB_OUTPUT_DP) - outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index)); - else - outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index)); - outp->edid = outp->port; + outp->i2c = nvkm_i2c_bus_find(i2c, outp->info.i2c_index); data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); if (!data) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 6b85408541b6d..fb2ce7ca934dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -13,8 +13,8 @@ struct nvkm_output { int index; int or; - struct nvkm_i2c_port *port; - struct nvkm_i2c_port *edid; + // whatever (if anything) is pointed at by the dcb device entry + struct nvkm_i2c_bus *i2c; struct nvkm_connector *conn; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c index 0bde0fa5b59d1..dac6f17bd1b63 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c @@ -40,7 +40,7 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) int ret, i; /* check that the link is trained at a high enough rate */ - ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2); + ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { DBG("failed to read link config, assuming no sink\n"); goto done; @@ -55,7 +55,7 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) } /* check that link is still trained */ - ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3); + ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); if (ret) { DBG("failed to read link status, assuming no sink\n"); goto done; @@ -102,37 +102,31 @@ done: } static void -nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present) +nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) { - struct nvkm_i2c_port *port = outp->base.edid; - if (present) { + struct nvkm_i2c_aux *aux = outp->aux; + + if (enable) { if (!outp->present) { - nvkm_i2c(port)->acquire_pad(port, 0); DBG("aux power -> always\n"); + nvkm_i2c_aux_monitor(aux, true); outp->present = true; } - nvkm_output_dp_train(&outp->base, 0, true); - } else { - if (outp->present) { - nvkm_i2c(port)->release_pad(port); - DBG("aux power -> demand\n"); - outp->present = false; + + if (!nvkm_rdaux(aux, DPCD_RC00_DPCD_REV, outp->dpcd, + sizeof(outp->dpcd))) { + nvkm_output_dp_train(&outp->base, 0, true); + return; } - atomic_set(&outp->lt.done, 0); } -} -static void -nvkm_output_dp_detect(struct nvkm_output_dp *outp) -{ - struct nvkm_i2c_port *port = outp->base.edid; - int ret = nvkm_i2c(port)->acquire_pad(port, 0); - if (ret == 0) { - ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV, - outp->dpcd, sizeof(outp->dpcd)); - nvkm_output_dp_enable(outp, ret == 0); - nvkm_i2c(port)->release_pad(port); + if (outp->present) { + DBG("aux power -> demand\n"); + nvkm_i2c_aux_monitor(aux, false); + outp->present = false; } + + atomic_set(&outp->lt.done, 0); } static int @@ -148,7 +142,7 @@ nvkm_output_dp_hpd(struct nvkm_notify *notify) if (outp->base.conn == conn && outp->info.type == DCB_OUTPUT_DP) { DBG("HPD: %d\n", line->mask); - nvkm_output_dp_detect(outp); + nvkm_output_dp_enable(outp, true); if (line->mask & NVKM_I2C_UNPLUG) rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; @@ -196,7 +190,7 @@ int _nvkm_output_dp_init(struct nvkm_object *object) { struct nvkm_output_dp *outp = (void *)object; - nvkm_output_dp_detect(outp); + nvkm_output_dp_enable(outp, true); return nvkm_output_init(&outp->base); } @@ -231,7 +225,9 @@ nvkm_output_dp_create_(struct nvkm_object *parent, nvkm_notify_fini(&outp->base.conn->hpd); /* access to the aux channel is not optional... */ - if (!outp->base.edid) { + //XXX: breaks anx support + outp->aux = nvkm_i2c_aux_find(i2c, outp->base.info.i2c_index); + if (!outp->aux) { ERR("aux channel not found\n"); return -ENODEV; } @@ -256,7 +252,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent, ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true, &(struct nvkm_i2c_ntfy_req) { .mask = NVKM_I2C_IRQ, - .port = outp->base.edid->index, + .port = outp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), @@ -270,7 +266,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent, ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true, &(struct nvkm_i2c_ntfy_req) { .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG, - .port = outp->base.edid->index, + .port = outp->aux->id, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index 70c77aec48508..f90e84c5fa29e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -12,6 +12,8 @@ struct nvkm_output_dp { struct nvbios_dpout info; u8 version; + struct nvkm_i2c_aux *aux; + struct nvkm_notify irq; bool present; u8 dpcd[16]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index 406ba2f493b35..ac122d72fb72f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -41,7 +41,6 @@ nv50_pior_tmds_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *info, u32 index, struct nvkm_object **pobject) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); struct nvkm_output *outp; int ret; @@ -50,7 +49,6 @@ nv50_pior_tmds_ctor(struct nvkm_object *parent, if (ret) return ret; - outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev)); return 0; } @@ -72,10 +70,7 @@ nv50_pior_tmds_impl = { static int nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nvkm_i2c_port *port = outp->base.edid; - if (port && port->func->pattern) - return port->func->pattern(port, pattern); - return port ? 0 : -ENODEV; + return -ENODEV; } static int @@ -87,19 +82,13 @@ nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) static int nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nvkm_i2c_port *port = outp->base.edid; - if (port && port->func->lnk_ctl) - return port->func->lnk_ctl(port, nr, bw, ef); - return port ? 0 : -ENODEV; + return nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); } static int nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nvkm_i2c_port *port = outp->base.edid; - if (port && port->func->drv_ctl) - return port->func->drv_ctl(port, ln, vs, pe); - return port ? 0 : -ENODEV; + return -ENODEV; } static int @@ -117,8 +106,7 @@ nv50_pior_dp_ctor(struct nvkm_object *parent, if (ret) return ret; - outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX( - outp->base.info.extdev)); + outp->aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(outp->base.info.extdev)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c index 7380f01ba731f..0fc60be327278 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c @@ -76,8 +76,8 @@ dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info) if (ent) { if (ver >= 0x41) { u32 ent_value = nvbios_rd32(bios, ent); - u8 i2c_port = (ent_value >> 27) & 0x1f; - u8 dpaux_port = (ent_value >> 22) & 0x1f; + u8 i2c_port = (ent_value >> 0) & 0x1f; + u8 dpaux_port = (ent_value >> 5) & 0x1f; /* value 0x1f means unused according to DCB 4.x spec */ if (i2c_port == 0x1f && dpaux_port == 0x1f) info->type = DCB_I2C_UNUSED; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index 8b175d8cec660..c2c2d90e04f59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -259,62 +259,60 @@ init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value) } } -static struct nvkm_i2c_port * +static struct i2c_adapter * init_i2c(struct nvbios_init *init, int index) { - struct nvkm_i2c *i2c = nvkm_i2c(init->bios); + struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; + struct nvkm_i2c_bus *bus; if (index == 0xff) { - index = NV_I2C_DEFAULT(0); + index = NVKM_I2C_BUS_PRI; if (init->outp && init->outp->i2c_upper_default) - index = NV_I2C_DEFAULT(1); - } else - if (index < 0) { - if (!init->outp) { - if (init_exec(init)) - error("script needs output for i2c\n"); - return NULL; - } - - if (index == -2 && init->outp->location) { - index = NV_I2C_TYPE_EXTAUX(init->outp->extdev); - return i2c->find_type(i2c, index); - } - - index = init->outp->i2c_index; - if (init->outp->type == DCB_OUTPUT_DP) - index += NV_I2C_AUX(0); + index = NVKM_I2C_BUS_SEC; } - return i2c->find(i2c, index); + bus = nvkm_i2c_bus_find(i2c, index); + return bus ? &bus->i2c : NULL; } static int init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg) { - struct nvkm_i2c_port *port = init_i2c(init, index); - if (port && init_exec(init)) - return nv_rdi2cr(port, addr, reg); + struct i2c_adapter *adap = init_i2c(init, index); + if (adap && init_exec(init)) + return nvkm_rdi2cr(adap, addr, reg); return -ENODEV; } static int init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val) { - struct nvkm_i2c_port *port = init_i2c(init, index); - if (port && init_exec(init)) - return nv_wri2cr(port, addr, reg, val); + struct i2c_adapter *adap = init_i2c(init, index); + if (adap && init_exec(init)) + return nvkm_wri2cr(adap, addr, reg, val); return -ENODEV; } +static struct nvkm_i2c_aux * +init_aux(struct nvbios_init *init) +{ + struct nvkm_i2c *i2c = init->bios->subdev.device->i2c; + if (!init->outp) { + if (init_exec(init)) + error("script needs output for aux\n"); + return NULL; + } + return nvkm_i2c_aux_find(i2c, init->outp->i2c_index); +} + static u8 init_rdauxr(struct nvbios_init *init, u32 addr) { - struct nvkm_i2c_port *port = init_i2c(init, -2); + struct nvkm_i2c_aux *aux = init_aux(init); u8 data; - if (port && init_exec(init)) { - int ret = nv_rdaux(port, addr, &data, 1); + if (aux && init_exec(init)) { + int ret = nvkm_rdaux(aux, addr, &data, 1); if (ret == 0) return data; trace("auxch read failed with %d\n", ret); @@ -326,9 +324,9 @@ init_rdauxr(struct nvbios_init *init, u32 addr) static int init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) { - struct nvkm_i2c_port *port = init_i2c(init, -2); - if (port && init_exec(init)) { - int ret = nv_wraux(port, addr, &data, 1); + struct nvkm_i2c_aux *aux = init_aux(init); + if (aux && init_exec(init)) { + int ret = nvkm_wraux(aux, addr, &data, 1); if (ret) trace("auxch write failed with %d\n", ret); return ret; @@ -1065,13 +1063,13 @@ init_zm_i2c(struct nvbios_init *init) } if (init_exec(init)) { - struct nvkm_i2c_port *port = init_i2c(init, index); + struct i2c_adapter *adap = init_i2c(init, index); struct i2c_msg msg = { .addr = addr, .flags = 0, .len = count, .buf = data, }; int ret; - if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1) + if (adap && (ret = i2c_transfer(adap, &msg, 1)) != 1) warn("i2c wr failed, %d\n", ret); } } @@ -2127,15 +2125,15 @@ init_i2c_long_if(struct nvbios_init *init) u8 reghi = nvbios_rd08(bios, init->offset + 4); u8 mask = nvbios_rd08(bios, init->offset + 5); u8 data = nvbios_rd08(bios, init->offset + 6); - struct nvkm_i2c_port *port; + struct i2c_adapter *adap; trace("I2C_LONG_IF\t" "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n", index, addr, reglo, reghi, mask, data); init->offset += 7; - port = init_i2c(init, index); - if (port) { + adap = init_i2c(init, index); + if (adap) { u8 i[2] = { reghi, reglo }; u8 o[1] = {}; struct i2c_msg msg[] = { @@ -2144,7 +2142,7 @@ init_i2c_long_if(struct nvbios_init *init) }; int ret; - ret = i2c_transfer(&port->adapter, msg, 2); + ret = i2c_transfer(adap, msg, 2); if (ret == 2 && ((o[0] & mask) == data)) return; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild index d68307409980e..200f996f20b7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild @@ -1,11 +1,4 @@ nvkm-y += nvkm/subdev/i2c/base.o -nvkm-y += nvkm/subdev/i2c/anx9805.o -nvkm-y += nvkm/subdev/i2c/aux.o -nvkm-y += nvkm/subdev/i2c/bit.o -nvkm-y += nvkm/subdev/i2c/pad.o -nvkm-y += nvkm/subdev/i2c/padnv04.o -nvkm-y += nvkm/subdev/i2c/padg94.o -nvkm-y += nvkm/subdev/i2c/padgm204.o nvkm-y += nvkm/subdev/i2c/nv04.o nvkm-y += nvkm/subdev/i2c/nv4e.o nvkm-y += nvkm/subdev/i2c/nv50.o @@ -14,3 +7,24 @@ nvkm-y += nvkm/subdev/i2c/gf110.o nvkm-y += nvkm/subdev/i2c/gf117.o nvkm-y += nvkm/subdev/i2c/gk104.o nvkm-y += nvkm/subdev/i2c/gm204.o + +nvkm-y += nvkm/subdev/i2c/pad.o +nvkm-y += nvkm/subdev/i2c/padnv04.o +nvkm-y += nvkm/subdev/i2c/padnv4e.o +nvkm-y += nvkm/subdev/i2c/padnv50.o +nvkm-y += nvkm/subdev/i2c/padg94.o +nvkm-y += nvkm/subdev/i2c/padgf119.o +nvkm-y += nvkm/subdev/i2c/padgm204.o + +nvkm-y += nvkm/subdev/i2c/bus.o +nvkm-y += nvkm/subdev/i2c/busnv04.o +nvkm-y += nvkm/subdev/i2c/busnv4e.o +nvkm-y += nvkm/subdev/i2c/busnv50.o +nvkm-y += nvkm/subdev/i2c/busgf119.o +nvkm-y += nvkm/subdev/i2c/bit.o + +nvkm-y += nvkm/subdev/i2c/aux.o +nvkm-y += nvkm/subdev/i2c/auxg94.o +nvkm-y += nvkm/subdev/i2c/auxgm204.o + +nvkm-y += nvkm/subdev/i2c/anx9805.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c index 7b195393d15c5..b7b01c3f70376 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c @@ -21,274 +21,258 @@ * * Authors: Ben Skeggs */ -#include "port.h" +#define anx9805_pad(p) container_of((p), struct anx9805_pad, base) +#define anx9805_bus(p) container_of((p), struct anx9805_bus, base) +#define anx9805_aux(p) container_of((p), struct anx9805_aux, base) +#include "aux.h" +#include "bus.h" + +struct anx9805_pad { + struct nvkm_i2c_pad base; + struct nvkm_i2c_bus *bus; + u8 addr; +}; -struct anx9805_i2c_port { - struct nvkm_i2c_port base; - u32 addr; - u32 ctrl; +struct anx9805_bus { + struct nvkm_i2c_bus base; + struct anx9805_pad *pad; + u8 addr; }; static int -anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh) +anx9805_bus_xfer(struct nvkm_i2c_bus *base, struct i2c_msg *msgs, int num) { - struct nvkm_i2c *i2c = nvkm_i2c(port); - struct nvkm_subdev *subdev = &i2c->subdev; - struct anx9805_i2c_port *chan = (void *)port; - struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; - u8 tmp, i; - - DBG("ANX9805 train %d %02x %d\n", link_nr, link_bw, enh); + struct anx9805_bus *bus = anx9805_bus(base); + struct anx9805_pad *pad = bus->pad; + struct i2c_adapter *adap = &pad->bus->i2c; + struct i2c_msg *msg = msgs; + int ret = -ETIMEDOUT; + int i, j, cnt = num; + u8 seg = 0x00, off = 0x00, tmp; - nv_wri2cr(mast, chan->addr, 0xa0, link_bw); - nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); - nv_wri2cr(mast, chan->addr, 0xa2, 0x01); - nv_wri2cr(mast, chan->addr, 0xa8, 0x01); + tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x10; + nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x10); + nvkm_wri2cr(adap, pad->addr, 0x07, tmp); + nvkm_wri2cr(adap, bus->addr, 0x43, 0x05); + mdelay(5); - i = 0; - while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) { - mdelay(5); - if (i++ == 100) { - nvkm_error(subdev, "link training timed out\n"); - return -ETIMEDOUT; + while (cnt--) { + if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { + nvkm_wri2cr(adap, bus->addr, 0x40, msg->addr << 1); + nvkm_wri2cr(adap, bus->addr, 0x41, seg); + nvkm_wri2cr(adap, bus->addr, 0x42, off); + nvkm_wri2cr(adap, bus->addr, 0x44, msg->len); + nvkm_wri2cr(adap, bus->addr, 0x45, 0x00); + nvkm_wri2cr(adap, bus->addr, 0x43, 0x01); + for (i = 0; i < msg->len; i++) { + j = 0; + while (nvkm_rdi2cr(adap, bus->addr, 0x46) & 0x10) { + mdelay(5); + if (j++ == 32) + goto done; + } + msg->buf[i] = nvkm_rdi2cr(adap, bus->addr, 0x47); + } + } else + if (!(msg->flags & I2C_M_RD)) { + if (msg->addr == 0x50 && msg->len == 0x01) { + off = msg->buf[0]; + } else + if (msg->addr == 0x30 && msg->len == 0x01) { + seg = msg->buf[0]; + } else + goto done; + } else { + goto done; } + msg++; } - if (tmp & 0x70) { - nvkm_error(subdev, "link training failed: %02x\n", tmp); - return -EIO; + ret = num; +done: + nvkm_wri2cr(adap, bus->addr, 0x43, 0x00); + return ret; +} + +static const struct nvkm_i2c_bus_func +anx9805_bus_func = { + .xfer = anx9805_bus_xfer, +}; + +static int +anx9805_bus_new(struct nvkm_i2c_pad *base, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + struct anx9805_pad *pad = anx9805_pad(base); + struct anx9805_bus *bus; + int ret; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + bus->pad = pad; + + ret = nvkm_i2c_bus_ctor(&anx9805_bus_func, &pad->base, id, &bus->base); + if (ret) + return ret; + + switch (pad->addr) { + case 0x39: bus->addr = 0x3d; break; + case 0x3b: bus->addr = 0x3f; break; + default: + return -ENOSYS; } - return 1; + return 0; } +struct anx9805_aux { + struct nvkm_i2c_aux base; + struct anx9805_pad *pad; + u8 addr; +}; + static int -anx9805_aux(struct nvkm_i2c_port *port, bool retry, - u8 type, u32 addr, u8 *data, u8 size) +anx9805_aux_xfer(struct nvkm_i2c_aux *base, bool retry, + u8 type, u32 addr, u8 *data, u8 size) { - struct anx9805_i2c_port *chan = (void *)port; - struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent; + struct anx9805_aux *aux = anx9805_aux(base); + struct anx9805_pad *pad = aux->pad; + struct i2c_adapter *adap = &pad->bus->i2c; int i, ret = -ETIMEDOUT; u8 buf[16] = {}; u8 tmp; - DBG("%02x %05x %d\n", type, addr, size); + AUX_DBG(&aux->base, "%02x %05x %d", type, addr, size); - tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04; - nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04); - nv_wri2cr(mast, chan->ctrl, 0x07, tmp); - nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); + tmp = nvkm_rdi2cr(adap, pad->addr, 0x07) & ~0x04; + nvkm_wri2cr(adap, pad->addr, 0x07, tmp | 0x04); + nvkm_wri2cr(adap, pad->addr, 0x07, tmp); + nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01); - nv_wri2cr(mast, chan->addr, 0xe4, 0x80); + nvkm_wri2cr(adap, aux->addr, 0xe4, 0x80); if (!(type & 1)) { memcpy(buf, data, size); - DBG("%16ph", buf); + AUX_DBG(&aux->base, "%16ph", buf); for (i = 0; i < size; i++) - nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]); + nvkm_wri2cr(adap, aux->addr, 0xf0 + i, buf[i]); } - nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type); - nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0); - nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8); - nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16); - nv_wri2cr(mast, chan->addr, 0xe9, 0x01); + nvkm_wri2cr(adap, aux->addr, 0xe5, ((size - 1) << 4) | type); + nvkm_wri2cr(adap, aux->addr, 0xe6, (addr & 0x000ff) >> 0); + nvkm_wri2cr(adap, aux->addr, 0xe7, (addr & 0x0ff00) >> 8); + nvkm_wri2cr(adap, aux->addr, 0xe8, (addr & 0xf0000) >> 16); + nvkm_wri2cr(adap, aux->addr, 0xe9, 0x01); i = 0; - while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) { + while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xe9)) & 0x01) { mdelay(5); if (i++ == 32) goto done; } - if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) { + if ((tmp = nvkm_rdi2cr(adap, pad->addr, 0xf7)) & 0x01) { ret = -EIO; goto done; } if (type & 1) { for (i = 0; i < size; i++) - buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i); - DBG("%16ph", buf); + buf[i] = nvkm_rdi2cr(adap, aux->addr, 0xf0 + i); + AUX_DBG(&aux->base, "%16ph", buf); memcpy(data, buf, size); } ret = 0; done: - nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01); + nvkm_wri2cr(adap, pad->addr, 0xf7, 0x01); return ret; } -static const struct nvkm_i2c_func -anx9805_aux_func = { - .aux = anx9805_aux, - .lnk_ctl = anx9805_train, -}; - static int -anx9805_aux_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +anx9805_aux_lnk_ctl(struct nvkm_i2c_aux *base, + int link_nr, int link_bw, bool enh) { - struct nvkm_i2c_port *mast = (void *)parent; - struct anx9805_i2c_port *chan; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_aux_algo, &anx9805_aux_func, - &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - switch ((oclass->handle & 0xff00) >> 8) { - case 0x0d: - chan->addr = 0x38; - chan->ctrl = 0x39; - break; - case 0x0e: - chan->addr = 0x3c; - chan->ctrl = 0x3b; - break; - default: - BUG_ON(1); - } - - if (mast->adapter.algo == &i2c_bit_algo) { - struct i2c_algo_bit_data *algo = mast->adapter.algo_data; - algo->udelay = max(algo->udelay, 40); - } - - return 0; -} - -static struct nvkm_ofuncs -anx9805_aux_ofuncs = { - .ctor = anx9805_aux_chan_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, -}; + struct anx9805_aux *aux = anx9805_aux(base); + struct anx9805_pad *pad = aux->pad; + struct i2c_adapter *adap = &pad->bus->i2c; + u8 tmp, i; -static int -anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) -{ - struct anx9805_i2c_port *port = adap->algo_data; - struct nvkm_i2c_port *mast = (void *)nv_object(port)->parent; - struct i2c_msg *msg = msgs; - int ret = -ETIMEDOUT; - int i, j, cnt = num; - u8 seg = 0x00, off = 0x00, tmp; + AUX_DBG(&aux->base, "ANX9805 train %d %02x %d", + link_nr, link_bw, enh); - tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10; - nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10); - nv_wri2cr(mast, port->ctrl, 0x07, tmp); - nv_wri2cr(mast, port->addr, 0x43, 0x05); - mdelay(5); + nvkm_wri2cr(adap, aux->addr, 0xa0, link_bw); + nvkm_wri2cr(adap, aux->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00)); + nvkm_wri2cr(adap, aux->addr, 0xa2, 0x01); + nvkm_wri2cr(adap, aux->addr, 0xa8, 0x01); - while (cnt--) { - if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) { - nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1); - nv_wri2cr(mast, port->addr, 0x41, seg); - nv_wri2cr(mast, port->addr, 0x42, off); - nv_wri2cr(mast, port->addr, 0x44, msg->len); - nv_wri2cr(mast, port->addr, 0x45, 0x00); - nv_wri2cr(mast, port->addr, 0x43, 0x01); - for (i = 0; i < msg->len; i++) { - j = 0; - while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) { - mdelay(5); - if (j++ == 32) - goto done; - } - msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47); - } - } else - if (!(msg->flags & I2C_M_RD)) { - if (msg->addr == 0x50 && msg->len == 0x01) { - off = msg->buf[0]; - } else - if (msg->addr == 0x30 && msg->len == 0x01) { - seg = msg->buf[0]; - } else - goto done; - } else { - goto done; + i = 0; + while ((tmp = nvkm_rdi2cr(adap, aux->addr, 0xa8)) & 0x01) { + mdelay(5); + if (i++ == 100) { + AUX_ERR(&aux->base, "link training timeout"); + return -ETIMEDOUT; } - msg++; } - ret = num; -done: - nv_wri2cr(mast, port->addr, 0x43, 0x00); - return ret; -} + if (tmp & 0x70) { + AUX_ERR(&aux->base, "link training failed"); + return -EIO; + } -static u32 -anx9805_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return 0; } -static const struct i2c_algorithm -anx9805_i2c_algo = { - .master_xfer = anx9805_xfer, - .functionality = anx9805_func -}; - -static const struct nvkm_i2c_func -anx9805_i2c_func = { +static const struct nvkm_i2c_aux_func +anx9805_aux_func = { + .xfer = anx9805_aux_xfer, + .lnk_ctl = anx9805_aux_lnk_ctl, }; static int -anx9805_ddc_port_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +anx9805_aux_new(struct nvkm_i2c_pad *base, int id, u8 drive, + struct nvkm_i2c_aux **pbus) { - struct nvkm_i2c_port *mast = (void *)parent; - struct anx9805_i2c_port *port; + struct anx9805_pad *pad = anx9805_pad(base); + struct anx9805_aux *aux; int ret; - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &anx9805_i2c_algo, &anx9805_i2c_func, &port); - *pobject = nv_object(port); + if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL))) + return -ENOMEM; + *pbus = &aux->base; + aux->pad = pad; + + ret = nvkm_i2c_aux_ctor(&anx9805_aux_func, &pad->base, id, &aux->base); if (ret) return ret; - switch ((oclass->handle & 0xff00) >> 8) { - case 0x0d: - port->addr = 0x3d; - port->ctrl = 0x39; - break; - case 0x0e: - port->addr = 0x3f; - port->ctrl = 0x3b; - break; + switch (pad->addr) { + case 0x39: aux->addr = 0x38; break; + case 0x3b: aux->addr = 0x3c; break; default: - BUG_ON(1); - } - - if (mast->adapter.algo == &i2c_bit_algo) { - struct i2c_algo_bit_data *algo = mast->adapter.algo_data; - algo->udelay = max(algo->udelay, 40); + return -ENOSYS; } return 0; } -static struct nvkm_ofuncs -anx9805_ddc_ofuncs = { - .ctor = anx9805_ddc_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, +static const struct nvkm_i2c_pad_func +anx9805_pad_func = { + .bus_new_4 = anx9805_bus_new, + .aux_new_6 = anx9805_aux_new, }; -struct nvkm_oclass -nvkm_anx9805_sclass[] = { - { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs }, - { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs }, - { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs }, - { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs }, - {} -}; +int +anx9805_pad_new(struct nvkm_i2c_bus *bus, int id, u8 addr, + struct nvkm_i2c_pad **ppad) +{ + struct anx9805_pad *pad; + + if (!(pad = kzalloc(sizeof(*pad), GFP_KERNEL))) + return -ENOMEM; + *ppad = &pad->base; + + nvkm_i2c_pad_ctor(&anx9805_pad_func, bus->pad->i2c, id, &pad->base); + pad->bus = bus; + pad->addr = addr; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c index 1c18860f80d10..f0851d57df2f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c @@ -21,50 +21,17 @@ * * Authors: Ben Skeggs */ -#include "priv.h" - -int -nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *i2c = nvkm_i2c(port); - if (port->func->aux) { - int ret = i2c->acquire(port, 0); - if (ret == 0) { - ret = port->func->aux(port, true, 9, addr, data, size); - i2c->release(port); - } - return ret; - } - return -ENODEV; -} - -int -nv_wraux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *i2c = nvkm_i2c(port); - if (port->func->aux) { - int ret = i2c->acquire(port, 0); - if (ret == 0) { - ret = port->func->aux(port, true, 8, addr, data, size); - i2c->release(port); - } - return ret; - } - return -ENODEV; -} +#include "aux.h" +#include "pad.h" static int -aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +nvkm_i2c_aux_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { - struct nvkm_i2c_port *port = adap->algo_data; - struct nvkm_i2c *i2c = nvkm_i2c(port); + struct nvkm_i2c_aux *aux = container_of(adap, typeof(*aux), i2c); struct i2c_msg *msg = msgs; int ret, mcnt = num; - if (!port->func->aux) - return -ENODEV; - - ret = i2c->acquire(port, 0); + ret = nvkm_i2c_aux_acquire(aux); if (ret) return ret; @@ -84,9 +51,9 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (mcnt || remaining > 16) cmd |= 4; /* MOT */ - ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt); + ret = aux->func->xfer(aux, true, cmd, msg->addr, ptr, cnt); if (ret < 0) { - i2c->release(port); + nvkm_i2c_aux_release(aux); return ret; } @@ -97,17 +64,111 @@ aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) msg++; } - i2c->release(port); + nvkm_i2c_aux_release(aux); return num; } static u32 -aux_func(struct i2c_adapter *adap) +nvkm_i2c_aux_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } -const struct i2c_algorithm nvkm_i2c_aux_algo = { - .master_xfer = aux_xfer, - .functionality = aux_func +const struct i2c_algorithm +nvkm_i2c_aux_i2c_algo = { + .master_xfer = nvkm_i2c_aux_i2c_xfer, + .functionality = nvkm_i2c_aux_i2c_func }; + +void +nvkm_i2c_aux_monitor(struct nvkm_i2c_aux *aux, bool monitor) +{ + struct nvkm_i2c_pad *pad = aux->pad; + AUX_TRACE(aux, "monitor: %s", monitor ? "yes" : "no"); + if (monitor) + nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_AUX); + else + nvkm_i2c_pad_mode(pad, NVKM_I2C_PAD_OFF); +} + +void +nvkm_i2c_aux_release(struct nvkm_i2c_aux *aux) +{ + struct nvkm_i2c_pad *pad = aux->pad; + AUX_TRACE(aux, "release"); + nvkm_i2c_pad_release(pad); + mutex_unlock(&aux->mutex); +} + +int +nvkm_i2c_aux_acquire(struct nvkm_i2c_aux *aux) +{ + struct nvkm_i2c_pad *pad = aux->pad; + int ret; + AUX_TRACE(aux, "acquire"); + mutex_lock(&aux->mutex); + ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_AUX); + if (ret) + mutex_unlock(&aux->mutex); + return ret; +} + +int +nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *aux, bool retry, u8 type, + u32 addr, u8 *data, u8 size) +{ + return aux->func->xfer(aux, retry, type, addr, data, size); +} + +int +nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *aux, int nr, int bw, bool ef) +{ + if (aux->func->lnk_ctl) + return aux->func->lnk_ctl(aux, nr, bw, ef); + return -ENODEV; +} + +void +nvkm_i2c_aux_del(struct nvkm_i2c_aux **paux) +{ + struct nvkm_i2c_aux *aux = *paux; + if (aux && !WARN_ON(!aux->func)) { + AUX_TRACE(aux, "dtor"); + list_del(&aux->head); + i2c_del_adapter(&aux->i2c); + kfree(*paux); + *paux = NULL; + } +} + +int +nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_aux *aux) +{ + struct nvkm_device *device = pad->i2c->subdev.device; + + aux->func = func; + aux->pad = pad; + aux->id = id; + mutex_init(&aux->mutex); + list_add_tail(&aux->head, &pad->i2c->aux); + AUX_TRACE(aux, "ctor"); + + snprintf(aux->i2c.name, sizeof(aux->i2c.name), "nvkm-%s-aux-%04x", + dev_name(device->dev), id); + aux->i2c.owner = THIS_MODULE; + aux->i2c.dev.parent = device->dev; + aux->i2c.algo = &nvkm_i2c_aux_i2c_algo; + return i2c_add_adapter(&aux->i2c); +} + +int +nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_aux **paux) +{ + if (!(*paux = kzalloc(sizeof(**paux), GFP_KERNEL))) + return -ENOMEM; + return nvkm_i2c_aux_ctor(func, pad, id, *paux); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h new file mode 100644 index 0000000000000..35a892e4a4c3f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.h @@ -0,0 +1,30 @@ +#ifndef __NVKM_I2C_AUX_H__ +#define __NVKM_I2C_AUX_H__ +#include "pad.h" + +struct nvkm_i2c_aux_func { + int (*xfer)(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 size); + int (*lnk_ctl)(struct nvkm_i2c_aux *, int link_nr, int link_bw, + bool enhanced_framing); +}; + +int nvkm_i2c_aux_ctor(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_aux *); +int nvkm_i2c_aux_new_(const struct nvkm_i2c_aux_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_aux **); +void nvkm_i2c_aux_del(struct nvkm_i2c_aux **); +int nvkm_i2c_aux_xfer(struct nvkm_i2c_aux *, bool retry, u8 type, + u32 addr, u8 *data, u8 size); + +int g94_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); +int gm204_i2c_aux_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_aux **); + +#define AUX_MSG(b,l,f,a...) do { \ + struct nvkm_i2c_aux *_aux = (b); \ + nvkm_##l(&_aux->pad->i2c->subdev, "aux %04x: "f"\n", _aux->id, ##a); \ +} while(0) +#define AUX_ERR(b,f,a...) AUX_MSG((b), error, f, ##a) +#define AUX_DBG(b,f,a...) AUX_MSG((b), debug, f, ##a) +#define AUX_TRACE(b,f,a...) AUX_MSG((b), trace, f, ##a) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c new file mode 100644 index 0000000000000..954f5b76bfcf7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxg94.c @@ -0,0 +1,181 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 shall be included in + * all copies or substantial busions 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define g94_i2c_aux(p) container_of((p), struct g94_i2c_aux, base) +#include "aux.h" + +struct g94_i2c_aux { + struct nvkm_i2c_aux base; + int ch; +}; + +static void +g94_i2c_aux_fini(struct g94_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00310000, 0x00000000); +} + +static int +g94_i2c_aux_init(struct g94_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nvkm_mask(device, 0x00e4e4 + (aux->ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00e4e4 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "magic wait %08x", ctrl); + g94_i2c_aux_fini(aux); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); + + return 0; +} + +static int +g94_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, + u8 type, u32 addr, u8 *data, u8 size) +{ + struct g94_i2c_aux *aux = g94_i2c_aux(obj); + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 base = aux->ch * 0x50; + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; + + AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, size); + + ret = g94_i2c_aux_init(aux); + if (ret < 0) + goto out; + + stat = nvkm_rd32(device, 0x00e4e8 + base); + if (!(stat & 0x10000000)) { + AUX_TRACE(&aux->base, "sink not detected"); + ret = -ENXIO; + goto out; + } + + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]); + nvkm_wr32(device, 0x00e4c0 + base + i, xbuf[i / 4]); + } + } + + ctrl = nvkm_rd32(device, 0x00e4e4 + base); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nvkm_wr32(device, 0x00e4e0 + base, addr); + + /* (maybe) retry transaction a number of times on failure... */ + for (retries = 0; !ret && retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nvkm_wr32(device, 0x00e4e4 + base, 0x80000000 | ctrl); + nvkm_wr32(device, 0x00e4e4 + base, 0x00000000 | ctrl); + if (retries) + udelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nvkm_wr32(device, 0x00e4e4 + base, 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00e4e4 + base); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "timeout %08x", ctrl); + ret = -EIO; + goto out; + } + } while (ctrl & 0x00010000); + ret = 1; + + /* read status, and check if transaction completed ok */ + stat = nvkm_mask(device, 0x00e4e8 + base, 0, 0); + if ((stat & 0x000f0000) == 0x00080000 || + (stat & 0x000f0000) == 0x00020000) + ret = retry ? 0 : 1; + if ((stat & 0x00000100)) + ret = -ETIMEDOUT; + if ((stat & 0x00000e00)) + ret = -EIO; + + AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat); + } + + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nvkm_rd32(device, 0x00e4d0 + base + i); + AUX_TRACE(&aux->base, "rd %08x", xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } + +out: + g94_i2c_aux_fini(aux); + return ret < 0 ? ret : (stat & 0x000f0000) >> 16; +} + +static const struct nvkm_i2c_aux_func +g94_i2c_aux_func = { + .xfer = g94_i2c_aux_xfer, +}; + +int +g94_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive, + struct nvkm_i2c_aux **paux) +{ + struct g94_i2c_aux *aux; + + if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL))) + return -ENOMEM; + *paux = &aux->base; + + nvkm_i2c_aux_ctor(&g94_i2c_aux_func, pad, index, &aux->base); + aux->ch = drive; + aux->base.intr = 1 << aux->ch; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c new file mode 100644 index 0000000000000..bed231b56dbd2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/auxgm204.c @@ -0,0 +1,181 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 shall be included in + * all copies or substantial busions 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define gm204_i2c_aux(p) container_of((p), struct gm204_i2c_aux, base) +#include "aux.h" + +struct gm204_i2c_aux { + struct nvkm_i2c_aux base; + int ch; +}; + +static void +gm204_i2c_aux_fini(struct gm204_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00310000, 0x00000000); +} + +static int +gm204_i2c_aux_init(struct gm204_i2c_aux *aux) +{ + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 unksel = 1; /* nfi which to use, or if it matters.. */ + const u32 ureq = unksel ? 0x00100000 : 0x00200000; + const u32 urep = unksel ? 0x01000000 : 0x02000000; + u32 ctrl, timeout; + + /* wait up to 1ms for any previous transaction to be done... */ + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "begin idle timeout %08x", ctrl); + return -EBUSY; + } + } while (ctrl & 0x03010000); + + /* set some magic, and wait up to 1ms for it to appear */ + nvkm_mask(device, 0x00d954 + (aux->ch * 0x50), 0x00300000, ureq); + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00d954 + (aux->ch * 0x50)); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "magic wait %08x", ctrl); + gm204_i2c_aux_fini(aux); + return -EBUSY; + } + } while ((ctrl & 0x03000000) != urep); + + return 0; +} + +static int +gm204_i2c_aux_xfer(struct nvkm_i2c_aux *obj, bool retry, + u8 type, u32 addr, u8 *data, u8 size) +{ + struct gm204_i2c_aux *aux = gm204_i2c_aux(obj); + struct nvkm_device *device = aux->base.pad->i2c->subdev.device; + const u32 base = aux->ch * 0x50; + u32 ctrl, stat, timeout, retries; + u32 xbuf[4] = {}; + int ret, i; + + AUX_TRACE(&aux->base, "%d: %08x %d", type, addr, size); + + ret = gm204_i2c_aux_init(aux); + if (ret < 0) + goto out; + + stat = nvkm_rd32(device, 0x00d958 + base); + if (!(stat & 0x10000000)) { + AUX_TRACE(&aux->base, "sink not detected"); + ret = -ENXIO; + goto out; + } + + if (!(type & 1)) { + memcpy(xbuf, data, size); + for (i = 0; i < 16; i += 4) { + AUX_TRACE(&aux->base, "wr %08x", xbuf[i / 4]); + nvkm_wr32(device, 0x00d930 + base + i, xbuf[i / 4]); + } + } + + ctrl = nvkm_rd32(device, 0x00d954 + base); + ctrl &= ~0x0001f0ff; + ctrl |= type << 12; + ctrl |= size - 1; + nvkm_wr32(device, 0x00d950 + base, addr); + + /* (maybe) retry transaction a number of times on failure... */ + for (retries = 0; !ret && retries < 32; retries++) { + /* reset, and delay a while if this is a retry */ + nvkm_wr32(device, 0x00d954 + base, 0x80000000 | ctrl); + nvkm_wr32(device, 0x00d954 + base, 0x00000000 | ctrl); + if (retries) + udelay(400); + + /* transaction request, wait up to 1ms for it to complete */ + nvkm_wr32(device, 0x00d954 + base, 0x00010000 | ctrl); + + timeout = 1000; + do { + ctrl = nvkm_rd32(device, 0x00d954 + base); + udelay(1); + if (!timeout--) { + AUX_ERR(&aux->base, "timeout %08x", ctrl); + ret = -EIO; + goto out; + } + } while (ctrl & 0x00010000); + ret = 1; + + /* read status, and check if transaction completed ok */ + stat = nvkm_mask(device, 0x00d958 + base, 0, 0); + if ((stat & 0x000f0000) == 0x00080000 || + (stat & 0x000f0000) == 0x00020000) + ret = retry ? 0 : 1; + if ((stat & 0x00000100)) + ret = -ETIMEDOUT; + if ((stat & 0x00000e00)) + ret = -EIO; + + AUX_TRACE(&aux->base, "%02d %08x %08x", retries, ctrl, stat); + } + + if (type & 1) { + for (i = 0; i < 16; i += 4) { + xbuf[i / 4] = nvkm_rd32(device, 0x00d940 + base + i); + AUX_TRACE(&aux->base, "rd %08x", xbuf[i / 4]); + } + memcpy(data, xbuf, size); + } + +out: + gm204_i2c_aux_fini(aux); + return ret < 0 ? ret : (stat & 0x000f0000) >> 16; +} + +static const struct nvkm_i2c_aux_func +gm204_i2c_aux_func = { + .xfer = gm204_i2c_aux_xfer, +}; + +int +gm204_i2c_aux_new(struct nvkm_i2c_pad *pad, int index, u8 drive, + struct nvkm_i2c_aux **paux) +{ + struct gm204_i2c_aux *aux; + + if (!(aux = kzalloc(sizeof(*aux), GFP_KERNEL))) + return -ENOMEM; + *paux = &aux->base; + + nvkm_i2c_aux_ctor(&gm204_i2c_aux_func, pad, index, &aux->base); + aux->ch = drive; + aux->base.intr = 1 << aux->ch; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 6b0f8f0746f51..86bff984e7e10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -22,330 +22,93 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "aux.h" +#include "bus.h" #include "pad.h" #include #include #include #include +#include -/****************************************************************************** - * interface to linux i2c bit-banging algorithm - *****************************************************************************/ - -#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT -#define CSTMSEL true -#else -#define CSTMSEL false -#endif - -static int -nvkm_i2c_pre_xfer(struct i2c_adapter *adap) -{ - struct i2c_algo_bit_data *bit = adap->algo_data; - struct nvkm_i2c_port *port = bit->data; - return nvkm_i2c(port)->acquire(port, bit->timeout); -} - -static void -nvkm_i2c_post_xfer(struct i2c_adapter *adap) -{ - struct i2c_algo_bit_data *bit = adap->algo_data; - struct nvkm_i2c_port *port = bit->data; - return nvkm_i2c(port)->release(port); -} - -static void -nvkm_i2c_setscl(void *data, int state) -{ - struct nvkm_i2c_port *port = data; - port->func->drive_scl(port, state); -} - -static void -nvkm_i2c_setsda(void *data, int state) -{ - struct nvkm_i2c_port *port = data; - port->func->drive_sda(port, state); -} - -static int -nvkm_i2c_getscl(void *data) +static struct nvkm_i2c_pad * +nvkm_i2c_pad_find(struct nvkm_i2c *i2c, int id) { - struct nvkm_i2c_port *port = data; - return port->func->sense_scl(port); -} - -static int -nvkm_i2c_getsda(void *data) -{ - struct nvkm_i2c_port *port = data; - return port->func->sense_sda(port); -} - -/****************************************************************************** - * base i2c "port" class implementation - *****************************************************************************/ - -int -_nvkm_i2c_port_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_i2c_port *port = (void *)object; - struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); - nv_ofuncs(pad)->fini(nv_object(pad), suspend); - return nvkm_object_fini(&port->base, suspend); -} - -void -_nvkm_i2c_port_dtor(struct nvkm_object *object) -{ - struct nvkm_i2c_port *port = (void *)object; - i2c_del_adapter(&port->adapter); - nvkm_object_destroy(&port->base); -} - -int -nvkm_i2c_port_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u8 index, - const struct i2c_algorithm *algo, - const struct nvkm_i2c_func *func, - int size, void **pobject) -{ - struct nvkm_device *device = nv_device(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_i2c_port *port; - int ret; + struct nvkm_i2c_pad *pad; - ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject); - port = *pobject; - if (ret) - return ret; - - snprintf(port->adapter.name, sizeof(port->adapter.name), - "nvkm-%s-%d", device->name, index); - port->adapter.owner = THIS_MODULE; - port->adapter.dev.parent = nv_device_base(device); - port->index = index; - port->aux = -1; - port->func = func; - mutex_init(&port->mutex); - - if ( algo == &nvkm_i2c_bit_algo && - !nvkm_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) { - struct i2c_algo_bit_data *bit; - - bit = kzalloc(sizeof(*bit), GFP_KERNEL); - if (!bit) - return -ENOMEM; - - bit->udelay = 10; - bit->timeout = usecs_to_jiffies(2200); - bit->data = port; - bit->pre_xfer = nvkm_i2c_pre_xfer; - bit->post_xfer = nvkm_i2c_post_xfer; - bit->setsda = nvkm_i2c_setsda; - bit->setscl = nvkm_i2c_setscl; - bit->getsda = nvkm_i2c_getsda; - bit->getscl = nvkm_i2c_getscl; - - port->adapter.algo_data = bit; - ret = i2c_bit_add_bus(&port->adapter); - } else { - port->adapter.algo_data = port; - port->adapter.algo = algo; - ret = i2c_add_adapter(&port->adapter); + list_for_each_entry(pad, &i2c->pad, head) { + if (pad->id == id) + return pad; } - if (ret == 0) - list_add_tail(&port->head, &i2c->ports); - return ret; + return NULL; } -/****************************************************************************** - * base i2c subdev class implementation - *****************************************************************************/ - -static struct nvkm_i2c_port * -nvkm_i2c_find(struct nvkm_i2c *i2c, u8 index) +struct nvkm_i2c_bus * +nvkm_i2c_bus_find(struct nvkm_i2c *i2c, int id) { - struct nvkm_bios *bios = nvkm_bios(i2c); - struct nvkm_i2c_port *port; + struct nvkm_bios *bios = i2c->subdev.device->bios; + struct nvkm_i2c_bus *bus; - if (index == NV_I2C_DEFAULT(0) || - index == NV_I2C_DEFAULT(1)) { + if (id == NVKM_I2C_BUS_PRI || id == NVKM_I2C_BUS_SEC) { u8 ver, hdr, cnt, len; u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len); if (i2c && ver >= 0x30) { u8 auxidx = nvbios_rd08(bios, i2c + 4); - if (index == NV_I2C_DEFAULT(0)) - index = (auxidx & 0x0f) >> 0; + if (id == NVKM_I2C_BUS_PRI) + id = NVKM_I2C_BUS_CCB((auxidx & 0x0f) >> 0); else - index = (auxidx & 0xf0) >> 4; + id = NVKM_I2C_BUS_CCB((auxidx & 0xf0) >> 4); } else { - index = 2; + id = NVKM_I2C_BUS_CCB(2); } } - list_for_each_entry(port, &i2c->ports, head) { - if (port->index == index) - return port; + list_for_each_entry(bus, &i2c->bus, head) { + if (bus->id == id) + return bus; } return NULL; } -static struct nvkm_i2c_port * -nvkm_i2c_find_type(struct nvkm_i2c *i2c, u16 type) +struct nvkm_i2c_aux * +nvkm_i2c_aux_find(struct nvkm_i2c *i2c, int id) { - struct nvkm_i2c_port *port; + struct nvkm_i2c_aux *aux; - list_for_each_entry(port, &i2c->ports, head) { - if (nv_hclass(port) == type) - return port; + list_for_each_entry(aux, &i2c->aux, head) { + if (aux->id == id) + return aux; } return NULL; } static void -nvkm_i2c_release_pad(struct nvkm_i2c_port *port) -{ - struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); - struct nvkm_i2c *i2c = nvkm_i2c(port); - - if (atomic_dec_and_test(&nv_object(pad)->usecount)) { - nv_ofuncs(pad)->fini(nv_object(pad), false); - wake_up_all(&i2c->wait); - } -} - -static int -nvkm_i2c_try_acquire_pad(struct nvkm_i2c_port *port) -{ - struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port); - - if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) { - struct nvkm_object *owner = (void *)pad->port; - do { - if (owner == (void *)port) - return 0; - owner = owner->parent; - } while(owner); - nvkm_i2c_release_pad(port); - return -EBUSY; - } - - pad->next = port; - nv_ofuncs(pad)->init(nv_object(pad)); - return 0; -} - -static int -nvkm_i2c_acquire_pad(struct nvkm_i2c_port *port, unsigned long timeout) -{ - struct nvkm_i2c *i2c = nvkm_i2c(port); - - if (timeout) { - if (wait_event_timeout(i2c->wait, - nvkm_i2c_try_acquire_pad(port) == 0, - timeout) == 0) - return -EBUSY; - } else { - wait_event(i2c->wait, nvkm_i2c_try_acquire_pad(port) == 0); - } - - return 0; -} - -static void -nvkm_i2c_release(struct nvkm_i2c_port *port) -__releases(pad->mutex) -{ - nvkm_i2c(port)->release_pad(port); - mutex_unlock(&port->mutex); -} - -static int -nvkm_i2c_acquire(struct nvkm_i2c_port *port, unsigned long timeout) -__acquires(pad->mutex) -{ - int ret; - mutex_lock(&port->mutex); - if ((ret = nvkm_i2c(port)->acquire_pad(port, timeout))) - mutex_unlock(&port->mutex); - return ret; -} - -static int -nvkm_i2c_identify(struct nvkm_i2c *i2c, int index, const char *what, - struct nvkm_i2c_board_info *info, - bool (*match)(struct nvkm_i2c_port *, - struct i2c_board_info *, void *), void *data) -{ - struct nvkm_subdev *subdev = &i2c->subdev; - struct nvkm_i2c_port *port = nvkm_i2c_find(i2c, index); - int i; - - if (!port) { - nvkm_debug(subdev, "no bus when probing %s on %d\n", - what, index); - return -ENODEV; - } - - nvkm_debug(subdev, "probing %ss on bus: %d\n", what, port->index); - for (i = 0; info[i].dev.addr; i++) { - u8 orig_udelay = 0; - - if ((port->adapter.algo == &i2c_bit_algo) && - (info[i].udelay != 0)) { - struct i2c_algo_bit_data *algo = port->adapter.algo_data; - nvkm_debug(subdev, - "using custom udelay %d instead of %d\n", - info[i].udelay, algo->udelay); - orig_udelay = algo->udelay; - algo->udelay = info[i].udelay; - } - - if (nv_probe_i2c(port, info[i].dev.addr) && - (!match || match(port, &info[i].dev, data))) { - nvkm_info(subdev, "detected %s: %s\n", what, - info[i].dev.type); - return i; - } - - if (orig_udelay) { - struct i2c_algo_bit_data *algo = port->adapter.algo_data; - algo->udelay = orig_udelay; - } - } - - nvkm_debug(subdev, "no devices found.\n"); - return -ENODEV; -} - -static void -nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int index) +nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int id) { struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event); - struct nvkm_i2c_port *port = i2c->find(i2c, index); + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id); const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass; - if (port && port->aux >= 0) - impl->aux_mask(i2c, type, 1 << port->aux, 0); + if (aux) + impl->aux_mask(i2c, type, aux->intr, 0); } static void -nvkm_i2c_intr_init(struct nvkm_event *event, int type, int index) +nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id) { struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event); - struct nvkm_i2c_port *port = i2c->find(i2c, index); + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id); const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass; - if (port && port->aux >= 0) - impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux); + if (aux) + impl->aux_mask(i2c, type, aux->intr, aux->intr); } static int nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) + struct nvkm_notify *notify) { struct nvkm_i2c_ntfy_req *req = data; if (!WARN_ON(size != sizeof(*req))) { @@ -358,33 +121,32 @@ nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size, } static void -nvkm_i2c_intr(struct nvkm_subdev *subdev) +nvkm_i2c_intr(struct nvkm_subdev *obj) { - struct nvkm_i2c_impl *impl = (void *)nv_oclass(subdev); - struct nvkm_i2c *i2c = nvkm_i2c(subdev); - struct nvkm_i2c_port *port; - u32 hi, lo, rq, tx, e; - - if (impl->aux_stat) { - impl->aux_stat(i2c, &hi, &lo, &rq, &tx); - if (hi || lo || rq || tx) { - list_for_each_entry(port, &i2c->ports, head) { - if (e = 0, port->aux < 0) - continue; - - if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG; - if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG; - if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ; - if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE; - if (e) { - struct nvkm_i2c_ntfy_rep rep = { - .mask = e, - }; - nvkm_event_send(&i2c->event, rep.mask, - port->index, &rep, - sizeof(rep)); - } - } + struct nvkm_i2c *i2c = container_of(obj, typeof(*i2c), subdev); + struct nvkm_i2c_impl *impl = (void *)i2c->subdev.object.oclass; + struct nvkm_i2c_aux *aux; + u32 hi, lo, rq, tx; + + if (!impl->aux_stat) + return; + + impl->aux_stat(i2c, &hi, &lo, &rq, &tx); + if (!hi && !lo && !rq && !tx) + return; + + list_for_each_entry(aux, &i2c->aux, head) { + u32 mask = 0; + if (hi & aux->intr) mask |= NVKM_I2C_PLUG; + if (lo & aux->intr) mask |= NVKM_I2C_UNPLUG; + if (rq & aux->intr) mask |= NVKM_I2C_IRQ; + if (tx & aux->intr) mask |= NVKM_I2C_DONE; + if (mask) { + struct nvkm_i2c_ntfy_rep rep = { + .mask = mask, + }; + nvkm_event_send(&i2c->event, rep.mask, aux->id, + &rep, sizeof(rep)); } } } @@ -401,206 +163,241 @@ _nvkm_i2c_fini(struct nvkm_object *object, bool suspend) { struct nvkm_i2c_impl *impl = (void *)nv_oclass(object); struct nvkm_i2c *i2c = (void *)object; - struct nvkm_i2c_port *port; + struct nvkm_i2c_pad *pad; u32 mask; - int ret; - - list_for_each_entry(port, &i2c->ports, head) { - ret = nv_ofuncs(port)->fini(nv_object(port), suspend); - if (ret && suspend) - goto fail; - } if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); impl->aux_stat(i2c, &mask, &mask, &mask, &mask); } - return nvkm_subdev_fini(&i2c->subdev, suspend); -fail: - list_for_each_entry_continue_reverse(port, &i2c->ports, head) { - nv_ofuncs(port)->init(nv_object(port)); + list_for_each_entry(pad, &i2c->pad, head) { + nvkm_i2c_pad_fini(pad); } - return ret; + return nvkm_subdev_fini(&i2c->subdev, suspend); } int _nvkm_i2c_init(struct nvkm_object *object) { struct nvkm_i2c *i2c = (void *)object; - struct nvkm_i2c_port *port; + struct nvkm_i2c_bus *bus; + struct nvkm_i2c_pad *pad; int ret; ret = nvkm_subdev_init(&i2c->subdev); - if (ret == 0) { - list_for_each_entry(port, &i2c->ports, head) { - ret = nv_ofuncs(port)->init(nv_object(port)); - if (ret) - goto fail; - } + if (ret) + return ret; + + list_for_each_entry(pad, &i2c->pad, head) { + nvkm_i2c_pad_init(pad); } - return ret; -fail: - list_for_each_entry_continue_reverse(port, &i2c->ports, head) { - nv_ofuncs(port)->fini(nv_object(port), false); + list_for_each_entry(bus, &i2c->bus, head) { + nvkm_i2c_bus_init(bus); } - return ret; + return 0; } void _nvkm_i2c_dtor(struct nvkm_object *object) { struct nvkm_i2c *i2c = (void *)object; - struct nvkm_i2c_port *port, *temp; nvkm_event_fini(&i2c->event); - list_for_each_entry_safe(port, temp, &i2c->ports, head) { - nvkm_object_ref(NULL, (struct nvkm_object **)&port); + while (!list_empty(&i2c->aux)) { + struct nvkm_i2c_aux *aux = + list_first_entry(&i2c->aux, typeof(*aux), head); + nvkm_i2c_aux_del(&aux); } - nvkm_subdev_destroy(&i2c->subdev); -} - -static struct nvkm_oclass * -nvkm_i2c_extdev_sclass[] = { - nvkm_anx9805_sclass, -}; - -static void -nvkm_i2c_create_port(struct nvkm_i2c *i2c, int index, u8 type, - struct dcb_i2c_entry *info) -{ - const struct nvkm_i2c_impl *impl = (void *)nv_oclass(i2c); - struct nvkm_oclass *oclass; - struct nvkm_object *parent; - struct nvkm_object *object; - int ret, pad; - - if (info->share != DCB_I2C_UNUSED) { - pad = info->share; - oclass = impl->pad_s; - } else { - if (type != DCB_I2C_NVIO_AUX) - pad = 0x100 + info->drive; - else - pad = 0x100 + info->auxch; - oclass = impl->pad_x; + while (!list_empty(&i2c->bus)) { + struct nvkm_i2c_bus *bus = + list_first_entry(&i2c->bus, typeof(*bus), head); + nvkm_i2c_bus_del(&bus); } - ret = nvkm_object_ctor(nv_object(i2c), NULL, oclass, - NULL, pad, &parent); - if (ret < 0) - return; + while (!list_empty(&i2c->pad)) { + struct nvkm_i2c_pad *pad = + list_first_entry(&i2c->pad, typeof(*pad), head); + nvkm_i2c_pad_del(&pad); + } - oclass = impl->sclass; - do { - ret = -EINVAL; - if (oclass->handle == type) { - ret = nvkm_object_ctor(parent, NULL, oclass, - info, index, &object); - } - } while (ret && (++oclass)->handle); + nvkm_subdev_destroy(&i2c->subdev); +} - nvkm_object_ref(NULL, &parent); +static const struct nvkm_i2c_drv { + u8 bios; + u8 addr; + int (*pad_new)(struct nvkm_i2c_bus *, int id, u8 addr, + struct nvkm_i2c_pad **); } +nvkm_i2c_drv[] = { + { 0x0d, 0x39, anx9805_pad_new }, + { 0x0e, 0x3b, anx9805_pad_new }, + {} +}; int nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_bios *bios = nvkm_bios(parent); + struct nvkm_i2c_impl *impl = (void *)oclass; + struct nvkm_device *device = (void *)parent; + struct nvkm_bios *bios = device->bios; struct nvkm_i2c *i2c; - struct nvkm_object *object; - struct dcb_i2c_entry info; - int ret, i, j, index = -1; - struct dcb_output outp; - u8 ver, hdr; - u32 data; + struct dcb_i2c_entry ccbE; + struct dcb_output dcbE; + u8 ver, hdr; + int ret, i; ret = nvkm_subdev_create(parent, engine, oclass, 0, "I2C", "i2c", &i2c); *pobject = nv_object(i2c); if (ret) return ret; + INIT_LIST_HEAD(&i2c->pad); + INIT_LIST_HEAD(&i2c->bus); + INIT_LIST_HEAD(&i2c->aux); + nv_subdev(i2c)->intr = nvkm_i2c_intr; - i2c->find = nvkm_i2c_find; - i2c->find_type = nvkm_i2c_find_type; - i2c->acquire_pad = nvkm_i2c_acquire_pad; - i2c->release_pad = nvkm_i2c_release_pad; - i2c->acquire = nvkm_i2c_acquire; - i2c->release = nvkm_i2c_release; - i2c->identify = nvkm_i2c_identify; - init_waitqueue_head(&i2c->wait); - INIT_LIST_HEAD(&i2c->ports); - - while (!dcb_i2c_parse(bios, ++index, &info)) { - switch (info.type) { - case DCB_I2C_NV04_BIT: - case DCB_I2C_NV4E_BIT: - case DCB_I2C_NVIO_BIT: - nvkm_i2c_create_port(i2c, NV_I2C_PORT(index), - info.type, &info); - break; - case DCB_I2C_NVIO_AUX: - nvkm_i2c_create_port(i2c, NV_I2C_AUX(index), - info.type, &info); - break; - case DCB_I2C_PMGR: - if (info.drive != DCB_I2C_UNUSED) { - nvkm_i2c_create_port(i2c, NV_I2C_PORT(index), - DCB_I2C_NVIO_BIT, &info); - } - if (info.auxch != DCB_I2C_UNUSED) { - nvkm_i2c_create_port(i2c, NV_I2C_AUX(index), - DCB_I2C_NVIO_AUX, &info); - } - break; - case DCB_I2C_UNUSED: - default: + + i = -1; + while (!dcb_i2c_parse(bios, ++i, &ccbE)) { + struct nvkm_i2c_pad *pad = NULL; + struct nvkm_i2c_bus *bus = NULL; + struct nvkm_i2c_aux *aux = NULL; + + nvkm_debug(&i2c->subdev, "ccb %02x: type %02x drive %02x " + "sense %02x share %02x auxch %02x\n", i, ccbE.type, + ccbE.drive, ccbE.sense, ccbE.share, ccbE.auxch); + + if (ccbE.share != DCB_I2C_UNUSED) { + const int id = NVKM_I2C_PAD_HYBRID(ccbE.share); + if (!(pad = nvkm_i2c_pad_find(i2c, id))) + ret = impl->pad_s_new(i2c, id, &pad); + else + ret = 0; + } else { + ret = impl->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad); + } + + if (ret) { + nvkm_error(&i2c->subdev, "ccb %02x pad, %d\n", i, ret); + nvkm_i2c_pad_del(&pad); + continue; + } + + if (pad->func->bus_new_0 && ccbE.type == DCB_I2C_NV04_BIT) { + ret = pad->func->bus_new_0(pad, NVKM_I2C_BUS_CCB(i), + ccbE.drive, + ccbE.sense, &bus); + } else + if (pad->func->bus_new_4 && + ( ccbE.type == DCB_I2C_NV4E_BIT || + ccbE.type == DCB_I2C_NVIO_BIT || + (ccbE.type == DCB_I2C_PMGR && + ccbE.drive != DCB_I2C_UNUSED))) { + ret = pad->func->bus_new_4(pad, NVKM_I2C_BUS_CCB(i), + ccbE.drive, &bus); + } + + if (ret) { + nvkm_error(&i2c->subdev, "ccb %02x bus, %d\n", i, ret); + nvkm_i2c_bus_del(&bus); + } + + if (pad->func->aux_new_6 && + ( ccbE.type == DCB_I2C_NVIO_AUX || + (ccbE.type == DCB_I2C_PMGR && + ccbE.auxch != DCB_I2C_UNUSED))) { + ret = pad->func->aux_new_6(pad, NVKM_I2C_BUS_CCB(i), + ccbE.auxch, &aux); + } else { + ret = 0; + } + + if (ret) { + nvkm_error(&i2c->subdev, "ccb %02x aux, %d\n", i, ret); + nvkm_i2c_aux_del(&aux); + } + + if (ccbE.type != DCB_I2C_UNUSED && !bus && !aux) { + nvkm_warn(&i2c->subdev, "ccb %02x was ignored\n", i); continue; } } - /* in addition to the busses specified in the i2c table, there - * may be ddc/aux channels hiding behind external tmds/dp/etc - * transmitters. - */ - index = NV_I2C_EXT(0); i = -1; - while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) { - if (!outp.location || !outp.extdev) + while (dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE)) { + const struct nvkm_i2c_drv *drv = nvkm_i2c_drv; + struct nvkm_i2c_bus *bus; + struct nvkm_i2c_pad *pad; + + /* internal outputs handled by native i2c busses (above) */ + if (!dcbE.location) + continue; + + /* we need an i2c bus to talk to the external encoder */ + bus = nvkm_i2c_bus_find(i2c, dcbE.i2c_index); + if (!bus) { + nvkm_debug(&i2c->subdev, "dcb %02x no bus\n", i); continue; + } - switch (outp.type) { - case DCB_OUTPUT_TMDS: - info.type = NV_I2C_TYPE_EXTDDC(outp.extdev); - break; - case DCB_OUTPUT_DP: - info.type = NV_I2C_TYPE_EXTAUX(outp.extdev); - break; - default: + /* ... and a driver for it */ + while (drv->pad_new) { + if (drv->bios == dcbE.extdev) + break; + drv++; + } + + if (!drv->pad_new) { + nvkm_debug(&i2c->subdev, "dcb %02x drv %02x unknown\n", + i, dcbE.extdev); continue; } - ret = -ENODEV; - j = -1; - while (ret && ++j < ARRAY_SIZE(nvkm_i2c_extdev_sclass)) { - parent = nv_object(i2c->find(i2c, outp.i2c_index)); - oclass = nvkm_i2c_extdev_sclass[j]; - do { - if (oclass->handle != info.type) - continue; - ret = nvkm_object_ctor(parent, NULL, oclass, - NULL, index++, &object); - } while (ret && (++oclass)->handle); + /* find/create an instance of the driver */ + pad = nvkm_i2c_pad_find(i2c, NVKM_I2C_PAD_EXT(dcbE.extdev)); + if (!pad) { + const int id = NVKM_I2C_PAD_EXT(dcbE.extdev); + ret = drv->pad_new(bus, id, drv->addr, &pad); + if (ret) { + nvkm_error(&i2c->subdev, "dcb %02x pad, %d\n", + i, ret); + nvkm_i2c_pad_del(&pad); + continue; + } + } + + /* create any i2c bus / aux channel required by the output */ + if (pad->func->aux_new_6 && dcbE.type == DCB_OUTPUT_DP) { + const int id = NVKM_I2C_AUX_EXT(dcbE.extdev); + struct nvkm_i2c_aux *aux = NULL; + ret = pad->func->aux_new_6(pad, id, 0, &aux); + if (ret) { + nvkm_error(&i2c->subdev, "dcb %02x aux, %d\n", + i, ret); + nvkm_i2c_aux_del(&aux); + } + } else + if (pad->func->bus_new_4) { + const int id = NVKM_I2C_BUS_EXT(dcbE.extdev); + struct nvkm_i2c_bus *bus = NULL; + ret = pad->func->bus_new_4(pad, id, 0, &bus); + if (ret) { + nvkm_error(&i2c->subdev, "dcb %02x bus, %d\n", + i, ret); + nvkm_i2c_bus_del(&bus); + } } } - ret = nvkm_event_init(&nvkm_i2c_intr_func, 4, index, &i2c->event); + ret = nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c index 861a453d2a675..cdce11bbabe5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c @@ -9,7 +9,7 @@ * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * all copies or substantial busions 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, @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "bus.h" #ifdef CONFIG_NOUVEAU_I2C_INTERNAL #define T_TIMEOUT 2200000 @@ -29,205 +29,188 @@ #define T_HOLD 5000 static inline void -i2c_drive_scl(struct nvkm_i2c_port *port, int state) +nvkm_i2c_drive_scl(struct nvkm_i2c_bus *bus, int state) { - port->func->drive_scl(port, state); + bus->func->drive_scl(bus, state); } static inline void -i2c_drive_sda(struct nvkm_i2c_port *port, int state) +nvkm_i2c_drive_sda(struct nvkm_i2c_bus *bus, int state) { - port->func->drive_sda(port, state); + bus->func->drive_sda(bus, state); } static inline int -i2c_sense_scl(struct nvkm_i2c_port *port) +nvkm_i2c_sense_scl(struct nvkm_i2c_bus *bus) { - return port->func->sense_scl(port); + return bus->func->sense_scl(bus); } static inline int -i2c_sense_sda(struct nvkm_i2c_port *port) +nvkm_i2c_sense_sda(struct nvkm_i2c_bus *bus) { - return port->func->sense_sda(port); + return bus->func->sense_sda(bus); } static void -i2c_delay(struct nvkm_i2c_port *port, u32 nsec) +nvkm_i2c_delay(struct nvkm_i2c_bus *bus, u32 nsec) { udelay((nsec + 500) / 1000); } static bool -i2c_raise_scl(struct nvkm_i2c_port *port) +nvkm_i2c_raise_scl(struct nvkm_i2c_bus *bus) { u32 timeout = T_TIMEOUT / T_RISEFALL; - i2c_drive_scl(port, 1); + nvkm_i2c_drive_scl(bus, 1); do { - i2c_delay(port, T_RISEFALL); - } while (!i2c_sense_scl(port) && --timeout); + nvkm_i2c_delay(bus, T_RISEFALL); + } while (!nvkm_i2c_sense_scl(bus) && --timeout); return timeout != 0; } static int -i2c_start(struct nvkm_i2c_port *port) +i2c_start(struct nvkm_i2c_bus *bus) { int ret = 0; - if (!i2c_sense_scl(port) || - !i2c_sense_sda(port)) { - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 1); - if (!i2c_raise_scl(port)) + if (!nvkm_i2c_sense_scl(bus) || + !nvkm_i2c_sense_sda(bus)) { + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_drive_sda(bus, 1); + if (!nvkm_i2c_raise_scl(bus)) ret = -EBUSY; } - i2c_drive_sda(port, 0); - i2c_delay(port, T_HOLD); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_sda(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); return ret; } static void -i2c_stop(struct nvkm_i2c_port *port) +i2c_stop(struct nvkm_i2c_bus *bus) { - i2c_drive_scl(port, 0); - i2c_drive_sda(port, 0); - i2c_delay(port, T_RISEFALL); - - i2c_drive_scl(port, 1); - i2c_delay(port, T_HOLD); - i2c_drive_sda(port, 1); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_drive_sda(bus, 0); + nvkm_i2c_delay(bus, T_RISEFALL); + + nvkm_i2c_drive_scl(bus, 1); + nvkm_i2c_delay(bus, T_HOLD); + nvkm_i2c_drive_sda(bus, 1); + nvkm_i2c_delay(bus, T_HOLD); } static int -i2c_bitw(struct nvkm_i2c_port *port, int sda) +i2c_bitw(struct nvkm_i2c_bus *bus, int sda) { - i2c_drive_sda(port, sda); - i2c_delay(port, T_RISEFALL); + nvkm_i2c_drive_sda(bus, sda); + nvkm_i2c_delay(bus, T_RISEFALL); - if (!i2c_raise_scl(port)) + if (!nvkm_i2c_raise_scl(bus)) return -ETIMEDOUT; - i2c_delay(port, T_HOLD); + nvkm_i2c_delay(bus, T_HOLD); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); return 0; } static int -i2c_bitr(struct nvkm_i2c_port *port) +i2c_bitr(struct nvkm_i2c_bus *bus) { int sda; - i2c_drive_sda(port, 1); - i2c_delay(port, T_RISEFALL); + nvkm_i2c_drive_sda(bus, 1); + nvkm_i2c_delay(bus, T_RISEFALL); - if (!i2c_raise_scl(port)) + if (!nvkm_i2c_raise_scl(bus)) return -ETIMEDOUT; - i2c_delay(port, T_HOLD); + nvkm_i2c_delay(bus, T_HOLD); - sda = i2c_sense_sda(port); + sda = nvkm_i2c_sense_sda(bus); - i2c_drive_scl(port, 0); - i2c_delay(port, T_HOLD); + nvkm_i2c_drive_scl(bus, 0); + nvkm_i2c_delay(bus, T_HOLD); return sda; } static int -i2c_get_byte(struct nvkm_i2c_port *port, u8 *byte, bool last) +nvkm_i2c_get_byte(struct nvkm_i2c_bus *bus, u8 *byte, bool last) { int i, bit; *byte = 0; for (i = 7; i >= 0; i--) { - bit = i2c_bitr(port); + bit = i2c_bitr(bus); if (bit < 0) return bit; *byte |= bit << i; } - return i2c_bitw(port, last ? 1 : 0); + return i2c_bitw(bus, last ? 1 : 0); } static int -i2c_put_byte(struct nvkm_i2c_port *port, u8 byte) +nvkm_i2c_put_byte(struct nvkm_i2c_bus *bus, u8 byte) { int i, ret; for (i = 7; i >= 0; i--) { - ret = i2c_bitw(port, !!(byte & (1 << i))); + ret = i2c_bitw(bus, !!(byte & (1 << i))); if (ret < 0) return ret; } - ret = i2c_bitr(port); + ret = i2c_bitr(bus); if (ret == 1) /* nack */ ret = -EIO; return ret; } static int -i2c_addr(struct nvkm_i2c_port *port, struct i2c_msg *msg) +i2c_addr(struct nvkm_i2c_bus *bus, struct i2c_msg *msg) { u32 addr = msg->addr << 1; if (msg->flags & I2C_M_RD) addr |= 1; - return i2c_put_byte(port, addr); + return nvkm_i2c_put_byte(bus, addr); } -static int -i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +int +nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *bus, struct i2c_msg *msgs, int num) { - struct nvkm_i2c_port *port = adap->algo_data; struct i2c_msg *msg = msgs; int ret = 0, mcnt = num; - ret = nvkm_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT)); - if (ret) - return ret; - while (!ret && mcnt--) { u8 remaining = msg->len; u8 *ptr = msg->buf; - ret = i2c_start(port); + ret = i2c_start(bus); if (ret == 0) - ret = i2c_addr(port, msg); + ret = i2c_addr(bus, msg); if (msg->flags & I2C_M_RD) { while (!ret && remaining--) - ret = i2c_get_byte(port, ptr++, !remaining); + ret = nvkm_i2c_get_byte(bus, ptr++, !remaining); } else { while (!ret && remaining--) - ret = i2c_put_byte(port, *ptr++); + ret = nvkm_i2c_put_byte(bus, *ptr++); } msg++; } - i2c_stop(port); - nvkm_i2c(port)->release(port); + i2c_stop(bus); return (ret < 0) ? ret : num; } #else -static int -i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +int +nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *bus, struct i2c_msg *msgs, int num) { return -ENODEV; } #endif - -static u32 -i2c_bit_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -const struct i2c_algorithm nvkm_i2c_bit_algo = { - .master_xfer = i2c_bit_xfer, - .functionality = i2c_bit_func -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c new file mode 100644 index 0000000000000..807a2b67bd641 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.c @@ -0,0 +1,245 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "bus.h" +#include "pad.h" + +#include + +/******************************************************************************* + * i2c-algo-bit + ******************************************************************************/ +static int +nvkm_i2c_bus_pre_xfer(struct i2c_adapter *adap) +{ + struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c); + return nvkm_i2c_bus_acquire(bus); +} + +static void +nvkm_i2c_bus_post_xfer(struct i2c_adapter *adap) +{ + struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c); + return nvkm_i2c_bus_release(bus); +} + +static void +nvkm_i2c_bus_setscl(void *data, int state) +{ + struct nvkm_i2c_bus *bus = data; + bus->func->drive_scl(bus, state); +} + +static void +nvkm_i2c_bus_setsda(void *data, int state) +{ + struct nvkm_i2c_bus *bus = data; + bus->func->drive_sda(bus, state); +} + +static int +nvkm_i2c_bus_getscl(void *data) +{ + struct nvkm_i2c_bus *bus = data; + return bus->func->sense_scl(bus); +} + +static int +nvkm_i2c_bus_getsda(void *data) +{ + struct nvkm_i2c_bus *bus = data; + return bus->func->sense_sda(bus); +} + +/******************************************************************************* + * !i2c-algo-bit (off-chip i2c bus / hw i2c / internal bit-banging algo) + ******************************************************************************/ +static int +nvkm_i2c_bus_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nvkm_i2c_bus *bus = container_of(adap, typeof(*bus), i2c); + int ret; + + ret = nvkm_i2c_bus_acquire(bus); + if (ret) + return ret; + + ret = bus->func->xfer(bus, msgs, num); + nvkm_i2c_bus_release(bus); + return ret; +} + +static u32 +nvkm_i2c_bus_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm +nvkm_i2c_bus_algo = { + .master_xfer = nvkm_i2c_bus_xfer, + .functionality = nvkm_i2c_bus_func, +}; + +/******************************************************************************* + * nvkm_i2c_bus base + ******************************************************************************/ +void +nvkm_i2c_bus_init(struct nvkm_i2c_bus *bus) +{ + BUS_TRACE(bus, "init"); + if (bus->func->init) + bus->func->init(bus); +} + +void +nvkm_i2c_bus_release(struct nvkm_i2c_bus *bus) +{ + struct nvkm_i2c_pad *pad = bus->pad; + BUS_TRACE(bus, "release"); + nvkm_i2c_pad_release(pad); + mutex_unlock(&bus->mutex); +} + +int +nvkm_i2c_bus_acquire(struct nvkm_i2c_bus *bus) +{ + struct nvkm_i2c_pad *pad = bus->pad; + int ret; + BUS_TRACE(bus, "acquire"); + mutex_lock(&bus->mutex); + ret = nvkm_i2c_pad_acquire(pad, NVKM_I2C_PAD_I2C); + if (ret) + mutex_unlock(&bus->mutex); + return ret; +} + +int +nvkm_i2c_bus_probe(struct nvkm_i2c_bus *bus, const char *what, + struct nvkm_i2c_bus_probe *info, + bool (*match)(struct nvkm_i2c_bus *, + struct i2c_board_info *, void *), void *data) +{ + int i; + + BUS_DBG(bus, "probing %ss", what); + for (i = 0; info[i].dev.addr; i++) { + u8 orig_udelay = 0; + + if ((bus->i2c.algo == &i2c_bit_algo) && (info[i].udelay != 0)) { + struct i2c_algo_bit_data *algo = bus->i2c.algo_data; + BUS_DBG(bus, "%dms delay instead of %dms", + info[i].udelay, algo->udelay); + orig_udelay = algo->udelay; + algo->udelay = info[i].udelay; + } + + if (nvkm_probe_i2c(&bus->i2c, info[i].dev.addr) && + (!match || match(bus, &info[i].dev, data))) { + BUS_DBG(bus, "detected %s: %s", + what, info[i].dev.type); + return i; + } + + if (orig_udelay) { + struct i2c_algo_bit_data *algo = bus->i2c.algo_data; + algo->udelay = orig_udelay; + } + } + + BUS_DBG(bus, "no devices found."); + return -ENODEV; +} + +void +nvkm_i2c_bus_del(struct nvkm_i2c_bus **pbus) +{ + struct nvkm_i2c_bus *bus = *pbus; + if (bus && !WARN_ON(!bus->func)) { + BUS_TRACE(bus, "dtor"); + list_del(&bus->head); + i2c_del_adapter(&bus->i2c); + kfree(bus->i2c.algo_data); + kfree(*pbus); + *pbus = NULL; + } +} + +int +nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_bus *bus) +{ + struct nvkm_device *device = pad->i2c->subdev.device; + struct i2c_algo_bit_data *bit; +#ifndef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT + const bool internal = false; +#else + const bool internal = true; +#endif + int ret; + + bus->func = func; + bus->pad = pad; + bus->id = id; + mutex_init(&bus->mutex); + list_add_tail(&bus->head, &pad->i2c->bus); + BUS_TRACE(bus, "ctor"); + + snprintf(bus->i2c.name, sizeof(bus->i2c.name), "nvkm-%s-bus-%04x", + dev_name(device->dev), id); + bus->i2c.owner = THIS_MODULE; + bus->i2c.dev.parent = device->dev; + + if ( bus->func->drive_scl && + !nvkm_boolopt(device->cfgopt, "NvI2C", internal)) { + if (!(bit = kzalloc(sizeof(*bit), GFP_KERNEL))) + return -ENOMEM; + bit->udelay = 10; + bit->timeout = usecs_to_jiffies(2200); + bit->data = bus; + bit->pre_xfer = nvkm_i2c_bus_pre_xfer; + bit->post_xfer = nvkm_i2c_bus_post_xfer; + bit->setscl = nvkm_i2c_bus_setscl; + bit->setsda = nvkm_i2c_bus_setsda; + bit->getscl = nvkm_i2c_bus_getscl; + bit->getsda = nvkm_i2c_bus_getsda; + bus->i2c.algo_data = bit; + ret = i2c_bit_add_bus(&bus->i2c); + } else { + bus->i2c.algo = &nvkm_i2c_bus_algo; + ret = i2c_add_adapter(&bus->i2c); + } + + return ret; +} + +int +nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *func, + struct nvkm_i2c_pad *pad, int id, + struct nvkm_i2c_bus **pbus) +{ + if (!(*pbus = kzalloc(sizeof(**pbus), GFP_KERNEL))) + return -ENOMEM; + return nvkm_i2c_bus_ctor(func, pad, id, *pbus); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h new file mode 100644 index 0000000000000..e1be14c23e546 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bus.h @@ -0,0 +1,37 @@ +#ifndef __NVKM_I2C_BUS_H__ +#define __NVKM_I2C_BUS_H__ +#include "pad.h" + +struct nvkm_i2c_bus_func { + void (*init)(struct nvkm_i2c_bus *); + void (*drive_scl)(struct nvkm_i2c_bus *, int state); + void (*drive_sda)(struct nvkm_i2c_bus *, int state); + int (*sense_scl)(struct nvkm_i2c_bus *); + int (*sense_sda)(struct nvkm_i2c_bus *); + int (*xfer)(struct nvkm_i2c_bus *, struct i2c_msg *, int num); +}; + +int nvkm_i2c_bus_ctor(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_bus *); +int nvkm_i2c_bus_new_(const struct nvkm_i2c_bus_func *, struct nvkm_i2c_pad *, + int id, struct nvkm_i2c_bus **); +void nvkm_i2c_bus_del(struct nvkm_i2c_bus **); +void nvkm_i2c_bus_init(struct nvkm_i2c_bus *); + +int nvkm_i2c_bit_xfer(struct nvkm_i2c_bus *, struct i2c_msg *, int); + +int nv04_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, u8, + struct nvkm_i2c_bus **); + +int nv4e_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **); +int nv50_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **); +int gf119_i2c_bus_new(struct nvkm_i2c_pad *, int, u8, struct nvkm_i2c_bus **); + +#define BUS_MSG(b,l,f,a...) do { \ + struct nvkm_i2c_bus *_bus = (b); \ + nvkm_##l(&_bus->pad->i2c->subdev, "bus %04x: "f"\n", _bus->id, ##a); \ +} while(0) +#define BUS_ERR(b,f,a...) BUS_MSG((b), error, f, ##a) +#define BUS_DBG(b,f,a...) BUS_MSG((b), debug, f, ##a) +#define BUS_TRACE(b,f,a...) BUS_MSG((b), trace, f, ##a) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c new file mode 100644 index 0000000000000..96bbdda0f4392 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busgf119.c @@ -0,0 +1,95 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 shall be included in + * all copies or substantial busions 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define gf119_i2c_bus(p) container_of((p), struct gf119_i2c_bus, base) +#include "bus.h" + +struct gf119_i2c_bus { + struct nvkm_i2c_bus base; + u32 addr; +}; + +static void +gf119_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x00000001, state ? 0x00000001 : 0); +} + +static void +gf119_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x00000002, state ? 0x00000002 : 0); +} + +static int +gf119_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000010); +} + +static int +gf119_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000020); +} + +static void +gf119_i2c_bus_init(struct nvkm_i2c_bus *base) +{ + struct gf119_i2c_bus *bus = gf119_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_wr32(device, bus->addr, 0x00000007); +} + +static const struct nvkm_i2c_bus_func +gf119_i2c_bus_func = { + .init = gf119_i2c_bus_init, + .drive_scl = gf119_i2c_bus_drive_scl, + .drive_sda = gf119_i2c_bus_drive_sda, + .sense_scl = gf119_i2c_bus_sense_scl, + .sense_sda = gf119_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +gf119_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + struct gf119_i2c_bus *bus; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&gf119_i2c_bus_func, pad, id, &bus->base); + bus->addr = 0x00d014 + (drive * 0x20); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c new file mode 100644 index 0000000000000..a58db159231f2 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv04.c @@ -0,0 +1,96 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 shall be included in + * all copies or substantial busions 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define nv04_i2c_bus(p) container_of((p), struct nv04_i2c_bus, base) +#include "bus.h" + +#include + +struct nv04_i2c_bus { + struct nvkm_i2c_bus base; + u8 drive; + u8 sense; +}; + +static void +nv04_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + u8 val = nvkm_rdvgac(device, 0, bus->drive); + if (state) val |= 0x20; + else val &= 0xdf; + nvkm_wrvgac(device, 0, bus->drive, val | 0x01); +} + +static void +nv04_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + u8 val = nvkm_rdvgac(device, 0, bus->drive); + if (state) val |= 0x10; + else val &= 0xef; + nvkm_wrvgac(device, 0, bus->drive, val | 0x01); +} + +static int +nv04_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rdvgac(device, 0, bus->sense) & 0x04); +} + +static int +nv04_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct nv04_i2c_bus *bus = nv04_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rdvgac(device, 0, bus->sense) & 0x08); +} + +static const struct nvkm_i2c_bus_func +nv04_i2c_bus_func = { + .drive_scl = nv04_i2c_bus_drive_scl, + .drive_sda = nv04_i2c_bus_drive_sda, + .sense_scl = nv04_i2c_bus_sense_scl, + .sense_sda = nv04_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +nv04_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, u8 sense, + struct nvkm_i2c_bus **pbus) +{ + struct nv04_i2c_bus *bus; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&nv04_i2c_bus_func, pad, id, &bus->base); + bus->drive = drive; + bus->sense = sense; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c new file mode 100644 index 0000000000000..cdd73dcb11977 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv4e.c @@ -0,0 +1,86 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 shall be included in + * all copies or substantial busions 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define nv4e_i2c_bus(p) container_of((p), struct nv4e_i2c_bus, base) +#include "bus.h" + +struct nv4e_i2c_bus { + struct nvkm_i2c_bus base; + u32 addr; +}; + +static void +nv4e_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x2f, state ? 0x21 : 0x01); +} + +static void +nv4e_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_mask(device, bus->addr, 0x1f, state ? 0x11 : 0x01); +} + +static int +nv4e_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00040000); +} + +static int +nv4e_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct nv4e_i2c_bus *bus = nv4e_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00080000); +} + +static const struct nvkm_i2c_bus_func +nv4e_i2c_bus_func = { + .drive_scl = nv4e_i2c_bus_drive_scl, + .drive_sda = nv4e_i2c_bus_drive_sda, + .sense_scl = nv4e_i2c_bus_sense_scl, + .sense_sda = nv4e_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +nv4e_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + struct nv4e_i2c_bus *bus; + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&nv4e_i2c_bus_func, pad, id, &bus->base); + bus->addr = 0x600800 + drive; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c new file mode 100644 index 0000000000000..8db8399381ca8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/busnv50.c @@ -0,0 +1,113 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 shall be included in + * all copies or substantial busions 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define nv50_i2c_bus(p) container_of((p), struct nv50_i2c_bus, base) +#include "bus.h" + +#include + +struct nv50_i2c_bus { + struct nvkm_i2c_bus base; + u32 addr; + u32 data; +}; + +static void +nv50_i2c_bus_drive_scl(struct nvkm_i2c_bus *base, int state) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + if (state) bus->data |= 0x01; + else bus->data &= 0xfe; + nvkm_wr32(device, bus->addr, bus->data); +} + +static void +nv50_i2c_bus_drive_sda(struct nvkm_i2c_bus *base, int state) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + if (state) bus->data |= 0x02; + else bus->data &= 0xfd; + nvkm_wr32(device, bus->addr, bus->data); +} + +static int +nv50_i2c_bus_sense_scl(struct nvkm_i2c_bus *base) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000001); +} + +static int +nv50_i2c_bus_sense_sda(struct nvkm_i2c_bus *base) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + return !!(nvkm_rd32(device, bus->addr) & 0x00000002); +} + +static void +nv50_i2c_bus_init(struct nvkm_i2c_bus *base) +{ + struct nv50_i2c_bus *bus = nv50_i2c_bus(base); + struct nvkm_device *device = bus->base.pad->i2c->subdev.device; + nvkm_wr32(device, bus->addr, (bus->data = 0x00000007)); +} + +static const struct nvkm_i2c_bus_func +nv50_i2c_bus_func = { + .init = nv50_i2c_bus_init, + .drive_scl = nv50_i2c_bus_drive_scl, + .drive_sda = nv50_i2c_bus_drive_sda, + .sense_scl = nv50_i2c_bus_sense_scl, + .sense_sda = nv50_i2c_bus_sense_sda, + .xfer = nvkm_i2c_bit_xfer, +}; + +int +nv50_i2c_bus_new(struct nvkm_i2c_pad *pad, int id, u8 drive, + struct nvkm_i2c_bus **pbus) +{ + static const u32 addr[] = { + 0x00e138, 0x00e150, 0x00e168, 0x00e180, + 0x00e254, 0x00e274, 0x00e764, 0x00e780, + 0x00e79c, 0x00e7b8 + }; + struct nv50_i2c_bus *bus; + + if (drive >= ARRAY_SIZE(addr)) { + nvkm_warn(&pad->i2c->subdev, "bus %d unknown\n", drive); + return -ENODEV; + } + + if (!(bus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + *pbus = &bus->base; + + nvkm_i2c_bus_ctor(&nv50_i2c_bus_func, pad, id, &bus->base); + bus->addr = addr[drive]; + bus->data = 0x00000007; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c index acbfbe0a7ea91..e18dc855f21b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "priv.h" +#include "pad.h" void g94_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) @@ -55,219 +56,6 @@ g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00e068, temp); } -#define AUX_DBG(fmt, args...) \ - nvkm_debug(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) \ - nvkm_error(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) - -static void -auxch_fini(struct nvkm_i2c *i2c, int ch) -{ - struct nvkm_device *device = i2c->subdev.device; - nvkm_mask(device, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000); -} - -static int -auxch_init(struct nvkm_i2c *i2c, int ch) -{ - struct nvkm_device *device = i2c->subdev.device; - const u32 unksel = 1; /* nfi which to use, or if it matters.. */ - const u32 ureq = unksel ? 0x00100000 : 0x00200000; - const u32 urep = unksel ? 0x01000000 : 0x02000000; - u32 ctrl, timeout; - - /* wait up to 1ms for any previous transaction to be done... */ - timeout = 1000; - do { - ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("begin idle timeout %08x\n", ctrl); - return -EBUSY; - } - } while (ctrl & 0x03010000); - - /* set some magic, and wait up to 1ms for it to appear */ - nvkm_mask(device, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq); - timeout = 1000; - do { - ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("magic wait %08x\n", ctrl); - auxch_fini(i2c, ch); - return -EBUSY; - } - } while ((ctrl & 0x03000000) != urep); - - return 0; -} - -int -g94_aux(struct nvkm_i2c_port *base, bool retry, - u8 type, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *i2c = nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - u32 ctrl, stat, timeout, retries; - u32 xbuf[4] = {}; - int ch = port->addr; - int ret, i; - - AUX_DBG("%d: %08x %d\n", type, addr, size); - - ret = auxch_init(i2c, ch); - if (ret < 0) - goto out; - - stat = nvkm_rd32(device, 0x00e4e8 + (ch * 0x50)); - if (!(stat & 0x10000000)) { - AUX_DBG("sink not detected\n"); - ret = -ENXIO; - goto out; - } - - if (!(type & 1)) { - memcpy(xbuf, data, size); - for (i = 0; i < 16; i += 4) { - AUX_DBG("wr %08x\n", xbuf[i / 4]); - nvkm_wr32(device, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]); - } - } - - ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); - ctrl &= ~0x0001f0ff; - ctrl |= type << 12; - ctrl |= size - 1; - nvkm_wr32(device, 0x00e4e0 + (ch * 0x50), addr); - - /* (maybe) retry transaction a number of times on failure... */ - for (retries = 0; !ret && retries < 32; retries++) { - /* reset, and delay a while if this is a retry */ - nvkm_wr32(device, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl); - nvkm_wr32(device, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl); - if (retries) - udelay(400); - - /* transaction request, wait up to 1ms for it to complete */ - nvkm_wr32(device, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl); - - timeout = 1000; - do { - ctrl = nvkm_rd32(device, 0x00e4e4 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("tx req timeout %08x\n", ctrl); - ret = -EIO; - goto out; - } - } while (ctrl & 0x00010000); - ret = 1; - - /* read status, and check if transaction completed ok */ - stat = nvkm_mask(device, 0x00e4e8 + (ch * 0x50), 0, 0); - if ((stat & 0x000f0000) == 0x00080000 || - (stat & 0x000f0000) == 0x00020000) - ret = retry ? 0 : 1; - if ((stat & 0x00000100)) - ret = -ETIMEDOUT; - if ((stat & 0x00000e00)) - ret = -EIO; - - AUX_DBG("%02d %08x %08x\n", retries, ctrl, stat); - } - - if (type & 1) { - for (i = 0; i < 16; i += 4) { - xbuf[i / 4] = nvkm_rd32(device, 0x00e4d0 + (ch * 0x50) + i); - AUX_DBG("rd %08x\n", xbuf[i / 4]); - } - memcpy(data, xbuf, size); - } - -out: - auxch_fini(i2c, ch); - return ret < 0 ? ret : (stat & 0x000f0000) >> 16; -} - -static const struct nvkm_i2c_func -g94_i2c_func = { - .drive_scl = nv50_i2c_drive_scl, - .drive_sda = nv50_i2c_drive_sda, - .sense_scl = nv50_i2c_sense_scl, - .sense_sda = nv50_i2c_sense_sda, -}; - -static int -g94_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &g94_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - if (info->drive >= nv50_i2c_addr_nr) - return -EINVAL; - - port->state = 7; - port->addr = nv50_i2c_addr[info->drive]; - return 0; -} - -static const struct nvkm_i2c_func -g94_aux_func = { - .aux = g94_aux, -}; - -int -g94_aux_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_aux_algo, &g94_aux_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->base.aux = info->auxch; - port->addr = info->auxch; - return 0; -} - -static struct nvkm_oclass -g94_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_aux_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; - struct nvkm_oclass * g94_i2c_oclass = &(struct nvkm_i2c_impl) { .base.handle = NV_SUBDEV(I2C, 0x94), @@ -277,9 +65,8 @@ g94_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = g94_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &g94_i2c_pad_oclass, + .pad_x_new = g94_i2c_pad_x_new, + .pad_s_new = g94_i2c_pad_s_new, .aux = 4, .aux_stat = g94_aux_stat, .aux_mask = g94_aux_mask, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c index 6795e5c28b064..cb6774ae24872 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c @@ -21,74 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" - -static int -gf110_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - return !!(nvkm_rd32(device, port->addr) & 0x00000010); -} - -static int -gf110_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - return !!(nvkm_rd32(device, port->addr) & 0x00000020); -} - -static const struct nvkm_i2c_func -gf110_i2c_func = { - .drive_scl = nv50_i2c_drive_scl, - .drive_sda = nv50_i2c_drive_sda, - .sense_scl = gf110_i2c_sense_scl, - .sense_sda = gf110_i2c_sense_sda, -}; - -int -gf110_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &gf110_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->state = 0x00000007; - port->addr = 0x00d014 + (info->drive * 0x20); - return 0; -} - -struct nvkm_oclass -gf110_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_aux_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; +#include "priv.h" +#include "pad.h" struct nvkm_oclass * gf110_i2c_oclass = &(struct nvkm_i2c_impl) { @@ -99,9 +33,8 @@ gf110_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = gf110_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &g94_i2c_pad_oclass, + .pad_x_new = gf119_i2c_pad_x_new, + .pad_s_new = gf119_i2c_pad_s_new, .aux = 4, .aux_stat = g94_aux_stat, .aux_mask = g94_aux_mask, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c index e290b40f2d131..bd5e7c987cf06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "priv.h" +#include "pad.h" struct nvkm_oclass * gf117_i2c_oclass = &(struct nvkm_i2c_impl) { @@ -32,7 +33,5 @@ gf117_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = gf110_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &nv04_i2c_pad_oclass, + .pad_x_new = gf119_i2c_pad_x_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c index 9573fdb769b53..ac97c20693931 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" +#include "priv.h" +#include "pad.h" void gk104_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx) @@ -64,9 +65,8 @@ gk104_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = gf110_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &g94_i2c_pad_oclass, + .pad_x_new = gf119_i2c_pad_x_new, + .pad_s_new = gf119_i2c_pad_s_new, .aux = 4, .aux_stat = gk104_aux_stat, .aux_mask = gk104_aux_mask, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c index f027aedb7361a..e84b9a4aadc75 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c @@ -21,190 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" - -#define AUX_DBG(fmt, args...) \ - nvkm_debug(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) -#define AUX_ERR(fmt, args...) \ - nvkm_error(&i2c->subdev, "AUXCH(%d): " fmt, ch, ##args) - -static void -auxch_fini(struct nvkm_i2c *i2c, int ch) -{ - struct nvkm_device *device = i2c->subdev.device; - nvkm_mask(device, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000); -} - -static int -auxch_init(struct nvkm_i2c *i2c, int ch) -{ - struct nvkm_device *device = i2c->subdev.device; - const u32 unksel = 1; /* nfi which to use, or if it matters.. */ - const u32 ureq = unksel ? 0x00100000 : 0x00200000; - const u32 urep = unksel ? 0x01000000 : 0x02000000; - u32 ctrl, timeout; - - /* wait up to 1ms for any previous transaction to be done... */ - timeout = 1000; - do { - ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("begin idle timeout %08x\n", ctrl); - return -EBUSY; - } - } while (ctrl & 0x03010000); - - /* set some magic, and wait up to 1ms for it to appear */ - nvkm_mask(device, 0x00d954 + (ch * 0x50), 0x00300000, ureq); - timeout = 1000; - do { - ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("magic wait %08x\n", ctrl); - auxch_fini(i2c, ch); - return -EBUSY; - } - } while ((ctrl & 0x03000000) != urep); - - return 0; -} - -int -gm204_aux(struct nvkm_i2c_port *base, bool retry, - u8 type, u32 addr, u8 *data, u8 size) -{ - struct nvkm_i2c *i2c = nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - u32 ctrl, stat, timeout, retries; - u32 xbuf[4] = {}; - int ch = port->addr; - int ret, i; - - AUX_DBG("%d: %08x %d\n", type, addr, size); - - ret = auxch_init(i2c, ch); - if (ret < 0) - goto out; - - stat = nvkm_rd32(device, 0x00d958 + (ch * 0x50)); - if (!(stat & 0x10000000)) { - AUX_DBG("sink not detected\n"); - ret = -ENXIO; - goto out; - } - - if (!(type & 1)) { - memcpy(xbuf, data, size); - for (i = 0; i < 16; i += 4) { - AUX_DBG("wr %08x\n", xbuf[i / 4]); - nvkm_wr32(device, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]); - } - } - - ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); - ctrl &= ~0x0001f0ff; - ctrl |= type << 12; - ctrl |= size - 1; - nvkm_wr32(device, 0x00d950 + (ch * 0x50), addr); - - /* (maybe) retry transaction a number of times on failure... */ - for (retries = 0; !ret && retries < 32; retries++) { - /* reset, and delay a while if this is a retry */ - nvkm_wr32(device, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl); - nvkm_wr32(device, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl); - if (retries) - udelay(400); - - /* transaction request, wait up to 1ms for it to complete */ - nvkm_wr32(device, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl); - - timeout = 1000; - do { - ctrl = nvkm_rd32(device, 0x00d954 + (ch * 0x50)); - udelay(1); - if (!timeout--) { - AUX_ERR("tx req timeout %08x\n", ctrl); - ret = -EIO; - goto out; - } - } while (ctrl & 0x00010000); - ret = 1; - - /* read status, and check if transaction completed ok */ - stat = nvkm_mask(device, 0x00d958 + (ch * 0x50), 0, 0); - if ((stat & 0x000f0000) == 0x00080000 || - (stat & 0x000f0000) == 0x00020000) - ret = retry ? 0 : 1; - if ((stat & 0x00000100)) - ret = -ETIMEDOUT; - if ((stat & 0x00000e00)) - ret = -EIO; - - AUX_DBG("%02d %08x %08x\n", retries, ctrl, stat); - } - - if (type & 1) { - for (i = 0; i < 16; i += 4) { - xbuf[i / 4] = nvkm_rd32(device, 0x00d940 + (ch * 0x50) + i); - AUX_DBG("rd %08x\n", xbuf[i / 4]); - } - memcpy(data, xbuf, size); - } - -out: - auxch_fini(i2c, ch); - return ret < 0 ? ret : (stat & 0x000f0000) >> 16; -} - -static const struct nvkm_i2c_func -gm204_aux_func = { - .aux = gm204_aux, -}; - -int -gm204_aux_port_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_aux_algo, &gm204_aux_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->base.aux = info->auxch; - port->addr = info->auxch; - return 0; -} - -struct nvkm_oclass -gm204_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_aux_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; +#include "priv.h" +#include "pad.h" struct nvkm_oclass * gm204_i2c_oclass = &(struct nvkm_i2c_impl) { @@ -215,9 +33,8 @@ gm204_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = gm204_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, - .pad_s = &gm204_i2c_pad_oclass, + .pad_x_new = gf119_i2c_pad_x_new, + .pad_s_new = gm204_i2c_pad_s_new, .aux = 8, .aux_stat = gk104_aux_stat, .aux_mask = gk104_aux_mask, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c index e76c555d4d0e1..9a7279f3ae390 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c @@ -22,93 +22,7 @@ * Authors: Ben Skeggs */ #include "priv.h" - -#include - -struct nv04_i2c_port { - struct nvkm_i2c_port base; - u8 drive; - u8 sense; -}; - -static void -nv04_i2c_drive_scl(struct nvkm_i2c_port *base, int state) -{ - struct nvkm_device *device = nvkm_i2c(base)->subdev.device; - struct nv04_i2c_port *port = (void *)base; - u8 val = nvkm_rdvgac(device, 0, port->drive); - if (state) val |= 0x20; - else val &= 0xdf; - nvkm_wrvgac(device, 0, port->drive, val | 0x01); -} - -static void -nv04_i2c_drive_sda(struct nvkm_i2c_port *base, int state) -{ - struct nvkm_device *device = nvkm_i2c(base)->subdev.device; - struct nv04_i2c_port *port = (void *)base; - u8 val = nvkm_rdvgac(device, 0, port->drive); - if (state) val |= 0x10; - else val &= 0xef; - nvkm_wrvgac(device, 0, port->drive, val | 0x01); -} - -static int -nv04_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nvkm_device *device = nvkm_i2c(base)->subdev.device; - struct nv04_i2c_port *port = (void *)base; - return !!(nvkm_rdvgac(device, 0, port->sense) & 0x04); -} - -static int -nv04_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nvkm_device *device = nvkm_i2c(base)->subdev.device; - struct nv04_i2c_port *port = (void *)base; - return !!(nvkm_rdvgac(device, 0, port->sense) & 0x08); -} - -static const struct nvkm_i2c_func -nv04_i2c_func = { - .drive_scl = nv04_i2c_drive_scl, - .drive_sda = nv04_i2c_drive_sda, - .sense_scl = nv04_i2c_sense_scl, - .sense_sda = nv04_i2c_sense_sda, -}; - -static int -nv04_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv04_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &nv04_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->drive = info->drive; - port->sense = info->sense; - return 0; -} - -static struct nvkm_oclass -nv04_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; +#include "pad.h" struct nvkm_oclass * nv04_i2c_oclass = &(struct nvkm_i2c_impl) { @@ -119,6 +33,5 @@ nv04_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = nv04_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, + .pad_x_new = nv04_i2c_pad_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c index 24edcdbca3de2..40533d7868941 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c @@ -22,89 +22,7 @@ * Authors: Ben Skeggs */ #include "priv.h" - -#include - -struct nv4e_i2c_port { - struct nvkm_i2c_port base; - u32 addr; -}; - -static void -nv4e_i2c_drive_scl(struct nvkm_i2c_port *base, int state) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv4e_i2c_port *port = (void *)base; - nvkm_mask(device, port->addr, 0x2f, state ? 0x21 : 0x01); -} - -static void -nv4e_i2c_drive_sda(struct nvkm_i2c_port *base, int state) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv4e_i2c_port *port = (void *)base; - nvkm_mask(device, port->addr, 0x1f, state ? 0x11 : 0x01); -} - -static int -nv4e_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv4e_i2c_port *port = (void *)base; - return !!(nvkm_rd32(device, port->addr) & 0x00040000); -} - -static int -nv4e_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv4e_i2c_port *port = (void *)base; - return !!(nvkm_rd32(device, port->addr) & 0x00080000); -} - -static const struct nvkm_i2c_func -nv4e_i2c_func = { - .drive_scl = nv4e_i2c_drive_scl, - .drive_sda = nv4e_i2c_drive_sda, - .sense_scl = nv4e_i2c_sense_scl, - .sense_sda = nv4e_i2c_sense_sda, -}; - -static int -nv4e_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv4e_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &nv4e_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - port->addr = 0x600800 + info->drive; - return 0; -} - -static struct nvkm_oclass -nv4e_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv4e_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = _nvkm_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; +#include "pad.h" struct nvkm_oclass * nv4e_i2c_oclass = &(struct nvkm_i2c_impl) { @@ -115,6 +33,5 @@ nv4e_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = nv4e_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, + .pad_x_new = nv4e_i2c_pad_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c index 6c04fe0088370..678585c44cb02 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c @@ -21,108 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" - -void -nv50_i2c_drive_scl(struct nvkm_i2c_port *base, int state) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - if (state) port->state |= 0x01; - else port->state &= 0xfe; - nvkm_wr32(device, port->addr, port->state); -} - -void -nv50_i2c_drive_sda(struct nvkm_i2c_port *base, int state) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - if (state) port->state |= 0x02; - else port->state &= 0xfd; - nvkm_wr32(device, port->addr, port->state); -} - -int -nv50_i2c_sense_scl(struct nvkm_i2c_port *base) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - return !!(nvkm_rd32(device, port->addr) & 0x00000001); -} - -int -nv50_i2c_sense_sda(struct nvkm_i2c_port *base) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(base); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)base; - return !!(nvkm_rd32(device, port->addr) & 0x00000002); -} - -static const struct nvkm_i2c_func -nv50_i2c_func = { - .drive_scl = nv50_i2c_drive_scl, - .drive_sda = nv50_i2c_drive_sda, - .sense_scl = nv50_i2c_sense_scl, - .sense_sda = nv50_i2c_sense_sda, -}; - -const u32 nv50_i2c_addr[] = { - 0x00e138, 0x00e150, 0x00e168, 0x00e180, - 0x00e254, 0x00e274, 0x00e764, 0x00e780, - 0x00e79c, 0x00e7b8 -}; -const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr); - -static int -nv50_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct dcb_i2c_entry *info = data; - struct nv50_i2c_port *port; - int ret; - - ret = nvkm_i2c_port_create(parent, engine, oclass, index, - &nvkm_i2c_bit_algo, &nv50_i2c_func, &port); - *pobject = nv_object(port); - if (ret) - return ret; - - if (info->drive >= nv50_i2c_addr_nr) - return -EINVAL; - - port->state = 0x00000007; - port->addr = nv50_i2c_addr[info->drive]; - return 0; -} - -int -nv50_i2c_port_init(struct nvkm_object *object) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct nvkm_device *device = i2c->subdev.device; - struct nv50_i2c_port *port = (void *)object; - nvkm_wr32(device, port->addr, port->state); - return nvkm_i2c_port_init(&port->base); -} - -static struct nvkm_oclass -nv50_i2c_sclass[] = { - { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_i2c_port_ctor, - .dtor = _nvkm_i2c_port_dtor, - .init = nv50_i2c_port_init, - .fini = _nvkm_i2c_port_fini, - }, - }, - {} -}; +#include "priv.h" +#include "pad.h" struct nvkm_oclass * nv50_i2c_oclass = &(struct nvkm_i2c_impl) { @@ -133,6 +33,5 @@ nv50_i2c_oclass = &(struct nvkm_i2c_impl) { .init = _nvkm_i2c_init, .fini = _nvkm_i2c_fini, }, - .sclass = nv50_i2c_sclass, - .pad_x = &nv04_i2c_pad_oclass, + .pad_x_new = nv50_i2c_pad_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h deleted file mode 100644 index 520bafbf1a70e..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NV50_I2C_H__ -#define __NV50_I2C_H__ -#include "priv.h" - -struct nv50_i2c_port { - struct nvkm_i2c_port base; - u32 addr; - u32 state; -}; - -extern const u32 nv50_i2c_addr[]; -extern const int nv50_i2c_addr_nr; -int nv50_i2c_port_init(struct nvkm_object *); -int nv50_i2c_sense_scl(struct nvkm_i2c_port *); -int nv50_i2c_sense_sda(struct nvkm_i2c_port *); -void nv50_i2c_drive_scl(struct nvkm_i2c_port *, int state); -void nv50_i2c_drive_sda(struct nvkm_i2c_port *, int state); - -int g94_aux_port_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void g94_i2c_acquire(struct nvkm_i2c_port *); -void g94_i2c_release(struct nvkm_i2c_port *); - -int gf110_i2c_port_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c index a242eeb678297..2c5fcb9c504b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c @@ -1,5 +1,5 @@ /* - * Copyright 2014 Red Hat Inc. + * Copyright 2015 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -19,65 +19,98 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * - * Authors: Ben Skeggs + * Authors: Ben Skeggs */ #include "pad.h" -int -_nvkm_i2c_pad_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_i2c_pad_mode_locked(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c_pad *pad = (void *)object; - DBG("-> NULL\n"); - pad->port = NULL; - return nvkm_object_fini(&pad->base, suspend); + PAD_TRACE(pad, "-> %s", (mode == NVKM_I2C_PAD_AUX) ? "aux" : + (mode == NVKM_I2C_PAD_I2C) ? "i2c" : "off"); + if (pad->func->mode) + pad->func->mode(pad, mode); } -int -_nvkm_i2c_pad_init(struct nvkm_object *object) +void +nvkm_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c_pad *pad = (void *)object; - DBG("-> PORT:%02x\n", pad->next->index); - pad->port = pad->next; - return nvkm_object_init(&pad->base); + PAD_TRACE(pad, "mode %d", mode); + mutex_lock(&pad->mutex); + nvkm_i2c_pad_mode_locked(pad, mode); + pad->mode = mode; + mutex_unlock(&pad->mutex); } -int -nvkm_i2c_pad_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int index, - int size, void **pobject) +void +nvkm_i2c_pad_release(struct nvkm_i2c_pad *pad) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_i2c_port *port; - struct nvkm_i2c_pad *pad; - int ret; + PAD_TRACE(pad, "release"); + if (pad->mode == NVKM_I2C_PAD_OFF) + nvkm_i2c_pad_mode_locked(pad, pad->mode); + mutex_unlock(&pad->mutex); +} - list_for_each_entry(port, &i2c->ports, head) { - pad = nvkm_i2c_pad(port); - if (pad->index == index) { - atomic_inc(&nv_object(pad)->refcount); - *pobject = pad; - return 1; +int +nvkm_i2c_pad_acquire(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) +{ + PAD_TRACE(pad, "acquire"); + mutex_lock(&pad->mutex); + if (pad->mode != mode) { + if (pad->mode != NVKM_I2C_PAD_OFF) { + mutex_unlock(&pad->mutex); + return -EBUSY; } + nvkm_i2c_pad_mode_locked(pad, mode); } + return 0; +} + +void +nvkm_i2c_pad_fini(struct nvkm_i2c_pad *pad) +{ + PAD_TRACE(pad, "fini"); + nvkm_i2c_pad_mode_locked(pad, NVKM_I2C_PAD_OFF); +} - ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject); - pad = *pobject; - if (ret) - return ret; +void +nvkm_i2c_pad_init(struct nvkm_i2c_pad *pad) +{ + PAD_TRACE(pad, "init"); + nvkm_i2c_pad_mode_locked(pad, pad->mode); +} - pad->index = index; - return 0; +void +nvkm_i2c_pad_del(struct nvkm_i2c_pad **ppad) +{ + struct nvkm_i2c_pad *pad = *ppad; + if (pad) { + PAD_TRACE(pad, "dtor"); + list_del(&pad->head); + kfree(pad); + pad = NULL; + } +} + +void +nvkm_i2c_pad_ctor(const struct nvkm_i2c_pad_func *func, struct nvkm_i2c *i2c, + int id, struct nvkm_i2c_pad *pad) +{ + pad->func = func; + pad->i2c = i2c; + pad->id = id; + pad->mode = NVKM_I2C_PAD_OFF; + mutex_init(&pad->mutex); + list_add_tail(&pad->head, &i2c->pad); + PAD_TRACE(pad, "ctor"); } int -_nvkm_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) +nvkm_i2c_pad_new_(const struct nvkm_i2c_pad_func *func, struct nvkm_i2c *i2c, + int id, struct nvkm_i2c_pad **ppad) { - struct nvkm_i2c_pad *pad; - int ret; - ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); - *pobject = nv_object(pad); - return ret; + if (!(*ppad = kzalloc(sizeof(**ppad), GFP_KERNEL))) + return -ENOMEM; + nvkm_i2c_pad_ctor(func, i2c, id, *ppad); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h index 577b18ecf5c67..9eeb992944c69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h @@ -1,58 +1,67 @@ #ifndef __NVKM_I2C_PAD_H__ #define __NVKM_I2C_PAD_H__ -#include "priv.h" +#include struct nvkm_i2c_pad { - struct nvkm_object base; - int index; - struct nvkm_i2c_port *port; - struct nvkm_i2c_port *next; + const struct nvkm_i2c_pad_func *func; + struct nvkm_i2c *i2c; +#define NVKM_I2C_PAD_HYBRID(n) /* 'n' is hw pad index */ (n) +#define NVKM_I2C_PAD_CCB(n) /* 'n' is ccb index */ ((n) + 0x100) +#define NVKM_I2C_PAD_EXT(n) /* 'n' is dcb external encoder type */ ((n) + 0x200) + int id; + + enum nvkm_i2c_pad_mode { + NVKM_I2C_PAD_OFF, + NVKM_I2C_PAD_I2C, + NVKM_I2C_PAD_AUX, + } mode; + struct mutex mutex; + struct list_head head; +}; + +struct nvkm_i2c_pad_func { + int (*bus_new_0)(struct nvkm_i2c_pad *, int id, u8 drive, u8 sense, + struct nvkm_i2c_bus **); + int (*bus_new_4)(struct nvkm_i2c_pad *, int id, u8 drive, + struct nvkm_i2c_bus **); + + int (*aux_new_6)(struct nvkm_i2c_pad *, int id, u8 drive, + struct nvkm_i2c_aux **); + + void (*mode)(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); }; -static inline struct nvkm_i2c_pad * -nvkm_i2c_pad(struct nvkm_i2c_port *port) -{ - struct nvkm_object *pad = nv_object(port); - while (!nv_iclass(pad->parent, NV_SUBDEV_CLASS)) - pad = pad->parent; - return (void *)pad; -} - -#define nvkm_i2c_pad_create(p,e,o,i,d) \ - nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d) -#define nvkm_i2c_pad_destroy(p) ({ \ - struct nvkm_i2c_pad *_p = (p); \ - _nvkm_i2c_pad_dtor(nv_object(_p)); \ -}) -#define nvkm_i2c_pad_init(p) ({ \ - struct nvkm_i2c_pad *_p = (p); \ - _nvkm_i2c_pad_init(nv_object(_p)); \ -}) -#define nvkm_i2c_pad_fini(p,s) ({ \ - struct nvkm_i2c_pad *_p = (p); \ - _nvkm_i2c_pad_fini(nv_object(_p), (s)); \ -}) - -int nvkm_i2c_pad_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int index, int, void **); - -int _nvkm_i2c_pad_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_i2c_pad_dtor nvkm_object_destroy -int _nvkm_i2c_pad_init(struct nvkm_object *); -int _nvkm_i2c_pad_fini(struct nvkm_object *, bool); - -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_i2c_pad *_pad = (void *)pad; \ - struct nvkm_i2c *_i2c = nvkm_i2c(_pad); \ - nvkm_##l(&_i2c->subdev, "PAD:%c:%02x: "f, \ - _pad->index >= 0x100 ? 'X' : 'S', \ - _pad->index >= 0x100 ? \ - _pad->index - 0x100 : _pad->index, ##a); \ +void nvkm_i2c_pad_ctor(const struct nvkm_i2c_pad_func *, struct nvkm_i2c *, + int id, struct nvkm_i2c_pad *); +int nvkm_i2c_pad_new_(const struct nvkm_i2c_pad_func *, struct nvkm_i2c *, + int id, struct nvkm_i2c_pad **); +void nvkm_i2c_pad_del(struct nvkm_i2c_pad **); +void nvkm_i2c_pad_init(struct nvkm_i2c_pad *); +void nvkm_i2c_pad_fini(struct nvkm_i2c_pad *); +void nvkm_i2c_pad_mode(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); +int nvkm_i2c_pad_acquire(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); +void nvkm_i2c_pad_release(struct nvkm_i2c_pad *); + +void g94_i2c_pad_mode(struct nvkm_i2c_pad *, enum nvkm_i2c_pad_mode); + +int nv04_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int nv4e_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int nv50_i2c_pad_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int g94_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gf119_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gm204_i2c_pad_x_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); + +int g94_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gf119_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); +int gm204_i2c_pad_s_new(struct nvkm_i2c *, int, struct nvkm_i2c_pad **); + +int anx9805_pad_new(struct nvkm_i2c_bus *, int, u8, struct nvkm_i2c_pad **); + +#define PAD_MSG(p,l,f,a...) do { \ + struct nvkm_i2c_pad *_pad = (p); \ + nvkm_##l(&_pad->i2c->subdev, "pad %04x: "f"\n", _pad->id, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define PAD_ERR(p,f,a...) PAD_MSG((p), error, f, ##a) +#define PAD_DBG(p,f,a...) PAD_MSG((p), debug, f, ##a) +#define PAD_TRACE(p,f,a...) PAD_MSG((p), trace, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c index 2e5f6da97f094..5904bc5f2d2a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c @@ -22,66 +22,55 @@ * Authors: Ben Skeggs */ #include "pad.h" +#include "aux.h" +#include "bus.h" -struct g94_i2c_pad { - struct nvkm_i2c_pad base; - int addr; -}; - -static int -g94_i2c_pad_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct nvkm_device *device = i2c->subdev.device; - struct g94_i2c_pad *pad = (void *)object; - nvkm_mask(device, 0x00e50c + pad->addr, 0x00000001, 0x00000001); - return nvkm_i2c_pad_fini(&pad->base, suspend); -} - -static int -g94_i2c_pad_init(struct nvkm_object *object) +void +g94_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct nvkm_device *device = i2c->subdev.device; - struct g94_i2c_pad *pad = (void *)object; + struct nvkm_subdev *subdev = &pad->i2c->subdev; + struct nvkm_device *device = subdev->device; + const u32 base = (pad->id - NVKM_I2C_PAD_HYBRID(0)) * 0x50; - switch (nv_oclass(pad->base.next)->handle) { - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): - nvkm_mask(device, 0x00e500 + pad->addr, 0x0000c003, 0x00000002); + switch (mode) { + case NVKM_I2C_PAD_OFF: + nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000001); + break; + case NVKM_I2C_PAD_I2C: + nvkm_mask(device, 0x00e500 + base, 0x0000c003, 0x0000c001); + nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000000); + break; + case NVKM_I2C_PAD_AUX: + nvkm_mask(device, 0x00e500 + base, 0x0000c003, 0x00000002); + nvkm_mask(device, 0x00e50c + base, 0x00000001, 0x00000000); break; - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): default: - nvkm_mask(device, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001); + WARN_ON(1); break; } - - nvkm_mask(device, 0x00e50c + pad->addr, 0x00000001, 0x00000000); - return nvkm_i2c_pad_init(&pad->base); } -static int -g94_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct g94_i2c_pad *pad; - int ret; - - ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); - *pobject = nv_object(pad); - if (ret) - return ret; +static const struct nvkm_i2c_pad_func +g94_i2c_pad_s_func = { + .bus_new_4 = nv50_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, + .mode = g94_i2c_pad_mode, +}; - pad->addr = index * 0x50;; - return 0; +int +g94_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&g94_i2c_pad_s_func, i2c, id, ppad); } -struct nvkm_oclass -g94_i2c_pad_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_i2c_pad_ctor, - .dtor = _nvkm_i2c_pad_dtor, - .init = g94_i2c_pad_init, - .fini = g94_i2c_pad_fini, - }, +static const struct nvkm_i2c_pad_func +g94_i2c_pad_x_func = { + .bus_new_4 = nv50_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, }; + +int +g94_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&g94_i2c_pad_x_func, i2c, id, ppad); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c new file mode 100644 index 0000000000000..d53212f1aa527 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgf119.c @@ -0,0 +1,51 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "pad.h" +#include "aux.h" +#include "bus.h" + +static const struct nvkm_i2c_pad_func +gf119_i2c_pad_s_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, + .mode = g94_i2c_pad_mode, +}; + +int +gf119_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gf119_i2c_pad_s_func, i2c, id, ppad); +} + +static const struct nvkm_i2c_pad_func +gf119_i2c_pad_x_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = g94_i2c_aux_new, +}; + +int +gf119_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gf119_i2c_pad_x_func, i2c, id, ppad); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c index fa43046575bd9..24a4d760c67b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c @@ -22,66 +22,55 @@ * Authors: Ben Skeggs */ #include "pad.h" +#include "aux.h" +#include "bus.h" -struct gm204_i2c_pad { - struct nvkm_i2c_pad base; - int addr; -}; - -static int -gm204_i2c_pad_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct nvkm_device *device = i2c->subdev.device; - struct gm204_i2c_pad *pad = (void *)object; - nvkm_mask(device, 0x00d97c + pad->addr, 0x00000001, 0x00000001); - return nvkm_i2c_pad_fini(&pad->base, suspend); -} - -static int -gm204_i2c_pad_init(struct nvkm_object *object) +static void +gm204_i2c_pad_mode(struct nvkm_i2c_pad *pad, enum nvkm_i2c_pad_mode mode) { - struct nvkm_i2c *i2c = (void *)nvkm_i2c(object); - struct nvkm_device *device = i2c->subdev.device; - struct gm204_i2c_pad *pad = (void *)object; + struct nvkm_subdev *subdev = &pad->i2c->subdev; + struct nvkm_device *device = subdev->device; + const u32 base = (pad->id - NVKM_I2C_PAD_HYBRID(0)) * 0x50; - switch (nv_oclass(pad->base.next)->handle) { - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX): - nvkm_mask(device, 0x00d970 + pad->addr, 0x0000c003, 0x00000002); + switch (mode) { + case NVKM_I2C_PAD_OFF: + nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000001); + break; + case NVKM_I2C_PAD_I2C: + nvkm_mask(device, 0x00d970 + base, 0x0000c003, 0x0000c001); + nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000000); + break; + case NVKM_I2C_PAD_AUX: + nvkm_mask(device, 0x00d970 + base, 0x0000c003, 0x00000002); + nvkm_mask(device, 0x00d97c + base, 0x00000001, 0x00000000); break; - case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT): default: - nvkm_mask(device, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001); + WARN_ON(1); break; } - - nvkm_mask(device, 0x00d97c + pad->addr, 0x00000001, 0x00000000); - return nvkm_i2c_pad_init(&pad->base); } -static int -gm204_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 index, - struct nvkm_object **pobject) -{ - struct gm204_i2c_pad *pad; - int ret; - - ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad); - *pobject = nv_object(pad); - if (ret) - return ret; +static const struct nvkm_i2c_pad_func +gm204_i2c_pad_s_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = gm204_i2c_aux_new, + .mode = gm204_i2c_pad_mode, +}; - pad->addr = index * 0x50;; - return 0; +int +gm204_i2c_pad_s_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gm204_i2c_pad_s_func, i2c, id, ppad); } -struct nvkm_oclass -gm204_i2c_pad_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_i2c_pad_ctor, - .dtor = _nvkm_i2c_pad_dtor, - .init = gm204_i2c_pad_init, - .fini = gm204_i2c_pad_fini, - }, +static const struct nvkm_i2c_pad_func +gm204_i2c_pad_x_func = { + .bus_new_4 = gf119_i2c_bus_new, + .aux_new_6 = gm204_i2c_aux_new, }; + +int +gm204_i2c_pad_x_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&gm204_i2c_pad_x_func, i2c, id, ppad); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c index 22c7daaad3a05..310046ad9c61b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c @@ -22,13 +22,15 @@ * Authors: Ben Skeggs */ #include "pad.h" +#include "bus.h" -struct nvkm_oclass -nv04_i2c_pad_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_pad_ctor, - .dtor = _nvkm_i2c_pad_dtor, - .init = _nvkm_i2c_pad_init, - .fini = _nvkm_i2c_pad_fini, - }, +static const struct nvkm_i2c_pad_func +nv04_i2c_pad_func = { + .bus_new_0 = nv04_i2c_bus_new, }; + +int +nv04_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&nv04_i2c_pad_func, i2c, id, ppad); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c new file mode 100644 index 0000000000000..dda6fc0b089d9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv4e.c @@ -0,0 +1,36 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "pad.h" +#include "bus.h" + +static const struct nvkm_i2c_pad_func +nv4e_i2c_pad_func = { + .bus_new_4 = nv4e_i2c_bus_new, +}; + +int +nv4e_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&nv4e_i2c_pad_func, i2c, id, ppad); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c new file mode 100644 index 0000000000000..a03f25b1914f4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv50.c @@ -0,0 +1,36 @@ +/* + * Copyright 2014 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "pad.h" +#include "bus.h" + +static const struct nvkm_i2c_pad_func +nv50_i2c_pad_func = { + .bus_new_4 = nv50_i2c_bus_new, +}; + +int +nv50_i2c_pad_new(struct nvkm_i2c *i2c, int id, struct nvkm_i2c_pad **ppad) +{ + return nvkm_i2c_pad_new_(&nv50_i2c_pad_func, i2c, id, ppad); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h deleted file mode 100644 index ac6be72633478..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __NVKM_I2C_PORT_H__ -#define __NVKM_I2C_PORT_H__ -#include "priv.h" - -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_i2c_port *_port = (void *)port; \ - struct nvkm_i2c *_i2c = nvkm_i2c(_port); \ - nvkm_##l(&_i2c->subdev, "PORT:%02x: "f, _port->index, ##a); \ -} while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h index 6586e1567fcfc..e320e9da415bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h @@ -2,31 +2,6 @@ #define __NVKM_I2C_PRIV_H__ #include -extern struct nvkm_oclass nv04_i2c_pad_oclass; -extern struct nvkm_oclass g94_i2c_pad_oclass; -extern struct nvkm_oclass gm204_i2c_pad_oclass; - -#define nvkm_i2c_port_create(p,e,o,i,a,f,d) \ - nvkm_i2c_port_create_((p), (e), (o), (i), (a), (f), \ - sizeof(**d), (void **)d) -#define nvkm_i2c_port_destroy(p) ({ \ - struct nvkm_i2c_port *port = (p); \ - _nvkm_i2c_port_dtor(nv_object(i2c)); \ -}) -#define nvkm_i2c_port_init(p) \ - nvkm_object_init(&(p)->base) -#define nvkm_i2c_port_fini(p,s) \ - nvkm_object_fini(&(p)->base, (s)) - -int nvkm_i2c_port_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u8, - const struct i2c_algorithm *, - const struct nvkm_i2c_func *, - int, void **); -void _nvkm_i2c_port_dtor(struct nvkm_object *); -#define _nvkm_i2c_port_init nvkm_object_init -int _nvkm_i2c_port_fini(struct nvkm_object *, bool); - #define nvkm_i2c_create(p,e,o,d) \ nvkm_i2c_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_i2c_destroy(p) ({ \ @@ -51,19 +26,11 @@ void _nvkm_i2c_dtor(struct nvkm_object *); int _nvkm_i2c_init(struct nvkm_object *); int _nvkm_i2c_fini(struct nvkm_object *, bool); -extern struct nvkm_oclass nvkm_anx9805_sclass[]; -extern struct nvkm_oclass gf110_i2c_sclass[]; - -extern const struct i2c_algorithm nvkm_i2c_bit_algo; -extern const struct i2c_algorithm nvkm_i2c_aux_algo; - struct nvkm_i2c_impl { struct nvkm_oclass base; - /* supported i2c port classes */ - struct nvkm_oclass *sclass; - struct nvkm_oclass *pad_x; - struct nvkm_oclass *pad_s; + int (*pad_x_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **); + int (*pad_s_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **); /* number of native dp aux channels present */ int aux; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 1818994b14b26..9dcfbffe1ce42 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -29,7 +29,7 @@ #include static bool -mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr, +mxm_shadow_rom_fetch(struct nvkm_i2c_bus *bus, u8 addr, u8 offset, u8 size, u8 *data) { struct i2c_msg msgs[] = { @@ -37,7 +37,7 @@ mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr, { .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, }, }; - return i2c_transfer(&i2c->adapter, msgs, 2) == 2; + return i2c_transfer(&bus->i2c, msgs, 2) == 2; } static bool @@ -45,19 +45,19 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) { struct nvkm_bios *bios = nvkm_bios(mxm); struct nvkm_i2c *i2c = nvkm_i2c(mxm); - struct nvkm_i2c_port *port = NULL; + struct nvkm_i2c_bus *bus = NULL; u8 i2cidx, mxms[6], addr, size; i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f; if (i2cidx < 0x0f) - port = i2c->find(i2c, i2cidx); - if (!port) + bus = nvkm_i2c_bus_find(i2c, i2cidx); + if (!bus) return false; addr = 0x54; - if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) { + if (!mxm_shadow_rom_fetch(bus, addr, 0, 6, mxms)) { addr = 0x56; - if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) + if (!mxm_shadow_rom_fetch(bus, addr, 0, 6, mxms)) return false; } @@ -66,7 +66,7 @@ mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) mxm->mxms = kmalloc(size, GFP_KERNEL); if (mxm->mxms && - mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms)) + mxm_shadow_rom_fetch(bus, addr, 0, size, mxm->mxms)) return true; kfree(mxm->mxms); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c index f2b0165c6d96c..c19af7d242394 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c @@ -27,7 +27,7 @@ #include static bool -probe_monitoring_device(struct nvkm_i2c_port *i2c, +probe_monitoring_device(struct nvkm_i2c_bus *bus, struct i2c_board_info *info, void *data) { struct nvkm_therm_priv *therm = data; @@ -36,7 +36,7 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c, request_module("%s%s", I2C_MODULE_PREFIX, info->type); - client = i2c_new_device(&i2c->adapter, info); + client = i2c_new_device(&bus->i2c, info); if (!client) return false; @@ -54,7 +54,7 @@ probe_monitoring_device(struct nvkm_i2c_port *i2c, return true; } -static struct nvkm_i2c_board_info +static struct nvkm_i2c_bus_probe nv_board_infos[] = { { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 }, { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 }, @@ -83,30 +83,36 @@ void nvkm_therm_ic_ctor(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_bios *bios = nvkm_bios(therm); - struct nvkm_i2c *i2c = nvkm_i2c(therm); + struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; + struct nvkm_i2c_bus *bus; struct nvbios_extdev_func extdev_entry; + bus = nvkm_i2c_bus_find(i2c, NVKM_I2C_BUS_PRI); + if (!bus) + return; + if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) { - struct nvkm_i2c_board_info board[] = { + struct nvkm_i2c_bus_probe board[] = { { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0}, { } }; - i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - board, probe_monitoring_device, therm); + nvkm_i2c_bus_probe(bus, "monitoring device", board, + probe_monitoring_device, therm); if (therm->ic) return; } if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) { - struct nvkm_i2c_board_info board[] = { + struct nvkm_i2c_bus_probe board[] = { { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 }, { } }; - i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - board, probe_monitoring_device, therm); + nvkm_i2c_bus_probe(bus, "monitoring device", board, + probe_monitoring_device, therm); if (therm->ic) return; } @@ -114,6 +120,6 @@ nvkm_therm_ic_ctor(struct nvkm_therm *obj) /* The vbios doesn't provide the address of an exisiting monitoring device. Let's try our static list. */ - i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device", - nv_board_infos, probe_monitoring_device, therm); + nvkm_i2c_bus_probe(bus, "monitoring device", nv_board_infos, + probe_monitoring_device, therm); } -- GitLab From f2c906fc0cf1657e4164e09ae6061534eebd5430 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5460/7006] drm/nouveau/disp: transition outp/conn away from being based on nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 1 + .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 21 ++- .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 166 ++++++++++++++---- .../gpu/drm/nouveau/nvkm/engine/disp/conn.c | 114 ++++-------- .../gpu/drm/nouveau/nvkm/engine/disp/conn.h | 61 ++----- .../drm/nouveau/nvkm/engine/disp/dacnv50.c | 12 ++ .../gpu/drm/nouveau/nvkm/engine/disp/dport.c | 60 +++---- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm204.c | 11 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 7 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 21 +-- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/outp.c | 123 ++++--------- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 74 ++++---- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.c | 156 ++++++++-------- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 59 ++++--- .../drm/nouveau/nvkm/engine/disp/piornv50.c | 160 +++++++---------- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 21 ++- .../gpu/drm/nouveau/nvkm/engine/disp/sorg94.c | 62 ++++--- .../drm/nouveau/nvkm/engine/disp/sorgf110.c | 29 ++- .../drm/nouveau/nvkm/engine/disp/sorgm204.c | 36 ++-- .../drm/nouveau/nvkm/engine/disp/sornv50.c | 12 ++ 28 files changed, 629 insertions(+), 635 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 24bce1a93dbfa..cc2ea61535042 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -7,6 +7,7 @@ struct nvkm_disp { struct nvkm_engine engine; struct list_head outp; + struct list_head conn; struct nvkm_event hpd; struct nvkm_event vblank; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 16a4e2a37008e..38a872409c2ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -1,7 +1,4 @@ nvkm-y += nvkm/engine/disp/base.o -nvkm-y += nvkm/engine/disp/conn.o -nvkm-y += nvkm/engine/disp/outp.o -nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/nv04.o nvkm-y += nvkm/engine/disp/nv50.o nvkm-y += nvkm/engine/disp/g84.o @@ -13,17 +10,25 @@ nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o nvkm-y += nvkm/engine/disp/gm204.o + +nvkm-y += nvkm/engine/disp/outp.o +nvkm-y += nvkm/engine/disp/outpdp.o nvkm-y += nvkm/engine/disp/dacnv50.o +nvkm-y += nvkm/engine/disp/piornv50.o +nvkm-y += nvkm/engine/disp/sornv50.o +nvkm-y += nvkm/engine/disp/sorg94.o +nvkm-y += nvkm/engine/disp/sorgf110.o +nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/dport.o + +nvkm-y += nvkm/engine/disp/conn.o + nvkm-y += nvkm/engine/disp/hdagt215.o nvkm-y += nvkm/engine/disp/hdagf110.o + nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o nvkm-y += nvkm/engine/disp/hdmigf110.o nvkm-y += nvkm/engine/disp/hdmigk104.o -nvkm-y += nvkm/engine/disp/piornv50.o -nvkm-y += nvkm/engine/disp/sornv50.o -nvkm-y += nvkm/engine/disp/sorg94.o -nvkm-y += nvkm/engine/disp/sorgf110.o -nvkm-y += nvkm/engine/disp/sorgm204.o + nvkm-y += nvkm/engine/disp/vga.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 2090e90d67702..7e6744536fa0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -118,29 +118,25 @@ int _nvkm_disp_fini(struct nvkm_object *object, bool suspend) { struct nvkm_disp *disp = (void *)object; + struct nvkm_connector *conn; struct nvkm_output *outp; - int ret; list_for_each_entry(outp, &disp->outp, head) { - ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend); - if (ret && suspend) - goto fail_outp; + nvkm_output_fini(outp); } - return nvkm_engine_fini(&disp->engine, suspend); - -fail_outp: - list_for_each_entry_continue_reverse(outp, &disp->outp, head) { - nv_ofuncs(outp)->init(nv_object(outp)); + list_for_each_entry(conn, &disp->conn, head) { + nvkm_connector_fini(conn); } - return ret; + return nvkm_engine_fini(&disp->engine, suspend); } int _nvkm_disp_init(struct nvkm_object *object) { struct nvkm_disp *disp = (void *)object; + struct nvkm_connector *conn; struct nvkm_output *outp; int ret; @@ -148,17 +144,12 @@ _nvkm_disp_init(struct nvkm_object *object) if (ret) return ret; - list_for_each_entry(outp, &disp->outp, head) { - ret = nv_ofuncs(outp)->init(nv_object(outp)); - if (ret) - goto fail_outp; + list_for_each_entry(conn, &disp->conn, head) { + nvkm_connector_init(conn); } - return ret; - -fail_outp: - list_for_each_entry_continue_reverse(outp, &disp->outp, head) { - nv_ofuncs(outp)->fini(nv_object(outp), false); + list_for_each_entry(outp, &disp->outp, head) { + nvkm_output_init(outp); } return ret; @@ -168,15 +159,22 @@ void _nvkm_disp_dtor(struct nvkm_object *object) { struct nvkm_disp *disp = (void *)object; - struct nvkm_output *outp, *outt; + struct nvkm_connector *conn; + struct nvkm_output *outp; nvkm_event_fini(&disp->vblank); nvkm_event_fini(&disp->hpd); - if (disp->outp.next) { - list_for_each_entry_safe(outp, outt, &disp->outp, head) { - nvkm_object_ref(NULL, (struct nvkm_object **)&outp); - } + while (!list_empty(&disp->outp)) { + outp = list_first_entry(&disp->outp, typeof(*outp), head); + list_del(&outp->head); + nvkm_output_del(&outp); + } + + while (!list_empty(&disp->conn)) { + conn = list_first_entry(&disp->conn, typeof(*conn), head); + list_del(&conn->head); + nvkm_connector_del(&conn); } nvkm_engine_destroy(&disp->engine); @@ -188,10 +186,12 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, const char *extname, int length, void **pobject) { struct nvkm_disp_impl *impl = (void *)oclass; - struct nvkm_bios *bios = nvkm_bios(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_bios *bios = device->bios; struct nvkm_disp *disp; - struct nvkm_oclass **sclass; - struct nvkm_object *object; + struct nvkm_connector *conn; + struct nvkm_output *outp, *outt, *pair; + struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; u32 data; @@ -204,30 +204,124 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, return ret; INIT_LIST_HEAD(&disp->outp); + INIT_LIST_HEAD(&disp->conn); /* create output objects for each display path in the vbios */ i = -1; while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) { + const struct nvkm_disp_func_outp *outps; + int (*ctor)(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + if (dcbE.type == DCB_OUTPUT_UNUSED) continue; if (dcbE.type == DCB_OUTPUT_EOL) break; - data = dcbE.location << 4 | dcbE.type; + outp = NULL; + + switch (dcbE.location) { + case 0: outps = &impl->outp.internal; break; + case 1: outps = &impl->outp.external; break; + default: + nvkm_warn(&disp->engine.subdev, + "dcb %d locn %d unknown\n", i, dcbE.location); + continue; + } - oclass = nvkm_output_oclass; - sclass = impl->outp; - while (sclass && sclass[0]) { - if (sclass[0]->handle == data) { - oclass = sclass[0]; - break; + switch (dcbE.type) { + case DCB_OUTPUT_ANALOG: ctor = outps->crt ; break; + case DCB_OUTPUT_TV : ctor = outps->tv ; break; + case DCB_OUTPUT_TMDS : ctor = outps->tmds; break; + case DCB_OUTPUT_LVDS : ctor = outps->lvds; break; + case DCB_OUTPUT_DP : ctor = outps->dp ; break; + default: + nvkm_warn(&disp->engine.subdev, + "dcb %d type %d unknown\n", i, dcbE.type); + continue; + } + + if (ctor) + ret = ctor(disp, i, &dcbE, &outp); + else + ret = -ENODEV; + + if (ret) { + if (ret == -ENODEV) { + nvkm_debug(&disp->engine.subdev, + "dcb %d %d/%d not supported\n", + i, dcbE.location, dcbE.type); + continue; } - sclass++; + nvkm_error(&disp->engine.subdev, + "failed to create output %d\n", i); + nvkm_output_del(&outp); + continue; } - nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object); + list_add_tail(&outp->head, &disp->outp); hpd = max(hpd, (u8)(dcbE.connector + 1)); } + /* create connector objects based on the outputs we support */ + list_for_each_entry_safe(outp, outt, &disp->outp, head) { + /* bios data *should* give us the most useful information */ + data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, + &connE); + + /* no bios connector data... */ + if (!data) { + /* heuristic: anything with the same ccb index is + * considered to be on the same connector, any + * output path without an associated ccb entry will + * be put on its own connector + */ + int ccb_index = outp->info.i2c_index; + if (ccb_index != 0xf) { + list_for_each_entry(pair, &disp->outp, head) { + if (pair->info.i2c_index == ccb_index) { + outp->conn = pair->conn; + break; + } + } + } + + /* connector shared with another output path */ + if (outp->conn) + continue; + + memset(&connE, 0x00, sizeof(connE)); + connE.type = DCB_CONNECTOR_NONE; + i = -1; + } else { + i = outp->info.connector; + } + + /* check that we haven't already created this connector */ + list_for_each_entry(conn, &disp->conn, head) { + if (conn->index == outp->info.connector) { + outp->conn = conn; + break; + } + } + + if (outp->conn) + continue; + + /* apparently we need to create a new one! */ + ret = nvkm_connector_new(disp, i, &connE, &outp->conn); + if (ret) { + nvkm_error(&disp->engine.subdev, + "failed to create output %d conn: %d\n", + outp->index, ret); + nvkm_connector_del(&outp->conn); + list_del(&outp->head); + nvkm_output_del(&outp); + continue; + } + + list_add_tail(&outp->conn->head, &disp->conn); + } + ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index cf03e0240ced6..2eb55be056d9b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -33,13 +33,13 @@ static int nvkm_connector_hpd(struct nvkm_notify *notify) { struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); - struct nvkm_disp *disp = nvkm_disp(conn); - struct nvkm_gpio *gpio = nvkm_gpio(conn); + struct nvkm_disp *disp = conn->disp; + struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; const struct nvkm_gpio_ntfy_rep *line = notify->data; struct nvif_notify_conn_rep_v0 rep; int index = conn->index; - DBG("HPD: %d\n", line->mask); + CONN_DBG(conn, "HPD: %d", line->mask); if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; @@ -51,78 +51,58 @@ nvkm_connector_hpd(struct nvkm_notify *notify) return NVKM_NOTIFY_KEEP; } -int -_nvkm_connector_fini(struct nvkm_object *object, bool suspend) +void +nvkm_connector_fini(struct nvkm_connector *conn) { - struct nvkm_connector *conn = (void *)object; nvkm_notify_put(&conn->hpd); - return nvkm_object_fini(&conn->base, suspend); } -int -_nvkm_connector_init(struct nvkm_object *object) +void +nvkm_connector_init(struct nvkm_connector *conn) { - struct nvkm_connector *conn = (void *)object; - int ret = nvkm_object_init(&conn->base); - if (ret == 0) - nvkm_notify_get(&conn->hpd); - return ret; + nvkm_notify_get(&conn->hpd); } void -_nvkm_connector_dtor(struct nvkm_object *object) +nvkm_connector_del(struct nvkm_connector **pconn) { - struct nvkm_connector *conn = (void *)object; - nvkm_notify_fini(&conn->hpd); - nvkm_object_destroy(&conn->base); + struct nvkm_connector *conn = *pconn; + if (conn) { + nvkm_notify_fini(&conn->hpd); + kfree(*pconn); + *pconn = NULL; + } } -int -nvkm_connector_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct nvbios_connE *info, int index, - int length, void **pobject) +static void +nvkm_connector_ctor(struct nvkm_disp *disp, int index, + struct nvbios_connE *info, struct nvkm_connector *conn) { static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 }; - struct nvkm_disp *disp = nvkm_disp(parent); - struct nvkm_gpio *gpio = nvkm_gpio(parent); - struct nvkm_connector *conn; - struct nvkm_output *outp; + struct nvkm_gpio *gpio = disp->engine.subdev.device->gpio; struct dcb_gpio_func func; int ret; - list_for_each_entry(outp, &disp->outp, head) { - if (outp->conn && outp->conn->index == index) { - atomic_inc(&nv_object(outp->conn)->refcount); - *pobject = outp->conn; - return 1; - } - } - - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - conn = *pobject; - if (ret) - return ret; - - conn->info = *info; + conn->disp = disp; conn->index = index; + conn->info = *info; - DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n", - info->type, info->location, info->hpd, info->dp, - info->di, info->sr, info->lcdid); + CONN_DBG(conn, "type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x", + info->type, info->location, info->hpd, info->dp, + info->di, info->sr, info->lcdid); if ((info->hpd = ffs(info->hpd))) { if (--info->hpd >= ARRAY_SIZE(hpd)) { - ERR("hpd %02x unknown\n", info->hpd); - return 0; + CONN_ERR(conn, "hpd %02x unknown", info->hpd); + return; } info->hpd = hpd[info->hpd]; ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); if (ret) { - ERR("func %02x lookup failed, %d\n", info->hpd, ret); - return 0; + CONN_ERR(conn, "func %02x lookup failed, %d", + info->hpd, ret); + return; } ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd, @@ -134,41 +114,19 @@ nvkm_connector_create_(struct nvkm_object *parent, sizeof(struct nvkm_gpio_ntfy_rep), &conn->hpd); if (ret) { - ERR("func %02x failed, %d\n", info->hpd, ret); + CONN_ERR(conn, "func %02x failed, %d", info->hpd, ret); } else { - DBG("func %02x (HPD)\n", info->hpd); + CONN_DBG(conn, "func %02x (HPD)", info->hpd); } } - - return 0; } int -_nvkm_connector_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nvkm_connector_new(struct nvkm_disp *disp, int index, + struct nvbios_connE *info, struct nvkm_connector **pconn) { - struct nvkm_connector *conn; - int ret; - - ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn); - *pobject = nv_object(conn); - if (ret) - return ret; - + if (!(*pconn = kzalloc(sizeof(**pconn), GFP_KERNEL))) + return -ENOMEM; + nvkm_connector_ctor(disp, index, info, *pconn); return 0; } - -struct nvkm_oclass * -nvkm_connector_oclass = &(struct nvkm_connector_impl) { - .base = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_connector_ctor, - .dtor = _nvkm_connector_dtor, - .init = _nvkm_connector_init, - .fini = _nvkm_connector_fini, - }, - }, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h index 7789f70e556a2..ed32fe7f18649 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h @@ -1,58 +1,33 @@ #ifndef __NVKM_DISP_CONN_H__ #define __NVKM_DISP_CONN_H__ -#include -#include +#include +#include #include #include struct nvkm_connector { - struct nvkm_object base; - struct list_head head; - - struct nvbios_connE info; + struct nvkm_disp *disp; int index; + struct nvbios_connE info; struct nvkm_notify hpd; -}; -#define nvkm_connector_create(p,e,c,b,i,d) \ - nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_connector_destroy(d) ({ \ - struct nvkm_connector *disp = (d); \ - _nvkm_connector_dtor(nv_object(disp)); \ -}) -#define nvkm_connector_init(d) ({ \ - struct nvkm_connector *disp = (d); \ - _nvkm_connector_init(nv_object(disp)); \ -}) -#define nvkm_connector_fini(d,s) ({ \ - struct nvkm_connector *disp = (d); \ - _nvkm_connector_fini(nv_object(disp), (s)); \ -}) - -int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct nvbios_connE *, - int, int, void **); - -int _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_connector_dtor(struct nvkm_object *); -int _nvkm_connector_init(struct nvkm_object *); -int _nvkm_connector_fini(struct nvkm_object *, bool); - -struct nvkm_connector_impl { - struct nvkm_oclass base; + struct list_head head; }; -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_connector *_conn = (void *)conn; \ - nvkm_##l(&nvkm_disp(_conn)->engine.subdev, "%02x:%02x%02x: "f, _conn->index, \ - _conn->info.location, _conn->info.type, ##a); \ +int nvkm_connector_new(struct nvkm_disp *, int index, struct nvbios_connE *, + struct nvkm_connector **); +void nvkm_connector_del(struct nvkm_connector **); +void nvkm_connector_init(struct nvkm_connector *); +void nvkm_connector_fini(struct nvkm_connector *); + +#define CONN_MSG(c,l,f,a...) do { \ + struct nvkm_connector *_conn = (c); \ + nvkm_##l(&_conn->disp->engine.subdev, "conn %02x:%02x%02x: "f"\n", \ + _conn->index, _conn->info.location, _conn->info.type, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define CONN_ERR(c,f,a...) CONN_MSG((c), error, f, ##a) +#define CONN_DBG(c,f,a...) CONN_MSG((c), debug, f, ##a) +#define CONN_TRACE(c,f,a...) CONN_MSG((c), trace, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c index ddd4144bee478..9bfa9e7dc1615 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c @@ -112,3 +112,15 @@ nv50_dac_sense(NV50_DISP_MTHD_V1) args->v0.load = (loadval & 0x38000000) >> 27; return 0; } + +static const struct nvkm_output_func +nv50_dac_output_func = { +}; + +int +nv50_dac_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_dac_output_func, disp, + index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index d671da6d6ac14..cf1ec5f3aad7f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -48,12 +48,12 @@ struct dp_state { static int dp_set_link_config(struct dp_state *dp) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = 0x0000, .outp = &outp->base.info, @@ -64,7 +64,7 @@ dp_set_link_config(struct dp_state *dp) u8 sink[2]; int ret; - DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw); + OUTP_DBG(&outp->base, "%d lanes at %d KB/s", dp->link_nr, dp->link_bw); /* set desired link configuration on the source */ if ((lnkcmp = dp->outp->info.lnkcmp)) { @@ -81,16 +81,16 @@ dp_set_link_config(struct dp_state *dp) nvbios_exec(&init); } - ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, - outp->dpcd[DPCD_RC02] & - DPCD_RC02_ENHANCED_FRAME_CAP); + ret = outp->func->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000, + outp->dpcd[DPCD_RC02] & + DPCD_RC02_ENHANCED_FRAME_CAP); if (ret) { if (ret < 0) - ERR("lnk_ctl failed with %d\n", ret); + OUTP_ERR(&outp->base, "lnk_ctl failed with %d", ret); return ret; } - impl->lnk_pwr(outp, dp->link_nr); + outp->func->lnk_pwr(outp, dp->link_nr); /* set desired link configuration on the sink */ sink[0] = dp->link_bw / 27000; @@ -104,12 +104,11 @@ dp_set_link_config(struct dp_state *dp) static void dp_set_training_pattern(struct dp_state *dp, u8 pattern) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; u8 sink_tp; - DBG("training pattern %d\n", pattern); - impl->pattern(outp, pattern); + OUTP_DBG(&outp->base, "training pattern %d", pattern); + outp->func->pattern(outp, pattern); nvkm_rdaux(outp->aux, DPCD_LC02, &sink_tp, 1); sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET; @@ -120,7 +119,6 @@ dp_set_training_pattern(struct dp_state *dp, u8 pattern) static int dp_link_train_commit(struct dp_state *dp, bool pc) { - struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp); struct nvkm_output_dp *outp = dp->outp; int ret, i; @@ -146,8 +144,9 @@ dp_link_train_commit(struct dp_state *dp, bool pc) dp->conf[i] = (lpre << 3) | lvsw; dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4); - DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2); - impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); + OUTP_DBG(&outp->base, "config lane %d %02x %02x", + i, dp->conf[i], lpc2); + outp->func->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3); } ret = nvkm_wraux(outp->aux, DPCD_LC03(0), dp->conf, 4); @@ -182,9 +181,10 @@ dp_link_train_update(struct dp_state *dp, bool pc, u32 delay) ret = nvkm_rdaux(outp->aux, DPCD_LS0C, &dp->pc2stat, 1); if (ret) dp->pc2stat = 0x00; - DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat); + OUTP_DBG(&outp->base, "status %6ph pc2 %02x", + dp->stat, dp->pc2stat); } else { - DBG("status %6ph\n", dp->stat); + OUTP_DBG(&outp->base, "status %6ph", dp->stat); } return 0; @@ -260,11 +260,11 @@ static void dp_link_train_init(struct dp_state *dp, bool spread) { struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->base.info, .crtc = -1, .execute = 1, @@ -286,11 +286,11 @@ static void dp_link_train_fini(struct dp_state *dp) { struct nvkm_output_dp *outp = dp->outp; - struct nvkm_disp *disp = nvkm_disp(outp); - struct nvkm_bios *bios = nvkm_bios(disp); + struct nvkm_disp *disp = outp->base.disp; + struct nvkm_subdev *subdev = &disp->engine.subdev; struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->base.info, .crtc = -1, .execute = 1, @@ -322,7 +322,7 @@ void nvkm_dp_train(struct work_struct *w) { struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); - struct nv50_disp *disp = (void *)nvkm_disp(outp); + struct nv50_disp *disp = (void *)outp->base.disp; const struct dp_rates *cfg = nvkm_dp_rates; struct dp_state _dp = { .outp = outp, @@ -334,7 +334,7 @@ nvkm_dp_train(struct work_struct *w) disp->sor.magic(&outp->base); /* bring capabilities within encoder limits */ - if (nv_mclass(disp) < GF110_DISP) + if (disp->base.engine.subdev.device->chipset < 0xd0) outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED; if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) { outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT; @@ -386,12 +386,12 @@ nvkm_dp_train(struct work_struct *w) /* finish link training and execute post-train script from vbios */ dp_set_training_pattern(dp, 0); if (ret < 0) - ERR("link training failed\n"); + OUTP_ERR(&outp->base, "link training failed"); dp_link_train_fini(dp); /* signal completion and enable link interrupt handling */ - DBG("training complete\n"); + OUTP_DBG(&outp->base, "training complete"); atomic_set(&outp->lt.done, 1); wake_up(&outp->lt.wait); nvkm_notify_get(&outp->irq); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index a0801846b4777..c8d3093f95b9b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -262,8 +262,12 @@ g84_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.external.tmds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, .mthd.core = &g84_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 9082fb71cda91..b190a07c89d5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -113,13 +113,6 @@ g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass * -g94_disp_outp_sclass[] = { - &nv50_pior_dp_impl.base.base, - &g94_sor_dp_impl.base.base, - NULL -}; - struct nvkm_oclass * g94_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x88), @@ -129,8 +122,13 @@ g94_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = g94_sor_dp_new, + .base.outp.external.lvds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = g94_disp_outp_sclass, .mthd.core = &g94_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index bf729966d6a2b..4161326b4f5b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -988,7 +988,7 @@ gf110_disp_intr_unk2_0(struct nv50_disp *disp, int head) /* see note in nv50_disp_intr_unk20_0() */ if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { .subdev = nv_subdev(disp), .bios = nvkm_bios(disp), @@ -1101,7 +1101,7 @@ gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) } if (nvkm_output_dp_train(outp, pclk, true)) - ERR("link not trained before attach\n"); + OUTP_ERR(outp, "link not trained before attach"); } else { if (disp->sor.magic) disp->sor.magic(outp); @@ -1339,12 +1339,6 @@ gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass * -gf110_disp_outp_sclass[] = { - &gf110_sor_dp_impl.base.base, - NULL -}; - struct nvkm_oclass * gf110_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x90), @@ -1354,8 +1348,11 @@ gf110_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gf110_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gf110_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index baf2c2832c409..ffd8e7798a77f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -259,8 +259,11 @@ gk104_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index ee51b4f22aaa0..ca2d6f1ea4ba0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -94,8 +94,11 @@ gk110_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index 13a02ac2ffa76..f841d820a7939 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -94,8 +94,11 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf110_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gf110_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index 89d9839ecf656..8da317468bdf3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -87,12 +87,6 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass * -gm204_disp_outp_sclass[] = { - &gm204_sor_dp_impl.base.base, - NULL -}; - struct nvkm_oclass * gm204_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x07), @@ -102,8 +96,11 @@ gm204_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gm204_sor_dp_new, .base.vblank = &gf110_disp_vblank_func, - .base.outp = gm204_disp_outp_sclass, .mthd.core = &gk104_disp_core_mthd_chan, .mthd.base = &gf110_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 65cf51f3e8bd3..7f9f3a0da5f4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -138,8 +138,12 @@ gt200_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.external.tmds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, .mthd.core = &g84_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = >200_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index 0a2b794c3f63f..ef6c713c3d50b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -94,8 +94,13 @@ gt215_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = g94_sor_dp_new, + .base.outp.external.lvds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = g94_disp_outp_sclass, .mthd.core = &g94_disp_core_mthd_chan, .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index b07cb0626e873..5079ea3df4bfb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1109,7 +1109,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) } break; case NV50_DISP_MTHD_V1_SOR_DP_PWR: { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); union { struct nv50_disp_sor_dp_pwr_v0 v0; } *args = data; @@ -1119,8 +1119,7 @@ nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) args->v0.version, args->v0.state); if (args->v0.state == 0) { nvkm_notify_put(&outpdp->irq); - ((struct nvkm_output_dp_impl *)nv_oclass(outp)) - ->lnk_pwr(outpdp, 0); + outpdp->func->lnk_pwr(outpdp, 0); atomic_set(&outpdp->lt.done, 0); return 0; } else @@ -1655,7 +1654,7 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) * in a blank screen (SOR_PWR off/on can restore it) */ if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = (void *)outp; + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { .subdev = nv_subdev(disp), .bios = nvkm_bios(disp), @@ -1855,7 +1854,7 @@ nv50_disp_intr_unk20_2(struct nv50_disp *disp, int head) } if (nvkm_output_dp_train(outp, datarate / soff, true)) - ERR("link not trained before attach\n"); + OUTP_ERR(outp, "link not trained before attach"); } exec_clkcmp(disp, head, 0, pclk, &conf); @@ -2047,12 +2046,6 @@ nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass * -nv50_disp_outp_sclass[] = { - &nv50_pior_dp_impl.base.base, - NULL -}; - struct nvkm_oclass * nv50_disp_oclass = &(struct nv50_disp_impl) { .base.base.handle = NV_ENGINE(DISP, 0x50), @@ -2062,8 +2055,12 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { .init = _nvkm_disp_init, .fini = _nvkm_disp_fini, }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.external.tmds = nv50_pior_output_new, + .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .base.outp = nv50_disp_outp_sclass, .mthd.core = &nv50_disp_core_mthd_chan, .mthd.base = &nv50_disp_base_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 24d3413defbdd..0d495d274eb35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -214,7 +214,7 @@ extern struct nvkm_output_dp_impl nv50_pior_dp_impl; extern struct nvkm_oclass *nv50_disp_outp_sclass[]; extern struct nvkm_output_dp_impl g94_sor_dp_impl; -u32 g94_sor_dp_lane_map(struct nv50_disp *, u8 lane); +u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); extern struct nvkm_oclass *g94_disp_outp_sclass[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c index 88a990ec70251..bbe5ec0dedb26 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c @@ -22,117 +22,66 @@ * Authors: Ben Skeggs */ #include "outp.h" -#include "priv.h" #include -#include #include #include -int -_nvkm_output_fini(struct nvkm_object *object, bool suspend) +void +nvkm_output_fini(struct nvkm_output *outp) { - struct nvkm_output *outp = (void *)object; - nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend); - return nvkm_object_fini(&outp->base, suspend); + if (outp->func->fini) + outp->func->fini(outp); } -int -_nvkm_output_init(struct nvkm_object *object) +void +nvkm_output_init(struct nvkm_output *outp) { - struct nvkm_output *outp = (void *)object; - int ret = nvkm_object_init(&outp->base); - if (ret == 0) - nv_ofuncs(outp->conn)->init(nv_object(outp->conn)); - return 0; + if (outp->func->init) + outp->func->init(outp); } void -_nvkm_output_dtor(struct nvkm_object *object) +nvkm_output_del(struct nvkm_output **poutp) { - struct nvkm_output *outp = (void *)object; - list_del(&outp->head); - nvkm_object_ref(NULL, (void *)&outp->conn); - nvkm_object_destroy(&outp->base); + struct nvkm_output *outp = *poutp; + if (outp && !WARN_ON(!outp->func)) { + if (outp->func->dtor) + *poutp = outp->func->dtor(outp); + kfree(*poutp); + *poutp = NULL; + } } -int -nvkm_output_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct dcb_output *dcbE, int index, - int length, void **pobject) +void +nvkm_output_ctor(const struct nvkm_output_func *func, struct nvkm_disp *disp, + int index, struct dcb_output *dcbE, struct nvkm_output *outp) { - struct nvkm_disp *disp = nvkm_disp(parent); - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvbios_connE connE; - struct nvkm_output *outp; - u8 ver, hdr; - u32 data; - int ret; + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - outp = *pobject; - if (ret) - return ret; - - outp->info = *dcbE; + outp->func = func; + outp->disp = disp; outp->index = index; + outp->info = *dcbE; + outp->i2c = nvkm_i2c_bus_find(i2c, dcbE->i2c_index); outp->or = ffs(outp->info.or) - 1; - DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n", - dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ? - dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index, - dcbE->bus, dcbE->heads); - - outp->i2c = nvkm_i2c_bus_find(i2c, outp->info.i2c_index); - - data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE); - if (!data) { - DBG("vbios connector data not found\n"); - memset(&connE, 0x00, sizeof(connE)); - connE.type = DCB_CONNECTOR_NONE; - } - - ret = nvkm_object_ctor(parent, NULL, nvkm_connector_oclass, - &connE, outp->info.connector, - (struct nvkm_object **)&outp->conn); - if (ret < 0) { - ERR("error %d creating connector, disabling\n", ret); - return ret; - } - - list_add_tail(&outp->head, &disp->outp); - return 0; + OUTP_DBG(outp, "type %02x loc %d or %d link %d con %x " + "edid %x bus %d head %x", + outp->info.type, outp->info.location, outp->info.or, + outp->info.type >= 2 ? outp->info.sorconf.link : 0, + outp->info.connector, outp->info.i2c_index, + outp->info.bus, outp->info.heads); } int -_nvkm_output_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *dcbE, u32 index, - struct nvkm_object **pobject) +nvkm_output_new_(const struct nvkm_output_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { - struct nvkm_output *outp; - int ret; - - ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp); - *pobject = nv_object(outp); - if (ret) - return ret; + if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL))) + return -ENOMEM; + nvkm_output_ctor(func, disp, index, dcbE, *poutp); return 0; } - -struct nvkm_oclass * -nvkm_output_oclass = &(struct nvkm_output_impl) { - .base = { - .handle = 0, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_ctor, - .dtor = _nvkm_output_dtor, - .init = _nvkm_output_init, - .fini = _nvkm_output_fini, - }, - }, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index fb2ce7ca934dd..83d9d3f129f54 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -1,61 +1,51 @@ #ifndef __NVKM_DISP_OUTP_H__ #define __NVKM_DISP_OUTP_H__ -#include +#include #include #include struct nvkm_output { - struct nvkm_object base; - struct list_head head; - - struct dcb_output info; + const struct nvkm_output_func *func; + struct nvkm_disp *disp; int index; - int or; + struct dcb_output info; // whatever (if anything) is pointed at by the dcb device entry struct nvkm_i2c_bus *i2c; + int or; + struct list_head head; struct nvkm_connector *conn; }; -#define nvkm_output_create(p,e,c,b,i,d) \ - nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_output_destroy(d) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_dtor(nv_object(_outp)); \ -}) -#define nvkm_output_init(d) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_init(nv_object(_outp)); \ -}) -#define nvkm_output_fini(d,s) ({ \ - struct nvkm_output *_outp = (d); \ - _nvkm_output_fini(nv_object(_outp), (s)); \ -}) - -int nvkm_output_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct dcb_output *, - int, int, void **); - -int _nvkm_output_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_output_dtor(struct nvkm_object *); -int _nvkm_output_init(struct nvkm_object *); -int _nvkm_output_fini(struct nvkm_object *, bool); - -struct nvkm_output_impl { - struct nvkm_oclass base; +struct nvkm_output_func { + void *(*dtor)(struct nvkm_output *); + void (*init)(struct nvkm_output *); + void (*fini)(struct nvkm_output *); }; -#ifndef MSG -#define MSG(l,f,a...) do { \ - struct nvkm_output *_outp = (void *)outp; \ - nvkm_##l(&nvkm_disp(_outp)->engine.subdev, "%02x:%04x:%04x: "f, _outp->index, \ - _outp->info.hasht, _outp->info.hashm, ##a); \ +void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output *); +int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output **); +void nvkm_output_del(struct nvkm_output **); +void nvkm_output_init(struct nvkm_output *); +void nvkm_output_fini(struct nvkm_output *); + +int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +#define OUTP_MSG(o,l,f,a...) do { \ + struct nvkm_output *_outp = (o); \ + nvkm_##l(&_outp->disp->engine.subdev, "outp %02x:%04x:%04x: "f"\n", \ + _outp->index, _outp->info.hasht, _outp->info.hashm, ##a); \ } while(0) -#define DBG(f,a...) MSG(debug, f, ##a) -#define ERR(f,a...) MSG(error, f, ##a) -#endif +#define OUTP_ERR(o,f,a...) OUTP_MSG((o), error, f, ##a) +#define OUTP_DBG(o,f,a...) OUTP_MSG((o), debug, f, ##a) +#define OUTP_TRACE(o,f,a...) OUTP_MSG((o), trace, f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c index dac6f17bd1b63..3b7a9e7a1ea86 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c @@ -33,7 +33,7 @@ int nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) { - struct nvkm_output_dp *outp = (void *)base; + struct nvkm_output_dp *outp = nvkm_output_dp(base); bool retrain = true; u8 link[2], stat[3]; u32 linkrate; @@ -42,7 +42,8 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) /* check that the link is trained at a high enough rate */ ret = nvkm_rdaux(outp->aux, DPCD_LC00_LINK_BW_SET, link, 2); if (ret) { - DBG("failed to read link config, assuming no sink\n"); + OUTP_DBG(&outp->base, + "failed to read link config, assuming no sink"); goto done; } @@ -50,14 +51,15 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */ datarate = (datarate + 9) / 10; /* -> decakilobits */ if (linkrate < datarate) { - DBG("link not trained at sufficient rate\n"); + OUTP_DBG(&outp->base, "link not trained at sufficient rate"); goto done; } /* check that link is still trained */ ret = nvkm_rdaux(outp->aux, DPCD_LS02, stat, 3); if (ret) { - DBG("failed to read link status, assuming no sink\n"); + OUTP_DBG(&outp->base, + "failed to read link status, assuming no sink"); goto done; } @@ -67,13 +69,14 @@ nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait) if (!(lane & DPCD_LS02_LANE0_CR_DONE) || !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) || !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) { - DBG("lane %d not equalised\n", lane); + OUTP_DBG(&outp->base, + "lane %d not equalised", lane); goto done; } } retrain = false; } else { - DBG("no inter-lane alignment\n"); + OUTP_DBG(&outp->base, "no inter-lane alignment"); } done: @@ -108,7 +111,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) if (enable) { if (!outp->present) { - DBG("aux power -> always\n"); + OUTP_DBG(&outp->base, "aux power -> always"); nvkm_i2c_aux_monitor(aux, true); outp->present = true; } @@ -121,7 +124,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) } if (outp->present) { - DBG("aux power -> demand\n"); + OUTP_DBG(&outp->base, "aux power -> demand"); nvkm_i2c_aux_monitor(aux, false); outp->present = false; } @@ -132,116 +135,108 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool enable) static int nvkm_output_dp_hpd(struct nvkm_notify *notify) { - struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd); - struct nvkm_output_dp *outp; - struct nvkm_disp *disp = nvkm_disp(conn); const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), hpd); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; struct nvif_notify_conn_rep_v0 rep = {}; - list_for_each_entry(outp, &disp->outp, base.head) { - if (outp->base.conn == conn && - outp->info.type == DCB_OUTPUT_DP) { - DBG("HPD: %d\n", line->mask); - nvkm_output_dp_enable(outp, true); - - if (line->mask & NVKM_I2C_UNPLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; - if (line->mask & NVKM_I2C_PLUG) - rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; + OUTP_DBG(&outp->base, "HPD: %d", line->mask); + nvkm_output_dp_enable(outp, true); - nvkm_event_send(&disp->hpd, rep.mask, conn->index, - &rep, sizeof(rep)); - return NVKM_NOTIFY_KEEP; - } - } + if (line->mask & NVKM_I2C_UNPLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG; + if (line->mask & NVKM_I2C_PLUG) + rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG; - WARN_ON(1); - return NVKM_NOTIFY_DROP; + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); + return NVKM_NOTIFY_KEEP; } static int nvkm_output_dp_irq(struct nvkm_notify *notify) { - struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); - struct nvkm_disp *disp = nvkm_disp(outp); const struct nvkm_i2c_ntfy_rep *line = notify->data; + struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq); + struct nvkm_connector *conn = outp->base.conn; + struct nvkm_disp *disp = outp->base.disp; struct nvif_notify_conn_rep_v0 rep = { .mask = NVIF_NOTIFY_CONN_V0_IRQ, }; - int index = outp->base.info.connector; - DBG("IRQ: %d\n", line->mask); + OUTP_DBG(&outp->base, "IRQ: %d", line->mask); nvkm_output_dp_train(&outp->base, 0, true); - nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep)); + nvkm_event_send(&disp->hpd, rep.mask, conn->index, &rep, sizeof(rep)); return NVKM_NOTIFY_DROP; } -int -_nvkm_output_dp_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_output_dp_fini(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->hpd); nvkm_notify_put(&outp->irq); + flush_work(&outp->lt.work); nvkm_output_dp_enable(outp, false); - return nvkm_output_fini(&outp->base, suspend); } -int -_nvkm_output_dp_init(struct nvkm_object *object) +static void +nvkm_output_dp_init(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_put(&outp->base.conn->hpd); nvkm_output_dp_enable(outp, true); - return nvkm_output_init(&outp->base); + nvkm_notify_get(&outp->hpd); } -void -_nvkm_output_dp_dtor(struct nvkm_object *object) +static void * +nvkm_output_dp_dtor(struct nvkm_output *base) { - struct nvkm_output_dp *outp = (void *)object; + struct nvkm_output_dp *outp = nvkm_output_dp(base); + nvkm_notify_fini(&outp->hpd); nvkm_notify_fini(&outp->irq); - nvkm_output_destroy(&outp->base); + return outp; } +static const struct nvkm_output_func +nvkm_output_dp_func = { + .dtor = nvkm_output_dp_dtor, + .init = nvkm_output_dp_init, + .fini = nvkm_output_dp_fini, +}; + int -nvkm_output_dp_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - struct dcb_output *info, int index, - int length, void **pobject) +nvkm_output_dp_ctor(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_i2c_aux *aux, struct nvkm_output_dp *outp) { - struct nvkm_bios *bios = nvkm_bios(parent); - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output_dp *outp; + struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; u8 hdr, cnt, len; u32 data; int ret; - ret = nvkm_output_create_(parent, engine, oclass, info, index, - length, pobject); - outp = *pobject; - if (ret) - return ret; - - nvkm_notify_fini(&outp->base.conn->hpd); - - /* access to the aux channel is not optional... */ - //XXX: breaks anx support - outp->aux = nvkm_i2c_aux_find(i2c, outp->base.info.i2c_index); + nvkm_output_ctor(&nvkm_output_dp_func, disp, index, dcbE, &outp->base); + outp->func = func; + outp->aux = aux; if (!outp->aux) { - ERR("aux channel not found\n"); + OUTP_ERR(&outp->base, "no aux"); return -ENODEV; } - /* nor is the bios data for this output... */ + /* bios data is not optional */ data = nvbios_dpout_match(bios, outp->base.info.hasht, outp->base.info.hashm, &outp->version, &hdr, &cnt, &len, &outp->info); if (!data) { - ERR("no bios dp data\n"); + OUTP_ERR(&outp->base, "no bios dp data"); return -ENODEV; } - DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len); + OUTP_DBG(&outp->base, "bios dp %02x %02x %02x %02x", + outp->version, hdr, cnt, len); /* link training */ INIT_WORK(&outp->lt.work, nvkm_dp_train); @@ -258,7 +253,7 @@ nvkm_output_dp_create_(struct nvkm_object *parent, sizeof(struct nvkm_i2c_ntfy_rep), &outp->irq); if (ret) { - ERR("error monitoring aux irq event: %d\n", ret); + OUTP_ERR(&outp->base, "error monitoring aux irq: %d", ret); return ret; } @@ -270,9 +265,9 @@ nvkm_output_dp_create_(struct nvkm_object *parent, }, sizeof(struct nvkm_i2c_ntfy_req), sizeof(struct nvkm_i2c_ntfy_rep), - &outp->base.conn->hpd); + &outp->hpd); if (ret) { - ERR("error monitoring aux hpd events: %d\n", ret); + OUTP_ERR(&outp->base, "error monitoring aux hpd: %d", ret); return ret; } @@ -280,18 +275,17 @@ nvkm_output_dp_create_(struct nvkm_object *parent, } int -_nvkm_output_dp_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nvkm_output_dp_new_(const struct nvkm_output_dp_func *func, + struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, dcbE->i2c_index); struct nvkm_output_dp *outp; - int ret; - ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); - if (ret) - return ret; + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; - return 0; + return nvkm_output_dp_ctor(func, disp, index, dcbE, aux, outp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index f90e84c5fa29e..1c1bd38d88b01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -1,5 +1,14 @@ #ifndef __NVKM_DISP_OUTP_DP_H__ #define __NVKM_DISP_OUTP_DP_H__ +#define nvkm_output_dp(p) container_of((p), struct nvkm_output_dp, base) +#ifndef MSG +#define MSG(l,f,a...) \ + nvkm_##l(&outp->base.disp->engine.subdev, "%02x:%04x:%04x: "f, \ + outp->base.index, outp->base.info.hasht, \ + outp->base.info.hashm, ##a) +#define DBG(f,a...) MSG(debug, f, ##a) +#define ERR(f,a...) MSG(error, f, ##a) +#endif #include "outp.h" #include @@ -7,6 +16,7 @@ #include struct nvkm_output_dp { + const struct nvkm_output_dp_func *func; struct nvkm_output base; struct nvbios_dpout info; @@ -15,6 +25,7 @@ struct nvkm_output_dp { struct nvkm_i2c_aux *aux; struct nvkm_notify irq; + struct nvkm_notify hpd; bool present; u8 dpcd[16]; @@ -25,34 +36,7 @@ struct nvkm_output_dp { } lt; }; -#define nvkm_output_dp_create(p,e,c,b,i,d) \ - nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d) -#define nvkm_output_dp_destroy(d) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_dtor(nv_object(_outp)); \ -}) -#define nvkm_output_dp_init(d) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_init(nv_object(_outp)); \ -}) -#define nvkm_output_dp_fini(d,s) ({ \ - struct nvkm_output_dp *_outp = (d); \ - _nvkm_output_dp_fini(nv_object(_outp), (s)); \ -}) - -int nvkm_output_dp_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct dcb_output *, - int, int, void **); - -int _nvkm_output_dp_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_output_dp_dtor(struct nvkm_object *); -int _nvkm_output_dp_init(struct nvkm_object *); -int _nvkm_output_dp_fini(struct nvkm_object *, bool); - -struct nvkm_output_dp_impl { - struct nvkm_output_impl base; +struct nvkm_output_dp_func { int (*pattern)(struct nvkm_output_dp *, int); int (*lnk_pwr)(struct nvkm_output_dp *, int nr); int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef); @@ -60,4 +44,23 @@ struct nvkm_output_dp_impl { }; int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait); + +int nvkm_output_dp_ctor(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_i2c_aux *, + struct nvkm_output_dp *); +int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, + int index, struct dcb_output *, + struct nvkm_output **); + +int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int gf110_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); + +int gm204_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c index ac122d72fb72f..ab524bde77952 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c @@ -21,8 +21,8 @@ * * Authors: Ben Skeggs */ -#include "nv50.h" #include "outpdp.h" +#include "nv50.h" #include #include @@ -31,135 +31,101 @@ #include #include -/****************************************************************************** - * TMDS - *****************************************************************************/ - -static int -nv50_pior_tmds_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +int +nv50_pior_power(NV50_DISP_MTHD_V1) { - struct nvkm_output *outp; + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 soff = outp->or * 0x800; + union { + struct nv50_disp_pior_pwr_v0 v0; + } *args = data; + u32 ctrl, type; int ret; - ret = nvkm_output_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); - if (ret) + nvif_ioctl(object, "disp pior pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", + args->v0.version, args->v0.state, args->v0.type); + if (args->v0.type > 0x0f) + return -EINVAL; + ctrl = !!args->v0.state; + type = args->v0.type; + } else return ret; + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) + break; + ); + disp->pior.type[outp->or] = type; return 0; } -struct nvkm_output_impl -nv50_pior_tmds_impl = { - .base.handle = DCB_OUTPUT_TMDS | 0x0100, - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_pior_tmds_ctor, - .dtor = _nvkm_output_dtor, - .init = _nvkm_output_init, - .fini = _nvkm_output_fini, - }, -}; - /****************************************************************************** - * DisplayPort + * TMDS *****************************************************************************/ +static const struct nvkm_output_func +nv50_pior_output_func = { +}; -static int -nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern) +int +nv50_pior_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) { - return -ENODEV; + return nvkm_output_new_(&nv50_pior_output_func, disp, + index, dcbE, poutp); } +/****************************************************************************** + * DisplayPort + *****************************************************************************/ static int -nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) +nv50_pior_output_dp_pattern(struct nvkm_output_dp *outp, int pattern) { return 0; } static int -nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) -{ - return nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); -} - -static int -nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) +nv50_pior_output_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - return -ENODEV; + return 0; } static int -nv50_pior_dp_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *info, u32 index, - struct nvkm_object **pobject) +nv50_pior_output_dp_lnk_ctl(struct nvkm_output_dp *outp, + int nr, int bw, bool ef) { - struct nvkm_i2c *i2c = nvkm_i2c(parent); - struct nvkm_output_dp *outp; - int ret; - - ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp); - *pobject = nv_object(outp); + int ret = nvkm_i2c_aux_lnk_ctl(outp->aux, nr, bw, ef); if (ret) return ret; - - outp->aux = nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(outp->base.info.extdev)); - return 0; + return 1; } -struct nvkm_output_dp_impl -nv50_pior_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP | 0x0010, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_pior_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, - .pattern = nv50_pior_dp_pattern, - .lnk_pwr = nv50_pior_dp_lnk_pwr, - .lnk_ctl = nv50_pior_dp_lnk_ctl, - .drv_ctl = nv50_pior_dp_drv_ctl, +static const struct nvkm_output_dp_func +nv50_pior_output_dp_func = { + .pattern = nv50_pior_output_dp_pattern, + .lnk_pwr = nv50_pior_output_dp_lnk_pwr, + .lnk_ctl = nv50_pior_output_dp_lnk_ctl, }; -/****************************************************************************** - * General PIOR handling - *****************************************************************************/ - int -nv50_pior_power(NV50_DISP_MTHD_V1) +nv50_pior_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) { - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 soff = outp->or * 0x800; - union { - struct nv50_disp_pior_pwr_v0 v0; - } *args = data; - u32 ctrl, type; - int ret; + struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c; + struct nvkm_i2c_aux *aux = + nvkm_i2c_aux_find(i2c, NVKM_I2C_AUX_EXT(dcbE->extdev)); + struct nvkm_output_dp *outp; - nvif_ioctl(object, "disp pior pwr size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp pior pwr vers %d state %d type %x\n", - args->v0.version, args->v0.state, args->v0.type); - if (args->v0.type > 0x0f) - return -EINVAL; - ctrl = !!args->v0.state; - type = args->v0.type; - } else - return ret; + if (!(outp = kzalloc(sizeof(*outp), GFP_KERNEL))) + return -ENOMEM; + *poutp = &outp->base; - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - nvkm_mask(device, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x61e004 + soff) & 0x80000000)) - break; - ); - disp->pior.type[outp->or] = type; - return 0; + return nvkm_output_dp_ctor(&nv50_pior_output_dp_func, disp, + index, dcbE, aux, outp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 961ce8bb21359..f1df2972a8d11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -1,11 +1,28 @@ #ifndef __NVKM_DISP_PRIV_H__ #define __NVKM_DISP_PRIV_H__ #include +#include "outp.h" +#include "outpdp.h" + +struct nvkm_disp_func_outp { + int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); +}; struct nvkm_disp_impl { struct nvkm_oclass base; - struct nvkm_oclass **outp; - struct nvkm_oclass **conn; + struct { + const struct nvkm_disp_func_outp internal; + const struct nvkm_disp_func_outp external; + } outp; const struct nvkm_event_func *vblank; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c index d921efe7e7316..1bb9d661e9b35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c @@ -38,15 +38,33 @@ g94_sor_loff(struct nvkm_output_dp *outp) return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } +/******************************************************************************* + * TMDS/LVDS + ******************************************************************************/ +static const struct nvkm_output_func +g94_sor_output_func = { +}; + +int +g94_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&g94_sor_output_func, disp, + index, dcbE, poutp); +} + +/******************************************************************************* + * DisplayPort + ******************************************************************************/ u32 -g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) +g94_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { static const u8 gm100[] = { 0, 8, 16, 24 }; static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */ static const u8 g94[] = { 16, 8, 0, 24 }; - if (nv_device(disp)->chipset >= 0x110) + if (device->chipset >= 0x110) return gm100[lane]; - if (nv_device(disp)->chipset == 0xaf) + if (device->chipset == 0xaf) return mcp89[lane]; return g94[lane]; } @@ -54,8 +72,7 @@ g94_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) static int g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 loff = g94_sor_loff(outp); nvkm_mask(device, 0x61c10c + loff, 0x0f000000, pattern << 24); return 0; @@ -64,14 +81,13 @@ g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (g94_sor_dp_lane_map(disp, i) >> 3); + mask |= 1 << (g94_sor_dp_lane_map(device, i) >> 3); nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); @@ -85,8 +101,7 @@ g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) static int g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = g94_sor_soff(outp); const u32 loff = g94_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -106,10 +121,9 @@ g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) static int g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(disp, ln); + const u32 shift = g94_sor_dp_lane_map(device, ln); const u32 loff = g94_sor_loff(outp); u32 addr, data[3]; u8 ver, hdr, cnt, len; @@ -118,12 +132,12 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) addr = nvbios_dpout_match(bios, outp->base.info.hasht, outp->base.info.hashm, - &ver, &hdr, &cnt, &len, &info); + &ver, &hdr, &cnt, &len, &info); if (!addr) return -ENODEV; addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe, - &ver, &hdr, &cnt, &len, &ocfg); + &ver, &hdr, &cnt, &len, &ocfg); if (!addr) return -EINVAL; @@ -138,17 +152,17 @@ g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) return 0; } -struct nvkm_output_dp_impl -g94_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +g94_sor_dp_func = { .pattern = g94_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = g94_sor_dp_lnk_ctl, .drv_ctl = g94_sor_dp_drv_ctl, }; + +int +g94_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&g94_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c index 696bc64693772..7e5ef507ab042 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c @@ -39,8 +39,7 @@ gf110_sor_loff(struct nvkm_output_dp *outp) static int gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 loff = gf110_sor_loff(outp); nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; @@ -49,8 +48,7 @@ gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gf110_sor_soff(outp); const u32 loff = gf110_sor_loff(outp); u32 dpctrl = 0x00000000; @@ -70,10 +68,9 @@ static int gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; - const u32 shift = g94_sor_dp_lane_map(disp, ln); + const u32 shift = g94_sor_dp_lane_map(device, ln); const u32 loff = gf110_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -104,17 +101,17 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -struct nvkm_output_dp_impl -gf110_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +gf110_sor_dp_func = { .pattern = gf110_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, .lnk_ctl = gf110_sor_dp_lnk_ctl, .drv_ctl = gf110_sor_dp_drv_ctl, }; + +int +gf110_sor_dp_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&gf110_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 8792dcf4a4687..5a35bf4f1e1d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -41,8 +41,7 @@ gm204_sor_loff(struct nvkm_output_dp *outp) void gm204_sor_magic(struct nvkm_output *outp) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->disp->engine.subdev.device; const u32 soff = outp->or * 0x100; const u32 data = outp->or + 1; if (outp->info.sorconf.link & 1) @@ -52,7 +51,7 @@ gm204_sor_magic(struct nvkm_output *outp) } static inline u32 -gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) +gm204_sor_dp_lane_map(struct nvkm_device *device, u8 lane) { return lane * 0x08; } @@ -60,8 +59,7 @@ gm204_sor_dp_lane_map(struct nv50_disp *disp, u8 lane) static int gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 data = 0x01010101 * pattern; if (outp->base.info.sorconf.link & 1) @@ -74,14 +72,13 @@ gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) static int gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; const u32 soff = gm204_sor_soff(outp); const u32 loff = gm204_sor_loff(outp); u32 mask = 0, i; for (i = 0; i < nr; i++) - mask |= 1 << (gm204_sor_dp_lane_map(disp, i) >> 3); + mask |= 1 << (gm204_sor_dp_lane_map(device, i) >> 3); nvkm_mask(device, 0x61c130 + loff, 0x0000000f, mask); nvkm_mask(device, 0x61c034 + soff, 0x80000000, 0x80000000); @@ -96,10 +93,9 @@ static int gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { - struct nv50_disp *disp = (void *)nvkm_disp(outp); - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; - const u32 shift = gm204_sor_dp_lane_map(disp, ln); + const u32 shift = gm204_sor_dp_lane_map(device, ln); const u32 loff = gm204_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; @@ -131,17 +127,17 @@ gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, return 0; } -struct nvkm_output_dp_impl -gm204_sor_dp_impl = { - .base.base.handle = DCB_OUTPUT_DP, - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_output_dp_ctor, - .dtor = _nvkm_output_dp_dtor, - .init = _nvkm_output_dp_init, - .fini = _nvkm_output_dp_fini, - }, +static const struct nvkm_output_dp_func +gm204_sor_dp_func = { .pattern = gm204_sor_dp_pattern, .lnk_pwr = gm204_sor_dp_lnk_pwr, .lnk_ctl = gf110_sor_dp_lnk_ctl, .drv_ctl = gm204_sor_dp_drv_ctl, }; + +int +gm204_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, + struct nvkm_output **poutp) +{ + return nvkm_output_dp_new_(&gm204_sor_dp_func, disp, index, dcbE, poutp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c index 73ee036c134da..29e0d2a9a839d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c @@ -65,3 +65,15 @@ nv50_sor_power(NV50_DISP_MTHD_V1) ); return 0; } + +static const struct nvkm_output_func +nv50_sor_output_func = { +}; + +int +nv50_sor_output_new(struct nvkm_disp *disp, int index, + struct dcb_output *dcbE, struct nvkm_output **poutp) +{ + return nvkm_output_new_(&nv50_sor_output_func, disp, + index, dcbE, poutp); +} -- GitLab From 47b2505efb2d951f16c3a229d93450b463d925e5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5461/7006] drm/nouveau/platform: remove subclassing of nvkm_device Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/device.h | 2 ++ drivers/gpu/drm/nouveau/nouveau_drm.c | 14 +++++++------- drivers/gpu/drm/nouveau/nouveau_drm.h | 5 +---- drivers/gpu/drm/nouveau/nouveau_platform.c | 6 +++--- drivers/gpu/drm/nouveau/nouveau_platform.h | 10 ---------- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 5 ++--- .../gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c | 13 ++++++------- drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 10 ++++------ 8 files changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index ffff6fd5a3482..d48e5006e14e0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -144,6 +144,8 @@ struct nvkm_device { struct nvkm_sw *sw; struct nvkm_engine *vic; struct nvkm_engine *vp; + + struct nouveau_platform_gpu *gpu; }; struct nvkm_device *nvkm_device_find(u64 name); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 4e6c1803fd37d..9e420f6c1a742 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -1056,16 +1056,16 @@ nouveau_drm_pci_driver = { }; struct drm_device * -nouveau_platform_device_create_(struct platform_device *pdev, int size, - void **pobject) +nouveau_platform_device_create(struct platform_device *pdev, + struct nvkm_device **pdevice) { struct drm_device *drm; int err; - err = nvkm_device_create_(pdev, NVKM_BUS_PLATFORM, - nouveau_platform_name(pdev), - dev_name(&pdev->dev), nouveau_config, - nouveau_debug, size, pobject); + err = nvkm_device_create(pdev, NVKM_BUS_PLATFORM, + nouveau_platform_name(pdev), + dev_name(&pdev->dev), nouveau_config, + nouveau_debug, pdevice); if (err) return ERR_PTR(err); @@ -1085,7 +1085,7 @@ nouveau_platform_device_create_(struct platform_device *pdev, int size, return drm; err_free: - nvkm_object_ref(NULL, (struct nvkm_object **)pobject); + nvkm_object_ref(NULL, (struct nvkm_object **)pdevice); return ERR_PTR(err); } diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 81ef59272ed29..d1a4c120b71bd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -182,11 +182,8 @@ nouveau_drm(struct drm_device *dev) int nouveau_pmops_suspend(struct device *); int nouveau_pmops_resume(struct device *); -#define nouveau_platform_device_create(p, u) \ - nouveau_platform_device_create_(p, sizeof(**u), (void **)u) struct drm_device * -nouveau_platform_device_create_(struct platform_device *pdev, - int size, void **pobject); +nouveau_platform_device_create(struct platform_device *, struct nvkm_device **); void nouveau_drm_device_remove(struct drm_device *dev); #define NV_PRINTK(l,c,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index 7a39d449fefa6..c03736bce9537 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -177,7 +177,7 @@ static void nouveau_platform_remove_iommu(struct device *dev, static int nouveau_platform_probe(struct platform_device *pdev) { struct nouveau_platform_gpu *gpu; - struct nouveau_platform_device *device; + struct nvkm_device *device; struct drm_device *drm; int err; @@ -214,7 +214,7 @@ static int nouveau_platform_probe(struct platform_device *pdev) } device->gpu = gpu; - device->gpu_speedo = tegra_sku_info.gpu_speedo_value; + gpu->gpu_speedo = tegra_sku_info.gpu_speedo_value; err = drm_dev_register(drm, 0); if (err < 0) @@ -237,7 +237,7 @@ static int nouveau_platform_remove(struct platform_device *pdev) struct drm_device *drm_dev = platform_get_drvdata(pdev); struct nouveau_drm *drm = nouveau_drm(drm_dev); struct nvkm_device *device = nvxx_device(&drm->device); - struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu; + struct nouveau_platform_gpu *gpu = device->gpu; int err; nouveau_drm_device_remove(drm_dev); diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.h b/drivers/gpu/drm/nouveau/nouveau_platform.h index 392874cf47257..7a4020f31cc52 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.h +++ b/drivers/gpu/drm/nouveau/nouveau_platform.h @@ -54,19 +54,9 @@ struct nouveau_platform_gpu { struct iommu_domain *domain; unsigned long pgshift; } iommu; -}; - -struct nouveau_platform_device { - struct nvkm_device device; - - struct nouveau_platform_gpu *gpu; int gpu_speedo; }; -#define nv_device_to_platform(d) \ - container_of(d, struct nouveau_platform_device, device) - extern struct platform_driver nouveau_platform_driver; - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 2d10dc17238d3..ce89955ff8f9b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -650,8 +650,8 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct gk20a_clk *clk; - struct nouveau_platform_device *plat; int ret; int i; @@ -670,8 +670,7 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, clk->params = &gk20a_pllg_params; - plat = nv_device_to_platform(nv_device(parent)); - clk->parent_rate = clk_get_rate(plat->gpu->clk); + clk->parent_rate = clk_get_rate(device->gpu->clk); nvkm_info(&clk->base.subdev, "parent clock rate: %d Mhz\n", clk->parent_rate / MHZ); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index f5642698406ae..e6370382109b4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -396,8 +396,8 @@ gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct gk20a_instmem *imem; - struct nouveau_platform_device *plat; int ret; ret = nvkm_instmem_create(parent, engine, oclass, &imem); @@ -407,12 +407,11 @@ gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, spin_lock_init(&imem->lock); - plat = nv_device_to_platform(nv_device(parent)); - if (plat->gpu->iommu.domain) { - imem->domain = plat->gpu->iommu.domain; - imem->mm = plat->gpu->iommu.mm; - imem->iommu_pgshift = plat->gpu->iommu.pgshift; - imem->mm_mutex = &plat->gpu->iommu.mutex; + if (device->gpu->iommu.domain) { + imem->domain = device->gpu->iommu.domain; + imem->mm = device->gpu->iommu.mm; + imem->iommu_pgshift = device->gpu->iommu.pgshift; + imem->mm_mutex = &device->gpu->iommu.mutex; nvkm_info(&imem->base.subdev, "using IOMMU\n"); } else { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index d86f4eaba04c0..59fa2cf898d20 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -152,8 +152,8 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct gk20a_volt *volt; - struct nouveau_platform_device *plat; int i, ret, uv; ret = nvkm_volt_create(parent, engine, oclass, &volt); @@ -161,12 +161,10 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - plat = nv_device_to_platform(nv_device(parent)); - - uv = regulator_get_voltage(plat->gpu->vdd); + uv = regulator_get_voltage(device->gpu->vdd); nvkm_info(&volt->base.subdev, "The default voltage is %duV\n", uv); - volt->vdd = plat->gpu->vdd; + volt->vdd = device->gpu->vdd; volt->base.vid_get = gk20a_volt_vid_get; volt->base.vid_set = gk20a_volt_vid_set; volt->base.set_id = gk20a_volt_set_id; @@ -178,7 +176,7 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, volt->base.vid[i].vid = i; volt->base.vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], - plat->gpu_speedo); + device->gpu->gpu_speedo); nvkm_debug(&volt->base.subdev, "%2d: vid=%d, uv=%d\n", i, volt->base.vid[i].vid, volt->base.vid[i].uv); } -- GitLab From 76ecea5b4b9383edde2bfe49e59e76fec4e21aa4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5462/7006] drm/nouveau/client: tidy ctor/dtor interfaces Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/client.h | 13 +-- drivers/gpu/drm/nouveau/nouveau_drm.c | 4 +- drivers/gpu/drm/nouveau/nouveau_nvif.c | 8 +- drivers/gpu/drm/nouveau/nvkm/core/client.c | 104 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +- 5 files changed, 64 insertions(+), 67 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 882ff6ed1e41a..473d66b22aeb0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -5,7 +5,7 @@ struct nvkm_client { struct nvkm_namedb namedb; struct nvkm_handle *root; - struct nvkm_object *device; + struct nvkm_device *device; char name[32]; u32 debug; struct nvkm_vm *vm; @@ -34,14 +34,9 @@ nvkm_client(void *obj) return (void *)client; } -#define nvkm_client_create(n,c,oc,od,d) \ - nvkm_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d) - -int nvkm_client_create_(const char *name, u64 device, const char *cfg, - const char *dbg, int, void **); -#define nvkm_client_destroy(p) \ - nvkm_namedb_destroy(&(p)->base) - +int nvkm_client_new(const char *name, u64 device, const char *cfg, + const char *dbg, struct nvkm_client **); +void nvkm_client_del(struct nvkm_client **); int nvkm_client_init(struct nvkm_client *); int nvkm_client_fini(struct nvkm_client *, bool suspend); const char *nvkm_client_name(void *obj); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 9e420f6c1a742..6180c3d302877 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -530,14 +530,14 @@ nouveau_drm_device_remove(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_client *client; - struct nvkm_object *device; + struct nvkm_device *device; dev->irq_enabled = false; client = nvxx_client(&drm->client.base); device = client->device; drm_put_dev(dev); - nvkm_object_ref(NULL, &device); + nvkm_object_ref(NULL, (struct nvkm_object **)&device); } static void diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c index ca0ad9d1563df..55eb942847fa6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_nvif.c +++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c @@ -72,10 +72,8 @@ nvkm_client_suspend(void *priv) static void nvkm_client_driver_fini(void *priv) { - struct nvkm_object *client = priv; - nvkm_client_fini(nv_client(client), false); - atomic_set(&client->refcount, 1); - nvkm_object_ref(NULL, &client); + struct nvkm_client *client = priv; + nvkm_client_del(&client); } static int @@ -113,7 +111,7 @@ nvkm_client_driver_init(const char *name, u64 device, const char *cfg, struct nvkm_client *client; int ret; - ret = nvkm_client_create(name, device, cfg, dbg, &client); + ret = nvkm_client_new(name, device, cfg, dbg, &client); *ppriv = client; if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 0c7162fbe06c8..cd8e51f74aa17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -176,43 +176,73 @@ nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } -static void -nvkm_client_dtor(struct nvkm_object *object) -{ - struct nvkm_client *client = (void *)object; - int i; - for (i = 0; i < ARRAY_SIZE(client->notify); i++) - nvkm_client_notify_del(client, i); - nvkm_object_ref(NULL, &client->device); - nvkm_handle_destroy(client->root); - nvkm_namedb_destroy(&client->namedb); -} - static struct nvkm_oclass nvkm_client_oclass = { .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_client_dtor, .mthd = nvkm_client_mthd, }, }; int -nvkm_client_create_(const char *name, u64 devname, const char *cfg, - const char *dbg, int length, void **pobject) +nvkm_client_fini(struct nvkm_client *client, bool suspend) +{ + struct nvkm_object *object = &client->namedb.parent.object; + const char *name[2] = { "fini", "suspend" }; + int ret, i; + nvif_trace(object, "%s running\n", name[suspend]); + nvif_trace(object, "%s notify\n", name[suspend]); + for (i = 0; i < ARRAY_SIZE(client->notify); i++) + nvkm_client_notify_put(client, i); + nvif_trace(object, "%s object\n", name[suspend]); + ret = nvkm_handle_fini(client->root, suspend); + nvif_trace(object, "%s completed with %d\n", name[suspend], ret); + return ret; +} + +int +nvkm_client_init(struct nvkm_client *client) +{ + struct nvkm_object *object = &client->namedb.parent.object; + int ret; + nvif_trace(object, "init running\n"); + ret = nvkm_handle_init(client->root); + nvif_trace(object, "init completed with %d\n", ret); + return ret; +} + +void +nvkm_client_del(struct nvkm_client **pclient) +{ + struct nvkm_client *client = *pclient; + int i; + if (client) { + nvkm_client_fini(client, false); + for (i = 0; i < ARRAY_SIZE(client->notify); i++) + nvkm_client_notify_del(client, i); + nvkm_object_ref(NULL, (struct nvkm_object **)&client->device); + nvkm_handle_destroy(client->root); + nvkm_namedb_destroy(&client->namedb); + *pclient = NULL; + } +} + +int +nvkm_client_new(const char *name, u64 devname, const char *cfg, + const char *dbg, struct nvkm_client **pclient) { - struct nvkm_object *device; + struct nvkm_device *device; struct nvkm_client *client; int ret; - device = (void *)nvkm_device_find(devname); + device = nvkm_device_find(devname); if (!device) return -ENODEV; - ret = nvkm_namedb_create_(NULL, NULL, &nvkm_client_oclass, - NV_CLIENT_CLASS, NULL, - (1ULL << NVDEV_ENGINE_DEVICE), - length, pobject); - client = *pobject; + ret = nvkm_namedb_create(NULL, NULL, &nvkm_client_oclass, + NV_CLIENT_CLASS, NULL, + (1ULL << NVDEV_ENGINE_DEVICE), + &client); + *pclient = client; if (ret) return ret; @@ -224,39 +254,13 @@ nvkm_client_create_(const char *name, u64 devname, const char *cfg, /* prevent init/fini being called, os in in charge of this */ atomic_set(&nv_object(client)->usecount, 2); - nvkm_object_ref(device, &client->device); + nvkm_object_ref(&device->engine.subdev.object, + (struct nvkm_object **)&client->device); snprintf(client->name, sizeof(client->name), "%s", name); client->debug = nvkm_dbgopt(dbg, "CLIENT"); return 0; } -int -nvkm_client_init(struct nvkm_client *client) -{ - struct nvkm_object *object = &client->namedb.parent.object; - int ret; - nvif_trace(object, "init running\n"); - ret = nvkm_handle_init(client->root); - nvif_trace(object, "init completed with %d\n", ret); - return ret; -} - -int -nvkm_client_fini(struct nvkm_client *client, bool suspend) -{ - struct nvkm_object *object = &client->namedb.parent.object; - const char *name[2] = { "fini", "suspend" }; - int ret, i; - nvif_trace(object, "%s running\n", name[suspend]); - nvif_trace(object, "%s notify\n", name[suspend]); - for (i = 0; i < ARRAY_SIZE(client->notify); i++) - nvkm_client_notify_put(client, i); - nvif_trace(object, "%s object\n", name[suspend]); - ret = nvkm_handle_fini(client->root, suspend); - nvif_trace(object, "%s completed with %d\n", name[suspend], ret); - return ret; -} - const char * nvkm_client_name(void *obj) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index af8f9ccdc8f6c..e08418436e0cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -308,7 +308,7 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, oclass = &nvkm_devobj_oclass_super; /* find the device subdev that matches what the client requested */ - device = nv_device(client->device); + device = client->device; if (args->v0.device != ~0) { device = nvkm_device_find(args->v0.device); if (!device) -- GitLab From e781dc8f6cebf69bd410eb652a13e0a3797d71fe Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5463/7006] drm/nouveau/device: tidy ctor/dtor interfaces Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 10 ++-- drivers/gpu/drm/nouveau/nouveau_drm.c | 22 ++++----- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 49 ++++++++++--------- 3 files changed, 40 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index d48e5006e14e0..d44e66f34bd73 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -210,12 +210,10 @@ enum nv_bus_type { NVKM_BUS_PLATFORM, }; -#define nvkm_device_create(p,t,n,s,c,d,u) \ - nvkm_device_create_((void *)(p), (t), (n), (s), (c), (d), \ - sizeof(**u), (void **)u) -int nvkm_device_create_(void *, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - int, void **); +int nvkm_device_new(void *, enum nv_bus_type type, u64 name, + const char *sname, const char *cfg, const char *dbg, + struct nvkm_device **); +void nvkm_device_del(struct nvkm_device **); /* device logging */ #define nvdev_printk_(d,l,p,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 6180c3d302877..16c5da7db9a92 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -325,9 +325,9 @@ static int nouveau_drm_probe(struct pci_dev *pdev, remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); - ret = nvkm_device_create(pdev, NVKM_BUS_PCI, - nouveau_pci_name(pdev), pci_name(pdev), - nouveau_config, nouveau_debug, &device); + ret = nvkm_device_new(pdev, NVKM_BUS_PCI, nouveau_pci_name(pdev), + pci_name(pdev), nouveau_config, nouveau_debug, + &device); if (ret) return ret; @@ -335,7 +335,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev, ret = drm_get_pci_dev(pdev, pent, &driver_pci); if (ret) { - nvkm_object_ref(NULL, (struct nvkm_object **)&device); + nvkm_device_del(&device); return ret; } @@ -537,7 +537,7 @@ nouveau_drm_device_remove(struct drm_device *dev) device = client->device; drm_put_dev(dev); - nvkm_object_ref(NULL, (struct nvkm_object **)&device); + nvkm_device_del(&device); } static void @@ -1062,12 +1062,12 @@ nouveau_platform_device_create(struct platform_device *pdev, struct drm_device *drm; int err; - err = nvkm_device_create(pdev, NVKM_BUS_PLATFORM, - nouveau_platform_name(pdev), - dev_name(&pdev->dev), nouveau_config, - nouveau_debug, pdevice); + err = nvkm_device_new(pdev, NVKM_BUS_PLATFORM, + nouveau_platform_name(pdev), + dev_name(&pdev->dev), nouveau_config, + nouveau_debug, pdevice); if (err) - return ERR_PTR(err); + goto err_free; drm = drm_dev_alloc(&driver_platform, &pdev->dev); if (!drm) { @@ -1085,7 +1085,7 @@ nouveau_platform_device_create(struct platform_device *pdev, return drm; err_free: - nvkm_object_ref(NULL, (struct nvkm_object **)pdevice); + nvkm_device_del(pdevice); return ERR_PTR(err); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e08418436e0cd..c943a2ad26c7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -666,23 +666,6 @@ fail: return ret; } -static void -nvkm_device_dtor(struct nvkm_object *object) -{ - struct nvkm_device *device = (void *)object; - - nvkm_event_fini(&device->event); - - mutex_lock(&nv_devices_mutex); - list_del(&device->head); - mutex_unlock(&nv_devices_mutex); - - if (device->pri) - iounmap(device->pri); - - nvkm_engine_destroy(&device->engine); -} - resource_size_t nv_device_resource_start(struct nvkm_device *device, unsigned int bar) { @@ -728,16 +711,34 @@ static struct nvkm_oclass nvkm_device_oclass = { .handle = NV_ENGINE(DEVICE, 0x00), .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_device_dtor, .init = nvkm_device_init, .fini = nvkm_device_fini, }, }; +void +nvkm_device_del(struct nvkm_device **pdevice) +{ + struct nvkm_device *device = *pdevice; + if (device) { + nvkm_event_fini(&device->event); + + mutex_lock(&nv_devices_mutex); + list_del(&device->head); + mutex_unlock(&nv_devices_mutex); + + if (device->pri) + iounmap(device->pri); + + nvkm_engine_destroy(&device->engine); + *pdevice = NULL; + } +} + int -nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - int length, void **pobject) +nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, + const char *sname, const char *cfg, const char *dbg, + struct nvkm_device **pdevice) { struct nvkm_device *device; int ret = -EEXIST; @@ -748,9 +749,9 @@ nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name, goto done; } - ret = nvkm_engine_create_(NULL, NULL, &nvkm_device_oclass, true, - "DEVICE", "device", length, pobject); - device = *pobject; + ret = nvkm_engine_create(NULL, NULL, &nvkm_device_oclass, true, + "DEVICE", "device", &device); + *pdevice = device; if (ret) goto done; -- GitLab From c813d8e048740ca82b88a9d3f639bbd8095b24ac Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5464/7006] drm/nouveau/bin: punt client/device argument handling into a common helper Signed-off-by: Ben Skeggs -- GitLab From 0ac9d210a13c6eaa5492bdd27eb0add952238b8c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5465/7006] drm/nouveau/device: simplify subdev construction Replaces the piece-by-piece (in response to NV_DEVICE ctor args) device contruction with a once-off all-or-nothing approach, eliminating some tricky refcounting issues. The partial device init capability was only required by some tools, and has been moved to probe time instead. Temporarily removes a workaround for some boards where we need to fiddle with AGP registers before executing the DEVINIT scripts. A later commit in this series reinstates it. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 23 - .../drm/nouveau/include/nvkm/core/device.h | 1 + drivers/gpu/drm/nouveau/nouveau_drm.c | 32 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 501 ++++++++---------- 4 files changed, 218 insertions(+), 339 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 59d598357a43b..91e57ba855039 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -126,29 +126,6 @@ struct nv_device_v0 { __u8 version; __u8 pad01[7]; __u64 device; /* device identifier, ~0 for client default */ -#define NV_DEVICE_V0_DISABLE_IDENTIFY 0x0000000000000001ULL -#define NV_DEVICE_V0_DISABLE_MMIO 0x0000000000000002ULL -#define NV_DEVICE_V0_DISABLE_VBIOS 0x0000000000000004ULL -#define NV_DEVICE_V0_DISABLE_CORE 0x0000000000000008ULL -#define NV_DEVICE_V0_DISABLE_DISP 0x0000000000010000ULL -#define NV_DEVICE_V0_DISABLE_FIFO 0x0000000000020000ULL -#define NV_DEVICE_V0_DISABLE_GR 0x0000000100000000ULL -#define NV_DEVICE_V0_DISABLE_MPEG 0x0000000200000000ULL -#define NV_DEVICE_V0_DISABLE_ME 0x0000000400000000ULL -#define NV_DEVICE_V0_DISABLE_VP 0x0000000800000000ULL -#define NV_DEVICE_V0_DISABLE_CIPHER 0x0000001000000000ULL -#define NV_DEVICE_V0_DISABLE_BSP 0x0000002000000000ULL -#define NV_DEVICE_V0_DISABLE_MSPPP 0x0000004000000000ULL -#define NV_DEVICE_V0_DISABLE_CE0 0x0000008000000000ULL -#define NV_DEVICE_V0_DISABLE_CE1 0x0000010000000000ULL -#define NV_DEVICE_V0_DISABLE_VIC 0x0000020000000000ULL -#define NV_DEVICE_V0_DISABLE_MSENC 0x0000040000000000ULL -#define NV_DEVICE_V0_DISABLE_CE2 0x0000080000000000ULL -#define NV_DEVICE_V0_DISABLE_MSVLD 0x0000100000000000ULL -#define NV_DEVICE_V0_DISABLE_SEC 0x0000200000000000ULL -#define NV_DEVICE_V0_DISABLE_MSPDEC 0x0000400000000000ULL - __u64 disable; /* disable particular subsystems */ - __u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */ }; #define NV_DEVICE_V0_INFO 0x00 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index d44e66f34bd73..84d9cb070e864 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -212,6 +212,7 @@ enum nv_bus_type { int nvkm_device_new(void *, enum nv_bus_type type, u64 name, const char *sname, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, struct nvkm_device **); void nvkm_device_del(struct nvkm_device **); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 16c5da7db9a92..0c293fe410bf4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -327,7 +327,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev, ret = nvkm_device_new(pdev, NVKM_BUS_PCI, nouveau_pci_name(pdev), pci_name(pdev), nouveau_config, nouveau_debug, - &device); + true, true, ~0ULL, &device); if (ret) return ret; @@ -375,7 +375,6 @@ nouveau_get_hdmi_dev(struct nouveau_drm *drm) static int nouveau_drm_load(struct drm_device *dev, unsigned long flags) { - struct pci_dev *pdev = dev->pdev; struct nouveau_drm *drm; int ret; @@ -393,36 +392,10 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) nouveau_get_hdmi_dev(drm); - /* make sure AGP controller is in a consistent state before we - * (possibly) execute vbios init tables (see nouveau_agp.h) - */ - if (pdev && drm_pci_device_is_agp(dev) && dev->agp) { - const u64 enables = NV_DEVICE_V0_DISABLE_IDENTIFY | - NV_DEVICE_V0_DISABLE_MMIO; - /* dummy device object, doesn't init anything, but allows - * agp code access to registers - */ - ret = nvif_device_init(&drm->client.base.base, NULL, - NVDRM_DEVICE, NV_DEVICE, - &(struct nv_device_v0) { - .device = ~0, - .disable = ~enables, - .debug0 = ~0, - }, sizeof(struct nv_device_v0), - &drm->device); - if (ret) - goto fail_device; - - nouveau_agp_reset(drm); - nvif_device_fini(&drm->device); - } - ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE, NV_DEVICE, &(struct nv_device_v0) { .device = ~0, - .disable = 0, - .debug0 = 0, }, sizeof(struct nv_device_v0), &drm->device); if (ret) @@ -1065,7 +1038,8 @@ nouveau_platform_device_create(struct platform_device *pdev, err = nvkm_device_new(pdev, NVKM_BUS_PLATFORM, nouveau_platform_name(pdev), dev_name(&pdev->dev), nouveau_config, - nouveau_debug, pdevice); + nouveau_debug, true, true, ~0ULL, + pdevice); if (err) goto err_free; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index c943a2ad26c7c..1e4935f33842b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -73,7 +73,6 @@ nvkm_device_list(u64 *name, int size) struct nvkm_devobj { struct nvkm_parent base; - struct nvkm_object *subdev[NVDEV_SUBDEV_NR]; }; static int @@ -206,65 +205,11 @@ nvkm_devobj_map(struct nvkm_object *object, u64 *addr, u32 *size) return 0; } -static const u64 disable_map[] = { - [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS, - [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_CLK ] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_MMU] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_PMU] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_SUBDEV_FUSE] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_ENGINE_PM ] = NV_DEVICE_V0_DISABLE_CORE, - [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO, - [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO, - [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GR, - [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG, - [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME, - [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP, - [NVDEV_ENGINE_CIPHER] = NV_DEVICE_V0_DISABLE_CIPHER, - [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP, - [NVDEV_ENGINE_MSPPP] = NV_DEVICE_V0_DISABLE_MSPPP, - [NVDEV_ENGINE_CE0] = NV_DEVICE_V0_DISABLE_CE0, - [NVDEV_ENGINE_CE1] = NV_DEVICE_V0_DISABLE_CE1, - [NVDEV_ENGINE_CE2] = NV_DEVICE_V0_DISABLE_CE2, - [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC, - [NVDEV_ENGINE_MSENC] = NV_DEVICE_V0_DISABLE_MSENC, - [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP, - [NVDEV_ENGINE_MSVLD] = NV_DEVICE_V0_DISABLE_MSVLD, - [NVDEV_ENGINE_SEC] = NV_DEVICE_V0_DISABLE_SEC, - [NVDEV_SUBDEV_NR] = 0, -}; - -static void -nvkm_devobj_dtor(struct nvkm_object *object) -{ - struct nvkm_devobj *devobj = (void *)object; - int i; - - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) - nvkm_object_ref(NULL, &devobj->subdev[i]); - - nvkm_parent_destroy(&devobj->base); -} - static struct nvkm_oclass nvkm_devobj_oclass_super = { .handle = NV_DEVICE, .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_devobj_dtor, + .dtor = _nvkm_parent_dtor, .init = _nvkm_parent_init, .fini = _nvkm_parent_fini, .mthd = nvkm_devobj_mthd, @@ -289,17 +234,12 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_client *client = nv_client(parent); struct nvkm_device *device; struct nvkm_devobj *devobj; - u32 boot0, strap; - u64 disable, mmio_base, mmio_size; - void __iomem *map; - int ret, i, c; + int ret; nvif_ioctl(parent, "create device size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create device v%d device %016llx " - "disable %016llx debug0 %016llx\n", - args->v0.version, args->v0.device, - args->v0.disable, args->v0.debug0); + nvif_ioctl(parent, "create device v%d device %016llx\n", + args->v0.version, args->v0.device); } else return ret; @@ -325,226 +265,13 @@ nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - mmio_base = nv_device_resource_start(device, 0); - mmio_size = nv_device_resource_len(device, 0); - - /* translate api disable mask into internal mapping */ - disable = args->v0.debug0; - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if (args->v0.disable & disable_map[i]) - disable |= (1ULL << i); - } - - /* identify the chipset, and determine classes of subdev/engines */ - if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) && - !device->card_type) { - map = ioremap(mmio_base, 0x102000); - if (map == NULL) - return -ENOMEM; - - /* switch mmio to cpu's native endianness */ -#ifndef __BIG_ENDIAN - if (ioread32_native(map + 0x000004) != 0x00000000) { -#else - if (ioread32_native(map + 0x000004) == 0x00000000) { -#endif - iowrite32_native(0x01000001, map + 0x000004); - ioread32_native(map); - } - - /* read boot0 and strapping information */ - boot0 = ioread32_native(map + 0x000000); - strap = ioread32_native(map + 0x101000); - iounmap(map); - - /* determine chipset and derive architecture from it */ - if ((boot0 & 0x1f000000) > 0) { - device->chipset = (boot0 & 0x1ff00000) >> 20; - device->chiprev = (boot0 & 0x000000ff); - switch (device->chipset & 0x1f0) { - case 0x010: { - if (0x461 & (1 << (device->chipset & 0xf))) - device->card_type = NV_10; - else - device->card_type = NV_11; - device->chiprev = 0x00; - break; - } - case 0x020: device->card_type = NV_20; break; - case 0x030: device->card_type = NV_30; break; - case 0x040: - case 0x060: device->card_type = NV_40; break; - case 0x050: - case 0x080: - case 0x090: - case 0x0a0: device->card_type = NV_50; break; - case 0x0c0: - case 0x0d0: device->card_type = NV_C0; break; - case 0x0e0: - case 0x0f0: - case 0x100: device->card_type = NV_E0; break; - case 0x110: - case 0x120: device->card_type = GM100; break; - default: - break; - } - } else - if ((boot0 & 0xff00fff0) == 0x20004000) { - if (boot0 & 0x00f00000) - device->chipset = 0x05; - else - device->chipset = 0x04; - device->card_type = NV_04; - } - - switch (device->card_type) { - case NV_04: ret = nv04_identify(device); break; - case NV_10: - case NV_11: ret = nv10_identify(device); break; - case NV_20: ret = nv20_identify(device); break; - case NV_30: ret = nv30_identify(device); break; - case NV_40: ret = nv40_identify(device); break; - case NV_50: ret = nv50_identify(device); break; - case NV_C0: ret = gf100_identify(device); break; - case NV_E0: ret = gk104_identify(device); break; - case GM100: ret = gm100_identify(device); break; - default: - ret = -EINVAL; - break; - } - - if (ret) { - nvdev_error(device, "unknown chipset (%08x)\n", boot0); - return ret; - } - - nvdev_info(device, "NVIDIA %s (%08x)\n", device->cname, boot0); - - /* determine frequency of timing crystal */ - if ( device->card_type <= NV_10 || device->chipset < 0x17 || - (device->chipset >= 0x20 && device->chipset < 0x25)) - strap &= 0x00000040; - else - strap &= 0x00400040; - - switch (strap) { - case 0x00000000: device->crystal = 13500; break; - case 0x00000040: device->crystal = 14318; break; - case 0x00400000: device->crystal = 27000; break; - case 0x00400040: device->crystal = 25000; break; - } - } else - if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) { - device->cname = "NULL"; - device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass; - } - - if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) && !device->pri) { - device->pri = ioremap(mmio_base, mmio_size); - if (!device->pri) { - nvdev_error(device, "unable to map PRI\n"); - return -ENOMEM; - } - } - - /* ensure requested subsystems are available for use */ - for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) { - if (!(oclass = device->oclass[i]) || (disable & (1ULL << i))) - continue; - - if (device->subdev[i]) { - nvkm_object_ref(device->subdev[i], &devobj->subdev[i]); - continue; - } - -#define _(s,m) case s: \ - ret = nvkm_object_ctor(nv_object(device), NULL, oclass, NULL, \ - (s), (struct nvkm_object **)&device->m);\ - if (ret == -ENODEV) \ - continue; \ - if (ret) \ - return ret; \ - devobj->subdev[s] = (struct nvkm_object *)device->m; \ - device->subdev[s] = devobj->subdev[s]; \ - break - - switch (i) { - _(NVDEV_SUBDEV_BAR , bar); - _(NVDEV_SUBDEV_VBIOS , bios); - _(NVDEV_SUBDEV_BUS , bus); - _(NVDEV_SUBDEV_CLK , clk); - _(NVDEV_SUBDEV_DEVINIT, devinit); - _(NVDEV_SUBDEV_FB , fb); - _(NVDEV_SUBDEV_FUSE , fuse); - _(NVDEV_SUBDEV_GPIO , gpio); - _(NVDEV_SUBDEV_I2C , i2c); - _(NVDEV_SUBDEV_IBUS , ibus); - _(NVDEV_SUBDEV_INSTMEM, imem); - _(NVDEV_SUBDEV_LTC , ltc); - _(NVDEV_SUBDEV_MC , mc); - _(NVDEV_SUBDEV_MMU , mmu); - _(NVDEV_SUBDEV_MXM , mxm); - _(NVDEV_SUBDEV_PMU , pmu); - _(NVDEV_SUBDEV_THERM , therm); - _(NVDEV_SUBDEV_TIMER , timer); - _(NVDEV_SUBDEV_VOLT , volt); - _(NVDEV_ENGINE_BSP , bsp); - _(NVDEV_ENGINE_CE0 , ce[0]); - _(NVDEV_ENGINE_CE1 , ce[1]); - _(NVDEV_ENGINE_CE2 , ce[2]); - _(NVDEV_ENGINE_CIPHER , cipher); - _(NVDEV_ENGINE_DISP , disp); - _(NVDEV_ENGINE_DMAOBJ , dma); - _(NVDEV_ENGINE_FIFO , fifo); - _(NVDEV_ENGINE_GR , gr); - _(NVDEV_ENGINE_IFB , ifb); - _(NVDEV_ENGINE_ME , me); - _(NVDEV_ENGINE_MPEG , mpeg); - _(NVDEV_ENGINE_MSENC , msenc); - _(NVDEV_ENGINE_MSPDEC , mspdec); - _(NVDEV_ENGINE_MSPPP , msppp); - _(NVDEV_ENGINE_MSVLD , msvld); - _(NVDEV_ENGINE_PM , pm); - _(NVDEV_ENGINE_SEC , sec); - _(NVDEV_ENGINE_SW , sw); - _(NVDEV_ENGINE_VIC , vic); - _(NVDEV_ENGINE_VP , vp); - default: - WARN_ON(1); - continue; - } -#undef _ - - /* note: can't init *any* subdevs until devinit has been run - * due to not knowing exactly what the vbios init tables will - * mess with. devinit also can't be run until all of its - * dependencies have been created. - * - * this code delays init of any subdev until all of devinit's - * dependencies have been created, and then initialises each - * subdev in turn as they're created. - */ - while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) { - struct nvkm_object *subdev = devobj->subdev[c++]; - if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_inc(subdev); - if (ret) - return ret; - atomic_dec(&nv_object(device)->usecount); - } else - if (subdev) { - nvkm_subdev_reset(subdev); - } - } - } - return 0; } static struct nvkm_ofuncs nvkm_devobj_ofuncs = { .ctor = nvkm_devobj_ctor, - .dtor = nvkm_devobj_dtor, + .dtor = _nvkm_parent_dtor, .init = _nvkm_parent_init, .fini = _nvkm_parent_fini, .mthd = nvkm_devobj_mthd, @@ -634,19 +361,89 @@ nvkm_device_init(struct nvkm_object *object) { struct nvkm_device *device = (void *)object; struct nvkm_object *subdev; - int ret, i = 0; + int ret, i = 0, c; ret = nvkm_acpi_init(device); if (ret) goto fail; - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { + for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) { +#define _(s,m) case s: if (device->oclass[s] && !device->subdev[s]) { \ + ret = nvkm_object_ctor(nv_object(device), NULL, \ + device->oclass[s], NULL, (s), \ + (struct nvkm_object **)&device->m); \ + if (ret == -ENODEV) { \ + device->oclass[s] = NULL; \ + continue; \ + } \ + if (ret) \ + goto fail; \ + device->subdev[s] = (struct nvkm_object *)device->m; \ +} break + switch (i) { + _(NVDEV_SUBDEV_BAR , bar); + _(NVDEV_SUBDEV_VBIOS , bios); + _(NVDEV_SUBDEV_BUS , bus); + _(NVDEV_SUBDEV_CLK , clk); + _(NVDEV_SUBDEV_DEVINIT, devinit); + _(NVDEV_SUBDEV_FB , fb); + _(NVDEV_SUBDEV_FUSE , fuse); + _(NVDEV_SUBDEV_GPIO , gpio); + _(NVDEV_SUBDEV_I2C , i2c); + _(NVDEV_SUBDEV_IBUS , ibus); + _(NVDEV_SUBDEV_INSTMEM, imem); + _(NVDEV_SUBDEV_LTC , ltc); + _(NVDEV_SUBDEV_MC , mc); + _(NVDEV_SUBDEV_MMU , mmu); + _(NVDEV_SUBDEV_MXM , mxm); + _(NVDEV_SUBDEV_PMU , pmu); + _(NVDEV_SUBDEV_THERM , therm); + _(NVDEV_SUBDEV_TIMER , timer); + _(NVDEV_SUBDEV_VOLT , volt); + _(NVDEV_ENGINE_BSP , bsp); + _(NVDEV_ENGINE_CE0 , ce[0]); + _(NVDEV_ENGINE_CE1 , ce[1]); + _(NVDEV_ENGINE_CE2 , ce[2]); + _(NVDEV_ENGINE_CIPHER , cipher); + _(NVDEV_ENGINE_DISP , disp); + _(NVDEV_ENGINE_DMAOBJ , dma); + _(NVDEV_ENGINE_FIFO , fifo); + _(NVDEV_ENGINE_GR , gr); + _(NVDEV_ENGINE_IFB , ifb); + _(NVDEV_ENGINE_ME , me); + _(NVDEV_ENGINE_MPEG , mpeg); + _(NVDEV_ENGINE_MSENC , msenc); + _(NVDEV_ENGINE_MSPDEC , mspdec); + _(NVDEV_ENGINE_MSPPP , msppp); + _(NVDEV_ENGINE_MSVLD , msvld); + _(NVDEV_ENGINE_PM , pm); + _(NVDEV_ENGINE_SEC , sec); + _(NVDEV_ENGINE_SW , sw); + _(NVDEV_ENGINE_VIC , vic); + _(NVDEV_ENGINE_VP , vp); + default: + WARN_ON(1); + continue; + } +#undef _ + + /* note: can't init *any* subdevs until devinit has been run + * due to not knowing exactly what the vbios init tables will + * mess with. devinit also can't be run until all of its + * dependencies have been created. + * + * this code delays init of any subdev until all of devinit's + * dependencies have been created, and then initialises each + * subdev in turn as they're created. + */ + while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) { + struct nvkm_object *subdev = device->subdev[c++]; + if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) { ret = nvkm_object_inc(subdev); if (ret) goto fail; - } else { + } else + if (subdev) { nvkm_subdev_reset(subdev); } } @@ -720,15 +517,18 @@ void nvkm_device_del(struct nvkm_device **pdevice) { struct nvkm_device *device = *pdevice; + int i; if (device) { - nvkm_event_fini(&device->event); - mutex_lock(&nv_devices_mutex); - list_del(&device->head); - mutex_unlock(&nv_devices_mutex); + for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) + nvkm_object_ref(NULL, &device->subdev[i]); + + nvkm_event_fini(&device->event); if (device->pri) iounmap(device->pri); + list_del(&device->head); + mutex_unlock(&nv_devices_mutex); nvkm_engine_destroy(&device->engine); *pdevice = NULL; @@ -738,10 +538,15 @@ nvkm_device_del(struct nvkm_device **pdevice) int nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, const char *sname, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, struct nvkm_device **pdevice) { struct nvkm_device *device; + u64 mmio_base, mmio_size; + u32 boot0, strap; + void __iomem *map; int ret = -EEXIST; + int i; mutex_lock(&nv_devices_mutex); list_for_each_entry(device, &nv_devices, head) { @@ -775,6 +580,128 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, list_add_tail(&device->head, &nv_devices); ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); + if (ret) + goto done; + + mmio_base = nv_device_resource_start(device, 0); + mmio_size = nv_device_resource_len(device, 0); + + /* identify the chipset, and determine classes of subdev/engines */ + if (detect) { + map = ioremap(mmio_base, 0x102000); + if (ret = -ENOMEM, map == NULL) + goto done; + + /* switch mmio to cpu's native endianness */ +#ifndef __BIG_ENDIAN + if (ioread32_native(map + 0x000004) != 0x00000000) { +#else + if (ioread32_native(map + 0x000004) == 0x00000000) { +#endif + iowrite32_native(0x01000001, map + 0x000004); + ioread32_native(map); + } + + /* read boot0 and strapping information */ + boot0 = ioread32_native(map + 0x000000); + strap = ioread32_native(map + 0x101000); + iounmap(map); + + /* determine chipset and derive architecture from it */ + if ((boot0 & 0x1f000000) > 0) { + device->chipset = (boot0 & 0x1ff00000) >> 20; + device->chiprev = (boot0 & 0x000000ff); + switch (device->chipset & 0x1f0) { + case 0x010: { + if (0x461 & (1 << (device->chipset & 0xf))) + device->card_type = NV_10; + else + device->card_type = NV_11; + device->chiprev = 0x00; + break; + } + case 0x020: device->card_type = NV_20; break; + case 0x030: device->card_type = NV_30; break; + case 0x040: + case 0x060: device->card_type = NV_40; break; + case 0x050: + case 0x080: + case 0x090: + case 0x0a0: device->card_type = NV_50; break; + case 0x0c0: + case 0x0d0: device->card_type = NV_C0; break; + case 0x0e0: + case 0x0f0: + case 0x100: device->card_type = NV_E0; break; + case 0x110: + case 0x120: device->card_type = GM100; break; + default: + break; + } + } else + if ((boot0 & 0xff00fff0) == 0x20004000) { + if (boot0 & 0x00f00000) + device->chipset = 0x05; + else + device->chipset = 0x04; + device->card_type = NV_04; + } + + switch (device->card_type) { + case NV_04: ret = nv04_identify(device); break; + case NV_10: + case NV_11: ret = nv10_identify(device); break; + case NV_20: ret = nv20_identify(device); break; + case NV_30: ret = nv30_identify(device); break; + case NV_40: ret = nv40_identify(device); break; + case NV_50: ret = nv50_identify(device); break; + case NV_C0: ret = gf100_identify(device); break; + case NV_E0: ret = gk104_identify(device); break; + case GM100: ret = gm100_identify(device); break; + default: + ret = -EINVAL; + break; + } + + if (ret) { + nvdev_error(device, "unknown chipset (%08x)\n", boot0); + goto done; + } + + nvdev_info(device, "NVIDIA %s (%08x)\n", device->cname, boot0); + + /* determine frequency of timing crystal */ + if ( device->card_type <= NV_10 || device->chipset < 0x17 || + (device->chipset >= 0x20 && device->chipset < 0x25)) + strap &= 0x00000040; + else + strap &= 0x00400040; + + switch (strap) { + case 0x00000000: device->crystal = 13500; break; + case 0x00000040: device->crystal = 14318; break; + case 0x00400000: device->crystal = 27000; break; + case 0x00400040: device->crystal = 25000; break; + } + } else { + device->cname = "NULL"; + device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass; + } + + if (mmio) { + device->pri = ioremap(mmio_base, mmio_size); + if (!device->pri) { + nvdev_error(device, "unable to map PRI\n"); + return -ENOMEM; + } + } + + /* disable subdevs that aren't required (used by tools) */ + for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + if (!(subdev_mask & (1ULL << i))) + device->oclass[i] = NULL; + } + done: mutex_unlock(&nv_devices_mutex); return ret; -- GitLab From a1bfb29a33521efa6b1714589bf68cb4afebacb1 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5466/7006] drm/nouveau/device: split user device implementation out on its own Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/device/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 226 +--------------- .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 2 + .../gpu/drm/nouveau/nvkm/engine/device/user.c | 247 ++++++++++++++++++ 4 files changed, 254 insertions(+), 223 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/user.c diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild index de1bf092b2b2a..47c8fe8f9e3e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild @@ -1,6 +1,8 @@ nvkm-y += nvkm/engine/device/acpi.o nvkm-y += nvkm/engine/device/base.o nvkm-y += nvkm/engine/device/ctrl.o +nvkm-y += nvkm/engine/device/user.o + nvkm-y += nvkm/engine/device/nv04.o nvkm-y += nvkm/engine/device/nv10.o nvkm-y += nvkm/engine/device/nv20.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 1e4935f33842b..5f64349c9623d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -24,16 +24,10 @@ #include "priv.h" #include "acpi.h" -#include -#include #include -#include -#include -#include -#include +#include -#include -#include +#include static DEFINE_MUTEX(nv_devices_mutex); static LIST_HEAD(nv_devices); @@ -67,220 +61,6 @@ nvkm_device_list(u64 *name, int size) return nr; } -/****************************************************************************** - * nvkm_devobj (0x0080): class implementation - *****************************************************************************/ - -struct nvkm_devobj { - struct nvkm_parent base; -}; - -static int -nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size) -{ - struct nvkm_device *device = nv_device(object); - struct nvkm_fb *fb = nvkm_fb(device); - struct nvkm_instmem *imem = nvkm_instmem(device); - union { - struct nv_device_info_v0 v0; - } *args = data; - int ret; - - nvif_ioctl(object, "device info size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "device info vers %d\n", args->v0.version); - } else - return ret; - - switch (device->chipset) { - case 0x01a: - case 0x01f: - case 0x04c: - case 0x04e: - case 0x063: - case 0x067: - case 0x068: - case 0x0aa: - case 0x0ac: - case 0x0af: - args->v0.platform = NV_DEVICE_INFO_V0_IGP; - break; - default: - if (device->pdev) { - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP)) - args->v0.platform = NV_DEVICE_INFO_V0_AGP; - else - if (pci_is_pcie(device->pdev)) - args->v0.platform = NV_DEVICE_INFO_V0_PCIE; - else - args->v0.platform = NV_DEVICE_INFO_V0_PCI; - } else { - args->v0.platform = NV_DEVICE_INFO_V0_SOC; - } - break; - } - - switch (device->card_type) { - case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break; - case NV_10: - case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break; - case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break; - case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break; - case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break; - case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break; - case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break; - case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break; - case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break; - default: - args->v0.family = 0; - break; - } - - args->v0.chipset = device->chipset; - args->v0.revision = device->chiprev; - if (fb && fb->ram) - args->v0.ram_size = args->v0.ram_user = fb->ram->size; - else - args->v0.ram_size = args->v0.ram_user = 0; - if (imem && args->v0.ram_size > 0) - args->v0.ram_user = args->v0.ram_user - imem->reserved; - - return 0; -} - -static int -nvkm_devobj_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - switch (mthd) { - case NV_DEVICE_V0_INFO: - return nvkm_devobj_info(object, data, size); - default: - break; - } - return -EINVAL; -} - -static u8 -nvkm_devobj_rd08(struct nvkm_object *object, u64 addr) -{ - return nvkm_rd08(object->engine->subdev.device, addr); -} - -static u16 -nvkm_devobj_rd16(struct nvkm_object *object, u64 addr) -{ - return nvkm_rd16(object->engine->subdev.device, addr); -} - -static u32 -nvkm_devobj_rd32(struct nvkm_object *object, u64 addr) -{ - return nvkm_rd32(object->engine->subdev.device, addr); -} - -static void -nvkm_devobj_wr08(struct nvkm_object *object, u64 addr, u8 data) -{ - nvkm_wr08(object->engine->subdev.device, addr, data); -} - -static void -nvkm_devobj_wr16(struct nvkm_object *object, u64 addr, u16 data) -{ - nvkm_wr16(object->engine->subdev.device, addr, data); -} - -static void -nvkm_devobj_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - nvkm_wr32(object->engine->subdev.device, addr, data); -} - -static int -nvkm_devobj_map(struct nvkm_object *object, u64 *addr, u32 *size) -{ - struct nvkm_device *device = nv_device(object); - *addr = nv_device_resource_start(device, 0); - *size = nv_device_resource_len(device, 0); - return 0; -} - -static struct nvkm_oclass -nvkm_devobj_oclass_super = { - .handle = NV_DEVICE, - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = _nvkm_parent_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, - .mthd = nvkm_devobj_mthd, - .map = nvkm_devobj_map, - .rd08 = nvkm_devobj_rd08, - .rd16 = nvkm_devobj_rd16, - .rd32 = nvkm_devobj_rd32, - .wr08 = nvkm_devobj_wr08, - .wr16 = nvkm_devobj_wr16, - .wr32 = nvkm_devobj_wr32, - } -}; - -static int -nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv_device_v0 v0; - } *args = data; - struct nvkm_client *client = nv_client(parent); - struct nvkm_device *device; - struct nvkm_devobj *devobj; - int ret; - - nvif_ioctl(parent, "create device size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create device v%d device %016llx\n", - args->v0.version, args->v0.device); - } else - return ret; - - /* give priviledged clients register access */ - if (client->super) - oclass = &nvkm_devobj_oclass_super; - - /* find the device subdev that matches what the client requested */ - device = client->device; - if (args->v0.device != ~0) { - device = nvkm_device_find(args->v0.device); - if (!device) - return -ENODEV; - } - - ret = nvkm_parent_create(parent, nv_object(device), oclass, 0, - nvkm_control_oclass, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_FIFO) | - (1ULL << NVDEV_ENGINE_DISP) | - (1ULL << NVDEV_ENGINE_PM), &devobj); - *pobject = nv_object(devobj); - if (ret) - return ret; - - return 0; -} - -static struct nvkm_ofuncs -nvkm_devobj_ofuncs = { - .ctor = nvkm_devobj_ctor, - .dtor = _nvkm_parent_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, - .mthd = nvkm_devobj_mthd, -}; - -/****************************************************************************** - * nvkm_device: engine functions - *****************************************************************************/ - struct nvkm_device * nv_device(void *obj) { @@ -301,7 +81,7 @@ nv_device(void *obj) static struct nvkm_oclass nvkm_device_sclass[] = { - { 0x0080, &nvkm_devobj_ofuncs }, + { 0x0080, &nvkm_udevice_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 8d3590e7bd875..7adba2c70a638 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -13,4 +13,6 @@ int nv50_identify(struct nvkm_device *); int gf100_identify(struct nvkm_device *); int gk104_identify(struct nvkm_device *); int gm100_identify(struct nvkm_device *); + +extern struct nvkm_ofuncs nvkm_udevice_ofuncs; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c new file mode 100644 index 0000000000000..16bb0410382f7 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -0,0 +1,247 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +#include +#include +#include + +#include +#include + +struct nvkm_udevice { + struct nvkm_parent base; + struct nvkm_device *device; +}; + +static int +nvkm_udevice_info(struct nvkm_object *object, void *data, u32 size) +{ + struct nvkm_udevice *udev = (void *)object; + struct nvkm_device *device = udev->device; + struct nvkm_fb *fb = device->fb; + struct nvkm_instmem *imem = device->imem; + union { + struct nv_device_info_v0 v0; + } *args = data; + int ret; + + nvif_ioctl(object, "device info size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "device info vers %d\n", args->v0.version); + } else + return ret; + + switch (device->chipset) { + case 0x01a: + case 0x01f: + case 0x04c: + case 0x04e: + case 0x063: + case 0x067: + case 0x068: + case 0x0aa: + case 0x0ac: + case 0x0af: + args->v0.platform = NV_DEVICE_INFO_V0_IGP; + break; + default: + if (device->pdev) { + if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP)) + args->v0.platform = NV_DEVICE_INFO_V0_AGP; + else + if (pci_is_pcie(device->pdev)) + args->v0.platform = NV_DEVICE_INFO_V0_PCIE; + else + args->v0.platform = NV_DEVICE_INFO_V0_PCI; + } else { + args->v0.platform = NV_DEVICE_INFO_V0_SOC; + } + break; + } + + switch (device->card_type) { + case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break; + case NV_10: + case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break; + case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break; + case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break; + case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break; + case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break; + case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break; + case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break; + case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break; + default: + args->v0.family = 0; + break; + } + + args->v0.chipset = device->chipset; + args->v0.revision = device->chiprev; + if (fb && fb->ram) + args->v0.ram_size = args->v0.ram_user = fb->ram->size; + else + args->v0.ram_size = args->v0.ram_user = 0; + if (imem && args->v0.ram_size > 0) + args->v0.ram_user = args->v0.ram_user - imem->reserved; + + return 0; +} + +static int +nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + switch (mthd) { + case NV_DEVICE_V0_INFO: + return nvkm_udevice_info(object, data, size); + default: + break; + } + return -EINVAL; +} + +static u8 +nvkm_udevice_rd08(struct nvkm_object *object, u64 addr) +{ + struct nvkm_udevice *udev = (void *)object; + return nvkm_rd08(udev->device, addr); +} + +static u16 +nvkm_udevice_rd16(struct nvkm_object *object, u64 addr) +{ + struct nvkm_udevice *udev = (void *)object; + return nvkm_rd16(udev->device, addr); +} + +static u32 +nvkm_udevice_rd32(struct nvkm_object *object, u64 addr) +{ + struct nvkm_udevice *udev = (void *)object; + return nvkm_rd32(udev->device, addr); +} + +static void +nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data) +{ + struct nvkm_udevice *udev = (void *)object; + nvkm_wr08(udev->device, addr, data); +} + +static void +nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data) +{ + struct nvkm_udevice *udev = (void *)object; + nvkm_wr16(udev->device, addr, data); +} + +static void +nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nvkm_udevice *udev = (void *)object; + nvkm_wr32(udev->device, addr, data); +} + +static int +nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nvkm_udevice *udev = (void *)object; + struct nvkm_device *device = udev->device; + *addr = nv_device_resource_start(device, 0); + *size = nv_device_resource_len(device, 0); + return 0; +} + +static struct nvkm_oclass +nvkm_udevice_oclass_super = { + .handle = NV_DEVICE, + .ofuncs = &(struct nvkm_ofuncs) { + .dtor = _nvkm_parent_dtor, + .init = _nvkm_parent_init, + .fini = _nvkm_parent_fini, + .mthd = nvkm_udevice_mthd, + .map = nvkm_udevice_map, + .rd08 = nvkm_udevice_rd08, + .rd16 = nvkm_udevice_rd16, + .rd32 = nvkm_udevice_rd32, + .wr08 = nvkm_udevice_wr08, + .wr16 = nvkm_udevice_wr16, + .wr32 = nvkm_udevice_wr32, + } +}; + +static int +nvkm_udevice_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv_device_v0 v0; + } *args = data; + struct nvkm_client *client = nvkm_client(parent); + struct nvkm_device *device; + struct nvkm_udevice *udev; + int ret; + + nvif_ioctl(parent, "create device size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create device v%d device %016llx\n", + args->v0.version, args->v0.device); + } else + return ret; + + /* give priviledged clients register access */ + if (client->super) + oclass = &nvkm_udevice_oclass_super; + + /* find the device subdev that matches what the client requested */ + device = client->device; + if (args->v0.device != ~0) { + device = nvkm_device_find(args->v0.device); + if (!device) + return -ENODEV; + } + + ret = nvkm_parent_create(parent, nv_object(device), oclass, 0, + nvkm_control_oclass, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_FIFO) | + (1ULL << NVDEV_ENGINE_DISP) | + (1ULL << NVDEV_ENGINE_PM), &udev); + *pobject = nv_object(udev); + if (ret) + return ret; + + udev->device = device; + return 0; +} + +struct nvkm_ofuncs +nvkm_udevice_ofuncs = { + .ctor = nvkm_udevice_ctor, + .dtor = _nvkm_parent_dtor, + .init = _nvkm_parent_init, + .fini = _nvkm_parent_fini, + .mthd = nvkm_udevice_mthd, +}; -- GitLab From a1e88736221d2e971726931c449ed7d0af31755b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5467/7006] drm/nouveau/device: decouple from engine machinery Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 8 ++- drivers/gpu/drm/nouveau/nvkm/core/client.c | 11 ++-- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 9 +--- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 37 ++++++------- .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 2 - .../gpu/drm/nouveau/nvkm/engine/device/user.c | 53 ++++++++++++++++--- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 28 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 9 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 4 +- 10 files changed, 104 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 84d9cb070e864..875c247d4cfc4 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -4,7 +4,6 @@ #include enum nvkm_devidx { - NVDEV_ENGINE_DEVICE, NVDEV_SUBDEV_VBIOS, /* All subdevs from DEVINIT to DEVINIT_LAST will be created before @@ -65,7 +64,10 @@ enum nvkm_devidx { struct nvkm_device { struct nvkm_engine engine; + struct list_head head; + struct mutex mutex; + int refcount; struct pci_dev *pdev; struct platform_device *platformdev; @@ -210,11 +212,15 @@ enum nv_bus_type { NVKM_BUS_PLATFORM, }; +extern struct nvkm_ofuncs nvkm_udevice_ofuncs; + int nvkm_device_new(void *, enum nv_bus_type type, u64 name, const char *sname, const char *cfg, const char *dbg, bool detect, bool mmio, u64 subdev_mask, struct nvkm_device **); void nvkm_device_del(struct nvkm_device **); +int nvkm_device_init(struct nvkm_device *); +int nvkm_device_fini(struct nvkm_device *, bool suspend); /* device logging */ #define nvdev_printk_(d,l,p,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index cd8e51f74aa17..5a1ddb3433de2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -226,6 +226,12 @@ nvkm_client_del(struct nvkm_client **pclient) } } +static struct nvkm_oclass +nvkm_client_sclass[] = { + { NV_DEVICE, &nvkm_udevice_ofuncs }, + {} +}; + int nvkm_client_new(const char *name, u64 devname, const char *cfg, const char *dbg, struct nvkm_client **pclient) @@ -239,9 +245,8 @@ nvkm_client_new(const char *name, u64 devname, const char *cfg, return -ENODEV; ret = nvkm_namedb_create(NULL, NULL, &nvkm_client_oclass, - NV_CLIENT_CLASS, NULL, - (1ULL << NVDEV_ENGINE_DEVICE), - &client); + NV_CLIENT_CLASS, nvkm_client_sclass, + 0, &client); *pclient = client; if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index f99b446c1e10f..6e26833235707 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -216,7 +216,6 @@ nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu, u32 size, u32 align, u32 flags, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_object *engine = parent; struct nvkm_gpuobj_class args = { .pargpu = pargpu, .size = size, @@ -224,12 +223,8 @@ nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu, .flags = flags, }; - if (!nv_iclass(engine, NV_SUBDEV_CLASS)) - engine = &engine->engine->subdev.object; - BUG_ON(engine == NULL); - - return nvkm_object_ctor(parent, engine, &_nvkm_gpuobj_oclass, - &args, sizeof(args), + return nvkm_object_ctor(parent, &parent->engine->subdev.object, + &_nvkm_gpuobj_oclass, &args, sizeof(args), (struct nvkm_object **)pgpuobj); } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index da5ed8c109d9e..25f3503cd37a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -31,7 +31,7 @@ nvkm_subdev(void *obj, int idx) struct nvkm_object *object = nv_object(obj); while (object && !nv_iclass(object, NV_SUBDEV_CLASS)) object = object->parent; - if (object == NULL || nv_subidx(nv_subdev(object)) != idx) + if (object == NULL || !object->parent || nv_subidx(nv_subdev(object)) != idx) object = nv_device(obj)->subdev[idx]; return object ? nv_subdev(object) : NULL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 5f64349c9623d..479181c839b48 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -61,13 +61,24 @@ nvkm_device_list(u64 *name, int size) return nr; } +#include + struct nvkm_device * nv_device(void *obj) { struct nvkm_object *device = nv_object(obj); + if (device->engine == NULL) { - while (device && device->parent) + while (device && device->parent) { + if (nv_mclass(device) == 0x0080) { + struct { + struct nvkm_parent base; + struct nvkm_device *device; + } *udevice = (void *)device; + return udevice->device; + } device = device->parent; + } } else { device = &nv_object(obj)->engine->subdev.object; if (device && device->parent) @@ -79,12 +90,6 @@ nv_device(void *obj) return (void *)device; } -static struct nvkm_oclass -nvkm_device_sclass[] = { - { 0x0080, &nvkm_udevice_ofuncs }, - {} -}; - static int nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -103,10 +108,9 @@ nvkm_device_event_func = { .ctor = nvkm_device_event_ctor, }; -static int -nvkm_device_fini(struct nvkm_object *object, bool suspend) +int +nvkm_device_fini(struct nvkm_device *device, bool suspend) { - struct nvkm_device *device = (void *)object; struct nvkm_object *subdev; int ret, i; @@ -136,10 +140,9 @@ fail: return ret; } -static int -nvkm_device_init(struct nvkm_object *object) +int +nvkm_device_init(struct nvkm_device *device) { - struct nvkm_device *device = (void *)object; struct nvkm_object *subdev; int ret, i = 0, c; @@ -147,7 +150,7 @@ nvkm_device_init(struct nvkm_object *object) if (ret) goto fail; - for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) { + for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) { #define _(s,m) case s: if (device->oclass[s] && !device->subdev[s]) { \ ret = nvkm_object_ctor(nv_object(device), NULL, \ device->oclass[s], NULL, (s), \ @@ -286,10 +289,7 @@ nv_device_get_irq(struct nvkm_device *device, bool stall) static struct nvkm_oclass nvkm_device_oclass = { - .handle = NV_ENGINE(DEVICE, 0x00), .ofuncs = &(struct nvkm_ofuncs) { - .init = nvkm_device_init, - .fini = nvkm_device_fini, }, }; @@ -356,7 +356,6 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, device->name = sname; nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE"); - nv_engine(device)->sclass = nvkm_device_sclass; list_add_tail(&device->head, &nv_devices); ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); @@ -482,6 +481,8 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, device->oclass[i] = NULL; } + atomic_set(&device->engine.subdev.object.usecount, 2); + mutex_init(&device->mutex); done: mutex_unlock(&nv_devices_mutex); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 7adba2c70a638..8d3590e7bd875 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -13,6 +13,4 @@ int nv50_identify(struct nvkm_device *); int gf100_identify(struct nvkm_device *); int gk104_identify(struct nvkm_device *); int gm100_identify(struct nvkm_device *); - -extern struct nvkm_ofuncs nvkm_udevice_ofuncs; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 16bb0410382f7..4867bbd0788f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -173,13 +173,55 @@ nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size) return 0; } +static int +nvkm_udevice_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_udevice *udev = (void *)object; + struct nvkm_device *device = udev->device; + int ret = 0; + + mutex_lock(&device->mutex); + if (!--device->refcount) { + ret = nvkm_device_fini(device, suspend); + if (ret && suspend) { + device->refcount++; + goto done; + } + } + +done: + mutex_unlock(&device->mutex); + return ret; +} + +static int +nvkm_udevice_init(struct nvkm_object *object) +{ + struct nvkm_udevice *udev = (void *)object; + struct nvkm_device *device = udev->device; + int ret = 0; + + mutex_lock(&device->mutex); + if (!device->refcount++) { + ret = nvkm_device_init(device); + if (ret) { + device->refcount--; + goto done; + } + } + +done: + mutex_unlock(&device->mutex); + return ret; +} + static struct nvkm_oclass nvkm_udevice_oclass_super = { .handle = NV_DEVICE, .ofuncs = &(struct nvkm_ofuncs) { .dtor = _nvkm_parent_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, + .init = nvkm_udevice_init, + .fini = nvkm_udevice_fini, .mthd = nvkm_udevice_mthd, .map = nvkm_udevice_map, .rd08 = nvkm_udevice_rd08, @@ -223,8 +265,7 @@ nvkm_udevice_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -ENODEV; } - ret = nvkm_parent_create(parent, nv_object(device), oclass, 0, - nvkm_control_oclass, + ret = nvkm_parent_create(parent, NULL, oclass, 0, nvkm_control_oclass, (1ULL << NVDEV_ENGINE_DMAOBJ) | (1ULL << NVDEV_ENGINE_FIFO) | (1ULL << NVDEV_ENGINE_DISP) | @@ -241,7 +282,7 @@ struct nvkm_ofuncs nvkm_udevice_ofuncs = { .ctor = nvkm_udevice_ctor, .dtor = _nvkm_parent_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, + .init = nvkm_udevice_init, + .fini = nvkm_udevice_fini, .mthd = nvkm_udevice_mthd, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 5079ea3df4bfb..9d7ac6a15bd71 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -26,7 +26,7 @@ #include "outpdp.h" #include -#include +#include #include #include #include @@ -1292,8 +1292,8 @@ nv50_disp_data_ctor(struct nvkm_object *parent, struct nvkm_object **pobject) { struct nv50_disp *disp = (void *)engine; - struct nvkm_engctx *ectx; - int ret = -EBUSY; + struct nvkm_gpuobj *gpuobj; + int ret; /* no context needed for channel objects... */ if (nv_mclass(parent) != NV_DEVICE) { @@ -1303,26 +1303,26 @@ nv50_disp_data_ctor(struct nvkm_object *parent, } /* allocate display hardware to client */ + ret = nvkm_gpuobj_create(parent, engine, oclass, 0, NULL, + 0x10000, 0x10000, NVOBJ_FLAG_HEAP, + &gpuobj); + *pobject = nv_object(gpuobj); mutex_lock(&nv_subdev(disp)->mutex); - if (list_empty(&nv_engine(disp)->contexts)) { - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, - 0x10000, NVOBJ_FLAG_HEAP, &ectx); - *pobject = nv_object(ectx); - } + if (!list_empty(&nv_engine(disp)->contexts)) + ret = -EBUSY; mutex_unlock(&nv_subdev(disp)->mutex); return ret; } struct nvkm_oclass nv50_disp_cclass = { - .handle = NV_ENGCTX(DISP, 0x50), .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv50_disp_data_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, + .dtor = _nvkm_gpuobj_dtor, + .init = _nvkm_gpuobj_init, + .fini = _nvkm_gpuobj_fini, + .rd32 = _nvkm_gpuobj_rd32, + .wr32 = _nvkm_gpuobj_wr32, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index ba1623de8bcb9..b75395bf8ffa3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -639,7 +639,7 @@ nvkm_perfctx_dtor(struct nvkm_object *object) struct nvkm_perfctx *ctx = (void *)object; mutex_lock(&nv_subdev(pm)->mutex); - nvkm_engctx_destroy(&ctx->base); + nvkm_gpuobj_destroy(&ctx->base); if (pm->context == ctx) pm->context = NULL; mutex_unlock(&nv_subdev(pm)->mutex); @@ -661,7 +661,7 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 1; } - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0, 0, 0, &ctx); + ret = nvkm_gpuobj_create(parent, engine, oclass, 0, NULL, 0, 0, 0, &ctx); *pobject = nv_object(ctx); if (ret) return ret; @@ -678,12 +678,11 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass nvkm_pm_cclass = { - .handle = NV_ENGCTX(PM, 0x00), .ofuncs = &(struct nvkm_ofuncs) { .ctor = nvkm_perfctx_ctor, .dtor = nvkm_perfctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, + .init = _nvkm_gpuobj_init, + .fini = _nvkm_gpuobj_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 69b72780b34b9..2af3a50130963 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -14,10 +14,10 @@ struct nvkm_perfctr { extern struct nvkm_oclass nvkm_pm_sclass[]; -#include +#include struct nvkm_perfctx { - struct nvkm_engctx base; + struct nvkm_gpuobj base; }; extern struct nvkm_oclass nvkm_pm_cclass; -- GitLab From 493f189dc0cbbe9bde8074fb49ca777ba1ef292c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5468/7006] drm/nouveau/object: store object type data outside of handle Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h | 2 +- drivers/gpu/drm/nouveau/include/nvkm/core/engine.h | 2 +- drivers/gpu/drm/nouveau/include/nvkm/core/object.h | 6 +++--- drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h | 2 +- drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h | 2 +- drivers/gpu/drm/nouveau/nvkm/core/object.c | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h index e4bf2982c1902..aa465def4f95f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h @@ -4,7 +4,7 @@ #include -#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng)) +#define NV_ENGCTX_(eng,var) (((var) << 8) | (eng)) #define NV_ENGCTX(name,var) NV_ENGCTX_(NVDEV_ENGINE_##name, (var)) struct nvkm_engctx { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 67e3afcbdd970..0b5f05aec2dff 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -2,7 +2,7 @@ #define __NVKM_ENGINE_H__ #include -#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng)) +#define NV_ENGINE_(eng,var) (((var) << 8) | (eng)) #define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var)) struct nvkm_engine { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 04e8a62ade32f..ef0ff9e1a9480 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -11,10 +11,10 @@ #define NV_MEMOBJ_CLASS 0x04000000 #define NV_GPUOBJ_CLASS 0x02000000 #define NV_ENGCTX_CLASS 0x01000000 -#define NV_OBJECT_CLASS 0x0000ffff struct nvkm_object { struct nvkm_oclass *oclass; + u32 pclass; struct nvkm_object *parent; struct nvkm_engine *engine; atomic_t refcount; @@ -70,8 +70,8 @@ struct nvkm_oclass { #define nv_oclass(o) nv_object(o)->oclass #define nv_hclass(o) nv_oclass(o)->handle -#define nv_iclass(o,i) (nv_hclass(o) & (i)) -#define nv_mclass(o) nv_iclass(o, NV_OBJECT_CLASS) +#define nv_iclass(o,i) (nv_object(o)->pclass & (i)) +#define nv_mclass(o) nv_oclass(o)->handle static inline struct nvkm_object * nv_pclass(struct nvkm_object *parent, u32 oclass) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index 8e762830902d1..ce5f1b93ef9aa 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -2,7 +2,7 @@ #define __NVKM_SUBDEV_H__ #include -#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub)) +#define NV_SUBDEV_(sub,var) (((var) << 8) | (sub)) #define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var)) struct nvkm_subdev { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 3e77c924434b3..0ec929e00b36e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -50,7 +50,7 @@ struct nvkm_fifo_base { }; #define nvkm_fifo_context_create(p,e,c,g,s,a,f,d) \ - nvkm_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d)) + nvkm_gpuobj_create((p), (e), (c), NV_ENGCTX_CLASS, (g), (s), (a), (f), (d)) #define nvkm_fifo_context_destroy(p) \ nvkm_gpuobj_destroy(&(p)->gpuobj) #define nvkm_fifo_context_init(p) \ diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index b32a041636a40..98ba58ec1d394 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -107,7 +107,7 @@ nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_object_ref(parent, &object->parent); nvkm_object_ref(engine, (struct nvkm_object **)&object->engine); object->oclass = oclass; - object->oclass->handle |= pclass; + object->pclass = pclass; atomic_set(&object->refcount, 1); atomic_set(&object->usecount, 0); -- GitLab From 102b49da15834c1d2ba508457fdf69b3d07c6fee Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5469/7006] drm/nouveau/parent: remove some (now) unnecessary special-case handling Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/parent.h | 8 +-- drivers/gpu/drm/nouveau/nvkm/core/parent.c | 55 +++++-------------- 2 files changed, 14 insertions(+), 49 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h index 57932131b601c..2e5266fa75841 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h @@ -2,16 +2,10 @@ #define __NVKM_PARENT_H__ #include -struct nvkm_sclass { - struct nvkm_sclass *sclass; - struct nvkm_engine *engine; - struct nvkm_oclass *oclass; -}; - struct nvkm_parent { struct nvkm_object object; - struct nvkm_sclass *sclass; + struct nvkm_oclass *sclass; u64 engine; int (*context_attach)(struct nvkm_object *, struct nvkm_object *); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c index dd56cd1eeb389..5c75c64f22709 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/parent.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/parent.c @@ -30,35 +30,27 @@ nvkm_parent_sclass(struct nvkm_object *parent, u16 handle, struct nvkm_object **pengine, struct nvkm_oclass **poclass) { - struct nvkm_sclass *sclass; + struct nvkm_oclass *sclass, *oclass; struct nvkm_engine *engine; - struct nvkm_oclass *oclass; u64 mask; + int i; sclass = nv_parent(parent)->sclass; - while (sclass) { - if ((sclass->oclass->handle & 0xffff) == handle) { + while ((oclass = sclass++) && oclass->ofuncs) { + if (oclass->handle == handle) { *pengine = &parent->engine->subdev.object; - *poclass = sclass->oclass; + *poclass = oclass; return 0; } - - sclass = sclass->sclass; } mask = nv_parent(parent)->engine; - while (mask) { - int i = __ffs64(mask); - - if (nv_iclass(parent, NV_CLIENT_CLASS)) - engine = nv_engine(nv_client(parent)->device); - else - engine = nvkm_engine(parent, i); - + while (i = __ffs64(mask), mask) { + engine = nvkm_engine(parent, i); if (engine) { oclass = engine->sclass; while (oclass->ofuncs) { - if ((oclass->handle & 0xffff) == handle) { + if (oclass->handle == handle) { *pengine = nv_object(engine); *poclass = oclass; return 0; @@ -76,17 +68,15 @@ nvkm_parent_sclass(struct nvkm_object *parent, u16 handle, int nvkm_parent_lclass(struct nvkm_object *parent, u32 *lclass, int size) { - struct nvkm_sclass *sclass; + struct nvkm_oclass *sclass, *oclass; struct nvkm_engine *engine; - struct nvkm_oclass *oclass; int nr = -1, i; u64 mask; sclass = nv_parent(parent)->sclass; - while (sclass) { + while ((oclass = sclass++) && oclass->ofuncs) { if (++nr < size) - lclass[nr] = sclass->oclass->handle & 0xffff; - sclass = sclass->sclass; + lclass[nr] = oclass->handle; } mask = nv_parent(parent)->engine; @@ -95,7 +85,7 @@ nvkm_parent_lclass(struct nvkm_object *parent, u32 *lclass, int size) if (engine && (oclass = engine->sclass)) { while (oclass->ofuncs) { if (++nr < size) - lclass[nr] = oclass->handle & 0xffff; + lclass[nr] = oclass->handle; oclass++; } } @@ -113,7 +103,6 @@ nvkm_parent_create_(struct nvkm_object *parent, struct nvkm_object *engine, int size, void **pobject) { struct nvkm_parent *object; - struct nvkm_sclass *nclass; int ret; ret = nvkm_object_create_(parent, engine, oclass, pclass | @@ -122,18 +111,7 @@ nvkm_parent_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - while (sclass && sclass->ofuncs) { - nclass = kzalloc(sizeof(*nclass), GFP_KERNEL); - if (!nclass) - return -ENOMEM; - - nclass->sclass = object->sclass; - object->sclass = nclass; - nclass->engine = engine ? nv_engine(engine) : NULL; - nclass->oclass = sclass; - sclass++; - } - + object->sclass = sclass; object->engine = engcls; return 0; } @@ -141,13 +119,6 @@ nvkm_parent_create_(struct nvkm_object *parent, struct nvkm_object *engine, void nvkm_parent_destroy(struct nvkm_parent *parent) { - struct nvkm_sclass *sclass; - - while ((sclass = parent->sclass)) { - parent->sclass = sclass->sclass; - kfree(sclass); - } - nvkm_object_destroy(&parent->object); } -- GitLab From 4e7e62d607a711bc8e8576a0fc7d8f242d25c9b3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5470/7006] drm/nouveau/client: store default device by handle, not reference Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/client.h | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- drivers/gpu/drm/nouveau/nvkm/core/client.c | 11 ++--------- drivers/gpu/drm/nouveau/nvkm/engine/device/user.c | 10 +++++----- 4 files changed, 9 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 473d66b22aeb0..f79f9025d1c56 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -5,7 +5,7 @@ struct nvkm_client { struct nvkm_namedb namedb; struct nvkm_handle *root; - struct nvkm_device *device; + u64 device; char name[32]; u32 debug; struct nvkm_vm *vm; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 0c293fe410bf4..86f567d4e5cd2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -507,7 +507,7 @@ nouveau_drm_device_remove(struct drm_device *dev) dev->irq_enabled = false; client = nvxx_client(&drm->client.base); - device = client->device; + device = nvkm_device_find(client->device); drm_put_dev(dev); nvkm_device_del(&device); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 5a1ddb3433de2..7615cdd752949 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -219,7 +219,6 @@ nvkm_client_del(struct nvkm_client **pclient) nvkm_client_fini(client, false); for (i = 0; i < ARRAY_SIZE(client->notify); i++) nvkm_client_notify_del(client, i); - nvkm_object_ref(NULL, (struct nvkm_object **)&client->device); nvkm_handle_destroy(client->root); nvkm_namedb_destroy(&client->namedb); *pclient = NULL; @@ -233,17 +232,12 @@ nvkm_client_sclass[] = { }; int -nvkm_client_new(const char *name, u64 devname, const char *cfg, +nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, struct nvkm_client **pclient) { - struct nvkm_device *device; struct nvkm_client *client; int ret; - device = nvkm_device_find(devname); - if (!device) - return -ENODEV; - ret = nvkm_namedb_create(NULL, NULL, &nvkm_client_oclass, NV_CLIENT_CLASS, nvkm_client_sclass, 0, &client); @@ -259,8 +253,7 @@ nvkm_client_new(const char *name, u64 devname, const char *cfg, /* prevent init/fini being called, os in in charge of this */ atomic_set(&nv_object(client)->usecount, 2); - nvkm_object_ref(&device->engine.subdev.object, - (struct nvkm_object **)&client->device); + client->device = device; snprintf(client->name, sizeof(client->name), "%s", name); client->debug = nvkm_dbgopt(dbg, "CLIENT"); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 4867bbd0788f3..c16bde41c279a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -258,12 +258,12 @@ nvkm_udevice_ctor(struct nvkm_object *parent, struct nvkm_object *engine, oclass = &nvkm_udevice_oclass_super; /* find the device subdev that matches what the client requested */ - device = client->device; - if (args->v0.device != ~0) { + if (args->v0.device != ~0) device = nvkm_device_find(args->v0.device); - if (!device) - return -ENODEV; - } + else + device = nvkm_device_find(client->device); + if (!device) + return -ENODEV; ret = nvkm_parent_create(parent, NULL, oclass, 0, nvkm_control_oclass, (1ULL << NVDEV_ENGINE_DMAOBJ) | -- GitLab From a01ca78c8f118e5a24f1527ecf078ab56ddd4805 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:15 +1000 Subject: [PATCH 5471/7006] drm/nouveau/nvif: simplify and tidy library interfaces A variety of tweaks to the NVIF library interfaces, mostly ripping out things that turned out to be not so useful. - Removed refcounting from nvif_object, callers are expected to not be stupid instead. - nvif_client is directly reachable from anything derived from nvif_object, removing the need for heuristics to locate it - _new() versions of interfaces, that allocate memory for the object they construct, have been removed. The vast majority of callers used the embedded _init() interfaces. - No longer storing constructor arguments (and the data returned from nvkm) inside nvif_object, it's more or less unused and just wastes memory. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/arb.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/dac.c | 15 +- drivers/gpu/drm/nouveau/dispnv04/dfp.c | 2 +- drivers/gpu/drm/nouveau/dispnv04/disp.c | 4 +- drivers/gpu/drm/nouveau/dispnv04/hw.c | 22 +-- drivers/gpu/drm/nouveau/dispnv04/hw.h | 26 ++-- drivers/gpu/drm/nouveau/dispnv04/overlay.c | 13 +- drivers/gpu/drm/nouveau/dispnv04/tvnv17.h | 4 +- drivers/gpu/drm/nouveau/include/nvif/client.h | 26 +--- drivers/gpu/drm/nouveau/include/nvif/device.h | 24 +--- drivers/gpu/drm/nouveau/include/nvif/notify.h | 12 +- drivers/gpu/drm/nouveau/include/nvif/object.h | 57 ++++---- drivers/gpu/drm/nouveau/nouveau_abi16.c | 134 +++++++---------- drivers/gpu/drm/nouveau/nouveau_abi16.h | 2 +- drivers/gpu/drm/nouveau/nouveau_agp.c | 2 +- drivers/gpu/drm/nouveau/nouveau_backlight.c | 22 +-- drivers/gpu/drm/nouveau/nouveau_bios.c | 11 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 4 +- drivers/gpu/drm/nouveau/nouveau_chan.c | 55 ++++--- drivers/gpu/drm/nouveau/nouveau_chan.h | 2 +- drivers/gpu/drm/nouveau/nouveau_connector.c | 4 +- drivers/gpu/drm/nouveau/nouveau_display.c | 6 +- drivers/gpu/drm/nouveau/nouveau_dma.c | 10 +- drivers/gpu/drm/nouveau/nouveau_dma.h | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 18 +-- drivers/gpu/drm/nouveau/nouveau_fence.c | 15 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- drivers/gpu/drm/nouveau/nouveau_sysfs.c | 4 +- drivers/gpu/drm/nouveau/nouveau_vga.c | 9 +- drivers/gpu/drm/nouveau/nv04_fbcon.c | 12 +- drivers/gpu/drm/nouveau/nv04_fence.c | 2 +- drivers/gpu/drm/nouveau/nv10_fence.c | 2 +- drivers/gpu/drm/nouveau/nv17_fence.c | 4 +- drivers/gpu/drm/nouveau/nv50_display.c | 110 +++++++------- drivers/gpu/drm/nouveau/nv50_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nv50_fence.c | 4 +- drivers/gpu/drm/nouveau/nv84_fence.c | 2 +- drivers/gpu/drm/nouveau/nvc0_fbcon.c | 2 +- drivers/gpu/drm/nouveau/nvif/client.c | 61 ++------ drivers/gpu/drm/nouveau/nvif/device.c | 45 +----- drivers/gpu/drm/nouveau/nvif/notify.c | 49 +------ drivers/gpu/drm/nouveau/nvif/object.c | 135 ++++++------------ 42 files changed, 365 insertions(+), 574 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/arb.c b/drivers/gpu/drm/nouveau/dispnv04/arb.c index c6361422a0b28..82bd4658aa588 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/arb.c +++ b/drivers/gpu/drm/nouveau/dispnv04/arb.c @@ -198,7 +198,7 @@ nv04_update_arb(struct drm_device *dev, int VClk, int bpp, int *burst, int *lwm) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; struct nv_fifo_info fifo_data; struct nv_sim_state sim_data; int MClk = nouveau_hw_get_clock(dev, PLL_MEMORY); diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index 81c1efb8b3b6b..71e99cdfc40eb 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -65,7 +65,8 @@ int nv04_dac_output_offset(struct drm_encoder *encoder) static int sample_load_twice(struct drm_device *dev, bool sense[2]) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvif_object *device = &drm->device.object; int i; for (i = 0; i < 2; i++) { @@ -79,19 +80,19 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2]) * use a 10ms timeout (guards against crtc being inactive, in * which case blank state would never change) */ - if (nvif_msec(device, 10, + if (nvif_msec(&drm->device, 10, if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) break; ) < 0) return -EBUSY; - if (nvif_msec(device, 10, + if (nvif_msec(&drm->device, 10, if ( (nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) break; ) < 0) return -EBUSY; - if (nvif_msec(device, 10, + if (nvif_msec(&drm->device, 10, if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 1)) break; ) < 0) @@ -132,7 +133,7 @@ static enum drm_connector_status nv04_dac_detect(struct drm_encoder *encoder, struct drm_connector *connector) { struct drm_device *dev = encoder->dev; - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; struct nouveau_drm *drm = nouveau_drm(dev); uint8_t saved_seq1, saved_pi, saved_rpc1, saved_cr_mode; uint8_t saved_palette0[3], saved_palette_mask; @@ -235,8 +236,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) { struct drm_device *dev = encoder->dev; struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &nouveau_drm(dev)->device; - struct nvkm_gpio *gpio = nvxx_gpio(device); + struct nvif_object *device = &nouveau_drm(dev)->device.object; + struct nvkm_gpio *gpio = nvxx_gpio(&drm->device); struct dcb_output *dcb = nouveau_encoder(encoder)->dcb; uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder); uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput, diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index a85e7251e0cbe..522e91ab53607 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -281,7 +281,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *adjusted_mode) { struct drm_device *dev = encoder->dev; - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_crtc *nv_crtc = nouveau_crtc(encoder->crtc); struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index]; diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c index 018a4480cfc57..9e650081c3577 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c @@ -47,7 +47,7 @@ nv04_display_create(struct drm_device *dev) if (!disp) return -ENOMEM; - nvif_object_map(nvif_object(&drm->device)); + nvif_object_map(&drm->device.object); nouveau_display(dev)->priv = disp; nouveau_display(dev)->dtor = nv04_display_destroy; @@ -153,7 +153,7 @@ nv04_display_destroy(struct drm_device *dev) nouveau_display(dev)->priv = NULL; kfree(disp); - nvif_object_unmap(nvif_object(&drm->device)); + nvif_object_unmap(&drm->device.object); } int diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c index 5039bb5305232..956a833b82005 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.c +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c @@ -165,8 +165,8 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype, struct nvkm_pll_vals *pllvals) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->device; - struct nvkm_bios *bios = nvxx_bios(device); + struct nvif_object *device = &drm->device.object; + struct nvkm_bios *bios = nvxx_bios(&drm->device); uint32_t reg1, pll1, pll2 = 0; struct nvbios_pll pll_lim; int ret; @@ -660,7 +660,7 @@ nv_load_state_ext(struct drm_device *dev, int head, struct nv04_mode_state *state) { struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; struct nv04_crtc_reg *regp = &state->crtc_reg[head]; uint32_t reg900; int i; @@ -677,10 +677,10 @@ nv_load_state_ext(struct drm_device *dev, int head, nvif_wr32(device, NV_PVIDEO_INTR_EN, 0); nvif_wr32(device, NV_PVIDEO_OFFSET_BUFF(0), 0); nvif_wr32(device, NV_PVIDEO_OFFSET_BUFF(1), 0); - nvif_wr32(device, NV_PVIDEO_LIMIT(0), device->info.ram_size - 1); - nvif_wr32(device, NV_PVIDEO_LIMIT(1), device->info.ram_size - 1); - nvif_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), device->info.ram_size - 1); - nvif_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), device->info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_LIMIT(0), drm->device.info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_LIMIT(1), drm->device.info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(0), drm->device.info.ram_size - 1); + nvif_wr32(device, NV_PVIDEO_UVPLANE_LIMIT(1), drm->device.info.ram_size - 1); nvif_wr32(device, NV_PBUS_POWERCTRL_2, 0); NVWriteCRTC(dev, head, NV_PCRTC_CURSOR_CONFIG, regp->cursor_cfg); @@ -740,11 +740,11 @@ nv_load_state_ext(struct drm_device *dev, int head, if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) { /* Not waiting for vertical retrace before modifying CRE_53/CRE_54 causes lockups. */ - nvif_msec(device, 650, + nvif_msec(&drm->device, 650, if ( (nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 8)) break; ); - nvif_msec(device, 650, + nvif_msec(&drm->device, 650, if (!(nvif_rd32(device, NV_PRMCIO_INP0__COLOR) & 8)) break; ); @@ -770,7 +770,7 @@ static void nv_save_state_palette(struct drm_device *dev, int head, struct nv04_mode_state *state) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; int head_offset = head * NV_PRMDIO_SIZE, i; nvif_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset, @@ -789,7 +789,7 @@ void nouveau_hw_load_state_palette(struct drm_device *dev, int head, struct nv04_mode_state *state) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; int head_offset = head * NV_PRMDIO_SIZE, i; nvif_wr08(device, NV_PRMDIO_PIXEL_MASK + head_offset, diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.h b/drivers/gpu/drm/nouveau/dispnv04/hw.h index 6c796178bf0cf..3bded60c55968 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/hw.h +++ b/drivers/gpu/drm/nouveau/dispnv04/hw.h @@ -60,7 +60,7 @@ extern void nouveau_calc_arb(struct drm_device *, int vclk, int bpp, static inline uint32_t NVReadCRTC(struct drm_device *dev, int head, uint32_t reg) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; uint32_t val; if (head) reg += NV_PCRTC0_SIZE; @@ -71,7 +71,7 @@ static inline uint32_t NVReadCRTC(struct drm_device *dev, static inline void NVWriteCRTC(struct drm_device *dev, int head, uint32_t reg, uint32_t val) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; if (head) reg += NV_PCRTC0_SIZE; nvif_wr32(device, reg, val); @@ -80,7 +80,7 @@ static inline void NVWriteCRTC(struct drm_device *dev, static inline uint32_t NVReadRAMDAC(struct drm_device *dev, int head, uint32_t reg) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; uint32_t val; if (head) reg += NV_PRAMDAC0_SIZE; @@ -91,7 +91,7 @@ static inline uint32_t NVReadRAMDAC(struct drm_device *dev, static inline void NVWriteRAMDAC(struct drm_device *dev, int head, uint32_t reg, uint32_t val) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; if (head) reg += NV_PRAMDAC0_SIZE; nvif_wr32(device, reg, val); @@ -120,7 +120,7 @@ static inline void nv_write_tmds(struct drm_device *dev, static inline void NVWriteVgaCrtc(struct drm_device *dev, int head, uint8_t index, uint8_t value) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); nvif_wr08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE, value); } @@ -128,7 +128,7 @@ static inline void NVWriteVgaCrtc(struct drm_device *dev, static inline uint8_t NVReadVgaCrtc(struct drm_device *dev, int head, uint8_t index) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; uint8_t val; nvif_wr08(device, NV_PRMCIO_CRX__COLOR + head * NV_PRMCIO_SIZE, index); val = nvif_rd08(device, NV_PRMCIO_CR__COLOR + head * NV_PRMCIO_SIZE); @@ -165,7 +165,7 @@ static inline uint8_t NVReadVgaCrtc5758(struct drm_device *dev, int head, uint8_ static inline uint8_t NVReadPRMVIO(struct drm_device *dev, int head, uint32_t reg) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; struct nouveau_drm *drm = nouveau_drm(dev); uint8_t val; @@ -181,7 +181,7 @@ static inline uint8_t NVReadPRMVIO(struct drm_device *dev, static inline void NVWritePRMVIO(struct drm_device *dev, int head, uint32_t reg, uint8_t value) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; struct nouveau_drm *drm = nouveau_drm(dev); /* Only NV4x have two pvio ranges; other twoHeads cards MUST call @@ -194,14 +194,14 @@ static inline void NVWritePRMVIO(struct drm_device *dev, static inline void NVSetEnablePalette(struct drm_device *dev, int head, bool enable) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); nvif_wr08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE, enable ? 0 : 0x20); } static inline bool NVGetEnablePalette(struct drm_device *dev, int head) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; nvif_rd08(device, NV_PRMCIO_INP0__COLOR + head * NV_PRMCIO_SIZE); return !(nvif_rd08(device, NV_PRMCIO_ARX + head * NV_PRMCIO_SIZE) & 0x20); } @@ -209,7 +209,7 @@ static inline bool NVGetEnablePalette(struct drm_device *dev, int head) static inline void NVWriteVgaAttr(struct drm_device *dev, int head, uint8_t index, uint8_t value) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; if (NVGetEnablePalette(dev, head)) index &= ~0x20; else @@ -223,7 +223,7 @@ static inline void NVWriteVgaAttr(struct drm_device *dev, static inline uint8_t NVReadVgaAttr(struct drm_device *dev, int head, uint8_t index) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; uint8_t val; if (NVGetEnablePalette(dev, head)) index &= ~0x20; @@ -259,7 +259,7 @@ static inline void NVVgaProtect(struct drm_device *dev, int head, bool protect) static inline bool nv_heads_tied(struct drm_device *dev) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; struct nouveau_drm *drm = nouveau_drm(dev); if (drm->device.info.chipset == 0x11) diff --git a/drivers/gpu/drm/nouveau/dispnv04/overlay.c b/drivers/gpu/drm/nouveau/dispnv04/overlay.c index 5f6ea1873f517..aeebdd402478b 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/overlay.c +++ b/drivers/gpu/drm/nouveau/dispnv04/overlay.c @@ -96,7 +96,8 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nouveau_drm *drm = nouveau_drm(plane->dev); + struct nvif_object *dev = &drm->device.object; struct nouveau_plane *nv_plane = container_of(plane, struct nouveau_plane, base); struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); @@ -118,7 +119,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, if (format > 0xffff) return -ERANGE; - if (dev->info.chipset >= 0x30) { + if (drm->device.info.chipset >= 0x30) { if (crtc_w < (src_w >> 1) || crtc_h < (src_h >> 1)) return -ERANGE; } else { @@ -173,7 +174,7 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, static int nv10_disable_plane(struct drm_plane *plane) { - struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nvif_object *dev = &nouveau_drm(plane->dev)->device.object; struct nouveau_plane *nv_plane = container_of(plane, struct nouveau_plane, base); @@ -197,7 +198,7 @@ nv_destroy_plane(struct drm_plane *plane) static void nv10_set_params(struct nouveau_plane *plane) { - struct nvif_device *dev = &nouveau_drm(plane->base.dev)->device; + struct nvif_object *dev = &nouveau_drm(plane->base.dev)->device.object; u32 luma = (plane->brightness - 512) << 16 | plane->contrast; u32 chroma = ((sin_mul(plane->hue, plane->saturation) & 0xffff) << 16) | (cos_mul(plane->hue, plane->saturation) & 0xffff); @@ -346,7 +347,7 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, uint32_t src_x, uint32_t src_y, uint32_t src_w, uint32_t src_h) { - struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nvif_object *dev = &nouveau_drm(plane->dev)->device.object; struct nouveau_plane *nv_plane = container_of(plane, struct nouveau_plane, base); struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb); @@ -426,7 +427,7 @@ nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc, static int nv04_disable_plane(struct drm_plane *plane) { - struct nvif_device *dev = &nouveau_drm(plane->dev)->device; + struct nvif_object *dev = &nouveau_drm(plane->dev)->device.object; struct nouveau_plane *nv_plane = container_of(plane, struct nouveau_plane, base); diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h index 225894cdcac2d..459910b6bb320 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.h @@ -131,13 +131,13 @@ static inline void nv_write_ptv(struct drm_device *dev, uint32_t reg, uint32_t val) { struct nvif_device *device = &nouveau_drm(dev)->device; - nvif_wr32(device, reg, val); + nvif_wr32(&device->object, reg, val); } static inline uint32_t nv_read_ptv(struct drm_device *dev, uint32_t reg) { struct nvif_device *device = &nouveau_drm(dev)->device; - return nvif_rd32(device, reg); + return nvif_rd32(&device->object, reg); } static inline void nv_write_tv_enc(struct drm_device *dev, uint8_t reg, diff --git a/drivers/gpu/drm/nouveau/include/nvif/client.h b/drivers/gpu/drm/nouveau/include/nvif/client.h index eca648ef0f7a2..cd6fbfa887621 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/client.h +++ b/drivers/gpu/drm/nouveau/include/nvif/client.h @@ -4,36 +4,24 @@ #include struct nvif_client { - struct nvif_object base; - struct nvif_object *object; /*XXX: hack for nvif_object() */ + struct nvif_object object; const struct nvif_driver *driver; + u8 route; bool super; }; -static inline struct nvif_client * -nvif_client(struct nvif_object *object) -{ - while (object && object->parent != object) - object = object->parent; - return (void *)object; -} - -int nvif_client_init(void (*dtor)(struct nvif_client *), const char *, - const char *, u64, const char *, const char *, +int nvif_client_init(const char *drv, const char *name, u64 device, + const char *cfg, const char *dbg, struct nvif_client *); void nvif_client_fini(struct nvif_client *); -int nvif_client_new(const char *, const char *, u64, const char *, - const char *, struct nvif_client **); -void nvif_client_ref(struct nvif_client *, struct nvif_client **); int nvif_client_ioctl(struct nvif_client *, void *, u32); int nvif_client_suspend(struct nvif_client *); int nvif_client_resume(struct nvif_client *); /*XXX*/ #include -#define nvxx_client(a) ({ \ - struct nvif_client *_client = nvif_client(nvif_object(a)); \ - nvkm_client(_client->base.priv); \ +#define nvxx_client(a) ({ \ + struct nvif_client *_client = (a); \ + nvkm_client(_client->object.priv); \ }) - #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 077651f9b7e9d..1973e65f21a68 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -5,26 +5,13 @@ #include struct nvif_device { - struct nvif_object base; - struct nvif_object *object; /*XXX: hack for nvif_object() */ + struct nvif_object object; struct nv_device_info_v0 info; }; -static inline struct nvif_device * -nvif_device(struct nvif_object *object) -{ - while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ ) - object = object->parent; - return (void *)object; -} - -int nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *), - u32 handle, u32 oclass, void *, u32, +int nvif_device_init(struct nvif_object *, u32 handle, u32 oclass, void *, u32, struct nvif_device *); void nvif_device_fini(struct nvif_device *); -int nvif_device_new(struct nvif_object *, u32 handle, u32 oclass, - void *, u32, struct nvif_device **); -void nvif_device_ref(struct nvif_device *, struct nvif_device **); u64 nvif_device_time(struct nvif_device *); /* Delay based on GPU time (ie. PTIMER). @@ -59,7 +46,10 @@ u64 nvif_device_time(struct nvif_device *); #include #include -#define nvxx_device(a) nv_device(nvxx_object((a))) +#define nvxx_device(a) ({ \ + struct nvif_device *_device = (a); \ + nv_device(_device->object.priv); \ +}) #define nvxx_bios(a) nvkm_bios(nvxx_device(a)) #define nvxx_fb(a) nvkm_fb(nvxx_device(a)) #define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) @@ -77,5 +67,5 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_fifo(a) nvkm_fifo(nvxx_device(a)) #define nvxx_fifo_chan(a) ((struct nvkm_fifo_chan *)nvxx_object(a)) -#define nvxx_gr(a) ((struct nvkm_gr *)nvkm_engine(nvxx_object(a), NVDEV_ENGINE_GR)) +#define nvxx_gr(a) nvkm_gr(nvxx_device(a)) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/notify.h b/drivers/gpu/drm/nouveau/include/nvif/notify.h index 9ebfa3b45e76b..51e2eb5808099 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/notify.h +++ b/drivers/gpu/drm/nouveau/include/nvif/notify.h @@ -23,17 +23,11 @@ struct nvif_notify { struct work_struct work; }; -int nvif_notify_init(struct nvif_object *, void (*dtor)(struct nvif_notify *), - int (*func)(struct nvif_notify *), bool work, u8 type, - void *data, u32 size, u32 reply, struct nvif_notify *); +int nvif_notify_init(struct nvif_object *, int (*func)(struct nvif_notify *), + bool work, u8 type, void *data, u32 size, u32 reply, + struct nvif_notify *); int nvif_notify_fini(struct nvif_notify *); int nvif_notify_get(struct nvif_notify *); int nvif_notify_put(struct nvif_notify *); int nvif_notify(const void *, u32, const void *, u32); - -int nvif_notify_new(struct nvif_object *, int (*func)(struct nvif_notify *), - bool work, u8 type, void *data, u32 size, u32 reply, - struct nvif_notify **); -void nvif_notify_ref(struct nvif_notify *, struct nvif_notify **); - #endif diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index 04c874707b96a..66d94c74b351f 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -4,28 +4,20 @@ #include struct nvif_object { + struct nvif_client *client; struct nvif_object *parent; - struct nvif_object *object; /*XXX: hack for nvif_object() */ - struct kref refcount; u32 handle; u32 oclass; - void *data; - u32 size; void *priv; /*XXX: hack */ - void (*dtor)(struct nvif_object *); struct { void __iomem *ptr; u32 size; } map; }; -int nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *), - u32 handle, u32 oclass, void *, u32, +int nvif_object_init(struct nvif_object *, u32 handle, u32 oclass, void *, u32, struct nvif_object *); void nvif_object_fini(struct nvif_object *); -int nvif_object_new(struct nvif_object *, u32 handle, u32 oclass, - void *, u32, struct nvif_object **); -void nvif_object_ref(struct nvif_object *, struct nvif_object **); int nvif_object_ioctl(struct nvif_object *, void *, u32, void **); int nvif_object_sclass(struct nvif_object *, u32 *, int); u32 nvif_object_rd(struct nvif_object *, int, u64); @@ -36,40 +28,41 @@ void nvif_object_unmap(struct nvif_object *); #define nvif_object(a) (a)->object -#define ioread8_native ioread8 -#define iowrite8_native iowrite8 -#define nvif_rd(a,b,c) ({ \ - struct nvif_object *_object = nvif_object(a); \ +#define nvif_rd(a,f,b,c) ({ \ + struct nvif_object *_object = (a); \ u32 _data; \ if (likely(_object->map.ptr)) \ - _data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c)); \ + _data = f((u8 __iomem *)_object->map.ptr + (c)); \ else \ - _data = nvif_object_rd(_object, (b) / 8, (c)); \ + _data = nvif_object_rd(_object, (b), (c)); \ _data; \ }) -#define nvif_wr(a,b,c,d) ({ \ - struct nvif_object *_object = nvif_object(a); \ +#define nvif_wr(a,f,b,c,d) ({ \ + struct nvif_object *_object = (a); \ if (likely(_object->map.ptr)) \ - iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c)); \ + f((d), (u8 __iomem *)_object->map.ptr + (c)); \ else \ - nvif_object_wr(_object, (b) / 8, (c), (d)); \ + nvif_object_wr(_object, (b), (c), (d)); \ }) -#define nvif_rd08(a,b) ({ u8 _v = nvif_rd((a), 8, (b)); _v; }) -#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; }) -#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; }) -#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c)) -#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c)) -#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c)) +#define nvif_rd08(a,b) ({ ((u8)nvif_rd((a), ioread8, 1, (b))); }) +#define nvif_rd16(a,b) ({ ((u16)nvif_rd((a), ioread16_native, 2, (b))); }) +#define nvif_rd32(a,b) ({ ((u32)nvif_rd((a), ioread32_native, 4, (b))); }) +#define nvif_wr08(a,b,c) nvif_wr((a), iowrite8, 1, (b), (u8)(c)) +#define nvif_wr16(a,b,c) nvif_wr((a), iowrite16_native, 2, (b), (u16)(c)) +#define nvif_wr32(a,b,c) nvif_wr((a), iowrite32_native, 4, (b), (u32)(c)) #define nvif_mask(a,b,c,d) ({ \ - u32 _v = nvif_rd32(nvif_object(a), (b)); \ - nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d)); \ - _v; \ + struct nvif_object *__object = (a); \ + u32 _addr = (b), _data = nvif_rd32(__object, _addr); \ + nvif_wr32(__object, _addr, (_data & ~(c)) | (d)); \ + _data; \ }) -#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d)) +#define nvif_mthd(a,b,c,d) nvif_object_mthd((a), (b), (c), (d)) /*XXX*/ #include -#define nvxx_object(a) ((struct nvkm_object *)nvif_object(a)->priv) - +#define nvxx_object(a) ({ \ + struct nvif_object *_object = (a); \ + (struct nvkm_object *)_object->priv; \ +}) #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 01ffdb37a66b2..76c363223e3f7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -51,7 +51,7 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) * device (ie. the one that belongs to the fd it * opened) */ - if (nvif_device_init(&cli->base.base, NULL, + if (nvif_device_init(&cli->base.object, NOUVEAU_ABI16_DEVICE, NV_DEVICE, &args, sizeof(args), &abi16->device) == 0) @@ -69,7 +69,7 @@ nouveau_abi16_get(struct drm_file *file_priv, struct drm_device *dev) int nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret) { - struct nouveau_cli *cli = (void *)nvif_client(&abi16->device.base); + struct nouveau_cli *cli = (void *)abi16->device.object.client; mutex_unlock(&cli->mutex); return ret; } @@ -100,6 +100,7 @@ static void nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan, struct nouveau_abi16_ntfy *ntfy) { + nvif_object_fini(&ntfy->object); nvkm_mm_free(&chan->heap, &ntfy->node); list_del(&ntfy->head); kfree(ntfy); @@ -132,7 +133,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, /* destroy channel object, all children will be killed too */ if (chan->chan) { - abi16->handles &= ~(1ULL << (chan->chan->object->handle & 0xffff)); + abi16->handles &= ~(1ULL << (chan->chan->user.handle & 0xffff)); nouveau_channel_del(&chan->chan); } @@ -143,7 +144,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, void nouveau_abi16_fini(struct nouveau_abi16 *abi16) { - struct nouveau_cli *cli = (void *)nvif_client(&abi16->device.base); + struct nouveau_cli *cli = (void *)abi16->device.object.client; struct nouveau_abi16_chan *chan, *temp; /* cleanup channels */ @@ -336,7 +337,7 @@ nouveau_abi16_chan(struct nouveau_abi16 *abi16, int channel) struct nouveau_abi16_chan *chan; list_for_each_entry(chan, &abi16->channels, head) { - if (chan->chan->object->handle == NOUVEAU_ABI16_CHAN(channel)) + if (chan->chan->user.handle == NOUVEAU_ABI16_CHAN(channel)) return chan; } @@ -364,21 +365,9 @@ int nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) { struct drm_nouveau_grobj_alloc *init = data; - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_new_v0 new; - } args = { - .ioctl.owner = NVIF_IOCTL_V0_OWNER_ANY, - .ioctl.type = NVIF_IOCTL_V0_NEW, - .ioctl.path_nr = 3, - .ioctl.path[2] = NOUVEAU_ABI16_CLIENT, - .ioctl.path[1] = NOUVEAU_ABI16_DEVICE, - .ioctl.path[0] = NOUVEAU_ABI16_CHAN(init->channel), - .new.route = NVDRM_OBJECT_ABI16, - .new.handle = init->handle, - .new.oclass = init->class, - }; struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); + struct nouveau_abi16_chan *chan; + struct nouveau_abi16_ntfy *ntfy; struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_client *client; int ret; @@ -388,7 +377,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if (init->handle == ~0) return nouveau_abi16_put(abi16, -EINVAL); - client = nvif_client(nvif_object(&abi16->device)); + client = abi16->device.object.client; /* compatibility with userspace that assumes 506e for all chipsets */ if (init->class == 0x506e) { @@ -397,7 +386,23 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, 0); } - ret = nvif_client_ioctl(client, &args, sizeof(args)); + chan = nouveau_abi16_chan(abi16, init->channel); + if (!chan) + return nouveau_abi16_put(abi16, -ENOENT); + + ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL); + if (!ntfy) + return nouveau_abi16_put(abi16, -ENOMEM); + + list_add(&ntfy->head, &chan->notifiers); + + client->route = NVDRM_OBJECT_ABI16; + ret = nvif_object_init(&chan->chan->user, init->handle, init->class, + NULL, 0, &ntfy->object); + client->route = NVDRM_OBJECT_NVIF; + + if (ret) + nouveau_abi16_ntfy_fini(chan, ntfy); return nouveau_abi16_put(abi16, ret); } @@ -405,27 +410,13 @@ int nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) { struct drm_nouveau_notifierobj_alloc *info = data; - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_new_v0 new; - struct nv_dma_v0 ctxdma; - } args = { - .ioctl.owner = NVIF_IOCTL_V0_OWNER_ANY, - .ioctl.type = NVIF_IOCTL_V0_NEW, - .ioctl.path_nr = 3, - .ioctl.path[2] = NOUVEAU_ABI16_CLIENT, - .ioctl.path[1] = NOUVEAU_ABI16_DEVICE, - .ioctl.path[0] = NOUVEAU_ABI16_CHAN(info->channel), - .new.route = NVDRM_OBJECT_ABI16, - .new.handle = info->handle, - .new.oclass = NV_DMA_IN_MEMORY, - }; struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; struct nvif_device *device = &abi16->device; struct nvif_client *client; + struct nv_dma_v0 args = {}; int ret; if (unlikely(!abi16)) @@ -434,7 +425,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) /* completely unnecessary for these chipsets... */ if (unlikely(device->info.family >= NV_DEVICE_INFO_V0_FERMI)) return nouveau_abi16_put(abi16, -EINVAL); - client = nvif_client(nvif_object(&abi16->device)); + client = abi16->device.object.client; chan = nouveau_abi16_chan(abi16, info->channel); if (!chan) @@ -445,41 +436,43 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, -ENOMEM); list_add(&ntfy->head, &chan->notifiers); - ntfy->handle = info->handle; ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1, &ntfy->node); if (ret) goto done; - args.ctxdma.start = ntfy->node->offset; - args.ctxdma.limit = ntfy->node->offset + ntfy->node->length - 1; + args.start = ntfy->node->offset; + args.limit = ntfy->node->offset + ntfy->node->length - 1; if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) { - args.ctxdma.target = NV_DMA_V0_TARGET_VM; - args.ctxdma.access = NV_DMA_V0_ACCESS_VM; - args.ctxdma.start += chan->ntfy_vma.offset; - args.ctxdma.limit += chan->ntfy_vma.offset; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_VM; + args.start += chan->ntfy_vma.offset; + args.limit += chan->ntfy_vma.offset; } else if (drm->agp.stat == ENABLED) { - args.ctxdma.target = NV_DMA_V0_TARGET_AGP; - args.ctxdma.access = NV_DMA_V0_ACCESS_RDWR; - args.ctxdma.start += drm->agp.base + chan->ntfy->bo.offset; - args.ctxdma.limit += drm->agp.base + chan->ntfy->bo.offset; - client->super = true; + args.target = NV_DMA_V0_TARGET_AGP; + args.access = NV_DMA_V0_ACCESS_RDWR; + args.start += drm->agp.base + chan->ntfy->bo.offset; + args.limit += drm->agp.base + chan->ntfy->bo.offset; } else { - args.ctxdma.target = NV_DMA_V0_TARGET_VM; - args.ctxdma.access = NV_DMA_V0_ACCESS_RDWR; - args.ctxdma.start += chan->ntfy->bo.offset; - args.ctxdma.limit += chan->ntfy->bo.offset; + args.target = NV_DMA_V0_TARGET_VM; + args.access = NV_DMA_V0_ACCESS_RDWR; + args.start += chan->ntfy->bo.offset; + args.limit += chan->ntfy->bo.offset; } - ret = nvif_client_ioctl(client, &args, sizeof(args)); + client->route = NVDRM_OBJECT_ABI16; + client->super = true; + ret = nvif_object_init(&chan->chan->user, info->handle, + NV_DMA_IN_MEMORY, &args, sizeof(args), + &ntfy->object); client->super = false; + client->route = NVDRM_OBJECT_NVIF; if (ret) goto done; info->offset = ntfy->node->offset; - done: if (ret) nouveau_abi16_ntfy_fini(chan, ntfy); @@ -490,47 +483,28 @@ int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS) { struct drm_nouveau_gpuobj_free *fini = data; - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_del del; - } args = { - .ioctl.owner = NVDRM_OBJECT_ABI16, - .ioctl.type = NVIF_IOCTL_V0_DEL, - .ioctl.path_nr = 4, - .ioctl.path[3] = NOUVEAU_ABI16_CLIENT, - .ioctl.path[2] = NOUVEAU_ABI16_DEVICE, - .ioctl.path[1] = NOUVEAU_ABI16_CHAN(fini->channel), - .ioctl.path[0] = fini->handle, - }; struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; - struct nvif_client *client; - int ret; + int ret = -ENOENT; if (unlikely(!abi16)) return -ENOMEM; chan = nouveau_abi16_chan(abi16, fini->channel); if (!chan) - return nouveau_abi16_put(abi16, -ENOENT); - client = nvif_client(nvif_object(&abi16->device)); + return nouveau_abi16_put(abi16, -EINVAL); /* synchronize with the user channel and destroy the gpu object */ nouveau_channel_idle(chan->chan); - ret = nvif_client_ioctl(client, &args, sizeof(args)); - if (ret) - return nouveau_abi16_put(abi16, ret); - - /* cleanup extra state if this object was a notifier */ list_for_each_entry(ntfy, &chan->notifiers, head) { - if (ntfy->handle == fini->handle) { - nvkm_mm_free(&chan->heap, &ntfy->node); - list_del(&ntfy->head); + if (ntfy->object.handle == fini->handle) { + nouveau_abi16_ntfy_fini(chan, ntfy); + ret = 0; break; } } - return nouveau_abi16_put(abi16, 0); + return nouveau_abi16_put(abi16, ret); } diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index 86eb1caf4957f..b8acfd787d54d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -13,9 +13,9 @@ int nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS); int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS); struct nouveau_abi16_ntfy { + struct nvif_object object; struct list_head head; struct nvkm_mm_node *node; - u32 handle; }; struct nouveau_abi16_chan { diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c index 0b59709556047..320f48c41fe0d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c @@ -102,7 +102,7 @@ void nouveau_agp_reset(struct nouveau_drm *drm) { #if __OS_HAS_AGP - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; struct drm_device *dev = drm->dev; u32 save[2]; int ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_backlight.c b/drivers/gpu/drm/nouveau/nouveau_backlight.c index e566c5b53651e..89eb46040b139 100644 --- a/drivers/gpu/drm/nouveau/nouveau_backlight.c +++ b/drivers/gpu/drm/nouveau/nouveau_backlight.c @@ -40,7 +40,7 @@ static int nv40_get_intensity(struct backlight_device *bd) { struct nouveau_drm *drm = bl_get_data(bd); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; int val = (nvif_rd32(device, NV40_PMC_BACKLIGHT) & NV40_PMC_BACKLIGHT_MASK) >> 16; @@ -51,7 +51,7 @@ static int nv40_set_intensity(struct backlight_device *bd) { struct nouveau_drm *drm = bl_get_data(bd); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; int val = bd->props.brightness; int reg = nvif_rd32(device, NV40_PMC_BACKLIGHT); @@ -71,7 +71,7 @@ static int nv40_backlight_init(struct drm_connector *connector) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; struct backlight_properties props; struct backlight_device *bd; @@ -97,7 +97,7 @@ nv50_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; int or = nv_encoder->or; u32 div = 1025; u32 val; @@ -112,7 +112,7 @@ nv50_set_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; int or = nv_encoder->or; u32 div = 1025; u32 val = (bd->props.brightness * div) / 100; @@ -133,7 +133,7 @@ nva3_get_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; int or = nv_encoder->or; u32 div, val; @@ -151,7 +151,7 @@ nva3_set_intensity(struct backlight_device *bd) { struct nouveau_encoder *nv_encoder = bl_get_data(bd); struct nouveau_drm *drm = nouveau_drm(nv_encoder->base.base.dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; int or = nv_encoder->or; u32 div, val; @@ -177,7 +177,7 @@ static int nv50_backlight_init(struct drm_connector *connector) { struct nouveau_drm *drm = nouveau_drm(connector->dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; struct nouveau_encoder *nv_encoder; struct backlight_properties props; struct backlight_device *bd; @@ -193,9 +193,9 @@ nv50_backlight_init(struct drm_connector *connector) if (!nvif_rd32(device, NV50_PDISP_SOR_PWM_CTL(nv_encoder->or))) return 0; - if (device->info.chipset <= 0xa0 || - device->info.chipset == 0xaa || - device->info.chipset == 0xac) + if (drm->device.info.chipset <= 0xa0 || + drm->device.info.chipset == 0xaa || + drm->device.info.chipset == 0xac) ops = &nv50_bl_ops; else ops = &nva3_bl_ops; diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c index 3199479ac5b3a..4dca65a63b922 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bios.c +++ b/drivers/gpu/drm/nouveau/nouveau_bios.c @@ -215,7 +215,7 @@ int call_lvds_script(struct drm_device *dev, struct dcb_output *dcbent, int head */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; struct nvbios *bios = &drm->vbios; uint8_t lvds_ver = bios->data[bios->fp.lvdsmanufacturerpointer]; uint32_t sel_clk_binding, sel_clk; @@ -318,7 +318,8 @@ static int parse_lvds_manufacturer_table_header(struct drm_device *dev, struct n static int get_fp_strap(struct drm_device *dev, struct nvbios *bios) { - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvif_object *device = &drm->device.object; /* * The fp strap is normally dictated by the "User Strap" in @@ -332,7 +333,7 @@ get_fp_strap(struct drm_device *dev, struct nvbios *bios) if (bios->major_version < 5 && bios->data[0x48] & 0x4) return NVReadVgaCrtc5758(dev, 0, 0xf) & 0xf; - if (device->info.family >= NV_DEVICE_INFO_V0_TESLA) + if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) return (nvif_rd32(device, NV_PEXTDEV_BOOT_0) >> 24) & 0xf; else return (nvif_rd32(device, NV_PEXTDEV_BOOT_0) >> 16) & 0xf; @@ -634,7 +635,7 @@ int run_tmds_table(struct drm_device *dev, struct dcb_output *dcbent, int head, */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; struct nvbios *bios = &drm->vbios; int cv = bios->chip_version; uint16_t clktable = 0, scriptptr; @@ -1914,7 +1915,7 @@ static int load_nv17_hwsq_ucode_entry(struct drm_device *dev, struct nvbios *bio */ struct nouveau_drm *drm = nouveau_drm(dev); - struct nvif_device *device = &drm->device; + struct nvif_object *device = &drm->device.object; uint8_t bytes_to_write; uint16_t hwsq_entry_offset; int i; diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 37ed3b250ac5e..5529fc479d8a3 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1064,7 +1064,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr, { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_channel *chan = drm->ttm.chan; - struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base); + struct nouveau_cli *cli = (void *)chan->user.client; struct nouveau_fence *fence; int ret; @@ -1137,7 +1137,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) if (chan == NULL) continue; - ret = nvif_object_init(chan->object, NULL, + ret = nvif_object_init(&chan->user, mthd->oclass | (mthd->engine << 16), mthd->oclass, NULL, 0, &drm->ttm.copy); diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 694b135e27c95..302713821f086 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -42,7 +42,7 @@ module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); int nouveau_channel_idle(struct nouveau_channel *chan) { - struct nouveau_cli *cli = (void *)nvif_client(chan->object); + struct nouveau_cli *cli = (void *)chan->user.client; struct nouveau_fence *fence = NULL; int ret; @@ -54,7 +54,7 @@ nouveau_channel_idle(struct nouveau_channel *chan) if (ret) NV_PRINTK(err, cli, "failed to idle channel 0x%08x [%s]\n", - chan->object->handle, nvxx_client(&cli->base)->name); + chan->user.handle, nvxx_client(&cli->base)->name); return ret; } @@ -70,14 +70,13 @@ nouveau_channel_del(struct nouveau_channel **pchan) nvif_object_fini(&chan->nvsw); nvif_object_fini(&chan->gart); nvif_object_fini(&chan->vram); - nvif_object_ref(NULL, &chan->object); + nvif_object_fini(&chan->user); nvif_object_fini(&chan->push.ctxdma); nouveau_bo_vma_del(chan->push.buffer, &chan->push.vma); nouveau_bo_unmap(chan->push.buffer); if (chan->push.buffer && chan->push.buffer->pin_refcnt) nouveau_bo_unpin(chan->push.buffer); nouveau_bo_ref(NULL, &chan->push.buffer); - nvif_device_ref(NULL, &chan->device); kfree(chan); } *pchan = NULL; @@ -87,7 +86,7 @@ static int nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, u32 handle, u32 size, struct nouveau_channel **pchan) { - struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_cli *cli = (void *)device->object.client; struct nvkm_mmu *mmu = nvxx_mmu(device); struct nv_dma_v0 args = {}; struct nouveau_channel *chan; @@ -98,7 +97,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, if (!chan) return -ENOMEM; - nvif_device_ref(device, &chan->device); + chan->device = device; chan->drm = drm; /* allocate memory for dma push buffer */ @@ -169,7 +168,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, } } - ret = nvif_object_init(nvif_object(device), NULL, NVDRM_PUSH | + ret = nvif_object_init(&device->object, NVDRM_PUSH | (handle & 0xffff), NV_DMA_FROM_MEMORY, &args, sizeof(args), &chan->push.ctxdma); if (ret) { @@ -194,7 +193,7 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, union { struct nv50_channel_gpfifo_v0 nv50; struct kepler_channel_gpfifo_a_v0 kepler; - } args, *retn; + } args; struct nouveau_channel *chan; u32 size; int ret; @@ -222,14 +221,13 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, size = sizeof(args.nv50); } - ret = nvif_object_new(nvif_object(device), handle, *oclass++, - &args, size, &chan->object); + ret = nvif_object_init(&device->object, handle, *oclass++, + &args, size, &chan->user); if (ret == 0) { - retn = chan->object->data; - if (chan->object->oclass >= KEPLER_CHANNEL_GPFIFO_A) - chan->chid = retn->kepler.chid; + if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) + chan->chid = args.kepler.chid; else - chan->chid = retn->nv50.chid; + chan->chid = args.nv50.chid; return ret; } } while (*oclass); @@ -248,7 +246,7 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, NV03_CHANNEL_DMA, 0 }; const u16 *oclass = oclasses; - struct nv03_channel_dma_v0 args, *retn; + struct nv03_channel_dma_v0 args; struct nouveau_channel *chan; int ret; @@ -264,11 +262,10 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, args.offset = chan->push.vma.offset; do { - ret = nvif_object_new(nvif_object(device), handle, *oclass++, - &args, sizeof(args), &chan->object); + ret = nvif_object_init(&device->object, handle, *oclass++, + &args, sizeof(args), &chan->user); if (ret == 0) { - retn = chan->object->data; - chan->chid = retn->chid; + chan->chid = args.chid; return ret; } } while (ret && *oclass); @@ -281,13 +278,13 @@ static int nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) { struct nvif_device *device = chan->device; - struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_cli *cli = (void *)chan->user.client; struct nvkm_mmu *mmu = nvxx_mmu(device); struct nvkm_sw_chan *swch; struct nv_dma_v0 args = {}; int ret, i; - nvif_object_map(chan->object); + nvif_object_map(&chan->user); /* allocate dma objects to cover all allowed vram, and gart */ if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { @@ -303,9 +300,8 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) args.limit = device->info.ram_user - 1; } - ret = nvif_object_init(chan->object, NULL, vram, - NV_DMA_IN_MEMORY, &args, - sizeof(args), &chan->vram); + ret = nvif_object_init(&chan->user, vram, NV_DMA_IN_MEMORY, + &args, sizeof(args), &chan->vram); if (ret) return ret; @@ -328,15 +324,14 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) args.limit = mmu->limit - 1; } - ret = nvif_object_init(chan->object, NULL, gart, - NV_DMA_IN_MEMORY, &args, - sizeof(args), &chan->gart); + ret = nvif_object_init(&chan->user, gart, NV_DMA_IN_MEMORY, + &args, sizeof(args), &chan->gart); if (ret) return ret; } /* initialise dma tracking parameters */ - switch (chan->object->oclass & 0x00ff) { + switch (chan->user.oclass & 0x00ff) { case 0x006b: case 0x006e: chan->user_put = 0x40; @@ -368,7 +363,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) /* allocate software object class (used for fences on <= nv05) */ if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { - ret = nvif_object_init(chan->object, NULL, 0x006e, 0x006e, + ret = nvif_object_init(&chan->user, 0x006e, 0x006e, NULL, 0, &chan->nvsw); if (ret) return ret; @@ -395,7 +390,7 @@ nouveau_channel_new(struct nouveau_drm *drm, struct nvif_device *device, u32 handle, u32 arg0, u32 arg1, struct nouveau_channel **pchan) { - struct nouveau_cli *cli = (void *)nvif_client(&device->base); + struct nouveau_cli *cli = (void *)device->object.client; bool super; int ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h index 8b3640f69e4fc..2ed32414cb697 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.h +++ b/drivers/gpu/drm/nouveau/nouveau_chan.h @@ -37,7 +37,7 @@ struct nouveau_channel { u32 user_get; u32 user_put; - struct nvif_object *object; + struct nvif_object user; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 054f0f25c8bee..309c20b086d42 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -1256,8 +1256,8 @@ nouveau_connector_create(struct drm_device *dev, int index) break; } - ret = nvif_notify_init(&disp->disp, NULL, nouveau_connector_hotplug, - true, NV04_DISP_NTFY_CONN, + ret = nvif_notify_init(&disp->disp, nouveau_connector_hotplug, true, + NV04_DISP_NTFY_CONN, &(struct nvif_notify_conn_req_v0) { .mask = NVIF_NOTIFY_CONN_V0_ANY, .conn = index, diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 8670d90cdc11e..d913074c952f7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -185,7 +185,7 @@ nouveau_display_vblank_init(struct drm_device *dev) list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - ret = nvif_notify_init(&disp->disp, NULL, + ret = nvif_notify_init(&disp->disp, nouveau_display_vblank_handler, false, NV04_DISP_NTFY_VBLANK, &(struct nvif_notify_head_req_v0) { @@ -494,7 +494,7 @@ nouveau_display_create(struct drm_device *dev) int i; for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) { - ret = nvif_object_init(nvif_object(&drm->device), NULL, + ret = nvif_object_init(&drm->device.object, NVDRM_DISPLAY, oclass[i], NULL, 0, &disp->disp); } @@ -711,7 +711,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb, chan = drm->channel; if (!chan) return -ENODEV; - cli = (void *)nvif_client(&chan->device->base); + cli = (void *)chan->user.client; s = kzalloc(sizeof(*s), GFP_KERNEL); if (!s) diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c index 6d9245aa81a6a..d168c63533c17 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.c +++ b/drivers/gpu/drm/nouveau/nouveau_dma.c @@ -52,9 +52,9 @@ READ_GET(struct nouveau_channel *chan, uint64_t *prev_get, int *timeout) { uint64_t val; - val = nvif_rd32(chan, chan->user_get); + val = nvif_rd32(&chan->user, chan->user_get); if (chan->user_get_hi) - val |= (uint64_t)nvif_rd32(chan, chan->user_get_hi) << 32; + val |= (uint64_t)nvif_rd32(&chan->user, chan->user_get_hi) << 32; /* reset counter as long as GET is still advancing, this is * to avoid misdetecting a GPU lockup if the GPU happens to @@ -82,7 +82,7 @@ void nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo, int delta, int length) { - struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base); + struct nouveau_cli *cli = (void *)chan->user.client; struct nouveau_bo *pb = chan->push.buffer; struct nvkm_vma *vma; int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base; @@ -103,7 +103,7 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo, /* Flush writes. */ nouveau_bo_rd32(pb, 0); - nvif_wr32(chan, 0x8c, chan->dma.ib_put); + nvif_wr32(&chan->user, 0x8c, chan->dma.ib_put); chan->dma.ib_free--; } @@ -113,7 +113,7 @@ nv50_dma_push_wait(struct nouveau_channel *chan, int count) uint32_t cnt = 0, prev_get = 0; while (chan->dma.ib_free < count) { - uint32_t get = nvif_rd32(chan, 0x88); + uint32_t get = nvif_rd32(&chan->user, 0x88); if (get != prev_get) { prev_get = get; cnt = 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.h b/drivers/gpu/drm/nouveau/nouveau_dma.h index 8da0a272c45a3..aff3a9d0a1fcd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_dma.h +++ b/drivers/gpu/drm/nouveau/nouveau_dma.h @@ -140,7 +140,7 @@ BEGIN_IMC0(struct nouveau_channel *chan, int subc, int mthd, u16 data) #define WRITE_PUT(val) do { \ mb(); \ nouveau_bo_rd32(chan->push.buffer, 0); \ - nvif_wr32(chan, chan->user_put, ((val) << 2) + chan->push.vma.offset); \ + nvif_wr32(&chan->user, chan->user_put, ((val) << 2) + chan->push.vma.offset); \ } while (0) static inline void diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 86f567d4e5cd2..11cf52a7ff750 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -114,7 +114,7 @@ nouveau_cli_create(struct drm_device *dev, const char *sname, snprintf(cli->name, sizeof(cli->name), "%s", sname); cli->dev = dev; - ret = nvif_client_init(NULL, NULL, cli->name, nouveau_name(dev), + ret = nvif_client_init(NULL, cli->name, nouveau_name(dev), nouveau_config, nouveau_debug, &cli->base); if (ret == 0) { @@ -163,7 +163,7 @@ nouveau_accel_init(struct nouveau_drm *drm) /*XXX: this is crap, but the fence/channel stuff is a little * backwards in some places. this will be fixed. */ - ret = nvif_object_sclass(&device->base, sclass, ARRAY_SIZE(sclass)); + ret = nvif_object_sclass(&device->object, sclass, ARRAY_SIZE(sclass)); if (ret < 0) return; @@ -235,7 +235,7 @@ nouveau_accel_init(struct nouveau_drm *drm) return; } - ret = nvif_object_init(drm->channel->object, NULL, NVDRM_NVSW, + ret = nvif_object_init(&drm->channel->user, NVDRM_NVSW, nouveau_abi16_swclass(drm), NULL, 0, &drm->nvsw); if (ret == 0) { struct nvkm_sw_chan *swch; @@ -262,7 +262,7 @@ nouveau_accel_init(struct nouveau_drm *drm) } if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { - ret = nvkm_gpuobj_new(nvxx_object(&drm->device), NULL, 32, + ret = nvkm_gpuobj_new(nvxx_object(&drm->device.object), NULL, 32, 0, 0, &drm->notify); if (ret) { NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); @@ -270,7 +270,7 @@ nouveau_accel_init(struct nouveau_drm *drm) return; } - ret = nvif_object_init(drm->channel->object, NULL, NvNotify0, + ret = nvif_object_init(&drm->channel->user, NvNotify0, NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_VRAM, @@ -392,8 +392,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) nouveau_get_hdmi_dev(drm); - ret = nvif_device_init(&drm->client.base.base, NULL, NVDRM_DEVICE, - NV_DEVICE, + ret = nvif_device_init(&drm->client.base.object, + NVDRM_DEVICE, NV_DEVICE, &(struct nv_device_v0) { .device = ~0, }, sizeof(struct nv_device_v0), @@ -408,7 +408,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) * better fix is found - assuming there is one... */ if (drm->device.info.chipset == 0xc1) - nvif_mask(&drm->device, 0x00088080, 0x00000800, 0x00000000); + nvif_mask(&drm->device.object, 0x00088080, 0x00000800, 0x00000000); nouveau_vga_init(drm); nouveau_agp_init(drm); @@ -736,7 +736,7 @@ nouveau_pmops_runtime_resume(struct device *dev) ret = nouveau_do_resume(drm_dev, true); drm_kms_helper_poll_enable(drm_dev); /* do magic */ - nvif_mask(device, 0x88488, (1 << 25), (1 << 25)); + nvif_mask(&device->object, 0x088488, (1 << 25), (1 << 25)); vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_ON); drm_dev->switch_power_state = DRM_SWITCH_POWER_ON; return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c index c6d56bef5823f..574c36b492ee4 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.c +++ b/drivers/gpu/drm/nouveau/nouveau_fence.c @@ -169,7 +169,7 @@ void nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_chan *fctx) { struct nouveau_fence_priv *priv = (void*)chan->drm->fence; - struct nouveau_cli *cli = (void *)nvif_client(chan->object); + struct nouveau_cli *cli = (void *)chan->user.client; int ret; INIT_LIST_HEAD(&fctx->flip); @@ -188,13 +188,12 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha if (!priv->uevent) return; - ret = nvif_notify_init(chan->object, NULL, - nouveau_fence_wait_uevent_handler, false, - G82_CHANNEL_DMA_V0_NTFY_UEVENT, - &(struct nvif_notify_uevent_req) { }, - sizeof(struct nvif_notify_uevent_req), - sizeof(struct nvif_notify_uevent_rep), - &fctx->notify); + ret = nvif_notify_init(&chan->user, nouveau_fence_wait_uevent_handler, + false, G82_CHANNEL_DMA_V0_NTFY_UEVENT, + &(struct nvif_notify_uevent_req) { }, + sizeof(struct nvif_notify_uevent_req), + sizeof(struct nvif_notify_uevent_rep), + &fctx->notify); WARN_ON(ret); } diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index dc5845ee2fa0d..dc2378c01b6d1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -681,7 +681,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, return -ENOMEM; list_for_each_entry(temp, &abi16->channels, head) { - if (temp->chan->object->handle == (NVDRM_CHAN | req->channel)) { + if (temp->chan->user.handle == (NVDRM_CHAN | req->channel)) { chan = temp->chan; break; } diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c index 1ec8f38ae69a0..ce612064fa6a9 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c @@ -188,9 +188,9 @@ nouveau_sysfs_init(struct drm_device *dev) if (!sysfs) return -ENOMEM; - ret = nvif_object_init(nvif_object(device), NULL, NVDRM_CONTROL, + ret = nvif_object_init(&device->object, NVDRM_CONTROL, NVIF_IOCTL_NEW_V0_CONTROL, NULL, 0, - &sysfs->ctrl); + &sysfs->ctrl); if (ret == 0) device_create_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate); diff --git a/drivers/gpu/drm/nouveau/nouveau_vga.c b/drivers/gpu/drm/nouveau/nouveau_vga.c index c7592ec8ecb8e..af89c3665b2ab 100644 --- a/drivers/gpu/drm/nouveau/nouveau_vga.c +++ b/drivers/gpu/drm/nouveau/nouveau_vga.c @@ -12,13 +12,14 @@ static unsigned int nouveau_vga_set_decode(void *priv, bool state) { - struct nvif_device *device = &nouveau_drm(priv)->device; + struct nouveau_drm *drm = nouveau_drm(priv); + struct nvif_object *device = &drm->device.object; - if (device->info.family == NV_DEVICE_INFO_V0_CURIE && - device->info.chipset >= 0x4c) + if (drm->device.info.family == NV_DEVICE_INFO_V0_CURIE && + drm->device.info.chipset >= 0x4c) nvif_wr32(device, 0x088060, state); else - if (device->info.chipset >= 0x40) + if (drm->device.info.chipset >= 0x40) nvif_wr32(device, 0x088054, state); else nvif_wr32(device, 0x001854, state); diff --git a/drivers/gpu/drm/nouveau/nv04_fbcon.c b/drivers/gpu/drm/nouveau/nv04_fbcon.c index 495c57644ced9..789dc2993b0dd 100644 --- a/drivers/gpu/drm/nouveau/nv04_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv04_fbcon.c @@ -171,33 +171,33 @@ nv04_fbcon_accel_init(struct fb_info *info) return -EINVAL; } - ret = nvif_object_init(chan->object, NULL, 0x0062, + ret = nvif_object_init(&chan->user, 0x0062, device->info.family >= NV_DEVICE_INFO_V0_CELSIUS ? 0x0062 : 0x0042, NULL, 0, &nfbdev->surf2d); if (ret) return ret; - ret = nvif_object_init(chan->object, NULL, 0x0019, 0x0019, NULL, 0, + ret = nvif_object_init(&chan->user, 0x0019, 0x0019, NULL, 0, &nfbdev->clip); if (ret) return ret; - ret = nvif_object_init(chan->object, NULL, 0x0043, 0x0043, NULL, 0, + ret = nvif_object_init(&chan->user, 0x0043, 0x0043, NULL, 0, &nfbdev->rop); if (ret) return ret; - ret = nvif_object_init(chan->object, NULL, 0x0044, 0x0044, NULL, 0, + ret = nvif_object_init(&chan->user, 0x0044, 0x0044, NULL, 0, &nfbdev->patt); if (ret) return ret; - ret = nvif_object_init(chan->object, NULL, 0x004a, 0x004a, NULL, 0, + ret = nvif_object_init(&chan->user, 0x004a, 0x004a, NULL, 0, &nfbdev->gdi); if (ret) return ret; - ret = nvif_object_init(chan->object, NULL, 0x005f, + ret = nvif_object_init(&chan->user, 0x005f, device->info.chipset >= 0x11 ? 0x009f : 0x005f, NULL, 0, &nfbdev->blit); if (ret) diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index c2e05e64cd6f5..f4a26224ac68b 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c @@ -57,7 +57,7 @@ nv04_fence_sync(struct nouveau_fence *fence, static u32 nv04_fence_read(struct nouveau_channel *chan) { - struct nvkm_fifo_chan *fifo = nvxx_fifo_chan(chan);; + struct nvkm_fifo_chan *fifo = nvxx_fifo_chan(&chan->user); return atomic_read(&fifo->refcnt); } diff --git a/drivers/gpu/drm/nouveau/nv10_fence.c b/drivers/gpu/drm/nouveau/nv10_fence.c index 5e1ea1cdce75e..2c35213da2758 100644 --- a/drivers/gpu/drm/nouveau/nv10_fence.c +++ b/drivers/gpu/drm/nouveau/nv10_fence.c @@ -50,7 +50,7 @@ nv10_fence_sync(struct nouveau_fence *fence, u32 nv10_fence_read(struct nouveau_channel *chan) { - return nvif_rd32(chan, 0x0048); + return nvif_rd32(&chan->user, 0x0048); } void diff --git a/drivers/gpu/drm/nouveau/nv17_fence.c b/drivers/gpu/drm/nouveau/nv17_fence.c index 57860cfa1de5c..80b6eb8b3d02a 100644 --- a/drivers/gpu/drm/nouveau/nv17_fence.c +++ b/drivers/gpu/drm/nouveau/nv17_fence.c @@ -33,7 +33,7 @@ int nv17_fence_sync(struct nouveau_fence *fence, struct nouveau_channel *prev, struct nouveau_channel *chan) { - struct nouveau_cli *cli = (void *)nvif_client(&prev->device->base); + struct nouveau_cli *cli = (void *)prev->user.client; struct nv10_fence_priv *priv = chan->drm->fence; struct nv10_fence_chan *fctx = chan->fence; u32 value; @@ -89,7 +89,7 @@ nv17_fence_context_new(struct nouveau_channel *chan) fctx->base.read = nv10_fence_read; fctx->base.sync = nv17_fence_sync; - ret = nvif_object_init(chan->object, NULL, NvSema, NV_DMA_FROM_MEMORY, + ret = nvif_object_init(&chan->user, NvSema, NV_DMA_FROM_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_VRAM, .access = NV_DMA_V0_ACCESS_RDWR, diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index c56775f5aff39..794a20ea71fea 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -60,16 +60,20 @@ struct nv50_chan { struct nvif_object user; + struct nvif_device *device; }; static int -nv50_chan_create(struct nvif_object *disp, const u32 *oclass, u8 head, - void *data, u32 size, struct nv50_chan *chan) +nv50_chan_create(struct nvif_device *device, struct nvif_object *disp, + const u32 *oclass, u8 head, void *data, u32 size, + struct nv50_chan *chan) { const u32 handle = (oclass[0] << 16) | head; u32 sclass[8]; int ret, i; + chan->device = device; + ret = nvif_object_sclass(disp, sclass, ARRAY_SIZE(sclass)); WARN_ON(ret > ARRAY_SIZE(sclass)); if (ret < 0) @@ -78,9 +82,8 @@ nv50_chan_create(struct nvif_object *disp, const u32 *oclass, u8 head, while (oclass[0]) { for (i = 0; i < ARRAY_SIZE(sclass); i++) { if (sclass[i] == oclass[0]) { - ret = nvif_object_init(disp, NULL, handle, - oclass[0], data, size, - &chan->user); + ret = nvif_object_init(disp, handle, oclass[0], + data, size, &chan->user); if (ret == 0) nvif_object_map(&chan->user); return ret; @@ -113,10 +116,12 @@ nv50_pioc_destroy(struct nv50_pioc *pioc) } static int -nv50_pioc_create(struct nvif_object *disp, const u32 *oclass, u8 head, - void *data, u32 size, struct nv50_pioc *pioc) +nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp, + const u32 *oclass, u8 head, void *data, u32 size, + struct nv50_pioc *pioc) { - return nv50_chan_create(disp, oclass, head, data, size, &pioc->base); + return nv50_chan_create(device, disp, oclass, head, data, size, + &pioc->base); } /****************************************************************************** @@ -128,7 +133,8 @@ struct nv50_curs { }; static int -nv50_curs_create(struct nvif_object *disp, int head, struct nv50_curs *curs) +nv50_curs_create(struct nvif_device *device, struct nvif_object *disp, + int head, struct nv50_curs *curs) { struct nv50_disp_cursor_v0 args = { .head = head, @@ -142,8 +148,8 @@ nv50_curs_create(struct nvif_object *disp, int head, struct nv50_curs *curs) 0 }; - return nv50_pioc_create(disp, oclass, head, &args, sizeof(args), - &curs->base); + return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args), + &curs->base); } /****************************************************************************** @@ -155,7 +161,8 @@ struct nv50_oimm { }; static int -nv50_oimm_create(struct nvif_object *disp, int head, struct nv50_oimm *oimm) +nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp, + int head, struct nv50_oimm *oimm) { struct nv50_disp_cursor_v0 args = { .head = head, @@ -169,8 +176,8 @@ nv50_oimm_create(struct nvif_object *disp, int head, struct nv50_oimm *oimm) 0 }; - return nv50_pioc_create(disp, oclass, head, &args, sizeof(args), - &oimm->base); + return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args), + &oimm->base); } /****************************************************************************** @@ -194,23 +201,24 @@ struct nv50_dmac { static void nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp) { + struct nvif_device *device = dmac->base.device; + nvif_object_fini(&dmac->vram); nvif_object_fini(&dmac->sync); nv50_chan_destroy(&dmac->base); if (dmac->ptr) { - struct pci_dev *pdev = nvxx_device(nvif_device(disp))->pdev; + struct pci_dev *pdev = nvxx_device(device)->pdev; pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle); } } static int -nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head, - void *data, u32 size, u64 syncbuf, +nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, + const u32 *oclass, u8 head, void *data, u32 size, u64 syncbuf, struct nv50_dmac *dmac) { - struct nvif_device *device = nvif_device(disp); struct nv50_disp_core_channel_dma_v0 *args = data; struct nvif_object pushbuf; int ret; @@ -222,9 +230,8 @@ nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head, if (!dmac->ptr) return -ENOMEM; - ret = nvif_object_init(nvif_object(device), NULL, - args->pushbuf, NV_DMA_FROM_MEMORY, - &(struct nv_dma_v0) { + ret = nvif_object_init(&device->object, args->pushbuf, + NV_DMA_FROM_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_PCI_US, .access = NV_DMA_V0_ACCESS_RD, .start = dmac->handle + 0x0000, @@ -233,13 +240,13 @@ nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head, if (ret) return ret; - ret = nv50_chan_create(disp, oclass, head, data, size, &dmac->base); + ret = nv50_chan_create(device, disp, oclass, head, data, size, + &dmac->base); nvif_object_fini(&pushbuf); if (ret) return ret; - ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000000, - NV_DMA_IN_MEMORY, + ret = nvif_object_init(&dmac->base.user, 0xf0000000, NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_VRAM, .access = NV_DMA_V0_ACCESS_RDWR, @@ -250,8 +257,7 @@ nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head, if (ret) return ret; - ret = nvif_object_init(&dmac->base.user, NULL, 0xf0000001, - NV_DMA_IN_MEMORY, + ret = nvif_object_init(&dmac->base.user, 0xf0000001, NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_VRAM, .access = NV_DMA_V0_ACCESS_RDWR, @@ -274,7 +280,8 @@ struct nv50_mast { }; static int -nv50_core_create(struct nvif_object *disp, u64 syncbuf, struct nv50_mast *core) +nv50_core_create(struct nvif_device *device, struct nvif_object *disp, + u64 syncbuf, struct nv50_mast *core) { struct nv50_disp_core_channel_dma_v0 args = { .pushbuf = 0xb0007d00, @@ -293,8 +300,8 @@ nv50_core_create(struct nvif_object *disp, u64 syncbuf, struct nv50_mast *core) 0 }; - return nv50_dmac_create(disp, oclass, 0, &args, sizeof(args), syncbuf, - &core->base); + return nv50_dmac_create(device, disp, oclass, 0, &args, sizeof(args), + syncbuf, &core->base); } /****************************************************************************** @@ -308,8 +315,8 @@ struct nv50_sync { }; static int -nv50_base_create(struct nvif_object *disp, int head, u64 syncbuf, - struct nv50_sync *base) +nv50_base_create(struct nvif_device *device, struct nvif_object *disp, + int head, u64 syncbuf, struct nv50_sync *base) { struct nv50_disp_base_channel_dma_v0 args = { .pushbuf = 0xb0007c00 | head, @@ -326,7 +333,7 @@ nv50_base_create(struct nvif_object *disp, int head, u64 syncbuf, 0 }; - return nv50_dmac_create(disp, oclass, head, &args, sizeof(args), + return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args), syncbuf, &base->base); } @@ -339,8 +346,8 @@ struct nv50_ovly { }; static int -nv50_ovly_create(struct nvif_object *disp, int head, u64 syncbuf, - struct nv50_ovly *ovly) +nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp, + int head, u64 syncbuf, struct nv50_ovly *ovly) { struct nv50_disp_overlay_channel_dma_v0 args = { .pushbuf = 0xb0007e00 | head, @@ -356,7 +363,7 @@ nv50_ovly_create(struct nvif_object *disp, int head, u64 syncbuf, 0 }; - return nv50_dmac_create(disp, oclass, head, &args, sizeof(args), + return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args), syncbuf, &ovly->base); } @@ -413,7 +420,7 @@ static u32 * evo_wait(void *evoc, int nr) { struct nv50_dmac *dmac = evoc; - struct nvif_device *device = nvif_device(&dmac->base.user); + struct nvif_device *device = dmac->base.device; u32 put = nvif_rd32(&dmac->base.user, 0x0000) / 4; mutex_lock(&dmac->lock); @@ -573,7 +580,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, if (unlikely(push == NULL)) return -EBUSY; - if (chan && chan->object->oclass < G82_CHANNEL_GPFIFO) { + if (chan && chan->user.oclass < G82_CHANNEL_GPFIFO) { ret = RING_SPACE(chan, 8); if (ret) return ret; @@ -587,7 +594,7 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, OUT_RING (chan, sync->addr); OUT_RING (chan, sync->data); } else - if (chan && chan->object->oclass < FERMI_CHANNEL_GPFIFO) { + if (chan && chan->user.oclass < FERMI_CHANNEL_GPFIFO) { u64 addr = nv84_fence_crtc(chan, nv_crtc->index) + sync->addr; ret = RING_SPACE(chan, 12); if (ret) @@ -1418,6 +1425,8 @@ static const struct drm_crtc_funcs nv50_crtc_func = { static int nv50_crtc_create(struct drm_device *dev, int index) { + struct nouveau_drm *drm = nouveau_drm(dev); + struct nvif_device *device = &drm->device; struct nv50_disp *disp = nv50_disp(dev); struct nv50_head *head; struct drm_crtc *crtc; @@ -1462,13 +1471,13 @@ nv50_crtc_create(struct drm_device *dev, int index) goto out; /* allocate cursor resources */ - ret = nv50_curs_create(disp->disp, index, &head->curs); + ret = nv50_curs_create(device, disp->disp, index, &head->curs); if (ret) goto out; /* allocate page flip / sync resources */ - ret = nv50_base_create(disp->disp, index, disp->sync->bo.offset, - &head->sync); + ret = nv50_base_create(device, disp->disp, index, disp->sync->bo.offset, + &head->sync); if (ret) goto out; @@ -1476,12 +1485,12 @@ nv50_crtc_create(struct drm_device *dev, int index) head->sync.data = 0x00000000; /* allocate overlay resources */ - ret = nv50_oimm_create(disp->disp, index, &head->oimm); + ret = nv50_oimm_create(device, disp->disp, index, &head->oimm); if (ret) goto out; - ret = nv50_ovly_create(disp->disp, index, disp->sync->bo.offset, - &head->ovly); + ret = nv50_ovly_create(device, disp->disp, index, disp->sync->bo.offset, + &head->ovly); if (ret) goto out; @@ -2370,8 +2379,8 @@ nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kin list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { struct nv50_head *head = nv50_head(crtc); - int ret = nvif_object_init(&head->sync.base.base.user, NULL, - name, NV_DMA_IN_MEMORY, &args, size, + int ret = nvif_object_init(&head->sync.base.base.user, name, + NV_DMA_IN_MEMORY, &args, size, &fbdma->base[head->base.index]); if (ret) { nv50_fbdma_fini(fbdma); @@ -2379,9 +2388,8 @@ nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kin } } - ret = nvif_object_init(&mast->base.base.user, NULL, name, - NV_DMA_IN_MEMORY, &args, size, - &fbdma->core); + ret = nvif_object_init(&mast->base.base.user, name, NV_DMA_IN_MEMORY, + &args, size, &fbdma->core); if (ret) { nv50_fbdma_fini(fbdma); return ret; @@ -2534,14 +2542,14 @@ nv50_display_create(struct drm_device *dev) goto out; /* allocate master evo channel */ - ret = nv50_core_create(disp->disp, disp->sync->bo.offset, + ret = nv50_core_create(device, disp->disp, disp->sync->bo.offset, &disp->mast); if (ret) goto out; /* create crtc objects to represent the hw heads */ if (disp->disp->oclass >= GF110_DISP) - crtcs = nvif_rd32(device, 0x022448); + crtcs = nvif_rd32(&device->object, 0x022448); else crtcs = 2; diff --git a/drivers/gpu/drm/nouveau/nv50_fbcon.c b/drivers/gpu/drm/nouveau/nv50_fbcon.c index 901130b060729..e05499d6ed839 100644 --- a/drivers/gpu/drm/nouveau/nv50_fbcon.c +++ b/drivers/gpu/drm/nouveau/nv50_fbcon.c @@ -183,7 +183,7 @@ nv50_fbcon_accel_init(struct fb_info *info) return -EINVAL; } - ret = nvif_object_init(chan->object, NULL, 0x502d, 0x502d, NULL, 0, + ret = nvif_object_init(&chan->user, 0x502d, 0x502d, NULL, 0, &nfbdev->twod); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nv50_fence.c b/drivers/gpu/drm/nouveau/nv50_fence.c index a82d9ea7c6fde..f0d96e5da6b47 100644 --- a/drivers/gpu/drm/nouveau/nv50_fence.c +++ b/drivers/gpu/drm/nouveau/nv50_fence.c @@ -51,7 +51,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) fctx->base.read = nv10_fence_read; fctx->base.sync = nv17_fence_sync; - ret = nvif_object_init(chan->object, NULL, NvSema, NV_DMA_IN_MEMORY, + ret = nvif_object_init(&chan->user, NvSema, NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_VRAM, .access = NV_DMA_V0_ACCESS_RDWR, @@ -66,7 +66,7 @@ nv50_fence_context_new(struct nouveau_channel *chan) u32 start = bo->bo.mem.start * PAGE_SIZE; u32 limit = start + bo->bo.mem.size - 1; - ret = nvif_object_init(chan->object, NULL, NvEvoSema0 + i, + ret = nvif_object_init(&chan->user, NvEvoSema0 + i, NV_DMA_IN_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_VRAM, .access = NV_DMA_V0_ACCESS_RDWR, diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 76098a58e2faf..4d7ad6d3fbd4d 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -131,7 +131,7 @@ nv84_fence_context_del(struct nouveau_channel *chan) int nv84_fence_context_new(struct nouveau_channel *chan) { - struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base); + struct nouveau_cli *cli = (void *)chan->user.client; struct nv84_fence_priv *priv = chan->drm->fence; struct nv84_fence_chan *fctx; int ret, i; diff --git a/drivers/gpu/drm/nouveau/nvc0_fbcon.c b/drivers/gpu/drm/nouveau/nvc0_fbcon.c index fcd2e5f27bb95..c97395b4a3124 100644 --- a/drivers/gpu/drm/nouveau/nvc0_fbcon.c +++ b/drivers/gpu/drm/nouveau/nvc0_fbcon.c @@ -156,7 +156,7 @@ nvc0_fbcon_accel_init(struct fb_info *info) struct nouveau_channel *chan = drm->channel; int ret, format; - ret = nvif_object_init(chan->object, NULL, 0x902d, 0x902d, NULL, 0, + ret = nvif_object_init(&chan->user, 0x902d, 0x902d, NULL, 0, &nfbdev->twod); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index 80b96844221e1..4a830ebf9661b 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -29,29 +29,30 @@ int nvif_client_ioctl(struct nvif_client *client, void *data, u32 size) { - return client->driver->ioctl(client->base.priv, client->super, data, size, NULL); + return client->driver->ioctl(client->object.priv, client->super, data, size, NULL); } int nvif_client_suspend(struct nvif_client *client) { - return client->driver->suspend(client->base.priv); + return client->driver->suspend(client->object.priv); } int nvif_client_resume(struct nvif_client *client) { - return client->driver->resume(client->base.priv); + return client->driver->resume(client->object.priv); } void nvif_client_fini(struct nvif_client *client) { if (client->driver) { - client->driver->fini(client->base.priv); + client->driver->fini(client->object.priv); client->driver = NULL; - client->base.parent = NULL; - nvif_object_fini(&client->base); + client->object.parent = NULL; + client->object.client = NULL; + nvif_object_fini(&client->object); } } @@ -68,25 +69,25 @@ nvif_drivers[] = { }; int -nvif_client_init(void (*dtor)(struct nvif_client *), const char *driver, - const char *name, u64 device, const char *cfg, const char *dbg, - struct nvif_client *client) +nvif_client_init(const char *driver, const char *name, u64 device, + const char *cfg, const char *dbg, struct nvif_client *client) { int ret, i; - ret = nvif_object_init(NULL, (void*)dtor, 0, 0, NULL, 0, &client->base); + ret = nvif_object_init(NULL, 0, 0, NULL, 0, &client->object); if (ret) return ret; - client->base.parent = &client->base; - client->base.handle = ~0; - client->object = &client->base; + client->object.client = client; + client->object.parent = &client->object; + client->object.handle = ~0; + client->route = NVIF_IOCTL_V0_ROUTE_NVIF; client->super = true; for (i = 0, ret = -EINVAL; (client->driver = nvif_drivers[i]); i++) { if (!driver || !strcmp(client->driver->name, driver)) { ret = client->driver->init(name, device, cfg, dbg, - &client->base.priv); + &client->object.priv); if (!ret || driver) break; } @@ -96,35 +97,3 @@ nvif_client_init(void (*dtor)(struct nvif_client *), const char *driver, nvif_client_fini(client); return ret; } - -static void -nvif_client_del(struct nvif_client *client) -{ - nvif_client_fini(client); - kfree(client); -} - -int -nvif_client_new(const char *driver, const char *name, u64 device, - const char *cfg, const char *dbg, - struct nvif_client **pclient) -{ - struct nvif_client *client = kzalloc(sizeof(*client), GFP_KERNEL); - if (client) { - int ret = nvif_client_init(nvif_client_del, driver, name, - device, cfg, dbg, client); - if (ret) { - kfree(client); - client = NULL; - } - *pclient = client; - return ret; - } - return -ENOMEM; -} - -void -nvif_client_ref(struct nvif_client *client, struct nvif_client **pclient) -{ - nvif_object_ref(&client->base, (struct nvif_object **)pclient); -} diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c index 837442c69a5d2..f15d51a69df2b 100644 --- a/drivers/gpu/drm/nouveau/nvif/device.c +++ b/drivers/gpu/drm/nouveau/nvif/device.c @@ -33,52 +33,19 @@ nvif_device_time(struct nvif_device *device) void nvif_device_fini(struct nvif_device *device) { - nvif_object_fini(&device->base); + nvif_object_fini(&device->object); } int -nvif_device_init(struct nvif_object *parent, void (*dtor)(struct nvif_device *), - u32 handle, u32 oclass, void *data, u32 size, - struct nvif_device *device) +nvif_device_init(struct nvif_object *parent, u32 handle, u32 oclass, + void *data, u32 size, struct nvif_device *device) { - int ret = nvif_object_init(parent, (void *)dtor, handle, oclass, - data, size, &device->base); + int ret = nvif_object_init(parent, handle, oclass, data, size, + &device->object); if (ret == 0) { - device->object = &device->base; device->info.version = 0; - ret = nvif_object_mthd(&device->base, NV_DEVICE_V0_INFO, + ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_INFO, &device->info, sizeof(device->info)); } return ret; } - -static void -nvif_device_del(struct nvif_device *device) -{ - nvif_device_fini(device); - kfree(device); -} - -int -nvif_device_new(struct nvif_object *parent, u32 handle, u32 oclass, - void *data, u32 size, struct nvif_device **pdevice) -{ - struct nvif_device *device = kzalloc(sizeof(*device), GFP_KERNEL); - if (device) { - int ret = nvif_device_init(parent, nvif_device_del, handle, - oclass, data, size, device); - if (ret) { - kfree(device); - device = NULL; - } - *pdevice = device; - return ret; - } - return -ENOMEM; -} - -void -nvif_device_ref(struct nvif_device *device, struct nvif_device **pdevice) -{ - nvif_object_ref(&device->base, (struct nvif_object **)pdevice); -} diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c index 8e34748709a0c..b0787ff833ef6 100644 --- a/drivers/gpu/drm/nouveau/nvif/notify.c +++ b/drivers/gpu/drm/nouveau/nvif/notify.c @@ -124,7 +124,7 @@ nvif_notify(const void *header, u32 length, const void *data, u32 size) } if (!WARN_ON(notify == NULL)) { - struct nvif_client *client = nvif_client(notify->object); + struct nvif_client *client = notify->object->client; if (!WARN_ON(notify->size != size)) { atomic_inc(¬ify->putcnt); if (test_bit(NVIF_NOTIFY_WORK, ¬ify->flags)) { @@ -156,7 +156,7 @@ nvif_notify_fini(struct nvif_notify *notify) if (ret >= 0 && object) { ret = nvif_object_ioctl(object, &args, sizeof(args), NULL); if (ret == 0) { - nvif_object_ref(NULL, ¬ify->object); + notify->object = NULL; kfree((void *)notify->data); } } @@ -164,9 +164,9 @@ nvif_notify_fini(struct nvif_notify *notify) } int -nvif_notify_init(struct nvif_object *object, void (*dtor)(struct nvif_notify *), - int (*func)(struct nvif_notify *), bool work, u8 event, - void *data, u32 size, u32 reply, struct nvif_notify *notify) +nvif_notify_init(struct nvif_object *object, int (*func)(struct nvif_notify *), + bool work, u8 event, void *data, u32 size, u32 reply, + struct nvif_notify *notify) { struct { struct nvif_ioctl_v0 ioctl; @@ -175,11 +175,9 @@ nvif_notify_init(struct nvif_object *object, void (*dtor)(struct nvif_notify *), } *args; int ret = -ENOMEM; - notify->object = NULL; - nvif_object_ref(object, ¬ify->object); + notify->object = object; notify->flags = 0; atomic_set(¬ify->putcnt, 1); - notify->dtor = dtor; notify->func = func; notify->data = NULL; notify->size = reply; @@ -211,38 +209,3 @@ done: nvif_notify_fini(notify); return ret; } - -static void -nvif_notify_del(struct nvif_notify *notify) -{ - nvif_notify_fini(notify); - kfree(notify); -} - -void -nvif_notify_ref(struct nvif_notify *notify, struct nvif_notify **pnotify) -{ - BUG_ON(notify != NULL); - if (*pnotify) - (*pnotify)->dtor(*pnotify); - *pnotify = notify; -} - -int -nvif_notify_new(struct nvif_object *object, int (*func)(struct nvif_notify *), - bool work, u8 type, void *data, u32 size, u32 reply, - struct nvif_notify **pnotify) -{ - struct nvif_notify *notify = kzalloc(sizeof(*notify), GFP_KERNEL); - if (notify) { - int ret = nvif_notify_init(object, nvif_notify_del, func, work, - type, data, size, reply, notify); - if (ret) { - kfree(notify); - notify = NULL; - } - *pnotify = notify; - return ret; - } - return -ENOMEM; -} diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index 3ab4e2f8cc12e..a727f72ca2343 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -30,7 +30,7 @@ int nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) { - struct nvif_client *client = nvif_client(object); + struct nvif_client *client = object->client; union { struct nvif_ioctl_v0 v0; } *args = data; @@ -47,7 +47,8 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) } else return -ENOSYS; - return client->driver->ioctl(client->base.priv, client->super, data, size, hack); + return client->driver->ioctl(client->object.priv, client->super, + data, size, hack); } int @@ -145,7 +146,7 @@ void nvif_object_unmap(struct nvif_object *object) { if (object->map.size) { - struct nvif_client *client = nvif_client(object); + struct nvif_client *client = object->client; struct { struct nvif_ioctl_v0 ioctl; struct nvif_ioctl_unmap unmap; @@ -167,7 +168,7 @@ nvif_object_unmap(struct nvif_object *object) int nvif_object_map(struct nvif_object *object) { - struct nvif_client *client = nvif_client(object); + struct nvif_client *client = object->client; struct { struct nvif_ioctl_v0 ioctl; struct nvif_ioctl_map_v0 map; @@ -186,119 +187,65 @@ nvif_object_map(struct nvif_object *object) return ret; } -struct ctor { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_new_v0 new; -}; - void nvif_object_fini(struct nvif_object *object) { - struct ctor *ctor = container_of(object->data, typeof(*ctor), new.data); - if (object->parent) { - struct { - struct nvif_ioctl_v0 ioctl; - struct nvif_ioctl_del del; - } args = { - .ioctl.type = NVIF_IOCTL_V0_DEL, - }; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_del del; + } args = { + .ioctl.type = NVIF_IOCTL_V0_DEL, + }; - nvif_object_unmap(object); - nvif_object_ioctl(object, &args, sizeof(args), NULL); - if (object->data) { - object->size = 0; - object->data = NULL; - kfree(ctor); - } - nvif_object_ref(NULL, &object->parent); - } + if (!object->client) + return; + + nvif_object_unmap(object); + nvif_object_ioctl(object, &args, sizeof(args), NULL); + object->client = NULL; } int -nvif_object_init(struct nvif_object *parent, void (*dtor)(struct nvif_object *), - u32 handle, u32 oclass, void *data, u32 size, - struct nvif_object *object) +nvif_object_init(struct nvif_object *parent, u32 handle, u32 oclass, + void *data, u32 size, struct nvif_object *object) { - struct ctor *ctor; + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_new_v0 new; + } *args; int ret = 0; - object->parent = NULL; - object->object = object; - nvif_object_ref(parent, &object->parent); - kref_init(&object->refcount); + object->client = NULL; + object->parent = parent; object->handle = handle; object->oclass = oclass; - object->data = NULL; - object->size = 0; - object->dtor = dtor; object->map.ptr = NULL; object->map.size = 0; if (object->parent) { - if (!(ctor = kmalloc(sizeof(*ctor) + size, GFP_KERNEL))) { + if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) { nvif_object_fini(object); return -ENOMEM; } - object->data = ctor->new.data; - object->size = size; - memcpy(object->data, data, size); - ctor->ioctl.version = 0; - ctor->ioctl.type = NVIF_IOCTL_V0_NEW; - ctor->new.version = 0; - ctor->new.route = NVIF_IOCTL_V0_ROUTE_NVIF; - ctor->new.token = (unsigned long)(void *)object; - ctor->new.handle = handle; - ctor->new.oclass = oclass; - - ret = nvif_object_ioctl(parent, ctor, sizeof(*ctor) + - object->size, &object->priv); + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_NEW; + args->new.version = 0; + args->new.route = parent->client->route; + args->new.token = (unsigned long)(void *)object; + args->new.handle = handle; + args->new.oclass = oclass; + + memcpy(args->new.data, data, size); + ret = nvif_object_ioctl(parent, args, sizeof(*args) + size, + &object->priv); + memcpy(data, args->new.data, size); + kfree(args); + if (ret == 0) + object->client = parent->client; } if (ret) nvif_object_fini(object); return ret; } - -static void -nvif_object_del(struct nvif_object *object) -{ - nvif_object_fini(object); - kfree(object); -} - -int -nvif_object_new(struct nvif_object *parent, u32 handle, u32 oclass, - void *data, u32 size, struct nvif_object **pobject) -{ - struct nvif_object *object = kzalloc(sizeof(*object), GFP_KERNEL); - if (object) { - int ret = nvif_object_init(parent, nvif_object_del, handle, - oclass, data, size, object); - if (ret) { - kfree(object); - object = NULL; - } - *pobject = object; - return ret; - } - return -ENOMEM; -} - -static void -nvif_object_put(struct kref *kref) -{ - struct nvif_object *object = - container_of(kref, typeof(*object), refcount); - object->dtor(object); -} - -void -nvif_object_ref(struct nvif_object *object, struct nvif_object **pobject) -{ - if (object) - kref_get(&object->refcount); - if (*pobject) - kref_put(&(*pobject)->refcount, nvif_object_put); - *pobject = object; -} -- GitLab From bf81df9be28657eea4aca8c6ab4ed3e69f8a051c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5472/7006] drm/nouveau/nvif: replace path-based object identification Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 23 ++++----- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 12 ++--- drivers/gpu/drm/nouveau/include/nvif/object.h | 2 +- .../drm/nouveau/include/nvkm/core/client.h | 6 +++ .../drm/nouveau/include/nvkm/core/handle.h | 5 +- .../drm/nouveau/include/nvkm/engine/fifo.h | 3 +- drivers/gpu/drm/nouveau/nouveau_chan.c | 6 +-- drivers/gpu/drm/nouveau/nv50_display.c | 4 +- drivers/gpu/drm/nouveau/nvif/client.c | 2 - drivers/gpu/drm/nouveau/nvif/object.c | 17 +++---- drivers/gpu/drm/nouveau/nvkm/core/client.c | 50 ++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/core/handle.c | 22 ++------ drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 51 ++++++++----------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 27 +++++----- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 17 ++++--- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 4 +- 24 files changed, 152 insertions(+), 116 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 91e57ba855039..f7394b9a1047b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -354,8 +354,8 @@ struct nvif_control_pstate_user_v0 { struct nv03_channel_dma_v0 { __u8 version; __u8 chid; - __u8 pad02[2]; - __u32 pushbuf; + __u8 pad02[6]; + __u64 pushbuf; __u64 offset; }; @@ -368,10 +368,10 @@ struct nv03_channel_dma_v0 { struct nv50_channel_gpfifo_v0 { __u8 version; __u8 chid; - __u8 pad01[6]; - __u32 pushbuf; + __u8 pad02[2]; __u32 ilength; __u64 ioffset; + __u64 pushbuf; }; struct kepler_channel_gpfifo_a_v0 { @@ -385,10 +385,9 @@ struct kepler_channel_gpfifo_a_v0 { #define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40 __u8 engine; __u16 chid; - __u8 pad04[4]; - __u32 pushbuf; __u32 ilength; __u64 ioffset; + __u64 pushbuf; }; /******************************************************************************* @@ -509,8 +508,8 @@ struct nv50_disp_pior_pwr_v0 { /* core */ struct nv50_disp_core_channel_dma_v0 { __u8 version; - __u8 pad01[3]; - __u32 pushbuf; + __u8 pad01[7]; + __u64 pushbuf; }; #define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 @@ -527,9 +526,9 @@ struct nv50_disp_cursor_v0 { /* base */ struct nv50_disp_base_channel_dma_v0 { __u8 version; - __u8 pad01[2]; __u8 head; - __u32 pushbuf; + __u8 pad02[6]; + __u64 pushbuf; }; #define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 @@ -537,9 +536,9 @@ struct nv50_disp_base_channel_dma_v0 { /* overlay */ struct nv50_disp_overlay_channel_dma_v0 { __u8 version; - __u8 pad01[2]; __u8 head; - __u32 pushbuf; + __u8 pad02[6]; + __u64 pushbuf; }; #define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00 diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 2eb9b899ab36b..9d99768f1a357 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -3,9 +3,6 @@ struct nvif_ioctl_v0 { __u8 version; -#define NVIF_IOCTL_V0_OWNER_NVIF 0x00 -#define NVIF_IOCTL_V0_OWNER_ANY 0xff - __u8 owner; #define NVIF_IOCTL_V0_NOP 0x00 #define NVIF_IOCTL_V0_SCLASS 0x01 #define NVIF_IOCTL_V0_NEW 0x02 @@ -20,13 +17,15 @@ struct nvif_ioctl_v0 { #define NVIF_IOCTL_V0_NTFY_GET 0x0b #define NVIF_IOCTL_V0_NTFY_PUT 0x0c __u8 type; - __u8 path_nr; + __u8 pad02[4]; +#define NVIF_IOCTL_V0_OWNER_NVIF 0x00 +#define NVIF_IOCTL_V0_OWNER_ANY 0xff + __u8 owner; #define NVIF_IOCTL_V0_ROUTE_NVIF 0x00 #define NVIF_IOCTL_V0_ROUTE_HIDDEN 0xff - __u8 pad04[3]; __u8 route; __u64 token; - __u32 path[8]; /* in reverse */ + __u64 object; __u8 data[]; /* ioctl data (below) */ }; @@ -47,6 +46,7 @@ struct nvif_ioctl_new_v0 { __u8 pad01[6]; __u8 route; __u64 token; + __u64 object; __u32 handle; /* these class numbers are made up by us, and not nvidia-assigned */ #define NVIF_IOCTL_NEW_V0_PERFMON 0x0000ffff diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index 66d94c74b351f..b46c2f4aa0db2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -5,7 +5,6 @@ struct nvif_object { struct nvif_client *client; - struct nvif_object *parent; u32 handle; u32 oclass; void *priv; /*XXX: hack */ @@ -26,6 +25,7 @@ int nvif_object_mthd(struct nvif_object *, u32, void *, u32); int nvif_object_map(struct nvif_object *); void nvif_object_unmap(struct nvif_object *); +#define nvif_handle(a) (unsigned long)(void *)(a) #define nvif_object(a) (a)->object #define nvif_rd(a,f,b,c) ({ \ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index f79f9025d1c56..d70d28f90285d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -14,8 +14,14 @@ struct nvkm_client { int (*ntfy)(const void *, u32, const void *, u32); struct nvkm_client_notify *notify[16]; + + struct rb_root objroot; }; +bool nvkm_client_insert(struct nvkm_client *, struct nvkm_handle *); +void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *); +struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle); + static inline struct nvkm_client * nv_client(void *obj) { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h index 67f384d0916c3..64f9e62168ff2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h @@ -17,6 +17,9 @@ struct nvkm_handle { struct nvkm_handle *parent; struct nvkm_object *object; + + struct rb_node rb; + u64 handle; }; int nvkm_handle_create(struct nvkm_object *, u32 parent, u32 handle, @@ -25,8 +28,6 @@ void nvkm_handle_destroy(struct nvkm_handle *); int nvkm_handle_init(struct nvkm_handle *); int nvkm_handle_fini(struct nvkm_handle *, bool suspend); -struct nvkm_object *nvkm_handle_ref(struct nvkm_object *, u32 name); - struct nvkm_handle *nvkm_handle_get_class(struct nvkm_object *, u16); struct nvkm_handle *nvkm_handle_get_vinst(struct nvkm_object *, u64); struct nvkm_handle *nvkm_handle_get_cinst(struct nvkm_object *, u32); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 0ec929e00b36e..fb8d2b5a05671 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -4,7 +4,6 @@ struct nvkm_fifo_chan { struct nvkm_namedb namedb; - struct nvkm_dmaobj *pushdma; struct nvkm_gpuobj *pushgpu; void __iomem *user; u64 addr; @@ -30,7 +29,7 @@ nvkm_fifo_chan(void *obj) int nvkm_fifo_channel_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, - int bar, u32 addr, u32 size, u32 push, + int bar, u32 addr, u32 size, u64 push, u64 engmask, int len, void **); void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *); diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 302713821f086..9dd2f4f8e1276 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -209,13 +209,13 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { args.kepler.version = 0; args.kepler.engine = engine; - args.kepler.pushbuf = chan->push.ctxdma.handle; + args.kepler.pushbuf = nvif_handle(&chan->push.ctxdma); args.kepler.ilength = 0x02000; args.kepler.ioffset = 0x10000 + chan->push.vma.offset; size = sizeof(args.kepler); } else { args.nv50.version = 0; - args.nv50.pushbuf = chan->push.ctxdma.handle; + args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); args.nv50.ilength = 0x02000; args.nv50.ioffset = 0x10000 + chan->push.vma.offset; size = sizeof(args.nv50); @@ -258,7 +258,7 @@ nouveau_channel_dma(struct nouveau_drm *drm, struct nvif_device *device, /* create channel object */ args.version = 0; - args.pushbuf = chan->push.ctxdma.handle; + args.pushbuf = nvif_handle(&chan->push.ctxdma); args.offset = chan->push.vma.offset; do { diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 794a20ea71fea..c8e7974043538 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -230,7 +230,7 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, if (!dmac->ptr) return -ENOMEM; - ret = nvif_object_init(&device->object, args->pushbuf, + ret = nvif_object_init(&device->object, 0xd0000000, NV_DMA_FROM_MEMORY, &(struct nv_dma_v0) { .target = NV_DMA_V0_TARGET_PCI_US, .access = NV_DMA_V0_ACCESS_RD, @@ -240,6 +240,8 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, if (ret) return ret; + args->pushbuf = nvif_handle(&pushbuf); + ret = nv50_chan_create(device, disp, oclass, head, data, size, &dmac->base); nvif_object_fini(&pushbuf); diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index 4a830ebf9661b..64d3d0c37a83a 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -50,7 +50,6 @@ nvif_client_fini(struct nvif_client *client) if (client->driver) { client->driver->fini(client->object.priv); client->driver = NULL; - client->object.parent = NULL; client->object.client = NULL; nvif_object_fini(&client->object); } @@ -79,7 +78,6 @@ nvif_client_init(const char *driver, const char *name, u64 device, return ret; client->object.client = client; - client->object.parent = &client->object; client->object.handle = ~0; client->route = NVIF_IOCTL_V0_ROUTE_NVIF; client->super = true; diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index a727f72ca2343..b914e34a43c3b 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -36,14 +36,11 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) } *args = data; if (size >= sizeof(*args) && args->v0.version == 0) { + if (object != &client->object) + args->v0.object = nvif_handle(object); + else + args->v0.object = 0; args->v0.owner = NVIF_IOCTL_V0_OWNER_ANY; - args->v0.path_nr = 0; - while (args->v0.path_nr < ARRAY_SIZE(args->v0.path)) { - args->v0.path[args->v0.path_nr++] = object->handle; - if (object->parent == object) - break; - object = object->parent; - } } else return -ENOSYS; @@ -216,13 +213,12 @@ nvif_object_init(struct nvif_object *parent, u32 handle, u32 oclass, int ret = 0; object->client = NULL; - object->parent = parent; object->handle = handle; object->oclass = oclass; object->map.ptr = NULL; object->map.size = 0; - if (object->parent) { + if (parent) { if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) { nvif_object_fini(object); return -ENOMEM; @@ -232,7 +228,8 @@ nvif_object_init(struct nvif_object *parent, u32 handle, u32 oclass, args->ioctl.type = NVIF_IOCTL_V0_NEW; args->new.version = 0; args->new.route = parent->client->route; - args->new.token = (unsigned long)(void *)object; + args->new.token = nvif_handle(object); + args->new.object = nvif_handle(object); args->new.handle = handle; args->new.oclass = oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 7615cdd752949..bfe5357d73348 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -183,6 +183,55 @@ nvkm_client_oclass = { }, }; +void +nvkm_client_remove(struct nvkm_client *client, struct nvkm_handle *object) +{ + if (!RB_EMPTY_NODE(&object->rb)) + rb_erase(&object->rb, &client->objroot); +} + +bool +nvkm_client_insert(struct nvkm_client *client, struct nvkm_handle *object) +{ + struct rb_node **ptr = &client->objroot.rb_node; + struct rb_node *parent = NULL; + + while (*ptr) { + struct nvkm_handle *this = + container_of(*ptr, typeof(*this), rb); + parent = *ptr; + if (object->handle < this->handle) + ptr = &parent->rb_left; + else + if (object->handle > this->handle) + ptr = &parent->rb_right; + else + return false; + } + + rb_link_node(&object->rb, parent, ptr); + rb_insert_color(&object->rb, &client->objroot); + return true; +} + +struct nvkm_handle * +nvkm_client_search(struct nvkm_client *client, u64 handle) +{ + struct rb_node *node = client->objroot.rb_node; + while (node) { + struct nvkm_handle *object = + container_of(node, typeof(*object), rb); + if (handle < object->handle) + node = node->rb_left; + else + if (handle > object->handle) + node = node->rb_right; + else + return object; + } + return NULL; +} + int nvkm_client_fini(struct nvkm_client *client, bool suspend) { @@ -256,6 +305,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, client->device = device; snprintf(client->name, sizeof(client->name), "%s", name); client->debug = nvkm_dbgopt(dbg, "CLIENT"); + client->objroot = RB_ROOT; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index 6230eaece64d6..a12ab80017018 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -113,6 +113,7 @@ nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle, INIT_LIST_HEAD(&handle->tree); handle->name = _handle; handle->priv = ~0; + RB_CLEAR_NODE(&handle->rb); ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, object, handle); if (ret) { @@ -149,12 +150,15 @@ nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle, void nvkm_handle_destroy(struct nvkm_handle *handle) { + struct nvkm_client *client = nvkm_client(handle->object); struct nvkm_handle *item, *temp; hprintk(handle, TRACE, "destroy running\n"); list_for_each_entry_safe(item, temp, &handle->tree, head) { nvkm_handle_destroy(item); } + + nvkm_client_remove(client, handle); list_del(&handle->head); if (handle->priv != ~0) { @@ -167,24 +171,6 @@ nvkm_handle_destroy(struct nvkm_handle *handle) kfree(handle); } -struct nvkm_object * -nvkm_handle_ref(struct nvkm_object *parent, u32 name) -{ - struct nvkm_object *object = NULL; - struct nvkm_handle *handle; - - while (!nv_iclass(parent, NV_NAMEDB_CLASS)) - parent = parent->parent; - - handle = nvkm_namedb_get(nv_namedb(parent), name); - if (handle) { - nvkm_object_ref(handle->object, &object); - nvkm_namedb_put(handle); - } - - return object; -} - struct nvkm_handle * nvkm_handle_get_class(struct nvkm_object *engctx, u16 oclass) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 7434958846f7b..7654783e83504 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -103,9 +103,9 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) return ret; nvif_ioctl(handle->object, "new vers %d handle %08x class %08x " - "route %02x token %llx\n", + "route %02x token %llx object %016llx\n", args->v0.version, _handle, _oclass, - args->v0.route, args->v0.token); + args->v0.route, args->v0.token, args->v0.object); if (!nv_iclass(handle->object, NV_PARENT_CLASS)) { nvif_debug(handle->object, "cannot have children (ctor)\n"); @@ -166,6 +166,8 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) if (ret) nvkm_handle_destroy(handle); + handle->handle = args->v0.object; + nvkm_client_insert(client, handle); fail_handle: nvkm_object_dec(object, false); fail_init: @@ -438,40 +440,31 @@ nvkm_ioctl_v0[] = { }; static int -nvkm_ioctl_path(struct nvkm_handle *parent, u32 type, u32 nr, u32 *path, +nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type, void *data, u32 size, u8 owner, u8 *route, u64 *token) { - struct nvkm_handle *handle = parent; - struct nvkm_namedb *namedb; - struct nvkm_object *object; + struct nvkm_handle *object; int ret; - while ((object = parent->object), nr--) { - nvif_ioctl(object, "path 0x%08x\n", path[nr]); - if (!nv_iclass(object, NV_PARENT_CLASS)) { - nvif_debug(object, "cannot have children (path)\n"); - return -EINVAL; - } - - if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) || - !(handle = nvkm_namedb_get(namedb, path[nr]))) { - nvif_debug(object, "handle 0x%08x not found\n", path[nr]); - return -ENOENT; - } - nvkm_namedb_put(handle); - parent = handle; + if (handle) + object = nvkm_client_search(client, handle); + else + object = client->root; + if (unlikely(!object)) { + nvif_ioctl(&client->namedb.parent.object, "object not found\n"); + return -ENOENT; } - if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != handle->route) { - nvif_ioctl(object, "object route != owner\n"); + if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) { + nvif_ioctl(&client->namedb.parent.object, "route != owner\n"); return -EACCES; } - *route = handle->route; - *token = handle->token; + *route = object->route; + *token = object->token; if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) { if (nvkm_ioctl_v0[type].version == 0) - ret = nvkm_ioctl_v0[type].func(handle, data, size); + ret = nvkm_ioctl_v0[type].func(object, data, size); } return ret; @@ -491,11 +484,11 @@ nvkm_ioctl(struct nvkm_client *client, bool supervisor, nvif_ioctl(object, "size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { - nvif_ioctl(object, "vers %d type %02x path %d owner %02x\n", - args->v0.version, args->v0.type, args->v0.path_nr, + nvif_ioctl(object, + "vers %d type %02x object %016llx owner %02x\n", + args->v0.version, args->v0.type, args->v0.object, args->v0.owner); - ret = nvkm_ioctl_path(client->root, args->v0.type, - args->v0.path_nr, args->v0.path, + ret = nvkm_ioctl_path(client, args->v0.object, args->v0.type, data, size, args->v0.owner, &args->v0.route, &args->v0.token); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 9d7ac6a15bd71..2568e5d5790e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -206,9 +206,12 @@ nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) static int nv50_disp_dmac_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 pushbuf, int head, + struct nvkm_oclass *oclass, u64 pushbuf, int head, int length, void **pobject) { + struct nvkm_client *client = nvkm_client(parent); + struct nvkm_handle *handle; + struct nvkm_dmaobj *dmaobj; struct nv50_disp_dmac *dmac; int ret; @@ -218,22 +221,23 @@ nv50_disp_dmac_create_(struct nvkm_object *parent, if (ret) return ret; - dmac->pushdma = (void *)nvkm_handle_ref(parent, pushbuf); - if (!dmac->pushdma) + handle = nvkm_client_search(client, pushbuf); + if (!handle) return -ENOENT; + dmaobj = (void *)handle->object; - switch (nv_mclass(dmac->pushdma)) { + switch (nv_mclass(dmaobj)) { case 0x0002: case 0x003d: - if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff) + if (dmaobj->limit - dmaobj->start != 0xfff) return -EINVAL; - switch (dmac->pushdma->target) { + switch (dmaobj->target) { case NV_MEM_TARGET_VRAM: - dmac->push = 0x00000001 | dmac->pushdma->start >> 8; + dmac->push = 0x00000001 | dmaobj->start >> 8; break; case NV_MEM_TARGET_PCI_NOSNOOP: - dmac->push = 0x00000003 | dmac->pushdma->start >> 8; + dmac->push = 0x00000003 | dmaobj->start >> 8; break; default: return -EINVAL; @@ -250,7 +254,6 @@ void nv50_disp_dmac_dtor(struct nvkm_object *object) { struct nv50_disp_dmac *dmac = (void *)object; - nvkm_object_ref(NULL, (struct nvkm_object **)&dmac->pushdma); nv50_disp_chan_destroy(&dmac->base); } @@ -513,7 +516,7 @@ nv50_disp_core_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create disp core channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create disp core channel dma vers %d " - "pushbuf %08x\n", + "pushbuf %016llx\n", args->v0.version, args->v0.pushbuf); } else return ret; @@ -682,7 +685,7 @@ nv50_disp_base_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create disp base channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create disp base channel dma vers %d " - "pushbuf %08x head %d\n", + "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; @@ -772,7 +775,7 @@ nv50_disp_ovly_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create disp overlay channel dma vers %d " - "pushbuf %08x head %d\n", + "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 0d495d274eb35..21dbd39011132 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -113,7 +113,6 @@ extern const struct nvkm_event_func gf110_disp_chan_uevent; struct nv50_disp_dmac { struct nv50_disp_chan base; - struct nvkm_dmaobj *pushdma; u32 push; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index e298aef71918c..73b8ab4c222eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -54,9 +54,12 @@ int nvkm_fifo_channel_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, - int bar, u32 addr, u32 size, u32 pushbuf, + int bar, u32 addr, u32 size, u64 pushbuf, u64 engmask, int len, void **ptr) { + struct nvkm_client *client = nvkm_client(parent); + struct nvkm_handle *handle; + struct nvkm_dmaobj *dmaobj; struct nvkm_fifo *fifo = (void *)engine; struct nvkm_fifo_chan *chan; struct nvkm_dmaeng *dmaeng; @@ -73,12 +76,13 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return ret; /* validate dma object representing push buffer */ - chan->pushdma = (void *)nvkm_handle_ref(parent, pushbuf); - if (!chan->pushdma) + handle = nvkm_client_search(client, pushbuf); + if (!handle) return -ENOENT; + dmaobj = (void *)handle->object; - dmaeng = (void *)chan->pushdma->base.engine; - switch (chan->pushdma->base.oclass->handle) { + dmaeng = (void *)dmaobj->base.engine; + switch (dmaobj->base.oclass->handle) { case NV_DMA_FROM_MEMORY: case NV_DMA_IN_MEMORY: break; @@ -86,7 +90,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return -EINVAL; } - ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu); + ret = dmaeng->bind(dmaobj, parent, &chan->pushgpu); if (ret) return ret; @@ -126,7 +130,6 @@ nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) spin_unlock_irqrestore(&fifo->lock, flags); nvkm_gpuobj_ref(NULL, &chan->pushgpu); - nvkm_object_ref(NULL, (struct nvkm_object **)&chan->pushdma); nvkm_namedb_destroy(&chan->namedb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index c4f48112aa059..575329d3f2bb4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -182,7 +182,7 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else @@ -258,7 +258,7 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " "ioffset %016llx ilength %08x\n", args->v0.version, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index d940d41d1182c..cfaa8aeb22235 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -210,7 +210,7 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " "ioffset %016llx ilength %08x\n", args->v0.version, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 9a1ecef248139..9c423514fee7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -251,7 +251,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " "ioffset %016llx ilength %08x engine %08x\n", args->v0.version, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength, args->v0.engine); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index d5346636b7e35..6458fa0dcb950 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -120,7 +120,7 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 5a7b11f926842..c4b5a3002e3ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -64,7 +64,7 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 537bb7229e3d8..ece2715e77ff5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -69,7 +69,7 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 27f07d1db85f3..a42218a961d47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -192,7 +192,7 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 24154778c01e2..1a7ca8e5aecbf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -212,7 +212,7 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else @@ -276,7 +276,7 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x " + nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " "ioffset %016llx ilength %08x\n", args->v0.version, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); -- GitLab From 99d4d36ad673c2b4fea364f6d456718f0f701ce4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5473/7006] drm/nouveau/nvif: extend nop ioctl to return nvif version identifier Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/client.h | 1 + drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 5 ++++- drivers/gpu/drm/nouveau/nvif/client.c | 9 +++++++++ drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 7 ++++--- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/client.h b/drivers/gpu/drm/nouveau/include/nvif/client.h index cd6fbfa887621..4d5db8039576b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/client.h +++ b/drivers/gpu/drm/nouveau/include/nvif/client.h @@ -6,6 +6,7 @@ struct nvif_client { struct nvif_object object; const struct nvif_driver *driver; + u64 version; u8 route; bool super; }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 9d99768f1a357..772db0de044ae 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -1,6 +1,8 @@ #ifndef __NVIF_IOCTL_H__ #define __NVIF_IOCTL_H__ +#define NVIF_VERSION_LATEST 0x0000000000000000ULL + struct nvif_ioctl_v0 { __u8 version; #define NVIF_IOCTL_V0_NOP 0x00 @@ -29,7 +31,8 @@ struct nvif_ioctl_v0 { __u8 data[]; /* ioctl data (below) */ }; -struct nvif_ioctl_nop { +struct nvif_ioctl_nop_v0 { + __u64 version; }; struct nvif_ioctl_sclass_v0 { diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c index 64d3d0c37a83a..1ee9294eca2ea 100644 --- a/drivers/gpu/drm/nouveau/nvif/client.c +++ b/drivers/gpu/drm/nouveau/nvif/client.c @@ -71,6 +71,10 @@ int nvif_client_init(const char *driver, const char *name, u64 device, const char *cfg, const char *dbg, struct nvif_client *client) { + struct { + struct nvif_ioctl_v0 ioctl; + struct nvif_ioctl_nop_v0 nop; + } args = {}; int ret, i; ret = nvif_object_init(NULL, 0, 0, NULL, 0, &client->object); @@ -91,6 +95,11 @@ nvif_client_init(const char *driver, const char *name, u64 device, } } + if (ret == 0) { + ret = nvif_client_ioctl(client, &args, sizeof(args)); + client->version = args.nop.version; + } + if (ret) nvif_client_fini(client); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 7654783e83504..629ee56dd8ab9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -35,13 +35,14 @@ nvkm_ioctl_nop(struct nvkm_handle *handle, void *data, u32 size) { struct nvkm_object *object = handle->object; union { - struct nvif_ioctl_nop none; + struct nvif_ioctl_nop_v0 v0; } *args = data; int ret; nvif_ioctl(object, "nop size %d\n", size); - if (nvif_unvers(args->none)) { - nvif_ioctl(object, "nop\n"); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "nop vers %lld\n", args->v0.version); + args->v0.version = NVIF_VERSION_LATEST; } return ret; -- GitLab From 5c15bf709eb6fb52c5bcb95d545250dde22f9625 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5474/7006] drm/nouveau/nvif: return success from sclass even for objects without children Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 629ee56dd8ab9..ee6ff01c2b1ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -57,18 +57,18 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) } *args = data; int ret; - if (!nv_iclass(object, NV_PARENT_CLASS)) { - nvif_debug(object, "cannot have children (sclass)\n"); - return -ENODEV; - } - nvif_ioctl(object, "sclass size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "sclass vers %d count %d\n", args->v0.version, args->v0.count); if (size == args->v0.count * sizeof(args->v0.oclass[0])) { - ret = nvkm_parent_lclass(object, args->v0.oclass, + if (nv_iclass(object, NV_PARENT_CLASS)) { + ret = nvkm_parent_lclass(object, + args->v0.oclass, args->v0.count); + } else { + ret = 0; + } if (ret >= 0) { args->v0.count = ret; ret = 0; -- GitLab From 315a8b2edf51711857795ba6e02b843d7792b59c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5475/7006] drm/nouveau/nvif: use negative oclass identifier for internal classes Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 10 +++++----- drivers/gpu/drm/nouveau/include/nvif/object.h | 6 +++--- .../gpu/drm/nouveau/include/nvkm/core/client.h | 11 +---------- .../gpu/drm/nouveau/include/nvkm/core/object.h | 2 +- .../gpu/drm/nouveau/include/nvkm/core/parent.h | 4 ++-- drivers/gpu/drm/nouveau/nouveau_bo.c | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.c | 18 +++++++++--------- drivers/gpu/drm/nouveau/nvif/device.c | 2 +- drivers/gpu/drm/nouveau/nvif/object.c | 5 ++--- drivers/gpu/drm/nouveau/nvkm/core/parent.c | 4 ++-- 12 files changed, 29 insertions(+), 39 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 1973e65f21a68..68b431b24ae6e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -9,7 +9,7 @@ struct nvif_device { struct nv_device_info_v0 info; }; -int nvif_device_init(struct nvif_object *, u32 handle, u32 oclass, void *, u32, +int nvif_device_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32, struct nvif_device *); void nvif_device_fini(struct nvif_device *); u64 nvif_device_time(struct nvif_device *); diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 772db0de044ae..193437c4a1f06 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -40,7 +40,7 @@ struct nvif_ioctl_sclass_v0 { __u8 version; __u8 count; __u8 pad02[6]; - __u32 oclass[]; + __s32 oclass[]; }; struct nvif_ioctl_new_v0 { @@ -52,10 +52,10 @@ struct nvif_ioctl_new_v0 { __u64 object; __u32 handle; /* these class numbers are made up by us, and not nvidia-assigned */ -#define NVIF_IOCTL_NEW_V0_PERFMON 0x0000ffff -#define NVIF_IOCTL_NEW_V0_PERFDOM 0x0000fffe -#define NVIF_IOCTL_NEW_V0_CONTROL 0x0000fffd - __u32 oclass; +#define NVIF_IOCTL_NEW_V0_CONTROL -1 +#define NVIF_IOCTL_NEW_V0_PERFMON -2 +#define NVIF_IOCTL_NEW_V0_PERFDOM -3 + __s32 oclass; __u8 data[]; /* class data (class.h) */ }; diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index b46c2f4aa0db2..66d3425e47644 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -6,7 +6,7 @@ struct nvif_object { struct nvif_client *client; u32 handle; - u32 oclass; + s32 oclass; void *priv; /*XXX: hack */ struct { void __iomem *ptr; @@ -14,11 +14,11 @@ struct nvif_object { } map; }; -int nvif_object_init(struct nvif_object *, u32 handle, u32 oclass, void *, u32, +int nvif_object_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32, struct nvif_object *); void nvif_object_fini(struct nvif_object *); int nvif_object_ioctl(struct nvif_object *, void *, u32, void **); -int nvif_object_sclass(struct nvif_object *, u32 *, int); +int nvif_object_sclass(struct nvif_object *, s32 *, int); u32 nvif_object_rd(struct nvif_object *, int, u64); void nvif_object_wr(struct nvif_object *, int, u64, u32); int nvif_object_mthd(struct nvif_object *, u32, void *, u32); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index d70d28f90285d..977c8a85e1199 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -22,20 +22,11 @@ bool nvkm_client_insert(struct nvkm_client *, struct nvkm_handle *); void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *); struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle); -static inline struct nvkm_client * -nv_client(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_CLIENT_CLASS)); -#endif - return obj; -} - static inline struct nvkm_client * nvkm_client(void *obj) { struct nvkm_object *client = nv_object(obj); - while (client && !(nv_iclass(client, NV_CLIENT_CLASS))) + while (client && client->parent) client = client->parent; return (void *)client; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index ef0ff9e1a9480..005cd4a868491 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -62,7 +62,7 @@ extern struct nvkm_ofuncs nvkm_object_ofuncs; /* Don't allocate dynamically, because lockdep needs lock_class_keys to be in * ".data". */ struct nvkm_oclass { - u32 handle; + s32 handle; struct nvkm_ofuncs * const ofuncs; struct nvkm_omthds * const omthds; struct lock_class_key lock_class_key; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h index 2e5266fa75841..bc4dc1f2403fa 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h @@ -44,8 +44,8 @@ void _nvkm_parent_dtor(struct nvkm_object *); #define _nvkm_parent_init nvkm_object_init #define _nvkm_parent_fini nvkm_object_fini -int nvkm_parent_sclass(struct nvkm_object *, u16 handle, +int nvkm_parent_sclass(struct nvkm_object *, s32 handle, struct nvkm_object **pengine, struct nvkm_oclass **poclass); -int nvkm_parent_lclass(struct nvkm_object *, u32 *, int); +int nvkm_parent_lclass(struct nvkm_object *, s32 *, int); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 5529fc479d8a3..496c00d585cd2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1104,7 +1104,7 @@ nouveau_bo_move_init(struct nouveau_drm *drm) static const struct { const char *name; int engine; - u32 oclass; + s32 oclass; int (*exec)(struct nouveau_channel *, struct ttm_buffer_object *, struct ttm_mem_reg *, struct ttm_mem_reg *); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 11cf52a7ff750..65ceb6fa42094 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -153,7 +153,7 @@ nouveau_accel_init(struct nouveau_drm *drm) { struct nvif_device *device = &drm->device; u32 arg0, arg1; - u32 sclass[16]; + s32 sclass[16]; int ret, i; if (nouveau_noaccel) diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index c8e7974043538..65e70f085325b 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -65,11 +65,11 @@ struct nv50_chan { static int nv50_chan_create(struct nvif_device *device, struct nvif_object *disp, - const u32 *oclass, u8 head, void *data, u32 size, + const s32 *oclass, u8 head, void *data, u32 size, struct nv50_chan *chan) { const u32 handle = (oclass[0] << 16) | head; - u32 sclass[8]; + s32 sclass[8]; int ret, i; chan->device = device; @@ -117,7 +117,7 @@ nv50_pioc_destroy(struct nv50_pioc *pioc) static int nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp, - const u32 *oclass, u8 head, void *data, u32 size, + const s32 *oclass, u8 head, void *data, u32 size, struct nv50_pioc *pioc) { return nv50_chan_create(device, disp, oclass, head, data, size, @@ -139,7 +139,7 @@ nv50_curs_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_disp_cursor_v0 args = { .head = head, }; - static const u32 oclass[] = { + static const s32 oclass[] = { GK104_DISP_CURSOR, GF110_DISP_CURSOR, GT214_DISP_CURSOR, @@ -167,7 +167,7 @@ nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_disp_cursor_v0 args = { .head = head, }; - static const u32 oclass[] = { + static const s32 oclass[] = { GK104_DISP_OVERLAY, GF110_DISP_OVERLAY, GT214_DISP_OVERLAY, @@ -216,7 +216,7 @@ nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp) static int nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, - const u32 *oclass, u8 head, void *data, u32 size, u64 syncbuf, + const s32 *oclass, u8 head, void *data, u32 size, u64 syncbuf, struct nv50_dmac *dmac) { struct nv50_disp_core_channel_dma_v0 *args = data; @@ -288,7 +288,7 @@ nv50_core_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_disp_core_channel_dma_v0 args = { .pushbuf = 0xb0007d00, }; - static const u32 oclass[] = { + static const s32 oclass[] = { GM204_DISP_CORE_CHANNEL_DMA, GM107_DISP_CORE_CHANNEL_DMA, GK110_DISP_CORE_CHANNEL_DMA, @@ -324,7 +324,7 @@ nv50_base_create(struct nvif_device *device, struct nvif_object *disp, .pushbuf = 0xb0007c00 | head, .head = head, }; - static const u32 oclass[] = { + static const s32 oclass[] = { GK110_DISP_BASE_CHANNEL_DMA, GK104_DISP_BASE_CHANNEL_DMA, GF110_DISP_BASE_CHANNEL_DMA, @@ -355,7 +355,7 @@ nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp, .pushbuf = 0xb0007e00 | head, .head = head, }; - static const u32 oclass[] = { + static const s32 oclass[] = { GK104_DISP_OVERLAY_CONTROL_DMA, GF110_DISP_OVERLAY_CONTROL_DMA, GT214_DISP_OVERLAY_CHANNEL_DMA, diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c index f15d51a69df2b..561fb9d7b1550 100644 --- a/drivers/gpu/drm/nouveau/nvif/device.c +++ b/drivers/gpu/drm/nouveau/nvif/device.c @@ -37,7 +37,7 @@ nvif_device_fini(struct nvif_device *device) } int -nvif_device_init(struct nvif_object *parent, u32 handle, u32 oclass, +nvif_device_init(struct nvif_object *parent, u32 handle, s32 oclass, void *data, u32 size, struct nvif_device *device) { int ret = nvif_object_init(parent, handle, oclass, data, size, diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index b914e34a43c3b..0c09e6433fbbb 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -49,7 +49,7 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) } int -nvif_object_sclass(struct nvif_object *object, u32 *oclass, int count) +nvif_object_sclass(struct nvif_object *object, s32 *oclass, int count) { struct { struct nvif_ioctl_v0 ioctl; @@ -65,7 +65,6 @@ nvif_object_sclass(struct nvif_object *object, u32 *oclass, int count) args->sclass.version = 0; args->sclass.count = count; - memcpy(args->sclass.oclass, oclass, size); ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); ret = ret ? ret : args->sclass.count; memcpy(oclass, args->sclass.oclass, size); @@ -203,7 +202,7 @@ nvif_object_fini(struct nvif_object *object) } int -nvif_object_init(struct nvif_object *parent, u32 handle, u32 oclass, +nvif_object_init(struct nvif_object *parent, u32 handle, s32 oclass, void *data, u32 size, struct nvif_object *object) { struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c index 5c75c64f22709..43abd208b4865 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/parent.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/parent.c @@ -26,7 +26,7 @@ #include int -nvkm_parent_sclass(struct nvkm_object *parent, u16 handle, +nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, struct nvkm_object **pengine, struct nvkm_oclass **poclass) { @@ -66,7 +66,7 @@ nvkm_parent_sclass(struct nvkm_object *parent, u16 handle, } int -nvkm_parent_lclass(struct nvkm_object *parent, u32 *lclass, int size) +nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) { struct nvkm_oclass *sclass, *oclass; struct nvkm_engine *engine; -- GitLab From f58ddf9581655d3fea51465f06f292d365af9c87 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5476/7006] drm/nouveau/nvif: assign internal class identifiers to sw classes Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 4 + .../drm/nouveau/include/nvkm/core/namedb.h | 2 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 76 +++++++++++++++---- drivers/gpu/drm/nouveau/nouveau_abi16.h | 2 +- drivers/gpu/drm/nouveau/nouveau_chan.c | 4 +- drivers/gpu/drm/nouveau/nvkm/core/namedb.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 3 +- 12 files changed, 87 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 193437c4a1f06..7ac185c6e71f2 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -55,6 +55,10 @@ struct nvif_ioctl_new_v0 { #define NVIF_IOCTL_NEW_V0_CONTROL -1 #define NVIF_IOCTL_NEW_V0_PERFMON -2 #define NVIF_IOCTL_NEW_V0_PERFDOM -3 +#define NVIF_IOCTL_NEW_V0_SW_NV04 -4 +#define NVIF_IOCTL_NEW_V0_SW_NV10 -5 +#define NVIF_IOCTL_NEW_V0_SW_NV50 -6 +#define NVIF_IOCTL_NEW_V0_SW_GF100 -7 __s32 oclass; __u8 data[]; /* class data (class.h) */ }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h index f880d66bb6e54..16337f69b113d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h @@ -45,7 +45,7 @@ int nvkm_namedb_insert(struct nvkm_namedb *, u32 name, struct nvkm_object *, void nvkm_namedb_remove(struct nvkm_handle *); struct nvkm_handle *nvkm_namedb_get(struct nvkm_namedb *, u32); -struct nvkm_handle *nvkm_namedb_get_class(struct nvkm_namedb *, u16); +struct nvkm_handle *nvkm_namedb_get_class(struct nvkm_namedb *, s32); struct nvkm_handle *nvkm_namedb_get_vinst(struct nvkm_namedb *, u64); struct nvkm_handle *nvkm_namedb_get_cinst(struct nvkm_namedb *, u32); void nvkm_namedb_put(struct nvkm_handle *); diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 76c363223e3f7..1b3067ee04429 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -74,23 +74,23 @@ nouveau_abi16_put(struct nouveau_abi16 *abi16, int ret) return ret; } -u16 +s32 nouveau_abi16_swclass(struct nouveau_drm *drm) { switch (drm->device.info.family) { case NV_DEVICE_INFO_V0_TNT: - return 0x006e; + return NVIF_IOCTL_NEW_V0_SW_NV04; case NV_DEVICE_INFO_V0_CELSIUS: case NV_DEVICE_INFO_V0_KELVIN: case NV_DEVICE_INFO_V0_RANKINE: case NV_DEVICE_INFO_V0_CURIE: - return 0x016e; + return NVIF_IOCTL_NEW_V0_SW_NV10; case NV_DEVICE_INFO_V0_TESLA: - return 0x506e; + return NVIF_IOCTL_NEW_V0_SW_NV50; case NV_DEVICE_INFO_V0_FERMI: case NV_DEVICE_INFO_V0_KEPLER: case NV_DEVICE_INFO_V0_MAXWELL: - return 0x906e; + return NVIF_IOCTL_NEW_V0_SW_GF100; } return 0x0000; @@ -368,9 +368,10 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) struct nouveau_abi16 *abi16 = nouveau_abi16_get(file_priv, dev); struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; - struct nouveau_drm *drm = nouveau_drm(dev); struct nvif_client *client; - int ret; + u32 sclass[32]; + s32 oclass = 0; + int ret, i; if (unlikely(!abi16)) return -ENOMEM; @@ -379,17 +380,62 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) return nouveau_abi16_put(abi16, -EINVAL); client = abi16->device.object.client; - /* compatibility with userspace that assumes 506e for all chipsets */ - if (init->class == 0x506e) { - init->class = nouveau_abi16_swclass(drm); - if (init->class == 0x906e) - return nouveau_abi16_put(abi16, 0); - } - chan = nouveau_abi16_chan(abi16, init->channel); if (!chan) return nouveau_abi16_put(abi16, -ENOENT); + ret = nvif_object_sclass(&chan->chan->user, sclass, ARRAY_SIZE(sclass)); + if (ret < 0) + return nouveau_abi16_put(abi16, ret); + + if ((init->class & 0x00ff) == 0x006e) { + /* nvsw: compatibility with older 0x*6e class identifier */ + for (i = 0; !oclass && i < ret; i++) { + switch (sclass[i]) { + case NVIF_IOCTL_NEW_V0_SW_NV04: + case NVIF_IOCTL_NEW_V0_SW_NV10: + case NVIF_IOCTL_NEW_V0_SW_NV50: + case NVIF_IOCTL_NEW_V0_SW_GF100: + oclass = sclass[i]; + break; + default: + break; + } + } + } else + if ((init->class & 0x00ff) == 0x00b1) { + /* msvld: compatibility with incorrect version exposure */ + for (i = 0; i < ret; i++) { + if ((sclass[i] & 0x00ff) == 0x00b1) { + oclass = sclass[i]; + break; + } + } + } else + if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */ + /* mspdec: compatibility with incorrect version exposure */ + for (i = 0; i < ret; i++) { + if ((sclass[i] & 0x00ff) == 0x00b2) { + oclass = sclass[i]; + break; + } + } + } else + if ((init->class & 0x00ff) == 0x00b3) { /* msppp */ + /* msppp: compatibility with incorrect version exposure */ + for (i = 0; i < ret; i++) { + if ((sclass[i] & 0x00ff) == 0x00b3) { + oclass = sclass[i]; + break; + } + } + } else { + oclass = init->class; + } + + if (!oclass) + return nouveau_abi16_put(abi16, -EINVAL); + ntfy = kzalloc(sizeof(*ntfy), GFP_KERNEL); if (!ntfy) return nouveau_abi16_put(abi16, -ENOMEM); @@ -397,7 +443,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) list_add(&ntfy->head, &chan->notifiers); client->route = NVDRM_OBJECT_ABI16; - ret = nvif_object_init(&chan->chan->user, init->handle, init->class, + ret = nvif_object_init(&chan->chan->user, init->handle, oclass, NULL, 0, &ntfy->object); client->route = NVDRM_OBJECT_NVIF; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h index b8acfd787d54d..6584557afa40a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.h +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h @@ -37,7 +37,7 @@ struct nouveau_drm; struct nouveau_abi16 *nouveau_abi16_get(struct drm_file *, struct drm_device *); int nouveau_abi16_put(struct nouveau_abi16 *, int); void nouveau_abi16_fini(struct nouveau_abi16 *); -u16 nouveau_abi16_swclass(struct nouveau_drm *); +s32 nouveau_abi16_swclass(struct nouveau_drm *); #define NOUVEAU_GEM_DOMAIN_VRAM (1 << 1) #define NOUVEAU_GEM_DOMAIN_GART (1 << 2) diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 9dd2f4f8e1276..65a144f8d3a7e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -24,6 +24,7 @@ #include #include +#include /*XXX*/ #include @@ -363,7 +364,8 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) /* allocate software object class (used for fences on <= nv05) */ if (device->info.family < NV_DEVICE_INFO_V0_CELSIUS) { - ret = nvif_object_init(&chan->user, 0x006e, 0x006e, + ret = nvif_object_init(&chan->user, 0x006e, + NVIF_IOCTL_NEW_V0_SW_NV04, NULL, 0, &chan->nvsw); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c index 6400767c5dba0..ca625c527c57a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c @@ -39,7 +39,7 @@ nvkm_namedb_lookup(struct nvkm_namedb *namedb, u32 name) } static struct nvkm_handle * -nvkm_namedb_lookup_class(struct nvkm_namedb *namedb, u16 oclass) +nvkm_namedb_lookup_class(struct nvkm_namedb *namedb, s32 oclass) { struct nvkm_handle *handle; @@ -122,7 +122,7 @@ nvkm_namedb_get(struct nvkm_namedb *namedb, u32 name) } struct nvkm_handle * -nvkm_namedb_get_class(struct nvkm_namedb *namedb, u16 oclass) +nvkm_namedb_get_class(struct nvkm_namedb *namedb, s32 oclass) { struct nvkm_handle *handle; read_lock(&namedb->lock); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index cfaa8aeb22235..cdb25b5cf2752 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -33,6 +33,7 @@ #include #include +#include #include struct gf100_fifo { @@ -494,7 +495,7 @@ gf100_fifo_swmthd(struct gf100_fifo *fifo, u32 chid, u32 mthd, u32 data) if (unlikely(!chan)) goto out; - bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e); + bind = nvkm_namedb_get_class(nv_namedb(chan), NVIF_IOCTL_NEW_V0_SW_GF100); if (likely(bind)) { if (!mthd || !nv_call(bind->object, mthd, data)) ret = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 9c423514fee7d..49d7ea0acbd10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -33,6 +33,7 @@ #include #include +#include #include #define _(a,b) { (a), ((1ULL << (a)) | (b)) } @@ -533,7 +534,7 @@ gk104_fifo_swmthd(struct gk104_fifo *fifo, u32 chid, u32 mthd, u32 data) if (unlikely(!chan)) goto out; - bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e); + bind = nvkm_namedb_get_class(nv_namedb(chan), NVIF_IOCTL_NEW_V0_SW_GF100); if (likely(bind)) { if (!mthd || !nv_call(bind->object, mthd, data)) ret = 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index eade9e30e1429..061ea72f5d0f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -25,6 +25,8 @@ #include +#include + /******************************************************************************* * software object classes ******************************************************************************/ @@ -87,7 +89,7 @@ gf100_sw_omthds[] = { static struct nvkm_oclass gf100_sw_sclass[] = { - { 0x906e, &nvkm_object_ofuncs, gf100_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_GF100, &nvkm_object_ofuncs, gf100_sw_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index 3bdab840ebf84..74c8c9dc2350b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -24,6 +24,8 @@ #include #include +#include + /******************************************************************************* * software object classes ******************************************************************************/ @@ -55,7 +57,7 @@ nv04_sw_omthds[] = { static struct nvkm_oclass nv04_sw_sclass[] = { - { 0x006e, &nvkm_object_ofuncs, nv04_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV04, &nvkm_object_ofuncs, nv04_sw_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index 1288142437b76..26ccd690bea85 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -23,6 +23,8 @@ */ #include +#include + /******************************************************************************* * software object classes ******************************************************************************/ @@ -44,7 +46,7 @@ nv10_sw_omthds[] = { static struct nvkm_oclass nv10_sw_sclass[] = { - { 0x016e, &nvkm_object_ofuncs, nv10_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV10, &nvkm_object_ofuncs, nv10_sw_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index ab3175af88fed..ca4b8a02b9712 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -29,6 +29,7 @@ #include #include +#include /******************************************************************************* * software object classes @@ -108,7 +109,7 @@ nv50_sw_omthds[] = { static struct nvkm_oclass nv50_sw_sclass[] = { - { 0x506e, &nvkm_object_ofuncs, nv50_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV50, &nvkm_object_ofuncs, nv50_sw_omthds }, {} }; -- GitLab From 41a634064db489713945e228e216336080ba57f8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5477/7006] drm/nouveau/nvif: return min/max versions for supported object classes Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/ioctl.h | 6 ++- drivers/gpu/drm/nouveau/include/nvif/object.h | 9 +++- .../drm/nouveau/include/nvkm/core/parent.h | 2 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 21 ++++---- drivers/gpu/drm/nouveau/nouveau_drm.c | 11 ++-- drivers/gpu/drm/nouveau/nv50_display.c | 13 ++--- drivers/gpu/drm/nouveau/nvif/object.c | 53 ++++++++++++++----- drivers/gpu/drm/nouveau/nvkm/core/parent.c | 19 +++++-- 8 files changed, 92 insertions(+), 42 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h index 7ac185c6e71f2..b0ac0215ebf98 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/ioctl.h +++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h @@ -40,7 +40,11 @@ struct nvif_ioctl_sclass_v0 { __u8 version; __u8 count; __u8 pad02[6]; - __s32 oclass[]; + struct nvif_ioctl_sclass_oclass_v0 { + __s32 oclass; + __s16 minver; + __s16 maxver; + } oclass[]; }; struct nvif_ioctl_new_v0 { diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h index 66d3425e47644..8d815967767fc 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/object.h +++ b/drivers/gpu/drm/nouveau/include/nvif/object.h @@ -3,6 +3,12 @@ #include +struct nvif_sclass { + s32 oclass; + int minver; + int maxver; +}; + struct nvif_object { struct nvif_client *client; u32 handle; @@ -18,7 +24,8 @@ int nvif_object_init(struct nvif_object *, u32 handle, s32 oclass, void *, u32, struct nvif_object *); void nvif_object_fini(struct nvif_object *); int nvif_object_ioctl(struct nvif_object *, void *, u32, void **); -int nvif_object_sclass(struct nvif_object *, s32 *, int); +int nvif_object_sclass_get(struct nvif_object *, struct nvif_sclass **); +void nvif_object_sclass_put(struct nvif_sclass **); u32 nvif_object_rd(struct nvif_object *, int, u64); void nvif_object_wr(struct nvif_object *, int, u64, u32); int nvif_object_mthd(struct nvif_object *, u32, void *, u32); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h index bc4dc1f2403fa..45d2066ff97a0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h @@ -47,5 +47,5 @@ void _nvkm_parent_dtor(struct nvkm_object *); int nvkm_parent_sclass(struct nvkm_object *, s32 handle, struct nvkm_object **pengine, struct nvkm_oclass **poclass); -int nvkm_parent_lclass(struct nvkm_object *, s32 *, int); +int nvkm_parent_lclass(struct nvkm_object *, void *, int); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 1b3067ee04429..98c74985e27de 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -369,7 +369,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) struct nouveau_abi16_chan *chan; struct nouveau_abi16_ntfy *ntfy; struct nvif_client *client; - u32 sclass[32]; + struct nvif_sclass *sclass; s32 oclass = 0; int ret, i; @@ -384,19 +384,19 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if (!chan) return nouveau_abi16_put(abi16, -ENOENT); - ret = nvif_object_sclass(&chan->chan->user, sclass, ARRAY_SIZE(sclass)); + ret = nvif_object_sclass_get(&chan->chan->user, &sclass); if (ret < 0) return nouveau_abi16_put(abi16, ret); if ((init->class & 0x00ff) == 0x006e) { /* nvsw: compatibility with older 0x*6e class identifier */ for (i = 0; !oclass && i < ret; i++) { - switch (sclass[i]) { + switch (sclass[i].oclass) { case NVIF_IOCTL_NEW_V0_SW_NV04: case NVIF_IOCTL_NEW_V0_SW_NV10: case NVIF_IOCTL_NEW_V0_SW_NV50: case NVIF_IOCTL_NEW_V0_SW_GF100: - oclass = sclass[i]; + oclass = sclass[i].oclass; break; default: break; @@ -406,8 +406,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if ((init->class & 0x00ff) == 0x00b1) { /* msvld: compatibility with incorrect version exposure */ for (i = 0; i < ret; i++) { - if ((sclass[i] & 0x00ff) == 0x00b1) { - oclass = sclass[i]; + if ((sclass[i].oclass & 0x00ff) == 0x00b1) { + oclass = sclass[i].oclass; break; } } @@ -415,8 +415,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if ((init->class & 0x00ff) == 0x00b2) { /* mspdec */ /* mspdec: compatibility with incorrect version exposure */ for (i = 0; i < ret; i++) { - if ((sclass[i] & 0x00ff) == 0x00b2) { - oclass = sclass[i]; + if ((sclass[i].oclass & 0x00ff) == 0x00b2) { + oclass = sclass[i].oclass; break; } } @@ -424,8 +424,8 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) if ((init->class & 0x00ff) == 0x00b3) { /* msppp */ /* msppp: compatibility with incorrect version exposure */ for (i = 0; i < ret; i++) { - if ((sclass[i] & 0x00ff) == 0x00b3) { - oclass = sclass[i]; + if ((sclass[i].oclass & 0x00ff) == 0x00b3) { + oclass = sclass[i].oclass; break; } } @@ -433,6 +433,7 @@ nouveau_abi16_ioctl_grobj_alloc(ABI16_IOCTL_ARGS) oclass = init->class; } + nvif_object_sclass_put(&sclass); if (!oclass) return nouveau_abi16_put(abi16, -EINVAL); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 65ceb6fa42094..37dbd5e1c08f0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -152,9 +152,9 @@ static void nouveau_accel_init(struct nouveau_drm *drm) { struct nvif_device *device = &drm->device; + struct nvif_sclass *sclass; u32 arg0, arg1; - s32 sclass[16]; - int ret, i; + int ret, i, n; if (nouveau_noaccel) return; @@ -163,12 +163,12 @@ nouveau_accel_init(struct nouveau_drm *drm) /*XXX: this is crap, but the fence/channel stuff is a little * backwards in some places. this will be fixed. */ - ret = nvif_object_sclass(&device->object, sclass, ARRAY_SIZE(sclass)); + ret = n = nvif_object_sclass_get(&device->object, &sclass); if (ret < 0) return; - for (ret = -ENOSYS, i = 0; ret && i < ARRAY_SIZE(sclass); i++) { - switch (sclass[i]) { + for (ret = -ENOSYS, i = 0; i < n; i++) { + switch (sclass[i].oclass) { case NV03_CHANNEL_DMA: ret = nv04_fence_create(drm); break; @@ -195,6 +195,7 @@ nouveau_accel_init(struct nouveau_drm *drm) } } + nvif_object_sclass_put(&sclass); if (ret) { NV_ERROR(drm, "failed to initialise sync subsystem, %d\n", ret); nouveau_accel_fini(drm); diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 65e70f085325b..817ce09acb192 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -69,29 +69,30 @@ nv50_chan_create(struct nvif_device *device, struct nvif_object *disp, struct nv50_chan *chan) { const u32 handle = (oclass[0] << 16) | head; - s32 sclass[8]; - int ret, i; + struct nvif_sclass *sclass; + int ret, i, n; chan->device = device; - ret = nvif_object_sclass(disp, sclass, ARRAY_SIZE(sclass)); - WARN_ON(ret > ARRAY_SIZE(sclass)); + ret = n = nvif_object_sclass_get(disp, &sclass); if (ret < 0) return ret; while (oclass[0]) { - for (i = 0; i < ARRAY_SIZE(sclass); i++) { - if (sclass[i] == oclass[0]) { + for (i = 0; i < n; i++) { + if (sclass[i].oclass == oclass[0]) { ret = nvif_object_init(disp, handle, oclass[0], data, size, &chan->user); if (ret == 0) nvif_object_map(&chan->user); + nvif_object_sclass_put(&sclass); return ret; } } oclass++; } + nvif_object_sclass_put(&sclass); return -ENOSYS; } diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c index 0c09e6433fbbb..c3fb6a20f567d 100644 --- a/drivers/gpu/drm/nouveau/nvif/object.c +++ b/drivers/gpu/drm/nouveau/nvif/object.c @@ -48,26 +48,53 @@ nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack) data, size, hack); } +void +nvif_object_sclass_put(struct nvif_sclass **psclass) +{ + kfree(*psclass); + *psclass = NULL; +} + int -nvif_object_sclass(struct nvif_object *object, s32 *oclass, int count) +nvif_object_sclass_get(struct nvif_object *object, struct nvif_sclass **psclass) { struct { struct nvif_ioctl_v0 ioctl; struct nvif_ioctl_sclass_v0 sclass; - } *args; - u32 size = count * sizeof(args->sclass.oclass[0]); - int ret; + } *args = NULL; + int ret, cnt = 0, i; + u32 size; - if (!(args = kmalloc(sizeof(*args) + size, GFP_KERNEL))) - return -ENOMEM; - args->ioctl.version = 0; - args->ioctl.type = NVIF_IOCTL_V0_SCLASS; - args->sclass.version = 0; - args->sclass.count = count; + while (1) { + size = sizeof(*args) + cnt * sizeof(args->sclass.oclass[0]); + if (!(args = kmalloc(size, GFP_KERNEL))) + return -ENOMEM; + args->ioctl.version = 0; + args->ioctl.type = NVIF_IOCTL_V0_SCLASS; + args->sclass.version = 0; + args->sclass.count = cnt; + + ret = nvif_object_ioctl(object, args, size, NULL); + if (ret == 0 && args->sclass.count <= cnt) + break; + cnt = args->sclass.count; + kfree(args); + if (ret != 0) + return ret; + } + + *psclass = kzalloc(sizeof(**psclass) * args->sclass.count, GFP_KERNEL); + if (*psclass) { + for (i = 0; i < args->sclass.count; i++) { + (*psclass)[i].oclass = args->sclass.oclass[i].oclass; + (*psclass)[i].minver = args->sclass.oclass[i].minver; + (*psclass)[i].maxver = args->sclass.oclass[i].maxver; + } + ret = args->sclass.count; + } else { + ret = -ENOMEM; + } - ret = nvif_object_ioctl(object, args, sizeof(*args) + size, NULL); - ret = ret ? ret : args->sclass.count; - memcpy(oclass, args->sclass.oclass, size); kfree(args); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c index 43abd208b4865..aecf5b8901b29 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/parent.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/parent.c @@ -25,6 +25,8 @@ #include #include +#include + int nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, struct nvkm_object **pengine, @@ -66,8 +68,9 @@ nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, } int -nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) +nvkm_parent_lclass(struct nvkm_object *parent, void *data, int size) { + struct nvif_ioctl_sclass_oclass_v0 *lclass = data; struct nvkm_oclass *sclass, *oclass; struct nvkm_engine *engine; int nr = -1, i; @@ -75,8 +78,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) sclass = nv_parent(parent)->sclass; while ((oclass = sclass++) && oclass->ofuncs) { - if (++nr < size) - lclass[nr] = oclass->handle; + if (++nr < size) { + lclass[nr].oclass = oclass->handle; + lclass[nr].minver = -2; + lclass[nr].maxver = -2; + } } mask = nv_parent(parent)->engine; @@ -84,8 +90,11 @@ nvkm_parent_lclass(struct nvkm_object *parent, s32 *lclass, int size) engine = nvkm_engine(parent, i); if (engine && (oclass = engine->sclass)) { while (oclass->ofuncs) { - if (++nr < size) - lclass[nr] = oclass->handle; + if (++nr < size) { + lclass[nr].oclass = oclass->handle; + lclass[nr].minver = -2; + lclass[nr].maxver = -2; + } oclass++; } } -- GitLab From d56241794c293ff7341d373d853e5a4e2f5de244 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5478/7006] drm/nouveau/nvif: add supported engines query to kepler gpfifo class Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 49d7ea0acbd10..bdd0b00c59c9f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -245,9 +245,9 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct gk104_fifo *fifo = (void *)engine; struct gk104_fifo_base *base = (void *)parent; struct gk104_fifo_chan *chan; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_gpuobj *ramfc = &base->base.gpuobj; u64 usermem, ioffset, ilength; + u32 engines; int ret, i; nvif_ioctl(parent, "create channel gpfifo size %d\n", size); @@ -259,20 +259,27 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, } else return ret; - for (i = 0; i < FIFO_ENGINE_NR; i++) { - if (args->v0.engine & (1 << i)) { - if (nvkm_engine(parent, fifo_engine[i].subdev)) { - args->v0.engine = (1 << i); - break; - } - } + for (i = 0, engines = 0; i < FIFO_ENGINE_NR; i++) { + if (!nvkm_engine(parent, fifo_engine[i].subdev)) + continue; + engines |= (1 << i); + } + + if (!args->v0.engine) { + static struct nvkm_oclass oclass = { + .ofuncs = &nvkm_object_ofuncs, + }; + args->v0.engine = engines; + return nvkm_object_ctor(parent, engine, &oclass, NULL, 0, pobject); } - if (i == FIFO_ENGINE_NR) { - nvkm_error(subdev, "unsupported engines %08x\n", + engines &= args->v0.engine; + if (!engines) { + nvif_ioctl(parent, "unsupported engines %08x\n", args->v0.engine); return -ENODEV; } + i = __ffs(engines); ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, fifo->user.bar.offset, 0x200, -- GitLab From 22827fa42b0baa9287ea56691f26dc45fecea049 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5479/7006] drm/nouveau/nvif: return chipset/board names from device info method Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 2 ++ drivers/gpu/drm/nouveau/nvkm/engine/device/user.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index f7394b9a1047b..9c25272b4b793 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -153,6 +153,8 @@ struct nv_device_info_v0 { __u8 pad06[2]; __u64 ram_size; __u64 ram_user; + char chip[16]; + char name[64]; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index c16bde41c279a..e44d60739b56e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -106,6 +106,8 @@ nvkm_udevice_info(struct nvkm_object *object, void *data, u32 size) if (imem && args->v0.ram_size > 0) args->v0.ram_user = args->v0.ram_user - imem->reserved; + strncpy(args->v0.chip, device->cname, sizeof(args->v0.chip)); + strncpy(args->v0.name, device->cname, sizeof(args->v0.name)); return 0; } -- GitLab From 159045cdc460794df27e2cc624a9641be5c54b23 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5480/7006] drm/nouveau/nvif: replace pushbuf with vm in fermi/kepler gpfifo class args Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 21 +++++++++++- drivers/gpu/drm/nouveau/nouveau_chan.c | 16 +++++++-- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 34 ++++++++++--------- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 6 +++- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 11 +++--- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 9 ++--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 6 +++- 11 files changed, 77 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 9c25272b4b793..e11b5acb35e78 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -354,9 +354,18 @@ struct nvif_control_pstate_user_v0 { ******************************************************************************/ struct nv03_channel_dma_v0 { + __u8 version; + __u8 chid; + __u8 pad02[2]; + __u32 offset; + __u64 pushbuf; +}; + +struct nv50_channel_dma_v0 { __u8 version; __u8 chid; __u8 pad02[6]; + __u64 vm; __u64 pushbuf; __u64 offset; }; @@ -374,6 +383,16 @@ struct nv50_channel_gpfifo_v0 { __u32 ilength; __u64 ioffset; __u64 pushbuf; + __u64 vm; +}; + +struct fermi_channel_gpfifo_v0 { + __u8 version; + __u8 chid; + __u8 pad02[2]; + __u32 ilength; + __u64 ioffset; + __u64 vm; }; struct kepler_channel_gpfifo_a_v0 { @@ -389,7 +408,7 @@ struct kepler_channel_gpfifo_a_v0 { __u16 chid; __u32 ilength; __u64 ioffset; - __u64 pushbuf; + __u64 vm; }; /******************************************************************************* diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 65a144f8d3a7e..7f3e821e235de 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -193,6 +193,7 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, const u16 *oclass = oclasses; union { struct nv50_channel_gpfifo_v0 nv50; + struct fermi_channel_gpfifo_v0 fermi; struct kepler_channel_gpfifo_a_v0 kepler; } args; struct nouveau_channel *chan; @@ -210,15 +211,23 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, if (oclass[0] >= KEPLER_CHANNEL_GPFIFO_A) { args.kepler.version = 0; args.kepler.engine = engine; - args.kepler.pushbuf = nvif_handle(&chan->push.ctxdma); args.kepler.ilength = 0x02000; args.kepler.ioffset = 0x10000 + chan->push.vma.offset; + args.kepler.vm = 0; size = sizeof(args.kepler); + } else + if (oclass[0] >= FERMI_CHANNEL_GPFIFO) { + args.fermi.version = 0; + args.fermi.ilength = 0x02000; + args.fermi.ioffset = 0x10000 + chan->push.vma.offset; + args.fermi.vm = 0; + size = sizeof(args.fermi); } else { args.nv50.version = 0; - args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); args.nv50.ilength = 0x02000; args.nv50.ioffset = 0x10000 + chan->push.vma.offset; + args.nv50.pushbuf = nvif_handle(&chan->push.ctxdma); + args.nv50.vm = 0; size = sizeof(args.nv50); } @@ -227,6 +236,9 @@ nouveau_channel_ind(struct nouveau_drm *drm, struct nvif_device *device, if (ret == 0) { if (chan->user.oclass >= KEPLER_CHANNEL_GPFIFO_A) chan->chid = args.kepler.chid; + else + if (chan->user.oclass >= FERMI_CHANNEL_GPFIFO) + chan->chid = args.fermi.chid; else chan->chid = args.nv50.chid; return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 73b8ab4c222eb..f937d705d6687 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -76,23 +76,25 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return ret; /* validate dma object representing push buffer */ - handle = nvkm_client_search(client, pushbuf); - if (!handle) - return -ENOENT; - dmaobj = (void *)handle->object; - - dmaeng = (void *)dmaobj->base.engine; - switch (dmaobj->base.oclass->handle) { - case NV_DMA_FROM_MEMORY: - case NV_DMA_IN_MEMORY: - break; - default: - return -EINVAL; - } + if (pushbuf) { + handle = nvkm_client_search(client, pushbuf); + if (!handle) + return -ENOENT; + dmaobj = (void *)handle->object; + + dmaeng = (void *)dmaobj->base.engine; + switch (dmaobj->base.oclass->handle) { + case NV_DMA_FROM_MEMORY: + case NV_DMA_IN_MEMORY: + break; + default: + return -EINVAL; + } - ret = dmaeng->bind(dmaobj, parent, &chan->pushgpu); - if (ret) - return ret; + ret = dmaeng->bind(dmaobj, parent, &chan->pushgpu); + if (ret) + return ret; + } /* find a free fifo channel */ spin_lock_irqsave(&fifo->lock, flags); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 575329d3f2bb4..64523d7eea589 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -173,7 +173,7 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { union { - struct nv03_channel_dma_v0 v0; + struct nv50_channel_dma_v0 v0; } *args = data; struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent; @@ -185,6 +185,8 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); + if (args->v0.vm) + return -ENOENT; } else return ret; @@ -262,6 +264,8 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, "ioffset %016llx ilength %08x\n", args->v0.version, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); + if (args->v0.vm) + return -ENOENT; } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index cdb25b5cf2752..1fa38227059f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -199,7 +199,7 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { union { - struct nv50_channel_gpfifo_v0 v0; + struct fermi_channel_gpfifo_v0 v0; } *args = data; struct nvkm_bar *bar = nvkm_bar(parent); struct gf100_fifo *fifo = (void *)engine; @@ -211,16 +211,17 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " + nvif_ioctl(parent, "create channel gpfifo vers %d " "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.version, args->v0.ioffset, args->v0.ilength); + if (args->v0.vm) + return -ENOENT; } else return ret; ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - fifo->user.bar.offset, 0x1000, - args->v0.pushbuf, + fifo->user.bar.offset, 0x1000, 0, (1ULL << NVDEV_ENGINE_SW) | (1ULL << NVDEV_ENGINE_GR) | (1ULL << NVDEV_ENGINE_CE0) | diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index bdd0b00c59c9f..48b526cb8cb5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -252,10 +252,12 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " + nvif_ioctl(parent, "create channel gpfifo vers %d " "ioffset %016llx ilength %08x engine %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, + args->v0.version, args->v0.ioffset, args->v0.ilength, args->v0.engine); + if (args->v0.vm) + return -ENOENT; } else return ret; @@ -282,8 +284,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, i = __ffs(engines); ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - fifo->user.bar.offset, 0x200, - args->v0.pushbuf, + fifo->user.bar.offset, 0x200, 0, fifo_engine[i].mask, &chan); *pobject = nv_object(chan); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 6458fa0dcb950..51b8fce9e0fc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -121,7 +121,7 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %016llx\n", args->v0.version, + "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index c4b5a3002e3ce..046acc2813817 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -65,7 +65,7 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %016llx\n", args->v0.version, + "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index ece2715e77ff5..7be6fea900100 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -70,7 +70,7 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %016llx\n", args->v0.version, + "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index a42218a961d47..cad4b4be19387 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -193,7 +193,7 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %016llx\n", args->v0.version, + "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); } else return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 1a7ca8e5aecbf..402639cb4ec9e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -203,7 +203,7 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { union { - struct nv03_channel_dma_v0 v0; + struct nv50_channel_dma_v0 v0; } *args = data; struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent; @@ -215,6 +215,8 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %016llx\n", args->v0.version, args->v0.pushbuf, args->v0.offset); + if (args->v0.vm) + return -ENOENT; } else return ret; @@ -280,6 +282,8 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, "ioffset %016llx ilength %08x\n", args->v0.version, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); + if (args->v0.vm) + return -ENOENT; } else return ret; -- GitLab From d61f4c178cb36a7b15871fcc60814f1f94a5044d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5481/7006] drm/nouveau/nvif: device time mthd Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 7 +++++++ drivers/gpu/drm/nouveau/include/nvif/device.h | 1 - drivers/gpu/drm/nouveau/nvif/device.c | 6 +++++- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 21 +++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index e11b5acb35e78..d52b27ac33ff1 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -129,6 +129,7 @@ struct nv_device_v0 { }; #define NV_DEVICE_V0_INFO 0x00 +#define NV_DEVICE_V0_TIME 0x01 struct nv_device_info_v0 { __u8 version; @@ -157,6 +158,12 @@ struct nv_device_info_v0 { char name[64]; }; +struct nv_device_time_v0 { + __u8 version; + __u8 pad01[7]; + __u64 time; +}; + /******************************************************************************* * context dma diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 68b431b24ae6e..68196f4874f8e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -57,7 +57,6 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_gpio(a) nvkm_gpio(nvxx_device(a)) #define nvxx_clk(a) nvkm_clk(nvxx_device(a)) #define nvxx_i2c(a) nvkm_i2c(nvxx_device(a)) -#define nvxx_timer(a) nvkm_timer(nvxx_device(a)) #define nvxx_therm(a) nvkm_therm(nvxx_device(a)) #include diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c index 561fb9d7b1550..252d8c33215bb 100644 --- a/drivers/gpu/drm/nouveau/nvif/device.c +++ b/drivers/gpu/drm/nouveau/nvif/device.c @@ -27,7 +27,11 @@ u64 nvif_device_time(struct nvif_device *device) { - return nvxx_timer(device)->read(nvxx_timer(device)); + struct nv_device_time_v0 args = {}; + int ret = nvif_object_mthd(&device->object, NV_DEVICE_V0_TIME, + &args, sizeof(args)); + WARN_ON_ONCE(ret != 0); + return args.time; } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index e44d60739b56e..cb3f3deefb018 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -111,12 +112,32 @@ nvkm_udevice_info(struct nvkm_object *object, void *data, u32 size) return 0; } +static int +nvkm_udevice_time(struct nvkm_object *object, void *data, u32 size) +{ + struct nvkm_udevice *udev = (void *)object; + struct nvkm_device *device = udev->device; + struct nvkm_timer *tmr = device->timer; + union { + struct nv_device_time_v0 v0; + } *args = data; + int ret; + + if (nvif_unpack(args->v0, 0, 0, false)) { + args->v0.time = tmr->read(tmr); + } + + return ret; +} + static int nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { switch (mthd) { case NV_DEVICE_V0_INFO: return nvkm_udevice_info(object, data, size); + case NV_DEVICE_V0_TIME: + return nvkm_udevice_time(object, data, size); default: break; } -- GitLab From aa35888ff024b18c7b6b29eb773a221f642987f7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5482/7006] drm/nouveau/object: rename some functions to avoid upcoming conflicts Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/core/object.h | 6 +++--- drivers/gpu/drm/nouveau/include/nvkm/core/parent.h | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/core/object.c | 10 +++++----- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c | 6 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h | 8 ++++---- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 2 +- 22 files changed, 51 insertions(+), 51 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index 0dd216c055f67..46975785ba3c0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -32,8 +32,8 @@ nv_gpuobj(void *obj) #define nvkm_gpuobj_create(p,e,c,v,g,s,a,f,d) \ nvkm_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f), \ sizeof(**d), (void **)d) -#define nvkm_gpuobj_init(p) nvkm_object_init(&(p)->object) -#define nvkm_gpuobj_fini(p,s) nvkm_object_fini(&(p)->object, (s)) +#define nvkm_gpuobj_init(p) _nvkm_object_init(&(p)->object) +#define nvkm_gpuobj_fini(p,s) _nvkm_object_fini(&(p)->object, (s)) int nvkm_gpuobj_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, u32 pclass, struct nvkm_object *, u32 size, u32 align, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 005cd4a868491..39a4962d39821 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -50,8 +50,8 @@ nv_object(void *obj) int nvkm_object_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, u32, int size, void **); void nvkm_object_destroy(struct nvkm_object *); -int nvkm_object_init(struct nvkm_object *); -int nvkm_object_fini(struct nvkm_object *, bool suspend); +int _nvkm_object_init(struct nvkm_object *); +int _nvkm_object_fini(struct nvkm_object *, bool suspend); int _nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, @@ -112,7 +112,7 @@ nv_ofuncs(void *obj) return nv_oclass(obj)->ofuncs; } -int nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *, +int nvkm_object_old(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h index 45d2066ff97a0..92270afc666a2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h @@ -30,9 +30,9 @@ nv_parent(void *obj) nvkm_parent_create_((p), (e), (c), (v), (s), (m), \ sizeof(**d), (void **)d) #define nvkm_parent_init(p) \ - nvkm_object_init(&(p)->object) + _nvkm_object_init(&(p)->object) #define nvkm_parent_fini(p,s) \ - nvkm_object_fini(&(p)->object, (s)) + _nvkm_object_fini(&(p)->object, (s)) int nvkm_parent_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, u32 pclass, @@ -41,8 +41,8 @@ int nvkm_parent_create_(struct nvkm_object *, struct nvkm_object *, void nvkm_parent_destroy(struct nvkm_parent *); void _nvkm_parent_dtor(struct nvkm_object *); -#define _nvkm_parent_init nvkm_object_init -#define _nvkm_parent_fini nvkm_object_fini +#define _nvkm_parent_init _nvkm_object_init +#define _nvkm_parent_fini _nvkm_object_fini int nvkm_parent_sclass(struct nvkm_object *, s32 handle, struct nvkm_object **pengine, diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index 6e26833235707..1ca5479ee38b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -223,9 +223,9 @@ nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu, .flags = flags, }; - return nvkm_object_ctor(parent, &parent->engine->subdev.object, - &_nvkm_gpuobj_oclass, &args, sizeof(args), - (struct nvkm_object **)pgpuobj); + return nvkm_object_old(parent, &parent->engine->subdev.object, + &_nvkm_gpuobj_oclass, &args, sizeof(args), + (struct nvkm_object **)pgpuobj); } int @@ -288,8 +288,8 @@ nvkm_gpudup_oclass = { .handle = NV_GPUOBJ_CLASS, .ofuncs = &(struct nvkm_ofuncs) { .dtor = nvkm_gpudup_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index ee6ff01c2b1ba..7a15b15bfce0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -137,7 +137,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) * between the parent and its children (eg. PGRAPH context) */ if (engine && nv_engine(engine)->cclass) { - ret = nvkm_object_ctor(&parent->object, engine, + ret = nvkm_object_old(&parent->object, engine, nv_engine(engine)->cclass, data, size, &engctx); if (ret) @@ -147,7 +147,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) } /* finally, create new object and bind it to its handle */ - ret = nvkm_object_ctor(engctx, engine, oclass, data, size, &object); + ret = nvkm_object_old(engctx, engine, oclass, data, size, &object); client->data = object; if (ret) goto fail_ctor; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index 98ba58ec1d394..1c117f0a7245d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -136,13 +136,13 @@ nvkm_object_destroy(struct nvkm_object *object) } int -nvkm_object_init(struct nvkm_object *object) +_nvkm_object_init(struct nvkm_object *object) { return 0; } int -nvkm_object_fini(struct nvkm_object *object, bool suspend) +_nvkm_object_fini(struct nvkm_object *object, bool suspend) { return 0; } @@ -151,12 +151,12 @@ struct nvkm_ofuncs nvkm_object_ofuncs = { .ctor = _nvkm_object_ctor, .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, }; int -nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, +nvkm_object_old(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 25f3503cd37a0..0c313468d94e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -48,7 +48,7 @@ nvkm_subdev_reset(struct nvkm_object *obj) int nvkm_subdev_init(struct nvkm_subdev *subdev) { - int ret = nvkm_object_init(&subdev->object); + int ret = _nvkm_object_init(&subdev->object); if (ret) return ret; @@ -72,7 +72,7 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) nvkm_mask(device, 0x000200, subdev->unit, subdev->unit); } - return nvkm_object_fini(&subdev->object, suspend); + return _nvkm_object_fini(&subdev->object, suspend); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 479181c839b48..b7892e6f080b4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -152,7 +152,7 @@ nvkm_device_init(struct nvkm_device *device) for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) { #define _(s,m) case s: if (device->oclass[s] && !device->subdev[s]) { \ - ret = nvkm_object_ctor(nv_object(device), NULL, \ + ret = nvkm_object_old(nv_object(device), NULL, \ device->oclass[s], NULL, (s), \ (struct nvkm_object **)&device->m); \ if (ret == -ENODEV) { \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c index c13cd9d46a1ab..0abee2d21a78f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c @@ -185,8 +185,8 @@ static struct nvkm_ofuncs nvkm_control_ofuncs = { .ctor = _nvkm_object_ctor, .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, .mthd = nvkm_control_mthd, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index d6c0cf0e5a35b..ab5f8429e680b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -106,8 +106,8 @@ static struct nvkm_ofuncs nv04_disp_ofuncs = { .ctor = _nvkm_object_ctor, .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, .mthd = nv04_disp_mthd, .ntfy = nvkm_disp_ntfy, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h index 44ae8a0ca65c6..c4c210bdbf7e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h @@ -9,8 +9,8 @@ int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void **, u32 *, int, void **); #define _nvkm_dmaobj_dtor nvkm_object_destroy -#define _nvkm_dmaobj_init nvkm_object_init -#define _nvkm_dmaobj_fini nvkm_object_fini +#define _nvkm_dmaobj_init _nvkm_object_init +#define _nvkm_dmaobj_fini _nvkm_object_fini int _nvkm_dmaeng_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 48b526cb8cb5b..3562b791162f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -272,7 +272,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, .ofuncs = &nvkm_object_ofuncs, }; args->v0.engine = engines; - return nvkm_object_ctor(parent, engine, &oclass, NULL, 0, pobject); + return nvkm_object_old(parent, engine, &oclass, NULL, 0, pobject); } engines &= args->v0.engine; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index a7141e08930c7..6afdb20cf304e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -228,8 +228,8 @@ struct nvkm_ofuncs gf100_fermi_ofuncs = { .ctor = _nvkm_object_ctor, .dtor = nvkm_object_destroy, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, .mthd = gf100_fermi_mthd, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 323f020166da5..617161e4fc15d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1187,7 +1187,7 @@ nv04_gr_context_fini(struct nvkm_object *object, bool suspend) nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); - return nvkm_object_fini(&chan->base, suspend); + return _nvkm_object_fini(&chan->base, suspend); } static struct nvkm_oclass @@ -1196,7 +1196,7 @@ nv04_gr_cclass = { .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv04_gr_context_ctor, .dtor = nv04_gr_context_dtor, - .init = nvkm_object_init, + .init = _nvkm_object_init, .fini = nv04_gr_context_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 94f7dc794d2f1..be92015d8f9e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -1111,7 +1111,7 @@ nv10_gr_context_fini(struct nvkm_object *object, bool suspend) nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); - return nvkm_object_fini(&chan->base, suspend); + return _nvkm_object_fini(&chan->base, suspend); } static struct nvkm_oclass @@ -1120,7 +1120,7 @@ nv10_gr_cclass = { .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv10_gr_context_ctor, .dtor = nv10_gr_context_dtor, - .init = nvkm_object_init, + .init = _nvkm_object_init, .fini = nv10_gr_context_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 1586213b0830d..0f02b281f34e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -173,8 +173,8 @@ nv31_mpeg_cclass = { .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv31_mpeg_context_ctor, .dtor = nv31_mpeg_context_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, }, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index b75395bf8ffa3..ac27f511163af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -419,8 +419,8 @@ static struct nvkm_ofuncs nvkm_perfdom_ofuncs = { .ctor = nvkm_perfdom_ctor, .dtor = nvkm_perfdom_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, .mthd = nvkm_perfdom_mthd, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 0cdb49e983ab9..6fe71b2276cca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -94,8 +94,8 @@ nvkm_barobj_oclass = { .ofuncs = &(struct nvkm_ofuncs) { .ctor = nvkm_barobj_ctor, .dtor = nvkm_barobj_dtor, - .init = nvkm_object_init, - .fini = nvkm_object_fini, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, .rd32 = nvkm_barobj_rd32, .wr32 = nvkm_barobj_wr32, }, @@ -106,7 +106,7 @@ nvkm_bar_alloc(struct nvkm_bar *bar, struct nvkm_object *parent, struct nvkm_mem *mem, struct nvkm_object **pobject) { struct nvkm_object *gpuobj; - int ret = nvkm_object_ctor(parent, &parent->engine->subdev.object, + int ret = nvkm_object_old(parent, &parent->engine->subdev.object, &nvkm_barobj_oclass, mem, 0, &gpuobj); if (ret == 0) *pobject = gpuobj; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 4219eb39cf450..495da913bd111 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -72,7 +72,7 @@ nvkm_instmem_alloc(struct nvkm_instmem *imem, struct nvkm_object *parent, { struct nvkm_instmem_impl *impl = (void *)imem->subdev.object.oclass; struct nvkm_instobj_args args = { .size = size, .align = align }; - return nvkm_object_ctor(parent, &parent->engine->subdev.object, + return nvkm_object_old(parent, &parent->engine->subdev.object, impl->instobj, &args, sizeof(args), pobject); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index e217ebebd325b..819f615782cf8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -18,15 +18,15 @@ struct nvkm_instobj_args { _nvkm_instobj_dtor(nv_object(iobj)); \ }) #define nvkm_instobj_init(p) \ - nvkm_object_init(&(p)->base) + _nvkm_object_init(&(p)->base) #define nvkm_instobj_fini(p,s) \ - nvkm_object_fini(&(p)->base, (s)) + _nvkm_object_fini(&(p)->base, (s)) int nvkm_instobj_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); void _nvkm_instobj_dtor(struct nvkm_object *); -#define _nvkm_instobj_init nvkm_object_init -#define _nvkm_instobj_fini nvkm_object_fini +#define _nvkm_instobj_init _nvkm_object_init +#define _nvkm_instobj_fini _nvkm_object_fini struct nvkm_instmem_impl { struct nvkm_oclass base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index c44f880120abf..26192b91e456d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -96,7 +96,7 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) { - return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass, + return nvkm_object_old(parent, engine, &nv04_mmu_oclass, data, size, pobject); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 3be8a796d797b..3e51dc772536d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -169,7 +169,7 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) { - return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass, + return nvkm_object_old(parent, engine, &nv04_mmu_oclass, data, size, pobject); } -- GitLab From 3a8c3400f3e74638bedd0d2410416aa8b794c0fd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5483/7006] drm/nouveau/subdev: rename some functions to avoid upcoming conflicts Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/engine.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h | 2 +- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 10 ++++++---- drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c | 2 +- 24 files changed, 48 insertions(+), 46 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 0b5f05aec2dff..3212b12a70eda 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -41,9 +41,9 @@ struct nvkm_engine *nvkm_engine(void *obj, int idx); #define nvkm_engine_destroy(p) \ nvkm_subdev_destroy(&(p)->subdev) #define nvkm_engine_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_engine_fini(p,s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) int nvkm_engine_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, bool, const char *, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index ce5f1b93ef9aa..d3e08bf8d977e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -44,8 +44,8 @@ int nvkm_subdev_create_(struct nvkm_object *, struct nvkm_object *, const char *sname, const char *fname, int size, void **); void nvkm_subdev_destroy(struct nvkm_subdev *); -int nvkm_subdev_init(struct nvkm_subdev *); -int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend); +int nvkm_subdev_init_old(struct nvkm_subdev *); +int nvkm_subdev_fini_old(struct nvkm_subdev *, bool suspend); void nvkm_subdev_reset(struct nvkm_object *); void _nvkm_subdev_dtor(struct nvkm_object *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h index ce7663c60015c..5cf58a15bf41f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h @@ -25,9 +25,9 @@ nvkm_bus(void *obj) #define nvkm_bus_destroy(p) \ nvkm_subdev_destroy(&(p)->subdev) #define nvkm_bus_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_bus_fini(p, s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) #define _nvkm_bus_dtor _nvkm_subdev_dtor #define _nvkm_bus_init _nvkm_subdev_init diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h index 3538e87a44528..8fc7946b8a42f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h @@ -18,9 +18,9 @@ nvkm_ibus(void *obj) #define nvkm_ibus_destroy(p) \ nvkm_subdev_destroy(&(p)->subdev) #define nvkm_ibus_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_ibus_fini(p,s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) #define _nvkm_ibus_dtor _nvkm_subdev_dtor #define _nvkm_ibus_init _nvkm_subdev_init diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index b596a1dd5b81c..2bf8f46c1bb05 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -71,9 +71,9 @@ nvkm_mmu(void *obj) #define nvkm_mmu_destroy(p) \ nvkm_subdev_destroy(&(p)->subdev) #define nvkm_mmu_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_mmu_fini(p,s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) #define _nvkm_mmu_dtor _nvkm_subdev_dtor #define _nvkm_mmu_init _nvkm_subdev_init diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h index 98904392547d6..93f9a4ec23205 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h @@ -19,9 +19,9 @@ nvkm_mxm(void *obj) #define nvkm_mxm_create(p,e,o,d) \ nvkm_mxm_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_mxm_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_mxm_fini(p,s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) int nvkm_mxm_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); void nvkm_mxm_destroy(struct nvkm_mxm *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index 4ae73689488bd..f818adcc74670 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -70,9 +70,9 @@ nvkm_timer(void *obj) #define nvkm_timer_destroy(p) \ nvkm_subdev_destroy(&(p)->subdev) #define nvkm_timer_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_timer_fini(p,s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) int nvkm_timer_create_(struct nvkm_object *, struct nvkm_engine *, struct nvkm_oclass *, int size, void **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index 1eeb80a380d22..dc8846899a60a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -41,7 +41,7 @@ nvkm_volt(void *obj) _nvkm_volt_init(nv_object(v)); \ }) #define nvkm_volt_fini(p,s) \ - nvkm_subdev_fini((p), (s)) + nvkm_subdev_fini_old((p), (s)) int nvkm_volt_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 0c313468d94e5..3f6795f512185 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -46,7 +46,7 @@ nvkm_subdev_reset(struct nvkm_object *obj) } int -nvkm_subdev_init(struct nvkm_subdev *subdev) +nvkm_subdev_init_old(struct nvkm_subdev *subdev) { int ret = _nvkm_object_init(&subdev->object); if (ret) @@ -59,11 +59,12 @@ nvkm_subdev_init(struct nvkm_subdev *subdev) int _nvkm_subdev_init(struct nvkm_object *object) { - return nvkm_subdev_init(nv_subdev(object)); + struct nvkm_subdev *subdev = (void *)object; + return nvkm_subdev_init_old(subdev); } int -nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) +nvkm_subdev_fini_old(struct nvkm_subdev *subdev, bool suspend) { struct nvkm_device *device = subdev->device; @@ -78,7 +79,8 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) int _nvkm_subdev_fini(struct nvkm_object *object, bool suspend) { - return nvkm_subdev_fini(nv_subdev(object), suspend); + struct nvkm_subdev *subdev = (void *)object; + return nvkm_subdev_fini_old(subdev, suspend); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h index e6e4dfc97dcc1..e9d2f7b6b22f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h @@ -5,9 +5,9 @@ #define nvkm_bar_create(p,e,o,d) \ nvkm_bar_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_bar_init(p) \ - nvkm_subdev_init(&(p)->subdev) + nvkm_subdev_init_old(&(p)->subdev) #define nvkm_bar_fini(p,s) \ - nvkm_subdev_fini(&(p)->subdev, (s)) + nvkm_subdev_fini_old(&(p)->subdev, (s)) int nvkm_bar_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index cc434268d9958..b48ec70d9c553 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -149,14 +149,14 @@ static int nvkm_bios_init(struct nvkm_object *object) { struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_init(&bios->subdev); + return nvkm_subdev_init_old(&bios->subdev); } static int nvkm_bios_fini(struct nvkm_object *object, bool suspend) { struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_fini(&bios->subdev, suspend); + return nvkm_subdev_fini_old(&bios->subdev, suspend); } struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index cfd1feed99c38..659122721b7db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -479,7 +479,7 @@ _nvkm_clk_fini(struct nvkm_object *object, bool suspend) { struct nvkm_clk *clk = (void *)object; nvkm_notify_put(&clk->pwrsrc_ntfy); - return nvkm_subdev_fini(&clk->subdev, suspend); + return nvkm_subdev_fini_old(&clk->subdev, suspend); } int @@ -490,7 +490,7 @@ _nvkm_clk_init(struct nvkm_object *object) struct nvkm_domain *clock = clk->domains; int ret; - ret = nvkm_subdev_init(&clk->subdev); + ret = nvkm_subdev_init_old(&clk->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index 989513fae7d5a..e5ef999adbb93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -38,7 +38,7 @@ _nvkm_devinit_fini(struct nvkm_object *object, bool suspend) /* unlock the extended vga crtc regs */ nvkm_lockvgac(init->subdev.device, false); - return nvkm_subdev_fini(&init->subdev, suspend); + return nvkm_subdev_fini_old(&init->subdev, suspend); } int @@ -48,7 +48,7 @@ _nvkm_devinit_init(struct nvkm_object *object) struct nvkm_devinit *init = (void *)object; int ret; - ret = nvkm_subdev_init(&init->subdev); + ret = nvkm_subdev_init_old(&init->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 328381b8f0acf..d435bd155684f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -56,7 +56,7 @@ int _nvkm_fb_fini(struct nvkm_object *object, bool suspend) { struct nvkm_fb *fb = (void *)object; - return nvkm_subdev_fini(&fb->subdev, suspend); + return nvkm_subdev_fini_old(&fb->subdev, suspend); } int @@ -65,7 +65,7 @@ _nvkm_fb_init(struct nvkm_object *object) struct nvkm_fb *fb = (void *)object; int ret, i; - ret = nvkm_subdev_init(&fb->subdev); + ret = nvkm_subdev_init_old(&fb->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c index 4c1884ee7e385..8889925da3d7b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c @@ -27,7 +27,7 @@ int _nvkm_fuse_init(struct nvkm_object *object) { struct nvkm_fuse *fuse = (void *)object; - return nvkm_subdev_init(&fuse->subdev); + return nvkm_subdev_init_old(&fuse->subdev); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index 1f10e7e773c27..07db5845f8b20 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -168,7 +168,7 @@ _nvkm_gpio_fini(struct nvkm_object *object, bool suspend) impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); impl->intr_stat(gpio, &mask, &mask); - return nvkm_subdev_fini(&gpio->subdev, suspend); + return nvkm_subdev_fini_old(&gpio->subdev, suspend); } static struct dmi_system_id gpio_reset_ids[] = { @@ -188,7 +188,7 @@ _nvkm_gpio_init(struct nvkm_object *object) struct nvkm_gpio *gpio = nvkm_gpio(object); int ret; - ret = nvkm_subdev_init(&gpio->subdev); + ret = nvkm_subdev_init_old(&gpio->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index 86bff984e7e10..fe29e728a6029 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -175,7 +175,7 @@ _nvkm_i2c_fini(struct nvkm_object *object, bool suspend) nvkm_i2c_pad_fini(pad); } - return nvkm_subdev_fini(&i2c->subdev, suspend); + return nvkm_subdev_fini_old(&i2c->subdev, suspend); } int @@ -186,7 +186,7 @@ _nvkm_i2c_init(struct nvkm_object *object) struct nvkm_i2c_pad *pad; int ret; - ret = nvkm_subdev_init(&i2c->subdev); + ret = nvkm_subdev_init_old(&i2c->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 495da913bd111..8ac8e4f4fa4b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -102,7 +102,7 @@ _nvkm_instmem_fini(struct nvkm_object *object, bool suspend) return ret; } - return nvkm_subdev_fini(&imem->subdev, suspend); + return nvkm_subdev_fini_old(&imem->subdev, suspend); } int @@ -112,7 +112,7 @@ _nvkm_instmem_init(struct nvkm_object *object) struct nvkm_instobj *iobj; int ret, i; - ret = nvkm_subdev_init(&imem->subdev); + ret = nvkm_subdev_init_old(&imem->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c index f9cfbabeeeb32..d0af1aec0fc6a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c @@ -83,7 +83,7 @@ _nvkm_ltc_init(struct nvkm_object *object) const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object); int ret, i; - ret = nvkm_subdev_init(<c->base.subdev); + ret = nvkm_subdev_init_old(<c->base.subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index babd6d8725f0f..f861a02d8d59f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -86,7 +86,7 @@ _nvkm_mc_fini(struct nvkm_object *object, bool suspend) struct nvkm_mc *mc = (void *)object; struct nvkm_device *device = mc->subdev.device; nvkm_wr32(device, 0x000140, 0x00000000); - return nvkm_subdev_fini(&mc->subdev, suspend); + return nvkm_subdev_fini_old(&mc->subdev, suspend); } int @@ -94,7 +94,7 @@ _nvkm_mc_init(struct nvkm_object *object) { struct nvkm_mc *mc = (void *)object; struct nvkm_device *device = mc->subdev.device; - int ret = nvkm_subdev_init(&mc->subdev); + int ret = nvkm_subdev_init_old(&mc->subdev); if (ret) return ret; nvkm_wr32(device, 0x000140, 0x00000001); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index 2479940179658..c700d3d956e81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -189,7 +189,7 @@ _nvkm_pmu_fini(struct nvkm_object *object, bool suspend) nvkm_wr32(device, 0x10a014, 0x00000060); flush_work(&pmu->recv.work); - return nvkm_subdev_fini(&pmu->subdev, suspend); + return nvkm_subdev_fini_old(&pmu->subdev, suspend); } int @@ -200,7 +200,7 @@ _nvkm_pmu_init(struct nvkm_object *object) struct nvkm_device *device = pmu->subdev.device; int ret, i; - ret = nvkm_subdev_init(&pmu->subdev); + ret = nvkm_subdev_init_old(&pmu->subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 1003013666a94..47c6dbe8fff3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -171,7 +171,7 @@ gk20a_pmu_fini(struct nvkm_object *object, bool suspend) nvkm_timer_alarm_cancel(pmu, &pmu->alarm); - return nvkm_subdev_fini(&pmu->base.subdev, suspend); + return nvkm_subdev_fini_old(&pmu->base.subdev, suspend); } static int @@ -181,7 +181,7 @@ gk20a_pmu_init(struct nvkm_object *object) struct nvkm_device *device = pmu->base.subdev.device; int ret; - ret = nvkm_subdev_init(&pmu->base.subdev); + ret = nvkm_subdev_init_old(&pmu->base.subdev); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index 18fa0443b6d3e..e757fd9b7a07e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -288,7 +288,7 @@ _nvkm_therm_init(struct nvkm_object *object) struct nvkm_therm_priv *therm = (void *)object; int ret; - ret = nvkm_subdev_init(&therm->base.subdev); + ret = nvkm_subdev_init_old(&therm->base.subdev); if (ret) return ret; @@ -316,7 +316,7 @@ _nvkm_therm_fini(struct nvkm_object *object, bool suspend) therm->mode = NVKM_THERM_CTRL_NONE; } - return nvkm_subdev_fini(&therm->base.subdev, suspend); + return nvkm_subdev_fini_old(&therm->base.subdev, suspend); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 67650a351a96a..88e5f62ec7722 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -142,7 +142,7 @@ _nvkm_volt_init(struct nvkm_object *object) struct nvkm_subdev *subdev = &volt->subdev; int ret; - ret = nvkm_subdev_init(&volt->subdev); + ret = nvkm_subdev_init_old(&volt->subdev); if (ret) return ret; -- GitLab From 89c651e2213a148d19407109051abbf81328a4a8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5484/7006] drm/nouveau/engine: rename some functions to avoid upcoming conflicts Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/core/engine.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h | 4 ++-- drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 4 ++-- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 4 ++-- 10 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 3212b12a70eda..f98980e15f264 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -40,9 +40,9 @@ struct nvkm_engine *nvkm_engine(void *obj, int idx); #define nvkm_engine_destroy(p) \ nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_engine_init(p) \ +#define nvkm_engine_init_old(p) \ nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_engine_fini(p,s) \ +#define nvkm_engine_fini_old(p,s) \ nvkm_subdev_fini_old(&(p)->subdev, (s)) int nvkm_engine_create_(struct nvkm_object *, struct nvkm_object *, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index fb8d2b5a05671..0af10f9db9e29 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -91,9 +91,9 @@ nvkm_fifo(void *obj) #define nvkm_fifo_create(o,e,c,fc,lc,d) \ nvkm_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d) #define nvkm_fifo_init(p) \ - nvkm_engine_init(&(p)->engine) + nvkm_engine_init_old(&(p)->engine) #define nvkm_fifo_fini(p,s) \ - nvkm_engine_fini(&(p)->engine, (s)) + nvkm_engine_fini_old(&(p)->engine, (s)) int nvkm_fifo_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int min, int max, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index 74bf2fe9a3ca3..0fd02c27b869b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -42,9 +42,9 @@ nvkm_gr(void *obj) #define nvkm_gr_destroy(d) \ nvkm_engine_destroy(&(d)->engine) #define nvkm_gr_init(d) \ - nvkm_engine_init(&(d)->engine) + nvkm_engine_init_old(&(d)->engine) #define nvkm_gr_fini(d,s) \ - nvkm_engine_fini(&(d)->engine, (s)) + nvkm_engine_fini_old(&(d)->engine, (s)) #define _nvkm_gr_dtor _nvkm_engine_dtor #define _nvkm_gr_init _nvkm_engine_init diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h index 24cfd93f65d5f..db5c3d5a07520 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h @@ -32,9 +32,9 @@ struct nvkm_mpeg { #define nvkm_mpeg_destroy(d) \ nvkm_engine_destroy(&(d)->engine) #define nvkm_mpeg_init(d) \ - nvkm_engine_init(&(d)->engine) + nvkm_engine_init_old(&(d)->engine) #define nvkm_mpeg_fini(d,s) \ - nvkm_engine_fini(&(d)->engine, (s)) + nvkm_engine_fini_old(&(d)->engine, (s)) #define _nvkm_mpeg_dtor _nvkm_engine_dtor #define _nvkm_mpeg_init _nvkm_engine_init diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h index c46e5595573b5..8dae95829f664 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h @@ -33,9 +33,9 @@ struct nvkm_sw { #define nvkm_sw_destroy(d) \ nvkm_engine_destroy(&(d)->engine) #define nvkm_sw_init(d) \ - nvkm_engine_init(&(d)->engine) + nvkm_engine_init_old(&(d)->engine) #define nvkm_sw_fini(d,s) \ - nvkm_engine_fini(&(d)->engine, (s)) + nvkm_engine_fini_old(&(d)->engine, (s)) #define _nvkm_sw_dtor _nvkm_engine_dtor #define _nvkm_sw_init _nvkm_engine_init diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 312df6fa57078..67892295e51ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -163,7 +163,7 @@ g84_cipher_init(struct nvkm_object *object) struct nvkm_device *device = cipher->subdev.device; int ret; - ret = nvkm_engine_init(cipher); + ret = nvkm_engine_init_old(cipher); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 7e6744536fa0a..fea8516220f3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -129,7 +129,7 @@ _nvkm_disp_fini(struct nvkm_object *object, bool suspend) nvkm_connector_fini(conn); } - return nvkm_engine_fini(&disp->engine, suspend); + return nvkm_engine_fini_old(&disp->engine, suspend); } int @@ -140,7 +140,7 @@ _nvkm_disp_init(struct nvkm_object *object) struct nvkm_output *outp; int ret; - ret = nvkm_engine_init(&disp->engine); + ret = nvkm_engine_init_old(&disp->engine); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index d2849ece1ba66..52f6a6e492167 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -67,7 +67,7 @@ _nvkm_falcon_init(struct nvkm_object *object) u32 caps; /* enable engine, and determine its capabilities */ - ret = nvkm_engine_init(&falcon->engine); + ret = nvkm_engine_init_old(&falcon->engine); if (ret) return ret; @@ -254,7 +254,7 @@ _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); nvkm_wr32(device, base + 0x014, 0xffffffff); - return nvkm_engine_fini(&falcon->engine, suspend); + return nvkm_engine_fini_old(&falcon->engine, suspend); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index ac27f511163af..a441fd3b69bc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -813,14 +813,14 @@ int _nvkm_pm_fini(struct nvkm_object *object, bool suspend) { struct nvkm_pm *pm = (void *)object; - return nvkm_engine_fini(&pm->engine, suspend); + return nvkm_engine_fini_old(&pm->engine, suspend); } int _nvkm_pm_init(struct nvkm_object *object) { struct nvkm_pm *pm = (void *)object; - return nvkm_engine_init(&pm->engine); + return nvkm_engine_init_old(&pm->engine); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index 974d7a0d7a36b..45dd8b8da4c95 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -90,7 +90,7 @@ _nvkm_xtensa_init(struct nvkm_object *object) int i, ret; u32 tmp; - ret = nvkm_engine_init(&xtensa->engine); + ret = nvkm_engine_init_old(&xtensa->engine); if (ret) return ret; @@ -161,5 +161,5 @@ _nvkm_xtensa_fini(struct nvkm_object *object, bool suspend) if (!suspend) nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw); - return nvkm_engine_fini(&xtensa->engine, suspend); + return nvkm_engine_fini_old(&xtensa->engine, suspend); } -- GitLab From cbea21e2ab658ca1256bfe5f4c535b2b1b9e4060 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5485/7006] drm/nouveau/object: implement support for new-style nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/gpuobj.h | 8 +- .../drm/nouveau/include/nvkm/core/object.h | 62 ++++- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 8 +- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 17 +- drivers/gpu/drm/nouveau/nvkm/core/object.c | 227 +++++++++++++++--- drivers/gpu/drm/nouveau/nvkm/core/ramht.c | 2 +- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 4 +- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 2 +- 10 files changed, 271 insertions(+), 65 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index 46975785ba3c0..2260aef3ec3e8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -68,8 +68,12 @@ void _nvkm_gpuobj_wr32(struct nvkm_object *, u64, u32); struct nvkm_gpuobj *_gpuobj = (o); \ (void)_gpuobj; \ } while(0) -#define nvkm_ro32(o,a) nv_ofuncs(o)->rd32(&(o)->object, (a)) -#define nvkm_wo32(o,a,d) nv_ofuncs(o)->wr32(&(o)->object, (a), (d)) +#define nvkm_ro32(o,a) ({ \ + u32 _data; \ + nvkm_object_rd32(&(o)->object, (a), &_data); \ + _data; \ +}) +#define nvkm_wo32(o,a,d) nvkm_object_wr32(&(o)->object, (a), (d)) #define nvkm_mo32(o,a,m,d) ({ \ u32 _addr = (a), _data = nvkm_ro32((o), _addr); \ nvkm_wo32((o), _addr, (_data & ~(m)) | (d)); \ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 39a4962d39821..84040a336036b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -2,6 +2,8 @@ #define __NVKM_OBJECT_H__ #include #include +struct nvkm_event; +struct nvkm_gpuobj; #define NV_PARENT_CLASS 0x80000000 #define NV_NAMEDB_CLASS 0x40000000 @@ -13,10 +15,14 @@ #define NV_ENGCTX_CLASS 0x01000000 struct nvkm_object { + const struct nvkm_object_func *func; + struct nvkm_client *client; + struct nvkm_engine *engine; + u32 oclass_name; + u32 handle; + struct nvkm_object *parent; struct nvkm_oclass *oclass; u32 pclass; - struct nvkm_object *parent; - struct nvkm_engine *engine; atomic_t refcount; atomic_t usecount; #if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA @@ -26,12 +32,44 @@ struct nvkm_object { #endif }; +struct nvkm_object_func { + void *(*dtor)(struct nvkm_object *); + int (*init)(struct nvkm_object *); + int (*fini)(struct nvkm_object *, bool suspend); + int (*mthd)(struct nvkm_object *, u32 mthd, void *data, u32 size); + int (*ntfy)(struct nvkm_object *, u32 mthd, struct nvkm_event **); + int (*map)(struct nvkm_object *, u64 *addr, u32 *size); + int (*rd08)(struct nvkm_object *, u64 addr, u8 *data); + int (*rd16)(struct nvkm_object *, u64 addr, u16 *data); + int (*rd32)(struct nvkm_object *, u64 addr, u32 *data); + int (*wr08)(struct nvkm_object *, u64 addr, u8 data); + int (*wr16)(struct nvkm_object *, u64 addr, u16 data); + int (*wr32)(struct nvkm_object *, u64 addr, u32 data); + int (*bind)(struct nvkm_object *, struct nvkm_gpuobj *, int align, + struct nvkm_gpuobj **); + int (*sclass)(struct nvkm_object *, int index, struct nvkm_oclass *); +}; + +void nvkm_object_ctor(const struct nvkm_object_func *, + const struct nvkm_oclass *, struct nvkm_object *); +int nvkm_object_new_(const struct nvkm_object_func *, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +int nvkm_object_new(const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +int nvkm_object_init(struct nvkm_object *); +int nvkm_object_fini(struct nvkm_object *, bool suspend); +int nvkm_object_mthd(struct nvkm_object *, u32 mthd, void *data, u32 size); +int nvkm_object_ntfy(struct nvkm_object *, u32 mthd, struct nvkm_event **); +int nvkm_object_map(struct nvkm_object *, u64 *addr, u32 *size); int nvkm_object_rd08(struct nvkm_object *, u64 addr, u8 *data); int nvkm_object_rd16(struct nvkm_object *, u64 addr, u16 *data); int nvkm_object_rd32(struct nvkm_object *, u64 addr, u32 *data); int nvkm_object_wr08(struct nvkm_object *, u64 addr, u8 data); int nvkm_object_wr16(struct nvkm_object *, u64 addr, u16 data); int nvkm_object_wr32(struct nvkm_object *, u64 addr, u32 data); +int nvkm_object_bind(struct nvkm_object *, struct nvkm_gpuobj *, int align, + struct nvkm_gpuobj **); static inline struct nvkm_object * nv_object(void *obj) @@ -59,6 +97,15 @@ int _nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *, extern struct nvkm_ofuncs nvkm_object_ofuncs; +struct nvkm_sclass { + int minver; + int maxver; + s32 oclass; + const struct nvkm_object_func *func; + int (*ctor)(const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +}; + /* Don't allocate dynamically, because lockdep needs lock_class_keys to be in * ".data". */ struct nvkm_oclass { @@ -66,6 +113,16 @@ struct nvkm_oclass { struct nvkm_ofuncs * const ofuncs; struct nvkm_omthds * const omthds; struct lock_class_key lock_class_key; + + int (*ctor)(const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + struct nvkm_sclass base; + const void *priv; + const void *engn; + u64 object; + struct nvkm_client *client; + struct nvkm_object *parent; + struct nvkm_engine *engine; }; #define nv_oclass(o) nv_object(o)->oclass @@ -87,7 +144,6 @@ struct nvkm_omthds { int (*call)(struct nvkm_object *, u32, void *, u32); }; -struct nvkm_event; struct nvkm_ofuncs { int (*ctor)(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *data, u32 size, diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index 1ca5479ee38b2..bc4b3c2d075e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -182,20 +182,20 @@ u32 _nvkm_gpuobj_rd32(struct nvkm_object *object, u64 addr) { struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - struct nvkm_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent); + u32 data; if (gpuobj->node) addr += gpuobj->node->offset; - return pfuncs->rd32(gpuobj->parent, addr); + nvkm_object_rd32(gpuobj->parent, addr, &data); + return data; } void _nvkm_gpuobj_wr32(struct nvkm_object *object, u64 addr, u32 data) { struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - struct nvkm_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent); if (gpuobj->node) addr += gpuobj->node->offset; - pfuncs->wr32(gpuobj->parent, addr, data); + nvkm_object_wr32(gpuobj->parent, addr, data); } static struct nvkm_oclass diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 7a15b15bfce0a..6e5ff942a6da3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -152,6 +152,8 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) if (ret) goto fail_ctor; + object->handle = _handle; + ret = nvkm_object_inc(object); if (ret) goto fail_init; @@ -205,7 +207,6 @@ static int nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size) { struct nvkm_object *object = handle->object; - struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; union { struct nvif_ioctl_mthd_v0 v0; } *args = data; @@ -215,8 +216,7 @@ nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size) if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "mthd vers %d mthd %02x\n", args->v0.version, args->v0.method); - if (ret = -ENODEV, ofuncs->mthd) - ret = ofuncs->mthd(object, args->v0.method, data, size); + ret = nvkm_object_mthd(object, args->v0.method, data, size); } return ret; @@ -296,7 +296,6 @@ static int nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size) { struct nvkm_object *object = handle->object; - struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; union { struct nvif_ioctl_map_v0 v0; } *args = data; @@ -305,10 +304,8 @@ nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size) nvif_ioctl(object, "map size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(object, "map vers %d\n", args->v0.version); - if (ret = -ENODEV, ofuncs->map) { - ret = ofuncs->map(object, &args->v0.handle, - &args->v0.length); - } + ret = nvkm_object_map(object, &args->v0.handle, + &args->v0.length); } return ret; @@ -335,7 +332,6 @@ static int nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size) { struct nvkm_object *object = handle->object; - struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs; union { struct nvif_ioctl_ntfy_new_v0 v0; } *args = data; @@ -346,8 +342,7 @@ nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size) if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "ntfy new vers %d event %02x\n", args->v0.version, args->v0.event); - if (ret = -ENODEV, ofuncs->ntfy) - ret = ofuncs->ntfy(object, args->v0.event, &event); + ret = nvkm_object_ntfy(object, args->v0.event, &event); if (ret == 0) { ret = nvkm_client_notify_new(object, event, data, size); if (ret >= 0) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index 1c117f0a7245d..0abee78168746 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -24,75 +24,232 @@ #include #include +int +nvkm_object_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + if (object->oclass) { + if (object->oclass->ofuncs->mthd) + return object->oclass->ofuncs->mthd(object, mthd, data, size); + return -ENODEV; + } + if (likely(object->func->mthd)) + return object->func->mthd(object, mthd, data, size); + return -ENODEV; +} + +int +nvkm_object_ntfy(struct nvkm_object *object, u32 mthd, + struct nvkm_event **pevent) +{ + if (object->oclass) { + if (object->oclass->ofuncs->ntfy) + return object->oclass->ofuncs->ntfy(object, mthd, pevent); + return -ENODEV; + } + if (likely(object->func->ntfy)) + return object->func->ntfy(object, mthd, pevent); + return -ENODEV; +} + +int +nvkm_object_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + if (object->oclass) { + if (object->oclass->ofuncs->map) + return object->oclass->ofuncs->map(object, addr, size); + return -ENODEV; + } + if (likely(object->func->map)) + return object->func->map(object, addr, size); + return -ENODEV; +} + int nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data) { - const struct nvkm_oclass *oclass = object->oclass; - if (oclass->ofuncs && oclass->ofuncs->rd08) { - *data = oclass->ofuncs->rd08(object, addr); - return 0; + if (object->oclass) { + if (object->oclass->ofuncs->rd08) { + *data = object->oclass->ofuncs->rd08(object, addr); + return 0; + } + *data = 0x00; + return -ENODEV; } - *data = 0x00; + if (likely(object->func->rd08)) + return object->func->rd08(object, addr, data); return -ENODEV; } int nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data) { - const struct nvkm_oclass *oclass = object->oclass; - if (oclass->ofuncs && oclass->ofuncs->rd16) { - *data = oclass->ofuncs->rd16(object, addr); - return 0; + if (object->oclass) { + if (object->oclass->ofuncs->rd16) { + *data = object->oclass->ofuncs->rd16(object, addr); + return 0; + } + *data = 0x0000; + return -ENODEV; } - *data = 0x0000; + if (likely(object->func->rd16)) + return object->func->rd16(object, addr, data); return -ENODEV; } int nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data) { - const struct nvkm_oclass *oclass = object->oclass; - if (oclass->ofuncs && oclass->ofuncs->rd32) { - *data = oclass->ofuncs->rd32(object, addr); - return 0; + if (object->oclass) { + if (object->oclass->ofuncs->rd32) { + *data = object->oclass->ofuncs->rd32(object, addr); + return 0; + } + *data = 0x00000000; + return -ENODEV; } - *data = 0x0000; + if (likely(object->func->rd32)) + return object->func->rd32(object, addr, data); return -ENODEV; } int nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data) { - const struct nvkm_oclass *oclass = object->oclass; - if (oclass->ofuncs && oclass->ofuncs->wr08) { - oclass->ofuncs->wr08(object, addr, data); - return 0; + if (object->oclass) { + if (object->oclass->ofuncs->wr08) { + object->oclass->ofuncs->wr08(object, addr, data); + return 0; + } + return -ENODEV; } + if (likely(object->func->wr08)) + return object->func->wr08(object, addr, data); return -ENODEV; } int nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data) { - const struct nvkm_oclass *oclass = object->oclass; - if (oclass->ofuncs && oclass->ofuncs->wr16) { - oclass->ofuncs->wr16(object, addr, data); - return 0; + if (object->oclass) { + if (object->oclass->ofuncs->wr16) { + object->oclass->ofuncs->wr16(object, addr, data); + return 0; + } + return -ENODEV; } + if (likely(object->func->wr16)) + return object->func->wr16(object, addr, data); return -ENODEV; } int nvkm_object_wr32(struct nvkm_object *object, u64 addr, u32 data) { - const struct nvkm_oclass *oclass = object->oclass; - if (oclass->ofuncs && oclass->ofuncs->wr32) { - oclass->ofuncs->wr32(object, addr, data); - return 0; + if (object->oclass) { + if (object->oclass->ofuncs->wr32) { + object->oclass->ofuncs->wr32(object, addr, data); + return 0; + } + return -ENODEV; } + if (likely(object->func->wr32)) + return object->func->wr32(object, addr, data); return -ENODEV; } +int +nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj, + int align, struct nvkm_gpuobj **pgpuobj) +{ + if (object->oclass) + return -ENODEV; + if (object->func->bind) + return object->func->bind(object, gpuobj, align, pgpuobj); + return -ENODEV; +} + +int +nvkm_object_fini(struct nvkm_object *object, bool suspend) +{ + if (object->oclass) + return object->oclass->ofuncs->fini(object, suspend); + if (object->func->fini) + return object->func->fini(object, suspend); + return 0; +} + +int +nvkm_object_init(struct nvkm_object *object) +{ + if (object->oclass) + return object->oclass->ofuncs->init(object); + if (object->func->init) + return object->func->init(object); + return 0; +} + +static void +nvkm_object_del(struct nvkm_object **pobject) +{ + struct nvkm_object *object = *pobject; + + if (object && object->oclass) { + object->oclass->ofuncs->dtor(object); + return; + } + + if (object && !WARN_ON(!object->func)) { + if (object->func->dtor) + *pobject = object->func->dtor(object); + kfree(*pobject); + *pobject = NULL; + } +} + +void +nvkm_object_ctor(const struct nvkm_object_func *func, + const struct nvkm_oclass *oclass, struct nvkm_object *object) +{ + object->func = func; + object->client = oclass->client; + object->engine = oclass->engine; + object->oclass_name = oclass->base.oclass; + object->handle = oclass->handle; + object->parent = oclass->parent; + atomic_set(&object->refcount, 1); + atomic_set(&object->usecount, 0); +#ifdef NVKM_OBJECT_MAGIC + object->_magic = NVKM_OBJECT_MAGIC; +#endif +} + +int +nvkm_object_new_(const struct nvkm_object_func *func, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + if (size == 0) { + if (!(*pobject = kzalloc(sizeof(**pobject), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(func, oclass, *pobject); + return 0; + } + return -ENOSYS; +} + +static const struct nvkm_object_func +nvkm_object_func = { +}; + +int +nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + const struct nvkm_object_func *func = + oclass->base.func ? oclass->base.func : &nvkm_object_func; + return nvkm_object_new_(func, oclass, data, size, pobject); +} + int nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 pclass, @@ -182,12 +339,6 @@ nvkm_object_old(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -static void -nvkm_object_dtor(struct nvkm_object *object) -{ - nv_ofuncs(object)->dtor(object); -} - void nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref) { @@ -198,7 +349,7 @@ nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref) if (*ref) { int dead = atomic_dec_and_test(&(*ref)->refcount); if (dead) - nvkm_object_dtor(*ref); + nvkm_object_del(ref); } *ref = obj; @@ -227,7 +378,7 @@ nvkm_object_inc(struct nvkm_object *object) goto fail_engine; } - ret = nv_ofuncs(object)->init(object); + ret = nvkm_object_init(object); atomic_set(&object->usecount, 1); if (ret) goto fail_self; @@ -251,7 +402,7 @@ fail_parent: static int nvkm_object_decf(struct nvkm_object *object) { - nv_ofuncs(object)->fini(object, false); + nvkm_object_fini(object, false); atomic_set(&object->usecount, 0); if (object->engine) { @@ -271,7 +422,7 @@ nvkm_object_decs(struct nvkm_object *object) { int ret; - ret = nv_ofuncs(object)->fini(object, true); + ret = nvkm_object_fini(object, true); atomic_set(&object->usecount, 0); if (ret) return ret; @@ -300,7 +451,7 @@ fail_parent: } fail_engine: - nv_ofuncs(object)->init(object); + nvkm_object_init(object); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index c61bb0fa93f66..4717af0800e91 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -102,7 +102,7 @@ nvkm_ramht_new(struct nvkm_object *parent, struct nvkm_object *pargpu, int ret; ret = nvkm_gpuobj_create(parent, parent->engine ? - &parent->engine->subdev.object : parent, /* engine->subdev.object : NULL, /* fini(&subdev->object, false); + nvkm_object_fini(&subdev->object, false); nvkm_trace(subdev, "reset\n"); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 1fa38227059f8..dd7fe30edf46b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -451,8 +451,8 @@ gf100_fifo_recover_work(struct work_struct *work) for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { if ((engine = (void *)nvkm_engine(fifo, engn))) { - nv_ofuncs(engine)->fini(engine, false); - WARN_ON(nv_ofuncs(engine)->init(engine)); + nvkm_object_fini(engine, false); + WARN_ON(nvkm_object_init(engine)); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 3562b791162f9..9d75dbaa01c0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -497,8 +497,8 @@ gk104_fifo_recover_work(struct work_struct *work) for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { if ((engine = (void *)nvkm_engine(fifo, engn))) { - nv_ofuncs(engine)->fini(engine, false); - WARN_ON(nv_ofuncs(engine)->init(engine)); + nvkm_object_fini(engine, false); + WARN_ON(nvkm_object_init(engine)); } gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn)); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index bbcc3080a478f..bf40509cda94f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -117,7 +117,7 @@ nv50_devinit_init(struct nvkm_object *object) * the vbios engineers didn't make the scripts just work... */ if (init->base.post && ibus) - nv_ofuncs(ibus)->init(nv_object(ibus)); + nvkm_object_init(&ibus->object); ret = nvkm_devinit_init(&init->base); if (ret) -- GitLab From f0290215c44370ff5d55c01a13dc5a44a1f86efa Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5486/7006] drm/nouveau/subdev: implement support for new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/object.h | 3 - .../drm/nouveau/include/nvkm/core/subdev.h | 30 ++- drivers/gpu/drm/nouveau/nvkm/core/engctx.c | 8 +- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 189 +++++++++++++++++- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 2 +- 6 files changed, 217 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 84040a336036b..3366ec59a64ec 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -106,13 +106,10 @@ struct nvkm_sclass { struct nvkm_object **); }; -/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in - * ".data". */ struct nvkm_oclass { s32 handle; struct nvkm_ofuncs * const ofuncs; struct nvkm_omthds * const omthds; - struct lock_class_key lock_class_key; int (*ctor)(const struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index d3e08bf8d977e..01f2f71e6112e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -7,17 +7,37 @@ struct nvkm_subdev { struct nvkm_object object; - + const struct nvkm_subdev_func *func; struct nvkm_device *device; + int index; + u32 pmc_enable; struct mutex mutex; - const char *name, *sname; u32 debug; + bool oneinit; + + void (*intr)(struct nvkm_subdev *); u32 unit; +}; +struct nvkm_subdev_func { + void *(*dtor)(struct nvkm_subdev *); + int (*preinit)(struct nvkm_subdev *); + int (*oneinit)(struct nvkm_subdev *); + int (*init)(struct nvkm_subdev *); + int (*fini)(struct nvkm_subdev *, bool suspend); void (*intr)(struct nvkm_subdev *); }; +extern const char *nvkm_subdev_name[64]; +void nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *, + int index, u32 pmc_enable, struct nvkm_subdev *); +void nvkm_subdev_del(struct nvkm_subdev **); +int nvkm_subdev_preinit(struct nvkm_subdev *); +int nvkm_subdev_init(struct nvkm_subdev *); +int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend); +void nvkm_subdev_intr(struct nvkm_subdev *); + static inline struct nvkm_subdev * nv_subdev(void *obj) { @@ -55,8 +75,10 @@ int _nvkm_subdev_fini(struct nvkm_object *, bool suspend); /* subdev logging */ #define nvkm_printk_(s,l,p,f,a...) do { \ struct nvkm_subdev *_subdev = (s); \ - if (_subdev->debug >= (l)) \ - dev_##p(_subdev->device->dev, "%s: "f, _subdev->sname, ##a); \ + if (_subdev->debug >= (l)) { \ + dev_##p(_subdev->device->dev, "%s: "f, \ + nvkm_subdev_name[_subdev->index], ##a); \ + } \ } while(0) #define nvkm_printk(s,l,p,f,a...) nvkm_printk_((s), NV_DBG_##l, p, f, ##a) #define nvkm_fatal(s,f,a...) nvkm_printk((s), FATAL, crit, f, ##a) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c index fc2a2cb0a617f..c9c5787493382 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c @@ -144,11 +144,11 @@ nvkm_engctx_init(struct nvkm_engctx *engctx) if (ret) { nvkm_error(pardev, "failed to attach %s context, %d\n", - subdev->name, ret); + nvkm_subdev_name[subdev->index], ret); return ret; } - nvkm_trace(pardev, "attached %s context\n", subdev->name); + nvkm_trace(pardev, "attached %s context\n", nvkm_subdev_name[subdev->index]); return 0; } @@ -171,11 +171,11 @@ nvkm_engctx_fini(struct nvkm_engctx *engctx, bool suspend) if (ret) { nvkm_error(pardev, "failed to detach %s context, %d\n", - subdev->name, ret); + nvkm_subdev_name[subdev->index], ret); return ret; } - nvkm_trace(pardev, "detached %s context\n", subdev->name); + nvkm_trace(pardev, "detached %s context\n", nvkm_subdev_name[subdev->index]); return nvkm_gpuobj_fini(&engctx->gpuobj, suspend); } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 9e9e0cadaefcc..5af13d8be2f58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -25,6 +25,186 @@ #include #include +static struct lock_class_key nvkm_subdev_lock_class[NVDEV_SUBDEV_NR]; + +const char * +nvkm_subdev_name[64] = { + [NVDEV_SUBDEV_BAR ] = "bar", + [NVDEV_SUBDEV_VBIOS ] = "bios", + [NVDEV_SUBDEV_BUS ] = "bus", + [NVDEV_SUBDEV_CLK ] = "clk", + [NVDEV_SUBDEV_DEVINIT] = "devinit", + [NVDEV_SUBDEV_FB ] = "fb", + [NVDEV_SUBDEV_FUSE ] = "fuse", + [NVDEV_SUBDEV_GPIO ] = "gpio", + [NVDEV_SUBDEV_I2C ] = "i2c", + [NVDEV_SUBDEV_IBUS ] = "priv", + [NVDEV_SUBDEV_INSTMEM] = "imem", + [NVDEV_SUBDEV_LTC ] = "ltc", + [NVDEV_SUBDEV_MC ] = "mc", + [NVDEV_SUBDEV_MMU ] = "mmu", + [NVDEV_SUBDEV_MXM ] = "mxm", + [NVDEV_SUBDEV_PMU ] = "pmu", + [NVDEV_SUBDEV_THERM ] = "therm", + [NVDEV_SUBDEV_TIMER ] = "tmr", + [NVDEV_SUBDEV_VOLT ] = "volt", + [NVDEV_ENGINE_BSP ] = "bsp", + [NVDEV_ENGINE_CE0 ] = "ce0", + [NVDEV_ENGINE_CE1 ] = "ce1", + [NVDEV_ENGINE_CE2 ] = "ce2", + [NVDEV_ENGINE_CIPHER ] = "cipher", + [NVDEV_ENGINE_DISP ] = "disp", + [NVDEV_ENGINE_DMAOBJ ] = "dma", + [NVDEV_ENGINE_FIFO ] = "fifo", + [NVDEV_ENGINE_GR ] = "gr", + [NVDEV_ENGINE_IFB ] = "ifb", + [NVDEV_ENGINE_ME ] = "me", + [NVDEV_ENGINE_MPEG ] = "mpeg", + [NVDEV_ENGINE_MSENC ] = "msenc", + [NVDEV_ENGINE_MSPDEC ] = "mspdec", + [NVDEV_ENGINE_MSPPP ] = "msppp", + [NVDEV_ENGINE_MSVLD ] = "msvld", + [NVDEV_ENGINE_PM ] = "pm", + [NVDEV_ENGINE_SEC ] = "sec", + [NVDEV_ENGINE_SW ] = "sw", + [NVDEV_ENGINE_VIC ] = "vic", + [NVDEV_ENGINE_VP ] = "vp", +}; + +void +nvkm_subdev_intr(struct nvkm_subdev *subdev) +{ + if (subdev->func->intr) + subdev->func->intr(subdev); +} + +int +nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_device *device = subdev->device; + const char *action = suspend ? "suspend" : "fini"; + u32 pmc_enable = subdev->pmc_enable; + s64 time; + + nvkm_trace(subdev, "%s running...\n", action); + time = ktime_to_us(ktime_get()); + + if (subdev->func->fini) { + int ret = subdev->func->fini(subdev, suspend); + if (ret) { + nvkm_error(subdev, "%s failed, %d\n", action, ret); + if (suspend) + return ret; + } + } + + if (pmc_enable) { + nvkm_mask(device, 0x000200, pmc_enable, 0x00000000); + nvkm_mask(device, 0x000200, pmc_enable, pmc_enable); + nvkm_rd32(device, 0x000200); + } + + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "%s completed in %lldus\n", action, time); + return 0; +} + +int +nvkm_subdev_preinit(struct nvkm_subdev *subdev) +{ + s64 time; + + nvkm_trace(subdev, "preinit running...\n"); + time = ktime_to_us(ktime_get()); + + if (subdev->func->preinit) { + int ret = subdev->func->preinit(subdev); + if (ret) { + nvkm_error(subdev, "preinit failed, %d\n", ret); + return ret; + } + } + + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "preinit completed in %lldus\n", time); + return 0; +} + +int +nvkm_subdev_init(struct nvkm_subdev *subdev) +{ + s64 time; + int ret; + + nvkm_trace(subdev, "init running...\n"); + time = ktime_to_us(ktime_get()); + + if (subdev->func->oneinit && !subdev->oneinit) { + s64 time; + nvkm_trace(subdev, "one-time init running...\n"); + time = ktime_to_us(ktime_get()); + ret = subdev->func->oneinit(subdev); + if (ret) { + nvkm_error(subdev, "one-time init failed, %d\n", ret); + return ret; + } + + subdev->oneinit = true; + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "one-time init completed in %lldus\n", time); + } + + if (subdev->func->init) { + ret = subdev->func->init(subdev); + if (ret) { + nvkm_error(subdev, "init failed, %d\n", ret); + return ret; + } + } + + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "init completed in %lldus\n", time); + return 0; +} + +void +nvkm_subdev_del(struct nvkm_subdev **psubdev) +{ + struct nvkm_subdev *subdev = *psubdev; + s64 time; + if (subdev && !WARN_ON(!subdev->func)) { + nvkm_trace(subdev, "destroy running...\n"); + time = ktime_to_us(ktime_get()); + if (subdev->func->dtor) + *psubdev = subdev->func->dtor(subdev); + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "destroy completed in %lldus\n", time); + kfree(*psubdev); + *psubdev = NULL; + } +} + +static const struct nvkm_object_func +nvkm_subdev_func = { +}; + +void +nvkm_subdev_ctor(const struct nvkm_subdev_func *func, + struct nvkm_device *device, int index, u32 pmc_enable, + struct nvkm_subdev *subdev) +{ + const char *name = nvkm_subdev_name[index]; + struct nvkm_oclass hack = {}; + nvkm_object_ctor(&nvkm_subdev_func, &hack, &subdev->object); + subdev->func = func; + subdev->device = device; + subdev->index = index; + subdev->pmc_enable = pmc_enable; + + __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[index]); + subdev->debug = nvkm_dbgopt(device->dbgopt, name); +} + struct nvkm_subdev * nvkm_subdev(void *obj, int idx) { @@ -103,6 +283,8 @@ nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine, const char *subname, const char *sysname, int size, void **pobject) { + const int subidx = oclass->handle & 0xff; + const char *name = nvkm_subdev_name[subidx]; struct nvkm_subdev *subdev; int ret; @@ -112,13 +294,12 @@ nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key); - subdev->name = subname; - subdev->sname = sysname; + __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[subidx]); + subdev->index = subidx; if (parent) { struct nvkm_device *device = nv_device(parent); - subdev->debug = nvkm_dbgopt(device->dbgopt, subname); + subdev->debug = nvkm_dbgopt(device->dbgopt, name); subdev->device = device; } else { subdev->device = nv_device(subdev); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index dd7fe30edf46b..975a2547b8cd7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -471,7 +471,7 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, unsigned long flags; nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", - engine->subdev.name, chid); + nvkm_subdev_name[engine->subdev.index], chid); nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); chan->state = KILLED; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 9d75dbaa01c0b..216205cdf115e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -517,7 +517,7 @@ gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, unsigned long flags; nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", - nv_subdev(engine)->name, chid); + nvkm_subdev_name[nv_subdev(engine)->index], chid); nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); chan->state = KILLED; -- GitLab From 168c2e213d3a9b605856d3676d9e93733c8b37d3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:16 +1000 Subject: [PATCH 5487/7006] drm/nouveau/engine: implement support for new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/engine.h | 37 +++++ drivers/gpu/drm/nouveau/nvkm/core/engine.c | 127 ++++++++++++++++++ 2 files changed, 164 insertions(+) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index f98980e15f264..8c67d755e5c1e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -1,12 +1,18 @@ #ifndef __NVKM_ENGINE_H__ #define __NVKM_ENGINE_H__ #include +struct nvkm_device_oclass; /*XXX: DEV!ENG */ +struct nvkm_fifo_chan; #define NV_ENGINE_(eng,var) (((var) << 8) | (eng)) #define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var)) struct nvkm_engine { struct nvkm_subdev subdev; + const struct nvkm_engine_func *func; + + int usecount; + struct nvkm_oclass *cclass; struct nvkm_oclass *sclass; @@ -17,6 +23,37 @@ struct nvkm_engine { int (*tlb_flush)(struct nvkm_engine *); }; +struct nvkm_engine_func { + void *(*dtor)(struct nvkm_engine *); + int (*oneinit)(struct nvkm_engine *); + int (*init)(struct nvkm_engine *); + int (*fini)(struct nvkm_engine *, bool suspend); + void (*intr)(struct nvkm_engine *); + + struct { + int (*sclass)(struct nvkm_oclass *, int index, + const struct nvkm_device_oclass **); + } base; + + struct { + int (*cclass)(struct nvkm_fifo_chan *, + const struct nvkm_oclass *, + struct nvkm_object **); + int (*sclass)(struct nvkm_oclass *, int index); + } fifo; + + struct nvkm_sclass sclass[]; +}; + +int nvkm_engine_ctor(const struct nvkm_engine_func *, struct nvkm_device *, + int index, u32 pmc_enable, bool enable, + struct nvkm_engine *); +int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *, + int index, u32 pmc_enable, bool enable, + struct nvkm_engine **); +struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *); +void nvkm_engine_unref(struct nvkm_engine **); + static inline struct nvkm_engine * nv_engine(void *obj) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index a6294e86d4676..07559e7c4c4c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -25,6 +25,133 @@ #include #include +void +nvkm_engine_unref(struct nvkm_engine **pengine) +{ + struct nvkm_engine *engine = *pengine; + if (engine) { + mutex_lock(&engine->subdev.mutex); + if (--engine->usecount == 0) + nvkm_subdev_fini(&engine->subdev, false); + mutex_unlock(&engine->subdev.mutex); + *pengine = NULL; + } +} + +struct nvkm_engine * +nvkm_engine_ref(struct nvkm_engine *engine) +{ + if (engine) { + mutex_lock(&engine->subdev.mutex); + if (++engine->usecount == 1) { + int ret = nvkm_subdev_init(&engine->subdev); + if (ret) { + engine->usecount--; + mutex_unlock(&engine->subdev.mutex); + return ERR_PTR(ret); + } + } + mutex_unlock(&engine->subdev.mutex); + } + return engine; +} + +static void +nvkm_engine_intr(struct nvkm_subdev *obj) +{ + struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + if (engine->func->intr) + engine->func->intr(engine); +} + +static int +nvkm_engine_fini(struct nvkm_subdev *obj, bool suspend) +{ + struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + if (engine->func->fini) + return engine->func->fini(engine, suspend); + return 0; +} + +static int +nvkm_engine_init(struct nvkm_subdev *obj) +{ + struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + struct nvkm_subdev *subdev = &engine->subdev; + int ret = 0; + s64 time; + + if (!engine->usecount) { + nvkm_trace(subdev, "init skipped, engine has no users\n"); + return ret; + } + + if (engine->func->oneinit && !engine->subdev.oneinit) { + nvkm_trace(subdev, "one-time init running...\n"); + time = ktime_to_us(ktime_get()); + ret = engine->func->oneinit(engine); + if (ret) { + nvkm_trace(subdev, "one-time init failed, %d\n", ret); + return ret; + } + + engine->subdev.oneinit = true; + time = ktime_to_us(ktime_get()) - time; + nvkm_trace(subdev, "one-time init completed in %lldus\n", time); + } + + if (engine->func->init) + ret = engine->func->init(engine); + + return ret; +} + +static void * +nvkm_engine_dtor(struct nvkm_subdev *obj) +{ + struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + if (engine->func->dtor) + return engine->func->dtor(engine); + return engine; +} + +static const struct nvkm_subdev_func +nvkm_engine_func = { + .dtor = nvkm_engine_dtor, + .init = nvkm_engine_init, + .fini = nvkm_engine_fini, + .intr = nvkm_engine_intr, +}; + +int +nvkm_engine_ctor(const struct nvkm_engine_func *func, + struct nvkm_device *device, int index, u32 pmc_enable, + bool enable, struct nvkm_engine *engine) +{ + nvkm_subdev_ctor(&nvkm_engine_func, device, index, + pmc_enable, &engine->subdev); + engine->func = func; + + if (!nvkm_boolopt(device->cfgopt, nvkm_subdev_name[index], enable)) { + nvkm_debug(&engine->subdev, "disabled\n"); + return -ENODEV; + } + + spin_lock_init(&engine->lock); + return 0; +} + +int +nvkm_engine_new_(const struct nvkm_engine_func *func, + struct nvkm_device *device, int index, u32 pmc_enable, + bool enable, struct nvkm_engine **pengine) +{ + if (!(*pengine = kzalloc(sizeof(**pengine), GFP_KERNEL))) + return -ENOMEM; + return nvkm_engine_ctor(func, device, index, pmc_enable, + enable, *pengine); +} + struct nvkm_engine * nvkm_engine(void *obj, int idx) { -- GitLab From 7974dd1bdb43aaf5b45a915c6b439d11733450fc Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5488/7006] drm/nouveau/device: separate construction of pci/tegra devices Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/os.h | 3 +- .../drm/nouveau/include/nvkm/core/client.h | 4 +- .../drm/nouveau/include/nvkm/core/device.h | 30 +++-- .../gpu/drm/nouveau/include/nvkm/core/pci.h | 14 +++ .../gpu/drm/nouveau/include/nvkm/core/tegra.h | 14 +++ drivers/gpu/drm/nouveau/nouveau_drm.c | 15 +-- .../gpu/drm/nouveau/nvkm/engine/device/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 104 ++++++++++++------ .../gpu/drm/nouveau/nvkm/engine/device/pci.c | 100 +++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 9 ++ .../drm/nouveau/nvkm/engine/device/tegra.c | 66 +++++++++++ 11 files changed, 307 insertions(+), 54 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/pci.h create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h index bdd05ee7ec72e..54492cb5011be 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/os.h +++ b/drivers/gpu/drm/nouveau/include/nvif/os.h @@ -27,6 +27,8 @@ #include +#include + #ifndef ioread32_native #ifdef __BIG_ENDIAN #define ioread16_native ioread16be @@ -40,5 +42,4 @@ #define iowrite32_native iowrite32 #endif /* def __BIG_ENDIAN else */ #endif /* !ioread32_native */ - #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 977c8a85e1199..dd0db88f8213f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -28,7 +28,9 @@ nvkm_client(void *obj) struct nvkm_object *client = nv_object(obj); while (client && client->parent) client = client->parent; - return (void *)client; + if (client && nv_iclass(client, NV_CLIENT_CLASS)) + return (void *)client; + return NULL; } int nvkm_client_new(const char *name, u64 device, const char *cfg, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 875c247d4cfc4..eb843e3ff0055 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -65,22 +65,25 @@ enum nvkm_devidx { struct nvkm_device { struct nvkm_engine engine; + const struct nvkm_device_func *func; + const struct nvkm_device_quirk *quirk; + struct device *dev; + u64 handle; + const char *name; + const char *cfgopt; + const char *dbgopt; + struct list_head head; struct mutex mutex; int refcount; struct pci_dev *pdev; struct platform_device *platformdev; - struct device *dev; - u64 handle; void __iomem *pri; struct nvkm_event event; - const char *cfgopt; - const char *dbgopt; - const char *name; const char *cname; u64 disable_mask; @@ -150,6 +153,17 @@ struct nvkm_device { struct nouveau_platform_gpu *gpu; }; +struct nvkm_device_func { + struct nvkm_device_pci *(*pci)(struct nvkm_device *); + struct nvkm_device_tegra *(*tegra)(struct nvkm_device *); + void *(*dtor)(struct nvkm_device *); + int (*preinit)(struct nvkm_device *); + void (*fini)(struct nvkm_device *, bool suspend); +}; + +struct nvkm_device_quirk { +}; + struct nvkm_device *nvkm_device_find(u64 name); int nvkm_device_list(u64 *name, int size); @@ -214,13 +228,7 @@ enum nv_bus_type { extern struct nvkm_ofuncs nvkm_udevice_ofuncs; -int nvkm_device_new(void *, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - bool detect, bool mmio, u64 subdev_mask, - struct nvkm_device **); void nvkm_device_del(struct nvkm_device **); -int nvkm_device_init(struct nvkm_device *); -int nvkm_device_fini(struct nvkm_device *, bool suspend); /* device logging */ #define nvdev_printk_(d,l,p,f,a...) do { \ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h new file mode 100644 index 0000000000000..78d41be20b8ce --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/pci.h @@ -0,0 +1,14 @@ +#ifndef __NVKM_DEVICE_PCI_H__ +#define __NVKM_DEVICE_PCI_H__ +#include + +struct nvkm_device_pci { + struct nvkm_device device; + struct pci_dev *pdev; + bool suspend; +}; + +int nvkm_device_pci_new(struct pci_dev *, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **); +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h new file mode 100644 index 0000000000000..162986e7f8c40 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h @@ -0,0 +1,14 @@ +#ifndef __NVKM_DEVICE_TEGRA_H__ +#define __NVKM_DEVICE_TEGRA_H__ +#include + +struct nvkm_device_tegra { + struct nvkm_device device; + struct platform_device *pdev; +}; + +int nvkm_device_tegra_new(struct platform_device *, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **); +#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 37dbd5e1c08f0..e638ae7c00c25 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -32,9 +32,10 @@ #include "drmP.h" #include "drm_crtc_helper.h" -#include #include #include +#include +#include #include "nouveau_drm.h" #include "nouveau_dma.h" @@ -326,9 +327,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev, remove_conflicting_framebuffers(aper, "nouveaufb", boot); kfree(aper); - ret = nvkm_device_new(pdev, NVKM_BUS_PCI, nouveau_pci_name(pdev), - pci_name(pdev), nouveau_config, nouveau_debug, - true, true, ~0ULL, &device); + ret = nvkm_device_pci_new(pdev, nouveau_config, nouveau_debug, + true, true, ~0ULL, &device); if (ret) return ret; @@ -1036,11 +1036,8 @@ nouveau_platform_device_create(struct platform_device *pdev, struct drm_device *drm; int err; - err = nvkm_device_new(pdev, NVKM_BUS_PLATFORM, - nouveau_platform_name(pdev), - dev_name(&pdev->dev), nouveau_config, - nouveau_debug, true, true, ~0ULL, - pdevice); + err = nvkm_device_tegra_new(pdev, nouveau_config, nouveau_debug, + true, true, ~0ULL, pdevice); if (err) goto err_free; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild index 47c8fe8f9e3e7..91110cd2562ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild @@ -1,6 +1,8 @@ nvkm-y += nvkm/engine/device/acpi.o nvkm-y += nvkm/engine/device/base.o nvkm-y += nvkm/engine/device/ctrl.o +nvkm-y += nvkm/engine/device/pci.o +nvkm-y += nvkm/engine/device/tegra.o nvkm-y += nvkm/engine/device/user.o nvkm-y += nvkm/engine/device/nv04.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b7892e6f080b4..c7d8e2902c6c5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -32,19 +32,25 @@ static DEFINE_MUTEX(nv_devices_mutex); static LIST_HEAD(nv_devices); -struct nvkm_device * -nvkm_device_find(u64 name) +static struct nvkm_device * +nvkm_device_find_locked(u64 handle) { - struct nvkm_device *device, *match = NULL; - mutex_lock(&nv_devices_mutex); + struct nvkm_device *device; list_for_each_entry(device, &nv_devices, head) { - if (device->handle == name) { - match = device; - break; - } + if (device->handle == handle) + return device; } + return NULL; +} + +struct nvkm_device * +nvkm_device_find(u64 handle) +{ + struct nvkm_device *device; + mutex_lock(&nv_devices_mutex); + device = nvkm_device_find_locked(handle); mutex_unlock(&nv_devices_mutex); - return match; + return device; } int @@ -62,6 +68,7 @@ nvkm_device_list(u64 *name, int size) } #include +#include struct nvkm_device * nv_device(void *obj) @@ -70,7 +77,8 @@ nv_device(void *obj) if (device->engine == NULL) { while (device && device->parent) { - if (nv_mclass(device) == 0x0080) { + if (!nv_iclass(device, NV_SUBDEV_CLASS) && + device->parent == &nvkm_client(device)->namedb.parent.object) { struct { struct nvkm_parent base; struct nvkm_device *device; @@ -125,6 +133,9 @@ nvkm_device_fini(struct nvkm_device *device, bool suspend) } ret = nvkm_acpi_fini(device, suspend); + + if (device->func->fini) + device->func->fini(device, suspend); fail: for (; ret && i < NVDEV_SUBDEV_NR; i++) { if ((subdev = device->subdev[i])) { @@ -140,12 +151,40 @@ fail: return ret; } +int +nvkm_device_preinit(struct nvkm_device *device) +{ + int ret; + s64 time; + + nvdev_trace(device, "preinit running...\n"); + time = ktime_to_us(ktime_get()); + + if (device->func->preinit) { + ret = device->func->preinit(device); + if (ret) + goto fail; + } + + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "preinit completed in %lldus\n", time); + return 0; + +fail: + nvdev_error(device, "preinit failed with %d\n", ret); + return ret; +} + int nvkm_device_init(struct nvkm_device *device) { struct nvkm_object *subdev; int ret, i = 0, c; + ret = nvkm_device_preinit(device); + if (ret) + return ret; + ret = nvkm_acpi_init(device); if (ret) goto fail; @@ -287,12 +326,6 @@ nv_device_get_irq(struct nvkm_device *device, bool stall) } } -static struct nvkm_oclass -nvkm_device_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - }, -}; - void nvkm_device_del(struct nvkm_device **pdevice) { @@ -308,20 +341,28 @@ nvkm_device_del(struct nvkm_device **pdevice) if (device->pri) iounmap(device->pri); list_del(&device->head); + + if (device->func->dtor) + *pdevice = device->func->dtor(device); mutex_unlock(&nv_devices_mutex); - nvkm_engine_destroy(&device->engine); + kfree(*pdevice); *pdevice = NULL; } } +static const struct nvkm_engine_func +nvkm_device_func = { +}; + int -nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, - const char *sname, const char *cfg, const char *dbg, - bool detect, bool mmio, u64 subdev_mask, - struct nvkm_device **pdevice) +nvkm_device_ctor(const struct nvkm_device_func *func, + const struct nvkm_device_quirk *quirk, + void *dev, enum nv_bus_type type, u64 handle, + const char *name, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device *device) { - struct nvkm_device *device; u64 mmio_base, mmio_size; u32 boot0, strap; void __iomem *map; @@ -329,17 +370,17 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, int i; mutex_lock(&nv_devices_mutex); - list_for_each_entry(device, &nv_devices, head) { - if (device->handle == name) - goto done; - } + if (nvkm_device_find_locked(handle)) + goto done; - ret = nvkm_engine_create(NULL, NULL, &nvkm_device_oclass, true, - "DEVICE", "device", &device); - *pdevice = device; + ret = nvkm_engine_ctor(&nvkm_device_func, device, 0, 0, + true, &device->engine); + device->engine.subdev.object.parent = NULL; + device->func = func; if (ret) goto done; + device->quirk = quirk; switch (type) { case NVKM_BUS_PCI: device->pdev = dev; @@ -350,12 +391,11 @@ nvkm_device_new(void *dev, enum nv_bus_type type, u64 name, device->dev = &device->platformdev->dev; break; } - device->handle = name; + device->handle = handle; device->cfgopt = cfg; device->dbgopt = dbg; - device->name = sname; + device->name = name; - nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE"); list_add_tail(&device->head, &nv_devices); ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c new file mode 100644 index 0000000000000..1a1d1e584a7f9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -0,0 +1,100 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include +#include "priv.h" + +static struct nvkm_device_pci * +nvkm_device_pci(struct nvkm_device *device) +{ + return container_of(device, struct nvkm_device_pci, device); +} + +static void +nvkm_device_pci_fini(struct nvkm_device *device, bool suspend) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + if (suspend) { + pci_disable_device(pdev->pdev); + pdev->suspend = true; + } +} + +static int +nvkm_device_pci_preinit(struct nvkm_device *device) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + if (pdev->suspend) { + int ret = pci_enable_device(pdev->pdev); + if (ret) + return ret; + pci_set_master(pdev->pdev); + pdev->suspend = false; + } + return 0; +} + +static void * +nvkm_device_pci_dtor(struct nvkm_device *device) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + pci_disable_device(pdev->pdev); + return pdev; +} + +static const struct nvkm_device_func +nvkm_device_pci_func = { + .pci = nvkm_device_pci, + .dtor = nvkm_device_pci_dtor, + .preinit = nvkm_device_pci_preinit, + .fini = nvkm_device_pci_fini, +}; + +int +nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + struct nvkm_device_pci *pdev; + int ret; + + ret = pci_enable_device(pci_dev); + if (ret) + return ret; + + if (!(pdev = kzalloc(sizeof(*pdev), GFP_KERNEL))) { + pci_disable_device(pci_dev); + return -ENOMEM; + } + *pdevice = &pdev->device; + pdev->pdev = pci_dev; + + return nvkm_device_ctor(&nvkm_device_pci_func, NULL, + pci_dev, NVKM_BUS_PCI, + (u64)pci_domain_nr(pci_dev->bus) << 32 | + pci_dev->bus->number << 16 | + PCI_SLOT(pci_dev->devfn) << 8 | + PCI_FUNC(pci_dev->devfn), NULL, + cfg, dbg, detect, mmio, subdev_mask, + &pdev->device); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 8d3590e7bd875..df9c1550301f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -2,6 +2,15 @@ #define __NVKM_DEVICE_PRIV_H__ #include +int nvkm_device_ctor(const struct nvkm_device_func *, + const struct nvkm_device_quirk *, + void *, enum nv_bus_type type, u64 handle, + const char *name, const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device *); +int nvkm_device_init(struct nvkm_device *); +int nvkm_device_fini(struct nvkm_device *, bool suspend); + extern struct nvkm_oclass nvkm_control_oclass[]; int nv04_identify(struct nvkm_device *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c new file mode 100644 index 0000000000000..0a5e5b88fee2a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -0,0 +1,66 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include +#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER +#include "priv.h" + +static struct nvkm_device_tegra * +nvkm_device_tegra(struct nvkm_device *obj) +{ + return container_of(obj, struct nvkm_device_tegra, device); +} + +static const struct nvkm_device_func +nvkm_device_tegra_func = { + .tegra = nvkm_device_tegra, +}; + +int +nvkm_device_tegra_new(struct platform_device *pdev, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + struct nvkm_device_tegra *tdev; + + if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL))) + return -ENOMEM; + *pdevice = &tdev->device; + tdev->pdev = pdev; + + return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, pdev, + NVKM_BUS_PLATFORM, pdev->id, NULL, + cfg, dbg, detect, mmio, subdev_mask, + &tdev->device); +} +#else +int +nvkm_device_tegra_new(struct platform_device *pdev, + const char *cfg, const char *dbg, + bool detect, bool mmio, u64 subdev_mask, + struct nvkm_device **pdevice) +{ + return -ENOSYS; +} +#endif -- GitLab From 6cf813fb26640ef539051fb7f965af8c9ff10d92 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5489/7006] drm/nouveau/device: prepare for new-style subdevs Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 50 +- drivers/gpu/drm/nouveau/nvkm/core/engine.c | 10 + drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 25 +- drivers/gpu/drm/nouveau/nvkm/core/object.c | 48 +- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 39 +- .../gpu/drm/nouveau/nvkm/engine/device/acpi.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/device/acpi.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 2251 ++++++++++++++++- .../drm/nouveau/nvkm/engine/device/gf100.c | 41 - .../drm/nouveau/nvkm/engine/device/gk104.c | 40 - .../drm/nouveau/nvkm/engine/device/gm100.c | 36 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 19 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 26 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 23 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 24 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 39 - .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 48 - .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 36 + .../gpu/drm/nouveau/nvkm/engine/device/user.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 4 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 4 +- 28 files changed, 2378 insertions(+), 437 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index eb843e3ff0055..3786982c1360b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -84,9 +84,9 @@ struct nvkm_device { struct nvkm_event event; - const char *cname; u64 disable_mask; + const struct nvkm_device_chip *chip; enum { NV_04 = 0x04, NV_10 = 0x10, @@ -104,7 +104,6 @@ struct nvkm_device { u32 crystal; struct nvkm_oclass *oclass[NVDEV_SUBDEV_NR]; - struct nvkm_object *subdev[NVDEV_SUBDEV_NR]; struct { struct notifier_block nb; @@ -153,6 +152,9 @@ struct nvkm_device { struct nouveau_platform_gpu *gpu; }; +struct nvkm_subdev *nvkm_device_subdev(struct nvkm_device *, int index); +struct nvkm_engine *nvkm_device_engine(struct nvkm_device *, int index); + struct nvkm_device_func { struct nvkm_device_pci *(*pci)(struct nvkm_device *); struct nvkm_device_tegra *(*tegra)(struct nvkm_device *); @@ -164,6 +166,50 @@ struct nvkm_device_func { struct nvkm_device_quirk { }; +struct nvkm_device_chip { + const char *name; + + int (*bar )(struct nvkm_device *, int idx, struct nvkm_bar **); + int (*bios )(struct nvkm_device *, int idx, struct nvkm_bios **); + int (*bus )(struct nvkm_device *, int idx, struct nvkm_bus **); + int (*clk )(struct nvkm_device *, int idx, struct nvkm_clk **); + int (*devinit)(struct nvkm_device *, int idx, struct nvkm_devinit **); + int (*fb )(struct nvkm_device *, int idx, struct nvkm_fb **); + int (*fuse )(struct nvkm_device *, int idx, struct nvkm_fuse **); + int (*gpio )(struct nvkm_device *, int idx, struct nvkm_gpio **); + int (*i2c )(struct nvkm_device *, int idx, struct nvkm_i2c **); + int (*ibus )(struct nvkm_device *, int idx, struct nvkm_subdev **); + int (*imem )(struct nvkm_device *, int idx, struct nvkm_instmem **); + int (*ltc )(struct nvkm_device *, int idx, struct nvkm_ltc **); + int (*mc )(struct nvkm_device *, int idx, struct nvkm_mc **); + int (*mmu )(struct nvkm_device *, int idx, struct nvkm_mmu **); + int (*mxm )(struct nvkm_device *, int idx, struct nvkm_subdev **); + int (*pmu )(struct nvkm_device *, int idx, struct nvkm_pmu **); + int (*therm )(struct nvkm_device *, int idx, struct nvkm_therm **); + int (*timer )(struct nvkm_device *, int idx, struct nvkm_timer **); + int (*volt )(struct nvkm_device *, int idx, struct nvkm_volt **); + + int (*bsp )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*ce[3] )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*cipher )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*disp )(struct nvkm_device *, int idx, struct nvkm_disp **); + int (*dma )(struct nvkm_device *, int idx, struct nvkm_dmaeng **); + int (*fifo )(struct nvkm_device *, int idx, struct nvkm_fifo **); + int (*gr )(struct nvkm_device *, int idx, struct nvkm_gr **); + int (*ifb )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*me )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*mpeg )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*msenc )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*mspdec )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*msppp )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*msvld )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*pm )(struct nvkm_device *, int idx, struct nvkm_pm **); + int (*sec )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*sw )(struct nvkm_device *, int idx, struct nvkm_sw **); + int (*vic )(struct nvkm_device *, int idx, struct nvkm_engine **); + int (*vp )(struct nvkm_device *, int idx, struct nvkm_engine **); +}; + struct nvkm_device *nvkm_device_find(u64 name); int nvkm_device_list(u64 *name, int size); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index 07559e7c4c4c0..eabd271f68b39 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -68,6 +68,8 @@ static int nvkm_engine_fini(struct nvkm_subdev *obj, bool suspend) { struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + if (engine->subdev.object.oclass) + return engine->subdev.object.oclass->ofuncs->fini(&engine->subdev.object, suspend); if (engine->func->fini) return engine->func->fini(engine, suspend); return 0; @@ -86,6 +88,9 @@ nvkm_engine_init(struct nvkm_subdev *obj) return ret; } + if (engine->subdev.object.oclass) + return engine->subdev.object.oclass->ofuncs->init(&engine->subdev.object); + if (engine->func->oneinit && !engine->subdev.oneinit) { nvkm_trace(subdev, "one-time init running...\n"); time = ktime_to_us(ktime_get()); @@ -110,6 +115,10 @@ static void * nvkm_engine_dtor(struct nvkm_subdev *obj) { struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + if (engine->subdev.object.oclass) { + engine->subdev.object.oclass->ofuncs->dtor(&engine->subdev.object); + return NULL; + } if (engine->func->dtor) return engine->func->dtor(engine); return engine; @@ -201,5 +210,6 @@ nvkm_engine_create_(struct nvkm_object *parent, struct nvkm_object *engobj, INIT_LIST_HEAD(&engine->contexts); spin_lock_init(&engine->lock); + engine->subdev.func = &nvkm_engine_func; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 6e5ff942a6da3..d9c26e40ae320 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -91,7 +91,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) struct nvkm_object *engctx = NULL; struct nvkm_object *object = NULL; struct nvkm_parent *parent; - struct nvkm_object *engine; + struct nvkm_engine *engine; struct nvkm_oclass *oclass; u32 _handle, _oclass; int ret; @@ -117,7 +117,8 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) parent = nv_parent(handle->object); /* check that parent supports the requested subclass */ - ret = nvkm_parent_sclass(&parent->object, _oclass, &engine, &oclass); + ret = nvkm_parent_sclass(&parent->object, _oclass, + (struct nvkm_object **)&engine, &oclass); if (ret) { nvif_debug(&parent->object, "illegal class 0x%04x\n", _oclass); goto fail_class; @@ -128,18 +129,20 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) * state calculated at init (ie. default context construction) */ if (engine) { - ret = nvkm_object_inc(engine); - if (ret) + engine = nvkm_engine_ref(engine); + if (IS_ERR(engine)) { + ret = PTR_ERR(engine); + engine = NULL; goto fail_class; + } } /* if engine requires it, create a context object to insert * between the parent and its children (eg. PGRAPH context) */ - if (engine && nv_engine(engine)->cclass) { - ret = nvkm_object_old(&parent->object, engine, - nv_engine(engine)->cclass, - data, size, &engctx); + if (engine && engine->cclass) { + ret = nvkm_object_old(&parent->object, &engine->subdev.object, + engine->cclass, data, size, &engctx); if (ret) goto fail_engctx; } else { @@ -147,7 +150,8 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) } /* finally, create new object and bind it to its handle */ - ret = nvkm_object_old(engctx, engine, oclass, data, size, &object); + ret = nvkm_object_old(engctx, &engine->subdev.object, oclass, + data, size, &object); client->data = object; if (ret) goto fail_ctor; @@ -178,8 +182,7 @@ fail_init: fail_ctor: nvkm_object_ref(NULL, &engctx); fail_engctx: - if (engine) - nvkm_object_dec(engine, false); + nvkm_engine_unref(&engine); fail_class: return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index 0abee78168746..0680eae072cf0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -201,6 +201,7 @@ nvkm_object_del(struct nvkm_object **pobject) if (object && !WARN_ON(!object->func)) { if (object->func->dtor) *pobject = object->func->dtor(object); + nvkm_engine_unref(&object->engine); kfree(*pobject); *pobject = NULL; } @@ -212,7 +213,7 @@ nvkm_object_ctor(const struct nvkm_object_func *func, { object->func = func; object->client = oclass->client; - object->engine = oclass->engine; + object->engine = nvkm_engine_ref(oclass->engine); object->oclass_name = oclass->base.oclass; object->handle = oclass->handle; object->parent = oclass->parent; @@ -251,10 +252,11 @@ nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size, } int -nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, +nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engobj, struct nvkm_oclass *oclass, u32 pclass, int size, void **pobject) { + struct nvkm_engine *engine = engobj ? nv_engine(engobj) : NULL; struct nvkm_object *object; object = *pobject = kzalloc(size, GFP_KERNEL); @@ -262,7 +264,7 @@ nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine, return -ENOMEM; nvkm_object_ref(parent, &object->parent); - nvkm_object_ref(engine, (struct nvkm_object **)&object->engine); + object->engine = nvkm_engine_ref(engine); object->oclass = oclass; object->pclass = pclass; atomic_set(&object->refcount, 1); @@ -287,7 +289,7 @@ _nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, void nvkm_object_destroy(struct nvkm_object *object) { - nvkm_object_ref(NULL, (struct nvkm_object **)&object->engine); + nvkm_engine_unref(&object->engine); nvkm_object_ref(NULL, &object->parent); kfree(object); } @@ -333,7 +335,8 @@ nvkm_object_old(struct nvkm_object *parent, struct nvkm_object *engine, } if (ret == 0) { - atomic_set(&object->refcount, 1); + if (!nv_iclass(object, NV_SUBDEV_CLASS)) + atomic_set(&object->refcount, 1); } return 0; @@ -370,14 +373,6 @@ nvkm_object_inc(struct nvkm_object *object) goto fail_parent; } - if (object->engine) { - mutex_lock(&nv_subdev(object->engine)->mutex); - ret = nvkm_object_inc(&object->engine->subdev.object); - mutex_unlock(&nv_subdev(object->engine)->mutex); - if (ret) - goto fail_engine; - } - ret = nvkm_object_init(object); atomic_set(&object->usecount, 1); if (ret) @@ -386,12 +381,6 @@ nvkm_object_inc(struct nvkm_object *object) return 0; fail_self: - if (object->engine) { - mutex_lock(&nv_subdev(object->engine)->mutex); - nvkm_object_dec(&object->engine->subdev.object, false); - mutex_unlock(&nv_subdev(object->engine)->mutex); - } -fail_engine: if (object->parent) nvkm_object_dec(object->parent, false); fail_parent: @@ -405,12 +394,6 @@ nvkm_object_decf(struct nvkm_object *object) nvkm_object_fini(object, false); atomic_set(&object->usecount, 0); - if (object->engine) { - mutex_lock(&nv_subdev(object->engine)->mutex); - nvkm_object_dec(&object->engine->subdev.object, false); - mutex_unlock(&nv_subdev(object->engine)->mutex); - } - if (object->parent) nvkm_object_dec(object->parent, false); @@ -427,14 +410,6 @@ nvkm_object_decs(struct nvkm_object *object) if (ret) return ret; - if (object->engine) { - mutex_lock(&nv_subdev(object->engine)->mutex); - ret = nvkm_object_dec(&object->engine->subdev.object, true); - mutex_unlock(&nv_subdev(object->engine)->mutex); - if (ret) - goto fail_engine; - } - if (object->parent) { ret = nvkm_object_dec(object->parent, true); if (ret) @@ -444,13 +419,6 @@ nvkm_object_decs(struct nvkm_object *object) return 0; fail_parent: - if (object->engine) { - mutex_lock(&nv_subdev(object->engine)->mutex); - nvkm_object_inc(&object->engine->subdev.object); - mutex_unlock(&nv_subdev(object->engine)->mutex); - } - -fail_engine: nvkm_object_init(object); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 5af13d8be2f58..b0647c233478b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -74,6 +74,12 @@ nvkm_subdev_name[64] = { void nvkm_subdev_intr(struct nvkm_subdev *subdev) { + if (subdev->object.oclass) { + if (subdev->intr) + subdev->intr(subdev); + return; + } + if (subdev->func->intr) subdev->func->intr(subdev); } @@ -85,10 +91,18 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) const char *action = suspend ? "suspend" : "fini"; u32 pmc_enable = subdev->pmc_enable; s64 time; + int ret; nvkm_trace(subdev, "%s running...\n", action); time = ktime_to_us(ktime_get()); + if (!subdev->func) { + ret = subdev->object.oclass->ofuncs->fini(&subdev->object, suspend); + if (ret) + return ret; + goto done; + } + if (subdev->func->fini) { int ret = subdev->func->fini(subdev, suspend); if (ret) { @@ -104,6 +118,7 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) nvkm_rd32(device, 0x000200); } +done: time = ktime_to_us(ktime_get()) - time; nvkm_trace(subdev, "%s completed in %lldus\n", action, time); return 0; @@ -117,7 +132,7 @@ nvkm_subdev_preinit(struct nvkm_subdev *subdev) nvkm_trace(subdev, "preinit running...\n"); time = ktime_to_us(ktime_get()); - if (subdev->func->preinit) { + if (!subdev->object.oclass && subdev->func->preinit) { int ret = subdev->func->preinit(subdev); if (ret) { nvkm_error(subdev, "preinit failed, %d\n", ret); @@ -139,6 +154,13 @@ nvkm_subdev_init(struct nvkm_subdev *subdev) nvkm_trace(subdev, "init running...\n"); time = ktime_to_us(ktime_get()); + if (!subdev->func) { + ret = subdev->object.oclass->ofuncs->init(&subdev->object); + if (ret) + return ret; + goto done; + } + if (subdev->func->oneinit && !subdev->oneinit) { s64 time; nvkm_trace(subdev, "one-time init running...\n"); @@ -162,6 +184,7 @@ nvkm_subdev_init(struct nvkm_subdev *subdev) } } +done: time = ktime_to_us(ktime_get()) - time; nvkm_trace(subdev, "init completed in %lldus\n", time); return 0; @@ -172,6 +195,12 @@ nvkm_subdev_del(struct nvkm_subdev **psubdev) { struct nvkm_subdev *subdev = *psubdev; s64 time; + + if (subdev && subdev->object.oclass) { + subdev->object.oclass->ofuncs->dtor(&subdev->object); + return; + } + if (subdev && !WARN_ON(!subdev->func)) { nvkm_trace(subdev, "destroy running...\n"); time = ktime_to_us(ktime_get()); @@ -211,8 +240,10 @@ nvkm_subdev(void *obj, int idx) struct nvkm_object *object = nv_object(obj); while (object && !nv_iclass(object, NV_SUBDEV_CLASS)) object = object->parent; - if (object == NULL || !object->parent || nv_subidx(nv_subdev(object)) != idx) - object = nv_device(obj)->subdev[idx]; + if (object == NULL || !object->parent || nv_subidx(nv_subdev(object)) != idx) { + struct nvkm_device *device = nv_device(obj); + return nvkm_device_subdev(device, idx); + } return object ? nv_subdev(object) : NULL; } @@ -266,8 +297,6 @@ _nvkm_subdev_fini(struct nvkm_object *object, bool suspend) void nvkm_subdev_destroy(struct nvkm_subdev *subdev) { - int subidx = nv_hclass(subdev) & 0xff; - nv_device(subdev)->subdev[subidx] = NULL; nvkm_object_destroy(&subdev->object); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c index f42706e1d5dbc..fdca90bc8f0e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c @@ -40,21 +40,19 @@ nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data) } #endif -int -nvkm_acpi_fini(struct nvkm_device *device, bool suspend) +void +nvkm_acpi_fini(struct nvkm_device *device) { #ifdef CONFIG_ACPI unregister_acpi_notifier(&device->acpi.nb); #endif - return 0; } -int +void nvkm_acpi_init(struct nvkm_device *device) { #ifdef CONFIG_ACPI device->acpi.nb.notifier_call = nvkm_acpi_ntfy; register_acpi_notifier(&device->acpi.nb); #endif - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h index 82dd359ddfa45..1bbe76e0740a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h @@ -3,6 +3,6 @@ #include struct nvkm_device; -int nvkm_acpi_init(struct nvkm_device *); -int nvkm_acpi_fini(struct nvkm_device *, bool); +void nvkm_acpi_init(struct nvkm_device *); +void nvkm_acpi_fini(struct nvkm_device *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index c7d8e2902c6c5..b3f3336025829 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -67,6 +67,1916 @@ nvkm_device_list(u64 *name, int size) return nr; } +static const struct nvkm_device_chip +null_chipset = { + .name = "NULL", +// .bios = nvkm_bios_new, +}; + +static const struct nvkm_device_chip +nv4_chipset = { + .name = "NV04", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv04_devinit_new, +// .fb = nv04_fb_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv04_fifo_new, +// .gr = nv04_gr_new, +// .sw = nv04_sw_new, +}; + +static const struct nvkm_device_chip +nv5_chipset = { + .name = "NV05", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv05_devinit_new, +// .fb = nv04_fb_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv04_fifo_new, +// .gr = nv04_gr_new, +// .sw = nv04_sw_new, +}; + +static const struct nvkm_device_chip +nv10_chipset = { + .name = "NV10", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv10_devinit_new, +// .fb = nv10_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .gr = nv10_gr_new, +}; + +static const struct nvkm_device_chip +nv11_chipset = { + .name = "NV11", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv10_devinit_new, +// .fb = nv10_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv10_fifo_new, +// .gr = nv10_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv15_chipset = { + .name = "NV15", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv10_devinit_new, +// .fb = nv10_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv10_fifo_new, +// .gr = nv10_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv17_chipset = { + .name = "NV17", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv10_devinit_new, +// .fb = nv10_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv10_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv18_chipset = { + .name = "NV18", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv10_devinit_new, +// .fb = nv10_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv10_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv1a_chipset = { + .name = "nForce", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv1a_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv10_fifo_new, +// .gr = nv10_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv1f_chipset = { + .name = "nForce2", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv1a_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv10_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv20_chipset = { + .name = "NV20", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv20_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv20_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv25_chipset = { + .name = "NV25", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv25_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv25_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv28_chipset = { + .name = "NV28", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv25_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv25_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv2a_chipset = { + .name = "NV2A", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv25_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv2a_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv30_chipset = { + .name = "NV30", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv30_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv30_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv31_chipset = { + .name = "NV31", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv30_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv30_gr_new, +// .mpeg = nv31_mpeg_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv34_chipset = { + .name = "NV34", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv10_devinit_new, +// .fb = nv10_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv34_gr_new, +// .mpeg = nv31_mpeg_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv35_chipset = { + .name = "NV35", +// .bios = nvkm_bios_new, +// .bus = nv04_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv35_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv35_gr_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv36_chipset = { + .name = "NV36", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv04_clk_new, +// .devinit = nv20_devinit_new, +// .fb = nv36_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv04_instmem_new, +// .mc = nv04_mc_new, +// .mmu = nv04_mmu_new, +// .timer = nv04_timer_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv17_fifo_new, +// .gr = nv35_gr_new, +// .mpeg = nv31_mpeg_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv40_chipset = { + .name = "NV40", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv40_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv04_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv40_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv41_chipset = { + .name = "NV41", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv41_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv41_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv40_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv42_chipset = { + .name = "NV42", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv41_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv41_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv40_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv43_chipset = { + .name = "NV43", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv41_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv41_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv40_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv44_chipset = { + .name = "NV44", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv44_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv44_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv45_chipset = { + .name = "NV45", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv40_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv04_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv46_chipset = { + .name = "G72", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv46_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv44_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv47_chipset = { + .name = "G70", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv47_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv41_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv49_chipset = { + .name = "G71", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv49_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv41_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4a_chipset = { + .name = "NV44A", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv44_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv44_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4b_chipset = { + .name = "G73", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv49_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv40_mc_new, +// .mmu = nv41_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4c_chipset = { + .name = "C61", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv46_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv4c_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv4e_chipset = { + .name = "C51", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv4e_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv4e_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv4c_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv50_chipset = { + .name = "G80", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = nv50_bus_new, +// .clk = nv50_clk_new, +// .devinit = nv50_devinit_new, +// .fb = nv50_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = nv50_gpio_new, +// .i2c = nv50_i2c_new, +// .imem = nv50_instmem_new, +// .mc = nv50_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = nv50_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv50_disp_new, +// .dma = nv50_dma_new, +// .fifo = nv50_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = nv50_mpeg_new, +// .pm = nv50_pm_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nv63_chipset = { + .name = "C73", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv46_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv4c_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv67_chipset = { + .name = "C67", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv46_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv4c_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv68_chipset = { + .name = "C68", +// .bios = nvkm_bios_new, +// .bus = nv31_bus_new, +// .clk = nv40_clk_new, +// .devinit = nv1a_devinit_new, +// .fb = nv46_fb_new, +// .gpio = nv10_gpio_new, +// .i2c = nv04_i2c_new, +// .imem = nv40_instmem_new, +// .mc = nv4c_mc_new, +// .mmu = nv44_mmu_new, +// .therm = nv40_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = nv04_disp_new, +// .dma = nv04_dma_new, +// .fifo = nv40_fifo_new, +// .gr = nv40_gr_new, +// .mpeg = nv44_mpeg_new, +// .pm = nv40_pm_new, +// .sw = nv10_sw_new, +}; + +static const struct nvkm_device_chip +nv84_chipset = { + .name = "G84", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = nv50_bus_new, +// .clk = g84_clk_new, +// .devinit = g84_devinit_new, +// .fb = g84_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = nv50_gpio_new, +// .i2c = nv50_i2c_new, +// .imem = nv50_instmem_new, +// .mc = nv50_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .bsp = g84_bsp_new, +// .cipher = g84_cipher_new, +// .disp = g84_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .pm = g84_pm_new, +// .sw = nv50_sw_new, +// .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv86_chipset = { + .name = "G86", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = nv50_bus_new, +// .clk = g84_clk_new, +// .devinit = g84_devinit_new, +// .fb = g84_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = nv50_gpio_new, +// .i2c = nv50_i2c_new, +// .imem = nv50_instmem_new, +// .mc = nv50_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .bsp = g84_bsp_new, +// .cipher = g84_cipher_new, +// .disp = g84_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .pm = g84_pm_new, +// .sw = nv50_sw_new, +// .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv92_chipset = { + .name = "G92", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = nv50_bus_new, +// .clk = g84_clk_new, +// .devinit = g84_devinit_new, +// .fb = g84_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = nv50_gpio_new, +// .i2c = nv50_i2c_new, +// .imem = nv50_instmem_new, +// .mc = nv50_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .bsp = g84_bsp_new, +// .cipher = g84_cipher_new, +// .disp = g84_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .pm = g84_pm_new, +// .sw = nv50_sw_new, +// .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv94_chipset = { + .name = "G94", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = g84_clk_new, +// .devinit = g84_devinit_new, +// .fb = g84_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g94_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .bsp = g84_bsp_new, +// .cipher = g84_cipher_new, +// .disp = g94_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .pm = g84_pm_new, +// .sw = nv50_sw_new, +// .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nv96_chipset = { + .name = "G96", +// .bios = nvkm_bios_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .fuse = nv50_fuse_new, +// .clk = g84_clk_new, +// .therm = g84_therm_new, +// .mxm = nv50_mxm_new, +// .devinit = g84_devinit_new, +// .mc = g94_mc_new, +// .bus = g94_bus_new, +// .timer = nv04_timer_new, +// .fb = g84_fb_new, +// .imem = nv50_instmem_new, +// .mmu = nv50_mmu_new, +// .bar = nv50_bar_new, +// .volt = nv40_volt_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .sw = nv50_sw_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .vp = g84_vp_new, +// .cipher = g84_cipher_new, +// .bsp = g84_bsp_new, +// .disp = g94_disp_new, +// .pm = g84_pm_new, +}; + +static const struct nvkm_device_chip +nv98_chipset = { + .name = "G98", +// .bios = nvkm_bios_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .fuse = nv50_fuse_new, +// .clk = g84_clk_new, +// .therm = g84_therm_new, +// .mxm = nv50_mxm_new, +// .devinit = g98_devinit_new, +// .mc = g98_mc_new, +// .bus = g94_bus_new, +// .timer = nv04_timer_new, +// .fb = g84_fb_new, +// .imem = nv50_instmem_new, +// .mmu = nv50_mmu_new, +// .bar = nv50_bar_new, +// .volt = nv40_volt_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .sw = nv50_sw_new, +// .gr = nv50_gr_new, +// .mspdec = g98_mspdec_new, +// .sec = g98_sec_new, +// .msvld = g98_msvld_new, +// .msppp = g98_msppp_new, +// .disp = g94_disp_new, +// .pm = g84_pm_new, +}; + +static const struct nvkm_device_chip +nva0_chipset = { + .name = "GT200", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = g84_clk_new, +// .devinit = g84_devinit_new, +// .fb = g84_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = nv50_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .bsp = g84_bsp_new, +// .cipher = g84_cipher_new, +// .disp = gt200_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .pm = gt200_pm_new, +// .sw = nv50_sw_new, +// .vp = g84_vp_new, +}; + +static const struct nvkm_device_chip +nva3_chipset = { + .name = "GT215", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = gt215_clk_new, +// .devinit = gt215_devinit_new, +// .fb = gt215_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gt215_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gt215_ce_new, +// .disp = gt215_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mpeg = g84_mpeg_new, +// .mspdec = g98_mspdec_new, +// .msppp = g98_msppp_new, +// .msvld = g98_msvld_new, +// .pm = gt215_pm_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nva5_chipset = { + .name = "GT216", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = gt215_clk_new, +// .devinit = gt215_devinit_new, +// .fb = gt215_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gt215_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gt215_ce_new, +// .disp = gt215_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mspdec = g98_mspdec_new, +// .msppp = g98_msppp_new, +// .msvld = g98_msvld_new, +// .pm = gt215_pm_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nva8_chipset = { + .name = "GT218", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = gt215_clk_new, +// .devinit = gt215_devinit_new, +// .fb = gt215_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gt215_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gt215_ce_new, +// .disp = gt215_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mspdec = g98_mspdec_new, +// .msppp = g98_msppp_new, +// .msvld = g98_msvld_new, +// .pm = gt215_pm_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvaa_chipset = { + .name = "MCP77/MCP78", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = mcp77_clk_new, +// .devinit = g98_devinit_new, +// .fb = mcp77_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = g94_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mspdec = g98_mspdec_new, +// .msppp = g98_msppp_new, +// .msvld = g98_msvld_new, +// .pm = g84_pm_new, +// .sec = g98_sec_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvac_chipset = { + .name = "MCP79/MCP7A", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = mcp77_clk_new, +// .devinit = g98_devinit_new, +// .fb = mcp77_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = g84_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .disp = g94_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mspdec = g98_mspdec_new, +// .msppp = g98_msppp_new, +// .msvld = g98_msvld_new, +// .pm = g84_pm_new, +// .sec = g98_sec_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvaf_chipset = { + .name = "MCP89", +// .bar = nv50_bar_new, +// .bios = nvkm_bios_new, +// .bus = g94_bus_new, +// .clk = gt215_clk_new, +// .devinit = mcp89_devinit_new, +// .fb = mcp89_fb_new, +// .fuse = nv50_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .imem = nv50_instmem_new, +// .mc = g98_mc_new, +// .mmu = nv50_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gt215_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gt215_ce_new, +// .disp = gt215_disp_new, +// .dma = nv50_dma_new, +// .fifo = g84_fifo_new, +// .gr = nv50_gr_new, +// .mspdec = g98_mspdec_new, +// .msppp = g98_msppp_new, +// .msvld = g98_msvld_new, +// .pm = gt215_pm_new, +// .sw = nv50_sw_new, +}; + +static const struct nvkm_device_chip +nvc0_chipset = { + .name = "GF100", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf100_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .ce[1] = gf100_ce1_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf100_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf100_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc1_chipset = { + .name = "GF108", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf108_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf108_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc3_chipset = { + .name = "GF106", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf104_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf100_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc4_chipset = { + .name = "GF104", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf100_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .ce[1] = gf100_ce1_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf104_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf100_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvc8_chipset = { + .name = "GF110", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf100_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .ce[1] = gf100_ce1_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf110_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf100_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvce_chipset = { + .name = "GF114", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf100_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .ce[1] = gf100_ce1_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf104_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf100_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvcf_chipset = { + .name = "GF116", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = g94_gpio_new, +// .i2c = g94_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf100_pmu_new, +// .therm = gt215_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .disp = gt215_disp_new, +// .dma = gf100_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf104_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf100_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvd7_chipset = { + .name = "GF117", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gf110_gpio_new, +// .i2c = gf117_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .ce[0] = gf100_ce0_new, +// .disp = gf119_disp_new, +// .dma = gf119_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf117_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf117_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvd9_chipset = { + .name = "GF119", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gf100_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gf100_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gf110_gpio_new, +// .i2c = gf110_i2c_new, +// .ibus = gf100_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gf100_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf110_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gf100_ce0_new, +// .disp = gf119_disp_new, +// .dma = gf119_dma_new, +// .fifo = gf100_fifo_new, +// .gr = gf119_gr_new, +// .mspdec = gf100_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gf100_msvld_new, +// .pm = gf117_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nve4_chipset = { + .name = "GK104", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gk104_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk104_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk104_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk104_fifo_new, +// .gr = gk104_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .pm = gk104_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nve6_chipset = { + .name = "GK106", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gk104_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk104_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk104_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk104_fifo_new, +// .gr = gk104_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .pm = gk104_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nve7_chipset = { + .name = "GK107", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gk104_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gf110_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk104_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk104_fifo_new, +// .gr = gk104_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .pm = gk104_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvea_chipset = { + .name = "GK20A", +// .bar = gk20a_bar_new, +// .bus = gf100_bus_new, +// .clk = gk20a_clk_new, +// .fb = gk20a_fb_new, +// .fuse = gf100_fuse_new, +// .ibus = gk20a_ibus_new, +// .imem = gk20a_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .pmu = gk20a_pmu_new, +// .timer = gk20a_timer_new, +// .volt = gk20a_volt_new, +// .ce[2] = gk104_ce2_new, +// .dma = gf119_dma_new, +// .fifo = gk20a_fifo_new, +// .gr = gk20a_gr_new, +// .pm = gk104_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvf0_chipset = { + .name = "GK110", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gk104_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk110_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk110_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk104_fifo_new, +// .gr = gk110_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .pm = gk110_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nvf1_chipset = { + .name = "GK110B", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gf110_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gf106_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk110_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk110_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk104_fifo_new, +// .gr = gk110b_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .pm = gk110_pm_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv106_chipset = { + .name = "GK208B", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gk104_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk208_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk110_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk208_fifo_new, +// .gr = gk208_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv108_chipset = { + .name = "GK208", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gf100_devinit_new, +// .fb = gk104_fb_new, +// .fuse = gf100_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gk104_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gk104_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk208_pmu_new, +// .therm = gf110_therm_new, +// .timer = nv04_timer_new, +// .volt = nv40_volt_new, +// .ce[0] = gk104_ce0_new, +// .ce[1] = gk104_ce1_new, +// .ce[2] = gk104_ce2_new, +// .disp = gk110_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk208_fifo_new, +// .gr = gk208_gr_new, +// .mspdec = gk104_mspdec_new, +// .msppp = gf100_msppp_new, +// .msvld = gk104_msvld_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv117_chipset = { + .name = "GM107", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .clk = gk104_clk_new, +// .devinit = gm107_devinit_new, +// .fb = gm107_fb_new, +// .fuse = gm107_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gf110_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gm107_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk208_pmu_new, +// .therm = gm107_therm_new, +// .timer = gk20a_timer_new, +// .ce[0] = gk104_ce0_new, +// .ce[2] = gk104_ce2_new, +// .disp = gm107_disp_new, +// .dma = gf119_dma_new, +// .fifo = gk208_fifo_new, +// .gr = gm107_gr_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv124_chipset = { + .name = "GM204", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .devinit = gm204_devinit_new, +// .fb = gm107_fb_new, +// .fuse = gm107_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gm204_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gm107_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk208_pmu_new, +// .timer = gk20a_timer_new, +// .ce[0] = gm204_ce0_new, +// .ce[1] = gm204_ce1_new, +// .ce[2] = gm204_ce2_new, +// .disp = gm204_disp_new, +// .dma = gf119_dma_new, +// .fifo = gm204_fifo_new, +// .gr = gm204_gr_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv126_chipset = { + .name = "GM206", +// .bar = gf100_bar_new, +// .bios = nvkm_bios_new, +// .bus = gf100_bus_new, +// .devinit = gm204_devinit_new, +// .fb = gm107_fb_new, +// .fuse = gm107_fuse_new, +// .gpio = gk104_gpio_new, +// .i2c = gm204_i2c_new, +// .ibus = gk104_ibus_new, +// .imem = nv50_instmem_new, +// .ltc = gm107_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .mxm = nv50_mxm_new, +// .pmu = gk208_pmu_new, +// .timer = gk20a_timer_new, +// .ce[0] = gm204_ce0_new, +// .ce[1] = gm204_ce1_new, +// .ce[2] = gm204_ce2_new, +// .disp = gm204_disp_new, +// .dma = gf119_dma_new, +// .fifo = gm204_fifo_new, +// .gr = gm206_gr_new, +// .sw = gf100_sw_new, +}; + +static const struct nvkm_device_chip +nv12b_chipset = { + .name = "GM20B", +// .bar = gk20a_bar_new, +// .bus = gf100_bus_new, +// .fb = gk20a_fb_new, +// .fuse = gm107_fuse_new, +// .ibus = gk20a_ibus_new, +// .imem = gk20a_instmem_new, +// .ltc = gm107_ltc_new, +// .mc = gk20a_mc_new, +// .mmu = gf100_mmu_new, +// .mmu = gf100_mmu_new, +// .timer = gk20a_timer_new, +// .ce[2] = gm204_ce2_new, +// .dma = gf119_dma_new, +// .fifo = gm20b_fifo_new, +// .gr = gm20b_gr_new, +// .sw = gf100_sw_new, +}; + #include #include @@ -116,45 +2026,129 @@ nvkm_device_event_func = { .ctor = nvkm_device_event_ctor, }; +struct nvkm_subdev * +nvkm_device_subdev(struct nvkm_device *device, int index) +{ + struct nvkm_engine *engine; + + if (device->disable_mask & (1ULL << index)) + return NULL; + + switch (index) { +#define _(n,p,m) case NVDEV_SUBDEV_##n: if (p) return (m); break + _(BAR , device->bar , &device->bar->subdev); + _(VBIOS , device->bios , &device->bios->subdev); + _(BUS , device->bus , &device->bus->subdev); + _(CLK , device->clk , &device->clk->subdev); + _(DEVINIT, device->devinit, &device->devinit->subdev); + _(FB , device->fb , &device->fb->subdev); + _(FUSE , device->fuse , &device->fuse->subdev); + _(GPIO , device->gpio , &device->gpio->subdev); + _(I2C , device->i2c , &device->i2c->subdev); + _(IBUS , device->ibus , device->ibus); + _(INSTMEM, device->imem , &device->imem->subdev); + _(LTC , device->ltc , &device->ltc->subdev); + _(MC , device->mc , &device->mc->subdev); + _(MMU , device->mmu , &device->mmu->subdev); + _(MXM , device->mxm , device->mxm); + _(PMU , device->pmu , &device->pmu->subdev); + _(THERM , device->therm , &device->therm->subdev); + _(TIMER , device->timer , &device->timer->subdev); + _(VOLT , device->volt , &device->volt->subdev); +#undef _ + default: + engine = nvkm_device_engine(device, index); + if (engine) + return &engine->subdev; + break; + } + return NULL; +} + +struct nvkm_engine * +nvkm_device_engine(struct nvkm_device *device, int index) +{ + if (device->disable_mask & (1ULL << index)) + return NULL; + + switch (index) { +#define _(n,p,m) case NVDEV_ENGINE_##n: if (p) return (m); break + _(BSP , device->bsp , device->bsp); + _(CE0 , device->ce[0] , device->ce[0]); + _(CE1 , device->ce[1] , device->ce[1]); + _(CE2 , device->ce[2] , device->ce[2]); + _(CIPHER , device->cipher , device->cipher); + _(DISP , device->disp , &device->disp->engine); + _(DMAOBJ , device->dma , &device->dma->engine); + _(FIFO , device->fifo , &device->fifo->engine); + _(GR , device->gr , &device->gr->engine); + _(IFB , device->ifb , device->ifb); + _(ME , device->me , device->me); + _(MPEG , device->mpeg , device->mpeg); + _(MSENC , device->msenc , device->msenc); + _(MSPDEC , device->mspdec , device->mspdec); + _(MSPPP , device->msppp , device->msppp); + _(MSVLD , device->msvld , device->msvld); + _(PM , device->pm , &device->pm->engine); + _(SEC , device->sec , device->sec); + _(SW , device->sw , &device->sw->engine); + _(VIC , device->vic , device->vic); + _(VP , device->vp , device->vp); +#undef _ + default: + WARN_ON(1); + break; + } + return NULL; +} + int nvkm_device_fini(struct nvkm_device *device, bool suspend) { - struct nvkm_object *subdev; + const char *action = suspend ? "suspend" : "fini"; + struct nvkm_subdev *subdev; int ret, i; + s64 time; + + nvdev_trace(device, "%s running...\n", action); + time = ktime_to_us(ktime_get()); + + nvkm_acpi_fini(device); for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_dec(subdev, suspend); - if (ret && suspend) - goto fail; - } + if ((subdev = nvkm_device_subdev(device, i))) { + ret = nvkm_subdev_fini(subdev, suspend); + if (ret && suspend) + goto fail; } } - ret = nvkm_acpi_fini(device, suspend); if (device->func->fini) device->func->fini(device, suspend); + + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "%s completed in %lldus...\n", action, time); + return 0; + fail: - for (; ret && i < NVDEV_SUBDEV_NR; i++) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_inc(subdev); - if (ret) { - /* XXX */ - } - } + do { + if ((subdev = nvkm_device_subdev(device, i))) { + int rret = nvkm_subdev_init(subdev); + if (rret) + nvkm_fatal(subdev, "failed restart, %d\n", ret); } - } + } while (++i < NVDEV_SUBDEV_NR); + nvdev_trace(device, "%s failed with %d\n", action, ret); return ret; } -int +static int nvkm_device_preinit(struct nvkm_device *device) { - int ret; + struct nvkm_subdev *subdev; + int ret, i; s64 time; nvdev_trace(device, "preinit running...\n"); @@ -166,6 +2160,16 @@ nvkm_device_preinit(struct nvkm_device *device) goto fail; } + for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + if ((subdev = nvkm_device_subdev(device, i))) { + ret = nvkm_subdev_preinit(subdev); + if (ret) + goto fail; + } + } + + /*XXX: devinit */ + time = ktime_to_us(ktime_get()) - time; nvdev_trace(device, "preinit completed in %lldus\n", time); return 0; @@ -178,19 +2182,21 @@ fail: int nvkm_device_init(struct nvkm_device *device) { - struct nvkm_object *subdev; + struct nvkm_subdev *subdev; int ret, i = 0, c; + s64 time; ret = nvkm_device_preinit(device); if (ret) return ret; - ret = nvkm_acpi_init(device); - if (ret) - goto fail; + nvkm_device_fini(device, false); + + nvdev_trace(device, "init running...\n"); + time = ktime_to_us(ktime_get()); for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) { -#define _(s,m) case s: if (device->oclass[s] && !device->subdev[s]) { \ +#define _(s,m) case s: if (device->oclass[s] && !device->m) { \ ret = nvkm_object_old(nv_object(device), NULL, \ device->oclass[s], NULL, (s), \ (struct nvkm_object **)&device->m); \ @@ -200,7 +2206,6 @@ nvkm_device_init(struct nvkm_device *device) } \ if (ret) \ goto fail; \ - device->subdev[s] = (struct nvkm_object *)device->m; \ } break switch (i) { _(NVDEV_SUBDEV_BAR , bar); @@ -259,29 +2264,27 @@ nvkm_device_init(struct nvkm_device *device) * subdev in turn as they're created. */ while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) { - struct nvkm_object *subdev = device->subdev[c++]; - if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) { - ret = nvkm_object_inc(subdev); + if ((subdev = nvkm_device_subdev(device, c++))) { + ret = nvkm_subdev_init(subdev); if (ret) goto fail; - } else - if (subdev) { - nvkm_subdev_reset(subdev); } } } - ret = 0; + nvkm_acpi_init(device); + + time = ktime_to_us(ktime_get()) - time; + nvdev_trace(device, "init completed in %lldus\n", time); + return 0; + fail: - for (--i; ret && i >= 0; i--) { - if ((subdev = device->subdev[i])) { - if (!nv_iclass(subdev, NV_ENGINE_CLASS)) - nvkm_object_dec(subdev, false); - } - } + do { + if ((subdev = nvkm_device_subdev(device, i))) + nvkm_subdev_fini(subdev, false); + } while (--i >= 0); - if (ret) - nvkm_acpi_fini(device, false); + nvdev_error(device, "init failed with %d\n", ret); return ret; } @@ -333,8 +2336,12 @@ nvkm_device_del(struct nvkm_device **pdevice) int i; if (device) { mutex_lock(&nv_devices_mutex); - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) - nvkm_object_ref(NULL, &device->subdev[i]); + device->disable_mask = 0; + for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { + struct nvkm_subdev *subdev = + nvkm_device_subdev(device, i); + nvkm_subdev_del(&subdev); + } nvkm_event_fini(&device->event); @@ -363,6 +2370,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, bool detect, bool mmio, u64 subdev_mask, struct nvkm_device *device) { + struct nvkm_subdev *subdev; u64 mmio_base, mmio_size; u32 boot0, strap; void __iomem *map; @@ -373,13 +2381,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, if (nvkm_device_find_locked(handle)) goto done; - ret = nvkm_engine_ctor(&nvkm_device_func, device, 0, 0, - true, &device->engine); - device->engine.subdev.object.parent = NULL; device->func = func; - if (ret) - goto done; - device->quirk = quirk; switch (type) { case NVKM_BUS_PCI: @@ -395,9 +2397,14 @@ nvkm_device_ctor(const struct nvkm_device_func *func, device->cfgopt = cfg; device->dbgopt = dbg; device->name = name; - list_add_tail(&device->head, &nv_devices); + ret = nvkm_engine_ctor(&nvkm_device_func, device, 0, 0, + true, &device->engine); + device->engine.subdev.object.parent = NULL; + if (ret) + goto done; + ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); if (ret) goto done; @@ -482,12 +2489,83 @@ nvkm_device_ctor(const struct nvkm_device_func *func, break; } - if (ret) { + switch (!ret * device->chipset) { + case 0x004: device->chip = &nv4_chipset; break; + case 0x005: device->chip = &nv5_chipset; break; + case 0x010: device->chip = &nv10_chipset; break; + case 0x011: device->chip = &nv11_chipset; break; + case 0x015: device->chip = &nv15_chipset; break; + case 0x017: device->chip = &nv17_chipset; break; + case 0x018: device->chip = &nv18_chipset; break; + case 0x01a: device->chip = &nv1a_chipset; break; + case 0x01f: device->chip = &nv1f_chipset; break; + case 0x020: device->chip = &nv20_chipset; break; + case 0x025: device->chip = &nv25_chipset; break; + case 0x028: device->chip = &nv28_chipset; break; + case 0x02a: device->chip = &nv2a_chipset; break; + case 0x030: device->chip = &nv30_chipset; break; + case 0x031: device->chip = &nv31_chipset; break; + case 0x034: device->chip = &nv34_chipset; break; + case 0x035: device->chip = &nv35_chipset; break; + case 0x036: device->chip = &nv36_chipset; break; + case 0x040: device->chip = &nv40_chipset; break; + case 0x041: device->chip = &nv41_chipset; break; + case 0x042: device->chip = &nv42_chipset; break; + case 0x043: device->chip = &nv43_chipset; break; + case 0x044: device->chip = &nv44_chipset; break; + case 0x045: device->chip = &nv45_chipset; break; + case 0x046: device->chip = &nv46_chipset; break; + case 0x047: device->chip = &nv47_chipset; break; + case 0x049: device->chip = &nv49_chipset; break; + case 0x04a: device->chip = &nv4a_chipset; break; + case 0x04b: device->chip = &nv4b_chipset; break; + case 0x04c: device->chip = &nv4c_chipset; break; + case 0x04e: device->chip = &nv4e_chipset; break; + case 0x050: device->chip = &nv50_chipset; break; + case 0x063: device->chip = &nv63_chipset; break; + case 0x067: device->chip = &nv67_chipset; break; + case 0x068: device->chip = &nv68_chipset; break; + case 0x084: device->chip = &nv84_chipset; break; + case 0x086: device->chip = &nv86_chipset; break; + case 0x092: device->chip = &nv92_chipset; break; + case 0x094: device->chip = &nv94_chipset; break; + case 0x096: device->chip = &nv96_chipset; break; + case 0x098: device->chip = &nv98_chipset; break; + case 0x0a0: device->chip = &nva0_chipset; break; + case 0x0a3: device->chip = &nva3_chipset; break; + case 0x0a5: device->chip = &nva5_chipset; break; + case 0x0a8: device->chip = &nva8_chipset; break; + case 0x0aa: device->chip = &nvaa_chipset; break; + case 0x0ac: device->chip = &nvac_chipset; break; + case 0x0af: device->chip = &nvaf_chipset; break; + case 0x0c0: device->chip = &nvc0_chipset; break; + case 0x0c1: device->chip = &nvc1_chipset; break; + case 0x0c3: device->chip = &nvc3_chipset; break; + case 0x0c4: device->chip = &nvc4_chipset; break; + case 0x0c8: device->chip = &nvc8_chipset; break; + case 0x0ce: device->chip = &nvce_chipset; break; + case 0x0cf: device->chip = &nvcf_chipset; break; + case 0x0d7: device->chip = &nvd7_chipset; break; + case 0x0d9: device->chip = &nvd9_chipset; break; + case 0x0e4: device->chip = &nve4_chipset; break; + case 0x0e6: device->chip = &nve6_chipset; break; + case 0x0e7: device->chip = &nve7_chipset; break; + case 0x0ea: device->chip = &nvea_chipset; break; + case 0x0f0: device->chip = &nvf0_chipset; break; + case 0x0f1: device->chip = &nvf1_chipset; break; + case 0x106: device->chip = &nv106_chipset; break; + case 0x108: device->chip = &nv108_chipset; break; + case 0x117: device->chip = &nv117_chipset; break; + case 0x124: device->chip = &nv124_chipset; break; + case 0x126: device->chip = &nv126_chipset; break; + case 0x12b: device->chip = &nv12b_chipset; break; + default: nvdev_error(device, "unknown chipset (%08x)\n", boot0); goto done; } - nvdev_info(device, "NVIDIA %s (%08x)\n", device->cname, boot0); + nvdev_info(device, "NVIDIA %s (%08x)\n", + device->chip->name, boot0); /* determine frequency of timing crystal */ if ( device->card_type <= NV_10 || device->chipset < 0x17 || @@ -503,10 +2581,13 @@ nvkm_device_ctor(const struct nvkm_device_func *func, case 0x00400040: device->crystal = 25000; break; } } else { - device->cname = "NULL"; + device->chip = &null_chipset; device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass; } + if (!device->name) + device->name = device->chip->name; + if (mmio) { device->pri = ioremap(mmio_base, mmio_size); if (!device->pri) { @@ -523,6 +2604,72 @@ nvkm_device_ctor(const struct nvkm_device_func *func, atomic_set(&device->engine.subdev.object.usecount, 2); mutex_init(&device->mutex); + + for (i = 0; i < NVDEV_SUBDEV_NR; i++) { +#define _(s,m) case s: \ + if (device->chip->m && (subdev_mask & (1ULL << (s)))) { \ + ret = device->chip->m(device, (s), &device->m); \ + if (ret) { \ + subdev = nvkm_device_subdev(device, (s)); \ + nvkm_subdev_del(&subdev); \ + device->m = NULL; \ + if (ret != -ENODEV) { \ + nvdev_error(device, "%s ctor failed, %d\n", \ + nvkm_subdev_name[s], ret); \ + goto done; \ + } \ + } \ + } \ + break + switch (i) { + _(NVDEV_SUBDEV_BAR , bar); + _(NVDEV_SUBDEV_VBIOS , bios); + _(NVDEV_SUBDEV_BUS , bus); + _(NVDEV_SUBDEV_CLK , clk); + _(NVDEV_SUBDEV_DEVINIT, devinit); + _(NVDEV_SUBDEV_FB , fb); + _(NVDEV_SUBDEV_FUSE , fuse); + _(NVDEV_SUBDEV_GPIO , gpio); + _(NVDEV_SUBDEV_I2C , i2c); + _(NVDEV_SUBDEV_IBUS , ibus); + _(NVDEV_SUBDEV_INSTMEM, imem); + _(NVDEV_SUBDEV_LTC , ltc); + _(NVDEV_SUBDEV_MC , mc); + _(NVDEV_SUBDEV_MMU , mmu); + _(NVDEV_SUBDEV_MXM , mxm); + _(NVDEV_SUBDEV_PMU , pmu); + _(NVDEV_SUBDEV_THERM , therm); + _(NVDEV_SUBDEV_TIMER , timer); + _(NVDEV_SUBDEV_VOLT , volt); + _(NVDEV_ENGINE_BSP , bsp); + _(NVDEV_ENGINE_CE0 , ce[0]); + _(NVDEV_ENGINE_CE1 , ce[1]); + _(NVDEV_ENGINE_CE2 , ce[2]); + _(NVDEV_ENGINE_CIPHER , cipher); + _(NVDEV_ENGINE_DISP , disp); + _(NVDEV_ENGINE_DMAOBJ , dma); + _(NVDEV_ENGINE_FIFO , fifo); + _(NVDEV_ENGINE_GR , gr); + _(NVDEV_ENGINE_IFB , ifb); + _(NVDEV_ENGINE_ME , me); + _(NVDEV_ENGINE_MPEG , mpeg); + _(NVDEV_ENGINE_MSENC , msenc); + _(NVDEV_ENGINE_MSPDEC , mspdec); + _(NVDEV_ENGINE_MSPPP , msppp); + _(NVDEV_ENGINE_MSVLD , msvld); + _(NVDEV_ENGINE_PM , pm); + _(NVDEV_ENGINE_SEC , sec); + _(NVDEV_ENGINE_SW , sw); + _(NVDEV_ENGINE_VIC , vic); + _(NVDEV_ENGINE_VP , vp); + default: + WARN_ON(1); + continue; + } +#undef _ + } + + ret = 0; done: mutex_unlock(&nv_devices_mutex); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index d8ddd228491ab..cc152e78d0b22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -23,44 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - int gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->cname = "GF100"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -93,7 +60,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->cname = "GF104"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -126,7 +92,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->cname = "GF106"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -158,7 +123,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->cname = "GF114"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -191,7 +155,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->cname = "GF116"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -223,7 +186,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->cname = "GF108"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -255,7 +217,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->cname = "GF110"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -288,7 +249,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->cname = "GF119"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; @@ -320,7 +280,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->cname = "GF117"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 4e0d309443599..8811a40e87272 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -23,44 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - int gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->cname = "GK104"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; @@ -94,7 +61,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->cname = "GK107"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; @@ -128,7 +94,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->cname = "GK106"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; @@ -162,7 +127,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: - device->cname = "GK20A"; device->oclass[NVDEV_SUBDEV_CLK ] = &gk20a_clk_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; @@ -184,7 +148,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; break; case 0xf0: - device->cname = "GK110"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; @@ -218,7 +181,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->cname = "GK110B"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; @@ -252,7 +214,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->cname = "GK208B"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; @@ -285,7 +246,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->cname = "GK208"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index cd979543cdff2..41bfec2dd63aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -23,44 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - int gm100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x117: - device->cname = "GM107"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; @@ -100,7 +67,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x124: - device->cname = "GM204"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; @@ -141,7 +107,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x126: - device->cname = "GM206"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; @@ -182,7 +147,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x12b: - device->cname = "GM20B"; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index ec357da766e5d..5245b78794f98 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -23,29 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - int nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->cname = "NV04"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -63,7 +45,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: - device->cname = "NV05"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 37997e848d295..3794c53cfbda7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -23,30 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - int nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->cname = "NV10"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -63,7 +44,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->cname = "NV15"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -82,7 +62,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->cname = "NV16"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -101,7 +80,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->cname = "nForce"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -120,7 +98,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->cname = "NV11"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -139,7 +116,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->cname = "NV17"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -158,7 +134,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->cname = "nForce2"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -177,7 +152,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->cname = "NV18"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index a0d414dcc1fd1..9acdadeea0ca1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -23,31 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - int nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->cname = "NV20"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -66,7 +46,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->cname = "NV25"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -85,7 +64,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->cname = "NV28"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -104,7 +82,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->cname = "NV2A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index ea1739739e5f2..3d687d760601e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -23,31 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - int nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->cname = "NV30"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -66,7 +46,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->cname = "NV35"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -85,7 +64,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->cname = "NV31"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -105,7 +83,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->cname = "NV36"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -125,7 +102,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->cname = "NV34"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 9c7aa8d0ebd4c..35fb2f92d171d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -23,35 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - int nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->cname = "NV40"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -74,7 +50,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->cname = "NV41"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -97,7 +72,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->cname = "NV42"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -120,7 +94,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->cname = "NV43"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -143,7 +116,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->cname = "NV45"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -166,7 +138,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->cname = "G70"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -189,7 +160,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->cname = "G71"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -212,7 +182,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->cname = "G73"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -235,7 +204,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->cname = "NV44"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -258,7 +226,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->cname = "G72"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -281,7 +248,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->cname = "NV44A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -304,7 +270,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->cname = "C61"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -327,7 +292,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->cname = "C51"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; @@ -350,7 +314,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->cname = "C73"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -373,7 +336,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->cname = "C67"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; @@ -396,7 +358,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->cname = "C68"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 3c97dba02fc4e..56a443a1c74eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -23,46 +23,11 @@ */ #include "priv.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - int nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->cname = "G80"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; @@ -88,7 +53,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->cname = "G84"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; @@ -117,7 +81,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->cname = "G86"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; @@ -146,7 +109,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->cname = "G92"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; @@ -175,7 +137,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->cname = "G94"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -204,7 +165,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->cname = "G96"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -233,7 +193,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->cname = "G98"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -262,7 +221,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->cname = "G200"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; @@ -291,7 +249,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->cname = "MCP77/MCP78"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -320,7 +277,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->cname = "MCP79/MCP7A"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -349,7 +305,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->cname = "GT215"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -380,7 +335,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->cname = "GT216"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -410,7 +364,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->cname = "GT218"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; @@ -440,7 +393,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->cname = "MCP89"; device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index df9c1550301f4..59e9026624080 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -2,6 +2,42 @@ #define __NVKM_DEVICE_PRIV_H__ #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + int nvkm_device_ctor(const struct nvkm_device_func *, const struct nvkm_device_quirk *, void *, enum nv_bus_type type, u64 handle, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index cb3f3deefb018..0df54c6574690 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -107,8 +107,8 @@ nvkm_udevice_info(struct nvkm_object *object, void *data, u32 size) if (imem && args->v0.ram_size > 0) args->v0.ram_user = args->v0.ram_user - imem->reserved; - strncpy(args->v0.chip, device->cname, sizeof(args->v0.chip)); - strncpy(args->v0.name, device->cname, sizeof(args->v0.name)); + strncpy(args->v0.chip, device->chip->name, sizeof(args->v0.chip)); + strncpy(args->v0.name, device->name, sizeof(args->v0.name)); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 52f6a6e492167..ac39cb7e7299b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -138,7 +138,7 @@ _nvkm_falcon_init(struct nvkm_object *object) ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nvkm_error(subdev, "unable to load firmware data\n"); - return ret; + return -ENODEV; } falcon->data.data = vmemdup(fw->data, fw->size); @@ -153,7 +153,7 @@ _nvkm_falcon_init(struct nvkm_object *object) ret = request_firmware(&fw, name, nv_device_base(device)); if (ret) { nvkm_error(subdev, "unable to load firmware code\n"); - return ret; + return -ENODEV; } falcon->code.data = vmemdup(fw->data, fw->size); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 975a2547b8cd7..ba6b390a1fef4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -435,7 +435,7 @@ gf100_fifo_recover_work(struct work_struct *work) { struct gf100_fifo *fifo = container_of(work, typeof(*fifo), fault); struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_object *engine; + struct nvkm_engine *engine; unsigned long flags; u32 engn, engm = 0; u64 mask, todo; @@ -450,9 +450,9 @@ gf100_fifo_recover_work(struct work_struct *work) nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = (void *)nvkm_engine(fifo, engn))) { - nvkm_object_fini(engine, false); - WARN_ON(nvkm_object_init(engine)); + if ((engine = nvkm_device_engine(device, engn))) { + nvkm_subdev_fini(&engine->subdev, false); + WARN_ON(nvkm_subdev_init(&engine->subdev)); } } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 216205cdf115e..62b3de4e9353d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -481,7 +481,7 @@ gk104_fifo_recover_work(struct work_struct *work) { struct gk104_fifo *fifo = container_of(work, typeof(*fifo), fault); struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_object *engine; + struct nvkm_engine *engine; unsigned long flags; u32 engn, engm = 0; u64 mask, todo; @@ -496,9 +496,9 @@ gk104_fifo_recover_work(struct work_struct *work) nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { - if ((engine = (void *)nvkm_engine(fifo, engn))) { - nvkm_object_fini(engine, false); - WARN_ON(nvkm_object_init(engine)); + if ((engine = nvkm_device_engine(device, engn))) { + nvkm_subdev_fini(&engine->subdev, false); + WARN_ON(nvkm_subdev_init(&engine->subdev)); } gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn)); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 6afdb20cf304e..1e712355a70b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1601,7 +1601,7 @@ gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, int i; /* Convert device name to lowercase */ - strncpy(cname, device->cname, sizeof(cname)); + strncpy(cname, device->chip->name, sizeof(cname)); cname[sizeof(cname) - 1] = '\0'; i = strlen(cname); while (i) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index a441fd3b69bc1..b3ae0d96ddb05 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -638,8 +638,8 @@ nvkm_perfctx_dtor(struct nvkm_object *object) struct nvkm_pm *pm = (void *)object->engine; struct nvkm_perfctx *ctx = (void *)object; - mutex_lock(&nv_subdev(pm)->mutex); nvkm_gpuobj_destroy(&ctx->base); + mutex_lock(&nv_subdev(pm)->mutex); if (pm->context == ctx) pm->context = NULL; mutex_unlock(&nv_subdev(pm)->mutex); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c index 3b57f50db4dec..ab6aecf29f4b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c @@ -40,8 +40,8 @@ nv04_bus_intr(struct nvkm_subdev *subdev) if (stat & 0x00000110) { struct nvkm_gpio *gpio = device->gpio; - if (gpio && gpio->subdev.intr) - gpio->subdev.intr(&gpio->subdev); + if (gpio) + nvkm_subdev_intr(&gpio->subdev); stat &= ~0x00000110; nvkm_wr32(device, 0x001100, 0x00000110); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c index e99d7a20f90ee..2e5340a2c94d1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c @@ -36,8 +36,8 @@ nv31_bus_intr(struct nvkm_subdev *subdev) if (gpio) { struct nvkm_gpio *gpio = device->gpio; - if (gpio && gpio->subdev.intr) - gpio->subdev.intr(&gpio->subdev); + if (gpio) + nvkm_subdev_intr(&gpio->subdev); } if (stat & 0x00000008) { /* NV41- */ @@ -54,8 +54,8 @@ nv31_bus_intr(struct nvkm_subdev *subdev) if (stat & 0x00070000) { struct nvkm_therm *therm = device->therm; - if (therm && therm->subdev.intr) - therm->subdev.intr(&therm->subdev); + if (therm) + nvkm_subdev_intr(&therm->subdev); stat &= ~0x00070000; nvkm_wr32(device, 0x001100, 0x00070000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index 47d1e436bd44f..3948ec73d31a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -69,8 +69,8 @@ nv50_bus_intr(struct nvkm_subdev *subdev) if (stat & 0x00010000) { struct nvkm_therm *therm = device->therm; - if (therm && therm->subdev.intr) - therm->subdev.intr(&therm->subdev); + if (therm) + nvkm_subdev_intr(&therm->subdev); stat &= ~0x00010000; nvkm_wr32(device, 0x001100, 0x00010000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index f861a02d8d59f..ee4c34f4b9c48 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -65,8 +65,8 @@ nvkm_mc_intr(int irq, void *arg) while (map->stat) { if (intr & map->stat) { unit = nvkm_subdev(mc, map->unit); - if (unit && unit->intr) - unit->intr(unit); + if (unit) + nvkm_subdev_intr(unit); stat &= ~map->stat; } map++; -- GitLab From 524bdbf2025d44cdea672511d21012a52b427374 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5490/7006] drm/nouveau/core: prepare for new-style objects Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/client.h | 11 +- .../drm/nouveau/include/nvkm/core/handle.h | 2 +- drivers/gpu/drm/nouveau/nvkm/core/client.c | 3 +- drivers/gpu/drm/nouveau/nvkm/core/engctx.c | 2 +- drivers/gpu/drm/nouveau/nvkm/core/handle.c | 48 ++++---- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 111 ++++++++++++++++-- drivers/gpu/drm/nouveau/nvkm/core/namedb.c | 8 +- 7 files changed, 135 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index dd0db88f8213f..ff6331d7e9e67 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -23,13 +23,12 @@ void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *); struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle); static inline struct nvkm_client * -nvkm_client(void *obj) +nvkm_client(struct nvkm_object *object) { - struct nvkm_object *client = nv_object(obj); - while (client && client->parent) - client = client->parent; - if (client && nv_iclass(client, NV_CLIENT_CLASS)) - return (void *)client; + while (object && object->parent) + object = object->parent; + if (object && nv_iclass(object, NV_CLIENT_CLASS)) + return container_of(object, struct nvkm_client, namedb.parent.object); return NULL; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h index 64f9e62168ff2..88e8bb17a280c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h @@ -22,7 +22,7 @@ struct nvkm_handle { u64 handle; }; -int nvkm_handle_create(struct nvkm_object *, u32 parent, u32 handle, +int nvkm_handle_create(struct nvkm_handle *, u32 handle, struct nvkm_object *, struct nvkm_handle **); void nvkm_handle_destroy(struct nvkm_handle *); int nvkm_handle_init(struct nvkm_handle *); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index bfe5357d73348..9a7c4bc24a767 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -294,8 +294,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, if (ret) return ret; - ret = nvkm_handle_create(nv_object(client), ~0, ~0, nv_object(client), - &client->root); + ret = nvkm_handle_create(NULL, ~0, nv_object(client), &client->root); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c index c9c5787493382..be640fd24f77b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c @@ -104,7 +104,7 @@ void nvkm_engctx_destroy(struct nvkm_engctx *engctx) { struct nvkm_engine *engine = engctx->gpuobj.object.engine; - struct nvkm_client *client = nvkm_client(engctx); + struct nvkm_client *client = nvkm_client(&engctx->gpuobj.object); unsigned long save; nvkm_gpuobj_unmap(&engctx->vma); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index a12ab80017018..0c7cde900df60 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -94,15 +94,15 @@ fail: } int -nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle, +nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, struct nvkm_object *object, struct nvkm_handle **phandle) { struct nvkm_object *namedb; struct nvkm_handle *handle; int ret; - namedb = parent; - while (!nv_iclass(namedb, NV_NAMEDB_CLASS)) + namedb = parent ? parent->object : NULL; + while (namedb && !nv_iclass(namedb, NV_NAMEDB_CLASS)) namedb = namedb->parent; handle = kzalloc(sizeof(*handle), GFP_KERNEL); @@ -114,32 +114,32 @@ nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle, handle->name = _handle; handle->priv = ~0; RB_CLEAR_NODE(&handle->rb); - - ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, object, handle); - if (ret) { - kfree(handle); - return ret; - } - - if (nv_parent(parent)->object_attach) { - ret = nv_parent(parent)->object_attach(parent, object, _handle); - if (ret < 0) { - nvkm_handle_destroy(handle); + handle->parent = parent; + nvkm_object_ref(object, &handle->object); + + if (namedb) { + ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, + object, handle); + if (ret) { + kfree(handle); return ret; } - - handle->priv = ret; } - if (object != namedb) { - while (!nv_iclass(namedb, NV_CLIENT_CLASS)) - namedb = namedb->parent; - - handle->parent = nvkm_namedb_get(nv_namedb(namedb), _parent); - if (handle->parent) { - list_add(&handle->head, &handle->parent->tree); - nvkm_namedb_put(handle->parent); + if (parent) { + if (nv_iclass(parent->object, NV_PARENT_CLASS) && + nv_parent(parent->object)->object_attach) { + ret = nv_parent(parent->object)-> + object_attach(parent->object, object, _handle); + if (ret < 0) { + nvkm_handle_destroy(handle); + return ret; + } + + handle->priv = ret; } + + list_add(&handle->head, &handle->parent->tree); } hprintk(handle, TRACE, "created\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index d9c26e40ae320..b9c8136904338 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -55,34 +55,45 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) union { struct nvif_ioctl_sclass_v0 v0; } *args = data; - int ret; + struct nvkm_oclass oclass; + int ret, i = 0; nvif_ioctl(object, "sclass size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(object, "sclass vers %d count %d\n", args->v0.version, args->v0.count); - if (size == args->v0.count * sizeof(args->v0.oclass[0])) { + if (size != args->v0.count * sizeof(args->v0.oclass[0])) + return -EINVAL; + + if (object->oclass) { if (nv_iclass(object, NV_PARENT_CLASS)) { ret = nvkm_parent_lclass(object, args->v0.oclass, args->v0.count); - } else { - ret = 0; } - if (ret >= 0) { - args->v0.count = ret; - ret = 0; + + args->v0.count = ret; + return 0; + } + + while (object->func->sclass && + object->func->sclass(object, i, &oclass) >= 0) { + if (i < args->v0.count) { + args->v0.oclass[i].oclass = oclass.base.oclass; + args->v0.oclass[i].minver = oclass.base.minver; + args->v0.oclass[i].maxver = oclass.base.maxver; } - } else { - ret = -EINVAL; + i++; } + + args->v0.count = i; } return ret; } static int -nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_new_old(struct nvkm_handle *handle, void *data, u32 size) { union { struct nvif_ioctl_new_v0 v0; @@ -152,7 +163,6 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) /* finally, create new object and bind it to its handle */ ret = nvkm_object_old(engctx, &engine->subdev.object, oclass, data, size, &object); - client->data = object; if (ret) goto fail_ctor; @@ -162,8 +172,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) if (ret) goto fail_init; - ret = nvkm_handle_create(&parent->object, handle->name, - _handle, object, &handle); + ret = nvkm_handle_create(handle, _handle, object, &handle); if (ret) goto fail_handle; @@ -175,6 +184,7 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) handle->handle = args->v0.object; nvkm_client_insert(client, handle); + client->data = object; fail_handle: nvkm_object_dec(object, false); fail_init: @@ -187,6 +197,81 @@ fail_class: return ret; } +static int +nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) +{ + union { + struct nvif_ioctl_new_v0 v0; + } *args = data; + struct nvkm_client *client = handle->object->client; + struct nvkm_object *parent = handle->object; + struct nvkm_object *object = NULL; + struct nvkm_oclass oclass; + int ret, i = 0; + + if (parent->oclass) + return nvkm_ioctl_new_old(handle, data, size); + + nvif_ioctl(parent, "new size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nvif_ioctl(parent, "new vers %d handle %08x class %08x " + "route %02x token %llx object %016llx\n", + args->v0.version, args->v0.handle, args->v0.oclass, + args->v0.route, args->v0.token, args->v0.object); + } else + return ret; + + if (!parent->func->sclass) { + nvif_ioctl(parent, "cannot have children\n"); + return -EINVAL; + } + + do { + memset(&oclass, 0x00, sizeof(oclass)); + oclass.client = client; + oclass.handle = args->v0.handle; + oclass.object = args->v0.object; + oclass.parent = parent; + ret = parent->func->sclass(parent, i++, &oclass); + if (ret) + return ret; + } while (oclass.base.oclass != args->v0.oclass); + + if (oclass.engine) { + oclass.engine = nvkm_engine_ref(oclass.engine); + if (IS_ERR(oclass.engine)) + return PTR_ERR(oclass.engine); + } + + ret = oclass.ctor(&oclass, data, size, &object); + if (ret) + goto fail_object; + + ret = nvkm_object_inc(object); + if (ret) + goto fail_object; + + ret = nvkm_handle_create(handle, args->v0.handle, object, &handle); + if (ret) + goto fail_handle; + + ret = nvkm_handle_init(handle); + handle->route = args->v0.route; + handle->token = args->v0.token; + if (ret) + nvkm_handle_destroy(handle); + + handle->handle = args->v0.object; + nvkm_client_insert(client, handle); + client->data = object; +fail_handle: + nvkm_object_dec(object, false); +fail_object: + nvkm_object_ref(NULL, &object); + nvkm_engine_unref(&oclass.engine); + return ret; +} + static int nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c index ca625c527c57a..9be1ce9670346 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c @@ -104,9 +104,11 @@ nvkm_namedb_remove(struct nvkm_handle *handle) { struct nvkm_namedb *namedb = handle->namedb; struct nvkm_object *object = handle->object; - write_lock_irq(&namedb->lock); - list_del(&handle->node); - write_unlock_irq(&namedb->lock); + if (handle->namedb) { + write_lock_irq(&namedb->lock); + list_del(&handle->node); + write_unlock_irq(&namedb->lock); + } nvkm_object_ref(NULL, &object); } -- GitLab From 1de68568d69ac518db076cc6118af91e930b5f90 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5491/7006] drm/nouveau/mmu: protect each vm with its own mutex An upcoming commit requires being able to modify the PRAMIN BAR page tables while already holding the MMU subdev mutex. To solve this issue, each VM has been given its own mutex. As a nice side-effect, this also allows separate VMs to be updated concurrently. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 11 +++-- drivers/gpu/drm/nouveau/nouveau_drm.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 11 +++-- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 6 ++- .../gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 46 +++++++------------ .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 6 +-- 10 files changed, 46 insertions(+), 50 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 2bf8f46c1bb05..0991c9011dc19 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -26,6 +26,8 @@ struct nvkm_vma { struct nvkm_vm { struct nvkm_mmu *mmu; + + struct mutex mutex; struct nvkm_mm mm; struct kref refcount; @@ -47,7 +49,8 @@ struct nvkm_mmu { u8 lpg_shift; int (*create)(struct nvkm_mmu *, u64 offset, u64 length, - u64 mm_offset, struct nvkm_vm **); + u64 mm_offset, struct lock_class_key *, + struct nvkm_vm **); void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2]); @@ -85,14 +88,14 @@ extern struct nvkm_oclass nv44_mmu_oclass; extern struct nvkm_oclass nv50_mmu_oclass; extern struct nvkm_oclass gf100_mmu_oclass; -int nv04_vm_create(struct nvkm_mmu *, u64, u64, u64, +int nv04_vm_create(struct nvkm_mmu *, u64, u64, u64, struct lock_class_key *, struct nvkm_vm **); void nv04_mmu_dtor(struct nvkm_object *); int nvkm_vm_create(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset, - u32 block, struct nvkm_vm **); + u32 block, struct lock_class_key *, struct nvkm_vm **); int nvkm_vm_new(struct nvkm_device *, u64 offset, u64 length, u64 mm_offset, - struct nvkm_vm **); + struct lock_class_key *, struct nvkm_vm **); int nvkm_vm_ref(struct nvkm_vm *, struct nvkm_vm **, struct nvkm_gpuobj *pgd); int nvkm_vm_get(struct nvkm_vm *, u64 size, u32 page_shift, u32 access, struct nvkm_vma *); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index e638ae7c00c25..650e911dd7042 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -416,7 +416,7 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40), - 0x1000, &drm->client.vm); + 0x1000, NULL, &drm->client.vm); if (ret) goto fail_device; @@ -809,7 +809,7 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv) if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40), - 0x1000, &cli->vm); + 0x1000, NULL, &cli->vm); if (ret) { nouveau_cli_destroy(cli); goto out_suspend; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index b997d8d128c53..01e26213fd88c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -77,9 +77,10 @@ gf100_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) nvkm_vm_put(vma); } + static int gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, - int bar_nr) + struct lock_class_key *key, int bar_nr) { struct nvkm_device *device = nv_device(&bar->base); struct nvkm_vm *vm; @@ -98,7 +99,7 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, bar_len = nv_device_resource_len(device, bar_nr); - ret = nvkm_vm_new(device, 0, bar_len, 0, &vm); + ret = nvkm_vm_new(device, 0, bar_len, 0, key, &vm); if (ret) return ret; @@ -136,6 +137,8 @@ gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + static struct lock_class_key bar1_lock; + static struct lock_class_key bar3_lock; struct nvkm_device *device = nv_device(parent); struct gf100_bar *bar; bool has_bar3 = nv_device_resource_len(device, 3) != 0; @@ -148,13 +151,13 @@ gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* BAR3 */ if (has_bar3) { - ret = gf100_bar_ctor_vm(bar, &bar->bar[0], 3); + ret = gf100_bar_ctor_vm(bar, &bar->bar[0], &bar3_lock, 3); if (ret) return ret; } /* BAR1 */ - ret = gf100_bar_ctor_vm(bar, &bar->bar[1], 1); + ret = gf100_bar_ctor_vm(bar, &bar->bar[1], &bar1_lock, 1); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 6909e52a6d8d7..cb58cc5b2b579 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -112,6 +112,8 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + static struct lock_class_key bar1_lock; + static struct lock_class_key bar3_lock; struct nvkm_device *device = nv_device(parent); struct nvkm_object *heap; struct nvkm_vm *vm; @@ -144,7 +146,7 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, start = 0x0100000000ULL; limit = start + nv_device_resource_len(device, 3); - ret = nvkm_vm_new(device, start, limit, start, &vm); + ret = nvkm_vm_new(device, start, limit, start, &bar3_lock, &vm); if (ret) return ret; @@ -180,7 +182,7 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, start = 0x0000000000ULL; limit = start + nv_device_resource_len(device, 1); - ret = nvkm_vm_new(device, start, limit--, start, &vm); + ret = nvkm_vm_new(device, start, limit--, start, &bar1_lock, &vm); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 277b6ec04e244..e81d3170325f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -240,9 +240,7 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde) mmu->map_pgt(vpgd->obj, pde, vpgt->obj); } - mutex_unlock(&nv_subdev(mmu)->mutex); nvkm_gpuobj_ref(NULL, &pgt); - mutex_lock(&nv_subdev(mmu)->mutex); } } @@ -252,7 +250,6 @@ nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type) struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; struct nvkm_vm_pgd *vpgd; - struct nvkm_gpuobj *pgt; int big = (type != mmu->spg_shift); u32 pgt_size; int ret; @@ -260,26 +257,16 @@ nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type) pgt_size = (1 << (mmu->pgt_bits + 12)) >> type; pgt_size *= 8; - mutex_unlock(&nv_subdev(mmu)->mutex); ret = nvkm_gpuobj_new(nv_object(vm->mmu), NULL, pgt_size, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &pgt); - mutex_lock(&nv_subdev(mmu)->mutex); + NVOBJ_FLAG_ZERO_ALLOC, &vpgt->obj[big]); if (unlikely(ret)) return ret; - /* someone beat us to filling the PDE while we didn't have the lock */ - if (unlikely(vpgt->refcount[big]++)) { - mutex_unlock(&nv_subdev(mmu)->mutex); - nvkm_gpuobj_ref(NULL, &pgt); - mutex_lock(&nv_subdev(mmu)->mutex); - return 0; - } - - vpgt->obj[big] = pgt; list_for_each_entry(vpgd, &vm->pgd_list, head) { mmu->map_pgt(vpgd->obj, pde, vpgt->obj); } + vpgt->refcount[big]++; return 0; } @@ -293,11 +280,11 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, u32 fpde, lpde, pde; int ret; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); ret = nvkm_mm_head(&vm->mm, 0, page_shift, msize, msize, align, &vma->node); if (unlikely(ret != 0)) { - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); return ret; } @@ -318,11 +305,11 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, if (pde != fpde) nvkm_vm_unmap_pgt(vm, big, fpde, pde - 1); nvkm_mm_free(&vm->mm, &vma->node); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); return ret; } } - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); vma->vm = NULL; nvkm_vm_ref(vm, &vma->vm, NULL); @@ -343,18 +330,19 @@ nvkm_vm_put(struct nvkm_vma *vma) fpde = (vma->node->offset >> mmu->pgt_bits); lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->spg_shift, fpde, lpde); nvkm_mm_free(&vm->mm, &vma->node); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); nvkm_vm_ref(NULL, &vma->vm, NULL); } int nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, - u32 block, struct nvkm_vm **pvm) + u32 block, struct lock_class_key *key, struct nvkm_vm **pvm) { + static struct lock_class_key _key; struct nvkm_vm *vm; u64 mm_length = (offset + length) - mm_offset; int ret; @@ -363,6 +351,7 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, if (!vm) return -ENOMEM; + __mutex_init(&vm->mutex, "&vm->mutex", key ? key : &_key); INIT_LIST_HEAD(&vm->pgd_list); vm->mmu = mmu; kref_init(&vm->refcount); @@ -390,10 +379,10 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, int nvkm_vm_new(struct nvkm_device *device, u64 offset, u64 length, u64 mm_offset, - struct nvkm_vm **pvm) + struct lock_class_key *key, struct nvkm_vm **pvm) { struct nvkm_mmu *mmu = nvkm_mmu(device); - return mmu->create(mmu, offset, length, mm_offset, pvm); + return mmu->create(mmu, offset, length, mm_offset, key, pvm); } static int @@ -412,25 +401,24 @@ nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd) nvkm_gpuobj_ref(pgd, &vpgd->obj); - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); for (i = vm->fpde; i <= vm->lpde; i++) mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); list_add(&vpgd->head, &vm->pgd_list); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); return 0; } static void nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd) { - struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgd *vpgd, *tmp; struct nvkm_gpuobj *pgd = NULL; if (!mpgd) return; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&vm->mutex); list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { if (vpgd->obj == mpgd) { pgd = vpgd->obj; @@ -439,7 +427,7 @@ nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd) break; } } - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&vm->mutex); nvkm_gpuobj_ref(NULL, &pgd); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 13798fdac1a80..e801e57946ad8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -197,9 +197,9 @@ gf100_vm_flush(struct nvkm_vm *vm) static int gf100_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, - struct nvkm_vm **pvm) + struct lock_class_key *key, struct nvkm_vm **pvm) { - return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, pvm); + return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, key, pvm); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index 57b13d2a348ca..b30a865a40710 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -74,7 +74,7 @@ nv04_vm_flush(struct nvkm_vm *vm) int nv04_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mmstart, - struct nvkm_vm **pvm) + struct lock_class_key *key, struct nvkm_vm **pvm) { return -EINVAL; } @@ -108,7 +108,7 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mmu->base.unmap = nv04_vm_unmap; mmu->base.flush = nv04_vm_flush; - ret = nvkm_vm_create(&mmu->base, 0, NV04_PDMA_SIZE, 0, 4096, + ret = nvkm_vm_create(&mmu->base, 0, NV04_PDMA_SIZE, 0, 4096, NULL, &mmu->vm); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 26192b91e456d..6fd74f1f7290d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -116,7 +116,7 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mmu->base.unmap = nv41_vm_unmap; mmu->base.flush = nv41_vm_flush; - ret = nvkm_vm_create(&mmu->base, 0, NV41_GART_SIZE, 0, 4096, + ret = nvkm_vm_create(&mmu->base, 0, NV41_GART_SIZE, 0, 4096, NULL, &mmu->vm); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 3e51dc772536d..ef53dfa356bb0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -195,7 +195,7 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mmu->null = 0; } - ret = nvkm_vm_create(&mmu->base, 0, NV44_GART_SIZE, 0, 4096, + ret = nvkm_vm_create(&mmu->base, 0, NV44_GART_SIZE, 0, 4096, NULL, &mmu->vm); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index cec41ca80f4b9..b87fef9ee1988 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -201,14 +201,14 @@ nv50_vm_flush(struct nvkm_vm *vm) } static int -nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, - u64 mm_offset, struct nvkm_vm **pvm) +nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, + struct lock_class_key *key, struct nvkm_vm **pvm) { u32 block = (1 << (mmu->pgt_bits + 12)); if (block > length) block = length; - return nvkm_vm_create(mmu, offset, length, mm_offset, block, pvm); + return nvkm_vm_create(mmu, offset, length, mm_offset, block, key, pvm); } static int -- GitLab From d8e83994aaf6749b7124a219f5b46bd1329e2a08 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5492/7006] drm/nouveau/imem: improve management of instance memory Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/gpuobj.h | 33 +-- .../drm/nouveau/include/nvkm/core/memory.h | 53 ++++ .../gpu/drm/nouveau/include/nvkm/subdev/bar.h | 9 +- .../drm/nouveau/include/nvkm/subdev/instmem.h | 27 +- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 1 + drivers/gpu/drm/nouveau/nouveau_bo.c | 6 +- drivers/gpu/drm/nouveau/nvkm/core/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 133 ++++++---- drivers/gpu/drm/nouveau/nvkm/core/memory.c | 64 +++++ drivers/gpu/drm/nouveau/nvkm/core/ramht.c | 8 - .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 9 - .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 9 - .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 9 - .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 11 - .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 3 - .../gpu/drm/nouveau/nvkm/subdev/bar/base.c | 90 ------- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 43 +-- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 32 +-- .../gpu/drm/nouveau/nvkm/subdev/bar/priv.h | 3 - .../drm/nouveau/nvkm/subdev/instmem/base.c | 244 ++++++++++++++---- .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 214 ++++++++------- .../drm/nouveau/nvkm/subdev/instmem/nv04.c | 160 +++++++----- .../drm/nouveau/nvkm/subdev/instmem/nv04.h | 36 --- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 146 ++++++++++- .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 198 ++++++++++---- .../drm/nouveau/nvkm/subdev/instmem/priv.h | 31 +-- .../gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 19 ++ .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 4 - .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 4 - 34 files changed, 968 insertions(+), 656 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/memory.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/core/memory.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index 2260aef3ec3e8..4e4a9964d235b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -1,6 +1,7 @@ #ifndef __NVKM_GPUOBJ_H__ #define __NVKM_GPUOBJ_H__ #include +#include #include struct nvkm_vma; struct nvkm_vm; @@ -11,13 +12,23 @@ struct nvkm_vm; struct nvkm_gpuobj { struct nvkm_object object; - struct nvkm_object *parent; + struct nvkm_memory *memory; + struct nvkm_gpuobj *parent; struct nvkm_mm_node *node; struct nvkm_mm heap; u32 flags; u64 addr; u32 size; + + const struct nvkm_gpuobj_func *func; +}; + +struct nvkm_gpuobj_func { + void (*acquire)(struct nvkm_gpuobj *); + void (*release)(struct nvkm_gpuobj *); + u32 (*rd32)(struct nvkm_gpuobj *, u32 offset); + void (*wr32)(struct nvkm_gpuobj *, u32 offset, u32 data); }; static inline struct nvkm_gpuobj * @@ -60,24 +71,4 @@ int _nvkm_gpuobj_init(struct nvkm_object *); int _nvkm_gpuobj_fini(struct nvkm_object *, bool); u32 _nvkm_gpuobj_rd32(struct nvkm_object *, u64); void _nvkm_gpuobj_wr32(struct nvkm_object *, u64, u32); - -/* accessor macros - kmap()/done() must bracket use of the other accessor - * macros to guarantee correct behaviour across all chipsets - */ -#define nvkm_kmap(o) do { \ - struct nvkm_gpuobj *_gpuobj = (o); \ - (void)_gpuobj; \ -} while(0) -#define nvkm_ro32(o,a) ({ \ - u32 _data; \ - nvkm_object_rd32(&(o)->object, (a), &_data); \ - _data; \ -}) -#define nvkm_wo32(o,a,d) nvkm_object_wr32(&(o)->object, (a), (d)) -#define nvkm_mo32(o,a,m,d) ({ \ - u32 _addr = (a), _data = nvkm_ro32((o), _addr); \ - nvkm_wo32((o), _addr, (_data & ~(m)) | (d)); \ - _data; \ -}) -#define nvkm_done(o) nvkm_kmap(o) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h new file mode 100644 index 0000000000000..9363b839a9da0 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/memory.h @@ -0,0 +1,53 @@ +#ifndef __NVKM_MEMORY_H__ +#define __NVKM_MEMORY_H__ +#include +struct nvkm_device; +struct nvkm_vma; +struct nvkm_vm; + +enum nvkm_memory_target { + NVKM_MEM_TARGET_INST, + NVKM_MEM_TARGET_VRAM, + NVKM_MEM_TARGET_HOST, +}; + +struct nvkm_memory { + const struct nvkm_memory_func *func; +}; + +struct nvkm_memory_func { + void *(*dtor)(struct nvkm_memory *); + enum nvkm_memory_target (*target)(struct nvkm_memory *); + u64 (*addr)(struct nvkm_memory *); + u64 (*size)(struct nvkm_memory *); + void (*boot)(struct nvkm_memory *, struct nvkm_vm *); + void __iomem *(*acquire)(struct nvkm_memory *); + void (*release)(struct nvkm_memory *); + u32 (*rd32)(struct nvkm_memory *, u64 offset); + void (*wr32)(struct nvkm_memory *, u64 offset, u32 data); + void (*map)(struct nvkm_memory *, struct nvkm_vma *, u64 offset); +}; + +void nvkm_memory_ctor(const struct nvkm_memory_func *, struct nvkm_memory *); +int nvkm_memory_new(struct nvkm_device *, enum nvkm_memory_target, + u64 size, u32 align, bool zero, struct nvkm_memory **); +void nvkm_memory_del(struct nvkm_memory **); +#define nvkm_memory_target(p) (p)->func->target(p) +#define nvkm_memory_addr(p) (p)->func->addr(p) +#define nvkm_memory_size(p) (p)->func->size(p) +#define nvkm_memory_boot(p,v) (p)->func->boot((p),(v)) +#define nvkm_memory_map(p,v,o) (p)->func->map((p),(v),(o)) + +/* accessor macros - kmap()/done() must bracket use of the other accessor + * macros to guarantee correct behaviour across all chipsets + */ +#define nvkm_kmap(o) (o)->func->acquire(o) +#define nvkm_ro32(o,a) (o)->func->rd32((o), (a)) +#define nvkm_wo32(o,a,d) (o)->func->wr32((o), (a), (d)) +#define nvkm_mo32(o,a,m,d) ({ \ + u32 _addr = (a), _data = nvkm_ro32((o), _addr); \ + nvkm_wo32((o), _addr, (_data & ~(m)) | (d)); \ + _data; \ +}) +#define nvkm_done(o) (o)->func->release(o) +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h index 753b7e9530351..1eaf7de79d507 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h @@ -7,13 +7,8 @@ struct nvkm_vma; struct nvkm_bar { struct nvkm_subdev subdev; - int (*alloc)(struct nvkm_bar *, struct nvkm_object *, - struct nvkm_mem *, struct nvkm_object **); - - int (*kmap)(struct nvkm_bar *, struct nvkm_mem *, u32 flags, - struct nvkm_vma *); - int (*umap)(struct nvkm_bar *, struct nvkm_mem *, u32 flags, - struct nvkm_vma *); + struct nvkm_vm *(*kmap)(struct nvkm_bar *); + int (*umap)(struct nvkm_bar *, u64 size, int type, struct nvkm_vma *); void (*unmap)(struct nvkm_bar *, struct nvkm_vma *); void (*flush)(struct nvkm_bar *); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index 7ba3ff27e89ec..2e9e6f058dc08 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -1,33 +1,22 @@ #ifndef __NVKM_INSTMEM_H__ #define __NVKM_INSTMEM_H__ #include - -struct nvkm_instobj { - struct nvkm_object object; - struct list_head head; - u32 *suspend; - u64 addr; - u32 size; -}; - -static inline struct nvkm_instobj * -nv_memobj(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_MEMOBJ_CLASS)); -#endif - return obj; -} +struct nvkm_memory; struct nvkm_instmem { struct nvkm_subdev subdev; struct list_head list; u32 reserved; - int (*alloc)(struct nvkm_instmem *, struct nvkm_object *, - u32 size, u32 align, struct nvkm_object **); + int (*alloc)(struct nvkm_instmem *, u32 size, u32 align, bool zero, + struct nvkm_memory **); const struct nvkm_instmem_func *func; + + struct nvkm_gpuobj *vbios; + struct nvkm_ramht *ramht; + struct nvkm_gpuobj *ramro; + struct nvkm_gpuobj *ramfc; }; struct nvkm_instmem_func { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 0991c9011dc19..677f6c0cbb9b7 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -97,6 +97,7 @@ int nvkm_vm_create(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset, int nvkm_vm_new(struct nvkm_device *, u64 offset, u64 length, u64 mm_offset, struct lock_class_key *, struct nvkm_vm **); int nvkm_vm_ref(struct nvkm_vm *, struct nvkm_vm **, struct nvkm_gpuobj *pgd); +int nvkm_vm_boot(struct nvkm_vm *, u64 size); int nvkm_vm_get(struct nvkm_vm *, u64 size, u32 page_shift, u32 access, struct nvkm_vma *); void nvkm_vm_put(struct nvkm_vma *); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 496c00d585cd2..982c0ed163ebd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1388,12 +1388,16 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) mem->bus.is_iomem = true; if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { struct nvkm_bar *bar = nvxx_bar(&drm->device); + int page_shift = 12; + if (drm->device.info.family >= NV_DEVICE_INFO_V0_FERMI) + page_shift = node->page_shift; - ret = bar->umap(bar, node, NV_MEM_ACCESS_RW, + ret = bar->umap(bar, node->size << 12, page_shift, &node->bar_vma); if (ret) return ret; + nvkm_vm_map(&node->bar_vma, node); mem->bus.offset = node->bar_vma.offset; } break; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index c4198164bc591..98cf39f732c14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -6,6 +6,7 @@ nvkm-y += nvkm/core/event.o nvkm-y += nvkm/core/gpuobj.o nvkm-y += nvkm/core/handle.o nvkm-y += nvkm/core/ioctl.o +nvkm-y += nvkm/core/memory.o nvkm-y += nvkm/core/mm.o nvkm-y += nvkm/core/namedb.o nvkm-y += nvkm/core/notify.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index bc4b3c2d075e6..0370360698395 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -28,6 +28,44 @@ #include #include +static void +nvkm_gpuobj_release(struct nvkm_gpuobj *gpuobj) +{ + if (gpuobj->node) { + nvkm_done(gpuobj->parent); + return; + } + nvkm_done(gpuobj->memory); +} + +static void +nvkm_gpuobj_acquire(struct nvkm_gpuobj *gpuobj) +{ + if (gpuobj->node) { + nvkm_kmap(gpuobj->parent); + return; + } + nvkm_kmap(gpuobj->memory); +} + +static u32 +nvkm_gpuobj_rd32(struct nvkm_gpuobj *gpuobj, u32 offset) +{ + if (gpuobj->node) + return nvkm_ro32(gpuobj->parent, gpuobj->node->offset + offset); + return nvkm_ro32(gpuobj->memory, offset); +} + +static void +nvkm_gpuobj_wr32(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data) +{ + if (gpuobj->node) { + nvkm_wo32(gpuobj->parent, gpuobj->node->offset + offset, data); + return; + } + nvkm_wo32(gpuobj->memory, offset, data); +} + void nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) { @@ -46,17 +84,27 @@ nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) if (gpuobj->heap.block_size) nvkm_mm_fini(&gpuobj->heap); + nvkm_memory_del(&gpuobj->memory); nvkm_object_destroy(&gpuobj->object); } +static const struct nvkm_gpuobj_func +nvkm_gpuobj_func = { + .acquire = nvkm_gpuobj_acquire, + .release = nvkm_gpuobj_release, + .rd32 = nvkm_gpuobj_rd32, + .wr32 = nvkm_gpuobj_wr32, +}; + int nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 pclass, - struct nvkm_object *pargpu, u32 size, u32 align, u32 flags, + struct nvkm_object *objgpu, u32 size, u32 align, u32 flags, int length, void **pobject) { - struct nvkm_instmem *imem = nvkm_instmem(parent); - struct nvkm_bar *bar = nvkm_bar(parent); + struct nvkm_device *device = nv_device(parent); + struct nvkm_memory *memory = NULL; + struct nvkm_gpuobj *pargpu = NULL; struct nvkm_gpuobj *gpuobj; struct nvkm_mm *heap = NULL; int ret, i; @@ -64,46 +112,39 @@ nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, *pobject = NULL; - if (pargpu) { - while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) { - if (nv_gpuobj(pargpu)->heap.block_size) + if (objgpu) { + while ((objgpu = nv_pclass(objgpu, NV_GPUOBJ_CLASS))) { + if (nv_gpuobj(objgpu)->heap.block_size) break; - pargpu = pargpu->parent; + objgpu = objgpu->parent; } - if (WARN_ON(pargpu == NULL)) + if (WARN_ON(objgpu == NULL)) return -EINVAL; + pargpu = nv_gpuobj(objgpu); - addr = nv_gpuobj(pargpu)->addr; - heap = &nv_gpuobj(pargpu)->heap; - atomic_inc(&parent->refcount); + addr = pargpu->addr; + heap = &pargpu->heap; } else { - ret = imem->alloc(imem, parent, size, align, &parent); - pargpu = parent; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + size, align, false, &memory); if (ret) return ret; - addr = nv_memobj(pargpu)->addr; - size = nv_memobj(pargpu)->size; - - if (bar && bar->alloc) { - struct nvkm_instobj *iobj = (void *)parent; - struct nvkm_mem **mem = (void *)(iobj + 1); - struct nvkm_mem *node = *mem; - if (!bar->alloc(bar, parent, node, &pargpu)) { - nvkm_object_ref(NULL, &parent); - parent = pargpu; - } - } + addr = nvkm_memory_addr(memory); + size = nvkm_memory_size(memory); } ret = nvkm_object_create_(parent, engine, oclass, pclass | NV_GPUOBJ_CLASS, length, pobject); - nvkm_object_ref(NULL, &parent); gpuobj = *pobject; - if (ret) + if (ret) { + nvkm_memory_del(&memory); return ret; + } + gpuobj->func = &nvkm_gpuobj_func; + gpuobj->memory = memory; gpuobj->parent = pargpu; gpuobj->flags = flags; gpuobj->addr = addr; @@ -182,20 +223,14 @@ u32 _nvkm_gpuobj_rd32(struct nvkm_object *object, u64 addr) { struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - u32 data; - if (gpuobj->node) - addr += gpuobj->node->offset; - nvkm_object_rd32(gpuobj->parent, addr, &data); - return data; + return nvkm_ro32(gpuobj, addr); } void _nvkm_gpuobj_wr32(struct nvkm_object *object, u64 addr, u32 data) { struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - if (gpuobj->node) - addr += gpuobj->node->offset; - nvkm_object_wr32(gpuobj->parent, addr, data); + nvkm_wo32(gpuobj, addr, data); } static struct nvkm_oclass @@ -231,14 +266,14 @@ nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu, int nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, u32 access, struct nvkm_vma *vma) { + struct nvkm_memory *memory = gpuobj->memory; struct nvkm_bar *bar = nvkm_bar(gpuobj); int ret = -EINVAL; if (bar && bar->umap) { - struct nvkm_instobj *iobj = (void *) - nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS); - struct nvkm_mem **mem = (void *)(iobj + 1); - ret = bar->umap(bar, *mem, access, vma); + ret = bar->umap(bar, gpuobj->size, 12, vma); + if (ret == 0) + nvkm_memory_map(memory, vma, 0); } return ret; @@ -248,17 +283,11 @@ int nvkm_gpuobj_map_vm(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm, u32 access, struct nvkm_vma *vma) { - struct nvkm_instobj *iobj = (void *) - nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS); - struct nvkm_mem **mem = (void *)(iobj + 1); - int ret; - - ret = nvkm_vm_get(vm, gpuobj->size, 12, access, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, *mem); - return 0; + struct nvkm_memory *memory = gpuobj->memory; + int ret = nvkm_vm_get(vm, gpuobj->size, 12, access, vma); + if (ret == 0) + nvkm_memory_map(memory, vma, 0); + return ret; } void @@ -279,7 +308,7 @@ static void nvkm_gpudup_dtor(struct nvkm_object *object) { struct nvkm_gpuobj *gpuobj = (void *)object; - nvkm_object_ref(NULL, &gpuobj->parent); + nvkm_object_ref(NULL, (struct nvkm_object **)&gpuobj->parent); nvkm_object_destroy(&gpuobj->object); } @@ -306,7 +335,7 @@ nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_gpuobj *base, if (ret) return ret; - nvkm_object_ref(nv_object(base), &gpuobj->parent); + nvkm_object_ref(nv_object(base), (struct nvkm_object **)&gpuobj->parent); gpuobj->addr = base->addr; gpuobj->size = base->size; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/memory.c b/drivers/gpu/drm/nouveau/nvkm/core/memory.c new file mode 100644 index 0000000000000..0b88faa845f37 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/core/memory.c @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include +#include + +void +nvkm_memory_ctor(const struct nvkm_memory_func *func, + struct nvkm_memory *memory) +{ + memory->func = func; +} + +void +nvkm_memory_del(struct nvkm_memory **pmemory) +{ + struct nvkm_memory *memory = *pmemory; + if (memory && !WARN_ON(!memory->func)) { + if (memory->func->dtor) + *pmemory = memory->func->dtor(memory); + kfree(*pmemory); + *pmemory = NULL; + } +} + +int +nvkm_memory_new(struct nvkm_device *device, enum nvkm_memory_target target, + u64 size, u32 align, bool zero, + struct nvkm_memory **pmemory) +{ + struct nvkm_instmem *imem = device->imem; + struct nvkm_memory *memory; + int ret = -ENOSYS; + + if (unlikely(target != NVKM_MEM_TARGET_INST || !imem)) + return -ENOSYS; + + ret = imem->alloc(imem, size, align, zero, &memory); + if (ret) + return ret; + + *pmemory = memory; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index 4717af0800e91..061adedc6e2cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -22,8 +22,6 @@ #include #include -#include - static u32 nvkm_ramht_hash(struct nvkm_ramht *ramht, int chid, u32 handle) { @@ -43,7 +41,6 @@ int nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context) { struct nvkm_gpuobj *gpuobj = &ramht->gpuobj; - struct nvkm_bar *bar = nvkm_bar(ramht); int ret = -ENOSPC; u32 co, ho; @@ -53,8 +50,6 @@ nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context) if (!nvkm_ro32(gpuobj, co + 4)) { nvkm_wo32(gpuobj, co + 0, handle); nvkm_wo32(gpuobj, co + 4, context); - if (bar) - bar->flush(bar); ret = co; break; } @@ -72,12 +67,9 @@ void nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie) { struct nvkm_gpuobj *gpuobj = &ramht->gpuobj; - struct nvkm_bar *bar = nvkm_bar(ramht); nvkm_kmap(gpuobj); nvkm_wo32(gpuobj, cookie + 0, 0x00000000); nvkm_wo32(gpuobj, cookie + 4, 0x00000000); - if (bar) - bar->flush(bar); nvkm_done(gpuobj); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 64523d7eea589..c6150eaf16f08 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -41,7 +40,6 @@ static int g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent->parent; struct nvkm_gpuobj *ectx = (void *)object; u64 limit = ectx->addr + ectx->size - 1; @@ -73,7 +71,6 @@ g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) upper_32_bits(start)); nvkm_wo32(base->eng, addr + 0x10, 0x00000000); nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); nvkm_done(base->eng); return 0; } @@ -87,7 +84,6 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nv50_fifo_chan *chan = (void *)parent; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; u32 addr, save, engn; bool done; @@ -128,7 +124,6 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); nvkm_wo32(base->eng, addr + 0x10, 0x00000000); nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); nvkm_done(base->eng); return 0; } @@ -175,7 +170,6 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_dma_v0 v0; } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; int ret; @@ -239,7 +233,6 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, (chan->ramht->gpuobj.node->offset >> 4)); nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - bar->flush(bar); nvkm_done(base->ramfc); return 0; } @@ -252,7 +245,6 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_gpfifo_v0 v0; } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; u64 ioffset, ilength; @@ -318,7 +310,6 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, (chan->ramht->gpuobj.node->offset >> 4)); nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - bar->flush(bar); nvkm_done(base->ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index ba6b390a1fef4..763a2db7603a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -79,7 +78,6 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) { struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -96,7 +94,6 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) p += 8; } } - bar->flush(bar); nvkm_done(cur); nvkm_wr32(device, 0x002270, cur->addr >> 12); @@ -113,7 +110,6 @@ static int gf100_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct gf100_fifo_base *base = (void *)parent->parent; struct nvkm_gpuobj *engn = &base->base.gpuobj; struct nvkm_engctx *ectx = (void *)object; @@ -144,7 +140,6 @@ gf100_fifo_context_attach(struct nvkm_object *parent, nvkm_kmap(engn); nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); - bar->flush(bar); nvkm_done(engn); return 0; } @@ -159,7 +154,6 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_gpuobj *engn = &base->base.gpuobj; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; u32 addr; switch (nv_engidx(object->engine)) { @@ -188,7 +182,6 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, nvkm_kmap(engn); nvkm_wo32(engn, addr + 0x00, 0x00000000); nvkm_wo32(engn, addr + 0x04, 0x00000000); - bar->flush(bar); nvkm_done(engn); return 0; } @@ -201,7 +194,6 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct fermi_channel_gpfifo_v0 v0; } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); struct gf100_fifo *fifo = (void *)engine; struct gf100_fifo_base *base = (void *)parent; struct gf100_fifo_chan *chan; @@ -264,7 +256,6 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(ramfc, 0xb8, 0xf8000000); nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ - bar->flush(bar); nvkm_done(ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 62b3de4e9353d..d1238aa7bec55 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -99,7 +98,6 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) struct gk104_fifo_engn *engn = &fifo->engine[engine]; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -116,7 +114,6 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) p += 8; } } - bar->flush(bar); nvkm_done(cur); nvkm_wr32(device, 0x002270, cur->addr >> 12); @@ -133,7 +130,6 @@ static int gk104_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct gk104_fifo_base *base = (void *)parent->parent; struct nvkm_gpuobj *engn = &base->base.gpuobj; struct nvkm_engctx *ectx = (void *)object; @@ -168,7 +164,6 @@ gk104_fifo_context_attach(struct nvkm_object *parent, nvkm_kmap(engn); nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); - bar->flush(bar); nvkm_done(engn); return 0; } @@ -198,7 +193,6 @@ static int gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct gk104_fifo_base *base = (void *)parent->parent; struct gk104_fifo_chan *chan = (void *)parent; struct nvkm_gpuobj *engn = &base->base.gpuobj; @@ -226,7 +220,6 @@ gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, nvkm_kmap(engn); nvkm_wo32(engn, addr + 0x00, 0x00000000); nvkm_wo32(engn, addr + 0x04, 0x00000000); - bar->flush(bar); nvkm_done(engn); } @@ -241,7 +234,6 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, union { struct kepler_channel_gpfifo_a_v0 v0; } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); struct gk104_fifo *fifo = (void *)engine; struct gk104_fifo_base *base = (void *)parent; struct gk104_fifo_chan *chan; @@ -320,7 +312,6 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(ramfc, 0xb8, 0xf8000000); nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ - bar->flush(bar); nvkm_done(ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 51b8fce9e0fc1..b01490f71f098 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -574,7 +574,8 @@ nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem *imem = nv04_instmem(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 046acc2813817..7491b10a76b7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -145,7 +145,8 @@ nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem *imem = nv04_instmem(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 7be6fea900100..e652941d04f3b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -152,7 +152,8 @@ nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem *imem = nv04_instmem(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index cad4b4be19387..f35ae76472392 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -276,7 +276,8 @@ nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nv04_instmem *imem = nv04_instmem(parent); + struct nvkm_device *device = (void *)parent; + struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 402639cb4ec9e..ffa495c1692bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include @@ -42,7 +41,6 @@ static void nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) { struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *cur; int i, p; @@ -54,7 +52,6 @@ nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000) nvkm_wo32(cur, p++ * 4, i); } - bar->flush(bar); nvkm_done(cur); nvkm_wr32(device, 0x0032f4, cur->addr >> 12); @@ -73,7 +70,6 @@ nv50_fifo_playlist_update(struct nv50_fifo *fifo) static int nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) { - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent->parent; struct nvkm_gpuobj *ectx = (void *)object; u64 limit = ectx->addr + ectx->size - 1; @@ -98,7 +94,6 @@ nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) upper_32_bits(start)); nvkm_wo32(base->eng, addr + 0x10, 0x00000000); nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); nvkm_done(base->eng); return 0; } @@ -112,7 +107,6 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nv50_fifo_chan *chan = (void *)parent; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; u32 addr, me; int ret = 0; @@ -159,7 +153,6 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); nvkm_wo32(base->eng, addr + 0x10, 0x00000000); nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - bar->flush(bar); nvkm_done(base->eng); } @@ -205,7 +198,6 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_dma_v0 v0; } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; int ret; @@ -257,7 +249,6 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | (chan->ramht->gpuobj.node->offset >> 4)); - bar->flush(bar); nvkm_done(base->ramfc); return 0; } @@ -270,7 +261,6 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_gpfifo_v0 v0; } *args = data; - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; u64 ioffset, ilength; @@ -324,7 +314,6 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | (chan->ramht->gpuobj.node->offset >> 4)); - bar->flush(bar); nvkm_done(base->ramfc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index f36e0896ae9c6..a2e60b1ddb27c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -23,7 +23,6 @@ */ #include "ctxgf100.h" -#include #include #include #include @@ -1273,7 +1272,6 @@ gf100_grctx_generate(struct gf100_gr *gr) struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; struct nvkm_gpuobj *chan; struct gf100_grctx info; int ret, i; @@ -1309,7 +1307,6 @@ gf100_grctx_generate(struct gf100_gr *gr) /* context pointer (virt) */ nvkm_wo32(chan, 0x0210, 0x00080004); nvkm_wo32(chan, 0x0214, 0x00000000); - bar->flush(bar); nvkm_done(chan); nvkm_wr32(device, 0x100cb8, (chan->addr + 0x1000) >> 8); @@ -1341,7 +1338,6 @@ gf100_grctx_generate(struct gf100_gr *gr) nvkm_wo32(chan, 0x80020, 0); nvkm_wo32(chan, 0x80028, 0); nvkm_wo32(chan, 0x8002c, 0); - bar->flush(bar); nvkm_done(chan); } else { nvkm_wr32(device, 0x409840, 0x80000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index 6af707b5be189..c906c43e9065c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -23,7 +23,6 @@ */ #include -#include #include struct nv50_mpeg_chan { @@ -84,7 +83,6 @@ nv50_mpeg_context_ctor(struct nvkm_object *parent, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_bar *bar = nvkm_bar(parent); struct nv50_mpeg_chan *chan; struct nvkm_gpuobj *image; int ret; @@ -100,7 +98,6 @@ nv50_mpeg_context_ctor(struct nvkm_object *parent, nvkm_kmap(image); nvkm_wo32(image, 0x0070, 0x00801ec1); nvkm_wo32(image, 0x007c, 0x0000037c); - bar->flush(bar); nvkm_done(image); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 6fe71b2276cca..8daaa65fc8cf5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -23,96 +23,6 @@ */ #include "priv.h" -#include -#include - -struct nvkm_barobj { - struct nvkm_object base; - struct nvkm_vma vma; - void __iomem *iomem; -}; - -static int -nvkm_barobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_device(parent); - struct nvkm_bar *bar = nvkm_bar(device); - struct nvkm_mem *mem = data; - struct nvkm_barobj *barobj; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &barobj); - *pobject = nv_object(barobj); - if (ret) - return ret; - - ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma); - if (ret) - return ret; - - barobj->iomem = ioremap(nv_device_resource_start(device, 3) + - (u32)barobj->vma.offset, mem->size << 12); - if (!barobj->iomem) { - nvkm_warn(&bar->subdev, "PRAMIN ioremap failed\n"); - return -ENOMEM; - } - - return 0; -} - -static void -nvkm_barobj_dtor(struct nvkm_object *object) -{ - struct nvkm_bar *bar = nvkm_bar(object); - struct nvkm_barobj *barobj = (void *)object; - if (barobj->vma.node) { - if (barobj->iomem) - iounmap(barobj->iomem); - bar->unmap(bar, &barobj->vma); - } - nvkm_object_destroy(&barobj->base); -} - -static u32 -nvkm_barobj_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_barobj *barobj = (void *)object; - return ioread32_native(barobj->iomem + addr); -} - -static void -nvkm_barobj_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_barobj *barobj = (void *)object; - iowrite32_native(data, barobj->iomem + addr); -} - -static struct nvkm_oclass -nvkm_barobj_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nvkm_barobj_ctor, - .dtor = nvkm_barobj_dtor, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - .rd32 = nvkm_barobj_rd32, - .wr32 = nvkm_barobj_wr32, - }, -}; - -int -nvkm_bar_alloc(struct nvkm_bar *bar, struct nvkm_object *parent, - struct nvkm_mem *mem, struct nvkm_object **pobject) -{ - struct nvkm_object *gpuobj; - int ret = nvkm_object_old(parent, &parent->engine->subdev.object, - &nvkm_barobj_oclass, mem, 0, &gpuobj); - if (ret == 0) - *pobject = gpuobj; - return ret; -} - int nvkm_bar_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 01e26213fd88c..1ea6b3909c3a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -39,35 +39,18 @@ struct gf100_bar { struct gf100_bar_vm bar[2]; }; -static int -gf100_bar_kmap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) +static struct nvkm_vm * +gf100_bar_kmap(struct nvkm_bar *obj) { struct gf100_bar *bar = container_of(obj, typeof(*bar), base); - int ret; - - ret = nvkm_vm_get(bar->bar[0].vm, mem->size << 12, 12, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; + return bar->bar[0].vm; } static int -gf100_bar_umap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) +gf100_bar_umap(struct nvkm_bar *obj, u64 size, int type, struct nvkm_vma *vma) { struct gf100_bar *bar = container_of(obj, typeof(*bar), base); - int ret; - - ret = nvkm_vm_get(bar->bar[1].vm, mem->size << 12, - mem->page_shift, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; + return nvkm_vm_get(bar->bar[1].vm, size, type, NV_MEM_ACCESS_RW, vma); } static void @@ -109,11 +92,7 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, * Bootstrap page table lookup. */ if (bar_nr == 3) { - ret = nvkm_gpuobj_new(nv_object(bar), NULL, - (bar_len >> 12) * 8, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, - &vm->pgt[0].obj[0]); - vm->pgt[0].refcount[0] = 1; + ret = nvkm_vm_boot(vm, bar_len); if (ret) return ret; } @@ -149,6 +128,10 @@ gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + device->bar = &bar->base; + bar->base.flush = g84_bar_flush; + spin_lock_init(&bar->lock); + /* BAR3 */ if (has_bar3) { ret = gf100_bar_ctor_vm(bar, &bar->bar[0], &bar3_lock, 3); @@ -161,14 +144,10 @@ gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - if (has_bar3) { - bar->base.alloc = nvkm_bar_alloc; + if (has_bar3) bar->base.kmap = gf100_bar_kmap; - } bar->base.umap = gf100_bar_umap; bar->base.unmap = gf100_bar_unmap; - bar->base.flush = g84_bar_flush; - spin_lock_init(&bar->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index cb58cc5b2b579..ec864afc8862c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -40,34 +40,18 @@ struct nv50_bar { struct nvkm_gpuobj *bar3; }; -static int -nv50_bar_kmap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) +static struct nvkm_vm * +nv50_bar_kmap(struct nvkm_bar *obj) { struct nv50_bar *bar = container_of(obj, typeof(*bar), base); - int ret; - - ret = nvkm_vm_get(bar->bar3_vm, mem->size << 12, 12, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; + return bar->bar3_vm; } static int -nv50_bar_umap(struct nvkm_bar *obj, struct nvkm_mem *mem, u32 flags, - struct nvkm_vma *vma) +nv50_bar_umap(struct nvkm_bar *obj, u64 size, int type, struct nvkm_vma *vma) { struct nv50_bar *bar = container_of(obj, typeof(*bar), base); - int ret; - - ret = nvkm_vm_get(bar->bar1_vm, mem->size << 12, 12, flags, vma); - if (ret) - return ret; - - nvkm_vm_map(vma, mem); - return 0; + return nvkm_vm_get(bar->bar1_vm, size, type, NV_MEM_ACCESS_RW, vma); } static void @@ -152,10 +136,7 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); - ret = nvkm_gpuobj_new(nv_object(bar), heap, - ((limit-- - start) >> 12) * 8, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]); - vm->pgt[0].refcount[0] = 1; + ret = nvkm_vm_boot(vm, limit-- - start); if (ret) return ret; @@ -207,7 +188,6 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(bar->bar1, 0x14, 0x00000000); nvkm_done(bar->bar1); - bar->base.alloc = nvkm_bar_alloc; bar->base.kmap = nv50_bar_kmap; bar->base.umap = nv50_bar_umap; bar->base.unmap = nv50_bar_unmap; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h index e9d2f7b6b22f8..3a8fbaea582d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h @@ -17,9 +17,6 @@ void _nvkm_bar_dtor(struct nvkm_object *); #define _nvkm_bar_init _nvkm_subdev_init #define _nvkm_bar_fini _nvkm_subdev_fini -int nvkm_bar_alloc(struct nvkm_bar *, struct nvkm_object *, - struct nvkm_mem *, struct nvkm_object **); - void g84_bar_flush(struct nvkm_bar *); int gf100_bar_ctor(struct nvkm_object *, struct nvkm_object *, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 8ac8e4f4fa4b5..2a1dab304087c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -23,83 +23,221 @@ */ #include "priv.h" -#include +#include +#include /****************************************************************************** * instmem object base implementation *****************************************************************************/ +#define nvkm_instobj(p) container_of((p), struct nvkm_instobj, memory) -void -_nvkm_instobj_dtor(struct nvkm_object *object) +struct nvkm_instobj { + struct nvkm_memory memory; + struct nvkm_memory *parent; + struct nvkm_instmem *imem; + struct list_head head; + u32 *suspend; + void __iomem *map; +}; + +static enum nvkm_memory_target +nvkm_instobj_target(struct nvkm_memory *memory) +{ + memory = nvkm_instobj(memory)->parent; + return nvkm_memory_target(memory); +} + +static u64 +nvkm_instobj_addr(struct nvkm_memory *memory) +{ + memory = nvkm_instobj(memory)->parent; + return nvkm_memory_addr(memory); +} + +static u64 +nvkm_instobj_size(struct nvkm_memory *memory) +{ + memory = nvkm_instobj(memory)->parent; + return nvkm_memory_size(memory); +} + +static void +nvkm_instobj_release(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + struct nvkm_bar *bar = iobj->imem->subdev.device->bar; + if (bar && bar->flush) + bar->flush(bar); +} + +static void __iomem * +nvkm_instobj_acquire(struct nvkm_memory *memory) +{ + return nvkm_instobj(memory)->map; +} + +static u32 +nvkm_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + return ioread32_native(nvkm_instobj(memory)->map + offset); +} + +static void +nvkm_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct nvkm_instmem *imem = nvkm_instmem(object); - struct nvkm_instobj *iobj = (void *)object; + iowrite32_native(data, nvkm_instobj(memory)->map + offset); +} + +static void +nvkm_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset) +{ + memory = nvkm_instobj(memory)->parent; + nvkm_memory_map(memory, vma, offset); +} - mutex_lock(&nv_subdev(imem)->mutex); +static void * +nvkm_instobj_dtor(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); list_del(&iobj->head); - mutex_unlock(&nv_subdev(imem)->mutex); + nvkm_memory_del(&iobj->parent); + return iobj; +} - return nvkm_object_destroy(&iobj->object); +const struct nvkm_memory_func +nvkm_instobj_func = { + .dtor = nvkm_instobj_dtor, + .target = nvkm_instobj_target, + .addr = nvkm_instobj_addr, + .size = nvkm_instobj_size, + .acquire = nvkm_instobj_acquire, + .release = nvkm_instobj_release, + .rd32 = nvkm_instobj_rd32, + .wr32 = nvkm_instobj_wr32, + .map = nvkm_instobj_map, +}; + +static void +nvkm_instobj_boot(struct nvkm_memory *memory, struct nvkm_vm *vm) +{ + memory = nvkm_instobj(memory)->parent; + nvkm_memory_boot(memory, vm); } -int -nvkm_instobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static void +nvkm_instobj_release_slow(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + nvkm_instobj_release(memory); + nvkm_done(iobj->parent); +} + +static void __iomem * +nvkm_instobj_acquire_slow(struct nvkm_memory *memory) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + iobj->map = nvkm_kmap(iobj->parent); + if (iobj->map) + memory->func = &nvkm_instobj_func; + return iobj->map; +} + +static u32 +nvkm_instobj_rd32_slow(struct nvkm_memory *memory, u64 offset) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + return nvkm_ro32(iobj->parent, offset); +} + +static void +nvkm_instobj_wr32_slow(struct nvkm_memory *memory, u64 offset, u32 data) +{ + struct nvkm_instobj *iobj = nvkm_instobj(memory); + return nvkm_wo32(iobj->parent, offset, data); +} + +const struct nvkm_memory_func +nvkm_instobj_func_slow = { + .dtor = nvkm_instobj_dtor, + .target = nvkm_instobj_target, + .addr = nvkm_instobj_addr, + .size = nvkm_instobj_size, + .boot = nvkm_instobj_boot, + .acquire = nvkm_instobj_acquire_slow, + .release = nvkm_instobj_release_slow, + .rd32 = nvkm_instobj_rd32_slow, + .wr32 = nvkm_instobj_wr32_slow, + .map = nvkm_instobj_map, +}; + +static int +nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_instmem *imem = nvkm_instmem(parent); + struct nvkm_instmem_impl *impl = (void *)imem->subdev.object.oclass; + struct nvkm_memory *memory; struct nvkm_instobj *iobj; + u32 offset; int ret; - ret = nvkm_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS, - length, pobject); - iobj = *pobject; + ret = impl->memory_new(imem, size, align, zero, &memory); if (ret) - return ret; + goto done; - mutex_lock(&imem->subdev.mutex); - list_add(&iobj->head, &imem->list); - mutex_unlock(&imem->subdev.mutex); - return 0; + if (!impl->persistent) { + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) { + ret = -ENOMEM; + goto done; + } + + nvkm_memory_ctor(&nvkm_instobj_func_slow, &iobj->memory); + iobj->parent = memory; + iobj->imem = imem; + list_add_tail(&iobj->head, &imem->list); + memory = &iobj->memory; + } + + if (!impl->zero && zero) { + void __iomem *map = nvkm_kmap(memory); + if (unlikely(!map)) { + for (offset = 0; offset < size; offset += 4) + nvkm_wo32(memory, offset, 0x00000000); + } else { + memset_io(map, 0x00, size); + } + nvkm_done(memory); + } + +done: + if (ret) + nvkm_memory_del(&memory); + *pmemory = memory; + return ret; } /****************************************************************************** * instmem subdev base implementation *****************************************************************************/ -static int -nvkm_instmem_alloc(struct nvkm_instmem *imem, struct nvkm_object *parent, - u32 size, u32 align, struct nvkm_object **pobject) -{ - struct nvkm_instmem_impl *impl = (void *)imem->subdev.object.oclass; - struct nvkm_instobj_args args = { .size = size, .align = align }; - return nvkm_object_old(parent, &parent->engine->subdev.object, - impl->instobj, &args, sizeof(args), pobject); -} - int _nvkm_instmem_fini(struct nvkm_object *object, bool suspend) { struct nvkm_instmem *imem = (void *)object; struct nvkm_instobj *iobj; - int i, ret = 0; + int i; if (suspend) { - mutex_lock(&imem->subdev.mutex); list_for_each_entry(iobj, &imem->list, head) { - iobj->suspend = vmalloc(iobj->size); - if (!iobj->suspend) { - ret = -ENOMEM; - break; - } - - for (i = 0; i < iobj->size; i += 4) { - nvkm_object_rd32(&iobj->object, i, (u32 *) - &iobj->suspend[i/4]); - } + struct nvkm_memory *memory = iobj->parent; + u64 size = nvkm_memory_size(memory); + + iobj->suspend = vmalloc(size); + if (!iobj->suspend) + return -ENOMEM; + + for (i = 0; i < size; i += 4) + iobj->suspend[i / 4] = nvkm_ro32(memory, i); } - mutex_unlock(&imem->subdev.mutex); - if (ret) - return ret; } return nvkm_subdev_fini_old(&imem->subdev, suspend); @@ -116,18 +254,17 @@ _nvkm_instmem_init(struct nvkm_object *object) if (ret) return ret; - mutex_lock(&imem->subdev.mutex); list_for_each_entry(iobj, &imem->list, head) { if (iobj->suspend) { - for (i = 0; i < iobj->size; i += 4) { - nvkm_object_wr32(&iobj->object, i, *(u32 *) - &iobj->suspend[i/4]); - } + struct nvkm_memory *memory = iobj->parent; + u64 size = nvkm_memory_size(memory); + for (i = 0; i < size; i += 4) + nvkm_wo32(memory, i, iobj->suspend[i / 4]); vfree(iobj->suspend); iobj->suspend = NULL; } } - mutex_unlock(&imem->subdev.mutex); + return 0; } @@ -135,6 +272,7 @@ int nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { + struct nvkm_device *device = (void *)parent; struct nvkm_instmem *imem; int ret; @@ -144,7 +282,9 @@ nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + device->imem = imem; + INIT_LIST_HEAD(&imem->list); - imem->alloc = nvkm_instmem_alloc; + imem->alloc = nvkm_instobj_new; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index e6370382109b4..a64c3f9bfc3dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -37,9 +37,12 @@ * to use more "relaxed" allocation parameters when using the DMA API, since we * never need a kernel mapping. */ +#define gk20a_instmem(p) container_of((p), struct gk20a_instmem, base) +#include "priv.h" -#include +#include #include +#include #ifdef __KERNEL__ #include @@ -47,14 +50,12 @@ #include #endif -#include "priv.h" +#define gk20a_instobj(p) container_of((p), struct gk20a_instobj, memory) struct gk20a_instobj { - struct nvkm_instobj base; - /* Must be second member here - see nouveau_gpuobj_map_vm() */ - struct nvkm_mem *mem; - /* Pointed by mem */ - struct nvkm_mem _mem; + struct nvkm_memory memory; + struct gk20a_instmem *imem; + struct nvkm_mem mem; }; /* @@ -80,6 +81,7 @@ struct gk20a_instobj_iommu { struct gk20a_instmem { struct nvkm_instmem base; + unsigned long lock_flags; spinlock_t lock; u64 addr; @@ -93,6 +95,42 @@ struct gk20a_instmem { struct dma_attrs attrs; }; +static enum nvkm_memory_target +gk20a_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_HOST; +} + +static u64 +gk20a_instobj_addr(struct nvkm_memory *memory) +{ + return gk20a_instobj(memory)->mem.offset; + +} + +static u64 +gk20a_instobj_size(struct nvkm_memory *memory) +{ + return (u64)gk20a_instobj(memory)->mem.size << 12; +} + +static void __iomem * +gk20a_instobj_acquire(struct nvkm_memory *memory) +{ + struct gk20a_instmem *imem = gk20a_instobj(memory)->imem; + unsigned long flags; + spin_lock_irqsave(&imem->lock, flags); + imem->lock_flags = flags; + return NULL; +} + +static void +gk20a_instobj_release(struct nvkm_memory *memory) +{ + struct gk20a_instmem *imem = gk20a_instobj(memory)->imem; + spin_unlock_irqrestore(&imem->lock, imem->lock_flags); +} + /* * Use PRAMIN to read/write data and avoid coherency issues. * PRAMIN uses the GPU path and ensures data will always be coherent. @@ -103,56 +141,57 @@ struct gk20a_instmem { */ static u32 -gk20a_instobj_rd32(struct nvkm_object *object, u64 offset) +gk20a_instobj_rd32(struct nvkm_memory *memory, u64 offset) { - struct gk20a_instmem *imem = (void *)nvkm_instmem(object); - struct gk20a_instobj *node = (void *)object; + struct gk20a_instobj *node = gk20a_instobj(memory); + struct gk20a_instmem *imem = node->imem; struct nvkm_device *device = imem->base.subdev.device; - unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + u64 base = (node->mem.offset + offset) & 0xffffff00000ULL; + u64 addr = (node->mem.offset + offset) & 0x000000fffffULL; u32 data; - spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } data = nvkm_rd32(device, 0x700000 + addr); - spin_unlock_irqrestore(&imem->lock, flags); return data; } static void -gk20a_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) +gk20a_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct gk20a_instmem *imem = (void *)nvkm_instmem(object); - struct gk20a_instobj *node = (void *)object; + struct gk20a_instobj *node = gk20a_instobj(memory); + struct gk20a_instmem *imem = node->imem; struct nvkm_device *device = imem->base.subdev.device; - unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + u64 base = (node->mem.offset + offset) & 0xffffff00000ULL; + u64 addr = (node->mem.offset + offset) & 0x000000fffffULL; - spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } nvkm_wr32(device, 0x700000 + addr, data); - spin_unlock_irqrestore(&imem->lock, flags); +} + +static void +gk20a_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset) +{ + struct gk20a_instobj *node = gk20a_instobj(memory); + nvkm_vm_map_at(vma, offset, &node->mem); } static void gk20a_instobj_dtor_dma(struct gk20a_instobj *_node) { struct gk20a_instobj_dma *node = (void *)_node; - struct gk20a_instmem *imem = (void *)nvkm_instmem(node); + struct gk20a_instmem *imem = _node->imem; struct device *dev = nv_device_base(nv_device(imem)); if (unlikely(!node->cpuaddr)) return; - dma_free_attrs(dev, _node->mem->size << PAGE_SHIFT, node->cpuaddr, + dma_free_attrs(dev, _node->mem.size << PAGE_SHIFT, node->cpuaddr, node->handle, &imem->attrs); } @@ -160,21 +199,21 @@ static void gk20a_instobj_dtor_iommu(struct gk20a_instobj *_node) { struct gk20a_instobj_iommu *node = (void *)_node; - struct gk20a_instmem *imem = (void *)nvkm_instmem(node); + struct gk20a_instmem *imem = _node->imem; struct nvkm_mm_node *r; int i; - if (unlikely(list_empty(&_node->mem->regions))) + if (unlikely(list_empty(&_node->mem.regions))) return; - r = list_first_entry(&_node->mem->regions, struct nvkm_mm_node, + r = list_first_entry(&_node->mem.regions, struct nvkm_mm_node, rl_entry); /* clear bit 34 to unmap pages */ r->offset &= ~BIT(34 - imem->iommu_pgshift); /* Unmap pages from GPU address space and free them */ - for (i = 0; i < _node->mem->size; i++) { + for (i = 0; i < _node->mem.size; i++) { iommu_unmap(imem->domain, (r->offset + i) << imem->iommu_pgshift, PAGE_SIZE); __free_page(node->pages[i]); @@ -186,36 +225,44 @@ gk20a_instobj_dtor_iommu(struct gk20a_instobj *_node) mutex_unlock(imem->mm_mutex); } -static void -gk20a_instobj_dtor(struct nvkm_object *object) +static void * +gk20a_instobj_dtor(struct nvkm_memory *memory) { - struct gk20a_instobj *node = (void *)object; - struct gk20a_instmem *imem = (void *)nvkm_instmem(node); + struct gk20a_instobj *node = gk20a_instobj(memory); + struct gk20a_instmem *imem = node->imem; if (imem->domain) gk20a_instobj_dtor_iommu(node); else gk20a_instobj_dtor_dma(node); - nvkm_instobj_destroy(&node->base); + return node; } +static const struct nvkm_memory_func +gk20a_instobj_func = { + .dtor = gk20a_instobj_dtor, + .target = gk20a_instobj_target, + .addr = gk20a_instobj_addr, + .size = gk20a_instobj_size, + .acquire = gk20a_instobj_acquire, + .release = gk20a_instobj_release, + .rd32 = gk20a_instobj_rd32, + .wr32 = gk20a_instobj_wr32, + .map = gk20a_instobj_map, +}; + static int -gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 npages, u32 align, +gk20a_instobj_ctor_dma(struct gk20a_instmem *imem, u32 npages, u32 align, struct gk20a_instobj **_node) { struct gk20a_instobj_dma *node; - struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); struct nvkm_subdev *subdev = &imem->base.subdev; - struct device *dev = nv_device_base(nv_device(parent)); - int ret; + struct device *dev = subdev->device->dev; - ret = nvkm_instobj_create_(parent, engine, oclass, sizeof(*node), - (void **)&node); + if (!(node = kzalloc(sizeof(*node), GFP_KERNEL))) + return -ENOMEM; *_node = &node->base; - if (ret) - return ret; node->cpuaddr = dma_alloc_attrs(dev, npages << PAGE_SHIFT, &node->handle, GFP_KERNEL, @@ -236,32 +283,28 @@ gk20a_instobj_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, node->r.offset = node->handle >> 12; node->r.length = (npages << PAGE_SHIFT) >> 12; - node->base._mem.offset = node->handle; + node->base.mem.offset = node->handle; - INIT_LIST_HEAD(&node->base._mem.regions); - list_add_tail(&node->r.rl_entry, &node->base._mem.regions); + INIT_LIST_HEAD(&node->base.mem.regions); + list_add_tail(&node->r.rl_entry, &node->base.mem.regions); return 0; } static int -gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 npages, u32 align, +gk20a_instobj_ctor_iommu(struct gk20a_instmem *imem, u32 npages, u32 align, struct gk20a_instobj **_node) { struct gk20a_instobj_iommu *node; - struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); struct nvkm_subdev *subdev = &imem->base.subdev; struct nvkm_mm_node *r; int ret; int i; - ret = nvkm_instobj_create_(parent, engine, oclass, - sizeof(*node) + sizeof(node->pages[0]) * npages, - (void **)&node); + if (!(node = kzalloc(sizeof(*node) + + sizeof( node->pages[0]) * npages, GFP_KERNEL))) + return -ENOMEM; *_node = &node->base; - if (ret) - return ret; /* Allocate backing memory */ for (i = 0; i < npages; i++) { @@ -305,10 +348,10 @@ gk20a_instobj_ctor_iommu(struct nvkm_object *parent, struct nvkm_object *engine, /* Bit 34 tells that an address is to be resolved through the IOMMU */ r->offset |= BIT(34 - imem->iommu_pgshift); - node->base._mem.offset = ((u64)r->offset) << imem->iommu_pgshift; + node->base.mem.offset = ((u64)r->offset) << imem->iommu_pgshift; - INIT_LIST_HEAD(&node->base._mem.regions); - list_add_tail(&r->rl_entry, &node->base._mem.regions); + INIT_LIST_HEAD(&node->base.mem.regions); + list_add_tail(&r->rl_entry, &node->base.mem.regions); return 0; @@ -325,64 +368,45 @@ free_pages: } static int -gk20a_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 _size, - struct nvkm_object **pobject) +gk20a_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_instobj_args *args = data; - struct gk20a_instmem *imem = (void *)nvkm_instmem(parent); + struct gk20a_instmem *imem = gk20a_instmem(base); struct gk20a_instobj *node; struct nvkm_subdev *subdev = &imem->base.subdev; - u32 size, align; int ret; nvkm_debug(subdev, "%s (%s): size: %x align: %x\n", __func__, - imem->domain ? "IOMMU" : "DMA", args->size, args->align); + imem->domain ? "IOMMU" : "DMA", size, align); /* Round size and align to page bounds */ - size = max(roundup(args->size, PAGE_SIZE), PAGE_SIZE); - align = max(roundup(args->align, PAGE_SIZE), PAGE_SIZE); + size = max(roundup(size, PAGE_SIZE), PAGE_SIZE); + align = max(roundup(align, PAGE_SIZE), PAGE_SIZE); if (imem->domain) - ret = gk20a_instobj_ctor_iommu(parent, engine, oclass, - size >> PAGE_SHIFT, align, &node); + ret = gk20a_instobj_ctor_iommu(imem, size >> PAGE_SHIFT, + align, &node); else - ret = gk20a_instobj_ctor_dma(parent, engine, oclass, - size >> PAGE_SHIFT, align, &node); - *pobject = nv_object(node); + ret = gk20a_instobj_ctor_dma(imem, size >> PAGE_SHIFT, + align, &node); if (ret) return ret; + *pmemory = &node->memory; - node->mem = &node->_mem; + nvkm_memory_ctor(&gk20a_instobj_func, &node->memory); + node->imem = imem; /* present memory for being mapped using small pages */ - node->mem->size = size >> 12; - node->mem->memtype = 0; - node->mem->page_shift = 12; - - node->base.addr = node->mem->offset; - node->base.size = size; + node->mem.size = size >> 12; + node->mem.memtype = 0; + node->mem.page_shift = 12; nvkm_debug(subdev, "alloc size: 0x%x, align: 0x%x, gaddr: 0x%llx\n", - size, align, node->mem->offset); + size, align, node->mem.offset); return 0; } -static struct nvkm_instobj_impl -gk20a_instobj_oclass = { - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_instobj_ctor, - .dtor = gk20a_instobj_dtor, - .init = _nvkm_instobj_init, - .fini = _nvkm_instobj_fini, - .rd32 = gk20a_instobj_rd32, - .wr32 = gk20a_instobj_wr32, - }, -}; - - - static int gk20a_instmem_fini(struct nvkm_object *object, bool suspend) { @@ -440,5 +464,7 @@ gk20a_instmem_oclass = &(struct nvkm_instmem_impl) { .init = _nvkm_instmem_init, .fini = gk20a_instmem_fini, }, - .instobj = &gk20a_instobj_oclass.base, + .memory_new = gk20a_instobj_new, + .persistent = true, + .zero = false, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 8ba95f366e2fe..c499e485373b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -21,83 +21,119 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#define nv04_instmem(p) container_of((p), struct nv04_instmem, base) +#include "priv.h" +#include #include +struct nv04_instmem { + struct nvkm_instmem base; + struct nvkm_mm heap; +}; + /****************************************************************************** * instmem object implementation *****************************************************************************/ +#define nv04_instobj(p) container_of((p), struct nv04_instobj, memory) -static u32 -nv04_instobj_rd32(struct nvkm_object *object, u64 addr) +struct nv04_instobj { + struct nvkm_memory memory; + struct nv04_instmem *imem; + struct nvkm_mm_node *node; +}; + +static enum nvkm_memory_target +nv04_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_INST; +} + +static u64 +nv04_instobj_addr(struct nvkm_memory *memory) +{ + return nv04_instobj(memory)->node->offset; +} + +static u64 +nv04_instobj_size(struct nvkm_memory *memory) +{ + return nv04_instobj(memory)->node->length; +} + +static void __iomem * +nv04_instobj_acquire(struct nvkm_memory *memory) { - struct nvkm_instmem *imem = nvkm_instmem(object); - struct nv04_instobj *node = (void *)object; - return imem->func->rd32(imem, node->mem->offset + addr); + struct nv04_instobj *iobj = nv04_instobj(memory); + struct nvkm_device *device = iobj->imem->base.subdev.device; + return device->pri + 0x700000 + iobj->node->offset; } static void -nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data) +nv04_instobj_release(struct nvkm_memory *memory) { - struct nvkm_instmem *imem = nvkm_instmem(object); - struct nv04_instobj *node = (void *)object; - imem->func->wr32(imem, node->mem->offset + addr, data); +} + +static u32 +nv04_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + struct nv04_instobj *iobj = nv04_instobj(memory); + struct nvkm_device *device = iobj->imem->base.subdev.device; + return nvkm_rd32(device, 0x700000 + iobj->node->offset + offset); } static void -nv04_instobj_dtor(struct nvkm_object *object) +nv04_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct nv04_instmem *imem = (void *)nvkm_instmem(object); - struct nv04_instobj *node = (void *)object; - mutex_lock(&imem->base.subdev.mutex); - nvkm_mm_free(&imem->heap, &node->mem); - mutex_unlock(&imem->base.subdev.mutex); - nvkm_instobj_destroy(&node->base); + struct nv04_instobj *iobj = nv04_instobj(memory); + struct nvkm_device *device = iobj->imem->base.subdev.device; + nvkm_wr32(device, 0x700000 + iobj->node->offset + offset, data); } +static void * +nv04_instobj_dtor(struct nvkm_memory *memory) +{ + struct nv04_instobj *iobj = nv04_instobj(memory); + mutex_lock(&iobj->imem->base.subdev.mutex); + nvkm_mm_free(&iobj->imem->heap, &iobj->node); + mutex_unlock(&iobj->imem->base.subdev.mutex); + return iobj; +} + +static const struct nvkm_memory_func +nv04_instobj_func = { + .dtor = nv04_instobj_dtor, + .target = nv04_instobj_target, + .size = nv04_instobj_size, + .addr = nv04_instobj_addr, + .acquire = nv04_instobj_acquire, + .release = nv04_instobj_release, + .rd32 = nv04_instobj_rd32, + .wr32 = nv04_instobj_wr32, +}; + static int -nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nv04_instmem *imem = (void *)nvkm_instmem(parent); - struct nv04_instobj *node; - struct nvkm_instobj_args *args = data; + struct nv04_instmem *imem = nv04_instmem(base); + struct nv04_instobj *iobj; int ret; - if (!args->align) - args->align = 1; + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) + return -ENOMEM; + *pmemory = &iobj->memory; - ret = nvkm_instobj_create(parent, engine, oclass, &node); - *pobject = nv_object(node); - if (ret) - return ret; + nvkm_memory_ctor(&nv04_instobj_func, &iobj->memory); + iobj->imem = imem; mutex_lock(&imem->base.subdev.mutex); - ret = nvkm_mm_head(&imem->heap, 0, 1, args->size, args->size, - args->align, &node->mem); + ret = nvkm_mm_head(&imem->heap, 0, 1, size, size, + align ? align : 1, &iobj->node); mutex_unlock(&imem->base.subdev.mutex); - if (ret) - return ret; - - node->base.addr = node->mem->offset; - node->base.size = node->mem->length; - return 0; + return ret; } -struct nvkm_instobj_impl -nv04_instobj_oclass = { - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_instobj_ctor, - .dtor = nv04_instobj_dtor, - .init = _nvkm_instobj_init, - .fini = _nvkm_instobj_fini, - .rd32 = nv04_instobj_rd32, - .wr32 = nv04_instobj_wr32, - }, -}; - /****************************************************************************** * instmem subdev implementation *****************************************************************************/ @@ -114,17 +150,15 @@ nv04_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data) nvkm_wr32(imem->subdev.device, 0x700000 + addr, data); } -void +static void nv04_instmem_dtor(struct nvkm_object *object) { struct nv04_instmem *imem = (void *)object; - nvkm_gpuobj_ref(NULL, &imem->ramfc); - nvkm_gpuobj_ref(NULL, &imem->ramro); - nvkm_ramht_ref(NULL, &imem->ramht); - nvkm_gpuobj_ref(NULL, &imem->vbios); + nvkm_gpuobj_ref(NULL, &imem->base.ramfc); + nvkm_gpuobj_ref(NULL, &imem->base.ramro); + nvkm_ramht_ref(NULL, &imem->base.ramht); + nvkm_gpuobj_ref(NULL, &imem->base.vbios); nvkm_mm_fini(&imem->heap); - if (imem->iomem) - iounmap(imem->iomem); nvkm_instmem_destroy(&imem->base); } @@ -158,24 +192,26 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* 0x00000-0x10000: reserve for probable vbios image */ ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x10000, 0, 0, - &imem->vbios); + &imem->base.vbios); if (ret) return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, &imem->ramht); + ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, + &imem->base.ramht); if (ret) return ret; /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */ ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x00800, 0, - NVOBJ_FLAG_ZERO_ALLOC, &imem->ramfc); + NVOBJ_FLAG_ZERO_ALLOC, + &imem->base.ramfc); if (ret) return ret; /* 0x18800-0x18a00: reserve for RAMRO */ ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x00200, 0, 0, - &imem->ramro); + &imem->base.ramro); if (ret) return ret; @@ -191,5 +227,7 @@ nv04_instmem_oclass = &(struct nvkm_instmem_impl) { .init = _nvkm_instmem_init, .fini = _nvkm_instmem_fini, }, - .instobj = &nv04_instobj_oclass.base, + .memory_new = nv04_instobj_new, + .persistent = false, + .zero = false, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h deleted file mode 100644 index 6065e34e2f0d6..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef __NV04_INSTMEM_H__ -#define __NV04_INSTMEM_H__ -#include "priv.h" - -#include - -extern struct nvkm_instobj_impl nv04_instobj_oclass; - -struct nv04_instmem { - struct nvkm_instmem base; - - void __iomem *iomem; - struct nvkm_mm heap; - - struct nvkm_gpuobj *vbios; - struct nvkm_ramht *ramht; - struct nvkm_gpuobj *ramro; - struct nvkm_gpuobj *ramfc; -}; - -static inline struct nv04_instmem * -nv04_instmem(void *obj) -{ - return (void *)nvkm_instmem(obj); -} - -struct nv04_instobj { - struct nvkm_instobj base; - struct nvkm_mm_node *mem; -}; - -void nv04_instmem_dtor(struct nvkm_object *); - -int nv04_instmem_alloc(struct nvkm_instmem *, struct nvkm_object *, - u32 size, u32 align, struct nvkm_object **pobject); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index c645e02615301..3ac55481cc97d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -21,11 +21,118 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#define nv40_instmem(p) container_of((p), struct nv40_instmem, base) +#include "priv.h" +#include #include #include +struct nv40_instmem { + struct nvkm_instmem base; + struct nvkm_mm heap; + void __iomem *iomem; +}; + +/****************************************************************************** + * instmem object implementation + *****************************************************************************/ +#define nv40_instobj(p) container_of((p), struct nv40_instobj, memory) + +struct nv40_instobj { + struct nvkm_memory memory; + struct nv40_instmem *imem; + struct nvkm_mm_node *node; +}; + +static enum nvkm_memory_target +nv40_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_INST; +} + +static u64 +nv40_instobj_addr(struct nvkm_memory *memory) +{ + return nv40_instobj(memory)->node->offset; +} + +static u64 +nv40_instobj_size(struct nvkm_memory *memory) +{ + return nv40_instobj(memory)->node->length; +} + +static void __iomem * +nv40_instobj_acquire(struct nvkm_memory *memory) +{ + struct nv40_instobj *iobj = nv40_instobj(memory); + return iobj->imem->iomem + iobj->node->offset; +} + +static void +nv40_instobj_release(struct nvkm_memory *memory) +{ +} + +static u32 +nv40_instobj_rd32(struct nvkm_memory *memory, u64 offset) +{ + struct nv40_instobj *iobj = nv40_instobj(memory); + return ioread32_native(iobj->imem->iomem + iobj->node->offset + offset); +} + +static void +nv40_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) +{ + struct nv40_instobj *iobj = nv40_instobj(memory); + iowrite32_native(data, iobj->imem->iomem + iobj->node->offset + offset); +} + +static void * +nv40_instobj_dtor(struct nvkm_memory *memory) +{ + struct nv40_instobj *iobj = nv40_instobj(memory); + mutex_lock(&iobj->imem->base.subdev.mutex); + nvkm_mm_free(&iobj->imem->heap, &iobj->node); + mutex_unlock(&iobj->imem->base.subdev.mutex); + return iobj; +} + +static const struct nvkm_memory_func +nv40_instobj_func = { + .dtor = nv40_instobj_dtor, + .target = nv40_instobj_target, + .size = nv40_instobj_size, + .addr = nv40_instobj_addr, + .acquire = nv40_instobj_acquire, + .release = nv40_instobj_release, + .rd32 = nv40_instobj_rd32, + .wr32 = nv40_instobj_wr32, +}; + +static int +nv40_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) +{ + struct nv40_instmem *imem = nv40_instmem(base); + struct nv40_instobj *iobj; + int ret; + + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) + return -ENOMEM; + *pmemory = &iobj->memory; + + nvkm_memory_ctor(&nv40_instobj_func, &iobj->memory); + iobj->imem = imem; + + mutex_lock(&imem->base.subdev.mutex); + ret = nvkm_mm_head(&imem->heap, 0, 1, size, size, + align ? align : 1, &iobj->node); + mutex_unlock(&imem->base.subdev.mutex); + return ret; +} + /****************************************************************************** * instmem subdev implementation *****************************************************************************/ @@ -33,17 +140,31 @@ static u32 nv40_instmem_rd32(struct nvkm_instmem *obj, u32 addr) { - struct nv04_instmem *imem = container_of(obj, typeof(*imem), base); + struct nv40_instmem *imem = container_of(obj, typeof(*imem), base); return ioread32_native(imem->iomem + addr); } static void nv40_instmem_wr32(struct nvkm_instmem *obj, u32 addr, u32 data) { - struct nv04_instmem *imem = container_of(obj, typeof(*imem), base); + struct nv40_instmem *imem = container_of(obj, typeof(*imem), base); iowrite32_native(data, imem->iomem + addr); } +static void +nv40_instmem_dtor(struct nvkm_object *object) +{ + struct nv40_instmem *imem = (void *)object; + nvkm_gpuobj_ref(NULL, &imem->base.ramfc); + nvkm_gpuobj_ref(NULL, &imem->base.ramro); + nvkm_ramht_ref(NULL, &imem->base.ramht); + nvkm_gpuobj_ref(NULL, &imem->base.vbios); + nvkm_mm_fini(&imem->heap); + if (imem->iomem) + iounmap(imem->iomem); + nvkm_instmem_destroy(&imem->base); +} + static const struct nvkm_instmem_func nv40_instmem_func = { .rd32 = nv40_instmem_rd32, @@ -56,7 +177,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_object **pobject) { struct nvkm_device *device = (void *)parent; - struct nv04_instmem *imem; + struct nv40_instmem *imem; int ret, bar, vs; ret = nvkm_instmem_create(parent, engine, oclass, &imem); @@ -86,7 +207,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, vs = hweight8((nvkm_rd32(device, 0x001540) & 0x0000ff00) >> 8); if (device->chipset == 0x40) imem->base.reserved = 0x6aa0 * vs; else if (device->chipset < 0x43) imem->base.reserved = 0x4f00 * vs; - else if (nv44_gr_class(imem)) imem->base.reserved = 0x4980 * vs; + else if (nv44_gr_class(imem)) imem->base.reserved = 0x4980 * vs; else imem->base.reserved = 0x4a40 * vs; imem->base.reserved += 16 * 1024; imem->base.reserved *= 32; /* per-channel */ @@ -101,12 +222,13 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* 0x00000-0x10000: reserve for probable vbios image */ ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x10000, 0, 0, - &imem->vbios); + &imem->base.vbios); if (ret) return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, &imem->ramht); + ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, + &imem->base.ramht); if (ret) return ret; @@ -114,7 +236,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * 0x18200-0x20000: padding */ ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x08000, 0, 0, - &imem->ramro); + &imem->base.ramro); if (ret) return ret; @@ -122,7 +244,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * 0x21000-0x40000: padding and some unknown crap */ ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x20000, 0, - NVOBJ_FLAG_ZERO_ALLOC, &imem->ramfc); + NVOBJ_FLAG_ZERO_ALLOC, &imem->base.ramfc); if (ret) return ret; @@ -134,9 +256,11 @@ nv40_instmem_oclass = &(struct nvkm_instmem_impl) { .base.handle = NV_SUBDEV(INSTMEM, 0x40), .base.ofuncs = &(struct nvkm_ofuncs) { .ctor = nv40_instmem_ctor, - .dtor = nv04_instmem_dtor, + .dtor = nv40_instmem_dtor, .init = _nvkm_instmem_init, .fini = _nvkm_instmem_fini, }, - .instobj = &nv04_instobj_oclass.base, + .memory_new = nv40_instobj_new, + .persistent = false, + .zero = false, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 4f6354df538a4..535a8f9c23ce9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -21,115 +21,201 @@ * * Authors: Ben Skeggs */ +#define nv50_instmem(p) container_of((p), struct nv50_instmem, base) #include "priv.h" +#include +#include #include +#include struct nv50_instmem { struct nvkm_instmem base; + unsigned long lock_flags; spinlock_t lock; u64 addr; }; +/****************************************************************************** + * instmem object implementation + *****************************************************************************/ +#define nv50_instobj(p) container_of((p), struct nv50_instobj, memory) + struct nv50_instobj { - struct nvkm_instobj base; + struct nvkm_memory memory; + struct nv50_instmem *imem; struct nvkm_mem *mem; + struct nvkm_vma bar; + void *map; }; -/****************************************************************************** - * instmem object implementation - *****************************************************************************/ +static enum nvkm_memory_target +nv50_instobj_target(struct nvkm_memory *memory) +{ + return NVKM_MEM_TARGET_VRAM; +} + +static u64 +nv50_instobj_addr(struct nvkm_memory *memory) +{ + return nv50_instobj(memory)->mem->offset; +} + +static u64 +nv50_instobj_size(struct nvkm_memory *memory) +{ + return (u64)nv50_instobj(memory)->mem->size << NVKM_RAM_MM_SHIFT; +} + +static void +nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vm *vm) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nvkm_subdev *subdev = &iobj->imem->base.subdev; + struct nvkm_device *device = subdev->device; + u64 size = nvkm_memory_size(memory); + void __iomem *map; + int ret; + + iobj->map = ERR_PTR(-ENOMEM); + + ret = nvkm_vm_get(vm, size, 12, NV_MEM_ACCESS_RW, &iobj->bar); + if (ret == 0) { + map = ioremap(nv_device_resource_start(device, 3) + + (u32)iobj->bar.offset, size); + if (map) { + nvkm_memory_map(memory, &iobj->bar, 0); + iobj->map = map; + } else { + nvkm_warn(subdev, "PRAMIN ioremap failed\n"); + nvkm_vm_put(&iobj->bar); + } + } else { + nvkm_warn(subdev, "PRAMIN exhausted\n"); + } +} + +static void +nv50_instobj_release(struct nvkm_memory *memory) +{ + struct nv50_instmem *imem = nv50_instobj(memory)->imem; + spin_unlock_irqrestore(&imem->lock, imem->lock_flags); +} + +static void __iomem * +nv50_instobj_acquire(struct nvkm_memory *memory) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nv50_instmem *imem = iobj->imem; + struct nvkm_bar *bar = imem->base.subdev.device->bar; + struct nvkm_vm *vm; + unsigned long flags; + + if (!iobj->map && bar && bar->kmap && (vm = bar->kmap(bar))) + nvkm_memory_boot(memory, vm); + if (!IS_ERR_OR_NULL(iobj->map)) + return iobj->map; + + spin_lock_irqsave(&imem->lock, flags); + imem->lock_flags = flags; + return NULL; +} static u32 -nv50_instobj_rd32(struct nvkm_object *object, u64 offset) +nv50_instobj_rd32(struct nvkm_memory *memory, u64 offset) { - struct nv50_instmem *imem = (void *)nvkm_instmem(object); - struct nv50_instobj *node = (void *)object; + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nv50_instmem *imem = iobj->imem; struct nvkm_device *device = imem->base.subdev.device; - unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + u64 base = (iobj->mem->offset + offset) & 0xffffff00000ULL; + u64 addr = (iobj->mem->offset + offset) & 0x000000fffffULL; u32 data; - spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } data = nvkm_rd32(device, 0x700000 + addr); - spin_unlock_irqrestore(&imem->lock, flags); return data; } static void -nv50_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data) +nv50_instobj_wr32(struct nvkm_memory *memory, u64 offset, u32 data) { - struct nv50_instmem *imem = (void *)nvkm_instmem(object); - struct nv50_instobj *node = (void *)object; + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nv50_instmem *imem = iobj->imem; struct nvkm_device *device = imem->base.subdev.device; - unsigned long flags; - u64 base = (node->mem->offset + offset) & 0xffffff00000ULL; - u64 addr = (node->mem->offset + offset) & 0x000000fffffULL; + u64 base = (iobj->mem->offset + offset) & 0xffffff00000ULL; + u64 addr = (iobj->mem->offset + offset) & 0x000000fffffULL; - spin_lock_irqsave(&imem->lock, flags); if (unlikely(imem->addr != base)) { nvkm_wr32(device, 0x001700, base >> 16); imem->addr = base; } nvkm_wr32(device, 0x700000 + addr, data); - spin_unlock_irqrestore(&imem->lock, flags); } static void -nv50_instobj_dtor(struct nvkm_object *object) +nv50_instobj_map(struct nvkm_memory *memory, struct nvkm_vma *vma, u64 offset) { - struct nv50_instobj *node = (void *)object; - struct nvkm_ram *ram = nvkm_fb(object)->ram; - ram->func->put(ram, &node->mem); - nvkm_instobj_destroy(&node->base); + struct nv50_instobj *iobj = nv50_instobj(memory); + nvkm_vm_map_at(vma, offset, iobj->mem); } +static void * +nv50_instobj_dtor(struct nvkm_memory *memory) +{ + struct nv50_instobj *iobj = nv50_instobj(memory); + struct nvkm_ram *ram = iobj->imem->base.subdev.device->fb->ram; + if (!IS_ERR_OR_NULL(iobj->map)) { + nvkm_vm_put(&iobj->bar); + iounmap(iobj->map); + } + ram->func->put(ram, &iobj->mem); + return iobj; +} + +static const struct nvkm_memory_func +nv50_instobj_func = { + .dtor = nv50_instobj_dtor, + .target = nv50_instobj_target, + .size = nv50_instobj_size, + .addr = nv50_instobj_addr, + .boot = nv50_instobj_boot, + .acquire = nv50_instobj_acquire, + .release = nv50_instobj_release, + .rd32 = nv50_instobj_rd32, + .wr32 = nv50_instobj_wr32, + .map = nv50_instobj_map, +}; + static int -nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, + struct nvkm_memory **pmemory) { - struct nvkm_ram *ram = nvkm_fb(parent)->ram; - struct nvkm_instobj_args *args = data; - struct nv50_instobj *node; + struct nv50_instmem *imem = nv50_instmem(base); + struct nv50_instobj *iobj; + struct nvkm_ram *ram = imem->base.subdev.device->fb->ram; int ret; - args->size = max((args->size + 4095) & ~4095, (u32)4096); - args->align = max((args->align + 4095) & ~4095, (u32)4096); + if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) + return -ENOMEM; + *pmemory = &iobj->memory; - ret = nvkm_instobj_create(parent, engine, oclass, &node); - *pobject = nv_object(node); - if (ret) - return ret; + nvkm_memory_ctor(&nv50_instobj_func, &iobj->memory); + iobj->imem = imem; + + size = max((size + 4095) & ~4095, (u32)4096); + align = max((align + 4095) & ~4095, (u32)4096); - ret = ram->func->get(ram, args->size, args->align, 0, 0x800, - &node->mem); + ret = ram->func->get(ram, size, align, 0, 0x800, &iobj->mem); if (ret) return ret; - node->base.addr = node->mem->offset; - node->base.size = node->mem->size << 12; - node->mem->page_shift = 12; + iobj->mem->page_shift = 12; return 0; } -static struct nvkm_instobj_impl -nv50_instobj_oclass = { - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_instobj_ctor, - .dtor = nv50_instobj_dtor, - .init = _nvkm_instobj_init, - .fini = _nvkm_instobj_fini, - .rd32 = nv50_instobj_rd32, - .wr32 = nv50_instobj_wr32, - }, -}; - /****************************************************************************** * instmem subdev implementation *****************************************************************************/ @@ -168,5 +254,7 @@ nv50_instmem_oclass = &(struct nvkm_instmem_impl) { .init = _nvkm_instmem_init, .fini = nv50_instmem_fini, }, - .instobj = &nv50_instobj_oclass.base, + .memory_new = nv50_instobj_new, + .persistent = false, + .zero = false, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index 819f615782cf8..2b6d73005767b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -2,35 +2,12 @@ #define __NVKM_INSTMEM_PRIV_H__ #include -struct nvkm_instobj_impl { - struct nvkm_oclass base; -}; - -struct nvkm_instobj_args { - u32 size; - u32 align; -}; - -#define nvkm_instobj_create(p,e,o,d) \ - nvkm_instobj_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_instobj_destroy(p) ({ \ - struct nvkm_instobj *iobj = (p); \ - _nvkm_instobj_dtor(nv_object(iobj)); \ -}) -#define nvkm_instobj_init(p) \ - _nvkm_object_init(&(p)->base) -#define nvkm_instobj_fini(p,s) \ - _nvkm_object_fini(&(p)->base, (s)) - -int nvkm_instobj_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_instobj_dtor(struct nvkm_object *); -#define _nvkm_instobj_init _nvkm_object_init -#define _nvkm_instobj_fini _nvkm_object_fini - struct nvkm_instmem_impl { struct nvkm_oclass base; - struct nvkm_oclass *instobj; + int (*memory_new)(struct nvkm_instmem *, u32 size, u32 align, + bool zero, struct nvkm_memory **); + bool persistent; + bool zero; }; #define nvkm_instmem_create(p,e,o,d) \ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index e81d3170325f6..35b6d33f6669c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -338,6 +338,25 @@ nvkm_vm_put(struct nvkm_vma *vma) nvkm_vm_ref(NULL, &vma->vm, NULL); } +int +nvkm_vm_boot(struct nvkm_vm *vm, u64 size) +{ + struct nvkm_mmu *mmu = vm->mmu; + struct nvkm_gpuobj *pgt; + int ret; + + ret = nvkm_gpuobj_new(nv_object(mmu), NULL, + (size >> mmu->spg_shift) * 8, 0x1000, + NVOBJ_FLAG_ZERO_ALLOC, &pgt); + if (ret == 0) { + vm->pgt[0].refcount[0] = 1; + vm->pgt[0].obj[0] = pgt; + nvkm_memory_boot(pgt->memory, vm); + } + + return ret; +} + int nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, u32 block, struct lock_class_key *key, struct nvkm_vm **pvm) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index e801e57946ad8..12d6ef461c62c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include -#include #include #include #include @@ -163,12 +162,9 @@ gf100_vm_flush(struct nvkm_vm *vm) { struct nvkm_mmu *mmu = (void *)vm->mmu; struct nvkm_device *device = mmu->subdev.device; - struct nvkm_bar *bar = device->bar; struct nvkm_vm_pgd *vpgd; u32 type; - bar->flush(bar); - type = 0x00000001; /* PAGE_ALL */ if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index b87fef9ee1988..cd63b9288507d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include -#include #include #include @@ -156,12 +155,9 @@ nv50_vm_flush(struct nvkm_vm *vm) struct nvkm_mmu *mmu = (void *)vm->mmu; struct nvkm_subdev *subdev = &mmu->subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bar *bar = device->bar; struct nvkm_engine *engine; int i, vme; - bar->flush(bar); - mutex_lock(&subdev->mutex); for (i = 0; i < NVDEV_SUBDEV_NR; i++) { if (!atomic_read(&vm->engref[i])) -- GitLab From d0659d3277cd7bf50e45d48f4692a7fbb11e5957 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5493/7006] drm/nouveau/mmu: directly use instmem for page tables Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/gpuobj.h | 2 +- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 11 +++--- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 8 ++-- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 39 +++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 12 +++--- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 16 ++++---- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 17 ++++---- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 22 +++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 18 +++++---- 12 files changed, 75 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index 4e4a9964d235b..f854b8098804c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -53,7 +53,7 @@ void nvkm_gpuobj_destroy(struct nvkm_gpuobj *); int nvkm_gpuobj_new(struct nvkm_object *, struct nvkm_object *, u32 size, u32 align, u32 flags, struct nvkm_gpuobj **); -int nvkm_gpuobj_dup(struct nvkm_object *, struct nvkm_gpuobj *, +int nvkm_gpuobj_dup(struct nvkm_object *, struct nvkm_memory *, struct nvkm_gpuobj **); int nvkm_gpuobj_map(struct nvkm_gpuobj *, u32 acc, struct nvkm_vma *); int nvkm_gpuobj_map_vm(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 677f6c0cbb9b7..ba4183cedf7ee 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -6,7 +6,7 @@ struct nvkm_device; struct nvkm_mem; struct nvkm_vm_pgt { - struct nvkm_gpuobj *obj[2]; + struct nvkm_memory *mem[2]; u32 refcount[2]; }; @@ -53,13 +53,14 @@ struct nvkm_mmu { struct nvkm_vm **); void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde, - struct nvkm_gpuobj *pgt[2]); - void (*map)(struct nvkm_vma *, struct nvkm_gpuobj *, + struct nvkm_memory *pgt[2]); + void (*map)(struct nvkm_vma *, struct nvkm_memory *, struct nvkm_mem *, u32 pte, u32 cnt, u64 phys, u64 delta); - void (*map_sg)(struct nvkm_vma *, struct nvkm_gpuobj *, + void (*map_sg)(struct nvkm_vma *, struct nvkm_memory *, struct nvkm_mem *, u32 pte, u32 cnt, dma_addr_t *); - void (*unmap)(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt); + void (*unmap)(struct nvkm_vma *, struct nvkm_memory *pgt, + u32 pte, u32 cnt); void (*flush)(struct nvkm_vm *); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index 0370360698395..ada5b6114a40f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -308,7 +308,6 @@ static void nvkm_gpudup_dtor(struct nvkm_object *object) { struct nvkm_gpuobj *gpuobj = (void *)object; - nvkm_object_ref(NULL, (struct nvkm_object **)&gpuobj->parent); nvkm_object_destroy(&gpuobj->object); } @@ -323,7 +322,7 @@ nvkm_gpudup_oclass = { }; int -nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_gpuobj *base, +nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_memory *base, struct nvkm_gpuobj **pgpuobj) { struct nvkm_gpuobj *gpuobj; @@ -335,8 +334,7 @@ nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_gpuobj *base, if (ret) return ret; - nvkm_object_ref(nv_object(base), (struct nvkm_object **)&gpuobj->parent); - gpuobj->addr = base->addr; - gpuobj->size = base->size; + gpuobj->addr = nvkm_memory_addr(base); + gpuobj->size = nvkm_memory_size(base); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c index 60c962bc0e477..9c68eb0e4a70f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c @@ -61,7 +61,7 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, if (dmaobj->clone) { struct nv04_mmu *mmu = nv04_mmu(dmaobj); - struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0]; + struct nvkm_memory *pgt = mmu->vm->pgt[0].mem[0]; if (!dmaobj->base.start) return nvkm_gpuobj_dup(parent, pgt, pgpuobj); nvkm_kmap(pgt); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 1ea6b3909c3a5..ccbc1fbc1d1e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -161,7 +161,7 @@ gf100_bar_dtor(struct nvkm_object *object) nvkm_gpuobj_ref(NULL, &bar->bar[1].mem); if (bar->bar[0].vm) { - nvkm_gpuobj_ref(NULL, &bar->bar[0].vm->pgt[0].obj[0]); + nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); } nvkm_gpuobj_ref(NULL, &bar->bar[0].pgd); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index ec864afc8862c..8e17b62fa1dae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -207,7 +207,7 @@ nv50_bar_dtor(struct nvkm_object *object) nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd); nvkm_gpuobj_ref(NULL, &bar->bar3); if (bar->bar3_vm) { - nvkm_gpuobj_ref(NULL, &bar->bar3_vm->pgt[0].obj[0]); + nvkm_memory_del(&bar->bar3_vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &bar->bar3_vm, bar->pgd); } nvkm_gpuobj_ref(NULL, &bar->pgd); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 35b6d33f6669c..6f284e5dc2c87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -46,7 +46,7 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) u32 num = r->length >> bits; while (num) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; end = (pte + num); if (unlikely(end >= max)) @@ -89,7 +89,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, struct scatterlist *sg; for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; sglen = sg_dma_len(sg) >> PAGE_SHIFT; end = pte + sglen; @@ -145,7 +145,7 @@ nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length, u32 end, len; while (num) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; end = (pte + num); if (unlikely(end >= max)) @@ -193,14 +193,14 @@ nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length) u32 end, len; while (num) { - struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big]; + struct nvkm_memory *pgt = vm->pgt[pde].mem[big]; end = (pte + num); if (unlikely(end >= max)) end = max; len = end - pte; - mmu->unmap(pgt, pte, len); + mmu->unmap(vma, pgt, pte, len); num -= len; pte += len; @@ -225,7 +225,7 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde) struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgd *vpgd; struct nvkm_vm_pgt *vpgt; - struct nvkm_gpuobj *pgt; + struct nvkm_memory *pgt; u32 pde; for (pde = fpde; pde <= lpde; pde++) { @@ -233,14 +233,14 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde) if (--vpgt->refcount[big]) continue; - pgt = vpgt->obj[big]; - vpgt->obj[big] = NULL; + pgt = vpgt->mem[big]; + vpgt->mem[big] = NULL; list_for_each_entry(vpgd, &vm->pgd_list, head) { - mmu->map_pgt(vpgd->obj, pde, vpgt->obj); + mmu->map_pgt(vpgd->obj, pde, vpgt->mem); } - nvkm_gpuobj_ref(NULL, &pgt); + nvkm_memory_del(&pgt); } } @@ -257,13 +257,13 @@ nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type) pgt_size = (1 << (mmu->pgt_bits + 12)) >> type; pgt_size *= 8; - ret = nvkm_gpuobj_new(nv_object(vm->mmu), NULL, pgt_size, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &vpgt->obj[big]); + ret = nvkm_memory_new(mmu->subdev.device, NVKM_MEM_TARGET_INST, + pgt_size, 0x1000, true, &vpgt->mem[big]); if (unlikely(ret)) return ret; list_for_each_entry(vpgd, &vm->pgd_list, head) { - mmu->map_pgt(vpgd->obj, pde, vpgt->obj); + mmu->map_pgt(vpgd->obj, pde, vpgt->mem); } vpgt->refcount[big]++; @@ -342,16 +342,15 @@ int nvkm_vm_boot(struct nvkm_vm *vm, u64 size) { struct nvkm_mmu *mmu = vm->mmu; - struct nvkm_gpuobj *pgt; + struct nvkm_memory *pgt; int ret; - ret = nvkm_gpuobj_new(nv_object(mmu), NULL, - (size >> mmu->spg_shift) * 8, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &pgt); + ret = nvkm_memory_new(mmu->subdev.device, NVKM_MEM_TARGET_INST, + (size >> mmu->spg_shift) * 8, 0x1000, true, &pgt); if (ret == 0) { vm->pgt[0].refcount[0] = 1; - vm->pgt[0].obj[0] = pgt; - nvkm_memory_boot(pgt->memory, vm); + vm->pgt[0].mem[0] = pgt; + nvkm_memory_boot(pgt, vm); } return ret; @@ -422,7 +421,7 @@ nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd) mutex_lock(&vm->mutex); for (i = vm->fpde; i <= vm->lpde; i++) - mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj); + mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].mem); list_add(&vpgd->head, &vm->pgd_list); mutex_unlock(&vm->mutex); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 12d6ef461c62c..e1374a01463a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -69,14 +69,14 @@ const u8 gf100_pte_storage_type_map[256] = static void -gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_gpuobj *pgt[2]) +gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_memory *pgt[2]) { u32 pde[2] = { 0, 0 }; if (pgt[0]) - pde[1] = 0x00000001 | (pgt[0]->addr >> 8); + pde[1] = 0x00000001 | (nvkm_memory_addr(pgt[0]) >> 8); if (pgt[1]) - pde[0] = 0x00000001 | (pgt[1]->addr >> 8); + pde[0] = 0x00000001 | (nvkm_memory_addr(pgt[1]) >> 8); nvkm_kmap(pgd); nvkm_wo32(pgd, (index * 8) + 0, pde[0]); @@ -99,7 +99,7 @@ gf100_vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target) } static void -gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +gf100_vm_map(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) { u64 next = 1 << (vma->node->type - 8); @@ -126,7 +126,7 @@ gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5; @@ -145,7 +145,7 @@ gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -gf100_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +gf100_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { nvkm_kmap(pgt); pte <<= 3; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index b30a865a40710..6995845ac6a1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -33,7 +33,7 @@ ******************************************************************************/ static void -nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { pte = 0x00008 + (pte * 4); @@ -52,7 +52,7 @@ nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -nv04_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv04_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { pte = 0x00008 + (pte * 4); nvkm_kmap(pgt); @@ -88,8 +88,9 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv04_mmu *mmu; - struct nvkm_gpuobj *dma; + struct nvkm_memory *dma; int ret; ret = nvkm_mmu_create(parent, engine, oclass, "PCIGART", @@ -113,11 +114,10 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(mmu), NULL, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 + 8, - 16, NVOBJ_FLAG_ZERO_ALLOC, - &mmu->vm->pgt[0].obj[0]); - dma = mmu->vm->pgt[0].obj[0]; + 16, true, &dma); + mmu->vm->pgt[0].mem[0] = dma; mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; @@ -134,7 +134,7 @@ nv04_mmu_dtor(struct nvkm_object *object) { struct nv04_mmu *mmu = (void *)object; if (mmu->vm) { - nvkm_gpuobj_ref(NULL, &mmu->vm->pgt[0].obj[0]); + nvkm_memory_del(&mmu->vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &mmu->vm, NULL); } if (mmu->nullp) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 6fd74f1f7290d..0f91d7aeb53f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -35,7 +35,7 @@ ******************************************************************************/ static void -nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { pte = pte * 4; @@ -54,7 +54,7 @@ nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv41_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { pte = pte * 4; nvkm_kmap(pgt); @@ -68,7 +68,7 @@ nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) static void nv41_vm_flush(struct nvkm_vm *vm) { - struct nv04_mmu *mmu = (void *)vm->mmu; + struct nv04_mmu *mmu = nv04_mmu(vm->mmu); struct nvkm_device *device = mmu->base.subdev.device; mutex_lock(&nv_subdev(mmu)->mutex); @@ -121,10 +121,9 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(mmu), NULL, - (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, - &mmu->vm->pgt[0].obj[0]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16, true, + &mmu->vm->pgt[0].mem[0]); mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; @@ -137,14 +136,14 @@ nv41_mmu_init(struct nvkm_object *object) { struct nv04_mmu *mmu = (void *)object; struct nvkm_device *device = mmu->base.subdev.device; - struct nvkm_gpuobj *dma = mmu->vm->pgt[0].obj[0]; + struct nvkm_memory *dma = mmu->vm->pgt[0].mem[0]; int ret; ret = nvkm_mmu_init(&mmu->base); if (ret) return ret; - nvkm_wr32(device, 0x100800, dma->addr | 0x00000002); + nvkm_wr32(device, 0x100800, 0x00000002 | nvkm_memory_addr(dma)); nvkm_mask(device, 0x10008c, 0x00000100, 0x00000100); nvkm_wr32(device, 0x100820, 0x00000000); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index ef53dfa356bb0..d2b586bc57a2a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -35,7 +35,7 @@ ******************************************************************************/ static void -nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null, +nv44_vm_fill(struct nvkm_memory *pgt, dma_addr_t null, dma_addr_t *list, u32 pte, u32 cnt) { u32 base = (pte << 2) & ~0x0000000f; @@ -81,10 +81,10 @@ nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null, } static void -nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { - struct nv04_mmu *mmu = (void *)vma->vm->mmu; + struct nv04_mmu *mmu = nv04_mmu(vma->vm->mmu); u32 tmp[4]; int i; @@ -114,9 +114,9 @@ nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv44_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { - struct nv04_mmu *mmu = (void *)nvkm_mmu(pgt); + struct nv04_mmu *mmu = nv04_mmu(vma->vm->mmu); nvkm_kmap(pgt); if (pte & 3) { @@ -143,7 +143,7 @@ nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) static void nv44_vm_flush(struct nvkm_vm *vm) { - struct nv04_mmu *mmu = (void *)vm->mmu; + struct nv04_mmu *mmu = nv04_mmu(vm->mmu); struct nvkm_device *device = mmu->base.subdev.device; nvkm_wr32(device, 0x100814, mmu->base.limit - NV44_GART_PAGE); nvkm_wr32(device, 0x100808, 0x00000020); @@ -200,10 +200,10 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(mmu), NULL, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, (NV44_GART_SIZE / NV44_GART_PAGE) * 4, - 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC, - &mmu->vm->pgt[0].obj[0]); + 512 * 1024, true, + &mmu->vm->pgt[0].mem[0]); mmu->vm->pgt[0].refcount[0] = 1; if (ret) return ret; @@ -216,7 +216,7 @@ nv44_mmu_init(struct nvkm_object *object) { struct nv04_mmu *mmu = (void *)object; struct nvkm_device *device = mmu->base.subdev.device; - struct nvkm_gpuobj *gart = mmu->vm->pgt[0].obj[0]; + struct nvkm_memory *gart = mmu->vm->pgt[0].mem[0]; u32 addr; int ret; @@ -229,7 +229,7 @@ nv44_mmu_init(struct nvkm_object *object) * of 512KiB for this to work correctly */ addr = nvkm_rd32(device, 0x10020c); - addr -= ((gart->addr >> 19) + 1) << 19; + addr -= ((nvkm_memory_addr(gart) >> 19) + 1) << 19; nvkm_wr32(device, 0x100850, 0x80000000); nvkm_wr32(device, 0x100818, mmu->null); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index cd63b9288507d..c08ac609cbe75 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -29,18 +29,20 @@ #include static void -nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2]) +nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_memory *pgt[2]) { u64 phys = 0xdeadcafe00000000ULL; u32 coverage = 0; if (pgt[0]) { - phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */ - coverage = (pgt[0]->size >> 3) << 12; + /* present, 4KiB pages */ + phys = 0x00000003 | nvkm_memory_addr(pgt[0]); + coverage = (nvkm_memory_size(pgt[0]) >> 3) << 12; } else if (pgt[1]) { - phys = 0x00000001 | pgt[1]->addr; /* present */ - coverage = (pgt[1]->size >> 3) << 16; + /* present, 64KiB pages */ + phys = 0x00000001 | nvkm_memory_addr(pgt[1]); + coverage = (nvkm_memory_size(pgt[1]) >> 3) << 16; } if (phys & 1) { @@ -72,7 +74,7 @@ vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target) } static void -nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv50_vm_map(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) { u32 comp = (mem->memtype & 0x180) >> 7; @@ -121,7 +123,7 @@ nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, +nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list) { u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2; @@ -137,7 +139,7 @@ nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt, } static void -nv50_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt) +nv50_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) { pte <<= 3; nvkm_kmap(pgt); -- GitLab From adb53d2773a7b0e95bb47e092c71906c7d989366 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5494/7006] drm/nouveau/bar/gf100: directly use instmem for channel descriptors Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index ccbc1fbc1d1e3..8e3574631068f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -28,7 +28,7 @@ #include struct gf100_bar_vm { - struct nvkm_gpuobj *mem; + struct nvkm_memory *mem; struct nvkm_gpuobj *pgd; struct nvkm_vm *vm; }; @@ -70,7 +70,7 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, resource_size_t bar_len; int ret; - ret = nvkm_gpuobj_new(nv_object(bar), NULL, 0x1000, 0, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0, false, &bar_vm->mem); if (ret) return ret; @@ -158,14 +158,14 @@ gf100_bar_dtor(struct nvkm_object *object) nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); nvkm_gpuobj_ref(NULL, &bar->bar[1].pgd); - nvkm_gpuobj_ref(NULL, &bar->bar[1].mem); + nvkm_memory_del(&bar->bar[1].mem); if (bar->bar[0].vm) { nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); } nvkm_gpuobj_ref(NULL, &bar->bar[0].pgd); - nvkm_gpuobj_ref(NULL, &bar->bar[0].mem); + nvkm_memory_del(&bar->bar[0].mem); nvkm_bar_destroy(&bar->base); } @@ -175,6 +175,7 @@ gf100_bar_init(struct nvkm_object *object) { struct gf100_bar *bar = (void *)object; struct nvkm_device *device = bar->base.subdev.device; + u32 addr; int ret; ret = nvkm_bar_init(&bar->base); @@ -184,10 +185,14 @@ gf100_bar_init(struct nvkm_object *object) nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); - nvkm_wr32(device, 0x001704, 0x80000000 | bar->bar[1].mem->addr >> 12); - if (bar->bar[0].mem) - nvkm_wr32(device, 0x001714, - 0xc0000000 | bar->bar[0].mem->addr >> 12); + addr = nvkm_memory_addr(bar->bar[1].mem) >> 12; + nvkm_wr32(device, 0x001704, 0x80000000 | addr); + + if (bar->bar[0].mem) { + addr = nvkm_memory_addr(bar->bar[0].mem) >> 12; + nvkm_wr32(device, 0x001714, 0xc0000000 | addr); + } + return 0; } -- GitLab From 5b1ab0c2c79c3556c4350f4f47d11745fdffad8f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5495/7006] drm/nouveau/imem/nv04-nv40: directly use instmem for vbios/ramfc/ramro Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/instmem.h | 6 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 49 +++++++++-------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.h | 3 -- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 20 +++---- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 32 ++++++------ .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 52 ++++++++++--------- .../drm/nouveau/nvkm/subdev/instmem/nv04.c | 14 ++--- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 14 ++--- 8 files changed, 91 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index 2e9e6f058dc08..a4b943ee7a9ad 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -13,10 +13,10 @@ struct nvkm_instmem { const struct nvkm_instmem_func *func; - struct nvkm_gpuobj *vbios; + struct nvkm_memory *vbios; struct nvkm_ramht *ramht; - struct nvkm_gpuobj *ramro; - struct nvkm_gpuobj *ramfc; + struct nvkm_memory *ramro; + struct nvkm_memory *ramfc; }; struct nvkm_instmem_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index b01490f71f098..f0fd1ce8f671b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -56,6 +56,7 @@ nv04_fifo_object_attach(struct nvkm_object *parent, { struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; u32 context, chid = chan->base.chid; int ret; @@ -83,7 +84,7 @@ nv04_fifo_object_attach(struct nvkm_object *parent, context |= chid << 24; mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(fifo->ramht, chid, handle, context); + ret = nvkm_ramht_insert(imem->ramht, chid, handle, context); mutex_unlock(&nv_subdev(fifo)->mutex); return ret; } @@ -92,8 +93,9 @@ void nv04_fifo_object_detach(struct nvkm_object *parent, int cookie) { struct nv04_fifo *fifo = (void *)parent->engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; mutex_lock(&nv_subdev(fifo)->mutex); - nvkm_ramht_remove(fifo->ramht, cookie); + nvkm_ramht_remove(imem->ramht, cookie); mutex_unlock(&nv_subdev(fifo)->mutex); } @@ -115,6 +117,7 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, struct nv03_channel_dma_v0 v0; } *args = data; struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; struct nv04_fifo_chan *chan; int ret; @@ -142,18 +145,18 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nvkm_kmap(fifo->ramfc); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x10, + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(fifo->ramfc); + nvkm_done(imem->ramfc); return 0; } @@ -162,13 +165,14 @@ nv04_fifo_chan_dtor(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; struct ramfc_desc *c = fifo->ramfc_desc; - nvkm_kmap(fifo->ramfc); + nvkm_kmap(imem->ramfc); do { - nvkm_wo32(fifo->ramfc, chan->ramfc + c->ctxp, 0x00000000); + nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); } while ((++c)->bits); - nvkm_done(fifo->ramfc); + nvkm_done(imem->ramfc); nvkm_fifo_channel_destroy(&chan->base); } @@ -198,8 +202,8 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) { struct nv04_fifo *fifo = (void *)object->engine; struct nv04_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *fctx = fifo->ramfc; struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_memory *fctx = device->imem->ramfc; struct ramfc_desc *c; unsigned long flags; u32 data = chan->ramfc; @@ -574,8 +578,6 @@ nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_device *device = (void *)parent; - struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; @@ -584,10 +586,6 @@ nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &fifo->ramht); - nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); - nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); - nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; nv_engine(fifo)->cclass = &nv04_fifo_cclass; @@ -602,9 +600,6 @@ void nv04_fifo_dtor(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object; - nvkm_gpuobj_ref(NULL, &fifo->ramfc); - nvkm_gpuobj_ref(NULL, &fifo->ramro); - nvkm_ramht_ref(NULL, &fifo->ramht); nvkm_fifo_destroy(&fifo->base); } @@ -613,6 +608,10 @@ nv04_fifo_init(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object; struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + struct nvkm_ramht *ramht = imem->ramht; + struct nvkm_memory *ramro = imem->ramro; + struct nvkm_memory *ramfc = imem->ramfc; int ret; ret = nvkm_fifo_init(&fifo->base); @@ -623,10 +622,10 @@ nv04_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((fifo->ramht->bits - 9) << 16) | - (fifo->ramht->gpuobj.addr >> 8)); - nvkm_wr32(device, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); - nvkm_wr32(device, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8); + ((ramht->bits - 9) << 16) | + (ramht->gpuobj.addr >> 8)); + nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8); nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h index cb4ec7bd7c51d..c7ce656eca7b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h @@ -142,9 +142,6 @@ struct ramfc_desc { struct nv04_fifo { struct nvkm_fifo base; struct ramfc_desc *ramfc_desc; - struct nvkm_ramht *ramht; - struct nvkm_gpuobj *ramro; - struct nvkm_gpuobj *ramfc; }; struct nv04_fifo_base { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 7491b10a76b7d..734c3a7678737 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -59,6 +58,7 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, struct nv03_channel_dma_v0 v0; } *args = data; struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; struct nv04_fifo_chan *chan; int ret; @@ -86,18 +86,18 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; - nvkm_kmap(fifo->ramfc); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x14, + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(fifo->ramfc); + nvkm_done(imem->ramfc); return 0; } @@ -145,8 +145,6 @@ nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_device *device = (void *)parent; - struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; @@ -155,10 +153,6 @@ nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &fifo->ramht); - nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); - nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); - nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; nv_engine(fifo)->cclass = &nv10_fifo_cclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index e652941d04f3b..69b9d421305bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -64,6 +64,7 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, struct nv03_channel_dma_v0 v0; } *args = data; struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; struct nv04_fifo_chan *chan; int ret; @@ -93,18 +94,18 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 64; - nvkm_kmap(fifo->ramfc); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x14, + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(fifo->ramfc); + nvkm_done(imem->ramfc); return 0; } @@ -152,8 +153,6 @@ nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_device *device = (void *)parent; - struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; @@ -162,10 +161,6 @@ nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &fifo->ramht); - nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); - nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); - nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; nv_engine(fifo)->cclass = &nv17_fifo_cclass; @@ -181,6 +176,10 @@ nv17_fifo_init(struct nvkm_object *object) { struct nv04_fifo *fifo = (void *)object; struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + struct nvkm_ramht *ramht = imem->ramht; + struct nvkm_memory *ramro = imem->ramro; + struct nvkm_memory *ramfc = imem->ramfc; int ret; ret = nvkm_fifo_init(&fifo->base); @@ -191,10 +190,11 @@ nv17_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((fifo->ramht->bits - 9) << 16) | - (fifo->ramht->gpuobj.addr >> 8)); - nvkm_wr32(device, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); - nvkm_wr32(device, NV03_PFIFO_RAMFC, fifo->ramfc->addr >> 8 | 0x00010000); + ((ramht->bits - 9) << 16) | + (ramht->gpuobj.addr >> 8)); + nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); + nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 | + 0x00010000); nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index f35ae76472392..eb6588ec0b6d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -69,6 +69,7 @@ nv40_fifo_object_attach(struct nvkm_object *parent, { struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; u32 context, chid = chan->base.chid; int ret; @@ -95,7 +96,7 @@ nv40_fifo_object_attach(struct nvkm_object *parent, context |= chid << 23; mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(fifo->ramht, chid, handle, context); + ret = nvkm_ramht_insert(imem->ramht, chid, handle, context); mutex_unlock(&nv_subdev(fifo)->mutex); return ret; } @@ -106,6 +107,7 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; unsigned long flags; u32 reg, ctx; @@ -130,9 +132,9 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) nvkm_wr32(device, reg, nv_engctx(engctx)->addr); - nvkm_kmap(fifo->ramfc); - nvkm_wo32(fifo->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); - nvkm_done(fifo->ramfc); + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + nvkm_done(imem->ramfc); nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); @@ -146,6 +148,7 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, struct nv04_fifo *fifo = (void *)parent->engine; struct nv04_fifo_chan *chan = (void *)parent; struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; unsigned long flags; u32 reg, ctx; @@ -169,9 +172,9 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) nvkm_wr32(device, reg, 0x00000000); - nvkm_kmap(fifo->ramfc); - nvkm_wo32(fifo->ramfc, chan->ramfc + ctx, 0x00000000); - nvkm_done(fifo->ramfc); + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000); + nvkm_done(imem->ramfc); nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); spin_unlock_irqrestore(&fifo->base.lock, flags); @@ -187,6 +190,7 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nv03_channel_dma_v0 v0; } *args = data; struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; struct nv04_fifo_chan *chan; int ret; @@ -216,19 +220,19 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_parent(chan)->object_detach = nv04_fifo_object_detach; chan->ramfc = chan->base.chid * 128; - nvkm_kmap(fifo->ramfc); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x18, 0x30000000 | + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | #ifdef __BIG_ENDIAN NV_PFIFO_CACHE1_BIG_ENDIAN | #endif NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_wo32(fifo->ramfc, chan->ramfc + 0x3c, 0x0001ffff); - nvkm_done(fifo->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + nvkm_done(imem->ramfc); return 0; } @@ -276,8 +280,6 @@ nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_device *device = (void *)parent; - struct nvkm_instmem *imem = device->imem; struct nv04_fifo *fifo; int ret; @@ -286,10 +288,6 @@ nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nvkm_ramht_ref(imem->ramht, &fifo->ramht); - nvkm_gpuobj_ref(imem->ramro, &fifo->ramro); - nvkm_gpuobj_ref(imem->ramfc, &fifo->ramfc); - nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; nv_engine(fifo)->cclass = &nv40_fifo_cclass; @@ -306,6 +304,10 @@ nv40_fifo_init(struct nvkm_object *object) struct nv04_fifo *fifo = (void *)object; struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_fb *fb = device->fb; + struct nvkm_instmem *imem = device->imem; + struct nvkm_ramht *ramht = imem->ramht; + struct nvkm_memory *ramro = imem->ramro; + struct nvkm_memory *ramfc = imem->ramfc; int ret; ret = nvkm_fifo_init(&fifo->base); @@ -317,9 +319,9 @@ nv40_fifo_init(struct nvkm_object *object) nvkm_wr32(device, 0x002058, 0x00000001); nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | - ((fifo->ramht->bits - 9) << 16) | - (fifo->ramht->gpuobj.addr >> 8)); - nvkm_wr32(device, NV03_PFIFO_RAMRO, fifo->ramro->addr >> 8); + ((ramht->bits - 9) << 16) | + (ramht->gpuobj.addr >> 8)); + nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); switch (nv_device(fifo)->chipset) { case 0x47: @@ -337,8 +339,8 @@ nv40_fifo_init(struct nvkm_object *object) default: nvkm_wr32(device, 0x002230, 0x00000000); nvkm_wr32(device, 0x002220, ((fb->ram->size - 512 * 1024 + - fifo->ramfc->addr) >> 16) | - 0x00030000); + nvkm_memory_addr(ramfc)) >> 16) | + 0x00030000); break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index c499e485373b8..56330ccf46563 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -154,10 +154,10 @@ static void nv04_instmem_dtor(struct nvkm_object *object) { struct nv04_instmem *imem = (void *)object; - nvkm_gpuobj_ref(NULL, &imem->base.ramfc); - nvkm_gpuobj_ref(NULL, &imem->base.ramro); + nvkm_memory_del(&imem->base.ramfc); + nvkm_memory_del(&imem->base.ramro); nvkm_ramht_ref(NULL, &imem->base.ramht); - nvkm_gpuobj_ref(NULL, &imem->base.vbios); + nvkm_memory_del(&imem->base.vbios); nvkm_mm_fini(&imem->heap); nvkm_instmem_destroy(&imem->base); } @@ -173,6 +173,7 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv04_instmem *imem; int ret; @@ -191,7 +192,7 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* 0x00000-0x10000: reserve for probable vbios image */ - ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x10000, 0, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x10000, 0, false, &imem->base.vbios); if (ret) return ret; @@ -203,14 +204,13 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */ - ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x00800, 0, - NVOBJ_FLAG_ZERO_ALLOC, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x00800, 0, true, &imem->base.ramfc); if (ret) return ret; /* 0x18800-0x18a00: reserve for RAMRO */ - ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x00200, 0, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x00200, 0, false, &imem->base.ramro); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index 3ac55481cc97d..5a2709d499e99 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -155,10 +155,10 @@ static void nv40_instmem_dtor(struct nvkm_object *object) { struct nv40_instmem *imem = (void *)object; - nvkm_gpuobj_ref(NULL, &imem->base.ramfc); - nvkm_gpuobj_ref(NULL, &imem->base.ramro); + nvkm_memory_del(&imem->base.ramfc); + nvkm_memory_del(&imem->base.ramro); nvkm_ramht_ref(NULL, &imem->base.ramht); - nvkm_gpuobj_ref(NULL, &imem->base.vbios); + nvkm_memory_del(&imem->base.vbios); nvkm_mm_fini(&imem->heap); if (imem->iomem) iounmap(imem->iomem); @@ -221,7 +221,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* 0x00000-0x10000: reserve for probable vbios image */ - ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x10000, 0, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x10000, 0, false, &imem->base.vbios); if (ret) return ret; @@ -235,7 +235,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* 0x18000-0x18200: reserve for RAMRO * 0x18200-0x20000: padding */ - ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x08000, 0, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x08000, 0, false, &imem->base.ramro); if (ret) return ret; @@ -243,8 +243,8 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* 0x20000-0x21000: reserve for RAMFC * 0x21000-0x40000: padding and some unknown crap */ - ret = nvkm_gpuobj_new(nv_object(imem), NULL, 0x20000, 0, - NVOBJ_FLAG_ZERO_ALLOC, &imem->base.ramfc); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x20000, 0, true, + &imem->base.ramfc); if (ret) return ret; -- GitLab From 406ca8c714825c2d9e2c866787150eae4e1a1cc3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5496/7006] drm/nouveau/falcon: directly use instmem for ucode image Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index 3ce0ffc8ef869..5e6f1f518ea5b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -35,7 +35,7 @@ struct nvkm_falcon { u8 version; u8 secret; - struct nvkm_gpuobj *core; + struct nvkm_memory *core; bool external; struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index ac39cb7e7299b..27bc50e80a56b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -168,8 +168,9 @@ _nvkm_falcon_init(struct nvkm_object *object) /* ensure any "self-bootstrapping" firmware image is in vram */ if (!falcon->data.data && !falcon->core) { - ret = nvkm_gpuobj_new(object->parent, NULL, falcon->code.size, - 256, 0, &falcon->core); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + falcon->code.size, 256, false, + &falcon->core); if (ret) { nvkm_error(subdev, "core allocation failed, %d\n", ret); return ret; @@ -183,12 +184,13 @@ _nvkm_falcon_init(struct nvkm_object *object) /* upload firmware bootloader (or the full code segments) */ if (falcon->core) { + u64 addr = nvkm_memory_addr(falcon->core); if (device->card_type < NV_C0) nvkm_wr32(device, base + 0x618, 0x04000000); else nvkm_wr32(device, base + 0x618, 0x00000114); nvkm_wr32(device, base + 0x11c, 0); - nvkm_wr32(device, base + 0x110, falcon->core->addr >> 8); + nvkm_wr32(device, base + 0x110, addr >> 8); nvkm_wr32(device, base + 0x114, 0); nvkm_wr32(device, base + 0x118, 0x00006610); } else { @@ -243,7 +245,7 @@ _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) const u32 base = falcon->addr; if (!suspend) { - nvkm_gpuobj_ref(NULL, &falcon->core); + nvkm_memory_del(&falcon->core); if (falcon->external) { vfree(falcon->data.data); vfree(falcon->code.data); -- GitLab From faf468981e3a50ce088460595bd10812af9be7f8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5497/7006] drm/nouveau/xtensa: directly use instmem for ucode image Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/xtensa.h | 3 +-- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 16 +++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h index 5bd4b6e59584c..b05babfe0ca4c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h @@ -1,13 +1,12 @@ #ifndef __NVKM_XTENSA_H__ #define __NVKM_XTENSA_H__ #include -struct nvkm_gpuobj; struct nvkm_xtensa { struct nvkm_engine engine; u32 addr; - struct nvkm_gpuobj *gpu_fw; + struct nvkm_memory *gpu_fw; u32 fifo_val; u32 unkd28; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index 45dd8b8da4c95..6ffc6c4315b6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -88,6 +88,7 @@ _nvkm_xtensa_init(struct nvkm_object *object) const struct firmware *fw; char name[32]; int i, ret; + u64 addr, size; u32 tmp; ret = nvkm_engine_init_old(&xtensa->engine); @@ -110,16 +111,14 @@ _nvkm_xtensa_init(struct nvkm_object *object) return -EINVAL; } - ret = nvkm_gpuobj_new(object, NULL, 0x40000, 0x1000, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x40000, 0x1000, false, &xtensa->gpu_fw); if (ret) { release_firmware(fw); return ret; } - nvkm_debug(subdev, "Loading firmware to address: %010llx\n", - xtensa->gpu_fw->addr); - nvkm_kmap(xtensa->gpu_fw); for (i = 0; i < fw->size / 4; i++) nvkm_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i)); @@ -127,6 +126,9 @@ _nvkm_xtensa_init(struct nvkm_object *object) release_firmware(fw); } + addr = nvkm_memory_addr(xtensa->gpu_fw); + size = nvkm_memory_size(xtensa->gpu_fw); + nvkm_wr32(device, base + 0xd10, 0x1fffffff); /* ?? */ nvkm_wr32(device, base + 0xd08, 0x0fffffff); /* ?? */ @@ -134,9 +136,9 @@ _nvkm_xtensa_init(struct nvkm_object *object) nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ - nvkm_wr32(device, base + 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */ + nvkm_wr32(device, base + 0xcc0, addr >> 8); /* XT_REGION_BASE */ nvkm_wr32(device, base + 0xcc4, 0x1c); /* XT_REGION_SETUP */ - nvkm_wr32(device, base + 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */ + nvkm_wr32(device, base + 0xcc8, size >> 8); /* XT_REGION_LIMIT */ tmp = nvkm_rd32(device, 0x0); nvkm_wr32(device, base + 0xde0, tmp); /* SCRATCH_H2X */ @@ -159,7 +161,7 @@ _nvkm_xtensa_fini(struct nvkm_object *object, bool suspend) nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */ if (!suspend) - nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw); + nvkm_memory_del(&xtensa->gpu_fw); return nvkm_engine_fini_old(&xtensa->engine, suspend); } -- GitLab From 358ce601ae5de59bf6f08f79455c5b3cb7d359d4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5498/7006] drm/nouveau/fifo: directly use instmem for runlists and polling areas Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/gpuobj.h | 1 - drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 16 ------- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 9 ++-- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 41 +++++++++-------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 44 +++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 17 +++---- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.h | 2 +- 7 files changed, 64 insertions(+), 66 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index f854b8098804c..7613107c05fa6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -55,7 +55,6 @@ int nvkm_gpuobj_new(struct nvkm_object *, struct nvkm_object *, u32 size, u32 align, u32 flags, struct nvkm_gpuobj **); int nvkm_gpuobj_dup(struct nvkm_object *, struct nvkm_memory *, struct nvkm_gpuobj **); -int nvkm_gpuobj_map(struct nvkm_gpuobj *, u32 acc, struct nvkm_vma *); int nvkm_gpuobj_map_vm(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access, struct nvkm_vma *); void nvkm_gpuobj_unmap(struct nvkm_vma *); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index ada5b6114a40f..c14469c3a861e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -263,22 +263,6 @@ nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu, (struct nvkm_object **)pgpuobj); } -int -nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, u32 access, struct nvkm_vma *vma) -{ - struct nvkm_memory *memory = gpuobj->memory; - struct nvkm_bar *bar = nvkm_bar(gpuobj); - int ret = -EINVAL; - - if (bar && bar->umap) { - ret = bar->umap(bar, gpuobj->size, 12, vma); - if (ret == 0) - nvkm_memory_map(memory, vma, 0); - } - - return ret; -} - int nvkm_gpuobj_map_vm(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm, u32 access, struct nvkm_vma *vma) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index c6150eaf16f08..96c6835e9f149 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -455,6 +455,7 @@ g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_fifo *fifo; int ret; @@ -463,13 +464,13 @@ g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, - &fifo->playlist[0]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->playlist[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, - &fifo->playlist[1]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->playlist[1]); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 763a2db7603a5..cbb8d249e7fbd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -42,13 +43,13 @@ struct gf100_fifo { u64 mask; struct { - struct nvkm_gpuobj *mem[2]; + struct nvkm_memory *mem[2]; int active; wait_queue_head_t wait; } runlist; struct { - struct nvkm_gpuobj *mem; + struct nvkm_memory *mem; struct nvkm_vma bar; } user; int spoon_nr; @@ -78,7 +79,7 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) { struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_gpuobj *cur; + struct nvkm_memory *cur; int i, p; mutex_lock(&nv_subdev(fifo)->mutex); @@ -96,7 +97,7 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) } nvkm_done(cur); - nvkm_wr32(device, 0x002270, cur->addr >> 12); + nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); nvkm_wr32(device, 0x002274, 0x01f00000 | (p >> 3)); if (wait_event_timeout(fifo->runlist.wait, @@ -238,10 +239,11 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (i = 0; i < 0x1000; i += 4) nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); nvkm_done(fifo->user.mem); + usermem = nvkm_memory_addr(fifo->user.mem) + usermem; nvkm_kmap(ramfc); - nvkm_wo32(ramfc, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); - nvkm_wo32(ramfc, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); + nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); + nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); nvkm_wo32(ramfc, 0x10, 0x0000face); nvkm_wo32(ramfc, 0x30, 0xfffff902); nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); @@ -879,6 +881,8 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; + struct nvkm_bar *bar = device->bar; struct gf100_fifo *fifo; int ret; @@ -889,28 +893,29 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, INIT_WORK(&fifo->fault, gf100_fifo_recover_work); - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x1000, 0x1000, 0, - &fifo->runlist.mem[0]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, + false, &fifo->runlist.mem[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x1000, 0x1000, 0, - &fifo->runlist.mem[1]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, + false, &fifo->runlist.mem[1]); if (ret) return ret; init_waitqueue_head(&fifo->runlist.wait); - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 0x1000, 0x1000, 0, - &fifo->user.mem); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000, + 0x1000, false, &fifo->user.mem); if (ret) return ret; - ret = nvkm_gpuobj_map(fifo->user.mem, NV_MEM_ACCESS_RW, - &fifo->user.bar); + ret = bar->umap(bar, 128 * 0x1000, 12, &fifo->user.bar); if (ret) return ret; + nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); + ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &fifo->base.uevent); if (ret) return ret; @@ -927,10 +932,10 @@ gf100_fifo_dtor(struct nvkm_object *object) { struct gf100_fifo *fifo = (void *)object; - nvkm_gpuobj_unmap(&fifo->user.bar); - nvkm_gpuobj_ref(NULL, &fifo->user.mem); - nvkm_gpuobj_ref(NULL, &fifo->runlist.mem[0]); - nvkm_gpuobj_ref(NULL, &fifo->runlist.mem[1]); + nvkm_vm_put(&fifo->user.bar); + nvkm_memory_del(&fifo->user.mem); + nvkm_memory_del(&fifo->runlist.mem[0]); + nvkm_memory_del(&fifo->runlist.mem[1]); nvkm_fifo_destroy(&fifo->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index d1238aa7bec55..0e8356d5fa02e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,7 @@ static const struct { #define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) struct gk104_fifo_engn { - struct nvkm_gpuobj *runlist[2]; + struct nvkm_memory *runlist[2]; int cur_runlist; wait_queue_head_t wait; }; @@ -66,7 +67,7 @@ struct gk104_fifo { struct gk104_fifo_engn engine[FIFO_ENGINE_NR]; struct { - struct nvkm_gpuobj *mem; + struct nvkm_memory *mem; struct nvkm_vma bar; } user; int spoon_nr; @@ -98,7 +99,7 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) struct gk104_fifo_engn *engn = &fifo->engine[engine]; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_gpuobj *cur; + struct nvkm_memory *cur; int i, p; mutex_lock(&nv_subdev(fifo)->mutex); @@ -116,7 +117,7 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) } nvkm_done(cur); - nvkm_wr32(device, 0x002270, cur->addr >> 12); + nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); nvkm_wr32(device, 0x002274, (engine << 20) | (p >> 3)); if (wait_event_timeout(engn->wait, !(nvkm_rd32(device, 0x002284 + @@ -296,10 +297,11 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, for (i = 0; i < 0x200; i += 4) nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); nvkm_done(fifo->user.mem); + usermem = nvkm_memory_addr(fifo->user.mem) + usermem; nvkm_kmap(ramfc); - nvkm_wo32(ramfc, 0x08, lower_32_bits(fifo->user.mem->addr + usermem)); - nvkm_wo32(ramfc, 0x0c, upper_32_bits(fifo->user.mem->addr + usermem)); + nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); + nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); nvkm_wo32(ramfc, 0x10, 0x0000face); nvkm_wo32(ramfc, 0x30, 0xfffff902); nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); @@ -1107,12 +1109,12 @@ gk104_fifo_dtor(struct nvkm_object *object) struct gk104_fifo *fifo = (void *)object; int i; - nvkm_gpuobj_unmap(&fifo->user.bar); - nvkm_gpuobj_ref(NULL, &fifo->user.mem); + nvkm_vm_put(&fifo->user.bar); + nvkm_memory_del(&fifo->user.mem); for (i = 0; i < FIFO_ENGINE_NR; i++) { - nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[1]); - nvkm_gpuobj_ref(NULL, &fifo->engine[i].runlist[0]); + nvkm_memory_del(&fifo->engine[i].runlist[1]); + nvkm_memory_del(&fifo->engine[i].runlist[0]); } nvkm_fifo_destroy(&fifo->base); @@ -1123,6 +1125,8 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; + struct nvkm_bar *bar = device->bar; struct gk104_fifo_impl *impl = (void *)oclass; struct gk104_fifo *fifo; int ret, i; @@ -1136,29 +1140,33 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, INIT_WORK(&fifo->fault, gk104_fifo_recover_work); for (i = 0; i < FIFO_ENGINE_NR; i++) { - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000, - 0, &fifo->engine[i].runlist[0]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x8000, 0x1000, false, + &fifo->engine[i].runlist[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 0x8000, 0x1000, - 0, &fifo->engine[i].runlist[1]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x8000, 0x1000, false, + &fifo->engine[i].runlist[1]); if (ret) return ret; init_waitqueue_head(&fifo->engine[i].wait); } - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, impl->channels * 0x200, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &fifo->user.mem); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + impl->channels * 0x200, 0x1000, + true, &fifo->user.mem); if (ret) return ret; - ret = nvkm_gpuobj_map(fifo->user.mem, NV_MEM_ACCESS_RW, - &fifo->user.bar); + ret = bar->umap(bar, impl->channels * 0x200, 12, &fifo->user.bar); if (ret) return ret; + nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); + ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &fifo->base.uevent); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index ffa495c1692bb..96e5b61daf10c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -41,7 +41,7 @@ static void nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) { struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_gpuobj *cur; + struct nvkm_memory *cur; int i, p; cur = fifo->playlist[fifo->cur_playlist]; @@ -54,7 +54,7 @@ nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) } nvkm_done(cur); - nvkm_wr32(device, 0x0032f4, cur->addr >> 12); + nvkm_wr32(device, 0x0032f4, nvkm_memory_addr(cur) >> 12); nvkm_wr32(device, 0x0032ec, p); nvkm_wr32(device, 0x002500, 0x00000101); } @@ -467,6 +467,7 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv50_fifo *fifo; int ret; @@ -475,13 +476,13 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, - &fifo->playlist[0]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->playlist[0]); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(fifo), NULL, 128 * 4, 0x1000, 0, - &fifo->playlist[1]); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->playlist[1]); if (ret) return ret; @@ -499,8 +500,8 @@ nv50_fifo_dtor(struct nvkm_object *object) { struct nv50_fifo *fifo = (void *)object; - nvkm_gpuobj_ref(NULL, &fifo->playlist[1]); - nvkm_gpuobj_ref(NULL, &fifo->playlist[0]); + nvkm_memory_del(&fifo->playlist[1]); + nvkm_memory_del(&fifo->playlist[0]); nvkm_fifo_destroy(&fifo->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h index 722fcce7070ed..0c826153bac66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h @@ -4,7 +4,7 @@ struct nv50_fifo { struct nvkm_fifo base; - struct nvkm_gpuobj *playlist[2]; + struct nvkm_memory *playlist[2]; int cur_playlist; }; -- GitLab From 227c95d90a3c50defbc7b4f98605e13af4e6214c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5499/7006] drm/nouveau/gr: directly use instmem where currently possible Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 27 ++++++----- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 48 +++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 8 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c | 8 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 10 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 8 ++-- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 7 ++- 15 files changed, 87 insertions(+), 63 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index a2e60b1ddb27c..d04c015eea818 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1272,34 +1272,37 @@ gf100_grctx_generate(struct gf100_gr *gr) struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_gpuobj *chan; + struct nvkm_memory *chan; struct gf100_grctx info; int ret, i; + u64 addr; /* allocate memory to for a "channel", which we'll use to generate * the default context values */ - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x80000 + gr->size, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x80000 + gr->size, + 0x1000, true, &chan); if (ret) { nvkm_error(subdev, "failed to allocate chan memory, %d\n", ret); return ret; } + addr = nvkm_memory_addr(chan); + /* PGD pointer */ nvkm_kmap(chan); - nvkm_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000)); - nvkm_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000)); + nvkm_wo32(chan, 0x0200, lower_32_bits(addr + 0x1000)); + nvkm_wo32(chan, 0x0204, upper_32_bits(addr + 0x1000)); nvkm_wo32(chan, 0x0208, 0xffffffff); nvkm_wo32(chan, 0x020c, 0x000000ff); /* PGT[0] pointer */ nvkm_wo32(chan, 0x1000, 0x00000000); - nvkm_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8); + nvkm_wo32(chan, 0x1004, 0x00000001 | (addr + 0x2000) >> 8); /* identity-map the whole "channel" into its own vm */ - for (i = 0; i < chan->size / 4096; i++) { - u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1; + for (i = 0; i < nvkm_memory_size(chan) / 4096; i++) { + u64 addr = ((nvkm_memory_addr(chan) + (i * 4096)) >> 8) | 1; nvkm_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr)); nvkm_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr)); } @@ -1309,7 +1312,7 @@ gf100_grctx_generate(struct gf100_gr *gr) nvkm_wo32(chan, 0x0214, 0x00000000); nvkm_done(chan); - nvkm_wr32(device, 0x100cb8, (chan->addr + 0x1000) >> 8); + nvkm_wr32(device, 0x100cb8, (addr + 0x1000) >> 8); nvkm_wr32(device, 0x100cbc, 0x80000001); nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x100c80) & 0x00008000) @@ -1326,7 +1329,7 @@ gf100_grctx_generate(struct gf100_gr *gr) /* make channel current */ if (gr->firmware) { nvkm_wr32(device, 0x409840, 0x00000030); - nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); + nvkm_wr32(device, 0x409500, 0x80000000 | addr >> 12); nvkm_wr32(device, 0x409504, 0x00000003); nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x409800) & 0x00000010) @@ -1341,7 +1344,7 @@ gf100_grctx_generate(struct gf100_gr *gr) nvkm_done(chan); } else { nvkm_wr32(device, 0x409840, 0x80000000); - nvkm_wr32(device, 0x409500, 0x80000000 | chan->addr >> 12); + nvkm_wr32(device, 0x409500, 0x80000000 | addr >> 12); nvkm_wr32(device, 0x409504, 0x00000001); nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x409800) & 0x80000000) @@ -1376,7 +1379,7 @@ gf100_grctx_generate(struct gf100_gr *gr) } done: - nvkm_gpuobj_ref(NULL, &chan); + nvkm_memory_del(&chan); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 1e712355a70b5..362d5fa394d44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -283,6 +283,7 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct gf100_gr_data *data = gr->mmio_data; struct gf100_gr_mmio *mmio = gr->mmio_list; struct gf100_gr_chan *chan; + struct nvkm_device *device = gr->base.engine.subdev.device; struct nvkm_gpuobj *image; int ret, i; @@ -298,29 +299,32 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, * fuc to modify some per-context register settings on first load * of the context. */ - ret = nvkm_gpuobj_new(nv_object(chan), NULL, 0x1000, 0x100, 0, - &chan->mmio); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x100, + false, &chan->mmio); if (ret) return ret; - ret = nvkm_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm, - NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, - &chan->mmio_vma); + ret = nvkm_vm_get(vm, 0x1000, 12, NV_MEM_ACCESS_RW | + NV_MEM_ACCESS_SYS, &chan->mmio_vma); if (ret) return ret; + nvkm_memory_map(chan->mmio, &chan->mmio_vma, 0); + /* allocate buffers referenced by mmio list */ for (i = 0; data->size && i < ARRAY_SIZE(gr->mmio_data); i++) { - ret = nvkm_gpuobj_new(nv_object(chan), NULL, data->size, - data->align, 0, &chan->data[i].mem); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + data->size, data->align, false, + &chan->data[i].mem); if (ret) return ret; - ret = nvkm_gpuobj_map_vm(chan->data[i].mem, vm, data->access, - &chan->data[i].vma); + ret = nvkm_vm_get(vm, nvkm_memory_size(chan->data[i].mem), + 12, data->access, &chan->data[i].vma); if (ret) return ret; + nvkm_memory_map(chan->data[i].mem, &chan->data[i].vma, 0); data++; } @@ -372,12 +376,18 @@ gf100_gr_context_dtor(struct nvkm_object *object) int i; for (i = 0; i < ARRAY_SIZE(chan->data); i++) { - nvkm_gpuobj_unmap(&chan->data[i].vma); - nvkm_gpuobj_ref(NULL, &chan->data[i].mem); + if (chan->data[i].vma.node) { + nvkm_vm_unmap(&chan->data[i].vma); + nvkm_vm_put(&chan->data[i].vma); + } + nvkm_memory_del(&chan->data[i].mem); } - nvkm_gpuobj_unmap(&chan->mmio_vma); - nvkm_gpuobj_ref(NULL, &chan->mmio); + if (chan->mmio_vma.node) { + nvkm_vm_unmap(&chan->mmio_vma); + nvkm_vm_put(&chan->mmio_vma); + } + nvkm_memory_del(&chan->mmio); nvkm_gr_context_destroy(&chan->base); } @@ -1490,8 +1500,8 @@ gf100_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); - nvkm_wr32(device, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); - nvkm_wr32(device, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); gf100_gr_mmio(gr, oclass->mmio); @@ -1634,8 +1644,8 @@ gf100_gr_dtor(struct nvkm_object *object) gf100_gr_dtor_fw(&gr->fuc41ac); gf100_gr_dtor_fw(&gr->fuc41ad); - nvkm_gpuobj_ref(NULL, &gr->unk4188b8); - nvkm_gpuobj_ref(NULL, &gr->unk4188b4); + nvkm_memory_del(&gr->unk4188b8); + nvkm_memory_del(&gr->unk4188b4); nvkm_gr_destroy(&gr->base); } @@ -1675,12 +1685,12 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, gr->firmware = true; } - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x1000, 256, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, &gr->unk4188b4); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 0x1000, 256, 0, + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, &gr->unk4188b8); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index b23bc32536fe9..62bf56906cbe8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -95,8 +95,8 @@ struct gf100_gr { u8 ppc_nr[GPC_MAX]; u8 ppc_tpc_nr[GPC_MAX][4]; - struct nvkm_gpuobj *unk4188b4; - struct nvkm_gpuobj *unk4188b8; + struct nvkm_memory *unk4188b4; + struct nvkm_memory *unk4188b8; struct gf100_gr_data mmio_data[4]; struct gf100_gr_mmio mmio_list[4096/8]; @@ -109,11 +109,11 @@ struct gf100_gr { struct gf100_gr_chan { struct nvkm_gr_chan base; - struct nvkm_gpuobj *mmio; + struct nvkm_memory *mmio; struct nvkm_vma mmio_vma; int mmio_nr; struct { - struct nvkm_gpuobj *mem; + struct nvkm_memory *mem; struct nvkm_vma vma; } data[4]; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index 89bb101615544..94c6ca1d739a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -218,8 +218,8 @@ gk104_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_BCAST(0x088c), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); - nvkm_wr32(device, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); - nvkm_wr32(device, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); gf100_gr_mmio(gr, oclass->mmio); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index 6cb8ff3fb68a4..a80fda50719aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -280,8 +280,8 @@ gk20a_gr_init(struct nvkm_object *object) return ret; /* MMU debug buffer */ - nvkm_wr32(device, 0x100cc8, gr->unk4188b4->addr >> 8); - nvkm_wr32(device, 0x100ccc, gr->unk4188b8->addr >> 8); + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8); if (oclass->init_gpc_mmu) oclass->init_gpc_mmu(gr); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index 1e451a9e22903..97b0e1ad040f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -339,8 +339,8 @@ gm107_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0894), 0x00000000); - nvkm_wr32(device, GPC_BCAST(0x08b4), gr->unk4188b4->addr >> 8); - nvkm_wr32(device, GPC_BCAST(0x08b8), gr->unk4188b8->addr >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); gf100_gr_mmio(gr, oclass->mmio); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index c3d2343d41d3b..0a8d850051eee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -269,13 +269,13 @@ gm204_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x418880, 0x00001000 | (tmp & 0x00000fff)); nvkm_wr32(device, 0x418890, 0x00000000); nvkm_wr32(device, 0x418894, 0x00000000); - nvkm_wr32(device, 0x4188b4, gr->unk4188b4->addr >> 8); - nvkm_wr32(device, 0x4188b8, gr->unk4188b8->addr >> 8); + nvkm_wr32(device, 0x4188b4, nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, 0x4188b8, nvkm_memory_addr(gr->unk4188b8) >> 8); nvkm_mask(device, 0x4188b0, 0x00040000, 0x00040000); /*XXX: belongs in fb */ - nvkm_wr32(device, 0x100cc8, gr->unk4188b4->addr >> 8); - nvkm_wr32(device, 0x100ccc, gr->unk4188b8->addr >> 8); + nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(gr->unk4188b4) >> 8); + nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8); nvkm_mask(device, 0x100cc4, 0x00040000, 0x00040000); gf100_gr_mmio(gr, oclass->mmio); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index f4b8eaced1b6e..6e5b321128a6b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -249,6 +249,7 @@ nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv20_gr *gr; int ret; @@ -257,8 +258,8 @@ nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, + &gr->ctxtab); if (ret) return ret; @@ -274,7 +275,7 @@ void nv20_gr_dtor(struct nvkm_object *object) { struct nv20_gr *gr = (void *)object; - nvkm_gpuobj_ref(NULL, &gr->ctxtab); + nvkm_memory_del(&gr->ctxtab); nvkm_gr_destroy(&gr->base); } @@ -292,7 +293,8 @@ nv20_gr_init(struct nvkm_object *object) if (ret) return ret; - nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); + nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, + nvkm_memory_addr(gr->ctxtab) >> 4); if (nv_device(gr)->chipset == 0x20) { nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x003d0000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h index 06dfe4bd50b13..bffbba075b4dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h @@ -4,7 +4,7 @@ struct nv20_gr { struct nvkm_gr base; - struct nvkm_gpuobj *ctxtab; + struct nvkm_memory *ctxtab; }; struct nv20_gr_chan { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index 1a186bd93f64d..f0df11e479750 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -129,6 +129,7 @@ nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv20_gr *gr; int ret; @@ -137,8 +138,8 @@ nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, + &gr->ctxtab); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index dfb62dc6b3b88..3bc6dae76fa5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -96,6 +96,7 @@ nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv20_gr *gr; int ret; @@ -104,8 +105,8 @@ nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, + &gr->ctxtab); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 51573736bb480..3c369f4b09e11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -131,6 +131,7 @@ nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv20_gr *gr; int ret; @@ -139,8 +140,8 @@ nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, + &gr->ctxtab); if (ret) return ret; @@ -165,7 +166,8 @@ nv30_gr_init(struct nvkm_object *object) if (ret) return ret; - nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, gr->ctxtab->addr >> 4); + nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, + nvkm_memory_addr(gr->ctxtab) >> 4); nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index f9d71185ee749..48bd9da606be3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -130,6 +130,7 @@ nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv20_gr *gr; int ret; @@ -138,8 +139,8 @@ nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, + &gr->ctxtab); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index c6357f2fdb363..d25d3303f2fd2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -130,6 +130,7 @@ nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv20_gr *gr; int ret; @@ -138,8 +139,8 @@ nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(gr), NULL, 32 * 4, 16, - NVOBJ_FLAG_ZERO_ALLOC, &gr->ctxtab); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, + &gr->ctxtab); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 6f284e5dc2c87..9c712818528b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -321,12 +321,15 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, void nvkm_vm_put(struct nvkm_vma *vma) { - struct nvkm_vm *vm = vma->vm; - struct nvkm_mmu *mmu = vm->mmu; + struct nvkm_mmu *mmu; + struct nvkm_vm *vm; u32 fpde, lpde; if (unlikely(vma->node == NULL)) return; + vm = vma->vm; + mmu = vm->mmu; + fpde = (vma->node->offset >> mmu->pgt_bits); lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits; -- GitLab From f027f49166171c98d5945af12ac3ee9bc9f9bf4c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5500/7006] drm/nouveau/gpuobj: separate allocation from nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/gpuobj.h | 24 +- .../drm/nouveau/include/nvkm/engine/dmaobj.h | 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 6 +- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 358 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/dmaobj/base.c | 52 ++- .../drm/nouveau/nvkm/engine/dmaobj/gf100.c | 19 +- .../drm/nouveau/nvkm/engine/dmaobj/gf110.c | 26 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c | 23 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c | 31 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 53 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 35 +- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 7 +- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 27 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 6 +- 20 files changed, 373 insertions(+), 379 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index 7613107c05fa6..d171535b8eef1 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -7,30 +7,33 @@ struct nvkm_vma; struct nvkm_vm; #define NVOBJ_FLAG_ZERO_ALLOC 0x00000001 -#define NVOBJ_FLAG_ZERO_FREE 0x00000002 #define NVOBJ_FLAG_HEAP 0x00000004 struct nvkm_gpuobj { struct nvkm_object object; - struct nvkm_memory *memory; + const struct nvkm_gpuobj_func *func; struct nvkm_gpuobj *parent; + struct nvkm_memory *memory; struct nvkm_mm_node *node; - struct nvkm_mm heap; - u32 flags; u64 addr; u32 size; + struct nvkm_mm heap; - const struct nvkm_gpuobj_func *func; + void __iomem *map; }; struct nvkm_gpuobj_func { - void (*acquire)(struct nvkm_gpuobj *); + void *(*acquire)(struct nvkm_gpuobj *); void (*release)(struct nvkm_gpuobj *); u32 (*rd32)(struct nvkm_gpuobj *, u32 offset); void (*wr32)(struct nvkm_gpuobj *, u32 offset, u32 data); }; +int nvkm_gpuobj_new(struct nvkm_device *, u32 size, int align, bool zero, + struct nvkm_gpuobj *parent, struct nvkm_gpuobj **); +void nvkm_gpuobj_del(struct nvkm_gpuobj **); + static inline struct nvkm_gpuobj * nv_gpuobj(void *obj) { @@ -51,12 +54,9 @@ int nvkm_gpuobj_create_(struct nvkm_object *, struct nvkm_object *, u32 flags, int length, void **); void nvkm_gpuobj_destroy(struct nvkm_gpuobj *); -int nvkm_gpuobj_new(struct nvkm_object *, struct nvkm_object *, u32 size, - u32 align, u32 flags, struct nvkm_gpuobj **); -int nvkm_gpuobj_dup(struct nvkm_object *, struct nvkm_memory *, - struct nvkm_gpuobj **); -int nvkm_gpuobj_map_vm(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access, - struct nvkm_vma *); +int nvkm_gpuobj_wrap(struct nvkm_memory *, struct nvkm_gpuobj **); +int nvkm_gpuobj_map(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access, + struct nvkm_vma *); void nvkm_gpuobj_unmap(struct nvkm_vma *); static inline void diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h index 2c3cc61adb74b..343d2d73cd943 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h @@ -15,7 +15,7 @@ struct nvkm_dmaeng { struct nvkm_engine engine; /* creates a "physical" dma object from a struct nvkm_dmaobj */ - int (*bind)(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, + int (*bind)(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **); }; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 650e911dd7042..ebcbe7bbdddf6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -141,7 +141,7 @@ nouveau_accel_fini(struct nouveau_drm *drm) { nouveau_channel_del(&drm->channel); nvif_object_fini(&drm->ntfy); - nvkm_gpuobj_ref(NULL, &drm->notify); + nvkm_gpuobj_del(&drm->notify); nvif_object_fini(&drm->nvsw); nouveau_channel_del(&drm->cechan); nvif_object_fini(&drm->ttm.copy); @@ -264,8 +264,8 @@ nouveau_accel_init(struct nouveau_drm *drm) } if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { - ret = nvkm_gpuobj_new(nvxx_object(&drm->device.object), NULL, 32, - 0, 0, &drm->notify); + ret = nvkm_gpuobj_new(nvxx_device(&drm->device), 32, 0, false, + NULL, &drm->notify); if (ret) { NV_ERROR(drm, "failed to allocate notifier, %d\n", ret); nouveau_accel_fini(drm); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index c14469c3a861e..54b46037f4ba3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -28,74 +28,209 @@ #include #include -static void -nvkm_gpuobj_release(struct nvkm_gpuobj *gpuobj) +/* fast-path, where backend is able to provide direct pointer to memory */ +static u32 +nvkm_gpuobj_rd32_fast(struct nvkm_gpuobj *gpuobj, u32 offset) { - if (gpuobj->node) { - nvkm_done(gpuobj->parent); - return; - } - nvkm_done(gpuobj->memory); + return ioread32_native(gpuobj->map + offset); } static void -nvkm_gpuobj_acquire(struct nvkm_gpuobj *gpuobj) +nvkm_gpuobj_wr32_fast(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data) { - if (gpuobj->node) { - nvkm_kmap(gpuobj->parent); - return; - } - nvkm_kmap(gpuobj->memory); + iowrite32_native(data, gpuobj->map + offset); } +/* accessor functions for gpuobjs allocated directly from instmem */ static u32 -nvkm_gpuobj_rd32(struct nvkm_gpuobj *gpuobj, u32 offset) +nvkm_gpuobj_heap_rd32(struct nvkm_gpuobj *gpuobj, u32 offset) { - if (gpuobj->node) - return nvkm_ro32(gpuobj->parent, gpuobj->node->offset + offset); return nvkm_ro32(gpuobj->memory, offset); } static void -nvkm_gpuobj_wr32(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data) +nvkm_gpuobj_heap_wr32(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data) { - if (gpuobj->node) { - nvkm_wo32(gpuobj->parent, gpuobj->node->offset + offset, data); - return; - } nvkm_wo32(gpuobj->memory, offset, data); } -void -nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) +static const struct nvkm_gpuobj_func nvkm_gpuobj_heap; +static void +nvkm_gpuobj_heap_release(struct nvkm_gpuobj *gpuobj) { - int i; + gpuobj->func = &nvkm_gpuobj_heap; + nvkm_done(gpuobj->memory); +} - if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) { - nvkm_kmap(gpuobj); - for (i = 0; i < gpuobj->size; i += 4) - nvkm_wo32(gpuobj, i, 0x00000000); - nvkm_done(gpuobj); - } +static const struct nvkm_gpuobj_func +nvkm_gpuobj_heap_fast = { + .release = nvkm_gpuobj_heap_release, + .rd32 = nvkm_gpuobj_rd32_fast, + .wr32 = nvkm_gpuobj_wr32_fast, +}; - if (gpuobj->node) - nvkm_mm_free(&nv_gpuobj(gpuobj->parent)->heap, &gpuobj->node); +static const struct nvkm_gpuobj_func +nvkm_gpuobj_heap_slow = { + .release = nvkm_gpuobj_heap_release, + .rd32 = nvkm_gpuobj_heap_rd32, + .wr32 = nvkm_gpuobj_heap_wr32, +}; - if (gpuobj->heap.block_size) - nvkm_mm_fini(&gpuobj->heap); +static void * +nvkm_gpuobj_heap_acquire(struct nvkm_gpuobj *gpuobj) +{ + gpuobj->map = nvkm_kmap(gpuobj->memory); + if (likely(gpuobj->map)) + gpuobj->func = &nvkm_gpuobj_heap_fast; + else + gpuobj->func = &nvkm_gpuobj_heap_slow; + return gpuobj->map; +} - nvkm_memory_del(&gpuobj->memory); - nvkm_object_destroy(&gpuobj->object); +static const struct nvkm_gpuobj_func +nvkm_gpuobj_heap = { + .acquire = nvkm_gpuobj_heap_acquire, +}; + +/* accessor functions for gpuobjs sub-allocated from a parent gpuobj */ +static u32 +nvkm_gpuobj_rd32(struct nvkm_gpuobj *gpuobj, u32 offset) +{ + return nvkm_ro32(gpuobj->parent, gpuobj->node->offset + offset); +} + +static void +nvkm_gpuobj_wr32(struct nvkm_gpuobj *gpuobj, u32 offset, u32 data) +{ + nvkm_wo32(gpuobj->parent, gpuobj->node->offset + offset, data); +} + +static const struct nvkm_gpuobj_func nvkm_gpuobj_func; +static void +nvkm_gpuobj_release(struct nvkm_gpuobj *gpuobj) +{ + gpuobj->func = &nvkm_gpuobj_func; + nvkm_done(gpuobj->parent); } static const struct nvkm_gpuobj_func -nvkm_gpuobj_func = { - .acquire = nvkm_gpuobj_acquire, +nvkm_gpuobj_fast = { + .release = nvkm_gpuobj_release, + .rd32 = nvkm_gpuobj_rd32_fast, + .wr32 = nvkm_gpuobj_wr32_fast, +}; + +static const struct nvkm_gpuobj_func +nvkm_gpuobj_slow = { .release = nvkm_gpuobj_release, .rd32 = nvkm_gpuobj_rd32, .wr32 = nvkm_gpuobj_wr32, }; +static void * +nvkm_gpuobj_acquire(struct nvkm_gpuobj *gpuobj) +{ + gpuobj->map = nvkm_kmap(gpuobj->parent); + if (likely(gpuobj->map)) { + gpuobj->map = (u8 *)gpuobj->map + gpuobj->node->offset; + gpuobj->func = &nvkm_gpuobj_fast; + } else { + gpuobj->func = &nvkm_gpuobj_slow; + } + return gpuobj->map; +} + +static const struct nvkm_gpuobj_func +nvkm_gpuobj_func = { + .acquire = nvkm_gpuobj_acquire, +}; + +static int +nvkm_gpuobj_ctor(struct nvkm_device *device, u32 size, int align, bool zero, + struct nvkm_gpuobj *parent, struct nvkm_gpuobj *gpuobj) +{ + u32 offset; + int ret; + + if (parent) { + if (align >= 0) { + ret = nvkm_mm_head(&parent->heap, 0, 1, size, size, + max(align, 1), &gpuobj->node); + } else { + ret = nvkm_mm_tail(&parent->heap, 0, 1, size, size, + -align, &gpuobj->node); + } + if (ret) + return ret; + + gpuobj->parent = parent; + gpuobj->func = &nvkm_gpuobj_func; + gpuobj->addr = parent->addr + gpuobj->node->offset; + gpuobj->size = gpuobj->node->length; + + if (zero) { + nvkm_kmap(gpuobj); + for (offset = 0; offset < gpuobj->size; offset += 4) + nvkm_wo32(gpuobj, offset, 0x00000000); + nvkm_done(gpuobj); + } + } else { + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, size, + abs(align), zero, &gpuobj->memory); + if (ret) + return ret; + + gpuobj->func = &nvkm_gpuobj_heap; + gpuobj->addr = nvkm_memory_addr(gpuobj->memory); + gpuobj->size = nvkm_memory_size(gpuobj->memory); + } + + return nvkm_mm_init(&gpuobj->heap, 0, gpuobj->size, 1); +} + +void +nvkm_gpuobj_del(struct nvkm_gpuobj **pgpuobj) +{ + struct nvkm_gpuobj *gpuobj = *pgpuobj; + if (gpuobj) { + if (gpuobj->parent) + nvkm_mm_free(&gpuobj->parent->heap, &gpuobj->node); + nvkm_mm_fini(&gpuobj->heap); + nvkm_memory_del(&gpuobj->memory); + kfree(*pgpuobj); + *pgpuobj = NULL; + } +} + +int +nvkm_gpuobj_new(struct nvkm_device *device, u32 size, int align, bool zero, + struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) +{ + struct nvkm_gpuobj *gpuobj; + int ret; + + if (!(gpuobj = *pgpuobj = kzalloc(sizeof(*gpuobj), GFP_KERNEL))) + return -ENOMEM; + + ret = nvkm_gpuobj_ctor(device, size, align, zero, parent, gpuobj); + if (ret) + nvkm_gpuobj_del(pgpuobj); + return ret; +} + +void +nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) +{ + if (gpuobj->node) + nvkm_mm_free(&gpuobj->parent->heap, &gpuobj->node); + + gpuobj->heap.block_size = 1; + nvkm_mm_fini(&gpuobj->heap); + + nvkm_memory_del(&gpuobj->memory); + nvkm_object_destroy(&gpuobj->object); +} + int nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 pclass, @@ -103,12 +238,10 @@ nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, int length, void **pobject) { struct nvkm_device *device = nv_device(parent); - struct nvkm_memory *memory = NULL; struct nvkm_gpuobj *pargpu = NULL; struct nvkm_gpuobj *gpuobj; - struct nvkm_mm *heap = NULL; - int ret, i; - u64 addr; + const bool zero = (flags & NVOBJ_FLAG_ZERO_ALLOC); + int ret; *pobject = NULL; @@ -122,83 +255,18 @@ nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (WARN_ON(objgpu == NULL)) return -EINVAL; pargpu = nv_gpuobj(objgpu); - - addr = pargpu->addr; - heap = &pargpu->heap; - } else { - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - size, align, false, &memory); - if (ret) - return ret; - - addr = nvkm_memory_addr(memory); - size = nvkm_memory_size(memory); } ret = nvkm_object_create_(parent, engine, oclass, pclass | NV_GPUOBJ_CLASS, length, pobject); gpuobj = *pobject; - if (ret) { - nvkm_memory_del(&memory); - return ret; - } - - gpuobj->func = &nvkm_gpuobj_func; - gpuobj->memory = memory; - gpuobj->parent = pargpu; - gpuobj->flags = flags; - gpuobj->addr = addr; - gpuobj->size = size; - - if (heap) { - ret = nvkm_mm_head(heap, 0, 1, size, size, max(align, (u32)1), - &gpuobj->node); - if (ret) - return ret; - - gpuobj->addr += gpuobj->node->offset; - } - - if (gpuobj->flags & NVOBJ_FLAG_HEAP) { - ret = nvkm_mm_init(&gpuobj->heap, 0, gpuobj->size, 1); - if (ret) - return ret; - } - - if (flags & NVOBJ_FLAG_ZERO_ALLOC) { - nvkm_kmap(gpuobj); - for (i = 0; i < gpuobj->size; i += 4) - nvkm_wo32(gpuobj, i, 0x00000000); - nvkm_done(gpuobj); - } - - return ret; -} - -struct nvkm_gpuobj_class { - struct nvkm_object *pargpu; - u64 size; - u32 align; - u32 flags; -}; - -static int -_nvkm_gpuobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_gpuobj_class *args = data; - struct nvkm_gpuobj *object; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, args->pargpu, - args->size, args->align, args->flags, - &object); - *pobject = nv_object(object); if (ret) return ret; - return 0; + ret = nvkm_gpuobj_ctor(device, size, align, zero, pargpu, gpuobj); + if (!(flags & NVOBJ_FLAG_HEAP)) + gpuobj->heap.block_size = 0; + return ret; } void @@ -233,39 +301,9 @@ _nvkm_gpuobj_wr32(struct nvkm_object *object, u64 addr, u32 data) nvkm_wo32(gpuobj, addr, data); } -static struct nvkm_oclass -_nvkm_gpuobj_oclass = { - .handle = 0x00000000, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpuobj_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, - }, -}; - -int -nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu, - u32 size, u32 align, u32 flags, - struct nvkm_gpuobj **pgpuobj) -{ - struct nvkm_gpuobj_class args = { - .pargpu = pargpu, - .size = size, - .align = align, - .flags = flags, - }; - - return nvkm_object_old(parent, &parent->engine->subdev.object, - &_nvkm_gpuobj_oclass, &args, sizeof(args), - (struct nvkm_object **)pgpuobj); -} - int -nvkm_gpuobj_map_vm(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm, - u32 access, struct nvkm_vma *vma) +nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm, + u32 access, struct nvkm_vma *vma) { struct nvkm_memory *memory = gpuobj->memory; int ret = nvkm_vm_get(vm, gpuobj->size, 12, access, vma); @@ -288,37 +326,13 @@ nvkm_gpuobj_unmap(struct nvkm_vma *vma) * anywhere else. */ -static void -nvkm_gpudup_dtor(struct nvkm_object *object) -{ - struct nvkm_gpuobj *gpuobj = (void *)object; - nvkm_object_destroy(&gpuobj->object); -} - -static struct nvkm_oclass -nvkm_gpudup_oclass = { - .handle = NV_GPUOBJ_CLASS, - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_gpudup_dtor, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - }, -}; - int -nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_memory *base, - struct nvkm_gpuobj **pgpuobj) +nvkm_gpuobj_wrap(struct nvkm_memory *memory, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *gpuobj; - int ret; - - ret = nvkm_object_create(parent, &parent->engine->subdev.object, - &nvkm_gpudup_oclass, 0, &gpuobj); - *pgpuobj = gpuobj; - if (ret) - return ret; + if (!(*pgpuobj = kzalloc(sizeof(**pgpuobj), GFP_KERNEL))) + return -ENOMEM; - gpuobj->addr = nvkm_memory_addr(base); - gpuobj->size = nvkm_memory_size(base); + (*pgpuobj)->addr = nvkm_memory_addr(memory); + (*pgpuobj)->size = nvkm_memory_size(memory); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c index f9f38ee49058d..7f9870789a0f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c @@ -24,32 +24,74 @@ #include "priv.h" #include +#include #include #include #include #include +struct hack { + struct nvkm_gpuobj object; + struct nvkm_gpuobj *parent; +}; + +static void +dtor(struct nvkm_object *object) +{ + struct hack *hack = (void *)object; + nvkm_gpuobj_del(&hack->parent); + nvkm_object_destroy(&hack->object.object); +} + +static struct nvkm_oclass +hack = { + .handle = NV_GPUOBJ_CLASS, + .ofuncs = &(struct nvkm_ofuncs) { + .dtor = dtor, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, + }, +}; + static int -nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent, +nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *pargpu, struct nvkm_gpuobj **pgpuobj) { const struct nvkm_dmaeng_impl *impl = (void *) nv_oclass(nv_object(dmaobj)->engine); int ret = 0; - if (nv_object(dmaobj) == parent) { /* ctor bind */ + if (&dmaobj->base == &pargpu->object) { /* ctor bind */ + struct nvkm_object *parent = (void *)pargpu; + struct hack *object; + if (nv_mclass(parent->parent) == NV_DEVICE) { /* delayed, or no, binding */ return 0; } - ret = impl->bind(dmaobj, parent, pgpuobj); - if (ret == 0) + + pargpu = (void *)nv_pclass((void *)pargpu, NV_GPUOBJ_CLASS); + + ret = nvkm_object_create(parent, NULL, &hack, NV_GPUOBJ_CLASS, &object); + if (ret == 0) { nvkm_object_ref(NULL, &parent); + *pgpuobj = &object->object; + + ret = impl->bind(dmaobj, pargpu, &object->parent); + if (ret) + return ret; + + object->object.node = object->parent->node; + object->object.addr = object->parent->addr; + object->object.size = object->parent->size; + return 0; + } + return ret; } - return impl->bind(dmaobj, parent, pgpuobj); + return impl->bind(dmaobj, pargpu, pgpuobj); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c index 499a7c7e024a5..96a604de4b632 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c @@ -37,25 +37,14 @@ struct gf100_dmaobj { }; static int -gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, +gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { struct gf100_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); + struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; int ret; - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case GT214_DISP_CORE_CHANNEL_DMA: - case GT214_DISP_BASE_CHANNEL_DMA: - case GT214_DISP_OVERLAY_CHANNEL_DMA: - break; - default: - return -EINVAL; - } - } else - return 0; - - ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); + ret = nvkm_gpuobj_new(device, 24, 32, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); @@ -146,7 +135,7 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, break; } - return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); + return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c index a28cf56454e46..017c7a2affe51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c @@ -36,32 +36,14 @@ struct gf110_dmaobj { }; static int -gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, +gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { struct gf110_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); + struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; int ret; - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case GF110_DISP_CORE_CHANNEL_DMA: - case GK104_DISP_CORE_CHANNEL_DMA: - case GK110_DISP_CORE_CHANNEL_DMA: - case GM107_DISP_CORE_CHANNEL_DMA: - case GM204_DISP_CORE_CHANNEL_DMA: - case GF110_DISP_BASE_CHANNEL_DMA: - case GK104_DISP_BASE_CHANNEL_DMA: - case GK110_DISP_BASE_CHANNEL_DMA: - case GF110_DISP_OVERLAY_CONTROL_DMA: - case GK104_DISP_OVERLAY_CONTROL_DMA: - break; - default: - return -EINVAL; - } - } else - return 0; - - ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); + ret = nvkm_gpuobj_new(device, 24, 32, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); @@ -135,7 +117,7 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); + return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c index 9c68eb0e4a70f..6be2dfc70cb71 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c @@ -37,41 +37,28 @@ struct nv04_dmaobj { }; static int -nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, +nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { struct nv04_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); - struct nvkm_gpuobj *gpuobj; + struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; u64 offset = dmaobj->base.start & 0xfffff000; u64 adjust = dmaobj->base.start & 0x00000fff; u32 length = dmaobj->base.limit - dmaobj->base.start; int ret; - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case NV03_CHANNEL_DMA: - case NV10_CHANNEL_DMA: - case NV17_CHANNEL_DMA: - case NV40_CHANNEL_DMA: - break; - default: - return -EINVAL; - } - } - if (dmaobj->clone) { struct nv04_mmu *mmu = nv04_mmu(dmaobj); struct nvkm_memory *pgt = mmu->vm->pgt[0].mem[0]; if (!dmaobj->base.start) - return nvkm_gpuobj_dup(parent, pgt, pgpuobj); + return nvkm_gpuobj_wrap(pgt, pgpuobj); nvkm_kmap(pgt); offset = nvkm_ro32(pgt, 8 + (offset >> 10)); offset &= 0xfffff000; nvkm_done(pgt); } - ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj); - *pgpuobj = gpuobj; + ret = nvkm_gpuobj_new(device, 16, 16, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | (adjust << 20)); @@ -134,7 +121,7 @@ nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); + return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c index 3566fa9b3ba97..f87134ec5b341 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c @@ -37,37 +37,14 @@ struct nv50_dmaobj { }; static int -nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_object *parent, +nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { struct nv50_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); + struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; int ret; - if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { - switch (nv_mclass(parent->parent)) { - case NV40_CHANNEL_DMA: - case NV50_CHANNEL_GPFIFO: - case G82_CHANNEL_GPFIFO: - case NV50_DISP_CORE_CHANNEL_DMA: - case G82_DISP_CORE_CHANNEL_DMA: - case GT206_DISP_CORE_CHANNEL_DMA: - case GT200_DISP_CORE_CHANNEL_DMA: - case GT214_DISP_CORE_CHANNEL_DMA: - case NV50_DISP_BASE_CHANNEL_DMA: - case G82_DISP_BASE_CHANNEL_DMA: - case GT200_DISP_BASE_CHANNEL_DMA: - case GT214_DISP_BASE_CHANNEL_DMA: - case NV50_DISP_OVERLAY_CHANNEL_DMA: - case G82_DISP_OVERLAY_CHANNEL_DMA: - case GT200_DISP_OVERLAY_CHANNEL_DMA: - case GT214_DISP_OVERLAY_CHANNEL_DMA: - break; - default: - return -EINVAL; - } - } - - ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj); + ret = nvkm_gpuobj_new(device, 24, 32, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); @@ -164,7 +141,7 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&dmaobj->base, nv_object(dmaobj), (void *)pobject); + return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); } static struct nvkm_ofuncs diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h index c4c210bdbf7e9..614d9e697bd42 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h @@ -22,7 +22,7 @@ int _nvkm_dmaeng_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_dmaeng_impl { struct nvkm_oclass base; struct nvkm_oclass *sclass; - int (*bind)(struct nvkm_dmaobj *, struct nvkm_object *, + int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, struct nvkm_gpuobj **); }; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index f937d705d6687..1934dfb5a434a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -61,6 +61,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, struct nvkm_handle *handle; struct nvkm_dmaobj *dmaobj; struct nvkm_fifo *fifo = (void *)engine; + struct nvkm_fifo_base *base = (void *)parent; struct nvkm_fifo_chan *chan; struct nvkm_dmaeng *dmaeng; struct nvkm_subdev *subdev = &fifo->engine.subdev; @@ -91,7 +92,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return -EINVAL; } - ret = dmaeng->bind(dmaobj, parent, &chan->pushgpu); + ret = dmaeng->bind(dmaobj, &base->gpuobj, &chan->pushgpu); if (ret) return ret; } @@ -131,7 +132,7 @@ nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) fifo->channel[chan->chid] = NULL; spin_unlock_irqrestore(&fifo->lock, flags); - nvkm_gpuobj_ref(NULL, &chan->pushgpu); + nvkm_gpuobj_del(&chan->pushgpu); nvkm_namedb_destroy(&chan->namedb); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 96c6835e9f149..058296b2f2852 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -140,23 +140,25 @@ g84_fifo_object_attach(struct nvkm_object *parent, else context = 0x00000004; /* just non-zero */ - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break; - case NVDEV_ENGINE_ME : - case NVDEV_ENGINE_CE0 : context |= 0x00300000; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : - case NVDEV_ENGINE_VIC : context |= 0x00500000; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break; - default: - return -EINVAL; + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : + case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break; + case NVDEV_ENGINE_ME : + case NVDEV_ENGINE_CE0 : context |= 0x00300000; break; + case NVDEV_ENGINE_VP : + case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break; + case NVDEV_ENGINE_CIPHER: + case NVDEV_ENGINE_SEC : + case NVDEV_ENGINE_VIC : context |= 0x00500000; break; + case NVDEV_ENGINE_BSP : + case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break; + default: + return -EINVAL; + } } return nvkm_ramht_insert(chan->ramht, 0, handle, context); @@ -374,6 +376,7 @@ g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = nv_engine(engine)->subdev.device; struct nv50_fifo_base *base; int ret; @@ -383,13 +386,13 @@ g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0, - NVOBJ_FLAG_ZERO_ALLOC, &base->eng); + ret = nvkm_gpuobj_new(device, 0x0200, 0, true, &base->base.gpuobj, + &base->eng); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, - 0, &base->pgd); + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, + &base->pgd); if (ret) return ret; @@ -397,13 +400,13 @@ g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1000, - 0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache); + ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, &base->base.gpuobj, + &base->cache); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0100, - 0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); + ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, &base->base.gpuobj, + &base->ramfc); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index cbb8d249e7fbd..77b8df1f57fba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -130,8 +130,8 @@ gf100_fifo_context_attach(struct nvkm_object *parent, } if (!ectx->vma.node) { - ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); + ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, + NV_MEM_ACCESS_RW, &ectx->vma); if (ret) return ret; @@ -334,6 +334,7 @@ gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = nv_engine(engine)->subdev.device; struct gf100_fifo_base *base; int ret; @@ -344,8 +345,7 @@ gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0, - &base->pgd); + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); if (ret) return ret; @@ -368,7 +368,7 @@ gf100_fifo_context_dtor(struct nvkm_object *object) { struct gf100_fifo_base *base = (void *)object; nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_ref(NULL, &base->pgd); + nvkm_gpuobj_del(&base->pgd); nvkm_fifo_context_destroy(&base->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 0e8356d5fa02e..39dae1a28dd1e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -154,8 +154,8 @@ gk104_fifo_context_attach(struct nvkm_object *parent, } if (!ectx->vma.node) { - ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); + ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, + NV_MEM_ACCESS_RW, &ectx->vma); if (ret) return ret; @@ -388,6 +388,7 @@ gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = nv_engine(engine)->subdev.device; struct gk104_fifo_base *base; int ret; @@ -397,8 +398,7 @@ gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0, - &base->pgd); + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); if (ret) return ret; @@ -421,7 +421,7 @@ gk104_fifo_context_dtor(struct nvkm_object *object) { struct gk104_fifo_base *base = (void *)object; nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_ref(NULL, &base->pgd); + nvkm_gpuobj_del(&base->pgd); nvkm_fifo_context_destroy(&base->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index f0fd1ce8f671b..4bec707305586 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -65,19 +65,21 @@ nv04_fifo_object_attach(struct nvkm_object *parent, else context = 0x00000004; /* just non-zero */ - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00010000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00020000; - break; - default: - return -EINVAL; + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + context |= 0x00000000; + break; + case NVDEV_ENGINE_GR: + context |= 0x00010000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00020000; + break; + default: + return -EINVAL; + } } context |= 0x80000000; /* valid */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index eb6588ec0b6d4..a2d8da8a9341e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -78,19 +78,21 @@ nv40_fifo_object_attach(struct nvkm_object *parent, else context = 0x00000004; /* just non-zero */ - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00100000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00200000; - break; - default: - return -EINVAL; + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + context |= 0x00000000; + break; + case NVDEV_ENGINE_GR: + context |= 0x00100000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00200000; + break; + default: + return -EINVAL; + } } context |= chid << 23; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 96e5b61daf10c..620c0cfb2453b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -171,13 +171,15 @@ nv50_fifo_object_attach(struct nvkm_object *parent, else context = 0x00000004; /* just non-zero */ - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; - default: - return -EINVAL; + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; + default: + return -EINVAL; + } } return nvkm_ramht_insert(chan->ramht, 0, handle, context); @@ -402,6 +404,7 @@ nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = nv_engine(engine)->subdev.device; struct nv50_fifo_base *base; int ret; @@ -411,17 +414,17 @@ nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc); + ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, &base->base.gpuobj, + &base->ramfc); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0, - NVOBJ_FLAG_ZERO_ALLOC, &base->eng); + ret = nvkm_gpuobj_new(device, 0x1200, 0, true, &base->base.gpuobj, + &base->eng); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0, + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, &base->pgd); if (ret) return ret; @@ -438,10 +441,10 @@ nv50_fifo_context_dtor(struct nvkm_object *object) { struct nv50_fifo_base *base = (void *)object; nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_ref(NULL, &base->pgd); - nvkm_gpuobj_ref(NULL, &base->eng); - nvkm_gpuobj_ref(NULL, &base->ramfc); - nvkm_gpuobj_ref(NULL, &base->cache); + nvkm_gpuobj_del(&base->pgd); + nvkm_gpuobj_del(&base->eng); + nvkm_gpuobj_del(&base->ramfc); + nvkm_gpuobj_del(&base->cache); nvkm_fifo_context_destroy(&base->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 8e3574631068f..7d304ccc6a64a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -75,8 +75,7 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(bar), NULL, 0x8000, 0, 0, - &bar_vm->pgd); + ret = nvkm_gpuobj_new(device, 0x8000, 0, false, NULL, &bar_vm->pgd); if (ret) return ret; @@ -157,14 +156,14 @@ gf100_bar_dtor(struct nvkm_object *object) struct gf100_bar *bar = (void *)object; nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); - nvkm_gpuobj_ref(NULL, &bar->bar[1].pgd); + nvkm_gpuobj_del(&bar->bar[1].pgd); nvkm_memory_del(&bar->bar[1].mem); if (bar->bar[0].vm) { nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); } - nvkm_gpuobj_ref(NULL, &bar->bar[0].pgd); + nvkm_gpuobj_del(&bar->bar[0].pgd); nvkm_memory_del(&bar->bar[0].mem); nvkm_bar_destroy(&bar->base); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 8e17b62fa1dae..add132b2ed7aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -99,7 +99,6 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, static struct lock_class_key bar1_lock; static struct lock_class_key bar3_lock; struct nvkm_device *device = nv_device(parent); - struct nvkm_object *heap; struct nvkm_vm *vm; struct nv50_bar *bar; u64 start, limit; @@ -110,19 +109,17 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(bar), NULL, 0x20000, 0, - NVOBJ_FLAG_HEAP, &bar->mem); - heap = nv_object(bar->mem); + ret = nvkm_gpuobj_new(device, 0x20000, 0, false, NULL, &bar->mem); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(bar), heap, - (device->chipset == 0x50) ? 0x1400 : 0x0200, - 0, 0, &bar->pad); + ret = nvkm_gpuobj_new(device, (device->chipset == 0x50) ? + 0x1400 : 0x200, 0, false, bar->mem, + &bar->pad); if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(bar), heap, 0x4000, 0, 0, &bar->pgd); + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, bar->mem, &bar->pgd); if (ret) return ret; @@ -145,7 +142,7 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(bar), heap, 24, 16, 0, &bar->bar3); + ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar3); if (ret) return ret; @@ -174,7 +171,7 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_gpuobj_new(nv_object(bar), heap, 24, 16, 0, &bar->bar1); + ret = nvkm_gpuobj_new(device, 24, 16, false, bar->mem, &bar->bar1); if (ret) return ret; @@ -203,16 +200,16 @@ static void nv50_bar_dtor(struct nvkm_object *object) { struct nv50_bar *bar = (void *)object; - nvkm_gpuobj_ref(NULL, &bar->bar1); + nvkm_gpuobj_del(&bar->bar1); nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd); - nvkm_gpuobj_ref(NULL, &bar->bar3); + nvkm_gpuobj_del(&bar->bar3); if (bar->bar3_vm) { nvkm_memory_del(&bar->bar3_vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &bar->bar3_vm, bar->pgd); } - nvkm_gpuobj_ref(NULL, &bar->pgd); - nvkm_gpuobj_ref(NULL, &bar->pad); - nvkm_gpuobj_ref(NULL, &bar->mem); + nvkm_gpuobj_del(&bar->pgd); + nvkm_gpuobj_del(&bar->pad); + nvkm_gpuobj_del(&bar->mem); nvkm_bar_destroy(&bar->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 9c712818528b9..6fa1bdb02dfdb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -420,7 +420,7 @@ nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd) if (!vpgd) return -ENOMEM; - nvkm_gpuobj_ref(pgd, &vpgd->obj); + vpgd->obj = pgd; mutex_lock(&vm->mutex); for (i = vm->fpde; i <= vm->lpde; i++) @@ -434,7 +434,6 @@ static void nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd) { struct nvkm_vm_pgd *vpgd, *tmp; - struct nvkm_gpuobj *pgd = NULL; if (!mpgd) return; @@ -442,15 +441,12 @@ nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd) mutex_lock(&vm->mutex); list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) { if (vpgd->obj == mpgd) { - pgd = vpgd->obj; list_del(&vpgd->head); kfree(vpgd); break; } } mutex_unlock(&vm->mutex); - - nvkm_gpuobj_ref(NULL, &pgd); } static void -- GitLab From 1d2a1e53865266a67fb569705eba3ec992682721 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:17 +1000 Subject: [PATCH 5501/7006] drm/nouveau/ramht: remove dependence on namedb Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/core/ramht.h | 28 ++-- drivers/gpu/drm/nouveau/nvkm/core/ramht.c | 157 +++++++++++++----- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 11 +- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 12 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 14 +- .../drm/nouveau/nvkm/subdev/instmem/nv04.c | 5 +- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 5 +- 11 files changed, 162 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h b/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h index cc132eaa10cca..5ee6298991e21 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h @@ -2,19 +2,27 @@ #define __NVKM_RAMHT_H__ #include +struct nvkm_ramht_data { + struct nvkm_gpuobj *inst; + int chid; + u32 handle; +}; + struct nvkm_ramht { - struct nvkm_gpuobj gpuobj; + struct nvkm_device *device; + struct nvkm_gpuobj *parent; + struct nvkm_gpuobj *gpuobj; + int size; int bits; + struct nvkm_ramht_data data[]; }; -int nvkm_ramht_insert(struct nvkm_ramht *, int chid, u32 handle, u32 context); +int nvkm_ramht_new(struct nvkm_device *, u32 size, u32 align, + struct nvkm_gpuobj *, struct nvkm_ramht **); +void nvkm_ramht_del(struct nvkm_ramht **); +int nvkm_ramht_insert(struct nvkm_ramht *, struct nvkm_object *, + int chid, int addr, u32 handle, u32 context); void nvkm_ramht_remove(struct nvkm_ramht *, int cookie); -int nvkm_ramht_new(struct nvkm_object *, struct nvkm_object *, u32 size, - u32 align, struct nvkm_ramht **); - -static inline void -nvkm_ramht_ref(struct nvkm_ramht *obj, struct nvkm_ramht **ref) -{ - nvkm_gpuobj_ref(&obj->gpuobj, (struct nvkm_gpuobj **)ref); -} +struct nvkm_gpuobj * +nvkm_ramht_search(struct nvkm_ramht *, int chid, u32 handle); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index 061adedc6e2cf..307d532696250 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -33,74 +33,143 @@ nvkm_ramht_hash(struct nvkm_ramht *ramht, int chid, u32 handle) } hash ^= chid << (ramht->bits - 4); - hash = hash << 3; return hash; } -int -nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context) +struct nvkm_gpuobj * +nvkm_ramht_search(struct nvkm_ramht *ramht, int chid, u32 handle) { - struct nvkm_gpuobj *gpuobj = &ramht->gpuobj; - int ret = -ENOSPC; u32 co, ho; co = ho = nvkm_ramht_hash(ramht, chid, handle); - nvkm_kmap(gpuobj); do { - if (!nvkm_ro32(gpuobj, co + 4)) { - nvkm_wo32(gpuobj, co + 0, handle); - nvkm_wo32(gpuobj, co + 4, context); - ret = co; - break; + if (ramht->data[co].chid == chid) { + if (ramht->data[co].handle == handle) + return ramht->data[co].inst; } - co += 8; - if (co >= nv_gpuobj(ramht)->size) + if (++co >= ramht->size) co = 0; } while (co != ho); - nvkm_done(gpuobj); - return ret; + return NULL; +} + +static int +nvkm_ramht_update(struct nvkm_ramht *ramht, int co, struct nvkm_object *object, + int chid, int addr, u32 handle, u32 context) +{ + struct nvkm_ramht_data *data = &ramht->data[co]; + u64 inst = 0x00000040; /* just non-zero for <=g8x fifo ramht */ + int ret; + + nvkm_gpuobj_del(&data->inst); + data->chid = chid; + data->handle = handle; + + if (!object) { + inst = 0; + goto done; + } + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) { + struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); + if (ramht->device->card_type >= NV_50) + inst = gpuobj->node->offset; + else + inst = gpuobj->addr; + goto done; + } + + ret = nvkm_object_bind(object, ramht->parent, 16, &data->inst); + if (ret) { + if (ret != -ENODEV) { + data->chid = -1; + return ret; + } + data->inst = NULL; + } + + if (data->inst) { + if (ramht->device->card_type >= NV_50) + inst = data->inst->node->offset; + else + inst = data->inst->addr; + } + +done: + if (addr < 0) context |= inst << -addr; + else context |= inst >> addr; + + nvkm_kmap(ramht->gpuobj); + nvkm_wo32(ramht->gpuobj, (co << 3) + 0, handle); + nvkm_wo32(ramht->gpuobj, (co << 3) + 4, context); + nvkm_done(ramht->gpuobj); + return co + 1; } void nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie) { - struct nvkm_gpuobj *gpuobj = &ramht->gpuobj; - nvkm_kmap(gpuobj); - nvkm_wo32(gpuobj, cookie + 0, 0x00000000); - nvkm_wo32(gpuobj, cookie + 4, 0x00000000); - nvkm_done(gpuobj); + if (--cookie >= 0) + nvkm_ramht_update(ramht, cookie, NULL, -1, 0, 0, 0); } -static struct nvkm_oclass -nvkm_ramht_oclass = { - .handle = 0x0000abcd, - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = NULL, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, - }, -}; +int +nvkm_ramht_insert(struct nvkm_ramht *ramht, struct nvkm_object *object, + int chid, int addr, u32 handle, u32 context) +{ + u32 co, ho; + + if (nvkm_ramht_search(ramht, chid, handle)) + return -EEXIST; + + co = ho = nvkm_ramht_hash(ramht, chid, handle); + do { + if (ramht->data[co].chid < 0) { + return nvkm_ramht_update(ramht, co, object, chid, + addr, handle, context); + } + + if (++co >= ramht->size) + co = 0; + } while (co != ho); + + return -ENOSPC; +} + +void +nvkm_ramht_del(struct nvkm_ramht **pramht) +{ + struct nvkm_ramht *ramht = *pramht; + if (ramht) { + nvkm_gpuobj_del(&ramht->gpuobj); + kfree(*pramht); + *pramht = NULL; + } +} int -nvkm_ramht_new(struct nvkm_object *parent, struct nvkm_object *pargpu, - u32 size, u32 align, struct nvkm_ramht **pramht) +nvkm_ramht_new(struct nvkm_device *device, u32 size, u32 align, + struct nvkm_gpuobj *parent, struct nvkm_ramht **pramht) { struct nvkm_ramht *ramht; - int ret; + int ret, i; - ret = nvkm_gpuobj_create(parent, parent->engine ? - &parent->engine->subdev.object : NULL, /* > 3) * + sizeof(*ramht->data), GFP_KERNEL))) + return -ENOMEM; + + ramht->device = device; + ramht->parent = parent; + ramht->size = size >> 3; + ramht->bits = order_base_2(ramht->size); + for (i = 0; i < ramht->size; i++) + ramht->data[i].chid = -1; - ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3); - return 0; + ret = nvkm_gpuobj_new(ramht->device, size, align, true, + ramht->parent, &ramht->gpuobj); + if (ret) + nvkm_ramht_del(pramht); + return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c index 4161326b4f5b9..7a8ea497eb26b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c @@ -80,7 +80,7 @@ gf110_disp_dmac_object_attach(struct nvkm_object *parent, struct nv50_disp_chan *chan = (void *)parent; u32 addr = nv_gpuobj(object)->node->offset; u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001; - return nvkm_ramht_insert(base->ramht, chan->chid, name, data); + return nvkm_ramht_insert(base->ramht, NULL, chan->chid, 0, name, data); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 2568e5d5790e8..a3632d4b05d4c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -193,7 +193,7 @@ nv50_disp_dmac_object_attach(struct nvkm_object *parent, u32 addr = nv_gpuobj(object)->node->offset; u32 chid = chan->chid; u32 data = (chid << 28) | (addr << 10) | chid; - return nvkm_ramht_insert(base->ramht, chid, name, data); + return nvkm_ramht_insert(base->ramht, NULL, chid, 0, name, data); } static void @@ -1153,6 +1153,8 @@ nv50_disp_main_ctor(struct nvkm_object *parent, { struct nv50_disp *disp = (void *)engine; struct nv50_disp_base *base; + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_gpuobj *instmem = (void *)parent; int ret; ret = nvkm_parent_create(parent, engine, oclass, 0, @@ -1161,15 +1163,14 @@ nv50_disp_main_ctor(struct nvkm_object *parent, if (ret) return ret; - return nvkm_ramht_new(nv_object(base), nv_object(base), 0x1000, 0, - &base->ramht); + return nvkm_ramht_new(device, 0x1000, 0, instmem, &base->ramht); } void nv50_disp_main_dtor(struct nvkm_object *object) { struct nv50_disp_base *base = (void *)object; - nvkm_ramht_ref(NULL, &base->ramht); + nvkm_ramht_del(&base->ramht); nvkm_parent_destroy(&base->base); } @@ -1235,7 +1236,7 @@ nv50_disp_main_init(struct nvkm_object *object) } /* point at display engine memory area (hash table, objects) */ - nvkm_wr32(device, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); + nvkm_wr32(device, 0x610010, (base->ramht->gpuobj->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ nvkm_wr32(device, 0x61002c, 0x00000370); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 058296b2f2852..2997193697c0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -161,7 +161,7 @@ g84_fifo_object_attach(struct nvkm_object *parent, } } - return nvkm_ramht_insert(chan->ramht, 0, handle, context); + return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); } static int @@ -172,6 +172,7 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_dma_v0 v0; } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; int ret; @@ -208,7 +209,7 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, args->v0.chid = chan->base.chid; - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, &chan->ramht); if (ret) return ret; @@ -232,7 +233,7 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(base->ramfc, 0x7c, 0x30000001); nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); + (chan->ramht->gpuobj->node->offset >> 4)); nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); nvkm_done(base->ramfc); @@ -247,6 +248,7 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_gpfifo_v0 v0; } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; u64 ioffset, ilength; @@ -285,7 +287,7 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, args->v0.chid = chan->base.chid; - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, &chan->ramht); if (ret) return ret; @@ -309,7 +311,7 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(base->ramfc, 0x7c, 0x30000001); nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); + (chan->ramht->gpuobj->node->offset >> 4)); nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); nvkm_done(base->ramfc); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 4bec707305586..cd5009302e223 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -86,7 +86,7 @@ nv04_fifo_object_attach(struct nvkm_object *parent, context |= chid << 24; mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(imem->ramht, chid, handle, context); + ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); mutex_unlock(&nv_subdev(fifo)->mutex); return ret; } @@ -625,7 +625,7 @@ nv04_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | ((ramht->bits - 9) << 16) | - (ramht->gpuobj.addr >> 8)); + (ramht->gpuobj->addr >> 8)); nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index 69b9d421305bc..e27180435bff3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -191,7 +191,7 @@ nv17_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | ((ramht->bits - 9) << 16) | - (ramht->gpuobj.addr >> 8)); + (ramht->gpuobj->addr >> 8)); nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 | 0x00010000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index a2d8da8a9341e..f2f0e3d744936 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -98,7 +98,7 @@ nv40_fifo_object_attach(struct nvkm_object *parent, context |= chid << 23; mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(imem->ramht, chid, handle, context); + ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); mutex_unlock(&nv_subdev(fifo)->mutex); return ret; } @@ -322,7 +322,7 @@ nv40_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ | ((ramht->bits - 9) << 16) | - (ramht->gpuobj.addr >> 8)); + (ramht->gpuobj->addr >> 8)); nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); switch (nv_device(fifo)->chipset) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 620c0cfb2453b..2b37fda876f43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -182,7 +182,7 @@ nv50_fifo_object_attach(struct nvkm_object *parent, } } - return nvkm_ramht_insert(chan->ramht, 0, handle, context); + return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); } void @@ -200,6 +200,7 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_dma_v0 v0; } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; int ret; @@ -231,7 +232,7 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nv_parent(chan)->object_attach = nv50_fifo_object_attach; nv_parent(chan)->object_detach = nv50_fifo_object_detach; - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, &chan->ramht); if (ret) return ret; @@ -250,7 +251,7 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(base->ramfc, 0x7c, 0x30000001); nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); + (chan->ramht->gpuobj->node->offset >> 4)); nvkm_done(base->ramfc); return 0; } @@ -263,6 +264,7 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, union { struct nv50_channel_gpfifo_v0 v0; } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; struct nv50_fifo_base *base = (void *)parent; struct nv50_fifo_chan *chan; u64 ioffset, ilength; @@ -296,7 +298,7 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, nv_parent(chan)->object_attach = nv50_fifo_object_attach; nv_parent(chan)->object_detach = nv50_fifo_object_detach; - ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16, + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, &chan->ramht); if (ret) return ret; @@ -315,7 +317,7 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(base->ramfc, 0x7c, 0x30000001); nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj.node->offset >> 4)); + (chan->ramht->gpuobj->node->offset >> 4)); nvkm_done(base->ramfc); return 0; } @@ -324,7 +326,7 @@ void nv50_fifo_chan_dtor(struct nvkm_object *object) { struct nv50_fifo_chan *chan = (void *)object; - nvkm_ramht_ref(NULL, &chan->ramht); + nvkm_ramht_del(&chan->ramht); nvkm_fifo_channel_destroy(&chan->base); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 56330ccf46563..1df45273bff7b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -156,7 +156,7 @@ nv04_instmem_dtor(struct nvkm_object *object) struct nv04_instmem *imem = (void *)object; nvkm_memory_del(&imem->base.ramfc); nvkm_memory_del(&imem->base.ramro); - nvkm_ramht_ref(NULL, &imem->base.ramht); + nvkm_ramht_del(&imem->base.ramht); nvkm_memory_del(&imem->base.vbios); nvkm_mm_fini(&imem->heap); nvkm_instmem_destroy(&imem->base); @@ -198,8 +198,7 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, - &imem->base.ramht); + ret = nvkm_ramht_new(device, 0x08000, 0, NULL, &imem->base.ramht); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index 5a2709d499e99..8e7a11503c09e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -157,7 +157,7 @@ nv40_instmem_dtor(struct nvkm_object *object) struct nv40_instmem *imem = (void *)object; nvkm_memory_del(&imem->base.ramfc); nvkm_memory_del(&imem->base.ramro); - nvkm_ramht_ref(NULL, &imem->base.ramht); + nvkm_ramht_del(&imem->base.ramht); nvkm_memory_del(&imem->base.vbios); nvkm_mm_fini(&imem->heap); if (imem->iomem) @@ -227,8 +227,7 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; /* 0x10000-0x18000: reserve for RAMHT */ - ret = nvkm_ramht_new(nv_object(imem), NULL, 0x08000, 0, - &imem->base.ramht); + ret = nvkm_ramht_new(device, 0x08000, 0, NULL, &imem->base.ramht); if (ret) return ret; -- GitLab From cd459e7776c2c08e3771e20fca7de96272f2c9cd Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5502/7006] drm/nouveau/sw/nv04: replace direct context access with GetRef method Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 12 ++++ drivers/gpu/drm/nouveau/include/nvif/device.h | 1 - .../drm/nouveau/include/nvkm/engine/fifo.h | 1 - drivers/gpu/drm/nouveau/nv04_fence.c | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 55 +++++++++++++++++-- 5 files changed, 65 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index d52b27ac33ff1..4dd2c6ec0ec32 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -580,6 +580,18 @@ struct nv50_disp_overlay_v0 { #define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00 +/******************************************************************************* + * software + ******************************************************************************/ + +#define NV04_NVSW_GET_REF 0x00 + +struct nv04_nvsw_get_ref_v0 { + __u8 version; + __u8 pad01[3]; + __u32 ref; +}; + /******************************************************************************* * fermi ******************************************************************************/ diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 68196f4874f8e..78c6649407e66 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -65,6 +65,5 @@ u64 nvif_device_time(struct nvif_device *); #include #define nvxx_fifo(a) nvkm_fifo(nvxx_device(a)) -#define nvxx_fifo_chan(a) ((struct nvkm_fifo_chan *)nvxx_object(a)) #define nvxx_gr(a) nvkm_gr(nvxx_device(a)) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 0af10f9db9e29..1efcf0fb18e3a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -9,7 +9,6 @@ struct nvkm_fifo_chan { u64 addr; u32 size; u16 chid; - atomic_t refcnt; /* NV04_NVSW_SET_REF */ }; static inline struct nvkm_fifo_chan * diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c index f4a26224ac68b..f3d705d67738a 100644 --- a/drivers/gpu/drm/nouveau/nv04_fence.c +++ b/drivers/gpu/drm/nouveau/nv04_fence.c @@ -57,8 +57,10 @@ nv04_fence_sync(struct nouveau_fence *fence, static u32 nv04_fence_read(struct nouveau_channel *chan) { - struct nvkm_fifo_chan *fifo = nvxx_fifo_chan(&chan->user); - return atomic_read(&fifo->refcnt); + struct nv04_nvsw_get_ref_v0 args = {}; + WARN_ON(nvif_object_mthd(&chan->nvsw, NV04_NVSW_GET_REF, + &args, sizeof(args))); + return args.ref; } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index 74c8c9dc2350b..a2ffe2ccdbe56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -22,9 +22,15 @@ * Authors: Ben Skeggs */ #include -#include +#include #include +#include + +struct nv04_sw_chan { + struct nvkm_sw_chan base; + atomic_t ref; +}; /******************************************************************************* * software object classes @@ -33,9 +39,8 @@ static int nv04_sw_set_ref(struct nvkm_object *object, u32 mthd, void *data, u32 size) { - struct nvkm_object *channel = (void *)nv_engctx(object->parent); - struct nvkm_fifo_chan *fifo = (void *)channel->parent; - atomic_set(&fifo->refcnt, *(u32*)data); + struct nv04_sw_chan *chan = (void *)nv_engctx(object->parent); + atomic_set(&chan->ref, *(u32*)data); return 0; } @@ -55,9 +60,46 @@ nv04_sw_omthds[] = { {} }; +static int +nv04_sw_mthd_get_ref(struct nvkm_object *object, void *data, u32 size) +{ + struct nv04_sw_chan *chan = (void *)object->parent; + union { + struct nv04_nvsw_get_ref_v0 v0; + } *args = data; + int ret; + + if (nvif_unpack(args->v0, 0, 0, false)) { + args->v0.ref = atomic_read(&chan->ref); + } + + return ret; +} + +static int +nv04_sw_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + switch (mthd) { + case NV04_NVSW_GET_REF: + return nv04_sw_mthd_get_ref(object, data, size); + default: + break; + } + return -EINVAL; +} + +static struct nvkm_ofuncs +nv04_sw_ofuncs = { + .ctor = _nvkm_object_ctor, + .dtor = nvkm_object_destroy, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, + .mthd = nv04_sw_mthd, +}; + static struct nvkm_oclass nv04_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV04, &nvkm_object_ofuncs, nv04_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV04, &nv04_sw_ofuncs, nv04_sw_omthds }, {} }; @@ -70,7 +112,7 @@ nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_sw_chan *chan; + struct nv04_sw_chan *chan; int ret; ret = nvkm_sw_context_create(parent, engine, oclass, &chan); @@ -78,6 +120,7 @@ nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + atomic_set(&chan->ref, 0); return 0; } -- GitLab From 898a2b32138da26ed8f7abc0cc8232741ca03de7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5503/7006] drm/nouveau/sw: turn flip completion into an event Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 2 + .../gpu/drm/nouveau/include/nvkm/engine/sw.h | 22 ------ drivers/gpu/drm/nouveau/nouveau_chan.c | 5 -- drivers/gpu/drm/nouveau/nouveau_display.c | 15 +++- drivers/gpu/drm/nouveau/nouveau_drm.c | 15 +++- drivers/gpu/drm/nouveau/nouveau_drm.h | 1 + drivers/gpu/drm/nouveau/nouveau_fence.h | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild | 4 + drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c | 76 +++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h | 25 ++++++ .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 11 +-- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c | 11 +-- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 9 +-- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c | 74 ++++++++++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h | 10 +++ drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h | 5 ++ 18 files changed, 240 insertions(+), 53 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 4dd2c6ec0ec32..d8bad60642ac5 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -584,6 +584,8 @@ struct nv50_disp_overlay_v0 { * software ******************************************************************************/ +#define NVSW_NTFY_UEVENT 0x00 + #define NV04_NVSW_GET_REF 0x00 struct nv04_nvsw_get_ref_v0 { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h index 8dae95829f664..b06140af0a05b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h @@ -1,27 +1,5 @@ #ifndef __NVKM_SW_H__ #define __NVKM_SW_H__ -#include - -struct nvkm_sw_chan { - struct nvkm_engctx base; - - int (*flip)(void *); - void *flip_data; -}; - -#define nvkm_sw_context_create(p,e,c,d) \ - nvkm_engctx_create((p), (e), (c), (p), 0, 0, 0, (d)) -#define nvkm_sw_context_destroy(d) \ - nvkm_engctx_destroy(&(d)->base) -#define nvkm_sw_context_init(d) \ - nvkm_engctx_init(&(d)->base) -#define nvkm_sw_context_fini(d,s) \ - nvkm_engctx_fini(&(d)->base, (s)) - -#define _nvkm_sw_context_dtor _nvkm_engctx_dtor -#define _nvkm_sw_context_init _nvkm_engctx_init -#define _nvkm_sw_context_fini _nvkm_engctx_fini - #include struct nvkm_sw { diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 7f3e821e235de..4a13bda1475b7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -293,7 +293,6 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) struct nvif_device *device = chan->device; struct nouveau_cli *cli = (void *)chan->user.client; struct nvkm_mmu *mmu = nvxx_mmu(device); - struct nvkm_sw_chan *swch; struct nv_dma_v0 args = {}; int ret, i; @@ -382,10 +381,6 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) if (ret) return ret; - swch = (void *)nvxx_object(&chan->nvsw)->parent; - swch->flip = nouveau_flip_complete; - swch->flip_data = chan; - ret = RING_SPACE(chan, 2); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index d913074c952f7..5553caa16b9cd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -358,6 +358,7 @@ int nouveau_display_init(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); + struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; int ret; @@ -374,6 +375,8 @@ nouveau_display_init(struct drm_device *dev) nvif_notify_get(&conn->hpd); } + /* enable flip completion events */ + nvif_notify_get(&drm->flip); return ret; } @@ -381,6 +384,7 @@ void nouveau_display_fini(struct drm_device *dev) { struct nouveau_display *disp = nouveau_display(dev); + struct nouveau_drm *drm = nouveau_drm(dev); struct drm_connector *connector; int head; @@ -388,6 +392,9 @@ nouveau_display_fini(struct drm_device *dev) for (head = 0; head < dev->mode_config.num_crtc; head++) drm_vblank_off(dev, head); + /* disable flip completion events */ + nvif_notify_put(&drm->flip); + /* disable hotplug interrupts */ list_for_each_entry(connector, &dev->mode_config.connector_list, head) { struct nouveau_connector *conn = nouveau_connector(connector); @@ -847,10 +854,10 @@ nouveau_finish_page_flip(struct nouveau_channel *chan, } int -nouveau_flip_complete(void *data) +nouveau_flip_complete(struct nvif_notify *notify) { - struct nouveau_channel *chan = data; - struct nouveau_drm *drm = chan->drm; + struct nouveau_drm *drm = container_of(notify, typeof(*drm), flip); + struct nouveau_channel *chan = drm->channel; struct nouveau_page_flip_state state; if (!nouveau_finish_page_flip(chan, &state)) { @@ -861,7 +868,7 @@ nouveau_flip_complete(void *data) } } - return 0; + return NVIF_NOTIFY_KEEP; } int diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index ebcbe7bbdddf6..d04d08cc546dd 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -139,6 +139,7 @@ nouveau_cli_destroy(struct nouveau_cli *cli) static void nouveau_accel_fini(struct nouveau_drm *drm) { + nvif_notify_fini(&drm->flip); nouveau_channel_del(&drm->channel); nvif_object_fini(&drm->ntfy); nvkm_gpuobj_del(&drm->notify); @@ -240,7 +241,6 @@ nouveau_accel_init(struct nouveau_drm *drm) ret = nvif_object_init(&drm->channel->user, NVDRM_NVSW, nouveau_abi16_swclass(drm), NULL, 0, &drm->nvsw); if (ret == 0) { - struct nvkm_sw_chan *swch; ret = RING_SPACE(drm->channel, 2); if (ret == 0) { if (device->info.family < NV_DEVICE_INFO_V0_FERMI) { @@ -252,9 +252,16 @@ nouveau_accel_init(struct nouveau_drm *drm) OUT_RING (drm->channel, 0x001f0000); } } - swch = (void *)nvxx_object(&drm->nvsw)->parent; - swch->flip = nouveau_flip_complete; - swch->flip_data = drm->channel; + + ret = nvif_notify_init(&drm->nvsw, nouveau_flip_complete, + false, NVSW_NTFY_UEVENT, NULL, 0, 0, + &drm->flip); + if (ret == 0) + ret = nvif_notify_get(&drm->flip); + if (ret) { + nouveau_accel_fini(drm); + return; + } } if (ret) { diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index d1a4c120b71bd..f18710afcfd3b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -150,6 +150,7 @@ struct nouveau_drm { struct nouveau_fbdev *fbcon; struct nvif_object nvsw; struct nvif_object ntfy; + struct nvif_notify flip; /* nv10-nv40 tiling regions */ struct { diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h index d9241d8247fbc..2e3a62d38fe9d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_fence.h +++ b/drivers/gpu/drm/nouveau/nouveau_fence.h @@ -85,7 +85,7 @@ int nv50_fence_create(struct nouveau_drm *); int nv84_fence_create(struct nouveau_drm *); int nvc0_fence_create(struct nouveau_drm *); -int nouveau_flip_complete(void *chan); +int nouveau_flip_complete(struct nvif_notify *); struct nv84_fence_chan { struct nouveau_fence_chan base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild index bdc3a05907d5b..1144d84e46de3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild @@ -2,3 +2,7 @@ nvkm-y += nvkm/engine/sw/nv04.o nvkm-y += nvkm/engine/sw/nv10.o nvkm-y += nvkm/engine/sw/nv50.o nvkm-y += nvkm/engine/sw/gf100.o + +nvkm-y += nvkm/engine/sw/chan.o + +nvkm-y += nvkm/engine/sw/nvsw.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c new file mode 100644 index 0000000000000..97c0d96463a2c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c @@ -0,0 +1,76 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "chan.h" + +#include + +#include +#include + +static int +nvkm_sw_chan_event_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + union { + struct nvif_notify_uevent_req none; + } *req = data; + int ret; + + if (nvif_unvers(req->none)) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; + notify->index = 0; + } + + return ret; +} + +static const struct nvkm_event_func +nvkm_sw_chan_event = { + .ctor = nvkm_sw_chan_event_ctor, +}; + +void +nvkm_sw_chan_dtor(struct nvkm_object *base) +{ + struct nvkm_sw_chan *chan = (void *)base; + nvkm_event_fini(&chan->event); + nvkm_engctx_destroy(&chan->base); +} + +int +nvkm_sw_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, int length, void **pobject) +{ + struct nvkm_sw_chan *chan; + int ret; + + ret = nvkm_engctx_create_(parent, engine, oclass, parent, + 0, 0, 0, length, pobject); + chan = *pobject; + if (ret) + return ret; + + return nvkm_event_init(&nvkm_sw_chan_event, 1, 1, &chan->event); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h new file mode 100644 index 0000000000000..b5cf4c517a955 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h @@ -0,0 +1,25 @@ +#ifndef __NVKM_SW_CHAN_H__ +#define __NVKM_SW_CHAN_H__ +#include "priv.h" +#include +#include + +struct nvkm_sw_chan { + struct nvkm_engctx base; + struct nvkm_event event; +}; + +#define nvkm_sw_context_create(p,e,c,d) \ + nvkm_sw_chan_ctor((p), (e), (c), sizeof(**d), (void **)d) +int nvkm_sw_chan_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, int, void **); +void nvkm_sw_chan_dtor(struct nvkm_object *); +#define nvkm_sw_context_init(d) \ + nvkm_engctx_init(&(d)->base) +#define nvkm_sw_context_fini(d,s) \ + nvkm_engctx_fini(&(d)->base, (s)) + +#define _nvkm_sw_context_dtor nvkm_sw_chan_dtor +#define _nvkm_sw_context_init _nvkm_engctx_init +#define _nvkm_sw_context_fini _nvkm_engctx_fini +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 061ea72f5d0f7..d57052cdcad3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -89,7 +89,7 @@ gf100_sw_omthds[] = { static struct nvkm_oclass gf100_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_GF100, &nvkm_object_ofuncs, gf100_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_GF100, &nvkm_nvsw_ofuncs, gf100_sw_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index a2ffe2ccdbe56..08b59f198c73a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -21,7 +21,9 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" +#include "chan.h" +#include "nvsw.h" #include #include @@ -48,9 +50,8 @@ static int nv04_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nvkm_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->flip) - return chan->flip(chan->flip_data); - return -EINVAL; + nvkm_event_send(&chan->event, 1, 0, NULL, 0); + return 0; } static struct nvkm_omthds @@ -90,7 +91,7 @@ nv04_sw_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) static struct nvkm_ofuncs nv04_sw_ofuncs = { - .ctor = _nvkm_object_ctor, + .ctor = nvkm_nvsw_ctor, .dtor = nvkm_object_destroy, .init = _nvkm_object_init, .fini = _nvkm_object_fini, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index 26ccd690bea85..d0d4339b857c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -21,7 +21,9 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" +#include "chan.h" +#include "nvsw.h" #include @@ -33,9 +35,8 @@ static int nv10_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nvkm_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->flip) - return chan->flip(chan->flip_data); - return -EINVAL; + nvkm_event_send(&chan->event, 1, 0, NULL, 0); + return 0; } static struct nvkm_omthds @@ -46,7 +47,7 @@ nv10_sw_omthds[] = { static struct nvkm_oclass nv10_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV10, &nvkm_object_ofuncs, nv10_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV10, &nvkm_nvsw_ofuncs, nv10_sw_omthds }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index ca4b8a02b9712..9322bde518d2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -92,9 +92,8 @@ int nv50_sw_mthd_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) { struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - if (chan->base.flip) - return chan->base.flip(chan->base.flip_data); - return -EINVAL; + nvkm_event_send(&chan->base.event, 1, 0, NULL, 0); + return 0; } static struct nvkm_omthds @@ -109,7 +108,7 @@ nv50_sw_omthds[] = { static struct nvkm_oclass nv50_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV50, &nvkm_object_ofuncs, nv50_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV50, &nvkm_nvsw_ofuncs, nv50_sw_omthds }, {} }; @@ -150,7 +149,7 @@ nv50_sw_context_dtor(struct nvkm_object *object) for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++) nvkm_notify_fini(&chan->vblank.notify[i]); - nvkm_sw_context_destroy(&chan->base); + nvkm_sw_chan_dtor(&chan->base.base.gpuobj.object); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index 1c9101bff8945..f3bf451546b12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -1,6 +1,8 @@ #ifndef __NVKM_SW_NV50_H__ #define __NVKM_SW_NV50_H__ -#include +#include "priv.h" +#include "chan.h" +#include "nvsw.h" #include struct nv50_sw_oclass { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c new file mode 100644 index 0000000000000..c3c6829fd0010 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c @@ -0,0 +1,74 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#define nvkm_nvsw(p) container_of((p), struct nvkm_nvsw, object) +#include "nvsw.h" +#include "chan.h" + +#include + +struct nvkm_nvsw { + struct nvkm_object object; + struct nvkm_sw_chan *chan; +}; + +static int +nvkm_nvsw_ntfy(struct nvkm_object *base, u32 mthd, struct nvkm_event **pevent) +{ + struct nvkm_nvsw *nvsw = nvkm_nvsw(base); + switch (mthd) { + case NVSW_NTFY_UEVENT: + *pevent = &nvsw->chan->event; + return 0; + default: + break; + } + return -EINVAL; +} + +int +nvkm_nvsw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_sw_chan *chan = (void *)parent; + struct nvkm_nvsw *nvsw; + int ret; + + ret = nvkm_object_create(parent, engine, oclass, 0, &nvsw); + *pobject = &nvsw->object; + if (ret) + return ret; + + nvsw->chan = chan; + return 0; +} + +struct nvkm_ofuncs +nvkm_nvsw_ofuncs = { + .ctor = nvkm_nvsw_ctor, + .dtor = nvkm_object_destroy, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, + .ntfy = nvkm_nvsw_ntfy, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h new file mode 100644 index 0000000000000..c54a12798e847 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h @@ -0,0 +1,10 @@ +#ifndef __NVKM_NVSW_H__ +#define __NVKM_NVSW_H__ +#include "priv.h" + +extern struct nvkm_ofuncs nvkm_nvsw_ofuncs; +int +nvkm_nvsw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h new file mode 100644 index 0000000000000..42707355eb92c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h @@ -0,0 +1,5 @@ +#ifndef __NVKM_SW_PRIV_H__ +#define __NVKM_SW_PRIV_H__ +#include + +#endif -- GitLab From 344c2d429dd86b1b0113177e18f15adb74e9d936 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5504/7006] drm/nouveau/fb: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/fifo.h | 8 + .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 41 +++++ .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 2 + .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 2 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 162 ++++++++---------- 7 files changed, 125 insertions(+), 92 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 1efcf0fb18e3a..d70fe7f9a44d9 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -9,6 +9,7 @@ struct nvkm_fifo_chan { u64 addr; u32 size; u16 chid; + u64 inst; }; static inline struct nvkm_fifo_chan * @@ -81,6 +82,13 @@ struct nvkm_fifo { void (*start)(struct nvkm_fifo *, unsigned long *); }; +void nvkm_fifo_chan_put(struct nvkm_fifo *, unsigned long flags, + struct nvkm_fifo_chan **); +struct nvkm_fifo_chan * +nvkm_fifo_chan_inst(struct nvkm_fifo *, u64 inst, unsigned long *flags); +struct nvkm_fifo_chan * +nvkm_fifo_chan_chid(struct nvkm_fifo *, int chid, unsigned long *flags); + static inline struct nvkm_fifo * nvkm_fifo(void *obj) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 1934dfb5a434a..60e5fab4c80a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -32,6 +32,47 @@ #include #include +void +nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, + struct nvkm_fifo_chan **pchan) +{ + struct nvkm_fifo_chan *chan = *pchan; + if (likely(chan)) { + *pchan = NULL; + spin_unlock_irqrestore(&fifo->lock, flags); + } +} + +struct nvkm_fifo_chan * +nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) +{ + unsigned long flags; + int i; + spin_lock_irqsave(&fifo->lock, flags); + for (i = fifo->min; i < fifo->max; i++) { + struct nvkm_fifo_chan *chan = (void *)fifo->channel[i]; + if (chan && chan->inst == inst) { + *rflags = flags; + return chan; + } + } + spin_unlock_irqrestore(&fifo->lock, flags); + return NULL; +} + +struct nvkm_fifo_chan * +nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) +{ + unsigned long flags; + spin_lock_irqsave(&fifo->lock, flags); + if (fifo->channel[chid]) { + *rflags = flags; + return (void *)fifo->channel[chid]; + } + spin_unlock_irqrestore(&fifo->lock, flags); + return NULL; +} + static int nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 2997193697c0e..c2ce3fa31f10a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -207,6 +207,7 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, @@ -285,6 +286,7 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 77b8df1f57fba..9053730aafca3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -226,6 +226,7 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; nv_parent(chan)->context_attach = gf100_fifo_context_attach; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 39dae1a28dd1e..4407f6bbf94fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -283,6 +283,7 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; nv_parent(chan)->context_attach = gk104_fifo_context_attach; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 2b37fda876f43..23d5ee2fed853 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -225,6 +225,7 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; nv_parent(chan)->context_attach = nv50_fifo_context_attach; @@ -291,6 +292,7 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; nv_parent(chan)->context_attach = nv50_fifo_context_attach; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 072b0c3881df5..ea83f7d9ddc81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -25,8 +25,8 @@ #include "ram.h" #include -#include #include +#include int nv50_fb_memtype[0x80] = { @@ -47,98 +47,98 @@ nv50_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) } static const struct nvkm_enum vm_dispatch_subclients[] = { - { 0x00000000, "GRCTX", NULL }, - { 0x00000001, "NOTIFY", NULL }, - { 0x00000002, "QUERY", NULL }, - { 0x00000003, "COND", NULL }, - { 0x00000004, "M2M_IN", NULL }, - { 0x00000005, "M2M_OUT", NULL }, - { 0x00000006, "M2M_NOTIFY", NULL }, + { 0x00000000, "GRCTX" }, + { 0x00000001, "NOTIFY" }, + { 0x00000002, "QUERY" }, + { 0x00000003, "COND" }, + { 0x00000004, "M2M_IN" }, + { 0x00000005, "M2M_OUT" }, + { 0x00000006, "M2M_NOTIFY" }, {} }; static const struct nvkm_enum vm_ccache_subclients[] = { - { 0x00000000, "CB", NULL }, - { 0x00000001, "TIC", NULL }, - { 0x00000002, "TSC", NULL }, + { 0x00000000, "CB" }, + { 0x00000001, "TIC" }, + { 0x00000002, "TSC" }, {} }; static const struct nvkm_enum vm_prop_subclients[] = { - { 0x00000000, "RT0", NULL }, - { 0x00000001, "RT1", NULL }, - { 0x00000002, "RT2", NULL }, - { 0x00000003, "RT3", NULL }, - { 0x00000004, "RT4", NULL }, - { 0x00000005, "RT5", NULL }, - { 0x00000006, "RT6", NULL }, - { 0x00000007, "RT7", NULL }, - { 0x00000008, "ZETA", NULL }, - { 0x00000009, "LOCAL", NULL }, - { 0x0000000a, "GLOBAL", NULL }, - { 0x0000000b, "STACK", NULL }, - { 0x0000000c, "DST2D", NULL }, + { 0x00000000, "RT0" }, + { 0x00000001, "RT1" }, + { 0x00000002, "RT2" }, + { 0x00000003, "RT3" }, + { 0x00000004, "RT4" }, + { 0x00000005, "RT5" }, + { 0x00000006, "RT6" }, + { 0x00000007, "RT7" }, + { 0x00000008, "ZETA" }, + { 0x00000009, "LOCAL" }, + { 0x0000000a, "GLOBAL" }, + { 0x0000000b, "STACK" }, + { 0x0000000c, "DST2D" }, {} }; static const struct nvkm_enum vm_pfifo_subclients[] = { - { 0x00000000, "PUSHBUF", NULL }, - { 0x00000001, "SEMAPHORE", NULL }, + { 0x00000000, "PUSHBUF" }, + { 0x00000001, "SEMAPHORE" }, {} }; static const struct nvkm_enum vm_bar_subclients[] = { - { 0x00000000, "FB", NULL }, - { 0x00000001, "IN", NULL }, + { 0x00000000, "FB" }, + { 0x00000001, "IN" }, {} }; static const struct nvkm_enum vm_client[] = { - { 0x00000000, "STRMOUT", NULL }, + { 0x00000000, "STRMOUT" }, { 0x00000003, "DISPATCH", vm_dispatch_subclients }, - { 0x00000004, "PFIFO_WRITE", NULL }, + { 0x00000004, "PFIFO_WRITE" }, { 0x00000005, "CCACHE", vm_ccache_subclients }, - { 0x00000006, "PMSPPP", NULL }, - { 0x00000007, "CLIPID", NULL }, - { 0x00000008, "PFIFO_READ", NULL }, - { 0x00000009, "VFETCH", NULL }, - { 0x0000000a, "TEXTURE", NULL }, + { 0x00000006, "PMSPPP" }, + { 0x00000007, "CLIPID" }, + { 0x00000008, "PFIFO_READ" }, + { 0x00000009, "VFETCH" }, + { 0x0000000a, "TEXTURE" }, { 0x0000000b, "PROP", vm_prop_subclients }, - { 0x0000000c, "PVP", NULL }, - { 0x0000000d, "PBSP", NULL }, - { 0x0000000e, "PCRYPT", NULL }, - { 0x0000000f, "PCOUNTER", NULL }, - { 0x00000011, "PDAEMON", NULL }, + { 0x0000000c, "PVP" }, + { 0x0000000d, "PBSP" }, + { 0x0000000e, "PCRYPT" }, + { 0x0000000f, "PCOUNTER" }, + { 0x00000011, "PDAEMON" }, {} }; static const struct nvkm_enum vm_engine[] = { - { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR }, - { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP }, - { 0x00000004, "PEEPHOLE", NULL }, - { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO }, + { 0x00000000, "PGRAPH" }, + { 0x00000001, "PVP" }, + { 0x00000004, "PEEPHOLE" }, + { 0x00000005, "PFIFO", vm_pfifo_subclients }, { 0x00000006, "BAR", vm_bar_subclients }, - { 0x00000008, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP }, - { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG }, - { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP }, - { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CIPHER }, - { 0x0000000b, "PCOUNTER", NULL }, - { 0x0000000c, "SEMAPHORE_BG", NULL }, - { 0x0000000d, "PCE0", NULL, NVDEV_ENGINE_CE0 }, - { 0x0000000e, "PDAEMON", NULL }, + { 0x00000008, "PMSPPP" }, + { 0x00000008, "PMPEG" }, + { 0x00000009, "PBSP" }, + { 0x0000000a, "PCRYPT" }, + { 0x0000000b, "PCOUNTER" }, + { 0x0000000c, "SEMAPHORE_BG" }, + { 0x0000000d, "PCE0" }, + { 0x0000000e, "PDAEMON" }, {} }; static const struct nvkm_enum vm_fault[] = { - { 0x00000000, "PT_NOT_PRESENT", NULL }, - { 0x00000001, "PT_TOO_SHORT", NULL }, - { 0x00000002, "PAGE_NOT_PRESENT", NULL }, - { 0x00000003, "PAGE_SYSTEM_ONLY", NULL }, - { 0x00000004, "PAGE_READ_ONLY", NULL }, - { 0x00000006, "NULL_DMAOBJ", NULL }, - { 0x00000007, "WRONG_MEMTYPE", NULL }, - { 0x0000000b, "VRAM_LIMIT", NULL }, - { 0x0000000f, "DMAOBJ_LIMIT", NULL }, + { 0x00000000, "PT_NOT_PRESENT" }, + { 0x00000001, "PT_TOO_SHORT" }, + { 0x00000002, "PAGE_NOT_PRESENT" }, + { 0x00000003, "PAGE_SYSTEM_ONLY" }, + { 0x00000004, "PAGE_READ_ONLY" }, + { 0x00000006, "NULL_DMAOBJ" }, + { 0x00000007, "WRONG_MEMTYPE" }, + { 0x0000000b, "VRAM_LIMIT" }, + { 0x0000000f, "DMAOBJ_LIMIT" }, {} }; @@ -147,11 +147,12 @@ nv50_fb_intr(struct nvkm_subdev *subdev) { struct nv50_fb *fb = (void *)subdev; struct nvkm_device *device = fb->base.subdev.device; - struct nvkm_engine *engine; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fifo_chan *chan; const struct nvkm_enum *en, *re, *cl, *sc; - struct nvkm_object *engctx = NULL; - u32 trap[6], idx, chan; + u32 trap[6], idx, inst; u8 st0, st1, st2, st3; + unsigned long flags; int i; idx = nvkm_rd32(device, 0x100c90); @@ -178,48 +179,25 @@ nv50_fb_intr(struct nvkm_subdev *subdev) st2 = (trap[0] & 0x00ff0000) >> 16; st3 = (trap[0] & 0xff000000) >> 24; } - chan = (trap[2] << 16) | trap[1]; + inst = ((trap[2] << 16) | trap[1]) << 12; en = nvkm_enum_find(vm_engine, st0); - - if (en && en->data2) { - const struct nvkm_enum *orig_en = en; - while (en->name && en->value == st0 && en->data2) { - engine = nvkm_engine(subdev, en->data2); - /*XXX: clean this up */ - if (!engine && en->data2 == NVDEV_ENGINE_BSP) - engine = nvkm_engine(subdev, NVDEV_ENGINE_MSVLD); - if (!engine && en->data2 == NVDEV_ENGINE_CIPHER) - engine = nvkm_engine(subdev, NVDEV_ENGINE_SEC); - if (!engine && en->data2 == NVDEV_ENGINE_VP) - engine = nvkm_engine(subdev, NVDEV_ENGINE_MSPDEC); - if (engine) { - engctx = nvkm_engctx_get(engine, chan); - if (engctx) - break; - } - en++; - } - if (!engctx) - en = orig_en; - } - re = nvkm_enum_find(vm_fault , st1); cl = nvkm_enum_find(vm_client, st2); if (cl && cl->data) sc = nvkm_enum_find(cl->data, st3); else if (en && en->data) sc = nvkm_enum_find(en->data, st3); else sc = NULL; + chan = nvkm_fifo_chan_inst(fifo, inst, &flags); nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel " "%08x [%s] engine %02x [%s] client %02x [%s] " "subclient %02x [%s] reason %08x [%s]\n", (trap[5] & 0x00000100) ? "read" : "write", - trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan, - nvkm_client_name(engctx), st0, en ? en->name : "", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, inst, + nvkm_client_name(chan), st0, en ? en->name : "", st2, cl ? cl->name : "", st3, sc ? sc->name : "", st1, re ? re->name : ""); - - nvkm_engctx_put(engctx); + nvkm_fifo_chan_put(fifo, flags, &chan); } int -- GitLab From a83d8872fc8a482e47f7375ab66006e1f8c1fd59 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5505/7006] drm/nouveau/falcon: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/ce.h | 4 +- .../drm/nouveau/include/nvkm/engine/falcon.h | 20 ++++--- .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 15 +++-- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 54 ++++++------------ drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 27 +++++++-- .../gpu/drm/nouveau/nvkm/engine/mspdec/g98.c | 8 ++- .../drm/nouveau/nvkm/engine/mspdec/gf100.c | 9 ++- .../drm/nouveau/nvkm/engine/mspdec/gk104.c | 9 ++- .../gpu/drm/nouveau/nvkm/engine/msppp/g98.c | 8 ++- .../gpu/drm/nouveau/nvkm/engine/msppp/gf100.c | 9 ++- .../gpu/drm/nouveau/nvkm/engine/msvld/g98.c | 8 ++- .../gpu/drm/nouveau/nvkm/engine/msvld/gf100.c | 9 ++- .../gpu/drm/nouveau/nvkm/engine/msvld/gk104.c | 9 ++- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 55 +++++++------------ 14 files changed, 131 insertions(+), 113 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h index e832f729e1b4e..43c18abd40343 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h @@ -1,8 +1,8 @@ #ifndef __NVKM_CE_H__ #define __NVKM_CE_H__ -#include +#include -void gt215_ce_intr(struct nvkm_subdev *); +void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_fifo_chan *); extern struct nvkm_oclass gt215_ce_oclass; extern struct nvkm_oclass gf100_ce0_oclass; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index 5e6f1f518ea5b..bdadc8b602811 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -1,6 +1,7 @@ #ifndef __NVKM_FALCON_H__ #define __NVKM_FALCON_H__ #include +struct nvkm_fifo_chan; struct nvkm_falcon_chan { struct nvkm_engctx base; @@ -30,6 +31,7 @@ struct nvkm_falcon_data { struct nvkm_falcon { struct nvkm_engine engine; + const struct nvkm_falcon_func *func; u32 addr; u8 version; @@ -51,10 +53,14 @@ struct nvkm_falcon { } data; }; +struct nvkm_falcon_func { + void (*intr)(struct nvkm_falcon *, struct nvkm_fifo_chan *); +}; + #define nv_falcon(priv) ((struct nvkm_falcon *)priv) -#define nvkm_falcon_create(p,e,c,b,d,i,f,r) \ - nvkm_falcon_create_((p), (e), (c), (b), (d), (i), (f), \ +#define nvkm_falcon_create(a,p,e,c,b,d,i,f,r) \ + nvkm_falcon_create_((a), (p), (e), (c), (b), (d), (i), (f), \ sizeof(**r),(void **)r) #define nvkm_falcon_destroy(p) \ nvkm_engine_destroy(&(p)->engine) @@ -67,12 +73,10 @@ struct nvkm_falcon { _nvkm_falcon_fini(nv_object(_falcon), (s)); \ }) -int nvkm_falcon_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32, bool, const char *, - const char *, int, void **); - -void nvkm_falcon_intr(struct nvkm_subdev *subdev); - +int nvkm_falcon_create_(const struct nvkm_falcon_func *, + struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, u32, bool, const char *, + const char *, int, void **); #define _nvkm_falcon_dtor _nvkm_engine_dtor int _nvkm_falcon_init(struct nvkm_object *); int _nvkm_falcon_fini(struct nvkm_object *, bool); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 1989f659716c1..6faf38e3dbbc5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -88,6 +88,11 @@ gf100_ce_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +gf100_ce_func = { + .intr = gt215_ce_intr, +}; + static int gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -96,14 +101,13 @@ gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *ce; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, true, - "PCE0", "ce0", &ce); + ret = nvkm_falcon_create(&gf100_ce_func, parent, engine, oclass, + 0x104000, true, "PCE0", "ce0", &ce); *pobject = nv_object(ce); if (ret) return ret; nv_subdev(ce)->unit = 0x00000040; - nv_subdev(ce)->intr = gt215_ce_intr; nv_engine(ce)->cclass = &gf100_ce0_cclass; nv_engine(ce)->sclass = gf100_ce0_sclass; nv_falcon(ce)->code.data = gf100_ce_code; @@ -121,14 +125,13 @@ gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *ce; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x105000, true, - "PCE1", "ce1", &ce); + ret = nvkm_falcon_create(&gf100_ce_func, parent, engine, oclass, + 0x105000, true, "PCE1", "ce1", &ce); *pobject = nv_object(ce); if (ret) return ret; nv_subdev(ce)->unit = 0x00000080; - nv_subdev(ce)->intr = gt215_ce_intr; nv_engine(ce)->cclass = &gf100_ce1_cclass; nv_engine(ce)->sclass = gf100_ce1_sclass; nv_falcon(ce)->code.data = gf100_ce_code; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index b52acdcaa81e9..a632570f20e1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include -#include #include #include "fuc/gt215.fuc3.h" @@ -70,47 +69,31 @@ gt215_ce_isr_error_name[] = { }; void -gt215_ce_intr(struct nvkm_subdev *subdev) +gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) { - struct nvkm_falcon *ce = (void *)subdev; - struct nvkm_engine *engine = &ce->engine; - struct nvkm_device *device = engine->subdev.device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_object *engctx; - const struct nvkm_enum *en; + struct nvkm_subdev *subdev = &ce->engine.subdev; + struct nvkm_device *device = subdev->device; const u32 base = (nv_subidx(subdev) - NVDEV_ENGINE_CE0) * 0x1000; - u32 dispatch = nvkm_rd32(device, 0x10401c + base); - u32 stat = nvkm_rd32(device, 0x104008 + base) & dispatch & ~(dispatch >> 16); - u64 inst = nvkm_rd32(device, 0x104050 + base) & 0x3fffffff; u32 ssta = nvkm_rd32(device, 0x104040 + base) & 0x0000ffff; u32 addr = nvkm_rd32(device, 0x104040 + base) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; u32 data = nvkm_rd32(device, 0x104044 + base); - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); - - if (stat & 0x00000040) { - en = nvkm_enum_find(gt215_ce_isr_error_name, ssta); - nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] " - "ch %d [%010llx %s] subc %d " - "mthd %04x data %08x\n", - ssta, en ? en->name : "", chid, inst << 12, - nvkm_client_name(engctx), subc, mthd, data); - nvkm_wr32(device, 0x104004 + base, 0x00000040); - stat &= ~0x00000040; - } - - if (stat) { - nvkm_error(subdev, "intr %08x\n", stat); - nvkm_wr32(device, 0x104004 + base, stat); - } - - nvkm_engctx_put(engctx); + const struct nvkm_enum *en = + nvkm_enum_find(gt215_ce_isr_error_name, ssta); + + nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", ssta, + en ? en->name : "", chan ? chan->chid : -1, + chan ? chan->inst : 0, nvkm_client_name(chan), + subc, mthd, data); } +static const struct nvkm_falcon_func +gt215_ce_func = { + .intr = gt215_ce_intr, +}; + static int gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -120,14 +103,13 @@ gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *ce; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, enable, - "PCE0", "ce0", &ce); + ret = nvkm_falcon_create(>215_ce_func, parent, engine, oclass, + 0x104000, enable, "PCE0", "ce0", &ce); *pobject = nv_object(ce); if (ret) return ret; nv_subdev(ce)->unit = 0x00802000; - nv_subdev(ce)->intr = gt215_ce_intr; nv_engine(ce)->cclass = >215_ce_cclass; nv_engine(ce)->sclass = gt215_ce_sclass; nv_falcon(ce)->code.data = gt215_ce_code; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 27bc50e80a56b..b0cbe819497a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -20,17 +20,31 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include +#include #include -void +static void nvkm_falcon_intr(struct nvkm_subdev *subdev) { struct nvkm_falcon *falcon = (void *)subdev; struct nvkm_device *device = falcon->engine.subdev.device; const u32 base = falcon->addr; - u32 dispatch = nvkm_rd32(device, base + 0x01c); - u32 intr = nvkm_rd32(device, base + 0x008) & dispatch & ~(dispatch >> 16); + u32 dest = nvkm_rd32(device, base + 0x01c); + u32 intr = nvkm_rd32(device, base + 0x008) & dest & ~(dest >> 16); + u32 inst = nvkm_rd32(device, base + 0x050) & 0x3fffffff; + struct nvkm_fifo_chan *chan; + unsigned long flags; + + chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + + if (intr & 0x00000040) { + if (falcon->func->intr) { + falcon->func->intr(falcon, chan); + nvkm_wr32(device, base + 0x004, 0x00000040); + intr &= ~0x00000040; + } + } if (intr & 0x00000010) { nvkm_debug(subdev, "ucode halted\n"); @@ -42,6 +56,8 @@ nvkm_falcon_intr(struct nvkm_subdev *subdev) nvkm_error(subdev, "intr %08x\n", intr); nvkm_wr32(device, base + 0x004, intr); } + + nvkm_fifo_chan_put(device->fifo, flags, &chan); } static void * @@ -260,7 +276,8 @@ _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) } int -nvkm_falcon_create_(struct nvkm_object *parent, struct nvkm_object *engine, +nvkm_falcon_create_(const struct nvkm_falcon_func *func, + struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 addr, bool enable, const char *iname, const char *fname, int length, void **pobject) @@ -274,6 +291,8 @@ nvkm_falcon_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + falcon->engine.subdev.intr = nvkm_falcon_intr; + falcon->func = func; falcon->addr = addr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index c8a1a1288af6e..fbb38450f1e50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -72,6 +72,10 @@ g98_mspdec_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +g98_mspdec_func = { +}; + static int g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -80,8 +84,8 @@ g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *mspdec; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &mspdec); + ret = nvkm_falcon_create(&g98_mspdec_func, parent, engine, oclass, + 0x085000, true, "PMSPDEC", "mspdec", &mspdec); *pobject = nv_object(mspdec); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index 4b759f3e8f51b..71b75e9177b43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -71,6 +71,10 @@ gf100_mspdec_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +gf100_mspdec_func = { +}; + static int gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -79,14 +83,13 @@ gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *mspdec; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &mspdec); + ret = nvkm_falcon_create(&gf100_mspdec_func, parent, engine, oclass, + 0x085000, true, "PMSPDEC", "mspdec", &mspdec); *pobject = nv_object(mspdec); if (ret) return ret; nv_subdev(mspdec)->unit = 0x00020000; - nv_subdev(mspdec)->intr = nvkm_falcon_intr; nv_engine(mspdec)->cclass = &gf100_mspdec_cclass; nv_engine(mspdec)->sclass = gf100_mspdec_sclass; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index ab2923634644e..a103789a26112 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -71,6 +71,10 @@ gk104_mspdec_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +gk104_mspdec_func = { +}; + static int gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -79,14 +83,13 @@ gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *falcon; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true, - "PMSPDEC", "mspdec", &falcon); + ret = nvkm_falcon_create(&gk104_mspdec_func, parent, engine, oclass, + 0x085000, true, "PMSPDEC", "mspdec", &falcon); *pobject = nv_object(falcon); if (ret) return ret; nv_subdev(falcon)->unit = 0x00020000; - nv_subdev(falcon)->intr = nvkm_falcon_intr; nv_engine(falcon)->cclass = &gk104_mspdec_cclass; nv_engine(falcon)->sclass = gk104_mspdec_sclass; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index 80b12ab097814..9029ff0ea86d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -72,6 +72,10 @@ g98_msppp_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +g98_msppp_func = { +}; + static int g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -80,8 +84,8 @@ g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *msppp; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true, - "PMSPPP", "msppp", &msppp); + ret = nvkm_falcon_create(&g98_msppp_func, parent, engine, oclass, + 0x086000, true, "PMSPPP", "msppp", &msppp); *pobject = nv_object(msppp); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index 5f5018bf82809..2b21fe5dafdae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -71,6 +71,10 @@ gf100_msppp_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +gf100_msppp_func = { +}; + static int gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -79,14 +83,13 @@ gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *msppp; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true, - "PMSPPP", "msppp", &msppp); + ret = nvkm_falcon_create(&gf100_msppp_func, parent, engine, oclass, + 0x086000, true, "PMSPPP", "msppp", &msppp); *pobject = nv_object(msppp); if (ret) return ret; nv_subdev(msppp)->unit = 0x00000002; - nv_subdev(msppp)->intr = nvkm_falcon_intr; nv_engine(msppp)->cclass = &gf100_msppp_cclass; nv_engine(msppp)->sclass = gf100_msppp_sclass; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index 5312cd605dd7a..cdb7de5a73054 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -73,6 +73,10 @@ g98_msvld_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +g98_msvld_func = { +}; + static int g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -81,8 +85,8 @@ g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *msvld; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &msvld); + ret = nvkm_falcon_create(&g98_msvld_func, parent, engine, oclass, + 0x084000, true, "PMSVLD", "msvld", &msvld); *pobject = nv_object(msvld); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index e5de6db866cfd..1124373be9207 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -71,6 +71,10 @@ gf100_msvld_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +gf100_msvld_func = { +}; + static int gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -79,14 +83,13 @@ gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *msvld; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &msvld); + ret = nvkm_falcon_create(&gf100_msvld_func, parent, engine, oclass, + 0x084000, true, "PMSVLD", "msvld", &msvld); *pobject = nv_object(msvld); if (ret) return ret; nv_subdev(msvld)->unit = 0x00008000; - nv_subdev(msvld)->intr = nvkm_falcon_intr; nv_engine(msvld)->cclass = &gf100_msvld_cclass; nv_engine(msvld)->sclass = gf100_msvld_sclass; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index 0858765c5201c..addef2bbfe76b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -71,6 +71,10 @@ gk104_msvld_init(struct nvkm_object *object) return 0; } +static const struct nvkm_falcon_func +gk104_msvld_func = { +}; + static int gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -79,14 +83,13 @@ gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *msvld; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true, - "PMSVLD", "msvld", &msvld); + ret = nvkm_falcon_create(&gk104_msvld_func, parent, engine, oclass, + 0x084000, true, "PMSVLD", "msvld", &msvld); *pobject = nv_object(msvld); if (ret) return ret; nv_subdev(msvld)->unit = 0x00008000; - nv_subdev(msvld)->intr = nvkm_falcon_intr; nv_engine(msvld)->cclass = &gk104_msvld_cclass; nv_engine(msvld)->sclass = gk104_msvld_sclass; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index 431bd5aa6c3d1..e6544097726c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -23,11 +23,11 @@ */ #include #include +#include #include "fuc/g98.fuc0s.h" #include #include -#include /******************************************************************************* * Crypt object classes @@ -69,46 +69,30 @@ static const struct nvkm_enum g98_sec_isr_error_name[] = { }; static void -g98_sec_intr(struct nvkm_subdev *subdev) +g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) { - struct nvkm_falcon *sec = (void *)subdev; - struct nvkm_device *device = sec->engine.subdev.device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - u32 disp = nvkm_rd32(device, 0x08701c); - u32 stat = nvkm_rd32(device, 0x087008) & disp & ~(disp >> 16); - u32 inst = nvkm_rd32(device, 0x087050) & 0x3fffffff; + struct nvkm_subdev *subdev = &sec->engine.subdev; + struct nvkm_device *device = subdev->device; u32 ssta = nvkm_rd32(device, 0x087040) & 0x0000ffff; u32 addr = nvkm_rd32(device, 0x087040) >> 16; u32 mthd = (addr & 0x07ff) << 2; u32 subc = (addr & 0x3800) >> 11; u32 data = nvkm_rd32(device, 0x087044); - const struct nvkm_enum *en; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); - - if (stat & 0x00000040) { - en = nvkm_enum_find(g98_sec_isr_error_name, ssta); - nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] " - "ch %d [%010llx %s] subc %d " - "mthd %04x data %08x\n", ssta, - en ? en->name : "", chid, (u64)inst << 12, - nvkm_client_name(engctx), subc, mthd, data); - nvkm_wr32(device, 0x087004, 0x00000040); - stat &= ~0x00000040; - } - - if (stat) { - nvkm_error(subdev, "intr %08x\n", stat); - nvkm_wr32(device, 0x087004, stat); - } - - nvkm_engctx_put(engctx); + const struct nvkm_enum *en = + nvkm_enum_find(g98_sec_isr_error_name, ssta); + + nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", ssta, + en ? en->name : "UNKNOWN", chan ? chan->chid : -1, + chan ? chan->inst : 0, nvkm_client_name(chan), + subc, mthd, data); } +static const struct nvkm_falcon_func +g98_sec_func = { + .intr = g98_sec_intr, +}; + static int g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -117,14 +101,13 @@ g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *sec; int ret; - ret = nvkm_falcon_create(parent, engine, oclass, 0x087000, true, - "PSEC", "sec", &sec); + ret = nvkm_falcon_create(&g98_sec_func, parent, engine, oclass, + 0x087000, true, "PSEC", "sec", &sec); *pobject = nv_object(sec); if (ret) return ret; nv_subdev(sec)->unit = 0x00004000; - nv_subdev(sec)->intr = g98_sec_intr; nv_engine(sec)->cclass = &g98_sec_cclass; nv_engine(sec)->sclass = g98_sec_sclass; nv_falcon(sec)->code.data = g98_sec_code; -- GitLab From 35acf3d72cf273e164c9a8bbf30610b95e2a4c84 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5506/7006] drm/nouveau/cipher: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 67892295e51ca..62cdd1e50a95d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -106,33 +106,29 @@ g84_cipher_intr_mask[] = { static void g84_cipher_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; struct nvkm_engine *cipher = (void *)subdev; struct nvkm_device *device = cipher->subdev.device; + struct nvkm_fifo *fifo = device->fifo; + struct nvkm_fifo_chan *chan; u32 stat = nvkm_rd32(device, 0x102130); u32 mthd = nvkm_rd32(device, 0x102190); u32 data = nvkm_rd32(device, 0x102194); u32 inst = nvkm_rd32(device, 0x102188) & 0x7fffffff; + unsigned long flags; char msg[128]; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); + chan = nvkm_fifo_chan_inst(fifo, (u64)inst << 12, &flags); if (stat) { nvkm_snprintbf(msg, sizeof(msg), g84_cipher_intr_mask, stat); nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] " "mthd %04x data %08x\n", - stat, msg, chid, (u64)inst << 12, - nvkm_client_name(engctx), mthd, data); + stat, msg, chan ? chan->chid : -1, (u64)inst << 12, + nvkm_client_name(chan), mthd, data); } + nvkm_fifo_chan_put(fifo, flags, &chan); nvkm_wr32(device, 0x102130, stat); nvkm_wr32(device, 0x10200c, 0x10); - - nvkm_engctx_put(engctx); } static int -- GitLab From 6ca307b0c9c7878eb1b2b42982c05671f0591229 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5507/7006] drm/nouveau/fifo: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 34 ++++++++---------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 35 ++++++++----------- 2 files changed, 28 insertions(+), 41 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 9053730aafca3..39031841d057c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -462,17 +462,15 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; - unsigned long flags; nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", nvkm_subdev_name[engine->subdev.index], chid); + assert_spin_locked(&fifo->base.lock); nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); chan->state = KILLED; - spin_lock_irqsave(&fifo->base.lock, flags); fifo->mask |= 1ULL << nv_engidx(engine); - spin_unlock_irqrestore(&fifo->base.lock, flags); schedule_work(&fifo->fault); } @@ -514,8 +512,10 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; struct gf100_fifo_chan *chan; + unsigned long flags; u32 engn; + spin_lock_irqsave(&fifo->base.lock, flags); for (engn = 0; engn < 6; engn++) { u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); @@ -533,6 +533,7 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) gf100_fifo_recover(fifo, engine, chan); } } + spin_unlock_irqrestore(&fifo->base.lock, flags); } static void @@ -630,9 +631,10 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) u32 write = (stat & 0x00000080); u32 hub = (stat & 0x00000040); u32 reason = (stat & 0x0000000f); - struct nvkm_object *engctx = NULL, *object; - struct nvkm_engine *engine = NULL; const struct nvkm_enum *er, *eu, *ec; + struct nvkm_engine *engine = NULL; + struct nvkm_fifo_chan *chan; + unsigned long flags; char gpcid[8] = ""; er = nvkm_enum_find(gf100_fifo_fault_reason, reason); @@ -657,31 +659,23 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) break; default: engine = nvkm_engine(fifo, eu->data2); - if (engine) - engctx = nvkm_engctx_get(engine, inst); break; } } + chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags); + nvkm_error(subdev, "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " "reason %02x [%s] on channel %d [%010llx %s]\n", write ? "write" : "read", (u64)vahi << 32 | valo, unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", - reason, er ? er->name : "", -1, (u64)inst << 12, - nvkm_client_name(engctx)); - - object = engctx; - while (object) { - switch (nv_mclass(object)) { - case FERMI_CHANNEL_GPFIFO: - gf100_fifo_recover(fifo, engine, (void *)object); - break; - } - object = object->parent; - } + reason, er ? er->name : "", chan ? chan->chid : -1, + (u64)inst << 12, nvkm_client_name(chan)); - nvkm_engctx_put(engctx); + if (engine && chan) + gf100_fifo_recover(fifo, engine, (void *)chan); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } static const struct nvkm_bitfield diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 4407f6bbf94fa..3d2b16e7a7ee6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -508,17 +508,15 @@ gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 chid = chan->base.chid; - unsigned long flags; nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", nvkm_subdev_name[nv_subdev(engine)->index], chid); + assert_spin_locked(&fifo->base.lock); nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); chan->state = KILLED; - spin_lock_irqsave(&fifo->base.lock, flags); fifo->mask |= 1ULL << nv_engidx(engine); - spin_unlock_irqrestore(&fifo->base.lock, flags); schedule_work(&fifo->fault); } @@ -584,8 +582,10 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_engine *engine; struct gk104_fifo_chan *chan; + unsigned long flags; u32 engn; + spin_lock_irqsave(&fifo->base.lock, flags); for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); @@ -605,6 +605,7 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) gk104_fifo_recover(fifo, engine, chan); } } + spin_unlock_irqrestore(&fifo->base.lock, flags); } static void @@ -766,9 +767,10 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) u32 write = (stat & 0x00000080); u32 hub = (stat & 0x00000040); u32 reason = (stat & 0x0000000f); - struct nvkm_object *engctx = NULL, *object; - struct nvkm_engine *engine = NULL; const struct nvkm_enum *er, *eu, *ec; + struct nvkm_engine *engine = NULL; + struct nvkm_fifo_chan *chan; + unsigned long flags; char gpcid[8] = ""; er = nvkm_enum_find(gk104_fifo_fault_reason, reason); @@ -793,32 +795,23 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) break; default: engine = nvkm_engine(fifo, eu->data2); - if (engine) - engctx = nvkm_engctx_get(engine, inst); break; } } + chan = nvkm_fifo_chan_inst(&fifo->base, (u64)inst << 12, &flags); + nvkm_error(subdev, "%s fault at %010llx engine %02x [%s] client %02x [%s%s] " "reason %02x [%s] on channel %d [%010llx %s]\n", write ? "write" : "read", (u64)vahi << 32 | valo, unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", - reason, er ? er->name : "", -1, (u64)inst << 12, - nvkm_client_name(engctx)); - - object = engctx; - while (object) { - switch (nv_mclass(object)) { - case KEPLER_CHANNEL_GPFIFO_A: - case MAXWELL_CHANNEL_GPFIFO_A: - gk104_fifo_recover(fifo, engine, (void *)object); - break; - } - object = object->parent; - } + reason, er ? er->name : "", chan ? chan->chid : -1, + (u64)inst << 12, nvkm_client_name(chan)); - nvkm_engctx_put(engctx); + if (engine && chan) + gk104_fifo_recover(fifo, engine, (void *)chan); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = { -- GitLab From a65955e19e769e92a0e29cccdc29aea0b19f3809 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5508/7006] drm/nouveau/gr: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 81 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 2 - .../gpu/drm/nouveau/nvkm/engine/gr/gf108.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf110.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk110.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c | 4 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 787 ++++++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 104 ++- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 21 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 59 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 34 +- 15 files changed, 593 insertions(+), 533 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 362d5fa394d44..c6ff24b5a11df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -26,12 +26,11 @@ #include "fuc/os.h" #include -#include #include -#include #include #include #include +#include #include #include @@ -233,39 +232,39 @@ gf100_fermi_ofuncs = { .mthd = gf100_fermi_mthd, }; -static int -gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd, - void *pdata, u32 size) +static void +gf100_gr_mthd_set_shader_exceptions(struct nvkm_device *device, u32 data) { - struct gf100_gr *gr = (void *)object->engine; - struct nvkm_device *device = gr->base.engine.subdev.device; - if (size >= sizeof(u32)) { - u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000; - nvkm_wr32(device, 0x419e44, data); - nvkm_wr32(device, 0x419e4c, data); - return 0; - } - return -EINVAL; + nvkm_wr32(device, 0x419e44, data ? 0xffffffff : 0x00000000); + nvkm_wr32(device, 0x419e4c, data ? 0xffffffff : 0x00000000); } -struct nvkm_omthds -gf100_gr_9097_omthds[] = { - { 0x1528, 0x1528, gf100_gr_set_shader_exceptions }, - {} -}; - -struct nvkm_omthds -gf100_gr_90c0_omthds[] = { - { 0x1528, 0x1528, gf100_gr_set_shader_exceptions }, - {} -}; +static bool +gf100_gr_mthd_sw(struct nvkm_device *device, u16 class, u32 mthd, u32 data) +{ + switch (class & 0x00ff) { + case 0x97: + case 0xc0: + switch (mthd) { + case 0x1528: + gf100_gr_mthd_set_shader_exceptions(device, data); + return true; + default: + break; + } + break; + default: + break; + } + return false; +} struct nvkm_oclass gf100_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { FERMI_A, &gf100_fermi_ofuncs }, + { FERMI_COMPUTE_A, &nvkm_object_ofuncs }, {} }; @@ -365,7 +364,6 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(image, 0x2c, 0); } nvkm_done(image); - return 0; } @@ -1160,10 +1158,8 @@ gf100_gr_intr(struct nvkm_subdev *subdev) { struct gf100_gr *gr = (void *)subdev; struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle; + struct nvkm_fifo_chan *chan; + unsigned long flags; u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff; u32 stat = nvkm_rd32(device, 0x400100); u32 addr = nvkm_rd32(device, 0x400704); @@ -1174,14 +1170,14 @@ gf100_gr_intr(struct nvkm_subdev *subdev) u32 class; int chid; + chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + chid = chan ? chan->chid : -1; + if (nv_device(gr)->card_type < NV_E0 || subc < 4) class = nvkm_rd32(device, 0x404200 + (subc * 4)); else class = 0x0000; - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); - if (stat & 0x00000001) { /* * notifier interrupt, only needed for cyclestats @@ -1192,14 +1188,12 @@ gf100_gr_intr(struct nvkm_subdev *subdev) } if (stat & 0x00000010) { - handle = nvkm_handle_get_class(engctx, class); - if (!handle || nv_call(handle->object, mthd, data)) { + if (!gf100_gr_mthd_sw(device, class, mthd, data)) { nvkm_error(subdev, "ILLEGAL_MTHD ch %d [%010llx %s] " "subc %d class %04x mthd %04x data %08x\n", - chid, inst << 12, nvkm_client_name(engctx), + chid, inst << 12, nvkm_client_name(chan), subc, class, mthd, data); } - nvkm_handle_put(handle); nvkm_wr32(device, 0x400100, 0x00000010); stat &= ~0x00000010; } @@ -1207,7 +1201,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) if (stat & 0x00000020) { nvkm_error(subdev, "ILLEGAL_CLASS ch %d [%010llx %s] " "subc %d class %04x mthd %04x data %08x\n", - chid, inst << 12, nvkm_client_name(engctx), subc, + chid, inst << 12, nvkm_client_name(chan), subc, class, mthd, data); nvkm_wr32(device, 0x400100, 0x00000020); stat &= ~0x00000020; @@ -1219,15 +1213,14 @@ gf100_gr_intr(struct nvkm_subdev *subdev) nvkm_error(subdev, "DATA_ERROR %08x [%s] ch %d [%010llx %s] " "subc %d class %04x mthd %04x data %08x\n", code, en ? en->name : "", chid, inst << 12, - nvkm_client_name(engctx), subc, class, mthd, data); + nvkm_client_name(chan), subc, class, mthd, data); nvkm_wr32(device, 0x400100, 0x00100000); stat &= ~0x00100000; } if (stat & 0x00200000) { nvkm_error(subdev, "TRAP ch %d [%010llx %s]\n", - chid, inst << 12, - nvkm_client_name(engctx)); + chid, inst << 12, nvkm_client_name(chan)); gf100_gr_trap_intr(gr); nvkm_wr32(device, 0x400100, 0x00200000); stat &= ~0x00200000; @@ -1245,7 +1238,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) } nvkm_wr32(device, 0x400500, 0x00010001); - nvkm_engctx_put(engctx); + nvkm_fifo_chan_put(device->fifo, flags, &chan); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 62bf56906cbe8..612d5346eae90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -152,8 +152,6 @@ int gm204_gr_init(struct nvkm_object *); extern struct nvkm_ofuncs gf100_fermi_ofuncs; extern struct nvkm_oclass gf100_gr_sclass[]; -extern struct nvkm_omthds gf100_gr_9097_omthds[]; -extern struct nvkm_omthds gf100_gr_90c0_omthds[]; extern struct nvkm_oclass gf110_gr_sclass[]; extern struct nvkm_oclass gk110_gr_sclass[]; extern struct nvkm_oclass gm204_gr_sclass[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c index 8df73421c78ca..1e8290ab1d374 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c @@ -34,9 +34,9 @@ static struct nvkm_oclass gf108_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { FERMI_A, &gf100_fermi_ofuncs }, + { FERMI_B, &gf100_fermi_ofuncs }, + { FERMI_COMPUTE_A, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c index ef76e2dd1d31e..4fe0f969de826 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c @@ -34,10 +34,10 @@ struct nvkm_oclass gf110_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { FERMI_A, &gf100_fermi_ofuncs }, + { FERMI_B, &gf100_fermi_ofuncs }, + { FERMI_C, &gf100_fermi_ofuncs }, + { FERMI_COMPUTE_A, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index 94c6ca1d739a9..a00731979698f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -36,8 +36,8 @@ static struct nvkm_oclass gk104_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs }, - { KEPLER_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { KEPLER_A, &gf100_fermi_ofuncs }, + { KEPLER_COMPUTE_A, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c index f4cd8e5546af4..ec21f62e72486 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c @@ -36,8 +36,8 @@ struct nvkm_oclass gk110_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { KEPLER_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { KEPLER_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { KEPLER_B, &gf100_fermi_ofuncs }, + { KEPLER_COMPUTE_B, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index a80fda50719aa..c213e9a005c6a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -29,8 +29,8 @@ static struct nvkm_oclass gk20a_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs }, - { KEPLER_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { KEPLER_C, &gf100_fermi_ofuncs }, + { KEPLER_COMPUTE_A, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index 97b0e1ad040f5..aad5fdb29c60a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -37,8 +37,8 @@ static struct nvkm_oclass gm107_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { MAXWELL_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { MAXWELL_A, &gf100_fermi_ofuncs }, + { MAXWELL_COMPUTE_A, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index 0a8d850051eee..39f42a1c2b789 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -34,8 +34,8 @@ struct nvkm_oclass gm204_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { MAXWELL_B, &gf100_fermi_ofuncs }, + { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c index 719ebfb6e6404..87388926efa65 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -29,8 +29,8 @@ static struct nvkm_oclass gm20b_gr_sclass[] = { { FERMI_TWOD_A, &nvkm_object_ofuncs }, { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds }, - { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds }, + { MAXWELL_B, &gf100_fermi_ofuncs }, + { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 617161e4fc15d..b15b86478c4fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -25,7 +25,6 @@ #include "regs.h" #include -#include #include #include #include @@ -443,42 +442,34 @@ nv04_gr(struct nv04_gr_chan *chan) */ static void -nv04_gr_set_ctx1(struct nvkm_object *obj, u32 mask, u32 value) +nv04_gr_set_ctx1(struct nvkm_device *device, u32 inst, u32 mask, u32 value) { - struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object); - struct nv04_gr *gr = (void *)object->object.engine; - struct nvkm_device *device = gr->base.engine.subdev.device; int subc = (nvkm_rd32(device, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7; u32 tmp; - nvkm_kmap(object); - tmp = nvkm_ro32(object, 0x00); + tmp = nvkm_rd32(device, 0x700000 + inst); tmp &= ~mask; tmp |= value; - nvkm_wo32(object, 0x00, tmp); - nvkm_done(object); + nvkm_wr32(device, 0x700000 + inst, tmp); nvkm_wr32(device, NV04_PGRAPH_CTX_SWITCH1, tmp); - nvkm_wr32(device, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp); + nvkm_wr32(device, NV04_PGRAPH_CTX_CACHE1 + (subc << 2), tmp); } static void -nv04_gr_set_ctx_val(struct nvkm_object *obj, u32 mask, u32 value) +nv04_gr_set_ctx_val(struct nvkm_device *device, u32 inst, u32 mask, u32 value) { - struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object); int class, op, valid = 1; u32 tmp, ctx1; - nvkm_kmap(object); - ctx1 = nvkm_ro32(object, 0x00); + ctx1 = nvkm_rd32(device, 0x700000 + inst); class = ctx1 & 0xff; op = (ctx1 >> 15) & 7; - tmp = nvkm_ro32(object, 0x0c); + tmp = nvkm_rd32(device, 0x70000c + inst); tmp &= ~mask; tmp |= value; - nvkm_wo32(object, 0x0c, tmp); - nvkm_done(object); + nvkm_wr32(device, 0x70000c + inst, tmp); /* check for valid surf2d/surf_dst/surf_color */ if (!(tmp & 0x02000000)) @@ -510,39 +501,32 @@ nv04_gr_set_ctx_val(struct nvkm_object *obj, u32 mask, u32 value) break; } - nv04_gr_set_ctx1(obj, 0x01000000, valid << 24); + nv04_gr_set_ctx1(device, inst, 0x01000000, valid << 24); } -static int -nv04_gr_mthd_set_operation(struct nvkm_object *obj, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_set_operation(struct nvkm_device *device, u32 inst, u32 data) { - struct nvkm_gpuobj *object = container_of(obj, typeof(*object), object); - u32 class = nvkm_ro32(object, 0) & 0xff; - u32 data = *(u32 *)args; + u8 class = nvkm_rd32(device, 0x700000) & 0x000000ff; if (data > 5) - return 1; + return false; /* Old versions of the objects only accept first three operations. */ if (data > 2 && class < 0x40) - return 1; - nv04_gr_set_ctx1(obj, 0x00038000, data << 15); + return false; + nv04_gr_set_ctx1(device, inst, 0x00038000, data << 15); /* changing operation changes set of objects needed for validation */ - nv04_gr_set_ctx_val(obj, 0, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0, 0); + return true; } -static int -nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_surf3d_clip_h(struct nvkm_device *device, u32 inst, u32 data) { - struct nv04_gr *gr = (void *)object->engine; - struct nvkm_device *device = gr->base.engine.subdev.device; - u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; if (min & 0x8000) /* too large */ - return 1; + return false; if (w & 0x8000) /* yes, it accepts negative for some reason. */ w |= 0xffff0000; @@ -550,21 +534,17 @@ nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd, max &= 0x3ffff; nvkm_wr32(device, 0x40053c, min); nvkm_wr32(device, 0x400544, max); - return 0; + return true; } -static int -nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_surf3d_clip_v(struct nvkm_device *device, u32 inst, u32 data) { - struct nv04_gr *gr = (void *)object->engine; - struct nvkm_device *device = gr->base.engine.subdev.device; - u32 data = *(u32 *)args; u32 min = data & 0xffff, max; u32 w = data >> 16; if (min & 0x8000) /* too large */ - return 1; + return false; if (w & 0x8000) /* yes, it accepts negative for some reason. */ w |= 0xffff0000; @@ -572,389 +552,492 @@ nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd, max &= 0x3ffff; nvkm_wr32(device, 0x400540, min); nvkm_wr32(device, 0x400548, max); - return 0; + return true; } -static u16 -nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size) +static u8 +nv04_gr_mthd_bind_class(struct nvkm_device *device, u32 inst) { - struct nvkm_instmem *imem = nvkm_instmem(object); - u32 inst = *(u32 *)args << 4; - return imem->func->rd32(imem, inst); + return nvkm_rd32(device, 0x700000 + (inst << 4)); } -static int -nv04_gr_mthd_bind_surf2d(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf2d(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x42: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x42: - nv04_gr_set_ctx1(object, 0x00004000, 0); - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; case 0x52: - nv04_gr_set_ctx1(object, 0x00004000, 0x00004000); - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x00004000, 0x00004000); + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv01_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv01_gr_mthd_bind_patt(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x08000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0); + return true; case 0x18: - nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0x08000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_patt(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x08000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0); + return true; case 0x44: - nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x08000000, 0x08000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_rop(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_rop(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x10000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x10000000, 0); + return true; case 0x43: - nv04_gr_set_ctx_val(object, 0x10000000, 0x10000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x10000000, 0x10000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_beta1(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_beta1(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x20000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x20000000, 0); + return true; case 0x12: - nv04_gr_set_ctx_val(object, 0x20000000, 0x20000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x20000000, 0x20000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_beta4(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_beta4(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x40000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x40000000, 0); + return true; case 0x72: - nv04_gr_set_ctx_val(object, 0x40000000, 0x40000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x40000000, 0x40000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_dst(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_dst(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x58: - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_src(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_src(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x04000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0); + return true; case 0x59: - nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0x04000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_color(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_color(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x02000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0); + return true; case 0x5a: - nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x02000000, 0x02000000); + return true; } - return 1; + return false; } -static int -nv04_gr_mthd_bind_surf_zeta(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv04_gr_mthd_bind_surf_zeta(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx_val(object, 0x04000000, 0); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0); + return true; case 0x5b: - nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000); - return 0; + nv04_gr_set_ctx_val(device, inst, 0x04000000, 0x04000000); + return true; } - return 1; + return false; } -static int -nv01_gr_mthd_bind_clip(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv01_gr_mthd_bind_clip(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x2000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x2000, 0); + return true; case 0x19: - nv04_gr_set_ctx1(object, 0x2000, 0x2000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x2000, 0x2000); + return true; } - return 1; + return false; } -static int -nv01_gr_mthd_bind_chroma(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static bool +nv01_gr_mthd_bind_chroma(struct nvkm_device *device, u32 inst, u32 data) { - switch (nv04_gr_mthd_bind_class(object, args, size)) { + switch (nv04_gr_mthd_bind_class(device, data)) { case 0x30: - nv04_gr_set_ctx1(object, 0x1000, 0); - return 0; + nv04_gr_set_ctx1(device, inst, 0x1000, 0); + return true; /* Yes, for some reason even the old versions of objects * accept 0x57 and not 0x17. Consistency be damned. */ case 0x57: - nv04_gr_set_ctx1(object, 0x1000, 0x1000); - return 0; + nv04_gr_set_ctx1(device, inst, 0x1000, 0x1000); + return true; } - return 1; + return false; } -static struct nvkm_omthds -nv03_gr_gdi_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_patt }, - { 0x0188, 0x0188, nv04_gr_mthd_bind_rop }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_beta1 }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_gdi(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_patt; break; + case 0x0188: func = nv04_gr_mthd_bind_rop; break; + case 0x018c: func = nv04_gr_mthd_bind_beta1; break; + case 0x0190: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_gdi_omthds[] = { - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_gdi(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv01_gr_blit_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv01_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_surf_src }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv01_gr_mthd_blit(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv01_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x019c: func = nv04_gr_mthd_bind_surf_src; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_blit_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_blit(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv04_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_beta4; break; + case 0x019c: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_iifc_omthds[] = { - { 0x0188, 0x0188, nv01_gr_mthd_bind_chroma }, - { 0x018c, 0x018c, nv01_gr_mthd_bind_clip }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_patt }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_rop }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_beta1 }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_beta4 }, - { 0x01a0, 0x01a0, nv04_gr_mthd_bind_surf2d_swzsurf }, - { 0x03e4, 0x03e4, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_iifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv01_gr_mthd_bind_chroma; break; + case 0x018c: func = nv01_gr_mthd_bind_clip; break; + case 0x0190: func = nv04_gr_mthd_bind_patt; break; + case 0x0194: func = nv04_gr_mthd_bind_rop; break; + case 0x0198: func = nv04_gr_mthd_bind_beta1; break; + case 0x019c: func = nv04_gr_mthd_bind_beta4; break; + case 0x01a0: func = nv04_gr_mthd_bind_surf2d_swzsurf; break; + case 0x03e4: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv01_gr_ifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv01_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv01_gr_mthd_ifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv01_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_ifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_patt }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_rop }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 }, - { 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_ifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv04_gr_mthd_bind_patt; break; + case 0x0190: func = nv04_gr_mthd_bind_rop; break; + case 0x0194: func = nv04_gr_mthd_bind_beta1; break; + case 0x0198: func = nv04_gr_mthd_bind_beta4; break; + case 0x019c: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv03_gr_sifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_sifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv01_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_sifc_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma }, - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_sifc(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_chroma; break; + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv03_gr_sifm_omthds[] = { - { 0x0188, 0x0188, nv01_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst }, - { 0x0304, 0x0304, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv03_gr_mthd_sifm(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv01_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x0304: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_sifm_omthds[] = { - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x0304, 0x0304, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_sifm(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x0304: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_surf3d_omthds[] = { - { 0x02f8, 0x02f8, nv04_gr_mthd_surf3d_clip_h }, - { 0x02fc, 0x02fc, nv04_gr_mthd_surf3d_clip_v }, - {} -}; +static bool +nv04_gr_mthd_surf3d(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x02f8: func = nv04_gr_mthd_surf3d_clip_h; break; + case 0x02fc: func = nv04_gr_mthd_surf3d_clip_v; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv03_gr_ttri_omthds[] = { - { 0x0188, 0x0188, nv01_gr_mthd_bind_clip }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_surf_color }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_surf_zeta }, - {} -}; +static bool +nv03_gr_mthd_ttri(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0188: func = nv01_gr_mthd_bind_clip; break; + case 0x018c: func = nv04_gr_mthd_bind_surf_color; break; + case 0x0190: func = nv04_gr_mthd_bind_surf_zeta; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv01_gr_prim_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_clip }, - { 0x0188, 0x0188, nv01_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv01_gr_mthd_prim(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_clip; break; + case 0x0188: func = nv01_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_surf_dst; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} -static struct nvkm_omthds -nv04_gr_prim_omthds[] = { - { 0x0184, 0x0184, nv01_gr_mthd_bind_clip }, - { 0x0188, 0x0188, nv04_gr_mthd_bind_patt }, - { 0x018c, 0x018c, nv04_gr_mthd_bind_rop }, - { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 }, - { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 }, - { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d }, - { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation }, - {} -}; +static bool +nv04_gr_mthd_prim(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32); + switch (mthd) { + case 0x0184: func = nv01_gr_mthd_bind_clip; break; + case 0x0188: func = nv04_gr_mthd_bind_patt; break; + case 0x018c: func = nv04_gr_mthd_bind_rop; break; + case 0x0190: func = nv04_gr_mthd_bind_beta1; break; + case 0x0194: func = nv04_gr_mthd_bind_beta4; break; + case 0x0198: func = nv04_gr_mthd_bind_surf2d; break; + case 0x02fc: func = nv04_gr_mthd_set_operation; break; + default: + return false; + } + return func(device, inst, data); +} + +static bool +nv04_gr_mthd(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) +{ + bool (*func)(struct nvkm_device *, u32, u32, u32); + switch (nvkm_rd32(device, 0x700000 + inst) & 0x000000ff) { + case 0x1c ... 0x1e: + func = nv01_gr_mthd_prim; break; + case 0x1f: func = nv01_gr_mthd_blit; break; + case 0x21: func = nv01_gr_mthd_ifc; break; + case 0x36: func = nv03_gr_mthd_sifc; break; + case 0x37: func = nv03_gr_mthd_sifm; break; + case 0x48: func = nv03_gr_mthd_ttri; break; + case 0x4a: func = nv04_gr_mthd_gdi; break; + case 0x4b: func = nv03_gr_mthd_gdi; break; + case 0x53: func = nv04_gr_mthd_surf3d; break; + case 0x5c ... 0x5e: + func = nv04_gr_mthd_prim; break; + case 0x5f: func = nv04_gr_mthd_blit; break; + case 0x60: func = nv04_gr_mthd_iifc; break; + case 0x61: func = nv04_gr_mthd_ifc; break; + case 0x76: func = nv04_gr_mthd_sifc; break; + case 0x77: func = nv04_gr_mthd_sifm; break; + default: + return false; + } + return func(device, inst, mthd, data); +} static int nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -998,24 +1081,24 @@ nv04_gr_sclass[] = { { 0x0017, &nv04_gr_ofuncs }, /* chroma */ { 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */ { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x001c, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* line */ - { 0x001d, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* tri */ - { 0x001e, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* rect */ - { 0x001f, &nv04_gr_ofuncs, nv01_gr_blit_omthds }, - { 0x0021, &nv04_gr_ofuncs, nv01_gr_ifc_omthds }, + { 0x001c, &nv04_gr_ofuncs }, /* line */ + { 0x001d, &nv04_gr_ofuncs }, /* tri */ + { 0x001e, &nv04_gr_ofuncs }, /* rect */ + { 0x001f, &nv04_gr_ofuncs }, + { 0x0021, &nv04_gr_ofuncs }, { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0036, &nv04_gr_ofuncs, nv03_gr_sifc_omthds }, - { 0x0037, &nv04_gr_ofuncs, nv03_gr_sifm_omthds }, + { 0x0036, &nv04_gr_ofuncs }, + { 0x0037, &nv04_gr_ofuncs }, { 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */ { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ { 0x0042, &nv04_gr_ofuncs }, /* surf2d */ { 0x0043, &nv04_gr_ofuncs }, /* rop */ { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x0048, &nv04_gr_ofuncs, nv03_gr_ttri_omthds }, - { 0x004a, &nv04_gr_ofuncs, nv04_gr_gdi_omthds }, - { 0x004b, &nv04_gr_ofuncs, nv03_gr_gdi_omthds }, + { 0x0048, &nv04_gr_ofuncs }, + { 0x004a, &nv04_gr_ofuncs }, + { 0x004b, &nv04_gr_ofuncs }, { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x0053, &nv04_gr_ofuncs, nv04_gr_surf3d_omthds }, + { 0x0053, &nv04_gr_ofuncs }, { 0x0054, &nv04_gr_ofuncs }, /* ttri */ { 0x0055, &nv04_gr_ofuncs }, /* mtri */ { 0x0057, &nv04_gr_ofuncs }, /* chroma */ @@ -1023,18 +1106,18 @@ nv04_gr_sclass[] = { { 0x0059, &nv04_gr_ofuncs }, /* surf_src */ { 0x005a, &nv04_gr_ofuncs }, /* surf_color */ { 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */ - { 0x005c, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* line */ - { 0x005d, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* tri */ - { 0x005e, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* rect */ - { 0x005f, &nv04_gr_ofuncs, nv04_gr_blit_omthds }, - { 0x0060, &nv04_gr_ofuncs, nv04_gr_iifc_omthds }, - { 0x0061, &nv04_gr_ofuncs, nv04_gr_ifc_omthds }, + { 0x005c, &nv04_gr_ofuncs }, /* line */ + { 0x005d, &nv04_gr_ofuncs }, /* tri */ + { 0x005e, &nv04_gr_ofuncs }, /* rect */ + { 0x005f, &nv04_gr_ofuncs }, + { 0x0060, &nv04_gr_ofuncs }, + { 0x0061, &nv04_gr_ofuncs }, { 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */ { 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */ { 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */ { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0076, &nv04_gr_ofuncs, nv04_gr_sifc_omthds }, - { 0x0077, &nv04_gr_ofuncs, nv04_gr_sifm_omthds }, + { 0x0076, &nv04_gr_ofuncs }, + { 0x0077, &nv04_gr_ofuncs }, {}, }; @@ -1092,10 +1175,8 @@ nv04_gr_context_switch(struct nv04_gr *gr) struct nvkm_device *device = gr->base.engine.subdev.device; struct nv04_gr_chan *prev = NULL; struct nv04_gr_chan *next = NULL; - unsigned long flags; int chid; - spin_lock_irqsave(&gr->lock, flags); nv04_gr_idle(gr); /* If previous context is valid, we need to save it */ @@ -1108,8 +1189,6 @@ nv04_gr_context_switch(struct nv04_gr *gr) next = gr->chan[chid]; if (next) nv04_gr_load_context(next, chid); - - spin_unlock_irqrestore(&gr->lock, flags); } static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg) @@ -1272,8 +1351,6 @@ nv04_gr_intr(struct nvkm_subdev *subdev) { struct nv04_gr *gr = (void *)subdev; struct nv04_gr_chan *chan = NULL; - struct nvkm_namedb *namedb = NULL; - struct nvkm_handle *handle = NULL; struct nvkm_device *device = gr->base.engine.subdev.device; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); @@ -1291,14 +1368,10 @@ nv04_gr_intr(struct nvkm_subdev *subdev) spin_lock_irqsave(&gr->lock, flags); chan = gr->chan[chid]; - if (chan) - namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); - spin_unlock_irqrestore(&gr->lock, flags); if (stat & NV_PGRAPH_INTR_NOTIFY) { if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { - handle = nvkm_namedb_get_vinst(namedb, inst); - if (handle && !nv_call(handle->object, mthd, data)) + if (!nv04_gr_mthd(device, inst, mthd, data)) show &= ~NV_PGRAPH_INTR_NOTIFY; } } @@ -1324,7 +1397,7 @@ nv04_gr_intr(struct nvkm_subdev *subdev) nvkm_client_name(chan), subc, class, mthd, data); } - nvkm_namedb_put(handle); + spin_unlock_irqrestore(&gr->lock, flags); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index be92015d8f9e0..8f0c62d56d9df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -25,7 +25,6 @@ #include "regs.h" #include -#include #include #include @@ -473,40 +472,37 @@ nv15_gr_sclass[] = { {}, }; -static int -nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static void +nv17_gr_mthd_lma_window(struct nv10_gr_chan *chan, u32 mthd, u32 data) { - struct nv10_gr_chan *chan = (void *)object->parent; - struct nv10_gr *gr = nv10_gr(chan); + struct nvkm_device *device = chan->base.engine->subdev.device; + struct nvkm_gr *gr = nvkm_gr(chan); struct pipe_state *pipe = &chan->pipe_state; - struct nvkm_device *device = gr->base.engine.subdev.device; u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; u32 xfmode0, xfmode1; - u32 data = *(u32 *)args; int i; chan->lma_window[(mthd - 0x1638) / 4] = data; if (mthd != 0x1644) - return 0; + return; nv04_gr_idle(gr); - PIPE_SAVE(gr, pipe_0x0040, 0x0040); - PIPE_SAVE(gr, pipe->pipe_0x0200, 0x0200); + PIPE_SAVE(device, pipe_0x0040, 0x0040); + PIPE_SAVE(device, pipe->pipe_0x0200, 0x0200); - PIPE_RESTORE(gr, chan->lma_window, 0x6790); + PIPE_RESTORE(device, chan->lma_window, 0x6790); nv04_gr_idle(gr); xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0); xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1); - PIPE_SAVE(gr, pipe->pipe_0x4400, 0x4400); - PIPE_SAVE(gr, pipe_0x64c0, 0x64c0); - PIPE_SAVE(gr, pipe_0x6ab0, 0x6ab0); - PIPE_SAVE(gr, pipe_0x6a80, 0x6a80); + PIPE_SAVE(device, pipe->pipe_0x4400, 0x4400); + PIPE_SAVE(device, pipe_0x64c0, 0x64c0); + PIPE_SAVE(device, pipe_0x6ab0, 0x6ab0); + PIPE_SAVE(device, pipe_0x6a80, 0x6a80); nv04_gr_idle(gr); @@ -529,52 +525,64 @@ nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd, nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040); nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000008); - PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); + PIPE_RESTORE(device, pipe->pipe_0x0200, 0x0200); nv04_gr_idle(gr); - PIPE_RESTORE(gr, pipe_0x0040, 0x0040); + PIPE_RESTORE(device, pipe_0x0040, 0x0040); nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0); nvkm_wr32(device, NV10_PGRAPH_XFMODE1, xfmode1); - PIPE_RESTORE(gr, pipe_0x64c0, 0x64c0); - PIPE_RESTORE(gr, pipe_0x6ab0, 0x6ab0); - PIPE_RESTORE(gr, pipe_0x6a80, 0x6a80); - PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400); + PIPE_RESTORE(device, pipe_0x64c0, 0x64c0); + PIPE_RESTORE(device, pipe_0x6ab0, 0x6ab0); + PIPE_RESTORE(device, pipe_0x6a80, 0x6a80); + PIPE_RESTORE(device, pipe->pipe_0x4400, 0x4400); nvkm_wr32(device, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0); nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, 0x00000000); nv04_gr_idle(gr); - - return 0; } -static int -nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd, - void *args, u32 size) +static void +nv17_gr_mthd_lma_enable(struct nv10_gr_chan *chan, u32 mthd, u32 data) { - struct nv10_gr_chan *chan = (void *)object->parent; - struct nv10_gr *gr = nv10_gr(chan); - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_device *device = chan->base.engine->subdev.device; + struct nvkm_gr *gr = nvkm_gr(chan); nv04_gr_idle(gr); nvkm_mask(device, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100); nvkm_mask(device, 0x4006b0, 0x08000000, 0x08000000); - return 0; } -static struct nvkm_omthds -nv17_celcius_omthds[] = { - { 0x1638, 0x1638, nv17_gr_mthd_lma_window }, - { 0x163c, 0x163c, nv17_gr_mthd_lma_window }, - { 0x1640, 0x1640, nv17_gr_mthd_lma_window }, - { 0x1644, 0x1644, nv17_gr_mthd_lma_window }, - { 0x1658, 0x1658, nv17_gr_mthd_lma_enable }, - {} -}; +static bool +nv17_gr_mthd_celcius(struct nv10_gr_chan *chan, u32 mthd, u32 data) +{ + void (*func)(struct nv10_gr_chan *, u32, u32); + switch (mthd) { + case 0x1638 ... 0x1644: + func = nv17_gr_mthd_lma_window; break; + case 0x1658: func = nv17_gr_mthd_lma_enable; break; + default: + return false; + } + func(chan, mthd, data); + return true; +} + +static bool +nv10_gr_mthd(struct nv10_gr_chan *chan, u8 class, u32 mthd, u32 data) +{ + bool (*func)(struct nv10_gr_chan *, u32, u32); + switch (class) { + case 0x99: func = nv17_gr_mthd_celcius; break; + default: + return false; + } + return func(chan, mthd, data); +} static struct nvkm_oclass nv17_gr_sclass[] = { @@ -595,7 +603,7 @@ nv17_gr_sclass[] = { { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ { 0x0094, &nv04_gr_ofuncs }, /* ttri */ { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0099, &nv04_gr_ofuncs, nv17_celcius_omthds }, + { 0x0099, &nv04_gr_ofuncs }, {}, }; @@ -996,10 +1004,8 @@ nv10_gr_context_switch(struct nv10_gr *gr) struct nvkm_device *device = gr->base.engine.subdev.device; struct nv10_gr_chan *prev = NULL; struct nv10_gr_chan *next = NULL; - unsigned long flags; int chid; - spin_lock_irqsave(&gr->lock, flags); nv04_gr_idle(gr); /* If previous context is valid, we need to save it */ @@ -1012,8 +1018,6 @@ nv10_gr_context_switch(struct nv10_gr *gr) next = gr->chan[chid]; if (next) nv10_gr_load_context(next, chid); - - spin_unlock_irqrestore(&gr->lock, flags); } #define NV_WRITE_CTX(reg, val) do { \ @@ -1167,8 +1171,6 @@ nv10_gr_intr(struct nvkm_subdev *subdev) { struct nv10_gr *gr = (void *)subdev; struct nv10_gr_chan *chan = NULL; - struct nvkm_namedb *namedb = NULL; - struct nvkm_handle *handle = NULL; struct nvkm_device *device = gr->base.engine.subdev.device; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); @@ -1185,14 +1187,10 @@ nv10_gr_intr(struct nvkm_subdev *subdev) spin_lock_irqsave(&gr->lock, flags); chan = gr->chan[chid]; - if (chan) - namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS); - spin_unlock_irqrestore(&gr->lock, flags); if (stat & NV_PGRAPH_INTR_ERROR) { if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) { - handle = nvkm_namedb_get_class(namedb, class); - if (handle && !nv_call(handle->object, mthd, data)) + if (!nv10_gr_mthd(chan, class, mthd, data)) show &= ~NV_PGRAPH_INTR_ERROR; } } @@ -1218,7 +1216,7 @@ nv10_gr_intr(struct nvkm_subdev *subdev) nvkm_client_name(chan), subc, class, mthd, data); } - nvkm_namedb_put(handle); + spin_unlock_irqrestore(&gr->lock, flags); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 6e5b321128a6b..a33ed6121d7f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -2,7 +2,6 @@ #include "regs.h" #include -#include #include #include #include @@ -145,6 +144,7 @@ nv20_gr_context_fini(struct nvkm_object *object, bool suspend) nvkm_kmap(gr->ctxtab); nvkm_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); nvkm_done(gr->ctxtab); + return nvkm_gr_context_fini(&chan->base, suspend); } @@ -200,11 +200,9 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) void nv20_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle; struct nv20_gr *gr = (void *)subdev; struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo_chan *chan; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); @@ -216,16 +214,9 @@ nv20_gr_intr(struct nvkm_subdev *subdev) u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; char msg[128], src[128], sta[128]; + unsigned long flags; - engctx = nvkm_engctx_get(engine, chid); - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - handle = nvkm_handle_get_class(engctx, class); - if (handle && !nv_call(handle->object, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - nvkm_handle_put(handle); - } - } + chan = nvkm_fifo_chan_chid(device->fifo, chid, &flags); nvkm_wr32(device, NV03_PGRAPH_INTR, stat); nvkm_wr32(device, NV04_PGRAPH_FIFO, 0x00000001); @@ -238,10 +229,10 @@ nv20_gr_intr(struct nvkm_subdev *subdev) "nstatus %08x [%s] ch %d [%s] subc %d " "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, chid, - nvkm_client_name(engctx), subc, class, mthd, data); + nvkm_client_name(chan), subc, class, mthd, data); } - nvkm_engctx_put(engctx); + nvkm_fifo_chan_put(device->fifo, flags, &chan); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 1ebf2edef4d40..4db2a17f5308b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -25,7 +25,6 @@ #include "regs.h" #include -#include #include #include #include @@ -33,10 +32,14 @@ struct nv40_gr { struct nvkm_gr base; u32 size; + struct list_head chan; }; struct nv40_gr_chan { struct nvkm_gr_chan base; + struct nvkm_fifo_chan *fifo; + u32 inst; + struct list_head head; }; static u64 @@ -132,6 +135,16 @@ nv44_gr_sclass[] = { * PGRAPH context ******************************************************************************/ +static void +nv40_gr_context_dtor(struct nvkm_object *object) +{ + struct nv40_gr_chan *chan = (void *)object; + unsigned long flags; + spin_lock_irqsave(&object->engine->lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&object->engine->lock, flags); +} + static int nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -139,6 +152,7 @@ nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, { struct nv40_gr *gr = (void *)engine; struct nv40_gr_chan *chan; + unsigned long flags; int ret; ret = nvkm_gr_context_create(parent, engine, oclass, NULL, gr->size, @@ -149,6 +163,12 @@ nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv40_grctx_fill(nv_device(gr), nv_gpuobj(chan)); nvkm_wo32(&chan->base.base.gpuobj, 0x00000, nv_gpuobj(chan)->addr >> 4); + + spin_lock_irqsave(&gr->base.engine.lock, flags); + chan->fifo = (void *)parent; + chan->inst = chan->base.base.gpuobj.addr; + list_add(&chan->head, &gr->chan); + spin_unlock_irqrestore(&gr->base.engine.lock, flags); return 0; } @@ -195,7 +215,7 @@ nv40_gr_cclass = { .handle = NV_ENGCTX(GR, 0x40), .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv40_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, + .dtor = nv40_gr_context_dtor, .init = _nvkm_gr_context_init, .fini = nv40_gr_context_fini, .rd32 = _nvkm_gr_context_rd32, @@ -289,11 +309,8 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) static void nv40_gr_intr(struct nvkm_subdev *subdev) { - struct nvkm_fifo *fifo = nvkm_fifo(subdev); - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle = NULL; struct nv40_gr *gr = (void *)subdev; + struct nv40_gr_chan *temp, *chan = NULL; struct nvkm_device *device = gr->base.engine.subdev.device; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); @@ -306,19 +323,19 @@ nv40_gr_intr(struct nvkm_subdev *subdev) u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xffff; u32 show = stat; char msg[128], src[128], sta[128]; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); + unsigned long flags; - if (stat & NV_PGRAPH_INTR_ERROR) { - if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) { - handle = nvkm_handle_get_class(engctx, class); - if (handle && !nv_call(handle->object, mthd, data)) - show &= ~NV_PGRAPH_INTR_ERROR; - nvkm_handle_put(handle); + spin_lock_irqsave(&gr->base.engine.lock, flags); + list_for_each_entry(temp, &gr->chan, head) { + if (temp->inst >> 4 == inst) { + chan = temp; + list_del(&chan->head); + list_add(&chan->head, &gr->chan); + break; } + } + if (stat & NV_PGRAPH_INTR_ERROR) { if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) { nvkm_mask(device, 0x402000, 0, 0); } @@ -334,12 +351,12 @@ nv40_gr_intr(struct nvkm_subdev *subdev) nvkm_error(subdev, "intr %08x [%s] nsource %08x [%s] " "nstatus %08x [%s] ch %d [%08x %s] subc %d " "class %04x mthd %04x data %08x\n", - show, msg, nsource, src, nstatus, sta, chid, - inst << 4, nvkm_client_name(engctx), subc, - class, mthd, data); + show, msg, nsource, src, nstatus, sta, + chan ? chan->fifo->chid : -1, inst << 4, + nvkm_client_name(chan), subc, class, mthd, data); } - nvkm_engctx_put(engctx); + spin_unlock_irqrestore(&gr->base.engine.lock, flags); } static int @@ -355,6 +372,8 @@ nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + INIT_LIST_HEAD(&gr->chan); + nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv40_gr_intr; nv_engine(gr)->cclass = &nv40_gr_cclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index c50cfe4875ef2..daac54075705f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -24,9 +24,8 @@ #include "nv50.h" #include -#include -#include #include +#include struct nv50_gr { struct nvkm_gr base; @@ -609,7 +608,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, static int nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, - int chid, u64 inst, struct nvkm_object *engctx) + int chid, u64 inst, struct nvkm_fifo_chan *chan) { struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; @@ -649,8 +648,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, "ch %d [%010llx %s] subc %d " "class %04x mthd %04x data %08x%08x " "400808 %08x 400848 %08x\n", - chid, inst, - nvkm_client_name(engctx), + chid, inst, nvkm_client_name(chan), subc, class, mthd, datah, datal, addr, r848); } else @@ -677,7 +675,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, "ch %d [%010llx %s] subc %d " "class %04x mthd %04x data %08x " "40084c %08x\n", chid, inst, - nvkm_client_name(engctx), subc, + nvkm_client_name(chan), subc, class, mthd, data, addr); } else if (display) { @@ -840,10 +838,7 @@ nv50_gr_intr(struct nvkm_subdev *subdev) { struct nv50_gr *gr = (void *)subdev; struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle = NULL; + struct nvkm_fifo_chan *chan; u32 stat = nvkm_rd32(device, 0x400100); u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff; u32 addr = nvkm_rd32(device, 0x400704); @@ -853,18 +848,12 @@ nv50_gr_intr(struct nvkm_subdev *subdev) u32 class = nvkm_rd32(device, 0x400814); u32 show = stat, show_bitfield = stat; const struct nvkm_enum *en; + unsigned long flags; char msg[128]; int chid; - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); - - if (stat & 0x00000010) { - handle = nvkm_handle_get_class(engctx, class); - if (handle && !nv_call(handle->object, mthd, data)) - show &= ~0x00000010; - nvkm_handle_put(handle); - } + chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); + chid = chan ? chan->chid : -1; if (show & 0x00100000) { u32 ecode = nvkm_rd32(device, 0x400110); @@ -875,8 +864,7 @@ nv50_gr_intr(struct nvkm_subdev *subdev) } if (stat & 0x00200000) { - if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12, - engctx)) + if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12, chan)) show &= ~0x00200000; show_bitfield &= ~0x00200000; } @@ -890,13 +878,13 @@ nv50_gr_intr(struct nvkm_subdev *subdev) nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] subc %d " "class %04x mthd %04x data %08x\n", stat, msg, chid, (u64)inst << 12, - nvkm_client_name(engctx), subc, class, mthd, data); + nvkm_client_name(chan), subc, class, mthd, data); } if (nvkm_rd32(device, 0x400824) & (1 << 31)) nvkm_wr32(device, 0x400824, nvkm_rd32(device, 0x400824) & ~(1 << 31)); - nvkm_engctx_put(engctx); + nvkm_fifo_chan_put(device->fifo, flags, &chan); } static int -- GitLab From 590801c1a3b19883b0d0e4c60241cbed8a916d47 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5509/7006] drm/nouveau/mpeg: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 76 ++++++++-------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h | 3 + .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 25 ++---- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 90 ++++++++++++++----- 4 files changed, 118 insertions(+), 76 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 0f02b281f34e0..05597f2070ed7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -24,9 +24,6 @@ #include "nv31.h" #include -#include -#include -#include #include #include @@ -58,44 +55,58 @@ nv31_mpeg_object_ctor(struct nvkm_object *parent, return 0; } -static int -nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) +static bool +nv31_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) { - struct nv31_mpeg *mpeg = (void *)object->engine; - struct nvkm_device *device = mpeg->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - u32 inst = *(u32 *)arg << 4; - u32 dma0 = imem->func->rd32(imem, inst + 0); - u32 dma1 = imem->func->rd32(imem, inst + 4); - u32 dma2 = imem->func->rd32(imem, inst + 8); + u32 inst = data << 4; + u32 dma0 = nvkm_rd32(device, 0x700000 + inst); + u32 dma1 = nvkm_rd32(device, 0x700004 + inst); + u32 dma2 = nvkm_rd32(device, 0x700008 + inst); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; /* only allow linear DMA objects */ if (!(dma0 & 0x00002000)) - return -EINVAL; + return false; if (mthd == 0x0190) { /* DMA_CMD */ - nvkm_mask(device, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0); + nvkm_mask(device, 0x00b300, 0x00010000, + (dma0 & 0x00030000) ? 0x00010000 : 0); nvkm_wr32(device, 0x00b334, base); nvkm_wr32(device, 0x00b324, size); } else if (mthd == 0x01a0) { /* DMA_DATA */ - nvkm_mask(device, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0); + nvkm_mask(device, 0x00b300, 0x00020000, + (dma0 & 0x00030000) ? 0x00020000 : 0); nvkm_wr32(device, 0x00b360, base); nvkm_wr32(device, 0x00b364, size); } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) - return -EINVAL; + return false; nvkm_wr32(device, 0x00b370, base); nvkm_wr32(device, 0x00b374, size); } - return 0; + return true; +} + +static bool +nv31_mpeg_mthd(struct nv31_mpeg *mpeg, u32 mthd, u32 data) +{ + struct nvkm_device *device = mpeg->base.engine.subdev.device; + switch (mthd) { + case 0x190: + case 0x1a0: + case 0x1b0: + return mpeg->mthd_dma(device, mthd, data); + default: + break; + } + return false; } struct nvkm_ofuncs @@ -108,17 +119,9 @@ nv31_mpeg_ofuncs = { .wr32 = _nvkm_gpuobj_wr32, }; -static struct nvkm_omthds -nv31_mpeg_omthds[] = { - { 0x0190, 0x0190, nv31_mpeg_mthd_dma }, - { 0x01a0, 0x01a0, nv31_mpeg_mthd_dma }, - { 0x01b0, 0x01b0, nv31_mpeg_mthd_dma }, - {} -}; - struct nvkm_oclass nv31_mpeg_sclass[] = { - { 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds }, + { 0x3174, &nv31_mpeg_ofuncs }, {} }; @@ -149,6 +152,7 @@ nv31_mpeg_context_ctor(struct nvkm_object *parent, *pobject = NULL; return -EBUSY; } + chan->fifo = nvkm_fifo_chan(parent); mpeg->chan = chan; spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); return 0; @@ -199,9 +203,6 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) { struct nv31_mpeg *mpeg = (void *)subdev; struct nvkm_device *device = mpeg->base.engine.subdev.device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_handle *handle; - struct nvkm_object *engctx; u32 stat = nvkm_rd32(device, 0x00b100); u32 type = nvkm_rd32(device, 0x00b230); u32 mthd = nvkm_rd32(device, 0x00b234); @@ -209,8 +210,7 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) u32 show = stat; unsigned long flags; - spin_lock_irqsave(&nv_engine(mpeg)->lock, flags); - engctx = nv_object(mpeg->chan); + spin_lock_irqsave(&mpeg->base.engine.lock, flags); if (stat & 0x01000000) { /* happens on initial binding of the object */ @@ -219,11 +219,9 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) show &= ~0x01000000; } - if (type == 0x00000010 && engctx) { - handle = nvkm_handle_get_class(engctx, 0x3174); - if (handle && !nv_call(handle->object, mthd, data)) + if (type == 0x00000010) { + if (!nv31_mpeg_mthd(mpeg, mthd, data)) show &= ~0x01000000; - nvkm_handle_put(handle); } } @@ -232,11 +230,12 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) if (show) { nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", - fifo->chid(fifo, engctx), - nvkm_client_name(engctx), stat, type, mthd, data); + mpeg->chan ? mpeg->chan->fifo->chid : -1, + nvkm_client_name(mpeg->chan), + stat, type, mthd, data); } - spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); + spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); } static int @@ -252,6 +251,7 @@ nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + mpeg->mthd_dma = nv31_mpeg_mthd_dma; nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv31_mpeg_intr; nv_engine(mpeg)->cclass = &nv31_mpeg_cclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h index 022a98e622dee..6bdd409d5769c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h @@ -1,13 +1,16 @@ #ifndef __NV31_MPEG_H__ #define __NV31_MPEG_H__ #include +#include struct nv31_mpeg_chan { struct nvkm_object base; + struct nvkm_fifo_chan *fifo; }; struct nv31_mpeg { struct nvkm_mpeg base; struct nv31_mpeg_chan *chan; + bool (*mthd_dma)(struct nvkm_device *, u32 mthd, u32 data); }; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 7c009c3aa7f81..cc167dcc788f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -29,13 +29,11 @@ * MPEG object classes ******************************************************************************/ -static int -nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) +bool +nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) { - struct nv31_mpeg *mpeg = (void *)object->engine; - struct nvkm_device *device = mpeg->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; - u32 inst = *(u32 *)arg << 4; + u32 inst = data << 4; u32 dma0 = imem->func->rd32(imem, inst + 0); u32 dma1 = imem->func->rd32(imem, inst + 4); u32 dma2 = imem->func->rd32(imem, inst + 8); @@ -44,7 +42,7 @@ nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) /* only allow linear DMA objects */ if (!(dma0 & 0x00002000)) - return -EINVAL; + return false; if (mthd == 0x0190) { /* DMA_CMD */ @@ -60,26 +58,18 @@ nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len) } else { /* DMA_IMAGE, VRAM only */ if (dma0 & 0x00030000) - return -EINVAL; + return false; nvkm_wr32(device, 0x00b370, base); nvkm_wr32(device, 0x00b374, size); } - return 0; + return true; } -static struct nvkm_omthds -nv40_mpeg_omthds[] = { - { 0x0190, 0x0190, nv40_mpeg_mthd_dma }, - { 0x01a0, 0x01a0, nv40_mpeg_mthd_dma }, - { 0x01b0, 0x01b0, nv40_mpeg_mthd_dma }, - {} -}; - struct nvkm_oclass nv40_mpeg_sclass[] = { - { 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds }, + { 0x3174, &nv31_mpeg_ofuncs }, {} }; @@ -116,6 +106,7 @@ nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + mpeg->mthd_dma = nv40_mpeg_mthd_dma; nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv40_mpeg_intr; nv_engine(mpeg)->cclass = &nv31_mpeg_cclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 93936671f39b7..1223baddfb9ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -24,24 +24,47 @@ #include #include -#include #include +struct nv44_mpeg { + struct nvkm_mpeg base; + struct list_head chan; +}; + struct nv44_mpeg_chan { struct nvkm_mpeg_chan base; + struct nvkm_fifo_chan *fifo; + u32 inst; + struct list_head head; }; +bool nv40_mpeg_mthd_dma(struct nvkm_device *, u32, u32); + /******************************************************************************* * PMPEG context ******************************************************************************/ +static void +nv44_mpeg_context_dtor(struct nvkm_object *object) +{ + struct nv44_mpeg_chan *chan = (void *)object; + struct nv44_mpeg *mpeg = (void *)object->engine; + unsigned long flags; + spin_lock_irqsave(&mpeg->base.engine.lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + nvkm_mpeg_context_destroy(&chan->base); +} + static int nv44_mpeg_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nv44_mpeg *mpeg = (void *)engine; struct nv44_mpeg_chan *chan; + unsigned long flags; int ret; ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 264 * 4, @@ -50,6 +73,12 @@ nv44_mpeg_context_ctor(struct nvkm_object *parent, if (ret) return ret; + spin_lock_irqsave(&mpeg->base.engine.lock, flags); + chan->fifo = nvkm_fifo_chan(parent); + chan->inst = chan->base.base.gpuobj.addr; + list_add(&chan->head, &mpeg->chan); + spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + nvkm_kmap(&chan->base.base.gpuobj); nvkm_wo32(&chan->base.base.gpuobj, 0x78, 0x02001ec1); nvkm_done(&chan->base.base.gpuobj); @@ -77,7 +106,7 @@ nv44_mpeg_cclass = { .handle = NV_ENGCTX(MPEG, 0x44), .ofuncs = &(struct nvkm_ofuncs) { .ctor = nv44_mpeg_context_ctor, - .dtor = _nvkm_mpeg_context_dtor, + .dtor = nv44_mpeg_context_dtor, .init = _nvkm_mpeg_context_init, .fini = nv44_mpeg_context_fini, .rd32 = _nvkm_mpeg_context_rd32, @@ -89,25 +118,45 @@ nv44_mpeg_cclass = { * PMPEG engine/subdev functions ******************************************************************************/ +static bool +nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data) +{ + switch (mthd) { + case 0x190: + case 0x1a0: + case 0x1b0: + return nv40_mpeg_mthd_dma(device, mthd, data); + default: + break; + } + return false; +} + static void nv44_mpeg_intr(struct nvkm_subdev *subdev) { - struct nvkm_mpeg *mpeg = (void *)subdev; - struct nvkm_device *device = mpeg->engine.subdev.device; - struct nvkm_fifo *fifo = device->fifo; - struct nvkm_engine *engine = nv_engine(subdev); - struct nvkm_object *engctx; - struct nvkm_handle *handle; + struct nv44_mpeg *mpeg = (void *)subdev; + struct nv44_mpeg_chan *temp, *chan = NULL; + struct nvkm_device *device = mpeg->base.engine.subdev.device; + unsigned long flags; u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff; u32 stat = nvkm_rd32(device, 0x00b100); u32 type = nvkm_rd32(device, 0x00b230); u32 mthd = nvkm_rd32(device, 0x00b234); u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; - int chid; - - engctx = nvkm_engctx_get(engine, inst); - chid = fifo->chid(fifo, engctx); + int chid = -1; + + spin_lock_irqsave(&mpeg->base.engine.lock, flags); + list_for_each_entry(temp, &mpeg->chan, head) { + if (temp->inst >> 4 == inst) { + chan = temp; + chid = chan->fifo->chid; + list_del(&chan->head); + list_add(&chan->head, &mpeg->chan); + break; + } + } if (stat & 0x01000000) { /* happens on initial binding of the object */ @@ -117,10 +166,8 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) } if (type == 0x00000010) { - handle = nvkm_handle_get_class(engctx, 0x3174); - if (handle && !nv_call(handle->object, mthd, data)) + if (!nv44_mpeg_mthd(subdev->device, mthd, data)) show &= ~0x01000000; - nvkm_handle_put(handle); } } @@ -128,13 +175,12 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x00b230, 0x00000001); if (show) { - nvkm_error(subdev, - "ch %d [%08x %s] %08x %08x %08x %08x\n", - chid, inst << 4, nvkm_client_name(engctx), stat, - type, mthd, data); + nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", + chid, inst << 4, nvkm_client_name(chan), + stat, type, mthd, data); } - nvkm_engctx_put(engctx); + spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); } static void @@ -158,7 +204,7 @@ nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_mpeg *mpeg; + struct nv44_mpeg *mpeg; int ret; ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); @@ -166,6 +212,8 @@ nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + INIT_LIST_HEAD(&mpeg->chan); + nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv44_mpeg_me_intr; nv_engine(mpeg)->cclass = &nv44_mpeg_cclass; -- GitLab From 6157091177102638c7d94ffc159c0b157a1c9b56 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5510/7006] drm/nouveau/sw: remove dependence on namedb/engctx lookup Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/object.h | 27 ----- .../gpu/drm/nouveau/include/nvkm/engine/sw.h | 8 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 33 +----- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 33 +----- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 59 +++------- drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c | 64 +++++++++++ drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c | 27 ++++- drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h | 16 ++- .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 107 ++++++++---------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 50 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c | 23 ++-- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 101 +++++------------ drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h | 2 + 15 files changed, 251 insertions(+), 301 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 3366ec59a64ec..7befea315c985 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -109,7 +109,6 @@ struct nvkm_sclass { struct nvkm_oclass { s32 handle; struct nvkm_ofuncs * const ofuncs; - struct nvkm_omthds * const omthds; int (*ctor)(const struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **); @@ -135,12 +134,6 @@ nv_pclass(struct nvkm_object *parent, u32 oclass) return parent; } -struct nvkm_omthds { - u32 start; - u32 limit; - int (*call)(struct nvkm_object *, u32, void *, u32); -}; - struct nvkm_ofuncs { int (*ctor)(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *data, u32 size, @@ -171,24 +164,4 @@ int nvkm_object_old(struct nvkm_object *, struct nvkm_object *, void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **); int nvkm_object_inc(struct nvkm_object *); int nvkm_object_dec(struct nvkm_object *, bool suspend); - -static inline int -nv_exec(void *obj, u32 mthd, void *data, u32 size) -{ - struct nvkm_omthds *method = nv_oclass(obj)->omthds; - - while (method && method->call) { - if (mthd >= method->start && mthd <= method->limit) - return method->call(obj, mthd, data, size); - method++; - } - - return -EINVAL; -} - -static inline int -nv_call(void *obj, u32 mthd, u32 data) -{ - return nv_exec(obj, mthd, &data, sizeof(data)); -} #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h index b06140af0a05b..f5857a6404d35 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h @@ -4,10 +4,16 @@ struct nvkm_sw { struct nvkm_engine engine; + struct list_head chan; }; +bool nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data); + #define nvkm_sw_create(p,e,c,d) \ - nvkm_engine_create((p), (e), (c), true, "SW", "software", (d)) + nvkm_sw_ctor((p), (e), (c), sizeof(**d), (void **)d) +int +nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, int length, void **pobject); #define nvkm_sw_destroy(d) \ nvkm_engine_destroy(&(d)->engine) #define nvkm_sw_init(d) \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 21dbd39011132..3c50d28d33a00 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -174,7 +174,6 @@ int nv50_disp_main_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); void nv50_disp_main_dtor(struct nvkm_object *); -extern struct nvkm_omthds nv50_disp_main_omthds[]; extern struct nvkm_oclass nv50_disp_cclass; void nv50_disp_mthd_chan(struct nv50_disp *, int debug, int head, const struct nv50_disp_mthd_chan *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 39031841d057c..7f05985ebb377 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -474,32 +475,6 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, schedule_work(&fifo->fault); } -static int -gf100_fifo_swmthd(struct gf100_fifo *fifo, u32 chid, u32 mthd, u32 data) -{ - struct gf100_fifo_chan *chan = NULL; - struct nvkm_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&fifo->base.lock, flags); - if (likely(chid >= fifo->base.min && chid <= fifo->base.max)) - chan = (void *)fifo->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nvkm_namedb_get_class(nv_namedb(chan), NVIF_IOCTL_NEW_V0_SW_GF100); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nvkm_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&fifo->base.lock, flags); - return ret; -} - static const struct nvkm_enum gf100_fifo_sched_reason[] = { { 0x0a, "CTXSW_TIMEOUT" }, @@ -701,8 +676,10 @@ gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) char msg[128]; if (stat & 0x00800000) { - if (!gf100_fifo_swmthd(fifo, chid, mthd, data)) - show &= ~0x00800000; + if (device->sw) { + if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) + show &= ~0x00800000; + } } if (show) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 3d2b16e7a7ee6..e0badfc54dc80 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -520,32 +521,6 @@ gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, schedule_work(&fifo->fault); } -static int -gk104_fifo_swmthd(struct gk104_fifo *fifo, u32 chid, u32 mthd, u32 data) -{ - struct gk104_fifo_chan *chan = NULL; - struct nvkm_handle *bind; - unsigned long flags; - int ret = -EINVAL; - - spin_lock_irqsave(&fifo->base.lock, flags); - if (likely(chid >= fifo->base.min && chid <= fifo->base.max)) - chan = (void *)fifo->base.channel[chid]; - if (unlikely(!chan)) - goto out; - - bind = nvkm_namedb_get_class(nv_namedb(chan), NVIF_IOCTL_NEW_V0_SW_GF100); - if (likely(bind)) { - if (!mthd || !nv_call(bind->object, mthd, data)) - ret = 0; - nvkm_namedb_put(bind); - } - -out: - spin_unlock_irqrestore(&fifo->base.lock, flags); - return ret; -} - static const struct nvkm_enum gk104_fifo_bind_reason[] = { { 0x01, "BIND_NOT_UNBOUND" }, @@ -864,8 +839,10 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) char msg[128]; if (stat & 0x00800000) { - if (!gk104_fifo_swmthd(fifo, chid, mthd, data)) - show &= ~0x00800000; + if (device->sw) { + if (nvkm_sw_mthd(device->sw, chid, subc, mthd, data)) + show &= ~0x00800000; + } nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index cd5009302e223..8bdb71f5f1c54 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -369,55 +370,29 @@ nv_dma_state_err(u32 state) } static bool -nv04_fifo_swmthd(struct nv04_fifo *fifo, u32 chid, u32 addr, u32 data) +nv04_fifo_swmthd(struct nvkm_device *device, u32 chid, u32 addr, u32 data) { - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nv04_fifo_chan *chan = NULL; - struct nvkm_handle *bind; - const int subc = (addr >> 13) & 0x7; - const int mthd = addr & 0x1ffc; + struct nvkm_sw *sw = device->sw; + const int subc = (addr & 0x0000e000) >> 13; + const int mthd = (addr & 0x00001ffc); + const u32 mask = 0x0000000f << (subc * 4); + u32 engine = nvkm_rd32(device, 0x003280); bool handled = false; - unsigned long flags; - u32 engine; - - spin_lock_irqsave(&fifo->base.lock, flags); - if (likely(chid >= fifo->base.min && chid <= fifo->base.max)) - chan = (void *)fifo->base.channel[chid]; - if (unlikely(!chan)) - goto out; switch (mthd) { - case 0x0000: - bind = nvkm_namedb_get(nv_namedb(chan), data); - if (unlikely(!bind)) - break; - - if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) { - engine = 0x0000000f << (subc * 4); - chan->subc[subc] = data; - handled = true; - - nvkm_mask(device, NV04_PFIFO_CACHE1_ENGINE, engine, 0); - } - - nvkm_namedb_put(bind); + case 0x0000 ... 0x0000: /* subchannel's engine -> software */ + nvkm_wr32(device, 0x003280, (engine &= ~mask)); + case 0x0180 ... 0x01fc: /* handle -> instance */ + data = nvkm_rd32(device, 0x003258) & 0x0000ffff; + case 0x0100 ... 0x017c: + case 0x0200 ... 0x1ffc: /* pass method down to sw */ + if (!(engine & mask) && sw) + handled = nvkm_sw_mthd(sw, chid, subc, mthd, data); break; default: - engine = nvkm_rd32(device, NV04_PFIFO_CACHE1_ENGINE); - if (unlikely(((engine >> (subc * 4)) & 0xf) != 0)) - break; - - bind = nvkm_namedb_get(nv_namedb(chan), chan->subc[subc]); - if (likely(bind)) { - if (!nv_call(bind->object, mthd, data)) - handled = true; - nvkm_namedb_put(bind); - } break; } -out: - spin_unlock_irqrestore(&fifo->base.lock, flags); return handled; } @@ -426,6 +401,7 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) { struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; + u32 pull0 = nvkm_rd32(device, 0x003250); u32 mthd, data; int ptr; @@ -444,7 +420,8 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) data = nvkm_rd32(device, NV40_PFIFO_CACHE1_DATA(ptr)); } - if (!nv04_fifo_swmthd(fifo, chid, mthd, data)) { + if (!(pull0 & 0x00000100) || + !nv04_fifo_swmthd(device, chid, mthd, data)) { const char *client_name = nvkm_client_name_for_fifo_chid(&fifo->base, chid); nvkm_error(subdev, "CACHE_ERROR - " diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild index 1144d84e46de3..1c291e6fcf964 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild @@ -1,3 +1,4 @@ +nvkm-y += nvkm/engine/sw/base.o nvkm-y += nvkm/engine/sw/nv04.o nvkm-y += nvkm/engine/sw/nv10.o nvkm-y += nvkm/engine/sw/nv50.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c new file mode 100644 index 0000000000000..1d68ae68884a3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "chan.h" + +#include + +bool +nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data) +{ + struct nvkm_sw_chan *chan; + bool handled = false; + unsigned long flags; + + spin_lock_irqsave(&sw->engine.lock, flags); + list_for_each_entry(chan, &sw->chan, head) { + if (chan->fifo->chid == chid) { + handled = nvkm_sw_chan_mthd(chan, subc, mthd, data); + list_del(&chan->head); + list_add(&chan->head, &sw->chan); + break; + } + } + spin_unlock_irqrestore(&sw->engine.lock, flags); + return handled; +} + +int +nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, int length, void **pobject) +{ + struct nvkm_sw *sw; + int ret; + + ret = nvkm_engine_create_(parent, engine, oclass, true, "sw", + "sw", length, pobject); + sw = *pobject; + if (ret) + return ret; + + INIT_LIST_HEAD(&sw->chan); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c index 97c0d96463a2c..904405a8f5c6b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c @@ -24,10 +24,28 @@ #include "chan.h" #include +#include #include #include +bool +nvkm_sw_chan_mthd(struct nvkm_sw_chan *chan, int subc, u32 mthd, u32 data) +{ + switch (mthd) { + case 0x0000: + return true; + case 0x0500: + nvkm_event_send(&chan->event, 1, 0, NULL, 0); + return true; + default: + if (chan->func->mthd) + return chan->func->mthd(chan, subc, mthd, data); + break; + } + return false; +} + static int nvkm_sw_chan_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -55,14 +73,17 @@ void nvkm_sw_chan_dtor(struct nvkm_object *base) { struct nvkm_sw_chan *chan = (void *)base; + list_del(&chan->head); nvkm_event_fini(&chan->event); nvkm_engctx_destroy(&chan->base); } int -nvkm_sw_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, +nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *func, + struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { + struct nvkm_sw *sw = (void *)engine; struct nvkm_sw_chan *chan; int ret; @@ -72,5 +93,9 @@ nvkm_sw_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + chan->func = func; + chan->fifo = nvkm_fifo_chan(parent); + list_add(&chan->head, &sw->chan); + return nvkm_event_init(&nvkm_sw_chan_event, 1, 1, &chan->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h index b5cf4c517a955..edebd9c30c0c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h @@ -6,12 +6,22 @@ struct nvkm_sw_chan { struct nvkm_engctx base; + const struct nvkm_sw_chan_func *func; + struct nvkm_fifo_chan *fifo; + struct list_head head; struct nvkm_event event; }; -#define nvkm_sw_context_create(p,e,c,d) \ - nvkm_sw_chan_ctor((p), (e), (c), sizeof(**d), (void **)d) -int nvkm_sw_chan_ctor(struct nvkm_object *, struct nvkm_object *, +struct nvkm_sw_chan_func { + bool (*mthd)(struct nvkm_sw_chan *, int subc, u32 mthd, u32 data); +}; + +bool nvkm_sw_chan_mthd(struct nvkm_sw_chan *, int subc, u32 mthd, u32 data); + +#define nvkm_sw_context_create(f,p,e,c,d) \ + nvkm_sw_chan_ctor((f), (p), (e), (c), sizeof(**d), (void **)d) +int nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *, + struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int, void **); void nvkm_sw_chan_dtor(struct nvkm_object *); #define nvkm_sw_context_init(d) \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index d57052cdcad3d..ac106c6c25d07 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -24,6 +24,7 @@ #include "nv50.h" #include +#include #include @@ -31,65 +32,9 @@ * software object classes ******************************************************************************/ -static int -gf100_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - u64 data = *(u32 *)args; - if (mthd == 0x0400) { - chan->vblank.offset &= 0x00ffffffffULL; - chan->vblank.offset |= data << 32; - } else { - chan->vblank.offset &= 0xff00000000ULL; - chan->vblank.offset |= data; - } - return 0; -} - -static int -gf100_sw_mthd_mp_control(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - struct nvkm_sw *sw = (void *)nv_object(chan)->engine; - struct nvkm_device *device = sw->engine.subdev.device; - u32 data = *(u32 *)args; - - switch (mthd) { - case 0x600: - nvkm_wr32(device, 0x419e00, data); /* MP.PM_UNK000 */ - break; - case 0x644: - if (data & ~0x1ffffe) - return -EINVAL; - nvkm_wr32(device, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */ - break; - case 0x6ac: - nvkm_wr32(device, 0x419eac, data); /* MP.PM_UNK0AC */ - break; - default: - return -EINVAL; - } - return 0; -} - -static struct nvkm_omthds -gf100_sw_omthds[] = { - { 0x0400, 0x0400, gf100_sw_mthd_vblsem_offset }, - { 0x0404, 0x0404, gf100_sw_mthd_vblsem_offset }, - { 0x0408, 0x0408, nv50_sw_mthd_vblsem_value }, - { 0x040c, 0x040c, nv50_sw_mthd_vblsem_release }, - { 0x0500, 0x0500, nv50_sw_mthd_flip }, - { 0x0600, 0x0600, gf100_sw_mthd_mp_control }, - { 0x0644, 0x0644, gf100_sw_mthd_mp_control }, - { 0x06ac, 0x06ac, gf100_sw_mthd_mp_control }, - {} -}; - static struct nvkm_oclass gf100_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_GF100, &nvkm_nvsw_ofuncs, gf100_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_GF100, &nvkm_nvsw_ofuncs }, {} }; @@ -115,6 +60,53 @@ gf100_sw_vblsem_release(struct nvkm_notify *notify) return NVKM_NOTIFY_DROP; } +static bool +gf100_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) +{ + struct nv50_sw_chan *chan = nv50_sw_chan(base); + struct nvkm_engine *engine = chan->base.base.gpuobj.object.engine; + struct nvkm_device *device = engine->subdev.device; + switch (mthd) { + case 0x0400: + chan->vblank.offset &= 0x00ffffffffULL; + chan->vblank.offset |= (u64)data << 32; + return true; + case 0x0404: + chan->vblank.offset &= 0xff00000000ULL; + chan->vblank.offset |= data; + return true; + case 0x0408: + chan->vblank.value = data; + return true; + case 0x040c: + if (data < device->disp->vblank.index_nr) { + nvkm_notify_get(&chan->vblank.notify[data]); + return true; + } + break; + case 0x600: /* MP.PM_UNK000 */ + nvkm_wr32(device, 0x419e00, data); + return true; + case 0x644: /* MP.TRAP_WARP_ERROR_EN */ + if (!(data & ~0x001ffffe)) { + nvkm_wr32(device, 0x419e44, data); + return true; + } + break; + case 0x6ac: /* MP.PM_UNK0AC */ + nvkm_wr32(device, 0x419eac, data); + return true; + default: + break; + } + return false; +} + +static const struct nvkm_sw_chan_func +gf100_sw_chan_func = { + .mthd = gf100_sw_chan_mthd, +}; + static struct nv50_sw_cclass gf100_sw_cclass = { .base.handle = NV_ENGCTX(SW, 0xc0), @@ -125,6 +117,7 @@ gf100_sw_cclass = { .fini = _nvkm_sw_context_fini, }, .vblank = gf100_sw_vblsem_release, + .chan = &gf100_sw_chan_func, }; /******************************************************************************* diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index 08b59f198c73a..6958cba393daa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define nv04_sw_chan(p) container_of((p), struct nv04_sw_chan, base) #include "priv.h" #include "chan.h" #include "nvsw.h" @@ -38,29 +39,6 @@ struct nv04_sw_chan { * software object classes ******************************************************************************/ -static int -nv04_sw_set_ref(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - struct nv04_sw_chan *chan = (void *)nv_engctx(object->parent); - atomic_set(&chan->ref, *(u32*)data); - return 0; -} - -static int -nv04_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) -{ - struct nvkm_sw_chan *chan = (void *)nv_engctx(object->parent); - nvkm_event_send(&chan->event, 1, 0, NULL, 0); - return 0; -} - -static struct nvkm_omthds -nv04_sw_omthds[] = { - { 0x0150, 0x0150, nv04_sw_set_ref }, - { 0x0500, 0x0500, nv04_sw_flip }, - {} -}; - static int nv04_sw_mthd_get_ref(struct nvkm_object *object, void *data, u32 size) { @@ -100,7 +78,7 @@ nv04_sw_ofuncs = { static struct nvkm_oclass nv04_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV04, &nv04_sw_ofuncs, nv04_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV04, &nv04_sw_ofuncs }, {} }; @@ -108,6 +86,27 @@ nv04_sw_sclass[] = { * software context ******************************************************************************/ +static bool +nv04_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) +{ + struct nv04_sw_chan *chan = nv04_sw_chan(base); + + switch (mthd) { + case 0x0150: + atomic_set(&chan->ref, data); + return true; + default: + break; + } + + return false; +} + +static const struct nvkm_sw_chan_func +nv04_sw_chan_func = { + .mthd = nv04_sw_chan_mthd, +}; + static int nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -116,7 +115,8 @@ nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nv04_sw_chan *chan; int ret; - ret = nvkm_sw_context_create(parent, engine, oclass, &chan); + ret = nvkm_sw_context_create(&nv04_sw_chan_func, + parent, engine, oclass, &chan); *pobject = nv_object(chan); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index d0d4339b857c0..ecaeeaa8edc7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -31,23 +31,9 @@ * software object classes ******************************************************************************/ -static int -nv10_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) -{ - struct nvkm_sw_chan *chan = (void *)nv_engctx(object->parent); - nvkm_event_send(&chan->event, 1, 0, NULL, 0); - return 0; -} - -static struct nvkm_omthds -nv10_sw_omthds[] = { - { 0x0500, 0x0500, nv10_sw_flip }, - {} -}; - static struct nvkm_oclass nv10_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV10, &nvkm_nvsw_ofuncs, nv10_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV10, &nvkm_nvsw_ofuncs }, {} }; @@ -55,6 +41,10 @@ nv10_sw_sclass[] = { * software context ******************************************************************************/ +static const struct nvkm_sw_chan_func +nv10_sw_chan_func = { +}; + static int nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -63,7 +53,8 @@ nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_sw_chan *chan; int ret; - ret = nvkm_sw_context_create(parent, engine, oclass, &chan); + ret = nvkm_sw_context_create(&nv10_sw_chan_func, + parent, engine, oclass, &chan); *pobject = nv_object(chan); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 9322bde518d2e..c3af125c7132e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -35,80 +35,9 @@ * software object classes ******************************************************************************/ -static int -nv50_sw_mthd_dma_vblsem(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent; - struct nvkm_handle *handle; - int ret = -EINVAL; - - handle = nvkm_namedb_get(nv_namedb(fifo), *(u32 *)args); - if (!handle) - return -ENOENT; - - if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { - struct nvkm_gpuobj *gpuobj = nv_gpuobj(handle->object); - chan->vblank.ctxdma = gpuobj->node->offset >> 4; - ret = 0; - } - nvkm_namedb_put(handle); - return ret; -} - -static int -nv50_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - chan->vblank.offset = *(u32 *)args; - return 0; -} - -int -nv50_sw_mthd_vblsem_value(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - chan->vblank.value = *(u32 *)args; - return 0; -} - -int -nv50_sw_mthd_vblsem_release(struct nvkm_object *object, u32 mthd, - void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - u32 head = *(u32 *)args; - if (head >= nvkm_disp(chan)->vblank.index_nr) - return -EINVAL; - - nvkm_notify_get(&chan->vblank.notify[head]); - return 0; -} - -int -nv50_sw_mthd_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size) -{ - struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent); - nvkm_event_send(&chan->base.event, 1, 0, NULL, 0); - return 0; -} - -static struct nvkm_omthds -nv50_sw_omthds[] = { - { 0x018c, 0x018c, nv50_sw_mthd_dma_vblsem }, - { 0x0400, 0x0400, nv50_sw_mthd_vblsem_offset }, - { 0x0404, 0x0404, nv50_sw_mthd_vblsem_value }, - { 0x0408, 0x0408, nv50_sw_mthd_vblsem_release }, - { 0x0500, 0x0500, nv50_sw_mthd_flip }, - {} -}; - static struct nvkm_oclass nv50_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV50, &nvkm_nvsw_ofuncs, nv50_sw_omthds }, + { NVIF_IOCTL_NEW_V0_SW_NV50, &nvkm_nvsw_ofuncs }, {} }; @@ -140,6 +69,31 @@ nv50_sw_vblsem_release(struct nvkm_notify *notify) return NVKM_NOTIFY_DROP; } +static bool +nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) +{ + struct nv50_sw_chan *chan = nv50_sw_chan(base); + switch (mthd) { + case 0x018c: chan->vblank.ctxdma = data; return true; + case 0x0400: chan->vblank.offset = data; return true; + case 0x0404: chan->vblank.value = data; return true; + case 0x0408: + if (data < nvkm_disp(chan)->vblank.index_nr) { + nvkm_notify_get(&chan->vblank.notify[data]); + return true; + } + break; + default: + break; + } + return false; +} + +static const struct nvkm_sw_chan_func +nv50_sw_chan_func = { + .mthd = nv50_sw_chan_mthd, +}; + void nv50_sw_context_dtor(struct nvkm_object *object) { @@ -162,7 +116,7 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nv50_sw_chan *chan; int ret, i; - ret = nvkm_sw_context_create(parent, engine, oclass, &chan); + ret = nvkm_sw_context_create(pclass->chan, parent, engine, oclass, &chan); *pobject = nv_object(chan); if (ret) return ret; @@ -194,6 +148,7 @@ nv50_sw_cclass = { .fini = _nvkm_sw_context_fini, }, .vblank = nv50_sw_vblsem_release, + .chan = &nv50_sw_chan_func, }; /******************************************************************************* diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index f3bf451546b12..534c21079b81a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -1,5 +1,6 @@ #ifndef __NVKM_SW_NV50_H__ #define __NVKM_SW_NV50_H__ +#define nv50_sw_chan(p) container_of((p), struct nv50_sw_chan, base) #include "priv.h" #include "chan.h" #include "nvsw.h" @@ -18,6 +19,7 @@ int nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *, struct nv50_sw_cclass { struct nvkm_oclass base; int (*vblank)(struct nvkm_notify *); + const struct nvkm_sw_chan_func *chan; }; struct nv50_sw_chan { -- GitLab From 24bd0930bedea1182aaadc52757897d2b9b3ca99 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5511/7006] drm/nouveau/client: convert to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/client.h | 2 +- .../drm/nouveau/include/nvkm/core/client.h | 36 +++++----- .../drm/nouveau/include/nvkm/core/engctx.h | 1 + drivers/gpu/drm/nouveau/nvkm/core/client.c | 72 +++++++++++-------- drivers/gpu/drm/nouveau/nvkm/core/handle.c | 1 + drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 1 + 9 files changed, 70 insertions(+), 52 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/client.h b/drivers/gpu/drm/nouveau/include/nvif/client.h index 4d5db8039576b..4a7f6f7b836d6 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/client.h +++ b/drivers/gpu/drm/nouveau/include/nvif/client.h @@ -23,6 +23,6 @@ int nvif_client_resume(struct nvif_client *); #include #define nvxx_client(a) ({ \ struct nvif_client *_client = (a); \ - nvkm_client(_client->object.priv); \ + (struct nvkm_client *)_client->object.priv; \ }) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index ff6331d7e9e67..4bb0acca8650a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -1,37 +1,29 @@ #ifndef __NVKM_CLIENT_H__ #define __NVKM_CLIENT_H__ -#include +#include struct nvkm_client { - struct nvkm_namedb namedb; - struct nvkm_handle *root; - u64 device; + struct nvkm_object object; char name[32]; + u64 device; u32 debug; - struct nvkm_vm *vm; + + struct nvkm_client_notify *notify[16]; + struct rb_root objroot; + + struct nvkm_handle *root; + bool super; void *data; - int (*ntfy)(const void *, u32, const void *, u32); - struct nvkm_client_notify *notify[16]; - struct rb_root objroot; + struct nvkm_vm *vm; }; bool nvkm_client_insert(struct nvkm_client *, struct nvkm_handle *); void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *); struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle); -static inline struct nvkm_client * -nvkm_client(struct nvkm_object *object) -{ - while (object && object->parent) - object = object->parent; - if (object && nv_iclass(object, NV_CLIENT_CLASS)) - return container_of(object, struct nvkm_client, namedb.parent.object); - return NULL; -} - int nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, struct nvkm_client **); void nvkm_client_del(struct nvkm_client **); @@ -39,6 +31,14 @@ int nvkm_client_init(struct nvkm_client *); int nvkm_client_fini(struct nvkm_client *, bool suspend); const char *nvkm_client_name(void *obj); +static inline struct nvkm_client * +nvkm_client(struct nvkm_object *object) +{ + while (object && object->parent) + object = object->parent; + return container_of(object, struct nvkm_client, object); +} + int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *, void *data, u32 size); int nvkm_client_notify_del(struct nvkm_client *, int index); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h index aa465def4f95f..dfa24d233321a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h @@ -1,6 +1,7 @@ #ifndef __NVKM_ENGCTX_H__ #define __NVKM_ENGCTX_H__ #include +#include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 9a7c4bc24a767..1affa2299a8ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -176,11 +176,35 @@ nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } -static struct nvkm_oclass -nvkm_client_oclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .mthd = nvkm_client_mthd, - }, +static int +nvkm_client_child_new(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + static struct nvkm_oclass devobj = { + .handle = NV_DEVICE, + .ofuncs = &nvkm_udevice_ofuncs, + }; + return nvkm_object_old(oclass->parent, NULL, &devobj, data, size, pobject); +} + +static int +nvkm_client_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + if (index == 0) { + oclass->base.oclass = NV_DEVICE; + oclass->base.minver = 0; + oclass->base.maxver = 0; + oclass->ctor = nvkm_client_child_new; + return 0; + } + return -EINVAL; +} + +static const struct nvkm_object_func +nvkm_client_object_func = { + .mthd = nvkm_client_mthd, + .sclass = nvkm_client_child_get, }; void @@ -235,7 +259,7 @@ nvkm_client_search(struct nvkm_client *client, u64 handle) int nvkm_client_fini(struct nvkm_client *client, bool suspend) { - struct nvkm_object *object = &client->namedb.parent.object; + struct nvkm_object *object = &client->object; const char *name[2] = { "fini", "suspend" }; int ret, i; nvif_trace(object, "%s running\n", name[suspend]); @@ -251,7 +275,7 @@ nvkm_client_fini(struct nvkm_client *client, bool suspend) int nvkm_client_init(struct nvkm_client *client) { - struct nvkm_object *object = &client->namedb.parent.object; + struct nvkm_object *object = &client->object; int ret; nvif_trace(object, "init running\n"); ret = nvkm_handle_init(client->root); @@ -269,43 +293,33 @@ nvkm_client_del(struct nvkm_client **pclient) for (i = 0; i < ARRAY_SIZE(client->notify); i++) nvkm_client_notify_del(client, i); nvkm_handle_destroy(client->root); - nvkm_namedb_destroy(&client->namedb); + kfree(*pclient); *pclient = NULL; } } -static struct nvkm_oclass -nvkm_client_sclass[] = { - { NV_DEVICE, &nvkm_udevice_ofuncs }, - {} -}; - int nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, struct nvkm_client **pclient) { + struct nvkm_oclass oclass = {}; struct nvkm_client *client; int ret; - ret = nvkm_namedb_create(NULL, NULL, &nvkm_client_oclass, - NV_CLIENT_CLASS, nvkm_client_sclass, - 0, &client); - *pclient = client; - if (ret) - return ret; - - ret = nvkm_handle_create(NULL, ~0, nv_object(client), &client->root); - if (ret) - return ret; - - /* prevent init/fini being called, os in in charge of this */ - atomic_set(&nv_object(client)->usecount, 2); + if (!(client = *pclient = kzalloc(sizeof(*client), GFP_KERNEL))) + return -ENOMEM; + oclass.client = client; - client->device = device; + nvkm_object_ctor(&nvkm_client_object_func, &oclass, &client->object); snprintf(client->name, sizeof(client->name), "%s", name); + client->device = device; client->debug = nvkm_dbgopt(dbg, "CLIENT"); client->objroot = RB_ROOT; - return 0; + + ret = nvkm_handle_create(NULL, ~0, &client->object, &client->root); + if (ret) + nvkm_client_del(pclient); + return ret; } const char * diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index 0c7cde900df60..2b52a655309b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -23,6 +23,7 @@ */ #include #include +#include #define hprintk(h,l,f,a...) do { \ struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \ diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index b9c8136904338..04f1bc2d0f8ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -535,12 +535,12 @@ nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type, else object = client->root; if (unlikely(!object)) { - nvif_ioctl(&client->namedb.parent.object, "object not found\n"); + nvif_ioctl(&client->object, "object not found\n"); return -ENOENT; } if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != object->route) { - nvif_ioctl(&client->namedb.parent.object, "route != owner\n"); + nvif_ioctl(&client->object, "route != owner\n"); return -EACCES; } *route = object->route; @@ -558,7 +558,7 @@ int nvkm_ioctl(struct nvkm_client *client, bool supervisor, void *data, u32 size, void **hack) { - struct nvkm_object *object = &client->namedb.parent.object; + struct nvkm_object *object = &client->object; union { struct nvif_ioctl_v0 v0; } *args = data; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b3f3336025829..a59a8e50706ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1988,7 +1988,7 @@ nv_device(void *obj) if (device->engine == NULL) { while (device && device->parent) { if (!nv_iclass(device, NV_SUBDEV_CLASS) && - device->parent == &nvkm_client(device)->namedb.parent.object) { + device->parent == &nvkm_client(device)->object) { struct { struct nvkm_parent base; struct nvkm_device *device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 0df54c6574690..59b28cbe66344 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -24,6 +24,7 @@ #include "priv.h" #include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index b3ae0d96ddb05..ae84db1f296bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -25,6 +25,7 @@ #include #include +#include #include #include -- GitLab From 2a9f847f5d43d15c0401d050cdd77fb4cbe7da06 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5512/7006] drm/nouveau/device: convert user class to new-style nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 4 +- drivers/gpu/drm/nouveau/nvkm/core/client.c | 23 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 233 ++++++++++++------ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/dmaobj/base.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 2 +- 7 files changed, 180 insertions(+), 88 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 3786982c1360b..2467d4e0acf67 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -272,10 +272,10 @@ enum nv_bus_type { NVKM_BUS_PLATFORM, }; -extern struct nvkm_ofuncs nvkm_udevice_ofuncs; - void nvkm_device_del(struct nvkm_device **); +extern const struct nvkm_sclass nvkm_udevice_sclass; + /* device logging */ #define nvdev_printk_(d,l,p,f,a...) do { \ struct nvkm_device *_device = (d); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 1affa2299a8ce..dce1d45cac5ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -180,25 +180,24 @@ static int nvkm_client_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - static struct nvkm_oclass devobj = { - .handle = NV_DEVICE, - .ofuncs = &nvkm_udevice_ofuncs, - }; - return nvkm_object_old(oclass->parent, NULL, &devobj, data, size, pobject); + return oclass->base.ctor(oclass, data, size, pobject); } static int nvkm_client_child_get(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) { - if (index == 0) { - oclass->base.oclass = NV_DEVICE; - oclass->base.minver = 0; - oclass->base.maxver = 0; - oclass->ctor = nvkm_client_child_new; - return 0; + const struct nvkm_sclass *sclass; + + switch (index) { + case 0: sclass = &nvkm_udevice_sclass; break; + default: + return -EINVAL; } - return -EINVAL; + + oclass->ctor = nvkm_client_child_new; + oclass->base = *sclass; + return 0; } static const struct nvkm_object_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index a59a8e50706ba..73770fb4da975 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1990,7 +1990,7 @@ nv_device(void *obj) if (!nv_iclass(device, NV_SUBDEV_CLASS) && device->parent == &nvkm_client(device)->object) { struct { - struct nvkm_parent base; + struct nvkm_object base; struct nvkm_device *device; } *udevice = (void *)device; return udevice->device; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 59b28cbe66344..fb4d04dc9340f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define nvkm_udevice(p) container_of((p), struct nvkm_udevice, object) #include "priv.h" #include @@ -28,19 +29,23 @@ #include #include #include +#include +#include +#include +#include #include #include struct nvkm_udevice { - struct nvkm_parent base; + struct nvkm_object object; struct nvkm_device *device; }; static int -nvkm_udevice_info(struct nvkm_object *object, void *data, u32 size) +nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_object *object = &udev->object; struct nvkm_device *device = udev->device; struct nvkm_fb *fb = device->fb; struct nvkm_instmem *imem = device->imem; @@ -114,9 +119,8 @@ nvkm_udevice_info(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_udevice_time(struct nvkm_object *object, void *data, u32 size) +nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size) { - struct nvkm_udevice *udev = (void *)object; struct nvkm_device *device = udev->device; struct nvkm_timer *tmr = device->timer; union { @@ -134,63 +138,70 @@ nvkm_udevice_time(struct nvkm_object *object, void *data, u32 size) static int nvkm_udevice_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { + struct nvkm_udevice *udev = nvkm_udevice(object); switch (mthd) { case NV_DEVICE_V0_INFO: - return nvkm_udevice_info(object, data, size); + return nvkm_udevice_info(udev, data, size); case NV_DEVICE_V0_TIME: - return nvkm_udevice_time(object, data, size); + return nvkm_udevice_time(udev, data, size); default: break; } return -EINVAL; } -static u8 -nvkm_udevice_rd08(struct nvkm_object *object, u64 addr) +static int +nvkm_udevice_rd08(struct nvkm_object *object, u64 addr, u8 *data) { - struct nvkm_udevice *udev = (void *)object; - return nvkm_rd08(udev->device, addr); + struct nvkm_udevice *udev = nvkm_udevice(object); + *data = nvkm_rd08(udev->device, addr); + return 0; } -static u16 -nvkm_udevice_rd16(struct nvkm_object *object, u64 addr) +static int +nvkm_udevice_rd16(struct nvkm_object *object, u64 addr, u16 *data) { - struct nvkm_udevice *udev = (void *)object; - return nvkm_rd16(udev->device, addr); + struct nvkm_udevice *udev = nvkm_udevice(object); + *data = nvkm_rd16(udev->device, addr); + return 0; } -static u32 -nvkm_udevice_rd32(struct nvkm_object *object, u64 addr) +static int +nvkm_udevice_rd32(struct nvkm_object *object, u64 addr, u32 *data) { - struct nvkm_udevice *udev = (void *)object; - return nvkm_rd32(udev->device, addr); + struct nvkm_udevice *udev = nvkm_udevice(object); + *data = nvkm_rd32(udev->device, addr); + return 0; } -static void +static int nvkm_udevice_wr08(struct nvkm_object *object, u64 addr, u8 data) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_udevice *udev = nvkm_udevice(object); nvkm_wr08(udev->device, addr, data); + return 0; } -static void +static int nvkm_udevice_wr16(struct nvkm_object *object, u64 addr, u16 data) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_udevice *udev = nvkm_udevice(object); nvkm_wr16(udev->device, addr, data); + return 0; } -static void +static int nvkm_udevice_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_udevice *udev = nvkm_udevice(object); nvkm_wr32(udev->device, addr, data); + return 0; } static int nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_udevice *udev = nvkm_udevice(object); struct nvkm_device *device = udev->device; *addr = nv_device_resource_start(device, 0); *size = nv_device_resource_len(device, 0); @@ -200,7 +211,7 @@ nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size) static int nvkm_udevice_fini(struct nvkm_object *object, bool suspend) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_udevice *udev = nvkm_udevice(object); struct nvkm_device *device = udev->device; int ret = 0; @@ -221,7 +232,7 @@ done: static int nvkm_udevice_init(struct nvkm_object *object) { - struct nvkm_udevice *udev = (void *)object; + struct nvkm_udevice *udev = nvkm_udevice(object); struct nvkm_device *device = udev->device; int ret = 0; @@ -239,34 +250,120 @@ done: return ret; } -static struct nvkm_oclass -nvkm_udevice_oclass_super = { - .handle = NV_DEVICE, - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = _nvkm_parent_dtor, - .init = nvkm_udevice_init, - .fini = nvkm_udevice_fini, - .mthd = nvkm_udevice_mthd, - .map = nvkm_udevice_map, - .rd08 = nvkm_udevice_rd08, - .rd16 = nvkm_udevice_rd16, - .rd32 = nvkm_udevice_rd32, - .wr08 = nvkm_udevice_wr08, - .wr16 = nvkm_udevice_wr16, - .wr32 = nvkm_udevice_wr32, +static int +nvkm_udevice_child_old(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_object *parent = oclass->parent; + struct nvkm_engine *engine = oclass->engine; + struct nvkm_oclass *eclass = (void *)oclass->priv; + struct nvkm_object *engctx = NULL; + int ret; + + if (engine->cclass) { + ret = nvkm_object_old(parent, &engine->subdev.object, + engine->cclass, NULL, 0, &engctx); + if (ret) + return ret; + } else { + nvkm_object_ref(parent, &engctx); } -}; + + ret = nvkm_object_old(engctx, &engine->subdev.object, eclass, + data, size, pobject); + nvkm_object_ref(NULL, &engctx); + return ret; +} static int -nvkm_udevice_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, +nvkm_udevice_child_new(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_udevice *udev = nvkm_udevice(oclass->parent); + const struct nvkm_oclass *sclass = oclass->priv; + return nvkm_object_old(&udev->object, NULL, + (struct nvkm_oclass *)sclass, + data, size, pobject); +} + +static int +nvkm_udevice_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + struct nvkm_udevice *udev = nvkm_udevice(object); + struct nvkm_device *device = udev->device; + struct nvkm_engine *engine; + u64 mask = (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_FIFO) | + (1ULL << NVDEV_ENGINE_DISP) | + (1ULL << NVDEV_ENGINE_PM); + int i; + + for (; i = __ffs64(mask), mask; mask &= ~(1ULL << i)) { + if ((engine = nvkm_device_engine(device, i))) { + struct nvkm_oclass *sclass = engine->sclass; + int c = 0; + while (sclass && sclass->ofuncs) { + if (c++ == index) { + oclass->base.oclass = sclass->handle; + oclass->base.minver = -2; + oclass->base.maxver = -2; + oclass->ctor = nvkm_udevice_child_old; + oclass->priv = sclass; + oclass->engine = engine; + return 0; + } + sclass++; + } + index -= c; + } + } + + if (index == 0) { + oclass->ctor = nvkm_udevice_child_new; + oclass->base.oclass = nvkm_control_oclass[0].handle; + oclass->base.minver = -2; + oclass->base.maxver = -2; + oclass->priv = &nvkm_control_oclass[0]; + return 0; + } + + return -EINVAL; +} + +static const struct nvkm_object_func +nvkm_udevice_super = { + .init = nvkm_udevice_init, + .fini = nvkm_udevice_fini, + .mthd = nvkm_udevice_mthd, + .map = nvkm_udevice_map, + .rd08 = nvkm_udevice_rd08, + .rd16 = nvkm_udevice_rd16, + .rd32 = nvkm_udevice_rd32, + .wr08 = nvkm_udevice_wr08, + .wr16 = nvkm_udevice_wr16, + .wr32 = nvkm_udevice_wr32, + .sclass = nvkm_udevice_child_get, +}; + +static const struct nvkm_object_func +nvkm_udevice = { + .init = nvkm_udevice_init, + .fini = nvkm_udevice_fini, + .mthd = nvkm_udevice_mthd, + .sclass = nvkm_udevice_child_get, +}; + +int +nvkm_udevice_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { struct nv_device_v0 v0; } *args = data; - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_device *device; + struct nvkm_client *client = oclass->client; + struct nvkm_object *parent = &client->object; + const struct nvkm_object_func *func; struct nvkm_udevice *udev; int ret; @@ -279,34 +376,30 @@ nvkm_udevice_ctor(struct nvkm_object *parent, struct nvkm_object *engine, /* give priviledged clients register access */ if (client->super) - oclass = &nvkm_udevice_oclass_super; + func = &nvkm_udevice_super; + else + func = &nvkm_udevice; - /* find the device subdev that matches what the client requested */ + if (!(udev = kzalloc(sizeof(*udev), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(func, oclass, &udev->object); + *pobject = &udev->object; + + /* find the device that matches what the client requested */ if (args->v0.device != ~0) - device = nvkm_device_find(args->v0.device); + udev->device = nvkm_device_find(args->v0.device); else - device = nvkm_device_find(client->device); - if (!device) + udev->device = nvkm_device_find(client->device); + if (!udev->device) return -ENODEV; - ret = nvkm_parent_create(parent, NULL, oclass, 0, nvkm_control_oclass, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_FIFO) | - (1ULL << NVDEV_ENGINE_DISP) | - (1ULL << NVDEV_ENGINE_PM), &udev); - *pobject = nv_object(udev); - if (ret) - return ret; - - udev->device = device; return 0; } -struct nvkm_ofuncs -nvkm_udevice_ofuncs = { - .ctor = nvkm_udevice_ctor, - .dtor = _nvkm_parent_dtor, - .init = nvkm_udevice_init, - .fini = nvkm_udevice_fini, - .mthd = nvkm_udevice_mthd, +const struct nvkm_sclass +nvkm_udevice_sclass = { + .oclass = NV_DEVICE, + .minver = 0, + .maxver = 0, + .ctor = nvkm_udevice_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index a3632d4b05d4c..8743972009dc2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -1300,7 +1300,7 @@ nv50_disp_data_ctor(struct nvkm_object *parent, int ret; /* no context needed for channel objects... */ - if (nv_mclass(parent) != NV_DEVICE) { + if (parent->parent != &nvkm_client(parent)->object) { atomic_inc(&parent->refcount); *pobject = parent; return 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c index 7f9870789a0f3..62f627360c875 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c @@ -66,7 +66,7 @@ nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *pargpu, struct nvkm_object *parent = (void *)pargpu; struct hack *object; - if (nv_mclass(parent->parent) == NV_DEVICE) { + if (parent->parent->parent == &nvkm_client(parent)->object) { /* delayed, or no, binding */ return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index ae84db1f296bc..90a7d89cc019b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -656,7 +656,7 @@ nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int ret; /* no context needed for perfdom objects... */ - if (nv_mclass(parent) != NV_DEVICE) { + if (parent->parent != &nvkm_client(parent)->object) { atomic_inc(&parent->refcount); *pobject = parent; return 1; -- GitLab From 0e29998a89a6254f5ca9f78167f9ce790d01da45 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5513/7006] drm/nouveau/device: convert ctrl class to new-style nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 6 ++ .../gpu/drm/nouveau/nvkm/engine/device/ctrl.c | 74 +++++++++++-------- .../gpu/drm/nouveau/nvkm/engine/device/ctrl.h | 12 +++ .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 2 - .../gpu/drm/nouveau/nvkm/engine/device/user.c | 24 +++--- 5 files changed, 73 insertions(+), 45 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 2467d4e0acf67..334d64dbb6413 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -274,6 +274,12 @@ enum nv_bus_type { void nvkm_device_del(struct nvkm_device **); +struct nvkm_device_oclass { + int (*ctor)(struct nvkm_device *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; + extern const struct nvkm_sclass nvkm_udevice_sclass; /* device logging */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c index 0abee2d21a78f..f24990a8d60b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "ctrl.h" #include #include @@ -31,17 +31,17 @@ #include static int -nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size) +nvkm_control_mthd_pstate_info(struct nvkm_control *ctrl, void *data, u32 size) { union { struct nvif_control_pstate_info_v0 v0; } *args = data; - struct nvkm_clk *clk = nvkm_clk(object); + struct nvkm_clk *clk = ctrl->device->clk; int ret; - nvif_ioctl(object, "control pstate info size %d\n", size); + nvif_ioctl(&ctrl->object, "control pstate info size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "control pstate info vers %d\n", + nvif_ioctl(&ctrl->object, "control pstate info vers %d\n", args->v0.version); } else return ret; @@ -64,12 +64,12 @@ nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) +nvkm_control_mthd_pstate_attr(struct nvkm_control *ctrl, void *data, u32 size) { union { struct nvif_control_pstate_attr_v0 v0; } *args = data; - struct nvkm_clk *clk = nvkm_clk(object); + struct nvkm_clk *clk = ctrl->device->clk; struct nvkm_domain *domain; struct nvkm_pstate *pstate; struct nvkm_cstate *cstate; @@ -77,10 +77,10 @@ nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) u32 lo, hi; int ret; - nvif_ioctl(object, "control pstate attr size %d\n", size); + nvif_ioctl(&ctrl->object, "control pstate attr size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "control pstate attr vers %d state %d " - "index %d\n", + nvif_ioctl(&ctrl->object, + "control pstate attr vers %d state %d index %d\n", args->v0.version, args->v0.state, args->v0.index); if (!clk) return -ENODEV; @@ -137,19 +137,19 @@ nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size) +nvkm_control_mthd_pstate_user(struct nvkm_control *ctrl, void *data, u32 size) { union { struct nvif_control_pstate_user_v0 v0; } *args = data; - struct nvkm_clk *clk = nvkm_clk(object); + struct nvkm_clk *clk = ctrl->device->clk; int ret; - nvif_ioctl(object, "control pstate user size %d\n", size); + nvif_ioctl(&ctrl->object, "control pstate user size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "control pstate user vers %d ustate %d " - "pwrsrc %d\n", args->v0.version, - args->v0.ustate, args->v0.pwrsrc); + nvif_ioctl(&ctrl->object, + "control pstate user vers %d ustate %d pwrsrc %d\n", + args->v0.version, args->v0.ustate, args->v0.pwrsrc); if (!clk) return -ENODEV; } else @@ -168,32 +168,44 @@ nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size) static int nvkm_control_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { + struct nvkm_control *ctrl = nvkm_control(object); switch (mthd) { case NVIF_CONTROL_PSTATE_INFO: - return nvkm_control_mthd_pstate_info(object, data, size); + return nvkm_control_mthd_pstate_info(ctrl, data, size); case NVIF_CONTROL_PSTATE_ATTR: - return nvkm_control_mthd_pstate_attr(object, data, size); + return nvkm_control_mthd_pstate_attr(ctrl, data, size); case NVIF_CONTROL_PSTATE_USER: - return nvkm_control_mthd_pstate_user(object, data, size); + return nvkm_control_mthd_pstate_user(ctrl, data, size); default: break; } return -EINVAL; } -static struct nvkm_ofuncs -nvkm_control_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, +static const struct nvkm_object_func +nvkm_control = { .mthd = nvkm_control_mthd, }; -struct nvkm_oclass -nvkm_control_oclass[] = { - { .handle = NVIF_IOCTL_NEW_V0_CONTROL, - .ofuncs = &nvkm_control_ofuncs - }, - {} +static int +nvkm_control_new(struct nvkm_device *device, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nvkm_control *ctrl; + + if (!(ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL))) + return -ENOMEM; + *pobject = &ctrl->object; + ctrl->device = device; + + nvkm_object_ctor(&nvkm_control, oclass, &ctrl->object); + return 0; +} + +const struct nvkm_device_oclass +nvkm_control_oclass = { + .base.oclass = NVIF_IOCTL_NEW_V0_CONTROL, + .base.minver = -1, + .base.maxver = -1, + .ctor = nvkm_control_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h new file mode 100644 index 0000000000000..20249d8e444de --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.h @@ -0,0 +1,12 @@ +#ifndef __NVKM_DEVICE_CTRL_H__ +#define __NVKM_DEVICE_CTRL_H__ +#define nvkm_control(p) container_of((p), struct nvkm_control, object) +#include + +struct nvkm_control { + struct nvkm_object object; + struct nvkm_device *device; +}; + +extern const struct nvkm_device_oclass nvkm_control_oclass; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 59e9026624080..76b441ddc7133 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -47,8 +47,6 @@ int nvkm_device_ctor(const struct nvkm_device_func *, int nvkm_device_init(struct nvkm_device *); int nvkm_device_fini(struct nvkm_device *, bool suspend); -extern struct nvkm_oclass nvkm_control_oclass[]; - int nv04_identify(struct nvkm_device *); int nv10_identify(struct nvkm_device *); int nv20_identify(struct nvkm_device *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index fb4d04dc9340f..d9d15385d0ad9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -23,6 +23,7 @@ */ #define nvkm_udevice(p) container_of((p), struct nvkm_udevice, object) #include "priv.h" +#include "ctrl.h" #include #include @@ -280,10 +281,8 @@ nvkm_udevice_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { struct nvkm_udevice *udev = nvkm_udevice(oclass->parent); - const struct nvkm_oclass *sclass = oclass->priv; - return nvkm_object_old(&udev->object, NULL, - (struct nvkm_oclass *)sclass, - data, size, pobject); + const struct nvkm_device_oclass *sclass = oclass->priv; + return sclass->ctor(udev->device, oclass, data, size, pobject); } static int @@ -297,6 +296,7 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, (1ULL << NVDEV_ENGINE_FIFO) | (1ULL << NVDEV_ENGINE_DISP) | (1ULL << NVDEV_ENGINE_PM); + const struct nvkm_device_oclass *sclass; int i; for (; i = __ffs64(mask), mask; mask &= ~(1ULL << i)) { @@ -319,16 +319,16 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, } } - if (index == 0) { - oclass->ctor = nvkm_udevice_child_new; - oclass->base.oclass = nvkm_control_oclass[0].handle; - oclass->base.minver = -2; - oclass->base.maxver = -2; - oclass->priv = &nvkm_control_oclass[0]; - return 0; + switch (index) { + case 0: sclass = &nvkm_control_oclass; break; + default: + return -EINVAL; } - return -EINVAL; + oclass->ctor = nvkm_udevice_child_new; + oclass->base = sclass->base; + oclass->priv = sclass; + return 0; } static const struct nvkm_object_func -- GitLab From 19fef52d93518cc01fd284b55ee93c0a9967634f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5514/7006] drm/nouveau/dma: split user classes out from engine implementations Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 4 +- .../include/nvkm/engine/{dmaobj.h => dma.h} | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/Kbuild | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 4 - .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/dma/Kbuild | 11 ++ .../gpu/drm/nouveau/nvkm/engine/dma/base.c | 110 ++++++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/dma/gf100.c | 38 ++++++ .../gpu/drm/nouveau/nvkm/engine/dma/gf110.c | 38 ++++++ .../gpu/drm/nouveau/nvkm/engine/dma/nv04.c | 38 ++++++ .../gpu/drm/nouveau/nvkm/engine/dma/nv50.c | 38 ++++++ .../gpu/drm/nouveau/nvkm/engine/dma/priv.h | 18 +++ .../nvkm/engine/{dmaobj/base.c => dma/user.c} | 86 +------------- .../gpu/drm/nouveau/nvkm/engine/dma/user.h | 29 +++++ .../{dmaobj/gf100.c => dma/usergf100.c} | 21 +--- .../{dmaobj/gf110.c => dma/usergf110.c} | 21 +--- .../engine/{dmaobj/nv04.c => dma/usernv04.c} | 21 +--- .../engine/{dmaobj/nv50.c => dma/usernv50.c} | 21 +--- .../gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild | 5 - .../gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h | 28 ----- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 8 +- 22 files changed, 349 insertions(+), 202 deletions(-) rename drivers/gpu/drm/nouveau/include/nvkm/engine/{dmaobj.h => dma.h} (88%) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h rename drivers/gpu/drm/nouveau/nvkm/engine/{dmaobj/base.c => dma/user.c} (63%) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h rename drivers/gpu/drm/nouveau/nvkm/engine/{dmaobj/gf100.c => dma/usergf100.c} (90%) rename drivers/gpu/drm/nouveau/nvkm/engine/{dmaobj/gf110.c => dma/usergf110.c} (89%) rename drivers/gpu/drm/nouveau/nvkm/engine/{dmaobj/nv04.c => dma/usernv04.c} (90%) rename drivers/gpu/drm/nouveau/nvkm/engine/{dmaobj/nv50.c => dma/usernv50.c} (91%) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 334d64dbb6413..1d72d670bed27 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -133,7 +133,7 @@ struct nvkm_device { struct nvkm_engine *ce[3]; struct nvkm_engine *cipher; struct nvkm_disp *disp; - struct nvkm_dmaeng *dma; + struct nvkm_dma *dma; struct nvkm_fifo *fifo; struct nvkm_gr *gr; struct nvkm_engine *ifb; @@ -193,7 +193,7 @@ struct nvkm_device_chip { int (*ce[3] )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*cipher )(struct nvkm_device *, int idx, struct nvkm_engine **); int (*disp )(struct nvkm_device *, int idx, struct nvkm_disp **); - int (*dma )(struct nvkm_device *, int idx, struct nvkm_dmaeng **); + int (*dma )(struct nvkm_device *, int idx, struct nvkm_dma **); int (*fifo )(struct nvkm_device *, int idx, struct nvkm_fifo **); int (*gr )(struct nvkm_device *, int idx, struct nvkm_gr **); int (*ifb )(struct nvkm_device *, int idx, struct nvkm_engine **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h similarity index 88% rename from drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h rename to drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h index 343d2d73cd943..5f461e95987e8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h @@ -1,5 +1,5 @@ -#ifndef __NVKM_DMAOBJ_H__ -#define __NVKM_DMAOBJ_H__ +#ifndef __NVKM_DMA_H__ +#define __NVKM_DMA_H__ #include struct nvkm_gpuobj; @@ -11,7 +11,7 @@ struct nvkm_dmaobj { u64 limit; }; -struct nvkm_dmaeng { +struct nvkm_dma { struct nvkm_engine engine; /* creates a "physical" dma object from a struct nvkm_dmaobj */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild index 6bd3d756f32c9..36f724763fde5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild @@ -6,7 +6,7 @@ include $(src)/nvkm/engine/ce/Kbuild include $(src)/nvkm/engine/cipher/Kbuild include $(src)/nvkm/engine/device/Kbuild include $(src)/nvkm/engine/disp/Kbuild -include $(src)/nvkm/engine/dmaobj/Kbuild +include $(src)/nvkm/engine/dma/Kbuild include $(src)/nvkm/engine/fifo/Kbuild include $(src)/nvkm/engine/gr/Kbuild include $(src)/nvkm/engine/mpeg/Kbuild diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 76b441ddc7133..4cf483894af01 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index d9d15385d0ad9..58a09f828b7fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -30,10 +30,6 @@ #include #include #include -#include -#include -#include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 8743972009dc2..12b835fee0d52 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild new file mode 100644 index 0000000000000..bb3a0528b6b59 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild @@ -0,0 +1,11 @@ +nvkm-y += nvkm/engine/dma/base.o +nvkm-y += nvkm/engine/dma/nv04.o +nvkm-y += nvkm/engine/dma/nv50.o +nvkm-y += nvkm/engine/dma/gf100.o +nvkm-y += nvkm/engine/dma/gf110.o + +nvkm-y += nvkm/engine/dma/user.o +nvkm-y += nvkm/engine/dma/usernv04.o +nvkm-y += nvkm/engine/dma/usernv50.o +nvkm-y += nvkm/engine/dma/usergf100.o +nvkm-y += nvkm/engine/dma/usergf110.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c new file mode 100644 index 0000000000000..a48978d398435 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c @@ -0,0 +1,110 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +#include +#include + +struct hack { + struct nvkm_gpuobj object; + struct nvkm_gpuobj *parent; +}; + +static void +dtor(struct nvkm_object *object) +{ + struct hack *hack = (void *)object; + nvkm_gpuobj_del(&hack->parent); + nvkm_object_destroy(&hack->object.object); +} + +static struct nvkm_oclass +hack = { + .handle = NV_GPUOBJ_CLASS, + .ofuncs = &(struct nvkm_ofuncs) { + .dtor = dtor, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, + }, +}; + +static int +nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *pargpu, + struct nvkm_gpuobj **pgpuobj) +{ + const struct nvkm_dma_impl *impl = (void *) + nv_oclass(nv_object(dmaobj)->engine); + int ret = 0; + + if (&dmaobj->base == &pargpu->object) { /* ctor bind */ + struct nvkm_object *parent = (void *)pargpu; + struct hack *object; + + if (parent->parent->parent == &nvkm_client(parent)->object) { + /* delayed, or no, binding */ + return 0; + } + + pargpu = (void *)nv_pclass((void *)pargpu, NV_GPUOBJ_CLASS); + + ret = nvkm_object_create(parent, NULL, &hack, NV_GPUOBJ_CLASS, &object); + if (ret == 0) { + nvkm_object_ref(NULL, &parent); + *pgpuobj = &object->object; + + ret = impl->bind(dmaobj, pargpu, &object->parent); + if (ret) + return ret; + + object->object.node = object->parent->node; + object->object.addr = object->parent->addr; + object->object.size = object->parent->size; + return 0; + } + + return ret; + } + + return impl->bind(dmaobj, pargpu, pgpuobj); +} + +int +_nvkm_dma_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + const struct nvkm_dma_impl *impl = (void *)oclass; + struct nvkm_dma *dmaeng; + int ret; + + ret = nvkm_engine_create(parent, engine, oclass, true, "DMAOBJ", + "dmaobj", &dmaeng); + *pobject = nv_object(dmaeng); + if (ret) + return ret; + + nv_engine(dmaeng)->sclass = impl->sclass; + dmaeng->bind = nvkm_dmaobj_bind; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c new file mode 100644 index 0000000000000..cb5c6adb8048e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "user.h" + +struct nvkm_oclass * +gf100_dmaeng_oclass = &(struct nvkm_dma_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0xc0), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = _nvkm_dma_ctor, + .dtor = _nvkm_dma_dtor, + .init = _nvkm_dma_init, + .fini = _nvkm_dma_fini, + }, + .sclass = gf100_dmaeng_sclass, + .bind = gf100_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c new file mode 100644 index 0000000000000..9a93ec6924f90 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "user.h" + +struct nvkm_oclass * +gf110_dmaeng_oclass = &(struct nvkm_dma_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0xd0), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = _nvkm_dma_ctor, + .dtor = _nvkm_dma_dtor, + .init = _nvkm_dma_init, + .fini = _nvkm_dma_fini, + }, + .sclass = gf110_dmaeng_sclass, + .bind = gf110_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c new file mode 100644 index 0000000000000..32bccdc57d2db --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "user.h" + +struct nvkm_oclass * +nv04_dmaeng_oclass = &(struct nvkm_dma_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0x04), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = _nvkm_dma_ctor, + .dtor = _nvkm_dma_dtor, + .init = _nvkm_dma_init, + .fini = _nvkm_dma_fini, + }, + .sclass = nv04_dmaeng_sclass, + .bind = nv04_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c new file mode 100644 index 0000000000000..20346d635c9c3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c @@ -0,0 +1,38 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "user.h" + +struct nvkm_oclass * +nv50_dmaeng_oclass = &(struct nvkm_dma_impl) { + .base.handle = NV_ENGINE(DMAOBJ, 0x50), + .base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = _nvkm_dma_ctor, + .dtor = _nvkm_dma_dtor, + .init = _nvkm_dma_init, + .fini = _nvkm_dma_fini, + }, + .sclass = nv50_dmaeng_sclass, + .bind = nv50_dmaobj_bind, +}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h new file mode 100644 index 0000000000000..fb2f7eced0cf4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_DMA_PRIV_H__ +#define __NVKM_DMA_PRIV_H__ +#include + +int _nvkm_dma_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void *, u32, + struct nvkm_object **); +#define _nvkm_dma_dtor _nvkm_engine_dtor +#define _nvkm_dma_init _nvkm_engine_init +#define _nvkm_dma_fini _nvkm_engine_fini + +struct nvkm_dma_impl { + struct nvkm_oclass base; + struct nvkm_oclass *sclass; + int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, + struct nvkm_gpuobj **); +}; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c similarity index 63% rename from drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c index 62f627360c875..11571dbd9e917 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c @@ -21,79 +21,15 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "user.h" #include -#include #include #include #include #include -struct hack { - struct nvkm_gpuobj object; - struct nvkm_gpuobj *parent; -}; - -static void -dtor(struct nvkm_object *object) -{ - struct hack *hack = (void *)object; - nvkm_gpuobj_del(&hack->parent); - nvkm_object_destroy(&hack->object.object); -} - -static struct nvkm_oclass -hack = { - .handle = NV_GPUOBJ_CLASS, - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = dtor, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - }, -}; - -static int -nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *pargpu, - struct nvkm_gpuobj **pgpuobj) -{ - const struct nvkm_dmaeng_impl *impl = (void *) - nv_oclass(nv_object(dmaobj)->engine); - int ret = 0; - - if (&dmaobj->base == &pargpu->object) { /* ctor bind */ - struct nvkm_object *parent = (void *)pargpu; - struct hack *object; - - if (parent->parent->parent == &nvkm_client(parent)->object) { - /* delayed, or no, binding */ - return 0; - } - - pargpu = (void *)nv_pclass((void *)pargpu, NV_GPUOBJ_CLASS); - - ret = nvkm_object_create(parent, NULL, &hack, NV_GPUOBJ_CLASS, &object); - if (ret == 0) { - nvkm_object_ref(NULL, &parent); - *pgpuobj = &object->object; - - ret = impl->bind(dmaobj, pargpu, &object->parent); - if (ret) - return ret; - - object->object.node = object->parent->node; - object->object.addr = object->parent->addr; - object->object.size = object->parent->size; - return 0; - } - - return ret; - } - - return impl->bind(dmaobj, pargpu, pgpuobj); -} - int nvkm_dmaobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, @@ -183,23 +119,3 @@ nvkm_dmaobj_create_(struct nvkm_object *parent, return ret; } - -int -_nvkm_dmaeng_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - const struct nvkm_dmaeng_impl *impl = (void *)oclass; - struct nvkm_dmaeng *dmaeng; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, "DMAOBJ", - "dmaobj", &dmaeng); - *pobject = nv_object(dmaeng); - if (ret) - return ret; - - nv_engine(dmaeng)->sclass = impl->sclass; - dmaeng->bind = nvkm_dmaobj_bind; - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h new file mode 100644 index 0000000000000..83dc1d621e3dc --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h @@ -0,0 +1,29 @@ +#ifndef __NVKM_DMA_USER_H__ +#define __NVKM_DMA_USER_H__ +#include "priv.h" + +#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \ + nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d) + +int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void **, u32 *, + int, void **); +#define _nvkm_dmaobj_dtor nvkm_object_destroy +#define _nvkm_dmaobj_init _nvkm_object_init +#define _nvkm_dmaobj_fini _nvkm_object_fini + +extern struct nvkm_oclass nv04_dmaeng_sclass[]; +extern struct nvkm_oclass nv50_dmaeng_sclass[]; +extern struct nvkm_oclass gf100_dmaeng_sclass[]; +extern struct nvkm_oclass gf110_dmaeng_sclass[]; + +int nv04_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, + struct nvkm_gpuobj **); +int nv50_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, + struct nvkm_gpuobj **); +int gf100_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, + struct nvkm_gpuobj **); +int gf110_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, + struct nvkm_gpuobj **); + +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c similarity index 90% rename from drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c index 96a604de4b632..3f2d7d93f026a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "user.h" #include #include @@ -36,7 +36,7 @@ struct gf100_dmaobj { u32 flags5; }; -static int +int gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { @@ -65,7 +65,7 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_dmaeng *dmaeng = (void *)engine; + struct nvkm_dma *dmaeng = (void *)engine; union { struct gf100_dma_v0 v0; } *args; @@ -146,23 +146,10 @@ gf100_dmaobj_ofuncs = { .fini = _nvkm_dmaobj_fini, }; -static struct nvkm_oclass +struct nvkm_oclass gf100_dmaeng_sclass[] = { { NV_DMA_FROM_MEMORY, &gf100_dmaobj_ofuncs }, { NV_DMA_TO_MEMORY, &gf100_dmaobj_ofuncs }, { NV_DMA_IN_MEMORY, &gf100_dmaobj_ofuncs }, {} }; - -struct nvkm_oclass * -gf100_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = gf100_dmaeng_sclass, - .bind = gf100_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c similarity index 89% rename from drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c index 017c7a2affe51..db22a8b2033c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "user.h" #include #include @@ -35,7 +35,7 @@ struct gf110_dmaobj { u32 flags0; }; -static int +int gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { @@ -63,7 +63,7 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_dmaeng *dmaeng = (void *)engine; + struct nvkm_dma *dmaeng = (void *)engine; union { struct gf110_dma_v0 v0; } *args; @@ -128,23 +128,10 @@ gf110_dmaobj_ofuncs = { .fini = _nvkm_dmaobj_fini, }; -static struct nvkm_oclass +struct nvkm_oclass gf110_dmaeng_sclass[] = { { NV_DMA_FROM_MEMORY, &gf110_dmaobj_ofuncs }, { NV_DMA_TO_MEMORY, &gf110_dmaobj_ofuncs }, { NV_DMA_IN_MEMORY, &gf110_dmaobj_ofuncs }, {} }; - -struct nvkm_oclass * -gf110_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = gf110_dmaeng_sclass, - .bind = gf110_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c similarity index 90% rename from drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c index 6be2dfc70cb71..bd8ca8ec09b69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "user.h" #include #include @@ -36,7 +36,7 @@ struct nv04_dmaobj { u32 flags2; }; -static int +int nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { @@ -76,7 +76,7 @@ nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_dmaeng *dmaeng = (void *)engine; + struct nvkm_dma *dmaeng = (void *)engine; struct nv04_mmu *mmu = nv04_mmu(engine); struct nv04_dmaobj *dmaobj; int ret; @@ -132,23 +132,10 @@ nv04_dmaobj_ofuncs = { .fini = _nvkm_dmaobj_fini, }; -static struct nvkm_oclass +struct nvkm_oclass nv04_dmaeng_sclass[] = { { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs }, { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs }, { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs }, {} }; - -struct nvkm_oclass * -nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = nv04_dmaeng_sclass, - .bind = nv04_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c similarity index 91% rename from drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c index f87134ec5b341..fd99b1e151430 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "user.h" #include #include @@ -36,7 +36,7 @@ struct nv50_dmaobj { u32 flags5; }; -static int +int nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, struct nvkm_gpuobj **pgpuobj) { @@ -65,7 +65,7 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_dmaeng *dmaeng = (void *)engine; + struct nvkm_dma *dmaeng = (void *)engine; union { struct nv50_dma_v0 v0; } *args; @@ -152,23 +152,10 @@ nv50_dmaobj_ofuncs = { .fini = _nvkm_dmaobj_fini, }; -static struct nvkm_oclass +struct nvkm_oclass nv50_dmaeng_sclass[] = { { NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs }, { NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs }, { NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs }, {} }; - -struct nvkm_oclass * -nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dmaeng_ctor, - .dtor = _nvkm_dmaeng_dtor, - .init = _nvkm_dmaeng_init, - .fini = _nvkm_dmaeng_fini, - }, - .sclass = nv50_dmaeng_sclass, - .bind = nv50_dmaobj_bind, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild deleted file mode 100644 index 7529632dbedb6..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild +++ /dev/null @@ -1,5 +0,0 @@ -nvkm-y += nvkm/engine/dmaobj/base.o -nvkm-y += nvkm/engine/dmaobj/nv04.o -nvkm-y += nvkm/engine/dmaobj/nv50.o -nvkm-y += nvkm/engine/dmaobj/gf100.o -nvkm-y += nvkm/engine/dmaobj/gf110.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h deleted file mode 100644 index 614d9e697bd42..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NVKM_DMAOBJ_PRIV_H__ -#define __NVKM_DMAOBJ_PRIV_H__ -#include - -#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \ - nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d) - -int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void **, u32 *, - int, void **); -#define _nvkm_dmaobj_dtor nvkm_object_destroy -#define _nvkm_dmaobj_init _nvkm_object_init -#define _nvkm_dmaobj_fini _nvkm_object_fini - -int _nvkm_dmaeng_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_dmaeng_dtor _nvkm_engine_dtor -#define _nvkm_dmaeng_init _nvkm_engine_init -#define _nvkm_dmaeng_fini _nvkm_engine_fini - -struct nvkm_dmaeng_impl { - struct nvkm_oclass base; - struct nvkm_oclass *sclass; - int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, - struct nvkm_gpuobj **); -}; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 60e5fab4c80a3..a3b663832dbf6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include @@ -104,7 +104,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, struct nvkm_fifo *fifo = (void *)engine; struct nvkm_fifo_base *base = (void *)parent; struct nvkm_fifo_chan *chan; - struct nvkm_dmaeng *dmaeng; + struct nvkm_dma *dma; struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; unsigned long flags; @@ -124,7 +124,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return -ENOENT; dmaobj = (void *)handle->object; - dmaeng = (void *)dmaobj->base.engine; + dma = (void *)dmaobj->base.engine; switch (dmaobj->base.oclass->handle) { case NV_DMA_FROM_MEMORY: case NV_DMA_IN_MEMORY: @@ -133,7 +133,7 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, return -EINVAL; } - ret = dmaeng->bind(dmaobj, &base->gpuobj, &chan->pushgpu); + ret = dma->bind(dmaobj, &base->gpuobj, &chan->pushgpu); if (ret) return ret; } -- GitLab From 0710cc31482ae3711367c42e61580126c50c8ec0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:18 +1000 Subject: [PATCH 5515/7006] drm/nouveau/dma: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/client.h | 1 + .../gpu/drm/nouveau/include/nvkm/engine/dma.h | 21 +- drivers/gpu/drm/nouveau/nvkm/core/client.c | 1 + .../gpu/drm/nouveau/nvkm/engine/device/user.c | 27 ++- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 31 ++- .../gpu/drm/nouveau/nvkm/engine/dma/base.c | 195 ++++++++++++++---- .../gpu/drm/nouveau/nvkm/engine/dma/gf100.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/dma/gf110.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/dma/nv04.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/dma/nv50.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/dma/priv.h | 3 + .../gpu/drm/nouveau/nvkm/engine/dma/user.c | 49 +++-- .../gpu/drm/nouveau/nvkm/engine/dma/user.h | 35 ++-- .../drm/nouveau/nvkm/engine/dma/usergf100.c | 58 +++--- .../drm/nouveau/nvkm/engine/dma/usergf110.c | 54 +++-- .../drm/nouveau/nvkm/engine/dma/usernv04.c | 60 +++--- .../drm/nouveau/nvkm/engine/dma/usernv50.c | 59 +++--- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 20 +- 18 files changed, 362 insertions(+), 264 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 4bb0acca8650a..7ec1762a0ec1d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -10,6 +10,7 @@ struct nvkm_client { struct nvkm_client_notify *notify[16]; struct rb_root objroot; + struct rb_root dmaroot; struct nvkm_handle *root; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h index 5f461e95987e8..7439a02bf7c9b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h @@ -1,24 +1,35 @@ #ifndef __NVKM_DMA_H__ #define __NVKM_DMA_H__ #include +struct nvkm_client; struct nvkm_gpuobj; struct nvkm_dmaobj { - struct nvkm_object base; + const struct nvkm_dmaobj_func *func; + struct nvkm_dma *dma; + + struct nvkm_object object; u32 target; u32 access; u64 start; u64 limit; + + struct rb_node rb; + u64 handle; /*XXX HANDLE MERGE */ +}; + +struct nvkm_dmaobj_func { + int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, int align, + struct nvkm_gpuobj **); }; struct nvkm_dma { struct nvkm_engine engine; - - /* creates a "physical" dma object from a struct nvkm_dmaobj */ - int (*bind)(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *parent, - struct nvkm_gpuobj **); }; +struct nvkm_dmaobj * +nvkm_dma_search(struct nvkm_dma *, struct nvkm_client *, u64 object); + extern struct nvkm_oclass *nv04_dmaeng_oclass; extern struct nvkm_oclass *nv50_dmaeng_oclass; extern struct nvkm_oclass *gf100_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index dce1d45cac5ef..910f736cd1b6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -314,6 +314,7 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, client->device = device; client->debug = nvkm_dbgopt(dbg, "CLIENT"); client->objroot = RB_ROOT; + client->dmaroot = RB_ROOT; ret = nvkm_handle_create(NULL, ~0, &client->object, &client->root); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 58a09f828b7fc..39f31e2e281bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -292,11 +292,12 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, (1ULL << NVDEV_ENGINE_FIFO) | (1ULL << NVDEV_ENGINE_DISP) | (1ULL << NVDEV_ENGINE_PM); - const struct nvkm_device_oclass *sclass; + const struct nvkm_device_oclass *sclass = NULL; int i; - for (; i = __ffs64(mask), mask; mask &= ~(1ULL << i)) { - if ((engine = nvkm_device_engine(device, i))) { + for (; i = __ffs64(mask), mask && !sclass; mask &= ~(1ULL << i)) { + if ((engine = nvkm_device_engine(device, i)) && + !engine->func) { struct nvkm_oclass *sclass = engine->sclass; int c = 0; while (sclass && sclass->ofuncs) { @@ -312,17 +313,27 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, sclass++; } index -= c; + continue; } + + if (!(engine = nvkm_device_engine(device, i)) || + !(engine->func->base.sclass)) + continue; + oclass->engine = engine; + + index -= engine->func->base.sclass(oclass, index, &sclass); } - switch (index) { - case 0: sclass = &nvkm_control_oclass; break; - default: - return -EINVAL; + if (!sclass) { + switch (index) { + case 0: sclass = &nvkm_control_oclass; break; + default: + return -EINVAL; + } + oclass->base = sclass->base; } oclass->ctor = nvkm_udevice_child_new; - oclass->base = sclass->base; oclass->priv = sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 12b835fee0d52..36241cf9173e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -209,8 +209,9 @@ nv50_disp_dmac_create_(struct nvkm_object *parent, struct nvkm_oclass *oclass, u64 pushbuf, int head, int length, void **pobject) { + struct nvkm_device *device = parent->engine->subdev.device; struct nvkm_client *client = nvkm_client(parent); - struct nvkm_handle *handle; + struct nvkm_dma *dma = device->dma; struct nvkm_dmaobj *dmaobj; struct nv50_disp_dmac *dmac; int ret; @@ -221,27 +222,19 @@ nv50_disp_dmac_create_(struct nvkm_object *parent, if (ret) return ret; - handle = nvkm_client_search(client, pushbuf); - if (!handle) + dmaobj = nvkm_dma_search(dma, client, pushbuf); + if (!dmaobj) return -ENOENT; - dmaobj = (void *)handle->object; - switch (nv_mclass(dmaobj)) { - case 0x0002: - case 0x003d: - if (dmaobj->limit - dmaobj->start != 0xfff) - return -EINVAL; + if (dmaobj->limit - dmaobj->start != 0xfff) + return -EINVAL; - switch (dmaobj->target) { - case NV_MEM_TARGET_VRAM: - dmac->push = 0x00000001 | dmaobj->start >> 8; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - dmac->push = 0x00000003 | dmaobj->start >> 8; - break; - default: - return -EINVAL; - } + switch (dmaobj->target) { + case NV_MEM_TARGET_VRAM: + dmac->push = 0x00000001 | dmaobj->start >> 8; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + dmac->push = 0x00000003 | dmaobj->start >> 8; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c index a48978d398435..57f6eca078ef6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c @@ -24,77 +24,182 @@ #include "priv.h" #include -#include -struct hack { - struct nvkm_gpuobj object; - struct nvkm_gpuobj *parent; +#include + +struct nvkm_dmaobj * +nvkm_dma_search(struct nvkm_dma *dma, struct nvkm_client *client, u64 object) +{ + struct rb_node *node = client->dmaroot.rb_node; + while (node) { + struct nvkm_dmaobj *dmaobj = + container_of(node, typeof(*dmaobj), rb); + if (object < dmaobj->handle) + node = node->rb_left; + else + if (object > dmaobj->handle) + node = node->rb_right; + else + return dmaobj; + } + return NULL; +} + +static int +nvkm_dma_oclass_new(struct nvkm_device *device, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_dma *dma = nvkm_dma(oclass->engine); + struct nvkm_dma_impl *impl = (void *)dma->engine.subdev.object.oclass; + struct nvkm_dmaobj *dmaobj = NULL; + struct nvkm_client *client = oclass->client; + struct rb_node **ptr = &client->dmaroot.rb_node; + struct rb_node *parent = NULL; + int ret; + + ret = impl->class_new(dma, oclass, data, size, &dmaobj); + if (dmaobj) + *pobject = &dmaobj->object; + if (ret) + return ret; + + dmaobj->handle = oclass->object; + + while (*ptr) { + struct nvkm_dmaobj *obj = container_of(*ptr, typeof(*obj), rb); + parent = *ptr; + if (dmaobj->handle < obj->handle) + ptr = &parent->rb_left; + else + if (dmaobj->handle > obj->handle) + ptr = &parent->rb_right; + else + return -EEXIST; + } + + rb_link_node(&dmaobj->rb, parent, ptr); + rb_insert_color(&dmaobj->rb, &client->dmaroot); + return 0; +} + +static const struct nvkm_device_oclass +nvkm_dma_oclass_base = { + .ctor = nvkm_dma_oclass_new, }; -static void -dtor(struct nvkm_object *object) +static const struct nvkm_sclass +nvkm_dma_sclass[] = { + { 0, 0, NV_DMA_FROM_MEMORY }, + { 0, 0, NV_DMA_TO_MEMORY }, + { 0, 0, NV_DMA_IN_MEMORY }, +}; + +static int +nvkm_dma_oclass_base_get(struct nvkm_oclass *sclass, int index, + const struct nvkm_device_oclass **class) { - struct hack *hack = (void *)object; - nvkm_gpuobj_del(&hack->parent); - nvkm_object_destroy(&hack->object.object); + const int count = ARRAY_SIZE(nvkm_dma_sclass); + if (index < count) { + const struct nvkm_sclass *oclass = &nvkm_dma_sclass[index]; + sclass->base = oclass[0]; + sclass->engn = oclass; + *class = &nvkm_dma_oclass_base; + return index; + } + return count; } -static struct nvkm_oclass -hack = { - .handle = NV_GPUOBJ_CLASS, +static const struct nvkm_engine_func +nvkm_dma = { + .base.sclass = nvkm_dma_oclass_base_get, +}; + +#include + +static struct nvkm_oclass empty = { .ofuncs = &(struct nvkm_ofuncs) { - .dtor = dtor, + .dtor = nvkm_object_destroy, .init = _nvkm_object_init, .fini = _nvkm_object_fini, }, }; static int -nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_gpuobj *pargpu, - struct nvkm_gpuobj **pgpuobj) +nvkm_dmaobj_compat_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { - const struct nvkm_dma_impl *impl = (void *) - nv_oclass(nv_object(dmaobj)->engine); - int ret = 0; + struct nvkm_oclass hack = { + .base.oclass = oclass->handle, + .client = nvkm_client(parent), + .parent = parent, + .engine = nv_engine(engine), + }; + struct nvkm_dma *dma = (void *)engine; + struct nvkm_dma_impl *impl = (void *)dma->engine.subdev.object.oclass; + struct nvkm_dmaobj *dmaobj = NULL; + struct nvkm_gpuobj *gpuobj; + int ret; - if (&dmaobj->base == &pargpu->object) { /* ctor bind */ - struct nvkm_object *parent = (void *)pargpu; - struct hack *object; + ret = impl->class_new(dma, &hack, data, size, &dmaobj); + if (dmaobj) + *pobject = &dmaobj->object; + if (ret) + return ret; - if (parent->parent->parent == &nvkm_client(parent)->object) { - /* delayed, or no, binding */ - return 0; - } + gpuobj = (void *)nv_pclass(parent, NV_GPUOBJ_CLASS); - pargpu = (void *)nv_pclass((void *)pargpu, NV_GPUOBJ_CLASS); + ret = dmaobj->func->bind(dmaobj, gpuobj, 16, &gpuobj); + nvkm_object_ref(NULL, pobject); + if (ret) + return ret; - ret = nvkm_object_create(parent, NULL, &hack, NV_GPUOBJ_CLASS, &object); - if (ret == 0) { - nvkm_object_ref(NULL, &parent); - *pgpuobj = &object->object; + ret = nvkm_object_create(parent, engine, &empty, 0, pobject); + if (ret) + return ret; - ret = impl->bind(dmaobj, pargpu, &object->parent); - if (ret) - return ret; + gpuobj->object.parent = *pobject; + gpuobj->object.engine = &dma->engine; + gpuobj->object.oclass = oclass; + gpuobj->object.pclass = NV_GPUOBJ_CLASS; +#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA + gpuobj->object._magic = NVKM_OBJECT_MAGIC; +#endif + *pobject = &gpuobj->object; + return 0; +} - object->object.node = object->parent->node; - object->object.addr = object->parent->addr; - object->object.size = object->parent->size; - return 0; - } +static void +nvkm_dmaobj_compat_dtor(struct nvkm_object *object) +{ + struct nvkm_object *parent = object->parent; + struct nvkm_gpuobj *gpuobj = (void *)object; + nvkm_gpuobj_del(&gpuobj); + nvkm_object_ref(NULL, &parent); +} - return ret; - } +static struct nvkm_ofuncs +nvkm_dmaobj_compat_ofuncs = { + .ctor = nvkm_dmaobj_compat_ctor, + .dtor = nvkm_dmaobj_compat_dtor, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, +}; - return impl->bind(dmaobj, pargpu, pgpuobj); -} +static struct nvkm_oclass +nvkm_dma_compat_sclass[] = { + { NV_DMA_FROM_MEMORY, &nvkm_dmaobj_compat_ofuncs }, + { NV_DMA_TO_MEMORY, &nvkm_dmaobj_compat_ofuncs }, + { NV_DMA_IN_MEMORY, &nvkm_dmaobj_compat_ofuncs }, + {} +}; int _nvkm_dma_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - const struct nvkm_dma_impl *impl = (void *)oclass; struct nvkm_dma *dmaeng; int ret; @@ -104,7 +209,7 @@ _nvkm_dma_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(dmaeng)->sclass = impl->sclass; - dmaeng->bind = nvkm_dmaobj_bind; + dmaeng->engine.sclass = nvkm_dma_compat_sclass; + dmaeng->engine.func = &nvkm_dma; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c index cb5c6adb8048e..81badf09eed86 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c @@ -33,6 +33,5 @@ gf100_dmaeng_oclass = &(struct nvkm_dma_impl) { .init = _nvkm_dma_init, .fini = _nvkm_dma_fini, }, - .sclass = gf100_dmaeng_sclass, - .bind = gf100_dmaobj_bind, + .class_new = gf100_dmaobj_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c index 9a93ec6924f90..79d869bf9a612 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c @@ -33,6 +33,5 @@ gf110_dmaeng_oclass = &(struct nvkm_dma_impl) { .init = _nvkm_dma_init, .fini = _nvkm_dma_fini, }, - .sclass = gf110_dmaeng_sclass, - .bind = gf110_dmaobj_bind, + .class_new = gf110_dmaobj_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c index 32bccdc57d2db..c116995f84946 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c @@ -33,6 +33,5 @@ nv04_dmaeng_oclass = &(struct nvkm_dma_impl) { .init = _nvkm_dma_init, .fini = _nvkm_dma_fini, }, - .sclass = nv04_dmaeng_sclass, - .bind = nv04_dmaobj_bind, + .class_new = nv04_dmaobj_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c index 20346d635c9c3..b8d87e7d6ed7d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c @@ -33,6 +33,5 @@ nv50_dmaeng_oclass = &(struct nvkm_dma_impl) { .init = _nvkm_dma_init, .fini = _nvkm_dma_fini, }, - .sclass = nv50_dmaeng_sclass, - .bind = nv50_dmaobj_bind, + .class_new = nv50_dmaobj_new, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h index fb2f7eced0cf4..fbff168e6cc8f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h @@ -1,5 +1,6 @@ #ifndef __NVKM_DMA_PRIV_H__ #define __NVKM_DMA_PRIV_H__ +#define nvkm_dma(p) container_of((p), struct nvkm_dma, engine) #include int _nvkm_dma_ctor(struct nvkm_object *, struct nvkm_object *, @@ -14,5 +15,7 @@ struct nvkm_dma_impl { struct nvkm_oclass *sclass; int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, struct nvkm_gpuobj **); + int (*class_new)(struct nvkm_dma *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_dmaobj **); }; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c index 11571dbd9e917..45ab062661a4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.c @@ -24,34 +24,57 @@ #include "user.h" #include +#include #include #include #include #include +static int +nvkm_dmaobj_bind(struct nvkm_object *base, struct nvkm_gpuobj *gpuobj, + int align, struct nvkm_gpuobj **pgpuobj) +{ + struct nvkm_dmaobj *dmaobj = nvkm_dmaobj(base); + return dmaobj->func->bind(dmaobj, gpuobj, align, pgpuobj); +} + +static void * +nvkm_dmaobj_dtor(struct nvkm_object *base) +{ + struct nvkm_dmaobj *dmaobj = nvkm_dmaobj(base); + if (!RB_EMPTY_NODE(&dmaobj->rb)) + rb_erase(&dmaobj->rb, &dmaobj->object.client->dmaroot); + return dmaobj; +} + +static const struct nvkm_object_func +nvkm_dmaobj_func = { + .dtor = nvkm_dmaobj_dtor, + .bind = nvkm_dmaobj_bind, +}; + int -nvkm_dmaobj_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void **pdata, u32 *psize, - int length, void **pobject) +nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *func, struct nvkm_dma *dma, + const struct nvkm_oclass *oclass, void **pdata, u32 *psize, + struct nvkm_dmaobj *dmaobj) { union { struct nv_dma_v0 v0; } *args = *pdata; - struct nvkm_instmem *instmem = nvkm_instmem(parent); - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_device *device = nv_device(parent); - struct nvkm_fb *fb = nvkm_fb(parent); - struct nvkm_dmaobj *dmaobj; + struct nvkm_device *device = dma->engine.subdev.device; + struct nvkm_client *client = oclass->client; + struct nvkm_object *parent = oclass->parent; + struct nvkm_instmem *instmem = device->imem; + struct nvkm_fb *fb = device->fb; void *data = *pdata; u32 size = *psize; int ret; - ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject); - dmaobj = *pobject; - if (ret) - return ret; + nvkm_object_ctor(&nvkm_dmaobj_func, oclass, &dmaobj->object); + dmaobj->func = func; + dmaobj->dma = dma; + RB_CLEAR_NODE(&dmaobj->rb); nvif_ioctl(parent, "create dma size %d\n", *psize); if (nvif_unpack(args->v0, 0, 0, true)) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h index 83dc1d621e3dc..f667505a892b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h @@ -1,29 +1,18 @@ #ifndef __NVKM_DMA_USER_H__ #define __NVKM_DMA_USER_H__ +#define nvkm_dmaobj(p) container_of((p), struct nvkm_dmaobj, object) #include "priv.h" -#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \ - nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d) - -int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void **, u32 *, - int, void **); -#define _nvkm_dmaobj_dtor nvkm_object_destroy -#define _nvkm_dmaobj_init _nvkm_object_init -#define _nvkm_dmaobj_fini _nvkm_object_fini - -extern struct nvkm_oclass nv04_dmaeng_sclass[]; -extern struct nvkm_oclass nv50_dmaeng_sclass[]; -extern struct nvkm_oclass gf100_dmaeng_sclass[]; -extern struct nvkm_oclass gf110_dmaeng_sclass[]; - -int nv04_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, - struct nvkm_gpuobj **); -int nv50_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, - struct nvkm_gpuobj **); -int gf100_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, - struct nvkm_gpuobj **); -int gf110_dmaobj_bind(struct nvkm_dmaobj *, struct nvkm_gpuobj *, - struct nvkm_gpuobj **); +int nvkm_dmaobj_ctor(const struct nvkm_dmaobj_func *, struct nvkm_dma *, + const struct nvkm_oclass *, void **data, u32 *size, + struct nvkm_dmaobj *); +int nv04_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +int nv50_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +int gf100_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); +int gf110_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, + struct nvkm_dmaobj **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c index 3f2d7d93f026a..13e341cc4e32a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf100.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define gf100_dmaobj(p) container_of((p), struct gf100_dmaobj, base) #include "user.h" #include @@ -36,18 +37,18 @@ struct gf100_dmaobj { u32 flags5; }; -int -gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, - struct nvkm_gpuobj **pgpuobj) +static int +gf100_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct gf100_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); - struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; + struct gf100_dmaobj *dmaobj = gf100_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; int ret; - ret = nvkm_gpuobj_new(device, 24, 32, false, parent, pgpuobj); + ret = nvkm_gpuobj_new(device, 24, align, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); nvkm_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); nvkm_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); nvkm_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | @@ -60,23 +61,32 @@ gf100_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, return ret; } -static int -gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_dmaobj_func +gf100_dmaobj_func = { + .bind = gf100_dmaobj_bind, +}; + +int +gf100_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { - struct nvkm_dma *dmaeng = (void *)engine; union { struct gf100_dma_v0 v0; } *args; + struct nvkm_object *parent = oclass->parent; struct gf100_dmaobj *dmaobj; u32 kind, user, unkn; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); - *pobject = nv_object(dmaobj); + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&gf100_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); if (ret) return ret; + args = data; nvif_ioctl(parent, "create gf100 dma size %d\n", size); @@ -103,7 +113,7 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (user > 2) return -EINVAL; - dmaobj->flags0 |= (kind << 22) | (user << 20); + dmaobj->flags0 |= (kind << 22) | (user << 20) | oclass->base.oclass; dmaobj->flags5 |= (unkn << 16); switch (dmaobj->base.target) { @@ -135,21 +145,5 @@ gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, break; } - return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); + return 0; } - -static struct nvkm_ofuncs -gf100_dmaobj_ofuncs = { - .ctor = gf100_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -struct nvkm_oclass -gf100_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &gf100_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &gf100_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &gf100_dmaobj_ofuncs }, - {} -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c index db22a8b2033c8..f6bbdffed4e75 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define gf110_dmaobj(p) container_of((p), struct gf110_dmaobj, base) #include "user.h" #include @@ -35,15 +36,15 @@ struct gf110_dmaobj { u32 flags0; }; -int -gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, - struct nvkm_gpuobj **pgpuobj) +static int +gf110_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct gf110_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); - struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; + struct gf110_dmaobj *dmaobj = gf110_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; int ret; - ret = nvkm_gpuobj_new(device, 24, 32, false, parent, pgpuobj); + ret = nvkm_gpuobj_new(device, 24, align, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); @@ -58,23 +59,32 @@ gf110_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, return ret; } -static int -gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_dmaobj_func +gf110_dmaobj_func = { + .bind = gf110_dmaobj_bind, +}; + +int +gf110_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { - struct nvkm_dma *dmaeng = (void *)engine; union { struct gf110_dma_v0 v0; } *args; + struct nvkm_object *parent = oclass->parent; struct gf110_dmaobj *dmaobj; u32 kind, page; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); - *pobject = nv_object(dmaobj); + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&gf110_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); if (ret) return ret; + args = data; nvif_ioctl(parent, "create gf110 dma size %d\n", size); @@ -117,21 +127,5 @@ gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); + return 0; } - -static struct nvkm_ofuncs -gf110_dmaobj_ofuncs = { - .ctor = gf110_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -struct nvkm_oclass -gf110_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &gf110_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &gf110_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &gf110_dmaobj_ofuncs }, - {} -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c index bd8ca8ec09b69..2c2fb0988ed4b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define nv04_dmaobj(p) container_of((p), struct nv04_dmaobj, base) #include "user.h" #include @@ -36,19 +37,19 @@ struct nv04_dmaobj { u32 flags2; }; -int -nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, - struct nvkm_gpuobj **pgpuobj) +static int +nv04_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv04_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); - struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; + struct nv04_dmaobj *dmaobj = nv04_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; u64 offset = dmaobj->base.start & 0xfffff000; u64 adjust = dmaobj->base.start & 0x00000fff; u32 length = dmaobj->base.limit - dmaobj->base.start; int ret; if (dmaobj->clone) { - struct nv04_mmu *mmu = nv04_mmu(dmaobj); + struct nv04_mmu *mmu = nv04_mmu(device->mmu); struct nvkm_memory *pgt = mmu->vm->pgt[0].mem[0]; if (!dmaobj->base.start) return nvkm_gpuobj_wrap(pgt, pgpuobj); @@ -58,7 +59,7 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, nvkm_done(pgt); } - ret = nvkm_gpuobj_new(device, 16, 16, false, parent, pgpuobj); + ret = nvkm_gpuobj_new(device, 16, align, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | (adjust << 20)); @@ -71,19 +72,26 @@ nv04_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, return ret; } -static int -nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_dmaobj_func +nv04_dmaobj_func = { + .bind = nv04_dmaobj_bind, +}; + +int +nv04_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { - struct nvkm_dma *dmaeng = (void *)engine; - struct nv04_mmu *mmu = nv04_mmu(engine); + struct nv04_mmu *mmu = nv04_mmu(dma); struct nv04_dmaobj *dmaobj; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); - *pobject = nv_object(dmaobj); - if (ret || (ret = -ENOSYS, size)) + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&nv04_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); + if (ret) return ret; if (dmaobj->base.target == NV_MEM_TARGET_VM) { @@ -93,7 +101,7 @@ nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, dmaobj->base.access = NV_MEM_ACCESS_RW; } - dmaobj->flags0 = nv_mclass(dmaobj); + dmaobj->flags0 = oclass->base.oclass; switch (dmaobj->base.target) { case NV_MEM_TARGET_VRAM: dmaobj->flags0 |= 0x00003000; @@ -121,21 +129,5 @@ nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); + return 0; } - -static struct nvkm_ofuncs -nv04_dmaobj_ofuncs = { - .ctor = nv04_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -struct nvkm_oclass -nv04_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs }, - {} -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c index fd99b1e151430..5b7ce313ea14b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv50.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define nv50_dmaobj(p) container_of((p), struct nv50_dmaobj, base) #include "user.h" #include @@ -36,18 +37,18 @@ struct nv50_dmaobj { u32 flags5; }; -int -nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, - struct nvkm_gpuobj **pgpuobj) +static int +nv50_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv50_dmaobj *dmaobj = container_of(obj, typeof(*dmaobj), base); - struct nvkm_device *device = dmaobj->base.base.engine->subdev.device; + struct nv50_dmaobj *dmaobj = nv50_dmaobj(base); + struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; int ret; - ret = nvkm_gpuobj_new(device, 24, 32, false, parent, pgpuobj); + ret = nvkm_gpuobj_new(device, 24, align, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0 | nv_mclass(dmaobj)); + nvkm_wo32(*pgpuobj, 0x00, dmaobj->flags0); nvkm_wo32(*pgpuobj, 0x04, lower_32_bits(dmaobj->base.limit)); nvkm_wo32(*pgpuobj, 0x08, lower_32_bits(dmaobj->base.start)); nvkm_wo32(*pgpuobj, 0x0c, upper_32_bits(dmaobj->base.limit) << 24 | @@ -60,23 +61,32 @@ nv50_dmaobj_bind(struct nvkm_dmaobj *obj, struct nvkm_gpuobj *parent, return ret; } -static int -nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_dmaobj_func +nv50_dmaobj_func = { + .bind = nv50_dmaobj_bind, +}; + +int +nv50_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { - struct nvkm_dma *dmaeng = (void *)engine; union { struct nv50_dma_v0 v0; } *args; + struct nvkm_object *parent = oclass->parent; struct nv50_dmaobj *dmaobj; u32 user, part, comp, kind; int ret; - ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &dmaobj); - *pobject = nv_object(dmaobj); + if (!(dmaobj = kzalloc(sizeof(*dmaobj), GFP_KERNEL))) + return -ENOMEM; + *pdmaobj = &dmaobj->base; + + ret = nvkm_dmaobj_ctor(&nv50_dmaobj_func, dma, oclass, + &data, &size, &dmaobj->base); if (ret) return ret; + args = data; nvif_ioctl(parent, "create nv50 dma size %d\n", size); @@ -107,7 +117,8 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (user > 2 || part > 2 || comp > 3 || kind > 0x7f) return -EINVAL; - dmaobj->flags0 = (comp << 29) | (kind << 22) | (user << 20); + dmaobj->flags0 = (comp << 29) | (kind << 22) | (user << 20) | + oclass->base.oclass; dmaobj->flags5 = (part << 16); switch (dmaobj->base.target) { @@ -141,21 +152,5 @@ nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EINVAL; } - return dmaeng->bind(&dmaobj->base, (void *)dmaobj, (void *)pobject); + return 0; } - -static struct nvkm_ofuncs -nv50_dmaobj_ofuncs = { - .ctor = nv50_dmaobj_ctor, - .dtor = _nvkm_dmaobj_dtor, - .init = _nvkm_dmaobj_init, - .fini = _nvkm_dmaobj_fini, -}; - -struct nvkm_oclass -nv50_dmaeng_sclass[] = { - { NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs }, - { NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs }, - { NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs }, - {} -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index a3b663832dbf6..958f290d088e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -99,14 +99,13 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, u64 engmask, int len, void **ptr) { struct nvkm_client *client = nvkm_client(parent); - struct nvkm_handle *handle; struct nvkm_dmaobj *dmaobj; struct nvkm_fifo *fifo = (void *)engine; struct nvkm_fifo_base *base = (void *)parent; struct nvkm_fifo_chan *chan; - struct nvkm_dma *dma; struct nvkm_subdev *subdev = &fifo->engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_dma *dma = device->dma; unsigned long flags; int ret; @@ -119,21 +118,12 @@ nvkm_fifo_channel_create_(struct nvkm_object *parent, /* validate dma object representing push buffer */ if (pushbuf) { - handle = nvkm_client_search(client, pushbuf); - if (!handle) + dmaobj = nvkm_dma_search(dma, client, pushbuf); + if (!dmaobj) return -ENOENT; - dmaobj = (void *)handle->object; - dma = (void *)dmaobj->base.engine; - switch (dmaobj->base.oclass->handle) { - case NV_DMA_FROM_MEMORY: - case NV_DMA_IN_MEMORY: - break; - default: - return -EINVAL; - } - - ret = dma->bind(dmaobj, &base->gpuobj, &chan->pushgpu); + ret = dmaobj->func->bind(dmaobj, &base->gpuobj, 16, + &chan->pushgpu); if (ret) return ret; } -- GitLab From 2a7909c0ade08c66690e6115ae49765dc47873e6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5516/7006] drm/nouveau/disp: split user classes out from engine implementations Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 6 - .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 51 +- .../drm/nouveau/nvkm/engine/disp/baseg84.c | 65 + .../drm/nouveau/nvkm/engine/disp/basegf119.c | 114 ++ .../drm/nouveau/nvkm/engine/disp/basenv50.c | 127 ++ .../drm/nouveau/nvkm/engine/disp/changf119.c | 49 + .../drm/nouveau/nvkm/engine/disp/channv50.c | 229 +++ .../drm/nouveau/nvkm/engine/disp/channv50.h | 103 ++ .../drm/nouveau/nvkm/engine/disp/coreg84.c | 102 ++ .../drm/nouveau/nvkm/engine/disp/coreg94.c | 48 + .../drm/nouveau/nvkm/engine/disp/coregf119.c | 246 +++ .../drm/nouveau/nvkm/engine/disp/coregk104.c | 117 ++ .../drm/nouveau/nvkm/engine/disp/corenv50.c | 250 +++ .../drm/nouveau/nvkm/engine/disp/cursgf119.c | 37 + .../drm/nouveau/nvkm/engine/disp/cursnv50.c | 73 + .../drm/nouveau/nvkm/engine/disp/dmacgf119.c | 113 ++ .../drm/nouveau/nvkm/engine/disp/dmacnv50.c | 163 ++ .../drm/nouveau/nvkm/engine/disp/dmacnv50.h | 24 + .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 200 +-- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 60 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf110.c | 1361 ----------------- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 586 +++++++ .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 210 +-- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 45 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 45 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm204.c | 46 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 76 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 31 +- .../engine/disp/{hdagf110.c => hdagf119.c} | 2 +- .../engine/disp/{hdmigf110.c => hdmigf119.c} | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 99 -- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 1261 +-------------- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 136 +- .../drm/nouveau/nvkm/engine/disp/oimmgf119.c | 37 + .../drm/nouveau/nvkm/engine/disp/oimmnv50.c | 73 + .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 2 +- .../drm/nouveau/nvkm/engine/disp/ovlyg84.c | 62 + .../drm/nouveau/nvkm/engine/disp/ovlygf119.c | 101 ++ .../drm/nouveau/nvkm/engine/disp/ovlygk104.c | 88 ++ .../drm/nouveau/nvkm/engine/disp/ovlygt200.c | 65 + .../drm/nouveau/nvkm/engine/disp/ovlynv50.c | 115 ++ .../drm/nouveau/nvkm/engine/disp/piocgf119.c | 85 + .../drm/nouveau/nvkm/engine/disp/piocnv50.c | 104 ++ .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 2 + .../drm/nouveau/nvkm/engine/disp/rootg84.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootg94.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootgf119.c | 176 +++ .../drm/nouveau/nvkm/engine/disp/rootgk104.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootgk110.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootgm107.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootgm204.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootgt200.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootgt215.c | 43 + .../drm/nouveau/nvkm/engine/disp/rootnv04.c | 119 ++ .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 328 ++++ .../drm/nouveau/nvkm/engine/disp/rootnv50.h | 36 + .../engine/disp/{sorgf110.c => sorgf119.c} | 32 +- .../drm/nouveau/nvkm/engine/disp/sorgm204.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 6 +- 59 files changed, 4329 insertions(+), 3525 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c rename drivers/gpu/drm/nouveau/nvkm/engine/disp/{hdagf110.c => hdagf119.c} (98%) rename drivers/gpu/drm/nouveau/nvkm/engine/disp/{hdmigf110.c => hdmigf119.c} (98%) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h rename drivers/gpu/drm/nouveau/nvkm/engine/disp/{sorgf110.c => sorgf119.c} (81%) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index cc2ea61535042..2df776525b839 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -13,12 +13,6 @@ struct nvkm_disp { struct nvkm_event vblank; }; -static inline struct nvkm_disp * -nvkm_disp(void *obj) -{ - return (void *)nvkm_engine(obj, NVDEV_ENGINE_DISP); -} - extern struct nvkm_oclass *nv04_disp_oclass; extern struct nvkm_oclass *nv50_disp_oclass; extern struct nvkm_oclass *g84_disp_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 38a872409c2ee..75fc7e62fb74c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -5,7 +5,7 @@ nvkm-y += nvkm/engine/disp/g84.o nvkm-y += nvkm/engine/disp/g94.o nvkm-y += nvkm/engine/disp/gt200.o nvkm-y += nvkm/engine/disp/gt215.o -nvkm-y += nvkm/engine/disp/gf110.o +nvkm-y += nvkm/engine/disp/gf119.o nvkm-y += nvkm/engine/disp/gk104.o nvkm-y += nvkm/engine/disp/gk110.o nvkm-y += nvkm/engine/disp/gm107.o @@ -17,18 +17,61 @@ nvkm-y += nvkm/engine/disp/dacnv50.o nvkm-y += nvkm/engine/disp/piornv50.o nvkm-y += nvkm/engine/disp/sornv50.o nvkm-y += nvkm/engine/disp/sorg94.o -nvkm-y += nvkm/engine/disp/sorgf110.o +nvkm-y += nvkm/engine/disp/sorgf119.o nvkm-y += nvkm/engine/disp/sorgm204.o nvkm-y += nvkm/engine/disp/dport.o nvkm-y += nvkm/engine/disp/conn.o nvkm-y += nvkm/engine/disp/hdagt215.o -nvkm-y += nvkm/engine/disp/hdagf110.o +nvkm-y += nvkm/engine/disp/hdagf119.o nvkm-y += nvkm/engine/disp/hdmig84.o nvkm-y += nvkm/engine/disp/hdmigt215.o -nvkm-y += nvkm/engine/disp/hdmigf110.o +nvkm-y += nvkm/engine/disp/hdmigf119.o nvkm-y += nvkm/engine/disp/hdmigk104.o nvkm-y += nvkm/engine/disp/vga.o + +nvkm-y += nvkm/engine/disp/rootnv04.o +nvkm-y += nvkm/engine/disp/rootnv50.o +nvkm-y += nvkm/engine/disp/rootg84.o +nvkm-y += nvkm/engine/disp/rootg94.o +nvkm-y += nvkm/engine/disp/rootgt200.o +nvkm-y += nvkm/engine/disp/rootgt215.o +nvkm-y += nvkm/engine/disp/rootgf119.o +nvkm-y += nvkm/engine/disp/rootgk104.o +nvkm-y += nvkm/engine/disp/rootgk110.o +nvkm-y += nvkm/engine/disp/rootgm107.o +nvkm-y += nvkm/engine/disp/rootgm204.o + +nvkm-y += nvkm/engine/disp/channv50.o +nvkm-y += nvkm/engine/disp/changf119.o + +nvkm-y += nvkm/engine/disp/dmacnv50.o +nvkm-y += nvkm/engine/disp/dmacgf119.o + +nvkm-y += nvkm/engine/disp/basenv50.o +nvkm-y += nvkm/engine/disp/baseg84.o +nvkm-y += nvkm/engine/disp/basegf119.o + +nvkm-y += nvkm/engine/disp/corenv50.o +nvkm-y += nvkm/engine/disp/coreg84.o +nvkm-y += nvkm/engine/disp/coreg94.o +nvkm-y += nvkm/engine/disp/coregf119.o +nvkm-y += nvkm/engine/disp/coregk104.o + +nvkm-y += nvkm/engine/disp/ovlynv50.o +nvkm-y += nvkm/engine/disp/ovlyg84.o +nvkm-y += nvkm/engine/disp/ovlygt200.o +nvkm-y += nvkm/engine/disp/ovlygf119.o +nvkm-y += nvkm/engine/disp/ovlygk104.o + +nvkm-y += nvkm/engine/disp/piocnv50.o +nvkm-y += nvkm/engine/disp/piocgf119.o + +nvkm-y += nvkm/engine/disp/cursnv50.o +nvkm-y += nvkm/engine/disp/cursgf119.o + +nvkm-y += nvkm/engine/disp/oimmnv50.o +nvkm-y += nvkm/engine/disp/oimmgf119.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c new file mode 100644 index 0000000000000..c476ed0d70aea --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c @@ -0,0 +1,65 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +g84_disp_base_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00c4, 0x610800 }, + { 0x00c8, 0x61080c }, + { 0x00cc, 0x610818 }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x00fc, 0x610824 }, + { 0x0100, 0x610894 }, + { 0x0104, 0x61082c }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +g84_disp_base_mthd_chan = { + .name = "Base", + .addr = 0x000540, + .data = { + { "Global", 1, &g84_disp_base_mthd_base }, + { "Image", 2, &nv50_disp_base_mthd_image }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c new file mode 100644 index 0000000000000..d3c37b49d31c6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c @@ -0,0 +1,114 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +gf119_disp_base_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x661080 }, + { 0x0084, 0x661084 }, + { 0x0088, 0x661088 }, + { 0x008c, 0x66108c }, + { 0x0090, 0x661090 }, + { 0x0094, 0x661094 }, + { 0x00a0, 0x6610a0 }, + { 0x00a4, 0x6610a4 }, + { 0x00c0, 0x6610c0 }, + { 0x00c4, 0x6610c4 }, + { 0x00c8, 0x6610c8 }, + { 0x00cc, 0x6610cc }, + { 0x00e0, 0x6610e0 }, + { 0x00e4, 0x6610e4 }, + { 0x00e8, 0x6610e8 }, + { 0x00ec, 0x6610ec }, + { 0x00fc, 0x6610fc }, + { 0x0100, 0x661100 }, + { 0x0104, 0x661104 }, + { 0x0108, 0x661108 }, + { 0x010c, 0x66110c }, + { 0x0110, 0x661110 }, + { 0x0114, 0x661114 }, + { 0x0118, 0x661118 }, + { 0x011c, 0x66111c }, + { 0x0130, 0x661130 }, + { 0x0134, 0x661134 }, + { 0x0138, 0x661138 }, + { 0x013c, 0x66113c }, + { 0x0140, 0x661140 }, + { 0x0144, 0x661144 }, + { 0x0148, 0x661148 }, + { 0x014c, 0x66114c }, + { 0x0150, 0x661150 }, + { 0x0154, 0x661154 }, + { 0x0158, 0x661158 }, + { 0x015c, 0x66115c }, + { 0x0160, 0x661160 }, + { 0x0164, 0x661164 }, + { 0x0168, 0x661168 }, + { 0x016c, 0x66116c }, + {} + } +}; + +static const struct nv50_disp_mthd_list +gf119_disp_base_mthd_image = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0400, 0x661400 }, + { 0x0404, 0x661404 }, + { 0x0408, 0x661408 }, + { 0x040c, 0x66140c }, + { 0x0410, 0x661410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +gf119_disp_base_mthd_chan = { + .name = "Base", + .addr = 0x001000, + .data = { + { "Global", 1, &gf119_disp_base_mthd_base }, + { "Image", 2, &gf119_disp_base_mthd_image }, + {} + } +}; + +struct nv50_disp_chan_impl +gf119_disp_base_ofuncs = { + .base.ctor = nv50_disp_base_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = gf119_disp_dmac_init, + .base.fini = gf119_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 1, + .attach = gf119_disp_dmac_object_attach, + .detach = gf119_disp_dmac_object_detach, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c new file mode 100644 index 0000000000000..cfb1eac55958f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c @@ -0,0 +1,127 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +#include + +#include +#include + +static const struct nv50_disp_mthd_list +nv50_disp_base_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0008c4 }, + { 0x0088, 0x0008d0 }, + { 0x008c, 0x0008dc }, + { 0x0090, 0x0008e4 }, + { 0x0094, 0x610884 }, + { 0x00a0, 0x6108a0 }, + { 0x00a4, 0x610878 }, + { 0x00c0, 0x61086c }, + { 0x00e0, 0x610858 }, + { 0x00e4, 0x610860 }, + { 0x00e8, 0x6108ac }, + { 0x00ec, 0x6108b4 }, + { 0x0100, 0x610894 }, + { 0x0110, 0x6108bc }, + { 0x0114, 0x61088c }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_base_mthd_image = { + .mthd = 0x0400, + .addr = 0x000000, + .data = { + { 0x0800, 0x6108f0 }, + { 0x0804, 0x6108fc }, + { 0x0808, 0x61090c }, + { 0x080c, 0x610914 }, + { 0x0810, 0x610904 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv50_disp_base_mthd_chan = { + .name = "Base", + .addr = 0x000540, + .data = { + { "Global", 1, &nv50_disp_base_mthd_base }, + { "Image", 2, &nv50_disp_base_mthd_image }, + {} + } +}; + +int +nv50_disp_base_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_base_channel_dma_v0 v0; + } *args = data; + struct nv50_disp *disp = (void *)engine; + struct nv50_disp_dmac *dmac; + int ret; + + nvif_ioctl(parent, "create disp base channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp base channel dma vers %d " + "pushbuf %016llx head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > disp->head.nr) + return -EINVAL; + } else + return ret; + + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, + args->v0.head, sizeof(*dmac), + (void **)&dmac); + *pobject = nv_object(dmac); + if (ret) + return ret; + + return 0; +} + +struct nv50_disp_chan_impl +nv50_disp_base_ofuncs = { + .base.ctor = nv50_disp_base_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nv50_disp_dmac_init, + .base.fini = nv50_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 1, + .attach = nv50_disp_dmac_object_attach, + .detach = nv50_disp_dmac_object_detach, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c new file mode 100644 index 0000000000000..17a3d835cb424 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/changf119.c @@ -0,0 +1,49 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +static void +gf119_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000000 << index); + nvkm_wr32(device, 0x61008c, 0x00000001 << index); +} + +static void +gf119_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x61008c, 0x00000001 << index); + nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000001 << index); +} + +const struct nvkm_event_func +gf119_disp_chan_uevent = { + .ctor = nv50_disp_chan_uevent_ctor, + .init = gf119_disp_chan_uevent_init, + .fini = gf119_disp_chan_uevent_fini, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c new file mode 100644 index 0000000000000..2999996497fff --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -0,0 +1,229 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include +#include +#include + +static void +nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, + const struct nv50_disp_mthd_list *list, int inst) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int i; + + for (i = 0; list->data[i].mthd; i++) { + if (list->data[i].addr) { + u32 next = nvkm_rd32(device, list->data[i].addr + base + 0); + u32 prev = nvkm_rd32(device, list->data[i].addr + base + c); + u32 mthd = list->data[i].mthd + (list->mthd * inst); + const char *name = list->data[i].name; + char mods[16]; + + if (prev != next) + snprintf(mods, sizeof(mods), "-> %08x", next); + else + snprintf(mods, sizeof(mods), "%13c", ' '); + + nvkm_printk_(subdev, debug, info, + "\t%04x: %08x %s%s%s\n", + mthd, prev, mods, name ? " // " : "", + name ? name : ""); + } + } +} + +void +nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, + const struct nv50_disp_mthd_chan *chan) +{ + struct nvkm_object *object = nv_object(disp); + const struct nv50_disp_impl *impl = (void *)object->oclass; + const struct nv50_disp_mthd_list *list; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + int i, j; + + if (debug > nv_subdev(disp)->debug) + return; + + for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { + u32 base = head * chan->addr; + for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { + const char *cname = chan->name; + const char *sname = ""; + char cname_[16], sname_[16]; + + if (chan->addr) { + snprintf(cname_, sizeof(cname_), "%s %d", + chan->name, head); + cname = cname_; + } + + if (chan->data[i].nr > 1) { + snprintf(sname_, sizeof(sname_), " - %s %d", + chan->data[i].name, j); + sname = sname_; + } + + nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname); + nv50_disp_mthd_list(disp, debug, base, impl->mthd.prev, + list, j); + } + } +} + +static void +nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000000 << index); + nvkm_wr32(device, 0x610020, 0x00000001 << index); +} + +static void +nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) +{ + struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x610020, 0x00000001 << index); + nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index); +} + +void +nv50_disp_chan_uevent_send(struct nv50_disp *disp, int chid) +{ + struct nvif_notify_uevent_rep { + } rep; + + nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep)); +} + +int +nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) +{ + struct nv50_disp_dmac *dmac = (void *)object; + union { + struct nvif_notify_uevent_req none; + } *args = data; + int ret; + + if (nvif_unvers(args->none)) { + notify->size = sizeof(struct nvif_notify_uevent_rep); + notify->types = 1; + notify->index = dmac->base.chid; + return 0; + } + + return ret; +} + +const struct nvkm_event_func +nv50_disp_chan_uevent = { + .ctor = nv50_disp_chan_uevent_ctor, + .init = nv50_disp_chan_uevent_init, + .fini = nv50_disp_chan_uevent_fini, +}; + +int +nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, + struct nvkm_event **pevent) +{ + struct nv50_disp *disp = (void *)object->engine; + switch (type) { + case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: + *pevent = &disp->uevent; + return 0; + default: + break; + } + return -EINVAL; +} + +int +nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nv50_disp_chan *chan = (void *)object; + *addr = nv_device_resource_start(nv_device(object), 0) + + 0x640000 + (chan->chid * 0x1000); + *size = 0x001000; + return 0; +} + +u32 +nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) +{ + struct nv50_disp_chan *chan = (void *)object; + struct nvkm_device *device = object->engine->subdev.device; + return nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); +} + +void +nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nv50_disp_chan *chan = (void *)object; + struct nvkm_device *device = object->engine->subdev.device; + nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); +} + +void +nv50_disp_chan_destroy(struct nv50_disp_chan *chan) +{ + struct nv50_disp_root *root = (void *)nv_object(chan)->parent; + root->chan &= ~(1 << chan->chid); + nvkm_namedb_destroy(&chan->base); +} + +int +nv50_disp_chan_create_(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, int head, + int length, void **pobject) +{ + const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs; + struct nv50_disp_root *root = (void *)parent; + struct nv50_disp_chan *chan; + int chid = impl->chid + head; + int ret; + + if (root->chan & (1 << chid)) + return -EBUSY; + root->chan |= (1 << chid); + + ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, + (1ULL << NVDEV_ENGINE_DMAOBJ), + length, pobject); + chan = *pobject; + if (ret) + return ret; + chan->chid = chid; + + nv_parent(chan)->object_attach = impl->attach; + nv_parent(chan)->object_detach = impl->detach; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h new file mode 100644 index 0000000000000..982d1bfe9a6b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h @@ -0,0 +1,103 @@ +#ifndef __NV50_DISP_CHAN_H__ +#define __NV50_DISP_CHAN_H__ +#include "nv50.h" + +struct nv50_disp_chan_impl { + struct nvkm_ofuncs base; + int chid; + int (*attach)(struct nvkm_object *, struct nvkm_object *, u32); + void (*detach)(struct nvkm_object *, int); +}; + +#include + +struct nv50_disp_chan { + struct nvkm_namedb base; + int chid; +}; + +int nv50_disp_chan_create_(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, int, int, void **); +void nv50_disp_chan_destroy(struct nv50_disp_chan *); +int nv50_disp_chan_ntfy(struct nvkm_object *, u32, struct nvkm_event **); +int nv50_disp_chan_map(struct nvkm_object *, u64 *, u32 *); +u32 nv50_disp_chan_rd32(struct nvkm_object *, u64); +void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32); +extern const struct nvkm_event_func nv50_disp_chan_uevent; +int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32, + struct nvkm_notify *); +void nv50_disp_chan_uevent_send(struct nv50_disp *, int); + +extern const struct nvkm_event_func gf119_disp_chan_uevent; + +#define nv50_disp_chan_init(a) \ + nvkm_namedb_init(&(a)->base) +#define nv50_disp_chan_fini(a,b) \ + nvkm_namedb_fini(&(a)->base, (b)) + +struct nv50_disp_pioc { + struct nv50_disp_chan base; +}; + +int nv50_disp_pioc_create_(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, int, int, void **); +void nv50_disp_pioc_dtor(struct nvkm_object *); +int nv50_disp_pioc_init(struct nvkm_object *); +int nv50_disp_pioc_fini(struct nvkm_object *, bool); + +int gf119_disp_pioc_init(struct nvkm_object *); +int gf119_disp_pioc_fini(struct nvkm_object *, bool); + +struct nv50_disp_mthd_list { + u32 mthd; + u32 addr; + struct { + u32 mthd; + u32 addr; + const char *name; + } data[]; +}; + +struct nv50_disp_mthd_chan { + const char *name; + u32 addr; + struct { + const char *name; + int nr; + const struct nv50_disp_mthd_list *mthd; + } data[]; +}; + +void nv50_disp_mthd_chan(struct nv50_disp *, int debug, int head, + const struct nv50_disp_mthd_chan *); + +extern const struct nv50_disp_mthd_chan nv50_disp_core_mthd_chan; +extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base; +extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor; +extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior; +extern const struct nv50_disp_mthd_chan nv50_disp_base_mthd_chan; +extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image; +extern const struct nv50_disp_mthd_chan nv50_disp_ovly_mthd_chan; +extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; + +extern const struct nv50_disp_mthd_chan g84_disp_core_mthd_chan; +extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac; +extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head; +extern const struct nv50_disp_mthd_chan g84_disp_base_mthd_chan; +extern const struct nv50_disp_mthd_chan g84_disp_ovly_mthd_chan; + +extern const struct nv50_disp_mthd_chan g94_disp_core_mthd_chan; + +extern const struct nv50_disp_mthd_chan gt200_disp_ovly_mthd_chan; + +extern const struct nv50_disp_mthd_chan gf119_disp_core_mthd_chan; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_base; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_dac; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_sor; +extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_pior; +extern const struct nv50_disp_mthd_chan gf119_disp_base_mthd_chan; +extern const struct nv50_disp_mthd_chan gf119_disp_ovly_mthd_chan; + +extern const struct nv50_disp_mthd_chan gk104_disp_core_mthd_chan; +extern const struct nv50_disp_mthd_chan gk104_disp_ovly_mthd_chan; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c new file mode 100644 index 0000000000000..29b020f025e33 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c @@ -0,0 +1,102 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +const struct nv50_disp_mthd_list +g84_disp_core_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610bc4 }, + {} + } +}; + +const struct nv50_disp_mthd_list +g84_disp_core_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x085c, 0x610c5c }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0878, 0x610c50 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x089c, 0x610c68 }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + { 0x0910, 0x610c70 }, + { 0x0914, 0x610c78 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +g84_disp_core_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_core_mthd_base }, + { "DAC", 3, &g84_disp_core_mthd_dac }, + { "SOR", 2, &nv50_disp_core_mthd_sor }, + { "PIOR", 3, &nv50_disp_core_mthd_pior }, + { "HEAD", 2, &g84_disp_core_mthd_head }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c new file mode 100644 index 0000000000000..81455256ebb1d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c @@ -0,0 +1,48 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +const struct nv50_disp_mthd_list +g94_disp_core_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610794 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +g94_disp_core_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_core_mthd_base }, + { "DAC", 3, &g84_disp_core_mthd_dac }, + { "SOR", 4, &g94_disp_core_mthd_sor }, + { "PIOR", 3, &nv50_disp_core_mthd_pior }, + { "HEAD", 2, &g84_disp_core_mthd_head }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c new file mode 100644 index 0000000000000..87f5c43115c1f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c @@ -0,0 +1,246 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +#include + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x660080 }, + { 0x0084, 0x660084 }, + { 0x0088, 0x660088 }, + { 0x008c, 0x000000 }, + {} + } +}; + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_dac = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0180, 0x660180 }, + { 0x0184, 0x660184 }, + { 0x0188, 0x660188 }, + { 0x0190, 0x660190 }, + {} + } +}; + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_sor = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0200, 0x660200 }, + { 0x0204, 0x660204 }, + { 0x0208, 0x660208 }, + { 0x0210, 0x660210 }, + {} + } +}; + +const struct nv50_disp_mthd_list +gf119_disp_core_mthd_pior = { + .mthd = 0x0020, + .addr = 0x000020, + .data = { + { 0x0300, 0x660300 }, + { 0x0304, 0x660304 }, + { 0x0308, 0x660308 }, + { 0x0310, 0x660310 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +gf119_disp_core_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +gf119_disp_core_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &gf119_disp_core_mthd_base }, + { "DAC", 3, &gf119_disp_core_mthd_dac }, + { "SOR", 8, &gf119_disp_core_mthd_sor }, + { "PIOR", 4, &gf119_disp_core_mthd_pior }, + { "HEAD", 4, &gf119_disp_core_mthd_head }, + {} + } +}; + +static int +gf119_disp_core_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* deactivate channel */ + nvkm_mask(device, 0x610490, 0x00000010, 0x00000000); + nvkm_mask(device, 0x610490, 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "core fini: %08x\n", + nvkm_rd32(device, 0x610490)); + if (suspend) + return -EBUSY; + } + + /* disable error reporting and completion notification */ + nvkm_mask(device, 0x610090, 0x00000001, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000000); + + return nv50_disp_chan_fini(&mast->base, suspend); +} + +static int +gf119_disp_core_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int ret; + + ret = nv50_disp_chan_init(&mast->base); + if (ret) + return ret; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000001); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610494, mast->push); + nvkm_wr32(device, 0x610498, 0x00010000); + nvkm_wr32(device, 0x61049c, 0x00000001); + nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610490, 0x01000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610490)); + return -EBUSY; + } + + return 0; +} + +struct nv50_disp_chan_impl +gf119_disp_core_ofuncs = { + .base.ctor = nv50_disp_core_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = gf119_disp_core_init, + .base.fini = gf119_disp_core_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 0, + .attach = gf119_disp_dmac_object_attach, + .detach = gf119_disp_dmac_object_detach, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c new file mode 100644 index 0000000000000..6662cc6d70a30 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c @@ -0,0 +1,117 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +gk104_disp_core_mthd_head = { + .mthd = 0x0300, + .addr = 0x000300, + .data = { + { 0x0400, 0x660400 }, + { 0x0404, 0x660404 }, + { 0x0408, 0x660408 }, + { 0x040c, 0x66040c }, + { 0x0410, 0x660410 }, + { 0x0414, 0x660414 }, + { 0x0418, 0x660418 }, + { 0x041c, 0x66041c }, + { 0x0420, 0x660420 }, + { 0x0424, 0x660424 }, + { 0x0428, 0x660428 }, + { 0x042c, 0x66042c }, + { 0x0430, 0x660430 }, + { 0x0434, 0x660434 }, + { 0x0438, 0x660438 }, + { 0x0440, 0x660440 }, + { 0x0444, 0x660444 }, + { 0x0448, 0x660448 }, + { 0x044c, 0x66044c }, + { 0x0450, 0x660450 }, + { 0x0454, 0x660454 }, + { 0x0458, 0x660458 }, + { 0x045c, 0x66045c }, + { 0x0460, 0x660460 }, + { 0x0468, 0x660468 }, + { 0x046c, 0x66046c }, + { 0x0470, 0x660470 }, + { 0x0474, 0x660474 }, + { 0x047c, 0x66047c }, + { 0x0480, 0x660480 }, + { 0x0484, 0x660484 }, + { 0x0488, 0x660488 }, + { 0x048c, 0x66048c }, + { 0x0490, 0x660490 }, + { 0x0494, 0x660494 }, + { 0x0498, 0x660498 }, + { 0x04a0, 0x6604a0 }, + { 0x04b0, 0x6604b0 }, + { 0x04b8, 0x6604b8 }, + { 0x04bc, 0x6604bc }, + { 0x04c0, 0x6604c0 }, + { 0x04c4, 0x6604c4 }, + { 0x04c8, 0x6604c8 }, + { 0x04d0, 0x6604d0 }, + { 0x04d4, 0x6604d4 }, + { 0x04e0, 0x6604e0 }, + { 0x04e4, 0x6604e4 }, + { 0x04e8, 0x6604e8 }, + { 0x04ec, 0x6604ec }, + { 0x04f0, 0x6604f0 }, + { 0x04f4, 0x6604f4 }, + { 0x04f8, 0x6604f8 }, + { 0x04fc, 0x6604fc }, + { 0x0500, 0x660500 }, + { 0x0504, 0x660504 }, + { 0x0508, 0x660508 }, + { 0x050c, 0x66050c }, + { 0x0510, 0x660510 }, + { 0x0514, 0x660514 }, + { 0x0518, 0x660518 }, + { 0x051c, 0x66051c }, + { 0x0520, 0x660520 }, + { 0x0524, 0x660524 }, + { 0x052c, 0x66052c }, + { 0x0530, 0x660530 }, + { 0x054c, 0x66054c }, + { 0x0550, 0x660550 }, + { 0x0554, 0x660554 }, + { 0x0558, 0x660558 }, + { 0x055c, 0x66055c }, + {} + } +}; + +const struct nv50_disp_mthd_chan +gk104_disp_core_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &gf119_disp_core_mthd_base }, + { "DAC", 3, &gf119_disp_core_mthd_dac }, + { "SOR", 8, &gf119_disp_core_mthd_sor }, + { "PIOR", 4, &gf119_disp_core_mthd_pior }, + { "HEAD", 4, &gk104_disp_core_mthd_head }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c new file mode 100644 index 0000000000000..624b795101759 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c @@ -0,0 +1,250 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +#include +#include + +#include +#include + +const struct nv50_disp_mthd_list +nv50_disp_core_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x610bb8 }, + { 0x0088, 0x610b9c }, + { 0x008c, 0x000000 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_core_mthd_dac = { + .mthd = 0x0080, + .addr = 0x000008, + .data = { + { 0x0400, 0x610b58 }, + { 0x0404, 0x610bdc }, + { 0x0420, 0x610828 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_core_mthd_sor = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0600, 0x610b70 }, + {} + } +}; + +const struct nv50_disp_mthd_list +nv50_disp_core_mthd_pior = { + .mthd = 0x0040, + .addr = 0x000008, + .data = { + { 0x0700, 0x610b80 }, + {} + } +}; + +static const struct nv50_disp_mthd_list +nv50_disp_core_mthd_head = { + .mthd = 0x0400, + .addr = 0x000540, + .data = { + { 0x0800, 0x610ad8 }, + { 0x0804, 0x610ad0 }, + { 0x0808, 0x610a48 }, + { 0x080c, 0x610a78 }, + { 0x0810, 0x610ac0 }, + { 0x0814, 0x610af8 }, + { 0x0818, 0x610b00 }, + { 0x081c, 0x610ae8 }, + { 0x0820, 0x610af0 }, + { 0x0824, 0x610b08 }, + { 0x0828, 0x610b10 }, + { 0x082c, 0x610a68 }, + { 0x0830, 0x610a60 }, + { 0x0834, 0x000000 }, + { 0x0838, 0x610a40 }, + { 0x0840, 0x610a24 }, + { 0x0844, 0x610a2c }, + { 0x0848, 0x610aa8 }, + { 0x084c, 0x610ab0 }, + { 0x0860, 0x610a84 }, + { 0x0864, 0x610a90 }, + { 0x0868, 0x610b18 }, + { 0x086c, 0x610b20 }, + { 0x0870, 0x610ac8 }, + { 0x0874, 0x610a38 }, + { 0x0880, 0x610a58 }, + { 0x0884, 0x610a9c }, + { 0x08a0, 0x610a70 }, + { 0x08a4, 0x610a50 }, + { 0x08a8, 0x610ae0 }, + { 0x08c0, 0x610b28 }, + { 0x08c4, 0x610b30 }, + { 0x08c8, 0x610b40 }, + { 0x08d4, 0x610b38 }, + { 0x08d8, 0x610b48 }, + { 0x08dc, 0x610b50 }, + { 0x0900, 0x610a18 }, + { 0x0904, 0x610ab8 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv50_disp_core_mthd_chan = { + .name = "Core", + .addr = 0x000000, + .data = { + { "Global", 1, &nv50_disp_core_mthd_base }, + { "DAC", 3, &nv50_disp_core_mthd_dac }, + { "SOR", 2, &nv50_disp_core_mthd_sor }, + { "PIOR", 3, &nv50_disp_core_mthd_pior }, + { "HEAD", 2, &nv50_disp_core_mthd_head }, + {} + } +}; + +static int +nv50_disp_core_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + /* deactivate channel */ + nvkm_mask(device, 0x610200, 0x00000010, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "core fini: %08x\n", + nvkm_rd32(device, 0x610200)); + if (suspend) + return -EBUSY; + } + + /* disable error reporting and completion notifications */ + nvkm_mask(device, 0x610028, 0x00010001, 0x00000000); + + return nv50_disp_chan_fini(&mast->base, suspend); +} + +static int +nv50_disp_core_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *mast = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int ret; + + ret = nv50_disp_chan_init(&mast->base); + if (ret) + return ret; + + /* enable error reporting */ + nvkm_mask(device, 0x610028, 0x00010000, 0x00010000); + + /* attempt to unstick channel from some unknown state */ + if ((nvkm_rd32(device, 0x610200) & 0x009f0000) == 0x00020000) + nvkm_mask(device, 0x610200, 0x00800000, 0x00800000); + if ((nvkm_rd32(device, 0x610200) & 0x003f0000) == 0x00030000) + nvkm_mask(device, 0x610200, 0x00600000, 0x00600000); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610204, mast->push); + nvkm_wr32(device, 0x610208, 0x00010000); + nvkm_wr32(device, 0x61020c, 0x00000000); + nvkm_mask(device, 0x610200, 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000, 0x00000000); + nvkm_wr32(device, 0x610200, 0x01000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "core init: %08x\n", + nvkm_rd32(device, 0x610200)); + return -EBUSY; + } + + return 0; +} + +int +nv50_disp_core_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_core_channel_dma_v0 v0; + } *args = data; + struct nv50_disp_dmac *mast; + int ret; + + nvif_ioctl(parent, "create disp core channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp core channel dma vers %d " + "pushbuf %016llx\n", + args->v0.version, args->v0.pushbuf); + } else + return ret; + + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, + 0, sizeof(*mast), (void **)&mast); + *pobject = nv_object(mast); + if (ret) + return ret; + + return 0; +} + +struct nv50_disp_chan_impl +nv50_disp_core_ofuncs = { + .base.ctor = nv50_disp_core_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nv50_disp_core_init, + .base.fini = nv50_disp_core_fini, + .base.map = nv50_disp_chan_map, + .base.ntfy = nv50_disp_chan_ntfy, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 0, + .attach = nv50_disp_dmac_object_attach, + .detach = nv50_disp_dmac_object_detach, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c new file mode 100644 index 0000000000000..5537a4ae4e15d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +struct nv50_disp_chan_impl +gf119_disp_curs_ofuncs = { + .base.ctor = nv50_disp_curs_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = gf119_disp_pioc_init, + .base.fini = gf119_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 13, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c new file mode 100644 index 0000000000000..2b4e877347cbe --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c @@ -0,0 +1,73 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include + +#include +#include + +int +nv50_disp_curs_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_cursor_v0 v0; + } *args = data; + struct nv50_disp *disp = (void *)engine; + struct nv50_disp_pioc *pioc; + int ret; + + nvif_ioctl(parent, "create disp cursor size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp cursor vers %d head %d\n", + args->v0.version, args->v0.head); + if (args->v0.head > disp->head.nr) + return -EINVAL; + } else + return ret; + + ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, + sizeof(*pioc), (void **)&pioc); + *pobject = nv_object(pioc); + if (ret) + return ret; + + return 0; +} + +struct nv50_disp_chan_impl +nv50_disp_curs_ofuncs = { + .base.ctor = nv50_disp_curs_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = nv50_disp_pioc_init, + .base.fini = nv50_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 7, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c new file mode 100644 index 0000000000000..6add32fa24d81 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c @@ -0,0 +1,113 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include +#include + +void +gf119_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) +{ + struct nv50_disp_root *root = (void *)parent->parent; + nvkm_ramht_remove(root->ramht, cookie); +} + +int +gf119_disp_dmac_object_attach(struct nvkm_object *parent, + struct nvkm_object *object, u32 name) +{ + struct nv50_disp_root *root = (void *)parent->parent; + struct nv50_disp_chan *chan = (void *)parent; + u32 addr = nv_gpuobj(object)->node->offset; + u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001; + return nvkm_ramht_insert(root->ramht, NULL, chan->chid, 0, name, data); +} + +int +gf119_disp_dmac_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = dmac->base.chid; + + /* deactivate channel */ + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d fini: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + if (suspend) + return -EBUSY; + } + + /* disable error reporting and completion notification */ + nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); + + return nv50_disp_chan_fini(&dmac->base, suspend); +} + +int +gf119_disp_dmac_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = dmac->base.chid; + int ret; + + ret = nv50_disp_chan_init(&dmac->base); + if (ret) + return ret; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610494 + (chid * 0x0010), dmac->push); + nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001); + nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c new file mode 100644 index 0000000000000..43c17d07e96ef --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c @@ -0,0 +1,163 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include +#include +#include +#include +#include +#include + +void +nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) +{ + struct nv50_disp_root *root = (void *)parent->parent; + nvkm_ramht_remove(root->ramht, cookie); +} + +int +nv50_disp_dmac_object_attach(struct nvkm_object *parent, + struct nvkm_object *object, u32 name) +{ + struct nv50_disp_root *root = (void *)parent->parent; + struct nv50_disp_chan *chan = (void *)parent; + u32 addr = nv_gpuobj(object)->node->offset; + u32 chid = chan->chid; + u32 data = (chid << 28) | (addr << 10) | chid; + return nvkm_ramht_insert(root->ramht, NULL, chid, 0, name, data); +} + +int +nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = dmac->base.chid; + + /* deactivate channel */ + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + if (suspend) + return -EBUSY; + } + + /* disable error reporting and completion notifications */ + nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid); + + return nv50_disp_chan_fini(&dmac->base, suspend); +} + +int +nv50_disp_dmac_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_dmac *dmac = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = dmac->base.chid; + int ret; + + ret = nv50_disp_chan_init(&dmac->base); + if (ret) + return ret; + + /* enable error reporting */ + nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid); + + /* initialise channel for dma command submission */ + nvkm_wr32(device, 0x610204 + (chid * 0x0010), dmac->push); + nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000); + nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid); + nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); + nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); + nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init timeout, %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +void +nv50_disp_dmac_dtor(struct nvkm_object *object) +{ + struct nv50_disp_dmac *dmac = (void *)object; + nv50_disp_chan_destroy(&dmac->base); +} + +int +nv50_disp_dmac_create_(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, u64 pushbuf, int head, + int length, void **pobject) +{ + struct nvkm_device *device = parent->engine->subdev.device; + struct nvkm_client *client = nvkm_client(parent); + struct nvkm_dmaobj *dmaobj; + struct nv50_disp_dmac *dmac; + int ret; + + ret = nv50_disp_chan_create_(parent, engine, oclass, head, + length, pobject); + dmac = *pobject; + if (ret) + return ret; + + dmaobj = nvkm_dma_search(device->dma, client, pushbuf); + if (!dmaobj) + return -ENOENT; + + if (dmaobj->limit - dmaobj->start != 0xfff) + return -EINVAL; + + switch (dmaobj->target) { + case NV_MEM_TARGET_VRAM: + dmac->push = 0x00000001 | dmaobj->start >> 8; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + dmac->push = 0x00000003 | dmaobj->start >> 8; + break; + default: + return -EINVAL; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h new file mode 100644 index 0000000000000..cfd09d275b139 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h @@ -0,0 +1,24 @@ +#ifndef __NV50_DISP_DMAC_H__ +#define __NV50_DISP_DMAC_H__ +#include "channv50.h" + +struct nv50_disp_dmac { + struct nv50_disp_chan base; + u32 push; +}; + +void nv50_disp_dmac_dtor(struct nvkm_object *); +int nv50_disp_dmac_object_attach(struct nvkm_object *, + struct nvkm_object *, u32); +void nv50_disp_dmac_object_detach(struct nvkm_object *, int); +int nv50_disp_dmac_create_(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, u64, int, int, void **); +int nv50_disp_dmac_init(struct nvkm_object *); +int nv50_disp_dmac_fini(struct nvkm_object *, bool); + +int gf119_disp_dmac_object_attach(struct nvkm_object *, + struct nvkm_object *, u32); +void gf119_disp_dmac_object_detach(struct nvkm_object *, int); +int gf119_disp_dmac_init(struct nvkm_object *); +int gf119_disp_dmac_fini(struct nvkm_object *, bool); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index c8d3093f95b9b..5995bcae21788 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -22,201 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -const struct nv50_disp_mthd_list -g84_disp_core_mthd_dac = { - .mthd = 0x0080, - .addr = 0x000008, - .data = { - { 0x0400, 0x610b58 }, - { 0x0404, 0x610bdc }, - { 0x0420, 0x610bc4 }, - {} - } -}; - -const struct nv50_disp_mthd_list -g84_disp_core_mthd_head = { - .mthd = 0x0400, - .addr = 0x000540, - .data = { - { 0x0800, 0x610ad8 }, - { 0x0804, 0x610ad0 }, - { 0x0808, 0x610a48 }, - { 0x080c, 0x610a78 }, - { 0x0810, 0x610ac0 }, - { 0x0814, 0x610af8 }, - { 0x0818, 0x610b00 }, - { 0x081c, 0x610ae8 }, - { 0x0820, 0x610af0 }, - { 0x0824, 0x610b08 }, - { 0x0828, 0x610b10 }, - { 0x082c, 0x610a68 }, - { 0x0830, 0x610a60 }, - { 0x0834, 0x000000 }, - { 0x0838, 0x610a40 }, - { 0x0840, 0x610a24 }, - { 0x0844, 0x610a2c }, - { 0x0848, 0x610aa8 }, - { 0x084c, 0x610ab0 }, - { 0x085c, 0x610c5c }, - { 0x0860, 0x610a84 }, - { 0x0864, 0x610a90 }, - { 0x0868, 0x610b18 }, - { 0x086c, 0x610b20 }, - { 0x0870, 0x610ac8 }, - { 0x0874, 0x610a38 }, - { 0x0878, 0x610c50 }, - { 0x0880, 0x610a58 }, - { 0x0884, 0x610a9c }, - { 0x089c, 0x610c68 }, - { 0x08a0, 0x610a70 }, - { 0x08a4, 0x610a50 }, - { 0x08a8, 0x610ae0 }, - { 0x08c0, 0x610b28 }, - { 0x08c4, 0x610b30 }, - { 0x08c8, 0x610b40 }, - { 0x08d4, 0x610b38 }, - { 0x08d8, 0x610b48 }, - { 0x08dc, 0x610b50 }, - { 0x0900, 0x610a18 }, - { 0x0904, 0x610ab8 }, - { 0x0910, 0x610c70 }, - { 0x0914, 0x610c78 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g84_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &g84_disp_core_mthd_dac }, - { "SOR", 2, &nv50_disp_core_mthd_sor }, - { "PIOR", 3, &nv50_disp_core_mthd_pior }, - { "HEAD", 2, &g84_disp_core_mthd_head }, - {} - } -}; - -/******************************************************************************* - * EVO sync channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -g84_disp_base_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x0008c4 }, - { 0x0088, 0x0008d0 }, - { 0x008c, 0x0008dc }, - { 0x0090, 0x0008e4 }, - { 0x0094, 0x610884 }, - { 0x00a0, 0x6108a0 }, - { 0x00a4, 0x610878 }, - { 0x00c0, 0x61086c }, - { 0x00c4, 0x610800 }, - { 0x00c8, 0x61080c }, - { 0x00cc, 0x610818 }, - { 0x00e0, 0x610858 }, - { 0x00e4, 0x610860 }, - { 0x00e8, 0x6108ac }, - { 0x00ec, 0x6108b4 }, - { 0x00fc, 0x610824 }, - { 0x0100, 0x610894 }, - { 0x0104, 0x61082c }, - { 0x0110, 0x6108bc }, - { 0x0114, 0x61088c }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g84_disp_base_mthd_chan = { - .name = "Base", - .addr = 0x000540, - .data = { - { "Global", 1, &g84_disp_base_mthd_base }, - { "Image", 2, &nv50_disp_base_mthd_image }, - {} - } -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -g84_disp_ovly_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x6109a0 }, - { 0x0088, 0x6109c0 }, - { 0x008c, 0x6109c8 }, - { 0x0090, 0x6109b4 }, - { 0x0094, 0x610970 }, - { 0x00a0, 0x610998 }, - { 0x00a4, 0x610964 }, - { 0x00c0, 0x610958 }, - { 0x00e0, 0x6109a8 }, - { 0x00e4, 0x6109d0 }, - { 0x00e8, 0x6109d8 }, - { 0x0100, 0x61094c }, - { 0x0104, 0x610984 }, - { 0x0108, 0x61098c }, - { 0x0800, 0x6109f8 }, - { 0x0808, 0x610a08 }, - { 0x080c, 0x610a10 }, - { 0x0810, 0x610a00 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g84_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x000540, - .data = { - { "Global", 1, &g84_disp_ovly_mthd_base }, - {} - } -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -g84_disp_sclass[] = { - { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -g84_disp_main_oclass[] = { - { G82_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -236,7 +42,7 @@ g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(disp)->sclass = g84_disp_main_oclass; + nv_engine(disp)->sclass = g84_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); @@ -272,5 +78,5 @@ g84_disp_oclass = &(struct nv50_disp_impl) { .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, + .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index b190a07c89d5d..0247090076357 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -22,61 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" - -#include - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -const struct nv50_disp_mthd_list -g94_disp_core_mthd_sor = { - .mthd = 0x0040, - .addr = 0x000008, - .data = { - { 0x0600, 0x610794 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -g94_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &g84_disp_core_mthd_dac }, - { "SOR", 4, &g94_disp_core_mthd_sor }, - { "PIOR", 3, &nv50_disp_core_mthd_pior }, - { "HEAD", 2, &g84_disp_core_mthd_head }, - {} - } -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -g94_disp_sclass[] = { - { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -g94_disp_main_oclass[] = { - { GT206_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -96,7 +42,7 @@ g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(disp)->sclass = g94_disp_main_oclass; + nv_engine(disp)->sclass = g94_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); @@ -133,5 +79,5 @@ g94_disp_oclass = &(struct nv50_disp_impl) { .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, + .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c deleted file mode 100644 index 7a8ea497eb26b..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c +++ /dev/null @@ -1,1361 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "nv50.h" -#include "outp.h" -#include "outpdp.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/******************************************************************************* - * EVO channel base class - ******************************************************************************/ - -static void -gf110_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000000 << index); - nvkm_wr32(device, 0x61008c, 0x00000001 << index); -} - -static void -gf110_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) -{ - struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_wr32(device, 0x61008c, 0x00000001 << index); - nvkm_mask(device, 0x610090, 0x00000001 << index, 0x00000001 << index); -} - -const struct nvkm_event_func -gf110_disp_chan_uevent = { - .ctor = nv50_disp_chan_uevent_ctor, - .init = gf110_disp_chan_uevent_init, - .fini = gf110_disp_chan_uevent_fini, -}; - -/******************************************************************************* - * EVO DMA channel base class - ******************************************************************************/ - -static int -gf110_disp_dmac_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 name) -{ - struct nv50_disp_base *base = (void *)parent->parent; - struct nv50_disp_chan *chan = (void *)parent; - u32 addr = nv_gpuobj(object)->node->offset; - u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001; - return nvkm_ramht_insert(base->ramht, NULL, chan->chid, 0, name, data); -} - -static void -gf110_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv50_disp_base *base = (void *)parent->parent; - nvkm_ramht_remove(base->ramht, cookie); -} - -static int -gf110_disp_dmac_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; - int ret; - - ret = nv50_disp_chan_init(&dmac->base); - if (ret) - return ret; - - /* enable error reporting */ - nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); - - /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610494 + (chid * 0x0010), dmac->push); - nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000); - nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001); - nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); - nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); - nvkm_wr32(device, 0x610490 + (chid * 0x0010), 0x00000013); - - /* wait for it to go inactive */ - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x80000000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d init: %08x\n", chid, - nvkm_rd32(device, 0x610490 + (chid * 0x10))); - return -EBUSY; - } - - return 0; -} - -static int -gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; - - /* deactivate channel */ - nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); - nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x001e0000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d fini: %08x\n", chid, - nvkm_rd32(device, 0x610490 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notification */ - nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); - nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); - - return nv50_disp_chan_fini(&dmac->base, suspend); -} - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x660080 }, - { 0x0084, 0x660084 }, - { 0x0088, 0x660088 }, - { 0x008c, 0x000000 }, - {} - } -}; - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_dac = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0180, 0x660180 }, - { 0x0184, 0x660184 }, - { 0x0188, 0x660188 }, - { 0x0190, 0x660190 }, - {} - } -}; - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_sor = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0200, 0x660200 }, - { 0x0204, 0x660204 }, - { 0x0208, 0x660208 }, - { 0x0210, 0x660210 }, - {} - } -}; - -const struct nv50_disp_mthd_list -gf110_disp_core_mthd_pior = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0300, 0x660300 }, - { 0x0304, 0x660304 }, - { 0x0308, 0x660308 }, - { 0x0310, 0x660310 }, - {} - } -}; - -static const struct nv50_disp_mthd_list -gf110_disp_core_mthd_head = { - .mthd = 0x0300, - .addr = 0x000300, - .data = { - { 0x0400, 0x660400 }, - { 0x0404, 0x660404 }, - { 0x0408, 0x660408 }, - { 0x040c, 0x66040c }, - { 0x0410, 0x660410 }, - { 0x0414, 0x660414 }, - { 0x0418, 0x660418 }, - { 0x041c, 0x66041c }, - { 0x0420, 0x660420 }, - { 0x0424, 0x660424 }, - { 0x0428, 0x660428 }, - { 0x042c, 0x66042c }, - { 0x0430, 0x660430 }, - { 0x0434, 0x660434 }, - { 0x0438, 0x660438 }, - { 0x0440, 0x660440 }, - { 0x0444, 0x660444 }, - { 0x0448, 0x660448 }, - { 0x044c, 0x66044c }, - { 0x0450, 0x660450 }, - { 0x0454, 0x660454 }, - { 0x0458, 0x660458 }, - { 0x045c, 0x66045c }, - { 0x0460, 0x660460 }, - { 0x0468, 0x660468 }, - { 0x046c, 0x66046c }, - { 0x0470, 0x660470 }, - { 0x0474, 0x660474 }, - { 0x0480, 0x660480 }, - { 0x0484, 0x660484 }, - { 0x048c, 0x66048c }, - { 0x0490, 0x660490 }, - { 0x0494, 0x660494 }, - { 0x0498, 0x660498 }, - { 0x04b0, 0x6604b0 }, - { 0x04b8, 0x6604b8 }, - { 0x04bc, 0x6604bc }, - { 0x04c0, 0x6604c0 }, - { 0x04c4, 0x6604c4 }, - { 0x04c8, 0x6604c8 }, - { 0x04d0, 0x6604d0 }, - { 0x04d4, 0x6604d4 }, - { 0x04e0, 0x6604e0 }, - { 0x04e4, 0x6604e4 }, - { 0x04e8, 0x6604e8 }, - { 0x04ec, 0x6604ec }, - { 0x04f0, 0x6604f0 }, - { 0x04f4, 0x6604f4 }, - { 0x04f8, 0x6604f8 }, - { 0x04fc, 0x6604fc }, - { 0x0500, 0x660500 }, - { 0x0504, 0x660504 }, - { 0x0508, 0x660508 }, - { 0x050c, 0x66050c }, - { 0x0510, 0x660510 }, - { 0x0514, 0x660514 }, - { 0x0518, 0x660518 }, - { 0x051c, 0x66051c }, - { 0x052c, 0x66052c }, - { 0x0530, 0x660530 }, - { 0x054c, 0x66054c }, - { 0x0550, 0x660550 }, - { 0x0554, 0x660554 }, - { 0x0558, 0x660558 }, - { 0x055c, 0x66055c }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -gf110_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &gf110_disp_core_mthd_base }, - { "DAC", 3, &gf110_disp_core_mthd_dac }, - { "SOR", 8, &gf110_disp_core_mthd_sor }, - { "PIOR", 4, &gf110_disp_core_mthd_pior }, - { "HEAD", 4, &gf110_disp_core_mthd_head }, - {} - } -}; - -static int -gf110_disp_core_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int ret; - - ret = nv50_disp_chan_init(&mast->base); - if (ret) - return ret; - - /* enable error reporting */ - nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000001); - - /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610494, mast->push); - nvkm_wr32(device, 0x610498, 0x00010000); - nvkm_wr32(device, 0x61049c, 0x00000001); - nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); - nvkm_wr32(device, 0x640000, 0x00000000); - nvkm_wr32(device, 0x610490, 0x01000013); - - /* wait for it to go inactive */ - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610490) & 0x80000000)) - break; - ) < 0) { - nvkm_error(subdev, "core init: %08x\n", - nvkm_rd32(device, 0x610490)); - return -EBUSY; - } - - return 0; -} - -static int -gf110_disp_core_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - - /* deactivate channel */ - nvkm_mask(device, 0x610490, 0x00000010, 0x00000000); - nvkm_mask(device, 0x610490, 0x00000003, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610490) & 0x001e0000)) - break; - ) < 0) { - nvkm_error(subdev, "core fini: %08x\n", - nvkm_rd32(device, 0x610490)); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notification */ - nvkm_mask(device, 0x610090, 0x00000001, 0x00000000); - nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000000); - - return nv50_disp_chan_fini(&mast->base, suspend); -} - -struct nv50_disp_chan_impl -gf110_disp_core_ofuncs = { - .base.ctor = nv50_disp_core_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf110_disp_core_init, - .base.fini = gf110_disp_core_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 0, - .attach = gf110_disp_dmac_object_attach, - .detach = gf110_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO sync channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gf110_disp_base_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x661080 }, - { 0x0084, 0x661084 }, - { 0x0088, 0x661088 }, - { 0x008c, 0x66108c }, - { 0x0090, 0x661090 }, - { 0x0094, 0x661094 }, - { 0x00a0, 0x6610a0 }, - { 0x00a4, 0x6610a4 }, - { 0x00c0, 0x6610c0 }, - { 0x00c4, 0x6610c4 }, - { 0x00c8, 0x6610c8 }, - { 0x00cc, 0x6610cc }, - { 0x00e0, 0x6610e0 }, - { 0x00e4, 0x6610e4 }, - { 0x00e8, 0x6610e8 }, - { 0x00ec, 0x6610ec }, - { 0x00fc, 0x6610fc }, - { 0x0100, 0x661100 }, - { 0x0104, 0x661104 }, - { 0x0108, 0x661108 }, - { 0x010c, 0x66110c }, - { 0x0110, 0x661110 }, - { 0x0114, 0x661114 }, - { 0x0118, 0x661118 }, - { 0x011c, 0x66111c }, - { 0x0130, 0x661130 }, - { 0x0134, 0x661134 }, - { 0x0138, 0x661138 }, - { 0x013c, 0x66113c }, - { 0x0140, 0x661140 }, - { 0x0144, 0x661144 }, - { 0x0148, 0x661148 }, - { 0x014c, 0x66114c }, - { 0x0150, 0x661150 }, - { 0x0154, 0x661154 }, - { 0x0158, 0x661158 }, - { 0x015c, 0x66115c }, - { 0x0160, 0x661160 }, - { 0x0164, 0x661164 }, - { 0x0168, 0x661168 }, - { 0x016c, 0x66116c }, - {} - } -}; - -static const struct nv50_disp_mthd_list -gf110_disp_base_mthd_image = { - .mthd = 0x0020, - .addr = 0x000020, - .data = { - { 0x0400, 0x661400 }, - { 0x0404, 0x661404 }, - { 0x0408, 0x661408 }, - { 0x040c, 0x66140c }, - { 0x0410, 0x661410 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -gf110_disp_base_mthd_chan = { - .name = "Base", - .addr = 0x001000, - .data = { - { "Global", 1, &gf110_disp_base_mthd_base }, - { "Image", 2, &gf110_disp_base_mthd_image }, - {} - } -}; - -struct nv50_disp_chan_impl -gf110_disp_base_ofuncs = { - .base.ctor = nv50_disp_base_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf110_disp_dmac_init, - .base.fini = gf110_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 1, - .attach = gf110_disp_dmac_object_attach, - .detach = gf110_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gf110_disp_ovly_mthd_base = { - .mthd = 0x0000, - .data = { - { 0x0080, 0x665080 }, - { 0x0084, 0x665084 }, - { 0x0088, 0x665088 }, - { 0x008c, 0x66508c }, - { 0x0090, 0x665090 }, - { 0x0094, 0x665094 }, - { 0x00a0, 0x6650a0 }, - { 0x00a4, 0x6650a4 }, - { 0x00b0, 0x6650b0 }, - { 0x00b4, 0x6650b4 }, - { 0x00b8, 0x6650b8 }, - { 0x00c0, 0x6650c0 }, - { 0x00e0, 0x6650e0 }, - { 0x00e4, 0x6650e4 }, - { 0x00e8, 0x6650e8 }, - { 0x0100, 0x665100 }, - { 0x0104, 0x665104 }, - { 0x0108, 0x665108 }, - { 0x010c, 0x66510c }, - { 0x0110, 0x665110 }, - { 0x0118, 0x665118 }, - { 0x011c, 0x66511c }, - { 0x0120, 0x665120 }, - { 0x0124, 0x665124 }, - { 0x0130, 0x665130 }, - { 0x0134, 0x665134 }, - { 0x0138, 0x665138 }, - { 0x013c, 0x66513c }, - { 0x0140, 0x665140 }, - { 0x0144, 0x665144 }, - { 0x0148, 0x665148 }, - { 0x014c, 0x66514c }, - { 0x0150, 0x665150 }, - { 0x0154, 0x665154 }, - { 0x0158, 0x665158 }, - { 0x015c, 0x66515c }, - { 0x0160, 0x665160 }, - { 0x0164, 0x665164 }, - { 0x0168, 0x665168 }, - { 0x016c, 0x66516c }, - { 0x0400, 0x665400 }, - { 0x0408, 0x665408 }, - { 0x040c, 0x66540c }, - { 0x0410, 0x665410 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -gf110_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x001000, - .data = { - { "Global", 1, &gf110_disp_ovly_mthd_base }, - {} - } -}; - -struct nv50_disp_chan_impl -gf110_disp_ovly_ofuncs = { - .base.ctor = nv50_disp_ovly_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf110_disp_dmac_init, - .base.fini = gf110_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 5, - .attach = gf110_disp_dmac_object_attach, - .detach = gf110_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO PIO channel base class - ******************************************************************************/ - -static int -gf110_disp_pioc_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; - int ret; - - ret = nv50_disp_chan_init(&pioc->base); - if (ret) - return ret; - - /* enable error reporting */ - nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); - - /* activate channel */ - nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001); - if (nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x610490 + (chid * 0x10)); - if ((tmp & 0x00030000) == 0x00010000) - break; - ) < 0) { - nvkm_error(subdev, "ch %d init: %08x\n", chid, - nvkm_rd32(device, 0x610490 + (chid * 0x10))); - return -EBUSY; - } - - return 0; -} - -static int -gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; - - nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d fini: %08x\n", chid, - nvkm_rd32(device, 0x610490 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notification */ - nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); - nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); - - return nv50_disp_chan_fini(&pioc->base, suspend); -} - -/******************************************************************************* - * EVO immediate overlay channel objects - ******************************************************************************/ - -struct nv50_disp_chan_impl -gf110_disp_oimm_ofuncs = { - .base.ctor = nv50_disp_oimm_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = gf110_disp_pioc_init, - .base.fini = gf110_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 9, -}; - -/******************************************************************************* - * EVO cursor channel objects - ******************************************************************************/ - -struct nv50_disp_chan_impl -gf110_disp_curs_ofuncs = { - .base.ctor = nv50_disp_curs_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = gf110_disp_pioc_init, - .base.fini = gf110_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 13, -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -int -gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300)); - const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300)); - const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300)); - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - int ret; - - nvif_ioctl(object, "disp scanoutpos size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp scanoutpos vers %d\n", - args->v0.version); - args->v0.vblanke = (blanke & 0xffff0000) >> 16; - args->v0.hblanke = (blanke & 0x0000ffff); - args->v0.vblanks = (blanks & 0xffff0000) >> 16; - args->v0.hblanks = (blanks & 0x0000ffff); - args->v0.vtotal = ( total & 0xffff0000) >> 16; - args->v0.htotal = ( total & 0x0000ffff); - args->v0.time[0] = ktime_to_ns(ktime_get()); - args->v0.vline = /* vline read locks hline */ - nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = - nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; - } else - return ret; - - return 0; -} - -static int -gf110_disp_main_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; - int ret, i; - u32 tmp; - - ret = nvkm_parent_init(&base->base); - if (ret) - return ret; - - /* The below segments of code copying values from one register to - * another appear to inform EVO of the display capabilities or - * something similar. - */ - - /* ... CRTC caps */ - for (i = 0; i < disp->head.nr; i++) { - tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); - nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); - tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); - nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); - tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); - nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); - } - - /* ... DAC caps */ - for (i = 0; i < disp->dac.nr; i++) { - tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); - nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp); - } - - /* ... SOR caps */ - for (i = 0; i < disp->sor.nr; i++) { - tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); - nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp); - } - - /* steal display away from vbios, or something like that */ - if (nvkm_rd32(device, 0x6100ac) & 0x00000100) { - nvkm_wr32(device, 0x6100ac, 0x00000100); - nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) - break; - ) < 0) - return -EBUSY; - } - - /* point at display engine memory area (hash table, objects) */ - nvkm_wr32(device, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); - - /* enable supervisor interrupts, disable everything else */ - nvkm_wr32(device, 0x610090, 0x00000000); - nvkm_wr32(device, 0x6100a0, 0x00000000); - nvkm_wr32(device, 0x6100b0, 0x00000307); - - /* disable underflow reporting, preventing an intermittent issue - * on some gk104 boards where the production vbios left this - * setting enabled by default. - * - * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt - */ - for (i = 0; i < disp->head.nr; i++) - nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); - - return 0; -} - -static int -gf110_disp_main_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; - - /* disable all interrupts */ - nvkm_wr32(device, 0x6100b0, 0x00000000); - - return nvkm_parent_fini(&base->base, suspend); -} - -struct nvkm_ofuncs -gf110_disp_main_ofuncs = { - .ctor = nv50_disp_main_ctor, - .dtor = nv50_disp_main_dtor, - .init = gf110_disp_main_init, - .fini = gf110_disp_main_fini, - .mthd = nv50_disp_main_mthd, - .ntfy = nvkm_disp_ntfy, -}; - -static struct nvkm_oclass -gf110_disp_main_oclass[] = { - { GF110_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -static struct nvkm_oclass -gf110_disp_sclass[] = { - { GF110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GF110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GF110_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GF110_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GF110_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - -static void -gf110_disp_vblank_init(struct nvkm_event *event, int type, int head) -{ - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - struct nvkm_device *device = disp->engine.subdev.device; - nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); -} - -static void -gf110_disp_vblank_fini(struct nvkm_event *event, int type, int head) -{ - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - struct nvkm_device *device = disp->engine.subdev.device; - nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); -} - -const struct nvkm_event_func -gf110_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = gf110_disp_vblank_init, - .fini = gf110_disp_vblank_fini, -}; - -static struct nvkm_output * -exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, - u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, - struct nvbios_outp *info) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_bios *bios = subdev->device->bios; - struct nvkm_output *outp; - u16 mask, type; - - if (or < 4) { - type = DCB_OUTPUT_ANALOG; - mask = 0; - } else { - or -= 4; - switch (ctrl & 0x00000f00) { - case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; - case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; - case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; - case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; - case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; - case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; - default: - nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); - return NULL; - } - } - - mask = 0x00c0 & (mask << 6); - mask |= 0x0001 << or; - mask |= 0x0100 << head; - - list_for_each_entry(outp, &disp->base.outp, head) { - if ((outp->info.hasht & 0xff) == type && - (outp->info.hashm & mask) == mask) { - *data = nvbios_outp_match(bios, outp->info.hasht, - outp->info.hashm, - ver, hdr, cnt, len, info); - if (!*data) - return NULL; - return outp; - } - } - - return NULL; -} - -static struct nvkm_output * -exec_script(struct nv50_disp *disp, int head, int id) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); - if (outp) { - struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, - .offset = info.script[id], - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - - return outp; -} - -static struct nvkm_output * -exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_bios *bios = device->bios; - struct nvkm_output *outp; - struct nvbios_outp info1; - struct nvbios_ocfg info2; - u8 ver, hdr, cnt, len; - u32 data, ctrl = 0; - int or; - - for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { - ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20)); - if (ctrl & (1 << head)) - break; - } - - if (or == 8) - return NULL; - - outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); - if (!outp) - return NULL; - - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - *conf = (ctrl & 0x00000f00) >> 8; - if (pclk >= 165000) - *conf |= 0x0100; - break; - case DCB_OUTPUT_LVDS: - *conf = disp->sor.lvdsconf; - break; - case DCB_OUTPUT_DP: - *conf = (ctrl & 0x00000f00) >> 8; - break; - case DCB_OUTPUT_ANALOG: - default: - *conf = 0x00ff; - break; - } - - data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); - if (data && id < 0xff) { - data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); - if (data) { - struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = bios, - .offset = data, - .outp = &outp->info, - .crtc = head, - .execute = 1, - }; - - nvbios_exec(&init); - } - } - - return outp; -} - -static void -gf110_disp_intr_unk1_0(struct nv50_disp *disp, int head) -{ - exec_script(disp, head, 1); -} - -static void -gf110_disp_intr_unk2_0(struct nv50_disp *disp, int head) -{ - struct nvkm_output *outp = exec_script(disp, head, 2); - - /* see note in nv50_disp_intr_unk20_0() */ - if (outp && outp->info.type == DCB_OUTPUT_DP) { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = nvkm_bios(disp), - .outp = &outp->info, - .crtc = head, - .offset = outpdp->info.script[4], - .execute = 1, - }; - - nvbios_exec(&init); - atomic_set(&outpdp->lt.done, 0); - } -} - -static void -gf110_disp_intr_unk2_1(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_devinit *devinit = device->devinit; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - if (pclk) - devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); - nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); -} - -static void -gf110_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, - struct dcb_output *outp) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const int or = ffs(outp->or) - 1; - const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020)); - const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300)); - const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff; - const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff; - const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff; - const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; - const u32 hoff = (head * 0x800); - const u32 soff = ( or * 0x800); - const u32 loff = (link * 0x080) + soff; - const u32 symbol = 100000; - const u32 TU = 64; - u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); - u32 clksor = nvkm_rd32(device, 0x612300 + soff); - u32 datarate, link_nr, link_bw, bits; - u64 ratio, value; - - link_nr = hweight32(dpctrl & 0x000f0000); - link_bw = (clksor & 0x007c0000) >> 18; - link_bw *= 27000; - - /* symbols/hblank - algorithm taken from comments in tegra driver */ - value = vblanke + vactive - vblanks - 7; - value = value * link_bw; - do_div(value, pclk); - value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); - nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value); - - /* symbols/vblank - algorithm taken from comments in tegra driver */ - value = vblanks - vblanke - 25; - value = value * link_bw; - do_div(value, pclk); - value = value - ((36 / link_nr) + 3) - 1; - nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value); - - /* watermark */ - if ((conf & 0x3c0) == 0x180) bits = 30; - else if ((conf & 0x3c0) == 0x140) bits = 24; - else bits = 18; - datarate = (pclk * bits) / 8; - - ratio = datarate; - ratio *= symbol; - do_div(ratio, link_nr * link_bw); - - value = (symbol - ratio) * TU; - value *= ratio; - do_div(value, symbol); - do_div(value, symbol); - - value += 5; - value |= 0x08000000; - - nvkm_wr32(device, 0x616610 + hoff, value); -} - -static void -gf110_disp_intr_unk2_2(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_output *outp; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - u32 conf, addr, data; - - outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); - if (!outp) - return; - - /* see note in nv50_disp_intr_unk20_2() */ - if (outp->info.type == DCB_OUTPUT_DP) { - u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300)); - switch ((sync & 0x000003c0) >> 6) { - case 6: pclk = pclk * 30; break; - case 5: pclk = pclk * 24; break; - case 2: - default: - pclk = pclk * 18; - break; - } - - if (nvkm_output_dp_train(outp, pclk, true)) - OUTP_ERR(outp, "link not trained before attach"); - } else { - if (disp->sor.magic) - disp->sor.magic(outp); - } - - exec_clkcmp(disp, head, 0, pclk, &conf); - - if (outp->info.type == DCB_OUTPUT_ANALOG) { - addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; - data = 0x00000000; - } else { - addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; - data = (conf & 0x0100) ? 0x00000101 : 0x00000000; - switch (outp->info.type) { - case DCB_OUTPUT_TMDS: - nvkm_mask(device, addr, 0x007c0000, 0x00280000); - break; - case DCB_OUTPUT_DP: - gf110_disp_intr_unk2_2_tu(disp, head, &outp->info); - break; - default: - break; - } - } - - nvkm_mask(device, addr, 0x00000707, data); -} - -static void -gf110_disp_intr_unk4_0(struct nv50_disp *disp, int head) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; - u32 conf; - - exec_clkcmp(disp, head, 1, pclk, &conf); -} - -void -gf110_disp_intr_supervisor(struct work_struct *work) -{ - struct nv50_disp *disp = - container_of(work, struct nv50_disp, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 mask[4]; - int head; - - nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); - for (head = 0; head < disp->head.nr; head++) { - mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); - nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); - } - - if (disp->super & 0x00000001) { - nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); - for (head = 0; head < disp->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); - gf110_disp_intr_unk1_0(disp, head); - } - } else - if (disp->super & 0x00000002) { - for (head = 0; head < disp->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); - gf110_disp_intr_unk2_0(disp, head); - } - for (head = 0; head < disp->head.nr; head++) { - if (!(mask[head] & 0x00010000)) - continue; - nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); - gf110_disp_intr_unk2_1(disp, head); - } - for (head = 0; head < disp->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); - gf110_disp_intr_unk2_2(disp, head); - } - } else - if (disp->super & 0x00000004) { - for (head = 0; head < disp->head.nr; head++) { - if (!(mask[head] & 0x00001000)) - continue; - nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); - gf110_disp_intr_unk4_0(disp, head); - } - } - - for (head = 0; head < disp->head.nr; head++) - nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); - nvkm_wr32(device, 0x6101d0, 0x80000000); -} - -static void -gf110_disp_intr_error(struct nv50_disp *disp, int chid) -{ - const struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12)); - u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12)); - u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12)); - - nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", - chid, (mthd & 0x0000ffc), data, mthd, unkn); - - if (chid == 0) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 0, - impl->mthd.core); - break; - default: - break; - } - } else - if (chid <= 4) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 1, - impl->mthd.base); - break; - default: - break; - } - } else - if (chid <= 8) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 5, - impl->mthd.ovly); - break; - default: - break; - } - } - - nvkm_wr32(device, 0x61009c, (1 << chid)); - nvkm_wr32(device, 0x6101f0 + (chid * 12), 0x90000000); -} - -void -gf110_disp_intr(struct nvkm_subdev *subdev) -{ - struct nv50_disp *disp = (void *)subdev; - struct nvkm_device *device = subdev->device; - u32 intr = nvkm_rd32(device, 0x610088); - int i; - - if (intr & 0x00000001) { - u32 stat = nvkm_rd32(device, 0x61008c); - while (stat) { - int chid = __ffs(stat); stat &= ~(1 << chid); - nv50_disp_chan_uevent_send(disp, chid); - nvkm_wr32(device, 0x61008c, 1 << chid); - } - intr &= ~0x00000001; - } - - if (intr & 0x00000002) { - u32 stat = nvkm_rd32(device, 0x61009c); - int chid = ffs(stat) - 1; - if (chid >= 0) - gf110_disp_intr_error(disp, chid); - intr &= ~0x00000002; - } - - if (intr & 0x00100000) { - u32 stat = nvkm_rd32(device, 0x6100ac); - if (stat & 0x00000007) { - disp->super = (stat & 0x00000007); - schedule_work(&disp->supervisor); - nvkm_wr32(device, 0x6100ac, disp->super); - stat &= ~0x00000007; - } - - if (stat) { - nvkm_warn(subdev, "intr24 %08x\n", stat); - nvkm_wr32(device, 0x6100ac, stat); - } - - intr &= ~0x00100000; - } - - for (i = 0; i < disp->head.nr; i++) { - u32 mask = 0x01000000 << i; - if (mask & intr) { - u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); - if (stat & 0x00000001) - nvkm_disp_vblank(&disp->base, i); - nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); - nvkm_rd32(device, 0x6100c0 + (i * 0x800)); - } - } -} - -static int -gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = (void *)parent; - struct nv50_disp *disp; - int heads = nvkm_rd32(device, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); - if (ret) - return ret; - - nv_engine(disp)->sclass = gf110_disp_main_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; - nv_subdev(disp)->intr = gf110_disp_intr; - INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); - disp->sclass = gf110_disp_sclass; - disp->head.nr = heads; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf110_hda_eld; - disp->sor.hdmi = gf110_hdmi_ctrl; - return 0; -} - -struct nvkm_oclass * -gf110_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x90), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf110_sor_dp_new, - .base.vblank = &gf110_disp_vblank_func, - .mthd.core = &gf110_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, - .mthd.ovly = &gf110_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c new file mode 100644 index 0000000000000..154185a98e017 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -0,0 +1,586 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv50.h" +#include "rootnv50.h" + +#include +#include +#include +#include +#include + +static void +gf119_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); +} + +static void +gf119_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); + struct nvkm_device *device = disp->engine.subdev.device; + nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); +} + +const struct nvkm_event_func +gf119_disp_vblank_func = { + .ctor = nvkm_disp_vblank_ctor, + .init = gf119_disp_vblank_init, + .fini = gf119_disp_vblank_fini, +}; + +static struct nvkm_output * +exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, + u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, + struct nvbios_outp *info) +{ + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_bios *bios = subdev->device->bios; + struct nvkm_output *outp; + u16 mask, type; + + if (or < 4) { + type = DCB_OUTPUT_ANALOG; + mask = 0; + } else { + or -= 4; + switch (ctrl & 0x00000f00) { + case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break; + case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break; + case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break; + case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break; + case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break; + case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break; + default: + nvkm_error(subdev, "unknown SOR mc %08x\n", ctrl); + return NULL; + } + } + + mask = 0x00c0 & (mask << 6); + mask |= 0x0001 << or; + mask |= 0x0100 << head; + + list_for_each_entry(outp, &disp->base.outp, head) { + if ((outp->info.hasht & 0xff) == type && + (outp->info.hashm & mask) == mask) { + *data = nvbios_outp_match(bios, outp->info.hasht, + outp->info.hashm, + ver, hdr, cnt, len, info); + if (!*data) + return NULL; + return outp; + } + } + + return NULL; +} + +static struct nvkm_output * +exec_script(struct nv50_disp *disp, int head, int id) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_output *outp; + struct nvbios_outp info; + u8 ver, hdr, cnt, len; + u32 data, ctrl = 0; + int or; + + for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { + ctrl = nvkm_rd32(device, 0x640180 + (or * 0x20)); + if (ctrl & (1 << head)) + break; + } + + if (or == 8) + return NULL; + + outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); + if (outp) { + struct nvbios_init init = { + .subdev = nv_subdev(disp), + .bios = bios, + .offset = info.script[id], + .outp = &outp->info, + .crtc = head, + .execute = 1, + }; + + nvbios_exec(&init); + } + + return outp; +} + +static struct nvkm_output * +exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_output *outp; + struct nvbios_outp info1; + struct nvbios_ocfg info2; + u8 ver, hdr, cnt, len; + u32 data, ctrl = 0; + int or; + + for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) { + ctrl = nvkm_rd32(device, 0x660180 + (or * 0x20)); + if (ctrl & (1 << head)) + break; + } + + if (or == 8) + return NULL; + + outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1); + if (!outp) + return NULL; + + switch (outp->info.type) { + case DCB_OUTPUT_TMDS: + *conf = (ctrl & 0x00000f00) >> 8; + if (pclk >= 165000) + *conf |= 0x0100; + break; + case DCB_OUTPUT_LVDS: + *conf = disp->sor.lvdsconf; + break; + case DCB_OUTPUT_DP: + *conf = (ctrl & 0x00000f00) >> 8; + break; + case DCB_OUTPUT_ANALOG: + default: + *conf = 0x00ff; + break; + } + + data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2); + if (data && id < 0xff) { + data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); + if (data) { + struct nvbios_init init = { + .subdev = nv_subdev(disp), + .bios = bios, + .offset = data, + .outp = &outp->info, + .crtc = head, + .execute = 1, + }; + + nvbios_exec(&init); + } + } + + return outp; +} + +static void +gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head) +{ + exec_script(disp, head, 1); +} + +static void +gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) +{ + struct nvkm_output *outp = exec_script(disp, head, 2); + + /* see note in nv50_disp_intr_unk20_0() */ + if (outp && outp->info.type == DCB_OUTPUT_DP) { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + struct nvbios_init init = { + .subdev = nv_subdev(disp), + .bios = nvkm_bios(disp), + .outp = &outp->info, + .crtc = head, + .offset = outpdp->info.script[4], + .execute = 1, + }; + + nvbios_exec(&init); + atomic_set(&outpdp->lt.done, 0); + } +} + +static void +gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_devinit *devinit = device->devinit; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + if (pclk) + devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); + nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); +} + +static void +gf119_disp_intr_unk2_2_tu(struct nv50_disp *disp, int head, + struct dcb_output *outp) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const int or = ffs(outp->or) - 1; + const u32 ctrl = nvkm_rd32(device, 0x660200 + (or * 0x020)); + const u32 conf = nvkm_rd32(device, 0x660404 + (head * 0x300)); + const s32 vactive = nvkm_rd32(device, 0x660414 + (head * 0x300)) & 0xffff; + const s32 vblanke = nvkm_rd32(device, 0x66041c + (head * 0x300)) & 0xffff; + const s32 vblanks = nvkm_rd32(device, 0x660420 + (head * 0x300)) & 0xffff; + const u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1; + const u32 hoff = (head * 0x800); + const u32 soff = ( or * 0x800); + const u32 loff = (link * 0x080) + soff; + const u32 symbol = 100000; + const u32 TU = 64; + u32 dpctrl = nvkm_rd32(device, 0x61c10c + loff); + u32 clksor = nvkm_rd32(device, 0x612300 + soff); + u32 datarate, link_nr, link_bw, bits; + u64 ratio, value; + + link_nr = hweight32(dpctrl & 0x000f0000); + link_bw = (clksor & 0x007c0000) >> 18; + link_bw *= 27000; + + /* symbols/hblank - algorithm taken from comments in tegra driver */ + value = vblanke + vactive - vblanks - 7; + value = value * link_bw; + do_div(value, pclk); + value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr); + nvkm_mask(device, 0x616620 + hoff, 0x0000ffff, value); + + /* symbols/vblank - algorithm taken from comments in tegra driver */ + value = vblanks - vblanke - 25; + value = value * link_bw; + do_div(value, pclk); + value = value - ((36 / link_nr) + 3) - 1; + nvkm_mask(device, 0x616624 + hoff, 0x00ffffff, value); + + /* watermark */ + if ((conf & 0x3c0) == 0x180) bits = 30; + else if ((conf & 0x3c0) == 0x140) bits = 24; + else bits = 18; + datarate = (pclk * bits) / 8; + + ratio = datarate; + ratio *= symbol; + do_div(ratio, link_nr * link_bw); + + value = (symbol - ratio) * TU; + value *= ratio; + do_div(value, symbol); + do_div(value, symbol); + + value += 5; + value |= 0x08000000; + + nvkm_wr32(device, 0x616610 + hoff, value); +} + +static void +gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_output *outp; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + u32 conf, addr, data; + + outp = exec_clkcmp(disp, head, 0xff, pclk, &conf); + if (!outp) + return; + + /* see note in nv50_disp_intr_unk20_2() */ + if (outp->info.type == DCB_OUTPUT_DP) { + u32 sync = nvkm_rd32(device, 0x660404 + (head * 0x300)); + switch ((sync & 0x000003c0) >> 6) { + case 6: pclk = pclk * 30; break; + case 5: pclk = pclk * 24; break; + case 2: + default: + pclk = pclk * 18; + break; + } + + if (nvkm_output_dp_train(outp, pclk, true)) + OUTP_ERR(outp, "link not trained before attach"); + } else { + if (disp->sor.magic) + disp->sor.magic(outp); + } + + exec_clkcmp(disp, head, 0, pclk, &conf); + + if (outp->info.type == DCB_OUTPUT_ANALOG) { + addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800; + data = 0x00000000; + } else { + addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800; + data = (conf & 0x0100) ? 0x00000101 : 0x00000000; + switch (outp->info.type) { + case DCB_OUTPUT_TMDS: + nvkm_mask(device, addr, 0x007c0000, 0x00280000); + break; + case DCB_OUTPUT_DP: + gf119_disp_intr_unk2_2_tu(disp, head, &outp->info); + break; + default: + break; + } + } + + nvkm_mask(device, addr, 0x00000707, data); +} + +static void +gf119_disp_intr_unk4_0(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; + u32 conf; + + exec_clkcmp(disp, head, 1, pclk, &conf); +} + +void +gf119_disp_intr_supervisor(struct work_struct *work) +{ + struct nv50_disp *disp = + container_of(work, struct nv50_disp, supervisor); + struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mask[4]; + int head; + + nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); + for (head = 0; head < disp->head.nr; head++) { + mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); + nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); + } + + if (disp->super & 0x00000001) { + nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); + for (head = 0; head < disp->head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); + gf119_disp_intr_unk1_0(disp, head); + } + } else + if (disp->super & 0x00000002) { + for (head = 0; head < disp->head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); + gf119_disp_intr_unk2_0(disp, head); + } + for (head = 0; head < disp->head.nr; head++) { + if (!(mask[head] & 0x00010000)) + continue; + nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); + gf119_disp_intr_unk2_1(disp, head); + } + for (head = 0; head < disp->head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); + gf119_disp_intr_unk2_2(disp, head); + } + } else + if (disp->super & 0x00000004) { + for (head = 0; head < disp->head.nr; head++) { + if (!(mask[head] & 0x00001000)) + continue; + nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); + gf119_disp_intr_unk4_0(disp, head); + } + } + + for (head = 0; head < disp->head.nr; head++) + nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); + nvkm_wr32(device, 0x6101d0, 0x80000000); +} + +static void +gf119_disp_intr_error(struct nv50_disp *disp, int chid) +{ + const struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12)); + u32 data = nvkm_rd32(device, 0x6101f4 + (chid * 12)); + u32 unkn = nvkm_rd32(device, 0x6101f8 + (chid * 12)); + + nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", + chid, (mthd & 0x0000ffc), data, mthd, unkn); + + if (chid == 0) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 0, + impl->mthd.core); + break; + default: + break; + } + } else + if (chid <= 4) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 1, + impl->mthd.base); + break; + default: + break; + } + } else + if (chid <= 8) { + switch (mthd & 0xffc) { + case 0x0080: + nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 5, + impl->mthd.ovly); + break; + default: + break; + } + } + + nvkm_wr32(device, 0x61009c, (1 << chid)); + nvkm_wr32(device, 0x6101f0 + (chid * 12), 0x90000000); +} + +void +gf119_disp_intr(struct nvkm_subdev *subdev) +{ + struct nv50_disp *disp = (void *)subdev; + struct nvkm_device *device = subdev->device; + u32 intr = nvkm_rd32(device, 0x610088); + int i; + + if (intr & 0x00000001) { + u32 stat = nvkm_rd32(device, 0x61008c); + while (stat) { + int chid = __ffs(stat); stat &= ~(1 << chid); + nv50_disp_chan_uevent_send(disp, chid); + nvkm_wr32(device, 0x61008c, 1 << chid); + } + intr &= ~0x00000001; + } + + if (intr & 0x00000002) { + u32 stat = nvkm_rd32(device, 0x61009c); + int chid = ffs(stat) - 1; + if (chid >= 0) + gf119_disp_intr_error(disp, chid); + intr &= ~0x00000002; + } + + if (intr & 0x00100000) { + u32 stat = nvkm_rd32(device, 0x6100ac); + if (stat & 0x00000007) { + disp->super = (stat & 0x00000007); + schedule_work(&disp->supervisor); + nvkm_wr32(device, 0x6100ac, disp->super); + stat &= ~0x00000007; + } + + if (stat) { + nvkm_warn(subdev, "intr24 %08x\n", stat); + nvkm_wr32(device, 0x6100ac, stat); + } + + intr &= ~0x00100000; + } + + for (i = 0; i < disp->head.nr; i++) { + u32 mask = 0x01000000 << i; + if (mask & intr) { + u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); + if (stat & 0x00000001) + nvkm_disp_vblank(&disp->base, i); + nvkm_mask(device, 0x6100bc + (i * 0x800), 0, 0); + nvkm_rd32(device, 0x6100c0 + (i * 0x800)); + } + } +} + +static int +gf119_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = (void *)parent; + struct nv50_disp *disp; + int heads = nvkm_rd32(device, 0x022448); + int ret; + + ret = nvkm_disp_create(parent, engine, oclass, heads, + "PDISP", "display", &disp); + *pobject = nv_object(disp); + if (ret) + return ret; + + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); + if (ret) + return ret; + + nv_engine(disp)->sclass = gf119_disp_root_oclass; + nv_engine(disp)->cclass = &nv50_disp_cclass; + nv_subdev(disp)->intr = gf119_disp_intr; + INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); + disp->sclass = gf119_disp_sclass; + disp->head.nr = heads; + disp->dac.nr = 3; + disp->sor.nr = 4; + disp->dac.power = nv50_dac_power; + disp->dac.sense = nv50_dac_sense; + disp->sor.power = nv50_sor_power; + disp->sor.hda_eld = gf119_hda_eld; + disp->sor.hdmi = gf119_hdmi_ctrl; + return 0; +} + +struct nvkm_oclass * +gf110_disp_oclass = &(struct nv50_disp_impl) { + .base.base.handle = NV_ENGINE(DISP, 0x90), + .base.base.ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf119_disp_ctor, + .dtor = _nvkm_disp_dtor, + .init = _nvkm_disp_init, + .fini = _nvkm_disp_fini, + }, + .base.outp.internal.crt = nv50_dac_output_new, + .base.outp.internal.tmds = nv50_sor_output_new, + .base.outp.internal.lvds = nv50_sor_output_new, + .base.outp.internal.dp = gf119_sor_dp_new, + .base.vblank = &gf119_disp_vblank_func, + .mthd.core = &gf119_disp_core_mthd_chan, + .mthd.base = &gf119_disp_base_mthd_chan, + .mthd.ovly = &gf119_disp_ovly_mthd_chan, + .mthd.prev = -0x020000, + .head.scanoutpos = gf119_disp_root_scanoutpos, +}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index ffd8e7798a77f..404c75278dd8c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -22,197 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gk104_disp_core_mthd_head = { - .mthd = 0x0300, - .addr = 0x000300, - .data = { - { 0x0400, 0x660400 }, - { 0x0404, 0x660404 }, - { 0x0408, 0x660408 }, - { 0x040c, 0x66040c }, - { 0x0410, 0x660410 }, - { 0x0414, 0x660414 }, - { 0x0418, 0x660418 }, - { 0x041c, 0x66041c }, - { 0x0420, 0x660420 }, - { 0x0424, 0x660424 }, - { 0x0428, 0x660428 }, - { 0x042c, 0x66042c }, - { 0x0430, 0x660430 }, - { 0x0434, 0x660434 }, - { 0x0438, 0x660438 }, - { 0x0440, 0x660440 }, - { 0x0444, 0x660444 }, - { 0x0448, 0x660448 }, - { 0x044c, 0x66044c }, - { 0x0450, 0x660450 }, - { 0x0454, 0x660454 }, - { 0x0458, 0x660458 }, - { 0x045c, 0x66045c }, - { 0x0460, 0x660460 }, - { 0x0468, 0x660468 }, - { 0x046c, 0x66046c }, - { 0x0470, 0x660470 }, - { 0x0474, 0x660474 }, - { 0x047c, 0x66047c }, - { 0x0480, 0x660480 }, - { 0x0484, 0x660484 }, - { 0x0488, 0x660488 }, - { 0x048c, 0x66048c }, - { 0x0490, 0x660490 }, - { 0x0494, 0x660494 }, - { 0x0498, 0x660498 }, - { 0x04a0, 0x6604a0 }, - { 0x04b0, 0x6604b0 }, - { 0x04b8, 0x6604b8 }, - { 0x04bc, 0x6604bc }, - { 0x04c0, 0x6604c0 }, - { 0x04c4, 0x6604c4 }, - { 0x04c8, 0x6604c8 }, - { 0x04d0, 0x6604d0 }, - { 0x04d4, 0x6604d4 }, - { 0x04e0, 0x6604e0 }, - { 0x04e4, 0x6604e4 }, - { 0x04e8, 0x6604e8 }, - { 0x04ec, 0x6604ec }, - { 0x04f0, 0x6604f0 }, - { 0x04f4, 0x6604f4 }, - { 0x04f8, 0x6604f8 }, - { 0x04fc, 0x6604fc }, - { 0x0500, 0x660500 }, - { 0x0504, 0x660504 }, - { 0x0508, 0x660508 }, - { 0x050c, 0x66050c }, - { 0x0510, 0x660510 }, - { 0x0514, 0x660514 }, - { 0x0518, 0x660518 }, - { 0x051c, 0x66051c }, - { 0x0520, 0x660520 }, - { 0x0524, 0x660524 }, - { 0x052c, 0x66052c }, - { 0x0530, 0x660530 }, - { 0x054c, 0x66054c }, - { 0x0550, 0x660550 }, - { 0x0554, 0x660554 }, - { 0x0558, 0x660558 }, - { 0x055c, 0x66055c }, - {} - } -}; - -const struct nv50_disp_mthd_chan -gk104_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &gf110_disp_core_mthd_base }, - { "DAC", 3, &gf110_disp_core_mthd_dac }, - { "SOR", 8, &gf110_disp_core_mthd_sor }, - { "PIOR", 4, &gf110_disp_core_mthd_pior }, - { "HEAD", 4, &gk104_disp_core_mthd_head }, - {} - } -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gk104_disp_ovly_mthd_base = { - .mthd = 0x0000, - .data = { - { 0x0080, 0x665080 }, - { 0x0084, 0x665084 }, - { 0x0088, 0x665088 }, - { 0x008c, 0x66508c }, - { 0x0090, 0x665090 }, - { 0x0094, 0x665094 }, - { 0x00a0, 0x6650a0 }, - { 0x00a4, 0x6650a4 }, - { 0x00b0, 0x6650b0 }, - { 0x00b4, 0x6650b4 }, - { 0x00b8, 0x6650b8 }, - { 0x00c0, 0x6650c0 }, - { 0x00c4, 0x6650c4 }, - { 0x00e0, 0x6650e0 }, - { 0x00e4, 0x6650e4 }, - { 0x00e8, 0x6650e8 }, - { 0x0100, 0x665100 }, - { 0x0104, 0x665104 }, - { 0x0108, 0x665108 }, - { 0x010c, 0x66510c }, - { 0x0110, 0x665110 }, - { 0x0118, 0x665118 }, - { 0x011c, 0x66511c }, - { 0x0120, 0x665120 }, - { 0x0124, 0x665124 }, - { 0x0130, 0x665130 }, - { 0x0134, 0x665134 }, - { 0x0138, 0x665138 }, - { 0x013c, 0x66513c }, - { 0x0140, 0x665140 }, - { 0x0144, 0x665144 }, - { 0x0148, 0x665148 }, - { 0x014c, 0x66514c }, - { 0x0150, 0x665150 }, - { 0x0154, 0x665154 }, - { 0x0158, 0x665158 }, - { 0x015c, 0x66515c }, - { 0x0160, 0x665160 }, - { 0x0164, 0x665164 }, - { 0x0168, 0x665168 }, - { 0x016c, 0x66516c }, - { 0x0400, 0x665400 }, - { 0x0404, 0x665404 }, - { 0x0408, 0x665408 }, - { 0x040c, 0x66540c }, - { 0x0410, 0x665410 }, - {} - } -}; - -const struct nv50_disp_mthd_chan -gk104_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x001000, - .data = { - { "Global", 1, &gk104_disp_ovly_mthd_base }, - {} - } -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gk104_disp_sclass[] = { - { GK104_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK104_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gk104_disp_main_oclass[] = { - { GK104_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -230,14 +40,14 @@ gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gk104_disp_main_oclass; + nv_engine(disp)->sclass = gk104_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; - nv_subdev(disp)->intr = gf110_disp_intr; - INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + nv_subdev(disp)->intr = gf119_disp_intr; + INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); disp->sclass = gk104_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; @@ -245,7 +55,7 @@ gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, disp->dac.power = nv50_dac_power; disp->dac.sense = nv50_dac_sense; disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hda_eld = gf119_hda_eld; disp->sor.hdmi = gk104_hdmi_ctrl; return 0; } @@ -262,11 +72,11 @@ gk104_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.crt = nv50_dac_output_new, .base.outp.internal.tmds = nv50_sor_output_new, .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf110_sor_dp_new, - .base.vblank = &gf110_disp_vblank_func, + .base.outp.internal.dp = gf119_sor_dp_new, + .base.vblank = &gf119_disp_vblank_func, .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, + .mthd.base = &gf119_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, + .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index ca2d6f1ea4ba0..2bb3515060af5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -22,32 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gk110_disp_sclass[] = { - { GK110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gk110_disp_main_oclass[] = { - { GK110_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -65,14 +40,14 @@ gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gk110_disp_main_oclass; + nv_engine(disp)->sclass = gk110_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; - nv_subdev(disp)->intr = gf110_disp_intr; - INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + nv_subdev(disp)->intr = gf119_disp_intr; + INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); disp->sclass = gk110_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; @@ -80,7 +55,7 @@ gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, disp->dac.power = nv50_dac_power; disp->dac.sense = nv50_dac_sense; disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hda_eld = gf119_hda_eld; disp->sor.hdmi = gk104_hdmi_ctrl; return 0; } @@ -97,11 +72,11 @@ gk110_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.crt = nv50_dac_output_new, .base.outp.internal.tmds = nv50_sor_output_new, .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf110_sor_dp_new, - .base.vblank = &gf110_disp_vblank_func, + .base.outp.internal.dp = gf119_sor_dp_new, + .base.vblank = &gf119_disp_vblank_func, .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, + .mthd.base = &gf119_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, + .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index f841d820a7939..fbc6b7c861896 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -22,32 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gm107_disp_sclass[] = { - { GM107_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gm107_disp_main_oclass[] = { - { GM107_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -65,14 +40,14 @@ gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gm107_disp_main_oclass; + nv_engine(disp)->sclass = gm107_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; - nv_subdev(disp)->intr = gf110_disp_intr; - INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + nv_subdev(disp)->intr = gf119_disp_intr; + INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); disp->sclass = gm107_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; @@ -80,7 +55,7 @@ gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, disp->dac.power = nv50_dac_power; disp->dac.sense = nv50_dac_sense; disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf110_hda_eld; + disp->sor.hda_eld = gf119_hda_eld; disp->sor.hdmi = gk104_hdmi_ctrl; return 0; } @@ -97,11 +72,11 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.crt = nv50_dac_output_new, .base.outp.internal.tmds = nv50_sor_output_new, .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf110_sor_dp_new, - .base.vblank = &gf110_disp_vblank_func, + .base.outp.internal.dp = gf119_sor_dp_new, + .base.vblank = &gf119_disp_vblank_func, .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, + .mthd.base = &gf119_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, + .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index 8da317468bdf3..bf6ede5c424e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -22,33 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outpdp.h" - -#include - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gm204_disp_sclass[] = { - { GM204_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gm204_disp_main_oclass[] = { - { GM204_DISP, &gf110_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -66,14 +40,14 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &disp->uevent); + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gm204_disp_main_oclass; + nv_engine(disp)->sclass = gm204_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; - nv_subdev(disp)->intr = gf110_disp_intr; - INIT_WORK(&disp->supervisor, gf110_disp_intr_supervisor); + nv_subdev(disp)->intr = gf119_disp_intr; + INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); disp->sclass = gm204_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; @@ -81,8 +55,8 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, disp->dac.power = nv50_dac_power; disp->dac.sense = nv50_dac_sense; disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf110_hda_eld; - disp->sor.hdmi = gf110_hdmi_ctrl; + disp->sor.hda_eld = gf119_hda_eld; + disp->sor.hdmi = gf119_hdmi_ctrl; disp->sor.magic = gm204_sor_magic; return 0; } @@ -100,10 +74,10 @@ gm204_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.tmds = nv50_sor_output_new, .base.outp.internal.lvds = nv50_sor_output_new, .base.outp.internal.dp = gm204_sor_dp_new, - .base.vblank = &gf110_disp_vblank_func, + .base.vblank = &gf119_disp_vblank_func, .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf110_disp_base_mthd_chan, + .mthd.base = &gf119_disp_base_mthd_chan, .mthd.ovly = &gk104_disp_ovly_mthd_chan, .mthd.prev = -0x020000, - .head.scanoutpos = gf110_disp_main_scanoutpos, + .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 7f9f3a0da5f4a..811f092a2df0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -22,77 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -gt200_disp_ovly_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x6109a0 }, - { 0x0088, 0x6109c0 }, - { 0x008c, 0x6109c8 }, - { 0x0090, 0x6109b4 }, - { 0x0094, 0x610970 }, - { 0x00a0, 0x610998 }, - { 0x00a4, 0x610964 }, - { 0x00b0, 0x610c98 }, - { 0x00b4, 0x610ca4 }, - { 0x00b8, 0x610cac }, - { 0x00c0, 0x610958 }, - { 0x00e0, 0x6109a8 }, - { 0x00e4, 0x6109d0 }, - { 0x00e8, 0x6109d8 }, - { 0x0100, 0x61094c }, - { 0x0104, 0x610984 }, - { 0x0108, 0x61098c }, - { 0x0800, 0x6109f8 }, - { 0x0808, 0x610a08 }, - { 0x080c, 0x610a10 }, - { 0x0810, 0x610a00 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -gt200_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x000540, - .data = { - { "Global", 1, >200_disp_ovly_mthd_base }, - {} - } -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gt200_disp_sclass[] = { - { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gt200_disp_main_oclass[] = { - { GT200_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -112,7 +42,7 @@ gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(disp)->sclass = gt200_disp_main_oclass; + nv_engine(disp)->sclass = gt200_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); @@ -148,5 +78,5 @@ gt200_disp_oclass = &(struct nv50_disp_impl) { .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = >200_disp_ovly_mthd_chan, .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, + .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index ef6c713c3d50b..fdde7ce18ce1d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -22,32 +22,7 @@ * Authors: Ben Skeggs */ #include "nv50.h" - -#include - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -static struct nvkm_oclass -gt215_disp_sclass[] = { - { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -static struct nvkm_oclass -gt215_disp_main_oclass[] = { - { GT214_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ +#include "rootnv50.h" static int gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -67,7 +42,7 @@ gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(disp)->sclass = gt215_disp_main_oclass; + nv_engine(disp)->sclass = gt215_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); @@ -105,5 +80,5 @@ gt215_disp_oclass = &(struct nv50_disp_impl) { .mthd.base = &g84_disp_base_mthd_chan, .mthd.ovly = &g84_disp_ovly_mthd_chan, .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, + .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c similarity index 98% rename from drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c rename to drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c index 3e940dd0fc2fc..af99efbd63f72 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf119.c @@ -33,7 +33,7 @@ #include int -gf110_hda_eld(NV50_DISP_MTHD_V1) +gf119_hda_eld(NV50_DISP_MTHD_V1) { struct nvkm_device *device = disp->base.engine.subdev.device; union { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c similarity index 98% rename from drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c rename to drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c index fea4d11a49e56..b5af025d3b047 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf119.c @@ -29,7 +29,7 @@ #include int -gf110_hdmi_ctrl(NV50_DISP_MTHD_V1) +gf119_hdmi_ctrl(NV50_DISP_MTHD_V1) { struct nvkm_device *device = disp->base.engine.subdev.device; const u32 hoff = (head * 0x800); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index ab5f8429e680b..ceac0c0bbb4fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -23,105 +23,6 @@ */ #include "priv.h" -#include - -#include -#include - -static int -nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, - void *data, u32 size, int head) -{ - struct nvkm_device *device = disp->engine.subdev.device; - const u32 hoff = head * 0x2000; - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - u32 line; - int ret; - - nvif_ioctl(object, "disp scanoutpos size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp scanoutpos vers %d\n", - args->v0.version); - args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff; - args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff; - args->v0.vblanke = args->v0.vtotal - 1; - - args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff; - args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff; - args->v0.hblanke = args->v0.htotal - 1; - - /* - * If output is vga instead of digital then vtotal/htotal is - * invalid so we have to give up and trigger the timestamping - * fallback in the drm core. - */ - if (!args->v0.vtotal || !args->v0.htotal) - return -ENOTSUPP; - - args->v0.time[0] = ktime_to_ns(ktime_get()); - line = nvkm_rd32(device, 0x600868 + hoff); - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = (line & 0xffff0000) >> 16; - args->v0.vline = (line & 0x0000ffff); - } else - return ret; - - return 0; -} - -static int -nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - union { - struct nv04_disp_mthd_v0 v0; - } *args = data; - struct nvkm_disp *disp = (void *)object->engine; - int head, ret; - - nvif_ioctl(object, "disp mthd size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, true)) { - nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); - mthd = args->v0.method; - head = args->v0.head; - } else - return ret; - - if (head < 0 || head >= 2) - return -ENXIO; - - switch (mthd) { - case NV04_DISP_SCANOUTPOS: - return nv04_disp_scanoutpos(object, disp, data, size, head); - default: - break; - } - - return -EINVAL; -} - -static struct nvkm_ofuncs -nv04_disp_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - .mthd = nv04_disp_mthd, - .ntfy = nvkm_disp_ntfy, -}; - -static struct nvkm_oclass -nv04_disp_sclass[] = { - { NV04_DISP, &nv04_disp_ofuncs }, - {}, -}; - -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - static void nv04_disp_vblank_init(struct nvkm_event *event, int type, int head) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 36241cf9173e5..240a5438c7acd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -22,1265 +22,16 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "outp.h" -#include "outpdp.h" +#include "rootnv50.h" #include -#include #include -#include -#include -#include +#include #include -#include #include #include #include #include -#include -#include - -#include -#include -#include - -/******************************************************************************* - * EVO channel base class - ******************************************************************************/ - -static int -nv50_disp_chan_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) -{ - const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs; - struct nv50_disp_base *base = (void *)parent; - struct nv50_disp_chan *chan; - int chid = impl->chid + head; - int ret; - - if (base->chan & (1 << chid)) - return -EBUSY; - base->chan |= (1 << chid); - - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - (1ULL << NVDEV_ENGINE_DMAOBJ), - length, pobject); - chan = *pobject; - if (ret) - return ret; - chan->chid = chid; - - nv_parent(chan)->object_attach = impl->attach; - nv_parent(chan)->object_detach = impl->detach; - return 0; -} - -static void -nv50_disp_chan_destroy(struct nv50_disp_chan *chan) -{ - struct nv50_disp_base *base = (void *)nv_object(chan)->parent; - base->chan &= ~(1 << chan->chid); - nvkm_namedb_destroy(&chan->base); -} - -static void -nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000000 << index); - nvkm_wr32(device, 0x610020, 0x00000001 << index); -} - -static void -nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index) -{ - struct nv50_disp *disp = container_of(event, typeof(*disp), uevent); - struct nvkm_device *device = disp->base.engine.subdev.device; - nvkm_wr32(device, 0x610020, 0x00000001 << index); - nvkm_mask(device, 0x610028, 0x00000001 << index, 0x00000001 << index); -} - -void -nv50_disp_chan_uevent_send(struct nv50_disp *disp, int chid) -{ - struct nvif_notify_uevent_rep { - } rep; - - nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep)); -} - -int -nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - struct nv50_disp_dmac *dmac = (void *)object; - union { - struct nvif_notify_uevent_req none; - } *args = data; - int ret; - - if (nvif_unvers(args->none)) { - notify->size = sizeof(struct nvif_notify_uevent_rep); - notify->types = 1; - notify->index = dmac->base.chid; - return 0; - } - - return ret; -} - -const struct nvkm_event_func -nv50_disp_chan_uevent = { - .ctor = nv50_disp_chan_uevent_ctor, - .init = nv50_disp_chan_uevent_init, - .fini = nv50_disp_chan_uevent_fini, -}; - -int -nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **pevent) -{ - struct nv50_disp *disp = (void *)object->engine; - switch (type) { - case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: - *pevent = &disp->uevent; - return 0; - default: - break; - } - return -EINVAL; -} - -int -nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) -{ - struct nv50_disp_chan *chan = (void *)object; - *addr = nv_device_resource_start(nv_device(object), 0) + - 0x640000 + (chan->chid * 0x1000); - *size = 0x001000; - return 0; -} - -u32 -nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) -{ - struct nv50_disp_chan *chan = (void *)object; - struct nvkm_device *device = object->engine->subdev.device; - return nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); -} - -void -nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nv50_disp_chan *chan = (void *)object; - struct nvkm_device *device = object->engine->subdev.device; - nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); -} - -/******************************************************************************* - * EVO DMA channel base class - ******************************************************************************/ - -static int -nv50_disp_dmac_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 name) -{ - struct nv50_disp_base *base = (void *)parent->parent; - struct nv50_disp_chan *chan = (void *)parent; - u32 addr = nv_gpuobj(object)->node->offset; - u32 chid = chan->chid; - u32 data = (chid << 28) | (addr << 10) | chid; - return nvkm_ramht_insert(base->ramht, NULL, chid, 0, name, data); -} - -static void -nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv50_disp_base *base = (void *)parent->parent; - nvkm_ramht_remove(base->ramht, cookie); -} - -static int -nv50_disp_dmac_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, u64 pushbuf, int head, - int length, void **pobject) -{ - struct nvkm_device *device = parent->engine->subdev.device; - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_dma *dma = device->dma; - struct nvkm_dmaobj *dmaobj; - struct nv50_disp_dmac *dmac; - int ret; - - ret = nv50_disp_chan_create_(parent, engine, oclass, head, - length, pobject); - dmac = *pobject; - if (ret) - return ret; - - dmaobj = nvkm_dma_search(dma, client, pushbuf); - if (!dmaobj) - return -ENOENT; - - if (dmaobj->limit - dmaobj->start != 0xfff) - return -EINVAL; - - switch (dmaobj->target) { - case NV_MEM_TARGET_VRAM: - dmac->push = 0x00000001 | dmaobj->start >> 8; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - dmac->push = 0x00000003 | dmaobj->start >> 8; - break; - default: - return -EINVAL; - } - - return 0; -} - -void -nv50_disp_dmac_dtor(struct nvkm_object *object) -{ - struct nv50_disp_dmac *dmac = (void *)object; - nv50_disp_chan_destroy(&dmac->base); -} - -static int -nv50_disp_dmac_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; - int ret; - - ret = nv50_disp_chan_init(&dmac->base); - if (ret) - return ret; - - /* enable error reporting */ - nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid); - - /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610204 + (chid * 0x0010), dmac->push); - nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000); - nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid); - nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); - nvkm_wr32(device, 0x640000 + (chid * 0x1000), 0x00000000); - nvkm_wr32(device, 0x610200 + (chid * 0x0010), 0x00000013); - - /* wait for it to go inactive */ - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x80000000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d init timeout, %08x\n", chid, - nvkm_rd32(device, 0x610200 + (chid * 0x10))); - return -EBUSY; - } - - return 0; -} - -static int -nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; - - /* deactivate channel */ - nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); - nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x001e0000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid, - nvkm_rd32(device, 0x610200 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notifications */ - nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid); - - return nv50_disp_chan_fini(&dmac->base, suspend); -} - -/******************************************************************************* - * EVO master channel object - ******************************************************************************/ - -static void -nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, - const struct nv50_disp_mthd_list *list, int inst) -{ - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int i; - - for (i = 0; list->data[i].mthd; i++) { - if (list->data[i].addr) { - u32 next = nvkm_rd32(device, list->data[i].addr + base + 0); - u32 prev = nvkm_rd32(device, list->data[i].addr + base + c); - u32 mthd = list->data[i].mthd + (list->mthd * inst); - const char *name = list->data[i].name; - char mods[16]; - - if (prev != next) - snprintf(mods, sizeof(mods), "-> %08x", next); - else - snprintf(mods, sizeof(mods), "%13c", ' '); - - nvkm_printk_(subdev, debug, info, - "\t%04x: %08x %s%s%s\n", - mthd, prev, mods, name ? " // " : "", - name ? name : ""); - } - } -} - -void -nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, - const struct nv50_disp_mthd_chan *chan) -{ - struct nvkm_object *object = nv_object(disp); - const struct nv50_disp_impl *impl = (void *)object->oclass; - const struct nv50_disp_mthd_list *list; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - int i, j; - - if (debug > nv_subdev(disp)->debug) - return; - - for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { - u32 base = head * chan->addr; - for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { - const char *cname = chan->name; - const char *sname = ""; - char cname_[16], sname_[16]; - - if (chan->addr) { - snprintf(cname_, sizeof(cname_), "%s %d", - chan->name, head); - cname = cname_; - } - - if (chan->data[i].nr > 1) { - snprintf(sname_, sizeof(sname_), " - %s %d", - chan->data[i].name, j); - sname = sname_; - } - - nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname); - nv50_disp_mthd_list(disp, debug, base, impl->mthd.prev, - list, j); - } - } -} - -const struct nv50_disp_mthd_list -nv50_disp_core_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x610bb8 }, - { 0x0088, 0x610b9c }, - { 0x008c, 0x000000 }, - {} - } -}; - -static const struct nv50_disp_mthd_list -nv50_disp_core_mthd_dac = { - .mthd = 0x0080, - .addr = 0x000008, - .data = { - { 0x0400, 0x610b58 }, - { 0x0404, 0x610bdc }, - { 0x0420, 0x610828 }, - {} - } -}; - -const struct nv50_disp_mthd_list -nv50_disp_core_mthd_sor = { - .mthd = 0x0040, - .addr = 0x000008, - .data = { - { 0x0600, 0x610b70 }, - {} - } -}; - -const struct nv50_disp_mthd_list -nv50_disp_core_mthd_pior = { - .mthd = 0x0040, - .addr = 0x000008, - .data = { - { 0x0700, 0x610b80 }, - {} - } -}; - -static const struct nv50_disp_mthd_list -nv50_disp_core_mthd_head = { - .mthd = 0x0400, - .addr = 0x000540, - .data = { - { 0x0800, 0x610ad8 }, - { 0x0804, 0x610ad0 }, - { 0x0808, 0x610a48 }, - { 0x080c, 0x610a78 }, - { 0x0810, 0x610ac0 }, - { 0x0814, 0x610af8 }, - { 0x0818, 0x610b00 }, - { 0x081c, 0x610ae8 }, - { 0x0820, 0x610af0 }, - { 0x0824, 0x610b08 }, - { 0x0828, 0x610b10 }, - { 0x082c, 0x610a68 }, - { 0x0830, 0x610a60 }, - { 0x0834, 0x000000 }, - { 0x0838, 0x610a40 }, - { 0x0840, 0x610a24 }, - { 0x0844, 0x610a2c }, - { 0x0848, 0x610aa8 }, - { 0x084c, 0x610ab0 }, - { 0x0860, 0x610a84 }, - { 0x0864, 0x610a90 }, - { 0x0868, 0x610b18 }, - { 0x086c, 0x610b20 }, - { 0x0870, 0x610ac8 }, - { 0x0874, 0x610a38 }, - { 0x0880, 0x610a58 }, - { 0x0884, 0x610a9c }, - { 0x08a0, 0x610a70 }, - { 0x08a4, 0x610a50 }, - { 0x08a8, 0x610ae0 }, - { 0x08c0, 0x610b28 }, - { 0x08c4, 0x610b30 }, - { 0x08c8, 0x610b40 }, - { 0x08d4, 0x610b38 }, - { 0x08d8, 0x610b48 }, - { 0x08dc, 0x610b50 }, - { 0x0900, 0x610a18 }, - { 0x0904, 0x610ab8 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -nv50_disp_core_mthd_chan = { - .name = "Core", - .addr = 0x000000, - .data = { - { "Global", 1, &nv50_disp_core_mthd_base }, - { "DAC", 3, &nv50_disp_core_mthd_dac }, - { "SOR", 2, &nv50_disp_core_mthd_sor }, - { "PIOR", 3, &nv50_disp_core_mthd_pior }, - { "HEAD", 2, &nv50_disp_core_mthd_head }, - {} - } -}; - -int -nv50_disp_core_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_core_channel_dma_v0 v0; - } *args = data; - struct nv50_disp_dmac *mast; - int ret; - - nvif_ioctl(parent, "create disp core channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp core channel dma vers %d " - "pushbuf %016llx\n", - args->v0.version, args->v0.pushbuf); - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - 0, sizeof(*mast), (void **)&mast); - *pobject = nv_object(mast); - if (ret) - return ret; - - return 0; -} - -static int -nv50_disp_core_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int ret; - - ret = nv50_disp_chan_init(&mast->base); - if (ret) - return ret; - - /* enable error reporting */ - nvkm_mask(device, 0x610028, 0x00010000, 0x00010000); - - /* attempt to unstick channel from some unknown state */ - if ((nvkm_rd32(device, 0x610200) & 0x009f0000) == 0x00020000) - nvkm_mask(device, 0x610200, 0x00800000, 0x00800000); - if ((nvkm_rd32(device, 0x610200) & 0x003f0000) == 0x00030000) - nvkm_mask(device, 0x610200, 0x00600000, 0x00600000); - - /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610204, mast->push); - nvkm_wr32(device, 0x610208, 0x00010000); - nvkm_wr32(device, 0x61020c, 0x00000000); - nvkm_mask(device, 0x610200, 0x00000010, 0x00000010); - nvkm_wr32(device, 0x640000, 0x00000000); - nvkm_wr32(device, 0x610200, 0x01000013); - - /* wait for it to go inactive */ - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610200) & 0x80000000)) - break; - ) < 0) { - nvkm_error(subdev, "core init: %08x\n", - nvkm_rd32(device, 0x610200)); - return -EBUSY; - } - - return 0; -} - -static int -nv50_disp_core_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - - /* deactivate channel */ - nvkm_mask(device, 0x610200, 0x00000010, 0x00000000); - nvkm_mask(device, 0x610200, 0x00000003, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610200) & 0x001e0000)) - break; - ) < 0) { - nvkm_error(subdev, "core fini: %08x\n", - nvkm_rd32(device, 0x610200)); - if (suspend) - return -EBUSY; - } - - /* disable error reporting and completion notifications */ - nvkm_mask(device, 0x610028, 0x00010001, 0x00000000); - - return nv50_disp_chan_fini(&mast->base, suspend); -} - -struct nv50_disp_chan_impl -nv50_disp_core_ofuncs = { - .base.ctor = nv50_disp_core_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_core_init, - .base.fini = nv50_disp_core_fini, - .base.map = nv50_disp_chan_map, - .base.ntfy = nv50_disp_chan_ntfy, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 0, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO sync channel objects - ******************************************************************************/ - -static const struct nv50_disp_mthd_list -nv50_disp_base_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x0008c4 }, - { 0x0088, 0x0008d0 }, - { 0x008c, 0x0008dc }, - { 0x0090, 0x0008e4 }, - { 0x0094, 0x610884 }, - { 0x00a0, 0x6108a0 }, - { 0x00a4, 0x610878 }, - { 0x00c0, 0x61086c }, - { 0x00e0, 0x610858 }, - { 0x00e4, 0x610860 }, - { 0x00e8, 0x6108ac }, - { 0x00ec, 0x6108b4 }, - { 0x0100, 0x610894 }, - { 0x0110, 0x6108bc }, - { 0x0114, 0x61088c }, - {} - } -}; - -const struct nv50_disp_mthd_list -nv50_disp_base_mthd_image = { - .mthd = 0x0400, - .addr = 0x000000, - .data = { - { 0x0800, 0x6108f0 }, - { 0x0804, 0x6108fc }, - { 0x0808, 0x61090c }, - { 0x080c, 0x610914 }, - { 0x0810, 0x610904 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -nv50_disp_base_mthd_chan = { - .name = "Base", - .addr = 0x000540, - .data = { - { "Global", 1, &nv50_disp_base_mthd_base }, - { "Image", 2, &nv50_disp_base_mthd_image }, - {} - } -}; - -int -nv50_disp_base_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_base_channel_dma_v0 v0; - } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - nvif_ioctl(parent, "create disp base channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp base channel dma vers %d " - "pushbuf %016llx head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - args->v0.head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_base_ofuncs = { - .base.ctor = nv50_disp_base_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_dmac_init, - .base.fini = nv50_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 1, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO overlay channel objects - ******************************************************************************/ - -const struct nv50_disp_mthd_list -nv50_disp_ovly_mthd_base = { - .mthd = 0x0000, - .addr = 0x000000, - .data = { - { 0x0080, 0x000000 }, - { 0x0084, 0x0009a0 }, - { 0x0088, 0x0009c0 }, - { 0x008c, 0x0009c8 }, - { 0x0090, 0x6109b4 }, - { 0x0094, 0x610970 }, - { 0x00a0, 0x610998 }, - { 0x00a4, 0x610964 }, - { 0x00c0, 0x610958 }, - { 0x00e0, 0x6109a8 }, - { 0x00e4, 0x6109d0 }, - { 0x00e8, 0x6109d8 }, - { 0x0100, 0x61094c }, - { 0x0104, 0x610984 }, - { 0x0108, 0x61098c }, - { 0x0800, 0x6109f8 }, - { 0x0808, 0x610a08 }, - { 0x080c, 0x610a10 }, - { 0x0810, 0x610a00 }, - {} - } -}; - -static const struct nv50_disp_mthd_chan -nv50_disp_ovly_mthd_chan = { - .name = "Overlay", - .addr = 0x000540, - .data = { - { "Global", 1, &nv50_disp_ovly_mthd_base }, - {} - } -}; - -int -nv50_disp_ovly_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_overlay_channel_dma_v0 v0; - } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp overlay channel dma vers %d " - "pushbuf %016llx head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - args->v0.head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_ovly_ofuncs = { - .base.ctor = nv50_disp_ovly_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_dmac_init, - .base.fini = nv50_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 3, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, -}; - -/******************************************************************************* - * EVO PIO channel base class - ******************************************************************************/ - -static int -nv50_disp_pioc_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) -{ - return nv50_disp_chan_create_(parent, engine, oclass, head, - length, pobject); -} - -void -nv50_disp_pioc_dtor(struct nvkm_object *object) -{ - struct nv50_disp_pioc *pioc = (void *)object; - nv50_disp_chan_destroy(&pioc->base); -} - -static int -nv50_disp_pioc_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; - int ret; - - ret = nv50_disp_chan_init(&pioc->base); - if (ret) - return ret; - - nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d timeout0: %08x\n", chid, - nvkm_rd32(device, 0x610200 + (chid * 0x10))); - return -EBUSY; - } - - nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001); - if (nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x610200 + (chid * 0x10)); - if ((tmp & 0x00030000) == 0x00010000) - break; - ) < 0) { - nvkm_error(subdev, "ch %d timeout1: %08x\n", chid, - nvkm_rd32(device, 0x610200 + (chid * 0x10))); - return -EBUSY; - } - - return 0; -} - -static int -nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; - struct nvkm_subdev *subdev = &disp->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; - - nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) - break; - ) < 0) { - nvkm_error(subdev, "ch %d timeout: %08x\n", chid, - nvkm_rd32(device, 0x610200 + (chid * 0x10))); - if (suspend) - return -EBUSY; - } - - return nv50_disp_chan_fini(&pioc->base, suspend); -} - -/******************************************************************************* - * EVO immediate overlay channel objects - ******************************************************************************/ - -int -nv50_disp_oimm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_overlay_v0 v0; - } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; - - nvif_ioctl(parent, "create disp overlay size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp overlay vers %d head %d\n", - args->v0.version, args->v0.head); - if (args->v0.head > disp->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_oimm_ofuncs = { - .base.ctor = nv50_disp_oimm_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = nv50_disp_pioc_init, - .base.fini = nv50_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 5, -}; - -/******************************************************************************* - * EVO cursor channel objects - ******************************************************************************/ - -int -nv50_disp_curs_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_cursor_v0 v0; - } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; - - nvif_ioctl(parent, "create disp cursor size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp cursor vers %d head %d\n", - args->v0.version, args->v0.head); - if (args->v0.head > disp->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_curs_ofuncs = { - .base.ctor = nv50_disp_curs_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = nv50_disp_pioc_init, - .base.fini = nv50_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, - .chid = 7, -}; - -/******************************************************************************* - * Base display object - ******************************************************************************/ - -int -nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0) -{ - struct nvkm_device *device = disp->base.engine.subdev.device; - const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540)); - const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540)); - const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540)); - union { - struct nv04_disp_scanoutpos_v0 v0; - } *args = data; - int ret; - - nvif_ioctl(object, "disp scanoutpos size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp scanoutpos vers %d\n", - args->v0.version); - args->v0.vblanke = (blanke & 0xffff0000) >> 16; - args->v0.hblanke = (blanke & 0x0000ffff); - args->v0.vblanks = (blanks & 0xffff0000) >> 16; - args->v0.hblanks = (blanks & 0x0000ffff); - args->v0.vtotal = ( total & 0xffff0000) >> 16; - args->v0.htotal = ( total & 0x0000ffff); - args->v0.time[0] = ktime_to_ns(ktime_get()); - args->v0.vline = /* vline read locks hline */ - nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; - args->v0.time[1] = ktime_to_ns(ktime_get()); - args->v0.hline = - nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; - } else - return ret; - - return 0; -} - -int -nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) -{ - const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); - union { - struct nv50_disp_mthd_v0 v0; - struct nv50_disp_mthd_v1 v1; - } *args = data; - struct nv50_disp *disp = (void *)object->engine; - struct nvkm_output *outp = NULL; - struct nvkm_output *temp; - u16 type, mask = 0; - int head, ret; - - if (mthd != NV50_DISP_MTHD) - return -EINVAL; - - nvif_ioctl(object, "disp mthd size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, true)) { - nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", - args->v0.version, args->v0.method, args->v0.head); - mthd = args->v0.method; - head = args->v0.head; - } else - if (nvif_unpack(args->v1, 1, 1, true)) { - nvif_ioctl(object, "disp mthd vers %d mthd %02x " - "type %04x mask %04x\n", - args->v1.version, args->v1.method, - args->v1.hasht, args->v1.hashm); - mthd = args->v1.method; - type = args->v1.hasht; - mask = args->v1.hashm; - head = ffs((mask >> 8) & 0x0f) - 1; - } else - return ret; - - if (head < 0 || head >= disp->head.nr) - return -ENXIO; - - if (mask) { - list_for_each_entry(temp, &disp->base.outp, head) { - if ((temp->info.hasht == type) && - (temp->info.hashm & mask) == mask) { - outp = temp; - break; - } - } - if (outp == NULL) - return -ENXIO; - } - - switch (mthd) { - case NV50_DISP_SCANOUTPOS: - return impl->head.scanoutpos(object, disp, data, size, head); - default: - break; - } - - switch (mthd * !!outp) { - case NV50_DISP_MTHD_V1_DAC_PWR: - return disp->dac.power(object, disp, data, size, head, outp); - case NV50_DISP_MTHD_V1_DAC_LOAD: - return disp->dac.sense(object, disp, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_PWR: - return disp->sor.power(object, disp, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_HDA_ELD: - if (!disp->sor.hda_eld) - return -ENODEV; - return disp->sor.hda_eld(object, disp, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: - if (!disp->sor.hdmi) - return -ENODEV; - return disp->sor.hdmi(object, disp, data, size, head, outp); - case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { - union { - struct nv50_disp_sor_lvds_script_v0 v0; - } *args = data; - nvif_ioctl(object, "disp sor lvds script size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp sor lvds script " - "vers %d name %04x\n", - args->v0.version, args->v0.script); - disp->sor.lvdsconf = args->v0.script; - return 0; - } else - return ret; - } - break; - case NV50_DISP_MTHD_V1_SOR_DP_PWR: { - struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); - union { - struct nv50_disp_sor_dp_pwr_v0 v0; - } *args = data; - nvif_ioctl(object, "disp sor dp pwr size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n", - args->v0.version, args->v0.state); - if (args->v0.state == 0) { - nvkm_notify_put(&outpdp->irq); - outpdp->func->lnk_pwr(outpdp, 0); - atomic_set(&outpdp->lt.done, 0); - return 0; - } else - if (args->v0.state != 0) { - nvkm_output_dp_train(&outpdp->base, 0, true); - return 0; - } - } else - return ret; - } - break; - case NV50_DISP_MTHD_V1_PIOR_PWR: - if (!disp->pior.power) - return -ENODEV; - return disp->pior.power(object, disp, data, size, head, outp); - default: - break; - } - - return -EINVAL; -} - -int -nv50_disp_main_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_base *base; - struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_gpuobj *instmem = (void *)parent; - int ret; - - ret = nvkm_parent_create(parent, engine, oclass, 0, - disp->sclass, 0, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - return nvkm_ramht_new(device, 0x1000, 0, instmem, &base->ramht); -} - -void -nv50_disp_main_dtor(struct nvkm_object *object) -{ - struct nv50_disp_base *base = (void *)object; - nvkm_ramht_del(&base->ramht); - nvkm_parent_destroy(&base->base); -} - -static int -nv50_disp_main_init(struct nvkm_object *object) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; - int ret, i; - u32 tmp; - - ret = nvkm_parent_init(&base->base); - if (ret) - return ret; - - /* The below segments of code copying values from one register to - * another appear to inform EVO of the display capabilities or - * something similar. NFI what the 0x614004 caps are for.. - */ - tmp = nvkm_rd32(device, 0x614004); - nvkm_wr32(device, 0x610184, tmp); - - /* ... CRTC caps */ - for (i = 0; i < disp->head.nr; i++) { - tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); - nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); - nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); - nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); - tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); - nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); - } - - /* ... DAC caps */ - for (i = 0; i < disp->dac.nr; i++) { - tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); - nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp); - } - - /* ... SOR caps */ - for (i = 0; i < disp->sor.nr; i++) { - tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); - nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp); - } - - /* ... PIOR caps */ - for (i = 0; i < disp->pior.nr; i++) { - tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800)); - nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp); - } - - /* steal display away from vbios, or something like that */ - if (nvkm_rd32(device, 0x610024) & 0x00000100) { - nvkm_wr32(device, 0x610024, 0x00000100); - nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) - break; - ) < 0) - return -EBUSY; - } - - /* point at display engine memory area (hash table, objects) */ - nvkm_wr32(device, 0x610010, (base->ramht->gpuobj->addr >> 8) | 9); - - /* enable supervisor interrupts, disable everything else */ - nvkm_wr32(device, 0x61002c, 0x00000370); - nvkm_wr32(device, 0x610028, 0x00000000); - return 0; -} - -static int -nv50_disp_main_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_base *base = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; - - /* disable all interrupts */ - nvkm_wr32(device, 0x610024, 0x00000000); - nvkm_wr32(device, 0x610020, 0x00000000); - - return nvkm_parent_fini(&base->base, suspend); -} - -struct nvkm_ofuncs -nv50_disp_main_ofuncs = { - .ctor = nv50_disp_main_ctor, - .dtor = nv50_disp_main_dtor, - .init = nv50_disp_main_init, - .fini = nv50_disp_main_fini, - .mthd = nv50_disp_main_mthd, - .ntfy = nvkm_disp_ntfy, -}; - -static struct nvkm_oclass -nv50_disp_main_oclass[] = { - { NV50_DISP, &nv50_disp_main_ofuncs }, - {} -}; - -static struct nvkm_oclass -nv50_disp_sclass[] = { - { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} -}; - -/******************************************************************************* - * Display context, tracks instmem allocation and prevents more than one - * client using the display hardware at any time. - ******************************************************************************/ static int nv50_disp_data_ctor(struct nvkm_object *parent, @@ -1323,10 +74,6 @@ nv50_disp_cclass = { }, }; -/******************************************************************************* - * Display engine implementation - ******************************************************************************/ - static void nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) { @@ -2027,7 +774,7 @@ nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(disp)->sclass = nv50_disp_main_oclass; + nv_engine(disp)->sclass = nv50_disp_root_oclass; nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); @@ -2062,5 +809,5 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { .mthd.base = &nv50_disp_base_mthd_chan, .mthd.ovly = &nv50_disp_ovly_mthd_chan, .mthd.prev = 0x000004, - .head.scanoutpos = nv50_disp_main_scanoutpos, + .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 3c50d28d33a00..e42e66e1c1f33 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -54,113 +54,37 @@ struct nv50_disp_impl { } head; }; -int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0); -int nv50_disp_main_mthd(struct nvkm_object *, u32, void *, u32); +int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0); +int nv50_disp_root_mthd(struct nvkm_object *, u32, void *, u32); -int gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0); +int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0); int nv50_dac_power(NV50_DISP_MTHD_V1); int nv50_dac_sense(NV50_DISP_MTHD_V1); int gt215_hda_eld(NV50_DISP_MTHD_V1); -int gf110_hda_eld(NV50_DISP_MTHD_V1); +int gf119_hda_eld(NV50_DISP_MTHD_V1); int g84_hdmi_ctrl(NV50_DISP_MTHD_V1); int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1); -int gf110_hdmi_ctrl(NV50_DISP_MTHD_V1); +int gf119_hdmi_ctrl(NV50_DISP_MTHD_V1); int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1); int nv50_sor_power(NV50_DISP_MTHD_V1); int nv50_pior_power(NV50_DISP_MTHD_V1); -#include - -struct nv50_disp_base { - struct nvkm_parent base; - struct nvkm_ramht *ramht; - u32 chan; -}; - -struct nv50_disp_chan_impl { - struct nvkm_ofuncs base; - int chid; - int (*attach)(struct nvkm_object *, struct nvkm_object *, u32); - void (*detach)(struct nvkm_object *, int); -}; - -#include - -struct nv50_disp_chan { - struct nvkm_namedb base; - int chid; -}; - -int nv50_disp_chan_ntfy(struct nvkm_object *, u32, struct nvkm_event **); -int nv50_disp_chan_map(struct nvkm_object *, u64 *, u32 *); -u32 nv50_disp_chan_rd32(struct nvkm_object *, u64); -void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32); -extern const struct nvkm_event_func nv50_disp_chan_uevent; -int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32, - struct nvkm_notify *); -void nv50_disp_chan_uevent_send(struct nv50_disp *, int); - -extern const struct nvkm_event_func gf110_disp_chan_uevent; - -#define nv50_disp_chan_init(a) \ - nvkm_namedb_init(&(a)->base) -#define nv50_disp_chan_fini(a,b) \ - nvkm_namedb_fini(&(a)->base, (b)) - -struct nv50_disp_dmac { - struct nv50_disp_chan base; - u32 push; -}; - -void nv50_disp_dmac_dtor(struct nvkm_object *); - -struct nv50_disp_pioc { - struct nv50_disp_chan base; -}; - -void nv50_disp_pioc_dtor(struct nvkm_object *); - -struct nv50_disp_mthd_list { - u32 mthd; - u32 addr; - struct { - u32 mthd; - u32 addr; - const char *name; - } data[]; -}; - -struct nv50_disp_mthd_chan { - const char *name; - u32 addr; - struct { - const char *name; - int nr; - const struct nv50_disp_mthd_list *mthd; - } data[]; -}; - extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs; int nv50_disp_core_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); -extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base; -extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor; -extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior; extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs; int nv50_disp_base_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); -extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image; extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs; int nv50_disp_ovly_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); -extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs; int nv50_disp_oimm_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, @@ -169,44 +93,26 @@ extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs; int nv50_disp_curs_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); -extern struct nvkm_ofuncs nv50_disp_main_ofuncs; -int nv50_disp_main_ctor(struct nvkm_object *, struct nvkm_object *, +extern struct nvkm_ofuncs nv50_disp_root_ofuncs; +int nv50_disp_root_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); -void nv50_disp_main_dtor(struct nvkm_object *); +void nv50_disp_root_dtor(struct nvkm_object *); extern struct nvkm_oclass nv50_disp_cclass; -void nv50_disp_mthd_chan(struct nv50_disp *, int debug, int head, - const struct nv50_disp_mthd_chan *); void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr(struct nvkm_subdev *); extern const struct nvkm_event_func nv50_disp_vblank_func; -extern const struct nv50_disp_mthd_chan g84_disp_core_mthd_chan; -extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac; -extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head; -extern const struct nv50_disp_mthd_chan g84_disp_base_mthd_chan; -extern const struct nv50_disp_mthd_chan g84_disp_ovly_mthd_chan; - -extern const struct nv50_disp_mthd_chan g94_disp_core_mthd_chan; - -extern struct nv50_disp_chan_impl gf110_disp_core_ofuncs; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_base; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_dac; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_sor; -extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_pior; -extern struct nv50_disp_chan_impl gf110_disp_base_ofuncs; -extern struct nv50_disp_chan_impl gf110_disp_ovly_ofuncs; -extern const struct nv50_disp_mthd_chan gf110_disp_base_mthd_chan; -extern struct nv50_disp_chan_impl gf110_disp_oimm_ofuncs; -extern struct nv50_disp_chan_impl gf110_disp_curs_ofuncs; -extern struct nvkm_ofuncs gf110_disp_main_ofuncs; -extern struct nvkm_oclass gf110_disp_cclass; -void gf110_disp_intr_supervisor(struct work_struct *); -void gf110_disp_intr(struct nvkm_subdev *); -extern const struct nvkm_event_func gf110_disp_vblank_func; - -extern const struct nv50_disp_mthd_chan gk104_disp_core_mthd_chan; -extern const struct nv50_disp_mthd_chan gk104_disp_ovly_mthd_chan; +extern struct nv50_disp_chan_impl gf119_disp_core_ofuncs; +extern struct nv50_disp_chan_impl gf119_disp_base_ofuncs; +extern struct nv50_disp_chan_impl gf119_disp_ovly_ofuncs; +extern struct nv50_disp_chan_impl gf119_disp_oimm_ofuncs; +extern struct nv50_disp_chan_impl gf119_disp_curs_ofuncs; +extern struct nvkm_ofuncs gf119_disp_root_ofuncs; +extern struct nvkm_oclass gf119_disp_cclass; +void gf119_disp_intr_supervisor(struct work_struct *); +void gf119_disp_intr(struct nvkm_subdev *); +extern const struct nvkm_event_func gf119_disp_vblank_func; extern struct nvkm_output_dp_impl nv50_pior_dp_impl; extern struct nvkm_oclass *nv50_disp_outp_sclass[]; @@ -216,9 +122,9 @@ u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); extern struct nvkm_oclass *g94_disp_outp_sclass[]; -extern struct nvkm_output_dp_impl gf110_sor_dp_impl; -int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); -extern struct nvkm_oclass *gf110_disp_outp_sclass[]; +extern struct nvkm_output_dp_impl gf119_sor_dp_impl; +int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); +extern struct nvkm_oclass *gf119_disp_outp_sclass[]; void gm204_sor_magic(struct nvkm_output *outp); extern struct nvkm_output_dp_impl gm204_sor_dp_impl; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c new file mode 100644 index 0000000000000..fa528051faa5a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +struct nv50_disp_chan_impl +gf119_disp_oimm_ofuncs = { + .base.ctor = nv50_disp_oimm_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = gf119_disp_pioc_init, + .base.fini = gf119_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 9, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c new file mode 100644 index 0000000000000..2128b01ae5726 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c @@ -0,0 +1,73 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include + +#include +#include + +int +nv50_disp_oimm_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_overlay_v0 v0; + } *args = data; + struct nv50_disp *disp = (void *)engine; + struct nv50_disp_pioc *pioc; + int ret; + + nvif_ioctl(parent, "create disp overlay size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp overlay vers %d head %d\n", + args->v0.version, args->v0.head); + if (args->v0.head > disp->head.nr) + return -EINVAL; + } else + return ret; + + ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, + sizeof(*pioc), (void **)&pioc); + *pobject = nv_object(pioc); + if (ret) + return ret; + + return 0; +} + +struct nv50_disp_chan_impl +nv50_disp_oimm_ofuncs = { + .base.ctor = nv50_disp_oimm_ctor, + .base.dtor = nv50_disp_pioc_dtor, + .base.init = nv50_disp_pioc_init, + .base.fini = nv50_disp_pioc_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index 1c1bd38d88b01..18ddf481c3467 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -58,7 +58,7 @@ int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int gf110_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, +int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); int gm204_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c new file mode 100644 index 0000000000000..149e7c4c75fa6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c @@ -0,0 +1,62 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +g84_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +g84_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &g84_disp_ovly_mthd_base }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c new file mode 100644 index 0000000000000..c44c927460bce --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c @@ -0,0 +1,101 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +gf119_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +gf119_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x001000, + .data = { + { "Global", 1, &gf119_disp_ovly_mthd_base }, + {} + } +}; + +struct nv50_disp_chan_impl +gf119_disp_ovly_ofuncs = { + .base.ctor = nv50_disp_ovly_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = gf119_disp_dmac_init, + .base.fini = gf119_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 5, + .attach = gf119_disp_dmac_object_attach, + .detach = gf119_disp_dmac_object_detach, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c new file mode 100644 index 0000000000000..7b83d70b244ae --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +gk104_disp_ovly_mthd_base = { + .mthd = 0x0000, + .data = { + { 0x0080, 0x665080 }, + { 0x0084, 0x665084 }, + { 0x0088, 0x665088 }, + { 0x008c, 0x66508c }, + { 0x0090, 0x665090 }, + { 0x0094, 0x665094 }, + { 0x00a0, 0x6650a0 }, + { 0x00a4, 0x6650a4 }, + { 0x00b0, 0x6650b0 }, + { 0x00b4, 0x6650b4 }, + { 0x00b8, 0x6650b8 }, + { 0x00c0, 0x6650c0 }, + { 0x00c4, 0x6650c4 }, + { 0x00e0, 0x6650e0 }, + { 0x00e4, 0x6650e4 }, + { 0x00e8, 0x6650e8 }, + { 0x0100, 0x665100 }, + { 0x0104, 0x665104 }, + { 0x0108, 0x665108 }, + { 0x010c, 0x66510c }, + { 0x0110, 0x665110 }, + { 0x0118, 0x665118 }, + { 0x011c, 0x66511c }, + { 0x0120, 0x665120 }, + { 0x0124, 0x665124 }, + { 0x0130, 0x665130 }, + { 0x0134, 0x665134 }, + { 0x0138, 0x665138 }, + { 0x013c, 0x66513c }, + { 0x0140, 0x665140 }, + { 0x0144, 0x665144 }, + { 0x0148, 0x665148 }, + { 0x014c, 0x66514c }, + { 0x0150, 0x665150 }, + { 0x0154, 0x665154 }, + { 0x0158, 0x665158 }, + { 0x015c, 0x66515c }, + { 0x0160, 0x665160 }, + { 0x0164, 0x665164 }, + { 0x0168, 0x665168 }, + { 0x016c, 0x66516c }, + { 0x0400, 0x665400 }, + { 0x0404, 0x665404 }, + { 0x0408, 0x665408 }, + { 0x040c, 0x66540c }, + { 0x0410, 0x665410 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +gk104_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x001000, + .data = { + { "Global", 1, &gk104_disp_ovly_mthd_base }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c new file mode 100644 index 0000000000000..8299b5e023525 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c @@ -0,0 +1,65 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +static const struct nv50_disp_mthd_list +gt200_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x6109a0 }, + { 0x0088, 0x6109c0 }, + { 0x008c, 0x6109c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00b0, 0x610c98 }, + { 0x00b4, 0x610ca4 }, + { 0x00b8, 0x610cac }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +gt200_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, >200_disp_ovly_mthd_base }, + {} + } +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c new file mode 100644 index 0000000000000..840e2b0a90a4e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c @@ -0,0 +1,115 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" + +#include + +#include +#include + +const struct nv50_disp_mthd_list +nv50_disp_ovly_mthd_base = { + .mthd = 0x0000, + .addr = 0x000000, + .data = { + { 0x0080, 0x000000 }, + { 0x0084, 0x0009a0 }, + { 0x0088, 0x0009c0 }, + { 0x008c, 0x0009c8 }, + { 0x0090, 0x6109b4 }, + { 0x0094, 0x610970 }, + { 0x00a0, 0x610998 }, + { 0x00a4, 0x610964 }, + { 0x00c0, 0x610958 }, + { 0x00e0, 0x6109a8 }, + { 0x00e4, 0x6109d0 }, + { 0x00e8, 0x6109d8 }, + { 0x0100, 0x61094c }, + { 0x0104, 0x610984 }, + { 0x0108, 0x61098c }, + { 0x0800, 0x6109f8 }, + { 0x0808, 0x610a08 }, + { 0x080c, 0x610a10 }, + { 0x0810, 0x610a00 }, + {} + } +}; + +const struct nv50_disp_mthd_chan +nv50_disp_ovly_mthd_chan = { + .name = "Overlay", + .addr = 0x000540, + .data = { + { "Global", 1, &nv50_disp_ovly_mthd_base }, + {} + } +}; + +int +nv50_disp_ovly_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_overlay_channel_dma_v0 v0; + } *args = data; + struct nv50_disp *disp = (void *)engine; + struct nv50_disp_dmac *dmac; + int ret; + + nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp overlay channel dma vers %d " + "pushbuf %016llx head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > disp->head.nr) + return -EINVAL; + } else + return ret; + + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, + args->v0.head, sizeof(*dmac), + (void **)&dmac); + *pobject = nv_object(dmac); + if (ret) + return ret; + + return 0; +} + +struct nv50_disp_chan_impl +nv50_disp_ovly_ofuncs = { + .base.ctor = nv50_disp_ovly_ctor, + .base.dtor = nv50_disp_dmac_dtor, + .base.init = nv50_disp_dmac_init, + .base.fini = nv50_disp_dmac_fini, + .base.ntfy = nv50_disp_chan_ntfy, + .base.map = nv50_disp_chan_map, + .base.rd32 = nv50_disp_chan_rd32, + .base.wr32 = nv50_disp_chan_wr32, + .chid = 3, + .attach = nv50_disp_dmac_object_attach, + .detach = nv50_disp_dmac_object_detach, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c new file mode 100644 index 0000000000000..08aeb8e4e6dc3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c @@ -0,0 +1,85 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include + +int +gf119_disp_pioc_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = pioc->base.chid; + + nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610490 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d fini: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + if (suspend) + return -EBUSY; + } + + /* disable error reporting and completion notification */ + nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); + + return nv50_disp_chan_fini(&pioc->base, suspend); +} + +int +gf119_disp_pioc_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = pioc->base.chid; + int ret; + + ret = nv50_disp_chan_init(&pioc->base); + if (ret) + return ret; + + /* enable error reporting */ + nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); + + /* activate channel */ + nvkm_wr32(device, 0x610490 + (chid * 0x10), 0x00000001); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x610490 + (chid * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { + nvkm_error(subdev, "ch %d init: %08x\n", chid, + nvkm_rd32(device, 0x610490 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c new file mode 100644 index 0000000000000..13e4711ec0c79 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c @@ -0,0 +1,104 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include + +int +nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = pioc->base.chid; + + nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d timeout: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + if (suspend) + return -EBUSY; + } + + return nv50_disp_chan_fini(&pioc->base, suspend); +} + +int +nv50_disp_pioc_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_pioc *pioc = (void *)object; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int chid = pioc->base.chid; + int ret; + + ret = nv50_disp_chan_init(&pioc->base); + if (ret) + return ret; + + nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x610200 + (chid * 0x10)) & 0x00030000)) + break; + ) < 0) { + nvkm_error(subdev, "ch %d timeout0: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00000001); + if (nvkm_msec(device, 2000, + u32 tmp = nvkm_rd32(device, 0x610200 + (chid * 0x10)); + if ((tmp & 0x00030000) == 0x00010000) + break; + ) < 0) { + nvkm_error(subdev, "ch %d timeout1: %08x\n", chid, + nvkm_rd32(device, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +void +nv50_disp_pioc_dtor(struct nvkm_object *object) +{ + struct nv50_disp_pioc *pioc = (void *)object; + nv50_disp_chan_destroy(&pioc->base); +} + +int +nv50_disp_pioc_create_(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, int head, + int length, void **pobject) +{ + return nv50_disp_chan_create_(parent, engine, oclass, head, + length, pobject); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index f1df2972a8d11..603526ceaa281 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -56,4 +56,6 @@ int nvkm_disp_vblank_ctor(struct nvkm_object *, void *data, u32 size, struct nvkm_notify *); void nvkm_disp_vblank(struct nvkm_disp *, int head); int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); + +extern struct nvkm_oclass nv04_disp_sclass[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c new file mode 100644 index 0000000000000..128b2d797e6f6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +g84_disp_sclass[] = { + { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, + { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, + { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +g84_disp_root_oclass[] = { + { G82_DISP, &nv50_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c new file mode 100644 index 0000000000000..9b1ef885a2627 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +g94_disp_sclass[] = { + { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, + { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, + { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +g94_disp_root_oclass[] = { + { GT206_DISP, &nv50_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c new file mode 100644 index 0000000000000..ae55cb21eb339 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -0,0 +1,176 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include +#include +#include + +#include +#include + +int +gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 total = nvkm_rd32(device, 0x640414 + (head * 0x300)); + const u32 blanke = nvkm_rd32(device, 0x64041c + (head * 0x300)); + const u32 blanks = nvkm_rd32(device, 0x640420 + (head * 0x300)); + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + int ret; + + nvif_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); + args->v0.vblanke = (blanke & 0xffff0000) >> 16; + args->v0.hblanke = (blanke & 0x0000ffff); + args->v0.vblanks = (blanks & 0xffff0000) >> 16; + args->v0.hblanks = (blanks & 0x0000ffff); + args->v0.vtotal = ( total & 0xffff0000) >> 16; + args->v0.htotal = ( total & 0x0000ffff); + args->v0.time[0] = ktime_to_ns(ktime_get()); + args->v0.vline = /* vline read locks hline */ + nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = + nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; + } else + return ret; + + return 0; +} + +static int +gf119_disp_root_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_root *root = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; + int ret, i; + u32 tmp; + + ret = nvkm_parent_init(&root->base); + if (ret) + return ret; + + /* The below segments of code copying values from one register to + * another appear to inform EVO of the display capabilities or + * something similar. + */ + + /* ... CRTC caps */ + for (i = 0; i < disp->head.nr; i++) { + tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); + nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); + nvkm_wr32(device, 0x6101b8 + (i * 0x800), tmp); + tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); + nvkm_wr32(device, 0x6101bc + (i * 0x800), tmp); + } + + /* ... DAC caps */ + for (i = 0; i < disp->dac.nr; i++) { + tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); + nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp); + } + + /* ... SOR caps */ + for (i = 0; i < disp->sor.nr; i++) { + tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); + nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp); + } + + /* steal display away from vbios, or something like that */ + if (nvkm_rd32(device, 0x6100ac) & 0x00000100) { + nvkm_wr32(device, 0x6100ac, 0x00000100); + nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) + break; + ) < 0) + return -EBUSY; + } + + /* point at display engine memory area (hash table, objects) */ + nvkm_wr32(device, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); + + /* enable supervisor interrupts, disable everything else */ + nvkm_wr32(device, 0x610090, 0x00000000); + nvkm_wr32(device, 0x6100a0, 0x00000000); + nvkm_wr32(device, 0x6100b0, 0x00000307); + + /* disable underflow reporting, preventing an intermittent issue + * on some gk104 boards where the production vbios left this + * setting enabled by default. + * + * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt + */ + for (i = 0; i < disp->head.nr; i++) + nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); + + return 0; +} + +static int +gf119_disp_root_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_root *root = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; + + /* disable all interrupts */ + nvkm_wr32(device, 0x6100b0, 0x00000000); + + return nvkm_parent_fini(&root->base, suspend); +} + +struct nvkm_ofuncs +gf119_disp_root_ofuncs = { + .ctor = nv50_disp_root_ctor, + .dtor = nv50_disp_root_dtor, + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .mthd = nv50_disp_root_mthd, + .ntfy = nvkm_disp_ntfy, +}; + +struct nvkm_oclass +gf119_disp_root_oclass[] = { + { GF110_DISP, &gf119_disp_root_ofuncs }, + {} +}; + +struct nvkm_oclass +gf119_disp_sclass[] = { + { GF110_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, + { GF110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, + { GF110_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, + { GF110_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, + { GF110_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c new file mode 100644 index 0000000000000..f89b33496b1e4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +gk104_disp_sclass[] = { + { GK104_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, + { GK104_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +gk104_disp_root_oclass[] = { + { GK104_DISP, &gf119_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c new file mode 100644 index 0000000000000..ef2f73a6539d9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +gk110_disp_sclass[] = { + { GK110_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, + { GK110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +gk110_disp_root_oclass[] = { + { GK110_DISP, &gf119_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c new file mode 100644 index 0000000000000..ba69ee4e0a494 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +gm107_disp_sclass[] = { + { GM107_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, + { GK110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +gm107_disp_root_oclass[] = { + { GM107_DISP, &gf119_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c new file mode 100644 index 0000000000000..255308f6ec255 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +gm204_disp_sclass[] = { + { GM204_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, + { GK110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, + { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, + { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, + { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +gm204_disp_root_oclass[] = { + { GM204_DISP, &gf119_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c new file mode 100644 index 0000000000000..b1963e531ae12 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +gt200_disp_sclass[] = { + { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, + { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, + { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +gt200_disp_root_oclass[] = { + { GT200_DISP, &nv50_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c new file mode 100644 index 0000000000000..83b214abb13af --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include + +struct nvkm_oclass +gt215_disp_sclass[] = { + { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, + { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, + { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, + {} +}; + +struct nvkm_oclass +gt215_disp_root_oclass[] = { + { GT214_DISP, &nv50_disp_root_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c new file mode 100644 index 0000000000000..603ebb6fd541a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c @@ -0,0 +1,119 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +#include + +#include +#include + +static int +nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, + void *data, u32 size, int head) +{ + struct nvkm_device *device = disp->engine.subdev.device; + const u32 hoff = head * 0x2000; + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + u32 line; + int ret; + + nvif_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); + args->v0.vblanks = nvkm_rd32(device, 0x680800 + hoff) & 0xffff; + args->v0.vtotal = nvkm_rd32(device, 0x680804 + hoff) & 0xffff; + args->v0.vblanke = args->v0.vtotal - 1; + + args->v0.hblanks = nvkm_rd32(device, 0x680820 + hoff) & 0xffff; + args->v0.htotal = nvkm_rd32(device, 0x680824 + hoff) & 0xffff; + args->v0.hblanke = args->v0.htotal - 1; + + /* + * If output is vga instead of digital then vtotal/htotal is + * invalid so we have to give up and trigger the timestamping + * fallback in the drm core. + */ + if (!args->v0.vtotal || !args->v0.htotal) + return -ENOTSUPP; + + args->v0.time[0] = ktime_to_ns(ktime_get()); + line = nvkm_rd32(device, 0x600868 + hoff); + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = (line & 0xffff0000) >> 16; + args->v0.vline = (line & 0x0000ffff); + } else + return ret; + + return 0; +} + +static int +nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + union { + struct nv04_disp_mthd_v0 v0; + } *args = data; + struct nvkm_disp *disp = (void *)object->engine; + int head, ret; + + nvif_ioctl(object, "disp mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); + mthd = args->v0.method; + head = args->v0.head; + } else + return ret; + + if (head < 0 || head >= 2) + return -ENXIO; + + switch (mthd) { + case NV04_DISP_SCANOUTPOS: + return nv04_disp_scanoutpos(object, disp, data, size, head); + default: + break; + } + + return -EINVAL; +} + +static struct nvkm_ofuncs +nv04_disp_ofuncs = { + .ctor = _nvkm_object_ctor, + .dtor = nvkm_object_destroy, + .init = _nvkm_object_init, + .fini = _nvkm_object_fini, + .mthd = nv04_disp_mthd, + .ntfy = nvkm_disp_ntfy, +}; + +struct nvkm_oclass +nv04_disp_sclass[] = { + { NV04_DISP, &nv04_disp_ofuncs }, + {}, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c new file mode 100644 index 0000000000000..83549702bbc13 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -0,0 +1,328 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "rootnv50.h" +#include "dmacnv50.h" + +#include +#include +#include + +#include +#include + +int +nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + const u32 blanke = nvkm_rd32(device, 0x610aec + (head * 0x540)); + const u32 blanks = nvkm_rd32(device, 0x610af4 + (head * 0x540)); + const u32 total = nvkm_rd32(device, 0x610afc + (head * 0x540)); + union { + struct nv04_disp_scanoutpos_v0 v0; + } *args = data; + int ret; + + nvif_ioctl(object, "disp scanoutpos size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp scanoutpos vers %d\n", + args->v0.version); + args->v0.vblanke = (blanke & 0xffff0000) >> 16; + args->v0.hblanke = (blanke & 0x0000ffff); + args->v0.vblanks = (blanks & 0xffff0000) >> 16; + args->v0.hblanks = (blanks & 0x0000ffff); + args->v0.vtotal = ( total & 0xffff0000) >> 16; + args->v0.htotal = ( total & 0x0000ffff); + args->v0.time[0] = ktime_to_ns(ktime_get()); + args->v0.vline = /* vline read locks hline */ + nvkm_rd32(device, 0x616340 + (head * 0x800)) & 0xffff; + args->v0.time[1] = ktime_to_ns(ktime_get()); + args->v0.hline = + nvkm_rd32(device, 0x616344 + (head * 0x800)) & 0xffff; + } else + return ret; + + return 0; +} + +int +nv50_disp_root_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); + union { + struct nv50_disp_mthd_v0 v0; + struct nv50_disp_mthd_v1 v1; + } *args = data; + struct nv50_disp *disp = (void *)object->engine; + struct nvkm_output *outp = NULL; + struct nvkm_output *temp; + u16 type, mask = 0; + int head, ret; + + if (mthd != NV50_DISP_MTHD) + return -EINVAL; + + nvif_ioctl(object, "disp mthd size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, true)) { + nvif_ioctl(object, "disp mthd vers %d mthd %02x head %d\n", + args->v0.version, args->v0.method, args->v0.head); + mthd = args->v0.method; + head = args->v0.head; + } else + if (nvif_unpack(args->v1, 1, 1, true)) { + nvif_ioctl(object, "disp mthd vers %d mthd %02x " + "type %04x mask %04x\n", + args->v1.version, args->v1.method, + args->v1.hasht, args->v1.hashm); + mthd = args->v1.method; + type = args->v1.hasht; + mask = args->v1.hashm; + head = ffs((mask >> 8) & 0x0f) - 1; + } else + return ret; + + if (head < 0 || head >= disp->head.nr) + return -ENXIO; + + if (mask) { + list_for_each_entry(temp, &disp->base.outp, head) { + if ((temp->info.hasht == type) && + (temp->info.hashm & mask) == mask) { + outp = temp; + break; + } + } + if (outp == NULL) + return -ENXIO; + } + + switch (mthd) { + case NV50_DISP_SCANOUTPOS: + return impl->head.scanoutpos(object, disp, data, size, head); + default: + break; + } + + switch (mthd * !!outp) { + case NV50_DISP_MTHD_V1_DAC_PWR: + return disp->dac.power(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_DAC_LOAD: + return disp->dac.sense(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_PWR: + return disp->sor.power(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_HDA_ELD: + if (!disp->sor.hda_eld) + return -ENODEV; + return disp->sor.hda_eld(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: + if (!disp->sor.hdmi) + return -ENODEV; + return disp->sor.hdmi(object, disp, data, size, head, outp); + case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { + union { + struct nv50_disp_sor_lvds_script_v0 v0; + } *args = data; + nvif_ioctl(object, "disp sor lvds script size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp sor lvds script " + "vers %d name %04x\n", + args->v0.version, args->v0.script); + disp->sor.lvdsconf = args->v0.script; + return 0; + } else + return ret; + } + break; + case NV50_DISP_MTHD_V1_SOR_DP_PWR: { + struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); + union { + struct nv50_disp_sor_dp_pwr_v0 v0; + } *args = data; + nvif_ioctl(object, "disp sor dp pwr size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(object, "disp sor dp pwr vers %d state %d\n", + args->v0.version, args->v0.state); + if (args->v0.state == 0) { + nvkm_notify_put(&outpdp->irq); + outpdp->func->lnk_pwr(outpdp, 0); + atomic_set(&outpdp->lt.done, 0); + return 0; + } else + if (args->v0.state != 0) { + nvkm_output_dp_train(&outpdp->base, 0, true); + return 0; + } + } else + return ret; + } + break; + case NV50_DISP_MTHD_V1_PIOR_PWR: + if (!disp->pior.power) + return -ENODEV; + return disp->pior.power(object, disp, data, size, head, outp); + default: + break; + } + + return -EINVAL; +} + +int +nv50_disp_root_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nv50_disp *disp = (void *)engine; + struct nv50_disp_root *root; + struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_gpuobj *instmem = (void *)parent; + int ret; + + ret = nvkm_parent_create(parent, engine, oclass, 0, + disp->sclass, 0, &root); + *pobject = nv_object(root); + if (ret) + return ret; + + + return nvkm_ramht_new(device, 0x1000, 0, instmem, &root->ramht); +} + +void +nv50_disp_root_dtor(struct nvkm_object *object) +{ + struct nv50_disp_root *root = (void *)object; + nvkm_ramht_del(&root->ramht); + nvkm_parent_destroy(&root->base); +} + +static int +nv50_disp_root_init(struct nvkm_object *object) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_root *root = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; + int ret, i; + u32 tmp; + + ret = nvkm_parent_init(&root->base); + if (ret) + return ret; + + /* The below segments of code copying values from one register to + * another appear to inform EVO of the display capabilities or + * something similar. NFI what the 0x614004 caps are for.. + */ + tmp = nvkm_rd32(device, 0x614004); + nvkm_wr32(device, 0x610184, tmp); + + /* ... CRTC caps */ + for (i = 0; i < disp->head.nr; i++) { + tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); + nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); + nvkm_wr32(device, 0x610194 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); + nvkm_wr32(device, 0x610198 + (i * 0x10), tmp); + tmp = nvkm_rd32(device, 0x61610c + (i * 0x800)); + nvkm_wr32(device, 0x61019c + (i * 0x10), tmp); + } + + /* ... DAC caps */ + for (i = 0; i < disp->dac.nr; i++) { + tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); + nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp); + } + + /* ... SOR caps */ + for (i = 0; i < disp->sor.nr; i++) { + tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); + nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp); + } + + /* ... PIOR caps */ + for (i = 0; i < disp->pior.nr; i++) { + tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800)); + nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp); + } + + /* steal display away from vbios, or something like that */ + if (nvkm_rd32(device, 0x610024) & 0x00000100) { + nvkm_wr32(device, 0x610024, 0x00000100); + nvkm_mask(device, 0x6194e8, 0x00000001, 0x00000000); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x6194e8) & 0x00000002)) + break; + ) < 0) + return -EBUSY; + } + + /* point at display engine memory area (hash table, objects) */ + nvkm_wr32(device, 0x610010, (root->ramht->gpuobj->addr >> 8) | 9); + + /* enable supervisor interrupts, disable everything else */ + nvkm_wr32(device, 0x61002c, 0x00000370); + nvkm_wr32(device, 0x610028, 0x00000000); + return 0; +} + +static int +nv50_disp_root_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_root *root = (void *)object; + struct nvkm_device *device = disp->base.engine.subdev.device; + + /* disable all interrupts */ + nvkm_wr32(device, 0x610024, 0x00000000); + nvkm_wr32(device, 0x610020, 0x00000000); + + return nvkm_parent_fini(&root->base, suspend); +} + +struct nvkm_ofuncs +nv50_disp_root_ofuncs = { + .ctor = nv50_disp_root_ctor, + .dtor = nv50_disp_root_dtor, + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .mthd = nv50_disp_root_mthd, + .ntfy = nvkm_disp_ntfy, +}; + +struct nvkm_oclass +nv50_disp_root_oclass[] = { + { NV50_DISP, &nv50_disp_root_ofuncs }, + {} +}; + +struct nvkm_oclass +nv50_disp_sclass[] = { + { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, + { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, + { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, + { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, + { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h new file mode 100644 index 0000000000000..9ae4bf9270651 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h @@ -0,0 +1,36 @@ +#ifndef __NV50_DISP_ROOT_H__ +#define __NV50_DISP_ROOT_H__ +#include "nv50.h" +#include "channv50.h" +#include "dmacnv50.h" +#include + +#include + +struct nv50_disp_root { + struct nvkm_parent base; + struct nvkm_ramht *ramht; + u32 chan; +}; + +extern struct nvkm_oclass nv50_disp_root_oclass[]; +extern struct nvkm_oclass nv50_disp_sclass[]; +extern struct nvkm_oclass g84_disp_root_oclass[]; +extern struct nvkm_oclass g84_disp_sclass[]; +extern struct nvkm_oclass g94_disp_root_oclass[]; +extern struct nvkm_oclass g94_disp_sclass[]; +extern struct nvkm_oclass gt200_disp_root_oclass[]; +extern struct nvkm_oclass gt200_disp_sclass[]; +extern struct nvkm_oclass gt215_disp_root_oclass[]; +extern struct nvkm_oclass gt215_disp_sclass[]; +extern struct nvkm_oclass gf119_disp_root_oclass[]; +extern struct nvkm_oclass gf119_disp_sclass[]; +extern struct nvkm_oclass gk104_disp_root_oclass[]; +extern struct nvkm_oclass gk104_disp_sclass[]; +extern struct nvkm_oclass gk110_disp_root_oclass[]; +extern struct nvkm_oclass gk110_disp_sclass[]; +extern struct nvkm_oclass gm107_disp_root_oclass[]; +extern struct nvkm_oclass gm107_disp_sclass[]; +extern struct nvkm_oclass gm204_disp_root_oclass[]; +extern struct nvkm_oclass gm204_disp_sclass[]; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c similarity index 81% rename from drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c rename to drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c index 7e5ef507ab042..b4b41b1356434 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf119.c @@ -25,32 +25,32 @@ #include "outpdp.h" static inline u32 -gf110_sor_soff(struct nvkm_output_dp *outp) +gf119_sor_soff(struct nvkm_output_dp *outp) { return (ffs(outp->base.info.or) - 1) * 0x800; } static inline u32 -gf110_sor_loff(struct nvkm_output_dp *outp) +gf119_sor_loff(struct nvkm_output_dp *outp) { - return gf110_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; + return gf119_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80; } static int -gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) +gf119_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern) { struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 loff = gf110_sor_loff(outp); + const u32 loff = gf119_sor_loff(outp); nvkm_mask(device, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern); return 0; } int -gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) +gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) { struct nvkm_device *device = outp->base.disp->engine.subdev.device; - const u32 soff = gf110_sor_soff(outp); - const u32 loff = gf110_sor_loff(outp); + const u32 soff = gf119_sor_soff(outp); + const u32 loff = gf119_sor_loff(outp); u32 dpctrl = 0x00000000; u32 clksor = 0x00000000; @@ -65,13 +65,13 @@ gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef) } static int -gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, +gf119_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc) { struct nvkm_device *device = outp->base.disp->engine.subdev.device; struct nvkm_bios *bios = device->bios; const u32 shift = g94_sor_dp_lane_map(device, ln); - const u32 loff = gf110_sor_loff(outp); + const u32 loff = gf119_sor_loff(outp); u32 addr, data[4]; u8 ver, hdr, cnt, len; struct nvbios_dpout info; @@ -102,16 +102,16 @@ gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp, } static const struct nvkm_output_dp_func -gf110_sor_dp_func = { - .pattern = gf110_sor_dp_pattern, +gf119_sor_dp_func = { + .pattern = gf119_sor_dp_pattern, .lnk_pwr = g94_sor_dp_lnk_pwr, - .lnk_ctl = gf110_sor_dp_lnk_ctl, - .drv_ctl = gf110_sor_dp_drv_ctl, + .lnk_ctl = gf119_sor_dp_lnk_ctl, + .drv_ctl = gf119_sor_dp_drv_ctl, }; int -gf110_sor_dp_new(struct nvkm_disp *disp, int index, +gf119_sor_dp_new(struct nvkm_disp *disp, int index, struct dcb_output *dcbE, struct nvkm_output **poutp) { - return nvkm_output_dp_new_(&gf110_sor_dp_func, disp, index, dcbE, poutp); + return nvkm_output_dp_new_(&gf119_sor_dp_func, disp, index, dcbE, poutp); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c index 5a35bf4f1e1d8..029e5f16c2a80 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c @@ -131,7 +131,7 @@ static const struct nvkm_output_dp_func gm204_sor_dp_func = { .pattern = gm204_sor_dp_pattern, .lnk_pwr = gm204_sor_dp_lnk_pwr, - .lnk_ctl = gf110_sor_dp_lnk_ctl, + .lnk_ctl = gf119_sor_dp_lnk_ctl, .drv_ctl = gm204_sor_dp_drv_ctl, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index c3af125c7132e..4e8b632ef5b16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -73,12 +73,14 @@ static bool nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) { struct nv50_sw_chan *chan = nv50_sw_chan(base); + struct nvkm_engine *engine = chan->base.base.gpuobj.object.engine; + struct nvkm_device *device = engine->subdev.device; switch (mthd) { case 0x018c: chan->vblank.ctxdma = data; return true; case 0x0400: chan->vblank.offset = data; return true; case 0x0404: chan->vblank.value = data; return true; case 0x0408: - if (data < nvkm_disp(chan)->vblank.index_nr) { + if (data < device->disp->vblank.index_nr) { nvkm_notify_get(&chan->vblank.notify[data]); return true; } @@ -111,7 +113,7 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_disp *disp = nvkm_disp(parent); + struct nvkm_disp *disp = parent->engine->subdev.device->disp; struct nv50_sw_cclass *pclass = (void *)oclass; struct nv50_sw_chan *chan; int ret, i; -- GitLab From 0ce41e3c66ca8958dec427f1c46f64efdda90f30 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5517/7006] drm/nouveau/disp: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/oproxy.h | 22 ++ .../drm/nouveau/include/nvkm/engine/disp.h | 8 + drivers/gpu/drm/nouveau/nvkm/core/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/core/oproxy.c | 198 +++++++++++++++ .../gpu/drm/nouveau/nvkm/engine/disp/Kbuild | 16 ++ .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 68 +++++ .../drm/nouveau/nvkm/engine/disp/baseg84.c | 19 +- .../drm/nouveau/nvkm/engine/disp/basegf119.c | 28 +-- .../drm/nouveau/nvkm/engine/disp/basegk104.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/basegk110.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/basegt200.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/basegt215.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/basenv50.c | 90 ++++--- .../drm/nouveau/nvkm/engine/disp/channv50.c | 184 +++++++++----- .../drm/nouveau/nvkm/engine/disp/channv50.h | 128 ++++++---- .../drm/nouveau/nvkm/engine/disp/coreg84.c | 19 +- .../drm/nouveau/nvkm/engine/disp/coreg94.c | 19 +- .../drm/nouveau/nvkm/engine/disp/coregf119.c | 60 +++-- .../drm/nouveau/nvkm/engine/disp/coregk104.c | 19 +- .../drm/nouveau/nvkm/engine/disp/coregk110.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/coregm107.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/coregm204.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/coregt200.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/coregt215.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/corenv50.c | 110 ++++---- .../drm/nouveau/nvkm/engine/disp/cursg84.c | 37 +++ .../drm/nouveau/nvkm/engine/disp/cursgf119.c | 20 +- .../drm/nouveau/nvkm/engine/disp/cursgk104.c | 37 +++ .../drm/nouveau/nvkm/engine/disp/cursgt215.c | 37 +++ .../drm/nouveau/nvkm/engine/disp/cursnv50.c | 43 ++-- .../drm/nouveau/nvkm/engine/disp/dmacgf119.c | 55 ++-- .../drm/nouveau/nvkm/engine/disp/dmacnv50.c | 237 ++++++++++++------ .../drm/nouveau/nvkm/engine/disp/dmacnv50.h | 95 +++++-- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 43 +--- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gm204.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 14 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 84 +------ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 59 +---- .../drm/nouveau/nvkm/engine/disp/oimmg84.c | 37 +++ .../drm/nouveau/nvkm/engine/disp/oimmgf119.c | 20 +- .../drm/nouveau/nvkm/engine/disp/oimmgk104.c | 37 +++ .../drm/nouveau/nvkm/engine/disp/oimmgt215.c | 37 +++ .../drm/nouveau/nvkm/engine/disp/oimmnv50.c | 43 ++-- .../gpu/drm/nouveau/nvkm/engine/disp/outp.h | 18 +- .../gpu/drm/nouveau/nvkm/engine/disp/outpdp.h | 14 +- .../drm/nouveau/nvkm/engine/disp/ovlyg84.c | 19 +- .../drm/nouveau/nvkm/engine/disp/ovlygf119.c | 28 +-- .../drm/nouveau/nvkm/engine/disp/ovlygk104.c | 19 +- .../drm/nouveau/nvkm/engine/disp/ovlygt200.c | 19 +- .../drm/nouveau/nvkm/engine/disp/ovlygt215.c | 38 +++ .../drm/nouveau/nvkm/engine/disp/ovlynv50.c | 92 ++++--- .../drm/nouveau/nvkm/engine/disp/piocgf119.c | 34 ++- .../drm/nouveau/nvkm/engine/disp/piocnv50.c | 49 ++-- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 8 +- .../drm/nouveau/nvkm/engine/disp/rootg84.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootg94.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootgf119.c | 79 +++--- .../drm/nouveau/nvkm/engine/disp/rootgk104.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootgk110.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootgm107.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootgm204.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootgt200.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootgt215.c | 39 ++- .../drm/nouveau/nvkm/engine/disp/rootnv04.c | 48 ++-- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 193 +++++++++----- .../drm/nouveau/nvkm/engine/disp/rootnv50.h | 57 +++-- 73 files changed, 2346 insertions(+), 1053 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/oproxy.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/core/oproxy.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/oproxy.h b/drivers/gpu/drm/nouveau/include/nvkm/core/oproxy.h new file mode 100644 index 0000000000000..bd52236cc2f48 --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/oproxy.h @@ -0,0 +1,22 @@ +#ifndef __NVKM_OPROXY_H__ +#define __NVKM_OPROXY_H__ +#define nvkm_oproxy(p) container_of((p), struct nvkm_oproxy, base) +#include + +struct nvkm_oproxy { + const struct nvkm_oproxy_func *func; + struct nvkm_object base; + struct nvkm_object *object; +}; + +struct nvkm_oproxy_func { + void (*dtor[2])(struct nvkm_oproxy *); + int (*init[2])(struct nvkm_oproxy *); + int (*fini[2])(struct nvkm_oproxy *, bool suspend); +}; + +void nvkm_oproxy_ctor(const struct nvkm_oproxy_func *, + const struct nvkm_oclass *, struct nvkm_oproxy *); +int nvkm_oproxy_new_(const struct nvkm_oproxy_func *, + const struct nvkm_oclass *, struct nvkm_oproxy **); +#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 2df776525b839..026a18ab4d904 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -1,10 +1,14 @@ #ifndef __NVKM_DISP_H__ #define __NVKM_DISP_H__ +#define nvkm_disp(p) container_of((p), struct nvkm_disp, engine) #include #include struct nvkm_disp { struct nvkm_engine engine; + const struct nvkm_disp_func *func; + + struct nvkm_oproxy *client; struct list_head outp; struct list_head conn; @@ -13,6 +17,10 @@ struct nvkm_disp { struct nvkm_event vblank; }; +struct nvkm_disp_func { + const struct nvkm_disp_oclass *root; +}; + extern struct nvkm_oclass *nv04_disp_oclass; extern struct nvkm_oclass *nv50_disp_oclass; extern struct nvkm_oclass *g84_disp_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index 98cf39f732c14..e56c8eb9b054f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -11,6 +11,7 @@ nvkm-y += nvkm/core/mm.o nvkm-y += nvkm/core/namedb.o nvkm-y += nvkm/core/notify.o nvkm-y += nvkm/core/object.o +nvkm-y += nvkm/core/oproxy.o nvkm-y += nvkm/core/option.o nvkm-y += nvkm/core/parent.o nvkm-y += nvkm/core/ramht.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c new file mode 100644 index 0000000000000..b2b743587168c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c @@ -0,0 +1,198 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include + +static int +nvkm_oproxy_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +{ + return nvkm_object_mthd(nvkm_oproxy(object)->object, mthd, data, size); +} + +static int +nvkm_oproxy_ntfy(struct nvkm_object *object, u32 mthd, + struct nvkm_event **pevent) +{ + return nvkm_object_ntfy(nvkm_oproxy(object)->object, mthd, pevent); +} + +static int +nvkm_oproxy_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + return nvkm_object_map(nvkm_oproxy(object)->object, addr, size); +} + +static int +nvkm_oproxy_rd08(struct nvkm_object *object, u64 addr, u8 *data) +{ + return nvkm_object_rd08(nvkm_oproxy(object)->object, addr, data); +} + +static int +nvkm_oproxy_rd16(struct nvkm_object *object, u64 addr, u16 *data) +{ + return nvkm_object_rd16(nvkm_oproxy(object)->object, addr, data); +} + +static int +nvkm_oproxy_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + return nvkm_object_rd32(nvkm_oproxy(object)->object, addr, data); +} + +static int +nvkm_oproxy_wr08(struct nvkm_object *object, u64 addr, u8 data) +{ + return nvkm_object_wr08(nvkm_oproxy(object)->object, addr, data); +} + +static int +nvkm_oproxy_wr16(struct nvkm_object *object, u64 addr, u16 data) +{ + return nvkm_object_wr16(nvkm_oproxy(object)->object, addr, data); +} + +static int +nvkm_oproxy_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + return nvkm_object_wr32(nvkm_oproxy(object)->object, addr, data); +} + +static int +nvkm_oproxy_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + return nvkm_object_bind(nvkm_oproxy(object)->object, + parent, align, pgpuobj); +} + +static int +nvkm_oproxy_sclass(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + struct nvkm_oproxy *oproxy = nvkm_oproxy(object); + oclass->parent = oproxy->object; + if (oproxy->object->oclass) + return -ENOSYS; + if (!oproxy->object->func->sclass) + return -ENODEV; + return oproxy->object->func->sclass(oproxy->object, index, oclass); +} + +static int +nvkm_oproxy_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_oproxy *oproxy = nvkm_oproxy(object); + int ret; + + if (oproxy->func->fini[0]) { + ret = oproxy->func->fini[0](oproxy, suspend); + if (ret && suspend) + return ret; + } + + ret = nvkm_object_fini(oproxy->object, suspend); + if (ret && suspend) + return ret; + + if (oproxy->func->fini[1]) { + ret = oproxy->func->fini[1](oproxy, suspend); + if (ret && suspend) + return ret; + } + + return 0; +} + +static int +nvkm_oproxy_init(struct nvkm_object *object) +{ + struct nvkm_oproxy *oproxy = nvkm_oproxy(object); + int ret; + + if (oproxy->func->init[0]) { + ret = oproxy->func->init[0](oproxy); + if (ret) + return ret; + } + + ret = nvkm_object_init(oproxy->object); + if (ret) + return ret; + + if (oproxy->func->init[1]) { + ret = oproxy->func->init[1](oproxy); + if (ret) + return ret; + } + + return 0; +} + +static void * +nvkm_oproxy_dtor(struct nvkm_object *object) +{ + struct nvkm_oproxy *oproxy = nvkm_oproxy(object); + if (oproxy->func->dtor[0]) + oproxy->func->dtor[0](oproxy); + nvkm_object_ref(NULL, &oproxy->object); + if (oproxy->func->dtor[1]) + oproxy->func->dtor[1](oproxy); + return oproxy; +} + +static const struct nvkm_object_func +nvkm_oproxy_func = { + .dtor = nvkm_oproxy_dtor, + .init = nvkm_oproxy_init, + .fini = nvkm_oproxy_fini, + .mthd = nvkm_oproxy_mthd, + .ntfy = nvkm_oproxy_ntfy, + .map = nvkm_oproxy_map, + .rd08 = nvkm_oproxy_rd08, + .rd16 = nvkm_oproxy_rd16, + .rd32 = nvkm_oproxy_rd32, + .wr08 = nvkm_oproxy_wr08, + .wr16 = nvkm_oproxy_wr16, + .wr32 = nvkm_oproxy_wr32, + .bind = nvkm_oproxy_bind, + .sclass = nvkm_oproxy_sclass, +}; + +void +nvkm_oproxy_ctor(const struct nvkm_oproxy_func *func, + const struct nvkm_oclass *oclass, struct nvkm_oproxy *oproxy) +{ + nvkm_object_ctor(&nvkm_oproxy_func, oclass, &oproxy->base); + oproxy->func = func; +} + +int +nvkm_oproxy_new_(const struct nvkm_oproxy_func *func, + const struct nvkm_oclass *oclass, struct nvkm_oproxy **poproxy) +{ + if (!(*poproxy = kzalloc(sizeof(**poproxy), GFP_KERNEL))) + return -ENOMEM; + nvkm_oproxy_ctor(func, oclass, *poproxy); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild index 75fc7e62fb74c..04f60452011e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild @@ -53,17 +53,27 @@ nvkm-y += nvkm/engine/disp/dmacgf119.o nvkm-y += nvkm/engine/disp/basenv50.o nvkm-y += nvkm/engine/disp/baseg84.o +nvkm-y += nvkm/engine/disp/basegt200.o +nvkm-y += nvkm/engine/disp/basegt215.o nvkm-y += nvkm/engine/disp/basegf119.o +nvkm-y += nvkm/engine/disp/basegk104.o +nvkm-y += nvkm/engine/disp/basegk110.o nvkm-y += nvkm/engine/disp/corenv50.o nvkm-y += nvkm/engine/disp/coreg84.o nvkm-y += nvkm/engine/disp/coreg94.o +nvkm-y += nvkm/engine/disp/coregt200.o +nvkm-y += nvkm/engine/disp/coregt215.o nvkm-y += nvkm/engine/disp/coregf119.o nvkm-y += nvkm/engine/disp/coregk104.o +nvkm-y += nvkm/engine/disp/coregk110.o +nvkm-y += nvkm/engine/disp/coregm107.o +nvkm-y += nvkm/engine/disp/coregm204.o nvkm-y += nvkm/engine/disp/ovlynv50.o nvkm-y += nvkm/engine/disp/ovlyg84.o nvkm-y += nvkm/engine/disp/ovlygt200.o +nvkm-y += nvkm/engine/disp/ovlygt215.o nvkm-y += nvkm/engine/disp/ovlygf119.o nvkm-y += nvkm/engine/disp/ovlygk104.o @@ -71,7 +81,13 @@ nvkm-y += nvkm/engine/disp/piocnv50.o nvkm-y += nvkm/engine/disp/piocgf119.o nvkm-y += nvkm/engine/disp/cursnv50.o +nvkm-y += nvkm/engine/disp/cursg84.o +nvkm-y += nvkm/engine/disp/cursgt215.o nvkm-y += nvkm/engine/disp/cursgf119.o +nvkm-y += nvkm/engine/disp/cursgk104.o nvkm-y += nvkm/engine/disp/oimmnv50.o +nvkm-y += nvkm/engine/disp/oimmg84.o +nvkm-y += nvkm/engine/disp/oimmgt215.o nvkm-y += nvkm/engine/disp/oimmgf119.o +nvkm-y += nvkm/engine/disp/oimmgk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index fea8516220f3c..165f9d47d11dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -25,7 +25,9 @@ #include "conn.h" #include "outp.h" +#include #include +#include #include #include @@ -114,6 +116,66 @@ nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event) return -EINVAL; } +static void +nvkm_disp_class_del(struct nvkm_oproxy *oproxy) +{ + struct nvkm_disp *disp = nvkm_disp(oproxy->base.engine); + mutex_lock(&disp->engine.subdev.mutex); + if (disp->client == oproxy) + disp->client = NULL; + mutex_unlock(&disp->engine.subdev.mutex); +} + +static const struct nvkm_oproxy_func +nvkm_disp_class = { + .dtor[1] = nvkm_disp_class_del, +}; + +static int +nvkm_disp_class_new(struct nvkm_device *device, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + const struct nvkm_disp_oclass *sclass = oclass->engn; + struct nvkm_disp *disp = nvkm_disp(oclass->engine); + struct nvkm_oproxy *oproxy; + int ret; + + ret = nvkm_oproxy_new_(&nvkm_disp_class, oclass, &oproxy); + if (ret) + return ret; + *pobject = &oproxy->base; + + mutex_lock(&disp->engine.subdev.mutex); + if (disp->client) { + mutex_unlock(&disp->engine.subdev.mutex); + return -EBUSY; + } + disp->client = oproxy; + mutex_unlock(&disp->engine.subdev.mutex); + + return sclass->ctor(disp, oclass, data, size, &oproxy->object); +} + +static const struct nvkm_device_oclass +nvkm_disp_sclass = { + .ctor = nvkm_disp_class_new, +}; + +static int +nvkm_disp_class_get(struct nvkm_oclass *oclass, int index, + const struct nvkm_device_oclass **class) +{ + struct nvkm_disp *disp = nvkm_disp(oclass->engine); + if (index == 0) { + oclass->base = disp->func->root->base; + oclass->engn = disp->func->root; + *class = &nvkm_disp_sclass; + return 0; + } + return 1; +} + int _nvkm_disp_fini(struct nvkm_object *object, bool suspend) { @@ -180,6 +242,11 @@ _nvkm_disp_dtor(struct nvkm_object *object) nvkm_engine_destroy(&disp->engine); } +static const struct nvkm_engine_func +nvkm_disp = { + .base.sclass = nvkm_disp_class_get, +}; + int nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int heads, const char *intname, @@ -203,6 +270,7 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->engine.func = &nvkm_disp; INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c index c476ed0d70aea..6d17630a3dee5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/baseg84.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list g84_disp_base_mthd_base = { @@ -53,13 +56,25 @@ g84_disp_base_mthd_base = { } }; -const struct nv50_disp_mthd_chan -g84_disp_base_mthd_chan = { +const struct nv50_disp_chan_mthd +g84_disp_base_chan_mthd = { .name = "Base", .addr = 0x000540, + .prev = 0x000004, .data = { { "Global", 1, &g84_disp_base_mthd_base }, { "Image", 2, &nv50_disp_base_mthd_image }, {} } }; + +const struct nv50_disp_dmac_oclass +g84_disp_base_oclass = { + .base.oclass = G82_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c index d3c37b49d31c6..ebcb925e9d908 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegf119.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list gf119_disp_base_mthd_base = { @@ -87,10 +90,11 @@ gf119_disp_base_mthd_image = { } }; -const struct nv50_disp_mthd_chan -gf119_disp_base_mthd_chan = { +const struct nv50_disp_chan_mthd +gf119_disp_base_chan_mthd = { .name = "Base", .addr = 0x001000, + .prev = -0x020000, .data = { { "Global", 1, &gf119_disp_base_mthd_base }, { "Image", 2, &gf119_disp_base_mthd_image }, @@ -98,17 +102,13 @@ gf119_disp_base_mthd_chan = { } }; -struct nv50_disp_chan_impl -gf119_disp_base_ofuncs = { - .base.ctor = nv50_disp_base_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf119_disp_dmac_init, - .base.fini = gf119_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_dmac_oclass +gf119_disp_base_oclass = { + .base.oclass = GF110_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, .chid = 1, - .attach = gf119_disp_dmac_object_attach, - .detach = gf119_disp_dmac_object_detach, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c new file mode 100644 index 0000000000000..780a1d9736341 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk104.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gk104_disp_base_oclass = { + .base.oclass = GK104_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c new file mode 100644 index 0000000000000..d8bdd246c8ed9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegk110.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gk110_disp_base_oclass = { + .base.oclass = GK110_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c new file mode 100644 index 0000000000000..93451e46570c6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt200.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gt200_disp_base_oclass = { + .base.oclass = GT200_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c new file mode 100644 index 0000000000000..08e2b1fa3806a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basegt215.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gt215_disp_base_oclass = { + .base.oclass = GT214_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_base_chan_mthd, + .chid = 1, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c index cfb1eac55958f..52775d88dd8fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c @@ -22,12 +22,44 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" #include #include #include +int +nv50_disp_base_new(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_base_channel_dma_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; + u64 push; + + nvif_ioctl(parent, "create disp base channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp base channel dma vers %d " + "pushbuf %016llx head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > disp->head.nr) + return -EINVAL; + push = args->v0.pushbuf; + head = args->v0.head; + } else + return ret; + + return nv50_disp_dmac_new_(func, mthd, root, chid + head, + head, push, oclass, pobject); +} + static const struct nv50_disp_mthd_list nv50_disp_base_mthd_base = { .mthd = 0x0000, @@ -67,10 +99,11 @@ nv50_disp_base_mthd_image = { } }; -const struct nv50_disp_mthd_chan -nv50_disp_base_mthd_chan = { +static const struct nv50_disp_chan_mthd +nv50_disp_base_chan_mthd = { .name = "Base", .addr = 0x000540, + .prev = 0x000004, .data = { { "Global", 1, &nv50_disp_base_mthd_base }, { "Image", 2, &nv50_disp_base_mthd_image }, @@ -78,50 +111,13 @@ nv50_disp_base_mthd_chan = { } }; -int -nv50_disp_base_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_base_channel_dma_v0 v0; - } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - nvif_ioctl(parent, "create disp base channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp base channel dma vers %d " - "pushbuf %016llx head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - args->v0.head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_base_ofuncs = { - .base.ctor = nv50_disp_base_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_dmac_init, - .base.fini = nv50_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_dmac_oclass +nv50_disp_base_oclass = { + .base.oclass = NV50_DISP_BASE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_base_new, + .func = &nv50_disp_dmac_func, + .mthd = &nv50_disp_base_chan_mthd, .chid = 1, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index 2999996497fff..c9cbfbd2a1aef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -24,6 +24,10 @@ #include "channv50.h" #include "rootnv50.h" +#include +#include +#include + #include #include #include @@ -58,39 +62,38 @@ nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, } void -nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, - const struct nv50_disp_mthd_chan *chan) +nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug) { - struct nvkm_object *object = nv_object(disp); - const struct nv50_disp_impl *impl = (void *)object->oclass; - const struct nv50_disp_mthd_list *list; + struct nv50_disp *disp = chan->root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; + const struct nv50_disp_chan_mthd *mthd = chan->mthd; + const struct nv50_disp_mthd_list *list; int i, j; - if (debug > nv_subdev(disp)->debug) + if (debug > subdev->debug) return; - for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { - u32 base = head * chan->addr; - for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { - const char *cname = chan->name; + for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) { + u32 base = chan->head * mthd->addr; + for (j = 0; j < mthd->data[i].nr; j++, base += list->addr) { + const char *cname = mthd->name; const char *sname = ""; char cname_[16], sname_[16]; - if (chan->addr) { + if (mthd->addr) { snprintf(cname_, sizeof(cname_), "%s %d", - chan->name, head); + mthd->name, chan->chid); cname = cname_; } - if (chan->data[i].nr > 1) { + if (mthd->data[i].nr > 1) { snprintf(sname_, sizeof(sname_), " - %s %d", - chan->data[i].name, j); + mthd->data[i].name, j); sname = sname_; } nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname); - nv50_disp_mthd_list(disp, debug, base, impl->mthd.prev, + nv50_disp_mthd_list(disp, debug, base, mthd->prev, list, j); } } @@ -127,7 +130,7 @@ int nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) { - struct nv50_disp_dmac *dmac = (void *)object; + struct nv50_disp_chan *chan = nv50_disp_chan(object); union { struct nvif_notify_uevent_req none; } *args = data; @@ -136,7 +139,7 @@ nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, if (nvif_unvers(args->none)) { notify->size = sizeof(struct nvif_notify_uevent_rep); notify->types = 1; - notify->index = dmac->base.chid; + notify->index = chan->chid; return 0; } @@ -150,11 +153,32 @@ nv50_disp_chan_uevent = { .fini = nv50_disp_chan_uevent_fini, }; +int +nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *data = nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); + return 0; +} + +int +nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); + return 0; +} + int nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent) { - struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; switch (type) { case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: *pevent = &disp->uevent; @@ -168,62 +192,110 @@ nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, int nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) { - struct nv50_disp_chan *chan = (void *)object; - *addr = nv_device_resource_start(nv_device(object), 0) + + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *addr = nv_device_resource_start(device, 0) + 0x640000 + (chan->chid * 0x1000); *size = 0x001000; return 0; } -u32 -nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) +static int +nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_chan *chan = (void *)object; - struct nvkm_device *device = object->engine->subdev.device; - return nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); + struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent); + return chan->func->child_new(chan, oclass, data, size, pobject); } -void -nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +static int +nv50_disp_chan_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) { - struct nv50_disp_chan *chan = (void *)object; - struct nvkm_device *device = object->engine->subdev.device; - nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); + struct nv50_disp_chan *chan = nv50_disp_chan(object); + if (chan->func->child_get) { + int ret = chan->func->child_get(chan, index, oclass); + if (ret == 0) + oclass->ctor = nv50_disp_chan_child_new; + return ret; + } + return -EINVAL; } -void -nv50_disp_chan_destroy(struct nv50_disp_chan *chan) +static int +nv50_disp_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_root *root = (void *)nv_object(chan)->parent; - root->chan &= ~(1 << chan->chid); - nvkm_namedb_destroy(&chan->base); + struct nv50_disp_chan *chan = nv50_disp_chan(object); + chan->func->fini(chan); + return 0; } -int -nv50_disp_chan_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) +static int +nv50_disp_chan_init(struct nvkm_object *object) { - const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs; - struct nv50_disp_root *root = (void *)parent; - struct nv50_disp_chan *chan; - int chid = impl->chid + head; - int ret; + struct nv50_disp_chan *chan = nv50_disp_chan(object); + return chan->func->init(chan); +} - if (root->chan & (1 << chid)) - return -EBUSY; - root->chan |= (1 << chid); +static void * +nv50_disp_chan_dtor(struct nvkm_object *object) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + if (chan->chid >= 0) + disp->chan[chan->chid] = NULL; + return chan->func->dtor ? chan->func->dtor(chan) : chan; +} - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - (1ULL << NVDEV_ENGINE_DMAOBJ), - length, pobject); - chan = *pobject; - if (ret) - return ret; +static const struct nvkm_object_func +nv50_disp_chan = { + .dtor = nv50_disp_chan_dtor, + .init = nv50_disp_chan_init, + .fini = nv50_disp_chan_fini, + .rd32 = nv50_disp_chan_rd32, + .wr32 = nv50_disp_chan_wr32, + .ntfy = nv50_disp_chan_ntfy, + .map = nv50_disp_chan_map, + .sclass = nv50_disp_chan_child_get, +}; + +int +nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, + const struct nvkm_oclass *oclass, + struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = root->disp; + + nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object); + chan->func = func; + chan->mthd = mthd; + chan->root = root; chan->chid = chid; + chan->head = head; - nv_parent(chan)->object_attach = impl->attach; - nv_parent(chan)->object_detach = impl->detach; + if (disp->chan[chan->chid]) { + chan->chid = -1; + return -EBUSY; + } + disp->chan[chan->chid] = chan; return 0; } + +int +nv50_disp_chan_new_(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nv50_disp_chan *chan; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->object; + + return nv50_disp_chan_ctor(func, mthd, root, chid, head, oclass, chan); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h index 982d1bfe9a6b9..aee374884c960 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.h @@ -1,28 +1,40 @@ #ifndef __NV50_DISP_CHAN_H__ #define __NV50_DISP_CHAN_H__ +#define nv50_disp_chan(p) container_of((p), struct nv50_disp_chan, object) #include "nv50.h" -struct nv50_disp_chan_impl { - struct nvkm_ofuncs base; +struct nv50_disp_chan { + const struct nv50_disp_chan_func *func; + const struct nv50_disp_chan_mthd *mthd; + struct nv50_disp_root *root; int chid; - int (*attach)(struct nvkm_object *, struct nvkm_object *, u32); - void (*detach)(struct nvkm_object *, int); -}; + int head; -#include + struct nvkm_object object; +}; -struct nv50_disp_chan { - struct nvkm_namedb base; - int chid; +struct nv50_disp_chan_func { + void *(*dtor)(struct nv50_disp_chan *); + int (*init)(struct nv50_disp_chan *); + void (*fini)(struct nv50_disp_chan *); + int (*child_get)(struct nv50_disp_chan *, int index, + struct nvkm_oclass *); + int (*child_new)(struct nv50_disp_chan *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); }; -int nv50_disp_chan_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, int, void **); -void nv50_disp_chan_destroy(struct nv50_disp_chan *); -int nv50_disp_chan_ntfy(struct nvkm_object *, u32, struct nvkm_event **); -int nv50_disp_chan_map(struct nvkm_object *, u64 *, u32 *); -u32 nv50_disp_chan_rd32(struct nvkm_object *, u64); -void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32); +int nv50_disp_chan_ctor(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, int head, + const struct nvkm_oclass *, struct nv50_disp_chan *); +int nv50_disp_chan_new_(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, int head, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nv50_disp_chan_func nv50_disp_pioc_func; +extern const struct nv50_disp_chan_func gf119_disp_pioc_func; + extern const struct nvkm_event_func nv50_disp_chan_uevent; int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32, struct nvkm_notify *); @@ -30,24 +42,6 @@ void nv50_disp_chan_uevent_send(struct nv50_disp *, int); extern const struct nvkm_event_func gf119_disp_chan_uevent; -#define nv50_disp_chan_init(a) \ - nvkm_namedb_init(&(a)->base) -#define nv50_disp_chan_fini(a,b) \ - nvkm_namedb_fini(&(a)->base, (b)) - -struct nv50_disp_pioc { - struct nv50_disp_chan base; -}; - -int nv50_disp_pioc_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, int, void **); -void nv50_disp_pioc_dtor(struct nvkm_object *); -int nv50_disp_pioc_init(struct nvkm_object *); -int nv50_disp_pioc_fini(struct nvkm_object *, bool); - -int gf119_disp_pioc_init(struct nvkm_object *); -int gf119_disp_pioc_fini(struct nvkm_object *, bool); - struct nv50_disp_mthd_list { u32 mthd; u32 addr; @@ -58,9 +52,10 @@ struct nv50_disp_mthd_list { } data[]; }; -struct nv50_disp_mthd_chan { +struct nv50_disp_chan_mthd { const char *name; u32 addr; + s32 prev; struct { const char *name; int nr; @@ -68,36 +63,65 @@ struct nv50_disp_mthd_chan { } data[]; }; -void nv50_disp_mthd_chan(struct nv50_disp *, int debug, int head, - const struct nv50_disp_mthd_chan *); +void nv50_disp_chan_mthd(struct nv50_disp_chan *, int debug); -extern const struct nv50_disp_mthd_chan nv50_disp_core_mthd_chan; extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base; extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor; extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior; -extern const struct nv50_disp_mthd_chan nv50_disp_base_mthd_chan; extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image; -extern const struct nv50_disp_mthd_chan nv50_disp_ovly_mthd_chan; -extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base; -extern const struct nv50_disp_mthd_chan g84_disp_core_mthd_chan; +extern const struct nv50_disp_chan_mthd g84_disp_core_chan_mthd; extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac; extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head; -extern const struct nv50_disp_mthd_chan g84_disp_base_mthd_chan; -extern const struct nv50_disp_mthd_chan g84_disp_ovly_mthd_chan; - -extern const struct nv50_disp_mthd_chan g94_disp_core_mthd_chan; +extern const struct nv50_disp_chan_mthd g84_disp_base_chan_mthd; +extern const struct nv50_disp_chan_mthd g84_disp_ovly_chan_mthd; -extern const struct nv50_disp_mthd_chan gt200_disp_ovly_mthd_chan; +extern const struct nv50_disp_chan_mthd g94_disp_core_chan_mthd; -extern const struct nv50_disp_mthd_chan gf119_disp_core_mthd_chan; extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_base; extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_dac; extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_sor; extern const struct nv50_disp_mthd_list gf119_disp_core_mthd_pior; -extern const struct nv50_disp_mthd_chan gf119_disp_base_mthd_chan; -extern const struct nv50_disp_mthd_chan gf119_disp_ovly_mthd_chan; +extern const struct nv50_disp_chan_mthd gf119_disp_base_chan_mthd; + +extern const struct nv50_disp_chan_mthd gk104_disp_core_chan_mthd; + +struct nv50_disp_pioc_oclass { + int (*ctor)(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + struct nvkm_sclass base; + const struct nv50_disp_chan_func *func; + const struct nv50_disp_chan_mthd *mthd; + int chid; +}; + +extern const struct nv50_disp_pioc_oclass nv50_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass nv50_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass g84_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass g84_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass gt215_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass gt215_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass gf119_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass gf119_disp_curs_oclass; + +extern const struct nv50_disp_pioc_oclass gk104_disp_oimm_oclass; +extern const struct nv50_disp_pioc_oclass gk104_disp_curs_oclass; + -extern const struct nv50_disp_mthd_chan gk104_disp_core_mthd_chan; -extern const struct nv50_disp_mthd_chan gk104_disp_ovly_mthd_chan; +int nv50_disp_curs_new(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_oimm_new(const struct nv50_disp_chan_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c index 29b020f025e33..1baa5c34b3272 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg84.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include const struct nv50_disp_mthd_list g84_disp_core_mthd_dac = { @@ -87,10 +90,11 @@ g84_disp_core_mthd_head = { } }; -const struct nv50_disp_mthd_chan -g84_disp_core_mthd_chan = { +const struct nv50_disp_chan_mthd +g84_disp_core_chan_mthd = { .name = "Core", .addr = 0x000000, + .prev = 0x000004, .data = { { "Global", 1, &nv50_disp_core_mthd_base }, { "DAC", 3, &g84_disp_core_mthd_dac }, @@ -100,3 +104,14 @@ g84_disp_core_mthd_chan = { {} } }; + +const struct nv50_disp_dmac_oclass +g84_disp_core_oclass = { + .base.oclass = G82_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g84_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c index 81455256ebb1d..019379a3a01cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coreg94.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include const struct nv50_disp_mthd_list g94_disp_core_mthd_sor = { @@ -33,10 +36,11 @@ g94_disp_core_mthd_sor = { } }; -const struct nv50_disp_mthd_chan -g94_disp_core_mthd_chan = { +const struct nv50_disp_chan_mthd +g94_disp_core_chan_mthd = { .name = "Core", .addr = 0x000000, + .prev = 0x000004, .data = { { "Global", 1, &nv50_disp_core_mthd_base }, { "DAC", 3, &g84_disp_core_mthd_dac }, @@ -46,3 +50,14 @@ g94_disp_core_mthd_chan = { {} } }; + +const struct nv50_disp_dmac_oclass +g94_disp_core_oclass = { + .base.oclass = GT206_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g94_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c index 87f5c43115c1f..6b1dc703dac7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregf119.c @@ -22,9 +22,14 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" +#include #include +#include +#include + const struct nv50_disp_mthd_list gf119_disp_core_mthd_base = { .mthd = 0x0000, @@ -151,10 +156,11 @@ gf119_disp_core_mthd_head = { } }; -const struct nv50_disp_mthd_chan -gf119_disp_core_mthd_chan = { +static const struct nv50_disp_chan_mthd +gf119_disp_core_chan_mthd = { .name = "Core", .addr = 0x000000, + .prev = -0x020000, .data = { { "Global", 1, &gf119_disp_core_mthd_base }, { "DAC", 3, &gf119_disp_core_mthd_dac }, @@ -165,11 +171,10 @@ gf119_disp_core_mthd_chan = { } }; -static int -gf119_disp_core_fini(struct nvkm_object *object, bool suspend) +static void +gf119_disp_core_fini(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; @@ -182,35 +187,25 @@ gf119_disp_core_fini(struct nvkm_object *object, bool suspend) ) < 0) { nvkm_error(subdev, "core fini: %08x\n", nvkm_rd32(device, 0x610490)); - if (suspend) - return -EBUSY; } /* disable error reporting and completion notification */ nvkm_mask(device, 0x610090, 0x00000001, 0x00000000); nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000000); - - return nv50_disp_chan_fini(&mast->base, suspend); } static int -gf119_disp_core_init(struct nvkm_object *object) +gf119_disp_core_init(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int ret; - - ret = nv50_disp_chan_init(&mast->base); - if (ret) - return ret; /* enable error reporting */ nvkm_mask(device, 0x6100a0, 0x00000001, 0x00000001); /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610494, mast->push); + nvkm_wr32(device, 0x610494, chan->push); nvkm_wr32(device, 0x610498, 0x00010000); nvkm_wr32(device, 0x61049c, 0x00000001); nvkm_mask(device, 0x610490, 0x00000010, 0x00000010); @@ -230,17 +225,20 @@ gf119_disp_core_init(struct nvkm_object *object) return 0; } -struct nv50_disp_chan_impl -gf119_disp_core_ofuncs = { - .base.ctor = nv50_disp_core_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf119_disp_core_init, - .base.fini = gf119_disp_core_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_dmac_func +gf119_disp_core_func = { + .init = gf119_disp_core_init, + .fini = gf119_disp_core_fini, + .bind = gf119_disp_dmac_bind, +}; + +const struct nv50_disp_dmac_oclass +gf119_disp_core_oclass = { + .base.oclass = GF110_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gf119_disp_core_chan_mthd, .chid = 0, - .attach = gf119_disp_dmac_object_attach, - .detach = gf119_disp_dmac_object_detach, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c index 6662cc6d70a30..088ab222e8232 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk104.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list gk104_disp_core_mthd_head = { @@ -102,10 +105,11 @@ gk104_disp_core_mthd_head = { } }; -const struct nv50_disp_mthd_chan -gk104_disp_core_mthd_chan = { +const struct nv50_disp_chan_mthd +gk104_disp_core_chan_mthd = { .name = "Core", .addr = 0x000000, + .prev = -0x020000, .data = { { "Global", 1, &gf119_disp_core_mthd_base }, { "DAC", 3, &gf119_disp_core_mthd_dac }, @@ -115,3 +119,14 @@ gk104_disp_core_mthd_chan = { {} } }; + +const struct nv50_disp_dmac_oclass +gk104_disp_core_oclass = { + .base.oclass = GK104_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c new file mode 100644 index 0000000000000..df0f45c20108e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregk110.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gk110_disp_core_oclass = { + .base.oclass = GK110_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c new file mode 100644 index 0000000000000..9e27f8fd98b6c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm107.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gm107_disp_core_oclass = { + .base.oclass = GM107_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c new file mode 100644 index 0000000000000..222f4a822f4de --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregm204.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gm204_disp_core_oclass = { + .base.oclass = GM204_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &gf119_disp_core_func, + .mthd = &gk104_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c new file mode 100644 index 0000000000000..b234547708fcf --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt200.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gt200_disp_core_oclass = { + .base.oclass = GT200_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g84_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c new file mode 100644 index 0000000000000..8f5ba20189756 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/coregt215.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gt215_disp_core_oclass = { + .base.oclass = GT214_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &g94_disp_core_chan_mthd, + .chid = 0, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c index 624b795101759..db4a9b3e0e09e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/corenv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" #include #include @@ -29,6 +30,33 @@ #include #include +int +nv50_disp_core_new(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_core_channel_dma_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + u64 push; + int ret; + + nvif_ioctl(parent, "create disp core channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp core channel dma vers %d " + "pushbuf %016llx\n", + args->v0.version, args->v0.pushbuf); + push = args->v0.pushbuf; + } else + return ret; + + return nv50_disp_dmac_new_(func, mthd, root, chid, 0, + push, oclass, pobject); +} + const struct nv50_disp_mthd_list nv50_disp_core_mthd_base = { .mthd = 0x0000, @@ -121,10 +149,11 @@ nv50_disp_core_mthd_head = { } }; -const struct nv50_disp_mthd_chan -nv50_disp_core_mthd_chan = { +static const struct nv50_disp_chan_mthd +nv50_disp_core_chan_mthd = { .name = "Core", .addr = 0x000000, + .prev = 0x000004, .data = { { "Global", 1, &nv50_disp_core_mthd_base }, { "DAC", 3, &nv50_disp_core_mthd_dac }, @@ -135,11 +164,10 @@ nv50_disp_core_mthd_chan = { } }; -static int -nv50_disp_core_fini(struct nvkm_object *object, bool suspend) +static void +nv50_disp_core_fini(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; @@ -152,28 +180,18 @@ nv50_disp_core_fini(struct nvkm_object *object, bool suspend) ) < 0) { nvkm_error(subdev, "core fini: %08x\n", nvkm_rd32(device, 0x610200)); - if (suspend) - return -EBUSY; } /* disable error reporting and completion notifications */ nvkm_mask(device, 0x610028, 0x00010001, 0x00000000); - - return nv50_disp_chan_fini(&mast->base, suspend); } static int -nv50_disp_core_init(struct nvkm_object *object) +nv50_disp_core_init(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *mast = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int ret; - - ret = nv50_disp_chan_init(&mast->base); - if (ret) - return ret; /* enable error reporting */ nvkm_mask(device, 0x610028, 0x00010000, 0x00010000); @@ -185,7 +203,7 @@ nv50_disp_core_init(struct nvkm_object *object) nvkm_mask(device, 0x610200, 0x00600000, 0x00600000); /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610204, mast->push); + nvkm_wr32(device, 0x610204, chan->push); nvkm_wr32(device, 0x610208, 0x00010000); nvkm_wr32(device, 0x61020c, 0x00000000); nvkm_mask(device, 0x610200, 0x00000010, 0x00000010); @@ -205,46 +223,20 @@ nv50_disp_core_init(struct nvkm_object *object) return 0; } -int -nv50_disp_core_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_core_channel_dma_v0 v0; - } *args = data; - struct nv50_disp_dmac *mast; - int ret; - - nvif_ioctl(parent, "create disp core channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp core channel dma vers %d " - "pushbuf %016llx\n", - args->v0.version, args->v0.pushbuf); - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - 0, sizeof(*mast), (void **)&mast); - *pobject = nv_object(mast); - if (ret) - return ret; - - return 0; -} +const struct nv50_disp_dmac_func +nv50_disp_core_func = { + .init = nv50_disp_core_init, + .fini = nv50_disp_core_fini, + .bind = nv50_disp_dmac_bind, +}; -struct nv50_disp_chan_impl -nv50_disp_core_ofuncs = { - .base.ctor = nv50_disp_core_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_core_init, - .base.fini = nv50_disp_core_fini, - .base.map = nv50_disp_chan_map, - .base.ntfy = nv50_disp_chan_ntfy, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_dmac_oclass +nv50_disp_core_oclass = { + .base.oclass = NV50_DISP_CORE_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_core_new, + .func = &nv50_disp_core_func, + .mthd = &nv50_disp_core_chan_mthd, .chid = 0, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c new file mode 100644 index 0000000000000..dd99fc7060b19 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursg84.c @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_pioc_oclass +g84_disp_curs_oclass = { + .base.oclass = G82_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, + .chid = 7, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c index 5537a4ae4e15d..2a1574e06ad6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgf119.c @@ -22,16 +22,16 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "rootnv50.h" -struct nv50_disp_chan_impl -gf119_disp_curs_ofuncs = { - .base.ctor = nv50_disp_curs_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = gf119_disp_pioc_init, - .base.fini = gf119_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +#include + +const struct nv50_disp_pioc_oclass +gf119_disp_curs_oclass = { + .base.oclass = GF110_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &gf119_disp_pioc_func, .chid = 13, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c new file mode 100644 index 0000000000000..28e8f06c9472b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgk104.c @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_pioc_oclass +gk104_disp_curs_oclass = { + .base.oclass = GK104_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &gf119_disp_pioc_func, + .chid = 13, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c new file mode 100644 index 0000000000000..d8a4b9ca139c6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursgt215.c @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_pioc_oclass +gt215_disp_curs_oclass = { + .base.oclass = GT214_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, + .chid = 7, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c index 2b4e877347cbe..f3ce583fbcf2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "rootnv50.h" #include @@ -29,17 +30,18 @@ #include int -nv50_disp_curs_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_disp_curs_new(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { union { struct nv50_disp_cursor_v0 v0; } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; nvif_ioctl(parent, "create disp cursor size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { @@ -47,27 +49,20 @@ nv50_disp_curs_ctor(struct nvkm_object *parent, args->v0.version, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; + head = args->v0.head; } else return ret; - ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; + return nv50_disp_chan_new_(func, mthd, root, chid + head, + head, oclass, pobject); } -struct nv50_disp_chan_impl -nv50_disp_curs_ofuncs = { - .base.ctor = nv50_disp_curs_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = nv50_disp_pioc_init, - .base.fini = nv50_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_pioc_oclass +nv50_disp_curs_oclass = { + .base.oclass = NV50_DISP_CURSOR, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_curs_new, + .func = &nv50_disp_pioc_func, .chid = 7, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c index 6add32fa24d81..876b14549a587 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacgf119.c @@ -27,32 +27,22 @@ #include #include -void -gf119_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv50_disp_root *root = (void *)parent->parent; - nvkm_ramht_remove(root->ramht, cookie); -} - int -gf119_disp_dmac_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 name) +gf119_disp_dmac_bind(struct nv50_disp_dmac *chan, + struct nvkm_object *object, u32 handle) { - struct nv50_disp_root *root = (void *)parent->parent; - struct nv50_disp_chan *chan = (void *)parent; - u32 addr = nv_gpuobj(object)->node->offset; - u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001; - return nvkm_ramht_insert(root->ramht, NULL, chan->chid, 0, name, data); + return nvkm_ramht_insert(chan->base.root->ramht, object, + chan->base.chid, -9, handle, + chan->base.chid << 27 | 0x00000001); } -int -gf119_disp_dmac_fini(struct nvkm_object *object, bool suspend) +static void +gf119_disp_dmac_fini(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; + int chid = chan->base.chid; /* deactivate channel */ nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000); @@ -63,36 +53,26 @@ gf119_disp_dmac_fini(struct nvkm_object *object, bool suspend) ) < 0) { nvkm_error(subdev, "ch %d fini: %08x\n", chid, nvkm_rd32(device, 0x610490 + (chid * 0x10))); - if (suspend) - return -EBUSY; } /* disable error reporting and completion notification */ nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); - - return nv50_disp_chan_fini(&dmac->base, suspend); } -int -gf119_disp_dmac_init(struct nvkm_object *object) +static int +gf119_disp_dmac_init(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; - int ret; - - ret = nv50_disp_chan_init(&dmac->base); - if (ret) - return ret; + int chid = chan->base.chid; /* enable error reporting */ nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610494 + (chid * 0x0010), dmac->push); + nvkm_wr32(device, 0x610494 + (chid * 0x0010), chan->push); nvkm_wr32(device, 0x610498 + (chid * 0x0010), 0x00010000); nvkm_wr32(device, 0x61049c + (chid * 0x0010), 0x00000001); nvkm_mask(device, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010); @@ -111,3 +91,10 @@ gf119_disp_dmac_init(struct nvkm_object *object) return 0; } + +const struct nv50_disp_dmac_func +gf119_disp_dmac_func = { + .init = gf119_disp_dmac_init, + .fini = gf119_disp_dmac_fini, + .bind = gf119_disp_dmac_bind, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c index 43c17d07e96ef..9ad9512782a59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c @@ -26,38 +26,172 @@ #include #include +#include #include #include #include #include -void -nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie) +struct nv50_disp_dmac_object { + struct nvkm_oproxy oproxy; + struct nv50_disp_root *root; + int hash; +}; + +static void +nv50_disp_dmac_child_del_(struct nvkm_oproxy *base) +{ + struct nv50_disp_dmac_object *object = + container_of(base, typeof(*object), oproxy); + nvkm_ramht_remove(object->root->ramht, object->hash); +} + +static const struct nvkm_oproxy_func +nv50_disp_dmac_child_func_ = { + .dtor[0] = nv50_disp_dmac_child_del_, +}; + +static int +nv50_disp_dmac_child_new_(struct nv50_disp_chan *base, + const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + struct nv50_disp_root *root = chan->base.root; + struct nvkm_device *device = root->disp->base.engine.subdev.device; + const struct nvkm_device_oclass *sclass = oclass->priv; + struct nv50_disp_dmac_object *object; + int ret; + + if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) + return -ENOMEM; + nvkm_oproxy_ctor(&nv50_disp_dmac_child_func_, oclass, &object->oproxy); + object->root = root; + *pobject = &object->oproxy.base; + + ret = sclass->ctor(device, oclass, data, size, &object->oproxy.object); + if (ret) + return ret; + + object->hash = chan->func->bind(chan, object->oproxy.object, + oclass->handle); + if (object->hash < 0) + return object->hash; + + return 0; +} + +static int +nv50_disp_dmac_child_get_(struct nv50_disp_chan *base, int index, + struct nvkm_oclass *sclass) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + struct nv50_disp *disp = chan->base.root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + const struct nvkm_device_oclass *oclass = NULL; + + sclass->engine = nvkm_device_engine(device, NVDEV_ENGINE_DMAOBJ); + if (sclass->engine && sclass->engine->func->base.sclass) { + sclass->engine->func->base.sclass(sclass, index, &oclass); + if (oclass) { + sclass->priv = oclass; + return 0; + } + } + + return -EINVAL; +} + +static void +nv50_disp_dmac_fini_(struct nv50_disp_chan *base) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + chan->func->fini(chan); +} + +static int +nv50_disp_dmac_init_(struct nv50_disp_chan *base) +{ + struct nv50_disp_dmac *chan = nv50_disp_dmac(base); + return chan->func->init(chan); +} + +static void * +nv50_disp_dmac_dtor_(struct nv50_disp_chan *base) { - struct nv50_disp_root *root = (void *)parent->parent; - nvkm_ramht_remove(root->ramht, cookie); + return nv50_disp_dmac(base); } +static const struct nv50_disp_chan_func +nv50_disp_dmac_func_ = { + .dtor = nv50_disp_dmac_dtor_, + .init = nv50_disp_dmac_init_, + .fini = nv50_disp_dmac_fini_, + .child_get = nv50_disp_dmac_child_get_, + .child_new = nv50_disp_dmac_child_new_, +}; + int -nv50_disp_dmac_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 name) +nv50_disp_dmac_new_(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, u64 push, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) { - struct nv50_disp_root *root = (void *)parent->parent; - struct nv50_disp_chan *chan = (void *)parent; - u32 addr = nv_gpuobj(object)->node->offset; - u32 chid = chan->chid; - u32 data = (chid << 28) | (addr << 10) | chid; - return nvkm_ramht_insert(root->ramht, NULL, chid, 0, name, data); + struct nvkm_device *device = root->disp->base.engine.subdev.device; + struct nvkm_client *client = oclass->client; + struct nvkm_dmaobj *dmaobj; + struct nv50_disp_dmac *chan; + int ret; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + chan->func = func; + + ret = nv50_disp_chan_ctor(&nv50_disp_dmac_func_, mthd, root, + chid, head, oclass, &chan->base); + if (ret) + return ret; + + dmaobj = nvkm_dma_search(device->dma, client, push); + if (!dmaobj) + return -ENOENT; + + if (dmaobj->limit - dmaobj->start != 0xfff) + return -EINVAL; + + switch (dmaobj->target) { + case NV_MEM_TARGET_VRAM: + chan->push = 0x00000001 | dmaobj->start >> 8; + break; + case NV_MEM_TARGET_PCI_NOSNOOP: + chan->push = 0x00000003 | dmaobj->start >> 8; + break; + default: + return -EINVAL; + } + + return 0; } int -nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) +nv50_disp_dmac_bind(struct nv50_disp_dmac *chan, + struct nvkm_object *object, u32 handle) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; + return nvkm_ramht_insert(chan->base.root->ramht, object, + chan->base.chid, -10, handle, + chan->base.chid << 28 | + chan->base.chid); +} + +static void +nv50_disp_dmac_fini(struct nv50_disp_dmac *chan) +{ + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; + int chid = chan->base.chid; /* deactivate channel */ nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); @@ -68,35 +202,25 @@ nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend) ) < 0) { nvkm_error(subdev, "ch %d fini timeout, %08x\n", chid, nvkm_rd32(device, 0x610200 + (chid * 0x10))); - if (suspend) - return -EBUSY; } /* disable error reporting and completion notifications */ nvkm_mask(device, 0x610028, 0x00010001 << chid, 0x00000000 << chid); - - return nv50_disp_chan_fini(&dmac->base, suspend); } -int -nv50_disp_dmac_init(struct nvkm_object *object) +static int +nv50_disp_dmac_init(struct nv50_disp_dmac *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_dmac *dmac = (void *)object; + struct nv50_disp *disp = chan->base.root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = dmac->base.chid; - int ret; - - ret = nv50_disp_chan_init(&dmac->base); - if (ret) - return ret; + int chid = chan->base.chid; /* enable error reporting */ nvkm_mask(device, 0x610028, 0x00010000 << chid, 0x00010000 << chid); /* initialise channel for dma command submission */ - nvkm_wr32(device, 0x610204 + (chid * 0x0010), dmac->push); + nvkm_wr32(device, 0x610204 + (chid * 0x0010), chan->push); nvkm_wr32(device, 0x610208 + (chid * 0x0010), 0x00010000); nvkm_wr32(device, 0x61020c + (chid * 0x0010), chid); nvkm_mask(device, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); @@ -116,48 +240,9 @@ nv50_disp_dmac_init(struct nvkm_object *object) return 0; } -void -nv50_disp_dmac_dtor(struct nvkm_object *object) -{ - struct nv50_disp_dmac *dmac = (void *)object; - nv50_disp_chan_destroy(&dmac->base); -} - -int -nv50_disp_dmac_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, u64 pushbuf, int head, - int length, void **pobject) -{ - struct nvkm_device *device = parent->engine->subdev.device; - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_dmaobj *dmaobj; - struct nv50_disp_dmac *dmac; - int ret; - - ret = nv50_disp_chan_create_(parent, engine, oclass, head, - length, pobject); - dmac = *pobject; - if (ret) - return ret; - - dmaobj = nvkm_dma_search(device->dma, client, pushbuf); - if (!dmaobj) - return -ENOENT; - - if (dmaobj->limit - dmaobj->start != 0xfff) - return -EINVAL; - - switch (dmaobj->target) { - case NV_MEM_TARGET_VRAM: - dmac->push = 0x00000001 | dmaobj->start >> 8; - break; - case NV_MEM_TARGET_PCI_NOSNOOP: - dmac->push = 0x00000003 | dmaobj->start >> 8; - break; - default: - return -EINVAL; - } - - return 0; -} +const struct nv50_disp_dmac_func +nv50_disp_dmac_func = { + .init = nv50_disp_dmac_init, + .fini = nv50_disp_dmac_fini, + .bind = nv50_disp_dmac_bind, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h index cfd09d275b139..c748ca23ab708 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.h @@ -1,24 +1,91 @@ #ifndef __NV50_DISP_DMAC_H__ #define __NV50_DISP_DMAC_H__ +#define nv50_disp_dmac(p) container_of((p), struct nv50_disp_dmac, base) #include "channv50.h" struct nv50_disp_dmac { + const struct nv50_disp_dmac_func *func; struct nv50_disp_chan base; u32 push; }; -void nv50_disp_dmac_dtor(struct nvkm_object *); -int nv50_disp_dmac_object_attach(struct nvkm_object *, - struct nvkm_object *, u32); -void nv50_disp_dmac_object_detach(struct nvkm_object *, int); -int nv50_disp_dmac_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u64, int, int, void **); -int nv50_disp_dmac_init(struct nvkm_object *); -int nv50_disp_dmac_fini(struct nvkm_object *, bool); - -int gf119_disp_dmac_object_attach(struct nvkm_object *, - struct nvkm_object *, u32); -void gf119_disp_dmac_object_detach(struct nvkm_object *, int); -int gf119_disp_dmac_init(struct nvkm_object *); -int gf119_disp_dmac_fini(struct nvkm_object *, bool); +struct nv50_disp_dmac_func { + int (*init)(struct nv50_disp_dmac *); + void (*fini)(struct nv50_disp_dmac *); + int (*bind)(struct nv50_disp_dmac *, struct nvkm_object *, u32 handle); +}; + +int nv50_disp_dmac_new_(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, int head, u64 push, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nv50_disp_dmac_func nv50_disp_dmac_func; +int nv50_disp_dmac_bind(struct nv50_disp_dmac *, struct nvkm_object *, u32); +extern const struct nv50_disp_dmac_func nv50_disp_core_func; + +extern const struct nv50_disp_dmac_func gf119_disp_dmac_func; +int gf119_disp_dmac_bind(struct nv50_disp_dmac *, struct nvkm_object *, u32); +extern const struct nv50_disp_dmac_func gf119_disp_core_func; + +struct nv50_disp_dmac_oclass { + int (*ctor)(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); + struct nvkm_sclass base; + const struct nv50_disp_dmac_func *func; + const struct nv50_disp_chan_mthd *mthd; + int chid; +}; + +int nv50_disp_core_new(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_base_new(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_ovly_new(const struct nv50_disp_dmac_func *, + const struct nv50_disp_chan_mthd *, + struct nv50_disp_root *, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **); + +extern const struct nv50_disp_dmac_oclass nv50_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass nv50_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass nv50_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass g84_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass g84_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass g84_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass g94_disp_core_oclass; + +extern const struct nv50_disp_dmac_oclass gt200_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gt200_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gt200_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gt215_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gt215_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gt215_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gf119_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gf119_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gf119_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gk104_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gk104_disp_base_oclass; +extern const struct nv50_disp_dmac_oclass gk104_disp_ovly_oclass; + +extern const struct nv50_disp_dmac_oclass gk110_disp_core_oclass; +extern const struct nv50_disp_dmac_oclass gk110_disp_base_oclass; + +extern const struct nv50_disp_dmac_oclass gm107_disp_core_oclass; + +extern const struct nv50_disp_dmac_oclass gm204_disp_core_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index 5995bcae21788..a223cef2b81f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +g84_disp = { + .root = &g84_disp_root_oclass, +}; + static int g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -38,15 +43,14 @@ g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &g84_disp; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = g84_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->sclass = g84_disp_sclass; disp->head.nr = 2; disp->dac.nr = 3; disp->sor.nr = 2; @@ -74,9 +78,5 @@ g84_disp_oclass = &(struct nv50_disp_impl) { .base.outp.external.tmds = nv50_pior_output_new, .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .mthd.core = &g84_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = &g84_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 0247090076357..639b02b2fc141 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +g94_disp = { + .root = &g94_disp_root_oclass, +}; + static int g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -38,15 +43,14 @@ g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &g94_disp; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = g94_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->sclass = g94_disp_sclass; disp->head.nr = 2; disp->dac.nr = 3; disp->sor.nr = 4; @@ -75,9 +79,5 @@ g94_disp_oclass = &(struct nv50_disp_impl) { .base.outp.external.lvds = nv50_pior_output_new, .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .mthd.core = &g94_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = &g84_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 154185a98e017..c3d22e33e0736 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -370,7 +370,6 @@ gf119_disp_intr_supervisor(struct work_struct *work) { struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 mask[4]; @@ -383,7 +382,7 @@ gf119_disp_intr_supervisor(struct work_struct *work) } if (disp->super & 0x00000001) { - nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); + nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); for (head = 0; head < disp->head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; @@ -428,7 +427,6 @@ gf119_disp_intr_supervisor(struct work_struct *work) static void gf119_disp_intr_error(struct nv50_disp *disp, int chid) { - const struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 mthd = nvkm_rd32(device, 0x6101f0 + (chid * 12)); @@ -438,31 +436,10 @@ gf119_disp_intr_error(struct nv50_disp *disp, int chid) nvkm_error(subdev, "chid %d mthd %04x data %08x %08x %08x\n", chid, (mthd & 0x0000ffc), data, mthd, unkn); - if (chid == 0) { + if (chid < ARRAY_SIZE(disp->chan)) { switch (mthd & 0xffc) { case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 0, - impl->mthd.core); - break; - default: - break; - } - } else - if (chid <= 4) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 1, - impl->mthd.base); - break; - default: - break; - } - } else - if (chid <= 8) { - switch (mthd & 0xffc) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 5, - impl->mthd.ovly); + nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); break; default: break; @@ -528,6 +505,11 @@ gf119_disp_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_disp_func +gf119_disp = { + .root = &gf119_disp_root_oclass, +}; + static int gf119_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -544,15 +526,14 @@ gf119_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &gf119_disp; + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gf119_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = gf119_disp_intr; INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->sclass = gf119_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; disp->sor.nr = 4; @@ -578,9 +559,5 @@ gf110_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.lvds = nv50_sor_output_new, .base.outp.internal.dp = gf119_sor_dp_new, .base.vblank = &gf119_disp_vblank_func, - .mthd.core = &gf119_disp_core_mthd_chan, - .mthd.base = &gf119_disp_base_mthd_chan, - .mthd.ovly = &gf119_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index 404c75278dd8c..e478c9f87fc6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +gk104_disp = { + .root = &gk104_disp_root_oclass, +}; + static int gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -40,15 +45,14 @@ gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &gk104_disp; + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gk104_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = gf119_disp_intr; INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->sclass = gk104_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; disp->sor.nr = 4; @@ -74,9 +78,5 @@ gk104_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.lvds = nv50_sor_output_new, .base.outp.internal.dp = gf119_sor_dp_new, .base.vblank = &gf119_disp_vblank_func, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf119_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index 2bb3515060af5..f4801f8e8c7e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +gk110_disp = { + .root = &gk110_disp_root_oclass, +}; + static int gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -40,15 +45,14 @@ gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &gk110_disp; + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gk110_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = gf119_disp_intr; INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->sclass = gk110_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; disp->sor.nr = 4; @@ -74,9 +78,5 @@ gk110_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.lvds = nv50_sor_output_new, .base.outp.internal.dp = gf119_sor_dp_new, .base.vblank = &gf119_disp_vblank_func, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf119_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index fbc6b7c861896..a72f61078acf2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +gm107_disp = { + .root = &gm107_disp_root_oclass, +}; + static int gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -40,15 +45,14 @@ gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &gm107_disp; + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gm107_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = gf119_disp_intr; INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->sclass = gm107_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; disp->sor.nr = 4; @@ -74,9 +78,5 @@ gm107_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.lvds = nv50_sor_output_new, .base.outp.internal.dp = gf119_sor_dp_new, .base.vblank = &gf119_disp_vblank_func, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf119_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index bf6ede5c424e0..363e939376e96 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +gm204_disp = { + .root = &gm204_disp_root_oclass, +}; + static int gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -40,15 +45,14 @@ gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &gm204_disp; + ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gm204_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = gf119_disp_intr; INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->sclass = gm204_disp_sclass; disp->head.nr = heads; disp->dac.nr = 3; disp->sor.nr = 4; @@ -75,9 +79,5 @@ gm204_disp_oclass = &(struct nv50_disp_impl) { .base.outp.internal.lvds = nv50_sor_output_new, .base.outp.internal.dp = gm204_sor_dp_new, .base.vblank = &gf119_disp_vblank_func, - .mthd.core = &gk104_disp_core_mthd_chan, - .mthd.base = &gf119_disp_base_mthd_chan, - .mthd.ovly = &gk104_disp_ovly_mthd_chan, - .mthd.prev = -0x020000, .head.scanoutpos = gf119_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index 811f092a2df0d..c699c5f70b8d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +gt200_disp = { + .root = >200_disp_root_oclass, +}; + static int gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -38,15 +43,14 @@ gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = >200_disp; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gt200_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->sclass = gt200_disp_sclass; disp->head.nr = 2; disp->dac.nr = 3; disp->sor.nr = 2; @@ -74,9 +78,5 @@ gt200_disp_oclass = &(struct nv50_disp_impl) { .base.outp.external.tmds = nv50_pior_output_new, .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .mthd.core = &g84_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = >200_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index fdde7ce18ce1d..ddf65902fd231 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -24,6 +24,11 @@ #include "nv50.h" #include "rootnv50.h" +static const struct nvkm_disp_func +gt215_disp_func = { + .root = >215_disp_root_oclass, +}; + static int gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -38,15 +43,14 @@ gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = >215_disp_func; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = gt215_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->sclass = gt215_disp_sclass; disp->head.nr = 2; disp->dac.nr = 3; disp->sor.nr = 4; @@ -76,9 +80,5 @@ gt215_disp_oclass = &(struct nv50_disp_impl) { .base.outp.external.lvds = nv50_pior_output_new, .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .mthd.core = &g94_disp_core_mthd_chan, - .mthd.base = &g84_disp_base_mthd_chan, - .mthd.ovly = &g84_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index ceac0c0bbb4fb..33922f3a176a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -74,6 +74,11 @@ nv04_disp_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_disp_func +nv04_disp = { + .root = &nv04_disp_root_oclass, +}; + static int nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -88,7 +93,8 @@ nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(disp)->sclass = nv04_disp_sclass; + disp->func = &nv04_disp; + nv_subdev(disp)->intr = nv04_disp_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 240a5438c7acd..9bc4273947c34 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -33,47 +33,6 @@ #include #include -static int -nv50_disp_data_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_disp *disp = (void *)engine; - struct nvkm_gpuobj *gpuobj; - int ret; - - /* no context needed for channel objects... */ - if (parent->parent != &nvkm_client(parent)->object) { - atomic_inc(&parent->refcount); - *pobject = parent; - return 1; - } - - /* allocate display hardware to client */ - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, NULL, - 0x10000, 0x10000, NVOBJ_FLAG_HEAP, - &gpuobj); - *pobject = nv_object(gpuobj); - mutex_lock(&nv_subdev(disp)->mutex); - if (!list_empty(&nv_engine(disp)->contexts)) - ret = -EBUSY; - mutex_unlock(&nv_subdev(disp)->mutex); - return ret; -} - -struct nvkm_oclass -nv50_disp_cclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_disp_data_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, - }, -}; - static void nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) { @@ -115,7 +74,6 @@ nv50_disp_intr_error_code[] = { static void nv50_disp_intr_error(struct nv50_disp *disp, int chid) { - struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 data = nvkm_rd32(device, 0x610084 + (chid * 0x08)); @@ -133,31 +91,10 @@ nv50_disp_intr_error(struct nv50_disp *disp, int chid) type, et ? et->name : "", code, ec ? ec->name : "", chid, mthd, data); - if (chid == 0) { - switch (mthd) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 0, - impl->mthd.core); - break; - default: - break; - } - } else - if (chid <= 2) { - switch (mthd) { - case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 1, - impl->mthd.base); - break; - default: - break; - } - } else - if (chid <= 4) { + if (chid < ARRAY_SIZE(disp->chan)) { switch (mthd) { case 0x0080: - nv50_disp_mthd_chan(disp, NV_DBG_ERROR, chid - 3, - impl->mthd.ovly); + nv50_disp_chan_mthd(disp->chan[chid], NV_DBG_ERROR); break; default: break; @@ -673,7 +610,6 @@ nv50_disp_intr_supervisor(struct work_struct *work) { struct nv50_disp *disp = container_of(work, struct nv50_disp, supervisor); - struct nv50_disp_impl *impl = (void *)nv_object(disp)->oclass; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 super = nvkm_rd32(device, 0x610030); @@ -682,7 +618,7 @@ nv50_disp_intr_supervisor(struct work_struct *work) nvkm_debug(subdev, "supervisor %08x %08x\n", disp->super, super); if (disp->super & 0x00000010) { - nv50_disp_mthd_chan(disp, NV_DBG_DEBUG, 0, impl->mthd.core); + nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); for (head = 0; head < disp->head.nr; head++) { if (!(super & (0x00000020 << head))) continue; @@ -756,6 +692,11 @@ nv50_disp_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_disp_func +nv50_disp = { + .root = &nv50_disp_root_oclass, +}; + static int nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -770,15 +711,14 @@ nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + disp->base.func = &nv50_disp; + ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); if (ret) return ret; - nv_engine(disp)->sclass = nv50_disp_root_oclass; - nv_engine(disp)->cclass = &nv50_disp_cclass; nv_subdev(disp)->intr = nv50_disp_intr; INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->sclass = nv50_disp_sclass; disp->head.nr = 2; disp->dac.nr = 3; disp->sor.nr = 2; @@ -805,9 +745,5 @@ nv50_disp_oclass = &(struct nv50_disp_impl) { .base.outp.external.tmds = nv50_pior_output_new, .base.outp.external.dp = nv50_pior_dp_new, .base.vblank = &nv50_disp_vblank_func, - .mthd.core = &nv50_disp_core_mthd_chan, - .mthd.base = &nv50_disp_base_mthd_chan, - .mthd.ovly = &nv50_disp_ovly_mthd_chan, - .mthd.prev = 0x000004, .head.scanoutpos = nv50_disp_root_scanoutpos, }.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index e42e66e1c1f33..13766b24706d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -1,5 +1,6 @@ #ifndef __NV50_DISP_H__ #define __NV50_DISP_H__ +#define nv50_disp(p) container_of((p), struct nv50_disp, base) #include "priv.h" struct nvkm_output; struct nvkm_output_dp; @@ -11,7 +12,6 @@ struct nvkm_output_dp; struct nv50_disp { struct nvkm_disp base; - struct nvkm_oclass *sclass; struct work_struct supervisor; u32 super; @@ -39,23 +39,18 @@ struct nv50_disp { int (*power)(NV50_DISP_MTHD_V1); u8 type[3]; } pior; + + struct nv50_disp_chan *chan[17]; }; struct nv50_disp_impl { struct nvkm_disp_impl base; - struct { - const struct nv50_disp_mthd_chan *core; - const struct nv50_disp_mthd_chan *base; - const struct nv50_disp_mthd_chan *ovly; - int prev; - } mthd; struct { int (*scanoutpos)(NV50_DISP_MTHD_V0); } head; }; int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0); -int nv50_disp_root_mthd(struct nvkm_object *, u32, void *, u32); int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0); @@ -73,59 +68,11 @@ int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1); int nv50_sor_power(NV50_DISP_MTHD_V1); int nv50_pior_power(NV50_DISP_MTHD_V1); -extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs; -int nv50_disp_core_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs; -int nv50_disp_base_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs; -int nv50_disp_ovly_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs; -int nv50_disp_oimm_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs; -int nv50_disp_curs_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -extern struct nvkm_ofuncs nv50_disp_root_ofuncs; -int nv50_disp_root_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_disp_root_dtor(struct nvkm_object *); -extern struct nvkm_oclass nv50_disp_cclass; void nv50_disp_intr_supervisor(struct work_struct *); void nv50_disp_intr(struct nvkm_subdev *); extern const struct nvkm_event_func nv50_disp_vblank_func; -extern struct nv50_disp_chan_impl gf119_disp_core_ofuncs; -extern struct nv50_disp_chan_impl gf119_disp_base_ofuncs; -extern struct nv50_disp_chan_impl gf119_disp_ovly_ofuncs; -extern struct nv50_disp_chan_impl gf119_disp_oimm_ofuncs; -extern struct nv50_disp_chan_impl gf119_disp_curs_ofuncs; -extern struct nvkm_ofuncs gf119_disp_root_ofuncs; -extern struct nvkm_oclass gf119_disp_cclass; void gf119_disp_intr_supervisor(struct work_struct *); void gf119_disp_intr(struct nvkm_subdev *); extern const struct nvkm_event_func gf119_disp_vblank_func; - -extern struct nvkm_output_dp_impl nv50_pior_dp_impl; -extern struct nvkm_oclass *nv50_disp_outp_sclass[]; - -extern struct nvkm_output_dp_impl g94_sor_dp_impl; -u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); -int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); -extern struct nvkm_oclass *g94_disp_outp_sclass[]; - -extern struct nvkm_output_dp_impl gf119_sor_dp_impl; -int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); -extern struct nvkm_oclass *gf119_disp_outp_sclass[]; - -void gm204_sor_magic(struct nvkm_output *outp); -extern struct nvkm_output_dp_impl gm204_sor_dp_impl; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c new file mode 100644 index 0000000000000..54a4ae8d66c6f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmg84.c @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_pioc_oclass +g84_disp_oimm_oclass = { + .base.oclass = G82_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c index fa528051faa5a..c658db54afc51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgf119.c @@ -22,16 +22,16 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "rootnv50.h" -struct nv50_disp_chan_impl -gf119_disp_oimm_ofuncs = { - .base.ctor = nv50_disp_oimm_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = gf119_disp_pioc_init, - .base.fini = gf119_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +#include + +const struct nv50_disp_pioc_oclass +gf119_disp_oimm_oclass = { + .base.oclass = GF110_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &gf119_disp_pioc_func, .chid = 9, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c new file mode 100644 index 0000000000000..b1fde8c125d67 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgk104.c @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_pioc_oclass +gk104_disp_oimm_oclass = { + .base.oclass = GK104_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &gf119_disp_pioc_func, + .chid = 9, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c new file mode 100644 index 0000000000000..f4e7eb3d1177a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmgt215.c @@ -0,0 +1,37 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_pioc_oclass +gt215_disp_oimm_oclass = { + .base.oclass = GT214_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c index 2128b01ae5726..6f31c81fdb018 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "rootnv50.h" #include @@ -29,17 +30,18 @@ #include int -nv50_disp_oimm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) { union { struct nv50_disp_overlay_v0 v0; } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_pioc *pioc; - int ret; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; nvif_ioctl(parent, "create disp overlay size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { @@ -47,27 +49,20 @@ nv50_disp_oimm_ctor(struct nvkm_object *parent, args->v0.version, args->v0.head); if (args->v0.head > disp->head.nr) return -EINVAL; + head = args->v0.head; } else return ret; - ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head, - sizeof(*pioc), (void **)&pioc); - *pobject = nv_object(pioc); - if (ret) - return ret; - - return 0; + return nv50_disp_chan_new_(func, mthd, root, chid + head, + head, oclass, pobject); } -struct nv50_disp_chan_impl -nv50_disp_oimm_ofuncs = { - .base.ctor = nv50_disp_oimm_ctor, - .base.dtor = nv50_disp_pioc_dtor, - .base.init = nv50_disp_pioc_init, - .base.fini = nv50_disp_pioc_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_pioc_oclass +nv50_disp_oimm_oclass = { + .base.oclass = NV50_DISP_OVERLAY, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_oimm_new, + .func = &nv50_disp_pioc_func, .chid = 5, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h index 83d9d3f129f54..2590fec67ca92 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h @@ -27,18 +27,22 @@ struct nvkm_output_func { void nvkm_output_ctor(const struct nvkm_output_func *, struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_output *); -int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, - int index, struct dcb_output *, struct nvkm_output **); +int nvkm_output_new_(const struct nvkm_output_func *, struct nvkm_disp *, + int index, struct dcb_output *, struct nvkm_output **); void nvkm_output_del(struct nvkm_output **); void nvkm_output_init(struct nvkm_output *); void nvkm_output_fini(struct nvkm_output *); -int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, +int nv50_dac_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); -int nv50_sor_output_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); -int nv50_pior_output_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); + +u32 g94_sor_dp_lane_map(struct nvkm_device *, u8 lane); + +void gm204_sor_magic(struct nvkm_output *outp); #define OUTP_MSG(o,l,f,a...) do { \ struct nvkm_output *_outp = (o); \ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h index 18ddf481c3467..731136d660b78 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h @@ -52,14 +52,16 @@ int nvkm_output_dp_new_(const struct nvkm_output_dp_func *, struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_output **); -int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); +int nv50_pior_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); -int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); +int g94_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int); -int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, - struct nvkm_output **); +int gf119_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, + struct nvkm_output **); +int gf119_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool); int gm204_sor_dp_new(struct nvkm_disp *, int, struct dcb_output *, struct nvkm_output **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c index 149e7c4c75fa6..db6234eebc61a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlyg84.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list g84_disp_ovly_mthd_base = { @@ -51,12 +54,24 @@ g84_disp_ovly_mthd_base = { } }; -const struct nv50_disp_mthd_chan -g84_disp_ovly_mthd_chan = { +const struct nv50_disp_chan_mthd +g84_disp_ovly_chan_mthd = { .name = "Overlay", .addr = 0x000540, + .prev = 0x000004, .data = { { "Global", 1, &g84_disp_ovly_mthd_base }, {} } }; + +const struct nv50_disp_dmac_oclass +g84_disp_ovly_oclass = { + .base.oclass = G82_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c index c44c927460bce..5985879abd239 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygf119.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list gf119_disp_ovly_mthd_base = { @@ -75,27 +78,24 @@ gf119_disp_ovly_mthd_base = { } }; -const struct nv50_disp_mthd_chan -gf119_disp_ovly_mthd_chan = { +static const struct nv50_disp_chan_mthd +gf119_disp_ovly_chan_mthd = { .name = "Overlay", .addr = 0x001000, + .prev = -0x020000, .data = { { "Global", 1, &gf119_disp_ovly_mthd_base }, {} } }; -struct nv50_disp_chan_impl -gf119_disp_ovly_ofuncs = { - .base.ctor = nv50_disp_ovly_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = gf119_disp_dmac_init, - .base.fini = gf119_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_dmac_oclass +gf119_disp_ovly_oclass = { + .base.oclass = GF110_DISP_OVERLAY_CONTROL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &gf119_disp_dmac_func, + .mthd = &gf119_disp_ovly_chan_mthd, .chid = 5, - .attach = gf119_disp_dmac_object_attach, - .detach = gf119_disp_dmac_object_detach, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c index 7b83d70b244ae..2e2dc0641ef2b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygk104.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list gk104_disp_ovly_mthd_base = { @@ -77,12 +80,24 @@ gk104_disp_ovly_mthd_base = { } }; -const struct nv50_disp_mthd_chan -gk104_disp_ovly_mthd_chan = { +static const struct nv50_disp_chan_mthd +gk104_disp_ovly_chan_mthd = { .name = "Overlay", .addr = 0x001000, + .prev = -0x020000, .data = { { "Global", 1, &gk104_disp_ovly_mthd_base }, {} } }; + +const struct nv50_disp_dmac_oclass +gk104_disp_ovly_oclass = { + .base.oclass = GK104_DISP_OVERLAY_CONTROL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &gf119_disp_dmac_func, + .mthd = &gk104_disp_ovly_chan_mthd, + .chid = 5, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c index 8299b5e023525..f858053db83da 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt200.c @@ -22,6 +22,9 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" + +#include static const struct nv50_disp_mthd_list gt200_disp_ovly_mthd_base = { @@ -54,12 +57,24 @@ gt200_disp_ovly_mthd_base = { } }; -const struct nv50_disp_mthd_chan -gt200_disp_ovly_mthd_chan = { +static const struct nv50_disp_chan_mthd +gt200_disp_ovly_chan_mthd = { .name = "Overlay", .addr = 0x000540, + .prev = 0x000004, .data = { { "Global", 1, >200_disp_ovly_mthd_base }, {} } }; + +const struct nv50_disp_dmac_oclass +gt200_disp_ovly_oclass = { + .base.oclass = GT200_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = >200_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c new file mode 100644 index 0000000000000..c947e1e16a37b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlygt215.c @@ -0,0 +1,38 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "dmacnv50.h" +#include "rootnv50.h" + +#include + +const struct nv50_disp_dmac_oclass +gt215_disp_ovly_oclass = { + .base.oclass = GT214_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = &g84_disp_ovly_chan_mthd, + .chid = 3, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c index 840e2b0a90a4e..110662c1fe04a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c @@ -22,13 +22,45 @@ * Authors: Ben Skeggs */ #include "dmacnv50.h" +#include "rootnv50.h" #include #include #include -const struct nv50_disp_mthd_list +int +nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_disp_overlay_channel_dma_v0 v0; + } *args = data; + struct nvkm_object *parent = oclass->parent; + struct nv50_disp *disp = root->disp; + int head, ret; + u64 push; + + nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create disp overlay channel dma vers %d " + "pushbuf %016llx head %d\n", + args->v0.version, args->v0.pushbuf, args->v0.head); + if (args->v0.head > disp->head.nr) + return -EINVAL; + push = args->v0.pushbuf; + head = args->v0.head; + } else + return ret; + + return nv50_disp_dmac_new_(func, mthd, root, chid + head, + head, push, oclass, pobject); +} + +static const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base = { .mthd = 0x0000, .addr = 0x000000, @@ -56,60 +88,24 @@ nv50_disp_ovly_mthd_base = { } }; -const struct nv50_disp_mthd_chan -nv50_disp_ovly_mthd_chan = { +static const struct nv50_disp_chan_mthd +nv50_disp_ovly_chan_mthd = { .name = "Overlay", .addr = 0x000540, + .prev = 0x000004, .data = { { "Global", 1, &nv50_disp_ovly_mthd_base }, {} } }; -int -nv50_disp_ovly_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_disp_overlay_channel_dma_v0 v0; - } *args = data; - struct nv50_disp *disp = (void *)engine; - struct nv50_disp_dmac *dmac; - int ret; - - nvif_ioctl(parent, "create disp overlay channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create disp overlay channel dma vers %d " - "pushbuf %016llx head %d\n", - args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->head.nr) - return -EINVAL; - } else - return ret; - - ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf, - args->v0.head, sizeof(*dmac), - (void **)&dmac); - *pobject = nv_object(dmac); - if (ret) - return ret; - - return 0; -} - -struct nv50_disp_chan_impl -nv50_disp_ovly_ofuncs = { - .base.ctor = nv50_disp_ovly_ctor, - .base.dtor = nv50_disp_dmac_dtor, - .base.init = nv50_disp_dmac_init, - .base.fini = nv50_disp_dmac_fini, - .base.ntfy = nv50_disp_chan_ntfy, - .base.map = nv50_disp_chan_map, - .base.rd32 = nv50_disp_chan_rd32, - .base.wr32 = nv50_disp_chan_wr32, +const struct nv50_disp_dmac_oclass +nv50_disp_ovly_oclass = { + .base.oclass = NV50_DISP_OVERLAY_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_disp_ovly_new, + .func = &nv50_disp_dmac_func, + .mthd = &nv50_disp_ovly_chan_mthd, .chid = 3, - .attach = nv50_disp_dmac_object_attach, - .detach = nv50_disp_dmac_object_detach, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c index 08aeb8e4e6dc3..a625a9876e34a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocgf119.c @@ -22,17 +22,17 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "rootnv50.h" #include -int -gf119_disp_pioc_fini(struct nvkm_object *object, bool suspend) +static void +gf119_disp_pioc_fini(struct nv50_disp_chan *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; + struct nv50_disp *disp = chan->root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; + int chid = chan->chid; nvkm_mask(device, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000); if (nvkm_msec(device, 2000, @@ -41,30 +41,20 @@ gf119_disp_pioc_fini(struct nvkm_object *object, bool suspend) ) < 0) { nvkm_error(subdev, "ch %d fini: %08x\n", chid, nvkm_rd32(device, 0x610490 + (chid * 0x10))); - if (suspend) - return -EBUSY; } /* disable error reporting and completion notification */ nvkm_mask(device, 0x610090, 0x00000001 << chid, 0x00000000); nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000000); - - return nv50_disp_chan_fini(&pioc->base, suspend); } -int -gf119_disp_pioc_init(struct nvkm_object *object) +static int +gf119_disp_pioc_init(struct nv50_disp_chan *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; + struct nv50_disp *disp = chan->root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; - int ret; - - ret = nv50_disp_chan_init(&pioc->base); - if (ret) - return ret; + int chid = chan->chid; /* enable error reporting */ nvkm_mask(device, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid); @@ -83,3 +73,9 @@ gf119_disp_pioc_init(struct nvkm_object *object) return 0; } + +const struct nv50_disp_chan_func +gf119_disp_pioc_func = { + .init = gf119_disp_pioc_init, + .fini = gf119_disp_pioc_fini, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c index 13e4711ec0c79..9d2618dacf20b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piocnv50.c @@ -22,17 +22,17 @@ * Authors: Ben Skeggs */ #include "channv50.h" +#include "rootnv50.h" #include -int -nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) +static void +nv50_disp_pioc_fini(struct nv50_disp_chan *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; + struct nv50_disp *disp = chan->root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; + int chid = chan->chid; nvkm_mask(device, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); if (nvkm_msec(device, 2000, @@ -41,26 +41,16 @@ nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend) ) < 0) { nvkm_error(subdev, "ch %d timeout: %08x\n", chid, nvkm_rd32(device, 0x610200 + (chid * 0x10))); - if (suspend) - return -EBUSY; } - - return nv50_disp_chan_fini(&pioc->base, suspend); } -int -nv50_disp_pioc_init(struct nvkm_object *object) +static int +nv50_disp_pioc_init(struct nv50_disp_chan *chan) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_pioc *pioc = (void *)object; + struct nv50_disp *disp = chan->root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; - int chid = pioc->base.chid; - int ret; - - ret = nv50_disp_chan_init(&pioc->base); - if (ret) - return ret; + int chid = chan->chid; nvkm_wr32(device, 0x610200 + (chid * 0x10), 0x00002000); if (nvkm_msec(device, 2000, @@ -86,19 +76,8 @@ nv50_disp_pioc_init(struct nvkm_object *object) return 0; } -void -nv50_disp_pioc_dtor(struct nvkm_object *object) -{ - struct nv50_disp_pioc *pioc = (void *)object; - nv50_disp_chan_destroy(&pioc->base); -} - -int -nv50_disp_pioc_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) -{ - return nv50_disp_chan_create_(parent, engine, oclass, head, - length, pobject); -} +const struct nv50_disp_chan_func +nv50_disp_pioc_func = { + .init = nv50_disp_pioc_init, + .fini = nv50_disp_pioc_fini, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 603526ceaa281..6cd6086ce78bf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -57,5 +57,11 @@ int nvkm_disp_vblank_ctor(struct nvkm_object *, void *data, u32 size, void nvkm_disp_vblank(struct nvkm_disp *, int head); int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); -extern struct nvkm_oclass nv04_disp_sclass[]; +extern const struct nvkm_disp_oclass nv04_disp_root_oclass; + +struct nvkm_disp_oclass { + int (*ctor)(struct nvkm_disp *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c index 128b2d797e6f6..721e4f74d1fce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg84.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -g84_disp_sclass[] = { - { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +g84_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + &g84_disp_core_oclass, + &g84_disp_base_oclass, + &g84_disp_ovly_oclass, + }, + .pioc = { + &g84_disp_oimm_oclass, + &g84_disp_curs_oclass, + }, }; -struct nvkm_oclass -g84_disp_root_oclass[] = { - { G82_DISP, &nv50_disp_root_ofuncs }, - {} +static int +g84_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&g84_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +g84_disp_root_oclass = { + .base.oclass = G82_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = g84_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c index 9b1ef885a2627..9493f6edf62be 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootg94.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -g94_disp_sclass[] = { - { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +g94_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + &g94_disp_core_oclass, + >200_disp_base_oclass, + >200_disp_ovly_oclass, + }, + .pioc = { + &g84_disp_oimm_oclass, + &g84_disp_curs_oclass, + }, }; -struct nvkm_oclass -g94_disp_root_oclass[] = { - { GT206_DISP, &nv50_disp_root_ofuncs }, - {} +static int +g94_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&g94_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +g94_disp_root_oclass = { + .base.oclass = GT206_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = g94_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c index ae55cb21eb339..5868c446b8461 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -65,18 +65,21 @@ gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0) return 0; } -static int -gf119_disp_root_init(struct nvkm_object *object) +void +gf119_disp_root_fini(struct nv50_disp_root *root) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_root *root = (void *)object; + struct nvkm_device *device = root->disp->base.engine.subdev.device; + /* disable all interrupts */ + nvkm_wr32(device, 0x6100b0, 0x00000000); +} + +int +gf119_disp_root_init(struct nv50_disp_root *root) +{ + struct nv50_disp *disp = root->disp; struct nvkm_device *device = disp->base.engine.subdev.device; - int ret, i; u32 tmp; - - ret = nvkm_parent_init(&root->base); - if (ret) - return ret; + int i; /* The below segments of code copying values from one register to * another appear to inform EVO of the display capabilities or @@ -117,7 +120,7 @@ gf119_disp_root_init(struct nvkm_object *object) } /* point at display engine memory area (hash table, objects) */ - nvkm_wr32(device, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); + nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ nvkm_wr32(device, 0x610090, 0x00000000); @@ -136,41 +139,33 @@ gf119_disp_root_init(struct nvkm_object *object) return 0; } -static int -gf119_disp_root_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_root *root = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; - - /* disable all interrupts */ - nvkm_wr32(device, 0x6100b0, 0x00000000); - - return nvkm_parent_fini(&root->base, suspend); -} - -struct nvkm_ofuncs -gf119_disp_root_ofuncs = { - .ctor = nv50_disp_root_ctor, - .dtor = nv50_disp_root_dtor, +static const struct nv50_disp_root_func +gf119_disp_root = { .init = gf119_disp_root_init, .fini = gf119_disp_root_fini, - .mthd = nv50_disp_root_mthd, - .ntfy = nvkm_disp_ntfy, + .dmac = { + &gf119_disp_core_oclass, + &gf119_disp_base_oclass, + &gf119_disp_ovly_oclass, + }, + .pioc = { + &gf119_disp_oimm_oclass, + &gf119_disp_curs_oclass, + }, }; -struct nvkm_oclass -gf119_disp_root_oclass[] = { - { GF110_DISP, &gf119_disp_root_ofuncs }, - {} -}; +static int +gf119_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gf119_disp_root, disp, oclass, + data, size, pobject); +} -struct nvkm_oclass -gf119_disp_sclass[] = { - { GF110_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, - { GF110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, - { GF110_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, - { GF110_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, - { GF110_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, - {} +const struct nvkm_disp_oclass +gf119_disp_root_oclass = { + .base.oclass = GF110_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gf119_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c index f89b33496b1e4..0bfdb1d1c6ab4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk104.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -gk104_disp_sclass[] = { - { GK104_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, - { GK104_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +gk104_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gk104_disp_core_oclass, + &gk104_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, }; -struct nvkm_oclass -gk104_disp_root_oclass[] = { - { GK104_DISP, &gf119_disp_root_ofuncs }, - {} +static int +gk104_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gk104_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gk104_disp_root_oclass = { + .base.oclass = GK104_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gk104_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c index ef2f73a6539d9..1e8dbed8a67c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgk110.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -gk110_disp_sclass[] = { - { GK110_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +gk110_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gk110_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, }; -struct nvkm_oclass -gk110_disp_root_oclass[] = { - { GK110_DISP, &gf119_disp_root_ofuncs }, - {} +static int +gk110_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gk110_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gk110_disp_root_oclass = { + .base.oclass = GK110_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gk110_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c index ba69ee4e0a494..44c55be69e996 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm107.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -gm107_disp_sclass[] = { - { GM107_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +gm107_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gm107_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, }; -struct nvkm_oclass -gm107_disp_root_oclass[] = { - { GM107_DISP, &gf119_disp_root_ofuncs }, - {} +static int +gm107_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gm107_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gm107_disp_root_oclass = { + .base.oclass = GM107_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gm107_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c index 255308f6ec255..168bffe0643cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgm204.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -gm204_disp_sclass[] = { - { GM204_DISP_CORE_CHANNEL_DMA, &gf119_disp_core_ofuncs.base }, - { GK110_DISP_BASE_CHANNEL_DMA, &gf119_disp_base_ofuncs.base }, - { GK104_DISP_OVERLAY_CONTROL_DMA, &gf119_disp_ovly_ofuncs.base }, - { GK104_DISP_OVERLAY, &gf119_disp_oimm_ofuncs.base }, - { GK104_DISP_CURSOR, &gf119_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +gm204_disp_root = { + .init = gf119_disp_root_init, + .fini = gf119_disp_root_fini, + .dmac = { + &gm204_disp_core_oclass, + &gk110_disp_base_oclass, + &gk104_disp_ovly_oclass, + }, + .pioc = { + &gk104_disp_oimm_oclass, + &gk104_disp_curs_oclass, + }, }; -struct nvkm_oclass -gm204_disp_root_oclass[] = { - { GM204_DISP, &gf119_disp_root_ofuncs }, - {} +static int +gm204_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&gm204_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gm204_disp_root_oclass = { + .base.oclass = GM204_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gm204_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c index b1963e531ae12..124a0c24f92cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt200.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -gt200_disp_sclass[] = { - { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +gt200_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + >200_disp_core_oclass, + >200_disp_base_oclass, + >200_disp_ovly_oclass, + }, + .pioc = { + &g84_disp_oimm_oclass, + &g84_disp_curs_oclass, + }, }; -struct nvkm_oclass -gt200_disp_root_oclass[] = { - { GT200_DISP, &nv50_disp_root_ofuncs }, - {} +static int +gt200_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(>200_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gt200_disp_root_oclass = { + .base.oclass = GT200_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gt200_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c index 83b214abb13af..dff52f30668bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgt215.c @@ -26,18 +26,33 @@ #include -struct nvkm_oclass -gt215_disp_sclass[] = { - { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} +static const struct nv50_disp_root_func +gt215_disp_root = { + .init = nv50_disp_root_init, + .fini = nv50_disp_root_fini, + .dmac = { + >215_disp_core_oclass, + >215_disp_base_oclass, + >215_disp_ovly_oclass, + }, + .pioc = { + >215_disp_oimm_oclass, + >215_disp_curs_oclass, + }, }; -struct nvkm_oclass -gt215_disp_root_oclass[] = { - { GT214_DISP, &nv50_disp_root_ofuncs }, - {} +static int +gt215_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(>215_disp_root, disp, oclass, + data, size, pobject); +} + +const struct nvkm_disp_oclass +gt215_disp_root_oclass = { + .base.oclass = GT214_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = gt215_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c index 603ebb6fd541a..2d9b81fb83a22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object); #include "priv.h" #include @@ -28,11 +29,17 @@ #include #include +struct nv04_disp_root { + struct nvkm_object object; + struct nvkm_disp *disp; +}; + static int -nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, +nv04_disp_scanoutpos(struct nv04_disp_root *root, void *data, u32 size, int head) { - struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_device *device = root->disp->engine.subdev.device; + struct nvkm_object *object = &root->object; const u32 hoff = head * 0x2000; union { struct nv04_disp_scanoutpos_v0 v0; @@ -74,10 +81,10 @@ nv04_disp_scanoutpos(struct nvkm_object *object, struct nvkm_disp *disp, static int nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { + struct nv04_disp_root *root = nv04_disp_root(object); union { struct nv04_disp_mthd_v0 v0; } *args = data; - struct nvkm_disp *disp = (void *)object->engine; int head, ret; nvif_ioctl(object, "disp mthd size %d\n", size); @@ -94,7 +101,7 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) switch (mthd) { case NV04_DISP_SCANOUTPOS: - return nv04_disp_scanoutpos(object, disp, data, size, head); + return nv04_disp_scanoutpos(root, data, size, head); default: break; } @@ -102,18 +109,31 @@ nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } -static struct nvkm_ofuncs -nv04_disp_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, +static struct nvkm_object_func +nv04_disp_root = { .mthd = nv04_disp_mthd, .ntfy = nvkm_disp_ntfy, }; -struct nvkm_oclass -nv04_disp_sclass[] = { - { NV04_DISP, &nv04_disp_ofuncs }, - {}, +static int +nv04_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + struct nv04_disp_root *root; + + if (!(root = kzalloc(sizeof(*root), GFP_KERNEL))) + return -ENOMEM; + root->disp = disp; + *pobject = &root->object; + + nvkm_object_ctor(&nv04_disp_root, oclass, &root->object); + return 0; +} + +const struct nvkm_disp_oclass +nv04_disp_root_oclass = { + .base.oclass = NV04_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = nv04_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 83549702bbc13..472357f499ad0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -66,14 +66,15 @@ nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0) } int -nv50_disp_root_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) { - const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); union { struct nv50_disp_mthd_v0 v0; struct nv50_disp_mthd_v1 v1; } *args = data; - struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_root *root = nv50_disp_root(object); + struct nv50_disp *disp = root->disp; + const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); struct nvkm_output *outp = NULL; struct nvkm_output *temp; u16 type, mask = 0; @@ -187,48 +188,127 @@ nv50_disp_root_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } +static int +nv50_disp_root_dmac_new_(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + const struct nv50_disp_dmac_oclass *sclass = oclass->priv; + struct nv50_disp_root *root = nv50_disp_root(oclass->parent); + return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid, + oclass, data, size, pobject); +} + +static int +nv50_disp_root_pioc_new_(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + const struct nv50_disp_pioc_oclass *sclass = oclass->priv; + struct nv50_disp_root *root = nv50_disp_root(oclass->parent); + return sclass->ctor(sclass->func, sclass->mthd, root, sclass->chid, + oclass, data, size, pobject); +} + +static int +nv50_disp_root_child_get_(struct nvkm_object *object, int index, + struct nvkm_oclass *sclass) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + + if (index < ARRAY_SIZE(root->func->dmac)) { + sclass->base = root->func->dmac[index]->base; + sclass->priv = root->func->dmac[index]; + sclass->ctor = nv50_disp_root_dmac_new_; + return 0; + } + + index -= ARRAY_SIZE(root->func->dmac); + + if (index < ARRAY_SIZE(root->func->pioc)) { + sclass->base = root->func->pioc[index]->base; + sclass->priv = root->func->pioc[index]; + sclass->ctor = nv50_disp_root_pioc_new_; + return 0; + } + + return -EINVAL; +} + +static int +nv50_disp_root_fini_(struct nvkm_object *object, bool suspend) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + root->func->fini(root); + return 0; +} + +static int +nv50_disp_root_init_(struct nvkm_object *object) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + return root->func->init(root); +} + +static void * +nv50_disp_root_dtor_(struct nvkm_object *object) +{ + struct nv50_disp_root *root = nv50_disp_root(object); + nvkm_ramht_del(&root->ramht); + nvkm_gpuobj_del(&root->instmem); + return root; +} + +static const struct nvkm_object_func +nv50_disp_root_ = { + .dtor = nv50_disp_root_dtor_, + .init = nv50_disp_root_init_, + .fini = nv50_disp_root_fini_, + .mthd = nv50_disp_root_mthd_, + .ntfy = nvkm_disp_ntfy, + .sclass = nv50_disp_root_child_get_, +}; + int -nv50_disp_root_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_disp_root_new_(const struct nv50_disp_root_func *func, + struct nvkm_disp *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp *disp = (void *)engine; + struct nv50_disp *disp = nv50_disp(base); struct nv50_disp_root *root; struct nvkm_device *device = disp->base.engine.subdev.device; - struct nvkm_gpuobj *instmem = (void *)parent; int ret; - ret = nvkm_parent_create(parent, engine, oclass, 0, - disp->sclass, 0, &root); - *pobject = nv_object(root); + if (!(root = kzalloc(sizeof(*root), GFP_KERNEL))) + return -ENOMEM; + *pobject = &root->object; + + nvkm_object_ctor(&nv50_disp_root_, oclass, &root->object); + root->func = func; + root->disp = disp; + + ret = nvkm_gpuobj_new(disp->base.engine.subdev.device, 0x10000, 0x10000, + false, NULL, &root->instmem); if (ret) return ret; - - return nvkm_ramht_new(device, 0x1000, 0, instmem, &root->ramht); + return nvkm_ramht_new(device, 0x1000, 0, root->instmem, &root->ramht); } void -nv50_disp_root_dtor(struct nvkm_object *object) +nv50_disp_root_fini(struct nv50_disp_root *root) { - struct nv50_disp_root *root = (void *)object; - nvkm_ramht_del(&root->ramht); - nvkm_parent_destroy(&root->base); + struct nvkm_device *device = root->disp->base.engine.subdev.device; + /* disable all interrupts */ + nvkm_wr32(device, 0x610024, 0x00000000); + nvkm_wr32(device, 0x610020, 0x00000000); } -static int -nv50_disp_root_init(struct nvkm_object *object) +int +nv50_disp_root_init(struct nv50_disp_root *root) { - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_root *root = (void *)object; + struct nv50_disp *disp = root->disp; struct nvkm_device *device = disp->base.engine.subdev.device; - int ret, i; u32 tmp; - - ret = nvkm_parent_init(&root->base); - if (ret) - return ret; + int i; /* The below segments of code copying values from one register to * another appear to inform EVO of the display capabilities or @@ -279,7 +359,7 @@ nv50_disp_root_init(struct nvkm_object *object) } /* point at display engine memory area (hash table, objects) */ - nvkm_wr32(device, 0x610010, (root->ramht->gpuobj->addr >> 8) | 9); + nvkm_wr32(device, 0x610010, (root->instmem->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ nvkm_wr32(device, 0x61002c, 0x00000370); @@ -287,42 +367,33 @@ nv50_disp_root_init(struct nvkm_object *object) return 0; } -static int -nv50_disp_root_fini(struct nvkm_object *object, bool suspend) -{ - struct nv50_disp *disp = (void *)object->engine; - struct nv50_disp_root *root = (void *)object; - struct nvkm_device *device = disp->base.engine.subdev.device; - - /* disable all interrupts */ - nvkm_wr32(device, 0x610024, 0x00000000); - nvkm_wr32(device, 0x610020, 0x00000000); - - return nvkm_parent_fini(&root->base, suspend); -} - -struct nvkm_ofuncs -nv50_disp_root_ofuncs = { - .ctor = nv50_disp_root_ctor, - .dtor = nv50_disp_root_dtor, +static const struct nv50_disp_root_func +nv50_disp_root = { .init = nv50_disp_root_init, .fini = nv50_disp_root_fini, - .mthd = nv50_disp_root_mthd, - .ntfy = nvkm_disp_ntfy, + .dmac = { + &nv50_disp_core_oclass, + &nv50_disp_base_oclass, + &nv50_disp_ovly_oclass, + }, + .pioc = { + &nv50_disp_oimm_oclass, + &nv50_disp_curs_oclass, + }, }; -struct nvkm_oclass -nv50_disp_root_oclass[] = { - { NV50_DISP, &nv50_disp_root_ofuncs }, - {} -}; +static int +nv50_disp_root_new(struct nvkm_disp *disp, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nv50_disp_root_new_(&nv50_disp_root, disp, oclass, + data, size, pobject); +} -struct nvkm_oclass -nv50_disp_sclass[] = { - { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base }, - { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base }, - { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base }, - { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base }, - { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base }, - {} +const struct nvkm_disp_oclass +nv50_disp_root_oclass = { + .base.oclass = NV50_DISP, + .base.minver = -1, + .base.maxver = -1, + .ctor = nv50_disp_root_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h index 9ae4bf9270651..5b2c903ce9ee2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.h @@ -1,36 +1,43 @@ #ifndef __NV50_DISP_ROOT_H__ #define __NV50_DISP_ROOT_H__ +#define nv50_disp_root(p) container_of((p), struct nv50_disp_root, object) #include "nv50.h" #include "channv50.h" #include "dmacnv50.h" -#include - -#include struct nv50_disp_root { - struct nvkm_parent base; + const struct nv50_disp_root_func *func; + struct nv50_disp *disp; + struct nvkm_object object; + + struct nvkm_gpuobj *instmem; struct nvkm_ramht *ramht; - u32 chan; }; -extern struct nvkm_oclass nv50_disp_root_oclass[]; -extern struct nvkm_oclass nv50_disp_sclass[]; -extern struct nvkm_oclass g84_disp_root_oclass[]; -extern struct nvkm_oclass g84_disp_sclass[]; -extern struct nvkm_oclass g94_disp_root_oclass[]; -extern struct nvkm_oclass g94_disp_sclass[]; -extern struct nvkm_oclass gt200_disp_root_oclass[]; -extern struct nvkm_oclass gt200_disp_sclass[]; -extern struct nvkm_oclass gt215_disp_root_oclass[]; -extern struct nvkm_oclass gt215_disp_sclass[]; -extern struct nvkm_oclass gf119_disp_root_oclass[]; -extern struct nvkm_oclass gf119_disp_sclass[]; -extern struct nvkm_oclass gk104_disp_root_oclass[]; -extern struct nvkm_oclass gk104_disp_sclass[]; -extern struct nvkm_oclass gk110_disp_root_oclass[]; -extern struct nvkm_oclass gk110_disp_sclass[]; -extern struct nvkm_oclass gm107_disp_root_oclass[]; -extern struct nvkm_oclass gm107_disp_sclass[]; -extern struct nvkm_oclass gm204_disp_root_oclass[]; -extern struct nvkm_oclass gm204_disp_sclass[]; +struct nv50_disp_root_func { + int (*init)(struct nv50_disp_root *); + void (*fini)(struct nv50_disp_root *); + const struct nv50_disp_dmac_oclass *dmac[3]; + const struct nv50_disp_pioc_oclass *pioc[2]; +}; + +int nv50_disp_root_new_(const struct nv50_disp_root_func *, struct nvkm_disp *, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **); +int nv50_disp_root_init(struct nv50_disp_root *); +void nv50_disp_root_fini(struct nv50_disp_root *); + +int gf119_disp_root_init(struct nv50_disp_root *); +void gf119_disp_root_fini(struct nv50_disp_root *); + +extern const struct nvkm_disp_oclass nv50_disp_root_oclass; +extern const struct nvkm_disp_oclass g84_disp_root_oclass; +extern const struct nvkm_disp_oclass g94_disp_root_oclass; +extern const struct nvkm_disp_oclass gt200_disp_root_oclass; +extern const struct nvkm_disp_oclass gt215_disp_root_oclass; +extern const struct nvkm_disp_oclass gf119_disp_root_oclass; +extern const struct nvkm_disp_oclass gk104_disp_root_oclass; +extern const struct nvkm_disp_oclass gk110_disp_root_oclass; +extern const struct nvkm_disp_oclass gm107_disp_root_oclass; +extern const struct nvkm_disp_oclass gm204_disp_root_oclass; #endif -- GitLab From 9a65a38c456ebac97f0498e85fe26f6d26fe3936 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5518/7006] drm/nouveau/fifo: split user classes out from engine implementations Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/fifo.h | 24 - .../gpu/drm/nouveau/nvkm/engine/fifo/Kbuild | 17 + .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 194 ++----- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 162 ++++++ .../gpu/drm/nouveau/nvkm/engine/fifo/chan.h | 28 ++ .../drm/nouveau/nvkm/engine/fifo/chang84.c | 231 +++++++++ .../drm/nouveau/nvkm/engine/fifo/changf100.h | 23 + .../drm/nouveau/nvkm/engine/fifo/changk104.h | 27 + .../drm/nouveau/nvkm/engine/fifo/channv04.h | 24 + .../drm/nouveau/nvkm/engine/fifo/channv50.c | 259 ++++++++++ .../drm/nouveau/nvkm/engine/fifo/channv50.h | 42 ++ .../gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c | 127 +++++ .../drm/nouveau/nvkm/engine/fifo/dmanv04.c | 282 +++++++++++ .../drm/nouveau/nvkm/engine/fifo/dmanv10.c | 102 ++++ .../drm/nouveau/nvkm/engine/fifo/dmanv17.c | 104 ++++ .../drm/nouveau/nvkm/engine/fifo/dmanv40.c | 225 +++++++++ .../drm/nouveau/nvkm/engine/fifo/dmanv50.c | 115 +++++ .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 424 +--------------- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 473 +++-------------- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.h | 26 + .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 403 +-------------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 39 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gm204.c | 9 +- .../drm/nouveau/nvkm/engine/fifo/gpfifog84.c | 122 +++++ .../nouveau/nvkm/engine/fifo/gpfifogf100.c | 304 +++++++++++ .../nouveau/nvkm/engine/fifo/gpfifogk104.c | 357 +++++++++++++ .../nouveau/nvkm/engine/fifo/gpfifogm204.c | 32 ++ .../drm/nouveau/nvkm/engine/fifo/gpfifonv50.c | 110 ++++ .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 329 ++---------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.h | 146 +----- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 92 +--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 138 +---- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 258 +--------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 475 ++---------------- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.h | 30 +- .../gpu/drm/nouveau/nvkm/engine/fifo/priv.h | 8 + .../drm/nouveau/nvkm/engine/fifo/regsnv04.h | 132 +++++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 1 + 45 files changed, 3147 insertions(+), 2754 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index d70fe7f9a44d9..ac97072dcfefd 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -18,30 +18,6 @@ nvkm_fifo_chan(void *obj) return (void *)nv_namedb(obj); } -#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d) \ - nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \ - (m), sizeof(**d), (void **)d) -#define nvkm_fifo_channel_init(p) \ - nvkm_namedb_init(&(p)->namedb) -#define nvkm_fifo_channel_fini(p,s) \ - nvkm_namedb_fini(&(p)->namedb, (s)) - -int nvkm_fifo_channel_create_(struct nvkm_object *, - struct nvkm_object *, - struct nvkm_oclass *, - int bar, u32 addr, u32 size, u64 push, - u64 engmask, int len, void **); -void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *); - -#define _nvkm_fifo_channel_init _nvkm_namedb_init -#define _nvkm_fifo_channel_fini _nvkm_namedb_fini - -void _nvkm_fifo_channel_dtor(struct nvkm_object *); -int _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *); -u32 _nvkm_fifo_channel_rd32(struct nvkm_object *, u64); -void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32); -int _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **); - #include struct nvkm_fifo_base { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index dc81a8b64f359..4525b01598a9e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -11,3 +11,20 @@ nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gk208.o nvkm-y += nvkm/engine/fifo/gm204.o nvkm-y += nvkm/engine/fifo/gm20b.o + +nvkm-y += nvkm/engine/fifo/chan.o +nvkm-y += nvkm/engine/fifo/channv50.o +nvkm-y += nvkm/engine/fifo/chang84.o + +nvkm-y += nvkm/engine/fifo/dmanv04.o +nvkm-y += nvkm/engine/fifo/dmanv10.o +nvkm-y += nvkm/engine/fifo/dmanv17.o +nvkm-y += nvkm/engine/fifo/dmanv40.o +nvkm-y += nvkm/engine/fifo/dmanv50.o +nvkm-y += nvkm/engine/fifo/dmag84.o + +nvkm-y += nvkm/engine/fifo/gpfifonv50.o +nvkm-y += nvkm/engine/fifo/gpfifog84.o +nvkm-y += nvkm/engine/fifo/gpfifogf100.o +nvkm-y += nvkm/engine/fifo/gpfifogk104.o +nvkm-y += nvkm/engine/fifo/gpfifogm204.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 958f290d088e7..510de3c2d2e43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -21,14 +21,12 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" +#include "chan.h" #include -#include #include -#include -#include #include #include @@ -74,138 +72,51 @@ nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) } static int -nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size, - struct nvkm_notify *notify) -{ - if (size == 0) { - notify->size = 0; - notify->types = 1; - notify->index = 0; - return 0; - } - return -ENOSYS; -} - -static const struct nvkm_event_func -nvkm_fifo_event_func = { - .ctor = nvkm_fifo_event_ctor, -}; - -int -nvkm_fifo_channel_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - int bar, u32 addr, u32 size, u64 pushbuf, - u64 engmask, int len, void **ptr) +nvkm_fifo_chid(struct nvkm_fifo *fifo, struct nvkm_object *object) { - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_dmaobj *dmaobj; - struct nvkm_fifo *fifo = (void *)engine; - struct nvkm_fifo_base *base = (void *)parent; - struct nvkm_fifo_chan *chan; - struct nvkm_subdev *subdev = &fifo->engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_dma *dma = device->dma; - unsigned long flags; - int ret; - - /* create base object class */ - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - engmask, len, ptr); - chan = *ptr; - if (ret) - return ret; - - /* validate dma object representing push buffer */ - if (pushbuf) { - dmaobj = nvkm_dma_search(dma, client, pushbuf); - if (!dmaobj) - return -ENOENT; - - ret = dmaobj->func->bind(dmaobj, &base->gpuobj, 16, - &chan->pushgpu); - if (ret) - return ret; - } - - /* find a free fifo channel */ - spin_lock_irqsave(&fifo->lock, flags); - for (chan->chid = fifo->min; chan->chid < fifo->max; chan->chid++) { - if (!fifo->channel[chan->chid]) { - fifo->channel[chan->chid] = nv_object(chan); - break; - } - } - spin_unlock_irqrestore(&fifo->lock, flags); + int engidx = nv_hclass(fifo) & 0xff; - if (chan->chid == fifo->max) { - nvkm_error(subdev, "no free channels\n"); - return -ENOSPC; + while (object && object->parent) { + if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && + (nv_hclass(object->parent) & 0xff) == engidx) + return nvkm_fifo_chan(object)->chid; + object = object->parent; } - chan->addr = nv_device_resource_start(device, bar) + - addr + size * chan->chid; - chan->size = size; - nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); - return 0; + return -1; } -void -nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) +const char * +nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid) { - struct nvkm_fifo *fifo = (void *)nv_object(chan)->engine; + struct nvkm_fifo_chan *chan = NULL; unsigned long flags; - if (chan->user) - iounmap(chan->user); - spin_lock_irqsave(&fifo->lock, flags); - fifo->channel[chan->chid] = NULL; + if (chid >= fifo->min && chid <= fifo->max) + chan = (void *)fifo->channel[chid]; spin_unlock_irqrestore(&fifo->lock, flags); - nvkm_gpuobj_del(&chan->pushgpu); - nvkm_namedb_destroy(&chan->namedb); -} - -void -_nvkm_fifo_channel_dtor(struct nvkm_object *object) -{ - struct nvkm_fifo_chan *chan = (void *)object; - nvkm_fifo_channel_destroy(chan); -} - -int -_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size) -{ - struct nvkm_fifo_chan *chan = (void *)object; - *addr = chan->addr; - *size = chan->size; - return 0; + return nvkm_client_name(chan); } -u32 -_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr) +static int +nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size, + struct nvkm_notify *notify) { - struct nvkm_fifo_chan *chan = (void *)object; - if (unlikely(!chan->user)) { - chan->user = ioremap(chan->addr, chan->size); - if (WARN_ON_ONCE(chan->user == NULL)) - return 0; + if (size == 0) { + notify->size = 0; + notify->types = 1; + notify->index = 0; + return 0; } - return ioread32_native(chan->user + addr); + return -ENOSYS; } -void -_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_fifo_chan *chan = (void *)object; - if (unlikely(!chan->user)) { - chan->user = ioremap(chan->addr, chan->size); - if (WARN_ON_ONCE(chan->user == NULL)) - return; - } - iowrite32_native(data, chan->user + addr); -} +static const struct nvkm_event_func +nvkm_fifo_event_func = { + .ctor = nvkm_fifo_event_ctor, +}; int nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, @@ -233,53 +144,6 @@ nvkm_fifo_uevent(struct nvkm_fifo *fifo) nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); } -int -_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **event) -{ - struct nvkm_fifo *fifo = (void *)object->engine; - switch (type) { - case G82_CHANNEL_DMA_V0_NTFY_UEVENT: - if (nv_mclass(object) >= G82_CHANNEL_DMA) { - *event = &fifo->uevent; - return 0; - } - break; - default: - break; - } - return -EINVAL; -} - -static int -nvkm_fifo_chid(struct nvkm_fifo *fifo, struct nvkm_object *object) -{ - int engidx = nv_hclass(fifo) & 0xff; - - while (object && object->parent) { - if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && - (nv_hclass(object->parent) & 0xff) == engidx) - return nvkm_fifo_chan(object)->chid; - object = object->parent; - } - - return -1; -} - -const char * -nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid) -{ - struct nvkm_fifo_chan *chan = NULL; - unsigned long flags; - - spin_lock_irqsave(&fifo->lock, flags); - if (chid >= fifo->min && chid <= fifo->max) - chan = (void *)fifo->channel[chid]; - spin_unlock_irqrestore(&fifo->lock, flags); - - return nvkm_client_name(chan); -} - void nvkm_fifo_destroy(struct nvkm_fifo *fifo) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c new file mode 100644 index 0000000000000..cc401ae1d6a5d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -0,0 +1,162 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "chan.h" + +#include +#include + +#include + +int +_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type, + struct nvkm_event **event) +{ + struct nvkm_fifo *fifo = (void *)object->engine; + switch (type) { + case G82_CHANNEL_DMA_V0_NTFY_UEVENT: + if (nv_mclass(object) >= G82_CHANNEL_DMA) { + *event = &fifo->uevent; + return 0; + } + break; + default: + break; + } + return -EINVAL; +} + +int +_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nvkm_fifo_chan *chan = (void *)object; + *addr = chan->addr; + *size = chan->size; + return 0; +} + +u32 +_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr) +{ + struct nvkm_fifo_chan *chan = (void *)object; + if (unlikely(!chan->user)) { + chan->user = ioremap(chan->addr, chan->size); + if (WARN_ON_ONCE(chan->user == NULL)) + return 0; + } + return ioread32_native(chan->user + addr); +} + +void +_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nvkm_fifo_chan *chan = (void *)object; + if (unlikely(!chan->user)) { + chan->user = ioremap(chan->addr, chan->size); + if (WARN_ON_ONCE(chan->user == NULL)) + return; + } + iowrite32_native(data, chan->user + addr); +} + +void +nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) +{ + struct nvkm_fifo *fifo = (void *)nv_object(chan)->engine; + unsigned long flags; + + if (chan->user) + iounmap(chan->user); + + spin_lock_irqsave(&fifo->lock, flags); + fifo->channel[chan->chid] = NULL; + spin_unlock_irqrestore(&fifo->lock, flags); + + nvkm_gpuobj_del(&chan->pushgpu); + nvkm_namedb_destroy(&chan->namedb); +} + +void +_nvkm_fifo_channel_dtor(struct nvkm_object *object) +{ + struct nvkm_fifo_chan *chan = (void *)object; + nvkm_fifo_channel_destroy(chan); +} + +int +nvkm_fifo_channel_create_(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, + int bar, u32 addr, u32 size, u64 pushbuf, + u64 engmask, int len, void **ptr) +{ + struct nvkm_client *client = nvkm_client(parent); + struct nvkm_fifo *fifo = (void *)engine; + struct nvkm_fifo_base *base = (void *)parent; + struct nvkm_fifo_chan *chan; + struct nvkm_subdev *subdev = &fifo->engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_dmaobj *dmaobj; + unsigned long flags; + int ret; + + /* create base object class */ + ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, + engmask, len, ptr); + chan = *ptr; + if (ret) + return ret; + + /* validate dma object representing push buffer */ + if (pushbuf) { + dmaobj = nvkm_dma_search(device->dma, client, pushbuf); + if (!dmaobj) + return -ENOENT; + + ret = nvkm_object_bind(&dmaobj->object, &base->gpuobj, 16, + &chan->pushgpu); + if (ret) + return ret; + } + + /* find a free fifo channel */ + spin_lock_irqsave(&fifo->lock, flags); + for (chan->chid = fifo->min; chan->chid < fifo->max; chan->chid++) { + if (!fifo->channel[chan->chid]) { + fifo->channel[chan->chid] = nv_object(chan); + break; + } + } + spin_unlock_irqrestore(&fifo->lock, flags); + + if (chan->chid == fifo->max) { + nvkm_error(subdev, "no free channels\n"); + return -ENOSPC; + } + + chan->addr = nv_device_resource_start(device, bar) + + addr + size * chan->chid; + chan->size = size; + nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h new file mode 100644 index 0000000000000..63209bc8856be --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h @@ -0,0 +1,28 @@ +#ifndef __NVKM_FIFO_CHAN_H__ +#define __NVKM_FIFO_CHAN_H__ +#include "priv.h" + +#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d) \ + nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \ + (m), sizeof(**d), (void **)d) +#define nvkm_fifo_channel_init(p) \ + nvkm_namedb_init(&(p)->namedb) +#define nvkm_fifo_channel_fini(p,s) \ + nvkm_namedb_fini(&(p)->namedb, (s)) + +int nvkm_fifo_channel_create_(struct nvkm_object *, + struct nvkm_object *, + struct nvkm_oclass *, + int bar, u32 addr, u32 size, u64 push, + u64 engmask, int len, void **); +void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *); + +#define _nvkm_fifo_channel_init _nvkm_namedb_init +#define _nvkm_fifo_channel_fini _nvkm_namedb_fini + +void _nvkm_fifo_channel_dtor(struct nvkm_object *); +int _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *); +u32 _nvkm_fifo_channel_rd32(struct nvkm_object *, u64); +void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32); +int _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c new file mode 100644 index 0000000000000..f2b4a96f87940 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c @@ -0,0 +1,231 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include +#include +#include + +int +g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, + struct nvkm_object *object) +{ + struct nv50_fifo *fifo = (void *)parent->engine; + struct nv50_fifo_base *base = (void *)parent->parent; + struct nv50_fifo_chan *chan = (void *)parent; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 addr, save, engn; + bool done; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; + case NVDEV_ENGINE_VP : + case NVDEV_ENGINE_MSPDEC: engn = 3; addr = 0x0040; break; + case NVDEV_ENGINE_MSPPP : + case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; + case NVDEV_ENGINE_BSP : + case NVDEV_ENGINE_MSVLD : engn = 5; addr = 0x0080; break; + case NVDEV_ENGINE_CIPHER: + case NVDEV_ENGINE_SEC : engn = 4; addr = 0x00a0; break; + case NVDEV_ENGINE_CE0 : engn = 2; addr = 0x00c0; break; + default: + return -EINVAL; + } + + save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); + nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); + done = nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ) >= 0; + nvkm_wr32(device, 0x002520, save); + if (!done) { + nvkm_error(subdev, "channel %d [%s] unload timeout\n", + chan->base.chid, nvkm_client_name(chan)); + if (suspend) + return -EBUSY; + } + + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00000000); + nvkm_wo32(base->eng, addr + 0x04, 0x00000000); + nvkm_wo32(base->eng, addr + 0x08, 0x00000000); + nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_done(base->eng); + return 0; +} + + +int +g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) +{ + struct nv50_fifo_base *base = (void *)parent->parent; + struct nvkm_gpuobj *ectx = (void *)object; + u64 limit = ectx->addr + ectx->size - 1; + u64 start = ectx->addr; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0020; break; + case NVDEV_ENGINE_VP : + case NVDEV_ENGINE_MSPDEC: addr = 0x0040; break; + case NVDEV_ENGINE_MSPPP : + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + case NVDEV_ENGINE_BSP : + case NVDEV_ENGINE_MSVLD : addr = 0x0080; break; + case NVDEV_ENGINE_CIPHER: + case NVDEV_ENGINE_SEC : addr = 0x00a0; break; + case NVDEV_ENGINE_CE0 : addr = 0x00c0; break; + default: + return -EINVAL; + } + + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00190000); + nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); + nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_done(base->eng); + return 0; +} + +int +g84_fifo_object_attach(struct nvkm_object *parent, + struct nvkm_object *object, u32 handle) +{ + struct nv50_fifo_chan *chan = (void *)parent; + u32 context; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->node->offset >> 4; + else + context = 0x00000004; /* just non-zero */ + + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : + case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break; + case NVDEV_ENGINE_ME : + case NVDEV_ENGINE_CE0 : context |= 0x00300000; break; + case NVDEV_ENGINE_VP : + case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break; + case NVDEV_ENGINE_CIPHER: + case NVDEV_ENGINE_SEC : + case NVDEV_ENGINE_VIC : context |= 0x00500000; break; + case NVDEV_ENGINE_BSP : + case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break; + default: + return -EINVAL; + } + } + + return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); +} + +int +g84_fifo_chan_init(struct nvkm_object *object) +{ + struct nv50_fifo *fifo = (void *)object->engine; + struct nv50_fifo_base *base = (void *)object->parent; + struct nv50_fifo_chan *chan = (void *)object; + struct nvkm_gpuobj *ramfc = base->ramfc; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + int ret; + + ret = nvkm_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); + nv50_fifo_runlist_update(fifo); + return 0; +} + +static int +g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = nv_engine(engine)->subdev.device; + struct nv50_fifo_base *base; + int ret; + + ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x0200, 0, true, &base->base.gpuobj, + &base->eng); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, + &base->pgd); + if (ret) + return ret; + + ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, &base->base.gpuobj, + &base->cache); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, &base->base.gpuobj, + &base->ramfc); + if (ret) + return ret; + + return 0; +} + +struct nvkm_oclass +g84_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x84), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = g84_fifo_context_ctor, + .dtor = nv50_fifo_context_dtor, + .init = _nvkm_fifo_context_init, + .fini = _nvkm_fifo_context_fini, + .rd32 = _nvkm_fifo_context_rd32, + .wr32 = _nvkm_fifo_context_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h new file mode 100644 index 0000000000000..99324222dadec --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h @@ -0,0 +1,23 @@ +#ifndef __GF100_FIFO_CHAN_H__ +#define __GF100_FIFO_CHAN_H__ +#include "chan.h" +#include "gf100.h" + +struct gf100_fifo_base { + struct nvkm_fifo_base base; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; +}; + +struct gf100_fifo_chan { + struct nvkm_fifo_chan base; + enum { + STOPPED, + RUNNING, + KILLED + } state; +}; + +extern struct nvkm_oclass gf100_fifo_cclass; +extern struct nvkm_oclass gf100_fifo_sclass[]; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h new file mode 100644 index 0000000000000..3490cb6d8bd3e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h @@ -0,0 +1,27 @@ +#ifndef __GK104_FIFO_CHAN_H__ +#define __GK104_FIFO_CHAN_H__ +#include "chan.h" +#include "gk104.h" + +struct gk104_fifo_base { + struct nvkm_fifo_base base; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; +}; + +struct gk104_fifo_chan { + struct nvkm_fifo_chan base; + u32 engine; + enum { + STOPPED, + RUNNING, + KILLED + } state; +}; + +extern struct nvkm_oclass gk104_fifo_cclass; +extern struct nvkm_oclass gk104_fifo_sclass[]; +extern struct nvkm_ofuncs gk104_fifo_chan_ofuncs; + +extern struct nvkm_oclass gm204_fifo_sclass[]; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h new file mode 100644 index 0000000000000..028212df41bcd --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h @@ -0,0 +1,24 @@ +#ifndef __NV04_FIFO_CHAN_H__ +#define __NV04_FIFO_CHAN_H__ +#include "chan.h" +#include "nv04.h" + +struct nv04_fifo_chan { + struct nvkm_fifo_chan base; + u32 subc[8]; + u32 ramfc; +}; + +int nv04_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); +void nv04_fifo_object_detach(struct nvkm_object *, int); + +void nv04_fifo_chan_dtor(struct nvkm_object *); +int nv04_fifo_chan_init(struct nvkm_object *); +int nv04_fifo_chan_fini(struct nvkm_object *, bool suspend); + +extern struct nvkm_oclass nv04_fifo_cclass; +extern struct nvkm_oclass nv04_fifo_sclass[]; +extern struct nvkm_oclass nv10_fifo_sclass[]; +extern struct nvkm_oclass nv17_fifo_sclass[]; +extern struct nvkm_oclass nv40_fifo_sclass[]; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c new file mode 100644 index 0000000000000..aeaba7b9bcae6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c @@ -0,0 +1,259 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include +#include +#include + +int +nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, + struct nvkm_object *object) +{ + struct nv50_fifo *fifo = (void *)parent->engine; + struct nv50_fifo_base *base = (void *)parent->parent; + struct nv50_fifo_chan *chan = (void *)parent; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 addr, me; + int ret = 0; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0000; break; + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + default: + return -EINVAL; + } + + /* HW bug workaround: + * + * PFIFO will hang forever if the connected engines don't report + * that they've processed the context switch request. + * + * In order for the kickoff to work, we need to ensure all the + * connected engines are in a state where they can answer. + * + * Newer chipsets don't seem to suffer from this issue, and well, + * there's also a "ignore these engines" bitmask reg we can use + * if we hit the issue there.. + */ + me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); + + /* do the kickoff... */ + nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) + break; + ) < 0) { + nvkm_error(subdev, "channel %d [%s] unload timeout\n", + chan->base.chid, nvkm_client_name(chan)); + if (suspend) + ret = -EBUSY; + } + nvkm_wr32(device, 0x00b860, me); + + if (ret == 0) { + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00000000); + nvkm_wo32(base->eng, addr + 0x04, 0x00000000); + nvkm_wo32(base->eng, addr + 0x08, 0x00000000); + nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_done(base->eng); + } + + return ret; +} + +int +nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) +{ + struct nv50_fifo_base *base = (void *)parent->parent; + struct nvkm_gpuobj *ectx = (void *)object; + u64 limit = ectx->addr + ectx->size - 1; + u64 start = ectx->addr; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0000; break; + case NVDEV_ENGINE_MPEG : addr = 0x0060; break; + default: + return -EINVAL; + } + + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + + nvkm_kmap(base->eng); + nvkm_wo32(base->eng, addr + 0x00, 0x00190000); + nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); + nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(base->eng, addr + 0x10, 0x00000000); + nvkm_wo32(base->eng, addr + 0x14, 0x00000000); + nvkm_done(base->eng); + return 0; +} + +void +nv50_fifo_object_detach(struct nvkm_object *parent, int cookie) +{ + struct nv50_fifo_chan *chan = (void *)parent; + nvkm_ramht_remove(chan->ramht, cookie); +} + +int +nv50_fifo_object_attach(struct nvkm_object *parent, + struct nvkm_object *object, u32 handle) +{ + struct nv50_fifo_chan *chan = (void *)parent; + u32 context; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->node->offset >> 4; + else + context = 0x00000004; /* just non-zero */ + + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; + default: + return -EINVAL; + } + } + + return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); +} + +int +nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nv50_fifo *fifo = (void *)object->engine; + struct nv50_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + + /* remove channel from runlist, fifo will unload context */ + nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000); + nv50_fifo_runlist_update(fifo); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000); + + return nvkm_fifo_channel_fini(&chan->base, suspend); +} + +int +nv50_fifo_chan_init(struct nvkm_object *object) +{ + struct nv50_fifo *fifo = (void *)object->engine; + struct nv50_fifo_base *base = (void *)object->parent; + struct nv50_fifo_chan *chan = (void *)object; + struct nvkm_gpuobj *ramfc = base->ramfc; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + int ret; + + ret = nvkm_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); + nv50_fifo_runlist_update(fifo); + return 0; +} + +void +nv50_fifo_chan_dtor(struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = (void *)object; + nvkm_ramht_del(&chan->ramht); + nvkm_fifo_channel_destroy(&chan->base); +} + +void +nv50_fifo_context_dtor(struct nvkm_object *object) +{ + struct nv50_fifo_base *base = (void *)object; + nvkm_vm_ref(NULL, &base->vm, base->pgd); + nvkm_gpuobj_del(&base->pgd); + nvkm_gpuobj_del(&base->eng); + nvkm_gpuobj_del(&base->ramfc); + nvkm_gpuobj_del(&base->cache); + nvkm_fifo_context_destroy(&base->base); +} + +static int +nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = nv_engine(engine)->subdev.device; + struct nv50_fifo_base *base; + int ret; + + ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, &base->base.gpuobj, + &base->ramfc); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x1200, 0, true, &base->base.gpuobj, + &base->eng); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, + &base->pgd); + if (ret) + return ret; + + ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; + + return 0; +} + +struct nvkm_oclass +nv50_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x50), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = nv50_fifo_context_ctor, + .dtor = nv50_fifo_context_dtor, + .init = _nvkm_fifo_context_init, + .fini = _nvkm_fifo_context_fini, + .rd32 = _nvkm_fifo_context_rd32, + .wr32 = _nvkm_fifo_context_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h new file mode 100644 index 0000000000000..c4f2f1ff4c9e9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h @@ -0,0 +1,42 @@ +#ifndef __NV50_FIFO_CHAN_H__ +#define __NV50_FIFO_CHAN_H__ +#include "chan.h" +#include "nv50.h" + +struct nv50_fifo_base { + struct nvkm_fifo_base base; + struct nvkm_gpuobj *ramfc; + struct nvkm_gpuobj *cache; + struct nvkm_gpuobj *eng; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; +}; + +struct nv50_fifo_chan { + struct nvkm_fifo_chan base; + u32 subc[8]; + struct nvkm_ramht *ramht; +}; + +extern struct nvkm_oclass nv50_fifo_cclass; +extern struct nvkm_oclass nv50_fifo_sclass[]; +void nv50_fifo_context_dtor(struct nvkm_object *); +void nv50_fifo_chan_dtor(struct nvkm_object *); +int nv50_fifo_chan_init(struct nvkm_object *); +int nv50_fifo_chan_fini(struct nvkm_object *, bool); +int nv50_fifo_context_attach(struct nvkm_object *, struct nvkm_object *); +int nv50_fifo_context_detach(struct nvkm_object *, bool, + struct nvkm_object *); +int nv50_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); +void nv50_fifo_object_detach(struct nvkm_object *, int); +extern struct nvkm_ofuncs nv50_fifo_ofuncs_ind; + +extern struct nvkm_oclass g84_fifo_cclass; +extern struct nvkm_oclass g84_fifo_sclass[]; +int g84_fifo_chan_init(struct nvkm_object *); +int g84_fifo_context_attach(struct nvkm_object *, struct nvkm_object *); +int g84_fifo_context_detach(struct nvkm_object *, bool, + struct nvkm_object *); +int g84_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); +extern struct nvkm_ofuncs g84_fifo_ofuncs_ind; +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c new file mode 100644 index 0000000000000..2016a9884b38c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c @@ -0,0 +1,127 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include +#include + +#include +#include + +static int +g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_channel_dma_v0 v0; + } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; + struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d vm %llx " + "pushbuf %llx offset %016llx\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.offset); + if (args->v0.vm) + return -ENOENT; + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x2000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG) | + (1ULL << NVDEV_ENGINE_ME) | + (1ULL << NVDEV_ENGINE_VP) | + (1ULL << NVDEV_ENGINE_CIPHER) | + (1ULL << NVDEV_ENGINE_SEC) | + (1ULL << NVDEV_ENGINE_BSP) | + (1ULL << NVDEV_ENGINE_MSVLD) | + (1ULL << NVDEV_ENGINE_MSPDEC) | + (1ULL << NVDEV_ENGINE_MSPPP) | + (1ULL << NVDEV_ENGINE_CE0) | + (1ULL << NVDEV_ENGINE_VIC), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.inst = base->base.gpuobj.addr; + args->v0.chid = chan->base.chid; + + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, + &chan->ramht); + if (ret) + return ret; + + nv_parent(chan)->context_attach = g84_fifo_context_attach; + nv_parent(chan)->context_detach = g84_fifo_context_detach; + nv_parent(chan)->object_attach = g84_fifo_object_attach; + nv_parent(chan)->object_detach = nv50_fifo_object_detach; + + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); + nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); + nvkm_done(base->ramfc); + return 0; +} + +static struct nvkm_ofuncs +g84_fifo_ofuncs_dma = { + .ctor = g84_fifo_chan_ctor_dma, + .dtor = nv50_fifo_chan_dtor, + .init = g84_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +g84_fifo_sclass[] = { + { G82_CHANNEL_DMA, &g84_fifo_ofuncs_dma }, + { G82_CHANNEL_GPFIFO, &g84_fifo_ofuncs_ind }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c new file mode 100644 index 0000000000000..8cc87103a369a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c @@ -0,0 +1,282 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv04.h" +#include "regsnv04.h" + +#include +#include +#include + +#include +#include + +int +nv04_fifo_context_attach(struct nvkm_object *parent, + struct nvkm_object *object) +{ + nv_engctx(object)->addr = nvkm_fifo_chan(parent)->chid; + return 0; +} + +void +nv04_fifo_object_detach(struct nvkm_object *parent, int cookie) +{ + struct nv04_fifo *fifo = (void *)parent->engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + mutex_lock(&nv_subdev(fifo)->mutex); + nvkm_ramht_remove(imem->ramht, cookie); + mutex_unlock(&nv_subdev(fifo)->mutex); +} + +int +nv04_fifo_object_attach(struct nvkm_object *parent, + struct nvkm_object *object, u32 handle) +{ + struct nv04_fifo *fifo = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + u32 context, chid = chan->base.chid; + int ret; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->addr >> 4; + else + context = 0x00000004; /* just non-zero */ + + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + context |= 0x00000000; + break; + case NVDEV_ENGINE_GR: + context |= 0x00010000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00020000; + break; + default: + return -EINVAL; + } + } + + context |= 0x80000000; /* valid */ + context |= chid << 24; + + mutex_lock(&nv_subdev(fifo)->mutex); + ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); + mutex_unlock(&nv_subdev(fifo)->mutex); + return ret; +} + +int +nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nv04_fifo *fifo = (void *)object->engine; + struct nv04_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_memory *fctx = device->imem->ramfc; + struct ramfc_desc *c; + unsigned long flags; + u32 data = chan->ramfc; + u32 chid; + + /* prevent fifo context switches */ + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_wr32(device, NV03_PFIFO_CACHES, 0); + + /* if this channel is active, replace it with a null context */ + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; + if (chid == chan->base.chid) { + nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); + nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); + + c = fifo->ramfc_desc; + do { + u32 rm = ((1ULL << c->bits) - 1) << c->regs; + u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; + u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; + u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); + nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); + } while ((++c)->bits); + + c = fifo->ramfc_desc; + do { + nvkm_wr32(device, c->regp, 0x00000000); + } while ((++c)->bits); + + nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); + nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); + } + + /* restore normal operation, after disabling dma mode */ + nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); + nvkm_wr32(device, NV03_PFIFO_CACHES, 1); + spin_unlock_irqrestore(&fifo->base.lock, flags); + + return nvkm_fifo_channel_fini(&chan->base, suspend); +} + +int +nv04_fifo_chan_init(struct nvkm_object *object) +{ + struct nv04_fifo *fifo = (void *)object->engine; + struct nv04_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 mask = 1 << chan->base.chid; + unsigned long flags; + int ret; + + ret = nvkm_fifo_channel_init(&chan->base); + if (ret) + return ret; + + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); + spin_unlock_irqrestore(&fifo->base.lock, flags); + return 0; +} + +void +nv04_fifo_chan_dtor(struct nvkm_object *object) +{ + struct nv04_fifo *fifo = (void *)object->engine; + struct nv04_fifo_chan *chan = (void *)object; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + struct ramfc_desc *c = fifo->ramfc_desc; + + nvkm_kmap(imem->ramfc); + do { + nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); + } while ((++c)->bits); + nvkm_done(imem->ramfc); + + nvkm_fifo_channel_destroy(&chan->base); +} + +static int +nv04_fifo_chan_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + struct nv04_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, + 0x10000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + nv_parent(chan)->object_attach = nv04_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + nv_parent(chan)->context_attach = nv04_fifo_context_attach; + chan->ramfc = chan->base.chid * 32; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(imem->ramfc); + return 0; +} + +static struct nvkm_ofuncs +nv04_fifo_ofuncs = { + .ctor = nv04_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +nv04_fifo_sclass[] = { + { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs }, + {} +}; + +int +nv04_fifo_context_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nv04_fifo_base *base; + int ret; + + ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + return 0; +} + +struct nvkm_oclass +nv04_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0x04), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = nv04_fifo_context_ctor, + .dtor = _nvkm_fifo_context_dtor, + .init = _nvkm_fifo_context_init, + .fini = _nvkm_fifo_context_fini, + .rd32 = _nvkm_fifo_context_rd32, + .wr32 = _nvkm_fifo_context_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c new file mode 100644 index 0000000000000..a542515e63f0b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c @@ -0,0 +1,102 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv04.h" +#include "regsnv04.h" + +#include +#include + +#include +#include + +static int +nv10_fifo_chan_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + struct nv04_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, + 0x10000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + nv_parent(chan)->object_attach = nv04_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + nv_parent(chan)->context_attach = nv04_fifo_context_attach; + chan->ramfc = chan->base.chid * 32; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(imem->ramfc); + return 0; +} + +static struct nvkm_ofuncs +nv10_fifo_ofuncs = { + .ctor = nv10_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +nv10_fifo_sclass[] = { + { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c new file mode 100644 index 0000000000000..d0ece53a750b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c @@ -0,0 +1,104 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv04.h" +#include "regsnv04.h" + +#include +#include + +#include +#include + +static int +nv17_fifo_chan_ctor(struct nvkm_object *parent, + struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + struct nv04_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, + 0x10000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */ + &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + nv_parent(chan)->object_attach = nv04_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + nv_parent(chan)->context_attach = nv04_fifo_context_attach; + chan->ramfc = chan->base.chid * 64; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_done(imem->ramfc); + return 0; +} + +static struct nvkm_ofuncs +nv17_fifo_ofuncs = { + .ctor = nv17_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +nv17_fifo_sclass[] = { + { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c new file mode 100644 index 0000000000000..cd3503cb6837e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c @@ -0,0 +1,225 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv04.h" +#include "regsnv04.h" + +#include +#include +#include + +#include +#include + +static int +nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, + struct nvkm_object *engctx) +{ + struct nv04_fifo *fifo = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + unsigned long flags; + u32 reg, ctx; + + switch (nv_engidx(engctx->engine)) { + case NVDEV_ENGINE_SW: + return 0; + case NVDEV_ENGINE_GR: + reg = 0x32e0; + ctx = 0x38; + break; + case NVDEV_ENGINE_MPEG: + reg = 0x330c; + ctx = 0x54; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&fifo->base.lock, flags); + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); + + if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) + nvkm_wr32(device, reg, 0x00000000); + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000); + nvkm_done(imem->ramfc); + + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&fifo->base.lock, flags); + return 0; +} + +static int +nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) +{ + struct nv04_fifo *fifo = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; + unsigned long flags; + u32 reg, ctx; + + switch (nv_engidx(engctx->engine)) { + case NVDEV_ENGINE_SW: + return 0; + case NVDEV_ENGINE_GR: + reg = 0x32e0; + ctx = 0x38; + break; + case NVDEV_ENGINE_MPEG: + reg = 0x330c; + ctx = 0x54; + break; + default: + return -EINVAL; + } + + spin_lock_irqsave(&fifo->base.lock, flags); + nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; + nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); + + if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) + nvkm_wr32(device, reg, nv_engctx(engctx)->addr); + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + nvkm_done(imem->ramfc); + + nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&fifo->base.lock, flags); + return 0; +} + +static int +nv40_fifo_object_attach(struct nvkm_object *parent, + struct nvkm_object *object, u32 handle) +{ + struct nv04_fifo *fifo = (void *)parent->engine; + struct nv04_fifo_chan *chan = (void *)parent; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + u32 context, chid = chan->base.chid; + int ret; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) + context = nv_gpuobj(object)->addr >> 4; + else + context = 0x00000004; /* just non-zero */ + + if (object->engine) { + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + context |= 0x00000000; + break; + case NVDEV_ENGINE_GR: + context |= 0x00100000; + break; + case NVDEV_ENGINE_MPEG: + context |= 0x00200000; + break; + default: + return -EINVAL; + } + } + + context |= chid << 23; + + mutex_lock(&nv_subdev(fifo)->mutex); + ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); + mutex_unlock(&nv_subdev(fifo)->mutex); + return ret; +} + +static int +nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv03_channel_dma_v0 v0; + } *args = data; + struct nv04_fifo *fifo = (void *)engine; + struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; + struct nv04_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " + "offset %08x\n", args->v0.version, + args->v0.pushbuf, args->v0.offset); + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x1000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + args->v0.chid = chan->base.chid; + + nv_parent(chan)->context_attach = nv40_fifo_context_attach; + nv_parent(chan)->context_detach = nv40_fifo_context_detach; + nv_parent(chan)->object_attach = nv40_fifo_object_attach; + nv_parent(chan)->object_detach = nv04_fifo_object_detach; + chan->ramfc = chan->base.chid * 128; + + nvkm_kmap(imem->ramfc); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | + NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | + NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | +#ifdef __BIG_ENDIAN + NV_PFIFO_CACHE1_BIG_ENDIAN | +#endif + NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff); + nvkm_done(imem->ramfc); + return 0; +} + +static struct nvkm_ofuncs +nv40_fifo_ofuncs = { + .ctor = nv40_fifo_chan_ctor, + .dtor = nv04_fifo_chan_dtor, + .init = nv04_fifo_chan_init, + .fini = nv04_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +nv40_fifo_sclass[] = { + { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c new file mode 100644 index 0000000000000..11a2830992358 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c @@ -0,0 +1,115 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include +#include + +#include +#include + +static int +nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_channel_dma_v0 v0; + } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; + struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo_chan *chan; + int ret; + + nvif_ioctl(parent, "create channel dma size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel dma vers %d vm %llx " + "pushbuf %llx offset %016llx\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.offset); + if (args->v0.vm) + return -ENOENT; + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x2000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.inst = base->base.gpuobj.addr; + args->v0.chid = chan->base.chid; + + nv_parent(chan)->context_attach = nv50_fifo_context_attach; + nv_parent(chan)->context_detach = nv50_fifo_context_detach; + nv_parent(chan)->object_attach = nv50_fifo_object_attach; + nv_parent(chan)->object_detach = nv50_fifo_object_detach; + + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, + &chan->ramht); + if (ret) + return ret; + + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_done(base->ramfc); + return 0; +} + +static struct nvkm_ofuncs +nv50_fifo_ofuncs_dma = { + .ctor = nv50_fifo_chan_ctor_dma, + .dtor = nv50_fifo_chan_dtor, + .init = nv50_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +nv50_fifo_sclass[] = { + { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma }, + { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index c2ce3fa31f10a..ab0ecc423e684 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -22,432 +22,22 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "nv04.h" - -#include -#include -#include -#include -#include - -#include -#include - -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) -{ - struct nv50_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *ectx = (void *)object; - u64 limit = ectx->addr + ectx->size - 1; - u64 start = ectx->addr; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0020; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: addr = 0x0040; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : addr = 0x0080; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : addr = 0x00a0; break; - case NVDEV_ENGINE_CE0 : addr = 0x00c0; break; - default: - return -EINVAL; - } - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00190000); - nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); - return 0; -} - -static int -g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) -{ - struct nv50_fifo *fifo = (void *)parent->engine; - struct nv50_fifo_base *base = (void *)parent->parent; - struct nv50_fifo_chan *chan = (void *)parent; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 addr, save, engn; - bool done; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: engn = 3; addr = 0x0040; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : engn = 5; addr = 0x0080; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : engn = 4; addr = 0x00a0; break; - case NVDEV_ENGINE_CE0 : engn = 2; addr = 0x00c0; break; - default: - return -EINVAL; - } - - save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); - nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); - done = nvkm_msec(device, 2000, - if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) - break; - ) >= 0; - nvkm_wr32(device, 0x002520, save); - if (!done) { - nvkm_error(subdev, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - return -EBUSY; - } - - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00000000); - nvkm_wo32(base->eng, addr + 0x04, 0x00000000); - nvkm_wo32(base->eng, addr + 0x08, 0x00000000); - nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); - return 0; -} - -static int -g84_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv50_fifo_chan *chan = (void *)parent; - u32 context; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->node->offset >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break; - case NVDEV_ENGINE_ME : - case NVDEV_ENGINE_CE0 : context |= 0x00300000; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : - case NVDEV_ENGINE_VIC : context |= 0x00500000; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break; - default: - return -EINVAL; - } - } - - return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); -} - -static int -g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_channel_dma_v0 v0; - } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - int ret; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - if (args->v0.vm) - return -ENOENT; - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_VP) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_VIC), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); - if (ret) - return ret; - - nv_parent(chan)->context_attach = g84_fifo_context_attach; - nv_parent(chan)->context_detach = g84_fifo_context_detach; - nv_parent(chan)->object_attach = g84_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - nvkm_done(base->ramfc); - return 0; -} - -static int -g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_channel_gpfifo_v0 v0; - } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - u64 ioffset, ilength; - int ret; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); - if (args->v0.vm) - return -ENOENT; - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_VP) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_VIC), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); - if (ret) - return ret; - - nv_parent(chan)->context_attach = g84_fifo_context_attach; - nv_parent(chan)->context_detach = g84_fifo_context_detach; - nv_parent(chan)->object_attach = g84_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - nvkm_done(base->ramfc); - return 0; -} - -static int -g84_fifo_chan_init(struct nvkm_object *object) -{ - struct nv50_fifo *fifo = (void *)object->engine; - struct nv50_fifo_base *base = (void *)object->parent; - struct nv50_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *ramfc = base->ramfc; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); - nv50_fifo_playlist_update(fifo); - return 0; -} - -static struct nvkm_ofuncs -g84_fifo_ofuncs_dma = { - .ctor = g84_fifo_chan_ctor_dma, - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_ofuncs -g84_fifo_ofuncs_ind = { - .ctor = g84_fifo_chan_ctor_ind, - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -g84_fifo_sclass[] = { - { G82_CHANNEL_DMA, &g84_fifo_ofuncs_dma }, - { G82_CHANNEL_GPFIFO, &g84_fifo_ofuncs_ind }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static int -g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct nv50_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x0200, 0, true, &base->base.gpuobj, - &base->eng); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, - &base->pgd); - if (ret) - return ret; - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, &base->base.gpuobj, - &base->cache); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, &base->base.gpuobj, - &base->ramfc); - if (ret) - return ret; - - return 0; -} - -static struct nvkm_oclass -g84_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_fifo_context_ctor, - .dtor = nv50_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ +#include "channv50.h" static void -g84_fifo_uevent_init(struct nvkm_event *event, int type, int index) +g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x40000000, 0x40000000); + nvkm_mask(device, 0x002140, 0x40000000, 0x00000000); } static void -g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +g84_fifo_uevent_init(struct nvkm_event *event, int type, int index) { struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x40000000, 0x00000000); + nvkm_mask(device, 0x002140, 0x40000000, 0x40000000); } static const struct nvkm_event_func @@ -472,12 +62,12 @@ g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->playlist[0]); + false, &fifo->runlist[0]); if (ret) return ret; ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->playlist[1]); + false, &fifo->runlist[1]); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 7f05985ebb377..b88e7c569c0a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -21,61 +21,41 @@ * * Authors: Ben Skeggs */ -#include +#include "gf100.h" +#include "changf100.h" #include -#include #include #include #include -#include -#include -#include #include #include -#include -#include - -struct gf100_fifo { - struct nvkm_fifo base; - - struct work_struct fault; - u64 mask; - - struct { - struct nvkm_memory *mem[2]; - int active; - wait_queue_head_t wait; - } runlist; - - struct { - struct nvkm_memory *mem; - struct nvkm_vma bar; - } user; - int spoon_nr; -}; -struct gf100_fifo_base { - struct nvkm_fifo_base base; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; +static void +gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); +} -struct gf100_fifo_chan { - struct nvkm_fifo_chan base; - enum { - STOPPED, - RUNNING, - KILLED - } state; -}; +static void +gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); +} -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ +static const struct nvkm_event_func +gf100_fifo_uevent_func = { + .ctor = nvkm_fifo_uevent_ctor, + .init = gf100_fifo_uevent_init, + .fini = gf100_fifo_uevent_fini, +}; -static void +void gf100_fifo_runlist_update(struct gf100_fifo *fifo) { struct nvkm_subdev *subdev = &fifo->base.engine.subdev; @@ -108,289 +88,6 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) mutex_unlock(&nv_subdev(fifo)->mutex); } -static int -gf100_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) -{ - struct gf100_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - struct nvkm_engctx *ectx = (void *)object; - u32 addr; - int ret; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_CE0 : addr = 0x0230; break; - case NVDEV_ENGINE_CE1 : addr = 0x0240; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - if (!ectx->vma.node) { - ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); - if (ret) - return ret; - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - } - - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); - nvkm_done(engn); - return 0; -} - -static int -gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) -{ - struct gf100_fifo *fifo = (void *)parent->engine; - struct gf100_fifo_base *base = (void *)parent->parent; - struct gf100_fifo_chan *chan = (void *)parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_CE0 : addr = 0x0230; break; - case NVDEV_ENGINE_CE1 : addr = 0x0240; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - nvkm_wr32(device, 0x002634, chan->base.chid); - if (nvkm_msec(device, 2000, - if (nvkm_rd32(device, 0x002634) == chan->base.chid) - break; - ) < 0) { - nvkm_error(subdev, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - return -EBUSY; - } - - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, 0x00000000); - nvkm_wo32(engn, addr + 0x04, 0x00000000); - nvkm_done(engn); - return 0; -} - -static int -gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct fermi_channel_gpfifo_v0 v0; - } *args = data; - struct gf100_fifo *fifo = (void *)engine; - struct gf100_fifo_base *base = (void *)parent; - struct gf100_fifo_chan *chan; - struct nvkm_gpuobj *ramfc = &base->base.gpuobj; - u64 usermem, ioffset, ilength; - int ret, i; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.ioffset, - args->v0.ilength); - if (args->v0.vm) - return -ENOENT; - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - fifo->user.bar.offset, 0x1000, 0, - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_CE1) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = gf100_fifo_context_attach; - nv_parent(chan)->context_detach = gf100_fifo_context_detach; - - usermem = chan->base.chid * 0x1000; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(fifo->user.mem); - for (i = 0; i < 0x1000; i += 4) - nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); - nvkm_done(fifo->user.mem); - usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - - nvkm_kmap(ramfc); - nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); - nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); - nvkm_wo32(ramfc, 0x10, 0x0000face); - nvkm_wo32(ramfc, 0x30, 0xfffff902); - nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); - nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(ramfc, 0x54, 0x00000002); - nvkm_wo32(ramfc, 0x84, 0x20400000); - nvkm_wo32(ramfc, 0x94, 0x30000001); - nvkm_wo32(ramfc, 0x9c, 0x00000100); - nvkm_wo32(ramfc, 0xa4, 0x1f1f1f1f); - nvkm_wo32(ramfc, 0xa8, 0x1f1f1f1f); - nvkm_wo32(ramfc, 0xac, 0x0000001f); - nvkm_wo32(ramfc, 0xb8, 0xf8000000); - nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ - nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ - nvkm_done(ramfc); - return 0; -} - -static int -gf100_fifo_chan_init(struct nvkm_object *object) -{ - struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gf100_fifo *fifo = (void *)object->engine; - struct gf100_fifo_chan *chan = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nvkm_wr32(device, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); - - if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nvkm_wr32(device, 0x003004 + (chid * 8), 0x001f0001); - gf100_fifo_runlist_update(fifo); - } - - return 0; -} - -static void gf100_fifo_intr_engine(struct gf100_fifo *fifo); - -static int -gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct gf100_fifo *fifo = (void *)object->engine; - struct gf100_fifo_chan *chan = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - - if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nvkm_mask(device, 0x003004 + (chid * 8), 0x00000001, 0x00000000); - gf100_fifo_runlist_update(fifo); - } - - gf100_fifo_intr_engine(fifo); - - nvkm_wr32(device, 0x003000 + (chid * 8), 0x00000000); - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -static struct nvkm_ofuncs -gf100_fifo_ofuncs = { - .ctor = gf100_fifo_chan_ctor, - .dtor = _nvkm_fifo_channel_dtor, - .init = gf100_fifo_chan_init, - .fini = gf100_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -gf100_fifo_sclass[] = { - { FERMI_CHANNEL_GPFIFO, &gf100_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - instmem heap and vm setup - ******************************************************************************/ - -static int -gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct gf100_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); - if (ret) - return ret; - - nvkm_kmap(&base->base.gpuobj); - nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); - nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); - nvkm_done(&base->base.gpuobj); - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - - return 0; -} - -static void -gf100_fifo_context_dtor(struct nvkm_object *object) -{ - struct gf100_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_del(&base->pgd); - nvkm_fifo_context_destroy(&base->base); -} - -static struct nvkm_oclass -gf100_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fifo_context_ctor, - .dtor = gf100_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - static inline int gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn) { @@ -739,7 +436,7 @@ gf100_fifo_intr_engine_unit(struct gf100_fifo *fifo, int engn) } } -static void +void gf100_fifo_intr_engine(struct gf100_fifo *fifo) { struct nvkm_device *device = fifo->base.engine.subdev.device; @@ -825,28 +522,62 @@ gf100_fifo_intr(struct nvkm_subdev *subdev) } } -static void -gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index) +static int +gf100_fifo_init(struct nvkm_object *object) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); + struct gf100_fifo *fifo = (void *)object; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int ret, i; + + ret = nvkm_fifo_init(&fifo->base); + if (ret) + return ret; + + nvkm_wr32(device, 0x000204, 0xffffffff); + nvkm_wr32(device, 0x002204, 0xffffffff); + + fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204)); + nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); + + /* assign engines to PBDMAs */ + if (fifo->spoon_nr >= 3) { + nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */ + nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */ + nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */ + nvkm_wr32(device, 0x002214, ~(1 << 1)); /* PMSVLD */ + nvkm_wr32(device, 0x002218, ~(1 << 2)); /* PCE0 */ + nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */ + } + + /* PBDMA[n] */ + for (i = 0; i < fifo->spoon_nr; i++) { + nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); + nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ + nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ + } + + nvkm_mask(device, 0x002200, 0x00000001, 0x00000001); + nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); + + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0x7fffffff); + nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ + return 0; } static void -gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +gf100_fifo_dtor(struct nvkm_object *object) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); -} + struct gf100_fifo *fifo = (void *)object; -static const struct nvkm_event_func -gf100_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = gf100_fifo_uevent_init, - .fini = gf100_fifo_uevent_fini, -}; + nvkm_vm_put(&fifo->user.bar); + nvkm_memory_del(&fifo->user.mem); + nvkm_memory_del(&fifo->runlist.mem[0]); + nvkm_memory_del(&fifo->runlist.mem[1]); + + nvkm_fifo_destroy(&fifo->base); +} static int gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -899,62 +630,6 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -static void -gf100_fifo_dtor(struct nvkm_object *object) -{ - struct gf100_fifo *fifo = (void *)object; - - nvkm_vm_put(&fifo->user.bar); - nvkm_memory_del(&fifo->user.mem); - nvkm_memory_del(&fifo->runlist.mem[0]); - nvkm_memory_del(&fifo->runlist.mem[1]); - - nvkm_fifo_destroy(&fifo->base); -} - -static int -gf100_fifo_init(struct nvkm_object *object) -{ - struct gf100_fifo *fifo = (void *)object; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int ret, i; - - ret = nvkm_fifo_init(&fifo->base); - if (ret) - return ret; - - nvkm_wr32(device, 0x000204, 0xffffffff); - nvkm_wr32(device, 0x002204, 0xffffffff); - - fifo->spoon_nr = hweight32(nvkm_rd32(device, 0x002204)); - nvkm_debug(subdev, "%d PBDMA unit(s)\n", fifo->spoon_nr); - - /* assign engines to PBDMAs */ - if (fifo->spoon_nr >= 3) { - nvkm_wr32(device, 0x002208, ~(1 << 0)); /* PGRAPH */ - nvkm_wr32(device, 0x00220c, ~(1 << 1)); /* PVP */ - nvkm_wr32(device, 0x002210, ~(1 << 1)); /* PMSPP */ - nvkm_wr32(device, 0x002214, ~(1 << 1)); /* PMSVLD */ - nvkm_wr32(device, 0x002218, ~(1 << 2)); /* PCE0 */ - nvkm_wr32(device, 0x00221c, ~(1 << 1)); /* PCE1 */ - } - - /* PBDMA[n] */ - for (i = 0; i < fifo->spoon_nr; i++) { - nvkm_mask(device, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000); - nvkm_wr32(device, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */ - nvkm_wr32(device, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */ - } - - nvkm_mask(device, 0x002200, 0x00000001, 0x00000001); - nvkm_wr32(device, 0x002254, 0x10000000 | fifo->user.bar.offset >> 12); - - nvkm_wr32(device, 0x002100, 0xffffffff); - nvkm_wr32(device, 0x002140, 0x7fffffff); - nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ - return 0; -} struct nvkm_oclass * gf100_fifo_oclass = &(struct nvkm_oclass) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h new file mode 100644 index 0000000000000..5190bbc6e1a18 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h @@ -0,0 +1,26 @@ +#ifndef __GF100_FIFO_H__ +#define __GF100_FIFO_H__ +#include "priv.h" + +struct gf100_fifo { + struct nvkm_fifo base; + + struct work_struct fault; + u64 mask; + + struct { + struct nvkm_memory *mem[2]; + int active; + wait_queue_head_t wait; + } runlist; + + struct { + struct nvkm_memory *mem; + struct nvkm_vma bar; + } user; + int spoon_nr; +}; + +void gf100_fifo_intr_engine(struct gf100_fifo *); +void gf100_fifo_runlist_update(struct gf100_fifo *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index e0badfc54dc80..9ab3fd40b7dd9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -22,20 +22,15 @@ * Authors: Ben Skeggs */ #include "gk104.h" +#include "changk104.h" #include -#include #include #include #include -#include -#include -#include #include #include -#include -#include #define _(a,b) { (a), ((1ULL << (a)) | (b)) } static const struct { @@ -54,47 +49,30 @@ static const struct { #undef _ #define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) -struct gk104_fifo_engn { - struct nvkm_memory *runlist[2]; - int cur_runlist; - wait_queue_head_t wait; -}; - -struct gk104_fifo { - struct nvkm_fifo base; - - struct work_struct fault; - u64 mask; - - struct gk104_fifo_engn engine[FIFO_ENGINE_NR]; - struct { - struct nvkm_memory *mem; - struct nvkm_vma bar; - } user; - int spoon_nr; -}; +static void +gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); +} -struct gk104_fifo_base { - struct nvkm_fifo_base base; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; +static void +gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + struct nvkm_device *device = fifo->engine.subdev.device; + nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); +} -struct gk104_fifo_chan { - struct nvkm_fifo_chan base; - u32 engine; - enum { - STOPPED, - RUNNING, - KILLED - } state; +static const struct nvkm_event_func +gk104_fifo_uevent_func = { + .ctor = nvkm_fifo_uevent_ctor, + .init = gk104_fifo_uevent_init, + .fini = gk104_fifo_uevent_fini, }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static void +void gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { struct gk104_fifo_engn *engn = &fifo->engine[engine]; @@ -128,322 +106,6 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) mutex_unlock(&nv_subdev(fifo)->mutex); } -static int -gk104_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) -{ - struct gk104_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - struct nvkm_engctx *ectx = (void *)object; - u32 addr; - int ret; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : - return 0; - case NVDEV_ENGINE_CE0: - case NVDEV_ENGINE_CE1: - case NVDEV_ENGINE_CE2: - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - if (!ectx->vma.node) { - ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); - if (ret) - return ret; - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - } - - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); - nvkm_done(engn); - return 0; -} - -static int -gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) -{ - struct nvkm_object *obj = (void *)chan; - struct gk104_fifo *fifo = (void *)obj->engine; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - - nvkm_wr32(device, 0x002634, chan->base.chid); - if (nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) - break; - ) < 0) { - nvkm_error(subdev, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); - return -EBUSY; - } - - return 0; -} - -static int -gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) -{ - struct gk104_fifo_base *base = (void *)parent->parent; - struct gk104_fifo_chan *chan = (void *)parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - u32 addr; - int ret; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_CE0 : - case NVDEV_ENGINE_CE1 : - case NVDEV_ENGINE_CE2 : addr = 0x0000; break; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - ret = gk104_fifo_chan_kick(chan); - if (ret && suspend) - return ret; - - if (addr) { - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, 0x00000000); - nvkm_wo32(engn, addr + 0x04, 0x00000000); - nvkm_done(engn); - } - - return 0; -} - -static int -gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct kepler_channel_gpfifo_a_v0 v0; - } *args = data; - struct gk104_fifo *fifo = (void *)engine; - struct gk104_fifo_base *base = (void *)parent; - struct gk104_fifo_chan *chan; - struct nvkm_gpuobj *ramfc = &base->base.gpuobj; - u64 usermem, ioffset, ilength; - u32 engines; - int ret, i; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d " - "ioffset %016llx ilength %08x engine %08x\n", - args->v0.version, args->v0.ioffset, - args->v0.ilength, args->v0.engine); - if (args->v0.vm) - return -ENOENT; - } else - return ret; - - for (i = 0, engines = 0; i < FIFO_ENGINE_NR; i++) { - if (!nvkm_engine(parent, fifo_engine[i].subdev)) - continue; - engines |= (1 << i); - } - - if (!args->v0.engine) { - static struct nvkm_oclass oclass = { - .ofuncs = &nvkm_object_ofuncs, - }; - args->v0.engine = engines; - return nvkm_object_old(parent, engine, &oclass, NULL, 0, pobject); - } - - engines &= args->v0.engine; - if (!engines) { - nvif_ioctl(parent, "unsupported engines %08x\n", - args->v0.engine); - return -ENODEV; - } - i = __ffs(engines); - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - fifo->user.bar.offset, 0x200, 0, - fifo_engine[i].mask, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = gk104_fifo_context_attach; - nv_parent(chan)->context_detach = gk104_fifo_context_detach; - chan->engine = i; - - usermem = chan->base.chid * 0x200; - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(fifo->user.mem); - for (i = 0; i < 0x200; i += 4) - nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); - nvkm_done(fifo->user.mem); - usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - - nvkm_kmap(ramfc); - nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); - nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); - nvkm_wo32(ramfc, 0x10, 0x0000face); - nvkm_wo32(ramfc, 0x30, 0xfffff902); - nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); - nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(ramfc, 0x84, 0x20400000); - nvkm_wo32(ramfc, 0x94, 0x30000001); - nvkm_wo32(ramfc, 0x9c, 0x00000100); - nvkm_wo32(ramfc, 0xac, 0x0000001f); - nvkm_wo32(ramfc, 0xe8, chan->base.chid); - nvkm_wo32(ramfc, 0xb8, 0xf8000000); - nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ - nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ - nvkm_done(ramfc); - return 0; -} - -static int -gk104_fifo_chan_init(struct nvkm_object *object) -{ - struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gk104_fifo *fifo = (void *)object->engine; - struct gk104_fifo_chan *chan = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nvkm_mask(device, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); - nvkm_wr32(device, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); - - if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - gk104_fifo_runlist_update(fifo, chan->engine); - nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); - } - - return 0; -} - -static int -gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct gk104_fifo *fifo = (void *)object->engine; - struct gk104_fifo_chan *chan = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - - if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nvkm_mask(device, 0x800004 + (chid * 8), 0x00000800, 0x00000800); - gk104_fifo_runlist_update(fifo, chan->engine); - } - - nvkm_wr32(device, 0x800000 + (chid * 8), 0x00000000); - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -struct nvkm_ofuncs -gk104_fifo_chan_ofuncs = { - .ctor = gk104_fifo_chan_ctor, - .dtor = _nvkm_fifo_channel_dtor, - .init = gk104_fifo_chan_init, - .fini = gk104_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -gk104_fifo_sclass[] = { - { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - instmem heap and vm setup - ******************************************************************************/ - -static int -gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct gk104_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); - if (ret) - return ret; - - nvkm_kmap(&base->base.gpuobj); - nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); - nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); - nvkm_done(&base->base.gpuobj); - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - - return 0; -} - -static void -gk104_fifo_context_dtor(struct nvkm_object *object) -{ - struct gk104_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_del(&base->pgd); - nvkm_fifo_context_destroy(&base->base); -} - -static struct nvkm_oclass -gk104_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_context_ctor, - .dtor = gk104_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - static inline int gk104_fifo_engidx(struct gk104_fifo *fifo, u32 engn) { @@ -998,29 +660,6 @@ gk104_fifo_intr(struct nvkm_subdev *subdev) } } -static void -gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); -} - -static void -gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index) -{ - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); - struct nvkm_device *device = fifo->engine.subdev.device; - nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); -} - -static const struct nvkm_event_func -gk104_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = gk104_fifo_uevent_init, - .fini = gk104_fifo_uevent_fini, -}; - int gk104_fifo_fini(struct nvkm_object *object, bool suspend) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index b77d75f86b734..b71abef84349b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -1,20 +1,39 @@ -#ifndef __NVKM_FIFO_NVE0_H__ -#define __NVKM_FIFO_NVE0_H__ -#include +#ifndef __GK104_FIFO_H__ +#define __GK104_FIFO_H__ +#include "priv.h" -int gk104_fifo_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gk104_fifo_dtor(struct nvkm_object *); -int gk104_fifo_init(struct nvkm_object *); -int gk104_fifo_fini(struct nvkm_object *, bool); +struct gk104_fifo_engn { + struct nvkm_memory *runlist[2]; + int cur_runlist; + wait_queue_head_t wait; +}; + +struct gk104_fifo { + struct nvkm_fifo base; + + struct work_struct fault; + u64 mask; + + struct gk104_fifo_engn engine[7]; + struct { + struct nvkm_memory *mem; + struct nvkm_vma bar; + } user; + int spoon_nr; +}; struct gk104_fifo_impl { struct nvkm_oclass base; u32 channels; }; -extern struct nvkm_ofuncs gk104_fifo_chan_ofuncs; +int gk104_fifo_ctor(struct nvkm_object *, struct nvkm_object *, + struct nvkm_oclass *, void *, u32, + struct nvkm_object **); +void gk104_fifo_dtor(struct nvkm_object *); +int gk104_fifo_init(struct nvkm_object *); +int gk104_fifo_fini(struct nvkm_object *, bool); +void gk104_fifo_runlist_update(struct gk104_fifo *, u32 engine); int gm204_fifo_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c index 6a93b911e8a8b..2367b4f81a912 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c @@ -22,14 +22,7 @@ * Authors: Ben Skeggs */ #include "gk104.h" - -#include - -static struct nvkm_oclass -gm204_fifo_sclass[] = { - { MAXWELL_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, - {} -}; +#include "changk104.h" int gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c new file mode 100644 index 0000000000000..fd11e0afec256 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c @@ -0,0 +1,122 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include +#include + +#include +#include + +static int +g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; + struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo_chan *chan; + u64 ioffset, ilength; + int ret; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "pushbuf %llx ioffset %016llx " + "ilength %08x\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.ioffset, args->v0.ilength); + if (args->v0.vm) + return -ENOENT; + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x2000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG) | + (1ULL << NVDEV_ENGINE_ME) | + (1ULL << NVDEV_ENGINE_VP) | + (1ULL << NVDEV_ENGINE_CIPHER) | + (1ULL << NVDEV_ENGINE_SEC) | + (1ULL << NVDEV_ENGINE_BSP) | + (1ULL << NVDEV_ENGINE_MSVLD) | + (1ULL << NVDEV_ENGINE_MSPDEC) | + (1ULL << NVDEV_ENGINE_MSPPP) | + (1ULL << NVDEV_ENGINE_CE0) | + (1ULL << NVDEV_ENGINE_VIC), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.inst = base->base.gpuobj.addr; + args->v0.chid = chan->base.chid; + + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, + &chan->ramht); + if (ret) + return ret; + + nv_parent(chan)->context_attach = g84_fifo_context_attach; + nv_parent(chan)->context_detach = g84_fifo_context_detach; + nv_parent(chan)->object_attach = g84_fifo_object_attach; + nv_parent(chan)->object_detach = nv50_fifo_object_detach; + + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); + nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); + nvkm_done(base->ramfc); + return 0; +} + +struct nvkm_ofuncs +g84_fifo_ofuncs_ind = { + .ctor = g84_fifo_chan_ctor_ind, + .dtor = nv50_fifo_chan_dtor, + .init = g84_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c new file mode 100644 index 0000000000000..7fd6401ca905f --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c @@ -0,0 +1,304 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "changf100.h" + +#include +#include +#include + +#include +#include + +static int +gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, + struct nvkm_object *object) +{ + struct gf100_fifo *fifo = (void *)parent->engine; + struct gf100_fifo_base *base = (void *)parent->parent; + struct gf100_fifo_chan *chan = (void *)parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 addr; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + case NVDEV_ENGINE_CE0 : addr = 0x0230; break; + case NVDEV_ENGINE_CE1 : addr = 0x0240; break; + case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; + case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; + case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; + default: + return -EINVAL; + } + + nvkm_wr32(device, 0x002634, chan->base.chid); + if (nvkm_msec(device, 2000, + if (nvkm_rd32(device, 0x002634) == chan->base.chid) + break; + ) < 0) { + nvkm_error(subdev, "channel %d [%s] kick timeout\n", + chan->base.chid, nvkm_client_name(chan)); + if (suspend) + return -EBUSY; + } + + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, 0x00000000); + nvkm_wo32(engn, addr + 0x04, 0x00000000); + nvkm_done(engn); + return 0; +} + +static int +gf100_fifo_context_attach(struct nvkm_object *parent, + struct nvkm_object *object) +{ + struct gf100_fifo_base *base = (void *)parent->parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; + struct nvkm_engctx *ectx = (void *)object; + u32 addr; + int ret; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + case NVDEV_ENGINE_CE0 : addr = 0x0230; break; + case NVDEV_ENGINE_CE1 : addr = 0x0240; break; + case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; + case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; + case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; + default: + return -EINVAL; + } + + if (!ectx->vma.node) { + ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, + NV_MEM_ACCESS_RW, &ectx->vma); + if (ret) + return ret; + + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + } + + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); + nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); + nvkm_done(engn); + return 0; +} + +static int +gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct gf100_fifo *fifo = (void *)object->engine; + struct gf100_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + + if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { + nvkm_mask(device, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + gf100_fifo_runlist_update(fifo); + } + + gf100_fifo_intr_engine(fifo); + + nvkm_wr32(device, 0x003000 + (chid * 8), 0x00000000); + return nvkm_fifo_channel_fini(&chan->base, suspend); +} + +static int +gf100_fifo_chan_init(struct nvkm_object *object) +{ + struct nvkm_gpuobj *base = nv_gpuobj(object->parent); + struct gf100_fifo *fifo = (void *)object->engine; + struct gf100_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + int ret; + + ret = nvkm_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nvkm_wr32(device, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); + + if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { + nvkm_wr32(device, 0x003004 + (chid * 8), 0x001f0001); + gf100_fifo_runlist_update(fifo); + } + + return 0; +} + +static int +gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct fermi_channel_gpfifo_v0 v0; + } *args = data; + struct gf100_fifo *fifo = (void *)engine; + struct gf100_fifo_base *base = (void *)parent; + struct gf100_fifo_chan *chan; + struct nvkm_gpuobj *ramfc = &base->base.gpuobj; + u64 usermem, ioffset, ilength; + int ret, i; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx" + "ioffset %016llx ilength %08x\n", + args->v0.version, args->v0.vm, args->v0.ioffset, + args->v0.ilength); + if (args->v0.vm) + return -ENOENT; + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, + fifo->user.bar.offset, 0x1000, 0, + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_CE0) | + (1ULL << NVDEV_ENGINE_CE1) | + (1ULL << NVDEV_ENGINE_MSVLD) | + (1ULL << NVDEV_ENGINE_MSPDEC) | + (1ULL << NVDEV_ENGINE_MSPPP), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.inst = base->base.gpuobj.addr; + args->v0.chid = chan->base.chid; + + nv_parent(chan)->context_attach = gf100_fifo_context_attach; + nv_parent(chan)->context_detach = gf100_fifo_context_detach; + + usermem = chan->base.chid * 0x1000; + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(fifo->user.mem); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); + nvkm_done(fifo->user.mem); + usermem = nvkm_memory_addr(fifo->user.mem) + usermem; + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); + nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); + nvkm_wo32(ramfc, 0x10, 0x0000face); + nvkm_wo32(ramfc, 0x30, 0xfffff902); + nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(ramfc, 0x54, 0x00000002); + nvkm_wo32(ramfc, 0x84, 0x20400000); + nvkm_wo32(ramfc, 0x94, 0x30000001); + nvkm_wo32(ramfc, 0x9c, 0x00000100); + nvkm_wo32(ramfc, 0xa4, 0x1f1f1f1f); + nvkm_wo32(ramfc, 0xa8, 0x1f1f1f1f); + nvkm_wo32(ramfc, 0xac, 0x0000001f); + nvkm_wo32(ramfc, 0xb8, 0xf8000000); + nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(ramfc); + return 0; +} + +static struct nvkm_ofuncs +gf100_fifo_ofuncs = { + .ctor = gf100_fifo_chan_ctor, + .dtor = _nvkm_fifo_channel_dtor, + .init = gf100_fifo_chan_init, + .fini = gf100_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +gf100_fifo_sclass[] = { + { FERMI_CHANNEL_GPFIFO, &gf100_fifo_ofuncs }, + {} +}; + +static int +gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = nv_engine(engine)->subdev.device; + struct gf100_fifo_base *base; + int ret; + + ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC | + NVOBJ_FLAG_HEAP, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); + if (ret) + return ret; + + nvkm_kmap(&base->base.gpuobj); + nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); + nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); + nvkm_done(&base->base.gpuobj); + + ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; + + return 0; +} + +static void +gf100_fifo_context_dtor(struct nvkm_object *object) +{ + struct gf100_fifo_base *base = (void *)object; + nvkm_vm_ref(NULL, &base->vm, base->pgd); + nvkm_gpuobj_del(&base->pgd); + nvkm_fifo_context_destroy(&base->base); +} + +struct nvkm_oclass +gf100_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0xc0), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = gf100_fifo_context_ctor, + .dtor = gf100_fifo_context_dtor, + .init = _nvkm_fifo_context_init, + .fini = _nvkm_fifo_context_fini, + .rd32 = _nvkm_fifo_context_rd32, + .wr32 = _nvkm_fifo_context_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c new file mode 100644 index 0000000000000..264c9705bccc5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -0,0 +1,357 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "changk104.h" + +#include +#include +#include +#include + +#include +#include + +#define _(a,b) { (a), ((1ULL << (a)) | (b)) } +static const struct { + u64 subdev; + u64 mask; +} fifo_engine[] = { + _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_CE2)), + _(NVDEV_ENGINE_MSPDEC , 0), + _(NVDEV_ENGINE_MSPPP , 0), + _(NVDEV_ENGINE_MSVLD , 0), + _(NVDEV_ENGINE_CE0 , 0), + _(NVDEV_ENGINE_CE1 , 0), + _(NVDEV_ENGINE_MSENC , 0), +}; +#undef _ +#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) + +static int +gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) +{ + struct nvkm_object *obj = (void *)chan; + struct gk104_fifo *fifo = (void *)obj->engine; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + + nvkm_wr32(device, 0x002634, chan->base.chid); + if (nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x002634) & 0x00100000)) + break; + ) < 0) { + nvkm_error(subdev, "channel %d [%s] kick timeout\n", + chan->base.chid, nvkm_client_name(chan)); + return -EBUSY; + } + + return 0; +} + +static int +gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, + struct nvkm_object *object) +{ + struct gk104_fifo_base *base = (void *)parent->parent; + struct gk104_fifo_chan *chan = (void *)parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; + u32 addr; + int ret; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : return 0; + case NVDEV_ENGINE_CE0 : + case NVDEV_ENGINE_CE1 : + case NVDEV_ENGINE_CE2 : addr = 0x0000; break; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; + case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; + case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; + default: + return -EINVAL; + } + + ret = gk104_fifo_chan_kick(chan); + if (ret && suspend) + return ret; + + if (addr) { + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, 0x00000000); + nvkm_wo32(engn, addr + 0x04, 0x00000000); + nvkm_done(engn); + } + + return 0; +} + +static int +gk104_fifo_context_attach(struct nvkm_object *parent, + struct nvkm_object *object) +{ + struct gk104_fifo_base *base = (void *)parent->parent; + struct nvkm_gpuobj *engn = &base->base.gpuobj; + struct nvkm_engctx *ectx = (void *)object; + u32 addr; + int ret; + + switch (nv_engidx(object->engine)) { + case NVDEV_ENGINE_SW : + return 0; + case NVDEV_ENGINE_CE0: + case NVDEV_ENGINE_CE1: + case NVDEV_ENGINE_CE2: + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + return 0; + case NVDEV_ENGINE_GR : addr = 0x0210; break; + case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; + case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; + case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; + default: + return -EINVAL; + } + + if (!ectx->vma.node) { + ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, + NV_MEM_ACCESS_RW, &ectx->vma); + if (ret) + return ret; + + nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + } + + nvkm_kmap(engn); + nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); + nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); + nvkm_done(engn); + return 0; +} + +static int +gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct gk104_fifo *fifo = (void *)object->engine; + struct gk104_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + + if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { + nvkm_mask(device, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + gk104_fifo_runlist_update(fifo, chan->engine); + } + + nvkm_wr32(device, 0x800000 + (chid * 8), 0x00000000); + return nvkm_fifo_channel_fini(&chan->base, suspend); +} + +static int +gk104_fifo_chan_init(struct nvkm_object *object) +{ + struct nvkm_gpuobj *base = nv_gpuobj(object->parent); + struct gk104_fifo *fifo = (void *)object->engine; + struct gk104_fifo_chan *chan = (void *)object; + struct nvkm_device *device = fifo->base.engine.subdev.device; + u32 chid = chan->base.chid; + int ret; + + ret = nvkm_fifo_channel_init(&chan->base); + if (ret) + return ret; + + nvkm_mask(device, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); + nvkm_wr32(device, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); + + if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { + nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + gk104_fifo_runlist_update(fifo, chan->engine); + nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + } + + return 0; +} + +static int +gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct kepler_channel_gpfifo_a_v0 v0; + } *args = data; + struct gk104_fifo *fifo = (void *)engine; + struct gk104_fifo_base *base = (void *)parent; + struct gk104_fifo_chan *chan; + struct nvkm_gpuobj *ramfc = &base->base.gpuobj; + u64 usermem, ioffset, ilength; + u32 engines; + int ret, i; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx" + "ioffset %016llx ilength %08x engine %08x\n", + args->v0.version, args->v0.vm, args->v0.ioffset, + args->v0.ilength, args->v0.engine); + if (args->v0.vm) + return -ENOENT; + } else + return ret; + + for (i = 0, engines = 0; i < FIFO_ENGINE_NR; i++) { + if (!nvkm_engine(parent, fifo_engine[i].subdev)) + continue; + engines |= (1 << i); + } + + if (!args->v0.engine) { + static struct nvkm_oclass oclass = { + .ofuncs = &nvkm_object_ofuncs, + }; + args->v0.engine = engines; + return nvkm_object_old(parent, engine, &oclass, NULL, 0, pobject); + } + + engines &= args->v0.engine; + if (!engines) { + nvif_ioctl(parent, "unsupported engines %08x\n", + args->v0.engine); + return -ENODEV; + } + i = __ffs(engines); + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, + fifo->user.bar.offset, 0x200, 0, + fifo_engine[i].mask, &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.inst = base->base.gpuobj.addr; + args->v0.chid = chan->base.chid; + + nv_parent(chan)->context_attach = gk104_fifo_context_attach; + nv_parent(chan)->context_detach = gk104_fifo_context_detach; + chan->engine = i; + + usermem = chan->base.chid * 0x200; + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(fifo->user.mem); + for (i = 0; i < 0x200; i += 4) + nvkm_wo32(fifo->user.mem, usermem + i, 0x00000000); + nvkm_done(fifo->user.mem); + usermem = nvkm_memory_addr(fifo->user.mem) + usermem; + + nvkm_kmap(ramfc); + nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); + nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); + nvkm_wo32(ramfc, 0x10, 0x0000face); + nvkm_wo32(ramfc, 0x30, 0xfffff902); + nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(ramfc, 0x84, 0x20400000); + nvkm_wo32(ramfc, 0x94, 0x30000001); + nvkm_wo32(ramfc, 0x9c, 0x00000100); + nvkm_wo32(ramfc, 0xac, 0x0000001f); + nvkm_wo32(ramfc, 0xe8, chan->base.chid); + nvkm_wo32(ramfc, 0xb8, 0xf8000000); + nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(ramfc); + return 0; +} + +struct nvkm_ofuncs +gk104_fifo_chan_ofuncs = { + .ctor = gk104_fifo_chan_ctor, + .dtor = _nvkm_fifo_channel_dtor, + .init = gk104_fifo_chan_init, + .fini = gk104_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; + +struct nvkm_oclass +gk104_fifo_sclass[] = { + { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, + {} +}; + +static int +gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_device *device = nv_engine(engine)->subdev.device; + struct gk104_fifo_base *base; + int ret; + + ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, + 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base); + *pobject = nv_object(base); + if (ret) + return ret; + + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); + if (ret) + return ret; + + nvkm_kmap(&base->base.gpuobj); + nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); + nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); + nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); + nvkm_done(&base->base.gpuobj); + + ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + if (ret) + return ret; + + return 0; +} + +static void +gk104_fifo_context_dtor(struct nvkm_object *object) +{ + struct gk104_fifo_base *base = (void *)object; + nvkm_vm_ref(NULL, &base->vm, base->pgd); + nvkm_gpuobj_del(&base->pgd); + nvkm_fifo_context_destroy(&base->base); +} + +struct nvkm_oclass +gk104_fifo_cclass = { + .handle = NV_ENGCTX(FIFO, 0xe0), + .ofuncs = &(struct nvkm_ofuncs) { + .ctor = gk104_fifo_context_ctor, + .dtor = gk104_fifo_context_dtor, + .init = _nvkm_fifo_context_init, + .fini = _nvkm_fifo_context_fini, + .rd32 = _nvkm_fifo_context_rd32, + .wr32 = _nvkm_fifo_context_wr32, + }, +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c new file mode 100644 index 0000000000000..7beee1f8729af --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "changk104.h" + +#include + +struct nvkm_oclass +gm204_fifo_sclass[] = { + { MAXWELL_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, + {} +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c new file mode 100644 index 0000000000000..ca7de9a6d67fb --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c @@ -0,0 +1,110 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "channv50.h" + +#include +#include + +#include +#include + +static int +nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + union { + struct nv50_channel_gpfifo_v0 v0; + } *args = data; + struct nvkm_device *device = parent->engine->subdev.device; + struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo_chan *chan; + u64 ioffset, ilength; + int ret; + + nvif_ioctl(parent, "create channel gpfifo size %d\n", size); + if (nvif_unpack(args->v0, 0, 0, false)) { + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " + "pushbuf %llx ioffset %016llx " + "ilength %08x\n", + args->v0.version, args->v0.vm, args->v0.pushbuf, + args->v0.ioffset, args->v0.ilength); + if (args->v0.vm) + return -ENOENT; + } else + return ret; + + ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, + 0x2000, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG), &chan); + *pobject = nv_object(chan); + if (ret) + return ret; + + chan->base.inst = base->base.gpuobj.addr; + args->v0.chid = chan->base.chid; + + nv_parent(chan)->context_attach = nv50_fifo_context_attach; + nv_parent(chan)->context_detach = nv50_fifo_context_detach; + nv_parent(chan)->object_attach = nv50_fifo_object_attach; + nv_parent(chan)->object_detach = nv50_fifo_object_detach; + + ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, + &chan->ramht); + if (ret) + return ret; + + ioffset = args->v0.ioffset; + ilength = order_base_2(args->v0.ilength / 8); + + nvkm_kmap(base->ramfc); + nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(base->ramfc, 0x44, 0x01003fff); + nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); + nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(base->ramfc, 0x78, 0x00000000); + nvkm_wo32(base->ramfc, 0x7c, 0x30000001); + nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + (4 << 24) /* SEARCH_FULL */ | + (chan->ramht->gpuobj->node->offset >> 4)); + nvkm_done(base->ramfc); + return 0; +} + +struct nvkm_ofuncs +nv50_fifo_ofuncs_ind = { + .ctor = nv50_fifo_chan_ctor_ind, + .dtor = nv50_fifo_chan_dtor, + .init = nv50_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .map = _nvkm_fifo_channel_map, + .rd32 = _nvkm_fifo_channel_rd32, + .wr32 = _nvkm_fifo_channel_wr32, + .ntfy = _nvkm_fifo_channel_ntfy +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index 8bdb71f5f1c54..d880cfa6de9ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -22,18 +22,15 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" -#include -#include #include #include #include #include #include -#include -#include - static struct ramfc_desc nv04_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, @@ -47,268 +44,6 @@ nv04_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -int -nv04_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - u32 context, chid = chan->base.chid; - int ret; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->addr >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00010000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00020000; - break; - default: - return -EINVAL; - } - } - - context |= 0x80000000; /* valid */ - context |= chid << 24; - - mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); - mutex_unlock(&nv_subdev(fifo)->mutex); - return ret; -} - -void -nv04_fifo_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv04_fifo *fifo = (void *)parent->engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - mutex_lock(&nv_subdev(fifo)->mutex); - nvkm_ramht_remove(imem->ramht, cookie); - mutex_unlock(&nv_subdev(fifo)->mutex); -} - -int -nv04_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) -{ - nv_engctx(object)->addr = nvkm_fifo_chan(parent)->chid; - return 0; -} - -static int -nv04_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; - int ret; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; - chan->ramfc = chan->base.chid * 32; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(imem->ramfc); - return 0; -} - -void -nv04_fifo_chan_dtor(struct nvkm_object *object) -{ - struct nv04_fifo *fifo = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct ramfc_desc *c = fifo->ramfc_desc; - - nvkm_kmap(imem->ramfc); - do { - nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); - } while ((++c)->bits); - nvkm_done(imem->ramfc); - - nvkm_fifo_channel_destroy(&chan->base); -} - -int -nv04_fifo_chan_init(struct nvkm_object *object) -{ - struct nv04_fifo *fifo = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 mask = 1 << chan->base.chid; - unsigned long flags; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); - spin_unlock_irqrestore(&fifo->base.lock, flags); - return 0; -} - -int -nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) -{ - struct nv04_fifo *fifo = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_memory *fctx = device->imem->ramfc; - struct ramfc_desc *c; - unsigned long flags; - u32 data = chan->ramfc; - u32 chid; - - /* prevent fifo context switches */ - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_wr32(device, NV03_PFIFO_CACHES, 0); - - /* if this channel is active, replace it with a null context */ - chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; - if (chid == chan->base.chid) { - nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); - nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); - - c = fifo->ramfc_desc; - do { - u32 rm = ((1ULL << c->bits) - 1) << c->regs; - u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; - u32 rv = (nvkm_rd32(device, c->regp) & rm) >> c->regs; - u32 cv = (nvkm_ro32(fctx, c->ctxp + data) & ~cm); - nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); - } while ((++c)->bits); - - c = fifo->ramfc_desc; - do { - nvkm_wr32(device, c->regp, 0x00000000); - } while ((++c)->bits); - - nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); - nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); - } - - /* restore normal operation, after disabling dma mode */ - nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); - nvkm_wr32(device, NV03_PFIFO_CACHES, 1); - spin_unlock_irqrestore(&fifo->base.lock, flags); - - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -static struct nvkm_ofuncs -nv04_fifo_ofuncs = { - .ctor = nv04_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv04_fifo_sclass[] = { - { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -int -nv04_fifo_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - return 0; -} - -static struct nvkm_oclass -nv04_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - void nv04_fifo_pause(struct nvkm_fifo *obj, unsigned long *pflags) __acquires(fifo->base.lock) @@ -552,36 +287,6 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, NV03_PFIFO_CACHES, reassign); } -static int -nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv04_fifo_cclass; - nv_engine(fifo)->sclass = nv04_fifo_sclass; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv04_ramfc; - return 0; -} - -void -nv04_fifo_dtor(struct nvkm_object *object) -{ - struct nv04_fifo *fifo = (void *)object; - nvkm_fifo_destroy(&fifo->base); -} - int nv04_fifo_init(struct nvkm_object *object) { @@ -617,6 +322,36 @@ nv04_fifo_init(struct nvkm_object *object) return 0; } +void +nv04_fifo_dtor(struct nvkm_object *object) +{ + struct nv04_fifo *fifo = (void *)object; + nvkm_fifo_destroy(&fifo->base); +} + +static int +nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nv04_fifo *fifo; + int ret; + + ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &fifo); + *pobject = nv_object(fifo); + if (ret) + return ret; + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv04_fifo_cclass; + nv_engine(fifo)->sclass = nv04_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv04_ramfc; + return 0; +} + struct nvkm_oclass * nv04_fifo_oclass = &(struct nvkm_oclass) { .handle = NV_ENGINE(FIFO, 0x04), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h index c7ce656eca7b9..5cde3310ee4dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h @@ -1,135 +1,6 @@ #ifndef __NV04_FIFO_H__ #define __NV04_FIFO_H__ -#include - -#define NV04_PFIFO_DELAY_0 0x00002040 -#define NV04_PFIFO_DMA_TIMESLICE 0x00002044 -#define NV04_PFIFO_NEXT_CHANNEL 0x00002050 -#define NV03_PFIFO_INTR_0 0x00002100 -#define NV03_PFIFO_INTR_EN_0 0x00002140 -# define NV_PFIFO_INTR_CACHE_ERROR (1<<0) -# define NV_PFIFO_INTR_RUNOUT (1<<4) -# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8) -# define NV_PFIFO_INTR_DMA_PUSHER (1<<12) -# define NV_PFIFO_INTR_DMA_PT (1<<16) -# define NV_PFIFO_INTR_SEMAPHORE (1<<20) -# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24) -#define NV03_PFIFO_RAMHT 0x00002210 -#define NV03_PFIFO_RAMFC 0x00002214 -#define NV03_PFIFO_RAMRO 0x00002218 -#define NV40_PFIFO_RAMFC 0x00002220 -#define NV03_PFIFO_CACHES 0x00002500 -#define NV04_PFIFO_MODE 0x00002504 -#define NV04_PFIFO_DMA 0x00002508 -#define NV04_PFIFO_SIZE 0x0000250c -#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4) -#define NV50_PFIFO_CTX_TABLE__SIZE 128 -#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31) -#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30) -#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF -#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF -#define NV03_PFIFO_CACHE0_PUSH0 0x00003000 -#define NV03_PFIFO_CACHE0_PULL0 0x00003040 -#define NV04_PFIFO_CACHE0_PULL0 0x00003050 -#define NV04_PFIFO_CACHE0_PULL1 0x00003054 -#define NV03_PFIFO_CACHE1_PUSH0 0x00003200 -#define NV03_PFIFO_CACHE1_PUSH1 0x00003204 -#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8) -#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16) -#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f -#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f -#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f -#define NV03_PFIFO_CACHE1_PUT 0x00003210 -#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220 -#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0 -# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000 -# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000 -# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000 -# define NV_PFIFO_CACHE1_ENDIAN 0x80000000 -# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF -# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000 -#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228 -#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c -#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230 -#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240 -#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244 -#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248 -#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C -#define NV03_PFIFO_CACHE1_PULL0 0x00003240 -#define NV04_PFIFO_CACHE1_PULL0 0x00003250 -# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010 -# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000 -#define NV03_PFIFO_CACHE1_PULL1 0x00003250 -#define NV04_PFIFO_CACHE1_PULL1 0x00003254 -#define NV04_PFIFO_CACHE1_HASH 0x00003258 -#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260 -#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264 -#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268 -#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C -#define NV03_PFIFO_CACHE1_GET 0x00003270 -#define NV04_PFIFO_CACHE1_ENGINE 0x00003280 -#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0 -#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0 -#define NV40_PFIFO_UNK32E4 0x000032E4 -#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8)) -#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8)) -#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8)) -#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8)) +#include "priv.h" struct ramfc_desc { unsigned bits:6; @@ -148,25 +19,10 @@ struct nv04_fifo_base { struct nvkm_fifo_base base; }; -struct nv04_fifo_chan { - struct nvkm_fifo_chan base; - u32 subc[8]; - u32 ramfc; -}; - -int nv04_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); -void nv04_fifo_object_detach(struct nvkm_object *, int); - -void nv04_fifo_chan_dtor(struct nvkm_object *); -int nv04_fifo_chan_init(struct nvkm_object *); -int nv04_fifo_chan_fini(struct nvkm_object *, bool suspend); - int nv04_fifo_context_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); void nv04_fifo_dtor(struct nvkm_object *); int nv04_fifo_init(struct nvkm_object *); -void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); -void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index 734c3a7678737..ae0a1b17eb922 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -22,13 +22,8 @@ * Authors: Ben Skeggs */ #include "nv04.h" - -#include -#include -#include - -#include -#include +#include "channv04.h" +#include "regsnv04.h" static struct ramfc_desc nv10_ramfc[] = { @@ -44,85 +39,6 @@ nv10_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -nv10_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; - int ret; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; - chan->ramfc = chan->base.chid * 32; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(imem->ramfc); - return 0; -} - -static struct nvkm_ofuncs -nv10_fifo_ofuncs = { - .ctor = nv10_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv10_fifo_sclass[] = { - { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - static struct nvkm_oclass nv10_fifo_cclass = { .handle = NV_ENGCTX(FIFO, 0x10), @@ -136,10 +52,6 @@ nv10_fifo_cclass = { }, }; -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - static int nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index e27180435bff3..ff2b6d95d8047 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -22,15 +22,12 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" -#include -#include #include #include -#include -#include - static struct ramfc_desc nv17_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, @@ -50,87 +47,6 @@ nv17_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -nv17_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; - int ret; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */ - &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; - chan->ramfc = chan->base.chid * 64; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_done(imem->ramfc); - return 0; -} - -static struct nvkm_ofuncs -nv17_fifo_ofuncs = { - .ctor = nv17_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv17_fifo_sclass[] = { - { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - static struct nvkm_oclass nv17_fifo_cclass = { .handle = NV_ENGCTX(FIFO, 0x17), @@ -144,33 +60,6 @@ nv17_fifo_cclass = { }, }; -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static int -nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv17_fifo_cclass; - nv_engine(fifo)->sclass = nv17_fifo_sclass; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv17_ramfc; - return 0; -} - static int nv17_fifo_init(struct nvkm_object *object) { @@ -207,6 +96,29 @@ nv17_fifo_init(struct nvkm_object *object) return 0; } +static int +nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nv04_fifo *fifo; + int ret; + + ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); + *pobject = nv_object(fifo); + if (ret) + return ret; + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv17_fifo_cclass; + nv_engine(fifo)->sclass = nv17_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv17_ramfc; + return 0; +} + struct nvkm_oclass * nv17_fifo_oclass = &(struct nvkm_oclass) { .handle = NV_ENGINE(FIFO, 0x17), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index f2f0e3d744936..64be69fc95723 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -22,16 +22,13 @@ * Authors: Ben Skeggs */ #include "nv04.h" +#include "channv04.h" +#include "regsnv04.h" -#include -#include #include #include #include -#include -#include - static struct ramfc_desc nv40_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, @@ -59,207 +56,6 @@ nv40_ramfc[] = { {} }; -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ - -static int -nv40_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - u32 context, chid = chan->base.chid; - int ret; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->addr >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00100000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00200000; - break; - default: - return -EINVAL; - } - } - - context |= chid << 23; - - mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); - mutex_unlock(&nv_subdev(fifo)->mutex); - return ret; -} - -static int -nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) -{ - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - unsigned long flags; - u32 reg, ctx; - - switch (nv_engidx(engctx->engine)) { - case NVDEV_ENGINE_SW: - return 0; - case NVDEV_ENGINE_GR: - reg = 0x32e0; - ctx = 0x38; - break; - case NVDEV_ENGINE_MPEG: - reg = 0x330c; - ctx = 0x54; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&fifo->base.lock, flags); - nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; - nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - - if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) - nvkm_wr32(device, reg, nv_engctx(engctx)->addr); - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); - nvkm_done(imem->ramfc); - - nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&fifo->base.lock, flags); - return 0; -} - -static int -nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *engctx) -{ - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - struct nvkm_device *device = fifo->base.engine.subdev.device; - struct nvkm_instmem *imem = device->imem; - unsigned long flags; - u32 reg, ctx; - - switch (nv_engidx(engctx->engine)) { - case NVDEV_ENGINE_SW: - return 0; - case NVDEV_ENGINE_GR: - reg = 0x32e0; - ctx = 0x38; - break; - case NVDEV_ENGINE_MPEG: - reg = 0x330c; - ctx = 0x54; - break; - default: - return -EINVAL; - } - - spin_lock_irqsave(&fifo->base.lock, flags); - nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - - if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) - nvkm_wr32(device, reg, 0x00000000); - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000); - nvkm_done(imem->ramfc); - - nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&fifo->base.lock, flags); - return 0; -} - -static int -nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv03_channel_dma_v0 v0; - } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; - int ret; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %08x\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x1000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv40_fifo_context_attach; - nv_parent(chan)->context_detach = nv40_fifo_context_detach; - nv_parent(chan)->object_attach = nv40_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - chan->ramfc = chan->base.chid * 128; - - nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | - NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | - NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | -#ifdef __BIG_ENDIAN - NV_PFIFO_CACHE1_BIG_ENDIAN | -#endif - NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x3c, 0x0001ffff); - nvkm_done(imem->ramfc); - return 0; -} - -static struct nvkm_ofuncs -nv40_fifo_ofuncs = { - .ctor = nv40_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv40_fifo_sclass[] = { - { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - static struct nvkm_oclass nv40_fifo_cclass = { .handle = NV_ENGCTX(FIFO, 0x40), @@ -273,33 +69,6 @@ nv40_fifo_cclass = { }, }; -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ - -static int -nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv40_fifo_cclass; - nv_engine(fifo)->sclass = nv40_fifo_sclass; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv40_ramfc; - return 0; -} - static int nv40_fifo_init(struct nvkm_object *object) { @@ -357,6 +126,29 @@ nv40_fifo_init(struct nvkm_object *object) return 0; } +static int +nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nv04_fifo *fifo; + int ret; + + ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); + *pobject = nv_object(fifo); + if (ret) + return ret; + + nv_subdev(fifo)->unit = 0x00000100; + nv_subdev(fifo)->intr = nv04_fifo_intr; + nv_engine(fifo)->cclass = &nv40_fifo_cclass; + nv_engine(fifo)->sclass = nv40_fifo_sclass; + fifo->base.pause = nv04_fifo_pause; + fifo->base.start = nv04_fifo_start; + fifo->ramfc_desc = nv40_ramfc; + return 0; +} + struct nvkm_oclass * nv40_fifo_oclass = &(struct nvkm_oclass) { .handle = NV_ENGINE(FIFO, 0x40), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index 23d5ee2fed853..bf17cb0e8385b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -22,30 +22,17 @@ * Authors: Ben Skeggs */ #include "nv50.h" -#include "nv04.h" - -#include -#include -#include -#include -#include - -#include -#include - -/******************************************************************************* - * FIFO channel objects - ******************************************************************************/ +#include "channv50.h" static void -nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) +nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo) { struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_memory *cur; int i, p; - cur = fifo->playlist[fifo->cur_playlist]; - fifo->cur_playlist = !fifo->cur_playlist; + cur = fifo->runlist[fifo->cur_runlist]; + fifo->cur_runlist = !fifo->cur_runlist; nvkm_kmap(cur); for (i = fifo->base.min, p = 0; i < fifo->base.max; i++) { @@ -60,414 +47,52 @@ nv50_fifo_playlist_update_locked(struct nv50_fifo *fifo) } void -nv50_fifo_playlist_update(struct nv50_fifo *fifo) +nv50_fifo_runlist_update(struct nv50_fifo *fifo) { mutex_lock(&nv_subdev(fifo)->mutex); - nv50_fifo_playlist_update_locked(fifo); + nv50_fifo_runlist_update_locked(fifo); mutex_unlock(&nv_subdev(fifo)->mutex); } -static int -nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) -{ - struct nv50_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *ectx = (void *)object; - u64 limit = ectx->addr + ectx->size - 1; - u64 start = ectx->addr; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0000; break; - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - default: - return -EINVAL; - } - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00190000); - nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); - return 0; -} - -static int -nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) -{ - struct nv50_fifo *fifo = (void *)parent->engine; - struct nv50_fifo_base *base = (void *)parent->parent; - struct nv50_fifo_chan *chan = (void *)parent; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 addr, me; - int ret = 0; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0000; break; - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - default: - return -EINVAL; - } - - /* HW bug workaround: - * - * PFIFO will hang forever if the connected engines don't report - * that they've processed the context switch request. - * - * In order for the kickoff to work, we need to ensure all the - * connected engines are in a state where they can answer. - * - * Newer chipsets don't seem to suffer from this issue, and well, - * there's also a "ignore these engines" bitmask reg we can use - * if we hit the issue there.. - */ - me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); - - /* do the kickoff... */ - nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); - if (nvkm_msec(device, 2000, - if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) - break; - ) < 0) { - nvkm_error(subdev, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); - if (suspend) - ret = -EBUSY; - } - nvkm_wr32(device, 0x00b860, me); - - if (ret == 0) { - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00000000); - nvkm_wo32(base->eng, addr + 0x04, 0x00000000); - nvkm_wo32(base->eng, addr + 0x08, 0x00000000); - nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); - } - - return ret; -} - -static int -nv50_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) -{ - struct nv50_fifo_chan *chan = (void *)parent; - u32 context; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->node->offset >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; - default: - return -EINVAL; - } - } - - return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); -} - -void -nv50_fifo_object_detach(struct nvkm_object *parent, int cookie) -{ - struct nv50_fifo_chan *chan = (void *)parent; - nvkm_ramht_remove(chan->ramht, cookie); -} - -static int -nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_channel_dma_v0 v0; - } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - int ret; - - nvif_ioctl(parent, "create channel dma size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " - "offset %016llx\n", args->v0.version, - args->v0.pushbuf, args->v0.offset); - if (args->v0.vm) - return -ENOENT; - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv50_fifo_context_attach; - nv_parent(chan)->context_detach = nv50_fifo_context_detach; - nv_parent(chan)->object_attach = nv50_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); - if (ret) - return ret; - - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_done(base->ramfc); - return 0; -} - -static int -nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - union { - struct nv50_channel_gpfifo_v0 v0; - } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; - struct nv50_fifo_chan *chan; - u64 ioffset, ilength; - int ret; - - nvif_ioctl(parent, "create channel gpfifo size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d pushbuf %llx " - "ioffset %016llx ilength %08x\n", - args->v0.version, args->v0.pushbuf, args->v0.ioffset, - args->v0.ilength); - if (args->v0.vm) - return -ENOENT; - } else - return ret; - - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv50_fifo_context_attach; - nv_parent(chan)->context_detach = nv50_fifo_context_detach; - nv_parent(chan)->object_attach = nv50_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); - if (ret) - return ret; - - ioffset = args->v0.ioffset; - ilength = order_base_2(args->v0.ilength / 8); - - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | - (4 << 24) /* SEARCH_FULL */ | - (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_done(base->ramfc); - return 0; -} - -void -nv50_fifo_chan_dtor(struct nvkm_object *object) -{ - struct nv50_fifo_chan *chan = (void *)object; - nvkm_ramht_del(&chan->ramht); - nvkm_fifo_channel_destroy(&chan->base); -} - -static int -nv50_fifo_chan_init(struct nvkm_object *object) -{ - struct nv50_fifo *fifo = (void *)object->engine; - struct nv50_fifo_base *base = (void *)object->parent; - struct nv50_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *ramfc = base->ramfc; - struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - - nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); - nv50_fifo_playlist_update(fifo); - return 0; -} - int -nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) +nv50_fifo_init(struct nvkm_object *object) { - struct nv50_fifo *fifo = (void *)object->engine; - struct nv50_fifo_chan *chan = (void *)object; + struct nv50_fifo *fifo = (void *)object; struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - - /* remove channel from playlist, fifo will unload context */ - nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000); - nv50_fifo_playlist_update(fifo); - nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000); - - return nvkm_fifo_channel_fini(&chan->base, suspend); -} - -static struct nvkm_ofuncs -nv50_fifo_ofuncs_dma = { - .ctor = nv50_fifo_chan_ctor_dma, - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_ofuncs -nv50_fifo_ofuncs_ind = { - .ctor = nv50_fifo_chan_ctor_ind, - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -static struct nvkm_oclass -nv50_fifo_sclass[] = { - { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma }, - { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind }, - {} -}; - -/******************************************************************************* - * FIFO context - basically just the instmem reserved for the channel - ******************************************************************************/ - -static int -nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct nv50_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; + int ret, i; - ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, &base->base.gpuobj, - &base->ramfc); + ret = nvkm_fifo_init(&fifo->base); if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x1200, 0, true, &base->base.gpuobj, - &base->eng); - if (ret) - return ret; + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); + nvkm_wr32(device, 0x00250c, 0x6f3cfc34); + nvkm_wr32(device, 0x002044, 0x01003fff); - ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, - &base->pgd); - if (ret) - return ret; + nvkm_wr32(device, 0x002100, 0xffffffff); + nvkm_wr32(device, 0x002140, 0xbfffffff); - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; + for (i = 0; i < 128; i++) + nvkm_wr32(device, 0x002600 + (i * 4), 0x00000000); + nv50_fifo_runlist_update_locked(fifo); + nvkm_wr32(device, 0x003200, 0x00000001); + nvkm_wr32(device, 0x003250, 0x00000001); + nvkm_wr32(device, 0x002500, 0x00000001); return 0; } void -nv50_fifo_context_dtor(struct nvkm_object *object) +nv50_fifo_dtor(struct nvkm_object *object) { - struct nv50_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_del(&base->pgd); - nvkm_gpuobj_del(&base->eng); - nvkm_gpuobj_del(&base->ramfc); - nvkm_gpuobj_del(&base->cache); - nvkm_fifo_context_destroy(&base->base); -} + struct nv50_fifo *fifo = (void *)object; -static struct nvkm_oclass -nv50_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fifo_context_ctor, - .dtor = nv50_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; + nvkm_memory_del(&fifo->runlist[1]); + nvkm_memory_del(&fifo->runlist[0]); -/******************************************************************************* - * PFIFO engine - ******************************************************************************/ + nvkm_fifo_destroy(&fifo->base); +} static int nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, @@ -484,12 +109,12 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->playlist[0]); + false, &fifo->runlist[0]); if (ret) return ret; ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->playlist[1]); + false, &fifo->runlist[1]); if (ret) return ret; @@ -502,46 +127,6 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -void -nv50_fifo_dtor(struct nvkm_object *object) -{ - struct nv50_fifo *fifo = (void *)object; - - nvkm_memory_del(&fifo->playlist[1]); - nvkm_memory_del(&fifo->playlist[0]); - - nvkm_fifo_destroy(&fifo->base); -} - -int -nv50_fifo_init(struct nvkm_object *object) -{ - struct nv50_fifo *fifo = (void *)object; - struct nvkm_device *device = fifo->base.engine.subdev.device; - int ret, i; - - ret = nvkm_fifo_init(&fifo->base); - if (ret) - return ret; - - nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); - nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); - nvkm_wr32(device, 0x00250c, 0x6f3cfc34); - nvkm_wr32(device, 0x002044, 0x01003fff); - - nvkm_wr32(device, 0x002100, 0xffffffff); - nvkm_wr32(device, 0x002140, 0xbfffffff); - - for (i = 0; i < 128; i++) - nvkm_wr32(device, 0x002600 + (i * 4), 0x00000000); - nv50_fifo_playlist_update_locked(fifo); - - nvkm_wr32(device, 0x003200, 0x00000001); - nvkm_wr32(device, 0x003250, 0x00000001); - nvkm_wr32(device, 0x002500, 0x00000001); - return 0; -} - struct nvkm_oclass * nv50_fifo_oclass = &(struct nvkm_oclass) { .handle = NV_ENGINE(FIFO, 0x50), diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h index 0c826153bac66..306593fc56bb1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h @@ -1,36 +1,14 @@ #ifndef __NV50_FIFO_H__ #define __NV50_FIFO_H__ -#include +#include "priv.h" struct nv50_fifo { struct nvkm_fifo base; - struct nvkm_memory *playlist[2]; - int cur_playlist; + struct nvkm_memory *runlist[2]; + int cur_runlist; }; -struct nv50_fifo_base { - struct nvkm_fifo_base base; - struct nvkm_gpuobj *ramfc; - struct nvkm_gpuobj *cache; - struct nvkm_gpuobj *eng; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; - -struct nv50_fifo_chan { - struct nvkm_fifo_chan base; - u32 subc[8]; - struct nvkm_ramht *ramht; -}; - -void nv50_fifo_playlist_update(struct nv50_fifo *); - -void nv50_fifo_object_detach(struct nvkm_object *, int); -void nv50_fifo_chan_dtor(struct nvkm_object *); -int nv50_fifo_chan_fini(struct nvkm_object *, bool); - -void nv50_fifo_context_dtor(struct nvkm_object *); - void nv50_fifo_dtor(struct nvkm_object *); int nv50_fifo_init(struct nvkm_object *); +void nv50_fifo_runlist_update(struct nv50_fifo *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h new file mode 100644 index 0000000000000..b202f7f9413d1 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -0,0 +1,8 @@ +#ifndef __NVKM_FIFO_PRIV_H__ +#define __NVKM_FIFO_PRIV_H__ +#include +#include + +void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); +void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h new file mode 100644 index 0000000000000..92d56221197b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/regsnv04.h @@ -0,0 +1,132 @@ +#ifndef __NV04_FIFO_REGS_H__ +#define __NV04_FIFO_REGS_H__ + +#define NV04_PFIFO_DELAY_0 0x00002040 +#define NV04_PFIFO_DMA_TIMESLICE 0x00002044 +#define NV04_PFIFO_NEXT_CHANNEL 0x00002050 +#define NV03_PFIFO_INTR_0 0x00002100 +#define NV03_PFIFO_INTR_EN_0 0x00002140 +# define NV_PFIFO_INTR_CACHE_ERROR (1<<0) +# define NV_PFIFO_INTR_RUNOUT (1<<4) +# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8) +# define NV_PFIFO_INTR_DMA_PUSHER (1<<12) +# define NV_PFIFO_INTR_DMA_PT (1<<16) +# define NV_PFIFO_INTR_SEMAPHORE (1<<20) +# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24) +#define NV03_PFIFO_RAMHT 0x00002210 +#define NV03_PFIFO_RAMFC 0x00002214 +#define NV03_PFIFO_RAMRO 0x00002218 +#define NV40_PFIFO_RAMFC 0x00002220 +#define NV03_PFIFO_CACHES 0x00002500 +#define NV04_PFIFO_MODE 0x00002504 +#define NV04_PFIFO_DMA 0x00002508 +#define NV04_PFIFO_SIZE 0x0000250c +#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4) +#define NV50_PFIFO_CTX_TABLE__SIZE 128 +#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31) +#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30) +#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF +#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF +#define NV03_PFIFO_CACHE0_PUSH0 0x00003000 +#define NV03_PFIFO_CACHE0_PULL0 0x00003040 +#define NV04_PFIFO_CACHE0_PULL0 0x00003050 +#define NV04_PFIFO_CACHE0_PULL1 0x00003054 +#define NV03_PFIFO_CACHE1_PUSH0 0x00003200 +#define NV03_PFIFO_CACHE1_PUSH1 0x00003204 +#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8) +#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16) +#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f +#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f +#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f +#define NV03_PFIFO_CACHE1_PUT 0x00003210 +#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220 +#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0 +# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000 +# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000 +# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000 +# define NV_PFIFO_CACHE1_ENDIAN 0x80000000 +# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF +# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000 +#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228 +#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c +#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230 +#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240 +#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244 +#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248 +#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C +#define NV03_PFIFO_CACHE1_PULL0 0x00003240 +#define NV04_PFIFO_CACHE1_PULL0 0x00003250 +# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010 +# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000 +#define NV03_PFIFO_CACHE1_PULL1 0x00003250 +#define NV04_PFIFO_CACHE1_PULL1 0x00003254 +#define NV04_PFIFO_CACHE1_HASH 0x00003258 +#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260 +#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264 +#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268 +#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C +#define NV03_PFIFO_CACHE1_GET 0x00003270 +#define NV04_PFIFO_CACHE1_ENGINE 0x00003280 +#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0 +#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0 +#define NV40_PFIFO_UNK32E4 0x000032E4 +#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8)) +#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8)) +#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8)) +#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8)) +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index b15b86478c4fa..e2d3d79ee37b3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -26,6 +26,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 8f0c62d56d9df..761aaa451e21b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -26,6 +26,7 @@ #include #include +#include #include struct pipe_state { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index a33ed6121d7f2..262638b4e0c59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index f0df11e479750..9cb5a90dde514 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -2,6 +2,7 @@ #include "regs.h" #include +#include /******************************************************************************* * Graphics object classes diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index 3bc6dae76fa5d..c5d8cd6d66c0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -2,6 +2,7 @@ #include "regs.h" #include +#include /******************************************************************************* * PGRAPH context diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 3c369f4b09e11..733de46a30dc9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -2,6 +2,7 @@ #include "regs.h" #include +#include #include /******************************************************************************* diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 48bd9da606be3..368c0cff35fb1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -2,6 +2,7 @@ #include "regs.h" #include +#include /******************************************************************************* * Graphics object classes diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index d25d3303f2fd2..676234d28e50a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -2,6 +2,7 @@ #include "regs.h" #include +#include /******************************************************************************* * Graphics object classes -- GitLab From 8f0649b5c6e70ec18122255690e39f010c12a614 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5519/7006] drm/nouveau/fifo: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../drm/nouveau/include/nvkm/core/engctx.h | 3 - .../drm/nouveau/include/nvkm/core/engine.h | 1 + .../drm/nouveau/include/nvkm/core/handle.h | 1 - .../drm/nouveau/include/nvkm/core/namedb.h | 52 -- .../drm/nouveau/include/nvkm/engine/fifo.h | 60 ++- drivers/gpu/drm/nouveau/nv84_fence.c | 2 +- drivers/gpu/drm/nouveau/nvkm/core/Kbuild | 1 - drivers/gpu/drm/nouveau/nvkm/core/engctx.c | 75 +-- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 10 + drivers/gpu/drm/nouveau/nvkm/core/handle.c | 52 +- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 2 +- drivers/gpu/drm/nouveau/nvkm/core/namedb.c | 201 -------- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 7 +- .../drm/nouveau/nvkm/engine/disp/rootnv04.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/dma/base.c | 106 +--- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 108 ++-- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 477 +++++++++++++++--- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.h | 44 +- .../drm/nouveau/nvkm/engine/fifo/chang84.c | 327 +++++++----- .../drm/nouveau/nvkm/engine/fifo/changf100.h | 25 +- .../drm/nouveau/nvkm/engine/fifo/changk104.h | 32 +- .../drm/nouveau/nvkm/engine/fifo/channv04.h | 24 +- .../drm/nouveau/nvkm/engine/fifo/channv50.c | 293 ++++++----- .../drm/nouveau/nvkm/engine/fifo/channv50.h | 47 +- .../gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c | 102 ++-- .../drm/nouveau/nvkm/engine/fifo/dmanv04.c | 216 +++----- .../drm/nouveau/nvkm/engine/fifo/dmanv10.c | 61 +-- .../drm/nouveau/nvkm/engine/fifo/dmanv17.c | 64 +-- .../drm/nouveau/nvkm/engine/fifo/dmanv40.c | 240 +++++---- .../drm/nouveau/nvkm/engine/fifo/dmanv50.c | 88 ++-- .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 13 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 61 ++- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.h | 5 + .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 114 ++--- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 42 ++ .../gpu/drm/nouveau/nvkm/engine/fifo/gm204.c | 10 +- .../drm/nouveau/nvkm/engine/fifo/gpfifog84.c | 90 ++-- .../nouveau/nvkm/engine/fifo/gpfifogf100.c | 374 +++++++------- .../nouveau/nvkm/engine/fifo/gpfifogk104.c | 407 +++++++-------- .../nouveau/nvkm/engine/fifo/gpfifogm204.c | 10 +- .../drm/nouveau/nvkm/engine/fifo/gpfifonv50.c | 76 ++- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 40 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.h | 9 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 19 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 27 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 27 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.h | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/priv.h | 1 - .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 19 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 24 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 10 +- 61 files changed, 2025 insertions(+), 2121 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h delete mode 100644 drivers/gpu/drm/nouveau/nvkm/core/namedb.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 78c6649407e66..d52ef8419fd27 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -64,6 +64,6 @@ u64 nvif_device_time(struct nvif_device *); #include #include -#define nvxx_fifo(a) nvkm_fifo(nvxx_device(a)) +#define nvxx_fifo(a) nvxx_device(a)->fifo #define nvxx_gr(a) nvkm_gr(nvxx_device(a)) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h index dfa24d233321a..4a77fdaa8b90c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h @@ -45,7 +45,4 @@ int _nvkm_engctx_init(struct nvkm_object *); int _nvkm_engctx_fini(struct nvkm_object *, bool suspend); #define _nvkm_engctx_rd32 _nvkm_gpuobj_rd32 #define _nvkm_engctx_wr32 _nvkm_gpuobj_wr32 - -struct nvkm_object *nvkm_engctx_get(struct nvkm_engine *, u64 addr); -void nvkm_engctx_put(struct nvkm_object *); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 8c67d755e5c1e..9d9c0e779f3fe 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -42,6 +42,7 @@ struct nvkm_engine_func { int (*sclass)(struct nvkm_oclass *, int index); } fifo; + const struct nvkm_object_func *cclass; struct nvkm_sclass sclass[]; }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h index 88e8bb17a280c..539278916d23b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h @@ -4,7 +4,6 @@ struct nvkm_object; struct nvkm_handle { - struct nvkm_namedb *namedb; struct list_head node; struct list_head head; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h deleted file mode 100644 index 16337f69b113d..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef __NVKM_NAMEDB_H__ -#define __NVKM_NAMEDB_H__ -#include -struct nvkm_handle; - -struct nvkm_namedb { - struct nvkm_parent parent; - rwlock_t lock; - struct list_head list; -}; - -static inline struct nvkm_namedb * -nv_namedb(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_NAMEDB_CLASS)); -#endif - return obj; -} - -#define nvkm_namedb_create(p,e,c,v,s,m,d) \ - nvkm_namedb_create_((p), (e), (c), (v), (s), (m), \ - sizeof(**d), (void **)d) -#define nvkm_namedb_init(p) \ - nvkm_parent_init(&(p)->parent) -#define nvkm_namedb_fini(p,s) \ - nvkm_parent_fini(&(p)->parent, (s)) -#define nvkm_namedb_destroy(p) \ - nvkm_parent_destroy(&(p)->parent) - -int nvkm_namedb_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32 pclass, - struct nvkm_oclass *, u64 engcls, - int size, void **); - -int _nvkm_namedb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_namedb_dtor _nvkm_parent_dtor -#define _nvkm_namedb_init _nvkm_parent_init -#define _nvkm_namedb_fini _nvkm_parent_fini - -int nvkm_namedb_insert(struct nvkm_namedb *, u32 name, struct nvkm_object *, - struct nvkm_handle *); -void nvkm_namedb_remove(struct nvkm_handle *); - -struct nvkm_handle *nvkm_namedb_get(struct nvkm_namedb *, u32); -struct nvkm_handle *nvkm_namedb_get_class(struct nvkm_namedb *, s32); -struct nvkm_handle *nvkm_namedb_get_vinst(struct nvkm_namedb *, u64); -struct nvkm_handle *nvkm_namedb_get_cinst(struct nvkm_namedb *, u32); -void nvkm_namedb_put(struct nvkm_handle *); -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index ac97072dcfefd..d9e494ba50338 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -1,25 +1,39 @@ #ifndef __NVKM_FIFO_H__ #define __NVKM_FIFO_H__ -#include +#define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object) +#define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine) +#include +#include + +#define NVKM_FIFO_CHID_NR 4096 + +struct nvkm_fifo_engn { + struct nvkm_object *object; + int refcount; + int usecount; +}; struct nvkm_fifo_chan { - struct nvkm_namedb namedb; - struct nvkm_gpuobj *pushgpu; + const struct nvkm_fifo_chan_func *func; + struct nvkm_fifo *fifo; + u64 engines; + struct nvkm_object object; + + struct list_head head; + u16 chid; + struct nvkm_gpuobj *inst; + struct nvkm_gpuobj *push; + struct nvkm_vm *vm; void __iomem *user; u64 addr; u32 size; - u16 chid; - u64 inst; + + struct nvkm_fifo_engn engn[NVDEV_SUBDEV_NR]; }; -static inline struct nvkm_fifo_chan * -nvkm_fifo_chan(void *obj) -{ - return (void *)nv_namedb(obj); -} +extern const struct nvkm_object_func nvkm_fifo_chan_func; #include - struct nvkm_fifo_base { struct nvkm_gpuobj gpuobj; }; @@ -39,25 +53,27 @@ struct nvkm_fifo_base { #define _nvkm_fifo_context_rd32 _nvkm_gpuobj_rd32 #define _nvkm_fifo_context_wr32 _nvkm_gpuobj_wr32 -#include -#include - struct nvkm_fifo { struct nvkm_engine engine; + const struct nvkm_fifo_func *func; struct nvkm_event cevent; /* channel creation event */ struct nvkm_event uevent; /* async user trigger */ - struct nvkm_object **channel; + DECLARE_BITMAP(mask, NVKM_FIFO_CHID_NR); + int nr; + struct list_head chan; spinlock_t lock; - u16 min; - u16 max; - int (*chid)(struct nvkm_fifo *, struct nvkm_object *); void (*pause)(struct nvkm_fifo *, unsigned long *); void (*start)(struct nvkm_fifo *, unsigned long *); }; +struct nvkm_fifo_func { + void *(*dtor)(struct nvkm_fifo *); + const struct nvkm_fifo_chan_oclass *chan[]; +}; + void nvkm_fifo_chan_put(struct nvkm_fifo *, unsigned long flags, struct nvkm_fifo_chan **); struct nvkm_fifo_chan * @@ -65,12 +81,6 @@ nvkm_fifo_chan_inst(struct nvkm_fifo *, u64 inst, unsigned long *flags); struct nvkm_fifo_chan * nvkm_fifo_chan_chid(struct nvkm_fifo *, int chid, unsigned long *flags); -static inline struct nvkm_fifo * -nvkm_fifo(void *obj) -{ - return (void *)nvkm_engine(obj, NVDEV_ENGINE_FIFO); -} - #define nvkm_fifo_create(o,e,c,fc,lc,d) \ nvkm_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d) #define nvkm_fifo_init(p) \ @@ -82,8 +92,6 @@ int nvkm_fifo_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, int min, int max, int size, void **); void nvkm_fifo_destroy(struct nvkm_fifo *); -const char * -nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid); #define _nvkm_fifo_init _nvkm_engine_init #define _nvkm_fifo_fini _nvkm_engine_fini diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c index 4d7ad6d3fbd4d..412c5be5a9ca2 100644 --- a/drivers/gpu/drm/nouveau/nv84_fence.c +++ b/drivers/gpu/drm/nouveau/nv84_fence.c @@ -228,7 +228,7 @@ nv84_fence_create(struct nouveau_drm *drm) priv->base.context_new = nv84_fence_context_new; priv->base.context_del = nv84_fence_context_del; - priv->base.contexts = fifo->max + 1; + priv->base.contexts = fifo->nr; priv->base.context_base = fence_context_alloc(priv->base.contexts); priv->base.uevent = true; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index e56c8eb9b054f..d3932d59ff092 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -8,7 +8,6 @@ nvkm-y += nvkm/core/handle.o nvkm-y += nvkm/core/ioctl.o nvkm-y += nvkm/core/memory.o nvkm-y += nvkm/core/mm.o -nvkm-y += nvkm/core/namedb.o nvkm-y += nvkm/core/notify.o nvkm-y += nvkm/core/object.o nvkm-y += nvkm/core/oproxy.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c index be640fd24f77b..bd13facc53d81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c @@ -124,58 +124,12 @@ nvkm_engctx_destroy(struct nvkm_engctx *engctx) int nvkm_engctx_init(struct nvkm_engctx *engctx) { - struct nvkm_object *object = nv_object(engctx); - struct nvkm_subdev *subdev = nv_subdev(object->engine); - struct nvkm_object *parent; - struct nvkm_subdev *pardev; - int ret; - - ret = nvkm_gpuobj_init(&engctx->gpuobj); - if (ret) - return ret; - - parent = nv_pclass(object->parent, NV_PARENT_CLASS); - pardev = nv_subdev(parent->engine); - if (nv_parent(parent)->context_attach) { - mutex_lock(&pardev->mutex); - ret = nv_parent(parent)->context_attach(parent, object); - mutex_unlock(&pardev->mutex); - } - - if (ret) { - nvkm_error(pardev, "failed to attach %s context, %d\n", - nvkm_subdev_name[subdev->index], ret); - return ret; - } - - nvkm_trace(pardev, "attached %s context\n", nvkm_subdev_name[subdev->index]); - return 0; + return nvkm_gpuobj_init(&engctx->gpuobj); } int nvkm_engctx_fini(struct nvkm_engctx *engctx, bool suspend) { - struct nvkm_object *object = nv_object(engctx); - struct nvkm_subdev *subdev = nv_subdev(object->engine); - struct nvkm_object *parent; - struct nvkm_subdev *pardev; - int ret = 0; - - parent = nv_pclass(object->parent, NV_PARENT_CLASS); - pardev = nv_subdev(parent->engine); - if (nv_parent(parent)->context_detach) { - mutex_lock(&pardev->mutex); - ret = nv_parent(parent)->context_detach(parent, suspend, object); - mutex_unlock(&pardev->mutex); - } - - if (ret) { - nvkm_error(pardev, "failed to detach %s context, %d\n", - nvkm_subdev_name[subdev->index], ret); - return ret; - } - - nvkm_trace(pardev, "detached %s context\n", nvkm_subdev_name[subdev->index]); return nvkm_gpuobj_fini(&engctx->gpuobj, suspend); } @@ -210,30 +164,3 @@ _nvkm_engctx_fini(struct nvkm_object *object, bool suspend) { return nvkm_engctx_fini(nv_engctx(object), suspend); } - -struct nvkm_object * -nvkm_engctx_get(struct nvkm_engine *engine, u64 addr) -{ - struct nvkm_engctx *engctx; - unsigned long flags; - - spin_lock_irqsave(&engine->lock, flags); - list_for_each_entry(engctx, &engine->contexts, head) { - if (engctx->addr == addr) { - engctx->save = flags; - return nv_object(engctx); - } - } - spin_unlock_irqrestore(&engine->lock, flags); - return NULL; -} - -void -nvkm_engctx_put(struct nvkm_object *object) -{ - if (object) { - struct nvkm_engine *engine = nv_engine(object->engine); - struct nvkm_engctx *engctx = nv_engctx(object); - spin_unlock_irqrestore(&engine->lock, engctx->save); - } -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index 54b46037f4ba3..e056f7afc35cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -231,6 +231,8 @@ nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) nvkm_object_destroy(&gpuobj->object); } +#include + int nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 pclass, @@ -240,11 +242,19 @@ nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_device *device = nv_device(parent); struct nvkm_gpuobj *pargpu = NULL; struct nvkm_gpuobj *gpuobj; + struct nvkm_object *object = objgpu; const bool zero = (flags & NVOBJ_FLAG_ZERO_ALLOC); int ret; *pobject = NULL; + while (object && object->func != &nvkm_fifo_chan_func) + object = object->parent; + + if (object) { + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + pargpu = chan->inst; + } else if (objgpu) { while ((objgpu = nv_pclass(objgpu, NV_GPUOBJ_CLASS))) { if (nv_gpuobj(objgpu)->heap.block_size) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index 2b52a655309b7..a74ee1c29f8cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -23,7 +23,7 @@ */ #include #include -#include +#include #define hprintk(h,l,f,a...) do { \ struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \ @@ -98,14 +98,9 @@ int nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, struct nvkm_object *object, struct nvkm_handle **phandle) { - struct nvkm_object *namedb; struct nvkm_handle *handle; int ret; - namedb = parent ? parent->object : NULL; - while (namedb && !nv_iclass(namedb, NV_NAMEDB_CLASS)) - namedb = namedb->parent; - handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) return -ENOMEM; @@ -118,15 +113,6 @@ nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, handle->parent = parent; nvkm_object_ref(object, &handle->object); - if (namedb) { - ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, - object, handle); - if (ret) { - kfree(handle); - return ret; - } - } - if (parent) { if (nv_iclass(parent->object, NV_PARENT_CLASS) && nv_parent(parent->object)->object_attach) { @@ -168,40 +154,6 @@ nvkm_handle_destroy(struct nvkm_handle *handle) } hprintk(handle, TRACE, "destroy completed\n"); - nvkm_namedb_remove(handle); + nvkm_object_ref(NULL, &handle->object); kfree(handle); } - -struct nvkm_handle * -nvkm_handle_get_class(struct nvkm_object *engctx, u16 oclass) -{ - struct nvkm_namedb *namedb; - if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS))) - return nvkm_namedb_get_class(namedb, oclass); - return NULL; -} - -struct nvkm_handle * -nvkm_handle_get_vinst(struct nvkm_object *engctx, u64 vinst) -{ - struct nvkm_namedb *namedb; - if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS))) - return nvkm_namedb_get_vinst(namedb, vinst); - return NULL; -} - -struct nvkm_handle * -nvkm_handle_get_cinst(struct nvkm_object *engctx, u32 cinst) -{ - struct nvkm_namedb *namedb; - if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS))) - return nvkm_namedb_get_cinst(namedb, cinst); - return NULL; -} - -void -nvkm_handle_put(struct nvkm_handle *handle) -{ - if (handle) - nvkm_namedb_put(handle); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 04f1bc2d0f8ee..28f9fa289e809 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c deleted file mode 100644 index 9be1ce9670346..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include -#include -#include - -static struct nvkm_handle * -nvkm_namedb_lookup(struct nvkm_namedb *namedb, u32 name) -{ - struct nvkm_handle *handle; - - list_for_each_entry(handle, &namedb->list, node) { - if (handle->name == name) - return handle; - } - - return NULL; -} - -static struct nvkm_handle * -nvkm_namedb_lookup_class(struct nvkm_namedb *namedb, s32 oclass) -{ - struct nvkm_handle *handle; - - list_for_each_entry(handle, &namedb->list, node) { - if (nv_mclass(handle->object) == oclass) - return handle; - } - - return NULL; -} - -static struct nvkm_handle * -nvkm_namedb_lookup_vinst(struct nvkm_namedb *namedb, u64 vinst) -{ - struct nvkm_handle *handle; - - list_for_each_entry(handle, &namedb->list, node) { - if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { - if (nv_gpuobj(handle->object)->addr == vinst) - return handle; - } - } - - return NULL; -} - -static struct nvkm_handle * -nvkm_namedb_lookup_cinst(struct nvkm_namedb *namedb, u32 cinst) -{ - struct nvkm_handle *handle; - - list_for_each_entry(handle, &namedb->list, node) { - if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) { - if (nv_gpuobj(handle->object)->node && - nv_gpuobj(handle->object)->node->offset == cinst) - return handle; - } - } - - return NULL; -} - -int -nvkm_namedb_insert(struct nvkm_namedb *namedb, u32 name, - struct nvkm_object *object, - struct nvkm_handle *handle) -{ - int ret = -EEXIST; - write_lock_irq(&namedb->lock); - if (!nvkm_namedb_lookup(namedb, name)) { - nvkm_object_ref(object, &handle->object); - handle->namedb = namedb; - list_add(&handle->node, &namedb->list); - ret = 0; - } - write_unlock_irq(&namedb->lock); - return ret; -} - -void -nvkm_namedb_remove(struct nvkm_handle *handle) -{ - struct nvkm_namedb *namedb = handle->namedb; - struct nvkm_object *object = handle->object; - if (handle->namedb) { - write_lock_irq(&namedb->lock); - list_del(&handle->node); - write_unlock_irq(&namedb->lock); - } - nvkm_object_ref(NULL, &object); -} - -struct nvkm_handle * -nvkm_namedb_get(struct nvkm_namedb *namedb, u32 name) -{ - struct nvkm_handle *handle; - read_lock(&namedb->lock); - handle = nvkm_namedb_lookup(namedb, name); - if (handle == NULL) - read_unlock(&namedb->lock); - return handle; -} - -struct nvkm_handle * -nvkm_namedb_get_class(struct nvkm_namedb *namedb, s32 oclass) -{ - struct nvkm_handle *handle; - read_lock(&namedb->lock); - handle = nvkm_namedb_lookup_class(namedb, oclass); - if (handle == NULL) - read_unlock(&namedb->lock); - return handle; -} - -struct nvkm_handle * -nvkm_namedb_get_vinst(struct nvkm_namedb *namedb, u64 vinst) -{ - struct nvkm_handle *handle; - read_lock(&namedb->lock); - handle = nvkm_namedb_lookup_vinst(namedb, vinst); - if (handle == NULL) - read_unlock(&namedb->lock); - return handle; -} - -struct nvkm_handle * -nvkm_namedb_get_cinst(struct nvkm_namedb *namedb, u32 cinst) -{ - struct nvkm_handle *handle; - read_lock(&namedb->lock); - handle = nvkm_namedb_lookup_cinst(namedb, cinst); - if (handle == NULL) - read_unlock(&namedb->lock); - return handle; -} - -void -nvkm_namedb_put(struct nvkm_handle *handle) -{ - if (handle) - read_unlock(&handle->namedb->lock); -} - -int -nvkm_namedb_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 pclass, - struct nvkm_oclass *sclass, u64 engcls, - int length, void **pobject) -{ - struct nvkm_namedb *namedb; - int ret; - - ret = nvkm_parent_create_(parent, engine, oclass, pclass | - NV_NAMEDB_CLASS, sclass, engcls, - length, pobject); - namedb = *pobject; - if (ret) - return ret; - - rwlock_init(&namedb->lock); - INIT_LIST_HEAD(&namedb->list); - return 0; -} - -int -_nvkm_namedb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_namedb *object; - int ret; - - ret = nvkm_namedb_create(parent, engine, oclass, 0, NULL, 0, &object); - *pobject = nv_object(object); - if (ret) - return ret; - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index a632570f20e1f..1a15b8d6fecea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -85,7 +85,8 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " "subc %d mthd %04x data %08x\n", ssta, en ? en->name : "", chan ? chan->chid : -1, - chan ? chan->inst : 0, nvkm_client_name(chan), + chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", subc, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 62cdd1e50a95d..74bea4397bf4e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -121,9 +121,10 @@ g84_cipher_intr(struct nvkm_subdev *subdev) if (stat) { nvkm_snprintbf(msg, sizeof(msg), g84_cipher_intr_mask, stat); nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] " - "mthd %04x data %08x\n", - stat, msg, chan ? chan->chid : -1, (u64)inst << 12, - nvkm_client_name(chan), mthd, data); + "mthd %04x data %08x\n", stat, msg, + chan ? chan->chid : -1, (u64)inst << 12, + chan ? chan->object.client->name : "unknown", + mthd, data); } nvkm_fifo_chan_put(fifo, flags, &chan); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c index 2d9b81fb83a22..62d3fb66d0ec2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv04.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object); +#define nv04_disp_root(p) container_of((p), struct nv04_disp_root, object) #include "priv.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c index 57f6eca078ef6..1a377201949c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c @@ -24,6 +24,7 @@ #include "priv.h" #include +#include #include @@ -88,11 +89,19 @@ nvkm_dma_oclass_base = { .ctor = nvkm_dma_oclass_new, }; +static int +nvkm_dma_oclass_fifo_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + return nvkm_dma_oclass_new(oclass->engine->subdev.device, + oclass, data, size, pobject); +} + static const struct nvkm_sclass nvkm_dma_sclass[] = { - { 0, 0, NV_DMA_FROM_MEMORY }, - { 0, 0, NV_DMA_TO_MEMORY }, - { 0, 0, NV_DMA_IN_MEMORY }, + { 0, 0, NV_DMA_FROM_MEMORY, NULL, nvkm_dma_oclass_fifo_new }, + { 0, 0, NV_DMA_TO_MEMORY, NULL, nvkm_dma_oclass_fifo_new }, + { 0, 0, NV_DMA_IN_MEMORY, NULL, nvkm_dma_oclass_fifo_new }, }; static int @@ -110,89 +119,21 @@ nvkm_dma_oclass_base_get(struct nvkm_oclass *sclass, int index, return count; } -static const struct nvkm_engine_func -nvkm_dma = { - .base.sclass = nvkm_dma_oclass_base_get, -}; - -#include - -static struct nvkm_oclass empty = { - .ofuncs = &(struct nvkm_ofuncs) { - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - }, -}; - static int -nvkm_dmaobj_compat_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_oclass hack = { - .base.oclass = oclass->handle, - .client = nvkm_client(parent), - .parent = parent, - .engine = nv_engine(engine), - }; - struct nvkm_dma *dma = (void *)engine; - struct nvkm_dma_impl *impl = (void *)dma->engine.subdev.object.oclass; - struct nvkm_dmaobj *dmaobj = NULL; - struct nvkm_gpuobj *gpuobj; - int ret; - - ret = impl->class_new(dma, &hack, data, size, &dmaobj); - if (dmaobj) - *pobject = &dmaobj->object; - if (ret) - return ret; - - gpuobj = (void *)nv_pclass(parent, NV_GPUOBJ_CLASS); - - ret = dmaobj->func->bind(dmaobj, gpuobj, 16, &gpuobj); - nvkm_object_ref(NULL, pobject); - if (ret) - return ret; - - ret = nvkm_object_create(parent, engine, &empty, 0, pobject); - if (ret) - return ret; - - gpuobj->object.parent = *pobject; - gpuobj->object.engine = &dma->engine; - gpuobj->object.oclass = oclass; - gpuobj->object.pclass = NV_GPUOBJ_CLASS; -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - gpuobj->object._magic = NVKM_OBJECT_MAGIC; -#endif - *pobject = &gpuobj->object; - return 0; -} - -static void -nvkm_dmaobj_compat_dtor(struct nvkm_object *object) +nvkm_dma_oclass_fifo_get(struct nvkm_oclass *oclass, int index) { - struct nvkm_object *parent = object->parent; - struct nvkm_gpuobj *gpuobj = (void *)object; - nvkm_gpuobj_del(&gpuobj); - nvkm_object_ref(NULL, &parent); + const int count = ARRAY_SIZE(nvkm_dma_sclass); + if (index < count) { + oclass->base = nvkm_dma_sclass[index]; + return index; + } + return count; } -static struct nvkm_ofuncs -nvkm_dmaobj_compat_ofuncs = { - .ctor = nvkm_dmaobj_compat_ctor, - .dtor = nvkm_dmaobj_compat_dtor, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, -}; - -static struct nvkm_oclass -nvkm_dma_compat_sclass[] = { - { NV_DMA_FROM_MEMORY, &nvkm_dmaobj_compat_ofuncs }, - { NV_DMA_TO_MEMORY, &nvkm_dmaobj_compat_ofuncs }, - { NV_DMA_IN_MEMORY, &nvkm_dmaobj_compat_ofuncs }, - {} +static const struct nvkm_engine_func +nvkm_dma = { + .base.sclass = nvkm_dma_oclass_base_get, + .fifo.sclass = nvkm_dma_oclass_fifo_get, }; int @@ -209,7 +150,6 @@ _nvkm_dma_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - dmaeng->engine.sclass = nvkm_dma_compat_sclass; dmaeng->engine.func = &nvkm_dma; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index 510de3c2d2e43..b693127d80e10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -44,12 +44,13 @@ nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, struct nvkm_fifo_chan * nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) { + struct nvkm_fifo_chan *chan; unsigned long flags; - int i; spin_lock_irqsave(&fifo->lock, flags); - for (i = fifo->min; i < fifo->max; i++) { - struct nvkm_fifo_chan *chan = (void *)fifo->channel[i]; - if (chan && chan->inst == inst) { + list_for_each_entry(chan, &fifo->chan, head) { + if (chan->inst->addr == inst) { + list_del(&chan->head); + list_add(&chan->head, &fifo->chan); *rflags = flags; return chan; } @@ -61,45 +62,21 @@ nvkm_fifo_chan_inst(struct nvkm_fifo *fifo, u64 inst, unsigned long *rflags) struct nvkm_fifo_chan * nvkm_fifo_chan_chid(struct nvkm_fifo *fifo, int chid, unsigned long *rflags) { + struct nvkm_fifo_chan *chan; unsigned long flags; spin_lock_irqsave(&fifo->lock, flags); - if (fifo->channel[chid]) { - *rflags = flags; - return (void *)fifo->channel[chid]; + list_for_each_entry(chan, &fifo->chan, head) { + if (chan->chid == chid) { + list_del(&chan->head); + list_add(&chan->head, &fifo->chan); + *rflags = flags; + return chan; + } } spin_unlock_irqrestore(&fifo->lock, flags); return NULL; } -static int -nvkm_fifo_chid(struct nvkm_fifo *fifo, struct nvkm_object *object) -{ - int engidx = nv_hclass(fifo) & 0xff; - - while (object && object->parent) { - if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) && - (nv_hclass(object->parent) & 0xff) == engidx) - return nvkm_fifo_chan(object)->chid; - object = object->parent; - } - - return -1; -} - -const char * -nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid) -{ - struct nvkm_fifo_chan *chan = NULL; - unsigned long flags; - - spin_lock_irqsave(&fifo->lock, flags); - if (chid >= fifo->min && chid <= fifo->max) - chan = (void *)fifo->channel[chid]; - spin_unlock_irqrestore(&fifo->lock, flags); - - return nvkm_client_name(chan); -} - static int nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -144,21 +121,62 @@ nvkm_fifo_uevent(struct nvkm_fifo *fifo) nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep)); } +static int +nvkm_fifo_class_new(struct nvkm_device *device, + const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + const struct nvkm_fifo_chan_oclass *sclass = oclass->engn; + struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); + return sclass->ctor(fifo, oclass, data, size, pobject); +} + +static const struct nvkm_device_oclass +nvkm_fifo_class = { + .ctor = nvkm_fifo_class_new, +}; + +static int +nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, + const struct nvkm_device_oclass **class) +{ + struct nvkm_fifo *fifo = nvkm_fifo(oclass->engine); + const struct nvkm_fifo_chan_oclass *sclass; + int c = 0; + + while ((sclass = fifo->func->chan[c])) { + if (c++ == index) { + oclass->base = sclass->base; + oclass->engn = sclass; + *class = &nvkm_fifo_class; + return 0; + } + } + + return c; +} + void nvkm_fifo_destroy(struct nvkm_fifo *fifo) { - kfree(fifo->channel); nvkm_event_fini(&fifo->uevent); nvkm_event_fini(&fifo->cevent); nvkm_engine_destroy(&fifo->engine); } +static const struct nvkm_engine_func +nvkm_fifo_func = { + .base.sclass = nvkm_fifo_class_get, +}; + int nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int min, int max, int length, void **pobject) { struct nvkm_fifo *fifo; + int nr = max + 1; + int cnt = nr - min; int ret; ret = nvkm_engine_create_(parent, engine, oclass, true, "PFIFO", @@ -167,17 +185,21 @@ nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - fifo->min = min; - fifo->max = max; - fifo->channel = kzalloc(sizeof(*fifo->channel) * (max + 1), GFP_KERNEL); - if (!fifo->channel) - return -ENOMEM; + fifo->engine.func = &nvkm_fifo_func; + INIT_LIST_HEAD(&fifo->chan); + + fifo->nr = nr; + if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) { + fifo->nr = NVKM_FIFO_CHID_NR; + cnt = fifo->nr - min; + } + bitmap_fill(fifo->mask, NVKM_FIFO_CHID_NR); + bitmap_clear(fifo->mask, min, cnt); ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent); if (ret) return ret; - fifo->chid = nvkm_fifo_chid; spin_lock_init(&fifo->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index cc401ae1d6a5d..2735c2df22183 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -24,139 +24,472 @@ #include "chan.h" #include +#include +#include #include -#include +struct nvkm_fifo_chan_object { + struct nvkm_oproxy oproxy; + struct nvkm_fifo_chan *chan; + int hash; +}; -int -_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type, - struct nvkm_event **event) +static int +nvkm_fifo_chan_child_fini(struct nvkm_oproxy *base, bool suspend) +{ + struct nvkm_fifo_chan_object *object = + container_of(base, typeof(*object), oproxy); + struct nvkm_engine *engine = object->oproxy.object->engine; + struct nvkm_fifo_chan *chan = object->chan; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + const char *name = nvkm_subdev_name[engine->subdev.index]; + int ret = 0; + + if (--engn->usecount) + return 0; + + if (chan->func->engine_fini) { + ret = chan->func->engine_fini(chan, engine, suspend); + if (ret) { + nvif_error(&chan->object, + "detach %s failed, %d\n", name, ret); + return ret; + } + } + + if (engn->object) { + ret = nvkm_object_fini(engn->object, suspend); + if (ret && suspend) + return ret; + } + + nvif_trace(&chan->object, "detached %s\n", name); + return ret; +} + +static int +nvkm_fifo_chan_child_init(struct nvkm_oproxy *base) +{ + struct nvkm_fifo_chan_object *object = + container_of(base, typeof(*object), oproxy); + struct nvkm_engine *engine = object->oproxy.object->engine; + struct nvkm_fifo_chan *chan = object->chan; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + const char *name = nvkm_subdev_name[engine->subdev.index]; + int ret; + + if (engn->usecount++) + return 0; + + if (engn->object) { + ret = nvkm_object_init(engn->object); + if (ret) + return ret; + } + + if (chan->func->engine_init) { + ret = chan->func->engine_init(chan, engine); + if (ret) { + nvif_error(&chan->object, + "attach %s failed, %d\n", name, ret); + return ret; + } + } + + nvif_trace(&chan->object, "attached %s\n", name); + return 0; +} + +static void +nvkm_fifo_chan_child_del(struct nvkm_oproxy *base) +{ + struct nvkm_fifo_chan_object *object = + container_of(base, typeof(*object), oproxy); + struct nvkm_engine *engine = object->oproxy.base.engine; + struct nvkm_fifo_chan *chan = object->chan; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + + if (chan->func->object_dtor) + chan->func->object_dtor(chan, object->hash); + + if (!--engn->refcount) { + if (chan->func->engine_dtor) + chan->func->engine_dtor(chan, engine); + nvkm_object_ref(NULL, &engn->object); + if (chan->vm) + atomic_dec(&chan->vm->engref[engine->subdev.index]); + } +} + +static const struct nvkm_oproxy_func +nvkm_fifo_chan_child_func = { + .dtor[0] = nvkm_fifo_chan_child_del, + .init[0] = nvkm_fifo_chan_child_init, + .fini[0] = nvkm_fifo_chan_child_fini, +}; + +static int +nvkm_fifo_chan_child_old(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_fifo *fifo = (void *)object->engine; - switch (type) { - case G82_CHANNEL_DMA_V0_NTFY_UEVENT: - if (nv_mclass(object) >= G82_CHANNEL_DMA) { - *event = &fifo->uevent; - return 0; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(oclass->parent); + struct nvkm_object *parent = &chan->object; + struct nvkm_engine *engine = oclass->engine; + struct nvkm_oclass *eclass = (void *)oclass->priv; + struct nvkm_object *engctx = NULL; + struct nvkm_fifo_chan_object *object; + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + int ret; + + if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) + return -ENOMEM; + nvkm_oproxy_ctor(&nvkm_fifo_chan_child_func, oclass, &object->oproxy); + *pobject = &object->oproxy.base; + object->chan = chan; + + if (!engn->refcount++) { + if (chan->vm) + atomic_inc(&chan->vm->engref[engine->subdev.index]); + if (engine->cclass && !engn->object) { + ret = nvkm_object_old(parent, &engine->subdev.object, + engine->cclass, NULL, 0, + &engn->object); + if (ret) { + nvkm_engine_unref(&engine); + return ret; + } + } else { + nvkm_object_ref(parent, &engn->object); } - break; - default: - break; + + if (chan->func->engine_ctor) { + ret = chan->func->engine_ctor(chan, engine, + engn->object); + if (ret) + return ret; + } + } + nvkm_object_ref(engn->object, &engctx); + + ret = nvkm_object_old(engctx, &engine->subdev.object, eclass, + data, size, &object->oproxy.object); + nvkm_object_ref(NULL, &engctx); + if (ret) + return ret; + + object->oproxy.object->handle = oclass->handle; + + if (chan->func->object_ctor) { + object->hash = + chan->func->object_ctor(chan, object->oproxy.object); + if (object->hash < 0) + return object->hash; } + + return 0; +} + +static int +nvkm_fifo_chan_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_engine *engine = oclass->engine; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(oclass->parent); + struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; + struct nvkm_fifo_chan_object *object; + int ret = 0; + + if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) + return -ENOMEM; + nvkm_oproxy_ctor(&nvkm_fifo_chan_child_func, oclass, &object->oproxy); + object->chan = chan; + *pobject = &object->oproxy.base; + + if (!engn->refcount++) { + struct nvkm_oclass cclass = { + .client = oclass->client, + .engine = oclass->engine, + }; + + if (chan->vm) + atomic_inc(&chan->vm->engref[engine->subdev.index]); + + if (engine->func->fifo.cclass) { + ret = engine->func->fifo.cclass(chan, &cclass, + &engn->object); + } else + if (engine->func->cclass) { + ret = nvkm_object_new_(engine->func->cclass, &cclass, + NULL, 0, &engn->object); + } + if (ret) + return ret; + + if (chan->func->engine_ctor) { + ret = chan->func->engine_ctor(chan, oclass->engine, + engn->object); + if (ret) + return ret; + } + } + + ret = oclass->base.ctor(&(const struct nvkm_oclass) { + .base = oclass->base, + .engn = oclass->engn, + .handle = oclass->handle, + .object = oclass->object, + .client = oclass->client, + .parent = engn->object ? + engn->object : + oclass->parent, + .engine = engine, + }, data, size, &object->oproxy.object); + if (ret) + return ret; + + if (chan->func->object_ctor) { + object->hash = + chan->func->object_ctor(chan, object->oproxy.object); + if (object->hash < 0) + return object->hash; + } + + return 0; +} + +static int +nvkm_fifo_chan_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + struct nvkm_fifo *fifo = chan->fifo; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_engine *engine; + u64 mask = chan->engines; + int ret, i, c; + + for (; c = 0, i = __ffs64(mask), mask; mask &= ~(1ULL << i)) { + if ((engine = nvkm_device_engine(device, i)) && + !engine->func) { + struct nvkm_oclass *sclass = engine->sclass; + int c = 0; + while (sclass && sclass->ofuncs) { + if (c++ == index) { + oclass->base.oclass = sclass->handle; + oclass->base.minver = -2; + oclass->base.maxver = -2; + oclass->ctor = nvkm_fifo_chan_child_old; + oclass->priv = sclass; + oclass->engine = engine; + return 0; + } + sclass++; + } + index -= c; + continue; + } + + if (!(engine = nvkm_device_engine(device, i))) + continue; + oclass->engine = engine; + oclass->base.oclass = 0; + + if (engine->func->fifo.sclass) { + ret = engine->func->fifo.sclass(oclass, index); + if (oclass->base.oclass) { + if (!oclass->base.ctor) + oclass->base.ctor = nvkm_object_new; + oclass->ctor = nvkm_fifo_chan_child_new; + return 0; + } + + index -= ret; + continue; + } + + while (engine->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = engine->func->sclass[index]; + if (!oclass->base.ctor) + oclass->base.ctor = nvkm_object_new; + oclass->ctor = nvkm_fifo_chan_child_new; + return 0; + } + } + index -= c; + } + return -EINVAL; } -int -_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size) +static int +nvkm_fifo_chan_ntfy(struct nvkm_object *object, u32 type, + struct nvkm_event **pevent) { - struct nvkm_fifo_chan *chan = (void *)object; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + if (chan->func->ntfy) + return chan->func->ntfy(chan, type, pevent); + return -ENODEV; +} + +static int +nvkm_fifo_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); *addr = chan->addr; *size = chan->size; return 0; } -u32 -_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr) +static int +nvkm_fifo_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) { - struct nvkm_fifo_chan *chan = (void *)object; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); if (unlikely(!chan->user)) { chan->user = ioremap(chan->addr, chan->size); - if (WARN_ON_ONCE(chan->user == NULL)) - return 0; + if (!chan->user) + return -ENOMEM; } - return ioread32_native(chan->user + addr); + if (unlikely(addr + 4 > chan->size)) + return -EINVAL; + *data = ioread32_native(chan->user + addr); + return 0; } -void -_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data) +static int +nvkm_fifo_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) { - struct nvkm_fifo_chan *chan = (void *)object; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); if (unlikely(!chan->user)) { chan->user = ioremap(chan->addr, chan->size); - if (WARN_ON_ONCE(chan->user == NULL)) - return; + if (!chan->user) + return -ENOMEM; } + if (unlikely(addr + 4 > chan->size)) + return -EINVAL; iowrite32_native(data, chan->user + addr); + return 0; +} + +static int +nvkm_fifo_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + chan->func->fini(chan); + return 0; } -void -nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan) +static int +nvkm_fifo_chan_init(struct nvkm_object *object) { - struct nvkm_fifo *fifo = (void *)nv_object(chan)->engine; + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + chan->func->init(chan); + return 0; +} + +static void * +nvkm_fifo_chan_dtor(struct nvkm_object *object) +{ + struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); + struct nvkm_fifo *fifo = chan->fifo; + void *data = chan->func->dtor(chan); unsigned long flags; + spin_lock_irqsave(&fifo->lock, flags); + if (!list_empty(&chan->head)) { + __clear_bit(chan->chid, fifo->mask); + list_del(&chan->head); + } + spin_unlock_irqrestore(&fifo->lock, flags); + if (chan->user) iounmap(chan->user); - spin_lock_irqsave(&fifo->lock, flags); - fifo->channel[chan->chid] = NULL; - spin_unlock_irqrestore(&fifo->lock, flags); + nvkm_vm_ref(NULL, &chan->vm, NULL); - nvkm_gpuobj_del(&chan->pushgpu); - nvkm_namedb_destroy(&chan->namedb); + nvkm_gpuobj_del(&chan->push); + nvkm_gpuobj_del(&chan->inst); + return data; } -void -_nvkm_fifo_channel_dtor(struct nvkm_object *object) -{ - struct nvkm_fifo_chan *chan = (void *)object; - nvkm_fifo_channel_destroy(chan); -} +const struct nvkm_object_func +nvkm_fifo_chan_func = { + .dtor = nvkm_fifo_chan_dtor, + .init = nvkm_fifo_chan_init, + .fini = nvkm_fifo_chan_fini, + .ntfy = nvkm_fifo_chan_ntfy, + .map = nvkm_fifo_chan_map, + .rd32 = nvkm_fifo_chan_rd32, + .wr32 = nvkm_fifo_chan_wr32, + .sclass = nvkm_fifo_chan_child_get, +}; int -nvkm_fifo_channel_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, - int bar, u32 addr, u32 size, u64 pushbuf, - u64 engmask, int len, void **ptr) +nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *func, + struct nvkm_fifo *fifo, u32 size, u32 align, bool zero, + u64 vm, u64 push, u64 engines, int bar, u32 base, u32 user, + const struct nvkm_oclass *oclass, + struct nvkm_fifo_chan *chan) { - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_fifo *fifo = (void *)engine; - struct nvkm_fifo_base *base = (void *)parent; - struct nvkm_fifo_chan *chan; - struct nvkm_subdev *subdev = &fifo->engine.subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_client *client = oclass->client; + struct nvkm_device *device = fifo->engine.subdev.device; + struct nvkm_mmu *mmu = device->mmu; struct nvkm_dmaobj *dmaobj; unsigned long flags; int ret; - /* create base object class */ - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - engmask, len, ptr); - chan = *ptr; + nvkm_object_ctor(&nvkm_fifo_chan_func, oclass, &chan->object); + chan->func = func; + chan->fifo = fifo; + chan->engines = engines; + INIT_LIST_HEAD(&chan->head); + + /* instance memory */ + ret = nvkm_gpuobj_new(device, size, align, zero, NULL, &chan->inst); if (ret) return ret; - /* validate dma object representing push buffer */ - if (pushbuf) { - dmaobj = nvkm_dma_search(device->dma, client, pushbuf); + /* allocate push buffer ctxdma instance */ + if (push) { + dmaobj = nvkm_dma_search(device->dma, oclass->client, push); if (!dmaobj) return -ENOENT; - ret = nvkm_object_bind(&dmaobj->object, &base->gpuobj, 16, - &chan->pushgpu); + ret = nvkm_object_bind(&dmaobj->object, chan->inst, -16, + &chan->push); if (ret) return ret; } - /* find a free fifo channel */ - spin_lock_irqsave(&fifo->lock, flags); - for (chan->chid = fifo->min; chan->chid < fifo->max; chan->chid++) { - if (!fifo->channel[chan->chid]) { - fifo->channel[chan->chid] = nv_object(chan); - break; + /* channel address space */ + if (!vm && mmu) { + if (!client->vm || client->vm->mmu == mmu) { + ret = nvkm_vm_ref(client->vm, &chan->vm, NULL); + if (ret) + return ret; + } else { + return -EINVAL; } + } else { + return -ENOENT; } - spin_unlock_irqrestore(&fifo->lock, flags); - if (chan->chid == fifo->max) { - nvkm_error(subdev, "no free channels\n"); + /* allocate channel id */ + spin_lock_irqsave(&fifo->lock, flags); + chan->chid = find_first_zero_bit(fifo->mask, NVKM_FIFO_CHID_NR); + if (chan->chid >= NVKM_FIFO_CHID_NR) { + spin_unlock_irqrestore(&fifo->lock, flags); return -ENOSPC; } + list_add(&chan->head, &fifo->chan); + __set_bit(chan->chid, fifo->mask); + spin_unlock_irqrestore(&fifo->lock, flags); + /* determine address of this channel's user registers */ chan->addr = nv_device_resource_start(device, bar) + - addr + size * chan->chid; - chan->size = size; + base + user * chan->chid; + chan->size = user; + nvkm_event_send(&fifo->cevent, 1, 0, NULL, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h index 63209bc8856be..bfec12dbf4929 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h @@ -2,27 +2,31 @@ #define __NVKM_FIFO_CHAN_H__ #include "priv.h" -#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d) \ - nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \ - (m), sizeof(**d), (void **)d) -#define nvkm_fifo_channel_init(p) \ - nvkm_namedb_init(&(p)->namedb) -#define nvkm_fifo_channel_fini(p,s) \ - nvkm_namedb_fini(&(p)->namedb, (s)) +struct nvkm_fifo_chan_func { + void *(*dtor)(struct nvkm_fifo_chan *); + void (*init)(struct nvkm_fifo_chan *); + void (*fini)(struct nvkm_fifo_chan *); + int (*ntfy)(struct nvkm_fifo_chan *, u32 type, struct nvkm_event **); + int (*engine_ctor)(struct nvkm_fifo_chan *, struct nvkm_engine *, + struct nvkm_object *); + void (*engine_dtor)(struct nvkm_fifo_chan *, struct nvkm_engine *); + int (*engine_init)(struct nvkm_fifo_chan *, struct nvkm_engine *); + int (*engine_fini)(struct nvkm_fifo_chan *, struct nvkm_engine *, + bool suspend); + int (*object_ctor)(struct nvkm_fifo_chan *, struct nvkm_object *); + void (*object_dtor)(struct nvkm_fifo_chan *, int); +}; -int nvkm_fifo_channel_create_(struct nvkm_object *, - struct nvkm_object *, - struct nvkm_oclass *, - int bar, u32 addr, u32 size, u64 push, - u64 engmask, int len, void **); -void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *); +int nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *, struct nvkm_fifo *, + u32 size, u32 align, bool zero, u64 vm, u64 push, + u64 engines, int bar, u32 base, u32 user, + const struct nvkm_oclass *, struct nvkm_fifo_chan *); -#define _nvkm_fifo_channel_init _nvkm_namedb_init -#define _nvkm_fifo_channel_fini _nvkm_namedb_fini +struct nvkm_fifo_chan_oclass { + int (*ctor)(struct nvkm_fifo *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; -void _nvkm_fifo_channel_dtor(struct nvkm_object *); -int _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *); -u32 _nvkm_fifo_channel_rd32(struct nvkm_object *, u64); -void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32); -int _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **); +int g84_fifo_chan_ntfy(struct nvkm_fifo_chan *, u32, struct nvkm_event **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c index f2b4a96f87940..a7e5dfae38337 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c @@ -25,38 +25,86 @@ #include #include +#include #include +#include + int -g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) +g84_fifo_chan_ntfy(struct nvkm_fifo_chan *chan, u32 type, + struct nvkm_event **pevent) { - struct nv50_fifo *fifo = (void *)parent->engine; - struct nv50_fifo_base *base = (void *)parent->parent; - struct nv50_fifo_chan *chan = (void *)parent; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 addr, save, engn; - bool done; + switch (type) { + case G82_CHANNEL_DMA_V0_NTFY_UEVENT: + *pevent = &chan->fifo->uevent; + return 0; + default: + break; + } + return -EINVAL; +} - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break; +static int +g84_fifo_chan_engine(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVDEV_ENGINE_GR : return 0; + case NVDEV_ENGINE_MPEG : + case NVDEV_ENGINE_MSPPP : return 1; + case NVDEV_ENGINE_CE0 : return 2; case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: engn = 3; addr = 0x0040; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break; + case NVDEV_ENGINE_MSPDEC: return 3; + case NVDEV_ENGINE_CIPHER: + case NVDEV_ENGINE_SEC : return 4; case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : engn = 5; addr = 0x0080; break; + case NVDEV_ENGINE_MSVLD : return 5; + default: + WARN_ON(1); + return 0; + } +} + +static int +g84_fifo_chan_engine_addr(struct nvkm_engine *engine) +{ + switch (engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : return -1; + case NVDEV_ENGINE_GR : return 0x0020; + case NVDEV_ENGINE_VP : + case NVDEV_ENGINE_MSPDEC: return 0x0040; + case NVDEV_ENGINE_MPEG : + case NVDEV_ENGINE_MSPPP : return 0x0060; + case NVDEV_ENGINE_BSP : + case NVDEV_ENGINE_MSVLD : return 0x0080; case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : engn = 4; addr = 0x00a0; break; - case NVDEV_ENGINE_CE0 : engn = 2; addr = 0x00c0; break; + case NVDEV_ENGINE_SEC : return 0x00a0; + case NVDEV_ENGINE_CE0 : return 0x00c0; default: - return -EINVAL; + WARN_ON(1); + return -1; } +} +static int +g84_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + u32 engn, save; + int offset; + bool done; + + offset = g84_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + + engn = g84_fifo_chan_engine(engine); save = nvkm_mask(device, 0x002520, 0x0000003f, 1 << engn); - nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); + nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); done = nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) break; @@ -64,168 +112,179 @@ g84_fifo_context_detach(struct nvkm_object *parent, bool suspend, nvkm_wr32(device, 0x002520, save); if (!done) { nvkm_error(subdev, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); + chan->base.chid, chan->base.object.client->name); if (suspend) return -EBUSY; } - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00000000); - nvkm_wo32(base->eng, addr + 0x04, 0x00000000); - nvkm_wo32(base->eng, addr + 0x08, 0x00000000); - nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); return 0; } int -g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) +g84_fifo_chan_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) { - struct nv50_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *ectx = (void *)object; - u64 limit = ectx->addr + ectx->size - 1; - u64 start = ectx->addr; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0020; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: addr = 0x0040; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : addr = 0x0080; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : addr = 0x00a0; break; - case NVDEV_ENGINE_CE0 : addr = 0x00c0; break; - default: - return -EINVAL; - } + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index]; + u64 limit, start; + int offset; - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00190000); - nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); + offset = g84_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + limit = engn->addr + engn->size - 1; + start = engn->addr; + + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); + nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); + nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); return 0; } +static int +g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + int engn = engine->subdev.index; + + if (g84_fifo_chan_engine_addr(engine) < 0) + return 0; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) { + chan->engn[engn] = nv_gpuobj(object); + return 0; + } + + return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); +} + int -g84_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) +g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) { - struct nv50_fifo_chan *chan = (void *)parent; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + u32 handle = object->handle; u32 context; - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->node->offset >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break; - case NVDEV_ENGINE_ME : - case NVDEV_ENGINE_CE0 : context |= 0x00300000; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : - case NVDEV_ENGINE_VIC : context |= 0x00500000; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break; - default: - return -EINVAL; - } + switch (object->engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context = 0x00000000; break; + case NVDEV_ENGINE_GR : context = 0x00100000; break; + case NVDEV_ENGINE_MPEG : + case NVDEV_ENGINE_MSPPP : context = 0x00200000; break; + case NVDEV_ENGINE_ME : + case NVDEV_ENGINE_CE0 : context = 0x00300000; break; + case NVDEV_ENGINE_VP : + case NVDEV_ENGINE_MSPDEC: context = 0x00400000; break; + case NVDEV_ENGINE_CIPHER: + case NVDEV_ENGINE_SEC : + case NVDEV_ENGINE_VIC : context = 0x00500000; break; + case NVDEV_ENGINE_BSP : + case NVDEV_ENGINE_MSVLD : context = 0x00600000; break; + default: + WARN_ON(1); + return -EINVAL; } - return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); + return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); } -int -g84_fifo_chan_init(struct nvkm_object *object) +static void +g84_fifo_chan_init(struct nvkm_fifo_chan *base) { - struct nv50_fifo *fifo = (void *)object->engine; - struct nv50_fifo_base *base = (void *)object->parent; - struct nv50_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *ramfc = base->ramfc; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; + u64 addr = chan->ramfc->addr >> 8; u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); nv50_fifo_runlist_update(fifo); - return 0; } -static int -g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_fifo_chan_func +g84_fifo_chan_func = { + .dtor = nv50_fifo_chan_dtor, + .init = g84_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .ntfy = g84_fifo_chan_ntfy, + .engine_ctor = g84_fifo_chan_engine_ctor, + .engine_dtor = nv50_fifo_chan_engine_dtor, + .engine_init = g84_fifo_chan_engine_init, + .engine_fini = g84_fifo_chan_engine_fini, + .object_ctor = g84_fifo_chan_object_ctor, + .object_dtor = nv50_fifo_chan_object_dtor, +}; + +int +g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, + const struct nvkm_oclass *oclass, + struct nv50_fifo_chan *chan) { - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct nv50_fifo_base *base; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); + ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base, + 0x10000, 0x1000, false, vm, push, + (1ULL << NVDEV_ENGINE_BSP) | + (1ULL << NVDEV_ENGINE_CE0) | + (1ULL << NVDEV_ENGINE_CIPHER) | + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_ME) | + (1ULL << NVDEV_ENGINE_MPEG) | + (1ULL << NVDEV_ENGINE_MSPDEC) | + (1ULL << NVDEV_ENGINE_MSPPP) | + (1ULL << NVDEV_ENGINE_MSVLD) | + (1ULL << NVDEV_ENGINE_SEC) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_VIC) | + (1ULL << NVDEV_ENGINE_VP), + 0, 0xc00000, 0x2000, oclass, &chan->base); + chan->fifo = fifo; if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x0200, 0, true, &base->base.gpuobj, - &base->eng); + ret = nvkm_gpuobj_new(device, 0x0200, 0, true, chan->base.inst, + &chan->eng); if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, - &base->pgd); + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, + &chan->pgd); if (ret) return ret; - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, chan->base.inst, + &chan->cache); if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x1000, 0x400, true, &base->base.gpuobj, - &base->cache); + ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, chan->base.inst, + &chan->ramfc); if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x100, 0x100, true, &base->base.gpuobj, - &base->ramfc); + ret = nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); if (ret) return ret; - return 0; + return nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); } - -struct nvkm_oclass -g84_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_fifo_context_ctor, - .dtor = nv50_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h index 99324222dadec..413288597e04c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h @@ -1,23 +1,24 @@ #ifndef __GF100_FIFO_CHAN_H__ #define __GF100_FIFO_CHAN_H__ +#define gf100_fifo_chan(p) container_of((p), struct gf100_fifo_chan, base) #include "chan.h" #include "gf100.h" -struct gf100_fifo_base { - struct nvkm_fifo_base base; +struct gf100_fifo_chan { + struct nvkm_fifo_chan base; + struct gf100_fifo *fifo; + + struct list_head head; + bool killed; + struct nvkm_gpuobj *pgd; struct nvkm_vm *vm; -}; -struct gf100_fifo_chan { - struct nvkm_fifo_chan base; - enum { - STOPPED, - RUNNING, - KILLED - } state; + struct { + struct nvkm_gpuobj *inst; + struct nvkm_vma vma; + } engn[NVDEV_SUBDEV_NR]; }; -extern struct nvkm_oclass gf100_fifo_cclass; -extern struct nvkm_oclass gf100_fifo_sclass[]; +extern const struct nvkm_fifo_chan_oclass gf100_fifo_gpfifo_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h index 3490cb6d8bd3e..2b9d8bfc7fd7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h @@ -1,27 +1,29 @@ #ifndef __GK104_FIFO_CHAN_H__ #define __GK104_FIFO_CHAN_H__ +#define gk104_fifo_chan(p) container_of((p), struct gk104_fifo_chan, base) #include "chan.h" #include "gk104.h" -struct gk104_fifo_base { - struct nvkm_fifo_base base; +struct gk104_fifo_chan { + struct nvkm_fifo_chan base; + struct gk104_fifo *fifo; + int engine; + + struct list_head head; + bool killed; + struct nvkm_gpuobj *pgd; struct nvkm_vm *vm; -}; -struct gk104_fifo_chan { - struct nvkm_fifo_chan base; - u32 engine; - enum { - STOPPED, - RUNNING, - KILLED - } state; + struct { + struct nvkm_gpuobj *inst; + struct nvkm_vma vma; + } engn[NVDEV_SUBDEV_NR]; }; -extern struct nvkm_oclass gk104_fifo_cclass; -extern struct nvkm_oclass gk104_fifo_sclass[]; -extern struct nvkm_ofuncs gk104_fifo_chan_ofuncs; +int gk104_fifo_gpfifo_new(struct nvkm_fifo *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); -extern struct nvkm_oclass gm204_fifo_sclass[]; +extern const struct nvkm_fifo_chan_oclass gk104_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass gm204_fifo_gpfifo_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h index 028212df41bcd..ac62a6404f873 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h @@ -1,24 +1,24 @@ #ifndef __NV04_FIFO_CHAN_H__ #define __NV04_FIFO_CHAN_H__ +#define nv04_fifo_chan(p) container_of((p), struct nv04_fifo_chan, base) #include "chan.h" #include "nv04.h" struct nv04_fifo_chan { struct nvkm_fifo_chan base; - u32 subc[8]; + struct nv04_fifo *fifo; u32 ramfc; + struct nvkm_gpuobj *engn[NVDEV_SUBDEV_NR]; }; -int nv04_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); -void nv04_fifo_object_detach(struct nvkm_object *, int); +extern const struct nvkm_fifo_chan_func nv04_fifo_dma_func; +void *nv04_fifo_dma_dtor(struct nvkm_fifo_chan *); +void nv04_fifo_dma_init(struct nvkm_fifo_chan *); +void nv04_fifo_dma_fini(struct nvkm_fifo_chan *); +void nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *, int); -void nv04_fifo_chan_dtor(struct nvkm_object *); -int nv04_fifo_chan_init(struct nvkm_object *); -int nv04_fifo_chan_fini(struct nvkm_object *, bool suspend); - -extern struct nvkm_oclass nv04_fifo_cclass; -extern struct nvkm_oclass nv04_fifo_sclass[]; -extern struct nvkm_oclass nv10_fifo_sclass[]; -extern struct nvkm_oclass nv17_fifo_sclass[]; -extern struct nvkm_oclass nv40_fifo_sclass[]; +extern const struct nvkm_fifo_chan_oclass nv04_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv10_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv17_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv40_fifo_dma_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c index aeaba7b9bcae6..2a25019ce0f47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c @@ -25,27 +25,37 @@ #include #include +#include #include -int -nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) +static int +nv50_fifo_chan_engine_addr(struct nvkm_engine *engine) { - struct nv50_fifo *fifo = (void *)parent->engine; - struct nv50_fifo_base *base = (void *)parent->parent; - struct nv50_fifo_chan *chan = (void *)parent; + switch (engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : return -1; + case NVDEV_ENGINE_GR : return 0x0000; + case NVDEV_ENGINE_MPEG : return 0x0060; + default: + WARN_ON(1); + return -1; + } +} + +static int +nv50_fifo_chan_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - u32 addr, me; - int ret = 0; + int offset, ret = 0; + u32 me; - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0000; break; - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - default: - return -EINVAL; - } + offset = nv50_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; /* HW bug workaround: * @@ -62,101 +72,124 @@ nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend, me = nvkm_mask(device, 0x00b860, 0x00000001, 0x00000001); /* do the kickoff... */ - nvkm_wr32(device, 0x0032fc, nv_gpuobj(base)->addr >> 12); + nvkm_wr32(device, 0x0032fc, chan->base.inst->addr >> 12); if (nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x0032fc) != 0xffffffff) break; ) < 0) { nvkm_error(subdev, "channel %d [%s] unload timeout\n", - chan->base.chid, nvkm_client_name(chan)); + chan->base.chid, chan->base.object.client->name); if (suspend) ret = -EBUSY; } nvkm_wr32(device, 0x00b860, me); if (ret == 0) { - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00000000); - nvkm_wo32(base->eng, addr + 0x04, 0x00000000); - nvkm_wo32(base->eng, addr + 0x08, 0x00000000); - nvkm_wo32(base->eng, addr + 0x0c, 0x00000000); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x04, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x08, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x0c, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); } return ret; } -int -nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object) +static int +nv50_fifo_chan_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) { - struct nv50_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *ectx = (void *)object; - u64 limit = ectx->addr + ectx->size - 1; - u64 start = ectx->addr; - u32 addr; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0000; break; - case NVDEV_ENGINE_MPEG : addr = 0x0060; break; - default: - return -EINVAL; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nvkm_gpuobj *engn = chan->engn[engine->subdev.index]; + u64 limit, start; + int offset; + + offset = nv50_fifo_chan_engine_addr(engine); + if (offset < 0) + return 0; + limit = engn->addr + engn->size - 1; + start = engn->addr; + + nvkm_kmap(chan->eng); + nvkm_wo32(chan->eng, offset + 0x00, 0x00190000); + nvkm_wo32(chan->eng, offset + 0x04, lower_32_bits(limit)); + nvkm_wo32(chan->eng, offset + 0x08, lower_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x0c, upper_32_bits(limit) << 24 | + upper_32_bits(start)); + nvkm_wo32(chan->eng, offset + 0x10, 0x00000000); + nvkm_wo32(chan->eng, offset + 0x14, 0x00000000); + nvkm_done(chan->eng); + return 0; +} + +void +nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + if (!chan->engn[engine->subdev.index] || + chan->engn[engine->subdev.index]->object.oclass) { + chan->engn[engine->subdev.index] = NULL; + return; } + nvkm_gpuobj_del(&chan->engn[engine->subdev.index]); +} - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; - - nvkm_kmap(base->eng); - nvkm_wo32(base->eng, addr + 0x00, 0x00190000); - nvkm_wo32(base->eng, addr + 0x04, lower_32_bits(limit)); - nvkm_wo32(base->eng, addr + 0x08, lower_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 | - upper_32_bits(start)); - nvkm_wo32(base->eng, addr + 0x10, 0x00000000); - nvkm_wo32(base->eng, addr + 0x14, 0x00000000); - nvkm_done(base->eng); - return 0; +static int +nv50_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) +{ + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + int engn = engine->subdev.index; + + if (nv50_fifo_chan_engine_addr(engine) < 0) + return 0; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) { + chan->engn[engn] = nv_gpuobj(object); + return 0; + } + + return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); } void -nv50_fifo_object_detach(struct nvkm_object *parent, int cookie) +nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *base, int cookie) { - struct nv50_fifo_chan *chan = (void *)parent; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); nvkm_ramht_remove(chan->ramht, cookie); } -int -nv50_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) +static int +nv50_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) { - struct nv50_fifo_chan *chan = (void *)parent; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + u32 handle = object->handle; u32 context; - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->node->offset >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; - default: - return -EINVAL; - } + switch (object->engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context = 0x00000000; break; + case NVDEV_ENGINE_GR : context = 0x00100000; break; + case NVDEV_ENGINE_MPEG : context = 0x00200000; break; + default: + WARN_ON(1); + return -EINVAL; } - return nvkm_ramht_insert(chan->ramht, NULL, 0, 0, handle, context); + return nvkm_ramht_insert(chan->ramht, object, 0, 4, handle, context); } -int -nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) +void +nv50_fifo_chan_fini(struct nvkm_fifo_chan *base) { - struct nv50_fifo *fifo = (void *)object->engine; - struct nv50_fifo_chan *chan = (void *)object; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; u32 chid = chan->base.chid; @@ -164,96 +197,84 @@ nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend) nvkm_mask(device, 0x002600 + (chid * 4), 0x80000000, 0x00000000); nv50_fifo_runlist_update(fifo); nvkm_wr32(device, 0x002600 + (chid * 4), 0x00000000); - - return nvkm_fifo_channel_fini(&chan->base, suspend); } -int -nv50_fifo_chan_init(struct nvkm_object *object) +static void +nv50_fifo_chan_init(struct nvkm_fifo_chan *base) { - struct nv50_fifo *fifo = (void *)object->engine; - struct nv50_fifo_base *base = (void *)object->parent; - struct nv50_fifo_chan *chan = (void *)object; - struct nvkm_gpuobj *ramfc = base->ramfc; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + struct nv50_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; + u64 addr = chan->ramfc->addr >> 12; u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12); + nvkm_wr32(device, 0x002600 + (chid * 4), 0x80000000 | addr); nv50_fifo_runlist_update(fifo); - return 0; } -void -nv50_fifo_chan_dtor(struct nvkm_object *object) +void * +nv50_fifo_chan_dtor(struct nvkm_fifo_chan *base) { - struct nv50_fifo_chan *chan = (void *)object; + struct nv50_fifo_chan *chan = nv50_fifo_chan(base); + nvkm_vm_ref(NULL, &chan->vm, chan->pgd); nvkm_ramht_del(&chan->ramht); - nvkm_fifo_channel_destroy(&chan->base); + nvkm_gpuobj_del(&chan->pgd); + nvkm_gpuobj_del(&chan->eng); + nvkm_gpuobj_del(&chan->cache); + nvkm_gpuobj_del(&chan->ramfc); + return chan; } -void -nv50_fifo_context_dtor(struct nvkm_object *object) -{ - struct nv50_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_del(&base->pgd); - nvkm_gpuobj_del(&base->eng); - nvkm_gpuobj_del(&base->ramfc); - nvkm_gpuobj_del(&base->cache); - nvkm_fifo_context_destroy(&base->base); -} +static const struct nvkm_fifo_chan_func +nv50_fifo_chan_func = { + .dtor = nv50_fifo_chan_dtor, + .init = nv50_fifo_chan_init, + .fini = nv50_fifo_chan_fini, + .engine_ctor = nv50_fifo_chan_engine_ctor, + .engine_dtor = nv50_fifo_chan_engine_dtor, + .engine_init = nv50_fifo_chan_engine_init, + .engine_fini = nv50_fifo_chan_engine_fini, + .object_ctor = nv50_fifo_chan_object_ctor, + .object_dtor = nv50_fifo_chan_object_dtor, +}; -static int -nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, + const struct nvkm_oclass *oclass, + struct nv50_fifo_chan *chan) { - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct nv50_fifo_base *base; + struct nvkm_device *device = fifo->base.engine.subdev.device; int ret; - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); + ret = nvkm_fifo_chan_ctor(&nv50_fifo_chan_func, &fifo->base, + 0x10000, 0x1000, false, vm, push, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG), + 0, 0xc00000, 0x2000, oclass, &chan->base); + chan->fifo = fifo; if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, &base->base.gpuobj, - &base->ramfc); + ret = nvkm_gpuobj_new(device, 0x0200, 0x1000, true, chan->base.inst, + &chan->ramfc); if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x1200, 0, true, &base->base.gpuobj, - &base->eng); + ret = nvkm_gpuobj_new(device, 0x1200, 0, true, chan->base.inst, + &chan->eng); if (ret) return ret; - ret = nvkm_gpuobj_new(device, 0x4000, 0, false, &base->base.gpuobj, - &base->pgd); + ret = nvkm_gpuobj_new(device, 0x4000, 0, false, chan->base.inst, + &chan->pgd); if (ret) return ret; - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); + ret = nvkm_ramht_new(device, 0x8000, 16, chan->base.inst, &chan->ramht); if (ret) return ret; - return 0; + return nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); } - -struct nvkm_oclass -nv50_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fifo_context_ctor, - .dtor = nv50_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h index c4f2f1ff4c9e9..7ef6bc2e27ecf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h @@ -1,42 +1,35 @@ #ifndef __NV50_FIFO_CHAN_H__ #define __NV50_FIFO_CHAN_H__ +#define nv50_fifo_chan(p) container_of((p), struct nv50_fifo_chan, base) #include "chan.h" #include "nv50.h" -struct nv50_fifo_base { - struct nvkm_fifo_base base; +struct nv50_fifo_chan { + struct nv50_fifo *fifo; + struct nvkm_fifo_chan base; + struct nvkm_gpuobj *ramfc; struct nvkm_gpuobj *cache; struct nvkm_gpuobj *eng; struct nvkm_gpuobj *pgd; + struct nvkm_ramht *ramht; struct nvkm_vm *vm; -}; -struct nv50_fifo_chan { - struct nvkm_fifo_chan base; - u32 subc[8]; - struct nvkm_ramht *ramht; + struct nvkm_gpuobj *engn[NVDEV_SUBDEV_NR]; }; -extern struct nvkm_oclass nv50_fifo_cclass; -extern struct nvkm_oclass nv50_fifo_sclass[]; -void nv50_fifo_context_dtor(struct nvkm_object *); -void nv50_fifo_chan_dtor(struct nvkm_object *); -int nv50_fifo_chan_init(struct nvkm_object *); -int nv50_fifo_chan_fini(struct nvkm_object *, bool); -int nv50_fifo_context_attach(struct nvkm_object *, struct nvkm_object *); -int nv50_fifo_context_detach(struct nvkm_object *, bool, - struct nvkm_object *); -int nv50_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); -void nv50_fifo_object_detach(struct nvkm_object *, int); -extern struct nvkm_ofuncs nv50_fifo_ofuncs_ind; +int nv50_fifo_chan_ctor(struct nv50_fifo *, u64 vm, u64 push, + const struct nvkm_oclass *, struct nv50_fifo_chan *); +void *nv50_fifo_chan_dtor(struct nvkm_fifo_chan *); +void nv50_fifo_chan_fini(struct nvkm_fifo_chan *); +void nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *, struct nvkm_engine *); +void nv50_fifo_chan_object_dtor(struct nvkm_fifo_chan *, int); + +int g84_fifo_chan_ctor(struct nv50_fifo *, u64 vm, u64 push, + const struct nvkm_oclass *, struct nv50_fifo_chan *); -extern struct nvkm_oclass g84_fifo_cclass; -extern struct nvkm_oclass g84_fifo_sclass[]; -int g84_fifo_chan_init(struct nvkm_object *); -int g84_fifo_context_attach(struct nvkm_object *, struct nvkm_object *); -int g84_fifo_context_detach(struct nvkm_object *, bool, - struct nvkm_object *); -int g84_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32); -extern struct nvkm_ofuncs g84_fifo_ofuncs_ind; +extern const struct nvkm_fifo_chan_oclass nv50_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass nv50_fifo_gpfifo_oclass; +extern const struct nvkm_fifo_chan_oclass g84_fifo_dma_oclass; +extern const struct nvkm_fifo_chan_oclass g84_fifo_gpfifo_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c index 2016a9884b38c..a5ca52c7b74ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmag84.c @@ -30,15 +30,14 @@ #include static int -g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +g84_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv50_channel_dma_v0 v0; } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo *fifo = nv50_fifo(base); struct nv50_fifo_chan *chan; int ret; @@ -48,80 +47,47 @@ g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, "pushbuf %llx offset %016llx\n", args->v0.version, args->v0.vm, args->v0.pushbuf, args->v0.offset); - if (args->v0.vm) - return -ENOENT; + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_VP) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_VIC), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); + ret = g84_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); if (ret) return ret; - nv_parent(chan)->context_attach = g84_fifo_context_attach; - nv_parent(chan)->context_detach = g84_fifo_context_detach; - nv_parent(chan)->object_attach = g84_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; + args->v0.chid = chan->base.chid; - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - nvkm_done(base->ramfc); + nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); + nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12); + nvkm_done(chan->ramfc); return 0; } -static struct nvkm_ofuncs -g84_fifo_ofuncs_dma = { - .ctor = g84_fifo_chan_ctor_dma, - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -g84_fifo_sclass[] = { - { G82_CHANNEL_DMA, &g84_fifo_ofuncs_dma }, - { G82_CHANNEL_GPFIFO, &g84_fifo_ofuncs_ind }, - {} +const struct nvkm_fifo_chan_oclass +g84_fifo_dma_oclass = { + .base.oclass = G82_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = g84_fifo_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c index 8cc87103a369a..eafa87886643e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c @@ -31,74 +31,51 @@ #include #include -int -nv04_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) -{ - nv_engctx(object)->addr = nvkm_fifo_chan(parent)->chid; - return 0; -} - void -nv04_fifo_object_detach(struct nvkm_object *parent, int cookie) +nv04_fifo_dma_object_dtor(struct nvkm_fifo_chan *base, int cookie) { - struct nv04_fifo *fifo = (void *)parent->engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - mutex_lock(&nv_subdev(fifo)->mutex); + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; nvkm_ramht_remove(imem->ramht, cookie); - mutex_unlock(&nv_subdev(fifo)->mutex); } -int -nv04_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) +static int +nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) { - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - u32 context, chid = chan->base.chid; - int ret; - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->addr >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00010000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00020000; - break; - default: - return -EINVAL; - } + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; + u32 context = 0x80000000 | chan->base.chid << 24; + u32 handle = object->handle; + int hash; + + switch (object->engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00010000; break; + case NVDEV_ENGINE_MPEG : context |= 0x00020000; break; + default: + WARN_ON(1); + return -EINVAL; } - context |= 0x80000000; /* valid */ - context |= chid << 24; - - mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); - mutex_unlock(&nv_subdev(fifo)->mutex); - return ret; + mutex_lock(&chan->fifo->base.engine.subdev.mutex); + hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, + handle, context); + mutex_unlock(&chan->fifo->base.engine.subdev.mutex); + return hash; } -int -nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) +void +nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) { - struct nv04_fifo *fifo = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_memory *fctx = device->imem->ramfc; struct ramfc_desc *c; unsigned long flags; + u32 mask = fifo->base.nr - 1; u32 data = chan->ramfc; u32 chid; @@ -107,7 +84,7 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) nvkm_wr32(device, NV03_PFIFO_CACHES, 0); /* if this channel is active, replace it with a null context */ - chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & mask; if (chid == chan->base.chid) { nvkm_mask(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0); nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); @@ -129,7 +106,7 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) nvkm_wr32(device, NV03_PFIFO_CACHE1_GET, 0); nvkm_wr32(device, NV03_PFIFO_CACHE1_PUT, 0); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, mask); nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); } @@ -138,35 +115,26 @@ nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend) nvkm_mask(device, NV04_PFIFO_MODE, 1 << chan->base.chid, 0); nvkm_wr32(device, NV03_PFIFO_CACHES, 1); spin_unlock_irqrestore(&fifo->base.lock, flags); - - return nvkm_fifo_channel_fini(&chan->base, suspend); } -int -nv04_fifo_chan_init(struct nvkm_object *object) +void +nv04_fifo_dma_init(struct nvkm_fifo_chan *base) { - struct nv04_fifo *fifo = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; u32 mask = 1 << chan->base.chid; unsigned long flags; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; - spin_lock_irqsave(&fifo->base.lock, flags); nvkm_mask(device, NV04_PFIFO_MODE, mask, mask); spin_unlock_irqrestore(&fifo->base.lock, flags); - return 0; } -void -nv04_fifo_chan_dtor(struct nvkm_object *object) +void * +nv04_fifo_dma_dtor(struct nvkm_fifo_chan *base) { - struct nv04_fifo *fifo = (void *)object->engine; - struct nv04_fifo_chan *chan = (void *)object; + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; struct ramfc_desc *c = fifo->ramfc_desc; @@ -175,22 +143,30 @@ nv04_fifo_chan_dtor(struct nvkm_object *object) nvkm_wo32(imem->ramfc, chan->ramfc + c->ctxp, 0x00000000); } while ((++c)->bits); nvkm_done(imem->ramfc); - - nvkm_fifo_channel_destroy(&chan->base); + return chan; } +const struct nvkm_fifo_chan_func +nv04_fifo_dma_func = { + .dtor = nv04_fifo_dma_dtor, + .init = nv04_fifo_dma_init, + .fini = nv04_fifo_dma_fini, + .object_ctor = nv04_fifo_dma_object_ctor, + .object_dtor = nv04_fifo_dma_object_dtor, +}; + static int -nv04_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; int ret; nvif_ioctl(parent, "create channel dma size %d\n", size); @@ -198,29 +174,32 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR), &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_SW), + 0, 0x800000, 0x10000, oclass, &chan->base); + chan->fifo = fifo; if (ret) return ret; args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; nvkm_kmap(imem->ramfc); nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x08, chan->base.push->addr >> 4); nvkm_wo32(imem->ramfc, chan->ramfc + 0x10, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | @@ -232,51 +211,10 @@ nv04_fifo_chan_ctor(struct nvkm_object *parent, return 0; } -static struct nvkm_ofuncs -nv04_fifo_ofuncs = { - .ctor = nv04_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -nv04_fifo_sclass[] = { - { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs }, - {} -}; - -int -nv04_fifo_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv04_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - return 0; -} - -struct nvkm_oclass -nv04_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, +const struct nvkm_fifo_chan_oclass +nv04_fifo_dma_oclass = { + .base.oclass = NV03_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv04_fifo_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c index a542515e63f0b..1ad16205305f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c @@ -31,17 +31,17 @@ #include static int -nv10_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv10_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; int ret; nvif_ioctl(parent, "create channel dma size %d\n", size); @@ -49,29 +49,32 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR), &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_SW), + 0, 0x800000, 0x10000, oclass, &chan->base); + chan->fifo = fifo; if (ret) return ret; args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 32; nvkm_kmap(imem->ramfc); nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | @@ -83,20 +86,10 @@ nv10_fifo_chan_ctor(struct nvkm_object *parent, return 0; } -static struct nvkm_ofuncs -nv10_fifo_ofuncs = { - .ctor = nv10_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -nv10_fifo_sclass[] = { - { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs }, - {} +const struct nvkm_fifo_chan_oclass +nv10_fifo_dma_oclass = { + .base.oclass = NV10_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv10_fifo_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c index d0ece53a750b9..2fbb9d4f0900e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c @@ -31,17 +31,17 @@ #include static int -nv17_fifo_chan_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv17_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; int ret; nvif_ioctl(parent, "create channel dma size %d\n", size); @@ -49,31 +49,33 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000, - 0x10000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */ - &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG) | /* NV31- */ + (1ULL << NVDEV_ENGINE_SW), + 0, 0x800000, 0x10000, oclass, &chan->base); + chan->fifo = fifo; if (ret) return ret; args->v0.chid = chan->base.chid; - - nv_parent(chan)->object_attach = nv04_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; - nv_parent(chan)->context_attach = nv04_fifo_context_attach; chan->ramfc = chan->base.chid * 64; nvkm_kmap(imem->ramfc); nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); nvkm_wo32(imem->ramfc, chan->ramfc + 0x14, NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | @@ -85,20 +87,10 @@ nv17_fifo_chan_ctor(struct nvkm_object *parent, return 0; } -static struct nvkm_ofuncs -nv17_fifo_ofuncs = { - .ctor = nv17_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -nv17_fifo_sclass[] = { - { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs }, - {} +const struct nvkm_fifo_chan_oclass +nv17_fifo_dma_oclass = { + .base.oclass = NV17_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv17_fifo_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c index cd3503cb6837e..b46a3b3cd0924 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c @@ -31,36 +31,47 @@ #include #include +static bool +nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx) +{ + switch (engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW: + return false; + case NVDEV_ENGINE_GR: + *reg = 0x0032e0; + *ctx = 0x38; + return true; + case NVDEV_ENGINE_MPEG: + *reg = 0x00330c; + *ctx = 0x54; + return true; + default: + WARN_ON(1); + return false; + } +} + static int -nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *engctx) +nv40_fifo_dma_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) { - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; unsigned long flags; u32 reg, ctx; + int chid; - switch (nv_engidx(engctx->engine)) { - case NVDEV_ENGINE_SW: + if (!nv40_fifo_dma_engine(engine, ®, &ctx)) return 0; - case NVDEV_ENGINE_GR: - reg = 0x32e0; - ctx = 0x38; - break; - case NVDEV_ENGINE_MPEG: - reg = 0x330c; - ctx = 0x54; - break; - default: - return -EINVAL; - } spin_lock_irqsave(&fifo->base.lock, flags); nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) + chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1); + if (chid == chan->base.chid) nvkm_wr32(device, reg, 0x00000000); nvkm_kmap(imem->ramfc); nvkm_wo32(imem->ramfc, chan->ramfc + ctx, 0x00000000); @@ -72,38 +83,29 @@ nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend, } static int -nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) +nv40_fifo_dma_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) { - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nv04_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; unsigned long flags; - u32 reg, ctx; + u32 inst, reg, ctx; + int chid; - switch (nv_engidx(engctx->engine)) { - case NVDEV_ENGINE_SW: + if (!nv40_fifo_dma_engine(engine, ®, &ctx)) return 0; - case NVDEV_ENGINE_GR: - reg = 0x32e0; - ctx = 0x38; - break; - case NVDEV_ENGINE_MPEG: - reg = 0x330c; - ctx = 0x54; - break; - default: - return -EINVAL; - } + inst = chan->engn[engine->subdev.index]->addr >> 4; spin_lock_irqsave(&fifo->base.lock, flags); - nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4; nvkm_mask(device, 0x002500, 0x00000001, 0x00000000); - if ((nvkm_rd32(device, 0x003204) & fifo->base.max) == chan->base.chid) - nvkm_wr32(device, reg, nv_engctx(engctx)->addr); + chid = nvkm_rd32(device, 0x003204) & (fifo->base.nr - 1); + if (chid == chan->base.chid) + nvkm_wr32(device, reg, inst); nvkm_kmap(imem->ramfc); - nvkm_wo32(imem->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr); + nvkm_wo32(imem->ramfc, chan->ramfc + ctx, inst); nvkm_done(imem->ramfc); nvkm_mask(device, 0x002500, 0x00000001, 0x00000001); @@ -111,57 +113,91 @@ nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx) return 0; } +static void +nv40_fifo_dma_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + if (!chan->engn[engine->subdev.index] || + chan->engn[engine->subdev.index]->object.oclass) { + chan->engn[engine->subdev.index] = NULL; + return; + } + nvkm_gpuobj_del(&chan->engn[engine->subdev.index]); +} + static int -nv40_fifo_object_attach(struct nvkm_object *parent, - struct nvkm_object *object, u32 handle) +nv40_fifo_dma_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) { - struct nv04_fifo *fifo = (void *)parent->engine; - struct nv04_fifo_chan *chan = (void *)parent; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - u32 context, chid = chan->base.chid; - int ret; + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + const int engn = engine->subdev.index; + u32 reg, ctx; - if (nv_iclass(object, NV_GPUOBJ_CLASS)) - context = nv_gpuobj(object)->addr >> 4; - else - context = 0x00000004; /* just non-zero */ - - if (object->engine) { - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: - context |= 0x00000000; - break; - case NVDEV_ENGINE_GR: - context |= 0x00100000; - break; - case NVDEV_ENGINE_MPEG: - context |= 0x00200000; - break; - default: - return -EINVAL; - } + if (!nv40_fifo_dma_engine(engine, ®, &ctx)) + return 0; + + if (nv_iclass(object, NV_GPUOBJ_CLASS)) { + chan->engn[engn] = nv_gpuobj(object); + return 0; } - context |= chid << 23; + return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); +} - mutex_lock(&nv_subdev(fifo)->mutex); - ret = nvkm_ramht_insert(imem->ramht, NULL, chid, 0, handle, context); - mutex_unlock(&nv_subdev(fifo)->mutex); - return ret; +static int +nv40_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, + struct nvkm_object *object) +{ + struct nv04_fifo_chan *chan = nv04_fifo_chan(base); + struct nvkm_instmem *imem = chan->fifo->base.engine.subdev.device->imem; + u32 context = chan->base.chid << 23; + u32 handle = object->handle; + int hash; + + switch (object->engine->subdev.index) { + case NVDEV_ENGINE_DMAOBJ: + case NVDEV_ENGINE_SW : context |= 0x00000000; break; + case NVDEV_ENGINE_GR : context |= 0x00100000; break; + case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; + default: + WARN_ON(1); + return -EINVAL; + } + + mutex_lock(&chan->fifo->base.engine.subdev.mutex); + hash = nvkm_ramht_insert(imem->ramht, object, chan->base.chid, 4, + handle, context); + mutex_unlock(&chan->fifo->base.engine.subdev.mutex); + return hash; } +static const struct nvkm_fifo_chan_func +nv40_fifo_dma_func = { + .dtor = nv04_fifo_dma_dtor, + .init = nv04_fifo_dma_init, + .fini = nv04_fifo_dma_fini, + .engine_ctor = nv40_fifo_dma_engine_ctor, + .engine_dtor = nv40_fifo_dma_engine_dtor, + .engine_init = nv40_fifo_dma_engine_init, + .engine_fini = nv40_fifo_dma_engine_fini, + .object_ctor = nv40_fifo_dma_object_ctor, + .object_dtor = nv04_fifo_dma_object_dtor, +}; + static int -nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv03_channel_dma_v0 v0; } *args = data; - struct nv04_fifo *fifo = (void *)engine; - struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct nv04_fifo_chan *chan; + struct nv04_fifo *fifo = nv04_fifo(base); + struct nv04_fifo_chan *chan = NULL; + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_instmem *imem = device->imem; int ret; nvif_ioctl(parent, "create channel dma size %d\n", size); @@ -169,31 +205,33 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvif_ioctl(parent, "create channel dma vers %d pushbuf %llx " "offset %08x\n", args->v0.version, args->v0.pushbuf, args->v0.offset); + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x1000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_fifo_chan_ctor(&nv40_fifo_dma_func, &fifo->base, + 0x1000, 0x1000, false, 0, args->v0.pushbuf, + (1ULL << NVDEV_ENGINE_DMAOBJ) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MPEG) | + (1ULL << NVDEV_ENGINE_SW), + 0, 0xc00000, 0x1000, oclass, &chan->base); + chan->fifo = fifo; if (ret) return ret; args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv40_fifo_context_attach; - nv_parent(chan)->context_detach = nv40_fifo_context_detach; - nv_parent(chan)->object_attach = nv40_fifo_object_attach; - nv_parent(chan)->object_detach = nv04_fifo_object_detach; chan->ramfc = chan->base.chid * 128; nvkm_kmap(imem->ramfc); nvkm_wo32(imem->ramfc, chan->ramfc + 0x00, args->v0.offset); nvkm_wo32(imem->ramfc, chan->ramfc + 0x04, args->v0.offset); - nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4); + nvkm_wo32(imem->ramfc, chan->ramfc + 0x0c, chan->base.push->addr >> 4); nvkm_wo32(imem->ramfc, chan->ramfc + 0x18, 0x30000000 | NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES | NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES | @@ -206,20 +244,10 @@ nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -static struct nvkm_ofuncs -nv40_fifo_ofuncs = { - .ctor = nv40_fifo_chan_ctor, - .dtor = nv04_fifo_chan_dtor, - .init = nv04_fifo_chan_init, - .fini = nv04_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -nv40_fifo_sclass[] = { - { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs }, - {} +const struct nvkm_fifo_chan_oclass +nv40_fifo_dma_oclass = { + .base.oclass = NV40_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv40_fifo_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c index 11a2830992358..6b3b15f12c392 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv50.c @@ -30,15 +30,14 @@ #include static int -nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv50_channel_dma_v0 v0; } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo *fifo = nv50_fifo(base); struct nv50_fifo_chan *chan; int ret; @@ -48,68 +47,45 @@ nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine, "pushbuf %llx offset %016llx\n", args->v0.version, args->v0.vm, args->v0.pushbuf, args->v0.offset); - if (args->v0.vm) - return -ENOENT; + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nv50_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); if (ret) return ret; - chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; - nv_parent(chan)->context_attach = nv50_fifo_context_attach; - nv_parent(chan)->context_detach = nv50_fifo_context_detach; - nv_parent(chan)->object_attach = nv50_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); - if (ret) - return ret; - - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset)); - nvkm_wo32(base->ramfc, 0x3c, 0x003f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x4c, 0xffffffff); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x08, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x0c, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x10, lower_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x14, upper_32_bits(args->v0.offset)); + nvkm_wo32(chan->ramfc, 0x3c, 0x003f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x4c, 0xffffffff); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_done(base->ramfc); + nvkm_done(chan->ramfc); return 0; } -static struct nvkm_ofuncs -nv50_fifo_ofuncs_dma = { - .ctor = nv50_fifo_chan_ctor_dma, - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -nv50_fifo_sclass[] = { - { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma }, - { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind }, - {} +const struct nvkm_fifo_chan_oclass +nv50_fifo_dma_oclass = { + .base.oclass = NV50_CHANNEL_DMA, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_fifo_dma_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index ab0ecc423e684..00fa9d3eff7ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -47,6 +47,15 @@ g84_fifo_uevent_func = { .fini = g84_fifo_uevent_fini, }; +static const struct nvkm_fifo_func +g84_fifo_func = { + .chan = { + &g84_fifo_dma_oclass, + &g84_fifo_gpfifo_oclass, + NULL + }, +}; + static int g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -61,6 +70,8 @@ g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &g84_fifo_func; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, false, &fifo->runlist[0]); if (ret) @@ -77,8 +88,6 @@ g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &g84_fifo_cclass; - nv_engine(fifo)->sclass = g84_fifo_sclass; fifo->base.pause = nv04_fifo_pause; fifo->base.start = nv04_fifo_start; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index b88e7c569c0a0..bdad44e84b920 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -58,28 +58,26 @@ gf100_fifo_uevent_func = { void gf100_fifo_runlist_update(struct gf100_fifo *fifo) { + struct gf100_fifo_chan *chan; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; struct nvkm_memory *cur; - int i, p; + int nr = 0; mutex_lock(&nv_subdev(fifo)->mutex); cur = fifo->runlist.mem[fifo->runlist.active]; fifo->runlist.active = !fifo->runlist.active; nvkm_kmap(cur); - for (i = 0, p = 0; i < 128; i++) { - struct gf100_fifo_chan *chan = (void *)fifo->base.channel[i]; - if (chan && chan->state == RUNNING) { - nvkm_wo32(cur, p + 0, i); - nvkm_wo32(cur, p + 4, 0x00000004); - p += 8; - } + list_for_each_entry(chan, &fifo->chan, head) { + nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid); + nvkm_wo32(cur, (nr * 8) + 4, 0x00000004); + nr++; } nvkm_done(cur); nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); - nvkm_wr32(device, 0x002274, 0x01f00000 | (p >> 3)); + nvkm_wr32(device, 0x002274, 0x01f00000 | nr); if (wait_event_timeout(fifo->runlist.wait, !(nvkm_rd32(device, 0x00227c) & 0x00100000), @@ -166,7 +164,8 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, assert_spin_locked(&fifo->base.lock); nvkm_mask(device, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000); - chan->state = KILLED; + list_del_init(&chan->head); + chan->killed = true; fifo->mask |= 1ULL << nv_engidx(engine); schedule_work(&fifo->fault); @@ -198,11 +197,15 @@ gf100_fifo_intr_sched_ctxsw(struct gf100_fifo *fifo) (void)save; if (busy && unk0 && unk1) { - if (!(chan = (void *)fifo->base.channel[chid])) - continue; - if (!(engine = gf100_fifo_engine(fifo, engn))) - continue; - gf100_fifo_recover(fifo, engine, chan); + list_for_each_entry(chan, &fifo->chan, head) { + if (chan->base.chid == chid) { + engine = gf100_fifo_engine(fifo, engn); + if (!engine) + break; + gf100_fifo_recover(fifo, engine, chan); + break; + } + } } } spin_unlock_irqrestore(&fifo->base.lock, flags); @@ -343,7 +346,8 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) write ? "write" : "read", (u64)vahi << 32 | valo, unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", reason, er ? er->name : "", chan ? chan->chid : -1, - (u64)inst << 12, nvkm_client_name(chan)); + (u64)inst << 12, + chan ? chan->object.client->name : "unknown"); if (engine && chan) gf100_fifo_recover(fifo, engine, (void *)chan); @@ -369,6 +373,8 @@ gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) u32 chid = nvkm_rd32(device, 0x040120 + (unit * 0x2000)) & 0x7f; u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); + struct nvkm_fifo_chan *chan; + unsigned long flags; u32 show= stat; char msg[128]; @@ -381,11 +387,13 @@ gf100_fifo_intr_pbdma(struct gf100_fifo *fifo, int unit) if (show) { nvkm_snprintbf(msg, sizeof(msg), gf100_fifo_pbdma_intr, show); - nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%s] subc %d " - "mthd %04x data %08x\n", - unit, show, msg, chid, - nvkm_client_name_for_fifo_chid(&fifo->base, chid), + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", + unit, show, msg, chid, chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", subc, mthd, data); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } nvkm_wr32(device, 0x0400c0 + (unit * 0x2000), 0x80600008); @@ -579,6 +587,14 @@ gf100_fifo_dtor(struct nvkm_object *object) nvkm_fifo_destroy(&fifo->base); } +static const struct nvkm_fifo_func +gf100_fifo_func = { + .chan = { + &gf100_fifo_gpfifo_oclass, + NULL + }, +}; + static int gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -594,6 +610,9 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &gf100_fifo_func; + + INIT_LIST_HEAD(&fifo->chan); INIT_WORK(&fifo->fault, gf100_fifo_recover_work); ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, @@ -625,8 +644,6 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = gf100_fifo_intr; - nv_engine(fifo)->cclass = &gf100_fifo_cclass; - nv_engine(fifo)->sclass = gf100_fifo_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h index 5190bbc6e1a18..c649ca9b53e3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.h @@ -1,10 +1,15 @@ #ifndef __GF100_FIFO_H__ #define __GF100_FIFO_H__ +#define gf100_fifo(p) container_of((p), struct gf100_fifo, base) #include "priv.h" +#include + struct gf100_fifo { struct nvkm_fifo base; + struct list_head chan; + struct work_struct fault; u64 mask; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 9ab3fd40b7dd9..e7f4679971942 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -32,23 +32,6 @@ #include -#define _(a,b) { (a), ((1ULL << (a)) | (b)) } -static const struct { - u64 subdev; - u64 mask; -} fifo_engine[] = { - _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_CE2)), - _(NVDEV_ENGINE_MSPDEC , 0), - _(NVDEV_ENGINE_MSPPP , 0), - _(NVDEV_ENGINE_MSVLD , 0), - _(NVDEV_ENGINE_CE0 , 0), - _(NVDEV_ENGINE_CE1 , 0), - _(NVDEV_ENGINE_MSENC , 0), -}; -#undef _ -#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) - static void gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index) { @@ -76,28 +59,26 @@ void gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { struct gk104_fifo_engn *engn = &fifo->engine[engine]; + struct gk104_fifo_chan *chan; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; struct nvkm_memory *cur; - int i, p; + int nr = 0; mutex_lock(&nv_subdev(fifo)->mutex); cur = engn->runlist[engn->cur_runlist]; engn->cur_runlist = !engn->cur_runlist; nvkm_kmap(cur); - for (i = 0, p = 0; i < fifo->base.max; i++) { - struct gk104_fifo_chan *chan = (void *)fifo->base.channel[i]; - if (chan && chan->state == RUNNING && chan->engine == engine) { - nvkm_wo32(cur, p + 0, i); - nvkm_wo32(cur, p + 4, 0x00000000); - p += 8; - } + list_for_each_entry(chan, &engn->chan, head) { + nvkm_wo32(cur, (nr * 8) + 0, chan->base.chid); + nvkm_wo32(cur, (nr * 8) + 4, 0x00000000); + nr++; } nvkm_done(cur); nvkm_wr32(device, 0x002270, nvkm_memory_addr(cur) >> 12); - nvkm_wr32(device, 0x002274, (engine << 20) | (p >> 3)); + nvkm_wr32(device, 0x002274, (engine << 20) | nr); if (wait_event_timeout(engn->wait, !(nvkm_rd32(device, 0x002284 + (engine * 0x08)) & 0x00100000), @@ -106,31 +87,13 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) mutex_unlock(&nv_subdev(fifo)->mutex); } -static inline int -gk104_fifo_engidx(struct gk104_fifo *fifo, u32 engn) -{ - switch (engn) { - case NVDEV_ENGINE_GR : - case NVDEV_ENGINE_CE2 : engn = 0; break; - case NVDEV_ENGINE_MSVLD : engn = 1; break; - case NVDEV_ENGINE_MSPPP : engn = 2; break; - case NVDEV_ENGINE_MSPDEC: engn = 3; break; - case NVDEV_ENGINE_CE0 : engn = 4; break; - case NVDEV_ENGINE_CE1 : engn = 5; break; - case NVDEV_ENGINE_MSENC : engn = 6; break; - default: - return -1; - } - - return engn; -} - static inline struct nvkm_engine * gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn) { - if (engn >= ARRAY_SIZE(fifo_engine)) - return NULL; - return nvkm_engine(fifo, fifo_engine[engn].subdev); + u64 subdevs = gk104_fifo_engine_subdev(engn); + if (subdevs) + return nvkm_engine(fifo, __ffs(subdevs)); + return NULL; } static void @@ -149,7 +112,7 @@ gk104_fifo_recover_work(struct work_struct *work) spin_unlock_irqrestore(&fifo->base.lock, flags); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) - engm |= 1 << gk104_fifo_engidx(fifo, engn); + engm |= 1 << gk104_fifo_subdev_engine(engn); nvkm_mask(device, 0x002630, engm, engm); for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) { @@ -157,7 +120,7 @@ gk104_fifo_recover_work(struct work_struct *work) nvkm_subdev_fini(&engine->subdev, false); WARN_ON(nvkm_subdev_init(&engine->subdev)); } - gk104_fifo_runlist_update(fifo, gk104_fifo_engidx(fifo, engn)); + gk104_fifo_runlist_update(fifo, gk104_fifo_subdev_engine(engn)); } nvkm_wr32(device, 0x00262c, engm); @@ -177,7 +140,8 @@ gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, assert_spin_locked(&fifo->base.lock); nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); - chan->state = KILLED; + list_del_init(&chan->head); + chan->killed = true; fifo->mask |= 1ULL << nv_engidx(engine); schedule_work(&fifo->fault); @@ -223,7 +187,7 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) u32 engn; spin_lock_irqsave(&fifo->base.lock, flags); - for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) { + for (engn = 0; engn < ARRAY_SIZE(fifo->engine); engn++) { u32 stat = nvkm_rd32(device, 0x002640 + (engn * 0x04)); u32 busy = (stat & 0x80000000); u32 next = (stat & 0x07ff0000) >> 16; @@ -235,11 +199,15 @@ gk104_fifo_intr_sched_ctxsw(struct gk104_fifo *fifo) (void)save; if (busy && chsw) { - if (!(chan = (void *)fifo->base.channel[chid])) - continue; - if (!(engine = gk104_fifo_engine(fifo, engn))) - continue; - gk104_fifo_recover(fifo, engine, chan); + list_for_each_entry(chan, &fifo->engine[engn].chan, head) { + if (chan->base.chid == chid) { + engine = gk104_fifo_engine(fifo, engn); + if (!engine) + break; + gk104_fifo_recover(fifo, engine, chan); + break; + } + } } } spin_unlock_irqrestore(&fifo->base.lock, flags); @@ -444,7 +412,8 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) write ? "write" : "read", (u64)vahi << 32 | valo, unit, eu ? eu->name : "", client, gpcid, ec ? ec->name : "", reason, er ? er->name : "", chan ? chan->chid : -1, - (u64)inst << 12, nvkm_client_name(chan)); + (u64)inst << 12, + chan ? chan->object.client->name : "unknown"); if (engine && chan) gk104_fifo_recover(fifo, engine, (void *)chan); @@ -498,6 +467,8 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) u32 subc = (addr & 0x00070000) >> 16; u32 mthd = (addr & 0x00003ffc); u32 show = stat; + struct nvkm_fifo_chan *chan; + unsigned long flags; char msg[128]; if (stat & 0x00800000) { @@ -510,11 +481,13 @@ gk104_fifo_intr_pbdma_0(struct gk104_fifo *fifo, int unit) if (show) { nvkm_snprintbf(msg, sizeof(msg), gk104_fifo_pbdma_intr_0, show); - nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%s] subc %d " - "mthd %04x data %08x\n", - unit, show, msg, chid, - nvkm_client_name_for_fifo_chid(&fifo->base, chid), + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + nvkm_error(subdev, "PBDMA%d: %08x [%s] ch %d [%010llx %s] " + "subc %d mthd %04x data %08x\n", + unit, show, msg, chid, chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", subc, mthd, data); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } nvkm_wr32(device, 0x040108 + (unit * 0x2000), stat); @@ -722,7 +695,7 @@ gk104_fifo_dtor(struct nvkm_object *object) nvkm_vm_put(&fifo->user.bar); nvkm_memory_del(&fifo->user.mem); - for (i = 0; i < FIFO_ENGINE_NR; i++) { + for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { nvkm_memory_del(&fifo->engine[i].runlist[1]); nvkm_memory_del(&fifo->engine[i].runlist[0]); } @@ -730,6 +703,14 @@ gk104_fifo_dtor(struct nvkm_object *object) nvkm_fifo_destroy(&fifo->base); } +static const struct nvkm_fifo_func +gk104_fifo_func = { + .chan = { + &gk104_fifo_gpfifo_oclass, + NULL + }, +}; + int gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -747,9 +728,11 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &gk104_fifo_func; + INIT_WORK(&fifo->fault, gk104_fifo_recover_work); - for (i = 0; i < FIFO_ENGINE_NR; i++) { + for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x8000, 0x1000, false, &fifo->engine[i].runlist[0]); @@ -763,6 +746,7 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; init_waitqueue_head(&fifo->engine[i].wait); + INIT_LIST_HEAD(&fifo->engine[i].chan); } ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, @@ -783,8 +767,6 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = gk104_fifo_intr; - nv_engine(fifo)->cclass = &gk104_fifo_cclass; - nv_engine(fifo)->sclass = gk104_fifo_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index b71abef84349b..1103e6b1ee5a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -1,11 +1,15 @@ #ifndef __GK104_FIFO_H__ #define __GK104_FIFO_H__ +#define gk104_fifo(p) container_of((p), struct gk104_fifo, base) #include "priv.h" +#include + struct gk104_fifo_engn { struct nvkm_memory *runlist[2]; int cur_runlist; wait_queue_head_t wait; + struct list_head chan; }; struct gk104_fifo { @@ -38,4 +42,42 @@ void gk104_fifo_runlist_update(struct gk104_fifo *, u32 engine); int gm204_fifo_ctor(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, void *, u32, struct nvkm_object **); + +static inline u64 +gk104_fifo_engine_subdev(int engine) +{ + switch (engine) { + case 0: return (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_SW) | + (1ULL << NVDEV_ENGINE_CE2); + case 1: return (1ULL << NVDEV_ENGINE_MSPDEC); + case 2: return (1ULL << NVDEV_ENGINE_MSPPP); + case 3: return (1ULL << NVDEV_ENGINE_MSVLD); + case 4: return (1ULL << NVDEV_ENGINE_CE0); + case 5: return (1ULL << NVDEV_ENGINE_CE1); + case 6: return (1ULL << NVDEV_ENGINE_MSENC); + default: + WARN_ON(1); + return 0; + } +} + +static inline int +gk104_fifo_subdev_engine(int subdev) +{ + switch (subdev) { + case NVDEV_ENGINE_GR: + case NVDEV_ENGINE_SW: + case NVDEV_ENGINE_CE2 : return 0; + case NVDEV_ENGINE_MSPDEC: return 1; + case NVDEV_ENGINE_MSPPP : return 2; + case NVDEV_ENGINE_MSVLD : return 3; + case NVDEV_ENGINE_CE0 : return 4; + case NVDEV_ENGINE_CE1 : return 5; + case NVDEV_ENGINE_MSENC : return 6; + default: + WARN_ON(1); + return 0; + } +} #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c index 2367b4f81a912..18c68ac741a0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c @@ -24,6 +24,14 @@ #include "gk104.h" #include "changk104.h" +static const struct nvkm_fifo_func +gm204_fifo_func = { + .chan = { + &gm204_fifo_gpfifo_oclass, + NULL + }, +}; + int gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -32,7 +40,7 @@ gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, int ret = gk104_fifo_ctor(parent, engine, oclass, data, size, pobject); if (ret == 0) { struct gk104_fifo *fifo = (void *)*pobject; - nv_engine(fifo)->sclass = gm204_fifo_sclass; + fifo->base.func = &gm204_fifo_func; } return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c index fd11e0afec256..820132363f68f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifog84.c @@ -30,15 +30,14 @@ #include static int -g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +g84_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv50_channel_gpfifo_v0 v0; } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo *fifo = nv50_fifo(base); struct nv50_fifo_chan *chan; u64 ioffset, ilength; int ret; @@ -50,73 +49,46 @@ g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, "ilength %08x\n", args->v0.version, args->v0.vm, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); - if (args->v0.vm) - return -ENOENT; + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_VP) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_VIC), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); + ret = g84_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); if (ret) return ret; - nv_parent(chan)->context_attach = g84_fifo_context_attach; - nv_parent(chan)->context_detach = g84_fifo_context_detach; - nv_parent(chan)->object_attach = g84_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; - + args->v0.chid = chan->base.chid; ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_wo32(base->ramfc, 0x88, base->cache->addr >> 10); - nvkm_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12); - nvkm_done(base->ramfc); + nvkm_wo32(chan->ramfc, 0x88, chan->cache->addr >> 10); + nvkm_wo32(chan->ramfc, 0x98, chan->base.inst->addr >> 12); + nvkm_done(chan->ramfc); return 0; } -struct nvkm_ofuncs -g84_fifo_ofuncs_ind = { - .ctor = g84_fifo_chan_ctor_ind, - .dtor = nv50_fifo_chan_dtor, - .init = g84_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy +const struct nvkm_fifo_chan_oclass +g84_fifo_gpfifo_oclass = { + .base.oclass = G82_CHANNEL_GPFIFO, + .base.minver = 0, + .base.maxver = 0, + .ctor = g84_fifo_gpfifo_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c index 7fd6401ca905f..eb9195a6f375f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c @@ -30,29 +30,33 @@ #include #include -static int -gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) +static u32 +gf100_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) { - struct gf100_fifo *fifo = (void *)parent->engine; - struct gf100_fifo_base *base = (void *)parent->parent; - struct gf100_fifo_chan *chan = (void *)parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - u32 addr; - - switch (nv_engidx(object->engine)) { + switch (engine->subdev.index) { case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_CE0 : addr = 0x0230; break; - case NVDEV_ENGINE_CE1 : addr = 0x0240; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; + case NVDEV_ENGINE_GR : return 0x0210; + case NVDEV_ENGINE_CE0 : return 0x0230; + case NVDEV_ENGINE_CE1 : return 0x0240; + case NVDEV_ENGINE_MSPDEC: return 0x0250; + case NVDEV_ENGINE_MSPPP : return 0x0260; + case NVDEV_ENGINE_MSVLD : return 0x0270; default: - return -EINVAL; + WARN_ON(1); + return 0; } +} + +static int +gf100_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + const u32 offset = gf100_fifo_gpfifo_engine_addr(engine); + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct nvkm_subdev *subdev = &chan->fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_gpuobj *inst = chan->base.inst; + int ret = 0; nvkm_wr32(device, 0x002634, chan->base.chid); if (nvkm_msec(device, 2000, @@ -60,143 +64,197 @@ gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend, break; ) < 0) { nvkm_error(subdev, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); + chan->base.chid, chan->base.object.client->name); + ret = -EBUSY; if (suspend) - return -EBUSY; + return ret; + } + + if (offset) { + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, 0x00000000); + nvkm_wo32(inst, offset + 0x04, 0x00000000); + nvkm_done(inst); + } + + return ret; +} + +static int +gf100_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + const u32 offset = gf100_fifo_gpfifo_engine_addr(engine); + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct nvkm_gpuobj *inst = chan->base.inst; + + if (offset) { + u64 addr = chan->engn[engine->subdev.index].vma.offset; + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, lower_32_bits(addr) | 4); + nvkm_wo32(inst, offset + 0x04, upper_32_bits(addr)); + nvkm_done(inst); } - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, 0x00000000); - nvkm_wo32(engn, addr + 0x04, 0x00000000); - nvkm_done(engn); return 0; } +static void +gf100_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + nvkm_gpuobj_unmap(&chan->engn[engine->subdev.index].vma); + nvkm_gpuobj_del(&chan->engn[engine->subdev.index].inst); +} + static int -gf100_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) +gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) { - struct gf100_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - struct nvkm_engctx *ectx = (void *)object; - u32 addr; + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + int engn = engine->subdev.index; int ret; - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_CE0 : addr = 0x0230; break; - case NVDEV_ENGINE_CE1 : addr = 0x0240; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - - if (!ectx->vma.node) { - ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); - if (ret) - return ret; + if (!gf100_fifo_gpfifo_engine_addr(engine)) + return 0; - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + if (object->oclass) { + return nvkm_gpuobj_map(nv_gpuobj(object), chan->vm, + NV_MEM_ACCESS_RW, + &chan->engn[engn].vma); } - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); - nvkm_done(engn); - return 0; + ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst); + if (ret) + return ret; + + return nvkm_gpuobj_map(chan->engn[engn].inst, chan->vm, + NV_MEM_ACCESS_RW, &chan->engn[engn].vma); } -static int -gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend) +static void +gf100_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) { - struct gf100_fifo *fifo = (void *)object->engine; - struct gf100_fifo_chan *chan = (void *)object; + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct gf100_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; + u32 coff = chan->base.chid * 8; - if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nvkm_mask(device, 0x003004 + (chid * 8), 0x00000001, 0x00000000); + if (!list_empty(&chan->head) && !chan->killed) { + list_del_init(&chan->head); + nvkm_mask(device, 0x003004 + coff, 0x00000001, 0x00000000); gf100_fifo_runlist_update(fifo); } gf100_fifo_intr_engine(fifo); - nvkm_wr32(device, 0x003000 + (chid * 8), 0x00000000); - return nvkm_fifo_channel_fini(&chan->base, suspend); + nvkm_wr32(device, 0x003000 + coff, 0x00000000); } -static int -gf100_fifo_chan_init(struct nvkm_object *object) +static void +gf100_fifo_gpfifo_init(struct nvkm_fifo_chan *base) { - struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gf100_fifo *fifo = (void *)object->engine; - struct gf100_fifo_chan *chan = (void *)object; + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + struct gf100_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - int ret; - - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; + u32 addr = chan->base.inst->addr >> 12; + u32 coff = chan->base.chid * 8; - nvkm_wr32(device, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12); + nvkm_wr32(device, 0x003000 + coff, 0xc0000000 | addr); - if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nvkm_wr32(device, 0x003004 + (chid * 8), 0x001f0001); + if (list_empty(&chan->head) && !chan->killed) { + list_add_tail(&chan->head, &fifo->chan); + nvkm_wr32(device, 0x003004 + coff, 0x001f0001); gf100_fifo_runlist_update(fifo); } +} - return 0; +static void * +gf100_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base) +{ + struct gf100_fifo_chan *chan = gf100_fifo_chan(base); + nvkm_vm_ref(NULL, &chan->vm, chan->pgd); + nvkm_gpuobj_del(&chan->pgd); + return chan; } +static const struct nvkm_fifo_chan_func +gf100_fifo_gpfifo_func = { + .dtor = gf100_fifo_gpfifo_dtor, + .init = gf100_fifo_gpfifo_init, + .fini = gf100_fifo_gpfifo_fini, + .ntfy = g84_fifo_chan_ntfy, + .engine_ctor = gf100_fifo_gpfifo_engine_ctor, + .engine_dtor = gf100_fifo_gpfifo_engine_dtor, + .engine_init = gf100_fifo_gpfifo_engine_init, + .engine_fini = gf100_fifo_gpfifo_engine_fini, +}; + static int -gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { union { struct fermi_channel_gpfifo_v0 v0; } *args = data; - struct gf100_fifo *fifo = (void *)engine; - struct gf100_fifo_base *base = (void *)parent; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_object *parent = oclass->parent; struct gf100_fifo_chan *chan; - struct nvkm_gpuobj *ramfc = &base->base.gpuobj; u64 usermem, ioffset, ilength; int ret, i; nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx" + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " "ioffset %016llx ilength %08x\n", args->v0.version, args->v0.vm, args->v0.ioffset, args->v0.ilength); - if (args->v0.vm) - return -ENOENT; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - fifo->user.bar.offset, 0x1000, 0, - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_CE1) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP), &chan); - *pobject = nv_object(chan); + /* allocate channel */ + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + chan->fifo = fifo; + INIT_LIST_HEAD(&chan->head); + + ret = nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func, &fifo->base, + 0x1000, 0x1000, true, args->v0.vm, 0, + (1ULL << NVDEV_ENGINE_CE0) | + (1ULL << NVDEV_ENGINE_CE1) | + (1ULL << NVDEV_ENGINE_GR) | + (1ULL << NVDEV_ENGINE_MSPDEC) | + (1ULL << NVDEV_ENGINE_MSPPP) | + (1ULL << NVDEV_ENGINE_MSVLD) | + (1ULL << NVDEV_ENGINE_SW), + 1, fifo->user.bar.offset, 0x1000, + oclass, &chan->base); if (ret) return ret; - chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; - nv_parent(chan)->context_attach = gf100_fifo_context_attach; - nv_parent(chan)->context_detach = gf100_fifo_context_detach; + /* page directory */ + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd); + if (ret) + return ret; + + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x0200, lower_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0204, upper_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0208, 0xffffffff); + nvkm_wo32(chan->base.inst, 0x020c, 0x000000ff); + nvkm_done(chan->base.inst); + + ret = nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); + if (ret) + return ret; + + /* clear channel control registers */ usermem = chan->base.chid * 0x1000; ioffset = args->v0.ioffset; @@ -208,97 +266,33 @@ gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_done(fifo->user.mem); usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - nvkm_kmap(ramfc); - nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); - nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); - nvkm_wo32(ramfc, 0x10, 0x0000face); - nvkm_wo32(ramfc, 0x30, 0xfffff902); - nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); - nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(ramfc, 0x54, 0x00000002); - nvkm_wo32(ramfc, 0x84, 0x20400000); - nvkm_wo32(ramfc, 0x94, 0x30000001); - nvkm_wo32(ramfc, 0x9c, 0x00000100); - nvkm_wo32(ramfc, 0xa4, 0x1f1f1f1f); - nvkm_wo32(ramfc, 0xa8, 0x1f1f1f1f); - nvkm_wo32(ramfc, 0xac, 0x0000001f); - nvkm_wo32(ramfc, 0xb8, 0xf8000000); - nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ - nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ - nvkm_done(ramfc); - return 0; -} - -static struct nvkm_ofuncs -gf100_fifo_ofuncs = { - .ctor = gf100_fifo_chan_ctor, - .dtor = _nvkm_fifo_channel_dtor, - .init = gf100_fifo_chan_init, - .fini = gf100_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -gf100_fifo_sclass[] = { - { FERMI_CHANNEL_GPFIFO, &gf100_fifo_ofuncs }, - {} -}; - -static int -gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct gf100_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC | - NVOBJ_FLAG_HEAP, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); - if (ret) - return ret; - - nvkm_kmap(&base->base.gpuobj); - nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); - nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); - nvkm_done(&base->base.gpuobj); - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - + /* RAMFC */ + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x10, 0x0000face); + nvkm_wo32(chan->base.inst, 0x30, 0xfffff902); + nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) | + (ilength << 16)); + nvkm_wo32(chan->base.inst, 0x54, 0x00000002); + nvkm_wo32(chan->base.inst, 0x84, 0x20400000); + nvkm_wo32(chan->base.inst, 0x94, 0x30000001); + nvkm_wo32(chan->base.inst, 0x9c, 0x00000100); + nvkm_wo32(chan->base.inst, 0xa4, 0x1f1f1f1f); + nvkm_wo32(chan->base.inst, 0xa8, 0x1f1f1f1f); + nvkm_wo32(chan->base.inst, 0xac, 0x0000001f); + nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000); + nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(chan->base.inst); return 0; } -static void -gf100_fifo_context_dtor(struct nvkm_object *object) -{ - struct gf100_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_del(&base->pgd); - nvkm_fifo_context_destroy(&base->base); -} - -struct nvkm_oclass -gf100_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fifo_context_ctor, - .dtor = gf100_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, +const struct nvkm_fifo_chan_oclass +gf100_fifo_gpfifo_oclass = { + .base.oclass = FERMI_CHANNEL_GPFIFO, + .base.minver = 0, + .base.maxver = 0, + .ctor = gf100_fifo_gpfifo_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index 264c9705bccc5..2595cf92ff804 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -31,30 +31,13 @@ #include #include -#define _(a,b) { (a), ((1ULL << (a)) | (b)) } -static const struct { - u64 subdev; - u64 mask; -} fifo_engine[] = { - _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_CE2)), - _(NVDEV_ENGINE_MSPDEC , 0), - _(NVDEV_ENGINE_MSPPP , 0), - _(NVDEV_ENGINE_MSVLD , 0), - _(NVDEV_ENGINE_CE0 , 0), - _(NVDEV_ENGINE_CE1 , 0), - _(NVDEV_ENGINE_MSENC , 0), -}; -#undef _ -#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine) - static int -gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) +gk104_fifo_gpfifo_kick(struct gk104_fifo_chan *chan) { - struct nvkm_object *obj = (void *)chan; - struct gk104_fifo *fifo = (void *)obj->engine; + struct gk104_fifo *fifo = chan->fifo; struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_client *client = chan->base.object.client; nvkm_wr32(device, 0x002634, chan->base.chid); if (nvkm_msec(device, 2000, @@ -62,198 +45,249 @@ gk104_fifo_chan_kick(struct gk104_fifo_chan *chan) break; ) < 0) { nvkm_error(subdev, "channel %d [%s] kick timeout\n", - chan->base.chid, nvkm_client_name(chan)); + chan->base.chid, client->name); return -EBUSY; } return 0; } -static int -gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend, - struct nvkm_object *object) +static u32 +gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) { - struct gk104_fifo_base *base = (void *)parent->parent; - struct gk104_fifo_chan *chan = (void *)parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - u32 addr; - int ret; - - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : return 0; + switch (engine->subdev.index) { + case NVDEV_ENGINE_SW : case NVDEV_ENGINE_CE0 : case NVDEV_ENGINE_CE1 : - case NVDEV_ENGINE_CE2 : addr = 0x0000; break; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; + case NVDEV_ENGINE_CE2 : return 0x0000; + case NVDEV_ENGINE_GR : return 0x0210; + case NVDEV_ENGINE_MSPDEC: return 0x0250; + case NVDEV_ENGINE_MSPPP : return 0x0260; + case NVDEV_ENGINE_MSVLD : return 0x0270; default: - return -EINVAL; + WARN_ON(1); + return 0; } +} - ret = gk104_fifo_chan_kick(chan); +static int +gk104_fifo_gpfifo_engine_fini(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, bool suspend) +{ + const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct nvkm_gpuobj *inst = chan->base.inst; + int ret; + + ret = gk104_fifo_gpfifo_kick(chan); if (ret && suspend) return ret; - if (addr) { - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, 0x00000000); - nvkm_wo32(engn, addr + 0x04, 0x00000000); - nvkm_done(engn); + if (offset) { + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, 0x00000000); + nvkm_wo32(inst, offset + 0x04, 0x00000000); + nvkm_done(inst); + } + + return ret; +} + +static int +gk104_fifo_gpfifo_engine_init(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + const u32 offset = gk104_fifo_gpfifo_engine_addr(engine); + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct nvkm_gpuobj *inst = chan->base.inst; + + if (offset) { + u64 addr = chan->engn[engine->subdev.index].vma.offset; + nvkm_kmap(inst); + nvkm_wo32(inst, offset + 0x00, lower_32_bits(addr) | 4); + nvkm_wo32(inst, offset + 0x04, upper_32_bits(addr)); + nvkm_done(inst); } return 0; } +static void +gk104_fifo_gpfifo_engine_dtor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + nvkm_gpuobj_unmap(&chan->engn[engine->subdev.index].vma); + nvkm_gpuobj_del(&chan->engn[engine->subdev.index].inst); +} + static int -gk104_fifo_context_attach(struct nvkm_object *parent, - struct nvkm_object *object) +gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, + struct nvkm_engine *engine, + struct nvkm_object *object) { - struct gk104_fifo_base *base = (void *)parent->parent; - struct nvkm_gpuobj *engn = &base->base.gpuobj; - struct nvkm_engctx *ectx = (void *)object; - u32 addr; + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + int engn = engine->subdev.index; int ret; - switch (nv_engidx(object->engine)) { - case NVDEV_ENGINE_SW : - return 0; - case NVDEV_ENGINE_CE0: - case NVDEV_ENGINE_CE1: - case NVDEV_ENGINE_CE2: - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + if (!gk104_fifo_gpfifo_engine_addr(engine)) return 0; - case NVDEV_ENGINE_GR : addr = 0x0210; break; - case NVDEV_ENGINE_MSVLD : addr = 0x0270; break; - case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break; - case NVDEV_ENGINE_MSPPP : addr = 0x0260; break; - default: - return -EINVAL; - } - if (!ectx->vma.node) { - ret = nvkm_gpuobj_map(nv_gpuobj(ectx), base->vm, - NV_MEM_ACCESS_RW, &ectx->vma); - if (ret) - return ret; - - nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12; + if (object->oclass) { + return nvkm_gpuobj_map(nv_gpuobj(object), chan->vm, + NV_MEM_ACCESS_RW, + &chan->engn[engn].vma); } - nvkm_kmap(engn); - nvkm_wo32(engn, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4); - nvkm_wo32(engn, addr + 0x04, upper_32_bits(ectx->vma.offset)); - nvkm_done(engn); - return 0; + ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst); + if (ret) + return ret; + + return nvkm_gpuobj_map(chan->engn[engn].inst, chan->vm, + NV_MEM_ACCESS_RW, &chan->engn[engn].vma); } -static int -gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend) +static void +gk104_fifo_gpfifo_fini(struct nvkm_fifo_chan *base) { - struct gk104_fifo *fifo = (void *)object->engine; - struct gk104_fifo_chan *chan = (void *)object; + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct gk104_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; + u32 coff = chan->base.chid * 8; - if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) { - nvkm_mask(device, 0x800004 + (chid * 8), 0x00000800, 0x00000800); + if (!list_empty(&chan->head)) { + list_del_init(&chan->head); + nvkm_mask(device, 0x800004 + coff, 0x00000800, 0x00000800); gk104_fifo_runlist_update(fifo, chan->engine); } - nvkm_wr32(device, 0x800000 + (chid * 8), 0x00000000); - return nvkm_fifo_channel_fini(&chan->base, suspend); + nvkm_wr32(device, 0x800000 + coff, 0x00000000); } -static int -gk104_fifo_chan_init(struct nvkm_object *object) +static void +gk104_fifo_gpfifo_init(struct nvkm_fifo_chan *base) { - struct nvkm_gpuobj *base = nv_gpuobj(object->parent); - struct gk104_fifo *fifo = (void *)object->engine; - struct gk104_fifo_chan *chan = (void *)object; + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + struct gk104_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; - u32 chid = chan->base.chid; - int ret; + u32 addr = chan->base.inst->addr >> 12; + u32 coff = chan->base.chid * 8; - ret = nvkm_fifo_channel_init(&chan->base); - if (ret) - return ret; + nvkm_mask(device, 0x800004 + coff, 0x000f0000, chan->engine << 16); + nvkm_wr32(device, 0x800000 + coff, 0x80000000 | addr); - nvkm_mask(device, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16); - nvkm_wr32(device, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12); - - if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) { - nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + if (list_empty(&chan->head) && !chan->killed) { + list_add_tail(&chan->head, &fifo->engine[chan->engine].chan); + nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); gk104_fifo_runlist_update(fifo, chan->engine); - nvkm_mask(device, 0x800004 + (chid * 8), 0x00000400, 0x00000400); + nvkm_mask(device, 0x800004 + coff, 0x00000400, 0x00000400); } +} - return 0; +static void * +gk104_fifo_gpfifo_dtor(struct nvkm_fifo_chan *base) +{ + struct gk104_fifo_chan *chan = gk104_fifo_chan(base); + nvkm_vm_ref(NULL, &chan->vm, chan->pgd); + nvkm_gpuobj_del(&chan->pgd); + return chan; } -static int -gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_fifo_chan_func +gk104_fifo_gpfifo_func = { + .dtor = gk104_fifo_gpfifo_dtor, + .init = gk104_fifo_gpfifo_init, + .fini = gk104_fifo_gpfifo_fini, + .ntfy = g84_fifo_chan_ntfy, + .engine_ctor = gk104_fifo_gpfifo_engine_ctor, + .engine_dtor = gk104_fifo_gpfifo_engine_dtor, + .engine_init = gk104_fifo_gpfifo_engine_init, + .engine_fini = gk104_fifo_gpfifo_engine_fini, +}; + +int +gk104_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { union { struct kepler_channel_gpfifo_a_v0 v0; } *args = data; - struct gk104_fifo *fifo = (void *)engine; - struct gk104_fifo_base *base = (void *)parent; + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + struct nvkm_object *parent = oclass->parent; struct gk104_fifo_chan *chan; - struct nvkm_gpuobj *ramfc = &base->base.gpuobj; u64 usermem, ioffset, ilength; u32 engines; int ret, i; nvif_ioctl(parent, "create channel gpfifo size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { - nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx" + nvif_ioctl(parent, "create channel gpfifo vers %d vm %llx " "ioffset %016llx ilength %08x engine %08x\n", args->v0.version, args->v0.vm, args->v0.ioffset, args->v0.ilength, args->v0.engine); - if (args->v0.vm) - return -ENOENT; } else return ret; - for (i = 0, engines = 0; i < FIFO_ENGINE_NR; i++) { - if (!nvkm_engine(parent, fifo_engine[i].subdev)) + /* determine which downstream engines are present */ + for (i = 0, engines = 0; i < ARRAY_SIZE(fifo->engine); i++) { + u64 subdevs = gk104_fifo_engine_subdev(i); + if (!nvkm_device_engine(device, __ffs64(subdevs))) continue; engines |= (1 << i); } + /* if this is an engine mask query, we're done */ if (!args->v0.engine) { - static struct nvkm_oclass oclass = { - .ofuncs = &nvkm_object_ofuncs, - }; args->v0.engine = engines; - return nvkm_object_old(parent, engine, &oclass, NULL, 0, pobject); + return nvkm_object_new(oclass, NULL, 0, pobject); } - engines &= args->v0.engine; - if (!engines) { - nvif_ioctl(parent, "unsupported engines %08x\n", - args->v0.engine); + /* check that we support a requested engine - note that the user + * argument is a mask in order to allow the user to request (for + * example) *any* copy engine, but doesn't matter which. + */ + args->v0.engine &= engines; + if (!args->v0.engine) { + nvif_ioctl(parent, "no supported engine\n"); return -ENODEV; } - i = __ffs(engines); - ret = nvkm_fifo_channel_create(parent, engine, oclass, 1, - fifo->user.bar.offset, 0x200, 0, - fifo_engine[i].mask, &chan); - *pobject = nv_object(chan); + /* allocate the channel */ + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + chan->fifo = fifo; + chan->engine = __ffs(args->v0.engine); + INIT_LIST_HEAD(&chan->head); + + ret = nvkm_fifo_chan_ctor(&gk104_fifo_gpfifo_func, &fifo->base, + 0x1000, 0x1000, true, args->v0.vm, 0, + gk104_fifo_engine_subdev(chan->engine), + 1, fifo->user.bar.offset, 0x200, + oclass, &chan->base); if (ret) return ret; - chan->base.inst = base->base.gpuobj.addr; args->v0.chid = chan->base.chid; - nv_parent(chan)->context_attach = gk104_fifo_context_attach; - nv_parent(chan)->context_detach = gk104_fifo_context_detach; - chan->engine = i; + /* page directory */ + ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &chan->pgd); + if (ret) + return ret; + + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x0200, lower_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0204, upper_32_bits(chan->pgd->addr)); + nvkm_wo32(chan->base.inst, 0x0208, 0xffffffff); + nvkm_wo32(chan->base.inst, 0x020c, 0x000000ff); + nvkm_done(chan->base.inst); + ret = nvkm_vm_ref(chan->base.vm, &chan->vm, chan->pgd); + if (ret) + return ret; + + /* clear channel control registers */ usermem = chan->base.chid * 0x200; ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); @@ -264,94 +298,31 @@ gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_done(fifo->user.mem); usermem = nvkm_memory_addr(fifo->user.mem) + usermem; - nvkm_kmap(ramfc); - nvkm_wo32(ramfc, 0x08, lower_32_bits(usermem)); - nvkm_wo32(ramfc, 0x0c, upper_32_bits(usermem)); - nvkm_wo32(ramfc, 0x10, 0x0000face); - nvkm_wo32(ramfc, 0x30, 0xfffff902); - nvkm_wo32(ramfc, 0x48, lower_32_bits(ioffset)); - nvkm_wo32(ramfc, 0x4c, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(ramfc, 0x84, 0x20400000); - nvkm_wo32(ramfc, 0x94, 0x30000001); - nvkm_wo32(ramfc, 0x9c, 0x00000100); - nvkm_wo32(ramfc, 0xac, 0x0000001f); - nvkm_wo32(ramfc, 0xe8, chan->base.chid); - nvkm_wo32(ramfc, 0xb8, 0xf8000000); - nvkm_wo32(ramfc, 0xf8, 0x10003080); /* 0x002310 */ - nvkm_wo32(ramfc, 0xfc, 0x10000010); /* 0x002350 */ - nvkm_done(ramfc); - return 0; -} - -struct nvkm_ofuncs -gk104_fifo_chan_ofuncs = { - .ctor = gk104_fifo_chan_ctor, - .dtor = _nvkm_fifo_channel_dtor, - .init = gk104_fifo_chan_init, - .fini = gk104_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy -}; - -struct nvkm_oclass -gk104_fifo_sclass[] = { - { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, - {} -}; - -static int -gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = nv_engine(engine)->subdev.device; - struct gk104_fifo_base *base; - int ret; - - ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000, - 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base); - *pobject = nv_object(base); - if (ret) - return ret; - - ret = nvkm_gpuobj_new(device, 0x10000, 0x1000, false, NULL, &base->pgd); - if (ret) - return ret; - - nvkm_kmap(&base->base.gpuobj); - nvkm_wo32(&base->base.gpuobj, 0x0200, lower_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0204, upper_32_bits(base->pgd->addr)); - nvkm_wo32(&base->base.gpuobj, 0x0208, 0xffffffff); - nvkm_wo32(&base->base.gpuobj, 0x020c, 0x000000ff); - nvkm_done(&base->base.gpuobj); - - ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd); - if (ret) - return ret; - + /* RAMFC */ + nvkm_kmap(chan->base.inst); + nvkm_wo32(chan->base.inst, 0x08, lower_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x0c, upper_32_bits(usermem)); + nvkm_wo32(chan->base.inst, 0x10, 0x0000face); + nvkm_wo32(chan->base.inst, 0x30, 0xfffff902); + nvkm_wo32(chan->base.inst, 0x48, lower_32_bits(ioffset)); + nvkm_wo32(chan->base.inst, 0x4c, upper_32_bits(ioffset) | + (ilength << 16)); + nvkm_wo32(chan->base.inst, 0x84, 0x20400000); + nvkm_wo32(chan->base.inst, 0x94, 0x30000001); + nvkm_wo32(chan->base.inst, 0x9c, 0x00000100); + nvkm_wo32(chan->base.inst, 0xac, 0x0000001f); + nvkm_wo32(chan->base.inst, 0xe8, chan->base.chid); + nvkm_wo32(chan->base.inst, 0xb8, 0xf8000000); + nvkm_wo32(chan->base.inst, 0xf8, 0x10003080); /* 0x002310 */ + nvkm_wo32(chan->base.inst, 0xfc, 0x10000010); /* 0x002350 */ + nvkm_done(chan->base.inst); return 0; } -static void -gk104_fifo_context_dtor(struct nvkm_object *object) -{ - struct gk104_fifo_base *base = (void *)object; - nvkm_vm_ref(NULL, &base->vm, base->pgd); - nvkm_gpuobj_del(&base->pgd); - nvkm_fifo_context_destroy(&base->base); -} - -struct nvkm_oclass -gk104_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_context_ctor, - .dtor = gk104_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, +const struct nvkm_fifo_chan_oclass +gk104_fifo_gpfifo_oclass = { + .base.oclass = KEPLER_CHANNEL_GPFIFO_A, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c index 7beee1f8729af..6511d6e21ecc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogm204.c @@ -25,8 +25,10 @@ #include -struct nvkm_oclass -gm204_fifo_sclass[] = { - { MAXWELL_CHANNEL_GPFIFO_A, &gk104_fifo_chan_ofuncs }, - {} +const struct nvkm_fifo_chan_oclass +gm204_fifo_gpfifo_oclass = { + .base.oclass = MAXWELL_CHANNEL_GPFIFO_A, + .base.minver = 0, + .base.maxver = 0, + .ctor = gk104_fifo_gpfifo_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c index ca7de9a6d67fb..a8c69f8782211 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifonv50.c @@ -30,15 +30,14 @@ #include static int -nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_object *parent = oclass->parent; union { struct nv50_channel_gpfifo_v0 v0; } *args = data; - struct nvkm_device *device = parent->engine->subdev.device; - struct nv50_fifo_base *base = (void *)parent; + struct nv50_fifo *fifo = nv50_fifo(base); struct nv50_fifo_chan *chan; u64 ioffset, ilength; int ret; @@ -50,61 +49,44 @@ nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine, "ilength %08x\n", args->v0.version, args->v0.vm, args->v0.pushbuf, args->v0.ioffset, args->v0.ilength); - if (args->v0.vm) - return -ENOENT; + if (!args->v0.pushbuf) + return -EINVAL; } else return ret; - ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000, - 0x2000, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->base.inst = base->base.gpuobj.addr; - args->v0.chid = chan->base.chid; - - nv_parent(chan)->context_attach = nv50_fifo_context_attach; - nv_parent(chan)->context_detach = nv50_fifo_context_detach; - nv_parent(chan)->object_attach = nv50_fifo_object_attach; - nv_parent(chan)->object_detach = nv50_fifo_object_detach; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; - ret = nvkm_ramht_new(device, 0x8000, 16, &base->base.gpuobj, - &chan->ramht); + ret = nv50_fifo_chan_ctor(fifo, args->v0.vm, args->v0.pushbuf, + oclass, chan); if (ret) return ret; + args->v0.chid = chan->base.chid; ioffset = args->v0.ioffset; ilength = order_base_2(args->v0.ilength / 8); - nvkm_kmap(base->ramfc); - nvkm_wo32(base->ramfc, 0x3c, 0x403f6078); - nvkm_wo32(base->ramfc, 0x44, 0x01003fff); - nvkm_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4); - nvkm_wo32(base->ramfc, 0x50, lower_32_bits(ioffset)); - nvkm_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); - nvkm_wo32(base->ramfc, 0x60, 0x7fffffff); - nvkm_wo32(base->ramfc, 0x78, 0x00000000); - nvkm_wo32(base->ramfc, 0x7c, 0x30000001); - nvkm_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | + nvkm_kmap(chan->ramfc); + nvkm_wo32(chan->ramfc, 0x3c, 0x403f6078); + nvkm_wo32(chan->ramfc, 0x44, 0x01003fff); + nvkm_wo32(chan->ramfc, 0x48, chan->base.push->node->offset >> 4); + nvkm_wo32(chan->ramfc, 0x50, lower_32_bits(ioffset)); + nvkm_wo32(chan->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16)); + nvkm_wo32(chan->ramfc, 0x60, 0x7fffffff); + nvkm_wo32(chan->ramfc, 0x78, 0x00000000); + nvkm_wo32(chan->ramfc, 0x7c, 0x30000001); + nvkm_wo32(chan->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) | (4 << 24) /* SEARCH_FULL */ | (chan->ramht->gpuobj->node->offset >> 4)); - nvkm_done(base->ramfc); + nvkm_done(chan->ramfc); return 0; } -struct nvkm_ofuncs -nv50_fifo_ofuncs_ind = { - .ctor = nv50_fifo_chan_ctor_ind, - .dtor = nv50_fifo_chan_dtor, - .init = nv50_fifo_chan_init, - .fini = nv50_fifo_chan_fini, - .map = _nvkm_fifo_channel_map, - .rd32 = _nvkm_fifo_channel_rd32, - .wr32 = _nvkm_fifo_channel_wr32, - .ntfy = _nvkm_fifo_channel_ntfy +const struct nvkm_fifo_chan_oclass +nv50_fifo_gpfifo_oclass = { + .base.oclass = NV50_CHANNEL_GPFIFO, + .base.minver = 0, + .base.maxver = 0, + .ctor = nv50_fifo_gpfifo_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index d880cfa6de9ef..d1ad3fa72c343 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -25,6 +25,7 @@ #include "channv04.h" #include "regsnv04.h" +#include #include #include #include @@ -136,6 +137,8 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) { struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; + struct nvkm_fifo_chan *chan; + unsigned long flags; u32 pull0 = nvkm_rd32(device, 0x003250); u32 mthd, data; int ptr; @@ -157,12 +160,12 @@ nv04_fifo_cache_error(struct nv04_fifo *fifo, u32 chid, u32 get) if (!(pull0 & 0x00000100) || !nv04_fifo_swmthd(device, chid, mthd, data)) { - const char *client_name = - nvkm_client_name_for_fifo_chid(&fifo->base, chid); + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); nvkm_error(subdev, "CACHE_ERROR - " "ch %d [%s] subc %d mthd %04x data %08x\n", - chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc, - data); + chid, chan ? chan->object.client->name : "unknown", + (mthd >> 13) & 7, mthd & 0x1ffc, data); + nvkm_fifo_chan_put(&fifo->base, flags, &chan); } nvkm_wr32(device, NV04_PFIFO_CACHE1_DMA_PUSH, 0); @@ -189,10 +192,12 @@ nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) u32 dma_put = nvkm_rd32(device, 0x003240); u32 push = nvkm_rd32(device, 0x003220); u32 state = nvkm_rd32(device, 0x003228); - const char *client_name; - - client_name = nvkm_client_name_for_fifo_chid(&fifo->base, chid); + struct nvkm_fifo_chan *chan; + unsigned long flags; + const char *name; + chan = nvkm_fifo_chan_chid(&fifo->base, chid, &flags); + name = chan ? chan->object.client->name : "unknown"; if (device->card_type == NV_50) { u32 ho_get = nvkm_rd32(device, 0x003328); u32 ho_put = nvkm_rd32(device, 0x003320); @@ -202,7 +207,7 @@ nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) nvkm_error(subdev, "DMA_PUSHER - " "ch %d [%s] get %02x%08x put %02x%08x ib_get %08x " "ib_put %08x state %08x (err: %s) push %08x\n", - chid, client_name, ho_get, dma_get, ho_put, dma_put, + chid, name, ho_get, dma_get, ho_put, dma_put, ib_get, ib_put, state, nv_dma_state_err(state), push); @@ -217,12 +222,13 @@ nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) } else { nvkm_error(subdev, "DMA_PUSHER - ch %d [%s] get %08x put %08x " "state %08x (err: %s) push %08x\n", - chid, client_name, dma_get, dma_put, state, + chid, name, dma_get, dma_put, state, nv_dma_state_err(state), push); if (dma_get != dma_put) nvkm_wr32(device, 0x003244, dma_put); } + nvkm_fifo_chan_put(&fifo->base, flags, &chan); nvkm_wr32(device, 0x003228, 0x00000000); nvkm_wr32(device, 0x003220, 0x00000001); @@ -241,7 +247,7 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) reassign = nvkm_rd32(device, NV03_PFIFO_CACHES) & 1; nvkm_wr32(device, NV03_PFIFO_CACHES, 0); - chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & fifo->base.max; + chid = nvkm_rd32(device, NV03_PFIFO_CACHE1_PUSH1) & (fifo->base.nr - 1); get = nvkm_rd32(device, NV03_PFIFO_CACHE1_GET); if (stat & NV_PFIFO_INTR_CACHE_ERROR) { @@ -311,7 +317,7 @@ nv04_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); @@ -329,6 +335,14 @@ nv04_fifo_dtor(struct nvkm_object *object) nvkm_fifo_destroy(&fifo->base); } +static const struct nvkm_fifo_func +nv04_fifo_func = { + .chan = { + &nv04_fifo_dma_oclass, + NULL + }, +}; + static int nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -342,10 +356,10 @@ nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &nv04_fifo_func; + nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv04_fifo_cclass; - nv_engine(fifo)->sclass = nv04_fifo_sclass; fifo->base.pause = nv04_fifo_pause; fifo->base.start = nv04_fifo_start; fifo->ramfc_desc = nv04_ramfc; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h index 5cde3310ee4dd..c33dc56f8e022 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h @@ -1,5 +1,6 @@ #ifndef __NV04_FIFO_H__ #define __NV04_FIFO_H__ +#define nv04_fifo(p) container_of((p), struct nv04_fifo, base) #include "priv.h" struct ramfc_desc { @@ -15,14 +16,6 @@ struct nv04_fifo { struct ramfc_desc *ramfc_desc; }; -struct nv04_fifo_base { - struct nvkm_fifo_base base; -}; - -int nv04_fifo_context_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - void nv04_fifo_dtor(struct nvkm_object *); int nv04_fifo_init(struct nvkm_object *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index ae0a1b17eb922..d7fab9598fb0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -39,16 +39,11 @@ nv10_ramfc[] = { {} }; -static struct nvkm_oclass -nv10_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, +static const struct nvkm_fifo_func +nv10_fifo_func = { + .chan = { + &nv10_fifo_dma_oclass, + NULL }, }; @@ -65,10 +60,10 @@ nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &nv10_fifo_func; + nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv10_fifo_cclass; - nv_engine(fifo)->sclass = nv10_fifo_sclass; fifo->base.pause = nv04_fifo_pause; fifo->base.start = nv04_fifo_start; fifo->ramfc_desc = nv10_ramfc; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index ff2b6d95d8047..a8e28fc24e756 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -47,19 +47,6 @@ nv17_ramfc[] = { {} }; -static struct nvkm_oclass -nv17_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x17), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - static int nv17_fifo_init(struct nvkm_object *object) { @@ -85,7 +72,7 @@ nv17_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_RAMFC, nvkm_memory_addr(ramfc) >> 8 | 0x00010000); - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); @@ -96,6 +83,14 @@ nv17_fifo_init(struct nvkm_object *object) return 0; } +static const struct nvkm_fifo_func +nv17_fifo_func = { + .chan = { + &nv17_fifo_dma_oclass, + NULL + }, +}; + static int nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -109,10 +104,10 @@ nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &nv17_fifo_func; + nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv17_fifo_cclass; - nv_engine(fifo)->sclass = nv17_fifo_sclass; fifo->base.pause = nv04_fifo_pause; fifo->base.start = nv04_fifo_start; fifo->ramfc_desc = nv17_ramfc; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index 64be69fc95723..aca146377d36d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -56,19 +56,6 @@ nv40_ramfc[] = { {} }; -static struct nvkm_oclass -nv40_fifo_cclass = { - .handle = NV_ENGCTX(FIFO, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_context_ctor, - .dtor = _nvkm_fifo_context_dtor, - .init = _nvkm_fifo_context_init, - .fini = _nvkm_fifo_context_fini, - .rd32 = _nvkm_fifo_context_rd32, - .wr32 = _nvkm_fifo_context_wr32, - }, -}; - static int nv40_fifo_init(struct nvkm_object *object) { @@ -115,7 +102,7 @@ nv40_fifo_init(struct nvkm_object *object) break; } - nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.max); + nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH1, fifo->base.nr - 1); nvkm_wr32(device, NV03_PFIFO_INTR_0, 0xffffffff); nvkm_wr32(device, NV03_PFIFO_INTR_EN_0, 0xffffffff); @@ -126,6 +113,14 @@ nv40_fifo_init(struct nvkm_object *object) return 0; } +static const struct nvkm_fifo_func +nv40_fifo_func = { + .chan = { + &nv40_fifo_dma_oclass, + NULL + }, +}; + static int nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -139,10 +134,10 @@ nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &nv40_fifo_func; + nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv40_fifo_cclass; - nv_engine(fifo)->sclass = nv40_fifo_sclass; fifo->base.pause = nv04_fifo_pause; fifo->base.start = nv04_fifo_start; fifo->ramfc_desc = nv40_ramfc; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index bf17cb0e8385b..ad653e9c461a3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -35,7 +35,7 @@ nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo) fifo->cur_runlist = !fifo->cur_runlist; nvkm_kmap(cur); - for (i = fifo->base.min, p = 0; i < fifo->base.max; i++) { + for (i = 0, p = 0; i < fifo->base.nr; i++) { if (nvkm_rd32(device, 0x002600 + (i * 4)) & 0x80000000) nvkm_wo32(cur, p++ * 4, i); } @@ -94,6 +94,15 @@ nv50_fifo_dtor(struct nvkm_object *object) nvkm_fifo_destroy(&fifo->base); } +static const struct nvkm_fifo_func +nv50_fifo_func = { + .chan = { + &nv50_fifo_dma_oclass, + &nv50_fifo_gpfifo_oclass, + NULL + }, +}; + static int nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -108,6 +117,8 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + fifo->base.func = &nv50_fifo_func; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, false, &fifo->runlist[0]); if (ret) @@ -120,8 +131,6 @@ nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(fifo)->unit = 0x00000100; nv_subdev(fifo)->intr = nv04_fifo_intr; - nv_engine(fifo)->cclass = &nv50_fifo_cclass; - nv_engine(fifo)->sclass = nv50_fifo_sclass; fifo->base.pause = nv04_fifo_pause; fifo->base.start = nv04_fifo_start; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h index 306593fc56bb1..a7d5dba12fb8e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h @@ -1,5 +1,6 @@ #ifndef __NV50_FIFO_H__ #define __NV50_FIFO_H__ +#define nv50_fifo(p) container_of((p), struct nv50_fifo, base) #include "priv.h" struct nv50_fifo { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h index b202f7f9413d1..a30d160f30db6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -1,7 +1,6 @@ #ifndef __NVKM_FIFO_PRIV_H__ #define __NVKM_FIFO_PRIV_H__ #include -#include void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index c6ff24b5a11df..ebc9dee03beb8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1168,10 +1168,14 @@ gf100_gr_intr(struct nvkm_subdev *subdev) u32 data = nvkm_rd32(device, 0x400708); u32 code = nvkm_rd32(device, 0x400110); u32 class; - int chid; + const char *name = "unknown"; + int chid = -1; chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); - chid = chan ? chan->chid : -1; + if (chan) { + name = chan->object.client->name; + chid = chan->chid; + } if (nv_device(gr)->card_type < NV_E0 || subc < 4) class = nvkm_rd32(device, 0x404200 + (subc * 4)); @@ -1191,8 +1195,8 @@ gf100_gr_intr(struct nvkm_subdev *subdev) if (!gf100_gr_mthd_sw(device, class, mthd, data)) { nvkm_error(subdev, "ILLEGAL_MTHD ch %d [%010llx %s] " "subc %d class %04x mthd %04x data %08x\n", - chid, inst << 12, nvkm_client_name(chan), - subc, class, mthd, data); + chid, inst << 12, name, subc, + class, mthd, data); } nvkm_wr32(device, 0x400100, 0x00000010); stat &= ~0x00000010; @@ -1201,8 +1205,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) if (stat & 0x00000020) { nvkm_error(subdev, "ILLEGAL_CLASS ch %d [%010llx %s] " "subc %d class %04x mthd %04x data %08x\n", - chid, inst << 12, nvkm_client_name(chan), subc, - class, mthd, data); + chid, inst << 12, name, subc, class, mthd, data); nvkm_wr32(device, 0x400100, 0x00000020); stat &= ~0x00000020; } @@ -1213,14 +1216,14 @@ gf100_gr_intr(struct nvkm_subdev *subdev) nvkm_error(subdev, "DATA_ERROR %08x [%s] ch %d [%010llx %s] " "subc %d class %04x mthd %04x data %08x\n", code, en ? en->name : "", chid, inst << 12, - nvkm_client_name(chan), subc, class, mthd, data); + name, subc, class, mthd, data); nvkm_wr32(device, 0x400100, 0x00100000); stat &= ~0x00100000; } if (stat & 0x00200000) { nvkm_error(subdev, "TRAP ch %d [%010llx %s]\n", - chid, inst << 12, nvkm_client_name(chan)); + chid, inst << 12, name); gf100_gr_trap_intr(gr); nvkm_wr32(device, 0x400100, 0x00200000); stat &= ~0x00200000; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 262638b4e0c59..29feab391fe40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -230,7 +230,8 @@ nv20_gr_intr(struct nvkm_subdev *subdev) "nstatus %08x [%s] ch %d [%s] subc %d " "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, chid, - nvkm_client_name(chan), subc, class, mthd, data); + chan ? chan->object.client->name : "unknown", + subc, class, mthd, data); } nvkm_fifo_chan_put(device->fifo, flags, &chan); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 4db2a17f5308b..e716ae12b55ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -353,7 +353,8 @@ nv40_gr_intr(struct nvkm_subdev *subdev) "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, chan ? chan->fifo->chid : -1, inst << 4, - nvkm_client_name(chan), subc, class, mthd, data); + chan ? chan->fifo->object.client->name : "unknown", + subc, class, mthd, data); } spin_unlock_irqrestore(&gr->base.engine.lock, flags); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index daac54075705f..5f22dd3c788cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -608,7 +608,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, static int nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, - int chid, u64 inst, struct nvkm_fifo_chan *chan) + int chid, u64 inst, const char *name) { struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; @@ -648,8 +648,7 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, "ch %d [%010llx %s] subc %d " "class %04x mthd %04x data %08x%08x " "400808 %08x 400848 %08x\n", - chid, inst, nvkm_client_name(chan), - subc, class, mthd, + chid, inst, name, subc, class, mthd, datah, datal, addr, r848); } else if (display) { @@ -674,9 +673,8 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, nvkm_error(subdev, "ch %d [%010llx %s] subc %d " "class %04x mthd %04x data %08x " - "40084c %08x\n", chid, inst, - nvkm_client_name(chan), subc, - class, mthd, data, addr); + "40084c %08x\n", chid, inst, name, + subc, class, mthd, data, addr); } else if (display) { nvkm_error(subdev, "no stuck command?\n"); @@ -849,11 +847,15 @@ nv50_gr_intr(struct nvkm_subdev *subdev) u32 show = stat, show_bitfield = stat; const struct nvkm_enum *en; unsigned long flags; + const char *name = "unknown"; char msg[128]; - int chid; + int chid = -1; chan = nvkm_fifo_chan_inst(device->fifo, (u64)inst << 12, &flags); - chid = chan ? chan->chid : -1; + if (chan) { + name = chan->object.client->name; + chid = chan->chid; + } if (show & 0x00100000) { u32 ecode = nvkm_rd32(device, 0x400110); @@ -864,7 +866,7 @@ nv50_gr_intr(struct nvkm_subdev *subdev) } if (stat & 0x00200000) { - if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12, chan)) + if (!nv50_gr_trap_handler(gr, show, chid, (u64)inst << 12, name)) show &= ~0x00200000; show_bitfield &= ~0x00200000; } @@ -877,8 +879,8 @@ nv50_gr_intr(struct nvkm_subdev *subdev) nvkm_snprintbf(msg, sizeof(msg), nv50_gr_intr_name, show); nvkm_error(subdev, "%08x [%s] ch %d [%010llx %s] subc %d " "class %04x mthd %04x data %08x\n", - stat, msg, chid, (u64)inst << 12, - nvkm_client_name(chan), subc, class, mthd, data); + stat, msg, chid, (u64)inst << 12, name, + subc, class, mthd, data); } if (nvkm_rd32(device, 0x400824) & (1 << 31)) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 05597f2070ed7..211b44c00c850 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -231,8 +231,8 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) if (show) { nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", mpeg->chan ? mpeg->chan->fifo->chid : -1, - nvkm_client_name(mpeg->chan), - stat, type, mthd, data); + mpeg->chan ? mpeg->chan->fifo->object.client->name : + "unknown", stat, type, mthd, data); } spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 1223baddfb9ab..ff9ddc67a2921 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -145,13 +145,11 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) u32 mthd = nvkm_rd32(device, 0x00b234); u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; - int chid = -1; spin_lock_irqsave(&mpeg->base.engine.lock, flags); list_for_each_entry(temp, &mpeg->chan, head) { if (temp->inst >> 4 == inst) { chan = temp; - chid = chan->fifo->chid; list_del(&chan->head); list_add(&chan->head, &mpeg->chan); break; @@ -176,7 +174,8 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) if (show) { nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", - chid, inst << 4, nvkm_client_name(chan), + chan ? chan->fifo->chid : -1, inst << 4, + chan ? chan->fifo->object.client->name : "unknown", stat, type, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index e6544097726c4..c15934d7ff63a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -84,7 +84,8 @@ g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) nvkm_error(subdev, "DISPATCH_ERROR %04x [%s] ch %d [%010llx %s] " "subc %d mthd %04x data %08x\n", ssta, en ? en->name : "UNKNOWN", chan ? chan->chid : -1, - chan ? chan->inst : 0, nvkm_client_name(chan), + chan ? chan->inst->addr : 0, + chan ? chan->object.client->name : "unknown", subc, mthd, data); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 4e8b632ef5b16..35ec1cffb53a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -24,8 +24,8 @@ #include "nv50.h" #include -#include #include +#include #include #include @@ -136,7 +136,7 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; } - chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12; + chan->vblank.channel = nvkm_fifo_chan(parent)->inst->addr >> 12; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 4a88bbd814b76..383030434079b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -338,7 +338,7 @@ void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) { struct nvkm_device *device = clk->subdev.device; - struct nvkm_fifo *fifo = nvkm_fifo(clk); + struct nvkm_fifo *fifo = device->fifo; if (fifo && flags) fifo->start(fifo, flags); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index ea83f7d9ddc81..711ea96bcd36a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -189,12 +189,14 @@ nv50_fb_intr(struct nvkm_subdev *subdev) else sc = NULL; chan = nvkm_fifo_chan_inst(fifo, inst, &flags); - nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel " - "%08x [%s] engine %02x [%s] client %02x [%s] " + nvkm_error(subdev, "trapped %s at %02x%04x%04x on channel %d [%08x %s] " + "engine %02x [%s] client %02x [%s] " "subclient %02x [%s] reason %08x [%s]\n", (trap[5] & 0x00000100) ? "read" : "write", - trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, inst, - nvkm_client_name(chan), st0, en ? en->name : "", + trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, + chan ? chan->chid : -1, inst, + chan ? chan->object.client->name : "unknown", + st0, en ? en->name : "", st2, cl ? cl->name : "", st3, sc ? sc->name : "", st1, re ? re->name : ""); nvkm_fifo_chan_put(fifo, flags, &chan); -- GitLab From 9d498e0f7a5ece8f61c8a174b40668a2621a82e3 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5520/7006] drm/nouveau/falcon: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 22 ++++++ .../drm/nouveau/include/nvkm/engine/falcon.h | 26 +------ .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 69 +++++-------------- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 38 ++-------- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 36 ++++++++++ .../gpu/drm/nouveau/nvkm/engine/mspdec/g98.c | 39 ++--------- .../drm/nouveau/nvkm/engine/mspdec/gf100.c | 37 ++-------- .../drm/nouveau/nvkm/engine/mspdec/gk104.c | 37 ++-------- .../gpu/drm/nouveau/nvkm/engine/msppp/g98.c | 39 ++--------- .../gpu/drm/nouveau/nvkm/engine/msppp/gf100.c | 37 ++-------- .../gpu/drm/nouveau/nvkm/engine/msvld/g98.c | 41 ++--------- .../gpu/drm/nouveau/nvkm/engine/msvld/gf100.c | 37 ++-------- .../gpu/drm/nouveau/nvkm/engine/msvld/gk104.c | 37 ++-------- drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 37 ++-------- 14 files changed, 132 insertions(+), 400 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index d8bad60642ac5..10b6685cf5e7a 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -94,6 +94,28 @@ #define MAXWELL_A 0x0000b097 #define MAXWELL_B 0x0000b197 +#define GT212_MSVLD 0x000085b1 +#define IGT21A_MSVLD 0x000086b1 +#define G98_MSVLD 0x000088b1 +#define GF100_MSVLD 0x000090b1 +#define GK104_MSVLD 0x000095b1 + +#define GT212_MSPDEC 0x000085b2 +#define G98_MSPDEC 0x000088b2 +#define GF100_MSPDEC 0x000090b2 +#define GK104_MSPDEC 0x000095b2 + +#define GT212_MSPPP 0x000085b3 +#define G98_MSPPP 0x000088b3 +#define GF100_MSPPP 0x000090b3 + +#define G98_SEC 0x000088b4 + +#define GT212_DMA 0x000085b5 +#define FERMI_DMA 0x000090b5 + +#define FERMI_DECOMPRESS 0x000090b8 + #define FERMI_COMPUTE_A 0x000090c0 #define FERMI_COMPUTE_B 0x000091c0 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index bdadc8b602811..cd113fcbfccb2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -1,34 +1,13 @@ #ifndef __NVKM_FALCON_H__ #define __NVKM_FALCON_H__ -#include +#define nvkm_falcon(p) container_of((p), struct nvkm_falcon, engine) +#include struct nvkm_fifo_chan; -struct nvkm_falcon_chan { - struct nvkm_engctx base; -}; - -#define nvkm_falcon_context_create(p,e,c,g,s,a,f,d) \ - nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) -#define nvkm_falcon_context_destroy(d) \ - nvkm_engctx_destroy(&(d)->base) -#define nvkm_falcon_context_init(d) \ - nvkm_engctx_init(&(d)->base) -#define nvkm_falcon_context_fini(d,s) \ - nvkm_engctx_fini(&(d)->base, (s)) - -#define _nvkm_falcon_context_ctor _nvkm_engctx_ctor -#define _nvkm_falcon_context_dtor _nvkm_engctx_dtor -#define _nvkm_falcon_context_init _nvkm_engctx_init -#define _nvkm_falcon_context_fini _nvkm_engctx_fini -#define _nvkm_falcon_context_rd32 _nvkm_engctx_rd32 -#define _nvkm_falcon_context_wr32 _nvkm_engctx_wr32 - struct nvkm_falcon_data { bool external; }; -#include - struct nvkm_falcon { struct nvkm_engine engine; const struct nvkm_falcon_func *func; @@ -55,6 +34,7 @@ struct nvkm_falcon { struct nvkm_falcon_func { void (*intr)(struct nvkm_falcon *, struct nvkm_fifo_chan *); + struct nvkm_sclass sclass[]; }; #define nv_falcon(priv) ((struct nvkm_falcon *)priv) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 6faf38e3dbbc5..3abab3992e7cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -25,51 +25,7 @@ #include #include "fuc/gf100.fuc3.h" -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_ce0_sclass[] = { - { 0x90b5, &nvkm_object_ofuncs }, - {}, -}; - -static struct nvkm_oclass -gf100_ce1_sclass[] = { - { 0x90b8, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_ofuncs -gf100_ce_context_ofuncs = { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, -}; - -static struct nvkm_oclass -gf100_ce0_cclass = { - .handle = NV_ENGCTX(CE0, 0xc0), - .ofuncs = &gf100_ce_context_ofuncs, -}; - -static struct nvkm_oclass -gf100_ce1_cclass = { - .handle = NV_ENGCTX(CE1, 0xc0), - .ofuncs = &gf100_ce_context_ofuncs, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ +#include static int gf100_ce_init(struct nvkm_object *object) @@ -89,8 +45,12 @@ gf100_ce_init(struct nvkm_object *object) } static const struct nvkm_falcon_func -gf100_ce_func = { +gf100_ce0_func = { .intr = gt215_ce_intr, + .sclass = { + { -1, -1, FERMI_DMA }, + {} + } }; static int @@ -101,15 +61,13 @@ gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *ce; int ret; - ret = nvkm_falcon_create(&gf100_ce_func, parent, engine, oclass, + ret = nvkm_falcon_create(&gf100_ce0_func, parent, engine, oclass, 0x104000, true, "PCE0", "ce0", &ce); *pobject = nv_object(ce); if (ret) return ret; nv_subdev(ce)->unit = 0x00000040; - nv_engine(ce)->cclass = &gf100_ce0_cclass; - nv_engine(ce)->sclass = gf100_ce0_sclass; nv_falcon(ce)->code.data = gf100_ce_code; nv_falcon(ce)->code.size = sizeof(gf100_ce_code); nv_falcon(ce)->data.data = gf100_ce_data; @@ -117,6 +75,15 @@ gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } +static const struct nvkm_falcon_func +gf100_ce1_func = { + .intr = gt215_ce_intr, + .sclass = { + { -1, -1, FERMI_DECOMPRESS }, + {} + } +}; + static int gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -125,15 +92,13 @@ gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_falcon *ce; int ret; - ret = nvkm_falcon_create(&gf100_ce_func, parent, engine, oclass, + ret = nvkm_falcon_create(&gf100_ce1_func, parent, engine, oclass, 0x105000, true, "PCE1", "ce1", &ce); *pobject = nv_object(ce); if (ret) return ret; nv_subdev(ce)->unit = 0x00000080; - nv_engine(ce)->cclass = &gf100_ce1_cclass; - nv_engine(ce)->sclass = gf100_ce1_sclass; nv_falcon(ce)->code.data = gf100_ce_code; nv_falcon(ce)->code.size = sizeof(gf100_ce_code); nv_falcon(ce)->data.data = gf100_ce_data; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 1a15b8d6fecea..35e4d578b153b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -28,37 +28,7 @@ #include #include -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gt215_ce_sclass[] = { - { 0x85b5, &nvkm_object_ofuncs }, - {} -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_oclass -gt215_ce_cclass = { - .handle = NV_ENGCTX(CE0, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - - }, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ +#include static const struct nvkm_enum gt215_ce_isr_error_name[] = { @@ -93,6 +63,10 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) static const struct nvkm_falcon_func gt215_ce_func = { .intr = gt215_ce_intr, + .sclass = { + { -1, -1, GT212_DMA }, + {} + } }; static int @@ -111,8 +85,6 @@ gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(ce)->unit = 0x00802000; - nv_engine(ce)->cclass = >215_ce_cclass; - nv_engine(ce)->sclass = gt215_ce_sclass; nv_falcon(ce)->code.data = gt215_ce_code; nv_falcon(ce)->code.size = sizeof(gt215_ce_code); nv_falcon(ce)->data.data = gt215_ce_data; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index b0cbe819497a4..3d3e73cfb6b0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -24,6 +24,35 @@ #include +static int +nvkm_falcon_oclass_get(struct nvkm_oclass *oclass, int index) +{ + struct nvkm_falcon *falcon = nvkm_falcon(oclass->engine); + int c = 0; + + while (falcon->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = falcon->func->sclass[index]; + return index; + } + } + + return c; +} + +static int +nvkm_falcon_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + return nvkm_gpuobj_new(object->engine->subdev.device, 256, + align, true, parent, pgpuobj); +} + +static const struct nvkm_object_func +nvkm_falcon_cclass = { + .bind = nvkm_falcon_cclass_bind, +}; + static void nvkm_falcon_intr(struct nvkm_subdev *subdev) { @@ -275,6 +304,12 @@ _nvkm_falcon_fini(struct nvkm_object *object, bool suspend) return nvkm_engine_fini_old(&falcon->engine, suspend); } +static const struct nvkm_engine_func +nvkm_falcon = { + .fifo.sclass = nvkm_falcon_oclass_get, + .cclass = &nvkm_falcon_cclass, +}; + int nvkm_falcon_create_(const struct nvkm_falcon_func *func, struct nvkm_object *parent, struct nvkm_object *engine, @@ -292,6 +327,7 @@ nvkm_falcon_create_(const struct nvkm_falcon_func *func, return ret; falcon->engine.subdev.intr = nvkm_falcon_intr; + falcon->engine.func = &nvkm_falcon; falcon->func = func; falcon->addr = addr; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index fbb38450f1e50..f14971783270c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -24,37 +24,7 @@ #include #include -/******************************************************************************* - * MSPDEC object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_mspdec_sclass[] = { - { 0x88b2, &nvkm_object_ofuncs }, - { 0x85b2, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPDEC context - ******************************************************************************/ - -static struct nvkm_oclass -g98_mspdec_cclass = { - .handle = NV_ENGCTX(MSPDEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPDEC engine/subdev functions - ******************************************************************************/ +#include static int g98_mspdec_init(struct nvkm_object *object) @@ -74,6 +44,11 @@ g98_mspdec_init(struct nvkm_object *object) static const struct nvkm_falcon_func g98_mspdec_func = { + .sclass = { + { -1, -1, G98_MSPDEC }, + { -1, -1, GT212_MSPDEC }, + {} + }, }; static int @@ -91,8 +66,6 @@ g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(mspdec)->unit = 0x01020000; - nv_engine(mspdec)->cclass = &g98_mspdec_cclass; - nv_engine(mspdec)->sclass = g98_mspdec_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index 71b75e9177b43..1296f775ea310 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -24,36 +24,7 @@ #include #include -/******************************************************************************* - * MSPDEC object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_mspdec_sclass[] = { - { 0x90b2, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPDEC context - ******************************************************************************/ - -static struct nvkm_oclass -gf100_mspdec_cclass = { - .handle = NV_ENGCTX(MSPDEC, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPDEC engine/subdev functions - ******************************************************************************/ +#include static int gf100_mspdec_init(struct nvkm_object *object) @@ -73,6 +44,10 @@ gf100_mspdec_init(struct nvkm_object *object) static const struct nvkm_falcon_func gf100_mspdec_func = { + .sclass = { + { -1, -1, GF100_MSPDEC }, + {} + } }; static int @@ -90,8 +65,6 @@ gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(mspdec)->unit = 0x00020000; - nv_engine(mspdec)->cclass = &gf100_mspdec_cclass; - nv_engine(mspdec)->sclass = gf100_mspdec_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index a103789a26112..315da1695c72a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -24,36 +24,7 @@ #include #include -/******************************************************************************* - * MSPDEC object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_mspdec_sclass[] = { - { 0x95b2, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPDEC context - ******************************************************************************/ - -static struct nvkm_oclass -gk104_mspdec_cclass = { - .handle = NV_ENGCTX(MSPDEC, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPDEC engine/subdev functions - ******************************************************************************/ +#include static int gk104_mspdec_init(struct nvkm_object *object) @@ -73,6 +44,10 @@ gk104_mspdec_init(struct nvkm_object *object) static const struct nvkm_falcon_func gk104_mspdec_func = { + .sclass = { + { -1, -1, GK104_MSPDEC }, + {} + } }; static int @@ -90,8 +65,6 @@ gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(falcon)->unit = 0x00020000; - nv_engine(falcon)->cclass = &gk104_mspdec_cclass; - nv_engine(falcon)->sclass = gk104_mspdec_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index 9029ff0ea86d7..314736d6aa5b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -24,37 +24,7 @@ #include #include -/******************************************************************************* - * MSPPP object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_msppp_sclass[] = { - { 0x88b3, &nvkm_object_ofuncs }, - { 0x85b3, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPPP context - ******************************************************************************/ - -static struct nvkm_oclass -g98_msppp_cclass = { - .handle = NV_ENGCTX(MSPPP, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPPP engine/subdev functions - ******************************************************************************/ +#include static int g98_msppp_init(struct nvkm_object *object) @@ -74,6 +44,11 @@ g98_msppp_init(struct nvkm_object *object) static const struct nvkm_falcon_func g98_msppp_func = { + .sclass = { + { -1, -1, G98_MSPPP }, + { -1, -1, GT212_MSPPP }, + {} + } }; static int @@ -91,8 +66,6 @@ g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(msppp)->unit = 0x00400002; - nv_engine(msppp)->cclass = &g98_msppp_cclass; - nv_engine(msppp)->sclass = g98_msppp_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index 2b21fe5dafdae..f977c2adf9d2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -24,36 +24,7 @@ #include #include -/******************************************************************************* - * MSPPP object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msppp_sclass[] = { - { 0x90b3, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSPPP context - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msppp_cclass = { - .handle = NV_ENGCTX(MSPPP, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSPPP engine/subdev functions - ******************************************************************************/ +#include static int gf100_msppp_init(struct nvkm_object *object) @@ -73,6 +44,10 @@ gf100_msppp_init(struct nvkm_object *object) static const struct nvkm_falcon_func gf100_msppp_func = { + .sclass = { + { -1, -1, GF100_MSPPP }, + {} + } }; static int @@ -90,8 +65,6 @@ gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(msppp)->unit = 0x00000002; - nv_engine(msppp)->cclass = &gf100_msppp_cclass; - nv_engine(msppp)->sclass = gf100_msppp_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index cdb7de5a73054..0ee767373f790 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -24,38 +24,7 @@ #include #include -/******************************************************************************* - * MSVLD object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_msvld_sclass[] = { - { 0x88b1, &nvkm_object_ofuncs }, - { 0x85b1, &nvkm_object_ofuncs }, - { 0x86b1, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSVLD context - ******************************************************************************/ - -static struct nvkm_oclass -g98_msvld_cclass = { - .handle = NV_ENGCTX(MSVLD, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSVLD engine/subdev functions - ******************************************************************************/ +#include static int g98_msvld_init(struct nvkm_object *object) @@ -75,6 +44,12 @@ g98_msvld_init(struct nvkm_object *object) static const struct nvkm_falcon_func g98_msvld_func = { + .sclass = { + { -1, -1, G98_MSVLD }, + { -1, -1, GT212_MSVLD }, + { -1, -1, IGT21A_MSVLD }, + {} + } }; static int @@ -92,8 +67,6 @@ g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(msvld)->unit = 0x04008000; - nv_engine(msvld)->cclass = &g98_msvld_cclass; - nv_engine(msvld)->sclass = g98_msvld_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index 1124373be9207..839d648dcfdfb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -24,36 +24,7 @@ #include #include -/******************************************************************************* - * MSVLD object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msvld_sclass[] = { - { 0x90b1, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSVLD context - ******************************************************************************/ - -static struct nvkm_oclass -gf100_msvld_cclass = { - .handle = NV_ENGCTX(MSVLD, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSVLD engine/subdev functions - ******************************************************************************/ +#include static int gf100_msvld_init(struct nvkm_object *object) @@ -73,6 +44,10 @@ gf100_msvld_init(struct nvkm_object *object) static const struct nvkm_falcon_func gf100_msvld_func = { + .sclass = { + { -1, -1, GF100_MSVLD }, + {} + } }; static int @@ -90,8 +65,6 @@ gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(msvld)->unit = 0x00008000; - nv_engine(msvld)->cclass = &gf100_msvld_cclass; - nv_engine(msvld)->sclass = gf100_msvld_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index addef2bbfe76b..74bdca359d4ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -24,36 +24,7 @@ #include #include -/******************************************************************************* - * MSVLD object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_msvld_sclass[] = { - { 0x95b1, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PMSVLD context - ******************************************************************************/ - -static struct nvkm_oclass -gk104_msvld_cclass = { - .handle = NV_ENGCTX(MSVLD, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PMSVLD engine/subdev functions - ******************************************************************************/ +#include static int gk104_msvld_init(struct nvkm_object *object) @@ -73,6 +44,10 @@ gk104_msvld_init(struct nvkm_object *object) static const struct nvkm_falcon_func gk104_msvld_func = { + .sclass = { + { -1, -1, GK104_MSVLD }, + {} + } }; static int @@ -90,8 +65,6 @@ gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(msvld)->unit = 0x00008000; - nv_engine(msvld)->cclass = &gk104_msvld_cclass; - nv_engine(msvld)->sclass = gk104_msvld_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index c15934d7ff63a..aae0e85b10752 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -29,36 +29,7 @@ #include #include -/******************************************************************************* - * Crypt object classes - ******************************************************************************/ - -static struct nvkm_oclass -g98_sec_sclass[] = { - { 0x88b4, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PSEC context - ******************************************************************************/ - -static struct nvkm_oclass -g98_sec_cclass = { - .handle = NV_ENGCTX(SEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_falcon_context_ctor, - .dtor = _nvkm_falcon_context_dtor, - .init = _nvkm_falcon_context_init, - .fini = _nvkm_falcon_context_fini, - .rd32 = _nvkm_falcon_context_rd32, - .wr32 = _nvkm_falcon_context_wr32, - }, -}; - -/******************************************************************************* - * PSEC engine/subdev functions - ******************************************************************************/ +#include static const struct nvkm_enum g98_sec_isr_error_name[] = { { 0x0000, "ILLEGAL_MTHD" }, @@ -92,6 +63,10 @@ g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) static const struct nvkm_falcon_func g98_sec_func = { .intr = g98_sec_intr, + .sclass = { + { -1, -1, G98_SEC }, + {} + } }; static int @@ -109,8 +84,6 @@ g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; nv_subdev(sec)->unit = 0x00004000; - nv_engine(sec)->cclass = &g98_sec_cclass; - nv_engine(sec)->sclass = g98_sec_sclass; nv_falcon(sec)->code.data = g98_sec_code; nv_falcon(sec)->code.size = sizeof(g98_sec_code); nv_falcon(sec)->data.data = g98_sec_data; -- GitLab From c79a191b2799fb36a7b64c0f9ddc20383ed0dcdb Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5521/7006] drm/nouveau/xtensa: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 4 ++ .../gpu/drm/nouveau/include/nvkm/engine/bsp.h | 2 +- .../gpu/drm/nouveau/include/nvkm/engine/vp.h | 2 +- .../drm/nouveau/include/nvkm/engine/xtensa.h | 13 ++--- drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c | 41 ++++------------ drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c | 41 ++++------------ drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 47 ++++++++++++++----- 7 files changed, 63 insertions(+), 87 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 10b6685cf5e7a..1ce75be9c2d4c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -45,6 +45,8 @@ #define GM107_DISP 0x00009470 #define GM204_DISP 0x00009570 +#define NV74_VP2 0x00007476 + #define NV50_DISP_CURSOR 0x0000507a #define G82_DISP_CURSOR 0x0000827a #define GT214_DISP_CURSOR 0x0000857a @@ -94,6 +96,8 @@ #define MAXWELL_A 0x0000b097 #define MAXWELL_B 0x0000b197 +#define NV74_BSP 0x000074b0 + #define GT212_MSVLD 0x000085b1 #define IGT21A_MSVLD 0x000086b1 #define G98_MSVLD 0x000088b1 diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h index e489beef2b92b..af2134586eb7b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h @@ -1,5 +1,5 @@ #ifndef __NVKM_BSP_H__ #define __NVKM_BSP_H__ -#include +#include extern struct nvkm_oclass g84_bsp_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h index 7851f18c5add1..145216d312257 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h @@ -1,5 +1,5 @@ #ifndef __NVKM_VP_H__ #define __NVKM_VP_H__ -#include +#include extern struct nvkm_oclass g84_vp_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h index b05babfe0ca4c..6a53812c064d8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h @@ -1,9 +1,11 @@ #ifndef __NVKM_XTENSA_H__ #define __NVKM_XTENSA_H__ +#define nvkm_xtensa(p) container_of((p), struct nvkm_xtensa, engine) #include struct nvkm_xtensa { struct nvkm_engine engine; + const struct nvkm_xtensa_func *func; u32 addr; struct nvkm_memory *gpu_fw; @@ -11,16 +13,15 @@ struct nvkm_xtensa { u32 unkd28; }; +struct nvkm_xtensa_func { + void (*init)(struct nvkm_xtensa *); + struct nvkm_sclass sclass[]; +}; + #define nvkm_xtensa_create(p,e,c,b,d,i,f,r) \ nvkm_xtensa_create_((p), (e), (c), (b), (d), (i), (f), \ sizeof(**r),(void **)r) -int _nvkm_xtensa_engctx_ctor(struct nvkm_object *, - struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -void _nvkm_xtensa_intr(struct nvkm_subdev *); int nvkm_xtensa_create_(struct nvkm_object *, struct nvkm_object *, struct nvkm_oclass *, u32, bool, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c index 0f140bcd8e758..176495d9e7081 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c @@ -22,41 +22,17 @@ * Authors: Ben Skeggs, Ilia Mirkin */ #include -#include -#include +#include -/******************************************************************************* - * BSP object classes - ******************************************************************************/ - -static struct nvkm_oclass -g84_bsp_sclass[] = { - { 0x74b0, &nvkm_object_ofuncs }, - {}, +static const struct nvkm_xtensa_func +g84_bsp_func = { + .sclass = { + { -1, -1, NV74_BSP }, + {} + } }; -/******************************************************************************* - * BSP context - ******************************************************************************/ - -static struct nvkm_oclass -g84_bsp_cclass = { - .handle = NV_ENGCTX(BSP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_xtensa_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, -}; - -/******************************************************************************* - * BSP engine/subdev functions - ******************************************************************************/ - static int g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -71,9 +47,8 @@ g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + bsp->func = &g84_bsp_func; nv_subdev(bsp)->unit = 0x04008000; - nv_engine(bsp)->cclass = &g84_bsp_cclass; - nv_engine(bsp)->sclass = g84_bsp_sclass; bsp->fifo_val = 0x1111; bsp->unkd28 = 0x90044; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c index a4ff78a34566a..0035498024ec4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c @@ -22,41 +22,17 @@ * Authors: Ben Skeggs, Ilia Mirkin */ #include -#include -#include +#include -/******************************************************************************* - * VP object classes - ******************************************************************************/ - -static struct nvkm_oclass -g84_vp_sclass[] = { - { 0x7476, &nvkm_object_ofuncs }, - {}, +static const struct nvkm_xtensa_func +g84_vp_func = { + .sclass = { + { -1, -1, NV74_VP2 }, + {} + } }; -/******************************************************************************* - * PVP context - ******************************************************************************/ - -static struct nvkm_oclass -g84_vp_cclass = { - .handle = NV_ENGCTX(VP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_xtensa_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, -}; - -/******************************************************************************* - * PVP engine/subdev functions - ******************************************************************************/ - static int g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -71,9 +47,8 @@ g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + vp->func = &g84_vp_func; nv_subdev(vp)->unit = 0x01020000; - nv_engine(vp)->cclass = &g84_vp_cclass; - nv_engine(vp)->sclass = g84_vp_sclass; vp->fifo_val = 0x111; vp->unkd28 = 0x9c544; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index 6ffc6c4315b6c..fa8700005189e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -20,23 +20,37 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include +#include -#include - -int -_nvkm_xtensa_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static int +nvkm_xtensa_oclass_get(struct nvkm_oclass *oclass, int index) { - struct nvkm_engctx *engctx; - int ret; + struct nvkm_xtensa *xtensa = nvkm_xtensa(oclass->engine); + int c = 0; + + while (xtensa->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = xtensa->func->sclass[index]; + return index; + } + } - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x1000, - NVOBJ_FLAG_ZERO_ALLOC, &engctx); - *pobject = nv_object(engctx); - return ret; + return c; } +static int +nvkm_xtensa_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + return nvkm_gpuobj_new(object->engine->subdev.device, 0x10000, align, + true, parent, pgpuobj); +} + +static const struct nvkm_object_func +nvkm_xtensa_cclass = { + .bind = nvkm_xtensa_cclass_bind, +}; + void _nvkm_xtensa_intr(struct nvkm_subdev *subdev) { @@ -58,6 +72,12 @@ _nvkm_xtensa_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_engine_func +nvkm_xtensa = { + .fifo.sclass = nvkm_xtensa_oclass_get, + .cclass = &nvkm_xtensa_cclass, +}; + int nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, u32 addr, bool enable, @@ -73,7 +93,8 @@ nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_subdev(xtensa)->intr = _nvkm_xtensa_intr; + xtensa->engine.subdev.intr = _nvkm_xtensa_intr; + xtensa->engine.func = &nvkm_xtensa; xtensa->addr = addr; return 0; } -- GitLab From e5ff112781667dbe641aee2adf6189d8023cb27f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5522/7006] drm/nouveau/ce: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 2 + .../gpu/drm/nouveau/nvkm/engine/ce/gk104.c | 54 +++++-------------- .../gpu/drm/nouveau/nvkm/engine/ce/gm204.c | 54 +++++-------------- 3 files changed, 28 insertions(+), 82 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 1ce75be9c2d4c..d10cdfc777567 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -117,6 +117,8 @@ #define GT212_DMA 0x000085b5 #define FERMI_DMA 0x000090b5 +#define KEPLER_DMA_COPY_A 0x0000a0b5 +#define MAXWELL_DMA_COPY_A 0x0000b0b5 #define FERMI_DECOMPRESS 0x000090b8 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index 8fad0ef13bd06..f35677b87d29b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -22,42 +22,9 @@ * Authors: Ben Skeggs */ #include +#include -#include - -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_ce_sclass[] = { - { 0xa0b5, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_ofuncs -gk104_ce_context_ofuncs = { - .ctor = _nvkm_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, -}; - -static struct nvkm_oclass -gk104_ce_cclass = { - .handle = NV_ENGCTX(CE0, 0xc0), - .ofuncs = &gk104_ce_context_ofuncs, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ +#include static void gk104_ce_intr(struct nvkm_subdev *subdev) @@ -72,6 +39,14 @@ gk104_ce_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_engine_func +gk104_ce = { + .sclass = { + { -1, -1, KEPLER_DMA_COPY_A }, + {} + } +}; + static int gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -86,10 +61,9 @@ gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ce->func = &gk104_ce; nv_subdev(ce)->unit = 0x00000040; nv_subdev(ce)->intr = gk104_ce_intr; - nv_engine(ce)->cclass = &gk104_ce_cclass; - nv_engine(ce)->sclass = gk104_ce_sclass; return 0; } @@ -107,10 +81,9 @@ gk104_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ce->func = &gk104_ce; nv_subdev(ce)->unit = 0x00000080; nv_subdev(ce)->intr = gk104_ce_intr; - nv_engine(ce)->cclass = &gk104_ce_cclass; - nv_engine(ce)->sclass = gk104_ce_sclass; return 0; } @@ -128,10 +101,9 @@ gk104_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ce->func = &gk104_ce; nv_subdev(ce)->unit = 0x00200000; nv_subdev(ce)->intr = gk104_ce_intr; - nv_engine(ce)->cclass = &gk104_ce_cclass; - nv_engine(ce)->sclass = gk104_ce_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index 23dc90769b1ad..cb8faea1db74d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -22,42 +22,9 @@ * Authors: Ben Skeggs */ #include +#include -#include - -/******************************************************************************* - * Copy object classes - ******************************************************************************/ - -static struct nvkm_oclass -gm204_ce_sclass[] = { - { 0xb0b5, &nvkm_object_ofuncs }, - {}, -}; - -/******************************************************************************* - * PCE context - ******************************************************************************/ - -static struct nvkm_ofuncs -gm204_ce_context_ofuncs = { - .ctor = _nvkm_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, -}; - -static struct nvkm_oclass -gm204_ce_cclass = { - .handle = NV_ENGCTX(CE0, 0x24), - .ofuncs = &gm204_ce_context_ofuncs, -}; - -/******************************************************************************* - * PCE engine/subdev functions - ******************************************************************************/ +#include static void gm204_ce_intr(struct nvkm_subdev *subdev) @@ -72,6 +39,14 @@ gm204_ce_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_engine_func +gm204_ce = { + .sclass = { + { -1, -1, MAXWELL_DMA_COPY_A }, + {} + } +}; + static int gm204_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -86,10 +61,9 @@ gm204_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ce->func = &gm204_ce; nv_subdev(ce)->unit = 0x00000040; nv_subdev(ce)->intr = gm204_ce_intr; - nv_engine(ce)->cclass = &gm204_ce_cclass; - nv_engine(ce)->sclass = gm204_ce_sclass; return 0; } @@ -107,10 +81,9 @@ gm204_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ce->func = &gm204_ce; nv_subdev(ce)->unit = 0x00000080; nv_subdev(ce)->intr = gm204_ce_intr; - nv_engine(ce)->cclass = &gm204_ce_cclass; - nv_engine(ce)->sclass = gm204_ce_sclass; return 0; } @@ -128,10 +101,9 @@ gm204_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + ce->func = &gm204_ce; nv_subdev(ce)->unit = 0x00200000; nv_subdev(ce)->intr = gm204_ce_intr; - nv_engine(ce)->cclass = &gm204_ce_cclass; - nv_engine(ce)->sclass = gm204_ce_sclass; return 0; } -- GitLab From b3c981504721a5765641a21d521eb04f7d23e065 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5523/7006] drm/nouveau/cipher: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 3 +- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 93 ++++++++----------- 2 files changed, 38 insertions(+), 58 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index d10cdfc777567..3edd4c1d56311 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -124,13 +124,12 @@ #define FERMI_COMPUTE_A 0x000090c0 #define FERMI_COMPUTE_B 0x000091c0 - #define KEPLER_COMPUTE_A 0x0000a0c0 #define KEPLER_COMPUTE_B 0x0000a1c0 - #define MAXWELL_COMPUTE_A 0x0000b0c0 #define MAXWELL_COMPUTE_B 0x0000b1c0 +#define NV74_CIPHER 0x000074c1 /******************************************************************************* * client diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index 74bea4397bf4e..ae371ca64146c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -25,74 +25,47 @@ #include #include -#include #include +#include -/******************************************************************************* - * Crypt object classes - ******************************************************************************/ +#include static int -g84_cipher_object_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +g84_cipher_oclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nvkm_kmap(obj); - nvkm_wo32(obj, 0x00, nv_mclass(obj)); - nvkm_wo32(obj, 0x04, 0x00000000); - nvkm_wo32(obj, 0x08, 0x00000000); - nvkm_wo32(obj, 0x0c, 0x00000000); - nvkm_done(obj); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, + align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_ofuncs -g84_cipher_ofuncs = { - .ctor = g84_cipher_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, +static const struct nvkm_object_func +g84_cipher_oclass_func = { + .bind = g84_cipher_oclass_bind, }; -static struct nvkm_oclass -g84_cipher_sclass[] = { - { 0x74c1, &g84_cipher_ofuncs }, - {} -}; +static int +g84_cipher_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + return nvkm_gpuobj_new(object->engine->subdev.device, 256, + align, true, parent, pgpuobj); -/******************************************************************************* - * PCIPHER context - ******************************************************************************/ +} -static struct nvkm_oclass +static const struct nvkm_object_func g84_cipher_cclass = { - .handle = NV_ENGCTX(CIPHER, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_engctx_ctor, - .dtor = _nvkm_engctx_dtor, - .init = _nvkm_engctx_init, - .fini = _nvkm_engctx_fini, - .rd32 = _nvkm_engctx_rd32, - .wr32 = _nvkm_engctx_wr32, - }, + .bind = g84_cipher_cclass_bind, }; -/******************************************************************************* - * PCIPHER engine/subdev functions - ******************************************************************************/ - static const struct nvkm_bitfield g84_cipher_intr_mask[] = { { 0x00000001, "INVALID_STATE" }, @@ -132,6 +105,15 @@ g84_cipher_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x10200c, 0x10); } +static const struct nvkm_engine_func +g84_cipher = { + .cclass = &g84_cipher_cclass, + .sclass = { + { -1, -1, NV74_CIPHER, &g84_cipher_oclass_func }, + {} + } +}; + static int g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -146,10 +128,9 @@ g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + cipher->func = &g84_cipher, nv_subdev(cipher)->unit = 0x00004000; nv_subdev(cipher)->intr = g84_cipher_intr; - nv_engine(cipher)->cclass = &g84_cipher_cclass; - nv_engine(cipher)->sclass = g84_cipher_sclass; return 0; } -- GitLab From 27f3d6cf80324940edd29be7758f81145e73d1ff Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5524/7006] drm/nouveau/gr: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../drm/nouveau/include/nvkm/core/client.h | 1 - .../gpu/drm/nouveau/include/nvkm/engine/gr.h | 37 +- drivers/gpu/drm/nouveau/nvkm/core/client.c | 10 - drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c | 84 +++++ .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 63 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h | 39 +-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c | 29 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c | 53 ++- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c | 57 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c | 15 +- .../drm/nouveau/nvkm/engine/gr/ctxgk110b.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c | 71 ++-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c | 39 +-- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c | 2 - .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h | 2 - .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 4 - .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 204 ++++++----- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 27 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf104.c | 17 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf108.c | 30 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf110.c | 32 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf117.c | 19 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf119.c | 19 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk110.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk110b.c | 17 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk208.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm206.c | 17 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c | 25 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 265 +++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 319 +++++++++--------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 238 ++++++------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h | 15 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 184 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 144 ++++---- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 182 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 182 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 182 +++++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 259 +++++++------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h | 19 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 249 +++++++------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h | 24 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h | 15 + 55 files changed, 1760 insertions(+), 1738 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index d52ef8419fd27..14da7ad79c179 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -65,5 +65,5 @@ u64 nvif_device_time(struct nvif_device *); #include #define nvxx_fifo(a) nvxx_device(a)->fifo -#define nvxx_gr(a) nvkm_gr(nvxx_device(a)) +#define nvxx_gr(a) nvxx_device(a)->gr #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 7ec1762a0ec1d..5485bbac56772 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -30,7 +30,6 @@ int nvkm_client_new(const char *name, u64 device, const char *cfg, void nvkm_client_del(struct nvkm_client **); int nvkm_client_init(struct nvkm_client *); int nvkm_client_fini(struct nvkm_client *, bool suspend); -const char *nvkm_client_name(void *obj); static inline struct nvkm_client * nvkm_client(struct nvkm_object *object) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index 0fd02c27b869b..f09f1521e6ad4 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -1,44 +1,22 @@ #ifndef __NVKM_GR_H__ #define __NVKM_GR_H__ -#include - -struct nvkm_gr_chan { - struct nvkm_engctx base; -}; - -#define nvkm_gr_context_create(p,e,c,g,s,a,f,d) \ - nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) -#define nvkm_gr_context_destroy(d) \ - nvkm_engctx_destroy(&(d)->base) -#define nvkm_gr_context_init(d) \ - nvkm_engctx_init(&(d)->base) -#define nvkm_gr_context_fini(d,s) \ - nvkm_engctx_fini(&(d)->base, (s)) - -#define _nvkm_gr_context_dtor _nvkm_engctx_dtor -#define _nvkm_gr_context_init _nvkm_engctx_init -#define _nvkm_gr_context_fini _nvkm_engctx_fini -#define _nvkm_gr_context_rd32 _nvkm_engctx_rd32 -#define _nvkm_gr_context_wr32 _nvkm_engctx_wr32 - #include struct nvkm_gr { struct nvkm_engine engine; + const struct nvkm_gr_func *func; /* Returns chipset-specific counts of units packed into an u64. */ u64 (*units)(struct nvkm_gr *); }; -static inline struct nvkm_gr * -nvkm_gr(void *obj) -{ - return (void *)nvkm_engine(obj, NVDEV_ENGINE_GR); -} - #define nvkm_gr_create(p,e,c,y,d) \ - nvkm_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d)) + nvkm_gr_create_((p), (e), (c), (y), sizeof(**d), (void **)(d)) +int +nvkm_gr_create_(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, bool enable, + int length, void **pobject); #define nvkm_gr_destroy(d) \ nvkm_engine_destroy(&(d)->engine) #define nvkm_gr_init(d) \ @@ -79,8 +57,7 @@ extern struct nvkm_oclass *gm20b_gr_oclass; #include extern const struct nvkm_bitfield nv04_gr_nsource[]; -extern struct nvkm_ofuncs nv04_gr_ofuncs; -bool nv04_gr_idle(void *obj); +bool nv04_gr_idle(struct nvkm_gr *); extern const struct nvkm_bitfield nv10_gr_intr_name[]; extern const struct nvkm_bitfield nv10_gr_nstatus[]; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index 910f736cd1b6c..ab98f8c45950f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -321,13 +321,3 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, nvkm_client_del(pclient); return ret; } - -const char * -nvkm_client_name(void *obj) -{ - const char *client_name = "unknown"; - struct nvkm_client *client = nvkm_client(obj); - if (client) - client_name = client->name; - return client_name; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index cbdab5a686aff..79eceaac3c1d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -1,3 +1,4 @@ +nvkm-y += nvkm/engine/gr/base.o nvkm-y += nvkm/engine/gr/nv04.o nvkm-y += nvkm/engine/gr/nv10.o nvkm-y += nvkm/engine/gr/nv20.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c new file mode 100644 index 0000000000000..c6fb25847b89d --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c @@ -0,0 +1,84 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +#include + +static int +nvkm_gr_oclass_get(struct nvkm_oclass *oclass, int index) +{ + struct nvkm_gr *gr = nvkm_gr(oclass->engine); + int c = 0; + + if (gr->func->object_get) { + int ret = gr->func->object_get(gr, index, &oclass->base); + if (oclass->base.oclass) + return index; + return ret; + } + + while (gr->func->sclass[c].oclass) { + if (c++ == index) { + oclass->base = gr->func->sclass[index]; + return index; + } + } + + return c; +} + +static int +nvkm_gr_cclass_new(struct nvkm_fifo_chan *chan, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nvkm_gr *gr = nvkm_gr(oclass->engine); + if (gr->func->chan_new) + return gr->func->chan_new(gr, chan, oclass, pobject); + return 0; +} + +struct nvkm_engine_func +nvkm_gr = { + .fifo.cclass = nvkm_gr_cclass_new, + .fifo.sclass = nvkm_gr_oclass_get, +}; + +int +nvkm_gr_create_(struct nvkm_object *parent, struct nvkm_object *engine, + struct nvkm_oclass *oclass, bool enable, + int length, void **pobject) +{ + struct nvkm_gr *gr; + int ret; + + ret = nvkm_engine_create_(parent, engine, oclass, enable, + "gr", "gr", length, pobject); + gr = *pobject; + if (ret) + return ret; + + gr->engine.func = &nvkm_gr; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index d04c015eea818..96525b49e686d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1027,23 +1027,23 @@ gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data, void gf100_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + const int b = mmio_vram(info, grctx->bundle_size, (1 << s), access); mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); mmio_refn(info, 0x418808, 0x00000000, s, b); - mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s)); } void gf100_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); mmio_refn(info, 0x40800c, 0x00000000, s, b); mmio_wr32(info, 0x408010, 0x80000000); mmio_refn(info, 0x419004, 0x00000000, s, b); @@ -1054,9 +1054,9 @@ void gf100_grctx_generate_attrib(struct gf100_grctx *info) { struct gf100_gr *gr = info->gr; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(gr); - const u32 attrib = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 attrib = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); @@ -1072,7 +1072,7 @@ gf100_grctx_generate_attrib(struct gf100_grctx *info) const u32 o = TPC_UNIT(gpc, tpc, 0x0520); mmio_skip(info, o, (attrib << 16) | ++bo); mmio_wr32(info, o, (attrib << 16) | --bo); - bo += impl->attrib_nr_max; + bo += grctx->attrib_nr_max; } } } @@ -1237,22 +1237,22 @@ void gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - gf100_gr_mmio(gr, oclass->hub); - gf100_gr_mmio(gr, oclass->gpc); - gf100_gr_mmio(gr, oclass->zcull); - gf100_gr_mmio(gr, oclass->tpc); - gf100_gr_mmio(gr, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(gr); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); gf100_grctx_generate_tpcid(gr); gf100_grctx_generate_r406028(gr); @@ -1260,16 +1260,16 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_grctx_generate_r418bb8(gr); gf100_grctx_generate_r406800(gr); - gf100_gr_icmd(gr, oclass->icmd); + gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); - gf100_gr_mthd(gr, oclass->mthd); + gf100_gr_mthd(gr, grctx->mthd); nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); } int gf100_grctx_generate(struct gf100_gr *gr) { - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; struct nvkm_memory *chan; @@ -1352,7 +1352,7 @@ gf100_grctx_generate(struct gf100_gr *gr) ); } - oclass->main(gr, &info); + grctx->main(gr, &info); /* trigger a context unload by unsetting the "next channel valid" bit * and faking a context switch interrupt @@ -1383,17 +1383,8 @@ done: return ret; } -struct nvkm_oclass * -gf100_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf100_grctx = { .main = gf100_grctx_generate_main, .unkn = gf100_grctx_generate_unkn, .hub = gf100_grctx_pack_hub, @@ -1409,4 +1400,4 @@ gf100_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h index a555835b57893..3c64040ec5a25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h @@ -19,8 +19,7 @@ void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int) #define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1) #define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1) -struct gf100_grctx_oclass { - struct nvkm_oclass base; +struct gf100_grctx_func { /* main context generation function */ void (*main)(struct gf100_gr *, struct gf100_grctx *); /* context-specific modify-on-first-load list generation function */ @@ -50,13 +49,7 @@ struct gf100_grctx_oclass { u32 alpha_nr; }; -static inline const struct gf100_grctx_oclass * -gf100_grctx_impl(struct gf100_gr *gr) -{ - return (void *)nv_engine(gr)->cclass; -} - -extern struct nvkm_oclass *gf100_grctx_oclass; +extern const struct gf100_grctx_func gf100_grctx; int gf100_grctx_generate(struct gf100_gr *); void gf100_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gf100_grctx_generate_bundle(struct gf100_grctx *); @@ -69,20 +62,20 @@ void gf100_grctx_generate_r4060a8(struct gf100_gr *); void gf100_grctx_generate_r418bb8(struct gf100_gr *); void gf100_grctx_generate_r406800(struct gf100_gr *); -extern struct nvkm_oclass *gf108_grctx_oclass; +extern const struct gf100_grctx_func gf108_grctx; void gf108_grctx_generate_attrib(struct gf100_grctx *); void gf108_grctx_generate_unkn(struct gf100_gr *); -extern struct nvkm_oclass *gf104_grctx_oclass; -extern struct nvkm_oclass *gf110_grctx_oclass; +extern const struct gf100_grctx_func gf104_grctx; +extern const struct gf100_grctx_func gf110_grctx; -extern struct nvkm_oclass *gf117_grctx_oclass; +extern const struct gf100_grctx_func gf117_grctx; void gf117_grctx_generate_attrib(struct gf100_grctx *); -extern struct nvkm_oclass *gf119_grctx_oclass; +extern const struct gf100_grctx_func gf119_grctx; -extern struct nvkm_oclass *gk104_grctx_oclass; -extern struct nvkm_oclass *gk20a_grctx_oclass; +extern const struct gf100_grctx_func gk104_grctx; +extern const struct gf100_grctx_func gk20a_grctx; void gk104_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gk104_grctx_generate_bundle(struct gf100_grctx *); void gk104_grctx_generate_pagepool(struct gf100_grctx *); @@ -95,22 +88,22 @@ void gm107_grctx_generate_bundle(struct gf100_grctx *); void gm107_grctx_generate_pagepool(struct gf100_grctx *); void gm107_grctx_generate_attrib(struct gf100_grctx *); -extern struct nvkm_oclass *gk110_grctx_oclass; -extern struct nvkm_oclass *gk110b_grctx_oclass; -extern struct nvkm_oclass *gk208_grctx_oclass; +extern const struct gf100_grctx_func gk110_grctx; +extern const struct gf100_grctx_func gk110b_grctx; +extern const struct gf100_grctx_func gk208_grctx; -extern struct nvkm_oclass *gm107_grctx_oclass; +extern const struct gf100_grctx_func gm107_grctx; void gm107_grctx_generate_bundle(struct gf100_grctx *); void gm107_grctx_generate_pagepool(struct gf100_grctx *); void gm107_grctx_generate_attrib(struct gf100_grctx *); -extern struct nvkm_oclass *gm204_grctx_oclass; +extern const struct gf100_grctx_func gm204_grctx; void gm204_grctx_generate_main(struct gf100_gr *, struct gf100_grctx *); void gm204_grctx_generate_tpcid(struct gf100_gr *); void gm204_grctx_generate_405b60(struct gf100_gr *); -extern struct nvkm_oclass *gm206_grctx_oclass; -extern struct nvkm_oclass *gm20b_grctx_oclass; +extern const struct gf100_grctx_func gm206_grctx; +extern const struct gf100_grctx_func gm20b_grctx; /* context init value lists */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c index c5a8d55e2cac0..54fd74e9cca0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c @@ -79,17 +79,8 @@ gf104_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gf104_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf104_grctx = { .main = gf100_grctx_generate_main, .unkn = gf100_grctx_generate_unkn, .hub = gf100_grctx_pack_hub, @@ -105,4 +96,4 @@ gf104_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c index caccfed4ac7c5..505cdcbfc0855 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c @@ -731,17 +731,17 @@ void gf108_grctx_generate_attrib(struct gf100_grctx *info) { struct gf100_gr *gr = info->gr; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(gr); - const u32 alpha = impl->alpha_nr; - const u32 beta = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 beta = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * gr->tpc_total; + u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, tpc; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -757,9 +757,9 @@ gf108_grctx_generate_attrib(struct gf100_grctx *info) const u32 o = TPC_UNIT(gpc, tpc, 0x500); mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo); mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo); - bo += impl->attrib_nr_max; + bo += grctx->attrib_nr_max; mmio_wr32(info, o + 0x44, (a << 16) | ao); - ao += impl->alpha_nr_max; + ao += grctx->alpha_nr_max; } } } @@ -776,17 +776,8 @@ gf108_grctx_generate_unkn(struct gf100_gr *gr) nvkm_mask(device, 0x419c00, 0x00000008, 0x00000008); } -struct nvkm_oclass * -gf108_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf108_grctx = { .main = gf100_grctx_generate_main, .unkn = gf108_grctx_generate_unkn, .hub = gf108_grctx_pack_hub, @@ -804,4 +795,4 @@ gf108_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x324, .alpha_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c index b3acd931b978c..7df398b53f8f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c @@ -330,17 +330,8 @@ gf110_grctx_pack_gpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gf110_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xc8), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf110_grctx = { .main = gf100_grctx_generate_main, .unkn = gf100_grctx_generate_unkn, .hub = gf100_grctx_pack_hub, @@ -356,4 +347,4 @@ gf110_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib = gf100_grctx_generate_attrib, .attrib_nr_max = 0x324, .attrib_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index 78f6be2e92db8..6a3833b7cc4f7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -183,17 +183,17 @@ void gf117_grctx_generate_attrib(struct gf100_grctx *info) { struct gf100_gr *gr = info->gr; - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(gr); - const u32 alpha = impl->alpha_nr; - const u32 beta = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 beta = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int timeslice_mode = 1; const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * gr->tpc_total; + u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, ppc; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -209,9 +209,9 @@ gf117_grctx_generate_attrib(struct gf100_grctx *info) const u32 o = PPC_UNIT(gpc, ppc, 0); mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo); mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo); - bo += impl->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; + bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, o + 0xe4, (a << 16) | ao); - ao += impl->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; + ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; } } } @@ -220,23 +220,23 @@ void gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; int i; nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - gf100_gr_mmio(gr, oclass->hub); - gf100_gr_mmio(gr, oclass->gpc); - gf100_gr_mmio(gr, oclass->zcull); - gf100_gr_mmio(gr, oclass->tpc); - gf100_gr_mmio(gr, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(gr); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); gf100_grctx_generate_tpcid(gr); gf100_grctx_generate_r406028(gr); @@ -247,23 +247,14 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) for (i = 0; i < 8; i++) nvkm_wr32(device, 0x4064d0 + (i * 0x04), 0x00000000); - gf100_gr_icmd(gr, oclass->icmd); + gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); - gf100_gr_mthd(gr, oclass->mthd); + gf100_gr_mthd(gr, grctx->mthd); nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); } -struct nvkm_oclass * -gf117_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf117_grctx = { .main = gf117_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gf117_grctx_pack_hub, @@ -282,4 +273,4 @@ gf117_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x324, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c index 8d87614438098..605185b078be9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c @@ -498,17 +498,8 @@ gf119_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gf119_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xd9), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gf119_grctx = { .main = gf100_grctx_generate_main, .unkn = gf108_grctx_generate_unkn, .hub = gf119_grctx_pack_hub, @@ -526,4 +517,4 @@ gf119_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x324, .alpha_nr = 0x218, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index 0365acaf8c70b..77110ea019ea3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -843,27 +843,27 @@ gk104_grctx_pack_ppc[] = { void gk104_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); - const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, - impl->bundle_size / 0x20); - const u32 token_limit = impl->bundle_token_limit; + const struct gf100_grctx_func *grctx = info->gr->func->grctx; + const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, + grctx->bundle_size / 0x20); + const u32 token_limit = grctx->bundle_token_limit; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + const int b = mmio_vram(info, grctx->bundle_size, (1 << s), access); mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); mmio_refn(info, 0x418808, 0x00000000, s, b); - mmio_wr32(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x41880c, 0x80000000 | (grctx->bundle_size >> s)); mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); } void gk104_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); mmio_refn(info, 0x40800c, 0x00000000, s, b); mmio_wr32(info, 0x408010, 0x80000000); mmio_refn(info, 0x419004, 0x00000000, s, b); @@ -955,23 +955,23 @@ void gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; int i; nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); - gf100_gr_mmio(gr, oclass->hub); - gf100_gr_mmio(gr, oclass->gpc); - gf100_gr_mmio(gr, oclass->zcull); - gf100_gr_mmio(gr, oclass->tpc); - gf100_gr_mmio(gr, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(gr); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); gf100_grctx_generate_tpcid(gr); gf100_grctx_generate_r406028(gr); @@ -985,26 +985,17 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gk104_grctx_generate_rop_active_fbps(gr); nvkm_mask(device, 0x419f78, 0x00000001, 0x00000000); - gf100_gr_icmd(gr, oclass->icmd); + gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); - gf100_gr_mthd(gr, oclass->mthd); + gf100_gr_mthd(gr, grctx->mthd); nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); nvkm_mask(device, 0x418800, 0x00200000, 0x00200000); nvkm_mask(device, 0x41be10, 0x00800000, 0x00800000); } -struct nvkm_oclass * -gk104_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk104_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk104_grctx_pack_hub, @@ -1025,4 +1016,4 @@ gk104_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c index b3f58be04e9c3..7b95ec2fe4536 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c @@ -808,17 +808,8 @@ gk110_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gk110_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xf0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk110_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk110_grctx_pack_hub, @@ -839,4 +830,4 @@ gk110_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c index b11c26794fde8..048b1152da443 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c @@ -69,17 +69,8 @@ gk110b_grctx_pack_tpc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gk110b_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xf1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk110b_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk110_grctx_pack_hub, @@ -100,4 +91,4 @@ gk110b_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c index 6e8ce9fc311a2..67b7a1b43617e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c @@ -530,17 +530,8 @@ gk208_grctx_pack_ppc[] = { * PGRAPH context implementation ******************************************************************************/ -struct nvkm_oclass * -gk208_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk208_grctx = { .main = gk104_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gk208_grctx_pack_hub, @@ -561,4 +552,4 @@ gk208_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x218, .alpha_nr_max = 0x7ff, .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index 252bcc331a5a0..43d9ce2276685 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -29,7 +29,7 @@ static void gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; int idle_timeout_save; int i; @@ -40,9 +40,9 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) idle_timeout_save = nvkm_rd32(device, 0x404154); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->attrib(info); + grctx->attrib(info); - oclass->unkn(gr); + grctx->unkn(gr); gf100_grctx_generate_tpcid(gr); gf100_grctx_generate_r406028(gr); @@ -67,21 +67,12 @@ gk20a_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); gf100_gr_icmd(gr, gr->fuc_bundle); - oclass->pagepool(info); - oclass->bundle(info); + grctx->pagepool(info); + grctx->bundle(info); } -struct nvkm_oclass * -gk20a_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gk20a_grctx = { .main = gk20a_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .bundle = gk104_grctx_generate_bundle, @@ -95,4 +86,4 @@ gk20a_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x240, .alpha_nr_max = 0x648 + (0x648 / 2), .alpha_nr = 0x648, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c index 9c361ee21fbff..95f59e3169f25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c @@ -863,27 +863,27 @@ gm107_grctx_pack_ppc[] = { void gm107_grctx_generate_bundle(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); - const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth, - impl->bundle_size / 0x20); - const u32 token_limit = impl->bundle_token_limit; + const struct gf100_grctx_func *grctx = info->gr->func->grctx; + const u32 state_limit = min(grctx->bundle_min_gpm_fifo_depth, + grctx->bundle_size / 0x20); + const u32 token_limit = grctx->bundle_token_limit; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->bundle_size, (1 << s), access); + const int b = mmio_vram(info, grctx->bundle_size, (1 << s), access); mmio_refn(info, 0x408004, 0x00000000, s, b); - mmio_wr32(info, 0x408008, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x408008, 0x80000000 | (grctx->bundle_size >> s)); mmio_refn(info, 0x418e24, 0x00000000, s, b); - mmio_wr32(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s)); + mmio_wr32(info, 0x418e28, 0x80000000 | (grctx->bundle_size >> s)); mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit); } void gm107_grctx_generate_pagepool(struct gf100_grctx *info) { - const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->gr); + const struct gf100_grctx_func *grctx = info->gr->func->grctx; const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS; const int s = 8; - const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access); + const int b = mmio_vram(info, grctx->pagepool_size, (1 << s), access); mmio_refn(info, 0x40800c, 0x00000000, s, b); mmio_wr32(info, 0x408010, 0x80000000); mmio_refn(info, 0x419004, 0x00000000, s, b); @@ -896,16 +896,16 @@ void gm107_grctx_generate_attrib(struct gf100_grctx *info) { struct gf100_gr *gr = info->gr; - const struct gf100_grctx_oclass *impl = (void *)gf100_grctx_impl(gr); - const u32 alpha = impl->alpha_nr; - const u32 attrib = impl->attrib_nr; - const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max); + const struct gf100_grctx_func *grctx = gr->func->grctx; + const u32 alpha = grctx->alpha_nr; + const u32 attrib = grctx->attrib_nr; + const u32 size = 0x20 * (grctx->attrib_nr_max + grctx->alpha_nr_max); const u32 access = NV_MEM_ACCESS_RW; const int s = 12; const int b = mmio_vram(info, size * gr->tpc_total, (1 << s), access); const int max_batches = 0xffff; u32 bo = 0; - u32 ao = bo + impl->attrib_nr_max * gr->tpc_total; + u32 ao = bo + grctx->attrib_nr_max * gr->tpc_total; int gpc, ppc, n = 0; mmio_refn(info, 0x418810, 0x80000000, s, b); @@ -922,10 +922,10 @@ gm107_grctx_generate_attrib(struct gf100_grctx *info) const u32 o = PPC_UNIT(gpc, ppc, 0); mmio_wr32(info, o + 0xc0, bs); mmio_wr32(info, o + 0xf4, bo); - bo += impl->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; + bo += grctx->attrib_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, o + 0xe4, as); mmio_wr32(info, o + 0xf8, ao); - ao += impl->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; + ao += grctx->alpha_nr_max * gr->ppc_tpc_nr[gpc][ppc]; mmio_wr32(info, u, ((bs / 3 /*XXX*/) << 16) | bs); } } @@ -956,21 +956,21 @@ static void gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; int i; - gf100_gr_mmio(gr, oclass->hub); - gf100_gr_mmio(gr, oclass->gpc); - gf100_gr_mmio(gr, oclass->zcull); - gf100_gr_mmio(gr, oclass->tpc); - gf100_gr_mmio(gr, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(gr); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); gm107_grctx_generate_tpcid(gr); gf100_grctx_generate_r406028(gr); @@ -986,9 +986,9 @@ gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gk104_grctx_generate_rop_active_fbps(gr); - gf100_gr_icmd(gr, oclass->icmd); + gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); - gf100_gr_mthd(gr, oclass->mthd); + gf100_gr_mthd(gr, grctx->mthd); nvkm_mask(device, 0x419e00, 0x00808080, 0x00808080); nvkm_mask(device, 0x419ccc, 0x80000000, 0x80000000); @@ -996,17 +996,8 @@ gm107_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) nvkm_mask(device, 0x419f88, 0x80000000, 0x80000000); } -struct nvkm_oclass * -gm107_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm107_grctx = { .main = gm107_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gm107_grctx_pack_hub, @@ -1027,4 +1018,4 @@ gm107_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0xaa0, .alpha_nr_max = 0x1800, .alpha_nr = 0x1000, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c index f8c2432b7d7af..170cbfdbe1ae3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm204.c @@ -981,22 +981,22 @@ void gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; u32 tmp; int i; - gf100_gr_mmio(gr, oclass->hub); - gf100_gr_mmio(gr, oclass->gpc); - gf100_gr_mmio(gr, oclass->zcull); - gf100_gr_mmio(gr, oclass->tpc); - gf100_gr_mmio(gr, oclass->ppc); + gf100_gr_mmio(gr, grctx->hub); + gf100_gr_mmio(gr, grctx->gpc); + gf100_gr_mmio(gr, grctx->zcull); + gf100_gr_mmio(gr, grctx->tpc); + gf100_gr_mmio(gr, grctx->ppc); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->bundle(info); - oclass->pagepool(info); - oclass->attrib(info); - oclass->unkn(gr); + grctx->bundle(info); + grctx->pagepool(info); + grctx->attrib(info); + grctx->unkn(gr); gm204_grctx_generate_tpcid(gr); gf100_grctx_generate_r406028(gr); @@ -1016,25 +1016,16 @@ gm204_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gm204_grctx_generate_405b60(gr); - gf100_gr_icmd(gr, oclass->icmd); + gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000800); - gf100_gr_mthd(gr, oclass->mthd); + gf100_gr_mthd(gr, grctx->mthd); nvkm_mask(device, 0x418e94, 0xffffffff, 0xc4230000); nvkm_mask(device, 0x418e4c, 0xffffffff, 0x70000000); } -struct nvkm_oclass * -gm204_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm204_grctx = { .main = gm204_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gm204_grctx_pack_hub, @@ -1055,4 +1046,4 @@ gm204_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x400, .alpha_nr_max = 0x1800, .alpha_nr = 0x1000, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c index 91ec41617943f..d6be6034c2c25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm206.c @@ -49,17 +49,8 @@ gm206_grctx_pack_gpc[] = { {} }; -struct nvkm_oclass * -gm206_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x26), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm206_grctx = { .main = gm204_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .hub = gm204_grctx_pack_hub, @@ -80,4 +71,4 @@ gm206_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x400, .alpha_nr_max = 0x1800, .alpha_nr = 0x1000, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c index 5f5affc55fe0e..6702604025386 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm20b.c @@ -39,7 +39,7 @@ static void gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) { struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_grctx_oclass *oclass = (void *)nv_engine(gr)->cclass; + const struct gf100_grctx_func *grctx = gr->func->grctx; int idle_timeout_save; int i, tmp; @@ -50,9 +50,9 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) idle_timeout_save = nvkm_rd32(device, 0x404154); nvkm_wr32(device, 0x404154, 0x00000000); - oclass->attrib(info); + grctx->attrib(info); - oclass->unkn(gr); + grctx->unkn(gr); gm204_grctx_generate_tpcid(gr); gm20b_grctx_generate_r406028(gr); @@ -81,21 +81,12 @@ gm20b_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_wait_idle(gr); gf100_gr_icmd(gr, gr->fuc_bundle); - oclass->pagepool(info); - oclass->bundle(info); + grctx->pagepool(info); + grctx->bundle(info); } -struct nvkm_oclass * -gm20b_grctx_oclass = &(struct gf100_grctx_oclass) { - .base.handle = NV_ENGCTX(GR, 0x2b), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_context_ctor, - .dtor = gf100_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +const struct gf100_grctx_func +gm20b_grctx = { .main = gm20b_grctx_generate_main, .unkn = gk104_grctx_generate_unkn, .bundle = gm107_grctx_generate_bundle, @@ -109,4 +100,4 @@ gm20b_grctx_oclass = &(struct gf100_grctx_oclass) { .attrib_nr = 0x400, .alpha_nr_max = 0xc00, .alpha_nr = 0x800, -}.base; +}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c index 8ecdc94e3538b..80a6b017af647 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c @@ -580,7 +580,6 @@ nv40_gr_construct_shader(struct nvkm_grctx *ctx) if (ctx->mode != NVKM_GRCTX_VALS) return; - nvkm_kmap(obj); offset += 0x0280/4; for (i = 0; i < 16; i++, offset += 2) nvkm_wo32(obj, offset * 4, 0x3f800000); @@ -591,7 +590,6 @@ nv40_gr_construct_shader(struct nvkm_grctx *ctx) for (i = 0; i < vs_nr_b1 * 4; i += 4) nvkm_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000); } - nvkm_done(obj); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h index 6170b21b50ccf..50e808e9f926e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h @@ -125,8 +125,6 @@ gr_def(struct nvkm_grctx *ctx, u32 reg, u32 val) reg = (reg - 0x00400000) / 4; reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base; - nvkm_kmap(ctx->data); nvkm_wo32(ctx->data, reg * 4, val); - nvkm_done(ctx->data); } #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index 5bdb112dc945d..27fa96b222e3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -784,10 +784,8 @@ static void dd_emit(struct nvkm_grctx *ctx, int num, u32 val) { int i; if (val && ctx->mode == NVKM_GRCTX_VALS) { - nvkm_kmap(ctx->data); for (i = 0; i < num; i++) nvkm_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val); - nvkm_done(ctx->data); } ctx->ctxvals_pos += num; } @@ -1159,10 +1157,8 @@ static void xf_emit(struct nvkm_grctx *ctx, int num, u32 val) { int i; if (val && ctx->mode == NVKM_GRCTX_VALS) { - nvkm_kmap(ctx->data); for (i = 0; i < num; i++) nvkm_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val); - nvkm_done(ctx->data); } ctx->ctxvals_pos += num << 3; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index ebc9dee03beb8..7917d141fcb0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -223,12 +223,8 @@ gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } -struct nvkm_ofuncs -gf100_fermi_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, +const struct nvkm_object_func +gf100_fermi = { .mthd = gf100_fermi_mthd, }; @@ -259,40 +255,106 @@ gf100_gr_mthd_sw(struct nvkm_device *device, u16 class, u32 mthd, u32 data) return false; } -struct nvkm_oclass -gf100_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs }, - {} -}; +static int +gf100_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass) +{ + struct gf100_gr *gr = gf100_gr(base); + int c = 0; + + while (gr->func->sclass[c].oclass) { + if (c++ == index) { + *sclass = gr->func->sclass[index]; + return index; + } + } + + return c; +} /******************************************************************************* * PGRAPH context ******************************************************************************/ -int -gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *args, u32 size, - struct nvkm_object **pobject) +static int +gf100_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_vm *vm = nvkm_client(parent)->vm; - struct gf100_gr *gr = (void *)engine; + struct gf100_gr_chan *chan = gf100_gr_chan(object); + struct gf100_gr *gr = chan->gr; + int ret, i; + + ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, + align, false, parent, pgpuobj); + if (ret) + return ret; + + nvkm_kmap(*pgpuobj); + for (i = 0; i < gr->size; i += 4) + nvkm_wo32(*pgpuobj, i, gr->data[i / 4]); + + if (!gr->firmware) { + nvkm_wo32(*pgpuobj, 0x00, chan->mmio_nr / 2); + nvkm_wo32(*pgpuobj, 0x04, chan->mmio_vma.offset >> 8); + } else { + nvkm_wo32(*pgpuobj, 0xf4, 0); + nvkm_wo32(*pgpuobj, 0xf8, 0); + nvkm_wo32(*pgpuobj, 0x10, chan->mmio_nr / 2); + nvkm_wo32(*pgpuobj, 0x14, lower_32_bits(chan->mmio_vma.offset)); + nvkm_wo32(*pgpuobj, 0x18, upper_32_bits(chan->mmio_vma.offset)); + nvkm_wo32(*pgpuobj, 0x1c, 1); + nvkm_wo32(*pgpuobj, 0x20, 0); + nvkm_wo32(*pgpuobj, 0x28, 0); + nvkm_wo32(*pgpuobj, 0x2c, 0); + } + nvkm_done(*pgpuobj); + return 0; +} + +static void * +gf100_gr_chan_dtor(struct nvkm_object *object) +{ + struct gf100_gr_chan *chan = gf100_gr_chan(object); + int i; + + for (i = 0; i < ARRAY_SIZE(chan->data); i++) { + if (chan->data[i].vma.node) { + nvkm_vm_unmap(&chan->data[i].vma); + nvkm_vm_put(&chan->data[i].vma); + } + nvkm_memory_del(&chan->data[i].mem); + } + + if (chan->mmio_vma.node) { + nvkm_vm_unmap(&chan->mmio_vma); + nvkm_vm_put(&chan->mmio_vma); + } + nvkm_memory_del(&chan->mmio); + return chan; +} + +static const struct nvkm_object_func +gf100_gr_chan = { + .dtor = gf100_gr_chan_dtor, + .bind = gf100_gr_chan_bind, +}; + +static int +gf100_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct gf100_gr *gr = gf100_gr(base); struct gf100_gr_data *data = gr->mmio_data; struct gf100_gr_mmio *mmio = gr->mmio_list; struct gf100_gr_chan *chan; struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_gpuobj *image; int ret, i; - /* allocate memory for context, and fill with default values */ - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, - gr->size, 0x100, - NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&gf100_gr_chan, oclass, &chan->object); + chan->gr = gr; + *pobject = &chan->object; /* allocate memory for a "mmio list" buffer that's used by the HUB * fuc to modify some per-context register settings on first load @@ -303,7 +365,7 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_vm_get(vm, 0x1000, 12, NV_MEM_ACCESS_RW | + ret = nvkm_vm_get(fifoch->vm, 0x1000, 12, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS, &chan->mmio_vma); if (ret) return ret; @@ -318,8 +380,9 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_vm_get(vm, nvkm_memory_size(chan->data[i].mem), - 12, data->access, &chan->data[i].vma); + ret = nvkm_vm_get(fifoch->vm, + nvkm_memory_size(chan->data[i].mem), 12, + data->access, &chan->data[i].vma); if (ret) return ret; @@ -343,53 +406,9 @@ gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mmio++; } nvkm_done(chan->mmio); - - image = &chan->base.base.gpuobj; - nvkm_kmap(image); - for (i = 0; i < gr->size; i += 4) - nvkm_wo32(image, i, gr->data[i / 4]); - - if (!gr->firmware) { - nvkm_wo32(image, 0x00, chan->mmio_nr / 2); - nvkm_wo32(image, 0x04, chan->mmio_vma.offset >> 8); - } else { - nvkm_wo32(image, 0xf4, 0); - nvkm_wo32(image, 0xf8, 0); - nvkm_wo32(image, 0x10, chan->mmio_nr / 2); - nvkm_wo32(image, 0x14, lower_32_bits(chan->mmio_vma.offset)); - nvkm_wo32(image, 0x18, upper_32_bits(chan->mmio_vma.offset)); - nvkm_wo32(image, 0x1c, 1); - nvkm_wo32(image, 0x20, 0); - nvkm_wo32(image, 0x28, 0); - nvkm_wo32(image, 0x2c, 0); - } - nvkm_done(image); return 0; } -void -gf100_gr_context_dtor(struct nvkm_object *object) -{ - struct gf100_gr_chan *chan = (void *)object; - int i; - - for (i = 0; i < ARRAY_SIZE(chan->data); i++) { - if (chan->data[i].vma.node) { - nvkm_vm_unmap(&chan->data[i].vma); - nvkm_vm_put(&chan->data[i].vma); - } - nvkm_memory_del(&chan->data[i].mem); - } - - if (chan->mmio_vma.node) { - nvkm_vm_unmap(&chan->mmio_vma); - nvkm_vm_put(&chan->mmio_vma); - } - nvkm_memory_del(&chan->mmio); - - nvkm_gr_context_destroy(&chan->base); -} - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -1312,10 +1331,10 @@ gf100_gr_init_csdata(struct gf100_gr *gr, int gf100_gr_init_ctxctl(struct gf100_gr *gr) { + const struct gf100_grctx_func *grctx = gr->func->grctx; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass; - struct gf100_grctx_oclass *cclass = (void *)nv_engine(gr)->cclass; int i; if (gr->firmware) { @@ -1446,10 +1465,10 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); /* load register lists */ - gf100_gr_init_csdata(gr, cclass->hub, 0x409000, 0x000, 0x000000); - gf100_gr_init_csdata(gr, cclass->gpc, 0x41a000, 0x000, 0x418000); - gf100_gr_init_csdata(gr, cclass->tpc, 0x41a000, 0x004, 0x419800); - gf100_gr_init_csdata(gr, cclass->ppc, 0x41a000, 0x008, 0x41be00); + gf100_gr_init_csdata(gr, grctx->hub, 0x409000, 0x000, 0x000000); + gf100_gr_init_csdata(gr, grctx->gpc, 0x41a000, 0x000, 0x418000); + gf100_gr_init_csdata(gr, grctx->tpc, 0x41a000, 0x004, 0x419800); + gf100_gr_init_csdata(gr, grctx->ppc, 0x41a000, 0x008, 0x41be00); /* start HUB ucode running, it'll init the GPCs */ nvkm_wr32(device, 0x40910c, 0x00000000); @@ -1646,6 +1665,12 @@ gf100_gr_dtor(struct nvkm_object *object) nvkm_gr_destroy(&gr->base); } +static const struct nvkm_gr_func +gf100_gr_ = { + .chan_new = gf100_gr_chan_new, + .object_get = gf100_gr_object_get, +}; + int gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *bclass, void *data, u32 size, @@ -1666,6 +1691,8 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->func = oclass->func; + gr->base.func = &gf100_gr_; nv_subdev(gr)->unit = 0x08001000; nv_subdev(gr)->intr = gf100_gr_intr; @@ -1752,8 +1779,6 @@ gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, break; } - nv_engine(gr)->cclass = *oclass->cclass; - nv_engine(gr)->sclass = oclass->sclass; return 0; } @@ -1777,6 +1802,18 @@ gf100_gr_gpccs_ucode = { .data.size = sizeof(gf100_grgpc_data), }; +static const struct gf100_gr_func +gf100_gr = { + .grctx = &gf100_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gf100_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xc0), @@ -1786,8 +1823,7 @@ gf100_gr_oclass = &(struct gf100_gr_oclass) { .init = gf100_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gf100_grctx_oclass, - .sclass = gf100_gr_sclass, + .func = &gf100_gr, .mmio = gf100_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 612d5346eae90..43e9897ac8838 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -23,9 +23,12 @@ */ #ifndef __NVC0_GR_H__ #define __NVC0_GR_H__ -#include +#define gf100_gr(p) container_of((p), struct gf100_gr, base) +#include "priv.h" +#include #include +#include #define GPC_MAX 32 #define TPC_MAX (GPC_MAX * 8) @@ -69,6 +72,7 @@ struct gf100_gr_zbc_depth { struct gf100_gr { struct nvkm_gr base; + const struct gf100_gr_func *func; struct gf100_gr_fuc fuc409c; struct gf100_gr_fuc fuc409d; @@ -106,23 +110,27 @@ struct gf100_gr { u8 magic_not_rop_nr; }; +struct gf100_gr_func { + const struct gf100_grctx_func *grctx; + struct nvkm_sclass sclass[]; +}; + +#define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object) + struct gf100_gr_chan { - struct nvkm_gr_chan base; + struct nvkm_object object; + struct gf100_gr *gr; struct nvkm_memory *mmio; struct nvkm_vma mmio_vma; int mmio_nr; + struct { struct nvkm_memory *mem; struct nvkm_vma vma; } data[4]; }; -int gf100_gr_context_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_gr_context_dtor(struct nvkm_object *); - void gf100_gr_ctxctl_debug(struct gf100_gr *); void gf100_gr_dtor_fw(struct gf100_gr_fuc *); @@ -149,7 +157,7 @@ int gk20a_gr_init(struct nvkm_object *); int gm204_gr_init(struct nvkm_object *); -extern struct nvkm_ofuncs gf100_fermi_ofuncs; +extern const struct nvkm_object_func gf100_fermi; extern struct nvkm_oclass gf100_gr_sclass[]; extern struct nvkm_oclass gf110_gr_sclass[]; @@ -185,8 +193,7 @@ extern struct gf100_gr_ucode gk110_gr_gpccs_ucode; struct gf100_gr_oclass { struct nvkm_oclass base; - struct nvkm_oclass **cclass; - struct nvkm_oclass *sclass; + const struct gf100_gr_func *func; const struct gf100_gr_pack *mmio; struct { struct gf100_gr_ucode *ucode; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c index 20d3b85db3b51..aa529b5c0daaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -110,6 +112,18 @@ gf104_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct gf100_gr_func +gf104_gr = { + .grctx = &gf104_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gf104_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xc3), @@ -119,8 +133,7 @@ gf104_gr_oclass = &(struct gf100_gr_oclass) { .init = gf100_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gf104_grctx_oclass, - .sclass = gf100_gr_sclass, + .func = &gf104_gr, .mmio = gf104_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c index 1e8290ab1d374..971c897d59be9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c @@ -26,20 +26,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf108_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs }, - { FERMI_B, &gf100_fermi_ofuncs }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -117,6 +103,19 @@ gf108_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct gf100_gr_func +gf108_gr = { + .grctx = &gf108_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gf108_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xc1), @@ -126,8 +125,7 @@ gf108_gr_oclass = &(struct gf100_gr_oclass) { .init = gf100_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gf108_grctx_oclass, - .sclass = gf108_gr_sclass, + .func = &gf108_gr, .mmio = gf108_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c index 4fe0f969de826..f832a8bd454ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c @@ -26,21 +26,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -struct nvkm_oclass -gf110_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { FERMI_MEMORY_TO_MEMORY_FORMAT_A, &nvkm_object_ofuncs }, - { FERMI_A, &gf100_fermi_ofuncs }, - { FERMI_B, &gf100_fermi_ofuncs }, - { FERMI_C, &gf100_fermi_ofuncs }, - { FERMI_COMPUTE_A, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -99,6 +84,20 @@ gf110_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct gf100_gr_func +gf110_gr = { + .grctx = &gf110_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_C, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gf110_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xc8), @@ -108,8 +107,7 @@ gf110_gr_oclass = &(struct gf100_gr_oclass) { .init = gf100_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gf110_grctx_oclass, - .sclass = gf110_gr_sclass, + .func = &gf110_gr, .mmio = gf110_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c index 871ac5f806f6e..909b5a6fa8d2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -118,6 +120,20 @@ gf117_gr_gpccs_ucode = { .data.size = sizeof(gf117_grgpc_data), }; +static const struct gf100_gr_func +gf117_gr = { + .grctx = &gf117_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_C, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gf117_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xd7), @@ -127,8 +143,7 @@ gf117_gr_oclass = &(struct gf100_gr_oclass) { .init = gf100_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gf117_grctx_oclass, - .sclass = gf110_gr_sclass, + .func = &gf117_gr, .mmio = gf117_gr_pack_mmio, .fecs.ucode = &gf117_gr_fecs_ucode, .gpccs.ucode = &gf117_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c index e6dd651e26362..01c2dcc4e8733 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -173,6 +175,20 @@ gf119_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct gf100_gr_func +gf119_gr = { + .grctx = &gf119_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, FERMI_MEMORY_TO_MEMORY_FORMAT_A }, + { -1, -1, FERMI_A, &gf100_fermi }, + { -1, -1, FERMI_B, &gf100_fermi }, + { -1, -1, FERMI_C, &gf100_fermi }, + { -1, -1, FERMI_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gf119_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xd9), @@ -182,8 +198,7 @@ gf119_gr_oclass = &(struct gf100_gr_oclass) { .init = gf100_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gf119_grctx_oclass, - .sclass = gf110_gr_sclass, + .func = &gf119_gr, .mmio = gf119_gr_pack_mmio, .fecs.ucode = &gf100_gr_fecs_ucode, .gpccs.ucode = &gf100_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index a00731979698f..956e5926afe5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -28,19 +28,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk104_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs }, - { KEPLER_A, &gf100_fermi_ofuncs }, - { KEPLER_COMPUTE_A, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -311,6 +298,18 @@ gk104_gr_init(struct nvkm_object *object) return gf100_gr_init_ctxctl(gr); } +static const struct gf100_gr_func +gk104_gr = { + .grctx = &gk104_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_A }, + { -1, -1, KEPLER_A, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_A }, + {} + } +}; + int gk104_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -351,8 +350,7 @@ gk104_gr_oclass = &(struct gf100_gr_oclass) { .init = gk104_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gk104_grctx_oclass, - .sclass = gk104_gr_sclass, + .func = &gk104_gr, .mmio = gk104_gr_pack_mmio, .fecs.ucode = &gk104_gr_fecs_ucode, .gpccs.ucode = &gk104_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c index ec21f62e72486..fb513ea8bbd2a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c @@ -28,19 +28,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -struct nvkm_oclass -gk110_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { KEPLER_B, &gf100_fermi_ofuncs }, - { KEPLER_COMPUTE_B, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -193,6 +180,18 @@ gk110_gr_gpccs_ucode = { .data.size = sizeof(gk110_grgpc_data), }; +static const struct gf100_gr_func +gk110_gr = { + .grctx = &gk110_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, KEPLER_B, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_B }, + {} + } +}; + struct nvkm_oclass * gk110_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xf0), @@ -202,8 +201,7 @@ gk110_gr_oclass = &(struct gf100_gr_oclass) { .init = gk104_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gk110_grctx_oclass, - .sclass = gk110_gr_sclass, + .func = &gk110_gr, .mmio = gk110_gr_pack_mmio, .fecs.ucode = &gk110_gr_fecs_ucode, .gpccs.ucode = &gk110_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c index 9ff9eab0ccaff..b3da907b2b70e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c @@ -24,6 +24,8 @@ #include "gf100.h" #include "ctxgf100.h" +#include + /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -98,6 +100,18 @@ gk110b_gr_pack_mmio[] = { * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct gf100_gr_func +gk110b_gr = { + .grctx = &gk110b_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, KEPLER_B, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_B }, + {} + } +}; + struct nvkm_oclass * gk110b_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0xf1), @@ -107,8 +121,7 @@ gk110b_gr_oclass = &(struct gf100_gr_oclass) { .init = gk104_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gk110b_grctx_oclass, - .sclass = gk110_gr_sclass, + .func = &gk110b_gr, .mmio = gk110b_gr_pack_mmio, .fecs.ucode = &gk110_gr_fecs_ucode, .gpccs.ucode = &gk110_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c index 85f44a3d5d116..243b0a3f67c25 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c @@ -28,19 +28,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gk208_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { KEPLER_B, &gf100_fermi_ofuncs }, - { KEPLER_COMPUTE_B, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -172,6 +159,18 @@ gk208_gr_gpccs_ucode = { .data.size = sizeof(gk208_grgpc_data), }; +static const struct gf100_gr_func +gk208_gr = { + .grctx = &gk208_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, KEPLER_B, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_B }, + {} + } +}; + struct nvkm_oclass * gk208_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0x08), @@ -181,8 +180,7 @@ gk208_gr_oclass = &(struct gf100_gr_oclass) { .init = gk104_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gk208_grctx_oclass, - .sclass = gk208_gr_sclass, + .func = &gk208_gr, .mmio = gk208_gr_pack_mmio, .fecs.ucode = &gk208_gr_fecs_ucode, .gpccs.ucode = &gk208_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index c213e9a005c6a..a8100c4f5785d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -22,17 +22,9 @@ #include "gk20a.h" #include "ctxgf100.h" -#include #include -static struct nvkm_oclass -gk20a_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_A, &nvkm_object_ofuncs }, - { KEPLER_C, &gf100_fermi_ofuncs }, - { KEPLER_COMPUTE_A, &nvkm_object_ofuncs }, - {} -}; +#include static void gk20a_gr_init_dtor(struct gf100_gr_pack *pack) @@ -350,6 +342,18 @@ gk20a_gr_init(struct nvkm_object *object) return gf100_gr_init_ctxctl(gr); } +static const struct gf100_gr_func +gk20a_gr = { + .grctx = &gk20a_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_A }, + { -1, -1, KEPLER_C, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gk20a_gr_oclass = &(struct gk20a_gr_oclass) { .gf100 = { @@ -360,8 +364,7 @@ gk20a_gr_oclass = &(struct gk20a_gr_oclass) { .init = gk20a_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gk20a_grctx_oclass, - .sclass = gk20a_gr_sclass, + .func = &gk20a_gr, .ppc_nr = 1, }, .set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index aad5fdb29c60a..b3036cb610804 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -29,19 +29,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -gm107_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_A, &gf100_fermi_ofuncs }, - { MAXWELL_COMPUTE_A, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -454,6 +441,18 @@ gm107_gr_gpccs_ucode = { .data.size = sizeof(gm107_grgpc_data), }; +static const struct gf100_gr_func +gm107_gr = { + .grctx = &gm107_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_A, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_A }, + {} + } +}; + struct nvkm_oclass * gm107_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0x07), @@ -463,8 +462,7 @@ gm107_gr_oclass = &(struct gf100_gr_oclass) { .init = gm107_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gm107_grctx_oclass, - .sclass = gm107_gr_sclass, + .func = &gm107_gr, .mmio = gm107_gr_pack_mmio, .fecs.ucode = &gm107_gr_fecs_ucode, .gpccs.ucode = &gm107_gr_gpccs_ucode, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index 39f42a1c2b789..ff41232a8a536 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -26,19 +26,6 @@ #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -struct nvkm_oclass -gm204_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_B, &gf100_fermi_ofuncs }, - { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs }, - {} -}; - /******************************************************************************* * PGRAPH register lists ******************************************************************************/ @@ -371,6 +358,18 @@ gm204_gr_init(struct nvkm_object *object) return gm204_gr_init_ctxctl(gr); } +static const struct gf100_gr_func +gm204_gr = { + .grctx = &gm204_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_B, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_B }, + {} + } +}; + struct nvkm_oclass * gm204_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0x24), @@ -380,8 +379,7 @@ gm204_gr_oclass = &(struct gf100_gr_oclass) { .init = gm204_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gm204_grctx_oclass, - .sclass = gm204_gr_sclass, + .func = &gm204_gr, .mmio = gm204_gr_pack_mmio, .ppc_nr = 2, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c index 04b9733d146ad..4350b08f8dd22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c @@ -24,6 +24,20 @@ #include "gf100.h" #include "ctxgf100.h" +#include + +static const struct gf100_gr_func +gm206_gr = { + .grctx = &gm206_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_B, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_B }, + {} + } +}; + struct nvkm_oclass * gm206_gr_oclass = &(struct gf100_gr_oclass) { .base.handle = NV_ENGINE(GR, 0x26), @@ -33,8 +47,7 @@ gm206_gr_oclass = &(struct gf100_gr_oclass) { .init = gm204_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gm206_grctx_oclass, - .sclass = gm204_gr_sclass, + .func = &gm206_gr, .mmio = gm204_gr_pack_mmio, .ppc_nr = 2, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c index 87388926efa65..7a663654543bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -22,17 +22,9 @@ #include "gk20a.h" #include "ctxgf100.h" -#include #include -static struct nvkm_oclass -gm20b_gr_sclass[] = { - { FERMI_TWOD_A, &nvkm_object_ofuncs }, - { KEPLER_INLINE_TO_MEMORY_B, &nvkm_object_ofuncs }, - { MAXWELL_B, &gf100_fermi_ofuncs }, - { MAXWELL_COMPUTE_B, &nvkm_object_ofuncs }, - {} -}; +#include static void gm20b_gr_init_gpc_mmu(struct gf100_gr *gr) @@ -67,6 +59,18 @@ gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr) nvkm_wr32(device, 0x419e4c, 0x5); } +static const struct gf100_gr_func +gm20b_gr = { + .grctx = &gm20b_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_B }, + { -1, -1, MAXWELL_B, &gf100_fermi }, + { -1, -1, MAXWELL_COMPUTE_B }, + {} + } +}; + struct nvkm_oclass * gm20b_gr_oclass = &(struct gk20a_gr_oclass) { .gf100 = { @@ -77,8 +81,7 @@ gm20b_gr_oclass = &(struct gk20a_gr_oclass) { .init = gk20a_gr_init, .fini = _nvkm_gr_fini, }, - .cclass = &gm20b_grctx_oclass, - .sclass = gm20b_gr_sclass, + .func = &gm20b_gr, .ppc_nr = 1, }, .init_gpc_mmu = gm20b_gr_init_gpc_mmu, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index e2d3d79ee37b3..f06c16f61a981 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -21,7 +21,7 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include +#include "priv.h" #include "regs.h" #include @@ -345,25 +345,23 @@ nv04_gr_ctx_regs[] = { NV04_PGRAPH_DEBUG_3 }; +#define nv04_gr(p) container_of((p), struct nv04_gr, base) + struct nv04_gr { struct nvkm_gr base; struct nv04_gr_chan *chan[16]; spinlock_t lock; }; +#define nv04_gr_chan(p) container_of((p), struct nv04_gr_chan, object) + struct nv04_gr_chan { - struct nvkm_object base; + struct nvkm_object object; + struct nv04_gr *gr; int chid; u32 nv04[ARRAY_SIZE(nv04_gr_ctx_regs)]; }; - -static inline struct nv04_gr * -nv04_gr(struct nv04_gr_chan *chan) -{ - return (void *)nv_object(chan)->engine; -} - /******************************************************************************* * Graphics object classes ******************************************************************************/ @@ -1041,85 +1039,28 @@ nv04_gr_mthd(struct nvkm_device *device, u32 inst, u32 mthd, u32 data) } static int -nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nvkm_kmap(obj); - nvkm_wo32(obj, 0x00, nv_mclass(obj)); + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, align, + false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN - nvkm_mo32(obj, 0x00, 0x00080000, 0x00080000); + nvkm_mo32(*pgpuobj, 0x08, 0x00080000, 0x00080000); #endif - nvkm_wo32(obj, 0x04, 0x00000000); - nvkm_wo32(obj, 0x08, 0x00000000); - nvkm_wo32(obj, 0x0c, 0x00000000); - nvkm_done(obj); - return 0; + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -struct nvkm_ofuncs -nv04_gr_ofuncs = { - .ctor = nv04_gr_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv04_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0017, &nv04_gr_ofuncs }, /* chroma */ - { 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x001c, &nv04_gr_ofuncs }, /* line */ - { 0x001d, &nv04_gr_ofuncs }, /* tri */ - { 0x001e, &nv04_gr_ofuncs }, /* rect */ - { 0x001f, &nv04_gr_ofuncs }, - { 0x0021, &nv04_gr_ofuncs }, - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0036, &nv04_gr_ofuncs }, - { 0x0037, &nv04_gr_ofuncs }, - { 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0042, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x0048, &nv04_gr_ofuncs }, - { 0x004a, &nv04_gr_ofuncs }, - { 0x004b, &nv04_gr_ofuncs }, - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x0053, &nv04_gr_ofuncs }, - { 0x0054, &nv04_gr_ofuncs }, /* ttri */ - { 0x0055, &nv04_gr_ofuncs }, /* mtri */ - { 0x0057, &nv04_gr_ofuncs }, /* chroma */ - { 0x0058, &nv04_gr_ofuncs }, /* surf_dst */ - { 0x0059, &nv04_gr_ofuncs }, /* surf_src */ - { 0x005a, &nv04_gr_ofuncs }, /* surf_color */ - { 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */ - { 0x005c, &nv04_gr_ofuncs }, /* line */ - { 0x005d, &nv04_gr_ofuncs }, /* tri */ - { 0x005e, &nv04_gr_ofuncs }, /* rect */ - { 0x005f, &nv04_gr_ofuncs }, - { 0x0060, &nv04_gr_ofuncs }, - { 0x0061, &nv04_gr_ofuncs }, - { 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */ - { 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */ - { 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0076, &nv04_gr_ofuncs }, - { 0x0077, &nv04_gr_ofuncs }, - {}, +const struct nvkm_object_func +nv04_gr_object = { + .bind = nv04_gr_object_bind, }; /******************************************************************************* @@ -1142,8 +1083,7 @@ nv04_gr_channel(struct nv04_gr *gr) static int nv04_gr_load_context(struct nv04_gr_chan *chan, int chid) { - struct nv04_gr *gr = nv04_gr(chan); - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_device *device = chan->gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) @@ -1158,8 +1098,7 @@ nv04_gr_load_context(struct nv04_gr_chan *chan, int chid) static int nv04_gr_unload_context(struct nv04_gr_chan *chan) { - struct nv04_gr *gr = nv04_gr(chan); - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_device *device = chan->gr->base.engine.subdev.device; int i; for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) @@ -1178,7 +1117,7 @@ nv04_gr_context_switch(struct nv04_gr *gr) struct nv04_gr_chan *next = NULL; int chid; - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); /* If previous context is valid, we need to save it */ prev = nv04_gr_channel(gr); @@ -1204,59 +1143,24 @@ static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg) return NULL; } -static int -nv04_gr_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_fifo_chan *fifo = (void *)parent; - struct nv04_gr *gr = (void *)engine; - struct nv04_gr_chan *chan; - unsigned long flags; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - spin_lock_irqsave(&gr->lock, flags); - if (gr->chan[fifo->chid]) { - *pobject = nv_object(gr->chan[fifo->chid]); - atomic_inc(&(*pobject)->refcount); - spin_unlock_irqrestore(&gr->lock, flags); - nvkm_object_destroy(&chan->base); - return 1; - } - - *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; - - gr->chan[fifo->chid] = chan; - chan->chid = fifo->chid; - spin_unlock_irqrestore(&gr->lock, flags); - return 0; -} - -static void -nv04_gr_context_dtor(struct nvkm_object *object) +static void * +nv04_gr_chan_dtor(struct nvkm_object *object) { - struct nv04_gr *gr = (void *)object->engine; - struct nv04_gr_chan *chan = (void *)object; + struct nv04_gr_chan *chan = nv04_gr_chan(object); + struct nv04_gr *gr = chan->gr; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); gr->chan[chan->chid] = NULL; spin_unlock_irqrestore(&gr->lock, flags); - - nvkm_object_destroy(&chan->base); + return chan; } static int -nv04_gr_context_fini(struct nvkm_object *object, bool suspend) +nv04_gr_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv04_gr *gr = (void *)object->engine; - struct nv04_gr_chan *chan = (void *)object; + struct nv04_gr_chan *chan = nv04_gr_chan(object); + struct nv04_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; @@ -1266,34 +1170,50 @@ nv04_gr_context_fini(struct nvkm_object *object, bool suspend) nv04_gr_unload_context(chan); nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); spin_unlock_irqrestore(&gr->lock, flags); - - return _nvkm_object_fini(&chan->base, suspend); + return 0; } -static struct nvkm_oclass -nv04_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_gr_context_ctor, - .dtor = nv04_gr_context_dtor, - .init = _nvkm_object_init, - .fini = nv04_gr_context_fini, - }, +static const struct nvkm_object_func +nv04_gr_chan = { + .dtor = nv04_gr_chan_dtor, + .fini = nv04_gr_chan_fini, }; +static int +nv04_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) +{ + struct nv04_gr *gr = nv04_gr(base); + struct nv04_gr_chan *chan; + unsigned long flags; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv04_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31; + + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = chan; + spin_unlock_irqrestore(&gr->lock, flags); + return 0; +} + /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ bool -nv04_gr_idle(void *obj) +nv04_gr_idle(struct nvkm_gr *gr) { - struct nvkm_gr *gr = nvkm_gr(obj); struct nvkm_subdev *subdev = &gr->engine.subdev; struct nvkm_device *device = subdev->device; u32 mask = 0xffffffff; - if (nv_device(obj)->card_type == NV_40) + if (device->card_type == NV_40) mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL; if (nvkm_msec(device, 2000, @@ -1395,12 +1315,62 @@ nv04_gr_intr(struct nvkm_subdev *subdev) "nstatus %08x [%s] ch %d [%s] subc %d " "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, chid, - nvkm_client_name(chan), subc, class, mthd, data); + chan ? chan->object.client->name : "unknown", + subc, class, mthd, data); } spin_unlock_irqrestore(&gr->lock, flags); } +static const struct nvkm_gr_func +nv04_gr = { + .chan_new = nv04_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0017, &nv04_gr_object }, /* chroma */ + { -1, -1, 0x0018, &nv04_gr_object }, /* pattern (nv01) */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x001c, &nv04_gr_object }, /* line */ + { -1, -1, 0x001d, &nv04_gr_object }, /* tri */ + { -1, -1, 0x001e, &nv04_gr_object }, /* rect */ + { -1, -1, 0x001f, &nv04_gr_object }, + { -1, -1, 0x0021, &nv04_gr_object }, + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0036, &nv04_gr_object }, + { -1, -1, 0x0037, &nv04_gr_object }, + { -1, -1, 0x0038, &nv04_gr_object }, /* dvd subpicture */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0042, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x0048, &nv04_gr_object }, + { -1, -1, 0x004a, &nv04_gr_object }, + { -1, -1, 0x004b, &nv04_gr_object }, + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x0053, &nv04_gr_object }, + { -1, -1, 0x0054, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0055, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0057, &nv04_gr_object }, /* chroma */ + { -1, -1, 0x0058, &nv04_gr_object }, /* surf_dst */ + { -1, -1, 0x0059, &nv04_gr_object }, /* surf_src */ + { -1, -1, 0x005a, &nv04_gr_object }, /* surf_color */ + { -1, -1, 0x005b, &nv04_gr_object }, /* surf_zeta */ + { -1, -1, 0x005c, &nv04_gr_object }, /* line */ + { -1, -1, 0x005d, &nv04_gr_object }, /* tri */ + { -1, -1, 0x005e, &nv04_gr_object }, /* rect */ + { -1, -1, 0x005f, &nv04_gr_object }, + { -1, -1, 0x0060, &nv04_gr_object }, + { -1, -1, 0x0061, &nv04_gr_object }, + { -1, -1, 0x0064, &nv04_gr_object }, /* iifc (nv05) */ + { -1, -1, 0x0065, &nv04_gr_object }, /* ifc (nv05) */ + { -1, -1, 0x0066, &nv04_gr_object }, /* sifc (nv05) */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0076, &nv04_gr_object }, + { -1, -1, 0x0077, &nv04_gr_object }, + {} + } +}; + static int nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -1414,10 +1384,9 @@ nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv04_gr; nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv04_gr_intr; - nv_engine(gr)->cclass = &nv04_gr_cclass; - nv_engine(gr)->sclass = nv04_gr_sclass; spin_lock_init(&gr->lock); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 761aaa451e21b..98fb9e6efb975 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -21,7 +21,7 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include +#include "priv.h" #include "regs.h" #include @@ -385,14 +385,19 @@ static int nv17_gr_ctx_regs[] = { 0x00400a04, }; +#define nv10_gr(p) container_of((p), struct nv10_gr, base) + struct nv10_gr { struct nvkm_gr base; struct nv10_gr_chan *chan[32]; spinlock_t lock; }; +#define nv10_gr_chan(p) container_of((p), struct nv10_gr_chan, object) + struct nv10_gr_chan { - struct nvkm_object base; + struct nvkm_object object; + struct nv10_gr *gr; int chid; int nv10[ARRAY_SIZE(nv10_gr_ctx_regs)]; int nv17[ARRAY_SIZE(nv17_gr_ctx_regs)]; @@ -401,12 +406,6 @@ struct nv10_gr_chan { }; -static inline struct nv10_gr * -nv10_gr(struct nv10_gr_chan *chan) -{ - return (void *)nv_object(chan)->engine; -} - /******************************************************************************* * Graphics object classes ******************************************************************************/ @@ -427,57 +426,11 @@ nv10_gr(struct nv10_gr_chan *chan) nvkm_wr32(device, NV10_PGRAPH_PIPE_DATA, state[__i]); \ } while (0) -static struct nvkm_oclass -nv10_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x004a, &nv04_gr_ofuncs }, /* gdi */ - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x005f, &nv04_gr_ofuncs }, /* blit */ - { 0x0062, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs }, /* blit */ - { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ - { 0x0094, &nv04_gr_ofuncs }, /* ttri */ - { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0056, &nv04_gr_ofuncs }, /* celcius */ - {}, -}; - -static struct nvkm_oclass -nv15_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x004a, &nv04_gr_ofuncs }, /* gdi */ - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x005f, &nv04_gr_ofuncs }, /* blit */ - { 0x0062, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs }, /* blit */ - { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ - { 0x0094, &nv04_gr_ofuncs }, /* ttri */ - { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0096, &nv04_gr_ofuncs }, /* celcius */ - {}, -}; - static void nv17_gr_mthd_lma_window(struct nv10_gr_chan *chan, u32 mthd, u32 data) { - struct nvkm_device *device = chan->base.engine->subdev.device; - struct nvkm_gr *gr = nvkm_gr(chan); + struct nvkm_device *device = chan->object.engine->subdev.device; + struct nvkm_gr *gr = &chan->gr->base; struct pipe_state *pipe = &chan->pipe_state; u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3]; u32 xfmode0, xfmode1; @@ -549,8 +502,8 @@ nv17_gr_mthd_lma_window(struct nv10_gr_chan *chan, u32 mthd, u32 data) static void nv17_gr_mthd_lma_enable(struct nv10_gr_chan *chan, u32 mthd, u32 data) { - struct nvkm_device *device = chan->base.engine->subdev.device; - struct nvkm_gr *gr = nvkm_gr(chan); + struct nvkm_device *device = chan->object.engine->subdev.device; + struct nvkm_gr *gr = &chan->gr->base; nv04_gr_idle(gr); @@ -585,29 +538,6 @@ nv10_gr_mthd(struct nv10_gr_chan *chan, u8 class, u32 mthd, u32 data) return func(chan, mthd, data); } -static struct nvkm_oclass -nv17_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs }, /* clip */ - { 0x0030, &nv04_gr_ofuncs }, /* null */ - { 0x0039, &nv04_gr_ofuncs }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs }, /* rop */ - { 0x0044, &nv04_gr_ofuncs }, /* pattern */ - { 0x004a, &nv04_gr_ofuncs }, /* gdi */ - { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */ - { 0x005f, &nv04_gr_ofuncs }, /* blit */ - { 0x0062, &nv04_gr_ofuncs }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs }, /* blit */ - { 0x0093, &nv04_gr_ofuncs }, /* surf3d */ - { 0x0094, &nv04_gr_ofuncs }, /* ttri */ - { 0x0095, &nv04_gr_ofuncs }, /* mtri */ - { 0x0099, &nv04_gr_ofuncs }, - {}, -}; - /******************************************************************************* * PGRAPH context ******************************************************************************/ @@ -628,7 +558,7 @@ nv10_gr_channel(struct nv10_gr *gr) static void nv10_gr_save_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr *gr = nv10_gr(chan); + struct nv10_gr *gr = chan->gr; struct pipe_state *pipe = &chan->pipe_state; struct nvkm_device *device = gr->base.engine.subdev.device; @@ -647,13 +577,13 @@ nv10_gr_save_pipe(struct nv10_gr_chan *chan) static void nv10_gr_load_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr *gr = nv10_gr(chan); + struct nv10_gr *gr = chan->gr; struct pipe_state *pipe = &chan->pipe_state; struct nvkm_device *device = gr->base.engine.subdev.device; u32 xfmode0, xfmode1; int i; - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); /* XXX check haiku comments */ xfmode0 = nvkm_rd32(device, NV10_PGRAPH_XFMODE0); xfmode1 = nvkm_rd32(device, NV10_PGRAPH_XFMODE1); @@ -678,7 +608,7 @@ nv10_gr_load_pipe(struct nv10_gr_chan *chan) PIPE_RESTORE(gr, pipe->pipe_0x0200, 0x0200); - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); /* restore XFMODE */ nvkm_wr32(device, NV10_PGRAPH_XFMODE0, xfmode0); @@ -692,13 +622,13 @@ nv10_gr_load_pipe(struct nv10_gr_chan *chan) PIPE_RESTORE(gr, pipe->pipe_0x4400, 0x4400); PIPE_RESTORE(gr, pipe->pipe_0x0000, 0x0000); PIPE_RESTORE(gr, pipe->pipe_0x0040, 0x0040); - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); } static void nv10_gr_create_pipe(struct nv10_gr_chan *chan) { - struct nv10_gr *gr = nv10_gr(chan); + struct nv10_gr *gr = chan->gr; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct pipe_state *pipe_state = &chan->pipe_state; u32 *pipe_state_addr; @@ -880,7 +810,7 @@ nv17_gr_ctx_regs_find_offset(struct nv10_gr *gr, int reg) static void nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) { - struct nv10_gr *gr = nv10_gr(chan); + struct nv10_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4]; u32 ctx_user, ctx_switch[5]; @@ -951,7 +881,7 @@ nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst) static int nv10_gr_load_context(struct nv10_gr_chan *chan, int chid) { - struct nv10_gr *gr = nv10_gr(chan); + struct nv10_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; u32 inst; int i; @@ -979,7 +909,7 @@ nv10_gr_load_context(struct nv10_gr_chan *chan, int chid) static int nv10_gr_unload_context(struct nv10_gr_chan *chan) { - struct nv10_gr *gr = nv10_gr(chan); + struct nv10_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; int i; @@ -1007,7 +937,7 @@ nv10_gr_context_switch(struct nv10_gr *gr) struct nv10_gr_chan *next = NULL; int chid; - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); /* If previous context is valid, we need to save it */ prev = nv10_gr_channel(gr); @@ -1021,6 +951,42 @@ nv10_gr_context_switch(struct nv10_gr *gr) nv10_gr_load_context(next, chid); } +static int +nv10_gr_chan_fini(struct nvkm_object *object, bool suspend) +{ + struct nv10_gr_chan *chan = nv10_gr_chan(object); + struct nv10_gr *gr = chan->gr; + struct nvkm_device *device = gr->base.engine.subdev.device; + unsigned long flags; + + spin_lock_irqsave(&gr->lock, flags); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); + if (nv10_gr_channel(gr) == chan) + nv10_gr_unload_context(chan); + nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); + return 0; +} + +static void * +nv10_gr_chan_dtor(struct nvkm_object *object) +{ + struct nv10_gr_chan *chan = nv10_gr_chan(object); + struct nv10_gr *gr = chan->gr; + unsigned long flags; + + spin_lock_irqsave(&gr->lock, flags); + gr->chan[chan->chid] = NULL; + spin_unlock_irqrestore(&gr->lock, flags); + return chan; +} + +static const struct nvkm_object_func +nv10_gr_chan = { + .dtor = nv10_gr_chan_dtor, + .fini = nv10_gr_chan_fini, +}; + #define NV_WRITE_CTX(reg, val) do { \ int offset = nv10_gr_ctx_regs_find_offset(gr, reg); \ if (offset > 0) \ @@ -1034,30 +1000,20 @@ nv10_gr_context_switch(struct nv10_gr *gr) } while (0) static int -nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nvkm_fifo_chan *fifo = (void *)parent; - struct nv10_gr *gr = (void *)engine; + struct nv10_gr *gr = nv10_gr(base); struct nv10_gr_chan *chan; struct nvkm_device *device = gr->base.engine.subdev.device; unsigned long flags; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - spin_lock_irqsave(&gr->lock, flags); - if (gr->chan[fifo->chid]) { - *pobject = nv_object(gr->chan[fifo->chid]); - atomic_inc(&(*pobject)->refcount); - spin_unlock_irqrestore(&gr->lock, flags); - nvkm_object_destroy(&chan->base); - return 1; - } + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv10_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; NV_WRITE_CTX(0x00400e88, 0x08000000); NV_WRITE_CTX(0x00400e9c, 0x4b7fffff); @@ -1066,11 +1022,10 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, NV_WRITE_CTX(0x00400e14, 0x00001000); NV_WRITE_CTX(0x00400e30, 0x00080008); NV_WRITE_CTX(0x00400e34, 0x00080008); - if (nv_device(gr)->card_type >= NV_11 && - nv_device(gr)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { /* is it really needed ??? */ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4, - nvkm_rd32(device, NV10_PGRAPH_DEBUG_4)); + nvkm_rd32(device, NV10_PGRAPH_DEBUG_4)); NV17_WRITE_CTX(0x004006b0, nvkm_rd32(device, 0x004006b0)); NV17_WRITE_CTX(0x00400eac, 0x0fff0000); NV17_WRITE_CTX(0x00400eb0, 0x0fff0000); @@ -1081,55 +1036,12 @@ nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv10_gr_create_pipe(chan); - gr->chan[fifo->chid] = chan; - chan->chid = fifo->chid; - spin_unlock_irqrestore(&gr->lock, flags); - return 0; -} - -static void -nv10_gr_context_dtor(struct nvkm_object *object) -{ - struct nv10_gr *gr = (void *)object->engine; - struct nv10_gr_chan *chan = (void *)object; - unsigned long flags; - spin_lock_irqsave(&gr->lock, flags); - gr->chan[chan->chid] = NULL; + gr->chan[chan->chid] = chan; spin_unlock_irqrestore(&gr->lock, flags); - - nvkm_object_destroy(&chan->base); -} - -static int -nv10_gr_context_fini(struct nvkm_object *object, bool suspend) -{ - struct nv10_gr *gr = (void *)object->engine; - struct nv10_gr_chan *chan = (void *)object; - struct nvkm_device *device = gr->base.engine.subdev.device; - unsigned long flags; - - spin_lock_irqsave(&gr->lock, flags); - nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000); - if (nv10_gr_channel(gr) == chan) - nv10_gr_unload_context(chan); - nvkm_mask(device, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&gr->lock, flags); - - return _nvkm_object_fini(&chan->base, suspend); + return 0; } -static struct nvkm_oclass -nv10_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_gr_context_ctor, - .dtor = nv10_gr_context_dtor, - .init = _nvkm_object_init, - .fini = nv10_gr_context_fini, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ @@ -1144,7 +1056,7 @@ nv10_gr_tile_prog(struct nvkm_engine *engine, int i) unsigned long flags; fifo->pause(fifo, &flags); - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); nvkm_wr32(device, NV10_PGRAPH_TLIMIT(i), tile->limit); nvkm_wr32(device, NV10_PGRAPH_TSIZE(i), tile->pitch); @@ -1214,12 +1126,92 @@ nv10_gr_intr(struct nvkm_subdev *subdev) "nstatus %08x [%s] ch %d [%s] subc %d " "class %04x mthd %04x data %08x\n", show, msg, nsource, src, nstatus, sta, chid, - nvkm_client_name(chan), subc, class, mthd, data); + chan ? chan->object.client->name : "unknown", + subc, class, mthd, data); } spin_unlock_irqrestore(&gr->lock, flags); } +static const struct nvkm_gr_func +nv10_gr = { + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0056, &nv04_gr_object }, /* celcius */ + {} + } +}; + +static const struct nvkm_gr_func +nv15_gr = { + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + {} + } +}; + + +static const struct nvkm_gr_func +nv17_gr = { + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0099, &nv04_gr_object }, + {} + } +}; + static int nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -1235,16 +1227,15 @@ nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv10_gr_intr; - nv_engine(gr)->cclass = &nv10_gr_cclass; if (nv_device(gr)->chipset <= 0x10) - nv_engine(gr)->sclass = nv10_gr_sclass; + gr->base.func = &nv10_gr; else if (nv_device(gr)->chipset < 0x17 || nv_device(gr)->card_type < NV_11) - nv_engine(gr)->sclass = nv15_gr_sclass; + gr->base.func = &nv15_gr; else - nv_engine(gr)->sclass = nv17_gr_sclass; + gr->base.func = &nv17_gr; nv_engine(gr)->tile_prog = nv10_gr_tile_prog; spin_lock_init(&gr->lock); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 29feab391fe40..554f2e3f7e5b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -7,131 +7,37 @@ #include #include -/******************************************************************************* - * Graphics object classes - ******************************************************************************/ - -static struct nvkm_oclass -nv20_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */ - { 0x0097, &nv04_gr_ofuncs, NULL }, /* kelvin */ - { 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - {}, -}; - /******************************************************************************* * PGRAPH context ******************************************************************************/ -static int -nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv20_gr_chan *chan; - struct nvkm_gpuobj *image; - int ret, i; - - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x37f0, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - chan->chid = nvkm_fifo_chan(parent)->chid; - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0000, 0x00000001 | (chan->chid << 24)); - nvkm_wo32(image, 0x033c, 0xffff0000); - nvkm_wo32(image, 0x03a0, 0x0fff0000); - nvkm_wo32(image, 0x03a4, 0x0fff0000); - nvkm_wo32(image, 0x047c, 0x00000101); - nvkm_wo32(image, 0x0490, 0x00000111); - nvkm_wo32(image, 0x04a8, 0x44400000); - for (i = 0x04d4; i <= 0x04e0; i += 4) - nvkm_wo32(image, i, 0x00030303); - for (i = 0x04f4; i <= 0x0500; i += 4) - nvkm_wo32(image, i, 0x00080000); - for (i = 0x050c; i <= 0x0518; i += 4) - nvkm_wo32(image, i, 0x01012000); - for (i = 0x051c; i <= 0x0528; i += 4) - nvkm_wo32(image, i, 0x000105b8); - for (i = 0x052c; i <= 0x0538; i += 4) - nvkm_wo32(image, i, 0x00080008); - for (i = 0x055c; i <= 0x0598; i += 4) - nvkm_wo32(image, i, 0x07ff0000); - nvkm_wo32(image, 0x05a4, 0x4b7fffff); - nvkm_wo32(image, 0x05fc, 0x00000001); - nvkm_wo32(image, 0x0604, 0x00004000); - nvkm_wo32(image, 0x0610, 0x00000001); - nvkm_wo32(image, 0x0618, 0x00040000); - nvkm_wo32(image, 0x061c, 0x00010000); - for (i = 0x1c1c; i <= 0x248c; i += 16) { - nvkm_wo32(image, (i + 0), 0x10700ff9); - nvkm_wo32(image, (i + 4), 0x0436086c); - nvkm_wo32(image, (i + 8), 0x000c001b); - } - nvkm_wo32(image, 0x281c, 0x3f800000); - nvkm_wo32(image, 0x2830, 0x3f800000); - nvkm_wo32(image, 0x285c, 0x40000000); - nvkm_wo32(image, 0x2860, 0x3f800000); - nvkm_wo32(image, 0x2864, 0x3f000000); - nvkm_wo32(image, 0x286c, 0x40000000); - nvkm_wo32(image, 0x2870, 0x3f800000); - nvkm_wo32(image, 0x2878, 0xbf800000); - nvkm_wo32(image, 0x2880, 0xbf800000); - nvkm_wo32(image, 0x34a4, 0x000fe000); - nvkm_wo32(image, 0x3530, 0x000003f8); - nvkm_wo32(image, 0x3540, 0x002fe000); - for (i = 0x355c; i <= 0x3578; i += 4) - nvkm_wo32(image, i, 0x001c527c); - nvkm_done(image); - return 0; -} - int -nv20_gr_context_init(struct nvkm_object *object) +nv20_gr_chan_init(struct nvkm_object *object) { - struct nv20_gr *gr = (void *)object->engine; - struct nv20_gr_chan *chan = (void *)object; - int ret; - - ret = nvkm_gr_context_init(&chan->base); - if (ret) - return ret; + struct nv20_gr_chan *chan = nv20_gr_chan(object); + struct nv20_gr *gr = chan->gr; + u32 inst = nvkm_memory_addr(chan->inst); nvkm_kmap(gr->ctxtab); - nvkm_wo32(gr->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4); + nvkm_wo32(gr->ctxtab, chan->chid * 4, inst >> 4); nvkm_done(gr->ctxtab); return 0; } int -nv20_gr_context_fini(struct nvkm_object *object, bool suspend) +nv20_gr_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv20_gr *gr = (void *)object->engine; - struct nv20_gr_chan *chan = (void *)object; + struct nv20_gr_chan *chan = nv20_gr_chan(object); + struct nv20_gr *gr = chan->gr; struct nvkm_device *device = gr->base.engine.subdev.device; + u32 inst = nvkm_memory_addr(chan->inst); int chid = -1; nvkm_mask(device, 0x400720, 0x00000001, 0x00000000); if (nvkm_rd32(device, 0x400144) & 0x00010000) chid = (nvkm_rd32(device, 0x400148) & 0x1f000000) >> 24; if (chan->chid == chid) { - nvkm_wr32(device, 0x400784, nv_gpuobj(chan)->addr >> 4); + nvkm_wr32(device, 0x400784, inst >> 4); nvkm_wr32(device, 0x400788, 0x00000002); nvkm_msec(device, 2000, if (!nvkm_rd32(device, 0x400700)) @@ -145,23 +51,94 @@ nv20_gr_context_fini(struct nvkm_object *object, bool suspend) nvkm_kmap(gr->ctxtab); nvkm_wo32(gr->ctxtab, chan->chid * 4, 0x00000000); nvkm_done(gr->ctxtab); + return 0; +} - return nvkm_gr_context_fini(&chan->base, suspend); +void * +nv20_gr_chan_dtor(struct nvkm_object *object) +{ + struct nv20_gr_chan *chan = nv20_gr_chan(object); + nvkm_memory_del(&chan->inst); + return chan; } -static struct nvkm_oclass -nv20_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x20), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv20_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +static const struct nvkm_object_func +nv20_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; +static int +nv20_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) +{ + struct nv20_gr *gr = nv20_gr(base); + struct nv20_gr_chan *chan; + int ret, i; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv20_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x37f0, 16, true, + &chan->inst); + if (ret) + return ret; + + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0000, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x033c, 0xffff0000); + nvkm_wo32(chan->inst, 0x03a0, 0x0fff0000); + nvkm_wo32(chan->inst, 0x03a4, 0x0fff0000); + nvkm_wo32(chan->inst, 0x047c, 0x00000101); + nvkm_wo32(chan->inst, 0x0490, 0x00000111); + nvkm_wo32(chan->inst, 0x04a8, 0x44400000); + for (i = 0x04d4; i <= 0x04e0; i += 4) + nvkm_wo32(chan->inst, i, 0x00030303); + for (i = 0x04f4; i <= 0x0500; i += 4) + nvkm_wo32(chan->inst, i, 0x00080000); + for (i = 0x050c; i <= 0x0518; i += 4) + nvkm_wo32(chan->inst, i, 0x01012000); + for (i = 0x051c; i <= 0x0528; i += 4) + nvkm_wo32(chan->inst, i, 0x000105b8); + for (i = 0x052c; i <= 0x0538; i += 4) + nvkm_wo32(chan->inst, i, 0x00080008); + for (i = 0x055c; i <= 0x0598; i += 4) + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x05a4, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x05fc, 0x00000001); + nvkm_wo32(chan->inst, 0x0604, 0x00004000); + nvkm_wo32(chan->inst, 0x0610, 0x00000001); + nvkm_wo32(chan->inst, 0x0618, 0x00040000); + nvkm_wo32(chan->inst, 0x061c, 0x00010000); + for (i = 0x1c1c; i <= 0x248c; i += 16) { + nvkm_wo32(chan->inst, (i + 0), 0x10700ff9); + nvkm_wo32(chan->inst, (i + 4), 0x0436086c); + nvkm_wo32(chan->inst, (i + 8), 0x000c001b); + } + nvkm_wo32(chan->inst, 0x281c, 0x3f800000); + nvkm_wo32(chan->inst, 0x2830, 0x3f800000); + nvkm_wo32(chan->inst, 0x285c, 0x40000000); + nvkm_wo32(chan->inst, 0x2860, 0x3f800000); + nvkm_wo32(chan->inst, 0x2864, 0x3f000000); + nvkm_wo32(chan->inst, 0x286c, 0x40000000); + nvkm_wo32(chan->inst, 0x2870, 0x3f800000); + nvkm_wo32(chan->inst, 0x2878, 0xbf800000); + nvkm_wo32(chan->inst, 0x2880, 0xbf800000); + nvkm_wo32(chan->inst, 0x34a4, 0x000fe000); + nvkm_wo32(chan->inst, 0x3530, 0x000003f8); + nvkm_wo32(chan->inst, 0x3540, 0x002fe000); + for (i = 0x355c; i <= 0x3578; i += 4) + nvkm_wo32(chan->inst, i, 0x001c527c); + nvkm_done(chan->inst); + return 0; +} + /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ @@ -176,7 +153,7 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) unsigned long flags; fifo->pause(fifo, &flags); - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); @@ -237,6 +214,29 @@ nv20_gr_intr(struct nvkm_subdev *subdev) nvkm_fifo_chan_put(device->fifo, flags, &chan); } +static const struct nvkm_gr_func +nv20_gr = { + .chan_new = nv20_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x0097, &nv04_gr_object }, /* kelvin */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + {} + } +}; + static int nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -251,6 +251,8 @@ nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv20_gr; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, &gr->ctxtab); if (ret) @@ -258,8 +260,6 @@ nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->cclass = &nv20_gr_cclass; - nv_engine(gr)->sclass = nv20_gr_sclass; nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h index bffbba075b4dd..1ae4f2acc612a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h @@ -1,20 +1,25 @@ #ifndef __NV20_GR_H__ #define __NV20_GR_H__ -#include +#define nv20_gr(p) container_of((p), struct nv20_gr, base) +#include "priv.h" struct nv20_gr { struct nvkm_gr base; struct nvkm_memory *ctxtab; }; +#define nv20_gr_chan(p) container_of((p), struct nv20_gr_chan, object) + struct nv20_gr_chan { - struct nvkm_gr_chan base; + struct nvkm_object object; + struct nv20_gr *gr; int chid; + struct nvkm_memory *inst; }; -extern struct nvkm_oclass nv25_gr_sclass[]; -int nv20_gr_context_init(struct nvkm_object *); -int nv20_gr_context_fini(struct nvkm_object *, bool); +void *nv20_gr_chan_dtor(struct nvkm_object *); +int nv20_gr_chan_init(struct nvkm_object *); +int nv20_gr_chan_fini(struct nvkm_object *, bool); void nv20_gr_tile_prog(struct nvkm_engine *, int); void nv20_gr_intr(struct nvkm_subdev *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index 9cb5a90dde514..7fb53d53426cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -5,126 +5,122 @@ #include /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -struct nvkm_oclass -nv25_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */ - { 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0597, &nv04_gr_ofuncs, NULL }, /* kelvin */ - {}, +static const struct nvkm_object_func +nv25_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv25_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv25_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; - struct nvkm_gpuobj *image; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x3724, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv25_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x3724, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); - nvkm_wo32(image, 0x035c, 0xffff0000); - nvkm_wo32(image, 0x03c0, 0x0fff0000); - nvkm_wo32(image, 0x03c4, 0x0fff0000); - nvkm_wo32(image, 0x049c, 0x00000101); - nvkm_wo32(image, 0x04b0, 0x00000111); - nvkm_wo32(image, 0x04c8, 0x00000080); - nvkm_wo32(image, 0x04cc, 0xffff0000); - nvkm_wo32(image, 0x04d0, 0x00000001); - nvkm_wo32(image, 0x04e4, 0x44400000); - nvkm_wo32(image, 0x04fc, 0x4b800000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x035c, 0xffff0000); + nvkm_wo32(chan->inst, 0x03c0, 0x0fff0000); + nvkm_wo32(chan->inst, 0x03c4, 0x0fff0000); + nvkm_wo32(chan->inst, 0x049c, 0x00000101); + nvkm_wo32(chan->inst, 0x04b0, 0x00000111); + nvkm_wo32(chan->inst, 0x04c8, 0x00000080); + nvkm_wo32(chan->inst, 0x04cc, 0xffff0000); + nvkm_wo32(chan->inst, 0x04d0, 0x00000001); + nvkm_wo32(chan->inst, 0x04e4, 0x44400000); + nvkm_wo32(chan->inst, 0x04fc, 0x4b800000); for (i = 0x0510; i <= 0x051c; i += 4) - nvkm_wo32(image, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x0530; i <= 0x053c; i += 4) - nvkm_wo32(image, i, 0x00080000); + nvkm_wo32(chan->inst, i, 0x00080000); for (i = 0x0548; i <= 0x0554; i += 4) - nvkm_wo32(image, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0558; i <= 0x0564; i += 4) - nvkm_wo32(image, i, 0x000105b8); + nvkm_wo32(chan->inst, i, 0x000105b8); for (i = 0x0568; i <= 0x0574; i += 4) - nvkm_wo32(image, i, 0x00080008); + nvkm_wo32(chan->inst, i, 0x00080008); for (i = 0x0598; i <= 0x05d4; i += 4) - nvkm_wo32(image, i, 0x07ff0000); - nvkm_wo32(image, 0x05e0, 0x4b7fffff); - nvkm_wo32(image, 0x0620, 0x00000080); - nvkm_wo32(image, 0x0624, 0x30201000); - nvkm_wo32(image, 0x0628, 0x70605040); - nvkm_wo32(image, 0x062c, 0xb0a09080); - nvkm_wo32(image, 0x0630, 0xf0e0d0c0); - nvkm_wo32(image, 0x0664, 0x00000001); - nvkm_wo32(image, 0x066c, 0x00004000); - nvkm_wo32(image, 0x0678, 0x00000001); - nvkm_wo32(image, 0x0680, 0x00040000); - nvkm_wo32(image, 0x0684, 0x00010000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x05e0, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x0620, 0x00000080); + nvkm_wo32(chan->inst, 0x0624, 0x30201000); + nvkm_wo32(chan->inst, 0x0628, 0x70605040); + nvkm_wo32(chan->inst, 0x062c, 0xb0a09080); + nvkm_wo32(chan->inst, 0x0630, 0xf0e0d0c0); + nvkm_wo32(chan->inst, 0x0664, 0x00000001); + nvkm_wo32(chan->inst, 0x066c, 0x00004000); + nvkm_wo32(chan->inst, 0x0678, 0x00000001); + nvkm_wo32(chan->inst, 0x0680, 0x00040000); + nvkm_wo32(chan->inst, 0x0684, 0x00010000); for (i = 0x1b04; i <= 0x2374; i += 16) { - nvkm_wo32(image, (i + 0), 0x10700ff9); - nvkm_wo32(image, (i + 4), 0x0436086c); - nvkm_wo32(image, (i + 8), 0x000c001b); + nvkm_wo32(chan->inst, (i + 0), 0x10700ff9); + nvkm_wo32(chan->inst, (i + 4), 0x0436086c); + nvkm_wo32(chan->inst, (i + 8), 0x000c001b); } - nvkm_wo32(image, 0x2704, 0x3f800000); - nvkm_wo32(image, 0x2718, 0x3f800000); - nvkm_wo32(image, 0x2744, 0x40000000); - nvkm_wo32(image, 0x2748, 0x3f800000); - nvkm_wo32(image, 0x274c, 0x3f000000); - nvkm_wo32(image, 0x2754, 0x40000000); - nvkm_wo32(image, 0x2758, 0x3f800000); - nvkm_wo32(image, 0x2760, 0xbf800000); - nvkm_wo32(image, 0x2768, 0xbf800000); - nvkm_wo32(image, 0x308c, 0x000fe000); - nvkm_wo32(image, 0x3108, 0x000003f8); - nvkm_wo32(image, 0x3468, 0x002fe000); + nvkm_wo32(chan->inst, 0x2704, 0x3f800000); + nvkm_wo32(chan->inst, 0x2718, 0x3f800000); + nvkm_wo32(chan->inst, 0x2744, 0x40000000); + nvkm_wo32(chan->inst, 0x2748, 0x3f800000); + nvkm_wo32(chan->inst, 0x274c, 0x3f000000); + nvkm_wo32(chan->inst, 0x2754, 0x40000000); + nvkm_wo32(chan->inst, 0x2758, 0x3f800000); + nvkm_wo32(chan->inst, 0x2760, 0xbf800000); + nvkm_wo32(chan->inst, 0x2768, 0xbf800000); + nvkm_wo32(chan->inst, 0x308c, 0x000fe000); + nvkm_wo32(chan->inst, 0x3108, 0x000003f8); + nvkm_wo32(chan->inst, 0x3468, 0x002fe000); for (i = 0x3484; i <= 0x34a0; i += 4) - nvkm_wo32(image, i, 0x001c527c); - nvkm_done(image); + nvkm_wo32(chan->inst, i, 0x001c527c); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv25_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x25), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv25_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct nvkm_gr_func +nv25_gr = { + .chan_new = nv25_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */ + {} + } +}; + static int nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -139,6 +135,8 @@ nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv25_gr; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, &gr->ctxtab); if (ret) @@ -146,8 +144,6 @@ nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->cclass = &nv25_gr_cclass; - nv_engine(gr)->sclass = nv25_gr_sclass; nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index c5d8cd6d66c0a..2fabdc5866517 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -8,90 +8,110 @@ * PGRAPH context ******************************************************************************/ +static const struct nvkm_object_func +nv2a_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, +}; + static int -nv2a_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv2a_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; - struct nvkm_gpuobj *image; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x36b0, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv2a_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x36b0, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0000, 0x00000001 | (chan->chid << 24)); - nvkm_wo32(image, 0x033c, 0xffff0000); - nvkm_wo32(image, 0x03a0, 0x0fff0000); - nvkm_wo32(image, 0x03a4, 0x0fff0000); - nvkm_wo32(image, 0x047c, 0x00000101); - nvkm_wo32(image, 0x0490, 0x00000111); - nvkm_wo32(image, 0x04a8, 0x44400000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0000, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x033c, 0xffff0000); + nvkm_wo32(chan->inst, 0x03a0, 0x0fff0000); + nvkm_wo32(chan->inst, 0x03a4, 0x0fff0000); + nvkm_wo32(chan->inst, 0x047c, 0x00000101); + nvkm_wo32(chan->inst, 0x0490, 0x00000111); + nvkm_wo32(chan->inst, 0x04a8, 0x44400000); for (i = 0x04d4; i <= 0x04e0; i += 4) - nvkm_wo32(image, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x04f4; i <= 0x0500; i += 4) - nvkm_wo32(image, i, 0x00080000); + nvkm_wo32(chan->inst, i, 0x00080000); for (i = 0x050c; i <= 0x0518; i += 4) - nvkm_wo32(image, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x051c; i <= 0x0528; i += 4) - nvkm_wo32(image, i, 0x000105b8); + nvkm_wo32(chan->inst, i, 0x000105b8); for (i = 0x052c; i <= 0x0538; i += 4) - nvkm_wo32(image, i, 0x00080008); + nvkm_wo32(chan->inst, i, 0x00080008); for (i = 0x055c; i <= 0x0598; i += 4) - nvkm_wo32(image, i, 0x07ff0000); - nvkm_wo32(image, 0x05a4, 0x4b7fffff); - nvkm_wo32(image, 0x05fc, 0x00000001); - nvkm_wo32(image, 0x0604, 0x00004000); - nvkm_wo32(image, 0x0610, 0x00000001); - nvkm_wo32(image, 0x0618, 0x00040000); - nvkm_wo32(image, 0x061c, 0x00010000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x05a4, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x05fc, 0x00000001); + nvkm_wo32(chan->inst, 0x0604, 0x00004000); + nvkm_wo32(chan->inst, 0x0610, 0x00000001); + nvkm_wo32(chan->inst, 0x0618, 0x00040000); + nvkm_wo32(chan->inst, 0x061c, 0x00010000); for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */ - nvkm_wo32(image, (i + 0), 0x10700ff9); - nvkm_wo32(image, (i + 4), 0x0436086c); - nvkm_wo32(image, (i + 8), 0x000c001b); + nvkm_wo32(chan->inst, (i + 0), 0x10700ff9); + nvkm_wo32(chan->inst, (i + 4), 0x0436086c); + nvkm_wo32(chan->inst, (i + 8), 0x000c001b); } - nvkm_wo32(image, 0x269c, 0x3f800000); - nvkm_wo32(image, 0x26b0, 0x3f800000); - nvkm_wo32(image, 0x26dc, 0x40000000); - nvkm_wo32(image, 0x26e0, 0x3f800000); - nvkm_wo32(image, 0x26e4, 0x3f000000); - nvkm_wo32(image, 0x26ec, 0x40000000); - nvkm_wo32(image, 0x26f0, 0x3f800000); - nvkm_wo32(image, 0x26f8, 0xbf800000); - nvkm_wo32(image, 0x2700, 0xbf800000); - nvkm_wo32(image, 0x3024, 0x000fe000); - nvkm_wo32(image, 0x30a0, 0x000003f8); - nvkm_wo32(image, 0x33fc, 0x002fe000); + nvkm_wo32(chan->inst, 0x269c, 0x3f800000); + nvkm_wo32(chan->inst, 0x26b0, 0x3f800000); + nvkm_wo32(chan->inst, 0x26dc, 0x40000000); + nvkm_wo32(chan->inst, 0x26e0, 0x3f800000); + nvkm_wo32(chan->inst, 0x26e4, 0x3f000000); + nvkm_wo32(chan->inst, 0x26ec, 0x40000000); + nvkm_wo32(chan->inst, 0x26f0, 0x3f800000); + nvkm_wo32(chan->inst, 0x26f8, 0xbf800000); + nvkm_wo32(chan->inst, 0x2700, 0xbf800000); + nvkm_wo32(chan->inst, 0x3024, 0x000fe000); + nvkm_wo32(chan->inst, 0x30a0, 0x000003f8); + nvkm_wo32(chan->inst, 0x33fc, 0x002fe000); for (i = 0x341c; i <= 0x3438; i += 4) - nvkm_wo32(image, i, 0x001c527c); - nvkm_done(image); + nvkm_wo32(chan->inst, i, 0x001c527c); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv2a_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x2a), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv2a_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct nvkm_gr_func +nv2a_gr = { + .chan_new = nv2a_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0597, &nv04_gr_object }, /* kelvin */ + {} + } +}; + static int nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -106,6 +126,8 @@ nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv2a_gr; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, &gr->ctxtab); if (ret) @@ -113,8 +135,6 @@ nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->cclass = &nv2a_gr_cclass; - nv_engine(gr)->sclass = nv25_gr_sclass; nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 733de46a30dc9..8f5bfe3aa487d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -6,127 +6,123 @@ #include /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv30_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */ - { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */ - { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */ - { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */ - { 0x0397, &nv04_gr_ofuncs, NULL }, /* rankine */ - {}, +static const struct nvkm_object_func +nv30_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv30_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; - struct nvkm_gpuobj *image; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x5f48, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv30_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x5f48, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); - nvkm_wo32(image, 0x0410, 0x00000101); - nvkm_wo32(image, 0x0424, 0x00000111); - nvkm_wo32(image, 0x0428, 0x00000060); - nvkm_wo32(image, 0x0444, 0x00000080); - nvkm_wo32(image, 0x0448, 0xffff0000); - nvkm_wo32(image, 0x044c, 0x00000001); - nvkm_wo32(image, 0x0460, 0x44400000); - nvkm_wo32(image, 0x048c, 0xffff0000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x0410, 0x00000101); + nvkm_wo32(chan->inst, 0x0424, 0x00000111); + nvkm_wo32(chan->inst, 0x0428, 0x00000060); + nvkm_wo32(chan->inst, 0x0444, 0x00000080); + nvkm_wo32(chan->inst, 0x0448, 0xffff0000); + nvkm_wo32(chan->inst, 0x044c, 0x00000001); + nvkm_wo32(chan->inst, 0x0460, 0x44400000); + nvkm_wo32(chan->inst, 0x048c, 0xffff0000); for (i = 0x04e0; i < 0x04e8; i += 4) - nvkm_wo32(image, i, 0x0fff0000); - nvkm_wo32(image, 0x04ec, 0x00011100); + nvkm_wo32(chan->inst, i, 0x0fff0000); + nvkm_wo32(chan->inst, 0x04ec, 0x00011100); for (i = 0x0508; i < 0x0548; i += 4) - nvkm_wo32(image, i, 0x07ff0000); - nvkm_wo32(image, 0x0550, 0x4b7fffff); - nvkm_wo32(image, 0x058c, 0x00000080); - nvkm_wo32(image, 0x0590, 0x30201000); - nvkm_wo32(image, 0x0594, 0x70605040); - nvkm_wo32(image, 0x0598, 0xb8a89888); - nvkm_wo32(image, 0x059c, 0xf8e8d8c8); - nvkm_wo32(image, 0x05b0, 0xb0000000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x0550, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x058c, 0x00000080); + nvkm_wo32(chan->inst, 0x0590, 0x30201000); + nvkm_wo32(chan->inst, 0x0594, 0x70605040); + nvkm_wo32(chan->inst, 0x0598, 0xb8a89888); + nvkm_wo32(chan->inst, 0x059c, 0xf8e8d8c8); + nvkm_wo32(chan->inst, 0x05b0, 0xb0000000); for (i = 0x0600; i < 0x0640; i += 4) - nvkm_wo32(image, i, 0x00010588); + nvkm_wo32(chan->inst, i, 0x00010588); for (i = 0x0640; i < 0x0680; i += 4) - nvkm_wo32(image, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x06c0; i < 0x0700; i += 4) - nvkm_wo32(image, i, 0x0008aae4); + nvkm_wo32(chan->inst, i, 0x0008aae4); for (i = 0x0700; i < 0x0740; i += 4) - nvkm_wo32(image, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0740; i < 0x0780; i += 4) - nvkm_wo32(image, i, 0x00080008); - nvkm_wo32(image, 0x085c, 0x00040000); - nvkm_wo32(image, 0x0860, 0x00010000); + nvkm_wo32(chan->inst, i, 0x00080008); + nvkm_wo32(chan->inst, 0x085c, 0x00040000); + nvkm_wo32(chan->inst, 0x0860, 0x00010000); for (i = 0x0864; i < 0x0874; i += 4) - nvkm_wo32(image, i, 0x00040004); + nvkm_wo32(chan->inst, i, 0x00040004); for (i = 0x1f18; i <= 0x3088 ; i += 16) { - nvkm_wo32(image, i + 0, 0x10700ff9); - nvkm_wo32(image, i + 1, 0x0436086c); - nvkm_wo32(image, i + 2, 0x000c001b); + nvkm_wo32(chan->inst, i + 0, 0x10700ff9); + nvkm_wo32(chan->inst, i + 1, 0x0436086c); + nvkm_wo32(chan->inst, i + 2, 0x000c001b); } for (i = 0x30b8; i < 0x30c8; i += 4) - nvkm_wo32(image, i, 0x0000ffff); - nvkm_wo32(image, 0x344c, 0x3f800000); - nvkm_wo32(image, 0x3808, 0x3f800000); - nvkm_wo32(image, 0x381c, 0x3f800000); - nvkm_wo32(image, 0x3848, 0x40000000); - nvkm_wo32(image, 0x384c, 0x3f800000); - nvkm_wo32(image, 0x3850, 0x3f000000); - nvkm_wo32(image, 0x3858, 0x40000000); - nvkm_wo32(image, 0x385c, 0x3f800000); - nvkm_wo32(image, 0x3864, 0xbf800000); - nvkm_wo32(image, 0x386c, 0xbf800000); - nvkm_done(image); + nvkm_wo32(chan->inst, i, 0x0000ffff); + nvkm_wo32(chan->inst, 0x344c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3808, 0x3f800000); + nvkm_wo32(chan->inst, 0x381c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3848, 0x40000000); + nvkm_wo32(chan->inst, 0x384c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3850, 0x3f000000); + nvkm_wo32(chan->inst, 0x3858, 0x40000000); + nvkm_wo32(chan->inst, 0x385c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3864, 0xbf800000); + nvkm_wo32(chan->inst, 0x386c, 0xbf800000); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv30_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x30), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv30_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct nvkm_gr_func +nv30_gr = { + .chan_new = nv30_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */ + {} + } +}; + static int nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -141,6 +137,8 @@ nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv30_gr; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, &gr->ctxtab); if (ret) @@ -148,8 +146,6 @@ nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->cclass = &nv30_gr_cclass; - nv_engine(gr)->sclass = nv30_gr_sclass; nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 368c0cff35fb1..3781a5b311fbc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -5,127 +5,123 @@ #include /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv34_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */ - { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */ - { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */ - { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */ - { 0x0697, &nv04_gr_ofuncs, NULL }, /* rankine */ - {}, +static const struct nvkm_object_func +nv34_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv34_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; - struct nvkm_gpuobj *image; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x46dc, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv34_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x46dc, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); - nvkm_wo32(image, 0x040c, 0x01000101); - nvkm_wo32(image, 0x0420, 0x00000111); - nvkm_wo32(image, 0x0424, 0x00000060); - nvkm_wo32(image, 0x0440, 0x00000080); - nvkm_wo32(image, 0x0444, 0xffff0000); - nvkm_wo32(image, 0x0448, 0x00000001); - nvkm_wo32(image, 0x045c, 0x44400000); - nvkm_wo32(image, 0x0480, 0xffff0000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x040c, 0x01000101); + nvkm_wo32(chan->inst, 0x0420, 0x00000111); + nvkm_wo32(chan->inst, 0x0424, 0x00000060); + nvkm_wo32(chan->inst, 0x0440, 0x00000080); + nvkm_wo32(chan->inst, 0x0444, 0xffff0000); + nvkm_wo32(chan->inst, 0x0448, 0x00000001); + nvkm_wo32(chan->inst, 0x045c, 0x44400000); + nvkm_wo32(chan->inst, 0x0480, 0xffff0000); for (i = 0x04d4; i < 0x04dc; i += 4) - nvkm_wo32(image, i, 0x0fff0000); - nvkm_wo32(image, 0x04e0, 0x00011100); + nvkm_wo32(chan->inst, i, 0x0fff0000); + nvkm_wo32(chan->inst, 0x04e0, 0x00011100); for (i = 0x04fc; i < 0x053c; i += 4) - nvkm_wo32(image, i, 0x07ff0000); - nvkm_wo32(image, 0x0544, 0x4b7fffff); - nvkm_wo32(image, 0x057c, 0x00000080); - nvkm_wo32(image, 0x0580, 0x30201000); - nvkm_wo32(image, 0x0584, 0x70605040); - nvkm_wo32(image, 0x0588, 0xb8a89888); - nvkm_wo32(image, 0x058c, 0xf8e8d8c8); - nvkm_wo32(image, 0x05a0, 0xb0000000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x0544, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x057c, 0x00000080); + nvkm_wo32(chan->inst, 0x0580, 0x30201000); + nvkm_wo32(chan->inst, 0x0584, 0x70605040); + nvkm_wo32(chan->inst, 0x0588, 0xb8a89888); + nvkm_wo32(chan->inst, 0x058c, 0xf8e8d8c8); + nvkm_wo32(chan->inst, 0x05a0, 0xb0000000); for (i = 0x05f0; i < 0x0630; i += 4) - nvkm_wo32(image, i, 0x00010588); + nvkm_wo32(chan->inst, i, 0x00010588); for (i = 0x0630; i < 0x0670; i += 4) - nvkm_wo32(image, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x06b0; i < 0x06f0; i += 4) - nvkm_wo32(image, i, 0x0008aae4); + nvkm_wo32(chan->inst, i, 0x0008aae4); for (i = 0x06f0; i < 0x0730; i += 4) - nvkm_wo32(image, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0730; i < 0x0770; i += 4) - nvkm_wo32(image, i, 0x00080008); - nvkm_wo32(image, 0x0850, 0x00040000); - nvkm_wo32(image, 0x0854, 0x00010000); + nvkm_wo32(chan->inst, i, 0x00080008); + nvkm_wo32(chan->inst, 0x0850, 0x00040000); + nvkm_wo32(chan->inst, 0x0854, 0x00010000); for (i = 0x0858; i < 0x0868; i += 4) - nvkm_wo32(image, i, 0x00040004); + nvkm_wo32(chan->inst, i, 0x00040004); for (i = 0x15ac; i <= 0x271c ; i += 16) { - nvkm_wo32(image, i + 0, 0x10700ff9); - nvkm_wo32(image, i + 1, 0x0436086c); - nvkm_wo32(image, i + 2, 0x000c001b); + nvkm_wo32(chan->inst, i + 0, 0x10700ff9); + nvkm_wo32(chan->inst, i + 1, 0x0436086c); + nvkm_wo32(chan->inst, i + 2, 0x000c001b); } for (i = 0x274c; i < 0x275c; i += 4) - nvkm_wo32(image, i, 0x0000ffff); - nvkm_wo32(image, 0x2ae0, 0x3f800000); - nvkm_wo32(image, 0x2e9c, 0x3f800000); - nvkm_wo32(image, 0x2eb0, 0x3f800000); - nvkm_wo32(image, 0x2edc, 0x40000000); - nvkm_wo32(image, 0x2ee0, 0x3f800000); - nvkm_wo32(image, 0x2ee4, 0x3f000000); - nvkm_wo32(image, 0x2eec, 0x40000000); - nvkm_wo32(image, 0x2ef0, 0x3f800000); - nvkm_wo32(image, 0x2ef8, 0xbf800000); - nvkm_wo32(image, 0x2f00, 0xbf800000); - nvkm_done(image); + nvkm_wo32(chan->inst, i, 0x0000ffff); + nvkm_wo32(chan->inst, 0x2ae0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2e9c, 0x3f800000); + nvkm_wo32(chan->inst, 0x2eb0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2edc, 0x40000000); + nvkm_wo32(chan->inst, 0x2ee0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2ee4, 0x3f000000); + nvkm_wo32(chan->inst, 0x2eec, 0x40000000); + nvkm_wo32(chan->inst, 0x2ef0, 0x3f800000); + nvkm_wo32(chan->inst, 0x2ef8, 0xbf800000); + nvkm_wo32(chan->inst, 0x2f00, 0xbf800000); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv34_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x34), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv34_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct nvkm_gr_func +nv34_gr = { + .chan_new = nv34_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0697, &nv04_gr_object }, /* rankine */ + {} + } +}; + static int nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -140,6 +136,8 @@ nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv34_gr; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, &gr->ctxtab); if (ret) @@ -147,8 +145,6 @@ nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->cclass = &nv34_gr_cclass; - nv_engine(gr)->sclass = nv34_gr_sclass; nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 676234d28e50a..285c4eff2e5bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -5,127 +5,123 @@ #include /******************************************************************************* - * Graphics object classes + * PGRAPH context ******************************************************************************/ -static struct nvkm_oclass -nv35_gr_sclass[] = { - { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */ - { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */ - { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */ - { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */ - { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */ - { 0x0497, &nv04_gr_ofuncs, NULL }, /* rankine */ - {}, +static const struct nvkm_object_func +nv35_gr_chan = { + .dtor = nv20_gr_chan_dtor, + .init = nv20_gr_chan_init, + .fini = nv20_gr_chan_fini, }; -/******************************************************************************* - * PGRAPH context - ******************************************************************************/ - static int -nv35_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv35_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { + struct nv20_gr *gr = nv20_gr(base); struct nv20_gr_chan *chan; - struct nvkm_gpuobj *image; int ret, i; - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x577c, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv35_gr_chan, oclass, &chan->object); + chan->gr = gr; + chan->chid = fifoch->chid; + *pobject = &chan->object; + + ret = nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 0x577c, 16, true, + &chan->inst); if (ret) return ret; - chan->chid = nvkm_fifo_chan(parent)->chid; - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0028, 0x00000001 | (chan->chid << 24)); - nvkm_wo32(image, 0x040c, 0x00000101); - nvkm_wo32(image, 0x0420, 0x00000111); - nvkm_wo32(image, 0x0424, 0x00000060); - nvkm_wo32(image, 0x0440, 0x00000080); - nvkm_wo32(image, 0x0444, 0xffff0000); - nvkm_wo32(image, 0x0448, 0x00000001); - nvkm_wo32(image, 0x045c, 0x44400000); - nvkm_wo32(image, 0x0488, 0xffff0000); + nvkm_kmap(chan->inst); + nvkm_wo32(chan->inst, 0x0028, 0x00000001 | (chan->chid << 24)); + nvkm_wo32(chan->inst, 0x040c, 0x00000101); + nvkm_wo32(chan->inst, 0x0420, 0x00000111); + nvkm_wo32(chan->inst, 0x0424, 0x00000060); + nvkm_wo32(chan->inst, 0x0440, 0x00000080); + nvkm_wo32(chan->inst, 0x0444, 0xffff0000); + nvkm_wo32(chan->inst, 0x0448, 0x00000001); + nvkm_wo32(chan->inst, 0x045c, 0x44400000); + nvkm_wo32(chan->inst, 0x0488, 0xffff0000); for (i = 0x04dc; i < 0x04e4; i += 4) - nvkm_wo32(image, i, 0x0fff0000); - nvkm_wo32(image, 0x04e8, 0x00011100); + nvkm_wo32(chan->inst, i, 0x0fff0000); + nvkm_wo32(chan->inst, 0x04e8, 0x00011100); for (i = 0x0504; i < 0x0544; i += 4) - nvkm_wo32(image, i, 0x07ff0000); - nvkm_wo32(image, 0x054c, 0x4b7fffff); - nvkm_wo32(image, 0x0588, 0x00000080); - nvkm_wo32(image, 0x058c, 0x30201000); - nvkm_wo32(image, 0x0590, 0x70605040); - nvkm_wo32(image, 0x0594, 0xb8a89888); - nvkm_wo32(image, 0x0598, 0xf8e8d8c8); - nvkm_wo32(image, 0x05ac, 0xb0000000); + nvkm_wo32(chan->inst, i, 0x07ff0000); + nvkm_wo32(chan->inst, 0x054c, 0x4b7fffff); + nvkm_wo32(chan->inst, 0x0588, 0x00000080); + nvkm_wo32(chan->inst, 0x058c, 0x30201000); + nvkm_wo32(chan->inst, 0x0590, 0x70605040); + nvkm_wo32(chan->inst, 0x0594, 0xb8a89888); + nvkm_wo32(chan->inst, 0x0598, 0xf8e8d8c8); + nvkm_wo32(chan->inst, 0x05ac, 0xb0000000); for (i = 0x0604; i < 0x0644; i += 4) - nvkm_wo32(image, i, 0x00010588); + nvkm_wo32(chan->inst, i, 0x00010588); for (i = 0x0644; i < 0x0684; i += 4) - nvkm_wo32(image, i, 0x00030303); + nvkm_wo32(chan->inst, i, 0x00030303); for (i = 0x06c4; i < 0x0704; i += 4) - nvkm_wo32(image, i, 0x0008aae4); + nvkm_wo32(chan->inst, i, 0x0008aae4); for (i = 0x0704; i < 0x0744; i += 4) - nvkm_wo32(image, i, 0x01012000); + nvkm_wo32(chan->inst, i, 0x01012000); for (i = 0x0744; i < 0x0784; i += 4) - nvkm_wo32(image, i, 0x00080008); - nvkm_wo32(image, 0x0860, 0x00040000); - nvkm_wo32(image, 0x0864, 0x00010000); + nvkm_wo32(chan->inst, i, 0x00080008); + nvkm_wo32(chan->inst, 0x0860, 0x00040000); + nvkm_wo32(chan->inst, 0x0864, 0x00010000); for (i = 0x0868; i < 0x0878; i += 4) - nvkm_wo32(image, i, 0x00040004); + nvkm_wo32(chan->inst, i, 0x00040004); for (i = 0x1f1c; i <= 0x308c ; i += 16) { - nvkm_wo32(image, i + 0, 0x10700ff9); - nvkm_wo32(image, i + 4, 0x0436086c); - nvkm_wo32(image, i + 8, 0x000c001b); + nvkm_wo32(chan->inst, i + 0, 0x10700ff9); + nvkm_wo32(chan->inst, i + 4, 0x0436086c); + nvkm_wo32(chan->inst, i + 8, 0x000c001b); } for (i = 0x30bc; i < 0x30cc; i += 4) - nvkm_wo32(image, i, 0x0000ffff); - nvkm_wo32(image, 0x3450, 0x3f800000); - nvkm_wo32(image, 0x380c, 0x3f800000); - nvkm_wo32(image, 0x3820, 0x3f800000); - nvkm_wo32(image, 0x384c, 0x40000000); - nvkm_wo32(image, 0x3850, 0x3f800000); - nvkm_wo32(image, 0x3854, 0x3f000000); - nvkm_wo32(image, 0x385c, 0x40000000); - nvkm_wo32(image, 0x3860, 0x3f800000); - nvkm_wo32(image, 0x3868, 0xbf800000); - nvkm_wo32(image, 0x3870, 0xbf800000); - nvkm_done(image); + nvkm_wo32(chan->inst, i, 0x0000ffff); + nvkm_wo32(chan->inst, 0x3450, 0x3f800000); + nvkm_wo32(chan->inst, 0x380c, 0x3f800000); + nvkm_wo32(chan->inst, 0x3820, 0x3f800000); + nvkm_wo32(chan->inst, 0x384c, 0x40000000); + nvkm_wo32(chan->inst, 0x3850, 0x3f800000); + nvkm_wo32(chan->inst, 0x3854, 0x3f000000); + nvkm_wo32(chan->inst, 0x385c, 0x40000000); + nvkm_wo32(chan->inst, 0x3860, 0x3f800000); + nvkm_wo32(chan->inst, 0x3868, 0xbf800000); + nvkm_wo32(chan->inst, 0x3870, 0xbf800000); + nvkm_done(chan->inst); return 0; } -static struct nvkm_oclass -nv35_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x35), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv35_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = nv20_gr_context_init, - .fini = nv20_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ +static const struct nvkm_gr_func +nv35_gr = { + .chan_new = nv35_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0497, &nv04_gr_object }, /* rankine */ + {} + } +}; + static int nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -140,6 +136,8 @@ nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + gr->base.func = &nv35_gr; + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, &gr->ctxtab); if (ret) @@ -147,8 +145,6 @@ nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->cclass = &nv35_gr_cclass; - nv_engine(gr)->sclass = nv35_gr_sclass; nv_engine(gr)->tile_prog = nv20_gr_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index e716ae12b55ce..0103337f55d29 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -29,19 +29,6 @@ #include #include -struct nv40_gr { - struct nvkm_gr base; - u32 size; - struct list_head chan; -}; - -struct nv40_gr_chan { - struct nvkm_gr_chan base; - struct nvkm_fifo_chan *fifo; - u32 inst; - struct list_head head; -}; - static u64 nv40_gr_units(struct nvkm_gr *gr) { @@ -53,133 +40,61 @@ nv40_gr_units(struct nvkm_gr *gr) ******************************************************************************/ static int -nv40_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 20, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nvkm_kmap(obj); - nvkm_wo32(obj, 0x00, nv_mclass(obj)); - nvkm_wo32(obj, 0x04, 0x00000000); - nvkm_wo32(obj, 0x08, 0x00000000); + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 20, align, + false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN - nvkm_mo32(obj, 0x08, 0x01000000, 0x01000000); + nvkm_mo32(*pgpuobj, 0x08, 0x01000000, 0x01000000); #endif - nvkm_wo32(obj, 0x0c, 0x00000000); - nvkm_wo32(obj, 0x10, 0x00000000); - nvkm_done(obj); - return 0; + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_wo32(*pgpuobj, 0x10, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_ofuncs -nv40_gr_ofuncs = { - .ctor = nv40_gr_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv40_gr_sclass[] = { - { 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv40_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */ - { 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */ - { 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */ - { 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */ - { 0x4097, &nv40_gr_ofuncs, NULL }, /* curie */ - {}, -}; - -static struct nvkm_oclass -nv44_gr_sclass[] = { - { 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */ - { 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */ - { 0x0030, &nv40_gr_ofuncs, NULL }, /* null */ - { 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */ - { 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */ - { 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */ - { 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */ - { 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */ - { 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */ - { 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */ - { 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */ - { 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */ - { 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */ - { 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */ - { 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */ - { 0x4497, &nv40_gr_ofuncs, NULL }, /* curie */ - {}, +static const struct nvkm_object_func +nv40_gr_object = { + .bind = nv40_gr_object_bind, }; /******************************************************************************* * PGRAPH context ******************************************************************************/ -static void -nv40_gr_context_dtor(struct nvkm_object *object) -{ - struct nv40_gr_chan *chan = (void *)object; - unsigned long flags; - spin_lock_irqsave(&object->engine->lock, flags); - list_del(&chan->head); - spin_unlock_irqrestore(&object->engine->lock, flags); -} - static int -nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv40_gr *gr = (void *)engine; - struct nv40_gr_chan *chan; - unsigned long flags; - int ret; - - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, gr->size, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - nv40_grctx_fill(nv_device(gr), nv_gpuobj(chan)); - nvkm_wo32(&chan->base.base.gpuobj, 0x00000, nv_gpuobj(chan)->addr >> 4); - - spin_lock_irqsave(&gr->base.engine.lock, flags); - chan->fifo = (void *)parent; - chan->inst = chan->base.base.gpuobj.addr; - list_add(&chan->head, &gr->chan); - spin_unlock_irqrestore(&gr->base.engine.lock, flags); - return 0; + struct nv40_gr_chan *chan = nv40_gr_chan(object); + struct nv40_gr *gr = chan->gr; + int ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, + align, true, parent, pgpuobj); + if (ret == 0) { + chan->inst = (*pgpuobj)->addr; + nvkm_kmap(*pgpuobj); + nv40_grctx_fill(gr->base.engine.subdev.device, *pgpuobj); + nvkm_wo32(*pgpuobj, 0x00000, chan->inst >> 4); + nvkm_done(*pgpuobj); + } + return ret; } static int -nv40_gr_context_fini(struct nvkm_object *object, bool suspend) +nv40_gr_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv40_gr *gr = (void *)object->engine; - struct nv40_gr_chan *chan = (void *)object; + struct nv40_gr_chan *chan = nv40_gr_chan(object); + struct nv40_gr *gr = chan->gr; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4; + u32 inst = 0x01000000 | chan->inst >> 4; int ret = 0; nvkm_mask(device, 0x400720, 0x00000001, 0x00000000); @@ -210,19 +125,44 @@ nv40_gr_context_fini(struct nvkm_object *object, bool suspend) return ret; } -static struct nvkm_oclass -nv40_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_gr_context_ctor, - .dtor = nv40_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = nv40_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, +static void * +nv40_gr_chan_dtor(struct nvkm_object *object) +{ + struct nv40_gr_chan *chan = nv40_gr_chan(object); + unsigned long flags; + spin_lock_irqsave(&chan->gr->base.engine.lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&chan->gr->base.engine.lock, flags); + return chan; +} + +static const struct nvkm_object_func +nv40_gr_chan = { + .dtor = nv40_gr_chan_dtor, + .fini = nv40_gr_chan_fini, + .bind = nv40_gr_chan_bind, }; +static int +nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) +{ + struct nv40_gr *gr = nv40_gr(base); + struct nv40_gr_chan *chan; + unsigned long flags; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv40_gr_chan, oclass, &chan->object); + chan->gr = gr; + *pobject = &chan->object; + + spin_lock_irqsave(&chan->gr->base.engine.lock, flags); + list_add(&chan->head, &gr->chan); + spin_unlock_irqrestore(&chan->gr->base.engine.lock, flags); + return 0; +} + /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ @@ -237,7 +177,7 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) unsigned long flags; fifo->pause(fifo, &flags); - nv04_gr_idle(gr); + nv04_gr_idle(&gr->base); switch (nv_device(gr)->chipset) { case 0x40: @@ -360,6 +300,54 @@ nv40_gr_intr(struct nvkm_subdev *subdev) spin_unlock_irqrestore(&gr->base.engine.lock, flags); } +static const struct nvkm_gr_func +nv40_gr = { + .chan_new = nv40_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv40_gr_object }, /* null */ + { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ + { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ + { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ + { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ + { -1, -1, 0x4097, &nv40_gr_object }, /* curie */ + {} + } +}; + +static const struct nvkm_gr_func +nv44_gr = { + .chan_new = nv40_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv40_gr_object }, /* null */ + { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ + { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ + { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ + { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ + { -1, -1, 0x4497, &nv40_gr_object }, /* curie */ + {} + } +}; + static int nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -377,11 +365,10 @@ nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv40_gr_intr; - nv_engine(gr)->cclass = &nv40_gr_cclass; if (nv44_gr_class(gr)) - nv_engine(gr)->sclass = nv44_gr_sclass; + gr->base.func = &nv44_gr; else - nv_engine(gr)->sclass = nv40_gr_sclass; + gr->base.func = &nv40_gr; nv_engine(gr)->tile_prog = nv40_gr_tile_prog; gr->base.units = nv40_gr_units; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h index 01d9f73a024cb..eefb36cbeeeac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h @@ -1,8 +1,23 @@ #ifndef __NV40_GR_H__ #define __NV40_GR_H__ -#include +#define nv40_gr(p) container_of((p), struct nv40_gr, base) +#include "priv.h" -struct nvkm_gpuobj; +struct nv40_gr { + struct nvkm_gr base; + u32 size; + struct list_head chan; +}; + +#define nv40_gr_chan(p) container_of((p), struct nv40_gr_chan, object) + +struct nv40_gr_chan { + struct nvkm_object object; + struct nv40_gr *gr; + struct nvkm_fifo_chan *fifo; + u32 inst; + struct list_head head; +}; /* returns 1 if device is one of the nv4x using the 0x4497 object class, * helpful to determine a number of other hardware features diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 5f22dd3c788cc..403d2c9aff3b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -27,16 +27,6 @@ #include #include -struct nv50_gr { - struct nvkm_gr base; - spinlock_t lock; - u32 size; -}; - -struct nv50_gr_chan { - struct nvkm_gr_chan base; -}; - static u64 nv50_gr_units(struct nvkm_gr *gr) { @@ -48,126 +38,82 @@ nv50_gr_units(struct nvkm_gr *gr) ******************************************************************************/ static int -nv50_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nvkm_kmap(obj); - nvkm_wo32(obj, 0x00, nv_mclass(obj)); - nvkm_wo32(obj, 0x04, 0x00000000); - nvkm_wo32(obj, 0x08, 0x00000000); - nvkm_wo32(obj, 0x0c, 0x00000000); - nvkm_done(obj); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, + align, false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_ofuncs -nv50_gr_ofuncs = { - .ctor = nv50_gr_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv50_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x5097, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - {} +static const struct nvkm_object_func +nv50_gr_object = { + .bind = nv50_gr_object_bind, }; -static struct nvkm_oclass -g84_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x8297, &nv50_gr_ofuncs }, - {} -}; - -static struct nvkm_oclass -gt200_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x8397, &nv50_gr_ofuncs }, - {} -}; +static int +nv50_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass) +{ + struct nv50_gr *gr = nv50_gr(base); + int c = 0; -static struct nvkm_oclass -gt215_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x8597, &nv50_gr_ofuncs }, - { 0x85c0, &nv50_gr_ofuncs }, - {} -}; + while (gr->func->sclass[c].oclass) { + if (c++ == index) { + *sclass = gr->func->sclass[index]; + return index; + } + } -static struct nvkm_oclass -mcp89_gr_sclass[] = { - { 0x0030, &nv50_gr_ofuncs }, - { 0x502d, &nv50_gr_ofuncs }, - { 0x5039, &nv50_gr_ofuncs }, - { 0x50c0, &nv50_gr_ofuncs }, - { 0x85c0, &nv50_gr_ofuncs }, - { 0x8697, &nv50_gr_ofuncs }, - {} -}; + return c; +} /******************************************************************************* * PGRAPH context ******************************************************************************/ static int -nv50_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_gr_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv50_gr *gr = (void *)engine; - struct nv50_gr_chan *chan; - int ret; + struct nv50_gr *gr = nv50_gr_chan(object)->gr; + int ret = nvkm_gpuobj_new(gr->base.engine.subdev.device, gr->size, + align, true, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nv50_grctx_fill(gr->base.engine.subdev.device, *pgpuobj); + nvkm_done(*pgpuobj); + } + return ret; +} - ret = nvkm_gr_context_create(parent, engine, oclass, NULL, gr->size, - 0, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; +static const struct nvkm_object_func +nv50_gr_chan = { + .bind = nv50_gr_chan_bind, +}; + +static int +nv50_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) +{ + struct nv50_gr *gr = nv50_gr(base); + struct nv50_gr_chan *chan; - nv50_grctx_fill(nv_device(gr), nv_gpuobj(chan)); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv50_gr_chan, oclass, &chan->object); + chan->gr = gr; + *pobject = &chan->object; return 0; } -static struct nvkm_oclass -nv50_gr_cclass = { - .handle = NV_ENGCTX(GR, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_gr_context_ctor, - .dtor = _nvkm_gr_context_dtor, - .init = _nvkm_gr_context_init, - .fini = _nvkm_gr_context_fini, - .rd32 = _nvkm_gr_context_rd32, - .wr32 = _nvkm_gr_context_wr32, - }, -}; - /******************************************************************************* * PGRAPH engine/subdev functions ******************************************************************************/ @@ -889,6 +835,74 @@ nv50_gr_intr(struct nvkm_subdev *subdev) nvkm_fifo_chan_put(device->fifo, flags, &chan); } +static const struct nv50_gr_func +nv50_gr = { + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x5097, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + {} + } +}; + +static const struct nv50_gr_func +g84_gr = { + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8297, &nv50_gr_object }, + {} + } +}; + +static const struct nv50_gr_func +gt200_gr = { + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8397, &nv50_gr_object }, + {} + } +}; + +static const struct nv50_gr_func +gt215_gr = { + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8597, &nv50_gr_object }, + { -1, -1, 0x85c0, &nv50_gr_object }, + {} + } +}; + +static const struct nv50_gr_func +mcp89_gr = { + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x85c0, &nv50_gr_object }, + { -1, -1, 0x8697, &nv50_gr_object }, + {} + } +}; + +static const struct nvkm_gr_func +nv50_gr_ = { + .chan_new = nv50_gr_chan_new, + .object_get = nv50_gr_object_get, +}; + static int nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -904,13 +918,13 @@ nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00201000; nv_subdev(gr)->intr = nv50_gr_intr; - nv_engine(gr)->cclass = &nv50_gr_cclass; + gr->base.func = &nv50_gr_; gr->base.units = nv50_gr_units; switch (nv_device(gr)->chipset) { case 0x50: - nv_engine(gr)->sclass = nv50_gr_sclass; + gr->func = &nv50_gr; break; case 0x84: case 0x86: @@ -918,22 +932,21 @@ nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, case 0x94: case 0x96: case 0x98: - nv_engine(gr)->sclass = g84_gr_sclass; + gr->func = &g84_gr; break; case 0xa0: case 0xaa: case 0xac: - nv_engine(gr)->sclass = gt200_gr_sclass; + gr->func = >200_gr; break; case 0xa3: case 0xa5: case 0xa8: - nv_engine(gr)->sclass = gt215_gr_sclass; + gr->func = >215_gr; break; case 0xaf: - nv_engine(gr)->sclass = mcp89_gr_sclass; + gr->func = &mcp89_gr; break; - } /* unfortunate hw bug workaround... */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h index bcf786f6b7319..145ea5026a8e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h @@ -1,8 +1,26 @@ #ifndef __NV50_GR_H__ #define __NV50_GR_H__ -#include -struct nvkm_device; -struct nvkm_gpuobj; +#define nv50_gr(p) container_of((p), struct nv50_gr, base) +#include "priv.h" + +struct nv50_gr { + struct nvkm_gr base; + const struct nv50_gr_func *func; + spinlock_t lock; + u32 size; +}; + +struct nv50_gr_func { + void *(*dtor)(struct nv50_gr *); + struct nvkm_sclass sclass[]; +}; + +#define nv50_gr_chan(p) container_of((p), struct nv50_gr_chan, object) + +struct nv50_gr_chan { + struct nvkm_object object; + struct nv50_gr *gr; +}; int nv50_grctx_init(struct nvkm_device *, u32 *size); void nv50_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h new file mode 100644 index 0000000000000..f7fd617b6fe51 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h @@ -0,0 +1,15 @@ +#ifndef __NVKM_GR_PRIV_H__ +#define __NVKM_GR_PRIV_H__ +#define nvkm_gr(p) container_of((p), struct nvkm_gr, engine) +#include +struct nvkm_fifo_chan; + +struct nvkm_gr_func { + int (*chan_new)(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + int (*object_get)(struct nvkm_gr *, int, struct nvkm_sclass *); + struct nvkm_sclass sclass[]; +}; + +extern const struct nvkm_object_func nv04_gr_object; +#endif -- GitLab From 218f978d43296a9ac142a63361e25f517df3d318 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5525/7006] drm/nouveau/mpeg: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 3 + .../drm/nouveau/include/nvkm/engine/mpeg.h | 24 -- .../gpu/drm/nouveau/nvkm/engine/mpeg/g84.c | 46 +--- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 206 ++++++++---------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h | 19 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 27 +-- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 138 ++++++------ .../gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 110 +++------- .../gpu/drm/nouveau/nvkm/engine/mpeg/priv.h | 9 + 9 files changed, 249 insertions(+), 333 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 3edd4c1d56311..1b85ffe629aa7 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -45,6 +45,9 @@ #define GM107_DISP 0x00009470 #define GM204_DISP 0x00009570 +#define NV31_MPEG 0x00003174 +#define G82_MPEG 0x00008274 + #define NV74_VP2 0x00007476 #define NV50_DISP_CURSOR 0x0000507a diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h index db5c3d5a07520..029fd0c28d22f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h @@ -1,26 +1,5 @@ #ifndef __NVKM_MPEG_H__ #define __NVKM_MPEG_H__ -#include - -struct nvkm_mpeg_chan { - struct nvkm_engctx base; -}; - -#define nvkm_mpeg_context_create(p,e,c,g,s,a,f,d) \ - nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d)) -#define nvkm_mpeg_context_destroy(d) \ - nvkm_engctx_destroy(&(d)->base) -#define nvkm_mpeg_context_init(d) \ - nvkm_engctx_init(&(d)->base) -#define nvkm_mpeg_context_fini(d,s) \ - nvkm_engctx_fini(&(d)->base, (s)) - -#define _nvkm_mpeg_context_dtor _nvkm_engctx_dtor -#define _nvkm_mpeg_context_init _nvkm_engctx_init -#define _nvkm_mpeg_context_fini _nvkm_engctx_fini -#define _nvkm_mpeg_context_rd32 _nvkm_engctx_rd32 -#define _nvkm_mpeg_context_wr32 _nvkm_engctx_wr32 - #include struct nvkm_mpeg { @@ -45,9 +24,6 @@ extern struct nvkm_oclass nv40_mpeg_oclass; extern struct nvkm_oclass nv44_mpeg_oclass; extern struct nvkm_oclass nv50_mpeg_oclass; extern struct nvkm_oclass g84_mpeg_oclass; -extern struct nvkm_ofuncs nv31_mpeg_ofuncs; -extern struct nvkm_oclass nv31_mpeg_cclass; -extern struct nvkm_oclass nv31_mpeg_sclass[]; extern struct nvkm_oclass nv40_mpeg_sclass[]; void nv31_mpeg_intr(struct nvkm_subdev *); void nv31_mpeg_tile_prog(struct nvkm_engine *, int); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c index cdcca3ab4332b..c72fd75cd8cf6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c @@ -21,43 +21,19 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" -struct g84_mpeg_chan { - struct nvkm_mpeg_chan base; -}; - -/******************************************************************************* - * MPEG object classes - ******************************************************************************/ +#include -static struct nvkm_oclass -g84_mpeg_sclass[] = { - { 0x8274, &nv50_mpeg_ofuncs }, - {} +static const struct nvkm_engine_func +g84_mpeg = { + .cclass = &nv50_mpeg_cclass, + .sclass = { + { -1, -1, G82_MPEG, &nv31_mpeg_object }, + {} + } }; -/******************************************************************************* - * PMPEG context - ******************************************************************************/ - -static struct nvkm_oclass -g84_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mpeg_context_ctor, - .dtor = _nvkm_mpeg_context_dtor, - .init = _nvkm_mpeg_context_init, - .fini = _nvkm_mpeg_context_fini, - .rd32 = _nvkm_mpeg_context_rd32, - .wr32 = _nvkm_mpeg_context_wr32, - }, -}; - -/******************************************************************************* - * PMPEG engine/subdev functions - ******************************************************************************/ - static int g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -71,10 +47,10 @@ g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + mpeg->engine.func = &g84_mpeg; + nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv50_mpeg_intr; - nv_engine(mpeg)->cclass = &g84_mpeg_cclass; - nv_engine(mpeg)->sclass = g84_mpeg_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 211b44c00c850..417cc31a12ef7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -26,33 +26,99 @@ #include #include #include +#include + +#include /******************************************************************************* * MPEG object classes ******************************************************************************/ static int -nv31_mpeg_object_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv31_mpeg_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nvkm_gpuobj *obj; - int ret; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 16, align, + false, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); + nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); + nvkm_done(*pgpuobj); + } + return ret; +} - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 20, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; +const struct nvkm_object_func +nv31_mpeg_object = { + .bind = nv31_mpeg_object_bind, +}; - nvkm_kmap(obj); - nvkm_wo32(obj, 0x00, nv_mclass(obj)); - nvkm_wo32(obj, 0x04, 0x00000000); - nvkm_wo32(obj, 0x08, 0x00000000); - nvkm_wo32(obj, 0x0c, 0x00000000); - nvkm_done(obj); - return 0; +/******************************************************************************* + * PMPEG context + ******************************************************************************/ + +static void * +nv31_mpeg_chan_dtor(struct nvkm_object *object) +{ + struct nv31_mpeg_chan *chan = nv31_mpeg_chan(object); + struct nv31_mpeg *mpeg = chan->mpeg; + unsigned long flags; + + spin_lock_irqsave(&mpeg->base.engine.lock, flags); + if (mpeg->chan == chan) + mpeg->chan = NULL; + spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + return chan; +} + +static const struct nvkm_object_func +nv31_mpeg_chan = { + .dtor = nv31_mpeg_chan_dtor, +}; + +int +nv31_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nv31_mpeg *mpeg = nv31_mpeg(oclass->engine); + struct nv31_mpeg_chan *chan; + unsigned long flags; + int ret = -EBUSY; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv31_mpeg_chan, oclass, &chan->object); + chan->mpeg = mpeg; + chan->fifo = fifoch; + *pobject = &chan->object; + + spin_lock_irqsave(&mpeg->base.engine.lock, flags); + if (!mpeg->chan) { + mpeg->chan = chan; + ret = 0; + } + spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + return ret; +} + +/******************************************************************************* + * PMPEG engine/subdev functions + ******************************************************************************/ + +void +nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i) +{ + struct nv31_mpeg *mpeg = (void *)engine; + struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; + + nvkm_wr32(device, 0x00b008 + (i * 0x10), tile->pitch); + nvkm_wr32(device, 0x00b004 + (i * 0x10), tile->limit); + nvkm_wr32(device, 0x00b000 + (i * 0x10), tile->addr); } static bool @@ -109,95 +175,6 @@ nv31_mpeg_mthd(struct nv31_mpeg *mpeg, u32 mthd, u32 data) return false; } -struct nvkm_ofuncs -nv31_mpeg_ofuncs = { - .ctor = nv31_mpeg_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -struct nvkm_oclass -nv31_mpeg_sclass[] = { - { 0x3174, &nv31_mpeg_ofuncs }, - {} -}; - -/******************************************************************************* - * PMPEG context - ******************************************************************************/ - -static int -nv31_mpeg_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv31_mpeg *mpeg = (void *)engine; - struct nv31_mpeg_chan *chan; - unsigned long flags; - int ret; - - ret = nvkm_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - spin_lock_irqsave(&nv_engine(mpeg)->lock, flags); - if (mpeg->chan) { - spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); - nvkm_object_destroy(&chan->base); - *pobject = NULL; - return -EBUSY; - } - chan->fifo = nvkm_fifo_chan(parent); - mpeg->chan = chan; - spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); - return 0; -} - -static void -nv31_mpeg_context_dtor(struct nvkm_object *object) -{ - struct nv31_mpeg *mpeg = (void *)object->engine; - struct nv31_mpeg_chan *chan = (void *)object; - unsigned long flags; - - spin_lock_irqsave(&nv_engine(mpeg)->lock, flags); - mpeg->chan = NULL; - spin_unlock_irqrestore(&nv_engine(mpeg)->lock, flags); - nvkm_object_destroy(&chan->base); -} - -struct nvkm_oclass -nv31_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x31), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv31_mpeg_context_ctor, - .dtor = nv31_mpeg_context_dtor, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - }, -}; - -/******************************************************************************* - * PMPEG engine/subdev functions - ******************************************************************************/ - -void -nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i) -{ - struct nv31_mpeg *mpeg = (void *)engine; - struct nvkm_device *device = mpeg->base.engine.subdev.device; - struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; - - nvkm_wr32(device, 0x00b008 + (i * 0x10), tile->pitch); - nvkm_wr32(device, 0x00b004 + (i * 0x10), tile->limit); - nvkm_wr32(device, 0x00b000 + (i * 0x10), tile->addr); -} - void nv31_mpeg_intr(struct nvkm_subdev *subdev) { @@ -231,13 +208,22 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) if (show) { nvkm_error(subdev, "ch %d [%s] %08x %08x %08x %08x\n", mpeg->chan ? mpeg->chan->fifo->chid : -1, - mpeg->chan ? mpeg->chan->fifo->object.client->name : + mpeg->chan ? mpeg->chan->object.client->name : "unknown", stat, type, mthd, data); } spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); } +static const struct nvkm_engine_func +nv31_mpeg = { + .fifo.cclass = nv31_mpeg_chan_new, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } +}; + static int nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -251,11 +237,11 @@ nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + mpeg->base.engine.func = &nv31_mpeg; + mpeg->mthd_dma = nv31_mpeg_mthd_dma; nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv31_mpeg_intr; - nv_engine(mpeg)->cclass = &nv31_mpeg_cclass; - nv_engine(mpeg)->sclass = nv31_mpeg_sclass; nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h index 6bdd409d5769c..a2dae83fbc71a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h @@ -1,16 +1,23 @@ #ifndef __NV31_MPEG_H__ #define __NV31_MPEG_H__ +#define nv31_mpeg(p) container_of((p), struct nv31_mpeg, base.engine) +#include "priv.h" #include -#include - -struct nv31_mpeg_chan { - struct nvkm_object base; - struct nvkm_fifo_chan *fifo; -}; struct nv31_mpeg { struct nvkm_mpeg base; struct nv31_mpeg_chan *chan; bool (*mthd_dma)(struct nvkm_device *, u32 mthd, u32 data); }; + +#define nv31_mpeg_chan(p) container_of((p), struct nv31_mpeg_chan, object) + +struct nv31_mpeg_chan { + struct nvkm_object object; + struct nv31_mpeg *mpeg; + struct nvkm_fifo_chan *fifo; +}; + +int nv31_mpeg_chan_new(struct nvkm_fifo_chan *, const struct nvkm_oclass *, + struct nvkm_object **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index cc167dcc788f7..b4ef1ebd38ab2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -25,9 +25,7 @@ #include -/******************************************************************************* - * MPEG object classes - ******************************************************************************/ +#include bool nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) @@ -67,16 +65,6 @@ nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) return true; } -struct nvkm_oclass -nv40_mpeg_sclass[] = { - { 0x3174, &nv31_mpeg_ofuncs }, - {} -}; - -/******************************************************************************* - * PMPEG engine/subdev functions - ******************************************************************************/ - static void nv40_mpeg_intr(struct nvkm_subdev *subdev) { @@ -93,6 +81,15 @@ nv40_mpeg_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_engine_func +nv40_mpeg = { + .fifo.cclass = nv31_mpeg_chan_new, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } +}; + static int nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -106,11 +103,11 @@ nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + mpeg->base.engine.func = &nv40_mpeg; + mpeg->mthd_dma = nv40_mpeg_mthd_dma; nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv40_mpeg_intr; - nv_engine(mpeg)->cclass = &nv31_mpeg_cclass; - nv_engine(mpeg)->sclass = nv40_mpeg_sclass; nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index ff9ddc67a2921..0f9ef18bf18d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -21,99 +21,107 @@ * * Authors: Ben Skeggs */ -#include +#define nv44_mpeg(p) container_of((p), struct nv44_mpeg, base.engine) +#include "priv.h" #include #include +#include + struct nv44_mpeg { struct nvkm_mpeg base; struct list_head chan; }; +bool nv40_mpeg_mthd_dma(struct nvkm_device *, u32, u32); + +/******************************************************************************* + * PMPEG context + ******************************************************************************/ +#define nv44_mpeg_chan(p) container_of((p), struct nv44_mpeg_chan, object) + struct nv44_mpeg_chan { - struct nvkm_mpeg_chan base; + struct nvkm_object object; + struct nv44_mpeg *mpeg; struct nvkm_fifo_chan *fifo; - u32 inst; struct list_head head; + u32 inst; }; -bool nv40_mpeg_mthd_dma(struct nvkm_device *, u32, u32); +static int +nv44_mpeg_chan_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) +{ + struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); + int ret = nvkm_gpuobj_new(chan->object.engine->subdev.device, 264 * 4, + align, true, parent, pgpuobj); + if (ret == 0) { + chan->inst = (*pgpuobj)->addr; + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x78, 0x02001ec1); + nvkm_done(*pgpuobj); + } + return ret; +} -/******************************************************************************* - * PMPEG context - ******************************************************************************/ +static int +nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend) +{ -static void -nv44_mpeg_context_dtor(struct nvkm_object *object) + struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); + struct nv44_mpeg *mpeg = chan->mpeg; + struct nvkm_device *device = mpeg->base.engine.subdev.device; + u32 inst = 0x80000000 | (chan->inst >> 4); + + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); + if (nvkm_rd32(device, 0x00b318) == inst) + nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000); + nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); + return 0; +} + +static void * +nv44_mpeg_chan_dtor(struct nvkm_object *object) { - struct nv44_mpeg_chan *chan = (void *)object; - struct nv44_mpeg *mpeg = (void *)object->engine; + struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); + struct nv44_mpeg *mpeg = chan->mpeg; unsigned long flags; spin_lock_irqsave(&mpeg->base.engine.lock, flags); list_del(&chan->head); spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); - nvkm_mpeg_context_destroy(&chan->base); + return chan; } +static const struct nvkm_object_func +nv44_mpeg_chan = { + .dtor = nv44_mpeg_chan_dtor, + .fini = nv44_mpeg_chan_fini, + .bind = nv44_mpeg_chan_bind, +}; + static int -nv44_mpeg_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv44_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) { - struct nv44_mpeg *mpeg = (void *)engine; + struct nv44_mpeg *mpeg = nv44_mpeg(oclass->engine); struct nv44_mpeg_chan *chan; unsigned long flags; - int ret; - ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 264 * 4, - 16, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nv44_mpeg_chan, oclass, &chan->object); + chan->mpeg = mpeg; + chan->fifo = fifoch; + *pobject = &chan->object; spin_lock_irqsave(&mpeg->base.engine.lock, flags); - chan->fifo = nvkm_fifo_chan(parent); - chan->inst = chan->base.base.gpuobj.addr; list_add(&chan->head, &mpeg->chan); spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); - - nvkm_kmap(&chan->base.base.gpuobj); - nvkm_wo32(&chan->base.base.gpuobj, 0x78, 0x02001ec1); - nvkm_done(&chan->base.base.gpuobj); return 0; } -static int -nv44_mpeg_context_fini(struct nvkm_object *object, bool suspend) -{ - - struct nvkm_mpeg *mpeg = (void *)object->engine; - struct nv44_mpeg_chan *chan = (void *)object; - struct nvkm_device *device = mpeg->engine.subdev.device; - u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4; - - nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); - if (nvkm_rd32(device, 0x00b318) == inst) - nvkm_mask(device, 0x00b318, 0x80000000, 0x00000000); - nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000001); - return 0; -} - -static struct nvkm_oclass -nv44_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x44), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_mpeg_context_ctor, - .dtor = nv44_mpeg_context_dtor, - .init = _nvkm_mpeg_context_init, - .fini = nv44_mpeg_context_fini, - .rd32 = _nvkm_mpeg_context_rd32, - .wr32 = _nvkm_mpeg_context_wr32, - }, -}; - /******************************************************************************* * PMPEG engine/subdev functions ******************************************************************************/ @@ -175,7 +183,7 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) if (show) { nvkm_error(subdev, "ch %d [%08x %s] %08x %08x %08x %08x\n", chan ? chan->fifo->chid : -1, inst << 4, - chan ? chan->fifo->object.client->name : "unknown", + chan ? chan->object.client->name : "unknown", stat, type, mthd, data); } @@ -198,6 +206,15 @@ nv44_mpeg_me_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_engine_func +nv44_mpeg = { + .fifo.cclass = nv44_mpeg_chan_new, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } +}; + static int nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -212,11 +229,10 @@ nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; INIT_LIST_HEAD(&mpeg->chan); + mpeg->base.engine.func = &nv44_mpeg; nv_subdev(mpeg)->unit = 0x00000002; nv_subdev(mpeg)->intr = nv44_mpeg_me_intr; - nv_engine(mpeg)->cclass = &nv44_mpeg_cclass; - nv_engine(mpeg)->sclass = nv40_mpeg_sclass; nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index c906c43e9065c..a94c73e08ae36 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -21,98 +21,35 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" +#include #include -struct nv50_mpeg_chan { - struct nvkm_mpeg_chan base; -}; - -/******************************************************************************* - * MPEG object classes - ******************************************************************************/ - -static int -nv50_mpeg_object_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_gpuobj *obj; - int ret; - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent, - 16, 16, 0, &obj); - *pobject = nv_object(obj); - if (ret) - return ret; - - nvkm_kmap(obj); - nvkm_wo32(obj, 0x00, nv_mclass(obj)); - nvkm_wo32(obj, 0x04, 0x00000000); - nvkm_wo32(obj, 0x08, 0x00000000); - nvkm_wo32(obj, 0x0c, 0x00000000); - nvkm_done(obj); - return 0; -} - -struct nvkm_ofuncs -nv50_mpeg_ofuncs = { - .ctor = nv50_mpeg_object_ctor, - .dtor = _nvkm_gpuobj_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - .rd32 = _nvkm_gpuobj_rd32, - .wr32 = _nvkm_gpuobj_wr32, -}; - -static struct nvkm_oclass -nv50_mpeg_sclass[] = { - { 0x3174, &nv50_mpeg_ofuncs }, - {} -}; +#include /******************************************************************************* * PMPEG context ******************************************************************************/ -int -nv50_mpeg_context_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static int +nv50_mpeg_cclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, + int align, struct nvkm_gpuobj **pgpuobj) { - struct nv50_mpeg_chan *chan; - struct nvkm_gpuobj *image; - int ret; - - ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4, - 0, NVOBJ_FLAG_ZERO_ALLOC, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; - - image = &chan->base.base.gpuobj; - - nvkm_kmap(image); - nvkm_wo32(image, 0x0070, 0x00801ec1); - nvkm_wo32(image, 0x007c, 0x0000037c); - nvkm_done(image); - return 0; + int ret = nvkm_gpuobj_new(object->engine->subdev.device, 128 * 4, + align, true, parent, pgpuobj); + if (ret == 0) { + nvkm_kmap(*pgpuobj); + nvkm_wo32(*pgpuobj, 0x70, 0x00801ec1); + nvkm_wo32(*pgpuobj, 0x7c, 0x0000037c); + nvkm_done(*pgpuobj); + } + return ret; } -static struct nvkm_oclass +const struct nvkm_object_func nv50_mpeg_cclass = { - .handle = NV_ENGCTX(MPEG, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mpeg_context_ctor, - .dtor = _nvkm_mpeg_context_dtor, - .init = _nvkm_mpeg_context_init, - .fini = _nvkm_mpeg_context_fini, - .rd32 = _nvkm_mpeg_context_rd32, - .wr32 = _nvkm_mpeg_context_wr32, - }, + .bind = nv50_mpeg_cclass_bind, }; /******************************************************************************* @@ -162,6 +99,15 @@ nv50_vpe_intr(struct nvkm_subdev *subdev) } } +static const struct nvkm_engine_func +nv50_mpeg = { + .cclass = &nv50_mpeg_cclass, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } +}; + static int nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -175,10 +121,10 @@ nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + mpeg->engine.func = &nv50_mpeg; + nv_subdev(mpeg)->unit = 0x00400002; nv_subdev(mpeg)->intr = nv50_vpe_intr; - nv_engine(mpeg)->cclass = &nv50_mpeg_cclass; - nv_engine(mpeg)->sclass = nv50_mpeg_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h new file mode 100644 index 0000000000000..8b31ecabb5280 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h @@ -0,0 +1,9 @@ +#ifndef __NVKM_MPEG_PRIV_H__ +#define __NVKM_MPEG_PRIV_H__ +#include +struct nvkm_fifo_chan; + +extern const struct nvkm_object_func nv31_mpeg_object; + +extern const struct nvkm_object_func nv50_mpeg_cclass; +#endif -- GitLab From 5ffeb84b8eba71b4f88af6997db843ddf68149e0 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5526/7006] drm/nouveau/pm: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 10 +- drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 225 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 2 - .../gpu/drm/nouveau/nvkm/engine/pm/gk110.c | 2 - drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 2 - drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 22 +- 6 files changed, 132 insertions(+), 131 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index f13f8e6fc017c..c67cea6aae4d5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -1,5 +1,6 @@ #ifndef __NVKM_PM_H__ #define __NVKM_PM_H__ +#define nvkm_pm(p) container_of((p), struct nvkm_pm, engine) #include struct nvkm_perfdom; @@ -7,20 +8,13 @@ struct nvkm_perfctr; struct nvkm_pm { struct nvkm_engine engine; - struct nvkm_perfctx *context; - void *profile_data; + struct nvkm_object *perfmon; struct list_head domains; struct list_head sources; u32 sequence; }; -static inline struct nvkm_pm * -nvkm_pm(void *obj) -{ - return (void *)nvkm_engine(obj, NVDEV_ENGINE_PM); -} - extern struct nvkm_oclass *nv40_pm_oclass; extern struct nvkm_oclass *nv50_pm_oclass; extern struct nvkm_oclass *g84_pm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 90a7d89cc019b..5b4ab63809bee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -25,7 +25,6 @@ #include #include -#include #include #include @@ -304,11 +303,11 @@ nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) return -EINVAL; } -static void -nvkm_perfdom_dtor(struct nvkm_object *object) +static void * +nvkm_perfdom_dtor(struct nvkm_object *base) { - struct nvkm_pm *pm = (void *)object->engine; - struct nvkm_perfdom *dom = (void *)object; + struct nvkm_perfdom *dom = nvkm_perfdom(base); + struct nvkm_pm *pm = dom->perfmon->pm; int i; for (i = 0; i < 4; i++) { @@ -320,7 +319,8 @@ nvkm_perfdom_dtor(struct nvkm_object *object) } kfree(ctr); } - nvkm_object_destroy(&dom->base); + + return dom; } static int @@ -353,15 +353,22 @@ nvkm_perfctr_new(struct nvkm_perfdom *dom, int slot, u8 domain, return 0; } +static const struct nvkm_object_func +nvkm_perfdom = { + .dtor = nvkm_perfdom_dtor, + .mthd = nvkm_perfdom_mthd, +}; + static int -nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, +nvkm_perfdom_new_(struct nvkm_perfmon *perfmon, + const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { union { struct nvif_perfdom_v0 v0; } *args = data; - struct nvkm_pm *pm = (void *)engine; + struct nvkm_pm *pm = perfmon->pm; + struct nvkm_object *parent = oclass->parent; struct nvkm_perfdom *sdom = NULL; struct nvkm_perfctr *ctr[4] = {}; struct nvkm_perfdom *dom; @@ -403,10 +410,11 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (!sdom) return -EINVAL; - ret = nvkm_object_create(parent, engine, oclass, 0, &dom); - *pobject = nv_object(dom); - if (ret) - return ret; + if (!(dom = kzalloc(sizeof(*dom), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nvkm_perfdom, oclass, &dom->object); + dom->perfmon = perfmon; + *pobject = &dom->object; dom->func = sdom->func; dom->addr = sdom->addr; @@ -416,25 +424,18 @@ nvkm_perfdom_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -static struct nvkm_ofuncs -nvkm_perfdom_ofuncs = { - .ctor = nvkm_perfdom_ctor, - .dtor = nvkm_perfdom_dtor, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - .mthd = nvkm_perfdom_mthd, -}; - /******************************************************************************* * Perfmon object classes ******************************************************************************/ static int -nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) +nvkm_perfmon_mthd_query_domain(struct nvkm_perfmon *perfmon, + void *data, u32 size) { union { struct nvif_perfmon_query_domain_v0 v0; } *args = data; - struct nvkm_pm *pm = (void *)object->engine; + struct nvkm_object *object = &perfmon->object; + struct nvkm_pm *pm = perfmon->pm; struct nvkm_perfdom *dom; u8 domain_nr; int di, ret; @@ -475,13 +476,15 @@ nvkm_perfmon_mthd_query_domain(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) +nvkm_perfmon_mthd_query_signal(struct nvkm_perfmon *perfmon, + void *data, u32 size) { union { struct nvif_perfmon_query_signal_v0 v0; } *args = data; - struct nvkm_device *device = nv_device(object); - struct nvkm_pm *pm = (void *)object->engine; + struct nvkm_object *object = &perfmon->object; + struct nvkm_pm *pm = perfmon->pm; + struct nvkm_device *device = pm->engine.subdev.device; struct nvkm_perfdom *dom; struct nvkm_perfsig *sig; const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false); @@ -527,12 +530,14 @@ nvkm_perfmon_mthd_query_signal(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) +nvkm_perfmon_mthd_query_source(struct nvkm_perfmon *perfmon, + void *data, u32 size) { union { struct nvif_perfmon_query_source_v0 v0; } *args = data; - struct nvkm_pm *pm = (void *)object->engine; + struct nvkm_object *object = &perfmon->object; + struct nvkm_pm *pm = perfmon->pm; struct nvkm_perfdom *dom = NULL; struct nvkm_perfsig *sig; struct nvkm_perfsrc *src; @@ -579,117 +584,118 @@ nvkm_perfmon_mthd_query_source(struct nvkm_object *object, void *data, u32 size) static int nvkm_perfmon_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { + struct nvkm_perfmon *perfmon = nvkm_perfmon(object); switch (mthd) { case NVIF_PERFMON_V0_QUERY_DOMAIN: - return nvkm_perfmon_mthd_query_domain(object, data, size); + return nvkm_perfmon_mthd_query_domain(perfmon, data, size); case NVIF_PERFMON_V0_QUERY_SIGNAL: - return nvkm_perfmon_mthd_query_signal(object, data, size); + return nvkm_perfmon_mthd_query_signal(perfmon, data, size); case NVIF_PERFMON_V0_QUERY_SOURCE: - return nvkm_perfmon_mthd_query_source(object, data, size); + return nvkm_perfmon_mthd_query_source(perfmon, data, size); default: break; } return -EINVAL; } -static struct nvkm_oclass -nvkm_perfmon_sclass[] = { - { .handle = NVIF_IOCTL_NEW_V0_PERFDOM, - .ofuncs = &nvkm_perfdom_ofuncs, - }, - {} -}; +static int +nvkm_perfmon_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_perfmon *perfmon = nvkm_perfmon(oclass->parent); + return nvkm_perfdom_new_(perfmon, oclass, data, size, pobject); +} static int -nvkm_perfmon_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_perfmon_child_get(struct nvkm_object *base, int index, + struct nvkm_oclass *oclass) { - struct nvkm_parent *perfmon; - int ret = nvkm_parent_create(parent, engine, oclass, 0, - nvkm_perfmon_sclass, 0, &perfmon); - *pobject = perfmon ? &perfmon->object : NULL; - return ret; + if (index == 0) { + oclass->base.oclass = NVIF_IOCTL_NEW_V0_PERFDOM; + oclass->base.minver = 0; + oclass->base.maxver = 0; + oclass->ctor = nvkm_perfmon_child_new; + return 0; + } + return -EINVAL; } -static struct nvkm_ofuncs -nvkm_perfmon_ofuncs = { - .ctor = nvkm_perfmon_ctor, - .dtor = _nvkm_parent_dtor, - .init = _nvkm_parent_init, - .fini = _nvkm_parent_fini, - .mthd = nvkm_perfmon_mthd, -}; +static void * +nvkm_perfmon_dtor(struct nvkm_object *base) +{ + struct nvkm_perfmon *perfmon = nvkm_perfmon(base); + struct nvkm_pm *pm = perfmon->pm; + mutex_lock(&pm->engine.subdev.mutex); + if (pm->perfmon == &perfmon->object) + pm->perfmon = NULL; + mutex_unlock(&pm->engine.subdev.mutex); + return perfmon; +} -struct nvkm_oclass -nvkm_pm_sclass[] = { - { - .handle = NVIF_IOCTL_NEW_V0_PERFMON, - .ofuncs = &nvkm_perfmon_ofuncs, - }, - {}, +static struct nvkm_object_func +nvkm_perfmon = { + .dtor = nvkm_perfmon_dtor, + .mthd = nvkm_perfmon_mthd, + .sclass = nvkm_perfmon_child_get, }; -/******************************************************************************* - * PPM context - ******************************************************************************/ -static void -nvkm_perfctx_dtor(struct nvkm_object *object) +static int +nvkm_perfmon_new(struct nvkm_pm *pm, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_pm *pm = (void *)object->engine; - struct nvkm_perfctx *ctx = (void *)object; + struct nvkm_perfmon *perfmon; - nvkm_gpuobj_destroy(&ctx->base); - mutex_lock(&nv_subdev(pm)->mutex); - if (pm->context == ctx) - pm->context = NULL; - mutex_unlock(&nv_subdev(pm)->mutex); + if (!(perfmon = kzalloc(sizeof(*perfmon), GFP_KERNEL))) + return -ENOMEM; + nvkm_object_ctor(&nvkm_perfmon, oclass, &perfmon->object); + perfmon->pm = pm; + *pobject = &perfmon->object; + return 0; } +/******************************************************************************* + * PPM engine/subdev functions + ******************************************************************************/ + static int -nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_pm_oclass_new(struct nvkm_device *device, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_pm *pm = (void *)engine; - struct nvkm_perfctx *ctx; + struct nvkm_pm *pm = nvkm_pm(oclass->engine); int ret; - /* no context needed for perfdom objects... */ - if (parent->parent != &nvkm_client(parent)->object) { - atomic_inc(&parent->refcount); - *pobject = parent; - return 1; - } - - ret = nvkm_gpuobj_create(parent, engine, oclass, 0, NULL, 0, 0, 0, &ctx); - *pobject = nv_object(ctx); + ret = nvkm_perfmon_new(pm, oclass, data, size, pobject); if (ret) return ret; - mutex_lock(&nv_subdev(pm)->mutex); - if (pm->context == NULL) - pm->context = ctx; - if (ctx != pm->context) - ret = -EBUSY; - mutex_unlock(&nv_subdev(pm)->mutex); - + mutex_lock(&pm->engine.subdev.mutex); + if (pm->perfmon == NULL) + pm->perfmon = *pobject; + ret = (pm->perfmon == *pobject) ? 0 : -EBUSY; + mutex_unlock(&pm->engine.subdev.mutex); return ret; } -struct nvkm_oclass -nvkm_pm_cclass = { - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nvkm_perfctx_ctor, - .dtor = nvkm_perfctx_dtor, - .init = _nvkm_gpuobj_init, - .fini = _nvkm_gpuobj_fini, - }, +static const struct nvkm_device_oclass +nvkm_pm_oclass = { + .base.oclass = NVIF_IOCTL_NEW_V0_PERFMON, + .base.minver = -1, + .base.maxver = -1, + .ctor = nvkm_pm_oclass_new, }; -/******************************************************************************* - * PPM engine/subdev functions - ******************************************************************************/ +static int +nvkm_pm_oclass_get(struct nvkm_oclass *oclass, int index, + const struct nvkm_device_oclass **class) +{ + if (index == 0) { + oclass->base = nvkm_pm_oclass.base; + *class = &nvkm_pm_oclass; + return index; + } + return 1; +} + int nvkm_perfsrc_new(struct nvkm_pm *pm, struct nvkm_perfsig *sig, const struct nvkm_specsrc *spec) @@ -845,6 +851,11 @@ _nvkm_pm_dtor(struct nvkm_object *object) nvkm_engine_destroy(&pm->engine); } +static const struct nvkm_engine_func +nvkm_pm = { + .base.sclass = nvkm_pm_oclass_get, +}; + int nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) @@ -858,6 +869,8 @@ nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + pm->engine.func = &nvkm_pm; + INIT_LIST_HEAD(&pm->domains); INIT_LIST_HEAD(&pm->sources); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 75a9e6286101d..18e0ed5142495 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -226,8 +226,6 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(pm)->cclass = &nvkm_pm_cclass; - nv_engine(pm)->sclass = nvkm_pm_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c index 3177ba4d2f571..44df8d3110707 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c @@ -36,8 +36,6 @@ gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(pm)->cclass = &nvkm_pm_cclass; - nv_engine(pm)->sclass = nvkm_pm_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index b37c024f07838..a4660dc142593 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -112,8 +112,6 @@ nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(pm)->cclass = &nvkm_pm_cclass; - nv_engine(pm)->sclass = nvkm_pm_sclass; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 2af3a50130963..889dca2e87bea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -12,16 +12,6 @@ struct nvkm_perfctr { u32 ctr; }; -extern struct nvkm_oclass nvkm_pm_sclass[]; - -#include - -struct nvkm_perfctx { - struct nvkm_gpuobj base; -}; - -extern struct nvkm_oclass nvkm_pm_cclass; - struct nvkm_specmux { u32 mask; u8 shift; @@ -68,8 +58,11 @@ struct nvkm_specdom { const struct nvkm_funcdom *func; }; +#define nvkm_perfdom(p) container_of((p), struct nvkm_perfdom, object) + struct nvkm_perfdom { - struct nvkm_object base; + struct nvkm_object object; + struct nvkm_perfmon *perfmon; struct list_head head; struct list_head list; const struct nvkm_funcdom *func; @@ -93,6 +86,13 @@ struct nvkm_funcdom { int nvkm_perfdom_new(struct nvkm_pm *, const char *, u32, u32, u32, u32, const struct nvkm_specdom *); +#define nvkm_perfmon(p) container_of((p), struct nvkm_perfmon, object) + +struct nvkm_perfmon { + struct nvkm_object object; + struct nvkm_pm *pm; +}; + #define nvkm_pm_create(p,e,o,d) \ nvkm_pm_create_((p), (e), (o), sizeof(**d), (void **)d) #define nvkm_pm_dtor(p) ({ \ -- GitLab From 07b9e6cc957195bd1e6908612d67a92ba0ed2cb6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5527/7006] drm/nouveau/sw: convert user classes to new-style nvkm_object Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/sw.h | 1 + drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c | 43 +++++++++ drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c | 46 ++++++---- drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h | 25 ++---- .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 81 +++++++++++------ drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 72 +++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c | 51 ++++------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 89 ++++++++----------- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h | 14 +-- drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c | 50 ++++++----- drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h | 21 +++-- drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h | 13 +++ 12 files changed, 277 insertions(+), 229 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h index f5857a6404d35..f2288d468cb6b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h @@ -4,6 +4,7 @@ struct nvkm_sw { struct nvkm_engine engine; + const struct nvkm_sw_func *func; struct list_head chan; }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c index 1d68ae68884a3..efc18787490c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c @@ -46,6 +46,48 @@ nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data) return handled; } +static int +nvkm_sw_oclass_new(const struct nvkm_oclass *oclass, void *data, u32 size, + struct nvkm_object **pobject) +{ + struct nvkm_sw_chan *chan = nvkm_sw_chan(oclass->parent); + const struct nvkm_sw_chan_sclass *sclass = oclass->engn; + return sclass->ctor(chan, oclass, data, size, pobject); +} + +static int +nvkm_sw_oclass_get(struct nvkm_oclass *oclass, int index) +{ + struct nvkm_sw *sw = nvkm_sw(oclass->engine); + int c = 0; + + while (sw->func->sclass[c].ctor) { + if (c++ == index) { + oclass->engn = &sw->func->sclass[index]; + oclass->base = sw->func->sclass[index].base; + oclass->base.ctor = nvkm_sw_oclass_new; + return index; + } + } + + return c; +} + +static int +nvkm_sw_cclass_get(struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nvkm_sw *sw = nvkm_sw(oclass->engine); + return sw->func->chan_new(sw, fifoch, oclass, pobject); +} + +static const struct nvkm_engine_func +nvkm_sw = { + .fifo.cclass = nvkm_sw_cclass_get, + .fifo.sclass = nvkm_sw_oclass_get, +}; + int nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) @@ -59,6 +101,7 @@ nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; + sw->engine.func = &nvkm_sw; INIT_LIST_HEAD(&sw->chan); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c index 904405a8f5c6b..d082f4f73a80c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.c @@ -69,33 +69,43 @@ nvkm_sw_chan_event = { .ctor = nvkm_sw_chan_event_ctor, }; -void -nvkm_sw_chan_dtor(struct nvkm_object *base) +static void * +nvkm_sw_chan_dtor(struct nvkm_object *object) { - struct nvkm_sw_chan *chan = (void *)base; - list_del(&chan->head); + struct nvkm_sw_chan *chan = nvkm_sw_chan(object); + struct nvkm_sw *sw = chan->sw; + unsigned long flags; + void *data = chan; + + if (chan->func->dtor) + data = chan->func->dtor(chan); nvkm_event_fini(&chan->event); - nvkm_engctx_destroy(&chan->base); + + spin_lock_irqsave(&sw->engine.lock, flags); + list_del(&chan->head); + spin_unlock_irqrestore(&sw->engine.lock, flags); + return data; } +static const struct nvkm_object_func +nvkm_sw_chan = { + .dtor = nvkm_sw_chan_dtor, +}; + int -nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *func, - struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *func, struct nvkm_sw *sw, + struct nvkm_fifo_chan *fifo, const struct nvkm_oclass *oclass, + struct nvkm_sw_chan *chan) { - struct nvkm_sw *sw = (void *)engine; - struct nvkm_sw_chan *chan; - int ret; - - ret = nvkm_engctx_create_(parent, engine, oclass, parent, - 0, 0, 0, length, pobject); - chan = *pobject; - if (ret) - return ret; + unsigned long flags; + nvkm_object_ctor(&nvkm_sw_chan, oclass, &chan->object); chan->func = func; - chan->fifo = nvkm_fifo_chan(parent); + chan->sw = sw; + chan->fifo = fifo; + spin_lock_irqsave(&sw->engine.lock, flags); list_add(&chan->head, &sw->chan); + spin_unlock_irqrestore(&sw->engine.lock, flags); return nvkm_event_init(&nvkm_sw_chan_event, 1, 1, &chan->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h index edebd9c30c0c4..6608bf6c68421 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/chan.h @@ -1,35 +1,26 @@ #ifndef __NVKM_SW_CHAN_H__ #define __NVKM_SW_CHAN_H__ +#define nvkm_sw_chan(p) container_of((p), struct nvkm_sw_chan, object) #include "priv.h" -#include #include struct nvkm_sw_chan { - struct nvkm_engctx base; const struct nvkm_sw_chan_func *func; + struct nvkm_object object; + struct nvkm_sw *sw; struct nvkm_fifo_chan *fifo; struct list_head head; + struct nvkm_event event; }; struct nvkm_sw_chan_func { + void *(*dtor)(struct nvkm_sw_chan *); bool (*mthd)(struct nvkm_sw_chan *, int subc, u32 mthd, u32 data); }; +int nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *, struct nvkm_sw *, + struct nvkm_fifo_chan *, const struct nvkm_oclass *, + struct nvkm_sw_chan *); bool nvkm_sw_chan_mthd(struct nvkm_sw_chan *, int subc, u32 mthd, u32 data); - -#define nvkm_sw_context_create(f,p,e,c,d) \ - nvkm_sw_chan_ctor((f), (p), (e), (c), sizeof(**d), (void **)d) -int nvkm_sw_chan_ctor(const struct nvkm_sw_chan_func *, - struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void nvkm_sw_chan_dtor(struct nvkm_object *); -#define nvkm_sw_context_init(d) \ - nvkm_engctx_init(&(d)->base) -#define nvkm_sw_context_fini(d,s) \ - nvkm_engctx_fini(&(d)->base, (s)) - -#define _nvkm_sw_context_dtor nvkm_sw_chan_dtor -#define _nvkm_sw_context_init _nvkm_engctx_init -#define _nvkm_sw_context_fini _nvkm_engctx_fini #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index ac106c6c25d07..8920f367c1f8e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -25,33 +25,26 @@ #include #include +#include +#include #include -/******************************************************************************* - * software object classes - ******************************************************************************/ - -static struct nvkm_oclass -gf100_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_GF100, &nvkm_nvsw_ofuncs }, - {} -}; - /******************************************************************************* * software context ******************************************************************************/ static int -gf100_sw_vblsem_release(struct nvkm_notify *notify) +gf100_sw_chan_vblsem_release(struct nvkm_notify *notify) { struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); - struct nvkm_sw *sw = (void *)nv_object(chan)->engine; + struct nvkm_sw *sw = chan->base.sw; struct nvkm_device *device = sw->engine.subdev.device; struct nvkm_bar *bar = device->bar; + u32 inst = chan->base.fifo->inst->addr >> 12; - nvkm_wr32(device, 0x001718, 0x80000000 | chan->vblank.channel); + nvkm_wr32(device, 0x001718, 0x80000000 | inst); bar->flush(bar); nvkm_wr32(device, 0x06000c, upper_32_bits(chan->vblank.offset)); nvkm_wr32(device, 0x060010, lower_32_bits(chan->vblank.offset)); @@ -64,7 +57,7 @@ static bool gf100_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) { struct nv50_sw_chan *chan = nv50_sw_chan(base); - struct nvkm_engine *engine = chan->base.base.gpuobj.object.engine; + struct nvkm_engine *engine = chan->base.object.engine; struct nvkm_device *device = engine->subdev.device; switch (mthd) { case 0x0400: @@ -103,27 +96,58 @@ gf100_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) } static const struct nvkm_sw_chan_func -gf100_sw_chan_func = { +gf100_sw_chan = { + .dtor = nv50_sw_chan_dtor, .mthd = gf100_sw_chan_mthd, }; -static struct nv50_sw_cclass -gf100_sw_cclass = { - .base.handle = NV_ENGCTX(SW, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_context_ctor, - .dtor = nv50_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, - .vblank = gf100_sw_vblsem_release, - .chan = &gf100_sw_chan_func, -}; +static int +gf100_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nvkm_disp *disp = sw->engine.subdev.device->disp; + struct nv50_sw_chan *chan; + int ret, i; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_sw_chan_ctor(&gf100_sw_chan, sw, fifoch, oclass, + &chan->base); + if (ret) + return ret; + + for (i = 0; disp && i < disp->vblank.index_nr; i++) { + ret = nvkm_notify_init(NULL, &disp->vblank, + gf100_sw_chan_vblsem_release, false, + &(struct nvif_notify_head_req_v0) { + .head = i, + }, + sizeof(struct nvif_notify_head_req_v0), + sizeof(struct nvif_notify_head_rep_v0), + &chan->vblank.notify[i]); + if (ret) + return ret; + } + + return 0; +} /******************************************************************************* * software engine/subdev functions ******************************************************************************/ +static const struct nvkm_sw_func +gf100_sw_func = { + .chan_new = gf100_sw_chan_new, + .sclass = { + { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_GF100 } }, + {} + } +}; + struct nvkm_oclass * gf100_sw_oclass = &(struct nv50_sw_oclass) { .base.handle = NV_ENGINE(SW, 0xc0), @@ -133,6 +157,5 @@ gf100_sw_oclass = &(struct nv50_sw_oclass) { .init = _nvkm_sw_init, .fini = _nvkm_sw_fini, }, - .cclass = &gf100_sw_cclass.base, - .sclass = gf100_sw_sclass, + .func = &gf100_sw_func, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index 6958cba393daa..d8d9d48b66d28 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -40,9 +40,9 @@ struct nv04_sw_chan { ******************************************************************************/ static int -nv04_sw_mthd_get_ref(struct nvkm_object *object, void *data, u32 size) +nv04_nvsw_mthd_get_ref(struct nvkm_nvsw *nvsw, void *data, u32 size) { - struct nv04_sw_chan *chan = (void *)object->parent; + struct nv04_sw_chan *chan = nv04_sw_chan(nvsw->chan); union { struct nv04_nvsw_get_ref_v0 v0; } *args = data; @@ -56,31 +56,28 @@ nv04_sw_mthd_get_ref(struct nvkm_object *object, void *data, u32 size) } static int -nv04_sw_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) +nv04_nvsw_mthd(struct nvkm_nvsw *nvsw, u32 mthd, void *data, u32 size) { switch (mthd) { case NV04_NVSW_GET_REF: - return nv04_sw_mthd_get_ref(object, data, size); + return nv04_nvsw_mthd_get_ref(nvsw, data, size); default: break; } return -EINVAL; } -static struct nvkm_ofuncs -nv04_sw_ofuncs = { - .ctor = nvkm_nvsw_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - .mthd = nv04_sw_mthd, +static const struct nvkm_nvsw_func +nv04_nvsw = { + .mthd = nv04_nvsw_mthd, }; -static struct nvkm_oclass -nv04_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV04, &nv04_sw_ofuncs }, - {} -}; +static int +nv04_nvsw_new(struct nvkm_sw_chan *chan, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nvkm_nvsw_new_(&nv04_nvsw, chan, oclass, data, size, pobject); +} /******************************************************************************* * software context @@ -103,38 +100,23 @@ nv04_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) } static const struct nvkm_sw_chan_func -nv04_sw_chan_func = { +nv04_sw_chan = { .mthd = nv04_sw_chan_mthd, }; static int -nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifo, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { struct nv04_sw_chan *chan; - int ret; - - ret = nvkm_sw_context_create(&nv04_sw_chan_func, - parent, engine, oclass, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; atomic_set(&chan->ref, 0); - return 0; -} + *pobject = &chan->base.object; -static struct nvkm_oclass -nv04_sw_cclass = { - .handle = NV_ENGCTX(SW, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_sw_context_ctor, - .dtor = _nvkm_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, -}; + return nvkm_sw_chan_ctor(&nv04_sw_chan, sw, fifo, oclass, &chan->base); +} /******************************************************************************* * software engine/subdev functions @@ -146,6 +128,15 @@ nv04_sw_intr(struct nvkm_subdev *subdev) nvkm_mask(subdev->device, 0x000100, 0x80000000, 0x00000000); } +static const struct nvkm_sw_func +nv04_sw = { + .chan_new = nv04_sw_chan_new, + .sclass = { + { nv04_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV04 } }, + {} + } +}; + static int nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -159,8 +150,7 @@ nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(sw)->cclass = &nv04_sw_cclass; - nv_engine(sw)->sclass = nv04_sw_sclass; + sw->func = &nv04_sw; nv_subdev(sw)->intr = nv04_sw_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index ecaeeaa8edc7c..1b9fc1b1f69e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -27,56 +27,40 @@ #include -/******************************************************************************* - * software object classes - ******************************************************************************/ - -static struct nvkm_oclass -nv10_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV10, &nvkm_nvsw_ofuncs }, - {} -}; - /******************************************************************************* * software context ******************************************************************************/ static const struct nvkm_sw_chan_func -nv10_sw_chan_func = { +nv10_sw_chan = { }; static int -nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv10_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifo, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { struct nvkm_sw_chan *chan; - int ret; - ret = nvkm_sw_context_create(&nv10_sw_chan_func, - parent, engine, oclass, &chan); - *pobject = nv_object(chan); - if (ret) - return ret; + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->object; - return 0; + return nvkm_sw_chan_ctor(&nv10_sw_chan, sw, fifo, oclass, chan); } -static struct nvkm_oclass -nv10_sw_cclass = { - .handle = NV_ENGCTX(SW, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_sw_context_ctor, - .dtor = _nvkm_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, -}; - /******************************************************************************* * software engine/subdev functions ******************************************************************************/ +static const struct nvkm_sw_func +nv10_sw = { + .chan_new = nv10_sw_chan_new, + .sclass = { + { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV10 } }, + {} + } +}; + static int nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, @@ -90,8 +74,7 @@ nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(sw)->cclass = &nv10_sw_cclass; - nv_engine(sw)->sclass = nv10_sw_sclass; + sw->func = &nv10_sw; nv_subdev(sw)->intr = nv04_sw_intr; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 35ec1cffb53a2..451f758f5ebfd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -31,30 +31,20 @@ #include #include -/******************************************************************************* - * software object classes - ******************************************************************************/ - -static struct nvkm_oclass -nv50_sw_sclass[] = { - { NVIF_IOCTL_NEW_V0_SW_NV50, &nvkm_nvsw_ofuncs }, - {} -}; - /******************************************************************************* * software context ******************************************************************************/ static int -nv50_sw_vblsem_release(struct nvkm_notify *notify) +nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) { struct nv50_sw_chan *chan = container_of(notify, typeof(*chan), vblank.notify[notify->index]); - struct nvkm_sw *sw = (void *)nv_object(chan)->engine; + struct nvkm_sw *sw = chan->base.sw; struct nvkm_device *device = sw->engine.subdev.device; struct nvkm_bar *bar = device->bar; - nvkm_wr32(device, 0x001704, chan->vblank.channel); + nvkm_wr32(device, 0x001704, chan->base.fifo->inst->addr >> 12); nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma); bar->flush(bar); @@ -73,7 +63,7 @@ static bool nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) { struct nv50_sw_chan *chan = nv50_sw_chan(base); - struct nvkm_engine *engine = chan->base.base.gpuobj.object.engine; + struct nvkm_engine *engine = chan->base.object.engine; struct nvkm_device *device = engine->subdev.device; switch (mthd) { case 0x018c: chan->vblank.ctxdma = data; return true; @@ -91,41 +81,41 @@ nv50_sw_chan_mthd(struct nvkm_sw_chan *base, int subc, u32 mthd, u32 data) return false; } -static const struct nvkm_sw_chan_func -nv50_sw_chan_func = { - .mthd = nv50_sw_chan_mthd, -}; - -void -nv50_sw_context_dtor(struct nvkm_object *object) +void * +nv50_sw_chan_dtor(struct nvkm_sw_chan *base) { - struct nv50_sw_chan *chan = (void *)object; + struct nv50_sw_chan *chan = nv50_sw_chan(base); int i; - for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++) nvkm_notify_fini(&chan->vblank.notify[i]); - - nvkm_sw_chan_dtor(&chan->base.base.gpuobj.object); + return chan; } -int -nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_sw_chan_func +nv50_sw_chan = { + .dtor = nv50_sw_chan_dtor, + .mthd = nv50_sw_chan_mthd, +}; + +static int +nv50_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, + const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { - struct nvkm_disp *disp = parent->engine->subdev.device->disp; - struct nv50_sw_cclass *pclass = (void *)oclass; + struct nvkm_disp *disp = sw->engine.subdev.device->disp; struct nv50_sw_chan *chan; int ret, i; - ret = nvkm_sw_context_create(pclass->chan, parent, engine, oclass, &chan); - *pobject = nv_object(chan); + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->base.object; + + ret = nvkm_sw_chan_ctor(&nv50_sw_chan, sw, fifoch, oclass, &chan->base); if (ret) return ret; for (i = 0; disp && i < disp->vblank.index_nr; i++) { - ret = nvkm_notify_init(NULL, &disp->vblank, pclass->vblank, - false, + ret = nvkm_notify_init(NULL, &disp->vblank, + nv50_sw_chan_vblsem_release, false, &(struct nvif_notify_head_req_v0) { .head = i, }, @@ -136,23 +126,9 @@ nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return ret; } - chan->vblank.channel = nvkm_fifo_chan(parent)->inst->addr >> 12; return 0; } -static struct nv50_sw_cclass -nv50_sw_cclass = { - .base.handle = NV_ENGCTX(SW, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_context_ctor, - .dtor = nv50_sw_context_dtor, - .init = _nvkm_sw_context_init, - .fini = _nvkm_sw_context_fini, - }, - .vblank = nv50_sw_vblsem_release, - .chan = &nv50_sw_chan_func, -}; - /******************************************************************************* * software engine/subdev functions ******************************************************************************/ @@ -171,12 +147,20 @@ nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - nv_engine(sw)->cclass = pclass->cclass; - nv_engine(sw)->sclass = pclass->sclass; + sw->func = pclass->func; nv_subdev(sw)->intr = nv04_sw_intr; return 0; } +static const struct nvkm_sw_func +nv50_sw_func = { + .chan_new = nv50_sw_chan_new, + .sclass = { + { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV50 } }, + {} + } +}; + struct nvkm_oclass * nv50_sw_oclass = &(struct nv50_sw_oclass) { .base.handle = NV_ENGINE(SW, 0x50), @@ -186,6 +170,5 @@ nv50_sw_oclass = &(struct nv50_sw_oclass) { .init = _nvkm_sw_init, .fini = _nvkm_sw_fini, }, - .cclass = &nv50_sw_cclass.base, - .sclass = nv50_sw_sclass, + .func = &nv50_sw_func, }.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index 534c21079b81a..c90a470564e26 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -8,8 +8,7 @@ struct nv50_sw_oclass { struct nvkm_oclass base; - struct nvkm_oclass *cclass; - struct nvkm_oclass *sclass; + const struct nvkm_sw_func *func; }; int nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *, @@ -26,20 +25,11 @@ struct nv50_sw_chan { struct nvkm_sw_chan base; struct { struct nvkm_notify notify[4]; - u32 channel; u32 ctxdma; u64 offset; u32 value; } vblank; }; -int nv50_sw_context_ctor(struct nvkm_object *, - struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_sw_context_dtor(struct nvkm_object *); - -int nv50_sw_mthd_vblsem_value(struct nvkm_object *, u32, void *, u32); -int nv50_sw_mthd_vblsem_release(struct nvkm_object *, u32, void *, u32); -int nv50_sw_mthd_flip(struct nvkm_object *, u32, void *, u32); +void *nv50_sw_chan_dtor(struct nvkm_sw_chan *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c index c3c6829fd0010..6652a9196753c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c @@ -21,19 +21,22 @@ * * Authors: Ben Skeggs */ -#define nvkm_nvsw(p) container_of((p), struct nvkm_nvsw, object) #include "nvsw.h" #include "chan.h" #include -struct nvkm_nvsw { - struct nvkm_object object; - struct nvkm_sw_chan *chan; -}; +static int +nvkm_nvsw_mthd_(struct nvkm_object *base, u32 mthd, void *data, u32 size) +{ + struct nvkm_nvsw *nvsw = nvkm_nvsw(base); + if (nvsw->func->mthd) + return nvsw->func->mthd(nvsw, mthd, data, size); + return -ENODEV; +} static int -nvkm_nvsw_ntfy(struct nvkm_object *base, u32 mthd, struct nvkm_event **pevent) +nvkm_nvsw_ntfy_(struct nvkm_object *base, u32 mthd, struct nvkm_event **pevent) { struct nvkm_nvsw *nvsw = nvkm_nvsw(base); switch (mthd) { @@ -46,29 +49,36 @@ nvkm_nvsw_ntfy(struct nvkm_object *base, u32 mthd, struct nvkm_event **pevent) return -EINVAL; } +static const struct nvkm_object_func +nvkm_nvsw_ = { + .mthd = nvkm_nvsw_mthd_, + .ntfy = nvkm_nvsw_ntfy_, +}; + int -nvkm_nvsw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, +nvkm_nvsw_new_(const struct nvkm_nvsw_func *func, struct nvkm_sw_chan *chan, + const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_sw_chan *chan = (void *)parent; struct nvkm_nvsw *nvsw; - int ret; - ret = nvkm_object_create(parent, engine, oclass, 0, &nvsw); + if (!(nvsw = kzalloc(sizeof(*nvsw), GFP_KERNEL))) + return -ENOMEM; *pobject = &nvsw->object; - if (ret) - return ret; + nvkm_object_ctor(&nvkm_nvsw_, oclass, &nvsw->object); + nvsw->func = func; nvsw->chan = chan; return 0; } -struct nvkm_ofuncs -nvkm_nvsw_ofuncs = { - .ctor = nvkm_nvsw_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, - .ntfy = nvkm_nvsw_ntfy, +static const struct nvkm_nvsw_func +nvkm_nvsw = { }; + +int +nvkm_nvsw_new(struct nvkm_sw_chan *chan, const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) +{ + return nvkm_nvsw_new_(&nvkm_nvsw, chan, oclass, data, size, pobject); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h index c54a12798e847..943ef4c10091c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.h @@ -1,10 +1,21 @@ #ifndef __NVKM_NVSW_H__ #define __NVKM_NVSW_H__ +#define nvkm_nvsw(p) container_of((p), struct nvkm_nvsw, object) #include "priv.h" -extern struct nvkm_ofuncs nvkm_nvsw_ofuncs; -int -nvkm_nvsw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject); +struct nvkm_nvsw { + struct nvkm_object object; + const struct nvkm_nvsw_func *func; + struct nvkm_sw_chan *chan; +}; + +struct nvkm_nvsw_func { + int (*mthd)(struct nvkm_nvsw *, u32 mthd, void *data, u32 size); +}; + +int nvkm_nvsw_new_(const struct nvkm_nvsw_func *, struct nvkm_sw_chan *, + const struct nvkm_oclass *, void *data, u32 size, + struct nvkm_object **pobject); +int nvkm_nvsw_new(struct nvkm_sw_chan *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **pobject); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h index 42707355eb92c..ae610a32ef5ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h @@ -1,5 +1,18 @@ #ifndef __NVKM_SW_PRIV_H__ #define __NVKM_SW_PRIV_H__ +#define nvkm_sw(p) container_of((p), struct nvkm_sw, engine) #include +struct nvkm_sw_chan; +struct nvkm_sw_chan_sclass { + int (*ctor)(struct nvkm_sw_chan *, const struct nvkm_oclass *, + void *data, u32 size, struct nvkm_object **); + struct nvkm_sclass base; +}; + +struct nvkm_sw_func { + int (*chan_new)(struct nvkm_sw *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + const struct nvkm_sw_chan_sclass sclass[]; +}; #endif -- GitLab From ef8bc5760b51d69741ed5f42224f1fdd2935541a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:19 +1000 Subject: [PATCH 5528/7006] drm/nouveau/core: kill some (now) dead code Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/engctx.h | 48 ----- .../drm/nouveau/include/nvkm/core/parent.h | 51 ------ drivers/gpu/drm/nouveau/nvkm/core/Kbuild | 2 - drivers/gpu/drm/nouveau/nvkm/core/engctx.c | 166 ------------------ drivers/gpu/drm/nouveau/nvkm/core/handle.c | 22 +-- drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 120 ------------- drivers/gpu/drm/nouveau/nvkm/core/parent.c | 139 --------------- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 1 - .../gpu/drm/nouveau/nvkm/engine/device/user.c | 46 ----- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 81 --------- 10 files changed, 1 insertion(+), 675 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/parent.h delete mode 100644 drivers/gpu/drm/nouveau/nvkm/core/engctx.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/core/parent.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h deleted file mode 100644 index 4a77fdaa8b90c..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __NVKM_ENGCTX_H__ -#define __NVKM_ENGCTX_H__ -#include -#include - -#include - -#define NV_ENGCTX_(eng,var) (((var) << 8) | (eng)) -#define NV_ENGCTX(name,var) NV_ENGCTX_(NVDEV_ENGINE_##name, (var)) - -struct nvkm_engctx { - struct nvkm_gpuobj gpuobj; - struct nvkm_vma vma; - struct list_head head; - unsigned long save; - u64 addr; -}; - -static inline struct nvkm_engctx * -nv_engctx(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_ENGCTX_CLASS)); -#endif - return obj; -} - -#define nvkm_engctx_create(p,e,c,g,s,a,f,d) \ - nvkm_engctx_create_((p), (e), (c), (g), (s), (a), (f), \ - sizeof(**d), (void **)d) - -int nvkm_engctx_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, struct nvkm_object *, - u32 size, u32 align, u32 flags, - int length, void **data); -void nvkm_engctx_destroy(struct nvkm_engctx *); -int nvkm_engctx_init(struct nvkm_engctx *); -int nvkm_engctx_fini(struct nvkm_engctx *, bool suspend); - -int _nvkm_engctx_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_engctx_dtor(struct nvkm_object *); -int _nvkm_engctx_init(struct nvkm_object *); -int _nvkm_engctx_fini(struct nvkm_object *, bool suspend); -#define _nvkm_engctx_rd32 _nvkm_gpuobj_rd32 -#define _nvkm_engctx_wr32 _nvkm_gpuobj_wr32 -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h deleted file mode 100644 index 92270afc666a2..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __NVKM_PARENT_H__ -#define __NVKM_PARENT_H__ -#include - -struct nvkm_parent { - struct nvkm_object object; - - struct nvkm_oclass *sclass; - u64 engine; - - int (*context_attach)(struct nvkm_object *, struct nvkm_object *); - int (*context_detach)(struct nvkm_object *, bool suspend, - struct nvkm_object *); - - int (*object_attach)(struct nvkm_object *parent, - struct nvkm_object *object, u32 name); - void (*object_detach)(struct nvkm_object *parent, int cookie); -}; - -static inline struct nvkm_parent * -nv_parent(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!(nv_iclass(obj, NV_PARENT_CLASS))); -#endif - return obj; -} - -#define nvkm_parent_create(p,e,c,v,s,m,d) \ - nvkm_parent_create_((p), (e), (c), (v), (s), (m), \ - sizeof(**d), (void **)d) -#define nvkm_parent_init(p) \ - _nvkm_object_init(&(p)->object) -#define nvkm_parent_fini(p,s) \ - _nvkm_object_fini(&(p)->object, (s)) - -int nvkm_parent_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32 pclass, - struct nvkm_oclass *, u64 engcls, - int size, void **); -void nvkm_parent_destroy(struct nvkm_parent *); - -void _nvkm_parent_dtor(struct nvkm_object *); -#define _nvkm_parent_init _nvkm_object_init -#define _nvkm_parent_fini _nvkm_object_fini - -int nvkm_parent_sclass(struct nvkm_object *, s32 handle, - struct nvkm_object **pengine, - struct nvkm_oclass **poclass); -int nvkm_parent_lclass(struct nvkm_object *, void *, int); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index d3932d59ff092..09044cf0d9ff3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -1,5 +1,4 @@ nvkm-y := nvkm/core/client.o -nvkm-y += nvkm/core/engctx.o nvkm-y += nvkm/core/engine.o nvkm-y += nvkm/core/enum.o nvkm-y += nvkm/core/event.o @@ -12,6 +11,5 @@ nvkm-y += nvkm/core/notify.o nvkm-y += nvkm/core/object.o nvkm-y += nvkm/core/oproxy.o nvkm-y += nvkm/core/option.o -nvkm-y += nvkm/core/parent.o nvkm-y += nvkm/core/ramht.o nvkm-y += nvkm/core/subdev.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c deleted file mode 100644 index bd13facc53d81..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include -#include -#include - -static inline int -nvkm_engctx_exists(struct nvkm_object *parent, - struct nvkm_engine *engine, void **pobject) -{ - struct nvkm_engctx *engctx; - struct nvkm_object *parctx; - - list_for_each_entry(engctx, &engine->contexts, head) { - parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS); - if (parctx == parent) { - atomic_inc(&nv_object(engctx)->refcount); - *pobject = engctx; - return 1; - } - } - - return 0; -} - -int -nvkm_engctx_create_(struct nvkm_object *parent, struct nvkm_object *engobj, - struct nvkm_oclass *oclass, struct nvkm_object *pargpu, - u32 size, u32 align, u32 flags, int length, void **pobject) -{ - struct nvkm_client *client = nvkm_client(parent); - struct nvkm_engine *engine = nv_engine(engobj); - struct nvkm_object *engctx; - unsigned long save; - int ret; - - /* check if this engine already has a context for the parent object, - * and reference it instead of creating a new one - */ - spin_lock_irqsave(&engine->lock, save); - ret = nvkm_engctx_exists(parent, engine, pobject); - spin_unlock_irqrestore(&engine->lock, save); - if (ret) - return ret; - - /* create the new context, supports creating both raw objects and - * objects backed by instance memory - */ - if (size) { - ret = nvkm_gpuobj_create_(parent, engobj, oclass, - NV_ENGCTX_CLASS, pargpu, size, - align, flags, length, pobject); - } else { - ret = nvkm_object_create_(parent, engobj, oclass, - NV_ENGCTX_CLASS, length, pobject); - } - - engctx = *pobject; - if (ret) - return ret; - - /* must take the lock again and re-check a context doesn't already - * exist (in case of a race) - the lock had to be dropped before as - * it's not possible to allocate the object with it held. - */ - spin_lock_irqsave(&engine->lock, save); - ret = nvkm_engctx_exists(parent, engine, pobject); - if (ret) { - spin_unlock_irqrestore(&engine->lock, save); - nvkm_object_ref(NULL, &engctx); - return ret; - } - - if (client->vm) - atomic_inc(&client->vm->engref[nv_engidx(engine)]); - list_add(&nv_engctx(engctx)->head, &engine->contexts); - nv_engctx(engctx)->addr = ~0ULL; - spin_unlock_irqrestore(&engine->lock, save); - return 0; -} - -void -nvkm_engctx_destroy(struct nvkm_engctx *engctx) -{ - struct nvkm_engine *engine = engctx->gpuobj.object.engine; - struct nvkm_client *client = nvkm_client(&engctx->gpuobj.object); - unsigned long save; - - nvkm_gpuobj_unmap(&engctx->vma); - spin_lock_irqsave(&engine->lock, save); - list_del(&engctx->head); - spin_unlock_irqrestore(&engine->lock, save); - - if (client->vm) - atomic_dec(&client->vm->engref[nv_engidx(engine)]); - - if (engctx->gpuobj.size) - nvkm_gpuobj_destroy(&engctx->gpuobj); - else - nvkm_object_destroy(&engctx->gpuobj.object); -} - -int -nvkm_engctx_init(struct nvkm_engctx *engctx) -{ - return nvkm_gpuobj_init(&engctx->gpuobj); -} - -int -nvkm_engctx_fini(struct nvkm_engctx *engctx, bool suspend) -{ - return nvkm_gpuobj_fini(&engctx->gpuobj, suspend); -} - -int -_nvkm_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_engctx *engctx; - int ret; - - ret = nvkm_engctx_create(parent, engine, oclass, NULL, 256, 256, - NVOBJ_FLAG_ZERO_ALLOC, &engctx); - *pobject = nv_object(engctx); - return ret; -} - -void -_nvkm_engctx_dtor(struct nvkm_object *object) -{ - nvkm_engctx_destroy(nv_engctx(object)); -} - -int -_nvkm_engctx_init(struct nvkm_object *object) -{ - return nvkm_engctx_init(nv_engctx(object)); -} - -int -_nvkm_engctx_fini(struct nvkm_object *object, bool suspend) -{ - return nvkm_engctx_fini(nv_engctx(object), suspend); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c index a74ee1c29f8cb..d185cae0fbba3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c @@ -23,7 +23,6 @@ */ #include #include -#include #define hprintk(h,l,f,a...) do { \ struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \ @@ -99,7 +98,6 @@ nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, struct nvkm_object *object, struct nvkm_handle **phandle) { struct nvkm_handle *handle; - int ret; handle = kzalloc(sizeof(*handle), GFP_KERNEL); if (!handle) @@ -113,21 +111,8 @@ nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, handle->parent = parent; nvkm_object_ref(object, &handle->object); - if (parent) { - if (nv_iclass(parent->object, NV_PARENT_CLASS) && - nv_parent(parent->object)->object_attach) { - ret = nv_parent(parent->object)-> - object_attach(parent->object, object, _handle); - if (ret < 0) { - nvkm_handle_destroy(handle); - return ret; - } - - handle->priv = ret; - } - + if (parent) list_add(&handle->head, &handle->parent->tree); - } hprintk(handle, TRACE, "created\n"); *phandle = handle; @@ -148,11 +133,6 @@ nvkm_handle_destroy(struct nvkm_handle *handle) nvkm_client_remove(client, handle); list_del(&handle->head); - if (handle->priv != ~0) { - struct nvkm_object *parent = handle->parent->object; - nv_parent(parent)->object_detach(parent, handle->priv); - } - hprintk(handle, TRACE, "destroy completed\n"); nvkm_object_ref(NULL, &handle->object); kfree(handle); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index 28f9fa289e809..d9bb0394d83ff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -25,7 +25,6 @@ #include #include #include -#include #include #include @@ -65,17 +64,6 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) if (size != args->v0.count * sizeof(args->v0.oclass[0])) return -EINVAL; - if (object->oclass) { - if (nv_iclass(object, NV_PARENT_CLASS)) { - ret = nvkm_parent_lclass(object, - args->v0.oclass, - args->v0.count); - } - - args->v0.count = ret; - return 0; - } - while (object->func->sclass && object->func->sclass(object, i, &oclass) >= 0) { if (i < args->v0.count) { @@ -92,111 +80,6 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) return ret; } -static int -nvkm_ioctl_new_old(struct nvkm_handle *handle, void *data, u32 size) -{ - union { - struct nvif_ioctl_new_v0 v0; - } *args = data; - struct nvkm_client *client = nvkm_client(handle->object); - struct nvkm_object *engctx = NULL; - struct nvkm_object *object = NULL; - struct nvkm_parent *parent; - struct nvkm_engine *engine; - struct nvkm_oclass *oclass; - u32 _handle, _oclass; - int ret; - - nvif_ioctl(handle->object, "new size %d\n", size); - if (nvif_unpack(args->v0, 0, 0, true)) { - _handle = args->v0.handle; - _oclass = args->v0.oclass; - } else - return ret; - - nvif_ioctl(handle->object, "new vers %d handle %08x class %08x " - "route %02x token %llx object %016llx\n", - args->v0.version, _handle, _oclass, - args->v0.route, args->v0.token, args->v0.object); - - if (!nv_iclass(handle->object, NV_PARENT_CLASS)) { - nvif_debug(handle->object, "cannot have children (ctor)\n"); - ret = -ENODEV; - goto fail_class; - } - - parent = nv_parent(handle->object); - - /* check that parent supports the requested subclass */ - ret = nvkm_parent_sclass(&parent->object, _oclass, - (struct nvkm_object **)&engine, &oclass); - if (ret) { - nvif_debug(&parent->object, "illegal class 0x%04x\n", _oclass); - goto fail_class; - } - - /* make sure engine init has been completed *before* any objects - * it controls are created - the constructors may depend on - * state calculated at init (ie. default context construction) - */ - if (engine) { - engine = nvkm_engine_ref(engine); - if (IS_ERR(engine)) { - ret = PTR_ERR(engine); - engine = NULL; - goto fail_class; - } - } - - /* if engine requires it, create a context object to insert - * between the parent and its children (eg. PGRAPH context) - */ - if (engine && engine->cclass) { - ret = nvkm_object_old(&parent->object, &engine->subdev.object, - engine->cclass, data, size, &engctx); - if (ret) - goto fail_engctx; - } else { - nvkm_object_ref(&parent->object, &engctx); - } - - /* finally, create new object and bind it to its handle */ - ret = nvkm_object_old(engctx, &engine->subdev.object, oclass, - data, size, &object); - if (ret) - goto fail_ctor; - - object->handle = _handle; - - ret = nvkm_object_inc(object); - if (ret) - goto fail_init; - - ret = nvkm_handle_create(handle, _handle, object, &handle); - if (ret) - goto fail_handle; - - ret = nvkm_handle_init(handle); - handle->route = args->v0.route; - handle->token = args->v0.token; - if (ret) - nvkm_handle_destroy(handle); - - handle->handle = args->v0.object; - nvkm_client_insert(client, handle); - client->data = object; -fail_handle: - nvkm_object_dec(object, false); -fail_init: - nvkm_object_ref(NULL, &object); -fail_ctor: - nvkm_object_ref(NULL, &engctx); -fail_engctx: - nvkm_engine_unref(&engine); -fail_class: - return ret; -} - static int nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) { @@ -209,9 +92,6 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) struct nvkm_oclass oclass; int ret, i = 0; - if (parent->oclass) - return nvkm_ioctl_new_old(handle, data, size); - nvif_ioctl(parent, "new size %d\n", size); if (nvif_unpack(args->v0, 0, 0, true)) { nvif_ioctl(parent, "new vers %d handle %08x class %08x " diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c deleted file mode 100644 index aecf5b8901b29..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/core/parent.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include -#include -#include - -#include - -int -nvkm_parent_sclass(struct nvkm_object *parent, s32 handle, - struct nvkm_object **pengine, - struct nvkm_oclass **poclass) -{ - struct nvkm_oclass *sclass, *oclass; - struct nvkm_engine *engine; - u64 mask; - int i; - - sclass = nv_parent(parent)->sclass; - while ((oclass = sclass++) && oclass->ofuncs) { - if (oclass->handle == handle) { - *pengine = &parent->engine->subdev.object; - *poclass = oclass; - return 0; - } - } - - mask = nv_parent(parent)->engine; - while (i = __ffs64(mask), mask) { - engine = nvkm_engine(parent, i); - if (engine) { - oclass = engine->sclass; - while (oclass->ofuncs) { - if (oclass->handle == handle) { - *pengine = nv_object(engine); - *poclass = oclass; - return 0; - } - oclass++; - } - } - - mask &= ~(1ULL << i); - } - - return -EINVAL; -} - -int -nvkm_parent_lclass(struct nvkm_object *parent, void *data, int size) -{ - struct nvif_ioctl_sclass_oclass_v0 *lclass = data; - struct nvkm_oclass *sclass, *oclass; - struct nvkm_engine *engine; - int nr = -1, i; - u64 mask; - - sclass = nv_parent(parent)->sclass; - while ((oclass = sclass++) && oclass->ofuncs) { - if (++nr < size) { - lclass[nr].oclass = oclass->handle; - lclass[nr].minver = -2; - lclass[nr].maxver = -2; - } - } - - mask = nv_parent(parent)->engine; - while (i = __ffs64(mask), mask) { - engine = nvkm_engine(parent, i); - if (engine && (oclass = engine->sclass)) { - while (oclass->ofuncs) { - if (++nr < size) { - lclass[nr].oclass = oclass->handle; - lclass[nr].minver = -2; - lclass[nr].maxver = -2; - } - oclass++; - } - } - - mask &= ~(1ULL << i); - } - - return nr + 1; -} - -int -nvkm_parent_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 pclass, - struct nvkm_oclass *sclass, u64 engcls, - int size, void **pobject) -{ - struct nvkm_parent *object; - int ret; - - ret = nvkm_object_create_(parent, engine, oclass, pclass | - NV_PARENT_CLASS, size, pobject); - object = *pobject; - if (ret) - return ret; - - object->sclass = sclass; - object->engine = engcls; - return 0; -} - -void -nvkm_parent_destroy(struct nvkm_parent *parent) -{ - nvkm_object_destroy(&parent->object); -} - - -void -_nvkm_parent_dtor(struct nvkm_object *object) -{ - nvkm_parent_destroy(nv_parent(object)); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 73770fb4da975..46d616c7259d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1977,7 +1977,6 @@ nv12b_chipset = { // .sw = gf100_sw_new, }; -#include #include struct nvkm_device * diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index 39f31e2e281bf..c5da091c058ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -26,7 +26,6 @@ #include "ctrl.h" #include -#include #include #include #include @@ -247,31 +246,6 @@ done: return ret; } -static int -nvkm_udevice_child_old(const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_object *parent = oclass->parent; - struct nvkm_engine *engine = oclass->engine; - struct nvkm_oclass *eclass = (void *)oclass->priv; - struct nvkm_object *engctx = NULL; - int ret; - - if (engine->cclass) { - ret = nvkm_object_old(parent, &engine->subdev.object, - engine->cclass, NULL, 0, &engctx); - if (ret) - return ret; - } else { - nvkm_object_ref(parent, &engctx); - } - - ret = nvkm_object_old(engctx, &engine->subdev.object, eclass, - data, size, pobject); - nvkm_object_ref(NULL, &engctx); - return ret; -} - static int nvkm_udevice_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) @@ -296,26 +270,6 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, int i; for (; i = __ffs64(mask), mask && !sclass; mask &= ~(1ULL << i)) { - if ((engine = nvkm_device_engine(device, i)) && - !engine->func) { - struct nvkm_oclass *sclass = engine->sclass; - int c = 0; - while (sclass && sclass->ofuncs) { - if (c++ == index) { - oclass->base.oclass = sclass->handle; - oclass->base.minver = -2; - oclass->base.maxver = -2; - oclass->ctor = nvkm_udevice_child_old; - oclass->priv = sclass; - oclass->engine = engine; - return 0; - } - sclass++; - } - index -= c; - continue; - } - if (!(engine = nvkm_device_engine(device, i)) || !(engine->func->base.sclass)) continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index 2735c2df22183..a02c60f340c0a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -128,67 +128,6 @@ nvkm_fifo_chan_child_func = { .fini[0] = nvkm_fifo_chan_child_fini, }; -static int -nvkm_fifo_chan_child_old(const struct nvkm_oclass *oclass, - void *data, u32 size, struct nvkm_object **pobject) -{ - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(oclass->parent); - struct nvkm_object *parent = &chan->object; - struct nvkm_engine *engine = oclass->engine; - struct nvkm_oclass *eclass = (void *)oclass->priv; - struct nvkm_object *engctx = NULL; - struct nvkm_fifo_chan_object *object; - struct nvkm_fifo_engn *engn = &chan->engn[engine->subdev.index]; - int ret; - - if (!(object = kzalloc(sizeof(*object), GFP_KERNEL))) - return -ENOMEM; - nvkm_oproxy_ctor(&nvkm_fifo_chan_child_func, oclass, &object->oproxy); - *pobject = &object->oproxy.base; - object->chan = chan; - - if (!engn->refcount++) { - if (chan->vm) - atomic_inc(&chan->vm->engref[engine->subdev.index]); - if (engine->cclass && !engn->object) { - ret = nvkm_object_old(parent, &engine->subdev.object, - engine->cclass, NULL, 0, - &engn->object); - if (ret) { - nvkm_engine_unref(&engine); - return ret; - } - } else { - nvkm_object_ref(parent, &engn->object); - } - - if (chan->func->engine_ctor) { - ret = chan->func->engine_ctor(chan, engine, - engn->object); - if (ret) - return ret; - } - } - nvkm_object_ref(engn->object, &engctx); - - ret = nvkm_object_old(engctx, &engine->subdev.object, eclass, - data, size, &object->oproxy.object); - nvkm_object_ref(NULL, &engctx); - if (ret) - return ret; - - object->oproxy.object->handle = oclass->handle; - - if (chan->func->object_ctor) { - object->hash = - chan->func->object_ctor(chan, object->oproxy.object); - if (object->hash < 0) - return object->hash; - } - - return 0; -} - static int nvkm_fifo_chan_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) @@ -269,26 +208,6 @@ nvkm_fifo_chan_child_get(struct nvkm_object *object, int index, int ret, i, c; for (; c = 0, i = __ffs64(mask), mask; mask &= ~(1ULL << i)) { - if ((engine = nvkm_device_engine(device, i)) && - !engine->func) { - struct nvkm_oclass *sclass = engine->sclass; - int c = 0; - while (sclass && sclass->ofuncs) { - if (c++ == index) { - oclass->base.oclass = sclass->handle; - oclass->base.minver = -2; - oclass->base.maxver = -2; - oclass->ctor = nvkm_fifo_chan_child_old; - oclass->priv = sclass; - oclass->engine = engine; - return 0; - } - sclass++; - } - index -= c; - continue; - } - if (!(engine = nvkm_device_engine(device, i))) continue; oclass->engine = engine; -- GitLab From 3293228174e4d44cca56d809cc8409c3f88f8b90 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5529/7006] drm/nouveau/bar: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../gpu/drm/nouveau/include/nvkm/subdev/bar.h | 22 +-- drivers/gpu/drm/nouveau/nouveau_bo.c | 9 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 70 ++++---- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 - .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/bar/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/bar/base.c | 58 ++++-- drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c | 56 ++++++ .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 143 +++++++-------- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.h | 23 +++ .../gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c | 40 ++--- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 165 +++++++----------- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.h | 26 +++ .../gpu/drm/nouveau/nvkm/subdev/bar/priv.h | 30 ++-- .../drm/nouveau/nvkm/subdev/instmem/base.c | 4 +- .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 2 +- 23 files changed, 354 insertions(+), 342 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 14da7ad79c179..b36d48e09833c 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -53,7 +53,7 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_bios(a) nvkm_bios(nvxx_device(a)) #define nvxx_fb(a) nvkm_fb(nvxx_device(a)) #define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) -#define nvxx_bar(a) nvkm_bar(nvxx_device(a)) +#define nvxx_bar(a) nvxx_device(a)->bar #define nvxx_gpio(a) nvkm_gpio(nvxx_device(a)) #define nvxx_clk(a) nvkm_clk(nvxx_device(a)) #define nvxx_i2c(a) nvkm_i2c(nvxx_device(a)) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h index 1eaf7de79d507..d3071b5a4f982 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h @@ -1,28 +1,24 @@ #ifndef __NVKM_BAR_H__ #define __NVKM_BAR_H__ #include -struct nvkm_mem; struct nvkm_vma; struct nvkm_bar { + const struct nvkm_bar_func *func; struct nvkm_subdev subdev; - struct nvkm_vm *(*kmap)(struct nvkm_bar *); - int (*umap)(struct nvkm_bar *, u64 size, int type, struct nvkm_vma *); - void (*unmap)(struct nvkm_bar *, struct nvkm_vma *); - void (*flush)(struct nvkm_bar *); + spinlock_t lock; /* whether the BAR supports to be ioremapped WC or should be uncached */ bool iomap_uncached; }; -static inline struct nvkm_bar * -nvkm_bar(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_BAR); -} +void nvkm_bar_flush(struct nvkm_bar *); +struct nvkm_vm *nvkm_bar_kmap(struct nvkm_bar *); +int nvkm_bar_umap(struct nvkm_bar *, u64 size, int type, struct nvkm_vma *); -extern struct nvkm_oclass nv50_bar_oclass; -extern struct nvkm_oclass gf100_bar_oclass; -extern struct nvkm_oclass gk20a_bar_oclass; +int nv50_bar_new(struct nvkm_device *, int, struct nvkm_bar **); +int g84_bar_new(struct nvkm_device *, int, struct nvkm_bar **); +int gf100_bar_new(struct nvkm_device *, int, struct nvkm_bar **); +int gk20a_bar_new(struct nvkm_device *, int, struct nvkm_bar **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 982c0ed163ebd..79d2ba167fbae 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1392,8 +1392,8 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) if (drm->device.info.family >= NV_DEVICE_INFO_V0_FERMI) page_shift = node->page_shift; - ret = bar->umap(bar, node->size << 12, page_shift, - &node->bar_vma); + ret = nvkm_bar_umap(bar, node->size << 12, page_shift, + &node->bar_vma); if (ret) return ret; @@ -1410,14 +1410,13 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) static void nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { - struct nouveau_drm *drm = nouveau_bdev(bdev); - struct nvkm_bar *bar = nvxx_bar(&drm->device); struct nvkm_mem *node = mem->mm_node; if (!node->bar_vma.node) return; - bar->unmap(bar, &node->bar_vma); + nvkm_vm_unmap(&node->bar_vma); + nvkm_vm_put(&node->bar_vma); } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 46d616c7259d0..24609108cb901 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -778,7 +778,7 @@ nv4e_chipset = { static const struct nvkm_device_chip nv50_chipset = { .name = "G80", -// .bar = nv50_bar_new, + .bar = nv50_bar_new, // .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = nv50_clk_new, @@ -881,7 +881,7 @@ nv68_chipset = { static const struct nvkm_device_chip nv84_chipset = { .name = "G84", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = g84_clk_new, @@ -912,7 +912,7 @@ nv84_chipset = { static const struct nvkm_device_chip nv86_chipset = { .name = "G86", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = g84_clk_new, @@ -943,7 +943,7 @@ nv86_chipset = { static const struct nvkm_device_chip nv92_chipset = { .name = "G92", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = g84_clk_new, @@ -974,7 +974,7 @@ nv92_chipset = { static const struct nvkm_device_chip nv94_chipset = { .name = "G94", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = g84_clk_new, @@ -1019,7 +1019,7 @@ nv96_chipset = { // .fb = g84_fb_new, // .imem = nv50_instmem_new, // .mmu = nv50_mmu_new, -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .volt = nv40_volt_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -1050,7 +1050,7 @@ nv98_chipset = { // .fb = g84_fb_new, // .imem = nv50_instmem_new, // .mmu = nv50_mmu_new, -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .volt = nv40_volt_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -1067,7 +1067,7 @@ nv98_chipset = { static const struct nvkm_device_chip nva0_chipset = { .name = "GT200", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = g84_clk_new, @@ -1098,7 +1098,7 @@ nva0_chipset = { static const struct nvkm_device_chip nva3_chipset = { .name = "GT215", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, @@ -1131,7 +1131,7 @@ nva3_chipset = { static const struct nvkm_device_chip nva5_chipset = { .name = "GT216", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, @@ -1163,7 +1163,7 @@ nva5_chipset = { static const struct nvkm_device_chip nva8_chipset = { .name = "GT218", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, @@ -1195,7 +1195,7 @@ nva8_chipset = { static const struct nvkm_device_chip nvaa_chipset = { .name = "MCP77/MCP78", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = mcp77_clk_new, @@ -1226,7 +1226,7 @@ nvaa_chipset = { static const struct nvkm_device_chip nvac_chipset = { .name = "MCP79/MCP7A", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = mcp77_clk_new, @@ -1257,7 +1257,7 @@ nvac_chipset = { static const struct nvkm_device_chip nvaf_chipset = { .name = "MCP89", -// .bar = nv50_bar_new, + .bar = g84_bar_new, // .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, @@ -1289,7 +1289,7 @@ nvaf_chipset = { static const struct nvkm_device_chip nvc0_chipset = { .name = "GF100", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1324,7 +1324,7 @@ nvc0_chipset = { static const struct nvkm_device_chip nvc1_chipset = { .name = "GF108", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1358,7 +1358,7 @@ nvc1_chipset = { static const struct nvkm_device_chip nvc3_chipset = { .name = "GF106", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1392,7 +1392,7 @@ nvc3_chipset = { static const struct nvkm_device_chip nvc4_chipset = { .name = "GF104", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1427,7 +1427,7 @@ nvc4_chipset = { static const struct nvkm_device_chip nvc8_chipset = { .name = "GF110", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1462,7 +1462,7 @@ nvc8_chipset = { static const struct nvkm_device_chip nvce_chipset = { .name = "GF114", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1497,7 +1497,7 @@ nvce_chipset = { static const struct nvkm_device_chip nvcf_chipset = { .name = "GF116", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1531,7 +1531,7 @@ nvcf_chipset = { static const struct nvkm_device_chip nvd7_chipset = { .name = "GF117", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1563,7 +1563,7 @@ nvd7_chipset = { static const struct nvkm_device_chip nvd9_chipset = { .name = "GF119", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, @@ -1597,7 +1597,7 @@ nvd9_chipset = { static const struct nvkm_device_chip nve4_chipset = { .name = "GK104", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1633,7 +1633,7 @@ nve4_chipset = { static const struct nvkm_device_chip nve6_chipset = { .name = "GK106", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1669,7 +1669,7 @@ nve6_chipset = { static const struct nvkm_device_chip nve7_chipset = { .name = "GK107", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1705,7 +1705,7 @@ nve7_chipset = { static const struct nvkm_device_chip nvea_chipset = { .name = "GK20A", -// .bar = gk20a_bar_new, + .bar = gk20a_bar_new, // .bus = gf100_bus_new, // .clk = gk20a_clk_new, // .fb = gk20a_fb_new, @@ -1729,7 +1729,7 @@ nvea_chipset = { static const struct nvkm_device_chip nvf0_chipset = { .name = "GK110", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1765,7 +1765,7 @@ nvf0_chipset = { static const struct nvkm_device_chip nvf1_chipset = { .name = "GK110B", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1801,7 +1801,7 @@ nvf1_chipset = { static const struct nvkm_device_chip nv106_chipset = { .name = "GK208B", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1836,7 +1836,7 @@ nv106_chipset = { static const struct nvkm_device_chip nv108_chipset = { .name = "GK208", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1871,7 +1871,7 @@ nv108_chipset = { static const struct nvkm_device_chip nv117_chipset = { .name = "GM107", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, @@ -1901,7 +1901,7 @@ nv117_chipset = { static const struct nvkm_device_chip nv124_chipset = { .name = "GM204", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .devinit = gm204_devinit_new, @@ -1930,7 +1930,7 @@ nv124_chipset = { static const struct nvkm_device_chip nv126_chipset = { .name = "GM206", -// .bar = gf100_bar_new, + .bar = gf100_bar_new, // .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .devinit = gm204_devinit_new, @@ -1959,7 +1959,7 @@ nv126_chipset = { static const struct nvkm_device_chip nv12b_chipset = { .name = "GM20B", -// .bar = gk20a_bar_new, + .bar = gk20a_bar_new, // .bus = gf100_bus_new, // .fb = gk20a_fb_new, // .fuse = gm107_fuse_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index cc152e78d0b22..cb3fe0361c266 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -44,7 +44,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -76,7 +75,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -108,7 +106,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -139,7 +136,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -171,7 +167,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -202,7 +197,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -233,7 +227,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -265,7 +258,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -296,7 +288,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 8811a40e87272..b251b05889c67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -44,7 +44,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -77,7 +76,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -110,7 +108,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -137,7 +134,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -164,7 +160,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -197,7 +192,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -230,7 +224,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -262,7 +255,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 41bfec2dd63aa..95dec0c1134cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -44,7 +44,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -87,7 +86,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -127,7 +125,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -158,7 +155,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 56a443a1c74eb..ee72cd41345cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -42,7 +42,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; @@ -67,7 +66,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -95,7 +93,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -123,7 +120,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -151,7 +147,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -179,7 +174,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -207,7 +201,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -235,7 +228,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -263,7 +255,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -291,7 +282,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -319,7 +309,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -349,7 +338,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -378,7 +366,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -407,7 +394,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FB ] = mcp89_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index bdad44e84b920..e8598fc447962 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -632,7 +632,7 @@ gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = bar->umap(bar, 128 * 0x1000, 12, &fifo->user.bar); + ret = nvkm_bar_umap(bar, 128 * 0x1000, 12, &fifo->user.bar); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index e7f4679971942..a69f61f3ecac1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -755,7 +755,7 @@ gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = bar->umap(bar, impl->channels * 0x200, 12, &fifo->user.bar); + ret = nvkm_bar_umap(bar, impl->channels * 0x200, 12, &fifo->user.bar); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 8920f367c1f8e..4ca6b88e9a7f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -41,11 +41,10 @@ gf100_sw_chan_vblsem_release(struct nvkm_notify *notify) container_of(notify, typeof(*chan), vblank.notify[notify->index]); struct nvkm_sw *sw = chan->base.sw; struct nvkm_device *device = sw->engine.subdev.device; - struct nvkm_bar *bar = device->bar; u32 inst = chan->base.fifo->inst->addr >> 12; nvkm_wr32(device, 0x001718, 0x80000000 | inst); - bar->flush(bar); + nvkm_bar_flush(device->bar); nvkm_wr32(device, 0x06000c, upper_32_bits(chan->vblank.offset)); nvkm_wr32(device, 0x060010, lower_32_bits(chan->vblank.offset)); nvkm_wr32(device, 0x060014, chan->vblank.value); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 451f758f5ebfd..6c93a20295a43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -42,11 +42,10 @@ nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) container_of(notify, typeof(*chan), vblank.notify[notify->index]); struct nvkm_sw *sw = chan->base.sw; struct nvkm_device *device = sw->engine.subdev.device; - struct nvkm_bar *bar = device->bar; nvkm_wr32(device, 0x001704, chan->base.fifo->inst->addr >> 12); nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma); - bar->flush(bar); + nvkm_bar_flush(device->bar); if (nv_device(sw)->chipset == 0x50) { nvkm_wr32(device, 0x001570, chan->vblank.offset); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild index 1ab554a0b5e09..1e138b3379558 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild @@ -1,4 +1,5 @@ nvkm-y += nvkm/subdev/bar/base.o nvkm-y += nvkm/subdev/bar/nv50.o +nvkm-y += nvkm/subdev/bar/g84.o nvkm-y += nvkm/subdev/bar/gf100.o nvkm-y += nvkm/subdev/bar/gk20a.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c index 8daaa65fc8cf5..a9433ad45b1e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c @@ -23,23 +23,61 @@ */ #include "priv.h" +void +nvkm_bar_flush(struct nvkm_bar *bar) +{ + if (bar && bar->func->flush) + bar->func->flush(bar); +} + +struct nvkm_vm * +nvkm_bar_kmap(struct nvkm_bar *bar) +{ + /* disallow kmap() until after vm has been bootstrapped */ + if (bar && bar->func->kmap && bar->subdev.oneinit) + return bar->func->kmap(bar); + return NULL; +} + int -nvkm_bar_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_bar_umap(struct nvkm_bar *bar, u64 size, int type, struct nvkm_vma *vma) { - return nvkm_subdev_create_(parent, engine, oclass, 0, "BARCTL", - "bar", length, pobject); + return bar->func->umap(bar, size, type, vma); } -void -nvkm_bar_destroy(struct nvkm_bar *bar) +static int +nvkm_bar_oneinit(struct nvkm_subdev *subdev) { - nvkm_subdev_destroy(&bar->subdev); + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->oneinit(bar); } +static int +nvkm_bar_init(struct nvkm_subdev *subdev) +{ + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->init(bar); +} + +static void * +nvkm_bar_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_bar *bar = nvkm_bar(subdev); + return bar->func->dtor(bar); +} + +static const struct nvkm_subdev_func +nvkm_bar = { + .dtor = nvkm_bar_dtor, + .oneinit = nvkm_bar_oneinit, + .init = nvkm_bar_init, +}; + void -_nvkm_bar_dtor(struct nvkm_object *object) +nvkm_bar_ctor(const struct nvkm_bar_func *func, struct nvkm_device *device, + int index, struct nvkm_bar *bar) { - struct nvkm_bar *bar = (void *)object; - nvkm_bar_destroy(bar); + nvkm_subdev_ctor(&nvkm_bar, device, index, 0, &bar->subdev); + bar->func = func; + spin_lock_init(&bar->lock); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c new file mode 100644 index 0000000000000..ef717136c838c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/g84.c @@ -0,0 +1,56 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv50.h" + +#include + +void +g84_bar_flush(struct nvkm_bar *bar) +{ + struct nvkm_device *device = bar->subdev.device; + unsigned long flags; + spin_lock_irqsave(&bar->lock, flags); + nvkm_wr32(device, 0x070000, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x070000) & 0x00000002)) + break; + ); + spin_unlock_irqrestore(&bar->lock, flags); +} + +static const struct nvkm_bar_func +g84_bar_func = { + .dtor = nv50_bar_dtor, + .oneinit = nv50_bar_oneinit, + .init = nv50_bar_init, + .kmap = nv50_bar_kmap, + .umap = nv50_bar_umap, + .flush = g84_bar_flush, +}; + +int +g84_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) +{ + return nv50_bar_new_(&g84_bar_func, device, index, 0x200, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 7d304ccc6a64a..03ce10fcba4f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -21,51 +21,30 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "gf100.h" #include #include #include -struct gf100_bar_vm { - struct nvkm_memory *mem; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *vm; -}; - -struct gf100_bar { - struct nvkm_bar base; - spinlock_t lock; - struct gf100_bar_vm bar[2]; -}; - static struct nvkm_vm * -gf100_bar_kmap(struct nvkm_bar *obj) +gf100_bar_kmap(struct nvkm_bar *base) { - struct gf100_bar *bar = container_of(obj, typeof(*bar), base); - return bar->bar[0].vm; + return gf100_bar(base)->bar[0].vm; } -static int -gf100_bar_umap(struct nvkm_bar *obj, u64 size, int type, struct nvkm_vma *vma) +int +gf100_bar_umap(struct nvkm_bar *base, u64 size, int type, struct nvkm_vma *vma) { - struct gf100_bar *bar = container_of(obj, typeof(*bar), base); + struct gf100_bar *bar = gf100_bar(base); return nvkm_vm_get(bar->bar[1].vm, size, type, NV_MEM_ACCESS_RW, vma); } -static void -gf100_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) -{ - nvkm_vm_unmap(vma); - nvkm_vm_put(vma); -} - - static int gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, struct lock_class_key *key, int bar_nr) { - struct nvkm_device *device = nv_device(&bar->base); + struct nvkm_device *device = bar->base.subdev.device; struct nvkm_vm *vm; resource_size_t bar_len; int ret; @@ -92,8 +71,10 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, */ if (bar_nr == 3) { ret = nvkm_vm_boot(vm, bar_len); - if (ret) + if (ret) { + nvkm_vm_ref(NULL, &vm, NULL); return ret; + } } ret = nvkm_vm_ref(vm, &bar_vm->vm, bar_vm->pgd); @@ -111,28 +92,15 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, } int -gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_bar_oneinit(struct nvkm_bar *base) { static struct lock_class_key bar1_lock; static struct lock_class_key bar3_lock; - struct nvkm_device *device = nv_device(parent); - struct gf100_bar *bar; - bool has_bar3 = nv_device_resource_len(device, 3) != 0; + struct gf100_bar *bar = gf100_bar(base); int ret; - ret = nvkm_bar_create(parent, engine, oclass, &bar); - *pobject = nv_object(bar); - if (ret) - return ret; - - device->bar = &bar->base; - bar->base.flush = g84_bar_flush; - spin_lock_init(&bar->lock); - /* BAR3 */ - if (has_bar3) { + if (bar->base.func->kmap) { ret = gf100_bar_ctor_vm(bar, &bar->bar[0], &bar3_lock, 3); if (ret) return ret; @@ -143,43 +111,15 @@ gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - if (has_bar3) - bar->base.kmap = gf100_bar_kmap; - bar->base.umap = gf100_bar_umap; - bar->base.unmap = gf100_bar_unmap; return 0; } -void -gf100_bar_dtor(struct nvkm_object *object) -{ - struct gf100_bar *bar = (void *)object; - - nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); - nvkm_gpuobj_del(&bar->bar[1].pgd); - nvkm_memory_del(&bar->bar[1].mem); - - if (bar->bar[0].vm) { - nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); - nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); - } - nvkm_gpuobj_del(&bar->bar[0].pgd); - nvkm_memory_del(&bar->bar[0].mem); - - nvkm_bar_destroy(&bar->base); -} - int -gf100_bar_init(struct nvkm_object *object) +gf100_bar_init(struct nvkm_bar *base) { - struct gf100_bar *bar = (void *)object; + struct gf100_bar *bar = gf100_bar(base); struct nvkm_device *device = bar->base.subdev.device; u32 addr; - int ret; - - ret = nvkm_bar_init(&bar->base); - if (ret) - return ret; nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); @@ -195,13 +135,48 @@ gf100_bar_init(struct nvkm_object *object) return 0; } -struct nvkm_oclass -gf100_bar_oclass = { - .handle = NV_SUBDEV(BAR, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_bar_ctor, - .dtor = gf100_bar_dtor, - .init = gf100_bar_init, - .fini = _nvkm_bar_fini, - }, +void * +gf100_bar_dtor(struct nvkm_bar *base) +{ + struct gf100_bar *bar = gf100_bar(base); + + nvkm_vm_ref(NULL, &bar->bar[1].vm, bar->bar[1].pgd); + nvkm_gpuobj_del(&bar->bar[1].pgd); + nvkm_memory_del(&bar->bar[1].mem); + + if (bar->bar[0].vm) { + nvkm_memory_del(&bar->bar[0].vm->pgt[0].mem[0]); + nvkm_vm_ref(NULL, &bar->bar[0].vm, bar->bar[0].pgd); + } + nvkm_gpuobj_del(&bar->bar[0].pgd); + nvkm_memory_del(&bar->bar[0].mem); + return bar; +} + +int +gf100_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, + int index, struct nvkm_bar **pbar) +{ + struct gf100_bar *bar; + if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) + return -ENOMEM; + nvkm_bar_ctor(func, device, index, &bar->base); + *pbar = &bar->base; + return 0; +} + +static const struct nvkm_bar_func +gf100_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .init = gf100_bar_init, + .kmap = gf100_bar_kmap, + .umap = gf100_bar_umap, + .flush = g84_bar_flush, }; + +int +gf100_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) +{ + return gf100_bar_new_(&gf100_bar_func, device, index, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h new file mode 100644 index 0000000000000..f7dea69640d87 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.h @@ -0,0 +1,23 @@ +#ifndef __GF100_BAR_H__ +#define __GF100_BAR_H__ +#define gf100_bar(p) container_of((p), struct gf100_bar, base) +#include "priv.h" + +struct gf100_bar_vm { + struct nvkm_memory *mem; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *vm; +}; + +struct gf100_bar { + struct nvkm_bar base; + struct gf100_bar_vm bar[2]; +}; + +int gf100_bar_new_(const struct nvkm_bar_func *, struct nvkm_device *, + int, struct nvkm_bar **); +void *gf100_bar_dtor(struct nvkm_bar *); +int gf100_bar_oneinit(struct nvkm_bar *); +int gf100_bar_init(struct nvkm_bar *); +int gf100_bar_umap(struct nvkm_bar *, u64, int, struct nvkm_vma *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c index 148f739a276eb..9232fab4274c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c @@ -19,32 +19,22 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "priv.h" +#include "gf100.h" + +static const struct nvkm_bar_func +gk20a_bar_func = { + .dtor = gf100_bar_dtor, + .oneinit = gf100_bar_oneinit, + .init = gf100_bar_init, + .umap = gf100_bar_umap, + .flush = g84_bar_flush, +}; int -gk20a_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gk20a_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) { - struct nvkm_bar *bar; - int ret; - - ret = gf100_bar_ctor(parent, engine, oclass, data, size, pobject); - if (ret) - return ret; - - bar = (struct nvkm_bar *)*pobject; - bar->iomap_uncached = true; - return 0; + int ret = gf100_bar_new_(&gk20a_bar_func, device, index, pbar); + if (ret == 0) + (*pbar)->iomap_uncached = true; + return ret; } - -struct nvkm_oclass -gk20a_bar_oclass = { - .handle = NV_SUBDEV(BAR, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_bar_ctor, - .dtor = gf100_bar_dtor, - .init = gf100_bar_init, - .fini = _nvkm_bar_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index add132b2ed7aa..65646fb917c13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -21,100 +21,57 @@ * * Authors: Ben Skeggs */ -#include "priv.h" +#include "nv50.h" #include #include #include #include -struct nv50_bar { - struct nvkm_bar base; - spinlock_t lock; - struct nvkm_gpuobj *mem; - struct nvkm_gpuobj *pad; - struct nvkm_gpuobj *pgd; - struct nvkm_vm *bar1_vm; - struct nvkm_gpuobj *bar1; - struct nvkm_vm *bar3_vm; - struct nvkm_gpuobj *bar3; -}; - -static struct nvkm_vm * -nv50_bar_kmap(struct nvkm_bar *obj) +struct nvkm_vm * +nv50_bar_kmap(struct nvkm_bar *base) { - struct nv50_bar *bar = container_of(obj, typeof(*bar), base); - return bar->bar3_vm; + return nv50_bar(base)->bar3_vm; } -static int -nv50_bar_umap(struct nvkm_bar *obj, u64 size, int type, struct nvkm_vma *vma) +int +nv50_bar_umap(struct nvkm_bar *base, u64 size, int type, struct nvkm_vma *vma) { - struct nv50_bar *bar = container_of(obj, typeof(*bar), base); + struct nv50_bar *bar = nv50_bar(base); return nvkm_vm_get(bar->bar1_vm, size, type, NV_MEM_ACCESS_RW, vma); } static void -nv50_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma) +nv50_bar_flush(struct nvkm_bar *base) { - nvkm_vm_unmap(vma); - nvkm_vm_put(vma); -} - -static void -nv50_bar_flush(struct nvkm_bar *obj) -{ - struct nv50_bar *bar = container_of(obj, typeof(*bar), base); + struct nv50_bar *bar = nv50_bar(base); struct nvkm_device *device = bar->base.subdev.device; unsigned long flags; - spin_lock_irqsave(&bar->lock, flags); + spin_lock_irqsave(&bar->base.lock, flags); nvkm_wr32(device, 0x00330c, 0x00000001); nvkm_msec(device, 2000, if (!(nvkm_rd32(device, 0x00330c) & 0x00000002)) break; ); - spin_unlock_irqrestore(&bar->lock, flags); + spin_unlock_irqrestore(&bar->base.lock, flags); } -void -g84_bar_flush(struct nvkm_bar *obj) +int +nv50_bar_oneinit(struct nvkm_bar *base) { - struct nv50_bar *bar = container_of(obj, typeof(*bar), base); + struct nv50_bar *bar = nv50_bar(base); struct nvkm_device *device = bar->base.subdev.device; - unsigned long flags; - spin_lock_irqsave(&bar->lock, flags); - nvkm_wr32(device, 0x070000, 0x00000001); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x070000) & 0x00000002)) - break; - ); - spin_unlock_irqrestore(&bar->lock, flags); -} - -static int -nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ static struct lock_class_key bar1_lock; static struct lock_class_key bar3_lock; - struct nvkm_device *device = nv_device(parent); struct nvkm_vm *vm; - struct nv50_bar *bar; u64 start, limit; int ret; - ret = nvkm_bar_create(parent, engine, oclass, &bar); - *pobject = nv_object(bar); - if (ret) - return ret; - ret = nvkm_gpuobj_new(device, 0x20000, 0, false, NULL, &bar->mem); if (ret) return ret; - ret = nvkm_gpuobj_new(device, (device->chipset == 0x50) ? - 0x1400 : 0x200, 0, false, bar->mem, + ret = nvkm_gpuobj_new(device, bar->pgd_addr, 0, false, bar->mem, &bar->pad); if (ret) return ret; @@ -184,45 +141,15 @@ nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_wo32(bar->bar1, 0x10, 0x00000000); nvkm_wo32(bar->bar1, 0x14, 0x00000000); nvkm_done(bar->bar1); - - bar->base.kmap = nv50_bar_kmap; - bar->base.umap = nv50_bar_umap; - bar->base.unmap = nv50_bar_unmap; - if (device->chipset == 0x50) - bar->base.flush = nv50_bar_flush; - else - bar->base.flush = g84_bar_flush; - spin_lock_init(&bar->lock); return 0; } -static void -nv50_bar_dtor(struct nvkm_object *object) +int +nv50_bar_init(struct nvkm_bar *base) { - struct nv50_bar *bar = (void *)object; - nvkm_gpuobj_del(&bar->bar1); - nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd); - nvkm_gpuobj_del(&bar->bar3); - if (bar->bar3_vm) { - nvkm_memory_del(&bar->bar3_vm->pgt[0].mem[0]); - nvkm_vm_ref(NULL, &bar->bar3_vm, bar->pgd); - } - nvkm_gpuobj_del(&bar->pgd); - nvkm_gpuobj_del(&bar->pad); - nvkm_gpuobj_del(&bar->mem); - nvkm_bar_destroy(&bar->base); -} - -static int -nv50_bar_init(struct nvkm_object *object) -{ - struct nv50_bar *bar = (void *)object; + struct nv50_bar *bar = nv50_bar(base); struct nvkm_device *device = bar->base.subdev.device; - int ret, i; - - ret = nvkm_bar_init(&bar->base); - if (ret) - return ret; + int i; nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); @@ -242,20 +169,48 @@ nv50_bar_init(struct nvkm_object *object) return 0; } -static int -nv50_bar_fini(struct nvkm_object *object, bool suspend) +void * +nv50_bar_dtor(struct nvkm_bar *base) +{ + struct nv50_bar *bar = nv50_bar(base); + nvkm_gpuobj_del(&bar->bar1); + nvkm_vm_ref(NULL, &bar->bar1_vm, bar->pgd); + nvkm_gpuobj_del(&bar->bar3); + if (bar->bar3_vm) { + nvkm_memory_del(&bar->bar3_vm->pgt[0].mem[0]); + nvkm_vm_ref(NULL, &bar->bar3_vm, bar->pgd); + } + nvkm_gpuobj_del(&bar->pgd); + nvkm_gpuobj_del(&bar->pad); + nvkm_gpuobj_del(&bar->mem); + return bar; +} + +int +nv50_bar_new_(const struct nvkm_bar_func *func, struct nvkm_device *device, + int index, u32 pgd_addr, struct nvkm_bar **pbar) { - struct nv50_bar *bar = (void *)object; - return nvkm_bar_fini(&bar->base, suspend); + struct nv50_bar *bar; + if (!(bar = kzalloc(sizeof(*bar), GFP_KERNEL))) + return -ENOMEM; + nvkm_bar_ctor(func, device, index, &bar->base); + bar->pgd_addr = pgd_addr; + *pbar = &bar->base; + return 0; } -struct nvkm_oclass -nv50_bar_oclass = { - .handle = NV_SUBDEV(BAR, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_bar_ctor, - .dtor = nv50_bar_dtor, - .init = nv50_bar_init, - .fini = nv50_bar_fini, - }, +static const struct nvkm_bar_func +nv50_bar_func = { + .dtor = nv50_bar_dtor, + .oneinit = nv50_bar_oneinit, + .init = nv50_bar_init, + .kmap = nv50_bar_kmap, + .umap = nv50_bar_umap, + .flush = nv50_bar_flush, }; + +int +nv50_bar_new(struct nvkm_device *device, int index, struct nvkm_bar **pbar) +{ + return nv50_bar_new_(&nv50_bar_func, device, index, 0x1400, pbar); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h new file mode 100644 index 0000000000000..1eb764f22a499 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.h @@ -0,0 +1,26 @@ +#ifndef __NV50_BAR_H__ +#define __NV50_BAR_H__ +#define nv50_bar(p) container_of((p), struct nv50_bar, base) +#include "priv.h" + +struct nv50_bar { + struct nvkm_bar base; + u32 pgd_addr; + struct nvkm_gpuobj *mem; + struct nvkm_gpuobj *pad; + struct nvkm_gpuobj *pgd; + struct nvkm_vm *bar1_vm; + struct nvkm_gpuobj *bar1; + struct nvkm_vm *bar3_vm; + struct nvkm_gpuobj *bar3; +}; + +int nv50_bar_new_(const struct nvkm_bar_func *, struct nvkm_device *, + int, u32 pgd_addr, struct nvkm_bar **); +void *nv50_bar_dtor(struct nvkm_bar *); +int nv50_bar_oneinit(struct nvkm_bar *); +int nv50_bar_init(struct nvkm_bar *); +struct nvkm_vm *nv50_bar_kmap(struct nvkm_bar *); +int nv50_bar_umap(struct nvkm_bar *, u64, int, struct nvkm_vma *); +void nv50_bar_unmap(struct nvkm_bar *, struct nvkm_vma *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h index 3a8fbaea582d9..d834ef20db5bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h @@ -1,27 +1,19 @@ #ifndef __NVKM_BAR_PRIV_H__ #define __NVKM_BAR_PRIV_H__ +#define nvkm_bar(p) container_of((p), struct nvkm_bar, subdev) #include -#define nvkm_bar_create(p,e,o,d) \ - nvkm_bar_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_bar_init(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_bar_fini(p,s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) +void nvkm_bar_ctor(const struct nvkm_bar_func *, struct nvkm_device *, + int, struct nvkm_bar *); -int nvkm_bar_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void nvkm_bar_destroy(struct nvkm_bar *); - -void _nvkm_bar_dtor(struct nvkm_object *); -#define _nvkm_bar_init _nvkm_subdev_init -#define _nvkm_bar_fini _nvkm_subdev_fini +struct nvkm_bar_func { + void *(*dtor)(struct nvkm_bar *); + int (*oneinit)(struct nvkm_bar *); + int (*init)(struct nvkm_bar *); + struct nvkm_vm *(*kmap)(struct nvkm_bar *); + int (*umap)(struct nvkm_bar *, u64 size, int type, struct nvkm_vma *); + void (*flush)(struct nvkm_bar *); +}; void g84_bar_flush(struct nvkm_bar *); - -int gf100_bar_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_bar_dtor(struct nvkm_object *); -int gf100_bar_init(struct nvkm_object *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 2a1dab304087c..6a356f348c582 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -65,9 +65,7 @@ static void nvkm_instobj_release(struct nvkm_memory *memory) { struct nvkm_instobj *iobj = nvkm_instobj(memory); - struct nvkm_bar *bar = iobj->imem->subdev.device->bar; - if (bar && bar->flush) - bar->flush(bar); + nvkm_bar_flush(iobj->imem->subdev.device->bar); } static void __iomem * diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index 535a8f9c23ce9..af236f8e4ddc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -111,7 +111,7 @@ nv50_instobj_acquire(struct nvkm_memory *memory) struct nvkm_vm *vm; unsigned long flags; - if (!iobj->map && bar && bar->kmap && (vm = bar->kmap(bar))) + if (!iobj->map && (vm = nvkm_bar_kmap(bar))) nvkm_memory_boot(memory, vm); if (!IS_ERR_OR_NULL(iobj->map)) return iobj->map; -- GitLab From 46484438ab7dbab6ed29cf647d029e0b1ef3d9d8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5530/7006] drm/nouveau/bios: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/disp.h | 2 +- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../drm/nouveau/include/nvkm/subdev/bios.h | 8 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 137 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 7 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 5 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/bios/base.c | 60 +++----- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 16 +- .../gpu/drm/nouveau/nvkm/subdev/bios/perf.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bios/pll.c | 11 +- .../gpu/drm/nouveau/nvkm/subdev/bios/priv.h | 1 + .../gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 2 +- .../drm/nouveau/nvkm/subdev/bios/shadowacpi.c | 2 +- .../drm/nouveau/nvkm/subdev/bios/shadowof.c | 2 +- .../drm/nouveau/nvkm/subdev/bios/shadowpci.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/bios/therm.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/clk/nv04.c | 5 +- .../gpu/drm/nouveau/nvkm/subdev/clk/nv40.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c | 4 +- .../drm/nouveau/nvkm/subdev/devinit/nv04.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 9 +- .../gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c | 2 +- .../drm/nouveau/nvkm/subdev/therm/fanpwm.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/volt/base.c | 2 +- 42 files changed, 158 insertions(+), 249 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h index c910c5d5c662f..6c9a1e89810fe 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/disp.h +++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h @@ -172,7 +172,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table, struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_bios *bios = nvxx_bios(&drm->device); struct nvbios_init init = { - .subdev = nv_subdev(bios), + .subdev = &bios->subdev, .bios = bios, .offset = table, .outp = outp, diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index b36d48e09833c..15f4528ee130b 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -50,7 +50,7 @@ u64 nvif_device_time(struct nvif_device *); struct nvif_device *_device = (a); \ nv_device(_device->object.priv); \ }) -#define nvxx_bios(a) nvkm_bios(nvxx_device(a)) +#define nvxx_bios(a) nvxx_device(a)->bios #define nvxx_fb(a) nvkm_fb(nvxx_device(a)) #define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) #define nvxx_bar(a) nvxx_device(a)->bar diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h index 28600390c6b82..e39a1fea930be 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h @@ -19,12 +19,6 @@ struct nvkm_bios { } version; }; -static inline struct nvkm_bios * -nvkm_bios(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_VBIOS); -} - u8 nvbios_checksum(const u8 *data, int size); u16 nvbios_findstr(const u8 *data, int size, const char *str, int len); int nvbios_memcmp(struct nvkm_bios *, u32 addr, const char *, u32 len); @@ -33,5 +27,5 @@ int nvbios_memcmp(struct nvkm_bios *, u32 addr, const char *, u32 len); #define nvbios_rd16(b,o) get_unaligned_le16(&(b)->data[(o)]) #define nvbios_rd32(b,o) get_unaligned_le32(&(b)->data[(o)]) -extern struct nvkm_oclass nvkm_bios_oclass; +int nvkm_bios_new(struct nvkm_device *, int, struct nvkm_bios **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 24609108cb901..7ef3c14470385 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -70,13 +70,13 @@ nvkm_device_list(u64 *name, int size) static const struct nvkm_device_chip null_chipset = { .name = "NULL", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, }; static const struct nvkm_device_chip nv4_chipset = { .name = "NV04", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv04_devinit_new, @@ -96,7 +96,7 @@ nv4_chipset = { static const struct nvkm_device_chip nv5_chipset = { .name = "NV05", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv05_devinit_new, @@ -116,7 +116,7 @@ nv5_chipset = { static const struct nvkm_device_chip nv10_chipset = { .name = "NV10", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, @@ -135,7 +135,7 @@ nv10_chipset = { static const struct nvkm_device_chip nv11_chipset = { .name = "NV11", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, @@ -156,7 +156,7 @@ nv11_chipset = { static const struct nvkm_device_chip nv15_chipset = { .name = "NV15", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, @@ -177,7 +177,7 @@ nv15_chipset = { static const struct nvkm_device_chip nv17_chipset = { .name = "NV17", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, @@ -198,7 +198,7 @@ nv17_chipset = { static const struct nvkm_device_chip nv18_chipset = { .name = "NV18", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, @@ -219,7 +219,7 @@ nv18_chipset = { static const struct nvkm_device_chip nv1a_chipset = { .name = "nForce", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv1a_devinit_new, @@ -240,7 +240,7 @@ nv1a_chipset = { static const struct nvkm_device_chip nv1f_chipset = { .name = "nForce2", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv1a_devinit_new, @@ -261,7 +261,7 @@ nv1f_chipset = { static const struct nvkm_device_chip nv20_chipset = { .name = "NV20", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -282,7 +282,7 @@ nv20_chipset = { static const struct nvkm_device_chip nv25_chipset = { .name = "NV25", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -303,7 +303,7 @@ nv25_chipset = { static const struct nvkm_device_chip nv28_chipset = { .name = "NV28", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -324,7 +324,7 @@ nv28_chipset = { static const struct nvkm_device_chip nv2a_chipset = { .name = "NV2A", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -345,7 +345,7 @@ nv2a_chipset = { static const struct nvkm_device_chip nv30_chipset = { .name = "NV30", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -366,7 +366,7 @@ nv30_chipset = { static const struct nvkm_device_chip nv31_chipset = { .name = "NV31", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -388,7 +388,7 @@ nv31_chipset = { static const struct nvkm_device_chip nv34_chipset = { .name = "NV34", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, @@ -410,7 +410,7 @@ nv34_chipset = { static const struct nvkm_device_chip nv35_chipset = { .name = "NV35", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -431,7 +431,7 @@ nv35_chipset = { static const struct nvkm_device_chip nv36_chipset = { .name = "NV36", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, @@ -453,7 +453,7 @@ nv36_chipset = { static const struct nvkm_device_chip nv40_chipset = { .name = "NV40", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -478,7 +478,7 @@ nv40_chipset = { static const struct nvkm_device_chip nv41_chipset = { .name = "NV41", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -503,7 +503,7 @@ nv41_chipset = { static const struct nvkm_device_chip nv42_chipset = { .name = "NV42", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -528,7 +528,7 @@ nv42_chipset = { static const struct nvkm_device_chip nv43_chipset = { .name = "NV43", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -553,7 +553,7 @@ nv43_chipset = { static const struct nvkm_device_chip nv44_chipset = { .name = "NV44", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -578,7 +578,7 @@ nv44_chipset = { static const struct nvkm_device_chip nv45_chipset = { .name = "NV45", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -603,7 +603,7 @@ nv45_chipset = { static const struct nvkm_device_chip nv46_chipset = { .name = "G72", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -628,7 +628,7 @@ nv46_chipset = { static const struct nvkm_device_chip nv47_chipset = { .name = "G70", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -653,7 +653,7 @@ nv47_chipset = { static const struct nvkm_device_chip nv49_chipset = { .name = "G71", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -678,7 +678,7 @@ nv49_chipset = { static const struct nvkm_device_chip nv4a_chipset = { .name = "NV44A", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -703,7 +703,7 @@ nv4a_chipset = { static const struct nvkm_device_chip nv4b_chipset = { .name = "G73", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -728,7 +728,7 @@ nv4b_chipset = { static const struct nvkm_device_chip nv4c_chipset = { .name = "C61", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -753,7 +753,7 @@ nv4c_chipset = { static const struct nvkm_device_chip nv4e_chipset = { .name = "C51", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -779,7 +779,7 @@ static const struct nvkm_device_chip nv50_chipset = { .name = "G80", .bar = nv50_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = nv50_clk_new, // .devinit = nv50_devinit_new, @@ -806,7 +806,7 @@ nv50_chipset = { static const struct nvkm_device_chip nv63_chipset = { .name = "C73", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -831,7 +831,7 @@ nv63_chipset = { static const struct nvkm_device_chip nv67_chipset = { .name = "C67", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -856,7 +856,7 @@ nv67_chipset = { static const struct nvkm_device_chip nv68_chipset = { .name = "C68", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, @@ -882,7 +882,7 @@ static const struct nvkm_device_chip nv84_chipset = { .name = "G84", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, @@ -913,7 +913,7 @@ static const struct nvkm_device_chip nv86_chipset = { .name = "G86", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, @@ -944,7 +944,7 @@ static const struct nvkm_device_chip nv92_chipset = { .name = "G92", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = nv50_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, @@ -975,7 +975,7 @@ static const struct nvkm_device_chip nv94_chipset = { .name = "G94", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, @@ -1005,7 +1005,7 @@ nv94_chipset = { static const struct nvkm_device_chip nv96_chipset = { .name = "G96", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .fuse = nv50_fuse_new, @@ -1036,7 +1036,7 @@ nv96_chipset = { static const struct nvkm_device_chip nv98_chipset = { .name = "G98", -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .fuse = nv50_fuse_new, @@ -1068,7 +1068,7 @@ static const struct nvkm_device_chip nva0_chipset = { .name = "GT200", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, @@ -1099,7 +1099,7 @@ static const struct nvkm_device_chip nva3_chipset = { .name = "GT215", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = gt215_devinit_new, @@ -1132,7 +1132,7 @@ static const struct nvkm_device_chip nva5_chipset = { .name = "GT216", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = gt215_devinit_new, @@ -1164,7 +1164,7 @@ static const struct nvkm_device_chip nva8_chipset = { .name = "GT218", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = gt215_devinit_new, @@ -1196,7 +1196,7 @@ static const struct nvkm_device_chip nvaa_chipset = { .name = "MCP77/MCP78", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = mcp77_clk_new, // .devinit = g98_devinit_new, @@ -1227,7 +1227,7 @@ static const struct nvkm_device_chip nvac_chipset = { .name = "MCP79/MCP7A", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = mcp77_clk_new, // .devinit = g98_devinit_new, @@ -1258,7 +1258,7 @@ static const struct nvkm_device_chip nvaf_chipset = { .name = "MCP89", .bar = g84_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = mcp89_devinit_new, @@ -1290,7 +1290,7 @@ static const struct nvkm_device_chip nvc0_chipset = { .name = "GF100", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1325,7 +1325,7 @@ static const struct nvkm_device_chip nvc1_chipset = { .name = "GF108", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1359,7 +1359,7 @@ static const struct nvkm_device_chip nvc3_chipset = { .name = "GF106", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1393,7 +1393,7 @@ static const struct nvkm_device_chip nvc4_chipset = { .name = "GF104", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1428,7 +1428,7 @@ static const struct nvkm_device_chip nvc8_chipset = { .name = "GF110", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1463,7 +1463,7 @@ static const struct nvkm_device_chip nvce_chipset = { .name = "GF114", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1498,7 +1498,7 @@ static const struct nvkm_device_chip nvcf_chipset = { .name = "GF116", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1532,7 +1532,7 @@ static const struct nvkm_device_chip nvd7_chipset = { .name = "GF117", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1564,7 +1564,7 @@ static const struct nvkm_device_chip nvd9_chipset = { .name = "GF119", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, @@ -1598,7 +1598,7 @@ static const struct nvkm_device_chip nve4_chipset = { .name = "GK104", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1634,7 +1634,7 @@ static const struct nvkm_device_chip nve6_chipset = { .name = "GK106", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1670,7 +1670,7 @@ static const struct nvkm_device_chip nve7_chipset = { .name = "GK107", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1730,7 +1730,7 @@ static const struct nvkm_device_chip nvf0_chipset = { .name = "GK110", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1766,7 +1766,7 @@ static const struct nvkm_device_chip nvf1_chipset = { .name = "GK110B", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1802,7 +1802,7 @@ static const struct nvkm_device_chip nv106_chipset = { .name = "GK208B", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1837,7 +1837,7 @@ static const struct nvkm_device_chip nv108_chipset = { .name = "GK208", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, @@ -1872,7 +1872,7 @@ static const struct nvkm_device_chip nv117_chipset = { .name = "GM107", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gm107_devinit_new, @@ -1902,7 +1902,7 @@ static const struct nvkm_device_chip nv124_chipset = { .name = "GM204", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .devinit = gm204_devinit_new, // .fb = gm107_fb_new, @@ -1931,7 +1931,7 @@ static const struct nvkm_device_chip nv126_chipset = { .name = "GM206", .bar = gf100_bar_new, -// .bios = nvkm_bios_new, + .bios = nvkm_bios_new, // .bus = gf100_bus_new, // .devinit = gm204_devinit_new, // .fb = gm107_fb_new, @@ -2581,7 +2581,6 @@ nvkm_device_ctor(const struct nvkm_device_func *func, } } else { device->chip = &null_chipset; - device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass; } if (!device->name) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index cb3fe0361c266..ff8583e0ce853 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -59,7 +58,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -90,7 +88,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -120,7 +117,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -151,7 +147,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -181,7 +176,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -211,7 +205,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -242,7 +235,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -272,7 +264,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index b251b05889c67..f327c72d092d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -60,7 +59,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -92,7 +90,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -144,7 +141,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; break; case 0xf0: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -176,7 +172,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -208,7 +203,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; @@ -239,7 +233,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 95dec0c1134cd..6a85fed5a7c5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -28,7 +28,6 @@ gm100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x117: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; @@ -66,7 +65,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x124: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; @@ -105,7 +103,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x126: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 5245b78794f98..e79ca4e2aeec2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,7 +28,6 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; @@ -45,7 +44,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 3794c53cfbda7..9d8a4ef4217a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,7 +28,6 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -44,7 +43,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -62,7 +60,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -80,7 +77,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -98,7 +94,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -116,7 +111,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -134,7 +128,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -152,7 +145,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 9acdadeea0ca1..0a3f3e73c9aab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,7 +28,6 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -46,7 +45,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -64,7 +62,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -82,7 +79,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 3d687d760601e..8e37de00a0e14 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,7 +28,6 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -46,7 +45,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -64,7 +62,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -83,7 +80,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; @@ -102,7 +98,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 35fb2f92d171d..f21e53021f8ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -50,7 +49,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -72,7 +70,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -94,7 +91,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -116,7 +112,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -138,7 +133,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -160,7 +154,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -182,7 +175,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -204,7 +196,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -226,7 +217,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -248,7 +238,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -270,7 +259,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -292,7 +280,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -314,7 +301,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -336,7 +322,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; @@ -358,7 +343,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index ee72cd41345cb..7f249cf4e1e24 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -52,7 +51,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -79,7 +77,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -106,7 +103,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -133,7 +129,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -160,7 +155,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -187,7 +181,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -214,7 +207,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -241,7 +233,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -268,7 +259,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -295,7 +285,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -324,7 +313,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -352,7 +340,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; @@ -380,7 +367,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass; device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index c3d22e33e0736..f561072e6874f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -209,14 +209,15 @@ gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head) static void gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head) { + struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_output *outp = exec_script(disp, head, 2); /* see note in nv50_disp_intr_unk20_0() */ if (outp && outp->info.type == DCB_OUTPUT_DP) { struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = nvkm_bios(disp), + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->info, .crtc = head, .offset = outpdp->info.script[4], diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index 9bc4273947c34..efffecbc92a5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -319,6 +319,7 @@ nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head) static void nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) { + struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_output *outp = exec_script(disp, head, 2); /* the binary driver does this outside of the supervisor handling @@ -337,8 +338,8 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head) if (outp && outp->info.type == DCB_OUTPUT_DP) { struct nvkm_output_dp *outpdp = nvkm_output_dp(outp); struct nvbios_init init = { - .subdev = nv_subdev(disp), - .bios = nvkm_bios(disp), + .subdev = subdev, + .bios = subdev->device->bios, .outp = &outp->info, .crtc = head, .offset = outpdp->info.script[4], diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c index b48ec70d9c553..79536897efaad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c @@ -83,20 +83,29 @@ nvbios_extend(struct nvkm_bios *bios, u32 length) return 0; } -static int -nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void * +nvkm_bios_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_bios *bios = nvkm_bios(subdev); + kfree(bios->data); + return bios; +} + +static const struct nvkm_subdev_func +nvkm_bios = { + .dtor = nvkm_bios_dtor, +}; + +int +nvkm_bios_new(struct nvkm_device *device, int index, struct nvkm_bios **pbios) { struct nvkm_bios *bios; struct bit_entry bit_i; int ret; - ret = nvkm_subdev_create(parent, engine, oclass, 0, - "VBIOS", "bios", &bios); - *pobject = nv_object(bios); - if (ret) - return ret; + if (!(bios = *pbios = kzalloc(sizeof(*bios), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_bios, device, index, 0, &bios->subdev); ret = nvbios_shadow(bios); if (ret) @@ -136,36 +145,3 @@ nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine, bios->version.minor, bios->version.micro, bios->version.patch); return 0; } - -static void -nvkm_bios_dtor(struct nvkm_object *object) -{ - struct nvkm_bios *bios = (void *)object; - kfree(bios->data); - nvkm_subdev_destroy(&bios->subdev); -} - -static int -nvkm_bios_init(struct nvkm_object *object) -{ - struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_init_old(&bios->subdev); -} - -static int -nvkm_bios_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_bios *bios = (void *)object; - return nvkm_subdev_fini_old(&bios->subdev, suspend); -} - -struct nvkm_oclass -nvkm_bios_oclass = { - .handle = NV_SUBDEV(VBIOS, 0x00), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nvkm_bios_ctor, - .dtor = nvkm_bios_dtor, - .init = nvkm_bios_init, - .fini = nvkm_bios_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index c2c2d90e04f59..f119bc81d39e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -141,7 +141,7 @@ init_conn(struct nvbios_init *init) static inline u32 init_nvreg(struct nvbios_init *init, u32 reg) { - struct nvkm_devinit *devinit = nvkm_devinit(init->bios); + struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; /* C51 (at least) sometimes has the lower bits set which the VBIOS * interprets to mean that access needs to go through certain IO @@ -154,7 +154,7 @@ init_nvreg(struct nvbios_init *init, u32 reg) /* GF8+ display scripts need register addresses mangled a bit to * select a specific CRTC/OR */ - if (nv_device(init->bios)->card_type >= NV_50) { + if (init->bios->subdev.device->card_type >= NV_50) { if (reg & 0x80000000) { reg += init_crtc(init) * 0x800; reg &= ~0x80000000; @@ -337,7 +337,7 @@ init_wrauxr(struct nvbios_init *init, u32 addr, u8 data) static void init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) { - struct nvkm_devinit *devinit = nvkm_devinit(init->bios); + struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; if (devinit->pll_set && init_exec(init)) { int ret = devinit->pll_set(devinit, id, freq); if (ret) @@ -1447,7 +1447,7 @@ init_zm_index_io(struct nvbios_init *init) static void init_compute_mem(struct nvbios_init *init) { - struct nvkm_devinit *devinit = nvkm_devinit(init->bios); + struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; trace("COMPUTE_MEM\n"); init->offset += 1; @@ -1624,7 +1624,7 @@ init_io(struct nvbios_init *init) * needed some day.. it's almost certainly wrong, but, it also * somehow makes things work... */ - if (nv_device(init->bios)->card_type >= NV_50 && + if (bios->subdev.device->card_type >= NV_50 && port == 0x03c3 && data == 0x01) { init_mask(init, 0x614100, 0xf0800000, 0x00800000); init_mask(init, 0x00e18c, 0x00020000, 0x00020000); @@ -1930,7 +1930,7 @@ init_ram_restrict_pll(struct nvbios_init *init) static void init_gpio(struct nvbios_init *init) { - struct nvkm_gpio *gpio = nvkm_gpio(init->bios); + struct nvkm_gpio *gpio = init->bios->subdev.device->gpio; trace("GPIO\n"); init->offset += 1; @@ -2158,7 +2158,7 @@ static void init_gpio_ne(struct nvbios_init *init) { struct nvkm_bios *bios = init->bios; - struct nvkm_gpio *gpio = nvkm_gpio(bios); + struct nvkm_gpio *gpio = bios->subdev.device->gpio; struct dcb_gpio_func func; u8 count = nvbios_rd08(bios, init->offset + 1); u8 idx = 0, ver, len; @@ -2287,7 +2287,7 @@ nvbios_exec(struct nvbios_init *init) int nvbios_init(struct nvkm_subdev *subdev, bool execute) { - struct nvkm_bios *bios = nvkm_bios(subdev); + struct nvkm_bios *bios = subdev->device->bios; int ret = 0; int i = -1; u16 data; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c index 9385ae9f34638..aa7e33b42b30c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c @@ -115,7 +115,7 @@ nvbios_perfEp(struct nvkm_bios *bios, int idx, info->shader = nvbios_rd16(bios, perf + 0x06) * 1000; info->core = info->shader + (signed char) nvbios_rd08(bios, perf + 0x08) * 1000; - switch (nv_device(bios)->chipset) { + switch (bios->subdev.device->chipset) { case 0x49: case 0x4b: info->memory = nvbios_rd16(bios, perf + 0x0b) * 1000; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c index 1f5c1332bf255..125ec2ed6c2e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c @@ -111,7 +111,8 @@ pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len) static struct pll_mapping * pll_map(struct nvkm_bios *bios) { - switch (nv_device(bios)->card_type) { + struct nvkm_device *device = bios->subdev.device; + switch (device->card_type) { case NV_04: case NV_10: case NV_11: @@ -122,12 +123,12 @@ pll_map(struct nvkm_bios *bios) case NV_40: return nv40_pll_mapping; case NV_50: - if (nv_device(bios)->chipset == 0x50) + if (device->chipset == 0x50) return nv50_pll_mapping; else - if (nv_device(bios)->chipset < 0xa3 || - nv_device(bios)->chipset == 0xaa || - nv_device(bios)->chipset == 0xac) + if (device->chipset < 0xa3 || + device->chipset == 0xaa || + device->chipset == 0xac) return g84_pll_mapping; default: return NULL; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h index 95e4fa1531d64..e0ec2a6b7b795 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h @@ -1,5 +1,6 @@ #ifndef __NVKM_BIOS_PRIV_H__ #define __NVKM_BIOS_PRIV_H__ +#define nvkm_bios(p) container_of((p), struct nvkm_bios, subdev) #include struct nvbios_source { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c index 878d08fd0e29c..d5222af10b963 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c @@ -50,7 +50,7 @@ nvbios_ramcfg_count(struct nvkm_bios *bios) u8 nvbios_ramcfg_index(struct nvkm_subdev *subdev) { - struct nvkm_bios *bios = nvkm_bios(subdev); + struct nvkm_bios *bios = subdev->device->bios; u8 strap = nvbios_ramcfg_strap(subdev); u32 xlat = 0x00000000; struct bit_entry bit_M; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index 1bbc49677107b..b089a11ba08cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -134,7 +134,7 @@ shadow_fw_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * shadow_fw_init(struct nvkm_bios *bios, const char *name) { - struct device *dev = &nv_device(bios)->pdev->dev; + struct device *dev = &bios->subdev.device->pdev->dev; const struct firmware *fw; int ret = request_firmware(&fw, name, dev); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c index 74604d4a7ff2c..468066817c75c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c @@ -88,7 +88,7 @@ acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * acpi_init(struct nvkm_bios *bios, const char *name) { - if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev)) + if (!nouveau_acpi_rom_supported(bios->subdev.device->pdev)) return ERR_PTR(-ENODEV); return NULL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index 4f5cbf4d9666e..29a37f03ebf1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c @@ -43,7 +43,7 @@ of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * of_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = nv_device(bios)->pdev; + struct pci_dev *pdev = bios->subdev.device->pdev; struct device_node *dn; struct priv *priv; if (!(dn = pci_device_to_OF_node(pdev))) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c index ae1e229b617f0..0979bc89eeab0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c @@ -51,7 +51,7 @@ pcirom_fini(void *data) static void * pcirom_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = nv_device(bios)->pdev; + struct pci_dev *pdev = bios->subdev.device->pdev; struct priv *priv = NULL; int ret; @@ -83,7 +83,7 @@ nvbios_pcirom = { static void * platform_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = nv_device(bios)->pdev; + struct pci_dev *pdev = bios->subdev.device->pdev; struct priv *priv; int ret = -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c index 4039ec594b26c..a54cfec0550d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c @@ -203,7 +203,7 @@ nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan) } /* starting from fermi, fan management is always linear */ - if (nv_device(bios)->card_type >= NV_C0 && + if (bios->subdev.device->card_type >= NV_C0 && fan->fan_mode == NVBIOS_THERM_FAN_OTHER) { fan->fan_mode = NVBIOS_THERM_FAN_LINEAR; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index 659122721b7db..c99385329ef40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -39,7 +39,7 @@ static u32 nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust, u8 pstate, u8 domain, u32 input) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_bios *bios = clk->subdev.device->bios; struct nvbios_boostE boostE; u8 ver, hdr, cnt, len; u16 data; @@ -136,7 +136,7 @@ nvkm_cstate_del(struct nvkm_cstate *cstate) static int nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_bios *bios = clk->subdev.device->bios; struct nvkm_domain *domain = clk->domains; struct nvkm_cstate *cstate = NULL; struct nvbios_cstepX cstepX; @@ -305,7 +305,7 @@ nvkm_pstate_del(struct nvkm_pstate *pstate) static int nvkm_pstate_new(struct nvkm_clk *clk, int idx) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_bios *bios = clk->subdev.device->bios; struct nvkm_domain *domain = clk->domains - 1; struct nvkm_pstate *pstate; struct nvkm_cstate *cstate; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 6c3090898e365..966eeb51d7718 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -240,7 +240,8 @@ calc_src(struct gf100_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv) static u32 calc_pll(struct gf100_clk *clk, int idx, u32 freq, u32 *coef) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pll limits; int N, M, P, ret; @@ -252,7 +253,7 @@ calc_pll(struct gf100_clk *clk, int idx, u32 freq, u32 *coef) if (!limits.refclk) return 0; - ret = gt215_pll_calc(nv_subdev(clk), &limits, freq, &N, NULL, &M, &P); + ret = gt215_pll_calc(subdev, &limits, freq, &N, NULL, &M, &P); if (ret <= 0) return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index 7ca88da8a69be..2aea8fd23c037 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -261,7 +261,8 @@ calc_src(struct gk104_clk *clk, int idx, u32 freq, u32 *dsrc, u32 *ddiv) static u32 calc_pll(struct gk104_clk *clk, int idx, u32 freq, u32 *coef) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvbios_pll limits; int N, M, P, ret; @@ -273,7 +274,7 @@ calc_pll(struct gk104_clk *clk, int idx, u32 freq, u32 *coef) if (!limits.refclk) return 0; - ret = gt215_pll_calc(nv_subdev(clk), &limits, freq, &N, NULL, &M, &P); + ret = gt215_pll_calc(subdev, &limits, freq, &N, NULL, &M, &P); if (ret <= 0) return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 383030434079b..d01847d25d7f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -231,8 +231,8 @@ int gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, struct gt215_clk_info *info) { - struct nvkm_bios *bios = nvkm_bios(clock); struct gt215_clk *clk = (void *)clock; + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll limits; int P, N, M, diff; int ret; @@ -248,7 +248,7 @@ gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, } /* Try with PLL */ - ret = nvbios_pll_parse(bios, pll, &limits); + ret = nvbios_pll_parse(subdev->device->bios, pll, &limits); if (ret) return ret; @@ -256,7 +256,7 @@ gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, if (ret != limits.refclk) return -EINVAL; - ret = gt215_pll_calc(nv_subdev(clk), &limits, khz, &N, NULL, &M, &P); + ret = gt215_pll_calc(subdev, &limits, khz, &N, NULL, &M, &P); if (ret >= 0) { info->pll = (P << 16) | (N << 8) | M; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index 31e8fa02ba749..b2be8a6acfc16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -164,11 +164,11 @@ static u32 calc_pll(struct mcp77_clk *clk, u32 reg, u32 clock, int *N, int *M, int *P) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll pll; int ret; - ret = nvbios_pll_parse(bios, reg, &pll); + ret = nvbios_pll_parse(subdev->device->bios, reg, &pll); if (ret) return 0; @@ -177,7 +177,7 @@ calc_pll(struct mcp77_clk *clk, u32 reg, if (!pll.refclk) return 0; - return nv04_pll_calc(nv_subdev(clk), &pll, clock, N, M, NULL, NULL, P); + return nv04_pll_calc(subdev, &pll, clock, N, M, NULL, NULL, P); } static inline u32 diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c index 3d6c423b81f34..5ad4a13a297d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c @@ -48,8 +48,9 @@ nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info, int nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv) { - struct nvkm_devinit *devinit = nvkm_devinit(clk); - int cv = nvkm_bios(clk)->version.chip; + struct nvkm_device *device = clk->subdev.device; + struct nvkm_devinit *devinit = device->devinit; + int cv = device->bios->version.chip; if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 || cv >= 0x40) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index 1aabc5af45ec8..2f1a638bd307e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -133,18 +133,18 @@ static int nv40_clk_calc_pll(struct nv40_clk *clk, u32 reg, u32 khz, int *N1, int *M1, int *N2, int *M2, int *log2P) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll pll; int ret; - ret = nvbios_pll_parse(bios, reg, &pll); + ret = nvbios_pll_parse(subdev->device->bios, reg, &pll); if (ret) return ret; if (khz < pll.vco1.max_freq) pll.vco2.max_freq = 0; - ret = nv04_pll_calc(nv_subdev(clk), &pll, khz, N1, M1, N2, M2, log2P); + ret = nv04_pll_calc(subdev, &pll, khz, N1, M1, N2, M2, log2P); if (ret == 0) return -ERANGE; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index 369b8f45902fd..d4bf98657f04c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -324,11 +324,11 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) static u32 calc_pll(struct nv50_clk *clk, u32 reg, u32 idx, int *N, int *M, int *P) { - struct nvkm_bios *bios = nvkm_bios(clk); + struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll pll; int ret; - ret = nvbios_pll_parse(bios, reg, &pll); + ret = nvbios_pll_parse(subdev->device->bios, reg, &pll); if (ret) return 0; @@ -337,7 +337,7 @@ calc_pll(struct nv50_clk *clk, u32 reg, u32 idx, int *N, int *M, int *P) if (!pll.refclk) return 0; - return nv04_pll_calc(nv_subdev(clk), &pll, idx, N, M, NULL, NULL, P); + return nv04_pll_calc(subdev, &pll, idx, N, M, NULL, NULL, P); } static inline u32 diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c index 2050d1486641d..5ad67879e7036 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c @@ -37,7 +37,7 @@ getMNP_single(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - struct nvkm_bios *bios = nvkm_bios(subdev); + struct nvkm_bios *bios = subdev->device->bios; int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq; int minM = info->vco1.min_m, maxM = info->vco1.max_m; int minN = info->vco1.min_n, maxN = info->vco1.max_n; @@ -136,7 +136,7 @@ getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk, * "clk" parameter in kHz * returns calculated clock */ - int chip_version = nvkm_bios(subdev)->version.chip; + int chip_version = subdev->device->bios->version.chip; int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq; int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq; int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 41d9dbb075a4a..5947bbb91dba9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -355,7 +355,8 @@ setPLL_double_lowregs(struct nvkm_devinit *init, u32 NMNMreg, int nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) { - struct nvkm_bios *bios = nvkm_bios(devinit); + struct nvkm_subdev *subdev = &devinit->subdev; + struct nvkm_bios *bios = subdev->device->bios; struct nvkm_pll_vals pv; struct nvbios_pll info; int cv = bios->version.chip; @@ -366,8 +367,7 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) if (ret) return ret; - ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, - &N1, &M1, &N2, &M2, &P); + ret = nv04_pll_calc(subdev, &info, freq, &N1, &M1, &N2, &M2, &P); if (!ret) return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index 07db5845f8b20..faeb2041f6085 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -44,7 +44,7 @@ nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { struct nvkm_device *device = gpio->subdev.device; - struct nvkm_bios *bios = nvkm_bios(gpio); + struct nvkm_bios *bios = device->bios; u8 ver, len; u16 data; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 9dcfbffe1ce42..ed380db94fb4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -43,8 +43,9 @@ mxm_shadow_rom_fetch(struct nvkm_i2c_bus *bus, u8 addr, static bool mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version) { - struct nvkm_bios *bios = nvkm_bios(mxm); - struct nvkm_i2c *i2c = nvkm_i2c(mxm); + struct nvkm_device *device = mxm->subdev.device; + struct nvkm_bios *bios = device->bios; + struct nvkm_i2c *i2c = device->i2c; struct nvkm_i2c_bus *bus = NULL; u8 i2cidx, mxms[6], addr, size; @@ -229,8 +230,8 @@ int nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, int length, void **pobject) { - struct nvkm_device *device = nv_device(parent); - struct nvkm_bios *bios = nvkm_bios(device); + struct nvkm_device *device = (void *)parent; + struct nvkm_bios *bios = device->bios; struct nvkm_mxm *mxm; u8 ver, len; u16 data; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c index 9bf77b26ef585..9167e6098d6a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c @@ -49,7 +49,7 @@ mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info) static bool mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info) { - struct nvkm_bios *bios = nvkm_bios(mxm); + struct nvkm_bios *bios = mxm->subdev.device->bios; struct context *ctx = info; u64 desc = *(u64 *)data; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index 97917c532e148..ac4847f2912d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -87,8 +87,8 @@ int nvkm_fanpwm_create(struct nvkm_therm *obj, struct dcb_gpio_func *func) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = nv_device(therm); - struct nvkm_bios *bios = nvkm_bios(therm); + struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_bios *bios = device->bios; struct nvkm_fanpwm *fan; struct nvbios_therm_fan info; u32 divs, duty; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index b346f3a0ff119..2622c4403a73c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -251,7 +251,7 @@ nvkm_therm_sensor_ctor(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_subdev *subdev = &therm->base.subdev; - struct nvkm_bios *bios = nvkm_bios(therm); + struct nvkm_bios *bios = subdev->device->bios; nvkm_alarm_init(&therm->sensor.therm_poll_alarm, alarm_timer_callback); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index 88e5f62ec7722..c1668c86f521d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -64,7 +64,7 @@ nvkm_volt_set(struct nvkm_volt *volt, u32 uv) static int nvkm_volt_map(struct nvkm_volt *volt, u8 id) { - struct nvkm_bios *bios = nvkm_bios(volt); + struct nvkm_bios *bios = volt->subdev.device->bios; struct nvbios_vmap_entry info; u8 ver, len; u16 vmap; -- GitLab From bb23f9d7919311ebc696bc540e41c908168f9cb5 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5531/7006] drm/nouveau/bus: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/bus.h | 42 +----- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/subdev/bus/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/bus/base.c | 64 ++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c | 22 +-- .../gpu/drm/nouveau/nvkm/subdev/bus/gf100.c | 37 ++--- .../gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c | 27 ++-- .../gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h | 3 +- .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.c | 51 ++----- .../gpu/drm/nouveau/nvkm/subdev/bus/nv04.h | 17 --- .../gpu/drm/nouveau/nvkm/subdev/bus/nv31.c | 37 ++--- .../gpu/drm/nouveau/nvkm/subdev/bus/nv50.c | 37 ++--- .../gpu/drm/nouveau/nvkm/subdev/bus/priv.h | 18 +++ 22 files changed, 246 insertions(+), 318 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h index 5cf58a15bf41f..6a04d9c079441 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h @@ -2,49 +2,23 @@ #define __NVKM_BUS_H__ #include -struct nvkm_bus_intr { - u32 stat; - u32 unit; -}; - struct nvkm_bus { + const struct nvkm_bus_func *func; struct nvkm_subdev subdev; - int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32); - u32 hwsq_size; }; -static inline struct nvkm_bus * -nvkm_bus(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_BUS); -} - -#define nvkm_bus_create(p, e, o, d) \ - nvkm_subdev_create_((p), (e), (o), 0, "PBUS", "master", \ - sizeof(**d), (void **)d) -#define nvkm_bus_destroy(p) \ - nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_bus_init(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_bus_fini(p, s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) - -#define _nvkm_bus_dtor _nvkm_subdev_dtor -#define _nvkm_bus_init _nvkm_subdev_init -#define _nvkm_bus_fini _nvkm_subdev_fini - -extern struct nvkm_oclass *nv04_bus_oclass; -extern struct nvkm_oclass *nv31_bus_oclass; -extern struct nvkm_oclass *nv50_bus_oclass; -extern struct nvkm_oclass *g94_bus_oclass; -extern struct nvkm_oclass *gf100_bus_oclass; - /* interface to sequencer */ struct nvkm_hwsq; -int nvkm_hwsq_init(struct nvkm_bus *, struct nvkm_hwsq **); +int nvkm_hwsq_init(struct nvkm_subdev *, struct nvkm_hwsq **); int nvkm_hwsq_fini(struct nvkm_hwsq **, bool exec); void nvkm_hwsq_wr32(struct nvkm_hwsq *, u32 addr, u32 data); void nvkm_hwsq_setf(struct nvkm_hwsq *, u8 flag, int data); void nvkm_hwsq_wait(struct nvkm_hwsq *, u8 flag, u8 data); void nvkm_hwsq_nsec(struct nvkm_hwsq *, u32 nsec); + +int nv04_bus_new(struct nvkm_device *, int, struct nvkm_bus **); +int nv31_bus_new(struct nvkm_device *, int, struct nvkm_bus **); +int nv50_bus_new(struct nvkm_device *, int, struct nvkm_bus **); +int g94_bus_new(struct nvkm_device *, int, struct nvkm_bus **); +int gf100_bus_new(struct nvkm_device *, int, struct nvkm_bus **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 7ef3c14470385..21974c1c4990e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -77,7 +77,7 @@ static const struct nvkm_device_chip nv4_chipset = { .name = "NV04", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv04_devinit_new, // .fb = nv04_fb_new, @@ -97,7 +97,7 @@ static const struct nvkm_device_chip nv5_chipset = { .name = "NV05", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv05_devinit_new, // .fb = nv04_fb_new, @@ -117,7 +117,7 @@ static const struct nvkm_device_chip nv10_chipset = { .name = "NV10", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, @@ -136,7 +136,7 @@ static const struct nvkm_device_chip nv11_chipset = { .name = "NV11", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, @@ -157,7 +157,7 @@ static const struct nvkm_device_chip nv15_chipset = { .name = "NV15", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, @@ -178,7 +178,7 @@ static const struct nvkm_device_chip nv17_chipset = { .name = "NV17", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, @@ -199,7 +199,7 @@ static const struct nvkm_device_chip nv18_chipset = { .name = "NV18", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, @@ -220,7 +220,7 @@ static const struct nvkm_device_chip nv1a_chipset = { .name = "nForce", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv1a_fb_new, @@ -241,7 +241,7 @@ static const struct nvkm_device_chip nv1f_chipset = { .name = "nForce2", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv1a_fb_new, @@ -262,7 +262,7 @@ static const struct nvkm_device_chip nv20_chipset = { .name = "NV20", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv20_fb_new, @@ -283,7 +283,7 @@ static const struct nvkm_device_chip nv25_chipset = { .name = "NV25", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv25_fb_new, @@ -304,7 +304,7 @@ static const struct nvkm_device_chip nv28_chipset = { .name = "NV28", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv25_fb_new, @@ -325,7 +325,7 @@ static const struct nvkm_device_chip nv2a_chipset = { .name = "NV2A", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv25_fb_new, @@ -346,7 +346,7 @@ static const struct nvkm_device_chip nv30_chipset = { .name = "NV30", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv30_fb_new, @@ -367,7 +367,7 @@ static const struct nvkm_device_chip nv31_chipset = { .name = "NV31", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv30_fb_new, @@ -389,7 +389,7 @@ static const struct nvkm_device_chip nv34_chipset = { .name = "NV34", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, @@ -411,7 +411,7 @@ static const struct nvkm_device_chip nv35_chipset = { .name = "NV35", .bios = nvkm_bios_new, -// .bus = nv04_bus_new, + .bus = nv04_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv35_fb_new, @@ -432,7 +432,7 @@ static const struct nvkm_device_chip nv36_chipset = { .name = "NV36", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv36_fb_new, @@ -454,7 +454,7 @@ static const struct nvkm_device_chip nv40_chipset = { .name = "NV40", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv40_fb_new, @@ -479,7 +479,7 @@ static const struct nvkm_device_chip nv41_chipset = { .name = "NV41", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, @@ -504,7 +504,7 @@ static const struct nvkm_device_chip nv42_chipset = { .name = "NV42", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, @@ -529,7 +529,7 @@ static const struct nvkm_device_chip nv43_chipset = { .name = "NV43", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, @@ -554,7 +554,7 @@ static const struct nvkm_device_chip nv44_chipset = { .name = "NV44", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv44_fb_new, @@ -579,7 +579,7 @@ static const struct nvkm_device_chip nv45_chipset = { .name = "NV45", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv40_fb_new, @@ -604,7 +604,7 @@ static const struct nvkm_device_chip nv46_chipset = { .name = "G72", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, @@ -629,7 +629,7 @@ static const struct nvkm_device_chip nv47_chipset = { .name = "G70", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv47_fb_new, @@ -654,7 +654,7 @@ static const struct nvkm_device_chip nv49_chipset = { .name = "G71", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv49_fb_new, @@ -679,7 +679,7 @@ static const struct nvkm_device_chip nv4a_chipset = { .name = "NV44A", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv44_fb_new, @@ -704,7 +704,7 @@ static const struct nvkm_device_chip nv4b_chipset = { .name = "G73", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv49_fb_new, @@ -729,7 +729,7 @@ static const struct nvkm_device_chip nv4c_chipset = { .name = "C61", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, @@ -754,7 +754,7 @@ static const struct nvkm_device_chip nv4e_chipset = { .name = "C51", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv4e_fb_new, @@ -780,7 +780,7 @@ nv50_chipset = { .name = "G80", .bar = nv50_bar_new, .bios = nvkm_bios_new, -// .bus = nv50_bus_new, + .bus = nv50_bus_new, // .clk = nv50_clk_new, // .devinit = nv50_devinit_new, // .fb = nv50_fb_new, @@ -807,7 +807,7 @@ static const struct nvkm_device_chip nv63_chipset = { .name = "C73", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, @@ -832,7 +832,7 @@ static const struct nvkm_device_chip nv67_chipset = { .name = "C67", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, @@ -857,7 +857,7 @@ static const struct nvkm_device_chip nv68_chipset = { .name = "C68", .bios = nvkm_bios_new, -// .bus = nv31_bus_new, + .bus = nv31_bus_new, // .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, @@ -883,7 +883,7 @@ nv84_chipset = { .name = "G84", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = nv50_bus_new, + .bus = nv50_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, @@ -914,7 +914,7 @@ nv86_chipset = { .name = "G86", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = nv50_bus_new, + .bus = nv50_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, @@ -945,7 +945,7 @@ nv92_chipset = { .name = "G92", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = nv50_bus_new, + .bus = nv50_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, @@ -976,7 +976,7 @@ nv94_chipset = { .name = "G94", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, @@ -1014,7 +1014,7 @@ nv96_chipset = { // .mxm = nv50_mxm_new, // .devinit = g84_devinit_new, // .mc = g94_mc_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .timer = nv04_timer_new, // .fb = g84_fb_new, // .imem = nv50_instmem_new, @@ -1045,7 +1045,7 @@ nv98_chipset = { // .mxm = nv50_mxm_new, // .devinit = g98_devinit_new, // .mc = g98_mc_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .timer = nv04_timer_new, // .fb = g84_fb_new, // .imem = nv50_instmem_new, @@ -1069,7 +1069,7 @@ nva0_chipset = { .name = "GT200", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, @@ -1100,7 +1100,7 @@ nva3_chipset = { .name = "GT215", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = gt215_devinit_new, // .fb = gt215_fb_new, @@ -1133,7 +1133,7 @@ nva5_chipset = { .name = "GT216", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = gt215_devinit_new, // .fb = gt215_fb_new, @@ -1165,7 +1165,7 @@ nva8_chipset = { .name = "GT218", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = gt215_devinit_new, // .fb = gt215_fb_new, @@ -1197,7 +1197,7 @@ nvaa_chipset = { .name = "MCP77/MCP78", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = mcp77_clk_new, // .devinit = g98_devinit_new, // .fb = mcp77_fb_new, @@ -1228,7 +1228,7 @@ nvac_chipset = { .name = "MCP79/MCP7A", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = mcp77_clk_new, // .devinit = g98_devinit_new, // .fb = mcp77_fb_new, @@ -1259,7 +1259,7 @@ nvaf_chipset = { .name = "MCP89", .bar = g84_bar_new, .bios = nvkm_bios_new, -// .bus = g94_bus_new, + .bus = g94_bus_new, // .clk = gt215_clk_new, // .devinit = mcp89_devinit_new, // .fb = mcp89_fb_new, @@ -1291,7 +1291,7 @@ nvc0_chipset = { .name = "GF100", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1326,7 +1326,7 @@ nvc1_chipset = { .name = "GF108", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1360,7 +1360,7 @@ nvc3_chipset = { .name = "GF106", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1394,7 +1394,7 @@ nvc4_chipset = { .name = "GF104", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1429,7 +1429,7 @@ nvc8_chipset = { .name = "GF110", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1464,7 +1464,7 @@ nvce_chipset = { .name = "GF114", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1499,7 +1499,7 @@ nvcf_chipset = { .name = "GF116", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1533,7 +1533,7 @@ nvd7_chipset = { .name = "GF117", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1565,7 +1565,7 @@ nvd9_chipset = { .name = "GF119", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, @@ -1599,7 +1599,7 @@ nve4_chipset = { .name = "GK104", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1635,7 +1635,7 @@ nve6_chipset = { .name = "GK106", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1671,7 +1671,7 @@ nve7_chipset = { .name = "GK107", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1706,7 +1706,7 @@ static const struct nvkm_device_chip nvea_chipset = { .name = "GK20A", .bar = gk20a_bar_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk20a_clk_new, // .fb = gk20a_fb_new, // .fuse = gf100_fuse_new, @@ -1731,7 +1731,7 @@ nvf0_chipset = { .name = "GK110", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1767,7 +1767,7 @@ nvf1_chipset = { .name = "GK110B", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1803,7 +1803,7 @@ nv106_chipset = { .name = "GK208B", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1838,7 +1838,7 @@ nv108_chipset = { .name = "GK208", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, @@ -1873,7 +1873,7 @@ nv117_chipset = { .name = "GM107", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .clk = gk104_clk_new, // .devinit = gm107_devinit_new, // .fb = gm107_fb_new, @@ -1903,7 +1903,7 @@ nv124_chipset = { .name = "GM204", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .devinit = gm204_devinit_new, // .fb = gm107_fb_new, // .fuse = gm107_fuse_new, @@ -1932,7 +1932,7 @@ nv126_chipset = { .name = "GM206", .bar = gf100_bar_new, .bios = nvkm_bios_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .devinit = gm204_devinit_new, // .fb = gm107_fb_new, // .fuse = gm107_fuse_new, @@ -1960,7 +1960,7 @@ static const struct nvkm_device_chip nv12b_chipset = { .name = "GM20B", .bar = gk20a_bar_new, -// .bus = gf100_bus_new, + .bus = gf100_bus_new, // .fb = gk20a_fb_new, // .fuse = gm107_fuse_new, // .ibus = gk20a_ibus_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index ff8583e0ce853..117943075692f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -36,7 +36,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -66,7 +65,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -96,7 +94,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -125,7 +122,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -155,7 +151,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -184,7 +179,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -213,7 +207,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -243,7 +236,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; @@ -272,7 +264,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index f327c72d092d8..bb37f3f190b66 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -36,7 +36,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; @@ -67,7 +66,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; @@ -98,7 +96,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; @@ -123,7 +120,6 @@ gk104_identify(struct nvkm_device *device) case 0xea: device->oclass[NVDEV_SUBDEV_CLK ] = &gk20a_clk_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; @@ -149,7 +145,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; @@ -180,7 +175,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; @@ -211,7 +205,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; @@ -241,7 +234,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 6a85fed5a7c5d..2df5bf07f2170 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -36,7 +36,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; @@ -77,7 +76,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; @@ -115,7 +113,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; @@ -144,7 +141,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index e79ca4e2aeec2..7e77ee0d03e7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -32,7 +32,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -48,7 +47,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 9d8a4ef4217a1..dc51b0c3704c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -33,7 +33,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -48,7 +47,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -65,7 +63,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -82,7 +79,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -99,7 +95,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -116,7 +111,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -133,7 +127,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -150,7 +143,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 0a3f3e73c9aab..ef09f62e21bbc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -33,7 +33,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -50,7 +49,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -67,7 +65,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -84,7 +81,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 8e37de00a0e14..1c26b9b81ba40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -33,7 +33,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -50,7 +49,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -67,7 +65,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -85,7 +82,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -103,7 +99,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index f21e53021f8ca..b97cceb711376 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -34,7 +34,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -55,7 +54,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -76,7 +74,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -97,7 +94,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -118,7 +114,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -139,7 +134,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -160,7 +154,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -181,7 +174,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -202,7 +194,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -223,7 +214,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -244,7 +234,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -265,7 +254,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -286,7 +274,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -307,7 +294,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -328,7 +314,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; @@ -349,7 +334,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 7f249cf4e1e24..d071d57e6cf7f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -36,7 +36,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -59,7 +58,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -85,7 +83,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -111,7 +108,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -137,7 +133,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -163,7 +158,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -189,7 +183,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -215,7 +208,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -241,7 +233,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -267,7 +258,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -293,7 +283,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -321,7 +310,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -348,7 +336,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -375,7 +362,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = mcp89_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; - device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = mcp89_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild index 83d80b13f1496..5fa9e91835c88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild @@ -1,3 +1,4 @@ +nvkm-y += nvkm/subdev/bus/base.o nvkm-y += nvkm/subdev/bus/hwsq.o nvkm-y += nvkm/subdev/bus/nv04.o nvkm-y += nvkm/subdev/bus/nv31.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c new file mode 100644 index 0000000000000..dc5a10f18bdb5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/base.c @@ -0,0 +1,64 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +static void +nvkm_bus_intr(struct nvkm_subdev *subdev) +{ + struct nvkm_bus *bus = nvkm_bus(subdev); + bus->func->intr(bus); +} + +static int +nvkm_bus_init(struct nvkm_subdev *subdev) +{ + struct nvkm_bus *bus = nvkm_bus(subdev); + bus->func->init(bus); + return 0; +} + +static void * +nvkm_bus_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_bus(subdev); +} + +static const struct nvkm_subdev_func +nvkm_bus = { + .dtor = nvkm_bus_dtor, + .init = nvkm_bus_init, + .intr = nvkm_bus_intr, +}; + +int +nvkm_bus_new_(const struct nvkm_bus_func *func, struct nvkm_device *device, + int index, struct nvkm_bus **pbus) +{ + struct nvkm_bus *bus; + if (!(bus = *pbus = kzalloc(sizeof(*bus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_bus, device, index, 0, &bus->subdev); + bus->func = func; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c index 10ac729a4d903..9700b5c01cc69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c @@ -22,7 +22,7 @@ * Authors: Martin Peres * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" #include @@ -49,16 +49,16 @@ g94_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) return 0; } -struct nvkm_oclass * -g94_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv50_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +g94_bus = { + .init = nv50_bus_init, .intr = nv50_bus_intr, .hwsq_exec = g94_bus_hwsq_exec, .hwsq_size = 128, -}.base; +}; + +int +g94_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&g94_bus, device, index, pbus); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c index 1e437c7d91b0a..e0930d5fdfb18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c @@ -22,11 +22,12 @@ * Authors: Martin Peres * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" static void -gf100_bus_intr(struct nvkm_subdev *subdev) +gf100_bus_intr(struct nvkm_bus *bus) { + struct nvkm_subdev *subdev = &bus->subdev; struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); @@ -53,30 +54,22 @@ gf100_bus_intr(struct nvkm_subdev *subdev) } } -static int -gf100_bus_init(struct nvkm_object *object) +static void +gf100_bus_init(struct nvkm_bus *bus) { - struct nvkm_bus *bus = (void *)object; struct nvkm_device *device = bus->subdev.device; - int ret; - - ret = nvkm_bus_init(bus); - if (ret) - return ret; - nvkm_wr32(device, 0x001100, 0xffffffff); nvkm_wr32(device, 0x001140, 0x0000000e); - return 0; } -struct nvkm_oclass * -gf100_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = gf100_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +gf100_bus = { + .init = gf100_bus_init, .intr = gf100_bus_intr, -}.base; +}; + +int +gf100_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&gf100_bus, device, index, pbus); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c index 88b6bb433c8db..79f1cf513b36f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" struct nvkm_hwsq { - struct nvkm_bus *bus; + struct nvkm_subdev *subdev; u32 addr; u32 data; struct { @@ -41,13 +41,13 @@ hwsq_cmd(struct nvkm_hwsq *hwsq, int size, u8 data[]) } int -nvkm_hwsq_init(struct nvkm_bus *bus, struct nvkm_hwsq **phwsq) +nvkm_hwsq_init(struct nvkm_subdev *subdev, struct nvkm_hwsq **phwsq) { struct nvkm_hwsq *hwsq; hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL); if (hwsq) { - hwsq->bus = bus; + hwsq->subdev = subdev; hwsq->addr = ~0; hwsq->data = ~0; memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data)); @@ -63,13 +63,14 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) struct nvkm_hwsq *hwsq = *phwsq; int ret = 0, i; if (hwsq) { - struct nvkm_bus *bus = hwsq->bus; - struct nvkm_subdev *subdev = &bus->subdev; + struct nvkm_subdev *subdev = hwsq->subdev; + struct nvkm_bus *bus = subdev->device->bus; hwsq->c.size = (hwsq->c.size + 4) / 4; - if (hwsq->c.size <= bus->hwsq_size) { + if (hwsq->c.size <= bus->func->hwsq_size) { if (exec) - ret = bus->hwsq_exec(bus, (u32 *)hwsq->c.data, - hwsq->c.size); + ret = bus->func->hwsq_exec(bus, + (u32 *)hwsq->c.data, + hwsq->c.size); if (ret) nvkm_error(subdev, "hwsq exec failed: %d\n", ret); } else { @@ -89,7 +90,7 @@ nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec) void nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) { - nvkm_debug(&hwsq->bus->subdev, "R[%06x] = %08x\n", addr, data); + nvkm_debug(hwsq->subdev, "R[%06x] = %08x\n", addr, data); if (hwsq->data != data) { if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) { @@ -114,7 +115,7 @@ nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data) void nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) { - nvkm_debug(&hwsq->bus->subdev, " FLAG[%02x] = %d\n", flag, data); + nvkm_debug(hwsq->subdev, " FLAG[%02x] = %d\n", flag, data); flag += 0x80; if (data >= 0) flag += 0x20; @@ -126,7 +127,7 @@ nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data) void nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data) { - nvkm_debug(&hwsq->bus->subdev, " WAIT[%02x] = %d\n", flag, data); + nvkm_debug(hwsq->subdev, " WAIT[%02x] = %d\n", flag, data); hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data }); } @@ -139,6 +140,6 @@ nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec) shift++; } - nvkm_debug(&hwsq->bus->subdev, " DELAY = %d ns\n", nsec); + nvkm_debug(hwsq->subdev, " DELAY = %d ns\n", nsec); hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec }); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h index 6f498cd4b82f0..8117ec5a1468e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h @@ -59,10 +59,9 @@ hwsq_reg(u32 addr) static inline int hwsq_init(struct hwsq *ram, struct nvkm_subdev *subdev) { - struct nvkm_bus *bus = nvkm_bus(subdev); int ret; - ret = nvkm_hwsq_init(bus, &ram->hwsq); + ret = nvkm_hwsq_init(subdev, &ram->hwsq); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c index ab6aecf29f4b9..c80b96789c31d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c @@ -22,13 +22,16 @@ * Authors: Martin Peres * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" + +#include #include static void -nv04_bus_intr(struct nvkm_subdev *subdev) +nv04_bus_intr(struct nvkm_bus *bus) { + struct nvkm_subdev *subdev = &bus->subdev; struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); @@ -52,46 +55,22 @@ nv04_bus_intr(struct nvkm_subdev *subdev) } } -static int -nv04_bus_init(struct nvkm_object *object) +static void +nv04_bus_init(struct nvkm_bus *bus) { - struct nvkm_bus *bus = (void *)object; struct nvkm_device *device = bus->subdev.device; - nvkm_wr32(device, 0x001100, 0xffffffff); nvkm_wr32(device, 0x001140, 0x00000111); - - return nvkm_bus_init(bus); } +static const struct nvkm_bus_func +nv04_bus = { + .init = nv04_bus_init, + .intr = nv04_bus_intr, +}; + int -nv04_bus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) { - struct nv04_bus_impl *impl = (void *)oclass; - struct nvkm_bus *bus; - int ret; - - ret = nvkm_bus_create(parent, engine, oclass, &bus); - *pobject = nv_object(bus); - if (ret) - return ret; - - nv_subdev(bus)->intr = impl->intr; - bus->hwsq_exec = impl->hwsq_exec; - bus->hwsq_size = impl->hwsq_size; - return 0; + return nvkm_bus_new_(&nv04_bus, device, index, pbus); } - -struct nvkm_oclass * -nv04_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv04_bus_init, - .fini = _nvkm_bus_fini, - }, - .intr = nv04_bus_intr, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h deleted file mode 100644 index e8674f2370c8c..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __NVKM_BUS_NV04_H__ -#define __NVKM_BUS_NV04_H__ -#include - -int nv04_bus_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -int nv50_bus_init(struct nvkm_object *); -void nv50_bus_intr(struct nvkm_subdev *); - -struct nv04_bus_impl { - struct nvkm_oclass base; - void (*intr)(struct nvkm_subdev *); - int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32); - u32 hwsq_size; -}; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c index 2e5340a2c94d1..5153d89e1f0b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c @@ -22,14 +22,15 @@ * Authors: Martin Peres * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" #include #include static void -nv31_bus_intr(struct nvkm_subdev *subdev) +nv31_bus_intr(struct nvkm_bus *bus) { + struct nvkm_subdev *subdev = &bus->subdev; struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); u32 gpio = nvkm_rd32(device, 0x001104) & nvkm_rd32(device, 0x001144); @@ -66,30 +67,22 @@ nv31_bus_intr(struct nvkm_subdev *subdev) } } -static int -nv31_bus_init(struct nvkm_object *object) +static void +nv31_bus_init(struct nvkm_bus *bus) { - struct nvkm_bus *bus = (void *)object; struct nvkm_device *device = bus->subdev.device; - int ret; - - ret = nvkm_bus_init(bus); - if (ret) - return ret; - nvkm_wr32(device, 0x001100, 0xffffffff); nvkm_wr32(device, 0x001140, 0x00070008); - return 0; } -struct nvkm_oclass * -nv31_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x31), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv31_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +nv31_bus = { + .init = nv31_bus_init, .intr = nv31_bus_intr, -}.base; +}; + +int +nv31_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&nv31_bus, device, index, pbus); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c index 3948ec73d31a0..19e10fdc92918 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c @@ -22,7 +22,7 @@ * Authors: Martin Peres * Ben Skeggs */ -#include "nv04.h" +#include "priv.h" #include #include @@ -50,8 +50,9 @@ nv50_bus_hwsq_exec(struct nvkm_bus *bus, u32 *data, u32 size) } void -nv50_bus_intr(struct nvkm_subdev *subdev) +nv50_bus_intr(struct nvkm_bus *bus) { + struct nvkm_subdev *subdev = &bus->subdev; struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x001100) & nvkm_rd32(device, 0x001140); @@ -81,32 +82,24 @@ nv50_bus_intr(struct nvkm_subdev *subdev) } } -int -nv50_bus_init(struct nvkm_object *object) +void +nv50_bus_init(struct nvkm_bus *bus) { - struct nvkm_bus *bus = (void *)object; struct nvkm_device *device = bus->subdev.device; - int ret; - - ret = nvkm_bus_init(bus); - if (ret) - return ret; - nvkm_wr32(device, 0x001100, 0xffffffff); nvkm_wr32(device, 0x001140, 0x00010008); - return 0; } -struct nvkm_oclass * -nv50_bus_oclass = &(struct nv04_bus_impl) { - .base.handle = NV_SUBDEV(BUS, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_bus_ctor, - .dtor = _nvkm_bus_dtor, - .init = nv50_bus_init, - .fini = _nvkm_bus_fini, - }, +static const struct nvkm_bus_func +nv50_bus = { + .init = nv50_bus_init, .intr = nv50_bus_intr, .hwsq_exec = nv50_bus_hwsq_exec, .hwsq_size = 64, -}.base; +}; + +int +nv50_bus_new(struct nvkm_device *device, int index, struct nvkm_bus **pbus) +{ + return nvkm_bus_new_(&nv50_bus, device, index, pbus); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h new file mode 100644 index 0000000000000..a130f2c642d51 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/priv.h @@ -0,0 +1,18 @@ +#ifndef __NVKM_BUS_PRIV_H__ +#define __NVKM_BUS_PRIV_H__ +#define nvkm_bus(p) container_of((p), struct nvkm_bus, subdev) +#include + +struct nvkm_bus_func { + void (*init)(struct nvkm_bus *); + void (*intr)(struct nvkm_bus *); + int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32); + u32 hwsq_size; +}; + +int nvkm_bus_new_(const struct nvkm_bus_func *, struct nvkm_device *, int, + struct nvkm_bus **); + +void nv50_bus_init(struct nvkm_bus *); +void nv50_bus_intr(struct nvkm_bus *); +#endif -- GitLab From 6625f55c080f888ccf51b6881f0bad13f5762d15 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5532/7006] drm/nouveau/clk: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../gpu/drm/nouveau/include/nvkm/subdev/clk.h | 68 ++------ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 132 +++++++-------- .../gpu/drm/nouveau/nvkm/engine/device/ctrl.c | 4 +- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/subdev/clk/Kbuild | 1 + .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 105 +++++++----- drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c | 41 ++--- .../gpu/drm/nouveau/nvkm/subdev/clk/gf100.c | 97 +++++------ .../gpu/drm/nouveau/nvkm/subdev/clk/gk104.c | 83 ++++------ .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 105 +++++------- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 87 +++++----- .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c | 109 ++++++------- .../gpu/drm/nouveau/nvkm/subdev/clk/nv04.c | 47 ++---- .../gpu/drm/nouveau/nvkm/subdev/clk/nv40.c | 75 ++++----- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.c | 153 +++++++++--------- .../gpu/drm/nouveau/nvkm/subdev/clk/nv50.h | 22 +-- .../gpu/drm/nouveau/nvkm/subdev/clk/priv.h | 26 +++ .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 3 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 6 +- 31 files changed, 537 insertions(+), 706 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 15f4528ee130b..230ee81f3f608 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -55,7 +55,7 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) #define nvxx_bar(a) nvxx_device(a)->bar #define nvxx_gpio(a) nvkm_gpio(nvxx_device(a)) -#define nvxx_clk(a) nvkm_clk(nvxx_device(a)) +#define nvxx_clk(a) nvxx_device(a)->clk #define nvxx_i2c(a) nvkm_i2c(nvxx_device(a)) #define nvxx_therm(a) nvkm_therm(nvxx_device(a)) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h index 5c982401e142a..8708f0a4e1880 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h @@ -71,9 +71,10 @@ struct nvkm_domain { }; struct nvkm_clk { + const struct nvkm_clk_func *func; struct nvkm_subdev subdev; - struct nvkm_domain *domains; + const struct nvkm_domain *domains; struct nvkm_pstate bstate; struct list_head states; @@ -94,68 +95,27 @@ struct nvkm_clk { bool allow_reclock; - int (*read)(struct nvkm_clk *, enum nv_clk_src); - int (*calc)(struct nvkm_clk *, struct nvkm_cstate *); - int (*prog)(struct nvkm_clk *); - void (*tidy)(struct nvkm_clk *); - /*XXX: die, these are here *only* to support the completely - * bat-shit insane what-was-nvkm_hw.c code + * bat-shit insane what-was-nouveau_hw.c code */ int (*pll_calc)(struct nvkm_clk *, struct nvbios_pll *, int clk, struct nvkm_pll_vals *pv); int (*pll_prog)(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *pv); }; -static inline struct nvkm_clk * -nvkm_clk(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_CLK); -} - -#define nvkm_clk_create(p,e,o,i,r,s,n,d) \ - nvkm_clk_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \ - (void **)d) -#define nvkm_clk_destroy(p) ({ \ - struct nvkm_clk *_clk = (p); \ - _nvkm_clk_dtor(nv_object(_clk)); \ -}) -#define nvkm_clk_init(p) ({ \ - struct nvkm_clk *_clk = (p); \ - _nvkm_clk_init(nv_object(_clk)); \ -}) -#define nvkm_clk_fini(p,s) ({ \ - struct nvkm_clk *_clk = (p); \ - _nvkm_clk_fini(nv_object(_clk), (s)); \ -}) - -int nvkm_clk_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, - struct nvkm_domain *, struct nvkm_pstate *, - int, bool, int, void **); -void _nvkm_clk_dtor(struct nvkm_object *); -int _nvkm_clk_init(struct nvkm_object *); -int _nvkm_clk_fini(struct nvkm_object *, bool); - -extern struct nvkm_oclass nv04_clk_oclass; -extern struct nvkm_oclass nv40_clk_oclass; -extern struct nvkm_oclass *nv50_clk_oclass; -extern struct nvkm_oclass *g84_clk_oclass; -extern struct nvkm_oclass *mcp77_clk_oclass; -extern struct nvkm_oclass gt215_clk_oclass; -extern struct nvkm_oclass gf100_clk_oclass; -extern struct nvkm_oclass gk104_clk_oclass; -extern struct nvkm_oclass gk20a_clk_oclass; - -int nv04_clk_pll_set(struct nvkm_clk *, u32 type, u32 freq); -int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk, - struct nvkm_pll_vals *); -int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *); -int gt215_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, - int clk, struct nvkm_pll_vals *); - +int nvkm_clk_read(struct nvkm_clk *, enum nv_clk_src); int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr); int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait); int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel); int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel); + +int nv04_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int nv40_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int nv50_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int g84_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int mcp77_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int gt215_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int gf100_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int gk104_clk_new(struct nvkm_device *, int, struct nvkm_clk **); +int gk20a_clk_new(struct nvkm_device *, int, struct nvkm_clk **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 21974c1c4990e..96410defb1f84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -78,7 +78,7 @@ nv4_chipset = { .name = "NV04", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv04_devinit_new, // .fb = nv04_fb_new, // .i2c = nv04_i2c_new, @@ -98,7 +98,7 @@ nv5_chipset = { .name = "NV05", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv05_devinit_new, // .fb = nv04_fb_new, // .i2c = nv04_i2c_new, @@ -118,7 +118,7 @@ nv10_chipset = { .name = "NV10", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, @@ -137,7 +137,7 @@ nv11_chipset = { .name = "NV11", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, @@ -158,7 +158,7 @@ nv15_chipset = { .name = "NV15", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, @@ -179,7 +179,7 @@ nv17_chipset = { .name = "NV17", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, @@ -200,7 +200,7 @@ nv18_chipset = { .name = "NV18", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, @@ -221,7 +221,7 @@ nv1a_chipset = { .name = "nForce", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv1a_fb_new, // .gpio = nv10_gpio_new, @@ -242,7 +242,7 @@ nv1f_chipset = { .name = "nForce2", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv1a_fb_new, // .gpio = nv10_gpio_new, @@ -263,7 +263,7 @@ nv20_chipset = { .name = "NV20", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv20_fb_new, // .gpio = nv10_gpio_new, @@ -284,7 +284,7 @@ nv25_chipset = { .name = "NV25", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv25_fb_new, // .gpio = nv10_gpio_new, @@ -305,7 +305,7 @@ nv28_chipset = { .name = "NV28", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv25_fb_new, // .gpio = nv10_gpio_new, @@ -326,7 +326,7 @@ nv2a_chipset = { .name = "NV2A", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv25_fb_new, // .gpio = nv10_gpio_new, @@ -347,7 +347,7 @@ nv30_chipset = { .name = "NV30", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv30_fb_new, // .gpio = nv10_gpio_new, @@ -368,7 +368,7 @@ nv31_chipset = { .name = "NV31", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv30_fb_new, // .gpio = nv10_gpio_new, @@ -390,7 +390,7 @@ nv34_chipset = { .name = "NV34", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, @@ -412,7 +412,7 @@ nv35_chipset = { .name = "NV35", .bios = nvkm_bios_new, .bus = nv04_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv35_fb_new, // .gpio = nv10_gpio_new, @@ -433,7 +433,7 @@ nv36_chipset = { .name = "NV36", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv04_clk_new, + .clk = nv04_clk_new, // .devinit = nv20_devinit_new, // .fb = nv36_fb_new, // .gpio = nv10_gpio_new, @@ -455,7 +455,7 @@ nv40_chipset = { .name = "NV40", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv40_fb_new, // .gpio = nv10_gpio_new, @@ -480,7 +480,7 @@ nv41_chipset = { .name = "NV41", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, // .gpio = nv10_gpio_new, @@ -505,7 +505,7 @@ nv42_chipset = { .name = "NV42", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, // .gpio = nv10_gpio_new, @@ -530,7 +530,7 @@ nv43_chipset = { .name = "NV43", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, // .gpio = nv10_gpio_new, @@ -555,7 +555,7 @@ nv44_chipset = { .name = "NV44", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv44_fb_new, // .gpio = nv10_gpio_new, @@ -580,7 +580,7 @@ nv45_chipset = { .name = "NV45", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv40_fb_new, // .gpio = nv10_gpio_new, @@ -605,7 +605,7 @@ nv46_chipset = { .name = "G72", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, @@ -630,7 +630,7 @@ nv47_chipset = { .name = "G70", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv47_fb_new, // .gpio = nv10_gpio_new, @@ -655,7 +655,7 @@ nv49_chipset = { .name = "G71", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv49_fb_new, // .gpio = nv10_gpio_new, @@ -680,7 +680,7 @@ nv4a_chipset = { .name = "NV44A", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv44_fb_new, // .gpio = nv10_gpio_new, @@ -705,7 +705,7 @@ nv4b_chipset = { .name = "G73", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv49_fb_new, // .gpio = nv10_gpio_new, @@ -730,7 +730,7 @@ nv4c_chipset = { .name = "C61", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, @@ -755,7 +755,7 @@ nv4e_chipset = { .name = "C51", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv4e_fb_new, // .gpio = nv10_gpio_new, @@ -781,7 +781,7 @@ nv50_chipset = { .bar = nv50_bar_new, .bios = nvkm_bios_new, .bus = nv50_bus_new, -// .clk = nv50_clk_new, + .clk = nv50_clk_new, // .devinit = nv50_devinit_new, // .fb = nv50_fb_new, // .fuse = nv50_fuse_new, @@ -808,7 +808,7 @@ nv63_chipset = { .name = "C73", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, @@ -833,7 +833,7 @@ nv67_chipset = { .name = "C67", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, @@ -858,7 +858,7 @@ nv68_chipset = { .name = "C68", .bios = nvkm_bios_new, .bus = nv31_bus_new, -// .clk = nv40_clk_new, + .clk = nv40_clk_new, // .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, @@ -884,7 +884,7 @@ nv84_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = nv50_bus_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, @@ -915,7 +915,7 @@ nv86_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = nv50_bus_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, @@ -946,7 +946,7 @@ nv92_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = nv50_bus_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, @@ -977,7 +977,7 @@ nv94_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, @@ -1009,7 +1009,7 @@ nv96_chipset = { // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .fuse = nv50_fuse_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .therm = g84_therm_new, // .mxm = nv50_mxm_new, // .devinit = g84_devinit_new, @@ -1040,7 +1040,7 @@ nv98_chipset = { // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .fuse = nv50_fuse_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .therm = g84_therm_new, // .mxm = nv50_mxm_new, // .devinit = g98_devinit_new, @@ -1070,7 +1070,7 @@ nva0_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = g84_clk_new, + .clk = g84_clk_new, // .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, @@ -1101,7 +1101,7 @@ nva3_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = gt215_clk_new, + .clk = gt215_clk_new, // .devinit = gt215_devinit_new, // .fb = gt215_fb_new, // .fuse = nv50_fuse_new, @@ -1134,7 +1134,7 @@ nva5_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = gt215_clk_new, + .clk = gt215_clk_new, // .devinit = gt215_devinit_new, // .fb = gt215_fb_new, // .fuse = nv50_fuse_new, @@ -1166,7 +1166,7 @@ nva8_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = gt215_clk_new, + .clk = gt215_clk_new, // .devinit = gt215_devinit_new, // .fb = gt215_fb_new, // .fuse = nv50_fuse_new, @@ -1198,7 +1198,7 @@ nvaa_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = mcp77_clk_new, + .clk = mcp77_clk_new, // .devinit = g98_devinit_new, // .fb = mcp77_fb_new, // .fuse = nv50_fuse_new, @@ -1229,7 +1229,7 @@ nvac_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = mcp77_clk_new, + .clk = mcp77_clk_new, // .devinit = g98_devinit_new, // .fb = mcp77_fb_new, // .fuse = nv50_fuse_new, @@ -1260,7 +1260,7 @@ nvaf_chipset = { .bar = g84_bar_new, .bios = nvkm_bios_new, .bus = g94_bus_new, -// .clk = gt215_clk_new, + .clk = gt215_clk_new, // .devinit = mcp89_devinit_new, // .fb = mcp89_fb_new, // .fuse = nv50_fuse_new, @@ -1292,7 +1292,7 @@ nvc0_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1327,7 +1327,7 @@ nvc1_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1361,7 +1361,7 @@ nvc3_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1395,7 +1395,7 @@ nvc4_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1430,7 +1430,7 @@ nvc8_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1465,7 +1465,7 @@ nvce_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1500,7 +1500,7 @@ nvcf_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1534,7 +1534,7 @@ nvd7_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1566,7 +1566,7 @@ nvd9_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gf100_clk_new, + .clk = gf100_clk_new, // .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, @@ -1600,7 +1600,7 @@ nve4_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1636,7 +1636,7 @@ nve6_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1672,7 +1672,7 @@ nve7_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1707,7 +1707,7 @@ nvea_chipset = { .name = "GK20A", .bar = gk20a_bar_new, .bus = gf100_bus_new, -// .clk = gk20a_clk_new, + .clk = gk20a_clk_new, // .fb = gk20a_fb_new, // .fuse = gf100_fuse_new, // .ibus = gk20a_ibus_new, @@ -1732,7 +1732,7 @@ nvf0_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1768,7 +1768,7 @@ nvf1_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1804,7 +1804,7 @@ nv106_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1839,7 +1839,7 @@ nv108_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, @@ -1874,7 +1874,7 @@ nv117_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .clk = gk104_clk_new, + .clk = gk104_clk_new, // .devinit = gm107_devinit_new, // .fb = gm107_fb_new, // .fuse = gm107_fuse_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c index f24990a8d60b7..cf8bc068e9b70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c @@ -70,7 +70,7 @@ nvkm_control_mthd_pstate_attr(struct nvkm_control *ctrl, void *data, u32 size) struct nvif_control_pstate_attr_v0 v0; } *args = data; struct nvkm_clk *clk = ctrl->device->clk; - struct nvkm_domain *domain; + const struct nvkm_domain *domain; struct nvkm_pstate *pstate; struct nvkm_cstate *cstate; int i = 0, j = -1; @@ -116,7 +116,7 @@ nvkm_control_mthd_pstate_attr(struct nvkm_control *ctrl, void *data, u32 size) args->v0.state = pstate->pstate; } else { - lo = max(clk->read(clk, domain->name), 0); + lo = max(nvkm_clk_read(clk, domain->name), 0); hi = lo; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 117943075692f..01dcc5a168422 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -31,7 +31,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -60,7 +59,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -89,7 +87,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -117,7 +114,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -146,7 +142,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -174,7 +169,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -202,7 +196,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -231,7 +224,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -259,7 +251,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index bb37f3f190b66..77386ac4dba07 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -31,7 +31,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -61,7 +60,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -91,7 +89,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -118,7 +115,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: - device->oclass[NVDEV_SUBDEV_CLK ] = &gk20a_clk_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; @@ -140,7 +136,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -170,7 +165,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -200,7 +194,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; @@ -229,7 +222,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 2df5bf07f2170..2902bdc5626f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -31,7 +31,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; @@ -69,7 +68,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; #if 0 /* looks to be some non-trivial changes */ - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; /* priv ring says no to 0x10eb14 writes */ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif @@ -106,7 +104,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; #if 0 /* looks to be some non-trivial changes */ - device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass; /* priv ring says no to 0x10eb14 writes */ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 7e77ee0d03e7e..af120691b1322 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -29,7 +29,6 @@ nv04_identify(struct nvkm_device *device) switch (device->chipset) { case 0x04: device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -44,7 +43,6 @@ nv04_identify(struct nvkm_device *device) break; case 0x05: device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index dc51b0c3704c0..884ba56411cac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -30,7 +30,6 @@ nv10_identify(struct nvkm_device *device) case 0x10: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -44,7 +43,6 @@ nv10_identify(struct nvkm_device *device) case 0x15: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -60,7 +58,6 @@ nv10_identify(struct nvkm_device *device) case 0x16: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -76,7 +73,6 @@ nv10_identify(struct nvkm_device *device) case 0x1a: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -92,7 +88,6 @@ nv10_identify(struct nvkm_device *device) case 0x11: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -108,7 +103,6 @@ nv10_identify(struct nvkm_device *device) case 0x17: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -124,7 +118,6 @@ nv10_identify(struct nvkm_device *device) case 0x1f: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -140,7 +133,6 @@ nv10_identify(struct nvkm_device *device) case 0x18: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index ef09f62e21bbc..d18d702a10621 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -30,7 +30,6 @@ nv20_identify(struct nvkm_device *device) case 0x20: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -46,7 +45,6 @@ nv20_identify(struct nvkm_device *device) case 0x25: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -62,7 +60,6 @@ nv20_identify(struct nvkm_device *device) case 0x28: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -78,7 +75,6 @@ nv20_identify(struct nvkm_device *device) case 0x2a: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 1c26b9b81ba40..04f79162adc1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -30,7 +30,6 @@ nv30_identify(struct nvkm_device *device) case 0x30: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -46,7 +45,6 @@ nv30_identify(struct nvkm_device *device) case 0x35: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -62,7 +60,6 @@ nv30_identify(struct nvkm_device *device) case 0x31: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -79,7 +76,6 @@ nv30_identify(struct nvkm_device *device) case 0x36: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -96,7 +92,6 @@ nv30_identify(struct nvkm_device *device) case 0x34: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index b97cceb711376..b4ca9c8cbec6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -30,7 +30,6 @@ nv40_identify(struct nvkm_device *device) case 0x40: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -50,7 +49,6 @@ nv40_identify(struct nvkm_device *device) case 0x41: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -70,7 +68,6 @@ nv40_identify(struct nvkm_device *device) case 0x42: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -90,7 +87,6 @@ nv40_identify(struct nvkm_device *device) case 0x43: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -110,7 +106,6 @@ nv40_identify(struct nvkm_device *device) case 0x45: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -130,7 +125,6 @@ nv40_identify(struct nvkm_device *device) case 0x47: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -150,7 +144,6 @@ nv40_identify(struct nvkm_device *device) case 0x49: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -170,7 +163,6 @@ nv40_identify(struct nvkm_device *device) case 0x4b: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -190,7 +182,6 @@ nv40_identify(struct nvkm_device *device) case 0x44: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; @@ -210,7 +201,6 @@ nv40_identify(struct nvkm_device *device) case 0x46: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -230,7 +220,6 @@ nv40_identify(struct nvkm_device *device) case 0x4a: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; @@ -250,7 +239,6 @@ nv40_identify(struct nvkm_device *device) case 0x4c: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -270,7 +258,6 @@ nv40_identify(struct nvkm_device *device) case 0x4e: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -290,7 +277,6 @@ nv40_identify(struct nvkm_device *device) case 0x63: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -310,7 +296,6 @@ nv40_identify(struct nvkm_device *device) case 0x67: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -330,7 +315,6 @@ nv40_identify(struct nvkm_device *device) case 0x68: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index d071d57e6cf7f..5d5a4b23771b7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -31,7 +31,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = nv50_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass; @@ -53,7 +52,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; @@ -78,7 +76,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; @@ -103,7 +100,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; @@ -128,7 +124,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; @@ -153,7 +148,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; @@ -178,7 +172,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; @@ -203,7 +196,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; @@ -228,7 +220,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; @@ -253,7 +244,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; @@ -278,7 +268,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; @@ -305,7 +294,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; @@ -331,7 +319,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; @@ -357,7 +344,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; - device->oclass[NVDEV_SUBDEV_CLK ] = >215_clk_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_DEVINIT] = mcp89_devinit_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild index 9c2f688c9602c..ed7717bcc3a1a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild @@ -8,5 +8,6 @@ nvkm-y += nvkm/subdev/clk/mcp77.o nvkm-y += nvkm/subdev/clk/gf100.o nvkm-y += nvkm/subdev/clk/gk104.o nvkm-y += nvkm/subdev/clk/gk20a.o + nvkm-y += nvkm/subdev/clk/pllnv04.o nvkm-y += nvkm/subdev/clk/pllgt215.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index c99385329ef40..cdb87e2900f18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" + #include #include #include @@ -105,10 +106,10 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) } } - ret = clk->calc(clk, cstate); + ret = clk->func->calc(clk, cstate); if (ret == 0) { - ret = clk->prog(clk); - clk->tidy(clk); + ret = clk->func->prog(clk); + clk->func->tidy(clk); } if (volt) { @@ -137,7 +138,7 @@ static int nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate) { struct nvkm_bios *bios = clk->subdev.device->bios; - struct nvkm_domain *domain = clk->domains; + const struct nvkm_domain *domain = clk->domains; struct nvkm_cstate *cstate = NULL; struct nvbios_cstepX cstepX; u8 ver, hdr; @@ -249,7 +250,7 @@ nvkm_pstate_calc(struct nvkm_clk *clk, bool wait) static void nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate) { - struct nvkm_domain *clock = clk->domains - 1; + const struct nvkm_domain *clock = clk->domains - 1; struct nvkm_cstate *cstate; struct nvkm_subdev *subdev = &clk->subdev; char info[3][32] = { "", "", "" }; @@ -306,7 +307,7 @@ static int nvkm_pstate_new(struct nvkm_clk *clk, int idx) { struct nvkm_bios *bios = clk->subdev.device->bios; - struct nvkm_domain *domain = clk->domains - 1; + const struct nvkm_domain *domain = clk->domains - 1; struct nvkm_pstate *pstate; struct nvkm_cstate *cstate; struct nvbios_cstepE cstepE; @@ -475,31 +476,35 @@ nvkm_clk_pwrsrc(struct nvkm_notify *notify) *****************************************************************************/ int -_nvkm_clk_fini(struct nvkm_object *object, bool suspend) +nvkm_clk_read(struct nvkm_clk *clk, enum nv_clk_src src) { - struct nvkm_clk *clk = (void *)object; + return clk->func->read(clk, src); +} + +static int +nvkm_clk_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_clk *clk = nvkm_clk(subdev); nvkm_notify_put(&clk->pwrsrc_ntfy); - return nvkm_subdev_fini_old(&clk->subdev, suspend); + flush_work(&clk->work); + if (clk->func->fini) + clk->func->fini(clk); + return 0; } -int -_nvkm_clk_init(struct nvkm_object *object) +static int +nvkm_clk_init(struct nvkm_subdev *subdev) { - struct nvkm_clk *clk = (void *)object; - struct nvkm_subdev *subdev = &clk->subdev; - struct nvkm_domain *clock = clk->domains; + struct nvkm_clk *clk = nvkm_clk(subdev); + const struct nvkm_domain *clock = clk->domains; int ret; - ret = nvkm_subdev_init_old(&clk->subdev); - if (ret) - return ret; - memset(&clk->bstate, 0x00, sizeof(clk->bstate)); INIT_LIST_HEAD(&clk->bstate.list); clk->bstate.pstate = 0xff; while (clock->name != nv_clk_src_max) { - ret = clk->read(clk, clock->name); + ret = nvkm_clk_read(clk, clock->name); if (ret < 0) { nvkm_error(subdev, "%02x freq unknown\n", clock->name); return ret; @@ -510,6 +515,9 @@ _nvkm_clk_init(struct nvkm_object *object) nvkm_pstate_info(clk, &clk->bstate); + if (clk->func->init) + return clk->func->init(clk); + clk->astate = clk->state_nr - 1; clk->tstate = 0; clk->dstate = 0; @@ -518,61 +526,63 @@ _nvkm_clk_init(struct nvkm_object *object) return 0; } -void -_nvkm_clk_dtor(struct nvkm_object *object) +static void * +nvkm_clk_dtor(struct nvkm_subdev *subdev) { - struct nvkm_clk *clk = (void *)object; + struct nvkm_clk *clk = nvkm_clk(subdev); struct nvkm_pstate *pstate, *temp; nvkm_notify_fini(&clk->pwrsrc_ntfy); + /* Early return if the pstates have been provided statically */ + if (clk->func->pstates) + return clk; + list_for_each_entry_safe(pstate, temp, &clk->states, head) { nvkm_pstate_del(pstate); } - nvkm_subdev_destroy(&clk->subdev); + return clk; } +static const struct nvkm_subdev_func +nvkm_clk = { + .dtor = nvkm_clk_dtor, + .init = nvkm_clk_init, + .fini = nvkm_clk_fini, +}; + int -nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, struct nvkm_domain *clocks, - struct nvkm_pstate *pstates, int nb_pstates, - bool allow_reclock, int length, void **object) +nvkm_clk_ctor(const struct nvkm_clk_func *func, struct nvkm_device *device, + int index, bool allow_reclock, struct nvkm_clk *clk) { - struct nvkm_device *device = nv_device(parent); - struct nvkm_clk *clk; int ret, idx, arglen; const char *mode; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "CLK", - "clock", length, object); - clk = *object; - if (ret) - return ret; - + nvkm_subdev_ctor(&nvkm_clk, device, index, 0, &clk->subdev); + clk->func = func; INIT_LIST_HEAD(&clk->states); - clk->domains = clocks; + clk->domains = func->domains; clk->ustate_ac = -1; clk->ustate_dc = -1; + clk->allow_reclock = allow_reclock; INIT_WORK(&clk->work, nvkm_pstate_work); init_waitqueue_head(&clk->wait); atomic_set(&clk->waiting, 0); /* If no pstates are provided, try and fetch them from the BIOS */ - if (!pstates) { + if (!func->pstates) { idx = 0; do { ret = nvkm_pstate_new(clk, idx++); } while (ret == 0); } else { - for (idx = 0; idx < nb_pstates; idx++) - list_add_tail(&pstates[idx].head, &clk->states); - clk->state_nr = nb_pstates; + for (idx = 0; idx < func->nr_pstates; idx++) + list_add_tail(&func->pstates[idx].head, &clk->states); + clk->state_nr = func->nr_pstates; } - clk->allow_reclock = allow_reclock; - ret = nvkm_notify_init(NULL, &device->event, nvkm_clk_pwrsrc, true, NULL, 0, 0, &clk->pwrsrc_ntfy); if (ret) @@ -594,3 +604,12 @@ nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } + +int +nvkm_clk_new_(const struct nvkm_clk_func *func, struct nvkm_device *device, + int index, bool allow_reclock, struct nvkm_clk **pclk) +{ + if (!(*pclk = kzalloc(sizeof(**pclk), GFP_KERNEL))) + return -ENOMEM; + return nvkm_clk_ctor(func, device, index, allow_reclock, *pclk); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c index 4c90b9769d646..347da9ee20f53 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c @@ -23,25 +23,26 @@ */ #include "nv50.h" -static struct nvkm_domain -g84_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0xff }, - { nv_clk_src_max } +static const struct nvkm_clk_func +g84_clk = { + .read = nv50_clk_read, + .calc = nv50_clk_calc, + .prog = nv50_clk_prog, + .tidy = nv50_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0xff }, + { nv_clk_src_max } + } }; -struct nvkm_oclass * -g84_clk_oclass = &(struct nv50_clk_oclass) { - .base.handle = NV_SUBDEV(CLK, 0x84), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, - .domains = g84_domains, -}.base; +int +g84_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) +{ + return nv50_clk_new_(&g84_clk, device, index, + (device->chipset == 0xa0), pclk); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c index 966eeb51d7718..a52b7e7fce412 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include +#define gf100_clk(p) container_of((p), struct gf100_clk, base) +#include "priv.h" #include "pll.h" #include @@ -50,8 +51,8 @@ read_vco(struct gf100_clk *clk, u32 dsrc) struct nvkm_device *device = clk->base.subdev.device; u32 ssrc = nvkm_rd32(device, dsrc); if (!(ssrc & 0x00000100)) - return clk->base.read(&clk->base, nv_clk_src_sppll0); - return clk->base.read(&clk->base, nv_clk_src_sppll1); + return nvkm_clk_read(&clk->base, nv_clk_src_sppll0); + return nvkm_clk_read(&clk->base, nv_clk_src_sppll1); } static u32 @@ -75,10 +76,10 @@ read_pll(struct gf100_clk *clk, u32 pll) P = 1; break; case 0x132000: - sclk = clk->base.read(&clk->base, nv_clk_src_mpllsrc); + sclk = nvkm_clk_read(&clk->base, nv_clk_src_mpllsrc); break; case 0x132020: - sclk = clk->base.read(&clk->base, nv_clk_src_mpllsrcref); + sclk = nvkm_clk_read(&clk->base, nv_clk_src_mpllsrcref); break; case 0x137000: case 0x137020: @@ -146,9 +147,9 @@ read_clk(struct gf100_clk *clk, int idx) } static int -gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +gf100_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct gf100_clk *clk = container_of(obj, typeof(*clk), base); + struct gf100_clk *clk = gf100_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; @@ -172,8 +173,8 @@ gf100_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) return read_div(clk, 0, 0x137300, 0x137310); case nv_clk_src_mem: if (nvkm_rd32(device, 0x1373f0) & 0x00000002) - return clk->base.read(&clk->base, nv_clk_src_mpll); - return clk->base.read(&clk->base, nv_clk_src_mdiv); + return nvkm_clk_read(&clk->base, nv_clk_src_mpll); + return nvkm_clk_read(&clk->base, nv_clk_src_mdiv); case nv_clk_src_gpc: return read_clk(clk, 0x00); @@ -313,9 +314,9 @@ calc_clk(struct gf100_clk *clk, struct nvkm_cstate *cstate, int idx, int dom) } static int -gf100_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +gf100_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gf100_clk *clk = container_of(obj, typeof(*clk), base); + struct gf100_clk *clk = gf100_clk(base); int ret; if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) || @@ -398,9 +399,9 @@ gf100_clk_prog_4(struct gf100_clk *clk, int idx) } static int -gf100_clk_prog(struct nvkm_clk *obj) +gf100_clk_prog(struct nvkm_clk *base) { - struct gf100_clk *clk = container_of(obj, typeof(*clk), base); + struct gf100_clk *clk = gf100_clk(base); struct { void (*exec)(struct gf100_clk *, int); } stage[] = { @@ -424,56 +425,42 @@ gf100_clk_prog(struct nvkm_clk *obj) } static void -gf100_clk_tidy(struct nvkm_clk *obj) +gf100_clk_tidy(struct nvkm_clk *base) { - struct gf100_clk *clk = container_of(obj, typeof(*clk), base); + struct gf100_clk *clk = gf100_clk(base); memset(clk->eng, 0x00, sizeof(clk->eng)); } -static struct nvkm_domain -gf100_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_hubk06 , 0x00 }, - { nv_clk_src_hubk01 , 0x01 }, - { nv_clk_src_copy , 0x02 }, - { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, - { nv_clk_src_rop , 0x04 }, - { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x06 }, - { nv_clk_src_daemon , 0x0a }, - { nv_clk_src_hubk07 , 0x0b }, - { nv_clk_src_max } +static const struct nvkm_clk_func +gf100_clk = { + .read = gf100_clk_read, + .calc = gf100_clk_calc, + .prog = gf100_clk_prog, + .tidy = gf100_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_hubk06 , 0x00 }, + { nv_clk_src_hubk01 , 0x01 }, + { nv_clk_src_copy , 0x02 }, + { nv_clk_src_gpc , 0x03, 0, "core", 2000 }, + { nv_clk_src_rop , 0x04 }, + { nv_clk_src_mem , 0x05, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x0a }, + { nv_clk_src_hubk07 , 0x0b }, + { nv_clk_src_max } + } }; -static int -gf100_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { struct gf100_clk *clk; - int ret; - ret = nvkm_clk_create(parent, engine, oclass, gf100_domain, - NULL, 0, false, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - clk->base.read = gf100_clk_read; - clk->base.calc = gf100_clk_calc; - clk->base.prog = gf100_clk_prog; - clk->base.tidy = gf100_clk_tidy; - return 0; + return nvkm_clk_ctor(&gf100_clk, device, index, false, &clk->base); } - -struct nvkm_oclass -gf100_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c index 2aea8fd23c037..396f7e4dad0ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include +#define gk104_clk(p) container_of((p), struct gk104_clk, base) +#include "priv.h" #include "pll.h" #include @@ -185,9 +186,9 @@ read_clk(struct gk104_clk *clk, int idx) } static int -gk104_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +gk104_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct gk104_clk *clk = container_of(obj, typeof(*clk), base); + struct gk104_clk *clk = gk104_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; @@ -335,9 +336,9 @@ calc_clk(struct gk104_clk *clk, } static int -gk104_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +gk104_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gk104_clk *clk = container_of(obj, typeof(*clk), base); + struct gk104_clk *clk = gk104_clk(base); int ret; if ((ret = calc_clk(clk, cstate, 0x00, nv_clk_src_gpc)) || @@ -438,9 +439,9 @@ gk104_clk_prog_4_1(struct gk104_clk *clk, int idx) } static int -gk104_clk_prog(struct nvkm_clk *obj) +gk104_clk_prog(struct nvkm_clk *base) { - struct gk104_clk *clk = container_of(obj, typeof(*clk), base); + struct gk104_clk *clk = gk104_clk(base); struct { u32 mask; void (*exec)(struct gk104_clk *, int); @@ -469,55 +470,41 @@ gk104_clk_prog(struct nvkm_clk *obj) } static void -gk104_clk_tidy(struct nvkm_clk *obj) +gk104_clk_tidy(struct nvkm_clk *base) { - struct gk104_clk *clk = container_of(obj, typeof(*clk), base); + struct gk104_clk *clk = gk104_clk(base); memset(clk->eng, 0x00, sizeof(clk->eng)); } -static struct nvkm_domain -gk104_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, - { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_mem , 0x03, 0, "memory", 500 }, - { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, - { nv_clk_src_hubk01 , 0x05 }, - { nv_clk_src_vdec , 0x06 }, - { nv_clk_src_daemon , 0x07 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +gk104_clk = { + .read = gk104_clk_read, + .calc = gk104_clk_calc, + .prog = gk104_clk_prog, + .tidy = gk104_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 }, + { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_mem , 0x03, 0, "memory", 500 }, + { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE }, + { nv_clk_src_hubk01 , 0x05 }, + { nv_clk_src_vdec , 0x06 }, + { nv_clk_src_daemon , 0x07 }, + { nv_clk_src_max } + } }; -static int -gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { struct gk104_clk *clk; - int ret; - ret = nvkm_clk_create(parent, engine, oclass, gk104_domain, - NULL, 0, true, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - clk->base.read = gk104_clk_read; - clk->base.calc = gk104_clk_calc; - clk->base.prog = gk104_clk_prog; - clk->base.tidy = gk104_clk_tidy; - return 0; + return nvkm_clk_ctor(&gk104_clk, device, index, true, &clk->base); } - -struct nvkm_oclass -gk104_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index ce89955ff8f9b..6a74ce3730d05 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -22,7 +22,9 @@ * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c * */ -#include +#define gk20a_clk(p) container_of((p), struct gk20a_clk, base) +#include "priv.h" + #include #ifdef __KERNEL__ @@ -121,7 +123,6 @@ struct gk20a_clk { u32 m, n, pl; u32 parent_rate; }; -#define to_gk20a_clk(base) container_of(base, struct gk20a_clk, base) static void gk20a_pllg_read_mnp(struct gk20a_clk *clk) @@ -467,13 +468,6 @@ gk20a_pllg_disable(struct gk20a_clk *clk) #define GK20A_CLK_GPC_MDIV 1000 -static struct nvkm_domain -gk20a_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, - { nv_clk_src_max } -}; - static struct nvkm_pstate gk20a_pstates[] = { { @@ -569,9 +563,9 @@ gk20a_pstates[] = { }; static int -gk20a_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +gk20a_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); + struct gk20a_clk *clk = gk20a_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; @@ -588,54 +582,44 @@ gk20a_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) } static int -gk20a_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +gk20a_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); + struct gk20a_clk *clk = gk20a_clk(base); return gk20a_pllg_calc_mnp(clk, cstate->domain[nv_clk_src_gpc] * GK20A_CLK_GPC_MDIV); } static int -gk20a_clk_prog(struct nvkm_clk *obj) +gk20a_clk_prog(struct nvkm_clk *base) { - struct gk20a_clk *clk = container_of(obj, typeof(*clk), base); + struct gk20a_clk *clk = gk20a_clk(base); return gk20a_pllg_program_mnp(clk); } static void -gk20a_clk_tidy(struct nvkm_clk *obj) +gk20a_clk_tidy(struct nvkm_clk *base) { } -static int -gk20a_clk_fini(struct nvkm_object *object, bool suspend) +static void +gk20a_clk_fini(struct nvkm_clk *base) { - struct gk20a_clk *clk = (void *)object; - int ret; - - ret = nvkm_clk_fini(&clk->base, false); - + struct gk20a_clk *clk = gk20a_clk(base); gk20a_pllg_disable(clk); - - return ret; } static int -gk20a_clk_init(struct nvkm_object *object) +gk20a_clk_init(struct nvkm_clk *base) { - struct gk20a_clk *clk = (void *)object; + struct gk20a_clk *clk = gk20a_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; int ret; nvkm_mask(device, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL); - ret = nvkm_clk_init(&clk->base); - if (ret) - return ret; - ret = gk20a_clk_prog(&clk->base); if (ret) { nvkm_error(subdev, "cannot initialize clock\n"); @@ -645,15 +629,32 @@ gk20a_clk_init(struct nvkm_object *object) return 0; } -static int -gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_clk_func +gk20a_clk = { + .init = gk20a_clk_init, + .fini = gk20a_clk_fini, + .read = gk20a_clk_read, + .calc = gk20a_clk_calc, + .prog = gk20a_clk_prog, + .tidy = gk20a_clk_tidy, + .pstates = gk20a_pstates, + .nr_pstates = ARRAY_SIZE(gk20a_pstates), + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV }, + { nv_clk_src_max } + } +}; + +int +gk20a_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct nvkm_device *device = (void *)parent; struct gk20a_clk *clk; - int ret; - int i; + int ret, i; + + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; /* Finish initializing the pstates */ for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) { @@ -661,33 +662,11 @@ gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, gk20a_pstates[i].pstate = i + 1; } - ret = nvkm_clk_create(parent, engine, oclass, gk20a_domains, - gk20a_pstates, ARRAY_SIZE(gk20a_pstates), - true, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; - clk->params = &gk20a_pllg_params; - clk->parent_rate = clk_get_rate(device->gpu->clk); + + ret = nvkm_clk_ctor(&gk20a_clk, device, index, true, &clk->base); nvkm_info(&clk->base.subdev, "parent clock rate: %d Mhz\n", clk->parent_rate / MHZ); - - clk->base.read = gk20a_clk_read; - clk->base.calc = gk20a_clk_calc; - clk->base.prog = gk20a_clk_prog; - clk->base.tidy = gk20a_clk_tidy; - return 0; + return ret; } - -struct nvkm_oclass -gk20a_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_clk_ctor, - .dtor = _nvkm_subdev_dtor, - .init = gk20a_clk_init, - .fini = gk20a_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index d01847d25d7f1..e5258ba19834e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs * Roy Spliet */ +#define gt215_clk(p) container_of((p), struct gt215_clk, base) #include "gt215.h" #include "pll.h" @@ -136,9 +137,9 @@ read_pll(struct gt215_clk *clk, int idx, u32 pll) } static int -gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +gt215_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct gt215_clk *clk = gt215_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; u32 hsrc; @@ -180,10 +181,10 @@ gt215_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) } int -gt215_clk_info(struct nvkm_clk *obj, int idx, u32 khz, +gt215_clk_info(struct nvkm_clk *base, int idx, u32 khz, struct gt215_clk_info *info) { - struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct gt215_clk *clk = gt215_clk(base); u32 oclk, sclk, sdiv; s32 diff; @@ -228,10 +229,10 @@ gt215_clk_info(struct nvkm_clk *obj, int idx, u32 khz, } int -gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, +gt215_pll_info(struct nvkm_clk *base, int idx, u32 pll, u32 khz, struct gt215_clk_info *info) { - struct gt215_clk *clk = (void *)clock; + struct gt215_clk *clk = gt215_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvbios_pll limits; int P, N, M, diff; @@ -241,7 +242,7 @@ gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, /* If we can get a within [-2, 3) MHz of a divider, we'll disable the * PLL and use the divider instead. */ - ret = gt215_clk_info(clock, idx, khz, info); + ret = gt215_clk_info(&clk->base, idx, khz, info); diff = khz - ret; if (!pll || (diff >= -2000 && diff < 3000)) { goto out; @@ -252,7 +253,7 @@ gt215_pll_info(struct nvkm_clk *clock, int idx, u32 pll, u32 khz, if (ret) return ret; - ret = gt215_clk_info(clock, idx - 0x10, limits.refclk, info); + ret = gt215_clk_info(&clk->base, idx - 0x10, limits.refclk, info); if (ret != limits.refclk) return -EINVAL; @@ -452,9 +453,9 @@ prog_core(struct gt215_clk *clk, int dom) } static int -gt215_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +gt215_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct gt215_clk *clk = gt215_clk(base); struct gt215_clk_info *core = &clk->eng[nv_clk_src_core]; int ret; @@ -479,9 +480,9 @@ gt215_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) } static int -gt215_clk_prog(struct nvkm_clk *obj) +gt215_clk_prog(struct nvkm_clk *base) { - struct gt215_clk *clk = container_of(obj, typeof(*clk), base); + struct gt215_clk *clk = gt215_clk(base); struct gt215_clk_info *core = &clk->eng[nv_clk_src_core]; int ret = 0; unsigned long flags; @@ -509,51 +510,37 @@ out: } static void -gt215_clk_tidy(struct nvkm_clk *obj) +gt215_clk_tidy(struct nvkm_clk *base) { } -static struct nvkm_domain -gt215_domain[] = { - { nv_clk_src_crystal , 0xff }, - { nv_clk_src_core , 0x00, 0, "core", 1000 }, - { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, - { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, - { nv_clk_src_vdec , 0x03 }, - { nv_clk_src_disp , 0x04 }, - { nv_clk_src_host , 0x05 }, - { nv_clk_src_core_intm, 0x06 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +gt215_clk = { + .read = gt215_clk_read, + .calc = gt215_clk_calc, + .prog = gt215_clk_prog, + .tidy = gt215_clk_tidy, + .domains = { + { nv_clk_src_crystal , 0xff }, + { nv_clk_src_core , 0x00, 0, "core", 1000 }, + { nv_clk_src_shader , 0x01, 0, "shader", 1000 }, + { nv_clk_src_mem , 0x02, 0, "memory", 1000 }, + { nv_clk_src_vdec , 0x03 }, + { nv_clk_src_disp , 0x04 }, + { nv_clk_src_host , 0x05 }, + { nv_clk_src_core_intm, 0x06 }, + { nv_clk_src_max } + } }; -static int -gt215_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt215_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { struct gt215_clk *clk; - int ret; - ret = nvkm_clk_create(parent, engine, oclass, gt215_domain, - NULL, 0, true, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - clk->base.read = gt215_clk_read; - clk->base.calc = gt215_clk_calc; - clk->base.prog = gt215_clk_prog; - clk->base.tidy = gt215_clk_tidy; - return 0; + return nvkm_clk_ctor(>215_clk, device, index, true, &clk->base); } - -struct nvkm_oclass -gt215_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h index 39b0ef8187ea8..8865b59fe5752 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h @@ -1,6 +1,6 @@ #ifndef __NVKM_CLK_NVA3_H__ #define __NVKM_CLK_NVA3_H__ -#include +#include "priv.h" struct gt215_clk_info { u32 clk; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c index b2be8a6acfc16..1c21b8b53b78b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c @@ -21,6 +21,7 @@ * * Authors: Ben Skeggs */ +#define mcp77_clk(p) container_of((p), struct mcp77_clk, base) #include "gt215.h" #include "pll.h" @@ -50,7 +51,7 @@ read_pll(struct mcp77_clk *clk, u32 base) struct nvkm_device *device = clk->base.subdev.device; u32 ctrl = nvkm_rd32(device, base + 0); u32 coef = nvkm_rd32(device, base + 4); - u32 ref = clk->base.read(&clk->base, nv_clk_src_href); + u32 ref = nvkm_clk_read(&clk->base, nv_clk_src_href); u32 post_div = 0; u32 clock = 0; int N1, M1; @@ -77,9 +78,9 @@ read_pll(struct mcp77_clk *clk, u32 base) } static int -mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +mcp77_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); + struct mcp77_clk *clk = mcp77_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; u32 mast = nvkm_rd32(device, 0x00c054); @@ -91,38 +92,38 @@ mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclkm4: - return clk->base.read(&clk->base, nv_clk_src_href) * 4; + return nvkm_clk_read(&clk->base, nv_clk_src_href) * 4; case nv_clk_src_hclkm2d3: - return clk->base.read(&clk->base, nv_clk_src_href) * 2 / 3; + return nvkm_clk_read(&clk->base, nv_clk_src_href) * 2 / 3; case nv_clk_src_host: switch (mast & 0x000c0000) { - case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_hclkm2d3); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm2d3); case 0x00040000: break; - case 0x00080000: return clk->base.read(&clk->base, nv_clk_src_hclkm4); - case 0x000c0000: return clk->base.read(&clk->base, nv_clk_src_cclk); + case 0x00080000: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4); + case 0x000c0000: return nvkm_clk_read(&clk->base, nv_clk_src_cclk); } break; case nv_clk_src_core: P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { - case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000001: return 0; - case 0x00000002: return clk->base.read(&clk->base, nv_clk_src_hclkm4) >> P; + case 0x00000002: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4) >> P; case 0x00000003: return read_pll(clk, 0x004028) >> P; } break; case nv_clk_src_cclk: if ((mast & 0x03000000) != 0x03000000) - return clk->base.read(&clk->base, nv_clk_src_core); + return nvkm_clk_read(&clk->base, nv_clk_src_core); if ((mast & 0x00000200) == 0x00000000) - return clk->base.read(&clk->base, nv_clk_src_core); + return nvkm_clk_read(&clk->base, nv_clk_src_core); switch (mast & 0x00000c00) { - case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_href); - case 0x00000400: return clk->base.read(&clk->base, nv_clk_src_hclkm4); - case 0x00000800: return clk->base.read(&clk->base, nv_clk_src_hclkm2d3); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_href); + case 0x00000400: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm4); + case 0x00000800: return nvkm_clk_read(&clk->base, nv_clk_src_hclkm2d3); default: return 0; } case nv_clk_src_shader: @@ -130,8 +131,8 @@ mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000040) - return clk->base.read(&clk->base, nv_clk_src_href) >> P; - return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_href) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000010: break; case 0x00000020: return read_pll(clk, 0x004028) >> P; case 0x00000030: return read_pll(clk, 0x004020) >> P; @@ -145,7 +146,7 @@ mcp77_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) switch (mast & 0x00400000) { case 0x00400000: - return clk->base.read(&clk->base, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; break; default: return 500000 >> P; @@ -173,7 +174,7 @@ calc_pll(struct mcp77_clk *clk, u32 reg, return 0; pll.vco2.max_freq = 0; - pll.refclk = clk->base.read(&clk->base, nv_clk_src_href); + pll.refclk = nvkm_clk_read(&clk->base, nv_clk_src_href); if (!pll.refclk) return 0; @@ -199,9 +200,9 @@ calc_P(u32 src, u32 target, int *div) } static int -mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +mcp77_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); + struct mcp77_clk *clk = mcp77_clk(base); const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; @@ -211,8 +212,8 @@ mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) int divs = 0; /* cclk: find suitable source, disable PLL if we can */ - if (core < clk->base.read(&clk->base, nv_clk_src_hclkm4)) - out = calc_P(clk->base.read(&clk->base, nv_clk_src_hclkm4), core, &divs); + if (core < nvkm_clk_read(&clk->base, nv_clk_src_hclkm4)) + out = calc_P(nvkm_clk_read(&clk->base, nv_clk_src_hclkm4), core, &divs); /* Calculate clock * 2, so shader clock can use it too */ clock = calc_pll(clk, 0x4028, (core << 1), &N, &M, &P1); @@ -238,7 +239,7 @@ mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) /* sclk: nvpll + divisor, href or spll */ out = 0; - if (shader == clk->base.read(&clk->base, nv_clk_src_href)) { + if (shader == nvkm_clk_read(&clk->base, nv_clk_src_href)) { clk->ssrc = nv_clk_src_href; } else { clock = calc_pll(clk, 0x4020, shader, &N, &M, &P1); @@ -295,9 +296,9 @@ mcp77_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) } static int -mcp77_clk_prog(struct nvkm_clk *obj) +mcp77_clk_prog(struct nvkm_clk *base) { - struct mcp77_clk *clk = container_of(obj, typeof(*clk), base); + struct mcp77_clk *clk = mcp77_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; u32 pllmask = 0, mast; @@ -389,48 +390,34 @@ out: } static void -mcp77_clk_tidy(struct nvkm_clk *obj) +mcp77_clk_tidy(struct nvkm_clk *base) { } -static struct nvkm_domain -mcp77_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +mcp77_clk = { + .read = mcp77_clk_read, + .calc = mcp77_clk_calc, + .prog = mcp77_clk_prog, + .tidy = mcp77_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 }, + { nv_clk_src_max } + } }; -static int -mcp77_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +mcp77_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { struct mcp77_clk *clk; - int ret; - ret = nvkm_clk_create(parent, engine, oclass, mcp77_domains, - NULL, 0, true, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + *pclk = &clk->base; - clk->base.read = mcp77_clk_read; - clk->base.calc = mcp77_clk_calc; - clk->base.prog = mcp77_clk_prog; - clk->base.tidy = mcp77_clk_tidy; - return 0; + return nvkm_clk_ctor(&mcp77_clk, device, index, true, &clk->base); } - -struct nvkm_oclass * -mcp77_clk_oclass = &(struct nvkm_oclass) { - .handle = NV_SUBDEV(CLK, 0xaa), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = mcp77_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c index 5ad4a13a297d4..b280f85e88274 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" #include "pll.h" #include @@ -33,7 +33,7 @@ nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info, int clk, struct nvkm_pll_vals *pv) { int N1, M1, N2, M2, P; - int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P); + int ret = nv04_pll_calc(&clock->subdev, info, clk, &N1, &M1, &N2, &M2, &P); if (ret) { pv->refclk = info->refclk; pv->N1 = N1; @@ -64,37 +64,20 @@ nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv) return 0; } -static struct nvkm_domain -nv04_domain[] = { - { nv_clk_src_max } +static const struct nvkm_clk_func +nv04_clk = { + .domains = { + { nv_clk_src_max } + } }; -static int -nv04_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv04_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { - struct nvkm_clk *clk; - int ret; - - ret = nvkm_clk_create(parent, engine, oclass, nv04_domain, - NULL, 0, false, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; - - clk->pll_calc = nv04_clk_pll_calc; - clk->pll_prog = nv04_clk_pll_prog; - return 0; + int ret = nvkm_clk_new_(&nv04_clk, device, index, false, pclk); + if (ret == 0) { + (*pclk)->pll_calc = nv04_clk_pll_calc; + (*pclk)->pll_prog = nv04_clk_pll_prog; + } + return ret; } - -struct nvkm_oclass -nv04_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c index 2f1a638bd307e..2ab9b9b840186 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include +#define nv40_clk(p) container_of((p), struct nv40_clk, base) +#include "priv.h" #include "pll.h" #include @@ -35,16 +36,6 @@ struct nv40_clk { u32 spll; }; -static struct nvkm_domain -nv40_domain[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_max } -}; - static u32 read_pll_1(struct nv40_clk *clk, u32 reg) { @@ -103,9 +94,9 @@ read_clk(struct nv40_clk *clk, u32 src) } static int -nv40_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +nv40_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct nv40_clk *clk = container_of(obj, typeof(*clk), base); + struct nv40_clk *clk = nv40_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; u32 mast = nvkm_rd32(device, 0x00c040); @@ -152,9 +143,9 @@ nv40_clk_calc_pll(struct nv40_clk *clk, u32 reg, u32 khz, } static int -nv40_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +nv40_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct nv40_clk *clk = container_of(obj, typeof(*clk), base); + struct nv40_clk *clk = nv40_clk(base); int gclk = cstate->domain[nv_clk_src_core]; int sclk = cstate->domain[nv_clk_src_shader]; int N1, M1, N2, M2, log2P; @@ -192,9 +183,9 @@ nv40_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) } static int -nv40_clk_prog(struct nvkm_clk *obj) +nv40_clk_prog(struct nvkm_clk *base) { - struct nv40_clk *clk = container_of(obj, typeof(*clk), base); + struct nv40_clk *clk = nv40_clk(base); struct nvkm_device *device = clk->base.subdev.device; nvkm_mask(device, 0x00c040, 0x00000333, 0x00000000); nvkm_wr32(device, 0x004004, clk->npll_coef); @@ -210,36 +201,32 @@ nv40_clk_tidy(struct nvkm_clk *obj) { } -static int -nv40_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_clk_func +nv40_clk = { + .read = nv40_clk_read, + .calc = nv40_clk_calc, + .prog = nv40_clk_prog, + .tidy = nv40_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_max } + } +}; + +int +nv40_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { struct nv40_clk *clk; - int ret; - - ret = nvkm_clk_create(parent, engine, oclass, nv40_domain, - NULL, 0, true, &clk); - *pobject = nv_object(clk); - if (ret) - return ret; + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; clk->base.pll_calc = nv04_clk_pll_calc; clk->base.pll_prog = nv04_clk_pll_prog; - clk->base.read = nv40_clk_read; - clk->base.calc = nv40_clk_calc; - clk->base.prog = nv40_clk_prog; - clk->base.tidy = nv40_clk_tidy; - return 0; -} + *pclk = &clk->base; -struct nvkm_oclass -nv40_clk_oclass = { - .handle = NV_SUBDEV(CLK, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, -}; + return nvkm_clk_ctor(&nv40_clk, device, index, true, &clk->base); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c index d4bf98657f04c..5841f297973cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c @@ -53,7 +53,7 @@ read_pll_src(struct nv50_clk *clk, u32 base) { struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; - u32 coef, ref = clk->base.read(&clk->base, nv_clk_src_crystal); + u32 coef, ref = nvkm_clk_read(&clk->base, nv_clk_src_crystal); u32 rsel = nvkm_rd32(device, 0x00e18c); int P, N, M, id; @@ -100,8 +100,8 @@ read_pll_src(struct nv50_clk *clk, u32 base) switch (rsel) { case 0: id = 1; break; - case 1: return clk->base.read(&clk->base, nv_clk_src_crystal); - case 2: return clk->base.read(&clk->base, nv_clk_src_href); + case 1: return nvkm_clk_read(&clk->base, nv_clk_src_crystal); + case 2: return nvkm_clk_read(&clk->base, nv_clk_src_href); case 3: id = 0; break; } @@ -142,14 +142,14 @@ read_pll_ref(struct nv50_clk *clk, u32 base) src = !!(mast & 0x02000000); break; case 0x00e810: - return clk->base.read(&clk->base, nv_clk_src_crystal); + return nvkm_clk_read(&clk->base, nv_clk_src_crystal); default: nvkm_error(subdev, "bad pll %06x\n", base); return 0; } if (src) - return clk->base.read(&clk->base, nv_clk_src_href); + return nvkm_clk_read(&clk->base, nv_clk_src_href); return read_pll_src(clk, base); } @@ -168,7 +168,7 @@ read_pll(struct nv50_clk *clk, u32 base) if (base == 0x004028 && (mast & 0x00100000)) { /* wtf, appears to only disable post-divider on gt200 */ if (device->chipset != 0xa0) - return clk->base.read(&clk->base, nv_clk_src_dom6); + return nvkm_clk_read(&clk->base, nv_clk_src_dom6); } N2 = (coef & 0xff000000) >> 24; @@ -188,10 +188,10 @@ read_pll(struct nv50_clk *clk, u32 base) return freq; } -static int -nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) +int +nv50_clk_read(struct nvkm_clk *base, enum nv_clk_src src) { - struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + struct nv50_clk *clk = nv50_clk(base); struct nvkm_subdev *subdev = &clk->base.subdev; struct nvkm_device *device = subdev->device; u32 mast = nvkm_rd32(device, 0x00c040); @@ -203,25 +203,25 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case nv_clk_src_href: return 100000; /* PCIE reference clock */ case nv_clk_src_hclk: - return div_u64((u64)clk->base.read(&clk->base, nv_clk_src_href) * 27778, 10000); + return div_u64((u64)nvkm_clk_read(&clk->base, nv_clk_src_href) * 27778, 10000); case nv_clk_src_hclkm3: - return clk->base.read(&clk->base, nv_clk_src_hclk) * 3; + return nvkm_clk_read(&clk->base, nv_clk_src_hclk) * 3; case nv_clk_src_hclkm3d2: - return clk->base.read(&clk->base, nv_clk_src_hclk) * 3 / 2; + return nvkm_clk_read(&clk->base, nv_clk_src_hclk) * 3 / 2; case nv_clk_src_host: switch (mast & 0x30000000) { - case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_href); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_href); case 0x10000000: break; case 0x20000000: /* !0x50 */ - case 0x30000000: return clk->base.read(&clk->base, nv_clk_src_hclk); + case 0x30000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclk); } break; case nv_clk_src_core: if (!(mast & 0x00100000)) P = (nvkm_rd32(device, 0x004028) & 0x00070000) >> 16; switch (mast & 0x00000003) { - case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; - case 0x00000001: return clk->base.read(&clk->base, nv_clk_src_dom6); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; + case 0x00000001: return nvkm_clk_read(&clk->base, nv_clk_src_dom6); case 0x00000002: return read_pll(clk, 0x004020) >> P; case 0x00000003: return read_pll(clk, 0x004028) >> P; } @@ -231,8 +231,8 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) switch (mast & 0x00000030) { case 0x00000000: if (mast & 0x00000080) - return clk->base.read(&clk->base, nv_clk_src_host) >> P; - return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_host) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000010: break; case 0x00000020: return read_pll(clk, 0x004028) >> P; case 0x00000030: return read_pll(clk, 0x004020) >> P; @@ -243,10 +243,10 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) if (nvkm_rd32(device, 0x004008) & 0x00000200) { switch (mast & 0x0000c000) { case 0x00000000: - return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00008000: case 0x0000c000: - return clk->base.read(&clk->base, nv_clk_src_href) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_href) >> P; } } else { return read_pll(clk, 0x004008) >> P; @@ -264,8 +264,8 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) switch (mast & 0x00000c00) { case 0x00000000: if (device->chipset == 0xa0) /* wtf?? */ - return clk->base.read(&clk->base, nv_clk_src_core) >> P; - return clk->base.read(&clk->base, nv_clk_src_crystal) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_crystal) >> P; case 0x00000400: return 0; case 0x00000800: @@ -273,19 +273,19 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) return read_pll(clk, 0x004028) >> P; return read_pll(clk, 0x004030) >> P; case 0x00000c00: - return clk->base.read(&clk->base, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; } break; case 0x98: switch (mast & 0x00000c00) { case 0x00000000: - return clk->base.read(&clk->base, nv_clk_src_core) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_core) >> P; case 0x00000400: return 0; case 0x00000800: - return clk->base.read(&clk->base, nv_clk_src_hclkm3d2) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_hclkm3d2) >> P; case 0x00000c00: - return clk->base.read(&clk->base, nv_clk_src_mem) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_mem) >> P; } break; } @@ -303,11 +303,11 @@ nv50_clk_read(struct nvkm_clk *obj, enum nv_clk_src src) case 0x98: P = (read_div(clk) & 0x00000007) >> 0; switch (mast & 0x0c000000) { - case 0x00000000: return clk->base.read(&clk->base, nv_clk_src_href); + case 0x00000000: return nvkm_clk_read(&clk->base, nv_clk_src_href); case 0x04000000: break; - case 0x08000000: return clk->base.read(&clk->base, nv_clk_src_hclk); + case 0x08000000: return nvkm_clk_read(&clk->base, nv_clk_src_hclk); case 0x0c000000: - return clk->base.read(&clk->base, nv_clk_src_hclkm3) >> P; + return nvkm_clk_read(&clk->base, nv_clk_src_hclkm3) >> P; } break; default: @@ -364,11 +364,13 @@ clk_same(u32 a, u32 b) return ((a / 1000) == (b / 1000)); } -static int -nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) +int +nv50_clk_calc(struct nvkm_clk *base, struct nvkm_cstate *cstate) { - struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + struct nv50_clk *clk = nv50_clk(base); struct nv50_clk_hwsq *hwsq = &clk->hwsq; + struct nvkm_subdev *subdev = &clk->base.subdev; + struct nvkm_device *device = subdev->device; const int shader = cstate->domain[nv_clk_src_shader]; const int core = cstate->domain[nv_clk_src_core]; const int vdec = cstate->domain[nv_clk_src_vdec]; @@ -379,7 +381,7 @@ nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) int freq, out; /* prepare a hwsq script from which we'll perform the reclock */ - out = clk_init(hwsq, nv_subdev(clk)); + out = clk_init(hwsq, subdev); if (out) return out; @@ -397,15 +399,15 @@ nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) freq = calc_div(core, vdec, &P1); /* see how close we can get using xpll/hclk as a source */ - if (nv_device(clk)->chipset != 0x98) + if (device->chipset != 0x98) out = read_pll(clk, 0x004030); else - out = clk->base.read(&clk->base, nv_clk_src_hclkm3d2); + out = nvkm_clk_read(&clk->base, nv_clk_src_hclkm3d2); out = calc_div(out, vdec, &P2); /* select whichever gets us closest */ if (abs(vdec - freq) <= abs(vdec - out)) { - if (nv_device(clk)->chipset != 0x98) + if (device->chipset != 0x98) mastv |= 0x00000c00; divsv |= P1 << 8; } else { @@ -421,13 +423,13 @@ nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) * of the host clock frequency */ if (dom6) { - if (clk_same(dom6, clk->base.read(&clk->base, nv_clk_src_href))) { + if (clk_same(dom6, nvkm_clk_read(&clk->base, nv_clk_src_href))) { mastv |= 0x00000000; } else - if (clk_same(dom6, clk->base.read(&clk->base, nv_clk_src_hclk))) { + if (clk_same(dom6, nvkm_clk_read(&clk->base, nv_clk_src_hclk))) { mastv |= 0x08000000; } else { - freq = clk->base.read(&clk->base, nv_clk_src_hclk) * 3; + freq = nvkm_clk_read(&clk->base, nv_clk_src_hclk) * 3; calc_div(freq, dom6, &P1); mastv |= 0x0c000000; @@ -448,7 +450,7 @@ nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6, * sclk to hclk) before reprogramming */ - if (nv_device(clk)->chipset < 0x92) + if (device->chipset < 0x92) clk_mask(hwsq, mast, 0x001000b0, 0x00100080); else clk_mask(hwsq, mast, 0x000000b3, 0x00000081); @@ -489,33 +491,31 @@ nv50_clk_calc(struct nvkm_clk *obj, struct nvkm_cstate *cstate) return 0; } -static int -nv50_clk_prog(struct nvkm_clk *obj) +int +nv50_clk_prog(struct nvkm_clk *base) { - struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + struct nv50_clk *clk = nv50_clk(base); return clk_exec(&clk->hwsq, true); } -static void -nv50_clk_tidy(struct nvkm_clk *obj) +void +nv50_clk_tidy(struct nvkm_clk *base) { - struct nv50_clk *clk = container_of(obj, typeof(*clk), base); + struct nv50_clk *clk = nv50_clk(base); clk_exec(&clk->hwsq, false); } int -nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_clk_new_(const struct nvkm_clk_func *func, struct nvkm_device *device, + int index, bool allow_reclock, struct nvkm_clk **pclk) { - struct nv50_clk_oclass *pclass = (void *)oclass; struct nv50_clk *clk; int ret; - ret = nvkm_clk_create(parent, engine, oclass, pclass->domains, - NULL, 0, nv_device(parent)->chipset == 0xa0, - &clk); - *pobject = nv_object(clk); + if (!(clk = kzalloc(sizeof(*clk), GFP_KERNEL))) + return -ENOMEM; + ret = nvkm_clk_ctor(func, device, index, allow_reclock, &clk->base); + *pclk = &clk->base; if (ret) return ret; @@ -524,7 +524,7 @@ nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, clk->hwsq.r_spll[1] = hwsq_reg(0x004024); clk->hwsq.r_nvpll[0] = hwsq_reg(0x004028); clk->hwsq.r_nvpll[1] = hwsq_reg(0x00402c); - switch (nv_device(clk)->chipset) { + switch (device->chipset) { case 0x92: case 0x94: case 0x96: @@ -535,32 +535,27 @@ nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine, break; } clk->hwsq.r_mast = hwsq_reg(0x00c040); - - clk->base.read = nv50_clk_read; - clk->base.calc = nv50_clk_calc; - clk->base.prog = nv50_clk_prog; - clk->base.tidy = nv50_clk_tidy; return 0; } -static struct nvkm_domain -nv50_domains[] = { - { nv_clk_src_crystal, 0xff }, - { nv_clk_src_href , 0xff }, - { nv_clk_src_core , 0xff, 0, "core", 1000 }, - { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, - { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, - { nv_clk_src_max } +static const struct nvkm_clk_func +nv50_clk = { + .read = nv50_clk_read, + .calc = nv50_clk_calc, + .prog = nv50_clk_prog, + .tidy = nv50_clk_tidy, + .domains = { + { nv_clk_src_crystal, 0xff }, + { nv_clk_src_href , 0xff }, + { nv_clk_src_core , 0xff, 0, "core", 1000 }, + { nv_clk_src_shader , 0xff, 0, "shader", 1000 }, + { nv_clk_src_mem , 0xff, 0, "memory", 1000 }, + { nv_clk_src_max } + } }; -struct nvkm_oclass * -nv50_clk_oclass = &(struct nv50_clk_oclass) { - .base.handle = NV_SUBDEV(CLK, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_clk_ctor, - .dtor = _nvkm_clk_dtor, - .init = _nvkm_clk_init, - .fini = _nvkm_clk_fini, - }, - .domains = nv50_domains, -}.base; +int +nv50_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) +{ + return nv50_clk_new_(&nv50_clk, device, index, false, pclk); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h index 7432b9f921ea6..d3c7fb6efa16c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h @@ -1,7 +1,9 @@ -#ifndef __NVKM_CLK_NV50_H__ -#define __NVKM_CLK_NV50_H__ +#ifndef __NV50_CLK_H__ +#define __NV50_CLK_H__ +#define nv50_clk(p) container_of((p), struct nv50_clk, base) +#include "priv.h" + #include -#include struct nv50_clk_hwsq { struct hwsq base; @@ -17,12 +19,10 @@ struct nv50_clk { struct nv50_clk_hwsq hwsq; }; -int nv50_clk_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -struct nv50_clk_oclass { - struct nvkm_oclass base; - struct nvkm_domain *domains; -}; +int nv50_clk_new_(const struct nvkm_clk_func *, struct nvkm_device *, int, + bool, struct nvkm_clk **); +int nv50_clk_read(struct nvkm_clk *, enum nv_clk_src); +int nv50_clk_calc(struct nvkm_clk *, struct nvkm_cstate *); +int nv50_clk_prog(struct nvkm_clk *); +void nv50_clk_tidy(struct nvkm_clk *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h new file mode 100644 index 0000000000000..51eafc00c8b10 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/priv.h @@ -0,0 +1,26 @@ +#ifndef __NVKM_CLK_PRIV_H__ +#define __NVKM_CLK_PRIV_H__ +#define nvkm_clk(p) container_of((p), struct nvkm_clk, subdev) +#include + +struct nvkm_clk_func { + int (*init)(struct nvkm_clk *); + void (*fini)(struct nvkm_clk *); + int (*read)(struct nvkm_clk *, enum nv_clk_src); + int (*calc)(struct nvkm_clk *, struct nvkm_cstate *); + int (*prog)(struct nvkm_clk *); + void (*tidy)(struct nvkm_clk *); + struct nvkm_pstate *pstates; + int nr_pstates; + struct nvkm_domain domains[]; +}; + +int nvkm_clk_ctor(const struct nvkm_clk_func *, struct nvkm_device *, int, + bool allow_reclock, struct nvkm_clk *); +int nvkm_clk_new_(const struct nvkm_clk_func *, struct nvkm_device *, int, + bool allow_reclock, struct nvkm_clk **); + +int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk, + struct nvkm_pll_vals *); +int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index b579e910ef2d8..71902b64ffbc6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -187,9 +187,9 @@ gf100_ram_calc(struct nvkm_ram *base, u32 freq) /* determine target mclk configuration */ if (!(ram_rd32(fuc, 0x137300) & 0x00000100)) - ref = clk->read(clk, nv_clk_src_sppll0); + ref = nvkm_clk_read(clk, nv_clk_src_sppll0); else - ref = clk->read(clk, nv_clk_src_sppll1); + ref = nvkm_clk_read(clk, nv_clk_src_sppll1); div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2; out = (ref * 2) / (div + 2); mode = freq != out; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 28cd633db0f04..0f07309da71dd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -1032,7 +1032,8 @@ gk104_ram_calc(struct nvkm_ram *base, u32 freq) int ret; if (ram->base.next == NULL) { - ret = gk104_ram_calc_data(ram, clk->read(clk, nv_clk_src_mem), + ret = gk104_ram_calc_data(ram, + nvkm_clk_read(clk, nv_clk_src_mem), &ram->base.former); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index 2cfedc0e15927..a70219cc0a4ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -186,7 +186,7 @@ gt215_link_train(struct gt215_ram *ram) return -ENOENT; } - clk_current = clk->read(clk, nv_clk_src_mem); + clk_current = nvkm_clk_read(clk, nv_clk_src_mem); ret = gt215_clk_pre(clk, f); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 47c6dbe8fff3e..bf3c53851352c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -50,7 +50,7 @@ struct gk20a_pmu_dvfs_dev_status { static int gk20a_pmu_dvfs_target(struct gk20a_pmu *pmu, int *state) { - struct nvkm_clk *clk = nvkm_clk(pmu); + struct nvkm_clk *clk = pmu->base.subdev.device->clk; return nvkm_clk_astate(clk, *state, 0, false); } @@ -58,7 +58,7 @@ gk20a_pmu_dvfs_target(struct gk20a_pmu *pmu, int *state) static int gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu *pmu, int *state) { - struct nvkm_clk *clk = nvkm_clk(pmu); + struct nvkm_clk *clk = pmu->base.subdev.device->clk; *state = clk->pstate; return 0; @@ -69,7 +69,7 @@ gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu *pmu, int *state, int load) { struct gk20a_pmu_dvfs_data *data = pmu->data; - struct nvkm_clk *clk = nvkm_clk(pmu); + struct nvkm_clk *clk = pmu->base.subdev.device->clk; int cur_level, level; /* For GK20A, the performance level is directly mapped to pstate */ -- GitLab From 151abd44c27c1562f348a99c176b078a876ebe93 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5533/7006] drm/nouveau/devinit: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../nouveau/include/nvkm/subdev/bios/init.h | 1 + .../drm/nouveau/include/nvkm/subdev/devinit.h | 40 +++--- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 134 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 7 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 -- .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 --- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 12 +- .../drm/nouveau/nvkm/subdev/devinit/base.c | 112 ++++++++++----- .../gpu/drm/nouveau/nvkm/subdev/devinit/g84.c | 24 ++-- .../gpu/drm/nouveau/nvkm/subdev/devinit/g98.c | 24 ++-- .../drm/nouveau/nvkm/subdev/devinit/gf100.c | 44 ++---- .../drm/nouveau/nvkm/subdev/devinit/gm107.c | 24 ++-- .../drm/nouveau/nvkm/subdev/devinit/gm204.c | 29 ++-- .../drm/nouveau/nvkm/subdev/devinit/gt215.c | 30 ++-- .../drm/nouveau/nvkm/subdev/devinit/mcp89.c | 24 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv04.c | 78 +++++----- .../drm/nouveau/nvkm/subdev/devinit/nv04.h | 16 +-- .../drm/nouveau/nvkm/subdev/devinit/nv05.c | 24 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv10.c | 24 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv1a.c | 24 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv20.c | 26 ++-- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 82 ++++++----- .../drm/nouveau/nvkm/subdev/devinit/nv50.h | 13 +- .../drm/nouveau/nvkm/subdev/devinit/priv.h | 33 ++--- 32 files changed, 424 insertions(+), 466 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h index 578a667eed3bc..4dc1c8af840c4 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h @@ -1,5 +1,6 @@ #ifndef __NVBIOS_INIT_H__ #define __NVBIOS_INIT_H__ + struct nvbios_init { struct nvkm_subdev *subdev; struct nvkm_bios *bios; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h index 856ff5064dd3b..9e053460a9c77 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h @@ -1,32 +1,30 @@ #ifndef __NVKM_DEVINIT_H__ #define __NVKM_DEVINIT_H__ #include +struct nvkm_devinit; struct nvkm_devinit { + const struct nvkm_devinit_func *func; struct nvkm_subdev subdev; bool post; - void (*meminit)(struct nvkm_devinit *); - int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq); - u32 (*mmio)(struct nvkm_devinit *, u32 addr); }; -static inline struct nvkm_devinit * -nvkm_devinit(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_DEVINIT); -} +u32 nvkm_devinit_mmio(struct nvkm_devinit *, u32 addr); +int nvkm_devinit_pll_set(struct nvkm_devinit *, u32 type, u32 khz); +void nvkm_devinit_meminit(struct nvkm_devinit *); +u64 nvkm_devinit_disable(struct nvkm_devinit *); -extern struct nvkm_oclass *nv04_devinit_oclass; -extern struct nvkm_oclass *nv05_devinit_oclass; -extern struct nvkm_oclass *nv10_devinit_oclass; -extern struct nvkm_oclass *nv1a_devinit_oclass; -extern struct nvkm_oclass *nv20_devinit_oclass; -extern struct nvkm_oclass *nv50_devinit_oclass; -extern struct nvkm_oclass *g84_devinit_oclass; -extern struct nvkm_oclass *g98_devinit_oclass; -extern struct nvkm_oclass *gt215_devinit_oclass; -extern struct nvkm_oclass *mcp89_devinit_oclass; -extern struct nvkm_oclass *gf100_devinit_oclass; -extern struct nvkm_oclass *gm107_devinit_oclass; -extern struct nvkm_oclass *gm204_devinit_oclass; +int nv04_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int nv05_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int nv10_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int nv1a_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int nv20_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int nv50_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int g84_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int g98_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int gt215_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int mcp89_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int gf100_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int gm107_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); +int gm204_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 96410defb1f84..7bd8c39649d4b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -79,7 +79,7 @@ nv4_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv04_devinit_new, + .devinit = nv04_devinit_new, // .fb = nv04_fb_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -99,7 +99,7 @@ nv5_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv05_devinit_new, + .devinit = nv05_devinit_new, // .fb = nv04_fb_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -119,7 +119,7 @@ nv10_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv10_devinit_new, + .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -138,7 +138,7 @@ nv11_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv10_devinit_new, + .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -159,7 +159,7 @@ nv15_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv10_devinit_new, + .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -180,7 +180,7 @@ nv17_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv10_devinit_new, + .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -201,7 +201,7 @@ nv18_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv10_devinit_new, + .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -222,7 +222,7 @@ nv1a_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv1a_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -243,7 +243,7 @@ nv1f_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv1a_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -264,7 +264,7 @@ nv20_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv20_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -285,7 +285,7 @@ nv25_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv25_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -306,7 +306,7 @@ nv28_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv25_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -327,7 +327,7 @@ nv2a_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv25_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -348,7 +348,7 @@ nv30_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv30_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -369,7 +369,7 @@ nv31_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv30_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -391,7 +391,7 @@ nv34_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv04_clk_new, -// .devinit = nv10_devinit_new, + .devinit = nv10_devinit_new, // .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -413,7 +413,7 @@ nv35_chipset = { .bios = nvkm_bios_new, .bus = nv04_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv35_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -434,7 +434,7 @@ nv36_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv04_clk_new, -// .devinit = nv20_devinit_new, + .devinit = nv20_devinit_new, // .fb = nv36_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -456,7 +456,7 @@ nv40_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv40_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -481,7 +481,7 @@ nv41_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -506,7 +506,7 @@ nv42_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -531,7 +531,7 @@ nv43_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv41_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -556,7 +556,7 @@ nv44_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv44_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -581,7 +581,7 @@ nv45_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv40_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -606,7 +606,7 @@ nv46_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -631,7 +631,7 @@ nv47_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv47_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -656,7 +656,7 @@ nv49_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv49_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -681,7 +681,7 @@ nv4a_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv44_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -706,7 +706,7 @@ nv4b_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv49_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -731,7 +731,7 @@ nv4c_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -756,7 +756,7 @@ nv4e_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv4e_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv4e_i2c_new, @@ -782,7 +782,7 @@ nv50_chipset = { .bios = nvkm_bios_new, .bus = nv50_bus_new, .clk = nv50_clk_new, -// .devinit = nv50_devinit_new, + .devinit = nv50_devinit_new, // .fb = nv50_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, @@ -809,7 +809,7 @@ nv63_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -834,7 +834,7 @@ nv67_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -859,7 +859,7 @@ nv68_chipset = { .bios = nvkm_bios_new, .bus = nv31_bus_new, .clk = nv40_clk_new, -// .devinit = nv1a_devinit_new, + .devinit = nv1a_devinit_new, // .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, @@ -885,7 +885,7 @@ nv84_chipset = { .bios = nvkm_bios_new, .bus = nv50_bus_new, .clk = g84_clk_new, -// .devinit = g84_devinit_new, + .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, @@ -916,7 +916,7 @@ nv86_chipset = { .bios = nvkm_bios_new, .bus = nv50_bus_new, .clk = g84_clk_new, -// .devinit = g84_devinit_new, + .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, @@ -947,7 +947,7 @@ nv92_chipset = { .bios = nvkm_bios_new, .bus = nv50_bus_new, .clk = g84_clk_new, -// .devinit = g84_devinit_new, + .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, @@ -978,7 +978,7 @@ nv94_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = g84_clk_new, -// .devinit = g84_devinit_new, + .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1012,7 +1012,7 @@ nv96_chipset = { .clk = g84_clk_new, // .therm = g84_therm_new, // .mxm = nv50_mxm_new, -// .devinit = g84_devinit_new, + .devinit = g84_devinit_new, // .mc = g94_mc_new, .bus = g94_bus_new, // .timer = nv04_timer_new, @@ -1043,7 +1043,7 @@ nv98_chipset = { .clk = g84_clk_new, // .therm = g84_therm_new, // .mxm = nv50_mxm_new, -// .devinit = g98_devinit_new, + .devinit = g98_devinit_new, // .mc = g98_mc_new, .bus = g94_bus_new, // .timer = nv04_timer_new, @@ -1071,7 +1071,7 @@ nva0_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = g84_clk_new, -// .devinit = g84_devinit_new, + .devinit = g84_devinit_new, // .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1102,7 +1102,7 @@ nva3_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = gt215_clk_new, -// .devinit = gt215_devinit_new, + .devinit = gt215_devinit_new, // .fb = gt215_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1135,7 +1135,7 @@ nva5_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = gt215_clk_new, -// .devinit = gt215_devinit_new, + .devinit = gt215_devinit_new, // .fb = gt215_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1167,7 +1167,7 @@ nva8_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = gt215_clk_new, -// .devinit = gt215_devinit_new, + .devinit = gt215_devinit_new, // .fb = gt215_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1199,7 +1199,7 @@ nvaa_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = mcp77_clk_new, -// .devinit = g98_devinit_new, + .devinit = g98_devinit_new, // .fb = mcp77_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1230,7 +1230,7 @@ nvac_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = mcp77_clk_new, -// .devinit = g98_devinit_new, + .devinit = g98_devinit_new, // .fb = mcp77_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1261,7 +1261,7 @@ nvaf_chipset = { .bios = nvkm_bios_new, .bus = g94_bus_new, .clk = gt215_clk_new, -// .devinit = mcp89_devinit_new, + .devinit = mcp89_devinit_new, // .fb = mcp89_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, @@ -1293,7 +1293,7 @@ nvc0_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1328,7 +1328,7 @@ nvc1_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1362,7 +1362,7 @@ nvc3_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1396,7 +1396,7 @@ nvc4_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1431,7 +1431,7 @@ nvc8_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1466,7 +1466,7 @@ nvce_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1501,7 +1501,7 @@ nvcf_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, @@ -1535,7 +1535,7 @@ nvd7_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = gf110_gpio_new, @@ -1567,7 +1567,7 @@ nvd9_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gf100_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = gf110_gpio_new, @@ -1601,7 +1601,7 @@ nve4_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1637,7 +1637,7 @@ nve6_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1673,7 +1673,7 @@ nve7_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1733,7 +1733,7 @@ nvf0_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1769,7 +1769,7 @@ nvf1_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1805,7 +1805,7 @@ nv106_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1840,7 +1840,7 @@ nv108_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gf100_devinit_new, + .devinit = gf100_devinit_new, // .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, @@ -1875,7 +1875,7 @@ nv117_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .clk = gk104_clk_new, -// .devinit = gm107_devinit_new, + .devinit = gm107_devinit_new, // .fb = gm107_fb_new, // .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, @@ -1904,7 +1904,7 @@ nv124_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .devinit = gm204_devinit_new, + .devinit = gm204_devinit_new, // .fb = gm107_fb_new, // .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, @@ -1933,7 +1933,7 @@ nv126_chipset = { .bar = gf100_bar_new, .bios = nvkm_bios_new, .bus = gf100_bus_new, -// .devinit = gm204_devinit_new, + .devinit = gm204_devinit_new, // .fb = gm107_fb_new, // .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 01dcc5a168422..87a9cdb42bd64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -33,7 +33,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -61,7 +60,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -89,7 +87,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -116,7 +113,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -144,7 +140,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -171,7 +166,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -198,7 +192,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -226,7 +219,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; @@ -253,7 +245,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 77386ac4dba07..67c7b6386a4ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -33,7 +33,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; @@ -62,7 +61,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; @@ -91,7 +89,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; @@ -138,7 +135,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; @@ -167,7 +163,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; @@ -196,7 +191,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; @@ -224,7 +218,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 2902bdc5626f1..f9f0663f2206c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -33,7 +33,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; @@ -72,7 +71,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; @@ -108,7 +106,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index af120691b1322..0cabcfa8b63e1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -29,7 +29,6 @@ nv04_identify(struct nvkm_device *device) switch (device->chipset) { case 0x04: device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; @@ -43,7 +42,6 @@ nv04_identify(struct nvkm_device *device) break; case 0x05: device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 884ba56411cac..09eedfecfb367 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -30,7 +30,6 @@ nv10_identify(struct nvkm_device *device) case 0x10: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; @@ -43,7 +42,6 @@ nv10_identify(struct nvkm_device *device) case 0x15: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; @@ -58,7 +56,6 @@ nv10_identify(struct nvkm_device *device) case 0x16: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; @@ -73,7 +70,6 @@ nv10_identify(struct nvkm_device *device) case 0x1a: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; @@ -88,7 +84,6 @@ nv10_identify(struct nvkm_device *device) case 0x11: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; @@ -103,7 +98,6 @@ nv10_identify(struct nvkm_device *device) case 0x17: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; @@ -118,7 +112,6 @@ nv10_identify(struct nvkm_device *device) case 0x1f: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; @@ -133,7 +126,6 @@ nv10_identify(struct nvkm_device *device) case 0x18: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index d18d702a10621..9ea12b6426c6e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -30,7 +30,6 @@ nv20_identify(struct nvkm_device *device) case 0x20: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass; @@ -45,7 +44,6 @@ nv20_identify(struct nvkm_device *device) case 0x25: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; @@ -60,7 +58,6 @@ nv20_identify(struct nvkm_device *device) case 0x28: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; @@ -75,7 +72,6 @@ nv20_identify(struct nvkm_device *device) case 0x2a: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 04f79162adc1f..48b927bd104b9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -30,7 +30,6 @@ nv30_identify(struct nvkm_device *device) case 0x30: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; @@ -45,7 +44,6 @@ nv30_identify(struct nvkm_device *device) case 0x35: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass; @@ -60,7 +58,6 @@ nv30_identify(struct nvkm_device *device) case 0x31: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; @@ -76,7 +73,6 @@ nv30_identify(struct nvkm_device *device) case 0x36: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass; @@ -92,7 +88,6 @@ nv30_identify(struct nvkm_device *device) case 0x34: device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index b4ca9c8cbec6f..ef660d958f6bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -31,7 +31,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; @@ -50,7 +49,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; @@ -69,7 +67,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; @@ -88,7 +85,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; @@ -107,7 +103,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; @@ -126,7 +121,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass; @@ -145,7 +139,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; @@ -164,7 +157,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; @@ -183,7 +175,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; @@ -202,7 +193,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -221,7 +211,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; @@ -240,7 +229,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -259,7 +247,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass; @@ -278,7 +265,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -297,7 +283,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; @@ -316,7 +301,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 5d5a4b23771b7..7b942dfa7f4cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -33,7 +33,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass; @@ -54,7 +53,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -78,7 +76,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -102,7 +99,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -126,7 +122,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -150,7 +145,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -174,7 +168,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -198,7 +191,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; @@ -222,7 +214,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; @@ -246,7 +237,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; @@ -270,7 +260,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; @@ -296,7 +285,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; @@ -321,7 +309,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; @@ -346,7 +333,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_DEVINIT] = mcp89_devinit_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_FB ] = mcp89_fb_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index f561072e6874f..1573f86073f3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -236,7 +236,7 @@ gf119_disp_intr_unk2_1(struct nv50_disp *disp, int head) struct nvkm_devinit *devinit = device->devinit; u32 pclk = nvkm_rd32(device, 0x660450 + (head * 0x300)) / 1000; if (pclk) - devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); + nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); nvkm_wr32(device, 0x612200 + (head * 0x800), 0x00000000); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index efffecbc92a5b..ddffcc1088bec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -358,7 +358,7 @@ nv50_disp_intr_unk20_1(struct nv50_disp *disp, int head) struct nvkm_devinit *devinit = device->devinit; u32 pclk = nvkm_rd32(device, 0x610ad0 + (head * 0x540)) & 0x3fffff; if (pclk) - devinit->pll_set(devinit, PLL_VPLL0 + head, pclk); + nvkm_devinit_pll_set(devinit, PLL_VPLL0 + head, pclk); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index f119bc81d39e9..a50b027cf7030 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -173,9 +173,7 @@ init_nvreg(struct nvbios_init *init, u32 reg) if (reg & ~0x00fffffc) warn("unknown bits in register 0x%08x\n", reg); - if (devinit->mmio) - reg = devinit->mmio(devinit, reg); - return reg; + return nvkm_devinit_mmio(devinit, reg); } static u32 @@ -338,8 +336,8 @@ static void init_prog_pll(struct nvbios_init *init, u32 id, u32 freq) { struct nvkm_devinit *devinit = init->bios->subdev.device->devinit; - if (devinit->pll_set && init_exec(init)) { - int ret = devinit->pll_set(devinit, id, freq); + if (init_exec(init)) { + int ret = nvkm_devinit_pll_set(devinit, id, freq); if (ret) warn("failed to prog pll 0x%08x to %dkHz\n", id, freq); } @@ -1453,8 +1451,8 @@ init_compute_mem(struct nvbios_init *init) init->offset += 1; init_exec_force(init, true); - if (init_exec(init) && devinit->meminit) - devinit->meminit(devinit); + if (init_exec(init)) + nvkm_devinit_meminit(devinit); init_exec_force(init, false); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index e5ef999adbb93..47823f5a2cdff 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -26,70 +26,104 @@ #include #include +u32 +nvkm_devinit_mmio(struct nvkm_devinit *init, u32 addr) +{ + if (init->func->mmio) + addr = init->func->mmio(init, addr); + return addr; +} + int -_nvkm_devinit_fini(struct nvkm_object *object, bool suspend) +nvkm_devinit_pll_set(struct nvkm_devinit *init, u32 type, u32 khz) +{ + return init->func->pll_set(init, type, khz); +} + +void +nvkm_devinit_meminit(struct nvkm_devinit *init) +{ + if (init->func->meminit) + init->func->meminit(init); +} + +u64 +nvkm_devinit_disable(struct nvkm_devinit *init) { - struct nvkm_devinit *init = (void *)object; + if (init->func->disable) + return init->func->disable(init); + return 0; +} +static int +nvkm_devinit_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_devinit *init = nvkm_devinit(subdev); /* force full reinit on resume */ if (suspend) init->post = true; + return 0; +} - /* unlock the extended vga crtc regs */ - nvkm_lockvgac(init->subdev.device, false); +static int +nvkm_devinit_preinit(struct nvkm_subdev *subdev) +{ + struct nvkm_devinit *init = nvkm_devinit(subdev); + + if (init->func->preinit) + init->func->preinit(init); - return nvkm_subdev_fini_old(&init->subdev, suspend); + /* unlock the extended vga crtc regs */ + nvkm_lockvgac(subdev->device, false); + return 0; } -int -_nvkm_devinit_init(struct nvkm_object *object) +static int +nvkm_devinit_init(struct nvkm_subdev *subdev) { - struct nvkm_devinit_impl *impl = (void *)object->oclass; - struct nvkm_devinit *init = (void *)object; + struct nvkm_devinit *init = nvkm_devinit(subdev); int ret; - ret = nvkm_subdev_init_old(&init->subdev); + ret = init->func->post(init, init->post); if (ret) return ret; - ret = impl->post(&init->subdev, init->post); - if (ret) - return ret; + if (init->func->init) + init->func->init(init); - if (impl->disable) - nv_device(init)->disable_mask |= impl->disable(init); + if (init->func->disable) + subdev->device->disable_mask |= init->func->disable(init); return 0; } -void -_nvkm_devinit_dtor(struct nvkm_object *object) +static void * +nvkm_devinit_dtor(struct nvkm_subdev *subdev) { - struct nvkm_devinit *init = (void *)object; + struct nvkm_devinit *init = nvkm_devinit(subdev); + void *data = init; - /* lock crtc regs */ - nvkm_lockvgac(init->subdev.device, true); + if (init->func->dtor) + data = init->func->dtor(init); - nvkm_subdev_destroy(&init->subdev); + /* lock crtc regs */ + nvkm_lockvgac(subdev->device, true); + return data; } -int -nvkm_devinit_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int size, void **pobject) -{ - struct nvkm_devinit_impl *impl = (void *)oclass; - struct nvkm_device *device = nv_device(parent); - struct nvkm_devinit *init; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "DEVINIT", - "init", size, pobject); - init = *pobject; - if (ret) - return ret; +static const struct nvkm_subdev_func +nvkm_devinit = { + .dtor = nvkm_devinit_dtor, + .preinit = nvkm_devinit_preinit, + .init = nvkm_devinit_init, + .fini = nvkm_devinit_fini, +}; +void +nvkm_devinit_ctor(const struct nvkm_devinit_func *func, + struct nvkm_device *device, int index, + struct nvkm_devinit *init) +{ + nvkm_subdev_ctor(&nvkm_devinit, device, index, 0, &init->subdev); + init->func = func; init->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false); - init->meminit = impl->meminit; - init->pll_set = impl->pll_set; - init->mmio = impl->mmio; - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c index d70e1dd654e0f..18871a3caa28e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c @@ -51,16 +51,18 @@ g84_devinit_disable(struct nvkm_devinit *init) return disable; } -struct nvkm_oclass * -g84_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x84), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +g84_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = g84_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +g84_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&g84_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c index 6af12fd868d9e..a381efa9ae4a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c @@ -50,16 +50,18 @@ g98_devinit_disable(struct nvkm_devinit *init) return disable; } -struct nvkm_oclass * -g98_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x98), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +g98_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = g98_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +g98_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&g98_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index 58f75c33f555e..a9f2d02b6e187 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -90,38 +90,18 @@ gf100_devinit_disable(struct nvkm_devinit *init) return disable; } +static const struct nvkm_devinit_func +gf100_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, + .pll_set = gf100_devinit_pll_set, + .disable = gf100_devinit_disable, +}; + int -gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) { - struct nvkm_devinit_impl *impl = (void *)oclass; - struct nv50_devinit *init; - u64 disable; - int ret; - - ret = nvkm_devinit_create(parent, engine, oclass, &init); - *pobject = nv_object(init); - if (ret) - return ret; - - disable = impl->disable(&init->base); - if (disable & (1ULL << NVDEV_ENGINE_DISP)) - init->base.post = true; - - return 0; + return nv50_devinit_new_(&gf100_devinit, device, index, pinit); } - -struct nvkm_oclass * -gf100_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, - .pll_set = gf100_devinit_pll_set, - .disable = gf100_devinit_disable, - .post = nvbios_init, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c index 6c82c4afe0110..f0f84fef2350f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c @@ -44,16 +44,18 @@ gm107_devinit_disable(struct nvkm_devinit *init) return disable; } -struct nvkm_oclass * -gm107_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +gm107_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = gf100_devinit_pll_set, .disable = gm107_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +gm107_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&gm107_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c index c0eb827f5aa3d..2b9c3f11b7a87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c @@ -107,9 +107,10 @@ pmu_load(struct nv50_devinit *init, u8 type, bool post, } static int -gm204_devinit_post(struct nvkm_subdev *subdev, bool post) +gm204_devinit_post(struct nvkm_devinit *base, bool post) { - struct nv50_devinit *init = (void *)nvkm_devinit(subdev); + struct nv50_devinit *init = nv50_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct bit_entry bit_I; @@ -163,16 +164,18 @@ gm204_devinit_post(struct nvkm_subdev *subdev, bool post) return pmu_load(init, 0x01, post, NULL, NULL); } -struct nvkm_oclass * -gm204_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +gm204_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = gm204_devinit_post, .pll_set = gf100_devinit_pll_set, .disable = gm107_devinit_disable, - .post = gm204_devinit_post, -}.base; +}; + +int +gm204_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&gm204_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c index 145a1c7ba39c5..38f9827902e97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c @@ -99,9 +99,9 @@ gt215_devinit_mmio_part[] = { }; static u32 -gt215_devinit_mmio(struct nvkm_devinit *obj, u32 addr) +gt215_devinit_mmio(struct nvkm_devinit *base, u32 addr) { - struct nv50_devinit *init = container_of(obj, typeof(*init), base); + struct nv50_devinit *init = nv50_devinit(base); struct nvkm_device *device = init->base.subdev.device; u32 *mmio = gt215_devinit_mmio_part; @@ -135,17 +135,19 @@ gt215_devinit_mmio(struct nvkm_devinit *obj, u32 addr) return addr; } -struct nvkm_oclass * -gt215_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0xa3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +gt215_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, + .mmio = gt215_devinit_mmio, .pll_set = gt215_devinit_pll_set, .disable = gt215_devinit_disable, - .mmio = gt215_devinit_mmio, - .post = nvbios_init, -}.base; +}; + +int +gt215_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(>215_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c index e342b5c8dc2ae..892f5ea86d57e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c @@ -51,16 +51,18 @@ mcp89_devinit_disable(struct nvkm_devinit *init) return disable; } -struct nvkm_oclass * -mcp89_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0xaf), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +mcp89_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = gt215_devinit_pll_set, .disable = mcp89_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +mcp89_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&mcp89_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c index 5947bbb91dba9..c8d455346fcda 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c @@ -391,32 +391,25 @@ nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq) } int -nv04_devinit_fini(struct nvkm_object *object, bool suspend) +nv04_devinit_post(struct nvkm_devinit *init, bool execute) { - struct nv04_devinit *init = (void *)object; - struct nvkm_device *device = init->base.subdev.device; - int ret; + return nvbios_init(&init->subdev, execute); +} + +void +nv04_devinit_preinit(struct nvkm_devinit *base) +{ + struct nv04_devinit *init = nv04_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; /* make i2c busses accessible */ nvkm_mask(device, 0x000200, 0x00000001, 0x00000001); - ret = nvkm_devinit_fini(&init->base, suspend); - if (ret) - return ret; - /* unslave crtcs */ if (init->owner < 0) init->owner = nvkm_rdvgaowner(device); nvkm_wrvgaowner(device, 0); - return 0; -} - -int -nv04_devinit_init(struct nvkm_object *object) -{ - struct nv04_devinit *init = (void *)object; - struct nvkm_subdev *subdev = &init->base.subdev; - struct nvkm_device *device = subdev->device; if (!init->base.post) { u32 htotal = nvkm_rdvgac(device, 0, 0x06); @@ -429,48 +422,45 @@ nv04_devinit_init(struct nvkm_object *object) init->base.post = true; } } - - return nvkm_devinit_init(&init->base); } -void -nv04_devinit_dtor(struct nvkm_object *object) +void * +nv04_devinit_dtor(struct nvkm_devinit *base) { - struct nv04_devinit *init = (void *)object; - + struct nv04_devinit *init = nv04_devinit(base); /* restore vga owner saved at first init */ nvkm_wrvgaowner(init->base.subdev.device, init->owner); - - nvkm_devinit_destroy(&init->base); + return init; } int -nv04_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_devinit_new_(const struct nvkm_devinit_func *func, + struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) { struct nv04_devinit *init; - int ret; - ret = nvkm_devinit_create(parent, engine, oclass, &init); - *pobject = nv_object(init); - if (ret) - return ret; + if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) + return -ENOMEM; + *pinit = &init->base; + nvkm_devinit_ctor(func, device, index, &init->base); init->owner = -1; return 0; } -struct nvkm_oclass * -nv04_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv04_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv04_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv04_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv04_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h index abf6748c072ef..4a87c8c2bce84 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h @@ -1,5 +1,6 @@ -#ifndef __NVKM_DEVINIT_NV04_H__ -#define __NVKM_DEVINIT_NV04_H__ +#ifndef __NV04_DEVINIT_H__ +#define __NV04_DEVINIT_H__ +#define nv04_devinit(p) container_of((p), struct nv04_devinit, base) #include "priv.h" struct nvkm_pll_vals; @@ -8,12 +9,11 @@ struct nv04_devinit { int owner; }; -int nv04_devinit_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv04_devinit_dtor(struct nvkm_object *); -int nv04_devinit_init(struct nvkm_object *); -int nv04_devinit_fini(struct nvkm_object *, bool); +int nv04_devinit_new_(const struct nvkm_devinit_func *, struct nvkm_device *, + int, struct nvkm_devinit **); +void *nv04_devinit_dtor(struct nvkm_devinit *); +void nv04_devinit_preinit(struct nvkm_devinit *); +void nv04_devinit_fini(struct nvkm_devinit *); int nv04_devinit_pll_set(struct nvkm_devinit *, u32, u32); void setPLL_single(struct nvkm_devinit *, u32, struct nvkm_pll_vals *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c index 32be8852e0bcc..9891eadca1ce8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c @@ -126,16 +126,18 @@ out: fbmem_fini(fb); } -struct nvkm_oclass * -nv05_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x05), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv05_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv05_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv05_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv05_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c index 5f54906d45b76..570822f83acf5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c @@ -96,16 +96,18 @@ amount_found: fbmem_fini(fb); } -struct nvkm_oclass * -nv10_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x10), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv10_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv10_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv10_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv10_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c index 9f36fff5a1c36..fefafec7e2a7c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c @@ -26,15 +26,17 @@ #include #include -struct nvkm_oclass * -nv1a_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x1a), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv1a_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv1a_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv1a_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c index 1ea129c446745..4ef04e0d88261 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c @@ -39,7 +39,7 @@ nv20_devinit_meminit(struct nvkm_devinit *init) struct io_mapping *fb; /* Map the framebuffer aperture */ - fb = fbmem_init(nv_device(init)); + fb = fbmem_init(device); if (!fb) { nvkm_error(subdev, "failed to map fb\n"); return; @@ -62,16 +62,18 @@ nv20_devinit_meminit(struct nvkm_devinit *init) fbmem_fini(fb); } -struct nvkm_oclass * -nv20_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x20), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_devinit_ctor, - .dtor = nv04_devinit_dtor, - .init = nv04_devinit_init, - .fini = nv04_devinit_fini, - }, +static const struct nvkm_devinit_func +nv20_devinit = { + .dtor = nv04_devinit_dtor, + .preinit = nv04_devinit_preinit, + .post = nv04_devinit_post, .meminit = nv20_devinit_meminit, .pll_set = nv04_devinit_pll_set, - .post = nvbios_init, -}.base; +}; + +int +nv20_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv04_devinit_new_(&nv20_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index bf40509cda94f..b9ffe56d9eff5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -91,19 +91,27 @@ nv50_devinit_disable(struct nvkm_devinit *init) return disable; } -int -nv50_devinit_init(struct nvkm_object *object) +void +nv50_devinit_preinit(struct nvkm_devinit *base) { - struct nv50_devinit *init = (void *)object; + struct nv50_devinit *init = nv50_devinit(base); struct nvkm_subdev *subdev = &init->base.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_bios *bios = device->bios; struct nvkm_subdev *ibus = device->ibus; - struct nvbios_outp info; - struct dcb_output outp; - u8 ver = 0xff, hdr, cnt, len; - int ret, i = 0; + /* our heuristics can't detect whether the board has had its + * devinit scripts executed or not if the display engine is + * missing, assume it's a secondary gpu which requires post + */ + if (!init->base.post) { + u64 disable = nvkm_devinit_disable(&init->base); + if (disable & (1ULL << NVDEV_ENGINE_DISP)) + init->base.post = true; + } + + /* magic to detect whether or not x86 vbios code has executed + * the devinit scripts to initialise the board + */ if (!init->base.post) { if (!nvkm_rdvgac(device, 0, 0x00) && !nvkm_rdvgac(device, 0, 0x1a)) { @@ -118,10 +126,19 @@ nv50_devinit_init(struct nvkm_object *object) */ if (init->base.post && ibus) nvkm_object_init(&ibus->object); +} - ret = nvkm_devinit_init(&init->base); - if (ret) - return ret; +void +nv50_devinit_init(struct nvkm_devinit *base) +{ + struct nv50_devinit *init = nv50_devinit(base); + struct nvkm_subdev *subdev = &init->base.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_bios *bios = device->bios; + struct nvbios_outp info; + struct dcb_output outp; + u8 ver = 0xff, hdr, cnt, len; + int i = 0; /* if we ran the init tables, we have to execute the first script * pointer of each dcb entry's display encoder table in order @@ -131,7 +148,7 @@ nv50_devinit_init(struct nvkm_object *object) if (nvbios_outp_match(bios, outp.hasht, outp.hashm, &ver, &hdr, &cnt, &len, &info)) { struct nvbios_init exec = { - .subdev = nv_subdev(init), + .subdev = subdev, .bios = bios, .offset = info.script[0], .outp = &outp, @@ -143,36 +160,35 @@ nv50_devinit_init(struct nvkm_object *object) } i++; } - - return 0; } int -nv50_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv50_devinit_new_(const struct nvkm_devinit_func *func, + struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) { struct nv50_devinit *init; - int ret; - ret = nvkm_devinit_create(parent, engine, oclass, &init); - *pobject = nv_object(init); - if (ret) - return ret; + if (!(init = kzalloc(sizeof(*init), GFP_KERNEL))) + return -ENOMEM; + *pinit = &init->base; + nvkm_devinit_ctor(func, device, index, &init->base); return 0; } -struct nvkm_oclass * -nv50_devinit_oclass = &(struct nvkm_devinit_impl) { - .base.handle = NV_SUBDEV(DEVINIT, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_devinit_ctor, - .dtor = _nvkm_devinit_dtor, - .init = nv50_devinit_init, - .fini = _nvkm_devinit_fini, - }, +static const struct nvkm_devinit_func +nv50_devinit = { + .preinit = nv50_devinit_preinit, + .init = nv50_devinit_init, + .post = nv04_devinit_post, .pll_set = nv50_devinit_pll_set, .disable = nv50_devinit_disable, - .post = nvbios_init, -}.base; +}; + +int +nv50_devinit_new(struct nvkm_device *device, int index, + struct nvkm_devinit **pinit) +{ + return nv50_devinit_new_(&nv50_devinit, device, index, pinit); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h index c132fb4ae4f5b..5de70a8486b45 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h @@ -1,5 +1,6 @@ -#ifndef __NVKM_DEVINIT_NV50_H__ -#define __NVKM_DEVINIT_NV50_H__ +#ifndef __NV50_DEVINIT_H__ +#define __NV50_DEVINIT_H__ +#define nv50_devinit(p) container_of((p), struct nv50_devinit, base) #include "priv.h" struct nv50_devinit { @@ -7,10 +8,10 @@ struct nv50_devinit { u32 r001540; }; -int nv50_devinit_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -int nv50_devinit_init(struct nvkm_object *); +int nv50_devinit_new_(const struct nvkm_devinit_func *, struct nvkm_device *, + int, struct nvkm_devinit **); +void nv50_devinit_preinit(struct nvkm_devinit *); +void nv50_devinit_init(struct nvkm_devinit *); int nv50_devinit_pll_set(struct nvkm_devinit *, u32, u32); int gt215_devinit_pll_set(struct nvkm_devinit *, u32, u32); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h index bb51a95d80122..e1f6ae58f1d35 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h @@ -1,34 +1,21 @@ #ifndef __NVKM_DEVINIT_PRIV_H__ #define __NVKM_DEVINIT_PRIV_H__ +#define nvkm_devinit(p) container_of((p), struct nvkm_devinit, subdev) #include -struct nvkm_devinit_impl { - struct nvkm_oclass base; +struct nvkm_devinit_func { + void *(*dtor)(struct nvkm_devinit *); + void (*preinit)(struct nvkm_devinit *); + void (*init)(struct nvkm_devinit *); + int (*post)(struct nvkm_devinit *, bool post); + u32 (*mmio)(struct nvkm_devinit *, u32); void (*meminit)(struct nvkm_devinit *); int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq); u64 (*disable)(struct nvkm_devinit *); - u32 (*mmio)(struct nvkm_devinit *, u32); - int (*post)(struct nvkm_subdev *, bool); }; -#define nvkm_devinit_create(p,e,o,d) \ - nvkm_devinit_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_devinit_destroy(p) ({ \ - struct nvkm_devinit *d = (p); \ - _nvkm_devinit_dtor(nv_object(d)); \ -}) -#define nvkm_devinit_init(p) ({ \ - struct nvkm_devinit *d = (p); \ - _nvkm_devinit_init(nv_object(d)); \ -}) -#define nvkm_devinit_fini(p,s) ({ \ - struct nvkm_devinit *d = (p); \ - _nvkm_devinit_fini(nv_object(d), (s)); \ -}) +void nvkm_devinit_ctor(const struct nvkm_devinit_func *, struct nvkm_device *, + int index, struct nvkm_devinit *); -int nvkm_devinit_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_devinit_dtor(struct nvkm_object *); -int _nvkm_devinit_init(struct nvkm_object *); -int _nvkm_devinit_fini(struct nvkm_object *, bool suspend); +int nv04_devinit_post(struct nvkm_devinit *, bool); #endif -- GitLab From 03c8952fb36b58e451b8a93a1a2abd59e09ddf7b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5534/7006] drm/nouveau/fb: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../gpu/drm/nouveau/include/nvkm/subdev/fb.h | 74 ++++------ drivers/gpu/drm/nouveau/nouveau_bo.c | 12 +- drivers/gpu/drm/nouveau/nouveau_gem.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c | 2 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 134 +++++++++++------ drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c | 22 ++- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 68 ++++----- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.h | 12 +- .../gpu/drm/nouveau/nvkm/subdev/fb/gk104.c | 24 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c | 48 ++---- .../gpu/drm/nouveau/nvkm/subdev/fb/gm107.c | 24 +-- .../gpu/drm/nouveau/nvkm/subdev/fb/gt215.c | 22 ++- .../gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c | 22 ++- .../gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c | 22 ++- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c | 54 ++----- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h | 49 ------- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c | 25 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c | 25 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c | 27 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c | 25 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c | 47 +++--- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c | 26 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c | 26 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c | 41 ++---- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c | 41 ++---- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c | 38 ++--- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c | 26 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c | 26 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c | 26 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c | 26 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 127 ++++++++-------- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h | 14 +- drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h | 77 ++++++---- .../gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h | 9 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 5 +- 47 files changed, 648 insertions(+), 812 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 230ee81f3f608..2b17b13b9dbaa 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -51,7 +51,7 @@ u64 nvif_device_time(struct nvif_device *); nv_device(_device->object.priv); \ }) #define nvxx_bios(a) nvxx_device(a)->bios -#define nvxx_fb(a) nvkm_fb(nvxx_device(a)) +#define nvxx_fb(a) nvxx_device(a)->fb #define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) #define nvxx_bar(a) nvxx_device(a)->bar #define nvxx_gpio(a) nvkm_gpio(nvxx_device(a)) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h index f102cf97bb939..85ab72c7f821e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h @@ -46,59 +46,47 @@ struct nvkm_fb_tile { }; struct nvkm_fb { + const struct nvkm_fb_func *func; struct nvkm_subdev subdev; - bool (*memtype_valid)(struct nvkm_fb *, u32 memtype); - struct nvkm_ram *ram; struct { struct nvkm_fb_tile region[16]; int regions; - void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); - void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags, - struct nvkm_fb_tile *); - void (*fini)(struct nvkm_fb *, int i, struct nvkm_fb_tile *); - void (*prog)(struct nvkm_fb *, int i, struct nvkm_fb_tile *); } tile; }; -static inline struct nvkm_fb * -nvkm_fb(void *obj) -{ - /* fbram uses this before device subdev pointer is valid */ - if (nv_iclass(obj, NV_SUBDEV_CLASS) && - nv_subidx(obj) == NVDEV_SUBDEV_FB) - return obj; - - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_FB); -} - -extern struct nvkm_oclass *nv04_fb_oclass; -extern struct nvkm_oclass *nv10_fb_oclass; -extern struct nvkm_oclass *nv1a_fb_oclass; -extern struct nvkm_oclass *nv20_fb_oclass; -extern struct nvkm_oclass *nv25_fb_oclass; -extern struct nvkm_oclass *nv30_fb_oclass; -extern struct nvkm_oclass *nv35_fb_oclass; -extern struct nvkm_oclass *nv36_fb_oclass; -extern struct nvkm_oclass *nv40_fb_oclass; -extern struct nvkm_oclass *nv41_fb_oclass; -extern struct nvkm_oclass *nv44_fb_oclass; -extern struct nvkm_oclass *nv46_fb_oclass; -extern struct nvkm_oclass *nv47_fb_oclass; -extern struct nvkm_oclass *nv49_fb_oclass; -extern struct nvkm_oclass *nv4e_fb_oclass; -extern struct nvkm_oclass *nv50_fb_oclass; -extern struct nvkm_oclass *g84_fb_oclass; -extern struct nvkm_oclass *gt215_fb_oclass; -extern struct nvkm_oclass *mcp77_fb_oclass; -extern struct nvkm_oclass *mcp89_fb_oclass; -extern struct nvkm_oclass *gf100_fb_oclass; -extern struct nvkm_oclass *gk104_fb_oclass; -extern struct nvkm_oclass *gk20a_fb_oclass; -extern struct nvkm_oclass *gm107_fb_oclass; +bool nvkm_fb_memtype_valid(struct nvkm_fb *, u32 memtype); +void nvkm_fb_tile_init(struct nvkm_fb *, int region, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); +void nvkm_fb_tile_fini(struct nvkm_fb *, int region, struct nvkm_fb_tile *); +void nvkm_fb_tile_prog(struct nvkm_fb *, int region, struct nvkm_fb_tile *); + +int nv04_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv10_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv1a_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv20_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv25_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv30_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv35_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv36_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv40_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv41_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv44_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv46_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv47_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv49_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv4e_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int nv50_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int g84_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gt215_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int mcp77_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int mcp89_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gf100_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gk104_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gk20a_fb_new(struct nvkm_device *, int, struct nvkm_fb **); +int gm107_fb_new(struct nvkm_device *, int, struct nvkm_fb **); #include #include diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 79d2ba167fbae..140a1eb9c49e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -50,22 +50,16 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg, int i = reg - drm->tile.reg; struct nvkm_fb *fb = nvxx_fb(&drm->device); struct nvkm_fb_tile *tile = &fb->tile.region[i]; - struct nvkm_engine *engine; nouveau_fence_unref(®->fence); if (tile->pitch) - fb->tile.fini(fb, i, tile); + nvkm_fb_tile_fini(fb, i, tile); if (pitch) - fb->tile.init(fb, i, addr, size, pitch, flags, tile); + nvkm_fb_tile_init(fb, i, addr, size, pitch, flags, tile); - fb->tile.prog(fb, i, tile); - - if ((engine = nvkm_engine(fb, NVDEV_ENGINE_GR))) - engine->tile_prog(engine, i); - if ((engine = nvkm_engine(fb, NVDEV_ENGINE_MPEG))) - engine->tile_prog(engine, i); + nvkm_fb_tile_prog(fb, i, tile); } static struct nouveau_drm_tile * diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index dc2378c01b6d1..2c9981512d27b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c @@ -259,7 +259,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data, struct nouveau_bo *nvbo = NULL; int ret = 0; - if (!fb->memtype_valid(fb, req->info.tile_flags)) { + if (!nvkm_fb_memtype_valid(fb, req->info.tile_flags)) { NV_PRINTK(err, cli, "bad page flags: 0x%08x\n", req->info.tile_flags); return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 7bd8c39649d4b..b34c22ff88037 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -80,7 +80,7 @@ nv4_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv04_devinit_new, -// .fb = nv04_fb_new, + .fb = nv04_fb_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -100,7 +100,7 @@ nv5_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv05_devinit_new, -// .fb = nv04_fb_new, + .fb = nv04_fb_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -120,7 +120,7 @@ nv10_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv10_devinit_new, -// .fb = nv10_fb_new, + .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -139,7 +139,7 @@ nv11_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv10_devinit_new, -// .fb = nv10_fb_new, + .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -160,7 +160,7 @@ nv15_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv10_devinit_new, -// .fb = nv10_fb_new, + .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -181,7 +181,7 @@ nv17_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv10_devinit_new, -// .fb = nv10_fb_new, + .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -202,7 +202,7 @@ nv18_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv10_devinit_new, -// .fb = nv10_fb_new, + .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -223,7 +223,7 @@ nv1a_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv1a_fb_new, + .fb = nv1a_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -244,7 +244,7 @@ nv1f_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv1a_fb_new, + .fb = nv1a_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -265,7 +265,7 @@ nv20_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv20_fb_new, + .fb = nv20_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -286,7 +286,7 @@ nv25_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv25_fb_new, + .fb = nv25_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -307,7 +307,7 @@ nv28_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv25_fb_new, + .fb = nv25_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -328,7 +328,7 @@ nv2a_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv25_fb_new, + .fb = nv25_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -349,7 +349,7 @@ nv30_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv30_fb_new, + .fb = nv30_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -370,7 +370,7 @@ nv31_chipset = { .bus = nv31_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv30_fb_new, + .fb = nv30_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -392,7 +392,7 @@ nv34_chipset = { .bus = nv31_bus_new, .clk = nv04_clk_new, .devinit = nv10_devinit_new, -// .fb = nv10_fb_new, + .fb = nv10_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -414,7 +414,7 @@ nv35_chipset = { .bus = nv04_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv35_fb_new, + .fb = nv35_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -435,7 +435,7 @@ nv36_chipset = { .bus = nv31_bus_new, .clk = nv04_clk_new, .devinit = nv20_devinit_new, -// .fb = nv36_fb_new, + .fb = nv36_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, @@ -457,7 +457,7 @@ nv40_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv40_fb_new, + .fb = nv40_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -482,7 +482,7 @@ nv41_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv41_fb_new, + .fb = nv41_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -507,7 +507,7 @@ nv42_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv41_fb_new, + .fb = nv41_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -532,7 +532,7 @@ nv43_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv41_fb_new, + .fb = nv41_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -557,7 +557,7 @@ nv44_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv44_fb_new, + .fb = nv44_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -582,7 +582,7 @@ nv45_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv40_fb_new, + .fb = nv40_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -607,7 +607,7 @@ nv46_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv46_fb_new, + .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -632,7 +632,7 @@ nv47_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv47_fb_new, + .fb = nv47_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -657,7 +657,7 @@ nv49_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv49_fb_new, + .fb = nv49_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -682,7 +682,7 @@ nv4a_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv44_fb_new, + .fb = nv44_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -707,7 +707,7 @@ nv4b_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv49_fb_new, + .fb = nv49_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -732,7 +732,7 @@ nv4c_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv46_fb_new, + .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -757,7 +757,7 @@ nv4e_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv4e_fb_new, + .fb = nv4e_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv4e_i2c_new, // .imem = nv40_instmem_new, @@ -783,7 +783,7 @@ nv50_chipset = { .bus = nv50_bus_new, .clk = nv50_clk_new, .devinit = nv50_devinit_new, -// .fb = nv50_fb_new, + .fb = nv50_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, @@ -810,7 +810,7 @@ nv63_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv46_fb_new, + .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -835,7 +835,7 @@ nv67_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv46_fb_new, + .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -860,7 +860,7 @@ nv68_chipset = { .bus = nv31_bus_new, .clk = nv40_clk_new, .devinit = nv1a_devinit_new, -// .fb = nv46_fb_new, + .fb = nv46_fb_new, // .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, @@ -886,7 +886,7 @@ nv84_chipset = { .bus = nv50_bus_new, .clk = g84_clk_new, .devinit = g84_devinit_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, @@ -917,7 +917,7 @@ nv86_chipset = { .bus = nv50_bus_new, .clk = g84_clk_new, .devinit = g84_devinit_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, @@ -948,7 +948,7 @@ nv92_chipset = { .bus = nv50_bus_new, .clk = g84_clk_new, .devinit = g84_devinit_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, @@ -979,7 +979,7 @@ nv94_chipset = { .bus = g94_bus_new, .clk = g84_clk_new, .devinit = g84_devinit_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1016,7 +1016,7 @@ nv96_chipset = { // .mc = g94_mc_new, .bus = g94_bus_new, // .timer = nv04_timer_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .imem = nv50_instmem_new, // .mmu = nv50_mmu_new, .bar = g84_bar_new, @@ -1047,7 +1047,7 @@ nv98_chipset = { // .mc = g98_mc_new, .bus = g94_bus_new, // .timer = nv04_timer_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .imem = nv50_instmem_new, // .mmu = nv50_mmu_new, .bar = g84_bar_new, @@ -1072,7 +1072,7 @@ nva0_chipset = { .bus = g94_bus_new, .clk = g84_clk_new, .devinit = g84_devinit_new, -// .fb = g84_fb_new, + .fb = g84_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = nv50_i2c_new, @@ -1103,7 +1103,7 @@ nva3_chipset = { .bus = g94_bus_new, .clk = gt215_clk_new, .devinit = gt215_devinit_new, -// .fb = gt215_fb_new, + .fb = gt215_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1136,7 +1136,7 @@ nva5_chipset = { .bus = g94_bus_new, .clk = gt215_clk_new, .devinit = gt215_devinit_new, -// .fb = gt215_fb_new, + .fb = gt215_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1168,7 +1168,7 @@ nva8_chipset = { .bus = g94_bus_new, .clk = gt215_clk_new, .devinit = gt215_devinit_new, -// .fb = gt215_fb_new, + .fb = gt215_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1200,7 +1200,7 @@ nvaa_chipset = { .bus = g94_bus_new, .clk = mcp77_clk_new, .devinit = g98_devinit_new, -// .fb = mcp77_fb_new, + .fb = mcp77_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1231,7 +1231,7 @@ nvac_chipset = { .bus = g94_bus_new, .clk = mcp77_clk_new, .devinit = g98_devinit_new, -// .fb = mcp77_fb_new, + .fb = mcp77_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1262,7 +1262,7 @@ nvaf_chipset = { .bus = g94_bus_new, .clk = gt215_clk_new, .devinit = mcp89_devinit_new, -// .fb = mcp89_fb_new, + .fb = mcp89_fb_new, // .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1294,7 +1294,7 @@ nvc0_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1329,7 +1329,7 @@ nvc1_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1363,7 +1363,7 @@ nvc3_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1397,7 +1397,7 @@ nvc4_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1432,7 +1432,7 @@ nvc8_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1467,7 +1467,7 @@ nvce_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1502,7 +1502,7 @@ nvcf_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, @@ -1536,7 +1536,7 @@ nvd7_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = gf110_gpio_new, // .i2c = gf117_i2c_new, @@ -1568,7 +1568,7 @@ nvd9_chipset = { .bus = gf100_bus_new, .clk = gf100_clk_new, .devinit = gf100_devinit_new, -// .fb = gf100_fb_new, + .fb = gf100_fb_new, // .fuse = gf100_fuse_new, // .gpio = gf110_gpio_new, // .i2c = gf110_i2c_new, @@ -1602,7 +1602,7 @@ nve4_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, @@ -1638,7 +1638,7 @@ nve6_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, @@ -1674,7 +1674,7 @@ nve7_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, @@ -1708,7 +1708,7 @@ nvea_chipset = { .bar = gk20a_bar_new, .bus = gf100_bus_new, .clk = gk20a_clk_new, -// .fb = gk20a_fb_new, + .fb = gk20a_fb_new, // .fuse = gf100_fuse_new, // .ibus = gk20a_ibus_new, // .imem = gk20a_instmem_new, @@ -1734,7 +1734,7 @@ nvf0_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, @@ -1770,7 +1770,7 @@ nvf1_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gf110_i2c_new, @@ -1806,7 +1806,7 @@ nv106_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, @@ -1841,7 +1841,7 @@ nv108_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gf100_devinit_new, -// .fb = gk104_fb_new, + .fb = gk104_fb_new, // .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, @@ -1876,7 +1876,7 @@ nv117_chipset = { .bus = gf100_bus_new, .clk = gk104_clk_new, .devinit = gm107_devinit_new, -// .fb = gm107_fb_new, + .fb = gm107_fb_new, // .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gf110_i2c_new, @@ -1905,7 +1905,7 @@ nv124_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm204_devinit_new, -// .fb = gm107_fb_new, + .fb = gm107_fb_new, // .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gm204_i2c_new, @@ -1934,7 +1934,7 @@ nv126_chipset = { .bios = nvkm_bios_new, .bus = gf100_bus_new, .devinit = gm204_devinit_new, -// .fb = gm107_fb_new, + .fb = gm107_fb_new, // .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gm204_i2c_new, @@ -1961,7 +1961,7 @@ nv12b_chipset = { .name = "GM20B", .bar = gk20a_bar_new, .bus = gf100_bus_new, -// .fb = gk20a_fb_new, + .fb = gk20a_fb_new, // .fuse = gm107_fuse_new, // .ibus = gk20a_ibus_new, // .imem = gk20a_instmem_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 87a9cdb42bd64..dbc9f52f9e594 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -35,7 +35,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -62,7 +61,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -89,7 +87,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -115,7 +112,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -142,7 +138,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -168,7 +163,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -194,7 +188,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -221,7 +214,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -247,7 +239,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 67c7b6386a4ce..af4368784ac94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -35,7 +35,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -63,7 +62,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -91,7 +89,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -115,7 +112,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; @@ -137,7 +133,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -165,7 +160,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -193,7 +187,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -220,7 +213,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index f9f0663f2206c..6723b9eba1007 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -35,7 +35,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -73,7 +72,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -108,7 +106,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; @@ -137,7 +134,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 0cabcfa8b63e1..d65d2943d776c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -31,7 +31,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -44,7 +43,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 09eedfecfb367..dd42f9e64f76a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -32,7 +32,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -44,7 +43,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -58,7 +56,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -72,7 +69,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -86,7 +82,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -100,7 +95,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -114,7 +108,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -128,7 +121,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 9ea12b6426c6e..3e79a02ac687c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -32,7 +32,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -46,7 +45,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -60,7 +58,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -74,7 +71,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 48b927bd104b9..b045515a49037 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -32,7 +32,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -46,7 +45,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -60,7 +58,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -75,7 +72,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -90,7 +86,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index ef660d958f6bd..430707755ffa1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -33,7 +33,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -51,7 +50,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -69,7 +67,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -87,7 +84,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -105,7 +101,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -123,7 +118,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -141,7 +135,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -159,7 +152,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -177,7 +169,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -195,7 +186,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -213,7 +203,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -231,7 +220,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -249,7 +237,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -267,7 +254,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -285,7 +271,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -303,7 +288,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 7b942dfa7f4cb..3b22a2e3459ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -35,7 +35,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -55,7 +54,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -78,7 +76,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -101,7 +98,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -124,7 +120,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -147,7 +142,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -170,7 +164,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -193,7 +186,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -216,7 +208,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -239,7 +230,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -262,7 +252,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; @@ -287,7 +276,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; @@ -311,7 +299,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; @@ -335,7 +322,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_FB ] = mcp89_fb_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c index 27fa96b222e3f..1e13278cf3062 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c @@ -569,7 +569,7 @@ nv50_gr_construct_mmio(struct nvkm_grctx *ctx) else if (device->chipset < 0xa0) gr_def(ctx, 0x407d08, 0x00390040); else { - if (nvkm_fb(device)->ram->type != NVKM_RAM_TYPE_GDDR5) + if (device->fb->ram->type != NVKM_RAM_TYPE_GDDR5) gr_def(ctx, 0x407d08, 0x003d0040); else gr_def(ctx, 0x407d08, 0x003c0040); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index d435bd155684f..0f39ff883ec0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -26,6 +26,38 @@ #include #include +#include +#include + +bool +nvkm_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) +{ + return fb->func->memtype_valid(fb, memtype); +} + +void +nvkm_fb_tile_fini(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) +{ + fb->func->tile.fini(fb, region, tile); +} + +void +nvkm_fb_tile_init(struct nvkm_fb *fb, int region, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *tile) +{ + fb->func->tile.init(fb, region, addr, size, pitch, flags, tile); +} + +void +nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) +{ + struct nvkm_device *device = fb->subdev.device; + fb->func->tile.prog(fb, region, tile); + if (likely(device->gr)) + device->gr->engine.tile_prog(&device->gr->engine, region); + if (likely(device->mpeg)) + device->mpeg->tile_prog(device->mpeg, region); +} int nvkm_fb_bios_memtype(struct nvkm_bios *bios) @@ -52,69 +84,87 @@ nvkm_fb_bios_memtype(struct nvkm_bios *bios) return NVKM_RAM_TYPE_UNKNOWN; } -int -_nvkm_fb_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_fb_intr(struct nvkm_subdev *subdev) { - struct nvkm_fb *fb = (void *)object; - return nvkm_subdev_fini_old(&fb->subdev, suspend); + struct nvkm_fb *fb = nvkm_fb(subdev); + if (fb->func->intr) + fb->func->intr(fb); } -int -_nvkm_fb_init(struct nvkm_object *object) +static int +nvkm_fb_oneinit(struct nvkm_subdev *subdev) { - struct nvkm_fb *fb = (void *)object; - int ret, i; + struct nvkm_fb *fb = nvkm_fb(subdev); + if (fb->func->ram_new) { + int ret = fb->func->ram_new(fb, &fb->ram); + if (ret) { + nvkm_error(subdev, "vram setup failed, %d\n", ret); + return ret; + } + } + return 0; +} - ret = nvkm_subdev_init_old(&fb->subdev); - if (ret) - return ret; +static int +nvkm_fb_init(struct nvkm_subdev *subdev) +{ + struct nvkm_fb *fb = nvkm_fb(subdev); + int ret, i; - if (fb->ram) - nvkm_ram_init(fb->ram); + if (fb->ram) { + ret = nvkm_ram_init(fb->ram); + if (ret) + return ret; + } for (i = 0; i < fb->tile.regions; i++) - fb->tile.prog(fb, i, &fb->tile.region[i]); + fb->func->tile.prog(fb, i, &fb->tile.region[i]); + if (fb->func->init) + fb->func->init(fb); return 0; } -void -_nvkm_fb_dtor(struct nvkm_object *object) +static void * +nvkm_fb_dtor(struct nvkm_subdev *subdev) { - struct nvkm_fb *fb = (void *)object; + struct nvkm_fb *fb = nvkm_fb(subdev); int i; for (i = 0; i < fb->tile.regions; i++) - fb->tile.fini(fb, i, &fb->tile.region[i]); + fb->func->tile.fini(fb, i, &fb->tile.region[i]); nvkm_ram_del(&fb->ram); - nvkm_subdev_destroy(&fb->subdev); -} -int -nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - struct nvkm_fb_impl *impl = (void *)oclass; - struct nvkm_fb *fb; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PFB", "fb", - length, pobject); - fb = *pobject; - if (ret) - return ret; - - fb->memtype_valid = impl->memtype; + if (fb->func->dtor) + return fb->func->dtor(fb); + return fb; +} - if (!impl->ram_new) - return 0; +static const struct nvkm_subdev_func +nvkm_fb = { + .dtor = nvkm_fb_dtor, + .oneinit = nvkm_fb_oneinit, + .init = nvkm_fb_init, + .intr = nvkm_fb_intr, +}; - ret = impl->ram_new(fb, &fb->ram); - if (ret) { - nvkm_error(&fb->subdev, "vram init failed, %d\n", ret); - return ret; - } +void +nvkm_fb_ctor(const struct nvkm_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb *fb) +{ + nvkm_subdev_ctor(&nvkm_fb, device, index, 0, &fb->subdev); + fb->func = func; + fb->tile.regions = fb->func->tile.regions; +} +int +nvkm_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb **pfb) +{ + if (!(*pfb = kzalloc(sizeof(**pfb), GFP_KERNEL))) + return -ENOMEM; + nvkm_fb_ctor(func, device, index, *pfb); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c index 1fdb6c3493c68..9c28392d07e43 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c @@ -24,16 +24,14 @@ #include "nv50.h" #include "ram.h" -struct nvkm_oclass * -g84_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x84), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram_new = nv50_ram_new, +static const struct nv50_fb_func +g84_fb = { + .ram_new = nv50_ram_new, .trap = 0x001d07ff, -}.base.base; +}; + +int +g84_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&g84_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index b269f8f67eea4..ef3149aa51242 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -33,9 +33,11 @@ gf100_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) return likely((gf100_pte_storage_type_map[memtype] != 0xff)); } -static void -gf100_fb_intr(struct nvkm_subdev *subdev) +void +gf100_fb_intr(struct nvkm_fb *base) { + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_subdev *subdev = &fb->base.subdev; struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x000100); if (intr & 0x08000000) @@ -44,29 +46,23 @@ gf100_fb_intr(struct nvkm_subdev *subdev) nvkm_debug(subdev, "PBFB intr\n"); } -int -gf100_fb_init(struct nvkm_object *object) +void +gf100_fb_init(struct nvkm_fb *base) { - struct gf100_fb *fb = (void *)object; + struct gf100_fb *fb = gf100_fb(base); struct nvkm_device *device = fb->base.subdev.device; - int ret; - - ret = nvkm_fb_init(&fb->base); - if (ret) - return ret; if (fb->r100c10_page) nvkm_wr32(device, 0x100c10, fb->r100c10 >> 8); nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ - return 0; } -void -gf100_fb_dtor(struct nvkm_object *object) +void * +gf100_fb_dtor(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(object); - struct gf100_fb *fb = (void *)object; + struct gf100_fb *fb = gf100_fb(base); + struct nvkm_device *device = fb->base.subdev.device; if (fb->r100c10_page) { dma_unmap_page(nv_device_base(device), fb->r100c10, PAGE_SIZE, @@ -74,22 +70,19 @@ gf100_fb_dtor(struct nvkm_object *object) __free_page(fb->r100c10_page); } - nvkm_fb_destroy(&fb->base); + return fb; } int -gf100_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb **pfb) { - struct nvkm_device *device = nv_device(parent); struct gf100_fb *fb; - int ret; - ret = nvkm_fb_create(parent, engine, oclass, &fb); - *pobject = nv_object(fb); - if (ret) - return ret; + if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL))) + return -ENOMEM; + nvkm_fb_ctor(func, device, index, &fb->base); + *pfb = &fb->base; fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (fb->r100c10_page) { @@ -100,19 +93,20 @@ gf100_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return -EFAULT; } - nv_subdev(fb)->intr = gf100_fb_intr; return 0; } -struct nvkm_oclass * -gf100_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fb_ctor, - .dtor = gf100_fb_dtor, - .init = gf100_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, +static const struct nvkm_fb_func +gf100_fb = { + .dtor = gf100_fb_dtor, + .init = gf100_fb_init, + .intr = gf100_fb_intr, .ram_new = gf100_ram_new, -}.base; + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gf100_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gf100_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h index a0f6497d7a3f0..2160e5a39c9a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h @@ -1,5 +1,6 @@ #ifndef __NVKM_RAM_NVC0_H__ #define __NVKM_RAM_NVC0_H__ +#define gf100_fb(p) container_of((p), struct gf100_fb, base) #include "priv.h" struct gf100_fb { @@ -8,10 +9,9 @@ struct gf100_fb { dma_addr_t r100c10; }; -int gf100_fb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_fb_dtor(struct nvkm_object *); -int gf100_fb_init(struct nvkm_object *); -bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); +int gf100_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *, + int index, struct nvkm_fb **); +void *gf100_fb_dtor(struct nvkm_fb *); +void gf100_fb_init(struct nvkm_fb *); +void gf100_fb_intr(struct nvkm_fb *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c index 6ed6181a7b344..0edb3c316f5cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c @@ -24,15 +24,17 @@ #include "gf100.h" #include "ram.h" -struct nvkm_oclass * -gk104_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fb_ctor, - .dtor = gf100_fb_dtor, - .init = gf100_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, +static const struct nvkm_fb_func +gk104_fb = { + .dtor = gf100_fb_dtor, + .init = gf100_fb_init, + .intr = gf100_fb_intr, .ram_new = gk104_ram_new, -}.base; + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gk104_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gk104_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c index 24cbe90afec16..81447eb4c948b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c @@ -19,47 +19,23 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "gf100.h" +#include "priv.h" -static int -gk20a_fb_init(struct nvkm_object *object) +static void +gk20a_fb_init(struct nvkm_fb *fb) { - struct nvkm_fb *fb = (void *)object; struct nvkm_device *device = fb->subdev.device; - int ret; - - ret = nvkm_fb_init(fb); - if (ret) - return ret; - nvkm_mask(device, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */ - return 0; } -static int -gk20a_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_fb *fb; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &fb); - *pobject = nv_object(fb); - if (ret) - return ret; +static const struct nvkm_fb_func +gk20a_fb = { + .init = gk20a_fb_init, + .memtype_valid = gf100_fb_memtype_valid, +}; - return 0; +int +gk20a_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&gk20a_fb, device, index, pfb); } - -struct nvkm_oclass * -gk20a_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = gk20a_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c index 71e3bd50848a4..2a91df8655ddb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c @@ -24,15 +24,17 @@ #include "gf100.h" #include "ram.h" -struct nvkm_oclass * -gm107_fb_oclass = &(struct nvkm_fb_impl) { - .base.handle = NV_SUBDEV(FB, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fb_ctor, - .dtor = gf100_fb_dtor, - .init = gf100_fb_init, - .fini = _nvkm_fb_fini, - }, - .memtype = gf100_fb_memtype_valid, +static const struct nvkm_fb_func +gm107_fb = { + .dtor = gf100_fb_dtor, + .init = gf100_fb_init, + .intr = gf100_fb_intr, .ram_new = gm107_ram_new, -}.base; + .memtype_valid = gf100_fb_memtype_valid, +}; + +int +gm107_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return gf100_fb_new_(&gm107_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c index 425d289d4acc1..ebb30608d5efa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c @@ -24,16 +24,14 @@ #include "nv50.h" #include "ram.h" -struct nvkm_oclass * -gt215_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0xa3), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram_new = gt215_ram_new, +static const struct nv50_fb_func +gt215_fb = { + .ram_new = gt215_ram_new, .trap = 0x000d0fff, -}.base.base; +}; + +int +gt215_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(>215_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c index 3caed0f12a77a..73b3b86a28262 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c @@ -24,16 +24,14 @@ #include "nv50.h" #include "ram.h" -struct nvkm_oclass * -mcp77_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0xaa), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram_new = mcp77_ram_new, +static const struct nv50_fb_func +mcp77_fb = { + .ram_new = mcp77_ram_new, .trap = 0x001d07ff, -}.base.base; +}; + +int +mcp77_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&mcp77_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c index 3ff0bf9cefd25..6d11e32ec7add 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c @@ -24,16 +24,14 @@ #include "nv50.h" #include "ram.h" -struct nvkm_oclass * -mcp89_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0xaf), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram_new = mcp77_ram_new, +static const struct nv50_fb_func +mcp89_fb = { + .ram_new = mcp77_ram_new, .trap = 0x089d1fff, -}.base.base; +}; + +int +mcp89_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&mcp89_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c index 8c8b4b35930d6..8ff2e5db4571c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" #include "ram.h" #include "regsnv04.h" @@ -30,60 +30,30 @@ nv04_fb_memtype_valid(struct nvkm_fb *fb, u32 tile_flags) { if (!(tile_flags & 0xff00)) return true; - return false; } -static int -nv04_fb_init(struct nvkm_object *object) +static void +nv04_fb_init(struct nvkm_fb *fb) { - struct nvkm_fb *fb = (void *)object; struct nvkm_device *device = fb->subdev.device; - int ret; - - ret = nvkm_fb_init(fb); - if (ret) - return ret; /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows * nvidia reading PFB_CFG_0, then writing back its original value. * (which was 0x701114 in this case) */ nvkm_wr32(device, NV04_PFB_CFG0, 0x1114); - return 0; } +static const struct nvkm_fb_func +nv04_fb = { + .init = nv04_fb_init, + .ram_new = nv04_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + int -nv04_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) { - struct nv04_fb_impl *impl = (void *)oclass; - struct nvkm_fb *fb; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &fb); - *pobject = nv_object(fb); - if (ret) - return ret; - - fb->tile.regions = impl->tile.regions; - fb->tile.init = impl->tile.init; - fb->tile.comp = impl->tile.comp; - fb->tile.fini = impl->tile.fini; - fb->tile.prog = impl->tile.prog; - return 0; + return nvkm_fb_new_(&nv04_fb, device, index, pfb); } - -struct nvkm_oclass * -nv04_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x04), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv04_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv04_ram_new, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h deleted file mode 100644 index b85ef39835393..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef __NVKM_FB_NV04_H__ -#define __NVKM_FB_NV04_H__ -#include "priv.h" - -int nv04_fb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -struct nv04_fb_impl { - struct nvkm_fb_impl base; - struct { - int regions; - void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); - void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags, - struct nvkm_fb_tile *); - void (*fini)(struct nvkm_fb *, int i, - struct nvkm_fb_tile *); - void (*prog)(struct nvkm_fb *, int i, - struct nvkm_fb_tile *); - } tile; -}; - -void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); -void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); -void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); -void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); -void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -int nv30_fb_init(struct nvkm_object *); -void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); - -void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags, - struct nvkm_fb_tile *); - -int nv41_fb_init(struct nvkm_object *); -void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -int nv44_fb_init(struct nvkm_object *); -void nv44_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); - -void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, - u32 pitch, u32 flags, struct nvkm_fb_tile *); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c index a51c094df579e..e8c44f5a3d845 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" void @@ -54,19 +54,18 @@ nv10_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) nvkm_rd32(device, 0x100240 + (i * 0x10)); } -struct nvkm_oclass * -nv10_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x10), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv10_ram_new, +static const struct nvkm_fb_func +nv10_fb = { .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, .tile.prog = nv10_fb_tile_prog, -}.base.base; + .ram_new = nv10_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv10_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv10_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c index e56b93d593c53..2ae0beb87567d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c @@ -23,22 +23,21 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" -struct nvkm_oclass * -nv1a_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x1a), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv1a_ram_new, +static const struct nvkm_fb_func +nv1a_fb = { .tile.regions = 8, .tile.init = nv10_fb_tile_init, .tile.fini = nv10_fb_tile_fini, .tile.prog = nv10_fb_tile_prog, -}.base.base; + .ram_new = nv1a_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv1a_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv1a_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c index ada818ac1735e..126865dfe7773 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" void @@ -34,7 +34,7 @@ nv20_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, tile->limit = max(1u, addr + size) - 1; tile->pitch = pitch; if (flags & 4) { - fb->tile.comp(fb, i, size, flags, tile); + fb->func->tile.comp(fb, i, size, flags, tile); tile->addr |= 2; } } @@ -77,20 +77,19 @@ nv20_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) nvkm_wr32(device, 0x100300 + (i * 0x04), tile->zcomp); } -struct nvkm_oclass * -nv20_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x20), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv20_ram_new, +static const struct nvkm_fb_func +nv20_fb = { .tile.regions = 8, .tile.init = nv20_fb_tile_init, .tile.comp = nv20_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv20_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv20_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c index 31dc7cf3aa0c8..c56746d2a502c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" static void @@ -42,20 +42,19 @@ nv25_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, } } -struct nvkm_oclass * -nv25_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x25), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = _nvkm_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv20_ram_new, +static const struct nvkm_fb_func +nv25_fb = { .tile.regions = 8, .tile.init = nv20_fb_tile_init, .tile.comp = nv25_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv25_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv25_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c index 6bddaac59ad88..2a7c4831b8217 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" void @@ -34,8 +34,8 @@ nv30_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, if (!(flags & 4)) { tile->addr = (0 << 4); } else { - if (fb->tile.comp) /* z compression */ - fb->tile.comp(fb, i, size, flags, tile); + if (fb->func->tile.comp) /* z compression */ + fb->func->tile.comp(fb, i, size, flags, tile); tile->addr = (1 << 4); } @@ -65,7 +65,7 @@ nv30_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, static int calc_bias(struct nvkm_fb *fb, int k, int i, int j) { - struct nvkm_device *device = nv_device(fb); + struct nvkm_device *device = fb->subdev.device; int b = (device->chipset > 0x30 ? nvkm_rd32(device, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) : @@ -88,16 +88,11 @@ calc_ref(struct nvkm_fb *fb, int l, int k, int i) return x; } -int -nv30_fb_init(struct nvkm_object *object) +void +nv30_fb_init(struct nvkm_fb *fb) { - struct nvkm_device *device = nv_device(object); - struct nvkm_fb *fb = (void *)object; - int ret, i, j; - - ret = nvkm_fb_init(fb); - if (ret) - return ret; + struct nvkm_device *device = fb->subdev.device; + int i, j; /* Init the memory timing regs at 0x10037c/0x1003ac */ if (device->chipset == 0x30 || @@ -117,24 +112,22 @@ nv30_fb_init(struct nvkm_object *object) calc_ref(fb, l, 1, j)); } } - - return 0; } -struct nvkm_oclass * -nv30_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x30), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv30_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv20_ram_new, +static const struct nvkm_fb_func +nv30_fb = { + .init = nv30_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv30_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv30_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv30_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c index e4fd94d003aa0..1604b3789ad16 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" static void @@ -43,20 +43,20 @@ nv35_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, } } -struct nvkm_oclass * -nv35_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x35), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv30_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv20_ram_new, +static const struct nvkm_fb_func +nv35_fb = { + .init = nv30_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv35_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv35_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv35_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c index 51b9b4a589309..80cc0a6e3416d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" static void @@ -43,20 +43,20 @@ nv36_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, } } -struct nvkm_oclass * -nv36_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x36), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv30_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv20_ram_new, +static const struct nvkm_fb_func +nv36_fb = { + .init = nv30_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv36_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv20_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv36_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv36_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c index fa1f8047714e8..deec46a310f8f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" void @@ -43,35 +43,26 @@ nv40_fb_tile_comp(struct nvkm_fb *fb, int i, u32 size, u32 flags, } } -static int -nv40_fb_init(struct nvkm_object *object) +static void +nv40_fb_init(struct nvkm_fb *fb) { - struct nvkm_fb *fb = (void *)object; - struct nvkm_device *device = fb->subdev.device; - int ret; - - ret = nvkm_fb_init(fb); - if (ret) - return ret; - - nvkm_mask(device, 0x10033c, 0x00008000, 0x00000000); - return 0; + nvkm_mask(fb->subdev.device, 0x10033c, 0x00008000, 0x00000000); } -struct nvkm_oclass * -nv40_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x40), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv40_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv40_ram_new, +static const struct nvkm_fb_func +nv40_fb = { + .init = nv40_fb_init, .tile.regions = 8, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv20_fb_tile_prog, -}.base.base; + .ram_new = nv40_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv40_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv40_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c index 5e11dd8ab5c66..79e57dd5a00f4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" void @@ -37,35 +37,26 @@ nv41_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) nvkm_wr32(device, 0x100700 + (i * 0x04), tile->zcomp); } -int -nv41_fb_init(struct nvkm_object *object) +void +nv41_fb_init(struct nvkm_fb *fb) { - struct nvkm_fb *fb = (void *)object; - struct nvkm_device *device = fb->subdev.device; - int ret; - - ret = nvkm_fb_init(fb); - if (ret) - return ret; - - nvkm_wr32(device, 0x100800, 0x00000001); - return 0; + nvkm_wr32(fb->subdev.device, 0x100800, 0x00000001); } -struct nvkm_oclass * -nv41_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x41), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv41_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv41_ram_new, +static const struct nvkm_fb_func +nv41_fb = { + .init = nv41_fb_init, .tile.regions = 12, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv41_fb_tile_prog, -}.base.base; + .ram_new = nv41_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv41_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv41_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c index ffdf74b698a74..06246cce5ec45 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" static void @@ -46,35 +46,27 @@ nv44_fb_tile_prog(struct nvkm_fb *fb, int i, struct nvkm_fb_tile *tile) nvkm_rd32(device, 0x100600 + (i * 0x10)); } -int -nv44_fb_init(struct nvkm_object *object) +void +nv44_fb_init(struct nvkm_fb *fb) { - struct nvkm_fb *fb = (void *)object; struct nvkm_device *device = fb->subdev.device; - int ret; - - ret = nvkm_fb_init(fb); - if (ret) - return ret; - nvkm_wr32(device, 0x100850, 0x80000000); nvkm_wr32(device, 0x100800, 0x00000001); - return 0; } -struct nvkm_oclass * -nv44_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x44), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv44_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv44_ram_new, +static const struct nvkm_fb_func +nv44_fb = { + .init = nv44_fb_init, .tile.regions = 12, .tile.init = nv44_fb_tile_init, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv44_fb_tile_prog, -}.base.base; + .ram_new = nv44_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv44_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv44_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c index c9685991042a0..3598a1aa65beb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c @@ -23,7 +23,7 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" void @@ -40,19 +40,19 @@ nv46_fb_tile_init(struct nvkm_fb *fb, int i, u32 addr, u32 size, u32 pitch, tile->pitch = pitch; } -struct nvkm_oclass * -nv46_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x46), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv44_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv44_ram_new, +static const struct nvkm_fb_func +nv46_fb = { + .init = nv44_fb_init, .tile.regions = 15, .tile.init = nv46_fb_tile_init, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv44_fb_tile_prog, -}.base.base; + .ram_new = nv44_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv46_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv46_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c index f150f2df16dc1..c505e44293142 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c @@ -23,23 +23,23 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" -struct nvkm_oclass * -nv47_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x47), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv41_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv41_ram_new, +static const struct nvkm_fb_func +nv47_fb = { + .init = nv41_fb_init, .tile.regions = 15, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv41_fb_tile_prog, -}.base.base; + .ram_new = nv41_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv47_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv47_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c index 806c7851a1645..7b91b9f170e5b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c @@ -23,23 +23,23 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" -struct nvkm_oclass * -nv49_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x49), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv41_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv49_ram_new, +static const struct nvkm_fb_func +nv49_fb = { + .init = nv41_fb_init, .tile.regions = 15, .tile.init = nv30_fb_tile_init, .tile.comp = nv40_fb_tile_comp, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv41_fb_tile_prog, -}.base.base; + .ram_new = nv49_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv49_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv49_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c index 6f24565c97745..4e98210c1b1c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c @@ -23,22 +23,22 @@ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ -#include "nv04.h" +#include "priv.h" #include "ram.h" -struct nvkm_oclass * -nv4e_fb_oclass = &(struct nv04_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x4e), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fb_ctor, - .dtor = _nvkm_fb_dtor, - .init = nv44_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv04_fb_memtype_valid, - .base.ram_new = nv4e_ram_new, +static const struct nvkm_fb_func +nv4e_fb = { + .init = nv44_fb_init, .tile.regions = 12, .tile.init = nv46_fb_tile_init, .tile.fini = nv20_fb_tile_fini, .tile.prog = nv44_fb_tile_prog, -}.base.base; + .ram_new = nv44_ram_new, + .memtype_valid = nv04_fb_memtype_valid, +}; + +int +nv4e_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nvkm_fb_new_(&nv4e_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index 711ea96bcd36a..c2b6ccde7473f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -40,7 +40,14 @@ nv50_fb_memtype[0x80] = { 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0 }; -bool +static int +nv50_fb_ram_new(struct nvkm_fb *base, struct nvkm_ram **pram) +{ + struct nv50_fb *fb = nv50_fb(base); + return fb->func->ram_new(&fb->base, pram); +} + +static bool nv50_fb_memtype_valid(struct nvkm_fb *fb, u32 memtype) { return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0; @@ -143,10 +150,11 @@ static const struct nvkm_enum vm_fault[] = { }; static void -nv50_fb_intr(struct nvkm_subdev *subdev) +nv50_fb_intr(struct nvkm_fb *base) { - struct nv50_fb *fb = (void *)subdev; - struct nvkm_device *device = fb->base.subdev.device; + struct nv50_fb *fb = nv50_fb(base); + struct nvkm_subdev *subdev = &fb->base.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fifo *fifo = device->fifo; struct nvkm_fifo_chan *chan; const struct nvkm_enum *en, *re, *cl, *sc; @@ -202,40 +210,28 @@ nv50_fb_intr(struct nvkm_subdev *subdev) nvkm_fifo_chan_put(fifo, flags, &chan); } -int -nv50_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +nv50_fb_init(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(parent); - struct nv50_fb *fb; - int ret; - - ret = nvkm_fb_create(parent, engine, oclass, &fb); - *pobject = nv_object(fb); - if (ret) - return ret; + struct nv50_fb *fb = nv50_fb(base); + struct nvkm_device *device = fb->base.subdev.device; - fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (fb->r100c08_page) { - fb->r100c08 = dma_map_page(nv_device_base(device), - fb->r100c08_page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), fb->r100c08)) - return -EFAULT; - } else { - nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n"); - } + /* Not a clue what this is exactly. Without pointing it at a + * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) + * cause IOMMU "read from address 0" errors (rh#561267) + */ + nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8); - nv_subdev(fb)->intr = nv50_fb_intr; - return 0; + /* This is needed to get meaningful information from 100c90 + * on traps. No idea what these values mean exactly. */ + nvkm_wr32(device, 0x100c90, fb->func->trap); } -void -nv50_fb_dtor(struct nvkm_object *object) +static void * +nv50_fb_dtor(struct nvkm_fb *base) { - struct nvkm_device *device = nv_device(object); - struct nv50_fb *fb = (void *)object; + struct nv50_fb *fb = nv50_fb(base); + struct nvkm_device *device = fb->base.subdev.device; if (fb->r100c08_page) { dma_unmap_page(nv_device_base(device), fb->r100c08, PAGE_SIZE, @@ -243,43 +239,52 @@ nv50_fb_dtor(struct nvkm_object *object) __free_page(fb->r100c08_page); } - nvkm_fb_destroy(&fb->base); + return fb; } +static const struct nvkm_fb_func +nv50_fb_ = { + .dtor = nv50_fb_dtor, + .init = nv50_fb_init, + .intr = nv50_fb_intr, + .ram_new = nv50_fb_ram_new, + .memtype_valid = nv50_fb_memtype_valid, +}; + int -nv50_fb_init(struct nvkm_object *object) +nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device, + int index, struct nvkm_fb **pfb) { - struct nv50_fb_impl *impl = (void *)object->oclass; - struct nv50_fb *fb = (void *)object; - struct nvkm_device *device = fb->base.subdev.device; - int ret; + struct nv50_fb *fb; - ret = nvkm_fb_init(&fb->base); - if (ret) - return ret; + if (!(fb = kzalloc(sizeof(*fb), GFP_KERNEL))) + return -ENOMEM; + nvkm_fb_ctor(&nv50_fb_, device, index, &fb->base); + fb->func = func; + *pfb = &fb->base; - /* Not a clue what this is exactly. Without pointing it at a - * scratch page, VRAM->GART blits with M2MF (as in DDX DFS) - * cause IOMMU "read from address 0" errors (rh#561267) - */ - nvkm_wr32(device, 0x100c08, fb->r100c08 >> 8); + fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (fb->r100c08_page) { + fb->r100c08 = dma_map_page(nv_device_base(device), + fb->r100c08_page, 0, PAGE_SIZE, + DMA_BIDIRECTIONAL); + if (dma_mapping_error(nv_device_base(device), fb->r100c08)) + return -EFAULT; + } else { + nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n"); + } - /* This is needed to get meaningful information from 100c90 - * on traps. No idea what these values mean exactly. */ - nvkm_wr32(device, 0x100c90, impl->trap); return 0; } -struct nvkm_oclass * -nv50_fb_oclass = &(struct nv50_fb_impl) { - .base.base.handle = NV_SUBDEV(FB, 0x50), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fb_ctor, - .dtor = nv50_fb_dtor, - .init = nv50_fb_init, - .fini = _nvkm_fb_fini, - }, - .base.memtype = nv50_fb_memtype_valid, - .base.ram_new = nv50_ram_new, +static const struct nv50_fb_func +nv50_fb = { + .ram_new = nv50_ram_new, .trap = 0x000707ff, -}.base.base; +}; + +int +nv50_fb_new(struct nvkm_device *device, int index, struct nvkm_fb **pfb) +{ + return nv50_fb_new_(&nv50_fb, device, index, pfb); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h index 92bfc3b9bb6dc..faa88c8c66fe6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h @@ -1,23 +1,21 @@ #ifndef __NVKM_FB_NV50_H__ #define __NVKM_FB_NV50_H__ +#define nv50_fb(p) container_of((p), struct nv50_fb, base) #include "priv.h" struct nv50_fb { + const struct nv50_fb_func *func; struct nvkm_fb base; struct page *r100c08_page; dma_addr_t r100c08; }; -int nv50_fb_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_fb_dtor(struct nvkm_object *); -int nv50_fb_init(struct nvkm_object *); - -struct nv50_fb_impl { - struct nvkm_fb_impl base; +struct nv50_fb_func { + int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **); u32 trap; }; +int nv50_fb_new_(const struct nv50_fb_func *, struct nvkm_device *, int index, + struct nvkm_fb **pfb); extern int nv50_fb_memtype[0x80]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h index f206152a3e635..62b9feb531dc1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h @@ -1,37 +1,62 @@ #ifndef __NVKM_FB_PRIV_H__ #define __NVKM_FB_PRIV_H__ +#define nvkm_fb(p) container_of((p), struct nvkm_fb, subdev) #include struct nvkm_bios; -#define nvkm_fb_create(p,e,c,d) \ - nvkm_fb_create_((p), (e), (c), sizeof(**d), (void **)d) -#define nvkm_fb_destroy(p) ({ \ - struct nvkm_fb *_fb = (p); \ - _nvkm_fb_dtor(nv_object(_fb)); \ -}) -#define nvkm_fb_init(p) ({ \ - struct nvkm_fb *_fb = (p); \ - _nvkm_fb_init(nv_object(_fb)); \ -}) -#define nvkm_fb_fini(p,s) ({ \ - struct nvkm_fb *_fb = (p); \ - _nvkm_fb_fini(nv_object(_fb), (s)); \ -}) - -int nvkm_fb_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_fb_dtor(struct nvkm_object *); -int _nvkm_fb_init(struct nvkm_object *); -int _nvkm_fb_fini(struct nvkm_object *, bool); - -struct nvkm_fb_impl { - struct nvkm_oclass base; +struct nvkm_fb_func { + void *(*dtor)(struct nvkm_fb *); + void (*init)(struct nvkm_fb *); + void (*intr)(struct nvkm_fb *); + + struct { + int regions; + void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); + void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags, + struct nvkm_fb_tile *); + void (*fini)(struct nvkm_fb *, int i, struct nvkm_fb_tile *); + void (*prog)(struct nvkm_fb *, int i, struct nvkm_fb_tile *); + } tile; + int (*ram_new)(struct nvkm_fb *, struct nvkm_ram **); - bool (*memtype)(struct nvkm_fb *, u32); + + bool (*memtype_valid)(struct nvkm_fb *, u32 memtype); }; +void nvkm_fb_ctor(const struct nvkm_fb_func *, struct nvkm_device *device, + int index, struct nvkm_fb *); +int nvkm_fb_new_(const struct nvkm_fb_func *, struct nvkm_device *device, + int index, struct nvkm_fb **); +int nvkm_fb_bios_memtype(struct nvkm_bios *); + bool nv04_fb_memtype_valid(struct nvkm_fb *, u32 memtype); -bool nv50_fb_memtype_valid(struct nvkm_fb *, u32 memtype); -int nvkm_fb_bios_memtype(struct nvkm_bios *); +void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); +void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); +void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); + +void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); +void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *); +void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); + +void nv30_fb_init(struct nvkm_fb *); +void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); + +void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags, + struct nvkm_fb_tile *); + +void nv41_fb_init(struct nvkm_fb *); +void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); + +void nv44_fb_init(struct nvkm_fb *); +void nv44_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *); + +void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size, + u32 pitch, u32 flags, struct nvkm_fb_tile *); + +bool gf100_fb_memtype_valid(struct nvkm_fb *, u32); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h index 60d8ed4b78b2d..9ef9d6aa3721e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h @@ -57,10 +57,7 @@ ramfuc_reg(u32 addr) static inline int ramfuc_init(struct ramfuc *ram, struct nvkm_fb *fb) { - struct nvkm_pmu *pmu = nvkm_pmu(fb); - int ret; - - ret = nvkm_memx_init(pmu, &ram->memx); + int ret = nvkm_memx_init(fb->subdev.device->pmu, &ram->memx); if (ret) return ret; @@ -148,9 +145,7 @@ ramfuc_train(struct ramfuc *ram) static inline int ramfuc_train_result(struct nvkm_fb *fb, u32 *result, u32 rsize) { - struct nvkm_pmu *pmu = nvkm_pmu(fb); - - return nvkm_memx_train_result(pmu, result, rsize); + return nvkm_memx_train_result(fb->subdev.device->pmu, result, rsize); } static inline void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index 0f07309da71dd..b4306824f7a45 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -1457,7 +1457,7 @@ gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) struct dcb_gpio_func func; struct gk104_ram *ram; int ret, i; - u8 ramcfg = nvbios_ramcfg_index(nv_subdev(fb)); + u8 ramcfg = nvbios_ramcfg_index(subdev); u32 tmp; if (!(ram = kzalloc(sizeof(*ram), GFP_KERNEL))) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index c08ac609cbe75..f1f62a217e917 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -77,14 +77,15 @@ static void nv50_vm_map(struct nvkm_vma *vma, struct nvkm_memory *pgt, struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta) { + struct nvkm_ram *ram = vma->vm->mmu->subdev.device->fb->ram; u32 comp = (mem->memtype & 0x180) >> 7; u32 block, target; int i; /* IGPs don't have real VRAM, re-target to stolen system memory */ target = 0; - if (nvkm_fb(vma->vm->mmu)->ram->stolen) { - phys += nvkm_fb(vma->vm->mmu)->ram->stolen; + if (ram->stolen) { + phys += ram->stolen; target = 3; } -- GitLab From c5fcafa528463b207108cd606e0d41741fb7dc50 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5535/7006] drm/nouveau/fuse: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/fuse.h | 29 ++------ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 70 +++++++++---------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 --- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 --- .../drm/nouveau/nvkm/engine/device/gm100.c | 4 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 ---- .../gpu/drm/nouveau/nvkm/subdev/fuse/base.c | 34 +++++---- .../gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c | 56 ++++----------- .../gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c | 30 ++------ .../gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c | 52 +++----------- .../gpu/drm/nouveau/nvkm/subdev/fuse/priv.h | 9 ++- .../gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 6 +- 12 files changed, 100 insertions(+), 221 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h index 570a35356ff58..ae201e3884871 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h @@ -1,33 +1,16 @@ #ifndef __NVKM_FUSE_H__ #define __NVKM_FUSE_H__ #include -#include struct nvkm_fuse { - struct nvkm_subdev subdev; const struct nvkm_fuse_func *func; + struct nvkm_subdev subdev; + spinlock_t lock; }; -struct nvkm_fuse_func { - u32 (*read)(struct nvkm_fuse *, u32 addr); -}; - -static inline struct nvkm_fuse * -nvkm_fuse(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_FUSE); -} - -#define nvkm_fuse_create(p, e, o, d) \ - nvkm_fuse_create_((p), (e), (o), sizeof(**d), (void **)d) - -int nvkm_fuse_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_fuse_dtor(struct nvkm_object *); -int _nvkm_fuse_init(struct nvkm_object *); -#define _nvkm_fuse_fini _nvkm_subdev_fini +u32 nvkm_fuse_read(struct nvkm_fuse *, u32 addr); -extern struct nvkm_oclass nv50_fuse_oclass; -extern struct nvkm_oclass gf100_fuse_oclass; -extern struct nvkm_oclass gm107_fuse_oclass; +int nv50_fuse_new(struct nvkm_device *, int, struct nvkm_fuse **); +int gf100_fuse_new(struct nvkm_device *, int, struct nvkm_fuse **); +int gm107_fuse_new(struct nvkm_device *, int, struct nvkm_fuse **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b34c22ff88037..c3afd03df5a98 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -784,7 +784,7 @@ nv50_chipset = { .clk = nv50_clk_new, .devinit = nv50_devinit_new, .fb = nv50_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, @@ -887,7 +887,7 @@ nv84_chipset = { .clk = g84_clk_new, .devinit = g84_devinit_new, .fb = g84_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, @@ -918,7 +918,7 @@ nv86_chipset = { .clk = g84_clk_new, .devinit = g84_devinit_new, .fb = g84_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, @@ -949,7 +949,7 @@ nv92_chipset = { .clk = g84_clk_new, .devinit = g84_devinit_new, .fb = g84_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, @@ -980,7 +980,7 @@ nv94_chipset = { .clk = g84_clk_new, .devinit = g84_devinit_new, .fb = g84_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1008,7 +1008,7 @@ nv96_chipset = { .bios = nvkm_bios_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, .clk = g84_clk_new, // .therm = g84_therm_new, // .mxm = nv50_mxm_new, @@ -1039,7 +1039,7 @@ nv98_chipset = { .bios = nvkm_bios_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, .clk = g84_clk_new, // .therm = g84_therm_new, // .mxm = nv50_mxm_new, @@ -1073,7 +1073,7 @@ nva0_chipset = { .clk = g84_clk_new, .devinit = g84_devinit_new, .fb = g84_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, @@ -1104,7 +1104,7 @@ nva3_chipset = { .clk = gt215_clk_new, .devinit = gt215_devinit_new, .fb = gt215_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1137,7 +1137,7 @@ nva5_chipset = { .clk = gt215_clk_new, .devinit = gt215_devinit_new, .fb = gt215_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1169,7 +1169,7 @@ nva8_chipset = { .clk = gt215_clk_new, .devinit = gt215_devinit_new, .fb = gt215_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1201,7 +1201,7 @@ nvaa_chipset = { .clk = mcp77_clk_new, .devinit = g98_devinit_new, .fb = mcp77_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1232,7 +1232,7 @@ nvac_chipset = { .clk = mcp77_clk_new, .devinit = g98_devinit_new, .fb = mcp77_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1263,7 +1263,7 @@ nvaf_chipset = { .clk = gt215_clk_new, .devinit = mcp89_devinit_new, .fb = mcp89_fb_new, -// .fuse = nv50_fuse_new, + .fuse = nv50_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, @@ -1295,7 +1295,7 @@ nvc0_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1330,7 +1330,7 @@ nvc1_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1364,7 +1364,7 @@ nvc3_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1398,7 +1398,7 @@ nvc4_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1433,7 +1433,7 @@ nvc8_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1468,7 +1468,7 @@ nvce_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1503,7 +1503,7 @@ nvcf_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, @@ -1537,7 +1537,7 @@ nvd7_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gf110_gpio_new, // .i2c = gf117_i2c_new, // .ibus = gf100_ibus_new, @@ -1569,7 +1569,7 @@ nvd9_chipset = { .clk = gf100_clk_new, .devinit = gf100_devinit_new, .fb = gf100_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gf110_gpio_new, // .i2c = gf110_i2c_new, // .ibus = gf100_ibus_new, @@ -1603,7 +1603,7 @@ nve4_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, @@ -1639,7 +1639,7 @@ nve6_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, @@ -1675,7 +1675,7 @@ nve7_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, @@ -1709,7 +1709,7 @@ nvea_chipset = { .bus = gf100_bus_new, .clk = gk20a_clk_new, .fb = gk20a_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .ibus = gk20a_ibus_new, // .imem = gk20a_instmem_new, // .ltc = gk104_ltc_new, @@ -1735,7 +1735,7 @@ nvf0_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, @@ -1771,7 +1771,7 @@ nvf1_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gf110_i2c_new, // .ibus = gk104_ibus_new, @@ -1807,7 +1807,7 @@ nv106_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, @@ -1842,7 +1842,7 @@ nv108_chipset = { .clk = gk104_clk_new, .devinit = gf100_devinit_new, .fb = gk104_fb_new, -// .fuse = gf100_fuse_new, + .fuse = gf100_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, @@ -1877,7 +1877,7 @@ nv117_chipset = { .clk = gk104_clk_new, .devinit = gm107_devinit_new, .fb = gm107_fb_new, -// .fuse = gm107_fuse_new, + .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gf110_i2c_new, // .ibus = gk104_ibus_new, @@ -1906,7 +1906,7 @@ nv124_chipset = { .bus = gf100_bus_new, .devinit = gm204_devinit_new, .fb = gm107_fb_new, -// .fuse = gm107_fuse_new, + .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gm204_i2c_new, // .ibus = gk104_ibus_new, @@ -1935,7 +1935,7 @@ nv126_chipset = { .bus = gf100_bus_new, .devinit = gm204_devinit_new, .fb = gm107_fb_new, -// .fuse = gm107_fuse_new, + .fuse = gm107_fuse_new, // .gpio = gk104_gpio_new, // .i2c = gm204_i2c_new, // .ibus = gk104_ibus_new, @@ -1962,7 +1962,7 @@ nv12b_chipset = { .bar = gk20a_bar_new, .bus = gf100_bus_new, .fb = gk20a_fb_new, -// .fuse = gm107_fuse_new, + .fuse = gm107_fuse_new, // .ibus = gk20a_ibus_new, // .imem = gk20a_instmem_new, // .ltc = gm107_ltc_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index dbc9f52f9e594..df9e3fbca3df0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -30,7 +30,6 @@ gf100_identify(struct nvkm_device *device) case 0xc0: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -56,7 +55,6 @@ gf100_identify(struct nvkm_device *device) case 0xc4: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -82,7 +80,6 @@ gf100_identify(struct nvkm_device *device) case 0xc3: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -107,7 +104,6 @@ gf100_identify(struct nvkm_device *device) case 0xce: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -133,7 +129,6 @@ gf100_identify(struct nvkm_device *device) case 0xcf: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -158,7 +153,6 @@ gf100_identify(struct nvkm_device *device) case 0xc1: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -183,7 +177,6 @@ gf100_identify(struct nvkm_device *device) case 0xc8: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -209,7 +202,6 @@ gf100_identify(struct nvkm_device *device) case 0xd9: device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -234,7 +226,6 @@ gf100_identify(struct nvkm_device *device) case 0xd7: device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index af4368784ac94..623810dd095b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -30,7 +30,6 @@ gk104_identify(struct nvkm_device *device) case 0xe4: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -57,7 +56,6 @@ gk104_identify(struct nvkm_device *device) case 0xe7: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -84,7 +82,6 @@ gk104_identify(struct nvkm_device *device) case 0xe6: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -110,7 +107,6 @@ gk104_identify(struct nvkm_device *device) break; case 0xea: device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; @@ -128,7 +124,6 @@ gk104_identify(struct nvkm_device *device) case 0xf0: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -155,7 +150,6 @@ gk104_identify(struct nvkm_device *device) case 0xf1: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -182,7 +176,6 @@ gk104_identify(struct nvkm_device *device) case 0x106: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; @@ -208,7 +201,6 @@ gk104_identify(struct nvkm_device *device) case 0x108: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 6723b9eba1007..038045a7ac8ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -30,7 +30,6 @@ gm100_identify(struct nvkm_device *device) case 0x117: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; @@ -63,7 +62,6 @@ gm100_identify(struct nvkm_device *device) case 0x124: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; #if 0 /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ @@ -97,7 +95,6 @@ gm100_identify(struct nvkm_device *device) case 0x126: device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; #if 0 /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ @@ -132,7 +129,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 3b22a2e3459ee..095f3c3f8c3f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -30,7 +30,6 @@ nv50_identify(struct nvkm_device *device) case 0x50: device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -49,7 +48,6 @@ nv50_identify(struct nvkm_device *device) case 0x84: device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -71,7 +69,6 @@ nv50_identify(struct nvkm_device *device) case 0x86: device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -93,7 +90,6 @@ nv50_identify(struct nvkm_device *device) case 0x92: device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -115,7 +111,6 @@ nv50_identify(struct nvkm_device *device) case 0x94: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; @@ -137,7 +132,6 @@ nv50_identify(struct nvkm_device *device) case 0x96: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; @@ -159,7 +153,6 @@ nv50_identify(struct nvkm_device *device) case 0x98: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -181,7 +174,6 @@ nv50_identify(struct nvkm_device *device) case 0xa0: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -203,7 +195,6 @@ nv50_identify(struct nvkm_device *device) case 0xaa: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -225,7 +216,6 @@ nv50_identify(struct nvkm_device *device) case 0xac: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -247,7 +237,6 @@ nv50_identify(struct nvkm_device *device) case 0xa3: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -271,7 +260,6 @@ nv50_identify(struct nvkm_device *device) case 0xa5: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -294,7 +282,6 @@ nv50_identify(struct nvkm_device *device) case 0xa8: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -317,7 +304,6 @@ nv50_identify(struct nvkm_device *device) case 0xaf: device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; - device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c index 8889925da3d7b..f4144979a79c0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c @@ -21,26 +21,34 @@ * * Authors: Martin Peres */ -#include +#include "priv.h" -int -_nvkm_fuse_init(struct nvkm_object *object) +u32 +nvkm_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct nvkm_fuse *fuse = (void *)object; - return nvkm_subdev_init_old(&fuse->subdev); + return fuse->func->read(fuse, addr); } -void -_nvkm_fuse_dtor(struct nvkm_object *object) +static void * +nvkm_fuse_dtor(struct nvkm_subdev *subdev) { - struct nvkm_fuse *fuse = (void *)object; - nvkm_subdev_destroy(&fuse->subdev); + return nvkm_fuse(subdev); } +static const struct nvkm_subdev_func +nvkm_fuse = { + .dtor = nvkm_fuse_dtor, +}; + int -nvkm_fuse_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_fuse_new_(const struct nvkm_fuse_func *func, struct nvkm_device *device, + int index, struct nvkm_fuse **pfuse) { - return nvkm_subdev_create_(parent, engine, oclass, 0, "FUSE", - "fuse", length, pobject); + struct nvkm_fuse *fuse; + if (!(fuse = *pfuse = kzalloc(sizeof(*fuse), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_fuse, device, index, 0, &fuse->subdev); + fuse->func = func; + spin_lock_init(&fuse->lock); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c index 4e94cb94430c6..13671fedc8059 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c @@ -23,61 +23,31 @@ */ #include "priv.h" -struct gf100_fuse { - struct nvkm_fuse base; - - spinlock_t fuse_enable_lock; -}; - static u32 -gf100_fuse_read(struct nvkm_fuse *obj, u32 addr) +gf100_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct gf100_fuse *fuse = container_of(obj, typeof(*fuse), base); - struct nvkm_device *device = fuse->base.subdev.device; + struct nvkm_device *device = fuse->subdev.device; unsigned long flags; u32 fuse_enable, unk, val; /* racy if another part of nvkm start writing to these regs */ - spin_lock_irqsave(&fuse->fuse_enable_lock, flags); - fuse_enable = nvkm_mask(device, 0x22400, 0x800, 0x800); - unk = nvkm_mask(device, 0x21000, 0x1, 0x1); - val = nvkm_rd32(device, 0x21100 + addr); - nvkm_wr32(device, 0x21000, unk); - nvkm_wr32(device, 0x22400, fuse_enable); - spin_unlock_irqrestore(&fuse->fuse_enable_lock, flags); + spin_lock_irqsave(&fuse->lock, flags); + fuse_enable = nvkm_mask(device, 0x022400, 0x800, 0x800); + unk = nvkm_mask(device, 0x021000, 0x1, 0x1); + val = nvkm_rd32(device, 0x021100 + addr); + nvkm_wr32(device, 0x021000, unk); + nvkm_wr32(device, 0x022400, fuse_enable); + spin_unlock_irqrestore(&fuse->lock, flags); return val; } static const struct nvkm_fuse_func -gf100_fuse_func = { +gf100_fuse = { .read = gf100_fuse_read, }; -static int -gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_fuse_new(struct nvkm_device *device, int index, struct nvkm_fuse **pfuse) { - struct gf100_fuse *fuse; - int ret; - - ret = nvkm_fuse_create(parent, engine, oclass, &fuse); - *pobject = nv_object(fuse); - if (ret) - return ret; - - spin_lock_init(&fuse->fuse_enable_lock); - fuse->base.func = &gf100_fuse_func; - return 0; + return nvkm_fuse_new_(&gf100_fuse, device, index, pfuse); } - -struct nvkm_oclass -gf100_fuse_oclass = { - .handle = NV_SUBDEV(FUSE, 0xC0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fuse_ctor, - .dtor = _nvkm_fuse_dtor, - .init = _nvkm_fuse_init, - .fini = _nvkm_fuse_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c index bb1101e121488..9aff4ea045060 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c @@ -27,36 +27,16 @@ static u32 gm107_fuse_read(struct nvkm_fuse *fuse, u32 addr) { struct nvkm_device *device = fuse->subdev.device; - return nvkm_rd32(device, 0x21100 + addr); + return nvkm_rd32(device, 0x021100 + addr); } static const struct nvkm_fuse_func -gm107_fuse_func = { +gm107_fuse = { .read = gm107_fuse_read, }; -static int -gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm107_fuse_new(struct nvkm_device *device, int index, struct nvkm_fuse **pfuse) { - struct nvkm_fuse *fuse; - int ret; - - ret = nvkm_fuse_create(parent, engine, oclass, &fuse); - *pobject = nv_object(fuse); - - fuse->func = &gm107_fuse_func; - return ret; + return nvkm_fuse_new_(&gm107_fuse, device, index, pfuse); } - -struct nvkm_oclass -gm107_fuse_oclass = { - .handle = NV_SUBDEV(FUSE, 0x117), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_fuse_ctor, - .dtor = _nvkm_fuse_dtor, - .init = _nvkm_fuse_init, - .fini = _nvkm_fuse_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c index ee76268ae7026..514c193db25db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c @@ -23,59 +23,29 @@ */ #include "priv.h" -struct nv50_fuse { - struct nvkm_fuse base; - - spinlock_t fuse_enable_lock; -}; - static u32 -nv50_fuse_read(struct nvkm_fuse *obj, u32 addr) +nv50_fuse_read(struct nvkm_fuse *fuse, u32 addr) { - struct nv50_fuse *fuse = container_of(obj, typeof(*fuse), base); - struct nvkm_device *device = fuse->base.subdev.device; + struct nvkm_device *device = fuse->subdev.device; unsigned long flags; u32 fuse_enable, val; /* racy if another part of nvkm start writing to this reg */ - spin_lock_irqsave(&fuse->fuse_enable_lock, flags); - fuse_enable = nvkm_mask(device, 0x1084, 0x800, 0x800); - val = nvkm_rd32(device, 0x21000 + addr); - nvkm_wr32(device, 0x1084, fuse_enable); - spin_unlock_irqrestore(&fuse->fuse_enable_lock, flags); + spin_lock_irqsave(&fuse->lock, flags); + fuse_enable = nvkm_mask(device, 0x001084, 0x800, 0x800); + val = nvkm_rd32(device, 0x021000 + addr); + nvkm_wr32(device, 0x001084, fuse_enable); + spin_unlock_irqrestore(&fuse->lock, flags); return val; } static const struct nvkm_fuse_func -nv50_fuse_func = { +nv50_fuse = { .read = &nv50_fuse_read, }; -static int -nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_fuse_new(struct nvkm_device *device, int index, struct nvkm_fuse **pfuse) { - struct nv50_fuse *fuse; - int ret; - - ret = nvkm_fuse_create(parent, engine, oclass, &fuse); - *pobject = nv_object(fuse); - if (ret) - return ret; - - spin_lock_init(&fuse->fuse_enable_lock); - fuse->base.func = &nv50_fuse_func; - return 0; + return nvkm_fuse_new_(&nv50_fuse, device, index, pfuse); } - -struct nvkm_oclass -nv50_fuse_oclass = { - .handle = NV_SUBDEV(FUSE, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fuse_ctor, - .dtor = _nvkm_fuse_dtor, - .init = _nvkm_fuse_init, - .fini = _nvkm_fuse_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h index 7e050f7893842..b0390b540ef56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h @@ -1,7 +1,12 @@ #ifndef __NVKM_FUSE_PRIV_H__ #define __NVKM_FUSE_PRIV_H__ +#define nvkm_fuse(p) container_of((p), struct nvkm_fuse, subdev) #include -int _nvkm_fuse_init(struct nvkm_object *object); -void _nvkm_fuse_dtor(struct nvkm_object *object); +struct nvkm_fuse_func { + u32 (*read)(struct nvkm_fuse *, u32 addr); +}; + +int nvkm_fuse_new_(const struct nvkm_fuse_func *, struct nvkm_device *, + int index, struct nvkm_fuse **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index aea79d7201bda..c70b79f8786c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -30,9 +30,8 @@ int g84_temp_get(struct nvkm_therm *therm) { struct nvkm_device *device = therm->subdev.device; - struct nvkm_fuse *fuse = nvkm_fuse(therm); - if (fuse->func->read(fuse, 0x1a8) == 1) + if (nvkm_fuse_read(device->fuse, 0x1a8) == 1) return nvkm_rd32(device, 0x20400); else return -ENODEV; @@ -42,10 +41,9 @@ void g84_sensor_setup(struct nvkm_therm *therm) { struct nvkm_device *device = therm->subdev.device; - struct nvkm_fuse *fuse = nvkm_fuse(therm); /* enable temperature reading for cards with insane defaults */ - if (fuse->func->read(fuse, 0x1a8) == 1) { + if (nvkm_fuse_read(device->fuse, 0x1a8) == 1) { nvkm_mask(device, 0x20008, 0x80008000, 0x80000000); nvkm_mask(device, 0x2000c, 0x80000003, 0x00000000); mdelay(20); /* wait for the temperature to stabilize */ -- GitLab From 2ea7249fe2d4815fc6d0b50021bcbd8bb72b8437 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5536/7006] drm/nouveau/gpio: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/dac.c | 12 +- drivers/gpu/drm/nouveau/dispnv04/tvnv17.c | 16 +- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../drm/nouveau/include/nvkm/subdev/gpio.h | 29 ++-- drivers/gpu/drm/nouveau/nouveau_connector.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 130 ++++++++-------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 7 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/disp/conn.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/bios/init.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c | 8 +- .../gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild | 2 +- .../gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 139 +++++++----------- .../gpu/drm/nouveau/nvkm/subdev/gpio/g94.c | 19 ++- .../nvkm/subdev/gpio/{gf110.c => gf119.c} | 33 ++--- .../gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c | 25 ++-- .../gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c | 21 ++- .../gpu/drm/nouveau/nvkm/subdev/gpio/priv.h | 37 +---- .../gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 16 +- .../drm/nouveau/nvkm/subdev/therm/fanpwm.c | 7 +- .../drm/nouveau/nvkm/subdev/therm/fantog.c | 9 +- .../gpu/drm/nouveau/nvkm/subdev/volt/gpio.c | 10 +- 30 files changed, 252 insertions(+), 370 deletions(-) rename drivers/gpu/drm/nouveau/nvkm/subdev/gpio/{gf110.c => gf119.c} (80%) diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c index 71e99cdfc40eb..78cb033bc015a 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dac.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c @@ -270,10 +270,10 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) } if (gpio) { - saved_gpio1 = gpio->get(gpio, 0, DCB_GPIO_TVDAC1, 0xff); - saved_gpio0 = gpio->get(gpio, 0, DCB_GPIO_TVDAC0, 0xff); - gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, dcb->type == DCB_OUTPUT_TV); - gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, dcb->type == DCB_OUTPUT_TV); + saved_gpio1 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC1, 0xff); + saved_gpio0 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC0, 0xff); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, dcb->type == DCB_OUTPUT_TV); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, dcb->type == DCB_OUTPUT_TV); } msleep(4); @@ -325,8 +325,8 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder) nvif_wr32(device, NV_PBUS_POWERCTRL_2, saved_powerctrl_2); if (gpio) { - gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, saved_gpio1); - gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, saved_gpio0); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, saved_gpio1); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, saved_gpio0); } return sample; diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index 792bf5428f354..c59b2c7d94e14 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -62,8 +62,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) head = (dacclk & 0x100) >> 8; /* Save the previous state. */ - gpio1 = gpio->get(gpio, 0, DCB_GPIO_TVDAC1, 0xff); - gpio0 = gpio->get(gpio, 0, DCB_GPIO_TVDAC0, 0xff); + gpio1 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC1, 0xff); + gpio0 = nvkm_gpio_get(gpio, 0, DCB_GPIO_TVDAC0, 0xff); fp_htotal = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL); fp_hsync_start = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START); fp_hsync_end = NVReadRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END); @@ -74,8 +74,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) ctv_6c = NVReadRAMDAC(dev, head, 0x680c6c); /* Prepare the DAC for load detection. */ - gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, true); - gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, true); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, true); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, true); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, 1343); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, 1047); @@ -120,8 +120,8 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder) NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_END, fp_hsync_end); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HSYNC_START, fp_hsync_start); NVWriteRAMDAC(dev, head, NV_PRAMDAC_FP_HTOTAL, fp_htotal); - gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, gpio1); - gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, gpio0); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, gpio1); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, gpio0); return sample; } @@ -395,8 +395,8 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode) nv_load_ptv(dev, regs, 200); - gpio->set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, mode == DRM_MODE_DPMS_ON); - gpio->set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, mode == DRM_MODE_DPMS_ON); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC1, 0xff, mode == DRM_MODE_DPMS_ON); + nvkm_gpio_set(gpio, 0, DCB_GPIO_TVDAC0, 0xff, mode == DRM_MODE_DPMS_ON); nv04_dac_update_dacclk(encoder, mode == DRM_MODE_DPMS_ON); } diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 2b17b13b9dbaa..6cc9c65833a60 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -54,7 +54,7 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_fb(a) nvxx_device(a)->fb #define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) #define nvxx_bar(a) nvxx_device(a)->bar -#define nvxx_gpio(a) nvkm_gpio(nvxx_device(a)) +#define nvxx_gpio(a) nvxx_device(a)->gpio #define nvxx_clk(a) nvxx_device(a)->clk #define nvxx_i2c(a) nvkm_i2c(nvxx_device(a)) #define nvxx_therm(a) nvkm_therm(nvxx_device(a)) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h index f409cbb2bce78..9b9c6d2f90b6d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h @@ -19,26 +19,21 @@ struct nvkm_gpio_ntfy_rep { }; struct nvkm_gpio { + const struct nvkm_gpio_func *func; struct nvkm_subdev subdev; struct nvkm_event event; - - void (*reset)(struct nvkm_gpio *, u8 func); - int (*find)(struct nvkm_gpio *, int idx, u8 tag, u8 line, - struct dcb_gpio_func *); - int (*set)(struct nvkm_gpio *, int idx, u8 tag, u8 line, int state); - int (*get)(struct nvkm_gpio *, int idx, u8 tag, u8 line); }; -static inline struct nvkm_gpio * -nvkm_gpio(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_GPIO); -} - -extern struct nvkm_oclass *nv10_gpio_oclass; -extern struct nvkm_oclass *nv50_gpio_oclass; -extern struct nvkm_oclass *g94_gpio_oclass; -extern struct nvkm_oclass *gf110_gpio_oclass; -extern struct nvkm_oclass *gk104_gpio_oclass; +void nvkm_gpio_reset(struct nvkm_gpio *, u8 func); +int nvkm_gpio_find(struct nvkm_gpio *, int idx, u8 tag, u8 line, + struct dcb_gpio_func *); +int nvkm_gpio_set(struct nvkm_gpio *, int idx, u8 tag, u8 line, int state); +int nvkm_gpio_get(struct nvkm_gpio *, int idx, u8 tag, u8 line); + +int nv10_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **); +int nv50_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **); +int g94_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **); +int gf119_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **); +int gk104_gpio_new(struct nvkm_device *, int, struct nvkm_gpio **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c index 309c20b086d42..2e7cbe933533c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_connector.c +++ b/drivers/gpu/drm/nouveau/nouveau_connector.c @@ -125,9 +125,9 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) * is handled by the SOR itself, and not required for LVDS DDC. */ if (nv_connector->type == DCB_CONNECTOR_eDP) { - panel = gpio->get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); + panel = nvkm_gpio_get(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff); if (panel == 0) { - gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); + nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, 1); msleep(300); } } @@ -157,7 +157,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector) * state to avoid confusing the SOR for other output types. */ if (!nv_encoder && panel == 0) - gpio->set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel); + nvkm_gpio_set(gpio, 0, DCB_GPIO_PANEL_POWER, 0xff, panel); return nv_encoder; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index c3afd03df5a98..3caaa9caf4d3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -121,7 +121,7 @@ nv10_chipset = { .clk = nv04_clk_new, .devinit = nv10_devinit_new, .fb = nv10_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -140,7 +140,7 @@ nv11_chipset = { .clk = nv04_clk_new, .devinit = nv10_devinit_new, .fb = nv10_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -161,7 +161,7 @@ nv15_chipset = { .clk = nv04_clk_new, .devinit = nv10_devinit_new, .fb = nv10_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -182,7 +182,7 @@ nv17_chipset = { .clk = nv04_clk_new, .devinit = nv10_devinit_new, .fb = nv10_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -203,7 +203,7 @@ nv18_chipset = { .clk = nv04_clk_new, .devinit = nv10_devinit_new, .fb = nv10_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -224,7 +224,7 @@ nv1a_chipset = { .clk = nv04_clk_new, .devinit = nv1a_devinit_new, .fb = nv1a_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -245,7 +245,7 @@ nv1f_chipset = { .clk = nv04_clk_new, .devinit = nv1a_devinit_new, .fb = nv1a_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -266,7 +266,7 @@ nv20_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv20_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -287,7 +287,7 @@ nv25_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv25_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -308,7 +308,7 @@ nv28_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv25_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -329,7 +329,7 @@ nv2a_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv25_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -350,7 +350,7 @@ nv30_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv30_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -371,7 +371,7 @@ nv31_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv30_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -393,7 +393,7 @@ nv34_chipset = { .clk = nv04_clk_new, .devinit = nv10_devinit_new, .fb = nv10_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -415,7 +415,7 @@ nv35_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv35_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -436,7 +436,7 @@ nv36_chipset = { .clk = nv04_clk_new, .devinit = nv20_devinit_new, .fb = nv36_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, @@ -458,7 +458,7 @@ nv40_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv40_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -483,7 +483,7 @@ nv41_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv41_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -508,7 +508,7 @@ nv42_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv41_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -533,7 +533,7 @@ nv43_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv41_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -558,7 +558,7 @@ nv44_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv44_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv44_mc_new, @@ -583,7 +583,7 @@ nv45_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv40_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -608,7 +608,7 @@ nv46_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv46_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv44_mc_new, @@ -633,7 +633,7 @@ nv47_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv47_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -658,7 +658,7 @@ nv49_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv49_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -683,7 +683,7 @@ nv4a_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv44_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv44_mc_new, @@ -708,7 +708,7 @@ nv4b_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv49_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, @@ -733,7 +733,7 @@ nv4c_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv46_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, @@ -758,7 +758,7 @@ nv4e_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv4e_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv4e_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, @@ -785,7 +785,7 @@ nv50_chipset = { .devinit = nv50_devinit_new, .fb = nv50_fb_new, .fuse = nv50_fuse_new, -// .gpio = nv50_gpio_new, + .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, @@ -811,7 +811,7 @@ nv63_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv46_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, @@ -836,7 +836,7 @@ nv67_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv46_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, @@ -861,7 +861,7 @@ nv68_chipset = { .clk = nv40_clk_new, .devinit = nv1a_devinit_new, .fb = nv46_fb_new, -// .gpio = nv10_gpio_new, + .gpio = nv10_gpio_new, // .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, @@ -888,7 +888,7 @@ nv84_chipset = { .devinit = g84_devinit_new, .fb = g84_fb_new, .fuse = nv50_fuse_new, -// .gpio = nv50_gpio_new, + .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, @@ -919,7 +919,7 @@ nv86_chipset = { .devinit = g84_devinit_new, .fb = g84_fb_new, .fuse = nv50_fuse_new, -// .gpio = nv50_gpio_new, + .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, @@ -950,7 +950,7 @@ nv92_chipset = { .devinit = g84_devinit_new, .fb = g84_fb_new, .fuse = nv50_fuse_new, -// .gpio = nv50_gpio_new, + .gpio = nv50_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, @@ -981,7 +981,7 @@ nv94_chipset = { .devinit = g84_devinit_new, .fb = g84_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g94_mc_new, @@ -1006,7 +1006,7 @@ static const struct nvkm_device_chip nv96_chipset = { .name = "G96", .bios = nvkm_bios_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, .fuse = nv50_fuse_new, .clk = g84_clk_new, @@ -1037,7 +1037,7 @@ static const struct nvkm_device_chip nv98_chipset = { .name = "G98", .bios = nvkm_bios_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, .fuse = nv50_fuse_new, .clk = g84_clk_new, @@ -1074,7 +1074,7 @@ nva0_chipset = { .devinit = g84_devinit_new, .fb = g84_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1105,7 +1105,7 @@ nva3_chipset = { .devinit = gt215_devinit_new, .fb = gt215_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1138,7 +1138,7 @@ nva5_chipset = { .devinit = gt215_devinit_new, .fb = gt215_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1170,7 +1170,7 @@ nva8_chipset = { .devinit = gt215_devinit_new, .fb = gt215_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1202,7 +1202,7 @@ nvaa_chipset = { .devinit = g98_devinit_new, .fb = mcp77_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1233,7 +1233,7 @@ nvac_chipset = { .devinit = g98_devinit_new, .fb = mcp77_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1264,7 +1264,7 @@ nvaf_chipset = { .devinit = mcp89_devinit_new, .fb = mcp89_fb_new, .fuse = nv50_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, @@ -1296,7 +1296,7 @@ nvc0_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1331,7 +1331,7 @@ nvc1_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1365,7 +1365,7 @@ nvc3_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1399,7 +1399,7 @@ nvc4_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1434,7 +1434,7 @@ nvc8_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1469,7 +1469,7 @@ nvce_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1504,7 +1504,7 @@ nvcf_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = g94_gpio_new, + .gpio = g94_gpio_new, // .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1538,7 +1538,7 @@ nvd7_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = gf110_gpio_new, + .gpio = gf119_gpio_new, // .i2c = gf117_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1570,7 +1570,7 @@ nvd9_chipset = { .devinit = gf100_devinit_new, .fb = gf100_fb_new, .fuse = gf100_fuse_new, -// .gpio = gf110_gpio_new, + .gpio = gf119_gpio_new, // .i2c = gf110_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, @@ -1604,7 +1604,7 @@ nve4_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1640,7 +1640,7 @@ nve6_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1676,7 +1676,7 @@ nve7_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1736,7 +1736,7 @@ nvf0_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1772,7 +1772,7 @@ nvf1_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gf110_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1808,7 +1808,7 @@ nv106_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1843,7 +1843,7 @@ nv108_chipset = { .devinit = gf100_devinit_new, .fb = gk104_fb_new, .fuse = gf100_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1878,7 +1878,7 @@ nv117_chipset = { .devinit = gm107_devinit_new, .fb = gm107_fb_new, .fuse = gm107_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gf110_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1907,7 +1907,7 @@ nv124_chipset = { .devinit = gm204_devinit_new, .fb = gm107_fb_new, .fuse = gm107_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gm204_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, @@ -1936,7 +1936,7 @@ nv126_chipset = { .devinit = gm204_devinit_new, .fb = gm107_fb_new, .fuse = gm107_fuse_new, -// .gpio = gk104_gpio_new, + .gpio = gk104_gpio_new, // .i2c = gm204_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index df9e3fbca3df0..9059b43efe7d8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -53,7 +52,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -78,7 +76,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -102,7 +99,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -127,7 +123,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -151,7 +146,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -175,7 +169,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -200,7 +193,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -224,7 +216,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 623810dd095b2..89eabad81e83d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -54,7 +53,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -80,7 +78,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -122,7 +119,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; break; case 0xf0: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -148,7 +144,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -174,7 +169,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -199,7 +193,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 038045a7ac8ec..a57db5f56f680 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -28,7 +28,6 @@ gm100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x117: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -60,7 +59,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x124: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; #if 0 /* looks to be some non-trivial changes */ @@ -93,7 +91,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x126: - device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; #if 0 /* looks to be some non-trivial changes */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index dd42f9e64f76a..ac2994a3fb33c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,7 +28,6 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -39,7 +38,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -52,7 +50,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -65,7 +62,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -78,7 +74,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -91,7 +86,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -104,7 +98,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -117,7 +110,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 3e79a02ac687c..80290303606e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,7 +28,6 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -41,7 +40,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -54,7 +52,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -67,7 +64,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index b045515a49037..ce66504d1f3ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,7 +28,6 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -41,7 +40,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -54,7 +52,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -68,7 +65,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -82,7 +78,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 430707755ffa1..513fb7eea165a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -45,7 +44,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -62,7 +60,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -79,7 +76,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -96,7 +92,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -113,7 +108,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -130,7 +124,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -147,7 +140,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; @@ -164,7 +156,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; @@ -181,7 +172,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -198,7 +188,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; @@ -215,7 +204,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -232,7 +220,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -249,7 +236,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -266,7 +252,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; @@ -283,7 +268,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 095f3c3f8c3f8..cf8839c1d1f05 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -46,7 +45,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -67,7 +65,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -88,7 +85,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -109,7 +105,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -130,7 +125,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -151,7 +145,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -172,7 +165,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -193,7 +185,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -214,7 +205,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -235,7 +225,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -258,7 +247,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -280,7 +268,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; @@ -302,7 +289,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass; device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c index 2eb55be056d9b..c6910d644a3d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c @@ -41,7 +41,7 @@ nvkm_connector_hpd(struct nvkm_notify *notify) CONN_DBG(conn, "HPD: %d", line->mask); - if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) + if (!nvkm_gpio_get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index)) rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG; else rep.mask = NVIF_NOTIFY_CONN_V0_PLUG; @@ -98,7 +98,7 @@ nvkm_connector_ctor(struct nvkm_disp *disp, int index, } info->hpd = hpd[info->hpd]; - ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func); if (ret) { CONN_ERR(conn, "func %02x lookup failed, %d", info->hpd, ret); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c index a50b027cf7030..65af31441e9c2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c @@ -1933,8 +1933,8 @@ init_gpio(struct nvbios_init *init) trace("GPIO\n"); init->offset += 1; - if (init_exec(init) && gpio && gpio->reset) - gpio->reset(gpio, DCB_GPIO_UNUSED); + if (init_exec(init)) + nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED); } /** @@ -2179,8 +2179,8 @@ init_gpio_ne(struct nvbios_init *init) trace("\tFUNC[0x%02x]", func.func); if (i == (init->offset + count)) { cont(" *"); - if (init_exec(init) && gpio && gpio->reset) - gpio->reset(gpio, func.func); + if (init_exec(init)) + nvkm_gpio_reset(gpio, func.func); } cont("\n"); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c index b4306824f7a45..989355622aac8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c @@ -1522,14 +1522,14 @@ gk104_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) } /* lookup memory voltage gpios */ - ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func); if (ret == 0) { ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04)); ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12; ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12; } - ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); if (ret == 0) { ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04)); ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c index a70219cc0a4ba..5c08ae8023fa6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c @@ -468,13 +468,13 @@ gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk) static void gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val) { - struct nvkm_gpio *gpio = nvkm_gpio(fuc->base.fb); + struct nvkm_gpio *gpio = fuc->base.fb->subdev.device->gpio; struct dcb_gpio_func func; u32 reg, sh, gpio_val; int ret; - if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) { - ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); + if (nvkm_gpio_get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) { + ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); if (ret) return; @@ -982,7 +982,7 @@ gt215_ram_new(struct nvkm_fb *fb, struct nvkm_ram **pram) ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4); } - ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); + ret = nvkm_gpio_find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func); if (ret == 0) { nv50_gpio_location(func.line, ®, &shift); ram->fuc.r_gpioFBVREF = ramfuc_reg(reg); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild index ea42a9ed18214..e52c5e87f242f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild @@ -2,5 +2,5 @@ nvkm-y += nvkm/subdev/gpio/base.o nvkm-y += nvkm/subdev/gpio/nv10.o nvkm-y += nvkm/subdev/gpio/nv50.o nvkm-y += nvkm/subdev/gpio/g94.o -nvkm-y += nvkm/subdev/gpio/gf110.o +nvkm-y += nvkm/subdev/gpio/gf119.o nvkm-y += nvkm/subdev/gpio/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index faeb2041f6085..516a06b6b66ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -28,18 +28,23 @@ static int nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out) { - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV; + return gpio->func->drive(gpio, line, dir, out); } static int nvkm_gpio_sense(struct nvkm_gpio *gpio, int idx, int line) { - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - return impl->sense ? impl->sense(gpio, line) : -ENODEV; + return gpio->func->sense(gpio, line); } -static int +void +nvkm_gpio_reset(struct nvkm_gpio *gpio, u8 func) +{ + if (gpio->func->reset) + gpio->func->reset(gpio, func); +} + +int nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, struct dcb_gpio_func *func) { @@ -71,7 +76,7 @@ nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, return -ENOENT; } -static int +int nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state) { struct dcb_gpio_func func; @@ -87,7 +92,7 @@ nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state) return ret; } -static int +int nvkm_gpio_get(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line) { struct dcb_gpio_func func; @@ -107,16 +112,14 @@ static void nvkm_gpio_intr_fini(struct nvkm_event *event, int type, int index) { struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event); - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - impl->intr_mask(gpio, type, 1 << index, 0); + gpio->func->intr_mask(gpio, type, 1 << index, 0); } static void nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index) { struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event); - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; - impl->intr_mask(gpio, type, 1 << index, 1 << index); + gpio->func->intr_mask(gpio, type, 1 << index, 1 << index); } static int @@ -133,16 +136,22 @@ nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size, return -EINVAL; } +static const struct nvkm_event_func +nvkm_gpio_intr_func = { + .ctor = nvkm_gpio_intr_ctor, + .init = nvkm_gpio_intr_init, + .fini = nvkm_gpio_intr_fini, +}; + static void nvkm_gpio_intr(struct nvkm_subdev *subdev) { struct nvkm_gpio *gpio = nvkm_gpio(subdev); - const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass; u32 hi, lo, i; - impl->intr_stat(gpio, &hi, &lo); + gpio->func->intr_stat(gpio, &hi, &lo); - for (i = 0; (hi | lo) && i < impl->lines; i++) { + for (i = 0; (hi | lo) && i < gpio->func->lines; i++) { struct nvkm_gpio_ntfy_rep rep = { .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) | (NVKM_GPIO_LO * !!(lo & (1 << i))), @@ -151,24 +160,15 @@ nvkm_gpio_intr(struct nvkm_subdev *subdev) } } -static const struct nvkm_event_func -nvkm_gpio_intr_func = { - .ctor = nvkm_gpio_intr_ctor, - .init = nvkm_gpio_intr_init, - .fini = nvkm_gpio_intr_fini, -}; - -int -_nvkm_gpio_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_gpio_fini(struct nvkm_subdev *subdev, bool suspend) { - const struct nvkm_gpio_impl *impl = (void *)object->oclass; - struct nvkm_gpio *gpio = nvkm_gpio(object); - u32 mask = (1 << impl->lines) - 1; - - impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); - impl->intr_stat(gpio, &mask, &mask); + struct nvkm_gpio *gpio = nvkm_gpio(subdev); + u32 mask = (1 << gpio->func->lines) - 1; - return nvkm_subdev_fini_old(&gpio->subdev, suspend); + gpio->func->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0); + gpio->func->intr_stat(gpio, &mask, &mask); + return 0; } static struct dmi_system_id gpio_reset_ids[] = { @@ -182,70 +182,43 @@ static struct dmi_system_id gpio_reset_ids[] = { { } }; -int -_nvkm_gpio_init(struct nvkm_object *object) +static int +nvkm_gpio_init(struct nvkm_subdev *subdev) { - struct nvkm_gpio *gpio = nvkm_gpio(object); - int ret; - - ret = nvkm_subdev_init_old(&gpio->subdev); - if (ret) - return ret; - - if (gpio->reset && dmi_check_system(gpio_reset_ids)) - gpio->reset(gpio, DCB_GPIO_UNUSED); - - return ret; + struct nvkm_gpio *gpio = nvkm_gpio(subdev); + if (dmi_check_system(gpio_reset_ids)) + nvkm_gpio_reset(gpio, DCB_GPIO_UNUSED); + return 0; } -void -_nvkm_gpio_dtor(struct nvkm_object *object) +static void * +nvkm_gpio_dtor(struct nvkm_subdev *subdev) { - struct nvkm_gpio *gpio = (void *)object; + struct nvkm_gpio *gpio = nvkm_gpio(subdev); nvkm_event_fini(&gpio->event); - nvkm_subdev_destroy(&gpio->subdev); + return gpio; } -int -nvkm_gpio_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - const struct nvkm_gpio_impl *impl = (void *)oclass; - struct nvkm_gpio *gpio; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "GPIO", - "gpio", length, pobject); - gpio = *pobject; - if (ret) - return ret; - - gpio->find = nvkm_gpio_find; - gpio->set = nvkm_gpio_set; - gpio->get = nvkm_gpio_get; - gpio->reset = impl->reset; - - ret = nvkm_event_init(&nvkm_gpio_intr_func, 2, impl->lines, - &gpio->event); - if (ret) - return ret; - - nv_subdev(gpio)->intr = nvkm_gpio_intr; - return 0; -} +static const struct nvkm_subdev_func +nvkm_gpio = { + .dtor = nvkm_gpio_dtor, + .init = nvkm_gpio_init, + .fini = nvkm_gpio_fini, + .intr = nvkm_gpio_intr, +}; int -_nvkm_gpio_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_gpio_new_(const struct nvkm_gpio_func *func, struct nvkm_device *device, + int index, struct nvkm_gpio **pgpio) { struct nvkm_gpio *gpio; - int ret; - ret = nvkm_gpio_create(parent, engine, oclass, &gpio); - *pobject = nv_object(gpio); - if (ret) - return ret; + if (!(gpio = *pgpio = kzalloc(sizeof(*gpio), GFP_KERNEL))) + return -ENOMEM; - return 0; + nvkm_subdev_ctor(&nvkm_gpio, device, index, 0, &gpio->subdev); + gpio->func = func; + + return nvkm_event_init(&nvkm_gpio_intr_func, 2, func->lines, + &gpio->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c index 939f6b953ddde..6dcda55fb8655 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c @@ -57,19 +57,18 @@ g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00e070, inte1); } -struct nvkm_oclass * -g94_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +g94_gpio = { .lines = 32, .intr_stat = g94_gpio_intr_stat, .intr_mask = g94_gpio_intr_mask, .drive = nv50_gpio_drive, .sense = nv50_gpio_sense, .reset = nv50_gpio_reset, -}.base; +}; + +int +g94_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&g94_gpio, device, index, pgpio); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf119.c similarity index 80% rename from drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c rename to drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf119.c index a5aae486ec2b8..bb7400dfaef85 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf119.c @@ -24,7 +24,7 @@ #include "priv.h" void -gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) +gf119_gpio_reset(struct nvkm_gpio *gpio, u8 match) { struct nvkm_device *device = gpio->subdev.device; struct nvkm_bios *bios = device->bios; @@ -44,7 +44,7 @@ gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) (match != DCB_GPIO_UNUSED && match != func)) continue; - gpio->set(gpio, 0, func, line, defs); + nvkm_gpio_set(gpio, 0, func, line, defs); nvkm_mask(device, 0x00d610 + (line * 4), 0xff, unk0); if (unk1--) @@ -53,7 +53,7 @@ gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match) } int -gf110_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) +gf119_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) { struct nvkm_device *device = gpio->subdev.device; u32 data = ((dir ^ 1) << 13) | (out << 12); @@ -63,25 +63,24 @@ gf110_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out) } int -gf110_gpio_sense(struct nvkm_gpio *gpio, int line) +gf119_gpio_sense(struct nvkm_gpio *gpio, int line) { struct nvkm_device *device = gpio->subdev.device; return !!(nvkm_rd32(device, 0x00d610 + (line * 4)) & 0x00004000); } -struct nvkm_oclass * -gf110_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +gf119_gpio = { .lines = 32, .intr_stat = g94_gpio_intr_stat, .intr_mask = g94_gpio_intr_mask, - .drive = gf110_gpio_drive, - .sense = gf110_gpio_sense, - .reset = gf110_gpio_reset, -}.base; + .drive = gf119_gpio_drive, + .sense = gf119_gpio_sense, + .reset = gf119_gpio_reset, +}; + +int +gf119_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&gf119_gpio, device, index, pgpio); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c index e8e433cff17d2..3f45afd17d5a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c @@ -57,19 +57,18 @@ gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00dc88, inte1); } -struct nvkm_oclass * -gk104_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +gk104_gpio = { .lines = 32, .intr_stat = gk104_gpio_intr_stat, .intr_mask = gk104_gpio_intr_mask, - .drive = gf110_gpio_drive, - .sense = gf110_gpio_sense, - .reset = gf110_gpio_reset, -}.base; + .drive = gf119_gpio_drive, + .sense = gf119_gpio_sense, + .reset = gf119_gpio_reset, +}; + +int +gk104_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&gk104_gpio, device, index, pgpio); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c index b88cabcc28d7c..ae3499b48330d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c @@ -102,18 +102,17 @@ nv10_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x001144, inte); } -struct nvkm_oclass * -nv10_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x10), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +nv10_gpio = { .lines = 16, .intr_stat = nv10_gpio_intr_stat, .intr_mask = nv10_gpio_intr_mask, .drive = nv10_gpio_drive, .sense = nv10_gpio_sense, -}.base; +}; + +int +nv10_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&nv10_gpio, device, index, pgpio); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c index 4689836059b93..8996649209ab1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c @@ -48,7 +48,7 @@ nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match) (match != DCB_GPIO_UNUSED && match != func)) continue; - gpio->set(gpio, 0, func, line, defs); + nvkm_gpio_set(gpio, 0, func, line, defs); nvkm_mask(device, reg, 0x00010001 << lsh, val << lsh); } @@ -115,19 +115,18 @@ nv50_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00e050, inte); } -struct nvkm_oclass * -nv50_gpio_oclass = &(struct nvkm_gpio_impl) { - .base.handle = NV_SUBDEV(GPIO, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_gpio_ctor, - .dtor = _nvkm_gpio_dtor, - .init = _nvkm_gpio_init, - .fini = _nvkm_gpio_fini, - }, +static const struct nvkm_gpio_func +nv50_gpio = { .lines = 16, .intr_stat = nv50_gpio_intr_stat, .intr_mask = nv50_gpio_intr_mask, .drive = nv50_gpio_drive, .sense = nv50_gpio_sense, .reset = nv50_gpio_reset, -}.base; +}; + +int +nv50_gpio_new(struct nvkm_device *device, int index, struct nvkm_gpio **pgpio) +{ + return nvkm_gpio_new_(&nv50_gpio, device, index, pgpio); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h index 382f8d44e140c..371bcdbbe0d67 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h @@ -1,33 +1,9 @@ #ifndef __NVKM_GPIO_PRIV_H__ #define __NVKM_GPIO_PRIV_H__ +#define nvkm_gpio(p) container_of((p), struct nvkm_gpio, subdev) #include -#define nvkm_gpio_create(p,e,o,d) \ - nvkm_gpio_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_gpio_destroy(p) ({ \ - struct nvkm_gpio *gpio = (p); \ - _nvkm_gpio_dtor(nv_object(gpio)); \ -}) -#define nvkm_gpio_init(p) ({ \ - struct nvkm_gpio *gpio = (p); \ - _nvkm_gpio_init(nv_object(gpio)); \ -}) -#define nvkm_gpio_fini(p,s) ({ \ - struct nvkm_gpio *gpio = (p); \ - _nvkm_gpio_fini(nv_object(gpio), (s)); \ -}) - -int nvkm_gpio_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -int _nvkm_gpio_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_gpio_dtor(struct nvkm_object *); -int _nvkm_gpio_init(struct nvkm_object *); -int _nvkm_gpio_fini(struct nvkm_object *, bool); - -struct nvkm_gpio_impl { - struct nvkm_oclass base; +struct nvkm_gpio_func { int lines; /* read and ack pending interrupts, returning only data @@ -51,6 +27,9 @@ struct nvkm_gpio_impl { void (*reset)(struct nvkm_gpio *, u8); }; +int nvkm_gpio_new_(const struct nvkm_gpio_func *, struct nvkm_device *, + int index, struct nvkm_gpio **); + void nv50_gpio_reset(struct nvkm_gpio *, u8); int nv50_gpio_drive(struct nvkm_gpio *, int, int, int); int nv50_gpio_sense(struct nvkm_gpio *, int); @@ -58,7 +37,7 @@ int nv50_gpio_sense(struct nvkm_gpio *, int); void g94_gpio_intr_stat(struct nvkm_gpio *, u32 *, u32 *); void g94_gpio_intr_mask(struct nvkm_gpio *, u32, u32, u32); -void gf110_gpio_reset(struct nvkm_gpio *, u8); -int gf110_gpio_drive(struct nvkm_gpio *, int, int, int); -int gf110_gpio_sense(struct nvkm_gpio *, int); +void gf119_gpio_reset(struct nvkm_gpio *, u8); +int gf119_gpio_drive(struct nvkm_gpio *, int, int, int); +int gf119_gpio_sense(struct nvkm_gpio *, int); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index 43fff761a1777..e017607673a56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -126,8 +126,9 @@ int nvkm_therm_fan_sense(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *tmr = nvkm_timer(therm); - struct nvkm_gpio *gpio = nvkm_gpio(therm); + struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_timer *tmr = device->timer; + struct nvkm_gpio *gpio = device->gpio; u32 cycles, cur, prev; u64 start, end, tach; @@ -139,12 +140,14 @@ nvkm_therm_fan_sense(struct nvkm_therm *obj) * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ start = tmr->read(tmr); - prev = gpio->get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); + prev = nvkm_gpio_get(gpio, 0, therm->fan->tach.func, + therm->fan->tach.line); cycles = 0; do { usleep_range(500, 1000); /* supports 0 < rpm < 7500 */ - cur = gpio->get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); + cur = nvkm_gpio_get(gpio, 0, therm->fan->tach.func, + therm->fan->tach.line); if (prev != cur) { if (!start) start = tmr->read(tmr); @@ -237,7 +240,7 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) int ret; /* attempt to locate a drivable fan, and determine control method */ - ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); + ret = nvkm_gpio_find(gpio, 0, DCB_GPIO_FAN, 0xff, &func); if (ret == 0) { /* FIXME: is this really the place to perform such checks ? */ if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) { @@ -263,7 +266,8 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) therm->fan->percent = nvkm_therm_fan_get(&therm->base); /* attempt to detect a tachometer connection */ - ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &therm->fan->tach); + ret = nvkm_gpio_find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, + &therm->fan->tach); if (ret) therm->fan->tach.func = DCB_GPIO_UNUSED; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index ac4847f2912d0..944b7905b4a59 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -39,8 +39,9 @@ nvkm_fanpwm_get(struct nvkm_therm *obj) { struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fanpwm *fan = (void *)therm->fan; - struct nvkm_gpio *gpio = nvkm_gpio(therm); - int card_type = nv_device(therm)->card_type; + struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_gpio *gpio = device->gpio; + int card_type = device->card_type; u32 divs, duty; int ret; @@ -52,7 +53,7 @@ nvkm_fanpwm_get(struct nvkm_therm *obj) return (duty * 100) / divs; } - return gpio->get(gpio, 0, fan->func.func, fan->func.line) * 100; + return nvkm_gpio_get(gpio, 0, fan->func.func, fan->func.line) * 100; } static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 88cc190f5a3e1..7e1f21d81eb12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -39,8 +39,9 @@ static void nvkm_fantog_update(struct nvkm_fantog *fan, int percent) { struct nvkm_therm_priv *therm = (void *)fan->base.parent; - struct nvkm_timer *tmr = nvkm_timer(therm); - struct nvkm_gpio *gpio = nvkm_gpio(therm); + struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_timer *tmr = device->timer; + struct nvkm_gpio *gpio = device->gpio; unsigned long flags; int duty; @@ -49,8 +50,8 @@ nvkm_fantog_update(struct nvkm_fantog *fan, int percent) percent = fan->percent; fan->percent = percent; - duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff); - gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty); + duty = !nvkm_gpio_get(gpio, 0, DCB_GPIO_FAN, 0xff); + nvkm_gpio_set(gpio, 0, DCB_GPIO_FAN, 0xff, duty); if (list_empty(&fan->alarm.head) && percent != (duty * 100)) { u64 next_change = (percent * fan->period_us) / 100; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c index 33388378aa6d7..d2bac1d778190 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c @@ -34,13 +34,13 @@ static const u8 tags[] = { int nvkm_voltgpio_get(struct nvkm_volt *volt) { - struct nvkm_gpio *gpio = nvkm_gpio(volt); + struct nvkm_gpio *gpio = volt->subdev.device->gpio; u8 vid = 0; int i; for (i = 0; i < ARRAY_SIZE(tags); i++) { if (volt->vid_mask & (1 << i)) { - int ret = gpio->get(gpio, 0, tags[i], 0xff); + int ret = nvkm_gpio_get(gpio, 0, tags[i], 0xff); if (ret < 0) return ret; vid |= ret << i; @@ -53,12 +53,12 @@ nvkm_voltgpio_get(struct nvkm_volt *volt) int nvkm_voltgpio_set(struct nvkm_volt *volt, u8 vid) { - struct nvkm_gpio *gpio = nvkm_gpio(volt); + struct nvkm_gpio *gpio = volt->subdev.device->gpio; int i; for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) { if (volt->vid_mask & (1 << i)) { - int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1); + int ret = nvkm_gpio_set(gpio, 0, tags[i], 0xff, vid & 1); if (ret < 0) return ret; } @@ -83,7 +83,7 @@ nvkm_voltgpio_init(struct nvkm_volt *volt) */ for (i = 0; i < ARRAY_SIZE(tags); i++) { if (volt->vid_mask & (1 << i)) { - int ret = gpio->find(gpio, 0, tags[i], 0xff, &func); + int ret = nvkm_gpio_find(gpio, 0, tags[i], 0xff, &func); if (ret) { if (ret != -ENOENT) return ret; -- GitLab From 49bd8da5130aa2de1c891c71163a033254eaf932 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5537/7006] drm/nouveau/i2c: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../gpu/drm/nouveau/include/nvkm/subdev/i2c.h | 26 ++-- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 134 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 7 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 -- .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 --- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild | 2 +- .../gpu/drm/nouveau/nvkm/subdev/i2c/base.c | 113 ++++++--------- drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c | 19 ++- .../nvkm/subdev/i2c/{gf110.c => gf119.c} | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c | 19 ++- .../gpu/drm/nouveau/nvkm/subdev/i2c/priv.h | 30 +--- 23 files changed, 200 insertions(+), 327 deletions(-) rename drivers/gpu/drm/nouveau/nvkm/subdev/i2c/{gf110.c => gf119.c} (83%) diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 6cc9c65833a60..66d1bc23f3d7e 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -56,7 +56,7 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_bar(a) nvxx_device(a)->bar #define nvxx_gpio(a) nvxx_device(a)->gpio #define nvxx_clk(a) nvxx_device(a)->clk -#define nvxx_i2c(a) nvkm_i2c(nvxx_device(a)) +#define nvxx_i2c(a) nvxx_device(a)->i2c #define nvxx_therm(a) nvkm_therm(nvxx_device(a)) #include diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h index ddc7e6e4be60a..6b6224dbd5bb3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h @@ -69,31 +69,27 @@ int nvkm_i2c_aux_lnk_ctl(struct nvkm_i2c_aux *, int link_nr, int link_bw, bool enhanced_framing); struct nvkm_i2c { + const struct nvkm_i2c_func *func; struct nvkm_subdev subdev; - struct nvkm_event event; struct list_head pad; struct list_head bus; struct list_head aux; + + struct nvkm_event event; }; struct nvkm_i2c_bus *nvkm_i2c_bus_find(struct nvkm_i2c *, int); struct nvkm_i2c_aux *nvkm_i2c_aux_find(struct nvkm_i2c *, int); -static inline struct nvkm_i2c * -nvkm_i2c(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_I2C); -} - -extern struct nvkm_oclass *nv04_i2c_oclass; -extern struct nvkm_oclass *nv4e_i2c_oclass; -extern struct nvkm_oclass *nv50_i2c_oclass; -extern struct nvkm_oclass *g94_i2c_oclass; -extern struct nvkm_oclass *gf110_i2c_oclass; -extern struct nvkm_oclass *gf117_i2c_oclass; -extern struct nvkm_oclass *gk104_i2c_oclass; -extern struct nvkm_oclass *gm204_i2c_oclass; +int nv04_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int nv4e_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int nv50_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int g94_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int gf117_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int gf119_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int gk104_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); +int gm204_i2c_new(struct nvkm_device *, int, struct nvkm_i2c **); static inline int nvkm_rdi2cr(struct i2c_adapter *adap, u8 addr, u8 reg) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3caaa9caf4d3e..4c314961cc36c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -81,7 +81,7 @@ nv4_chipset = { .clk = nv04_clk_new, .devinit = nv04_devinit_new, .fb = nv04_fb_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -101,7 +101,7 @@ nv5_chipset = { .clk = nv04_clk_new, .devinit = nv05_devinit_new, .fb = nv04_fb_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -122,7 +122,7 @@ nv10_chipset = { .devinit = nv10_devinit_new, .fb = nv10_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -141,7 +141,7 @@ nv11_chipset = { .devinit = nv10_devinit_new, .fb = nv10_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -162,7 +162,7 @@ nv15_chipset = { .devinit = nv10_devinit_new, .fb = nv10_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -183,7 +183,7 @@ nv17_chipset = { .devinit = nv10_devinit_new, .fb = nv10_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -204,7 +204,7 @@ nv18_chipset = { .devinit = nv10_devinit_new, .fb = nv10_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -225,7 +225,7 @@ nv1a_chipset = { .devinit = nv1a_devinit_new, .fb = nv1a_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -246,7 +246,7 @@ nv1f_chipset = { .devinit = nv1a_devinit_new, .fb = nv1a_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -267,7 +267,7 @@ nv20_chipset = { .devinit = nv20_devinit_new, .fb = nv20_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -288,7 +288,7 @@ nv25_chipset = { .devinit = nv20_devinit_new, .fb = nv25_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -309,7 +309,7 @@ nv28_chipset = { .devinit = nv20_devinit_new, .fb = nv25_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -330,7 +330,7 @@ nv2a_chipset = { .devinit = nv20_devinit_new, .fb = nv25_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -351,7 +351,7 @@ nv30_chipset = { .devinit = nv20_devinit_new, .fb = nv30_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -372,7 +372,7 @@ nv31_chipset = { .devinit = nv20_devinit_new, .fb = nv30_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -394,7 +394,7 @@ nv34_chipset = { .devinit = nv10_devinit_new, .fb = nv10_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -416,7 +416,7 @@ nv35_chipset = { .devinit = nv20_devinit_new, .fb = nv35_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -437,7 +437,7 @@ nv36_chipset = { .devinit = nv20_devinit_new, .fb = nv36_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, @@ -459,7 +459,7 @@ nv40_chipset = { .devinit = nv1a_devinit_new, .fb = nv40_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv04_mmu_new, @@ -484,7 +484,7 @@ nv41_chipset = { .devinit = nv1a_devinit_new, .fb = nv41_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, @@ -509,7 +509,7 @@ nv42_chipset = { .devinit = nv1a_devinit_new, .fb = nv41_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, @@ -534,7 +534,7 @@ nv43_chipset = { .devinit = nv1a_devinit_new, .fb = nv41_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, @@ -559,7 +559,7 @@ nv44_chipset = { .devinit = nv1a_devinit_new, .fb = nv44_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv44_mc_new, // .mmu = nv44_mmu_new, @@ -584,7 +584,7 @@ nv45_chipset = { .devinit = nv1a_devinit_new, .fb = nv40_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv04_mmu_new, @@ -609,7 +609,7 @@ nv46_chipset = { .devinit = nv1a_devinit_new, .fb = nv46_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv44_mc_new, // .mmu = nv44_mmu_new, @@ -634,7 +634,7 @@ nv47_chipset = { .devinit = nv1a_devinit_new, .fb = nv47_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, @@ -659,7 +659,7 @@ nv49_chipset = { .devinit = nv1a_devinit_new, .fb = nv49_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, @@ -684,7 +684,7 @@ nv4a_chipset = { .devinit = nv1a_devinit_new, .fb = nv44_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv44_mc_new, // .mmu = nv44_mmu_new, @@ -709,7 +709,7 @@ nv4b_chipset = { .devinit = nv1a_devinit_new, .fb = nv49_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, @@ -734,7 +734,7 @@ nv4c_chipset = { .devinit = nv1a_devinit_new, .fb = nv46_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, @@ -759,7 +759,7 @@ nv4e_chipset = { .devinit = nv1a_devinit_new, .fb = nv4e_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv4e_i2c_new, + .i2c = nv4e_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, @@ -786,7 +786,7 @@ nv50_chipset = { .fb = nv50_fb_new, .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, -// .i2c = nv50_i2c_new, + .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, @@ -812,7 +812,7 @@ nv63_chipset = { .devinit = nv1a_devinit_new, .fb = nv46_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, @@ -837,7 +837,7 @@ nv67_chipset = { .devinit = nv1a_devinit_new, .fb = nv46_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, @@ -862,7 +862,7 @@ nv68_chipset = { .devinit = nv1a_devinit_new, .fb = nv46_fb_new, .gpio = nv10_gpio_new, -// .i2c = nv04_i2c_new, + .i2c = nv04_i2c_new, // .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, @@ -889,7 +889,7 @@ nv84_chipset = { .fb = g84_fb_new, .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, -// .i2c = nv50_i2c_new, + .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, @@ -920,7 +920,7 @@ nv86_chipset = { .fb = g84_fb_new, .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, -// .i2c = nv50_i2c_new, + .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, @@ -951,7 +951,7 @@ nv92_chipset = { .fb = g84_fb_new, .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, -// .i2c = nv50_i2c_new, + .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, @@ -982,7 +982,7 @@ nv94_chipset = { .fb = g84_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g94_mc_new, // .mmu = nv50_mmu_new, @@ -1007,7 +1007,7 @@ nv96_chipset = { .name = "G96", .bios = nvkm_bios_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, .fuse = nv50_fuse_new, .clk = g84_clk_new, // .therm = g84_therm_new, @@ -1038,7 +1038,7 @@ nv98_chipset = { .name = "G98", .bios = nvkm_bios_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, .fuse = nv50_fuse_new, .clk = g84_clk_new, // .therm = g84_therm_new, @@ -1075,7 +1075,7 @@ nva0_chipset = { .fb = g84_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = nv50_i2c_new, + .i2c = nv50_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1106,7 +1106,7 @@ nva3_chipset = { .fb = gt215_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1139,7 +1139,7 @@ nva5_chipset = { .fb = gt215_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1171,7 +1171,7 @@ nva8_chipset = { .fb = gt215_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1203,7 +1203,7 @@ nvaa_chipset = { .fb = mcp77_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1234,7 +1234,7 @@ nvac_chipset = { .fb = mcp77_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1265,7 +1265,7 @@ nvaf_chipset = { .fb = mcp89_fb_new, .fuse = nv50_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, @@ -1297,7 +1297,7 @@ nvc0_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1332,7 +1332,7 @@ nvc1_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1366,7 +1366,7 @@ nvc3_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1400,7 +1400,7 @@ nvc4_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1435,7 +1435,7 @@ nvc8_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1470,7 +1470,7 @@ nvce_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1505,7 +1505,7 @@ nvcf_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = g94_gpio_new, -// .i2c = g94_i2c_new, + .i2c = g94_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1539,7 +1539,7 @@ nvd7_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = gf119_gpio_new, -// .i2c = gf117_i2c_new, + .i2c = gf117_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1571,7 +1571,7 @@ nvd9_chipset = { .fb = gf100_fb_new, .fuse = gf100_fuse_new, .gpio = gf119_gpio_new, -// .i2c = gf110_i2c_new, + .i2c = gf119_i2c_new, // .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, @@ -1605,7 +1605,7 @@ nve4_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gk104_i2c_new, + .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1641,7 +1641,7 @@ nve6_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gk104_i2c_new, + .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1677,7 +1677,7 @@ nve7_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gk104_i2c_new, + .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1737,7 +1737,7 @@ nvf0_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gk104_i2c_new, + .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1773,7 +1773,7 @@ nvf1_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gf110_i2c_new, + .i2c = gf119_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1809,7 +1809,7 @@ nv106_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gk104_i2c_new, + .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1844,7 +1844,7 @@ nv108_chipset = { .fb = gk104_fb_new, .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gk104_i2c_new, + .i2c = gk104_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, @@ -1879,7 +1879,7 @@ nv117_chipset = { .fb = gm107_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gf110_i2c_new, + .i2c = gf119_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, @@ -1908,7 +1908,7 @@ nv124_chipset = { .fb = gm107_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gm204_i2c_new, + .i2c = gm204_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, @@ -1937,7 +1937,7 @@ nv126_chipset = { .fb = gm107_fb_new, .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, -// .i2c = gm204_i2c_new, + .i2c = gm204_i2c_new, // .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 9059b43efe7d8..0ed4eb72628e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -52,7 +51,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -76,7 +74,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -99,7 +96,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -123,7 +119,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -146,7 +141,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -169,7 +163,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; @@ -193,7 +186,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -216,7 +208,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 89eabad81e83d..05d8d276a4e63 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -53,7 +52,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -78,7 +76,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -119,7 +116,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; break; case 0xf0: - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -144,7 +140,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; @@ -169,7 +164,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; @@ -193,7 +187,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index a57db5f56f680..a04bd5b744fd0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -28,7 +28,6 @@ gm100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x117: - device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; @@ -59,7 +58,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x124: - device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; #if 0 /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ @@ -91,7 +89,6 @@ gm100_identify(struct nvkm_device *device) #endif break; case 0x126: - device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass; #if 0 /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index d65d2943d776c..de456b2d44b30 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,7 +28,6 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -40,7 +39,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index ac2994a3fb33c..6e58a0e20ba2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,7 +28,6 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -38,7 +37,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -50,7 +48,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -62,7 +59,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -74,7 +70,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -86,7 +81,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -98,7 +92,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -110,7 +103,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 80290303606e7..1467737759227 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,7 +28,6 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -40,7 +39,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -52,7 +50,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -64,7 +61,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index ce66504d1f3ed..e4d5fc697f494 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,7 +28,6 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -40,7 +39,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -52,7 +50,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -65,7 +62,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; @@ -78,7 +74,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 513fb7eea165a..0bf4fcefcf886 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -44,7 +43,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -60,7 +58,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -76,7 +73,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -92,7 +88,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -108,7 +103,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -124,7 +118,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -140,7 +133,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -156,7 +148,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -172,7 +163,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -188,7 +178,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -204,7 +193,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -220,7 +208,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -236,7 +223,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -252,7 +238,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; @@ -268,7 +253,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index cf8839c1d1f05..956ea9c02f459 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -45,7 +44,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -65,7 +63,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -85,7 +82,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; @@ -105,7 +101,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; @@ -125,7 +120,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; @@ -145,7 +139,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -165,7 +158,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -185,7 +177,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -205,7 +196,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -225,7 +215,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -247,7 +236,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -268,7 +256,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; @@ -289,7 +276,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass; device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild index 200f996f20b7d..1f730613c237b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild @@ -3,8 +3,8 @@ nvkm-y += nvkm/subdev/i2c/nv04.o nvkm-y += nvkm/subdev/i2c/nv4e.o nvkm-y += nvkm/subdev/i2c/nv50.o nvkm-y += nvkm/subdev/i2c/g94.o -nvkm-y += nvkm/subdev/i2c/gf110.o nvkm-y += nvkm/subdev/i2c/gf117.o +nvkm-y += nvkm/subdev/i2c/gf119.o nvkm-y += nvkm/subdev/i2c/gk104.o nvkm-y += nvkm/subdev/i2c/gm204.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c index fe29e728a6029..243a71ff0a0d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c @@ -91,9 +91,8 @@ nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int id) { struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event); struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id); - const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (aux) - impl->aux_mask(i2c, type, aux->intr, 0); + i2c->func->aux_mask(i2c, type, aux->intr, 0); } static void @@ -101,9 +100,8 @@ nvkm_i2c_intr_init(struct nvkm_event *event, int type, int id) { struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event); struct nvkm_i2c_aux *aux = nvkm_i2c_aux_find(i2c, id); - const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass; if (aux) - impl->aux_mask(i2c, type, aux->intr, aux->intr); + i2c->func->aux_mask(i2c, type, aux->intr, aux->intr); } static int @@ -120,18 +118,24 @@ nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size, return -EINVAL; } +static const struct nvkm_event_func +nvkm_i2c_intr_func = { + .ctor = nvkm_i2c_intr_ctor, + .init = nvkm_i2c_intr_init, + .fini = nvkm_i2c_intr_fini, +}; + static void -nvkm_i2c_intr(struct nvkm_subdev *obj) +nvkm_i2c_intr(struct nvkm_subdev *subdev) { - struct nvkm_i2c *i2c = container_of(obj, typeof(*i2c), subdev); - struct nvkm_i2c_impl *impl = (void *)i2c->subdev.object.oclass; + struct nvkm_i2c *i2c = nvkm_i2c(subdev); struct nvkm_i2c_aux *aux; u32 hi, lo, rq, tx; - if (!impl->aux_stat) + if (!i2c->func->aux_stat) return; - impl->aux_stat(i2c, &hi, &lo, &rq, &tx); + i2c->func->aux_stat(i2c, &hi, &lo, &rq, &tx); if (!hi && !lo && !rq && !tx) return; @@ -151,44 +155,31 @@ nvkm_i2c_intr(struct nvkm_subdev *obj) } } -static const struct nvkm_event_func -nvkm_i2c_intr_func = { - .ctor = nvkm_i2c_intr_ctor, - .init = nvkm_i2c_intr_init, - .fini = nvkm_i2c_intr_fini, -}; - -int -_nvkm_i2c_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_i2c_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_i2c_impl *impl = (void *)nv_oclass(object); - struct nvkm_i2c *i2c = (void *)object; + struct nvkm_i2c *i2c = nvkm_i2c(subdev); struct nvkm_i2c_pad *pad; u32 mask; - if ((mask = (1 << impl->aux) - 1), impl->aux_stat) { - impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); - impl->aux_stat(i2c, &mask, &mask, &mask, &mask); + if ((mask = (1 << i2c->func->aux) - 1), i2c->func->aux_stat) { + i2c->func->aux_mask(i2c, NVKM_I2C_ANY, mask, 0); + i2c->func->aux_stat(i2c, &mask, &mask, &mask, &mask); } list_for_each_entry(pad, &i2c->pad, head) { nvkm_i2c_pad_fini(pad); } - return nvkm_subdev_fini_old(&i2c->subdev, suspend); + return 0; } -int -_nvkm_i2c_init(struct nvkm_object *object) +static int +nvkm_i2c_init(struct nvkm_subdev *subdev) { - struct nvkm_i2c *i2c = (void *)object; + struct nvkm_i2c *i2c = nvkm_i2c(subdev); struct nvkm_i2c_bus *bus; struct nvkm_i2c_pad *pad; - int ret; - - ret = nvkm_subdev_init_old(&i2c->subdev); - if (ret) - return ret; list_for_each_entry(pad, &i2c->pad, head) { nvkm_i2c_pad_init(pad); @@ -201,10 +192,10 @@ _nvkm_i2c_init(struct nvkm_object *object) return 0; } -void -_nvkm_i2c_dtor(struct nvkm_object *object) +static void * +nvkm_i2c_dtor(struct nvkm_subdev *subdev) { - struct nvkm_i2c *i2c = (void *)object; + struct nvkm_i2c *i2c = nvkm_i2c(subdev); nvkm_event_fini(&i2c->event); @@ -226,9 +217,17 @@ _nvkm_i2c_dtor(struct nvkm_object *object) nvkm_i2c_pad_del(&pad); } - nvkm_subdev_destroy(&i2c->subdev); + return i2c; } +static const struct nvkm_subdev_func +nvkm_i2c = { + .dtor = nvkm_i2c_dtor, + .init = nvkm_i2c_init, + .fini = nvkm_i2c_fini, + .intr = nvkm_i2c_intr, +}; + static const struct nvkm_i2c_drv { u8 bios; u8 addr; @@ -242,11 +241,9 @@ nvkm_i2c_drv[] = { }; int -nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_i2c_new_(const struct nvkm_i2c_func *func, struct nvkm_device *device, + int index, struct nvkm_i2c **pi2c) { - struct nvkm_i2c_impl *impl = (void *)oclass; - struct nvkm_device *device = (void *)parent; struct nvkm_bios *bios = device->bios; struct nvkm_i2c *i2c; struct dcb_i2c_entry ccbE; @@ -254,17 +251,15 @@ nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine, u8 ver, hdr; int ret, i; - ret = nvkm_subdev_create(parent, engine, oclass, 0, "I2C", "i2c", &i2c); - *pobject = nv_object(i2c); - if (ret) - return ret; + if (!(i2c = *pi2c = kzalloc(sizeof(*i2c), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_i2c, device, index, 0, &i2c->subdev); + i2c->func = func; INIT_LIST_HEAD(&i2c->pad); INIT_LIST_HEAD(&i2c->bus); INIT_LIST_HEAD(&i2c->aux); - nv_subdev(i2c)->intr = nvkm_i2c_intr; - i = -1; while (!dcb_i2c_parse(bios, ++i, &ccbE)) { struct nvkm_i2c_pad *pad = NULL; @@ -278,11 +273,11 @@ nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ccbE.share != DCB_I2C_UNUSED) { const int id = NVKM_I2C_PAD_HYBRID(ccbE.share); if (!(pad = nvkm_i2c_pad_find(i2c, id))) - ret = impl->pad_s_new(i2c, id, &pad); + ret = func->pad_s_new(i2c, id, &pad); else ret = 0; } else { - ret = impl->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad); + ret = func->pad_x_new(i2c, NVKM_I2C_PAD_CCB(i), &pad); } if (ret) { @@ -397,25 +392,5 @@ nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine, } } - ret = nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event); - if (ret) - return ret; - - return 0; -} - -int -_nvkm_i2c_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_i2c *i2c; - int ret; - - ret = nvkm_i2c_create(parent, engine, oclass, &i2c); - *pobject = nv_object(i2c); - if (ret) - return ret; - - return 0; + return nvkm_event_init(&nvkm_i2c_intr_func, 4, i, &i2c->event); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c index e18dc855f21b9..bb2a31d881611 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c @@ -56,18 +56,17 @@ g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00e068, temp); } -struct nvkm_oclass * -g94_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +g94_i2c = { .pad_x_new = g94_i2c_pad_x_new, .pad_s_new = g94_i2c_pad_s_new, .aux = 4, .aux_stat = g94_aux_stat, .aux_mask = g94_aux_mask, -}.base; +}; + +int +g94_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&g94_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c index bd5e7c987cf06..ae4aad3fcd2e3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c @@ -24,14 +24,13 @@ #include "priv.h" #include "pad.h" -struct nvkm_oclass * -gf117_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +gf117_i2c = { .pad_x_new = gf119_i2c_pad_x_new, -}.base; +}; + +int +gf117_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gf117_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf119.c similarity index 83% rename from drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c rename to drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf119.c index cb6774ae24872..6f2b02af42c83 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf119.c @@ -24,18 +24,17 @@ #include "priv.h" #include "pad.h" -struct nvkm_oclass * -gf110_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +gf119_i2c = { .pad_x_new = gf119_i2c_pad_x_new, .pad_s_new = gf119_i2c_pad_s_new, .aux = 4, .aux_stat = g94_aux_stat, .aux_mask = g94_aux_mask, -}.base; +}; + +int +gf119_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gf119_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c index ac97c20693931..f9f6bf4b66c97 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c @@ -56,18 +56,17 @@ gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data) nvkm_wr32(device, 0x00dc68, temp); } -struct nvkm_oclass * -gk104_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +gk104_i2c = { .pad_x_new = gf119_i2c_pad_x_new, .pad_s_new = gf119_i2c_pad_s_new, .aux = 4, .aux_stat = gk104_aux_stat, .aux_mask = gk104_aux_mask, -}.base; +}; + +int +gk104_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gk104_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c index e84b9a4aadc75..ff9f7d62f6be3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c @@ -24,18 +24,17 @@ #include "priv.h" #include "pad.h" -struct nvkm_oclass * -gm204_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +gm204_i2c = { .pad_x_new = gf119_i2c_pad_x_new, .pad_s_new = gm204_i2c_pad_s_new, .aux = 8, .aux_stat = gk104_aux_stat, .aux_mask = gk104_aux_mask, -}.base; +}; + +int +gm204_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&gm204_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c index 9a7279f3ae390..18776f49355c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c @@ -24,14 +24,13 @@ #include "priv.h" #include "pad.h" -struct nvkm_oclass * -nv04_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +nv04_i2c = { .pad_x_new = nv04_i2c_pad_new, -}.base; +}; + +int +nv04_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&nv04_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c index 40533d7868941..6b762f7cee9ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c @@ -24,14 +24,13 @@ #include "priv.h" #include "pad.h" -struct nvkm_oclass * -nv4e_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x4e), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +nv4e_i2c = { .pad_x_new = nv4e_i2c_pad_new, -}.base; +}; + +int +nv4e_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&nv4e_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c index 678585c44cb02..75640ab97d6ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c @@ -24,14 +24,13 @@ #include "priv.h" #include "pad.h" -struct nvkm_oclass * -nv50_i2c_oclass = &(struct nvkm_i2c_impl) { - .base.handle = NV_SUBDEV(I2C, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_i2c_ctor, - .dtor = _nvkm_i2c_dtor, - .init = _nvkm_i2c_init, - .fini = _nvkm_i2c_fini, - }, +static const struct nvkm_i2c_func +nv50_i2c = { .pad_x_new = nv50_i2c_pad_new, -}.base; +}; + +int +nv50_i2c_new(struct nvkm_device *device, int index, struct nvkm_i2c **pi2c) +{ + return nvkm_i2c_new_(&nv50_i2c, device, index, pi2c); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h index e320e9da415bf..bf655a66ef400 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h @@ -1,34 +1,12 @@ #ifndef __NVKM_I2C_PRIV_H__ #define __NVKM_I2C_PRIV_H__ +#define nvkm_i2c(p) container_of((p), struct nvkm_i2c, subdev) #include -#define nvkm_i2c_create(p,e,o,d) \ - nvkm_i2c_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_i2c_destroy(p) ({ \ - struct nvkm_i2c *i2c = (p); \ - _nvkm_i2c_dtor(nv_object(i2c)); \ -}) -#define nvkm_i2c_init(p) ({ \ - struct nvkm_i2c *i2c = (p); \ - _nvkm_i2c_init(nv_object(i2c)); \ -}) -#define nvkm_i2c_fini(p,s) ({ \ - struct nvkm_i2c *i2c = (p); \ - _nvkm_i2c_fini(nv_object(i2c), (s)); \ -}) - -int nvkm_i2c_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -int _nvkm_i2c_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void _nvkm_i2c_dtor(struct nvkm_object *); -int _nvkm_i2c_init(struct nvkm_object *); -int _nvkm_i2c_fini(struct nvkm_object *, bool); - -struct nvkm_i2c_impl { - struct nvkm_oclass base; +int nvkm_i2c_new_(const struct nvkm_i2c_func *, struct nvkm_device *, + int index, struct nvkm_i2c **); +struct nvkm_i2c_func { int (*pad_x_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **); int (*pad_s_new)(struct nvkm_i2c *, int id, struct nvkm_i2c_pad **); -- GitLab From 551d341755e2ade4a915d889524a4187f2cd210e Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5538/7006] drm/nouveau/ibus: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/ibus.h | 30 +------ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 42 ++++----- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 9 -- .../gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c | 62 +++++-------- .../gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c | 88 ++++++++----------- .../gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c | 58 ++++-------- 9 files changed, 101 insertions(+), 209 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h index 8fc7946b8a42f..9d512cd5a0a7f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h @@ -2,31 +2,7 @@ #define __NVKM_IBUS_H__ #include -struct nvkm_ibus { - struct nvkm_subdev subdev; -}; - -static inline struct nvkm_ibus * -nvkm_ibus(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_IBUS); -} - -#define nvkm_ibus_create(p,e,o,d) \ - nvkm_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus", \ - sizeof(**d), (void **)d) -#define nvkm_ibus_destroy(p) \ - nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_ibus_init(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_ibus_fini(p,s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) - -#define _nvkm_ibus_dtor _nvkm_subdev_dtor -#define _nvkm_ibus_init _nvkm_subdev_init -#define _nvkm_ibus_fini _nvkm_subdev_fini - -extern struct nvkm_oclass gf100_ibus_oclass; -extern struct nvkm_oclass gk104_ibus_oclass; -extern struct nvkm_oclass gk20a_ibus_oclass; +int gf100_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **); +int gk104_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **); +int gk20a_ibus_new(struct nvkm_device *, int, struct nvkm_subdev **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 4c314961cc36c..2d8ef80f32e74 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1298,7 +1298,7 @@ nvc0_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, @@ -1333,7 +1333,7 @@ nvc1_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, @@ -1367,7 +1367,7 @@ nvc3_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, @@ -1401,7 +1401,7 @@ nvc4_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, @@ -1436,7 +1436,7 @@ nvc8_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, @@ -1471,7 +1471,7 @@ nvce_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, @@ -1506,7 +1506,7 @@ nvcf_chipset = { .fuse = gf100_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, @@ -1540,7 +1540,7 @@ nvd7_chipset = { .fuse = gf100_fuse_new, .gpio = gf119_gpio_new, .i2c = gf117_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, @@ -1572,7 +1572,7 @@ nvd9_chipset = { .fuse = gf100_fuse_new, .gpio = gf119_gpio_new, .i2c = gf119_i2c_new, -// .ibus = gf100_ibus_new, + .ibus = gf100_ibus_new, // .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, @@ -1606,7 +1606,7 @@ nve4_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, @@ -1642,7 +1642,7 @@ nve6_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, @@ -1678,7 +1678,7 @@ nve7_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, @@ -1710,7 +1710,7 @@ nvea_chipset = { .clk = gk20a_clk_new, .fb = gk20a_fb_new, .fuse = gf100_fuse_new, -// .ibus = gk20a_ibus_new, + .ibus = gk20a_ibus_new, // .imem = gk20a_instmem_new, // .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, @@ -1738,7 +1738,7 @@ nvf0_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, @@ -1774,7 +1774,7 @@ nvf1_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gf119_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, @@ -1810,7 +1810,7 @@ nv106_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, @@ -1845,7 +1845,7 @@ nv108_chipset = { .fuse = gf100_fuse_new, .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, @@ -1880,7 +1880,7 @@ nv117_chipset = { .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, .i2c = gf119_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, @@ -1909,7 +1909,7 @@ nv124_chipset = { .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, .i2c = gm204_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, @@ -1938,7 +1938,7 @@ nv126_chipset = { .fuse = gm107_fuse_new, .gpio = gk104_gpio_new, .i2c = gm204_i2c_new, -// .ibus = gk104_ibus_new, + .ibus = gk104_ibus_new, // .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, @@ -1963,7 +1963,7 @@ nv12b_chipset = { .bus = gf100_bus_new, .fb = gk20a_fb_new, .fuse = gm107_fuse_new, -// .ibus = gk20a_ibus_new, + .ibus = gk20a_ibus_new, // .imem = gk20a_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 0ed4eb72628e3..a0f54fd80810c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -33,7 +33,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -56,7 +55,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -79,7 +77,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -101,7 +98,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -124,7 +120,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -146,7 +141,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -168,7 +162,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -191,7 +184,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; @@ -213,7 +205,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 05d8d276a4e63..f2f524b219501 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -33,7 +33,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; @@ -57,7 +56,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; @@ -81,7 +79,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; @@ -103,7 +100,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -121,7 +117,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; @@ -145,7 +140,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; @@ -169,7 +163,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -192,7 +185,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index a04bd5b744fd0..9c0306279de88 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -33,7 +33,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -67,7 +66,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -98,7 +96,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -125,7 +122,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass; device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index b9ffe56d9eff5..e183729bfee0b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -29,7 +29,6 @@ #include #include #include -#include #include int @@ -97,7 +96,6 @@ nv50_devinit_preinit(struct nvkm_devinit *base) struct nv50_devinit *init = nv50_devinit(base); struct nvkm_subdev *subdev = &init->base.subdev; struct nvkm_device *device = subdev->device; - struct nvkm_subdev *ibus = device->ibus; /* our heuristics can't detect whether the board has had its * devinit scripts executed or not if the display engine is @@ -119,13 +117,6 @@ nv50_devinit_preinit(struct nvkm_devinit *base) init->base.post = true; } } - - /* some boards appear to require certain init register timeouts - * to be bumped before runing devinit scripts. not a clue why - * the vbios engineers didn't make the scripts just work... - */ - if (init->base.post && ibus) - nvkm_object_init(&ibus->object); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c index 6708fbafebaed..37a0496f7ed18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c @@ -24,46 +24,42 @@ #include static void -gf100_ibus_intr_hub(struct nvkm_ibus *ibus, int i) +gf100_ibus_intr_hub(struct nvkm_subdev *ibus, int i) { - struct nvkm_subdev *subdev = &ibus->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = ibus->device; u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0400)); u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0400)); u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0400)); - nvkm_error(subdev, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_error(ibus, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr_rop(struct nvkm_ibus *ibus, int i) +gf100_ibus_intr_rop(struct nvkm_subdev *ibus, int i) { - struct nvkm_subdev *subdev = &ibus->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = ibus->device; u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0400)); u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0400)); u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0400)); - nvkm_error(subdev, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_error(ibus, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) +gf100_ibus_intr_gpc(struct nvkm_subdev *ibus, int i) { - struct nvkm_subdev *subdev = &ibus->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = ibus->device; u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0400)); u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0400)); u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0400)); - nvkm_error(subdev, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_error(ibus, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000); } static void -gf100_ibus_intr(struct nvkm_subdev *subdev) +gf100_ibus_intr(struct nvkm_subdev *ibus) { - struct nvkm_ibus *ibus = (void *)subdev; - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_device *device = ibus->device; u32 intr0 = nvkm_rd32(device, 0x121c58); u32 intr1 = nvkm_rd32(device, 0x121c5c); u32 hubnr = nvkm_rd32(device, 0x121c70); @@ -96,30 +92,18 @@ gf100_ibus_intr(struct nvkm_subdev *subdev) } } -static int -gf100_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_ibus *ibus; - int ret; - - ret = nvkm_ibus_create(parent, engine, oclass, &ibus); - *pobject = nv_object(ibus); - if (ret) - return ret; +static const struct nvkm_subdev_func +gf100_ibus = { + .intr = gf100_ibus_intr, +}; - nv_subdev(ibus)->intr = gf100_ibus_intr; +int +gf100_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gf100_ibus, device, index, 0, ibus); return 0; } - -struct nvkm_oclass -gf100_ibus_oclass = { - .handle = NV_SUBDEV(IBUS, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ibus_ctor, - .dtor = _nvkm_ibus_dtor, - .init = _nvkm_ibus_init, - .fini = _nvkm_ibus_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c index 0ac0bbaa9d2ae..ba33609f643c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c @@ -24,46 +24,42 @@ #include static void -gk104_ibus_intr_hub(struct nvkm_ibus *ibus, int i) +gk104_ibus_intr_hub(struct nvkm_subdev *ibus, int i) { - struct nvkm_subdev *subdev = &ibus->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = ibus->device; u32 addr = nvkm_rd32(device, 0x122120 + (i * 0x0800)); u32 data = nvkm_rd32(device, 0x122124 + (i * 0x0800)); u32 stat = nvkm_rd32(device, 0x122128 + (i * 0x0800)); - nvkm_error(subdev, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_error(ibus, "HUB%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr_rop(struct nvkm_ibus *ibus, int i) +gk104_ibus_intr_rop(struct nvkm_subdev *ibus, int i) { - struct nvkm_subdev *subdev = &ibus->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = ibus->device; u32 addr = nvkm_rd32(device, 0x124120 + (i * 0x0800)); u32 data = nvkm_rd32(device, 0x124124 + (i * 0x0800)); u32 stat = nvkm_rd32(device, 0x124128 + (i * 0x0800)); - nvkm_error(subdev, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_error(ibus, "ROP%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr_gpc(struct nvkm_ibus *ibus, int i) +gk104_ibus_intr_gpc(struct nvkm_subdev *ibus, int i) { - struct nvkm_subdev *subdev = &ibus->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = ibus->device; u32 addr = nvkm_rd32(device, 0x128120 + (i * 0x0800)); u32 data = nvkm_rd32(device, 0x128124 + (i * 0x0800)); u32 stat = nvkm_rd32(device, 0x128128 + (i * 0x0800)); - nvkm_error(subdev, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); + nvkm_error(ibus, "GPC%d: %06x %08x (%08x)\n", i, addr, data, stat); nvkm_mask(device, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000); } static void -gk104_ibus_intr(struct nvkm_subdev *subdev) +gk104_ibus_intr(struct nvkm_subdev *ibus) { - struct nvkm_ibus *ibus = (void *)subdev; - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_device *device = ibus->device; u32 intr0 = nvkm_rd32(device, 0x120058); u32 intr1 = nvkm_rd32(device, 0x12005c); u32 hubnr = nvkm_rd32(device, 0x120070); @@ -97,47 +93,33 @@ gk104_ibus_intr(struct nvkm_subdev *subdev) } static int -gk104_ibus_init(struct nvkm_object *object) +gk104_ibus_init(struct nvkm_subdev *ibus) { - struct nvkm_ibus *ibus = (void *)object; - struct nvkm_device *device = ibus->subdev.device; - int ret = nvkm_ibus_init(ibus); - if (ret == 0) { - nvkm_mask(device, 0x122318, 0x0003ffff, 0x00001000); - nvkm_mask(device, 0x12231c, 0x0003ffff, 0x00000200); - nvkm_mask(device, 0x122310, 0x0003ffff, 0x00000800); - nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000100); - nvkm_mask(device, 0x1223b0, 0x0003ffff, 0x00000fff); - nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000200); - nvkm_mask(device, 0x122358, 0x0003ffff, 0x00002880); - } - return ret; + struct nvkm_device *device = ibus->device; + nvkm_mask(device, 0x122318, 0x0003ffff, 0x00001000); + nvkm_mask(device, 0x12231c, 0x0003ffff, 0x00000200); + nvkm_mask(device, 0x122310, 0x0003ffff, 0x00000800); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000100); + nvkm_mask(device, 0x1223b0, 0x0003ffff, 0x00000fff); + nvkm_mask(device, 0x122348, 0x0003ffff, 0x00000200); + nvkm_mask(device, 0x122358, 0x0003ffff, 0x00002880); + return 0; } -static int -gk104_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_ibus *ibus; - int ret; - - ret = nvkm_ibus_create(parent, engine, oclass, &ibus); - *pobject = nv_object(ibus); - if (ret) - return ret; +static const struct nvkm_subdev_func +gk104_ibus = { + .preinit = gk104_ibus_init, + .init = gk104_ibus_init, + .intr = gk104_ibus_intr, +}; - nv_subdev(ibus)->intr = gk104_ibus_intr; +int +gk104_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gk104_ibus, device, index, 0, ibus); return 0; } - -struct nvkm_oclass -gk104_ibus_oclass = { - .handle = NV_SUBDEV(IBUS, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ibus_ctor, - .dtor = _nvkm_ibus_dtor, - .init = gk104_ibus_init, - .fini = _nvkm_ibus_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c index 1b76423439571..3484079e885a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c @@ -23,9 +23,9 @@ #include static void -gk20a_ibus_init_ibus_ring(struct nvkm_ibus *ibus) +gk20a_ibus_init_ibus_ring(struct nvkm_subdev *ibus) { - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_device *device = ibus->device; nvkm_mask(device, 0x137250, 0x3f, 0); nvkm_mask(device, 0x000200, 0x20, 0); @@ -46,14 +46,13 @@ gk20a_ibus_init_ibus_ring(struct nvkm_ibus *ibus) } static void -gk20a_ibus_intr(struct nvkm_subdev *subdev) +gk20a_ibus_intr(struct nvkm_subdev *ibus) { - struct nvkm_ibus *ibus = (void *)subdev; - struct nvkm_device *device = ibus->subdev.device; + struct nvkm_device *device = ibus->device; u32 status0 = nvkm_rd32(device, 0x120058); if (status0 & 0x7) { - nvkm_debug(subdev, "resetting ibus ring\n"); + nvkm_debug(ibus, "resetting ibus ring\n"); gk20a_ibus_init_ibus_ring(ibus); } @@ -66,44 +65,25 @@ gk20a_ibus_intr(struct nvkm_subdev *subdev) } static int -gk20a_ibus_init(struct nvkm_object *object) +gk20a_ibus_init(struct nvkm_subdev *ibus) { - struct nvkm_ibus *ibus = (void *)object; - int ret; - - ret = _nvkm_ibus_init(object); - if (ret) - return ret; - gk20a_ibus_init_ibus_ring(ibus); - return 0; } -static int -gk20a_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_ibus *ibus; - int ret; - - ret = nvkm_ibus_create(parent, engine, oclass, &ibus); - *pobject = nv_object(ibus); - if (ret) - return ret; +static const struct nvkm_subdev_func +gk20a_ibus = { + .init = gk20a_ibus_init, + .intr = gk20a_ibus_intr, +}; - nv_subdev(ibus)->intr = gk20a_ibus_intr; +int +gk20a_ibus_new(struct nvkm_device *device, int index, + struct nvkm_subdev **pibus) +{ + struct nvkm_subdev *ibus; + if (!(ibus = *pibus = kzalloc(sizeof(*ibus), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&gk20a_ibus, device, index, 0, ibus); return 0; } - -struct nvkm_oclass -gk20a_ibus_oclass = { - .handle = NV_SUBDEV(IBUS, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_ibus_ctor, - .dtor = _nvkm_ibus_dtor, - .init = gk20a_ibus_init, - .fini = _nvkm_ibus_fini, - }, -}; -- GitLab From 8de65bd0901e2ee7a485a158bfe9e4631cc00644 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5539/7006] drm/nouveau/devinit: run devinit scripts right after preinit This ensures we have a valid mask of disabled engines before we start trying to execute fini()/init() on the subdevs, potentially touching devices that don't exist. Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/devinit.h | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 4 +++- .../drm/nouveau/nvkm/subdev/devinit/base.c | 21 ++++++++++--------- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h index 9e053460a9c77..6c1407fd317b0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h @@ -13,6 +13,7 @@ u32 nvkm_devinit_mmio(struct nvkm_devinit *, u32 addr); int nvkm_devinit_pll_set(struct nvkm_devinit *, u32 type, u32 khz); void nvkm_devinit_meminit(struct nvkm_devinit *); u64 nvkm_devinit_disable(struct nvkm_devinit *); +int nvkm_devinit_post(struct nvkm_devinit *, u64 *disable); int nv04_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); int nv05_devinit_new(struct nvkm_device *, int, struct nvkm_devinit **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 2d8ef80f32e74..99a07694a2985 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2167,7 +2167,9 @@ nvkm_device_preinit(struct nvkm_device *device) } } - /*XXX: devinit */ + ret = nvkm_devinit_post(device->devinit, &device->disable_mask); + if (ret) + goto fail; time = ktime_to_us(ktime_get()) - time; nvdev_trace(device, "preinit completed in %lldus\n", time); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c index 47823f5a2cdff..5f25402f6b096 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c @@ -50,11 +50,21 @@ nvkm_devinit_meminit(struct nvkm_devinit *init) u64 nvkm_devinit_disable(struct nvkm_devinit *init) { - if (init->func->disable) + if (init && init->func->disable) return init->func->disable(init); return 0; } +int +nvkm_devinit_post(struct nvkm_devinit *init, u64 *disable) +{ + int ret = 0; + if (init && init->func->post) + ret = init->func->post(init, init->post); + *disable = nvkm_devinit_disable(init); + return ret; +} + static int nvkm_devinit_fini(struct nvkm_subdev *subdev, bool suspend) { @@ -82,17 +92,8 @@ static int nvkm_devinit_init(struct nvkm_subdev *subdev) { struct nvkm_devinit *init = nvkm_devinit(subdev); - int ret; - - ret = init->func->post(init, init->post); - if (ret) - return ret; - if (init->func->init) init->func->init(init); - - if (init->func->disable) - subdev->device->disable_mask |= init->func->disable(init); return 0; } -- GitLab From b7a2bc1886d00f5f1358079e1e6f4979006a4ed6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:20 +1000 Subject: [PATCH 5540/7006] drm/nouveau/imem: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/instmem.h | 35 ++--- drivers/gpu/drm/nouveau/nvkm/core/memory.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 6 +- .../drm/nouveau/nvkm/subdev/instmem/base.c | 91 +++++++----- .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 54 +++---- .../drm/nouveau/nvkm/subdev/instmem/nv04.c | 75 +++++----- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 122 ++++++++-------- .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 47 +++--- .../drm/nouveau/nvkm/subdev/instmem/priv.h | 29 ++-- 21 files changed, 285 insertions(+), 391 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h index a4b943ee7a9ad..28bc202f9753e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h @@ -4,14 +4,11 @@ struct nvkm_memory; struct nvkm_instmem { + const struct nvkm_instmem_func *func; struct nvkm_subdev subdev; - struct list_head list; + struct list_head list; u32 reserved; - int (*alloc)(struct nvkm_instmem *, u32 size, u32 align, bool zero, - struct nvkm_memory **); - - const struct nvkm_instmem_func *func; struct nvkm_memory *vbios; struct nvkm_ramht *ramht; @@ -19,26 +16,14 @@ struct nvkm_instmem { struct nvkm_memory *ramfc; }; -struct nvkm_instmem_func { - u32 (*rd32)(struct nvkm_instmem *, u32 addr); - void (*wr32)(struct nvkm_instmem *, u32 addr, u32 data); -}; - -static inline struct nvkm_instmem * -nvkm_instmem(void *obj) -{ - /* nv04/nv40 impls need to create objects in their constructor, - * which is before the subdev pointer is valid - */ - if (nv_iclass(obj, NV_SUBDEV_CLASS) && - nv_subidx(obj) == NVDEV_SUBDEV_INSTMEM) - return obj; +u32 nvkm_instmem_rd32(struct nvkm_instmem *, u32 addr); +void nvkm_instmem_wr32(struct nvkm_instmem *, u32 addr, u32 data); +int nvkm_instobj_new(struct nvkm_instmem *, u32 size, u32 align, bool zero, + struct nvkm_memory **); - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_INSTMEM); -} -extern struct nvkm_oclass *nv04_instmem_oclass; -extern struct nvkm_oclass *nv40_instmem_oclass; -extern struct nvkm_oclass *nv50_instmem_oclass; -extern struct nvkm_oclass *gk20a_instmem_oclass; +int nv04_instmem_new(struct nvkm_device *, int, struct nvkm_instmem **); +int nv40_instmem_new(struct nvkm_device *, int, struct nvkm_instmem **); +int nv50_instmem_new(struct nvkm_device *, int, struct nvkm_instmem **); +int gk20a_instmem_new(struct nvkm_device *, int, struct nvkm_instmem **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/memory.c b/drivers/gpu/drm/nouveau/nvkm/core/memory.c index 0b88faa845f37..8903c04c977e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/memory.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/memory.c @@ -55,7 +55,7 @@ nvkm_memory_new(struct nvkm_device *device, enum nvkm_memory_target target, if (unlikely(target != NVKM_MEM_TARGET_INST || !imem)) return -ENOSYS; - ret = imem->alloc(imem, size, align, zero, &memory); + ret = nvkm_instobj_new(imem, size, align, zero, &memory); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 99a07694a2985..3b83f17b3a23f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -82,7 +82,7 @@ nv4_chipset = { .devinit = nv04_devinit_new, .fb = nv04_fb_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -102,7 +102,7 @@ nv5_chipset = { .devinit = nv05_devinit_new, .fb = nv04_fb_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -123,7 +123,7 @@ nv10_chipset = { .fb = nv10_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -142,7 +142,7 @@ nv11_chipset = { .fb = nv10_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -163,7 +163,7 @@ nv15_chipset = { .fb = nv10_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -184,7 +184,7 @@ nv17_chipset = { .fb = nv10_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -205,7 +205,7 @@ nv18_chipset = { .fb = nv10_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -226,7 +226,7 @@ nv1a_chipset = { .fb = nv1a_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -247,7 +247,7 @@ nv1f_chipset = { .fb = nv1a_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -268,7 +268,7 @@ nv20_chipset = { .fb = nv20_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -289,7 +289,7 @@ nv25_chipset = { .fb = nv25_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -310,7 +310,7 @@ nv28_chipset = { .fb = nv25_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -331,7 +331,7 @@ nv2a_chipset = { .fb = nv25_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -352,7 +352,7 @@ nv30_chipset = { .fb = nv30_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -373,7 +373,7 @@ nv31_chipset = { .fb = nv30_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -395,7 +395,7 @@ nv34_chipset = { .fb = nv10_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -417,7 +417,7 @@ nv35_chipset = { .fb = nv35_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -438,7 +438,7 @@ nv36_chipset = { .fb = nv36_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv04_instmem_new, + .imem = nv04_instmem_new, // .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, @@ -460,7 +460,7 @@ nv40_chipset = { .fb = nv40_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv04_mmu_new, // .therm = nv40_therm_new, @@ -485,7 +485,7 @@ nv41_chipset = { .fb = nv41_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, @@ -510,7 +510,7 @@ nv42_chipset = { .fb = nv41_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, @@ -535,7 +535,7 @@ nv43_chipset = { .fb = nv41_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, @@ -560,7 +560,7 @@ nv44_chipset = { .fb = nv44_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv44_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -585,7 +585,7 @@ nv45_chipset = { .fb = nv40_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv04_mmu_new, // .therm = nv40_therm_new, @@ -610,7 +610,7 @@ nv46_chipset = { .fb = nv46_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv44_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -635,7 +635,7 @@ nv47_chipset = { .fb = nv47_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, @@ -660,7 +660,7 @@ nv49_chipset = { .fb = nv49_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, @@ -685,7 +685,7 @@ nv4a_chipset = { .fb = nv44_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv44_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -710,7 +710,7 @@ nv4b_chipset = { .fb = nv49_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, @@ -735,7 +735,7 @@ nv4c_chipset = { .fb = nv46_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -760,7 +760,7 @@ nv4e_chipset = { .fb = nv4e_fb_new, .gpio = nv10_gpio_new, .i2c = nv4e_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -787,7 +787,7 @@ nv50_chipset = { .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -813,7 +813,7 @@ nv63_chipset = { .fb = nv46_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -838,7 +838,7 @@ nv67_chipset = { .fb = nv46_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -863,7 +863,7 @@ nv68_chipset = { .fb = nv46_fb_new, .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, -// .imem = nv40_instmem_new, + .imem = nv40_instmem_new, // .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, @@ -890,7 +890,7 @@ nv84_chipset = { .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -921,7 +921,7 @@ nv86_chipset = { .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -952,7 +952,7 @@ nv92_chipset = { .fuse = nv50_fuse_new, .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -983,7 +983,7 @@ nv94_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g94_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1017,7 +1017,7 @@ nv96_chipset = { .bus = g94_bus_new, // .timer = nv04_timer_new, .fb = g84_fb_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mmu = nv50_mmu_new, .bar = g84_bar_new, // .volt = nv40_volt_new, @@ -1048,7 +1048,7 @@ nv98_chipset = { .bus = g94_bus_new, // .timer = nv04_timer_new, .fb = g84_fb_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mmu = nv50_mmu_new, .bar = g84_bar_new, // .volt = nv40_volt_new, @@ -1076,7 +1076,7 @@ nva0_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = nv50_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1107,7 +1107,7 @@ nva3_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1140,7 +1140,7 @@ nva5_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1172,7 +1172,7 @@ nva8_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1204,7 +1204,7 @@ nvaa_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1235,7 +1235,7 @@ nvac_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1266,7 +1266,7 @@ nvaf_chipset = { .fuse = nv50_fuse_new, .gpio = g94_gpio_new, .i2c = g94_i2c_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, @@ -1299,7 +1299,7 @@ nvc0_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, @@ -1334,7 +1334,7 @@ nvc1_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1368,7 +1368,7 @@ nvc3_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1402,7 +1402,7 @@ nvc4_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, @@ -1437,7 +1437,7 @@ nvc8_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, @@ -1472,7 +1472,7 @@ nvce_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, @@ -1507,7 +1507,7 @@ nvcf_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1541,7 +1541,7 @@ nvd7_chipset = { .gpio = gf119_gpio_new, .i2c = gf117_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1573,7 +1573,7 @@ nvd9_chipset = { .gpio = gf119_gpio_new, .i2c = gf119_i2c_new, .ibus = gf100_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1607,7 +1607,7 @@ nve4_chipset = { .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1643,7 +1643,7 @@ nve6_chipset = { .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1679,7 +1679,7 @@ nve7_chipset = { .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1711,7 +1711,7 @@ nvea_chipset = { .fb = gk20a_fb_new, .fuse = gf100_fuse_new, .ibus = gk20a_ibus_new, -// .imem = gk20a_instmem_new, + .imem = gk20a_instmem_new, // .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, @@ -1739,7 +1739,7 @@ nvf0_chipset = { .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1775,7 +1775,7 @@ nvf1_chipset = { .gpio = gk104_gpio_new, .i2c = gf119_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, @@ -1811,7 +1811,7 @@ nv106_chipset = { .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, @@ -1846,7 +1846,7 @@ nv108_chipset = { .gpio = gk104_gpio_new, .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, @@ -1881,7 +1881,7 @@ nv117_chipset = { .gpio = gk104_gpio_new, .i2c = gf119_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, @@ -1910,7 +1910,7 @@ nv124_chipset = { .gpio = gk104_gpio_new, .i2c = gm204_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, @@ -1939,7 +1939,7 @@ nv126_chipset = { .gpio = gk104_gpio_new, .i2c = gm204_i2c_new, .ibus = gk104_ibus_new, -// .imem = nv50_instmem_new, + .imem = nv50_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, @@ -1964,7 +1964,7 @@ nv12b_chipset = { .fb = gk20a_fb_new, .fuse = gm107_fuse_new, .ibus = gk20a_ibus_new, -// .imem = gk20a_instmem_new, + .imem = gk20a_instmem_new, // .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index a0f54fd80810c..8f9d871b545f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -33,7 +33,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -55,7 +54,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -77,7 +75,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -98,7 +95,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -120,7 +116,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -141,7 +136,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -162,7 +156,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -184,7 +177,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -205,7 +197,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index f2f524b219501..dcb0f6db213d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -33,7 +33,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -56,7 +55,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -79,7 +77,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -100,7 +97,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; @@ -117,7 +113,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -140,7 +135,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -163,7 +157,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -185,7 +178,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 9c0306279de88..158af1f8799e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -33,7 +33,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -66,7 +65,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -96,7 +94,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -122,7 +119,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = gk20a_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index de456b2d44b30..dc90bad938697 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -30,7 +30,6 @@ nv04_identify(struct nvkm_device *device) case 0x04: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; @@ -41,7 +40,6 @@ nv04_identify(struct nvkm_device *device) case 0x05: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 6e58a0e20ba2c..b1db20f4a15c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -30,7 +30,6 @@ nv10_identify(struct nvkm_device *device) case 0x10: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; @@ -39,7 +38,6 @@ nv10_identify(struct nvkm_device *device) case 0x15: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; @@ -50,7 +48,6 @@ nv10_identify(struct nvkm_device *device) case 0x16: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; @@ -61,7 +58,6 @@ nv10_identify(struct nvkm_device *device) case 0x1a: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; @@ -72,7 +68,6 @@ nv10_identify(struct nvkm_device *device) case 0x11: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; @@ -83,7 +78,6 @@ nv10_identify(struct nvkm_device *device) case 0x17: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -94,7 +88,6 @@ nv10_identify(struct nvkm_device *device) case 0x1f: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -105,7 +98,6 @@ nv10_identify(struct nvkm_device *device) case 0x18: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 1467737759227..f11b7d01f34a9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -30,7 +30,6 @@ nv20_identify(struct nvkm_device *device) case 0x20: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -41,7 +40,6 @@ nv20_identify(struct nvkm_device *device) case 0x25: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -52,7 +50,6 @@ nv20_identify(struct nvkm_device *device) case 0x28: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -63,7 +60,6 @@ nv20_identify(struct nvkm_device *device) case 0x2a: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index e4d5fc697f494..780dd1019666f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -30,7 +30,6 @@ nv30_identify(struct nvkm_device *device) case 0x30: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -41,7 +40,6 @@ nv30_identify(struct nvkm_device *device) case 0x35: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -52,7 +50,6 @@ nv30_identify(struct nvkm_device *device) case 0x31: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -64,7 +61,6 @@ nv30_identify(struct nvkm_device *device) case 0x36: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; @@ -76,7 +72,6 @@ nv30_identify(struct nvkm_device *device) case 0x34: device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 0bf4fcefcf886..a5d874a2c2972 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -31,7 +31,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -46,7 +45,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -61,7 +59,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -76,7 +73,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -91,7 +87,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -106,7 +101,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -121,7 +115,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -136,7 +129,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -151,7 +143,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -166,7 +157,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -181,7 +171,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -196,7 +185,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -211,7 +199,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -226,7 +213,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -241,7 +227,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -256,7 +241,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 956ea9c02f459..2507559e5894a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -32,7 +32,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -48,7 +47,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -67,7 +65,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -86,7 +83,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -105,7 +101,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -124,7 +119,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -143,7 +137,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -162,7 +155,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -181,7 +173,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -200,7 +191,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -219,7 +209,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -240,7 +229,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -260,7 +248,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -280,7 +267,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 0103337f55d29..0e4e1152eeeca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -353,6 +353,7 @@ nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { + struct nvkm_device *device = (void *)parent; struct nv40_gr *gr; int ret; @@ -365,7 +366,7 @@ nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, nv_subdev(gr)->unit = 0x00001000; nv_subdev(gr)->intr = nv40_gr_intr; - if (nv44_gr_class(gr)) + if (nv44_gr_class(device)) gr->base.func = &nv44_gr; else gr->base.func = &nv40_gr; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h index eefb36cbeeeac..42cc409a8df2a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h @@ -23,10 +23,8 @@ struct nv40_gr_chan { * helpful to determine a number of other hardware features */ static inline int -nv44_gr_class(void *priv) +nv44_gr_class(struct nvkm_device *device) { - struct nvkm_device *device = nv_device(priv); - if ((device->chipset & 0xf0) == 0x60) return 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index b4ef1ebd38ab2..97529c4f0a25e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -32,9 +32,9 @@ nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) { struct nvkm_instmem *imem = device->imem; u32 inst = data << 4; - u32 dma0 = imem->func->rd32(imem, inst + 0); - u32 dma1 = imem->func->rd32(imem, inst + 4); - u32 dma2 = imem->func->rd32(imem, inst + 8); + u32 dma0 = nvkm_instmem_rd32(imem, inst + 0); + u32 dma1 = nvkm_instmem_rd32(imem, inst + 4); + u32 dma2 = nvkm_instmem_rd32(imem, inst + 8); u32 base = (dma2 & 0xfffff000) | (dma0 >> 20); u32 size = dma1 + 1; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c index 6a356f348c582..895ba74057d4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c @@ -168,21 +168,20 @@ nvkm_instobj_func_slow = { .map = nvkm_instobj_map, }; -static int +int nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, struct nvkm_memory **pmemory) { - struct nvkm_instmem_impl *impl = (void *)imem->subdev.object.oclass; - struct nvkm_memory *memory; + struct nvkm_memory *memory = NULL; struct nvkm_instobj *iobj; u32 offset; int ret; - ret = impl->memory_new(imem, size, align, zero, &memory); + ret = imem->func->memory_new(imem, size, align, zero, &memory); if (ret) goto done; - if (!impl->persistent) { + if (!imem->func->persistent) { if (!(iobj = kzalloc(sizeof(*iobj), GFP_KERNEL))) { ret = -ENOMEM; goto done; @@ -195,7 +194,7 @@ nvkm_instobj_new(struct nvkm_instmem *imem, u32 size, u32 align, bool zero, memory = &iobj->memory; } - if (!impl->zero && zero) { + if (!imem->func->zero && zero) { void __iomem *map = nvkm_kmap(memory); if (unlikely(!map)) { for (offset = 0; offset < size; offset += 4) @@ -217,13 +216,28 @@ done: * instmem subdev base implementation *****************************************************************************/ -int -_nvkm_instmem_fini(struct nvkm_object *object, bool suspend) +u32 +nvkm_instmem_rd32(struct nvkm_instmem *imem, u32 addr) +{ + return imem->func->rd32(imem, addr); +} + +void +nvkm_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data) +{ + return imem->func->wr32(imem, addr, data); +} + +static int +nvkm_instmem_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_instmem *imem = (void *)object; + struct nvkm_instmem *imem = nvkm_instmem(subdev); struct nvkm_instobj *iobj; int i; + if (imem->func->fini) + imem->func->fini(imem); + if (suspend) { list_for_each_entry(iobj, &imem->list, head) { struct nvkm_memory *memory = iobj->parent; @@ -238,19 +252,24 @@ _nvkm_instmem_fini(struct nvkm_object *object, bool suspend) } } - return nvkm_subdev_fini_old(&imem->subdev, suspend); + return 0; } -int -_nvkm_instmem_init(struct nvkm_object *object) +static int +nvkm_instmem_oneinit(struct nvkm_subdev *subdev) { - struct nvkm_instmem *imem = (void *)object; - struct nvkm_instobj *iobj; - int ret, i; + struct nvkm_instmem *imem = nvkm_instmem(subdev); + if (imem->func->oneinit) + return imem->func->oneinit(imem); + return 0; +} - ret = nvkm_subdev_init_old(&imem->subdev); - if (ret) - return ret; +static int +nvkm_instmem_init(struct nvkm_subdev *subdev) +{ + struct nvkm_instmem *imem = nvkm_instmem(subdev); + struct nvkm_instobj *iobj; + int i; list_for_each_entry(iobj, &imem->list, head) { if (iobj->suspend) { @@ -266,23 +285,29 @@ _nvkm_instmem_init(struct nvkm_object *object) return 0; } -int -nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static void * +nvkm_instmem_dtor(struct nvkm_subdev *subdev) { - struct nvkm_device *device = (void *)parent; - struct nvkm_instmem *imem; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "INSTMEM", - "instmem", length, pobject); - imem = *pobject; - if (ret) - return ret; + struct nvkm_instmem *imem = nvkm_instmem(subdev); + if (imem->func->dtor) + return imem->func->dtor(imem); + return imem; +} - device->imem = imem; +static const struct nvkm_subdev_func +nvkm_instmem = { + .dtor = nvkm_instmem_dtor, + .oneinit = nvkm_instmem_oneinit, + .init = nvkm_instmem_init, + .fini = nvkm_instmem_fini, +}; +void +nvkm_instmem_ctor(const struct nvkm_instmem_func *func, + struct nvkm_device *device, int index, + struct nvkm_instmem *imem) +{ + nvkm_subdev_ctor(&nvkm_instmem, device, index, 0, &imem->subdev); + imem->func = func; INIT_LIST_HEAD(&imem->list); - imem->alloc = nvkm_instobj_new; - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index a64c3f9bfc3dc..ab01989c34304 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -186,7 +186,7 @@ gk20a_instobj_dtor_dma(struct gk20a_instobj *_node) { struct gk20a_instobj_dma *node = (void *)_node; struct gk20a_instmem *imem = _node->imem; - struct device *dev = nv_device_base(nv_device(imem)); + struct device *dev = nv_device_base(imem->base.subdev.device); if (unlikely(!node->cpuaddr)) return; @@ -372,7 +372,7 @@ gk20a_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, struct nvkm_memory **pmemory) { struct gk20a_instmem *imem = gk20a_instmem(base); - struct gk20a_instobj *node; + struct gk20a_instobj *node = NULL; struct nvkm_subdev *subdev = &imem->base.subdev; int ret; @@ -389,9 +389,9 @@ gk20a_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, else ret = gk20a_instobj_ctor_dma(imem, size >> PAGE_SHIFT, align, &node); + *pmemory = node ? &node->memory : NULL; if (ret) return ret; - *pmemory = &node->memory; nvkm_memory_ctor(&gk20a_instobj_func, &node->memory); node->imem = imem; @@ -407,29 +407,31 @@ gk20a_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, return 0; } -static int -gk20a_instmem_fini(struct nvkm_object *object, bool suspend) +static void +gk20a_instmem_fini(struct nvkm_instmem *base) { - struct gk20a_instmem *imem = (void *)object; - imem->addr = ~0ULL; - return nvkm_instmem_fini(&imem->base, suspend); + gk20a_instmem(base)->addr = ~0ULL; } -static int -gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_instmem_func +gk20a_instmem = { + .fini = gk20a_instmem_fini, + .memory_new = gk20a_instobj_new, + .persistent = true, + .zero = false, +}; + +int +gk20a_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) { - struct nvkm_device *device = (void *)parent; struct gk20a_instmem *imem; - int ret; - - ret = nvkm_instmem_create(parent, engine, oclass, &imem); - *pobject = nv_object(imem); - if (ret) - return ret; + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&gk20a_instmem, device, index, &imem->base); spin_lock_init(&imem->lock); + *pimem = &imem->base; if (device->gpu->iommu.domain) { imem->domain = device->gpu->iommu.domain; @@ -454,17 +456,3 @@ gk20a_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } - -struct nvkm_oclass * -gk20a_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_instmem_ctor, - .dtor = _nvkm_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = gk20a_instmem_fini, - }, - .memory_new = gk20a_instobj_new, - .persistent = true, - .zero = false, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c index 1df45273bff7b..6133c8bb2d423 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c @@ -150,40 +150,13 @@ nv04_instmem_wr32(struct nvkm_instmem *imem, u32 addr, u32 data) nvkm_wr32(imem->subdev.device, 0x700000 + addr, data); } -static void -nv04_instmem_dtor(struct nvkm_object *object) -{ - struct nv04_instmem *imem = (void *)object; - nvkm_memory_del(&imem->base.ramfc); - nvkm_memory_del(&imem->base.ramro); - nvkm_ramht_del(&imem->base.ramht); - nvkm_memory_del(&imem->base.vbios); - nvkm_mm_fini(&imem->heap); - nvkm_instmem_destroy(&imem->base); -} - -static const struct nvkm_instmem_func -nv04_instmem_func = { - .rd32 = nv04_instmem_rd32, - .wr32 = nv04_instmem_wr32, -}; - static int -nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_instmem_oneinit(struct nvkm_instmem *base) { - struct nvkm_device *device = (void *)parent; - struct nv04_instmem *imem; + struct nv04_instmem *imem = nv04_instmem(base); + struct nvkm_device *device = imem->base.subdev.device; int ret; - ret = nvkm_instmem_create(parent, engine, oclass, &imem); - *pobject = nv_object(imem); - if (ret) - return ret; - - imem->base.func = &nv04_instmem_func; - /* PRAMIN aperture maps over the end of VRAM, reserve it */ imem->base.reserved = 512 * 1024; @@ -217,16 +190,38 @@ nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass * -nv04_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_instmem_ctor, - .dtor = nv04_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = _nvkm_instmem_fini, - }, +static void * +nv04_instmem_dtor(struct nvkm_instmem *base) +{ + struct nv04_instmem *imem = nv04_instmem(base); + nvkm_memory_del(&imem->base.ramfc); + nvkm_memory_del(&imem->base.ramro); + nvkm_ramht_del(&imem->base.ramht); + nvkm_memory_del(&imem->base.vbios); + nvkm_mm_fini(&imem->heap); + return imem; +} + +static const struct nvkm_instmem_func +nv04_instmem = { + .dtor = nv04_instmem_dtor, + .oneinit = nv04_instmem_oneinit, + .rd32 = nv04_instmem_rd32, + .wr32 = nv04_instmem_wr32, .memory_new = nv04_instobj_new, .persistent = false, .zero = false, -}.base; +}; + +int +nv04_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) +{ + struct nv04_instmem *imem; + + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&nv04_instmem, device, index, &imem->base); + *pimem = &imem->base; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index 8e7a11503c09e..a170ff9b32e75 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -138,67 +138,23 @@ nv40_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, *****************************************************************************/ static u32 -nv40_instmem_rd32(struct nvkm_instmem *obj, u32 addr) +nv40_instmem_rd32(struct nvkm_instmem *base, u32 addr) { - struct nv40_instmem *imem = container_of(obj, typeof(*imem), base); - return ioread32_native(imem->iomem + addr); + return ioread32_native(nv40_instmem(base)->iomem + addr); } static void -nv40_instmem_wr32(struct nvkm_instmem *obj, u32 addr, u32 data) +nv40_instmem_wr32(struct nvkm_instmem *base, u32 addr, u32 data) { - struct nv40_instmem *imem = container_of(obj, typeof(*imem), base); - iowrite32_native(data, imem->iomem + addr); + iowrite32_native(data, nv40_instmem(base)->iomem + addr); } -static void -nv40_instmem_dtor(struct nvkm_object *object) -{ - struct nv40_instmem *imem = (void *)object; - nvkm_memory_del(&imem->base.ramfc); - nvkm_memory_del(&imem->base.ramro); - nvkm_ramht_del(&imem->base.ramht); - nvkm_memory_del(&imem->base.vbios); - nvkm_mm_fini(&imem->heap); - if (imem->iomem) - iounmap(imem->iomem); - nvkm_instmem_destroy(&imem->base); -} - -static const struct nvkm_instmem_func -nv40_instmem_func = { - .rd32 = nv40_instmem_rd32, - .wr32 = nv40_instmem_wr32, -}; - static int -nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_instmem_oneinit(struct nvkm_instmem *base) { - struct nvkm_device *device = (void *)parent; - struct nv40_instmem *imem; - int ret, bar, vs; - - ret = nvkm_instmem_create(parent, engine, oclass, &imem); - *pobject = nv_object(imem); - if (ret) - return ret; - - imem->base.func = &nv40_instmem_func; - - /* map bar */ - if (nv_device_resource_len(device, 2)) - bar = 2; - else - bar = 3; - - imem->iomem = ioremap(nv_device_resource_start(device, bar), - nv_device_resource_len(device, bar)); - if (!imem->iomem) { - nvkm_error(&imem->base.subdev, "unable to map PRAMIN BAR\n"); - return -EFAULT; - } + struct nv40_instmem *imem = nv40_instmem(base); + struct nvkm_device *device = imem->base.subdev.device; + int ret, vs; /* PRAMIN aperture maps over the end of vram, reserve enough space * to fit graphics contexts for every channel, the magics come @@ -207,13 +163,12 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, vs = hweight8((nvkm_rd32(device, 0x001540) & 0x0000ff00) >> 8); if (device->chipset == 0x40) imem->base.reserved = 0x6aa0 * vs; else if (device->chipset < 0x43) imem->base.reserved = 0x4f00 * vs; - else if (nv44_gr_class(imem)) imem->base.reserved = 0x4980 * vs; + else if (nv44_gr_class(device)) imem->base.reserved = 0x4980 * vs; else imem->base.reserved = 0x4a40 * vs; imem->base.reserved += 16 * 1024; imem->base.reserved *= 32; /* per-channel */ imem->base.reserved += 512 * 1024; /* pci(e)gart table */ imem->base.reserved += 512 * 1024; /* object storage */ - imem->base.reserved = round_up(imem->base.reserved, 4096); ret = nvkm_mm_init(&imem->heap, 0, imem->base.reserved, 1); @@ -250,16 +205,55 @@ nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -struct nvkm_oclass * -nv40_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0x40), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_instmem_ctor, - .dtor = nv40_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = _nvkm_instmem_fini, - }, +static void * +nv40_instmem_dtor(struct nvkm_instmem *base) +{ + struct nv40_instmem *imem = nv40_instmem(base); + nvkm_memory_del(&imem->base.ramfc); + nvkm_memory_del(&imem->base.ramro); + nvkm_ramht_del(&imem->base.ramht); + nvkm_memory_del(&imem->base.vbios); + nvkm_mm_fini(&imem->heap); + if (imem->iomem) + iounmap(imem->iomem); + return imem; +} + +static const struct nvkm_instmem_func +nv40_instmem = { + .dtor = nv40_instmem_dtor, + .oneinit = nv40_instmem_oneinit, + .rd32 = nv40_instmem_rd32, + .wr32 = nv40_instmem_wr32, .memory_new = nv40_instobj_new, .persistent = false, .zero = false, -}.base; +}; + +int +nv40_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) +{ + struct nv40_instmem *imem; + int bar; + + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&nv40_instmem, device, index, &imem->base); + *pimem = &imem->base; + + /* map bar */ + if (nv_device_resource_len(device, 2)) + bar = 2; + else + bar = 3; + + imem->iomem = ioremap(nv_device_resource_start(device, bar), + nv_device_resource_len(device, bar)); + if (!imem->iomem) { + nvkm_error(&imem->base.subdev, "unable to map PRAMIN BAR\n"); + return -EFAULT; + } + + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index af236f8e4ddc7..ec5020e3fc42e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -220,41 +220,30 @@ nv50_instobj_new(struct nvkm_instmem *base, u32 size, u32 align, bool zero, * instmem subdev implementation *****************************************************************************/ -static int -nv50_instmem_fini(struct nvkm_object *object, bool suspend) +static void +nv50_instmem_fini(struct nvkm_instmem *base) { - struct nv50_instmem *imem = (void *)object; - imem->addr = ~0ULL; - return nvkm_instmem_fini(&imem->base, suspend); + nv50_instmem(base)->addr = ~0ULL; } -static int -nv50_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_instmem_func +nv50_instmem = { + .fini = nv50_instmem_fini, + .memory_new = nv50_instobj_new, + .persistent = false, + .zero = false, +}; + +int +nv50_instmem_new(struct nvkm_device *device, int index, + struct nvkm_instmem **pimem) { struct nv50_instmem *imem; - int ret; - - ret = nvkm_instmem_create(parent, engine, oclass, &imem); - *pobject = nv_object(imem); - if (ret) - return ret; + if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) + return -ENOMEM; + nvkm_instmem_ctor(&nv50_instmem, device, index, &imem->base); spin_lock_init(&imem->lock); + *pimem = &imem->base; return 0; } - -struct nvkm_oclass * -nv50_instmem_oclass = &(struct nvkm_instmem_impl) { - .base.handle = NV_SUBDEV(INSTMEM, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_instmem_ctor, - .dtor = _nvkm_instmem_dtor, - .init = _nvkm_instmem_init, - .fini = nv50_instmem_fini, - }, - .memory_new = nv50_instobj_new, - .persistent = false, - .zero = false, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h index 2b6d73005767b..ace4471864a3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h @@ -1,31 +1,20 @@ #ifndef __NVKM_INSTMEM_PRIV_H__ #define __NVKM_INSTMEM_PRIV_H__ +#define nvkm_instmem(p) container_of((p), struct nvkm_instmem, subdev) #include -struct nvkm_instmem_impl { - struct nvkm_oclass base; +struct nvkm_instmem_func { + void *(*dtor)(struct nvkm_instmem *); + int (*oneinit)(struct nvkm_instmem *); + void (*fini)(struct nvkm_instmem *); + u32 (*rd32)(struct nvkm_instmem *, u32 addr); + void (*wr32)(struct nvkm_instmem *, u32 addr, u32 data); int (*memory_new)(struct nvkm_instmem *, u32 size, u32 align, bool zero, struct nvkm_memory **); bool persistent; bool zero; }; -#define nvkm_instmem_create(p,e,o,d) \ - nvkm_instmem_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_instmem_destroy(p) \ - nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_instmem_init(p) ({ \ - struct nvkm_instmem *_imem = (p); \ - _nvkm_instmem_init(nv_object(_imem)); \ -}) -#define nvkm_instmem_fini(p,s) ({ \ - struct nvkm_instmem *_imem = (p); \ - _nvkm_instmem_fini(nv_object(_imem), (s)); \ -}) - -int nvkm_instmem_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -#define _nvkm_instmem_dtor _nvkm_subdev_dtor -int _nvkm_instmem_init(struct nvkm_object *); -int _nvkm_instmem_fini(struct nvkm_object *, bool); +void nvkm_instmem_ctor(const struct nvkm_instmem_func *, struct nvkm_device *, + int index, struct nvkm_instmem *); #endif -- GitLab From 70bc7182cbf1bb07e414bbb553890ddf1b540264 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5541/7006] drm/nouveau/ltc: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/ltc.h | 35 ++--- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 42 +++--- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 10 +- .../gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/ltc/base.c | 126 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c | 124 +++++++---------- .../gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c | 34 ++--- .../gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c | 101 ++++++-------- .../gpu/drm/nouveau/nvkm/subdev/ltc/priv.h | 76 +++-------- .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 4 +- 13 files changed, 235 insertions(+), 342 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h index e8234e5b735cf..c773b5e958b4d 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h @@ -1,31 +1,36 @@ #ifndef __NVKM_LTC_H__ #define __NVKM_LTC_H__ #include -struct nvkm_mm_node; +#include #define NVKM_LTC_MAX_ZBC_CNT 16 struct nvkm_ltc { + const struct nvkm_ltc_func *func; struct nvkm_subdev subdev; - int (*tags_alloc)(struct nvkm_ltc *, u32 count, - struct nvkm_mm_node **); - void (*tags_free)(struct nvkm_ltc *, struct nvkm_mm_node **); - void (*tags_clear)(struct nvkm_ltc *, u32 first, u32 count); + u32 ltc_nr; + u32 lts_nr; + + u32 num_tags; + u32 tag_base; + struct nvkm_mm tags; + struct nvkm_mm_node *tag_ram; int zbc_min; int zbc_max; - int (*zbc_color_get)(struct nvkm_ltc *, int index, const u32[4]); - int (*zbc_depth_get)(struct nvkm_ltc *, int index, const u32); + u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4]; + u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; }; -static inline struct nvkm_ltc * -nvkm_ltc(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_LTC); -} +int nvkm_ltc_tags_alloc(struct nvkm_ltc *, u32 count, struct nvkm_mm_node **); +void nvkm_ltc_tags_free(struct nvkm_ltc *, struct nvkm_mm_node **); +void nvkm_ltc_tags_clear(struct nvkm_ltc *, u32 first, u32 count); + +int nvkm_ltc_zbc_color_get(struct nvkm_ltc *, int index, const u32[4]); +int nvkm_ltc_zbc_depth_get(struct nvkm_ltc *, int index, const u32); -extern struct nvkm_oclass *gf100_ltc_oclass; -extern struct nvkm_oclass *gk104_ltc_oclass; -extern struct nvkm_oclass *gm107_ltc_oclass; +int gf100_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); +int gk104_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); +int gm107_ltc_new(struct nvkm_device *, int, struct nvkm_ltc **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3b83f17b3a23f..d1ee594dff56f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1300,7 +1300,7 @@ nvc0_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1335,7 +1335,7 @@ nvc1_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1369,7 +1369,7 @@ nvc3_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1403,7 +1403,7 @@ nvc4_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1438,7 +1438,7 @@ nvc8_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1473,7 +1473,7 @@ nvce_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1508,7 +1508,7 @@ nvcf_chipset = { .i2c = g94_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1542,7 +1542,7 @@ nvd7_chipset = { .i2c = gf117_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1574,7 +1574,7 @@ nvd9_chipset = { .i2c = gf119_i2c_new, .ibus = gf100_ibus_new, .imem = nv50_instmem_new, -// .ltc = gf100_ltc_new, + .ltc = gf100_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1608,7 +1608,7 @@ nve4_chipset = { .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1644,7 +1644,7 @@ nve6_chipset = { .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1680,7 +1680,7 @@ nve7_chipset = { .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1712,7 +1712,7 @@ nvea_chipset = { .fuse = gf100_fuse_new, .ibus = gk20a_ibus_new, .imem = gk20a_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .pmu = gk20a_pmu_new, @@ -1740,7 +1740,7 @@ nvf0_chipset = { .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1776,7 +1776,7 @@ nvf1_chipset = { .i2c = gf119_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1812,7 +1812,7 @@ nv106_chipset = { .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1847,7 +1847,7 @@ nv108_chipset = { .i2c = gk104_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gk104_ltc_new, + .ltc = gk104_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1882,7 +1882,7 @@ nv117_chipset = { .i2c = gf119_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gm107_ltc_new, + .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1911,7 +1911,7 @@ nv124_chipset = { .i2c = gm204_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gm107_ltc_new, + .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1940,7 +1940,7 @@ nv126_chipset = { .i2c = gm204_i2c_new, .ibus = gk104_ibus_new, .imem = nv50_instmem_new, -// .ltc = gm107_ltc_new, + .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, @@ -1965,7 +1965,7 @@ nv12b_chipset = { .fuse = gm107_fuse_new, .ibus = gk20a_ibus_new, .imem = gk20a_instmem_new, -// .ltc = gm107_ltc_new, + .ltc = gm107_ltc_new, // .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mmu = gf100_mmu_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 8f9d871b545f3..e0b57ed658f5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -32,7 +32,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -53,7 +52,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -74,7 +72,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -94,7 +91,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -115,7 +111,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -135,7 +130,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -155,7 +149,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -176,7 +169,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -196,7 +188,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index dcb0f6db213d3..115931cfe18ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -32,7 +32,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -54,7 +53,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -76,7 +74,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -96,7 +93,6 @@ gk104_identify(struct nvkm_device *device) case 0xea: device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; @@ -112,7 +108,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -134,7 +129,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -156,7 +150,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -177,7 +170,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 158af1f8799e0..a3c87b26dd9fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -32,7 +32,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -64,7 +63,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -93,7 +91,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -118,7 +115,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 7917d141fcb0e..2f22af2fb533f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -58,7 +58,7 @@ static int gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, const u32 ds[4], const u32 l2[4]) { - struct nvkm_ltc *ltc = nvkm_ltc(gr); + struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { @@ -85,7 +85,7 @@ gf100_gr_zbc_color_get(struct gf100_gr *gr, int format, memcpy(gr->zbc_color[zbc].ds, ds, sizeof(gr->zbc_color[zbc].ds)); memcpy(gr->zbc_color[zbc].l2, l2, sizeof(gr->zbc_color[zbc].l2)); gr->zbc_color[zbc].format = format; - ltc->zbc_color_get(ltc, zbc, l2); + nvkm_ltc_zbc_color_get(ltc, zbc, l2); gf100_gr_zbc_clear_color(gr, zbc); return zbc; } @@ -105,7 +105,7 @@ static int gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, const u32 ds, const u32 l2) { - struct nvkm_ltc *ltc = nvkm_ltc(gr); + struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int zbc = -ENOSPC, i; for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { @@ -130,7 +130,7 @@ gf100_gr_zbc_depth_get(struct gf100_gr *gr, int format, gr->zbc_depth[zbc].format = format; gr->zbc_depth[zbc].ds = ds; gr->zbc_depth[zbc].l2 = l2; - ltc->zbc_depth_get(ltc, zbc, l2); + nvkm_ltc_zbc_depth_get(ltc, zbc, l2); gf100_gr_zbc_clear_depth(gr, zbc); return zbc; } @@ -680,7 +680,7 @@ gf100_gr_zbc_init(struct gf100_gr *gr) 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 }; - struct nvkm_ltc *ltc = nvkm_ltc(gr); + struct nvkm_ltc *ltc = gr->base.engine.subdev.device->ltc; int index; if (!gr->zbc_color[0].format) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c index 71902b64ffbc6..772425ca5a9ea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c @@ -434,7 +434,7 @@ gf100_ram_put(struct nvkm_ram *ram, struct nvkm_mem **pmem) mutex_lock(&ram->fb->subdev.mutex); if (mem->tag) - ltc->tags_free(ltc, &mem->tag); + nvkm_ltc_tags_free(ltc, &mem->tag); __nv50_ram_put(ram, mem); mutex_unlock(&ram->fb->subdev.mutex); @@ -472,7 +472,7 @@ gf100_ram_get(struct nvkm_ram *ram, u64 size, u32 align, u32 ncmin, /* compression only works with lpages */ if (align == (1 << (17 - NVKM_RAM_MM_SHIFT))) { int n = size >> 5; - ltc->tags_alloc(ltc, n, &mem->tag); + nvkm_ltc_tags_alloc(ltc, n, &mem->tag); } if (unlikely(!mem->tag)) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c index d0af1aec0fc6a..930d25b6e63cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c @@ -23,102 +23,110 @@ */ #include "priv.h" -static int -nvkm_ltc_tags_alloc(struct nvkm_ltc *obj, u32 n, struct nvkm_mm_node **pnode) -{ - struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); - int ret; +#include - ret = nvkm_mm_head(<c->tags, 0, 1, n, n, 1, pnode); +int +nvkm_ltc_tags_alloc(struct nvkm_ltc *ltc, u32 n, struct nvkm_mm_node **pnode) +{ + int ret = nvkm_mm_head(<c->tags, 0, 1, n, n, 1, pnode); if (ret) *pnode = NULL; - return ret; } -static void -nvkm_ltc_tags_free(struct nvkm_ltc *obj, struct nvkm_mm_node **pnode) +void +nvkm_ltc_tags_free(struct nvkm_ltc *ltc, struct nvkm_mm_node **pnode) { - struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); nvkm_mm_free(<c->tags, pnode); } -static void -nvkm_ltc_tags_clear(struct nvkm_ltc *obj, u32 first, u32 count) +void +nvkm_ltc_tags_clear(struct nvkm_ltc *ltc, u32 first, u32 count) { - struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); const u32 limit = first + count - 1; BUG_ON((first > limit) || (limit >= ltc->num_tags)); - impl->cbc_clear(ltc, first, limit); - impl->cbc_wait(ltc); + ltc->func->cbc_clear(ltc, first, limit); + ltc->func->cbc_wait(ltc); } -static int -nvkm_ltc_zbc_color_get(struct nvkm_ltc *obj, int index, const u32 color[4]) +int +nvkm_ltc_zbc_color_get(struct nvkm_ltc *ltc, int index, const u32 color[4]) { - struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); memcpy(ltc->zbc_color[index], color, sizeof(ltc->zbc_color[index])); - impl->zbc_clear_color(ltc, index, color); + ltc->func->zbc_clear_color(ltc, index, color); return index; } -static int -nvkm_ltc_zbc_depth_get(struct nvkm_ltc *obj, int index, const u32 depth) +int +nvkm_ltc_zbc_depth_get(struct nvkm_ltc *ltc, int index, const u32 depth) { - struct nvkm_ltc_priv *ltc = container_of(obj, typeof(*ltc), base); - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc); ltc->zbc_depth[index] = depth; - impl->zbc_clear_depth(ltc, index, depth); + ltc->func->zbc_clear_depth(ltc, index, depth); return index; } -int -_nvkm_ltc_init(struct nvkm_object *object) +static void +nvkm_ltc_intr(struct nvkm_subdev *subdev) { - struct nvkm_ltc_priv *ltc = (void *)object; - const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object); - int ret, i; + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + ltc->func->intr(ltc); +} - ret = nvkm_subdev_init_old(<c->base.subdev); - if (ret) - return ret; +static int +nvkm_ltc_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + return ltc->func->oneinit(ltc); +} + +static int +nvkm_ltc_init(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + int i; - for (i = ltc->base.zbc_min; i <= ltc->base.zbc_max; i++) { - impl->zbc_clear_color(ltc, i, ltc->zbc_color[i]); - impl->zbc_clear_depth(ltc, i, ltc->zbc_depth[i]); + for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) { + ltc->func->zbc_clear_color(ltc, i, ltc->zbc_color[i]); + ltc->func->zbc_clear_depth(ltc, i, ltc->zbc_depth[i]); } + ltc->func->init(ltc); return 0; } +static void * +nvkm_ltc_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_ltc *ltc = nvkm_ltc(subdev); + struct nvkm_ram *ram = ltc->subdev.device->fb->ram; + nvkm_mm_fini(<c->tags); + if (ram) + nvkm_mm_free(&ram->vram, <c->tag_ram); + return ltc; +} + +static const struct nvkm_subdev_func +nvkm_ltc = { + .dtor = nvkm_ltc_dtor, + .oneinit = nvkm_ltc_oneinit, + .init = nvkm_ltc_init, + .intr = nvkm_ltc_intr, +}; + int -nvkm_ltc_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_ltc_new_(const struct nvkm_ltc_func *func, struct nvkm_device *device, + int index, struct nvkm_ltc **pltc) { - const struct nvkm_ltc_impl *impl = (void *)oclass; - struct nvkm_ltc_priv *ltc; - int ret; + struct nvkm_ltc *ltc; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PLTCG", - "l2c", length, pobject); - ltc = *pobject; - if (ret) - return ret; - - memset(ltc->zbc_color, 0x00, sizeof(ltc->zbc_color)); - memset(ltc->zbc_depth, 0x00, sizeof(ltc->zbc_depth)); - - ltc->base.subdev.intr = impl->intr; - ltc->base.tags_alloc = nvkm_ltc_tags_alloc; - ltc->base.tags_free = nvkm_ltc_tags_free; - ltc->base.tags_clear = nvkm_ltc_tags_clear; - ltc->base.zbc_min = 1; /* reserve 0 for disabled */ - ltc->base.zbc_max = min(impl->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; - ltc->base.zbc_color_get = nvkm_ltc_zbc_color_get; - ltc->base.zbc_depth_get = nvkm_ltc_zbc_depth_get; + if (!(ltc = *pltc = kzalloc(sizeof(*ltc), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_ltc, device, index, 0, <c->subdev); + ltc->func = func; + ltc->zbc_min = 1; /* reserve 0 for disabled */ + ltc->zbc_max = min(func->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c index 5cb7604beeb60..45ac765b753ed 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c @@ -28,18 +28,18 @@ #include void -gf100_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) +gf100_ltc_cbc_clear(struct nvkm_ltc *ltc, u32 start, u32 limit) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; nvkm_wr32(device, 0x17e8cc, start); nvkm_wr32(device, 0x17e8d0, limit); nvkm_wr32(device, 0x17e8c8, 0x00000004); } void -gf100_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) +gf100_ltc_cbc_wait(struct nvkm_ltc *ltc) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; int c, s; for (c = 0; c < ltc->ltc_nr; c++) { for (s = 0; s < ltc->lts_nr; s++) { @@ -53,9 +53,9 @@ gf100_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) } void -gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) +gf100_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4]) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; nvkm_mask(device, 0x17ea44, 0x0000000f, i); nvkm_wr32(device, 0x17ea48, color[0]); nvkm_wr32(device, 0x17ea4c, color[1]); @@ -64,9 +64,9 @@ gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) } void -gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) +gf100_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; nvkm_mask(device, 0x17ea44, 0x0000000f, i); nvkm_wr32(device, 0x17ea58, depth); } @@ -90,9 +90,9 @@ gf100_ltc_lts_intr_name[] = { }; static void -gf100_ltc_lts_intr(struct nvkm_ltc_priv *ltc, int c, int s) +gf100_ltc_lts_intr(struct nvkm_ltc *ltc, int c, int s) { - struct nvkm_subdev *subdev = <c->base.subdev; + struct nvkm_subdev *subdev = <c->subdev; struct nvkm_device *device = subdev->device; u32 base = 0x141000 + (c * 0x2000) + (s * 0x400); u32 intr = nvkm_rd32(device, base + 0x020); @@ -108,10 +108,9 @@ gf100_ltc_lts_intr(struct nvkm_ltc_priv *ltc, int c, int s) } void -gf100_ltc_intr(struct nvkm_subdev *subdev) +gf100_ltc_intr(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *ltc = (void *)subdev; - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; u32 mask; mask = nvkm_rd32(device, 0x00017c); @@ -123,44 +122,12 @@ gf100_ltc_intr(struct nvkm_subdev *subdev) } } -static int -gf100_ltc_init(struct nvkm_object *object) -{ - struct nvkm_ltc_priv *ltc = (void *)object; - struct nvkm_device *device = ltc->base.subdev.device; - u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - int ret; - - ret = nvkm_ltc_init(ltc); - if (ret) - return ret; - - nvkm_mask(device, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ - nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); - nvkm_wr32(device, 0x17e8d4, ltc->tag_base); - nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); - return 0; -} - -void -gf100_ltc_dtor(struct nvkm_object *object) -{ - struct nvkm_ltc_priv *ltc = (void *)object; - struct nvkm_ram *ram = ltc->base.subdev.device->fb->ram; - - nvkm_mm_fini(<c->tags); - if (ram) - nvkm_mm_free(&ram->vram, <c->tag_ram); - - nvkm_ltc_destroy(ltc); -} - /* TODO: Figure out tag memory details and drop the over-cautious allocation. */ int -gf100_ltc_init_tag_ram(struct nvkm_ltc_priv *ltc) +gf100_ltc_oneinit_tag_ram(struct nvkm_ltc *ltc) { - struct nvkm_ram *ram = ltc->base.subdev.device->fb->ram; + struct nvkm_ram *ram = ltc->subdev.device->fb->ram; u32 tag_size, tag_margin, tag_align; int ret; @@ -205,54 +172,53 @@ gf100_ltc_init_tag_ram(struct nvkm_ltc_priv *ltc) } mm_init: - ret = nvkm_mm_init(<c->tags, 0, ltc->num_tags, 1); - return ret; + return nvkm_mm_init(<c->tags, 0, ltc->num_tags, 1); } int -gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_ltc_oneinit(struct nvkm_ltc *ltc) { - struct nvkm_device *device = (void *)parent; - struct nvkm_ltc_priv *ltc; - u32 parts, mask; - int ret, i; - - ret = nvkm_ltc_create(parent, engine, oclass, <c); - *pobject = nv_object(ltc); - if (ret) - return ret; + struct nvkm_device *device = ltc->subdev.device; + const u32 parts = nvkm_rd32(device, 0x022438); + const u32 mask = nvkm_rd32(device, 0x022554); + const u32 slice = nvkm_rd32(device, 0x17e8dc) >> 28; + int i; - parts = nvkm_rd32(device, 0x022438); - mask = nvkm_rd32(device, 0x022554); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) ltc->ltc_nr++; } - ltc->lts_nr = nvkm_rd32(device, 0x17e8dc) >> 28; + ltc->lts_nr = slice; + + return gf100_ltc_oneinit_tag_ram(ltc); +} - ret = gf100_ltc_init_tag_ram(ltc); - if (ret) - return ret; +static void +gf100_ltc_init(struct nvkm_ltc *ltc) +{ + struct nvkm_device *device = ltc->subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - nv_subdev(ltc)->intr = gf100_ltc_intr; - return 0; + nvkm_mask(device, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */ + nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); + nvkm_wr32(device, 0x17e8d4, ltc->tag_base); + nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); } -struct nvkm_oclass * -gf100_ltc_oclass = &(struct nvkm_ltc_impl) { - .base.handle = NV_SUBDEV(LTC, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ltc_ctor, - .dtor = gf100_ltc_dtor, - .init = gf100_ltc_init, - .fini = _nvkm_ltc_fini, - }, +static const struct nvkm_ltc_func +gf100_ltc = { + .oneinit = gf100_ltc_oneinit, + .init = gf100_ltc_init, .intr = gf100_ltc_intr, .cbc_clear = gf100_ltc_cbc_clear, .cbc_wait = gf100_ltc_cbc_wait, .zbc = 16, .zbc_clear_color = gf100_ltc_zbc_clear_color, .zbc_clear_depth = gf100_ltc_zbc_clear_depth, -}.base; +}; + +int +gf100_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gf100_ltc, device, index, pltc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c index a1f97d2ec36f1..839e6b4c597b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c @@ -23,38 +23,32 @@ */ #include "priv.h" -static int -gk104_ltc_init(struct nvkm_object *object) +static void +gk104_ltc_init(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *ltc = (void *)object; - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - int ret; - - ret = nvkm_ltc_init(ltc); - if (ret) - return ret; nvkm_wr32(device, 0x17e8d8, ltc->ltc_nr); nvkm_wr32(device, 0x17e000, ltc->ltc_nr); nvkm_wr32(device, 0x17e8d4, ltc->tag_base); nvkm_mask(device, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); - return 0; } -struct nvkm_oclass * -gk104_ltc_oclass = &(struct nvkm_ltc_impl) { - .base.handle = NV_SUBDEV(LTC, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ltc_ctor, - .dtor = gf100_ltc_dtor, - .init = gk104_ltc_init, - .fini = _nvkm_ltc_fini, - }, +static const struct nvkm_ltc_func +gk104_ltc = { + .oneinit = gf100_ltc_oneinit, + .init = gk104_ltc_init, .intr = gf100_ltc_intr, .cbc_clear = gf100_ltc_cbc_clear, .cbc_wait = gf100_ltc_cbc_wait, .zbc = 16, .zbc_clear_color = gf100_ltc_zbc_clear_color, .zbc_clear_depth = gf100_ltc_zbc_clear_depth, -}.base; +}; + +int +gk104_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gk104_ltc, device, index, pltc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c index 431acbef6bb7d..389331bb63bae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c @@ -27,18 +27,18 @@ #include static void -gm107_ltc_cbc_clear(struct nvkm_ltc_priv *ltc, u32 start, u32 limit) +gm107_ltc_cbc_clear(struct nvkm_ltc *ltc, u32 start, u32 limit) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; nvkm_wr32(device, 0x17e270, start); nvkm_wr32(device, 0x17e274, limit); nvkm_wr32(device, 0x17e26c, 0x00000004); } static void -gm107_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) +gm107_ltc_cbc_wait(struct nvkm_ltc *ltc) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; int c, s; for (c = 0; c < ltc->ltc_nr; c++) { for (s = 0; s < ltc->lts_nr; s++) { @@ -52,9 +52,9 @@ gm107_ltc_cbc_wait(struct nvkm_ltc_priv *ltc) } static void -gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) +gm107_ltc_zbc_clear_color(struct nvkm_ltc *ltc, int i, const u32 color[4]) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; nvkm_mask(device, 0x17e338, 0x0000000f, i); nvkm_wr32(device, 0x17e33c, color[0]); nvkm_wr32(device, 0x17e340, color[1]); @@ -63,17 +63,17 @@ gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *ltc, int i, const u32 color[4]) } static void -gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *ltc, int i, const u32 depth) +gm107_ltc_zbc_clear_depth(struct nvkm_ltc *ltc, int i, const u32 depth) { - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; nvkm_mask(device, 0x17e338, 0x0000000f, i); nvkm_wr32(device, 0x17e34c, depth); } static void -gm107_ltc_lts_isr(struct nvkm_ltc_priv *ltc, int c, int s) +gm107_ltc_lts_isr(struct nvkm_ltc *ltc, int c, int s) { - struct nvkm_subdev *subdev = <c->base.subdev; + struct nvkm_subdev *subdev = <c->subdev; struct nvkm_device *device = subdev->device; u32 base = 0x140000 + (c * 0x2000) + (s * 0x400); u32 stat = nvkm_rd32(device, base + 0x00c); @@ -85,10 +85,9 @@ gm107_ltc_lts_isr(struct nvkm_ltc_priv *ltc, int c, int s) } static void -gm107_ltc_intr(struct nvkm_subdev *subdev) +gm107_ltc_intr(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *ltc = (void *)subdev; - struct nvkm_device *device = ltc->base.subdev.device; + struct nvkm_device *device = ltc->subdev.device; u32 mask; mask = nvkm_rd32(device, 0x00017c); @@ -101,66 +100,48 @@ gm107_ltc_intr(struct nvkm_subdev *subdev) } static int -gm107_ltc_init(struct nvkm_object *object) +gm107_ltc_oneinit(struct nvkm_ltc *ltc) { - struct nvkm_ltc_priv *ltc = (void *)object; - struct nvkm_device *device = ltc->base.subdev.device; - u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - int ret; - - ret = nvkm_ltc_init(ltc); - if (ret) - return ret; - - nvkm_wr32(device, 0x17e27c, ltc->ltc_nr); - nvkm_wr32(device, 0x17e278, ltc->tag_base); - nvkm_mask(device, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); - return 0; -} + struct nvkm_device *device = ltc->subdev.device; + const u32 parts = nvkm_rd32(device, 0x022438); + const u32 mask = nvkm_rd32(device, 0x021c14); + const u32 slice = nvkm_rd32(device, 0x17e280) >> 28; + int i; -static int -gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = (void *)parent; - struct nvkm_ltc_priv *ltc; - u32 parts, mask; - int ret, i; - - ret = nvkm_ltc_create(parent, engine, oclass, <c); - *pobject = nv_object(ltc); - if (ret) - return ret; - - parts = nvkm_rd32(device, 0x022438); - mask = nvkm_rd32(device, 0x021c14); for (i = 0; i < parts; i++) { if (!(mask & (1 << i))) ltc->ltc_nr++; } - ltc->lts_nr = nvkm_rd32(device, 0x17e280) >> 28; + ltc->lts_nr = slice; + + return gf100_ltc_oneinit_tag_ram(ltc); +} - ret = gf100_ltc_init_tag_ram(ltc); - if (ret) - return ret; +static void +gm107_ltc_init(struct nvkm_ltc *ltc) +{ + struct nvkm_device *device = ltc->subdev.device; + u32 lpg128 = !(nvkm_rd32(device, 0x100c80) & 0x00000001); - return 0; + nvkm_wr32(device, 0x17e27c, ltc->ltc_nr); + nvkm_wr32(device, 0x17e278, ltc->tag_base); + nvkm_mask(device, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000); } -struct nvkm_oclass * -gm107_ltc_oclass = &(struct nvkm_ltc_impl) { - .base.handle = NV_SUBDEV(LTC, 0xff), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_ltc_ctor, - .dtor = gf100_ltc_dtor, - .init = gm107_ltc_init, - .fini = _nvkm_ltc_fini, - }, +static const struct nvkm_ltc_func +gm107_ltc = { + .oneinit = gm107_ltc_oneinit, + .init = gm107_ltc_init, .intr = gm107_ltc_intr, .cbc_clear = gm107_ltc_cbc_clear, .cbc_wait = gm107_ltc_cbc_wait, .zbc = 16, .zbc_clear_color = gm107_ltc_zbc_clear_color, .zbc_clear_depth = gm107_ltc_zbc_clear_depth, -}.base; +}; + +int +gm107_ltc_new(struct nvkm_device *device, int index, struct nvkm_ltc **pltc) +{ + return nvkm_ltc_new_(&gm107_ltc, device, index, pltc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h index 0544288b0d1d0..4e05037cc99f9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h @@ -1,69 +1,29 @@ #ifndef __NVKM_LTC_PRIV_H__ #define __NVKM_LTC_PRIV_H__ +#define nvkm_ltc(p) container_of((p), struct nvkm_ltc, subdev) #include -#include -struct nvkm_fb; +int nvkm_ltc_new_(const struct nvkm_ltc_func *, struct nvkm_device *, + int index, struct nvkm_ltc **); -struct nvkm_ltc_priv { - struct nvkm_ltc base; - u32 ltc_nr; - u32 lts_nr; +struct nvkm_ltc_func { + int (*oneinit)(struct nvkm_ltc *); + void (*init)(struct nvkm_ltc *); + void (*intr)(struct nvkm_ltc *); - u32 num_tags; - u32 tag_base; - struct nvkm_mm tags; - struct nvkm_mm_node *tag_ram; - - u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4]; - u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT]; -}; - -#define nvkm_ltc_create(p,e,o,d) \ - nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_ltc_destroy(p) ({ \ - struct nvkm_ltc_priv *_priv = (p); \ - _nvkm_ltc_dtor(nv_object(_priv)); \ -}) -#define nvkm_ltc_init(p) ({ \ - struct nvkm_ltc_priv *_priv = (p); \ - _nvkm_ltc_init(nv_object(_priv)); \ -}) -#define nvkm_ltc_fini(p,s) ({ \ - struct nvkm_ltc_priv *_priv = (p); \ - _nvkm_ltc_fini(nv_object(_priv), (s)); \ -}) - -int nvkm_ltc_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); - -#define _nvkm_ltc_dtor _nvkm_subdev_dtor -int _nvkm_ltc_init(struct nvkm_object *); -#define _nvkm_ltc_fini _nvkm_subdev_fini - -int gf100_ltc_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gf100_ltc_dtor(struct nvkm_object *); -int gf100_ltc_init_tag_ram(struct nvkm_ltc_priv *); -int gf100_ltc_tags_alloc(struct nvkm_ltc *, u32, struct nvkm_mm_node **); -void gf100_ltc_tags_free(struct nvkm_ltc *, struct nvkm_mm_node **); - -struct nvkm_ltc_impl { - struct nvkm_oclass base; - void (*intr)(struct nvkm_subdev *); - - void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit); - void (*cbc_wait)(struct nvkm_ltc_priv *); + void (*cbc_clear)(struct nvkm_ltc *, u32 start, u32 limit); + void (*cbc_wait)(struct nvkm_ltc *); int zbc; - void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]); - void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32); + void (*zbc_clear_color)(struct nvkm_ltc *, int, const u32[4]); + void (*zbc_clear_depth)(struct nvkm_ltc *, int, const u32); }; -void gf100_ltc_intr(struct nvkm_subdev *); -void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32); -void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *); -void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]); -void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32); +int gf100_ltc_oneinit(struct nvkm_ltc *); +int gf100_ltc_oneinit_tag_ram(struct nvkm_ltc *); +void gf100_ltc_intr(struct nvkm_ltc *); +void gf100_ltc_cbc_clear(struct nvkm_ltc *, u32, u32); +void gf100_ltc_cbc_wait(struct nvkm_ltc *); +void gf100_ltc_zbc_clear_color(struct nvkm_ltc *, int, const u32[4]); +void gf100_ltc_zbc_clear_depth(struct nvkm_ltc *, int, const u32); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index e1374a01463a9..6a2a2d575f169 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -108,11 +108,11 @@ gf100_vm_map(struct nvkm_vma *vma, struct nvkm_memory *pgt, pte <<= 3; if (mem->tag) { - struct nvkm_ltc *ltc = nvkm_ltc(vma->vm->mmu); + struct nvkm_ltc *ltc = vma->vm->mmu->subdev.device->ltc; u32 tag = mem->tag->offset + (delta >> 17); phys |= (u64)tag << (32 + 12); next |= (u64)1 << (32 + 12); - ltc->tags_clear(ltc, tag, cnt); + nvkm_ltc_tags_clear(ltc, tag, cnt); } nvkm_kmap(pgt); -- GitLab From 54dcadd5b65e12f851ff80af4afef606040ad8b9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5542/7006] drm/nouveau/mc: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 31 ++-- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c | 4 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 8 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 83 +++++------ drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c | 22 +-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c | 22 +-- .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 22 +-- .../gpu/drm/nouveau/nvkm/subdev/mc/gf106.c | 22 +-- .../gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c | 22 +-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c | 42 ++---- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h | 16 -- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c | 22 +-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c | 29 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c | 22 +-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 28 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 35 ++--- 28 files changed, 265 insertions(+), 381 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index 726e3f02e3ec0..bafafa643e7f8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -3,26 +3,23 @@ #include struct nvkm_mc { + const struct nvkm_mc_func *func; struct nvkm_subdev subdev; - bool use_msi; + unsigned int irq; - void (*unk260)(struct nvkm_mc *, u32); + bool use_msi; }; -static inline struct nvkm_mc * -nvkm_mc(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MC); -} +void nvkm_mc_unk260(struct nvkm_mc *, u32 data); -extern struct nvkm_oclass *nv04_mc_oclass; -extern struct nvkm_oclass *nv40_mc_oclass; -extern struct nvkm_oclass *nv44_mc_oclass; -extern struct nvkm_oclass *nv4c_mc_oclass; -extern struct nvkm_oclass *nv50_mc_oclass; -extern struct nvkm_oclass *g94_mc_oclass; -extern struct nvkm_oclass *g98_mc_oclass; -extern struct nvkm_oclass *gf100_mc_oclass; -extern struct nvkm_oclass *gf106_mc_oclass; -extern struct nvkm_oclass *gk20a_mc_oclass; +int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int nv40_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int nv44_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int nv4c_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int nv50_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int g94_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int g98_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int gf100_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int gf106_mc_new(struct nvkm_device *, int, struct nvkm_mc **); +int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index d1ee594dff56f..96ac8804ce33a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -83,7 +83,7 @@ nv4_chipset = { .fb = nv04_fb_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -103,7 +103,7 @@ nv5_chipset = { .fb = nv04_fb_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -124,7 +124,7 @@ nv10_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -143,7 +143,7 @@ nv11_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -164,7 +164,7 @@ nv15_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -185,7 +185,7 @@ nv17_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -206,7 +206,7 @@ nv18_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -227,7 +227,7 @@ nv1a_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -248,7 +248,7 @@ nv1f_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -269,7 +269,7 @@ nv20_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -290,7 +290,7 @@ nv25_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -311,7 +311,7 @@ nv28_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -332,7 +332,7 @@ nv2a_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -353,7 +353,7 @@ nv30_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -374,7 +374,7 @@ nv31_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -396,7 +396,7 @@ nv34_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -418,7 +418,7 @@ nv35_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -439,7 +439,7 @@ nv36_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv04_instmem_new, -// .mc = nv04_mc_new, + .mc = nv04_mc_new, // .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, @@ -461,7 +461,7 @@ nv40_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv04_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -486,7 +486,7 @@ nv41_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -511,7 +511,7 @@ nv42_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -536,7 +536,7 @@ nv43_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -561,7 +561,7 @@ nv44_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv44_mc_new, + .mc = nv44_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -586,7 +586,7 @@ nv45_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv04_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -611,7 +611,7 @@ nv46_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv44_mc_new, + .mc = nv44_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -636,7 +636,7 @@ nv47_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -661,7 +661,7 @@ nv49_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -686,7 +686,7 @@ nv4a_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv44_mc_new, + .mc = nv44_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -711,7 +711,7 @@ nv4b_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv40_mc_new, + .mc = nv40_mc_new, // .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -736,7 +736,7 @@ nv4c_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv4c_mc_new, + .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -761,7 +761,7 @@ nv4e_chipset = { .gpio = nv10_gpio_new, .i2c = nv4e_i2c_new, .imem = nv40_instmem_new, -// .mc = nv4c_mc_new, + .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -788,7 +788,7 @@ nv50_chipset = { .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, .imem = nv50_instmem_new, -// .mc = nv50_mc_new, + .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = nv50_therm_new, @@ -814,7 +814,7 @@ nv63_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv4c_mc_new, + .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -839,7 +839,7 @@ nv67_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv4c_mc_new, + .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -864,7 +864,7 @@ nv68_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, -// .mc = nv4c_mc_new, + .mc = nv4c_mc_new, // .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, @@ -891,7 +891,7 @@ nv84_chipset = { .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, .imem = nv50_instmem_new, -// .mc = nv50_mc_new, + .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -922,7 +922,7 @@ nv86_chipset = { .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, .imem = nv50_instmem_new, -// .mc = nv50_mc_new, + .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -953,7 +953,7 @@ nv92_chipset = { .gpio = nv50_gpio_new, .i2c = nv50_i2c_new, .imem = nv50_instmem_new, -// .mc = nv50_mc_new, + .mc = nv50_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -984,7 +984,7 @@ nv94_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g94_mc_new, + .mc = g94_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -1013,7 +1013,7 @@ nv96_chipset = { // .therm = g84_therm_new, // .mxm = nv50_mxm_new, .devinit = g84_devinit_new, -// .mc = g94_mc_new, + .mc = g94_mc_new, .bus = g94_bus_new, // .timer = nv04_timer_new, .fb = g84_fb_new, @@ -1044,7 +1044,7 @@ nv98_chipset = { // .therm = g84_therm_new, // .mxm = nv50_mxm_new, .devinit = g98_devinit_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, .bus = g94_bus_new, // .timer = nv04_timer_new, .fb = g84_fb_new, @@ -1077,7 +1077,7 @@ nva0_chipset = { .gpio = g94_gpio_new, .i2c = nv50_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -1108,7 +1108,7 @@ nva3_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, @@ -1141,7 +1141,7 @@ nva5_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, @@ -1173,7 +1173,7 @@ nva8_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, @@ -1205,7 +1205,7 @@ nvaa_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -1236,7 +1236,7 @@ nvac_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, @@ -1267,7 +1267,7 @@ nvaf_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, -// .mc = g98_mc_new, + .mc = g98_mc_new, // .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, @@ -1301,7 +1301,7 @@ nvc0_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf100_mc_new, + .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1336,7 +1336,7 @@ nvc1_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1370,7 +1370,7 @@ nvc3_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1404,7 +1404,7 @@ nvc4_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf100_mc_new, + .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1439,7 +1439,7 @@ nvc8_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf100_mc_new, + .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1474,7 +1474,7 @@ nvce_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf100_mc_new, + .mc = gf100_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1509,7 +1509,7 @@ nvcf_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, @@ -1543,7 +1543,7 @@ nvd7_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .therm = gf110_therm_new, @@ -1575,7 +1575,7 @@ nvd9_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf110_pmu_new, @@ -1609,7 +1609,7 @@ nve4_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk104_pmu_new, @@ -1645,7 +1645,7 @@ nve6_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk104_pmu_new, @@ -1681,7 +1681,7 @@ nve7_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf110_pmu_new, @@ -1713,7 +1713,7 @@ nvea_chipset = { .ibus = gk20a_ibus_new, .imem = gk20a_instmem_new, .ltc = gk104_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .pmu = gk20a_pmu_new, // .timer = gk20a_timer_new, @@ -1741,7 +1741,7 @@ nvf0_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk110_pmu_new, @@ -1777,7 +1777,7 @@ nvf1_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gf106_mc_new, + .mc = gf106_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk110_pmu_new, @@ -1813,7 +1813,7 @@ nv106_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, @@ -1848,7 +1848,7 @@ nv108_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, @@ -1883,7 +1883,7 @@ nv117_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gm107_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, @@ -1912,7 +1912,7 @@ nv124_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gm107_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, @@ -1941,7 +1941,7 @@ nv126_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gm107_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, @@ -1966,7 +1966,7 @@ nv12b_chipset = { .ibus = gk20a_ibus_new, .imem = gk20a_instmem_new, .ltc = gm107_ltc_new, -// .mc = gk20a_mc_new, + .mc = gk20a_mc_new, // .mmu = gf100_mmu_new, // .mmu = gf100_mmu_new, // .timer = gk20a_timer_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index e0b57ed658f5a..c9f8589c410ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -30,7 +30,6 @@ gf100_identify(struct nvkm_device *device) case 0xc0: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -50,7 +49,6 @@ gf100_identify(struct nvkm_device *device) case 0xc4: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -70,7 +68,6 @@ gf100_identify(struct nvkm_device *device) case 0xc3: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -89,7 +86,6 @@ gf100_identify(struct nvkm_device *device) case 0xce: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -109,7 +105,6 @@ gf100_identify(struct nvkm_device *device) case 0xcf: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -128,7 +123,6 @@ gf100_identify(struct nvkm_device *device) case 0xc1: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -147,7 +141,6 @@ gf100_identify(struct nvkm_device *device) case 0xc8: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; @@ -167,7 +160,6 @@ gf100_identify(struct nvkm_device *device) case 0xd9: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; @@ -186,7 +178,6 @@ gf100_identify(struct nvkm_device *device) case 0xd7: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 115931cfe18ad..11a72fe235838 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -30,7 +30,6 @@ gk104_identify(struct nvkm_device *device) case 0xe4: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; @@ -51,7 +50,6 @@ gk104_identify(struct nvkm_device *device) case 0xe7: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; @@ -72,7 +70,6 @@ gk104_identify(struct nvkm_device *device) case 0xe6: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; @@ -91,7 +88,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -106,7 +102,6 @@ gk104_identify(struct nvkm_device *device) case 0xf0: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; @@ -127,7 +122,6 @@ gk104_identify(struct nvkm_device *device) case 0xf1: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; @@ -148,7 +142,6 @@ gk104_identify(struct nvkm_device *device) case 0x106: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -168,7 +161,6 @@ gk104_identify(struct nvkm_device *device) case 0x108: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index a3c87b26dd9fc..cc1209bdd30db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -30,7 +30,6 @@ gm100_identify(struct nvkm_device *device) case 0x117: device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -61,7 +60,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -89,7 +87,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -112,7 +109,6 @@ gm100_identify(struct nvkm_device *device) break; case 0x12b: - device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index dc90bad938697..19a7a3be7cd6b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,7 +28,6 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -38,7 +37,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index b1db20f4a15c1..a5b222095f590 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,7 +28,6 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -36,7 +35,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -46,7 +44,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -56,7 +53,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -66,7 +62,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -76,7 +71,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -86,7 +80,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -96,7 +89,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index f11b7d01f34a9..ad94aeb784b99 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,7 +28,6 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -38,7 +37,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -48,7 +46,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -58,7 +55,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 780dd1019666f..61ca82736ddaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,7 +28,6 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -38,7 +37,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -48,7 +46,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -59,7 +56,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -70,7 +66,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index a5d874a2c2972..05a259cf3a8b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -29,7 +29,6 @@ nv40_identify(struct nvkm_device *device) switch (device->chipset) { case 0x40: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -43,7 +42,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x41: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -57,7 +55,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x42: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -71,7 +68,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x43: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -85,7 +81,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x45: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -99,7 +94,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x47: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -113,7 +107,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x49: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -127,7 +120,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x4b: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -141,7 +133,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x44: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -155,7 +146,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x46: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -169,7 +159,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x4a: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -183,7 +172,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x4c: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -197,7 +185,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x4e: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -211,7 +198,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x63: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -225,7 +211,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x67: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -239,7 +224,6 @@ nv40_identify(struct nvkm_device *device) break; case 0x68: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 2507559e5894a..d72074f98d6f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -30,7 +30,6 @@ nv50_identify(struct nvkm_device *device) case 0x50: device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -45,7 +44,6 @@ nv50_identify(struct nvkm_device *device) case 0x84: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -63,7 +61,6 @@ nv50_identify(struct nvkm_device *device) case 0x86: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -81,7 +78,6 @@ nv50_identify(struct nvkm_device *device) case 0x92: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -99,7 +95,6 @@ nv50_identify(struct nvkm_device *device) case 0x94: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -117,7 +112,6 @@ nv50_identify(struct nvkm_device *device) case 0x96: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -135,7 +129,6 @@ nv50_identify(struct nvkm_device *device) case 0x98: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -153,7 +146,6 @@ nv50_identify(struct nvkm_device *device) case 0xa0: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -171,7 +163,6 @@ nv50_identify(struct nvkm_device *device) case 0xaa: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -189,7 +180,6 @@ nv50_identify(struct nvkm_device *device) case 0xac: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -207,7 +197,6 @@ nv50_identify(struct nvkm_device *device) case 0xa3: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; @@ -227,7 +216,6 @@ nv50_identify(struct nvkm_device *device) case 0xa5: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; @@ -246,7 +234,6 @@ nv50_identify(struct nvkm_device *device) case 0xa8: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; @@ -265,7 +252,6 @@ nv50_identify(struct nvkm_device *device) case 0xaf: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; - device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c index 96525b49e686d..56f392d3d4fdc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c @@ -1239,7 +1239,7 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) struct nvkm_device *device = gr->base.engine.subdev.device; const struct gf100_grctx_func *grctx = gr->func->grctx; - nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + nvkm_mc_unk260(device->mc, 0); gf100_gr_mmio(gr, grctx->hub); gf100_gr_mmio(gr, grctx->gpc); @@ -1263,7 +1263,7 @@ gf100_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, grctx->mthd); - nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); + nvkm_mc_unk260(device->mc, 1); } int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c index 6a3833b7cc4f7..b5b875928abad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c @@ -223,7 +223,7 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) const struct gf100_grctx_func *grctx = gr->func->grctx; int i; - nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + nvkm_mc_unk260(device->mc, 0); gf100_gr_mmio(gr, grctx->hub); gf100_gr_mmio(gr, grctx->gpc); @@ -250,7 +250,7 @@ gf117_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, grctx->mthd); - nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); + nvkm_mc_unk260(device->mc, 1); } const struct gf100_grctx_func diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c index 77110ea019ea3..a843e3689c3c4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c @@ -958,7 +958,7 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) const struct gf100_grctx_func *grctx = gr->func->grctx; int i; - nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + nvkm_mc_unk260(device->mc, 0); gf100_gr_mmio(gr, grctx->hub); gf100_gr_mmio(gr, grctx->gpc); @@ -988,7 +988,7 @@ gk104_grctx_generate_main(struct gf100_gr *gr, struct gf100_grctx *info) gf100_gr_icmd(gr, grctx->icmd); nvkm_wr32(device, 0x404154, 0x00000400); gf100_gr_mthd(gr, grctx->mthd); - nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); + nvkm_mc_unk260(device->mc, 1); nvkm_mask(device, 0x418800, 0x00200000, 0x00200000); nvkm_mask(device, 0x41be10, 0x00800000, 0x00800000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 2f22af2fb533f..8fd26fa03c2e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1339,12 +1339,12 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) if (gr->firmware) { /* load fuc microcode */ - nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + nvkm_mc_unk260(device->mc, 0); gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, &gr->fuc409d); gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad); - nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); + nvkm_mc_unk260(device->mc, 1); /* start both of them running */ nvkm_wr32(device, 0x409840, 0xffffffff); @@ -1439,7 +1439,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) } /* load HUB microcode */ - nvkm_mc(gr)->unk260(nvkm_mc(gr), 0); + nvkm_mc_unk260(device->mc, 0); nvkm_wr32(device, 0x4091c0, 0x01000000); for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) nvkm_wr32(device, 0x4091c4, oclass->fecs.ucode->data.data[i]); @@ -1462,7 +1462,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) nvkm_wr32(device, 0x41a188, i >> 6); nvkm_wr32(device, 0x41a184, oclass->gpccs.ucode->code.data[i]); } - nvkm_mc(gr)->unk260(nvkm_mc(gr), 1); + nvkm_mc_unk260(device->mc, 1); /* load register lists */ gf100_gr_init_csdata(gr, grctx->hub, 0x409000, 0x000, 0x000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index ee4c34f4b9c48..8d0f5aca3d539 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -25,12 +25,11 @@ #include -static inline void +void nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) { - const struct nvkm_mc_oclass *impl = (void *)nv_oclass(mc); - if (impl->unk260) - impl->unk260(mc, data); + if (mc->func->unk260) + mc->func->unk260(mc, data); } static inline u32 @@ -49,8 +48,7 @@ nvkm_mc_intr(int irq, void *arg) struct nvkm_mc *mc = arg; struct nvkm_subdev *subdev = &mc->subdev; struct nvkm_device *device = subdev->device; - const struct nvkm_mc_oclass *oclass = (void *)nv_object(mc)->oclass; - const struct nvkm_mc_intr *map = oclass->intr; + const struct nvkm_mc_intr *map = mc->func->intr; struct nvkm_subdev *unit; u32 intr; @@ -58,13 +56,13 @@ nvkm_mc_intr(int irq, void *arg) nvkm_rd32(device, 0x000140); intr = nvkm_mc_intr_mask(mc); if (mc->use_msi) - oclass->msi_rearm(mc); + mc->func->msi_rearm(mc); if (intr) { u32 stat = intr = nvkm_mc_intr_mask(mc); while (map->stat) { if (intr & map->stat) { - unit = nvkm_subdev(mc, map->unit); + unit = nvkm_device_subdev(device, map->unit); if (unit) nvkm_subdev_intr(unit); stat &= ~map->stat; @@ -80,54 +78,62 @@ nvkm_mc_intr(int irq, void *arg) return intr ? IRQ_HANDLED : IRQ_NONE; } -int -_nvkm_mc_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_mc *mc = (void *)object; - struct nvkm_device *device = mc->subdev.device; - nvkm_wr32(device, 0x000140, 0x00000000); - return nvkm_subdev_fini_old(&mc->subdev, suspend); + nvkm_wr32(subdev->device, 0x000140, 0x00000000); + return 0; } -int -_nvkm_mc_init(struct nvkm_object *object) +static int +nvkm_mc_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_mc *mc = nvkm_mc(subdev); + return request_irq(mc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", mc); +} + +static int +nvkm_mc_init(struct nvkm_subdev *subdev) { - struct nvkm_mc *mc = (void *)object; + struct nvkm_mc *mc = nvkm_mc(subdev); struct nvkm_device *device = mc->subdev.device; - int ret = nvkm_subdev_init_old(&mc->subdev); - if (ret) - return ret; + if (mc->func->init) + mc->func->init(mc); nvkm_wr32(device, 0x000140, 0x00000001); return 0; } -void -_nvkm_mc_dtor(struct nvkm_object *object) +static void * +nvkm_mc_dtor(struct nvkm_subdev *subdev) { - struct nvkm_mc *mc = (void *)object; + struct nvkm_mc *mc = nvkm_mc(subdev); struct nvkm_device *device = mc->subdev.device; free_irq(mc->irq, mc); if (mc->use_msi) pci_disable_msi(device->pdev); - nvkm_subdev_destroy(&mc->subdev); + return mc; } +static const struct nvkm_subdev_func +nvkm_mc = { + .dtor = nvkm_mc_dtor, + .oneinit = nvkm_mc_oneinit, + .init = nvkm_mc_init, + .fini = nvkm_mc_fini, +}; + int -nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *bclass, int length, void **pobject) +nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, + int index, struct nvkm_mc **pmc) { - const struct nvkm_mc_oclass *oclass = (void *)bclass; - struct nvkm_device *device = (void *)parent; struct nvkm_mc *mc; int ret; - ret = nvkm_subdev_create_(parent, engine, bclass, 0, "PMC", - "master", length, pobject); - mc = *pobject; - if (ret) - return ret; + if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL))) + return -ENOMEM; - mc->unk260 = nvkm_mc_unk260; + nvkm_subdev_ctor(&nvkm_mc, device, index, 0, &mc->subdev); + mc->func = func; if (nv_device_is_pci(device)) { switch (device->pdev->device & 0x0ff0) { @@ -149,11 +155,11 @@ nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, mc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI", mc->use_msi); - if (mc->use_msi && oclass->msi_rearm) { + if (mc->use_msi && mc->func->msi_rearm) { mc->use_msi = pci_enable_msi(device->pdev) == 0; if (mc->use_msi) { nvkm_debug(&mc->subdev, "MSI enabled\n"); - oclass->msi_rearm(mc); + mc->func->msi_rearm(mc); } } else { mc->use_msi = false; @@ -164,10 +170,5 @@ nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret < 0) return ret; mc->irq = ret; - - ret = request_irq(mc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", mc); - if (ret < 0) - return ret; - return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c index f042e7d8321d8..36720f25f952d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c @@ -21,17 +21,17 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -struct nvkm_oclass * -g94_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x94), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +g94_mc = { + .init = nv50_mc_init, .intr = nv50_mc_intr, .msi_rearm = nv40_mc_msi_rearm, -}.base; +}; + +int +g94_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&g94_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 8ab7f1272a143..44286a4bb356c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" static const struct nvkm_mc_intr g98_mc_intr[] = { @@ -44,15 +44,15 @@ g98_mc_intr[] = { {}, }; -struct nvkm_oclass * -g98_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x98), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +g98_mc = { + .init = nv50_mc_init, .intr = g98_mc_intr, .msi_rearm = nv40_mc_msi_rearm, -}.base; +}; + +int +g98_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&g98_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index f6989cc802c40..26f68d7e7ccc4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" const struct nvkm_mc_intr gf100_mc_intr[] = { @@ -60,16 +60,16 @@ gf100_mc_unk260(struct nvkm_mc *mc, u32 data) nvkm_wr32(mc->subdev.device, 0x000260, data); } -struct nvkm_oclass * -gf100_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +gf100_mc = { + .init = nv50_mc_init, .intr = gf100_mc_intr, .msi_rearm = gf100_mc_msi_rearm, .unk260 = gf100_mc_unk260, -}.base; +}; + +int +gf100_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&gf100_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c index 8d2a8f4577782..3515cff5ae48a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c @@ -21,18 +21,18 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -struct nvkm_oclass * -gf106_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0xc3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +gf106_mc = { + .init = nv50_mc_init, .intr = gf100_mc_intr, .msi_rearm = nv40_mc_msi_rearm, .unk260 = gf100_mc_unk260, -}.base; +}; + +int +gf106_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&gf106_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 43b27742956d2..aa812fe197509 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -21,17 +21,17 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -struct nvkm_oclass * -gk20a_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +gk20a_mc = { + .init = nv50_mc_init, .intr = gf100_mc_intr, .msi_rearm = nv40_mc_msi_rearm, -}.base; +}; + +int +gk20a_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&gk20a_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index 6e2fb94b6f848..bcba7bc9737b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" const struct nvkm_mc_intr nv04_mc_intr[] = { @@ -38,42 +38,22 @@ nv04_mc_intr[] = { {} }; -int -nv04_mc_init(struct nvkm_object *object) +void +nv04_mc_init(struct nvkm_mc *mc) { - struct nvkm_mc *mc = (void *)object; struct nvkm_device *device = mc->subdev.device; - nvkm_wr32(device, 0x000200, 0xffffffff); /* everything enabled */ nvkm_wr32(device, 0x001850, 0x00000001); /* disable rom access */ - - return nvkm_mc_init(mc); } +static const struct nvkm_mc_func +nv04_mc = { + .init = nv04_mc_init, + .intr = nv04_mc_intr, +}; + int -nv04_mc_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) { - struct nvkm_mc *mc; - int ret; - - ret = nvkm_mc_create(parent, engine, oclass, &mc); - *pobject = nv_object(mc); - if (ret) - return ret; - - return 0; + return nvkm_mc_new_(&nv04_mc, device, index, pmc); } - -struct nvkm_oclass * -nv04_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv04_mc_init, - .fini = _nvkm_mc_fini, - }, - .intr = nv04_mc_intr, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h deleted file mode 100644 index aa2e58fa69f0a..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __NVKM_MC_NV04_H__ -#define __NVKM_MC_NV04_H__ -#include "priv.h" - -int nv04_mc_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -extern const struct nvkm_mc_intr nv04_mc_intr[]; -int nv04_mc_init(struct nvkm_object *); -void nv40_mc_msi_rearm(struct nvkm_mc *); -int nv44_mc_init(struct nvkm_object *object); -int nv50_mc_init(struct nvkm_object *); -extern const struct nvkm_mc_intr nv50_mc_intr[]; -extern const struct nvkm_mc_intr gf100_mc_intr[]; -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c index 8b46ee26440df..1e75445f84de8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" void nv40_mc_msi_rearm(struct nvkm_mc *mc) @@ -29,15 +29,15 @@ nv40_mc_msi_rearm(struct nvkm_mc *mc) nvkm_wr08(mc->subdev.device, 0x088068, 0xff); } -struct nvkm_oclass * -nv40_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x40), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv04_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +nv40_mc = { + .init = nv04_mc_init, .intr = nv04_mc_intr, .msi_rearm = nv40_mc_msi_rearm, -}.base; +}; + +int +nv40_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv40_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 36b3caaa088e2..e6795d1aa60da 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -21,12 +21,11 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -int -nv44_mc_init(struct nvkm_object *object) +void +nv44_mc_init(struct nvkm_mc *mc) { - struct nvkm_mc *mc = (void *)object; struct nvkm_device *device = mc->subdev.device; u32 tmp = nvkm_rd32(device, 0x10020c); @@ -36,19 +35,17 @@ nv44_mc_init(struct nvkm_object *object) nvkm_wr32(device, 0x001704, 0); nvkm_wr32(device, 0x001708, 0); nvkm_wr32(device, 0x00170c, tmp); - - return nvkm_mc_init(mc); } -struct nvkm_oclass * -nv44_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x44), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv44_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +nv44_mc = { + .init = nv44_mc_init, .intr = nv04_mc_intr, .msi_rearm = nv40_mc_msi_rearm, -}.base; +}; + +int +nv44_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv44_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c index c0aac7e20d457..61ab2547af85d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c @@ -21,16 +21,16 @@ * * Authors: Ilia Mirkin */ -#include "nv04.h" +#include "priv.h" -struct nvkm_oclass * -nv4c_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x4c), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv44_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +nv4c_mc = { + .init = nv44_mc_init, .intr = nv04_mc_intr, -}.base; +}; + +int +nv4c_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv4c_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 4ef1c735a5425..b5a36c97e7718 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" const struct nvkm_mc_intr nv50_mc_intr[] = { @@ -48,24 +48,22 @@ nv50_mc_msi_rearm(struct nvkm_mc *mc) pci_write_config_byte(device->pdev, 0x68, 0xff); } -int -nv50_mc_init(struct nvkm_object *object) +void +nv50_mc_init(struct nvkm_mc *mc) { - struct nvkm_mc *mc = (void *)object; struct nvkm_device *device = mc->subdev.device; nvkm_wr32(device, 0x000200, 0xffffffff); /* everything on */ - return nvkm_mc_init(mc); } -struct nvkm_oclass * -nv50_mc_oclass = &(struct nvkm_mc_oclass) { - .base.handle = NV_SUBDEV(MC, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mc_ctor, - .dtor = _nvkm_mc_dtor, - .init = nv50_mc_init, - .fini = _nvkm_mc_fini, - }, +static const struct nvkm_mc_func +nv50_mc = { + .init = nv50_mc_init, .intr = nv50_mc_intr, .msi_rearm = nv50_mc_msi_rearm, -}.base; +}; + +int +nv50_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) +{ + return nvkm_mc_new_(&nv50_mc, device, index, pmc); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index d2cad07afd1a5..ca2249b189980 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -1,36 +1,33 @@ #ifndef __NVKM_MC_PRIV_H__ #define __NVKM_MC_PRIV_H__ +#define nvkm_mc(p) container_of((p), struct nvkm_mc, subdev) #include -#define nvkm_mc_create(p,e,o,d) \ - nvkm_mc_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_mc_destroy(p) ({ \ - struct nvkm_mc *pmc = (p); _nvkm_mc_dtor(nv_object(pmc)); \ -}) -#define nvkm_mc_init(p) ({ \ - struct nvkm_mc *pmc = (p); _nvkm_mc_init(nv_object(pmc)); \ -}) -#define nvkm_mc_fini(p,s) ({ \ - struct nvkm_mc *pmc = (p); _nvkm_mc_fini(nv_object(pmc), (s)); \ -}) - -int nvkm_mc_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_mc_dtor(struct nvkm_object *); -int _nvkm_mc_init(struct nvkm_object *); -int _nvkm_mc_fini(struct nvkm_object *, bool); +int nvkm_mc_new_(const struct nvkm_mc_func *, struct nvkm_device *, + int index, struct nvkm_mc **); struct nvkm_mc_intr { u32 stat; u32 unit; }; -struct nvkm_mc_oclass { - struct nvkm_oclass base; +struct nvkm_mc_func { + void (*init)(struct nvkm_mc *); const struct nvkm_mc_intr *intr; void (*msi_rearm)(struct nvkm_mc *); void (*unk260)(struct nvkm_mc *, u32); }; +void nv04_mc_init(struct nvkm_mc *); +extern const struct nvkm_mc_intr nv04_mc_intr[]; + +void nv40_mc_msi_rearm(struct nvkm_mc *); + +void nv44_mc_init(struct nvkm_mc *); + +void nv50_mc_init(struct nvkm_mc *); +extern const struct nvkm_mc_intr nv50_mc_intr[]; + +extern const struct nvkm_mc_intr gf100_mc_intr[]; void gf100_mc_unk260(struct nvkm_mc *, u32); #endif -- GitLab From c9582455ab74246ec9f5986db3821b33058de585 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5543/7006] drm/nouveau/mmu: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 71 ++------- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 140 ++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../drm/nouveau/nvkm/engine/dma/usernv04.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/base.c | 143 ++++++++++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 62 +++----- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 85 +++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h | 13 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 84 ++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 79 ++++------ .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 72 ++++----- .../gpu/drm/nouveau/nvkm/subdev/mmu/priv.h | 39 +++++ 21 files changed, 387 insertions(+), 478 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 66d1bc23f3d7e..383a47270f3e1 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -52,7 +52,7 @@ u64 nvif_device_time(struct nvif_device *); }) #define nvxx_bios(a) nvxx_device(a)->bios #define nvxx_fb(a) nvxx_device(a)->fb -#define nvxx_mmu(a) nvkm_mmu(nvxx_device(a)) +#define nvxx_mmu(a) nvxx_device(a)->mmu #define nvxx_bar(a) nvxx_device(a)->bar #define nvxx_gpio(a) nvxx_device(a)->gpio #define nvxx_clk(a) nvxx_device(a)->clk diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index ba4183cedf7ee..26c77aac4be4b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -39,62 +39,6 @@ struct nvkm_vm { u32 lpde; }; -struct nvkm_mmu { - struct nvkm_subdev subdev; - - u64 limit; - u8 dma_bits; - u32 pgt_bits; - u8 spg_shift; - u8 lpg_shift; - - int (*create)(struct nvkm_mmu *, u64 offset, u64 length, - u64 mm_offset, struct lock_class_key *, - struct nvkm_vm **); - - void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde, - struct nvkm_memory *pgt[2]); - void (*map)(struct nvkm_vma *, struct nvkm_memory *, - struct nvkm_mem *, u32 pte, u32 cnt, - u64 phys, u64 delta); - void (*map_sg)(struct nvkm_vma *, struct nvkm_memory *, - struct nvkm_mem *, u32 pte, u32 cnt, dma_addr_t *); - void (*unmap)(struct nvkm_vma *, struct nvkm_memory *pgt, - u32 pte, u32 cnt); - void (*flush)(struct nvkm_vm *); -}; - -static inline struct nvkm_mmu * -nvkm_mmu(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MMU); -} - -#define nvkm_mmu_create(p,e,o,i,f,d) \ - nvkm_subdev_create((p), (e), (o), 0, (i), (f), (d)) -#define nvkm_mmu_destroy(p) \ - nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_mmu_init(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_mmu_fini(p,s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) - -#define _nvkm_mmu_dtor _nvkm_subdev_dtor -#define _nvkm_mmu_init _nvkm_subdev_init -#define _nvkm_mmu_fini _nvkm_subdev_fini - -extern struct nvkm_oclass nv04_mmu_oclass; -extern struct nvkm_oclass nv41_mmu_oclass; -extern struct nvkm_oclass nv44_mmu_oclass; -extern struct nvkm_oclass nv50_mmu_oclass; -extern struct nvkm_oclass gf100_mmu_oclass; - -int nv04_vm_create(struct nvkm_mmu *, u64, u64, u64, struct lock_class_key *, - struct nvkm_vm **); -void nv04_mmu_dtor(struct nvkm_object *); - -int nvkm_vm_create(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset, - u32 block, struct lock_class_key *, struct nvkm_vm **); int nvkm_vm_new(struct nvkm_device *, u64 offset, u64 length, u64 mm_offset, struct lock_class_key *, struct nvkm_vm **); int nvkm_vm_ref(struct nvkm_vm *, struct nvkm_vm **, struct nvkm_gpuobj *pgd); @@ -106,4 +50,19 @@ void nvkm_vm_map(struct nvkm_vma *, struct nvkm_mem *); void nvkm_vm_map_at(struct nvkm_vma *, u64 offset, struct nvkm_mem *); void nvkm_vm_unmap(struct nvkm_vma *); void nvkm_vm_unmap_at(struct nvkm_vma *, u64 offset, u64 length); + +struct nvkm_mmu { + const struct nvkm_mmu_func *func; + struct nvkm_subdev subdev; + + u64 limit; + u8 dma_bits; + u8 lpg_shift; +}; + +int nv04_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **); +int nv41_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **); +int nv44_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **); +int nv50_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **); +int gf100_mmu_new(struct nvkm_device *, int, struct nvkm_mmu **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 96ac8804ce33a..7da5dc44baf47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -84,7 +84,7 @@ nv4_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -104,7 +104,7 @@ nv5_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -125,7 +125,7 @@ nv10_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -144,7 +144,7 @@ nv11_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -165,7 +165,7 @@ nv15_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -186,7 +186,7 @@ nv17_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -207,7 +207,7 @@ nv18_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -228,7 +228,7 @@ nv1a_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -249,7 +249,7 @@ nv1f_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -270,7 +270,7 @@ nv20_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -291,7 +291,7 @@ nv25_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -312,7 +312,7 @@ nv28_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -333,7 +333,7 @@ nv2a_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -354,7 +354,7 @@ nv30_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -375,7 +375,7 @@ nv31_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -397,7 +397,7 @@ nv34_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -419,7 +419,7 @@ nv35_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -440,7 +440,7 @@ nv36_chipset = { .i2c = nv04_i2c_new, .imem = nv04_instmem_new, .mc = nv04_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -462,7 +462,7 @@ nv40_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -487,7 +487,7 @@ nv41_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv41_mmu_new, + .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -512,7 +512,7 @@ nv42_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv41_mmu_new, + .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -537,7 +537,7 @@ nv43_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv41_mmu_new, + .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -562,7 +562,7 @@ nv44_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv44_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -587,7 +587,7 @@ nv45_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv04_mmu_new, + .mmu = nv04_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -612,7 +612,7 @@ nv46_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv44_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -637,7 +637,7 @@ nv47_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv41_mmu_new, + .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -662,7 +662,7 @@ nv49_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv41_mmu_new, + .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -687,7 +687,7 @@ nv4a_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv44_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -712,7 +712,7 @@ nv4b_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv40_mc_new, -// .mmu = nv41_mmu_new, + .mmu = nv41_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -737,7 +737,7 @@ nv4c_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv4c_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -762,7 +762,7 @@ nv4e_chipset = { .i2c = nv4e_i2c_new, .imem = nv40_instmem_new, .mc = nv4c_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -789,7 +789,7 @@ nv50_chipset = { .i2c = nv50_i2c_new, .imem = nv50_instmem_new, .mc = nv50_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = nv50_therm_new, // .timer = nv04_timer_new, @@ -815,7 +815,7 @@ nv63_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv4c_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -840,7 +840,7 @@ nv67_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv4c_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -865,7 +865,7 @@ nv68_chipset = { .i2c = nv04_i2c_new, .imem = nv40_instmem_new, .mc = nv4c_mc_new, -// .mmu = nv44_mmu_new, + .mmu = nv44_mmu_new, // .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -892,7 +892,7 @@ nv84_chipset = { .i2c = nv50_i2c_new, .imem = nv50_instmem_new, .mc = nv50_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -923,7 +923,7 @@ nv86_chipset = { .i2c = nv50_i2c_new, .imem = nv50_instmem_new, .mc = nv50_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -954,7 +954,7 @@ nv92_chipset = { .i2c = nv50_i2c_new, .imem = nv50_instmem_new, .mc = nv50_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -985,7 +985,7 @@ nv94_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g94_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -1018,7 +1018,7 @@ nv96_chipset = { // .timer = nv04_timer_new, .fb = g84_fb_new, .imem = nv50_instmem_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, .bar = g84_bar_new, // .volt = nv40_volt_new, // .dma = nv50_dma_new, @@ -1049,7 +1049,7 @@ nv98_chipset = { // .timer = nv04_timer_new, .fb = g84_fb_new, .imem = nv50_instmem_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, .bar = g84_bar_new, // .volt = nv40_volt_new, // .dma = nv50_dma_new, @@ -1078,7 +1078,7 @@ nva0_chipset = { .i2c = nv50_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -1109,7 +1109,7 @@ nva3_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, @@ -1142,7 +1142,7 @@ nva5_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, @@ -1174,7 +1174,7 @@ nva8_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, @@ -1206,7 +1206,7 @@ nvaa_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -1237,7 +1237,7 @@ nvac_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, @@ -1268,7 +1268,7 @@ nvaf_chipset = { .i2c = g94_i2c_new, .imem = nv50_instmem_new, .mc = g98_mc_new, -// .mmu = nv50_mmu_new, + .mmu = nv50_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, @@ -1302,7 +1302,7 @@ nvc0_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf100_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1337,7 +1337,7 @@ nvc1_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1371,7 +1371,7 @@ nvc3_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1405,7 +1405,7 @@ nvc4_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf100_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1440,7 +1440,7 @@ nvc8_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf100_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1475,7 +1475,7 @@ nvce_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf100_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1510,7 +1510,7 @@ nvcf_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, @@ -1544,7 +1544,7 @@ nvd7_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1576,7 +1576,7 @@ nvd9_chipset = { .imem = nv50_instmem_new, .ltc = gf100_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf110_pmu_new, // .therm = gf110_therm_new, @@ -1610,7 +1610,7 @@ nve4_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk104_pmu_new, // .therm = gf110_therm_new, @@ -1646,7 +1646,7 @@ nve6_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk104_pmu_new, // .therm = gf110_therm_new, @@ -1682,7 +1682,7 @@ nve7_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gf110_pmu_new, // .therm = gf110_therm_new, @@ -1714,7 +1714,7 @@ nvea_chipset = { .imem = gk20a_instmem_new, .ltc = gk104_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .pmu = gk20a_pmu_new, // .timer = gk20a_timer_new, // .volt = gk20a_volt_new, @@ -1742,7 +1742,7 @@ nvf0_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk110_pmu_new, // .therm = gf110_therm_new, @@ -1778,7 +1778,7 @@ nvf1_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gf106_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk110_pmu_new, // .therm = gf110_therm_new, @@ -1814,7 +1814,7 @@ nv106_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .therm = gf110_therm_new, @@ -1849,7 +1849,7 @@ nv108_chipset = { .imem = nv50_instmem_new, .ltc = gk104_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .therm = gf110_therm_new, @@ -1884,7 +1884,7 @@ nv117_chipset = { .imem = nv50_instmem_new, .ltc = gm107_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .therm = gm107_therm_new, @@ -1913,7 +1913,7 @@ nv124_chipset = { .imem = nv50_instmem_new, .ltc = gm107_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .timer = gk20a_timer_new, @@ -1942,7 +1942,7 @@ nv126_chipset = { .imem = nv50_instmem_new, .ltc = gm107_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .timer = gk20a_timer_new, @@ -1967,8 +1967,8 @@ nv12b_chipset = { .imem = gk20a_instmem_new, .ltc = gm107_ltc_new, .mc = gk20a_mc_new, -// .mmu = gf100_mmu_new, -// .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, + .mmu = gf100_mmu_new, // .timer = gk20a_timer_new, // .ce[2] = gm204_ce2_new, // .dma = gf119_dma_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index c9f8589c410ec..cf49c1d150e3d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -31,7 +31,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -50,7 +49,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -69,7 +67,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -87,7 +84,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -106,7 +102,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -124,7 +119,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -142,7 +136,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -161,7 +154,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -179,7 +171,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 11a72fe235838..df6aa5a98f5db 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -31,7 +31,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -51,7 +50,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -71,7 +69,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -89,7 +86,6 @@ gk104_identify(struct nvkm_device *device) break; case 0xea: device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -103,7 +99,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -123,7 +118,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -143,7 +137,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -162,7 +155,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index cc1209bdd30db..3076601d41121 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -31,7 +31,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -61,7 +60,6 @@ gm100_identify(struct nvkm_device *device) #endif device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -88,7 +86,6 @@ gm100_identify(struct nvkm_device *device) #endif device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -109,9 +106,7 @@ gm100_identify(struct nvkm_device *device) break; case 0x12b: - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 19a7a3be7cd6b..99e837f4879e0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -29,7 +29,6 @@ nv04_identify(struct nvkm_device *device) switch (device->chipset) { case 0x04: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; @@ -38,7 +37,6 @@ nv04_identify(struct nvkm_device *device) break; case 0x05: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index a5b222095f590..6f106f632e635 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -29,14 +29,12 @@ nv10_identify(struct nvkm_device *device) switch (device->chipset) { case 0x10: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -45,7 +43,6 @@ nv10_identify(struct nvkm_device *device) break; case 0x16: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -54,7 +51,6 @@ nv10_identify(struct nvkm_device *device) break; case 0x1a: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -63,7 +59,6 @@ nv10_identify(struct nvkm_device *device) break; case 0x11: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -72,7 +67,6 @@ nv10_identify(struct nvkm_device *device) break; case 0x17: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -81,7 +75,6 @@ nv10_identify(struct nvkm_device *device) break; case 0x1f: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -90,7 +83,6 @@ nv10_identify(struct nvkm_device *device) break; case 0x18: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index ad94aeb784b99..2a84c3ff85388 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -29,7 +29,6 @@ nv20_identify(struct nvkm_device *device) switch (device->chipset) { case 0x20: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -38,7 +37,6 @@ nv20_identify(struct nvkm_device *device) break; case 0x25: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -47,7 +45,6 @@ nv20_identify(struct nvkm_device *device) break; case 0x28: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -56,7 +53,6 @@ nv20_identify(struct nvkm_device *device) break; case 0x2a: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 61ca82736ddaf..b03249099bb5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -29,7 +29,6 @@ nv30_identify(struct nvkm_device *device) switch (device->chipset) { case 0x30: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -38,7 +37,6 @@ nv30_identify(struct nvkm_device *device) break; case 0x35: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -47,7 +45,6 @@ nv30_identify(struct nvkm_device *device) break; case 0x31: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -57,7 +54,6 @@ nv30_identify(struct nvkm_device *device) break; case 0x36: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -67,7 +63,6 @@ nv30_identify(struct nvkm_device *device) break; case 0x34: device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 05a259cf3a8b6..9af8044c16d2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -30,7 +30,6 @@ nv40_identify(struct nvkm_device *device) case 0x40: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -43,7 +42,6 @@ nv40_identify(struct nvkm_device *device) case 0x41: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -56,7 +54,6 @@ nv40_identify(struct nvkm_device *device) case 0x42: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -69,7 +66,6 @@ nv40_identify(struct nvkm_device *device) case 0x43: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -82,7 +78,6 @@ nv40_identify(struct nvkm_device *device) case 0x45: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -95,7 +90,6 @@ nv40_identify(struct nvkm_device *device) case 0x47: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -108,7 +102,6 @@ nv40_identify(struct nvkm_device *device) case 0x49: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -121,7 +114,6 @@ nv40_identify(struct nvkm_device *device) case 0x4b: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -134,7 +126,6 @@ nv40_identify(struct nvkm_device *device) case 0x44: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -147,7 +138,6 @@ nv40_identify(struct nvkm_device *device) case 0x46: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -160,7 +150,6 @@ nv40_identify(struct nvkm_device *device) case 0x4a: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -173,7 +162,6 @@ nv40_identify(struct nvkm_device *device) case 0x4c: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -186,7 +174,6 @@ nv40_identify(struct nvkm_device *device) case 0x4e: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -199,7 +186,6 @@ nv40_identify(struct nvkm_device *device) case 0x63: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -212,7 +198,6 @@ nv40_identify(struct nvkm_device *device) case 0x67: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -225,7 +210,6 @@ nv40_identify(struct nvkm_device *device) case 0x68: device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index d72074f98d6f1..23cbb0f39d84c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -31,7 +31,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; @@ -45,7 +44,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -62,7 +60,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -79,7 +76,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -96,7 +92,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -113,7 +108,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -130,7 +124,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -147,7 +140,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -164,7 +156,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -181,7 +172,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -198,7 +188,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -217,7 +206,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -235,7 +223,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -253,7 +240,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c index 2c2fb0988ed4b..c95942ef82167 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usernv04.c @@ -81,7 +81,7 @@ int nv04_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { - struct nv04_mmu *mmu = nv04_mmu(dma); + struct nvkm_device *device = dma->engine.subdev.device; struct nv04_dmaobj *dmaobj; int ret; @@ -95,7 +95,7 @@ nv04_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, return ret; if (dmaobj->base.target == NV_MEM_TARGET_VM) { - if (nv_object(mmu)->oclass == &nv04_mmu_oclass) + if (device->mmu->func == &nv04_mmu) dmaobj->clone = true; dmaobj->base.target = NV_MEM_TARGET_PCI; dmaobj->base.access = NV_MEM_ACCESS_RW; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c index 6fa1bdb02dfdb..e04a2296ecd0c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#include -#include +#include "priv.h" #include +#include void nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) @@ -32,12 +32,12 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; struct nvkm_mm_node *r; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); u32 end, len; delta = 0; @@ -53,7 +53,7 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) end = max; len = end - pte; - mmu->map(vma, pgt, node, pte, len, phys, delta); + mmu->func->map(vma, pgt, node, pte, len, phys, delta); num -= len; pte += len; @@ -67,7 +67,7 @@ nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node) } } - mmu->flush(vm); + mmu->func->flush(vm); } static void @@ -76,13 +76,13 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, { struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); unsigned m, sglen; u32 end, len; int i; @@ -100,7 +100,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, for (m = 0; m < len; m++) { dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - mmu->map_sg(vma, pgt, mem, pte, 1, &addr); + mmu->func->map_sg(vma, pgt, mem, pte, 1, &addr); num--; pte++; @@ -115,7 +115,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, for (; m < sglen; m++) { dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT); - mmu->map_sg(vma, pgt, mem, pte, 1, &addr); + mmu->func->map_sg(vma, pgt, mem, pte, 1, &addr); num--; pte++; if (num == 0) @@ -125,7 +125,7 @@ nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length, } finish: - mmu->flush(vm); + mmu->func->flush(vm); } static void @@ -135,13 +135,13 @@ nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length, struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; dma_addr_t *list = mem->pages; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); u32 end, len; while (num) { @@ -152,7 +152,7 @@ nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length, end = max; len = end - pte; - mmu->map_sg(vma, pgt, mem, pte, len, list); + mmu->func->map_sg(vma, pgt, mem, pte, len, list); num -= len; pte += len; @@ -163,7 +163,7 @@ nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length, } } - mmu->flush(vm); + mmu->func->flush(vm); } void @@ -183,13 +183,13 @@ nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length) { struct nvkm_vm *vm = vma->vm; struct nvkm_mmu *mmu = vm->mmu; - int big = vma->node->type != mmu->spg_shift; + int big = vma->node->type != mmu->func->spg_shift; u32 offset = vma->node->offset + (delta >> 12); u32 bits = vma->node->type - 12; u32 num = length >> vma->node->type; - u32 pde = (offset >> mmu->pgt_bits) - vm->fpde; - u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits; - u32 max = 1 << (mmu->pgt_bits - bits); + u32 pde = (offset >> mmu->func->pgt_bits) - vm->fpde; + u32 pte = (offset & ((1 << mmu->func->pgt_bits) - 1)) >> bits; + u32 max = 1 << (mmu->func->pgt_bits - bits); u32 end, len; while (num) { @@ -200,7 +200,7 @@ nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length) end = max; len = end - pte; - mmu->unmap(vma, pgt, pte, len); + mmu->func->unmap(vma, pgt, pte, len); num -= len; pte += len; @@ -210,7 +210,7 @@ nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length) } } - mmu->flush(vm); + mmu->func->flush(vm); } void @@ -237,7 +237,7 @@ nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde) vpgt->mem[big] = NULL; list_for_each_entry(vpgd, &vm->pgd_list, head) { - mmu->map_pgt(vpgd->obj, pde, vpgt->mem); + mmu->func->map_pgt(vpgd->obj, pde, vpgt->mem); } nvkm_memory_del(&pgt); @@ -250,11 +250,11 @@ nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type) struct nvkm_mmu *mmu = vm->mmu; struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; struct nvkm_vm_pgd *vpgd; - int big = (type != mmu->spg_shift); + int big = (type != mmu->func->spg_shift); u32 pgt_size; int ret; - pgt_size = (1 << (mmu->pgt_bits + 12)) >> type; + pgt_size = (1 << (mmu->func->pgt_bits + 12)) >> type; pgt_size *= 8; ret = nvkm_memory_new(mmu->subdev.device, NVKM_MEM_TARGET_INST, @@ -263,7 +263,7 @@ nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type) return ret; list_for_each_entry(vpgd, &vm->pgd_list, head) { - mmu->map_pgt(vpgd->obj, pde, vpgt->mem); + mmu->func->map_pgt(vpgd->obj, pde, vpgt->mem); } vpgt->refcount[big]++; @@ -288,12 +288,12 @@ nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access, return ret; } - fpde = (vma->node->offset >> mmu->pgt_bits); - lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits; + fpde = (vma->node->offset >> mmu->func->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> mmu->func->pgt_bits; for (pde = fpde; pde <= lpde; pde++) { struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde]; - int big = (vma->node->type != mmu->spg_shift); + int big = (vma->node->type != mmu->func->spg_shift); if (likely(vpgt->refcount[big])) { vpgt->refcount[big]++; @@ -330,11 +330,11 @@ nvkm_vm_put(struct nvkm_vma *vma) vm = vma->vm; mmu = vm->mmu; - fpde = (vma->node->offset >> mmu->pgt_bits); - lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits; + fpde = (vma->node->offset >> mmu->func->pgt_bits); + lpde = (vma->node->offset + vma->node->length - 1) >> mmu->func->pgt_bits; mutex_lock(&vm->mutex); - nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->spg_shift, fpde, lpde); + nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->func->spg_shift, fpde, lpde); nvkm_mm_free(&vm->mm, &vma->node); mutex_unlock(&vm->mutex); @@ -349,7 +349,7 @@ nvkm_vm_boot(struct nvkm_vm *vm, u64 size) int ret; ret = nvkm_memory_new(mmu->subdev.device, NVKM_MEM_TARGET_INST, - (size >> mmu->spg_shift) * 8, 0x1000, true, &pgt); + (size >> mmu->func->spg_shift) * 8, 0x1000, true, &pgt); if (ret == 0) { vm->pgt[0].refcount[0] = 1; vm->pgt[0].mem[0] = pgt; @@ -376,8 +376,8 @@ nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, INIT_LIST_HEAD(&vm->pgd_list); vm->mmu = mmu; kref_init(&vm->refcount); - vm->fpde = offset >> (mmu->pgt_bits + 12); - vm->lpde = (offset + length - 1) >> (mmu->pgt_bits + 12); + vm->fpde = offset >> (mmu->func->pgt_bits + 12); + vm->lpde = (offset + length - 1) >> (mmu->func->pgt_bits + 12); vm->pgt = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt)); if (!vm->pgt) { @@ -402,8 +402,10 @@ int nvkm_vm_new(struct nvkm_device *device, u64 offset, u64 length, u64 mm_offset, struct lock_class_key *key, struct nvkm_vm **pvm) { - struct nvkm_mmu *mmu = nvkm_mmu(device); - return mmu->create(mmu, offset, length, mm_offset, key, pvm); + struct nvkm_mmu *mmu = device->mmu; + if (!mmu->func->create) + return -EINVAL; + return mmu->func->create(mmu, offset, length, mm_offset, key, pvm); } static int @@ -424,7 +426,7 @@ nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd) mutex_lock(&vm->mutex); for (i = vm->fpde; i <= vm->lpde; i++) - mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].mem); + mmu->func->map_pgt(pgd, i, vm->pgt[i - vm->fpde].mem); list_add(&vpgd->head, &vm->pgd_list); mutex_unlock(&vm->mutex); return 0; @@ -483,3 +485,58 @@ nvkm_vm_ref(struct nvkm_vm *ref, struct nvkm_vm **ptr, struct nvkm_gpuobj *pgd) *ptr = ref; return 0; } + +static int +nvkm_mmu_oneinit(struct nvkm_subdev *subdev) +{ + struct nvkm_mmu *mmu = nvkm_mmu(subdev); + if (mmu->func->oneinit) + return mmu->func->oneinit(mmu); + return 0; +} + +static int +nvkm_mmu_init(struct nvkm_subdev *subdev) +{ + struct nvkm_mmu *mmu = nvkm_mmu(subdev); + if (mmu->func->init) + mmu->func->init(mmu); + return 0; +} + +static void * +nvkm_mmu_dtor(struct nvkm_subdev *subdev) +{ + struct nvkm_mmu *mmu = nvkm_mmu(subdev); + if (mmu->func->dtor) + return mmu->func->dtor(mmu); + return mmu; +} + +static const struct nvkm_subdev_func +nvkm_mmu = { + .dtor = nvkm_mmu_dtor, + .oneinit = nvkm_mmu_oneinit, + .init = nvkm_mmu_init, +}; + +void +nvkm_mmu_ctor(const struct nvkm_mmu_func *func, struct nvkm_device *device, + int index, struct nvkm_mmu *mmu) +{ + nvkm_subdev_ctor(&nvkm_mmu, device, index, 0, &mmu->subdev); + mmu->func = func; + mmu->limit = func->limit; + mmu->dma_bits = func->dma_bits; + mmu->lpg_shift = func->lpg_shift; +} + +int +nvkm_mmu_new_(const struct nvkm_mmu_func *func, struct nvkm_device *device, + int index, struct nvkm_mmu **pmmu) +{ + if (!(*pmmu = kzalloc(sizeof(**pmmu), GFP_KERNEL))) + return -ENOMEM; + nvkm_mmu_ctor(func, device, index, *pmmu); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 6a2a2d575f169..5f6c5df15a958 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" + #include #include #include @@ -160,7 +161,7 @@ gf100_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) static void gf100_vm_flush(struct nvkm_vm *vm) { - struct nvkm_mmu *mmu = (void *)vm->mmu; + struct nvkm_mmu *mmu = vm->mmu; struct nvkm_device *device = mmu->subdev.device; struct nvkm_vm_pgd *vpgd; u32 type; @@ -169,7 +170,7 @@ gf100_vm_flush(struct nvkm_vm *vm) if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&mmu->subdev.mutex); list_for_each_entry(vpgd, &vm->pgd_list, head) { /* looks like maybe a "free flush slots" counter, the * faster you write to 0x100cbc to more it decreases @@ -188,7 +189,7 @@ gf100_vm_flush(struct nvkm_vm *vm) break; ); } - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&mmu->subdev.mutex); } static int @@ -198,40 +199,23 @@ gf100_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, key, pvm); } -static int -gf100_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_mmu_func +gf100_mmu = { + .limit = (1ULL << 40), + .dma_bits = 40, + .pgt_bits = 27 - 12, + .spg_shift = 12, + .lpg_shift = 17, + .create = gf100_vm_create, + .map_pgt = gf100_vm_map_pgt, + .map = gf100_vm_map, + .map_sg = gf100_vm_map_sg, + .unmap = gf100_vm_unmap, + .flush = gf100_vm_flush, +}; + +int +gf100_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) { - struct nvkm_mmu *mmu; - int ret; - - ret = nvkm_mmu_create(parent, engine, oclass, "VM", "mmu", &mmu); - *pobject = nv_object(mmu); - if (ret) - return ret; - - mmu->limit = 1ULL << 40; - mmu->dma_bits = 40; - mmu->pgt_bits = 27 - 12; - mmu->spg_shift = 12; - mmu->lpg_shift = 17; - mmu->create = gf100_vm_create; - mmu->map_pgt = gf100_vm_map_pgt; - mmu->map = gf100_vm_map; - mmu->map_sg = gf100_vm_map_sg; - mmu->unmap = gf100_vm_unmap; - mmu->flush = gf100_vm_flush; - return 0; + return nvkm_mmu_new_(&gf100_mmu, device, index, pmmu); } - -struct nvkm_oclass -gf100_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_mmu_ctor, - .dtor = _nvkm_mmu_dtor, - .init = _nvkm_mmu_init, - .fini = _nvkm_mmu_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index 6995845ac6a1c..5def412f0467e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -68,47 +68,18 @@ nv04_vm_flush(struct nvkm_vm *vm) { } -/******************************************************************************* - * VM object - ******************************************************************************/ - -int -nv04_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mmstart, - struct lock_class_key *key, struct nvkm_vm **pvm) -{ - return -EINVAL; -} - /******************************************************************************* * MMU subdev ******************************************************************************/ static int -nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_mmu_oneinit(struct nvkm_mmu *base) { - struct nvkm_device *device = (void *)parent; - struct nv04_mmu *mmu; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; struct nvkm_memory *dma; int ret; - ret = nvkm_mmu_create(parent, engine, oclass, "PCIGART", - "mmu", &mmu); - *pobject = nv_object(mmu); - if (ret) - return ret; - - mmu->base.create = nv04_vm_create; - mmu->base.limit = NV04_PDMA_SIZE; - mmu->base.dma_bits = 32; - mmu->base.pgt_bits = 32 - 12; - mmu->base.spg_shift = 12; - mmu->base.lpg_shift = 12; - mmu->base.map_sg = nv04_vm_map_sg; - mmu->base.unmap = nv04_vm_unmap; - mmu->base.flush = nv04_vm_flush; - ret = nvkm_vm_create(&mmu->base, 0, NV04_PDMA_SIZE, 0, 4096, NULL, &mmu->vm); if (ret) @@ -129,28 +100,50 @@ nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } -void -nv04_mmu_dtor(struct nvkm_object *object) +void * +nv04_mmu_dtor(struct nvkm_mmu *base) { - struct nv04_mmu *mmu = (void *)object; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; if (mmu->vm) { nvkm_memory_del(&mmu->vm->pgt[0].mem[0]); nvkm_vm_ref(NULL, &mmu->vm, NULL); } if (mmu->nullp) { - pci_free_consistent(nv_device(mmu)->pdev, 16 * 1024, + pci_free_consistent(device->pdev, 16 * 1024, mmu->nullp, mmu->null); } - nvkm_mmu_destroy(&mmu->base); + return mmu; } -struct nvkm_oclass -nv04_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_mmu_ctor, - .dtor = nv04_mmu_dtor, - .init = _nvkm_mmu_init, - .fini = _nvkm_mmu_fini, - }, +int +nv04_mmu_new_(const struct nvkm_mmu_func *func, struct nvkm_device *device, + int index, struct nvkm_mmu **pmmu) +{ + struct nv04_mmu *mmu; + if (!(mmu = kzalloc(sizeof(*mmu), GFP_KERNEL))) + return -ENOMEM; + *pmmu = &mmu->base; + nvkm_mmu_ctor(func, device, index, &mmu->base); + return 0; +} + +const struct nvkm_mmu_func +nv04_mmu = { + .oneinit = nv04_mmu_oneinit, + .dtor = nv04_mmu_dtor, + .limit = NV04_PDMA_SIZE, + .dma_bits = 32, + .pgt_bits = 32 - 12, + .spg_shift = 12, + .lpg_shift = 12, + .map_sg = nv04_vm_map_sg, + .unmap = nv04_vm_unmap, + .flush = nv04_vm_flush, }; + +int +nv04_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) +{ + return nv04_mmu_new_(&nv04_mmu, device, index, pmmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h index 80a404eab441c..363e33b296d56 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h @@ -1,6 +1,7 @@ #ifndef __NV04_MMU_PRIV__ #define __NV04_MMU_PRIV__ -#include +#define nv04_mmu(p) container_of((p), struct nv04_mmu, base) +#include "priv.h" struct nv04_mmu { struct nvkm_mmu base; @@ -9,9 +10,9 @@ struct nv04_mmu { void *nullp; }; -static inline struct nv04_mmu * -nv04_mmu(void *obj) -{ - return (void *)nvkm_mmu(obj); -} +int nv04_mmu_new_(const struct nvkm_mmu_func *, struct nvkm_device *, + int index, struct nvkm_mmu **); +void *nv04_mmu_dtor(struct nvkm_mmu *); + +extern const struct nvkm_mmu_func nv04_mmu; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index 0f91d7aeb53f2..f30c3b890626c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -71,14 +71,14 @@ nv41_vm_flush(struct nvkm_vm *vm) struct nv04_mmu *mmu = nv04_mmu(vm->mmu); struct nvkm_device *device = mmu->base.subdev.device; - mutex_lock(&nv_subdev(mmu)->mutex); + mutex_lock(&mmu->base.subdev.mutex); nvkm_wr32(device, 0x100810, 0x00000022); nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x100810) & 0x00000020) break; ); nvkm_wr32(device, 0x100810, 0x00000000); - mutex_unlock(&nv_subdev(mmu)->mutex); + mutex_unlock(&mmu->base.subdev.mutex); } /******************************************************************************* @@ -86,36 +86,12 @@ nv41_vm_flush(struct nvkm_vm *vm) ******************************************************************************/ static int -nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv41_mmu_oneinit(struct nvkm_mmu *base) { - struct nvkm_device *device = nv_device(parent); - struct nv04_mmu *mmu; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; int ret; - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || - !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) { - return nvkm_object_old(parent, engine, &nv04_mmu_oclass, - data, size, pobject); - } - - ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART", - "mmu", &mmu); - *pobject = nv_object(mmu); - if (ret) - return ret; - - mmu->base.create = nv04_vm_create; - mmu->base.limit = NV41_GART_SIZE; - mmu->base.dma_bits = 39; - mmu->base.pgt_bits = 32 - 12; - mmu->base.spg_shift = 12; - mmu->base.lpg_shift = 12; - mmu->base.map_sg = nv41_vm_map_sg; - mmu->base.unmap = nv41_vm_unmap; - mmu->base.flush = nv41_vm_flush; - ret = nvkm_vm_create(&mmu->base, 0, NV41_GART_SIZE, 0, 4096, NULL, &mmu->vm); if (ret) @@ -125,37 +101,41 @@ nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16, true, &mmu->vm->pgt[0].mem[0]); mmu->vm->pgt[0].refcount[0] = 1; - if (ret) - return ret; - - return 0; + return ret; } -static int -nv41_mmu_init(struct nvkm_object *object) +static void +nv41_mmu_init(struct nvkm_mmu *base) { - struct nv04_mmu *mmu = (void *)object; + struct nv04_mmu *mmu = nv04_mmu(base); struct nvkm_device *device = mmu->base.subdev.device; struct nvkm_memory *dma = mmu->vm->pgt[0].mem[0]; - int ret; - - ret = nvkm_mmu_init(&mmu->base); - if (ret) - return ret; - nvkm_wr32(device, 0x100800, 0x00000002 | nvkm_memory_addr(dma)); nvkm_mask(device, 0x10008c, 0x00000100, 0x00000100); nvkm_wr32(device, 0x100820, 0x00000000); - return 0; } -struct nvkm_oclass -nv41_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x41), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv41_mmu_ctor, - .dtor = nv04_mmu_dtor, - .init = nv41_mmu_init, - .fini = _nvkm_mmu_fini, - }, +static const struct nvkm_mmu_func +nv41_mmu = { + .dtor = nv04_mmu_dtor, + .oneinit = nv41_mmu_oneinit, + .init = nv41_mmu_init, + .limit = NV41_GART_SIZE, + .dma_bits = 39, + .pgt_bits = 32 - 12, + .spg_shift = 12, + .lpg_shift = 12, + .map_sg = nv41_vm_map_sg, + .unmap = nv41_vm_unmap, + .flush = nv41_vm_flush, }; + +int +nv41_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) +{ + if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || + !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) + return nv04_mmu_new(device, index, pmmu); + + return nv04_mmu_new_(&nv41_mmu, device, index, pmmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index d2b586bc57a2a..7c37bd84b862d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -159,36 +159,12 @@ nv44_vm_flush(struct nvkm_vm *vm) ******************************************************************************/ static int -nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv44_mmu_oneinit(struct nvkm_mmu *base) { - struct nvkm_device *device = nv_device(parent); - struct nv04_mmu *mmu; + struct nv04_mmu *mmu = nv04_mmu(base); + struct nvkm_device *device = mmu->base.subdev.device; int ret; - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || - !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) { - return nvkm_object_old(parent, engine, &nv04_mmu_oclass, - data, size, pobject); - } - - ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART", - "mmu", &mmu); - *pobject = nv_object(mmu); - if (ret) - return ret; - - mmu->base.create = nv04_vm_create; - mmu->base.limit = NV44_GART_SIZE; - mmu->base.dma_bits = 39; - mmu->base.pgt_bits = 32 - 12; - mmu->base.spg_shift = 12; - mmu->base.lpg_shift = 12; - mmu->base.map_sg = nv44_vm_map_sg; - mmu->base.unmap = nv44_vm_unmap; - mmu->base.flush = nv44_vm_flush; - mmu->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &mmu->null); if (!mmu->nullp) { nvkm_warn(&mmu->base.subdev, "unable to allocate dummy pages\n"); @@ -205,24 +181,16 @@ nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, 512 * 1024, true, &mmu->vm->pgt[0].mem[0]); mmu->vm->pgt[0].refcount[0] = 1; - if (ret) - return ret; - - return 0; + return ret; } -static int -nv44_mmu_init(struct nvkm_object *object) +static void +nv44_mmu_init(struct nvkm_mmu *base) { - struct nv04_mmu *mmu = (void *)object; + struct nv04_mmu *mmu = nv04_mmu(base); struct nvkm_device *device = mmu->base.subdev.device; struct nvkm_memory *gart = mmu->vm->pgt[0].mem[0]; u32 addr; - int ret; - - ret = nvkm_mmu_init(&mmu->base); - if (ret) - return ret; /* calculate vram address of this PRAMIN block, object must be * allocated on 512KiB alignment, and not exceed a total size @@ -239,16 +207,29 @@ nv44_mmu_init(struct nvkm_object *object) nvkm_wr32(device, 0x100820, 0x00000000); nvkm_wr32(device, 0x10082c, 0x00000001); nvkm_wr32(device, 0x100800, addr | 0x00000010); - return 0; } -struct nvkm_oclass -nv44_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x44), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_mmu_ctor, - .dtor = nv04_mmu_dtor, - .init = nv44_mmu_init, - .fini = _nvkm_mmu_fini, - }, +static const struct nvkm_mmu_func +nv44_mmu = { + .dtor = nv04_mmu_dtor, + .oneinit = nv44_mmu_oneinit, + .init = nv44_mmu_init, + .limit = NV44_GART_SIZE, + .dma_bits = 39, + .pgt_bits = 32 - 12, + .spg_shift = 12, + .lpg_shift = 12, + .map_sg = nv44_vm_map_sg, + .unmap = nv44_vm_unmap, + .flush = nv44_vm_flush, }; + +int +nv44_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) +{ + if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || + !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) + return nv04_mmu_new(device, index, pmmu); + + return nv04_mmu_new_(&nv44_mmu, device, index, pmmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index f1f62a217e917..931f14094eb50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -21,7 +21,8 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" + #include #include @@ -155,10 +156,9 @@ nv50_vm_unmap(struct nvkm_vma *vma, struct nvkm_memory *pgt, u32 pte, u32 cnt) static void nv50_vm_flush(struct nvkm_vm *vm) { - struct nvkm_mmu *mmu = (void *)vm->mmu; + struct nvkm_mmu *mmu = vm->mmu; struct nvkm_subdev *subdev = &mmu->subdev; struct nvkm_device *device = subdev->device; - struct nvkm_engine *engine; int i, vme; mutex_lock(&subdev->mutex); @@ -167,10 +167,13 @@ nv50_vm_flush(struct nvkm_vm *vm) continue; /* unfortunate hw bug workaround... */ - engine = nvkm_engine(mmu, i); - if (engine && engine->tlb_flush) { - engine->tlb_flush(engine); - continue; + if (i == NVDEV_ENGINE_GR) { + struct nvkm_engine *engine = + nvkm_device_engine(device, i); + if (engine && engine->tlb_flush) { + engine->tlb_flush(engine); + continue; + } } switch (i) { @@ -203,47 +206,30 @@ static int nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset, struct lock_class_key *key, struct nvkm_vm **pvm) { - u32 block = (1 << (mmu->pgt_bits + 12)); + u32 block = (1 << (mmu->func->pgt_bits + 12)); if (block > length) block = length; return nvkm_vm_create(mmu, offset, length, mm_offset, block, key, pvm); } -static int -nv50_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_mmu_func +nv50_mmu = { + .limit = (1ULL << 40), + .dma_bits = 40, + .pgt_bits = 29 - 12, + .spg_shift = 12, + .lpg_shift = 16, + .create = nv50_vm_create, + .map_pgt = nv50_vm_map_pgt, + .map = nv50_vm_map, + .map_sg = nv50_vm_map_sg, + .unmap = nv50_vm_unmap, + .flush = nv50_vm_flush, +}; + +int +nv50_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) { - struct nvkm_mmu *mmu; - int ret; - - ret = nvkm_mmu_create(parent, engine, oclass, "VM", "mmu", &mmu); - *pobject = nv_object(mmu); - if (ret) - return ret; - - mmu->limit = 1ULL << 40; - mmu->dma_bits = 40; - mmu->pgt_bits = 29 - 12; - mmu->spg_shift = 12; - mmu->lpg_shift = 16; - mmu->create = nv50_vm_create; - mmu->map_pgt = nv50_vm_map_pgt; - mmu->map = nv50_vm_map; - mmu->map_sg = nv50_vm_map_sg; - mmu->unmap = nv50_vm_unmap; - mmu->flush = nv50_vm_flush; - return 0; + return nvkm_mmu_new_(&nv50_mmu, device, index, pmmu); } - -struct nvkm_oclass -nv50_mmu_oclass = { - .handle = NV_SUBDEV(MMU, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mmu_ctor, - .dtor = _nvkm_mmu_dtor, - .init = _nvkm_mmu_init, - .fini = _nvkm_mmu_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h new file mode 100644 index 0000000000000..27cedc60b507b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/priv.h @@ -0,0 +1,39 @@ +#ifndef __NVKM_MMU_PRIV_H__ +#define __NVKM_MMU_PRIV_H__ +#define nvkm_mmu(p) container_of((p), struct nvkm_mmu, subdev) +#include + +void nvkm_mmu_ctor(const struct nvkm_mmu_func *, struct nvkm_device *, + int index, struct nvkm_mmu *); +int nvkm_mmu_new_(const struct nvkm_mmu_func *, struct nvkm_device *, + int index, struct nvkm_mmu **); + +struct nvkm_mmu_func { + void *(*dtor)(struct nvkm_mmu *); + int (*oneinit)(struct nvkm_mmu *); + void (*init)(struct nvkm_mmu *); + + u64 limit; + u8 dma_bits; + u32 pgt_bits; + u8 spg_shift; + u8 lpg_shift; + + int (*create)(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset, + struct lock_class_key *, struct nvkm_vm **); + + void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde, + struct nvkm_memory *pgt[2]); + void (*map)(struct nvkm_vma *, struct nvkm_memory *, + struct nvkm_mem *, u32 pte, u32 cnt, + u64 phys, u64 delta); + void (*map_sg)(struct nvkm_vma *, struct nvkm_memory *, + struct nvkm_mem *, u32 pte, u32 cnt, dma_addr_t *); + void (*unmap)(struct nvkm_vma *, struct nvkm_memory *pgt, + u32 pte, u32 cnt); + void (*flush)(struct nvkm_vm *); +}; + +int nvkm_vm_create(struct nvkm_mmu *, u64, u64, u64, u32, + struct lock_class_key *, struct nvkm_vm **); +#endif -- GitLab From a4f7bd360893ab4f6bbc1ae4ef617c68bf987f3d Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5544/7006] drm/nouveau/mxm: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mxm.h | 30 +-------- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 66 +++++++++---------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 --- .../drm/nouveau/nvkm/engine/device/gk104.c | 7 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 ---- .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 18 ++--- .../gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c | 23 ++----- .../gpu/drm/nouveau/nvkm/subdev/mxm/priv.h | 15 +++++ 11 files changed, 66 insertions(+), 123 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h index 93f9a4ec23205..ed0250139dae5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h @@ -2,33 +2,5 @@ #define __NVKM_MXM_H__ #include -#define MXM_SANITISE_DCB 0x00000001 - -struct nvkm_mxm { - struct nvkm_subdev subdev; - u32 action; - u8 *mxms; -}; - -static inline struct nvkm_mxm * -nvkm_mxm(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MXM); -} - -#define nvkm_mxm_create(p,e,o,d) \ - nvkm_mxm_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_mxm_init(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_mxm_fini(p,s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) -int nvkm_mxm_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void nvkm_mxm_destroy(struct nvkm_mxm *); - -#define _nvkm_mxm_dtor _nvkm_subdev_dtor -#define _nvkm_mxm_init _nvkm_subdev_init -#define _nvkm_mxm_fini _nvkm_subdev_fini - -extern struct nvkm_oclass nv50_mxm_oclass; +int nv50_mxm_new(struct nvkm_device *, int, struct nvkm_subdev **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 7da5dc44baf47..350daa3c630ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -790,7 +790,7 @@ nv50_chipset = { .imem = nv50_instmem_new, .mc = nv50_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = nv50_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -893,7 +893,7 @@ nv84_chipset = { .imem = nv50_instmem_new, .mc = nv50_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -924,7 +924,7 @@ nv86_chipset = { .imem = nv50_instmem_new, .mc = nv50_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -955,7 +955,7 @@ nv92_chipset = { .imem = nv50_instmem_new, .mc = nv50_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -986,7 +986,7 @@ nv94_chipset = { .imem = nv50_instmem_new, .mc = g94_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1011,7 +1011,7 @@ nv96_chipset = { .fuse = nv50_fuse_new, .clk = g84_clk_new, // .therm = g84_therm_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, .devinit = g84_devinit_new, .mc = g94_mc_new, .bus = g94_bus_new, @@ -1042,7 +1042,7 @@ nv98_chipset = { .fuse = nv50_fuse_new, .clk = g84_clk_new, // .therm = g84_therm_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, .devinit = g98_devinit_new, .mc = g98_mc_new, .bus = g94_bus_new, @@ -1079,7 +1079,7 @@ nva0_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1110,7 +1110,7 @@ nva3_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1143,7 +1143,7 @@ nva5_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1175,7 +1175,7 @@ nva8_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1207,7 +1207,7 @@ nvaa_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1238,7 +1238,7 @@ nvac_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1269,7 +1269,7 @@ nvaf_chipset = { .imem = nv50_instmem_new, .mc = g98_mc_new, .mmu = nv50_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1303,7 +1303,7 @@ nvc0_chipset = { .ltc = gf100_ltc_new, .mc = gf100_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1338,7 +1338,7 @@ nvc1_chipset = { .ltc = gf100_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1372,7 +1372,7 @@ nvc3_chipset = { .ltc = gf100_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1406,7 +1406,7 @@ nvc4_chipset = { .ltc = gf100_ltc_new, .mc = gf100_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1441,7 +1441,7 @@ nvc8_chipset = { .ltc = gf100_ltc_new, .mc = gf100_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1476,7 +1476,7 @@ nvce_chipset = { .ltc = gf100_ltc_new, .mc = gf100_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1511,7 +1511,7 @@ nvcf_chipset = { .ltc = gf100_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, @@ -1545,7 +1545,7 @@ nvd7_chipset = { .ltc = gf100_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .ce[0] = gf100_ce0_new, @@ -1577,7 +1577,7 @@ nvd9_chipset = { .ltc = gf100_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf110_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1611,7 +1611,7 @@ nve4_chipset = { .ltc = gk104_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk104_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1647,7 +1647,7 @@ nve6_chipset = { .ltc = gk104_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk104_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1683,7 +1683,7 @@ nve7_chipset = { .ltc = gk104_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gf110_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1743,7 +1743,7 @@ nvf0_chipset = { .ltc = gk104_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk110_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1779,7 +1779,7 @@ nvf1_chipset = { .ltc = gk104_ltc_new, .mc = gf106_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk110_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1815,7 +1815,7 @@ nv106_chipset = { .ltc = gk104_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1850,7 +1850,7 @@ nv108_chipset = { .ltc = gk104_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, @@ -1885,7 +1885,7 @@ nv117_chipset = { .ltc = gm107_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .therm = gm107_therm_new, // .timer = gk20a_timer_new, @@ -1914,7 +1914,7 @@ nv124_chipset = { .ltc = gm107_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .timer = gk20a_timer_new, // .ce[0] = gm204_ce0_new, @@ -1943,7 +1943,7 @@ nv126_chipset = { .ltc = gm107_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, -// .mxm = nv50_mxm_new, + .mxm = nv50_mxm_new, // .pmu = gk208_pmu_new, // .timer = gk20a_timer_new, // .ce[0] = gm204_ce0_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index cf49c1d150e3d..ef161ef6be557 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -29,7 +29,6 @@ gf100_identify(struct nvkm_device *device) switch (device->chipset) { case 0xc0: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -47,7 +46,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xc4: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -65,7 +63,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xc3: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -82,7 +79,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xce: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -100,7 +96,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xcf: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -117,7 +112,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xc1: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -134,7 +128,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xc8: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -152,7 +145,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xd9: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -169,7 +161,6 @@ gf100_identify(struct nvkm_device *device) break; case 0xd7: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index df6aa5a98f5db..e649e38a11b5f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -29,7 +29,6 @@ gk104_identify(struct nvkm_device *device) switch (device->chipset) { case 0xe4: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -48,7 +47,6 @@ gk104_identify(struct nvkm_device *device) break; case 0xe7: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -67,7 +65,6 @@ gk104_identify(struct nvkm_device *device) break; case 0xe6: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -97,7 +94,6 @@ gk104_identify(struct nvkm_device *device) break; case 0xf0: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -116,7 +112,6 @@ gk104_identify(struct nvkm_device *device) break; case 0xf1: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -135,7 +130,6 @@ gk104_identify(struct nvkm_device *device) break; case 0x106: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -153,7 +147,6 @@ gk104_identify(struct nvkm_device *device) break; case 0x108: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 3076601d41121..e1dfea9764dea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -29,7 +29,6 @@ gm100_identify(struct nvkm_device *device) switch (device->chipset) { case 0x117: device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; @@ -58,7 +57,6 @@ gm100_identify(struct nvkm_device *device) /* priv ring says no to 0x10eb14 writes */ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 @@ -84,7 +82,6 @@ gm100_identify(struct nvkm_device *device) /* priv ring says no to 0x10eb14 writes */ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 23cbb0f39d84c..fad8e6819dcaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -29,7 +29,6 @@ nv50_identify(struct nvkm_device *device) switch (device->chipset) { case 0x50: device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -42,7 +41,6 @@ nv50_identify(struct nvkm_device *device) break; case 0x84: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -58,7 +56,6 @@ nv50_identify(struct nvkm_device *device) break; case 0x86: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -74,7 +71,6 @@ nv50_identify(struct nvkm_device *device) break; case 0x92: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -90,7 +86,6 @@ nv50_identify(struct nvkm_device *device) break; case 0x94: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -106,7 +101,6 @@ nv50_identify(struct nvkm_device *device) break; case 0x96: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -122,7 +116,6 @@ nv50_identify(struct nvkm_device *device) break; case 0x98: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -138,7 +131,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xa0: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -154,7 +146,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xaa: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -170,7 +161,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xac: device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -186,7 +176,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xa3: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -204,7 +193,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xa5: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -221,7 +209,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xa8: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -238,7 +225,6 @@ nv50_identify(struct nvkm_device *device) break; case 0xaf: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; - device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index ed380db94fb4d..442b5e200a778 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -226,22 +226,22 @@ mxm_shadow(struct nvkm_mxm *mxm, u8 version) return -ENOENT; } +static const struct nvkm_subdev_func +nvkm_mxm = { +}; + int -nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_mxm_new_(struct nvkm_device *device, int index, struct nvkm_mxm **pmxm) { - struct nvkm_device *device = (void *)parent; struct nvkm_bios *bios = device->bios; struct nvkm_mxm *mxm; u8 ver, len; u16 data; - int ret; - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm", - length, pobject); - mxm = *pobject; - if (ret) - return ret; + if (!(mxm = *pmxm = kzalloc(sizeof(*mxm), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_mxm, device, index, 0, &mxm->subdev); data = mxm_table(bios, &ver, &len); if (!data || !(ver = nvbios_rd08(bios, data))) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c index 1b3f5e32c7381..45a2f8e784f9f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c @@ -145,7 +145,7 @@ mxms_foreach(struct nvkm_mxm *mxm, u8 types, return false; } - if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) { + if (mxm->subdev.debug >= NV_DBG_DEBUG && (exec == NULL)) { static const char * mxms_desc[] = { "ODS", "SCCS", "TS", "IPS", "GSD", "VSS", "BCS", "FCS", diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h index 4ef804012d06e..333e0c01545a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h @@ -1,6 +1,6 @@ #ifndef __NVMXM_MXMS_H__ #define __NVMXM_MXMS_H__ -#include +#include "priv.h" struct mxms_odev { u8 outp_type; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c index 9167e6098d6a0..db14fad2ddfc9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c @@ -199,31 +199,20 @@ mxm_dcb_sanitise(struct nvkm_mxm *mxm) mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL); } -static int -nv50_mxm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_mxm_new(struct nvkm_device *device, int index, struct nvkm_subdev **pmxm) { struct nvkm_mxm *mxm; int ret; - ret = nvkm_mxm_create(parent, engine, oclass, &mxm); - *pobject = nv_object(mxm); + ret = nvkm_mxm_new_(device, index, &mxm); + if (mxm) + *pmxm = &mxm->subdev; if (ret) return ret; if (mxm->action & MXM_SANITISE_DCB) mxm_dcb_sanitise(mxm); + return 0; } - -struct nvkm_oclass -nv50_mxm_oclass = { - .handle = NV_SUBDEV(MXM, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mxm_ctor, - .dtor = _nvkm_mxm_dtor, - .init = _nvkm_mxm_init, - .fini = _nvkm_mxm_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h new file mode 100644 index 0000000000000..7d970157aed10 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/priv.h @@ -0,0 +1,15 @@ +#ifndef __NVKM_MXM_PRIV_H__ +#define __NVKM_MXM_PRIV_H__ +#define nvkm_mxm(p) container_of((p), struct nvkm_mxm, subdev) +#include + +#define MXM_SANITISE_DCB 0x00000001 + +struct nvkm_mxm { + struct nvkm_subdev subdev; + u32 action; + u8 *mxms; +}; + +int nvkm_mxm_new_(struct nvkm_device *, int index, struct nvkm_mxm **); +#endif -- GitLab From e2ca4e7d6e56cb73a068708f0b0c9bd62ab9e02c Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5545/7006] drm/nouveau/pmu: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/pmu.h | 29 +++---- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 46 +++++----- .../drm/nouveau/nvkm/engine/device/gf100.c | 8 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 4 - .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 9 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild | 3 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/base.c | 84 ++++++++----------- .../subdev/pmu/fuc/{gf110.fuc4 => gf119.fuc4} | 4 +- .../pmu/fuc/{gf110.fuc4.h => gf119.fuc4.h} | 4 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c | 19 ++--- .../nvkm/subdev/pmu/{gf110.c => gf119.c} | 29 ++++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 25 +++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c | 25 +++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c | 19 ++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 62 ++++++-------- .../gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c | 41 +++++++++ .../gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c | 26 +++--- .../gpu/drm/nouveau/nvkm/subdev/pmu/memx.c | 12 +-- .../gpu/drm/nouveau/nvkm/subdev/pmu/priv.h | 30 ++----- 21 files changed, 229 insertions(+), 261 deletions(-) rename drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/{gf110.fuc4 => gf119.fuc4} (97%) rename drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/{gf110.fuc4.h => gf119.fuc4.h} (99%) rename drivers/gpu/drm/nouveau/nvkm/subdev/pmu/{gf110.c => gf119.c} (73%) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h index 64b3a177bf88a..e61923d5e49cd 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h @@ -3,6 +3,7 @@ #include struct nvkm_pmu { + const struct nvkm_pmu_func *func; struct nvkm_subdev subdev; struct { @@ -20,24 +21,20 @@ struct nvkm_pmu { u32 message; u32 data[2]; } recv; - - int (*message)(struct nvkm_pmu *, u32[2], u32, u32, u32, u32); - void (*pgob)(struct nvkm_pmu *, bool); }; -static inline struct nvkm_pmu * -nvkm_pmu(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_PMU); -} - -extern struct nvkm_oclass *gt215_pmu_oclass; -extern struct nvkm_oclass *gf100_pmu_oclass; -extern struct nvkm_oclass *gf110_pmu_oclass; -extern struct nvkm_oclass *gk104_pmu_oclass; -extern struct nvkm_oclass *gk110_pmu_oclass; -extern struct nvkm_oclass *gk208_pmu_oclass; -extern struct nvkm_oclass *gk20a_pmu_oclass; +int nvkm_pmu_send(struct nvkm_pmu *, u32 reply[2], u32 process, + u32 message, u32 data0, u32 data1); +void nvkm_pmu_pgob(struct nvkm_pmu *, bool enable); + +int gt215_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gf100_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gf119_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gk104_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gk110_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gk208_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gk20a_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); +int gm107_pmu_new(struct nvkm_device *, int, struct nvkm_pmu **); /* interface to MEMX process running on PMU */ struct nvkm_memx; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 350daa3c630ce..8f201022377f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1111,7 +1111,7 @@ nva3_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gt215_pmu_new, + .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1144,7 +1144,7 @@ nva5_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gt215_pmu_new, + .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1176,7 +1176,7 @@ nva8_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gt215_pmu_new, + .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1270,7 +1270,7 @@ nvaf_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gt215_pmu_new, + .pmu = gt215_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1304,7 +1304,7 @@ nvc0_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1339,7 +1339,7 @@ nvc1_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1373,7 +1373,7 @@ nvc3_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1407,7 +1407,7 @@ nvc4_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1442,7 +1442,7 @@ nvc8_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1477,7 +1477,7 @@ nvce_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1512,7 +1512,7 @@ nvcf_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf100_pmu_new, + .pmu = gf100_pmu_new, // .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1578,7 +1578,7 @@ nvd9_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf110_pmu_new, + .pmu = gf119_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1612,7 +1612,7 @@ nve4_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk104_pmu_new, + .pmu = gk104_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1648,7 +1648,7 @@ nve6_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk104_pmu_new, + .pmu = gk104_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1684,7 +1684,7 @@ nve7_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gf110_pmu_new, + .pmu = gf119_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1715,7 +1715,7 @@ nvea_chipset = { .ltc = gk104_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, -// .pmu = gk20a_pmu_new, + .pmu = gk20a_pmu_new, // .timer = gk20a_timer_new, // .volt = gk20a_volt_new, // .ce[2] = gk104_ce2_new, @@ -1744,7 +1744,7 @@ nvf0_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk110_pmu_new, + .pmu = gk110_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1780,7 +1780,7 @@ nvf1_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk110_pmu_new, + .pmu = gk110_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1816,7 +1816,7 @@ nv106_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk208_pmu_new, + .pmu = gk208_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1851,7 +1851,7 @@ nv108_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk208_pmu_new, + .pmu = gk208_pmu_new, // .therm = gf110_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, @@ -1886,7 +1886,7 @@ nv117_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk208_pmu_new, + .pmu = gm107_pmu_new, // .therm = gm107_therm_new, // .timer = gk20a_timer_new, // .ce[0] = gk104_ce0_new, @@ -1915,7 +1915,7 @@ nv124_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk208_pmu_new, + .pmu = gm107_pmu_new, // .timer = gk20a_timer_new, // .ce[0] = gm204_ce0_new, // .ce[1] = gm204_ce1_new, @@ -1944,7 +1944,7 @@ nv126_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .pmu = gk208_pmu_new, + .pmu = gm107_pmu_new, // .timer = gk20a_timer_new, // .ce[0] = gm204_ce0_new, // .ce[1] = gm204_ce1_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index ef161ef6be557..556447727342a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -30,7 +30,6 @@ gf100_identify(struct nvkm_device *device) case 0xc0: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -47,7 +46,6 @@ gf100_identify(struct nvkm_device *device) case 0xc4: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -64,7 +62,6 @@ gf100_identify(struct nvkm_device *device) case 0xc3: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -80,7 +77,6 @@ gf100_identify(struct nvkm_device *device) case 0xce: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -97,7 +93,6 @@ gf100_identify(struct nvkm_device *device) case 0xcf: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -113,7 +108,6 @@ gf100_identify(struct nvkm_device *device) case 0xc1: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -129,7 +123,6 @@ gf100_identify(struct nvkm_device *device) case 0xc8: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -146,7 +139,6 @@ gf100_identify(struct nvkm_device *device) case 0xd9: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index e649e38a11b5f..9e05f8bbabc9a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -30,7 +30,6 @@ gk104_identify(struct nvkm_device *device) case 0xe4: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -48,7 +47,6 @@ gk104_identify(struct nvkm_device *device) case 0xe7: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -66,7 +64,6 @@ gk104_identify(struct nvkm_device *device) case 0xe6: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -90,12 +87,10 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass; break; case 0xf0: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -113,7 +108,6 @@ gk104_identify(struct nvkm_device *device) case 0xf1: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk110_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -131,7 +125,6 @@ gk104_identify(struct nvkm_device *device) case 0x106: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; @@ -148,7 +141,6 @@ gk104_identify(struct nvkm_device *device) case 0x108: device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index e1dfea9764dea..76c6b104a99af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -30,7 +30,6 @@ gm100_identify(struct nvkm_device *device) case 0x117: device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -58,7 +57,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif @@ -83,7 +81,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index fad8e6819dcaf..f2956d45d32ee 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -177,7 +177,6 @@ nv50_identify(struct nvkm_device *device) case 0xa3: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -194,7 +193,6 @@ nv50_identify(struct nvkm_device *device) case 0xa5: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -210,7 +208,6 @@ nv50_identify(struct nvkm_device *device) case 0xa8: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -226,7 +223,6 @@ nv50_identify(struct nvkm_device *device) case 0xaf: device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; - device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index 956e5926afe5d..efd5ebd1fa046 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -185,15 +185,13 @@ gk104_gr_init(struct nvkm_object *object) struct gf100_gr_oclass *oclass = (void *)object->oclass; struct gf100_gr *gr = (void *)object; struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_pmu *pmu = device->pmu; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; int ret, i; - if (pmu) - pmu->pgob(pmu, false); + nvkm_pmu_pgob(device->pmu, false); ret = nvkm_gr_init(&gr->base); if (ret) @@ -315,9 +313,8 @@ gk104_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_object **pobject) { - struct nvkm_pmu *pmu = nvkm_pmu(parent); - if (pmu) - pmu->pgob(pmu, false); + struct nvkm_device *device = (void *)parent; + nvkm_pmu_pgob(device->pmu, false); return gf100_gr_ctor(parent, engine, oclass, data, size, pobject); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild index 7081d6a9b95f6..88b643b8664e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild @@ -2,8 +2,9 @@ nvkm-y += nvkm/subdev/pmu/base.o nvkm-y += nvkm/subdev/pmu/memx.o nvkm-y += nvkm/subdev/pmu/gt215.o nvkm-y += nvkm/subdev/pmu/gf100.o -nvkm-y += nvkm/subdev/pmu/gf110.o +nvkm-y += nvkm/subdev/pmu/gf119.o nvkm-y += nvkm/subdev/pmu/gk104.o nvkm-y += nvkm/subdev/pmu/gk110.o nvkm-y += nvkm/subdev/pmu/gk208.o nvkm-y += nvkm/subdev/pmu/gk20a.o +nvkm-y += nvkm/subdev/pmu/gm107.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c index c700d3d956e81..27a79c0c38886 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c @@ -28,12 +28,11 @@ void nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable) { - const struct nvkm_pmu_impl *impl = (void *)nv_oclass(pmu); - if (impl->pgob) - impl->pgob(pmu, enable); + if (pmu->func->pgob) + pmu->func->pgob(pmu, enable); } -static int +int nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2], u32 process, u32 message, u32 data0, u32 data1) { @@ -144,7 +143,7 @@ nvkm_pmu_recv(struct work_struct *work) static void nvkm_pmu_intr(struct nvkm_subdev *subdev) { - struct nvkm_pmu *pmu = container_of(subdev, typeof(*pmu), subdev); + struct nvkm_pmu *pmu = nvkm_pmu(subdev); struct nvkm_device *device = pmu->subdev.device; u32 disp = nvkm_rd32(device, 0x10a01c); u32 intr = nvkm_rd32(device, 0x10a008) & disp & ~(disp >> 16); @@ -180,33 +179,23 @@ nvkm_pmu_intr(struct nvkm_subdev *subdev) } } -int -_nvkm_pmu_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_pmu *pmu = (void *)object; + struct nvkm_pmu *pmu = nvkm_pmu(subdev); struct nvkm_device *device = pmu->subdev.device; nvkm_wr32(device, 0x10a014, 0x00000060); flush_work(&pmu->recv.work); - - return nvkm_subdev_fini_old(&pmu->subdev, suspend); + return 0; } -int -_nvkm_pmu_init(struct nvkm_object *object) +static int +nvkm_pmu_init(struct nvkm_subdev *subdev) { - const struct nvkm_pmu_impl *impl = (void *)object->oclass; - struct nvkm_pmu *pmu = (void *)object; + struct nvkm_pmu *pmu = nvkm_pmu(subdev); struct nvkm_device *device = pmu->subdev.device; - int ret, i; - - ret = nvkm_subdev_init_old(&pmu->subdev); - if (ret) - return ret; - - nv_subdev(pmu)->intr = nvkm_pmu_intr; - pmu->message = nvkm_pmu_send; - pmu->pgob = nvkm_pmu_pgob; + int i; /* prevent previous ucode from running, wait for idle, reset */ nvkm_wr32(device, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */ @@ -224,15 +213,15 @@ _nvkm_pmu_init(struct nvkm_object *object) /* upload data segment */ nvkm_wr32(device, 0x10a1c0, 0x01000000); - for (i = 0; i < impl->data.size / 4; i++) - nvkm_wr32(device, 0x10a1c4, impl->data.data[i]); + for (i = 0; i < pmu->func->data.size / 4; i++) + nvkm_wr32(device, 0x10a1c4, pmu->func->data.data[i]); /* upload code segment */ nvkm_wr32(device, 0x10a180, 0x01000000); - for (i = 0; i < impl->code.size / 4; i++) { + for (i = 0; i < pmu->func->code.size / 4; i++) { if ((i & 0x3f) == 0) nvkm_wr32(device, 0x10a188, i >> 6); - nvkm_wr32(device, 0x10a184, impl->code.data[i]); + nvkm_wr32(device, 0x10a184, pmu->func->code.data[i]); } /* start it running */ @@ -262,31 +251,30 @@ _nvkm_pmu_init(struct nvkm_object *object) return 0; } -int -nvkm_pmu_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static void * +nvkm_pmu_dtor(struct nvkm_subdev *subdev) { - struct nvkm_pmu *pmu; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PMU", - "pmu", length, pobject); - pmu = *pobject; - if (ret) - return ret; - - INIT_WORK(&pmu->recv.work, nvkm_pmu_recv); - init_waitqueue_head(&pmu->recv.wait); - return 0; + return nvkm_pmu(subdev); } +static const struct nvkm_subdev_func +nvkm_pmu = { + .dtor = nvkm_pmu_dtor, + .init = nvkm_pmu_init, + .fini = nvkm_pmu_fini, + .intr = nvkm_pmu_intr, +}; + int -_nvkm_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_pmu_new_(const struct nvkm_pmu_func *func, struct nvkm_device *device, + int index, struct nvkm_pmu **ppmu) { struct nvkm_pmu *pmu; - int ret = nvkm_pmu_create(parent, engine, oclass, &pmu); - *pobject = nv_object(pmu); - return ret; + if (!(pmu = *ppmu = kzalloc(sizeof(*pmu), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_pmu, device, index, 0, &pmu->subdev); + pmu->func = func; + INIT_WORK(&pmu->recv.work, nvkm_pmu_recv); + init_waitqueue_head(&pmu->recv.wait); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4 similarity index 97% rename from drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4 index ae9c3f18ae010..2f28c7e26a14a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4 @@ -32,7 +32,7 @@ #include "macros.fuc" -.section #gf110_pmu_data +.section #gf119_pmu_data #define INCLUDE_PROC #include "kernel.fuc" #include "arith.fuc" @@ -56,7 +56,7 @@ #undef INCLUDE_DATA .align 256 -.section #gf110_pmu_code +.section #gf119_pmu_code #define INCLUDE_CODE #include "kernel.fuc" #include "arith.fuc" diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h similarity index 99% rename from drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h index a0c499e4543ce..31552af9b06e9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf119.fuc4.h @@ -1,4 +1,4 @@ -uint32_t gf110_pmu_data[] = { +uint32_t gf119_pmu_data[] = { /* 0x0000: proc_kern */ 0x52544e49, 0x00000000, @@ -915,7 +915,7 @@ uint32_t gf110_pmu_data[] = { 0x00000000, }; -uint32_t gf110_pmu_code[] = { +uint32_t gf119_pmu_code[] = { 0x034d0ef5, /* 0x0004: rd32 */ 0x07a007f1, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c index 78a4ea0101f15..aeb8ccd891fc5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c @@ -24,17 +24,16 @@ #include "priv.h" #include "fuc/gf100.fuc3.h" -struct nvkm_oclass * -gf100_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gf100_pmu = { .code.data = gf100_pmu_code, .code.size = sizeof(gf100_pmu_code), .data.data = gf100_pmu_data, .data.size = sizeof(gf100_pmu_data), -}.base; +}; + +int +gf100_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gf100_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c similarity index 73% rename from drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c rename to drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c index 6b3a23839ff0b..fbc88d8ecd4d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf119.c @@ -22,19 +22,18 @@ * Authors: Ben Skeggs */ #include "priv.h" -#include "fuc/gf110.fuc4.h" +#include "fuc/gf119.fuc4.h" -struct nvkm_oclass * -gf110_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, - .code.data = gf110_pmu_code, - .code.size = sizeof(gf110_pmu_code), - .data.data = gf110_pmu_data, - .data.size = sizeof(gf110_pmu_data), -}.base; +static const struct nvkm_pmu_func +gf119_pmu = { + .code.data = gf119_pmu_code, + .code.size = sizeof(gf119_pmu_code), + .data.data = gf119_pmu_data, + .data.size = sizeof(gf119_pmu_data), +}; + +int +gf119_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gf119_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index bea2833142402..584299737658e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#define gf110_pmu_code gk104_pmu_code -#define gf110_pmu_data gk104_pmu_data +#define gf119_pmu_code gk104_pmu_code +#define gf119_pmu_data gk104_pmu_data #include "priv.h" -#include "fuc/gf110.fuc4.h" +#include "fuc/gf119.fuc4.h" #include #include @@ -103,18 +103,17 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) } } -struct nvkm_oclass * -gk104_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gk104_pmu = { .code.data = gk104_pmu_code, .code.size = sizeof(gk104_pmu_code), .data.data = gk104_pmu_data, .data.size = sizeof(gk104_pmu_data), .pgob = gk104_pmu_pgob, -}.base; +}; + +int +gk104_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gk104_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c index 162c007d49c8f..ae255247c9d13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk110.c @@ -21,10 +21,10 @@ * * Authors: Ben Skeggs */ -#define gf110_pmu_code gk110_pmu_code -#define gf110_pmu_data gk110_pmu_data +#define gf119_pmu_code gk110_pmu_code +#define gf119_pmu_data gk110_pmu_data #include "priv.h" -#include "fuc/gf110.fuc4.h" +#include "fuc/gf119.fuc4.h" #include @@ -82,18 +82,17 @@ gk110_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nvkm_rd32(device, 0x000200); } -struct nvkm_oclass * -gk110_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xf0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gk110_pmu = { .code.data = gk110_pmu_code, .code.size = sizeof(gk110_pmu_code), .data.data = gk110_pmu_data, .data.size = sizeof(gk110_pmu_data), .pgob = gk110_pmu_pgob, -}.base; +}; + +int +gk110_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gk110_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c index b14134ef9ea52..3b49176379023 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c @@ -24,18 +24,17 @@ #include "priv.h" #include "fuc/gk208.fuc5.h" -struct nvkm_oclass * -gk208_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0x00), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = _nvkm_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gk208_pmu = { .code.data = gk208_pmu_code, .code.size = sizeof(gk208_pmu_code), .data.data = gk208_pmu_data, .data.size = sizeof(gk208_pmu_data), .pgob = gk110_pmu_pgob, -}.base; +}; + +int +gk208_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gk208_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index bf3c53851352c..860c8bc2b4220 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -19,6 +19,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ +#define gk20a_pmu(p) container_of((p), struct gk20a_pmu, base.subdev) #include "priv.h" #include @@ -165,27 +166,24 @@ resched: } static int -gk20a_pmu_fini(struct nvkm_object *object, bool suspend) +gk20a_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { - struct gk20a_pmu *pmu = (void *)object; - + struct gk20a_pmu *pmu = gk20a_pmu(subdev); nvkm_timer_alarm_cancel(pmu, &pmu->alarm); + return 0; +} - return nvkm_subdev_fini_old(&pmu->base.subdev, suspend); +static void * +gk20a_pmu_dtor(struct nvkm_subdev *subdev) +{ + return gk20a_pmu(subdev); } static int -gk20a_pmu_init(struct nvkm_object *object) +gk20a_pmu_init(struct nvkm_subdev *subdev) { - struct gk20a_pmu *pmu = (void *)object; + struct gk20a_pmu *pmu = gk20a_pmu(subdev); struct nvkm_device *device = pmu->base.subdev.device; - int ret; - - ret = nvkm_subdev_init_old(&pmu->base.subdev); - if (ret) - return ret; - - pmu->base.pgob = nvkm_pmu_pgob; /* init pwr perf counter */ nvkm_wr32(device, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001); @@ -193,7 +191,7 @@ gk20a_pmu_init(struct nvkm_object *object) nvkm_wr32(device, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); nvkm_timer_alarm(pmu, 2000000000, &pmu->alarm); - return ret; + return 0; } static struct gk20a_pmu_dvfs_data @@ -203,32 +201,26 @@ gk20a_dvfs_data= { .p_smooth = 1, }; -static int -gk20a_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_subdev_func +gk20a_pmu = { + .init = gk20a_pmu_init, + .fini = gk20a_pmu_fini, + .dtor = gk20a_pmu_dtor, +}; + +int +gk20a_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) { + static const struct nvkm_pmu_func func = {}; struct gk20a_pmu *pmu; - int ret; - ret = nvkm_pmu_create(parent, engine, oclass, &pmu); - *pobject = nv_object(pmu); - if (ret) - return ret; + if (!(pmu = kzalloc(sizeof(*pmu), GFP_KERNEL))) + return -ENOMEM; + pmu->base.func = &func; + *ppmu = &pmu->base; + nvkm_subdev_ctor(&gk20a_pmu, device, index, 0, &pmu->base.subdev); pmu->data = &gk20a_dvfs_data; - nvkm_alarm_init(&pmu->alarm, gk20a_pmu_dvfs_work); return 0; } - -struct nvkm_oclass * -gk20a_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = gk20a_pmu_init, - .fini = gk20a_pmu_fini, - }, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c new file mode 100644 index 0000000000000..31b8692b4641b --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gm107.c @@ -0,0 +1,41 @@ +/* + * Copyright 2013 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#define gk208_pmu_code gm107_pmu_code +#define gk208_pmu_data gm107_pmu_data +#include "fuc/gk208.fuc5.h" + +static const struct nvkm_pmu_func +gm107_pmu = { + .code.data = gm107_pmu_code, + .code.size = sizeof(gm107_pmu_code), + .data.data = gm107_pmu_data, + .data.size = sizeof(gm107_pmu_data), +}; + +int +gm107_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(&gm107_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c index 223f9fb9f44f5..8ba7fa4ca75bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c @@ -24,27 +24,25 @@ #include "priv.h" #include "fuc/gt215.fuc3.h" -static int -gt215_pmu_init(struct nvkm_object *object) +static void +gt215_pmu_reset(struct nvkm_pmu *pmu) { - struct nvkm_pmu *pmu = (void *)object; struct nvkm_device *device = pmu->subdev.device; nvkm_mask(device, 0x022210, 0x00000001, 0x00000000); nvkm_mask(device, 0x022210, 0x00000001, 0x00000001); - return nvkm_pmu_init(pmu); } -struct nvkm_oclass * -gt215_pmu_oclass = &(struct nvkm_pmu_impl) { - .base.handle = NV_SUBDEV(PMU, 0xa3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_pmu_ctor, - .dtor = _nvkm_pmu_dtor, - .init = gt215_pmu_init, - .fini = _nvkm_pmu_fini, - }, +static const struct nvkm_pmu_func +gt215_pmu = { + .reset = gt215_pmu_reset, .code.data = gt215_pmu_code, .code.size = sizeof(gt215_pmu_code), .data.data = gt215_pmu_data, .data.size = sizeof(gt215_pmu_data), -}.base; +}; + +int +gt215_pmu_new(struct nvkm_device *device, int index, struct nvkm_pmu **ppmu) +{ + return nvkm_pmu_new_(>215_pmu, device, index, ppmu); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c index 556aefe3614f1..e6f74168238c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c @@ -47,8 +47,8 @@ nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx) u32 reply[2]; int ret; - ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, - MEMX_INFO_DATA, 0); + ret = nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, + MEMX_INFO_DATA, 0); if (ret) return ret; @@ -85,8 +85,8 @@ nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec) /* call MEMX process to execute the script, and wait for reply */ if (exec) { - pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, - memx->base, finish); + nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC, + memx->base, finish); } nvkm_debug(subdev, "Exec took %uns, PMU_IN %08x\n", @@ -168,8 +168,8 @@ nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize) u32 reply[2], base, size, i; int ret; - ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, - MEMX_INFO_TRAIN, 0); + ret = nvkm_pmu_send(pmu, reply, PROC_MEMX, MEMX_MSG_INFO, + MEMX_INFO_TRAIN, 0); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h index 799e7c8b88f50..f38c88fae3d6f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h @@ -1,38 +1,20 @@ #ifndef __NVKM_PMU_PRIV_H__ #define __NVKM_PMU_PRIV_H__ +#define nvkm_pmu(p) container_of((p), struct nvkm_pmu, subdev) #include #include -#define nvkm_pmu_create(p, e, o, d) \ - nvkm_pmu_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_pmu_destroy(p) \ - nvkm_subdev_destroy(&(p)->base) -#define nvkm_pmu_init(p) ({ \ - struct nvkm_pmu *_pmu = (p); \ - _nvkm_pmu_init(nv_object(_pmu)); \ -}) -#define nvkm_pmu_fini(p,s) ({ \ - struct nvkm_pmu *_pmu = (p); \ - _nvkm_pmu_fini(nv_object(_pmu), (s)); \ -}) +int nvkm_pmu_new_(const struct nvkm_pmu_func *, struct nvkm_device *, + int index, struct nvkm_pmu **); -int nvkm_pmu_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); +struct nvkm_pmu_func { + void (*reset)(struct nvkm_pmu *); -int _nvkm_pmu_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_pmu_dtor _nvkm_subdev_dtor -int _nvkm_pmu_init(struct nvkm_object *); -int _nvkm_pmu_fini(struct nvkm_object *, bool); -void nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable); - -struct nvkm_pmu_impl { - struct nvkm_oclass base; struct { u32 *data; u32 size; } code; + struct { u32 *data; u32 size; -- GitLab From 57113c0170b9efeacb3e3e9d4c2178c30d9cd991 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5546/7006] drm/nouveau/therm: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 2 +- .../drm/nouveau/include/nvkm/subdev/therm.h | 104 +++++---- drivers/gpu/drm/nouveau/nouveau_hwmon.c | 10 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 94 ++++---- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 - .../drm/nouveau/nvkm/engine/device/gk104.c | 7 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/subdev/therm/Kbuild | 2 +- .../gpu/drm/nouveau/nvkm/subdev/therm/base.c | 212 ++++++++++-------- .../gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 70 +++--- .../drm/nouveau/nvkm/subdev/therm/fannil.c | 3 +- .../drm/nouveau/nvkm/subdev/therm/fanpwm.c | 32 ++- .../drm/nouveau/nvkm/subdev/therm/fantog.c | 21 +- .../gpu/drm/nouveau/nvkm/subdev/therm/g84.c | 127 +++++------ .../nvkm/subdev/therm/{gf110.c => gf119.c} | 74 +++--- .../gpu/drm/nouveau/nvkm/subdev/therm/gm107.c | 48 ++-- .../gpu/drm/nouveau/nvkm/subdev/therm/gt215.c | 66 ++---- .../gpu/drm/nouveau/nvkm/subdev/therm/ic.c | 9 +- .../gpu/drm/nouveau/nvkm/subdev/therm/nv40.c | 74 +++--- .../gpu/drm/nouveau/nvkm/subdev/therm/nv50.c | 64 ++---- .../gpu/drm/nouveau/nvkm/subdev/therm/priv.h | 86 +++---- .../gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 74 +++--- 24 files changed, 507 insertions(+), 714 deletions(-) rename drivers/gpu/drm/nouveau/nvkm/subdev/therm/{gf110.c => gf119.c} (70%) diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 383a47270f3e1..5723102232963 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -57,7 +57,7 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_gpio(a) nvxx_device(a)->gpio #define nvxx_clk(a) nvxx_device(a)->clk #define nvxx_i2c(a) nvxx_device(a)->i2c -#define nvxx_therm(a) nvkm_therm(nvxx_device(a)) +#define nvxx_therm(a) nvxx_device(a)->therm #include #include diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h index 6e60f9bceabaf..b268b96faecea 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h @@ -2,6 +2,28 @@ #define __NVKM_THERM_H__ #include +#include +#include +#include + +enum nvkm_therm_thrs_direction { + NVKM_THERM_THRS_FALLING = 0, + NVKM_THERM_THRS_RISING = 1 +}; + +enum nvkm_therm_thrs_state { + NVKM_THERM_THRS_LOWER = 0, + NVKM_THERM_THRS_HIGHER = 1 +}; + +enum nvkm_therm_thrs { + NVKM_THERM_THRS_FANBOOST = 0, + NVKM_THERM_THRS_DOWNCLOCK = 1, + NVKM_THERM_THRS_CRITICAL = 2, + NVKM_THERM_THRS_SHUTDOWN = 3, + NVKM_THERM_THRS_NR +}; + enum nvkm_therm_fan_mode { NVKM_THERM_CTRL_NONE = 0, NVKM_THERM_CTRL_MANUAL = 1, @@ -24,56 +46,54 @@ enum nvkm_therm_attr_type { }; struct nvkm_therm { + const struct nvkm_therm_func *func; struct nvkm_subdev subdev; - int (*pwm_ctrl)(struct nvkm_therm *, int line, bool); - int (*pwm_get)(struct nvkm_therm *, int line, u32 *, u32 *); - int (*pwm_set)(struct nvkm_therm *, int line, u32, u32); - int (*pwm_clock)(struct nvkm_therm *, int line); + /* automatic thermal management */ + struct nvkm_alarm alarm; + spinlock_t lock; + struct nvbios_therm_trip_point *last_trip; + int mode; + int cstate; + int suspend; + + /* bios */ + struct nvbios_therm_sensor bios_sensor; + + /* fan priv */ + struct nvkm_fan *fan; + + /* alarms priv */ + struct { + spinlock_t alarm_program_lock; + struct nvkm_alarm therm_poll_alarm; + enum nvkm_therm_thrs_state alarm_state[NVKM_THERM_THRS_NR]; + } sensor; + + /* what should be done if the card overheats */ + struct { + void (*downclock)(struct nvkm_therm *, bool active); + void (*pause)(struct nvkm_therm *, bool active); + } emergency; + + /* ic */ + struct i2c_client *ic; int (*fan_get)(struct nvkm_therm *); int (*fan_set)(struct nvkm_therm *, int); - int (*fan_sense)(struct nvkm_therm *); - - int (*temp_get)(struct nvkm_therm *); int (*attr_get)(struct nvkm_therm *, enum nvkm_therm_attr_type); int (*attr_set)(struct nvkm_therm *, enum nvkm_therm_attr_type, int); }; -static inline struct nvkm_therm * -nvkm_therm(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_THERM); -} - -#define nvkm_therm_create(p,e,o,d) \ - nvkm_therm_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_therm_destroy(p) ({ \ - struct nvkm_therm *_therm = (p); \ - _nvkm_therm_dtor(nv_object(_therm)); \ -}) -#define nvkm_therm_init(p) ({ \ - struct nvkm_therm *_therm = (p); \ - _nvkm_therm_init(nv_object(_therm)); \ -}) -#define nvkm_therm_fini(p,s) ({ \ - struct nvkm_therm *_therm = (p); \ - _nvkm_therm_init(nv_object(_therm), (s)); \ -}) - -int nvkm_therm_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_therm_dtor(struct nvkm_object *); -int _nvkm_therm_init(struct nvkm_object *); -int _nvkm_therm_fini(struct nvkm_object *, bool); - -int nvkm_therm_cstate(struct nvkm_therm *, int, int); - -extern struct nvkm_oclass nv40_therm_oclass; -extern struct nvkm_oclass nv50_therm_oclass; -extern struct nvkm_oclass g84_therm_oclass; -extern struct nvkm_oclass gt215_therm_oclass; -extern struct nvkm_oclass gf110_therm_oclass; -extern struct nvkm_oclass gm107_therm_oclass; +int nvkm_therm_temp_get(struct nvkm_therm *); +int nvkm_therm_fan_sense(struct nvkm_therm *); +int nvkm_therm_cstate(struct nvkm_therm *, int, int); + +int nv40_therm_new(struct nvkm_device *, int, struct nvkm_therm **); +int nv50_therm_new(struct nvkm_device *, int, struct nvkm_therm **); +int g84_therm_new(struct nvkm_device *, int, struct nvkm_therm **); +int gt215_therm_new(struct nvkm_device *, int, struct nvkm_therm **); +int gf119_therm_new(struct nvkm_device *, int, struct nvkm_therm **); +int gm107_therm_new(struct nvkm_device *, int, struct nvkm_therm **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c index 0dbe0060f86e2..491c7149d1972 100644 --- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c +++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c @@ -41,7 +41,7 @@ nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf) struct drm_device *dev = dev_get_drvdata(d); struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->device); - int temp = therm->temp_get(therm); + int temp = nvkm_therm_temp_get(therm); if (temp < 0) return temp; @@ -348,7 +348,7 @@ nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr, struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_therm *therm = nvxx_therm(&drm->device); - return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm)); + return snprintf(buf, PAGE_SIZE, "%d\n", nvkm_therm_fan_sense(therm)); } static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, nouveau_hwmon_show_fan1_input, NULL, 0); @@ -571,7 +571,7 @@ nouveau_hwmon_init(struct drm_device *dev) return -ENOMEM; hwmon->dev = dev; - if (!therm || !therm->temp_get || !therm->attr_get || !therm->attr_set) + if (!therm || !therm->attr_get || !therm->attr_set) return -ENODEV; hwmon_dev = hwmon_device_register(&dev->pdev->dev); @@ -588,7 +588,7 @@ nouveau_hwmon_init(struct drm_device *dev) goto error; /* if the card has a working thermal sensor */ - if (therm->temp_get(therm) >= 0) { + if (nvkm_therm_temp_get(therm) >= 0) { ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup); if (ret) goto error; @@ -606,7 +606,7 @@ nouveau_hwmon_init(struct drm_device *dev) } /* if the card can read the fan rpm */ - if (therm->fan_sense(therm) >= 0) { + if (nvkm_therm_fan_sense(therm) >= 0) { ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_fan_rpm_attrgroup); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 8f201022377f2..3734d1fb77562 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -463,7 +463,7 @@ nv40_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv04_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -488,7 +488,7 @@ nv41_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -513,7 +513,7 @@ nv42_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -538,7 +538,7 @@ nv43_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -563,7 +563,7 @@ nv44_chipset = { .imem = nv40_instmem_new, .mc = nv44_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -588,7 +588,7 @@ nv45_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv04_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -613,7 +613,7 @@ nv46_chipset = { .imem = nv40_instmem_new, .mc = nv44_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -638,7 +638,7 @@ nv47_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -663,7 +663,7 @@ nv49_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -688,7 +688,7 @@ nv4a_chipset = { .imem = nv40_instmem_new, .mc = nv44_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -713,7 +713,7 @@ nv4b_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -738,7 +738,7 @@ nv4c_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -763,7 +763,7 @@ nv4e_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -791,7 +791,7 @@ nv50_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = nv50_therm_new, + .therm = nv50_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv50_disp_new, @@ -816,7 +816,7 @@ nv63_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -841,7 +841,7 @@ nv67_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -866,7 +866,7 @@ nv68_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, -// .therm = nv40_therm_new, + .therm = nv40_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, @@ -894,7 +894,7 @@ nv84_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, @@ -925,7 +925,7 @@ nv86_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, @@ -956,7 +956,7 @@ nv92_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, @@ -987,7 +987,7 @@ nv94_chipset = { .mc = g94_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, @@ -1010,7 +1010,7 @@ nv96_chipset = { .i2c = g94_i2c_new, .fuse = nv50_fuse_new, .clk = g84_clk_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, .mxm = nv50_mxm_new, .devinit = g84_devinit_new, .mc = g94_mc_new, @@ -1041,7 +1041,7 @@ nv98_chipset = { .i2c = g94_i2c_new, .fuse = nv50_fuse_new, .clk = g84_clk_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, .mxm = nv50_mxm_new, .devinit = g98_devinit_new, .mc = g98_mc_new, @@ -1080,7 +1080,7 @@ nva0_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, @@ -1112,7 +1112,7 @@ nva3_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, @@ -1145,7 +1145,7 @@ nva5_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, @@ -1177,7 +1177,7 @@ nva8_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, @@ -1208,7 +1208,7 @@ nvaa_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = g94_disp_new, @@ -1239,7 +1239,7 @@ nvac_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, -// .therm = g84_therm_new, + .therm = g84_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .disp = g94_disp_new, @@ -1271,7 +1271,7 @@ nvaf_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, @@ -1305,7 +1305,7 @@ nvc0_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1340,7 +1340,7 @@ nvc1_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1374,7 +1374,7 @@ nvc3_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1408,7 +1408,7 @@ nvc4_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1443,7 +1443,7 @@ nvc8_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1478,7 +1478,7 @@ nvce_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1513,7 +1513,7 @@ nvcf_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, -// .therm = gt215_therm_new, + .therm = gt215_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1546,7 +1546,7 @@ nvd7_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .ce[0] = gf100_ce0_new, // .disp = gf119_disp_new, @@ -1579,7 +1579,7 @@ nvd9_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf119_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, @@ -1613,7 +1613,7 @@ nve4_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gk104_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1649,7 +1649,7 @@ nve6_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gk104_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1685,7 +1685,7 @@ nve7_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gf119_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1745,7 +1745,7 @@ nvf0_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gk110_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1781,7 +1781,7 @@ nvf1_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gk110_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1817,7 +1817,7 @@ nv106_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gk208_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1852,7 +1852,7 @@ nv108_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gk208_pmu_new, -// .therm = gf110_therm_new, + .therm = gf119_therm_new, // .timer = nv04_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, @@ -1887,7 +1887,7 @@ nv117_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, -// .therm = gm107_therm_new, + .therm = gm107_therm_new, // .timer = gk20a_timer_new, // .ce[0] = gk104_ce0_new, // .ce[2] = gk104_ce2_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 556447727342a..dcaa480cd3101 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -44,7 +43,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -60,7 +58,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -75,7 +72,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -91,7 +87,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -106,7 +101,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -121,7 +115,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; @@ -137,7 +130,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -152,7 +144,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 9e05f8bbabc9a..048f1beab81d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -45,7 +44,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -62,7 +60,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -89,7 +86,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; break; case 0xf0: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -106,7 +102,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -123,7 +118,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -139,7 +133,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 76c6b104a99af..e2d00b465b80e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -28,7 +28,6 @@ gm100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x117: - device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; #if 0 @@ -54,7 +53,6 @@ gm100_identify(struct nvkm_device *device) #if 0 /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ - device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; #if 0 @@ -78,7 +76,6 @@ gm100_identify(struct nvkm_device *device) #if 0 /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ - device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass; #endif device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; #if 0 diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 9af8044c16d2d..5aa4cac00402b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -40,7 +39,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -52,7 +50,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -64,7 +61,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -76,7 +72,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -88,7 +83,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -100,7 +94,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -112,7 +105,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -124,7 +116,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -136,7 +127,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -148,7 +138,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -160,7 +149,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -172,7 +160,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -184,7 +171,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -196,7 +182,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; @@ -208,7 +193,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index f2956d45d32ee..8cc924046b785 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -40,7 +39,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -55,7 +53,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -70,7 +67,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -85,7 +81,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -100,7 +95,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -115,7 +109,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -130,7 +123,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -145,7 +137,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -160,7 +151,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -175,7 +165,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -191,7 +180,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -206,7 +194,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; @@ -221,7 +208,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_SUBDEV_THERM ] = >215_therm_oclass; device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild index 5837cf1292d93..135758ba3e28d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild @@ -9,5 +9,5 @@ nvkm-y += nvkm/subdev/therm/nv40.o nvkm-y += nvkm/subdev/therm/nv50.o nvkm-y += nvkm/subdev/therm/g84.o nvkm-y += nvkm/subdev/therm/gt215.o -nvkm-y += nvkm/subdev/therm/gf110.o +nvkm-y += nvkm/subdev/therm/gf119.o nvkm-y += nvkm/subdev/therm/gm107.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index e757fd9b7a07e..304bdfc54445b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -23,14 +23,21 @@ */ #include "priv.h" +int +nvkm_therm_temp_get(struct nvkm_therm *therm) +{ + if (therm->func->temp_get) + return therm->func->temp_get(therm); + return -ENODEV; +} + static int -nvkm_therm_update_trip(struct nvkm_therm *obj) +nvkm_therm_update_trip(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvbios_therm_trip_point *trip = therm->fan->bios.trip, *cur_trip = NULL, *last_trip = therm->last_trip; - u8 temp = therm->base.temp_get(&therm->base); + u8 temp = therm->func->temp_get(therm); u16 duty, i; /* look for the trip point corresponding to the current temperature */ @@ -57,12 +64,11 @@ nvkm_therm_update_trip(struct nvkm_therm *obj) } static int -nvkm_therm_update_linear(struct nvkm_therm *obj) +nvkm_therm_update_linear(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); u8 linear_min_temp = therm->fan->bios.linear_min_temp; u8 linear_max_temp = therm->fan->bios.linear_max_temp; - u8 temp = therm->base.temp_get(&therm->base); + u8 temp = therm->func->temp_get(therm); u16 duty; /* handle the non-linear part first */ @@ -80,10 +86,9 @@ nvkm_therm_update_linear(struct nvkm_therm *obj) } static void -nvkm_therm_update(struct nvkm_therm *obj, int mode) +nvkm_therm_update(struct nvkm_therm *therm, int mode) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; struct nvkm_timer *tmr = subdev->device->timer; unsigned long flags; bool immd = true; @@ -98,7 +103,7 @@ nvkm_therm_update(struct nvkm_therm *obj, int mode) switch (mode) { case NVKM_THERM_CTRL_MANUAL: tmr->alarm_cancel(tmr, &therm->alarm); - duty = nvkm_therm_fan_get(&therm->base); + duty = nvkm_therm_fan_get(therm); if (duty < 0) duty = 100; poll = false; @@ -106,10 +111,10 @@ nvkm_therm_update(struct nvkm_therm *obj, int mode) case NVKM_THERM_CTRL_AUTO: switch(therm->fan->bios.fan_mode) { case NVBIOS_THERM_FAN_TRIP: - duty = nvkm_therm_update_trip(&therm->base); + duty = nvkm_therm_update_trip(therm); break; case NVBIOS_THERM_FAN_LINEAR: - duty = nvkm_therm_update_linear(&therm->base); + duty = nvkm_therm_update_linear(therm); break; case NVBIOS_THERM_FAN_OTHER: if (therm->cstate) @@ -131,20 +136,19 @@ nvkm_therm_update(struct nvkm_therm *obj, int mode) if (duty >= 0) { nvkm_debug(subdev, "FAN target request: %d%%\n", duty); - nvkm_therm_fan_set(&therm->base, immd, duty); + nvkm_therm_fan_set(therm, immd, duty); } } int -nvkm_therm_cstate(struct nvkm_therm *obj, int fan, int dir) +nvkm_therm_cstate(struct nvkm_therm *therm, int fan, int dir) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; if (!dir || (dir < 0 && fan < therm->cstate) || (dir > 0 && fan > therm->cstate)) { nvkm_debug(subdev, "default fan speed -> %d%%\n", fan); therm->cstate = fan; - nvkm_therm_update(&therm->base, -1); + nvkm_therm_update(therm, -1); } return 0; } @@ -152,16 +156,15 @@ nvkm_therm_cstate(struct nvkm_therm *obj, int fan, int dir) static void nvkm_therm_alarm(struct nvkm_alarm *alarm) { - struct nvkm_therm_priv *therm = - container_of(alarm, struct nvkm_therm_priv, alarm); - nvkm_therm_update(&therm->base, -1); + struct nvkm_therm *therm = + container_of(alarm, struct nvkm_therm, alarm); + nvkm_therm_update(therm, -1); } int -nvkm_therm_fan_mode(struct nvkm_therm *obj, int mode) +nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; struct nvkm_device *device = subdev->device; static const char *name[] = { "disabled", @@ -172,28 +175,26 @@ nvkm_therm_fan_mode(struct nvkm_therm *obj, int mode) /* The default PPWR ucode on fermi interferes with fan management */ if ((mode >= ARRAY_SIZE(name)) || (mode != NVKM_THERM_CTRL_NONE && device->card_type >= NV_C0 && - !nvkm_subdev(device, NVDEV_SUBDEV_PMU))) + !device->pmu)) return -EINVAL; /* do not allow automatic fan management if the thermal sensor is * not available */ if (mode == NVKM_THERM_CTRL_AUTO && - therm->base.temp_get(&therm->base) < 0) + therm->func->temp_get(therm) < 0) return -EINVAL; if (therm->mode == mode) return 0; nvkm_debug(subdev, "fan management: %s\n", name[mode]); - nvkm_therm_update(&therm->base, mode); + nvkm_therm_update(therm, mode); return 0; } int -nvkm_therm_attr_get(struct nvkm_therm *obj, enum nvkm_therm_attr_type type) +nvkm_therm_attr_get(struct nvkm_therm *therm, enum nvkm_therm_attr_type type) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - switch (type) { case NVKM_THERM_ATTR_FAN_MIN_DUTY: return therm->fan->bios.min_duty; @@ -223,11 +224,9 @@ nvkm_therm_attr_get(struct nvkm_therm *obj, enum nvkm_therm_attr_type type) } int -nvkm_therm_attr_set(struct nvkm_therm *obj, +nvkm_therm_attr_set(struct nvkm_therm *therm, enum nvkm_therm_attr_type type, int value) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - switch (type) { case NVKM_THERM_ATTR_FAN_MIN_DUTY: if (value < 0) @@ -244,123 +243,140 @@ nvkm_therm_attr_set(struct nvkm_therm *obj, therm->fan->bios.max_duty = value; return 0; case NVKM_THERM_ATTR_FAN_MODE: - return nvkm_therm_fan_mode(&therm->base, value); + return nvkm_therm_fan_mode(therm, value); case NVKM_THERM_ATTR_THRS_FAN_BOOST: therm->bios_sensor.thrs_fan_boost.temp = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST: therm->bios_sensor.thrs_fan_boost.hysteresis = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_DOWN_CLK: therm->bios_sensor.thrs_down_clock.temp = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST: therm->bios_sensor.thrs_down_clock.hysteresis = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_CRITICAL: therm->bios_sensor.thrs_critical.temp = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_CRITICAL_HYST: therm->bios_sensor.thrs_critical.hysteresis = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_SHUTDOWN: therm->bios_sensor.thrs_shutdown.temp = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST: therm->bios_sensor.thrs_shutdown.hysteresis = value; - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; } return -EINVAL; } -int -_nvkm_therm_init(struct nvkm_object *object) +static void +nvkm_therm_intr(struct nvkm_subdev *subdev) { - struct nvkm_therm_priv *therm = (void *)object; - int ret; - - ret = nvkm_subdev_init_old(&therm->base.subdev); - if (ret) - return ret; - - if (therm->suspend >= 0) { - /* restore the pwm value only when on manual or auto mode */ - if (therm->suspend > 0) - nvkm_therm_fan_set(&therm->base, true, therm->fan->percent); - - nvkm_therm_fan_mode(&therm->base, therm->suspend); - } - nvkm_therm_sensor_init(&therm->base); - nvkm_therm_fan_init(&therm->base); - return 0; + struct nvkm_therm *therm = nvkm_therm(subdev); + if (therm->func->intr) + therm->func->intr(therm); } -int -_nvkm_therm_fini(struct nvkm_object *object, bool suspend) +static int +nvkm_therm_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_therm_priv *therm = (void *)object; + struct nvkm_therm *therm = nvkm_therm(subdev); + + if (therm->func->fini) + therm->func->fini(therm); + + nvkm_therm_fan_fini(therm, suspend); + nvkm_therm_sensor_fini(therm, suspend); - nvkm_therm_fan_fini(&therm->base, suspend); - nvkm_therm_sensor_fini(&therm->base, suspend); if (suspend) { therm->suspend = therm->mode; therm->mode = NVKM_THERM_CTRL_NONE; } - return nvkm_subdev_fini_old(&therm->base.subdev, suspend); -} - -int -nvkm_therm_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) -{ - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PTHERM", - "therm", length, pobject); - therm = *pobject; - if (ret) - return ret; - - nvkm_alarm_init(&therm->alarm, nvkm_therm_alarm); - spin_lock_init(&therm->lock); - spin_lock_init(&therm->sensor.alarm_program_lock); - - therm->base.fan_get = nvkm_therm_fan_user_get; - therm->base.fan_set = nvkm_therm_fan_user_set; - therm->base.fan_sense = nvkm_therm_fan_sense; - therm->base.attr_get = nvkm_therm_attr_get; - therm->base.attr_set = nvkm_therm_attr_set; - therm->mode = therm->suspend = -1; /* undefined */ return 0; } -int -nvkm_therm_preinit(struct nvkm_therm *therm) +static int +nvkm_therm_oneinit(struct nvkm_subdev *subdev) { + struct nvkm_therm *therm = nvkm_therm(subdev); nvkm_therm_sensor_ctor(therm); nvkm_therm_ic_ctor(therm); nvkm_therm_fan_ctor(therm); - nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO); nvkm_therm_sensor_preinit(therm); return 0; } -void -_nvkm_therm_dtor(struct nvkm_object *object) +static int +nvkm_therm_init(struct nvkm_subdev *subdev) +{ + struct nvkm_therm *therm = nvkm_therm(subdev); + + therm->func->init(therm); + + if (therm->suspend >= 0) { + /* restore the pwm value only when on manual or auto mode */ + if (therm->suspend > 0) + nvkm_therm_fan_set(therm, true, therm->fan->percent); + + nvkm_therm_fan_mode(therm, therm->suspend); + } + + nvkm_therm_sensor_init(therm); + nvkm_therm_fan_init(therm); + return 0; +} + +static void * +nvkm_therm_dtor(struct nvkm_subdev *subdev) { - struct nvkm_therm_priv *therm = (void *)object; + struct nvkm_therm *therm = nvkm_therm(subdev); kfree(therm->fan); - nvkm_subdev_destroy(&therm->base.subdev); + return therm; +} + +static const struct nvkm_subdev_func +nvkm_therm = { + .dtor = nvkm_therm_dtor, + .oneinit = nvkm_therm_oneinit, + .init = nvkm_therm_init, + .fini = nvkm_therm_fini, + .intr = nvkm_therm_intr, +}; + +int +nvkm_therm_new_(const struct nvkm_therm_func *func, struct nvkm_device *device, + int index, struct nvkm_therm **ptherm) +{ + struct nvkm_therm *therm; + + if (!(therm = *ptherm = kzalloc(sizeof(*therm), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_therm, device, index, 0, &therm->subdev); + therm->func = func; + + nvkm_alarm_init(&therm->alarm, nvkm_therm_alarm); + spin_lock_init(&therm->lock); + spin_lock_init(&therm->sensor.alarm_program_lock); + + therm->fan_get = nvkm_therm_fan_user_get; + therm->fan_set = nvkm_therm_fan_user_set; + therm->attr_get = nvkm_therm_attr_get; + therm->attr_set = nvkm_therm_attr_set; + therm->mode = therm->suspend = -1; /* undefined */ + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index e017607673a56..a2be181677700 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -31,8 +31,8 @@ static int nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) { - struct nvkm_therm_priv *therm = (void *)fan->parent; - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_therm *therm = fan->parent; + struct nvkm_subdev *subdev = &therm->subdev; struct nvkm_timer *tmr = subdev->device->timer; unsigned long flags; int ret = 0; @@ -50,7 +50,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) } /* check that we're not already at the target duty cycle */ - duty = fan->get(&therm->base); + duty = fan->get(therm); if (duty == target) { spin_unlock_irqrestore(&fan->lock, flags); return 0; @@ -71,7 +71,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) } nvkm_debug(subdev, "FAN update: %d\n", duty); - ret = fan->set(&therm->base, duty); + ret = fan->set(therm, duty); if (ret) { spin_unlock_irqrestore(&fan->lock, flags); return ret; @@ -109,29 +109,29 @@ nvkm_fan_alarm(struct nvkm_alarm *alarm) } int -nvkm_therm_fan_get(struct nvkm_therm *obj) +nvkm_therm_fan_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - return therm->fan->get(&therm->base); + return therm->fan->get(therm); } int -nvkm_therm_fan_set(struct nvkm_therm *obj, bool immediate, int percent) +nvkm_therm_fan_set(struct nvkm_therm *therm, bool immediate, int percent) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); return nvkm_fan_update(therm->fan, immediate, percent); } int -nvkm_therm_fan_sense(struct nvkm_therm *obj) +nvkm_therm_fan_sense(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct nvkm_timer *tmr = device->timer; struct nvkm_gpio *gpio = device->gpio; u32 cycles, cur, prev; u64 start, end, tach; + if (therm->func->fan_sense) + return therm->func->fan_sense(therm); + if (therm->fan->tach.func == DCB_GPIO_UNUSED) return -ENODEV; @@ -166,28 +166,23 @@ nvkm_therm_fan_sense(struct nvkm_therm *obj) } int -nvkm_therm_fan_user_get(struct nvkm_therm *obj) +nvkm_therm_fan_user_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - return nvkm_therm_fan_get(&therm->base); + return nvkm_therm_fan_get(therm); } int -nvkm_therm_fan_user_set(struct nvkm_therm *obj, int percent) +nvkm_therm_fan_user_set(struct nvkm_therm *therm, int percent) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - if (therm->mode != NVKM_THERM_CTRL_MANUAL) return -EINVAL; - return nvkm_therm_fan_set(&therm->base, true, percent); + return nvkm_therm_fan_set(therm, true, percent); } static void -nvkm_therm_fan_set_defaults(struct nvkm_therm *obj) +nvkm_therm_fan_set_defaults(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - therm->fan->bios.pwm_freq = 0; therm->fan->bios.min_duty = 0; therm->fan->bios.max_duty = 100; @@ -198,10 +193,8 @@ nvkm_therm_fan_set_defaults(struct nvkm_therm *obj) } static void -nvkm_therm_fan_safety_checks(struct nvkm_therm *obj) +nvkm_therm_fan_safety_checks(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - if (therm->fan->bios.min_duty > 100) therm->fan->bios.min_duty = 100; if (therm->fan->bios.max_duty > 100) @@ -212,27 +205,24 @@ nvkm_therm_fan_safety_checks(struct nvkm_therm *obj) } int -nvkm_therm_fan_init(struct nvkm_therm *obj) +nvkm_therm_fan_init(struct nvkm_therm *therm) { return 0; } int -nvkm_therm_fan_fini(struct nvkm_therm *obj, bool suspend) +nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *tmr = nvkm_timer(therm); - + struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) tmr->alarm_cancel(tmr, &therm->fan->alarm); return 0; } int -nvkm_therm_fan_ctor(struct nvkm_therm *obj) +nvkm_therm_fan_ctor(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; struct nvkm_device *device = subdev->device; struct nvkm_gpio *gpio = device->gpio; struct nvkm_bios *bios = device->bios; @@ -247,15 +237,15 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) nvkm_debug(subdev, "GPIO_FAN is in input mode\n"); ret = -EINVAL; } else { - ret = nvkm_fanpwm_create(&therm->base, &func); + ret = nvkm_fanpwm_create(therm, &func); if (ret != 0) - ret = nvkm_fantog_create(&therm->base, &func); + ret = nvkm_fantog_create(therm, &func); } } /* no controllable fan found, create a dummy fan module */ if (ret != 0) { - ret = nvkm_fannil_create(&therm->base); + ret = nvkm_fannil_create(therm); if (ret) return ret; } @@ -263,7 +253,7 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) nvkm_debug(subdev, "FAN control: %s\n", therm->fan->type); /* read the current speed, it is useful when resuming */ - therm->fan->percent = nvkm_therm_fan_get(&therm->base); + therm->fan->percent = nvkm_therm_fan_get(therm); /* attempt to detect a tachometer connection */ ret = nvkm_gpio_find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, @@ -272,18 +262,18 @@ nvkm_therm_fan_ctor(struct nvkm_therm *obj) therm->fan->tach.func = DCB_GPIO_UNUSED; /* initialise fan bump/slow update handling */ - therm->fan->parent = &therm->base; + therm->fan->parent = therm; nvkm_alarm_init(&therm->fan->alarm, nvkm_fan_alarm); spin_lock_init(&therm->fan->lock); /* other random init... */ - nvkm_therm_fan_set_defaults(&therm->base); + nvkm_therm_fan_set_defaults(therm); nvbios_perf_fan_parse(bios, &therm->fan->perf); if (!nvbios_fan_parse(bios, &therm->fan->bios)) { nvkm_debug(subdev, "parsing the fan table failed\n"); if (nvbios_therm_fan_parse(bios, &therm->fan->bios)) nvkm_error(subdev, "parsing both fan tables failed\n"); } - nvkm_therm_fan_safety_checks(&therm->base); + nvkm_therm_fan_safety_checks(therm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c index 693b4efd18410..8ae300f911b61 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c @@ -36,9 +36,8 @@ nvkm_fannil_set(struct nvkm_therm *therm, int percent) } int -nvkm_fannil_create(struct nvkm_therm *obj) +nvkm_fannil_create(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fan *priv; priv = kzalloc(sizeof(*priv), GFP_KERNEL); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c index 944b7905b4a59..340f37a299dce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c @@ -35,17 +35,16 @@ struct nvkm_fanpwm { }; static int -nvkm_fanpwm_get(struct nvkm_therm *obj) +nvkm_fanpwm_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fanpwm *fan = (void *)therm->fan; - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct nvkm_gpio *gpio = device->gpio; int card_type = device->card_type; u32 divs, duty; int ret; - ret = therm->base.pwm_get(&therm->base, fan->func.line, &divs, &duty); + ret = therm->func->pwm_get(therm, fan->func.line, &divs, &duty); if (ret == 0 && divs) { divs = max(divs, duty); if (card_type <= NV_40 || (fan->func.log[0] & 1)) @@ -57,20 +56,18 @@ nvkm_fanpwm_get(struct nvkm_therm *obj) } static int -nvkm_fanpwm_set(struct nvkm_therm *obj, int percent) +nvkm_fanpwm_set(struct nvkm_therm *therm, int percent) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fanpwm *fan = (void *)therm->fan; - int card_type = nv_device(therm)->card_type; + int card_type = therm->subdev.device->card_type; u32 divs, duty; int ret; divs = fan->base.perf.pwm_divisor; if (fan->base.bios.pwm_freq) { divs = 1; - if (therm->base.pwm_clock) - divs = therm->base.pwm_clock(&therm->base, - fan->func.line); + if (therm->func->pwm_clock) + divs = therm->func->pwm_clock(therm, fan->func.line); divs /= fan->base.bios.pwm_freq; } @@ -78,27 +75,26 @@ nvkm_fanpwm_set(struct nvkm_therm *obj, int percent) if (card_type <= NV_40 || (fan->func.log[0] & 1)) duty = divs - duty; - ret = therm->base.pwm_set(&therm->base, fan->func.line, divs, duty); + ret = therm->func->pwm_set(therm, fan->func.line, divs, duty); if (ret == 0) - ret = therm->base.pwm_ctrl(&therm->base, fan->func.line, true); + ret = therm->func->pwm_ctrl(therm, fan->func.line, true); return ret; } int -nvkm_fanpwm_create(struct nvkm_therm *obj, struct dcb_gpio_func *func) +nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct nvkm_bios *bios = device->bios; struct nvkm_fanpwm *fan; - struct nvbios_therm_fan info; + struct nvbios_therm_fan info = {}; u32 divs, duty; nvbios_fan_parse(bios, &info); if (!nvkm_boolopt(device->cfgopt, "NvFanPWM", func->param) || - !therm->base.pwm_ctrl || info.type == NVBIOS_THERM_FAN_TOGGLE || - therm->base.pwm_get(&therm->base, func->line, &divs, &duty) == -ENODEV) + !therm->func->pwm_ctrl || info.type == NVBIOS_THERM_FAN_TOGGLE || + therm->func->pwm_get(therm, func->line, &divs, &duty) == -ENODEV) return -ENODEV; fan = kzalloc(sizeof(*fan), GFP_KERNEL); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 7e1f21d81eb12..64fe8f22336c8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -38,8 +38,8 @@ struct nvkm_fantog { static void nvkm_fantog_update(struct nvkm_fantog *fan, int percent) { - struct nvkm_therm_priv *therm = (void *)fan->base.parent; - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_therm *therm = fan->base.parent; + struct nvkm_device *device = therm->subdev.device; struct nvkm_timer *tmr = device->timer; struct nvkm_gpio *gpio = device->gpio; unsigned long flags; @@ -71,33 +71,30 @@ nvkm_fantog_alarm(struct nvkm_alarm *alarm) } static int -nvkm_fantog_get(struct nvkm_therm *obj) +nvkm_fantog_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fantog *fan = (void *)therm->fan; return fan->percent; } static int -nvkm_fantog_set(struct nvkm_therm *obj, int percent) +nvkm_fantog_set(struct nvkm_therm *therm, int percent) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fantog *fan = (void *)therm->fan; - if (therm->base.pwm_ctrl) - therm->base.pwm_ctrl(&therm->base, fan->func.line, false); + if (therm->func->pwm_ctrl) + therm->func->pwm_ctrl(therm, fan->func.line, false); nvkm_fantog_update(fan, percent); return 0; } int -nvkm_fantog_create(struct nvkm_therm *obj, struct dcb_gpio_func *func) +nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvkm_fantog *fan; int ret; - if (therm->base.pwm_ctrl) { - ret = therm->base.pwm_ctrl(&therm->base, func->line, false); + if (therm->func->pwm_ctrl) { + ret = therm->func->pwm_ctrl(therm, func->line, false); if (ret) return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c index c70b79f8786c1..86e81930d8ee7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c @@ -51,11 +51,10 @@ g84_sensor_setup(struct nvkm_therm *therm) } static void -g84_therm_program_alarms(struct nvkm_therm *obj) +g84_therm_program_alarms(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvbios_therm_sensor *sensor = &therm->bios_sensor; - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; struct nvkm_device *device = subdev->device; unsigned long flags; @@ -116,7 +115,7 @@ g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm, } /* fix the state (in case someone reprogrammed the alarms) */ - cur = therm->temp_get(therm); + cur = therm->func->temp_get(therm); if (new_state == NVKM_THERM_THRS_LOWER && cur > thrs->temp) new_state = NVKM_THERM_THRS_HIGHER; else if (new_state == NVKM_THERM_THRS_HIGHER && @@ -137,10 +136,10 @@ g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm, } static void -g84_therm_intr(struct nvkm_subdev *subdev) +g84_therm_intr(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = (void *)subdev; - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; unsigned long flags; uint32_t intr; @@ -151,7 +150,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* THRS_4: downclock */ if (intr & 0x002) { - g84_therm_threshold_hyst_emulation(&therm->base, 0x20414, 24, + g84_therm_threshold_hyst_emulation(therm, 0x20414, 24, &sensor->thrs_down_clock, NVKM_THERM_THRS_DOWNCLOCK); intr &= ~0x002; @@ -159,7 +158,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* shutdown */ if (intr & 0x004) { - g84_therm_threshold_hyst_emulation(&therm->base, 0x20480, 20, + g84_therm_threshold_hyst_emulation(therm, 0x20480, 20, &sensor->thrs_shutdown, NVKM_THERM_THRS_SHUTDOWN); intr &= ~0x004; @@ -167,7 +166,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* THRS_1 : fan boost */ if (intr & 0x008) { - g84_therm_threshold_hyst_emulation(&therm->base, 0x204c4, 21, + g84_therm_threshold_hyst_emulation(therm, 0x204c4, 21, &sensor->thrs_fan_boost, NVKM_THERM_THRS_FANBOOST); intr &= ~0x008; @@ -175,7 +174,7 @@ g84_therm_intr(struct nvkm_subdev *subdev) /* THRS_2 : critical */ if (intr & 0x010) { - g84_therm_threshold_hyst_emulation(&therm->base, 0x204c0, 22, + g84_therm_threshold_hyst_emulation(therm, 0x204c0, 22, &sensor->thrs_critical, NVKM_THERM_THRS_CRITICAL); intr &= ~0x010; @@ -191,62 +190,9 @@ g84_therm_intr(struct nvkm_subdev *subdev) spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); } -static int -g84_therm_init(struct nvkm_object *object) -{ - struct nvkm_therm_priv *therm = (void *)object; - int ret; - - ret = nvkm_therm_init(&therm->base); - if (ret) - return ret; - - g84_sensor_setup(&therm->base); - return 0; -} - -static int -g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &therm); - *pobject = nv_object(therm); - if (ret) - return ret; - - therm->base.pwm_ctrl = nv50_fan_pwm_ctrl; - therm->base.pwm_get = nv50_fan_pwm_get; - therm->base.pwm_set = nv50_fan_pwm_set; - therm->base.pwm_clock = nv50_fan_pwm_clock; - therm->base.temp_get = g84_temp_get; - therm->sensor.program_alarms = g84_therm_program_alarms; - nv_subdev(therm)->intr = g84_therm_intr; - - /* init the thresholds */ - nvkm_therm_sensor_set_threshold_state(&therm->base, - NVKM_THERM_THRS_SHUTDOWN, - NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&therm->base, - NVKM_THERM_THRS_FANBOOST, - NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&therm->base, - NVKM_THERM_THRS_CRITICAL, - NVKM_THERM_THRS_LOWER); - nvkm_therm_sensor_set_threshold_state(&therm->base, - NVKM_THERM_THRS_DOWNCLOCK, - NVKM_THERM_THRS_LOWER); - - return nvkm_therm_preinit(&therm->base); -} - -int -g84_therm_fini(struct nvkm_object *object, bool suspend) +void +g84_therm_fini(struct nvkm_therm *therm) { - struct nvkm_therm *therm = (void *)object; struct nvkm_device *device = therm->subdev.device; /* Disable PTherm IRQs */ @@ -255,17 +201,46 @@ g84_therm_fini(struct nvkm_object *object, bool suspend) /* ACK all PTherm IRQs */ nvkm_wr32(device, 0x20100, 0xffffffff); nvkm_wr32(device, 0x1100, 0x10000); /* PBUS */ +} - return _nvkm_therm_fini(object, suspend); +static void +g84_therm_init(struct nvkm_therm *therm) +{ + g84_sensor_setup(therm); } -struct nvkm_oclass -g84_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = g84_therm_init, - .fini = g84_therm_fini, - }, +static const struct nvkm_therm_func +g84_therm = { + .init = g84_therm_init, + .fini = g84_therm_fini, + .intr = g84_therm_intr, + .pwm_ctrl = nv50_fan_pwm_ctrl, + .pwm_get = nv50_fan_pwm_get, + .pwm_set = nv50_fan_pwm_set, + .pwm_clock = nv50_fan_pwm_clock, + .temp_get = g84_temp_get, + .program_alarms = g84_therm_program_alarms, }; + +int +g84_therm_new(struct nvkm_device *device, int index, struct nvkm_therm **ptherm) +{ + struct nvkm_therm *therm; + int ret; + + ret = nvkm_therm_new_(&g84_therm, device, index, &therm); + *ptherm = therm; + if (ret) + return ret; + + /* init the thresholds */ + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_SHUTDOWN, + NVKM_THERM_THRS_LOWER); + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_FANBOOST, + NVKM_THERM_THRS_LOWER); + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_CRITICAL, + NVKM_THERM_THRS_LOWER); + nvkm_therm_sensor_set_threshold_state(therm, NVKM_THERM_THRS_DOWNCLOCK, + NVKM_THERM_THRS_LOWER); + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c similarity index 70% rename from drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c rename to drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c index 4d017f62d7e4d..06dcfd6ee9664 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf119.c @@ -50,7 +50,7 @@ pwm_info(struct nvkm_therm *therm, int line) } static int -gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) +gf119_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) { struct nvkm_device *device = therm->subdev.device; u32 data = enable ? 0x00000040 : 0x00000000; @@ -64,7 +64,7 @@ gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable) } static int -gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) +gf119_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) { struct nvkm_device *device = therm->subdev.device; int indx = pwm_info(therm, line); @@ -86,7 +86,7 @@ gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty) } static int -gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) +gf119_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) { struct nvkm_device *device = therm->subdev.device; int indx = pwm_info(therm, line); @@ -103,7 +103,7 @@ gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) } static int -gf110_fan_pwm_clock(struct nvkm_therm *therm, int line) +gf119_fan_pwm_clock(struct nvkm_therm *therm, int line) { struct nvkm_device *device = therm->subdev.device; int indx = pwm_info(therm, line); @@ -115,61 +115,39 @@ gf110_fan_pwm_clock(struct nvkm_therm *therm, int line) return device->crystal * 1000 / 10; } -int -gf110_therm_init(struct nvkm_object *object) +void +gf119_therm_init(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = (void *)object; - struct nvkm_device *device = therm->base.subdev.device; - int ret; + struct nvkm_device *device = therm->subdev.device; - ret = nvkm_therm_init(&therm->base); - if (ret) - return ret; + g84_sensor_setup(therm); /* enable fan tach, count revolutions per-second */ nvkm_mask(device, 0x00e720, 0x00000003, 0x00000002); if (therm->fan->tach.func != DCB_GPIO_UNUSED) { nvkm_mask(device, 0x00d79c, 0x000000ff, therm->fan->tach.line); - nvkm_wr32(device, 0x00e724, nv_device(therm)->crystal * 1000); + nvkm_wr32(device, 0x00e724, device->crystal * 1000); nvkm_mask(device, 0x00e720, 0x00000001, 0x00000001); } nvkm_mask(device, 0x00e720, 0x00000002, 0x00000000); - - return 0; } -static int -gf110_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &therm); - *pobject = nv_object(therm); - if (ret) - return ret; - - g84_sensor_setup(&therm->base); +static const struct nvkm_therm_func +gf119_therm = { + .init = gf119_therm_init, + .fini = g84_therm_fini, + .pwm_ctrl = gf119_fan_pwm_ctrl, + .pwm_get = gf119_fan_pwm_get, + .pwm_set = gf119_fan_pwm_set, + .pwm_clock = gf119_fan_pwm_clock, + .temp_get = g84_temp_get, + .fan_sense = gt215_therm_fan_sense, + .program_alarms = nvkm_therm_program_alarms_polling, +}; - therm->base.pwm_ctrl = gf110_fan_pwm_ctrl; - therm->base.pwm_get = gf110_fan_pwm_get; - therm->base.pwm_set = gf110_fan_pwm_set; - therm->base.pwm_clock = gf110_fan_pwm_clock; - therm->base.temp_get = g84_temp_get; - therm->base.fan_sense = gt215_therm_fan_sense; - therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&therm->base); +int +gf119_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&gf119_therm, device, index, ptherm); } - -struct nvkm_oclass -gf110_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0xd0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf110_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = gf110_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c index bd17e631e2db2..86848ece4d897 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c @@ -54,36 +54,22 @@ gm107_fan_pwm_clock(struct nvkm_therm *therm, int line) return therm->subdev.device->crystal * 1000; } -static int -gm107_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &therm); - *pobject = nv_object(therm); - if (ret) - return ret; +static const struct nvkm_therm_func +gm107_therm = { + .init = gf119_therm_init, + .fini = g84_therm_fini, + .pwm_ctrl = gm107_fan_pwm_ctrl, + .pwm_get = gm107_fan_pwm_get, + .pwm_set = gm107_fan_pwm_set, + .pwm_clock = gm107_fan_pwm_clock, + .temp_get = g84_temp_get, + .fan_sense = gt215_therm_fan_sense, + .program_alarms = nvkm_therm_program_alarms_polling, +}; - therm->base.pwm_ctrl = gm107_fan_pwm_ctrl; - therm->base.pwm_get = gm107_fan_pwm_get; - therm->base.pwm_set = gm107_fan_pwm_set; - therm->base.pwm_clock = gm107_fan_pwm_clock; - therm->base.temp_get = g84_temp_get; - therm->base.fan_sense = gt215_therm_fan_sense; - therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&therm->base); +int +gm107_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&gm107_therm, device, index, ptherm); } - -struct nvkm_oclass -gm107_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x117), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = gf110_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c index 8814d8511ea50..c08097f2aff50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c @@ -36,62 +36,40 @@ gt215_therm_fan_sense(struct nvkm_therm *therm) return -ENODEV; } -static int -gt215_therm_init(struct nvkm_object *object) +static void +gt215_therm_init(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = (void *)object; - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct dcb_gpio_func *tach = &therm->fan->tach; - int ret; - - ret = nvkm_therm_init(&therm->base); - if (ret) - return ret; - g84_sensor_setup(&therm->base); + g84_sensor_setup(therm); /* enable fan tach, count revolutions per-second */ nvkm_mask(device, 0x00e720, 0x00000003, 0x00000002); if (tach->func != DCB_GPIO_UNUSED) { - nvkm_wr32(device, 0x00e724, nv_device(therm)->crystal * 1000); + nvkm_wr32(device, 0x00e724, device->crystal * 1000); nvkm_mask(device, 0x00e720, 0x001f0000, tach->line << 16); nvkm_mask(device, 0x00e720, 0x00000001, 0x00000001); } nvkm_mask(device, 0x00e720, 0x00000002, 0x00000000); - - return 0; } -static int -gt215_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &therm); - *pobject = nv_object(therm); - if (ret) - return ret; +static const struct nvkm_therm_func +gt215_therm = { + .init = gt215_therm_init, + .fini = g84_therm_fini, + .pwm_ctrl = nv50_fan_pwm_ctrl, + .pwm_get = nv50_fan_pwm_get, + .pwm_set = nv50_fan_pwm_set, + .pwm_clock = nv50_fan_pwm_clock, + .temp_get = g84_temp_get, + .fan_sense = gt215_therm_fan_sense, + .program_alarms = nvkm_therm_program_alarms_polling, +}; - therm->base.pwm_ctrl = nv50_fan_pwm_ctrl; - therm->base.pwm_get = nv50_fan_pwm_get; - therm->base.pwm_set = nv50_fan_pwm_set; - therm->base.pwm_clock = nv50_fan_pwm_clock; - therm->base.temp_get = g84_temp_get; - therm->base.fan_sense = gt215_therm_fan_sense; - therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; - return nvkm_therm_preinit(&therm->base); +int +gt215_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(>215_therm, device, index, ptherm); } - -struct nvkm_oclass -gt215_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = gt215_therm_init, - .fini = g84_therm_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c index c19af7d242394..6e0ddc1bb5835 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c @@ -30,7 +30,7 @@ static bool probe_monitoring_device(struct nvkm_i2c_bus *bus, struct i2c_board_info *info, void *data) { - struct nvkm_therm_priv *therm = data; + struct nvkm_therm *therm = data; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; struct i2c_client *client; @@ -46,7 +46,7 @@ probe_monitoring_device(struct nvkm_i2c_bus *bus, return false; } - nvkm_debug(&therm->base.subdev, + nvkm_debug(&therm->subdev, "Found an %s at address 0x%x (controlled by lm_sensors, " "temp offset %+i C)\n", info->type, info->addr, sensor->offset_constant); @@ -80,10 +80,9 @@ nv_board_infos[] = { }; void -nvkm_therm_ic_ctor(struct nvkm_therm *obj) +nvkm_therm_ic_ctor(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct nvkm_bios *bios = device->bios; struct nvkm_i2c *i2c = device->i2c; struct nvkm_i2c_bus *bus; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c index f2dd7520eff44..6326fdc5a48d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c @@ -29,15 +29,12 @@ enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 }; static enum nv40_sensor_style nv40_sensor_style(struct nvkm_therm *therm) { - struct nvkm_device *device = nv_device(therm); - - switch (device->chipset) { + switch (therm->subdev.device->chipset) { case 0x43: case 0x44: case 0x4a: case 0x47: return OLD_STYLE; - case 0x46: case 0x49: case 0x4b: @@ -73,12 +70,11 @@ nv40_sensor_setup(struct nvkm_therm *therm) } static int -nv40_temp_get(struct nvkm_therm *obj) +nv40_temp_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; - enum nv40_sensor_style style = nv40_sensor_style(&therm->base); + enum nv40_sensor_style style = nv40_sensor_style(therm); int core_temp; if (style == NEW_STYLE) { @@ -169,10 +165,10 @@ nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty) } void -nv40_therm_intr(struct nvkm_subdev *subdev) +nv40_therm_intr(struct nvkm_therm *therm) { - struct nvkm_therm *therm = nvkm_therm(subdev); - struct nvkm_device *device = therm->subdev.device; + struct nvkm_subdev *subdev = &therm->subdev; + struct nvkm_device *device = subdev->device; uint32_t stat = nvkm_rd32(device, 0x1100); /* traitement */ @@ -183,46 +179,26 @@ nv40_therm_intr(struct nvkm_subdev *subdev) nvkm_error(subdev, "THERM received an IRQ: stat = %x\n", stat); } -static int -nv40_therm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static void +nv40_therm_init(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &therm); - *pobject = nv_object(therm); - if (ret) - return ret; - - therm->base.pwm_ctrl = nv40_fan_pwm_ctrl; - therm->base.pwm_get = nv40_fan_pwm_get; - therm->base.pwm_set = nv40_fan_pwm_set; - therm->base.temp_get = nv40_temp_get; - therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; - nv_subdev(therm)->intr = nv40_therm_intr; - return nvkm_therm_preinit(&therm->base); -} - -static int -nv40_therm_init(struct nvkm_object *object) -{ - struct nvkm_therm *therm = (void *)object; - nv40_sensor_setup(therm); - - return _nvkm_therm_init(object); } -struct nvkm_oclass -nv40_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = nv40_therm_init, - .fini = _nvkm_therm_fini, - }, +static const struct nvkm_therm_func +nv40_therm = { + .init = nv40_therm_init, + .intr = nv40_therm_intr, + .pwm_ctrl = nv40_fan_pwm_ctrl, + .pwm_get = nv40_fan_pwm_get, + .pwm_set = nv40_fan_pwm_set, + .temp_get = nv40_temp_get, + .program_alarms = nvkm_therm_program_alarms_polling, }; + +int +nv40_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&nv40_therm, device, index, ptherm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c index 787f3cf19747c..9b57b433d4cf6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c @@ -126,10 +126,9 @@ nv50_sensor_setup(struct nvkm_therm *therm) } static int -nv50_temp_get(struct nvkm_therm *obj) +nv50_temp_get(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_device *device = therm->base.subdev.device; + struct nvkm_device *device = therm->subdev.device; struct nvbios_therm_sensor *sensor = &therm->bios_sensor; int core_temp; @@ -151,48 +150,27 @@ nv50_temp_get(struct nvkm_therm *obj) return core_temp; } -static int -nv50_therm_ctor(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_therm_priv *therm; - int ret; - - ret = nvkm_therm_create(parent, engine, oclass, &therm); - *pobject = nv_object(therm); - if (ret) - return ret; - - therm->base.pwm_ctrl = nv50_fan_pwm_ctrl; - therm->base.pwm_get = nv50_fan_pwm_get; - therm->base.pwm_set = nv50_fan_pwm_set; - therm->base.pwm_clock = nv50_fan_pwm_clock; - therm->base.temp_get = nv50_temp_get; - therm->sensor.program_alarms = nvkm_therm_program_alarms_polling; - nv_subdev(therm)->intr = nv40_therm_intr; - - return nvkm_therm_preinit(&therm->base); -} - -static int -nv50_therm_init(struct nvkm_object *object) +static void +nv50_therm_init(struct nvkm_therm *therm) { - struct nvkm_therm *therm = (void *)object; - nv50_sensor_setup(therm); - - return _nvkm_therm_init(object); } -struct nvkm_oclass -nv50_therm_oclass = { - .handle = NV_SUBDEV(THERM, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_therm_ctor, - .dtor = _nvkm_therm_dtor, - .init = nv50_therm_init, - .fini = _nvkm_therm_fini, - }, +static const struct nvkm_therm_func +nv50_therm = { + .init = nv50_therm_init, + .intr = nv40_therm_intr, + .pwm_ctrl = nv50_fan_pwm_ctrl, + .pwm_get = nv50_fan_pwm_get, + .pwm_set = nv50_fan_pwm_set, + .pwm_clock = nv50_fan_pwm_clock, + .temp_get = nv50_temp_get, + .program_alarms = nvkm_therm_program_alarms_polling, }; + +int +nv50_therm_new(struct nvkm_device *device, int index, + struct nvkm_therm **ptherm) +{ + return nvkm_therm_new_(&nv50_therm, device, index, ptherm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h index 916a149efe6e2..235a5d8daff68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h @@ -1,5 +1,6 @@ #ifndef __NVTHERM_PRIV_H__ #define __NVTHERM_PRIV_H__ +#define nvkm_therm(p) container_of((p), struct nvkm_therm, subdev) /* * Copyright 2012 The Nouveau community * @@ -28,8 +29,9 @@ #include #include #include -#include -#include + +int nvkm_therm_new_(const struct nvkm_therm_func *, struct nvkm_device *, + int index, struct nvkm_therm **); struct nvkm_fan { struct nvkm_therm *parent; @@ -48,59 +50,6 @@ struct nvkm_fan { struct dcb_gpio_func tach; }; -enum nvkm_therm_thrs_direction { - NVKM_THERM_THRS_FALLING = 0, - NVKM_THERM_THRS_RISING = 1 -}; - -enum nvkm_therm_thrs_state { - NVKM_THERM_THRS_LOWER = 0, - NVKM_THERM_THRS_HIGHER = 1 -}; - -enum nvkm_therm_thrs { - NVKM_THERM_THRS_FANBOOST = 0, - NVKM_THERM_THRS_DOWNCLOCK = 1, - NVKM_THERM_THRS_CRITICAL = 2, - NVKM_THERM_THRS_SHUTDOWN = 3, - NVKM_THERM_THRS_NR -}; - -struct nvkm_therm_priv { - struct nvkm_therm base; - - /* automatic thermal management */ - struct nvkm_alarm alarm; - spinlock_t lock; - struct nvbios_therm_trip_point *last_trip; - int mode; - int cstate; - int suspend; - - /* bios */ - struct nvbios_therm_sensor bios_sensor; - - /* fan priv */ - struct nvkm_fan *fan; - - /* alarms priv */ - struct { - spinlock_t alarm_program_lock; - struct nvkm_alarm therm_poll_alarm; - enum nvkm_therm_thrs_state alarm_state[NVKM_THERM_THRS_NR]; - void (*program_alarms)(struct nvkm_therm *); - } sensor; - - /* what should be done if the card overheats */ - struct { - void (*downclock)(struct nvkm_therm *, bool active); - void (*pause)(struct nvkm_therm *, bool active); - } emergency; - - /* ic */ - struct i2c_client *ic; -}; - int nvkm_therm_fan_mode(struct nvkm_therm *, int mode); int nvkm_therm_attr_get(struct nvkm_therm *, enum nvkm_therm_attr_type); int nvkm_therm_attr_set(struct nvkm_therm *, enum nvkm_therm_attr_type, int); @@ -117,8 +66,6 @@ int nvkm_therm_fan_set(struct nvkm_therm *, bool now, int percent); int nvkm_therm_fan_user_get(struct nvkm_therm *); int nvkm_therm_fan_user_set(struct nvkm_therm *, int percent); -int nvkm_therm_fan_sense(struct nvkm_therm *); - int nvkm_therm_preinit(struct nvkm_therm *); int nvkm_therm_sensor_init(struct nvkm_therm *); @@ -134,18 +81,37 @@ void nvkm_therm_sensor_event(struct nvkm_therm *, enum nvkm_therm_thrs, enum nvkm_therm_thrs_direction); void nvkm_therm_program_alarms_polling(struct nvkm_therm *); -void nv40_therm_intr(struct nvkm_subdev *); +struct nvkm_therm_func { + void (*init)(struct nvkm_therm *); + void (*fini)(struct nvkm_therm *); + void (*intr)(struct nvkm_therm *); + + int (*pwm_ctrl)(struct nvkm_therm *, int line, bool); + int (*pwm_get)(struct nvkm_therm *, int line, u32 *, u32 *); + int (*pwm_set)(struct nvkm_therm *, int line, u32, u32); + int (*pwm_clock)(struct nvkm_therm *, int line); + + int (*temp_get)(struct nvkm_therm *); + + int (*fan_sense)(struct nvkm_therm *); + + void (*program_alarms)(struct nvkm_therm *); +}; + +void nv40_therm_intr(struct nvkm_therm *); + int nv50_fan_pwm_ctrl(struct nvkm_therm *, int, bool); int nv50_fan_pwm_get(struct nvkm_therm *, int, u32 *, u32 *); int nv50_fan_pwm_set(struct nvkm_therm *, int, u32, u32); int nv50_fan_pwm_clock(struct nvkm_therm *, int); + int g84_temp_get(struct nvkm_therm *); void g84_sensor_setup(struct nvkm_therm *); -int g84_therm_fini(struct nvkm_object *, bool suspend); +void g84_therm_fini(struct nvkm_therm *); int gt215_therm_fan_sense(struct nvkm_therm *); -int gf110_therm_init(struct nvkm_object *); +void gf119_therm_init(struct nvkm_therm *); int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *); int nvkm_fantog_create(struct nvkm_therm *, struct dcb_gpio_func *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index 2622c4403a73c..4ab7ef7da2547 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -24,10 +24,8 @@ #include "priv.h" static void -nvkm_therm_temp_set_defaults(struct nvkm_therm *obj) +nvkm_therm_temp_set_defaults(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - therm->bios_sensor.offset_constant = 0; therm->bios_sensor.thrs_fan_boost.temp = 90; @@ -43,11 +41,9 @@ nvkm_therm_temp_set_defaults(struct nvkm_therm *obj) therm->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */ } - static void -nvkm_therm_temp_safety_checks(struct nvkm_therm *obj) +nvkm_therm_temp_safety_checks(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvbios_therm_sensor *s = &therm->bios_sensor; /* enforce a minimum hysteresis on thresholds */ @@ -59,20 +55,18 @@ nvkm_therm_temp_safety_checks(struct nvkm_therm *obj) /* must be called with alarm_program_lock taken ! */ void -nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *obj, +nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_state st) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); therm->sensor.alarm_state[thrs] = st; } /* must be called with alarm_program_lock taken ! */ enum nvkm_therm_thrs_state -nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *obj, +nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); return therm->sensor.alarm_state[thrs]; } @@ -84,16 +78,15 @@ nv_poweroff_work(struct work_struct *work) } void -nvkm_therm_sensor_event(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs, +nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs, enum nvkm_therm_thrs_direction dir) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; bool active; const char *thresolds[] = { "fanboost", "downclock", "critical", "shutdown" }; - int temperature = therm->base.temp_get(&therm->base); + int temperature = therm->func->temp_get(therm); if (thrs < 0 || thrs > 3) return; @@ -110,17 +103,17 @@ nvkm_therm_sensor_event(struct nvkm_therm *obj, enum nvkm_therm_thrs thrs, switch (thrs) { case NVKM_THERM_THRS_FANBOOST: if (active) { - nvkm_therm_fan_set(&therm->base, true, 100); - nvkm_therm_fan_mode(&therm->base, NVKM_THERM_CTRL_AUTO); + nvkm_therm_fan_set(therm, true, 100); + nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO); } break; case NVKM_THERM_THRS_DOWNCLOCK: if (therm->emergency.downclock) - therm->emergency.downclock(&therm->base, active); + therm->emergency.downclock(therm, active); break; case NVKM_THERM_THRS_CRITICAL: if (therm->emergency.pause) - therm->emergency.pause(&therm->base, active); + therm->emergency.pause(therm, active); break; case NVKM_THERM_THRS_SHUTDOWN: if (active) { @@ -147,7 +140,7 @@ nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm, { enum nvkm_therm_thrs_direction direction; enum nvkm_therm_thrs_state prev_state, new_state; - int temp = therm->temp_get(therm); + int temp = therm->func->temp_get(therm); prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name); @@ -168,41 +161,40 @@ nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm, static void alarm_timer_callback(struct nvkm_alarm *alarm) { - struct nvkm_therm_priv *therm = - container_of(alarm, struct nvkm_therm_priv, sensor.therm_poll_alarm); + struct nvkm_therm *therm = + container_of(alarm, struct nvkm_therm, sensor.therm_poll_alarm); struct nvbios_therm_sensor *sensor = &therm->bios_sensor; - struct nvkm_timer *tmr = nvkm_timer(therm); + struct nvkm_timer *tmr = therm->subdev.device->timer; unsigned long flags; spin_lock_irqsave(&therm->sensor.alarm_program_lock, flags); - nvkm_therm_threshold_hyst_polling(&therm->base, &sensor->thrs_fan_boost, + nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost, NVKM_THERM_THRS_FANBOOST); - nvkm_therm_threshold_hyst_polling(&therm->base, + nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock, NVKM_THERM_THRS_DOWNCLOCK); - nvkm_therm_threshold_hyst_polling(&therm->base, &sensor->thrs_critical, + nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_critical, NVKM_THERM_THRS_CRITICAL); - nvkm_therm_threshold_hyst_polling(&therm->base, &sensor->thrs_shutdown, + nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown, NVKM_THERM_THRS_SHUTDOWN); spin_unlock_irqrestore(&therm->sensor.alarm_program_lock, flags); /* schedule the next poll in one second */ - if (therm->base.temp_get(&therm->base) >= 0 && list_empty(&alarm->head)) + if (therm->func->temp_get(therm) >= 0 && list_empty(&alarm->head)) tmr->alarm(tmr, 1000000000ULL, alarm); } void -nvkm_therm_program_alarms_polling(struct nvkm_therm *obj) +nvkm_therm_program_alarms_polling(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); struct nvbios_therm_sensor *sensor = &therm->bios_sensor; - nvkm_debug(&therm->base.subdev, + nvkm_debug(&therm->subdev, "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n", sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis, @@ -217,19 +209,16 @@ nvkm_therm_program_alarms_polling(struct nvkm_therm *obj) } int -nvkm_therm_sensor_init(struct nvkm_therm *obj) +nvkm_therm_sensor_init(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - therm->sensor.program_alarms(&therm->base); + therm->func->program_alarms(therm); return 0; } int -nvkm_therm_sensor_fini(struct nvkm_therm *obj, bool suspend) +nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_timer *tmr = nvkm_timer(therm); - + struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) tmr->alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); return 0; @@ -240,26 +229,25 @@ nvkm_therm_sensor_preinit(struct nvkm_therm *therm) { const char *sensor_avail = "yes"; - if (therm->temp_get(therm) < 0) + if (therm->func->temp_get(therm) < 0) sensor_avail = "no"; nvkm_debug(&therm->subdev, "internal sensor: %s\n", sensor_avail); } int -nvkm_therm_sensor_ctor(struct nvkm_therm *obj) +nvkm_therm_sensor_ctor(struct nvkm_therm *therm) { - struct nvkm_therm_priv *therm = container_of(obj, typeof(*therm), base); - struct nvkm_subdev *subdev = &therm->base.subdev; + struct nvkm_subdev *subdev = &therm->subdev; struct nvkm_bios *bios = subdev->device->bios; nvkm_alarm_init(&therm->sensor.therm_poll_alarm, alarm_timer_callback); - nvkm_therm_temp_set_defaults(&therm->base); + nvkm_therm_temp_set_defaults(therm); if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE, &therm->bios_sensor)) nvkm_error(subdev, "nvbios_therm_sensor_parse failed\n"); - nvkm_therm_temp_safety_checks(&therm->base); + nvkm_therm_temp_safety_checks(therm); return 0; } -- GitLab From 31649ecf47a44e02e73bffc5680c8f56d6cf587a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5547/7006] drm/nouveau/tmr: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/timer.h | 54 ++--- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++++------ .../drm/nouveau/nvkm/engine/device/gf100.c | 9 - .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c | 7 +- .../gpu/drm/nouveau/nvkm/subdev/therm/base.c | 6 +- .../gpu/drm/nouveau/nvkm/subdev/therm/fan.c | 12 +- .../drm/nouveau/nvkm/subdev/therm/fantog.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/therm/temp.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/timer/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/subdev/timer/base.c | 127 +++++++++- .../gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c | 45 +--- .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.c | 227 +++++------------- .../gpu/drm/nouveau/nvkm/subdev/timer/nv04.h | 25 -- .../gpu/drm/nouveau/nvkm/subdev/timer/nv40.c | 88 +++++++ .../gpu/drm/nouveau/nvkm/subdev/timer/nv41.c | 85 +++++++ .../gpu/drm/nouveau/nvkm/subdev/timer/priv.h | 22 ++ .../drm/nouveau/nvkm/subdev/timer/regsnv04.h | 7 + 27 files changed, 501 insertions(+), 427 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h index f818adcc74670..62ed0880b0e1f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h @@ -9,15 +9,23 @@ struct nvkm_alarm { }; static inline void -nvkm_alarm_init(struct nvkm_alarm *alarm, - void (*func)(struct nvkm_alarm *)) +nvkm_alarm_init(struct nvkm_alarm *alarm, void (*func)(struct nvkm_alarm *)) { INIT_LIST_HEAD(&alarm->head); alarm->func = func; } -void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *); -void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *); +struct nvkm_timer { + const struct nvkm_timer_func *func; + struct nvkm_subdev subdev; + + struct list_head alarms; + spinlock_t lock; +}; + +u64 nvkm_timer_read(struct nvkm_timer *); +void nvkm_timer_alarm(struct nvkm_timer *, u32 nsec, struct nvkm_alarm *); +void nvkm_timer_alarm_cancel(struct nvkm_timer *, struct nvkm_alarm *); /* Delay based on GPU time (ie. PTIMER). * @@ -31,13 +39,13 @@ void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *); #define nvkm_nsec(d,n,cond...) ({ \ struct nvkm_device *_device = (d); \ struct nvkm_timer *_tmr = _device->timer; \ - u64 _nsecs = (n), _time0 = _tmr->read(_tmr); \ + u64 _nsecs = (n), _time0 = nvkm_timer_read(_tmr); \ s64 _taken = 0; \ - bool _warn = true; \ + bool _warn = true; \ \ do { \ cond \ - } while (_taken = _tmr->read(_tmr) - _time0, _taken < _nsecs); \ + } while (_taken = nvkm_timer_read(_tmr) - _time0, _taken < _nsecs); \ \ if (_taken >= _nsecs) { \ if (_warn) { \ @@ -51,32 +59,8 @@ void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *); #define nvkm_usec(d,u,cond...) nvkm_nsec((d), (u) * 1000, ##cond) #define nvkm_msec(d,m,cond...) nvkm_usec((d), (m) * 1000, ##cond) -struct nvkm_timer { - struct nvkm_subdev subdev; - u64 (*read)(struct nvkm_timer *); - void (*alarm)(struct nvkm_timer *, u64 time, struct nvkm_alarm *); - void (*alarm_cancel)(struct nvkm_timer *, struct nvkm_alarm *); -}; - -static inline struct nvkm_timer * -nvkm_timer(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_TIMER); -} - -#define nvkm_timer_create(p,e,o,d) \ - nvkm_subdev_create_((p), (e), (o), 0, "PTIMER", "timer", \ - sizeof(**d), (void **)d) -#define nvkm_timer_destroy(p) \ - nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_timer_init(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_timer_fini(p,s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) - -int nvkm_timer_create_(struct nvkm_object *, struct nvkm_engine *, - struct nvkm_oclass *, int size, void **); - -extern struct nvkm_oclass nv04_timer_oclass; -extern struct nvkm_oclass gk20a_timer_oclass; +int nv04_timer_new(struct nvkm_device *, int, struct nvkm_timer **); +int nv40_timer_new(struct nvkm_device *, int, struct nvkm_timer **); +int nv41_timer_new(struct nvkm_device *, int, struct nvkm_timer **); +int gk20a_timer_new(struct nvkm_device *, int, struct nvkm_timer **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3734d1fb77562..04895322d371a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -85,7 +85,7 @@ nv4_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv04_fifo_new, @@ -105,7 +105,7 @@ nv5_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv04_fifo_new, @@ -126,7 +126,7 @@ nv10_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .gr = nv10_gr_new, @@ -145,7 +145,7 @@ nv11_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv10_fifo_new, @@ -166,7 +166,7 @@ nv15_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv10_fifo_new, @@ -187,7 +187,7 @@ nv17_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -208,7 +208,7 @@ nv18_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -229,7 +229,7 @@ nv1a_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv10_fifo_new, @@ -250,7 +250,7 @@ nv1f_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -271,7 +271,7 @@ nv20_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -292,7 +292,7 @@ nv25_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -313,7 +313,7 @@ nv28_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -334,7 +334,7 @@ nv2a_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -355,7 +355,7 @@ nv30_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -376,7 +376,7 @@ nv31_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -398,7 +398,7 @@ nv34_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -420,7 +420,7 @@ nv35_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -441,7 +441,7 @@ nv36_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, -// .timer = nv04_timer_new, + .timer = nv04_timer_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv17_fifo_new, @@ -464,7 +464,7 @@ nv40_chipset = { .mc = nv40_mc_new, .mmu = nv04_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv40_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -489,7 +489,7 @@ nv41_chipset = { .mc = nv40_mc_new, .mmu = nv41_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -514,7 +514,7 @@ nv42_chipset = { .mc = nv40_mc_new, .mmu = nv41_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -539,7 +539,7 @@ nv43_chipset = { .mc = nv40_mc_new, .mmu = nv41_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -564,7 +564,7 @@ nv44_chipset = { .mc = nv44_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -589,7 +589,7 @@ nv45_chipset = { .mc = nv40_mc_new, .mmu = nv04_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -614,7 +614,7 @@ nv46_chipset = { .mc = nv44_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -639,7 +639,7 @@ nv47_chipset = { .mc = nv40_mc_new, .mmu = nv41_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -664,7 +664,7 @@ nv49_chipset = { .mc = nv40_mc_new, .mmu = nv41_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -689,7 +689,7 @@ nv4a_chipset = { .mc = nv44_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -714,7 +714,7 @@ nv4b_chipset = { .mc = nv40_mc_new, .mmu = nv41_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -739,7 +739,7 @@ nv4c_chipset = { .mc = nv4c_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -764,7 +764,7 @@ nv4e_chipset = { .mc = nv4c_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -792,7 +792,7 @@ nv50_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = nv50_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv50_disp_new, // .dma = nv50_dma_new, @@ -817,7 +817,7 @@ nv63_chipset = { .mc = nv4c_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -842,7 +842,7 @@ nv67_chipset = { .mc = nv4c_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -867,7 +867,7 @@ nv68_chipset = { .mc = nv4c_mc_new, .mmu = nv44_mmu_new, .therm = nv40_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, @@ -895,7 +895,7 @@ nv84_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, @@ -926,7 +926,7 @@ nv86_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, @@ -957,7 +957,7 @@ nv92_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, @@ -988,7 +988,7 @@ nv94_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, @@ -1015,7 +1015,7 @@ nv96_chipset = { .devinit = g84_devinit_new, .mc = g94_mc_new, .bus = g94_bus_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, .fb = g84_fb_new, .imem = nv50_instmem_new, .mmu = nv50_mmu_new, @@ -1046,7 +1046,7 @@ nv98_chipset = { .devinit = g98_devinit_new, .mc = g98_mc_new, .bus = g94_bus_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, .fb = g84_fb_new, .imem = nv50_instmem_new, .mmu = nv50_mmu_new, @@ -1081,7 +1081,7 @@ nva0_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, @@ -1113,7 +1113,7 @@ nva3_chipset = { .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, @@ -1146,7 +1146,7 @@ nva5_chipset = { .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, @@ -1178,7 +1178,7 @@ nva8_chipset = { .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, @@ -1209,7 +1209,7 @@ nvaa_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = g94_disp_new, // .dma = nv50_dma_new, @@ -1240,7 +1240,7 @@ nvac_chipset = { .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .therm = g84_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .disp = g94_disp_new, // .dma = nv50_dma_new, @@ -1272,7 +1272,7 @@ nvaf_chipset = { .mxm = nv50_mxm_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, @@ -1306,7 +1306,7 @@ nvc0_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, @@ -1341,7 +1341,7 @@ nvc1_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gt215_disp_new, @@ -1375,7 +1375,7 @@ nvc3_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gt215_disp_new, @@ -1409,7 +1409,7 @@ nvc4_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, @@ -1444,7 +1444,7 @@ nvc8_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, @@ -1479,7 +1479,7 @@ nvce_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, @@ -1514,7 +1514,7 @@ nvcf_chipset = { .mxm = nv50_mxm_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gt215_disp_new, @@ -1547,7 +1547,7 @@ nvd7_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .ce[0] = gf100_ce0_new, // .disp = gf119_disp_new, // .dma = gf119_dma_new, @@ -1580,7 +1580,7 @@ nvd9_chipset = { .mxm = nv50_mxm_new, .pmu = gf119_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gf119_disp_new, @@ -1614,7 +1614,7 @@ nve4_chipset = { .mxm = nv50_mxm_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1650,7 +1650,7 @@ nve6_chipset = { .mxm = nv50_mxm_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1686,7 +1686,7 @@ nve7_chipset = { .mxm = nv50_mxm_new, .pmu = gf119_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1716,7 +1716,7 @@ nvea_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .pmu = gk20a_pmu_new, -// .timer = gk20a_timer_new, + .timer = gk20a_timer_new, // .volt = gk20a_volt_new, // .ce[2] = gk104_ce2_new, // .dma = gf119_dma_new, @@ -1746,7 +1746,7 @@ nvf0_chipset = { .mxm = nv50_mxm_new, .pmu = gk110_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1782,7 +1782,7 @@ nvf1_chipset = { .mxm = nv50_mxm_new, .pmu = gk110_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1818,7 +1818,7 @@ nv106_chipset = { .mxm = nv50_mxm_new, .pmu = gk208_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1853,7 +1853,7 @@ nv108_chipset = { .mxm = nv50_mxm_new, .pmu = gk208_pmu_new, .therm = gf119_therm_new, -// .timer = nv04_timer_new, + .timer = nv41_timer_new, // .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, @@ -1888,7 +1888,7 @@ nv117_chipset = { .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, .therm = gm107_therm_new, -// .timer = gk20a_timer_new, + .timer = gk20a_timer_new, // .ce[0] = gk104_ce0_new, // .ce[2] = gk104_ce2_new, // .disp = gm107_disp_new, @@ -1916,7 +1916,7 @@ nv124_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, -// .timer = gk20a_timer_new, + .timer = gk20a_timer_new, // .ce[0] = gm204_ce0_new, // .ce[1] = gm204_ce1_new, // .ce[2] = gm204_ce2_new, @@ -1945,7 +1945,7 @@ nv126_chipset = { .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, -// .timer = gk20a_timer_new, + .timer = gk20a_timer_new, // .ce[0] = gm204_ce0_new, // .ce[1] = gm204_ce1_new, // .ce[2] = gm204_ce2_new, @@ -1969,7 +1969,7 @@ nv12b_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mmu = gf100_mmu_new, -// .timer = gk20a_timer_new, + .timer = gk20a_timer_new, // .ce[2] = gm204_ce2_new, // .dma = gf119_dma_new, // .fifo = gm20b_fifo_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index dcaa480cd3101..28421e6f1f268 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -43,7 +42,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -58,7 +56,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -72,7 +69,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -87,7 +83,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -101,7 +96,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -115,7 +109,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -130,7 +123,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; @@ -144,7 +136,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 048f1beab81d9..25d9092455aa0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -44,7 +43,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -60,7 +58,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -76,7 +73,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -86,7 +82,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; break; case 0xf0: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -102,7 +97,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; @@ -118,7 +112,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; @@ -133,7 +126,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index e2d00b465b80e..4b570a27e13af 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -28,7 +28,6 @@ gm100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x117: - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; @@ -54,7 +53,6 @@ gm100_identify(struct nvkm_device *device) /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ #endif - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif @@ -77,7 +75,6 @@ gm100_identify(struct nvkm_device *device) /* looks to be some non-trivial changes */ /* priv ring says no to 0x10eb14 writes */ #endif - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; #if 0 device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif @@ -97,7 +94,6 @@ gm100_identify(struct nvkm_device *device) break; case 0x12b: - device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 99e837f4879e0..1b2ebda82c1fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,7 +28,6 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; @@ -36,7 +35,6 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 6f106f632e635..c5ecdddfbce38 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,13 +28,11 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -42,7 +40,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -50,7 +47,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -58,7 +54,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -66,7 +61,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -74,7 +68,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -82,7 +75,6 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 2a84c3ff85388..104ed4f093b5e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,7 +28,6 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -36,7 +35,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -44,7 +42,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -52,7 +49,6 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index b03249099bb5a..5ea263c850438 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,7 +28,6 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -36,7 +35,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -44,7 +42,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -53,7 +50,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -62,7 +58,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 5aa4cac00402b..31df1b8ae7054 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -39,7 +38,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -50,7 +48,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -61,7 +58,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -72,7 +68,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -83,7 +78,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -94,7 +88,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -105,7 +98,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -116,7 +108,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -127,7 +118,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -138,7 +128,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -149,7 +138,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -160,7 +148,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -171,7 +158,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -182,7 +168,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; @@ -193,7 +178,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 8cc924046b785..e01add48ceb3e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; @@ -39,7 +38,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -53,7 +51,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -67,7 +64,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -81,7 +77,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -95,7 +90,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -109,7 +103,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -123,7 +116,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -137,7 +129,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -151,7 +142,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -165,7 +155,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -180,7 +169,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -194,7 +182,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; @@ -208,7 +195,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass; device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index c5da091c058ca..a9df61bf37807 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -118,14 +118,13 @@ static int nvkm_udevice_time(struct nvkm_udevice *udev, void *data, u32 size) { struct nvkm_device *device = udev->device; - struct nvkm_timer *tmr = device->timer; union { struct nv_device_time_v0 v0; } *args = data; int ret; if (nvif_unpack(args->v0, 0, 0, false)) { - args->v0.time = tmr->read(tmr); + args->v0.time = nvkm_timer_read(device->timer); } return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 403d2c9aff3b5..2a5bc9270fb9c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -218,7 +218,7 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) spin_lock_irqsave(&gr->lock, flags); nvkm_mask(device, 0x400500, 0x00000001, 0x00000000); - start = tmr->read(tmr); + start = nvkm_timer_read(tmr); do { idle = true; @@ -237,7 +237,7 @@ g84_gr_tlb_flush(struct nvkm_engine *engine) idle = false; } } while (!idle && - !(timeout = tmr->read(tmr) - start > 2000000000)); + !(timeout = nvkm_timer_read(tmr) - start > 2000000000)); if (timeout) { nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c index 860c8bc2b4220..6689d0290a7e2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c @@ -124,6 +124,7 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) struct nvkm_subdev *subdev = &pmu->base.subdev; struct nvkm_device *device = subdev->device; struct nvkm_clk *clk = device->clk; + struct nvkm_timer *tmr = device->timer; struct nvkm_volt *volt = device->volt; u32 utilization = 0; int state, ret; @@ -162,14 +163,14 @@ gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm) resched: gk20a_pmu_dvfs_reset_dev_status(pmu); - nvkm_timer_alarm(pmu, 100000000, alarm); + nvkm_timer_alarm(tmr, 100000000, alarm); } static int gk20a_pmu_fini(struct nvkm_subdev *subdev, bool suspend) { struct gk20a_pmu *pmu = gk20a_pmu(subdev); - nvkm_timer_alarm_cancel(pmu, &pmu->alarm); + nvkm_timer_alarm_cancel(subdev->device->timer, &pmu->alarm); return 0; } @@ -190,7 +191,7 @@ gk20a_pmu_init(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002); nvkm_wr32(device, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003); - nvkm_timer_alarm(pmu, 2000000000, &pmu->alarm); + nvkm_timer_alarm(device->timer, 2000000000, &pmu->alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c index 304bdfc54445b..949dc6101a58b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c @@ -102,7 +102,7 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) switch (mode) { case NVKM_THERM_CTRL_MANUAL: - tmr->alarm_cancel(tmr, &therm->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->alarm); duty = nvkm_therm_fan_get(therm); if (duty < 0) duty = 100; @@ -126,12 +126,12 @@ nvkm_therm_update(struct nvkm_therm *therm, int mode) break; case NVKM_THERM_CTRL_NONE: default: - tmr->alarm_cancel(tmr, &therm->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->alarm); poll = false; } if (list_empty(&therm->alarm.head) && poll) - tmr->alarm(tmr, 1000000000ULL, &therm->alarm); + nvkm_timer_alarm(tmr, 1000000000ULL, &therm->alarm); spin_unlock_irqrestore(&therm->lock, flags); if (duty >= 0) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c index a2be181677700..91198d79393ac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c @@ -95,7 +95,7 @@ nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target) else delay = bump_period; - tmr->alarm(tmr, delay * 1000 * 1000, &fan->alarm); + nvkm_timer_alarm(tmr, delay * 1000 * 1000, &fan->alarm); } return ret; @@ -139,7 +139,7 @@ nvkm_therm_fan_sense(struct nvkm_therm *therm) * When the fan spins, it changes the value of GPIO FAN_SENSE. * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation. */ - start = tmr->read(tmr); + start = nvkm_timer_read(tmr); prev = nvkm_gpio_get(gpio, 0, therm->fan->tach.func, therm->fan->tach.line); cycles = 0; @@ -150,12 +150,12 @@ nvkm_therm_fan_sense(struct nvkm_therm *therm) therm->fan->tach.line); if (prev != cur) { if (!start) - start = tmr->read(tmr); + start = nvkm_timer_read(tmr); cycles++; prev = cur; } - } while (cycles < 5 && tmr->read(tmr) - start < 250000000); - end = tmr->read(tmr); + } while (cycles < 5 && nvkm_timer_read(tmr) - start < 250000000); + end = nvkm_timer_read(tmr); if (cycles == 5) { tach = (u64)60000000000ULL; @@ -215,7 +215,7 @@ nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend) { struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - tmr->alarm_cancel(tmr, &therm->fan->alarm); + nvkm_timer_alarm_cancel(tmr, &therm->fan->alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c index 64fe8f22336c8..59701b7a65975 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c @@ -57,7 +57,7 @@ nvkm_fantog_update(struct nvkm_fantog *fan, int percent) u64 next_change = (percent * fan->period_us) / 100; if (!duty) next_change = fan->period_us - next_change; - tmr->alarm(tmr, next_change * 1000, &fan->alarm); + nvkm_timer_alarm(tmr, next_change * 1000, &fan->alarm); } spin_unlock_irqrestore(&fan->lock, flags); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c index 4ab7ef7da2547..b9703c02d8ca7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c @@ -186,7 +186,7 @@ alarm_timer_callback(struct nvkm_alarm *alarm) /* schedule the next poll in one second */ if (therm->func->temp_get(therm) >= 0 && list_empty(&alarm->head)) - tmr->alarm(tmr, 1000000000ULL, alarm); + nvkm_timer_alarm(tmr, 1000000000ULL, alarm); } void @@ -220,7 +220,7 @@ nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend) { struct nvkm_timer *tmr = therm->subdev.device->timer; if (suspend) - tmr->alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); + nvkm_timer_alarm_cancel(tmr, &therm->sensor.therm_poll_alarm); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild index d1d38b4ba30ac..e436f0ffe3f4c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild @@ -1,3 +1,5 @@ nvkm-y += nvkm/subdev/timer/base.o nvkm-y += nvkm/subdev/timer/nv04.o +nvkm-y += nvkm/subdev/timer/nv40.o +nvkm-y += nvkm/subdev/timer/nv41.o nvkm-y += nvkm/subdev/timer/gk20a.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c index 4c34e2bd0487d..d4dae1f12d622 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c @@ -21,18 +21,131 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" + +u64 +nvkm_timer_read(struct nvkm_timer *tmr) +{ + return tmr->func->read(tmr); +} + +void +nvkm_timer_alarm_trigger(struct nvkm_timer *tmr) +{ + struct nvkm_alarm *alarm, *atemp; + unsigned long flags; + LIST_HEAD(exec); + + /* move any due alarms off the pending list */ + spin_lock_irqsave(&tmr->lock, flags); + list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) { + if (alarm->timestamp <= nvkm_timer_read(tmr)) + list_move_tail(&alarm->head, &exec); + } + + /* reschedule interrupt for next alarm time */ + if (!list_empty(&tmr->alarms)) { + alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); + tmr->func->alarm_init(tmr, alarm->timestamp); + } else { + tmr->func->alarm_fini(tmr); + } + spin_unlock_irqrestore(&tmr->lock, flags); + + /* execute any pending alarm handlers */ + list_for_each_entry_safe(alarm, atemp, &exec, head) { + list_del_init(&alarm->head); + alarm->func(alarm); + } +} void -nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm) +nvkm_timer_alarm(struct nvkm_timer *tmr, u32 nsec, struct nvkm_alarm *alarm) { - struct nvkm_timer *tmr = nvkm_timer(obj); - tmr->alarm(tmr, nsec, alarm); + struct nvkm_alarm *list; + unsigned long flags; + + alarm->timestamp = nvkm_timer_read(tmr) + nsec; + + /* append new alarm to list, in soonest-alarm-first order */ + spin_lock_irqsave(&tmr->lock, flags); + if (!nsec) { + if (!list_empty(&alarm->head)) + list_del(&alarm->head); + } else { + list_for_each_entry(list, &tmr->alarms, head) { + if (list->timestamp > alarm->timestamp) + break; + } + list_add_tail(&alarm->head, &list->head); + } + spin_unlock_irqrestore(&tmr->lock, flags); + + /* process pending alarms */ + nvkm_timer_alarm_trigger(tmr); } void -nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm) +nvkm_timer_alarm_cancel(struct nvkm_timer *tmr, struct nvkm_alarm *alarm) +{ + unsigned long flags; + spin_lock_irqsave(&tmr->lock, flags); + list_del_init(&alarm->head); + spin_unlock_irqrestore(&tmr->lock, flags); +} + +static void +nvkm_timer_intr(struct nvkm_subdev *subdev) { - struct nvkm_timer *tmr = nvkm_timer(obj); - tmr->alarm_cancel(tmr, alarm); + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->intr(tmr); +} + +static int +nvkm_timer_fini(struct nvkm_subdev *subdev, bool suspend) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + tmr->func->alarm_fini(tmr); + return 0; +} + +static int +nvkm_timer_init(struct nvkm_subdev *subdev) +{ + struct nvkm_timer *tmr = nvkm_timer(subdev); + if (tmr->func->init) + tmr->func->init(tmr); + tmr->func->time(tmr, ktime_to_ns(ktime_get())); + nvkm_timer_alarm_trigger(tmr); + return 0; +} + +static void * +nvkm_timer_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_timer(subdev); +} + +static const struct nvkm_subdev_func +nvkm_timer = { + .dtor = nvkm_timer_dtor, + .init = nvkm_timer_init, + .fini = nvkm_timer_fini, + .intr = nvkm_timer_intr, +}; + +int +nvkm_timer_new_(const struct nvkm_timer_func *func, struct nvkm_device *device, + int index, struct nvkm_timer **ptmr) +{ + struct nvkm_timer *tmr; + + if (!(tmr = *ptmr = kzalloc(sizeof(*tmr), GFP_KERNEL))) + return -ENOMEM; + + nvkm_subdev_ctor(&nvkm_timer, device, index, 0, &tmr->subdev); + tmr->func = func; + INIT_LIST_HEAD(&tmr->alarms); + spin_lock_init(&tmr->lock); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c index 46bfa10b5b97c..9ed5f64912d0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c @@ -21,38 +21,19 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" -static int -gk20a_timer_init(struct nvkm_object *object) -{ - struct nv04_timer *tmr = (void *)object; - struct nvkm_subdev *subdev = &tmr->base.subdev; - struct nvkm_device *device = subdev->device; - u32 hi = upper_32_bits(tmr->suspend_time); - u32 lo = lower_32_bits(tmr->suspend_time); - int ret; - - ret = nvkm_timer_init(&tmr->base); - if (ret) - return ret; - - nvkm_debug(subdev, "time low : %08x\n", lo); - nvkm_debug(subdev, "time high : %08x\n", hi); +static const struct nvkm_timer_func +gk20a_timer = { + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; - /* restore the time before suspend */ - nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); - nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); - return 0; +int +gk20a_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&gk20a_timer, device, index, ptmr); } - -struct nvkm_oclass -gk20a_timer_oclass = { - .handle = NV_SUBDEV(TIMER, 0xff), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_timer_ctor, - .dtor = nv04_timer_dtor, - .init = gk20a_timer_init, - .fini = nv04_timer_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c index 8d45753f65acb..7b9ce87f06176 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c @@ -21,9 +21,25 @@ * * Authors: Ben Skeggs */ -#include "nv04.h" +#include "priv.h" +#include "regsnv04.h" -static u64 +void +nv04_timer_time(struct nvkm_timer *tmr, u64 time) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 hi = upper_32_bits(time); + u32 lo = lower_32_bits(time); + + nvkm_debug(subdev, "time low : %08x\n", lo); + nvkm_debug(subdev, "time high : %08x\n", hi); + + nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); + nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); +} + +u64 nv04_timer_read(struct nvkm_timer *tmr) { struct nvkm_device *device = tmr->subdev.device; @@ -37,85 +53,30 @@ nv04_timer_read(struct nvkm_timer *tmr) return ((u64)hi << 32 | lo); } -static void -nv04_timer_alarm_trigger(struct nvkm_timer *obj) -{ - struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); - struct nvkm_device *device = tmr->base.subdev.device; - struct nvkm_alarm *alarm, *atemp; - unsigned long flags; - LIST_HEAD(exec); - - /* move any due alarms off the pending list */ - spin_lock_irqsave(&tmr->lock, flags); - list_for_each_entry_safe(alarm, atemp, &tmr->alarms, head) { - if (alarm->timestamp <= tmr->base.read(&tmr->base)) - list_move_tail(&alarm->head, &exec); - } - - /* reschedule interrupt for next alarm time */ - if (!list_empty(&tmr->alarms)) { - alarm = list_first_entry(&tmr->alarms, typeof(*alarm), head); - nvkm_wr32(device, NV04_PTIMER_ALARM_0, alarm->timestamp); - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); - } else { - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); - } - spin_unlock_irqrestore(&tmr->lock, flags); - - /* execute any pending alarm handlers */ - list_for_each_entry_safe(alarm, atemp, &exec, head) { - list_del_init(&alarm->head); - alarm->func(alarm); - } -} - -static void -nv04_timer_alarm(struct nvkm_timer *obj, u64 time, struct nvkm_alarm *alarm) +void +nv04_timer_alarm_fini(struct nvkm_timer *tmr) { - struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); - struct nvkm_alarm *list; - unsigned long flags; - - alarm->timestamp = tmr->base.read(&tmr->base) + time; - - /* append new alarm to list, in soonest-alarm-first order */ - spin_lock_irqsave(&tmr->lock, flags); - if (!time) { - if (!list_empty(&alarm->head)) - list_del(&alarm->head); - } else { - list_for_each_entry(list, &tmr->alarms, head) { - if (list->timestamp > alarm->timestamp) - break; - } - list_add_tail(&alarm->head, &list->head); - } - spin_unlock_irqrestore(&tmr->lock, flags); - - /* process pending alarms */ - nv04_timer_alarm_trigger(&tmr->base); + struct nvkm_device *device = tmr->subdev.device; + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); } -static void -nv04_timer_alarm_cancel(struct nvkm_timer *obj, struct nvkm_alarm *alarm) +void +nv04_timer_alarm_init(struct nvkm_timer *tmr, u32 time) { - struct nv04_timer *tmr = container_of(obj, typeof(*tmr), base); - unsigned long flags; - spin_lock_irqsave(&tmr->lock, flags); - list_del_init(&alarm->head); - spin_unlock_irqrestore(&tmr->lock, flags); + struct nvkm_device *device = tmr->subdev.device; + nvkm_wr32(device, NV04_PTIMER_ALARM_0, time); + nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000001); } -static void -nv04_timer_intr(struct nvkm_subdev *subdev) +void +nv04_timer_intr(struct nvkm_timer *tmr) { - struct nv04_timer *tmr = (void *)subdev; - struct nvkm_device *device = tmr->base.subdev.device; + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, NV04_PTIMER_INTR_0); if (stat & 0x00000001) { - nv04_timer_alarm_trigger(&tmr->base); + nvkm_timer_alarm_trigger(tmr); nvkm_wr32(device, NV04_PTIMER_INTR_0, 0x00000001); stat &= ~0x00000001; } @@ -126,62 +87,26 @@ nv04_timer_intr(struct nvkm_subdev *subdev) } } -int -nv04_timer_fini(struct nvkm_object *object, bool suspend) -{ - struct nv04_timer *tmr = (void *)object; - struct nvkm_device *device = tmr->base.subdev.device; - if (suspend) - tmr->suspend_time = nv04_timer_read(&tmr->base); - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); - return nvkm_timer_fini(&tmr->base, suspend); -} - -static int -nv04_timer_init(struct nvkm_object *object) +static void +nv04_timer_init(struct nvkm_timer *tmr) { - struct nv04_timer *tmr = (void *)object; - struct nvkm_subdev *subdev = &tmr->base.subdev; + struct nvkm_subdev *subdev = &tmr->subdev; struct nvkm_device *device = subdev->device; - u32 m = 1, f, n, d, lo, hi; - int ret; - - ret = nvkm_timer_init(&tmr->base); - if (ret) - return ret; + u32 f = 0; /*XXX: nvclk */ + u32 n, d; /* aim for 31.25MHz, which gives us nanosecond timestamps */ d = 1000000 / 32; - - /* determine base clock for timer source */ -#if 0 /*XXX*/ - if (device->chipset < 0x40) { - n = nvkm_hw_get_clock(device, PLL_CORE); - } else -#endif - if (device->chipset <= 0x40) { - /*XXX: figure this out */ - f = -1; - n = 0; - } else { - f = device->crystal; - n = f; - while (n < (d * 2)) { - n += (n / m); - m++; + n = f; + + if (!f) { + n = nvkm_rd32(device, NV04_PTIMER_NUMERATOR); + d = nvkm_rd32(device, NV04_PTIMER_DENOMINATOR); + if (!n || !d) { + n = 1; + d = 1; } - - nvkm_wr32(device, 0x009220, m - 1); - } - - if (!n) { nvkm_warn(subdev, "unknown input clock freq\n"); - if (!nvkm_rd32(device, NV04_PTIMER_NUMERATOR) || - !nvkm_rd32(device, NV04_PTIMER_DENOMINATOR)) { - nvkm_wr32(device, NV04_PTIMER_NUMERATOR, 1); - nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, 1); - } - return 0; } /* reduce ratio to acceptable values */ @@ -200,65 +125,27 @@ nv04_timer_init(struct nvkm_object *object) d >>= 1; } - /* restore the time before suspend */ - lo = tmr->suspend_time; - hi = (tmr->suspend_time >> 32); - nvkm_debug(subdev, "input frequency : %dHz\n", f); - nvkm_debug(subdev, "input multiplier: %d\n", m); nvkm_debug(subdev, "numerator : %08x\n", n); nvkm_debug(subdev, "denominator : %08x\n", d); - nvkm_debug(subdev, "timer frequency : %dHz\n", (f * m) * d / n); - nvkm_debug(subdev, "time low : %08x\n", lo); - nvkm_debug(subdev, "time high : %08x\n", hi); + nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); - nvkm_wr32(device, NV04_PTIMER_INTR_0, 0xffffffff); - nvkm_wr32(device, NV04_PTIMER_INTR_EN_0, 0x00000000); - nvkm_wr32(device, NV04_PTIMER_TIME_1, hi); - nvkm_wr32(device, NV04_PTIMER_TIME_0, lo); - return 0; } -void -nv04_timer_dtor(struct nvkm_object *object) -{ - struct nv04_timer *tmr = (void *)object; - return nvkm_timer_destroy(&tmr->base); -} +static const struct nvkm_timer_func +nv04_timer = { + .init = nv04_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; int -nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv04_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) { - struct nv04_timer *tmr; - int ret; - - ret = nvkm_timer_create(parent, engine, oclass, &tmr); - *pobject = nv_object(tmr); - if (ret) - return ret; - - tmr->base.subdev.intr = nv04_timer_intr; - tmr->base.read = nv04_timer_read; - tmr->base.alarm = nv04_timer_alarm; - tmr->base.alarm_cancel = nv04_timer_alarm_cancel; - tmr->suspend_time = 0; - - INIT_LIST_HEAD(&tmr->alarms); - spin_lock_init(&tmr->lock); - return 0; + return nvkm_timer_new_(&nv04_timer, device, index, ptmr); } - -struct nvkm_oclass -nv04_timer_oclass = { - .handle = NV_SUBDEV(TIMER, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_timer_ctor, - .dtor = nv04_timer_dtor, - .init = nv04_timer_init, - .fini = nv04_timer_fini, - } -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h deleted file mode 100644 index 1bc0d7c073ef1..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef __NVKM_TIMER_NV04_H__ -#define __NVKM_TIMER_NV04_H__ -#include "priv.h" - -#define NV04_PTIMER_INTR_0 0x009100 -#define NV04_PTIMER_INTR_EN_0 0x009140 -#define NV04_PTIMER_NUMERATOR 0x009200 -#define NV04_PTIMER_DENOMINATOR 0x009210 -#define NV04_PTIMER_TIME_0 0x009400 -#define NV04_PTIMER_TIME_1 0x009410 -#define NV04_PTIMER_ALARM_0 0x009420 - -struct nv04_timer { - struct nvkm_timer base; - struct list_head alarms; - spinlock_t lock; - u64 suspend_time; -}; - -int nv04_timer_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv04_timer_dtor(struct nvkm_object *); -int nv04_timer_fini(struct nvkm_object *, bool); -#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c new file mode 100644 index 0000000000000..bb99a152f26e6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv40.c @@ -0,0 +1,88 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "regsnv04.h" + +static void +nv40_timer_init(struct nvkm_timer *tmr) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = 0; /*XXX: figure this out */ + u32 n, d; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + n = f; + + if (!f) { + n = nvkm_rd32(device, NV04_PTIMER_NUMERATOR); + d = nvkm_rd32(device, NV04_PTIMER_DENOMINATOR); + if (!n || !d) { + n = 1; + d = 1; + } + nvkm_warn(subdev, "unknown input clock freq\n"); + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", f * d / n); + + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); +} + +static const struct nvkm_timer_func +nv40_timer = { + .init = nv40_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; + +int +nv40_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&nv40_timer, device, index, ptmr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c new file mode 100644 index 0000000000000..3cf9ec1b1b57c --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv41.c @@ -0,0 +1,85 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" +#include "regsnv04.h" + +static void +nv41_timer_init(struct nvkm_timer *tmr) +{ + struct nvkm_subdev *subdev = &tmr->subdev; + struct nvkm_device *device = subdev->device; + u32 f = device->crystal; + u32 m = 1, n, d; + + /* aim for 31.25MHz, which gives us nanosecond timestamps */ + d = 1000000 / 32; + n = f; + + while (n < (d * 2)) { + n += (n / m); + m++; + } + + /* reduce ratio to acceptable values */ + while (((n % 5) == 0) && ((d % 5) == 0)) { + n /= 5; + d /= 5; + } + + while (((n % 2) == 0) && ((d % 2) == 0)) { + n /= 2; + d /= 2; + } + + while (n > 0xffff || d > 0xffff) { + n >>= 1; + d >>= 1; + } + + nvkm_debug(subdev, "input frequency : %dHz\n", f); + nvkm_debug(subdev, "input multiplier: %d\n", m); + nvkm_debug(subdev, "numerator : %08x\n", n); + nvkm_debug(subdev, "denominator : %08x\n", d); + nvkm_debug(subdev, "timer frequency : %dHz\n", (f * m) * d / n); + + nvkm_wr32(device, 0x009220, m - 1); + nvkm_wr32(device, NV04_PTIMER_NUMERATOR, n); + nvkm_wr32(device, NV04_PTIMER_DENOMINATOR, d); +} + +static const struct nvkm_timer_func +nv41_timer = { + .init = nv41_timer_init, + .intr = nv04_timer_intr, + .read = nv04_timer_read, + .time = nv04_timer_time, + .alarm_init = nv04_timer_alarm_init, + .alarm_fini = nv04_timer_alarm_fini, +}; + +int +nv41_timer_new(struct nvkm_device *device, int index, struct nvkm_timer **ptmr) +{ + return nvkm_timer_new_(&nv41_timer, device, index, ptmr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h index 08e29a3da1881..f820ca2aeda44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h @@ -1,4 +1,26 @@ #ifndef __NVKM_TIMER_PRIV_H__ #define __NVKM_TIMER_PRIV_H__ +#define nvkm_timer(p) container_of((p), struct nvkm_timer, subdev) #include + +int nvkm_timer_new_(const struct nvkm_timer_func *, struct nvkm_device *, + int index, struct nvkm_timer **); + +struct nvkm_timer_func { + void (*init)(struct nvkm_timer *); + void (*intr)(struct nvkm_timer *); + u64 (*read)(struct nvkm_timer *); + void (*time)(struct nvkm_timer *, u64 time); + void (*alarm_init)(struct nvkm_timer *, u32 time); + void (*alarm_fini)(struct nvkm_timer *); +}; + +void nvkm_timer_alarm_trigger(struct nvkm_timer *); + +void nv04_timer_fini(struct nvkm_timer *); +void nv04_timer_intr(struct nvkm_timer *); +void nv04_timer_time(struct nvkm_timer *, u64); +u64 nv04_timer_read(struct nvkm_timer *); +void nv04_timer_alarm_init(struct nvkm_timer *, u32); +void nv04_timer_alarm_fini(struct nvkm_timer *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h new file mode 100644 index 0000000000000..10bef85b485ee --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/regsnv04.h @@ -0,0 +1,7 @@ +#define NV04_PTIMER_INTR_0 0x009100 +#define NV04_PTIMER_INTR_EN_0 0x009140 +#define NV04_PTIMER_NUMERATOR 0x009200 +#define NV04_PTIMER_DENOMINATOR 0x009210 +#define NV04_PTIMER_TIME_0 0x009400 +#define NV04_PTIMER_TIME_1 0x009410 +#define NV04_PTIMER_ALARM_0 0x009420 -- GitLab From 437b2296ced574eada632b11346e22f6b0103e17 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5548/7006] drm/nouveau/volt: convert to new-style nvkm_subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/subdev/volt.h | 46 +------ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 92 +++++++------- .../drm/nouveau/nvkm/engine/device/gf100.c | 8 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 --- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 --- .../gpu/drm/nouveau/nvkm/subdev/clk/base.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/volt/base.c | 117 ++++++++---------- .../gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 55 ++++---- .../gpu/drm/nouveau/nvkm/subdev/volt/nv40.c | 31 ++--- .../gpu/drm/nouveau/nvkm/subdev/volt/priv.h | 20 +++ 12 files changed, 161 insertions(+), 253 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h index dc8846899a60a..5c8a3f1196de5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h @@ -2,20 +2,10 @@ #define __NVKM_VOLT_H__ #include -struct nvkm_voltage { - u32 uv; - u8 id; -}; - struct nvkm_volt { + const struct nvkm_volt_func *func; struct nvkm_subdev subdev; - int (*vid_get)(struct nvkm_volt *); - int (*get)(struct nvkm_volt *); - int (*vid_set)(struct nvkm_volt *, u8 vid); - int (*set)(struct nvkm_volt *, u32 uv); - int (*set_id)(struct nvkm_volt *, u8 id, int condition); - u8 vid_mask; u8 vid_nr; struct { @@ -24,35 +14,9 @@ struct nvkm_volt { } vid[256]; }; -static inline struct nvkm_volt * -nvkm_volt(void *obj) -{ - return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_VOLT); -} - -#define nvkm_volt_create(p, e, o, d) \ - nvkm_volt_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_volt_destroy(p) ({ \ - struct nvkm_volt *v = (p); \ - _nvkm_volt_dtor(nv_object(v)); \ -}) -#define nvkm_volt_init(p) ({ \ - struct nvkm_volt *v = (p); \ - _nvkm_volt_init(nv_object(v)); \ -}) -#define nvkm_volt_fini(p,s) \ - nvkm_subdev_fini_old((p), (s)) - -int nvkm_volt_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_volt_dtor(struct nvkm_object *); -int _nvkm_volt_init(struct nvkm_object *); -#define _nvkm_volt_fini _nvkm_subdev_fini - -extern struct nvkm_oclass nv40_volt_oclass; -extern struct nvkm_oclass gk20a_volt_oclass; +int nvkm_volt_get(struct nvkm_volt *); +int nvkm_volt_set_id(struct nvkm_volt *, u8 id, int condition); -int nvkm_voltgpio_init(struct nvkm_volt *); -int nvkm_voltgpio_get(struct nvkm_volt *); -int nvkm_voltgpio_set(struct nvkm_volt *, u8); +int nv40_volt_new(struct nvkm_device *, int, struct nvkm_volt **); +int gk20a_volt_new(struct nvkm_device *, int, struct nvkm_volt **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 04895322d371a..7f858efb2c442 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -465,7 +465,7 @@ nv40_chipset = { .mmu = nv04_mmu_new, .therm = nv40_therm_new, .timer = nv40_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -490,7 +490,7 @@ nv41_chipset = { .mmu = nv41_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -515,7 +515,7 @@ nv42_chipset = { .mmu = nv41_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -540,7 +540,7 @@ nv43_chipset = { .mmu = nv41_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -565,7 +565,7 @@ nv44_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -590,7 +590,7 @@ nv45_chipset = { .mmu = nv04_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -615,7 +615,7 @@ nv46_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -640,7 +640,7 @@ nv47_chipset = { .mmu = nv41_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -665,7 +665,7 @@ nv49_chipset = { .mmu = nv41_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -690,7 +690,7 @@ nv4a_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -715,7 +715,7 @@ nv4b_chipset = { .mmu = nv41_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -740,7 +740,7 @@ nv4c_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -765,7 +765,7 @@ nv4e_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -793,7 +793,7 @@ nv50_chipset = { .mxm = nv50_mxm_new, .therm = nv50_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv50_disp_new, // .dma = nv50_dma_new, // .fifo = nv50_fifo_new, @@ -818,7 +818,7 @@ nv63_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -843,7 +843,7 @@ nv67_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -868,7 +868,7 @@ nv68_chipset = { .mmu = nv44_mmu_new, .therm = nv40_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = nv04_disp_new, // .dma = nv04_dma_new, // .fifo = nv40_fifo_new, @@ -896,7 +896,7 @@ nv84_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g84_disp_new, @@ -927,7 +927,7 @@ nv86_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g84_disp_new, @@ -958,7 +958,7 @@ nv92_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g84_disp_new, @@ -989,7 +989,7 @@ nv94_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g94_disp_new, @@ -1020,7 +1020,7 @@ nv96_chipset = { .imem = nv50_instmem_new, .mmu = nv50_mmu_new, .bar = g84_bar_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .sw = nv50_sw_new, @@ -1051,7 +1051,7 @@ nv98_chipset = { .imem = nv50_instmem_new, .mmu = nv50_mmu_new, .bar = g84_bar_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .sw = nv50_sw_new, @@ -1082,7 +1082,7 @@ nva0_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = gt200_disp_new, @@ -1114,7 +1114,7 @@ nva3_chipset = { .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, @@ -1147,7 +1147,7 @@ nva5_chipset = { .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, @@ -1179,7 +1179,7 @@ nva8_chipset = { .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, @@ -1210,7 +1210,7 @@ nvaa_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = g94_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -1241,7 +1241,7 @@ nvac_chipset = { .mxm = nv50_mxm_new, .therm = g84_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .disp = g94_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -1273,7 +1273,7 @@ nvaf_chipset = { .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, @@ -1307,7 +1307,7 @@ nvc0_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, // .disp = gt215_disp_new, @@ -1342,7 +1342,7 @@ nvc1_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, @@ -1376,7 +1376,7 @@ nvc3_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, @@ -1410,7 +1410,7 @@ nvc4_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, // .disp = gt215_disp_new, @@ -1445,7 +1445,7 @@ nvc8_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, // .disp = gt215_disp_new, @@ -1480,7 +1480,7 @@ nvce_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .ce[1] = gf100_ce1_new, // .disp = gt215_disp_new, @@ -1515,7 +1515,7 @@ nvcf_chipset = { .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, @@ -1581,7 +1581,7 @@ nvd9_chipset = { .pmu = gf119_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gf100_ce0_new, // .disp = gf119_disp_new, // .dma = gf119_dma_new, @@ -1615,7 +1615,7 @@ nve4_chipset = { .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, @@ -1651,7 +1651,7 @@ nve6_chipset = { .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, @@ -1687,7 +1687,7 @@ nve7_chipset = { .pmu = gf119_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, @@ -1717,7 +1717,7 @@ nvea_chipset = { .mmu = gf100_mmu_new, .pmu = gk20a_pmu_new, .timer = gk20a_timer_new, -// .volt = gk20a_volt_new, + .volt = gk20a_volt_new, // .ce[2] = gk104_ce2_new, // .dma = gf119_dma_new, // .fifo = gk20a_fifo_new, @@ -1747,7 +1747,7 @@ nvf0_chipset = { .pmu = gk110_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, @@ -1783,7 +1783,7 @@ nvf1_chipset = { .pmu = gk110_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, @@ -1819,7 +1819,7 @@ nv106_chipset = { .pmu = gk208_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, @@ -1854,7 +1854,7 @@ nv108_chipset = { .pmu = gk208_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .volt = nv40_volt_new, + .volt = nv40_volt_new, // .ce[0] = gk104_ce0_new, // .ce[1] = gk104_ce1_new, // .ce[2] = gk104_ce2_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 28421e6f1f268..1f273e108618b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -42,7 +41,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -56,7 +54,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -69,7 +66,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -83,7 +79,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -96,7 +91,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -109,7 +103,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -123,7 +116,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 25d9092455aa0..414ff61873b9c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -43,7 +42,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -58,7 +56,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -79,10 +76,8 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; - device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass; break; case 0xf0: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -97,7 +92,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -112,7 +106,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; @@ -126,7 +119,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 4b570a27e13af..c16d9586708b2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -30,7 +30,6 @@ gm100_identify(struct nvkm_device *device) case 0x117: #if 0 - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; @@ -54,7 +53,6 @@ gm100_identify(struct nvkm_device *device) /* priv ring says no to 0x10eb14 writes */ #endif #if 0 - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; @@ -76,7 +74,6 @@ gm100_identify(struct nvkm_device *device) /* priv ring says no to 0x10eb14 writes */ #endif #if 0 - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; #endif device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 31df1b8ae7054..0d6da9716b7bc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -38,7 +37,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -48,7 +46,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -58,7 +55,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -68,7 +64,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -78,7 +73,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -88,7 +82,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -98,7 +91,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -108,7 +100,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -118,7 +109,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -128,7 +118,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -138,7 +127,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -148,7 +136,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -158,7 +145,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -168,7 +154,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; @@ -178,7 +163,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index e01add48ceb3e..7e2a4a93b2a7b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -38,7 +37,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -51,7 +49,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -64,7 +61,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -77,7 +73,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -90,7 +85,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -103,7 +97,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -116,7 +109,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -129,7 +121,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -142,7 +133,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -155,7 +145,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -169,7 +158,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -182,7 +170,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; @@ -195,7 +182,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass; device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c index cdb87e2900f18..dc8682c91cc74 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c @@ -99,7 +99,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) } if (volt) { - ret = volt->set_id(volt, cstate->voltage, +1); + ret = nvkm_volt_set_id(volt, cstate->voltage, +1); if (ret && ret != -ENODEV) { nvkm_error(subdev, "failed to raise voltage: %d\n", ret); return ret; @@ -113,7 +113,7 @@ nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei) } if (volt) { - ret = volt->set_id(volt, cstate->voltage, -1); + ret = nvkm_volt_set_id(volt, cstate->voltage, -1); if (ret && ret != -ENODEV) nvkm_error(subdev, "failed to lower voltage: %d\n", ret); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c index c1668c86f521d..4752dbd339230 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c @@ -21,44 +21,39 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" + #include #include #include -static int +int nvkm_volt_get(struct nvkm_volt *volt) { - if (volt->vid_get) { - int ret = volt->vid_get(volt), i; - if (ret >= 0) { - for (i = 0; i < volt->vid_nr; i++) { - if (volt->vid[i].vid == ret) - return volt->vid[i].uv; - } - ret = -EINVAL; + int ret = volt->func->vid_get(volt), i; + if (ret >= 0) { + for (i = 0; i < volt->vid_nr; i++) { + if (volt->vid[i].vid == ret) + return volt->vid[i].uv; } - return ret; + ret = -EINVAL; } - return -ENODEV; + return ret; } static int nvkm_volt_set(struct nvkm_volt *volt, u32 uv) { struct nvkm_subdev *subdev = &volt->subdev; - if (volt->vid_set) { - int i, ret = -EINVAL; - for (i = 0; i < volt->vid_nr; i++) { - if (volt->vid[i].uv == uv) { - ret = volt->vid_set(volt, volt->vid[i].vid); - nvkm_debug(subdev, "set %duv: %d\n", uv, ret); - break; - } + int i, ret = -EINVAL; + for (i = 0; i < volt->vid_nr; i++) { + if (volt->vid[i].uv == uv) { + ret = volt->func->vid_set(volt, volt->vid[i].vid); + nvkm_debug(subdev, "set %duv: %d\n", uv, ret); + break; } - return ret; } - return -ENODEV; + return ret; } static int @@ -83,10 +78,15 @@ nvkm_volt_map(struct nvkm_volt *volt, u8 id) return id ? id * 10000 : -ENODEV; } -static int +int nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition) { - int ret = nvkm_volt_map(volt, id); + int ret; + + if (volt->func->set_id) + return volt->func->set_id(volt, id, condition); + + ret = nvkm_volt_map(volt, id); if (ret >= 0) { int prev = nvkm_volt_get(volt); if (!condition || prev < 0 || @@ -135,53 +135,41 @@ nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt) } } -int -_nvkm_volt_init(struct nvkm_object *object) +static int +nvkm_volt_init(struct nvkm_subdev *subdev) { - struct nvkm_volt *volt = (void *)object; - struct nvkm_subdev *subdev = &volt->subdev; - int ret; - - ret = nvkm_subdev_init_old(&volt->subdev); - if (ret) - return ret; - - ret = volt->get(volt); + struct nvkm_volt *volt = nvkm_volt(subdev); + int ret = nvkm_volt_get(volt); if (ret < 0) { if (ret != -ENODEV) nvkm_debug(subdev, "current voltage unknown\n"); return 0; } - nvkm_debug(subdev, "current voltage: %duv\n", ret); return 0; } -void -_nvkm_volt_dtor(struct nvkm_object *object) +static void * +nvkm_volt_dtor(struct nvkm_subdev *subdev) { - struct nvkm_volt *volt = (void *)object; - nvkm_subdev_destroy(&volt->subdev); + return nvkm_volt(subdev); } -int -nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +static const struct nvkm_subdev_func +nvkm_volt = { + .dtor = nvkm_volt_dtor, + .init = nvkm_volt_init, +}; + +void +nvkm_volt_ctor(const struct nvkm_volt_func *func, struct nvkm_device *device, + int index, struct nvkm_volt *volt) { - struct nvkm_device *device = (void *)parent; struct nvkm_bios *bios = device->bios; - struct nvkm_volt *volt; - int ret, i; - - ret = nvkm_subdev_create_(parent, engine, oclass, 0, "VOLT", - "voltage", length, pobject); - volt = *pobject; - if (ret) - return ret; + int i; - volt->get = nvkm_volt_get; - volt->set = nvkm_volt_set; - volt->set_id = nvkm_volt_set_id; + nvkm_subdev_ctor(&nvkm_volt, device, index, 0, &volt->subdev); + volt->func = func; /* Assuming the non-bios device should build the voltage table later */ if (bios) @@ -192,16 +180,15 @@ nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine, nvkm_debug(&volt->subdev, "VID %02x: %duv\n", volt->vid[i].vid, volt->vid[i].uv); } - - /*XXX: this is an assumption.. there probably exists boards - * out there with i2c-connected voltage controllers too.. - */ - ret = nvkm_voltgpio_init(volt); - if (ret == 0) { - volt->vid_get = nvkm_voltgpio_get; - volt->vid_set = nvkm_voltgpio_set; - } } +} - return ret; +int +nvkm_volt_new_(const struct nvkm_volt_func *func, struct nvkm_device *device, + int index, struct nvkm_volt **pvolt) +{ + if (!(*pvolt = kzalloc(sizeof(**pvolt), GFP_KERNEL))) + return -ENOMEM; + nvkm_volt_ctor(func, device, index, *pvolt); + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 59fa2cf898d20..01394a05e9d8c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -19,7 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include +#define gk20a_volt(p) container_of((p), struct gk20a_volt, base) +#include "priv.h" + #ifdef __KERNEL__ #include #endif @@ -101,9 +103,9 @@ gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo) } static int -gk20a_volt_vid_get(struct nvkm_volt *obj) +gk20a_volt_vid_get(struct nvkm_volt *base) { - struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); + struct gk20a_volt *volt = gk20a_volt(base); int i, uv; uv = regulator_get_voltage(volt->vdd); @@ -116,9 +118,9 @@ gk20a_volt_vid_get(struct nvkm_volt *obj) } static int -gk20a_volt_vid_set(struct nvkm_volt *obj, u8 vid) +gk20a_volt_vid_set(struct nvkm_volt *base, u8 vid) { - struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); + struct gk20a_volt *volt = gk20a_volt(base); struct nvkm_subdev *subdev = &volt->base.subdev; nvkm_debug(subdev, "set voltage as %duv\n", volt->base.vid[vid].uv); @@ -126,9 +128,9 @@ gk20a_volt_vid_set(struct nvkm_volt *obj, u8 vid) } static int -gk20a_volt_set_id(struct nvkm_volt *obj, u8 id, int condition) +gk20a_volt_set_id(struct nvkm_volt *base, u8 id, int condition) { - struct gk20a_volt *volt = container_of(obj, typeof(*volt), base); + struct gk20a_volt *volt = gk20a_volt(base); struct nvkm_subdev *subdev = &volt->base.subdev; int prev_uv = regulator_get_voltage(volt->vdd); int target_uv = volt->base.vid[id].uv; @@ -147,27 +149,29 @@ gk20a_volt_set_id(struct nvkm_volt *obj, u8 id, int condition) return ret; } -static int -gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_volt_func +gk20a_volt = { + .vid_get = gk20a_volt_vid_get, + .vid_set = gk20a_volt_vid_set, + .set_id = gk20a_volt_set_id, +}; + +int +gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { - struct nvkm_device *device = (void *)parent; struct gk20a_volt *volt; - int i, ret, uv; + int i, uv; + + if (!(volt = kzalloc(sizeof(*volt), GFP_KERNEL))) + return -ENOMEM; - ret = nvkm_volt_create(parent, engine, oclass, &volt); - *pobject = nv_object(volt); - if (ret) - return ret; + nvkm_volt_ctor(&gk20a_volt, device, index, &volt->base); + *pvolt = &volt->base; uv = regulator_get_voltage(device->gpu->vdd); nvkm_info(&volt->base.subdev, "The default voltage is %duV\n", uv); volt->vdd = device->gpu->vdd; - volt->base.vid_get = gk20a_volt_vid_get; - volt->base.vid_set = gk20a_volt_vid_set; - volt->base.set_id = gk20a_volt_set_id; volt->base.vid_nr = ARRAY_SIZE(gk20a_cvb_coef); nvkm_debug(&volt->base.subdev, "%s - vid_nr = %d\n", __func__, @@ -183,14 +187,3 @@ gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, return 0; } - -struct nvkm_oclass -gk20a_volt_oclass = { - .handle = NV_SUBDEV(VOLT, 0xea), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_volt_ctor, - .dtor = _nvkm_volt_dtor, - .init = _nvkm_volt_init, - .fini = _nvkm_volt_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c index 16e8965c72f95..23409387abb58 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c @@ -21,31 +21,24 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" -static int -nv40_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +static const struct nvkm_volt_func +nv40_volt = { + .vid_get = nvkm_voltgpio_get, + .vid_set = nvkm_voltgpio_set, +}; + +int +nv40_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { struct nvkm_volt *volt; int ret; - ret = nvkm_volt_create(parent, engine, oclass, &volt); - *pobject = nv_object(volt); + ret = nvkm_volt_new_(&nv40_volt, device, index, &volt); + *pvolt = volt; if (ret) return ret; - return 0; + return nvkm_voltgpio_init(volt); } - -struct nvkm_oclass -nv40_volt_oclass = { - .handle = NV_SUBDEV(VOLT, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_volt_ctor, - .dtor = _nvkm_volt_dtor, - .init = _nvkm_volt_init, - .fini = _nvkm_volt_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h new file mode 100644 index 0000000000000..394f37c723afa --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/priv.h @@ -0,0 +1,20 @@ +#ifndef __NVKM_VOLT_PRIV_H__ +#define __NVKM_VOLT_PRIV_H__ +#define nvkm_volt(p) container_of((p), struct nvkm_volt, subdev) +#include + +void nvkm_volt_ctor(const struct nvkm_volt_func *, struct nvkm_device *, + int index, struct nvkm_volt *); +int nvkm_volt_new_(const struct nvkm_volt_func *, struct nvkm_device *, + int index, struct nvkm_volt **); + +struct nvkm_volt_func { + int (*vid_get)(struct nvkm_volt *); + int (*vid_set)(struct nvkm_volt *, u8 vid); + int (*set_id)(struct nvkm_volt *, u8 id, int condition); +}; + +int nvkm_voltgpio_init(struct nvkm_volt *); +int nvkm_voltgpio_get(struct nvkm_volt *); +int nvkm_voltgpio_set(struct nvkm_volt *, u8); +#endif -- GitLab From 53e60da43aee440d3f75000cdd269bd1324a8ad4 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5549/7006] drm/nouveau/falcon: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/ce.h | 5 +- .../drm/nouveau/include/nvkm/engine/falcon.h | 43 ++-- .../drm/nouveau/include/nvkm/engine/mspdec.h | 9 +- .../drm/nouveau/include/nvkm/engine/msppp.h | 7 +- .../drm/nouveau/include/nvkm/engine/msvld.h | 10 +- .../gpu/drm/nouveau/include/nvkm/engine/sec.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 109 +++------ .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 43 +--- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 216 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 40 ---- .../drm/nouveau/nvkm/engine/device/gk104.c | 21 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 9 - .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 28 --- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 114 +++++---- .../gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/mspdec/base.c | 32 +++ .../gpu/drm/nouveau/nvkm/engine/mspdec/g98.c | 52 +---- .../drm/nouveau/nvkm/engine/mspdec/gf100.c | 49 +--- .../drm/nouveau/nvkm/engine/mspdec/gk104.c | 53 +---- .../drm/nouveau/nvkm/engine/mspdec/gt215.c | 43 ++++ .../gpu/drm/nouveau/nvkm/engine/mspdec/priv.h | 11 + .../gpu/drm/nouveau/nvkm/engine/msppp/Kbuild | 2 + .../gpu/drm/nouveau/nvkm/engine/msppp/base.c | 31 +++ .../gpu/drm/nouveau/nvkm/engine/msppp/g98.c | 50 +--- .../gpu/drm/nouveau/nvkm/engine/msppp/gf100.c | 49 +--- .../gpu/drm/nouveau/nvkm/engine/msppp/gt215.c | 43 ++++ .../gpu/drm/nouveau/nvkm/engine/msppp/priv.h | 9 + .../gpu/drm/nouveau/nvkm/engine/msvld/Kbuild | 3 + .../gpu/drm/nouveau/nvkm/engine/msvld/base.c | 31 +++ .../gpu/drm/nouveau/nvkm/engine/msvld/g98.c | 51 +---- .../gpu/drm/nouveau/nvkm/engine/msvld/gf100.c | 49 +--- .../gpu/drm/nouveau/nvkm/engine/msvld/gk104.c | 53 +---- .../gpu/drm/nouveau/nvkm/engine/msvld/gt215.c | 43 ++++ .../gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c | 43 ++++ .../gpu/drm/nouveau/nvkm/engine/msvld/priv.h | 11 + drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 43 +--- 36 files changed, 640 insertions(+), 771 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h index 43c18abd40343..d0ce89b5be3aa 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h @@ -4,9 +4,8 @@ void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_fifo_chan *); -extern struct nvkm_oclass gt215_ce_oclass; -extern struct nvkm_oclass gf100_ce0_oclass; -extern struct nvkm_oclass gf100_ce1_oclass; +int gt215_ce_new(struct nvkm_device *, int, struct nvkm_engine **); +int gf100_ce_new(struct nvkm_device *, int, struct nvkm_engine **); extern struct nvkm_oclass gk104_ce0_oclass; extern struct nvkm_oclass gk104_ce1_oclass; extern struct nvkm_oclass gk104_ce2_oclass; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h index cd113fcbfccb2..81c0bc66a9f83 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h @@ -4,13 +4,9 @@ #include struct nvkm_fifo_chan; -struct nvkm_falcon_data { - bool external; -}; - struct nvkm_falcon { - struct nvkm_engine engine; const struct nvkm_falcon_func *func; + struct nvkm_engine engine; u32 addr; u8 version; @@ -32,32 +28,21 @@ struct nvkm_falcon { } data; }; +int nvkm_falcon_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, bool enable, u32 addr, struct nvkm_engine **); + struct nvkm_falcon_func { + struct { + u32 *data; + u32 size; + } code; + struct { + u32 *data; + u32 size; + } data; + u32 pmc_enable; + void (*init)(struct nvkm_falcon *); void (*intr)(struct nvkm_falcon *, struct nvkm_fifo_chan *); struct nvkm_sclass sclass[]; }; - -#define nv_falcon(priv) ((struct nvkm_falcon *)priv) - -#define nvkm_falcon_create(a,p,e,c,b,d,i,f,r) \ - nvkm_falcon_create_((a), (p), (e), (c), (b), (d), (i), (f), \ - sizeof(**r),(void **)r) -#define nvkm_falcon_destroy(p) \ - nvkm_engine_destroy(&(p)->engine) -#define nvkm_falcon_init(p) ({ \ - struct nvkm_falcon *_falcon = (p); \ - _nvkm_falcon_init(nv_object(_falcon)); \ -}) -#define nvkm_falcon_fini(p,s) ({ \ - struct nvkm_falcon *_falcon = (p); \ - _nvkm_falcon_fini(nv_object(_falcon), (s)); \ -}) - -int nvkm_falcon_create_(const struct nvkm_falcon_func *, - struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32, bool, const char *, - const char *, int, void **); -#define _nvkm_falcon_dtor _nvkm_engine_dtor -int _nvkm_falcon_init(struct nvkm_object *); -int _nvkm_falcon_fini(struct nvkm_object *, bool); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h index 54b7672eed9c7..08516ca82e044 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h @@ -1,7 +1,8 @@ #ifndef __NVKM_MSPDEC_H__ #define __NVKM_MSPDEC_H__ -#include -extern struct nvkm_oclass g98_mspdec_oclass; -extern struct nvkm_oclass gf100_mspdec_oclass; -extern struct nvkm_oclass gk104_mspdec_oclass; +#include +int g98_mspdec_new(struct nvkm_device *, int, struct nvkm_engine **); +int gt215_mspdec_new(struct nvkm_device *, int, struct nvkm_engine **); +int gf100_mspdec_new(struct nvkm_device *, int, struct nvkm_engine **); +int gk104_mspdec_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h index c6c69d0a8d01a..85fd306021ac7 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h @@ -1,6 +1,7 @@ #ifndef __NVKM_MSPPP_H__ #define __NVKM_MSPPP_H__ -#include -extern struct nvkm_oclass g98_msppp_oclass; -extern struct nvkm_oclass gf100_msppp_oclass; +#include +int g98_msppp_new(struct nvkm_device *, int, struct nvkm_engine **); +int gt215_msppp_new(struct nvkm_device *, int, struct nvkm_engine **); +int gf100_msppp_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h index 1f193b7bd6c50..99757ed96f76c 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h @@ -1,7 +1,9 @@ #ifndef __NVKM_MSVLD_H__ #define __NVKM_MSVLD_H__ -#include -extern struct nvkm_oclass g98_msvld_oclass; -extern struct nvkm_oclass gf100_msvld_oclass; -extern struct nvkm_oclass gk104_msvld_oclass; +#include +int g98_msvld_new(struct nvkm_device *, int, struct nvkm_engine **); +int gt215_msvld_new(struct nvkm_device *, int, struct nvkm_engine **); +int mcp89_msvld_new(struct nvkm_device *, int, struct nvkm_engine **); +int gf100_msvld_new(struct nvkm_device *, int, struct nvkm_engine **); +int gk104_msvld_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h index 44590a2a479d9..7317ef4c02072 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h @@ -1,5 +1,5 @@ #ifndef __NVKM_SEC_H__ #define __NVKM_SEC_H__ -#include -extern struct nvkm_oclass g98_sec_oclass; +#include +int g98_sec_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 3abab3992e7cd..e45c6d703c00b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -22,30 +22,26 @@ * Authors: Ben Skeggs */ #include -#include #include "fuc/gf100.fuc3.h" #include -static int -gf100_ce_init(struct nvkm_object *object) +static void +gf100_ce_init(struct nvkm_falcon *ce) { - struct nvkm_falcon *ce = (void *)object; struct nvkm_device *device = ce->engine.subdev.device; - const int idx = nv_engidx(&ce->engine) - NVDEV_ENGINE_CE0; - u32 base = idx * 0x1000; - int ret; - - ret = nvkm_falcon_init(ce); - if (ret) - return ret; - - nvkm_wr32(device, 0x104084 + base, idx); - return 0; + const int index = ce->engine.subdev.index - NVDEV_ENGINE_CE0; + nvkm_wr32(device, ce->addr + 0x084, index); } static const struct nvkm_falcon_func -gf100_ce0_func = { +gf100_ce0 = { + .code.data = gf100_ce_code, + .code.size = sizeof(gf100_ce_code), + .data.data = gf100_ce_data, + .data.size = sizeof(gf100_ce_data), + .pmc_enable = 0x00000040, + .init = gf100_ce_init, .intr = gt215_ce_intr, .sclass = { { -1, -1, FERMI_DMA }, @@ -53,30 +49,14 @@ gf100_ce0_func = { } }; -static int -gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_falcon *ce; - int ret; - - ret = nvkm_falcon_create(&gf100_ce0_func, parent, engine, oclass, - 0x104000, true, "PCE0", "ce0", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - nv_subdev(ce)->unit = 0x00000040; - nv_falcon(ce)->code.data = gf100_ce_code; - nv_falcon(ce)->code.size = sizeof(gf100_ce_code); - nv_falcon(ce)->data.data = gf100_ce_data; - nv_falcon(ce)->data.size = sizeof(gf100_ce_data); - return 0; -} - static const struct nvkm_falcon_func -gf100_ce1_func = { +gf100_ce1 = { + .code.data = gf100_ce_code, + .code.size = sizeof(gf100_ce_code), + .data.data = gf100_ce_data, + .data.size = sizeof(gf100_ce_data), + .pmc_enable = 0x00000080, + .init = gf100_ce_init, .intr = gt215_ce_intr, .sclass = { { -1, -1, FERMI_DECOMPRESS }, @@ -84,46 +64,17 @@ gf100_ce1_func = { } }; -static int -gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *ce; - int ret; - - ret = nvkm_falcon_create(&gf100_ce1_func, parent, engine, oclass, - 0x105000, true, "PCE1", "ce1", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - nv_subdev(ce)->unit = 0x00000080; - nv_falcon(ce)->code.data = gf100_ce_code; - nv_falcon(ce)->code.size = sizeof(gf100_ce_code); - nv_falcon(ce)->data.data = gf100_ce_data; - nv_falcon(ce)->data.size = sizeof(gf100_ce_data); - return 0; + if (index == NVDEV_ENGINE_CE0) { + return nvkm_falcon_new_(&gf100_ce0, device, index, true, + 0x104000, pengine); + } else + if (index == NVDEV_ENGINE_CE1) { + return nvkm_falcon_new_(&gf100_ce1, device, index, true, + 0x105000, pengine); + } + return -ENODEV; } - -struct nvkm_oclass -gf100_ce0_oclass = { - .handle = NV_ENGINE(CE0, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ce0_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_ce_init, - .fini = _nvkm_falcon_fini, - }, -}; - -struct nvkm_oclass -gf100_ce1_oclass = { - .handle = NV_ENGINE(CE1, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_ce1_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_ce_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 35e4d578b153b..f8223d696598d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -61,7 +61,12 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) } static const struct nvkm_falcon_func -gt215_ce_func = { +gt215_ce = { + .code.data = gt215_ce_code, + .code.size = sizeof(gt215_ce_code), + .data.data = gt215_ce_data, + .data.size = sizeof(gt215_ce_data), + .pmc_enable = 0x00802000, .intr = gt215_ce_intr, .sclass = { { -1, -1, GT212_DMA }, @@ -69,36 +74,10 @@ gt215_ce_func = { } }; -static int -gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt215_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - bool enable = (nv_device(parent)->chipset != 0xaf); - struct nvkm_falcon *ce; - int ret; - - ret = nvkm_falcon_create(>215_ce_func, parent, engine, oclass, - 0x104000, enable, "PCE0", "ce0", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - nv_subdev(ce)->unit = 0x00802000; - nv_falcon(ce)->code.data = gt215_ce_code; - nv_falcon(ce)->code.size = sizeof(gt215_ce_code); - nv_falcon(ce)->data.data = gt215_ce_data; - nv_falcon(ce)->data.size = sizeof(gt215_ce_data); - return 0; + return nvkm_falcon_new_(>215_ce, device, index, + (device->chipset != 0xaf), 0x104000, pengine); } - -struct nvkm_oclass -gt215_ce_oclass = { - .handle = NV_ENGINE(CE0, 0xa3), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_ce_ctor, - .dtor = _nvkm_falcon_dtor, - .init = _nvkm_falcon_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 7f858efb2c442..0556316e27c8a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1056,10 +1056,10 @@ nv98_chipset = { // .fifo = g84_fifo_new, // .sw = nv50_sw_new, // .gr = nv50_gr_new, -// .mspdec = g98_mspdec_new, -// .sec = g98_sec_new, -// .msvld = g98_msvld_new, -// .msppp = g98_msppp_new, + .mspdec = g98_mspdec_new, + .sec = g98_sec_new, + .msvld = g98_msvld_new, + .msppp = g98_msppp_new, // .disp = g94_disp_new, // .pm = g84_pm_new, }; @@ -1115,15 +1115,15 @@ nva3_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gt215_ce_new, + .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, -// .mspdec = g98_mspdec_new, -// .msppp = g98_msppp_new, -// .msvld = g98_msvld_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = gt215_msvld_new, // .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1148,14 +1148,14 @@ nva5_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gt215_ce_new, + .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, -// .mspdec = g98_mspdec_new, -// .msppp = g98_msppp_new, -// .msvld = g98_msvld_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = gt215_msvld_new, // .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1180,14 +1180,14 @@ nva8_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gt215_ce_new, + .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, -// .mspdec = g98_mspdec_new, -// .msppp = g98_msppp_new, -// .msvld = g98_msvld_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = gt215_msvld_new, // .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1215,11 +1215,11 @@ nvaa_chipset = { // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, -// .mspdec = g98_mspdec_new, -// .msppp = g98_msppp_new, -// .msvld = g98_msvld_new, + .mspdec = g98_mspdec_new, + .msppp = g98_msppp_new, + .msvld = g98_msvld_new, // .pm = g84_pm_new, -// .sec = g98_sec_new, + .sec = g98_sec_new, // .sw = nv50_sw_new, }; @@ -1246,11 +1246,11 @@ nvac_chipset = { // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, -// .mspdec = g98_mspdec_new, -// .msppp = g98_msppp_new, -// .msvld = g98_msvld_new, + .mspdec = g98_mspdec_new, + .msppp = g98_msppp_new, + .msvld = g98_msvld_new, // .pm = g84_pm_new, -// .sec = g98_sec_new, + .sec = g98_sec_new, // .sw = nv50_sw_new, }; @@ -1274,14 +1274,14 @@ nvaf_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gt215_ce_new, + .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, -// .mspdec = g98_mspdec_new, -// .msppp = g98_msppp_new, -// .msvld = g98_msvld_new, + .mspdec = gt215_mspdec_new, + .msppp = gt215_msppp_new, + .msvld = mcp89_msvld_new, // .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1308,15 +1308,15 @@ nvc0_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, -// .ce[1] = gf100_ce1_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf100_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1343,14 +1343,14 @@ nvc1_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, + .ce[0] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf108_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf108_pm_new, // .sw = gf100_sw_new, }; @@ -1377,14 +1377,14 @@ nvc3_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, + .ce[0] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1411,15 +1411,15 @@ nvc4_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, -// .ce[1] = gf100_ce1_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1446,15 +1446,15 @@ nvc8_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, -// .ce[1] = gf100_ce1_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf110_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1481,15 +1481,15 @@ nvce_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, -// .ce[1] = gf100_ce1_new, + .ce[0] = gf100_ce_new, + .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1516,14 +1516,14 @@ nvcf_chipset = { .therm = gt215_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, + .ce[0] = gf100_ce_new, // .disp = gt215_disp_new, // .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1548,14 +1548,14 @@ nvd7_chipset = { .mxm = nv50_mxm_new, .therm = gf119_therm_new, .timer = nv41_timer_new, -// .ce[0] = gf100_ce0_new, + .ce[0] = gf100_ce_new, // .disp = gf119_disp_new, // .dma = gf119_dma_new, // .fifo = gf100_fifo_new, // .gr = gf117_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf117_pm_new, // .sw = gf100_sw_new, }; @@ -1582,14 +1582,14 @@ nvd9_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gf100_ce0_new, + .ce[0] = gf100_ce_new, // .disp = gf119_disp_new, // .dma = gf119_dma_new, // .fifo = gf100_fifo_new, // .gr = gf119_gr_new, -// .mspdec = gf100_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gf100_msvld_new, + .mspdec = gf100_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gf100_msvld_new, // .pm = gf117_pm_new, // .sw = gf100_sw_new, }; @@ -1616,16 +1616,16 @@ nve4_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk104_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1652,16 +1652,16 @@ nve6_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk104_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1688,16 +1688,16 @@ nve7_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk104_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1748,16 +1748,16 @@ nvf0_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk110_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .pm = gk110_pm_new, // .sw = gf100_sw_new, }; @@ -1784,16 +1784,16 @@ nvf1_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk110b_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .pm = gk110_pm_new, // .sw = gf100_sw_new, }; @@ -1820,16 +1820,16 @@ nv106_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gk208_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .sw = gf100_sw_new, }; @@ -1855,16 +1855,16 @@ nv108_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce0_new, -// .ce[1] = gk104_ce1_new, +// .ce[0] = gk104_ce_new, +// .ce[1] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gk208_gr_new, -// .mspdec = gk104_mspdec_new, -// .msppp = gf100_msppp_new, -// .msvld = gk104_msvld_new, + .mspdec = gk104_mspdec_new, + .msppp = gf100_msppp_new, + .msvld = gk104_msvld_new, // .sw = gf100_sw_new, }; @@ -1889,7 +1889,7 @@ nv117_chipset = { .pmu = gm107_pmu_new, .therm = gm107_therm_new, .timer = gk20a_timer_new, -// .ce[0] = gk104_ce0_new, +// .ce[0] = gk104_ce_new, // .ce[2] = gk104_ce2_new, // .disp = gm107_disp_new, // .dma = gf119_dma_new, @@ -1917,8 +1917,8 @@ nv124_chipset = { .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, -// .ce[0] = gm204_ce0_new, -// .ce[1] = gm204_ce1_new, +// .ce[0] = gm204_ce_new, +// .ce[1] = gm204_ce_new, // .ce[2] = gm204_ce2_new, // .disp = gm204_disp_new, // .dma = gf119_dma_new, @@ -1946,8 +1946,8 @@ nv126_chipset = { .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, -// .ce[0] = gm204_ce0_new, -// .ce[1] = gm204_ce1_new, +// .ce[0] = gm204_ce_new, +// .ce[1] = gm204_ce_new, // .ce[2] = gm204_ce2_new, // .disp = gm204_disp_new, // .dma = gf119_dma_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 1f273e108618b..336964a0cd924 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -32,11 +32,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; @@ -45,11 +40,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; @@ -58,10 +48,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; @@ -70,11 +56,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; @@ -83,10 +64,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; @@ -95,10 +72,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; @@ -107,11 +80,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; @@ -120,10 +88,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; @@ -132,10 +96,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 414ff61873b9c..1162c030f4a23 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -36,9 +36,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: @@ -50,9 +47,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: @@ -64,9 +58,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: @@ -86,9 +77,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: @@ -100,9 +88,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: @@ -114,9 +99,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; case 0x108: device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -127,9 +109,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index c16d9586708b2..b7b10ca427b83 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -42,9 +42,6 @@ gm100_identify(struct nvkm_device *device) #endif device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; #if 0 - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; #endif break; case 0x124: @@ -63,9 +60,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; #if 0 - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; #endif break; case 0x126: @@ -84,9 +78,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass; device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; #if 0 - device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass; #endif break; case 0x12b: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 7e2a4a93b2a7b..bcbf2d8f692a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -101,10 +101,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -125,10 +121,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -137,10 +129,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -150,10 +138,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; @@ -162,10 +146,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; @@ -174,10 +154,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; @@ -186,10 +162,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass; - device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass; - device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = >215_ce_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 3d3e73cfb6b0d..e51372bdbf540 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -54,10 +54,11 @@ nvkm_falcon_cclass = { }; static void -nvkm_falcon_intr(struct nvkm_subdev *subdev) +nvkm_falcon_intr(struct nvkm_engine *engine) { - struct nvkm_falcon *falcon = (void *)subdev; - struct nvkm_device *device = falcon->engine.subdev.device; + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_subdev *subdev = &falcon->engine.subdev; + struct nvkm_device *device = subdev->device; const u32 base = falcon->addr; u32 dest = nvkm_rd32(device, base + 0x01c); u32 intr = nvkm_rd32(device, base + 0x008) & dest & ~(dest >> 16); @@ -89,6 +90,27 @@ nvkm_falcon_intr(struct nvkm_subdev *subdev) nvkm_fifo_chan_put(device->fifo, flags, &chan); } +static int +nvkm_falcon_fini(struct nvkm_engine *engine, bool suspend) +{ + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_device *device = falcon->engine.subdev.device; + const u32 base = falcon->addr; + + if (!suspend) { + nvkm_memory_del(&falcon->core); + if (falcon->external) { + vfree(falcon->data.data); + vfree(falcon->code.data); + falcon->code.data = NULL; + } + } + + nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); + nvkm_wr32(device, base + 0x014, 0xffffffff); + return 0; +} + static void * vmemdup(const void *src, size_t len) { @@ -99,23 +121,16 @@ vmemdup(const void *src, size_t len) return p; } -int -_nvkm_falcon_init(struct nvkm_object *object) +static int +nvkm_falcon_oneinit(struct nvkm_engine *engine) { - struct nvkm_falcon *falcon = (void *)object; + struct nvkm_falcon *falcon = nvkm_falcon(engine); struct nvkm_subdev *subdev = &falcon->engine.subdev; struct nvkm_device *device = subdev->device; - const struct firmware *fw; - char name[32] = "internal"; const u32 base = falcon->addr; - int ret, i; u32 caps; - /* enable engine, and determine its capabilities */ - ret = nvkm_engine_init_old(&falcon->engine); - if (ret) - return ret; - + /* determine falcon capabilities */ if (device->chipset < 0xa3 || device->chipset == 0xaa || device->chipset == 0xac) { falcon->version = 0; @@ -134,6 +149,19 @@ _nvkm_falcon_init(struct nvkm_object *object) nvkm_debug(subdev, "secret level: %d\n", falcon->secret); nvkm_debug(subdev, "code limit: %d\n", falcon->code.limit); nvkm_debug(subdev, "data limit: %d\n", falcon->data.limit); + return 0; +} + +static int +nvkm_falcon_init(struct nvkm_engine *engine) +{ + struct nvkm_falcon *falcon = nvkm_falcon(engine); + struct nvkm_subdev *subdev = &falcon->engine.subdev; + struct nvkm_device *device = subdev->device; + const struct firmware *fw; + char name[32] = "internal"; + const u32 base = falcon->addr; + int ret, i; /* wait for 'uc halted' to be signalled before continuing */ if (falcon->secret && falcon->version < 4) { @@ -279,56 +307,46 @@ _nvkm_falcon_init(struct nvkm_object *object) nvkm_wr32(device, base + 0x104, 0x00000000); /* ENTRY */ nvkm_wr32(device, base + 0x100, 0x00000002); /* TRIGGER */ nvkm_wr32(device, base + 0x048, 0x00000003); /* FIFO | CHSW */ + + if (falcon->func->init) + falcon->func->init(falcon); return 0; } -int -_nvkm_falcon_fini(struct nvkm_object *object, bool suspend) +static void * +nvkm_falcon_dtor(struct nvkm_engine *engine) { - struct nvkm_falcon *falcon = (void *)object; - struct nvkm_device *device = falcon->engine.subdev.device; - const u32 base = falcon->addr; - - if (!suspend) { - nvkm_memory_del(&falcon->core); - if (falcon->external) { - vfree(falcon->data.data); - vfree(falcon->code.data); - falcon->code.data = NULL; - } - } - - nvkm_mask(device, base + 0x048, 0x00000003, 0x00000000); - nvkm_wr32(device, base + 0x014, 0xffffffff); - - return nvkm_engine_fini_old(&falcon->engine, suspend); + return nvkm_falcon(engine); } static const struct nvkm_engine_func nvkm_falcon = { + .dtor = nvkm_falcon_dtor, + .oneinit = nvkm_falcon_oneinit, + .init = nvkm_falcon_init, + .fini = nvkm_falcon_fini, + .intr = nvkm_falcon_intr, .fifo.sclass = nvkm_falcon_oclass_get, .cclass = &nvkm_falcon_cclass, }; int -nvkm_falcon_create_(const struct nvkm_falcon_func *func, - struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 addr, bool enable, - const char *iname, const char *fname, - int length, void **pobject) +nvkm_falcon_new_(const struct nvkm_falcon_func *func, + struct nvkm_device *device, int index, bool enable, + u32 addr, struct nvkm_engine **pengine) { struct nvkm_falcon *falcon; - int ret; - - ret = nvkm_engine_create_(parent, engine, oclass, enable, iname, - fname, length, pobject); - falcon = *pobject; - if (ret) - return ret; - falcon->engine.subdev.intr = nvkm_falcon_intr; - falcon->engine.func = &nvkm_falcon; + if (!(falcon = kzalloc(sizeof(*falcon), GFP_KERNEL))) + return -ENOMEM; falcon->func = func; falcon->addr = addr; - return 0; + falcon->code.data = func->code.data; + falcon->code.size = func->code.size; + falcon->data.data = func->data.data; + falcon->data.size = func->data.size; + *pengine = &falcon->engine; + + return nvkm_engine_ctor(&nvkm_falcon, device, index, func->pmc_enable, + enable, &falcon->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild index c59c83a673155..1a7151146e9df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild @@ -1,3 +1,5 @@ +nvkm-y += nvkm/engine/mspdec/base.o nvkm-y += nvkm/engine/mspdec/g98.o +nvkm-y += nvkm/engine/mspdec/gt215.o nvkm-y += nvkm/engine/mspdec/gf100.o nvkm-y += nvkm/engine/mspdec/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c new file mode 100644 index 0000000000000..80211f76093bd --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/base.c @@ -0,0 +1,32 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +int +nvkm_mspdec_new_(const struct nvkm_falcon_func *func, + struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_falcon_new_(func, device, index, true, 0x085000, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c index f14971783270c..1f1a99e927b2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c @@ -21,61 +21,31 @@ * * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin */ -#include -#include +#include "priv.h" #include -static int -g98_mspdec_init(struct nvkm_object *object) +void +g98_mspdec_init(struct nvkm_falcon *mspdec) { - struct nvkm_falcon *mspdec = (void *)object; struct nvkm_device *device = mspdec->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(mspdec); - if (ret) - return ret; - nvkm_wr32(device, 0x085010, 0x0000ffd2); nvkm_wr32(device, 0x08501c, 0x0000fff2); - return 0; } static const struct nvkm_falcon_func -g98_mspdec_func = { +g98_mspdec = { + .pmc_enable = 0x01020000, + .init = g98_mspdec_init, .sclass = { { -1, -1, G98_MSPDEC }, - { -1, -1, GT212_MSPDEC }, {} - }, + } }; -static int -g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g98_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *mspdec; - int ret; - - ret = nvkm_falcon_create(&g98_mspdec_func, parent, engine, oclass, - 0x085000, true, "PMSPDEC", "mspdec", &mspdec); - *pobject = nv_object(mspdec); - if (ret) - return ret; - - nv_subdev(mspdec)->unit = 0x01020000; - return 0; + return nvkm_mspdec_new_(&g98_mspdec, device, index, pengine); } - -struct nvkm_oclass -g98_mspdec_oclass = { - .handle = NV_ENGINE(MSPDEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_mspdec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = g98_mspdec_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c index 1296f775ea310..371fd6c3c6630 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c @@ -21,60 +21,31 @@ * * Authors: Maarten Lankhorst */ -#include -#include +#include "priv.h" #include -static int -gf100_mspdec_init(struct nvkm_object *object) +void +gf100_mspdec_init(struct nvkm_falcon *mspdec) { - struct nvkm_falcon *mspdec = (void *)object; struct nvkm_device *device = mspdec->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(mspdec); - if (ret) - return ret; - nvkm_wr32(device, 0x085010, 0x0000fff2); nvkm_wr32(device, 0x08501c, 0x0000fff2); - return 0; } static const struct nvkm_falcon_func -gf100_mspdec_func = { +gf100_mspdec = { + .pmc_enable = 0x00020000, + .init = gf100_mspdec_init, .sclass = { { -1, -1, GF100_MSPDEC }, {} } }; -static int -gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *mspdec; - int ret; - - ret = nvkm_falcon_create(&gf100_mspdec_func, parent, engine, oclass, - 0x085000, true, "PMSPDEC", "mspdec", &mspdec); - *pobject = nv_object(mspdec); - if (ret) - return ret; - - nv_subdev(mspdec)->unit = 0x00020000; - return 0; + return nvkm_mspdec_new_(&gf100_mspdec, device, index, pengine); } - -struct nvkm_oclass -gf100_mspdec_oclass = { - .handle = NV_ENGINE(MSPDEC, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_mspdec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_mspdec_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c index 315da1695c72a..de804a15bfd46 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c @@ -21,60 +21,23 @@ * * Authors: Ben Skeggs */ -#include -#include +#include "priv.h" #include -static int -gk104_mspdec_init(struct nvkm_object *object) -{ - struct nvkm_falcon *mspdec = (void *)object; - struct nvkm_device *device = mspdec->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(mspdec); - if (ret) - return ret; - - nvkm_wr32(device, 0x085010, 0x0000fff2); - nvkm_wr32(device, 0x08501c, 0x0000fff2); - return 0; -} - static const struct nvkm_falcon_func -gk104_mspdec_func = { +gk104_mspdec = { + .pmc_enable = 0x00020000, + .init = gf100_mspdec_init, .sclass = { { -1, -1, GK104_MSPDEC }, {} } }; -static int -gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *falcon; - int ret; - - ret = nvkm_falcon_create(&gk104_mspdec_func, parent, engine, oclass, - 0x085000, true, "PMSPDEC", "mspdec", &falcon); - *pobject = nv_object(falcon); - if (ret) - return ret; - - nv_subdev(falcon)->unit = 0x00020000; - return 0; + return nvkm_mspdec_new_(&gk104_mspdec, device, index, pengine); } - -struct nvkm_oclass -gk104_mspdec_oclass = { - .handle = NV_ENGINE(MSPDEC, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_mspdec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gk104_mspdec_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c new file mode 100644 index 0000000000000..835631713c950 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include + +static const struct nvkm_falcon_func +gt215_mspdec = { + .pmc_enable = 0x01020000, + .init = g98_mspdec_init, + .sclass = { + { -1, -1, GT212_MSPDEC }, + {} + } +}; + +int +gt215_mspdec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_mspdec_new_(>215_mspdec, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h new file mode 100644 index 0000000000000..d518af4bc9de6 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/priv.h @@ -0,0 +1,11 @@ +#ifndef __NVKM_MSPDEC_PRIV_H__ +#define __NVKM_MSPDEC_PRIV_H__ +#include + +int nvkm_mspdec_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +void g98_mspdec_init(struct nvkm_falcon *); + +void gf100_mspdec_init(struct nvkm_falcon *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild index 4576a9eee39d8..3ea7eafb408f2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild @@ -1,2 +1,4 @@ +nvkm-y += nvkm/engine/msppp/base.o nvkm-y += nvkm/engine/msppp/g98.o +nvkm-y += nvkm/engine/msppp/gt215.o nvkm-y += nvkm/engine/msppp/gf100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c new file mode 100644 index 0000000000000..bfae5e60e9259 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/base.c @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +int +nvkm_msppp_new_(const struct nvkm_falcon_func *func, struct nvkm_device *device, + int index, struct nvkm_engine **pengine) +{ + return nvkm_falcon_new_(func, device, index, true, 0x086000, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c index 314736d6aa5b9..73f633ae2ee7e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c @@ -21,61 +21,31 @@ * * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin */ -#include -#include +#include "priv.h" #include -static int -g98_msppp_init(struct nvkm_object *object) +void +g98_msppp_init(struct nvkm_falcon *msppp) { - struct nvkm_falcon *msppp = (void *)object; struct nvkm_device *device = msppp->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(msppp); - if (ret) - return ret; - nvkm_wr32(device, 0x086010, 0x0000ffd2); nvkm_wr32(device, 0x08601c, 0x0000fff2); - return 0; } static const struct nvkm_falcon_func -g98_msppp_func = { +g98_msppp = { + .pmc_enable = 0x00400002, + .init = g98_msppp_init, .sclass = { { -1, -1, G98_MSPPP }, - { -1, -1, GT212_MSPPP }, {} } }; -static int -g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g98_msppp_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *msppp; - int ret; - - ret = nvkm_falcon_create(&g98_msppp_func, parent, engine, oclass, - 0x086000, true, "PMSPPP", "msppp", &msppp); - *pobject = nv_object(msppp); - if (ret) - return ret; - - nv_subdev(msppp)->unit = 0x00400002; - return 0; + return nvkm_msppp_new_(&g98_msppp, device, index, pengine); } - -struct nvkm_oclass -g98_msppp_oclass = { - .handle = NV_ENGINE(MSPPP, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_msppp_ctor, - .dtor = _nvkm_falcon_dtor, - .init = g98_msppp_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c index f977c2adf9d2d..c42c0c07e2db1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c @@ -21,60 +21,31 @@ * * Authors: Maarten Lankhorst */ -#include -#include +#include "priv.h" #include -static int -gf100_msppp_init(struct nvkm_object *object) +static void +gf100_msppp_init(struct nvkm_falcon *msppp) { - struct nvkm_falcon *msppp = (void *)object; struct nvkm_device *device = msppp->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(msppp); - if (ret) - return ret; - nvkm_wr32(device, 0x086010, 0x0000fff2); nvkm_wr32(device, 0x08601c, 0x0000fff2); - return 0; } static const struct nvkm_falcon_func -gf100_msppp_func = { +gf100_msppp = { + .pmc_enable = 0x00000002, + .init = gf100_msppp_init, .sclass = { { -1, -1, GF100_MSPPP }, {} } }; -static int -gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_msppp_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *msppp; - int ret; - - ret = nvkm_falcon_create(&gf100_msppp_func, parent, engine, oclass, - 0x086000, true, "PMSPPP", "msppp", &msppp); - *pobject = nv_object(msppp); - if (ret) - return ret; - - nv_subdev(msppp)->unit = 0x00000002; - return 0; + return nvkm_msppp_new_(&gf100_msppp, device, index, pengine); } - -struct nvkm_oclass -gf100_msppp_oclass = { - .handle = NV_ENGINE(MSPPP, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_msppp_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_msppp_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c new file mode 100644 index 0000000000000..00e7795f1d512 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include + +static const struct nvkm_falcon_func +gt215_msppp = { + .pmc_enable = 0x00400002, + .init = g98_msppp_init, + .sclass = { + { -1, -1, GT212_MSPPP }, + {} + } +}; + +int +gt215_msppp_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msppp_new_(>215_msppp, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h new file mode 100644 index 0000000000000..37a91f9d91814 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/priv.h @@ -0,0 +1,9 @@ +#ifndef __NVKM_MSPPP_PRIV_H__ +#define __NVKM_MSPPP_PRIV_H__ +#include + +int nvkm_msppp_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +void g98_msppp_init(struct nvkm_falcon *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild index 0c9811009e289..28c8ecd27b6d6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild @@ -1,3 +1,6 @@ +nvkm-y += nvkm/engine/msvld/base.o nvkm-y += nvkm/engine/msvld/g98.o +nvkm-y += nvkm/engine/msvld/gt215.o +nvkm-y += nvkm/engine/msvld/mcp89.o nvkm-y += nvkm/engine/msvld/gf100.o nvkm-y += nvkm/engine/msvld/gk104.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c new file mode 100644 index 0000000000000..745bbb653dc08 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/base.c @@ -0,0 +1,31 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +int +nvkm_msvld_new_(const struct nvkm_falcon_func *func, struct nvkm_device *device, + int index, struct nvkm_engine **pengine) +{ + return nvkm_falcon_new_(func, device, index, true, 0x084000, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c index 0ee767373f790..47e2929bfaf02 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c @@ -21,62 +21,31 @@ * * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin */ -#include -#include +#include "priv.h" #include -static int -g98_msvld_init(struct nvkm_object *object) +void +g98_msvld_init(struct nvkm_falcon *msvld) { - struct nvkm_falcon *msvld = (void *)object; struct nvkm_device *device = msvld->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(msvld); - if (ret) - return ret; - nvkm_wr32(device, 0x084010, 0x0000ffd2); nvkm_wr32(device, 0x08401c, 0x0000fff2); - return 0; } static const struct nvkm_falcon_func -g98_msvld_func = { +g98_msvld = { + .pmc_enable = 0x04008000, + .init = g98_msvld_init, .sclass = { { -1, -1, G98_MSVLD }, - { -1, -1, GT212_MSVLD }, - { -1, -1, IGT21A_MSVLD }, {} } }; -static int -g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g98_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *msvld; - int ret; - - ret = nvkm_falcon_create(&g98_msvld_func, parent, engine, oclass, - 0x084000, true, "PMSVLD", "msvld", &msvld); - *pobject = nv_object(msvld); - if (ret) - return ret; - - nv_subdev(msvld)->unit = 0x04008000; - return 0; + return nvkm_msvld_new_(&g98_msvld, device, index, pengine); } - -struct nvkm_oclass -g98_msvld_oclass = { - .handle = NV_ENGINE(MSVLD, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_msvld_ctor, - .dtor = _nvkm_falcon_dtor, - .init = g98_msvld_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c index 839d648dcfdfb..1ac581ba9f96f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c @@ -21,60 +21,31 @@ * * Authors: Maarten Lankhorst */ -#include -#include +#include "priv.h" #include -static int -gf100_msvld_init(struct nvkm_object *object) +void +gf100_msvld_init(struct nvkm_falcon *msvld) { - struct nvkm_falcon *msvld = (void *)object; struct nvkm_device *device = msvld->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(msvld); - if (ret) - return ret; - nvkm_wr32(device, 0x084010, 0x0000fff2); nvkm_wr32(device, 0x08401c, 0x0000fff2); - return 0; } static const struct nvkm_falcon_func -gf100_msvld_func = { +gf100_msvld = { + .pmc_enable = 0x00008000, + .init = gf100_msvld_init, .sclass = { { -1, -1, GF100_MSVLD }, {} } }; -static int -gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *msvld; - int ret; - - ret = nvkm_falcon_create(&gf100_msvld_func, parent, engine, oclass, - 0x084000, true, "PMSVLD", "msvld", &msvld); - *pobject = nv_object(msvld); - if (ret) - return ret; - - nv_subdev(msvld)->unit = 0x00008000; - return 0; + return nvkm_msvld_new_(&gf100_msvld, device, index, pengine); } - -struct nvkm_oclass -gf100_msvld_oclass = { - .handle = NV_ENGINE(MSVLD, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_msvld_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gf100_msvld_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c index 74bdca359d4ad..4bba16e0f5600 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c @@ -21,60 +21,23 @@ * * Authors: Ben Skeggs */ -#include -#include +#include "priv.h" #include -static int -gk104_msvld_init(struct nvkm_object *object) -{ - struct nvkm_falcon *msvld = (void *)object; - struct nvkm_device *device = msvld->engine.subdev.device; - int ret; - - ret = nvkm_falcon_init(msvld); - if (ret) - return ret; - - nvkm_wr32(device, 0x084010, 0x0000fff2); - nvkm_wr32(device, 0x08401c, 0x0000fff2); - return 0; -} - static const struct nvkm_falcon_func -gk104_msvld_func = { +gk104_msvld = { + .pmc_enable = 0x00008000, + .init = gf100_msvld_init, .sclass = { { -1, -1, GK104_MSVLD }, {} } }; -static int -gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *msvld; - int ret; - - ret = nvkm_falcon_create(&gk104_msvld_func, parent, engine, oclass, - 0x084000, true, "PMSVLD", "msvld", &msvld); - *pobject = nv_object(msvld); - if (ret) - return ret; - - nv_subdev(msvld)->unit = 0x00008000; - return 0; + return nvkm_msvld_new_(&gk104_msvld, device, index, pengine); } - -struct nvkm_oclass -gk104_msvld_oclass = { - .handle = NV_ENGINE(MSVLD, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_msvld_ctor, - .dtor = _nvkm_falcon_dtor, - .init = gk104_msvld_init, - .fini = _nvkm_falcon_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c new file mode 100644 index 0000000000000..e17cb5605b2d4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gt215.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include + +static const struct nvkm_falcon_func +gt215_msvld = { + .pmc_enable = 0x04008000, + .init = g98_msvld_init, + .sclass = { + { -1, -1, GT212_MSVLD }, + {} + } +}; + +int +gt215_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msvld_new_(>215_msvld, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c new file mode 100644 index 0000000000000..511800f6a43b8 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/mcp89.c @@ -0,0 +1,43 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin + */ +#include "priv.h" + +#include + +static const struct nvkm_falcon_func +mcp89_msvld = { + .pmc_enable = 0x04008000, + .init = g98_msvld_init, + .sclass = { + { -1, -1, IGT21A_MSVLD }, + {} + } +}; + +int +mcp89_msvld_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) +{ + return nvkm_msvld_new_(&mcp89_msvld, device, index, pengine); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h new file mode 100644 index 0000000000000..9dc1da67d929e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/priv.h @@ -0,0 +1,11 @@ +#ifndef __NVKM_MSVLD_PRIV_H__ +#define __NVKM_MSVLD_PRIV_H__ +#include + +int nvkm_msvld_new_(const struct nvkm_falcon_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +void g98_msvld_init(struct nvkm_falcon *); + +void gf100_msvld_init(struct nvkm_falcon *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index aae0e85b10752..1ec4f4fde1c2d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -22,7 +22,6 @@ * Authors: Ben Skeggs */ #include -#include #include #include "fuc/g98.fuc0s.h" @@ -61,7 +60,12 @@ g98_sec_intr(struct nvkm_falcon *sec, struct nvkm_fifo_chan *chan) } static const struct nvkm_falcon_func -g98_sec_func = { +g98_sec = { + .code.data = g98_sec_code, + .code.size = sizeof(g98_sec_code), + .data.data = g98_sec_data, + .data.size = sizeof(g98_sec_data), + .pmc_enable = 0x00004000, .intr = g98_sec_intr, .sclass = { { -1, -1, G98_SEC }, @@ -69,35 +73,10 @@ g98_sec_func = { } }; -static int -g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g98_sec_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_falcon *sec; - int ret; - - ret = nvkm_falcon_create(&g98_sec_func, parent, engine, oclass, - 0x087000, true, "PSEC", "sec", &sec); - *pobject = nv_object(sec); - if (ret) - return ret; - - nv_subdev(sec)->unit = 0x00004000; - nv_falcon(sec)->code.data = g98_sec_code; - nv_falcon(sec)->code.size = sizeof(g98_sec_code); - nv_falcon(sec)->data.data = g98_sec_data; - nv_falcon(sec)->data.size = sizeof(g98_sec_data); - return 0; + return nvkm_falcon_new_(&g98_sec, device, index, + true, 0x087000, pengine); } - -struct nvkm_oclass -g98_sec_oclass = { - .handle = NV_ENGINE(SEC, 0x98), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g98_sec_ctor, - .dtor = _nvkm_falcon_dtor, - .init = _nvkm_falcon_init, - .fini = _nvkm_falcon_fini, - }, -}; -- GitLab From 98b20c9ab88ff4dbe5f3e239efa5a6b7818c1da7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5550/7006] drm/nouveau/xtensa: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/bsp.h | 2 +- .../gpu/drm/nouveau/include/nvkm/engine/vp.h | 2 +- .../drm/nouveau/include/nvkm/engine/xtensa.h | 26 ++---- drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c | 38 ++------ .../gpu/drm/nouveau/nvkm/engine/device/base.c | 24 ++--- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 12 --- drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c | 38 ++------ drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 90 ++++++++++--------- 8 files changed, 84 insertions(+), 148 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h index af2134586eb7b..904820558fc07 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h @@ -1,5 +1,5 @@ #ifndef __NVKM_BSP_H__ #define __NVKM_BSP_H__ #include -extern struct nvkm_oclass g84_bsp_oclass; +int g84_bsp_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h index 145216d312257..616ea91e03f80 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h @@ -1,5 +1,5 @@ #ifndef __NVKM_VP_H__ #define __NVKM_VP_H__ #include -extern struct nvkm_oclass g84_vp_oclass; +int g84_vp_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h index 6a53812c064d8..3128d21a5d1a6 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h @@ -4,30 +4,20 @@ #include struct nvkm_xtensa { - struct nvkm_engine engine; const struct nvkm_xtensa_func *func; - u32 addr; + struct nvkm_engine engine; + struct nvkm_memory *gpu_fw; - u32 fifo_val; - u32 unkd28; }; +int nvkm_xtensa_new_(const struct nvkm_xtensa_func *, struct nvkm_device *, + int index, bool enable, u32 addr, struct nvkm_engine **); + struct nvkm_xtensa_func { - void (*init)(struct nvkm_xtensa *); + u32 pmc_enable; + u32 fifo_val; + u32 unkd28; struct nvkm_sclass sclass[]; }; - -#define nvkm_xtensa_create(p,e,c,b,d,i,f,r) \ - nvkm_xtensa_create_((p), (e), (c), (b), (d), (i), (f), \ - sizeof(**r),(void **)r) - -int nvkm_xtensa_create_(struct nvkm_object *, - struct nvkm_object *, - struct nvkm_oclass *, u32, bool, - const char *, const char *, - int, void **); -#define _nvkm_xtensa_dtor _nvkm_engine_dtor -int _nvkm_xtensa_init(struct nvkm_object *); -int _nvkm_xtensa_fini(struct nvkm_object *, bool); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c index 176495d9e7081..3ef01071f073d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c @@ -26,41 +26,19 @@ #include static const struct nvkm_xtensa_func -g84_bsp_func = { +g84_bsp = { + .pmc_enable = 0x04008000, + .fifo_val = 0x1111, + .unkd28 = 0x90044, .sclass = { { -1, -1, NV74_BSP }, {} } }; -static int -g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_bsp_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - struct nvkm_xtensa *bsp; - int ret; - - ret = nvkm_xtensa_create(parent, engine, oclass, 0x103000, true, - "PBSP", "bsp", &bsp); - *pobject = nv_object(bsp); - if (ret) - return ret; - - bsp->func = &g84_bsp_func; - nv_subdev(bsp)->unit = 0x04008000; - bsp->fifo_val = 0x1111; - bsp->unkd28 = 0x90044; - return 0; + return nvkm_xtensa_new_(&g84_bsp, device, index, + true, 0x103000, pengine); } - -struct nvkm_oclass -g84_bsp_oclass = { - .handle = NV_ENGINE(BSP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_bsp_ctor, - .dtor = _nvkm_xtensa_dtor, - .init = _nvkm_xtensa_init, - .fini = _nvkm_xtensa_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 0556316e27c8a..f5afe9353b452 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -897,7 +897,7 @@ nv84_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .bsp = g84_bsp_new, + .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g84_disp_new, // .dma = nv50_dma_new, @@ -906,7 +906,7 @@ nv84_chipset = { // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, -// .vp = g84_vp_new, + .vp = g84_vp_new, }; static const struct nvkm_device_chip @@ -928,7 +928,7 @@ nv86_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .bsp = g84_bsp_new, + .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g84_disp_new, // .dma = nv50_dma_new, @@ -937,7 +937,7 @@ nv86_chipset = { // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, -// .vp = g84_vp_new, + .vp = g84_vp_new, }; static const struct nvkm_device_chip @@ -959,7 +959,7 @@ nv92_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .bsp = g84_bsp_new, + .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g84_disp_new, // .dma = nv50_dma_new, @@ -968,7 +968,7 @@ nv92_chipset = { // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, -// .vp = g84_vp_new, + .vp = g84_vp_new, }; static const struct nvkm_device_chip @@ -990,7 +990,7 @@ nv94_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .bsp = g84_bsp_new, + .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = g94_disp_new, // .dma = nv50_dma_new, @@ -999,7 +999,7 @@ nv94_chipset = { // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, -// .vp = g84_vp_new, + .vp = g84_vp_new, }; static const struct nvkm_device_chip @@ -1026,9 +1026,9 @@ nv96_chipset = { // .sw = nv50_sw_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, -// .vp = g84_vp_new, + .vp = g84_vp_new, // .cipher = g84_cipher_new, -// .bsp = g84_bsp_new, + .bsp = g84_bsp_new, // .disp = g94_disp_new, // .pm = g84_pm_new, }; @@ -1083,7 +1083,7 @@ nva0_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .bsp = g84_bsp_new, + .bsp = g84_bsp_new, // .cipher = g84_cipher_new, // .disp = gt200_disp_new, // .dma = nv50_dma_new, @@ -1092,7 +1092,7 @@ nva0_chipset = { // .mpeg = g84_mpeg_new, // .pm = gt200_pm_new, // .sw = nv50_sw_new, -// .vp = g84_vp_new, + .vp = g84_vp_new, }; static const struct nvkm_device_chip diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index bcbf2d8f692a4..35cc167e7b069 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -42,9 +42,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -54,9 +52,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -66,9 +62,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -78,9 +72,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -90,9 +82,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -110,9 +100,7 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass; device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; - device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt200_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c index 0035498024ec4..4188c77ac9275 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c @@ -26,41 +26,19 @@ #include static const struct nvkm_xtensa_func -g84_vp_func = { +g84_vp = { + .pmc_enable = 0x01020000, + .fifo_val = 0x111, + .unkd28 = 0x9c544, .sclass = { { -1, -1, NV74_VP2 }, {} } }; -static int -g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_vp_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - struct nvkm_xtensa *vp; - int ret; - - ret = nvkm_xtensa_create(parent, engine, oclass, 0xf000, true, - "PVP", "vp", &vp); - *pobject = nv_object(vp); - if (ret) - return ret; - - vp->func = &g84_vp_func; - nv_subdev(vp)->unit = 0x01020000; - vp->fifo_val = 0x111; - vp->unkd28 = 0x9c544; - return 0; + return nvkm_xtensa_new_(&g84_vp, device, index, + true, 0x00f000, pengine); } - -struct nvkm_oclass -g84_vp_oclass = { - .handle = NV_ENGINE(VP, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_vp_ctor, - .dtor = _nvkm_xtensa_dtor, - .init = _nvkm_xtensa_init, - .fini = _nvkm_xtensa_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index fa8700005189e..fa36233a71ddf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -51,11 +51,12 @@ nvkm_xtensa_cclass = { .bind = nvkm_xtensa_cclass_bind, }; -void -_nvkm_xtensa_intr(struct nvkm_subdev *subdev) +static void +nvkm_xtensa_intr(struct nvkm_engine *engine) { - struct nvkm_xtensa *xtensa = (void *)subdev; - struct nvkm_device *device = xtensa->engine.subdev.device; + struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); + struct nvkm_subdev *subdev = &xtensa->engine.subdev; + struct nvkm_device *device = subdev->device; const u32 base = xtensa->addr; u32 unk104 = nvkm_rd32(device, base + 0xd04); u32 intr = nvkm_rd32(device, base + 0xc20); @@ -68,41 +69,29 @@ _nvkm_xtensa_intr(struct nvkm_subdev *subdev) intr = nvkm_rd32(device, base + 0xc20); if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) { nvkm_debug(subdev, "Enabling FIFO_CTRL\n"); - nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->fifo_val); + nvkm_mask(device, xtensa->addr + 0xd94, 0, xtensa->func->fifo_val); } } -static const struct nvkm_engine_func -nvkm_xtensa = { - .fifo.sclass = nvkm_xtensa_oclass_get, - .cclass = &nvkm_xtensa_cclass, -}; - -int -nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 addr, bool enable, - const char *iname, const char *fname, - int length, void **pobject) +static int +nvkm_xtensa_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_xtensa *xtensa; - int ret; + struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); + struct nvkm_device *device = xtensa->engine.subdev.device; + const u32 base = xtensa->addr; - ret = nvkm_engine_create_(parent, engine, oclass, enable, iname, - fname, length, pobject); - xtensa = *pobject; - if (ret) - return ret; + nvkm_wr32(device, base + 0xd84, 0); /* INTR_EN */ + nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */ - xtensa->engine.subdev.intr = _nvkm_xtensa_intr; - xtensa->engine.func = &nvkm_xtensa; - xtensa->addr = addr; + if (!suspend) + nvkm_memory_del(&xtensa->gpu_fw); return 0; } -int -_nvkm_xtensa_init(struct nvkm_object *object) +static int +nvkm_xtensa_init(struct nvkm_engine *engine) { - struct nvkm_xtensa *xtensa = (void *)object; + struct nvkm_xtensa *xtensa = nvkm_xtensa(engine); struct nvkm_subdev *subdev = &xtensa->engine.subdev; struct nvkm_device *device = subdev->device; const u32 base = xtensa->addr; @@ -112,10 +101,6 @@ _nvkm_xtensa_init(struct nvkm_object *object) u64 addr, size; u32 tmp; - ret = nvkm_engine_init_old(&xtensa->engine); - if (ret) - return ret; - if (!xtensa->gpu_fw) { snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x", xtensa->addr >> 12); @@ -153,7 +138,7 @@ _nvkm_xtensa_init(struct nvkm_object *object) nvkm_wr32(device, base + 0xd10, 0x1fffffff); /* ?? */ nvkm_wr32(device, base + 0xd08, 0x0fffffff); /* ?? */ - nvkm_wr32(device, base + 0xd28, xtensa->unkd28); /* ?? */ + nvkm_wr32(device, base + 0xd28, xtensa->func->unkd28); /* ?? */ nvkm_wr32(device, base + 0xc20, 0x3f); /* INTR */ nvkm_wr32(device, base + 0xd84, 0x3f); /* INTR_EN */ @@ -171,18 +156,35 @@ _nvkm_xtensa_init(struct nvkm_object *object) return 0; } -int -_nvkm_xtensa_fini(struct nvkm_object *object, bool suspend) +static void * +nvkm_xtensa_dtor(struct nvkm_engine *engine) { - struct nvkm_xtensa *xtensa = (void *)object; - struct nvkm_device *device = xtensa->engine.subdev.device; - const u32 base = xtensa->addr; + return nvkm_xtensa(engine); +} - nvkm_wr32(device, base + 0xd84, 0); /* INTR_EN */ - nvkm_wr32(device, base + 0xd94, 0); /* FIFO_CTRL */ +static const struct nvkm_engine_func +nvkm_xtensa = { + .dtor = nvkm_xtensa_dtor, + .init = nvkm_xtensa_init, + .fini = nvkm_xtensa_fini, + .intr = nvkm_xtensa_intr, + .fifo.sclass = nvkm_xtensa_oclass_get, + .cclass = &nvkm_xtensa_cclass, +}; - if (!suspend) - nvkm_memory_del(&xtensa->gpu_fw); +int +nvkm_xtensa_new_(const struct nvkm_xtensa_func *func, + struct nvkm_device *device, int index, bool enable, + u32 addr, struct nvkm_engine **pengine) +{ + struct nvkm_xtensa *xtensa; + + if (!(xtensa = kzalloc(sizeof(*xtensa), GFP_KERNEL))) + return -ENOMEM; + xtensa->func = func; + xtensa->addr = addr; + *pengine = &xtensa->engine; - return nvkm_engine_fini_old(&xtensa->engine, suspend); + return nvkm_engine_ctor(&nvkm_xtensa, device, index, func->pmc_enable, + enable, &xtensa->engine); } -- GitLab From e5b31ca63249f03e56529dcd4260b23196ce2c28 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5551/7006] drm/nouveau/ce: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/ce.h | 10 +- .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/ce/gk104.c | 122 ++++------------- .../gpu/drm/nouveau/nvkm/engine/ce/gm204.c | 123 +++--------------- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 6 +- drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h | 7 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 62 ++++----- .../drm/nouveau/nvkm/engine/device/gk104.c | 22 ---- .../drm/nouveau/nvkm/engine/device/gm100.c | 10 -- 9 files changed, 86 insertions(+), 278 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h index d0ce89b5be3aa..e2e22cd5305b7 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h @@ -2,14 +2,8 @@ #define __NVKM_CE_H__ #include -void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_fifo_chan *); - int gt215_ce_new(struct nvkm_device *, int, struct nvkm_engine **); int gf100_ce_new(struct nvkm_device *, int, struct nvkm_engine **); -extern struct nvkm_oclass gk104_ce0_oclass; -extern struct nvkm_oclass gk104_ce1_oclass; -extern struct nvkm_oclass gk104_ce2_oclass; -extern struct nvkm_oclass gm204_ce0_oclass; -extern struct nvkm_oclass gm204_ce1_oclass; -extern struct nvkm_oclass gm204_ce2_oclass; +int gk104_ce_new(struct nvkm_device *, int, struct nvkm_engine **); +int gm204_ce_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index e45c6d703c00b..6b36b86f858fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#include +#include "priv.h" #include "fuc/gf100.fuc3.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index f35677b87d29b..5de21a2ebb9ad 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -21,121 +21,47 @@ * * Authors: Ben Skeggs */ -#include -#include +#include "priv.h" #include -static void -gk104_ce_intr(struct nvkm_subdev *subdev) +void +gk104_ce_intr(struct nvkm_engine *ce) { + const u32 base = (ce->subdev.index - NVDEV_ENGINE_CE0) * 0x1000; + struct nvkm_subdev *subdev = &ce->subdev; struct nvkm_device *device = subdev->device; - const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - u32 stat = nvkm_rd32(device, 0x104908 + (idx * 0x1000)); - + u32 stat = nvkm_rd32(device, 0x104908 + base); if (stat) { nvkm_warn(subdev, "intr %08x\n", stat); - nvkm_wr32(device, 0x104908 + (idx * 0x1000), stat); + nvkm_wr32(device, 0x104908 + base, stat); } } static const struct nvkm_engine_func gk104_ce = { + .intr = gk104_ce_intr, .sclass = { { -1, -1, KEPLER_DMA_COPY_A }, {} } }; -static int -gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_engine *ce; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE0", "ce0", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - ce->func = &gk104_ce; - nv_subdev(ce)->unit = 0x00000040; - nv_subdev(ce)->intr = gk104_ce_intr; - return 0; -} - -static int -gk104_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_engine *ce; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE1", "ce1", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - ce->func = &gk104_ce; - nv_subdev(ce)->unit = 0x00000080; - nv_subdev(ce)->intr = gk104_ce_intr; - return 0; -} - -static int -gk104_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_engine *ce; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE2", "ce2", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - ce->func = &gk104_ce; - nv_subdev(ce)->unit = 0x00200000; - nv_subdev(ce)->intr = gk104_ce_intr; - return 0; + if (index == NVDEV_ENGINE_CE0) { + return nvkm_engine_new_(&gk104_ce, device, index, + 0x00000040, true, pengine); + } else + if (index == NVDEV_ENGINE_CE1) { + return nvkm_engine_new_(&gk104_ce, device, index, + 0x00000080, true, pengine); + } else + if (index == NVDEV_ENGINE_CE2) { + return nvkm_engine_new_(&gk104_ce, device, index, + 0x00200000, true, pengine); + } + return -ENODEV; } - -struct nvkm_oclass -gk104_ce0_oclass = { - .handle = NV_ENGINE(CE0, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ce0_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gk104_ce1_oclass = { - .handle = NV_ENGINE(CE1, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ce1_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gk104_ce2_oclass = { - .handle = NV_ENGINE(CE2, 0xe0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_ce2_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index cb8faea1db74d..e89c44cb23e1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -21,121 +21,34 @@ * * Authors: Ben Skeggs */ -#include -#include +#include "priv.h" #include -static void -gm204_ce_intr(struct nvkm_subdev *subdev) -{ - struct nvkm_device *device = subdev->device; - const int idx = nv_subidx(subdev) - NVDEV_ENGINE_CE0; - u32 stat = nvkm_rd32(device, 0x104908 + (idx * 0x1000)); - - if (stat) { - nvkm_warn(subdev, "intr %08x\n", stat); - nvkm_wr32(device, 0x104908 + (idx * 0x1000), stat); - } -} - static const struct nvkm_engine_func gm204_ce = { + .intr = gk104_ce_intr, .sclass = { { -1, -1, MAXWELL_DMA_COPY_A }, {} } }; -static int -gm204_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_engine *ce; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE0", "ce0", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - ce->func = &gm204_ce; - nv_subdev(ce)->unit = 0x00000040; - nv_subdev(ce)->intr = gm204_ce_intr; - return 0; -} - -static int -gm204_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_engine *ce; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE1", "ce1", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - ce->func = &gm204_ce; - nv_subdev(ce)->unit = 0x00000080; - nv_subdev(ce)->intr = gm204_ce_intr; - return 0; -} - -static int -gm204_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm204_ce_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_engine *ce; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCE2", "ce2", &ce); - *pobject = nv_object(ce); - if (ret) - return ret; - - ce->func = &gm204_ce; - nv_subdev(ce)->unit = 0x00200000; - nv_subdev(ce)->intr = gm204_ce_intr; - return 0; + if (index == NVDEV_ENGINE_CE0) { + return nvkm_engine_new_(&gm204_ce, device, index, + 0x00000040, true, pengine); + } else + if (index == NVDEV_ENGINE_CE1) { + return nvkm_engine_new_(&gm204_ce, device, index, + 0x00000080, true, pengine); + } else + if (index == NVDEV_ENGINE_CE2) { + return nvkm_engine_new_(&gm204_ce, device, index, + 0x00200000, true, pengine); + } + return -ENODEV; } - -struct nvkm_oclass -gm204_ce0_oclass = { - .handle = NV_ENGINE(CE0, 0x24), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_ce0_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gm204_ce1_oclass = { - .handle = NV_ENGINE(CE1, 0x24), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_ce1_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; - -struct nvkm_oclass -gm204_ce2_oclass = { - .handle = NV_ENGINE(CE2, 0x24), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_ce2_ctor, - .dtor = _nvkm_engine_dtor, - .init = _nvkm_engine_init, - .fini = _nvkm_engine_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index f8223d696598d..764b46751eb90 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -21,12 +21,12 @@ * * Authors: Ben Skeggs */ -#include -#include +#include "priv.h" #include "fuc/gt215.fuc3.h" #include #include +#include #include @@ -43,7 +43,7 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) { struct nvkm_subdev *subdev = &ce->engine.subdev; struct nvkm_device *device = subdev->device; - const u32 base = (nv_subidx(subdev) - NVDEV_ENGINE_CE0) * 0x1000; + const u32 base = (subdev->index - NVDEV_ENGINE_CE0) * 0x1000; u32 ssta = nvkm_rd32(device, 0x104040 + base) & 0x0000ffff; u32 addr = nvkm_rd32(device, 0x104040 + base) >> 16; u32 mthd = (addr & 0x07ff) << 2; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h new file mode 100644 index 0000000000000..e2fa8b1619437 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/priv.h @@ -0,0 +1,7 @@ +#ifndef __NVKM_CE_PRIV_H__ +#define __NVKM_CE_PRIV_H__ +#include + +void gt215_ce_intr(struct nvkm_falcon *, struct nvkm_fifo_chan *); +void gk104_ce_intr(struct nvkm_engine *); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index f5afe9353b452..926e07fe09128 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1616,9 +1616,9 @@ nve4_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk104_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, @@ -1652,9 +1652,9 @@ nve6_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk104_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, @@ -1688,9 +1688,9 @@ nve7_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk104_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, @@ -1718,7 +1718,7 @@ nvea_chipset = { .pmu = gk20a_pmu_new, .timer = gk20a_timer_new, .volt = gk20a_volt_new, -// .ce[2] = gk104_ce2_new, + .ce[2] = gk104_ce_new, // .dma = gf119_dma_new, // .fifo = gk20a_fifo_new, // .gr = gk20a_gr_new, @@ -1748,9 +1748,9 @@ nvf0_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, @@ -1784,9 +1784,9 @@ nvf1_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk104_fifo_new, @@ -1820,9 +1820,9 @@ nv106_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk208_fifo_new, @@ -1855,9 +1855,9 @@ nv108_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .ce[0] = gk104_ce_new, -// .ce[1] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[1] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, // .dma = gf119_dma_new, // .fifo = gk208_fifo_new, @@ -1889,8 +1889,8 @@ nv117_chipset = { .pmu = gm107_pmu_new, .therm = gm107_therm_new, .timer = gk20a_timer_new, -// .ce[0] = gk104_ce_new, -// .ce[2] = gk104_ce2_new, + .ce[0] = gk104_ce_new, + .ce[2] = gk104_ce_new, // .disp = gm107_disp_new, // .dma = gf119_dma_new, // .fifo = gk208_fifo_new, @@ -1917,9 +1917,9 @@ nv124_chipset = { .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, -// .ce[0] = gm204_ce_new, -// .ce[1] = gm204_ce_new, -// .ce[2] = gm204_ce2_new, + .ce[0] = gm204_ce_new, + .ce[1] = gm204_ce_new, + .ce[2] = gm204_ce_new, // .disp = gm204_disp_new, // .dma = gf119_dma_new, // .fifo = gm204_fifo_new, @@ -1946,9 +1946,9 @@ nv126_chipset = { .mxm = nv50_mxm_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, -// .ce[0] = gm204_ce_new, -// .ce[1] = gm204_ce_new, -// .ce[2] = gm204_ce2_new, + .ce[0] = gm204_ce_new, + .ce[1] = gm204_ce_new, + .ce[2] = gm204_ce_new, // .disp = gm204_disp_new, // .dma = gf119_dma_new, // .fifo = gm204_fifo_new, @@ -1970,7 +1970,7 @@ nv12b_chipset = { .mmu = gf100_mmu_new, .mmu = gf100_mmu_new, .timer = gk20a_timer_new, -// .ce[2] = gm204_ce2_new, + .ce[2] = gm204_ce_new, // .dma = gf119_dma_new, // .fifo = gm20b_fifo_new, // .gr = gm20b_gr_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 1162c030f4a23..3a9fa9428803e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -33,9 +33,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: @@ -44,9 +41,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: @@ -55,9 +49,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: @@ -65,7 +56,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xf0: @@ -74,9 +64,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: @@ -85,9 +72,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: @@ -96,9 +80,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; break; case 0x108: device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; @@ -106,9 +87,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index b7b10ca427b83..ec75f91e55cca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -36,11 +36,8 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass; #if 0 - device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass; #endif - device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass; #if 0 #endif break; @@ -56,9 +53,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm204_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gm204_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; #if 0 #endif break; @@ -74,9 +68,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm206_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; - device->oclass[NVDEV_ENGINE_CE0 ] = &gm204_ce0_oclass; - device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; #if 0 #endif break; @@ -86,7 +77,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm20b_gr_oclass; - device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass; break; default: return -EINVAL; -- GitLab From 14d74acafb15fd3fac16eef89de7643cddd01775 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5552/7006] drm/nouveau/cipher: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/cipher.h | 2 +- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 68 ++++++------------- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 12 ++-- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 6 -- 4 files changed, 27 insertions(+), 61 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h index 57c29e91bad56..03fa57a7c30a8 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h @@ -1,5 +1,5 @@ #ifndef __NVKM_CIPHER_H__ #define __NVKM_CIPHER_H__ #include -extern struct nvkm_oclass g84_cipher_oclass; +int g84_cipher_new(struct nvkm_device *, int, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index ae371ca64146c..d3a35db85fba7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -77,10 +77,10 @@ g84_cipher_intr_mask[] = { }; static void -g84_cipher_intr(struct nvkm_subdev *subdev) +g84_cipher_intr(struct nvkm_engine *cipher) { - struct nvkm_engine *cipher = (void *)subdev; - struct nvkm_device *device = cipher->subdev.device; + struct nvkm_subdev *subdev = &cipher->subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fifo *fifo = device->fifo; struct nvkm_fifo_chan *chan; u32 stat = nvkm_rd32(device, 0x102130); @@ -105,8 +105,20 @@ g84_cipher_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x10200c, 0x10); } +static int +g84_cipher_init(struct nvkm_engine *cipher) +{ + struct nvkm_device *device = cipher->subdev.device; + nvkm_wr32(device, 0x102130, 0xffffffff); + nvkm_wr32(device, 0x102140, 0xffffffbf); + nvkm_wr32(device, 0x10200c, 0x00000010); + return 0; +} + static const struct nvkm_engine_func g84_cipher = { + .init = g84_cipher_init, + .intr = g84_cipher_intr, .cclass = &g84_cipher_cclass, .sclass = { { -1, -1, NV74_CIPHER, &g84_cipher_oclass_func }, @@ -114,50 +126,10 @@ g84_cipher = { } }; -static int -g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_cipher_new(struct nvkm_device *device, int index, + struct nvkm_engine **pengine) { - struct nvkm_engine *cipher; - int ret; - - ret = nvkm_engine_create(parent, engine, oclass, true, - "PCIPHER", "cipher", &cipher); - *pobject = nv_object(cipher); - if (ret) - return ret; - - cipher->func = &g84_cipher, - nv_subdev(cipher)->unit = 0x00004000; - nv_subdev(cipher)->intr = g84_cipher_intr; - return 0; + return nvkm_engine_new_(&g84_cipher, device, index, + 0x00004000, true, pengine); } - -static int -g84_cipher_init(struct nvkm_object *object) -{ - struct nvkm_engine *cipher = (void *)object; - struct nvkm_device *device = cipher->subdev.device; - int ret; - - ret = nvkm_engine_init_old(cipher); - if (ret) - return ret; - - nvkm_wr32(device, 0x102130, 0xffffffff); - nvkm_wr32(device, 0x102140, 0xffffffbf); - nvkm_wr32(device, 0x10200c, 0x00000010); - return 0; -} - -struct nvkm_oclass -g84_cipher_oclass = { - .handle = NV_ENGINE(CIPHER, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_cipher_ctor, - .dtor = _nvkm_engine_dtor, - .init = g84_cipher_init, - .fini = _nvkm_engine_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 926e07fe09128..e9ed835630287 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -898,7 +898,7 @@ nv84_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .bsp = g84_bsp_new, -// .cipher = g84_cipher_new, + .cipher = g84_cipher_new, // .disp = g84_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -929,7 +929,7 @@ nv86_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .bsp = g84_bsp_new, -// .cipher = g84_cipher_new, + .cipher = g84_cipher_new, // .disp = g84_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -960,7 +960,7 @@ nv92_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .bsp = g84_bsp_new, -// .cipher = g84_cipher_new, + .cipher = g84_cipher_new, // .disp = g84_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -991,7 +991,7 @@ nv94_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .bsp = g84_bsp_new, -// .cipher = g84_cipher_new, + .cipher = g84_cipher_new, // .disp = g94_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, @@ -1027,7 +1027,7 @@ nv96_chipset = { // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, .vp = g84_vp_new, -// .cipher = g84_cipher_new, + .cipher = g84_cipher_new, .bsp = g84_bsp_new, // .disp = g94_disp_new, // .pm = g84_pm_new, @@ -1084,7 +1084,7 @@ nva0_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .bsp = g84_bsp_new, -// .cipher = g84_cipher_new, + .cipher = g84_cipher_new, // .disp = gt200_disp_new, // .dma = nv50_dma_new, // .fifo = g84_fifo_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 35cc167e7b069..087edc8d412cc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -42,7 +42,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -52,7 +51,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -62,7 +60,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -72,7 +69,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -82,7 +78,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; @@ -100,7 +95,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gt200_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; -- GitLab From bd70563f015a5204c62a52a87a35c32377940187 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:21 +1000 Subject: [PATCH 5553/7006] drm/nouveau/dma: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/class.h | 10 +- .../gpu/drm/nouveau/include/nvkm/engine/dma.h | 15 +- drivers/gpu/drm/nouveau/nv50_display.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- .../gpu/drm/nouveau/nvkm/engine/dma/Kbuild | 4 +- .../gpu/drm/nouveau/nvkm/engine/dma/base.c | 30 ++-- .../gpu/drm/nouveau/nvkm/engine/dma/gf100.c | 19 ++- .../nvkm/engine/dma/{gf110.c => gf119.c} | 21 ++- .../gpu/drm/nouveau/nvkm/engine/dma/nv04.c | 19 ++- .../gpu/drm/nouveau/nvkm/engine/dma/nv50.c | 19 ++- .../gpu/drm/nouveau/nvkm/engine/dma/priv.h | 19 +-- .../gpu/drm/nouveau/nvkm/engine/dma/user.h | 2 +- .../engine/dma/{usergf110.c => usergf119.c} | 30 ++-- 22 files changed, 162 insertions(+), 242 deletions(-) rename drivers/gpu/drm/nouveau/nvkm/engine/dma/{gf110.c => gf119.c} (79%) rename drivers/gpu/drm/nouveau/nvkm/engine/dma/{usergf110.c => usergf119.c} (83%) diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h index 1b85ffe629aa7..95a64d89547cd 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/class.h +++ b/drivers/gpu/drm/nouveau/include/nvif/class.h @@ -251,13 +251,13 @@ struct gf100_dma_v0 { __u8 pad03[5]; }; -struct gf110_dma_v0 { +struct gf119_dma_v0 { __u8 version; -#define GF110_DMA_V0_PAGE_LP 0x00 -#define GF110_DMA_V0_PAGE_SP 0x01 +#define GF119_DMA_V0_PAGE_LP 0x00 +#define GF119_DMA_V0_PAGE_SP 0x01 __u8 page; -#define GF110_DMA_V0_KIND_PITCH 0x00 -#define GF110_DMA_V0_KIND_VM 0xff +#define GF119_DMA_V0_KIND_PITCH 0x00 +#define GF119_DMA_V0_KIND_VM 0xff __u8 kind; __u8 pad03[5]; }; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h index 7439a02bf7c9b..114bfb737a812 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dma.h @@ -2,7 +2,6 @@ #define __NVKM_DMA_H__ #include struct nvkm_client; -struct nvkm_gpuobj; struct nvkm_dmaobj { const struct nvkm_dmaobj_func *func; @@ -18,20 +17,16 @@ struct nvkm_dmaobj { u64 handle; /*XXX HANDLE MERGE */ }; -struct nvkm_dmaobj_func { - int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, int align, - struct nvkm_gpuobj **); -}; - struct nvkm_dma { + const struct nvkm_dma_func *func; struct nvkm_engine engine; }; struct nvkm_dmaobj * nvkm_dma_search(struct nvkm_dma *, struct nvkm_client *, u64 object); -extern struct nvkm_oclass *nv04_dmaeng_oclass; -extern struct nvkm_oclass *nv50_dmaeng_oclass; -extern struct nvkm_oclass *gf100_dmaeng_oclass; -extern struct nvkm_oclass *gf110_dmaeng_oclass; +int nv04_dma_new(struct nvkm_device *, int, struct nvkm_dma **); +int nv50_dma_new(struct nvkm_device *, int, struct nvkm_dma **); +int gf100_dma_new(struct nvkm_device *, int, struct nvkm_dma **); +int gf119_dma_new(struct nvkm_device *, int, struct nvkm_dma **); #endif diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 817ce09acb192..57b13602b2c5a 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -2339,7 +2339,7 @@ nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kin union { struct nv50_dma_v0 nv50; struct gf100_dma_v0 gf100; - struct gf110_dma_v0 gf110; + struct gf119_dma_v0 gf119; }; } args = {}; struct nv50_fbdma *fbdma; @@ -2375,9 +2375,9 @@ nv50_fbdma_init(struct drm_device *dev, u32 name, u64 offset, u64 length, u8 kin args.gf100.kind = kind; size += sizeof(args.gf100); } else { - args.gf110.page = GF110_DMA_V0_PAGE_LP; - args.gf110.kind = kind; - size += sizeof(args.gf110); + args.gf119.page = GF119_DMA_V0_PAGE_LP; + args.gf119.kind = kind; + size += sizeof(args.gf119); } list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index e9ed835630287..fa4a1f00499c1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -87,7 +87,7 @@ nv4_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv04_fifo_new, // .gr = nv04_gr_new, // .sw = nv04_sw_new, @@ -107,7 +107,7 @@ nv5_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv04_fifo_new, // .gr = nv04_gr_new, // .sw = nv04_sw_new, @@ -128,7 +128,7 @@ nv10_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .gr = nv10_gr_new, }; @@ -147,7 +147,7 @@ nv11_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv10_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, @@ -168,7 +168,7 @@ nv15_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv10_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, @@ -189,7 +189,7 @@ nv17_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, @@ -210,7 +210,7 @@ nv18_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, @@ -231,7 +231,7 @@ nv1a_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv10_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, @@ -252,7 +252,7 @@ nv1f_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, @@ -273,7 +273,7 @@ nv20_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv20_gr_new, // .sw = nv10_sw_new, @@ -294,7 +294,7 @@ nv25_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv25_gr_new, // .sw = nv10_sw_new, @@ -315,7 +315,7 @@ nv28_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv25_gr_new, // .sw = nv10_sw_new, @@ -336,7 +336,7 @@ nv2a_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv2a_gr_new, // .sw = nv10_sw_new, @@ -357,7 +357,7 @@ nv30_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv30_gr_new, // .sw = nv10_sw_new, @@ -378,7 +378,7 @@ nv31_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv30_gr_new, // .mpeg = nv31_mpeg_new, @@ -400,7 +400,7 @@ nv34_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv34_gr_new, // .mpeg = nv31_mpeg_new, @@ -422,7 +422,7 @@ nv35_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv35_gr_new, // .sw = nv10_sw_new, @@ -443,7 +443,7 @@ nv36_chipset = { .mmu = nv04_mmu_new, .timer = nv04_timer_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv35_gr_new, // .mpeg = nv31_mpeg_new, @@ -467,7 +467,7 @@ nv40_chipset = { .timer = nv40_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, @@ -492,7 +492,7 @@ nv41_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, @@ -517,7 +517,7 @@ nv42_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, @@ -542,7 +542,7 @@ nv43_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, @@ -567,7 +567,7 @@ nv44_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -592,7 +592,7 @@ nv45_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -617,7 +617,7 @@ nv46_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -642,7 +642,7 @@ nv47_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -667,7 +667,7 @@ nv49_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -692,7 +692,7 @@ nv4a_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -717,7 +717,7 @@ nv4b_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -742,7 +742,7 @@ nv4c_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -767,7 +767,7 @@ nv4e_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -795,7 +795,7 @@ nv50_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv50_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = nv50_fifo_new, // .gr = nv50_gr_new, // .mpeg = nv50_mpeg_new, @@ -820,7 +820,7 @@ nv63_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -845,7 +845,7 @@ nv67_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -870,7 +870,7 @@ nv68_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = nv04_disp_new, -// .dma = nv04_dma_new, + .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, @@ -900,7 +900,7 @@ nv84_chipset = { .bsp = g84_bsp_new, .cipher = g84_cipher_new, // .disp = g84_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -931,7 +931,7 @@ nv86_chipset = { .bsp = g84_bsp_new, .cipher = g84_cipher_new, // .disp = g84_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -962,7 +962,7 @@ nv92_chipset = { .bsp = g84_bsp_new, .cipher = g84_cipher_new, // .disp = g84_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -993,7 +993,7 @@ nv94_chipset = { .bsp = g84_bsp_new, .cipher = g84_cipher_new, // .disp = g94_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -1021,7 +1021,7 @@ nv96_chipset = { .mmu = nv50_mmu_new, .bar = g84_bar_new, .volt = nv40_volt_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .sw = nv50_sw_new, // .gr = nv50_gr_new, @@ -1052,7 +1052,7 @@ nv98_chipset = { .mmu = nv50_mmu_new, .bar = g84_bar_new, .volt = nv40_volt_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .sw = nv50_sw_new, // .gr = nv50_gr_new, @@ -1086,7 +1086,7 @@ nva0_chipset = { .bsp = g84_bsp_new, .cipher = g84_cipher_new, // .disp = gt200_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -1117,7 +1117,7 @@ nva3_chipset = { .volt = nv40_volt_new, .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -1150,7 +1150,7 @@ nva5_chipset = { .volt = nv40_volt_new, .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = gt215_mspdec_new, @@ -1182,7 +1182,7 @@ nva8_chipset = { .volt = nv40_volt_new, .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = gt215_mspdec_new, @@ -1212,7 +1212,7 @@ nvaa_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = g94_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = g98_mspdec_new, @@ -1243,7 +1243,7 @@ nvac_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, // .disp = g94_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = g98_mspdec_new, @@ -1276,7 +1276,7 @@ nvaf_chipset = { .volt = nv40_volt_new, .ce[0] = gt215_ce_new, // .disp = gt215_disp_new, -// .dma = nv50_dma_new, + .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = gt215_mspdec_new, @@ -1311,7 +1311,7 @@ nvc0_chipset = { .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf100_gr_new, .mspdec = gf100_mspdec_new, @@ -1345,7 +1345,7 @@ nvc1_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf108_gr_new, .mspdec = gf100_mspdec_new, @@ -1379,7 +1379,7 @@ nvc3_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, @@ -1414,7 +1414,7 @@ nvc4_chipset = { .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, @@ -1449,7 +1449,7 @@ nvc8_chipset = { .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf110_gr_new, .mspdec = gf100_mspdec_new, @@ -1484,7 +1484,7 @@ nvce_chipset = { .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, @@ -1518,7 +1518,7 @@ nvcf_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, // .disp = gt215_disp_new, -// .dma = gf100_dma_new, + .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, @@ -1550,7 +1550,7 @@ nvd7_chipset = { .timer = nv41_timer_new, .ce[0] = gf100_ce_new, // .disp = gf119_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gf100_fifo_new, // .gr = gf117_gr_new, .mspdec = gf100_mspdec_new, @@ -1584,7 +1584,7 @@ nvd9_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, // .disp = gf119_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gf100_fifo_new, // .gr = gf119_gr_new, .mspdec = gf100_mspdec_new, @@ -1620,7 +1620,7 @@ nve4_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk104_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, @@ -1656,7 +1656,7 @@ nve6_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk104_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, @@ -1692,7 +1692,7 @@ nve7_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk104_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, @@ -1719,7 +1719,7 @@ nvea_chipset = { .timer = gk20a_timer_new, .volt = gk20a_volt_new, .ce[2] = gk104_ce_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk20a_fifo_new, // .gr = gk20a_gr_new, // .pm = gk104_pm_new, @@ -1752,7 +1752,7 @@ nvf0_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk110_gr_new, .mspdec = gk104_mspdec_new, @@ -1788,7 +1788,7 @@ nvf1_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk110b_gr_new, .mspdec = gk104_mspdec_new, @@ -1824,7 +1824,7 @@ nv106_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gk208_gr_new, .mspdec = gk104_mspdec_new, @@ -1859,7 +1859,7 @@ nv108_chipset = { .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gk110_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gk208_gr_new, .mspdec = gk104_mspdec_new, @@ -1892,7 +1892,7 @@ nv117_chipset = { .ce[0] = gk104_ce_new, .ce[2] = gk104_ce_new, // .disp = gm107_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gm107_gr_new, // .sw = gf100_sw_new, @@ -1921,7 +1921,7 @@ nv124_chipset = { .ce[1] = gm204_ce_new, .ce[2] = gm204_ce_new, // .disp = gm204_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gm204_fifo_new, // .gr = gm204_gr_new, // .sw = gf100_sw_new, @@ -1950,7 +1950,7 @@ nv126_chipset = { .ce[1] = gm204_ce_new, .ce[2] = gm204_ce_new, // .disp = gm204_disp_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gm204_fifo_new, // .gr = gm206_gr_new, // .sw = gf100_sw_new, @@ -1971,7 +1971,7 @@ nv12b_chipset = { .mmu = gf100_mmu_new, .timer = gk20a_timer_new, .ce[2] = gm204_ce_new, -// .dma = gf119_dma_new, + .dma = gf119_dma_new, // .fifo = gm20b_fifo_new, // .gr = gm20b_gr_new, // .sw = gf100_sw_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 336964a0cd924..3256b3b12e485 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,7 +28,6 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass; @@ -36,7 +35,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; @@ -44,7 +42,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; @@ -52,7 +49,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; @@ -60,7 +56,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; @@ -68,7 +63,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass; @@ -76,7 +70,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass; @@ -84,7 +77,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass; @@ -92,7 +84,6 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 3a9fa9428803e..c024741685363 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,7 +28,6 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; @@ -36,7 +35,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; @@ -44,7 +42,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; @@ -52,14 +49,12 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xf0: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass; @@ -67,7 +62,6 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass; @@ -75,14 +69,12 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; break; case 0x108: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index ec75f91e55cca..825e7cd07983a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -31,7 +31,6 @@ gm100_identify(struct nvkm_device *device) #if 0 #endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass; @@ -48,7 +47,6 @@ gm100_identify(struct nvkm_device *device) #endif #if 0 #endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm204_gr_oclass; @@ -63,7 +61,6 @@ gm100_identify(struct nvkm_device *device) #endif #if 0 #endif - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm206_gr_oclass; @@ -73,7 +70,6 @@ gm100_identify(struct nvkm_device *device) break; case 0x12b: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm20b_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 1b2ebda82c1fb..92c24618d101f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,14 +28,12 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index c5ecdddfbce38..17a694d60d7a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,54 +28,46 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 104ed4f093b5e..6b59530743a1c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,28 +28,24 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv20_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv2a_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 5ea263c850438..232951b9854ec 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,21 +28,18 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; @@ -50,7 +47,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; @@ -58,7 +54,6 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv34_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 0d6da9716b7bc..642000f8b2bbe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,7 +28,6 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -37,7 +36,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -46,7 +44,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -55,7 +52,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -64,7 +60,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -73,7 +68,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -82,7 +76,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -91,7 +84,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -100,7 +92,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -109,7 +100,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -118,7 +108,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -127,7 +116,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -136,7 +124,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -145,7 +132,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -154,7 +140,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; @@ -163,7 +148,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 087edc8d412cc..7e4ef30945e36 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,7 +28,6 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -37,7 +36,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -46,7 +44,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -55,7 +52,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -64,7 +60,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -73,7 +68,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -82,7 +76,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -90,7 +83,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -99,7 +91,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -107,7 +98,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -115,7 +105,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -124,7 +113,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -132,7 +120,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; @@ -140,7 +127,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass; device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild index bb3a0528b6b59..c4a2ce9b0d71b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/Kbuild @@ -2,10 +2,10 @@ nvkm-y += nvkm/engine/dma/base.o nvkm-y += nvkm/engine/dma/nv04.o nvkm-y += nvkm/engine/dma/nv50.o nvkm-y += nvkm/engine/dma/gf100.o -nvkm-y += nvkm/engine/dma/gf110.o +nvkm-y += nvkm/engine/dma/gf119.o nvkm-y += nvkm/engine/dma/user.o nvkm-y += nvkm/engine/dma/usernv04.o nvkm-y += nvkm/engine/dma/usernv50.o nvkm-y += nvkm/engine/dma/usergf100.o -nvkm-y += nvkm/engine/dma/usergf110.o +nvkm-y += nvkm/engine/dma/usergf119.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c index 1a377201949c9..9769fc0d5351b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/base.c @@ -52,14 +52,13 @@ nvkm_dma_oclass_new(struct nvkm_device *device, struct nvkm_object **pobject) { struct nvkm_dma *dma = nvkm_dma(oclass->engine); - struct nvkm_dma_impl *impl = (void *)dma->engine.subdev.object.oclass; struct nvkm_dmaobj *dmaobj = NULL; struct nvkm_client *client = oclass->client; struct rb_node **ptr = &client->dmaroot.rb_node; struct rb_node *parent = NULL; int ret; - ret = impl->class_new(dma, oclass, data, size, &dmaobj); + ret = dma->func->class_new(dma, oclass, data, size, &dmaobj); if (dmaobj) *pobject = &dmaobj->object; if (ret) @@ -130,26 +129,29 @@ nvkm_dma_oclass_fifo_get(struct nvkm_oclass *oclass, int index) return count; } +static void * +nvkm_dma_dtor(struct nvkm_engine *engine) +{ + return nvkm_dma(engine); +} + static const struct nvkm_engine_func nvkm_dma = { + .dtor = nvkm_dma_dtor, .base.sclass = nvkm_dma_oclass_base_get, .fifo.sclass = nvkm_dma_oclass_fifo_get, }; int -_nvkm_dma_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nvkm_dma_new_(const struct nvkm_dma_func *func, struct nvkm_device *device, + int index, struct nvkm_dma **pdma) { - struct nvkm_dma *dmaeng; - int ret; + struct nvkm_dma *dma; - ret = nvkm_engine_create(parent, engine, oclass, true, "DMAOBJ", - "dmaobj", &dmaeng); - *pobject = nv_object(dmaeng); - if (ret) - return ret; + if (!(dma = *pdma = kzalloc(sizeof(*dma), GFP_KERNEL))) + return -ENOMEM; + dma->func = func; - dmaeng->engine.func = &nvkm_dma; - return 0; + return nvkm_engine_ctor(&nvkm_dma, device, index, + 0, true, &dma->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c index 81badf09eed86..efec5d3221799 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf100.c @@ -24,14 +24,13 @@ #include "priv.h" #include "user.h" -struct nvkm_oclass * -gf100_dmaeng_oclass = &(struct nvkm_dma_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dma_ctor, - .dtor = _nvkm_dma_dtor, - .init = _nvkm_dma_init, - .fini = _nvkm_dma_fini, - }, +static const struct nvkm_dma_func +gf100_dma = { .class_new = gf100_dmaobj_new, -}.base; +}; + +int +gf100_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&gf100_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.c similarity index 79% rename from drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.c index 79d869bf9a612..34c766039aedb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/gf119.c @@ -24,14 +24,13 @@ #include "priv.h" #include "user.h" -struct nvkm_oclass * -gf110_dmaeng_oclass = &(struct nvkm_dma_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0xd0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dma_ctor, - .dtor = _nvkm_dma_dtor, - .init = _nvkm_dma_init, - .fini = _nvkm_dma_fini, - }, - .class_new = gf110_dmaobj_new, -}.base; +static const struct nvkm_dma_func +gf119_dma = { + .class_new = gf119_dmaobj_new, +}; + +int +gf119_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&gf119_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c index c116995f84946..30747a0ce488c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv04.c @@ -24,14 +24,13 @@ #include "priv.h" #include "user.h" -struct nvkm_oclass * -nv04_dmaeng_oclass = &(struct nvkm_dma_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dma_ctor, - .dtor = _nvkm_dma_dtor, - .init = _nvkm_dma_init, - .fini = _nvkm_dma_fini, - }, +static const struct nvkm_dma_func +nv04_dma = { .class_new = nv04_dmaobj_new, -}.base; +}; + +int +nv04_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&nv04_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c index b8d87e7d6ed7d..77aca7b71c83c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/nv50.c @@ -24,14 +24,13 @@ #include "priv.h" #include "user.h" -struct nvkm_oclass * -nv50_dmaeng_oclass = &(struct nvkm_dma_impl) { - .base.handle = NV_ENGINE(DMAOBJ, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = _nvkm_dma_ctor, - .dtor = _nvkm_dma_dtor, - .init = _nvkm_dma_init, - .fini = _nvkm_dma_fini, - }, +static const struct nvkm_dma_func +nv50_dma = { .class_new = nv50_dmaobj_new, -}.base; +}; + +int +nv50_dma_new(struct nvkm_device *device, int index, struct nvkm_dma **pdma) +{ + return nvkm_dma_new_(&nv50_dma, device, index, pdma); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h index fbff168e6cc8f..deb37ee55c0b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/priv.h @@ -3,18 +3,15 @@ #define nvkm_dma(p) container_of((p), struct nvkm_dma, engine) #include -int _nvkm_dma_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -#define _nvkm_dma_dtor _nvkm_engine_dtor -#define _nvkm_dma_init _nvkm_engine_init -#define _nvkm_dma_fini _nvkm_engine_fini - -struct nvkm_dma_impl { - struct nvkm_oclass base; - struct nvkm_oclass *sclass; - int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, +struct nvkm_dmaobj_func { + int (*bind)(struct nvkm_dmaobj *, struct nvkm_gpuobj *, int align, struct nvkm_gpuobj **); +}; + +int nvkm_dma_new_(const struct nvkm_dma_func *, struct nvkm_device *, + int index, struct nvkm_dma **); + +struct nvkm_dma_func { int (*class_new)(struct nvkm_dma *, const struct nvkm_oclass *, void *data, u32 size, struct nvkm_dmaobj **); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h index f667505a892b5..69a7f10340242 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/user.h @@ -13,6 +13,6 @@ int nv50_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, struct nvkm_dmaobj **); int gf100_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, struct nvkm_dmaobj **); -int gf110_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, +int gf119_dmaobj_new(struct nvkm_dma *, const struct nvkm_oclass *, void *, u32, struct nvkm_dmaobj **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c similarity index 83% rename from drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c rename to drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c index f6bbdffed4e75..0e1af8b4db84a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/dma/usergf119.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#define gf110_dmaobj(p) container_of((p), struct gf110_dmaobj, base) +#define gf119_dmaobj(p) container_of((p), struct gf119_dmaobj, base) #include "user.h" #include @@ -31,16 +31,16 @@ #include #include -struct gf110_dmaobj { +struct gf119_dmaobj { struct nvkm_dmaobj base; u32 flags0; }; static int -gf110_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, +gf119_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, int align, struct nvkm_gpuobj **pgpuobj) { - struct gf110_dmaobj *dmaobj = gf110_dmaobj(base); + struct gf119_dmaobj *dmaobj = gf119_dmaobj(base); struct nvkm_device *device = dmaobj->base.dma->engine.subdev.device; int ret; @@ -60,19 +60,19 @@ gf110_dmaobj_bind(struct nvkm_dmaobj *base, struct nvkm_gpuobj *parent, } static const struct nvkm_dmaobj_func -gf110_dmaobj_func = { - .bind = gf110_dmaobj_bind, +gf119_dmaobj_func = { + .bind = gf119_dmaobj_bind, }; int -gf110_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, +gf119_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, void *data, u32 size, struct nvkm_dmaobj **pdmaobj) { union { - struct gf110_dma_v0 v0; + struct gf119_dma_v0 v0; } *args; struct nvkm_object *parent = oclass->parent; - struct gf110_dmaobj *dmaobj; + struct gf119_dmaobj *dmaobj; u32 kind, page; int ret; @@ -80,14 +80,14 @@ gf110_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, return -ENOMEM; *pdmaobj = &dmaobj->base; - ret = nvkm_dmaobj_ctor(&gf110_dmaobj_func, dma, oclass, + ret = nvkm_dmaobj_ctor(&gf119_dmaobj_func, dma, oclass, &data, &size, &dmaobj->base); if (ret) return ret; args = data; - nvif_ioctl(parent, "create gf110 dma size %d\n", size); + nvif_ioctl(parent, "create gf119 dma size %d\n", size); if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n", @@ -97,11 +97,11 @@ gf110_dmaobj_new(struct nvkm_dma *dma, const struct nvkm_oclass *oclass, } else if (size == 0) { if (dmaobj->base.target != NV_MEM_TARGET_VM) { - kind = GF110_DMA_V0_KIND_PITCH; - page = GF110_DMA_V0_PAGE_SP; + kind = GF119_DMA_V0_KIND_PITCH; + page = GF119_DMA_V0_PAGE_SP; } else { - kind = GF110_DMA_V0_KIND_VM; - page = GF110_DMA_V0_PAGE_LP; + kind = GF119_DMA_V0_KIND_VM; + page = GF119_DMA_V0_PAGE_LP; } } else return ret; -- GitLab From 70aa8670e5229766f12c4b818a68aa61913df0b6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5554/7006] drm/nouveau/disp: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/disp.h | 30 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 134 ++++----- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 - .../drm/nouveau/nvkm/engine/device/gk104.c | 7 - .../drm/nouveau/nvkm/engine/device/gm100.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 - .../gpu/drm/nouveau/nvkm/engine/disp/base.c | 113 +++++--- .../drm/nouveau/nvkm/engine/disp/basenv50.c | 2 +- .../drm/nouveau/nvkm/engine/disp/cursnv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/dport.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/disp/g84.c | 73 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/g94.c | 75 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c | 134 ++++----- .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c | 71 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c | 71 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c | 71 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/gm204.c | 73 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c | 73 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c | 79 ++---- .../gpu/drm/nouveau/nvkm/engine/disp/nv04.c | 65 ++--- .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c | 262 ++++++++++++------ .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h | 91 ++++-- .../drm/nouveau/nvkm/engine/disp/oimmnv50.c | 2 +- .../drm/nouveau/nvkm/engine/disp/ovlynv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/disp/priv.h | 49 ++-- .../drm/nouveau/nvkm/engine/disp/rootgf119.c | 8 +- .../drm/nouveau/nvkm/engine/disp/rootnv50.c | 32 +-- 32 files changed, 696 insertions(+), 890 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h index 026a18ab4d904..efc74d03346b0 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h @@ -5,8 +5,8 @@ #include struct nvkm_disp { - struct nvkm_engine engine; const struct nvkm_disp_func *func; + struct nvkm_engine engine; struct nvkm_oproxy *client; @@ -15,21 +15,21 @@ struct nvkm_disp { struct nvkm_event hpd; struct nvkm_event vblank; -}; -struct nvkm_disp_func { - const struct nvkm_disp_oclass *root; + struct { + int nr; + } head; }; -extern struct nvkm_oclass *nv04_disp_oclass; -extern struct nvkm_oclass *nv50_disp_oclass; -extern struct nvkm_oclass *g84_disp_oclass; -extern struct nvkm_oclass *gt200_disp_oclass; -extern struct nvkm_oclass *g94_disp_oclass; -extern struct nvkm_oclass *gt215_disp_oclass; -extern struct nvkm_oclass *gf110_disp_oclass; -extern struct nvkm_oclass *gk104_disp_oclass; -extern struct nvkm_oclass *gk110_disp_oclass; -extern struct nvkm_oclass *gm107_disp_oclass; -extern struct nvkm_oclass *gm204_disp_oclass; +int nv04_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int nv50_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int g84_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gt200_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int g94_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gt215_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gf119_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gk104_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gk110_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gm107_disp_new(struct nvkm_device *, int, struct nvkm_disp **); +int gm204_disp_new(struct nvkm_device *, int, struct nvkm_disp **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index fa4a1f00499c1..ea3e8902f458f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -86,7 +86,7 @@ nv4_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv04_fifo_new, // .gr = nv04_gr_new, @@ -106,7 +106,7 @@ nv5_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv04_fifo_new, // .gr = nv04_gr_new, @@ -127,7 +127,7 @@ nv10_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .gr = nv10_gr_new, }; @@ -146,7 +146,7 @@ nv11_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv10_fifo_new, // .gr = nv10_gr_new, @@ -167,7 +167,7 @@ nv15_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv10_fifo_new, // .gr = nv10_gr_new, @@ -188,7 +188,7 @@ nv17_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv10_gr_new, @@ -209,7 +209,7 @@ nv18_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv10_gr_new, @@ -230,7 +230,7 @@ nv1a_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv10_fifo_new, // .gr = nv10_gr_new, @@ -251,7 +251,7 @@ nv1f_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv10_gr_new, @@ -272,7 +272,7 @@ nv20_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv20_gr_new, @@ -293,7 +293,7 @@ nv25_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv25_gr_new, @@ -314,7 +314,7 @@ nv28_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv25_gr_new, @@ -335,7 +335,7 @@ nv2a_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv2a_gr_new, @@ -356,7 +356,7 @@ nv30_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv30_gr_new, @@ -377,7 +377,7 @@ nv31_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv30_gr_new, @@ -399,7 +399,7 @@ nv34_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv34_gr_new, @@ -421,7 +421,7 @@ nv35_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv35_gr_new, @@ -442,7 +442,7 @@ nv36_chipset = { .mc = nv04_mc_new, .mmu = nv04_mmu_new, .timer = nv04_timer_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv17_fifo_new, // .gr = nv35_gr_new, @@ -466,7 +466,7 @@ nv40_chipset = { .therm = nv40_therm_new, .timer = nv40_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -491,7 +491,7 @@ nv41_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -516,7 +516,7 @@ nv42_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -541,7 +541,7 @@ nv43_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -566,7 +566,7 @@ nv44_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -591,7 +591,7 @@ nv45_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -616,7 +616,7 @@ nv46_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -641,7 +641,7 @@ nv47_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -666,7 +666,7 @@ nv49_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -691,7 +691,7 @@ nv4a_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -716,7 +716,7 @@ nv4b_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -741,7 +741,7 @@ nv4c_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -766,7 +766,7 @@ nv4e_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -794,7 +794,7 @@ nv50_chipset = { .therm = nv50_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv50_disp_new, + .disp = nv50_disp_new, .dma = nv50_dma_new, // .fifo = nv50_fifo_new, // .gr = nv50_gr_new, @@ -819,7 +819,7 @@ nv63_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -844,7 +844,7 @@ nv67_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -869,7 +869,7 @@ nv68_chipset = { .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = nv04_disp_new, + .disp = nv04_disp_new, .dma = nv04_dma_new, // .fifo = nv40_fifo_new, // .gr = nv40_gr_new, @@ -899,7 +899,7 @@ nv84_chipset = { .volt = nv40_volt_new, .bsp = g84_bsp_new, .cipher = g84_cipher_new, -// .disp = g84_disp_new, + .disp = g84_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -930,7 +930,7 @@ nv86_chipset = { .volt = nv40_volt_new, .bsp = g84_bsp_new, .cipher = g84_cipher_new, -// .disp = g84_disp_new, + .disp = g84_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -961,7 +961,7 @@ nv92_chipset = { .volt = nv40_volt_new, .bsp = g84_bsp_new, .cipher = g84_cipher_new, -// .disp = g84_disp_new, + .disp = g84_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -992,7 +992,7 @@ nv94_chipset = { .volt = nv40_volt_new, .bsp = g84_bsp_new, .cipher = g84_cipher_new, -// .disp = g94_disp_new, + .disp = g94_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1029,7 +1029,7 @@ nv96_chipset = { .vp = g84_vp_new, .cipher = g84_cipher_new, .bsp = g84_bsp_new, -// .disp = g94_disp_new, + .disp = g94_disp_new, // .pm = g84_pm_new, }; @@ -1060,7 +1060,7 @@ nv98_chipset = { .sec = g98_sec_new, .msvld = g98_msvld_new, .msppp = g98_msppp_new, -// .disp = g94_disp_new, + .disp = g94_disp_new, // .pm = g84_pm_new, }; @@ -1085,7 +1085,7 @@ nva0_chipset = { .volt = nv40_volt_new, .bsp = g84_bsp_new, .cipher = g84_cipher_new, -// .disp = gt200_disp_new, + .disp = gt200_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1116,7 +1116,7 @@ nva3_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gt215_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1149,7 +1149,7 @@ nva5_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gt215_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1181,7 +1181,7 @@ nva8_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gt215_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1211,7 +1211,7 @@ nvaa_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = g94_disp_new, + .disp = g94_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1242,7 +1242,7 @@ nvac_chipset = { .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, -// .disp = g94_disp_new, + .disp = g94_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1275,7 +1275,7 @@ nvaf_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gt215_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = nv50_dma_new, // .fifo = g84_fifo_new, // .gr = nv50_gr_new, @@ -1310,7 +1310,7 @@ nvc0_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf100_gr_new, @@ -1344,7 +1344,7 @@ nvc1_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf108_gr_new, @@ -1378,7 +1378,7 @@ nvc3_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, @@ -1413,7 +1413,7 @@ nvc4_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, @@ -1448,7 +1448,7 @@ nvc8_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf110_gr_new, @@ -1483,7 +1483,7 @@ nvce_chipset = { .volt = nv40_volt_new, .ce[0] = gf100_ce_new, .ce[1] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, @@ -1517,7 +1517,7 @@ nvcf_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gf100_ce_new, -// .disp = gt215_disp_new, + .disp = gt215_disp_new, .dma = gf100_dma_new, // .fifo = gf100_fifo_new, // .gr = gf104_gr_new, @@ -1549,7 +1549,7 @@ nvd7_chipset = { .therm = gf119_therm_new, .timer = nv41_timer_new, .ce[0] = gf100_ce_new, -// .disp = gf119_disp_new, + .disp = gf119_disp_new, .dma = gf119_dma_new, // .fifo = gf100_fifo_new, // .gr = gf117_gr_new, @@ -1583,7 +1583,7 @@ nvd9_chipset = { .timer = nv41_timer_new, .volt = nv40_volt_new, .ce[0] = gf100_ce_new, -// .disp = gf119_disp_new, + .disp = gf119_disp_new, .dma = gf119_dma_new, // .fifo = gf100_fifo_new, // .gr = gf119_gr_new, @@ -1619,7 +1619,7 @@ nve4_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk104_disp_new, + .disp = gk104_disp_new, .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, @@ -1655,7 +1655,7 @@ nve6_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk104_disp_new, + .disp = gk104_disp_new, .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, @@ -1691,7 +1691,7 @@ nve7_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk104_disp_new, + .disp = gk104_disp_new, .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk104_gr_new, @@ -1751,7 +1751,7 @@ nvf0_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk110_disp_new, + .disp = gk110_disp_new, .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk110_gr_new, @@ -1787,7 +1787,7 @@ nvf1_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk110_disp_new, + .disp = gk110_disp_new, .dma = gf119_dma_new, // .fifo = gk104_fifo_new, // .gr = gk110b_gr_new, @@ -1823,7 +1823,7 @@ nv106_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk110_disp_new, + .disp = gk110_disp_new, .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gk208_gr_new, @@ -1858,7 +1858,7 @@ nv108_chipset = { .ce[0] = gk104_ce_new, .ce[1] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gk110_disp_new, + .disp = gk110_disp_new, .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gk208_gr_new, @@ -1891,7 +1891,7 @@ nv117_chipset = { .timer = gk20a_timer_new, .ce[0] = gk104_ce_new, .ce[2] = gk104_ce_new, -// .disp = gm107_disp_new, + .disp = gm107_disp_new, .dma = gf119_dma_new, // .fifo = gk208_fifo_new, // .gr = gm107_gr_new, @@ -1920,7 +1920,7 @@ nv124_chipset = { .ce[0] = gm204_ce_new, .ce[1] = gm204_ce_new, .ce[2] = gm204_ce_new, -// .disp = gm204_disp_new, + .disp = gm204_disp_new, .dma = gf119_dma_new, // .fifo = gm204_fifo_new, // .gr = gm204_gr_new, @@ -1949,7 +1949,7 @@ nv126_chipset = { .ce[0] = gm204_ce_new, .ce[1] = gm204_ce_new, .ce[2] = gm204_ce_new, -// .disp = gm204_disp_new, + .disp = gm204_disp_new, .dma = gf119_dma_new, // .fifo = gm204_fifo_new, // .gr = gm206_gr_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 3256b3b12e485..09a1fe1604a2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -31,63 +31,54 @@ gf100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index c024741685363..b3d25aad22f71 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -31,21 +31,18 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: @@ -58,27 +55,23 @@ gk104_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; break; case 0x108: device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 825e7cd07983a..c0c1bd3989d60 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -34,7 +34,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass; #if 0 #endif #if 0 @@ -50,7 +49,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm204_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; #if 0 #endif break; @@ -64,7 +62,6 @@ gm100_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm206_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass; #if 0 #endif break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 92c24618d101f..7a71d0c1d22f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -31,13 +31,11 @@ nv04_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x05: device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 17a694d60d7a0..2b59c02fe7348 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -29,49 +29,41 @@ nv10_identify(struct nvkm_device *device) switch (device->chipset) { case 0x10: device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x15: device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x16: device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1a: device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x11: device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x17: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x1f: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x18: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 6b59530743a1c..b4f8c479f3d7a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -31,25 +31,21 @@ nv20_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv20_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x25: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x28: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x2a: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv2a_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 232951b9854ec..fec9e3f38a5cd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -31,34 +31,29 @@ nv30_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x35: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x31: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x36: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; case 0x34: device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv34_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 642000f8b2bbe..553923ab0376d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -32,7 +32,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: @@ -40,7 +39,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: @@ -48,7 +46,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: @@ -56,7 +53,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: @@ -64,7 +60,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: @@ -72,7 +67,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: @@ -80,7 +74,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: @@ -88,7 +81,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: @@ -96,7 +88,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: @@ -104,7 +95,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: @@ -112,7 +102,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: @@ -120,7 +109,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: @@ -128,7 +116,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: @@ -136,7 +123,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: @@ -144,7 +130,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: @@ -152,7 +137,6 @@ nv40_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 7e4ef30945e36..f4c4ded9193fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -32,7 +32,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = nv50_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: @@ -40,7 +39,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: @@ -48,7 +46,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: @@ -56,7 +53,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: @@ -64,7 +60,6 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: @@ -72,14 +67,12 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: @@ -87,21 +80,18 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt200_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: @@ -109,28 +99,24 @@ nv50_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; - device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c index 165f9d47d11dc..44b67719f64d7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c @@ -35,7 +35,21 @@ #include #include -int +static void +nvkm_disp_vblank_fini(struct nvkm_event *event, int type, int head) +{ + struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); + disp->func->head.vblank_fini(disp, head); +} + +static void +nvkm_disp_vblank_init(struct nvkm_event *event, int type, int head) +{ + struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); + disp->func->head.vblank_init(disp, head); +} + +static int nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) { @@ -58,6 +72,13 @@ nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size, return ret; } +static const struct nvkm_event_func +nvkm_disp_vblank_func = { + .ctor = nvkm_disp_vblank_ctor, + .init = nvkm_disp_vblank_init, + .fini = nvkm_disp_vblank_fini, +}; + void nvkm_disp_vblank(struct nvkm_disp *disp, int head) { @@ -102,7 +123,7 @@ nvkm_disp_hpd_func = { int nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event) { - struct nvkm_disp *disp = (void *)object->engine; + struct nvkm_disp *disp = nvkm_disp(object->engine); switch (type) { case NV04_DISP_NTFY_VBLANK: *event = &disp->vblank; @@ -168,18 +189,26 @@ nvkm_disp_class_get(struct nvkm_oclass *oclass, int index, { struct nvkm_disp *disp = nvkm_disp(oclass->engine); if (index == 0) { - oclass->base = disp->func->root->base; - oclass->engn = disp->func->root; + const struct nvkm_disp_oclass *root = disp->func->root(disp); + oclass->base = root->base; + oclass->engn = root; *class = &nvkm_disp_sclass; return 0; } return 1; } -int -_nvkm_disp_fini(struct nvkm_object *object, bool suspend) +static void +nvkm_disp_intr(struct nvkm_engine *engine) +{ + struct nvkm_disp *disp = nvkm_disp(engine); + disp->func->intr(disp); +} + +static int +nvkm_disp_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_disp *disp = (void *)object; + struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_connector *conn; struct nvkm_output *outp; @@ -191,20 +220,15 @@ _nvkm_disp_fini(struct nvkm_object *object, bool suspend) nvkm_connector_fini(conn); } - return nvkm_engine_fini_old(&disp->engine, suspend); + return 0; } -int -_nvkm_disp_init(struct nvkm_object *object) +static int +nvkm_disp_init(struct nvkm_engine *engine) { - struct nvkm_disp *disp = (void *)object; + struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_connector *conn; struct nvkm_output *outp; - int ret; - - ret = nvkm_engine_init_old(&disp->engine); - if (ret) - return ret; list_for_each_entry(conn, &disp->conn, head) { nvkm_connector_init(conn); @@ -214,15 +238,19 @@ _nvkm_disp_init(struct nvkm_object *object) nvkm_output_init(outp); } - return ret; + return 0; } -void -_nvkm_disp_dtor(struct nvkm_object *object) +static void * +nvkm_disp_dtor(struct nvkm_engine *engine) { - struct nvkm_disp *disp = (void *)object; + struct nvkm_disp *disp = nvkm_disp(engine); struct nvkm_connector *conn; struct nvkm_output *outp; + void *data = disp; + + if (disp->func->dtor) + data = disp->func->dtor(disp); nvkm_event_fini(&disp->vblank); nvkm_event_fini(&disp->hpd); @@ -239,40 +267,40 @@ _nvkm_disp_dtor(struct nvkm_object *object) nvkm_connector_del(&conn); } - nvkm_engine_destroy(&disp->engine); + return data; } static const struct nvkm_engine_func nvkm_disp = { + .dtor = nvkm_disp_dtor, + .init = nvkm_disp_init, + .fini = nvkm_disp_fini, + .intr = nvkm_disp_intr, .base.sclass = nvkm_disp_class_get, }; int -nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int heads, const char *intname, - const char *extname, int length, void **pobject) +nvkm_disp_ctor(const struct nvkm_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp *disp) { - struct nvkm_disp_impl *impl = (void *)oclass; - struct nvkm_device *device = (void *)parent; struct nvkm_bios *bios = device->bios; - struct nvkm_disp *disp; - struct nvkm_connector *conn; struct nvkm_output *outp, *outt, *pair; + struct nvkm_connector *conn; struct nvbios_connE connE; struct dcb_output dcbE; u8 hpd = 0, ver, hdr; u32 data; int ret, i; - ret = nvkm_engine_create_(parent, engine, oclass, true, intname, - extname, length, pobject); - disp = *pobject; - if (ret) - return ret; - - disp->engine.func = &nvkm_disp; INIT_LIST_HEAD(&disp->outp); INIT_LIST_HEAD(&disp->conn); + disp->func = func; + disp->head.nr = heads; + + ret = nvkm_engine_ctor(&nvkm_disp, device, index, 0, + true, &disp->engine); + if (ret) + return ret; /* create output objects for each display path in the vbios */ i = -1; @@ -288,8 +316,8 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, outp = NULL; switch (dcbE.location) { - case 0: outps = &impl->outp.internal; break; - case 1: outps = &impl->outp.external; break; + case 0: outps = &disp->func->outp.internal; break; + case 1: outps = &disp->func->outp.external; break; default: nvkm_warn(&disp->engine.subdev, "dcb %d locn %d unknown\n", i, dcbE.location); @@ -394,9 +422,18 @@ nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine, if (ret) return ret; - ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank); + ret = nvkm_event_init(&nvkm_disp_vblank_func, 1, heads, &disp->vblank); if (ret) return ret; return 0; } + +int +nvkm_disp_new_(const struct nvkm_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp **pdisp) +{ + if (!(*pdisp = kzalloc(sizeof(**pdisp), GFP_KERNEL))) + return -ENOMEM; + return nvkm_disp_ctor(func, device, index, heads, *pdisp); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c index 52775d88dd8fd..1fd89edefc267 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/basenv50.c @@ -49,7 +49,7 @@ nv50_disp_base_new(const struct nv50_disp_dmac_func *func, nvif_ioctl(parent, "create disp base channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->head.nr) + if (args->v0.head > disp->base.head.nr) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c index f3ce583fbcf2c..225858e62cf65 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/cursnv50.c @@ -47,7 +47,7 @@ nv50_disp_curs_new(const struct nv50_disp_chan_func *func, if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create disp cursor vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > disp->head.nr) + if (args->v0.head > disp->base.head.nr) return -EINVAL; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c index cf1ec5f3aad7f..74e2f7c6c07e4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c @@ -322,7 +322,7 @@ void nvkm_dp_train(struct work_struct *w) { struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work); - struct nv50_disp *disp = (void *)outp->base.disp; + struct nv50_disp *disp = nv50_disp(outp->base.disp); const struct dp_rates *cfg = nvkm_dp_rates; struct dp_state _dp = { .outp = outp, @@ -330,8 +330,8 @@ nvkm_dp_train(struct work_struct *w) u32 datarate = 0; int ret; - if (!outp->base.info.location && disp->sor.magic) - disp->sor.magic(&outp->base); + if (!outp->base.info.location && disp->func->sor.magic) + disp->func->sor.magic(&outp->base); /* bring capabilities within encoder limits */ if (disp->base.engine.subdev.device->chipset < 0xd0) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c index a223cef2b81f2..3e3e592cd09fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c @@ -24,59 +24,32 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func g84_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, .root = &g84_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 2, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -static int -g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp *disp; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &g84_disp; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = nv50_disp_intr; - INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->head.nr = 2; - disp->dac.nr = 3; - disp->sor.nr = 2; - disp->pior.nr = 3; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hdmi = g84_hdmi_ctrl; - disp->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(&g84_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -g84_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x82), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.external.tmds = nv50_pior_output_new, - .base.outp.external.dp = nv50_pior_dp_new, - .base.vblank = &nv50_disp_vblank_func, - .head.scanoutpos = nv50_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c index 639b02b2fc141..7a7af3b478f81 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c @@ -24,60 +24,33 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func g94_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, .root = &g94_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = g94_sor_dp_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -static int -g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g94_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp *disp; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &g94_disp; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = nv50_disp_intr; - INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->head.nr = 2; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->pior.nr = 3; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hdmi = g84_hdmi_ctrl; - disp->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(&g94_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -g94_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x88), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = g94_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = g94_sor_dp_new, - .base.outp.external.lvds = nv50_pior_output_new, - .base.outp.external.dp = nv50_pior_dp_new, - .base.vblank = &nv50_disp_vblank_func, - .head.scanoutpos = nv50_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c index 1573f86073f3c..186fd3ac78f6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c @@ -30,29 +30,20 @@ #include #include -static void -gf119_disp_vblank_init(struct nvkm_event *event, int type, int head) +void +gf119_disp_vblank_init(struct nv50_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_device *device = disp->base.engine.subdev.device; nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001); } -static void -gf119_disp_vblank_fini(struct nvkm_event *event, int type, int head) +void +gf119_disp_vblank_fini(struct nv50_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_device *device = disp->base.engine.subdev.device; nvkm_mask(device, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000); } -const struct nvkm_event_func -gf119_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = gf119_disp_vblank_init, - .fini = gf119_disp_vblank_fini, -}; - static struct nvkm_output * exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len, @@ -103,7 +94,8 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, static struct nvkm_output * exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info; @@ -123,7 +115,7 @@ exec_script(struct nv50_disp *disp, int head, int id) outp = exec_lookup(disp, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info); if (outp) { struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = info.script[id], .outp = &outp->info, @@ -140,7 +132,8 @@ exec_script(struct nv50_disp *disp, int head, int id) static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info1; @@ -185,7 +178,7 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = data, .outp = &outp->info, @@ -329,8 +322,8 @@ gf119_disp_intr_unk2_2(struct nv50_disp *disp, int head) if (nvkm_output_dp_train(outp, pclk, true)) OUTP_ERR(outp, "link not trained before attach"); } else { - if (disp->sor.magic) - disp->sor.magic(outp); + if (disp->func->sor.magic) + disp->func->sor.magic(outp); } exec_clkcmp(disp, head, 0, pclk, &conf); @@ -377,14 +370,14 @@ gf119_disp_intr_supervisor(struct work_struct *work) int head; nvkm_debug(subdev, "supervisor %d\n", ffs(disp->super)); - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { mask[head] = nvkm_rd32(device, 0x6101d4 + (head * 0x800)); nvkm_debug(subdev, "head %d: %08x\n", head, mask[head]); } if (disp->super & 0x00000001) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head); @@ -392,19 +385,19 @@ gf119_disp_intr_supervisor(struct work_struct *work) } } else if (disp->super & 0x00000002) { - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; nvkm_debug(subdev, "supervisor 2.0 - head %d\n", head); gf119_disp_intr_unk2_0(disp, head); } - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(mask[head] & 0x00010000)) continue; nvkm_debug(subdev, "supervisor 2.1 - head %d\n", head); gf119_disp_intr_unk2_1(disp, head); } - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; nvkm_debug(subdev, "supervisor 2.2 - head %d\n", head); @@ -412,7 +405,7 @@ gf119_disp_intr_supervisor(struct work_struct *work) } } else if (disp->super & 0x00000004) { - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(mask[head] & 0x00001000)) continue; nvkm_debug(subdev, "supervisor 3.0 - head %d\n", head); @@ -420,7 +413,7 @@ gf119_disp_intr_supervisor(struct work_struct *work) } } - for (head = 0; head < disp->head.nr; head++) + for (head = 0; head < disp->base.head.nr; head++) nvkm_wr32(device, 0x6101d4 + (head * 0x800), 0x00000000); nvkm_wr32(device, 0x6101d0, 0x80000000); } @@ -452,9 +445,9 @@ gf119_disp_intr_error(struct nv50_disp *disp, int chid) } void -gf119_disp_intr(struct nvkm_subdev *subdev) +gf119_disp_intr(struct nv50_disp *disp) { - struct nv50_disp *disp = (void *)subdev; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; struct nvkm_device *device = subdev->device; u32 intr = nvkm_rd32(device, 0x610088); int i; @@ -494,7 +487,7 @@ gf119_disp_intr(struct nvkm_subdev *subdev) intr &= ~0x00100000; } - for (i = 0; i < disp->head.nr; i++) { + for (i = 0; i < disp->base.head.nr; i++) { u32 mask = 0x01000000 << i; if (mask & intr) { u32 stat = nvkm_rd32(device, 0x6100bc + (i * 0x800)); @@ -506,59 +499,38 @@ gf119_disp_intr(struct nvkm_subdev *subdev) } } -static const struct nvkm_disp_func +int +gf119_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, + int index, struct nvkm_disp **pdisp) +{ + u32 heads = nvkm_rd32(device, 0x022448); + return nv50_disp_new_(func, device, index, heads, pdisp); +} + +static const struct nv50_disp_func gf119_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, .root = &gf119_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gf119_hdmi_ctrl, }; -static int -gf119_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf119_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nvkm_device *device = (void *)parent; - struct nv50_disp *disp; - int heads = nvkm_rd32(device, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &gf119_disp; - - ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = gf119_disp_intr; - INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->head.nr = heads; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf119_hda_eld; - disp->sor.hdmi = gf119_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gf119_disp, device, index, pdisp); } - -struct nvkm_oclass * -gf110_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x90), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf119_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf119_sor_dp_new, - .base.vblank = &gf119_disp_vblank_func, - .head.scanoutpos = gf119_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c index e478c9f87fc6f..a86384b8e388d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c @@ -24,59 +24,30 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func gk104_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, .root = &gk104_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, }; -static int -gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk104_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nvkm_device *device = (void *)parent; - struct nv50_disp *disp; - int heads = nvkm_rd32(device, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &gk104_disp; - - ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = gf119_disp_intr; - INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->head.nr = heads; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf119_hda_eld; - disp->sor.hdmi = gk104_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gk104_disp, device, index, pdisp); } - -struct nvkm_oclass * -gk104_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x91), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf119_sor_dp_new, - .base.vblank = &gf119_disp_vblank_func, - .head.scanoutpos = gf119_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c index f4801f8e8c7e9..0d574c7e594ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c @@ -24,59 +24,30 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func gk110_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, .root = &gk110_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, }; -static int -gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gk110_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nvkm_device *device = (void *)parent; - struct nv50_disp *disp; - int heads = nvkm_rd32(device, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &gk110_disp; - - ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = gf119_disp_intr; - INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->head.nr = heads; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf119_hda_eld; - disp->sor.hdmi = gk104_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gk110_disp, device, index, pdisp); } - -struct nvkm_oclass * -gk110_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x92), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk110_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf119_sor_dp_new, - .base.vblank = &gf119_disp_vblank_func, - .head.scanoutpos = gf119_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c index a72f61078acf2..b6944142d616f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c @@ -24,59 +24,30 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func gm107_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, .root = &gm107_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gf119_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, }; -static int -gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm107_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nvkm_device *device = (void *)parent; - struct nv50_disp *disp; - int heads = nvkm_rd32(device, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &gm107_disp; - - ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = gf119_disp_intr; - INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->head.nr = heads; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf119_hda_eld; - disp->sor.hdmi = gk104_hdmi_ctrl; - return 0; + return gf119_disp_new_(&gm107_disp, device, index, pdisp); } - -struct nvkm_oclass * -gm107_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x07), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm107_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gf119_sor_dp_new, - .base.vblank = &gf119_disp_vblank_func, - .head.scanoutpos = gf119_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c index 363e939376e96..30f1987b5b402 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c @@ -24,60 +24,31 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func gm204_disp = { + .intr = gf119_disp_intr, + .uevent = &gf119_disp_chan_uevent, + .super = gf119_disp_intr_supervisor, .root = &gm204_disp_root_oclass, + .head.vblank_init = gf119_disp_vblank_init, + .head.vblank_fini = gf119_disp_vblank_fini, + .head.scanoutpos = gf119_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = gm204_sor_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gf119_hda_eld, + .sor.hdmi = gk104_hdmi_ctrl, + .sor.magic = gm204_sor_magic, }; -static int -gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gm204_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nvkm_device *device = (void *)parent; - struct nv50_disp *disp; - int heads = nvkm_rd32(device, 0x022448); - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, heads, - "PDISP", "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &gm204_disp; - - ret = nvkm_event_init(&gf119_disp_chan_uevent, 1, 17, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = gf119_disp_intr; - INIT_WORK(&disp->supervisor, gf119_disp_intr_supervisor); - disp->head.nr = heads; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gf119_hda_eld; - disp->sor.hdmi = gf119_hdmi_ctrl; - disp->sor.magic = gm204_sor_magic; - return 0; + return gf119_disp_new_(&gm204_disp, device, index, pdisp); } - -struct nvkm_oclass * -gm204_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x07), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = gm204_sor_dp_new, - .base.vblank = &gf119_disp_vblank_func, - .head.scanoutpos = gf119_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c index c699c5f70b8d5..6bc3bf0960013 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c @@ -24,59 +24,32 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func +static const struct nv50_disp_func gt200_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, .root = >200_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 2, + .sor.power = nv50_sor_power, + .sor.hdmi = g84_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -static int -gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt200_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp *disp; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = >200_disp; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = nv50_disp_intr; - INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->head.nr = 2; - disp->dac.nr = 3; - disp->sor.nr = 2; - disp->pior.nr = 3; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hdmi = g84_hdmi_ctrl; - disp->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(>200_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -gt200_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x83), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt200_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.external.tmds = nv50_pior_output_new, - .base.outp.external.dp = nv50_pior_dp_new, - .base.vblank = &nv50_disp_vblank_func, - .head.scanoutpos = nv50_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c index ddf65902fd231..94026288ab4da 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c @@ -24,61 +24,34 @@ #include "nv50.h" #include "rootnv50.h" -static const struct nvkm_disp_func -gt215_disp_func = { +static const struct nv50_disp_func +gt215_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, .root = >215_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.internal.dp = g94_sor_dp_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 4, + .sor.power = nv50_sor_power, + .sor.hda_eld = gt215_hda_eld, + .sor.hdmi = gt215_hdmi_ctrl, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -static int -gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gt215_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp *disp; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = >215_disp_func; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = nv50_disp_intr; - INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->head.nr = 2; - disp->dac.nr = 3; - disp->sor.nr = 4; - disp->pior.nr = 3; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->sor.hda_eld = gt215_hda_eld; - disp->sor.hdmi = gt215_hdmi_ctrl; - disp->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(>215_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -gt215_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x85), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gt215_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.internal.dp = g94_sor_dp_new, - .base.outp.external.lvds = nv50_pior_output_new, - .base.outp.external.dp = nv50_pior_dp_new, - .base.vblank = &nv50_disp_vblank_func, - .head.scanoutpos = nv50_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c index 33922f3a176a5..67254ce6f83f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c @@ -23,34 +23,31 @@ */ #include "priv.h" +static const struct nvkm_disp_oclass * +nv04_disp_root(struct nvkm_disp *disp) +{ + return &nv04_disp_root_oclass; +} + static void -nv04_disp_vblank_init(struct nvkm_event *event, int type, int head) +nv04_disp_vblank_init(struct nvkm_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); struct nvkm_device *device = disp->engine.subdev.device; nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000001); } static void -nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head) +nv04_disp_vblank_fini(struct nvkm_disp *disp, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); struct nvkm_device *device = disp->engine.subdev.device; nvkm_wr32(device, 0x600140 + (head * 0x2000) , 0x00000000); } -static const struct nvkm_event_func -nv04_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = nv04_disp_vblank_init, - .fini = nv04_disp_vblank_fini, -}; - static void -nv04_disp_intr(struct nvkm_subdev *subdev) +nv04_disp_intr(struct nvkm_disp *disp) { - struct nvkm_disp *disp = (void *)subdev; - struct nvkm_device *device = disp->engine.subdev.device; + struct nvkm_subdev *subdev = &disp->engine.subdev; + struct nvkm_device *device = subdev->device; u32 crtc0 = nvkm_rd32(device, 0x600100); u32 crtc1 = nvkm_rd32(device, 0x602100); u32 pvideo; @@ -65,8 +62,7 @@ nv04_disp_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x602100, 0x00000001); } - if (nv_device(disp)->chipset >= 0x10 && - nv_device(disp)->chipset <= 0x40) { + if (device->chipset >= 0x10 && device->chipset <= 0x40) { pvideo = nvkm_rd32(device, 0x8100); if (pvideo & ~0x11) nvkm_info(subdev, "PVIDEO intr: %08x\n", pvideo); @@ -76,37 +72,14 @@ nv04_disp_intr(struct nvkm_subdev *subdev) static const struct nvkm_disp_func nv04_disp = { - .root = &nv04_disp_root_oclass, + .intr = nv04_disp_intr, + .root = nv04_disp_root, + .head.vblank_init = nv04_disp_vblank_init, + .head.vblank_fini = nv04_disp_vblank_fini, }; -static int -nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv04_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nvkm_disp *disp; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "DISPLAY", - "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->func = &nv04_disp; - - nv_subdev(disp)->intr = nv04_disp_intr; - return 0; + return nvkm_disp_new_(&nv04_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -nv04_disp_oclass = &(struct nvkm_disp_impl) { - .base.handle = NV_ENGINE(DISP, 0x04), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .vblank = &nv04_disp_vblank_func, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c index ddffcc1088bec..32e73a975b587 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c @@ -33,29 +33,147 @@ #include #include +static const struct nvkm_disp_oclass * +nv50_disp_root_(struct nvkm_disp *base) +{ + return nv50_disp(base)->func->root; +} + +static int +nv50_disp_outp_internal_crt_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, struct nvkm_output **poutp) +{ + struct nv50_disp *disp = nv50_disp(base); + return disp->func->outp.internal.crt(base, index, dcb, poutp); +} + +static int +nv50_disp_outp_internal_tmds_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, + struct nvkm_output **poutp) +{ + struct nv50_disp *disp = nv50_disp(base); + return disp->func->outp.internal.tmds(base, index, dcb, poutp); +} + +static int +nv50_disp_outp_internal_lvds_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, + struct nvkm_output **poutp) +{ + struct nv50_disp *disp = nv50_disp(base); + return disp->func->outp.internal.lvds(base, index, dcb, poutp); +} + +static int +nv50_disp_outp_internal_dp_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, struct nvkm_output **poutp) +{ + struct nv50_disp *disp = nv50_disp(base); + if (disp->func->outp.internal.dp) + return disp->func->outp.internal.dp(base, index, dcb, poutp); + return -ENODEV; +} + +static int +nv50_disp_outp_external_tmds_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, + struct nvkm_output **poutp) +{ + struct nv50_disp *disp = nv50_disp(base); + if (disp->func->outp.external.tmds) + return disp->func->outp.external.tmds(base, index, dcb, poutp); + return -ENODEV; +} + +static int +nv50_disp_outp_external_dp_(struct nvkm_disp *base, int index, + struct dcb_output *dcb, struct nvkm_output **poutp) +{ + struct nv50_disp *disp = nv50_disp(base); + if (disp->func->outp.external.dp) + return disp->func->outp.external.dp(base, index, dcb, poutp); + return -ENODEV; +} + static void -nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head) +nv50_disp_vblank_fini_(struct nvkm_disp *base, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - struct nvkm_device *device = disp->engine.subdev.device; - nvkm_mask(device, 0x61002c, (4 << head), 0); + struct nv50_disp *disp = nv50_disp(base); + disp->func->head.vblank_fini(disp, head); } static void -nv50_disp_vblank_init(struct nvkm_event *event, int type, int head) +nv50_disp_vblank_init_(struct nvkm_disp *base, int head) { - struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank); - struct nvkm_device *device = disp->engine.subdev.device; - nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); + struct nv50_disp *disp = nv50_disp(base); + disp->func->head.vblank_init(disp, head); +} + +static void +nv50_disp_intr_(struct nvkm_disp *base) +{ + struct nv50_disp *disp = nv50_disp(base); + disp->func->intr(disp); +} + +static void * +nv50_disp_dtor_(struct nvkm_disp *base) +{ + struct nv50_disp *disp = nv50_disp(base); + nvkm_event_fini(&disp->uevent); + return disp; } -const struct nvkm_event_func -nv50_disp_vblank_func = { - .ctor = nvkm_disp_vblank_ctor, - .init = nv50_disp_vblank_init, - .fini = nv50_disp_vblank_fini, +static const struct nvkm_disp_func +nv50_disp_ = { + .dtor = nv50_disp_dtor_, + .intr = nv50_disp_intr_, + .root = nv50_disp_root_, + .outp.internal.crt = nv50_disp_outp_internal_crt_, + .outp.internal.tmds = nv50_disp_outp_internal_tmds_, + .outp.internal.lvds = nv50_disp_outp_internal_lvds_, + .outp.internal.dp = nv50_disp_outp_internal_dp_, + .outp.external.tmds = nv50_disp_outp_external_tmds_, + .outp.external.dp = nv50_disp_outp_external_dp_, + .head.vblank_init = nv50_disp_vblank_init_, + .head.vblank_fini = nv50_disp_vblank_fini_, }; +int +nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device, + int index, int heads, struct nvkm_disp **pdisp) +{ + struct nv50_disp *disp; + int ret; + + if (!(disp = kzalloc(sizeof(*disp), GFP_KERNEL))) + return -ENOMEM; + INIT_WORK(&disp->supervisor, func->super); + disp->func = func; + *pdisp = &disp->base; + + ret = nvkm_disp_ctor(&nv50_disp_, device, index, heads, &disp->base); + if (ret) + return ret; + + return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent); +} + +void +nv50_disp_vblank_fini(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head), 0); +} + +void +nv50_disp_vblank_init(struct nv50_disp *disp, int head) +{ + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_mask(device, 0x61002c, (4 << head), (4 << head)); +} + static const struct nvkm_enum nv50_disp_intr_error_type[] = { { 3, "ILLEGAL_MTHD" }, @@ -166,7 +284,8 @@ exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl, static struct nvkm_output * exec_script(struct nv50_disp *disp, int head, int id) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info; @@ -176,26 +295,26 @@ exec_script(struct nv50_disp *disp, int head, int id) int i; /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) ctrl = nvkm_rd32(device, 0x610b5c + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { - if (nv_device(disp)->chipset < 0x90 || - nv_device(disp)->chipset == 0x92 || - nv_device(disp)->chipset == 0xa0) { + if (device->chipset < 0x90 || + device->chipset == 0x92 || + device->chipset == 0xa0) { reg = 0x610b74; } else { reg = 0x610798; } - for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) ctrl = nvkm_rd32(device, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) ctrl = nvkm_rd32(device, 0x610b84 + (i * 8)); i += 8; } @@ -207,7 +326,7 @@ exec_script(struct nv50_disp *disp, int head, int id) outp = exec_lookup(disp, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info); if (outp) { struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = info.script[id], .outp = &outp->info, @@ -224,7 +343,8 @@ exec_script(struct nv50_disp *disp, int head, int id) static struct nvkm_output * exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) { - struct nvkm_device *device = disp->base.engine.subdev.device; + struct nvkm_subdev *subdev = &disp->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_bios *bios = device->bios; struct nvkm_output *outp; struct nvbios_outp info1; @@ -235,26 +355,26 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) int i; /* DAC */ - for (i = 0; !(ctrl & (1 << head)) && i < disp->dac.nr; i++) + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->dac.nr; i++) ctrl = nvkm_rd32(device, 0x610b58 + (i * 8)); /* SOR */ if (!(ctrl & (1 << head))) { - if (nv_device(disp)->chipset < 0x90 || - nv_device(disp)->chipset == 0x92 || - nv_device(disp)->chipset == 0xa0) { + if (device->chipset < 0x90 || + device->chipset == 0x92 || + device->chipset == 0xa0) { reg = 0x610b70; } else { reg = 0x610794; } - for (i = 0; !(ctrl & (1 << head)) && i < disp->sor.nr; i++) + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->sor.nr; i++) ctrl = nvkm_rd32(device, reg + (i * 8)); i += 4; } /* PIOR */ if (!(ctrl & (1 << head))) { - for (i = 0; !(ctrl & (1 << head)) && i < disp->pior.nr; i++) + for (i = 0; !(ctrl & (1 << head)) && i < disp->func->pior.nr; i++) ctrl = nvkm_rd32(device, 0x610b80 + (i * 8)); i += 8; } @@ -295,7 +415,7 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf) data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk); if (data) { struct nvbios_init init = { - .subdev = nv_subdev(disp), + .subdev = subdev, .bios = bios, .offset = data, .outp = &outp->info, @@ -620,7 +740,7 @@ nv50_disp_intr_supervisor(struct work_struct *work) if (disp->super & 0x00000010) { nv50_disp_chan_mthd(disp->chan[0], NV_DBG_DEBUG); - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000020 << head))) continue; if (!(super & (0x00000080 << head))) @@ -629,24 +749,24 @@ nv50_disp_intr_supervisor(struct work_struct *work) } } else if (disp->super & 0x00000020) { - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000080 << head))) continue; nv50_disp_intr_unk20_0(disp, head); } - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000200 << head))) continue; nv50_disp_intr_unk20_1(disp, head); } - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000080 << head))) continue; nv50_disp_intr_unk20_2(disp, head); } } else if (disp->super & 0x00000040) { - for (head = 0; head < disp->head.nr; head++) { + for (head = 0; head < disp->base.head.nr; head++) { if (!(super & (0x00000080 << head))) continue; nv50_disp_intr_unk40_0(disp, head); @@ -657,9 +777,8 @@ nv50_disp_intr_supervisor(struct work_struct *work) } void -nv50_disp_intr(struct nvkm_subdev *subdev) +nv50_disp_intr(struct nv50_disp *disp) { - struct nv50_disp *disp = (void *)subdev; struct nvkm_device *device = disp->base.engine.subdev.device; u32 intr0 = nvkm_rd32(device, 0x610020); u32 intr1 = nvkm_rd32(device, 0x610024); @@ -693,58 +812,31 @@ nv50_disp_intr(struct nvkm_subdev *subdev) } } -static const struct nvkm_disp_func +static const struct nv50_disp_func nv50_disp = { + .intr = nv50_disp_intr, + .uevent = &nv50_disp_chan_uevent, + .super = nv50_disp_intr_supervisor, .root = &nv50_disp_root_oclass, + .head.vblank_init = nv50_disp_vblank_init, + .head.vblank_fini = nv50_disp_vblank_fini, + .head.scanoutpos = nv50_disp_root_scanoutpos, + .outp.internal.crt = nv50_dac_output_new, + .outp.internal.tmds = nv50_sor_output_new, + .outp.internal.lvds = nv50_sor_output_new, + .outp.external.tmds = nv50_pior_output_new, + .outp.external.dp = nv50_pior_dp_new, + .dac.nr = 3, + .dac.power = nv50_dac_power, + .dac.sense = nv50_dac_sense, + .sor.nr = 2, + .sor.power = nv50_sor_power, + .pior.nr = 3, + .pior.power = nv50_pior_power, }; -static int -nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_disp_new(struct nvkm_device *device, int index, struct nvkm_disp **pdisp) { - struct nv50_disp *disp; - int ret; - - ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP", - "display", &disp); - *pobject = nv_object(disp); - if (ret) - return ret; - - disp->base.func = &nv50_disp; - - ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &disp->uevent); - if (ret) - return ret; - - nv_subdev(disp)->intr = nv50_disp_intr; - INIT_WORK(&disp->supervisor, nv50_disp_intr_supervisor); - disp->head.nr = 2; - disp->dac.nr = 3; - disp->sor.nr = 2; - disp->pior.nr = 3; - disp->dac.power = nv50_dac_power; - disp->dac.sense = nv50_dac_sense; - disp->sor.power = nv50_sor_power; - disp->pior.power = nv50_pior_power; - return 0; + return nv50_disp_new_(&nv50_disp, device, index, 2, pdisp); } - -struct nvkm_oclass * -nv50_disp_oclass = &(struct nv50_disp_impl) { - .base.base.handle = NV_ENGINE(DISP, 0x50), - .base.base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_disp_ctor, - .dtor = _nvkm_disp_dtor, - .init = _nvkm_disp_init, - .fini = _nvkm_disp_fini, - }, - .base.outp.internal.crt = nv50_dac_output_new, - .base.outp.internal.tmds = nv50_sor_output_new, - .base.outp.internal.lvds = nv50_sor_output_new, - .base.outp.external.tmds = nv50_pior_output_new, - .base.outp.external.dp = nv50_pior_dp_new, - .base.vblank = &nv50_disp_vblank_func, - .head.scanoutpos = nv50_disp_root_scanoutpos, -}.base.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h index 13766b24706d7..aecebd8717e5c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h @@ -11,6 +11,7 @@ struct nvkm_output_dp; #define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp struct nv50_disp { + const struct nv50_disp_func *func; struct nvkm_disp base; struct work_struct supervisor; @@ -19,37 +20,16 @@ struct nv50_disp { struct nvkm_event uevent; struct { - int nr; - } head; - struct { - int nr; - int (*power)(NV50_DISP_MTHD_V1); - int (*sense)(NV50_DISP_MTHD_V1); - } dac; - struct { - int nr; - int (*power)(NV50_DISP_MTHD_V1); - int (*hda_eld)(NV50_DISP_MTHD_V1); - int (*hdmi)(NV50_DISP_MTHD_V1); u32 lvdsconf; - void (*magic)(struct nvkm_output *); } sor; + struct { - int nr; - int (*power)(NV50_DISP_MTHD_V1); u8 type[3]; } pior; struct nv50_disp_chan *chan[17]; }; -struct nv50_disp_impl { - struct nvkm_disp_impl base; - struct { - int (*scanoutpos)(NV50_DISP_MTHD_V0); - } head; -}; - int nv50_disp_root_scanoutpos(NV50_DISP_MTHD_V0); int gf119_disp_root_scanoutpos(NV50_DISP_MTHD_V0); @@ -68,11 +48,70 @@ int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1); int nv50_sor_power(NV50_DISP_MTHD_V1); int nv50_pior_power(NV50_DISP_MTHD_V1); +int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, + int index, int heads, struct nvkm_disp **); +int gf119_disp_new_(const struct nv50_disp_func *, struct nvkm_device *, + int index, struct nvkm_disp **); + +struct nv50_disp_func_outp { + int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* tv)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*tmds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (*lvds)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); + int (* dp)(struct nvkm_disp *, int index, struct dcb_output *, + struct nvkm_output **); +}; + +struct nv50_disp_func { + void (*intr)(struct nv50_disp *); + + const struct nvkm_event_func *uevent; + void (*super)(struct work_struct *); + + const struct nvkm_disp_oclass *root; + + struct { + void (*vblank_init)(struct nv50_disp *, int head); + void (*vblank_fini)(struct nv50_disp *, int head); + int (*scanoutpos)(NV50_DISP_MTHD_V0); + } head; + + struct { + const struct nv50_disp_func_outp internal; + const struct nv50_disp_func_outp external; + } outp; + + struct { + int nr; + int (*power)(NV50_DISP_MTHD_V1); + int (*sense)(NV50_DISP_MTHD_V1); + } dac; + + struct { + int nr; + int (*power)(NV50_DISP_MTHD_V1); + int (*hda_eld)(NV50_DISP_MTHD_V1); + int (*hdmi)(NV50_DISP_MTHD_V1); + void (*magic)(struct nvkm_output *); + } sor; + + struct { + int nr; + int (*power)(NV50_DISP_MTHD_V1); + } pior; +}; + +void nv50_disp_vblank_init(struct nv50_disp *, int); +void nv50_disp_vblank_fini(struct nv50_disp *, int); +void nv50_disp_intr(struct nv50_disp *); void nv50_disp_intr_supervisor(struct work_struct *); -void nv50_disp_intr(struct nvkm_subdev *); -extern const struct nvkm_event_func nv50_disp_vblank_func; +void gf119_disp_vblank_init(struct nv50_disp *, int); +void gf119_disp_vblank_fini(struct nv50_disp *, int); +void gf119_disp_intr(struct nv50_disp *); void gf119_disp_intr_supervisor(struct work_struct *); -void gf119_disp_intr(struct nvkm_subdev *); -extern const struct nvkm_event_func gf119_disp_vblank_func; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c index 6f31c81fdb018..cd888a1e443c7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/oimmnv50.c @@ -47,7 +47,7 @@ nv50_disp_oimm_new(const struct nv50_disp_chan_func *func, if (nvif_unpack(args->v0, 0, 0, false)) { nvif_ioctl(parent, "create disp overlay vers %d head %d\n", args->v0.version, args->v0.head); - if (args->v0.head > disp->head.nr) + if (args->v0.head > disp->base.head.nr) return -EINVAL; head = args->v0.head; } else diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c index 110662c1fe04a..6fa296c047b87 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ovlynv50.c @@ -49,7 +49,7 @@ nv50_disp_ovly_new(const struct nv50_disp_dmac_func *func, nvif_ioctl(parent, "create disp overlay channel dma vers %d " "pushbuf %016llx head %d\n", args->v0.version, args->v0.pushbuf, args->v0.head); - if (args->v0.head > disp->head.nr) + if (args->v0.head > disp->base.head.nr) return -EINVAL; push = args->v0.pushbuf; head = args->v0.head; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h index 6cd6086ce78bf..c2452957fc57c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h @@ -4,6 +4,12 @@ #include "outp.h" #include "outpdp.h" +int nvkm_disp_ctor(const struct nvkm_disp_func *, struct nvkm_device *, + int index, int heads, struct nvkm_disp *); +int nvkm_disp_new_(const struct nvkm_disp_func *, struct nvkm_device *, + int index, int heads, struct nvkm_disp **); +void nvkm_disp_vblank(struct nvkm_disp *, int head); + struct nvkm_disp_func_outp { int (* crt)(struct nvkm_disp *, int index, struct dcb_output *, struct nvkm_output **); @@ -17,44 +23,23 @@ struct nvkm_disp_func_outp { struct nvkm_output **); }; -struct nvkm_disp_impl { - struct nvkm_oclass base; +struct nvkm_disp_func { + void *(*dtor)(struct nvkm_disp *); + void (*intr)(struct nvkm_disp *); + + const struct nvkm_disp_oclass *(*root)(struct nvkm_disp *); + + struct { + void (*vblank_init)(struct nvkm_disp *, int head); + void (*vblank_fini)(struct nvkm_disp *, int head); + } head; + struct { const struct nvkm_disp_func_outp internal; const struct nvkm_disp_func_outp external; } outp; - const struct nvkm_event_func *vblank; }; -#define nvkm_disp_create(p,e,c,h,i,x,d) \ - nvkm_disp_create_((p), (e), (c), (h), (i), (x), \ - sizeof(**d), (void **)d) -#define nvkm_disp_destroy(d) ({ \ - struct nvkm_disp *disp = (d); \ - _nvkm_disp_dtor(nv_object(disp)); \ -}) -#define nvkm_disp_init(d) ({ \ - struct nvkm_disp *disp = (d); \ - _nvkm_disp_init(nv_object(disp)); \ -}) -#define nvkm_disp_fini(d,s) ({ \ - struct nvkm_disp *disp = (d); \ - _nvkm_disp_fini(nv_object(disp), (s)); \ -}) - -int nvkm_disp_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int heads, - const char *, const char *, int, void **); -void _nvkm_disp_dtor(struct nvkm_object *); -int _nvkm_disp_init(struct nvkm_object *); -int _nvkm_disp_fini(struct nvkm_object *, bool); - -extern struct nvkm_oclass *nvkm_output_oclass; -extern struct nvkm_oclass *nvkm_connector_oclass; - -int nvkm_disp_vblank_ctor(struct nvkm_object *, void *data, u32 size, - struct nvkm_notify *); -void nvkm_disp_vblank(struct nvkm_disp *, int head); int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **); extern const struct nvkm_disp_oclass nv04_disp_root_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c index 5868c446b8461..8591726871ac2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootgf119.c @@ -87,7 +87,7 @@ gf119_disp_root_init(struct nv50_disp_root *root) */ /* ... CRTC caps */ - for (i = 0; i < disp->head.nr; i++) { + for (i = 0; i < disp->base.head.nr; i++) { tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); nvkm_wr32(device, 0x6101b4 + (i * 0x800), tmp); tmp = nvkm_rd32(device, 0x616108 + (i * 0x800)); @@ -97,13 +97,13 @@ gf119_disp_root_init(struct nv50_disp_root *root) } /* ... DAC caps */ - for (i = 0; i < disp->dac.nr; i++) { + for (i = 0; i < disp->func->dac.nr; i++) { tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); nvkm_wr32(device, 0x6101c0 + (i * 0x800), tmp); } /* ... SOR caps */ - for (i = 0; i < disp->sor.nr; i++) { + for (i = 0; i < disp->func->sor.nr; i++) { tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); nvkm_wr32(device, 0x6301c4 + (i * 0x800), tmp); } @@ -133,7 +133,7 @@ gf119_disp_root_init(struct nv50_disp_root *root) * * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt */ - for (i = 0; i < disp->head.nr; i++) + for (i = 0; i < disp->base.head.nr; i++) nvkm_mask(device, 0x616308 + (i * 0x800), 0x00000111, 0x00000010); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c index 472357f499ad0..06fb24d887021 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/rootnv50.c @@ -74,7 +74,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } *args = data; struct nv50_disp_root *root = nv50_disp_root(object); struct nv50_disp *disp = root->disp; - const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine); + const struct nv50_disp_func *func = disp->func; struct nvkm_output *outp = NULL; struct nvkm_output *temp; u16 type, mask = 0; @@ -102,7 +102,7 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } else return ret; - if (head < 0 || head >= disp->head.nr) + if (head < 0 || head >= disp->base.head.nr) return -ENXIO; if (mask) { @@ -119,26 +119,26 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) switch (mthd) { case NV50_DISP_SCANOUTPOS: - return impl->head.scanoutpos(object, disp, data, size, head); + return func->head.scanoutpos(object, disp, data, size, head); default: break; } switch (mthd * !!outp) { case NV50_DISP_MTHD_V1_DAC_PWR: - return disp->dac.power(object, disp, data, size, head, outp); + return func->dac.power(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_DAC_LOAD: - return disp->dac.sense(object, disp, data, size, head, outp); + return func->dac.sense(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_PWR: - return disp->sor.power(object, disp, data, size, head, outp); + return func->sor.power(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_HDA_ELD: - if (!disp->sor.hda_eld) + if (!func->sor.hda_eld) return -ENODEV; - return disp->sor.hda_eld(object, disp, data, size, head, outp); + return func->sor.hda_eld(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_HDMI_PWR: - if (!disp->sor.hdmi) + if (!func->sor.hdmi) return -ENODEV; - return disp->sor.hdmi(object, disp, data, size, head, outp); + return func->sor.hdmi(object, disp, data, size, head, outp); case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: { union { struct nv50_disp_sor_lvds_script_v0 v0; @@ -178,9 +178,9 @@ nv50_disp_root_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) } break; case NV50_DISP_MTHD_V1_PIOR_PWR: - if (!disp->pior.power) + if (!func->pior.power) return -ENODEV; - return disp->pior.power(object, disp, data, size, head, outp); + return func->pior.power(object, disp, data, size, head, outp); default: break; } @@ -318,7 +318,7 @@ nv50_disp_root_init(struct nv50_disp_root *root) nvkm_wr32(device, 0x610184, tmp); /* ... CRTC caps */ - for (i = 0; i < disp->head.nr; i++) { + for (i = 0; i < disp->base.head.nr; i++) { tmp = nvkm_rd32(device, 0x616100 + (i * 0x800)); nvkm_wr32(device, 0x610190 + (i * 0x10), tmp); tmp = nvkm_rd32(device, 0x616104 + (i * 0x800)); @@ -330,19 +330,19 @@ nv50_disp_root_init(struct nv50_disp_root *root) } /* ... DAC caps */ - for (i = 0; i < disp->dac.nr; i++) { + for (i = 0; i < disp->func->dac.nr; i++) { tmp = nvkm_rd32(device, 0x61a000 + (i * 0x800)); nvkm_wr32(device, 0x6101d0 + (i * 0x04), tmp); } /* ... SOR caps */ - for (i = 0; i < disp->sor.nr; i++) { + for (i = 0; i < disp->func->sor.nr; i++) { tmp = nvkm_rd32(device, 0x61c000 + (i * 0x800)); nvkm_wr32(device, 0x6101e0 + (i * 0x04), tmp); } /* ... PIOR caps */ - for (i = 0; i < disp->pior.nr; i++) { + for (i = 0; i < disp->func->pior.nr; i++) { tmp = nvkm_rd32(device, 0x61e000 + (i * 0x800)); nvkm_wr32(device, 0x6101f0 + (i * 0x04), tmp); } -- GitLab From 13de7f462902d1a452d501cdb2d06ef02cabbfff Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5555/7006] drm/nouveau/fifo: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/engine/fifo.h | 83 ++------ drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 136 ++++++------ .../drm/nouveau/nvkm/engine/device/gf100.c | 9 - .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 7 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 -- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 3 +- .../gpu/drm/nouveau/nvkm/engine/fifo/Kbuild | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/base.c | 128 ++++++++--- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/chan.h | 1 + .../drm/nouveau/nvkm/engine/fifo/dmanv04.c | 8 +- .../drm/nouveau/nvkm/engine/fifo/dmanv10.c | 1 + .../drm/nouveau/nvkm/engine/fifo/dmanv17.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/g84.c | 71 ++----- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 162 +++++++------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 198 ++++++++---------- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 24 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/gk208.c | 30 ++- .../gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c | 30 ++- .../gpu/drm/nouveau/nvkm/engine/fifo/gm204.c | 32 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c | 30 ++- .../nouveau/nvkm/engine/fifo/gpfifogf100.c | 1 + .../nouveau/nvkm/engine/fifo/gpfifogk104.c | 1 + .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 92 ++++---- .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.h | 10 +- .../gpu/drm/nouveau/nvkm/engine/fifo/nv10.c | 45 +--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv17.c | 57 ++--- .../gpu/drm/nouveau/nvkm/engine/fifo/nv40.c | 59 ++---- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.c | 103 +++++---- .../gpu/drm/nouveau/nvkm/engine/fifo/nv50.h | 8 +- .../gpu/drm/nouveau/nvkm/engine/fifo/priv.h | 19 ++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 5 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 1 + .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 1 + .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c | 1 + .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 1 + drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 2 + .../gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 4 +- 56 files changed, 640 insertions(+), 801 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index d9e494ba50338..84cc3e9cfed72 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -1,7 +1,5 @@ #ifndef __NVKM_FIFO_H__ #define __NVKM_FIFO_H__ -#define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object) -#define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine) #include #include @@ -33,46 +31,21 @@ struct nvkm_fifo_chan { extern const struct nvkm_object_func nvkm_fifo_chan_func; -#include -struct nvkm_fifo_base { - struct nvkm_gpuobj gpuobj; -}; - -#define nvkm_fifo_context_create(p,e,c,g,s,a,f,d) \ - nvkm_gpuobj_create((p), (e), (c), NV_ENGCTX_CLASS, (g), (s), (a), (f), (d)) -#define nvkm_fifo_context_destroy(p) \ - nvkm_gpuobj_destroy(&(p)->gpuobj) -#define nvkm_fifo_context_init(p) \ - nvkm_gpuobj_init(&(p)->gpuobj) -#define nvkm_fifo_context_fini(p,s) \ - nvkm_gpuobj_fini(&(p)->gpuobj, (s)) - -#define _nvkm_fifo_context_dtor _nvkm_gpuobj_dtor -#define _nvkm_fifo_context_init _nvkm_gpuobj_init -#define _nvkm_fifo_context_fini _nvkm_gpuobj_fini -#define _nvkm_fifo_context_rd32 _nvkm_gpuobj_rd32 -#define _nvkm_fifo_context_wr32 _nvkm_gpuobj_wr32 - struct nvkm_fifo { - struct nvkm_engine engine; const struct nvkm_fifo_func *func; - - struct nvkm_event cevent; /* channel creation event */ - struct nvkm_event uevent; /* async user trigger */ + struct nvkm_engine engine; DECLARE_BITMAP(mask, NVKM_FIFO_CHID_NR); int nr; struct list_head chan; spinlock_t lock; - void (*pause)(struct nvkm_fifo *, unsigned long *); - void (*start)(struct nvkm_fifo *, unsigned long *); + struct nvkm_event uevent; /* async user trigger */ + struct nvkm_event cevent; /* channel creation event */ }; -struct nvkm_fifo_func { - void *(*dtor)(struct nvkm_fifo *); - const struct nvkm_fifo_chan_oclass *chan[]; -}; +void nvkm_fifo_pause(struct nvkm_fifo *, unsigned long *); +void nvkm_fifo_start(struct nvkm_fifo *, unsigned long *); void nvkm_fifo_chan_put(struct nvkm_fifo *, unsigned long flags, struct nvkm_fifo_chan **); @@ -81,38 +54,16 @@ nvkm_fifo_chan_inst(struct nvkm_fifo *, u64 inst, unsigned long *flags); struct nvkm_fifo_chan * nvkm_fifo_chan_chid(struct nvkm_fifo *, int chid, unsigned long *flags); -#define nvkm_fifo_create(o,e,c,fc,lc,d) \ - nvkm_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d) -#define nvkm_fifo_init(p) \ - nvkm_engine_init_old(&(p)->engine) -#define nvkm_fifo_fini(p,s) \ - nvkm_engine_fini_old(&(p)->engine, (s)) - -int nvkm_fifo_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int min, int max, - int size, void **); -void nvkm_fifo_destroy(struct nvkm_fifo *); - -#define _nvkm_fifo_init _nvkm_engine_init -#define _nvkm_fifo_fini _nvkm_engine_fini - -extern struct nvkm_oclass *nv04_fifo_oclass; -extern struct nvkm_oclass *nv10_fifo_oclass; -extern struct nvkm_oclass *nv17_fifo_oclass; -extern struct nvkm_oclass *nv40_fifo_oclass; -extern struct nvkm_oclass *nv50_fifo_oclass; -extern struct nvkm_oclass *g84_fifo_oclass; -extern struct nvkm_oclass *gf100_fifo_oclass; -extern struct nvkm_oclass *gk104_fifo_oclass; -extern struct nvkm_oclass *gk20a_fifo_oclass; -extern struct nvkm_oclass *gk208_fifo_oclass; -extern struct nvkm_oclass *gm204_fifo_oclass; -extern struct nvkm_oclass *gm20b_fifo_oclass; - -int nvkm_fifo_uevent_ctor(struct nvkm_object *, void *, u32, - struct nvkm_notify *); -void nvkm_fifo_uevent(struct nvkm_fifo *); - -void nv04_fifo_intr(struct nvkm_subdev *); -int nv04_fifo_context_attach(struct nvkm_object *, struct nvkm_object *); +int nv04_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int nv10_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int nv17_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int nv40_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int nv50_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int g84_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gf100_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gk104_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gk208_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gk20a_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gm204_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); +int gm20b_fifo_new(struct nvkm_device *, int, struct nvkm_fifo **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index e056f7afc35cf..b8fc539e0a994 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -231,7 +231,7 @@ nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) nvkm_object_destroy(&gpuobj->object); } -#include +#include int nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 764b46751eb90..03763268248f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -26,6 +26,7 @@ #include #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index ea3e8902f458f..62395ab742c5f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -88,7 +88,7 @@ nv4_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv04_fifo_new, + .fifo = nv04_fifo_new, // .gr = nv04_gr_new, // .sw = nv04_sw_new, }; @@ -108,7 +108,7 @@ nv5_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv04_fifo_new, + .fifo = nv04_fifo_new, // .gr = nv04_gr_new, // .sw = nv04_sw_new, }; @@ -148,7 +148,7 @@ nv11_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv10_fifo_new, + .fifo = nv10_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, }; @@ -169,7 +169,7 @@ nv15_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv10_fifo_new, + .fifo = nv10_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, }; @@ -190,7 +190,7 @@ nv17_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, }; @@ -211,7 +211,7 @@ nv18_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, }; @@ -232,7 +232,7 @@ nv1a_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv10_fifo_new, + .fifo = nv10_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, }; @@ -253,7 +253,7 @@ nv1f_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv10_gr_new, // .sw = nv10_sw_new, }; @@ -274,7 +274,7 @@ nv20_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv20_gr_new, // .sw = nv10_sw_new, }; @@ -295,7 +295,7 @@ nv25_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv25_gr_new, // .sw = nv10_sw_new, }; @@ -316,7 +316,7 @@ nv28_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv25_gr_new, // .sw = nv10_sw_new, }; @@ -337,7 +337,7 @@ nv2a_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv2a_gr_new, // .sw = nv10_sw_new, }; @@ -358,7 +358,7 @@ nv30_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv30_gr_new, // .sw = nv10_sw_new, }; @@ -379,7 +379,7 @@ nv31_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv30_gr_new, // .mpeg = nv31_mpeg_new, // .sw = nv10_sw_new, @@ -401,7 +401,7 @@ nv34_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv34_gr_new, // .mpeg = nv31_mpeg_new, // .sw = nv10_sw_new, @@ -423,7 +423,7 @@ nv35_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv35_gr_new, // .sw = nv10_sw_new, }; @@ -444,7 +444,7 @@ nv36_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv17_fifo_new, + .fifo = nv17_fifo_new, // .gr = nv35_gr_new, // .mpeg = nv31_mpeg_new, // .sw = nv10_sw_new, @@ -468,7 +468,7 @@ nv40_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, @@ -493,7 +493,7 @@ nv41_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, @@ -518,7 +518,7 @@ nv42_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, @@ -543,7 +543,7 @@ nv43_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, @@ -568,7 +568,7 @@ nv44_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -593,7 +593,7 @@ nv45_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -618,7 +618,7 @@ nv46_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -643,7 +643,7 @@ nv47_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -668,7 +668,7 @@ nv49_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -693,7 +693,7 @@ nv4a_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -718,7 +718,7 @@ nv4b_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -743,7 +743,7 @@ nv4c_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -768,7 +768,7 @@ nv4e_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -796,7 +796,7 @@ nv50_chipset = { .volt = nv40_volt_new, .disp = nv50_disp_new, .dma = nv50_dma_new, -// .fifo = nv50_fifo_new, + .fifo = nv50_fifo_new, // .gr = nv50_gr_new, // .mpeg = nv50_mpeg_new, // .pm = nv50_pm_new, @@ -821,7 +821,7 @@ nv63_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -846,7 +846,7 @@ nv67_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -871,7 +871,7 @@ nv68_chipset = { .volt = nv40_volt_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .fifo = nv40_fifo_new, + .fifo = nv40_fifo_new, // .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, @@ -901,7 +901,7 @@ nv84_chipset = { .cipher = g84_cipher_new, .disp = g84_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, @@ -932,7 +932,7 @@ nv86_chipset = { .cipher = g84_cipher_new, .disp = g84_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, @@ -963,7 +963,7 @@ nv92_chipset = { .cipher = g84_cipher_new, .disp = g84_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, @@ -994,7 +994,7 @@ nv94_chipset = { .cipher = g84_cipher_new, .disp = g94_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, @@ -1022,7 +1022,7 @@ nv96_chipset = { .bar = g84_bar_new, .volt = nv40_volt_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .sw = nv50_sw_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, @@ -1053,7 +1053,7 @@ nv98_chipset = { .bar = g84_bar_new, .volt = nv40_volt_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .sw = nv50_sw_new, // .gr = nv50_gr_new, .mspdec = g98_mspdec_new, @@ -1087,7 +1087,7 @@ nva0_chipset = { .cipher = g84_cipher_new, .disp = gt200_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, // .pm = gt200_pm_new, @@ -1118,7 +1118,7 @@ nva3_chipset = { .ce[0] = gt215_ce_new, .disp = gt215_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, .mspdec = gt215_mspdec_new, @@ -1151,7 +1151,7 @@ nva5_chipset = { .ce[0] = gt215_ce_new, .disp = gt215_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, @@ -1183,7 +1183,7 @@ nva8_chipset = { .ce[0] = gt215_ce_new, .disp = gt215_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, @@ -1213,7 +1213,7 @@ nvaa_chipset = { .volt = nv40_volt_new, .disp = g94_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = g98_mspdec_new, .msppp = g98_msppp_new, @@ -1244,7 +1244,7 @@ nvac_chipset = { .volt = nv40_volt_new, .disp = g94_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = g98_mspdec_new, .msppp = g98_msppp_new, @@ -1277,7 +1277,7 @@ nvaf_chipset = { .ce[0] = gt215_ce_new, .disp = gt215_disp_new, .dma = nv50_dma_new, -// .fifo = g84_fifo_new, + .fifo = g84_fifo_new, // .gr = nv50_gr_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, @@ -1312,7 +1312,7 @@ nvc0_chipset = { .ce[1] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf100_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1346,7 +1346,7 @@ nvc1_chipset = { .ce[0] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf108_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1380,7 +1380,7 @@ nvc3_chipset = { .ce[0] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1415,7 +1415,7 @@ nvc4_chipset = { .ce[1] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1450,7 +1450,7 @@ nvc8_chipset = { .ce[1] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf110_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1485,7 +1485,7 @@ nvce_chipset = { .ce[1] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1519,7 +1519,7 @@ nvcf_chipset = { .ce[0] = gf100_ce_new, .disp = gt215_disp_new, .dma = gf100_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1551,7 +1551,7 @@ nvd7_chipset = { .ce[0] = gf100_ce_new, .disp = gf119_disp_new, .dma = gf119_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf117_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1585,7 +1585,7 @@ nvd9_chipset = { .ce[0] = gf100_ce_new, .disp = gf119_disp_new, .dma = gf119_dma_new, -// .fifo = gf100_fifo_new, + .fifo = gf100_fifo_new, // .gr = gf119_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, @@ -1621,7 +1621,7 @@ nve4_chipset = { .ce[2] = gk104_ce_new, .disp = gk104_disp_new, .dma = gf119_dma_new, -// .fifo = gk104_fifo_new, + .fifo = gk104_fifo_new, // .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1657,7 +1657,7 @@ nve6_chipset = { .ce[2] = gk104_ce_new, .disp = gk104_disp_new, .dma = gf119_dma_new, -// .fifo = gk104_fifo_new, + .fifo = gk104_fifo_new, // .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1693,7 +1693,7 @@ nve7_chipset = { .ce[2] = gk104_ce_new, .disp = gk104_disp_new, .dma = gf119_dma_new, -// .fifo = gk104_fifo_new, + .fifo = gk104_fifo_new, // .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1720,7 +1720,7 @@ nvea_chipset = { .volt = gk20a_volt_new, .ce[2] = gk104_ce_new, .dma = gf119_dma_new, -// .fifo = gk20a_fifo_new, + .fifo = gk20a_fifo_new, // .gr = gk20a_gr_new, // .pm = gk104_pm_new, // .sw = gf100_sw_new, @@ -1753,7 +1753,7 @@ nvf0_chipset = { .ce[2] = gk104_ce_new, .disp = gk110_disp_new, .dma = gf119_dma_new, -// .fifo = gk104_fifo_new, + .fifo = gk104_fifo_new, // .gr = gk110_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1789,7 +1789,7 @@ nvf1_chipset = { .ce[2] = gk104_ce_new, .disp = gk110_disp_new, .dma = gf119_dma_new, -// .fifo = gk104_fifo_new, + .fifo = gk104_fifo_new, // .gr = gk110b_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1825,7 +1825,7 @@ nv106_chipset = { .ce[2] = gk104_ce_new, .disp = gk110_disp_new, .dma = gf119_dma_new, -// .fifo = gk208_fifo_new, + .fifo = gk208_fifo_new, // .gr = gk208_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1860,7 +1860,7 @@ nv108_chipset = { .ce[2] = gk104_ce_new, .disp = gk110_disp_new, .dma = gf119_dma_new, -// .fifo = gk208_fifo_new, + .fifo = gk208_fifo_new, // .gr = gk208_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, @@ -1893,7 +1893,7 @@ nv117_chipset = { .ce[2] = gk104_ce_new, .disp = gm107_disp_new, .dma = gf119_dma_new, -// .fifo = gk208_fifo_new, + .fifo = gk208_fifo_new, // .gr = gm107_gr_new, // .sw = gf100_sw_new, }; @@ -1922,7 +1922,7 @@ nv124_chipset = { .ce[2] = gm204_ce_new, .disp = gm204_disp_new, .dma = gf119_dma_new, -// .fifo = gm204_fifo_new, + .fifo = gm204_fifo_new, // .gr = gm204_gr_new, // .sw = gf100_sw_new, }; @@ -1951,7 +1951,7 @@ nv126_chipset = { .ce[2] = gm204_ce_new, .disp = gm204_disp_new, .dma = gf119_dma_new, -// .fifo = gm204_fifo_new, + .fifo = gm204_fifo_new, // .gr = gm206_gr_new, // .sw = gf100_sw_new, }; @@ -1972,7 +1972,7 @@ nv12b_chipset = { .timer = gk20a_timer_new, .ce[2] = gm204_ce_new, .dma = gf119_dma_new, -// .fifo = gm20b_fifo_new, + .fifo = gm20b_fifo_new, // .gr = gm20b_gr_new, // .sw = gf100_sw_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 09a1fe1604a2e..d319f5680f440 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,55 +28,46 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: - device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index b3d25aad22f71..fe8298e02e9f3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,48 +28,40 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: - device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xf0: - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: - device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: - device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; break; case 0x108: - device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index c0c1bd3989d60..2362a634462c3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -31,7 +31,6 @@ gm100_identify(struct nvkm_device *device) #if 0 #endif - device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass; #if 0 @@ -46,7 +45,6 @@ gm100_identify(struct nvkm_device *device) #endif #if 0 #endif - device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm204_gr_oclass; #if 0 @@ -59,7 +57,6 @@ gm100_identify(struct nvkm_device *device) #endif #if 0 #endif - device->oclass[NVDEV_ENGINE_FIFO ] = gm204_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm206_gr_oclass; #if 0 @@ -67,7 +64,6 @@ gm100_identify(struct nvkm_device *device) break; case 0x12b: - device->oclass[NVDEV_ENGINE_FIFO ] = gm20b_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = gm20b_gr_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 7a71d0c1d22f8..edddbaa41b43d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,12 +28,10 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; break; case 0x05: - device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 2b59c02fe7348..f1ebb9bcda3b6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -31,37 +31,30 @@ nv10_identify(struct nvkm_device *device) device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x15: - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x16: - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x1a: - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x11: - device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x17: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x1f: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x18: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index b4f8c479f3d7a..f9c4dad1f8ff0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,22 +28,18 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv20_gr_oclass; break; case 0x25: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; break; case 0x28: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; break; case 0x2a: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv2a_gr_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index fec9e3f38a5cd..b8e1e43723a3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,29 +28,24 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; break; case 0x35: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; break; case 0x31: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x36: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x34: - device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv34_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 553923ab0376d..158ed5e395df4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,112 +28,96 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: - device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index f4c4ded9193fe..688b3e2d61ff9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,93 +28,79 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: - device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass; device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index e51372bdbf540..2d11b328bee11 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -20,9 +20,10 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include -#include +#include #include +#include static int nvkm_falcon_oclass_get(struct nvkm_oclass *oclass, int index) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild index 4525b01598a9e..74993c144a846 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild @@ -7,8 +7,8 @@ nvkm-y += nvkm/engine/fifo/nv50.o nvkm-y += nvkm/engine/fifo/g84.o nvkm-y += nvkm/engine/fifo/gf100.o nvkm-y += nvkm/engine/fifo/gk104.o -nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gk208.o +nvkm-y += nvkm/engine/fifo/gk20a.o nvkm-y += nvkm/engine/fifo/gm204.o nvkm-y += nvkm/engine/fifo/gm20b.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c index b693127d80e10..1fbbfbe6ca9cf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c @@ -25,11 +25,24 @@ #include "chan.h" #include +#include #include #include #include +void +nvkm_fifo_pause(struct nvkm_fifo *fifo, unsigned long *flags) +{ + return fifo->func->pause(fifo, flags); +} + +void +nvkm_fifo_start(struct nvkm_fifo *fifo, unsigned long *flags) +{ + return fifo->func->start(fifo, flags); +} + void nvkm_fifo_chan_put(struct nvkm_fifo *fifo, unsigned long flags, struct nvkm_fifo_chan **pchan) @@ -95,7 +108,21 @@ nvkm_fifo_event_func = { .ctor = nvkm_fifo_event_ctor, }; -int +static void +nvkm_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + fifo->func->uevent_fini(fifo); +} + +static void +nvkm_fifo_uevent_init(struct nvkm_event *event, int type, int index) +{ + struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); + fifo->func->uevent_init(fifo); +} + +static int nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) { @@ -113,6 +140,13 @@ nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size, return ret; } +static const struct nvkm_event_func +nvkm_fifo_uevent_func = { + .ctor = nvkm_fifo_uevent_ctor, + .init = nvkm_fifo_uevent_init, + .fini = nvkm_fifo_uevent_fini, +}; + void nvkm_fifo_uevent(struct nvkm_fifo *fifo) { @@ -156,50 +190,88 @@ nvkm_fifo_class_get(struct nvkm_oclass *oclass, int index, return c; } -void -nvkm_fifo_destroy(struct nvkm_fifo *fifo) +static void +nvkm_fifo_intr(struct nvkm_engine *engine) { - nvkm_event_fini(&fifo->uevent); + struct nvkm_fifo *fifo = nvkm_fifo(engine); + fifo->func->intr(fifo); +} + +static int +nvkm_fifo_fini(struct nvkm_engine *engine, bool suspend) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + if (fifo->func->fini) + fifo->func->fini(fifo); + return 0; +} + +static int +nvkm_fifo_oneinit(struct nvkm_engine *engine) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + if (fifo->func->oneinit) + return fifo->func->oneinit(fifo); + return 0; +} + +static int +nvkm_fifo_init(struct nvkm_engine *engine) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + fifo->func->init(fifo); + return 0; +} + +static void * +nvkm_fifo_dtor(struct nvkm_engine *engine) +{ + struct nvkm_fifo *fifo = nvkm_fifo(engine); + void *data = fifo; + if (fifo->func->dtor) + data = fifo->func->dtor(fifo); nvkm_event_fini(&fifo->cevent); - nvkm_engine_destroy(&fifo->engine); + nvkm_event_fini(&fifo->uevent); + return data; } static const struct nvkm_engine_func -nvkm_fifo_func = { +nvkm_fifo = { + .dtor = nvkm_fifo_dtor, + .oneinit = nvkm_fifo_oneinit, + .init = nvkm_fifo_init, + .fini = nvkm_fifo_fini, + .intr = nvkm_fifo_intr, .base.sclass = nvkm_fifo_class_get, }; int -nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, - int min, int max, int length, void **pobject) +nvkm_fifo_ctor(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, int nr, struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo; - int nr = max + 1; - int cnt = nr - min; int ret; - ret = nvkm_engine_create_(parent, engine, oclass, true, "PFIFO", - "fifo", length, pobject); - fifo = *pobject; - if (ret) - return ret; - - fifo->engine.func = &nvkm_fifo_func; + fifo->func = func; INIT_LIST_HEAD(&fifo->chan); + spin_lock_init(&fifo->lock); - fifo->nr = nr; - if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) { + if (WARN_ON(fifo->nr > NVKM_FIFO_CHID_NR)) fifo->nr = NVKM_FIFO_CHID_NR; - cnt = fifo->nr - min; - } - bitmap_fill(fifo->mask, NVKM_FIFO_CHID_NR); - bitmap_clear(fifo->mask, min, cnt); + else + fifo->nr = nr; + bitmap_clear(fifo->mask, 0, fifo->nr); - ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent); + ret = nvkm_engine_ctor(&nvkm_fifo, device, index, 0x00000100, + true, &fifo->engine); if (ret) return ret; - spin_lock_init(&fifo->lock); - return 0; + if (func->uevent_init) { + ret = nvkm_event_init(&nvkm_fifo_uevent_func, 1, 1, + &fifo->uevent); + if (ret) + return ret; + } + + return nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &fifo->cevent); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index a02c60f340c0a..4ed06abdc9176 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -24,6 +24,7 @@ #include "chan.h" #include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h index bfec12dbf4929..55dc415c5c08b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.h @@ -1,5 +1,6 @@ #ifndef __NVKM_FIFO_CHAN_H__ #define __NVKM_FIFO_CHAN_H__ +#define nvkm_fifo_chan(p) container_of((p), struct nvkm_fifo_chan, object) #include "priv.h" struct nvkm_fifo_chan_func { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c index eafa87886643e..52cbc4b47b2c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c @@ -73,7 +73,7 @@ nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) struct nv04_fifo *fifo = chan->fifo; struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_memory *fctx = device->imem->ramfc; - struct ramfc_desc *c; + const struct nv04_fifo_ramfc *c; unsigned long flags; u32 mask = fifo->base.nr - 1; u32 data = chan->ramfc; @@ -90,7 +90,7 @@ nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 0); nvkm_mask(device, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0); - c = fifo->ramfc_desc; + c = fifo->ramfc; do { u32 rm = ((1ULL << c->bits) - 1) << c->regs; u32 cm = ((1ULL << c->bits) - 1) << c->ctxs; @@ -99,7 +99,7 @@ nv04_fifo_dma_fini(struct nvkm_fifo_chan *base) nvkm_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs)); } while ((++c)->bits); - c = fifo->ramfc_desc; + c = fifo->ramfc; do { nvkm_wr32(device, c->regp, 0x00000000); } while ((++c)->bits); @@ -136,7 +136,7 @@ nv04_fifo_dma_dtor(struct nvkm_fifo_chan *base) struct nv04_fifo_chan *chan = nv04_fifo_chan(base); struct nv04_fifo *fifo = chan->fifo; struct nvkm_instmem *imem = fifo->base.engine.subdev.device->imem; - struct ramfc_desc *c = fifo->ramfc_desc; + const struct nv04_fifo_ramfc *c = fifo->ramfc; nvkm_kmap(imem->ramfc); do { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c index 1ad16205305f8..d8e4d55704d1d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c @@ -25,6 +25,7 @@ #include "regsnv04.h" #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c index 2fbb9d4f0900e..1424dd9b62998 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c @@ -25,6 +25,7 @@ #include "regsnv04.h" #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c index 00fa9d3eff7ad..ff7b529764fe0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c @@ -25,30 +25,29 @@ #include "channv50.h" static void -g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +g84_fifo_uevent_fini(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002140, 0x40000000, 0x00000000); } static void -g84_fifo_uevent_init(struct nvkm_event *event, int type, int index) +g84_fifo_uevent_init(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002140, 0x40000000, 0x40000000); } -static const struct nvkm_event_func -g84_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = g84_fifo_uevent_init, - .fini = g84_fifo_uevent_fini, -}; - static const struct nvkm_fifo_func -g84_fifo_func = { +g84_fifo = { + .dtor = nv50_fifo_dtor, + .oneinit = nv50_fifo_oneinit, + .init = nv50_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .uevent_init = g84_fifo_uevent_init, + .uevent_fini = g84_fifo_uevent_fini, .chan = { &g84_fifo_dma_oclass, &g84_fifo_gpfifo_oclass, @@ -56,50 +55,8 @@ g84_fifo_func = { }, }; -static int -g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nvkm_device *device = (void *)parent; - struct nv50_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &g84_fifo_func; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->runlist[0]); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->runlist[1]); - if (ret) - return ret; - - ret = nvkm_event_init(&g84_fifo_uevent_func, 1, 1, &fifo->base.uevent); - if (ret) - return ret; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - return 0; + return nv50_fifo_new_(&g84_fifo, device, index, pfifo); } - -struct nvkm_oclass * -g84_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_fifo_ctor, - .dtor = nv50_fifo_dtor, - .init = nv50_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index e8598fc447962..bc094223f6877 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -33,28 +34,19 @@ #include static void -gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index) +gf100_fifo_uevent_init(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); } static void -gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +gf100_fifo_uevent_fini(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); } -static const struct nvkm_event_func -gf100_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = gf100_fifo_uevent_init, - .fini = gf100_fifo_uevent_fini, -}; - void gf100_fifo_runlist_update(struct gf100_fifo *fifo) { @@ -64,7 +56,7 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) struct nvkm_memory *cur; int nr = 0; - mutex_lock(&nv_subdev(fifo)->mutex); + mutex_lock(&subdev->mutex); cur = fifo->runlist.mem[fifo->runlist.active]; fifo->runlist.active = !fifo->runlist.active; @@ -83,7 +75,7 @@ gf100_fifo_runlist_update(struct gf100_fifo *fifo) !(nvkm_rd32(device, 0x00227c) & 0x00100000), msecs_to_jiffies(2000)) == 0) nvkm_error(subdev, "runlist update timeout\n"); - mutex_unlock(&nv_subdev(fifo)->mutex); + mutex_unlock(&subdev->mutex); } static inline int @@ -106,6 +98,8 @@ gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn) static inline struct nvkm_engine * gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn) { + struct nvkm_device *device = fifo->base.engine.subdev.device; + switch (engn) { case 0: engn = NVDEV_ENGINE_GR; break; case 1: engn = NVDEV_ENGINE_MSVLD; break; @@ -117,7 +111,7 @@ gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn) return NULL; } - return nvkm_engine(fifo, engn); + return nvkm_device_engine(device, engn); } static void @@ -167,7 +161,7 @@ gf100_fifo_recover(struct gf100_fifo *fifo, struct nvkm_engine *engine, list_del_init(&chan->head); chan->killed = true; - fifo->mask |= 1ULL << nv_engidx(engine); + fifo->mask |= 1ULL << engine->subdev.index; schedule_work(&fifo->fault); } @@ -333,7 +327,7 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_engine(fifo, eu->data2); + engine = nvkm_device_engine(device, eu->data2); break; } } @@ -457,10 +451,11 @@ gf100_fifo_intr_engine(struct gf100_fifo *fifo) } static void -gf100_fifo_intr(struct nvkm_subdev *subdev) +gf100_fifo_intr(struct nvkm_fifo *base) { - struct gf100_fifo *fifo = (void *)subdev; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, 0x002140); u32 stat = nvkm_rd32(device, 0x002100) & mask; @@ -531,17 +526,52 @@ gf100_fifo_intr(struct nvkm_subdev *subdev) } static int -gf100_fifo_init(struct nvkm_object *object) +gf100_fifo_oneinit(struct nvkm_fifo *base) { - struct gf100_fifo *fifo = (void *)object; - struct nvkm_subdev *subdev = &fifo->base.engine.subdev; - struct nvkm_device *device = subdev->device; - int ret, i; + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + int ret; - ret = nvkm_fifo_init(&fifo->base); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, + false, &fifo->runlist.mem[0]); + if (ret) + return ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, + false, &fifo->runlist.mem[1]); if (ret) return ret; + init_waitqueue_head(&fifo->runlist.wait); + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000, + 0x1000, false, &fifo->user.mem); + if (ret) + return ret; + + ret = nvkm_bar_umap(device->bar, 128 * 0x1000, 12, &fifo->user.bar); + if (ret) + return ret; + + nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); + return 0; +} + +static void +gf100_fifo_fini(struct nvkm_fifo *base) +{ + struct gf100_fifo *fifo = gf100_fifo(base); + flush_work(&fifo->fault); +} + +static void +gf100_fifo_init(struct nvkm_fifo *base) +{ + struct gf100_fifo *fifo = gf100_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; + int i; + nvkm_wr32(device, 0x000204, 0xffffffff); nvkm_wr32(device, 0x002204, 0xffffffff); @@ -571,90 +601,44 @@ gf100_fifo_init(struct nvkm_object *object) nvkm_wr32(device, 0x002100, 0xffffffff); nvkm_wr32(device, 0x002140, 0x7fffffff); nvkm_wr32(device, 0x002628, 0x00000001); /* ENGINE_INTR_EN */ - return 0; } -static void -gf100_fifo_dtor(struct nvkm_object *object) +static void * +gf100_fifo_dtor(struct nvkm_fifo *base) { - struct gf100_fifo *fifo = (void *)object; - + struct gf100_fifo *fifo = gf100_fifo(base); nvkm_vm_put(&fifo->user.bar); nvkm_memory_del(&fifo->user.mem); nvkm_memory_del(&fifo->runlist.mem[0]); nvkm_memory_del(&fifo->runlist.mem[1]); - - nvkm_fifo_destroy(&fifo->base); + return fifo; } static const struct nvkm_fifo_func -gf100_fifo_func = { +gf100_fifo = { + .dtor = gf100_fifo_dtor, + .oneinit = gf100_fifo_oneinit, + .init = gf100_fifo_init, + .fini = gf100_fifo_fini, + .intr = gf100_fifo_intr, + .uevent_init = gf100_fifo_uevent_init, + .uevent_fini = gf100_fifo_uevent_fini, .chan = { &gf100_fifo_gpfifo_oclass, NULL }, }; -static int -gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +gf100_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nvkm_device *device = (void *)parent; - struct nvkm_bar *bar = device->bar; struct gf100_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 127, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &gf100_fifo_func; + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; INIT_LIST_HEAD(&fifo->chan); INIT_WORK(&fifo->fault, gf100_fifo_recover_work); + *pfifo = &fifo->base; - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, - false, &fifo->runlist.mem[0]); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 0x1000, - false, &fifo->runlist.mem[1]); - if (ret) - return ret; - - init_waitqueue_head(&fifo->runlist.wait); - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 0x1000, - 0x1000, false, &fifo->user.mem); - if (ret) - return ret; - - ret = nvkm_bar_umap(bar, 128 * 0x1000, 12, &fifo->user.bar); - if (ret) - return ret; - - nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); - - ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &fifo->base.uevent); - if (ret) - return ret; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = gf100_fifo_intr; - return 0; + return nvkm_fifo_ctor(&gf100_fifo, device, index, 128, &fifo->base); } - - -struct nvkm_oclass * -gf100_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0xc0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_fifo_ctor, - .dtor = gf100_fifo_dtor, - .init = gf100_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index a69f61f3ecac1..465b52dee2777 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -26,35 +26,27 @@ #include #include +#include #include #include #include #include -static void -gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index) +void +gk104_fifo_uevent_fini(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002140, 0x80000000, 0x00000000); } -static void -gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index) +void +gk104_fifo_uevent_init(struct nvkm_fifo *fifo) { - struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent); struct nvkm_device *device = fifo->engine.subdev.device; nvkm_mask(device, 0x002140, 0x80000000, 0x80000000); } -static const struct nvkm_event_func -gk104_fifo_uevent_func = { - .ctor = nvkm_fifo_uevent_ctor, - .init = gk104_fifo_uevent_init, - .fini = gk104_fifo_uevent_fini, -}; - void gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) { @@ -65,7 +57,7 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) struct nvkm_memory *cur; int nr = 0; - mutex_lock(&nv_subdev(fifo)->mutex); + mutex_lock(&subdev->mutex); cur = engn->runlist[engn->cur_runlist]; engn->cur_runlist = !engn->cur_runlist; @@ -84,15 +76,16 @@ gk104_fifo_runlist_update(struct gk104_fifo *fifo, u32 engine) (engine * 0x08)) & 0x00100000), msecs_to_jiffies(2000)) == 0) nvkm_error(subdev, "runlist %d update timeout\n", engine); - mutex_unlock(&nv_subdev(fifo)->mutex); + mutex_unlock(&subdev->mutex); } static inline struct nvkm_engine * gk104_fifo_engine(struct gk104_fifo *fifo, u32 engn) { + struct nvkm_device *device = fifo->base.engine.subdev.device; u64 subdevs = gk104_fifo_engine_subdev(engn); if (subdevs) - return nvkm_engine(fifo, __ffs(subdevs)); + return nvkm_device_engine(device, __ffs(subdevs)); return NULL; } @@ -136,14 +129,14 @@ gk104_fifo_recover(struct gk104_fifo *fifo, struct nvkm_engine *engine, u32 chid = chan->base.chid; nvkm_error(subdev, "%s engine fault on channel %d, recovering...\n", - nvkm_subdev_name[nv_subdev(engine)->index], chid); + nvkm_subdev_name[engine->subdev.index], chid); assert_spin_locked(&fifo->base.lock); nvkm_mask(device, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800); list_del_init(&chan->head); chan->killed = true; - fifo->mask |= 1ULL << nv_engidx(engine); + fifo->mask |= 1ULL << engine->subdev.index; schedule_work(&fifo->fault); } @@ -399,7 +392,7 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: - engine = nvkm_engine(fifo, eu->data2); + engine = nvkm_device_engine(device, eu->data2); break; } } @@ -542,11 +535,12 @@ gk104_fifo_intr_engine(struct gk104_fifo *fifo) nvkm_fifo_uevent(&fifo->base); } -static void -gk104_fifo_intr(struct nvkm_subdev *subdev) +void +gk104_fifo_intr(struct nvkm_fifo *base) { - struct gk104_fifo *fifo = (void *)subdev; - struct nvkm_device *device = fifo->base.engine.subdev.device; + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 mask = nvkm_rd32(device, 0x002140); u32 stat = nvkm_rd32(device, 0x002100) & mask; @@ -633,33 +627,62 @@ gk104_fifo_intr(struct nvkm_subdev *subdev) } } +void +gk104_fifo_fini(struct nvkm_fifo *base) +{ + struct gk104_fifo *fifo = gk104_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + flush_work(&fifo->fault); + /* allow mmu fault interrupts, even when we're not using fifo */ + nvkm_mask(device, 0x002140, 0x10000000, 0x10000000); +} + int -gk104_fifo_fini(struct nvkm_object *object, bool suspend) +gk104_fifo_oneinit(struct nvkm_fifo *base) { - struct gk104_fifo *fifo = (void *)object; + struct gk104_fifo *fifo = gk104_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; - int ret; + int ret, i; - ret = nvkm_fifo_fini(&fifo->base, suspend); + for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x8000, 0x1000, false, + &fifo->engine[i].runlist[0]); + if (ret) + return ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + 0x8000, 0x1000, false, + &fifo->engine[i].runlist[1]); + if (ret) + return ret; + + init_waitqueue_head(&fifo->engine[i].wait); + INIT_LIST_HEAD(&fifo->engine[i].chan); + } + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, + fifo->base.nr * 0x200, 0x1000, true, + &fifo->user.mem); if (ret) return ret; - /* allow mmu fault interrupts, even when we're not using fifo */ - nvkm_mask(device, 0x002140, 0x10000000, 0x10000000); + ret = nvkm_bar_umap(device->bar, fifo->base.nr * 0x200, 12, + &fifo->user.bar); + if (ret) + return ret; + + nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); return 0; } -int -gk104_fifo_init(struct nvkm_object *object) +void +gk104_fifo_init(struct nvkm_fifo *base) { - struct gk104_fifo *fifo = (void *)object; + struct gk104_fifo *fifo = gk104_fifo(base); struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - int ret, i; - - ret = nvkm_fifo_init(&fifo->base); - if (ret) - return ret; + int i; /* enable all available PBDMA units */ nvkm_wr32(device, 0x000204, 0xffffffff); @@ -683,13 +706,12 @@ gk104_fifo_init(struct nvkm_object *object) nvkm_wr32(device, 0x002100, 0xffffffff); nvkm_wr32(device, 0x002140, 0x7fffffff); - return 0; } -void -gk104_fifo_dtor(struct nvkm_object *object) +void * +gk104_fifo_dtor(struct nvkm_fifo *base) { - struct gk104_fifo *fifo = (void *)object; + struct gk104_fifo *fifo = gk104_fifo(base); int i; nvkm_vm_put(&fifo->user.bar); @@ -700,11 +722,32 @@ gk104_fifo_dtor(struct nvkm_object *object) nvkm_memory_del(&fifo->engine[i].runlist[0]); } - nvkm_fifo_destroy(&fifo->base); + return fifo; +} + +int +gk104_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, int nr, struct nvkm_fifo **pfifo) +{ + struct gk104_fifo *fifo; + + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + INIT_WORK(&fifo->fault, gk104_fifo_recover_work); + *pfifo = &fifo->base; + + return nvkm_fifo_ctor(func, device, index, nr, &fifo->base); } static const struct nvkm_fifo_func -gk104_fifo_func = { +gk104_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, .chan = { &gk104_fifo_gpfifo_oclass, NULL @@ -712,72 +755,7 @@ gk104_fifo_func = { }; int -gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gk104_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nvkm_device *device = (void *)parent; - struct nvkm_bar *bar = device->bar; - struct gk104_fifo_impl *impl = (void *)oclass; - struct gk104_fifo *fifo; - int ret, i; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, - impl->channels - 1, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &gk104_fifo_func; - - INIT_WORK(&fifo->fault, gk104_fifo_recover_work); - - for (i = 0; i < ARRAY_SIZE(fifo->engine); i++) { - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - 0x8000, 0x1000, false, - &fifo->engine[i].runlist[0]); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - 0x8000, 0x1000, false, - &fifo->engine[i].runlist[1]); - if (ret) - return ret; - - init_waitqueue_head(&fifo->engine[i].wait); - INIT_LIST_HEAD(&fifo->engine[i].chan); - } - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, - impl->channels * 0x200, 0x1000, - true, &fifo->user.mem); - if (ret) - return ret; - - ret = nvkm_bar_umap(bar, impl->channels * 0x200, 12, &fifo->user.bar); - if (ret) - return ret; - - nvkm_memory_map(fifo->user.mem, &fifo->user.bar, 0); - - ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &fifo->base.uevent); - if (ret) - return ret; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = gk104_fifo_intr; - return 0; + return gk104_fifo_new_(&gk104_fifo, device, index, 4096, pfifo); } - -struct nvkm_oclass * -gk104_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, - }, - .channels = 4096, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index 1103e6b1ee5a6..7a5c544a5ffbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -26,23 +26,17 @@ struct gk104_fifo { int spoon_nr; }; -struct gk104_fifo_impl { - struct nvkm_oclass base; - u32 channels; -}; - -int gk104_fifo_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void gk104_fifo_dtor(struct nvkm_object *); -int gk104_fifo_init(struct nvkm_object *); -int gk104_fifo_fini(struct nvkm_object *, bool); +int gk104_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, int nr, struct nvkm_fifo **); +void *gk104_fifo_dtor(struct nvkm_fifo *); +int gk104_fifo_oneinit(struct nvkm_fifo *); +void gk104_fifo_init(struct nvkm_fifo *); +void gk104_fifo_fini(struct nvkm_fifo *); +void gk104_fifo_intr(struct nvkm_fifo *); +void gk104_fifo_uevent_init(struct nvkm_fifo *); +void gk104_fifo_uevent_fini(struct nvkm_fifo *); void gk104_fifo_runlist_update(struct gk104_fifo *, u32 engine); -int gm204_fifo_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - static inline u64 gk104_fifo_engine_subdev(int engine) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c index 927092217a06f..ce01c1a7d41cb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c @@ -22,15 +22,25 @@ * Authors: Ben Skeggs */ #include "gk104.h" +#include "changk104.h" -struct nvkm_oclass * -gk208_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +gk208_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk104_fifo_gpfifo_oclass, + NULL }, - .channels = 1024, -}.base; +}; + +int +gk208_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gk208_fifo, device, index, 1024, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c index b30dc87a1357c..b47fe98f41818 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c @@ -20,15 +20,25 @@ * DEALINGS IN THE SOFTWARE. */ #include "gk104.h" +#include "changk104.h" -struct nvkm_oclass * -gk20a_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, +static const struct nvkm_fifo_func +gk20a_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gk104_fifo_gpfifo_oclass, + NULL }, - .channels = 128, -}.base; +}; + +int +gk20a_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gk20a_fifo, device, index, 128, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c index 18c68ac741a0a..2db629f1bf7e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm204.c @@ -25,7 +25,14 @@ #include "changk104.h" static const struct nvkm_fifo_func -gm204_fifo_func = { +gm204_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, .chan = { &gm204_fifo_gpfifo_oclass, NULL @@ -33,26 +40,7 @@ gm204_fifo_func = { }; int -gm204_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gm204_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - int ret = gk104_fifo_ctor(parent, engine, oclass, data, size, pobject); - if (ret == 0) { - struct gk104_fifo *fifo = (void *)*pobject; - fifo->base.func = &gm204_fifo_func; - } - return ret; + return gk104_fifo_new_(&gm204_fifo, device, index, 4096, pfifo); } - -struct nvkm_oclass * -gm204_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = _nvkm_fifo_fini, - }, - .channels = 4096, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c index 4abf547c34e64..ae6375d9760f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gm20b.c @@ -20,15 +20,25 @@ * DEALINGS IN THE SOFTWARE. */ #include "gk104.h" +#include "changk104.h" -struct nvkm_oclass * -gm20b_fifo_oclass = &(struct gk104_fifo_impl) { - .base.handle = NV_ENGINE(FIFO, 0x2b), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gm204_fifo_ctor, - .dtor = gk104_fifo_dtor, - .init = gk104_fifo_init, - .fini = gk104_fifo_fini, +static const struct nvkm_fifo_func +gm20b_fifo = { + .dtor = gk104_fifo_dtor, + .oneinit = gk104_fifo_oneinit, + .init = gk104_fifo_init, + .fini = gk104_fifo_fini, + .intr = gk104_fifo_intr, + .uevent_init = gk104_fifo_uevent_init, + .uevent_fini = gk104_fifo_uevent_fini, + .chan = { + &gm204_fifo_gpfifo_oclass, + NULL }, - .channels = 512, -}.base; +}; + +int +gm20b_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return gk104_fifo_new_(&gm20b_fifo, device, index, 512, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c index eb9195a6f375f..5d76c3013a807 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c @@ -24,6 +24,7 @@ #include "changf100.h" #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index 2595cf92ff804..fe39981915b64 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -24,6 +24,7 @@ #include "changk104.h" #include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index d1ad3fa72c343..e6f04e87139a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -32,8 +32,8 @@ #include #include -static struct ramfc_desc -nv04_ramfc[] = { +static const struct nv04_fifo_ramfc +nv04_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE }, @@ -46,10 +46,10 @@ nv04_ramfc[] = { }; void -nv04_fifo_pause(struct nvkm_fifo *obj, unsigned long *pflags) +nv04_fifo_pause(struct nvkm_fifo *base, unsigned long *pflags) __acquires(fifo->base.lock) { - struct nv04_fifo *fifo = container_of(obj, typeof(*fifo), base); + struct nv04_fifo *fifo = nv04_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags; @@ -82,10 +82,10 @@ __acquires(fifo->base.lock) } void -nv04_fifo_start(struct nvkm_fifo *obj, unsigned long *pflags) +nv04_fifo_start(struct nvkm_fifo *base, unsigned long *pflags) __releases(fifo->base.lock) { - struct nv04_fifo *fifo = container_of(obj, typeof(*fifo), base); + struct nv04_fifo *fifo = nv04_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; unsigned long flags = *pflags; @@ -236,10 +236,11 @@ nv04_fifo_dma_pusher(struct nv04_fifo *fifo, u32 chid) } void -nv04_fifo_intr(struct nvkm_subdev *subdev) +nv04_fifo_intr(struct nvkm_fifo *base) { + struct nv04_fifo *fifo = nv04_fifo(base); + struct nvkm_subdev *subdev = &fifo->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct nv04_fifo *fifo = (void *)subdev; u32 mask = nvkm_rd32(device, NV03_PFIFO_INTR_EN_0); u32 stat = nvkm_rd32(device, NV03_PFIFO_INTR_0) & mask; u32 reassign, chid, get, sem; @@ -293,20 +294,15 @@ nv04_fifo_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, NV03_PFIFO_CACHES, reassign); } -int -nv04_fifo_init(struct nvkm_object *object) +void +nv04_fifo_init(struct nvkm_fifo *base) { - struct nv04_fifo *fifo = (void *)object; + struct nv04_fifo *fifo = nv04_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; struct nvkm_ramht *ramht = imem->ramht; struct nvkm_memory *ramro = imem->ramro; struct nvkm_memory *ramfc = imem->ramfc; - int ret; - - ret = nvkm_fifo_init(&fifo->base); - if (ret) - return ret; nvkm_wr32(device, NV04_PFIFO_DELAY_0, 0x000000ff); nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); @@ -325,54 +321,44 @@ nv04_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); nvkm_wr32(device, NV03_PFIFO_CACHES, 1); - return 0; } -void -nv04_fifo_dtor(struct nvkm_object *object) -{ - struct nv04_fifo *fifo = (void *)object; - nvkm_fifo_destroy(&fifo->base); -} - -static const struct nvkm_fifo_func -nv04_fifo_func = { - .chan = { - &nv04_fifo_dma_oclass, - NULL - }, -}; - -static int -nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv04_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, int nr, const struct nv04_fifo_ramfc *ramfc, + struct nvkm_fifo **pfifo) { struct nv04_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &fifo); - *pobject = nv_object(fifo); + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + fifo->ramfc = ramfc; + *pfifo = &fifo->base; + + ret = nvkm_fifo_ctor(func, device, index, nr, &fifo->base); if (ret) return ret; - fifo->base.func = &nv04_fifo_func; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv04_ramfc; + set_bit(nr - 1, fifo->base.mask); /* inactive channel */ return 0; } -struct nvkm_oclass * -nv04_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv04_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +nv04_fifo = { + .init = nv04_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv04_fifo_dma_oclass, + NULL }, }; + +int +nv04_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return nv04_fifo_new_(&nv04_fifo, device, index, 16, + nv04_fifo_ramfc, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h index c33dc56f8e022..03f60004bf7ca 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h @@ -3,7 +3,7 @@ #define nv04_fifo(p) container_of((p), struct nv04_fifo, base) #include "priv.h" -struct ramfc_desc { +struct nv04_fifo_ramfc { unsigned bits:6; unsigned ctxs:5; unsigned ctxp:8; @@ -13,9 +13,11 @@ struct ramfc_desc { struct nv04_fifo { struct nvkm_fifo base; - struct ramfc_desc *ramfc_desc; + const struct nv04_fifo_ramfc *ramfc; }; -void nv04_fifo_dtor(struct nvkm_object *); -int nv04_fifo_init(struct nvkm_object *); +int nv04_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, int nr, const struct nv04_fifo_ramfc *, + struct nvkm_fifo **); +void nv04_fifo_init(struct nvkm_fifo *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c index d7fab9598fb0e..f9a87deb2b3dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c @@ -25,8 +25,8 @@ #include "channv04.h" #include "regsnv04.h" -static struct ramfc_desc -nv10_ramfc[] = { +static const struct nv04_fifo_ramfc +nv10_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -40,43 +40,20 @@ nv10_ramfc[] = { }; static const struct nvkm_fifo_func -nv10_fifo_func = { +nv10_fifo = { + .init = nv04_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, .chan = { &nv10_fifo_dma_oclass, NULL }, }; -static int -nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv04_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &nv10_fifo_func; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv10_ramfc; - return 0; + return nv04_fifo_new_(&nv10_fifo, device, index, 32, + nv10_fifo_ramfc, pfifo); } - -struct nvkm_oclass * -nv10_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv04_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c index a8e28fc24e756..f6d383a21222e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c @@ -28,8 +28,8 @@ #include #include -static struct ramfc_desc -nv17_ramfc[] = { +static const struct nv04_fifo_ramfc +nv17_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -47,20 +47,15 @@ nv17_ramfc[] = { {} }; -static int -nv17_fifo_init(struct nvkm_object *object) +static void +nv17_fifo_init(struct nvkm_fifo *base) { - struct nv04_fifo *fifo = (void *)object; + struct nv04_fifo *fifo = nv04_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_instmem *imem = device->imem; struct nvkm_ramht *ramht = imem->ramht; struct nvkm_memory *ramro = imem->ramro; struct nvkm_memory *ramfc = imem->ramfc; - int ret; - - ret = nvkm_fifo_init(&fifo->base); - if (ret) - return ret; nvkm_wr32(device, NV04_PFIFO_DELAY_0, 0x000000ff); nvkm_wr32(device, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff); @@ -80,47 +75,23 @@ nv17_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); nvkm_wr32(device, NV03_PFIFO_CACHES, 1); - return 0; } static const struct nvkm_fifo_func -nv17_fifo_func = { +nv17_fifo = { + .init = nv17_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, .chan = { &nv17_fifo_dma_oclass, NULL }, }; -static int -nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv17_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv04_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &nv17_fifo_func; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv17_ramfc; - return 0; + return nv04_fifo_new_(&nv17_fifo, device, index, 32, + nv17_fifo_ramfc, pfifo); } - -struct nvkm_oclass * -nv17_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x17), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv17_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv17_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c index aca146377d36d..8c7ba32763c42 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c @@ -29,8 +29,8 @@ #include #include -static struct ramfc_desc -nv40_ramfc[] = { +static const struct nv04_fifo_ramfc +nv40_fifo_ramfc[] = { { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT }, { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET }, { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT }, @@ -56,21 +56,16 @@ nv40_ramfc[] = { {} }; -static int -nv40_fifo_init(struct nvkm_object *object) +static void +nv40_fifo_init(struct nvkm_fifo *base) { - struct nv04_fifo *fifo = (void *)object; + struct nv04_fifo *fifo = nv04_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; struct nvkm_fb *fb = device->fb; struct nvkm_instmem *imem = device->imem; struct nvkm_ramht *ramht = imem->ramht; struct nvkm_memory *ramro = imem->ramro; struct nvkm_memory *ramfc = imem->ramfc; - int ret; - - ret = nvkm_fifo_init(&fifo->base); - if (ret) - return ret; nvkm_wr32(device, 0x002040, 0x000000ff); nvkm_wr32(device, 0x002044, 0x2101ffff); @@ -81,7 +76,7 @@ nv40_fifo_init(struct nvkm_object *object) (ramht->gpuobj->addr >> 8)); nvkm_wr32(device, NV03_PFIFO_RAMRO, nvkm_memory_addr(ramro) >> 8); - switch (nv_device(fifo)->chipset) { + switch (device->chipset) { case 0x47: case 0x49: case 0x4b: @@ -110,47 +105,23 @@ nv40_fifo_init(struct nvkm_object *object) nvkm_wr32(device, NV03_PFIFO_CACHE1_PUSH0, 1); nvkm_wr32(device, NV04_PFIFO_CACHE1_PULL0, 1); nvkm_wr32(device, NV03_PFIFO_CACHES, 1); - return 0; } static const struct nvkm_fifo_func -nv40_fifo_func = { +nv40_fifo = { + .init = nv40_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, .chan = { &nv40_fifo_dma_oclass, NULL }, }; -static int -nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv40_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) { - struct nv04_fifo *fifo; - int ret; - - ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &nv40_fifo_func; - - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; - fifo->ramfc_desc = nv40_ramfc; - return 0; + return nv04_fifo_new_(&nv40_fifo, device, index, 32, + nv40_fifo_ramfc, pfifo); } - -struct nvkm_oclass * -nv40_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_fifo_ctor, - .dtor = nv04_fifo_dtor, - .init = nv40_fifo_init, - .fini = _nvkm_fifo_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c index ad653e9c461a3..66eb12c2b5ba7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c @@ -24,6 +24,8 @@ #include "nv50.h" #include "channv50.h" +#include + static void nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo) { @@ -49,22 +51,34 @@ nv50_fifo_runlist_update_locked(struct nv50_fifo *fifo) void nv50_fifo_runlist_update(struct nv50_fifo *fifo) { - mutex_lock(&nv_subdev(fifo)->mutex); + mutex_lock(&fifo->base.engine.subdev.mutex); nv50_fifo_runlist_update_locked(fifo); - mutex_unlock(&nv_subdev(fifo)->mutex); + mutex_unlock(&fifo->base.engine.subdev.mutex); } int -nv50_fifo_init(struct nvkm_object *object) +nv50_fifo_oneinit(struct nvkm_fifo *base) { - struct nv50_fifo *fifo = (void *)object; + struct nv50_fifo *fifo = nv50_fifo(base); struct nvkm_device *device = fifo->base.engine.subdev.device; - int ret, i; + int ret; - ret = nvkm_fifo_init(&fifo->base); + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->runlist[0]); if (ret) return ret; + return nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, + false, &fifo->runlist[1]); +} + +void +nv50_fifo_init(struct nvkm_fifo *base) +{ + struct nv50_fifo *fifo = nv50_fifo(base); + struct nvkm_device *device = fifo->base.engine.subdev.device; + int i; + nvkm_mask(device, 0x000200, 0x00000100, 0x00000000); nvkm_mask(device, 0x000200, 0x00000100, 0x00000100); nvkm_wr32(device, 0x00250c, 0x6f3cfc34); @@ -80,69 +94,54 @@ nv50_fifo_init(struct nvkm_object *object) nvkm_wr32(device, 0x003200, 0x00000001); nvkm_wr32(device, 0x003250, 0x00000001); nvkm_wr32(device, 0x002500, 0x00000001); - return 0; } -void -nv50_fifo_dtor(struct nvkm_object *object) +void * +nv50_fifo_dtor(struct nvkm_fifo *base) { - struct nv50_fifo *fifo = (void *)object; - + struct nv50_fifo *fifo = nv50_fifo(base); nvkm_memory_del(&fifo->runlist[1]); nvkm_memory_del(&fifo->runlist[0]); - - nvkm_fifo_destroy(&fifo->base); + return fifo; } -static const struct nvkm_fifo_func -nv50_fifo_func = { - .chan = { - &nv50_fifo_dma_oclass, - &nv50_fifo_gpfifo_oclass, - NULL - }, -}; - -static int -nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv50_fifo_new_(const struct nvkm_fifo_func *func, struct nvkm_device *device, + int index, struct nvkm_fifo **pfifo) { - struct nvkm_device *device = (void *)parent; struct nv50_fifo *fifo; int ret; - ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &fifo); - *pobject = nv_object(fifo); - if (ret) - return ret; - - fifo->base.func = &nv50_fifo_func; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->runlist[0]); - if (ret) - return ret; + if (!(fifo = kzalloc(sizeof(*fifo), GFP_KERNEL))) + return -ENOMEM; + *pfifo = &fifo->base; - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 128 * 4, 0x1000, - false, &fifo->runlist[1]); + ret = nvkm_fifo_ctor(func, device, index, 128, &fifo->base); if (ret) return ret; - nv_subdev(fifo)->unit = 0x00000100; - nv_subdev(fifo)->intr = nv04_fifo_intr; - fifo->base.pause = nv04_fifo_pause; - fifo->base.start = nv04_fifo_start; + set_bit(0, fifo->base.mask); /* PIO channel */ + set_bit(127, fifo->base.mask); /* inactive channel */ return 0; } -struct nvkm_oclass * -nv50_fifo_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(FIFO, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_fifo_ctor, - .dtor = nv50_fifo_dtor, - .init = nv50_fifo_init, - .fini = _nvkm_fifo_fini, +static const struct nvkm_fifo_func +nv50_fifo = { + .dtor = nv50_fifo_dtor, + .oneinit = nv50_fifo_oneinit, + .init = nv50_fifo_init, + .intr = nv04_fifo_intr, + .pause = nv04_fifo_pause, + .start = nv04_fifo_start, + .chan = { + &nv50_fifo_dma_oclass, + &nv50_fifo_gpfifo_oclass, + NULL }, }; + +int +nv50_fifo_new(struct nvkm_device *device, int index, struct nvkm_fifo **pfifo) +{ + return nv50_fifo_new_(&nv50_fifo, device, index, pfifo); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h index a7d5dba12fb8e..8ab53948cbb40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h @@ -9,7 +9,11 @@ struct nv50_fifo { int cur_runlist; }; -void nv50_fifo_dtor(struct nvkm_object *); -int nv50_fifo_init(struct nvkm_object *); +int nv50_fifo_new_(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, struct nvkm_fifo **); + +void *nv50_fifo_dtor(struct nvkm_fifo *); +int nv50_fifo_oneinit(struct nvkm_fifo *); +void nv50_fifo_init(struct nvkm_fifo *); void nv50_fifo_runlist_update(struct nv50_fifo *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h index a30d160f30db6..cb1432e9be08c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/priv.h @@ -1,7 +1,26 @@ #ifndef __NVKM_FIFO_PRIV_H__ #define __NVKM_FIFO_PRIV_H__ +#define nvkm_fifo(p) container_of((p), struct nvkm_fifo, engine) #include +int nvkm_fifo_ctor(const struct nvkm_fifo_func *, struct nvkm_device *, + int index, int nr, struct nvkm_fifo *); +void nvkm_fifo_uevent(struct nvkm_fifo *); + +struct nvkm_fifo_func { + void *(*dtor)(struct nvkm_fifo *); + int (*oneinit)(struct nvkm_fifo *); + void (*init)(struct nvkm_fifo *); + void (*fini)(struct nvkm_fifo *); + void (*intr)(struct nvkm_fifo *); + void (*pause)(struct nvkm_fifo *, unsigned long *); + void (*start)(struct nvkm_fifo *, unsigned long *); + void (*uevent_init)(struct nvkm_fifo *); + void (*uevent_fini)(struct nvkm_fifo *); + const struct nvkm_fifo_chan_oclass *chan[]; +}; + +void nv04_fifo_intr(struct nvkm_fifo *); void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *); void nv04_fifo_start(struct nvkm_fifo *, unsigned long *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index f06c16f61a981..a5a4bdd9863e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -25,6 +25,7 @@ #include "regs.h" #include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index 98fb9e6efb975..d5e44a7332ebb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -25,6 +25,7 @@ #include "regs.h" #include +#include #include #include #include @@ -1055,14 +1056,14 @@ nv10_gr_tile_prog(struct nvkm_engine *engine, int i) struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; - fifo->pause(fifo, &flags); + nvkm_fifo_pause(fifo, &flags); nv04_gr_idle(&gr->base); nvkm_wr32(device, NV10_PGRAPH_TLIMIT(i), tile->limit); nvkm_wr32(device, NV10_PGRAPH_TSIZE(i), tile->pitch); nvkm_wr32(device, NV10_PGRAPH_TILE(i), tile->addr); - fifo->start(fifo, &flags); + nvkm_fifo_start(fifo, &flags); } const struct nvkm_bitfield nv10_gr_intr_name[] = { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 554f2e3f7e5b7..ce4f9925ea9b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -2,6 +2,7 @@ #include "regs.h" #include +#include #include #include #include @@ -152,7 +153,7 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; - fifo->pause(fifo, &flags); + nvkm_fifo_pause(fifo, &flags); nv04_gr_idle(&gr->base); nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); @@ -172,7 +173,7 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->zcomp); } - fifo->start(fifo, &flags); + nvkm_fifo_start(fifo, &flags); } void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index 7fb53d53426cd..cc56ca9505f4a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -1,6 +1,7 @@ #include "nv20.h" #include "regs.h" +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index 2fabdc5866517..4e4cd93d686d3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -1,6 +1,7 @@ #include "nv20.h" #include "regs.h" +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index 8f5bfe3aa487d..ea46b16c31e69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -1,6 +1,7 @@ #include "nv20.h" #include "regs.h" +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 3781a5b311fbc..0667e9d14b42f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -1,6 +1,7 @@ #include "nv20.h" #include "regs.h" +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 285c4eff2e5bc..745d0e133d9a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -1,6 +1,7 @@ #include "nv20.h" #include "regs.h" +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 0e4e1152eeeca..be954500b4d8d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -25,6 +25,7 @@ #include "regs.h" #include +#include #include #include #include @@ -176,7 +177,7 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; - fifo->pause(fifo, &flags); + nvkm_fifo_pause(fifo, &flags); nv04_gr_idle(&gr->base); switch (nv_device(gr)->chipset) { @@ -243,7 +244,7 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) break; } - fifo->start(fifo, &flags); + nvkm_fifo_start(fifo, &flags); } static void diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 2a5bc9270fb9c..11c4c88389378 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -24,6 +24,7 @@ #include "nv50.h" #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 417cc31a12ef7..f79749946b72c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -24,6 +24,7 @@ #include "nv31.h" #include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index 0f9ef18bf18d0..d1b914b43cee4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -25,6 +25,7 @@ #include "priv.h" #include +#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c index 1ec4f4fde1c2d..995c2c5ec1503 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c @@ -27,6 +27,7 @@ #include #include +#include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 4ca6b88e9a7f3..5cd7844f1d5fa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -23,6 +23,7 @@ */ #include "nv50.h" +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index 6c93a20295a43..a00d9a55e53b8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -23,6 +23,7 @@ */ #include "nv50.h" +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index fa36233a71ddf..d6a2b9593538c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -20,6 +20,8 @@ * OTHER DEALINGS IN THE SOFTWARE. */ #include + +#include #include static int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index e5258ba19834e..07feae620c8d9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -317,7 +317,7 @@ gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) return -EBUSY; if (fifo) - fifo->pause(fifo, flags); + nvkm_fifo_pause(fifo, flags); if (nvkm_msec(device, 2000, if (nvkm_rd32(device, 0x002504) & 0x00000010) @@ -342,7 +342,7 @@ gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags) struct nvkm_fifo *fifo = device->fifo; if (fifo && flags) - fifo->start(fifo, flags); + nvkm_fifo_start(fifo, flags); nvkm_mask(device, 0x002504, 0x00000001, 0x00000000); nvkm_mask(device, 0x020060, 0x00070000, 0x00040000); -- GitLab From c85ee6ca79590cd51356bf24fb8936bc352138cf Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5556/7006] drm/nouveau/gr: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/engine.h | 4 +- .../gpu/drm/nouveau/include/nvkm/engine/gr.h | 94 ++-- drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- drivers/gpu/drm/nouveau/nouveau_bo.c | 3 +- drivers/gpu/drm/nouveau/nvkm/core/engine.c | 15 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 138 +++--- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 - .../drm/nouveau/nvkm/engine/device/gk104.c | 8 - .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 8 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 - .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 - drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild | 16 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c | 82 +++- .../gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c | 3 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c | 196 ++++++++ .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 455 +++++++++--------- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.h | 71 ++- .../gpu/drm/nouveau/nvkm/engine/gr/gf104.c | 23 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf108.c | 23 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf110.c | 23 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf117.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/gf119.c | 23 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk104.c | 67 +-- .../gpu/drm/nouveau/nvkm/engine/gr/gk110.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk110b.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk208.c | 25 +- .../gpu/drm/nouveau/nvkm/engine/gr/gk20a.c | 165 +++---- .../gpu/drm/nouveau/nvkm/engine/gr/gm107.c | 37 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm204.c | 36 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm206.c | 21 +- .../gpu/drm/nouveau/nvkm/engine/gr/gm20b.c | 28 +- .../gpu/drm/nouveau/nvkm/engine/gr/gt200.c | 47 ++ .../gpu/drm/nouveau/nvkm/engine/gr/gt215.c | 48 ++ .../nvkm/engine/gr/{gk20a.h => mcp79.c} | 43 +- .../gpu/drm/nouveau/nvkm/engine/gr/mcp89.c | 48 ++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 122 ++--- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c | 221 +++------ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h | 13 + drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c | 59 +++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c | 59 +++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 159 +++--- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h | 22 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c | 43 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c | 43 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c | 115 ++--- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c | 43 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c | 43 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 210 +++----- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h | 13 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c | 108 +++++ drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 372 +++----------- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h | 16 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h | 23 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 12 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 14 +- 59 files changed, 1744 insertions(+), 1847 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c rename drivers/gpu/drm/nouveau/nvkm/engine/gr/{gk20a.h => mcp79.c} (50%) create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 9d9c0e779f3fe..9c8c393247155 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -3,6 +3,7 @@ #include struct nvkm_device_oclass; /*XXX: DEV!ENG */ struct nvkm_fifo_chan; +struct nvkm_fb_tile; #define NV_ENGINE_(eng,var) (((var) << 8) | (eng)) #define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var)) @@ -20,7 +21,6 @@ struct nvkm_engine { spinlock_t lock; void (*tile_prog)(struct nvkm_engine *, int region); - int (*tlb_flush)(struct nvkm_engine *); }; struct nvkm_engine_func { @@ -29,6 +29,7 @@ struct nvkm_engine_func { int (*init)(struct nvkm_engine *); int (*fini)(struct nvkm_engine *, bool suspend); void (*intr)(struct nvkm_engine *); + void (*tile)(struct nvkm_engine *, int region, struct nvkm_fb_tile *); struct { int (*sclass)(struct nvkm_oclass *, int index, @@ -54,6 +55,7 @@ int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *, struct nvkm_engine **); struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *); void nvkm_engine_unref(struct nvkm_engine **); +void nvkm_engine_tile(struct nvkm_engine *, int region); static inline struct nvkm_engine * nv_engine(void *obj) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h index f09f1521e6ad4..f126e54d2e30b 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h @@ -3,64 +3,44 @@ #include struct nvkm_gr { - struct nvkm_engine engine; const struct nvkm_gr_func *func; - - /* Returns chipset-specific counts of units packed into an u64. - */ - u64 (*units)(struct nvkm_gr *); + struct nvkm_engine engine; }; -#define nvkm_gr_create(p,e,c,y,d) \ - nvkm_gr_create_((p), (e), (c), (y), sizeof(**d), (void **)(d)) -int -nvkm_gr_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, bool enable, - int length, void **pobject); -#define nvkm_gr_destroy(d) \ - nvkm_engine_destroy(&(d)->engine) -#define nvkm_gr_init(d) \ - nvkm_engine_init_old(&(d)->engine) -#define nvkm_gr_fini(d,s) \ - nvkm_engine_fini_old(&(d)->engine, (s)) - -#define _nvkm_gr_dtor _nvkm_engine_dtor -#define _nvkm_gr_init _nvkm_engine_init -#define _nvkm_gr_fini _nvkm_engine_fini - -extern struct nvkm_oclass nv04_gr_oclass; -extern struct nvkm_oclass nv10_gr_oclass; -extern struct nvkm_oclass nv20_gr_oclass; -extern struct nvkm_oclass nv25_gr_oclass; -extern struct nvkm_oclass nv2a_gr_oclass; -extern struct nvkm_oclass nv30_gr_oclass; -extern struct nvkm_oclass nv34_gr_oclass; -extern struct nvkm_oclass nv35_gr_oclass; -extern struct nvkm_oclass nv40_gr_oclass; -extern struct nvkm_oclass nv50_gr_oclass; -extern struct nvkm_oclass *gf100_gr_oclass; -extern struct nvkm_oclass *gf108_gr_oclass; -extern struct nvkm_oclass *gf104_gr_oclass; -extern struct nvkm_oclass *gf110_gr_oclass; -extern struct nvkm_oclass *gf117_gr_oclass; -extern struct nvkm_oclass *gf119_gr_oclass; -extern struct nvkm_oclass *gk104_gr_oclass; -extern struct nvkm_oclass *gk20a_gr_oclass; -extern struct nvkm_oclass *gk110_gr_oclass; -extern struct nvkm_oclass *gk110b_gr_oclass; -extern struct nvkm_oclass *gk208_gr_oclass; -extern struct nvkm_oclass *gm107_gr_oclass; -extern struct nvkm_oclass *gm204_gr_oclass; -extern struct nvkm_oclass *gm206_gr_oclass; -extern struct nvkm_oclass *gm20b_gr_oclass; - -#include - -extern const struct nvkm_bitfield nv04_gr_nsource[]; -bool nv04_gr_idle(struct nvkm_gr *); - -extern const struct nvkm_bitfield nv10_gr_intr_name[]; -extern const struct nvkm_bitfield nv10_gr_nstatus[]; - -extern const struct nvkm_enum nv50_data_error_names[]; +u64 nvkm_gr_units(struct nvkm_gr *); +int nvkm_gr_tlb_flush(struct nvkm_gr *); + +int nv04_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv10_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv15_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv17_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv20_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv25_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv2a_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv30_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv34_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv35_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv40_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv44_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int nv50_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int g84_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gt200_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int mcp79_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gt215_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int mcp89_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gf100_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gf104_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gf108_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gf110_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gf117_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gf119_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gk104_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gk110_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gk110b_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gk208_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gk20a_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gm107_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gm204_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gm206_gr_new(struct nvkm_device *, int, struct nvkm_gr **); +int gm20b_gr_new(struct nvkm_device *, int, struct nvkm_gr **); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 98c74985e27de..6634f420ded32 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -215,7 +215,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = 1; break; case NOUVEAU_GETPARAM_GRAPH_UNITS: - getparam->value = gr->units ? gr->units(gr) : 0; + getparam->value = nvkm_gr_units(gr); break; default: NV_PRINTK(dbg, cli, "unknown parameter %lld\n", getparam->param); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 140a1eb9c49e5..bd33d547d5740 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -48,7 +48,8 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg, { struct nouveau_drm *drm = nouveau_drm(dev); int i = reg - drm->tile.reg; - struct nvkm_fb *fb = nvxx_fb(&drm->device); + struct nvkm_device *device = nvxx_device(&drm->device); + struct nvkm_fb *fb = device->fb; struct nvkm_fb_tile *tile = &fb->tile.region[i]; nouveau_fence_unref(®->fence); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index eabd271f68b39..3fef9cc34345f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -25,6 +25,8 @@ #include #include +#include + void nvkm_engine_unref(struct nvkm_engine **pengine) { @@ -56,6 +58,14 @@ nvkm_engine_ref(struct nvkm_engine *engine) return engine; } +void +nvkm_engine_tile(struct nvkm_engine *engine, int region) +{ + struct nvkm_fb *fb = engine->subdev.device->fb; + if (engine->func->tile) + engine->func->tile(engine, region, &fb->tile.region[region]); +} + static void nvkm_engine_intr(struct nvkm_subdev *obj) { @@ -80,7 +90,8 @@ nvkm_engine_init(struct nvkm_subdev *obj) { struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); struct nvkm_subdev *subdev = &engine->subdev; - int ret = 0; + struct nvkm_fb *fb = subdev->device->fb; + int ret = 0, i; s64 time; if (!engine->usecount) { @@ -108,6 +119,8 @@ nvkm_engine_init(struct nvkm_subdev *obj) if (engine->func->init) ret = engine->func->init(engine); + for (i = 0; fb && i < fb->tile.regions; i++) + nvkm_engine_tile(engine, i); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 62395ab742c5f..3cf15d46f9d23 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -89,7 +89,7 @@ nv4_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv04_fifo_new, -// .gr = nv04_gr_new, + .gr = nv04_gr_new, // .sw = nv04_sw_new, }; @@ -109,7 +109,7 @@ nv5_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv04_fifo_new, -// .gr = nv04_gr_new, + .gr = nv04_gr_new, // .sw = nv04_sw_new, }; @@ -129,7 +129,7 @@ nv10_chipset = { .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, -// .gr = nv10_gr_new, + .gr = nv10_gr_new, }; static const struct nvkm_device_chip @@ -149,7 +149,7 @@ nv11_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv10_fifo_new, -// .gr = nv10_gr_new, + .gr = nv15_gr_new, // .sw = nv10_sw_new, }; @@ -170,7 +170,7 @@ nv15_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv10_fifo_new, -// .gr = nv10_gr_new, + .gr = nv15_gr_new, // .sw = nv10_sw_new, }; @@ -191,7 +191,7 @@ nv17_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv10_gr_new, + .gr = nv17_gr_new, // .sw = nv10_sw_new, }; @@ -212,7 +212,7 @@ nv18_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv10_gr_new, + .gr = nv17_gr_new, // .sw = nv10_sw_new, }; @@ -233,7 +233,7 @@ nv1a_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv10_fifo_new, -// .gr = nv10_gr_new, + .gr = nv15_gr_new, // .sw = nv10_sw_new, }; @@ -254,7 +254,7 @@ nv1f_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv10_gr_new, + .gr = nv17_gr_new, // .sw = nv10_sw_new, }; @@ -275,7 +275,7 @@ nv20_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv20_gr_new, + .gr = nv20_gr_new, // .sw = nv10_sw_new, }; @@ -296,7 +296,7 @@ nv25_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv25_gr_new, + .gr = nv25_gr_new, // .sw = nv10_sw_new, }; @@ -317,7 +317,7 @@ nv28_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv25_gr_new, + .gr = nv25_gr_new, // .sw = nv10_sw_new, }; @@ -338,7 +338,7 @@ nv2a_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv2a_gr_new, + .gr = nv2a_gr_new, // .sw = nv10_sw_new, }; @@ -359,7 +359,7 @@ nv30_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv30_gr_new, + .gr = nv30_gr_new, // .sw = nv10_sw_new, }; @@ -380,7 +380,7 @@ nv31_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv30_gr_new, + .gr = nv30_gr_new, // .mpeg = nv31_mpeg_new, // .sw = nv10_sw_new, }; @@ -402,7 +402,7 @@ nv34_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv34_gr_new, + .gr = nv34_gr_new, // .mpeg = nv31_mpeg_new, // .sw = nv10_sw_new, }; @@ -424,7 +424,7 @@ nv35_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv35_gr_new, + .gr = nv35_gr_new, // .sw = nv10_sw_new, }; @@ -445,7 +445,7 @@ nv36_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv17_fifo_new, -// .gr = nv35_gr_new, + .gr = nv35_gr_new, // .mpeg = nv31_mpeg_new, // .sw = nv10_sw_new, }; @@ -469,7 +469,7 @@ nv40_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -494,7 +494,7 @@ nv41_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -519,7 +519,7 @@ nv42_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -544,7 +544,7 @@ nv43_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -569,7 +569,7 @@ nv44_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -594,7 +594,7 @@ nv45_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -619,7 +619,7 @@ nv46_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -644,7 +644,7 @@ nv47_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -669,7 +669,7 @@ nv49_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -694,7 +694,7 @@ nv4a_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -719,7 +719,7 @@ nv4b_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -744,7 +744,7 @@ nv4c_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -769,7 +769,7 @@ nv4e_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -797,7 +797,7 @@ nv50_chipset = { .disp = nv50_disp_new, .dma = nv50_dma_new, .fifo = nv50_fifo_new, -// .gr = nv50_gr_new, + .gr = nv50_gr_new, // .mpeg = nv50_mpeg_new, // .pm = nv50_pm_new, // .sw = nv50_sw_new, @@ -822,7 +822,7 @@ nv63_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -847,7 +847,7 @@ nv67_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -872,7 +872,7 @@ nv68_chipset = { .disp = nv04_disp_new, .dma = nv04_dma_new, .fifo = nv40_fifo_new, -// .gr = nv40_gr_new, + .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, // .pm = nv40_pm_new, // .sw = nv10_sw_new, @@ -902,7 +902,7 @@ nv84_chipset = { .disp = g84_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = g84_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, @@ -933,7 +933,7 @@ nv86_chipset = { .disp = g84_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = g84_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, @@ -964,7 +964,7 @@ nv92_chipset = { .disp = g84_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = g84_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, @@ -995,7 +995,7 @@ nv94_chipset = { .disp = g94_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = g84_gr_new, // .mpeg = g84_mpeg_new, // .pm = g84_pm_new, // .sw = nv50_sw_new, @@ -1024,7 +1024,7 @@ nv96_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, // .sw = nv50_sw_new, -// .gr = nv50_gr_new, + .gr = g84_gr_new, // .mpeg = g84_mpeg_new, .vp = g84_vp_new, .cipher = g84_cipher_new, @@ -1055,7 +1055,7 @@ nv98_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, // .sw = nv50_sw_new, -// .gr = nv50_gr_new, + .gr = g84_gr_new, .mspdec = g98_mspdec_new, .sec = g98_sec_new, .msvld = g98_msvld_new, @@ -1088,7 +1088,7 @@ nva0_chipset = { .disp = gt200_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = gt200_gr_new, // .mpeg = g84_mpeg_new, // .pm = gt200_pm_new, // .sw = nv50_sw_new, @@ -1119,7 +1119,7 @@ nva3_chipset = { .disp = gt215_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = gt215_gr_new, // .mpeg = g84_mpeg_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, @@ -1152,7 +1152,7 @@ nva5_chipset = { .disp = gt215_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = gt215_gr_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, @@ -1184,7 +1184,7 @@ nva8_chipset = { .disp = gt215_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = gt215_gr_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, @@ -1214,7 +1214,7 @@ nvaa_chipset = { .disp = g94_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = gt200_gr_new, .mspdec = g98_mspdec_new, .msppp = g98_msppp_new, .msvld = g98_msvld_new, @@ -1245,7 +1245,7 @@ nvac_chipset = { .disp = g94_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = mcp79_gr_new, .mspdec = g98_mspdec_new, .msppp = g98_msppp_new, .msvld = g98_msvld_new, @@ -1278,7 +1278,7 @@ nvaf_chipset = { .disp = gt215_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .gr = nv50_gr_new, + .gr = mcp89_gr_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = mcp89_msvld_new, @@ -1313,7 +1313,7 @@ nvc0_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf100_gr_new, + .gr = gf100_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1347,7 +1347,7 @@ nvc1_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf108_gr_new, + .gr = gf108_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1381,7 +1381,7 @@ nvc3_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf104_gr_new, + .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1416,7 +1416,7 @@ nvc4_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf104_gr_new, + .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1451,7 +1451,7 @@ nvc8_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf110_gr_new, + .gr = gf110_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1486,7 +1486,7 @@ nvce_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf104_gr_new, + .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1520,7 +1520,7 @@ nvcf_chipset = { .disp = gt215_disp_new, .dma = gf100_dma_new, .fifo = gf100_fifo_new, -// .gr = gf104_gr_new, + .gr = gf104_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1552,7 +1552,7 @@ nvd7_chipset = { .disp = gf119_disp_new, .dma = gf119_dma_new, .fifo = gf100_fifo_new, -// .gr = gf117_gr_new, + .gr = gf117_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1586,7 +1586,7 @@ nvd9_chipset = { .disp = gf119_disp_new, .dma = gf119_dma_new, .fifo = gf100_fifo_new, -// .gr = gf119_gr_new, + .gr = gf119_gr_new, .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, @@ -1622,7 +1622,7 @@ nve4_chipset = { .disp = gk104_disp_new, .dma = gf119_dma_new, .fifo = gk104_fifo_new, -// .gr = gk104_gr_new, + .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1658,7 +1658,7 @@ nve6_chipset = { .disp = gk104_disp_new, .dma = gf119_dma_new, .fifo = gk104_fifo_new, -// .gr = gk104_gr_new, + .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1694,7 +1694,7 @@ nve7_chipset = { .disp = gk104_disp_new, .dma = gf119_dma_new, .fifo = gk104_fifo_new, -// .gr = gk104_gr_new, + .gr = gk104_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1721,7 +1721,7 @@ nvea_chipset = { .ce[2] = gk104_ce_new, .dma = gf119_dma_new, .fifo = gk20a_fifo_new, -// .gr = gk20a_gr_new, + .gr = gk20a_gr_new, // .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1754,7 +1754,7 @@ nvf0_chipset = { .disp = gk110_disp_new, .dma = gf119_dma_new, .fifo = gk104_fifo_new, -// .gr = gk110_gr_new, + .gr = gk110_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1790,7 +1790,7 @@ nvf1_chipset = { .disp = gk110_disp_new, .dma = gf119_dma_new, .fifo = gk104_fifo_new, -// .gr = gk110b_gr_new, + .gr = gk110b_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1826,7 +1826,7 @@ nv106_chipset = { .disp = gk110_disp_new, .dma = gf119_dma_new, .fifo = gk208_fifo_new, -// .gr = gk208_gr_new, + .gr = gk208_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1861,7 +1861,7 @@ nv108_chipset = { .disp = gk110_disp_new, .dma = gf119_dma_new, .fifo = gk208_fifo_new, -// .gr = gk208_gr_new, + .gr = gk208_gr_new, .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, @@ -1894,7 +1894,7 @@ nv117_chipset = { .disp = gm107_disp_new, .dma = gf119_dma_new, .fifo = gk208_fifo_new, -// .gr = gm107_gr_new, + .gr = gm107_gr_new, // .sw = gf100_sw_new, }; @@ -1923,7 +1923,7 @@ nv124_chipset = { .disp = gm204_disp_new, .dma = gf119_dma_new, .fifo = gm204_fifo_new, -// .gr = gm204_gr_new, + .gr = gm204_gr_new, // .sw = gf100_sw_new, }; @@ -1952,7 +1952,7 @@ nv126_chipset = { .disp = gm204_disp_new, .dma = gf119_dma_new, .fifo = gm204_fifo_new, -// .gr = gm206_gr_new, + .gr = gm206_gr_new, // .sw = gf100_sw_new, }; @@ -1973,7 +1973,7 @@ nv12b_chipset = { .ce[2] = gm204_ce_new, .dma = gf119_dma_new, .fifo = gm20b_fifo_new, -// .gr = gm20b_gr_new, + .gr = gm20b_gr_new, // .sw = gf100_sw_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index d319f5680f440..b88aceb343c8a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -29,47 +29,38 @@ gf100_identify(struct nvkm_device *device) switch (device->chipset) { case 0xc0: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index fe8298e02e9f3..1ad7b217e2b86 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -29,41 +29,33 @@ gk104_identify(struct nvkm_device *device) switch (device->chipset) { case 0xe4: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xf0: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; break; case 0x108: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 2362a634462c3..71e088abb620b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -32,7 +32,6 @@ gm100_identify(struct nvkm_device *device) #if 0 #endif device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass; #if 0 #endif #if 0 @@ -46,7 +45,6 @@ gm100_identify(struct nvkm_device *device) #if 0 #endif device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm204_gr_oclass; #if 0 #endif break; @@ -58,14 +56,12 @@ gm100_identify(struct nvkm_device *device) #if 0 #endif device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm206_gr_oclass; #if 0 #endif break; case 0x12b: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = gm20b_gr_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index edddbaa41b43d..7a8071be7ed0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -29,11 +29,9 @@ nv04_identify(struct nvkm_device *device) switch (device->chipset) { case 0x04: device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; break; case 0x05: device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index f1ebb9bcda3b6..15dbd71ebabf0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -28,35 +28,27 @@ nv10_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x10: - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x15: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x16: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x1a: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x11: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x17: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x1f: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; case 0x18: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index f9c4dad1f8ff0..158efa44054f5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -29,19 +29,15 @@ nv20_identify(struct nvkm_device *device) switch (device->chipset) { case 0x20: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv20_gr_oclass; break; case 0x25: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; break; case 0x28: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass; break; case 0x2a: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv2a_gr_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index b8e1e43723a3f..5a8fd485467a5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -29,25 +29,20 @@ nv30_identify(struct nvkm_device *device) switch (device->chipset) { case 0x30: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; break; case 0x35: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; break; case 0x31: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x36: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x34: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv34_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 158ed5e395df4..e3fdbf6ba8713 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -29,97 +29,81 @@ nv40_identify(struct nvkm_device *device) switch (device->chipset) { case 0x40: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 688b3e2d61ff9..912bd8070db76 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -29,80 +29,66 @@ nv50_identify(struct nvkm_device *device) switch (device->chipset) { case 0x50: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass; device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild index 79eceaac3c1d5..9ad0d0e78a96e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild @@ -1,6 +1,8 @@ nvkm-y += nvkm/engine/gr/base.o nvkm-y += nvkm/engine/gr/nv04.o nvkm-y += nvkm/engine/gr/nv10.o +nvkm-y += nvkm/engine/gr/nv15.o +nvkm-y += nvkm/engine/gr/nv17.o nvkm-y += nvkm/engine/gr/nv20.o nvkm-y += nvkm/engine/gr/nv25.o nvkm-y += nvkm/engine/gr/nv2a.o @@ -8,18 +10,24 @@ nvkm-y += nvkm/engine/gr/nv30.o nvkm-y += nvkm/engine/gr/nv34.o nvkm-y += nvkm/engine/gr/nv35.o nvkm-y += nvkm/engine/gr/nv40.o +nvkm-y += nvkm/engine/gr/nv44.o nvkm-y += nvkm/engine/gr/nv50.o +nvkm-y += nvkm/engine/gr/g84.o +nvkm-y += nvkm/engine/gr/gt200.o +nvkm-y += nvkm/engine/gr/mcp79.o +nvkm-y += nvkm/engine/gr/gt215.o +nvkm-y += nvkm/engine/gr/mcp89.o nvkm-y += nvkm/engine/gr/gf100.o -nvkm-y += nvkm/engine/gr/gf108.o nvkm-y += nvkm/engine/gr/gf104.o +nvkm-y += nvkm/engine/gr/gf108.o nvkm-y += nvkm/engine/gr/gf110.o nvkm-y += nvkm/engine/gr/gf117.o nvkm-y += nvkm/engine/gr/gf119.o nvkm-y += nvkm/engine/gr/gk104.o -nvkm-y += nvkm/engine/gr/gk20a.o nvkm-y += nvkm/engine/gr/gk110.o nvkm-y += nvkm/engine/gr/gk110b.o nvkm-y += nvkm/engine/gr/gk208.o +nvkm-y += nvkm/engine/gr/gk20a.o nvkm-y += nvkm/engine/gr/gm107.o nvkm-y += nvkm/engine/gr/gm204.o nvkm-y += nvkm/engine/gr/gm206.o @@ -28,16 +36,16 @@ nvkm-y += nvkm/engine/gr/gm20b.o nvkm-y += nvkm/engine/gr/ctxnv40.o nvkm-y += nvkm/engine/gr/ctxnv50.o nvkm-y += nvkm/engine/gr/ctxgf100.o -nvkm-y += nvkm/engine/gr/ctxgf108.o nvkm-y += nvkm/engine/gr/ctxgf104.o +nvkm-y += nvkm/engine/gr/ctxgf108.o nvkm-y += nvkm/engine/gr/ctxgf110.o nvkm-y += nvkm/engine/gr/ctxgf117.o nvkm-y += nvkm/engine/gr/ctxgf119.o nvkm-y += nvkm/engine/gr/ctxgk104.o -nvkm-y += nvkm/engine/gr/ctxgk20a.o nvkm-y += nvkm/engine/gr/ctxgk110.o nvkm-y += nvkm/engine/gr/ctxgk110b.o nvkm-y += nvkm/engine/gr/ctxgk208.o +nvkm-y += nvkm/engine/gr/ctxgk20a.o nvkm-y += nvkm/engine/gr/ctxgm107.o nvkm-y += nvkm/engine/gr/ctxgm204.o nvkm-y += nvkm/engine/gr/ctxgm206.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c index c6fb25847b89d..090765ff070de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/base.c @@ -25,6 +25,30 @@ #include +static void +nvkm_gr_tile(struct nvkm_engine *engine, int region, struct nvkm_fb_tile *tile) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + if (gr->func->tile) + gr->func->tile(gr, region, tile); +} + +u64 +nvkm_gr_units(struct nvkm_gr *gr) +{ + if (gr->func->units) + return gr->func->units(gr); + return 0; +} + +int +nvkm_gr_tlb_flush(struct nvkm_gr *gr) +{ + if (gr->func->tlb_flush) + return gr->func->tlb_flush(gr); + return -ENODEV; +} + static int nvkm_gr_oclass_get(struct nvkm_oclass *oclass, int index) { @@ -59,26 +83,54 @@ nvkm_gr_cclass_new(struct nvkm_fifo_chan *chan, return 0; } -struct nvkm_engine_func +static void +nvkm_gr_intr(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + gr->func->intr(gr); +} + +static int +nvkm_gr_oneinit(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + if (gr->func->oneinit) + return gr->func->oneinit(gr); + return 0; +} + +static int +nvkm_gr_init(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + return gr->func->init(gr); +} + +static void * +nvkm_gr_dtor(struct nvkm_engine *engine) +{ + struct nvkm_gr *gr = nvkm_gr(engine); + if (gr->func->dtor) + return gr->func->dtor(gr); + return gr; +} + +static const struct nvkm_engine_func nvkm_gr = { + .dtor = nvkm_gr_dtor, + .oneinit = nvkm_gr_oneinit, + .init = nvkm_gr_init, + .intr = nvkm_gr_intr, + .tile = nvkm_gr_tile, .fifo.cclass = nvkm_gr_cclass_new, .fifo.sclass = nvkm_gr_oclass_get, }; int -nvkm_gr_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, bool enable, - int length, void **pobject) +nvkm_gr_ctor(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, u32 pmc_enable, bool enable, struct nvkm_gr *gr) { - struct nvkm_gr *gr; - int ret; - - ret = nvkm_engine_create_(parent, engine, oclass, enable, - "gr", "gr", length, pobject); - gr = *pobject; - if (ret) - return ret; - - gr->engine.func = &nvkm_gr; - return 0; + gr->func = func; + return nvkm_engine_ctor(&nvkm_gr, device, index, pmc_enable, + enable, &gr->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c index 43d9ce2276685..ddaa16a71c84d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c @@ -19,9 +19,8 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ - #include "ctxgf100.h" -#include "gk20a.h" +#include "gf100.h" #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c new file mode 100644 index 0000000000000..ce913300539fe --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/g84.c @@ -0,0 +1,196 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv50.h" + +#include + +static const struct nvkm_bitfield nv50_gr_status[] = { + { 0x00000001, "BUSY" }, /* set when any bit is set */ + { 0x00000002, "DISPATCH" }, + { 0x00000004, "UNK2" }, + { 0x00000008, "UNK3" }, + { 0x00000010, "UNK4" }, + { 0x00000020, "UNK5" }, + { 0x00000040, "M2MF" }, + { 0x00000080, "UNK7" }, + { 0x00000100, "CTXPROG" }, + { 0x00000200, "VFETCH" }, + { 0x00000400, "CCACHE_PREGEOM" }, + { 0x00000800, "STRMOUT_VATTR_POSTGEOM" }, + { 0x00001000, "VCLIP" }, + { 0x00002000, "RATTR_APLANE" }, + { 0x00004000, "TRAST" }, + { 0x00008000, "CLIPID" }, + { 0x00010000, "ZCULL" }, + { 0x00020000, "ENG2D" }, + { 0x00040000, "RMASK" }, + { 0x00080000, "TPC_RAST" }, + { 0x00100000, "TPC_PROP" }, + { 0x00200000, "TPC_TEX" }, + { 0x00400000, "TPC_GEOM" }, + { 0x00800000, "TPC_MP" }, + { 0x01000000, "ROP" }, + {} +}; + +static const struct nvkm_bitfield +nv50_gr_vstatus_0[] = { + { 0x01, "VFETCH" }, + { 0x02, "CCACHE" }, + { 0x04, "PREGEOM" }, + { 0x08, "POSTGEOM" }, + { 0x10, "VATTR" }, + { 0x20, "STRMOUT" }, + { 0x40, "VCLIP" }, + {} +}; + +static const struct nvkm_bitfield +nv50_gr_vstatus_1[] = { + { 0x01, "TPC_RAST" }, + { 0x02, "TPC_PROP" }, + { 0x04, "TPC_TEX" }, + { 0x08, "TPC_GEOM" }, + { 0x10, "TPC_MP" }, + {} +}; + +static const struct nvkm_bitfield +nv50_gr_vstatus_2[] = { + { 0x01, "RATTR" }, + { 0x02, "APLANE" }, + { 0x04, "TRAST" }, + { 0x08, "CLIPID" }, + { 0x10, "ZCULL" }, + { 0x20, "ENG2D" }, + { 0x40, "RMASK" }, + { 0x80, "ROP" }, + {} +}; + +static void +nvkm_gr_vstatus_print(struct nv50_gr *gr, int r, + const struct nvkm_bitfield *units, u32 status) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + u32 stat = status; + u8 mask = 0x00; + char msg[64]; + int i; + + for (i = 0; units[i].name && status; i++) { + if ((status & 7) == 1) + mask |= (1 << i); + status >>= 3; + } + + nvkm_snprintbf(msg, sizeof(msg), units, mask); + nvkm_error(subdev, "PGRAPH_VSTATUS%d: %08x [%s]\n", r, stat, msg); +} + +int +g84_gr_tlb_flush(struct nvkm_gr *base) +{ + struct nv50_gr *gr = nv50_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + struct nvkm_timer *tmr = device->timer; + bool idle, timeout = false; + unsigned long flags; + char status[128]; + u64 start; + u32 tmp; + + spin_lock_irqsave(&gr->lock, flags); + nvkm_mask(device, 0x400500, 0x00000001, 0x00000000); + + start = nvkm_timer_read(tmr); + do { + idle = true; + + for (tmp = nvkm_rd32(device, 0x400380); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nvkm_rd32(device, 0x400384); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + + for (tmp = nvkm_rd32(device, 0x400388); tmp && idle; tmp >>= 3) { + if ((tmp & 7) == 1) + idle = false; + } + } while (!idle && + !(timeout = nvkm_timer_read(tmr) - start > 2000000000)); + + if (timeout) { + nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n"); + + tmp = nvkm_rd32(device, 0x400700); + nvkm_snprintbf(status, sizeof(status), nv50_gr_status, tmp); + nvkm_error(subdev, "PGRAPH_STATUS %08x [%s]\n", tmp, status); + + nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0, + nvkm_rd32(device, 0x400380)); + nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1, + nvkm_rd32(device, 0x400384)); + nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2, + nvkm_rd32(device, 0x400388)); + } + + + nvkm_wr32(device, 0x100c80, 0x00000001); + nvkm_msec(device, 2000, + if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) + break; + ); + nvkm_mask(device, 0x400500, 0x00000001, 0x00000001); + spin_unlock_irqrestore(&gr->lock, flags); + return timeout ? -EBUSY : 0; +} + +static const struct nvkm_gr_func +g84_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8297, &nv50_gr_object }, + {} + } +}; + +int +g84_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&g84_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 8fd26fa03c2e7..1ad6785683f2c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -813,9 +814,9 @@ gf100_gr_mthd(struct gf100_gr *gr, const struct gf100_gr_pack *p) } u64 -gf100_gr_units(struct nvkm_gr *obj) +gf100_gr_units(struct nvkm_gr *base) { - struct gf100_gr *gr = container_of(obj, typeof(*gr), base); + struct gf100_gr *gr = gf100_gr(base); u64 cfg; cfg = (u32)gr->gpc_nr; @@ -1173,10 +1174,11 @@ gf100_gr_ctxctl_isr(struct gf100_gr *gr) } static void -gf100_gr_intr(struct nvkm_subdev *subdev) +gf100_gr_intr(struct nvkm_gr *base) { - struct gf100_gr *gr = (void *)subdev; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct gf100_gr *gr = gf100_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fifo_chan *chan; unsigned long flags; u64 inst = nvkm_rd32(device, 0x409b00) & 0x0fffffff; @@ -1196,7 +1198,7 @@ gf100_gr_intr(struct nvkm_subdev *subdev) chid = chan->chid; } - if (nv_device(gr)->card_type < NV_E0 || subc < 4) + if (device->card_type < NV_E0 || subc < 4) class = nvkm_rd32(device, 0x404200 + (subc * 4)); else class = 0x0000; @@ -1334,16 +1336,13 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) const struct gf100_grctx_func *grctx = gr->func->grctx; struct nvkm_subdev *subdev = &gr->base.engine.subdev; struct nvkm_device *device = subdev->device; - struct gf100_gr_oclass *oclass = (void *)nv_object(gr)->oclass; int i; if (gr->firmware) { /* load fuc microcode */ nvkm_mc_unk260(device->mc, 0); - gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, - &gr->fuc409d); - gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, - &gr->fuc41ad); + gf100_gr_init_fw(gr, 0x409000, &gr->fuc409c, &gr->fuc409d); + gf100_gr_init_fw(gr, 0x41a000, &gr->fuc41ac, &gr->fuc41ad); nvkm_mc_unk260(device->mc, 1); /* start both of them running */ @@ -1389,7 +1388,7 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) ) < 0) return -EBUSY; - if (nv_device(gr)->chipset >= 0xe0) { + if (device->chipset >= 0xe0) { nvkm_wr32(device, 0x409800, 0x00000000); nvkm_wr32(device, 0x409500, 0x00000001); nvkm_wr32(device, 0x409504, 0x00000030); @@ -1434,33 +1433,33 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) return 0; } else - if (!oclass->fecs.ucode) { + if (!gr->func->fecs.ucode) { return -ENOSYS; } /* load HUB microcode */ nvkm_mc_unk260(device->mc, 0); nvkm_wr32(device, 0x4091c0, 0x01000000); - for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++) - nvkm_wr32(device, 0x4091c4, oclass->fecs.ucode->data.data[i]); + for (i = 0; i < gr->func->fecs.ucode->data.size / 4; i++) + nvkm_wr32(device, 0x4091c4, gr->func->fecs.ucode->data.data[i]); nvkm_wr32(device, 0x409180, 0x01000000); - for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) { + for (i = 0; i < gr->func->fecs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) nvkm_wr32(device, 0x409188, i >> 6); - nvkm_wr32(device, 0x409184, oclass->fecs.ucode->code.data[i]); + nvkm_wr32(device, 0x409184, gr->func->fecs.ucode->code.data[i]); } /* load GPC microcode */ nvkm_wr32(device, 0x41a1c0, 0x01000000); - for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++) - nvkm_wr32(device, 0x41a1c4, oclass->gpccs.ucode->data.data[i]); + for (i = 0; i < gr->func->gpccs.ucode->data.size / 4; i++) + nvkm_wr32(device, 0x41a1c4, gr->func->gpccs.ucode->data.data[i]); nvkm_wr32(device, 0x41a180, 0x01000000); - for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) { + for (i = 0; i < gr->func->gpccs.ucode->code.size / 4; i++) { if ((i & 0x3f) == 0) nvkm_wr32(device, 0x41a188, i >> 6); - nvkm_wr32(device, 0x41a184, oclass->gpccs.ucode->code.data[i]); + nvkm_wr32(device, 0x41a184, gr->func->gpccs.ucode->code.data[i]); } nvkm_mc_unk260(device->mc, 1); @@ -1493,21 +1492,216 @@ gf100_gr_init_ctxctl(struct gf100_gr *gr) return 0; } +static int +gf100_gr_oneinit(struct nvkm_gr *base) +{ + struct gf100_gr *gr = gf100_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + int ret, i, j; + + nvkm_pmu_pgob(device->pmu, false); + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, + &gr->unk4188b4); + if (ret) + return ret; + + ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, + &gr->unk4188b8); + if (ret) + return ret; + + nvkm_kmap(gr->unk4188b4); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(gr->unk4188b4, i, 0x00000010); + nvkm_done(gr->unk4188b4); + + nvkm_kmap(gr->unk4188b8); + for (i = 0; i < 0x1000; i += 4) + nvkm_wo32(gr->unk4188b8, i, 0x00000010); + nvkm_done(gr->unk4188b8); + + gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16; + gr->gpc_nr = nvkm_rd32(device, 0x409604) & 0x0000001f; + for (i = 0; i < gr->gpc_nr; i++) { + gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608)); + gr->tpc_total += gr->tpc_nr[i]; + gr->ppc_nr[i] = gr->func->ppc_nr; + for (j = 0; j < gr->ppc_nr[i]; j++) { + u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); + gr->ppc_tpc_nr[i][j] = hweight8(mask); + } + } + + /*XXX: these need figuring out... though it might not even matter */ + switch (device->chipset) { + case 0xc0: + if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ + gr->magic_not_rop_nr = 0x07; + } else + if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ + gr->magic_not_rop_nr = 0x05; + } else + if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ + gr->magic_not_rop_nr = 0x06; + } + break; + case 0xc3: /* 450, 4/0/0/0, 2 */ + gr->magic_not_rop_nr = 0x03; + break; + case 0xc4: /* 460, 3/4/0/0, 4 */ + gr->magic_not_rop_nr = 0x01; + break; + case 0xc1: /* 2/0/0/0, 1 */ + gr->magic_not_rop_nr = 0x01; + break; + case 0xc8: /* 4/4/3/4, 5 */ + gr->magic_not_rop_nr = 0x06; + break; + case 0xce: /* 4/4/0/0, 4 */ + gr->magic_not_rop_nr = 0x03; + break; + case 0xcf: /* 4/0/0/0, 3 */ + gr->magic_not_rop_nr = 0x03; + break; + case 0xd7: + case 0xd9: /* 1/0/0/0, 1 */ + case 0xea: /* gk20a */ + case 0x12b: /* gm20b */ + gr->magic_not_rop_nr = 0x01; + break; + } + + return 0; +} + +int +gf100_gr_init_(struct nvkm_gr *base) +{ + struct gf100_gr *gr = gf100_gr(base); + nvkm_pmu_pgob(gr->base.engine.subdev.device->pmu, false); + return gr->func->init(gr); +} + +void +gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc) +{ + kfree(fuc->data); + fuc->data = NULL; +} + +void * +gf100_gr_dtor(struct nvkm_gr *base) +{ + struct gf100_gr *gr = gf100_gr(base); + + if (gr->func->dtor) + gr->func->dtor(gr); + kfree(gr->data); + + gf100_gr_dtor_fw(&gr->fuc409c); + gf100_gr_dtor_fw(&gr->fuc409d); + gf100_gr_dtor_fw(&gr->fuc41ac); + gf100_gr_dtor_fw(&gr->fuc41ad); + + nvkm_memory_del(&gr->unk4188b8); + nvkm_memory_del(&gr->unk4188b4); + return gr; +} + +static const struct nvkm_gr_func +gf100_gr_ = { + .dtor = gf100_gr_dtor, + .oneinit = gf100_gr_oneinit, + .init = gf100_gr_init_, + .intr = gf100_gr_intr, + .units = gf100_gr_units, + .chan_new = gf100_gr_chan_new, + .object_get = gf100_gr_object_get, +}; + +int +gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, + struct gf100_gr_fuc *fuc) +{ + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; + const struct firmware *fw; + char f[64]; + char cname[16]; + int ret; + int i; + + /* Convert device name to lowercase */ + strncpy(cname, device->chip->name, sizeof(cname)); + cname[sizeof(cname) - 1] = '\0'; + i = strlen(cname); + while (i) { + --i; + cname[i] = tolower(cname[i]); + } + + snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); + ret = request_firmware(&fw, f, nv_device_base(device)); + if (ret) { + nvkm_error(subdev, "failed to load %s\n", fwname); + return ret; + } + + fuc->size = fw->size; + fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); + release_firmware(fw); + return (fuc->data != NULL) ? 0 : -ENOMEM; +} + +int +gf100_gr_ctor(const struct gf100_gr_func *func, struct nvkm_device *device, + int index, struct gf100_gr *gr) +{ + int ret; + + gr->func = func; + gr->firmware = nvkm_boolopt(device->cfgopt, "NvGrUseFW", + func->fecs.ucode == NULL); + + ret = nvkm_gr_ctor(&gf100_gr_, device, index, 0x08001000, + gr->firmware || func->fecs.ucode != NULL, + &gr->base); + if (ret) + return ret; + + if (gr->firmware) { + nvkm_info(&gr->base.engine.subdev, "using external firmware\n"); + if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) || + gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) || + gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) || + gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad)) + return -ENODEV; + } + + return 0; +} + int -gf100_gr_init(struct nvkm_object *object) +gf100_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct gf100_gr *gr; + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + return gf100_gr_ctor(func, device, index, gr); +} + +int +gf100_gr_init(struct gf100_gr *gr) { - struct gf100_gr *gr = (void *)object; struct nvkm_device *device = gr->base.engine.subdev.device; - struct gf100_gr_oclass *oclass = (void *)object->oclass; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; - int ret, i; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; + int i; nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); @@ -1518,7 +1712,7 @@ gf100_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); - gf100_gr_mmio(gr, oclass->mmio); + gf100_gr_mmio(gr, gr->func->mmio); memcpy(tpcnr, gr->tpc_nr, sizeof(gr->tpc_nr)); for (i = 0, gpc = -1; i < gr->tpc_total; i++) { @@ -1543,7 +1737,7 @@ gf100_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_UNIT(gpc, 0x0918), magicgpc918); } - if (nv_device(gr)->chipset != 0xd7) + if (device->chipset != 0xd7) nvkm_wr32(device, GPC_BCAST(0x1bd4), magicgpc918); else nvkm_wr32(device, GPC_BCAST(0x3fd4), magicgpc918); @@ -1606,182 +1800,6 @@ gf100_gr_init(struct nvkm_object *object) return gf100_gr_init_ctxctl(gr); } -void -gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc) -{ - kfree(fuc->data); - fuc->data = NULL; -} - -int -gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, - struct gf100_gr_fuc *fuc) -{ - struct nvkm_subdev *subdev = &gr->base.engine.subdev; - struct nvkm_device *device = subdev->device; - const struct firmware *fw; - char f[64]; - char cname[16]; - int ret; - int i; - - /* Convert device name to lowercase */ - strncpy(cname, device->chip->name, sizeof(cname)); - cname[sizeof(cname) - 1] = '\0'; - i = strlen(cname); - while (i) { - --i; - cname[i] = tolower(cname[i]); - } - - snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); - ret = request_firmware(&fw, f, nv_device_base(device)); - if (ret) { - nvkm_error(subdev, "failed to load %s\n", fwname); - return ret; - } - - fuc->size = fw->size; - fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL); - release_firmware(fw); - return (fuc->data != NULL) ? 0 : -ENOMEM; -} - -void -gf100_gr_dtor(struct nvkm_object *object) -{ - struct gf100_gr *gr = (void *)object; - - kfree(gr->data); - - gf100_gr_dtor_fw(&gr->fuc409c); - gf100_gr_dtor_fw(&gr->fuc409d); - gf100_gr_dtor_fw(&gr->fuc41ac); - gf100_gr_dtor_fw(&gr->fuc41ad); - - nvkm_memory_del(&gr->unk4188b8); - nvkm_memory_del(&gr->unk4188b4); - - nvkm_gr_destroy(&gr->base); -} - -static const struct nvkm_gr_func -gf100_gr_ = { - .chan_new = gf100_gr_chan_new, - .object_get = gf100_gr_object_get, -}; - -int -gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *bclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct gf100_gr_oclass *oclass = (void *)bclass; - struct nvkm_device *device = (void *)parent; - struct gf100_gr *gr; - bool use_ext_fw, enable; - int ret, i, j; - - use_ext_fw = nvkm_boolopt(device->cfgopt, "NvGrUseFW", - oclass->fecs.ucode == NULL); - enable = use_ext_fw || oclass->fecs.ucode != NULL; - - ret = nvkm_gr_create(parent, engine, bclass, enable, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->func = oclass->func; - gr->base.func = &gf100_gr_; - nv_subdev(gr)->unit = 0x08001000; - nv_subdev(gr)->intr = gf100_gr_intr; - - gr->base.units = gf100_gr_units; - - if (use_ext_fw) { - nvkm_info(&gr->base.engine.subdev, "using external firmware\n"); - if (gf100_gr_ctor_fw(gr, "fecs_inst", &gr->fuc409c) || - gf100_gr_ctor_fw(gr, "fecs_data", &gr->fuc409d) || - gf100_gr_ctor_fw(gr, "gpccs_inst", &gr->fuc41ac) || - gf100_gr_ctor_fw(gr, "gpccs_data", &gr->fuc41ad)) - return -ENODEV; - gr->firmware = true; - } - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, - &gr->unk4188b4); - if (ret) - return ret; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 0x1000, 256, false, - &gr->unk4188b8); - if (ret) - return ret; - - nvkm_kmap(gr->unk4188b4); - for (i = 0; i < 0x1000; i += 4) - nvkm_wo32(gr->unk4188b4, i, 0x00000010); - nvkm_done(gr->unk4188b4); - - nvkm_kmap(gr->unk4188b8); - for (i = 0; i < 0x1000; i += 4) - nvkm_wo32(gr->unk4188b8, i, 0x00000010); - nvkm_done(gr->unk4188b8); - - gr->rop_nr = (nvkm_rd32(device, 0x409604) & 0x001f0000) >> 16; - gr->gpc_nr = nvkm_rd32(device, 0x409604) & 0x0000001f; - for (i = 0; i < gr->gpc_nr; i++) { - gr->tpc_nr[i] = nvkm_rd32(device, GPC_UNIT(i, 0x2608)); - gr->tpc_total += gr->tpc_nr[i]; - gr->ppc_nr[i] = oclass->ppc_nr; - for (j = 0; j < gr->ppc_nr[i]; j++) { - u8 mask = nvkm_rd32(device, GPC_UNIT(i, 0x0c30 + (j * 4))); - gr->ppc_tpc_nr[i][j] = hweight8(mask); - } - } - - /*XXX: these need figuring out... though it might not even matter */ - switch (nv_device(gr)->chipset) { - case 0xc0: - if (gr->tpc_total == 11) { /* 465, 3/4/4/0, 4 */ - gr->magic_not_rop_nr = 0x07; - } else - if (gr->tpc_total == 14) { /* 470, 3/3/4/4, 5 */ - gr->magic_not_rop_nr = 0x05; - } else - if (gr->tpc_total == 15) { /* 480, 3/4/4/4, 6 */ - gr->magic_not_rop_nr = 0x06; - } - break; - case 0xc3: /* 450, 4/0/0/0, 2 */ - gr->magic_not_rop_nr = 0x03; - break; - case 0xc4: /* 460, 3/4/0/0, 4 */ - gr->magic_not_rop_nr = 0x01; - break; - case 0xc1: /* 2/0/0/0, 1 */ - gr->magic_not_rop_nr = 0x01; - break; - case 0xc8: /* 4/4/3/4, 5 */ - gr->magic_not_rop_nr = 0x06; - break; - case 0xce: /* 4/4/0/0, 4 */ - gr->magic_not_rop_nr = 0x03; - break; - case 0xcf: /* 4/0/0/0, 3 */ - gr->magic_not_rop_nr = 0x03; - break; - case 0xd7: - case 0xd9: /* 1/0/0/0, 1 */ - case 0xea: /* gk20a */ - case 0x12b: /* gm20b */ - gr->magic_not_rop_nr = 0x01; - break; - } - - return 0; -} - #include "fuc/hubgf100.fuc3.h" struct gf100_gr_ucode @@ -1804,6 +1822,10 @@ gf100_gr_gpccs_ucode = { static const struct gf100_gr_func gf100_gr = { + .init = gf100_gr_init, + .mmio = gf100_gr_pack_mmio, + .fecs.ucode = &gf100_gr_fecs_ucode, + .gpccs.ucode = &gf100_gr_gpccs_ucode, .grctx = &gf100_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -1814,17 +1836,8 @@ gf100_gr = { } }; -struct nvkm_oclass * -gf100_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gf100_gr, - .mmio = gf100_gr_pack_mmio, - .fecs.ucode = &gf100_gr_fecs_ucode, - .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; +int +gf100_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf100_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h index 43e9897ac8838..4611961b11874 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h @@ -21,8 +21,8 @@ * * Authors: Ben Skeggs */ -#ifndef __NVC0_GR_H__ -#define __NVC0_GR_H__ +#ifndef __GF100_GR_H__ +#define __GF100_GR_H__ #define gf100_gr(p) container_of((p), struct gf100_gr, base) #include "priv.h" @@ -71,8 +71,8 @@ struct gf100_gr_zbc_depth { }; struct gf100_gr { - struct nvkm_gr base; const struct gf100_gr_func *func; + struct nvkm_gr base; struct gf100_gr_fuc fuc409c; struct gf100_gr_fuc fuc409d; @@ -110,11 +110,40 @@ struct gf100_gr { u8 magic_not_rop_nr; }; +int gf100_gr_ctor(const struct gf100_gr_func *, struct nvkm_device *, + int, struct gf100_gr *); +int gf100_gr_new_(const struct gf100_gr_func *, struct nvkm_device *, + int, struct nvkm_gr **); +void *gf100_gr_dtor(struct nvkm_gr *); + struct gf100_gr_func { + void (*dtor)(struct gf100_gr *); + int (*init)(struct gf100_gr *); + void (*init_gpc_mmu)(struct gf100_gr *); + void (*set_hww_esr_report_mask)(struct gf100_gr *); + const struct gf100_gr_pack *mmio; + struct { + struct gf100_gr_ucode *ucode; + } fecs; + struct { + struct gf100_gr_ucode *ucode; + } gpccs; + int ppc_nr; const struct gf100_grctx_func *grctx; struct nvkm_sclass sclass[]; }; +int gf100_gr_init(struct gf100_gr *); + +int gk104_gr_init(struct gf100_gr *); + +int gk20a_gr_new_(const struct gf100_gr_func *, struct nvkm_device *, + int, struct nvkm_gr **); +void gk20a_gr_dtor(struct gf100_gr *); +int gk20a_gr_init(struct gf100_gr *); + +int gm204_gr_init(struct gf100_gr *); + #define gf100_gr_chan(p) container_of((p), struct gf100_gr_chan, object) struct gf100_gr_chan { @@ -137,33 +166,10 @@ void gf100_gr_dtor_fw(struct gf100_gr_fuc *); int gf100_gr_ctor_fw(struct gf100_gr *, const char *, struct gf100_gr_fuc *); u64 gf100_gr_units(struct nvkm_gr *); -int gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **); -void gf100_gr_dtor(struct nvkm_object *); -int gf100_gr_init(struct nvkm_object *); void gf100_gr_zbc_init(struct gf100_gr *); -int gk104_gr_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **); -int gk104_gr_init(struct nvkm_object *); - -int gk20a_gr_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **); -void gk20a_gr_dtor(struct nvkm_object *); -int gk20a_gr_init(struct nvkm_object *); - -int gm204_gr_init(struct nvkm_object *); - extern const struct nvkm_object_func gf100_fermi; -extern struct nvkm_oclass gf100_gr_sclass[]; -extern struct nvkm_oclass gf110_gr_sclass[]; -extern struct nvkm_oclass gk110_gr_sclass[]; -extern struct nvkm_oclass gm204_gr_sclass[]; - struct gf100_gr_init { u32 addr; u8 count; @@ -191,19 +197,6 @@ extern struct gf100_gr_ucode gf100_gr_gpccs_ucode; extern struct gf100_gr_ucode gk110_gr_fecs_ucode; extern struct gf100_gr_ucode gk110_gr_gpccs_ucode; -struct gf100_gr_oclass { - struct nvkm_oclass base; - const struct gf100_gr_func *func; - const struct gf100_gr_pack *mmio; - struct { - struct gf100_gr_ucode *ucode; - } fecs; - struct { - struct gf100_gr_ucode *ucode; - } gpccs; - int ppc_nr; -}; - int gf100_gr_wait_idle(struct gf100_gr *); void gf100_gr_mmio(struct gf100_gr *, const struct gf100_gr_pack *); void gf100_gr_icmd(struct gf100_gr *, const struct gf100_gr_pack *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c index aa529b5c0daaf..8f253e0a22f40 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c @@ -114,6 +114,10 @@ gf104_gr_pack_mmio[] = { static const struct gf100_gr_func gf104_gr = { + .init = gf100_gr_init, + .mmio = gf104_gr_pack_mmio, + .fecs.ucode = &gf100_gr_fecs_ucode, + .gpccs.ucode = &gf100_gr_gpccs_ucode, .grctx = &gf104_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -124,17 +128,8 @@ gf104_gr = { } }; -struct nvkm_oclass * -gf104_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gf104_gr, - .mmio = gf104_gr_pack_mmio, - .fecs.ucode = &gf100_gr_fecs_ucode, - .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; +int +gf104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf104_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c index 971c897d59be9..815a5aafa2457 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c @@ -105,6 +105,10 @@ gf108_gr_pack_mmio[] = { static const struct gf100_gr_func gf108_gr = { + .init = gf100_gr_init, + .mmio = gf108_gr_pack_mmio, + .fecs.ucode = &gf100_gr_fecs_ucode, + .gpccs.ucode = &gf100_gr_gpccs_ucode, .grctx = &gf108_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -116,17 +120,8 @@ gf108_gr = { } }; -struct nvkm_oclass * -gf108_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gf108_gr, - .mmio = gf108_gr_pack_mmio, - .fecs.ucode = &gf100_gr_fecs_ucode, - .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; +int +gf108_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf108_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c index f832a8bd454ce..d13187409d685 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c @@ -86,6 +86,10 @@ gf110_gr_pack_mmio[] = { static const struct gf100_gr_func gf110_gr = { + .init = gf100_gr_init, + .mmio = gf110_gr_pack_mmio, + .fecs.ucode = &gf100_gr_fecs_ucode, + .gpccs.ucode = &gf100_gr_gpccs_ucode, .grctx = &gf110_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -98,17 +102,8 @@ gf110_gr = { } }; -struct nvkm_oclass * -gf110_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xc8), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gf110_gr, - .mmio = gf110_gr_pack_mmio, - .fecs.ucode = &gf100_gr_fecs_ucode, - .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; +int +gf110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf110_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c index 909b5a6fa8d2d..28483d8bf3d2e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c @@ -122,6 +122,11 @@ gf117_gr_gpccs_ucode = { static const struct gf100_gr_func gf117_gr = { + .init = gf100_gr_init, + .mmio = gf117_gr_pack_mmio, + .fecs.ucode = &gf117_gr_fecs_ucode, + .gpccs.ucode = &gf117_gr_gpccs_ucode, + .ppc_nr = 1, .grctx = &gf117_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -134,18 +139,8 @@ gf117_gr = { } }; -struct nvkm_oclass * -gf117_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gf117_gr, - .mmio = gf117_gr_pack_mmio, - .fecs.ucode = &gf117_gr_fecs_ucode, - .gpccs.ucode = &gf117_gr_gpccs_ucode, - .ppc_nr = 1, -}.base; +int +gf117_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf117_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c index 01c2dcc4e8733..9811a72e03133 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c @@ -177,6 +177,10 @@ gf119_gr_pack_mmio[] = { static const struct gf100_gr_func gf119_gr = { + .init = gf100_gr_init, + .mmio = gf119_gr_pack_mmio, + .fecs.ucode = &gf100_gr_fecs_ucode, + .gpccs.ucode = &gf100_gr_gpccs_ucode, .grctx = &gf119_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -189,17 +193,8 @@ gf119_gr = { } }; -struct nvkm_oclass * -gf119_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xd9), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gf100_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gf119_gr, - .mmio = gf119_gr_pack_mmio, - .fecs.ucode = &gf100_gr_fecs_ucode, - .gpccs.ucode = &gf100_gr_gpccs_ucode, -}.base; +int +gf119_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gf119_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c index efd5ebd1fa046..abf54928a1a44 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c @@ -24,8 +24,6 @@ #include "gf100.h" #include "ctxgf100.h" -#include - #include /******************************************************************************* @@ -180,22 +178,14 @@ gk104_gr_pack_mmio[] = { ******************************************************************************/ int -gk104_gr_init(struct nvkm_object *object) +gk104_gr_init(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr *gr = (void *)object; struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, rop; - int ret, i; - - nvkm_pmu_pgob(device->pmu, false); - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; + int i; nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x08a4), 0x00000000); @@ -206,7 +196,7 @@ gk104_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); - gf100_gr_mmio(gr, oclass->mmio); + gf100_gr_mmio(gr, gr->func->mmio); nvkm_wr32(device, GPC_UNIT(0, 0x3018), 0x00000001); @@ -296,28 +286,6 @@ gk104_gr_init(struct nvkm_object *object) return gf100_gr_init_ctxctl(gr); } -static const struct gf100_gr_func -gk104_gr = { - .grctx = &gk104_grctx, - .sclass = { - { -1, -1, FERMI_TWOD_A }, - { -1, -1, KEPLER_INLINE_TO_MEMORY_A }, - { -1, -1, KEPLER_A, &gf100_fermi }, - { -1, -1, KEPLER_COMPUTE_A }, - {} - } -}; - -int -gk104_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = (void *)parent; - nvkm_pmu_pgob(device->pmu, false); - return gf100_gr_ctor(parent, engine, oclass, data, size, pobject); -} - #include "fuc/hubgk104.fuc3.h" static struct gf100_gr_ucode @@ -338,18 +306,25 @@ gk104_gr_gpccs_ucode = { .data.size = sizeof(gk104_grgpc_data), }; -struct nvkm_oclass * -gk104_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xe4), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gk104_gr, +static const struct gf100_gr_func +gk104_gr = { + .init = gk104_gr_init, .mmio = gk104_gr_pack_mmio, .fecs.ucode = &gk104_gr_fecs_ucode, .gpccs.ucode = &gk104_gr_gpccs_ucode, .ppc_nr = 1, -}.base; + .grctx = &gk104_grctx, + .sclass = { + { -1, -1, FERMI_TWOD_A }, + { -1, -1, KEPLER_INLINE_TO_MEMORY_A }, + { -1, -1, KEPLER_A, &gf100_fermi }, + { -1, -1, KEPLER_COMPUTE_A }, + {} + } +}; + +int +gk104_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk104_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c index fb513ea8bbd2a..32aa2946e7b70 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c @@ -182,6 +182,11 @@ gk110_gr_gpccs_ucode = { static const struct gf100_gr_func gk110_gr = { + .init = gk104_gr_init, + .mmio = gk110_gr_pack_mmio, + .fecs.ucode = &gk110_gr_fecs_ucode, + .gpccs.ucode = &gk110_gr_gpccs_ucode, + .ppc_nr = 2, .grctx = &gk110_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -192,18 +197,8 @@ gk110_gr = { } }; -struct nvkm_oclass * -gk110_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xf0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gk110_gr, - .mmio = gk110_gr_pack_mmio, - .fecs.ucode = &gk110_gr_fecs_ucode, - .gpccs.ucode = &gk110_gr_gpccs_ucode, - .ppc_nr = 2, -}.base; +int +gk110_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk110_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c index b3da907b2b70e..22f88afbf35fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c @@ -102,6 +102,11 @@ gk110b_gr_pack_mmio[] = { static const struct gf100_gr_func gk110b_gr = { + .init = gk104_gr_init, + .mmio = gk110b_gr_pack_mmio, + .fecs.ucode = &gk110_gr_fecs_ucode, + .gpccs.ucode = &gk110_gr_gpccs_ucode, + .ppc_nr = 2, .grctx = &gk110b_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -112,18 +117,8 @@ gk110b_gr = { } }; -struct nvkm_oclass * -gk110b_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0xf1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gk110b_gr, - .mmio = gk110b_gr_pack_mmio, - .fecs.ucode = &gk110_gr_fecs_ucode, - .gpccs.ucode = &gk110_gr_gpccs_ucode, - .ppc_nr = 2, -}.base; +int +gk110b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk110b_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c index 243b0a3f67c25..ee7554fc87dc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c @@ -161,6 +161,11 @@ gk208_gr_gpccs_ucode = { static const struct gf100_gr_func gk208_gr = { + .init = gk104_gr_init, + .mmio = gk208_gr_pack_mmio, + .fecs.ucode = &gk208_gr_fecs_ucode, + .gpccs.ucode = &gk208_gr_gpccs_ucode, + .ppc_nr = 1, .grctx = &gk208_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -171,18 +176,8 @@ gk208_gr = { } }; -struct nvkm_oclass * -gk208_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x08), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk104_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk104_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gk208_gr, - .mmio = gk208_gr_pack_mmio, - .fecs.ucode = &gk208_gr_fecs_ucode, - .gpccs.ucode = &gk208_gr_gpccs_ucode, - .ppc_nr = 1, -}.base; +int +gk208_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gk208_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c index a8100c4f5785d..b8758d3b8b51b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c @@ -19,7 +19,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "gk20a.h" +#include "gf100.h" #include "ctxgf100.h" #include @@ -146,69 +146,6 @@ gk20a_gr_av_to_method(struct gf100_gr_fuc *fuc) return pack; } -int -gk20a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - int err; - struct gf100_gr *gr; - struct gf100_gr_fuc fuc; - - err = gf100_gr_ctor(parent, engine, oclass, data, size, pobject); - if (err) - return err; - - gr = (void *)*pobject; - - err = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc); - if (err) - return err; - gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc); - gf100_gr_dtor_fw(&fuc); - if (IS_ERR(gr->fuc_sw_nonctx)) - return PTR_ERR(gr->fuc_sw_nonctx); - - err = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc); - if (err) - return err; - gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc); - gf100_gr_dtor_fw(&fuc); - if (IS_ERR(gr->fuc_sw_ctx)) - return PTR_ERR(gr->fuc_sw_ctx); - - err = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc); - if (err) - return err; - gr->fuc_bundle = gk20a_gr_av_to_init(&fuc); - gf100_gr_dtor_fw(&fuc); - if (IS_ERR(gr->fuc_bundle)) - return PTR_ERR(gr->fuc_bundle); - - err = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc); - if (err) - return err; - gr->fuc_method = gk20a_gr_av_to_method(&fuc); - gf100_gr_dtor_fw(&fuc); - if (IS_ERR(gr->fuc_method)) - return PTR_ERR(gr->fuc_method); - - return 0; -} - -void -gk20a_gr_dtor(struct nvkm_object *object) -{ - struct gf100_gr *gr = (void *)object; - - gk20a_gr_init_dtor(gr->fuc_method); - gk20a_gr_init_dtor(gr->fuc_bundle); - gk20a_gr_init_dtor(gr->fuc_sw_ctx); - gk20a_gr_init_dtor(gr->fuc_sw_nonctx); - - gf100_gr_dtor(object); -} - static int gk20a_gr_wait_mem_scrubbing(struct gf100_gr *gr) { @@ -243,10 +180,8 @@ gk20a_gr_set_hww_esr_report_mask(struct gf100_gr *gr) } int -gk20a_gr_init(struct nvkm_object *object) +gk20a_gr_init(struct gf100_gr *gr) { - struct gk20a_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr *gr = (void *)object; struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; @@ -254,10 +189,6 @@ gk20a_gr_init(struct nvkm_object *object) int gpc, tpc; int ret, i; - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; - /* Clear SCC RAM */ nvkm_wr32(device, 0x40802c, 0x1); @@ -275,8 +206,8 @@ gk20a_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x100cc8, nvkm_memory_addr(gr->unk4188b4) >> 8); nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8); - if (oclass->init_gpc_mmu) - oclass->init_gpc_mmu(gr); + if (gr->func->init_gpc_mmu) + gr->func->init_gpc_mmu(gr); /* Set the PE as stream master */ nvkm_mask(device, 0x503018, 0x1, 0x1); @@ -322,8 +253,8 @@ gk20a_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x404000, 0xc0000000); nvkm_wr32(device, 0x404600, 0xc0000000); - if (oclass->set_hww_esr_report_mask) - oclass->set_hww_esr_report_mask(gr); + if (gr->func->set_hww_esr_report_mask) + gr->func->set_hww_esr_report_mask(gr); /* Enable TPC exceptions per GPC */ nvkm_wr32(device, 0x419d0c, 0x2); @@ -342,8 +273,72 @@ gk20a_gr_init(struct nvkm_object *object) return gf100_gr_init_ctxctl(gr); } +void +gk20a_gr_dtor(struct gf100_gr *gr) +{ + gk20a_gr_init_dtor(gr->fuc_method); + gk20a_gr_init_dtor(gr->fuc_bundle); + gk20a_gr_init_dtor(gr->fuc_sw_ctx); + gk20a_gr_init_dtor(gr->fuc_sw_nonctx); +} + +int +gk20a_gr_new_(const struct gf100_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct gf100_gr_fuc fuc; + struct gf100_gr *gr; + int ret; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + + ret = gf100_gr_ctor(func, device, index, gr); + if (ret) + return ret; + + ret = gf100_gr_ctor_fw(gr, "sw_nonctx", &fuc); + if (ret) + return ret; + gr->fuc_sw_nonctx = gk20a_gr_av_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_sw_nonctx)) + return PTR_ERR(gr->fuc_sw_nonctx); + + ret = gf100_gr_ctor_fw(gr, "sw_ctx", &fuc); + if (ret) + return ret; + gr->fuc_sw_ctx = gk20a_gr_aiv_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_sw_ctx)) + return PTR_ERR(gr->fuc_sw_ctx); + + ret = gf100_gr_ctor_fw(gr, "sw_bundle_init", &fuc); + if (ret) + return ret; + gr->fuc_bundle = gk20a_gr_av_to_init(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_bundle)) + return PTR_ERR(gr->fuc_bundle); + + ret = gf100_gr_ctor_fw(gr, "sw_method_init", &fuc); + if (ret) + return ret; + gr->fuc_method = gk20a_gr_av_to_method(&fuc); + gf100_gr_dtor_fw(&fuc); + if (IS_ERR(gr->fuc_method)) + return PTR_ERR(gr->fuc_method); + + return 0; +} + static const struct gf100_gr_func gk20a_gr = { + .dtor = gk20a_gr_dtor, + .init = gk20a_gr_init, + .set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask, + .ppc_nr = 1, .grctx = &gk20a_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -354,18 +349,8 @@ gk20a_gr = { } }; -struct nvkm_oclass * -gk20a_gr_oclass = &(struct gk20a_gr_oclass) { - .gf100 = { - .base.handle = NV_ENGINE(GR, 0xea), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_gr_ctor, - .dtor = gk20a_gr_dtor, - .init = gk20a_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gk20a_gr, - .ppc_nr = 1, - }, - .set_hww_esr_report_mask = gk20a_gr_set_hww_esr_report_mask, -}.gf100.base; +int +gk20a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gk20a_gr_new_(&gk20a_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c index b3036cb610804..56e960212e5df 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c @@ -308,20 +308,14 @@ gm107_gr_init_bios(struct gf100_gr *gr) } int -gm107_gr_init(struct nvkm_object *object) +gm107_gr_init(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr *gr = (void *)object; struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); u32 data[TPC_MAX / 8] = {}; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; - int ret, i; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; + int i; nvkm_wr32(device, GPC_BCAST(0x0880), 0x00000000); nvkm_wr32(device, GPC_BCAST(0x0890), 0x00000000); @@ -329,7 +323,7 @@ gm107_gr_init(struct nvkm_object *object) nvkm_wr32(device, GPC_BCAST(0x08b4), nvkm_memory_addr(gr->unk4188b4) >> 8); nvkm_wr32(device, GPC_BCAST(0x08b8), nvkm_memory_addr(gr->unk4188b8) >> 8); - gf100_gr_mmio(gr, oclass->mmio); + gf100_gr_mmio(gr, gr->func->mmio); gm107_gr_init_bios(gr); @@ -443,6 +437,11 @@ gm107_gr_gpccs_ucode = { static const struct gf100_gr_func gm107_gr = { + .init = gm107_gr_init, + .mmio = gm107_gr_pack_mmio, + .fecs.ucode = &gm107_gr_fecs_ucode, + .gpccs.ucode = &gm107_gr_gpccs_ucode, + .ppc_nr = 2, .grctx = &gm107_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -453,18 +452,8 @@ gm107_gr = { } }; -struct nvkm_oclass * -gm107_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x07), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gm107_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gm107_gr, - .mmio = gm107_gr_pack_mmio, - .fecs.ucode = &gm107_gr_fecs_ucode, - .gpccs.ucode = &gm107_gr_gpccs_ucode, - .ppc_nr = 2, -}.base; +int +gm107_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gm107_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c index ff41232a8a536..90381dde451aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm204.c @@ -236,21 +236,14 @@ gm204_gr_init_ctxctl(struct gf100_gr *gr) } int -gm204_gr_init(struct nvkm_object *object) +gm204_gr_init(struct gf100_gr *gr) { - struct gf100_gr_oclass *oclass = (void *)object->oclass; - struct gf100_gr *gr = (void *)object; struct nvkm_device *device = gr->base.engine.subdev.device; const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, gr->tpc_total); - u32 data[TPC_MAX / 8] = {}; + u32 data[TPC_MAX / 8] = {}, tmp; u8 tpcnr[GPC_MAX]; int gpc, tpc, ppc, rop; - int ret, i; - u32 tmp; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; + int i; tmp = nvkm_rd32(device, 0x100c80); /*XXX: mask? */ nvkm_wr32(device, 0x418880, 0x00001000 | (tmp & 0x00000fff)); @@ -265,7 +258,7 @@ gm204_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x100ccc, nvkm_memory_addr(gr->unk4188b8) >> 8); nvkm_mask(device, 0x100cc4, 0x00040000, 0x00040000); - gf100_gr_mmio(gr, oclass->mmio); + gf100_gr_mmio(gr, gr->func->mmio); gm107_gr_init_bios(gr); @@ -360,6 +353,9 @@ gm204_gr_init(struct nvkm_object *object) static const struct gf100_gr_func gm204_gr = { + .init = gm204_gr_init, + .mmio = gm204_gr_pack_mmio, + .ppc_nr = 2, .grctx = &gm204_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -370,16 +366,8 @@ gm204_gr = { } }; -struct nvkm_oclass * -gm204_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x24), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gm204_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gm204_gr, - .mmio = gm204_gr_pack_mmio, - .ppc_nr = 2, -}.base; +int +gm204_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gm204_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c index 4350b08f8dd22..341dc560acbbf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm206.c @@ -28,6 +28,9 @@ static const struct gf100_gr_func gm206_gr = { + .init = gm204_gr_init, + .mmio = gm204_gr_pack_mmio, + .ppc_nr = 2, .grctx = &gm206_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -38,16 +41,8 @@ gm206_gr = { } }; -struct nvkm_oclass * -gm206_gr_oclass = &(struct gf100_gr_oclass) { - .base.handle = NV_ENGINE(GR, 0x26), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gm204_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gm206_gr, - .mmio = gm204_gr_pack_mmio, - .ppc_nr = 2, -}.base; +int +gm206_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gf100_gr_new_(&gm206_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c index 7a663654543bd..65b6e3d1e90dc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm20b.c @@ -19,7 +19,7 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "gk20a.h" +#include "gf100.h" #include "ctxgf100.h" #include @@ -61,6 +61,11 @@ gm20b_gr_set_hww_esr_report_mask(struct gf100_gr *gr) static const struct gf100_gr_func gm20b_gr = { + .dtor = gk20a_gr_dtor, + .init = gk20a_gr_init, + .init_gpc_mmu = gm20b_gr_init_gpc_mmu, + .set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask, + .ppc_nr = 1, .grctx = &gm20b_grctx, .sclass = { { -1, -1, FERMI_TWOD_A }, @@ -71,19 +76,8 @@ gm20b_gr = { } }; -struct nvkm_oclass * -gm20b_gr_oclass = &(struct gk20a_gr_oclass) { - .gf100 = { - .base.handle = NV_ENGINE(GR, 0x2b), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk20a_gr_ctor, - .dtor = gf100_gr_dtor, - .init = gk20a_gr_init, - .fini = _nvkm_gr_fini, - }, - .func = &gm20b_gr, - .ppc_nr = 1, - }, - .init_gpc_mmu = gm20b_gr_init_gpc_mmu, - .set_hww_esr_report_mask = gm20b_gr_set_hww_esr_report_mask, -}.gf100.base; +int +gm20b_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return gk20a_gr_new_(&gm20b_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c new file mode 100644 index 0000000000000..2e68919f00b20 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt200.c @@ -0,0 +1,47 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv50.h" + +static const struct nvkm_gr_func +gt200_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8397, &nv50_gr_object }, + {} + } +}; + +int +gt200_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(>200_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c new file mode 100644 index 0000000000000..2bf7aac360cc5 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gt215.c @@ -0,0 +1,48 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv50.h" + +static const struct nvkm_gr_func +gt215_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8597, &nv50_gr_object }, + { -1, -1, 0x85c0, &nv50_gr_object }, + {} + } +}; + +int +gt215_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(>215_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c similarity index 50% rename from drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h rename to drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c index 411099d222d43..95d5219faf936 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp79.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, NVIDIA CORPORATION. All rights reserved. + * Copyright 2012 Red Hat Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -14,22 +14,33 @@ * 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. + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs */ +#include "nv50.h" -#ifndef __GK20A_GR_H__ -#define __GK20A_GR_H__ - -#include "gf100.h" - -struct gk20a_gr_oclass { - struct gf100_gr_oclass gf100; - - void (*init_gpc_mmu)(struct gf100_gr *); - void (*set_hww_esr_report_mask)(struct gf100_gr *); +static const struct nvkm_gr_func +mcp79_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x8397, &nv50_gr_object }, + {} + } }; -#endif +int +mcp79_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&mcp79_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c new file mode 100644 index 0000000000000..027b58e5976b3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/mcp89.c @@ -0,0 +1,48 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv50.h" + +static const struct nvkm_gr_func +mcp89_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .tlb_flush = g84_gr_tlb_flush, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + { -1, -1, 0x85c0, &nv50_gr_object }, + { -1, -1, 0x8697, &nv50_gr_object }, + {} + } +}; + +int +mcp89_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&mcp89_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index a5a4bdd9863e7..7b4317ab8f02f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1269,11 +1269,11 @@ nv04_gr_nsource[] = { }; static void -nv04_gr_intr(struct nvkm_subdev *subdev) +nv04_gr_intr(struct nvkm_gr *base) { - struct nv04_gr *gr = (void *)subdev; - struct nv04_gr_chan *chan = NULL; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nv04_gr *gr = nv04_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); @@ -1286,6 +1286,7 @@ nv04_gr_intr(struct nvkm_subdev *subdev) u32 inst = (nvkm_rd32(device, 0x40016c) & 0xffff) << 4; u32 show = stat; char msg[128], src[128], sta[128]; + struct nv04_gr_chan *chan; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); @@ -1323,8 +1324,47 @@ nv04_gr_intr(struct nvkm_subdev *subdev) spin_unlock_irqrestore(&gr->lock, flags); } +static int +nv04_gr_init(struct nvkm_gr *base) +{ + struct nv04_gr *gr = nv04_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + + /* Enable PGRAPH interrupts */ + nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF); + nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); + + nvkm_wr32(device, NV04_PGRAPH_VALID1, 0); + nvkm_wr32(device, NV04_PGRAPH_VALID2, 0); + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF); + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000); + /*1231C000 blob, 001 haiku*/ + /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100); + /*0x72111100 blob , 01 haiku*/ + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071); + /*haiku same*/ + + /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ + nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); + /*haiku and blob 10d4*/ + + nvkm_wr32(device, NV04_PGRAPH_STATE , 0xFFFFFFFF); + nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL , 0x10000100); + nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); + + /* These don't belong here, they're part of a per-channel context */ + nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); + nvkm_wr32(device, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); + return 0; +} + static const struct nvkm_gr_func nv04_gr = { + .init = nv04_gr_init, + .intr = nv04_gr_intr, .chan_new = nv04_gr_chan_new, .sclass = { { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ @@ -1372,76 +1412,16 @@ nv04_gr = { } }; -static int -nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv04_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) { struct nv04_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - gr->base.func = &nv04_gr; - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv04_gr_intr; + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; spin_lock_init(&gr->lock); - return 0; -} + *pgr = &gr->base; -static int -nv04_gr_init(struct nvkm_object *object) -{ - struct nvkm_engine *engine = nv_engine(object); - struct nv04_gr *gr = (void *)engine; - struct nvkm_device *device = gr->base.engine.subdev.device; - int ret; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; - - /* Enable PGRAPH interrupts */ - nvkm_wr32(device, NV03_PGRAPH_INTR, 0xFFFFFFFF); - nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); - - nvkm_wr32(device, NV04_PGRAPH_VALID1, 0); - nvkm_wr32(device, NV04_PGRAPH_VALID2, 0); - /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x000001FF); - nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/ - nvkm_wr32(device, NV04_PGRAPH_DEBUG_0, 0x1231c000); - /*1231C000 blob, 001 haiku*/ - /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/ - nvkm_wr32(device, NV04_PGRAPH_DEBUG_1, 0x72111100); - /*0x72111100 blob , 01 haiku*/ - /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/ - nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x11d5f071); - /*haiku same*/ - - /*nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/ - nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31); - /*haiku and blob 10d4*/ - - nvkm_wr32(device, NV04_PGRAPH_STATE , 0xFFFFFFFF); - nvkm_wr32(device, NV04_PGRAPH_CTX_CONTROL , 0x10000100); - nvkm_mask(device, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000); - - /* These don't belong here, they're part of a per-channel context */ - nvkm_wr32(device, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000); - nvkm_wr32(device, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF); - return 0; + return nvkm_gr_ctor(&nv04_gr, device, index, 0x00001000, + true, &gr->base); } - -struct nvkm_oclass -nv04_gr_oclass = { - .handle = NV_ENGINE(GR, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_gr_ctor, - .dtor = _nvkm_gr_dtor, - .init = nv04_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c index d5e44a7332ebb..9436ada62cbab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c @@ -21,7 +21,7 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ -#include "priv.h" +#include "nv10.h" #include "regs.h" #include @@ -890,8 +890,7 @@ nv10_gr_load_context(struct nv10_gr_chan *chan, int chid) for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) nvkm_wr32(device, nv10_gr_ctx_regs[i], chan->nv10[i]); - if (nv_device(gr)->card_type >= NV_11 && - nv_device(gr)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) nvkm_wr32(device, nv17_gr_ctx_regs[i], chan->nv17[i]); } @@ -917,8 +916,7 @@ nv10_gr_unload_context(struct nv10_gr_chan *chan) for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) chan->nv10[i] = nvkm_rd32(device, nv10_gr_ctx_regs[i]); - if (nv_device(gr)->card_type >= NV_11 && - nv_device(gr)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) chan->nv17[i] = nvkm_rd32(device, nv17_gr_ctx_regs[i]); } @@ -1000,7 +998,7 @@ nv10_gr_chan = { chan->nv17[offset] = val; \ } while (0) -static int +int nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { @@ -1047,13 +1045,12 @@ nv10_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, * PGRAPH engine/subdev functions ******************************************************************************/ -static void -nv10_gr_tile_prog(struct nvkm_engine *engine, int i) +void +nv10_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) { - struct nv10_gr *gr = (void *)engine; + struct nv10_gr *gr = nv10_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; struct nvkm_fifo *fifo = device->fifo; - struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; nvkm_fifo_pause(fifo, &flags); @@ -1080,12 +1077,12 @@ const struct nvkm_bitfield nv10_gr_nstatus[] = { {} }; -static void -nv10_gr_intr(struct nvkm_subdev *subdev) +void +nv10_gr_intr(struct nvkm_gr *base) { - struct nv10_gr *gr = (void *)subdev; - struct nv10_gr_chan *chan = NULL; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nv10_gr *gr = nv10_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); @@ -1097,6 +1094,7 @@ nv10_gr_intr(struct nvkm_subdev *subdev) u32 class = nvkm_rd32(device, 0x400160 + subc * 4) & 0xfff; u32 show = stat; char msg[128], src[128], sta[128]; + struct nv10_gr_chan *chan; unsigned long flags; spin_lock_irqsave(&gr->lock, flags); @@ -1134,134 +1132,11 @@ nv10_gr_intr(struct nvkm_subdev *subdev) spin_unlock_irqrestore(&gr->lock, flags); } -static const struct nvkm_gr_func -nv10_gr = { - .chan_new = nv10_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv04_gr_object }, /* null */ - { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ - { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ - { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ - { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ - { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ - { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ - { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ - { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ - { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ - { -1, -1, 0x0056, &nv04_gr_object }, /* celcius */ - {} - } -}; - -static const struct nvkm_gr_func -nv15_gr = { - .chan_new = nv10_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv04_gr_object }, /* null */ - { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ - { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ - { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ - { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ - { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ - { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ - { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ - { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ - { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ - { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ - {} - } -}; - - -static const struct nvkm_gr_func -nv17_gr = { - .chan_new = nv10_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv04_gr_object }, /* null */ - { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ - { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ - { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ - { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ - { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ - { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ - { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ - { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ - { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ - { -1, -1, 0x0099, &nv04_gr_object }, - {} - } -}; - -static int -nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv10_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv10_gr_intr; - - if (nv_device(gr)->chipset <= 0x10) - gr->base.func = &nv10_gr; - else - if (nv_device(gr)->chipset < 0x17 || - nv_device(gr)->card_type < NV_11) - gr->base.func = &nv15_gr; - else - gr->base.func = &nv17_gr; - - nv_engine(gr)->tile_prog = nv10_gr_tile_prog; - spin_lock_init(&gr->lock); - return 0; -} - -static void -nv10_gr_dtor(struct nvkm_object *object) +int +nv10_gr_init(struct nvkm_gr *base) { - struct nv10_gr *gr = (void *)object; - nvkm_gr_destroy(&gr->base); -} - -static int -nv10_gr_init(struct nvkm_object *object) -{ - struct nvkm_engine *engine = nv_engine(object); - struct nv10_gr *gr = (void *)engine; + struct nv10_gr *gr = nv10_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_fb *fb = device->fb; - int ret, i; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; nvkm_wr32(device, NV03_PGRAPH_INTR , 0xFFFFFFFF); nvkm_wr32(device, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF); @@ -1273,8 +1148,7 @@ nv10_gr_init(struct nvkm_object *object) nvkm_wr32(device, NV04_PGRAPH_DEBUG_2, 0x25f92ad9); nvkm_wr32(device, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31)); - if (nv_device(gr)->card_type >= NV_11 && - nv_device(gr)->chipset >= 0x17) { + if (device->card_type >= NV_11 && device->chipset >= 0x17) { nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x1f000000); nvkm_wr32(device, 0x400a10, 0x03ff3fb6); nvkm_wr32(device, 0x400838, 0x002f8684); @@ -1284,10 +1158,6 @@ nv10_gr_init(struct nvkm_object *object) nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000); } - /* Turn all the tiling regions off. */ - for (i = 0; i < fb->tile.regions; i++) - engine->tile_prog(engine, i); - nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000); nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000); nvkm_wr32(device, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000); @@ -1301,20 +1171,51 @@ nv10_gr_init(struct nvkm_object *object) return 0; } -static int -nv10_gr_fini(struct nvkm_object *object, bool suspend) +int +nv10_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) { - struct nv10_gr *gr = (void *)object; - return nvkm_gr_fini(&gr->base, suspend); + struct nv10_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + spin_lock_init(&gr->lock); + *pgr = &gr->base; + + return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base); } -struct nvkm_oclass -nv10_gr_oclass = { - .handle = NV_ENGINE(GR, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_gr_ctor, - .dtor = nv10_gr_dtor, - .init = nv10_gr_init, - .fini = nv10_gr_fini, - }, +static const struct nvkm_gr_func +nv10_gr = { + .init = nv10_gr_init, + .intr = nv10_gr_intr, + .tile = nv10_gr_tile, + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0056, &nv04_gr_object }, /* celcius */ + {} + } }; + +int +nv10_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv10_gr_new_(&nv10_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h new file mode 100644 index 0000000000000..d7c3d86cc99df --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.h @@ -0,0 +1,13 @@ +#ifndef __NV10_GR_H__ +#define __NV10_GR_H__ +#include "priv.h" + +int nv10_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index, + struct nvkm_gr **); +int nv10_gr_init(struct nvkm_gr *); +void nv10_gr_intr(struct nvkm_gr *); +void nv10_gr_tile(struct nvkm_gr *, int, struct nvkm_fb_tile *); + +int nv10_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c new file mode 100644 index 0000000000000..3e2c6856b4c4e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv15.c @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Matthieu CASTET + * All Rights Reserved. + * + * 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 + * paragr) 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + */ +#include "nv10.h" + +static const struct nvkm_gr_func +nv15_gr = { + .init = nv10_gr_init, + .intr = nv10_gr_intr, + .tile = nv10_gr_tile, + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + {} + } +}; + +int +nv15_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv10_gr_new_(&nv15_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c new file mode 100644 index 0000000000000..12437d085a738 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv17.c @@ -0,0 +1,59 @@ +/* + * Copyright 2007 Matthieu CASTET + * All Rights Reserved. + * + * 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 + * paragr) 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 + * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + */ +#include "nv10.h" + +static const struct nvkm_gr_func +nv17_gr = { + .init = nv10_gr_init, + .intr = nv10_gr_intr, + .tile = nv10_gr_tile, + .chan_new = nv10_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* pattern */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0052, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x005f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* blit */ + { -1, -1, 0x0093, &nv04_gr_object }, /* surf3d */ + { -1, -1, 0x0094, &nv04_gr_object }, /* ttri */ + { -1, -1, 0x0095, &nv04_gr_object }, /* mtri */ + { -1, -1, 0x0099, &nv04_gr_object }, + {} + } +}; + +int +nv17_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv10_gr_new_(&nv17_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index ce4f9925ea9b8..32ea28a71a412 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -145,12 +145,11 @@ nv20_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, ******************************************************************************/ void -nv20_gr_tile_prog(struct nvkm_engine *engine, int i) +nv20_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) { - struct nv20_gr *gr = (void *)engine; + struct nv20_gr *gr = nv20_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; struct nvkm_fifo *fifo = device->fifo; - struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; nvkm_fifo_pause(fifo, &flags); @@ -167,7 +166,7 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i); nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->addr); - if (nv_device(engine)->chipset != 0x34) { + if (device->chipset != 0x34) { nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp); nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i); nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, tile->zcomp); @@ -177,10 +176,11 @@ nv20_gr_tile_prog(struct nvkm_engine *engine, int i) } void -nv20_gr_intr(struct nvkm_subdev *subdev) +nv20_gr_intr(struct nvkm_gr *base) { - struct nv20_gr *gr = (void *)subdev; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nv20_gr *gr = nv20_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fifo_chan *chan; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); @@ -215,82 +215,27 @@ nv20_gr_intr(struct nvkm_subdev *subdev) nvkm_fifo_chan_put(device->fifo, flags, &chan); } -static const struct nvkm_gr_func -nv20_gr = { - .chan_new = nv20_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv04_gr_object }, /* null */ - { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ - { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ - { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ - { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ - { -1, -1, 0x0097, &nv04_gr_object }, /* kelvin */ - { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ - { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ - {} - } -}; - -static int -nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = (void *)parent; - struct nv20_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->base.func = &nv20_gr; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, - &gr->ctxtab); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->tile_prog = nv20_gr_tile_prog; - return 0; -} - -void -nv20_gr_dtor(struct nvkm_object *object) +int +nv20_gr_oneinit(struct nvkm_gr *base) { - struct nv20_gr *gr = (void *)object; - nvkm_memory_del(&gr->ctxtab); - nvkm_gr_destroy(&gr->base); + struct nv20_gr *gr = nv20_gr(base); + return nvkm_memory_new(gr->base.engine.subdev.device, + NVKM_MEM_TARGET_INST, 32 * 4, 16, + true, &gr->ctxtab); } int -nv20_gr_init(struct nvkm_object *object) +nv20_gr_init(struct nvkm_gr *base) { - struct nvkm_engine *engine = nv_engine(object); - struct nv20_gr *gr = (void *)engine; + struct nv20_gr *gr = nv20_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_fb *fb = device->fb; u32 tmp, vramsz; - int ret, i; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; + int i; nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, nvkm_memory_addr(gr->ctxtab) >> 4); - if (nv_device(gr)->chipset == 0x20) { + if (device->chipset == 0x20) { nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x003d0000); for (i = 0; i < 15; i++) nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, 0x00000000); @@ -318,7 +263,7 @@ nv20_gr_init(struct nvkm_object *object) nvkm_wr32(device, NV10_PGRAPH_DEBUG_4, 0x00000000); nvkm_wr32(device, 0x40009C , 0x00000040); - if (nv_device(gr)->chipset >= 0x25) { + if (device->chipset >= 0x25) { nvkm_wr32(device, 0x400890, 0x00a8cfff); nvkm_wr32(device, 0x400610, 0x304B1FB6); nvkm_wr32(device, 0x400B80, 0x1cbd3883); @@ -338,10 +283,6 @@ nv20_gr_init(struct nvkm_object *object) nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00000030); } - /* Turn all the tiling regions off. */ - for (i = 0; i < fb->tile.regions; i++) - engine->tile_prog(engine, i); - nvkm_wr32(device, 0x4009a0, nvkm_rd32(device, 0x100324)); nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA000C); nvkm_wr32(device, NV10_PGRAPH_RDI_DATA, nvkm_rd32(device, 0x100324)); @@ -355,7 +296,7 @@ nv20_gr_init(struct nvkm_object *object) nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = nv_device_resource_len(nv_device(gr), 1) - 1; + vramsz = nv_device_resource_len(device, 1) - 1; nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); @@ -378,13 +319,57 @@ nv20_gr_init(struct nvkm_object *object) return 0; } -struct nvkm_oclass -nv20_gr_oclass = { - .handle = NV_ENGINE(GR, 0x20), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv20_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv20_gr_init, - .fini = _nvkm_gr_fini, - }, +void * +nv20_gr_dtor(struct nvkm_gr *base) +{ + struct nv20_gr *gr = nv20_gr(base); + nvkm_memory_del(&gr->ctxtab); + return gr; +} + +int +nv20_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct nv20_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + + return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base); +} + +static const struct nvkm_gr_func +nv20_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv20_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv20_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x0096, &nv04_gr_object }, /* celcius */ + { -1, -1, 0x0097, &nv04_gr_object }, /* kelvin */ + { -1, -1, 0x009e, &nv04_gr_object }, /* swzsurf */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + {} + } }; + +int +nv20_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv20_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h index 1ae4f2acc612a..cdf4501e3798d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h @@ -8,6 +8,16 @@ struct nv20_gr { struct nvkm_memory *ctxtab; }; +int nv20_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, + int, struct nvkm_gr **); +void *nv20_gr_dtor(struct nvkm_gr *); +int nv20_gr_oneinit(struct nvkm_gr *); +int nv20_gr_init(struct nvkm_gr *); +void nv20_gr_intr(struct nvkm_gr *); +void nv20_gr_tile(struct nvkm_gr *, int, struct nvkm_fb_tile *); + +int nv30_gr_init(struct nvkm_gr *); + #define nv20_gr_chan(p) container_of((p), struct nv20_gr_chan, object) struct nv20_gr_chan { @@ -18,14 +28,6 @@ struct nv20_gr_chan { }; void *nv20_gr_chan_dtor(struct nvkm_object *); -int nv20_gr_chan_init(struct nvkm_object *); -int nv20_gr_chan_fini(struct nvkm_object *, bool); - -void nv20_gr_tile_prog(struct nvkm_engine *, int); -void nv20_gr_intr(struct nvkm_subdev *); - -void nv20_gr_dtor(struct nvkm_object *); -int nv20_gr_init(struct nvkm_object *); - -int nv30_gr_init(struct nvkm_object *); +int nv20_gr_chan_init(struct nvkm_object *); +int nv20_gr_chan_fini(struct nvkm_object *, bool); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c index cc56ca9505f4a..6c4a00819b4bd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c @@ -101,6 +101,11 @@ nv25_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, static const struct nvkm_gr_func nv25_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv20_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, .chan_new = nv25_gr_chan_new, .sclass = { { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ @@ -122,40 +127,8 @@ nv25_gr = { } }; -static int -nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv25_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) { - struct nvkm_device *device = (void *)parent; - struct nv20_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->base.func = &nv25_gr; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, - &gr->ctxtab); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->tile_prog = nv20_gr_tile_prog; - return 0; + return nv20_gr_new_(&nv25_gr, device, index, pgr); } - -struct nvkm_oclass -nv25_gr_oclass = { - .handle = NV_ENGINE(GR, 0x25), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv25_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv20_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c index 4e4cd93d686d3..3cad26dbc2b1a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c @@ -92,6 +92,11 @@ nv2a_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, static const struct nvkm_gr_func nv2a_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv20_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, .chan_new = nv2a_gr_chan_new, .sclass = { { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ @@ -113,40 +118,8 @@ nv2a_gr = { } }; -static int -nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv2a_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) { - struct nvkm_device *device = (void *)parent; - struct nv20_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->base.func = &nv2a_gr; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, - &gr->ctxtab); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->tile_prog = nv20_gr_tile_prog; - return 0; + return nv20_gr_new_(&nv2a_gr, device, index, pgr); } - -struct nvkm_oclass -nv2a_gr_oclass = { - .handle = NV_ENGINE(GR, 0x2a), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv2a_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv20_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c index ea46b16c31e69..69de8c6259feb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c @@ -99,70 +99,11 @@ nv30_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, * PGRAPH engine/subdev functions ******************************************************************************/ -static const struct nvkm_gr_func -nv30_gr = { - .chan_new = nv30_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv04_gr_object }, /* null */ - { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ - { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ - { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ - { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ - { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ - { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ - { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ - { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ - { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */ - {} - } -}; - -static int -nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = (void *)parent; - struct nv20_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->base.func = &nv30_gr; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, - &gr->ctxtab); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->tile_prog = nv20_gr_tile_prog; - return 0; -} - int -nv30_gr_init(struct nvkm_object *object) +nv30_gr_init(struct nvkm_gr *base) { - struct nvkm_engine *engine = nv_engine(object); - struct nv20_gr *gr = (void *)engine; + struct nv20_gr *gr = nv20_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_fb *fb = device->fb; - int ret, i; - - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; nvkm_wr32(device, NV20_PGRAPH_CHANNEL_CTX_TABLE, nvkm_memory_addr(gr->ctxtab) >> 4); @@ -189,7 +130,7 @@ nv30_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x400ba4, 0x00231f3f); nvkm_wr32(device, 0x4008a4, 0x40000020); - if (nv_device(gr)->chipset == 0x34) { + if (device->chipset == 0x34) { nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0004); nvkm_wr32(device, NV10_PGRAPH_RDI_DATA , 0x00200201); nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0008); @@ -202,10 +143,6 @@ nv30_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x4000c0, 0x00000016); - /* Turn all the tiling regions off. */ - for (i = 0; i < fb->tile.regions; i++) - engine->tile_prog(engine, i); - nvkm_wr32(device, NV10_PGRAPH_CTX_CONTROL, 0x10000100); nvkm_wr32(device, NV10_PGRAPH_STATE , 0xFFFFFFFF); nvkm_wr32(device, 0x0040075c , 0x00000001); @@ -214,22 +151,48 @@ nv30_gr_init(struct nvkm_object *object) /* vramsz = pci_resource_len(gr->dev->pdev, 1) - 1; */ nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); - if (nv_device(gr)->chipset != 0x34) { + if (device->chipset != 0x34) { nvkm_wr32(device, 0x400750, 0x00EA0000); nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100200)); nvkm_wr32(device, 0x400750, 0x00EA0004); nvkm_wr32(device, 0x400754, nvkm_rd32(device, 0x100204)); } + return 0; } -struct nvkm_oclass -nv30_gr_oclass = { - .handle = NV_ENGINE(GR, 0x30), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv30_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv30_gr_init, - .fini = _nvkm_gr_fini, - }, +static const struct nvkm_gr_func +nv30_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv30_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, + .chan_new = nv30_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv04_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv04_gr_object }, /* null */ + { -1, -1, 0x0039, &nv04_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv04_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv04_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv04_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv04_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv04_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv04_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv04_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv04_gr_object }, /* imageblit */ + { -1, -1, 0x0362, &nv04_gr_object }, /* surf2d (nv30) */ + { -1, -1, 0x0389, &nv04_gr_object }, /* sifm (nv30) */ + { -1, -1, 0x038a, &nv04_gr_object }, /* ifc (nv30) */ + { -1, -1, 0x039e, &nv04_gr_object }, /* swzsurf (nv30) */ + { -1, -1, 0x0397, &nv04_gr_object }, /* rankine */ + {} + } }; + +int +nv30_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv20_gr_new_(&nv30_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c index 0667e9d14b42f..2207dac23981a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c @@ -100,6 +100,11 @@ nv34_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, static const struct nvkm_gr_func nv34_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv30_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, .chan_new = nv34_gr_chan_new, .sclass = { { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ @@ -123,40 +128,8 @@ nv34_gr = { } }; -static int -nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv34_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) { - struct nvkm_device *device = (void *)parent; - struct nv20_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->base.func = &nv34_gr; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, - &gr->ctxtab); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->tile_prog = nv20_gr_tile_prog; - return 0; + return nv20_gr_new_(&nv34_gr, device, index, pgr); } - -struct nvkm_oclass -nv34_gr_oclass = { - .handle = NV_ENGINE(GR, 0x34), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv34_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv30_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c index 745d0e133d9a0..740df0f52c388 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c @@ -100,6 +100,11 @@ nv35_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, static const struct nvkm_gr_func nv35_gr = { + .dtor = nv20_gr_dtor, + .oneinit = nv20_gr_oneinit, + .init = nv30_gr_init, + .intr = nv20_gr_intr, + .tile = nv20_gr_tile, .chan_new = nv35_gr_chan_new, .sclass = { { -1, -1, 0x0012, &nv04_gr_object }, /* beta1 */ @@ -123,40 +128,8 @@ nv35_gr = { } }; -static int -nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv35_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) { - struct nvkm_device *device = (void *)parent; - struct nv20_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - gr->base.func = &nv35_gr; - - ret = nvkm_memory_new(device, NVKM_MEM_TARGET_INST, 32 * 4, 16, true, - &gr->ctxtab); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv20_gr_intr; - nv_engine(gr)->tile_prog = nv20_gr_tile_prog; - return 0; + return nv20_gr_new_(&nv35_gr, device, index, pgr); } - -struct nvkm_oclass -nv35_gr_oclass = { - .handle = NV_ENGINE(GR, 0x35), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv35_gr_ctor, - .dtor = nv20_gr_dtor, - .init = nv30_gr_init, - .fini = _nvkm_gr_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index be954500b4d8d..127a36f5859e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -30,7 +30,7 @@ #include #include -static u64 +u64 nv40_gr_units(struct nvkm_gr *gr) { return nvkm_rd32(gr->engine.subdev.device, 0x1540); @@ -61,7 +61,7 @@ nv40_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, return ret; } -static const struct nvkm_object_func +const struct nvkm_object_func nv40_gr_object = { .bind = nv40_gr_object_bind, }; @@ -144,7 +144,7 @@ nv40_gr_chan = { .bind = nv40_gr_chan_bind, }; -static int +int nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { @@ -169,31 +169,29 @@ nv40_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, ******************************************************************************/ static void -nv40_gr_tile_prog(struct nvkm_engine *engine, int i) +nv40_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) { - struct nv40_gr *gr = (void *)engine; + struct nv40_gr *gr = nv40_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; struct nvkm_fifo *fifo = device->fifo; - struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; unsigned long flags; nvkm_fifo_pause(fifo, &flags); nv04_gr_idle(&gr->base); - switch (nv_device(gr)->chipset) { + switch (device->chipset) { case 0x40: case 0x41: case 0x42: case 0x43: case 0x45: - case 0x4e: nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); - switch (nv_device(gr)->chipset) { + switch (device->chipset) { case 0x40: case 0x45: nvkm_wr32(device, NV20_PGRAPH_ZCOMP(i), tile->zcomp); @@ -209,50 +207,33 @@ nv40_gr_tile_prog(struct nvkm_engine *engine, int i) break; } break; - case 0x44: - case 0x4a: - nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); - nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); - nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); - break; - case 0x46: - case 0x4c: case 0x47: case 0x49: case 0x4b: - case 0x63: - case 0x67: - case 0x68: nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch); nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit); nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr); nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); - switch (nv_device(gr)->chipset) { - case 0x47: - case 0x49: - case 0x4b: - nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); - nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); - break; - default: - break; - } + nvkm_wr32(device, NV47_PGRAPH_ZCOMP0(i), tile->zcomp); + nvkm_wr32(device, NV47_PGRAPH_ZCOMP1(i), tile->zcomp); break; default: + WARN_ON(1); break; } nvkm_fifo_start(fifo, &flags); } -static void -nv40_gr_intr(struct nvkm_subdev *subdev) +void +nv40_gr_intr(struct nvkm_gr *base) { - struct nv40_gr *gr = (void *)subdev; + struct nv40_gr *gr = nv40_gr(base); struct nv40_gr_chan *temp, *chan = NULL; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, NV03_PGRAPH_INTR); u32 nsource = nvkm_rd32(device, NV03_PGRAPH_NSOURCE); u32 nstatus = nvkm_rd32(device, NV03_PGRAPH_NSTATUS); @@ -301,98 +282,16 @@ nv40_gr_intr(struct nvkm_subdev *subdev) spin_unlock_irqrestore(&gr->base.engine.lock, flags); } -static const struct nvkm_gr_func -nv40_gr = { - .chan_new = nv40_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv40_gr_object }, /* null */ - { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ - { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ - { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ - { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ - { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ - { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ - { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ - { -1, -1, 0x4097, &nv40_gr_object }, /* curie */ - {} - } -}; - -static const struct nvkm_gr_func -nv44_gr = { - .chan_new = nv40_gr_chan_new, - .sclass = { - { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ - { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ - { -1, -1, 0x0030, &nv40_gr_object }, /* null */ - { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ - { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ - { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ - { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ - { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ - { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ - { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ - { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ - { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ - { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ - { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ - { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ - { -1, -1, 0x4497, &nv40_gr_object }, /* curie */ - {} - } -}; - -static int -nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_device *device = (void *)parent; - struct nv40_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - INIT_LIST_HEAD(&gr->chan); - - nv_subdev(gr)->unit = 0x00001000; - nv_subdev(gr)->intr = nv40_gr_intr; - if (nv44_gr_class(device)) - gr->base.func = &nv44_gr; - else - gr->base.func = &nv40_gr; - nv_engine(gr)->tile_prog = nv40_gr_tile_prog; - - gr->base.units = nv40_gr_units; - return 0; -} - -static int -nv40_gr_init(struct nvkm_object *object) +int +nv40_gr_init(struct nvkm_gr *base) { - struct nvkm_engine *engine = nv_engine(object); - struct nv40_gr *gr = (void *)engine; + struct nv40_gr *gr = nv40_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; - struct nvkm_fb *fb = device->fb; int ret, i, j; u32 vramsz; - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; - /* generate and upload context program */ - ret = nv40_grctx_init(nv_device(gr), &gr->size); + ret = nv40_grctx_init(device, &gr->size); if (ret) return ret; @@ -419,7 +318,7 @@ nv40_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x405000, i); } - if (nv_device(gr)->chipset == 0x40) { + if (device->chipset == 0x40) { nvkm_wr32(device, 0x4009b0, 0x83280fff); nvkm_wr32(device, 0x4009b4, 0x000000a0); } else { @@ -427,7 +326,7 @@ nv40_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x400824, 0x000000a0); } - switch (nv_device(gr)->chipset) { + switch (device->chipset) { case 0x40: case 0x45: nvkm_wr32(device, 0x4009b8, 0x0078e366); @@ -465,7 +364,7 @@ nv40_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x400b3c, 0x00006000); /* Tiling related stuff. */ - switch (nv_device(gr)->chipset) { + switch (device->chipset) { case 0x44: case 0x4a: nvkm_wr32(device, 0x400bc4, 0x1003d888); @@ -485,13 +384,9 @@ nv40_gr_init(struct nvkm_object *object) break; } - /* Turn all the tiling regions off. */ - for (i = 0; i < fb->tile.regions; i++) - engine->tile_prog(engine, i); - /* begin RAM config */ - vramsz = nv_device_resource_len(nv_device(gr), 1) - 1; - switch (nv_device(gr)->chipset) { + vramsz = nv_device_resource_len(device, 1) - 1; + switch (device->chipset) { case 0x40: nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); @@ -503,7 +398,7 @@ nv40_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x400868, vramsz); break; default: - switch (nv_device(gr)->chipset) { + switch (device->chipset) { case 0x41: case 0x42: case 0x43: @@ -531,13 +426,50 @@ nv40_gr_init(struct nvkm_object *object) return 0; } -struct nvkm_oclass -nv40_gr_oclass = { - .handle = NV_ENGINE(GR, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_gr_ctor, - .dtor = _nvkm_gr_dtor, - .init = nv40_gr_init, - .fini = _nvkm_gr_fini, - }, +int +nv40_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct nv40_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + *pgr = &gr->base; + INIT_LIST_HEAD(&gr->chan); + + return nvkm_gr_ctor(func, device, index, 0x00001000, true, &gr->base); +} + +static const struct nvkm_gr_func +nv40_gr = { + .init = nv40_gr_init, + .intr = nv40_gr_intr, + .tile = nv40_gr_tile, + .units = nv40_gr_units, + .chan_new = nv40_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv40_gr_object }, /* null */ + { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ + { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ + { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ + { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ + { -1, -1, 0x4097, &nv40_gr_object }, /* curie */ + {} + } }; + +int +nv40_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv40_gr_new_(&nv40_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h index 42cc409a8df2a..2812ed11f877b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h @@ -9,6 +9,12 @@ struct nv40_gr { struct list_head chan; }; +int nv40_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index, + struct nvkm_gr **); +int nv40_gr_init(struct nvkm_gr *); +void nv40_gr_intr(struct nvkm_gr *); +u64 nv40_gr_units(struct nvkm_gr *); + #define nv40_gr_chan(p) container_of((p), struct nv40_gr_chan, object) struct nv40_gr_chan { @@ -19,6 +25,11 @@ struct nv40_gr_chan { struct list_head head; }; +int nv40_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nvkm_object_func nv40_gr_object; + /* returns 1 if device is one of the nv4x using the 0x4497 object class, * helpful to determine a number of other hardware features */ @@ -28,7 +39,7 @@ nv44_gr_class(struct nvkm_device *device) if ((device->chipset & 0xf0) == 0x60) return 1; - return !(0x0baf & (1 << (device->chipset & 0x0f))); + return !(0x0aaf & (1 << (device->chipset & 0x0f))); } int nv40_grctx_init(struct nvkm_device *, u32 *size); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c new file mode 100644 index 0000000000000..45ff80254eb40 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv44.c @@ -0,0 +1,108 @@ +/* + * Copyright 2012 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "nv40.h" +#include "regs.h" + +#include +#include + +static void +nv44_gr_tile(struct nvkm_gr *base, int i, struct nvkm_fb_tile *tile) +{ + struct nv40_gr *gr = nv40_gr(base); + struct nvkm_device *device = gr->base.engine.subdev.device; + struct nvkm_fifo *fifo = device->fifo; + unsigned long flags; + + nvkm_fifo_pause(fifo, &flags); + nv04_gr_idle(&gr->base); + + switch (device->chipset) { + case 0x44: + case 0x4a: + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); + break; + case 0x46: + case 0x4c: + case 0x63: + case 0x67: + case 0x68: + nvkm_wr32(device, NV47_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV47_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV47_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); + break; + case 0x4e: + nvkm_wr32(device, NV20_PGRAPH_TSIZE(i), tile->pitch); + nvkm_wr32(device, NV20_PGRAPH_TLIMIT(i), tile->limit); + nvkm_wr32(device, NV20_PGRAPH_TILE(i), tile->addr); + nvkm_wr32(device, NV40_PGRAPH_TSIZE1(i), tile->pitch); + nvkm_wr32(device, NV40_PGRAPH_TLIMIT1(i), tile->limit); + nvkm_wr32(device, NV40_PGRAPH_TILE1(i), tile->addr); + break; + default: + WARN_ON(1); + break; + } + + nvkm_fifo_start(fifo, &flags); +} + +static const struct nvkm_gr_func +nv44_gr = { + .init = nv40_gr_init, + .intr = nv40_gr_intr, + .tile = nv44_gr_tile, + .units = nv40_gr_units, + .chan_new = nv40_gr_chan_new, + .sclass = { + { -1, -1, 0x0012, &nv40_gr_object }, /* beta1 */ + { -1, -1, 0x0019, &nv40_gr_object }, /* clip */ + { -1, -1, 0x0030, &nv40_gr_object }, /* null */ + { -1, -1, 0x0039, &nv40_gr_object }, /* m2mf */ + { -1, -1, 0x0043, &nv40_gr_object }, /* rop */ + { -1, -1, 0x0044, &nv40_gr_object }, /* patt */ + { -1, -1, 0x004a, &nv40_gr_object }, /* gdi */ + { -1, -1, 0x0062, &nv40_gr_object }, /* surf2d */ + { -1, -1, 0x0072, &nv40_gr_object }, /* beta4 */ + { -1, -1, 0x0089, &nv40_gr_object }, /* sifm */ + { -1, -1, 0x008a, &nv40_gr_object }, /* ifc */ + { -1, -1, 0x009f, &nv40_gr_object }, /* imageblit */ + { -1, -1, 0x3062, &nv40_gr_object }, /* surf2d (nv40) */ + { -1, -1, 0x3089, &nv40_gr_object }, /* sifm (nv40) */ + { -1, -1, 0x309e, &nv40_gr_object }, /* swzsurf (nv40) */ + { -1, -1, 0x4497, &nv40_gr_object }, /* curie */ + {} + } +}; + +int +nv44_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv40_gr_new_(&nv44_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 11c4c88389378..9992a919a6d9a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -25,10 +25,9 @@ #include #include -#include #include -static u64 +u64 nv50_gr_units(struct nvkm_gr *gr) { return nvkm_rd32(gr->engine.subdev.device, 0x1540); @@ -55,27 +54,11 @@ nv50_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, return ret; } -static const struct nvkm_object_func +const struct nvkm_object_func nv50_gr_object = { .bind = nv50_gr_object_bind, }; -static int -nv50_gr_object_get(struct nvkm_gr *base, int index, struct nvkm_sclass *sclass) -{ - struct nv50_gr *gr = nv50_gr(base); - int c = 0; - - while (gr->func->sclass[c].oclass) { - if (c++ == index) { - *sclass = gr->func->sclass[index]; - return index; - } - } - - return c; -} - /******************************************************************************* * PGRAPH context ******************************************************************************/ @@ -100,7 +83,7 @@ nv50_gr_chan = { .bind = nv50_gr_chan_bind, }; -static int +int nv50_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, const struct nvkm_oclass *oclass, struct nvkm_object **pobject) { @@ -119,153 +102,6 @@ nv50_gr_chan_new(struct nvkm_gr *base, struct nvkm_fifo_chan *fifoch, * PGRAPH engine/subdev functions ******************************************************************************/ -static const struct nvkm_bitfield nv50_gr_status[] = { - { 0x00000001, "BUSY" }, /* set when any bit is set */ - { 0x00000002, "DISPATCH" }, - { 0x00000004, "UNK2" }, - { 0x00000008, "UNK3" }, - { 0x00000010, "UNK4" }, - { 0x00000020, "UNK5" }, - { 0x00000040, "M2MF" }, - { 0x00000080, "UNK7" }, - { 0x00000100, "CTXPROG" }, - { 0x00000200, "VFETCH" }, - { 0x00000400, "CCACHE_PREGEOM" }, - { 0x00000800, "STRMOUT_VATTR_POSTGEOM" }, - { 0x00001000, "VCLIP" }, - { 0x00002000, "RATTR_APLANE" }, - { 0x00004000, "TRAST" }, - { 0x00008000, "CLIPID" }, - { 0x00010000, "ZCULL" }, - { 0x00020000, "ENG2D" }, - { 0x00040000, "RMASK" }, - { 0x00080000, "TPC_RAST" }, - { 0x00100000, "TPC_PROP" }, - { 0x00200000, "TPC_TEX" }, - { 0x00400000, "TPC_GEOM" }, - { 0x00800000, "TPC_MP" }, - { 0x01000000, "ROP" }, - {} -}; - -static const struct nvkm_bitfield -nv50_gr_vstatus_0[] = { - { 0x01, "VFETCH" }, - { 0x02, "CCACHE" }, - { 0x04, "PREGEOM" }, - { 0x08, "POSTGEOM" }, - { 0x10, "VATTR" }, - { 0x20, "STRMOUT" }, - { 0x40, "VCLIP" }, - {} -}; - -static const struct nvkm_bitfield -nv50_gr_vstatus_1[] = { - { 0x01, "TPC_RAST" }, - { 0x02, "TPC_PROP" }, - { 0x04, "TPC_TEX" }, - { 0x08, "TPC_GEOM" }, - { 0x10, "TPC_MP" }, - {} -}; - -static const struct nvkm_bitfield -nv50_gr_vstatus_2[] = { - { 0x01, "RATTR" }, - { 0x02, "APLANE" }, - { 0x04, "TRAST" }, - { 0x08, "CLIPID" }, - { 0x10, "ZCULL" }, - { 0x20, "ENG2D" }, - { 0x40, "RMASK" }, - { 0x80, "ROP" }, - {} -}; - -static void -nvkm_gr_vstatus_print(struct nv50_gr *gr, int r, - const struct nvkm_bitfield *units, u32 status) -{ - struct nvkm_subdev *subdev = &gr->base.engine.subdev; - u32 stat = status; - u8 mask = 0x00; - char msg[64]; - int i; - - for (i = 0; units[i].name && status; i++) { - if ((status & 7) == 1) - mask |= (1 << i); - status >>= 3; - } - - nvkm_snprintbf(msg, sizeof(msg), units, mask); - nvkm_error(subdev, "PGRAPH_VSTATUS%d: %08x [%s]\n", r, stat, msg); -} - -static int -g84_gr_tlb_flush(struct nvkm_engine *engine) -{ - struct nv50_gr *gr = (void *)engine; - struct nvkm_subdev *subdev = &gr->base.engine.subdev; - struct nvkm_device *device = subdev->device; - struct nvkm_timer *tmr = device->timer; - bool idle, timeout = false; - unsigned long flags; - char status[128]; - u64 start; - u32 tmp; - - spin_lock_irqsave(&gr->lock, flags); - nvkm_mask(device, 0x400500, 0x00000001, 0x00000000); - - start = nvkm_timer_read(tmr); - do { - idle = true; - - for (tmp = nvkm_rd32(device, 0x400380); tmp && idle; tmp >>= 3) { - if ((tmp & 7) == 1) - idle = false; - } - - for (tmp = nvkm_rd32(device, 0x400384); tmp && idle; tmp >>= 3) { - if ((tmp & 7) == 1) - idle = false; - } - - for (tmp = nvkm_rd32(device, 0x400388); tmp && idle; tmp >>= 3) { - if ((tmp & 7) == 1) - idle = false; - } - } while (!idle && - !(timeout = nvkm_timer_read(tmr) - start > 2000000000)); - - if (timeout) { - nvkm_error(subdev, "PGRAPH TLB flush idle timeout fail\n"); - - tmp = nvkm_rd32(device, 0x400700); - nvkm_snprintbf(status, sizeof(status), nv50_gr_status, tmp); - nvkm_error(subdev, "PGRAPH_STATUS %08x [%s]\n", tmp, status); - - nvkm_gr_vstatus_print(gr, 0, nv50_gr_vstatus_0, - nvkm_rd32(device, 0x400380)); - nvkm_gr_vstatus_print(gr, 1, nv50_gr_vstatus_1, - nvkm_rd32(device, 0x400384)); - nvkm_gr_vstatus_print(gr, 2, nv50_gr_vstatus_2, - nvkm_rd32(device, 0x400388)); - } - - - nvkm_wr32(device, 0x100c80, 0x00000001); - nvkm_msec(device, 2000, - if (!(nvkm_rd32(device, 0x100c80) & 0x00000001)) - break; - ); - nvkm_mask(device, 0x400500, 0x00000001, 0x00000001); - spin_unlock_irqrestore(&gr->lock, flags); - return timeout ? -EBUSY : 0; -} - static const struct nvkm_bitfield nv50_mp_exec_errors[] = { { 0x01, "STACK_UNDERFLOW" }, { 0x02, "STACK_MISMATCH" }, @@ -453,7 +289,7 @@ nv50_gr_mp_trap(struct nv50_gr *gr, int tpid, int display) for (i = 0; i < 4; i++) { if (!(units & 1 << (i+24))) continue; - if (nv_device(gr)->chipset < 0xa0) + if (device->chipset < 0xa0) addr = 0x408200 + (tpid << 12) + (i << 7); else addr = 0x408100 + (tpid << 11) + (i << 7); @@ -497,7 +333,7 @@ nv50_gr_tp_trap(struct nv50_gr *gr, int type, u32 ustatus_old, for (i = 0; i < 16; i++) { if (!(units & (1 << i))) continue; - if (nv_device(gr)->chipset < 0xa0) + if (device->chipset < 0xa0) ustatus_addr = ustatus_old + (i << 12); else ustatus_addr = ustatus_new + (i << 11); @@ -778,11 +614,12 @@ nv50_gr_trap_handler(struct nv50_gr *gr, u32 display, return 1; } -static void -nv50_gr_intr(struct nvkm_subdev *subdev) +void +nv50_gr_intr(struct nvkm_gr *base) { - struct nv50_gr *gr = (void *)subdev; - struct nvkm_device *device = gr->base.engine.subdev.device; + struct nv50_gr *gr = nv50_gr(base); + struct nvkm_subdev *subdev = &gr->base.engine.subdev; + struct nvkm_device *device = subdev->device; struct nvkm_fifo_chan *chan; u32 stat = nvkm_rd32(device, 0x400100); u32 inst = nvkm_rd32(device, 0x40032c) & 0x0fffffff; @@ -836,140 +673,13 @@ nv50_gr_intr(struct nvkm_subdev *subdev) nvkm_fifo_chan_put(device->fifo, flags, &chan); } -static const struct nv50_gr_func -nv50_gr = { - .sclass = { - { -1, -1, 0x0030, &nv50_gr_object }, - { -1, -1, 0x502d, &nv50_gr_object }, - { -1, -1, 0x5039, &nv50_gr_object }, - { -1, -1, 0x5097, &nv50_gr_object }, - { -1, -1, 0x50c0, &nv50_gr_object }, - {} - } -}; - -static const struct nv50_gr_func -g84_gr = { - .sclass = { - { -1, -1, 0x0030, &nv50_gr_object }, - { -1, -1, 0x502d, &nv50_gr_object }, - { -1, -1, 0x5039, &nv50_gr_object }, - { -1, -1, 0x50c0, &nv50_gr_object }, - { -1, -1, 0x8297, &nv50_gr_object }, - {} - } -}; - -static const struct nv50_gr_func -gt200_gr = { - .sclass = { - { -1, -1, 0x0030, &nv50_gr_object }, - { -1, -1, 0x502d, &nv50_gr_object }, - { -1, -1, 0x5039, &nv50_gr_object }, - { -1, -1, 0x50c0, &nv50_gr_object }, - { -1, -1, 0x8397, &nv50_gr_object }, - {} - } -}; - -static const struct nv50_gr_func -gt215_gr = { - .sclass = { - { -1, -1, 0x0030, &nv50_gr_object }, - { -1, -1, 0x502d, &nv50_gr_object }, - { -1, -1, 0x5039, &nv50_gr_object }, - { -1, -1, 0x50c0, &nv50_gr_object }, - { -1, -1, 0x8597, &nv50_gr_object }, - { -1, -1, 0x85c0, &nv50_gr_object }, - {} - } -}; - -static const struct nv50_gr_func -mcp89_gr = { - .sclass = { - { -1, -1, 0x0030, &nv50_gr_object }, - { -1, -1, 0x502d, &nv50_gr_object }, - { -1, -1, 0x5039, &nv50_gr_object }, - { -1, -1, 0x50c0, &nv50_gr_object }, - { -1, -1, 0x85c0, &nv50_gr_object }, - { -1, -1, 0x8697, &nv50_gr_object }, - {} - } -}; - -static const struct nvkm_gr_func -nv50_gr_ = { - .chan_new = nv50_gr_chan_new, - .object_get = nv50_gr_object_get, -}; - -static int -nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_gr *gr; - int ret; - - ret = nvkm_gr_create(parent, engine, oclass, true, &gr); - *pobject = nv_object(gr); - if (ret) - return ret; - - nv_subdev(gr)->unit = 0x00201000; - nv_subdev(gr)->intr = nv50_gr_intr; - - gr->base.func = &nv50_gr_; - gr->base.units = nv50_gr_units; - - switch (nv_device(gr)->chipset) { - case 0x50: - gr->func = &nv50_gr; - break; - case 0x84: - case 0x86: - case 0x92: - case 0x94: - case 0x96: - case 0x98: - gr->func = &g84_gr; - break; - case 0xa0: - case 0xaa: - case 0xac: - gr->func = >200_gr; - break; - case 0xa3: - case 0xa5: - case 0xa8: - gr->func = >215_gr; - break; - case 0xaf: - gr->func = &mcp89_gr; - break; - } - - /* unfortunate hw bug workaround... */ - if (nv_device(gr)->chipset != 0x50 && - nv_device(gr)->chipset != 0xac) - nv_engine(gr)->tlb_flush = g84_gr_tlb_flush; - - spin_lock_init(&gr->lock); - return 0; -} - -static int -nv50_gr_init(struct nvkm_object *object) +int +nv50_gr_init(struct nvkm_gr *base) { - struct nv50_gr *gr = (void *)object; + struct nv50_gr *gr = nv50_gr(base); struct nvkm_device *device = gr->base.engine.subdev.device; int ret, units, i; - ret = nvkm_gr_init(&gr->base); - if (ret) - return ret; - /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */ nvkm_wr32(device, 0x40008c, 0x00000004); @@ -986,7 +696,7 @@ nv50_gr_init(struct nvkm_object *object) if (!(units & (1 << i))) continue; - if (nv_device(gr)->chipset < 0xa0) { + if (device->chipset < 0xa0) { nvkm_wr32(device, 0x408900 + (i << 12), 0xc0000000); nvkm_wr32(device, 0x408e08 + (i << 12), 0xc0000000); nvkm_wr32(device, 0x408314 + (i << 12), 0xc0000000); @@ -1004,7 +714,7 @@ nv50_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x400500, 0x00010001); /* upload context program, initialise ctxctl defaults */ - ret = nv50_grctx_init(nv_device(gr), &gr->size); + ret = nv50_grctx_init(device, &gr->size); if (ret) return ret; @@ -1016,7 +726,7 @@ nv50_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x400330, 0x00000000); /* some unknown zcull magic */ - switch (nv_device(gr)->chipset & 0xf0) { + switch (device->chipset & 0xf0) { case 0x50: case 0x80: case 0x90: @@ -1024,9 +734,9 @@ nv50_gr_init(struct nvkm_object *object) break; case 0xa0: default: - if (nv_device(gr)->chipset == 0xa0 || - nv_device(gr)->chipset == 0xaa || - nv_device(gr)->chipset == 0xac) { + if (device->chipset == 0xa0 || + device->chipset == 0xaa || + device->chipset == 0xac) { nvkm_wr32(device, 0x402ca8, 0x00000802); } else { nvkm_wr32(device, 0x402cc0, 0x00000000); @@ -1043,16 +753,42 @@ nv50_gr_init(struct nvkm_object *object) nvkm_wr32(device, 0x402c28 + (i * 0x10), 0x00000000); nvkm_wr32(device, 0x402c2c + (i * 0x10), 0x00000000); } + return 0; } -struct nvkm_oclass -nv50_gr_oclass = { - .handle = NV_ENGINE(GR, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_gr_ctor, - .dtor = _nvkm_gr_dtor, - .init = nv50_gr_init, - .fini = _nvkm_gr_fini, - }, +int +nv50_gr_new_(const struct nvkm_gr_func *func, struct nvkm_device *device, + int index, struct nvkm_gr **pgr) +{ + struct nv50_gr *gr; + + if (!(gr = kzalloc(sizeof(*gr), GFP_KERNEL))) + return -ENOMEM; + spin_lock_init(&gr->lock); + *pgr = &gr->base; + + return nvkm_gr_ctor(func, device, index, 0x00201000, true, &gr->base); +} + +static const struct nvkm_gr_func +nv50_gr = { + .init = nv50_gr_init, + .intr = nv50_gr_intr, + .chan_new = nv50_gr_chan_new, + .units = nv50_gr_units, + .sclass = { + { -1, -1, 0x0030, &nv50_gr_object }, + { -1, -1, 0x502d, &nv50_gr_object }, + { -1, -1, 0x5039, &nv50_gr_object }, + { -1, -1, 0x5097, &nv50_gr_object }, + { -1, -1, 0x50c0, &nv50_gr_object }, + {} + } }; + +int +nv50_gr_new(struct nvkm_device *device, int index, struct nvkm_gr **pgr) +{ + return nv50_gr_new_(&nv50_gr, device, index, pgr); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h index 145ea5026a8e4..45eec83a5969b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h @@ -10,10 +10,13 @@ struct nv50_gr { u32 size; }; -struct nv50_gr_func { - void *(*dtor)(struct nv50_gr *); - struct nvkm_sclass sclass[]; -}; +int nv50_gr_new_(const struct nvkm_gr_func *, struct nvkm_device *, int index, + struct nvkm_gr **); +int nv50_gr_init(struct nvkm_gr *); +void nv50_gr_intr(struct nvkm_gr *); +u64 nv50_gr_units(struct nvkm_gr *); + +int g84_gr_tlb_flush(struct nvkm_gr *); #define nv50_gr_chan(p) container_of((p), struct nv50_gr_chan, object) @@ -22,6 +25,11 @@ struct nv50_gr_chan { struct nv50_gr *gr; }; +int nv50_gr_chan_new(struct nvkm_gr *, struct nvkm_fifo_chan *, + const struct nvkm_oclass *, struct nvkm_object **); + +extern const struct nvkm_object_func nv50_gr_object; + int nv50_grctx_init(struct nvkm_device *, u32 *size); void nv50_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h index f7fd617b6fe51..a234590be88e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/priv.h @@ -2,14 +2,37 @@ #define __NVKM_GR_PRIV_H__ #define nvkm_gr(p) container_of((p), struct nvkm_gr, engine) #include +#include +struct nvkm_fb_tile; struct nvkm_fifo_chan; +int nvkm_gr_ctor(const struct nvkm_gr_func *, struct nvkm_device *, + int index, u32 pmc_enable, bool enable, + struct nvkm_gr *); + +bool nv04_gr_idle(struct nvkm_gr *); + struct nvkm_gr_func { + void *(*dtor)(struct nvkm_gr *); + int (*oneinit)(struct nvkm_gr *); + int (*init)(struct nvkm_gr *); + void (*intr)(struct nvkm_gr *); + void (*tile)(struct nvkm_gr *, int region, struct nvkm_fb_tile *); + int (*tlb_flush)(struct nvkm_gr *); int (*chan_new)(struct nvkm_gr *, struct nvkm_fifo_chan *, const struct nvkm_oclass *, struct nvkm_object **); int (*object_get)(struct nvkm_gr *, int, struct nvkm_sclass *); + /* Returns chipset-specific counts of units packed into an u64. + */ + u64 (*units)(struct nvkm_gr *); struct nvkm_sclass sclass[]; }; +extern const struct nvkm_bitfield nv04_gr_nsource[]; extern const struct nvkm_object_func nv04_gr_object; + +extern const struct nvkm_bitfield nv10_gr_intr_name[]; +extern const struct nvkm_bitfield nv10_gr_nstatus[]; + +extern const struct nvkm_enum nv50_data_error_names[]; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 0f39ff883ec0d..1ca02f870095c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -52,11 +52,13 @@ void nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) { struct nvkm_device *device = fb->subdev.device; - fb->func->tile.prog(fb, region, tile); - if (likely(device->gr)) - device->gr->engine.tile_prog(&device->gr->engine, region); - if (likely(device->mpeg)) - device->mpeg->tile_prog(device->mpeg, region); + if (fb->func->tile.prog) { + fb->func->tile.prog(fb, region, tile); + if (device->gr) + nvkm_engine_tile(&device->gr->engine, region); + if (likely(device->mpeg)) + device->mpeg->tile_prog(device->mpeg, region); + } } int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index 931f14094eb50..21a990c1ac8bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -23,11 +23,10 @@ */ #include "priv.h" +#include #include #include - -#include -#include +#include static void nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_memory *pgt[2]) @@ -167,13 +166,10 @@ nv50_vm_flush(struct nvkm_vm *vm) continue; /* unfortunate hw bug workaround... */ - if (i == NVDEV_ENGINE_GR) { - struct nvkm_engine *engine = - nvkm_device_engine(device, i); - if (engine && engine->tlb_flush) { - engine->tlb_flush(engine); + if (i == NVDEV_ENGINE_GR && device->gr) { + int ret = nvkm_gr_tlb_flush(device->gr); + if (ret != -ENODEV) continue; - } } switch (i) { -- GitLab From 97070f23c60869830039b216ff88230f54ef7107 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5557/7006] drm/nouveau/pm: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/pm.h | 23 +++-- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 88 +++++++++---------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 6 -- .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 ---- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 --- drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild | 1 - drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c | 80 +++++++---------- drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c | 16 ++-- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.c | 69 +++++++-------- .../gpu/drm/nouveau/nvkm/engine/pm/gf100.h | 15 +--- .../gpu/drm/nouveau/nvkm/engine/pm/gf108.c | 23 +++-- .../gpu/drm/nouveau/nvkm/engine/pm/gf117.c | 23 +++-- .../gpu/drm/nouveau/nvkm/engine/pm/gk104.c | 23 +++-- .../gpu/drm/nouveau/nvkm/engine/pm/gk110.c | 51 ----------- .../gpu/drm/nouveau/nvkm/engine/pm/gt200.c | 16 ++-- .../gpu/drm/nouveau/nvkm/engine/pm/gt215.c | 16 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c | 69 +++++++-------- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h | 16 +--- drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c | 16 ++-- drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h | 29 ++---- 21 files changed, 219 insertions(+), 400 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h index c67cea6aae4d5..240855ad8c8d3 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h @@ -1,11 +1,9 @@ #ifndef __NVKM_PM_H__ #define __NVKM_PM_H__ -#define nvkm_pm(p) container_of((p), struct nvkm_pm, engine) #include -struct nvkm_perfdom; -struct nvkm_perfctr; struct nvkm_pm { + const struct nvkm_pm_func *func; struct nvkm_engine engine; struct nvkm_object *perfmon; @@ -15,14 +13,13 @@ struct nvkm_pm { u32 sequence; }; -extern struct nvkm_oclass *nv40_pm_oclass; -extern struct nvkm_oclass *nv50_pm_oclass; -extern struct nvkm_oclass *g84_pm_oclass; -extern struct nvkm_oclass *gt200_pm_oclass; -extern struct nvkm_oclass *gt215_pm_oclass; -extern struct nvkm_oclass *gf100_pm_oclass; -extern struct nvkm_oclass *gf108_pm_oclass; -extern struct nvkm_oclass *gf117_pm_oclass; -extern struct nvkm_oclass *gk104_pm_oclass; -extern struct nvkm_oclass gk110_pm_oclass; +int nv40_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int nv50_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int g84_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int gt200_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int gt215_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int gf100_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int gf108_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int gf117_pm_new(struct nvkm_device *, int, struct nvkm_pm **); +int gk104_pm_new(struct nvkm_device *, int, struct nvkm_pm **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 3cf15d46f9d23..c954ae4189a94 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -471,7 +471,7 @@ nv40_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -496,7 +496,7 @@ nv41_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -521,7 +521,7 @@ nv42_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -546,7 +546,7 @@ nv43_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -571,7 +571,7 @@ nv44_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -596,7 +596,7 @@ nv45_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -621,7 +621,7 @@ nv46_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -646,7 +646,7 @@ nv47_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -671,7 +671,7 @@ nv49_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -696,7 +696,7 @@ nv4a_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -721,7 +721,7 @@ nv4b_chipset = { .fifo = nv40_fifo_new, .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -746,7 +746,7 @@ nv4c_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -771,7 +771,7 @@ nv4e_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -799,7 +799,7 @@ nv50_chipset = { .fifo = nv50_fifo_new, .gr = nv50_gr_new, // .mpeg = nv50_mpeg_new, -// .pm = nv50_pm_new, + .pm = nv50_pm_new, // .sw = nv50_sw_new, }; @@ -824,7 +824,7 @@ nv63_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -849,7 +849,7 @@ nv67_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -874,7 +874,7 @@ nv68_chipset = { .fifo = nv40_fifo_new, .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, -// .pm = nv40_pm_new, + .pm = nv40_pm_new, // .sw = nv10_sw_new, }; @@ -904,7 +904,7 @@ nv84_chipset = { .fifo = g84_fifo_new, .gr = g84_gr_new, // .mpeg = g84_mpeg_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, // .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -935,7 +935,7 @@ nv86_chipset = { .fifo = g84_fifo_new, .gr = g84_gr_new, // .mpeg = g84_mpeg_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, // .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -966,7 +966,7 @@ nv92_chipset = { .fifo = g84_fifo_new, .gr = g84_gr_new, // .mpeg = g84_mpeg_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, // .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -997,7 +997,7 @@ nv94_chipset = { .fifo = g84_fifo_new, .gr = g84_gr_new, // .mpeg = g84_mpeg_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, // .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -1030,7 +1030,7 @@ nv96_chipset = { .cipher = g84_cipher_new, .bsp = g84_bsp_new, .disp = g94_disp_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, }; static const struct nvkm_device_chip @@ -1061,7 +1061,7 @@ nv98_chipset = { .msvld = g98_msvld_new, .msppp = g98_msppp_new, .disp = g94_disp_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, }; static const struct nvkm_device_chip @@ -1090,7 +1090,7 @@ nva0_chipset = { .fifo = g84_fifo_new, .gr = gt200_gr_new, // .mpeg = g84_mpeg_new, -// .pm = gt200_pm_new, + .pm = gt200_pm_new, // .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -1124,7 +1124,7 @@ nva3_chipset = { .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, -// .pm = gt215_pm_new, + .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1156,7 +1156,7 @@ nva5_chipset = { .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, -// .pm = gt215_pm_new, + .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1188,7 +1188,7 @@ nva8_chipset = { .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, -// .pm = gt215_pm_new, + .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1218,7 +1218,7 @@ nvaa_chipset = { .mspdec = g98_mspdec_new, .msppp = g98_msppp_new, .msvld = g98_msvld_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, .sec = g98_sec_new, // .sw = nv50_sw_new, }; @@ -1249,7 +1249,7 @@ nvac_chipset = { .mspdec = g98_mspdec_new, .msppp = g98_msppp_new, .msvld = g98_msvld_new, -// .pm = g84_pm_new, + .pm = g84_pm_new, .sec = g98_sec_new, // .sw = nv50_sw_new, }; @@ -1282,7 +1282,7 @@ nvaf_chipset = { .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = mcp89_msvld_new, -// .pm = gt215_pm_new, + .pm = gt215_pm_new, // .sw = nv50_sw_new, }; @@ -1317,7 +1317,7 @@ nvc0_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf100_pm_new, + .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1351,7 +1351,7 @@ nvc1_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf108_pm_new, + .pm = gf108_pm_new, // .sw = gf100_sw_new, }; @@ -1385,7 +1385,7 @@ nvc3_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf100_pm_new, + .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1420,7 +1420,7 @@ nvc4_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf100_pm_new, + .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1455,7 +1455,7 @@ nvc8_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf100_pm_new, + .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1490,7 +1490,7 @@ nvce_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf100_pm_new, + .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1524,7 +1524,7 @@ nvcf_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf100_pm_new, + .pm = gf100_pm_new, // .sw = gf100_sw_new, }; @@ -1556,7 +1556,7 @@ nvd7_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf117_pm_new, + .pm = gf117_pm_new, // .sw = gf100_sw_new, }; @@ -1590,7 +1590,7 @@ nvd9_chipset = { .mspdec = gf100_mspdec_new, .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, -// .pm = gf117_pm_new, + .pm = gf117_pm_new, // .sw = gf100_sw_new, }; @@ -1626,7 +1626,7 @@ nve4_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .pm = gk104_pm_new, + .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1662,7 +1662,7 @@ nve6_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .pm = gk104_pm_new, + .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1698,7 +1698,7 @@ nve7_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .pm = gk104_pm_new, + .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1722,7 +1722,7 @@ nvea_chipset = { .dma = gf119_dma_new, .fifo = gk20a_fifo_new, .gr = gk20a_gr_new, -// .pm = gk104_pm_new, + .pm = gk104_pm_new, // .sw = gf100_sw_new, }; @@ -1758,7 +1758,6 @@ nvf0_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .pm = gk110_pm_new, // .sw = gf100_sw_new, }; @@ -1794,7 +1793,6 @@ nvf1_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .pm = gk110_pm_new, // .sw = gf100_sw_new, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index b88aceb343c8a..67faff5d0b527 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -29,39 +29,30 @@ gf100_identify(struct nvkm_device *device) switch (device->chipset) { case 0xc0: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc4: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc3: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xce: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xcf: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xc1: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf108_pm_oclass; break; case 0xc8: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf100_pm_oclass; break; case 0xd9: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; case 0xd7: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gf117_pm_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 1ad7b217e2b86..3841dc0ac01b1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -29,27 +29,21 @@ gk104_identify(struct nvkm_device *device) switch (device->chipset) { case 0xe4: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe7: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xe6: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xea: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gk104_pm_oclass; break; case 0xf0: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0xf1: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass; break; case 0x106: device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index e3fdbf6ba8713..08c015b0e5a1d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -30,82 +30,66 @@ nv40_identify(struct nvkm_device *device) case 0x40: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x41: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x42: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x43: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x45: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x47: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x49: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4b: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x44: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x46: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4a: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4c: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x4e: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x63: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x67: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; case 0x68: device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 912bd8070db76..c285f61ffd8f6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -30,66 +30,52 @@ nv50_identify(struct nvkm_device *device) case 0x50: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass; break; case 0x84: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x86: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x92: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x94: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x96: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0x98: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa0: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt200_pm_oclass; break; case 0xaa: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xac: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass; break; case 0xa3: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa5: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xa8: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; case 0xaf: device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; - device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild index 4fadf55f51f9f..1614d385fb0c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild @@ -8,4 +8,3 @@ nvkm-y += nvkm/engine/pm/gf100.o nvkm-y += nvkm/engine/pm/gf108.o nvkm-y += nvkm/engine/pm/gf117.o nvkm-y += nvkm/engine/pm/gk104.o -nvkm-y += nvkm/engine/pm/gk110.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c index 5b4ab63809bee..0db9be202c42f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c @@ -203,13 +203,13 @@ nvkm_perfsrc_disable(struct nvkm_pm *pm, struct nvkm_perfctr *ctr) * Perfdom object classes ******************************************************************************/ static int -nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_init(struct nvkm_perfdom *dom, void *data, u32 size) { union { struct nvif_perfdom_init none; } *args = data; - struct nvkm_pm *pm = (void *)object->engine; - struct nvkm_perfdom *dom = (void *)object; + struct nvkm_object *object = &dom->object; + struct nvkm_pm *pm = dom->perfmon->pm; int ret, i; nvif_ioctl(object, "perfdom init size %d\n", size); @@ -233,13 +233,13 @@ nvkm_perfdom_init(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_sample(struct nvkm_perfdom *dom, void *data, u32 size) { union { struct nvif_perfdom_sample none; } *args = data; - struct nvkm_pm *pm = (void *)object->engine; - struct nvkm_perfdom *dom; + struct nvkm_object *object = &dom->object; + struct nvkm_pm *pm = dom->perfmon->pm; int ret; nvif_ioctl(object, "perfdom sample size %d\n", size); @@ -257,13 +257,13 @@ nvkm_perfdom_sample(struct nvkm_object *object, void *data, u32 size) } static int -nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size) +nvkm_perfdom_read(struct nvkm_perfdom *dom, void *data, u32 size) { union { struct nvif_perfdom_read_v0 v0; } *args = data; - struct nvkm_pm *pm = (void *)object->engine; - struct nvkm_perfdom *dom = (void *)object; + struct nvkm_object *object = &dom->object; + struct nvkm_pm *pm = dom->perfmon->pm; int ret, i; nvif_ioctl(object, "perfdom read size %d\n", size); @@ -290,13 +290,14 @@ nvkm_perfdom_read(struct nvkm_object *object, void *data, u32 size) static int nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { + struct nvkm_perfdom *dom = nvkm_perfdom(object); switch (mthd) { case NVIF_PERFDOM_V0_INIT: - return nvkm_perfdom_init(object, data, size); + return nvkm_perfdom_init(dom, data, size); case NVIF_PERFDOM_V0_SAMPLE: - return nvkm_perfdom_sample(object, data, size); + return nvkm_perfdom_sample(dom, data, size); case NVIF_PERFDOM_V0_READ: - return nvkm_perfdom_read(object, data, size); + return nvkm_perfdom_read(dom, data, size); default: break; } @@ -304,9 +305,9 @@ nvkm_perfdom_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) } static void * -nvkm_perfdom_dtor(struct nvkm_object *base) +nvkm_perfdom_dtor(struct nvkm_object *object) { - struct nvkm_perfdom *dom = nvkm_perfdom(base); + struct nvkm_perfdom *dom = nvkm_perfdom(object); struct nvkm_pm *pm = dom->perfmon->pm; int i; @@ -607,7 +608,7 @@ nvkm_perfmon_child_new(const struct nvkm_oclass *oclass, void *data, u32 size, } static int -nvkm_perfmon_child_get(struct nvkm_object *base, int index, +nvkm_perfmon_child_get(struct nvkm_object *object, int index, struct nvkm_oclass *oclass) { if (index == 0) { @@ -621,9 +622,9 @@ nvkm_perfmon_child_get(struct nvkm_object *base, int index, } static void * -nvkm_perfmon_dtor(struct nvkm_object *base) +nvkm_perfmon_dtor(struct nvkm_object *object) { - struct nvkm_perfmon *perfmon = nvkm_perfmon(base); + struct nvkm_perfmon *perfmon = nvkm_perfmon(object); struct nvkm_pm *pm = perfmon->pm; mutex_lock(&pm->engine.subdev.mutex); if (pm->perfmon == &perfmon->object) @@ -816,24 +817,19 @@ nvkm_perfdom_new(struct nvkm_pm *pm, const char *name, u32 mask, return 0; } -int -_nvkm_pm_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_pm *pm = (void *)object; - return nvkm_engine_fini_old(&pm->engine, suspend); -} - -int -_nvkm_pm_init(struct nvkm_object *object) +static int +nvkm_pm_fini(struct nvkm_engine *engine, bool suspend) { - struct nvkm_pm *pm = (void *)object; - return nvkm_engine_init_old(&pm->engine); + struct nvkm_pm *pm = nvkm_pm(engine); + if (pm->func->fini) + pm->func->fini(pm); + return 0; } -void -_nvkm_pm_dtor(struct nvkm_object *object) +static void * +nvkm_pm_dtor(struct nvkm_engine *engine) { - struct nvkm_pm *pm = (void *)object; + struct nvkm_pm *pm = nvkm_pm(engine); struct nvkm_perfdom *dom, *next_dom; struct nvkm_perfsrc *src, *next_src; @@ -848,30 +844,22 @@ _nvkm_pm_dtor(struct nvkm_object *object) kfree(src); } - nvkm_engine_destroy(&pm->engine); + return pm; } static const struct nvkm_engine_func nvkm_pm = { + .dtor = nvkm_pm_dtor, + .fini = nvkm_pm_fini, .base.sclass = nvkm_pm_oclass_get, }; int -nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_pm_ctor(const struct nvkm_pm_func *func, struct nvkm_device *device, + int index, struct nvkm_pm *pm) { - struct nvkm_pm *pm; - int ret; - - ret = nvkm_engine_create_(parent, engine, oclass, true, "PPM", - "pm", length, pobject); - pm = *pobject; - if (ret) - return ret; - - pm->engine.func = &nvkm_pm; - + pm->func = func; INIT_LIST_HEAD(&pm->domains); INIT_LIST_HEAD(&pm->sources); - return 0; + return nvkm_engine_ctor(&nvkm_pm, device, index, 0, true, &pm->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c index 815bb0dcbf7ed..6e441ddafd86f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c @@ -158,14 +158,8 @@ g84_pm[] = { {} }; -struct nvkm_oclass * -g84_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0x84), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = g84_pm, -}.base; +int +g84_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(g84_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c index 18e0ed5142495..d2901e9a78088 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c @@ -129,7 +129,6 @@ gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { struct nvkm_device *device = pm->engine.subdev.device; - struct gf100_pm_cntr *cntr = (void *)ctr; u32 log = ctr->logic_op; u32 src = 0x00000000; int i; @@ -139,8 +138,8 @@ gf100_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, nvkm_wr32(device, dom->addr + 0x09c, 0x00040002 | (dom->mode << 3)); nvkm_wr32(device, dom->addr + 0x100, 0x00000000); - nvkm_wr32(device, dom->addr + 0x040 + (cntr->base.slot * 0x08), src); - nvkm_wr32(device, dom->addr + 0x044 + (cntr->base.slot * 0x08), log); + nvkm_wr32(device, dom->addr + 0x040 + (ctr->slot * 0x08), src); + nvkm_wr32(device, dom->addr + 0x044 + (ctr->slot * 0x08), log); } static void @@ -148,13 +147,12 @@ gf100_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { struct nvkm_device *device = pm->engine.subdev.device; - struct gf100_pm_cntr *cntr = (void *)ctr; - switch (cntr->base.slot) { - case 0: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x08c); break; - case 1: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x088); break; - case 2: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x080); break; - case 3: cntr->base.ctr = nvkm_rd32(device, dom->addr + 0x090); break; + switch (ctr->slot) { + case 0: ctr->ctr = nvkm_rd32(device, dom->addr + 0x08c); break; + case 1: ctr->ctr = nvkm_rd32(device, dom->addr + 0x088); break; + case 2: ctr->ctr = nvkm_rd32(device, dom->addr + 0x080); break; + case 3: ctr->ctr = nvkm_rd32(device, dom->addr + 0x090); break; } dom->clk = nvkm_rd32(device, dom->addr + 0x070); } @@ -174,35 +172,37 @@ gf100_perfctr_func = { .next = gf100_perfctr_next, }; -int -gf100_pm_fini(struct nvkm_object *object, bool suspend) +static void +gf100_pm_fini(struct nvkm_pm *pm) { - struct nvkm_pm *pm = (void *)object; struct nvkm_device *device = pm->engine.subdev.device; nvkm_mask(device, 0x000200, 0x10000000, 0x00000000); nvkm_mask(device, 0x000200, 0x10000000, 0x10000000); - return nvkm_pm_fini(pm, suspend); } +static const struct nvkm_pm_func +gf100_pm_ = { + .fini = gf100_pm_fini, +}; + int -gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +gf100_pm_new_(const struct gf100_pm_func *func, struct nvkm_device *device, + int index, struct nvkm_pm **ppm) { - struct gf100_pm_oclass *mclass = (void *)oclass; - struct nvkm_device *device = (void *)parent; struct nvkm_pm *pm; u32 mask; int ret; - ret = nvkm_pm_create(parent, engine, oclass, &pm); - *pobject = nv_object(pm); + if (!(pm = *ppm = kzalloc(sizeof(*pm), GFP_KERNEL))) + return -ENOMEM; + + ret = nvkm_pm_ctor(&gf100_pm_, device, index, pm); if (ret) return ret; /* HUB */ ret = nvkm_perfdom_new(pm, "hub", 0, 0x1b0000, 0, 0x200, - mclass->doms_hub); + func->doms_hub); if (ret) return ret; @@ -212,7 +212,7 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mask &= ~nvkm_rd32(device, 0x022584); ret = nvkm_perfdom_new(pm, "gpc", mask, 0x180000, - 0x1000, 0x200, mclass->doms_gpc); + 0x1000, 0x200, func->doms_gpc); if (ret) return ret; @@ -222,23 +222,22 @@ gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, mask &= ~nvkm_rd32(device, 0x0225c8); ret = nvkm_perfdom_new(pm, "part", mask, 0x1a0000, - 0x1000, 0x200, mclass->doms_part); + 0x1000, 0x200, func->doms_part); if (ret) return ret; return 0; } -struct nvkm_oclass * -gf100_pm_oclass = &(struct gf100_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, - .doms_gpc = gf100_pm_gpc, - .doms_hub = gf100_pm_hub, +static const struct gf100_pm_func +gf100_pm = { + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf100_pm_hub, .doms_part = gf100_pm_part, -}.base; +}; + +int +gf100_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gf100_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h index de61622218232..56d0344853eac 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h @@ -2,27 +2,18 @@ #define __NVKM_PM_NVC0_H__ #include "priv.h" -struct gf100_pm_oclass { - struct nvkm_oclass base; +struct gf100_pm_func { const struct nvkm_specdom *doms_hub; const struct nvkm_specdom *doms_gpc; const struct nvkm_specdom *doms_part; }; -int gf100_pm_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **pobject); - -struct gf100_pm_cntr { - struct nvkm_perfctr base; -}; +int gf100_pm_new_(const struct gf100_pm_func *, struct nvkm_device *, + int index, struct nvkm_pm **); extern const struct nvkm_funcdom gf100_perfctr_func; -int gf100_pm_fini(struct nvkm_object *, bool); - extern const struct nvkm_specdom gf100_pm_gpc[]; extern const struct nvkm_specsrc gf100_pbfb_sources[]; extern const struct nvkm_specsrc gf100_pmfb_sources[]; - #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c index a4d86d1ab1b0b..49b24c98a7f7f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf108.c @@ -52,16 +52,15 @@ gf108_pm_part[] = { {} }; -struct nvkm_oclass * -gf108_pm_oclass = &(struct gf100_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xc1), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, - .doms_hub = gf108_pm_hub, - .doms_gpc = gf100_pm_gpc, +static const struct gf100_pm_func +gf108_pm = { + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf108_pm_hub, .doms_part = gf108_pm_part, -}.base; +}; + +int +gf108_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gf108_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c index a76c9283237d8..9170025fc9887 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf117.c @@ -66,16 +66,15 @@ gf117_pm_part[] = { {} }; -struct nvkm_oclass * -gf117_pm_oclass = &(struct gf100_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xd7), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, - .doms_gpc = gf100_pm_gpc, - .doms_hub = gf117_pm_hub, +static const struct gf100_pm_func +gf117_pm = { + .doms_gpc = gf100_pm_gpc, + .doms_hub = gf117_pm_hub, .doms_part = gf117_pm_part, -}.base; +}; + +int +gf117_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gf117_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c index a236db9b7a686..07f946d26ac6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c @@ -170,16 +170,15 @@ gk104_pm_part[] = { {} }; -struct nvkm_oclass * -gk104_pm_oclass = &(struct gf100_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xe0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = gf100_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, - .doms_gpc = gk104_pm_gpc, - .doms_hub = gk104_pm_hub, +static const struct gf100_pm_func +gk104_pm = { + .doms_gpc = gk104_pm_gpc, + .doms_hub = gk104_pm_hub, .doms_part = gk104_pm_part, -}.base; +}; + +int +gk104_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return gf100_pm_new_(&gk104_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c deleted file mode 100644 index 44df8d3110707..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2013 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "gf100.h" - -static int -gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_pm *pm; - int ret; - - ret = nvkm_pm_create(parent, engine, oclass, &pm); - *pobject = nv_object(pm); - if (ret) - return ret; - - return 0; -} - -struct nvkm_oclass -gk110_pm_oclass = { - .handle = NV_ENGINE(PM, 0xf0), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = gk110_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = gf100_pm_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c index e92f9c711bccf..5cf5dd536fd0f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt200.c @@ -150,14 +150,8 @@ gt200_pm[] = { {} }; -struct nvkm_oclass * -gt200_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xa0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = gt200_pm, -}.base; +int +gt200_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(gt200_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c index f5eae63d9f48d..c9227ad41b04b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c @@ -131,14 +131,8 @@ gt215_pm[] = { {} }; -struct nvkm_oclass * -gt215_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0xa3), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = gt215_pm, -}.base; +int +gt215_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(gt215_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c index a4660dc142593..4bef72a9d1068 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c @@ -28,7 +28,6 @@ nv40_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { struct nvkm_device *device = pm->engine.subdev.device; - struct nv40_pm_cntr *cntr = (void *)ctr; u32 log = ctr->logic_op; u32 src = 0x00000000; int i; @@ -37,8 +36,8 @@ nv40_perfctr_init(struct nvkm_pm *pm, struct nvkm_perfdom *dom, src |= ctr->signal[i] << (i * 8); nvkm_wr32(device, 0x00a7c0 + dom->addr, 0x00000001 | (dom->mode << 4)); - nvkm_wr32(device, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src); - nvkm_wr32(device, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log); + nvkm_wr32(device, 0x00a400 + dom->addr + (ctr->slot * 0x40), src); + nvkm_wr32(device, 0x00a420 + dom->addr + (ctr->slot * 0x40), log); } static void @@ -46,13 +45,12 @@ nv40_perfctr_read(struct nvkm_pm *pm, struct nvkm_perfdom *dom, struct nvkm_perfctr *ctr) { struct nvkm_device *device = pm->engine.subdev.device; - struct nv40_pm_cntr *cntr = (void *)ctr; - switch (cntr->base.slot) { - case 0: cntr->base.ctr = nvkm_rd32(device, 0x00a700 + dom->addr); break; - case 1: cntr->base.ctr = nvkm_rd32(device, 0x00a6c0 + dom->addr); break; - case 2: cntr->base.ctr = nvkm_rd32(device, 0x00a680 + dom->addr); break; - case 3: cntr->base.ctr = nvkm_rd32(device, 0x00a740 + dom->addr); break; + switch (ctr->slot) { + case 0: ctr->ctr = nvkm_rd32(device, 0x00a700 + dom->addr); break; + case 1: ctr->ctr = nvkm_rd32(device, 0x00a6c0 + dom->addr); break; + case 2: ctr->ctr = nvkm_rd32(device, 0x00a680 + dom->addr); break; + case 3: ctr->ctr = nvkm_rd32(device, 0x00a740 + dom->addr); break; } dom->clk = nvkm_rd32(device, 0x00a600 + dom->addr); } @@ -74,6 +72,28 @@ nv40_perfctr_func = { .next = nv40_perfctr_next, }; +static const struct nvkm_pm_func +nv40_pm_ = { +}; + +int +nv40_pm_new_(const struct nvkm_specdom *doms, struct nvkm_device *device, + int index, struct nvkm_pm **ppm) +{ + struct nv40_pm *pm; + int ret; + + if (!(pm = kzalloc(sizeof(*pm), GFP_KERNEL))) + return -ENOMEM; + *ppm = &pm->base; + + ret = nvkm_pm_ctor(&nv40_pm_, device, index, &pm->base); + if (ret) + return ret; + + return nvkm_perfdom_new(&pm->base, "pc", 0, 0, 0, 4, doms); +} + static const struct nvkm_specdom nv40_pm[] = { { 0x20, (const struct nvkm_specsig[]) { @@ -95,34 +115,7 @@ nv40_pm[] = { }; int -nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +nv40_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) { - struct nv40_pm_oclass *mclass = (void *)oclass; - struct nv40_pm *pm; - int ret; - - ret = nvkm_pm_create(parent, engine, oclass, &pm); - *pobject = nv_object(pm); - if (ret) - return ret; - - ret = nvkm_perfdom_new(&pm->base, "pc", 0, 0, 0, 4, mclass->doms); - if (ret) - return ret; - - return 0; + return nv40_pm_new_(nv40_pm, device, index, ppm); } - -struct nvkm_oclass * -nv40_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0x40), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = nv40_pm, -}.base; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h index 08287527615cc..da481abe8f7a2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h @@ -1,24 +1,14 @@ #ifndef __NVKM_PM_NV40_H__ #define __NVKM_PM_NV40_H__ +#define nv40_pm(p) container_of((p), struct nv40_pm, base) #include "priv.h" -struct nv40_pm_oclass { - struct nvkm_oclass base; - const struct nvkm_specdom *doms; -}; - struct nv40_pm { struct nvkm_pm base; u32 sequence; }; -int nv40_pm_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **pobject); - -struct nv40_pm_cntr { - struct nvkm_perfctr base; -}; - +int nv40_pm_new_(const struct nvkm_specdom *, struct nvkm_device *, + int index, struct nvkm_pm **); extern const struct nvkm_funcdom nv40_perfctr_func; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c index dee73af1c62ff..cc5a41d4c6f22 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c @@ -168,14 +168,8 @@ nv50_pm[] = { {} }; -struct nvkm_oclass * -nv50_pm_oclass = &(struct nv40_pm_oclass) { - .base.handle = NV_ENGINE(PM, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_pm_ctor, - .dtor = _nvkm_pm_dtor, - .init = _nvkm_pm_init, - .fini = _nvkm_pm_fini, - }, - .doms = nv50_pm, -}.base; +int +nv50_pm_new(struct nvkm_device *device, int index, struct nvkm_pm **ppm) +{ + return nv40_pm_new_(nv50_pm, device, index, ppm); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h index 889dca2e87bea..d7b81cbf82b50 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h @@ -1,7 +1,15 @@ #ifndef __NVKM_PM_PRIV_H__ #define __NVKM_PM_PRIV_H__ +#define nvkm_pm(p) container_of((p), struct nvkm_pm, engine) #include +int nvkm_pm_ctor(const struct nvkm_pm_func *, struct nvkm_device *, + int index, struct nvkm_pm *); + +struct nvkm_pm_func { + void (*fini)(struct nvkm_pm *); +}; + struct nvkm_perfctr { struct list_head head; u8 domain; @@ -92,25 +100,4 @@ struct nvkm_perfmon { struct nvkm_object object; struct nvkm_pm *pm; }; - -#define nvkm_pm_create(p,e,o,d) \ - nvkm_pm_create_((p), (e), (o), sizeof(**d), (void **)d) -#define nvkm_pm_dtor(p) ({ \ - struct nvkm_pm *c = (p); \ - _nvkm_pm_dtor(nv_object(c)); \ -}) -#define nvkm_pm_init(p) ({ \ - struct nvkm_pm *c = (p); \ - _nvkm_pm_init(nv_object(c)); \ -}) -#define nvkm_pm_fini(p,s) ({ \ - struct nvkm_pm *c = (p); \ - _nvkm_pm_fini(nv_object(c), (s)); \ -}) - -int nvkm_pm_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, int, void **); -void _nvkm_pm_dtor(struct nvkm_object *); -int _nvkm_pm_init(struct nvkm_object *); -int _nvkm_pm_fini(struct nvkm_object *, bool); #endif -- GitLab From 6f41c7c56929b3a2ad943d5b6dd4d66d716e74d7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5558/7006] drm/nouveau/sw: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/engine/sw.h | 29 +--- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 136 +++++++++--------- .../drm/nouveau/nvkm/engine/device/gf100.c | 9 -- .../drm/nouveau/nvkm/engine/device/gk104.c | 8 -- .../drm/nouveau/nvkm/engine/device/gm100.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 2 - .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 7 - .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 4 - .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 5 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 --- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 14 -- drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c | 25 ++-- .../gpu/drm/nouveau/nvkm/engine/sw/gf100.c | 18 +-- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c | 35 +---- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c | 29 +--- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 39 +---- drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h | 15 -- drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c | 9 +- drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h | 3 + 19 files changed, 115 insertions(+), 292 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h index f2288d468cb6b..096e7dbd1e655 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h @@ -3,33 +3,16 @@ #include struct nvkm_sw { - struct nvkm_engine engine; const struct nvkm_sw_func *func; + struct nvkm_engine engine; + struct list_head chan; }; bool nvkm_sw_mthd(struct nvkm_sw *sw, int chid, int subc, u32 mthd, u32 data); -#define nvkm_sw_create(p,e,c,d) \ - nvkm_sw_ctor((p), (e), (c), sizeof(**d), (void **)d) -int -nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject); -#define nvkm_sw_destroy(d) \ - nvkm_engine_destroy(&(d)->engine) -#define nvkm_sw_init(d) \ - nvkm_engine_init_old(&(d)->engine) -#define nvkm_sw_fini(d,s) \ - nvkm_engine_fini_old(&(d)->engine, (s)) - -#define _nvkm_sw_dtor _nvkm_engine_dtor -#define _nvkm_sw_init _nvkm_engine_init -#define _nvkm_sw_fini _nvkm_engine_fini - -extern struct nvkm_oclass *nv04_sw_oclass; -extern struct nvkm_oclass *nv10_sw_oclass; -extern struct nvkm_oclass *nv50_sw_oclass; -extern struct nvkm_oclass *gf100_sw_oclass; - -void nv04_sw_intr(struct nvkm_subdev *); +int nv04_sw_new(struct nvkm_device *, int, struct nvkm_sw **); +int nv10_sw_new(struct nvkm_device *, int, struct nvkm_sw **); +int nv50_sw_new(struct nvkm_device *, int, struct nvkm_sw **); +int gf100_sw_new(struct nvkm_device *, int, struct nvkm_sw **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index c954ae4189a94..302122c059b51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -90,7 +90,7 @@ nv4_chipset = { .dma = nv04_dma_new, .fifo = nv04_fifo_new, .gr = nv04_gr_new, -// .sw = nv04_sw_new, + .sw = nv04_sw_new, }; static const struct nvkm_device_chip @@ -110,7 +110,7 @@ nv5_chipset = { .dma = nv04_dma_new, .fifo = nv04_fifo_new, .gr = nv04_gr_new, -// .sw = nv04_sw_new, + .sw = nv04_sw_new, }; static const struct nvkm_device_chip @@ -150,7 +150,7 @@ nv11_chipset = { .dma = nv04_dma_new, .fifo = nv10_fifo_new, .gr = nv15_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -171,7 +171,7 @@ nv15_chipset = { .dma = nv04_dma_new, .fifo = nv10_fifo_new, .gr = nv15_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -192,7 +192,7 @@ nv17_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv17_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -213,7 +213,7 @@ nv18_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv17_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -234,7 +234,7 @@ nv1a_chipset = { .dma = nv04_dma_new, .fifo = nv10_fifo_new, .gr = nv15_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -255,7 +255,7 @@ nv1f_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv17_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -276,7 +276,7 @@ nv20_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv20_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -297,7 +297,7 @@ nv25_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv25_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -318,7 +318,7 @@ nv28_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv25_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -339,7 +339,7 @@ nv2a_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv2a_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -360,7 +360,7 @@ nv30_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv30_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -382,7 +382,7 @@ nv31_chipset = { .fifo = nv17_fifo_new, .gr = nv30_gr_new, // .mpeg = nv31_mpeg_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -404,7 +404,7 @@ nv34_chipset = { .fifo = nv17_fifo_new, .gr = nv34_gr_new, // .mpeg = nv31_mpeg_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -425,7 +425,7 @@ nv35_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv35_gr_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -447,7 +447,7 @@ nv36_chipset = { .fifo = nv17_fifo_new, .gr = nv35_gr_new, // .mpeg = nv31_mpeg_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -472,7 +472,7 @@ nv40_chipset = { .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -497,7 +497,7 @@ nv41_chipset = { .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -522,7 +522,7 @@ nv42_chipset = { .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -547,7 +547,7 @@ nv43_chipset = { .gr = nv40_gr_new, // .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -572,7 +572,7 @@ nv44_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -597,7 +597,7 @@ nv45_chipset = { .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -622,7 +622,7 @@ nv46_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -647,7 +647,7 @@ nv47_chipset = { .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -672,7 +672,7 @@ nv49_chipset = { .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -697,7 +697,7 @@ nv4a_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -722,7 +722,7 @@ nv4b_chipset = { .gr = nv40_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -747,7 +747,7 @@ nv4c_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -772,7 +772,7 @@ nv4e_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -800,7 +800,7 @@ nv50_chipset = { .gr = nv50_gr_new, // .mpeg = nv50_mpeg_new, .pm = nv50_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -825,7 +825,7 @@ nv63_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -850,7 +850,7 @@ nv67_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -875,7 +875,7 @@ nv68_chipset = { .gr = nv44_gr_new, // .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, -// .sw = nv10_sw_new, + .sw = nv10_sw_new, }; static const struct nvkm_device_chip @@ -905,7 +905,7 @@ nv84_chipset = { .gr = g84_gr_new, // .mpeg = g84_mpeg_new, .pm = g84_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -936,7 +936,7 @@ nv86_chipset = { .gr = g84_gr_new, // .mpeg = g84_mpeg_new, .pm = g84_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -967,7 +967,7 @@ nv92_chipset = { .gr = g84_gr_new, // .mpeg = g84_mpeg_new, .pm = g84_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -998,7 +998,7 @@ nv94_chipset = { .gr = g84_gr_new, // .mpeg = g84_mpeg_new, .pm = g84_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -1023,8 +1023,8 @@ nv96_chipset = { .volt = nv40_volt_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .sw = nv50_sw_new, .gr = g84_gr_new, + .gr = nv50_gr_new, // .mpeg = g84_mpeg_new, .vp = g84_vp_new, .cipher = g84_cipher_new, @@ -1054,8 +1054,8 @@ nv98_chipset = { .volt = nv40_volt_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, -// .sw = nv50_sw_new, .gr = g84_gr_new, + .sw = nv50_sw_new, .mspdec = g98_mspdec_new, .sec = g98_sec_new, .msvld = g98_msvld_new, @@ -1091,7 +1091,7 @@ nva0_chipset = { .gr = gt200_gr_new, // .mpeg = g84_mpeg_new, .pm = gt200_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, .vp = g84_vp_new, }; @@ -1125,7 +1125,7 @@ nva3_chipset = { .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, .pm = gt215_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1157,7 +1157,7 @@ nva5_chipset = { .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, .pm = gt215_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1189,7 +1189,7 @@ nva8_chipset = { .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, .pm = gt215_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1220,7 +1220,7 @@ nvaa_chipset = { .msvld = g98_msvld_new, .pm = g84_pm_new, .sec = g98_sec_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1251,7 +1251,7 @@ nvac_chipset = { .msvld = g98_msvld_new, .pm = g84_pm_new, .sec = g98_sec_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1283,7 +1283,7 @@ nvaf_chipset = { .msppp = gt215_msppp_new, .msvld = mcp89_msvld_new, .pm = gt215_pm_new, -// .sw = nv50_sw_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1318,7 +1318,7 @@ nvc0_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf100_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1352,7 +1352,7 @@ nvc1_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf108_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1386,7 +1386,7 @@ nvc3_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf100_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1421,7 +1421,7 @@ nvc4_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf100_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1456,7 +1456,7 @@ nvc8_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf100_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1491,7 +1491,7 @@ nvce_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf100_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1525,7 +1525,7 @@ nvcf_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf100_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1557,7 +1557,7 @@ nvd7_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf117_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1591,7 +1591,7 @@ nvd9_chipset = { .msppp = gf100_msppp_new, .msvld = gf100_msvld_new, .pm = gf117_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1627,7 +1627,7 @@ nve4_chipset = { .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, .pm = gk104_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1663,7 +1663,7 @@ nve6_chipset = { .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, .pm = gk104_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1699,7 +1699,7 @@ nve7_chipset = { .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, .pm = gk104_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1723,7 +1723,7 @@ nvea_chipset = { .fifo = gk20a_fifo_new, .gr = gk20a_gr_new, .pm = gk104_pm_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1758,7 +1758,7 @@ nvf0_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1793,7 +1793,7 @@ nvf1_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1828,7 +1828,7 @@ nv106_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1863,7 +1863,7 @@ nv108_chipset = { .mspdec = gk104_mspdec_new, .msppp = gf100_msppp_new, .msvld = gk104_msvld_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1893,7 +1893,7 @@ nv117_chipset = { .dma = gf119_dma_new, .fifo = gk208_fifo_new, .gr = gm107_gr_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1922,7 +1922,7 @@ nv124_chipset = { .dma = gf119_dma_new, .fifo = gm204_fifo_new, .gr = gm204_gr_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1951,7 +1951,7 @@ nv126_chipset = { .dma = gf119_dma_new, .fifo = gm204_fifo_new, .gr = gm206_gr_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; static const struct nvkm_device_chip @@ -1972,7 +1972,7 @@ nv12b_chipset = { .dma = gf119_dma_new, .fifo = gm20b_fifo_new, .gr = gm20b_gr_new, -// .sw = gf100_sw_new, + .sw = gf100_sw_new, }; #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c index 67faff5d0b527..3c618162923d4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c @@ -28,31 +28,22 @@ gf100_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xc0: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xc4: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xc3: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xce: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xcf: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xc1: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xc8: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xd9: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xd7: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c index 3841dc0ac01b1..4476597187099 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c @@ -28,28 +28,20 @@ gk104_identify(struct nvkm_device *device) { switch (device->chipset) { case 0xe4: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xe7: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xe6: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xea: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xf0: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0xf1: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0x106: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; case 0x108: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c index 71e088abb620b..e0a214c0cb6eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c @@ -31,7 +31,6 @@ gm100_identify(struct nvkm_device *device) #if 0 #endif - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; #if 0 #endif #if 0 @@ -44,7 +43,6 @@ gm100_identify(struct nvkm_device *device) #endif #if 0 #endif - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; #if 0 #endif break; @@ -55,13 +53,11 @@ gm100_identify(struct nvkm_device *device) #endif #if 0 #endif - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; #if 0 #endif break; case 0x12b: - device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c index 7a8071be7ed0d..369992ba9c36c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c @@ -28,10 +28,8 @@ nv04_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x04: - device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; break; case 0x05: - device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c index 15dbd71ebabf0..233f9f9cfda96 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c @@ -30,25 +30,18 @@ nv10_identify(struct nvkm_device *device) case 0x10: break; case 0x15: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x16: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x1a: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x11: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x17: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x1f: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x18: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c index 158efa44054f5..d6204a954cbaf 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c @@ -28,16 +28,12 @@ nv20_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x20: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x25: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x28: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x2a: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 5a8fd485467a5..5fc9f1751801e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -28,21 +28,16 @@ nv30_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x30: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x35: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; break; case 0x31: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x36: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x34: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index 08c015b0e5a1d..cd6c836801cbb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,67 +28,51 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x41: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x42: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x43: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x45: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x47: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x49: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4b: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x44: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x46: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4a: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4c: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4e: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x63: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x67: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x68: - device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index c285f61ffd8f6..2e45927991772 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,54 +28,40 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; break; case 0x84: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x86: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x92: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x94: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x96: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x98: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; break; case 0xa0: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0xaa: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; break; case 0xac: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; break; case 0xa3: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0xa5: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; break; case 0xa8: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; break; case 0xaf: - device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c index efc18787490c2..53c1f7e75b54c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/base.c @@ -82,26 +82,29 @@ nvkm_sw_cclass_get(struct nvkm_fifo_chan *fifoch, return sw->func->chan_new(sw, fifoch, oclass, pobject); } +static void * +nvkm_sw_dtor(struct nvkm_engine *engine) +{ + return nvkm_sw(engine); +} + static const struct nvkm_engine_func nvkm_sw = { + .dtor = nvkm_sw_dtor, .fifo.cclass = nvkm_sw_cclass_get, .fifo.sclass = nvkm_sw_oclass_get, }; int -nvkm_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, int length, void **pobject) +nvkm_sw_new_(const struct nvkm_sw_func *func, struct nvkm_device *device, + int index, struct nvkm_sw **psw) { struct nvkm_sw *sw; - int ret; - ret = nvkm_engine_create_(parent, engine, oclass, true, "sw", - "sw", length, pobject); - sw = *pobject; - if (ret) - return ret; - - sw->engine.func = &nvkm_sw; + if (!(sw = *psw = kzalloc(sizeof(*sw), GFP_KERNEL))) + return -ENOMEM; INIT_LIST_HEAD(&sw->chan); - return 0; + sw->func = func; + + return nvkm_engine_ctor(&nvkm_sw, device, index, 0, true, &sw->engine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c index 5cd7844f1d5fa..b01ef7eca9065 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c @@ -140,7 +140,7 @@ gf100_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, ******************************************************************************/ static const struct nvkm_sw_func -gf100_sw_func = { +gf100_sw = { .chan_new = gf100_sw_chan_new, .sclass = { { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_GF100 } }, @@ -148,14 +148,8 @@ gf100_sw_func = { } }; -struct nvkm_oclass * -gf100_sw_oclass = &(struct nv50_sw_oclass) { - .base.handle = NV_ENGINE(SW, 0xc0), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, - .func = &gf100_sw_func, -}.base; +int +gf100_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) +{ + return nvkm_sw_new_(&gf100_sw, device, index, psw); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c index d8d9d48b66d28..445217ffa7911 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c @@ -122,12 +122,6 @@ nv04_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifo, * software engine/subdev functions ******************************************************************************/ -void -nv04_sw_intr(struct nvkm_subdev *subdev) -{ - nvkm_mask(subdev->device, 0x000100, 0x80000000, 0x00000000); -} - static const struct nvkm_sw_func nv04_sw = { .chan_new = nv04_sw_chan_new, @@ -137,31 +131,8 @@ nv04_sw = { } }; -static int -nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv04_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) { - struct nvkm_sw *sw; - int ret; - - ret = nvkm_sw_create(parent, engine, oclass, &sw); - *pobject = nv_object(sw); - if (ret) - return ret; - - sw->func = &nv04_sw; - nv_subdev(sw)->intr = nv04_sw_intr; - return 0; + return nvkm_sw_new_(&nv04_sw, device, index, psw); } - -struct nvkm_oclass * -nv04_sw_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(SW, 0x04), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv04_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c index 1b9fc1b1f69e7..adf70d92b2443 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c @@ -61,31 +61,8 @@ nv10_sw = { } }; -static int -nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv10_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) { - struct nvkm_sw *sw; - int ret; - - ret = nvkm_sw_create(parent, engine, oclass, &sw); - *pobject = nv_object(sw); - if (ret) - return ret; - - sw->func = &nv10_sw; - nv_subdev(sw)->intr = nv04_sw_intr; - return 0; + return nvkm_sw_new_(&nv10_sw, device, index, psw); } - -struct nvkm_oclass * -nv10_sw_oclass = &(struct nvkm_oclass) { - .handle = NV_ENGINE(SW, 0x10), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv10_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index a00d9a55e53b8..ef36ba18bff83 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -48,7 +48,7 @@ nv50_sw_chan_vblsem_release(struct nvkm_notify *notify) nvkm_wr32(device, 0x001710, 0x80000000 | chan->vblank.ctxdma); nvkm_bar_flush(device->bar); - if (nv_device(sw)->chipset == 0x50) { + if (device->chipset == 0x50) { nvkm_wr32(device, 0x001570, chan->vblank.offset); nvkm_wr32(device, 0x001574, chan->vblank.value); } else { @@ -133,27 +133,8 @@ nv50_sw_chan_new(struct nvkm_sw *sw, struct nvkm_fifo_chan *fifoch, * software engine/subdev functions ******************************************************************************/ -int -nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv50_sw_oclass *pclass = (void *)oclass; - struct nvkm_sw *sw; - int ret; - - ret = nvkm_sw_create(parent, engine, oclass, &sw); - *pobject = nv_object(sw); - if (ret) - return ret; - - sw->func = pclass->func; - nv_subdev(sw)->intr = nv04_sw_intr; - return 0; -} - static const struct nvkm_sw_func -nv50_sw_func = { +nv50_sw = { .chan_new = nv50_sw_chan_new, .sclass = { { nvkm_nvsw_new, { -1, -1, NVIF_IOCTL_NEW_V0_SW_NV50 } }, @@ -161,14 +142,8 @@ nv50_sw_func = { } }; -struct nvkm_oclass * -nv50_sw_oclass = &(struct nv50_sw_oclass) { - .base.handle = NV_ENGINE(SW, 0x50), - .base.ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_sw_ctor, - .dtor = _nvkm_sw_dtor, - .init = _nvkm_sw_init, - .fini = _nvkm_sw_fini, - }, - .func = &nv50_sw_func, -}.base; +int +nv50_sw_new(struct nvkm_device *device, int index, struct nvkm_sw **psw) +{ + return nvkm_sw_new_(&nv50_sw, device, index, psw); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h index c90a470564e26..25cdfdef2d461 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h @@ -6,21 +6,6 @@ #include "nvsw.h" #include -struct nv50_sw_oclass { - struct nvkm_oclass base; - const struct nvkm_sw_func *func; -}; - -int nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -struct nv50_sw_cclass { - struct nvkm_oclass base; - int (*vblank)(struct nvkm_notify *); - const struct nvkm_sw_chan_func *chan; -}; - struct nv50_sw_chan { struct nvkm_sw_chan base; struct { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c index 6652a9196753c..66cf986b9572c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nvsw.c @@ -27,18 +27,19 @@ #include static int -nvkm_nvsw_mthd_(struct nvkm_object *base, u32 mthd, void *data, u32 size) +nvkm_nvsw_mthd_(struct nvkm_object *object, u32 mthd, void *data, u32 size) { - struct nvkm_nvsw *nvsw = nvkm_nvsw(base); + struct nvkm_nvsw *nvsw = nvkm_nvsw(object); if (nvsw->func->mthd) return nvsw->func->mthd(nvsw, mthd, data, size); return -ENODEV; } static int -nvkm_nvsw_ntfy_(struct nvkm_object *base, u32 mthd, struct nvkm_event **pevent) +nvkm_nvsw_ntfy_(struct nvkm_object *object, u32 mthd, + struct nvkm_event **pevent) { - struct nvkm_nvsw *nvsw = nvkm_nvsw(base); + struct nvkm_nvsw *nvsw = nvkm_nvsw(object); switch (mthd) { case NVSW_NTFY_UEVENT: *pevent = &nvsw->chan->event; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h index ae610a32ef5ad..0ef1318dc2fde 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/priv.h @@ -4,6 +4,9 @@ #include struct nvkm_sw_chan; +int nvkm_sw_new_(const struct nvkm_sw_func *, struct nvkm_device *, + int index, struct nvkm_sw **); + struct nvkm_sw_chan_sclass { int (*ctor)(struct nvkm_sw_chan *, const struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **); -- GitLab From 7624fc011e56902a83e409b14d6c1efa75aa4a58 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5559/7006] drm/nouveau/mpeg: convert to new-style nvkm_engine Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/engine.h | 2 - .../drm/nouveau/include/nvkm/engine/mpeg.h | 39 +----- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 54 ++++---- .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 3 - .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 16 --- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 8 -- .../gpu/drm/nouveau/nvkm/engine/mpeg/g84.c | 34 +---- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 130 ++++++++---------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h | 11 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c | 57 +------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c | 79 ++++------- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c | 85 +++--------- .../gpu/drm/nouveau/nvkm/engine/mpeg/priv.h | 7 + drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c | 4 +- 14 files changed, 166 insertions(+), 363 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 9c8c393247155..8c47ab210c06f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -19,8 +19,6 @@ struct nvkm_engine { struct list_head contexts; spinlock_t lock; - - void (*tile_prog)(struct nvkm_engine *, int region); }; struct nvkm_engine_func { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h index 029fd0c28d22f..257738eff9f62 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h @@ -1,38 +1,9 @@ #ifndef __NVKM_MPEG_H__ #define __NVKM_MPEG_H__ #include - -struct nvkm_mpeg { - struct nvkm_engine engine; -}; - -#define nvkm_mpeg_create(p,e,c,d) \ - nvkm_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d)) -#define nvkm_mpeg_destroy(d) \ - nvkm_engine_destroy(&(d)->engine) -#define nvkm_mpeg_init(d) \ - nvkm_engine_init_old(&(d)->engine) -#define nvkm_mpeg_fini(d,s) \ - nvkm_engine_fini_old(&(d)->engine, (s)) - -#define _nvkm_mpeg_dtor _nvkm_engine_dtor -#define _nvkm_mpeg_init _nvkm_engine_init -#define _nvkm_mpeg_fini _nvkm_engine_fini - -extern struct nvkm_oclass nv31_mpeg_oclass; -extern struct nvkm_oclass nv40_mpeg_oclass; -extern struct nvkm_oclass nv44_mpeg_oclass; -extern struct nvkm_oclass nv50_mpeg_oclass; -extern struct nvkm_oclass g84_mpeg_oclass; -extern struct nvkm_oclass nv40_mpeg_sclass[]; -void nv31_mpeg_intr(struct nvkm_subdev *); -void nv31_mpeg_tile_prog(struct nvkm_engine *, int); -int nv31_mpeg_init(struct nvkm_object *); - -extern struct nvkm_ofuncs nv50_mpeg_ofuncs; -int nv50_mpeg_context_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); -void nv50_mpeg_intr(struct nvkm_subdev *); -int nv50_mpeg_init(struct nvkm_object *); +int nv31_mpeg_new(struct nvkm_device *, int index, struct nvkm_engine **); +int nv40_mpeg_new(struct nvkm_device *, int index, struct nvkm_engine **); +int nv44_mpeg_new(struct nvkm_device *, int index, struct nvkm_engine **); +int nv50_mpeg_new(struct nvkm_device *, int index, struct nvkm_engine **); +int g84_mpeg_new(struct nvkm_device *, int index, struct nvkm_engine **); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 302122c059b51..48cc06372c9c9 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -381,7 +381,7 @@ nv31_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv30_gr_new, -// .mpeg = nv31_mpeg_new, + .mpeg = nv31_mpeg_new, .sw = nv10_sw_new, }; @@ -403,7 +403,7 @@ nv34_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv34_gr_new, -// .mpeg = nv31_mpeg_new, + .mpeg = nv31_mpeg_new, .sw = nv10_sw_new, }; @@ -446,7 +446,7 @@ nv36_chipset = { .dma = nv04_dma_new, .fifo = nv17_fifo_new, .gr = nv35_gr_new, -// .mpeg = nv31_mpeg_new, + .mpeg = nv31_mpeg_new, .sw = nv10_sw_new, }; @@ -470,7 +470,7 @@ nv40_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv40_mpeg_new, + .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -495,7 +495,7 @@ nv41_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv40_mpeg_new, + .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -520,7 +520,7 @@ nv42_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv40_mpeg_new, + .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -545,7 +545,7 @@ nv43_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv40_mpeg_new, + .mpeg = nv40_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -570,7 +570,7 @@ nv44_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -595,7 +595,7 @@ nv45_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -620,7 +620,7 @@ nv46_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -645,7 +645,7 @@ nv47_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -670,7 +670,7 @@ nv49_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -695,7 +695,7 @@ nv4a_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -720,7 +720,7 @@ nv4b_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv40_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -745,7 +745,7 @@ nv4c_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -770,7 +770,7 @@ nv4e_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -798,7 +798,7 @@ nv50_chipset = { .dma = nv50_dma_new, .fifo = nv50_fifo_new, .gr = nv50_gr_new, -// .mpeg = nv50_mpeg_new, + .mpeg = nv50_mpeg_new, .pm = nv50_pm_new, .sw = nv50_sw_new, }; @@ -823,7 +823,7 @@ nv63_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -848,7 +848,7 @@ nv67_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -873,7 +873,7 @@ nv68_chipset = { .dma = nv04_dma_new, .fifo = nv40_fifo_new, .gr = nv44_gr_new, -// .mpeg = nv44_mpeg_new, + .mpeg = nv44_mpeg_new, .pm = nv40_pm_new, .sw = nv10_sw_new, }; @@ -903,7 +903,7 @@ nv84_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = g84_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .pm = g84_pm_new, .sw = nv50_sw_new, .vp = g84_vp_new, @@ -934,7 +934,7 @@ nv86_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = g84_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .pm = g84_pm_new, .sw = nv50_sw_new, .vp = g84_vp_new, @@ -965,7 +965,7 @@ nv92_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = g84_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .pm = g84_pm_new, .sw = nv50_sw_new, .vp = g84_vp_new, @@ -996,7 +996,7 @@ nv94_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = g84_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .pm = g84_pm_new, .sw = nv50_sw_new, .vp = g84_vp_new, @@ -1025,7 +1025,7 @@ nv96_chipset = { .fifo = g84_fifo_new, .gr = g84_gr_new, .gr = nv50_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .vp = g84_vp_new, .cipher = g84_cipher_new, .bsp = g84_bsp_new, @@ -1089,7 +1089,7 @@ nva0_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = gt200_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .pm = gt200_pm_new, .sw = nv50_sw_new, .vp = g84_vp_new, @@ -1120,7 +1120,7 @@ nva3_chipset = { .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = gt215_gr_new, -// .mpeg = g84_mpeg_new, + .mpeg = g84_mpeg_new, .mspdec = gt215_mspdec_new, .msppp = gt215_msppp_new, .msvld = gt215_msvld_new, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c index 5fc9f1751801e..1787f3558d717 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c @@ -32,13 +32,10 @@ nv30_identify(struct nvkm_device *device) case 0x35: break; case 0x31: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x36: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; case 0x34: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c index cd6c836801cbb..d40e18693a730 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c @@ -28,52 +28,36 @@ nv40_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x40: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x41: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x42: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x43: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass; break; case 0x45: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x47: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x49: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4b: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x44: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x46: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4a: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4c: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x4e: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x63: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x67: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; case 0x68: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass; break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c index 2e45927991772..8ca1368e10682 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c @@ -28,34 +28,26 @@ nv50_identify(struct nvkm_device *device) { switch (device->chipset) { case 0x50: - device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass; break; case 0x84: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x86: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x92: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x94: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x96: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0x98: break; case 0xa0: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0xaa: break; case 0xac: break; case 0xa3: - device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass; break; case 0xa5: break; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c index c72fd75cd8cf6..34ff0014a6c1f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c @@ -27,6 +27,8 @@ static const struct nvkm_engine_func g84_mpeg = { + .init = nv50_mpeg_init, + .intr = nv50_mpeg_intr, .cclass = &nv50_mpeg_cclass, .sclass = { { -1, -1, G82_MPEG, &nv31_mpeg_object }, @@ -34,33 +36,9 @@ g84_mpeg = { } }; -static int -g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +g84_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) { - struct nvkm_mpeg *mpeg; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); - *pobject = nv_object(mpeg); - if (ret) - return ret; - - mpeg->engine.func = &g84_mpeg; - - nv_subdev(mpeg)->unit = 0x00000002; - nv_subdev(mpeg)->intr = nv50_mpeg_intr; - return 0; + return nvkm_engine_new_(&g84_mpeg, device, index, 0x00000002, + true, pmpeg); } - -struct nvkm_oclass -g84_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x84), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = g84_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv50_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index f79749946b72c..87420b8329ac2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -68,10 +68,10 @@ nv31_mpeg_chan_dtor(struct nvkm_object *object) struct nv31_mpeg *mpeg = chan->mpeg; unsigned long flags; - spin_lock_irqsave(&mpeg->base.engine.lock, flags); + spin_lock_irqsave(&mpeg->engine.lock, flags); if (mpeg->chan == chan) mpeg->chan = NULL; - spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); return chan; } @@ -97,12 +97,12 @@ nv31_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, chan->fifo = fifoch; *pobject = &chan->object; - spin_lock_irqsave(&mpeg->base.engine.lock, flags); + spin_lock_irqsave(&mpeg->engine.lock, flags); if (!mpeg->chan) { mpeg->chan = chan; ret = 0; } - spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); return ret; } @@ -111,11 +111,10 @@ nv31_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, ******************************************************************************/ void -nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i) +nv31_mpeg_tile(struct nvkm_engine *engine, int i, struct nvkm_fb_tile *tile) { - struct nv31_mpeg *mpeg = (void *)engine; - struct nvkm_device *device = mpeg->base.engine.subdev.device; - struct nvkm_fb_tile *tile = &device->fb->tile.region[i]; + struct nv31_mpeg *mpeg = nv31_mpeg(engine); + struct nvkm_device *device = mpeg->engine.subdev.device; nvkm_wr32(device, 0x00b008 + (i * 0x10), tile->pitch); nvkm_wr32(device, 0x00b004 + (i * 0x10), tile->limit); @@ -164,23 +163,24 @@ nv31_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) static bool nv31_mpeg_mthd(struct nv31_mpeg *mpeg, u32 mthd, u32 data) { - struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_device *device = mpeg->engine.subdev.device; switch (mthd) { case 0x190: case 0x1a0: case 0x1b0: - return mpeg->mthd_dma(device, mthd, data); + return mpeg->func->mthd_dma(device, mthd, data); default: break; } return false; } -void -nv31_mpeg_intr(struct nvkm_subdev *subdev) +static void +nv31_mpeg_intr(struct nvkm_engine *engine) { - struct nv31_mpeg *mpeg = (void *)subdev; - struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nv31_mpeg *mpeg = nv31_mpeg(engine); + struct nvkm_subdev *subdev = &mpeg->engine.subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x00b100); u32 type = nvkm_rd32(device, 0x00b230); u32 mthd = nvkm_rd32(device, 0x00b234); @@ -188,7 +188,7 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) u32 show = stat; unsigned long flags; - spin_lock_irqsave(&mpeg->base.engine.lock, flags); + spin_lock_irqsave(&mpeg->engine.lock, flags); if (stat & 0x01000000) { /* happens on initial binding of the object */ @@ -213,61 +213,19 @@ nv31_mpeg_intr(struct nvkm_subdev *subdev) "unknown", stat, type, mthd, data); } - spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); -} - -static const struct nvkm_engine_func -nv31_mpeg = { - .fifo.cclass = nv31_mpeg_chan_new, - .sclass = { - { -1, -1, NV31_MPEG, &nv31_mpeg_object }, - {} - } -}; - -static int -nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nv31_mpeg *mpeg; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); - *pobject = nv_object(mpeg); - if (ret) - return ret; - - mpeg->base.engine.func = &nv31_mpeg; - - mpeg->mthd_dma = nv31_mpeg_mthd_dma; - nv_subdev(mpeg)->unit = 0x00000002; - nv_subdev(mpeg)->intr = nv31_mpeg_intr; - nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; - return 0; + spin_unlock_irqrestore(&mpeg->engine.lock, flags); } int -nv31_mpeg_init(struct nvkm_object *object) +nv31_mpeg_init(struct nvkm_engine *mpeg) { - struct nvkm_engine *engine = nv_engine(object); - struct nv31_mpeg *mpeg = (void *)object; - struct nvkm_subdev *subdev = &mpeg->base.engine.subdev; + struct nvkm_subdev *subdev = &mpeg->subdev; struct nvkm_device *device = subdev->device; - struct nvkm_fb *fb = device->fb; - int ret, i; - - ret = nvkm_mpeg_init(&mpeg->base); - if (ret) - return ret; /* VPE init */ nvkm_wr32(device, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ nvkm_wr32(device, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */ - for (i = 0; i < fb->tile.regions; i++) - engine->tile_prog(engine, i); - /* PMPEG init */ nvkm_wr32(device, 0x00b32c, 0x00000000); nvkm_wr32(device, 0x00b314, 0x00000100); @@ -290,13 +248,47 @@ nv31_mpeg_init(struct nvkm_object *object) return 0; } -struct nvkm_oclass -nv31_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x31), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv31_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv31_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, +static void * +nv31_mpeg_dtor(struct nvkm_engine *engine) +{ + return nv31_mpeg(engine); +} + +static const struct nvkm_engine_func +nv31_mpeg_ = { + .dtor = nv31_mpeg_dtor, + .init = nv31_mpeg_init, + .intr = nv31_mpeg_intr, + .tile = nv31_mpeg_tile, + .fifo.cclass = nv31_mpeg_chan_new, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } }; + +int +nv31_mpeg_new_(const struct nv31_mpeg_func *func, struct nvkm_device *device, + int index, struct nvkm_engine **pmpeg) +{ + struct nv31_mpeg *mpeg; + + if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) + return -ENOMEM; + mpeg->func = func; + *pmpeg = &mpeg->engine; + + return nvkm_engine_ctor(&nv31_mpeg_, device, index, 0x00000002, + true, &mpeg->engine); +} + +static const struct nv31_mpeg_func +nv31_mpeg = { + .mthd_dma = nv31_mpeg_mthd_dma, +}; + +int +nv31_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) +{ + return nv31_mpeg_new_(&nv31_mpeg, device, index, pmpeg); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h index a2dae83fbc71a..d3bb34fcdebfe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h @@ -1,12 +1,19 @@ #ifndef __NV31_MPEG_H__ #define __NV31_MPEG_H__ -#define nv31_mpeg(p) container_of((p), struct nv31_mpeg, base.engine) +#define nv31_mpeg(p) container_of((p), struct nv31_mpeg, engine) #include "priv.h" #include struct nv31_mpeg { - struct nvkm_mpeg base; + const struct nv31_mpeg_func *func; + struct nvkm_engine engine; struct nv31_mpeg_chan *chan; +}; + +int nv31_mpeg_new_(const struct nv31_mpeg_func *, struct nvkm_device *, + int index, struct nvkm_engine **); + +struct nv31_mpeg_func { bool (*mthd_dma)(struct nvkm_device *, u32 mthd, u32 data); }; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c index 97529c4f0a25e..16de5bd94b143 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c @@ -65,60 +65,13 @@ nv40_mpeg_mthd_dma(struct nvkm_device *device, u32 mthd, u32 data) return true; } -static void -nv40_mpeg_intr(struct nvkm_subdev *subdev) -{ - struct nv31_mpeg *mpeg = (void *)subdev; - struct nvkm_device *device = mpeg->base.engine.subdev.device; - u32 stat; - - if ((stat = nvkm_rd32(device, 0x00b100))) - nv31_mpeg_intr(subdev); - - if ((stat = nvkm_rd32(device, 0x00b800))) { - nvkm_error(subdev, "PMSRCH %08x\n", stat); - nvkm_wr32(device, 0x00b800, stat); - } -} - -static const struct nvkm_engine_func +static const struct nv31_mpeg_func nv40_mpeg = { - .fifo.cclass = nv31_mpeg_chan_new, - .sclass = { - { -1, -1, NV31_MPEG, &nv31_mpeg_object }, - {} - } + .mthd_dma = nv40_mpeg_mthd_dma, }; -static int -nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv40_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) { - struct nv31_mpeg *mpeg; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); - *pobject = nv_object(mpeg); - if (ret) - return ret; - - mpeg->base.engine.func = &nv40_mpeg; - - mpeg->mthd_dma = nv40_mpeg_mthd_dma; - nv_subdev(mpeg)->unit = 0x00000002; - nv_subdev(mpeg)->intr = nv40_mpeg_intr; - nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; - return 0; + return nv31_mpeg_new_(&nv40_mpeg, device, index, pmpeg); } - -struct nvkm_oclass -nv40_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x40), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv40_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv31_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c index d1b914b43cee4..d433cfa4a8ab4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c @@ -21,7 +21,7 @@ * * Authors: Ben Skeggs */ -#define nv44_mpeg(p) container_of((p), struct nv44_mpeg, base.engine) +#define nv44_mpeg(p) container_of((p), struct nv44_mpeg, engine) #include "priv.h" #include @@ -31,12 +31,10 @@ #include struct nv44_mpeg { - struct nvkm_mpeg base; + struct nvkm_engine engine; struct list_head chan; }; -bool nv40_mpeg_mthd_dma(struct nvkm_device *, u32, u32); - /******************************************************************************* * PMPEG context ******************************************************************************/ @@ -72,7 +70,7 @@ nv44_mpeg_chan_fini(struct nvkm_object *object, bool suspend) struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); struct nv44_mpeg *mpeg = chan->mpeg; - struct nvkm_device *device = mpeg->base.engine.subdev.device; + struct nvkm_device *device = mpeg->engine.subdev.device; u32 inst = 0x80000000 | (chan->inst >> 4); nvkm_mask(device, 0x00b32c, 0x00000001, 0x00000000); @@ -88,9 +86,9 @@ nv44_mpeg_chan_dtor(struct nvkm_object *object) struct nv44_mpeg_chan *chan = nv44_mpeg_chan(object); struct nv44_mpeg *mpeg = chan->mpeg; unsigned long flags; - spin_lock_irqsave(&mpeg->base.engine.lock, flags); + spin_lock_irqsave(&mpeg->engine.lock, flags); list_del(&chan->head); - spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); return chan; } @@ -117,9 +115,9 @@ nv44_mpeg_chan_new(struct nvkm_fifo_chan *fifoch, chan->fifo = fifoch; *pobject = &chan->object; - spin_lock_irqsave(&mpeg->base.engine.lock, flags); + spin_lock_irqsave(&mpeg->engine.lock, flags); list_add(&chan->head, &mpeg->chan); - spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); + spin_unlock_irqrestore(&mpeg->engine.lock, flags); return 0; } @@ -142,11 +140,12 @@ nv44_mpeg_mthd(struct nvkm_device *device, u32 mthd, u32 data) } static void -nv44_mpeg_intr(struct nvkm_subdev *subdev) +nv44_mpeg_intr(struct nvkm_engine *engine) { - struct nv44_mpeg *mpeg = (void *)subdev; + struct nv44_mpeg *mpeg = nv44_mpeg(engine); + struct nvkm_subdev *subdev = &mpeg->engine.subdev; + struct nvkm_device *device = subdev->device; struct nv44_mpeg_chan *temp, *chan = NULL; - struct nvkm_device *device = mpeg->base.engine.subdev.device; unsigned long flags; u32 inst = nvkm_rd32(device, 0x00b318) & 0x000fffff; u32 stat = nvkm_rd32(device, 0x00b100); @@ -155,7 +154,7 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) u32 data = nvkm_rd32(device, 0x00b238); u32 show = stat; - spin_lock_irqsave(&mpeg->base.engine.lock, flags); + spin_lock_irqsave(&mpeg->engine.lock, flags); list_for_each_entry(temp, &mpeg->chan, head) { if (temp->inst >> 4 == inst) { chan = temp; @@ -188,27 +187,14 @@ nv44_mpeg_intr(struct nvkm_subdev *subdev) stat, type, mthd, data); } - spin_unlock_irqrestore(&mpeg->base.engine.lock, flags); -} - -static void -nv44_mpeg_me_intr(struct nvkm_subdev *subdev) -{ - struct nvkm_mpeg *mpeg = (void *)subdev; - struct nvkm_device *device = mpeg->engine.subdev.device; - u32 stat; - - if ((stat = nvkm_rd32(device, 0x00b100))) - nv44_mpeg_intr(subdev); - - if ((stat = nvkm_rd32(device, 0x00b800))) { - nvkm_error(subdev, "PMSRCH %08x\n", stat); - nvkm_wr32(device, 0x00b800, stat); - } + spin_unlock_irqrestore(&mpeg->engine.lock, flags); } static const struct nvkm_engine_func nv44_mpeg = { + .init = nv31_mpeg_init, + .intr = nv44_mpeg_intr, + .tile = nv31_mpeg_tile, .fifo.cclass = nv44_mpeg_chan_new, .sclass = { { -1, -1, NV31_MPEG, &nv31_mpeg_object }, @@ -216,35 +202,16 @@ nv44_mpeg = { } }; -static int -nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) +int +nv44_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) { struct nv44_mpeg *mpeg; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); - *pobject = nv_object(mpeg); - if (ret) - return ret; + if (!(mpeg = kzalloc(sizeof(*mpeg), GFP_KERNEL))) + return -ENOMEM; INIT_LIST_HEAD(&mpeg->chan); - mpeg->base.engine.func = &nv44_mpeg; + *pmpeg = &mpeg->engine; - nv_subdev(mpeg)->unit = 0x00000002; - nv_subdev(mpeg)->intr = nv44_mpeg_me_intr; - nv_engine(mpeg)->tile_prog = nv31_mpeg_tile_prog; - return 0; + return nvkm_engine_ctor(&nv44_mpeg, device, index, 0x00000002, + true, &mpeg->engine); } - -struct nvkm_oclass -nv44_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x44), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv44_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv31_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, -}; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c index a94c73e08ae36..c3a85dffc7822 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c @@ -57,10 +57,10 @@ nv50_mpeg_cclass = { ******************************************************************************/ void -nv50_mpeg_intr(struct nvkm_subdev *subdev) +nv50_mpeg_intr(struct nvkm_engine *mpeg) { - struct nvkm_mpeg *mpeg = (void *)subdev; - struct nvkm_device *device = mpeg->engine.subdev.device; + struct nvkm_subdev *subdev = &mpeg->subdev; + struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x00b100); u32 type = nvkm_rd32(device, 0x00b230); u32 mthd = nvkm_rd32(device, 0x00b234); @@ -84,61 +84,11 @@ nv50_mpeg_intr(struct nvkm_subdev *subdev) nvkm_wr32(device, 0x00b230, 0x00000001); } -static void -nv50_vpe_intr(struct nvkm_subdev *subdev) -{ - struct nvkm_device *device = subdev->device; - - if (nvkm_rd32(device, 0x00b100)) - nv50_mpeg_intr(subdev); - - if (nvkm_rd32(device, 0x00b800)) { - u32 stat = nvkm_rd32(device, 0x00b800); - nvkm_info(subdev, "PMSRCH: %08x\n", stat); - nvkm_wr32(device, 0xb800, stat); - } -} - -static const struct nvkm_engine_func -nv50_mpeg = { - .cclass = &nv50_mpeg_cclass, - .sclass = { - { -1, -1, NV31_MPEG, &nv31_mpeg_object }, - {} - } -}; - -static int -nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_mpeg *mpeg; - int ret; - - ret = nvkm_mpeg_create(parent, engine, oclass, &mpeg); - *pobject = nv_object(mpeg); - if (ret) - return ret; - - mpeg->engine.func = &nv50_mpeg; - - nv_subdev(mpeg)->unit = 0x00400002; - nv_subdev(mpeg)->intr = nv50_vpe_intr; - return 0; -} - int -nv50_mpeg_init(struct nvkm_object *object) +nv50_mpeg_init(struct nvkm_engine *mpeg) { - struct nvkm_mpeg *mpeg = (void *)object; - struct nvkm_subdev *subdev = &mpeg->engine.subdev; + struct nvkm_subdev *subdev = &mpeg->subdev; struct nvkm_device *device = subdev->device; - int ret; - - ret = nvkm_mpeg_init(mpeg); - if (ret) - return ret; nvkm_wr32(device, 0x00b32c, 0x00000000); nvkm_wr32(device, 0x00b314, 0x00000100); @@ -166,13 +116,20 @@ nv50_mpeg_init(struct nvkm_object *object) return 0; } -struct nvkm_oclass -nv50_mpeg_oclass = { - .handle = NV_ENGINE(MPEG, 0x50), - .ofuncs = &(struct nvkm_ofuncs) { - .ctor = nv50_mpeg_ctor, - .dtor = _nvkm_mpeg_dtor, - .init = nv50_mpeg_init, - .fini = _nvkm_mpeg_fini, - }, +static const struct nvkm_engine_func +nv50_mpeg = { + .init = nv50_mpeg_init, + .intr = nv50_mpeg_intr, + .cclass = &nv50_mpeg_cclass, + .sclass = { + { -1, -1, NV31_MPEG, &nv31_mpeg_object }, + {} + } }; + +int +nv50_mpeg_new(struct nvkm_device *device, int index, struct nvkm_engine **pmpeg) +{ + return nvkm_engine_new_(&nv50_mpeg, device, index, 0x00400002, + true, pmpeg); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h index 8b31ecabb5280..d5753103ff63f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/priv.h @@ -3,7 +3,14 @@ #include struct nvkm_fifo_chan; +int nv31_mpeg_init(struct nvkm_engine *); +void nv31_mpeg_tile(struct nvkm_engine *, int, struct nvkm_fb_tile *); extern const struct nvkm_object_func nv31_mpeg_object; +bool nv40_mpeg_mthd_dma(struct nvkm_device *, u32, u32); + +int nv50_mpeg_init(struct nvkm_engine *); +void nv50_mpeg_intr(struct nvkm_engine *); + extern const struct nvkm_object_func nv50_mpeg_cclass; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c index 1ca02f870095c..a719b9becb730 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c @@ -56,8 +56,8 @@ nvkm_fb_tile_prog(struct nvkm_fb *fb, int region, struct nvkm_fb_tile *tile) fb->func->tile.prog(fb, region, tile); if (device->gr) nvkm_engine_tile(&device->gr->engine, region); - if (likely(device->mpeg)) - device->mpeg->tile_prog(device->mpeg, region); + if (device->mpeg) + nvkm_engine_tile(device->mpeg, region); } } -- GitLab From 68f3f702b6a430a8d1e909455a60d26c0f2da530 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5560/7006] drm/nouveau/core: remove the remainder of the previous style Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/device.h | 6 +- .../drm/nouveau/include/nvkm/core/device.h | 110 ++++---- .../drm/nouveau/include/nvkm/core/engine.h | 52 +--- .../drm/nouveau/include/nvkm/core/gpuobj.h | 37 +-- .../drm/nouveau/include/nvkm/core/object.h | 88 +------ .../drm/nouveau/include/nvkm/core/subdev.h | 51 +--- .../drm/nouveau/include/nvkm/engine/fifo.h | 4 +- .../gpu/drm/nouveau/include/nvkm/subdev/mmu.h | 2 +- drivers/gpu/drm/nouveau/nvkm/core/engine.c | 79 +----- drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c | 93 ------- drivers/gpu/drm/nouveau/nvkm/core/object.c | 167 +----------- drivers/gpu/drm/nouveau/nvkm/core/oproxy.c | 2 - drivers/gpu/drm/nouveau/nvkm/core/ramht.c | 45 ++-- drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 223 ++++------------ .../gpu/drm/nouveau/nvkm/engine/ce/gf100.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/ce/gk104.c | 8 +- .../gpu/drm/nouveau/nvkm/engine/ce/gm204.c | 6 +- .../gpu/drm/nouveau/nvkm/engine/ce/gt215.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/cipher/g84.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/device/Kbuild | 10 - .../gpu/drm/nouveau/nvkm/engine/device/base.c | 241 ++++-------------- .../drm/nouveau/nvkm/engine/device/gf100.c | 53 ---- .../drm/nouveau/nvkm/engine/device/gk104.c | 51 ---- .../drm/nouveau/nvkm/engine/device/gm100.c | 67 ----- .../gpu/drm/nouveau/nvkm/engine/device/nv04.c | 39 --- .../gpu/drm/nouveau/nvkm/engine/device/nv10.c | 51 ---- .../gpu/drm/nouveau/nvkm/engine/device/nv20.c | 43 ---- .../gpu/drm/nouveau/nvkm/engine/device/nv30.c | 45 ---- .../gpu/drm/nouveau/nvkm/engine/device/nv40.c | 67 ----- .../gpu/drm/nouveau/nvkm/engine/device/nv50.c | 63 ----- .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 10 - .../gpu/drm/nouveau/nvkm/engine/device/user.c | 8 +- .../drm/nouveau/nvkm/engine/disp/dmacnv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 2 +- .../drm/nouveau/nvkm/engine/fifo/chang84.c | 105 ++++---- .../drm/nouveau/nvkm/engine/fifo/changf100.h | 2 +- .../drm/nouveau/nvkm/engine/fifo/changk104.h | 2 +- .../drm/nouveau/nvkm/engine/fifo/channv04.h | 2 +- .../drm/nouveau/nvkm/engine/fifo/channv50.c | 34 +-- .../drm/nouveau/nvkm/engine/fifo/channv50.h | 2 +- .../drm/nouveau/nvkm/engine/fifo/dmanv04.c | 14 +- .../drm/nouveau/nvkm/engine/fifo/dmanv10.c | 6 +- .../drm/nouveau/nvkm/engine/fifo/dmanv17.c | 8 +- .../drm/nouveau/nvkm/engine/fifo/dmanv40.c | 34 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 50 ++-- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 34 +-- .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.h | 36 +-- .../nouveau/nvkm/engine/fifo/gpfifogf100.c | 34 +-- .../nouveau/nvkm/engine/fifo/gpfifogk104.c | 22 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/devinit/g84.c | 14 +- .../gpu/drm/nouveau/nvkm/subdev/devinit/g98.c | 12 +- .../drm/nouveau/nvkm/subdev/devinit/gf100.c | 14 +- .../drm/nouveau/nvkm/subdev/devinit/gm107.c | 6 +- .../drm/nouveau/nvkm/subdev/devinit/gt215.c | 10 +- .../drm/nouveau/nvkm/subdev/devinit/mcp89.c | 12 +- .../drm/nouveau/nvkm/subdev/devinit/nv50.c | 4 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c | 32 +-- .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 40 +-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c | 20 +- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 26 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c | 26 +- 68 files changed, 496 insertions(+), 1856 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 5723102232963..900e492549d16 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -48,7 +48,11 @@ u64 nvif_device_time(struct nvif_device *); #define nvxx_device(a) ({ \ struct nvif_device *_device = (a); \ - nv_device(_device->object.priv); \ + struct { \ + struct nvkm_object object; \ + struct nvkm_device *device; \ + } *_udevice = _device->object.priv; \ + _udevice->device; \ }) #define nvxx_bios(a) nvxx_device(a)->bios #define nvxx_fb(a) nvxx_device(a)->fb diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 1d72d670bed27..8ef8058ed0313 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -1,70 +1,55 @@ #ifndef __NVKM_DEVICE_H__ #define __NVKM_DEVICE_H__ -#include #include +#include enum nvkm_devidx { - NVDEV_SUBDEV_VBIOS, - - /* All subdevs from DEVINIT to DEVINIT_LAST will be created before - * *any* of them are initialised. This subdev category is used - * for any subdevs that the VBIOS init table parsing may call out - * to during POST. - */ - NVDEV_SUBDEV_DEVINIT, - NVDEV_SUBDEV_IBUS, - NVDEV_SUBDEV_GPIO, - NVDEV_SUBDEV_I2C, - NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C, - - /* This grouping of subdevs are initialised right after they've - * been created, and are allowed to assume any subdevs in the - * list above them exist and have been initialised. - */ - NVDEV_SUBDEV_FUSE, - NVDEV_SUBDEV_MXM, - NVDEV_SUBDEV_MC, - NVDEV_SUBDEV_BUS, - NVDEV_SUBDEV_TIMER, - NVDEV_SUBDEV_FB, - NVDEV_SUBDEV_LTC, - NVDEV_SUBDEV_INSTMEM, - NVDEV_SUBDEV_MMU, - NVDEV_SUBDEV_BAR, - NVDEV_SUBDEV_PMU, - NVDEV_SUBDEV_VOLT, - NVDEV_SUBDEV_THERM, - NVDEV_SUBDEV_CLK, - - NVDEV_ENGINE_FIRST, - NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST, - NVDEV_ENGINE_IFB, - NVDEV_ENGINE_FIFO, - NVDEV_ENGINE_SW, - NVDEV_ENGINE_GR, - NVDEV_ENGINE_MPEG, - NVDEV_ENGINE_ME, - NVDEV_ENGINE_VP, - NVDEV_ENGINE_CIPHER, - NVDEV_ENGINE_BSP, - NVDEV_ENGINE_MSPPP, - NVDEV_ENGINE_CE0, - NVDEV_ENGINE_CE1, - NVDEV_ENGINE_CE2, - NVDEV_ENGINE_VIC, - NVDEV_ENGINE_MSENC, - NVDEV_ENGINE_DISP, - NVDEV_ENGINE_PM, - NVDEV_ENGINE_MSVLD, - NVDEV_ENGINE_SEC, - NVDEV_ENGINE_MSPDEC, - - NVDEV_SUBDEV_NR, + NVKM_SUBDEV_VBIOS, + NVKM_SUBDEV_DEVINIT, + NVKM_SUBDEV_IBUS, + NVKM_SUBDEV_GPIO, + NVKM_SUBDEV_I2C, + NVKM_SUBDEV_FUSE, + NVKM_SUBDEV_MXM, + NVKM_SUBDEV_MC, + NVKM_SUBDEV_BUS, + NVKM_SUBDEV_TIMER, + NVKM_SUBDEV_FB, + NVKM_SUBDEV_LTC, + NVKM_SUBDEV_INSTMEM, + NVKM_SUBDEV_MMU, + NVKM_SUBDEV_BAR, + NVKM_SUBDEV_PMU, + NVKM_SUBDEV_VOLT, + NVKM_SUBDEV_THERM, + NVKM_SUBDEV_CLK, + + NVKM_ENGINE_DMAOBJ, + NVKM_ENGINE_IFB, + NVKM_ENGINE_FIFO, + NVKM_ENGINE_SW, + NVKM_ENGINE_GR, + NVKM_ENGINE_MPEG, + NVKM_ENGINE_ME, + NVKM_ENGINE_VP, + NVKM_ENGINE_CIPHER, + NVKM_ENGINE_BSP, + NVKM_ENGINE_MSPPP, + NVKM_ENGINE_CE0, + NVKM_ENGINE_CE1, + NVKM_ENGINE_CE2, + NVKM_ENGINE_VIC, + NVKM_ENGINE_MSENC, + NVKM_ENGINE_DISP, + NVKM_ENGINE_PM, + NVKM_ENGINE_MSVLD, + NVKM_ENGINE_SEC, + NVKM_ENGINE_MSPDEC, + + NVKM_SUBDEV_NR, }; struct nvkm_device { - struct nvkm_engine engine; - const struct nvkm_device_func *func; const struct nvkm_device_quirk *quirk; struct device *dev; @@ -85,6 +70,7 @@ struct nvkm_device { struct nvkm_event event; u64 disable_mask; + u32 debug; const struct nvkm_device_chip *chip; enum { @@ -103,8 +89,6 @@ struct nvkm_device { u8 chiprev; u32 crystal; - struct nvkm_oclass *oclass[NVDEV_SUBDEV_NR]; - struct { struct notifier_block nb; } acpi; @@ -227,8 +211,6 @@ int nvkm_device_list(u64 *name, int size); _temp; \ }) -struct nvkm_device *nv_device(void *obj); - static inline bool nv_device_match(struct nvkm_device *device, u16 dev, u16 ven, u16 sub) { @@ -285,7 +267,7 @@ extern const struct nvkm_sclass nvkm_udevice_sclass; /* device logging */ #define nvdev_printk_(d,l,p,f,a...) do { \ struct nvkm_device *_device = (d); \ - if (_device->engine.subdev.debug >= (l)) \ + if (_device->debug >= (l)) \ dev_##p(_device->dev, f, ##a); \ } while(0) #define nvdev_printk(d,l,p,f,a...) nvdev_printk_((d), NV_DBG_##l, p, f, ##a) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h index 8c47ab210c06f..48bf128456a16 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h @@ -1,24 +1,16 @@ #ifndef __NVKM_ENGINE_H__ #define __NVKM_ENGINE_H__ +#define nvkm_engine(p) container_of((p), struct nvkm_engine, subdev) #include -struct nvkm_device_oclass; /*XXX: DEV!ENG */ struct nvkm_fifo_chan; struct nvkm_fb_tile; -#define NV_ENGINE_(eng,var) (((var) << 8) | (eng)) -#define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var)) - struct nvkm_engine { - struct nvkm_subdev subdev; const struct nvkm_engine_func *func; + struct nvkm_subdev subdev; + spinlock_t lock; int usecount; - - struct nvkm_oclass *cclass; - struct nvkm_oclass *sclass; - - struct list_head contexts; - spinlock_t lock; }; struct nvkm_engine_func { @@ -54,42 +46,4 @@ int nvkm_engine_new_(const struct nvkm_engine_func *, struct nvkm_device *, struct nvkm_engine *nvkm_engine_ref(struct nvkm_engine *); void nvkm_engine_unref(struct nvkm_engine **); void nvkm_engine_tile(struct nvkm_engine *, int region); - -static inline struct nvkm_engine * -nv_engine(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_ENGINE_CLASS)); -#endif - return obj; -} - -static inline int -nv_engidx(struct nvkm_engine *engine) -{ - return nv_subidx(&engine->subdev); -} - -struct nvkm_engine *nvkm_engine(void *obj, int idx); - -#define nvkm_engine_create(p,e,c,d,i,f,r) \ - nvkm_engine_create_((p), (e), (c), (d), (i), (f), \ - sizeof(**r),(void **)r) - -#define nvkm_engine_destroy(p) \ - nvkm_subdev_destroy(&(p)->subdev) -#define nvkm_engine_init_old(p) \ - nvkm_subdev_init_old(&(p)->subdev) -#define nvkm_engine_fini_old(p,s) \ - nvkm_subdev_fini_old(&(p)->subdev, (s)) - -int nvkm_engine_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, bool, const char *, - const char *, int, void **); - -#define _nvkm_engine_dtor _nvkm_subdev_dtor -#define _nvkm_engine_init _nvkm_subdev_init -#define _nvkm_engine_fini _nvkm_subdev_fini - -#include #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h index d171535b8eef1..d4f56eafb0738 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h @@ -30,44 +30,11 @@ struct nvkm_gpuobj_func { void (*wr32)(struct nvkm_gpuobj *, u32 offset, u32 data); }; -int nvkm_gpuobj_new(struct nvkm_device *, u32 size, int align, bool zero, - struct nvkm_gpuobj *parent, struct nvkm_gpuobj **); +int nvkm_gpuobj_new(struct nvkm_device *, u32 size, int align, bool zero, + struct nvkm_gpuobj *parent, struct nvkm_gpuobj **); void nvkm_gpuobj_del(struct nvkm_gpuobj **); - -static inline struct nvkm_gpuobj * -nv_gpuobj(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_GPUOBJ_CLASS)); -#endif - return obj; -} - -#define nvkm_gpuobj_create(p,e,c,v,g,s,a,f,d) \ - nvkm_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f), \ - sizeof(**d), (void **)d) -#define nvkm_gpuobj_init(p) _nvkm_object_init(&(p)->object) -#define nvkm_gpuobj_fini(p,s) _nvkm_object_fini(&(p)->object, (s)) -int nvkm_gpuobj_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32 pclass, - struct nvkm_object *, u32 size, u32 align, - u32 flags, int length, void **); -void nvkm_gpuobj_destroy(struct nvkm_gpuobj *); - int nvkm_gpuobj_wrap(struct nvkm_memory *, struct nvkm_gpuobj **); int nvkm_gpuobj_map(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access, struct nvkm_vma *); void nvkm_gpuobj_unmap(struct nvkm_vma *); - -static inline void -nvkm_gpuobj_ref(struct nvkm_gpuobj *obj, struct nvkm_gpuobj **ref) -{ - nvkm_object_ref(&obj->object, (struct nvkm_object **)ref); -} - -void _nvkm_gpuobj_dtor(struct nvkm_object *); -int _nvkm_gpuobj_init(struct nvkm_object *); -int _nvkm_gpuobj_fini(struct nvkm_object *, bool); -u32 _nvkm_gpuobj_rd32(struct nvkm_object *, u64); -void _nvkm_gpuobj_wr32(struct nvkm_object *, u64, u32); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index 7befea315c985..b4b822f6155cd 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -4,32 +4,18 @@ #include struct nvkm_event; struct nvkm_gpuobj; - -#define NV_PARENT_CLASS 0x80000000 -#define NV_NAMEDB_CLASS 0x40000000 -#define NV_CLIENT_CLASS 0x20000000 -#define NV_SUBDEV_CLASS 0x10000000 -#define NV_ENGINE_CLASS 0x08000000 -#define NV_MEMOBJ_CLASS 0x04000000 -#define NV_GPUOBJ_CLASS 0x02000000 -#define NV_ENGCTX_CLASS 0x01000000 +struct nvkm_oclass; struct nvkm_object { const struct nvkm_object_func *func; struct nvkm_client *client; struct nvkm_engine *engine; - u32 oclass_name; + u32 oclass; u32 handle; struct nvkm_object *parent; - struct nvkm_oclass *oclass; u32 pclass; atomic_t refcount; atomic_t usecount; -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA -#define NVKM_OBJECT_MAGIC 0x75ef0bad - struct list_head list; - u32 _magic; -#endif }; struct nvkm_object_func { @@ -71,32 +57,6 @@ int nvkm_object_wr32(struct nvkm_object *, u64 addr, u32 data); int nvkm_object_bind(struct nvkm_object *, struct nvkm_gpuobj *, int align, struct nvkm_gpuobj **); -static inline struct nvkm_object * -nv_object(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - if (likely(obj)) { - struct nvkm_object *object = obj; - BUG_ON(object->_magic != NVKM_OBJECT_MAGIC); - } -#endif - return obj; -} - -#define nvkm_object_create(p,e,c,s,d) \ - nvkm_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d) -int nvkm_object_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32, int size, void **); -void nvkm_object_destroy(struct nvkm_object *); -int _nvkm_object_init(struct nvkm_object *); -int _nvkm_object_fini(struct nvkm_object *, bool suspend); - -int _nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); - -extern struct nvkm_ofuncs nvkm_object_ofuncs; - struct nvkm_sclass { int minver; int maxver; @@ -107,60 +67,18 @@ struct nvkm_sclass { }; struct nvkm_oclass { - s32 handle; - struct nvkm_ofuncs * const ofuncs; - int (*ctor)(const struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **); struct nvkm_sclass base; const void *priv; const void *engn; + s32 handle; u64 object; struct nvkm_client *client; struct nvkm_object *parent; struct nvkm_engine *engine; }; -#define nv_oclass(o) nv_object(o)->oclass -#define nv_hclass(o) nv_oclass(o)->handle -#define nv_iclass(o,i) (nv_object(o)->pclass & (i)) -#define nv_mclass(o) nv_oclass(o)->handle - -static inline struct nvkm_object * -nv_pclass(struct nvkm_object *parent, u32 oclass) -{ - while (parent && !nv_iclass(parent, oclass)) - parent = parent->parent; - return parent; -} - -struct nvkm_ofuncs { - int (*ctor)(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *data, u32 size, - struct nvkm_object **); - void (*dtor)(struct nvkm_object *); - int (*init)(struct nvkm_object *); - int (*fini)(struct nvkm_object *, bool suspend); - int (*mthd)(struct nvkm_object *, u32, void *, u32); - int (*ntfy)(struct nvkm_object *, u32, struct nvkm_event **); - int (* map)(struct nvkm_object *, u64 *, u32 *); - u8 (*rd08)(struct nvkm_object *, u64 offset); - u16 (*rd16)(struct nvkm_object *, u64 offset); - u32 (*rd32)(struct nvkm_object *, u64 offset); - void (*wr08)(struct nvkm_object *, u64 offset, u8 data); - void (*wr16)(struct nvkm_object *, u64 offset, u16 data); - void (*wr32)(struct nvkm_object *, u64 offset, u32 data); -}; - -static inline struct nvkm_ofuncs * -nv_ofuncs(void *obj) -{ - return nv_oclass(obj)->ofuncs; -} - -int nvkm_object_old(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, void *, u32, - struct nvkm_object **); void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **); int nvkm_object_inc(struct nvkm_object *); int nvkm_object_dec(struct nvkm_object *, bool suspend); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h index 01f2f71e6112e..3b5dc9c630691 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h @@ -1,23 +1,16 @@ #ifndef __NVKM_SUBDEV_H__ #define __NVKM_SUBDEV_H__ -#include - -#define NV_SUBDEV_(sub,var) (((var) << 8) | (sub)) -#define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var)) +#include struct nvkm_subdev { - struct nvkm_object object; const struct nvkm_subdev_func *func; struct nvkm_device *device; - int index; + enum nvkm_devidx index; u32 pmc_enable; - struct mutex mutex; u32 debug; - bool oneinit; - void (*intr)(struct nvkm_subdev *); - u32 unit; + bool oneinit; }; struct nvkm_subdev_func { @@ -29,7 +22,7 @@ struct nvkm_subdev_func { void (*intr)(struct nvkm_subdev *); }; -extern const char *nvkm_subdev_name[64]; +extern const char *nvkm_subdev_name[NVKM_SUBDEV_NR]; void nvkm_subdev_ctor(const struct nvkm_subdev_func *, struct nvkm_device *, int index, u32 pmc_enable, struct nvkm_subdev *); void nvkm_subdev_del(struct nvkm_subdev **); @@ -38,40 +31,6 @@ int nvkm_subdev_init(struct nvkm_subdev *); int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend); void nvkm_subdev_intr(struct nvkm_subdev *); -static inline struct nvkm_subdev * -nv_subdev(void *obj) -{ -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!nv_iclass(obj, NV_SUBDEV_CLASS)); -#endif - return obj; -} - -static inline int -nv_subidx(struct nvkm_subdev *subdev) -{ - return nv_hclass(subdev) & 0xff; -} - -struct nvkm_subdev *nvkm_subdev(void *obj, int idx); - -#define nvkm_subdev_create(p,e,o,v,s,f,d) \ - nvkm_subdev_create_((p), (e), (o), (v), (s), (f), \ - sizeof(**d),(void **)d) - -int nvkm_subdev_create_(struct nvkm_object *, struct nvkm_object *, - struct nvkm_oclass *, u32 pclass, - const char *sname, const char *fname, - int size, void **); -void nvkm_subdev_destroy(struct nvkm_subdev *); -int nvkm_subdev_init_old(struct nvkm_subdev *); -int nvkm_subdev_fini_old(struct nvkm_subdev *, bool suspend); -void nvkm_subdev_reset(struct nvkm_object *); - -void _nvkm_subdev_dtor(struct nvkm_object *); -int _nvkm_subdev_init(struct nvkm_object *); -int _nvkm_subdev_fini(struct nvkm_object *, bool suspend); - /* subdev logging */ #define nvkm_printk_(s,l,p,f,a...) do { \ struct nvkm_subdev *_subdev = (s); \ @@ -88,6 +47,4 @@ int _nvkm_subdev_fini(struct nvkm_object *, bool suspend); #define nvkm_debug(s,f,a...) nvkm_printk((s), DEBUG, info, f, ##a) #define nvkm_trace(s,f,a...) nvkm_printk((s), TRACE, info, f, ##a) #define nvkm_spam(s,f,a...) nvkm_printk((s), SPAM, dbg, f, ##a) - -#include #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h index 84cc3e9cfed72..9e6644955d199 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h @@ -26,11 +26,9 @@ struct nvkm_fifo_chan { u64 addr; u32 size; - struct nvkm_fifo_engn engn[NVDEV_SUBDEV_NR]; + struct nvkm_fifo_engn engn[NVKM_SUBDEV_NR]; }; -extern const struct nvkm_object_func nvkm_fifo_chan_func; - struct nvkm_fifo { const struct nvkm_fifo_func *func; struct nvkm_engine engine; diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h index 26c77aac4be4b..dcd3deff27a49 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h @@ -32,7 +32,7 @@ struct nvkm_vm { struct kref refcount; struct list_head pgd_list; - atomic_t engref[NVDEV_SUBDEV_NR]; + atomic_t engref[NVKM_SUBDEV_NR]; struct nvkm_vm_pgt *pgt; u32 fpde; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c index 3fef9cc34345f..8a7bae7bd995c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/engine.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c @@ -67,29 +67,26 @@ nvkm_engine_tile(struct nvkm_engine *engine, int region) } static void -nvkm_engine_intr(struct nvkm_subdev *obj) +nvkm_engine_intr(struct nvkm_subdev *subdev) { - struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); + struct nvkm_engine *engine = nvkm_engine(subdev); if (engine->func->intr) engine->func->intr(engine); } static int -nvkm_engine_fini(struct nvkm_subdev *obj, bool suspend) +nvkm_engine_fini(struct nvkm_subdev *subdev, bool suspend) { - struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); - if (engine->subdev.object.oclass) - return engine->subdev.object.oclass->ofuncs->fini(&engine->subdev.object, suspend); + struct nvkm_engine *engine = nvkm_engine(subdev); if (engine->func->fini) return engine->func->fini(engine, suspend); return 0; } static int -nvkm_engine_init(struct nvkm_subdev *obj) +nvkm_engine_init(struct nvkm_subdev *subdev) { - struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); - struct nvkm_subdev *subdev = &engine->subdev; + struct nvkm_engine *engine = nvkm_engine(subdev); struct nvkm_fb *fb = subdev->device->fb; int ret = 0, i; s64 time; @@ -99,9 +96,6 @@ nvkm_engine_init(struct nvkm_subdev *obj) return ret; } - if (engine->subdev.object.oclass) - return engine->subdev.object.oclass->ofuncs->init(&engine->subdev.object); - if (engine->func->oneinit && !engine->subdev.oneinit) { nvkm_trace(subdev, "one-time init running...\n"); time = ktime_to_us(ktime_get()); @@ -125,13 +119,9 @@ nvkm_engine_init(struct nvkm_subdev *obj) } static void * -nvkm_engine_dtor(struct nvkm_subdev *obj) +nvkm_engine_dtor(struct nvkm_subdev *subdev) { - struct nvkm_engine *engine = container_of(obj, typeof(*engine), subdev); - if (engine->subdev.object.oclass) { - engine->subdev.object.oclass->ofuncs->dtor(&engine->subdev.object); - return NULL; - } + struct nvkm_engine *engine = nvkm_engine(subdev); if (engine->func->dtor) return engine->func->dtor(engine); return engine; @@ -173,56 +163,3 @@ nvkm_engine_new_(const struct nvkm_engine_func *func, return nvkm_engine_ctor(func, device, index, pmc_enable, enable, *pengine); } - -struct nvkm_engine * -nvkm_engine(void *obj, int idx) -{ - obj = nvkm_subdev(obj, idx); - if (obj && nv_iclass(obj, NV_ENGINE_CLASS)) - return nv_engine(obj); - return NULL; -} - -int -nvkm_engine_create_(struct nvkm_object *parent, struct nvkm_object *engobj, - struct nvkm_oclass *oclass, bool enable, - const char *iname, const char *fname, - int length, void **pobject) -{ - struct nvkm_engine *engine; - int ret; - - ret = nvkm_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS, - iname, fname, length, pobject); - engine = *pobject; - if (ret) - return ret; - - if (parent) { - struct nvkm_device *device = nv_device(parent); - int engidx = nv_engidx(engine); - - if (device->disable_mask & (1ULL << engidx)) { - if (!nvkm_boolopt(device->cfgopt, iname, false)) { - nvkm_debug(&engine->subdev, - "engine disabled by hw/fw\n"); - return -ENODEV; - } - - nvkm_warn(&engine->subdev, - "ignoring hw/fw engine disable\n"); - } - - if (!nvkm_boolopt(device->cfgopt, iname, enable)) { - if (!enable) - nvkm_warn(&engine->subdev, - "disabled, %s=1 to enable\n", iname); - return -ENODEV; - } - } - - INIT_LIST_HEAD(&engine->contexts); - spin_lock_init(&engine->lock); - engine->subdev.func = &nvkm_engine_func; - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c index b8fc539e0a994..c3a790eb8d6a1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c @@ -218,99 +218,6 @@ nvkm_gpuobj_new(struct nvkm_device *device, u32 size, int align, bool zero, return ret; } -void -nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj) -{ - if (gpuobj->node) - nvkm_mm_free(&gpuobj->parent->heap, &gpuobj->node); - - gpuobj->heap.block_size = 1; - nvkm_mm_fini(&gpuobj->heap); - - nvkm_memory_del(&gpuobj->memory); - nvkm_object_destroy(&gpuobj->object); -} - -#include - -int -nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 pclass, - struct nvkm_object *objgpu, u32 size, u32 align, u32 flags, - int length, void **pobject) -{ - struct nvkm_device *device = nv_device(parent); - struct nvkm_gpuobj *pargpu = NULL; - struct nvkm_gpuobj *gpuobj; - struct nvkm_object *object = objgpu; - const bool zero = (flags & NVOBJ_FLAG_ZERO_ALLOC); - int ret; - - *pobject = NULL; - - while (object && object->func != &nvkm_fifo_chan_func) - object = object->parent; - - if (object) { - struct nvkm_fifo_chan *chan = nvkm_fifo_chan(object); - pargpu = chan->inst; - } else - if (objgpu) { - while ((objgpu = nv_pclass(objgpu, NV_GPUOBJ_CLASS))) { - if (nv_gpuobj(objgpu)->heap.block_size) - break; - objgpu = objgpu->parent; - } - - if (WARN_ON(objgpu == NULL)) - return -EINVAL; - pargpu = nv_gpuobj(objgpu); - } - - ret = nvkm_object_create_(parent, engine, oclass, pclass | - NV_GPUOBJ_CLASS, length, pobject); - gpuobj = *pobject; - if (ret) - return ret; - - ret = nvkm_gpuobj_ctor(device, size, align, zero, pargpu, gpuobj); - if (!(flags & NVOBJ_FLAG_HEAP)) - gpuobj->heap.block_size = 0; - return ret; -} - -void -_nvkm_gpuobj_dtor(struct nvkm_object *object) -{ - nvkm_gpuobj_destroy(nv_gpuobj(object)); -} - -int -_nvkm_gpuobj_init(struct nvkm_object *object) -{ - return nvkm_gpuobj_init(nv_gpuobj(object)); -} - -int -_nvkm_gpuobj_fini(struct nvkm_object *object, bool suspend) -{ - return nvkm_gpuobj_fini(nv_gpuobj(object), suspend); -} - -u32 -_nvkm_gpuobj_rd32(struct nvkm_object *object, u64 addr) -{ - struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - return nvkm_ro32(gpuobj, addr); -} - -void -_nvkm_gpuobj_wr32(struct nvkm_object *object, u64 addr, u32 data) -{ - struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - nvkm_wo32(gpuobj, addr, data); -} - int nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm, u32 access, struct nvkm_vma *vma) diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index 0680eae072cf0..8976526b1c8fc 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -27,11 +27,6 @@ int nvkm_object_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size) { - if (object->oclass) { - if (object->oclass->ofuncs->mthd) - return object->oclass->ofuncs->mthd(object, mthd, data, size); - return -ENODEV; - } if (likely(object->func->mthd)) return object->func->mthd(object, mthd, data, size); return -ENODEV; @@ -41,11 +36,6 @@ int nvkm_object_ntfy(struct nvkm_object *object, u32 mthd, struct nvkm_event **pevent) { - if (object->oclass) { - if (object->oclass->ofuncs->ntfy) - return object->oclass->ofuncs->ntfy(object, mthd, pevent); - return -ENODEV; - } if (likely(object->func->ntfy)) return object->func->ntfy(object, mthd, pevent); return -ENODEV; @@ -54,11 +44,6 @@ nvkm_object_ntfy(struct nvkm_object *object, u32 mthd, int nvkm_object_map(struct nvkm_object *object, u64 *addr, u32 *size) { - if (object->oclass) { - if (object->oclass->ofuncs->map) - return object->oclass->ofuncs->map(object, addr, size); - return -ENODEV; - } if (likely(object->func->map)) return object->func->map(object, addr, size); return -ENODEV; @@ -67,14 +52,6 @@ nvkm_object_map(struct nvkm_object *object, u64 *addr, u32 *size) int nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data) { - if (object->oclass) { - if (object->oclass->ofuncs->rd08) { - *data = object->oclass->ofuncs->rd08(object, addr); - return 0; - } - *data = 0x00; - return -ENODEV; - } if (likely(object->func->rd08)) return object->func->rd08(object, addr, data); return -ENODEV; @@ -83,14 +60,6 @@ nvkm_object_rd08(struct nvkm_object *object, u64 addr, u8 *data) int nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data) { - if (object->oclass) { - if (object->oclass->ofuncs->rd16) { - *data = object->oclass->ofuncs->rd16(object, addr); - return 0; - } - *data = 0x0000; - return -ENODEV; - } if (likely(object->func->rd16)) return object->func->rd16(object, addr, data); return -ENODEV; @@ -99,14 +68,6 @@ nvkm_object_rd16(struct nvkm_object *object, u64 addr, u16 *data) int nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data) { - if (object->oclass) { - if (object->oclass->ofuncs->rd32) { - *data = object->oclass->ofuncs->rd32(object, addr); - return 0; - } - *data = 0x00000000; - return -ENODEV; - } if (likely(object->func->rd32)) return object->func->rd32(object, addr, data); return -ENODEV; @@ -115,13 +76,6 @@ nvkm_object_rd32(struct nvkm_object *object, u64 addr, u32 *data) int nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data) { - if (object->oclass) { - if (object->oclass->ofuncs->wr08) { - object->oclass->ofuncs->wr08(object, addr, data); - return 0; - } - return -ENODEV; - } if (likely(object->func->wr08)) return object->func->wr08(object, addr, data); return -ENODEV; @@ -130,13 +84,6 @@ nvkm_object_wr08(struct nvkm_object *object, u64 addr, u8 data) int nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data) { - if (object->oclass) { - if (object->oclass->ofuncs->wr16) { - object->oclass->ofuncs->wr16(object, addr, data); - return 0; - } - return -ENODEV; - } if (likely(object->func->wr16)) return object->func->wr16(object, addr, data); return -ENODEV; @@ -145,13 +92,6 @@ nvkm_object_wr16(struct nvkm_object *object, u64 addr, u16 data) int nvkm_object_wr32(struct nvkm_object *object, u64 addr, u32 data) { - if (object->oclass) { - if (object->oclass->ofuncs->wr32) { - object->oclass->ofuncs->wr32(object, addr, data); - return 0; - } - return -ENODEV; - } if (likely(object->func->wr32)) return object->func->wr32(object, addr, data); return -ENODEV; @@ -161,8 +101,6 @@ int nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj, int align, struct nvkm_gpuobj **pgpuobj) { - if (object->oclass) - return -ENODEV; if (object->func->bind) return object->func->bind(object, gpuobj, align, pgpuobj); return -ENODEV; @@ -171,8 +109,6 @@ nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj, int nvkm_object_fini(struct nvkm_object *object, bool suspend) { - if (object->oclass) - return object->oclass->ofuncs->fini(object, suspend); if (object->func->fini) return object->func->fini(object, suspend); return 0; @@ -181,8 +117,6 @@ nvkm_object_fini(struct nvkm_object *object, bool suspend) int nvkm_object_init(struct nvkm_object *object) { - if (object->oclass) - return object->oclass->ofuncs->init(object); if (object->func->init) return object->func->init(object); return 0; @@ -193,11 +127,6 @@ nvkm_object_del(struct nvkm_object **pobject) { struct nvkm_object *object = *pobject; - if (object && object->oclass) { - object->oclass->ofuncs->dtor(object); - return; - } - if (object && !WARN_ON(!object->func)) { if (object->func->dtor) *pobject = object->func->dtor(object); @@ -214,14 +143,11 @@ nvkm_object_ctor(const struct nvkm_object_func *func, object->func = func; object->client = oclass->client; object->engine = nvkm_engine_ref(oclass->engine); - object->oclass_name = oclass->base.oclass; + object->oclass = oclass->base.oclass; object->handle = oclass->handle; object->parent = oclass->parent; atomic_set(&object->refcount, 1); atomic_set(&object->usecount, 0); -#ifdef NVKM_OBJECT_MAGIC - object->_magic = NVKM_OBJECT_MAGIC; -#endif } int @@ -251,97 +177,6 @@ nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size, return nvkm_object_new_(func, oclass, data, size, pobject); } -int -nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engobj, - struct nvkm_oclass *oclass, u32 pclass, - int size, void **pobject) -{ - struct nvkm_engine *engine = engobj ? nv_engine(engobj) : NULL; - struct nvkm_object *object; - - object = *pobject = kzalloc(size, GFP_KERNEL); - if (!object) - return -ENOMEM; - - nvkm_object_ref(parent, &object->parent); - object->engine = nvkm_engine_ref(engine); - object->oclass = oclass; - object->pclass = pclass; - atomic_set(&object->refcount, 1); - atomic_set(&object->usecount, 0); - -#ifdef NVKM_OBJECT_MAGIC - object->_magic = NVKM_OBJECT_MAGIC; -#endif - return 0; -} - -int -_nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - if (size != 0) - return -ENOSYS; - return nvkm_object_create(parent, engine, oclass, 0, pobject); -} - -void -nvkm_object_destroy(struct nvkm_object *object) -{ - nvkm_engine_unref(&object->engine); - nvkm_object_ref(NULL, &object->parent); - kfree(object); -} - -int -_nvkm_object_init(struct nvkm_object *object) -{ - return 0; -} - -int -_nvkm_object_fini(struct nvkm_object *object, bool suspend) -{ - return 0; -} - -struct nvkm_ofuncs -nvkm_object_ofuncs = { - .ctor = _nvkm_object_ctor, - .dtor = nvkm_object_destroy, - .init = _nvkm_object_init, - .fini = _nvkm_object_fini, -}; - -int -nvkm_object_old(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, void *data, u32 size, - struct nvkm_object **pobject) -{ - struct nvkm_ofuncs *ofuncs = oclass->ofuncs; - struct nvkm_object *object = NULL; - int ret; - - ret = ofuncs->ctor(parent, engine, oclass, data, size, &object); - *pobject = object; - if (ret < 0) { - if (object) { - ofuncs->dtor(object); - *pobject = NULL; - } - - return ret; - } - - if (ret == 0) { - if (!nv_iclass(object, NV_SUBDEV_CLASS)) - atomic_set(&object->refcount, 1); - } - - return 0; -} - void nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref) { diff --git a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c index b2b743587168c..f32aa0dc425bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c @@ -92,8 +92,6 @@ nvkm_oproxy_sclass(struct nvkm_object *object, int index, { struct nvkm_oproxy *oproxy = nvkm_oproxy(object); oclass->parent = oproxy->object; - if (oproxy->object->oclass) - return -ENOSYS; if (!oproxy->object->func->sclass) return -ENODEV; return oproxy->object->func->sclass(oproxy->object, index, oclass); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c index 307d532696250..3216e157a8a0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c @@ -67,40 +67,27 @@ nvkm_ramht_update(struct nvkm_ramht *ramht, int co, struct nvkm_object *object, data->chid = chid; data->handle = handle; - if (!object) { - inst = 0; - goto done; - } - - if (nv_iclass(object, NV_GPUOBJ_CLASS)) { - struct nvkm_gpuobj *gpuobj = nv_gpuobj(object); - if (ramht->device->card_type >= NV_50) - inst = gpuobj->node->offset; - else - inst = gpuobj->addr; - goto done; - } + if (object) { + ret = nvkm_object_bind(object, ramht->parent, 16, &data->inst); + if (ret) { + if (ret != -ENODEV) { + data->chid = -1; + return ret; + } + data->inst = NULL; + } - ret = nvkm_object_bind(object, ramht->parent, 16, &data->inst); - if (ret) { - if (ret != -ENODEV) { - data->chid = -1; - return ret; + if (data->inst) { + if (ramht->device->card_type >= NV_50) + inst = data->inst->node->offset; + else + inst = data->inst->addr; } - data->inst = NULL; - } - if (data->inst) { - if (ramht->device->card_type >= NV_50) - inst = data->inst->node->offset; - else - inst = data->inst->addr; + if (addr < 0) context |= inst << -addr; + else context |= inst >> addr; } -done: - if (addr < 0) context |= inst << -addr; - else context |= inst >> addr; - nvkm_kmap(ramht->gpuobj); nvkm_wo32(ramht->gpuobj, (co << 3) + 0, handle); nvkm_wo32(ramht->gpuobj, (co << 3) + 4, context); diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index b0647c233478b..65e0cb35e1a0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -25,61 +25,55 @@ #include #include -static struct lock_class_key nvkm_subdev_lock_class[NVDEV_SUBDEV_NR]; +static struct lock_class_key nvkm_subdev_lock_class[NVKM_SUBDEV_NR]; const char * -nvkm_subdev_name[64] = { - [NVDEV_SUBDEV_BAR ] = "bar", - [NVDEV_SUBDEV_VBIOS ] = "bios", - [NVDEV_SUBDEV_BUS ] = "bus", - [NVDEV_SUBDEV_CLK ] = "clk", - [NVDEV_SUBDEV_DEVINIT] = "devinit", - [NVDEV_SUBDEV_FB ] = "fb", - [NVDEV_SUBDEV_FUSE ] = "fuse", - [NVDEV_SUBDEV_GPIO ] = "gpio", - [NVDEV_SUBDEV_I2C ] = "i2c", - [NVDEV_SUBDEV_IBUS ] = "priv", - [NVDEV_SUBDEV_INSTMEM] = "imem", - [NVDEV_SUBDEV_LTC ] = "ltc", - [NVDEV_SUBDEV_MC ] = "mc", - [NVDEV_SUBDEV_MMU ] = "mmu", - [NVDEV_SUBDEV_MXM ] = "mxm", - [NVDEV_SUBDEV_PMU ] = "pmu", - [NVDEV_SUBDEV_THERM ] = "therm", - [NVDEV_SUBDEV_TIMER ] = "tmr", - [NVDEV_SUBDEV_VOLT ] = "volt", - [NVDEV_ENGINE_BSP ] = "bsp", - [NVDEV_ENGINE_CE0 ] = "ce0", - [NVDEV_ENGINE_CE1 ] = "ce1", - [NVDEV_ENGINE_CE2 ] = "ce2", - [NVDEV_ENGINE_CIPHER ] = "cipher", - [NVDEV_ENGINE_DISP ] = "disp", - [NVDEV_ENGINE_DMAOBJ ] = "dma", - [NVDEV_ENGINE_FIFO ] = "fifo", - [NVDEV_ENGINE_GR ] = "gr", - [NVDEV_ENGINE_IFB ] = "ifb", - [NVDEV_ENGINE_ME ] = "me", - [NVDEV_ENGINE_MPEG ] = "mpeg", - [NVDEV_ENGINE_MSENC ] = "msenc", - [NVDEV_ENGINE_MSPDEC ] = "mspdec", - [NVDEV_ENGINE_MSPPP ] = "msppp", - [NVDEV_ENGINE_MSVLD ] = "msvld", - [NVDEV_ENGINE_PM ] = "pm", - [NVDEV_ENGINE_SEC ] = "sec", - [NVDEV_ENGINE_SW ] = "sw", - [NVDEV_ENGINE_VIC ] = "vic", - [NVDEV_ENGINE_VP ] = "vp", +nvkm_subdev_name[NVKM_SUBDEV_NR] = { + [NVKM_SUBDEV_BAR ] = "bar", + [NVKM_SUBDEV_VBIOS ] = "bios", + [NVKM_SUBDEV_BUS ] = "bus", + [NVKM_SUBDEV_CLK ] = "clk", + [NVKM_SUBDEV_DEVINIT] = "devinit", + [NVKM_SUBDEV_FB ] = "fb", + [NVKM_SUBDEV_FUSE ] = "fuse", + [NVKM_SUBDEV_GPIO ] = "gpio", + [NVKM_SUBDEV_I2C ] = "i2c", + [NVKM_SUBDEV_IBUS ] = "priv", + [NVKM_SUBDEV_INSTMEM] = "imem", + [NVKM_SUBDEV_LTC ] = "ltc", + [NVKM_SUBDEV_MC ] = "mc", + [NVKM_SUBDEV_MMU ] = "mmu", + [NVKM_SUBDEV_MXM ] = "mxm", + [NVKM_SUBDEV_PMU ] = "pmu", + [NVKM_SUBDEV_THERM ] = "therm", + [NVKM_SUBDEV_TIMER ] = "tmr", + [NVKM_SUBDEV_VOLT ] = "volt", + [NVKM_ENGINE_BSP ] = "bsp", + [NVKM_ENGINE_CE0 ] = "ce0", + [NVKM_ENGINE_CE1 ] = "ce1", + [NVKM_ENGINE_CE2 ] = "ce2", + [NVKM_ENGINE_CIPHER ] = "cipher", + [NVKM_ENGINE_DISP ] = "disp", + [NVKM_ENGINE_DMAOBJ ] = "dma", + [NVKM_ENGINE_FIFO ] = "fifo", + [NVKM_ENGINE_GR ] = "gr", + [NVKM_ENGINE_IFB ] = "ifb", + [NVKM_ENGINE_ME ] = "me", + [NVKM_ENGINE_MPEG ] = "mpeg", + [NVKM_ENGINE_MSENC ] = "msenc", + [NVKM_ENGINE_MSPDEC ] = "mspdec", + [NVKM_ENGINE_MSPPP ] = "msppp", + [NVKM_ENGINE_MSVLD ] = "msvld", + [NVKM_ENGINE_PM ] = "pm", + [NVKM_ENGINE_SEC ] = "sec", + [NVKM_ENGINE_SW ] = "sw", + [NVKM_ENGINE_VIC ] = "vic", + [NVKM_ENGINE_VP ] = "vp", }; void nvkm_subdev_intr(struct nvkm_subdev *subdev) { - if (subdev->object.oclass) { - if (subdev->intr) - subdev->intr(subdev); - return; - } - if (subdev->func->intr) subdev->func->intr(subdev); } @@ -91,18 +85,10 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) const char *action = suspend ? "suspend" : "fini"; u32 pmc_enable = subdev->pmc_enable; s64 time; - int ret; nvkm_trace(subdev, "%s running...\n", action); time = ktime_to_us(ktime_get()); - if (!subdev->func) { - ret = subdev->object.oclass->ofuncs->fini(&subdev->object, suspend); - if (ret) - return ret; - goto done; - } - if (subdev->func->fini) { int ret = subdev->func->fini(subdev, suspend); if (ret) { @@ -118,7 +104,6 @@ nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend) nvkm_rd32(device, 0x000200); } -done: time = ktime_to_us(ktime_get()) - time; nvkm_trace(subdev, "%s completed in %lldus\n", action, time); return 0; @@ -132,7 +117,7 @@ nvkm_subdev_preinit(struct nvkm_subdev *subdev) nvkm_trace(subdev, "preinit running...\n"); time = ktime_to_us(ktime_get()); - if (!subdev->object.oclass && subdev->func->preinit) { + if (subdev->func->preinit) { int ret = subdev->func->preinit(subdev); if (ret) { nvkm_error(subdev, "preinit failed, %d\n", ret); @@ -154,13 +139,6 @@ nvkm_subdev_init(struct nvkm_subdev *subdev) nvkm_trace(subdev, "init running...\n"); time = ktime_to_us(ktime_get()); - if (!subdev->func) { - ret = subdev->object.oclass->ofuncs->init(&subdev->object); - if (ret) - return ret; - goto done; - } - if (subdev->func->oneinit && !subdev->oneinit) { s64 time; nvkm_trace(subdev, "one-time init running...\n"); @@ -184,7 +162,6 @@ nvkm_subdev_init(struct nvkm_subdev *subdev) } } -done: time = ktime_to_us(ktime_get()) - time; nvkm_trace(subdev, "init completed in %lldus\n", time); return 0; @@ -196,11 +173,6 @@ nvkm_subdev_del(struct nvkm_subdev **psubdev) struct nvkm_subdev *subdev = *psubdev; s64 time; - if (subdev && subdev->object.oclass) { - subdev->object.oclass->ofuncs->dtor(&subdev->object); - return; - } - if (subdev && !WARN_ON(!subdev->func)) { nvkm_trace(subdev, "destroy running...\n"); time = ktime_to_us(ktime_get()); @@ -213,18 +185,12 @@ nvkm_subdev_del(struct nvkm_subdev **psubdev) } } -static const struct nvkm_object_func -nvkm_subdev_func = { -}; - void nvkm_subdev_ctor(const struct nvkm_subdev_func *func, struct nvkm_device *device, int index, u32 pmc_enable, struct nvkm_subdev *subdev) { const char *name = nvkm_subdev_name[index]; - struct nvkm_oclass hack = {}; - nvkm_object_ctor(&nvkm_subdev_func, &hack, &subdev->object); subdev->func = func; subdev->device = device; subdev->index = index; @@ -233,106 +199,3 @@ nvkm_subdev_ctor(const struct nvkm_subdev_func *func, __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[index]); subdev->debug = nvkm_dbgopt(device->dbgopt, name); } - -struct nvkm_subdev * -nvkm_subdev(void *obj, int idx) -{ - struct nvkm_object *object = nv_object(obj); - while (object && !nv_iclass(object, NV_SUBDEV_CLASS)) - object = object->parent; - if (object == NULL || !object->parent || nv_subidx(nv_subdev(object)) != idx) { - struct nvkm_device *device = nv_device(obj); - return nvkm_device_subdev(device, idx); - } - return object ? nv_subdev(object) : NULL; -} - -void -nvkm_subdev_reset(struct nvkm_object *obj) -{ - struct nvkm_subdev *subdev = container_of(obj, typeof(*subdev), object); - nvkm_trace(subdev, "resetting...\n"); - nvkm_object_fini(&subdev->object, false); - nvkm_trace(subdev, "reset\n"); -} - -int -nvkm_subdev_init_old(struct nvkm_subdev *subdev) -{ - int ret = _nvkm_object_init(&subdev->object); - if (ret) - return ret; - - nvkm_subdev_reset(&subdev->object); - return 0; -} - -int -_nvkm_subdev_init(struct nvkm_object *object) -{ - struct nvkm_subdev *subdev = (void *)object; - return nvkm_subdev_init_old(subdev); -} - -int -nvkm_subdev_fini_old(struct nvkm_subdev *subdev, bool suspend) -{ - struct nvkm_device *device = subdev->device; - - if (subdev->unit) { - nvkm_mask(device, 0x000200, subdev->unit, 0x00000000); - nvkm_mask(device, 0x000200, subdev->unit, subdev->unit); - } - - return _nvkm_object_fini(&subdev->object, suspend); -} - -int -_nvkm_subdev_fini(struct nvkm_object *object, bool suspend) -{ - struct nvkm_subdev *subdev = (void *)object; - return nvkm_subdev_fini_old(subdev, suspend); -} - -void -nvkm_subdev_destroy(struct nvkm_subdev *subdev) -{ - nvkm_object_destroy(&subdev->object); -} - -void -_nvkm_subdev_dtor(struct nvkm_object *object) -{ - nvkm_subdev_destroy(nv_subdev(object)); -} - -int -nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine, - struct nvkm_oclass *oclass, u32 pclass, - const char *subname, const char *sysname, - int size, void **pobject) -{ - const int subidx = oclass->handle & 0xff; - const char *name = nvkm_subdev_name[subidx]; - struct nvkm_subdev *subdev; - int ret; - - ret = nvkm_object_create_(parent, engine, oclass, pclass | - NV_SUBDEV_CLASS, size, pobject); - subdev = *pobject; - if (ret) - return ret; - - __mutex_init(&subdev->mutex, name, &nvkm_subdev_lock_class[subidx]); - subdev->index = subidx; - - if (parent) { - struct nvkm_device *device = nv_device(parent); - subdev->debug = nvkm_dbgopt(device->dbgopt, name); - subdev->device = device; - } else { - subdev->device = nv_device(subdev); - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c index 6b36b86f858fe..92a9f35df1a65 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c @@ -30,7 +30,7 @@ static void gf100_ce_init(struct nvkm_falcon *ce) { struct nvkm_device *device = ce->engine.subdev.device; - const int index = ce->engine.subdev.index - NVDEV_ENGINE_CE0; + const int index = ce->engine.subdev.index - NVKM_ENGINE_CE0; nvkm_wr32(device, ce->addr + 0x084, index); } @@ -68,11 +68,11 @@ int gf100_ce_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - if (index == NVDEV_ENGINE_CE0) { + if (index == NVKM_ENGINE_CE0) { return nvkm_falcon_new_(&gf100_ce0, device, index, true, 0x104000, pengine); } else - if (index == NVDEV_ENGINE_CE1) { + if (index == NVKM_ENGINE_CE1) { return nvkm_falcon_new_(&gf100_ce1, device, index, true, 0x105000, pengine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c index 5de21a2ebb9ad..c541a1c012dcd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c @@ -28,7 +28,7 @@ void gk104_ce_intr(struct nvkm_engine *ce) { - const u32 base = (ce->subdev.index - NVDEV_ENGINE_CE0) * 0x1000; + const u32 base = (ce->subdev.index - NVKM_ENGINE_CE0) * 0x1000; struct nvkm_subdev *subdev = &ce->subdev; struct nvkm_device *device = subdev->device; u32 stat = nvkm_rd32(device, 0x104908 + base); @@ -51,15 +51,15 @@ int gk104_ce_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - if (index == NVDEV_ENGINE_CE0) { + if (index == NVKM_ENGINE_CE0) { return nvkm_engine_new_(&gk104_ce, device, index, 0x00000040, true, pengine); } else - if (index == NVDEV_ENGINE_CE1) { + if (index == NVKM_ENGINE_CE1) { return nvkm_engine_new_(&gk104_ce, device, index, 0x00000080, true, pengine); } else - if (index == NVDEV_ENGINE_CE2) { + if (index == NVKM_ENGINE_CE2) { return nvkm_engine_new_(&gk104_ce, device, index, 0x00200000, true, pengine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c index e89c44cb23e1c..8eaa72a59f406 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gm204.c @@ -38,15 +38,15 @@ int gm204_ce_new(struct nvkm_device *device, int index, struct nvkm_engine **pengine) { - if (index == NVDEV_ENGINE_CE0) { + if (index == NVKM_ENGINE_CE0) { return nvkm_engine_new_(&gm204_ce, device, index, 0x00000040, true, pengine); } else - if (index == NVDEV_ENGINE_CE1) { + if (index == NVKM_ENGINE_CE1) { return nvkm_engine_new_(&gm204_ce, device, index, 0x00000080, true, pengine); } else - if (index == NVDEV_ENGINE_CE2) { + if (index == NVKM_ENGINE_CE2) { return nvkm_engine_new_(&gm204_ce, device, index, 0x00200000, true, pengine); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c index 03763268248f3..402dcbcc2192f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c @@ -44,7 +44,7 @@ gt215_ce_intr(struct nvkm_falcon *ce, struct nvkm_fifo_chan *chan) { struct nvkm_subdev *subdev = &ce->engine.subdev; struct nvkm_device *device = subdev->device; - const u32 base = (subdev->index - NVDEV_ENGINE_CE0) * 0x1000; + const u32 base = (subdev->index - NVKM_ENGINE_CE0) * 0x1000; u32 ssta = nvkm_rd32(device, 0x104040 + base) & 0x0000ffff; u32 addr = nvkm_rd32(device, 0x104040 + base) >> 16; u32 mthd = (addr & 0x07ff) << 2; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c index d3a35db85fba7..bfd01625ec7f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c @@ -38,7 +38,7 @@ g84_cipher_oclass_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, align, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); nvkm_wo32(*pgpuobj, 0x04, 0x00000000); nvkm_wo32(*pgpuobj, 0x08, 0x00000000); nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild index 91110cd2562ec..09032ba360004 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild @@ -4,13 +4,3 @@ nvkm-y += nvkm/engine/device/ctrl.o nvkm-y += nvkm/engine/device/pci.o nvkm-y += nvkm/engine/device/tegra.o nvkm-y += nvkm/engine/device/user.o - -nvkm-y += nvkm/engine/device/nv04.o -nvkm-y += nvkm/engine/device/nv10.o -nvkm-y += nvkm/engine/device/nv20.o -nvkm-y += nvkm/engine/device/nv30.o -nvkm-y += nvkm/engine/device/nv40.o -nvkm-y += nvkm/engine/device/nv50.o -nvkm-y += nvkm/engine/device/gf100.o -nvkm-y += nvkm/engine/device/gk104.o -nvkm-y += nvkm/engine/device/gm100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 48cc06372c9c9..b67cb37719481 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -1975,36 +1975,6 @@ nv12b_chipset = { .sw = gf100_sw_new, }; -#include - -struct nvkm_device * -nv_device(void *obj) -{ - struct nvkm_object *device = nv_object(obj); - - if (device->engine == NULL) { - while (device && device->parent) { - if (!nv_iclass(device, NV_SUBDEV_CLASS) && - device->parent == &nvkm_client(device)->object) { - struct { - struct nvkm_object base; - struct nvkm_device *device; - } *udevice = (void *)device; - return udevice->device; - } - device = device->parent; - } - } else { - device = &nv_object(obj)->engine->subdev.object; - if (device && device->parent) - device = device->parent; - } -#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA - BUG_ON(!device); -#endif - return (void *)device; -} - static int nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) @@ -2032,7 +2002,7 @@ nvkm_device_subdev(struct nvkm_device *device, int index) return NULL; switch (index) { -#define _(n,p,m) case NVDEV_SUBDEV_##n: if (p) return (m); break +#define _(n,p,m) case NVKM_SUBDEV_##n: if (p) return (m); break _(BAR , device->bar , &device->bar->subdev); _(VBIOS , device->bios , &device->bios->subdev); _(BUS , device->bus , &device->bus->subdev); @@ -2069,7 +2039,7 @@ nvkm_device_engine(struct nvkm_device *device, int index) return NULL; switch (index) { -#define _(n,p,m) case NVDEV_ENGINE_##n: if (p) return (m); break +#define _(n,p,m) case NVKM_ENGINE_##n: if (p) return (m); break _(BSP , device->bsp , device->bsp); _(CE0 , device->ce[0] , device->ce[0]); _(CE1 , device->ce[1] , device->ce[1]); @@ -2112,7 +2082,7 @@ nvkm_device_fini(struct nvkm_device *device, bool suspend) nvkm_acpi_fini(device); - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { + for (i = NVKM_SUBDEV_NR - 1; i >= 0; i--) { if ((subdev = nvkm_device_subdev(device, i))) { ret = nvkm_subdev_fini(subdev, suspend); if (ret && suspend) @@ -2135,7 +2105,7 @@ fail: if (rret) nvkm_fatal(subdev, "failed restart, %d\n", ret); } - } while (++i < NVDEV_SUBDEV_NR); + } while (++i < NVKM_SUBDEV_NR); nvdev_trace(device, "%s failed with %d\n", action, ret); return ret; @@ -2157,7 +2127,7 @@ nvkm_device_preinit(struct nvkm_device *device) goto fail; } - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + for (i = 0; i < NVKM_SUBDEV_NR; i++) { if ((subdev = nvkm_device_subdev(device, i))) { ret = nvkm_subdev_preinit(subdev); if (ret) @@ -2182,7 +2152,7 @@ int nvkm_device_init(struct nvkm_device *device) { struct nvkm_subdev *subdev; - int ret, i = 0, c; + int ret, i; s64 time; ret = nvkm_device_preinit(device); @@ -2194,80 +2164,11 @@ nvkm_device_init(struct nvkm_device *device) nvdev_trace(device, "init running...\n"); time = ktime_to_us(ktime_get()); - for (i = 0, c = 0; i < NVDEV_SUBDEV_NR; i++) { -#define _(s,m) case s: if (device->oclass[s] && !device->m) { \ - ret = nvkm_object_old(nv_object(device), NULL, \ - device->oclass[s], NULL, (s), \ - (struct nvkm_object **)&device->m); \ - if (ret == -ENODEV) { \ - device->oclass[s] = NULL; \ - continue; \ - } \ - if (ret) \ - goto fail; \ -} break - switch (i) { - _(NVDEV_SUBDEV_BAR , bar); - _(NVDEV_SUBDEV_VBIOS , bios); - _(NVDEV_SUBDEV_BUS , bus); - _(NVDEV_SUBDEV_CLK , clk); - _(NVDEV_SUBDEV_DEVINIT, devinit); - _(NVDEV_SUBDEV_FB , fb); - _(NVDEV_SUBDEV_FUSE , fuse); - _(NVDEV_SUBDEV_GPIO , gpio); - _(NVDEV_SUBDEV_I2C , i2c); - _(NVDEV_SUBDEV_IBUS , ibus); - _(NVDEV_SUBDEV_INSTMEM, imem); - _(NVDEV_SUBDEV_LTC , ltc); - _(NVDEV_SUBDEV_MC , mc); - _(NVDEV_SUBDEV_MMU , mmu); - _(NVDEV_SUBDEV_MXM , mxm); - _(NVDEV_SUBDEV_PMU , pmu); - _(NVDEV_SUBDEV_THERM , therm); - _(NVDEV_SUBDEV_TIMER , timer); - _(NVDEV_SUBDEV_VOLT , volt); - _(NVDEV_ENGINE_BSP , bsp); - _(NVDEV_ENGINE_CE0 , ce[0]); - _(NVDEV_ENGINE_CE1 , ce[1]); - _(NVDEV_ENGINE_CE2 , ce[2]); - _(NVDEV_ENGINE_CIPHER , cipher); - _(NVDEV_ENGINE_DISP , disp); - _(NVDEV_ENGINE_DMAOBJ , dma); - _(NVDEV_ENGINE_FIFO , fifo); - _(NVDEV_ENGINE_GR , gr); - _(NVDEV_ENGINE_IFB , ifb); - _(NVDEV_ENGINE_ME , me); - _(NVDEV_ENGINE_MPEG , mpeg); - _(NVDEV_ENGINE_MSENC , msenc); - _(NVDEV_ENGINE_MSPDEC , mspdec); - _(NVDEV_ENGINE_MSPPP , msppp); - _(NVDEV_ENGINE_MSVLD , msvld); - _(NVDEV_ENGINE_PM , pm); - _(NVDEV_ENGINE_SEC , sec); - _(NVDEV_ENGINE_SW , sw); - _(NVDEV_ENGINE_VIC , vic); - _(NVDEV_ENGINE_VP , vp); - default: - WARN_ON(1); - continue; - } -#undef _ - - /* note: can't init *any* subdevs until devinit has been run - * due to not knowing exactly what the vbios init tables will - * mess with. devinit also can't be run until all of its - * dependencies have been created. - * - * this code delays init of any subdev until all of devinit's - * dependencies have been created, and then initialises each - * subdev in turn as they're created. - */ - while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) { - if ((subdev = nvkm_device_subdev(device, c++))) { - ret = nvkm_subdev_init(subdev); - if (ret) - goto fail; - } + for (i = 0; i < NVKM_SUBDEV_NR; i++) { + if ((subdev = nvkm_device_subdev(device, i))) { + ret = nvkm_subdev_init(subdev); + if (ret) + goto fail; } } @@ -2336,7 +2237,7 @@ nvkm_device_del(struct nvkm_device **pdevice) if (device) { mutex_lock(&nv_devices_mutex); device->disable_mask = 0; - for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) { + for (i = NVKM_SUBDEV_NR - 1; i >= 0; i--) { struct nvkm_subdev *subdev = nvkm_device_subdev(device, i); nvkm_subdev_del(&subdev); @@ -2357,10 +2258,6 @@ nvkm_device_del(struct nvkm_device **pdevice) } } -static const struct nvkm_engine_func -nvkm_device_func = { -}; - int nvkm_device_ctor(const struct nvkm_device_func *func, const struct nvkm_device_quirk *quirk, @@ -2397,12 +2294,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, device->dbgopt = dbg; device->name = name; list_add_tail(&device->head, &nv_devices); - - ret = nvkm_engine_ctor(&nvkm_device_func, device, 0, 0, - true, &device->engine); - device->engine.subdev.object.parent = NULL; - if (ret) - goto done; + device->debug = nvkm_dbgopt(device->dbgopt, "device"); ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event); if (ret) @@ -2472,23 +2364,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, device->card_type = NV_04; } - switch (device->card_type) { - case NV_04: ret = nv04_identify(device); break; - case NV_10: - case NV_11: ret = nv10_identify(device); break; - case NV_20: ret = nv20_identify(device); break; - case NV_30: ret = nv30_identify(device); break; - case NV_40: ret = nv40_identify(device); break; - case NV_50: ret = nv50_identify(device); break; - case NV_C0: ret = gf100_identify(device); break; - case NV_E0: ret = gk104_identify(device); break; - case GM100: ret = gm100_identify(device); break; - default: - ret = -EINVAL; - break; - } - - switch (!ret * device->chipset) { + switch (device->chipset) { case 0x004: device->chip = &nv4_chipset; break; case 0x005: device->chip = &nv5_chipset; break; case 0x010: device->chip = &nv10_chipset; break; @@ -2594,16 +2470,9 @@ nvkm_device_ctor(const struct nvkm_device_func *func, } } - /* disable subdevs that aren't required (used by tools) */ - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { - if (!(subdev_mask & (1ULL << i))) - device->oclass[i] = NULL; - } - - atomic_set(&device->engine.subdev.object.usecount, 2); mutex_init(&device->mutex); - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + for (i = 0; i < NVKM_SUBDEV_NR; i++) { #define _(s,m) case s: \ if (device->chip->m && (subdev_mask & (1ULL << (s)))) { \ ret = device->chip->m(device, (s), &device->m); \ @@ -2620,46 +2489,46 @@ nvkm_device_ctor(const struct nvkm_device_func *func, } \ break switch (i) { - _(NVDEV_SUBDEV_BAR , bar); - _(NVDEV_SUBDEV_VBIOS , bios); - _(NVDEV_SUBDEV_BUS , bus); - _(NVDEV_SUBDEV_CLK , clk); - _(NVDEV_SUBDEV_DEVINIT, devinit); - _(NVDEV_SUBDEV_FB , fb); - _(NVDEV_SUBDEV_FUSE , fuse); - _(NVDEV_SUBDEV_GPIO , gpio); - _(NVDEV_SUBDEV_I2C , i2c); - _(NVDEV_SUBDEV_IBUS , ibus); - _(NVDEV_SUBDEV_INSTMEM, imem); - _(NVDEV_SUBDEV_LTC , ltc); - _(NVDEV_SUBDEV_MC , mc); - _(NVDEV_SUBDEV_MMU , mmu); - _(NVDEV_SUBDEV_MXM , mxm); - _(NVDEV_SUBDEV_PMU , pmu); - _(NVDEV_SUBDEV_THERM , therm); - _(NVDEV_SUBDEV_TIMER , timer); - _(NVDEV_SUBDEV_VOLT , volt); - _(NVDEV_ENGINE_BSP , bsp); - _(NVDEV_ENGINE_CE0 , ce[0]); - _(NVDEV_ENGINE_CE1 , ce[1]); - _(NVDEV_ENGINE_CE2 , ce[2]); - _(NVDEV_ENGINE_CIPHER , cipher); - _(NVDEV_ENGINE_DISP , disp); - _(NVDEV_ENGINE_DMAOBJ , dma); - _(NVDEV_ENGINE_FIFO , fifo); - _(NVDEV_ENGINE_GR , gr); - _(NVDEV_ENGINE_IFB , ifb); - _(NVDEV_ENGINE_ME , me); - _(NVDEV_ENGINE_MPEG , mpeg); - _(NVDEV_ENGINE_MSENC , msenc); - _(NVDEV_ENGINE_MSPDEC , mspdec); - _(NVDEV_ENGINE_MSPPP , msppp); - _(NVDEV_ENGINE_MSVLD , msvld); - _(NVDEV_ENGINE_PM , pm); - _(NVDEV_ENGINE_SEC , sec); - _(NVDEV_ENGINE_SW , sw); - _(NVDEV_ENGINE_VIC , vic); - _(NVDEV_ENGINE_VP , vp); + _(NVKM_SUBDEV_BAR , bar); + _(NVKM_SUBDEV_VBIOS , bios); + _(NVKM_SUBDEV_BUS , bus); + _(NVKM_SUBDEV_CLK , clk); + _(NVKM_SUBDEV_DEVINIT, devinit); + _(NVKM_SUBDEV_FB , fb); + _(NVKM_SUBDEV_FUSE , fuse); + _(NVKM_SUBDEV_GPIO , gpio); + _(NVKM_SUBDEV_I2C , i2c); + _(NVKM_SUBDEV_IBUS , ibus); + _(NVKM_SUBDEV_INSTMEM, imem); + _(NVKM_SUBDEV_LTC , ltc); + _(NVKM_SUBDEV_MC , mc); + _(NVKM_SUBDEV_MMU , mmu); + _(NVKM_SUBDEV_MXM , mxm); + _(NVKM_SUBDEV_PMU , pmu); + _(NVKM_SUBDEV_THERM , therm); + _(NVKM_SUBDEV_TIMER , timer); + _(NVKM_SUBDEV_VOLT , volt); + _(NVKM_ENGINE_BSP , bsp); + _(NVKM_ENGINE_CE0 , ce[0]); + _(NVKM_ENGINE_CE1 , ce[1]); + _(NVKM_ENGINE_CE2 , ce[2]); + _(NVKM_ENGINE_CIPHER , cipher); + _(NVKM_ENGINE_DISP , disp); + _(NVKM_ENGINE_DMAOBJ , dma); + _(NVKM_ENGINE_FIFO , fifo); + _(NVKM_ENGINE_GR , gr); + _(NVKM_ENGINE_IFB , ifb); + _(NVKM_ENGINE_ME , me); + _(NVKM_ENGINE_MPEG , mpeg); + _(NVKM_ENGINE_MSENC , msenc); + _(NVKM_ENGINE_MSPDEC , mspdec); + _(NVKM_ENGINE_MSPPP , msppp); + _(NVKM_ENGINE_MSVLD , msvld); + _(NVKM_ENGINE_PM , pm); + _(NVKM_ENGINE_SEC , sec); + _(NVKM_ENGINE_SW , sw); + _(NVKM_ENGINE_VIC , vic); + _(NVKM_ENGINE_VP , vp); default: WARN_ON(1); continue; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c deleted file mode 100644 index 3c618162923d4..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -gf100_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0xc0: - break; - case 0xc4: - break; - case 0xc3: - break; - case 0xce: - break; - case 0xcf: - break; - case 0xc1: - break; - case 0xc8: - break; - case 0xd9: - break; - case 0xd7: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c deleted file mode 100644 index 4476597187099..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -gk104_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0xe4: - break; - case 0xe7: - break; - case 0xe6: - break; - case 0xea: - break; - case 0xf0: - break; - case 0xf1: - break; - case 0x106: - break; - case 0x108: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c deleted file mode 100644 index e0a214c0cb6eb..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -gm100_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x117: - -#if 0 -#endif -#if 0 -#endif -#if 0 -#endif - break; - case 0x124: -#if 0 - /* looks to be some non-trivial changes */ - /* priv ring says no to 0x10eb14 writes */ -#endif -#if 0 -#endif -#if 0 -#endif - break; - case 0x126: -#if 0 - /* looks to be some non-trivial changes */ - /* priv ring says no to 0x10eb14 writes */ -#endif -#if 0 -#endif -#if 0 -#endif - break; - case 0x12b: - - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c deleted file mode 100644 index 369992ba9c36c..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -nv04_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x04: - break; - case 0x05: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c deleted file mode 100644 index 233f9f9cfda96..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -nv10_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x10: - break; - case 0x15: - break; - case 0x16: - break; - case 0x1a: - break; - case 0x11: - break; - case 0x17: - break; - case 0x1f: - break; - case 0x18: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c deleted file mode 100644 index d6204a954cbaf..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -nv20_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x20: - break; - case 0x25: - break; - case 0x28: - break; - case 0x2a: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c deleted file mode 100644 index 1787f3558d717..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -nv30_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x30: - break; - case 0x35: - break; - case 0x31: - break; - case 0x36: - break; - case 0x34: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c deleted file mode 100644 index d40e18693a730..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -nv40_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x40: - break; - case 0x41: - break; - case 0x42: - break; - case 0x43: - break; - case 0x45: - break; - case 0x47: - break; - case 0x49: - break; - case 0x4b: - break; - case 0x44: - break; - case 0x46: - break; - case 0x4a: - break; - case 0x4c: - break; - case 0x4e: - break; - case 0x63: - break; - case 0x67: - break; - case 0x68: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c deleted file mode 100644 index 8ca1368e10682..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -int -nv50_identify(struct nvkm_device *device) -{ - switch (device->chipset) { - case 0x50: - break; - case 0x84: - break; - case 0x86: - break; - case 0x92: - break; - case 0x94: - break; - case 0x96: - break; - case 0x98: - break; - case 0xa0: - break; - case 0xaa: - break; - case 0xac: - break; - case 0xa3: - break; - case 0xa5: - break; - case 0xa8: - break; - case 0xaf: - break; - default: - return -EINVAL; - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 4cf483894af01..adebf52578c10 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -46,14 +46,4 @@ int nvkm_device_ctor(const struct nvkm_device_func *, struct nvkm_device *); int nvkm_device_init(struct nvkm_device *); int nvkm_device_fini(struct nvkm_device *, bool suspend); - -int nv04_identify(struct nvkm_device *); -int nv10_identify(struct nvkm_device *); -int nv20_identify(struct nvkm_device *); -int nv30_identify(struct nvkm_device *); -int nv40_identify(struct nvkm_device *); -int nv50_identify(struct nvkm_device *); -int gf100_identify(struct nvkm_device *); -int gk104_identify(struct nvkm_device *); -int gm100_identify(struct nvkm_device *); #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index a9df61bf37807..a948960cc0566 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -261,10 +261,10 @@ nvkm_udevice_child_get(struct nvkm_object *object, int index, struct nvkm_udevice *udev = nvkm_udevice(object); struct nvkm_device *device = udev->device; struct nvkm_engine *engine; - u64 mask = (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_FIFO) | - (1ULL << NVDEV_ENGINE_DISP) | - (1ULL << NVDEV_ENGINE_PM); + u64 mask = (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_FIFO) | + (1ULL << NVKM_ENGINE_DISP) | + (1ULL << NVKM_ENGINE_PM); const struct nvkm_device_oclass *sclass = NULL; int i; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c index 9ad9512782a59..b05c04a209bea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c @@ -90,7 +90,7 @@ nv50_disp_dmac_child_get_(struct nv50_disp_chan *base, int index, struct nvkm_device *device = disp->base.engine.subdev.device; const struct nvkm_device_oclass *oclass = NULL; - sclass->engine = nvkm_device_engine(device, NVDEV_ENGINE_DMAOBJ); + sclass->engine = nvkm_device_engine(device, NVKM_ENGINE_DMAOBJ); if (sclass->engine && sclass->engine->func->base.sclass) { sclass->engine->func->base.sclass(sclass, index, &oclass); if (oclass) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index 4ed06abdc9176..a56e56eed57bb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -332,7 +332,7 @@ nvkm_fifo_chan_dtor(struct nvkm_object *object) return data; } -const struct nvkm_object_func +static const struct nvkm_object_func nvkm_fifo_chan_func = { .dtor = nvkm_fifo_chan_dtor, .init = nvkm_fifo_chan_init, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c index a7e5dfae38337..04305241ceed3 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chang84.c @@ -48,16 +48,16 @@ static int g84_fifo_chan_engine(struct nvkm_engine *engine) { switch (engine->subdev.index) { - case NVDEV_ENGINE_GR : return 0; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : return 1; - case NVDEV_ENGINE_CE0 : return 2; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: return 3; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : return 4; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : return 5; + case NVKM_ENGINE_GR : return 0; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : return 1; + case NVKM_ENGINE_CE0 : return 2; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: return 3; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : return 4; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : return 5; default: WARN_ON(1); return 0; @@ -68,18 +68,18 @@ static int g84_fifo_chan_engine_addr(struct nvkm_engine *engine) { switch (engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : return -1; - case NVDEV_ENGINE_GR : return 0x0020; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: return 0x0040; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : return 0x0060; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : return 0x0080; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : return 0x00a0; - case NVDEV_ENGINE_CE0 : return 0x00c0; + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : return -1; + case NVKM_ENGINE_GR : return 0x0020; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: return 0x0040; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : return 0x0060; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : return 0x0080; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : return 0x00a0; + case NVKM_ENGINE_CE0 : return 0x00c0; default: WARN_ON(1); return -1; @@ -167,11 +167,6 @@ g84_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, if (g84_fifo_chan_engine_addr(engine) < 0) return 0; - if (nv_iclass(object, NV_GPUOBJ_CLASS)) { - chan->engn[engn] = nv_gpuobj(object); - return 0; - } - return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); } @@ -184,20 +179,20 @@ g84_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, u32 context; switch (object->engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context = 0x00000000; break; - case NVDEV_ENGINE_GR : context = 0x00100000; break; - case NVDEV_ENGINE_MPEG : - case NVDEV_ENGINE_MSPPP : context = 0x00200000; break; - case NVDEV_ENGINE_ME : - case NVDEV_ENGINE_CE0 : context = 0x00300000; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: context = 0x00400000; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : - case NVDEV_ENGINE_VIC : context = 0x00500000; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : context = 0x00600000; break; + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context = 0x00000000; break; + case NVKM_ENGINE_GR : context = 0x00100000; break; + case NVKM_ENGINE_MPEG : + case NVKM_ENGINE_MSPPP : context = 0x00200000; break; + case NVKM_ENGINE_ME : + case NVKM_ENGINE_CE0 : context = 0x00300000; break; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: context = 0x00400000; break; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : + case NVKM_ENGINE_VIC : context = 0x00500000; break; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : context = 0x00600000; break; default: WARN_ON(1); return -EINVAL; @@ -243,20 +238,20 @@ g84_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, ret = nvkm_fifo_chan_ctor(&g84_fifo_chan_func, &fifo->base, 0x10000, 0x1000, false, vm, push, - (1ULL << NVDEV_ENGINE_BSP) | - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_CIPHER) | - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_ME) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_SEC) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_VIC) | - (1ULL << NVDEV_ENGINE_VP), + (1ULL << NVKM_ENGINE_BSP) | + (1ULL << NVKM_ENGINE_CE0) | + (1ULL << NVKM_ENGINE_CIPHER) | + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_ME) | + (1ULL << NVKM_ENGINE_MPEG) | + (1ULL << NVKM_ENGINE_MSPDEC) | + (1ULL << NVKM_ENGINE_MSPPP) | + (1ULL << NVKM_ENGINE_MSVLD) | + (1ULL << NVKM_ENGINE_SEC) | + (1ULL << NVKM_ENGINE_SW) | + (1ULL << NVKM_ENGINE_VIC) | + (1ULL << NVKM_ENGINE_VP), 0, 0xc00000, 0x2000, oclass, &chan->base); chan->fifo = fifo; if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h index 413288597e04c..7d697e2dce1ab 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changf100.h @@ -17,7 +17,7 @@ struct gf100_fifo_chan { struct { struct nvkm_gpuobj *inst; struct nvkm_vma vma; - } engn[NVDEV_SUBDEV_NR]; + } engn[NVKM_SUBDEV_NR]; }; extern const struct nvkm_fifo_chan_oclass gf100_fifo_gpfifo_oclass; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h index 2b9d8bfc7fd7e..97bdddb7644a0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/changk104.h @@ -18,7 +18,7 @@ struct gk104_fifo_chan { struct { struct nvkm_gpuobj *inst; struct nvkm_vma vma; - } engn[NVDEV_SUBDEV_NR]; + } engn[NVKM_SUBDEV_NR]; }; int gk104_fifo_gpfifo_new(struct nvkm_fifo *, const struct nvkm_oclass *, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h index ac62a6404f873..3361a1fd03438 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv04.h @@ -8,7 +8,7 @@ struct nv04_fifo_chan { struct nvkm_fifo_chan base; struct nv04_fifo *fifo; u32 ramfc; - struct nvkm_gpuobj *engn[NVDEV_SUBDEV_NR]; + struct nvkm_gpuobj *engn[NVKM_SUBDEV_NR]; }; extern const struct nvkm_fifo_chan_func nv04_fifo_dma_func; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c index 2a25019ce0f47..25b60aff40e47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.c @@ -32,10 +32,10 @@ static int nv50_fifo_chan_engine_addr(struct nvkm_engine *engine) { switch (engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : return -1; - case NVDEV_ENGINE_GR : return 0x0000; - case NVDEV_ENGINE_MPEG : return 0x0060; + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : return -1; + case NVKM_ENGINE_GR : return 0x0000; + case NVKM_ENGINE_MPEG : return 0x0060; default: WARN_ON(1); return -1; @@ -130,11 +130,6 @@ nv50_fifo_chan_engine_dtor(struct nvkm_fifo_chan *base, struct nvkm_engine *engine) { struct nv50_fifo_chan *chan = nv50_fifo_chan(base); - if (!chan->engn[engine->subdev.index] || - chan->engn[engine->subdev.index]->object.oclass) { - chan->engn[engine->subdev.index] = NULL; - return; - } nvkm_gpuobj_del(&chan->engn[engine->subdev.index]); } @@ -149,11 +144,6 @@ nv50_fifo_chan_engine_ctor(struct nvkm_fifo_chan *base, if (nv50_fifo_chan_engine_addr(engine) < 0) return 0; - if (nv_iclass(object, NV_GPUOBJ_CLASS)) { - chan->engn[engn] = nv_gpuobj(object); - return 0; - } - return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); } @@ -173,10 +163,10 @@ nv50_fifo_chan_object_ctor(struct nvkm_fifo_chan *base, u32 context; switch (object->engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context = 0x00000000; break; - case NVDEV_ENGINE_GR : context = 0x00100000; break; - case NVDEV_ENGINE_MPEG : context = 0x00200000; break; + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context = 0x00000000; break; + case NVKM_ENGINE_GR : context = 0x00100000; break; + case NVKM_ENGINE_MPEG : context = 0x00200000; break; default: WARN_ON(1); return -EINVAL; @@ -248,10 +238,10 @@ nv50_fifo_chan_ctor(struct nv50_fifo *fifo, u64 vm, u64 push, ret = nvkm_fifo_chan_ctor(&nv50_fifo_chan_func, &fifo->base, 0x10000, 0x1000, false, vm, push, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG), + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_SW) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MPEG), 0, 0xc00000, 0x2000, oclass, &chan->base); chan->fifo = fifo; if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h index 7ef6bc2e27ecf..4b9da469b704e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/channv50.h @@ -15,7 +15,7 @@ struct nv50_fifo_chan { struct nvkm_ramht *ramht; struct nvkm_vm *vm; - struct nvkm_gpuobj *engn[NVDEV_SUBDEV_NR]; + struct nvkm_gpuobj *engn[NVKM_SUBDEV_NR]; }; int nv50_fifo_chan_ctor(struct nv50_fifo *, u64 vm, u64 push, diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c index 52cbc4b47b2c6..bfcc6408a7720 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv04.c @@ -50,10 +50,10 @@ nv04_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, int hash; switch (object->engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00010000; break; - case NVDEV_ENGINE_MPEG : context |= 0x00020000; break; + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context |= 0x00000000; break; + case NVKM_ENGINE_GR : context |= 0x00010000; break; + case NVKM_ENGINE_MPEG : context |= 0x00020000; break; default: WARN_ON(1); return -EINVAL; @@ -185,9 +185,9 @@ nv04_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, 0x1000, 0x1000, false, 0, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_SW), + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_SW), 0, 0x800000, 0x10000, oclass, &chan->base); chan->fifo = fifo; if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c index d8e4d55704d1d..34f68e5bd0404 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv10.c @@ -61,9 +61,9 @@ nv10_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, 0x1000, 0x1000, false, 0, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_SW), + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_SW), 0, 0x800000, 0x10000, oclass, &chan->base); chan->fifo = fifo; if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c index 1424dd9b62998..ed7cc9f2b5403 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv17.c @@ -61,10 +61,10 @@ nv17_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, ret = nvkm_fifo_chan_ctor(&nv04_fifo_dma_func, &fifo->base, 0x1000, 0x1000, false, 0, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | /* NV31- */ - (1ULL << NVDEV_ENGINE_SW), + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MPEG) | /* NV31- */ + (1ULL << NVKM_ENGINE_SW), 0, 0x800000, 0x10000, oclass, &chan->base); chan->fifo = fifo; if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c index b46a3b3cd0924..043b6c3259499 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/dmanv40.c @@ -35,14 +35,14 @@ static bool nv40_fifo_dma_engine(struct nvkm_engine *engine, u32 *reg, u32 *ctx) { switch (engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW: + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW: return false; - case NVDEV_ENGINE_GR: + case NVKM_ENGINE_GR: *reg = 0x0032e0; *ctx = 0x38; return true; - case NVDEV_ENGINE_MPEG: + case NVKM_ENGINE_MPEG: *reg = 0x00330c; *ctx = 0x54; return true; @@ -118,11 +118,6 @@ nv40_fifo_dma_engine_dtor(struct nvkm_fifo_chan *base, struct nvkm_engine *engine) { struct nv04_fifo_chan *chan = nv04_fifo_chan(base); - if (!chan->engn[engine->subdev.index] || - chan->engn[engine->subdev.index]->object.oclass) { - chan->engn[engine->subdev.index] = NULL; - return; - } nvkm_gpuobj_del(&chan->engn[engine->subdev.index]); } @@ -138,11 +133,6 @@ nv40_fifo_dma_engine_ctor(struct nvkm_fifo_chan *base, if (!nv40_fifo_dma_engine(engine, ®, &ctx)) return 0; - if (nv_iclass(object, NV_GPUOBJ_CLASS)) { - chan->engn[engn] = nv_gpuobj(object); - return 0; - } - return nvkm_object_bind(object, NULL, 0, &chan->engn[engn]); } @@ -157,10 +147,10 @@ nv40_fifo_dma_object_ctor(struct nvkm_fifo_chan *base, int hash; switch (object->engine->subdev.index) { - case NVDEV_ENGINE_DMAOBJ: - case NVDEV_ENGINE_SW : context |= 0x00000000; break; - case NVDEV_ENGINE_GR : context |= 0x00100000; break; - case NVDEV_ENGINE_MPEG : context |= 0x00200000; break; + case NVKM_ENGINE_DMAOBJ: + case NVKM_ENGINE_SW : context |= 0x00000000; break; + case NVKM_ENGINE_GR : context |= 0x00100000; break; + case NVKM_ENGINE_MPEG : context |= 0x00200000; break; default: WARN_ON(1); return -EINVAL; @@ -216,10 +206,10 @@ nv40_fifo_dma_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, ret = nvkm_fifo_chan_ctor(&nv40_fifo_dma_func, &fifo->base, 0x1000, 0x1000, false, 0, args->v0.pushbuf, - (1ULL << NVDEV_ENGINE_DMAOBJ) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MPEG) | - (1ULL << NVDEV_ENGINE_SW), + (1ULL << NVKM_ENGINE_DMAOBJ) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MPEG) | + (1ULL << NVKM_ENGINE_SW), 0, 0xc00000, 0x1000, oclass, &chan->base); chan->fifo = fifo; if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index bc094223f6877..172f243011137 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -82,12 +82,12 @@ static inline int gf100_fifo_engidx(struct gf100_fifo *fifo, u32 engn) { switch (engn) { - case NVDEV_ENGINE_GR : engn = 0; break; - case NVDEV_ENGINE_MSVLD : engn = 1; break; - case NVDEV_ENGINE_MSPPP : engn = 2; break; - case NVDEV_ENGINE_MSPDEC: engn = 3; break; - case NVDEV_ENGINE_CE0 : engn = 4; break; - case NVDEV_ENGINE_CE1 : engn = 5; break; + case NVKM_ENGINE_GR : engn = 0; break; + case NVKM_ENGINE_MSVLD : engn = 1; break; + case NVKM_ENGINE_MSPPP : engn = 2; break; + case NVKM_ENGINE_MSPDEC: engn = 3; break; + case NVKM_ENGINE_CE0 : engn = 4; break; + case NVKM_ENGINE_CE1 : engn = 5; break; default: return -1; } @@ -101,12 +101,12 @@ gf100_fifo_engine(struct gf100_fifo *fifo, u32 engn) struct nvkm_device *device = fifo->base.engine.subdev.device; switch (engn) { - case 0: engn = NVDEV_ENGINE_GR; break; - case 1: engn = NVDEV_ENGINE_MSVLD; break; - case 2: engn = NVDEV_ENGINE_MSPPP; break; - case 3: engn = NVDEV_ENGINE_MSPDEC; break; - case 4: engn = NVDEV_ENGINE_CE0; break; - case 5: engn = NVDEV_ENGINE_CE1; break; + case 0: engn = NVKM_ENGINE_GR; break; + case 1: engn = NVKM_ENGINE_MSVLD; break; + case 2: engn = NVKM_ENGINE_MSPPP; break; + case 3: engn = NVKM_ENGINE_MSPDEC; break; + case 4: engn = NVKM_ENGINE_CE0; break; + case 5: engn = NVKM_ENGINE_CE1; break; default: return NULL; } @@ -229,17 +229,17 @@ gf100_fifo_intr_sched(struct gf100_fifo *fifo) static const struct nvkm_enum gf100_fifo_fault_engine[] = { - { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR }, - { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB }, - { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, - { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, - { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO }, - { 0x10, "PMSVLD", NULL, NVDEV_ENGINE_MSVLD }, - { 0x11, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP }, + { 0x00, "PGRAPH", NULL, NVKM_ENGINE_GR }, + { 0x03, "PEEPHOLE", NULL, NVKM_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, + { 0x07, "PFIFO", NULL, NVKM_ENGINE_FIFO }, + { 0x10, "PMSVLD", NULL, NVKM_ENGINE_MSVLD }, + { 0x11, "PMSPPP", NULL, NVKM_ENGINE_MSPPP }, { 0x13, "PCOUNTER" }, - { 0x14, "PMSPDEC", NULL, NVDEV_ENGINE_MSPDEC }, - { 0x15, "PCE0", NULL, NVDEV_ENGINE_CE0 }, - { 0x16, "PCE1", NULL, NVDEV_ENGINE_CE1 }, + { 0x14, "PMSPDEC", NULL, NVKM_ENGINE_MSPDEC }, + { 0x15, "PCE0", NULL, NVKM_ENGINE_CE0 }, + { 0x16, "PCE1", NULL, NVKM_ENGINE_CE1 }, { 0x17, "PDAEMON" }, {} }; @@ -317,13 +317,13 @@ gf100_fifo_intr_fault(struct gf100_fifo *fifo, int unit) if (eu) { switch (eu->data2) { - case NVDEV_SUBDEV_BAR: + case NVKM_SUBDEV_BAR: nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); break; - case NVDEV_SUBDEV_INSTMEM: + case NVKM_SUBDEV_INSTMEM: nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); break; - case NVDEV_ENGINE_IFB: + case NVKM_ENGINE_IFB: nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index 465b52dee2777..fc0ff2d37d069 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -248,22 +248,22 @@ gk104_fifo_intr_dropped_fault(struct gk104_fifo *fifo) static const struct nvkm_enum gk104_fifo_fault_engine[] = { - { 0x00, "GR", NULL, NVDEV_ENGINE_GR }, - { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB }, - { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR }, - { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM }, - { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO }, - { 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO }, - { 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO }, - { 0x10, "MSVLD", NULL, NVDEV_ENGINE_MSVLD }, - { 0x11, "MSPPP", NULL, NVDEV_ENGINE_MSPPP }, + { 0x00, "GR", NULL, NVKM_ENGINE_GR }, + { 0x03, "IFB", NULL, NVKM_ENGINE_IFB }, + { 0x04, "BAR1", NULL, NVKM_SUBDEV_BAR }, + { 0x05, "BAR3", NULL, NVKM_SUBDEV_INSTMEM }, + { 0x07, "PBDMA0", NULL, NVKM_ENGINE_FIFO }, + { 0x08, "PBDMA1", NULL, NVKM_ENGINE_FIFO }, + { 0x09, "PBDMA2", NULL, NVKM_ENGINE_FIFO }, + { 0x10, "MSVLD", NULL, NVKM_ENGINE_MSVLD }, + { 0x11, "MSPPP", NULL, NVKM_ENGINE_MSPPP }, { 0x13, "PERF" }, - { 0x14, "MSPDEC", NULL, NVDEV_ENGINE_MSPDEC }, - { 0x15, "CE0", NULL, NVDEV_ENGINE_CE0 }, - { 0x16, "CE1", NULL, NVDEV_ENGINE_CE1 }, + { 0x14, "MSPDEC", NULL, NVKM_ENGINE_MSPDEC }, + { 0x15, "CE0", NULL, NVKM_ENGINE_CE0 }, + { 0x16, "CE1", NULL, NVKM_ENGINE_CE1 }, { 0x17, "PMU" }, - { 0x19, "MSENC", NULL, NVDEV_ENGINE_MSENC }, - { 0x1b, "CE2", NULL, NVDEV_ENGINE_CE2 }, + { 0x19, "MSENC", NULL, NVKM_ENGINE_MSENC }, + { 0x1b, "CE2", NULL, NVKM_ENGINE_CE2 }, {} }; @@ -382,13 +382,13 @@ gk104_fifo_intr_fault(struct gk104_fifo *fifo, int unit) if (eu) { switch (eu->data2) { - case NVDEV_SUBDEV_BAR: + case NVKM_SUBDEV_BAR: nvkm_mask(device, 0x001704, 0x00000000, 0x00000000); break; - case NVDEV_SUBDEV_INSTMEM: + case NVKM_SUBDEV_INSTMEM: nvkm_mask(device, 0x001714, 0x00000000, 0x00000000); break; - case NVDEV_ENGINE_IFB: + case NVKM_ENGINE_IFB: nvkm_mask(device, 0x001718, 0x00000000, 0x00000000); break; default: diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h index 7a5c544a5ffbb..5afd9b5ec5d18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h @@ -41,15 +41,15 @@ static inline u64 gk104_fifo_engine_subdev(int engine) { switch (engine) { - case 0: return (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_SW) | - (1ULL << NVDEV_ENGINE_CE2); - case 1: return (1ULL << NVDEV_ENGINE_MSPDEC); - case 2: return (1ULL << NVDEV_ENGINE_MSPPP); - case 3: return (1ULL << NVDEV_ENGINE_MSVLD); - case 4: return (1ULL << NVDEV_ENGINE_CE0); - case 5: return (1ULL << NVDEV_ENGINE_CE1); - case 6: return (1ULL << NVDEV_ENGINE_MSENC); + case 0: return (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_SW) | + (1ULL << NVKM_ENGINE_CE2); + case 1: return (1ULL << NVKM_ENGINE_MSPDEC); + case 2: return (1ULL << NVKM_ENGINE_MSPPP); + case 3: return (1ULL << NVKM_ENGINE_MSVLD); + case 4: return (1ULL << NVKM_ENGINE_CE0); + case 5: return (1ULL << NVKM_ENGINE_CE1); + case 6: return (1ULL << NVKM_ENGINE_MSENC); default: WARN_ON(1); return 0; @@ -60,15 +60,15 @@ static inline int gk104_fifo_subdev_engine(int subdev) { switch (subdev) { - case NVDEV_ENGINE_GR: - case NVDEV_ENGINE_SW: - case NVDEV_ENGINE_CE2 : return 0; - case NVDEV_ENGINE_MSPDEC: return 1; - case NVDEV_ENGINE_MSPPP : return 2; - case NVDEV_ENGINE_MSVLD : return 3; - case NVDEV_ENGINE_CE0 : return 4; - case NVDEV_ENGINE_CE1 : return 5; - case NVDEV_ENGINE_MSENC : return 6; + case NVKM_ENGINE_GR: + case NVKM_ENGINE_SW: + case NVKM_ENGINE_CE2 : return 0; + case NVKM_ENGINE_MSPDEC: return 1; + case NVKM_ENGINE_MSPPP : return 2; + case NVKM_ENGINE_MSVLD : return 3; + case NVKM_ENGINE_CE0 : return 4; + case NVKM_ENGINE_CE1 : return 5; + case NVKM_ENGINE_MSENC : return 6; default: WARN_ON(1); return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c index 5d76c3013a807..e7cbc139c1d4f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogf100.c @@ -35,13 +35,13 @@ static u32 gf100_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) { switch (engine->subdev.index) { - case NVDEV_ENGINE_SW : return 0; - case NVDEV_ENGINE_GR : return 0x0210; - case NVDEV_ENGINE_CE0 : return 0x0230; - case NVDEV_ENGINE_CE1 : return 0x0240; - case NVDEV_ENGINE_MSPDEC: return 0x0250; - case NVDEV_ENGINE_MSPPP : return 0x0260; - case NVDEV_ENGINE_MSVLD : return 0x0270; + case NVKM_ENGINE_SW : return 0; + case NVKM_ENGINE_GR : return 0x0210; + case NVKM_ENGINE_CE0 : return 0x0230; + case NVKM_ENGINE_CE1 : return 0x0240; + case NVKM_ENGINE_MSPDEC: return 0x0250; + case NVKM_ENGINE_MSPPP : return 0x0260; + case NVKM_ENGINE_MSVLD : return 0x0270; default: WARN_ON(1); return 0; @@ -121,12 +121,6 @@ gf100_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, if (!gf100_fifo_gpfifo_engine_addr(engine)) return 0; - if (object->oclass) { - return nvkm_gpuobj_map(nv_gpuobj(object), chan->vm, - NV_MEM_ACCESS_RW, - &chan->engn[engn].vma); - } - ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst); if (ret) return ret; @@ -225,13 +219,13 @@ gf100_fifo_gpfifo_new(struct nvkm_fifo *base, const struct nvkm_oclass *oclass, ret = nvkm_fifo_chan_ctor(&gf100_fifo_gpfifo_func, &fifo->base, 0x1000, 0x1000, true, args->v0.vm, 0, - (1ULL << NVDEV_ENGINE_CE0) | - (1ULL << NVDEV_ENGINE_CE1) | - (1ULL << NVDEV_ENGINE_GR) | - (1ULL << NVDEV_ENGINE_MSPDEC) | - (1ULL << NVDEV_ENGINE_MSPPP) | - (1ULL << NVDEV_ENGINE_MSVLD) | - (1ULL << NVDEV_ENGINE_SW), + (1ULL << NVKM_ENGINE_CE0) | + (1ULL << NVKM_ENGINE_CE1) | + (1ULL << NVKM_ENGINE_GR) | + (1ULL << NVKM_ENGINE_MSPDEC) | + (1ULL << NVKM_ENGINE_MSPPP) | + (1ULL << NVKM_ENGINE_MSVLD) | + (1ULL << NVKM_ENGINE_SW), 1, fifo->user.bar.offset, 0x1000, oclass, &chan->base); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c index fe39981915b64..0b817540a9e4f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gpfifogk104.c @@ -57,14 +57,14 @@ static u32 gk104_fifo_gpfifo_engine_addr(struct nvkm_engine *engine) { switch (engine->subdev.index) { - case NVDEV_ENGINE_SW : - case NVDEV_ENGINE_CE0 : - case NVDEV_ENGINE_CE1 : - case NVDEV_ENGINE_CE2 : return 0x0000; - case NVDEV_ENGINE_GR : return 0x0210; - case NVDEV_ENGINE_MSPDEC: return 0x0250; - case NVDEV_ENGINE_MSPPP : return 0x0260; - case NVDEV_ENGINE_MSVLD : return 0x0270; + case NVKM_ENGINE_SW : + case NVKM_ENGINE_CE0 : + case NVKM_ENGINE_CE1 : + case NVKM_ENGINE_CE2 : return 0x0000; + case NVKM_ENGINE_GR : return 0x0210; + case NVKM_ENGINE_MSPDEC: return 0x0250; + case NVKM_ENGINE_MSPPP : return 0x0260; + case NVKM_ENGINE_MSVLD : return 0x0270; default: WARN_ON(1); return 0; @@ -134,12 +134,6 @@ gk104_fifo_gpfifo_engine_ctor(struct nvkm_fifo_chan *base, if (!gk104_fifo_gpfifo_engine_addr(engine)) return 0; - if (object->oclass) { - return nvkm_gpuobj_map(nv_gpuobj(object), chan->vm, - NV_MEM_ACCESS_RW, - &chan->engn[engn].vma); - } - ret = nvkm_object_bind(object, NULL, 0, &chan->engn[engn].inst); if (ret) return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 7b4317ab8f02f..426ba0025a8d0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1047,7 +1047,7 @@ nv04_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); nvkm_wo32(*pgpuobj, 0x04, 0x00000000); nvkm_wo32(*pgpuobj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 127a36f5859e6..7987df18415b5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -48,7 +48,7 @@ nv40_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); nvkm_wo32(*pgpuobj, 0x04, 0x00000000); nvkm_wo32(*pgpuobj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c index 9992a919a6d9a..b19b912d57877 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c @@ -45,7 +45,7 @@ nv50_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, align, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); nvkm_wo32(*pgpuobj, 0x04, 0x00000000); nvkm_wo32(*pgpuobj, 0x08, 0x00000000); nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c index 87420b8329ac2..d4d8942b13472 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c @@ -43,7 +43,7 @@ nv31_mpeg_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, false, parent, pgpuobj); if (ret == 0) { nvkm_kmap(*pgpuobj); - nvkm_wo32(*pgpuobj, 0x00, object->oclass_name); + nvkm_wo32(*pgpuobj, 0x00, object->oclass); nvkm_wo32(*pgpuobj, 0x04, 0x00000000); nvkm_wo32(*pgpuobj, 0x08, 0x00000000); nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 03ce10fcba4f4..2eb0a370a3a0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -64,7 +64,7 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); /* * Bootstrap page table lookup. diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index 65646fb917c13..fac54f97217e5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -88,7 +88,7 @@ nv50_bar_oneinit(struct nvkm_bar *base) if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); ret = nvkm_vm_boot(vm, limit-- - start); if (ret) @@ -121,7 +121,7 @@ nv50_bar_oneinit(struct nvkm_bar *base) if (ret) return ret; - atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]); + atomic_inc(&vm->engref[NVKM_SUBDEV_BAR]); ret = nvkm_vm_ref(vm, &bar->bar1_vm, bar->pgd); nvkm_vm_ref(NULL, &vm, NULL); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c index 18871a3caa28e..e895289bf3c17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c @@ -35,18 +35,18 @@ g84_devinit_disable(struct nvkm_devinit *init) u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MPEG); - disable |= (1ULL << NVDEV_ENGINE_VP); - disable |= (1ULL << NVDEV_ENGINE_BSP); - disable |= (1ULL << NVDEV_ENGINE_CIPHER); + disable |= (1ULL << NVKM_ENGINE_MPEG); + disable |= (1ULL << NVKM_ENGINE_VP); + disable |= (1ULL << NVKM_ENGINE_BSP); + disable |= (1ULL << NVKM_ENGINE_CIPHER); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_BSP); + disable |= (1ULL << NVKM_ENGINE_BSP); if (!(r00154c & 0x00000040)) - disable |= (1ULL << NVDEV_ENGINE_CIPHER); + disable |= (1ULL << NVKM_ENGINE_CIPHER); return disable; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c index a381efa9ae4a6..a9d45844df5a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c @@ -35,17 +35,17 @@ g98_devinit_disable(struct nvkm_devinit *init) u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSVLD); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (!(r00154c & 0x00000040)) - disable |= (1ULL << NVDEV_ENGINE_SEC); + disable |= (1ULL << NVKM_ENGINE_SEC); return disable; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c index a9f2d02b6e187..22b0140e28c65 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c @@ -71,21 +71,21 @@ gf100_devinit_disable(struct nvkm_devinit *init) u64 disable = 0ULL; if (r022500 & 0x00000001) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (r022500 & 0x00000002) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (r022500 & 0x00000004) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (r022500 & 0x00000008) - disable |= (1ULL << NVDEV_ENGINE_MSENC); + disable |= (1ULL << NVKM_ENGINE_MSENC); if (r022500 & 0x00000100) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); if (r022500 & 0x00000200) - disable |= (1ULL << NVDEV_ENGINE_CE1); + disable |= (1ULL << NVKM_ENGINE_CE1); return disable; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c index f0f84fef2350f..2be98bd782144 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c @@ -35,11 +35,11 @@ gm107_devinit_disable(struct nvkm_devinit *init) u64 disable = 0ULL; if (r021c00 & 0x00000001) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); if (r021c00 & 0x00000004) - disable |= (1ULL << NVDEV_ENGINE_CE2); + disable |= (1ULL << NVKM_ENGINE_CE2); if (r021c04 & 0x00000001) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); return disable; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c index 38f9827902e97..9a8522fa9c652 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c @@ -71,16 +71,16 @@ gt215_devinit_disable(struct nvkm_devinit *init) u64 disable = 0ULL; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (!(r00154c & 0x00000200)) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); return disable; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c index 892f5ea86d57e..ce4f718e98a17 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c @@ -35,18 +35,18 @@ mcp89_devinit_disable(struct nvkm_devinit *init) u64 disable = 0; if (!(r001540 & 0x40000000)) { - disable |= (1ULL << NVDEV_ENGINE_MSPDEC); - disable |= (1ULL << NVDEV_ENGINE_MSPPP); + disable |= (1ULL << NVKM_ENGINE_MSPDEC); + disable |= (1ULL << NVKM_ENGINE_MSPPP); } if (!(r00154c & 0x00000004)) - disable |= (1ULL << NVDEV_ENGINE_DISP); + disable |= (1ULL << NVKM_ENGINE_DISP); if (!(r00154c & 0x00000020)) - disable |= (1ULL << NVDEV_ENGINE_MSVLD); + disable |= (1ULL << NVKM_ENGINE_MSVLD); if (!(r00154c & 0x00000040)) - disable |= (1ULL << NVDEV_ENGINE_VIC); + disable |= (1ULL << NVKM_ENGINE_VIC); if (!(r00154c & 0x00000200)) - disable |= (1ULL << NVDEV_ENGINE_CE0); + disable |= (1ULL << NVKM_ENGINE_CE0); return disable; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c index e183729bfee0b..337c2c692dc75 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c @@ -85,7 +85,7 @@ nv50_devinit_disable(struct nvkm_devinit *init) u64 disable = 0ULL; if (!(r001540 & 0x40000000)) - disable |= (1ULL << NVDEV_ENGINE_MPEG); + disable |= (1ULL << NVKM_ENGINE_MPEG); return disable; } @@ -103,7 +103,7 @@ nv50_devinit_preinit(struct nvkm_devinit *base) */ if (!init->base.post) { u64 disable = nvkm_devinit_disable(&init->base); - if (disable & (1ULL << NVDEV_ENGINE_DISP)) + if (disable & (1ULL << NVKM_ENGINE_DISP)) init->base.post = true; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 44286a4bb356c..2936fabb7cf18 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -25,22 +25,22 @@ static const struct nvkm_mc_intr g98_mc_intr[] = { - { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */ - { 0x00000001, NVDEV_ENGINE_MSPPP }, - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00004000, NVDEV_ENGINE_SEC }, /* NV84:NVA3 */ - { 0x00008000, NVDEV_ENGINE_MSVLD }, - { 0x00020000, NVDEV_ENGINE_MSPDEC }, - { 0x00040000, NVDEV_SUBDEV_PMU }, /* NVA3:NVC0 */ - { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */ - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x00400000, NVDEV_ENGINE_CE0 }, /* NVA3- */ - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x80000000, NVDEV_ENGINE_SW }, - { 0x0042d101, NVDEV_SUBDEV_FB }, + { 0x04000000, NVKM_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */ + { 0x00000001, NVKM_ENGINE_MSPPP }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00004000, NVKM_ENGINE_SEC }, /* NV84:NVA3 */ + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00020000, NVKM_ENGINE_MSPDEC }, + { 0x00040000, NVKM_SUBDEV_PMU }, /* NVA3:NVC0 */ + { 0x00080000, NVKM_SUBDEV_THERM }, /* NVA3:NVC0 */ + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x00200000, NVKM_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVKM_SUBDEV_I2C }, /* PMGR->I2C/AUX */ + { 0x00400000, NVKM_ENGINE_CE0 }, /* NVA3- */ + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x80000000, NVKM_ENGINE_SW }, + { 0x0042d101, NVKM_SUBDEV_FB }, {}, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 26f68d7e7ccc4..6e7af483ccf3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -25,26 +25,26 @@ const struct nvkm_mc_intr gf100_mc_intr[] = { - { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */ - { 0x00000001, NVDEV_ENGINE_MSPPP }, - { 0x00000020, NVDEV_ENGINE_CE0 }, - { 0x00000040, NVDEV_ENGINE_CE1 }, - { 0x00000080, NVDEV_ENGINE_CE2 }, - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00002000, NVDEV_SUBDEV_FB }, - { 0x00008000, NVDEV_ENGINE_MSVLD }, - { 0x00040000, NVDEV_SUBDEV_THERM }, - { 0x00020000, NVDEV_ENGINE_MSPDEC }, - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x01000000, NVDEV_SUBDEV_PMU }, - { 0x02000000, NVDEV_SUBDEV_LTC }, - { 0x08000000, NVDEV_SUBDEV_FB }, - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x40000000, NVDEV_SUBDEV_IBUS }, - { 0x80000000, NVDEV_ENGINE_SW }, + { 0x04000000, NVKM_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */ + { 0x00000001, NVKM_ENGINE_MSPPP }, + { 0x00000020, NVKM_ENGINE_CE0 }, + { 0x00000040, NVKM_ENGINE_CE1 }, + { 0x00000080, NVKM_ENGINE_CE2 }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00002000, NVKM_SUBDEV_FB }, + { 0x00008000, NVKM_ENGINE_MSVLD }, + { 0x00040000, NVKM_SUBDEV_THERM }, + { 0x00020000, NVKM_ENGINE_MSPDEC }, + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x00200000, NVKM_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVKM_SUBDEV_I2C }, /* PMGR->I2C/AUX */ + { 0x01000000, NVKM_SUBDEV_PMU }, + { 0x02000000, NVKM_SUBDEV_LTC }, + { 0x08000000, NVKM_SUBDEV_FB }, + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x40000000, NVKM_SUBDEV_IBUS }, + { 0x80000000, NVKM_ENGINE_SW }, {}, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index bcba7bc9737b5..09dc2ebae7bc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -25,16 +25,16 @@ const struct nvkm_mc_intr nv04_mc_intr[] = { - { 0x00000001, NVDEV_ENGINE_MPEG }, /* NV17- MPEG/ME */ - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00010000, NVDEV_ENGINE_DISP }, - { 0x00020000, NVDEV_ENGINE_VP }, /* NV40- */ - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */ - { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */ - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x80000000, NVDEV_ENGINE_SW }, + { 0x00000001, NVKM_ENGINE_MPEG }, /* NV17- MPEG/ME */ + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00010000, NVKM_ENGINE_DISP }, + { 0x00020000, NVKM_ENGINE_VP }, /* NV40- */ + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x01000000, NVKM_ENGINE_DISP }, /* NV04- PCRTC0 */ + { 0x02000000, NVKM_ENGINE_DISP }, /* NV11- PCRTC1 */ + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x80000000, NVKM_ENGINE_SW }, {} }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index b5a36c97e7718..071789927615a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -25,19 +25,19 @@ const struct nvkm_mc_intr nv50_mc_intr[] = { - { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ - { 0x00000001, NVDEV_ENGINE_MPEG }, - { 0x00000100, NVDEV_ENGINE_FIFO }, - { 0x00001000, NVDEV_ENGINE_GR }, - { 0x00004000, NVDEV_ENGINE_CIPHER }, /* NV84- */ - { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */ - { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */ - { 0x00100000, NVDEV_SUBDEV_TIMER }, - { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */ - { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */ - { 0x10000000, NVDEV_SUBDEV_BUS }, - { 0x80000000, NVDEV_ENGINE_SW }, - { 0x0002d101, NVDEV_SUBDEV_FB }, + { 0x04000000, NVKM_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */ + { 0x00000001, NVKM_ENGINE_MPEG }, + { 0x00000100, NVKM_ENGINE_FIFO }, + { 0x00001000, NVKM_ENGINE_GR }, + { 0x00004000, NVKM_ENGINE_CIPHER }, /* NV84- */ + { 0x00008000, NVKM_ENGINE_BSP }, /* NV84- */ + { 0x00020000, NVKM_ENGINE_VP }, /* NV84- */ + { 0x00100000, NVKM_SUBDEV_TIMER }, + { 0x00200000, NVKM_SUBDEV_GPIO }, /* PMGR->GPIO */ + { 0x00200000, NVKM_SUBDEV_I2C }, /* PMGR->I2C/AUX */ + { 0x10000000, NVKM_SUBDEV_BUS }, + { 0x80000000, NVKM_ENGINE_SW }, + { 0x0002d101, NVKM_SUBDEV_FB }, {}, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c index 5f6c5df15a958..7ac507c927bb0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c @@ -167,7 +167,7 @@ gf100_vm_flush(struct nvkm_vm *vm) u32 type; type = 0x00000001; /* PAGE_ALL */ - if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR])) + if (atomic_read(&vm->engref[NVKM_SUBDEV_BAR])) type |= 0x00000004; /* HUB_ONLY */ mutex_lock(&mmu->subdev.mutex); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c index 21a990c1ac8bb..a1f8d65f02761 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c @@ -161,29 +161,29 @@ nv50_vm_flush(struct nvkm_vm *vm) int i, vme; mutex_lock(&subdev->mutex); - for (i = 0; i < NVDEV_SUBDEV_NR; i++) { + for (i = 0; i < NVKM_SUBDEV_NR; i++) { if (!atomic_read(&vm->engref[i])) continue; /* unfortunate hw bug workaround... */ - if (i == NVDEV_ENGINE_GR && device->gr) { + if (i == NVKM_ENGINE_GR && device->gr) { int ret = nvkm_gr_tlb_flush(device->gr); if (ret != -ENODEV) continue; } switch (i) { - case NVDEV_ENGINE_GR : vme = 0x00; break; - case NVDEV_ENGINE_VP : - case NVDEV_ENGINE_MSPDEC: vme = 0x01; break; - case NVDEV_SUBDEV_BAR : vme = 0x06; break; - case NVDEV_ENGINE_MSPPP : - case NVDEV_ENGINE_MPEG : vme = 0x08; break; - case NVDEV_ENGINE_BSP : - case NVDEV_ENGINE_MSVLD : vme = 0x09; break; - case NVDEV_ENGINE_CIPHER: - case NVDEV_ENGINE_SEC : vme = 0x0a; break; - case NVDEV_ENGINE_CE0 : vme = 0x0d; break; + case NVKM_ENGINE_GR : vme = 0x00; break; + case NVKM_ENGINE_VP : + case NVKM_ENGINE_MSPDEC: vme = 0x01; break; + case NVKM_SUBDEV_BAR : vme = 0x06; break; + case NVKM_ENGINE_MSPPP : + case NVKM_ENGINE_MPEG : vme = 0x08; break; + case NVKM_ENGINE_BSP : + case NVKM_ENGINE_MSVLD : vme = 0x09; break; + case NVKM_ENGINE_CIPHER: + case NVKM_ENGINE_SEC : vme = 0x0a; break; + case NVKM_ENGINE_CE0 : vme = 0x0d; break; default: continue; } -- GitLab From fbd58ebda9c8572ca6285b88e3348c7712f125ec Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5561/7006] drm/nouveau/object: merge with handle Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/client.h | 23 +- .../drm/nouveau/include/nvkm/core/handle.h | 34 --- .../drm/nouveau/include/nvkm/core/object.h | 23 +- drivers/gpu/drm/nouveau/nouveau_abi16.c | 1 + drivers/gpu/drm/nouveau/nouveau_chan.c | 34 +-- drivers/gpu/drm/nouveau/nouveau_drm.c | 10 +- drivers/gpu/drm/nouveau/nvkm/core/Kbuild | 1 - drivers/gpu/drm/nouveau/nvkm/core/client.c | 59 ++--- drivers/gpu/drm/nouveau/nvkm/core/handle.c | 139 ------------ drivers/gpu/drm/nouveau/nvkm/core/ioctl.c | 99 ++++---- drivers/gpu/drm/nouveau/nvkm/core/object.c | 213 ++++++++---------- drivers/gpu/drm/nouveau/nvkm/core/oproxy.c | 18 +- .../drm/nouveau/nvkm/engine/disp/dmacnv50.c | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/gf100.c | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/gk104.c | 1 - .../gpu/drm/nouveau/nvkm/engine/fifo/nv04.c | 1 - drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c | 1 - 18 files changed, 219 insertions(+), 442 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/include/nvkm/core/handle.h delete mode 100644 drivers/gpu/drm/nouveau/nvkm/core/handle.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h index 5485bbac56772..eaf5905a87a32 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h @@ -12,8 +12,6 @@ struct nvkm_client { struct rb_root objroot; struct rb_root dmaroot; - struct nvkm_handle *root; - bool super; void *data; int (*ntfy)(const void *, u32, const void *, u32); @@ -21,9 +19,9 @@ struct nvkm_client { struct nvkm_vm *vm; }; -bool nvkm_client_insert(struct nvkm_client *, struct nvkm_handle *); -void nvkm_client_remove(struct nvkm_client *, struct nvkm_handle *); -struct nvkm_handle *nvkm_client_search(struct nvkm_client *, u64 handle); +bool nvkm_client_insert(struct nvkm_client *, struct nvkm_object *); +void nvkm_client_remove(struct nvkm_client *, struct nvkm_object *); +struct nvkm_object *nvkm_client_search(struct nvkm_client *, u64 object); int nvkm_client_new(const char *name, u64 device, const char *cfg, const char *dbg, struct nvkm_client **); @@ -31,14 +29,6 @@ void nvkm_client_del(struct nvkm_client **); int nvkm_client_init(struct nvkm_client *); int nvkm_client_fini(struct nvkm_client *, bool suspend); -static inline struct nvkm_client * -nvkm_client(struct nvkm_object *object) -{ - while (object && object->parent) - object = object->parent; - return container_of(object, struct nvkm_client, object); -} - int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *, void *data, u32 size); int nvkm_client_notify_del(struct nvkm_client *, int index); @@ -48,12 +38,15 @@ int nvkm_client_notify_put(struct nvkm_client *, int index); /* logging for client-facing objects */ #define nvif_printk(o,l,p,f,a...) do { \ struct nvkm_object *_object = (o); \ - struct nvkm_client *_client = nvkm_client(_object); \ + struct nvkm_client *_client = _object->client; \ if (_client->debug >= NV_DBG_##l) \ - printk(KERN_##p "nouveau: %s: "f, _client->name, ##a); \ + printk(KERN_##p "nouveau: %s:%08x:%08x: "f, _client->name, \ + _object->handle, _object->oclass, ##a); \ } while(0) +#define nvif_fatal(o,f,a...) nvif_printk((o), FATAL, CRIT, f, ##a) #define nvif_error(o,f,a...) nvif_printk((o), ERROR, ERR, f, ##a) #define nvif_debug(o,f,a...) nvif_printk((o), DEBUG, INFO, f, ##a) #define nvif_trace(o,f,a...) nvif_printk((o), TRACE, INFO, f, ##a) +#define nvif_info(o,f,a...) nvif_printk((o), INFO, INFO, f, ##a) #define nvif_ioctl(o,f,a...) nvif_trace((o), "ioctl: "f, ##a) #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h deleted file mode 100644 index 539278916d23b..0000000000000 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __NVKM_HANDLE_H__ -#define __NVKM_HANDLE_H__ -#include -struct nvkm_object; - -struct nvkm_handle { - struct list_head node; - - struct list_head head; - struct list_head tree; - u32 name; - u32 priv; - - u8 route; - u64 token; - - struct nvkm_handle *parent; - struct nvkm_object *object; - - struct rb_node rb; - u64 handle; -}; - -int nvkm_handle_create(struct nvkm_handle *, u32 handle, - struct nvkm_object *, struct nvkm_handle **); -void nvkm_handle_destroy(struct nvkm_handle *); -int nvkm_handle_init(struct nvkm_handle *); -int nvkm_handle_fini(struct nvkm_handle *, bool suspend); - -struct nvkm_handle *nvkm_handle_get_class(struct nvkm_object *, u16); -struct nvkm_handle *nvkm_handle_get_vinst(struct nvkm_object *, u64); -struct nvkm_handle *nvkm_handle_get_cinst(struct nvkm_object *, u32); -void nvkm_handle_put(struct nvkm_handle *); -#endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h index b4b822f6155cd..dcd048b91face 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h @@ -10,12 +10,15 @@ struct nvkm_object { const struct nvkm_object_func *func; struct nvkm_client *client; struct nvkm_engine *engine; - u32 oclass; + s32 oclass; u32 handle; - struct nvkm_object *parent; - u32 pclass; - atomic_t refcount; - atomic_t usecount; + + struct list_head head; + struct list_head tree; + u8 route; + u64 token; + u64 object; + struct rb_node node; }; struct nvkm_object_func { @@ -43,6 +46,8 @@ int nvkm_object_new_(const struct nvkm_object_func *, struct nvkm_object **); int nvkm_object_new(const struct nvkm_oclass *, void *data, u32 size, struct nvkm_object **); +void nvkm_object_del(struct nvkm_object **); +void *nvkm_object_dtor(struct nvkm_object *); int nvkm_object_init(struct nvkm_object *); int nvkm_object_fini(struct nvkm_object *, bool suspend); int nvkm_object_mthd(struct nvkm_object *, u32 mthd, void *data, u32 size); @@ -72,14 +77,12 @@ struct nvkm_oclass { struct nvkm_sclass base; const void *priv; const void *engn; - s32 handle; + u32 handle; + u8 route; + u64 token; u64 object; struct nvkm_client *client; struct nvkm_object *parent; struct nvkm_engine *engine; }; - -void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **); -int nvkm_object_inc(struct nvkm_object *); -int nvkm_object_dec(struct nvkm_object *, bool suspend); #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 6634f420ded32..40a903b79343e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -134,6 +134,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16, /* destroy channel object, all children will be killed too */ if (chan->chan) { abi16->handles &= ~(1ULL << (chan->chan->user.handle & 0xffff)); + nouveau_channel_idle(chan->chan); nouveau_channel_del(&chan->chan); } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 4a13bda1475b7..8c88c5e5bf0b2 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -43,20 +43,26 @@ module_param_named(vram_pushbuf, nouveau_vram_pushbuf, int, 0400); int nouveau_channel_idle(struct nouveau_channel *chan) { - struct nouveau_cli *cli = (void *)chan->user.client; - struct nouveau_fence *fence = NULL; - int ret; + if (likely(chan && chan->fence)) { + struct nouveau_cli *cli = (void *)chan->user.client; + struct nouveau_fence *fence = NULL; + int ret; + + ret = nouveau_fence_new(chan, false, &fence); + if (!ret) { + ret = nouveau_fence_wait(fence, false, false); + nouveau_fence_unref(&fence); + } - ret = nouveau_fence_new(chan, false, &fence); - if (!ret) { - ret = nouveau_fence_wait(fence, false, false); - nouveau_fence_unref(&fence); + if (ret) { + NV_PRINTK(err, cli, "failed to idle channel " + "0x%08x [%s]\n", + chan->user.handle, + nvxx_client(&cli->base)->name); + return ret; + } } - - if (ret) - NV_PRINTK(err, cli, "failed to idle channel 0x%08x [%s]\n", - chan->user.handle, nvxx_client(&cli->base)->name); - return ret; + return 0; } void @@ -64,10 +70,8 @@ nouveau_channel_del(struct nouveau_channel **pchan) { struct nouveau_channel *chan = *pchan; if (chan) { - if (chan->fence) { - nouveau_channel_idle(chan); + if (chan->fence) nouveau_fence(chan->drm)->context_del(chan); - } nvif_object_fini(&chan->nvsw); nvif_object_fini(&chan->gart); nvif_object_fini(&chan->vram); diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index d04d08cc546dd..14a13486c27fe 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -139,13 +139,17 @@ nouveau_cli_destroy(struct nouveau_cli *cli) static void nouveau_accel_fini(struct nouveau_drm *drm) { - nvif_notify_fini(&drm->flip); - nouveau_channel_del(&drm->channel); + nouveau_channel_idle(drm->channel); nvif_object_fini(&drm->ntfy); nvkm_gpuobj_del(&drm->notify); + nvif_notify_fini(&drm->flip); nvif_object_fini(&drm->nvsw); - nouveau_channel_del(&drm->cechan); + nouveau_channel_del(&drm->channel); + + nouveau_channel_idle(drm->cechan); nvif_object_fini(&drm->ttm.copy); + nouveau_channel_del(&drm->cechan); + if (drm->fence) nouveau_fence(drm)->dtor(drm); } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild index 09044cf0d9ff3..7f66963f305ce 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild @@ -3,7 +3,6 @@ nvkm-y += nvkm/core/engine.o nvkm-y += nvkm/core/enum.o nvkm-y += nvkm/core/event.o nvkm-y += nvkm/core/gpuobj.o -nvkm-y += nvkm/core/handle.o nvkm-y += nvkm/core/ioctl.o nvkm-y += nvkm/core/memory.o nvkm-y += nvkm/core/mm.o diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c index ab98f8c45950f..297e1e953fa6c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/client.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c @@ -23,7 +23,6 @@ */ #include #include -#include #include #include @@ -91,7 +90,7 @@ int nvkm_client_notify_new(struct nvkm_object *object, struct nvkm_event *event, void *data, u32 size) { - struct nvkm_client *client = nvkm_client(object); + struct nvkm_client *client = object->client; struct nvkm_client_notify *notify; union { struct nvif_notify_req_v0 v0; @@ -207,47 +206,47 @@ nvkm_client_object_func = { }; void -nvkm_client_remove(struct nvkm_client *client, struct nvkm_handle *object) +nvkm_client_remove(struct nvkm_client *client, struct nvkm_object *object) { - if (!RB_EMPTY_NODE(&object->rb)) - rb_erase(&object->rb, &client->objroot); + if (!RB_EMPTY_NODE(&object->node)) + rb_erase(&object->node, &client->objroot); } bool -nvkm_client_insert(struct nvkm_client *client, struct nvkm_handle *object) +nvkm_client_insert(struct nvkm_client *client, struct nvkm_object *object) { struct rb_node **ptr = &client->objroot.rb_node; struct rb_node *parent = NULL; while (*ptr) { - struct nvkm_handle *this = - container_of(*ptr, typeof(*this), rb); + struct nvkm_object *this = + container_of(*ptr, typeof(*this), node); parent = *ptr; - if (object->handle < this->handle) + if (object->object < this->object) ptr = &parent->rb_left; else - if (object->handle > this->handle) + if (object->object > this->object) ptr = &parent->rb_right; else return false; } - rb_link_node(&object->rb, parent, ptr); - rb_insert_color(&object->rb, &client->objroot); + rb_link_node(&object->node, parent, ptr); + rb_insert_color(&object->node, &client->objroot); return true; } -struct nvkm_handle * +struct nvkm_object * nvkm_client_search(struct nvkm_client *client, u64 handle) { struct rb_node *node = client->objroot.rb_node; while (node) { - struct nvkm_handle *object = - container_of(node, typeof(*object), rb); - if (handle < object->handle) + struct nvkm_object *object = + container_of(node, typeof(*object), node); + if (handle < object->object) node = node->rb_left; else - if (handle > object->handle) + if (handle > object->object) node = node->rb_right; else return object; @@ -260,26 +259,17 @@ nvkm_client_fini(struct nvkm_client *client, bool suspend) { struct nvkm_object *object = &client->object; const char *name[2] = { "fini", "suspend" }; - int ret, i; - nvif_trace(object, "%s running\n", name[suspend]); - nvif_trace(object, "%s notify\n", name[suspend]); + int i; + nvif_debug(object, "%s notify\n", name[suspend]); for (i = 0; i < ARRAY_SIZE(client->notify); i++) nvkm_client_notify_put(client, i); - nvif_trace(object, "%s object\n", name[suspend]); - ret = nvkm_handle_fini(client->root, suspend); - nvif_trace(object, "%s completed with %d\n", name[suspend], ret); - return ret; + return nvkm_object_fini(&client->object, suspend); } int nvkm_client_init(struct nvkm_client *client) { - struct nvkm_object *object = &client->object; - int ret; - nvif_trace(object, "init running\n"); - ret = nvkm_handle_init(client->root); - nvif_trace(object, "init completed with %d\n", ret); - return ret; + return nvkm_object_init(&client->object); } void @@ -291,7 +281,7 @@ nvkm_client_del(struct nvkm_client **pclient) nvkm_client_fini(client, false); for (i = 0; i < ARRAY_SIZE(client->notify); i++) nvkm_client_notify_del(client, i); - nvkm_handle_destroy(client->root); + nvkm_object_dtor(&client->object); kfree(*pclient); *pclient = NULL; } @@ -303,7 +293,6 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, { struct nvkm_oclass oclass = {}; struct nvkm_client *client; - int ret; if (!(client = *pclient = kzalloc(sizeof(*client), GFP_KERNEL))) return -ENOMEM; @@ -315,9 +304,5 @@ nvkm_client_new(const char *name, u64 device, const char *cfg, client->debug = nvkm_dbgopt(dbg, "CLIENT"); client->objroot = RB_ROOT; client->dmaroot = RB_ROOT; - - ret = nvkm_handle_create(NULL, ~0, &client->object, &client->root); - if (ret) - nvkm_client_del(pclient); - return ret; + return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c deleted file mode 100644 index d185cae0fbba3..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/core/handle.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include -#include - -#define hprintk(h,l,f,a...) do { \ - struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \ - nvif_printk((h)->object, l, INFO, "0x%08x:0x%08x "f, n, (h)->name, ##a);\ -} while(0) - -int -nvkm_handle_init(struct nvkm_handle *handle) -{ - struct nvkm_handle *item; - int ret; - - hprintk(handle, TRACE, "init running\n"); - ret = nvkm_object_inc(handle->object); - if (ret) - return ret; - - hprintk(handle, TRACE, "init children\n"); - list_for_each_entry(item, &handle->tree, head) { - ret = nvkm_handle_init(item); - if (ret) - goto fail; - } - - hprintk(handle, TRACE, "init completed\n"); - return 0; -fail: - hprintk(handle, ERROR, "init failed with %d\n", ret); - list_for_each_entry_continue_reverse(item, &handle->tree, head) { - nvkm_handle_fini(item, false); - } - - nvkm_object_dec(handle->object, false); - return ret; -} - -int -nvkm_handle_fini(struct nvkm_handle *handle, bool suspend) -{ - static char *name[2] = { "fini", "suspend" }; - struct nvkm_handle *item; - int ret; - - hprintk(handle, TRACE, "%s children\n", name[suspend]); - list_for_each_entry(item, &handle->tree, head) { - ret = nvkm_handle_fini(item, suspend); - if (ret && suspend) - goto fail; - } - - hprintk(handle, TRACE, "%s running\n", name[suspend]); - if (handle->object) { - ret = nvkm_object_dec(handle->object, suspend); - if (ret && suspend) - goto fail; - } - - hprintk(handle, TRACE, "%s completed\n", name[suspend]); - return 0; -fail: - hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret); - list_for_each_entry_continue_reverse(item, &handle->tree, head) { - int rret = nvkm_handle_init(item); - if (rret) - hprintk(handle, FATAL, "failed to restart, %d\n", rret); - } - - return ret; -} - -int -nvkm_handle_create(struct nvkm_handle *parent, u32 _handle, - struct nvkm_object *object, struct nvkm_handle **phandle) -{ - struct nvkm_handle *handle; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) - return -ENOMEM; - - INIT_LIST_HEAD(&handle->head); - INIT_LIST_HEAD(&handle->tree); - handle->name = _handle; - handle->priv = ~0; - RB_CLEAR_NODE(&handle->rb); - handle->parent = parent; - nvkm_object_ref(object, &handle->object); - - if (parent) - list_add(&handle->head, &handle->parent->tree); - - hprintk(handle, TRACE, "created\n"); - *phandle = handle; - return 0; -} - -void -nvkm_handle_destroy(struct nvkm_handle *handle) -{ - struct nvkm_client *client = nvkm_client(handle->object); - struct nvkm_handle *item, *temp; - - hprintk(handle, TRACE, "destroy running\n"); - list_for_each_entry_safe(item, temp, &handle->tree, head) { - nvkm_handle_destroy(item); - } - - nvkm_client_remove(client, handle); - list_del(&handle->head); - - hprintk(handle, TRACE, "destroy completed\n"); - nvkm_object_ref(NULL, &handle->object); - kfree(handle); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c index d9bb0394d83ff..d87d6ab03cc7f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c @@ -24,15 +24,13 @@ #include #include #include -#include #include #include static int -nvkm_ioctl_nop(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_nop(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_nop_v0 v0; } *args = data; @@ -48,9 +46,8 @@ nvkm_ioctl_nop(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_sclass(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_sclass_v0 v0; } *args = data; @@ -81,13 +78,12 @@ nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_new(struct nvkm_object *parent, void *data, u32 size) { union { struct nvif_ioctl_new_v0 v0; } *args = data; - struct nvkm_client *client = handle->object->client; - struct nvkm_object *parent = handle->object; + struct nvkm_client *client = parent->client; struct nvkm_object *object = NULL; struct nvkm_oclass oclass; int ret, i = 0; @@ -124,38 +120,30 @@ nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size) } ret = oclass.ctor(&oclass, data, size, &object); - if (ret) - goto fail_object; - - ret = nvkm_object_inc(object); - if (ret) - goto fail_object; - - ret = nvkm_handle_create(handle, args->v0.handle, object, &handle); - if (ret) - goto fail_handle; - - ret = nvkm_handle_init(handle); - handle->route = args->v0.route; - handle->token = args->v0.token; - if (ret) - nvkm_handle_destroy(handle); - - handle->handle = args->v0.object; - nvkm_client_insert(client, handle); - client->data = object; -fail_handle: - nvkm_object_dec(object, false); -fail_object: - nvkm_object_ref(NULL, &object); nvkm_engine_unref(&oclass.engine); + if (ret == 0) { + ret = nvkm_object_init(object); + if (ret == 0) { + list_add(&object->head, &parent->tree); + object->route = args->v0.route; + object->token = args->v0.token; + object->object = args->v0.object; + if (nvkm_client_insert(client, object)) { + client->data = object; + return 0; + } + ret = -EEXIST; + } + nvkm_object_fini(object, false); + } + + nvkm_object_del(&object); return ret; } static int -nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_del(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_del none; } *args = data; @@ -164,17 +152,16 @@ nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size) nvif_ioctl(object, "delete size %d\n", size); if (nvif_unvers(args->none)) { nvif_ioctl(object, "delete\n"); - nvkm_handle_fini(handle, false); - nvkm_handle_destroy(handle); + nvkm_object_fini(object, false); + nvkm_object_del(&object); } return ret; } static int -nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_mthd(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_mthd_v0 v0; } *args = data; @@ -192,9 +179,8 @@ nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size) static int -nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_rd(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_rd_v0 v0; } *args = data; @@ -232,9 +218,8 @@ nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_wr(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_wr_v0 v0; } *args = data; @@ -261,9 +246,8 @@ nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_map(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_map_v0 v0; } *args = data; @@ -280,9 +264,8 @@ nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_unmap(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_unmap(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_unmap none; } *args = data; @@ -297,9 +280,8 @@ nvkm_ioctl_unmap(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_ntfy_new(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_object *object = handle->object; union { struct nvif_ioctl_ntfy_new_v0 v0; } *args = data; @@ -324,10 +306,9 @@ nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_ntfy_del(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_ntfy_del(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_client *client = nvkm_client(handle->object); - struct nvkm_object *object = handle->object; + struct nvkm_client *client = object->client; union { struct nvif_ioctl_ntfy_del_v0 v0; } *args = data; @@ -344,10 +325,9 @@ nvkm_ioctl_ntfy_del(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_ntfy_get(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_ntfy_get(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_client *client = nvkm_client(handle->object); - struct nvkm_object *object = handle->object; + struct nvkm_client *client = object->client; union { struct nvif_ioctl_ntfy_get_v0 v0; } *args = data; @@ -364,10 +344,9 @@ nvkm_ioctl_ntfy_get(struct nvkm_handle *handle, void *data, u32 size) } static int -nvkm_ioctl_ntfy_put(struct nvkm_handle *handle, void *data, u32 size) +nvkm_ioctl_ntfy_put(struct nvkm_object *object, void *data, u32 size) { - struct nvkm_client *client = nvkm_client(handle->object); - struct nvkm_object *object = handle->object; + struct nvkm_client *client = object->client; union { struct nvif_ioctl_ntfy_put_v0 v0; } *args = data; @@ -385,7 +364,7 @@ nvkm_ioctl_ntfy_put(struct nvkm_handle *handle, void *data, u32 size) static struct { int version; - int (*func)(struct nvkm_handle *, void *, u32); + int (*func)(struct nvkm_object *, void *, u32); } nvkm_ioctl_v0[] = { { 0x00, nvkm_ioctl_nop }, @@ -407,13 +386,13 @@ static int nvkm_ioctl_path(struct nvkm_client *client, u64 handle, u32 type, void *data, u32 size, u8 owner, u8 *route, u64 *token) { - struct nvkm_handle *object; + struct nvkm_object *object; int ret; if (handle) object = nvkm_client_search(client, handle); else - object = client->root; + object = &client->object; if (unlikely(!object)) { nvif_ioctl(&client->object, "object not found\n"); return -ENOENT; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c index 8976526b1c8fc..67aa7223dcd78 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/object.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include +#include #include int @@ -109,28 +110,112 @@ nvkm_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *gpuobj, int nvkm_object_fini(struct nvkm_object *object, bool suspend) { - if (object->func->fini) - return object->func->fini(object, suspend); + const char *action = suspend ? "suspend" : "fini"; + struct nvkm_object *child; + s64 time; + int ret; + + nvif_debug(object, "%s children...\n", action); + time = ktime_to_us(ktime_get()); + list_for_each_entry(child, &object->tree, head) { + ret = nvkm_object_fini(child, suspend); + if (ret && suspend) + goto fail_child; + } + + nvif_debug(object, "%s running...\n", action); + if (object->func->fini) { + ret = object->func->fini(object, suspend); + if (ret) { + nvif_error(object, "%s failed with %d\n", action, ret); + if (suspend) + goto fail; + } + } + + time = ktime_to_us(ktime_get()) - time; + nvif_debug(object, "%s completed in %lldus\n", action, time); return 0; + +fail: + if (object->func->init) { + int rret = object->func->init(object); + if (rret) + nvif_fatal(object, "failed to restart, %d\n", rret); + } +fail_child: + list_for_each_entry_continue_reverse(child, &object->tree, head) { + nvkm_object_init(child); + } + return ret; } int nvkm_object_init(struct nvkm_object *object) { - if (object->func->init) - return object->func->init(object); + struct nvkm_object *child; + s64 time; + int ret; + + nvif_debug(object, "init running...\n"); + time = ktime_to_us(ktime_get()); + if (object->func->init) { + ret = object->func->init(object); + if (ret) + goto fail; + } + + nvif_debug(object, "init children...\n"); + list_for_each_entry(child, &object->tree, head) { + ret = nvkm_object_init(child); + if (ret) + goto fail_child; + } + + time = ktime_to_us(ktime_get()) - time; + nvif_debug(object, "init completed in %lldus\n", time); return 0; + +fail_child: + list_for_each_entry_continue_reverse(child, &object->tree, head) + nvkm_object_fini(child, false); +fail: + nvif_error(object, "init failed with %d\n", ret); + if (object->func->fini) + object->func->fini(object, false); + return ret; } -static void +void * +nvkm_object_dtor(struct nvkm_object *object) +{ + struct nvkm_object *child, *ctemp; + void *data = object; + s64 time; + + nvif_debug(object, "destroy children...\n"); + time = ktime_to_us(ktime_get()); + list_for_each_entry_safe(child, ctemp, &object->tree, head) { + nvkm_object_del(&child); + } + + nvif_debug(object, "destroy running...\n"); + if (object->func->dtor) + data = object->func->dtor(object); + nvkm_engine_unref(&object->engine); + time = ktime_to_us(ktime_get()) - time; + nvif_debug(object, "destroy completed in %lldus...\n", time); + return data; +} + +void nvkm_object_del(struct nvkm_object **pobject) { struct nvkm_object *object = *pobject; - if (object && !WARN_ON(!object->func)) { - if (object->func->dtor) - *pobject = object->func->dtor(object); - nvkm_engine_unref(&object->engine); + *pobject = nvkm_object_dtor(object); + nvkm_client_remove(object->client, object); + list_del(&object->head); kfree(*pobject); *pobject = NULL; } @@ -145,9 +230,10 @@ nvkm_object_ctor(const struct nvkm_object_func *func, object->engine = nvkm_engine_ref(oclass->engine); object->oclass = oclass->base.oclass; object->handle = oclass->handle; - object->parent = oclass->parent; - atomic_set(&object->refcount, 1); - atomic_set(&object->usecount, 0); + INIT_LIST_HEAD(&object->head); + INIT_LIST_HEAD(&object->tree); + RB_CLEAR_NODE(&object->node); + WARN_ON(oclass->engine && !object->engine); } int @@ -176,106 +262,3 @@ nvkm_object_new(const struct nvkm_oclass *oclass, void *data, u32 size, oclass->base.func ? oclass->base.func : &nvkm_object_func; return nvkm_object_new_(func, oclass, data, size, pobject); } - -void -nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref) -{ - if (obj) { - atomic_inc(&obj->refcount); - } - - if (*ref) { - int dead = atomic_dec_and_test(&(*ref)->refcount); - if (dead) - nvkm_object_del(ref); - } - - *ref = obj; -} - -int -nvkm_object_inc(struct nvkm_object *object) -{ - int ref = atomic_add_return(1, &object->usecount); - int ret; - - if (ref != 1) - return 0; - - if (object->parent) { - ret = nvkm_object_inc(object->parent); - if (ret) - goto fail_parent; - } - - ret = nvkm_object_init(object); - atomic_set(&object->usecount, 1); - if (ret) - goto fail_self; - - return 0; - -fail_self: - if (object->parent) - nvkm_object_dec(object->parent, false); -fail_parent: - atomic_dec(&object->usecount); - return ret; -} - -static int -nvkm_object_decf(struct nvkm_object *object) -{ - nvkm_object_fini(object, false); - atomic_set(&object->usecount, 0); - - if (object->parent) - nvkm_object_dec(object->parent, false); - - return 0; -} - -static int -nvkm_object_decs(struct nvkm_object *object) -{ - int ret; - - ret = nvkm_object_fini(object, true); - atomic_set(&object->usecount, 0); - if (ret) - return ret; - - if (object->parent) { - ret = nvkm_object_dec(object->parent, true); - if (ret) - goto fail_parent; - } - - return 0; - -fail_parent: - nvkm_object_init(object); - - return ret; -} - -int -nvkm_object_dec(struct nvkm_object *object, bool suspend) -{ - int ref = atomic_add_return(-1, &object->usecount); - int ret; - - if (ref == 0) { - if (suspend) - ret = nvkm_object_decs(object); - else - ret = nvkm_object_decf(object); - - if (ret) { - atomic_inc(&object->usecount); - return ret; - } - } - - return 0; -} diff --git a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c index f32aa0dc425bb..e31a0479add0d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/oproxy.c @@ -109,9 +109,11 @@ nvkm_oproxy_fini(struct nvkm_object *object, bool suspend) return ret; } - ret = nvkm_object_fini(oproxy->object, suspend); - if (ret && suspend) - return ret; + if (oproxy->object->func->fini) { + ret = oproxy->object->func->fini(oproxy->object, suspend); + if (ret && suspend) + return ret; + } if (oproxy->func->fini[1]) { ret = oproxy->func->fini[1](oproxy, suspend); @@ -134,9 +136,11 @@ nvkm_oproxy_init(struct nvkm_object *object) return ret; } - ret = nvkm_object_init(oproxy->object); - if (ret) - return ret; + if (oproxy->object->func->init) { + ret = oproxy->object->func->init(oproxy->object); + if (ret) + return ret; + } if (oproxy->func->init[1]) { ret = oproxy->func->init[1](oproxy); @@ -153,7 +157,7 @@ nvkm_oproxy_dtor(struct nvkm_object *object) struct nvkm_oproxy *oproxy = nvkm_oproxy(object); if (oproxy->func->dtor[0]) oproxy->func->dtor[0](oproxy); - nvkm_object_ref(NULL, &oproxy->object); + nvkm_object_del(&oproxy->object); if (oproxy->func->dtor[1]) oproxy->func->dtor[1](oproxy); return oproxy; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c index b05c04a209bea..9c6645a357b93 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dmacnv50.c @@ -25,7 +25,6 @@ #include "rootnv50.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index a56e56eed57bb..9921482fc1624 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -116,7 +116,7 @@ nvkm_fifo_chan_child_del(struct nvkm_oproxy *base) if (!--engn->refcount) { if (chan->func->engine_dtor) chan->func->engine_dtor(chan, engine); - nvkm_object_ref(NULL, &engn->object); + nvkm_object_del(&engn->object); if (chan->vm) atomic_dec(&chan->vm->engref[engine->subdev.index]); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c index 172f243011137..ff6fcbda615b0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c index fc0ff2d37d069..98970a0b7a668 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c @@ -27,7 +27,6 @@ #include #include #include -#include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c index e6f04e87139a2..ad707ff176cc7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c @@ -26,7 +26,6 @@ #include "regsnv04.h" #include -#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c index ef36ba18bff83..a381196af69de 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c @@ -24,7 +24,6 @@ #include "nv50.h" #include -#include #include #include #include -- GitLab From 0a34fb3149c3001f9c1b2bd0f98f94d63e74cb85 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5562/7006] drm/nouveau/pci: new subdev Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 3 + .../gpu/drm/nouveau/include/nvkm/subdev/pci.h | 21 +++ drivers/gpu/drm/nouveau/nvkm/core/subdev.c | 1 + .../gpu/drm/nouveau/nvkm/engine/device/base.c | 124 ++++++++++++++---- .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild | 1 + .../drm/nouveau/nvkm/subdev/bios/shadowrom.c | 17 +-- .../gpu/drm/nouveau/nvkm/subdev/pci/Kbuild | 6 + .../gpu/drm/nouveau/nvkm/subdev/pci/base.c | 82 ++++++++++++ .../gpu/drm/nouveau/nvkm/subdev/pci/gf100.c | 44 +++++++ .../gpu/drm/nouveau/nvkm/subdev/pci/nv04.c | 58 ++++++++ .../gpu/drm/nouveau/nvkm/subdev/pci/nv40.c | 65 +++++++++ .../gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c | 37 ++++++ .../gpu/drm/nouveau/nvkm/subdev/pci/nv50.c | 51 +++++++ .../gpu/drm/nouveau/nvkm/subdev/pci/priv.h | 19 +++ 15 files changed, 491 insertions(+), 39 deletions(-) create mode 100644 drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv50.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 8ef8058ed0313..bc151c64bbad2 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -4,6 +4,7 @@ #include enum nvkm_devidx { + NVKM_SUBDEV_PCI, NVKM_SUBDEV_VBIOS, NVKM_SUBDEV_DEVINIT, NVKM_SUBDEV_IBUS, @@ -108,6 +109,7 @@ struct nvkm_device { struct nvkm_mc *mc; struct nvkm_mmu *mmu; struct nvkm_subdev *mxm; + struct nvkm_pci *pci; struct nvkm_pmu *pmu; struct nvkm_therm *therm; struct nvkm_timer *timer; @@ -168,6 +170,7 @@ struct nvkm_device_chip { int (*mc )(struct nvkm_device *, int idx, struct nvkm_mc **); int (*mmu )(struct nvkm_device *, int idx, struct nvkm_mmu **); int (*mxm )(struct nvkm_device *, int idx, struct nvkm_subdev **); + int (*pci )(struct nvkm_device *, int idx, struct nvkm_pci **); int (*pmu )(struct nvkm_device *, int idx, struct nvkm_pmu **); int (*therm )(struct nvkm_device *, int idx, struct nvkm_therm **); int (*timer )(struct nvkm_device *, int idx, struct nvkm_timer **); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h new file mode 100644 index 0000000000000..ea4b0cce6159a --- /dev/null +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h @@ -0,0 +1,21 @@ +#ifndef __NVKM_PCI_H__ +#define __NVKM_PCI_H__ +#include + +struct nvkm_pci { + const struct nvkm_pci_func *func; + struct nvkm_subdev subdev; +}; + +u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); +void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); +void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); +void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); +void nvkm_pci_msi_rearm(struct nvkm_pci *); + +int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int nv40_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int nv4c_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int nv50_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +int gf100_pci_new(struct nvkm_device *, int, struct nvkm_pci **); +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c index 65e0cb35e1a0e..7de98470a2a06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c @@ -44,6 +44,7 @@ nvkm_subdev_name[NVKM_SUBDEV_NR] = { [NVKM_SUBDEV_MC ] = "mc", [NVKM_SUBDEV_MMU ] = "mmu", [NVKM_SUBDEV_MXM ] = "mxm", + [NVKM_SUBDEV_PCI ] = "pci", [NVKM_SUBDEV_PMU ] = "pmu", [NVKM_SUBDEV_THERM ] = "therm", [NVKM_SUBDEV_TIMER ] = "tmr", diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b67cb37719481..743a3e9796dd7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -85,6 +85,7 @@ nv4_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -105,6 +106,7 @@ nv5_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -126,6 +128,7 @@ nv10_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -145,6 +148,7 @@ nv11_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -166,6 +170,7 @@ nv15_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -187,6 +192,7 @@ nv17_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -208,6 +214,7 @@ nv18_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -229,6 +236,7 @@ nv1a_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -250,6 +258,7 @@ nv1f_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -271,6 +280,7 @@ nv20_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -292,6 +302,7 @@ nv25_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -313,6 +324,7 @@ nv28_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -334,6 +346,7 @@ nv2a_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -355,6 +368,7 @@ nv30_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -376,6 +390,7 @@ nv31_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -398,6 +413,7 @@ nv34_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -420,6 +436,7 @@ nv35_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -441,6 +458,7 @@ nv36_chipset = { .imem = nv04_instmem_new, .mc = nv04_mc_new, .mmu = nv04_mmu_new, + .pci = nv04_pci_new, .timer = nv04_timer_new, .disp = nv04_disp_new, .dma = nv04_dma_new, @@ -463,6 +481,7 @@ nv40_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv04_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv40_timer_new, .volt = nv40_volt_new, @@ -488,6 +507,7 @@ nv41_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -513,6 +533,7 @@ nv42_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -538,6 +559,7 @@ nv43_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -563,6 +585,7 @@ nv44_chipset = { .imem = nv40_instmem_new, .mc = nv44_mc_new, .mmu = nv44_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -588,6 +611,7 @@ nv45_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv04_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -613,6 +637,7 @@ nv46_chipset = { .imem = nv40_instmem_new, .mc = nv44_mc_new, .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -638,6 +663,7 @@ nv47_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -663,6 +689,7 @@ nv49_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -688,6 +715,7 @@ nv4a_chipset = { .imem = nv40_instmem_new, .mc = nv44_mc_new, .mmu = nv44_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -713,6 +741,7 @@ nv4b_chipset = { .imem = nv40_instmem_new, .mc = nv40_mc_new, .mmu = nv41_mmu_new, + .pci = nv40_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -738,6 +767,7 @@ nv4c_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -763,6 +793,7 @@ nv4e_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -791,6 +822,7 @@ nv50_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv50_pci_new, .therm = nv50_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -816,6 +848,7 @@ nv63_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -841,6 +874,7 @@ nv67_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -866,6 +900,7 @@ nv68_chipset = { .imem = nv40_instmem_new, .mc = nv4c_mc_new, .mmu = nv44_mmu_new, + .pci = nv4c_pci_new, .therm = nv40_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -894,6 +929,7 @@ nv84_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv50_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -925,6 +961,7 @@ nv86_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv50_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -956,6 +993,7 @@ nv92_chipset = { .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv50_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -987,6 +1025,7 @@ nv94_chipset = { .mc = g94_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1005,63 +1044,65 @@ nv94_chipset = { static const struct nvkm_device_chip nv96_chipset = { .name = "G96", + .bar = g84_bar_new, .bios = nvkm_bios_new, - .gpio = g94_gpio_new, - .i2c = g94_i2c_new, - .fuse = nv50_fuse_new, + .bus = g94_bus_new, .clk = g84_clk_new, - .therm = g84_therm_new, - .mxm = nv50_mxm_new, .devinit = g84_devinit_new, - .mc = g94_mc_new, - .bus = g94_bus_new, - .timer = nv41_timer_new, .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, .imem = nv50_instmem_new, + .mc = g94_mc_new, .mmu = nv50_mmu_new, - .bar = g84_bar_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, .volt = nv40_volt_new, + .bsp = g84_bsp_new, + .cipher = g84_cipher_new, + .disp = g94_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = g84_gr_new, - .gr = nv50_gr_new, .mpeg = g84_mpeg_new, - .vp = g84_vp_new, - .cipher = g84_cipher_new, - .bsp = g84_bsp_new, - .disp = g94_disp_new, .pm = g84_pm_new, + .sw = nv50_sw_new, + .vp = g84_vp_new, }; static const struct nvkm_device_chip nv98_chipset = { .name = "G98", + .bar = g84_bar_new, .bios = nvkm_bios_new, - .gpio = g94_gpio_new, - .i2c = g94_i2c_new, - .fuse = nv50_fuse_new, + .bus = g94_bus_new, .clk = g84_clk_new, - .therm = g84_therm_new, - .mxm = nv50_mxm_new, .devinit = g98_devinit_new, - .mc = g98_mc_new, - .bus = g94_bus_new, - .timer = nv41_timer_new, .fb = g84_fb_new, + .fuse = nv50_fuse_new, + .gpio = g94_gpio_new, + .i2c = g94_i2c_new, .imem = nv50_instmem_new, + .mc = g98_mc_new, .mmu = nv50_mmu_new, - .bar = g84_bar_new, + .mxm = nv50_mxm_new, + .pci = nv40_pci_new, + .therm = g84_therm_new, + .timer = nv41_timer_new, .volt = nv40_volt_new, + .disp = g94_disp_new, .dma = nv50_dma_new, .fifo = g84_fifo_new, .gr = g84_gr_new, - .sw = nv50_sw_new, .mspdec = g98_mspdec_new, - .sec = g98_sec_new, - .msvld = g98_msvld_new, .msppp = g98_msppp_new, - .disp = g94_disp_new, + .msvld = g98_msvld_new, .pm = g84_pm_new, + .sec = g98_sec_new, + .sw = nv50_sw_new, }; static const struct nvkm_device_chip @@ -1080,6 +1121,7 @@ nva0_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1111,6 +1153,7 @@ nva3_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1144,6 +1187,7 @@ nva5_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1176,6 +1220,7 @@ nva8_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1208,6 +1253,7 @@ nvaa_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1239,6 +1285,7 @@ nvac_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .therm = g84_therm_new, .timer = nv41_timer_new, .volt = nv40_volt_new, @@ -1270,6 +1317,7 @@ nvaf_chipset = { .mc = g98_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gt215_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1304,6 +1352,7 @@ nvc0_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = gf100_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1339,6 +1388,7 @@ nvc1_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1373,6 +1423,7 @@ nvc3_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1407,6 +1458,7 @@ nvc4_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = gf100_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1442,6 +1494,7 @@ nvc8_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = gf100_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1477,6 +1530,7 @@ nvce_chipset = { .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = gf100_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1512,6 +1566,7 @@ nvcf_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gf100_pmu_new, .therm = gt215_therm_new, .timer = nv41_timer_new, @@ -1546,6 +1601,7 @@ nvd7_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .therm = gf119_therm_new, .timer = nv41_timer_new, .ce[0] = gf100_ce_new, @@ -1578,6 +1634,7 @@ nvd9_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gf119_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1612,6 +1669,7 @@ nve4_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1648,6 +1706,7 @@ nve6_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gk104_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1684,6 +1743,7 @@ nve7_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gf119_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1744,6 +1804,7 @@ nvf0_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gk110_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1779,6 +1840,7 @@ nvf1_chipset = { .mc = gf106_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gk110_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1814,6 +1876,7 @@ nv106_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gk208_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1849,6 +1912,7 @@ nv108_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gk208_pmu_new, .therm = gf119_therm_new, .timer = nv41_timer_new, @@ -1884,6 +1948,7 @@ nv117_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gm107_pmu_new, .therm = gm107_therm_new, .timer = gk20a_timer_new, @@ -1913,6 +1978,7 @@ nv124_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, .ce[0] = gm204_ce_new, @@ -1942,6 +2008,7 @@ nv126_chipset = { .mc = gk20a_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, + .pci = nv40_pci_new, .pmu = gm107_pmu_new, .timer = gk20a_timer_new, .ce[0] = gm204_ce_new, @@ -1966,7 +2033,6 @@ nv12b_chipset = { .ltc = gm107_ltc_new, .mc = gk20a_mc_new, .mmu = gf100_mmu_new, - .mmu = gf100_mmu_new, .timer = gk20a_timer_new, .ce[2] = gm204_ce_new, .dma = gf119_dma_new, @@ -2018,6 +2084,7 @@ nvkm_device_subdev(struct nvkm_device *device, int index) _(MC , device->mc , &device->mc->subdev); _(MMU , device->mmu , &device->mmu->subdev); _(MXM , device->mxm , device->mxm); + _(PCI , device->pci , &device->pci->subdev); _(PMU , device->pmu , &device->pmu->subdev); _(THERM , device->therm , &device->therm->subdev); _(TIMER , device->timer , &device->timer->subdev); @@ -2504,6 +2571,7 @@ nvkm_device_ctor(const struct nvkm_device_func *func, _(NVKM_SUBDEV_MC , mc); _(NVKM_SUBDEV_MMU , mmu); _(NVKM_SUBDEV_MXM , mxm); + _(NVKM_SUBDEV_PCI , pci); _(NVKM_SUBDEV_PMU , pmu); _(NVKM_SUBDEV_THERM , therm); _(NVKM_SUBDEV_TIMER , timer); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index adebf52578c10..6dea6e8fc8547 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild index a1bb3e48739c5..ee2c38f50ef5d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild @@ -13,6 +13,7 @@ include $(src)/nvkm/subdev/ltc/Kbuild include $(src)/nvkm/subdev/mc/Kbuild include $(src)/nvkm/subdev/mmu/Kbuild include $(src)/nvkm/subdev/mxm/Kbuild +include $(src)/nvkm/subdev/pci/Kbuild include $(src)/nvkm/subdev/pmu/Kbuild include $(src)/nvkm/subdev/therm/Kbuild include $(src)/nvkm/subdev/timer/Kbuild diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c index be116f35c4bc5..ffa4b395220aa 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c @@ -22,6 +22,8 @@ */ #include "priv.h" +#include + static u32 prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) { @@ -39,23 +41,16 @@ static void prom_fini(void *data) { struct nvkm_device *device = data; - if (device->card_type < NV_50) - nvkm_mask(device, 0x001850, 0x00000001, 0x00000001); - else - nvkm_mask(device, 0x088050, 0x00000001, 0x00000001); + nvkm_pci_rom_shadow(device->pci, true); } static void * prom_init(struct nvkm_bios *bios, const char *name) { struct nvkm_device *device = bios->subdev.device; - if (device->card_type < NV_50) { - if (device->card_type == NV_40 && device->chipset >= 0x4c) - return ERR_PTR(-ENODEV); - nvkm_mask(device, 0x001850, 0x00000001, 0x00000000); - } else { - nvkm_mask(device, 0x088050, 0x00000001, 0x00000000); - } + if (device->card_type == NV_40 && device->chipset >= 0x4c) + return ERR_PTR(-ENODEV); + nvkm_pci_rom_shadow(device->pci, false); return device; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild new file mode 100644 index 0000000000000..a8e9b0fc447ea --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -0,0 +1,6 @@ +nvkm-y += nvkm/subdev/pci/base.o +nvkm-y += nvkm/subdev/pci/nv04.o +nvkm-y += nvkm/subdev/pci/nv40.o +nvkm-y += nvkm/subdev/pci/nv4c.o +nvkm-y += nvkm/subdev/pci/nv50.o +nvkm-y += nvkm/subdev/pci/gf100.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c new file mode 100644 index 0000000000000..6a742659a9019 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -0,0 +1,82 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +u32 +nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr) +{ + return pci->func->rd32(pci, addr); +} + +void +nvkm_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) +{ + pci->func->wr08(pci, addr, data); +} + +void +nvkm_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) +{ + pci->func->wr32(pci, addr, data); +} + +void +nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) +{ + u32 data = nvkm_pci_rd32(pci, 0x0050); + if (shadow) + data |= 0x00000001; + else + data &= ~0x00000001; + nvkm_pci_wr32(pci, 0x0050, data); +} + +void +nvkm_pci_msi_rearm(struct nvkm_pci *pci) +{ + pci->func->msi_rearm(pci); +} + +static void * +nvkm_pci_dtor(struct nvkm_subdev *subdev) +{ + return nvkm_pci(subdev); +} + +static const struct nvkm_subdev_func +nvkm_pci_func = { + .dtor = nvkm_pci_dtor, +}; + +int +nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, + int index, struct nvkm_pci **ppci) +{ + struct nvkm_pci *pci; + if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL))) + return -ENOMEM; + nvkm_subdev_ctor(&nvkm_pci_func, device, index, 0, &pci->subdev); + pci->func = func; + return 0; +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c new file mode 100644 index 0000000000000..86f8226532d3a --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/gf100.c @@ -0,0 +1,44 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +static void +gf100_pci_msi_rearm(struct nvkm_pci *pci) +{ + nvkm_pci_wr08(pci, 0x0704, 0xff); +} + +static const struct nvkm_pci_func +gf100_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = gf100_pci_msi_rearm, +}; + +int +gf100_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&gf100_pci_func, device, index, ppci); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c new file mode 100644 index 0000000000000..5b1ed42cb90b9 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv04.c @@ -0,0 +1,58 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +static u32 +nv04_pci_rd32(struct nvkm_pci *pci, u16 addr) +{ + struct nvkm_device *device = pci->subdev.device; + return nvkm_rd32(device, 0x001800 + addr); +} + +static void +nv04_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr08(device, 0x001800 + addr, data); +} + +static void +nv04_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr32(device, 0x001800 + addr, data); +} + +static const struct nvkm_pci_func +nv04_pci_func = { + .rd32 = nv04_pci_rd32, + .wr08 = nv04_pci_wr08, + .wr32 = nv04_pci_wr32, +}; + +int +nv04_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv04_pci_func, device, index, ppci); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c new file mode 100644 index 0000000000000..090a187f165f3 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv40.c @@ -0,0 +1,65 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +u32 +nv40_pci_rd32(struct nvkm_pci *pci, u16 addr) +{ + struct nvkm_device *device = pci->subdev.device; + return nvkm_rd32(device, 0x088000 + addr); +} + +void +nv40_pci_wr08(struct nvkm_pci *pci, u16 addr, u8 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr08(device, 0x088000 + addr, data); +} + +void +nv40_pci_wr32(struct nvkm_pci *pci, u16 addr, u32 data) +{ + struct nvkm_device *device = pci->subdev.device; + nvkm_wr32(device, 0x088000 + addr, data); +} + +static void +nv40_pci_msi_rearm(struct nvkm_pci *pci) +{ + nvkm_pci_wr08(pci, 0x0068, 0xff); +} + +static const struct nvkm_pci_func +nv40_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv40_pci_msi_rearm, +}; + +int +nv40_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv40_pci_func, device, index, ppci); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c new file mode 100644 index 0000000000000..1f1b26b5fa729 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv4c.c @@ -0,0 +1,37 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +static const struct nvkm_pci_func +nv4c_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, +}; + +int +nv4c_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv4c_pci_func, device, index, ppci); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv50.c new file mode 100644 index 0000000000000..3e167d4a381f4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/nv50.c @@ -0,0 +1,51 @@ +/* + * Copyright 2015 Red Hat Inc. + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + */ +#include "priv.h" + +#include + +/* MSI re-arm through the PRI appears to be broken on the original G80, + * so we access it via alternate PCI config space mechanisms. + */ +static void +nv50_pci_msi_rearm(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + struct pci_dev *pdev = device->func->pci(device)->pdev; + pci_write_config_byte(pdev, 0x68, 0xff); +} + +static const struct nvkm_pci_func +nv50_pci_func = { + .rd32 = nv40_pci_rd32, + .wr08 = nv40_pci_wr08, + .wr32 = nv40_pci_wr32, + .msi_rearm = nv50_pci_msi_rearm, +}; + +int +nv50_pci_new(struct nvkm_device *device, int index, struct nvkm_pci **ppci) +{ + return nvkm_pci_new_(&nv50_pci_func, device, index, ppci); +} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h new file mode 100644 index 0000000000000..d22c2c117106e --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/priv.h @@ -0,0 +1,19 @@ +#ifndef __NVKM_PCI_PRIV_H__ +#define __NVKM_PCI_PRIV_H__ +#define nvkm_pci(p) container_of((p), struct nvkm_pci, subdev) +#include + +int nvkm_pci_new_(const struct nvkm_pci_func *, struct nvkm_device *, + int index, struct nvkm_pci **); + +struct nvkm_pci_func { + u32 (*rd32)(struct nvkm_pci *, u16 addr); + void (*wr08)(struct nvkm_pci *, u16 addr, u8 data); + void (*wr32)(struct nvkm_pci *, u16 addr, u32 data); + void (*msi_rearm)(struct nvkm_pci *); +}; + +u32 nv40_pci_rd32(struct nvkm_pci *, u16); +void nv40_pci_wr08(struct nvkm_pci *, u16, u8); +void nv40_pci_wr32(struct nvkm_pci *, u16, u32); +#endif -- GitLab From d4c4cc8373806d0f822f8847f8bcda64f36cb73f Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5563/7006] drm/nouveau/mc: abstract interface to master intr registers Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 32 ++++++++++++------- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c | 3 ++ .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 3 ++ .../gpu/drm/nouveau/nvkm/subdev/mc/gf106.c | 3 ++ .../gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c | 24 ++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 3 ++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 9 ++++++ 13 files changed, 84 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index bafafa643e7f8..1fbbdaad7fcd9 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -10,6 +10,9 @@ struct nvkm_mc { bool use_msi; }; +void nvkm_mc_intr_unarm(struct nvkm_mc *); +void nvkm_mc_intr_rearm(struct nvkm_mc *); +u32 nvkm_mc_intr_mask(struct nvkm_mc *); void nvkm_mc_unk260(struct nvkm_mc *, u32 data); int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 8d0f5aca3d539..6a8d56c7201ea 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -32,13 +32,24 @@ nvkm_mc_unk260(struct nvkm_mc *mc, u32 data) mc->func->unk260(mc, data); } -static inline u32 +void +nvkm_mc_intr_unarm(struct nvkm_mc *mc) +{ + return mc->func->intr_unarm(mc); +} + +void +nvkm_mc_intr_rearm(struct nvkm_mc *mc) +{ + return mc->func->intr_rearm(mc); +} + +u32 nvkm_mc_intr_mask(struct nvkm_mc *mc) { - struct nvkm_device *device = mc->subdev.device; - u32 intr = nvkm_rd32(device, 0x000100); - if (intr == 0xffffffff) /* likely fallen off the bus */ - intr = 0x00000000; + u32 intr = mc->func->intr_mask(mc); + if (WARN_ON_ONCE(intr == 0xffffffff)) + intr = 0; /* likely fallen off the bus */ return intr; } @@ -52,8 +63,7 @@ nvkm_mc_intr(int irq, void *arg) struct nvkm_subdev *unit; u32 intr; - nvkm_wr32(device, 0x000140, 0x00000000); - nvkm_rd32(device, 0x000140); + nvkm_mc_intr_unarm(mc); intr = nvkm_mc_intr_mask(mc); if (mc->use_msi) mc->func->msi_rearm(mc); @@ -74,14 +84,15 @@ nvkm_mc_intr(int irq, void *arg) nvkm_error(subdev, "unknown intr %08x\n", stat); } - nvkm_wr32(device, 0x000140, 0x00000001); + nvkm_mc_intr_rearm(mc); return intr ? IRQ_HANDLED : IRQ_NONE; } static int nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) { - nvkm_wr32(subdev->device, 0x000140, 0x00000000); + struct nvkm_mc *mc = nvkm_mc(subdev); + nvkm_mc_intr_unarm(mc); return 0; } @@ -96,10 +107,9 @@ static int nvkm_mc_init(struct nvkm_subdev *subdev) { struct nvkm_mc *mc = nvkm_mc(subdev); - struct nvkm_device *device = mc->subdev.device; if (mc->func->init) mc->func->init(mc); - nvkm_wr32(device, 0x000140, 0x00000001); + nvkm_mc_intr_rearm(mc); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c index 36720f25f952d..7d6a87f22b42e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c @@ -27,6 +27,9 @@ static const struct nvkm_mc_func g94_mc = { .init = nv50_mc_init, .intr = nv50_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 2936fabb7cf18..3eec7251b4d3f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -48,6 +48,9 @@ static const struct nvkm_mc_func g98_mc = { .init = nv50_mc_init, .intr = g98_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 6e7af483ccf3c..5ad00809d66fb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -64,6 +64,9 @@ static const struct nvkm_mc_func gf100_mc = { .init = nv50_mc_init, .intr = gf100_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = gf100_mc_msi_rearm, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c index 3515cff5ae48a..435f788b78bd0 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c @@ -27,6 +27,9 @@ static const struct nvkm_mc_func gf106_mc = { .init = nv50_mc_init, .intr = gf100_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index aa812fe197509..9a8b566202074 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -27,6 +27,9 @@ static const struct nvkm_mc_func gk20a_mc = { .init = nv50_mc_init, .intr = gf100_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c index 09dc2ebae7bc7..d282ec1555f86 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c @@ -38,6 +38,27 @@ nv04_mc_intr[] = { {} }; +void +nv04_mc_intr_unarm(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000000); + nvkm_rd32(device, 0x000140); +} + +void +nv04_mc_intr_rearm(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000001); +} + +u32 +nv04_mc_intr_mask(struct nvkm_mc *mc) +{ + return nvkm_rd32(mc->subdev.device, 0x000100); +} + void nv04_mc_init(struct nvkm_mc *mc) { @@ -50,6 +71,9 @@ static const struct nvkm_mc_func nv04_mc = { .init = nv04_mc_init, .intr = nv04_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c index 1e75445f84de8..80912e7d1dec6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c @@ -33,6 +33,9 @@ static const struct nvkm_mc_func nv40_mc = { .init = nv04_mc_init, .intr = nv04_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index e6795d1aa60da..79958c13a5f82 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -41,6 +41,9 @@ static const struct nvkm_mc_func nv44_mc = { .init = nv44_mc_init, .intr = nv04_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c index 61ab2547af85d..68a4a04777215 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c @@ -27,6 +27,9 @@ static const struct nvkm_mc_func nv4c_mc = { .init = nv44_mc_init, .intr = nv04_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 071789927615a..325a18232030b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -59,6 +59,9 @@ static const struct nvkm_mc_func nv50_mc = { .init = nv50_mc_init, .intr = nv50_mc_intr, + .intr_unarm = nv04_mc_intr_unarm, + .intr_rearm = nv04_mc_intr_rearm, + .intr_mask = nv04_mc_intr_mask, .msi_rearm = nv50_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index ca2249b189980..5f9407281b6fd 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -14,12 +14,21 @@ struct nvkm_mc_intr { struct nvkm_mc_func { void (*init)(struct nvkm_mc *); const struct nvkm_mc_intr *intr; + /* disable reporting of interrupts to host */ + void (*intr_unarm)(struct nvkm_mc *); + /* enable reporting of interrupts to host */ + void (*intr_rearm)(struct nvkm_mc *); + /* retrieve pending interrupt mask (NV_PMC_INTR) */ + u32 (*intr_mask)(struct nvkm_mc *); void (*msi_rearm)(struct nvkm_mc *); void (*unk260)(struct nvkm_mc *, u32); }; void nv04_mc_init(struct nvkm_mc *); extern const struct nvkm_mc_intr nv04_mc_intr[]; +void nv04_mc_intr_unarm(struct nvkm_mc *); +void nv04_mc_intr_rearm(struct nvkm_mc *); +u32 nv04_mc_intr_mask(struct nvkm_mc *); void nv40_mc_msi_rearm(struct nvkm_mc *); -- GitLab From ae0a5b2dd2f54584d677701d989732b464b6d8c9 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5564/7006] drm/nouveau/mc/gf100-: handle second interrupt tree Doesn't fix any known issue, but best be safe in case control is handed to us from firmware with these left enabled. Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 32 +++++++++++++++++-- .../gpu/drm/nouveau/nvkm/subdev/mc/gf106.c | 6 ++-- .../gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c | 6 ++-- drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 3 ++ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 5ad00809d66fb..6688d233a3e57 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -48,6 +48,32 @@ gf100_mc_intr[] = { {}, }; +void +gf100_mc_intr_unarm(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000000); + nvkm_wr32(device, 0x000144, 0x00000000); + nvkm_rd32(device, 0x000140); +} + +void +gf100_mc_intr_rearm(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + nvkm_wr32(device, 0x000140, 0x00000001); + nvkm_wr32(device, 0x000144, 0x00000001); +} + +u32 +gf100_mc_intr_mask(struct nvkm_mc *mc) +{ + struct nvkm_device *device = mc->subdev.device; + u32 intr0 = nvkm_rd32(device, 0x000100); + u32 intr1 = nvkm_rd32(device, 0x000104); + return intr0 | intr1; +} + static void gf100_mc_msi_rearm(struct nvkm_mc *mc) { @@ -64,9 +90,9 @@ static const struct nvkm_mc_func gf100_mc = { .init = nv50_mc_init, .intr = gf100_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_unarm = gf100_mc_intr_unarm, + .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .msi_rearm = gf100_mc_msi_rearm, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c index 435f788b78bd0..31223cfa1a0a8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c @@ -27,9 +27,9 @@ static const struct nvkm_mc_func gf106_mc = { .init = nv50_mc_init, .intr = gf100_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_unarm = gf100_mc_intr_unarm, + .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 9a8b566202074..0592bd54bb82c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -27,9 +27,9 @@ static const struct nvkm_mc_func gk20a_mc = { .init = nv50_mc_init, .intr = gf100_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, + .intr_unarm = gf100_mc_intr_unarm, + .intr_rearm = gf100_mc_intr_rearm, + .intr_mask = gf100_mc_intr_mask, .msi_rearm = nv40_mc_msi_rearm, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index 5f9407281b6fd..5e10ea6054223 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -38,5 +38,8 @@ void nv50_mc_init(struct nvkm_mc *); extern const struct nvkm_mc_intr nv50_mc_intr[]; extern const struct nvkm_mc_intr gf100_mc_intr[]; +void gf100_mc_intr_unarm(struct nvkm_mc *); +void gf100_mc_intr_rearm(struct nvkm_mc *); +u32 gf100_mc_intr_mask(struct nvkm_mc *); void gf100_mc_unk260(struct nvkm_mc *, u32); #endif -- GitLab From 2b700825e7a7702fb862edba1262c98040dc1bf6 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:22 +1000 Subject: [PATCH 5565/7006] drm/nouveau/mc: move device irq handling to platform-specific code Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 4 +- .../gpu/drm/nouveau/include/nvkm/core/tegra.h | 1 + .../gpu/drm/nouveau/include/nvkm/subdev/mc.h | 9 +- .../gpu/drm/nouveau/include/nvkm/subdev/pci.h | 4 +- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 72 +++++++------- .../drm/nouveau/nvkm/engine/device/tegra.c | 46 +++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild | 4 - drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c | 99 ++++--------------- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c | 40 -------- drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c | 1 - .../gpu/drm/nouveau/nvkm/subdev/mc/gf100.c | 7 -- .../gpu/drm/nouveau/nvkm/subdev/mc/gf106.c | 41 -------- .../gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c | 1 - drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c | 46 --------- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c | 1 - drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c | 39 -------- drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c | 8 -- drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h | 3 - .../gpu/drm/nouveau/nvkm/subdev/pci/base.c | 80 ++++++++++++++- 19 files changed, 182 insertions(+), 324 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c delete mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index bc151c64bbad2..b4974505af054 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -146,6 +146,7 @@ struct nvkm_device_func { struct nvkm_device_tegra *(*tegra)(struct nvkm_device *); void *(*dtor)(struct nvkm_device *); int (*preinit)(struct nvkm_device *); + int (*init)(struct nvkm_device *); void (*fini)(struct nvkm_device *, bool suspend); }; @@ -247,9 +248,6 @@ nv_device_resource_start(struct nvkm_device *device, unsigned int bar); resource_size_t nv_device_resource_len(struct nvkm_device *device, unsigned int bar); -int -nv_device_get_irq(struct nvkm_device *device, bool stall); - struct platform_device; enum nv_bus_type { diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h index 162986e7f8c40..1755c2d30fcdf 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h @@ -5,6 +5,7 @@ struct nvkm_device_tegra { struct nvkm_device device; struct platform_device *pdev; + int irq; }; int nvkm_device_tegra_new(struct platform_device *, diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h index 1fbbdaad7fcd9..4de05e718f838 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h @@ -5,24 +5,17 @@ struct nvkm_mc { const struct nvkm_mc_func *func; struct nvkm_subdev subdev; - - unsigned int irq; - bool use_msi; }; +void nvkm_mc_intr(struct nvkm_mc *, bool *handled); void nvkm_mc_intr_unarm(struct nvkm_mc *); void nvkm_mc_intr_rearm(struct nvkm_mc *); -u32 nvkm_mc_intr_mask(struct nvkm_mc *); void nvkm_mc_unk260(struct nvkm_mc *, u32 data); int nv04_mc_new(struct nvkm_device *, int, struct nvkm_mc **); -int nv40_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int nv44_mc_new(struct nvkm_device *, int, struct nvkm_mc **); -int nv4c_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int nv50_mc_new(struct nvkm_device *, int, struct nvkm_mc **); -int g94_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int g98_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int gf100_mc_new(struct nvkm_device *, int, struct nvkm_mc **); -int gf106_mc_new(struct nvkm_device *, int, struct nvkm_mc **); int gk20a_mc_new(struct nvkm_device *, int, struct nvkm_mc **); #endif diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h index ea4b0cce6159a..ac14fdf2f967a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h @@ -5,13 +5,15 @@ struct nvkm_pci { const struct nvkm_pci_func *func; struct nvkm_subdev subdev; + struct pci_dev *pdev; + int irq; + bool msi; }; u32 nvkm_pci_rd32(struct nvkm_pci *, u16 addr); void nvkm_pci_wr08(struct nvkm_pci *, u16 addr, u8 data); void nvkm_pci_wr32(struct nvkm_pci *, u16 addr, u32 data); void nvkm_pci_rom_shadow(struct nvkm_pci *, bool shadow); -void nvkm_pci_msi_rearm(struct nvkm_pci *); int nv04_pci_new(struct nvkm_device *, int, struct nvkm_pci **); int nv40_pci_new(struct nvkm_device *, int, struct nvkm_pci **); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 743a3e9796dd7..5fab8384d1f47 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -479,7 +479,7 @@ nv40_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv04_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -505,7 +505,7 @@ nv41_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv41_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -531,7 +531,7 @@ nv42_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv41_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -557,7 +557,7 @@ nv43_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv41_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -609,7 +609,7 @@ nv45_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv04_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -661,7 +661,7 @@ nv47_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv41_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -687,7 +687,7 @@ nv49_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv41_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -739,7 +739,7 @@ nv4b_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv40_mc_new, + .mc = nv04_mc_new, .mmu = nv41_mmu_new, .pci = nv40_pci_new, .therm = nv40_therm_new, @@ -765,7 +765,7 @@ nv4c_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv4c_mc_new, + .mc = nv44_mc_new, .mmu = nv44_mmu_new, .pci = nv4c_pci_new, .therm = nv40_therm_new, @@ -791,7 +791,7 @@ nv4e_chipset = { .gpio = nv10_gpio_new, .i2c = nv4e_i2c_new, .imem = nv40_instmem_new, - .mc = nv4c_mc_new, + .mc = nv44_mc_new, .mmu = nv44_mmu_new, .pci = nv4c_pci_new, .therm = nv40_therm_new, @@ -846,7 +846,7 @@ nv63_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv4c_mc_new, + .mc = nv44_mc_new, .mmu = nv44_mmu_new, .pci = nv4c_pci_new, .therm = nv40_therm_new, @@ -872,7 +872,7 @@ nv67_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv4c_mc_new, + .mc = nv44_mc_new, .mmu = nv44_mmu_new, .pci = nv4c_pci_new, .therm = nv40_therm_new, @@ -898,7 +898,7 @@ nv68_chipset = { .gpio = nv10_gpio_new, .i2c = nv04_i2c_new, .imem = nv40_instmem_new, - .mc = nv4c_mc_new, + .mc = nv44_mc_new, .mmu = nv44_mmu_new, .pci = nv4c_pci_new, .therm = nv40_therm_new, @@ -1022,7 +1022,7 @@ nv94_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, - .mc = g94_mc_new, + .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1054,7 +1054,7 @@ nv96_chipset = { .gpio = g94_gpio_new, .i2c = g94_i2c_new, .imem = nv50_instmem_new, - .mc = g94_mc_new, + .mc = nv50_mc_new, .mmu = nv50_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1385,7 +1385,7 @@ nvc1_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1420,7 +1420,7 @@ nvc3_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1563,7 +1563,7 @@ nvcf_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1598,7 +1598,7 @@ nvd7_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1631,7 +1631,7 @@ nvd9_chipset = { .ibus = gf100_ibus_new, .imem = nv50_instmem_new, .ltc = gf100_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1666,7 +1666,7 @@ nve4_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1703,7 +1703,7 @@ nve6_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1740,7 +1740,7 @@ nve7_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1801,7 +1801,7 @@ nvf0_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -1837,7 +1837,7 @@ nvf1_chipset = { .ibus = gk104_ibus_new, .imem = nv50_instmem_new, .ltc = gk104_ltc_new, - .mc = gf106_mc_new, + .mc = gf100_mc_new, .mmu = gf100_mmu_new, .mxm = nv50_mxm_new, .pci = nv40_pci_new, @@ -2231,11 +2231,17 @@ nvkm_device_init(struct nvkm_device *device) nvdev_trace(device, "init running...\n"); time = ktime_to_us(ktime_get()); + if (device->func->init) { + ret = device->func->init(device); + if (ret) + goto fail; + } + for (i = 0; i < NVKM_SUBDEV_NR; i++) { if ((subdev = nvkm_device_subdev(device, i))) { ret = nvkm_subdev_init(subdev); if (ret) - goto fail; + goto fail_subdev; } } @@ -2245,12 +2251,13 @@ nvkm_device_init(struct nvkm_device *device) nvdev_trace(device, "init completed in %lldus\n", time); return 0; -fail: +fail_subdev: do { if ((subdev = nvkm_device_subdev(device, i))) nvkm_subdev_fini(subdev, false); } while (--i >= 0); +fail: nvdev_error(device, "init failed with %d\n", ret); return ret; } @@ -2285,17 +2292,6 @@ nv_device_resource_len(struct nvkm_device *device, unsigned int bar) } } -int -nv_device_get_irq(struct nvkm_device *device, bool stall) -{ - if (nv_device_is_pci(device)) { - return device->pdev->irq; - } else { - return platform_get_irq_byname(device->platformdev, - stall ? "stall" : "nonstall"); - } -} - void nvkm_device_del(struct nvkm_device **pdevice) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 0a5e5b88fee2a..2587a17981b2f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -31,9 +31,54 @@ nvkm_device_tegra(struct nvkm_device *obj) return container_of(obj, struct nvkm_device_tegra, device); } +static irqreturn_t +nvkm_device_tegra_intr(int irq, void *arg) +{ + struct nvkm_device_tegra *tdev = arg; + struct nvkm_mc *mc = tdev->device.mc; + bool handled = false; + if (likely(mc)) { + nvkm_mc_intr_unarm(mc); + nvkm_mc_intr(mc, &handled); + nvkm_mc_intr_rearm(mc); + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static void +nvkm_device_tegra_fini(struct nvkm_device *device, bool suspend) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + if (tdev->irq) { + free_irq(tdev->irq, tdev); + tdev->irq = 0; + }; +} + +static int +nvkm_device_tegra_init(struct nvkm_device *device) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + int irq, ret; + + irq = platform_get_irq_byname(tdev->pdev, "stall"); + if (irq < 0) + return irq; + + ret = request_irq(irq, nvkm_device_tegra_intr, + IRQF_SHARED, "nvkm", tdev); + if (ret) + return ret; + + tdev->irq = irq; + return 0; +} + static const struct nvkm_device_func nvkm_device_tegra_func = { .tegra = nvkm_device_tegra, + .init = nvkm_device_tegra_init, + .fini = nvkm_device_tegra_fini, }; int @@ -48,6 +93,7 @@ nvkm_device_tegra_new(struct platform_device *pdev, return -ENOMEM; *pdevice = &tdev->device; tdev->pdev = pdev; + tdev->irq = -1; return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, pdev, NVKM_BUS_PLATFORM, pdev->id, NULL, diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild index 721643f04bb55..bef325dcb4d00 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild @@ -1,11 +1,7 @@ nvkm-y += nvkm/subdev/mc/base.o nvkm-y += nvkm/subdev/mc/nv04.o -nvkm-y += nvkm/subdev/mc/nv40.o nvkm-y += nvkm/subdev/mc/nv44.o -nvkm-y += nvkm/subdev/mc/nv4c.o nvkm-y += nvkm/subdev/mc/nv50.o -nvkm-y += nvkm/subdev/mc/g94.o nvkm-y += nvkm/subdev/mc/g98.o nvkm-y += nvkm/subdev/mc/gf100.o -nvkm-y += nvkm/subdev/mc/gf106.o nvkm-y += nvkm/subdev/mc/gk20a.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c index 6a8d56c7201ea..954fbbe56c4ba 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c @@ -44,7 +44,7 @@ nvkm_mc_intr_rearm(struct nvkm_mc *mc) return mc->func->intr_rearm(mc); } -u32 +static u32 nvkm_mc_intr_mask(struct nvkm_mc *mc) { u32 intr = mc->func->intr_mask(mc); @@ -53,39 +53,28 @@ nvkm_mc_intr_mask(struct nvkm_mc *mc) return intr; } -static irqreturn_t -nvkm_mc_intr(int irq, void *arg) +void +nvkm_mc_intr(struct nvkm_mc *mc, bool *handled) { - struct nvkm_mc *mc = arg; - struct nvkm_subdev *subdev = &mc->subdev; - struct nvkm_device *device = subdev->device; + struct nvkm_device *device = mc->subdev.device; + struct nvkm_subdev *subdev; const struct nvkm_mc_intr *map = mc->func->intr; - struct nvkm_subdev *unit; - u32 intr; - - nvkm_mc_intr_unarm(mc); - intr = nvkm_mc_intr_mask(mc); - if (mc->use_msi) - mc->func->msi_rearm(mc); - - if (intr) { - u32 stat = intr = nvkm_mc_intr_mask(mc); - while (map->stat) { - if (intr & map->stat) { - unit = nvkm_device_subdev(device, map->unit); - if (unit) - nvkm_subdev_intr(unit); - stat &= ~map->stat; - } - map++; + u32 stat, intr; + + stat = intr = nvkm_mc_intr_mask(mc); + while (map->stat) { + if (intr & map->stat) { + subdev = nvkm_device_subdev(device, map->unit); + if (subdev) + nvkm_subdev_intr(subdev); + stat &= ~map->stat; } - - if (stat) - nvkm_error(subdev, "unknown intr %08x\n", stat); + map++; } - nvkm_mc_intr_rearm(mc); - return intr ? IRQ_HANDLED : IRQ_NONE; + if (stat) + nvkm_error(&mc->subdev, "intr %08x\n", stat); + *handled = intr != 0; } static int @@ -96,13 +85,6 @@ nvkm_mc_fini(struct nvkm_subdev *subdev, bool suspend) return 0; } -static int -nvkm_mc_oneinit(struct nvkm_subdev *subdev) -{ - struct nvkm_mc *mc = nvkm_mc(subdev); - return request_irq(mc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", mc); -} - static int nvkm_mc_init(struct nvkm_subdev *subdev) { @@ -116,18 +98,12 @@ nvkm_mc_init(struct nvkm_subdev *subdev) static void * nvkm_mc_dtor(struct nvkm_subdev *subdev) { - struct nvkm_mc *mc = nvkm_mc(subdev); - struct nvkm_device *device = mc->subdev.device; - free_irq(mc->irq, mc); - if (mc->use_msi) - pci_disable_msi(device->pdev); - return mc; + return nvkm_mc(subdev); } static const struct nvkm_subdev_func nvkm_mc = { .dtor = nvkm_mc_dtor, - .oneinit = nvkm_mc_oneinit, .init = nvkm_mc_init, .fini = nvkm_mc_fini, }; @@ -137,48 +113,11 @@ nvkm_mc_new_(const struct nvkm_mc_func *func, struct nvkm_device *device, int index, struct nvkm_mc **pmc) { struct nvkm_mc *mc; - int ret; if (!(mc = *pmc = kzalloc(sizeof(*mc), GFP_KERNEL))) return -ENOMEM; nvkm_subdev_ctor(&nvkm_mc, device, index, 0, &mc->subdev); mc->func = func; - - if (nv_device_is_pci(device)) { - switch (device->pdev->device & 0x0ff0) { - case 0x00f0: - case 0x02e0: - /* BR02? NFI how these would be handled yet exactly */ - break; - default: - switch (device->chipset) { - case 0xaa: - /* reported broken, nv also disable it */ - break; - default: - mc->use_msi = true; - break; - } - } - - mc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI", - mc->use_msi); - - if (mc->use_msi && mc->func->msi_rearm) { - mc->use_msi = pci_enable_msi(device->pdev) == 0; - if (mc->use_msi) { - nvkm_debug(&mc->subdev, "MSI enabled\n"); - mc->func->msi_rearm(mc); - } - } else { - mc->use_msi = false; - } - } - - ret = nv_device_get_irq(device, true); - if (ret < 0) - return ret; - mc->irq = ret; return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c deleted file mode 100644 index 7d6a87f22b42e..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -static const struct nvkm_mc_func -g94_mc = { - .init = nv50_mc_init, - .intr = nv50_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, - .msi_rearm = nv40_mc_msi_rearm, -}; - -int -g94_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) -{ - return nvkm_mc_new_(&g94_mc, device, index, pmc); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c index 3eec7251b4d3f..7344ad659105c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c @@ -51,7 +51,6 @@ g98_mc = { .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, - .msi_rearm = nv40_mc_msi_rearm, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c index 6688d233a3e57..122fe69e83e41 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c @@ -74,12 +74,6 @@ gf100_mc_intr_mask(struct nvkm_mc *mc) return intr0 | intr1; } -static void -gf100_mc_msi_rearm(struct nvkm_mc *mc) -{ - nvkm_wr32(mc->subdev.device, 0x088704, 0x00000000); -} - void gf100_mc_unk260(struct nvkm_mc *mc, u32 data) { @@ -93,7 +87,6 @@ gf100_mc = { .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, .intr_mask = gf100_mc_intr_mask, - .msi_rearm = gf100_mc_msi_rearm, .unk260 = gf100_mc_unk260, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c deleted file mode 100644 index 31223cfa1a0a8..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -static const struct nvkm_mc_func -gf106_mc = { - .init = nv50_mc_init, - .intr = gf100_mc_intr, - .intr_unarm = gf100_mc_intr_unarm, - .intr_rearm = gf100_mc_intr_rearm, - .intr_mask = gf100_mc_intr_mask, - .msi_rearm = nv40_mc_msi_rearm, - .unk260 = gf100_mc_unk260, -}; - -int -gf106_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) -{ - return nvkm_mc_new_(&gf106_mc, device, index, pmc); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c index 0592bd54bb82c..d92efb33bcc3c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c @@ -30,7 +30,6 @@ gk20a_mc = { .intr_unarm = gf100_mc_intr_unarm, .intr_rearm = gf100_mc_intr_rearm, .intr_mask = gf100_mc_intr_mask, - .msi_rearm = nv40_mc_msi_rearm, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c deleted file mode 100644 index 80912e7d1dec6..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2012 Red Hat Inc. - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs - */ -#include "priv.h" - -void -nv40_mc_msi_rearm(struct nvkm_mc *mc) -{ - nvkm_wr08(mc->subdev.device, 0x088068, 0xff); -} - -static const struct nvkm_mc_func -nv40_mc = { - .init = nv04_mc_init, - .intr = nv04_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, - .msi_rearm = nv40_mc_msi_rearm, -}; - -int -nv40_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) -{ - return nvkm_mc_new_(&nv40_mc, device, index, pmc); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c index 79958c13a5f82..9a3ac9965be06 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c @@ -44,7 +44,6 @@ nv44_mc = { .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, - .msi_rearm = nv40_mc_msi_rearm, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c deleted file mode 100644 index 68a4a04777215..0000000000000 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2014 Ilia Mirkin - * - * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ilia Mirkin - */ -#include "priv.h" - -static const struct nvkm_mc_func -nv4c_mc = { - .init = nv44_mc_init, - .intr = nv04_mc_intr, - .intr_unarm = nv04_mc_intr_unarm, - .intr_rearm = nv04_mc_intr_rearm, - .intr_mask = nv04_mc_intr_mask, -}; - -int -nv4c_mc_new(struct nvkm_device *device, int index, struct nvkm_mc **pmc) -{ - return nvkm_mc_new_(&nv4c_mc, device, index, pmc); -} diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c index 325a18232030b..5f27d7b8fddda 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c @@ -41,13 +41,6 @@ nv50_mc_intr[] = { {}, }; -static void -nv50_mc_msi_rearm(struct nvkm_mc *mc) -{ - struct nvkm_device *device = mc->subdev.device; - pci_write_config_byte(device->pdev, 0x68, 0xff); -} - void nv50_mc_init(struct nvkm_mc *mc) { @@ -62,7 +55,6 @@ nv50_mc = { .intr_unarm = nv04_mc_intr_unarm, .intr_rearm = nv04_mc_intr_rearm, .intr_mask = nv04_mc_intr_mask, - .msi_rearm = nv50_mc_msi_rearm, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h index 5e10ea6054223..307f6c6922879 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h @@ -20,7 +20,6 @@ struct nvkm_mc_func { void (*intr_rearm)(struct nvkm_mc *); /* retrieve pending interrupt mask (NV_PMC_INTR) */ u32 (*intr_mask)(struct nvkm_mc *); - void (*msi_rearm)(struct nvkm_mc *); void (*unk260)(struct nvkm_mc *, u32); }; @@ -30,8 +29,6 @@ void nv04_mc_intr_unarm(struct nvkm_mc *); void nv04_mc_intr_rearm(struct nvkm_mc *); u32 nv04_mc_intr_mask(struct nvkm_mc *); -void nv40_mc_msi_rearm(struct nvkm_mc *); - void nv44_mc_init(struct nvkm_mc *); void nv50_mc_init(struct nvkm_mc *); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index 6a742659a9019..e5e0d02f3d88e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -23,6 +23,10 @@ */ #include "priv.h" +#include +#include +#include + u32 nvkm_pci_rd32(struct nvkm_pci *pci, u16 addr) { @@ -52,21 +56,62 @@ nvkm_pci_rom_shadow(struct nvkm_pci *pci, bool shadow) nvkm_pci_wr32(pci, 0x0050, data); } -void -nvkm_pci_msi_rearm(struct nvkm_pci *pci) +static irqreturn_t +nvkm_pci_intr(int irq, void *arg) +{ + struct nvkm_pci *pci = arg; + struct nvkm_mc *mc = pci->subdev.device->mc; + bool handled = false; + if (likely(mc)) { + nvkm_mc_intr_unarm(mc); + if (pci->msi) + pci->func->msi_rearm(pci); + nvkm_mc_intr(mc, &handled); + nvkm_mc_intr_rearm(mc); + } + return handled ? IRQ_HANDLED : IRQ_NONE; +} + +static int +nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) { - pci->func->msi_rearm(pci); + struct nvkm_pci *pci = nvkm_pci(subdev); + if (pci->irq >= 0) { + free_irq(pci->irq, pci); + pci->irq = -1; + }; + return 0; +} + +static int +nvkm_pci_init(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + struct pci_dev *pdev = pci->pdev; + int ret; + + ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci); + if (ret) + return ret; + + pci->irq = pdev->irq; + return ret; } static void * nvkm_pci_dtor(struct nvkm_subdev *subdev) { + struct nvkm_pci *pci = nvkm_pci(subdev); + if (pci->msi) + pci_disable_msi(pci->pdev); return nvkm_pci(subdev); } static const struct nvkm_subdev_func nvkm_pci_func = { .dtor = nvkm_pci_dtor, + .init = nvkm_pci_init, + .fini = nvkm_pci_fini, }; int @@ -74,9 +119,38 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, int index, struct nvkm_pci **ppci) { struct nvkm_pci *pci; + if (!(pci = *ppci = kzalloc(sizeof(**ppci), GFP_KERNEL))) return -ENOMEM; nvkm_subdev_ctor(&nvkm_pci_func, device, index, 0, &pci->subdev); pci->func = func; + pci->pdev = device->func->pci(device)->pdev; + pci->irq = -1; + + switch (pci->pdev->device & 0x0ff0) { + case 0x00f0: + case 0x02e0: + /* BR02? NFI how these would be handled yet exactly */ + break; + default: + switch (device->chipset) { + case 0xaa: + /* reported broken, nv also disable it */ + break; + default: + pci->msi = true; + break; + } + } + + pci->msi = nvkm_boolopt(device->cfgopt, "NvMSI", pci->msi); + if (pci->msi && func->msi_rearm) { + pci->msi = pci_enable_msi(pci->pdev) == 0; + if (pci->msi) + nvkm_debug(&pci->subdev, "MSI enabled\n"); + } else { + pci->msi = false; + } + return 0; } -- GitLab From 7e8820fed712c6de1933dcc91edbf08dcec74925 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:23 +1000 Subject: [PATCH 5566/7006] drm/nouveau/device: cleaner abstraction for device resource functions Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 8 ++--- drivers/gpu/drm/nouveau/nouveau_bo.c | 7 ++-- drivers/gpu/drm/nouveau/nouveau_chan.c | 3 +- drivers/gpu/drm/nouveau/nouveau_display.c | 3 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 5 +-- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 34 ++----------------- .../gpu/drm/nouveau/nvkm/engine/device/pci.c | 16 +++++++++ .../drm/nouveau/nvkm/engine/device/tegra.c | 27 +++++++++++++-- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 4 +-- .../drm/nouveau/nvkm/engine/disp/channv50.c | 2 +- .../gpu/drm/nouveau/nvkm/engine/fifo/chan.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/gf100.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bar/nv50.c | 4 +-- .../drm/nouveau/nvkm/subdev/devinit/fbmem.h | 4 +-- .../drm/nouveau/nvkm/subdev/instmem/nv40.c | 6 ++-- .../drm/nouveau/nvkm/subdev/instmem/nv50.c | 2 +- 18 files changed, 71 insertions(+), 62 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index b4974505af054..1fd0a07faadc9 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -148,6 +148,8 @@ struct nvkm_device_func { int (*preinit)(struct nvkm_device *); int (*init)(struct nvkm_device *); void (*fini)(struct nvkm_device *, bool suspend); + resource_size_t (*resource_addr)(struct nvkm_device *, unsigned bar); + resource_size_t (*resource_size)(struct nvkm_device *, unsigned bar); }; struct nvkm_device_quirk { @@ -242,12 +244,6 @@ nv_device_base(struct nvkm_device *device) &device->platformdev->dev; } -resource_size_t -nv_device_resource_start(struct nvkm_device *device, unsigned int bar); - -resource_size_t -nv_device_resource_len(struct nvkm_device *device, unsigned int bar); - struct platform_device; enum nv_bus_type { diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index bd33d547d5740..6024edf8529e5 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -1351,6 +1351,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) { struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type]; struct nouveau_drm *drm = nouveau_bdev(bdev); + struct nvkm_device *device = nvxx_device(&drm->device); struct nvkm_mem *node = mem->mm_node; int ret; @@ -1379,7 +1380,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) /* fallthrough, tiled memory */ case TTM_PL_VRAM: mem->bus.offset = mem->start << PAGE_SHIFT; - mem->bus.base = nv_device_resource_start(nvxx_device(&drm->device), 1); + mem->bus.base = device->func->resource_addr(device, 1); mem->bus.is_iomem = true; if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { struct nvkm_bar *bar = nvxx_bar(&drm->device); @@ -1419,8 +1420,8 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo) { struct nouveau_drm *drm = nouveau_bdev(bo->bdev); struct nouveau_bo *nvbo = nouveau_bo(bo); - struct nvif_device *device = &drm->device; - u32 mappable = nv_device_resource_len(nvxx_device(device), 1) >> PAGE_SHIFT; + struct nvkm_device *device = nvxx_device(&drm->device); + u32 mappable = device->func->resource_size(device, 1) >> PAGE_SHIFT; int i, ret; /* as long as the bo isn't in vram, and isn't tiled, we've got diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index 8c88c5e5bf0b2..f59c4f5716cc6 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -150,7 +150,8 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, */ args.target = NV_DMA_V0_TARGET_PCI; args.access = NV_DMA_V0_ACCESS_RDWR; - args.start = nv_device_resource_start(nvxx_device(device), 1); + args.start = nvxx_device(device)->func-> + resource_addr(nvxx_device(device), 1); args.limit = args.start + device->info.ram_user - 1; } else { args.target = NV_DMA_V0_TARGET_VRAM; diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c index 5553caa16b9cd..cc6c228e11c83 100644 --- a/drivers/gpu/drm/nouveau/nouveau_display.c +++ b/drivers/gpu/drm/nouveau/nouveau_display.c @@ -445,6 +445,7 @@ int nouveau_display_create(struct drm_device *dev) { struct nouveau_drm *drm = nouveau_drm(dev); + struct nvkm_device *device = nvxx_device(&drm->device); struct nouveau_display *disp; int ret; @@ -457,7 +458,7 @@ nouveau_display_create(struct drm_device *dev) drm_mode_create_dvi_i_properties(dev); dev->mode_config.funcs = &nouveau_mode_config_funcs; - dev->mode_config.fb_base = nv_device_resource_start(nvxx_device(&drm->device), 1); + dev->mode_config.fb_base = device->func->resource_addr(device, 1); dev->mode_config.min_width = 0; dev->mode_config.min_height = 0; diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index d8999f71a7988..1fd70d6900cf7 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -335,6 +335,7 @@ nouveau_ttm_global_release(struct nouveau_drm *drm) int nouveau_ttm_init(struct nouveau_drm *drm) { + struct nvkm_device *device = nvxx_device(&drm->device); struct drm_device *dev = drm->dev; u32 bits; int ret; @@ -381,8 +382,8 @@ nouveau_ttm_init(struct nouveau_drm *drm) return ret; } - drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(nvxx_device(&drm->device), 1), - nv_device_resource_len(nvxx_device(&drm->device), 1)); + drm->ttm.mtrr = arch_phys_wc_add(device->func->resource_addr(device, 1), + device->func->resource_size(device, 1)); /* GART init */ if (drm->agp.stat != ENABLED) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index 5fab8384d1f47..b8d46144e68a6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2262,36 +2262,6 @@ fail: return ret; } -resource_size_t -nv_device_resource_start(struct nvkm_device *device, unsigned int bar) -{ - if (nv_device_is_pci(device)) { - return pci_resource_start(device->pdev, bar); - } else { - struct resource *res; - res = platform_get_resource(device->platformdev, - IORESOURCE_MEM, bar); - if (!res) - return 0; - return res->start; - } -} - -resource_size_t -nv_device_resource_len(struct nvkm_device *device, unsigned int bar) -{ - if (nv_device_is_pci(device)) { - return pci_resource_len(device->pdev, bar); - } else { - struct resource *res; - res = platform_get_resource(device->platformdev, - IORESOURCE_MEM, bar); - if (!res) - return 0; - return resource_size(res); - } -} - void nvkm_device_del(struct nvkm_device **pdevice) { @@ -2363,8 +2333,8 @@ nvkm_device_ctor(const struct nvkm_device_func *func, if (ret) goto done; - mmio_base = nv_device_resource_start(device, 0); - mmio_size = nv_device_resource_len(device, 0); + mmio_base = device->func->resource_addr(device, 0); + mmio_size = device->func->resource_size(device, 0); /* identify the chipset, and determine classes of subdev/engines */ if (detect) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index 1a1d1e584a7f9..75612faaca2c6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -30,6 +30,20 @@ nvkm_device_pci(struct nvkm_device *device) return container_of(device, struct nvkm_device_pci, device); } +static resource_size_t +nvkm_device_pci_resource_addr(struct nvkm_device *device, unsigned bar) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + return pci_resource_start(pdev->pdev, bar); +} + +static resource_size_t +nvkm_device_pci_resource_size(struct nvkm_device *device, unsigned bar) +{ + struct nvkm_device_pci *pdev = nvkm_device_pci(device); + return pci_resource_len(pdev->pdev, bar); +} + static void nvkm_device_pci_fini(struct nvkm_device *device, bool suspend) { @@ -68,6 +82,8 @@ nvkm_device_pci_func = { .dtor = nvkm_device_pci_dtor, .preinit = nvkm_device_pci_preinit, .fini = nvkm_device_pci_fini, + .resource_addr = nvkm_device_pci_resource_addr, + .resource_size = nvkm_device_pci_resource_size, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index 2587a17981b2f..f4bc11c1671fe 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -26,9 +26,30 @@ #include "priv.h" static struct nvkm_device_tegra * -nvkm_device_tegra(struct nvkm_device *obj) +nvkm_device_tegra(struct nvkm_device *device) { - return container_of(obj, struct nvkm_device_tegra, device); + return container_of(device, struct nvkm_device_tegra, device); +} + +static struct resource * +nvkm_device_tegra_resource(struct nvkm_device *device, unsigned bar) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + return platform_get_resource(tdev->pdev, IORESOURCE_MEM, bar); +} + +static resource_size_t +nvkm_device_tegra_resource_addr(struct nvkm_device *device, unsigned bar) +{ + struct resource *res = nvkm_device_tegra_resource(device, bar); + return res ? res->start : 0; +} + +static resource_size_t +nvkm_device_tegra_resource_size(struct nvkm_device *device, unsigned bar) +{ + struct resource *res = nvkm_device_tegra_resource(device, bar); + return res ? resource_size(res) : 0; } static irqreturn_t @@ -79,6 +100,8 @@ nvkm_device_tegra_func = { .tegra = nvkm_device_tegra, .init = nvkm_device_tegra_init, .fini = nvkm_device_tegra_fini, + .resource_addr = nvkm_device_tegra_resource_addr, + .resource_size = nvkm_device_tegra_resource_size, }; int diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index a948960cc0566..eddf9b1d3340c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -198,8 +198,8 @@ nvkm_udevice_map(struct nvkm_object *object, u64 *addr, u32 *size) { struct nvkm_udevice *udev = nvkm_udevice(object); struct nvkm_device *device = udev->device; - *addr = nv_device_resource_start(device, 0); - *size = nv_device_resource_len(device, 0); + *addr = device->func->resource_addr(device, 0); + *size = device->func->resource_size(device, 0); return 0; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index c9cbfbd2a1aef..01803c0679b68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -195,7 +195,7 @@ nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) struct nv50_disp_chan *chan = nv50_disp_chan(object); struct nv50_disp *disp = chan->root->disp; struct nvkm_device *device = disp->base.engine.subdev.device; - *addr = nv_device_resource_start(device, 0) + + *addr = device->func->resource_addr(device, 0) + 0x640000 + (chan->chid * 0x1000); *size = 0x001000; return 0; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c index 9921482fc1624..dc6d4678f2285 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/chan.c @@ -406,7 +406,7 @@ nvkm_fifo_chan_ctor(const struct nvkm_fifo_chan_func *func, spin_unlock_irqrestore(&fifo->lock, flags); /* determine address of this channel's user registers */ - chan->addr = nv_device_resource_start(device, bar) + + chan->addr = device->func->resource_addr(device, bar) + base + user * chan->chid; chan->size = user; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c index 32ea28a71a412..5caef65d3c6eb 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c @@ -296,7 +296,7 @@ nv20_gr_init(struct nvkm_gr *base) nvkm_wr32(device, NV10_PGRAPH_SURFACE, tmp); /* begin RAM config */ - vramsz = nv_device_resource_len(device, 1) - 1; + vramsz = device->func->resource_size(device, 1) - 1; nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); nvkm_wr32(device, 0x4009A8, nvkm_rd32(device, 0x100204)); nvkm_wr32(device, NV10_PGRAPH_RDI_INDEX, 0x00EA0000); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c index 7987df18415b5..ffa902ece8723 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c @@ -385,7 +385,7 @@ nv40_gr_init(struct nvkm_gr *base) } /* begin RAM config */ - vramsz = nv_device_resource_len(device, 1) - 1; + vramsz = device->func->resource_size(device, 1) - 1; switch (device->chipset) { case 0x40: nvkm_wr32(device, 0x4009A4, nvkm_rd32(device, 0x100200)); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c index 2eb0a370a3a0e..c794b2c2d21e7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c @@ -58,7 +58,7 @@ gf100_bar_ctor_vm(struct gf100_bar *bar, struct gf100_bar_vm *bar_vm, if (ret) return ret; - bar_len = nv_device_resource_len(device, bar_nr); + bar_len = device->func->resource_size(device, bar_nr); ret = nvkm_vm_new(device, 0, bar_len, 0, key, &vm); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c index fac54f97217e5..370dcd8ff7b5a 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c @@ -82,7 +82,7 @@ nv50_bar_oneinit(struct nvkm_bar *base) /* BAR3 */ start = 0x0100000000ULL; - limit = start + nv_device_resource_len(device, 3); + limit = start + device->func->resource_size(device, 3); ret = nvkm_vm_new(device, start, limit, start, &bar3_lock, &vm); if (ret) @@ -115,7 +115,7 @@ nv50_bar_oneinit(struct nvkm_bar *base) /* BAR1 */ start = 0x0000000000ULL; - limit = start + nv_device_resource_len(device, 1); + limit = start + device->func->resource_size(device, 1); ret = nvkm_vm_new(device, start, limit--, start, &bar1_lock, &vm); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h index 4e484c40b5c63..6c5bbff12eb49 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h @@ -47,8 +47,8 @@ static inline struct io_mapping * fbmem_init(struct nvkm_device *dev) { - return io_mapping_create_wc(nv_device_resource_start(dev, 1), - nv_device_resource_len(dev, 1)); + return io_mapping_create_wc(dev->func->resource_addr(dev, 1), + dev->func->resource_size(dev, 1)); } static inline void diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c index a170ff9b32e75..c0543875e4904 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c @@ -243,13 +243,13 @@ nv40_instmem_new(struct nvkm_device *device, int index, *pimem = &imem->base; /* map bar */ - if (nv_device_resource_len(device, 2)) + if (device->func->resource_size(device, 2)) bar = 2; else bar = 3; - imem->iomem = ioremap(nv_device_resource_start(device, bar), - nv_device_resource_len(device, bar)); + imem->iomem = ioremap(device->func->resource_addr(device, bar), + device->func->resource_size(device, bar)); if (!imem->iomem) { nvkm_error(&imem->base.subdev, "unable to map PRAMIN BAR\n"); return -EFAULT; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c index ec5020e3fc42e..6d512c062ae32 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c @@ -81,7 +81,7 @@ nv50_instobj_boot(struct nvkm_memory *memory, struct nvkm_vm *vm) ret = nvkm_vm_get(vm, size, 12, NV_MEM_ACCESS_RW, &iobj->bar); if (ret == 0) { - map = ioremap(nv_device_resource_start(device, 3) + + map = ioremap(device->func->resource_addr(device, 3) + (u32)iobj->bar.offset, size); if (map) { nvkm_memory_map(memory, &iobj->bar, 0); -- GitLab From c7af0ff0e89327918743052d12bf5536e34c7f1a Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:23 +1000 Subject: [PATCH 5567/7006] drm/nouveau/device: import pciid list and integrate quirks with it PCI IDs taken from the NVIDIA binary driver, with permission. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/dispnv04/tvnv17.c | 12 +- .../drm/nouveau/include/nvkm/core/device.h | 11 +- .../gpu/drm/nouveau/nvkm/engine/device/pci.c | 1570 ++++++++++++++++- .../gpu/drm/nouveau/nvkm/subdev/gpio/base.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c | 6 +- 5 files changed, 1577 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c index c59b2c7d94e14..b734195d80a06 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c +++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c @@ -132,16 +132,8 @@ get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask) struct nouveau_drm *drm = nouveau_drm(dev); struct nvkm_device *device = nvxx_device(&drm->device); - /* Zotac FX5200 */ - if (nv_device_match(device, 0x0322, 0x19da, 0x1035) || - nv_device_match(device, 0x0322, 0x19da, 0x2035)) { - *pin_mask = 0xc; - return false; - } - - /* MSI nForce2 IGP */ - if (nv_device_match(device, 0x01f0, 0x1462, 0x5710)) { - *pin_mask = 0xc; + if (device->quirk && device->quirk->tv_pin_mask) { + *pin_mask = device->quirk->tv_pin_mask; return false; } diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 1fd0a07faadc9..5741bf228762f 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -153,6 +153,9 @@ struct nvkm_device_func { }; struct nvkm_device_quirk { + u8 tv_pin_mask; + u8 tv_gpio; + bool War00C800_0; }; struct nvkm_device_chip { @@ -217,14 +220,6 @@ int nvkm_device_list(u64 *name, int size); _temp; \ }) -static inline bool -nv_device_match(struct nvkm_device *device, u16 dev, u16 ven, u16 sub) -{ - return device->pdev->device == dev && - device->pdev->subsystem_vendor == ven && - device->pdev->subsystem_device == sub; -} - static inline bool nv_device_is_pci(struct nvkm_device *device) { diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index 75612faaca2c6..8702a9efc7b4b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -24,6 +24,1543 @@ #include #include "priv.h" +struct nvkm_device_pci_device { + u16 device; + const char *name; + const struct nvkm_device_pci_vendor *vendor; +}; + +struct nvkm_device_pci_vendor { + u16 vendor; + u16 device; + const char *name; + const struct nvkm_device_quirk quirk; +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0189[] = { + /* Apple iMac G4 NV18 */ + { 0x10de, 0x0010, NULL, { .tv_gpio = 4 } }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_01f0[] = { + /* MSI nForce2 IGP */ + { 0x1462, 0x5710, NULL, { .tv_pin_mask = 0xc } }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0322[] = { + /* Zotac FX5200 */ + { 0x19da, 0x1035, NULL, { .tv_pin_mask = 0xc } }, + { 0x19da, 0x2035, NULL, { .tv_pin_mask = 0xc } }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_05e7[] = { + { 0x10de, 0x0595, "Tesla T10 Processor" }, + { 0x10de, 0x068f, "Tesla T10 Processor" }, + { 0x10de, 0x0697, "Tesla M1060" }, + { 0x10de, 0x0714, "Tesla M1060" }, + { 0x10de, 0x0743, "Tesla M1060" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0609[] = { + { 0x106b, 0x00a7, "GeForce 8800 GS" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_062e[] = { + { 0x106b, 0x0605, "GeForce GT 130" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0649[] = { + { 0x1043, 0x202d, "GeForce GT 220M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0652[] = { + { 0x152d, 0x0850, "GeForce GT 240M LE" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0654[] = { + { 0x1043, 0x14a2, "GeForce GT 320M" }, + { 0x1043, 0x14d2, "GeForce GT 320M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0655[] = { + { 0x106b, 0x0633, "GeForce GT 120" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0656[] = { + { 0x106b, 0x0693, "GeForce GT 120" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06d1[] = { + { 0x10de, 0x0771, "Tesla C2050" }, + { 0x10de, 0x0772, "Tesla C2070" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06d2[] = { + { 0x10de, 0x088f, "Tesla X2070" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06de[] = { + { 0x10de, 0x0773, "Tesla S2050" }, + { 0x10de, 0x082f, "Tesla M2050" }, + { 0x10de, 0x0840, "Tesla X2070" }, + { 0x10de, 0x0842, "Tesla M2050" }, + { 0x10de, 0x0846, "Tesla M2050" }, + { 0x10de, 0x0866, "Tesla M2050" }, + { 0x10de, 0x0907, "Tesla M2050" }, + { 0x10de, 0x091e, "Tesla M2050" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06e8[] = { + { 0x103c, 0x360b, "GeForce 9200M GE" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06f9[] = { + { 0x10de, 0x060d, "Quadro FX 370 Low Profile" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_06ff[] = { + { 0x10de, 0x0711, "HICx8 + Graphics" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0866[] = { + { 0x106b, 0x00b1, "GeForce 9400M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0872[] = { + { 0x1043, 0x1c42, "GeForce G205M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0873[] = { + { 0x1043, 0x1c52, "GeForce G205M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a6e[] = { + { 0x17aa, 0x3607, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a70[] = { + { 0x17aa, 0x3605, "Second Generation ION" }, + { 0x17aa, 0x3617, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a73[] = { + { 0x17aa, 0x3607, "Second Generation ION" }, + { 0x17aa, 0x3610, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a74[] = { + { 0x17aa, 0x903a, "GeForce G210" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a75[] = { + { 0x17aa, 0x3605, "Second Generation ION" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0a7a[] = { + { 0x1462, 0xaa51, "GeForce 405" }, + { 0x1462, 0xaa58, "GeForce 405" }, + { 0x1462, 0xac71, "GeForce 405" }, + { 0x1462, 0xac82, "GeForce 405" }, + { 0x1642, 0x3980, "GeForce 405" }, + { 0x17aa, 0x3950, "GeForce 405M" }, + { 0x17aa, 0x397d, "GeForce 405M" }, + { 0x1b0a, 0x90b4, "GeForce 405" }, + { 0x1bfd, 0x0003, "GeForce 405" }, + { 0x1bfd, 0x8006, "GeForce 405" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0dd8[] = { + { 0x10de, 0x0914, "Quadro 2000D" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0de9[] = { + { 0x1025, 0x0692, "GeForce GT 620M" }, + { 0x1025, 0x0725, "GeForce GT 620M" }, + { 0x1025, 0x0728, "GeForce GT 620M" }, + { 0x1025, 0x072b, "GeForce GT 620M" }, + { 0x1025, 0x072e, "GeForce GT 620M" }, + { 0x1025, 0x0753, "GeForce GT 620M" }, + { 0x1025, 0x0754, "GeForce GT 620M" }, + { 0x17aa, 0x3977, "GeForce GT 640M LE" }, + { 0x1b0a, 0x2210, "GeForce GT 635M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0dea[] = { + { 0x17aa, 0x365a, "GeForce 615" }, + { 0x17aa, 0x365b, "GeForce 615" }, + { 0x17aa, 0x365e, "GeForce 615" }, + { 0x17aa, 0x3660, "GeForce 615" }, + { 0x17aa, 0x366c, "GeForce 615" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0df4[] = { + { 0x152d, 0x0952, "GeForce GT 630M" }, + { 0x152d, 0x0953, "GeForce GT 630M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0fd2[] = { + { 0x1028, 0x0595, "GeForce GT 640M LE" }, + { 0x1028, 0x05b2, "GeForce GT 640M LE" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_0fe3[] = { + { 0x103c, 0x2b16, "GeForce GT 745A" }, + { 0x17aa, 0x3675, "GeForce GT 745A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_104b[] = { + { 0x1043, 0x844c, "GeForce GT 625" }, + { 0x1043, 0x846b, "GeForce GT 625" }, + { 0x1462, 0xb590, "GeForce GT 625" }, + { 0x174b, 0x0625, "GeForce GT 625" }, + { 0x174b, 0xa625, "GeForce GT 625" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1058[] = { + { 0x103c, 0x2af1, "GeForce 610" }, + { 0x17aa, 0x3682, "GeForce 800A" }, + { 0x17aa, 0x3692, "GeForce 705A" }, + { 0x17aa, 0x3695, "GeForce 800A" }, + { 0x17aa, 0x36a8, "GeForce 800A" }, + { 0x17aa, 0x36ac, "GeForce 800A" }, + { 0x17aa, 0x36ad, "GeForce 800A" }, + { 0x705a, 0x3682, "GeForce 800A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_105b[] = { + { 0x103c, 0x2afb, "GeForce 705A" }, + { 0x17aa, 0x36a1, "GeForce 800A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1091[] = { + { 0x10de, 0x088e, "Tesla X2090" }, + { 0x10de, 0x0891, "Tesla X2090" }, + { 0x10de, 0x0974, "Tesla X2090" }, + { 0x10de, 0x098d, "Tesla X2090" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1096[] = { + { 0x10de, 0x0911, "Tesla C2050" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1140[] = { + { 0x1019, 0x999f, "GeForce GT 720M" }, + { 0x1025, 0x0600, "GeForce GT 620M" }, + { 0x1025, 0x0606, "GeForce GT 620M" }, + { 0x1025, 0x064a, "GeForce GT 620M" }, + { 0x1025, 0x064c, "GeForce GT 620M" }, + { 0x1025, 0x067a, "GeForce GT 620M" }, + { 0x1025, 0x0680, "GeForce GT 620M" }, + { 0x1025, 0x0686, "GeForce 710M" }, + { 0x1025, 0x0689, "GeForce 710M" }, + { 0x1025, 0x068b, "GeForce 710M" }, + { 0x1025, 0x068d, "GeForce 710M" }, + { 0x1025, 0x068e, "GeForce 710M" }, + { 0x1025, 0x0691, "GeForce 710M" }, + { 0x1025, 0x0692, "GeForce GT 620M" }, + { 0x1025, 0x0694, "GeForce GT 620M" }, + { 0x1025, 0x0702, "GeForce GT 620M" }, + { 0x1025, 0x0719, "GeForce GT 620M" }, + { 0x1025, 0x0725, "GeForce GT 620M" }, + { 0x1025, 0x0728, "GeForce GT 620M" }, + { 0x1025, 0x072b, "GeForce GT 620M" }, + { 0x1025, 0x072e, "GeForce GT 620M" }, + { 0x1025, 0x0732, "GeForce GT 620M" }, + { 0x1025, 0x0763, "GeForce GT 720M" }, + { 0x1025, 0x0773, "GeForce 710M" }, + { 0x1025, 0x0774, "GeForce 710M" }, + { 0x1025, 0x0776, "GeForce GT 720M" }, + { 0x1025, 0x077a, "GeForce 710M" }, + { 0x1025, 0x077b, "GeForce 710M" }, + { 0x1025, 0x077c, "GeForce 710M" }, + { 0x1025, 0x077d, "GeForce 710M" }, + { 0x1025, 0x077e, "GeForce 710M" }, + { 0x1025, 0x077f, "GeForce 710M" }, + { 0x1025, 0x0781, "GeForce GT 720M" }, + { 0x1025, 0x0798, "GeForce GT 720M" }, + { 0x1025, 0x0799, "GeForce GT 720M" }, + { 0x1025, 0x079b, "GeForce GT 720M" }, + { 0x1025, 0x079c, "GeForce GT 720M" }, + { 0x1025, 0x0807, "GeForce GT 720M" }, + { 0x1025, 0x0821, "GeForce 820M" }, + { 0x1025, 0x0823, "GeForce GT 720M" }, + { 0x1025, 0x0830, "GeForce GT 720M" }, + { 0x1025, 0x0833, "GeForce GT 720M" }, + { 0x1025, 0x0837, "GeForce GT 720M" }, + { 0x1025, 0x083e, "GeForce 820M" }, + { 0x1025, 0x0841, "GeForce 710M" }, + { 0x1025, 0x0853, "GeForce 820M" }, + { 0x1025, 0x0854, "GeForce 820M" }, + { 0x1025, 0x0855, "GeForce 820M" }, + { 0x1025, 0x0856, "GeForce 820M" }, + { 0x1025, 0x0857, "GeForce 820M" }, + { 0x1025, 0x0858, "GeForce 820M" }, + { 0x1025, 0x0863, "GeForce 820M" }, + { 0x1025, 0x0868, "GeForce 820M" }, + { 0x1025, 0x0869, "GeForce 810M" }, + { 0x1025, 0x0873, "GeForce 820M" }, + { 0x1025, 0x0878, "GeForce 820M" }, + { 0x1025, 0x087b, "GeForce 820M" }, + { 0x1025, 0x087f, "GeForce 820M" }, + { 0x1025, 0x0881, "GeForce 820M" }, + { 0x1025, 0x0885, "GeForce 820M" }, + { 0x1025, 0x088a, "GeForce 820M" }, + { 0x1025, 0x089b, "GeForce 820M" }, + { 0x1025, 0x0921, "GeForce 820M" }, + { 0x1025, 0x092e, "GeForce 810M" }, + { 0x1025, 0x092f, "GeForce 820M" }, + { 0x1025, 0x0932, "GeForce 820M" }, + { 0x1025, 0x093a, "GeForce 820M" }, + { 0x1025, 0x093c, "GeForce 820M" }, + { 0x1025, 0x093f, "GeForce 820M" }, + { 0x1025, 0x0941, "GeForce 820M" }, + { 0x1025, 0x0945, "GeForce 820M" }, + { 0x1025, 0x0954, "GeForce 820M" }, + { 0x1025, 0x0965, "GeForce 820M" }, + { 0x1028, 0x054d, "GeForce GT 630M" }, + { 0x1028, 0x054e, "GeForce GT 630M" }, + { 0x1028, 0x0554, "GeForce GT 620M" }, + { 0x1028, 0x0557, "GeForce GT 620M" }, + { 0x1028, 0x0562, "GeForce GT625M" }, + { 0x1028, 0x0565, "GeForce GT 630M" }, + { 0x1028, 0x0568, "GeForce GT 630M" }, + { 0x1028, 0x0590, "GeForce GT 630M" }, + { 0x1028, 0x0592, "GeForce GT625M" }, + { 0x1028, 0x0594, "GeForce GT625M" }, + { 0x1028, 0x0595, "GeForce GT625M" }, + { 0x1028, 0x05a2, "GeForce GT625M" }, + { 0x1028, 0x05b1, "GeForce GT625M" }, + { 0x1028, 0x05b3, "GeForce GT625M" }, + { 0x1028, 0x05da, "GeForce GT 630M" }, + { 0x1028, 0x05de, "GeForce GT 720M" }, + { 0x1028, 0x05e0, "GeForce GT 720M" }, + { 0x1028, 0x05e8, "GeForce GT 630M" }, + { 0x1028, 0x05f4, "GeForce GT 720M" }, + { 0x1028, 0x060f, "GeForce GT 720M" }, + { 0x1028, 0x062f, "GeForce GT 720M" }, + { 0x1028, 0x064e, "GeForce 820M" }, + { 0x1028, 0x0652, "GeForce 820M" }, + { 0x1028, 0x0653, "GeForce 820M" }, + { 0x1028, 0x0655, "GeForce 820M" }, + { 0x1028, 0x065e, "GeForce 820M" }, + { 0x1028, 0x0662, "GeForce 820M" }, + { 0x1028, 0x068d, "GeForce 820M" }, + { 0x1028, 0x06ad, "GeForce 820M" }, + { 0x1028, 0x06ae, "GeForce 820M" }, + { 0x1028, 0x06af, "GeForce 820M" }, + { 0x1028, 0x06b0, "GeForce 820M" }, + { 0x1028, 0x06c0, "GeForce 820M" }, + { 0x1028, 0x06c1, "GeForce 820M" }, + { 0x103c, 0x18ef, "GeForce GT 630M" }, + { 0x103c, 0x18f9, "GeForce GT 630M" }, + { 0x103c, 0x18fb, "GeForce GT 630M" }, + { 0x103c, 0x18fd, "GeForce GT 630M" }, + { 0x103c, 0x18ff, "GeForce GT 630M" }, + { 0x103c, 0x218a, "GeForce 820M" }, + { 0x103c, 0x21bb, "GeForce 820M" }, + { 0x103c, 0x21bc, "GeForce 820M" }, + { 0x103c, 0x220e, "GeForce 820M" }, + { 0x103c, 0x2210, "GeForce 820M" }, + { 0x103c, 0x2212, "GeForce 820M" }, + { 0x103c, 0x2214, "GeForce 820M" }, + { 0x103c, 0x2218, "GeForce 820M" }, + { 0x103c, 0x225b, "GeForce 820M" }, + { 0x103c, 0x225d, "GeForce 820M" }, + { 0x103c, 0x226d, "GeForce 820M" }, + { 0x103c, 0x226f, "GeForce 820M" }, + { 0x103c, 0x22d2, "GeForce 820M" }, + { 0x103c, 0x22d9, "GeForce 820M" }, + { 0x103c, 0x2335, "GeForce 820M" }, + { 0x103c, 0x2337, "GeForce 820M" }, + { 0x103c, 0x2aef, "GeForce GT 720A" }, + { 0x103c, 0x2af9, "GeForce 710A" }, + { 0x1043, 0x10dd, "NVS 5200M" }, + { 0x1043, 0x10ed, "NVS 5200M" }, + { 0x1043, 0x11fd, "GeForce GT 720M" }, + { 0x1043, 0x124d, "GeForce GT 720M" }, + { 0x1043, 0x126d, "GeForce GT 720M" }, + { 0x1043, 0x131d, "GeForce GT 720M" }, + { 0x1043, 0x13fd, "GeForce GT 720M" }, + { 0x1043, 0x14c7, "GeForce GT 720M" }, + { 0x1043, 0x1507, "GeForce GT 620M" }, + { 0x1043, 0x15ad, "GeForce 820M" }, + { 0x1043, 0x15ed, "GeForce 820M" }, + { 0x1043, 0x160d, "GeForce 820M" }, + { 0x1043, 0x163d, "GeForce 820M" }, + { 0x1043, 0x165d, "GeForce 820M" }, + { 0x1043, 0x166d, "GeForce 820M" }, + { 0x1043, 0x16cd, "GeForce 820M" }, + { 0x1043, 0x16dd, "GeForce 820M" }, + { 0x1043, 0x170d, "GeForce 820M" }, + { 0x1043, 0x176d, "GeForce 820M" }, + { 0x1043, 0x178d, "GeForce 820M" }, + { 0x1043, 0x179d, "GeForce 820M" }, + { 0x1043, 0x2132, "GeForce GT 620M" }, + { 0x1043, 0x2136, "NVS 5200M" }, + { 0x1043, 0x21ba, "GeForce GT 720M" }, + { 0x1043, 0x21fa, "GeForce GT 720M" }, + { 0x1043, 0x220a, "GeForce GT 720M" }, + { 0x1043, 0x221a, "GeForce GT 720M" }, + { 0x1043, 0x223a, "GeForce GT 710M" }, + { 0x1043, 0x224a, "GeForce GT 710M" }, + { 0x1043, 0x227a, "GeForce 820M" }, + { 0x1043, 0x228a, "GeForce 820M" }, + { 0x1043, 0x22fa, "GeForce 820M" }, + { 0x1043, 0x232a, "GeForce 820M" }, + { 0x1043, 0x233a, "GeForce 820M" }, + { 0x1043, 0x235a, "GeForce 820M" }, + { 0x1043, 0x236a, "GeForce 820M" }, + { 0x1043, 0x238a, "GeForce 820M" }, + { 0x1043, 0x8595, "GeForce GT 720M" }, + { 0x1043, 0x85ea, "GeForce GT 720M" }, + { 0x1043, 0x85eb, "GeForce 820M" }, + { 0x1043, 0x85ec, "GeForce 820M" }, + { 0x1043, 0x85ee, "GeForce GT 720M" }, + { 0x1043, 0x85f3, "GeForce 820M" }, + { 0x1043, 0x860e, "GeForce 820M" }, + { 0x1043, 0x861a, "GeForce 820M" }, + { 0x1043, 0x861b, "GeForce 820M" }, + { 0x1043, 0x8628, "GeForce 820M" }, + { 0x1043, 0x8643, "GeForce 820M" }, + { 0x1043, 0x864c, "GeForce 820M" }, + { 0x1043, 0x8652, "GeForce 820M" }, + { 0x1043, 0x8660, "GeForce 820M" }, + { 0x1043, 0x8661, "GeForce 820M" }, + { 0x105b, 0x0dac, "GeForce GT 720M" }, + { 0x105b, 0x0dad, "GeForce GT 720M" }, + { 0x105b, 0x0ef3, "GeForce GT 720M" }, + { 0x10cf, 0x17f5, "GeForce GT 720M" }, + { 0x1179, 0xfa01, "GeForce 710M" }, + { 0x1179, 0xfa02, "GeForce 710M" }, + { 0x1179, 0xfa03, "GeForce 710M" }, + { 0x1179, 0xfa05, "GeForce 710M" }, + { 0x1179, 0xfa11, "GeForce 710M" }, + { 0x1179, 0xfa13, "GeForce 710M" }, + { 0x1179, 0xfa18, "GeForce 710M" }, + { 0x1179, 0xfa19, "GeForce 710M" }, + { 0x1179, 0xfa21, "GeForce 710M" }, + { 0x1179, 0xfa23, "GeForce 710M" }, + { 0x1179, 0xfa2a, "GeForce 710M" }, + { 0x1179, 0xfa32, "GeForce 710M" }, + { 0x1179, 0xfa33, "GeForce 710M" }, + { 0x1179, 0xfa36, "GeForce 710M" }, + { 0x1179, 0xfa38, "GeForce 710M" }, + { 0x1179, 0xfa42, "GeForce 710M" }, + { 0x1179, 0xfa43, "GeForce 710M" }, + { 0x1179, 0xfa45, "GeForce 710M" }, + { 0x1179, 0xfa47, "GeForce 710M" }, + { 0x1179, 0xfa49, "GeForce 710M" }, + { 0x1179, 0xfa58, "GeForce 710M" }, + { 0x1179, 0xfa59, "GeForce 710M" }, + { 0x1179, 0xfa88, "GeForce 710M" }, + { 0x1179, 0xfa89, "GeForce 710M" }, + { 0x144d, 0xb092, "GeForce GT 620M" }, + { 0x144d, 0xc0d5, "GeForce GT 630M" }, + { 0x144d, 0xc0d7, "GeForce GT 620M" }, + { 0x144d, 0xc0e2, "NVS 5200M" }, + { 0x144d, 0xc0e3, "NVS 5200M" }, + { 0x144d, 0xc0e4, "NVS 5200M" }, + { 0x144d, 0xc10d, "GeForce 820M" }, + { 0x144d, 0xc652, "GeForce GT 620M" }, + { 0x144d, 0xc709, "GeForce 710M" }, + { 0x144d, 0xc711, "GeForce 710M" }, + { 0x144d, 0xc736, "GeForce 710M" }, + { 0x144d, 0xc737, "GeForce 710M" }, + { 0x144d, 0xc745, "GeForce 820M" }, + { 0x144d, 0xc750, "GeForce 820M" }, + { 0x1462, 0x10b8, "GeForce GT 710M" }, + { 0x1462, 0x10e9, "GeForce GT 720M" }, + { 0x1462, 0x1116, "GeForce 820M" }, + { 0x1462, 0xaa33, "GeForce 720M" }, + { 0x1462, 0xaaa2, "GeForce GT 720M" }, + { 0x1462, 0xaaa3, "GeForce 820M" }, + { 0x1462, 0xacb2, "GeForce GT 720M" }, + { 0x1462, 0xacc1, "GeForce GT 720M" }, + { 0x1462, 0xae61, "GeForce 720M" }, + { 0x1462, 0xae65, "GeForce GT 720M" }, + { 0x1462, 0xae6a, "GeForce 820M" }, + { 0x1462, 0xae71, "GeForce GT 720M" }, + { 0x14c0, 0x0083, "GeForce 820M" }, + { 0x152d, 0x0926, "GeForce 620M" }, + { 0x152d, 0x0982, "GeForce GT 630M" }, + { 0x152d, 0x0983, "GeForce GT 630M" }, + { 0x152d, 0x1005, "GeForce GT820M" }, + { 0x152d, 0x1012, "GeForce 710M" }, + { 0x152d, 0x1019, "GeForce 820M" }, + { 0x152d, 0x1030, "GeForce GT 630M" }, + { 0x152d, 0x1055, "GeForce 710M" }, + { 0x152d, 0x1067, "GeForce GT 720M" }, + { 0x152d, 0x1092, "GeForce 820M" }, + { 0x17aa, 0x2200, "NVS 5200M" }, + { 0x17aa, 0x2213, "GeForce GT 720M" }, + { 0x17aa, 0x2220, "GeForce GT 720M" }, + { 0x17aa, 0x309c, "GeForce GT 720A" }, + { 0x17aa, 0x30b4, "GeForce 820A" }, + { 0x17aa, 0x30b7, "GeForce 720A" }, + { 0x17aa, 0x30e4, "GeForce 820A" }, + { 0x17aa, 0x361b, "GeForce 820A" }, + { 0x17aa, 0x361c, "GeForce 820A" }, + { 0x17aa, 0x361d, "GeForce 820A" }, + { 0x17aa, 0x3656, "GeForce GT620M" }, + { 0x17aa, 0x365a, "GeForce 705M" }, + { 0x17aa, 0x365e, "GeForce 800M" }, + { 0x17aa, 0x3661, "GeForce 820A" }, + { 0x17aa, 0x366c, "GeForce 800M" }, + { 0x17aa, 0x3685, "GeForce 800M" }, + { 0x17aa, 0x3686, "GeForce 800M" }, + { 0x17aa, 0x3687, "GeForce 705A" }, + { 0x17aa, 0x3696, "GeForce 820A" }, + { 0x17aa, 0x369b, "GeForce 820A" }, + { 0x17aa, 0x369c, "GeForce 820A" }, + { 0x17aa, 0x369d, "GeForce 820A" }, + { 0x17aa, 0x369e, "GeForce 820A" }, + { 0x17aa, 0x36a6, "GeForce 820A" }, + { 0x17aa, 0x36a7, "GeForce 820A" }, + { 0x17aa, 0x36a9, "GeForce 820A" }, + { 0x17aa, 0x36af, "GeForce 820A" }, + { 0x17aa, 0x36b0, "GeForce 820A" }, + { 0x17aa, 0x36b6, "GeForce 820A" }, + { 0x17aa, 0x3800, "GeForce GT 720M" }, + { 0x17aa, 0x3801, "GeForce GT 720M" }, + { 0x17aa, 0x3802, "GeForce GT 720M" }, + { 0x17aa, 0x3803, "GeForce GT 720M" }, + { 0x17aa, 0x3804, "GeForce GT 720M" }, + { 0x17aa, 0x3806, "GeForce GT 720M" }, + { 0x17aa, 0x3808, "GeForce GT 720M" }, + { 0x17aa, 0x380d, "GeForce 820M" }, + { 0x17aa, 0x380e, "GeForce 820M" }, + { 0x17aa, 0x380f, "GeForce 820M" }, + { 0x17aa, 0x3811, "GeForce 820M" }, + { 0x17aa, 0x3812, "GeForce 820M" }, + { 0x17aa, 0x3813, "GeForce 820M" }, + { 0x17aa, 0x3816, "GeForce 820M" }, + { 0x17aa, 0x3817, "GeForce 820M" }, + { 0x17aa, 0x3818, "GeForce 820M" }, + { 0x17aa, 0x381a, "GeForce 820M" }, + { 0x17aa, 0x381c, "GeForce 820M" }, + { 0x17aa, 0x381d, "GeForce 820M" }, + { 0x17aa, 0x3901, "GeForce 610M" }, + { 0x17aa, 0x3902, "GeForce 710M" }, + { 0x17aa, 0x3903, "GeForce 710M" }, + { 0x17aa, 0x3904, "GeForce GT 625M" }, + { 0x17aa, 0x3905, "GeForce GT 720M" }, + { 0x17aa, 0x3907, "GeForce 820M" }, + { 0x17aa, 0x3910, "GeForce GT 720M" }, + { 0x17aa, 0x3912, "GeForce GT 720M" }, + { 0x17aa, 0x3913, "GeForce 820M" }, + { 0x17aa, 0x3915, "GeForce 820M" }, + { 0x17aa, 0x3983, "GeForce 610M" }, + { 0x17aa, 0x5001, "GeForce 610M" }, + { 0x17aa, 0x5003, "GeForce GT 720M" }, + { 0x17aa, 0x5005, "GeForce 705M" }, + { 0x17aa, 0x500d, "GeForce GT 620M" }, + { 0x17aa, 0x5014, "GeForce 710M" }, + { 0x17aa, 0x5017, "GeForce 710M" }, + { 0x17aa, 0x5019, "GeForce 710M" }, + { 0x17aa, 0x501a, "GeForce 710M" }, + { 0x17aa, 0x501f, "GeForce GT 720M" }, + { 0x17aa, 0x5025, "GeForce 710M" }, + { 0x17aa, 0x5027, "GeForce 710M" }, + { 0x17aa, 0x502a, "GeForce 710M" }, + { 0x17aa, 0x502b, "GeForce GT 720M" }, + { 0x17aa, 0x502d, "GeForce 710M" }, + { 0x17aa, 0x502e, "GeForce GT 720M" }, + { 0x17aa, 0x502f, "GeForce GT 720M" }, + { 0x17aa, 0x5030, "GeForce 705M" }, + { 0x17aa, 0x5031, "GeForce 705M" }, + { 0x17aa, 0x5032, "GeForce 820M" }, + { 0x17aa, 0x5033, "GeForce 820M" }, + { 0x17aa, 0x503e, "GeForce 710M" }, + { 0x17aa, 0x503f, "GeForce 820M" }, + { 0x17aa, 0x5040, "GeForce 820M" }, + { 0x1854, 0x0177, "GeForce 710M" }, + { 0x1854, 0x0180, "GeForce 710M" }, + { 0x1854, 0x0190, "GeForce GT 720M" }, + { 0x1854, 0x0192, "GeForce GT 720M" }, + { 0x1854, 0x0224, "GeForce 820M" }, + { 0x1b0a, 0x20dd, "GeForce GT 620M" }, + { 0x1b0a, 0x20df, "GeForce GT 620M" }, + { 0x1b0a, 0x210e, "GeForce 820M" }, + { 0x1b0a, 0x2202, "GeForce GT 720M" }, + { 0x1b0a, 0x90d7, "GeForce 820M" }, + { 0x1b0a, 0x90dd, "GeForce 820M" }, + { 0x1b50, 0x5530, "GeForce 820M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1185[] = { + { 0x10de, 0x106f, "GeForce GTX 760" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1189[] = { + { 0x10de, 0x1074, "GeForce GTX 760 Ti OEM" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1199[] = { + { 0x1458, 0xd001, "GeForce GTX 760" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_11e3[] = { + { 0x17aa, 0x3683, "GeForce GTX 760A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_11fc[] = { + { 0x17aa, 0x2211, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ + { 0x17aa, 0x221e, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1247[] = { + { 0x1043, 0x212a, "GeForce GT 635M" }, + { 0x1043, 0x212b, "GeForce GT 635M" }, + { 0x1043, 0x212c, "GeForce GT 635M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_124d[] = { + { 0x1462, 0x10cc, "GeForce GT 635M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1290[] = { + { 0x103c, 0x2afa, "GeForce 730A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1292[] = { + { 0x17aa, 0x3675, "GeForce GT 740A" }, + { 0x17aa, 0x367c, "GeForce GT 740A" }, + { 0x17aa, 0x3684, "GeForce GT 740A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1295[] = { + { 0x103c, 0x2b0d, "GeForce 710A" }, + { 0x103c, 0x2b0f, "GeForce 710A" }, + { 0x103c, 0x2b20, "GeForce 810A" }, + { 0x103c, 0x2b21, "GeForce 810A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1299[] = { + { 0x17aa, 0x369b, "GeForce 920A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1340[] = { + { 0x103c, 0x2b2b, "GeForce 830A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1341[] = { + { 0x17aa, 0x3697, "GeForce 840A" }, + { 0x17aa, 0x3699, "GeForce 840A" }, + { 0x17aa, 0x369c, "GeForce 840A" }, + { 0x17aa, 0x36af, "GeForce 840A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1346[] = { + { 0x17aa, 0x30ba, "GeForce 930A" }, + { 0x17aa, 0x362c, "GeForce 930A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1347[] = { + { 0x17aa, 0x36b9, "GeForce 940A" }, + { 0x17aa, 0x36ba, "GeForce 940A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_137a[] = { + { 0x17aa, 0x2225, "Quadro K620M" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_137d[] = { + { 0x17aa, 0x3699, "GeForce 940A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1391[] = { + { 0x17aa, 0x3697, "GeForce GTX 850A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_1392[] = { + { 0x1028, 0x066a, "GeForce GPU" }, + { 0x1043, 0x861e, "GeForce GTX 750 Ti" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_139a[] = { + { 0x17aa, 0x36b9, "GeForce GTX 950A" }, + {} +}; + +static const struct nvkm_device_pci_vendor +nvkm_device_pci_10de_139b[] = { + { 0x1028, 0x06a3, "GeForce GTX 860M" }, + { 0x19da, 0xc248, "GeForce GTX 750 Ti" }, + {} +}; + +static const struct nvkm_device_pci_device +nvkm_device_pci_10de[] = { + { 0x0020, "RIVA TNT" }, + { 0x0028, "RIVA TNT2/TNT2 Pro" }, + { 0x0029, "RIVA TNT2 Ultra" }, + { 0x002c, "Vanta/Vanta LT" }, + { 0x002d, "RIVA TNT2 Model 64/Model 64 Pro" }, + { 0x0040, "GeForce 6800 Ultra" }, + { 0x0041, "GeForce 6800" }, + { 0x0042, "GeForce 6800 LE" }, + { 0x0043, "GeForce 6800 XE" }, + { 0x0044, "GeForce 6800 XT" }, + { 0x0045, "GeForce 6800 GT" }, + { 0x0046, "GeForce 6800 GT" }, + { 0x0047, "GeForce 6800 GS" }, + { 0x0048, "GeForce 6800 XT" }, + { 0x004e, "Quadro FX 4000" }, + { 0x0090, "GeForce 7800 GTX" }, + { 0x0091, "GeForce 7800 GTX" }, + { 0x0092, "GeForce 7800 GT" }, + { 0x0093, "GeForce 7800 GS" }, + { 0x0095, "GeForce 7800 SLI" }, + { 0x0098, "GeForce Go 7800" }, + { 0x0099, "GeForce Go 7800 GTX" }, + { 0x009d, "Quadro FX 4500" }, + { 0x00a0, "Aladdin TNT2" }, + { 0x00c0, "GeForce 6800 GS" }, + { 0x00c1, "GeForce 6800" }, + { 0x00c2, "GeForce 6800 LE" }, + { 0x00c3, "GeForce 6800 XT" }, + { 0x00c8, "GeForce Go 6800" }, + { 0x00c9, "GeForce Go 6800 Ultra" }, + { 0x00cc, "Quadro FX Go1400" }, + { 0x00cd, "Quadro FX 3450/4000 SDI" }, + { 0x00ce, "Quadro FX 1400" }, + { 0x00f1, "GeForce 6600 GT" }, + { 0x00f2, "GeForce 6600" }, + { 0x00f3, "GeForce 6200" }, + { 0x00f4, "GeForce 6600 LE" }, + { 0x00f5, "GeForce 7800 GS" }, + { 0x00f6, "GeForce 6800 GS" }, + { 0x00f8, "Quadro FX 3400/Quadro FX 4000" }, + { 0x00f9, "GeForce 6800 Ultra" }, + { 0x00fa, "GeForce PCX 5750" }, + { 0x00fb, "GeForce PCX 5900" }, + { 0x00fc, "Quadro FX 330/GeForce PCX 5300" }, + { 0x00fd, "Quadro FX 330/Quadro NVS 280 PCI-E" }, + { 0x00fe, "Quadro FX 1300" }, + { 0x0100, "GeForce 256" }, + { 0x0101, "GeForce DDR" }, + { 0x0103, "Quadro" }, + { 0x0110, "GeForce2 MX/MX 400" }, + { 0x0111, "GeForce2 MX 100/200" }, + { 0x0112, "GeForce2 Go" }, + { 0x0113, "Quadro2 MXR/EX/Go" }, + { 0x0140, "GeForce 6600 GT" }, + { 0x0141, "GeForce 6600" }, + { 0x0142, "GeForce 6600 LE" }, + { 0x0143, "GeForce 6600 VE" }, + { 0x0144, "GeForce Go 6600" }, + { 0x0145, "GeForce 6610 XL" }, + { 0x0146, "GeForce Go 6600 TE/6200 TE" }, + { 0x0147, "GeForce 6700 XL" }, + { 0x0148, "GeForce Go 6600" }, + { 0x0149, "GeForce Go 6600 GT" }, + { 0x014a, "Quadro NVS 440" }, + { 0x014c, "Quadro FX 540M" }, + { 0x014d, "Quadro FX 550" }, + { 0x014e, "Quadro FX 540" }, + { 0x014f, "GeForce 6200" }, + { 0x0150, "GeForce2 GTS/GeForce2 Pro" }, + { 0x0151, "GeForce2 Ti" }, + { 0x0152, "GeForce2 Ultra" }, + { 0x0153, "Quadro2 Pro" }, + { 0x0160, "GeForce 6500" }, + { 0x0161, "GeForce 6200 TurboCache(TM)" }, + { 0x0162, "GeForce 6200SE TurboCache(TM)" }, + { 0x0163, "GeForce 6200 LE" }, + { 0x0164, "GeForce Go 6200" }, + { 0x0165, "Quadro NVS 285" }, + { 0x0166, "GeForce Go 6400" }, + { 0x0167, "GeForce Go 6200" }, + { 0x0168, "GeForce Go 6400" }, + { 0x0169, "GeForce 6250" }, + { 0x016a, "GeForce 7100 GS" }, + { 0x0170, "GeForce4 MX 460" }, + { 0x0171, "GeForce4 MX 440" }, + { 0x0172, "GeForce4 MX 420" }, + { 0x0173, "GeForce4 MX 440-SE" }, + { 0x0174, "GeForce4 440 Go" }, + { 0x0175, "GeForce4 420 Go" }, + { 0x0176, "GeForce4 420 Go 32M" }, + { 0x0177, "GeForce4 460 Go" }, + { 0x0178, "Quadro4 550 XGL" }, + { 0x0179, "GeForce4 440 Go 64M" }, + { 0x017a, "Quadro NVS 400" }, + { 0x017c, "Quadro4 500 GoGL" }, + { 0x017d, "GeForce4 410 Go 16M" }, + { 0x0181, "GeForce4 MX 440 with AGP8X" }, + { 0x0182, "GeForce4 MX 440SE with AGP8X" }, + { 0x0183, "GeForce4 MX 420 with AGP8X" }, + { 0x0185, "GeForce4 MX 4000" }, + { 0x0188, "Quadro4 580 XGL" }, + { 0x0189, "GeForce4 MX with AGP8X (Mac)", nvkm_device_pci_10de_0189 }, + { 0x018a, "Quadro NVS 280 SD" }, + { 0x018b, "Quadro4 380 XGL" }, + { 0x018c, "Quadro NVS 50 PCI" }, + { 0x0191, "GeForce 8800 GTX" }, + { 0x0193, "GeForce 8800 GTS" }, + { 0x0194, "GeForce 8800 Ultra" }, + { 0x0197, "Tesla C870" }, + { 0x019d, "Quadro FX 5600" }, + { 0x019e, "Quadro FX 4600" }, + { 0x01a0, "GeForce2 Integrated GPU" }, + { 0x01d0, "GeForce 7350 LE" }, + { 0x01d1, "GeForce 7300 LE" }, + { 0x01d2, "GeForce 7550 LE" }, + { 0x01d3, "GeForce 7300 SE/7200 GS" }, + { 0x01d6, "GeForce Go 7200" }, + { 0x01d7, "GeForce Go 7300" }, + { 0x01d8, "GeForce Go 7400" }, + { 0x01da, "Quadro NVS 110M" }, + { 0x01db, "Quadro NVS 120M" }, + { 0x01dc, "Quadro FX 350M" }, + { 0x01dd, "GeForce 7500 LE" }, + { 0x01de, "Quadro FX 350" }, + { 0x01df, "GeForce 7300 GS" }, + { 0x01f0, "GeForce4 MX Integrated GPU", nvkm_device_pci_10de_01f0 }, + { 0x0200, "GeForce3" }, + { 0x0201, "GeForce3 Ti 200" }, + { 0x0202, "GeForce3 Ti 500" }, + { 0x0203, "Quadro DCC" }, + { 0x0211, "GeForce 6800" }, + { 0x0212, "GeForce 6800 LE" }, + { 0x0215, "GeForce 6800 GT" }, + { 0x0218, "GeForce 6800 XT" }, + { 0x0221, "GeForce 6200" }, + { 0x0222, "GeForce 6200 A-LE" }, + { 0x0240, "GeForce 6150" }, + { 0x0241, "GeForce 6150 LE" }, + { 0x0242, "GeForce 6100" }, + { 0x0244, "GeForce Go 6150" }, + { 0x0245, "Quadro NVS 210S / GeForce 6150LE" }, + { 0x0247, "GeForce Go 6100" }, + { 0x0250, "GeForce4 Ti 4600" }, + { 0x0251, "GeForce4 Ti 4400" }, + { 0x0253, "GeForce4 Ti 4200" }, + { 0x0258, "Quadro4 900 XGL" }, + { 0x0259, "Quadro4 750 XGL" }, + { 0x025b, "Quadro4 700 XGL" }, + { 0x0280, "GeForce4 Ti 4800" }, + { 0x0281, "GeForce4 Ti 4200 with AGP8X" }, + { 0x0282, "GeForce4 Ti 4800 SE" }, + { 0x0286, "GeForce4 4200 Go" }, + { 0x0288, "Quadro4 980 XGL" }, + { 0x0289, "Quadro4 780 XGL" }, + { 0x028c, "Quadro4 700 GoGL" }, + { 0x0290, "GeForce 7900 GTX" }, + { 0x0291, "GeForce 7900 GT/GTO" }, + { 0x0292, "GeForce 7900 GS" }, + { 0x0293, "GeForce 7950 GX2" }, + { 0x0294, "GeForce 7950 GX2" }, + { 0x0295, "GeForce 7950 GT" }, + { 0x0297, "GeForce Go 7950 GTX" }, + { 0x0298, "GeForce Go 7900 GS" }, + { 0x0299, "Quadro NVS 510M" }, + { 0x029a, "Quadro FX 2500M" }, + { 0x029b, "Quadro FX 1500M" }, + { 0x029c, "Quadro FX 5500" }, + { 0x029d, "Quadro FX 3500" }, + { 0x029e, "Quadro FX 1500" }, + { 0x029f, "Quadro FX 4500 X2" }, + { 0x02e0, "GeForce 7600 GT" }, + { 0x02e1, "GeForce 7600 GS" }, + { 0x02e2, "GeForce 7300 GT" }, + { 0x02e3, "GeForce 7900 GS" }, + { 0x02e4, "GeForce 7950 GT" }, + { 0x0301, "GeForce FX 5800 Ultra" }, + { 0x0302, "GeForce FX 5800" }, + { 0x0308, "Quadro FX 2000" }, + { 0x0309, "Quadro FX 1000" }, + { 0x0311, "GeForce FX 5600 Ultra" }, + { 0x0312, "GeForce FX 5600" }, + { 0x0314, "GeForce FX 5600XT" }, + { 0x031a, "GeForce FX Go5600" }, + { 0x031b, "GeForce FX Go5650" }, + { 0x031c, "Quadro FX Go700" }, + { 0x0320, "GeForce FX 5200" }, + { 0x0321, "GeForce FX 5200 Ultra" }, + { 0x0322, "GeForce FX 5200", nvkm_device_pci_10de_0322 }, + { 0x0323, "GeForce FX 5200LE" }, + { 0x0324, "GeForce FX Go5200" }, + { 0x0325, "GeForce FX Go5250" }, + { 0x0326, "GeForce FX 5500" }, + { 0x0327, "GeForce FX 5100" }, + { 0x0328, "GeForce FX Go5200 32M/64M" }, + { 0x032a, "Quadro NVS 55/280 PCI" }, + { 0x032b, "Quadro FX 500/FX 600" }, + { 0x032c, "GeForce FX Go53xx" }, + { 0x032d, "GeForce FX Go5100" }, + { 0x0330, "GeForce FX 5900 Ultra" }, + { 0x0331, "GeForce FX 5900" }, + { 0x0332, "GeForce FX 5900XT" }, + { 0x0333, "GeForce FX 5950 Ultra" }, + { 0x0334, "GeForce FX 5900ZT" }, + { 0x0338, "Quadro FX 3000" }, + { 0x033f, "Quadro FX 700" }, + { 0x0341, "GeForce FX 5700 Ultra" }, + { 0x0342, "GeForce FX 5700" }, + { 0x0343, "GeForce FX 5700LE" }, + { 0x0344, "GeForce FX 5700VE" }, + { 0x0347, "GeForce FX Go5700" }, + { 0x0348, "GeForce FX Go5700" }, + { 0x034c, "Quadro FX Go1000" }, + { 0x034e, "Quadro FX 1100" }, + { 0x038b, "GeForce 7650 GS" }, + { 0x0390, "GeForce 7650 GS" }, + { 0x0391, "GeForce 7600 GT" }, + { 0x0392, "GeForce 7600 GS" }, + { 0x0393, "GeForce 7300 GT" }, + { 0x0394, "GeForce 7600 LE" }, + { 0x0395, "GeForce 7300 GT" }, + { 0x0397, "GeForce Go 7700" }, + { 0x0398, "GeForce Go 7600" }, + { 0x0399, "GeForce Go 7600 GT" }, + { 0x039c, "Quadro FX 560M" }, + { 0x039e, "Quadro FX 560" }, + { 0x03d0, "GeForce 6150SE nForce 430" }, + { 0x03d1, "GeForce 6100 nForce 405" }, + { 0x03d2, "GeForce 6100 nForce 400" }, + { 0x03d5, "GeForce 6100 nForce 420" }, + { 0x03d6, "GeForce 7025 / nForce 630a" }, + { 0x0400, "GeForce 8600 GTS" }, + { 0x0401, "GeForce 8600 GT" }, + { 0x0402, "GeForce 8600 GT" }, + { 0x0403, "GeForce 8600 GS" }, + { 0x0404, "GeForce 8400 GS" }, + { 0x0405, "GeForce 9500M GS" }, + { 0x0406, "GeForce 8300 GS" }, + { 0x0407, "GeForce 8600M GT" }, + { 0x0408, "GeForce 9650M GS" }, + { 0x0409, "GeForce 8700M GT" }, + { 0x040a, "Quadro FX 370" }, + { 0x040b, "Quadro NVS 320M" }, + { 0x040c, "Quadro FX 570M" }, + { 0x040d, "Quadro FX 1600M" }, + { 0x040e, "Quadro FX 570" }, + { 0x040f, "Quadro FX 1700" }, + { 0x0410, "GeForce GT 330" }, + { 0x0420, "GeForce 8400 SE" }, + { 0x0421, "GeForce 8500 GT" }, + { 0x0422, "GeForce 8400 GS" }, + { 0x0423, "GeForce 8300 GS" }, + { 0x0424, "GeForce 8400 GS" }, + { 0x0425, "GeForce 8600M GS" }, + { 0x0426, "GeForce 8400M GT" }, + { 0x0427, "GeForce 8400M GS" }, + { 0x0428, "GeForce 8400M G" }, + { 0x0429, "Quadro NVS 140M" }, + { 0x042a, "Quadro NVS 130M" }, + { 0x042b, "Quadro NVS 135M" }, + { 0x042c, "GeForce 9400 GT" }, + { 0x042d, "Quadro FX 360M" }, + { 0x042e, "GeForce 9300M G" }, + { 0x042f, "Quadro NVS 290" }, + { 0x0531, "GeForce 7150M / nForce 630M" }, + { 0x0533, "GeForce 7000M / nForce 610M" }, + { 0x053a, "GeForce 7050 PV / nForce 630a" }, + { 0x053b, "GeForce 7050 PV / nForce 630a" }, + { 0x053e, "GeForce 7025 / nForce 630a" }, + { 0x05e0, "GeForce GTX 295" }, + { 0x05e1, "GeForce GTX 280" }, + { 0x05e2, "GeForce GTX 260" }, + { 0x05e3, "GeForce GTX 285" }, + { 0x05e6, "GeForce GTX 275" }, + { 0x05e7, "Tesla C1060", nvkm_device_pci_10de_05e7 }, + { 0x05ea, "GeForce GTX 260" }, + { 0x05eb, "GeForce GTX 295" }, + { 0x05ed, "Quadroplex 2200 D2" }, + { 0x05f8, "Quadroplex 2200 S4" }, + { 0x05f9, "Quadro CX" }, + { 0x05fd, "Quadro FX 5800" }, + { 0x05fe, "Quadro FX 4800" }, + { 0x05ff, "Quadro FX 3800" }, + { 0x0600, "GeForce 8800 GTS 512" }, + { 0x0601, "GeForce 9800 GT" }, + { 0x0602, "GeForce 8800 GT" }, + { 0x0603, "GeForce GT 230" }, + { 0x0604, "GeForce 9800 GX2" }, + { 0x0605, "GeForce 9800 GT" }, + { 0x0606, "GeForce 8800 GS" }, + { 0x0607, "GeForce GTS 240" }, + { 0x0608, "GeForce 9800M GTX" }, + { 0x0609, "GeForce 8800M GTS", nvkm_device_pci_10de_0609 }, + { 0x060a, "GeForce GTX 280M" }, + { 0x060b, "GeForce 9800M GT" }, + { 0x060c, "GeForce 8800M GTX" }, + { 0x060d, "GeForce 8800 GS" }, + { 0x060f, "GeForce GTX 285M" }, + { 0x0610, "GeForce 9600 GSO" }, + { 0x0611, "GeForce 8800 GT" }, + { 0x0612, "GeForce 9800 GTX/9800 GTX+" }, + { 0x0613, "GeForce 9800 GTX+" }, + { 0x0614, "GeForce 9800 GT" }, + { 0x0615, "GeForce GTS 250" }, + { 0x0617, "GeForce 9800M GTX" }, + { 0x0618, "GeForce GTX 260M" }, + { 0x0619, "Quadro FX 4700 X2" }, + { 0x061a, "Quadro FX 3700" }, + { 0x061b, "Quadro VX 200" }, + { 0x061c, "Quadro FX 3600M" }, + { 0x061d, "Quadro FX 2800M" }, + { 0x061e, "Quadro FX 3700M" }, + { 0x061f, "Quadro FX 3800M" }, + { 0x0621, "GeForce GT 230" }, + { 0x0622, "GeForce 9600 GT" }, + { 0x0623, "GeForce 9600 GS" }, + { 0x0625, "GeForce 9600 GSO 512" }, + { 0x0626, "GeForce GT 130" }, + { 0x0627, "GeForce GT 140" }, + { 0x0628, "GeForce 9800M GTS" }, + { 0x062a, "GeForce 9700M GTS" }, + { 0x062b, "GeForce 9800M GS" }, + { 0x062c, "GeForce 9800M GTS" }, + { 0x062d, "GeForce 9600 GT" }, + { 0x062e, "GeForce 9600 GT", nvkm_device_pci_10de_062e }, + { 0x0630, "GeForce 9700 S" }, + { 0x0631, "GeForce GTS 160M" }, + { 0x0632, "GeForce GTS 150M" }, + { 0x0635, "GeForce 9600 GSO" }, + { 0x0637, "GeForce 9600 GT" }, + { 0x0638, "Quadro FX 1800" }, + { 0x063a, "Quadro FX 2700M" }, + { 0x0640, "GeForce 9500 GT" }, + { 0x0641, "GeForce 9400 GT" }, + { 0x0643, "GeForce 9500 GT" }, + { 0x0644, "GeForce 9500 GS" }, + { 0x0645, "GeForce 9500 GS" }, + { 0x0646, "GeForce GT 120" }, + { 0x0647, "GeForce 9600M GT" }, + { 0x0648, "GeForce 9600M GS" }, + { 0x0649, "GeForce 9600M GT", nvkm_device_pci_10de_0649 }, + { 0x064a, "GeForce 9700M GT" }, + { 0x064b, "GeForce 9500M G" }, + { 0x064c, "GeForce 9650M GT" }, + { 0x0651, "GeForce G 110M" }, + { 0x0652, "GeForce GT 130M", nvkm_device_pci_10de_0652 }, + { 0x0653, "GeForce GT 120M" }, + { 0x0654, "GeForce GT 220M", nvkm_device_pci_10de_0654 }, + { 0x0655, NULL, nvkm_device_pci_10de_0655 }, + { 0x0656, NULL, nvkm_device_pci_10de_0656 }, + { 0x0658, "Quadro FX 380" }, + { 0x0659, "Quadro FX 580" }, + { 0x065a, "Quadro FX 1700M" }, + { 0x065b, "GeForce 9400 GT" }, + { 0x065c, "Quadro FX 770M" }, + { 0x06c0, "GeForce GTX 480" }, + { 0x06c4, "GeForce GTX 465" }, + { 0x06ca, "GeForce GTX 480M" }, + { 0x06cd, "GeForce GTX 470" }, + { 0x06d1, "Tesla C2050 / C2070", nvkm_device_pci_10de_06d1 }, + { 0x06d2, "Tesla M2070", nvkm_device_pci_10de_06d2 }, + { 0x06d8, "Quadro 6000" }, + { 0x06d9, "Quadro 5000" }, + { 0x06da, "Quadro 5000M" }, + { 0x06dc, "Quadro 6000" }, + { 0x06dd, "Quadro 4000" }, + { 0x06de, "Tesla T20 Processor", nvkm_device_pci_10de_06de }, + { 0x06df, "Tesla M2070-Q" }, + { 0x06e0, "GeForce 9300 GE" }, + { 0x06e1, "GeForce 9300 GS" }, + { 0x06e2, "GeForce 8400" }, + { 0x06e3, "GeForce 8400 SE" }, + { 0x06e4, "GeForce 8400 GS" }, + { 0x06e5, "GeForce 9300M GS" }, + { 0x06e6, "GeForce G100" }, + { 0x06e7, "GeForce 9300 SE" }, + { 0x06e8, "GeForce 9200M GS", nvkm_device_pci_10de_06e8 }, + { 0x06e9, "GeForce 9300M GS" }, + { 0x06ea, "Quadro NVS 150M" }, + { 0x06eb, "Quadro NVS 160M" }, + { 0x06ec, "GeForce G 105M" }, + { 0x06ef, "GeForce G 103M" }, + { 0x06f1, "GeForce G105M" }, + { 0x06f8, "Quadro NVS 420" }, + { 0x06f9, "Quadro FX 370 LP", nvkm_device_pci_10de_06f9 }, + { 0x06fa, "Quadro NVS 450" }, + { 0x06fb, "Quadro FX 370M" }, + { 0x06fd, "Quadro NVS 295" }, + { 0x06ff, "HICx16 + Graphics", nvkm_device_pci_10de_06ff }, + { 0x07e0, "GeForce 7150 / nForce 630i" }, + { 0x07e1, "GeForce 7100 / nForce 630i" }, + { 0x07e2, "GeForce 7050 / nForce 630i" }, + { 0x07e3, "GeForce 7050 / nForce 610i" }, + { 0x07e5, "GeForce 7050 / nForce 620i" }, + { 0x0840, "GeForce 8200M" }, + { 0x0844, "GeForce 9100M G" }, + { 0x0845, "GeForce 8200M G" }, + { 0x0846, "GeForce 9200" }, + { 0x0847, "GeForce 9100" }, + { 0x0848, "GeForce 8300" }, + { 0x0849, "GeForce 8200" }, + { 0x084a, "nForce 730a" }, + { 0x084b, "GeForce 9200" }, + { 0x084c, "nForce 980a/780a SLI" }, + { 0x084d, "nForce 750a SLI" }, + { 0x084f, "GeForce 8100 / nForce 720a" }, + { 0x0860, "GeForce 9400" }, + { 0x0861, "GeForce 9400" }, + { 0x0862, "GeForce 9400M G" }, + { 0x0863, "GeForce 9400M" }, + { 0x0864, "GeForce 9300" }, + { 0x0865, "ION" }, + { 0x0866, "GeForce 9400M G", nvkm_device_pci_10de_0866 }, + { 0x0867, "GeForce 9400" }, + { 0x0868, "nForce 760i SLI" }, + { 0x0869, "GeForce 9400" }, + { 0x086a, "GeForce 9400" }, + { 0x086c, "GeForce 9300 / nForce 730i" }, + { 0x086d, "GeForce 9200" }, + { 0x086e, "GeForce 9100M G" }, + { 0x086f, "GeForce 8200M G" }, + { 0x0870, "GeForce 9400M" }, + { 0x0871, "GeForce 9200" }, + { 0x0872, "GeForce G102M", nvkm_device_pci_10de_0872 }, + { 0x0873, "GeForce G102M", nvkm_device_pci_10de_0873 }, + { 0x0874, "ION" }, + { 0x0876, "ION" }, + { 0x087a, "GeForce 9400" }, + { 0x087d, "ION" }, + { 0x087e, "ION LE" }, + { 0x087f, "ION LE" }, + { 0x08a0, "GeForce 320M" }, + { 0x08a2, "GeForce 320M" }, + { 0x08a3, "GeForce 320M" }, + { 0x08a4, "GeForce 320M" }, + { 0x08a5, "GeForce 320M" }, + { 0x0a20, "GeForce GT 220" }, + { 0x0a22, "GeForce 315" }, + { 0x0a23, "GeForce 210" }, + { 0x0a26, "GeForce 405" }, + { 0x0a27, "GeForce 405" }, + { 0x0a28, "GeForce GT 230M" }, + { 0x0a29, "GeForce GT 330M" }, + { 0x0a2a, "GeForce GT 230M" }, + { 0x0a2b, "GeForce GT 330M" }, + { 0x0a2c, "NVS 5100M" }, + { 0x0a2d, "GeForce GT 320M" }, + { 0x0a32, "GeForce GT 415" }, + { 0x0a34, "GeForce GT 240M" }, + { 0x0a35, "GeForce GT 325M" }, + { 0x0a38, "Quadro 400" }, + { 0x0a3c, "Quadro FX 880M" }, + { 0x0a60, "GeForce G210" }, + { 0x0a62, "GeForce 205" }, + { 0x0a63, "GeForce 310" }, + { 0x0a64, "Second Generation ION" }, + { 0x0a65, "GeForce 210" }, + { 0x0a66, "GeForce 310" }, + { 0x0a67, "GeForce 315" }, + { 0x0a68, "GeForce G105M" }, + { 0x0a69, "GeForce G105M" }, + { 0x0a6a, "NVS 2100M" }, + { 0x0a6c, "NVS 3100M" }, + { 0x0a6e, "GeForce 305M", nvkm_device_pci_10de_0a6e }, + { 0x0a6f, "Second Generation ION" }, + { 0x0a70, "GeForce 310M", nvkm_device_pci_10de_0a70 }, + { 0x0a71, "GeForce 305M" }, + { 0x0a72, "GeForce 310M" }, + { 0x0a73, "GeForce 305M", nvkm_device_pci_10de_0a73 }, + { 0x0a74, "GeForce G210M", nvkm_device_pci_10de_0a74 }, + { 0x0a75, "GeForce 310M", nvkm_device_pci_10de_0a75 }, + { 0x0a76, "Second Generation ION" }, + { 0x0a78, "Quadro FX 380 LP" }, + { 0x0a7a, "GeForce 315M", nvkm_device_pci_10de_0a7a }, + { 0x0a7c, "Quadro FX 380M" }, + { 0x0ca0, "GeForce GT 330" }, + { 0x0ca2, "GeForce GT 320" }, + { 0x0ca3, "GeForce GT 240" }, + { 0x0ca4, "GeForce GT 340" }, + { 0x0ca5, "GeForce GT 220" }, + { 0x0ca7, "GeForce GT 330" }, + { 0x0ca8, "GeForce GTS 260M" }, + { 0x0ca9, "GeForce GTS 250M" }, + { 0x0cac, "GeForce GT 220" }, + { 0x0caf, "GeForce GT 335M" }, + { 0x0cb0, "GeForce GTS 350M" }, + { 0x0cb1, "GeForce GTS 360M" }, + { 0x0cbc, "Quadro FX 1800M" }, + { 0x0dc0, "GeForce GT 440" }, + { 0x0dc4, "GeForce GTS 450" }, + { 0x0dc5, "GeForce GTS 450" }, + { 0x0dc6, "GeForce GTS 450" }, + { 0x0dcd, "GeForce GT 555M" }, + { 0x0dce, "GeForce GT 555M" }, + { 0x0dd1, "GeForce GTX 460M" }, + { 0x0dd2, "GeForce GT 445M" }, + { 0x0dd3, "GeForce GT 435M" }, + { 0x0dd6, "GeForce GT 550M" }, + { 0x0dd8, "Quadro 2000", nvkm_device_pci_10de_0dd8 }, + { 0x0dda, "Quadro 2000M" }, + { 0x0de0, "GeForce GT 440" }, + { 0x0de1, "GeForce GT 430" }, + { 0x0de2, "GeForce GT 420" }, + { 0x0de3, "GeForce GT 635M" }, + { 0x0de4, "GeForce GT 520" }, + { 0x0de5, "GeForce GT 530" }, + { 0x0de7, "GeForce GT 610" }, + { 0x0de8, "GeForce GT 620M" }, + { 0x0de9, "GeForce GT 630M", nvkm_device_pci_10de_0de9 }, + { 0x0dea, "GeForce 610M", nvkm_device_pci_10de_0dea }, + { 0x0deb, "GeForce GT 555M" }, + { 0x0dec, "GeForce GT 525M" }, + { 0x0ded, "GeForce GT 520M" }, + { 0x0dee, "GeForce GT 415M" }, + { 0x0def, "NVS 5400M" }, + { 0x0df0, "GeForce GT 425M" }, + { 0x0df1, "GeForce GT 420M" }, + { 0x0df2, "GeForce GT 435M" }, + { 0x0df3, "GeForce GT 420M" }, + { 0x0df4, "GeForce GT 540M", nvkm_device_pci_10de_0df4 }, + { 0x0df5, "GeForce GT 525M" }, + { 0x0df6, "GeForce GT 550M" }, + { 0x0df7, "GeForce GT 520M" }, + { 0x0df8, "Quadro 600" }, + { 0x0df9, "Quadro 500M" }, + { 0x0dfa, "Quadro 1000M" }, + { 0x0dfc, "NVS 5200M" }, + { 0x0e22, "GeForce GTX 460" }, + { 0x0e23, "GeForce GTX 460 SE" }, + { 0x0e24, "GeForce GTX 460" }, + { 0x0e30, "GeForce GTX 470M" }, + { 0x0e31, "GeForce GTX 485M" }, + { 0x0e3a, "Quadro 3000M" }, + { 0x0e3b, "Quadro 4000M" }, + { 0x0f00, "GeForce GT 630" }, + { 0x0f01, "GeForce GT 620" }, + { 0x0f02, "GeForce GT 730" }, + { 0x0fc0, "GeForce GT 640" }, + { 0x0fc1, "GeForce GT 640" }, + { 0x0fc2, "GeForce GT 630" }, + { 0x0fc6, "GeForce GTX 650" }, + { 0x0fc8, "GeForce GT 740" }, + { 0x0fc9, "GeForce GT 730" }, + { 0x0fcd, "GeForce GT 755M" }, + { 0x0fce, "GeForce GT 640M LE" }, + { 0x0fd1, "GeForce GT 650M" }, + { 0x0fd2, "GeForce GT 640M", nvkm_device_pci_10de_0fd2 }, + { 0x0fd3, "GeForce GT 640M LE" }, + { 0x0fd4, "GeForce GTX 660M" }, + { 0x0fd5, "GeForce GT 650M" }, + { 0x0fd8, "GeForce GT 640M" }, + { 0x0fd9, "GeForce GT 645M" }, + { 0x0fdf, "GeForce GT 740M" }, + { 0x0fe0, "GeForce GTX 660M" }, + { 0x0fe1, "GeForce GT 730M" }, + { 0x0fe2, "GeForce GT 745M" }, + { 0x0fe3, "GeForce GT 745M", nvkm_device_pci_10de_0fe3 }, + { 0x0fe4, "GeForce GT 750M" }, + { 0x0fe9, "GeForce GT 750M" }, + { 0x0fea, "GeForce GT 755M" }, + { 0x0fec, "GeForce 710A" }, + { 0x0fef, "GRID K340" }, + { 0x0ff2, "GRID K1" }, + { 0x0ff3, "Quadro K420" }, + { 0x0ff6, "Quadro K1100M" }, + { 0x0ff8, "Quadro K500M" }, + { 0x0ff9, "Quadro K2000D" }, + { 0x0ffa, "Quadro K600" }, + { 0x0ffb, "Quadro K2000M" }, + { 0x0ffc, "Quadro K1000M" }, + { 0x0ffd, "NVS 510" }, + { 0x0ffe, "Quadro K2000" }, + { 0x0fff, "Quadro 410" }, + { 0x1001, "GeForce GTX TITAN Z" }, + { 0x1004, "GeForce GTX 780" }, + { 0x1005, "GeForce GTX TITAN" }, + { 0x1007, "GeForce GTX 780" }, + { 0x1008, "GeForce GTX 780 Ti" }, + { 0x100a, "GeForce GTX 780 Ti" }, + { 0x100c, "GeForce GTX TITAN Black" }, + { 0x1021, "Tesla K20Xm" }, + { 0x1022, "Tesla K20c" }, + { 0x1023, "Tesla K40m" }, + { 0x1024, "Tesla K40c" }, + { 0x1026, "Tesla K20s" }, + { 0x1027, "Tesla K40st" }, + { 0x1028, "Tesla K20m" }, + { 0x1029, "Tesla K40s" }, + { 0x102a, "Tesla K40t" }, + { 0x102d, "Tesla K80" }, + { 0x103a, "Quadro K6000" }, + { 0x103c, "Quadro K5200" }, + { 0x1040, "GeForce GT 520" }, + { 0x1042, "GeForce 510" }, + { 0x1048, "GeForce 605" }, + { 0x1049, "GeForce GT 620" }, + { 0x104a, "GeForce GT 610" }, + { 0x104b, "GeForce GT 625 (OEM)", nvkm_device_pci_10de_104b }, + { 0x104c, "GeForce GT 705" }, + { 0x1050, "GeForce GT 520M" }, + { 0x1051, "GeForce GT 520MX" }, + { 0x1052, "GeForce GT 520M" }, + { 0x1054, "GeForce 410M" }, + { 0x1055, "GeForce 410M" }, + { 0x1056, "NVS 4200M" }, + { 0x1057, "NVS 4200M" }, + { 0x1058, "GeForce 610M", nvkm_device_pci_10de_1058 }, + { 0x1059, "GeForce 610M" }, + { 0x105a, "GeForce 610M" }, + { 0x105b, "GeForce 705M", nvkm_device_pci_10de_105b }, + { 0x107c, "NVS 315" }, + { 0x107d, "NVS 310" }, + { 0x1080, "GeForce GTX 580" }, + { 0x1081, "GeForce GTX 570" }, + { 0x1082, "GeForce GTX 560 Ti" }, + { 0x1084, "GeForce GTX 560" }, + { 0x1086, "GeForce GTX 570" }, + { 0x1087, "GeForce GTX 560 Ti" }, + { 0x1088, "GeForce GTX 590" }, + { 0x1089, "GeForce GTX 580" }, + { 0x108b, "GeForce GTX 580" }, + { 0x1091, "Tesla M2090", nvkm_device_pci_10de_1091 }, + { 0x1094, "Tesla M2075" }, + { 0x1096, "Tesla C2075", nvkm_device_pci_10de_1096 }, + { 0x109a, "Quadro 5010M" }, + { 0x109b, "Quadro 7000" }, + { 0x10c0, "GeForce 9300 GS" }, + { 0x10c3, "GeForce 8400GS" }, + { 0x10c5, "GeForce 405" }, + { 0x10d8, "NVS 300" }, + { 0x1140, NULL, nvkm_device_pci_10de_1140 }, + { 0x1180, "GeForce GTX 680" }, + { 0x1183, "GeForce GTX 660 Ti" }, + { 0x1184, "GeForce GTX 770" }, + { 0x1185, "GeForce GTX 660", nvkm_device_pci_10de_1185 }, + { 0x1187, "GeForce GTX 760" }, + { 0x1188, "GeForce GTX 690" }, + { 0x1189, "GeForce GTX 670", nvkm_device_pci_10de_1189 }, + { 0x118a, "GRID K520" }, + { 0x118e, "GeForce GTX 760 (192-bit)" }, + { 0x118f, "Tesla K10" }, + { 0x1193, "GeForce GTX 760 Ti OEM" }, + { 0x1194, "Tesla K8" }, + { 0x1195, "GeForce GTX 660" }, + { 0x1198, "GeForce GTX 880M" }, + { 0x1199, "GeForce GTX 870M", nvkm_device_pci_10de_1199 }, + { 0x119a, "GeForce GTX 860M" }, + { 0x119d, "GeForce GTX 775M" }, + { 0x119e, "GeForce GTX 780M" }, + { 0x119f, "GeForce GTX 780M" }, + { 0x11a0, "GeForce GTX 680M" }, + { 0x11a1, "GeForce GTX 670MX" }, + { 0x11a2, "GeForce GTX 675MX" }, + { 0x11a3, "GeForce GTX 680MX" }, + { 0x11a7, "GeForce GTX 675MX" }, + { 0x11b4, "Quadro K4200" }, + { 0x11b6, "Quadro K3100M" }, + { 0x11b7, "Quadro K4100M" }, + { 0x11b8, "Quadro K5100M" }, + { 0x11ba, "Quadro K5000" }, + { 0x11bc, "Quadro K5000M" }, + { 0x11bd, "Quadro K4000M" }, + { 0x11be, "Quadro K3000M" }, + { 0x11bf, "GRID K2" }, + { 0x11c0, "GeForce GTX 660" }, + { 0x11c2, "GeForce GTX 650 Ti BOOST" }, + { 0x11c3, "GeForce GTX 650 Ti" }, + { 0x11c4, "GeForce GTX 645" }, + { 0x11c5, "GeForce GT 740" }, + { 0x11c6, "GeForce GTX 650 Ti" }, + { 0x11c8, "GeForce GTX 650" }, + { 0x11cb, "GeForce GT 740" }, + { 0x11e0, "GeForce GTX 770M" }, + { 0x11e1, "GeForce GTX 765M" }, + { 0x11e2, "GeForce GTX 765M" }, + { 0x11e3, "GeForce GTX 760M", nvkm_device_pci_10de_11e3 }, + { 0x11fa, "Quadro K4000" }, + { 0x11fc, "Quadro K2100M", nvkm_device_pci_10de_11fc }, + { 0x1200, "GeForce GTX 560 Ti" }, + { 0x1201, "GeForce GTX 560" }, + { 0x1203, "GeForce GTX 460 SE v2" }, + { 0x1205, "GeForce GTX 460 v2" }, + { 0x1206, "GeForce GTX 555" }, + { 0x1207, "GeForce GT 645" }, + { 0x1208, "GeForce GTX 560 SE" }, + { 0x1210, "GeForce GTX 570M" }, + { 0x1211, "GeForce GTX 580M" }, + { 0x1212, "GeForce GTX 675M" }, + { 0x1213, "GeForce GTX 670M" }, + { 0x1241, "GeForce GT 545" }, + { 0x1243, "GeForce GT 545" }, + { 0x1244, "GeForce GTX 550 Ti" }, + { 0x1245, "GeForce GTS 450" }, + { 0x1246, "GeForce GT 550M" }, + { 0x1247, "GeForce GT 555M", nvkm_device_pci_10de_1247 }, + { 0x1248, "GeForce GT 555M" }, + { 0x1249, "GeForce GTS 450" }, + { 0x124b, "GeForce GT 640" }, + { 0x124d, "GeForce GT 555M", nvkm_device_pci_10de_124d }, + { 0x1251, "GeForce GTX 560M" }, + { 0x1280, "GeForce GT 635" }, + { 0x1281, "GeForce GT 710" }, + { 0x1282, "GeForce GT 640" }, + { 0x1284, "GeForce GT 630" }, + { 0x1286, "GeForce GT 720" }, + { 0x1287, "GeForce GT 730" }, + { 0x1288, "GeForce GT 720" }, + { 0x1289, "GeForce GT 710" }, + { 0x1290, "GeForce GT 730M", nvkm_device_pci_10de_1290 }, + { 0x1291, "GeForce GT 735M" }, + { 0x1292, "GeForce GT 740M", nvkm_device_pci_10de_1292 }, + { 0x1293, "GeForce GT 730M" }, + { 0x1295, "GeForce 710M", nvkm_device_pci_10de_1295 }, + { 0x1296, "GeForce 825M" }, + { 0x1298, "GeForce GT 720M" }, + { 0x1299, "GeForce 920M", nvkm_device_pci_10de_1299 }, + { 0x129a, "GeForce 910M" }, + { 0x12b9, "Quadro K610M" }, + { 0x12ba, "Quadro K510M" }, + { 0x1340, "GeForce 830M", nvkm_device_pci_10de_1340 }, + { 0x1341, "GeForce 840M", nvkm_device_pci_10de_1341 }, + { 0x1344, "GeForce 845M" }, + { 0x1346, "GeForce 930M", nvkm_device_pci_10de_1346 }, + { 0x1347, "GeForce 940M", nvkm_device_pci_10de_1347 }, + { 0x137a, NULL, nvkm_device_pci_10de_137a }, + { 0x137d, NULL, nvkm_device_pci_10de_137d }, + { 0x1380, "GeForce GTX 750 Ti" }, + { 0x1381, "GeForce GTX 750" }, + { 0x1382, "GeForce GTX 745" }, + { 0x1390, "GeForce 845M" }, + { 0x1391, "GeForce GTX 850M", nvkm_device_pci_10de_1391 }, + { 0x1392, "GeForce GTX 860M", nvkm_device_pci_10de_1392 }, + { 0x1393, "GeForce 840M" }, + { 0x1398, "GeForce 845M" }, + { 0x139a, "GeForce GTX 950M", nvkm_device_pci_10de_139a }, + { 0x139b, "GeForce GTX 960M", nvkm_device_pci_10de_139b }, + { 0x139c, "GeForce 940M" }, + { 0x13b3, "Quadro K2200M" }, + { 0x13ba, "Quadro K2200" }, + { 0x13bb, "Quadro K620" }, + { 0x13bc, "Quadro K1200" }, + { 0x13c0, "GeForce GTX 980" }, + { 0x13c2, "GeForce GTX 970" }, + { 0x13d7, "GeForce GTX 980M" }, + { 0x13d8, "GeForce GTX 970M" }, + { 0x13d9, "GeForce GTX 965M" }, + { 0x1401, "GeForce GTX 960" }, + { 0x1617, "GeForce GTX 980M" }, + { 0x1618, "GeForce GTX 970M" }, + { 0x1619, "GeForce GTX 965M" }, + { 0x17c2, "GeForce GTX TITAN X" }, + { 0x17c8, "GeForce GTX 980 Ti" }, + { 0x17f0, "Quadro M6000" }, + {} +}; + static struct nvkm_device_pci * nvkm_device_pci(struct nvkm_device *device) { @@ -91,6 +1628,10 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, bool detect, bool mmio, u64 subdev_mask, struct nvkm_device **pdevice) { + const struct nvkm_device_quirk *quirk = NULL; + const struct nvkm_device_pci_device *pcid; + const struct nvkm_device_pci_vendor *pciv; + const char *name = NULL; struct nvkm_device_pci *pdev; int ret; @@ -98,6 +1639,31 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, if (ret) return ret; + switch (pci_dev->vendor) { + case 0x10de: pcid = nvkm_device_pci_10de; break; + default: + pcid = NULL; + break; + } + + while (pcid && pcid->device) { + if (pciv = pcid->vendor, pcid->device == pci_dev->device) { + while (pciv && pciv->vendor) { + if (pciv->vendor == pci_dev->subsystem_vendor && + pciv->device == pci_dev->subsystem_device) { + quirk = &pciv->quirk; + name = pciv->name; + break; + } + pciv++; + } + if (!name) + name = pcid->name; + break; + } + pcid++; + } + if (!(pdev = kzalloc(sizeof(*pdev), GFP_KERNEL))) { pci_disable_device(pci_dev); return -ENOMEM; @@ -105,12 +1671,12 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, *pdevice = &pdev->device; pdev->pdev = pci_dev; - return nvkm_device_ctor(&nvkm_device_pci_func, NULL, + return nvkm_device_ctor(&nvkm_device_pci_func, quirk, pci_dev, NVKM_BUS_PCI, (u64)pci_domain_nr(pci_dev->bus) << 32 | pci_dev->bus->number << 16 | PCI_SLOT(pci_dev->devfn) << 8 | - PCI_FUNC(pci_dev->devfn), NULL, + PCI_FUNC(pci_dev->devfn), name, cfg, dbg, detect, mmio, subdev_mask, &pdev->device); } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c index 516a06b6b66ab..d45ec99f0e385 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c @@ -61,11 +61,11 @@ nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, return 0; /* Apple iMac G4 NV18 */ - if (nv_device_match(device, 0x0189, 0x10de, 0x0010)) { + if (device->quirk && device->quirk->tv_gpio) { if (tag == DCB_GPIO_TVDAC0) { *func = (struct dcb_gpio_func) { .func = DCB_GPIO_TVDAC0, - .line = 4, + .line = device->quirk->tv_gpio, .log[0] = 0, .log[1] = 1, }; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c index 584299737658e..e33f5c03b9ace 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c @@ -26,7 +26,6 @@ #include "priv.h" #include "fuc/gf119.fuc4.h" -#include #include #include @@ -78,9 +77,8 @@ gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable) nvkm_mask(device, 0x000200, 0x00001000, 0x00001000); nvkm_rd32(device, 0x000200); - if (nv_device_match(device, 0x11fc, 0x17aa, 0x2211) /* Lenovo W541 */ - || nv_device_match(device, 0x11fc, 0x17aa, 0x221e) /* Lenovo W541 */ - || nvkm_boolopt(device->cfgopt, "War00C800_0", false)) { + if ( nvkm_boolopt(device->cfgopt, "War00C800_0", + device->quirk ? device->quirk->War00C800_0 : false)) { nvkm_info(&pmu->subdev, "hw bug workaround enabled\n"); switch (device->chipset) { case 0xe4: -- GitLab From 26c9e8effebb9166eb1cfba2d164676e98c505c7 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:23 +1000 Subject: [PATCH 5568/7006] drm/nouveau/device: remove pci/platform_device from common struct Signed-off-by: Ben Skeggs --- .../drm/nouveau/include/nvkm/core/device.h | 40 +++++-------------- drivers/gpu/drm/nouveau/nouveau_abi16.c | 6 +-- drivers/gpu/drm/nouveau/nouveau_acpi.c | 4 +- drivers/gpu/drm/nouveau/nouveau_acpi.h | 4 +- drivers/gpu/drm/nouveau/nouveau_agp.c | 7 +++- drivers/gpu/drm/nouveau/nouveau_bo.c | 18 ++++----- drivers/gpu/drm/nouveau/nouveau_sysfs.c | 4 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 2 +- drivers/gpu/drm/nouveau/nv50_display.c | 8 ++-- .../gpu/drm/nouveau/nvkm/engine/device/base.c | 14 ++----- .../gpu/drm/nouveau/nvkm/engine/device/pci.c | 7 +++- .../gpu/drm/nouveau/nvkm/engine/device/priv.h | 2 +- .../drm/nouveau/nvkm/engine/device/tegra.c | 5 ++- .../gpu/drm/nouveau/nvkm/engine/device/user.c | 24 ++++++----- drivers/gpu/drm/nouveau/nvkm/engine/falcon.c | 6 +-- .../gpu/drm/nouveau/nvkm/engine/gr/gf100.c | 2 +- drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/bios/shadow.c | 2 +- .../drm/nouveau/nvkm/subdev/bios/shadowacpi.c | 6 +-- .../drm/nouveau/nvkm/subdev/bios/shadowpci.c | 18 ++++++++- .../gpu/drm/nouveau/nvkm/subdev/fb/gf100.c | 9 ++--- drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c | 9 ++--- .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c | 4 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c | 2 +- .../gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c | 5 ++- .../gpu/drm/nouveau/nvkm/subdev/mxm/base.c | 2 +- 27 files changed, 106 insertions(+), 108 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 5741bf228762f..773951bfd200a 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -47,13 +47,21 @@ enum nvkm_devidx { NVKM_ENGINE_SEC, NVKM_ENGINE_MSPDEC, - NVKM_SUBDEV_NR, + NVKM_SUBDEV_NR +}; + +enum nvkm_device_type { + NVKM_DEVICE_PCI, + NVKM_DEVICE_AGP, + NVKM_DEVICE_PCIE, + NVKM_DEVICE_TEGRA, }; struct nvkm_device { const struct nvkm_device_func *func; const struct nvkm_device_quirk *quirk; struct device *dev; + enum nvkm_device_type type; u64 handle; const char *name; const char *cfgopt; @@ -63,9 +71,6 @@ struct nvkm_device { struct mutex mutex; int refcount; - struct pci_dev *pdev; - struct platform_device *platformdev; - void __iomem *pri; struct nvkm_event event; @@ -150,6 +155,7 @@ struct nvkm_device_func { void (*fini)(struct nvkm_device *, bool suspend); resource_size_t (*resource_addr)(struct nvkm_device *, unsigned bar); resource_size_t (*resource_size)(struct nvkm_device *, unsigned bar); + bool cpu_coherent; }; struct nvkm_device_quirk { @@ -220,32 +226,6 @@ int nvkm_device_list(u64 *name, int size); _temp; \ }) -static inline bool -nv_device_is_pci(struct nvkm_device *device) -{ - return device->pdev != NULL; -} - -static inline bool -nv_device_is_cpu_coherent(struct nvkm_device *device) -{ - return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device)); -} - -static inline struct device * -nv_device_base(struct nvkm_device *device) -{ - return nv_device_is_pci(device) ? &device->pdev->dev : - &device->platformdev->dev; -} - -struct platform_device; - -enum nv_bus_type { - NVKM_BUS_PCI, - NVKM_BUS_PLATFORM, -}; - void nvkm_device_del(struct nvkm_device **); struct nvkm_device_oclass { diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 40a903b79343e..4252e7796c4c1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -174,19 +174,19 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS) getparam->value = device->info.chipset; break; case NOUVEAU_GETPARAM_PCI_VENDOR: - if (nv_device_is_pci(nvxx_device(device))) + if (nvxx_device(device)->func->pci) getparam->value = dev->pdev->vendor; else getparam->value = 0; break; case NOUVEAU_GETPARAM_PCI_DEVICE: - if (nv_device_is_pci(nvxx_device(device))) + if (nvxx_device(device)->func->pci) getparam->value = dev->pdev->device; else getparam->value = 0; break; case NOUVEAU_GETPARAM_BUS_TYPE: - if (!nv_device_is_pci(nvxx_device(device))) + if (!nvxx_device(device)->func->pci) getparam->value = 3; else if (drm_pci_device_is_agp(dev)) diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.c b/drivers/gpu/drm/nouveau/nouveau_acpi.c index 622424692b3bd..df2d9818aba3a 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.c +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.c @@ -372,12 +372,12 @@ static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios, return len; } -bool nouveau_acpi_rom_supported(struct pci_dev *pdev) +bool nouveau_acpi_rom_supported(struct device *dev) { acpi_status status; acpi_handle dhandle, rom_handle; - dhandle = ACPI_HANDLE(&pdev->dev); + dhandle = ACPI_HANDLE(dev); if (!dhandle) return false; diff --git a/drivers/gpu/drm/nouveau/nouveau_acpi.h b/drivers/gpu/drm/nouveau/nouveau_acpi.h index 74acf0f877850..2f03653aff86c 100644 --- a/drivers/gpu/drm/nouveau/nouveau_acpi.h +++ b/drivers/gpu/drm/nouveau/nouveau_acpi.h @@ -10,7 +10,7 @@ void nouveau_register_dsm_handler(void); void nouveau_unregister_dsm_handler(void); void nouveau_switcheroo_optimus_dsm(void); int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); -bool nouveau_acpi_rom_supported(struct pci_dev *pdev); +bool nouveau_acpi_rom_supported(struct device *); void *nouveau_acpi_edid(struct drm_device *, struct drm_connector *); #else static inline bool nouveau_is_optimus(void) { return false; }; @@ -18,7 +18,7 @@ static inline bool nouveau_is_v1_dsm(void) { return false; }; static inline void nouveau_register_dsm_handler(void) {} static inline void nouveau_unregister_dsm_handler(void) {} static inline void nouveau_switcheroo_optimus_dsm(void) {} -static inline bool nouveau_acpi_rom_supported(struct pci_dev *pdev) { return false; } +static inline bool nouveau_acpi_rom_supported(struct device *dev) { return false; } static inline int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len) { return -EINVAL; } static inline void *nouveau_acpi_edid(struct drm_device *dev, struct drm_connector *connector) { return NULL; } #endif diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c index 320f48c41fe0d..c3f3e49e5f8f1 100644 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ b/drivers/gpu/drm/nouveau/nouveau_agp.c @@ -4,6 +4,8 @@ #include "nouveau_agp.h" #include "nouveau_reg.h" +#include + #if __OS_HAS_AGP MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); static int nouveau_agpmode = -1; @@ -28,6 +30,7 @@ static unsigned long get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) { struct nvif_device *device = &drm->device; + struct pci_dev *pdev = nvxx_device(device)->func->pci(nvxx_device(device))->pdev; struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; int agpmode = nouveau_agpmode; unsigned long mode = info->mode; @@ -45,8 +48,8 @@ get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) while (agpmode == -1 && quirk->hostbridge_vendor) { if (info->id_vendor == quirk->hostbridge_vendor && info->id_device == quirk->hostbridge_device && - nvxx_device(device)->pdev->vendor == quirk->chip_vendor && - nvxx_device(device)->pdev->device == quirk->chip_device) { + pdev->vendor == quirk->chip_vendor && + pdev->device == quirk->chip_device) { agpmode = quirk->mode; NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n", agpmode); diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 6024edf8529e5..373fbd2d14ffb 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -209,7 +209,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align, nvbo->tile_flags = tile_flags; nvbo->bo.bdev = &drm->ttm.bdev; - if (!nv_device_is_cpu_coherent(nvxx_device(&drm->device))) + if (!nvxx_device(&drm->device)->func->cpu_coherent) nvbo->force_coherent = flags & TTM_PL_FLAG_UNCACHED; nvbo->page_shift = 12; @@ -466,8 +466,8 @@ nouveau_bo_sync_for_device(struct nouveau_bo *nvbo) return; for (i = 0; i < ttm_dma->ttm.num_pages; i++) - dma_sync_single_for_device(nv_device_base(device), - ttm_dma->dma_address[i], PAGE_SIZE, DMA_TO_DEVICE); + dma_sync_single_for_device(device->dev, ttm_dma->dma_address[i], + PAGE_SIZE, DMA_TO_DEVICE); } void @@ -486,8 +486,8 @@ nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo) return; for (i = 0; i < ttm_dma->ttm.num_pages; i++) - dma_sync_single_for_cpu(nv_device_base(device), - ttm_dma->dma_address[i], PAGE_SIZE, DMA_FROM_DEVICE); + dma_sync_single_for_cpu(device->dev, ttm_dma->dma_address[i], + PAGE_SIZE, DMA_FROM_DEVICE); } int @@ -1487,13 +1487,13 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) drm = nouveau_bdev(ttm->bdev); device = nvxx_device(&drm->device); dev = drm->dev; - pdev = nv_device_base(device); + pdev = device->dev; /* * Objects matching this condition have been marked as force_coherent, * so use the DMA API for them. */ - if (!nv_device_is_cpu_coherent(device) && + if (!nvxx_device(&drm->device)->func->cpu_coherent && ttm->caching_state == tt_uncached) return ttm_dma_populate(ttm_dma, dev->dev); @@ -1552,13 +1552,13 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) drm = nouveau_bdev(ttm->bdev); device = nvxx_device(&drm->device); dev = drm->dev; - pdev = nv_device_base(device); + pdev = device->dev; /* * Objects matching this condition have been marked as force_coherent, * so use the DMA API for them. */ - if (!nv_device_is_cpu_coherent(device) && + if (!nvxx_device(&drm->device)->func->cpu_coherent && ttm->caching_state == tt_uncached) { ttm_dma_unpopulate(ttm_dma, dev->dev); return; diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c index ce612064fa6a9..d12a5faee0478 100644 --- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c +++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c @@ -165,7 +165,7 @@ nouveau_sysfs_fini(struct drm_device *dev) struct nvif_device *device = &drm->device; if (sysfs && sysfs->ctrl.priv) { - device_remove_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate); + device_remove_file(nvxx_device(device)->dev, &dev_attr_pstate); nvif_object_fini(&sysfs->ctrl); } @@ -192,7 +192,7 @@ nouveau_sysfs_init(struct drm_device *dev) NVIF_IOCTL_NEW_V0_CONTROL, NULL, 0, &sysfs->ctrl); if (ret == 0) - device_create_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate); + device_create_file(nvxx_device(device)->dev, &dev_attr_pstate); return 0; } diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index 1fd70d6900cf7..ba9fd151bd281 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -341,7 +341,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) int ret; bits = nvxx_mmu(&drm->device)->dma_bits; - if (nv_device_is_pci(nvxx_device(&drm->device))) { + if (nvxx_device(&drm->device)->func->pci) { if (drm->agp.stat == ENABLED || !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) bits = 32; diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 57b13602b2c5a..4ae87aed45054 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -210,8 +210,8 @@ nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp) nv50_chan_destroy(&dmac->base); if (dmac->ptr) { - struct pci_dev *pdev = nvxx_device(device)->pdev; - pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle); + struct device *dev = nvxx_device(device)->dev; + dma_free_coherent(dev, PAGE_SIZE, dmac->ptr, dmac->handle); } } @@ -226,8 +226,8 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp, mutex_init(&dmac->lock); - dmac->ptr = pci_alloc_consistent(nvxx_device(device)->pdev, - PAGE_SIZE, &dmac->handle); + dmac->ptr = dma_alloc_coherent(nvxx_device(device)->dev, PAGE_SIZE, + &dmac->handle, GFP_KERNEL); if (!dmac->ptr) return -ENOMEM; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c index b8d46144e68a6..94a906b8cb88b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c @@ -2294,7 +2294,7 @@ nvkm_device_del(struct nvkm_device **pdevice) int nvkm_device_ctor(const struct nvkm_device_func *func, const struct nvkm_device_quirk *quirk, - void *dev, enum nv_bus_type type, u64 handle, + struct device *dev, enum nvkm_device_type type, u64 handle, const char *name, const char *cfg, const char *dbg, bool detect, bool mmio, u64 subdev_mask, struct nvkm_device *device) @@ -2312,16 +2312,8 @@ nvkm_device_ctor(const struct nvkm_device_func *func, device->func = func; device->quirk = quirk; - switch (type) { - case NVKM_BUS_PCI: - device->pdev = dev; - device->dev = &device->pdev->dev; - break; - case NVKM_BUS_PLATFORM: - device->platformdev = dev; - device->dev = &device->platformdev->dev; - break; - } + device->dev = dev; + device->type = type; device->handle = handle; device->cfgopt = cfg; device->dbgopt = dbg; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index 8702a9efc7b4b..9dd1cac81e808 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -1621,6 +1621,7 @@ nvkm_device_pci_func = { .fini = nvkm_device_pci_fini, .resource_addr = nvkm_device_pci_resource_addr, .resource_size = nvkm_device_pci_resource_size, + .cpu_coherent = !IS_ENABLED(CONFIG_ARM), }; int @@ -1671,8 +1672,10 @@ nvkm_device_pci_new(struct pci_dev *pci_dev, const char *cfg, const char *dbg, *pdevice = &pdev->device; pdev->pdev = pci_dev; - return nvkm_device_ctor(&nvkm_device_pci_func, quirk, - pci_dev, NVKM_BUS_PCI, + return nvkm_device_ctor(&nvkm_device_pci_func, quirk, &pci_dev->dev, + pci_is_pcie(pci_dev) ? NVKM_DEVICE_PCIE : + pci_find_capability(pci_dev, PCI_CAP_ID_AGP) ? + NVKM_DEVICE_AGP : NVKM_DEVICE_PCI, (u64)pci_domain_nr(pci_dev->bus) << 32 | pci_dev->bus->number << 16 | PCI_SLOT(pci_dev->devfn) << 8 | diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h index 6dea6e8fc8547..ed3ad2c30e17e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h @@ -41,7 +41,7 @@ int nvkm_device_ctor(const struct nvkm_device_func *, const struct nvkm_device_quirk *, - void *, enum nv_bus_type type, u64 handle, + struct device *, enum nvkm_device_type, u64 handle, const char *name, const char *cfg, const char *dbg, bool detect, bool mmio, u64 subdev_mask, struct nvkm_device *); diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index f4bc11c1671fe..ada73e13d1af5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -102,6 +102,7 @@ nvkm_device_tegra_func = { .fini = nvkm_device_tegra_fini, .resource_addr = nvkm_device_tegra_resource_addr, .resource_size = nvkm_device_tegra_resource_size, + .cpu_coherent = false, }; int @@ -118,8 +119,8 @@ nvkm_device_tegra_new(struct platform_device *pdev, tdev->pdev = pdev; tdev->irq = -1; - return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, pdev, - NVKM_BUS_PLATFORM, pdev->id, NULL, + return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev, + NVKM_DEVICE_TEGRA, pdev->id, NULL, cfg, dbg, detect, mmio, subdev_mask, &tdev->device); } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c index eddf9b1d3340c..1ae48f27029d5 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/user.c @@ -70,16 +70,22 @@ nvkm_udevice_info(struct nvkm_udevice *udev, void *data, u32 size) args->v0.platform = NV_DEVICE_INFO_V0_IGP; break; default: - if (device->pdev) { - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP)) - args->v0.platform = NV_DEVICE_INFO_V0_AGP; - else - if (pci_is_pcie(device->pdev)) - args->v0.platform = NV_DEVICE_INFO_V0_PCIE; - else - args->v0.platform = NV_DEVICE_INFO_V0_PCI; - } else { + switch (device->type) { + case NVKM_DEVICE_PCI: + args->v0.platform = NV_DEVICE_INFO_V0_PCI; + break; + case NVKM_DEVICE_AGP: + args->v0.platform = NV_DEVICE_INFO_V0_AGP; + break; + case NVKM_DEVICE_PCIE: + args->v0.platform = NV_DEVICE_INFO_V0_PCIE; + break; + case NVKM_DEVICE_TEGRA: args->v0.platform = NV_DEVICE_INFO_V0_SOC; + break; + default: + WARN_ON(1); + break; } break; } diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c index 2d11b328bee11..74000602fbb12 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c @@ -190,7 +190,7 @@ nvkm_falcon_init(struct nvkm_engine *engine) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret == 0) { falcon->code.data = vmemdup(fw->data, fw->size); falcon->code.size = fw->size; @@ -209,7 +209,7 @@ nvkm_falcon_init(struct nvkm_engine *engine) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret) { nvkm_error(subdev, "unable to load firmware data\n"); return -ENODEV; @@ -224,7 +224,7 @@ nvkm_falcon_init(struct nvkm_engine *engine) snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc", device->chipset, falcon->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret) { nvkm_error(subdev, "unable to load firmware code\n"); return -ENODEV; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c index 1ad6785683f2c..f1358a564e3e8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c @@ -1642,7 +1642,7 @@ gf100_gr_ctor_fw(struct gf100_gr *gr, const char *fwname, } snprintf(f, sizeof(f), "nvidia/%s/%s.bin", cname, fwname); - ret = request_firmware(&fw, f, nv_device_base(device)); + ret = request_firmware(&fw, f, device->dev); if (ret) { nvkm_error(subdev, "failed to load %s\n", fwname); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c index d6a2b9593538c..a3d4f5bcec7a4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c @@ -107,7 +107,7 @@ nvkm_xtensa_init(struct nvkm_engine *engine) snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x", xtensa->addr >> 12); - ret = request_firmware(&fw, name, nv_device_base(device)); + ret = request_firmware(&fw, name, device->dev); if (ret) { nvkm_warn(subdev, "unable to load firmware %s\n", name); return ret; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c index b089a11ba08cf..792f017525f68 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c @@ -134,7 +134,7 @@ shadow_fw_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * shadow_fw_init(struct nvkm_bios *bios, const char *name) { - struct device *dev = &bios->subdev.device->pdev->dev; + struct device *dev = bios->subdev.device->dev; const struct firmware *fw; int ret = request_firmware(&fw, name, dev); if (ret) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c index 468066817c75c..8fecb5ff22a0e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c @@ -24,10 +24,10 @@ #if defined(CONFIG_ACPI) && defined(CONFIG_X86) int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len); -bool nouveau_acpi_rom_supported(struct pci_dev *pdev); +bool nouveau_acpi_rom_supported(struct device *); #else static inline bool -nouveau_acpi_rom_supported(struct pci_dev *pdev) +nouveau_acpi_rom_supported(struct device *dev) { return false; } @@ -88,7 +88,7 @@ acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * acpi_init(struct nvkm_bios *bios, const char *name) { - if (!nouveau_acpi_rom_supported(bios->subdev.device->pdev)) + if (!nouveau_acpi_rom_supported(bios->subdev.device->dev)) return ERR_PTR(-ENODEV); return NULL; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c index 0979bc89eeab0..9b91da09dc5f8 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c @@ -22,6 +22,8 @@ */ #include "priv.h" +#include + struct priv { struct pci_dev *pdev; void __iomem *rom; @@ -51,10 +53,16 @@ pcirom_fini(void *data) static void * pcirom_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = bios->subdev.device->pdev; + struct nvkm_device *device = bios->subdev.device; struct priv *priv = NULL; + struct pci_dev *pdev; int ret; + if (device->func->pci) + pdev = device->func->pci(device)->pdev; + else + return ERR_PTR(-ENODEV); + if (!(ret = pci_enable_rom(pdev))) { if (ret = -ENOMEM, (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) { @@ -83,10 +91,16 @@ nvbios_pcirom = { static void * platform_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = bios->subdev.device->pdev; + struct nvkm_device *device = bios->subdev.device; + struct pci_dev *pdev; struct priv *priv; int ret = -ENOMEM; + if (device->func->pci) + pdev = device->func->pci(device)->pdev; + else + return ERR_PTR(-ENODEV); + if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) { if (ret = -ENODEV, (priv->rom = pci_platform_rom(pdev, &priv->size))) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c index ef3149aa51242..008bb9849f3b4 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c @@ -65,7 +65,7 @@ gf100_fb_dtor(struct nvkm_fb *base) struct nvkm_device *device = fb->base.subdev.device; if (fb->r100c10_page) { - dma_unmap_page(nv_device_base(device), fb->r100c10, PAGE_SIZE, + dma_unmap_page(device->dev, fb->r100c10, PAGE_SIZE, DMA_BIDIRECTIONAL); __free_page(fb->r100c10_page); } @@ -86,10 +86,9 @@ gf100_fb_new_(const struct nvkm_fb_func *func, struct nvkm_device *device, fb->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (fb->r100c10_page) { - fb->r100c10 = dma_map_page(nv_device_base(device), - fb->r100c10_page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), fb->r100c10)) + fb->r100c10 = dma_map_page(device->dev, fb->r100c10_page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(device->dev, fb->r100c10)) return -EFAULT; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c index c2b6ccde7473f..f5edfadb5b46c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c @@ -234,7 +234,7 @@ nv50_fb_dtor(struct nvkm_fb *base) struct nvkm_device *device = fb->base.subdev.device; if (fb->r100c08_page) { - dma_unmap_page(nv_device_base(device), fb->r100c08, PAGE_SIZE, + dma_unmap_page(device->dev, fb->r100c08, PAGE_SIZE, DMA_BIDIRECTIONAL); __free_page(fb->r100c08_page); } @@ -265,10 +265,9 @@ nv50_fb_new_(const struct nv50_fb_func *func, struct nvkm_device *device, fb->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO); if (fb->r100c08_page) { - fb->r100c08 = dma_map_page(nv_device_base(device), - fb->r100c08_page, 0, PAGE_SIZE, - DMA_BIDIRECTIONAL); - if (dma_mapping_error(nv_device_base(device), fb->r100c08)) + fb->r100c08 = dma_map_page(device->dev, fb->r100c08_page, 0, + PAGE_SIZE, DMA_BIDIRECTIONAL); + if (dma_mapping_error(device->dev, fb->r100c08)) return -EFAULT; } else { nvkm_warn(&fb->base.subdev, "failed 100c08 page alloc\n"); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index ab01989c34304..5ef04b72a80ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -186,7 +186,7 @@ gk20a_instobj_dtor_dma(struct gk20a_instobj *_node) { struct gk20a_instobj_dma *node = (void *)_node; struct gk20a_instmem *imem = _node->imem; - struct device *dev = nv_device_base(imem->base.subdev.device); + struct device *dev = imem->base.subdev.device->dev; if (unlikely(!node->cpuaddr)) return; diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c index 5def412f0467e..37927c3fdc3e6 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c @@ -110,8 +110,8 @@ nv04_mmu_dtor(struct nvkm_mmu *base) nvkm_vm_ref(NULL, &mmu->vm, NULL); } if (mmu->nullp) { - pci_free_consistent(device->pdev, 16 * 1024, - mmu->nullp, mmu->null); + dma_free_coherent(device->dev, 16 * 1024, + mmu->nullp, mmu->null); } return mmu; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c index f30c3b890626c..c6a26f907009c 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c @@ -133,7 +133,7 @@ nv41_mmu = { int nv41_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) { - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || + if (device->type == NVKM_DEVICE_AGP || !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) return nv04_mmu_new(device, index, pmmu); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c index 7c37bd84b862d..a648c2395545b 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c @@ -165,7 +165,8 @@ nv44_mmu_oneinit(struct nvkm_mmu *base) struct nvkm_device *device = mmu->base.subdev.device; int ret; - mmu->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &mmu->null); + mmu->nullp = dma_alloc_coherent(device->dev, 16 * 1024, + &mmu->null, GFP_KERNEL); if (!mmu->nullp) { nvkm_warn(&mmu->base.subdev, "unable to allocate dummy pages\n"); mmu->null = 0; @@ -227,7 +228,7 @@ nv44_mmu = { int nv44_mmu_new(struct nvkm_device *device, int index, struct nvkm_mmu **pmmu) { - if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) || + if (device->type == NVKM_DEVICE_AGP || !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) return nv04_mmu_new(device, index, pmmu); diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c index 442b5e200a778..9700a7625012d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c @@ -95,7 +95,7 @@ mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version) acpi_handle handle; int rev; - handle = ACPI_HANDLE(nv_device_base(device)); + handle = ACPI_HANDLE(device->dev); if (!handle) return false; -- GitLab From 340b0e7c500a0ac8fb649c58cf8528550642c1d8 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:23 +1000 Subject: [PATCH 5569/7006] drm/nouveau/pci: merge agp handling from nouveau drm This commit reinstates the pre-DEVINIT AGP fiddling that was broken in an earlier commit. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/Kbuild | 1 - drivers/gpu/drm/nouveau/include/nvif/device.h | 1 + drivers/gpu/drm/nouveau/include/nvif/os.h | 1 + .../drm/nouveau/include/nvkm/core/option.h | 1 + .../gpu/drm/nouveau/include/nvkm/subdev/pci.h | 11 + drivers/gpu/drm/nouveau/nouveau_abi16.c | 2 +- drivers/gpu/drm/nouveau/nouveau_agp.c | 198 ------------------ drivers/gpu/drm/nouveau/nouveau_agp.h | 10 - drivers/gpu/drm/nouveau/nouveau_bo.c | 17 +- drivers/gpu/drm/nouveau/nouveau_chan.c | 4 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 11 - drivers/gpu/drm/nouveau/nouveau_drm.h | 7 +- drivers/gpu/drm/nouveau/nouveau_ttm.c | 12 +- drivers/gpu/drm/nouveau/nvkm/core/option.c | 18 ++ .../gpu/drm/nouveau/nvkm/subdev/pci/Kbuild | 1 + drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c | 171 +++++++++++++++ drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h | 18 ++ .../gpu/drm/nouveau/nvkm/subdev/pci/base.c | 26 +++ 18 files changed, 271 insertions(+), 239 deletions(-) delete mode 100644 drivers/gpu/drm/nouveau/nouveau_agp.c delete mode 100644 drivers/gpu/drm/nouveau/nouveau_agp.h create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c create mode 100644 drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild index 2b765663c1a3f..a34b437dbc8f9 100644 --- a/drivers/gpu/drm/nouveau/Kbuild +++ b/drivers/gpu/drm/nouveau/Kbuild @@ -18,7 +18,6 @@ nouveau-y += $(nvkm-y) ifdef CONFIG_X86 nouveau-$(CONFIG_ACPI) += nouveau_acpi.o endif -nouveau-y += nouveau_agp.o nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o nouveau-y += nouveau_drm.o nouveau-y += nouveau_hwmon.o diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h index 900e492549d16..700a9b2067262 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/device.h +++ b/drivers/gpu/drm/nouveau/include/nvif/device.h @@ -45,6 +45,7 @@ u64 nvif_device_time(struct nvif_device *); #include #include #include +#include #define nvxx_device(a) ({ \ struct nvif_device *_device = (a); \ diff --git a/drivers/gpu/drm/nouveau/include/nvif/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h index 54492cb5011be..97317f7fe4e5a 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/os.h +++ b/drivers/gpu/drm/nouveau/include/nvif/os.h @@ -24,6 +24,7 @@ #include #include #include +#include #include diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/option.h b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h index 532bfa8e3f722..80fdc146e816e 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/option.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h @@ -4,6 +4,7 @@ const char *nvkm_stropt(const char *optstr, const char *opt, int *len); bool nvkm_boolopt(const char *optstr, const char *opt, bool value); +long nvkm_longopt(const char *optstr, const char *opt, long value); int nvkm_dbgopt(const char *optstr, const char *sub); /* compares unterminated string 'str' with zero-terminated string 'cmp' */ diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h index ac14fdf2f967a..5b3c054f3b551 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pci.h @@ -7,6 +7,17 @@ struct nvkm_pci { struct nvkm_subdev subdev; struct pci_dev *pdev; int irq; + + struct { + struct agp_bridge_data *bridge; + u32 mode; + u64 base; + u64 size; + int mtrr; + bool cma; + bool acquired; + } agp; + bool msi; }; diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c index 4252e7796c4c1..d336c2247d6af 100644 --- a/drivers/gpu/drm/nouveau/nouveau_abi16.c +++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c @@ -498,7 +498,7 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS) args.start += chan->ntfy_vma.offset; args.limit += chan->ntfy_vma.offset; } else - if (drm->agp.stat == ENABLED) { + if (drm->agp.bridge) { args.target = NV_DMA_V0_TARGET_AGP; args.access = NV_DMA_V0_ACCESS_RDWR; args.start += drm->agp.base + chan->ntfy->bo.offset; diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c deleted file mode 100644 index c3f3e49e5f8f1..0000000000000 --- a/drivers/gpu/drm/nouveau/nouveau_agp.c +++ /dev/null @@ -1,198 +0,0 @@ -#include - -#include "nouveau_drm.h" -#include "nouveau_agp.h" -#include "nouveau_reg.h" - -#include - -#if __OS_HAS_AGP -MODULE_PARM_DESC(agpmode, "AGP mode (0 to disable AGP)"); -static int nouveau_agpmode = -1; -module_param_named(agpmode, nouveau_agpmode, int, 0400); - -struct nouveau_agpmode_quirk { - u16 hostbridge_vendor; - u16 hostbridge_device; - u16 chip_vendor; - u16 chip_device; - int mode; -}; - -static struct nouveau_agpmode_quirk nouveau_agpmode_quirk_list[] = { - /* VIA Apollo PRO133x / GeForce FX 5600 Ultra, max agpmode 2, fdo #20341 */ - { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 }, - - {}, -}; - -static unsigned long -get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info) -{ - struct nvif_device *device = &drm->device; - struct pci_dev *pdev = nvxx_device(device)->func->pci(nvxx_device(device))->pdev; - struct nouveau_agpmode_quirk *quirk = nouveau_agpmode_quirk_list; - int agpmode = nouveau_agpmode; - unsigned long mode = info->mode; - - /* - * FW seems to be broken on nv18, it makes the card lock up - * randomly. - */ - if (device->info.chipset == 0x18) - mode &= ~PCI_AGP_COMMAND_FW; - - /* - * Go through the quirks list and adjust the agpmode accordingly. - */ - while (agpmode == -1 && quirk->hostbridge_vendor) { - if (info->id_vendor == quirk->hostbridge_vendor && - info->id_device == quirk->hostbridge_device && - pdev->vendor == quirk->chip_vendor && - pdev->device == quirk->chip_device) { - agpmode = quirk->mode; - NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n", - agpmode); - break; - } - ++quirk; - } - - /* - * AGP mode set in the command line. - */ - if (agpmode > 0) { - bool agpv3 = mode & 0x8; - int rate = agpv3 ? agpmode / 4 : agpmode; - - mode = (mode & ~0x7) | (rate & 0x7); - } - - return mode; -} - -static bool -nouveau_agp_enabled(struct nouveau_drm *drm) -{ - struct drm_device *dev = drm->dev; - - if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp) - return false; - - if (drm->agp.stat == UNKNOWN) { - if (!nouveau_agpmode) - return false; -#ifdef __powerpc__ - /* Disable AGP by default on all PowerPC machines for - * now -- At least some UniNorth-2 AGP bridges are - * known to be broken: DMA from the host to the card - * works just fine, but writeback from the card to the - * host goes straight to memory untranslated bypassing - * the GATT somehow, making them quite painful to deal - * with... - */ - if (nouveau_agpmode == -1) - return false; -#endif - return true; - } - - return (drm->agp.stat == ENABLED); -} -#endif - -void -nouveau_agp_reset(struct nouveau_drm *drm) -{ -#if __OS_HAS_AGP - struct nvif_object *device = &drm->device.object; - struct drm_device *dev = drm->dev; - u32 save[2]; - int ret; - - if (!nouveau_agp_enabled(drm)) - return; - - /* First of all, disable fast writes, otherwise if it's - * already enabled in the AGP bridge and we disable the card's - * AGP controller we might be locking ourselves out of it. */ - if ((nvif_rd32(device, NV04_PBUS_PCI_NV_19) | - dev->agp->mode) & PCI_AGP_COMMAND_FW) { - struct drm_agp_info info; - struct drm_agp_mode mode; - - ret = drm_agp_info(dev, &info); - if (ret) - return; - - mode.mode = get_agp_mode(drm, &info); - mode.mode &= ~PCI_AGP_COMMAND_FW; - - ret = drm_agp_enable(dev, mode); - if (ret) - return; - } - - - /* clear busmaster bit, and disable AGP */ - save[0] = nvif_mask(device, NV04_PBUS_PCI_NV_1, 0x00000004, 0x00000000); - nvif_wr32(device, NV04_PBUS_PCI_NV_19, 0); - - /* reset PGRAPH, PFIFO and PTIMER */ - save[1] = nvif_mask(device, 0x000200, 0x00011100, 0x00000000); - nvif_mask(device, 0x000200, 0x00011100, save[1]); - - /* and restore bustmaster bit (gives effect of resetting AGP) */ - nvif_wr32(device, NV04_PBUS_PCI_NV_1, save[0]); -#endif -} - -void -nouveau_agp_init(struct nouveau_drm *drm) -{ -#if __OS_HAS_AGP - struct drm_device *dev = drm->dev; - struct drm_agp_info info; - struct drm_agp_mode mode; - int ret; - - if (!nouveau_agp_enabled(drm)) - return; - drm->agp.stat = DISABLE; - - ret = drm_agp_acquire(dev); - if (ret) { - NV_ERROR(drm, "unable to acquire AGP: %d\n", ret); - return; - } - - ret = drm_agp_info(dev, &info); - if (ret) { - NV_ERROR(drm, "unable to get AGP info: %d\n", ret); - return; - } - - /* see agp.h for the AGPSTAT_* modes available */ - mode.mode = get_agp_mode(drm, &info); - - ret = drm_agp_enable(dev, mode); - if (ret) { - NV_ERROR(drm, "unable to enable AGP: %d\n", ret); - return; - } - - drm->agp.stat = ENABLED; - drm->agp.base = info.aperture_base; - drm->agp.size = info.aperture_size; -#endif -} - -void -nouveau_agp_fini(struct nouveau_drm *drm) -{ -#if __OS_HAS_AGP - struct drm_device *dev = drm->dev; - if (dev->agp && dev->agp->acquired) - drm_agp_release(dev); -#endif -} diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.h b/drivers/gpu/drm/nouveau/nouveau_agp.h deleted file mode 100644 index b55c08652963a..0000000000000 --- a/drivers/gpu/drm/nouveau/nouveau_agp.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __NOUVEAU_AGP_H__ -#define __NOUVEAU_AGP_H__ - -struct nouveau_drm; - -void nouveau_agp_reset(struct nouveau_drm *); -void nouveau_agp_init(struct nouveau_drm *); -void nouveau_agp_fini(struct nouveau_drm *); - -#endif diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c index 373fbd2d14ffb..15057b39491ca 100644 --- a/drivers/gpu/drm/nouveau/nouveau_bo.c +++ b/drivers/gpu/drm/nouveau/nouveau_bo.c @@ -576,10 +576,9 @@ nouveau_ttm_tt_create(struct ttm_bo_device *bdev, unsigned long size, { #if __OS_HAS_AGP struct nouveau_drm *drm = nouveau_bdev(bdev); - struct drm_device *dev = drm->dev; - if (drm->agp.stat == ENABLED) { - return ttm_agp_tt_create(bdev, dev->agp->bridge, size, + if (drm->agp.bridge) { + return ttm_agp_tt_create(bdev, drm->agp.bridge, size, page_flags, dummy_read); } #endif @@ -631,12 +630,12 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type, if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) man->func = &nouveau_gart_manager; else - if (drm->agp.stat != ENABLED) + if (!drm->agp.bridge) man->func = &nv04_gart_manager; else man->func = &ttm_bo_manager_func; - if (drm->agp.stat == ENABLED) { + if (drm->agp.bridge) { man->flags = TTM_MEMTYPE_FLAG_MAPPABLE; man->available_caching = TTM_PL_FLAG_UNCACHED | TTM_PL_FLAG_WC; @@ -1368,10 +1367,10 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem) return 0; case TTM_PL_TT: #if __OS_HAS_AGP - if (drm->agp.stat == ENABLED) { + if (drm->agp.bridge) { mem->bus.offset = mem->start << PAGE_SHIFT; mem->bus.base = drm->agp.base; - mem->bus.is_iomem = !drm->dev->agp->cant_use_aperture; + mem->bus.is_iomem = !drm->agp.cma; } #endif if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA || !node->memtype) @@ -1498,7 +1497,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm) return ttm_dma_populate(ttm_dma, dev->dev); #if __OS_HAS_AGP - if (drm->agp.stat == ENABLED) { + if (drm->agp.bridge) { return ttm_agp_tt_populate(ttm); } #endif @@ -1565,7 +1564,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm) } #if __OS_HAS_AGP - if (drm->agp.stat == ENABLED) { + if (drm->agp.bridge) { ttm_agp_tt_unpopulate(ttm); return; } diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c index f59c4f5716cc6..ff5e59db49db0 100644 --- a/drivers/gpu/drm/nouveau/nouveau_chan.c +++ b/drivers/gpu/drm/nouveau/nouveau_chan.c @@ -160,7 +160,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device, args.limit = device->info.ram_user - 1; } } else { - if (chan->drm->agp.stat == ENABLED) { + if (chan->drm->agp.bridge) { args.target = NV_DMA_V0_TARGET_AGP; args.access = NV_DMA_V0_ACCESS_RDWR; args.start = chan->drm->agp.base; @@ -328,7 +328,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart) args.start = 0; args.limit = cli->vm->mmu->limit - 1; } else - if (chan->drm->agp.stat == ENABLED) { + if (chan->drm->agp.bridge) { args.target = NV_DMA_V0_TARGET_AGP; args.access = NV_DMA_V0_ACCESS_RDWR; args.start = chan->drm->agp.base; diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c index 14a13486c27fe..ccefb645fd55d 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.c +++ b/drivers/gpu/drm/nouveau/nouveau_drm.c @@ -41,7 +41,6 @@ #include "nouveau_dma.h" #include "nouveau_ttm.h" #include "nouveau_gem.h" -#include "nouveau_agp.h" #include "nouveau_vga.h" #include "nouveau_sysfs.h" #include "nouveau_hwmon.h" @@ -423,7 +422,6 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags) nvif_mask(&drm->device.object, 0x00088080, 0x00000800, 0x00000000); nouveau_vga_init(drm); - nouveau_agp_init(drm); if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) { ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40), @@ -474,7 +472,6 @@ fail_dispctor: fail_bios: nouveau_ttm_fini(drm); fail_ttm: - nouveau_agp_fini(drm); nouveau_vga_fini(drm); fail_device: nvif_device_fini(&drm->device); @@ -500,7 +497,6 @@ nouveau_drm_unload(struct drm_device *dev) nouveau_bios_takedown(dev); nouveau_ttm_fini(drm); - nouveau_agp_fini(drm); nouveau_vga_fini(drm); nvif_device_fini(&drm->device); @@ -584,7 +580,6 @@ nouveau_do_suspend(struct drm_device *dev, bool runtime) if (ret) goto fail_client; - nouveau_agp_fini(drm); return 0; fail_client: @@ -609,13 +604,8 @@ nouveau_do_resume(struct drm_device *dev, bool runtime) struct nouveau_drm *drm = nouveau_drm(dev); struct nouveau_cli *cli; - NV_INFO(drm, "re-enabling device...\n"); - - nouveau_agp_reset(drm); - NV_INFO(drm, "resuming kernel object tree...\n"); nvif_client_resume(&drm->client.base); - nouveau_agp_init(drm); NV_INFO(drm, "resuming client object trees...\n"); if (drm->fence && nouveau_fence(drm)->resume) @@ -929,7 +919,6 @@ nouveau_driver_fops = { static struct drm_driver driver_stub = { .driver_features = - DRIVER_USE_AGP | DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER | DRIVER_KMS_LEGACY_CONTEXT, diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index f18710afcfd3b..7fb3a8ad12d7b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -111,13 +111,10 @@ struct nouveau_drm { struct list_head clients; struct { - enum { - UNKNOWN = 0, - DISABLE = 1, - ENABLED = 2 - } stat; + struct agp_bridge_data *bridge; u32 base; u32 size; + bool cma; } agp; /* TTM interface support */ diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c index ba9fd151bd281..3f0fb55cb4733 100644 --- a/drivers/gpu/drm/nouveau/nouveau_ttm.c +++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c @@ -336,13 +336,21 @@ int nouveau_ttm_init(struct nouveau_drm *drm) { struct nvkm_device *device = nvxx_device(&drm->device); + struct nvkm_pci *pci = device->pci; struct drm_device *dev = drm->dev; u32 bits; int ret; + if (pci && pci->agp.bridge) { + drm->agp.bridge = pci->agp.bridge; + drm->agp.base = pci->agp.base; + drm->agp.size = pci->agp.size; + drm->agp.cma = pci->agp.cma; + } + bits = nvxx_mmu(&drm->device)->dma_bits; if (nvxx_device(&drm->device)->func->pci) { - if (drm->agp.stat == ENABLED || + if (drm->agp.bridge || !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits))) bits = 32; @@ -386,7 +394,7 @@ nouveau_ttm_init(struct nouveau_drm *drm) device->func->resource_size(device, 1)); /* GART init */ - if (drm->agp.stat != ENABLED) { + if (!drm->agp.bridge) { drm->gem.gart_available = nvxx_mmu(&drm->device)->limit; } else { drm->gem.gart_available = drm->agp.size; diff --git a/drivers/gpu/drm/nouveau/nvkm/core/option.c b/drivers/gpu/drm/nouveau/nvkm/core/option.c index 98ebde3b72698..3e62cf8cde080 100644 --- a/drivers/gpu/drm/nouveau/nvkm/core/option.c +++ b/drivers/gpu/drm/nouveau/nvkm/core/option.c @@ -73,6 +73,24 @@ nvkm_boolopt(const char *optstr, const char *opt, bool value) return value; } +long +nvkm_longopt(const char *optstr, const char *opt, long value) +{ + long result = value; + int arglen; + char *s; + + optstr = nvkm_stropt(optstr, opt, &arglen); + if (optstr && (s = kstrndup(optstr, arglen, GFP_KERNEL))) { + int ret = kstrtol(s, 0, &value); + if (ret == 0) + result = value; + kfree(s); + } + + return result; +} + int nvkm_dbgopt(const char *optstr, const char *sub) { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild index a8e9b0fc447ea..99672c3d0bad7 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/Kbuild @@ -1,3 +1,4 @@ +nvkm-y += nvkm/subdev/pci/agp.o nvkm-y += nvkm/subdev/pci/base.o nvkm-y += nvkm/subdev/pci/nv04.o nvkm-y += nvkm/subdev/pci/nv40.o diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c new file mode 100644 index 0000000000000..814cb51cc8737 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.c @@ -0,0 +1,171 @@ +/* + * Copyright 2015 Nouveau Project + * + * 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 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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. + */ +#include "agp.h" +#ifdef __NVKM_PCI_AGP_H__ +#include + +struct nvkm_device_agp_quirk { + u16 hostbridge_vendor; + u16 hostbridge_device; + u16 chip_vendor; + u16 chip_device; + int mode; +}; + +static const struct nvkm_device_agp_quirk +nvkm_device_agp_quirks[] = { + /* VIA Apollo PRO133x / GeForce FX 5600 Ultra - fdo#20341 */ + { PCI_VENDOR_ID_VIA, 0x0691, PCI_VENDOR_ID_NVIDIA, 0x0311, 2 }, + {}, +}; + +void +nvkm_agp_fini(struct nvkm_pci *pci) +{ + if (pci->agp.acquired) { + agp_backend_release(pci->agp.bridge); + pci->agp.acquired = false; + } +} + +/* Ensure AGP controller is in a consistent state in case we need to + * execute the VBIOS DEVINIT scripts. + */ +void +nvkm_agp_preinit(struct nvkm_pci *pci) +{ + struct nvkm_device *device = pci->subdev.device; + u32 mode = nvkm_pci_rd32(pci, 0x004c); + u32 save[2]; + + /* First of all, disable fast writes, otherwise if it's already + * enabled in the AGP bridge and we disable the card's AGP + * controller we might be locking ourselves out of it. + */ + if ((mode | pci->agp.mode) & PCI_AGP_COMMAND_FW) { + mode = pci->agp.mode & ~PCI_AGP_COMMAND_FW; + agp_enable(pci->agp.bridge, mode); + } + + /* clear busmaster bit, and disable AGP */ + save[0] = nvkm_pci_rd32(pci, 0x0004); + nvkm_pci_wr32(pci, 0x0004, save[0] & ~0x00000004); + nvkm_pci_wr32(pci, 0x004c, 0x00000000); + + /* reset PGRAPH, PFIFO and PTIMER */ + save[1] = nvkm_mask(device, 0x000200, 0x00011100, 0x00000000); + nvkm_mask(device, 0x000200, 0x00011100, save[1]); + + /* and restore busmaster bit (gives effect of resetting AGP) */ + nvkm_pci_wr32(pci, 0x0004, save[0]); +} + +int +nvkm_agp_init(struct nvkm_pci *pci) +{ + if (!agp_backend_acquire(pci->pdev)) { + nvkm_error(&pci->subdev, "failed to acquire agp\n"); + return -ENODEV; + } + + agp_enable(pci->agp.bridge, pci->agp.mode); + pci->agp.acquired = true; + return 0; +} + +void +nvkm_agp_dtor(struct nvkm_pci *pci) +{ + arch_phys_wc_del(pci->agp.mtrr); +} + +void +nvkm_agp_ctor(struct nvkm_pci *pci) +{ + const struct nvkm_device_agp_quirk *quirk = nvkm_device_agp_quirks; + struct nvkm_subdev *subdev = &pci->subdev; + struct nvkm_device *device = subdev->device; + struct agp_kern_info info; + int mode = -1; + +#ifdef __powerpc__ + /* Disable AGP by default on all PowerPC machines for now -- At + * least some UniNorth-2 AGP bridges are known to be broken: + * DMA from the host to the card works just fine, but writeback + * from the card to the host goes straight to memory + * untranslated bypassing that GATT somehow, making them quite + * painful to deal with... + */ + mode = 0; +#endif + mode = nvkm_longopt(device->cfgopt, "NvAGP", mode); + + /* acquire bridge temporarily, so that we can copy its info */ + if (!(pci->agp.bridge = agp_backend_acquire(pci->pdev))) { + nvkm_warn(subdev, "failed to acquire agp\n"); + return; + } + agp_copy_info(pci->agp.bridge, &info); + agp_backend_release(pci->agp.bridge); + + pci->agp.mode = info.mode; + pci->agp.base = info.aper_base; + pci->agp.size = info.aper_size * 1024 * 1024; + pci->agp.cma = info.cant_use_aperture; + pci->agp.mtrr = -1; + + /* determine if bridge + chipset combination needs a workaround */ + while (quirk->hostbridge_vendor) { + if (info.device->vendor == quirk->hostbridge_vendor && + info.device->device == quirk->hostbridge_device && + pci->pdev->vendor == quirk->chip_vendor && + pci->pdev->device == quirk->chip_device) { + nvkm_info(subdev, "forcing default agp mode to %dX, " + "use NvAGP= to override\n", + quirk->mode); + mode = quirk->mode; + break; + } + quirk++; + } + + /* apply quirk / user-specified mode */ + if (mode >= 1) { + if (pci->agp.mode & 0x00000008) + mode /= 4; /* AGPv3 */ + pci->agp.mode &= ~0x00000007; + pci->agp.mode |= (mode & 0x7); + } else + if (mode == 0) { + pci->agp.bridge = NULL; + return; + } + + /* fast writes appear to be broken on nv18, they make the card + * lock up randomly. + */ + if (device->chipset == 0x18) + pci->agp.mode &= ~PCI_AGP_COMMAND_FW; + + pci->agp.mtrr = arch_phys_wc_add(pci->agp.base, pci->agp.size); +} +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h new file mode 100644 index 0000000000000..df2dd08363ad4 --- /dev/null +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/agp.h @@ -0,0 +1,18 @@ +#include "priv.h" +#if defined(CONFIG_AGP) || (defined(CONFIG_AGP_MODULE) && defined(MODULE)) +#ifndef __NVKM_PCI_AGP_H__ +#define __NVKM_PCI_AGP_H__ + +void nvkm_agp_ctor(struct nvkm_pci *); +void nvkm_agp_dtor(struct nvkm_pci *); +void nvkm_agp_preinit(struct nvkm_pci *); +int nvkm_agp_init(struct nvkm_pci *); +void nvkm_agp_fini(struct nvkm_pci *); +#endif +#else +static inline void nvkm_agp_ctor(struct nvkm_pci *pci) {} +static inline void nvkm_agp_dtor(struct nvkm_pci *pci) {} +static inline void nvkm_agp_preinit(struct nvkm_pci *pci) {} +static inline int nvkm_agp_init(struct nvkm_pci *pci) { return -ENOSYS; } +static inline void nvkm_agp_fini(struct nvkm_pci *pci) {} +#endif diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c index e5e0d02f3d88e..d1c148e519228 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pci/base.c @@ -22,6 +22,7 @@ * Authors: Ben Skeggs */ #include "priv.h" +#include "agp.h" #include #include @@ -76,10 +77,24 @@ static int nvkm_pci_fini(struct nvkm_subdev *subdev, bool suspend) { struct nvkm_pci *pci = nvkm_pci(subdev); + if (pci->irq >= 0) { free_irq(pci->irq, pci); pci->irq = -1; }; + + if (pci->agp.bridge) + nvkm_agp_fini(pci); + + return 0; +} + +static int +nvkm_pci_preinit(struct nvkm_subdev *subdev) +{ + struct nvkm_pci *pci = nvkm_pci(subdev); + if (pci->agp.bridge) + nvkm_agp_preinit(pci); return 0; } @@ -90,6 +105,12 @@ nvkm_pci_init(struct nvkm_subdev *subdev) struct pci_dev *pdev = pci->pdev; int ret; + if (pci->agp.bridge) { + ret = nvkm_agp_init(pci); + if (ret) + return ret; + } + ret = request_irq(pdev->irq, nvkm_pci_intr, IRQF_SHARED, "nvkm", pci); if (ret) return ret; @@ -102,6 +123,7 @@ static void * nvkm_pci_dtor(struct nvkm_subdev *subdev) { struct nvkm_pci *pci = nvkm_pci(subdev); + nvkm_agp_dtor(pci); if (pci->msi) pci_disable_msi(pci->pdev); return nvkm_pci(subdev); @@ -110,6 +132,7 @@ nvkm_pci_dtor(struct nvkm_subdev *subdev) static const struct nvkm_subdev_func nvkm_pci_func = { .dtor = nvkm_pci_dtor, + .preinit = nvkm_pci_preinit, .init = nvkm_pci_init, .fini = nvkm_pci_fini, }; @@ -127,6 +150,9 @@ nvkm_pci_new_(const struct nvkm_pci_func *func, struct nvkm_device *device, pci->pdev = device->func->pci(device)->pdev; pci->irq = -1; + if (device->type == NVKM_DEVICE_AGP) + nvkm_agp_ctor(pci); + switch (pci->pdev->device & 0x0ff0) { case 0x00f0: case 0x02e0: -- GitLab From 43a70661eaa64aa4e36e421eee3b9ded3190837b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:23 +1000 Subject: [PATCH 5570/7006] drm/nouveau/tegra: merge platform setup from nouveau drm The copyright header in nvkm/engine/device/platform.c has been replaced with the NVIDIA one from drm/nouveau_platform.c, as most of the actual code is now theirs. Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/include/nvif/os.h | 3 + .../drm/nouveau/include/nvkm/core/device.h | 2 - .../gpu/drm/nouveau/include/nvkm/core/tegra.h | 20 ++ drivers/gpu/drm/nouveau/nouveau_platform.c | 224 +----------------- drivers/gpu/drm/nouveau/nouveau_platform.h | 37 +-- .../drm/nouveau/nvkm/engine/device/tegra.c | 181 +++++++++++++- .../gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c | 8 +- .../drm/nouveau/nvkm/subdev/instmem/gk20a.c | 20 +- .../gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c | 11 +- 9 files changed, 221 insertions(+), 285 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvif/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h index 97317f7fe4e5a..3accc99d8e0b9 100644 --- a/drivers/gpu/drm/nouveau/include/nvif/os.h +++ b/drivers/gpu/drm/nouveau/include/nvif/os.h @@ -25,10 +25,13 @@ #include #include #include +#include +#include #include #include +#include #ifndef ioread32_native #ifdef __BIG_ENDIAN diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h index 773951bfd200a..8f760002e4018 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h @@ -139,8 +139,6 @@ struct nvkm_device { struct nvkm_sw *sw; struct nvkm_engine *vic; struct nvkm_engine *vp; - - struct nouveau_platform_gpu *gpu; }; struct nvkm_subdev *nvkm_device_subdev(struct nvkm_device *, int index); diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h index 1755c2d30fcdf..5aa2480da25f5 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/core/tegra.h @@ -1,11 +1,31 @@ #ifndef __NVKM_DEVICE_TEGRA_H__ #define __NVKM_DEVICE_TEGRA_H__ #include +#include struct nvkm_device_tegra { struct nvkm_device device; struct platform_device *pdev; int irq; + + struct reset_control *rst; + struct clk *clk; + struct clk *clk_pwr; + + struct regulator *vdd; + + struct { + /* + * Protects accesses to mm from subsystems + */ + struct mutex mutex; + + struct nvkm_mm mm; + struct iommu_domain *domain; + unsigned long pgshift; + } iommu; + + int gpu_speedo; }; int nvkm_device_tegra_new(struct platform_device *, diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c index c03736bce9537..3eb665453165b 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.c +++ b/drivers/gpu/drm/nouveau/nouveau_platform.c @@ -19,234 +19,32 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "nouveau_drm.h" #include "nouveau_platform.h" -static int nouveau_platform_power_up(struct nouveau_platform_gpu *gpu) -{ - int err; - - err = regulator_enable(gpu->vdd); - if (err) - goto err_power; - - err = clk_prepare_enable(gpu->clk); - if (err) - goto err_clk; - err = clk_prepare_enable(gpu->clk_pwr); - if (err) - goto err_clk_pwr; - clk_set_rate(gpu->clk_pwr, 204000000); - udelay(10); - - reset_control_assert(gpu->rst); - udelay(10); - - err = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); - if (err) - goto err_clamp; - udelay(10); - - reset_control_deassert(gpu->rst); - udelay(10); - - return 0; - -err_clamp: - clk_disable_unprepare(gpu->clk_pwr); -err_clk_pwr: - clk_disable_unprepare(gpu->clk); -err_clk: - regulator_disable(gpu->vdd); -err_power: - return err; -} - -static int nouveau_platform_power_down(struct nouveau_platform_gpu *gpu) -{ - int err; - - reset_control_assert(gpu->rst); - udelay(10); - - clk_disable_unprepare(gpu->clk_pwr); - clk_disable_unprepare(gpu->clk); - udelay(10); - - err = regulator_disable(gpu->vdd); - if (err) - return err; - - return 0; -} - -#if IS_ENABLED(CONFIG_IOMMU_API) - -static void nouveau_platform_probe_iommu(struct device *dev, - struct nouveau_platform_gpu *gpu) -{ - int err; - unsigned long pgsize_bitmap; - - mutex_init(&gpu->iommu.mutex); - - if (iommu_present(&platform_bus_type)) { - gpu->iommu.domain = iommu_domain_alloc(&platform_bus_type); - if (IS_ERR(gpu->iommu.domain)) - goto error; - - /* - * A IOMMU is only usable if it supports page sizes smaller - * or equal to the system's PAGE_SIZE, with a preference if - * both are equal. - */ - pgsize_bitmap = gpu->iommu.domain->ops->pgsize_bitmap; - if (pgsize_bitmap & PAGE_SIZE) { - gpu->iommu.pgshift = PAGE_SHIFT; - } else { - gpu->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK); - if (gpu->iommu.pgshift == 0) { - dev_warn(dev, "unsupported IOMMU page size\n"); - goto free_domain; - } - gpu->iommu.pgshift -= 1; - } - - err = iommu_attach_device(gpu->iommu.domain, dev); - if (err) - goto free_domain; - - err = nvkm_mm_init(&gpu->iommu._mm, 0, - (1ULL << 40) >> gpu->iommu.pgshift, 1); - if (err) - goto detach_device; - - gpu->iommu.mm = &gpu->iommu._mm; - } - - return; - -detach_device: - iommu_detach_device(gpu->iommu.domain, dev); - -free_domain: - iommu_domain_free(gpu->iommu.domain); - -error: - gpu->iommu.domain = NULL; - gpu->iommu.pgshift = 0; - dev_err(dev, "cannot initialize IOMMU MM\n"); -} - -static void nouveau_platform_remove_iommu(struct device *dev, - struct nouveau_platform_gpu *gpu) -{ - if (gpu->iommu.domain) { - nvkm_mm_fini(&gpu->iommu._mm); - iommu_detach_device(gpu->iommu.domain, dev); - iommu_domain_free(gpu->iommu.domain); - } -} - -#else - -static void nouveau_platform_probe_iommu(struct device *dev, - struct nouveau_platform_gpu *gpu) -{ -} - -static void nouveau_platform_remove_iommu(struct device *dev, - struct nouveau_platform_gpu *gpu) -{ -} - -#endif - static int nouveau_platform_probe(struct platform_device *pdev) { - struct nouveau_platform_gpu *gpu; struct nvkm_device *device; struct drm_device *drm; - int err; - - gpu = devm_kzalloc(&pdev->dev, sizeof(*gpu), GFP_KERNEL); - if (!gpu) - return -ENOMEM; - - gpu->vdd = devm_regulator_get(&pdev->dev, "vdd"); - if (IS_ERR(gpu->vdd)) - return PTR_ERR(gpu->vdd); - - gpu->rst = devm_reset_control_get(&pdev->dev, "gpu"); - if (IS_ERR(gpu->rst)) - return PTR_ERR(gpu->rst); - - gpu->clk = devm_clk_get(&pdev->dev, "gpu"); - if (IS_ERR(gpu->clk)) - return PTR_ERR(gpu->clk); - - gpu->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); - if (IS_ERR(gpu->clk_pwr)) - return PTR_ERR(gpu->clk_pwr); - - nouveau_platform_probe_iommu(&pdev->dev, gpu); - - err = nouveau_platform_power_up(gpu); - if (err) - return err; + int ret; drm = nouveau_platform_device_create(pdev, &device); - if (IS_ERR(drm)) { - err = PTR_ERR(drm); - goto power_down; - } + if (IS_ERR(drm)) + return PTR_ERR(drm); - device->gpu = gpu; - gpu->gpu_speedo = tegra_sku_info.gpu_speedo_value; - - err = drm_dev_register(drm, 0); - if (err < 0) - goto err_unref; + ret = drm_dev_register(drm, 0); + if (ret < 0) { + drm_dev_unref(drm); + return ret; + } return 0; - -err_unref: - drm_dev_unref(drm); - -power_down: - nouveau_platform_power_down(gpu); - nouveau_platform_remove_iommu(&pdev->dev, gpu); - - return err; } static int nouveau_platform_remove(struct platform_device *pdev) { - struct drm_device *drm_dev = platform_get_drvdata(pdev); - struct nouveau_drm *drm = nouveau_drm(drm_dev); - struct nvkm_device *device = nvxx_device(&drm->device); - struct nouveau_platform_gpu *gpu = device->gpu; - int err; - - nouveau_drm_device_remove(drm_dev); - - err = nouveau_platform_power_down(gpu); - - nouveau_platform_remove_iommu(&pdev->dev, gpu); - - return err; + struct drm_device *dev = platform_get_drvdata(pdev); + nouveau_drm_device_remove(dev); + return 0; } #if IS_ENABLED(CONFIG_OF) diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.h b/drivers/gpu/drm/nouveau/nouveau_platform.h index 7a4020f31cc52..f41056d0f5f49 100644 --- a/drivers/gpu/drm/nouveau/nouveau_platform.h +++ b/drivers/gpu/drm/nouveau/nouveau_platform.h @@ -19,44 +19,9 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ - #ifndef __NOUVEAU_PLATFORM_H__ #define __NOUVEAU_PLATFORM_H__ - -#include "core/device.h" -#include "core/mm.h" - -struct reset_control; -struct clk; -struct regulator; -struct iommu_domain; -struct platform_driver; - -struct nouveau_platform_gpu { - struct reset_control *rst; - struct clk *clk; - struct clk *clk_pwr; - - struct regulator *vdd; - - struct { - /* - * Protects accesses to mm from subsystems - */ - struct mutex mutex; - - struct nvkm_mm _mm; - /* - * Just points to _mm. We need this to avoid embedding - * struct nvkm_mm in os.h - */ - struct nvkm_mm *mm; - struct iommu_domain *domain; - unsigned long pgshift; - } iommu; - - int gpu_speedo; -}; +#include "nouveau_drm.h" extern struct platform_driver nouveau_platform_driver; #endif diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c index ada73e13d1af5..da57c8a606085 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/tegra.c @@ -1,5 +1,5 @@ /* - * Copyright 2015 Red Hat Inc. + * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -14,17 +14,138 @@ * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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: Ben Skeggs + * 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. */ #include #ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER #include "priv.h" +static int +nvkm_device_tegra_power_up(struct nvkm_device_tegra *tdev) +{ + int ret; + + ret = regulator_enable(tdev->vdd); + if (ret) + goto err_power; + + ret = clk_prepare_enable(tdev->clk); + if (ret) + goto err_clk; + ret = clk_prepare_enable(tdev->clk_pwr); + if (ret) + goto err_clk_pwr; + clk_set_rate(tdev->clk_pwr, 204000000); + udelay(10); + + reset_control_assert(tdev->rst); + udelay(10); + + ret = tegra_powergate_remove_clamping(TEGRA_POWERGATE_3D); + if (ret) + goto err_clamp; + udelay(10); + + reset_control_deassert(tdev->rst); + udelay(10); + + return 0; + +err_clamp: + clk_disable_unprepare(tdev->clk_pwr); +err_clk_pwr: + clk_disable_unprepare(tdev->clk); +err_clk: + regulator_disable(tdev->vdd); +err_power: + return ret; +} + +static int +nvkm_device_tegra_power_down(struct nvkm_device_tegra *tdev) +{ + reset_control_assert(tdev->rst); + udelay(10); + + clk_disable_unprepare(tdev->clk_pwr); + clk_disable_unprepare(tdev->clk); + udelay(10); + + return regulator_disable(tdev->vdd); +} + +static void +nvkm_device_tegra_probe_iommu(struct nvkm_device_tegra *tdev) +{ +#if IS_ENABLED(CONFIG_IOMMU_API) + struct device *dev = &tdev->pdev->dev; + unsigned long pgsize_bitmap; + int ret; + + mutex_init(&tdev->iommu.mutex); + + if (iommu_present(&platform_bus_type)) { + tdev->iommu.domain = iommu_domain_alloc(&platform_bus_type); + if (IS_ERR(tdev->iommu.domain)) + goto error; + + /* + * A IOMMU is only usable if it supports page sizes smaller + * or equal to the system's PAGE_SIZE, with a preference if + * both are equal. + */ + pgsize_bitmap = tdev->iommu.domain->ops->pgsize_bitmap; + if (pgsize_bitmap & PAGE_SIZE) { + tdev->iommu.pgshift = PAGE_SHIFT; + } else { + tdev->iommu.pgshift = fls(pgsize_bitmap & ~PAGE_MASK); + if (tdev->iommu.pgshift == 0) { + dev_warn(dev, "unsupported IOMMU page size\n"); + goto free_domain; + } + tdev->iommu.pgshift -= 1; + } + + ret = iommu_attach_device(tdev->iommu.domain, dev); + if (ret) + goto free_domain; + + ret = nvkm_mm_init(&tdev->iommu.mm, 0, + (1ULL << 40) >> tdev->iommu.pgshift, 1); + if (ret) + goto detach_device; + } + + return; + +detach_device: + iommu_detach_device(tdev->iommu.domain, dev); + +free_domain: + iommu_domain_free(tdev->iommu.domain); + +error: + tdev->iommu.domain = NULL; + tdev->iommu.pgshift = 0; + dev_err(dev, "cannot initialize IOMMU MM\n"); +#endif +} + +static void +nvkm_device_tegra_remove_iommu(struct nvkm_device_tegra *tdev) +{ +#if IS_ENABLED(CONFIG_IOMMU_API) + if (tdev->iommu.domain) { + nvkm_mm_fini(&tdev->iommu.mm); + iommu_detach_device(tdev->iommu.domain, tdev->device.dev); + iommu_domain_free(tdev->iommu.domain); + } +#endif +} + static struct nvkm_device_tegra * nvkm_device_tegra(struct nvkm_device *device) { @@ -95,9 +216,19 @@ nvkm_device_tegra_init(struct nvkm_device *device) return 0; } +static void * +nvkm_device_tegra_dtor(struct nvkm_device *device) +{ + struct nvkm_device_tegra *tdev = nvkm_device_tegra(device); + nvkm_device_tegra_power_down(tdev); + nvkm_device_tegra_remove_iommu(tdev); + return tdev; +} + static const struct nvkm_device_func nvkm_device_tegra_func = { .tegra = nvkm_device_tegra, + .dtor = nvkm_device_tegra_dtor, .init = nvkm_device_tegra_init, .fini = nvkm_device_tegra_fini, .resource_addr = nvkm_device_tegra_resource_addr, @@ -112,6 +243,7 @@ nvkm_device_tegra_new(struct platform_device *pdev, struct nvkm_device **pdevice) { struct nvkm_device_tegra *tdev; + int ret; if (!(tdev = kzalloc(sizeof(*tdev), GFP_KERNEL))) return -ENOMEM; @@ -119,10 +251,37 @@ nvkm_device_tegra_new(struct platform_device *pdev, tdev->pdev = pdev; tdev->irq = -1; - return nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev, - NVKM_DEVICE_TEGRA, pdev->id, NULL, - cfg, dbg, detect, mmio, subdev_mask, - &tdev->device); + tdev->vdd = devm_regulator_get(&pdev->dev, "vdd"); + if (IS_ERR(tdev->vdd)) + return PTR_ERR(tdev->vdd); + + tdev->rst = devm_reset_control_get(&pdev->dev, "gpu"); + if (IS_ERR(tdev->rst)) + return PTR_ERR(tdev->rst); + + tdev->clk = devm_clk_get(&pdev->dev, "gpu"); + if (IS_ERR(tdev->clk)) + return PTR_ERR(tdev->clk); + + tdev->clk_pwr = devm_clk_get(&pdev->dev, "pwr"); + if (IS_ERR(tdev->clk_pwr)) + return PTR_ERR(tdev->clk_pwr); + + nvkm_device_tegra_probe_iommu(tdev); + + ret = nvkm_device_tegra_power_up(tdev); + if (ret) + return ret; + + tdev->gpu_speedo = tegra_sku_info.gpu_speedo_value; + ret = nvkm_device_ctor(&nvkm_device_tegra_func, NULL, &pdev->dev, + NVKM_DEVICE_TEGRA, pdev->id, NULL, + cfg, dbg, detect, mmio, subdev_mask, + &tdev->device); + if (ret) + return ret; + + return 0; } #else int diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c index 6a74ce3730d05..254094ab7fb8f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c @@ -25,12 +25,9 @@ #define gk20a_clk(p) container_of((p), struct gk20a_clk, base) #include "priv.h" +#include #include -#ifdef __KERNEL__ -#include -#endif - #define MHZ (1000 * 1000) #define MASK(w) ((1 << w) - 1) @@ -649,6 +646,7 @@ gk20a_clk = { int gk20a_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) { + struct nvkm_device_tegra *tdev = device->func->tegra(device); struct gk20a_clk *clk; int ret, i; @@ -663,7 +661,7 @@ gk20a_clk_new(struct nvkm_device *device, int index, struct nvkm_clk **pclk) } clk->params = &gk20a_pllg_params; - clk->parent_rate = clk_get_rate(device->gpu->clk); + clk->parent_rate = clk_get_rate(tdev->clk); ret = nvkm_clk_ctor(&gk20a_clk, device, index, true, &clk->base); nvkm_info(&clk->base.subdev, "parent clock rate: %d Mhz\n", diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c index 5ef04b72a80ae..cd7feb1b25f69 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/gk20a.c @@ -42,14 +42,9 @@ #include #include +#include #include -#ifdef __KERNEL__ -#include -#include -#include -#endif - #define gk20a_instobj(p) container_of((p), struct gk20a_instobj, memory) struct gk20a_instobj { @@ -423,8 +418,9 @@ gk20a_instmem = { int gk20a_instmem_new(struct nvkm_device *device, int index, - struct nvkm_instmem **pimem) + struct nvkm_instmem **pimem) { + struct nvkm_device_tegra *tdev = device->func->tegra(device); struct gk20a_instmem *imem; if (!(imem = kzalloc(sizeof(*imem), GFP_KERNEL))) @@ -433,11 +429,11 @@ gk20a_instmem_new(struct nvkm_device *device, int index, spin_lock_init(&imem->lock); *pimem = &imem->base; - if (device->gpu->iommu.domain) { - imem->domain = device->gpu->iommu.domain; - imem->mm = device->gpu->iommu.mm; - imem->iommu_pgshift = device->gpu->iommu.pgshift; - imem->mm_mutex = &device->gpu->iommu.mutex; + if (tdev->iommu.domain) { + imem->domain = tdev->iommu.domain; + imem->mm = &tdev->iommu.mm; + imem->iommu_pgshift = tdev->iommu.pgshift; + imem->mm_mutex = &tdev->iommu.mutex; nvkm_info(&imem->base.subdev, "using IOMMU\n"); } else { diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c index 01394a05e9d8c..fd56c64760643 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c @@ -22,9 +22,7 @@ #define gk20a_volt(p) container_of((p), struct gk20a_volt, base) #include "priv.h" -#ifdef __KERNEL__ -#include -#endif +#include struct cvb_coef { int c0; @@ -159,6 +157,7 @@ gk20a_volt = { int gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) { + struct nvkm_device_tegra *tdev = device->func->tegra(device); struct gk20a_volt *volt; int i, uv; @@ -168,10 +167,10 @@ gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) nvkm_volt_ctor(&gk20a_volt, device, index, &volt->base); *pvolt = &volt->base; - uv = regulator_get_voltage(device->gpu->vdd); + uv = regulator_get_voltage(tdev->vdd); nvkm_info(&volt->base.subdev, "The default voltage is %duV\n", uv); - volt->vdd = device->gpu->vdd; + volt->vdd = tdev->vdd; volt->base.vid_nr = ARRAY_SIZE(gk20a_cvb_coef); nvkm_debug(&volt->base.subdev, "%s - vid_nr = %d\n", __func__, @@ -180,7 +179,7 @@ gk20a_volt_new(struct nvkm_device *device, int index, struct nvkm_volt **pvolt) volt->base.vid[i].vid = i; volt->base.vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i], - device->gpu->gpu_speedo); + tdev->gpu_speedo); nvkm_debug(&volt->base.subdev, "%2d: vid=%d, uv=%d\n", i, volt->base.vid[i].vid, volt->base.vid[i].uv); } -- GitLab From a3c1ff87cfe27f99de58c153eb9d42dcfdbfa59b Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 20 Aug 2015 14:54:23 +1000 Subject: [PATCH 5571/7006] drm/nouveau: bump driver version for release Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nouveau_drm.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h index 7fb3a8ad12d7b..3c902c24a8dde 100644 --- a/drivers/gpu/drm/nouveau/nouveau_drm.h +++ b/drivers/gpu/drm/nouveau/nouveau_drm.h @@ -9,8 +9,8 @@ #define DRIVER_DATE "20120801" #define DRIVER_MAJOR 1 -#define DRIVER_MINOR 2 -#define DRIVER_PATCHLEVEL 2 +#define DRIVER_MINOR 3 +#define DRIVER_PATCHLEVEL 0 /* * 1.1.1: @@ -30,6 +30,9 @@ * - allow concurrent access to bo's mapped read/write. * 1.2.2: * - add NOUVEAU_GEM_DOMAIN_COHERENT flag + * 1.3.0: + * - NVIF ABI modified, safe because only (current) users are test + * programs that get directly linked with NVKM. */ #include -- GitLab From 259800135c654a098d9f0adfdd3d1f20eef1f231 Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Fri, 28 Aug 2015 11:57:00 +1000 Subject: [PATCH 5572/7006] powerpc/eeh: Fix fenced PHB caused by eeh_slot_error_detail() The config space of some PCI devices can't be accessed when their PEs are in frozen state. Otherwise, fenced PHB might be seen. Those PEs are identified with flag EEH_PE_CFG_RESTRICTED, meaing EEH_PE_CFG_BLOCKED is set automatically when the PE is put to frozen state (EEH_PE_ISOLATED). eeh_slot_error_detail() restores PCI device BARs with eeh_pe_restore_bars(), which then calls eeh_ops->restore_config() to reinitialize the PCI device in (OPAL) firmware. eeh_ops->restore_config() produces PCI config access that causes fenced PHB. The problem was reported on below adapter: 0001:01:00.0 0200: 14e4:168e (rev 10) 0001:01:00.0 Ethernet controller: Broadcom Corporation \ NetXtreme II BCM57810 10 Gigabit Ethernet (rev 10) This fixes the issue by skipping eeh_pe_restore_bars() in eeh_slot_error_detail() when EEH_PE_CFG_BLOCKED is set for the PE. Fixes: b6541db1 ("powerpc/eeh: Block PCI config access upon frozen PE") Cc: stable@vger.kernel.org # v4.0+ Reported-by: Manvanthara B. Puttashankar Signed-off-by: Gavin Shan Signed-off-by: Michael Ellerman --- arch/powerpc/kernel/eeh.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/kernel/eeh.c b/arch/powerpc/kernel/eeh.c index 58c598400028c..e968533e3e057 100644 --- a/arch/powerpc/kernel/eeh.c +++ b/arch/powerpc/kernel/eeh.c @@ -308,11 +308,26 @@ void eeh_slot_error_detail(struct eeh_pe *pe, int severity) if (!(pe->type & EEH_PE_PHB)) { if (eeh_has_flag(EEH_ENABLE_IO_FOR_LOG)) eeh_pci_enable(pe, EEH_OPT_THAW_MMIO); + + /* + * The config space of some PCI devices can't be accessed + * when their PEs are in frozen state. Otherwise, fenced + * PHB might be seen. Those PEs are identified with flag + * EEH_PE_CFG_RESTRICTED, indicating EEH_PE_CFG_BLOCKED + * is set automatically when the PE is put to EEH_PE_ISOLATED. + * + * Restoring BARs possibly triggers PCI config access in + * (OPAL) firmware and then causes fenced PHB. If the + * PCI config is blocked with flag EEH_PE_CFG_BLOCKED, it's + * pointless to restore BARs and dump config space. + */ eeh_ops->configure_bridge(pe); - eeh_pe_restore_bars(pe); + if (!(pe->state & EEH_PE_CFG_BLOCKED)) { + eeh_pe_restore_bars(pe); - pci_regs_buf[0] = 0; - eeh_pe_traverse(pe, eeh_dump_pe_log, &loglen); + pci_regs_buf[0] = 0; + eeh_pe_traverse(pe, eeh_dump_pe_log, &loglen); + } } eeh_ops->get_log(pe, severity, pci_regs_buf, loglen); -- GitLab From 6ef41cf6f721573d286a06ca35a9f1e370637d51 Mon Sep 17 00:00:00 2001 From: yalin wang Date: Tue, 25 Aug 2015 16:15:13 +0800 Subject: [PATCH 5573/7006] dmaengine :ipu: change ipu_irq_handler() to remove compile warning Change ipu_irq_handler() to avoid gcc warning: drivers/dma/ipu/ipu_irq.c:305:4: warning: 'irq' may be used uninitialized in this function [-Wmaybe-uninitialized] generic_handle_irq(irq); Signed-off-by: yalin wang Signed-off-by: Vinod Koul --- drivers/dma/ipu/ipu_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/dma/ipu/ipu_irq.c b/drivers/dma/ipu/ipu_irq.c index 7489d2a5d246f..4768a829253a5 100644 --- a/drivers/dma/ipu/ipu_irq.c +++ b/drivers/dma/ipu/ipu_irq.c @@ -286,7 +286,7 @@ static void ipu_irq_handler(unsigned int __irq, struct irq_desc *desc) raw_spin_unlock(&bank_lock); while ((line = ffs(status))) { struct ipu_irq_map *map; - unsigned int irq; + unsigned int irq = NO_IRQ; line--; status &= ~(1UL << line); -- GitLab From ab98193dace971f4742eebb5103212e23bb392f5 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 26 Aug 2015 14:16:27 -0700 Subject: [PATCH 5574/7006] dmaengine: ioatdma: add Broadwell EP ioatdma PCI dev IDs Adding the Broadwell Xeon ioatdma PCI device IDs and related bits. This is still IOATDMA 3.2 based hw. Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/hw.h | 11 +++++++++++ drivers/dma/ioat/init.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h index ec64aced5655a..690e3b4f82022 100644 --- a/drivers/dma/ioat/hw.h +++ b/drivers/dma/ioat/hw.h @@ -53,6 +53,17 @@ #define PCI_DEVICE_ID_INTEL_IOAT_BDXDE2 0x6f52 #define PCI_DEVICE_ID_INTEL_IOAT_BDXDE3 0x6f53 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX0 0x6f20 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX1 0x6f21 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX2 0x6f22 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX3 0x6f23 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX4 0x6f24 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX5 0x6f25 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX6 0x6f26 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX7 0x6f27 +#define PCI_DEVICE_ID_INTEL_IOAT_BDX8 0x6f2e +#define PCI_DEVICE_ID_INTEL_IOAT_BDX9 0x6f2f + #define IOAT_VER_1_2 0x12 /* Version 1.2 */ #define IOAT_VER_2_0 0x20 /* Version 2.0 */ #define IOAT_VER_3_0 0x30 /* Version 3.0 */ diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 60a7c3211e0d4..1c3c9b0abf4e9 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -93,6 +93,17 @@ static struct pci_device_id ioat_pci_tbl[] = { { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW8) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_HSW9) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX0) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX1) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX2) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX3) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX4) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX5) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX6) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX7) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX8) }, + { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDX9) }, + /* I/OAT v3.3 platforms */ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD0) }, { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD1) }, @@ -219,10 +230,29 @@ static bool is_hsw_ioat(struct pci_dev *pdev) } +static bool is_bdx_ioat(struct pci_dev *pdev) +{ + switch (pdev->device) { + case PCI_DEVICE_ID_INTEL_IOAT_BDX0: + case PCI_DEVICE_ID_INTEL_IOAT_BDX1: + case PCI_DEVICE_ID_INTEL_IOAT_BDX2: + case PCI_DEVICE_ID_INTEL_IOAT_BDX3: + case PCI_DEVICE_ID_INTEL_IOAT_BDX4: + case PCI_DEVICE_ID_INTEL_IOAT_BDX5: + case PCI_DEVICE_ID_INTEL_IOAT_BDX6: + case PCI_DEVICE_ID_INTEL_IOAT_BDX7: + case PCI_DEVICE_ID_INTEL_IOAT_BDX8: + case PCI_DEVICE_ID_INTEL_IOAT_BDX9: + return true; + default: + return false; + } +} + static bool is_xeon_cb32(struct pci_dev *pdev) { return is_jf_ioat(pdev) || is_snb_ioat(pdev) || is_ivb_ioat(pdev) || - is_hsw_ioat(pdev); + is_hsw_ioat(pdev) || is_bdx_ioat(pdev); } bool is_bwd_ioat(struct pci_dev *pdev) -- GitLab From dfdd4ac66c2f921ecec730a2b24b0b13e10346b2 Mon Sep 17 00:00:00 2001 From: "Darrick J. Wong" Date: Fri, 28 Aug 2015 14:50:03 +1000 Subject: [PATCH 5575/7006] libxfs: bad magic number should set da block buffer error If xfs_da3_node_read_verify() doesn't recognize the magic number of a buffer it's just read, set the buffer error to -EFSCORRUPTED so that the error can be sent up to userspace. Without this patch we'll notice the bad magic eventually while trying to traverse or change the block, but we really ought to fail early in the verifier. Signed-off-by: Darrick J. Wong Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/libxfs/xfs_da_btree.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c index 2385f8cd08ab9..8951e34ab76a4 100644 --- a/fs/xfs/libxfs/xfs_da_btree.c +++ b/fs/xfs/libxfs/xfs_da_btree.c @@ -233,6 +233,7 @@ xfs_da3_node_read_verify( bp->b_ops->verify_read(bp); return; default: + xfs_buf_ioerror(bp, -EFSCORRUPTED); break; } -- GitLab From c9eb256eda4420c06bb10f5e8fbdbe1a34bc98e0 Mon Sep 17 00:00:00 2001 From: David Jeffery Date: Fri, 28 Aug 2015 14:50:45 +1000 Subject: [PATCH 5576/7006] xfs: return errors from partial I/O failures to files There is an issue with xfs's error reporting in some cases of I/O partially failing and partially succeeding. Calls like fsync() can report success even though not all I/O was successful in partial-failure cases such as one disk of a RAID0 array being offline. The issue can occur when there are more than one bio per xfs_ioend struct. Each call to xfs_end_bio() for a bio completing will write a value to ioend->io_error. If a successful bio completes after any failed bio, no error is reported do to it writing 0 over the error code set by any failed bio. The I/O error information is now lost and when the ioend is completed only success is reported back up the filesystem stack. xfs_end_bio() should only set ioend->io_error in the case of BIO_UPTODATE being clear. ioend->io_error is initialized to 0 at allocation so only needs to be updated by a failed bio. Also check that ioend->io_error is 0 so that the first error reported will be the error code returned. Cc: stable@vger.kernel.org Signed-off-by: David Jeffery Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_aops.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c index 3859f5e27a4dc..458fced2c0f9a 100644 --- a/fs/xfs/xfs_aops.c +++ b/fs/xfs/xfs_aops.c @@ -356,7 +356,8 @@ xfs_end_bio( { xfs_ioend_t *ioend = bio->bi_private; - ioend->io_error = test_bit(BIO_UPTODATE, &bio->bi_flags) ? 0 : error; + if (!ioend->io_error && !test_bit(BIO_UPTODATE, &bio->bi_flags)) + ioend->io_error = error; /* Toss bio and pass work off to an xfsdatad thread */ bio->bi_private = NULL; -- GitLab From 8774cf8bacd4e79b7c65cdf1208da264a9d436d2 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Fri, 28 Aug 2015 14:50:56 +1000 Subject: [PATCH 5577/7006] xfs: add mssing inode cache attempts counter increment Increasing the inode cache attempt counter was apparently dropped while refactoring the cache code and so stayed at the initial 0 value. Add the increment back to make the runtime stats more useful. Signed-off-by: Lucas Stach Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_icache.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index 76a9f27832827..0a326bd64d4e3 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c @@ -412,6 +412,8 @@ xfs_iget( if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount) return -EINVAL; + XFS_STATS_INC(xs_ig_attempts); + /* get the perag structure and ensure that it's inode capable */ pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino)); agino = XFS_INO_TO_AGINO(mp, ino); -- GitLab From 1a7ccad88d1bcebabc011b54a2f8615175e523fc Mon Sep 17 00:00:00 2001 From: Eric Sandeen Date: Fri, 28 Aug 2015 14:51:10 +1000 Subject: [PATCH 5578/7006] xfs: fix error gotos in xfs_setattr_nonsize As the code stands today, if xfs_trans_reserve() fails, we goto out_dqrele, which does not free the allocated transaction. Fix up the goto targets to undo everything properly. Addresses-Coverity-Id: 145571 Signed-off-by: Eric Sandeen Reviewed-by: Dave Chinner Signed-off-by: Dave Chinner --- fs/xfs/xfs_iops.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 766b23f86ce9f..8294132e6a3cd 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -609,7 +609,7 @@ xfs_setattr_nonsize( tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); if (error) - goto out_dqrele; + goto out_trans_cancel; xfs_ilock(ip, XFS_ILOCK_EXCL); @@ -640,7 +640,7 @@ xfs_setattr_nonsize( NULL, capable(CAP_FOWNER) ? XFS_QMOPT_FORCE_RES : 0); if (error) /* out of quota */ - goto out_trans_cancel; + goto out_unlock; } } @@ -729,10 +729,10 @@ xfs_setattr_nonsize( return 0; +out_unlock: + xfs_iunlock(ip, XFS_ILOCK_EXCL); out_trans_cancel: xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); -out_dqrele: xfs_qm_dqrele(udqp); xfs_qm_dqrele(gdqp); return error; -- GitLab From 4b9e78bd9f0efcf9e82b4886de7a4289dbf3cffe Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 28 Aug 2015 18:18:10 +1000 Subject: [PATCH 5579/7006] nouveau: fix powerpc build Reported-by: Ilia Mirkin on irc. Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c index 29a37f03ebf1c..bd60d7dd09f51 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c @@ -21,7 +21,7 @@ * */ #include "priv.h" - +#include #if defined(__powerpc__) struct priv { @@ -43,7 +43,7 @@ of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios) static void * of_init(struct nvkm_bios *bios, const char *name) { - struct pci_dev *pdev = bios->subdev.device->pdev; + struct pci_dev *pdev = bios->subdev.device->func->pci(bios->subdev.device)->pdev; struct device_node *dn; struct priv *priv; if (!(dn = pci_device_to_OF_node(pdev))) -- GitLab From 6aa6925cad06159dc6e25857991bbc4960821242 Mon Sep 17 00:00:00 2001 From: Yao-Wen Mao Date: Fri, 28 Aug 2015 16:33:25 +0800 Subject: [PATCH 5580/7006] ALSA: usb-audio: correct the value cache check. The check of cval->cached should be zero-based (including master channel). Signed-off-by: Yao-Wen Mao Cc: Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index fd5c49e948672..f494dced3c11e 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -2540,7 +2540,7 @@ static int restore_mixer_value(struct usb_mixer_elem_list *list) for (c = 0; c < MAX_CHANNELS; c++) { if (!(cval->cmask & (1 << c))) continue; - if (cval->cached & (1 << c)) { + if (cval->cached & (1 << (c + 1))) { err = snd_usb_set_cur_mix_value(cval, c + 1, idx, cval->cache_val[idx]); if (err < 0) -- GitLab From 90996511187d6282db6d02d3f97006b4dbb5c457 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 5 Aug 2015 15:42:35 -0700 Subject: [PATCH 5581/7006] MIPS: CPS: use 32b accesses to GCRs Commit b677bc03d757 ("MIPS: cps-vec: Use macros for various arithmetics and memory operations") replaced various load & store instructions through cps-vec.S with the PTR_L & PTR_S macros. However it was somewhat overzealous in doing so for CM GCR accesses, since the bit width of the CM doesn't necessarily match that of the CPU. The registers accessed (GCR_CL_COHERENCE & GCR_CL_ID) should be safe to simply always access using 32b instructions, so do so in order to avoid issues when using a 32b CM with a 64b CPU. Signed-off-by: Paul Burton Cc: Markos Chandras Cc: # 3.16+ Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: James Hogan Patchwork: https://patchwork.linux-mips.org/patch/10864/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cps-vec.S | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/cps-vec.S b/arch/mips/kernel/cps-vec.S index 1b6ca634e6465..9f71c06aebf63 100644 --- a/arch/mips/kernel/cps-vec.S +++ b/arch/mips/kernel/cps-vec.S @@ -152,7 +152,7 @@ dcache_done: /* Enter the coherent domain */ li t0, 0xff - PTR_S t0, GCR_CL_COHERENCE_OFS(v1) + sw t0, GCR_CL_COHERENCE_OFS(v1) ehb /* Jump to kseg0 */ @@ -302,7 +302,7 @@ LEAF(mips_cps_boot_vpes) PTR_L t0, 0(t0) /* Calculate a pointer to this cores struct core_boot_config */ - PTR_L t0, GCR_CL_ID_OFS(t0) + lw t0, GCR_CL_ID_OFS(t0) li t1, COREBOOTCFG_SIZE mul t0, t0, t1 PTR_LA t1, mips_cps_core_bootcfg -- GitLab From 92cffd56b21c825579f3b37bc7803e4c37073076 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Fri, 28 Aug 2015 20:33:58 +1000 Subject: [PATCH 5582/7006] drm/nouveau/dispnv04: fix build on powerpc align with mask code in overlay.c, Ben can clean the naming up later if necessary. Signed-off-by: Dave Airlie --- drivers/gpu/drm/nouveau/dispnv04/dfp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c index 522e91ab53607..429ab5e3025a6 100644 --- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c +++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c @@ -485,7 +485,7 @@ static void nv04_dfp_update_backlight(struct drm_encoder *encoder, int mode) { #ifdef __powerpc__ struct drm_device *dev = encoder->dev; - struct nvif_device *device = &nouveau_drm(dev)->device; + struct nvif_object *device = &nouveau_drm(dev)->device.object; /* BIOS scripts usually take care of the backlight, thanks * Apple for your consistency. -- GitLab From ba6a860d41ed3a377d61d59d7c7b08dd7455c686 Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Tue, 4 Aug 2015 13:48:55 +0800 Subject: [PATCH 5583/7006] cpuidle/coupled: Remove cpuidle_device::safe_state_index cpuidle_device::safe_state_index need to be initialized before use, it should be the same as cpuidle_driver::safe_state_index. We tackled this issue by removing the safe_state_index from the cpuidle_device structure and use the one in the cpuidle_driver structure instead. Suggested-by: Daniel Lezcano Signed-off-by: Xunlei Pang Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/coupled.c | 4 ++-- include/linux/cpuidle.h | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 7936dce4b8786..6493e4055abe3 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -473,7 +473,7 @@ int cpuidle_enter_state_coupled(struct cpuidle_device *dev, return entered_state; } entered_state = cpuidle_enter_state(dev, drv, - dev->safe_state_index); + drv->safe_state_index); local_irq_disable(); } @@ -521,7 +521,7 @@ retry: } entered_state = cpuidle_enter_state(dev, drv, - dev->safe_state_index); + drv->safe_state_index); local_irq_disable(); } diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h index d075d34279df3..786ad32631a67 100644 --- a/include/linux/cpuidle.h +++ b/include/linux/cpuidle.h @@ -84,7 +84,6 @@ struct cpuidle_device { struct list_head device_list; #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED - int safe_state_index; cpumask_t coupled_cpus; struct cpuidle_coupled *coupled; #endif -- GitLab From 4c1ed5a6079078699128064664913ae7b079648f Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Tue, 4 Aug 2015 13:48:56 +0800 Subject: [PATCH 5584/7006] cpuidle/coupled: Remove redundant 'dev' argument of cpuidle_state_is_coupled() For cpuidle_state_is_coupled(), 'dev' is not used, so remove it. Signed-off-by: Xunlei Pang Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/coupled.c | 4 +--- drivers/cpuidle/cpuidle.c | 4 ++-- drivers/cpuidle/cpuidle.h | 7 +++---- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 6493e4055abe3..1523e2d745eb5 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -176,14 +176,12 @@ void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a) /** * cpuidle_state_is_coupled - check if a state is part of a coupled set - * @dev: struct cpuidle_device for the current cpu * @drv: struct cpuidle_driver for the platform * @state: index of the target state in drv->states * * Returns true if the target state is coupled with cpus besides this one */ -bool cpuidle_state_is_coupled(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int state) +bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state) { return drv->states[state].flags & CPUIDLE_FLAG_COUPLED; } diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 48b7228563ad7..fe79cafb0f14c 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -210,7 +210,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, tick_broadcast_exit(); } - if (!cpuidle_state_is_coupled(dev, drv, entered_state)) + if (!cpuidle_state_is_coupled(drv, entered_state)) local_irq_enable(); diff = ktime_to_us(ktime_sub(time_end, time_start)); @@ -259,7 +259,7 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev) int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev, int index) { - if (cpuidle_state_is_coupled(dev, drv, index)) + if (cpuidle_state_is_coupled(drv, index)) return cpuidle_enter_state_coupled(dev, drv, index); return cpuidle_enter_state(dev, drv, index); } diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index ee97e9672ecfe..178c5ad3d5687 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -34,15 +34,14 @@ extern int cpuidle_add_sysfs(struct cpuidle_device *dev); extern void cpuidle_remove_sysfs(struct cpuidle_device *dev); #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED -bool cpuidle_state_is_coupled(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int state); +bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state); int cpuidle_enter_state_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int next_state); int cpuidle_coupled_register_device(struct cpuidle_device *dev); void cpuidle_coupled_unregister_device(struct cpuidle_device *dev); #else -static inline bool cpuidle_state_is_coupled(struct cpuidle_device *dev, - struct cpuidle_driver *drv, int state) +static inline +bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state) { return false; } -- GitLab From 68fa9f0ab1b61cfc7deee699da8b5b5cb12f7a58 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 17 Aug 2015 19:20:20 +0530 Subject: [PATCH 5585/7006] PM / OPP: Fix static checker warning (broken 64bit big endian systems) Dan Carpenter reported (generated with static checker): drivers/base/power/opp.c:949 _opp_add_static_v2() warn: passing casted pointer '&new_opp->clock_latency_ns' to 'of_property_read_u32()' 64 vs 32. This code will break on 64 bit, big endian machines. Fix this by reading the value in a u32 type variable first and then assigning it to the unsigned long variable. Reported-by: Dan Carpenter Suggested-by: Stephen Boyd Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 4d6c4576f7ae0..803d8b7ced895 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -918,6 +918,7 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) struct device_opp *dev_opp; struct dev_pm_opp *new_opp; u64 rate; + u32 val; int ret; /* Hold our list modification lock here */ @@ -946,14 +947,16 @@ static int _opp_add_static_v2(struct device *dev, struct device_node *np) new_opp->np = np; new_opp->dynamic = false; new_opp->available = true; - of_property_read_u32(np, "clock-latency-ns", - (u32 *)&new_opp->clock_latency_ns); + + if (!of_property_read_u32(np, "clock-latency-ns", &val)) + new_opp->clock_latency_ns = val; ret = opp_get_microvolt(new_opp, dev); if (ret) goto free_opp; - of_property_read_u32(np, "opp-microamp", (u32 *)&new_opp->u_amp); + if (!of_property_read_u32(new_opp->np, "opp-microamp", &val)) + new_opp->u_amp = val; ret = _opp_add(dev, new_opp, dev_opp); if (ret) -- GitLab From 50a3cb04a5f9cd5323a76db9ee409a7f3004259a Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 12 Aug 2015 15:59:39 +0530 Subject: [PATCH 5586/7006] PM / OPP: Drop unlikely before IS_ERR(_OR_NULL) IS_ERR(_OR_NULL) already contain an 'unlikely' compiler flag and there is no need to do that again from its callers. Drop it. Acked-by: Pavel Machek Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 803d8b7ced895..bb703b5ebaff9 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -204,7 +204,7 @@ static struct device_opp *_find_device_opp(struct device *dev) { struct device_opp *dev_opp; - if (unlikely(IS_ERR_OR_NULL(dev))) { + if (IS_ERR_OR_NULL(dev)) { pr_err("%s: Invalid parameters\n", __func__); return ERR_PTR(-EINVAL); } @@ -239,7 +239,7 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp) opp_rcu_lockdep_assert(); tmp_opp = rcu_dereference(opp); - if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) + if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) pr_err("%s: Invalid parameters\n", __func__); else v = tmp_opp->u_volt; @@ -271,7 +271,7 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp) opp_rcu_lockdep_assert(); tmp_opp = rcu_dereference(opp); - if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available) + if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) pr_err("%s: Invalid parameters\n", __func__); else f = tmp_opp->rate; -- GitLab From 56d4a3814690a62a3fd9724844e23ea152ce938c Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 20 Aug 2015 11:53:27 +0200 Subject: [PATCH 5587/7006] scripts: add stackusage script The current checkstack.pl script has a few problems, stemming from the overly simplistic attempt at parsing objdump output with regular expressions: For example, on x86_64 it doesn't take the push instruction into account, making it consistently underestimate the real stack use, and it also doesn't capture stack pointer adjustments of exactly 128 bytes [1]. Since newer gcc (>= 4.6) knows about -fstack-usage, we might as well take the information straight from the horse's mouth. This patch introduces scripts/stackusage, which is a simple wrapper for running make with KCFLAGS set to -fstack-usage. Example use is scripts/stackusage -o out.su -j8 lib/ The script understands "-o foo" for writing to 'foo' and -h for a trivial help text; anything else is passed to make. Afterwards, we find all newly created .su files, massage them a little, sort by stack use and write the result to a single output file. Note that the function names printed by (at least) gcc 4.7 are sometimes useless. For example, the first three lines of out.su generated above are ./lib/decompress_bunzip2.c:155 get_next_block 448 static ./lib/decompress_unlzma.c:537 unlzma 336 static ./lib/vsprintf.c:616 8 304 static That function '8' is really the static symbol_string(), but it has been subject to 'interprocedural scalar replacement of aggregates', so its name in the object file is 'symbol_string.isra.8'. gcc 5.0 doesn't have this problem; it uses the full name as seen in the object file. [1] Since gcc encodes that by 48 83 c4 80 add $0xffffffffffffff80,%rsp and not 48 81 ec 80 00 00 00 sub $0x80,%rsp since -128 fits in an imm8. Signed-off-by: Rasmus Villemoes Signed-off-by: Michal Marek --- scripts/stackusage | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100755 scripts/stackusage diff --git a/scripts/stackusage b/scripts/stackusage new file mode 100755 index 0000000000000..8cf26640ef8a9 --- /dev/null +++ b/scripts/stackusage @@ -0,0 +1,33 @@ +#!/bin/sh + +outfile="" +now=`date +%s` + +while [ $# -gt 0 ] +do + case "$1" in + -o) + outfile="$2" + shift 2;; + -h) + echo "usage: $0 [-o outfile] " + exit 0;; + *) break;; + esac +done + +if [ -z "$outfile" ] +then + outfile=`mktemp --tmpdir stackusage.$$.XXXX` +fi + +KCFLAGS="${KCFLAGS} -fstack-usage" make "$@" + +# Prepend directory name to file names, remove column information, +# make file:line/function/size/type properly tab-separated. +find . -name '*.su' -newermt "@${now}" -print | \ + xargs perl -MFile::Basename -pe \ + '$d = dirname($ARGV); s#([^:]+:[0-9]+):[0-9]+:#$d/$1\t#;' | \ + sort -k3,3nr > "${outfile}" + +echo "$0: output written to ${outfile}" -- GitLab From e25572878a70d9cd84020f577b7c45583b9d42ae Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 20 Aug 2015 11:53:28 +0200 Subject: [PATCH 5588/7006] .gitignore: add *.su pattern Ignore the *.su files generated by using the gcc option -fstack-usage. Signed-off-by: Rasmus Villemoes Signed-off-by: Michal Marek --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 98b91fccff45f..f0efae5e2963d 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,7 @@ modules.builtin Module.symvers *.dwo +*.su # # Top-level generic files -- GitLab From d523b255de60880304038006de5f93f2db612ad6 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 20 Aug 2015 11:53:29 +0200 Subject: [PATCH 5589/7006] kbuild: remove *.su files generated by -fstack-usage Make sure 'make clean' removes *.su files generated by the gcc option -fstack-usage. Signed-off-by: Rasmus Villemoes Signed-off-by: Michal Marek --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 7ff1239f9cd2c..f618530a38701 100644 --- a/Makefile +++ b/Makefile @@ -1430,6 +1430,7 @@ clean: $(clean-dirs) \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ -o -name '*.ko.*' \ -o -name '*.dwo' \ + -o -name '*.su' \ -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ -o -name '*.symtypes' -o -name 'modules.order' \ -o -name modules.builtin -o -name '.tmp_*.o.*' \ -- GitLab From 5bbb9f753afe213aebc8dba30c7e2dbb73616b79 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Thu, 20 Aug 2015 11:53:30 +0200 Subject: [PATCH 5590/7006] scripts: add stackdelta script This adds a simple perl script for reading two files as produced by the stackusage script and computing the changes in stack usage. For example: $ scripts/stackusage -o /tmp/old.su CC=gcc-4.7 -j8 fs/ext4/ $ scripts/stackusage -o /tmp/new.su CC=gcc-5.0 -j8 fs/ext4/ $ scripts/stackdelta /tmp/{old,new}.su | sort -k5,5g shows that gcc 5.0 generally produces less stack-hungry code than gcc 4.7. Obviously, the script can also be used for measuring the effect of commits, .config tweaks or whatnot. Signed-off-by: Rasmus Villemoes Signed-off-by: Michal Marek --- scripts/stackdelta | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100755 scripts/stackdelta diff --git a/scripts/stackdelta b/scripts/stackdelta new file mode 100755 index 0000000000000..48eabf2f48f85 --- /dev/null +++ b/scripts/stackdelta @@ -0,0 +1,59 @@ +#!/usr/bin/perl + +# Read two files produced by the stackusage script, and show the +# delta between them. +# +# Currently, only shows changes for functions listed in both files. We +# could add an option to show also functions which have vanished or +# appeared (which would often be due to gcc making other inlining +# decisions). +# +# Another possible option would be a minimum absolute value for the +# delta. +# +# A third possibility is for sorting by delta, but that can be +# achieved by piping to sort -k5,5g. + +sub read_stack_usage_file { + my %su; + my $f = shift; + open(my $fh, '<', $f) + or die "cannot open $f: $!"; + while (<$fh>) { + chomp; + my ($file, $func, $size, $type) = split; + # Old versions of gcc (at least 4.7) have an annoying quirk in + # that a (static) function whose name has been changed into + # for example ext4_find_unwritten_pgoff.isra.11 will show up + # in the .su file with a name of just "11". Since such a + # numeric suffix is likely to change across different + # commits/compilers/.configs or whatever else we're trying to + # tweak, we can't really track those functions, so we just + # silently skip them. + # + # Newer gcc (at least 5.0) report the full name, so again, + # since the suffix is likely to change, we strip it. + next if $func =~ m/^[0-9]+$/; + $func =~ s/\..*$//; + # Line numbers are likely to change; strip those. + $file =~ s/:[0-9]+$//; + $su{"${file}\t${func}"} = {size => $size, type => $type}; + } + close($fh); + return \%su; +} + +@ARGV == 2 + or die "usage: $0 "; + +my $old = read_stack_usage_file($ARGV[0]); +my $new = read_stack_usage_file($ARGV[1]); +my @common = sort grep {exists $new->{$_}} keys %$old; +for (@common) { + my $x = $old->{$_}{size}; + my $y = $new->{$_}{size}; + my $delta = $y - $x; + if ($delta) { + printf "%s\t%d\t%d\t%+d\n", $_, $x, $y, $delta; + } +} -- GitLab From 11d932416ecada27ca7576dca7e74e23477df7ef Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 28 Aug 2015 10:04:03 +0800 Subject: [PATCH 5591/7006] ASoC: ics43432: fix platform_no_drv_owner.cocci warnings sound/soc/codecs/ics43432.c:66:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Ricard Wanderlof Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- sound/soc/codecs/ics43432.c | 1 - 1 file changed, 1 deletion(-) diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index 4f202c15df395..d217fed8b4234 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -63,7 +63,6 @@ MODULE_DEVICE_TABLE(of, ics43432_dt_ids); static struct platform_driver ics43432_driver = { .driver = { .name = "ics43432", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ics43432_ids), }, .probe = ics43432_probe, -- GitLab From 2f38bc8829b83aed3e2c5e6d43a430d39f1b0e1d Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 11:23:05 +0800 Subject: [PATCH 5592/7006] ASoC: ics43432: Fix module license Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/codecs/ics43432.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index d217fed8b4234..7c35c989acf0c 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -6,7 +6,7 @@ * * Copyright (c) 2015 Axis Communications AB * - * Licensed under GPL2. + * Licensed under GPL v2. */ #include @@ -73,4 +73,4 @@ module_platform_driver(ics43432_driver); MODULE_DESCRIPTION("ASoC ICS43432 driver"); MODULE_AUTHOR("Ricard Wanderlof "); -MODULE_LICENSE("GPLv2"); +MODULE_LICENSE("GPL v2"); -- GitLab From b37bfdaac914f4886b8be803703b12177eb873f6 Mon Sep 17 00:00:00 2001 From: Ricard Wanderlof Date: Fri, 28 Aug 2015 12:11:48 +0200 Subject: [PATCH 5593/7006] ASoC: ics43432: Fix build errors Fix build errors Signed-off-by: Ricard Wanderlof Signed-off-by: Mark Brown --- sound/soc/codecs/ics43432.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/codecs/ics43432.c b/sound/soc/codecs/ics43432.c index 7c35c989acf0c..dd850b93938d5 100644 --- a/sound/soc/codecs/ics43432.c +++ b/sound/soc/codecs/ics43432.c @@ -57,7 +57,7 @@ static const struct of_device_id ics43432_ids[] = { { .compatible = "invensense,ics43432", }, { } }; -MODULE_DEVICE_TABLE(of, ics43432_dt_ids); +MODULE_DEVICE_TABLE(of, ics43432_ids); #endif static struct platform_driver ics43432_driver = { -- GitLab From 637ce53a1b1c489ff0e92aa00b8376464f697dc5 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:48:35 +0800 Subject: [PATCH 5594/7006] ASoC: pxa-ssp: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/pxa/pxa-ssp.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index fbe2e93d6edca..3da485ec1de7f 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -813,14 +813,8 @@ static const struct of_device_id pxa_ssp_of_ids[] = { static int asoc_ssp_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &pxa_ssp_component, - &pxa_ssp_dai, 1); -} - -static int asoc_ssp_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &pxa_ssp_component, + &pxa_ssp_dai, 1); } static struct platform_driver asoc_ssp_driver = { @@ -830,7 +824,6 @@ static struct platform_driver asoc_ssp_driver = { }, .probe = asoc_ssp_probe, - .remove = asoc_ssp_remove, }; module_platform_driver(asoc_ssp_driver); -- GitLab From 2cf32b7b338086e9b85bb9fdd8aa398e89d83e9e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:49:44 +0800 Subject: [PATCH 5595/7006] ASoC: pxa2xx-i2s: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/pxa/pxa2xx-i2s.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/sound/soc/pxa/pxa2xx-i2s.c b/sound/soc/pxa/pxa2xx-i2s.c index e68290c15328a..6b4e400369107 100644 --- a/sound/soc/pxa/pxa2xx-i2s.c +++ b/sound/soc/pxa/pxa2xx-i2s.c @@ -367,19 +367,12 @@ static const struct snd_soc_component_driver pxa_i2s_component = { static int pxa2xx_i2s_drv_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &pxa_i2s_component, - &pxa_i2s_dai, 1); -} - -static int pxa2xx_i2s_drv_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &pxa_i2s_component, + &pxa_i2s_dai, 1); } static struct platform_driver pxa2xx_i2s_driver = { .probe = pxa2xx_i2s_drv_probe, - .remove = pxa2xx_i2s_drv_remove, .driver = { .name = "pxa2xx-i2s", -- GitLab From 92eca20bbeaa4ec1908bad8aeefcaa2d98e302ff Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:50:53 +0800 Subject: [PATCH 5596/7006] ASoC: sh: ssi: Convert to devm_snd_soc_register_component Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/sh/ssi.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/sound/soc/sh/ssi.c b/sound/soc/sh/ssi.c index ab13146e4f826..89ed1b107ac52 100644 --- a/sound/soc/sh/ssi.c +++ b/sound/soc/sh/ssi.c @@ -385,14 +385,9 @@ static const struct snd_soc_component_driver sh4_ssi_component = { static int sh4_soc_dai_probe(struct platform_device *pdev) { - return snd_soc_register_component(&pdev->dev, &sh4_ssi_component, - sh4_ssi_dai, ARRAY_SIZE(sh4_ssi_dai)); -} - -static int sh4_soc_dai_remove(struct platform_device *pdev) -{ - snd_soc_unregister_component(&pdev->dev); - return 0; + return devm_snd_soc_register_component(&pdev->dev, &sh4_ssi_component, + sh4_ssi_dai, + ARRAY_SIZE(sh4_ssi_dai)); } static struct platform_driver sh4_ssi_driver = { @@ -401,7 +396,6 @@ static struct platform_driver sh4_ssi_driver = { }, .probe = sh4_soc_dai_probe, - .remove = sh4_soc_dai_remove, }; module_platform_driver(sh4_ssi_driver); -- GitLab From 618718dc56a49321a12f231b34f6c43f44c3c374 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 28 Aug 2015 10:53:31 +0800 Subject: [PATCH 5597/7006] ASoC: qcom: Constify asoc_qcom_lpass_cpu_dai_ops asoc_qcom_lpass_cpu_dai_ops is exported and used by multiple drivers, make it const to prevent modifying it at run time. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 2 +- sound/soc/qcom/lpass.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index 23f3d59e6d095..97bc2023f08aa 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -235,7 +235,7 @@ static int lpass_cpu_daiops_trigger(struct snd_pcm_substream *substream, return ret; } -struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { +const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops = { .set_sysclk = lpass_cpu_daiops_set_sysclk, .startup = lpass_cpu_daiops_startup, .shutdown = lpass_cpu_daiops_shutdown, diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index d6e86c119e749..0b63e2e5bcc92 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -93,6 +93,6 @@ int asoc_qcom_lpass_platform_register(struct platform_device *); int asoc_qcom_lpass_cpu_platform_remove(struct platform_device *pdev); int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev); int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai); -extern struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; +extern const struct snd_soc_dai_ops asoc_qcom_lpass_cpu_dai_ops; #endif /* __LPASS_H__ */ -- GitLab From 6fe7ccfd77415a6ba250c10c580eb3f9acf79753 Mon Sep 17 00:00:00 2001 From: Jozsef Kadlecsik Date: Tue, 25 Aug 2015 11:17:51 +0200 Subject: [PATCH 5598/7006] netfilter: ipset: Out of bound access in hash:net* types fixed Dave Jones reported that KASan detected out of bounds access in hash:net* types: [ 23.139532] ================================================================== [ 23.146130] BUG: KASan: out of bounds access in hash_net4_add_cidr+0x1db/0x220 at addr ffff8800d4844b58 [ 23.152937] Write of size 4 by task ipset/457 [ 23.159742] ============================================================================= [ 23.166672] BUG kmalloc-512 (Not tainted): kasan: bad access detected [ 23.173641] ----------------------------------------------------------------------------- [ 23.194668] INFO: Allocated in hash_net_create+0x16a/0x470 age=7 cpu=1 pid=456 [ 23.201836] __slab_alloc.constprop.66+0x554/0x620 [ 23.208994] __kmalloc+0x2f2/0x360 [ 23.216105] hash_net_create+0x16a/0x470 [ 23.223238] ip_set_create+0x3e6/0x740 [ 23.230343] nfnetlink_rcv_msg+0x599/0x640 [ 23.237454] netlink_rcv_skb+0x14f/0x190 [ 23.244533] nfnetlink_rcv+0x3f6/0x790 [ 23.251579] netlink_unicast+0x272/0x390 [ 23.258573] netlink_sendmsg+0x5a1/0xa50 [ 23.265485] SYSC_sendto+0x1da/0x2c0 [ 23.272364] SyS_sendto+0xe/0x10 [ 23.279168] entry_SYSCALL_64_fastpath+0x12/0x6f The bug is fixed in the patch and the testsuite is extended in ipset to check cidr handling more thoroughly. Signed-off-by: Jozsef Kadlecsik --- net/netfilter/ipset/ip_set_hash_gen.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h index afe905c208af8..691b54fcaf2a4 100644 --- a/net/netfilter/ipset/ip_set_hash_gen.h +++ b/net/netfilter/ipset/ip_set_hash_gen.h @@ -152,9 +152,13 @@ htable_bits(u32 hashsize) #define SET_HOST_MASK(family) (family == AF_INET ? 32 : 128) #ifdef IP_SET_HASH_WITH_NET0 +/* cidr from 0 to SET_HOST_MASK() value and c = cidr + 1 */ #define NLEN(family) (SET_HOST_MASK(family) + 1) +#define CIDR_POS(c) ((c) - 1) #else +/* cidr from 1 to SET_HOST_MASK() value and c = cidr + 1 */ #define NLEN(family) SET_HOST_MASK(family) +#define CIDR_POS(c) ((c) - 2) #endif #else @@ -305,7 +309,7 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n) } else if (h->nets[i].cidr[n] < cidr) { j = i; } else if (h->nets[i].cidr[n] == cidr) { - h->nets[cidr - 1].nets[n]++; + h->nets[CIDR_POS(cidr)].nets[n]++; return; } } @@ -314,7 +318,7 @@ mtype_add_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n) h->nets[i].cidr[n] = h->nets[i - 1].cidr[n]; } h->nets[i].cidr[n] = cidr; - h->nets[cidr - 1].nets[n] = 1; + h->nets[CIDR_POS(cidr)].nets[n] = 1; } static void @@ -325,8 +329,8 @@ mtype_del_cidr(struct htype *h, u8 cidr, u8 nets_length, u8 n) for (i = 0; i < nets_length; i++) { if (h->nets[i].cidr[n] != cidr) continue; - h->nets[cidr - 1].nets[n]--; - if (h->nets[cidr - 1].nets[n] > 0) + h->nets[CIDR_POS(cidr)].nets[n]--; + if (h->nets[CIDR_POS(cidr)].nets[n] > 0) return; for (j = i; j < net_end && h->nets[j].cidr[n]; j++) h->nets[j].cidr[n] = h->nets[j + 1].cidr[n]; -- GitLab From edd98a1a2d163cef6d91226bf42ca002ced6ff16 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:09:29 +0800 Subject: [PATCH 5599/7006] ASoC: au1x: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/au1x/dbdma2.c | 11 ++--------- sound/soc/au1x/dma.c | 11 ++--------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/sound/soc/au1x/dbdma2.c b/sound/soc/au1x/dbdma2.c index dd94fea72d5d2..5741c0aa6c030 100644 --- a/sound/soc/au1x/dbdma2.c +++ b/sound/soc/au1x/dbdma2.c @@ -344,14 +344,8 @@ static int au1xpsc_pcm_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, dmadata); - return snd_soc_register_platform(&pdev->dev, &au1xpsc_soc_platform); -} - -static int au1xpsc_pcm_drvremove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &au1xpsc_soc_platform); } static struct platform_driver au1xpsc_pcm_driver = { @@ -359,7 +353,6 @@ static struct platform_driver au1xpsc_pcm_driver = { .name = "au1xpsc-pcm", }, .probe = au1xpsc_pcm_drvprobe, - .remove = au1xpsc_pcm_drvremove, }; module_platform_driver(au1xpsc_pcm_driver); diff --git a/sound/soc/au1x/dma.c b/sound/soc/au1x/dma.c index 24cc7f40d87a6..fcf5a9adde817 100644 --- a/sound/soc/au1x/dma.c +++ b/sound/soc/au1x/dma.c @@ -312,14 +312,8 @@ static int alchemy_pcm_drvprobe(struct platform_device *pdev) platform_set_drvdata(pdev, ctx); - return snd_soc_register_platform(&pdev->dev, &alchemy_pcm_soc_platform); -} - -static int alchemy_pcm_drvremove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &alchemy_pcm_soc_platform); } static struct platform_driver alchemy_pcmdma_driver = { @@ -327,7 +321,6 @@ static struct platform_driver alchemy_pcmdma_driver = { .name = "alchemy-pcm-dma", }, .probe = alchemy_pcm_drvprobe, - .remove = alchemy_pcm_drvremove, }; module_platform_driver(alchemy_pcmdma_driver); -- GitLab From c4d2ab0d59f53a1534e6817b5dbd28719f667c39 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:11:13 +0800 Subject: [PATCH 5600/7006] ASoC: blackfin: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/blackfin/bf5xx-ac97-pcm.c | 10 ++-------- sound/soc/blackfin/bf5xx-i2s-pcm.c | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/sound/soc/blackfin/bf5xx-ac97-pcm.c b/sound/soc/blackfin/bf5xx-ac97-pcm.c index 238913e030e05..02ad2606fa19c 100644 --- a/sound/soc/blackfin/bf5xx-ac97-pcm.c +++ b/sound/soc/blackfin/bf5xx-ac97-pcm.c @@ -450,13 +450,8 @@ static struct snd_soc_platform_driver bf5xx_ac97_soc_platform = { static int bf5xx_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &bf5xx_ac97_soc_platform); -} - -static int bf5xx_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &bf5xx_ac97_soc_platform); } static struct platform_driver bf5xx_pcm_driver = { @@ -465,7 +460,6 @@ static struct platform_driver bf5xx_pcm_driver = { }, .probe = bf5xx_soc_platform_probe, - .remove = bf5xx_soc_platform_remove, }; module_platform_driver(bf5xx_pcm_driver); diff --git a/sound/soc/blackfin/bf5xx-i2s-pcm.c b/sound/soc/blackfin/bf5xx-i2s-pcm.c index d95477afcc671..6cba211da32ee 100644 --- a/sound/soc/blackfin/bf5xx-i2s-pcm.c +++ b/sound/soc/blackfin/bf5xx-i2s-pcm.c @@ -342,13 +342,8 @@ static struct snd_soc_platform_driver bf5xx_i2s_soc_platform = { static int bfin_i2s_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &bf5xx_i2s_soc_platform); -} - -static int bfin_i2s_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &bf5xx_i2s_soc_platform); } static struct platform_driver bfin_i2s_pcm_driver = { @@ -357,7 +352,6 @@ static struct platform_driver bfin_i2s_pcm_driver = { }, .probe = bfin_i2s_soc_platform_probe, - .remove = bfin_i2s_soc_platform_remove, }; module_platform_driver(bfin_i2s_pcm_driver); -- GitLab From d5f1117ff60d1e314b15e3a85b7705db3421d7d4 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:12:17 +0800 Subject: [PATCH 5601/7006] ASoC: nuc900: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/nuc900/nuc900-pcm.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/nuc900/nuc900-pcm.c b/sound/soc/nuc900/nuc900-pcm.c index 5ae5ca15b6d6b..e09326158bc2d 100644 --- a/sound/soc/nuc900/nuc900-pcm.c +++ b/sound/soc/nuc900/nuc900-pcm.c @@ -308,13 +308,7 @@ static struct snd_soc_platform_driver nuc900_soc_platform = { static int nuc900_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform); -} - -static int nuc900_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &nuc900_soc_platform); } static struct platform_driver nuc900_pcm_driver = { @@ -323,7 +317,6 @@ static struct platform_driver nuc900_pcm_driver = { }, .probe = nuc900_soc_platform_probe, - .remove = nuc900_soc_platform_remove, }; module_platform_driver(nuc900_pcm_driver); -- GitLab From 637c4497bbf0c9a4e00d6be2731bd560bf609f6b Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:13:46 +0800 Subject: [PATCH 5602/7006] ASoC: pxa: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/pxa/mmp-pcm.c | 9 +-------- sound/soc/pxa/pxa2xx-pcm.c | 9 +-------- 2 files changed, 2 insertions(+), 16 deletions(-) diff --git a/sound/soc/pxa/mmp-pcm.c b/sound/soc/pxa/mmp-pcm.c index 1eb45dcfb8e84..51e790d006f5c 100644 --- a/sound/soc/pxa/mmp-pcm.c +++ b/sound/soc/pxa/mmp-pcm.c @@ -232,13 +232,7 @@ static int mmp_pcm_probe(struct platform_device *pdev) mmp_pcm_hardware[SNDRV_PCM_STREAM_CAPTURE].period_bytes_max = pdata->period_max_capture; } - return snd_soc_register_platform(&pdev->dev, &mmp_soc_platform); -} - -static int mmp_pcm_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &mmp_soc_platform); } static struct platform_driver mmp_pcm_driver = { @@ -247,7 +241,6 @@ static struct platform_driver mmp_pcm_driver = { }, .probe = mmp_pcm_probe, - .remove = mmp_pcm_remove, }; module_platform_driver(mmp_pcm_driver); diff --git a/sound/soc/pxa/pxa2xx-pcm.c b/sound/soc/pxa/pxa2xx-pcm.c index a51c9da666149..831ee37d2e3e7 100644 --- a/sound/soc/pxa/pxa2xx-pcm.c +++ b/sound/soc/pxa/pxa2xx-pcm.c @@ -124,13 +124,7 @@ static struct snd_soc_platform_driver pxa2xx_soc_platform = { static int pxa2xx_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform); -} - -static int pxa2xx_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &pxa2xx_soc_platform); } #ifdef CONFIG_OF @@ -147,7 +141,6 @@ static struct platform_driver pxa_pcm_driver = { }, .probe = pxa2xx_soc_platform_probe, - .remove = pxa2xx_soc_platform_remove, }; module_platform_driver(pxa_pcm_driver); -- GitLab From 95e3c2305b79e9c0e5f2cb0090efca397249b51f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 27 Aug 2015 09:14:50 +0800 Subject: [PATCH 5603/7006] ASoC: txx9: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/txx9/txx9aclc.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c index 88eacfd83da67..a8f705bb60dc0 100644 --- a/sound/soc/txx9/txx9aclc.c +++ b/sound/soc/txx9/txx9aclc.c @@ -411,13 +411,8 @@ static struct snd_soc_platform_driver txx9aclc_soc_platform = { static int txx9aclc_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &txx9aclc_soc_platform); -} - -static int txx9aclc_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, + &txx9aclc_soc_platform); } static struct platform_driver txx9aclc_pcm_driver = { @@ -426,7 +421,6 @@ static struct platform_driver txx9aclc_pcm_driver = { }, .probe = txx9aclc_soc_platform_probe, - .remove = txx9aclc_soc_platform_remove, }; module_platform_driver(txx9aclc_pcm_driver); -- GitLab From 54d71856428961124be26301b7997f2ad23be520 Mon Sep 17 00:00:00 2001 From: Chao Yu Date: Fri, 28 Aug 2015 18:18:57 +0800 Subject: [PATCH 5604/7006] f2fs: avoid accessing NULL pointer in f2fs_drop_largest_extent If extent cache is disable, we will encounter oops when triggering direct IO as below: BUG: unable to handle kernel NULL pointer dereference at 0000000c IP: [] f2fs_drop_largest_extent+0xe/0x30 [f2fs] *pdpt = 000000002bb9a001 *pde = 0000000000000000 Oops: 0000 [#1] SMP Modules linked in: f2fs(O) fuse bnep rfcomm bluetooth nfsd dm_crypt nfs_acl auth_rpcgss oid_registry nfs binfmt_misc fscache lockd sunrpc grace snd_intel8x0 snd_ac97_codec ac97_bus snd_pcm snd_seq_midi snd_rawmidi snd_seq_midi_event snd_seq snd_timer snd_seq_device snd soundcore joydev psmouse hid_generic i2c_piix4 serio_raw ppdev mac_hid parport_pc lp parport ext4 jbd2 mbcache usbhid hid e1000 CPU: 3 PID: 3608 Comm: dd Tainted: G O 4.2.0-rc4 #12 Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 task: ef161600 ti: ebd5e000 task.ti: ebd5e000 EIP: 0060:[] EFLAGS: 00010202 CPU: 3 EIP is at f2fs_drop_largest_extent+0xe/0x30 [f2fs] EAX: 00000000 EBX: ddebc000 ECX: 00000000 EDX: 00000000 ESI: ebd5fdf8 EDI: 00000000 EBP: ebd5fd58 ESP: ebd5fd58 DS: 007b ES: 007b FS: 00d8 GS: 0033 SS: 0068 CR0: 80050033 CR2: 0000000c CR3: 2c24ee40 CR4: 000006f0 Stack: ebd5fda4 f0b8c005 00000000 00000001 00000000 f0b8c430 c816cd68 ddebc000 ddebc088 00001000 00000555 00000555 ffffffff c160bb00 00055501 00000000 00000000 00000100 00000000 ebd5fe20 f0b8c430 00000046 ef161600 00001000 Call Trace: [] __allocate_data_block+0x1a5/0x260 [f2fs] [] ? f2fs_direct_IO+0x370/0x440 [f2fs] [] ? down_read+0x30/0x50 [] f2fs_direct_IO+0x370/0x440 [f2fs] [] generic_file_direct_write+0xa5/0x260 [] ? current_fs_time+0x18/0x50 [] __generic_file_write_iter+0xbb/0x210 [] ? generic_file_write_iter+0x2f/0x320 [] generic_file_write_iter+0x15c/0x320 [] f2fs_file_write_iter+0x39/0x80 [f2fs] [] __vfs_write+0xa9/0xe0 [] vfs_write+0x97/0x180 [] SyS_write+0x5b/0xd0 [] sysenter_do_call+0x12/0x12 Code: 10 8b 50 1c 89 53 14 eb ca 8d 74 26 00 85 f6 74 86 eb a6 0f 0b 90 8d b4 26 00 00 00 00 55 89 e5 3e 8d 74 26 00 8b 80 d4 02 00 00 <8b> 48 0c 39 d1 77 0e 03 48 14 39 ca 73 07 c7 40 14 00 00 00 00 EIP: [] f2fs_drop_largest_extent+0xe/0x30 [f2fs] SS:ESP 0068:ebd5fd58 CR2: 000000000000000c ---[ end trace a38c07026a1afffd ]--- This is because when extent cache is disable, extent_tree pointer in struct f2fs_inode_info should be NULL, but in f2fs_drop_largest_extent we access this NULL pointer directly without checking state of extent cache, then, the oops occurs. Let's fix it by checking state of extent cache before accessing. Signed-off-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/extent_cache.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/f2fs/extent_cache.c b/fs/f2fs/extent_cache.c index e6b245718ef0a..997ac86f2a1d5 100644 --- a/fs/f2fs/extent_cache.c +++ b/fs/f2fs/extent_cache.c @@ -155,7 +155,7 @@ static unsigned int __free_extent_tree(struct f2fs_sb_info *sbi, return count - et->count; } -void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs) +static void __drop_largest_extent(struct inode *inode, pgoff_t fofs) { struct extent_info *largest = &F2FS_I(inode)->extent_tree->largest; @@ -163,6 +163,14 @@ void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs) largest->len = 0; } +void f2fs_drop_largest_extent(struct inode *inode, pgoff_t fofs) +{ + if (!f2fs_may_extent_tree(inode)) + return; + + __drop_largest_extent(inode, fofs); +} + void f2fs_init_extent_tree(struct inode *inode, struct f2fs_extent *i_ext) { struct f2fs_sb_info *sbi = F2FS_I_SB(inode); @@ -412,7 +420,7 @@ unsigned int f2fs_update_extent_tree_range(struct inode *inode, dei.len = 0; /* we do not guarantee that the largest extent is cached all the time */ - f2fs_drop_largest_extent(inode, fofs); + __drop_largest_extent(inode, fofs); /* 1. lookup first extent node in range [fofs, fofs + len - 1] */ en = __lookup_extent_tree_ret(et, fofs, &prev_en, &next_en, -- GitLab From 39d9b85a4d4fa1642663ca0d208b5c246a3d6f50 Mon Sep 17 00:00:00 2001 From: Gary Wang Date: Fri, 28 Aug 2015 16:40:34 +0800 Subject: [PATCH 5605/7006] drm/i915: set CDCLK if DPLL0 enabled during resuming from S3 Since BIOS RC 1.4 it would enable CDCLK PLL during BIOS S3 resume, then driver needs to set CDCLK to avoid display corruption if DPLL0 enabled. References: https://bugs.freedesktop.org/show_bug.cgi?id=91697 Reviewed-by: Rodrigo Vivi Reviewed-by: Damien Lespiau Reviewed-by: Cooper Chiou Reviewed-by: Wei Shun Chang Tested-by: Gary Wang Cc: Daniel Vetter Cc: Gavin Hindman Cc: Chris Wilson Cc: Xiong Y Zhang Signed-off-by: Gary Wang Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 53f5476bc4bb8..8ea9821261abc 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5712,16 +5712,13 @@ void skl_init_cdclk(struct drm_i915_private *dev_priv) /* enable PG1 and Misc I/O */ intel_display_power_get(dev_priv, POWER_DOMAIN_PLLS); - /* DPLL0 already enabed !? */ - if (I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE) { - DRM_DEBUG_DRIVER("DPLL0 already running\n"); - return; + /* DPLL0 not enabled (happens on early BIOS versions) */ + if (!(I915_READ(LCPLL1_CTL) & LCPLL_PLL_ENABLE)) { + /* enable DPLL0 */ + required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); + skl_dpll0_enable(dev_priv, required_vco); } - /* enable DPLL0 */ - required_vco = skl_cdclk_get_vco(dev_priv->skl_boot_cdclk); - skl_dpll0_enable(dev_priv, required_vco); - /* set CDCLK to the frequency the BIOS chose */ skl_set_cdclk(dev_priv, dev_priv->skl_boot_cdclk); -- GitLab From efd85cf86a56898686187397adfd52dfac79aff2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 26 Aug 2015 11:13:38 -0700 Subject: [PATCH 5606/7006] thinkpad_acpi: Remove side effects from vdbg_printk -> no_printk macro vdbg_printk when not using CONFIG_THINKPAD_ACPI_DEBUG uses no_printk which produces no logging output but always evaluates arguments. Change the macro to surround the no_printk call with do { if (0) no_printk(...); } while (0) to avoid the unnecessary argument evaluations. $ size drivers/platform/x86/thinkpad_acpi.o* text data bss dec hex filename 60918 6184 824 67926 10956 drivers/platform/x86/thinkpad_acpi.o.new 60927 6184 824 67935 1095f drivers/platform/x86/thinkpad_acpi.o.old Signed-off-by: Joe Perches Acked-by: Henrique de Moraes Holschuh Signed-off-by: Darren Hart --- drivers/platform/x86/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 33e488cf55698..131dd74641833 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -402,7 +402,7 @@ static const char *str_supported(int is_supported); #else static inline const char *str_supported(int is_supported) { return ""; } #define vdbg_printk(a_dbg_level, format, arg...) \ - no_printk(format, ##arg) + do { if (0) no_printk(format, ##arg); } while (0) #endif static void tpacpi_log_usertask(const char * const what) -- GitLab From 628536ea0627e71da654bd34b1942c85832dbdba Mon Sep 17 00:00:00 2001 From: Jonathan Corbet Date: Tue, 25 Aug 2015 01:14:48 -0600 Subject: [PATCH 5607/7006] ASoC: Clean up docbook warnings A number of functions and structures in the sound subsystem had incomplete and/or obsolete DocBook comments, leading to warnings when the docs were built. Correct those comments so that we can enjoy our audio in the absence of warning noise. Signed-off-by: Jonathan Corbet Signed-off-by: Mark Brown --- Documentation/DocBook/alsa-driver-api.tmpl | 2 +- include/sound/soc.h | 11 +++++++---- sound/soc/soc-core.c | 13 +++++++++---- sound/soc/soc-dapm.c | 2 +- 4 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl index 71f9246127eca..e94a10bb4a9e9 100644 --- a/Documentation/DocBook/alsa-driver-api.tmpl +++ b/Documentation/DocBook/alsa-driver-api.tmpl @@ -108,7 +108,7 @@ ASoC Core API !Iinclude/sound/soc.h !Esound/soc/soc-core.c -!Esound/soc/soc-cache.c + !Esound/soc/soc-devres.c !Esound/soc/soc-io.c !Esound/soc/soc-pcm.c diff --git a/include/sound/soc.h b/include/sound/soc.h index 93df8bf9d54a9..4537e81eeedaa 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -619,6 +619,7 @@ int snd_soc_put_strobe(struct snd_kcontrol *kcontrol, * @pin: name of the pin to update * @mask: bits to check for in reported jack status * @invert: if non-zero then pin is enabled when status is not reported + * @list: internal list entry */ struct snd_soc_jack_pin { struct list_head list; @@ -635,7 +636,7 @@ struct snd_soc_jack_pin { * @jack_type: type of jack that is expected for this voltage * @debounce_time: debounce_time for jack, codec driver should wait for this * duration before reading the adc for voltages - * @:list: list container + * @list: internal list entry */ struct snd_soc_jack_zone { unsigned int min_mv; @@ -651,12 +652,12 @@ struct snd_soc_jack_zone { * @gpio: legacy gpio number * @idx: gpio descriptor index within the function of the GPIO * consumer device - * @gpiod_dev GPIO consumer device + * @gpiod_dev: GPIO consumer device * @name: gpio name. Also as connection ID for the GPIO consumer * device function name lookup * @report: value to report when jack detected * @invert: report presence in low state - * @debouce_time: debouce time in ms + * @debounce_time: debounce time in ms * @wake: enable as wake source * @jack_status_check: callback function which overrides the detection * to provide more complex checks (eg, reading an @@ -672,11 +673,13 @@ struct snd_soc_jack_gpio { int debounce_time; bool wake; + /* private: */ struct snd_soc_jack *jack; struct delayed_work work; struct gpio_desc *desc; void *data; + /* public: */ int (*jack_status_check)(void *data); }; @@ -1319,7 +1322,7 @@ static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm( /** * snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level - * @dapm: The CODEC for which to initialize the DAPM bias level + * @codec: The CODEC for which to initialize the DAPM bias level * @level: The DAPM level to initialize to * * Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level(). diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 90d6335de17a8..32242512d828a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2798,6 +2798,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_component); /** * snd_soc_unregister_component - Unregister a component from the ASoC core * + * @dev: The device to unregister */ void snd_soc_unregister_component(struct device *dev) { @@ -2877,7 +2878,8 @@ EXPORT_SYMBOL_GPL(snd_soc_add_platform); /** * snd_soc_register_platform - Register a platform with the ASoC core * - * @platform: platform to register + * @dev: The device for the platform + * @platform_drv: The driver for the platform */ int snd_soc_register_platform(struct device *dev, const struct snd_soc_platform_driver *platform_drv) @@ -2938,7 +2940,7 @@ EXPORT_SYMBOL_GPL(snd_soc_lookup_platform); /** * snd_soc_unregister_platform - Unregister a platform from the ASoC core * - * @platform: platform to unregister + * @dev: platform to unregister */ void snd_soc_unregister_platform(struct device *dev) { @@ -3029,7 +3031,10 @@ static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm, /** * snd_soc_register_codec - Register a codec with the ASoC core * - * @codec: codec to register + * @dev: The parent device for this codec + * @codec_drv: Codec driver + * @dai_drv: The associated DAI driver + * @num_dai: Number of DAIs */ int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv, @@ -3128,7 +3133,7 @@ EXPORT_SYMBOL_GPL(snd_soc_register_codec); /** * snd_soc_unregister_codec - Unregister a codec from the ASoC core * - * @codec: codec to unregister + * @dev: codec to unregister */ void snd_soc_unregister_codec(struct device *dev) { diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c index aa327c92480c5..c4e3720bea410 100644 --- a/sound/soc/soc-dapm.c +++ b/sound/soc/soc-dapm.c @@ -2911,7 +2911,7 @@ EXPORT_SYMBOL_GPL(snd_soc_dapm_weak_routes); /** * snd_soc_dapm_new_widgets - add new dapm widgets - * @dapm: DAPM context + * @card: card to be checked for new dapm widgets * * Checks the codec for any new dapm widgets and creates them if found. * -- GitLab From 628b3198ccc235e387c0b8ee200c10c883e86644 Mon Sep 17 00:00:00 2001 From: Michael Powell Date: Sun, 2 Aug 2015 22:59:29 +0000 Subject: [PATCH 5608/7006] acer-wmi: No rfkill on HP Omen 15 wifi Prevents acer-wmi from blocking wifi on HP Omen 15 laptops Signed-off-by: Michael Powell [david.ward@ll.mit.edu: Resubmitted clean patch] Signed-off-by: Darren Hart --- drivers/platform/x86/acer-wmi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index f6b280dbfb333..d773b9dc48a0a 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -807,6 +807,7 @@ static const struct acpi_device_id norfkill_ids[] __initconst = { { "IBM0068", 0}, { "LEN0068", 0}, { "SNY5001", 0}, /* sony-laptop in charge */ + { "HPQ6601", 0}, { "", 0}, }; -- GitLab From 70ee06c5f447b9d50747b29d3e8d48ae7ef1cabe Mon Sep 17 00:00:00 2001 From: Aaron Skomra Date: Thu, 20 Aug 2015 16:05:16 -0700 Subject: [PATCH 5609/7006] HID: wacom: Set button bits based on a new numbered_buttons Prior to this commit, numbered button bit setting was done separately for each device type in wacom_setup_pad_capabilities(). Here we add a numbered_buttons property to the wacom_features struct and extract the repeated bit setting code to a new function: wacom_settup_numbered_buttons(). Signed-off-by: Aaron Skomra Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 175 ++++++++++++++-------------------------- drivers/hid/wacom_wac.h | 1 + 2 files changed, 61 insertions(+), 115 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 3024a3c2b4ff1..ee5d278afa3f7 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2577,11 +2577,23 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, return 0; } +void wacom_setup_numbered_buttons(struct input_dev *input_dev, + int button_count) +{ + int i; + + for (i = 0; i < button_count && i < 10; i++) + __set_bit(BTN_0 + i, input_dev->keybit); + for (i = 10; i < button_count && i < 16; i++) + __set_bit(BTN_A + (i-10), input_dev->keybit); + for (i = 16; i < button_count && i < 18; i++) + __set_bit(BTN_BASE + (i-16), input_dev->keybit); +} + int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { struct wacom_features *features = &wacom_wac->features; - int i; if (!(features->device_type & WACOM_DEVICETYPE_PAD)) return -ENODEV; @@ -2598,10 +2610,14 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, /* kept for making udev and libwacom accepting the pad */ __set_bit(BTN_STYLUS, input_dev->keybit); + wacom_setup_numbered_buttons(input_dev, features->numbered_buttons); + switch (features->type) { + + case CINTIQ_HYBRID: + case DTK: + case DTUS: case GRAPHIRE_BT: - __set_bit(BTN_0, input_dev->keybit); - __set_bit(BTN_1, input_dev->keybit); break; case WACOM_MO: @@ -2619,16 +2635,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, break; case WACOM_24HD: - __set_bit(BTN_A, input_dev->keybit); - __set_bit(BTN_B, input_dev->keybit); - __set_bit(BTN_C, input_dev->keybit); - __set_bit(BTN_X, input_dev->keybit); - __set_bit(BTN_Y, input_dev->keybit); - __set_bit(BTN_Z, input_dev->keybit); - - for (i = 0; i < 10; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - __set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit); __set_bit(KEY_PROG3, input_dev->keybit); @@ -2650,12 +2656,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit); break; - case DTK: - for (i = 0; i < 6; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - - break; - case WACOM_22HD: __set_bit(KEY_PROG1, input_dev->keybit); __set_bit(KEY_PROG2, input_dev->keybit); @@ -2663,52 +2663,22 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, /* fall through */ case WACOM_21UX2: - __set_bit(BTN_A, input_dev->keybit); - __set_bit(BTN_B, input_dev->keybit); - __set_bit(BTN_C, input_dev->keybit); - __set_bit(BTN_X, input_dev->keybit); - __set_bit(BTN_Y, input_dev->keybit); - __set_bit(BTN_Z, input_dev->keybit); - __set_bit(BTN_BASE, input_dev->keybit); - __set_bit(BTN_BASE2, input_dev->keybit); - /* fall through */ - case WACOM_BEE: - __set_bit(BTN_8, input_dev->keybit); - __set_bit(BTN_9, input_dev->keybit); - /* fall through */ - case CINTIQ: - for (i = 0; i < 8; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); break; case WACOM_13HD: - for (i = 0; i < 9; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; case INTUOS3: case INTUOS3L: - __set_bit(BTN_4, input_dev->keybit); - __set_bit(BTN_5, input_dev->keybit); - __set_bit(BTN_6, input_dev->keybit); - __set_bit(BTN_7, input_dev->keybit); - input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); /* fall through */ case INTUOS3S: - __set_bit(BTN_0, input_dev->keybit); - __set_bit(BTN_1, input_dev->keybit); - __set_bit(BTN_2, input_dev->keybit); - __set_bit(BTN_3, input_dev->keybit); - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); break; @@ -2716,15 +2686,8 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS5L: case INTUOSPM: case INTUOSPL: - __set_bit(BTN_7, input_dev->keybit); - __set_bit(BTN_8, input_dev->keybit); - /* fall through */ - case INTUOS5S: case INTUOSPS: - for (i = 0; i < 7; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; @@ -2739,28 +2702,10 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS4: case INTUOS4L: - __set_bit(BTN_7, input_dev->keybit); - __set_bit(BTN_8, input_dev->keybit); - /* fall through */ - case INTUOS4S: - for (i = 0; i < 7; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); break; - case CINTIQ_HYBRID: - for (i = 0; i < 9; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - - break; - - case DTUS: - for (i = 0; i < 4; i++) - __set_bit(BTN_0 + i, input_dev->keybit); - break; - case INTUOSHT: case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); @@ -2787,7 +2732,7 @@ static const struct wacom_features wacom_features_0x10 = GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; static const struct wacom_features wacom_features_0x81 = { "Wacom Graphire BT", 16704, 12064, 511, 32, - GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; + GRAPHIRE_BT, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES, 2 }; static const struct wacom_features wacom_features_0x11 = { "Wacom Graphire2 4x5", 10206, 7422, 511, 63, GRAPHIRE, WACOM_GRAPHIRE_RES, WACOM_GRAPHIRE_RES }; @@ -2913,77 +2858,77 @@ static const struct wacom_features wacom_features_0x45 = INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xB0 = { "Wacom Intuos3 4x5", 25400, 20320, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; static const struct wacom_features wacom_features_0xB1 = { "Wacom Intuos3 6x8", 40640, 30480, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB2 = { "Wacom Intuos3 9x12", 60960, 45720, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB3 = { "Wacom Intuos3 12x12", 60960, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB4 = { "Wacom Intuos3 12x19", 97536, 60960, 1023, 63, - INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB5 = { "Wacom Intuos3 6x11", 54204, 31750, 1023, 63, - INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xB7 = { "Wacom Intuos3 4x6", 31496, 19685, 1023, 63, - INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS3S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 4 }; static const struct wacom_features wacom_features_0xB8 = { "Wacom Intuos4 4x6", 31496, 19685, 2047, 63, - INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; static const struct wacom_features wacom_features_0xB9 = { "Wacom Intuos4 6x9", 44704, 27940, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBA = { "Wacom Intuos4 8x13", 65024, 40640, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBB = { "Wacom Intuos4 12x19", 97536, 60960, 2047, 63, - INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBC = { "Wacom Intuos4 WL", 40640, 25400, 2047, 63, - INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0xBD = { "Wacom Intuos4 WL", 40640, 25400, 2047, 63, - INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS4WL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0x26 = { "Wacom Intuos5 touch S", 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; + INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16 }; static const struct wacom_features wacom_features_0x27 = { "Wacom Intuos5 touch M", 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; + INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; static const struct wacom_features wacom_features_0x28 = { "Wacom Intuos5 touch L", 65024, 40640, 2047, 63, - INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16 }; + INTUOS5L, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16 }; static const struct wacom_features wacom_features_0x29 = { "Wacom Intuos5 S", 31496, 19685, 2047, 63, - INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS5S, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7 }; static const struct wacom_features wacom_features_0x2A = { "Wacom Intuos5 M", 44704, 27940, 2047, 63, - INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + INTUOS5, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9 }; static const struct wacom_features wacom_features_0x314 = { "Wacom Intuos Pro S", 31496, 19685, 2047, 63, - INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16, + INTUOSPS, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 7, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x315 = { "Wacom Intuos Pro M", 44704, 27940, 2047, 63, - INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16, + INTUOSPM, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x317 = { "Wacom Intuos Pro L", 65024, 40640, 2047, 63, - INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, .touch_max = 16, + INTUOSPL, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, .touch_max = 16, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0xF4 = { "Wacom Cintiq 24HD", 104080, 65200, 2047, 63, - WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0xF8 = { "Wacom Cintiq 24HD touch", 104080, 65200, 2047, 63, /* Pen */ - WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_24HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 16, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf6 }; static const struct wacom_features wacom_features_0xF6 = @@ -2992,11 +2937,11 @@ static const struct wacom_features wacom_features_0xF6 = .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x32A = { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63, - WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x32B = { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63, - WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 0, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C }; static const struct wacom_features wacom_features_0x32C = @@ -3004,20 +2949,20 @@ static const struct wacom_features wacom_features_0x32C = .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 }; static const struct wacom_features wacom_features_0x3F = { "Wacom Cintiq 21UX", 87200, 65600, 1023, 63, - CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 8 }; static const struct wacom_features wacom_features_0xC5 = { "Wacom Cintiq 20WSX", 86680, 54180, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; static const struct wacom_features wacom_features_0xC6 = { "Wacom Cintiq 12WX", 53020, 33440, 1023, 63, - WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES }; + WACOM_BEE, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 10 }; static const struct wacom_features wacom_features_0x304 = { "Wacom Cintiq 13HD", 59152, 33448, 1023, 63, - WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x333 = { "Wacom Cintiq 13HD touch", 59152, 33448, 2047, 63, - WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_13HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x335 }; static const struct wacom_features wacom_features_0x335 = @@ -3036,22 +2981,22 @@ static const struct wacom_features wacom_features_0xF0 = DTU, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xFB = { "Wacom DTU1031", 21896, 13760, 511, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_0x32F = { "Wacom DTU1031X", 22472, 12728, 511, 0, - DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, + DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 0, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; static const struct wacom_features wacom_features_0x336 = { "Wacom DTU1141", 23472, 13203, 1023, 0, - DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; + DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES, 4 }; static const struct wacom_features wacom_features_0x57 = { "Wacom DTK2241", 95640, 54060, 2047, 63, - DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x59 = /* Pen */ { "Wacom DTH2242", 95640, 54060, 2047, 63, - DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 6, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5D }; static const struct wacom_features wacom_features_0x5D = /* Touch */ @@ -3060,15 +3005,15 @@ static const struct wacom_features wacom_features_0x5D = /* Touch */ .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0xCC = { "Wacom Cintiq 21UX2", 86800, 65200, 2047, 63, - WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_21UX2, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0xFA = { "Wacom Cintiq 22HD", 95440, 53860, 2047, 63, - WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET }; static const struct wacom_features wacom_features_0x5B = { "Wacom Cintiq 22HDT", 95440, 53860, 2047, 63, - WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + WACOM_22HD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 18, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x5e }; static const struct wacom_features wacom_features_0x5E = @@ -3215,7 +3160,7 @@ static const struct wacom_features wacom_features_0x6004 = TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x307 = { "Wacom ISDv5 307", 59152, 33448, 2047, 63, - CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x309 }; static const struct wacom_features wacom_features_0x309 = @@ -3224,7 +3169,7 @@ static const struct wacom_features wacom_features_0x309 = .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_0x30A = { "Wacom ISDv5 30A", 59152, 33448, 2047, 63, - CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, + CINTIQ_HYBRID, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, 9, WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET, .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x30C }; static const struct wacom_features wacom_features_0x30C = diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 6233eeab028dd..4ee5c13b4e759 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -148,6 +148,7 @@ struct wacom_features { int type; int x_resolution; int y_resolution; + int numbered_buttons; int x_min; int y_min; int device_type; -- GitLab From 72b236d60218fe211a8e1210be31c31e81684b86 Mon Sep 17 00:00:00 2001 From: Aaron Skomra Date: Thu, 20 Aug 2015 16:05:17 -0700 Subject: [PATCH 5610/7006] HID: wacom: Add support for Express Key Remote. This device is pad (buttons) only, there is no stylus or touch. Up to five remotes can pair with the device's associated USB dongle. Signed-off-by: Aaron Skomra Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina --- Documentation/ABI/testing/sysfs-driver-wacom | 19 ++ drivers/hid/wacom.h | 7 +- drivers/hid/wacom_sys.c | 195 +++++++++++++++++++ drivers/hid/wacom_wac.c | 144 ++++++++++++++ drivers/hid/wacom_wac.h | 7 +- 5 files changed, 370 insertions(+), 2 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-wacom b/Documentation/ABI/testing/sysfs-driver-wacom index c4f0fed64a6e5..dca4293407726 100644 --- a/Documentation/ABI/testing/sysfs-driver-wacom +++ b/Documentation/ABI/testing/sysfs-driver-wacom @@ -77,3 +77,22 @@ Description: The format is also scrambled, like in the USB mode, and it can be summarized by converting 76543210 into GECA6420. HGFEDCBA HFDB7531 + +What: /sys/bus/hid/devices/::./wacom_remote/unpair_remote +Date: July 2015 +Contact: linux-input@vger.kernel.org +Description: + Writing the character sequence '*' followed by a newline to + this file will delete all of the current pairings on the + device. Other character sequences are reserved. This file is + write only. + +What: /sys/bus/hid/devices/::./wacom_remote//remote_mode +Date: July 2015 +Contact: linux-input@vger.kernel.org +Description: + Reading from this file reports the mode status of the + remote as indicated by the LED lights on the device. If no + reports have been received from the paired device, reading + from this file will report '-1'. The mode is read-only + and cannot be set through the driver. diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index a533787a6d857..4681a65a4579c 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -113,7 +113,7 @@ struct wacom { struct mutex lock; struct work_struct work; struct wacom_led { - u8 select[2]; /* status led selector (0..3) */ + u8 select[5]; /* status led selector (0..3) */ u8 llv; /* status led brightness no button (1..127) */ u8 hlv; /* status led brightness button pressed (1..127) */ u8 img_lum; /* OLED matrix display brightness */ @@ -123,6 +123,8 @@ struct wacom { struct power_supply *ac; struct power_supply_desc battery_desc; struct power_supply_desc ac_desc; + struct kobject *remote_dir; + struct attribute_group remote_group[5]; }; static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) @@ -147,4 +149,7 @@ int wacom_wac_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value); void wacom_wac_report(struct hid_device *hdev, struct hid_report *report); void wacom_battery_work(struct work_struct *work); +int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, + int index); +void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial); #endif diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 6edb7d1364762..5f6e48e55df9b 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -23,9 +23,13 @@ #define WAC_CMD_ICON_XFER 0x23 #define WAC_CMD_ICON_BT_XFER 0x26 #define WAC_CMD_RETRIES 10 +#define WAC_CMD_DELETE_PAIRING 0x20 +#define WAC_CMD_UNPAIR_ALL 0xFF +#define WAC_REMOTE_SERIAL_MAX_STRLEN 9 #define DEV_ATTR_RW_PERM (S_IRUGO | S_IWUSR | S_IWGRP) #define DEV_ATTR_WO_PERM (S_IWUSR | S_IWGRP) +#define DEV_ATTR_RO_PERM (S_IRUSR | S_IRGRP) static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, size_t size, unsigned int retries) @@ -1119,6 +1123,189 @@ static ssize_t wacom_store_speed(struct device *dev, static DEVICE_ATTR(speed, DEV_ATTR_RW_PERM, wacom_show_speed, wacom_store_speed); + +static ssize_t wacom_show_remote_mode(struct kobject *kobj, + struct kobj_attribute *kattr, + char *buf, int index) +{ + struct device *dev = container_of(kobj->parent, struct device, kobj); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct wacom *wacom = hid_get_drvdata(hdev); + u8 mode; + + mode = wacom->led.select[index]; + if (mode >= 0 && mode < 3) + return snprintf(buf, PAGE_SIZE, "%d\n", mode); + else + return snprintf(buf, PAGE_SIZE, "%d\n", -1); +} + +#define DEVICE_EKR_ATTR_GROUP(SET_ID) \ +static ssize_t wacom_show_remote##SET_ID##_mode(struct kobject *kobj, \ + struct kobj_attribute *kattr, char *buf) \ +{ \ + return wacom_show_remote_mode(kobj, kattr, buf, SET_ID); \ +} \ +static struct kobj_attribute remote##SET_ID##_mode_attr = { \ + .attr = {.name = "remote_mode", \ + .mode = DEV_ATTR_RO_PERM}, \ + .show = wacom_show_remote##SET_ID##_mode, \ +}; \ +static struct attribute *remote##SET_ID##_serial_attrs[] = { \ + &remote##SET_ID##_mode_attr.attr, \ + NULL \ +}; \ +static struct attribute_group remote##SET_ID##_serial_group = { \ + .name = NULL, \ + .attrs = remote##SET_ID##_serial_attrs, \ +} + +DEVICE_EKR_ATTR_GROUP(0); +DEVICE_EKR_ATTR_GROUP(1); +DEVICE_EKR_ATTR_GROUP(2); +DEVICE_EKR_ATTR_GROUP(3); +DEVICE_EKR_ATTR_GROUP(4); + +int wacom_remote_create_attr_group(struct wacom *wacom, __u32 serial, int index) +{ + int error = 0; + char *buf; + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + + wacom_wac->serial[index] = serial; + + buf = kzalloc(WAC_REMOTE_SERIAL_MAX_STRLEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; + snprintf(buf, WAC_REMOTE_SERIAL_MAX_STRLEN, "%d", serial); + wacom->remote_group[index].name = buf; + + error = sysfs_create_group(wacom->remote_dir, + &wacom->remote_group[index]); + if (error) { + hid_err(wacom->hdev, + "cannot create sysfs group err: %d\n", error); + kobject_put(wacom->remote_dir); + return error; + } + + return 0; +} + +void wacom_remote_destroy_attr_group(struct wacom *wacom, __u32 serial) +{ + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + int i; + + if (!serial) + return; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + if (wacom_wac->serial[i] == serial) { + wacom_wac->serial[i] = 0; + wacom->led.select[i] = WACOM_STATUS_UNKNOWN; + if (wacom->remote_group[i].name) { + sysfs_remove_group(wacom->remote_dir, + &wacom->remote_group[i]); + kfree(wacom->remote_group[i].name); + wacom->remote_group[i].name = NULL; + } + } + } +} + +static int wacom_cmd_unpair_remote(struct wacom *wacom, unsigned char selector) +{ + const size_t buf_size = 2; + unsigned char *buf; + int retval; + + buf = kzalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = WAC_CMD_DELETE_PAIRING; + buf[1] = selector; + + retval = wacom_set_report(wacom->hdev, HID_OUTPUT_REPORT, buf, + buf_size, WAC_CMD_RETRIES); + kfree(buf); + + return retval; +} + +static ssize_t wacom_store_unpair_remote(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned char selector = 0; + struct device *dev = container_of(kobj->parent, struct device, kobj); + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct wacom *wacom = hid_get_drvdata(hdev); + int err; + + if (!strncmp(buf, "*\n", 2)) { + selector = WAC_CMD_UNPAIR_ALL; + } else { + hid_info(wacom->hdev, "remote: unrecognized unpair code: %s\n", + buf); + return -1; + } + + mutex_lock(&wacom->lock); + + err = wacom_cmd_unpair_remote(wacom, selector); + mutex_unlock(&wacom->lock); + + return err < 0 ? err : count; +} + +static struct kobj_attribute unpair_remote_attr = { + .attr = {.name = "unpair_remote", .mode = 0200}, + .store = wacom_store_unpair_remote, +}; + +static const struct attribute *remote_unpair_attrs[] = { + &unpair_remote_attr.attr, + NULL +}; + +static int wacom_initialize_remote(struct wacom *wacom) +{ + int error = 0; + struct wacom_wac *wacom_wac = &(wacom->wacom_wac); + int i; + + if (wacom->wacom_wac.features.type != REMOTE) + return 0; + + wacom->remote_group[0] = remote0_serial_group; + wacom->remote_group[1] = remote1_serial_group; + wacom->remote_group[2] = remote2_serial_group; + wacom->remote_group[3] = remote3_serial_group; + wacom->remote_group[4] = remote4_serial_group; + + wacom->remote_dir = kobject_create_and_add("wacom_remote", + &wacom->hdev->dev.kobj); + if (!wacom->remote_dir) + return -ENOMEM; + + error = sysfs_create_files(wacom->remote_dir, remote_unpair_attrs); + + if (error) { + hid_err(wacom->hdev, + "cannot create sysfs group err: %d\n", error); + return error; + } + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + wacom->led.select[i] = WACOM_STATUS_UNKNOWN; + wacom_wac->serial[i] = 0; + } + + return 0; +} + static struct input_dev *wacom_allocate_input(struct wacom *wacom) { struct input_dev *input_dev; @@ -1164,6 +1351,8 @@ static void wacom_clean_inputs(struct wacom *wacom) else input_free_device(wacom->wacom_wac.pad_input); } + if (wacom->remote_dir) + kobject_put(wacom->remote_dir); wacom->wacom_wac.pen_input = NULL; wacom->wacom_wac.touch_input = NULL; wacom->wacom_wac.pad_input = NULL; @@ -1243,10 +1432,16 @@ static int wacom_register_inputs(struct wacom *wacom) error = wacom_initialize_leds(wacom); if (error) goto fail_leds; + + error = wacom_initialize_remote(wacom); + if (error) + goto fail_remote; } return 0; +fail_remote: + wacom_destroy_leds(wacom); fail_leds: input_unregister_device(pad_input_dev); pad_input_dev = NULL; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index ee5d278afa3f7..391a68731fe34 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -631,6 +631,130 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) return 0; } +static int wacom_remote_irq(struct wacom_wac *wacom_wac, size_t len) +{ + unsigned char *data = wacom_wac->data; + struct input_dev *input = wacom_wac->pad_input; + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); + struct wacom_features *features = &wacom_wac->features; + int bat_charging, bat_percent, touch_ring_mode; + __u32 serial; + int i; + + if (data[0] != WACOM_REPORT_REMOTE) { + dev_dbg(input->dev.parent, + "%s: received unknown report #%d", __func__, data[0]); + return 0; + } + + serial = data[3] + (data[4] << 8) + (data[5] << 16); + wacom_wac->id[0] = PAD_DEVICE_ID; + + input_report_key(input, BTN_0, (data[9] & 0x01)); + input_report_key(input, BTN_1, (data[9] & 0x02)); + input_report_key(input, BTN_2, (data[9] & 0x04)); + input_report_key(input, BTN_3, (data[9] & 0x08)); + input_report_key(input, BTN_4, (data[9] & 0x10)); + input_report_key(input, BTN_5, (data[9] & 0x20)); + input_report_key(input, BTN_6, (data[9] & 0x40)); + input_report_key(input, BTN_7, (data[9] & 0x80)); + + input_report_key(input, BTN_8, (data[10] & 0x01)); + input_report_key(input, BTN_9, (data[10] & 0x02)); + input_report_key(input, BTN_A, (data[10] & 0x04)); + input_report_key(input, BTN_B, (data[10] & 0x08)); + input_report_key(input, BTN_C, (data[10] & 0x10)); + input_report_key(input, BTN_X, (data[10] & 0x20)); + input_report_key(input, BTN_Y, (data[10] & 0x40)); + input_report_key(input, BTN_Z, (data[10] & 0x80)); + + input_report_key(input, BTN_BASE, (data[11] & 0x01)); + input_report_key(input, BTN_BASE2, (data[11] & 0x02)); + + if (data[12] & 0x80) + input_report_abs(input, ABS_WHEEL, (data[12] & 0x7f)); + else + input_report_abs(input, ABS_WHEEL, 0); + + bat_percent = data[7] & 0x7f; + bat_charging = !!(data[7] & 0x80); + + if (data[9] | data[10] | (data[11] & 0x03) | data[12]) + input_report_abs(input, ABS_MISC, PAD_DEVICE_ID); + else + input_report_abs(input, ABS_MISC, 0); + + input_event(input, EV_MSC, MSC_SERIAL, serial); + + /*Which mode select (LED light) is currently on?*/ + touch_ring_mode = (data[11] & 0xC0) >> 6; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + if (wacom_wac->serial[i] == serial) + wacom->led.select[i] = touch_ring_mode; + } + + if (!wacom->battery && + !(features->quirks & WACOM_QUIRK_BATTERY)) { + features->quirks |= WACOM_QUIRK_BATTERY; + INIT_WORK(&wacom->work, wacom_battery_work); + wacom_schedule_work(wacom_wac); + } + + wacom_notify_battery(wacom_wac, bat_percent, bat_charging, 1, + bat_charging); + + return 1; +} + +static int wacom_remote_status_irq(struct wacom_wac *wacom_wac, size_t len) +{ + struct wacom *wacom = container_of(wacom_wac, struct wacom, wacom_wac); + unsigned char *data = wacom_wac->data; + int i; + + if (data[0] != WACOM_REPORT_DEVICE_LIST) + return 0; + + for (i = 0; i < WACOM_MAX_REMOTES; i++) { + int j = i * 6; + int serial = (data[j+6] << 16) + (data[j+5] << 8) + data[j+4]; + bool connected = data[j+2]; + + if (connected) { + int k; + + if (wacom_wac->serial[i] == serial) + continue; + + if (wacom_wac->serial[i]) { + wacom_remote_destroy_attr_group(wacom, + wacom_wac->serial[i]); + } + + /* A remote can pair more than once with an EKR, + * check to make sure this serial isn't already paired. + */ + for (k = 0; k < WACOM_MAX_REMOTES; k++) { + if (wacom_wac->serial[k] == serial) + break; + } + + if (k < WACOM_MAX_REMOTES) { + wacom_wac->serial[i] = serial; + continue; + } + wacom_remote_create_attr_group(wacom, serial, i); + + } else if (wacom_wac->serial[i]) { + wacom_remote_destroy_attr_group(wacom, + wacom_wac->serial[i]); + } + } + + return 0; +} + static void wacom_intuos_general(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; @@ -2191,6 +2315,13 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) sync = wacom_wireless_irq(wacom_wac, len); break; + case REMOTE: + if (wacom_wac->data[0] == WACOM_REPORT_DEVICE_LIST) + sync = wacom_remote_status_irq(wacom_wac, len); + else + sync = wacom_remote_irq(wacom_wac, len); + break; + default: sync = false; break; @@ -2298,6 +2429,9 @@ void wacom_setup_device_quirks(struct wacom *wacom) if (features->type == BAMBOO_PAD) features->device_type = WACOM_DEVICETYPE_TOUCH; + if (features->type == REMOTE) + features->device_type = WACOM_DEVICETYPE_PAD; + if (wacom->hdev->bus == BUS_BLUETOOTH) features->quirks |= WACOM_QUIRK_BATTERY; @@ -2717,6 +2851,11 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, break; + case REMOTE: + input_set_capability(input_dev, EV_MSC, MSC_SERIAL); + input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); + break; + default: /* no pad supported */ return -ENODEV; @@ -3186,6 +3325,10 @@ static const struct wacom_features wacom_features_0x323 = { "Wacom Intuos P M", 21600, 13500, 1023, 31, INTUOSHT, WACOM_INTUOS_RES, WACOM_INTUOS_RES, .check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE }; +static const struct wacom_features wacom_features_0x331 = + { "Wacom Express Key Remote", 0, 0, 0, 0, + REMOTE, 0, 0, 18, .check_for_hid_type = true, + .hid_type = HID_TYPE_USBNONE }; static const struct wacom_features wacom_features_HID_ANY_ID = { "Wacom HID", .type = HID_GENERIC }; @@ -3341,6 +3484,7 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x32B) }, { USB_DEVICE_WACOM(0x32C) }, { USB_DEVICE_WACOM(0x32F) }, + { USB_DEVICE_WACOM(0x331) }, { USB_DEVICE_WACOM(0x333) }, { USB_DEVICE_WACOM(0x335) }, { USB_DEVICE_WACOM(0x336) }, diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 4ee5c13b4e759..1e270d401e181 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -16,6 +16,8 @@ #define WACOM_PKGLEN_MAX 192 #define WACOM_NAME_MAX 64 +#define WACOM_MAX_REMOTES 5 +#define WACOM_STATUS_UNKNOWN 255 /* packet length for individual models */ #define WACOM_PKGLEN_BBFUN 9 @@ -65,6 +67,8 @@ #define WACOM_REPORT_USB 192 #define WACOM_REPORT_BPAD_PEN 3 #define WACOM_REPORT_BPAD_TOUCH 16 +#define WACOM_REPORT_DEVICE_LIST 16 +#define WACOM_REPORT_REMOTE 17 /* device quirks */ #define WACOM_QUIRK_BBTOUCH_LOWRES 0x0001 @@ -129,6 +133,7 @@ enum { WACOM_24HDT, WACOM_27QHDT, BAMBOO_PAD, + REMOTE, TABLETPC, /* add new TPC below */ TABLETPCE, TABLETPC2FG, @@ -208,7 +213,7 @@ struct wacom_wac { unsigned char data[WACOM_PKGLEN_MAX]; int tool[2]; int id[2]; - __u32 serial[2]; + __u32 serial[5]; bool reporting_data; struct wacom_features features; struct wacom_shared *shared; -- GitLab From 5397df15fd993acd23d9590dbb29d39219d80e3d Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Fri, 28 Aug 2015 20:46:42 +0200 Subject: [PATCH 5611/7006] HID: wacom: wacom_setup_numbered_buttons is local to wacom_wac wacom_setup_numbered_buttons() is not used outside of wacom_wac.c, make it static. Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 391a68731fe34..c40a6d14c8f2e 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2711,7 +2711,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, return 0; } -void wacom_setup_numbered_buttons(struct input_dev *input_dev, +static void wacom_setup_numbered_buttons(struct input_dev *input_dev, int button_count) { int i; -- GitLab From d4902632ffe5d6958bd267a6712575e3a312a6e2 Mon Sep 17 00:00:00 2001 From: Shengzhen Li Date: Wed, 19 Aug 2015 03:12:19 -0700 Subject: [PATCH 5612/7006] Bluetooth: btmrvl: change device pointer passed to dev_coredumpv This change ensures we will get driver name as 'btmrvl_sdio' in udev event. Signed-off-by: Shengzhen Li Signed-off-by: Amitkumar Karwar Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btmrvl_sdio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 7c097629e5931..b9978a7ba0cc9 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -1376,8 +1376,7 @@ done: /* fw_dump_data will be free in device coredump release function after 5 min*/ - dev_coredumpv(&priv->btmrvl_dev.hcidev->dev, fw_dump_data, - fw_dump_len, GFP_KERNEL); + dev_coredumpv(&card->func->dev, fw_dump_data, fw_dump_len, GFP_KERNEL); BT_INFO("== btmrvl firmware dump to /sys/class/devcoredump end"); } -- GitLab From df945360ce07ca592464e44fdd2ce61ee1536e1e Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Tue, 18 Aug 2015 21:23:01 -0400 Subject: [PATCH 5613/7006] Bluetooth: Make the function sco_conn_del have a return type of void This makes the function sco_conn_del have a return type of void now due to this function always running successfully and thus never needing to signal its caller when a non recoverable internal failure occurs by returning a error code to its respective caller. Signed-off-by: Nicholas Krause Signed-off-by: Marcel Holtmann --- net/bluetooth/sco.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 688a040c5626e..f315c8d0e43b5 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -154,13 +154,13 @@ static void sco_chan_del(struct sock *sk, int err) sock_set_flag(sk, SOCK_ZAPPED); } -static int sco_conn_del(struct hci_conn *hcon, int err) +static void sco_conn_del(struct hci_conn *hcon, int err) { struct sco_conn *conn = hcon->sco_data; struct sock *sk; if (!conn) - return 0; + return; BT_DBG("hcon %p conn %p, err %d", hcon, conn, err); @@ -179,7 +179,6 @@ static int sco_conn_del(struct hci_conn *hcon, int err) hcon->sco_data = NULL; kfree(conn); - return 0; } static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) -- GitLab From 4e1795de10903ae561872c54a72fa1bcf78f49cd Mon Sep 17 00:00:00 2001 From: Stefan Schmidt Date: Thu, 20 Aug 2015 12:09:47 +0200 Subject: [PATCH 5614/7006] nl802154: stricter input checking for boolean inputs So far we handled boolean input by forcing them with !! and assigning them into a bool. This allowed userspace to send values > 1 which were used as 1. We should be stricter here and return -EINVAL for all but 0 or 1. Signed-off-by: Stefan Schmidt Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- net/ieee802154/nl802154.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/net/ieee802154/nl802154.c b/net/ieee802154/nl802154.c index 1b00a14850cb5..3f89c0abdab17 100644 --- a/net/ieee802154/nl802154.c +++ b/net/ieee802154/nl802154.c @@ -1034,7 +1034,7 @@ static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) struct cfg802154_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wpan_dev *wpan_dev = dev->ieee802154_ptr; - bool mode; + int mode; if (netif_running(dev)) return -EBUSY; @@ -1042,7 +1042,11 @@ static int nl802154_set_lbt_mode(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL802154_ATTR_LBT_MODE]) return -EINVAL; - mode = !!nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]); + mode = nla_get_u8(info->attrs[NL802154_ATTR_LBT_MODE]); + + if (mode != 0 && mode != 1) + return -EINVAL; + if (!wpan_phy_supported_bool(mode, rdev->wpan_phy.supported.lbt)) return -EINVAL; @@ -1055,7 +1059,7 @@ nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info) struct cfg802154_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; struct wpan_dev *wpan_dev = dev->ieee802154_ptr; - bool ackreq; + int ackreq; if (netif_running(dev)) return -EBUSY; @@ -1063,7 +1067,11 @@ nl802154_set_ackreq_default(struct sk_buff *skb, struct genl_info *info) if (!info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]) return -EINVAL; - ackreq = !!nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]); + ackreq = nla_get_u8(info->attrs[NL802154_ATTR_ACKREQ_DEFAULT]); + + if (ackreq != 0 && ackreq != 1) + return -EINVAL; + return rdev_set_ackreq_default(rdev, wpan_dev, ackreq); } -- GitLab From e54991677e1c8060ba5642472cbd9a0954298d01 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Mon, 24 Aug 2015 18:57:57 +0200 Subject: [PATCH 5615/7006] Bluetooth: hci_uart: Fix zero len data packet reception issue Packets with a variable length value equal to zero were not received. Since no more data expected (and input buffer entirely consumed), we need to complete/forward the packet immediately instead of waiting for more data. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_h4.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 57faddc53645a..eec3f28e4bb9f 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -223,8 +223,7 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, switch ((&pkts[i])->lsize) { case 0: /* No variable data length */ - (&pkts[i])->recv(hdev, skb); - skb = NULL; + dlen = 0; break; case 1: /* Single octet variable length */ @@ -252,6 +251,12 @@ struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, kfree_skb(skb); return ERR_PTR(-EILSEQ); } + + if (!dlen) { + /* No more data, complete frame */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + } } else { /* Complete frame */ (&pkts[i])->recv(hdev, skb); -- GitLab From ff2895592f0fccc59332d5c7d4917ccbecd7468e Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Tue, 25 Aug 2015 17:55:44 +0200 Subject: [PATCH 5616/7006] Bluetooth: hci_intel: Add Intel baudrate configuration support Implement the set_baudrate callback for hci_intel. - Controller requires a read Intel version command before updating its baudrate. - The operation consists in an async cmd since the controller does not respond at the same speed. - Wait 100ms to let the controller change its baudrate. - Clear RTS until we change our own UART speed Manage speed change in the setup function, we need to restore the oper speed once chip has booted on patched firmware. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_intel.c | 119 ++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index 21dfa89751dfe..da3192aee5e15 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -45,6 +45,38 @@ struct intel_data { unsigned long flags; }; +static u8 intel_convert_speed(unsigned int speed) +{ + switch (speed) { + case 9600: + return 0x00; + case 19200: + return 0x01; + case 38400: + return 0x02; + case 57600: + return 0x03; + case 115200: + return 0x04; + case 230400: + return 0x05; + case 460800: + return 0x06; + case 921600: + return 0x07; + case 1843200: + return 0x08; + case 3250000: + return 0x09; + case 2000000: + return 0x0a; + case 3000000: + return 0x0b; + default: + return 0xff; + } +} + static int intel_open(struct hci_uart *hu) { struct intel_data *intel; @@ -111,6 +143,56 @@ static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode) return hci_recv_frame(hdev, skb); } +static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed) +{ + struct intel_data *intel = hu->priv; + struct hci_dev *hdev = hu->hdev; + u8 speed_cmd[] = { 0x06, 0xfc, 0x01, 0x00 }; + struct sk_buff *skb; + + BT_INFO("%s: Change controller speed to %d", hdev->name, speed); + + speed_cmd[3] = intel_convert_speed(speed); + if (speed_cmd[3] == 0xff) { + BT_ERR("%s: Unsupported speed", hdev->name); + return -EINVAL; + } + + /* Device will not accept speed change if Intel version has not been + * previously requested. + */ + skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading Intel version information failed (%ld)", + hdev->name, PTR_ERR(skb)); + return PTR_ERR(skb); + } + kfree_skb(skb); + + skb = bt_skb_alloc(sizeof(speed_cmd), GFP_KERNEL); + if (!skb) { + BT_ERR("%s: Failed to allocate memory for baudrate packet", + hdev->name); + return -ENOMEM; + } + + memcpy(skb_put(skb, sizeof(speed_cmd)), speed_cmd, sizeof(speed_cmd)); + bt_cb(skb)->pkt_type = HCI_COMMAND_PKT; + + hci_uart_set_flow_control(hu, true); + + skb_queue_tail(&intel->txq, skb); + hci_uart_tx_wakeup(hu); + + /* wait 100ms to change baudrate on controller side */ + msleep(100); + + hci_uart_set_baudrate(hu, speed); + hci_uart_set_flow_control(hu, false); + + return 0; +} + static int intel_setup(struct hci_uart *hu) { static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01, @@ -126,6 +208,8 @@ static int intel_setup(struct hci_uart *hu) u32 frag_len; ktime_t calltime, delta, rettime; unsigned long long duration; + unsigned int init_speed, oper_speed; + int speed_change = 0; int err; BT_DBG("%s", hdev->name); @@ -134,6 +218,19 @@ static int intel_setup(struct hci_uart *hu) calltime = ktime_get(); + if (hu->init_speed) + init_speed = hu->init_speed; + else + init_speed = hu->proto->init_speed; + + if (hu->oper_speed) + oper_speed = hu->oper_speed; + else + oper_speed = hu->proto->oper_speed; + + if (oper_speed && init_speed && oper_speed != init_speed) + speed_change = 1; + set_bit(STATE_BOOTLOADER, &intel->flags); /* Read the Intel version information to determine if the device @@ -416,6 +513,13 @@ done: if (err < 0) return err; + /* We need to restore the default speed before Intel reset */ + if (speed_change) { + err = intel_set_baudrate(hu, init_speed); + if (err) + return err; + } + calltime = ktime_get(); set_bit(STATE_BOOTING, &intel->flags); @@ -456,6 +560,19 @@ done: BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration); + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_CMD_TIMEOUT); + if (IS_ERR(skb)) + return PTR_ERR(skb); + kfree_skb(skb); + + if (speed_change) { + err = intel_set_baudrate(hu, oper_speed); + if (err) + return err; + } + + BT_INFO("%s: Setup complete", hdev->name); + clear_bit(STATE_BOOTLOADER, &intel->flags); return 0; @@ -572,10 +689,12 @@ static const struct hci_uart_proto intel_proto = { .id = HCI_UART_INTEL, .name = "Intel", .init_speed = 115200, + .oper_speed = 3000000, .open = intel_open, .close = intel_close, .flush = intel_flush, .setup = intel_setup, + .set_baudrate = intel_set_baudrate, .recv = intel_recv, .enqueue = intel_enqueue, .dequeue = intel_dequeue, -- GitLab From 5075edae086ff1c09e66699b7a27e1589ca75a3f Mon Sep 17 00:00:00 2001 From: Minjune Kim Date: Thu, 27 Aug 2015 13:21:52 +0900 Subject: [PATCH 5617/7006] Bluetooth: btusb: Correct typos based on checkpatch.pl Signed-off-by: Minjune Kim Signed-off-by: Marcel Holtmann --- drivers/bluetooth/btusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index f759dea7d3bae..b6aceaf82aa88 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1581,7 +1581,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) /* fw_patch_num indicates the version of patch the device currently * have. If there is no patch data in the device, it is always 0x00. - * So, if it is other than 0x00, no need to patch the deivce again. + * So, if it is other than 0x00, no need to patch the device again. */ if (ver->fw_patch_num) { BT_INFO("%s: Intel device is already patched. patch num: %02x", @@ -2100,7 +2100,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) frag_len += sizeof(*cmd) + cmd->plen; - /* The paramter length of the secure send command requires + /* The parameter length of the secure send command requires * a 4 byte alignment. It happens so that the firmware file * contains proper Intel_NOP commands to align the fragments * as needed. -- GitLab From 0ed97e829458496cc41ff8c39eb330d5a2247191 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 27 Aug 2015 08:57:39 +0200 Subject: [PATCH 5618/7006] Bluetooth: btintel: Add MODULE_FIRMWARE entries for iBT 3.0 controllers The iBT 3.0 controllers need intel/ibt-11-5.sfi and intel/ibt-11-5.ddc firmware files from linux-firmware repository. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c index 1ce4ac16c7fac..048423fd83bf8 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c @@ -173,3 +173,5 @@ MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("intel/ibt-11-5.sfi"); +MODULE_FIRMWARE("intel/ibt-11-5.ddc"); -- GitLab From 1ab1f239bf17e91b183a0f18fbb22722ff16d164 Mon Sep 17 00:00:00 2001 From: Loic Poulain Date: Thu, 27 Aug 2015 07:21:51 +0200 Subject: [PATCH 5619/7006] Bluetooth: hci_intel: Add support for platform driver A platform device can be used to provide some specific resources in order to manage the controller. In this first patch we retrieve the reset gpio which is used to power on/off the controller. The main issue is to match the current tty with the correct pdev. In case of ACPI, we can easily find the right tty/pdev pair because they are both child of the same UART port. If controller is powered-on from the driver, we need to wait for a HCI boot event before being able to send any command. Signed-off-by: Loic Poulain Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_intel.c | 202 +++++++++++++++++++++++++++++++--- 1 file changed, 189 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index da3192aee5e15..cf07d11219562 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -25,7 +25,12 @@ #include #include #include +#include #include +#include +#include +#include +#include #include #include @@ -39,6 +44,15 @@ #define STATE_FIRMWARE_FAILED 3 #define STATE_BOOTING 4 +struct intel_device { + struct list_head list; + struct platform_device *pdev; + struct gpio_desc *reset; +}; + +static LIST_HEAD(intel_device_list); +static DEFINE_SPINLOCK(intel_device_list_lock); + struct intel_data { struct sk_buff *rx_skb; struct sk_buff_head txq; @@ -77,6 +91,61 @@ static u8 intel_convert_speed(unsigned int speed) } } +static int intel_wait_booting(struct hci_uart *hu) +{ + struct intel_data *intel = hu->priv; + int err; + + err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(1000)); + + if (err == 1) { + BT_ERR("%s: Device boot interrupted", hu->hdev->name); + return -EINTR; + } + + if (err) { + BT_ERR("%s: Device boot timeout", hu->hdev->name); + return -ETIMEDOUT; + } + + return err; +} + +static int intel_set_power(struct hci_uart *hu, bool powered) +{ + struct list_head *p; + int err = -ENODEV; + + spin_lock(&intel_device_list_lock); + + list_for_each(p, &intel_device_list) { + struct intel_device *idev = list_entry(p, struct intel_device, + list); + + /* tty device and pdev device should share the same parent + * which is the UART port. + */ + if (hu->tty->dev->parent != idev->pdev->dev.parent) + continue; + + if (!idev->reset) { + err = -ENOTSUPP; + break; + } + + BT_INFO("hu %p, Switching compatible pm device (%s) to %u", + hu, dev_name(&idev->pdev->dev), powered); + + gpiod_set_value(idev->reset, powered); + } + + spin_unlock(&intel_device_list_lock); + + return err; +} + static int intel_open(struct hci_uart *hu) { struct intel_data *intel; @@ -90,6 +159,10 @@ static int intel_open(struct hci_uart *hu) skb_queue_head_init(&intel->txq); hu->priv = intel; + + if (!intel_set_power(hu, true)) + set_bit(STATE_BOOTING, &intel->flags); + return 0; } @@ -99,6 +172,8 @@ static int intel_close(struct hci_uart *hu) BT_DBG("hu %p", hu); + intel_set_power(hu, false); + skb_queue_purge(&intel->txq); kfree_skb(intel->rx_skb); kfree(intel); @@ -149,6 +224,18 @@ static int intel_set_baudrate(struct hci_uart *hu, unsigned int speed) struct hci_dev *hdev = hu->hdev; u8 speed_cmd[] = { 0x06, 0xfc, 0x01, 0x00 }; struct sk_buff *skb; + int err; + + /* This can be the first command sent to the chip, check + * that the controller is ready. + */ + err = intel_wait_booting(hu); + + clear_bit(STATE_BOOTING, &intel->flags); + + /* In case of timeout, try to continue anyway */ + if (err && err != ETIMEDOUT) + return err; BT_INFO("%s: Change controller speed to %d", hdev->name, speed); @@ -231,6 +318,15 @@ static int intel_setup(struct hci_uart *hu) if (oper_speed && init_speed && oper_speed != init_speed) speed_change = 1; + /* Check that the controller is ready */ + err = intel_wait_booting(hu); + + clear_bit(STATE_BOOTING, &intel->flags); + + /* In case of timeout, try to continue anyway */ + if (err && err != ETIMEDOUT) + return err; + set_bit(STATE_BOOTLOADER, &intel->flags); /* Read the Intel version information to determine if the device @@ -540,19 +636,11 @@ done: */ BT_INFO("%s: Waiting for device to boot", hdev->name); - err = wait_on_bit_timeout(&intel->flags, STATE_BOOTING, - TASK_INTERRUPTIBLE, - msecs_to_jiffies(1000)); - - if (err == 1) { - BT_ERR("%s: Device boot interrupted", hdev->name); - return -EINTR; - } + err = intel_wait_booting(hu); + if (err) + return err; - if (err) { - BT_ERR("%s: Device boot timeout", hdev->name); - return -ETIMEDOUT; - } + clear_bit(STATE_BOOTING, &intel->flags); rettime = ktime_get(); delta = ktime_sub(rettime, calltime); @@ -584,7 +672,8 @@ static int intel_recv_event(struct hci_dev *hdev, struct sk_buff *skb) struct intel_data *intel = hu->priv; struct hci_event_hdr *hdr; - if (!test_bit(STATE_BOOTLOADER, &intel->flags)) + if (!test_bit(STATE_BOOTLOADER, &intel->flags) && + !test_bit(STATE_BOOTING, &intel->flags)) goto recv; hdr = (void *)skb->data; @@ -700,12 +789,99 @@ static const struct hci_uart_proto intel_proto = { .dequeue = intel_dequeue, }; +#ifdef CONFIG_ACPI +static const struct acpi_device_id intel_acpi_match[] = { + { "INT33E1", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, intel_acpi_match); + +static int intel_acpi_probe(struct intel_device *idev) +{ + const struct acpi_device_id *id; + + id = acpi_match_device(intel_acpi_match, &idev->pdev->dev); + if (!id) + return -ENODEV; + + return 0; +} +#else +static int intel_acpi_probe(struct intel_device *idev) +{ + return -ENODEV; +} +#endif + +static int intel_probe(struct platform_device *pdev) +{ + struct intel_device *idev; + + idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); + if (!idev) + return -ENOMEM; + + idev->pdev = pdev; + + if (ACPI_HANDLE(&pdev->dev)) { + int err = intel_acpi_probe(idev); + if (err) + return err; + } else { + return -ENODEV; + } + + idev->reset = devm_gpiod_get_optional(&pdev->dev, "reset", + GPIOD_OUT_LOW); + if (IS_ERR(idev->reset)) { + dev_err(&pdev->dev, "Unable to retrieve gpio\n"); + return PTR_ERR(idev->reset); + } + + platform_set_drvdata(pdev, idev); + + /* Place this instance on the device list */ + spin_lock(&intel_device_list_lock); + list_add_tail(&idev->list, &intel_device_list); + spin_unlock(&intel_device_list_lock); + + dev_info(&pdev->dev, "registered.\n"); + + return 0; +} + +static int intel_remove(struct platform_device *pdev) +{ + struct intel_device *idev = platform_get_drvdata(pdev); + + spin_lock(&intel_device_list_lock); + list_del(&idev->list); + spin_unlock(&intel_device_list_lock); + + dev_info(&pdev->dev, "unregistered.\n"); + + return 0; +} + +static struct platform_driver intel_driver = { + .probe = intel_probe, + .remove = intel_remove, + .driver = { + .name = "hci_intel", + .acpi_match_table = ACPI_PTR(intel_acpi_match), + }, +}; + int __init intel_init(void) { + platform_driver_register(&intel_driver); + return hci_uart_register_proto(&intel_proto); } int __exit intel_deinit(void) { + platform_driver_unregister(&intel_driver); + return hci_uart_unregister_proto(&intel_proto); } -- GitLab From 618353b1f34947b3a399d6f51934f10df40e42ff Mon Sep 17 00:00:00 2001 From: Kuba Pawlak Date: Fri, 28 Aug 2015 13:05:22 +0100 Subject: [PATCH 5620/7006] Bluetooth: Fix SCO link type handling on connection complete Synchronous connections are initially created with type eSCO. Link manager may reject proposed link parameters, which triggers connection setup retry with a different set. Link type embedded in responses should be disregarded until Synchronous Connect Complete returns Success (0x00). Current code updates link type every time which creates an issue when link type changes to SCO and back to eSCO on further attepts. Issue happens with BlackBerry 9100 and 9700 with Intel WilkinsPeak on third connection setup attept 2015-05-18 01:27:57.332242 < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 handle 256 voice setting 0x0060 ptype 0x0380 2015-05-18 01:27:57.333604 > HCI Event: Command Status (0x0f) plen 4 Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1 2015-05-18 01:27:57.334614 > HCI Event: Synchronous Connect Complete (0x2c) plen 17 status 0x1a handle 0 bdaddr 30:7C:30:B3:A8:86 type SCO Error: Unsupported Remote Feature / Unsupported LMP Feature 2015-05-18 01:27:57.334895 < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 handle 256 voice setting 0x0060 ptype 0x0380 2015-05-18 01:27:57.335601 > HCI Event: Command Status (0x0f) plen 4 Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1 2015-05-18 01:27:57.336610 > HCI Event: Synchronous Connect Complete (0x2c) plen 17 status 0x1a handle 0 bdaddr 30:7C:30:B3:A8:86 type SCO Error: Unsupported Remote Feature / Unsupported LMP Feature 2015-05-18 01:27:57.336685 < HCI Command: Setup Synchronous Connection (0x01|0x0028) plen 17 handle 256 voice setting 0x0060 ptype 0x03c8 2015-05-18 01:27:57.337603 > HCI Event: Command Status (0x0f) plen 4 Setup Synchronous Connection (0x01|0x0028) status 0x00 ncmd 1 2015-05-18 01:27:57.342608 > HCI Event: Max Slots Change (0x1b) plen 3 handle 256 slots 1 2015-05-18 01:27:57.377631 > HCI Event: Synchronous Connect Complete (0x2c) plen 17 status 0x00 handle 257 bdaddr 30:7C:30:B3:A8:86 type eSCO Air mode: CVSD Signed-off-by: Kuba Pawlak Signed-off-by: Marcel Holtmann --- net/bluetooth/hci_event.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7ba35a9ba6b77..186041866315a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -3726,17 +3726,25 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, if (ev->link_type == ESCO_LINK) goto unlock; + /* When the link type in the event indicates SCO connection + * and lookup of the connection object fails, then check + * if an eSCO connection object exists. + * + * The core limits the synchronous connections to either + * SCO or eSCO. The eSCO connection is preferred and tried + * to be setup first and until successfully established, + * the link type will be hinted as eSCO. + */ conn = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, &ev->bdaddr); if (!conn) goto unlock; - - conn->type = SCO_LINK; } switch (ev->status) { case 0x00: conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; + conn->type = ev->link_type; hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); -- GitLab From 98dbbfc3f1a555194e784304d930d2aafde3e2a3 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 26 Aug 2015 23:20:51 +0200 Subject: [PATCH 5621/7006] Revert "netfilter: xtables: compute exact size needed for jumpstack" This reverts commit 98d1bd802cdbc8f56868fae51edec13e86b59515. mark_source_chains will not re-visit chains, so *filter :INPUT ACCEPT [365:25776] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [217:45832] :t1 - [0:0] :t2 - [0:0] :t3 - [0:0] :t4 - [0:0] -A t1 -i lo -j t2 -A t2 -i lo -j t3 -A t3 -i lo -j t4 # -A INPUT -j t4 # -A INPUT -j t3 # -A INPUT -j t2 -A INPUT -j t1 COMMIT Will compute a chain depth of 2 if the comments are removed. Revert back to counting the number of chains for the time being. Reported-by: Cong Wang Reported-by: Hannes Frederic Sowa Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv4/netfilter/arp_tables.c | 19 +++++++------------ net/ipv4/netfilter/ip_tables.c | 28 ++++++++++------------------ net/ipv6/netfilter/ip6_tables.c | 23 ++++++++--------------- 3 files changed, 25 insertions(+), 45 deletions(-) diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index c416cb355cb0c..8f87fc38ccde3 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -367,13 +367,10 @@ static inline bool unconditional(const struct arpt_arp *arp) /* Figures out from what hook each rule can be called: returns 0 if * there are loops. Puts hook bitmask in comefrom. - * - * Keeps track of largest call depth seen and stores it in newinfo->stacksize. */ -static int mark_source_chains(struct xt_table_info *newinfo, +static int mark_source_chains(const struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { - unsigned int calldepth, max_calldepth = 0; unsigned int hook; /* No recursion; use packet counter to save back ptrs (reset @@ -389,7 +386,6 @@ static int mark_source_chains(struct xt_table_info *newinfo, /* Set initial back pointer. */ e->counters.pcnt = pos; - calldepth = 0; for (;;) { const struct xt_standard_target *t @@ -444,8 +440,6 @@ static int mark_source_chains(struct xt_table_info *newinfo, (entry0 + pos + size); e->counters.pcnt = pos; pos += size; - if (calldepth > 0) - --calldepth; } else { int newpos = t->verdict; @@ -460,10 +454,6 @@ static int mark_source_chains(struct xt_table_info *newinfo, return 0; } - if (entry0 + newpos != arpt_next_entry(e) && - ++calldepth > max_calldepth) - max_calldepth = calldepth; - /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -480,7 +470,6 @@ static int mark_source_chains(struct xt_table_info *newinfo, next: duprintf("Finished chain %u\n", hook); } - newinfo->stacksize = max_calldepth; return 1; } @@ -670,6 +659,9 @@ static int translate_table(struct xt_table_info *newinfo, void *entry0, if (ret != 0) break; ++i; + if (strcmp(arpt_get_target(iter)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } duprintf("translate_table: ARPT_ENTRY_ITERATE gives %d\n", ret); if (ret != 0) @@ -1442,6 +1434,9 @@ static int translate_compat_table(const char *name, break; } ++i; + if (strcmp(arpt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 787f99ed55e26..b0a86e73451c1 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -443,15 +443,11 @@ ipt_do_table(struct sk_buff *skb, } /* Figures out from what hook each rule can be called: returns 0 if - * there are loops. Puts hook bitmask in comefrom. - * - * Keeps track of largest call depth seen and stores it in newinfo->stacksize. - */ + there are loops. Puts hook bitmask in comefrom. */ static int -mark_source_chains(struct xt_table_info *newinfo, +mark_source_chains(const struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { - unsigned int calldepth, max_calldepth = 0; unsigned int hook; /* No recursion; use packet counter to save back ptrs (reset @@ -465,7 +461,6 @@ mark_source_chains(struct xt_table_info *newinfo, /* Set initial back pointer. */ e->counters.pcnt = pos; - calldepth = 0; for (;;) { const struct xt_standard_target *t @@ -527,9 +522,6 @@ mark_source_chains(struct xt_table_info *newinfo, (entry0 + pos + size); e->counters.pcnt = pos; pos += size; - WARN_ON_ONCE(calldepth == 0); - if (calldepth > 0) - --calldepth; } else { int newpos = t->verdict; @@ -543,14 +535,9 @@ mark_source_chains(struct xt_table_info *newinfo, newpos); return 0; } - if (entry0 + newpos != ipt_next_entry(e) && - !(e->ip.flags & IPT_F_GOTO) && - ++calldepth > max_calldepth) - max_calldepth = calldepth; - /* This a jump; chase it. */ - duprintf("Jump rule %u -> %u, calldepth %d\n", - pos, newpos, calldepth); + duprintf("Jump rule %u -> %u\n", + pos, newpos); } else { /* ... this is a fallthru */ newpos = pos + e->next_offset; @@ -564,7 +551,6 @@ mark_source_chains(struct xt_table_info *newinfo, next: duprintf("Finished chain %u\n", hook); } - newinfo->stacksize = max_calldepth; return 1; } @@ -844,6 +830,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, if (ret != 0) return ret; ++i; + if (strcmp(ipt_get_target(iter)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (i != repl->num_entries) { @@ -1759,6 +1748,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ipt_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c index 4e21f80228be2..0771991ed812a 100644 --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c @@ -455,15 +455,11 @@ ip6t_do_table(struct sk_buff *skb, } /* Figures out from what hook each rule can be called: returns 0 if - * there are loops. Puts hook bitmask in comefrom. - * - * Keeps track of largest call depth seen and stores it in newinfo->stacksize. - */ + there are loops. Puts hook bitmask in comefrom. */ static int -mark_source_chains(struct xt_table_info *newinfo, +mark_source_chains(const struct xt_table_info *newinfo, unsigned int valid_hooks, void *entry0) { - unsigned int calldepth, max_calldepth = 0; unsigned int hook; /* No recursion; use packet counter to save back ptrs (reset @@ -477,7 +473,6 @@ mark_source_chains(struct xt_table_info *newinfo, /* Set initial back pointer. */ e->counters.pcnt = pos; - calldepth = 0; for (;;) { const struct xt_standard_target *t @@ -539,8 +534,6 @@ mark_source_chains(struct xt_table_info *newinfo, (entry0 + pos + size); e->counters.pcnt = pos; pos += size; - if (calldepth > 0) - --calldepth; } else { int newpos = t->verdict; @@ -554,11 +547,6 @@ mark_source_chains(struct xt_table_info *newinfo, newpos); return 0; } - if (entry0 + newpos != ip6t_next_entry(e) && - !(e->ipv6.flags & IP6T_F_GOTO) && - ++calldepth > max_calldepth) - max_calldepth = calldepth; - /* This a jump; chase it. */ duprintf("Jump rule %u -> %u\n", pos, newpos); @@ -575,7 +563,6 @@ mark_source_chains(struct xt_table_info *newinfo, next: duprintf("Finished chain %u\n", hook); } - newinfo->stacksize = max_calldepth; return 1; } @@ -855,6 +842,9 @@ translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0, if (ret != 0) return ret; ++i; + if (strcmp(ip6t_get_target(iter)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (i != repl->num_entries) { @@ -1767,6 +1757,9 @@ translate_compat_table(struct net *net, if (ret != 0) break; ++i; + if (strcmp(ip6t_get_target(iter1)->u.user.name, + XT_ERROR_TARGET) == 0) + ++newinfo->stacksize; } if (ret) { /* -- GitLab From 851345c5bbb4644911f7c351c042559a71f57d19 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Fri, 28 Aug 2015 00:16:21 +0200 Subject: [PATCH 5622/7006] netfilter: reduce sparse warnings bridge/netfilter/ebtables.c:290:26: warning: incorrect type in assignment (different modifiers) -> remove __pure annotation. ipv6/netfilter/ip6t_SYNPROXY.c:240:27: warning: cast from restricted __be16 -> switch ntohs to htons and vice versa. netfilter/core.c:391:30: warning: symbol 'nfq_ct_nat_hook' was not declared. Should it be static? -> delete it, got removed net/netfilter/nf_synproxy_core.c:221:48: warning: cast to restricted __be32 -> Use __be32 instead of u32. Tested with objdiff that these changes do not affect generated code. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/bridge/netfilter/ebtables.c | 2 +- net/ipv6/netfilter/ip6t_SYNPROXY.c | 2 +- net/netfilter/core.c | 3 --- net/netfilter/nf_synproxy_core.c | 6 +++--- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 18ca4b24c4183..48b6b01295de4 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -176,7 +176,7 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, return 0; } -static inline __pure +static inline struct ebt_entry *ebt_next_entry(const struct ebt_entry *entry) { return (void *)entry + entry->next_offset; diff --git a/net/ipv6/netfilter/ip6t_SYNPROXY.c b/net/ipv6/netfilter/ip6t_SYNPROXY.c index ebbb754c2111b..1e4bf99ed16e6 100644 --- a/net/ipv6/netfilter/ip6t_SYNPROXY.c +++ b/net/ipv6/netfilter/ip6t_SYNPROXY.c @@ -237,7 +237,7 @@ synproxy_send_client_ack(const struct synproxy_net *snet, nth->ack_seq = th->ack_seq; tcp_flag_word(nth) = TCP_FLAG_ACK; nth->doff = tcp_hdr_size / 4; - nth->window = ntohs(htons(th->window) >> opts->wscale); + nth->window = htons(ntohs(th->window) >> opts->wscale); nth->check = 0; nth->urg_ptr = 0; diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 2a5a0704245cc..0b939b7ad7241 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -388,9 +388,6 @@ EXPORT_SYMBOL(nf_conntrack_destroy); struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly; EXPORT_SYMBOL_GPL(nfq_ct_hook); -struct nfq_ct_nat_hook __rcu *nfq_ct_nat_hook __read_mostly; -EXPORT_SYMBOL_GPL(nfq_ct_nat_hook); - #endif /* CONFIG_NF_CONNTRACK */ #ifdef CONFIG_NF_NAT_NEEDED diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c index 8fbbdb09826ee..888b9558415eb 100644 --- a/net/netfilter/nf_synproxy_core.c +++ b/net/netfilter/nf_synproxy_core.c @@ -188,7 +188,7 @@ unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, const struct nf_conn_synproxy *synproxy) { unsigned int optoff, optend; - u32 *ptr, old; + __be32 *ptr, old; if (synproxy->tsoff == 0) return 1; @@ -216,12 +216,12 @@ unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, if (op[0] == TCPOPT_TIMESTAMP && op[1] == TCPOLEN_TIMESTAMP) { if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { - ptr = (u32 *)&op[2]; + ptr = (__be32 *)&op[2]; old = *ptr; *ptr = htonl(ntohl(*ptr) - synproxy->tsoff); } else { - ptr = (u32 *)&op[6]; + ptr = (__be32 *)&op[6]; old = *ptr; *ptr = htonl(ntohl(*ptr) + synproxy->tsoff); -- GitLab From 86b7709d48f0df8796bddd7e1ce45c6fb7a7c6ec Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 Aug 2015 09:52:22 -0400 Subject: [PATCH 5623/7006] drm/radeon: fix HDMI quantization_range for pre-DCE5 asics Support for output_csc is only available on DCE5 and newer so don't mess with the HDMI quantization_range on pre-DCE5 asics. bug: https://bugs.freedesktop.org/show_bug.cgi?id=83226 Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_audio.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c index fbc8d88d6e5de..2c02e99b5f95a 100644 --- a/drivers/gpu/drm/radeon/radeon_audio.c +++ b/drivers/gpu/drm/radeon/radeon_audio.c @@ -522,13 +522,15 @@ static int radeon_audio_set_avi_packet(struct drm_encoder *encoder, return err; } - if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { - if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) - frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; - else - frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; - } else { - frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + if (radeon_encoder->output_csc != RADEON_OUTPUT_CSC_BYPASS) { + if (drm_rgb_quant_range_selectable(radeon_connector_edid(connector))) { + if (radeon_encoder->output_csc == RADEON_OUTPUT_CSC_TVRGB) + frame.quantization_range = HDMI_QUANTIZATION_RANGE_LIMITED; + else + frame.quantization_range = HDMI_QUANTIZATION_RANGE_FULL; + } else { + frame.quantization_range = HDMI_QUANTIZATION_RANGE_DEFAULT; + } } err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer)); -- GitLab From 69bd5bf13a8eccb4db5f26de608556416a56d973 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 26 Aug 2015 11:31:23 +0200 Subject: [PATCH 5624/7006] drm/amdgpu: let the scheduler work more with jobs v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v2: fix another race condition Signed-off-by: Christian König Reviewed-by: Chunming Zhou Reviewed-by: Jammy Zhou --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 61 +++++++++++-------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index d99fe90991dc4..205cb887d0232 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -27,6 +27,8 @@ #include #include "gpu_scheduler.h" +static struct amd_sched_job * +amd_sched_entity_pop_job(struct amd_sched_entity *entity); static void amd_sched_wakeup(struct amd_gpu_scheduler *sched); /* Initialize a given run queue struct */ @@ -56,34 +58,36 @@ static void amd_sched_rq_remove_entity(struct amd_sched_rq *rq, } /** - * Select next entity from a specified run queue with round robin policy. - * It could return the same entity as current one if current is the only - * available one in the queue. Return NULL if nothing available. + * Select next job from a specified run queue with round robin policy. + * Return NULL if nothing available. */ -static struct amd_sched_entity * -amd_sched_rq_select_entity(struct amd_sched_rq *rq) +static struct amd_sched_job * +amd_sched_rq_select_job(struct amd_sched_rq *rq) { struct amd_sched_entity *entity; + struct amd_sched_job *job; spin_lock(&rq->lock); entity = rq->current_entity; if (entity) { list_for_each_entry_continue(entity, &rq->entities, list) { - if (!kfifo_is_empty(&entity->job_queue)) { + job = amd_sched_entity_pop_job(entity); + if (job) { rq->current_entity = entity; spin_unlock(&rq->lock); - return rq->current_entity; + return job; } } } list_for_each_entry(entity, &rq->entities, list) { - if (!kfifo_is_empty(&entity->job_queue)) { + job = amd_sched_entity_pop_job(entity); + if (job) { rq->current_entity = entity; spin_unlock(&rq->lock); - return rq->current_entity; + return job; } if (entity == rq->current_entity) @@ -188,6 +192,17 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, kfifo_free(&entity->job_queue); } +static struct amd_sched_job * +amd_sched_entity_pop_job(struct amd_sched_entity *entity) +{ + struct amd_sched_job *job; + + if (!kfifo_out_peek(&entity->job_queue, &job, sizeof(job))) + return NULL; + + return job; +} + /** * Helper to submit a job to the job queue * @@ -260,22 +275,22 @@ static void amd_sched_wakeup(struct amd_gpu_scheduler *sched) } /** - * Select next entity containing real IB submissions + * Select next to run */ -static struct amd_sched_entity * -amd_sched_select_context(struct amd_gpu_scheduler *sched) +static struct amd_sched_job * +amd_sched_select_job(struct amd_gpu_scheduler *sched) { - struct amd_sched_entity *tmp; + struct amd_sched_job *job; if (!amd_sched_ready(sched)) return NULL; /* Kernel run queue has higher priority than normal run queue*/ - tmp = amd_sched_rq_select_entity(&sched->kernel_rq); - if (tmp == NULL) - tmp = amd_sched_rq_select_entity(&sched->sched_rq); + job = amd_sched_rq_select_job(&sched->kernel_rq); + if (job == NULL) + job = amd_sched_rq_select_job(&sched->sched_rq); - return tmp; + return job; } static void amd_sched_process_job(struct fence *f, struct fence_cb *cb) @@ -301,22 +316,19 @@ static int amd_sched_main(void *param) sched_setscheduler(current, SCHED_FIFO, &sparam); while (!kthread_should_stop()) { - struct amd_sched_entity *c_entity = NULL; + struct amd_sched_entity *entity; struct amd_sched_job *job; struct fence *fence; wait_event_interruptible(sched->wake_up_worker, kthread_should_stop() || - (c_entity = amd_sched_select_context(sched))); + (job = amd_sched_select_job(sched))); - if (!c_entity) + if (!job) continue; - r = kfifo_out(&c_entity->job_queue, &job, sizeof(void *)); - if (r != sizeof(void *)) - continue; + entity = job->s_entity; atomic_inc(&sched->hw_rq_count); - fence = sched->ops->run_job(job); if (fence) { r = fence_add_callback(fence, &job->cb, @@ -328,6 +340,7 @@ static int amd_sched_main(void *param) fence_put(fence); } + kfifo_out(&entity->job_queue, &job, sizeof(job)); wake_up(&sched->job_scheduled); } return 0; -- GitLab From e61235db62c5e68e56e59bea62b88f9f3d7a3cf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 25 Aug 2015 11:05:36 +0200 Subject: [PATCH 5625/7006] drm/amdgpu: add scheduler dependency callback v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This way the scheduler doesn't wait in it's work thread any more. v2: fix race conditions Signed-off-by: Christian König Reviewed-by: Chunming Zhou Reviewed-by: Jammy Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c | 7 ++++++ drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 22 +++++++++++++++++++ drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 22 +++++++++++++++++++ drivers/gpu/drm/amd/scheduler/gpu_scheduler.h | 3 +++ 5 files changed, 55 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index aa2dcf578dd6d..719506808b4a6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -717,6 +717,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, void *owner); int amdgpu_sync_rings(struct amdgpu_sync *sync, struct amdgpu_ring *ring); +struct fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync); int amdgpu_sync_wait(struct amdgpu_sync *sync); void amdgpu_sync_free(struct amdgpu_device *adev, struct amdgpu_sync *sync, struct fence *fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c index f93fb35414884..de98fbd2971ed 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sched.c @@ -27,6 +27,12 @@ #include #include "amdgpu.h" +static struct fence *amdgpu_sched_dependency(struct amd_sched_job *job) +{ + struct amdgpu_job *sched_job = (struct amdgpu_job *)job; + return amdgpu_sync_get_fence(&sched_job->ibs->sync); +} + static struct fence *amdgpu_sched_run_job(struct amd_sched_job *job) { struct amdgpu_job *sched_job; @@ -75,6 +81,7 @@ static void amdgpu_sched_process_job(struct amd_sched_job *job) } struct amd_sched_backend_ops amdgpu_sched_ops = { + .dependency = amdgpu_sched_dependency, .run_job = amdgpu_sched_run_job, .process_job = amdgpu_sched_process_job }; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 4fffb25393318..69b7d4540c6ef 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -202,6 +202,28 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, return r; } +struct fence *amdgpu_sync_get_fence(struct amdgpu_sync *sync) +{ + struct amdgpu_sync_entry *e; + struct hlist_node *tmp; + struct fence *f; + int i; + + hash_for_each_safe(sync->fences, i, tmp, e, node) { + + f = e->fence; + + hash_del(&e->node); + kfree(e); + + if (!fence_is_signaled(f)) + return f; + + fence_put(f); + } + return NULL; +} + int amdgpu_sync_wait(struct amdgpu_sync *sync) { struct amdgpu_sync_entry *e; diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 205cb887d0232..2f5d1f0da8e5f 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -192,14 +192,36 @@ void amd_sched_entity_fini(struct amd_gpu_scheduler *sched, kfifo_free(&entity->job_queue); } +static void amd_sched_entity_wakeup(struct fence *f, struct fence_cb *cb) +{ + struct amd_sched_entity *entity = + container_of(cb, struct amd_sched_entity, cb); + entity->dependency = NULL; + fence_put(f); + amd_sched_wakeup(entity->scheduler); +} + static struct amd_sched_job * amd_sched_entity_pop_job(struct amd_sched_entity *entity) { + struct amd_gpu_scheduler *sched = entity->scheduler; struct amd_sched_job *job; + if (ACCESS_ONCE(entity->dependency)) + return NULL; + if (!kfifo_out_peek(&entity->job_queue, &job, sizeof(job))) return NULL; + while ((entity->dependency = sched->ops->dependency(job))) { + + if (fence_add_callback(entity->dependency, &entity->cb, + amd_sched_entity_wakeup)) + fence_put(entity->dependency); + else + return NULL; + } + return job; } diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h index e797796dcad75..2af0e4d4d817a 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.h @@ -45,6 +45,8 @@ struct amd_sched_entity { spinlock_t queue_lock; struct amd_gpu_scheduler *scheduler; uint64_t fence_context; + struct fence *dependency; + struct fence_cb cb; }; /** @@ -89,6 +91,7 @@ static inline struct amd_sched_fence *to_amd_sched_fence(struct fence *f) * these functions should be implemented in driver side */ struct amd_sched_backend_ops { + struct fence *(*dependency)(struct amd_sched_job *job); struct fence *(*run_job)(struct amd_sched_job *job); void (*process_job)(struct amd_sched_job *job); }; -- GitLab From 8f8202f771c182a7244caa5880f50def1bedd713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Thu, 7 May 2015 15:19:25 +0200 Subject: [PATCH 5626/7006] drm/amdgpu: stop trying to suspend UVD sessions v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Saving the current UVD state on suspend and restoring it on resume just doesn't work reliable. Just close cleanup all sessions on suspend. Ported from radeon commit "12e49feadff6d7b7ebbe852b36943a71524d8d34". v2: rebased Signed-off-by: Christian König Reviewed-by: Alex Deucher (v1) --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 - drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 42 +++++++++++-------------- 2 files changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 719506808b4a6..9fefcd9c1af1a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1666,7 +1666,6 @@ struct amdgpu_uvd { struct amdgpu_bo *vcpu_bo; void *cpu_addr; uint64_t gpu_addr; - void *saved_bo; atomic_t handles[AMDGPU_MAX_UVD_HANDLES]; struct drm_file *filp[AMDGPU_MAX_UVD_HANDLES]; struct delayed_work idle_work; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index b87355ccfb1d0..3ad4a83c418fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -221,31 +221,32 @@ int amdgpu_uvd_sw_fini(struct amdgpu_device *adev) int amdgpu_uvd_suspend(struct amdgpu_device *adev) { - unsigned size; - void *ptr; - const struct common_firmware_header *hdr; - int i; + struct amdgpu_ring *ring = &adev->uvd.ring; + int i, r; if (adev->uvd.vcpu_bo == NULL) return 0; - for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) - if (atomic_read(&adev->uvd.handles[i])) - break; - - if (i == AMDGPU_MAX_UVD_HANDLES) - return 0; + for (i = 0; i < AMDGPU_MAX_UVD_HANDLES; ++i) { + uint32_t handle = atomic_read(&adev->uvd.handles[i]); + if (handle != 0) { + struct fence *fence; - hdr = (const struct common_firmware_header *)adev->uvd.fw->data; + amdgpu_uvd_note_usage(adev); - size = amdgpu_bo_size(adev->uvd.vcpu_bo); - size -= le32_to_cpu(hdr->ucode_size_bytes); + r = amdgpu_uvd_get_destroy_msg(ring, handle, &fence); + if (r) { + DRM_ERROR("Error destroying UVD (%d)!\n", r); + continue; + } - ptr = adev->uvd.cpu_addr; - ptr += le32_to_cpu(hdr->ucode_size_bytes); + fence_wait(fence, false); + fence_put(fence); - adev->uvd.saved_bo = kmalloc(size, GFP_KERNEL); - memcpy(adev->uvd.saved_bo, ptr, size); + adev->uvd.filp[i] = NULL; + atomic_set(&adev->uvd.handles[i], 0); + } + } return 0; } @@ -270,12 +271,7 @@ int amdgpu_uvd_resume(struct amdgpu_device *adev) ptr = adev->uvd.cpu_addr; ptr += le32_to_cpu(hdr->ucode_size_bytes); - if (adev->uvd.saved_bo != NULL) { - memcpy(ptr, adev->uvd.saved_bo, size); - kfree(adev->uvd.saved_bo); - adev->uvd.saved_bo = NULL; - } else - memset(ptr, 0, size); + memset(ptr, 0, size); return 0; } -- GitLab From 6e7a3840745c950c37d37cbb0af2e753a765d4ec Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Thu, 27 Aug 2015 13:46:09 +0800 Subject: [PATCH 5627/7006] drm/amdgpu: use IB for fill_buffer instead of direct command Signed-off-by: Chunming Zhou Reviewed-by: Christian K?nig Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 4 ++-- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 12 ++++++------ drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 12 ++++++------ drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 12 ++++++------ 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 9fefcd9c1af1a..c6812f2e198ee 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -262,7 +262,7 @@ struct amdgpu_buffer_funcs { unsigned fill_num_dw; /* used for buffer clearing */ - void (*emit_fill_buffer)(struct amdgpu_ring *ring, + void (*emit_fill_buffer)(struct amdgpu_ib *ib, /* value to write to memory */ uint32_t src_data, /* dst addr in bytes */ @@ -2248,7 +2248,7 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v) #define amdgpu_display_stop_mc_access(adev, s) (adev)->mode_info.funcs->stop_mc_access((adev), (s)) #define amdgpu_display_resume_mc_access(adev, s) (adev)->mode_info.funcs->resume_mc_access((adev), (s)) #define amdgpu_emit_copy_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_copy_buffer((ib), (s), (d), (b)) -#define amdgpu_emit_fill_buffer(adev, r, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((r), (s), (d), (b)) +#define amdgpu_emit_fill_buffer(adev, ib, s, d, b) (adev)->mman.buffer_funcs->emit_fill_buffer((ib), (s), (d), (b)) #define amdgpu_dpm_get_temperature(adev) (adev)->pm.funcs->get_temperature((adev)) #define amdgpu_dpm_pre_set_power_state(adev) (adev)->pm.funcs->pre_set_power_state((adev)) #define amdgpu_dpm_set_power_state(adev) (adev)->pm.funcs->set_power_state((adev)) diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index 3920c1e346f8e..c1e782952bd7b 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -1363,16 +1363,16 @@ static void cik_sdma_emit_copy_buffer(struct amdgpu_ib *ib, * * Fill GPU buffers using the DMA engine (CIK). */ -static void cik_sdma_emit_fill_buffer(struct amdgpu_ring *ring, +static void cik_sdma_emit_fill_buffer(struct amdgpu_ib *ib, uint32_t src_data, uint64_t dst_offset, uint32_t byte_count) { - amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0, 0)); - amdgpu_ring_write(ring, lower_32_bits(dst_offset)); - amdgpu_ring_write(ring, upper_32_bits(dst_offset)); - amdgpu_ring_write(ring, src_data); - amdgpu_ring_write(ring, byte_count); + ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_CONSTANT_FILL, 0, 0); + ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = src_data; + ib->ptr[ib->length_dw++] = byte_count; } static const struct amdgpu_buffer_funcs cik_sdma_buffer_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 715e02d3bfbac..2f3948c090816 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -1375,16 +1375,16 @@ static void sdma_v2_4_emit_copy_buffer(struct amdgpu_ib *ib, * * Fill GPU buffers using the DMA engine (VI). */ -static void sdma_v2_4_emit_fill_buffer(struct amdgpu_ring *ring, +static void sdma_v2_4_emit_fill_buffer(struct amdgpu_ib *ib, uint32_t src_data, uint64_t dst_offset, uint32_t byte_count) { - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL)); - amdgpu_ring_write(ring, lower_32_bits(dst_offset)); - amdgpu_ring_write(ring, upper_32_bits(dst_offset)); - amdgpu_ring_write(ring, src_data); - amdgpu_ring_write(ring, byte_count); + ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL); + ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = src_data; + ib->ptr[ib->length_dw++] = byte_count; } static const struct amdgpu_buffer_funcs sdma_v2_4_buffer_funcs = { diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 67128c8e78b84..a9d9607e8d916 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1499,16 +1499,16 @@ static void sdma_v3_0_emit_copy_buffer(struct amdgpu_ib *ib, * * Fill GPU buffers using the DMA engine (VI). */ -static void sdma_v3_0_emit_fill_buffer(struct amdgpu_ring *ring, +static void sdma_v3_0_emit_fill_buffer(struct amdgpu_ib *ib, uint32_t src_data, uint64_t dst_offset, uint32_t byte_count) { - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL)); - amdgpu_ring_write(ring, lower_32_bits(dst_offset)); - amdgpu_ring_write(ring, upper_32_bits(dst_offset)); - amdgpu_ring_write(ring, src_data); - amdgpu_ring_write(ring, byte_count); + ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_CONST_FILL); + ib->ptr[ib->length_dw++] = lower_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = upper_32_bits(dst_offset); + ib->ptr[ib->length_dw++] = src_data; + ib->ptr[ib->length_dw++] = byte_count; } static const struct amdgpu_buffer_funcs sdma_v3_0_buffer_funcs = { -- GitLab From 917522aae169ad02010dcee6ae42c16155bcd285 Mon Sep 17 00:00:00 2001 From: Frederic Danis Date: Fri, 28 Aug 2015 15:44:00 +0200 Subject: [PATCH 5628/7006] Bluetooth: hci_bcm: Fix crash on suspend If bcm_suspend is called whithout device opened there is a crash as it tries to use bdev->hu which is NULL. Rename bcm_device_list_lock to bcm_device_lock as it does not only apply to bcm_device_list. Signed-off-by: Frederic Danis Signed-off-by: Marcel Holtmann --- drivers/bluetooth/hci_bcm.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 33ec09752ea81..835bfab88ef56 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -66,7 +66,7 @@ struct bcm_data { }; /* List of BCM BT UART devices */ -static DEFINE_SPINLOCK(bcm_device_list_lock); +static DEFINE_SPINLOCK(bcm_device_lock); static LIST_HEAD(bcm_device_list); static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) @@ -118,7 +118,7 @@ static int bcm_set_baudrate(struct hci_uart *hu, unsigned int speed) return 0; } -/* bcm_device_exists should be protected by bcm_device_list_lock */ +/* bcm_device_exists should be protected by bcm_device_lock */ static bool bcm_device_exists(struct bcm_device *device) { struct list_head *p; @@ -164,7 +164,7 @@ static int bcm_open(struct hci_uart *hu) hu->priv = bcm; - spin_lock(&bcm_device_list_lock); + spin_lock(&bcm_device_lock); list_for_each(p, &bcm_device_list) { struct bcm_device *dev = list_entry(p, struct bcm_device, list); @@ -185,7 +185,7 @@ static int bcm_open(struct hci_uart *hu) if (bcm->dev) bcm_gpio_set_power(bcm->dev, true); - spin_unlock(&bcm_device_list_lock); + spin_unlock(&bcm_device_lock); return 0; } @@ -197,14 +197,14 @@ static int bcm_close(struct hci_uart *hu) BT_DBG("hu %p", hu); /* Protect bcm->dev against removal of the device or driver */ - spin_lock(&bcm_device_list_lock); + spin_lock(&bcm_device_lock); if (bcm_device_exists(bcm->dev)) { bcm_gpio_set_power(bcm->dev, false); #ifdef CONFIG_PM_SLEEP bcm->dev->hu = NULL; #endif } - spin_unlock(&bcm_device_list_lock); + spin_unlock(&bcm_device_lock); skb_queue_purge(&bcm->txq); kfree_skb(bcm->rx_skb); @@ -338,6 +338,11 @@ static int bcm_suspend(struct device *dev) BT_DBG("suspend (%p): is_suspended %d", bdev, bdev->is_suspended); + spin_lock(&bcm_device_lock); + + if (!bdev->hu) + goto unlock; + if (!bdev->is_suspended) { hci_uart_set_flow_control(bdev->hu, true); @@ -352,6 +357,9 @@ static int bcm_suspend(struct device *dev) mdelay(15); } +unlock: + spin_unlock(&bcm_device_lock); + return 0; } @@ -362,6 +370,11 @@ static int bcm_resume(struct device *dev) BT_DBG("resume (%p): is_suspended %d", bdev, bdev->is_suspended); + spin_lock(&bcm_device_lock); + + if (!bdev->hu) + goto unlock; + if (bdev->device_wakeup) { gpiod_set_value(bdev->device_wakeup, true); BT_DBG("resume, delaying 15 ms"); @@ -375,6 +388,9 @@ static int bcm_resume(struct device *dev) hci_uart_set_flow_control(bdev->hu, false); } +unlock: + spin_unlock(&bcm_device_lock); + return 0; } #endif @@ -488,9 +504,9 @@ static int bcm_probe(struct platform_device *pdev) dev_info(&pdev->dev, "%s device registered.\n", dev->name); /* Place this instance on the device list */ - spin_lock(&bcm_device_list_lock); + spin_lock(&bcm_device_lock); list_add_tail(&dev->list, &bcm_device_list); - spin_unlock(&bcm_device_list_lock); + spin_unlock(&bcm_device_lock); bcm_gpio_set_power(dev, false); @@ -501,9 +517,9 @@ static int bcm_remove(struct platform_device *pdev) { struct bcm_device *dev = platform_get_drvdata(pdev); - spin_lock(&bcm_device_list_lock); + spin_lock(&bcm_device_lock); list_del(&dev->list); - spin_unlock(&bcm_device_list_lock); + spin_unlock(&bcm_device_lock); acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev)); -- GitLab From 3cb4fc1fcae9647c594bc2b8fda1b818f4fb757f Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Wed, 19 Aug 2015 11:47:05 -0300 Subject: [PATCH 5629/7006] ipr: Inhibit underlength data check for AFDASD in raw mode. Disable underlength error verification based on count of bytes actually transferred for AF DASD devices when SIS pipe mode is enabled. This avoids unexpected underlength errors when issuing some commands in raw mode. Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Wen Xiong Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 341191952155d..ba16dd79f4519 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -6383,9 +6383,13 @@ static int ipr_queuecommand(struct Scsi_Host *shost, (!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE)) { ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD; } - if (res->raw_mode && ipr_is_af_dasd_device(res)) + if (res->raw_mode && ipr_is_af_dasd_device(res)) { ioarcb->cmd_pkt.request_type = IPR_RQTYPE_PIPE; + if (scsi_cmd->underflow == 0) + ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK; + } + if (ioa_cfg->sis64) rc = ipr_build_ioadl64(ioa_cfg, ipr_cmd); else -- GitLab From e35d7f27fbd51a09a41a5439e39f22a3d102c00b Mon Sep 17 00:00:00 2001 From: Gabriel Krisman Bertazi Date: Wed, 19 Aug 2015 11:47:06 -0300 Subject: [PATCH 5630/7006] ipr: Enable SIS pipe commands for SIS-32 devices. Remove unnecessary check that disabled SIS pipe commands for SIS-32 devices. This change was sufficient to enable raw mode and send SIS pipe commands for a 57B3 device. Fixes: f8ee25d7d239 ("ipr: AF DASD raw mode implementation in ipr driver") Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Wen Xiong Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/ipr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index ba16dd79f4519..b62836ddbbee5 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -4555,7 +4555,7 @@ static ssize_t ipr_store_raw_mode(struct device *dev, spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags); res = (struct ipr_resource_entry *)sdev->hostdata; if (res) { - if (ioa_cfg->sis64 && ipr_is_af_dasd_device(res)) { + if (ipr_is_af_dasd_device(res)) { res->raw_mode = simple_strtoul(buf, NULL, 10); len = strlen(buf); if (res->sdev) -- GitLab From 36dd5acd196574d41de3e81d8264df475bbb7123 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 6 Jul 2015 13:07:58 +0200 Subject: [PATCH 5631/7006] aic94xx: Skip reading user settings if flash is not found If no user settings are found it's pointless trying to read them from flash. So skip that step. This also fixes a compilation warning about uninitialized variables in aic94xx. Signed-off-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic94xx/aic94xx_sds.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c index edb43fda9f36f..c831e30411fa1 100644 --- a/drivers/scsi/aic94xx/aic94xx_sds.c +++ b/drivers/scsi/aic94xx/aic94xx_sds.c @@ -983,7 +983,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha, { int err, i; u32 offs, size; - struct asd_ll_el *el; + struct asd_ll_el *el = NULL; struct asd_ctrla_phy_settings *ps; struct asd_ctrla_phy_settings dflt_ps; @@ -1004,6 +1004,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha, size = sizeof(struct asd_ctrla_phy_settings); ps = &dflt_ps; + goto out_process; } if (size == 0) @@ -1028,7 +1029,7 @@ static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha, ASD_DPRINTK("couldn't find ctrla phy settings struct\n"); goto out2; } - +out_process: err = asd_process_ctrla_phy_settings(asd_ha, ps); if (err) { ASD_DPRINTK("couldn't process ctrla phy settings\n"); -- GitLab From 1bab0de0274fbe8c8ac92179e6705584c55ed169 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:16:54 +0200 Subject: [PATCH 5632/7006] dm-mpath, scsi_dh: don't let dm detach device handlers While allowing dm-mpath to attach device handlers is a functionality we need for backwards compatibility reason there is no reason to reference count them and detach them if dm-mpath stops using the device for some reason. If the device handler works for the given device it can just stay attached, and we can take the retain_hw_handler codepath. Signed-off-by: Christoph Hellwig Acked-by: Mike Snitzer Acked-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/md/dm-mpath.c | 21 ++---- drivers/scsi/device_handler/scsi_dh.c | 96 ++++++--------------------- include/scsi/scsi_device.h | 1 - include/scsi/scsi_dh.h | 5 -- 4 files changed, 28 insertions(+), 95 deletions(-) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index eff7bdd7731d5..a9f58fdb5d69d 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -159,12 +159,9 @@ static struct priority_group *alloc_priority_group(void) static void free_pgpaths(struct list_head *pgpaths, struct dm_target *ti) { struct pgpath *pgpath, *tmp; - struct multipath *m = ti->private; list_for_each_entry_safe(pgpath, tmp, pgpaths, list) { list_del(&pgpath->list); - if (m->hw_handler_name) - scsi_dh_detach(bdev_get_queue(pgpath->path.dev->bdev)); dm_put_device(ti, pgpath->path.dev); free_pgpath(pgpath); } @@ -580,6 +577,7 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps q = bdev_get_queue(p->path.dev->bdev); if (m->retain_attached_hw_handler) { +retain: attached_handler_name = scsi_dh_attached_handler_name(q, GFP_KERNEL); if (attached_handler_name) { /* @@ -599,20 +597,14 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps } if (m->hw_handler_name) { - /* - * Increments scsi_dh reference, even when using an - * already-attached handler. - */ r = scsi_dh_attach(q, m->hw_handler_name); if (r == -EBUSY) { - /* - * Already attached to different hw_handler: - * try to reattach with correct one. - */ - scsi_dh_detach(q); - r = scsi_dh_attach(q, m->hw_handler_name); - } + char b[BDEVNAME_SIZE]; + printk(KERN_INFO "dm-mpath: retaining handler on device %s\n", + bdevname(p->path.dev->bdev, b)); + goto retain; + } if (r < 0) { ti->error = "error attaching hardware handler"; dm_put_device(ti, p->path.dev); @@ -624,7 +616,6 @@ static struct pgpath *parse_path(struct dm_arg_set *as, struct path_selector *ps if (r < 0) { ti->error = "unable to set hardware " "handler parameters"; - scsi_dh_detach(q); dm_put_device(ti, p->path.dev); goto bad; } diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 1efebc9eedfb3..869b5bd1ad252 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -100,14 +100,6 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, { struct scsi_dh_data *d; - if (sdev->scsi_dh_data) { - if (sdev->scsi_dh_data->scsi_dh != scsi_dh) - return -EBUSY; - - kref_get(&sdev->scsi_dh_data->kref); - return 0; - } - if (!try_module_get(scsi_dh->module)) return -EINVAL; @@ -120,7 +112,6 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, } d->scsi_dh = scsi_dh; - kref_init(&d->kref); d->sdev = sdev; spin_lock_irq(sdev->request_queue->queue_lock); @@ -129,12 +120,14 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, return 0; } -static void __detach_handler (struct kref *kref) +/* + * scsi_dh_handler_detach - Detach a device handler from a device + * @sdev - SCSI device the device handler should be detached from + */ +static void scsi_dh_handler_detach(struct scsi_device *sdev) { - struct scsi_dh_data *scsi_dh_data = - container_of(kref, struct scsi_dh_data, kref); + struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh; - struct scsi_device *sdev = scsi_dh_data->sdev; scsi_dh->detach(sdev); @@ -146,30 +139,6 @@ static void __detach_handler (struct kref *kref) module_put(scsi_dh->module); } -/* - * scsi_dh_handler_detach - Detach a device handler from a device - * @sdev - SCSI device the device handler should be detached from - * @scsi_dh - Device handler to be detached - * - * Detach from a device handler. If a device handler is specified, - * only detach if the currently attached handler matches @scsi_dh. - */ -static void scsi_dh_handler_detach(struct scsi_device *sdev, - struct scsi_device_handler *scsi_dh) -{ - if (!sdev->scsi_dh_data) - return; - - if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh) - return; - - if (!scsi_dh) - scsi_dh = sdev->scsi_dh_data->scsi_dh; - - if (scsi_dh) - kref_put(&sdev->scsi_dh_data->kref, __detach_handler); -} - /* * Functions for sysfs attribute 'dh_state' */ @@ -198,7 +167,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr, /* * Detach from a device handler */ - scsi_dh_handler_detach(sdev, scsi_dh); + scsi_dh_handler_detach(sdev); err = 0; } else if (!strncmp(buf, "activate", 8)) { /* @@ -290,7 +259,8 @@ static int scsi_dh_notifier(struct notifier_block *nb, err = scsi_dh_handler_attach(sdev, devinfo); } else if (action == BUS_NOTIFY_DEL_DEVICE) { device_remove_file(dev, &scsi_dh_state_attr); - scsi_dh_handler_detach(sdev, NULL); + if (sdev->scsi_dh_data) + scsi_dh_handler_detach(sdev); } return err; } @@ -335,7 +305,8 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data) sdev = to_scsi_device(dev); - scsi_dh_handler_detach(sdev, scsi_dh); + if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh) + scsi_dh_handler_detach(sdev); put_device(dev); @@ -517,45 +488,22 @@ int scsi_dh_attach(struct request_queue *q, const char *name) err = -ENODEV; spin_unlock_irqrestore(q->queue_lock, flags); - if (!err) { - err = scsi_dh_handler_attach(sdev, scsi_dh); - put_device(&sdev->sdev_gendev); - } - return err; -} -EXPORT_SYMBOL_GPL(scsi_dh_attach); - -/* - * scsi_dh_detach - Detach device handler - * @q - Request queue that is associated with the scsi_device - * the handler should be detached from - * - * This function will detach the device handler only - * if the sdev is not part of the internal list, ie - * if it has been attached manually. - */ -void scsi_dh_detach(struct request_queue *q) -{ - unsigned long flags; - struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh = NULL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - sdev = NULL; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (!sdev) - return; + if (err) + return err; if (sdev->scsi_dh_data) { - scsi_dh = sdev->scsi_dh_data->scsi_dh; - scsi_dh_handler_detach(sdev, scsi_dh); + if (sdev->scsi_dh_data->scsi_dh != scsi_dh) + err = -EBUSY; + goto out_put_device; } + + err = scsi_dh_handler_attach(sdev, scsi_dh); + +out_put_device: put_device(&sdev->sdev_gendev); + return err; } -EXPORT_SYMBOL_GPL(scsi_dh_detach); +EXPORT_SYMBOL_GPL(scsi_dh_attach); /* * scsi_dh_attached_handler_name - Get attached device handler's name diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 50c2a363bc8fe..798d67994aeb2 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -221,7 +221,6 @@ struct scsi_device_handler { struct scsi_dh_data { struct scsi_device_handler *scsi_dh; struct scsi_device *sdev; - struct kref kref; }; #define to_scsi_device(d) \ diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 620c723ee8ed8..99c9196fe606b 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -59,7 +59,6 @@ enum { extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); extern int scsi_dh_handler_exist(const char *); extern int scsi_dh_attach(struct request_queue *, const char *); -extern void scsi_dh_detach(struct request_queue *); extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); extern int scsi_dh_set_params(struct request_queue *, const char *); #else @@ -77,10 +76,6 @@ static inline int scsi_dh_attach(struct request_queue *req, const char *name) { return SCSI_DH_NOSYS; } -static inline void scsi_dh_detach(struct request_queue *q) -{ - return; -} static inline const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) { -- GitLab From 566079c849cfe538e908c44ac11a9c4638db8f91 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:16:55 +0200 Subject: [PATCH 5633/7006] dm-mpath, scsi_dh: request scsi_dh modules in scsi_dh, not dm-mpath This way we can reused the same code any attachment method, not just those requested from dm-mpath. [jejb: fixup checkpatch error] Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Acked-by: Mike Snitzer Signed-off-by: James Bottomley --- drivers/md/dm-mpath.c | 6 ----- drivers/scsi/device_handler/scsi_dh.c | 36 ++++++++++++++------------- include/scsi/scsi_dh.h | 5 ---- 3 files changed, 19 insertions(+), 28 deletions(-) diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c index a9f58fdb5d69d..5a67671a3973b 100644 --- a/drivers/md/dm-mpath.c +++ b/drivers/md/dm-mpath.c @@ -725,12 +725,6 @@ static int parse_hw_handler(struct dm_arg_set *as, struct multipath *m) return 0; m->hw_handler_name = kstrdup(dm_shift_arg(as), GFP_KERNEL); - if (!try_then_request_module(scsi_dh_handler_exist(m->hw_handler_name), - "scsi_dh_%s", m->hw_handler_name)) { - ti->error = "unknown hardware handler type"; - ret = -EINVAL; - goto fail; - } if (hw_argc > 1) { char *p; diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c index 869b5bd1ad252..3dfef5b0d298f 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/device_handler/scsi_dh.c @@ -29,7 +29,7 @@ static DEFINE_SPINLOCK(list_lock); static LIST_HEAD(scsi_dh_list); -static struct scsi_device_handler *get_device_handler(const char *name) +static struct scsi_device_handler *__scsi_dh_lookup(const char *name) { struct scsi_device_handler *tmp, *found = NULL; @@ -44,6 +44,19 @@ static struct scsi_device_handler *get_device_handler(const char *name) return found; } +static struct scsi_device_handler *scsi_dh_lookup(const char *name) +{ + struct scsi_device_handler *dh; + + dh = __scsi_dh_lookup(name); + if (!dh) { + request_module(name); + dh = __scsi_dh_lookup(name); + } + + return dh; +} + /* * device_handler_match_function - Match a device handler to a device * @sdev - SCSI device to be tested @@ -158,7 +171,8 @@ store_dh_state(struct device *dev, struct device_attribute *attr, /* * Attach to a device handler */ - if (!(scsi_dh = get_device_handler(buf))) + scsi_dh = scsi_dh_lookup(buf); + if (!scsi_dh) return err; err = scsi_dh_handler_attach(sdev, scsi_dh); } else { @@ -322,8 +336,7 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data) */ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) { - - if (get_device_handler(scsi_dh->name)) + if (__scsi_dh_lookup(scsi_dh->name)) return -EBUSY; if (!scsi_dh->attach || !scsi_dh->detach) @@ -350,7 +363,7 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler); int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) { - if (!get_device_handler(scsi_dh->name)) + if (!__scsi_dh_lookup(scsi_dh->name)) return -ENODEV; bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, @@ -454,17 +467,6 @@ int scsi_dh_set_params(struct request_queue *q, const char *params) } EXPORT_SYMBOL_GPL(scsi_dh_set_params); -/* - * scsi_dh_handler_exist - Return TRUE(1) if a device handler exists for - * the given name. FALSE(0) otherwise. - * @name - name of the device handler. - */ -int scsi_dh_handler_exist(const char *name) -{ - return (get_device_handler(name) != NULL); -} -EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); - /* * scsi_dh_attach - Attach device handler * @q - Request queue that is associated with the scsi_device @@ -478,7 +480,7 @@ int scsi_dh_attach(struct request_queue *q, const char *name) struct scsi_device_handler *scsi_dh; int err = 0; - scsi_dh = get_device_handler(name); + scsi_dh = scsi_dh_lookup(name); if (!scsi_dh) return -EINVAL; diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 99c9196fe606b..966b921135b59 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -57,7 +57,6 @@ enum { }; #if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE) extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); -extern int scsi_dh_handler_exist(const char *); extern int scsi_dh_attach(struct request_queue *, const char *); extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); extern int scsi_dh_set_params(struct request_queue *, const char *); @@ -68,10 +67,6 @@ static inline int scsi_dh_activate(struct request_queue *req, fn(data, 0); return 0; } -static inline int scsi_dh_handler_exist(const char *name) -{ - return 0; -} static inline int scsi_dh_attach(struct request_queue *req, const char *name) { return SCSI_DH_NOSYS; -- GitLab From daaa858b7a6bb497f11c2aae555053b9c047824b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:16:56 +0200 Subject: [PATCH 5634/7006] scsi_dh: move to drivers/scsi Prepare for building scsi_dh.c into the core SCSI module by moving it to drivers/scsi. Signed-off-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/{device_handler => }/scsi_dh.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename drivers/scsi/{device_handler => }/scsi_dh.c (99%) diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/scsi_dh.c similarity index 99% rename from drivers/scsi/device_handler/scsi_dh.c rename to drivers/scsi/scsi_dh.c index 3dfef5b0d298f..3de9b6767be4d 100644 --- a/drivers/scsi/device_handler/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -24,7 +24,7 @@ #include #include #include -#include "../scsi_priv.h" +#include "scsi_priv.h" static DEFINE_SPINLOCK(list_lock); static LIST_HEAD(scsi_dh_list); -- GitLab From 086b91d052ebe4ead5d28021afe3bdfd70af15bf Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:16:57 +0200 Subject: [PATCH 5635/7006] scsi_dh: integrate into the core SCSI code Stop building scsi_dh as a separate module and integrate it fully into the core SCSI code with explicit callouts at bus scan time. For now the callouts are placed at the same point as the old bus notifiers were called, but in the future we will be able to look at ALUA INQUIRY data earlier on. Note that this also means that the device handler modules need to be loaded by the time we scan the bus. The next patches will add support for autoloading device handlers at bus scan time to make sure they are always loaded if they are enabled in the kernel config. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Acked-by: Mike Snitzer Signed-off-by: James Bottomley --- drivers/scsi/Makefile | 1 + drivers/scsi/device_handler/Kconfig | 2 +- drivers/scsi/device_handler/Makefile | 1 - drivers/scsi/scsi_dh.c | 183 ++------------------------- drivers/scsi/scsi_priv.h | 9 ++ drivers/scsi/scsi_sysfs.c | 10 ++ include/scsi/scsi_dh.h | 2 +- 7 files changed, 34 insertions(+), 174 deletions(-) diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 471d087917662..1a8c9b53fafad 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -172,6 +172,7 @@ scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o scsi_mod-y += scsi_trace.o scsi_logging.o scsi_mod-$(CONFIG_PM) += scsi_pm.o +scsi_mod-$(CONFIG_SCSI_DH) += scsi_dh.o hv_storvsc-y := storvsc_drv.o diff --git a/drivers/scsi/device_handler/Kconfig b/drivers/scsi/device_handler/Kconfig index 69abd0ad48e2d..e5647d59224fc 100644 --- a/drivers/scsi/device_handler/Kconfig +++ b/drivers/scsi/device_handler/Kconfig @@ -3,7 +3,7 @@ # menuconfig SCSI_DH - tristate "SCSI Device Handlers" + bool "SCSI Device Handlers" depends on SCSI default n help diff --git a/drivers/scsi/device_handler/Makefile b/drivers/scsi/device_handler/Makefile index e1d2ea083e159..09866c50fbb4a 100644 --- a/drivers/scsi/device_handler/Makefile +++ b/drivers/scsi/device_handler/Makefile @@ -1,7 +1,6 @@ # # SCSI Device Handler # -obj-$(CONFIG_SCSI_DH) += scsi_dh.o obj-$(CONFIG_SCSI_DH_RDAC) += scsi_dh_rdac.o obj-$(CONFIG_SCSI_DH_HP_SW) += scsi_dh_hp_sw.o obj-$(CONFIG_SCSI_DH_EMC) += scsi_dh_emc.o diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 3de9b6767be4d..f0dfdccc060e4 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -57,15 +57,8 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name) return dh; } -/* - * device_handler_match_function - Match a device handler to a device - * @sdev - SCSI device to be tested - * - * Tests @sdev against the match function of all registered device_handler. - * Returns the found device handler or NULL if not found. - */ static struct scsi_device_handler * -device_handler_match_function(struct scsi_device *sdev) +device_handler_match(struct scsi_device *sdev) { struct scsi_device_handler *tmp_dh, *found_dh = NULL; @@ -80,29 +73,6 @@ device_handler_match_function(struct scsi_device *sdev) return found_dh; } -/* - * device_handler_match - Attach a device handler to a device - * @scsi_dh - The device handler to match against or NULL - * @sdev - SCSI device to be tested against @scsi_dh - * - * Tests @sdev against the device handler @scsi_dh or against - * all registered device_handler if @scsi_dh == NULL. - * Returns the found device handler or NULL if not found. - */ -static struct scsi_device_handler * -device_handler_match(struct scsi_device_handler *scsi_dh, - struct scsi_device *sdev) -{ - struct scsi_device_handler *found_dh; - - found_dh = device_handler_match_function(sdev); - - if (scsi_dh && found_dh != scsi_dh) - found_dh = NULL; - - return found_dh; -} - /* * scsi_dh_handler_attach - Attach a device handler to a device * @sdev - SCSI device the device handler should attach to @@ -212,119 +182,26 @@ static struct device_attribute scsi_dh_state_attr = __ATTR(dh_state, S_IRUGO | S_IWUSR, show_dh_state, store_dh_state); -/* - * scsi_dh_sysfs_attr_add - Callback for scsi_init_dh - */ -static int scsi_dh_sysfs_attr_add(struct device *dev, void *data) +int scsi_dh_add_device(struct scsi_device *sdev) { - struct scsi_device *sdev; + struct scsi_device_handler *devinfo; int err; - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - err = device_create_file(&sdev->sdev_gendev, - &scsi_dh_state_attr); - - return 0; -} - -/* - * scsi_dh_sysfs_attr_remove - Callback for scsi_exit_dh - */ -static int scsi_dh_sysfs_attr_remove(struct device *dev, void *data) -{ - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - device_remove_file(&sdev->sdev_gendev, - &scsi_dh_state_attr); - - return 0; -} + err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr); + if (err) + return err; -/* - * scsi_dh_notifier - notifier chain callback - */ -static int scsi_dh_notifier(struct notifier_block *nb, - unsigned long action, void *data) -{ - struct device *dev = data; - struct scsi_device *sdev; - int err = 0; - struct scsi_device_handler *devinfo = NULL; - - if (!scsi_is_sdev_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - if (action == BUS_NOTIFY_ADD_DEVICE) { - err = device_create_file(dev, &scsi_dh_state_attr); - /* don't care about err */ - devinfo = device_handler_match(NULL, sdev); - if (devinfo) - err = scsi_dh_handler_attach(sdev, devinfo); - } else if (action == BUS_NOTIFY_DEL_DEVICE) { - device_remove_file(dev, &scsi_dh_state_attr); - if (sdev->scsi_dh_data) - scsi_dh_handler_detach(sdev); - } + devinfo = device_handler_match(sdev); + if (devinfo) + err = scsi_dh_handler_attach(sdev, devinfo); return err; } -/* - * scsi_dh_notifier_add - Callback for scsi_register_device_handler - */ -static int scsi_dh_notifier_add(struct device *dev, void *data) +void scsi_dh_remove_device(struct scsi_device *sdev) { - struct scsi_device_handler *scsi_dh = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - if (!get_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - if (device_handler_match(scsi_dh, sdev)) - scsi_dh_handler_attach(sdev, scsi_dh); - - put_device(dev); - - return 0; -} - -/* - * scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler - */ -static int scsi_dh_notifier_remove(struct device *dev, void *data) -{ - struct scsi_device_handler *scsi_dh = data; - struct scsi_device *sdev; - - if (!scsi_is_sdev_device(dev)) - return 0; - - if (!get_device(dev)) - return 0; - - sdev = to_scsi_device(dev); - - if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh == scsi_dh) + if (sdev->scsi_dh_data) scsi_dh_handler_detach(sdev); - - put_device(dev); - - return 0; + device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr); } /* @@ -346,7 +223,6 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh) list_add(&scsi_dh->list, &scsi_dh_list); spin_unlock(&list_lock); - bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add); printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name); return SCSI_DH_OK; @@ -362,13 +238,9 @@ EXPORT_SYMBOL_GPL(scsi_register_device_handler); */ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) { - if (!__scsi_dh_lookup(scsi_dh->name)) return -ENODEV; - bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, - scsi_dh_notifier_remove); - spin_lock(&list_lock); list_del(&scsi_dh->list); spin_unlock(&list_lock); @@ -538,34 +410,3 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) return handler_name; } EXPORT_SYMBOL_GPL(scsi_dh_attached_handler_name); - -static struct notifier_block scsi_dh_nb = { - .notifier_call = scsi_dh_notifier -}; - -static int __init scsi_dh_init(void) -{ - int r; - - r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb); - - if (!r) - bus_for_each_dev(&scsi_bus_type, NULL, NULL, - scsi_dh_sysfs_attr_add); - - return r; -} - -static void __exit scsi_dh_exit(void) -{ - bus_for_each_dev(&scsi_bus_type, NULL, NULL, - scsi_dh_sysfs_attr_remove); - bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb); -} - -module_init(scsi_dh_init); -module_exit(scsi_dh_exit); - -MODULE_DESCRIPTION("SCSI device handler"); -MODULE_AUTHOR("Chandra Seetharaman "); -MODULE_LICENSE("GPL"); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index e3902fc66278d..644bb7339b55b 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -170,6 +170,15 @@ static inline void scsi_autopm_put_host(struct Scsi_Host *h) {} extern struct async_domain scsi_sd_pm_domain; extern struct async_domain scsi_sd_probe_domain; +/* scsi_dh.c */ +#ifdef CONFIG_SCSI_DH +int scsi_dh_add_device(struct scsi_device *sdev); +void scsi_dh_remove_device(struct scsi_device *sdev); +#else +static inline int scsi_dh_add_device(struct scsi_device *sdev) { return 0; } +static inline void scsi_dh_remove_device(struct scsi_device *sdev) { } +#endif + /* * internal scsi timeout functions: for use by mid-layer and transport * classes. diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 9ad41168d26df..b333389f248ff 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1030,11 +1030,20 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) "failed to add device: %d\n", error); return error; } + + error = scsi_dh_add_device(sdev); + if (error) { + sdev_printk(KERN_INFO, sdev, + "failed to add device handler: %d\n", error); + return error; + } + device_enable_async_suspend(&sdev->sdev_dev); error = device_add(&sdev->sdev_dev); if (error) { sdev_printk(KERN_INFO, sdev, "failed to add class device: %d\n", error); + scsi_dh_remove_device(sdev); device_del(&sdev->sdev_gendev); return error; } @@ -1074,6 +1083,7 @@ void __scsi_remove_device(struct scsi_device *sdev) bsg_unregister_queue(sdev->request_queue); device_unregister(&sdev->sdev_dev); transport_remove_device(dev); + scsi_dh_remove_device(sdev); device_del(dev); } else put_device(&sdev->sdev_dev); diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 966b921135b59..3a37b4c459970 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -55,7 +55,7 @@ enum { SCSI_DH_NOSYS, SCSI_DH_DRIVER_MAX, }; -#if defined(CONFIG_SCSI_DH) || defined(CONFIG_SCSI_DH_MODULE) +#ifdef CONFIG_SCSI_DH extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); extern int scsi_dh_attach(struct request_queue *, const char *); extern const char *scsi_dh_attached_handler_name(struct request_queue *, gfp_t); -- GitLab From d95dbff2a41e934cd8789734b34dc591e78ba11c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:16:58 +0200 Subject: [PATCH 5636/7006] scsi_dh: move device matching to the core code Add a single list of devices that need non-ALUA device handlers to the core scsi_dh code so that we can autoload the modules for them at probe time. While this is a little ugly in terms of architecture it actually significantly simplifies the code in addition to the new autoloading functionality. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Acked-by: Mike Snitzer Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_alua.c | 6 -- drivers/scsi/device_handler/scsi_dh_emc.c | 29 ------- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 30 -------- drivers/scsi/device_handler/scsi_dh_rdac.c | 50 ------------ drivers/scsi/scsi_dh.c | 84 ++++++++++++++++----- include/scsi/scsi_device.h | 1 - 6 files changed, 66 insertions(+), 134 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index 854b568b99315..ace2457747a79 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -819,11 +819,6 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) } -static bool alua_match(struct scsi_device *sdev) -{ - return (scsi_device_tpgs(sdev) != 0); -} - /* * alua_bus_attach - Attach device handler * @sdev: device to be attached to @@ -877,7 +872,6 @@ static struct scsi_device_handler alua_dh = { .check_sense = alua_check_sense, .activate = alua_activate, .set_params = alua_set_params, - .match = alua_match, }; static int __init alua_init(void) diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index 6ed1caadbc6ab..fd31e67e9f509 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -622,34 +622,6 @@ done: return result; } -static const struct { - char *vendor; - char *model; -} clariion_dev_list[] = { - {"DGC", "RAID"}, - {"DGC", "DISK"}, - {"DGC", "VRAID"}, - {NULL, NULL}, -}; - -static bool clariion_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; clariion_dev_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor, - strlen(clariion_dev_list[i].vendor)) && - !strncmp(sdev->model, clariion_dev_list[i].model, - strlen(clariion_dev_list[i].model))) { - return true; - } - } - return false; -} - static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev) { struct clariion_dh_data *h; @@ -698,7 +670,6 @@ static struct scsi_device_handler clariion_dh = { .activate = clariion_activate, .prep_fn = clariion_prep_fn, .set_params = clariion_set_params, - .match = clariion_match, }; static int __init clariion_init(void) diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 485d99544a156..1bf10d37289ad 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -311,35 +311,6 @@ static int hp_sw_activate(struct scsi_device *sdev, return 0; } -static const struct { - char *vendor; - char *model; -} hp_sw_dh_data_list[] = { - {"COMPAQ", "MSA1000 VOLUME"}, - {"COMPAQ", "HSV110"}, - {"HP", "HSV100"}, - {"DEC", "HSG80"}, - {NULL, NULL}, -}; - -static bool hp_sw_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; hp_sw_dh_data_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor, - strlen(hp_sw_dh_data_list[i].vendor)) && - !strncmp(sdev->model, hp_sw_dh_data_list[i].model, - strlen(hp_sw_dh_data_list[i].model))) { - return true; - } - } - return false; -} - static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev) { struct hp_sw_dh_data *h; @@ -379,7 +350,6 @@ static struct scsi_device_handler hp_sw_dh = { .detach = hp_sw_bus_detach, .activate = hp_sw_activate, .prep_fn = hp_sw_prep_fn, - .match = hp_sw_match, }; static int __init hp_sw_init(void) diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index b46ace3d4bf0c..d89616fe3ffac 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -778,55 +778,6 @@ static int rdac_check_sense(struct scsi_device *sdev, return SCSI_RETURN_NOT_HANDLED; } -static const struct { - char *vendor; - char *model; -} rdac_dev_list[] = { - {"IBM", "1722"}, - {"IBM", "1724"}, - {"IBM", "1726"}, - {"IBM", "1742"}, - {"IBM", "1745"}, - {"IBM", "1746"}, - {"IBM", "1813"}, - {"IBM", "1814"}, - {"IBM", "1815"}, - {"IBM", "1818"}, - {"IBM", "3526"}, - {"SGI", "TP9"}, - {"SGI", "IS"}, - {"STK", "OPENstorage D280"}, - {"STK", "FLEXLINE 380"}, - {"SUN", "CSM"}, - {"SUN", "LCSM100"}, - {"SUN", "STK6580_6780"}, - {"SUN", "SUN_6180"}, - {"SUN", "ArrayStorage"}, - {"DELL", "MD3"}, - {"NETAPP", "INF-01-00"}, - {"LSI", "INF-01-00"}, - {"ENGENIO", "INF-01-00"}, - {NULL, NULL}, -}; - -static bool rdac_match(struct scsi_device *sdev) -{ - int i; - - if (scsi_device_tpgs(sdev)) - return false; - - for (i = 0; rdac_dev_list[i].vendor; i++) { - if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor, - strlen(rdac_dev_list[i].vendor)) && - !strncmp(sdev->model, rdac_dev_list[i].model, - strlen(rdac_dev_list[i].model))) { - return true; - } - } - return false; -} - static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev) { struct rdac_dh_data *h; @@ -895,7 +846,6 @@ static struct scsi_device_handler rdac_dh = { .attach = rdac_bus_attach, .detach = rdac_bus_detach, .activate = rdac_activate, - .match = rdac_match, }; static int __init rdac_init(void) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index f0dfdccc060e4..9c153309c96b9 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -29,6 +29,67 @@ static DEFINE_SPINLOCK(list_lock); static LIST_HEAD(scsi_dh_list); +struct scsi_dh_blist { + const char *vendor; + const char *model; + const char *driver; +}; + +static const struct scsi_dh_blist scsi_dh_blist[] = { + {"DGC", "RAID", "clariion" }, + {"DGC", "DISK", "clariion" }, + {"DGC", "VRAID", "clariion" }, + + {"COMPAQ", "MSA1000 VOLUME", "hp_sw" }, + {"COMPAQ", "HSV110", "hp_sw" }, + {"HP", "HSV100", "hp_sw"}, + {"DEC", "HSG80", "hp_sw"}, + + {"IBM", "1722", "rdac", }, + {"IBM", "1724", "rdac", }, + {"IBM", "1726", "rdac", }, + {"IBM", "1742", "rdac", }, + {"IBM", "1745", "rdac", }, + {"IBM", "1746", "rdac", }, + {"IBM", "1813", "rdac", }, + {"IBM", "1814", "rdac", }, + {"IBM", "1815", "rdac", }, + {"IBM", "1818", "rdac", }, + {"IBM", "3526", "rdac", }, + {"SGI", "TP9", "rdac", }, + {"SGI", "IS", "rdac", }, + {"STK", "OPENstorage D280", "rdac", }, + {"STK", "FLEXLINE 380", "rdac", }, + {"SUN", "CSM", "rdac", }, + {"SUN", "LCSM100", "rdac", }, + {"SUN", "STK6580_6780", "rdac", }, + {"SUN", "SUN_6180", "rdac", }, + {"SUN", "ArrayStorage", "rdac", }, + {"DELL", "MD3", "rdac", }, + {"NETAPP", "INF-01-00", "rdac", }, + {"LSI", "INF-01-00", "rdac", }, + {"ENGENIO", "INF-01-00", "rdac", }, + {NULL, NULL, NULL }, +}; + +static const char * +scsi_dh_find_driver(struct scsi_device *sdev) +{ + const struct scsi_dh_blist *b; + + if (scsi_device_tpgs(sdev)) + return "alua"; + + for (b = scsi_dh_blist; b->vendor; b++) { + if (!strncmp(sdev->vendor, b->vendor, strlen(b->vendor)) && + !strncmp(sdev->model, b->model, strlen(b->model))) { + return b->driver; + } + } + return NULL; +} + + static struct scsi_device_handler *__scsi_dh_lookup(const char *name) { struct scsi_device_handler *tmp, *found = NULL; @@ -57,22 +118,6 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name) return dh; } -static struct scsi_device_handler * -device_handler_match(struct scsi_device *sdev) -{ - struct scsi_device_handler *tmp_dh, *found_dh = NULL; - - spin_lock(&list_lock); - list_for_each_entry(tmp_dh, &scsi_dh_list, list) { - if (tmp_dh->match && tmp_dh->match(sdev)) { - found_dh = tmp_dh; - break; - } - } - spin_unlock(&list_lock); - return found_dh; -} - /* * scsi_dh_handler_attach - Attach a device handler to a device * @sdev - SCSI device the device handler should attach to @@ -184,14 +229,17 @@ static struct device_attribute scsi_dh_state_attr = int scsi_dh_add_device(struct scsi_device *sdev) { - struct scsi_device_handler *devinfo; + struct scsi_device_handler *devinfo = NULL; + const char *drv; int err; err = device_create_file(&sdev->sdev_gendev, &scsi_dh_state_attr); if (err) return err; - devinfo = device_handler_match(sdev); + drv = scsi_dh_find_driver(sdev); + if (drv) + devinfo = scsi_dh_lookup(drv); if (devinfo) err = scsi_dh_handler_attach(sdev, devinfo); return err; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 798d67994aeb2..4d501b7baa9bf 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -215,7 +215,6 @@ struct scsi_device_handler { int (*activate)(struct scsi_device *, activate_complete, void *); int (*prep_fn)(struct scsi_device *, struct request *); int (*set_params)(struct scsi_device *, const char *); - bool (*match)(struct scsi_device *); }; struct scsi_dh_data { -- GitLab From ee14c674e8fc57251223054fb52dc0ecfe711028 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:16:59 +0200 Subject: [PATCH 5637/7006] scsi_dh: kill struct scsi_dh_data Add a ->handler and a ->handler_data field to struct scsi_device and kill this indirection. Also move struct scsi_device_handler to scsi_dh.h so that changes to it don't require rebuilding every SCSI LLDD. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/device_handler/scsi_dh_alua.c | 25 +++---- drivers/scsi/device_handler/scsi_dh_emc.c | 29 +++----- drivers/scsi/device_handler/scsi_dh_hp_sw.c | 25 +++---- drivers/scsi/device_handler/scsi_dh_rdac.c | 30 ++++----- drivers/scsi/scsi_dh.c | 75 ++++++++------------- drivers/scsi/scsi_error.c | 6 +- drivers/scsi/scsi_lib.c | 6 +- include/scsi/scsi_device.h | 25 +------ include/scsi/scsi_dh.h | 17 +++++ 9 files changed, 98 insertions(+), 140 deletions(-) diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c index ace2457747a79..cc2773b5de68f 100644 --- a/drivers/scsi/device_handler/scsi_dh_alua.c +++ b/drivers/scsi/device_handler/scsi_dh_alua.c @@ -62,7 +62,6 @@ #define ALUA_OPTIMIZE_STPG 1 struct alua_dh_data { - struct scsi_dh_data dh_data; int group_id; int rel_port; int tpgs; @@ -86,11 +85,6 @@ struct alua_dh_data { static char print_alua_state(int); static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *); -static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev) -{ - return container_of(sdev->scsi_dh_data, struct alua_dh_data, dh_data); -} - static int realloc_buffer(struct alua_dh_data *h, unsigned len) { if (h->buff && h->buff != h->inq) @@ -708,7 +702,7 @@ out: */ static int alua_set_params(struct scsi_device *sdev, const char *params) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; unsigned int optimize = 0, argc; const char *p = params; int result = SCSI_DH_OK; @@ -746,7 +740,7 @@ MODULE_PARM_DESC(optimize_stpg, "Allow use of a non-optimized path, rather than static int alua_activate(struct scsi_device *sdev, activate_complete fn, void *data) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; int err = SCSI_DH_OK; int stpg = 0; @@ -804,7 +798,7 @@ out: */ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; int ret = BLKPREP_OK; if (h->state == TPGS_STATE_TRANSITIONING) @@ -823,14 +817,14 @@ static int alua_prep_fn(struct scsi_device *sdev, struct request *req) * alua_bus_attach - Attach device handler * @sdev: device to be attached to */ -static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev) +static int alua_bus_attach(struct scsi_device *sdev) { struct alua_dh_data *h; int err; h = kzalloc(sizeof(*h) , GFP_KERNEL); if (!h) - return ERR_PTR(-ENOMEM); + return -ENOMEM; h->tpgs = TPGS_MODE_UNINITIALIZED; h->state = TPGS_STATE_OPTIMIZED; h->group_id = -1; @@ -843,11 +837,11 @@ static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev) if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED) goto failed; - sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME); - return &h->dh_data; + sdev->handler_data = h; + return 0; failed: kfree(h); - return ERR_PTR(-EINVAL); + return -EINVAL; } /* @@ -856,10 +850,11 @@ failed: */ static void alua_bus_detach(struct scsi_device *sdev) { - struct alua_dh_data *h = get_alua_data(sdev); + struct alua_dh_data *h = sdev->handler_data; if (h->buff && h->inq != h->buff) kfree(h->buff); + sdev->handler_data = NULL; kfree(h); } diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c index fd31e67e9f509..e6fb97cb12f43 100644 --- a/drivers/scsi/device_handler/scsi_dh_emc.c +++ b/drivers/scsi/device_handler/scsi_dh_emc.c @@ -72,7 +72,6 @@ static const char * lun_state[] = }; struct clariion_dh_data { - struct scsi_dh_data dh_data; /* * Flags: * CLARIION_SHORT_TRESPASS @@ -114,13 +113,6 @@ struct clariion_dh_data { int current_sp; }; -static inline struct clariion_dh_data - *get_clariion_data(struct scsi_device *sdev) -{ - return container_of(sdev->scsi_dh_data, struct clariion_dh_data, - dh_data); -} - /* * Parse MODE_SELECT cmd reply. */ @@ -450,7 +442,7 @@ static int clariion_check_sense(struct scsi_device *sdev, static int clariion_prep_fn(struct scsi_device *sdev, struct request *req) { - struct clariion_dh_data *h = get_clariion_data(sdev); + struct clariion_dh_data *h = sdev->handler_data; int ret = BLKPREP_OK; if (h->lun_state != CLARIION_LUN_OWNED) { @@ -533,7 +525,7 @@ retry: static int clariion_activate(struct scsi_device *sdev, activate_complete fn, void *data) { - struct clariion_dh_data *csdev = get_clariion_data(sdev); + struct clariion_dh_data *csdev = sdev->handler_data; int result; result = clariion_send_inquiry(sdev, csdev); @@ -574,7 +566,7 @@ done: */ static int clariion_set_params(struct scsi_device *sdev, const char *params) { - struct clariion_dh_data *csdev = get_clariion_data(sdev); + struct clariion_dh_data *csdev = sdev->handler_data; unsigned int hr = 0, st = 0, argc; const char *p = params; int result = SCSI_DH_OK; @@ -622,14 +614,14 @@ done: return result; } -static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev) +static int clariion_bus_attach(struct scsi_device *sdev) { struct clariion_dh_data *h; int err; h = kzalloc(sizeof(*h) , GFP_KERNEL); if (!h) - return ERR_PTR(-ENOMEM); + return -ENOMEM; h->lun_state = CLARIION_LUN_UNINITIALIZED; h->default_sp = CLARIION_UNBOUND_LU; h->current_sp = CLARIION_UNBOUND_LU; @@ -647,18 +639,19 @@ static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev) CLARIION_NAME, h->current_sp + 'A', h->port, lun_state[h->lun_state], h->default_sp + 'A'); - return &h->dh_data; + + sdev->handler_data = h; + return 0; failed: kfree(h); - return ERR_PTR(-EINVAL); + return -EINVAL; } static void clariion_bus_detach(struct scsi_device *sdev) { - struct clariion_dh_data *h = get_clariion_data(sdev); - - kfree(h); + kfree(sdev->handler_data); + sdev->handler_data = NULL; } static struct scsi_device_handler clariion_dh = { diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c index 1bf10d37289ad..9406d5f4a3d38 100644 --- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c +++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c @@ -38,7 +38,6 @@ #define HP_SW_PATH_PASSIVE 1 struct hp_sw_dh_data { - struct scsi_dh_data dh_data; unsigned char sense[SCSI_SENSE_BUFFERSIZE]; int path_state; int retries; @@ -50,11 +49,6 @@ struct hp_sw_dh_data { static int hp_sw_start_stop(struct hp_sw_dh_data *); -static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev) -{ - return container_of(sdev->scsi_dh_data, struct hp_sw_dh_data, dh_data); -} - /* * tur_done - Handle TEST UNIT READY return status * @sdev: sdev the command has been sent to @@ -267,7 +261,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *h) static int hp_sw_prep_fn(struct scsi_device *sdev, struct request *req) { - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); + struct hp_sw_dh_data *h = sdev->handler_data; int ret = BLKPREP_OK; if (h->path_state != HP_SW_PATH_ACTIVE) { @@ -292,7 +286,7 @@ static int hp_sw_activate(struct scsi_device *sdev, activate_complete fn, void *data) { int ret = SCSI_DH_OK; - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); + struct hp_sw_dh_data *h = sdev->handler_data; ret = hp_sw_tur(sdev, h); @@ -311,14 +305,14 @@ static int hp_sw_activate(struct scsi_device *sdev, return 0; } -static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev) +static int hp_sw_bus_attach(struct scsi_device *sdev) { struct hp_sw_dh_data *h; int ret; h = kzalloc(sizeof(*h), GFP_KERNEL); if (!h) - return ERR_PTR(-ENOMEM); + return -ENOMEM; h->path_state = HP_SW_PATH_UNINITIALIZED; h->retries = HP_SW_RETRIES; h->sdev = sdev; @@ -330,17 +324,18 @@ static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev) sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n", HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE? "active":"passive"); - return &h->dh_data; + + sdev->handler_data = h; + return 0; failed: kfree(h); - return ERR_PTR(-EINVAL); + return -EINVAL; } static void hp_sw_bus_detach( struct scsi_device *sdev ) { - struct hp_sw_dh_data *h = get_hp_sw_data(sdev); - - kfree(h); + kfree(sdev->handler_data); + sdev->handler_data = NULL; } static struct scsi_device_handler hp_sw_dh = { diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c index d89616fe3ffac..3613581343159 100644 --- a/drivers/scsi/device_handler/scsi_dh_rdac.c +++ b/drivers/scsi/device_handler/scsi_dh_rdac.c @@ -181,7 +181,6 @@ struct c2_inquiry { }; struct rdac_dh_data { - struct scsi_dh_data dh_data; struct rdac_controller *ctlr; #define UNINITIALIZED_LUN (1 << 8) unsigned lun; @@ -260,11 +259,6 @@ do { \ sdev_printk(KERN_INFO, sdev, RDAC_NAME ": " f "\n", ## arg); \ } while (0); -static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev) -{ - return container_of(sdev->scsi_dh_data, struct rdac_dh_data, dh_data); -} - static struct request *get_rdac_req(struct scsi_device *sdev, void *buffer, unsigned buflen, int rw) { @@ -544,7 +538,7 @@ static int mode_select_handle_sense(struct scsi_device *sdev, { struct scsi_sense_hdr sense_hdr; int err = SCSI_DH_IO, ret; - struct rdac_dh_data *h = get_rdac_data(sdev); + struct rdac_dh_data *h = sdev->handler_data; ret = scsi_normalize_sense(sensebuf, SCSI_SENSE_BUFFERSIZE, &sense_hdr); if (!ret) @@ -589,7 +583,7 @@ static void send_mode_select(struct work_struct *work) container_of(work, struct rdac_controller, ms_work); struct request *rq; struct scsi_device *sdev = ctlr->ms_sdev; - struct rdac_dh_data *h = get_rdac_data(sdev); + struct rdac_dh_data *h = sdev->handler_data; struct request_queue *q = sdev->request_queue; int err, retry_cnt = RDAC_RETRY_COUNT; struct rdac_queue_data *tmp, *qdata; @@ -648,7 +642,7 @@ static int queue_mode_select(struct scsi_device *sdev, if (!qdata) return SCSI_DH_RETRY; - qdata->h = get_rdac_data(sdev); + qdata->h = sdev->handler_data; qdata->callback_fn = fn; qdata->callback_data = data; @@ -667,7 +661,7 @@ static int queue_mode_select(struct scsi_device *sdev, static int rdac_activate(struct scsi_device *sdev, activate_complete fn, void *data) { - struct rdac_dh_data *h = get_rdac_data(sdev); + struct rdac_dh_data *h = sdev->handler_data; int err = SCSI_DH_OK; int act = 0; @@ -702,7 +696,7 @@ done: static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) { - struct rdac_dh_data *h = get_rdac_data(sdev); + struct rdac_dh_data *h = sdev->handler_data; int ret = BLKPREP_OK; if (h->state != RDAC_STATE_ACTIVE) { @@ -716,7 +710,7 @@ static int rdac_prep_fn(struct scsi_device *sdev, struct request *req) static int rdac_check_sense(struct scsi_device *sdev, struct scsi_sense_hdr *sense_hdr) { - struct rdac_dh_data *h = get_rdac_data(sdev); + struct rdac_dh_data *h = sdev->handler_data; RDAC_LOG(RDAC_LOG_SENSE, sdev, "array %s, ctlr %d, " "I/O returned with sense %02x/%02x/%02x", @@ -778,7 +772,7 @@ static int rdac_check_sense(struct scsi_device *sdev, return SCSI_RETURN_NOT_HANDLED; } -static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev) +static int rdac_bus_attach(struct scsi_device *sdev) { struct rdac_dh_data *h; int err; @@ -787,7 +781,7 @@ static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev) h = kzalloc(sizeof(*h) , GFP_KERNEL); if (!h) - return ERR_PTR(-ENOMEM); + return -ENOMEM; h->lun = UNINITIALIZED_LUN; h->state = RDAC_STATE_ACTIVE; @@ -812,7 +806,8 @@ static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev) RDAC_NAME, h->lun, mode[(int)h->mode], lun_state[(int)h->lun_state]); - return &h->dh_data; + sdev->handler_data = h; + return 0; clean_ctlr: spin_lock(&list_lock); @@ -821,12 +816,12 @@ clean_ctlr: failed: kfree(h); - return ERR_PTR(-EINVAL); + return -EINVAL; } static void rdac_bus_detach( struct scsi_device *sdev ) { - struct rdac_dh_data *h = get_rdac_data(sdev); + struct rdac_dh_data *h = sdev->handler_data; if (h->ctlr && h->ctlr->ms_queued) flush_workqueue(kmpath_rdacd); @@ -835,6 +830,7 @@ static void rdac_bus_detach( struct scsi_device *sdev ) if (h->ctlr) kref_put(&h->ctlr->kref, release_controller); spin_unlock(&list_lock); + sdev->handler_data = NULL; kfree(h); } diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 9c153309c96b9..33c1148ff3b54 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -126,26 +126,20 @@ static struct scsi_device_handler *scsi_dh_lookup(const char *name) static int scsi_dh_handler_attach(struct scsi_device *sdev, struct scsi_device_handler *scsi_dh) { - struct scsi_dh_data *d; + int error; if (!try_module_get(scsi_dh->module)) return -EINVAL; - d = scsi_dh->attach(sdev); - if (IS_ERR(d)) { - sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n", - scsi_dh->name, PTR_ERR(d)); + error = scsi_dh->attach(sdev); + if (error) { + sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%d)\n", + scsi_dh->name, error); module_put(scsi_dh->module); - return PTR_ERR(d); - } - - d->scsi_dh = scsi_dh; - d->sdev = sdev; + } else + sdev->handler = scsi_dh; - spin_lock_irq(sdev->request_queue->queue_lock); - sdev->scsi_dh_data = d; - spin_unlock_irq(sdev->request_queue->queue_lock); - return 0; + return error; } /* @@ -154,17 +148,9 @@ static int scsi_dh_handler_attach(struct scsi_device *sdev, */ static void scsi_dh_handler_detach(struct scsi_device *sdev) { - struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data; - struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh; - - scsi_dh->detach(sdev); - - spin_lock_irq(sdev->request_queue->queue_lock); - sdev->scsi_dh_data = NULL; - spin_unlock_irq(sdev->request_queue->queue_lock); - - sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name); - module_put(scsi_dh->module); + sdev->handler->detach(sdev); + sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", sdev->handler->name); + module_put(sdev->handler->module); } /* @@ -182,7 +168,7 @@ store_dh_state(struct device *dev, struct device_attribute *attr, sdev->sdev_state == SDEV_DEL) return -ENODEV; - if (!sdev->scsi_dh_data) { + if (!sdev->handler) { /* * Attach to a device handler */ @@ -191,7 +177,6 @@ store_dh_state(struct device *dev, struct device_attribute *attr, return err; err = scsi_dh_handler_attach(sdev, scsi_dh); } else { - scsi_dh = sdev->scsi_dh_data->scsi_dh; if (!strncmp(buf, "detach", 6)) { /* * Detach from a device handler @@ -202,8 +187,8 @@ store_dh_state(struct device *dev, struct device_attribute *attr, /* * Activate a device handler */ - if (scsi_dh->activate) - err = scsi_dh->activate(sdev, NULL, NULL); + if (sdev->handler->activate) + err = sdev->handler->activate(sdev, NULL, NULL); else err = 0; } @@ -217,10 +202,10 @@ show_dh_state(struct device *dev, struct device_attribute *attr, char *buf) { struct scsi_device *sdev = to_scsi_device(dev); - if (!sdev->scsi_dh_data) + if (!sdev->handler) return snprintf(buf, 20, "detached\n"); - return snprintf(buf, 20, "%s\n", sdev->scsi_dh_data->scsi_dh->name); + return snprintf(buf, 20, "%s\n", sdev->handler->name); } static struct device_attribute scsi_dh_state_attr = @@ -247,7 +232,7 @@ int scsi_dh_add_device(struct scsi_device *sdev) void scsi_dh_remove_device(struct scsi_device *sdev) { - if (sdev->scsi_dh_data) + if (sdev->handler) scsi_dh_handler_detach(sdev); device_remove_file(&sdev->sdev_gendev, &scsi_dh_state_attr); } @@ -316,7 +301,6 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) int err = 0; unsigned long flags; struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh = NULL; struct device *dev = NULL; spin_lock_irqsave(q->queue_lock, flags); @@ -329,10 +313,8 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) return err; } - if (sdev->scsi_dh_data) - scsi_dh = sdev->scsi_dh_data->scsi_dh; dev = get_device(&sdev->sdev_gendev); - if (!scsi_dh || !dev || + if (!sdev->handler || !dev || sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) err = SCSI_DH_NOSYS; @@ -346,8 +328,8 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) goto out; } - if (scsi_dh->activate) - err = scsi_dh->activate(sdev, fn, data); + if (sdev->handler->activate) + err = sdev->handler->activate(sdev, fn, data); out: put_device(dev); return err; @@ -369,19 +351,18 @@ int scsi_dh_set_params(struct request_queue *q, const char *params) int err = -SCSI_DH_NOSYS; unsigned long flags; struct scsi_device *sdev; - struct scsi_device_handler *scsi_dh = NULL; spin_lock_irqsave(q->queue_lock, flags); sdev = q->queuedata; - if (sdev && sdev->scsi_dh_data) - scsi_dh = sdev->scsi_dh_data->scsi_dh; - if (scsi_dh && scsi_dh->set_params && get_device(&sdev->sdev_gendev)) + if (sdev->handler && + sdev->handler->set_params && + get_device(&sdev->sdev_gendev)) err = 0; spin_unlock_irqrestore(q->queue_lock, flags); if (err) return err; - err = scsi_dh->set_params(sdev, params); + err = sdev->handler->set_params(sdev, params); put_device(&sdev->sdev_gendev); return err; } @@ -413,8 +394,8 @@ int scsi_dh_attach(struct request_queue *q, const char *name) if (err) return err; - if (sdev->scsi_dh_data) { - if (sdev->scsi_dh_data->scsi_dh != scsi_dh) + if (sdev->handler) { + if (sdev->handler != scsi_dh) err = -EBUSY; goto out_put_device; } @@ -451,8 +432,8 @@ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) if (!sdev) return NULL; - if (sdev->scsi_dh_data) - handler_name = kstrdup(sdev->scsi_dh_data->scsi_dh->name, gfp); + if (sdev->handler) + handler_name = kstrdup(sdev->handler->name, gfp); put_device(&sdev->sdev_gendev); return handler_name; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 3aacd96d63f3f..410911c31c67f 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include "scsi_priv.h" @@ -464,11 +465,10 @@ static int scsi_check_sense(struct scsi_cmnd *scmd) if (scsi_sense_is_deferred(&sshdr)) return NEEDS_RETRY; - if (sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh && - sdev->scsi_dh_data->scsi_dh->check_sense) { + if (sdev->handler && sdev->handler->check_sense) { int rc; - rc = sdev->scsi_dh_data->scsi_dh->check_sense(sdev, &sshdr); + rc = sdev->handler->check_sense(sdev, &sshdr); if (rc != SCSI_RETURN_NOT_HANDLED) return rc; /* handler does not care. Drop down to default handling */ diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 882864f5cbae8..cbfc5990052b6 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -1248,9 +1249,8 @@ static int scsi_setup_fs_cmnd(struct scsi_device *sdev, struct request *req) { struct scsi_cmnd *cmd = req->special; - if (unlikely(sdev->scsi_dh_data && sdev->scsi_dh_data->scsi_dh - && sdev->scsi_dh_data->scsi_dh->prep_fn)) { - int ret = sdev->scsi_dh_data->scsi_dh->prep_fn(sdev, req); + if (unlikely(sdev->handler && sdev->handler->prep_fn)) { + int ret = sdev->handler->prep_fn(sdev, req); if (ret != BLKPREP_OK) return ret; } diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 4d501b7baa9bf..fe89d7cd67b9d 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -196,32 +196,13 @@ struct scsi_device { struct execute_work ew; /* used to get process context on put */ struct work_struct requeue_work; - struct scsi_dh_data *scsi_dh_data; + struct scsi_device_handler *handler; + void *handler_data; + enum scsi_device_state sdev_state; unsigned long sdev_data[0]; } __attribute__((aligned(sizeof(unsigned long)))); -typedef void (*activate_complete)(void *, int); -struct scsi_device_handler { - /* Used by the infrastructure */ - struct list_head list; /* list of scsi_device_handlers */ - - /* Filled by the hardware handler */ - struct module *module; - const char *name; - int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); - struct scsi_dh_data *(*attach)(struct scsi_device *); - void (*detach)(struct scsi_device *); - int (*activate)(struct scsi_device *, activate_complete, void *); - int (*prep_fn)(struct scsi_device *, struct request *); - int (*set_params)(struct scsi_device *, const char *); -}; - -struct scsi_dh_data { - struct scsi_device_handler *scsi_dh; - struct scsi_device *sdev; -}; - #define to_scsi_device(d) \ container_of(d, struct scsi_device, sdev_gendev) #define class_to_sdev(d) \ diff --git a/include/scsi/scsi_dh.h b/include/scsi/scsi_dh.h index 3a37b4c459970..85d731746834d 100644 --- a/include/scsi/scsi_dh.h +++ b/include/scsi/scsi_dh.h @@ -55,6 +55,23 @@ enum { SCSI_DH_NOSYS, SCSI_DH_DRIVER_MAX, }; + +typedef void (*activate_complete)(void *, int); +struct scsi_device_handler { + /* Used by the infrastructure */ + struct list_head list; /* list of scsi_device_handlers */ + + /* Filled by the hardware handler */ + struct module *module; + const char *name; + int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *); + int (*attach)(struct scsi_device *); + void (*detach)(struct scsi_device *); + int (*activate)(struct scsi_device *, activate_complete, void *); + int (*prep_fn)(struct scsi_device *, struct request *); + int (*set_params)(struct scsi_device *, const char *); +}; + #ifdef CONFIG_SCSI_DH extern int scsi_dh_activate(struct request_queue *, activate_complete, void *); extern int scsi_dh_attach(struct request_queue *, const char *); -- GitLab From e959ed9a44c5239863ca6db42cb37130bee3c7a3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:17:00 +0200 Subject: [PATCH 5638/7006] scsi_dh: add a common helper to get a scsi_device from a request_queue And cleanup the various messy opencoded versions of this. Note that this moves the sdev_state checks outside the queue_lock coverage, but as we don't hold the lock over the activation they are only advisory anyway. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_dh.c | 99 ++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 53 deletions(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 33c1148ff3b54..2e1db5738ae1a 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -283,6 +283,20 @@ int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh) } EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); +static struct scsi_device *get_sdev_from_queue(struct request_queue *q) +{ + struct scsi_device *sdev; + unsigned long flags; + + spin_lock_irqsave(q->queue_lock, flags); + sdev = q->queuedata; + if (!sdev || !get_device(&sdev->sdev_gendev)) + sdev = NULL; + spin_unlock_irqrestore(q->queue_lock, flags); + + return sdev; +} + /* * scsi_dh_activate - activate the path associated with the scsi_device * corresponding to the given request queue. @@ -298,41 +312,37 @@ EXPORT_SYMBOL_GPL(scsi_unregister_device_handler); */ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) { - int err = 0; - unsigned long flags; struct scsi_device *sdev; - struct device *dev = NULL; + int err = SCSI_DH_NOSYS; - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; + sdev = get_sdev_from_queue(q); if (!sdev) { - spin_unlock_irqrestore(q->queue_lock, flags); - err = SCSI_DH_NOSYS; if (fn) fn(data, err); return err; } - dev = get_device(&sdev->sdev_gendev); - if (!sdev->handler || !dev || - sdev->sdev_state == SDEV_CANCEL || + if (!sdev->handler) + goto out_fn; + if (sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) - err = SCSI_DH_NOSYS; - if (sdev->sdev_state == SDEV_OFFLINE) - err = SCSI_DH_DEV_OFFLINED; - spin_unlock_irqrestore(q->queue_lock, flags); + goto out_fn; - if (err) { - if (fn) - fn(data, err); - goto out; - } + err = SCSI_DH_DEV_OFFLINED; + if (sdev->sdev_state == SDEV_OFFLINE) + goto out_fn; if (sdev->handler->activate) err = sdev->handler->activate(sdev, fn, data); -out: - put_device(dev); + +out_put_device: + put_device(&sdev->sdev_gendev); return err; + +out_fn: + if (fn) + fn(data, err); + goto out_put_device; } EXPORT_SYMBOL_GPL(scsi_dh_activate); @@ -348,21 +358,15 @@ EXPORT_SYMBOL_GPL(scsi_dh_activate); */ int scsi_dh_set_params(struct request_queue *q, const char *params) { - int err = -SCSI_DH_NOSYS; - unsigned long flags; struct scsi_device *sdev; + int err = -SCSI_DH_NOSYS; - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (sdev->handler && - sdev->handler->set_params && - get_device(&sdev->sdev_gendev)) - err = 0; - spin_unlock_irqrestore(q->queue_lock, flags); - - if (err) + sdev = get_sdev_from_queue(q); + if (!sdev) return err; - err = sdev->handler->set_params(sdev, params); + + if (sdev->handler && sdev->handler->set_params) + err = sdev->handler->set_params(sdev, params); put_device(&sdev->sdev_gendev); return err; } @@ -376,23 +380,19 @@ EXPORT_SYMBOL_GPL(scsi_dh_set_params); */ int scsi_dh_attach(struct request_queue *q, const char *name) { - unsigned long flags; struct scsi_device *sdev; struct scsi_device_handler *scsi_dh; int err = 0; - scsi_dh = scsi_dh_lookup(name); - if (!scsi_dh) - return -EINVAL; - - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - err = -ENODEV; - spin_unlock_irqrestore(q->queue_lock, flags); + sdev = get_sdev_from_queue(q); + if (!sdev) + return -ENODEV; - if (err) - return err; + scsi_dh = scsi_dh_lookup(name); + if (!scsi_dh) { + err = -EINVAL; + goto out_put_device; + } if (sdev->handler) { if (sdev->handler != scsi_dh) @@ -419,22 +419,15 @@ EXPORT_SYMBOL_GPL(scsi_dh_attach); */ const char *scsi_dh_attached_handler_name(struct request_queue *q, gfp_t gfp) { - unsigned long flags; struct scsi_device *sdev; const char *handler_name = NULL; - spin_lock_irqsave(q->queue_lock, flags); - sdev = q->queuedata; - if (!sdev || !get_device(&sdev->sdev_gendev)) - sdev = NULL; - spin_unlock_irqrestore(q->queue_lock, flags); - + sdev = get_sdev_from_queue(q); if (!sdev) return NULL; if (sdev->handler) handler_name = kstrdup(sdev->handler->name, gfp); - put_device(&sdev->sdev_gendev); return handler_name; } -- GitLab From d44227749500d8b88a1c079bc04f69187eaf8747 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 27 Aug 2015 14:17:01 +0200 Subject: [PATCH 5639/7006] scsi_dh: don't allow to detach device handlers at runtime The I/O submission and completion paths call into the device handler without any synchronization agains detachment. So disallow detaching device handlers at runtime. Signed-off-by: Christoph Hellwig Reviewed-by: Martin K. Petersen Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_dh.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 2e1db5738ae1a..9f6511da50239 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -181,8 +181,10 @@ store_dh_state(struct device *dev, struct device_attribute *attr, /* * Detach from a device handler */ - scsi_dh_handler_detach(sdev); - err = 0; + sdev_printk(KERN_WARNING, sdev, + "can't detach handler %s.\n", + sdev->handler->name); + err = -EINVAL; } else if (!strncmp(buf, "activate", 8)) { /* * Activate a device handler -- GitLab From 710105fda7a7f350c9fb22e7f61f74c3dc0fe514 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 27 Aug 2015 14:17:02 +0200 Subject: [PATCH 5640/7006] scsi_dh: return SCSI_DH_NOTCONN in scsi_dh_activate() When calling scsi_dh_activate() we should be returning SCSI_DH_NOTCONN if the device handler couldn't be attached. Reviewed-by: Bart van Assche Reviewed-by: Christoph Hellwig Signed-off-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_dh.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_dh.c b/drivers/scsi/scsi_dh.c index 9f6511da50239..edb044a7b56d3 100644 --- a/drivers/scsi/scsi_dh.c +++ b/drivers/scsi/scsi_dh.c @@ -326,6 +326,7 @@ int scsi_dh_activate(struct request_queue *q, activate_complete fn, void *data) if (!sdev->handler) goto out_fn; + err = SCSI_DH_NOTCONN; if (sdev->sdev_state == SDEV_CANCEL || sdev->sdev_state == SDEV_DEL) goto out_fn; -- GitLab From d7d2d89d4b0afa8f4c2b169475a0c6e43553c146 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 27 Aug 2015 17:11:48 +0200 Subject: [PATCH 5641/7006] r8169: Add software counter for multicast packages The multicast hardware counter on 8168/8111 chips is only 32 bit while the statistics in struct rtnl_link_stats64 are 64 bit. Given that statistics are requested on an irregular basis, an overflow of the hardware counter can go unnoticed. To count even very large numbers of multicast packets reliably, add a software counter and remove previously applied code to fill the multicast field requested by @rtl8169_get_stats64 with the values read from the rx_multicast hardware counter. Signed-off-by: Corinna Vinschen Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index d6d39df5b3dc9..24dcbe62412a1 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -754,7 +754,6 @@ struct rtl8169_tc_offsets { bool inited; __le64 tx_errors; __le32 tx_multi_collision; - __le32 rx_multicast; __le16 tx_aborted; }; @@ -2326,7 +2325,6 @@ static bool rtl8169_init_counter_offsets(struct net_device *dev) tp->tc_offset.tx_errors = tp->counters.tx_errors; tp->tc_offset.tx_multi_collision = tp->counters.tx_multi_collision; - tp->tc_offset.rx_multicast = tp->counters.rx_multicast; tp->tc_offset.tx_aborted = tp->counters.tx_aborted; tp->tc_offset.inited = true; @@ -7480,6 +7478,9 @@ process_pkt: tp->rx_stats.packets++; tp->rx_stats.bytes += pkt_size; u64_stats_update_end(&tp->rx_stats.syncp); + + if (skb->pkt_type == PACKET_MULTICAST) + dev->stats.multicast++; } release_descriptor: desc->opts2 = 0; @@ -7790,7 +7791,6 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) stats->rx_bytes = tp->rx_stats.bytes; } while (u64_stats_fetch_retry_irq(&tp->rx_stats.syncp, start)); - do { start = u64_stats_fetch_begin_irq(&tp->tx_stats.syncp); stats->tx_packets = tp->tx_stats.packets; @@ -7804,6 +7804,7 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) stats->rx_crc_errors = dev->stats.rx_crc_errors; stats->rx_fifo_errors = dev->stats.rx_fifo_errors; stats->rx_missed_errors = dev->stats.rx_missed_errors; + stats->multicast = dev->stats.multicast; /* * Fetch additonal counter values missing in stats collected by driver @@ -7819,8 +7820,6 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) le64_to_cpu(tp->tc_offset.tx_errors); stats->collisions = le32_to_cpu(tp->counters.tx_multi_collision) - le32_to_cpu(tp->tc_offset.tx_multi_collision); - stats->multicast = le32_to_cpu(tp->counters.rx_multicast) - - le32_to_cpu(tp->tc_offset.rx_multicast); stats->tx_aborted_errors = le16_to_cpu(tp->counters.tx_aborted) - le16_to_cpu(tp->tc_offset.tx_aborted); -- GitLab From df2cf4a78e488d26728590cb3c6b4fe4c4862c77 Mon Sep 17 00:00:00 2001 From: Philip Downey Date: Thu, 27 Aug 2015 16:46:26 +0100 Subject: [PATCH 5642/7006] IGMP: Inhibit reports for local multicast groups The range of addresses between 224.0.0.0 and 224.0.0.255 inclusive, is reserved for the use of routing protocols and other low-level topology discovery or maintenance protocols, such as gateway discovery and group membership reporting. Multicast routers should not forward any multicast datagram with destination addresses in this range, regardless of its TTL. Currently, IGMP reports are generated for this reserved range of addresses even though a router will ignore this information since it has no purpose. However, the presence of reserved group addresses in an IGMP membership report uses up network bandwidth and can also obscure addresses of interest when inspecting membership reports using packet inspection or debug messages. Although the RFCs for the various version of IGMP (e.g.RFC 3376 for v3) do not specify that the reserved addresses be excluded from membership reports, it should do no harm in doing so. In particular there should be no adverse effect in any IGMP snooping functionality since 224.0.0.x is specifically excluded as per RFC 4541 (IGMP and MLD Snooping Switches Considerations) section 2.1.2. Data Forwarding Rules: 2) Packets with a destination IP (DIP) address in the 224.0.0.X range which are not IGMP must be forwarded on all ports. IGMP reports for local multicast groups can now be optionally inhibited by means of a system control variable (by setting the value to zero) e.g.: echo 0 > /proc/sys/net/ipv4/igmp_link_local_mcast_reports To retain backwards compatibility the previous behaviour is retained by default on system boot or reverted by setting the value back to non-zero e.g.: echo 1 > /proc/sys/net/ipv4/igmp_link_local_mcast_reports Signed-off-by: Philip Downey Signed-off-by: David S. Miller --- include/linux/igmp.h | 1 + net/ipv4/igmp.c | 26 +++++++++++++++++++++++++- net/ipv4/sysctl_net_ipv4.c | 7 +++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 193ad488d3e20..908429216d9f6 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -37,6 +37,7 @@ static inline struct igmpv3_query * return (struct igmpv3_query *)skb_transport_header(skb); } +extern int sysctl_igmp_llm_reports; extern int sysctl_igmp_max_memberships; extern int sysctl_igmp_max_msf; extern int sysctl_igmp_qrv; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index 9fdfd9deac11d..d38b8b61eaeef 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -110,6 +110,9 @@ #define IP_MAX_MEMBERSHIPS 20 #define IP_MAX_MSF 10 +/* IGMP reports for link-local multicast groups are enabled by default */ +int sysctl_igmp_llm_reports __read_mostly = 1; + #ifdef CONFIG_IP_MULTICAST /* Parameter names and values are taken from igmp-v2-06 draft */ @@ -437,6 +440,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, if (pmc->multiaddr == IGMP_ALL_HOSTS) return skb; + if (ipv4_is_local_multicast(pmc->multiaddr) && !sysctl_igmp_llm_reports) + return skb; isquery = type == IGMPV3_MODE_IS_INCLUDE || type == IGMPV3_MODE_IS_EXCLUDE; @@ -545,6 +550,9 @@ static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) for_each_pmc_rcu(in_dev, pmc) { if (pmc->multiaddr == IGMP_ALL_HOSTS) continue; + if (ipv4_is_local_multicast(pmc->multiaddr) && + !sysctl_igmp_llm_reports) + continue; spin_lock_bh(&pmc->lock); if (pmc->sfcount[MCAST_EXCLUDE]) type = IGMPV3_MODE_IS_EXCLUDE; @@ -678,7 +686,11 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) return igmpv3_send_report(in_dev, pmc); - else if (type == IGMP_HOST_LEAVE_MESSAGE) + + if (ipv4_is_local_multicast(group) && !sysctl_igmp_llm_reports) + return 0; + + if (type == IGMP_HOST_LEAVE_MESSAGE) dst = IGMP_ALL_ROUTER; else dst = group; @@ -851,6 +863,8 @@ static bool igmp_heard_report(struct in_device *in_dev, __be32 group) if (group == IGMP_ALL_HOSTS) return false; + if (ipv4_is_local_multicast(group) && !sysctl_igmp_llm_reports) + return false; rcu_read_lock(); for_each_pmc_rcu(in_dev, im) { @@ -957,6 +971,9 @@ static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, continue; if (im->multiaddr == IGMP_ALL_HOSTS) continue; + if (ipv4_is_local_multicast(im->multiaddr) && + !sysctl_igmp_llm_reports) + continue; spin_lock_bh(&im->lock); if (im->tm_running) im->gsquery = im->gsquery && mark; @@ -1181,6 +1198,8 @@ static void igmp_group_dropped(struct ip_mc_list *im) #ifdef CONFIG_IP_MULTICAST if (im->multiaddr == IGMP_ALL_HOSTS) return; + if (ipv4_is_local_multicast(im->multiaddr) && !sysctl_igmp_llm_reports) + return; reporter = im->reporter; igmp_stop_timer(im); @@ -1213,6 +1232,8 @@ static void igmp_group_added(struct ip_mc_list *im) #ifdef CONFIG_IP_MULTICAST if (im->multiaddr == IGMP_ALL_HOSTS) return; + if (ipv4_is_local_multicast(im->multiaddr) && !sysctl_igmp_llm_reports) + return; if (in_dev->dead) return; @@ -1518,6 +1539,9 @@ static void ip_mc_rejoin_groups(struct in_device *in_dev) for_each_pmc_rtnl(in_dev, im) { if (im->multiaddr == IGMP_ALL_HOSTS) continue; + if (ipv4_is_local_multicast(im->multiaddr) && + !sysctl_igmp_llm_reports) + continue; /* a failover is happening and switches * must be notified immediately diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 879bdc5c95b1d..894da3a70aff9 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -929,6 +929,13 @@ static struct ctl_table ipv4_net_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, + { + .procname = "igmp_link_local_mcast_reports", + .data = &sysctl_igmp_llm_reports, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, { } }; -- GitLab From 274b045509175db0405c784be85e8cce116e6f7d Mon Sep 17 00:00:00 2001 From: Chas Williams <3chas3@gmail.com> Date: Thu, 27 Aug 2015 12:28:46 -0400 Subject: [PATCH 5643/7006] net/xen-netfront: only napi_synchronize() if running If an interface isn't running napi_synchronize() will hang forever. [ 392.248403] rmmod R running task 0 359 343 0x00000000 [ 392.257671] ffff88003760fc88 ffff880037193b40 ffff880037193160 ffff88003760fc88 [ 392.267644] ffff880037610000 ffff88003760fcd8 0000000100014c22 ffffffff81f75c40 [ 392.277524] 0000000000bc7010 ffff88003760fca8 ffffffff81796927 ffffffff81f75c40 [ 392.287323] Call Trace: [ 392.291599] [] schedule+0x37/0x90 [ 392.298553] [] schedule_timeout+0x14b/0x280 [ 392.306421] [] ? irq_free_descs+0x69/0x80 [ 392.314006] [] ? internal_add_timer+0xb0/0xb0 [ 392.322125] [] msleep+0x37/0x50 [ 392.329037] [] xennet_disconnect_backend.isra.24+0xda/0x390 [xen_netfront] [ 392.339658] [] xennet_remove+0x2c/0x80 [xen_netfront] [ 392.348516] [] xenbus_dev_remove+0x59/0xc0 [ 392.356257] [] __device_release_driver+0x87/0x120 [ 392.364645] [] driver_detach+0xb8/0xc0 [ 392.371989] [] bus_remove_driver+0x59/0xe0 [ 392.379883] [] driver_unregister+0x30/0x70 [ 392.387495] [] xenbus_unregister_driver+0x12/0x20 [ 392.395908] [] netif_exit+0x10/0x775 [xen_netfront] [ 392.404877] [] SyS_delete_module+0x1d8/0x230 [ 392.412804] [] system_call_fastpath+0x12/0x71 Signed-off-by: Chas Williams <3chas3@gmail.com> Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 002062db2f1dc..e27e6d2ea6d28 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1348,7 +1348,8 @@ static void xennet_disconnect_backend(struct netfront_info *info) queue->tx_evtchn = queue->rx_evtchn = 0; queue->tx_irq = queue->rx_irq = 0; - napi_synchronize(&queue->napi); + if (netif_running(info->netdev)) + napi_synchronize(&queue->napi); xennet_release_tx_bufs(queue); xennet_release_rx_bufs(queue); -- GitLab From 8f58336d3f78aef61c8023c18546155f5fdf3224 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 27 Aug 2015 10:10:50 -0700 Subject: [PATCH 5644/7006] net: Add ethernet header for pass through VRF device The change to use a custom dst broke tcpdump captures on the VRF device: $ tcpdump -n -i vrf10 ... 05:32:29.009362 IP 10.2.1.254 > 10.2.1.2: ICMP echo request, id 21989, seq 1, length 64 05:32:29.009855 00:00:40:01:8d:36 > 45:00:00:54:d6:6f, ethertype Unknown (0x0a02), length 84: 0x0000: 0102 0a02 01fe 0000 9181 55e5 0001 bd11 ..........U..... 0x0010: da55 0000 0000 bb5d 0700 0000 0000 1011 .U.....]........ 0x0020: 1213 1415 1617 1819 1a1b 1c1d 1e1f 2021 ...............! 0x0030: 2223 2425 2627 2829 2a2b 2c2d 2e2f 3031 "#$%&'()*+,-./01 0x0040: 3233 3435 3637 234567 Local packets going through the VRF device are missing an ethernet header. Fix by adding one and then stripping it off before pushing back to the IP stack. With this patch you get the expected dumps: ... 05:36:15.713944 IP 10.2.1.254 > 10.2.1.2: ICMP echo request, id 23795, seq 1, length 64 05:36:15.714160 IP 10.2.1.2 > 10.2.1.254: ICMP echo reply, id 23795, seq 1, length 64 ... Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vrf.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index b3d9c5546c795..e7094fbd75685 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -219,6 +220,9 @@ err: static netdev_tx_t is_ip_tx_frame(struct sk_buff *skb, struct net_device *dev) { + /* strip the ethernet header added for pass through VRF device */ + __skb_pull(skb, skb_network_offset(skb)); + switch (skb->protocol) { case htons(ETH_P_IP): return vrf_process_v4_outbound(skb, dev); @@ -248,9 +252,47 @@ static netdev_tx_t vrf_xmit(struct sk_buff *skb, struct net_device *dev) return ret; } -static netdev_tx_t vrf_finish(struct sock *sk, struct sk_buff *skb) +/* modelled after ip_finish_output2 */ +static int vrf_finish_output(struct sock *sk, struct sk_buff *skb) { - return dev_queue_xmit(skb); + struct dst_entry *dst = skb_dst(skb); + struct rtable *rt = (struct rtable *)dst; + struct net_device *dev = dst->dev; + unsigned int hh_len = LL_RESERVED_SPACE(dev); + struct neighbour *neigh; + u32 nexthop; + int ret = -EINVAL; + + /* Be paranoid, rather than too clever. */ + if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { + struct sk_buff *skb2; + + skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); + if (!skb2) { + ret = -ENOMEM; + goto err; + } + if (skb->sk) + skb_set_owner_w(skb2, skb->sk); + + consume_skb(skb); + skb = skb2; + } + + rcu_read_lock_bh(); + + nexthop = (__force u32)rt_nexthop(rt, ip_hdr(skb)->daddr); + neigh = __ipv4_neigh_lookup_noref(dev, nexthop); + if (unlikely(!neigh)) + neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); + if (!IS_ERR(neigh)) + ret = dst_neigh_output(dst, neigh, skb); + + rcu_read_unlock_bh(); +err: + if (unlikely(ret < 0)) + vrf_tx_error(skb->dev, skb); + return ret; } static int vrf_output(struct sock *sk, struct sk_buff *skb) @@ -264,7 +306,7 @@ static int vrf_output(struct sock *sk, struct sk_buff *skb) return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, sk, skb, NULL, dev, - vrf_finish, + vrf_finish_output, !(IPCB(skb)->flags & IPSKB_REROUTED)); } -- GitLab From 72afa352d6a3d4da7783b5ddee02b94be49e051a Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 27 Aug 2015 16:06:59 -0700 Subject: [PATCH 5645/7006] net: Introduce ipv4_addr_hash and use it for tcp metrics Refactors a common line into helper function. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/ip.h | 5 +++++ net/ipv4/tcp_metrics.c | 12 ++++++------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index bee5f3582e388..7b9e1c782aa34 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -458,6 +458,11 @@ static __inline__ void inet_reset_saddr(struct sock *sk) #endif +static inline unsigned int ipv4_addr_hash(__be32 ip) +{ + return (__force unsigned int) ip; +} + bool ip_call_ra_chain(struct sk_buff *skb); /* diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index b3d64f61d922e..3a4289268f975 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -249,7 +249,7 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req, case AF_INET: saddr.addr.a4 = inet_rsk(req)->ir_loc_addr; daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr; - hash = (__force unsigned int) daddr.addr.a4; + hash = ipv4_addr_hash(inet_rsk(req)->ir_rmt_addr); break; #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: @@ -289,7 +289,7 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock saddr.addr.a4 = tw->tw_rcv_saddr; daddr.family = AF_INET; daddr.addr.a4 = tw->tw_daddr; - hash = (__force unsigned int) daddr.addr.a4; + hash = ipv4_addr_hash(tw->tw_daddr); } #if IS_ENABLED(CONFIG_IPV6) else if (tw->tw_family == AF_INET6) { @@ -298,7 +298,7 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock saddr.addr.a4 = tw->tw_rcv_saddr; daddr.family = AF_INET; daddr.addr.a4 = tw->tw_daddr; - hash = (__force unsigned int) daddr.addr.a4; + hash = ipv4_addr_hash(tw->tw_daddr); } else { saddr.family = AF_INET6; saddr.addr.in6 = tw->tw_v6_rcv_saddr; @@ -339,7 +339,7 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk, saddr.addr.a4 = inet_sk(sk)->inet_saddr; daddr.family = AF_INET; daddr.addr.a4 = inet_sk(sk)->inet_daddr; - hash = (__force unsigned int) daddr.addr.a4; + hash = ipv4_addr_hash(inet_sk(sk)->inet_daddr); } #if IS_ENABLED(CONFIG_IPV6) else if (sk->sk_family == AF_INET6) { @@ -348,7 +348,7 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk, saddr.addr.a4 = inet_sk(sk)->inet_saddr; daddr.family = AF_INET; daddr.addr.a4 = inet_sk(sk)->inet_daddr; - hash = (__force unsigned int) daddr.addr.a4; + hash = ipv4_addr_hash(inet_sk(sk)->inet_daddr); } else { saddr.family = AF_INET6; saddr.addr.in6 = sk->sk_v6_rcv_saddr; @@ -959,7 +959,7 @@ static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, addr->family = AF_INET; addr->addr.a4 = nla_get_in_addr(a); if (hash) - *hash = (__force unsigned int) addr->addr.a4; + *hash = ipv4_addr_hash(addr->addr.a4); return 0; } a = info->attrs[v6]; -- GitLab From 3abef286cf2f138de353fb0b54453621de961043 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 27 Aug 2015 16:07:00 -0700 Subject: [PATCH 5646/7006] net: Add set,get helpers for inetpeer addresses Use inetpeer set,get helpers in tcp_metrics rather than peeking into the inetpeer_addr struct. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/inetpeer.h | 23 +++++++++++++++ net/ipv4/tcp_metrics.c | 65 ++++++++++++++++++------------------------ 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 002f0bd270013..f75b9e7036a2f 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -71,6 +71,29 @@ void inet_initpeers(void) __init; #define INETPEER_METRICS_NEW (~(u32) 0) +static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) +{ + iaddr->addr.a4 = ip; + iaddr->family = AF_INET; +} + +static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) +{ + return iaddr->addr.a4; +} + +static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, + struct in6_addr *in6) +{ + iaddr->addr.in6 = *in6; + iaddr->family = AF_INET6; +} + +static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) +{ + return &iaddr->addr.in6; +} + /* can be called with or without local BH being disabled */ struct inet_peer *inet_getpeer(struct inet_peer_base *base, const struct inetpeer_addr *daddr, diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 3a4289268f975..4ef4dd4bf38cc 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -247,14 +247,14 @@ static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req, daddr.family = req->rsk_ops->family; switch (daddr.family) { case AF_INET: - saddr.addr.a4 = inet_rsk(req)->ir_loc_addr; - daddr.addr.a4 = inet_rsk(req)->ir_rmt_addr; + inetpeer_set_addr_v4(&saddr, inet_rsk(req)->ir_loc_addr); + inetpeer_set_addr_v4(&daddr, inet_rsk(req)->ir_rmt_addr); hash = ipv4_addr_hash(inet_rsk(req)->ir_rmt_addr); break; #if IS_ENABLED(CONFIG_IPV6) case AF_INET6: - saddr.addr.in6 = inet_rsk(req)->ir_v6_loc_addr; - daddr.addr.in6 = inet_rsk(req)->ir_v6_rmt_addr; + inetpeer_set_addr_v6(&saddr, &inet_rsk(req)->ir_v6_loc_addr); + inetpeer_set_addr_v6(&daddr, &inet_rsk(req)->ir_v6_rmt_addr); hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr); break; #endif @@ -285,25 +285,19 @@ static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock struct net *net; if (tw->tw_family == AF_INET) { - saddr.family = AF_INET; - saddr.addr.a4 = tw->tw_rcv_saddr; - daddr.family = AF_INET; - daddr.addr.a4 = tw->tw_daddr; + inetpeer_set_addr_v4(&saddr, tw->tw_rcv_saddr); + inetpeer_set_addr_v4(&daddr, tw->tw_daddr); hash = ipv4_addr_hash(tw->tw_daddr); } #if IS_ENABLED(CONFIG_IPV6) else if (tw->tw_family == AF_INET6) { if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) { - saddr.family = AF_INET; - saddr.addr.a4 = tw->tw_rcv_saddr; - daddr.family = AF_INET; - daddr.addr.a4 = tw->tw_daddr; + inetpeer_set_addr_v4(&saddr, tw->tw_rcv_saddr); + inetpeer_set_addr_v4(&daddr, tw->tw_daddr); hash = ipv4_addr_hash(tw->tw_daddr); } else { - saddr.family = AF_INET6; - saddr.addr.in6 = tw->tw_v6_rcv_saddr; - daddr.family = AF_INET6; - daddr.addr.in6 = tw->tw_v6_daddr; + inetpeer_set_addr_v6(&saddr, &tw->tw_v6_rcv_saddr); + inetpeer_set_addr_v6(&daddr, &tw->tw_v6_daddr); hash = ipv6_addr_hash(&tw->tw_v6_daddr); } } @@ -335,25 +329,19 @@ static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk, struct net *net; if (sk->sk_family == AF_INET) { - saddr.family = AF_INET; - saddr.addr.a4 = inet_sk(sk)->inet_saddr; - daddr.family = AF_INET; - daddr.addr.a4 = inet_sk(sk)->inet_daddr; + inetpeer_set_addr_v4(&saddr, inet_sk(sk)->inet_saddr); + inetpeer_set_addr_v4(&daddr, inet_sk(sk)->inet_daddr); hash = ipv4_addr_hash(inet_sk(sk)->inet_daddr); } #if IS_ENABLED(CONFIG_IPV6) else if (sk->sk_family == AF_INET6) { if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { - saddr.family = AF_INET; - saddr.addr.a4 = inet_sk(sk)->inet_saddr; - daddr.family = AF_INET; - daddr.addr.a4 = inet_sk(sk)->inet_daddr; + inetpeer_set_addr_v4(&saddr, inet_sk(sk)->inet_saddr); + inetpeer_set_addr_v4(&daddr, inet_sk(sk)->inet_daddr); hash = ipv4_addr_hash(inet_sk(sk)->inet_daddr); } else { - saddr.family = AF_INET6; - saddr.addr.in6 = sk->sk_v6_rcv_saddr; - daddr.family = AF_INET6; - daddr.addr.in6 = sk->sk_v6_daddr; + inetpeer_set_addr_v6(&saddr, &sk->sk_v6_rcv_saddr); + inetpeer_set_addr_v6(&daddr, &sk->sk_v6_daddr); hash = ipv6_addr_hash(&sk->sk_v6_daddr); } } @@ -796,18 +784,18 @@ static int tcp_metrics_fill_info(struct sk_buff *msg, switch (tm->tcpm_daddr.family) { case AF_INET: if (nla_put_in_addr(msg, TCP_METRICS_ATTR_ADDR_IPV4, - tm->tcpm_daddr.addr.a4) < 0) + inetpeer_get_addr_v4(&tm->tcpm_daddr)) < 0) goto nla_put_failure; if (nla_put_in_addr(msg, TCP_METRICS_ATTR_SADDR_IPV4, - tm->tcpm_saddr.addr.a4) < 0) + inetpeer_get_addr_v4(&tm->tcpm_saddr)) < 0) goto nla_put_failure; break; case AF_INET6: if (nla_put_in6_addr(msg, TCP_METRICS_ATTR_ADDR_IPV6, - &tm->tcpm_daddr.addr.in6) < 0) + inetpeer_get_addr_v6(&tm->tcpm_daddr)) < 0) goto nla_put_failure; if (nla_put_in6_addr(msg, TCP_METRICS_ATTR_SADDR_IPV6, - &tm->tcpm_saddr.addr.in6) < 0) + inetpeer_get_addr_v6(&tm->tcpm_saddr)) < 0) goto nla_put_failure; break; default: @@ -956,20 +944,21 @@ static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, a = info->attrs[v4]; if (a) { - addr->family = AF_INET; - addr->addr.a4 = nla_get_in_addr(a); + inetpeer_set_addr_v4(addr, nla_get_in_addr(a)); if (hash) - *hash = ipv4_addr_hash(addr->addr.a4); + *hash = ipv4_addr_hash(inetpeer_get_addr_v4(addr)); return 0; } a = info->attrs[v6]; if (a) { + struct in6_addr in6; + if (nla_len(a) != sizeof(struct in6_addr)) return -EINVAL; - addr->family = AF_INET6; - addr->addr.in6 = nla_get_in6_addr(a); + in6 = nla_get_in6_addr(a); + inetpeer_set_addr_v6(addr, &in6); if (hash) - *hash = ipv6_addr_hash(&addr->addr.in6); + *hash = ipv6_addr_hash(inetpeer_get_addr_v6(addr)); return 0; } return optional ? 1 : -EAFNOSUPPORT; -- GitLab From d39d14ffa24cca9f0e44aa4a63315f4c44c56a93 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 27 Aug 2015 16:07:01 -0700 Subject: [PATCH 5647/7006] net: Add helper function to compare inetpeer addresses tcp_metrics and inetpeer both have functions to compare inetpeer addresses. Consolidate into 1 version. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/inetpeer.h | 16 ++++++++++++++++ net/ipv4/inetpeer.c | 20 ++------------------ net/ipv4/tcp_metrics.c | 6 +----- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index f75b9e7036a2f..9d9b3446731dd 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -121,6 +121,22 @@ static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, return inet_getpeer(base, &daddr, create); } +static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, + const struct inetpeer_addr *b) +{ + int i, n = (a->family == AF_INET ? 1 : 4); + + for (i = 0; i < n; i++) { + if (a->addr.a6[i] == b->addr.a6[i]) + continue; + if ((__force u32)a->addr.a6[i] < (__force u32)b->addr.a6[i]) + return -1; + return 1; + } + + return 0; +} + /* can be called from BH context or outside */ void inet_putpeer(struct inet_peer *p); bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index 241afd743d2cc..86fa458095406 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -157,22 +157,6 @@ void __init inet_initpeers(void) INIT_DEFERRABLE_WORK(&gc_work, inetpeer_gc_worker); } -static int addr_compare(const struct inetpeer_addr *a, - const struct inetpeer_addr *b) -{ - int i, n = (a->family == AF_INET ? 1 : 4); - - for (i = 0; i < n; i++) { - if (a->addr.a6[i] == b->addr.a6[i]) - continue; - if ((__force u32)a->addr.a6[i] < (__force u32)b->addr.a6[i]) - return -1; - return 1; - } - - return 0; -} - #define rcu_deref_locked(X, BASE) \ rcu_dereference_protected(X, lockdep_is_held(&(BASE)->lock.lock)) @@ -188,7 +172,7 @@ static int addr_compare(const struct inetpeer_addr *a, *stackptr++ = &_base->root; \ for (u = rcu_deref_locked(_base->root, _base); \ u != peer_avl_empty;) { \ - int cmp = addr_compare(_daddr, &u->daddr); \ + int cmp = inetpeer_addr_cmp(_daddr, &u->daddr); \ if (cmp == 0) \ break; \ if (cmp == -1) \ @@ -215,7 +199,7 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr, int count = 0; while (u != peer_avl_empty) { - int cmp = addr_compare(daddr, &u->daddr); + int cmp = inetpeer_addr_cmp(daddr, &u->daddr); if (cmp == 0) { /* Before taking a reference, check if this entry was * deleted (refcnt=-1) diff --git a/net/ipv4/tcp_metrics.c b/net/ipv4/tcp_metrics.c index 4ef4dd4bf38cc..c8cbc2b4b7921 100644 --- a/net/ipv4/tcp_metrics.c +++ b/net/ipv4/tcp_metrics.c @@ -81,11 +81,7 @@ static void tcp_metric_set(struct tcp_metrics_block *tm, static bool addr_same(const struct inetpeer_addr *a, const struct inetpeer_addr *b) { - if (a->family != b->family) - return false; - if (a->family == AF_INET) - return a->addr.a4 == b->addr.a4; - return ipv6_addr_equal(&a->addr.in6, &b->addr.in6); + return inetpeer_addr_cmp(a, b) == 0; } struct tcpm_hash_bucket { -- GitLab From 5345c2e12d41f815c1009c9dee72f3d5fcfd4282 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 27 Aug 2015 16:07:02 -0700 Subject: [PATCH 5648/7006] net: Refactor inetpeer address struct Move the inetpeer_addr_base union to inetpeer_addr and drop inetpeer_addr_base. Both the a6 and in6_addr overlays are not needed; drop the __be32 version and rename in6 to a6 for consistency with ipv4. Add a new u32 array to the union which removes the need for the typecast in the compare function and the use of a consistent arg for both ipv4 and ipv6 addresses which makes the compare function more readable. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/inetpeer.h | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index 9d9b3446731dd..e34f98aa93b19 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -15,16 +15,14 @@ #include #include -struct inetpeer_addr_base { +#define INETPEER_MAXKEYSZ (sizeof(struct in6_addr) / sizeof(u32)) + +struct inetpeer_addr { union { __be32 a4; - __be32 a6[4]; - struct in6_addr in6; + struct in6_addr a6; + u32 key[INETPEER_MAXKEYSZ]; }; -}; - -struct inetpeer_addr { - struct inetpeer_addr_base addr; __u16 family; }; @@ -73,25 +71,25 @@ void inet_initpeers(void) __init; static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) { - iaddr->addr.a4 = ip; + iaddr->a4 = ip; iaddr->family = AF_INET; } static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) { - return iaddr->addr.a4; + return iaddr->a4; } static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, struct in6_addr *in6) { - iaddr->addr.in6 = *in6; + iaddr->a6 = *in6; iaddr->family = AF_INET6; } static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) { - return &iaddr->addr.in6; + return &iaddr->a6; } /* can be called with or without local BH being disabled */ @@ -105,7 +103,7 @@ static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, { struct inetpeer_addr daddr; - daddr.addr.a4 = v4daddr; + daddr.a4 = v4daddr; daddr.family = AF_INET; return inet_getpeer(base, &daddr, create); } @@ -116,7 +114,7 @@ static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, { struct inetpeer_addr daddr; - daddr.addr.in6 = *v6daddr; + daddr.a6 = *v6daddr; daddr.family = AF_INET6; return inet_getpeer(base, &daddr, create); } @@ -124,12 +122,17 @@ static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, const struct inetpeer_addr *b) { - int i, n = (a->family == AF_INET ? 1 : 4); + int i, n; + + if (a->family == AF_INET) + n = sizeof(a->a4) / sizeof(u32); + else + n = sizeof(a->a6) / sizeof(u32); for (i = 0; i < n; i++) { - if (a->addr.a6[i] == b->addr.a6[i]) + if (a->key[i] == b->key[i]) continue; - if ((__force u32)a->addr.a6[i] < (__force u32)b->addr.a6[i]) + if (a->key[i] < b->key[i]) return -1; return 1; } -- GitLab From 192132b9a034d87566294be0fba5f8f75c2cf16b Mon Sep 17 00:00:00 2001 From: David Ahern Date: Thu, 27 Aug 2015 16:07:03 -0700 Subject: [PATCH 5649/7006] net: Add support for VRFs to inetpeer cache inetpeer caches based on address only, so duplicate IP addresses within a namespace return the same cached entry. Enhance the ipv4 address key to contain both the IPv4 address and VRF device index. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/net/inetpeer.h | 17 ++++++++++++----- net/ipv4/icmp.c | 3 ++- net/ipv4/ip_fragment.c | 3 ++- net/ipv4/route.c | 7 +++++-- 4 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/net/inetpeer.h b/include/net/inetpeer.h index e34f98aa93b19..4a6009d4486b9 100644 --- a/include/net/inetpeer.h +++ b/include/net/inetpeer.h @@ -15,11 +15,17 @@ #include #include +/* IPv4 address key for cache lookups */ +struct ipv4_addr_key { + __be32 addr; + int vif; +}; + #define INETPEER_MAXKEYSZ (sizeof(struct in6_addr) / sizeof(u32)) struct inetpeer_addr { union { - __be32 a4; + struct ipv4_addr_key a4; struct in6_addr a6; u32 key[INETPEER_MAXKEYSZ]; }; @@ -71,13 +77,13 @@ void inet_initpeers(void) __init; static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) { - iaddr->a4 = ip; + iaddr->a4.addr = ip; iaddr->family = AF_INET; } static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) { - return iaddr->a4; + return iaddr->a4.addr; } static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, @@ -99,11 +105,12 @@ struct inet_peer *inet_getpeer(struct inet_peer_base *base, static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, __be32 v4daddr, - int create) + int vif, int create) { struct inetpeer_addr daddr; - daddr.a4 = v4daddr; + daddr.a4.addr = v4daddr; + daddr.a4.vif = vif; daddr.family = AF_INET; return inet_getpeer(base, &daddr, create); } diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index f16488efa1c89..79fe05befcae9 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -309,9 +309,10 @@ static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, rc = false; if (icmp_global_allow()) { + int vif = vrf_master_ifindex(dst->dev); struct inet_peer *peer; - peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, 1); + peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1); rc = inet_peer_xrlim_allow(peer, net->ipv4.sysctl_icmp_ratelimit); if (peer) diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 15762e758861b..fa7f15305f9a2 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -151,7 +151,8 @@ static void ip4_frag_init(struct inet_frag_queue *q, const void *a) qp->vif = arg->vif; qp->user = arg->user; qp->peer = sysctl_ipfrag_max_dist ? - inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, 1) : NULL; + inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, arg->vif, 1) : + NULL; } static void ip4_frag_free(struct inet_frag_queue *q) diff --git a/net/ipv4/route.c b/net/ipv4/route.c index f3087aaa6dd86..6b91879e9cbe5 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -838,6 +838,7 @@ void ip_rt_send_redirect(struct sk_buff *skb) struct inet_peer *peer; struct net *net; int log_martians; + int vif; rcu_read_lock(); in_dev = __in_dev_get_rcu(rt->dst.dev); @@ -846,10 +847,11 @@ void ip_rt_send_redirect(struct sk_buff *skb) return; } log_martians = IN_DEV_LOG_MARTIANS(in_dev); + vif = vrf_master_ifindex_rcu(rt->dst.dev); rcu_read_unlock(); net = dev_net(rt->dst.dev); - peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1); + peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif, 1); if (!peer) { icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt_nexthop(rt, ip_hdr(skb)->daddr)); @@ -938,7 +940,8 @@ static int ip_error(struct sk_buff *skb) break; } - peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, 1); + peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, + vrf_master_ifindex(skb->dev), 1); send = true; if (peer) { -- GitLab From 9723e6abc70a472c726d5d5ac6402a2d1bb10882 Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Fri, 28 Aug 2015 10:39:56 +0200 Subject: [PATCH 5650/7006] openswitch: fix typo CONFIG_NF_CONNTRACK_LABEL Fix typo in conntrack.c s/CONFIG_NF_CONNTRACK_LABEL/CONFIG_NF_CONNTRACK_LABELS/ Signed-off-by: Valentin Rothberg Signed-off-by: David S. Miller --- net/openvswitch/conntrack.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 890d3eedb447c..886bd27585025 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -169,7 +169,7 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) nla_put_u32(skb, OVS_KEY_ATTR_CT_MARK, key->ct.mark)) return -EMSGSIZE; - if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABEL) && + if (IS_ENABLED(CONFIG_NF_CONNTRACK_LABELS) && nla_put(skb, OVS_KEY_ATTR_CT_LABEL, sizeof(key->ct.label), &key->ct.label)) return -EMSGSIZE; -- GitLab From a69265e9f65a6747c27b01b4030ad85d71aa11ba Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Fri, 28 Aug 2015 11:17:12 +0530 Subject: [PATCH 5651/7006] cxgb4: Force uninitialized state if FW in adapter is unsupported Forcing uninitialized state allows us to upgrade and reinitialize the adapter. FW_VERSION_T4 = 1.4.0.0 FW_VERSION_T5 = 0.0.0.0 FW_VERSION_T6 = 0.0.0.0 At this point driver supports above and greater than above version. If FW in adapter < min FW_VERSION driver supports tries to upgrade the FW If FW in adapter >= FW_VERSION driver supports then it follows normal path Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4.h | 1 + .../net/ethernet/chelsio/cxgb4/cxgb4_main.c | 4 ++ drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 56 +++++++++++++++++++ .../net/ethernet/chelsio/cxgb4/t4fw_version.h | 11 ++++ 4 files changed, 72 insertions(+) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h index 3c99454aac0af..fa0c7b54ec7ad 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h @@ -1289,6 +1289,7 @@ int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op); int t4_fw_upgrade(struct adapter *adap, unsigned int mbox, const u8 *fw_data, unsigned int size, int force); unsigned int t4_flash_cfg_addr(struct adapter *adapter); +int t4_check_fw_version(struct adapter *adap); int t4_get_fw_version(struct adapter *adapter, u32 *vers); int t4_get_tp_version(struct adapter *adapter, u32 *vers); int t4_get_exprom_version(struct adapter *adapter, u32 *vers); diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index f35dd2284d405..eb22d58743e22 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -3668,6 +3668,10 @@ static int adap_init0(struct adapter *adap) */ t4_get_fw_version(adap, &adap->params.fw_vers); t4_get_tp_version(adap, &adap->params.tp_vers); + ret = t4_check_fw_version(adap); + /* If firmware is too old (not supported by driver) force an update. */ + if (ret == -EFAULT) + state = DEV_STATE_UNINIT; if ((adap->flags & MASTER_PF) && state != DEV_STATE_INIT) { struct fw_info *fw_info; struct fw_hdr *card_fw; diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c index ac368efe2862a..44806253c1780 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c @@ -37,6 +37,7 @@ #include "t4_regs.h" #include "t4_values.h" #include "t4fw_api.h" +#include "t4fw_version.h" /** * t4_wait_op_done_val - wait until an operation is completed @@ -2166,6 +2167,61 @@ int t4_get_exprom_version(struct adapter *adap, u32 *vers) return 0; } +/** + * t4_check_fw_version - check if the FW is supported with this driver + * @adap: the adapter + * + * Checks if an adapter's FW is compatible with the driver. Returns 0 + * if there's exact match, a negative error if the version could not be + * read or there's a major version mismatch + */ +int t4_check_fw_version(struct adapter *adap) +{ + int ret, major, minor, micro; + int exp_major, exp_minor, exp_micro; + unsigned int chip_version = CHELSIO_CHIP_VERSION(adap->params.chip); + + ret = t4_get_fw_version(adap, &adap->params.fw_vers); + if (ret) + return ret; + + major = FW_HDR_FW_VER_MAJOR_G(adap->params.fw_vers); + minor = FW_HDR_FW_VER_MINOR_G(adap->params.fw_vers); + micro = FW_HDR_FW_VER_MICRO_G(adap->params.fw_vers); + + switch (chip_version) { + case CHELSIO_T4: + exp_major = T4FW_MIN_VERSION_MAJOR; + exp_minor = T4FW_MIN_VERSION_MINOR; + exp_micro = T4FW_MIN_VERSION_MICRO; + break; + case CHELSIO_T5: + exp_major = T5FW_MIN_VERSION_MAJOR; + exp_minor = T5FW_MIN_VERSION_MINOR; + exp_micro = T5FW_MIN_VERSION_MICRO; + break; + case CHELSIO_T6: + exp_major = T6FW_MIN_VERSION_MAJOR; + exp_minor = T6FW_MIN_VERSION_MINOR; + exp_micro = T6FW_MIN_VERSION_MICRO; + break; + default: + dev_err(adap->pdev_dev, "Unsupported chip type, %x\n", + adap->chip); + return -EINVAL; + } + + if (major < exp_major || (major == exp_major && minor < exp_minor) || + (major == exp_major && minor == exp_minor && micro < exp_micro)) { + dev_err(adap->pdev_dev, + "Card has firmware version %u.%u.%u, minimum " + "supported firmware is %u.%u.%u.\n", major, minor, + micro, exp_major, exp_minor, exp_micro); + return -EFAULT; + } + return 0; +} + /* Is the given firmware API compatible with the one the driver was compiled * with? */ diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h index 32b213559b022..92bafa793de6c 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -40,14 +40,25 @@ #define T4FW_VERSION_MICRO 0x20 #define T4FW_VERSION_BUILD 0x00 +#define T4FW_MIN_VERSION_MAJOR 0x01 +#define T4FW_MIN_VERSION_MINOR 0x04 +#define T4FW_MIN_VERSION_MICRO 0x00 + #define T5FW_VERSION_MAJOR 0x01 #define T5FW_VERSION_MINOR 0x0D #define T5FW_VERSION_MICRO 0x20 #define T5FW_VERSION_BUILD 0x00 +#define T5FW_MIN_VERSION_MAJOR 0x00 +#define T5FW_MIN_VERSION_MINOR 0x00 +#define T5FW_MIN_VERSION_MICRO 0x00 + #define T6FW_VERSION_MAJOR 0x01 #define T6FW_VERSION_MINOR 0x0D #define T6FW_VERSION_MICRO 0x2D #define T6FW_VERSION_BUILD 0x00 +#define T6FW_MIN_VERSION_MAJOR 0x00 +#define T6FW_MIN_VERSION_MINOR 0x00 +#define T6FW_MIN_VERSION_MICRO 0x00 #endif -- GitLab From b0fbdae127a3968688ff7b474e9164dc4bf30dd5 Mon Sep 17 00:00:00 2001 From: Shradha Shah Date: Fri, 28 Aug 2015 10:55:42 +0100 Subject: [PATCH 5652/7006] sfc: Allow driver to cope with a lower number of VIs than it needs for RSS Previously, the driver would refuse to load if it couldn't secure enough VIs from the MC to fulfill its RSS requirements. This was causing probe to fail on later functions in configurations where we'd run out of VIs, such as having many VFs. This change allows the driver to load with fewer VIs, down to a minimum of 2. A warning will be printed saying that RSS requirements were not met, possibly affecting performance. efx->max_tx_channels needs to be set to avoid going down the failure path in efx_probe_nic() immediately in the loop after the probe() NIC-type function. Also, Set rc=ENOSPC when bombing out of efx_probe_nic due to lack of VIs. Signed-off-by: Shradha Shah Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ef10.c | 39 +++++++++++++----- drivers/net/ethernet/sfc/efx.c | 57 ++++++++++++++++++--------- drivers/net/ethernet/sfc/efx.h | 1 + drivers/net/ethernet/sfc/falcon.c | 1 + drivers/net/ethernet/sfc/net_driver.h | 1 + drivers/net/ethernet/sfc/siena.c | 1 + 6 files changed, 72 insertions(+), 28 deletions(-) diff --git a/drivers/net/ethernet/sfc/ef10.c b/drivers/net/ethernet/sfc/ef10.c index 9096b036d362f..ff649ebef6374 100644 --- a/drivers/net/ethernet/sfc/ef10.c +++ b/drivers/net/ethernet/sfc/ef10.c @@ -295,11 +295,11 @@ static int efx_ef10_probe(struct efx_nic *efx) /* We can have one VI for each 8K region. However, until we * use TX option descriptors we need two TX queues per channel. */ - efx->max_channels = - min_t(unsigned int, - EFX_MAX_CHANNELS, - efx_ef10_mem_map_size(efx) / - (EFX_VI_PAGE_SIZE * EFX_TXQ_TYPES)); + efx->max_channels = min_t(unsigned int, + EFX_MAX_CHANNELS, + efx_ef10_mem_map_size(efx) / + (EFX_VI_PAGE_SIZE * EFX_TXQ_TYPES)); + efx->max_tx_channels = efx->max_channels; if (WARN_ON(efx->max_channels == 0)) return -EIO; @@ -824,11 +824,13 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) { struct efx_ef10_nic_data *nic_data = efx->nic_data; unsigned int uc_mem_map_size, wc_mem_map_size; - unsigned int min_vis, pio_write_vi_base, max_vis; + unsigned int min_vis = max(EFX_TXQ_TYPES, + efx_separate_tx_channels ? 2 : 1); + unsigned int channel_vis, pio_write_vi_base, max_vis; void __iomem *membase; int rc; - min_vis = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); + channel_vis = max(efx->n_channels, efx->n_tx_channels * EFX_TXQ_TYPES); #ifdef EFX_USE_PIO /* Try to allocate PIO buffers if wanted and if the full @@ -862,11 +864,11 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) * page size is >4K). So we may allocate some extra VIs just * for writing PIO buffers through. * - * The UC mapping contains (min_vis - 1) complete VIs and the + * The UC mapping contains (channel_vis - 1) complete VIs and the * first half of the next VI. Then the WC mapping begins with * the second half of this last VI. */ - uc_mem_map_size = PAGE_ALIGN((min_vis - 1) * EFX_VI_PAGE_SIZE + + uc_mem_map_size = PAGE_ALIGN((channel_vis - 1) * EFX_VI_PAGE_SIZE + ER_DZ_TX_PIOBUF); if (nic_data->n_piobufs) { /* pio_write_vi_base rounds down to give the number of complete @@ -881,7 +883,7 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) } else { pio_write_vi_base = 0; wc_mem_map_size = 0; - max_vis = min_vis; + max_vis = channel_vis; } /* In case the last attached driver failed to free VIs, do it now */ @@ -893,6 +895,23 @@ static int efx_ef10_dimension_resources(struct efx_nic *efx) if (rc != 0) return rc; + if (nic_data->n_allocated_vis < channel_vis) { + netif_info(efx, drv, efx->net_dev, + "Could not allocate enough VIs to satisfy RSS" + " requirements. Performance may not be optimal.\n"); + /* We didn't get the VIs to populate our channels. + * We could keep what we got but then we'd have more + * interrupts than we need. + * Instead calculate new max_channels and restart + */ + efx->max_channels = nic_data->n_allocated_vis; + efx->max_tx_channels = + nic_data->n_allocated_vis / EFX_TXQ_TYPES; + + efx_ef10_free_vis(efx); + return -EAGAIN; + } + /* If we didn't get enough VIs to map all the PIO buffers, free the * PIO buffers */ diff --git a/drivers/net/ethernet/sfc/efx.c b/drivers/net/ethernet/sfc/efx.c index 03bc03b67f08b..974637d3ae252 100644 --- a/drivers/net/ethernet/sfc/efx.c +++ b/drivers/net/ethernet/sfc/efx.c @@ -115,9 +115,9 @@ static struct workqueue_struct *reset_workqueue; * * This is only used in MSI-X interrupt mode */ -static bool separate_tx_channels; -module_param(separate_tx_channels, bool, 0444); -MODULE_PARM_DESC(separate_tx_channels, +bool efx_separate_tx_channels; +module_param(efx_separate_tx_channels, bool, 0444); +MODULE_PARM_DESC(efx_separate_tx_channels, "Use separate channels for TX and RX"); /* This is the weight assigned to each of the (per-channel) virtual @@ -1391,7 +1391,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) unsigned int n_channels; n_channels = efx_wanted_parallelism(efx); - if (separate_tx_channels) + if (efx_separate_tx_channels) n_channels *= 2; n_channels += extra_channels; n_channels = min(n_channels, efx->max_channels); @@ -1418,13 +1418,16 @@ static int efx_probe_interrupts(struct efx_nic *efx) efx->n_channels = n_channels; if (n_channels > extra_channels) n_channels -= extra_channels; - if (separate_tx_channels) { - efx->n_tx_channels = max(n_channels / 2, 1U); + if (efx_separate_tx_channels) { + efx->n_tx_channels = min(max(n_channels / 2, + 1U), + efx->max_tx_channels); efx->n_rx_channels = max(n_channels - efx->n_tx_channels, 1U); } else { - efx->n_tx_channels = n_channels; + efx->n_tx_channels = min(n_channels, + efx->max_tx_channels); efx->n_rx_channels = n_channels; } for (i = 0; i < efx->n_channels; i++) @@ -1450,7 +1453,7 @@ static int efx_probe_interrupts(struct efx_nic *efx) /* Assume legacy interrupts */ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { - efx->n_channels = 1 + (separate_tx_channels ? 1 : 0); + efx->n_channels = 1 + (efx_separate_tx_channels ? 1 : 0); efx->n_rx_channels = 1; efx->n_tx_channels = 1; efx->legacy_irq = efx->pci_dev->irq; @@ -1624,7 +1627,8 @@ static void efx_set_channels(struct efx_nic *efx) struct efx_tx_queue *tx_queue; efx->tx_channel_offset = - separate_tx_channels ? efx->n_channels - efx->n_tx_channels : 0; + efx_separate_tx_channels ? + efx->n_channels - efx->n_tx_channels : 0; /* We need to mark which channels really have RX and TX * queues, and adjust the TX queue numbers if we have separate @@ -1653,17 +1657,34 @@ static int efx_probe_nic(struct efx_nic *efx) if (rc) return rc; - /* Determine the number of channels and queues by trying to hook - * in MSI-X interrupts. */ - rc = efx_probe_interrupts(efx); - if (rc) - goto fail1; + do { + if (!efx->max_channels || !efx->max_tx_channels) { + netif_err(efx, drv, efx->net_dev, + "Insufficient resources to allocate" + " any channels\n"); + rc = -ENOSPC; + goto fail1; + } - efx_set_channels(efx); + /* Determine the number of channels and queues by trying + * to hook in MSI-X interrupts. + */ + rc = efx_probe_interrupts(efx); + if (rc) + goto fail1; - rc = efx->type->dimension_resources(efx); - if (rc) - goto fail2; + efx_set_channels(efx); + + /* dimension_resources can fail with EAGAIN */ + rc = efx->type->dimension_resources(efx); + if (rc != 0 && rc != -EAGAIN) + goto fail2; + + if (rc == -EAGAIN) + /* try again with new max_channels */ + efx_remove_interrupts(efx); + + } while (rc == -EAGAIN); if (efx->n_channels > 1) netdev_rss_key_fill(&efx->rx_hash_key, diff --git a/drivers/net/ethernet/sfc/efx.h b/drivers/net/ethernet/sfc/efx.h index acb1e07184857..1aaf76c1ace86 100644 --- a/drivers/net/ethernet/sfc/efx.h +++ b/drivers/net/ethernet/sfc/efx.h @@ -35,6 +35,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index); int efx_setup_tc(struct net_device *net_dev, u8 num_tc); unsigned int efx_tx_max_skb_descs(struct efx_nic *efx); extern unsigned int efx_piobuf_size; +extern bool efx_separate_tx_channels; /* RX */ void efx_set_default_rx_indir_table(struct efx_nic *efx); diff --git a/drivers/net/ethernet/sfc/falcon.c b/drivers/net/ethernet/sfc/falcon.c index 80e69af216426..d790cb8d9db3c 100644 --- a/drivers/net/ethernet/sfc/falcon.c +++ b/drivers/net/ethernet/sfc/falcon.c @@ -2371,6 +2371,7 @@ static int falcon_probe_nic(struct efx_nic *efx) efx->max_channels = (efx_nic_rev(efx) <= EFX_REV_FALCON_A1 ? 4 : EFX_MAX_CHANNELS); + efx->max_tx_channels = efx->max_channels; efx->timer_quantum_ns = 4968; /* 621 cycles */ /* Initialise I2C adapter */ diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 4d35313a239db..c530e1c4cb4f1 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -972,6 +972,7 @@ struct efx_nic { unsigned next_buffer_table; unsigned int max_channels; + unsigned int max_tx_channels; unsigned n_channels; unsigned n_rx_channels; unsigned rss_spread; diff --git a/drivers/net/ethernet/sfc/siena.c b/drivers/net/ethernet/sfc/siena.c index b2f886d904297..2219b5424d2bd 100644 --- a/drivers/net/ethernet/sfc/siena.c +++ b/drivers/net/ethernet/sfc/siena.c @@ -262,6 +262,7 @@ static int siena_probe_nic(struct efx_nic *efx) } efx->max_channels = EFX_MAX_CHANNELS; + efx->max_tx_channels = EFX_MAX_CHANNELS; efx_reado(efx, ®, FR_AZ_CS_DEBUG); efx->port_num = EFX_OWORD_FIELD(reg, FRF_CZ_CS_PORT_NUM) - 1; -- GitLab From c1b3b19923a371c9e099c30372d376b02fe66088 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 28 Aug 2015 18:46:39 +0200 Subject: [PATCH 5653/7006] net: sched: don't break line in tc_classify loop notification Just some minor noise follow-up to address some stylistic issues of commit 3b3ae880266d ("net: sched: consolidate tc_classify{,_compat}"). Accidentally v1 instead of v2 of that commit got applied, so this patch adds the relative diff. Suggested-by: Alexei Starovoitov Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- net/sched/sch_api.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index a3c70a18a7647..f43c8f33f09ef 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -1825,8 +1825,7 @@ reclassify: err = tp->classify(skb, tp, res); #ifdef CONFIG_NET_CLS_ACT - if (unlikely(err == TC_ACT_RECLASSIFY && - !compat_mode)) + if (unlikely(err == TC_ACT_RECLASSIFY && !compat_mode)) goto reset; #endif if (err >= 0) @@ -1837,9 +1836,9 @@ reclassify: #ifdef CONFIG_NET_CLS_ACT reset: if (unlikely(limit++ >= MAX_REC_LOOP)) { - net_notice_ratelimited("%s: reclassify loop, rule prio %u, " - "protocol %02x\n", tp->q->ops->id, - tp->prio & 0xffff, ntohs(tp->protocol)); + net_notice_ratelimited("%s: reclassify loop, rule prio %u, protocol %02x\n", + tp->q->ops->id, tp->prio & 0xffff, + ntohs(tp->protocol)); return TC_ACT_SHOT; } -- GitLab From d3765f08d6f32f17ac898ec1f19957b322d4157f Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 28 Aug 2015 21:34:34 +0300 Subject: [PATCH 5654/7006] phylib: simplify bogus phy_device_create() result Get rid of the bogus string of type casts where ERR_PTR() is enough. Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 55f01788df5ec..ff7dcb3e8f271 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -157,7 +157,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, /* We allocate the device, and initialize the default values */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (NULL == dev) - return (struct phy_device *)PTR_ERR((void *)-ENOMEM); + return ERR_PTR(-ENOMEM); dev->dev.release = phy_device_release; -- GitLab From ef899c0778a39063816e19d749a688c06a6ac78e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 28 Aug 2015 21:35:14 +0300 Subject: [PATCH 5655/7006] phylib: simplify NULL checks Fix scripts/checkpatch.pl's messages like: CHECK: Comparison to NULL could be written "!phydrv->read_mmd_indirect" BTW, it doesn't detect the reversed comparisons (which I've fixed as well). Signed-off-by: Sergei Shtylyov Signed-off-by: David S. Miller --- drivers/net/phy/phy.c | 4 ++-- drivers/net/phy/phy_device.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index dcee3aa99e01b..adb48abafc872 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -1040,7 +1040,7 @@ int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, struct phy_driver *phydrv = phydev->drv; int value = -1; - if (phydrv->read_mmd_indirect == NULL) { + if (!phydrv->read_mmd_indirect) { struct mii_bus *bus = phydev->bus; mutex_lock(&bus->mdio_lock); @@ -1077,7 +1077,7 @@ void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, { struct phy_driver *phydrv = phydev->drv; - if (phydrv->write_mmd_indirect == NULL) { + if (!phydrv->write_mmd_indirect) { struct mii_bus *bus = phydev->bus; mutex_lock(&bus->mdio_lock); diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index ff7dcb3e8f271..c0f2111272744 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -156,7 +156,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, /* We allocate the device, and initialize the default values */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (NULL == dev) + if (!dev) return ERR_PTR(-ENOMEM); dev->dev.release = phy_device_release; @@ -178,7 +178,7 @@ struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, dev->bus = bus; dev->dev.parent = &bus->dev; dev->dev.bus = &mdio_bus_type; - dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; + dev->irq = bus->irq ? bus->irq[addr] : PHY_POLL; dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); dev->state = PHY_DOWN; @@ -589,7 +589,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, /* Assume that if there is no driver, that it doesn't * exist, and we should use the genphy driver. */ - if (NULL == d->driver) { + if (!d->driver) { if (phydev->is_c45) d->driver = &genphy_driver[GENPHY_DRV_10G].driver; else -- GitLab From 96be5f2806cd65a2ebced3bfcdf7df0116e6c4a6 Mon Sep 17 00:00:00 2001 From: Elad Raz Date: Sat, 22 Aug 2015 08:44:11 +0300 Subject: [PATCH 5656/7006] netfilter: ipset: Fixing unnamed union init In continue to proposed Vinson Lee's post [1], this patch fixes compilation issues founded at gcc 4.4.7. The initialization of .cidr field of unnamed unions causes compilation error in gcc 4.4.x. References Visible links [1] https://lkml.org/lkml/2015/7/5/74 Signed-off-by: Elad Raz Signed-off-by: Pablo Neira Ayuso --- net/netfilter/ipset/ip_set_hash_netnet.c | 20 ++++++++++++++++++-- net/netfilter/ipset/ip_set_hash_netportnet.c | 20 ++++++++++++++++++-- 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/net/netfilter/ipset/ip_set_hash_netnet.c b/net/netfilter/ipset/ip_set_hash_netnet.c index 3c862c0a76d1e..a93dfebffa811 100644 --- a/net/netfilter/ipset/ip_set_hash_netnet.c +++ b/net/netfilter/ipset/ip_set_hash_netnet.c @@ -131,6 +131,13 @@ hash_netnet4_data_next(struct hash_netnet4_elem *next, #define HOST_MASK 32 #include "ip_set_hash_gen.h" +static void +hash_netnet4_init(struct hash_netnet4_elem *e) +{ + e->cidr[0] = HOST_MASK; + e->cidr[1] = HOST_MASK; +} + static int hash_netnet4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, @@ -160,7 +167,7 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], { const struct hash_netnet *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_netnet4_elem e = { .cidr = { HOST_MASK, HOST_MASK, }, }; + struct hash_netnet4_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_UEXT(set); u32 ip = 0, ip_to = 0, last; u32 ip2 = 0, ip2_from = 0, ip2_to = 0, last2; @@ -169,6 +176,7 @@ hash_netnet4_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + hash_netnet4_init(&e); if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; @@ -357,6 +365,13 @@ hash_netnet6_data_next(struct hash_netnet4_elem *next, #define IP_SET_EMIT_CREATE #include "ip_set_hash_gen.h" +static void +hash_netnet6_init(struct hash_netnet6_elem *e) +{ + e->cidr[0] = HOST_MASK; + e->cidr[1] = HOST_MASK; +} + static int hash_netnet6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, @@ -385,13 +400,14 @@ hash_netnet6_uadt(struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt, u32 *lineno, u32 flags, bool retried) { ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_netnet6_elem e = { .cidr = { HOST_MASK, HOST_MASK, }, }; + struct hash_netnet6_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_UEXT(set); int ret; if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + hash_netnet6_init(&e); if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_optattr_netorder(tb, IPSET_ATTR_CADT_FLAGS))) return -IPSET_ERR_PROTOCOL; diff --git a/net/netfilter/ipset/ip_set_hash_netportnet.c b/net/netfilter/ipset/ip_set_hash_netportnet.c index 0c68734f5cc4a..9a14c237830f4 100644 --- a/net/netfilter/ipset/ip_set_hash_netportnet.c +++ b/net/netfilter/ipset/ip_set_hash_netportnet.c @@ -142,6 +142,13 @@ hash_netportnet4_data_next(struct hash_netportnet4_elem *next, #define HOST_MASK 32 #include "ip_set_hash_gen.h" +static void +hash_netportnet4_init(struct hash_netportnet4_elem *e) +{ + e->cidr[0] = HOST_MASK; + e->cidr[1] = HOST_MASK; +} + static int hash_netportnet4_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, @@ -175,7 +182,7 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], { const struct hash_netportnet *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_netportnet4_elem e = { .cidr = { HOST_MASK, HOST_MASK, }, }; + struct hash_netportnet4_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_UEXT(set); u32 ip = 0, ip_to = 0, ip_last, p = 0, port, port_to; u32 ip2_from = 0, ip2_to = 0, ip2_last, ip2; @@ -185,6 +192,7 @@ hash_netportnet4_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + hash_netportnet4_init(&e); if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || @@ -412,6 +420,13 @@ hash_netportnet6_data_next(struct hash_netportnet4_elem *next, #define IP_SET_EMIT_CREATE #include "ip_set_hash_gen.h" +static void +hash_netportnet6_init(struct hash_netportnet6_elem *e) +{ + e->cidr[0] = HOST_MASK; + e->cidr[1] = HOST_MASK; +} + static int hash_netportnet6_kadt(struct ip_set *set, const struct sk_buff *skb, const struct xt_action_param *par, @@ -445,7 +460,7 @@ hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[], { const struct hash_netportnet *h = set->data; ipset_adtfn adtfn = set->variant->adt[adt]; - struct hash_netportnet6_elem e = { .cidr = { HOST_MASK, HOST_MASK, }, }; + struct hash_netportnet6_elem e = { }; struct ip_set_ext ext = IP_SET_INIT_UEXT(set); u32 port, port_to; bool with_ports = false; @@ -454,6 +469,7 @@ hash_netportnet6_uadt(struct ip_set *set, struct nlattr *tb[], if (tb[IPSET_ATTR_LINENO]) *lineno = nla_get_u32(tb[IPSET_ATTR_LINENO]); + hash_netportnet6_init(&e); if (unlikely(!tb[IPSET_ATTR_IP] || !tb[IPSET_ATTR_IP2] || !ip_set_attr_netorder(tb, IPSET_ATTR_PORT) || !ip_set_optattr_netorder(tb, IPSET_ATTR_PORT_TO) || -- GitLab From a9de9777d613500b089a7416f936bf3ae5f070d2 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Fri, 28 Aug 2015 21:01:43 +0200 Subject: [PATCH 5657/7006] netfilter: nfnetlink: work around wrong endianess in res_id field The convention in nfnetlink is to use network byte order in every header field as well as in the attribute payload. The initial version of the batching infrastructure assumes that res_id comes in host byte order though. The only client of the batching infrastructure is nf_tables, so let's add a workaround to address this inconsistency. We currently have 11 nfnetlink subsystems according to NFNL_SUBSYS_COUNT, so we can assume that the subsystem 2560, ie. htons(10), will not be allocated anytime soon, so it can be an alias of nf_tables from the nfnetlink batching path when interpreting the res_id field. Based on original patch from Florian Westphal. Reported-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/netfilter/nfnetlink.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c index 0c0e8ecf02abb..70277b11f742e 100644 --- a/net/netfilter/nfnetlink.c +++ b/net/netfilter/nfnetlink.c @@ -444,6 +444,7 @@ done: static void nfnetlink_rcv(struct sk_buff *skb) { struct nlmsghdr *nlh = nlmsg_hdr(skb); + u_int16_t res_id; int msglen; if (nlh->nlmsg_len < NLMSG_HDRLEN || @@ -468,7 +469,12 @@ static void nfnetlink_rcv(struct sk_buff *skb) nfgenmsg = nlmsg_data(nlh); skb_pull(skb, msglen); - nfnetlink_rcv_batch(skb, nlh, nfgenmsg->res_id); + /* Work around old nft using host byte order */ + if (nfgenmsg->res_id == NFNL_SUBSYS_NFTABLES) + res_id = NFNL_SUBSYS_NFTABLES; + else + res_id = ntohs(nfgenmsg->res_id); + nfnetlink_rcv_batch(skb, nlh, res_id); } else { netlink_rcv_skb(skb, &nfnetlink_rcv_msg); } -- GitLab From c9fd56b34efd06a031cbc918d288f09e38173ff9 Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 28 Aug 2015 15:44:25 -0700 Subject: [PATCH 5658/7006] netpoll: warn on netpoll_send_udp users who haven't disabled irqs Make sure we catch future netpoll_send_udp users who use it without disabling irqs and also as a hint for poll_controller users. Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/core/netpoll.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/core/netpoll.c b/net/core/netpoll.c index c126a878c47c9..6aa3db8dfc3b5 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -380,6 +380,8 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) static atomic_t ip_ident; struct ipv6hdr *ip6h; + WARN_ON_ONCE(!irqs_disabled()); + udp_len = len + sizeof(*udph); if (np->ipv6) ip_len = udp_len + sizeof(*ip6h); -- GitLab From 1a6877b9c0c2ad901d4335d909432d3bb6d3a330 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Fri, 28 Aug 2015 15:56:22 -0700 Subject: [PATCH 5659/7006] lib: introduce strncpy_from_unsafe() generalize FETCH_FUNC_NAME(memory, string) into strncpy_from_unsafe() and fix sparse warnings that were present in original implementation. Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- include/linux/uaccess.h | 2 ++ kernel/trace/trace_kprobe.c | 20 ++++-------------- lib/strncpy_from_user.c | 41 +++++++++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 16 deletions(-) diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h index ae572c1386073..d6f2c2c5b0433 100644 --- a/include/linux/uaccess.h +++ b/include/linux/uaccess.h @@ -129,4 +129,6 @@ extern long __probe_kernel_read(void *dst, const void *src, size_t size); extern long notrace probe_kernel_write(void *dst, const void *src, size_t size); extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size); +extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count); + #endif /* __LINUX_UACCESS_H__ */ diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index b7d0cdd9906c1..c9956440d0e60 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c @@ -165,11 +165,9 @@ DEFINE_BASIC_FETCH_FUNCS(memory) static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, void *addr, void *dest) { - long ret; int maxlen = get_rloc_len(*(u32 *)dest); u8 *dst = get_rloc_data(dest); - u8 *src = addr; - mm_segment_t old_fs = get_fs(); + long ret; if (!maxlen) return; @@ -178,23 +176,13 @@ static void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, * Try to get string again, since the string can be changed while * probing. */ - set_fs(KERNEL_DS); - pagefault_disable(); - - do - ret = __copy_from_user_inatomic(dst++, src++, 1); - while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen); - - dst[-1] = '\0'; - pagefault_enable(); - set_fs(old_fs); + ret = strncpy_from_unsafe(dst, addr, maxlen); if (ret < 0) { /* Failed to fetch string */ - ((u8 *)get_rloc_data(dest))[0] = '\0'; + dst[0] = '\0'; *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); } else { - *(u32 *)dest = make_data_rloc(src - (u8 *)addr, - get_rloc_offs(*(u32 *)dest)); + *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); } } NOKPROBE_SYMBOL(FETCH_FUNC_NAME(memory, string)); diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c index e0af6ff73d146..ead8c4a068d12 100644 --- a/lib/strncpy_from_user.c +++ b/lib/strncpy_from_user.c @@ -112,3 +112,44 @@ long strncpy_from_user(char *dst, const char __user *src, long count) return -EFAULT; } EXPORT_SYMBOL(strncpy_from_user); + +/** + * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Unsafe address. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from unsafe address to kernel buffer. + * + * On success, returns the length of the string INCLUDING the trailing NUL. + * + * If access fails, returns -EFAULT (some data may have been copied + * and the trailing NUL added). + * + * If @count is smaller than the length of the string, copies @count-1 bytes, + * sets the last byte of @dst buffer to NUL and returns @count. + */ +long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) +{ + mm_segment_t old_fs = get_fs(); + const void *src = unsafe_addr; + long ret; + + if (unlikely(count <= 0)) + return 0; + + set_fs(KERNEL_DS); + pagefault_disable(); + + do { + ret = __copy_from_user_inatomic(dst++, + (const void __user __force *)src++, 1); + } while (dst[-1] && ret == 0 && src - unsafe_addr < count); + + dst[-1] = '\0'; + pagefault_enable(); + set_fs(old_fs); + + return ret < 0 ? ret : src - unsafe_addr; +} -- GitLab From 8d3b7dce8622919da5c5822ef7338d6604c9fe6e Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Fri, 28 Aug 2015 15:56:23 -0700 Subject: [PATCH 5660/7006] bpf: add support for %s specifier to bpf_trace_printk() %s specifier makes bpf program and kernel debugging easier. To make sure that trace_printk won't crash the unsafe string is copied into stack and unsafe pointer is substituted. The following C program: #include int foo(struct pt_regs *ctx, struct filename *filename) { void *name = 0; bpf_probe_read(&name, sizeof(name), &filename->name); bpf_trace_printk("executed %s\n", name); return 0; } when attached to kprobe do_execve() will produce output in /sys/kernel/debug/tracing/trace_pipe : make-13492 [002] d..1 3250.997277: : executed /bin/sh sh-13493 [004] d..1 3250.998716: : executed /usr/bin/gcc gcc-13494 [002] d..1 3250.999822: : executed /usr/lib/gcc/x86_64-linux-gnu/4.7/cc1 gcc-13495 [002] d..1 3251.006731: : executed /usr/bin/as gcc-13496 [002] d..1 3251.011831: : executed /usr/lib/gcc/x86_64-linux-gnu/4.7/collect2 collect2-13497 [000] d..1 3251.012941: : executed /usr/bin/ld Suggested-by: Brendan Gregg Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- kernel/trace/bpf_trace.c | 32 ++++++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index ef9936df1b049..0fe96c7c8803c 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -81,13 +81,16 @@ static const struct bpf_func_proto bpf_probe_read_proto = { /* * limited trace_printk() - * only %d %u %x %ld %lu %lx %lld %llu %llx %p conversion specifiers allowed + * only %d %u %x %ld %lu %lx %lld %llu %llx %p %s conversion specifiers allowed */ static u64 bpf_trace_printk(u64 r1, u64 fmt_size, u64 r3, u64 r4, u64 r5) { char *fmt = (char *) (long) r1; + bool str_seen = false; int mod[3] = {}; int fmt_cnt = 0; + u64 unsafe_addr; + char buf[64]; int i; /* @@ -114,12 +117,37 @@ static u64 bpf_trace_printk(u64 r1, u64 fmt_size, u64 r3, u64 r4, u64 r5) if (fmt[i] == 'l') { mod[fmt_cnt]++; i++; - } else if (fmt[i] == 'p') { + } else if (fmt[i] == 'p' || fmt[i] == 's') { mod[fmt_cnt]++; i++; if (!isspace(fmt[i]) && !ispunct(fmt[i]) && fmt[i] != 0) return -EINVAL; fmt_cnt++; + if (fmt[i - 1] == 's') { + if (str_seen) + /* allow only one '%s' per fmt string */ + return -EINVAL; + str_seen = true; + + switch (fmt_cnt) { + case 1: + unsafe_addr = r3; + r3 = (long) buf; + break; + case 2: + unsafe_addr = r4; + r4 = (long) buf; + break; + case 3: + unsafe_addr = r5; + r5 = (long) buf; + break; + } + buf[0] = 0; + strncpy_from_unsafe(buf, + (void *) (long) unsafe_addr, + sizeof(buf)); + } continue; } -- GitLab From 404c2db635b0e41697eed165b045cb47fd729dd0 Mon Sep 17 00:00:00 2001 From: "Shreyas B. Prabhu" Date: Mon, 3 Aug 2015 11:46:00 +0530 Subject: [PATCH 5661/7006] tools: cpupower: Fix error when running cpupower monitor get_cpu_topology() tries to get topology info from all cpus by reading files in the topology sysfs dir. If a cpu is offlined, since it doesn't have topology dir, this function fails and returns -1. This causes functions relying on get_cpu_topology() to fail. For example- $ cpupower monitor Cannot read number of available processors Fix this by skipping fetching topology info for offline cpus. Signed-off-by: Shreyas B. Prabhu Reported-by: Pavaman Subramaniyam Acked-by: Thomas Renninger Signed-off-by: Rafael J. Wysocki --- tools/power/cpupower/utils/helpers/topology.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index c13120af519b4..cea398c176e7f 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c @@ -73,6 +73,8 @@ int get_cpu_topology(struct cpupower_topology *cpu_top) for (cpu = 0; cpu < cpus; cpu++) { cpu_top->core_info[cpu].cpu = cpu; cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); + if (!cpu_top->core_info[cpu].is_online) + continue; if(sysfs_topology_read_file( cpu, "physical_package_id", -- GitLab From 5021282cc483d4126c1704942adb74806f7d15d6 Mon Sep 17 00:00:00 2001 From: Seiichi Ikarashi Date: Wed, 19 Aug 2015 14:26:03 +0900 Subject: [PATCH 5662/7006] powercap / RAPL: disable the 2nd power limit properly Let rapl_unregister_powercap() disable the second power limit only if it exists. Intel64 SDM Vol.3 14.9 says that the package domain has it but neither the power plane domain nor the DRAM domain has it. Signed-off-by: Seiichi Ikarashi Signed-off-by: Rafael J. Wysocki --- drivers/powercap/intel_rapl.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c index a5eddfbb02309..5efacd050c7d5 100644 --- a/drivers/powercap/intel_rapl.c +++ b/drivers/powercap/intel_rapl.c @@ -1147,9 +1147,11 @@ static int rapl_unregister_powercap(void) pr_debug("remove package, undo power limit on %d: %s\n", rp->id, rd->name); rapl_write_data_raw(rd, PL1_ENABLE, 0); - rapl_write_data_raw(rd, PL2_ENABLE, 0); rapl_write_data_raw(rd, PL1_CLAMP, 0); - rapl_write_data_raw(rd, PL2_CLAMP, 0); + if (find_nr_power_limit(rd) > 1) { + rapl_write_data_raw(rd, PL2_ENABLE, 0); + rapl_write_data_raw(rd, PL2_CLAMP, 0); + } if (rd->id == RAPL_DOMAIN_PACKAGE) { rd_package = rd; continue; -- GitLab From 15dec67ae3ddb222fe6907db299229906ede8143 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Aug 2015 14:50:49 +0200 Subject: [PATCH 5663/7006] PM / domains: Align column headers and data in pm_genpd_summary output "domain": header is indented by 4, data by 0 spaces => 0 spaces "/device": header is indented by 11, data by 4 spaces => 4 spaces "slaves": header is indented by 47, data by 49 spaces => 48 spaces Ruler: 1234567890123456789012345678901234567890123456789012345678901234567890 Before: domain status slaves /device runtime status ---------------------------------------------------------------------- a3sp on a2us /devices/platform/e60b0000.i2c suspended After: domain status slaves /device runtime status ---------------------------------------------------------------------- a3sp on a2us /devices/platform/e60b0000.i2c suspended Signed-off-by: Geert Uytterhoeven Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 7666a1cbaf951..9bd2b28da1ed3 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -2074,7 +2074,7 @@ static int pm_genpd_summary_one(struct seq_file *s, if (WARN_ON(genpd->status >= ARRAY_SIZE(status_lookup))) goto exit; - seq_printf(s, "%-30s %-15s ", genpd->name, status_lookup[genpd->status]); + seq_printf(s, "%-30s %-15s ", genpd->name, status_lookup[genpd->status]); /* * Modifications on the list require holding locks on both @@ -2109,8 +2109,8 @@ static int pm_genpd_summary_show(struct seq_file *s, void *data) struct generic_pm_domain *genpd; int ret = 0; - seq_puts(s, " domain status slaves\n"); - seq_puts(s, " /device runtime status\n"); + seq_puts(s, "domain status slaves\n"); + seq_puts(s, " /device runtime status\n"); seq_puts(s, "----------------------------------------------------------------------\n"); ret = mutex_lock_interruptible(&gpd_list_lock); -- GitLab From be5ed55de011bddbb8ef7b3453edf07a26865beb Mon Sep 17 00:00:00 2001 From: Rajendra Nayak Date: Thu, 13 Aug 2015 11:51:57 +0530 Subject: [PATCH 5664/7006] PM / Domains: Make pm_genpd_init() available to modules Export symbol pm_genpd_init so it can be used in loadable kernel modules Signed-off-by: Rajendra Nayak Reported-by: Stephen Rothwell Acked-by: Geert Uytterhoeven Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 9bd2b28da1ed3..6d465a9352f1f 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1716,6 +1716,7 @@ void pm_genpd_init(struct generic_pm_domain *genpd, list_add(&genpd->gpd_list_node, &gpd_list); mutex_unlock(&gpd_list_lock); } +EXPORT_SYMBOL_GPL(pm_genpd_init); #ifdef CONFIG_PM_GENERIC_DOMAINS_OF /* -- GitLab From ad440bf40e2846966da44e885bb7d8a1f8384fa6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 18 Aug 2015 13:38:02 +0200 Subject: [PATCH 5665/7006] PM / Domains: Remove unusable governor dummies The governor dummies for the !CONFIG_PM_GENERIC_DOMAINS case are unusable, as a governors is always referred to by taking its address, which you can't do with a literal NULL pointer. I.e. pm_genpd_init(genpd, &simple_qos_governor, false); fails to compile with: error: lvalue required as unary '&' operand Hence just remove the governor dummies. Signed-off-by: Geert Uytterhoeven Acked-by: Ulf Hansson Signed-off-by: Rafael J. Wysocki --- include/linux/pm_domain.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h index b2725e6e8e7b9..b1cf7e797892b 100644 --- a/include/linux/pm_domain.h +++ b/include/linux/pm_domain.h @@ -221,8 +221,6 @@ static inline int pm_genpd_name_poweron(const char *domain_name) return -ENOSYS; } static inline void pm_genpd_poweroff_unused(void) {} -#define simple_qos_governor NULL -#define pm_domain_always_on_gov NULL #endif static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, -- GitLab From 8bb6944e5aabaf9b7977502667a6981733564f85 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 27 Aug 2015 10:17:00 +0100 Subject: [PATCH 5666/7006] PM / Domains: Fix typo in description of genpd_dev_pm_detach() The function genpd_dev_pm_detach() detaches a device from a PM domain, however, in the description, the "dev" argument for the function is described as the device to "attach" instead of "detach". Correct this. Signed-off-by: Jon Hunter Acked-by: Geert Uytterhoeven Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 6d465a9352f1f..416720159e96c 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1890,7 +1890,7 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider); /** * genpd_dev_pm_detach - Detach a device from its PM domain. - * @dev: Device to attach. + * @dev: Device to detach. * @power_off: Currently not used * * Try to locate a corresponding generic PM domain, which the device was -- GitLab From 742f452b9b60c228a33e8d35fd2c74cd15bdaa29 Mon Sep 17 00:00:00 2001 From: Benson Leung Date: Fri, 28 Aug 2015 17:30:16 -0700 Subject: [PATCH 5667/7006] Input: elan_i2c - fix typos for validpage_count Search for "vaildpage_count" and replace with "validpage_count". Signed-off-by: Benson Leung Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index bbdaedc09261e..d4a38caa1ab13 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -84,7 +84,7 @@ struct elan_tp_data { int pressure_adjustment; u8 mode; u8 ic_type; - u16 fw_vaildpage_count; + u16 fw_validpage_count; u16 fw_signature_address; bool irq_wake; @@ -94,28 +94,28 @@ struct elan_tp_data { bool baseline_ready; }; -static int elan_get_fwinfo(u8 ic_type, u16 *vaildpage_count, +static int elan_get_fwinfo(u8 ic_type, u16 *validpage_count, u16 *signature_address) { switch(ic_type) { case 0x08: - *vaildpage_count = 512; + *validpage_count = 512; break; case 0x09: - *vaildpage_count = 768; + *validpage_count = 768; break; case 0x0D: - *vaildpage_count = 896; + *validpage_count = 896; break; default: /* unknown ic type clear value */ - *vaildpage_count = 0; + *validpage_count = 0; *signature_address = 0; return -ENXIO; } *signature_address = - (*vaildpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; + (*validpage_count * ETP_FW_PAGE_SIZE) - ETP_FW_SIGNATURE_SIZE; return 0; } @@ -264,7 +264,7 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = elan_get_fwinfo(data->ic_type, &data->fw_vaildpage_count, + error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count, &data->fw_signature_address); if (error) { dev_err(&data->client->dev, @@ -356,7 +356,7 @@ static int __elan_update_firmware(struct elan_tp_data *data, iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]); boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE; - for (i = boot_page_count; i < data->fw_vaildpage_count; i++) { + for (i = boot_page_count; i < data->fw_validpage_count; i++) { u16 checksum = 0; const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE]; -- GitLab From d6f5aef298b5e5bd12e5d3ef111a4d0fc727ca70 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 28 Aug 2015 17:30:46 -0700 Subject: [PATCH 5668/7006] Input: max8997_haptic - fix module alias The driver is a platform driver and not a I2C driver so its modalias should be exported with MODULE_DEVICE_TABLE(platform,...) instead of MODULE_DEVICE_TABLE(i2c,...). Also, remove the unnecessary MODULE_ALIAS("platform:max8997-haptic") now that the correct module alias is created. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/misc/max8997_haptic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/input/misc/max8997_haptic.c b/drivers/input/misc/max8997_haptic.c index d0f687281339b..a806ba3818f72 100644 --- a/drivers/input/misc/max8997_haptic.c +++ b/drivers/input/misc/max8997_haptic.c @@ -394,7 +394,7 @@ static const struct platform_device_id max8997_haptic_id[] = { { "max8997-haptic", 0 }, { }, }; -MODULE_DEVICE_TABLE(i2c, max8997_haptic_id); +MODULE_DEVICE_TABLE(platform, max8997_haptic_id); static struct platform_driver max8997_haptic_driver = { .driver = { @@ -407,7 +407,6 @@ static struct platform_driver max8997_haptic_driver = { }; module_platform_driver(max8997_haptic_driver); -MODULE_ALIAS("platform:max8997-haptic"); MODULE_AUTHOR("Donggeun Kim "); MODULE_DESCRIPTION("max8997_haptic driver"); MODULE_LICENSE("GPL"); -- GitLab From a3c874200cbcd95ed914ba84f33f571a0ef7adfa Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 20 Jul 2015 19:54:36 +0300 Subject: [PATCH 5669/7006] mlx5: Fix missing device local_dma_lkey The mlx5 driver exposes device capability IB_DEVICE_LOCAL_DMA_LKEY but does not set the the device local_dma_lkey. This breaks rpcrdma drivers. Query and set this lkey when creating the device resources. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 9 +++++++- drivers/net/ethernet/mellanox/mlx5/core/fw.c | 22 ++++++++++++++++++++ include/linux/mlx5/device.h | 11 ++++++++++ include/linux/mlx5/driver.h | 1 + 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 085c24b4b6036..5ab5bb3feb975 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1256,10 +1256,18 @@ static int create_dev_resources(struct mlx5_ib_resources *devr) struct ib_srq_init_attr attr; struct mlx5_ib_dev *dev; struct ib_cq_init_attr cq_attr = {.cqe = 1}; + u32 rsvd_lkey; int ret = 0; dev = container_of(devr, struct mlx5_ib_dev, devr); + ret = mlx5_core_query_special_context(dev->mdev, &rsvd_lkey); + if (ret) { + pr_err("Failed to query special context %d\n", ret); + return ret; + } + dev->ib_dev.local_dma_lkey = rsvd_lkey; + devr->p0 = mlx5_ib_alloc_pd(&dev->ib_dev, NULL, NULL); if (IS_ERR(devr->p0)) { ret = PTR_ERR(devr->p0); @@ -1421,7 +1429,6 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) strlcpy(dev->ib_dev.name, "mlx5_%d", IB_DEVICE_NAME_MAX); dev->ib_dev.owner = THIS_MODULE; dev->ib_dev.node_type = RDMA_NODE_IB_CA; - dev->ib_dev.local_dma_lkey = 0 /* not supported for now */; dev->num_ports = MLX5_CAP_GEN(mdev, num_ports); dev->ib_dev.phys_port_cnt = dev->num_ports; dev->ib_dev.num_comp_vectors = diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fw.c b/drivers/net/ethernet/mellanox/mlx5/core/fw.c index 9335e5ae18cce..aa0d5ffe92d81 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fw.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fw.c @@ -200,3 +200,25 @@ int mlx5_cmd_teardown_hca(struct mlx5_core_dev *dev) return err; } + +int mlx5_core_query_special_context(struct mlx5_core_dev *dev, u32 *rsvd_lkey) +{ + struct mlx5_cmd_query_special_contexts_mbox_in in; + struct mlx5_cmd_query_special_contexts_mbox_out out; + int err; + + memset(&in, 0, sizeof(in)); + memset(&out, 0, sizeof(out)); + in.hdr.opcode = cpu_to_be16(MLX5_CMD_OP_QUERY_SPECIAL_CONTEXTS); + err = mlx5_cmd_exec(dev, &in, sizeof(in), &out, sizeof(out)); + if (err) + return err; + + if (out.hdr.status) + err = mlx5_cmd_status_to_err(&out.hdr); + + *rsvd_lkey = be32_to_cpu(out.resd_lkey); + + return err; +} +EXPORT_SYMBOL(mlx5_core_query_special_context); diff --git a/include/linux/mlx5/device.h b/include/linux/mlx5/device.h index b943cd9e20973..6e4169c5ad781 100644 --- a/include/linux/mlx5/device.h +++ b/include/linux/mlx5/device.h @@ -402,6 +402,17 @@ struct mlx5_cmd_teardown_hca_mbox_out { u8 rsvd[8]; }; +struct mlx5_cmd_query_special_contexts_mbox_in { + struct mlx5_inbox_hdr hdr; + u8 rsvd[8]; +}; + +struct mlx5_cmd_query_special_contexts_mbox_out { + struct mlx5_outbox_hdr hdr; + __be32 dump_fill_mkey; + __be32 resd_lkey; +}; + struct mlx5_cmd_layout { u8 type; u8 rsvd0[3]; diff --git a/include/linux/mlx5/driver.h b/include/linux/mlx5/driver.h index 5722d88c24290..1e2e48ccb3fdc 100644 --- a/include/linux/mlx5/driver.h +++ b/include/linux/mlx5/driver.h @@ -828,6 +828,7 @@ void *mlx5_get_protocol_dev(struct mlx5_core_dev *mdev, int protocol); int mlx5_register_interface(struct mlx5_interface *intf); void mlx5_unregister_interface(struct mlx5_interface *intf); int mlx5_core_query_vendor_id(struct mlx5_core_dev *mdev, u32 *vendor_id); +int mlx5_core_query_special_context(struct mlx5_core_dev *dev, u32 *rsvd_lkey); struct mlx5_profile { u64 mask; -- GitLab From e0238a6a369eaa2e41b2c0321453272fb859f618 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Tue, 21 Jul 2015 14:40:12 +0300 Subject: [PATCH 5670/7006] mlx5: Expose correct page_size_cap in device attributes Should be all the page sizes that are supported by the device. Reported-by: Jason Gunthorpe Signed-off-by: Sagi Grimberg Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 5ab5bb3feb975..1ece3a7debd59 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -212,6 +212,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, int err = -ENOMEM; int max_rq_sg; int max_sq_sg; + u64 min_page_size = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz); if (uhw->inlen || uhw->outlen) return -EINVAL; @@ -264,7 +265,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->hw_ver = mdev->pdev->revision; props->max_mr_size = ~0ull; - props->page_size_cap = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz); + props->page_size_cap = ~(min_page_size - 1); props->max_qp = 1 << MLX5_CAP_GEN(mdev, log_max_qp); props->max_qp_wr = 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz); max_rq_sg = MLX5_CAP_GEN(mdev, max_wqe_sz_rq) / -- GitLab From d6f1c17e162b2a11e708f28fa93f2f79c164b442 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Tue, 21 Jul 2015 08:36:07 -0400 Subject: [PATCH 5671/7006] IB/qib: Change lkey table allocation to support more MRs The lkey table is allocated with with a get_user_pages() with an order based on a number of index bits from a module parameter. The underlying kernel code cannot allocate that many contiguous pages. There is no reason the underlying memory needs to be physically contiguous. This patch: - switches the allocation/deallocation to vmalloc/vfree - caps the number of bits to 23 to insure at least 1 generation bit o this matches the module parameter description Cc: stable@vger.kernel.org Reviewed-by: Vinit Agnihotri Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_keys.c | 4 ++++ drivers/infiniband/hw/qib/qib_verbs.c | 14 ++++++++++---- drivers/infiniband/hw/qib/qib_verbs.h | 2 ++ 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c index ad843c786e721..5afaa218508d2 100644 --- a/drivers/infiniband/hw/qib/qib_keys.c +++ b/drivers/infiniband/hw/qib/qib_keys.c @@ -86,6 +86,10 @@ int qib_alloc_lkey(struct qib_mregion *mr, int dma_region) * unrestricted LKEY. */ rkt->gen++; + /* + * bits are capped in qib_verbs.c to insure enough bits + * for generation number + */ mr->lkey = (r << (32 - ib_qib_lkey_table_size)) | ((((1 << (24 - ib_qib_lkey_table_size)) - 1) & rkt->gen) << 8); diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index a05d1a372208a..77e981abfce47 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -40,6 +40,7 @@ #include #include #include +#include #include "qib.h" #include "qib_common.h" @@ -2109,10 +2110,16 @@ int qib_register_ib_device(struct qib_devdata *dd) * the LKEY). The remaining bits act as a generation number or tag. */ spin_lock_init(&dev->lk_table.lock); + /* insure generation is at least 4 bits see keys.c */ + if (ib_qib_lkey_table_size > MAX_LKEY_TABLE_BITS) { + qib_dev_warn(dd, "lkey bits %u too large, reduced to %u\n", + ib_qib_lkey_table_size, MAX_LKEY_TABLE_BITS); + ib_qib_lkey_table_size = MAX_LKEY_TABLE_BITS; + } dev->lk_table.max = 1 << ib_qib_lkey_table_size; lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); dev->lk_table.table = (struct qib_mregion __rcu **) - __get_free_pages(GFP_KERNEL, get_order(lk_tab_size)); + vmalloc(lk_tab_size); if (dev->lk_table.table == NULL) { ret = -ENOMEM; goto err_lk; @@ -2286,7 +2293,7 @@ err_tx: sizeof(struct qib_pio_header), dev->pio_hdrs, dev->pio_hdrs_phys); err_hdrs: - free_pages((unsigned long) dev->lk_table.table, get_order(lk_tab_size)); + vfree(dev->lk_table.table); err_lk: kfree(dev->qp_table); err_qpt: @@ -2340,8 +2347,7 @@ void qib_unregister_ib_device(struct qib_devdata *dd) sizeof(struct qib_pio_header), dev->pio_hdrs, dev->pio_hdrs_phys); lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); - free_pages((unsigned long) dev->lk_table.table, - get_order(lk_tab_size)); + vfree(dev->lk_table.table); kfree(dev->qp_table); } diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index 1635572752ce5..bce0fa596b4df 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -647,6 +647,8 @@ struct qib_qpn_table { struct qpn_map map[QPNMAP_ENTRIES]; }; +#define MAX_LKEY_TABLE_BITS 23 + struct qib_lkey_table { spinlock_t lock; /* protect changes in this struct */ u32 next; /* next unused index (speeds search) */ -- GitLab From d6c7276be180fbd0a30cda8fac5c82d483be47b6 Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Mon, 27 Jul 2015 14:43:23 -0700 Subject: [PATCH 5672/7006] IB/mlx5: Remove dead code from alloc_cached_mr() The only place that assigns mr inside the loop already does a break. So "if (mr)" will never be true here since the function initializes mr to NULL at the top. We can just drop the extra if and break here. Signed-off-by: Roland Dreier Acked-by: Eli Cohen Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mr.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index bc9a0de897cb4..10d2b213a4d85 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -441,9 +441,6 @@ static struct mlx5_ib_mr *alloc_cached_mr(struct mlx5_ib_dev *dev, int order) spin_unlock_irq(&ent->lock); queue_work(cache->wq, &ent->work); - - if (mr) - break; } if (!mr) -- GitLab From 7854550ae6d89bb90980b9885c7a71e471820bf2 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Tue, 28 Jul 2015 09:13:52 -0500 Subject: [PATCH 5673/7006] RDMA/iser: Limit sgs to the device fastreg depth Currently the sg tablesize, which dictates fast register page list depth to use, does not take into account the limits of the rdma device. So adjust it once we discover the device fastreg max depth limit. Also adjust the max_sectors based on the resulting sg tablesize. Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 6a594aac22900..de8730dd97875 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -640,6 +640,15 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, SHOST_DIX_GUARD_CRC); } + /* + * Limit the sg_tablesize and max_sectors based on the device + * max fastreg page list length. + */ + shost->sg_tablesize = min_t(unsigned short, shost->sg_tablesize, + ib_conn->device->dev_attr.max_fast_reg_page_list_len); + shost->max_sectors = min_t(unsigned int, + 1024, (shost->sg_tablesize * PAGE_SIZE) >> 9); + if (iscsi_host_add(shost, ib_conn->device->ib_device->dma_device)) { mutex_unlock(&iser_conn->state_mutex); -- GitLab From b8ac3112462900a55a45df8e6098c67a139d8c2d Mon Sep 17 00:00:00 2001 From: Hariprasad S Date: Mon, 27 Jul 2015 14:08:52 +0530 Subject: [PATCH 5674/7006] iw_cxgb4: set the default MPA version to 2 This enables ORD/IRD negotiation and its about time to enable it by default Signed-off-by: Steve Wise Signed-off-by: Hariprasad Shenai Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/cm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 3ad8dc798f52c..75144d90c252d 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -115,11 +115,11 @@ module_param(ep_timeout_secs, int, 0644); MODULE_PARM_DESC(ep_timeout_secs, "CM Endpoint operation timeout " "in seconds (default=60)"); -static int mpa_rev = 1; +static int mpa_rev = 2; module_param(mpa_rev, int, 0644); MODULE_PARM_DESC(mpa_rev, "MPA Revision, 0 supports amso1100, " "1 is RFC0544 spec compliant, 2 is IETF MPA Peer Connect Draft" - " compliant (default=1)"); + " compliant (default=2)"); static int markers_enabled; module_param(markers_enabled, int, 0644); -- GitLab From 7e967fd0b84a843b2475acc67a5a8df138c5f5c0 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 4 Aug 2015 17:13:32 -0600 Subject: [PATCH 5675/7006] IB/ucma: Fix theoretical user triggered use-after-free Something like this: CPU A CPU B Acked-by: Sean Hefty ======================== ================================ ucma_destroy_id() wait_for_completion() .. anything ucma_put_ctx() complete() .. continues ... ucma_leave_multicast() mutex_lock(mut) atomic_inc(ctx->ref) mutex_unlock(mut) ucma_free_ctx() ucma_cleanup_multicast() mutex_lock(mut) kfree(mc) rdma_leave_multicast(mc->ctx->cm_id,.. Fix it by latching the ref at 0. Once it goes to 0 mc and ctx cannot leave the mutex(mut) protection. The other atomic_inc in ucma_get_ctx is OK because mutex(mut) protects it from racing with ucma_destroy_id. Signed-off-by: Jason Gunthorpe Acked-by: Sean Hefty Signed-off-by: Doug Ledford --- drivers/infiniband/core/ucma.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 29b21213ea758..acac9eafdbf69 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1321,10 +1321,10 @@ static ssize_t ucma_leave_multicast(struct ucma_file *file, mc = ERR_PTR(-ENOENT); else if (mc->ctx->file != file) mc = ERR_PTR(-EINVAL); - else { + else if (!atomic_inc_not_zero(&mc->ctx->ref)) + mc = ERR_PTR(-ENXIO); + else idr_remove(&multicast_idr, mc->id); - atomic_inc(&mc->ctx->ref); - } mutex_unlock(&mut); if (IS_ERR(mc)) { -- GitLab From 6c26a77124ff94102ea59ac23a54cdad2c49e644 Mon Sep 17 00:00:00 2001 From: Spencer Baugh Date: Thu, 13 Aug 2015 12:19:10 -0700 Subject: [PATCH 5676/7006] RDMA/cma: fix IPv6 address resolution Resolving a link-local IPv6 address with an unspecified source address was broken by commit 5462eddd7a, which prevented the IPv6 stack from learning the scope id of the link-local IPv6 address, causing random failures as the IP stack chose a random link to resolve the address on. This commit 5462eddd7a made us bail out of cma_check_linklocal early if the address passed in was not an IPv6 link-local address. On the address resolution path, the address passed in is the source address; if the source address is the unspecified address, which is not link-local, we will bail out early. This is mostly correct, but if the destination address is a link-local address, then we will be following a link-local route, and we'll need to tell the IPv6 stack what the scope id of the destination address is. This used to be done by last line of cma_check_linklocal, which is skipped when bailing out early: dev_addr->bound_dev_if = sin6->sin6_scope_id; (In cma_bind_addr, the sin6_scope_id of the source address is set to the sin6_scope_id of the destination address, so this is correct) This line is required in turn for the following line, L279 of addr6_resolve, to actually inform the IPv6 stack of the scope id: fl6.flowi6_oif = addr->bound_dev_if; Since we can only know we are in this failure case when we have access to both the source IPv6 address and destination IPv6 address, we have to deal with this further up the stack. So detect this failure case in cma_bind_addr, and set bound_dev_if to the destination address scope id to correct it. Signed-off-by: Spencer Baugh Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 143ded2bbe7c7..4e72e4c16cfe7 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -2203,8 +2203,11 @@ static int cma_bind_addr(struct rdma_cm_id *id, struct sockaddr *src_addr, src_addr = (struct sockaddr *) &id->route.addr.src_addr; src_addr->sa_family = dst_addr->sa_family; if (dst_addr->sa_family == AF_INET6) { - ((struct sockaddr_in6 *) src_addr)->sin6_scope_id = - ((struct sockaddr_in6 *) dst_addr)->sin6_scope_id; + struct sockaddr_in6 *src_addr6 = (struct sockaddr_in6 *) src_addr; + struct sockaddr_in6 *dst_addr6 = (struct sockaddr_in6 *) dst_addr; + src_addr6->sin6_scope_id = dst_addr6->sin6_scope_id; + if (ipv6_addr_type(&dst_addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + id->route.addr.dev_addr.bound_dev_if = dst_addr6->sin6_scope_id; } else if (dst_addr->sa_family == AF_IB) { ((struct sockaddr_ib *) src_addr)->sib_pkey = ((struct sockaddr_ib *) dst_addr)->sib_pkey; -- GitLab From 84cc6ac62d4386f5b6d9ccf2900686b5648e230f Mon Sep 17 00:00:00 2001 From: Hariprasad S Date: Tue, 25 Aug 2015 14:08:23 +0530 Subject: [PATCH 5677/7006] iw_cxgb4: Add support for clip Add support for ipv6 address handling clip api provided by lld Signed-off-by: Hariprasad Shenai Acked-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/cm.c | 76 ++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index 75144d90c252d..f0c1512c45cdb 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -50,6 +50,7 @@ #include #include "iw_cxgb4.h" +#include "clip_tbl.h" static char *states[] = { "idle", @@ -298,6 +299,16 @@ void _c4iw_free_ep(struct kref *kref) if (test_bit(QP_REFERENCED, &ep->com.flags)) deref_qp(ep); if (test_bit(RELEASE_RESOURCES, &ep->com.flags)) { + if (ep->com.remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *) + &ep->com.mapped_local_addr; + + cxgb4_clip_release( + ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, + 1); + } remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid); cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); dst_release(ep->dst); @@ -442,6 +453,12 @@ static void act_open_req_arp_failure(void *handle, struct sk_buff *skb) kfree_skb(skb); connect_reply_upcall(ep, -EHOSTUNREACH); state_set(&ep->com, DEAD); + if (ep->com.remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, 1); + } remove_handle(ep->com.dev, &ep->com.dev->atid_idr, ep->atid); cxgb4_free_atid(ep->com.dev->rdev.lldi.tids, ep->atid); dst_release(ep->dst); @@ -640,6 +657,7 @@ static int send_connect(struct c4iw_ep *ep) struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *) &ep->com.mapped_remote_addr; int win; + int ret; wrlen = (ep->com.remote_addr.ss_family == AF_INET) ? roundup(sizev4, 16) : @@ -693,6 +711,11 @@ static int send_connect(struct c4iw_ep *ep) opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE); opt2 |= T5_ISS_F; } + + if (ep->com.remote_addr.ss_family == AF_INET6) + cxgb4_clip_get(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&la6->sin6_addr.s6_addr, 1); + t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure); if (is_t4(ep->com.dev->rdev.lldi.adapter_type)) { @@ -790,7 +813,11 @@ static int send_connect(struct c4iw_ep *ep) } set_bit(ACT_OPEN_REQ, &ep->com.history); - return c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t); + ret = c4iw_l2t_send(&ep->com.dev->rdev, skb, ep->l2t); + if (ret && ep->com.remote_addr.ss_family == AF_INET6) + cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&la6->sin6_addr.s6_addr, 1); + return ret; } static void send_mpa_req(struct c4iw_ep *ep, struct sk_buff *skb, @@ -2091,6 +2118,15 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) case CPL_ERR_CONN_EXIST: if (ep->retry_count++ < ACT_OPEN_RETRY_COUNT) { set_bit(ACT_RETRY_INUSE, &ep->com.history); + if (ep->com.remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *) + &ep->com.mapped_local_addr; + cxgb4_clip_release( + ep->com.dev->rdev.lldi.ports[0], + (const u32 *) + &sin6->sin6_addr.s6_addr, 1); + } remove_handle(ep->com.dev, &ep->com.dev->atid_idr, atid); cxgb4_free_atid(t, atid); @@ -2118,6 +2154,12 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb) connect_reply_upcall(ep, status2errno(status)); state_set(&ep->com, DEAD); + if (ep->com.remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, 1); + } if (status && act_open_has_tid(status)) cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, GET_TID(rpl)); @@ -2302,6 +2344,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) struct dst_entry *dst; __u8 local_ip[16], peer_ip[16]; __be16 local_port, peer_port; + struct sockaddr_in6 *sin6; int err; u16 peer_mss = ntohs(req->tcpopt.mss); int iptype; @@ -2400,9 +2443,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) sin->sin_port = peer_port; sin->sin_addr.s_addr = *(__be32 *)peer_ip; } else { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) - &child_ep->com.mapped_local_addr; - + sin6 = (struct sockaddr_in6 *)&child_ep->com.mapped_local_addr; sin6->sin6_family = PF_INET6; sin6->sin6_port = local_port; memcpy(sin6->sin6_addr.s6_addr, local_ip, 16); @@ -2436,6 +2477,11 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb) insert_handle(dev, &dev->hwtid_idr, child_ep, child_ep->hwtid); accept_cr(child_ep, skb, req); set_bit(PASS_ACCEPT_REQ, &child_ep->com.history); + if (iptype == 6) { + sin6 = (struct sockaddr_in6 *)&child_ep->com.mapped_local_addr; + cxgb4_clip_get(child_ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, 1); + } goto out; reject: reject_cr(dev, hwtid, skb); @@ -2672,6 +2718,15 @@ out: if (release) release_ep_resources(ep); else if (ep->retry_with_mpa_v1) { + if (ep->com.remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *) + &ep->com.mapped_local_addr; + cxgb4_clip_release( + ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, + 1); + } remove_handle(ep->com.dev, &ep->com.dev->hwtid_idr, ep->hwtid); cxgb4_remove_tid(ep->com.dev->rdev.lldi.tids, 0, ep->hwtid); dst_release(ep->dst); @@ -3186,6 +3241,9 @@ static int create_server6(struct c4iw_dev *dev, struct c4iw_listen_ep *ep) pr_err("cxgb4_create_server6/filter failed err %d stid %d laddr %pI6 lport %d\n", err, ep->stid, sin6->sin6_addr.s6_addr, ntohs(sin6->sin6_port)); + else + cxgb4_clip_get(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, 1); return err; } @@ -3334,6 +3392,7 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id) ep->com.dev->rdev.lldi.ports[0], ep->stid, ep->com.dev->rdev.lldi.rxq_ids[0], 0); } else { + struct sockaddr_in6 *sin6; c4iw_init_wr_wait(&ep->com.wr_wait); err = cxgb4_remove_server( ep->com.dev->rdev.lldi.ports[0], ep->stid, @@ -3342,6 +3401,9 @@ int c4iw_destroy_listen(struct iw_cm_id *cm_id) goto done; err = c4iw_wait_for_reply(&ep->com.dev->rdev, &ep->com.wr_wait, 0, 0, __func__); + sin6 = (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, 1); } remove_handle(ep->com.dev, &ep->com.dev->stid_idr, ep->stid); cxgb4_free_stid(ep->com.dev->rdev.lldi.tids, ep->stid, @@ -3461,6 +3523,12 @@ static void active_ofld_conn_reply(struct c4iw_dev *dev, struct sk_buff *skb, mutex_unlock(&dev->rdev.stats.lock); connect_reply_upcall(ep, status2errno(req->retval)); state_set(&ep->com, DEAD); + if (ep->com.remote_addr.ss_family == AF_INET6) { + struct sockaddr_in6 *sin6 = + (struct sockaddr_in6 *)&ep->com.mapped_local_addr; + cxgb4_clip_release(ep->com.dev->rdev.lldi.ports[0], + (const u32 *)&sin6->sin6_addr.s6_addr, 1); + } remove_handle(dev, &dev->atid_idr, atid); cxgb4_free_atid(dev->rdev.lldi.tids, atid); dst_release(ep->dst); -- GitLab From 2dfcad3adea961916f013387889bc418c65421cd Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Thu, 27 Aug 2015 14:18:57 -0400 Subject: [PATCH 5678/7006] Staging: Add staging/rdma directory and update MAINTAINERS Create the rdma directory in the staging area for use as we deprecate some older drivers and as we bring in some new drivers that are in need of work. Update the MAINTAINERS file so that updates to these files go to linux-rdma@vger.kernel.org. Expected lifespan of this directory is three releases for any deprecated drivers moved here and an unknown, but theoretically bounded amount of time for the new drivers as a new core RDMA transfer library needs to be written and the drivers modified to use it in order for them to move out of this directory. Signed-off-by: Doug Ledford --- MAINTAINERS | 1 + drivers/staging/Kconfig | 2 ++ drivers/staging/Makefile | 1 + drivers/staging/rdma/Kconfig | 25 +++++++++++++++++++++++++ drivers/staging/rdma/Makefile | 1 + 5 files changed, 30 insertions(+) create mode 100644 drivers/staging/rdma/Kconfig create mode 100644 drivers/staging/rdma/Makefile diff --git a/MAINTAINERS b/MAINTAINERS index 569568f6644f2..a82aa07366d14 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5278,6 +5278,7 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/dledford/rdma.git S: Supported F: Documentation/infiniband/ F: drivers/infiniband/ +F: drivers/staging/rdma/ F: include/uapi/linux/if_infiniband.h F: include/uapi/rdma/ F: include/rdma/ diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 7f6cae5beb90f..936016f74afec 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -74,6 +74,8 @@ source "drivers/staging/nvec/Kconfig" source "drivers/staging/media/Kconfig" +source "drivers/staging/rdma/Kconfig" + source "drivers/staging/android/Kconfig" source "drivers/staging/board/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 347f6477aa3eb..c6c44545b94a5 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_FT1000) += ft1000/ obj-$(CONFIG_SPEAKUP) += speakup/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/ obj-$(CONFIG_MFD_NVEC) += nvec/ +obj-$(CONFIG_STAGING_RDMA) += rdma/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_STAGING_BOARD) += board/ obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/ diff --git a/drivers/staging/rdma/Kconfig b/drivers/staging/rdma/Kconfig new file mode 100644 index 0000000000000..0bff438ada6f3 --- /dev/null +++ b/drivers/staging/rdma/Kconfig @@ -0,0 +1,25 @@ +menuconfig STAGING_RDMA + bool "RDMA staging drivers" + depends on INFINIBAND + depends on PCI || BROKEN + depends on HAS_IOMEM + depends on NET + depends on INET + default n + ---help--- + This option allows you to select a number of RDMA drivers that + fall into one of two categories: deprecated drivers being held + here before finally being removed or new drivers that still need + some work before being moved to the normal RDMA driver area. + + If you wish to work on these drivers, to help improve them, or + to report problems you have with them, please use the + linux-rdma@vger.kernel.org mailing list. + + If in doubt, say N here. + + +# Please keep entries in alphabetic order +if STAGING_RDMA + +endif diff --git a/drivers/staging/rdma/Makefile b/drivers/staging/rdma/Makefile new file mode 100644 index 0000000000000..b5e94f1691019 --- /dev/null +++ b/drivers/staging/rdma/Makefile @@ -0,0 +1 @@ +# Entries for RDMA_STAGING tree -- GitLab From 6f9b38903c06c159d167344821cd7b4bae864380 Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Thu, 30 Jul 2015 09:25:42 -0400 Subject: [PATCH 5679/7006] IB/ipath: Deprecate ipath driver and move to staging. It is now time for the ipath driver to begin to be phased out of the kernel. This patch moves the ipath driver from the Infiniband sub tree to the staging area where it will remain until the code is removed from the kernel in a few releases. Reviewed-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- MAINTAINERS | 2 +- drivers/infiniband/Kconfig | 1 - drivers/infiniband/hw/Makefile | 1 - drivers/staging/rdma/Kconfig | 2 ++ drivers/staging/rdma/Makefile | 1 + drivers/{infiniband/hw => staging/rdma}/ipath/Kconfig | 4 +++- drivers/{infiniband/hw => staging/rdma}/ipath/Makefile | 0 drivers/staging/rdma/ipath/TODO | 5 +++++ drivers/{infiniband/hw => staging/rdma}/ipath/ipath_common.h | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_cq.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_debug.h | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_diag.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_dma.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_driver.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_eeprom.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_file_ops.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_fs.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_iba6110.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_init_chip.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_intr.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_kernel.h | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_keys.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_mad.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_mmap.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_mr.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_qp.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_rc.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_registers.h | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_ruc.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_sdma.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_srq.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_stats.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_sysfs.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_uc.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_ud.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_user_pages.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_user_sdma.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_user_sdma.h | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_verbs.c | 0 drivers/{infiniband/hw => staging/rdma}/ipath/ipath_verbs.h | 0 .../hw => staging/rdma}/ipath/ipath_verbs_mcast.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_wc_ppc64.c | 0 .../{infiniband/hw => staging/rdma}/ipath/ipath_wc_x86_64.c | 0 43 files changed, 12 insertions(+), 4 deletions(-) rename drivers/{infiniband/hw => staging/rdma}/ipath/Kconfig (81%) rename drivers/{infiniband/hw => staging/rdma}/ipath/Makefile (100%) create mode 100644 drivers/staging/rdma/ipath/TODO rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_common.h (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_cq.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_debug.h (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_diag.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_dma.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_driver.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_eeprom.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_file_ops.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_fs.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_iba6110.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_init_chip.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_intr.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_kernel.h (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_keys.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_mad.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_mmap.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_mr.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_qp.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_rc.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_registers.h (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_ruc.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_sdma.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_srq.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_stats.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_sysfs.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_uc.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_ud.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_user_pages.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_user_sdma.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_user_sdma.h (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_verbs.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_verbs.h (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_verbs_mcast.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_wc_ppc64.c (100%) rename drivers/{infiniband/hw => staging/rdma}/ipath/ipath_wc_x86_64.c (100%) diff --git a/MAINTAINERS b/MAINTAINERS index a82aa07366d14..db1a523ed4938 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5536,7 +5536,7 @@ IPATH DRIVER M: Mike Marciniszyn L: linux-rdma@vger.kernel.org S: Maintained -F: drivers/infiniband/hw/ipath/ +F: drivers/staging/rdma/ipath/ IPMI SUBSYSTEM M: Corey Minyard diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index b899531498eb0..7d6034fd456b1 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -55,7 +55,6 @@ config INFINIBAND_ADDR_TRANS default y source "drivers/infiniband/hw/mthca/Kconfig" -source "drivers/infiniband/hw/ipath/Kconfig" source "drivers/infiniband/hw/qib/Kconfig" source "drivers/infiniband/hw/ehca/Kconfig" source "drivers/infiniband/hw/amso1100/Kconfig" diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile index e900b03531a9a..d1212c441dfad 100644 --- a/drivers/infiniband/hw/Makefile +++ b/drivers/infiniband/hw/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += mthca/ -obj-$(CONFIG_INFINIBAND_IPATH) += ipath/ obj-$(CONFIG_INFINIBAND_QIB) += qib/ obj-$(CONFIG_INFINIBAND_EHCA) += ehca/ obj-$(CONFIG_INFINIBAND_AMSO1100) += amso1100/ diff --git a/drivers/staging/rdma/Kconfig b/drivers/staging/rdma/Kconfig index 0bff438ada6f3..e582553e18143 100644 --- a/drivers/staging/rdma/Kconfig +++ b/drivers/staging/rdma/Kconfig @@ -22,4 +22,6 @@ menuconfig STAGING_RDMA # Please keep entries in alphabetic order if STAGING_RDMA +source "drivers/staging/rdma/ipath/Kconfig" + endif diff --git a/drivers/staging/rdma/Makefile b/drivers/staging/rdma/Makefile index b5e94f1691019..484dac7549458 100644 --- a/drivers/staging/rdma/Makefile +++ b/drivers/staging/rdma/Makefile @@ -1 +1,2 @@ # Entries for RDMA_STAGING tree +obj-$(CONFIG_INFINIBAND_IPATH) += ipath/ diff --git a/drivers/infiniband/hw/ipath/Kconfig b/drivers/staging/rdma/ipath/Kconfig similarity index 81% rename from drivers/infiniband/hw/ipath/Kconfig rename to drivers/staging/rdma/ipath/Kconfig index 8fe54ff005808..041ce06349687 100644 --- a/drivers/infiniband/hw/ipath/Kconfig +++ b/drivers/staging/rdma/ipath/Kconfig @@ -2,7 +2,7 @@ config INFINIBAND_IPATH tristate "QLogic HTX HCA support" depends on 64BIT && NET && HT_IRQ ---help--- - This is a driver for the obsolete QLogic Hyper-Transport + This is a driver for the deprecated QLogic Hyper-Transport IB host channel adapter (model QHT7140), including InfiniBand verbs support. This driver allows these devices to be used with both kernel upper level protocols such @@ -12,3 +12,5 @@ config INFINIBAND_IPATH If you have this hardware you will need to boot with PAT disabled on your x86-64 systems, use the nopat kernel parameter. + + Note that this driver will soon be removed entirely from the kernel. diff --git a/drivers/infiniband/hw/ipath/Makefile b/drivers/staging/rdma/ipath/Makefile similarity index 100% rename from drivers/infiniband/hw/ipath/Makefile rename to drivers/staging/rdma/ipath/Makefile diff --git a/drivers/staging/rdma/ipath/TODO b/drivers/staging/rdma/ipath/TODO new file mode 100644 index 0000000000000..cb00158d64c85 --- /dev/null +++ b/drivers/staging/rdma/ipath/TODO @@ -0,0 +1,5 @@ +The ipath driver has been moved to staging in preparation for its removal in a +few releases. The driver will be deleted during the 4.6 merge window. + +Contact Dennis Dalessandro and +Cc: linux-rdma@vger.kernel.org diff --git a/drivers/infiniband/hw/ipath/ipath_common.h b/drivers/staging/rdma/ipath/ipath_common.h similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_common.h rename to drivers/staging/rdma/ipath/ipath_common.h diff --git a/drivers/infiniband/hw/ipath/ipath_cq.c b/drivers/staging/rdma/ipath/ipath_cq.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_cq.c rename to drivers/staging/rdma/ipath/ipath_cq.c diff --git a/drivers/infiniband/hw/ipath/ipath_debug.h b/drivers/staging/rdma/ipath/ipath_debug.h similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_debug.h rename to drivers/staging/rdma/ipath/ipath_debug.h diff --git a/drivers/infiniband/hw/ipath/ipath_diag.c b/drivers/staging/rdma/ipath/ipath_diag.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_diag.c rename to drivers/staging/rdma/ipath/ipath_diag.c diff --git a/drivers/infiniband/hw/ipath/ipath_dma.c b/drivers/staging/rdma/ipath/ipath_dma.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_dma.c rename to drivers/staging/rdma/ipath/ipath_dma.c diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/staging/rdma/ipath/ipath_driver.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_driver.c rename to drivers/staging/rdma/ipath/ipath_driver.c diff --git a/drivers/infiniband/hw/ipath/ipath_eeprom.c b/drivers/staging/rdma/ipath/ipath_eeprom.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_eeprom.c rename to drivers/staging/rdma/ipath/ipath_eeprom.c diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/staging/rdma/ipath/ipath_file_ops.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_file_ops.c rename to drivers/staging/rdma/ipath/ipath_file_ops.c diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/staging/rdma/ipath/ipath_fs.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_fs.c rename to drivers/staging/rdma/ipath/ipath_fs.c diff --git a/drivers/infiniband/hw/ipath/ipath_iba6110.c b/drivers/staging/rdma/ipath/ipath_iba6110.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_iba6110.c rename to drivers/staging/rdma/ipath/ipath_iba6110.c diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/staging/rdma/ipath/ipath_init_chip.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_init_chip.c rename to drivers/staging/rdma/ipath/ipath_init_chip.c diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/staging/rdma/ipath/ipath_intr.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_intr.c rename to drivers/staging/rdma/ipath/ipath_intr.c diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/staging/rdma/ipath/ipath_kernel.h similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_kernel.h rename to drivers/staging/rdma/ipath/ipath_kernel.h diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/staging/rdma/ipath/ipath_keys.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_keys.c rename to drivers/staging/rdma/ipath/ipath_keys.c diff --git a/drivers/infiniband/hw/ipath/ipath_mad.c b/drivers/staging/rdma/ipath/ipath_mad.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_mad.c rename to drivers/staging/rdma/ipath/ipath_mad.c diff --git a/drivers/infiniband/hw/ipath/ipath_mmap.c b/drivers/staging/rdma/ipath/ipath_mmap.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_mmap.c rename to drivers/staging/rdma/ipath/ipath_mmap.c diff --git a/drivers/infiniband/hw/ipath/ipath_mr.c b/drivers/staging/rdma/ipath/ipath_mr.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_mr.c rename to drivers/staging/rdma/ipath/ipath_mr.c diff --git a/drivers/infiniband/hw/ipath/ipath_qp.c b/drivers/staging/rdma/ipath/ipath_qp.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_qp.c rename to drivers/staging/rdma/ipath/ipath_qp.c diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/staging/rdma/ipath/ipath_rc.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_rc.c rename to drivers/staging/rdma/ipath/ipath_rc.c diff --git a/drivers/infiniband/hw/ipath/ipath_registers.h b/drivers/staging/rdma/ipath/ipath_registers.h similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_registers.h rename to drivers/staging/rdma/ipath/ipath_registers.h diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/staging/rdma/ipath/ipath_ruc.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_ruc.c rename to drivers/staging/rdma/ipath/ipath_ruc.c diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/staging/rdma/ipath/ipath_sdma.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_sdma.c rename to drivers/staging/rdma/ipath/ipath_sdma.c diff --git a/drivers/infiniband/hw/ipath/ipath_srq.c b/drivers/staging/rdma/ipath/ipath_srq.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_srq.c rename to drivers/staging/rdma/ipath/ipath_srq.c diff --git a/drivers/infiniband/hw/ipath/ipath_stats.c b/drivers/staging/rdma/ipath/ipath_stats.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_stats.c rename to drivers/staging/rdma/ipath/ipath_stats.c diff --git a/drivers/infiniband/hw/ipath/ipath_sysfs.c b/drivers/staging/rdma/ipath/ipath_sysfs.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_sysfs.c rename to drivers/staging/rdma/ipath/ipath_sysfs.c diff --git a/drivers/infiniband/hw/ipath/ipath_uc.c b/drivers/staging/rdma/ipath/ipath_uc.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_uc.c rename to drivers/staging/rdma/ipath/ipath_uc.c diff --git a/drivers/infiniband/hw/ipath/ipath_ud.c b/drivers/staging/rdma/ipath/ipath_ud.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_ud.c rename to drivers/staging/rdma/ipath/ipath_ud.c diff --git a/drivers/infiniband/hw/ipath/ipath_user_pages.c b/drivers/staging/rdma/ipath/ipath_user_pages.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_user_pages.c rename to drivers/staging/rdma/ipath/ipath_user_pages.c diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.c b/drivers/staging/rdma/ipath/ipath_user_sdma.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_user_sdma.c rename to drivers/staging/rdma/ipath/ipath_user_sdma.c diff --git a/drivers/infiniband/hw/ipath/ipath_user_sdma.h b/drivers/staging/rdma/ipath/ipath_user_sdma.h similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_user_sdma.h rename to drivers/staging/rdma/ipath/ipath_user_sdma.h diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/staging/rdma/ipath/ipath_verbs.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_verbs.c rename to drivers/staging/rdma/ipath/ipath_verbs.c diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.h b/drivers/staging/rdma/ipath/ipath_verbs.h similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_verbs.h rename to drivers/staging/rdma/ipath/ipath_verbs.h diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/staging/rdma/ipath/ipath_verbs_mcast.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_verbs_mcast.c rename to drivers/staging/rdma/ipath/ipath_verbs_mcast.c diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/staging/rdma/ipath/ipath_wc_ppc64.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_wc_ppc64.c rename to drivers/staging/rdma/ipath/ipath_wc_ppc64.c diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/staging/rdma/ipath/ipath_wc_x86_64.c similarity index 100% rename from drivers/infiniband/hw/ipath/ipath_wc_x86_64.c rename to drivers/staging/rdma/ipath/ipath_wc_x86_64.c -- GitLab From 072bf1f7e4b5963034df35460f5f311396347a36 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 29 Jul 2015 09:44:14 -0500 Subject: [PATCH 5680/7006] RDMA/amso1100: Deprecate the amso1100 driver and move to staging The HW hasn't been sold since 2005, and the SW has definite bit rot. Its time to remove it. So move it to staging for a few releases and then remove it after that. Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/Kconfig | 1 - drivers/infiniband/hw/Makefile | 1 - drivers/staging/rdma/Kconfig | 2 ++ drivers/staging/rdma/Makefile | 1 + drivers/{infiniband/hw => staging/rdma}/amso1100/Kbuild | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/Kconfig | 0 drivers/staging/rdma/amso1100/TODO | 4 ++++ drivers/{infiniband/hw => staging/rdma}/amso1100/c2.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_ae.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_ae.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_alloc.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_cm.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_cq.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_intr.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_mm.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_mq.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_mq.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_pd.c | 0 .../{infiniband/hw => staging/rdma}/amso1100/c2_provider.c | 0 .../{infiniband/hw => staging/rdma}/amso1100/c2_provider.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_qp.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_rnic.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_status.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_user.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_vq.c | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_vq.h | 0 drivers/{infiniband/hw => staging/rdma}/amso1100/c2_wr.h | 0 28 files changed, 7 insertions(+), 2 deletions(-) rename drivers/{infiniband/hw => staging/rdma}/amso1100/Kbuild (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/Kconfig (100%) create mode 100644 drivers/staging/rdma/amso1100/TODO rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_ae.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_ae.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_alloc.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_cm.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_cq.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_intr.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_mm.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_mq.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_mq.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_pd.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_provider.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_provider.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_qp.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_rnic.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_status.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_user.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_vq.c (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_vq.h (100%) rename drivers/{infiniband/hw => staging/rdma}/amso1100/c2_wr.h (100%) diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index 7d6034fd456b1..da4c6979fbb8e 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -57,7 +57,6 @@ config INFINIBAND_ADDR_TRANS source "drivers/infiniband/hw/mthca/Kconfig" source "drivers/infiniband/hw/qib/Kconfig" source "drivers/infiniband/hw/ehca/Kconfig" -source "drivers/infiniband/hw/amso1100/Kconfig" source "drivers/infiniband/hw/cxgb3/Kconfig" source "drivers/infiniband/hw/cxgb4/Kconfig" source "drivers/infiniband/hw/mlx4/Kconfig" diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile index d1212c441dfad..1bdb9996d371b 100644 --- a/drivers/infiniband/hw/Makefile +++ b/drivers/infiniband/hw/Makefile @@ -1,7 +1,6 @@ obj-$(CONFIG_INFINIBAND_MTHCA) += mthca/ obj-$(CONFIG_INFINIBAND_QIB) += qib/ obj-$(CONFIG_INFINIBAND_EHCA) += ehca/ -obj-$(CONFIG_INFINIBAND_AMSO1100) += amso1100/ obj-$(CONFIG_INFINIBAND_CXGB3) += cxgb3/ obj-$(CONFIG_INFINIBAND_CXGB4) += cxgb4/ obj-$(CONFIG_MLX4_INFINIBAND) += mlx4/ diff --git a/drivers/staging/rdma/Kconfig b/drivers/staging/rdma/Kconfig index e582553e18143..5084088c89468 100644 --- a/drivers/staging/rdma/Kconfig +++ b/drivers/staging/rdma/Kconfig @@ -22,6 +22,8 @@ menuconfig STAGING_RDMA # Please keep entries in alphabetic order if STAGING_RDMA +source "drivers/staging/rdma/amso1100/Kconfig" + source "drivers/staging/rdma/ipath/Kconfig" endif diff --git a/drivers/staging/rdma/Makefile b/drivers/staging/rdma/Makefile index 484dac7549458..a2a459ac8d673 100644 --- a/drivers/staging/rdma/Makefile +++ b/drivers/staging/rdma/Makefile @@ -1,2 +1,3 @@ # Entries for RDMA_STAGING tree +obj-$(CONFIG_INFINIBAND_AMSO1100) += amso1100/ obj-$(CONFIG_INFINIBAND_IPATH) += ipath/ diff --git a/drivers/infiniband/hw/amso1100/Kbuild b/drivers/staging/rdma/amso1100/Kbuild similarity index 100% rename from drivers/infiniband/hw/amso1100/Kbuild rename to drivers/staging/rdma/amso1100/Kbuild diff --git a/drivers/infiniband/hw/amso1100/Kconfig b/drivers/staging/rdma/amso1100/Kconfig similarity index 100% rename from drivers/infiniband/hw/amso1100/Kconfig rename to drivers/staging/rdma/amso1100/Kconfig diff --git a/drivers/staging/rdma/amso1100/TODO b/drivers/staging/rdma/amso1100/TODO new file mode 100644 index 0000000000000..18b00a5cb5494 --- /dev/null +++ b/drivers/staging/rdma/amso1100/TODO @@ -0,0 +1,4 @@ +7/2015 + +The amso1100 driver has been deprecated and moved to drivers/staging. +It will be removed in the 4.6 merge window. diff --git a/drivers/infiniband/hw/amso1100/c2.c b/drivers/staging/rdma/amso1100/c2.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2.c rename to drivers/staging/rdma/amso1100/c2.c diff --git a/drivers/infiniband/hw/amso1100/c2.h b/drivers/staging/rdma/amso1100/c2.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2.h rename to drivers/staging/rdma/amso1100/c2.h diff --git a/drivers/infiniband/hw/amso1100/c2_ae.c b/drivers/staging/rdma/amso1100/c2_ae.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_ae.c rename to drivers/staging/rdma/amso1100/c2_ae.c diff --git a/drivers/infiniband/hw/amso1100/c2_ae.h b/drivers/staging/rdma/amso1100/c2_ae.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_ae.h rename to drivers/staging/rdma/amso1100/c2_ae.h diff --git a/drivers/infiniband/hw/amso1100/c2_alloc.c b/drivers/staging/rdma/amso1100/c2_alloc.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_alloc.c rename to drivers/staging/rdma/amso1100/c2_alloc.c diff --git a/drivers/infiniband/hw/amso1100/c2_cm.c b/drivers/staging/rdma/amso1100/c2_cm.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_cm.c rename to drivers/staging/rdma/amso1100/c2_cm.c diff --git a/drivers/infiniband/hw/amso1100/c2_cq.c b/drivers/staging/rdma/amso1100/c2_cq.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_cq.c rename to drivers/staging/rdma/amso1100/c2_cq.c diff --git a/drivers/infiniband/hw/amso1100/c2_intr.c b/drivers/staging/rdma/amso1100/c2_intr.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_intr.c rename to drivers/staging/rdma/amso1100/c2_intr.c diff --git a/drivers/infiniband/hw/amso1100/c2_mm.c b/drivers/staging/rdma/amso1100/c2_mm.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_mm.c rename to drivers/staging/rdma/amso1100/c2_mm.c diff --git a/drivers/infiniband/hw/amso1100/c2_mq.c b/drivers/staging/rdma/amso1100/c2_mq.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_mq.c rename to drivers/staging/rdma/amso1100/c2_mq.c diff --git a/drivers/infiniband/hw/amso1100/c2_mq.h b/drivers/staging/rdma/amso1100/c2_mq.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_mq.h rename to drivers/staging/rdma/amso1100/c2_mq.h diff --git a/drivers/infiniband/hw/amso1100/c2_pd.c b/drivers/staging/rdma/amso1100/c2_pd.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_pd.c rename to drivers/staging/rdma/amso1100/c2_pd.c diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/staging/rdma/amso1100/c2_provider.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_provider.c rename to drivers/staging/rdma/amso1100/c2_provider.c diff --git a/drivers/infiniband/hw/amso1100/c2_provider.h b/drivers/staging/rdma/amso1100/c2_provider.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_provider.h rename to drivers/staging/rdma/amso1100/c2_provider.h diff --git a/drivers/infiniband/hw/amso1100/c2_qp.c b/drivers/staging/rdma/amso1100/c2_qp.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_qp.c rename to drivers/staging/rdma/amso1100/c2_qp.c diff --git a/drivers/infiniband/hw/amso1100/c2_rnic.c b/drivers/staging/rdma/amso1100/c2_rnic.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_rnic.c rename to drivers/staging/rdma/amso1100/c2_rnic.c diff --git a/drivers/infiniband/hw/amso1100/c2_status.h b/drivers/staging/rdma/amso1100/c2_status.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_status.h rename to drivers/staging/rdma/amso1100/c2_status.h diff --git a/drivers/infiniband/hw/amso1100/c2_user.h b/drivers/staging/rdma/amso1100/c2_user.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_user.h rename to drivers/staging/rdma/amso1100/c2_user.h diff --git a/drivers/infiniband/hw/amso1100/c2_vq.c b/drivers/staging/rdma/amso1100/c2_vq.c similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_vq.c rename to drivers/staging/rdma/amso1100/c2_vq.c diff --git a/drivers/infiniband/hw/amso1100/c2_vq.h b/drivers/staging/rdma/amso1100/c2_vq.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_vq.h rename to drivers/staging/rdma/amso1100/c2_vq.h diff --git a/drivers/infiniband/hw/amso1100/c2_wr.h b/drivers/staging/rdma/amso1100/c2_wr.h similarity index 100% rename from drivers/infiniband/hw/amso1100/c2_wr.h rename to drivers/staging/rdma/amso1100/c2_wr.h -- GitLab From d4ab347005fb26f414b98b2c8d5ef6de5778c3dc Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Thu, 30 Jul 2015 15:17:32 -0400 Subject: [PATCH 5681/7006] IB/core: Add core header changes needed for OPA This patch adds the value of the CNP opcode to the existing list of enumerated opcodes in ib_pack.h Add common OPA header definitions for driver build: - opa_port_info.h - opa_smi.h - hfi1_user.h Additionally, ib_mad.h, has additional definitions that are common to ib_drivers including: - trap support - cca support The qib driver has the duplication removed in favor those in ib_mad.h Reviewed-by: Mike Marciniszyn Reviewed-by: John, Jubin Signed-off-by: Ira Weiny Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_mad.h | 147 +--------- include/rdma/ib_mad.h | 138 +++++++++ include/rdma/ib_pack.h | 2 + include/rdma/opa_port_info.h | 433 ++++++++++++++++++++++++++++ include/rdma/opa_smi.h | 47 +++ include/uapi/rdma/hfi/hfi1_user.h | 427 +++++++++++++++++++++++++++ 6 files changed, 1055 insertions(+), 139 deletions(-) create mode 100644 include/rdma/opa_port_info.h create mode 100644 include/uapi/rdma/hfi/hfi1_user.h diff --git a/drivers/infiniband/hw/qib/qib_mad.h b/drivers/infiniband/hw/qib/qib_mad.h index 941d4d50d8e74..57e99dc0d80c8 100644 --- a/drivers/infiniband/hw/qib/qib_mad.h +++ b/drivers/infiniband/hw/qib/qib_mad.h @@ -36,148 +36,17 @@ #include -#define IB_SMP_UNSUP_VERSION cpu_to_be16(0x0004) -#define IB_SMP_UNSUP_METHOD cpu_to_be16(0x0008) -#define IB_SMP_UNSUP_METH_ATTR cpu_to_be16(0x000C) -#define IB_SMP_INVALID_FIELD cpu_to_be16(0x001C) +#define IB_SMP_UNSUP_VERSION \ +cpu_to_be16(IB_MGMT_MAD_STATUS_BAD_VERSION) -struct ib_node_info { - u8 base_version; - u8 class_version; - u8 node_type; - u8 num_ports; - __be64 sys_guid; - __be64 node_guid; - __be64 port_guid; - __be16 partition_cap; - __be16 device_id; - __be32 revision; - u8 local_port_num; - u8 vendor_id[3]; -} __packed; - -struct ib_mad_notice_attr { - u8 generic_type; - u8 prod_type_msb; - __be16 prod_type_lsb; - __be16 trap_num; - __be16 issuer_lid; - __be16 toggle_count; - - union { - struct { - u8 details[54]; - } raw_data; - - struct { - __be16 reserved; - __be16 lid; /* where violation happened */ - u8 port_num; /* where violation happened */ - } __packed ntc_129_131; - - struct { - __be16 reserved; - __be16 lid; /* LID where change occurred */ - u8 reserved2; - u8 local_changes; /* low bit - local changes */ - __be32 new_cap_mask; /* new capability mask */ - u8 reserved3; - u8 change_flags; /* low 3 bits only */ - } __packed ntc_144; - - struct { - __be16 reserved; - __be16 lid; /* lid where sys guid changed */ - __be16 reserved2; - __be64 new_sys_guid; - } __packed ntc_145; - - struct { - __be16 reserved; - __be16 lid; - __be16 dr_slid; - u8 method; - u8 reserved2; - __be16 attr_id; - __be32 attr_mod; - __be64 mkey; - u8 reserved3; - u8 dr_trunc_hop; - u8 dr_rtn_path[30]; - } __packed ntc_256; - - struct { - __be16 reserved; - __be16 lid1; - __be16 lid2; - __be32 key; - __be32 sl_qp1; /* SL: high 4 bits */ - __be32 qp2; /* high 8 bits reserved */ - union ib_gid gid1; - union ib_gid gid2; - } __packed ntc_257_258; - - } details; -}; - -/* - * Generic trap/notice types - */ -#define IB_NOTICE_TYPE_FATAL 0x80 -#define IB_NOTICE_TYPE_URGENT 0x81 -#define IB_NOTICE_TYPE_SECURITY 0x82 -#define IB_NOTICE_TYPE_SM 0x83 -#define IB_NOTICE_TYPE_INFO 0x84 +#define IB_SMP_UNSUP_METHOD \ +cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD) -/* - * Generic trap/notice producers - */ -#define IB_NOTICE_PROD_CA cpu_to_be16(1) -#define IB_NOTICE_PROD_SWITCH cpu_to_be16(2) -#define IB_NOTICE_PROD_ROUTER cpu_to_be16(3) -#define IB_NOTICE_PROD_CLASS_MGR cpu_to_be16(4) +#define IB_SMP_UNSUP_METH_ATTR \ +cpu_to_be16(IB_MGMT_MAD_STATUS_UNSUPPORTED_METHOD_ATTRIB) -/* - * Generic trap/notice numbers - */ -#define IB_NOTICE_TRAP_LLI_THRESH cpu_to_be16(129) -#define IB_NOTICE_TRAP_EBO_THRESH cpu_to_be16(130) -#define IB_NOTICE_TRAP_FLOW_UPDATE cpu_to_be16(131) -#define IB_NOTICE_TRAP_CAP_MASK_CHG cpu_to_be16(144) -#define IB_NOTICE_TRAP_SYS_GUID_CHG cpu_to_be16(145) -#define IB_NOTICE_TRAP_BAD_MKEY cpu_to_be16(256) -#define IB_NOTICE_TRAP_BAD_PKEY cpu_to_be16(257) -#define IB_NOTICE_TRAP_BAD_QKEY cpu_to_be16(258) - -/* - * Repress trap/notice flags - */ -#define IB_NOTICE_REPRESS_LLI_THRESH (1 << 0) -#define IB_NOTICE_REPRESS_EBO_THRESH (1 << 1) -#define IB_NOTICE_REPRESS_FLOW_UPDATE (1 << 2) -#define IB_NOTICE_REPRESS_CAP_MASK_CHG (1 << 3) -#define IB_NOTICE_REPRESS_SYS_GUID_CHG (1 << 4) -#define IB_NOTICE_REPRESS_BAD_MKEY (1 << 5) -#define IB_NOTICE_REPRESS_BAD_PKEY (1 << 6) -#define IB_NOTICE_REPRESS_BAD_QKEY (1 << 7) - -/* - * Generic trap/notice other local changes flags (trap 144). - */ -#define IB_NOTICE_TRAP_LSE_CHG 0x04 /* Link Speed Enable changed */ -#define IB_NOTICE_TRAP_LWE_CHG 0x02 /* Link Width Enable changed */ -#define IB_NOTICE_TRAP_NODE_DESC_CHG 0x01 - -/* - * Generic trap/notice M_Key volation flags in dr_trunc_hop (trap 256). - */ -#define IB_NOTICE_TRAP_DR_NOTICE 0x80 -#define IB_NOTICE_TRAP_DR_TRUNC 0x40 - -struct ib_vl_weight_elem { - u8 vl; /* Only low 4 bits, upper 4 bits reserved */ - u8 weight; -}; +#define IB_SMP_INVALID_FIELD \ +cpu_to_be16(IB_MGMT_MAD_STATUS_INVALID_ATTRIB_VALUE) #define IB_VLARB_LOWPRI_0_31 1 #define IB_VLARB_LOWPRI_32_63 2 diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index c8422d5a5a91f..d5ac0229f5e71 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -127,6 +127,60 @@ #define IB_DEFAULT_PKEY_PARTIAL 0x7FFF #define IB_DEFAULT_PKEY_FULL 0xFFFF +/* + * Generic trap/notice types + */ +#define IB_NOTICE_TYPE_FATAL 0x80 +#define IB_NOTICE_TYPE_URGENT 0x81 +#define IB_NOTICE_TYPE_SECURITY 0x82 +#define IB_NOTICE_TYPE_SM 0x83 +#define IB_NOTICE_TYPE_INFO 0x84 + +/* + * Generic trap/notice producers + */ +#define IB_NOTICE_PROD_CA cpu_to_be16(1) +#define IB_NOTICE_PROD_SWITCH cpu_to_be16(2) +#define IB_NOTICE_PROD_ROUTER cpu_to_be16(3) +#define IB_NOTICE_PROD_CLASS_MGR cpu_to_be16(4) + +/* + * Generic trap/notice numbers + */ +#define IB_NOTICE_TRAP_LLI_THRESH cpu_to_be16(129) +#define IB_NOTICE_TRAP_EBO_THRESH cpu_to_be16(130) +#define IB_NOTICE_TRAP_FLOW_UPDATE cpu_to_be16(131) +#define IB_NOTICE_TRAP_CAP_MASK_CHG cpu_to_be16(144) +#define IB_NOTICE_TRAP_SYS_GUID_CHG cpu_to_be16(145) +#define IB_NOTICE_TRAP_BAD_MKEY cpu_to_be16(256) +#define IB_NOTICE_TRAP_BAD_PKEY cpu_to_be16(257) +#define IB_NOTICE_TRAP_BAD_QKEY cpu_to_be16(258) + +/* + * Repress trap/notice flags + */ +#define IB_NOTICE_REPRESS_LLI_THRESH (1 << 0) +#define IB_NOTICE_REPRESS_EBO_THRESH (1 << 1) +#define IB_NOTICE_REPRESS_FLOW_UPDATE (1 << 2) +#define IB_NOTICE_REPRESS_CAP_MASK_CHG (1 << 3) +#define IB_NOTICE_REPRESS_SYS_GUID_CHG (1 << 4) +#define IB_NOTICE_REPRESS_BAD_MKEY (1 << 5) +#define IB_NOTICE_REPRESS_BAD_PKEY (1 << 6) +#define IB_NOTICE_REPRESS_BAD_QKEY (1 << 7) + +/* + * Generic trap/notice other local changes flags (trap 144). + */ +#define IB_NOTICE_TRAP_LSE_CHG 0x04 /* Link Speed Enable changed */ +#define IB_NOTICE_TRAP_LWE_CHG 0x02 /* Link Width Enable changed */ +#define IB_NOTICE_TRAP_NODE_DESC_CHG 0x01 + +/* + * Generic trap/notice M_Key volation flags in dr_trunc_hop (trap 256). + */ +#define IB_NOTICE_TRAP_DR_NOTICE 0x80 +#define IB_NOTICE_TRAP_DR_TRUNC 0x40 + enum { IB_MGMT_MAD_HDR = 24, IB_MGMT_MAD_DATA = 232, @@ -240,6 +294,90 @@ struct ib_class_port_info { __be32 trap_qkey; }; +struct ib_node_info { + u8 base_version; + u8 class_version; + u8 node_type; + u8 num_ports; + __be64 sys_guid; + __be64 node_guid; + __be64 port_guid; + __be16 partition_cap; + __be16 device_id; + __be32 revision; + u8 local_port_num; + u8 vendor_id[3]; +} __packed; + +struct ib_mad_notice_attr { + u8 generic_type; + u8 prod_type_msb; + __be16 prod_type_lsb; + __be16 trap_num; + __be16 issuer_lid; + __be16 toggle_count; + + union { + struct { + u8 details[54]; + } raw_data; + + struct { + __be16 reserved; + __be16 lid; /* where violation happened */ + u8 port_num; /* where violation happened */ + } __packed ntc_129_131; + + struct { + __be16 reserved; + __be16 lid; /* LID where change occurred */ + u8 reserved2; + u8 local_changes; /* low bit - local changes */ + __be32 new_cap_mask; /* new capability mask */ + u8 reserved3; + u8 change_flags; /* low 3 bits only */ + } __packed ntc_144; + + struct { + __be16 reserved; + __be16 lid; /* lid where sys guid changed */ + __be16 reserved2; + __be64 new_sys_guid; + } __packed ntc_145; + + struct { + __be16 reserved; + __be16 lid; + __be16 dr_slid; + u8 method; + u8 reserved2; + __be16 attr_id; + __be32 attr_mod; + __be64 mkey; + u8 reserved3; + u8 dr_trunc_hop; + u8 dr_rtn_path[30]; + } __packed ntc_256; + + struct { + __be16 reserved; + __be16 lid1; + __be16 lid2; + __be32 key; + __be32 sl_qp1; /* SL: high 4 bits */ + __be32 qp2; /* high 8 bits reserved */ + union ib_gid gid1; + union ib_gid gid2; + } __packed ntc_257_258; + + } details; +}; + +struct ib_vl_weight_elem { + u8 vl; /* VL is low 5 bits, upper 3 bits reserved */ + u8 weight; +}; + /** * ib_mad_send_buf - MAD data buffer and work request for sends. * @next: A pointer used to chain together MADs for posting. diff --git a/include/rdma/ib_pack.h b/include/rdma/ib_pack.h index b1f7592e02e40..709a5331e6b9d 100644 --- a/include/rdma/ib_pack.h +++ b/include/rdma/ib_pack.h @@ -76,6 +76,8 @@ enum { IB_OPCODE_UC = 0x20, IB_OPCODE_RD = 0x40, IB_OPCODE_UD = 0x60, + /* per IBTA 3.1 Table 38, A10.3.2 */ + IB_OPCODE_CNP = 0x80, /* operations -- just used to define real constants */ IB_OPCODE_SEND_FIRST = 0x00, diff --git a/include/rdma/opa_port_info.h b/include/rdma/opa_port_info.h new file mode 100644 index 0000000000000..391dae1931c08 --- /dev/null +++ b/include/rdma/opa_port_info.h @@ -0,0 +1,433 @@ +/* + * Copyright (c) 2014 Intel Corporation. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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. + */ + +#if !defined(OPA_PORT_INFO_H) +#define OPA_PORT_INFO_H + +/* Temporary until HFI driver is updated */ +#ifndef USE_PI_LED_ENABLE +#define USE_PI_LED_ENABLE 0 +#endif + +#define OPA_PORT_LINK_MODE_NOP 0 /* No change */ +#define OPA_PORT_LINK_MODE_OPA 4 /* Port mode is OPA */ + +#define OPA_PORT_PACKET_FORMAT_NOP 0 /* No change */ +#define OPA_PORT_PACKET_FORMAT_8B 1 /* Format 8B */ +#define OPA_PORT_PACKET_FORMAT_9B 2 /* Format 9B */ +#define OPA_PORT_PACKET_FORMAT_10B 4 /* Format 10B */ +#define OPA_PORT_PACKET_FORMAT_16B 8 /* Format 16B */ + +#define OPA_PORT_LTP_CRC_MODE_NONE 0 /* No change */ +#define OPA_PORT_LTP_CRC_MODE_14 1 /* 14-bit LTP CRC mode (optional) */ +#define OPA_PORT_LTP_CRC_MODE_16 2 /* 16-bit LTP CRC mode */ +#define OPA_PORT_LTP_CRC_MODE_48 4 /* 48-bit LTP CRC mode (optional) */ +#define OPA_PORT_LTP_CRC_MODE_PER_LANE 8 /* 12/16-bit per lane LTP CRC mode */ + +/* Link Down / Neighbor Link Down Reason; indicated as follows: */ +#define OPA_LINKDOWN_REASON_NONE 0 /* No specified reason */ +#define OPA_LINKDOWN_REASON_RCV_ERROR_0 1 +#define OPA_LINKDOWN_REASON_BAD_PKT_LEN 2 +#define OPA_LINKDOWN_REASON_PKT_TOO_LONG 3 +#define OPA_LINKDOWN_REASON_PKT_TOO_SHORT 4 +#define OPA_LINKDOWN_REASON_BAD_SLID 5 +#define OPA_LINKDOWN_REASON_BAD_DLID 6 +#define OPA_LINKDOWN_REASON_BAD_L2 7 +#define OPA_LINKDOWN_REASON_BAD_SC 8 +#define OPA_LINKDOWN_REASON_RCV_ERROR_8 9 +#define OPA_LINKDOWN_REASON_BAD_MID_TAIL 10 +#define OPA_LINKDOWN_REASON_RCV_ERROR_10 11 +#define OPA_LINKDOWN_REASON_PREEMPT_ERROR 12 +#define OPA_LINKDOWN_REASON_PREEMPT_VL15 13 +#define OPA_LINKDOWN_REASON_BAD_VL_MARKER 14 +#define OPA_LINKDOWN_REASON_RCV_ERROR_14 15 +#define OPA_LINKDOWN_REASON_RCV_ERROR_15 16 +#define OPA_LINKDOWN_REASON_BAD_HEAD_DIST 17 +#define OPA_LINKDOWN_REASON_BAD_TAIL_DIST 18 +#define OPA_LINKDOWN_REASON_BAD_CTRL_DIST 19 +#define OPA_LINKDOWN_REASON_BAD_CREDIT_ACK 20 +#define OPA_LINKDOWN_REASON_UNSUPPORTED_VL_MARKER 21 +#define OPA_LINKDOWN_REASON_BAD_PREEMPT 22 +#define OPA_LINKDOWN_REASON_BAD_CONTROL_FLIT 23 +#define OPA_LINKDOWN_REASON_EXCEED_MULTICAST_LIMIT 24 +#define OPA_LINKDOWN_REASON_RCV_ERROR_24 25 +#define OPA_LINKDOWN_REASON_RCV_ERROR_25 26 +#define OPA_LINKDOWN_REASON_RCV_ERROR_26 27 +#define OPA_LINKDOWN_REASON_RCV_ERROR_27 28 +#define OPA_LINKDOWN_REASON_RCV_ERROR_28 29 +#define OPA_LINKDOWN_REASON_RCV_ERROR_29 30 +#define OPA_LINKDOWN_REASON_RCV_ERROR_30 31 +#define OPA_LINKDOWN_REASON_EXCESSIVE_BUFFER_OVERRUN 32 +#define OPA_LINKDOWN_REASON_UNKNOWN 33 +/* 34 -reserved */ +#define OPA_LINKDOWN_REASON_REBOOT 35 +#define OPA_LINKDOWN_REASON_NEIGHBOR_UNKNOWN 36 +/* 37-38 reserved */ +#define OPA_LINKDOWN_REASON_FM_BOUNCE 39 +#define OPA_LINKDOWN_REASON_SPEED_POLICY 40 +#define OPA_LINKDOWN_REASON_WIDTH_POLICY 41 +/* 42-48 reserved */ +#define OPA_LINKDOWN_REASON_DISCONNECTED 49 +#define OPA_LINKDOWN_REASONLOCAL_MEDIA_NOT_INSTALLED 50 +#define OPA_LINKDOWN_REASON_NOT_INSTALLED 51 +#define OPA_LINKDOWN_REASON_CHASSIS_CONFIG 52 +/* 53 reserved */ +#define OPA_LINKDOWN_REASON_END_TO_END_NOT_INSTALLED 54 +/* 55 reserved */ +#define OPA_LINKDOWN_REASON_POWER_POLICY 56 +#define OPA_LINKDOWN_REASON_LINKSPEED_POLICY 57 +#define OPA_LINKDOWN_REASON_LINKWIDTH_POLICY 58 +/* 59 reserved */ +#define OPA_LINKDOWN_REASON_SWITCH_MGMT 60 +#define OPA_LINKDOWN_REASON_SMA_DISABLED 61 +/* 62 reserved */ +#define OPA_LINKDOWN_REASON_TRANSIENT 63 +/* 64-255 reserved */ + +/* OPA Link Init reason; indicated as follows: */ +/* 3-7; 11-15 reserved; 8-15 cleared on Polling->LinkUp */ +#define OPA_LINKINIT_REASON_NOP 0 +#define OPA_LINKINIT_REASON_LINKUP (1 << 4) +#define OPA_LINKINIT_REASON_FLAPPING (2 << 4) +#define OPA_LINKINIT_REASON_CLEAR (8 << 4) +#define OPA_LINKINIT_OUTSIDE_POLICY (8 << 4) +#define OPA_LINKINIT_QUARANTINED (9 << 4) +#define OPA_LINKINIT_INSUFIC_CAPABILITY (10 << 4) + +#define OPA_LINK_SPEED_NOP 0x0000 /* Reserved (1-5 Gbps) */ +#define OPA_LINK_SPEED_12_5G 0x0001 /* 12.5 Gbps */ +#define OPA_LINK_SPEED_25G 0x0002 /* 25.78125? Gbps (EDR) */ + +#define OPA_LINK_WIDTH_1X 0x0001 +#define OPA_LINK_WIDTH_2X 0x0002 +#define OPA_LINK_WIDTH_3X 0x0004 +#define OPA_LINK_WIDTH_4X 0x0008 + +#define OPA_CAP_MASK3_IsSnoopSupported (1 << 7) +#define OPA_CAP_MASK3_IsAsyncSC2VLSupported (1 << 6) +#define OPA_CAP_MASK3_IsAddrRangeConfigSupported (1 << 5) +#define OPA_CAP_MASK3_IsPassThroughSupported (1 << 4) +#define OPA_CAP_MASK3_IsSharedSpaceSupported (1 << 3) +/* reserved (1 << 2) */ +#define OPA_CAP_MASK3_IsVLMarkerSupported (1 << 1) +#define OPA_CAP_MASK3_IsVLrSupported (1 << 0) + +/** + * new MTU values + */ +enum { + OPA_MTU_8192 = 6, + OPA_MTU_10240 = 7, +}; + +enum { + OPA_PORT_PHYS_CONF_DISCONNECTED = 0, + OPA_PORT_PHYS_CONF_STANDARD = 1, + OPA_PORT_PHYS_CONF_FIXED = 2, + OPA_PORT_PHYS_CONF_VARIABLE = 3, + OPA_PORT_PHYS_CONF_SI_PHOTO = 4 +}; + +enum port_info_field_masks { + /* vl.cap */ + OPA_PI_MASK_VL_CAP = 0x1F, + /* port_states.ledenable_offlinereason */ + OPA_PI_MASK_OFFLINE_REASON = 0x0F, + OPA_PI_MASK_LED_ENABLE = 0x40, + /* port_states.unsleepstate_downdefstate */ + OPA_PI_MASK_UNSLEEP_STATE = 0xF0, + OPA_PI_MASK_DOWNDEF_STATE = 0x0F, + /* port_states.portphysstate_portstate */ + OPA_PI_MASK_PORT_PHYSICAL_STATE = 0xF0, + OPA_PI_MASK_PORT_STATE = 0x0F, + /* port_phys_conf */ + OPA_PI_MASK_PORT_PHYSICAL_CONF = 0x0F, + /* collectivemask_multicastmask */ + OPA_PI_MASK_COLLECT_MASK = 0x38, + OPA_PI_MASK_MULTICAST_MASK = 0x07, + /* mkeyprotect_lmc */ + OPA_PI_MASK_MKEY_PROT_BIT = 0xC0, + OPA_PI_MASK_LMC = 0x0F, + /* smsl */ + OPA_PI_MASK_SMSL = 0x1F, + /* partenforce_filterraw */ + /* Filter Raw In/Out bits 1 and 2 were removed */ + OPA_PI_MASK_LINKINIT_REASON = 0xF0, + OPA_PI_MASK_PARTITION_ENFORCE_IN = 0x08, + OPA_PI_MASK_PARTITION_ENFORCE_OUT = 0x04, + /* operational_vls */ + OPA_PI_MASK_OPERATIONAL_VL = 0x1F, + /* sa_qp */ + OPA_PI_MASK_SA_QP = 0x00FFFFFF, + /* sm_trap_qp */ + OPA_PI_MASK_SM_TRAP_QP = 0x00FFFFFF, + /* localphy_overrun_errors */ + OPA_PI_MASK_LOCAL_PHY_ERRORS = 0xF0, + OPA_PI_MASK_OVERRUN_ERRORS = 0x0F, + /* clientrereg_subnettimeout */ + OPA_PI_MASK_CLIENT_REREGISTER = 0x80, + OPA_PI_MASK_SUBNET_TIMEOUT = 0x1F, + /* port_link_mode */ + OPA_PI_MASK_PORT_LINK_SUPPORTED = (0x001F << 10), + OPA_PI_MASK_PORT_LINK_ENABLED = (0x001F << 5), + OPA_PI_MASK_PORT_LINK_ACTIVE = (0x001F << 0), + /* port_link_crc_mode */ + OPA_PI_MASK_PORT_LINK_CRC_SUPPORTED = 0x0F00, + OPA_PI_MASK_PORT_LINK_CRC_ENABLED = 0x00F0, + OPA_PI_MASK_PORT_LINK_CRC_ACTIVE = 0x000F, + /* port_mode */ + OPA_PI_MASK_PORT_MODE_SECURITY_CHECK = 0x0001, + OPA_PI_MASK_PORT_MODE_16B_TRAP_QUERY = 0x0002, + OPA_PI_MASK_PORT_MODE_PKEY_CONVERT = 0x0004, + OPA_PI_MASK_PORT_MODE_SC2SC_MAPPING = 0x0008, + OPA_PI_MASK_PORT_MODE_VL_MARKER = 0x0010, + OPA_PI_MASK_PORT_PASS_THROUGH = 0x0020, + OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE = 0x0040, + /* flit_control.interleave */ + OPA_PI_MASK_INTERLEAVE_DIST_SUP = (0x0003 << 12), + OPA_PI_MASK_INTERLEAVE_DIST_ENABLE = (0x0003 << 10), + OPA_PI_MASK_INTERLEAVE_MAX_NEST_TX = (0x001F << 5), + OPA_PI_MASK_INTERLEAVE_MAX_NEST_RX = (0x001F << 0), + + /* port_error_action */ + OPA_PI_MASK_EX_BUFFER_OVERRUN = 0x80000000, + /* 7 bits reserved */ + OPA_PI_MASK_FM_CFG_ERR_EXCEED_MULTICAST_LIMIT = 0x00800000, + OPA_PI_MASK_FM_CFG_BAD_CONTROL_FLIT = 0x00400000, + OPA_PI_MASK_FM_CFG_BAD_PREEMPT = 0x00200000, + OPA_PI_MASK_FM_CFG_UNSUPPORTED_VL_MARKER = 0x00100000, + OPA_PI_MASK_FM_CFG_BAD_CRDT_ACK = 0x00080000, + OPA_PI_MASK_FM_CFG_BAD_CTRL_DIST = 0x00040000, + OPA_PI_MASK_FM_CFG_BAD_TAIL_DIST = 0x00020000, + OPA_PI_MASK_FM_CFG_BAD_HEAD_DIST = 0x00010000, + /* 2 bits reserved */ + OPA_PI_MASK_PORT_RCV_BAD_VL_MARKER = 0x00002000, + OPA_PI_MASK_PORT_RCV_PREEMPT_VL15 = 0x00001000, + OPA_PI_MASK_PORT_RCV_PREEMPT_ERROR = 0x00000800, + /* 1 bit reserved */ + OPA_PI_MASK_PORT_RCV_BAD_MidTail = 0x00000200, + /* 1 bit reserved */ + OPA_PI_MASK_PORT_RCV_BAD_SC = 0x00000080, + OPA_PI_MASK_PORT_RCV_BAD_L2 = 0x00000040, + OPA_PI_MASK_PORT_RCV_BAD_DLID = 0x00000020, + OPA_PI_MASK_PORT_RCV_BAD_SLID = 0x00000010, + OPA_PI_MASK_PORT_RCV_PKTLEN_TOOSHORT = 0x00000008, + OPA_PI_MASK_PORT_RCV_PKTLEN_TOOLONG = 0x00000004, + OPA_PI_MASK_PORT_RCV_BAD_PKTLEN = 0x00000002, + OPA_PI_MASK_PORT_RCV_BAD_LT = 0x00000001, + + /* pass_through.res_drctl */ + OPA_PI_MASK_PASS_THROUGH_DR_CONTROL = 0x01, + + /* buffer_units */ + OPA_PI_MASK_BUF_UNIT_VL15_INIT = (0x00000FFF << 11), + OPA_PI_MASK_BUF_UNIT_VL15_CREDIT_RATE = (0x0000001F << 6), + OPA_PI_MASK_BUF_UNIT_CREDIT_ACK = (0x00000003 << 3), + OPA_PI_MASK_BUF_UNIT_BUF_ALLOC = (0x00000003 << 0), + + /* neigh_mtu.pvlx_to_mtu */ + OPA_PI_MASK_NEIGH_MTU_PVL0 = 0xF0, + OPA_PI_MASK_NEIGH_MTU_PVL1 = 0x0F, + + /* neigh_mtu.vlstall_hoq_life */ + OPA_PI_MASK_VL_STALL = (0x03 << 5), + OPA_PI_MASK_HOQ_LIFE = (0x1F << 0), + + /* port_neigh_mode */ + OPA_PI_MASK_NEIGH_MGMT_ALLOWED = (0x01 << 3), + OPA_PI_MASK_NEIGH_FW_AUTH_BYPASS = (0x01 << 2), + OPA_PI_MASK_NEIGH_NODE_TYPE = (0x03 << 0), + + /* resptime_value */ + OPA_PI_MASK_RESPONSE_TIME_VALUE = 0x1F, + + /* mtucap */ + OPA_PI_MASK_MTU_CAP = 0x0F, +}; + +#if USE_PI_LED_ENABLE +struct opa_port_states { + u8 reserved; + u8 ledenable_offlinereason; /* 1 res, 1 bit, 6 bits */ + u8 reserved2; + u8 portphysstate_portstate; /* 4 bits, 4 bits */ +}; +#define PI_LED_ENABLE_SUP 1 +#else +struct opa_port_states { + u8 reserved; + u8 offline_reason; /* 2 res, 6 bits */ + u8 reserved2; + u8 portphysstate_portstate; /* 4 bits, 4 bits */ +}; +#define PI_LED_ENABLE_SUP 0 +#endif + +struct opa_port_state_info { + struct opa_port_states port_states; + u16 link_width_downgrade_tx_active; + u16 link_width_downgrade_rx_active; +}; + +struct opa_port_info { + __be32 lid; + __be32 flow_control_mask; + + struct { + u8 res; /* was inittype */ + u8 cap; /* 3 res, 5 bits */ + __be16 high_limit; + __be16 preempt_limit; + u8 arb_high_cap; + u8 arb_low_cap; + } vl; + + struct opa_port_states port_states; + u8 port_phys_conf; /* 4 res, 4 bits */ + u8 collectivemask_multicastmask; /* 2 res, 3, 3 */ + u8 mkeyprotect_lmc; /* 2 bits, 2 res, 4 bits */ + u8 smsl; /* 3 res, 5 bits */ + + u8 partenforce_filterraw; /* bit fields */ + u8 operational_vls; /* 3 res, 5 bits */ + __be16 pkey_8b; + __be16 pkey_10b; + __be16 mkey_violations; + + __be16 pkey_violations; + __be16 qkey_violations; + __be32 sm_trap_qp; /* 8 bits, 24 bits */ + + __be32 sa_qp; /* 8 bits, 24 bits */ + u8 neigh_port_num; + u8 link_down_reason; + u8 neigh_link_down_reason; + u8 clientrereg_subnettimeout; /* 1 bit, 2 bits, 5 */ + + struct { + __be16 supported; + __be16 enabled; + __be16 active; + } link_speed; + struct { + __be16 supported; + __be16 enabled; + __be16 active; + } link_width; + struct { + __be16 supported; + __be16 enabled; + __be16 tx_active; + __be16 rx_active; + } link_width_downgrade; + __be16 port_link_mode; /* 1 res, 5 bits, 5 bits, 5 bits */ + __be16 port_ltp_crc_mode; /* 4 res, 4 bits, 4 bits, 4 bits */ + + __be16 port_mode; /* 9 res, bit fields */ + struct { + __be16 supported; + __be16 enabled; + } port_packet_format; + struct { + __be16 interleave; /* 2 res, 2,2,5,5 */ + struct { + __be16 min_initial; + __be16 min_tail; + u8 large_pkt_limit; + u8 small_pkt_limit; + u8 max_small_pkt_limit; + u8 preemption_limit; + } preemption; + } flit_control; + + __be32 reserved4; + __be32 port_error_action; /* bit field */ + + struct { + u8 egress_port; + u8 res_drctl; /* 7 res, 1 */ + } pass_through; + __be16 mkey_lease_period; + __be32 buffer_units; /* 9 res, 12, 5, 3, 3 */ + + __be32 reserved5; + __be32 sm_lid; + + __be64 mkey; + + __be64 subnet_prefix; + + struct { + u8 pvlx_to_mtu[OPA_MAX_VLS/2]; /* 4 bits, 4 bits */ + } neigh_mtu; + + struct { + u8 vlstall_hoqlife; /* 3 bits, 5 bits */ + } xmit_q[OPA_MAX_VLS]; + + struct { + u8 addr[16]; + } ipaddr_ipv6; + + struct { + u8 addr[4]; + } ipaddr_ipv4; + + u32 reserved6; + u32 reserved7; + u32 reserved8; + + __be64 neigh_node_guid; + + __be32 ib_cap_mask; + __be16 reserved9; /* was ib_cap_mask2 */ + __be16 opa_cap_mask; + + __be32 reserved10; /* was link_roundtrip_latency */ + __be16 overall_buffer_space; + __be16 reserved11; /* was max_credit_hint */ + + __be16 diag_code; + struct { + u8 buffer; + u8 wire; + } replay_depth; + u8 port_neigh_mode; + u8 mtucap; /* 4 res, 4 bits */ + + u8 resptimevalue; /* 3 res, 5 bits */ + u8 local_port_num; + u8 reserved12; + u8 reserved13; /* was guid_cap */ +} __attribute__ ((packed)); + +#endif /* OPA_PORT_INFO_H */ diff --git a/include/rdma/opa_smi.h b/include/rdma/opa_smi.h index 29063e84c253e..4a529ef479951 100644 --- a/include/rdma/opa_smi.h +++ b/include/rdma/opa_smi.h @@ -40,6 +40,10 @@ #define OPA_SMP_DR_DATA_SIZE 1872 #define OPA_SMP_MAX_PATH_HOPS 64 +#define OPA_MAX_VLS 32 +#define OPA_MAX_SLS 32 +#define OPA_MAX_SCS 32 + #define OPA_SMI_CLASS_VERSION 0x80 #define OPA_LID_PERMISSIVE cpu_to_be32(0xFFFFFFFF) @@ -73,6 +77,49 @@ struct opa_smp { } __packed; +/* Subnet management attributes */ +/* ... */ +#define OPA_ATTRIB_ID_NODE_DESCRIPTION cpu_to_be16(0x0010) +#define OPA_ATTRIB_ID_NODE_INFO cpu_to_be16(0x0011) +#define OPA_ATTRIB_ID_PORT_INFO cpu_to_be16(0x0015) +#define OPA_ATTRIB_ID_PARTITION_TABLE cpu_to_be16(0x0016) +#define OPA_ATTRIB_ID_SL_TO_SC_MAP cpu_to_be16(0x0017) +#define OPA_ATTRIB_ID_VL_ARBITRATION cpu_to_be16(0x0018) +#define OPA_ATTRIB_ID_SM_INFO cpu_to_be16(0x0020) +#define OPA_ATTRIB_ID_CABLE_INFO cpu_to_be16(0x0032) +#define OPA_ATTRIB_ID_AGGREGATE cpu_to_be16(0x0080) +#define OPA_ATTRIB_ID_SC_TO_SL_MAP cpu_to_be16(0x0082) +#define OPA_ATTRIB_ID_SC_TO_VLR_MAP cpu_to_be16(0x0083) +#define OPA_ATTRIB_ID_SC_TO_VLT_MAP cpu_to_be16(0x0084) +#define OPA_ATTRIB_ID_SC_TO_VLNT_MAP cpu_to_be16(0x0085) +/* ... */ +#define OPA_ATTRIB_ID_PORT_STATE_INFO cpu_to_be16(0x0087) +/* ... */ +#define OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE cpu_to_be16(0x008A) +/* ... */ + +struct opa_node_description { + u8 data[64]; +} __attribute__ ((packed)); + +struct opa_node_info { + u8 base_version; + u8 class_version; + u8 node_type; + u8 num_ports; + __be32 reserved; + __be64 system_image_guid; + __be64 node_guid; + __be64 port_guid; + __be16 partition_cap; + __be16 device_id; + __be32 revision; + u8 local_port_num; + u8 vendor_id[3]; /* network byte order */ +} __attribute__ ((packed)); + +#define OPA_PARTITION_TABLE_BLK_SIZE 32 + static inline u8 opa_get_smp_direction(struct opa_smp *smp) { diff --git a/include/uapi/rdma/hfi/hfi1_user.h b/include/uapi/rdma/hfi/hfi1_user.h new file mode 100644 index 0000000000000..78c442fbf263d --- /dev/null +++ b/include/uapi/rdma/hfi/hfi1_user.h @@ -0,0 +1,427 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * This file contains defines, structures, etc. that are used + * to communicate between kernel and user code. + */ + +#ifndef _LINUX__HFI1_USER_H +#define _LINUX__HFI1_USER_H + +#include + +/* + * This version number is given to the driver by the user code during + * initialization in the spu_userversion field of hfi1_user_info, so + * the driver can check for compatibility with user code. + * + * The major version changes when data structures change in an incompatible + * way. The driver must be the same for initialization to succeed. + */ +#define HFI1_USER_SWMAJOR 4 + +/* + * Minor version differences are always compatible + * a within a major version, however if user software is larger + * than driver software, some new features and/or structure fields + * may not be implemented; the user code must deal with this if it + * cares, or it must abort after initialization reports the difference. + */ +#define HFI1_USER_SWMINOR 0 + +/* + * Set of HW and driver capability/feature bits. + * These bit values are used to configure enabled/disabled HW and + * driver features. The same set of bits are communicated to user + * space. + */ +#define HFI1_CAP_DMA_RTAIL (1UL << 0) /* Use DMA'ed RTail value */ +#define HFI1_CAP_SDMA (1UL << 1) /* Enable SDMA support */ +#define HFI1_CAP_SDMA_AHG (1UL << 2) /* Enable SDMA AHG support */ +#define HFI1_CAP_EXTENDED_PSN (1UL << 3) /* Enable Extended PSN support */ +#define HFI1_CAP_HDRSUPP (1UL << 4) /* Enable Header Suppression */ +/* 1UL << 5 reserved */ +#define HFI1_CAP_USE_SDMA_HEAD (1UL << 6) /* DMA Hdr Q tail vs. use CSR */ +#define HFI1_CAP_MULTI_PKT_EGR (1UL << 7) /* Enable multi-packet Egr buffs*/ +#define HFI1_CAP_NODROP_RHQ_FULL (1UL << 8) /* Don't drop on Hdr Q full */ +#define HFI1_CAP_NODROP_EGR_FULL (1UL << 9) /* Don't drop on EGR buffs full */ +#define HFI1_CAP_TID_UNMAP (1UL << 10) /* Enable Expected TID caching */ +#define HFI1_CAP_PRINT_UNIMPL (1UL << 11) /* Show for unimplemented feats */ +#define HFI1_CAP_ALLOW_PERM_JKEY (1UL << 12) /* Allow use of permissive JKEY */ +#define HFI1_CAP_NO_INTEGRITY (1UL << 13) /* Enable ctxt integrity checks */ +#define HFI1_CAP_PKEY_CHECK (1UL << 14) /* Enable ctxt PKey checking */ +#define HFI1_CAP_STATIC_RATE_CTRL (1UL << 15) /* Allow PBC.StaticRateControl */ +#define HFI1_CAP_QSFP_ENABLED (1UL << 16) /* Enable QSFP check during LNI */ +#define HFI1_CAP_SDMA_HEAD_CHECK (1UL << 17) /* SDMA head checking */ +#define HFI1_CAP_EARLY_CREDIT_RETURN (1UL << 18) /* early credit return */ + +#define HFI1_RCVHDR_ENTSIZE_2 (1UL << 0) +#define HFI1_RCVHDR_ENTSIZE_16 (1UL << 1) +#define HFI1_RCVDHR_ENTSIZE_32 (1UL << 2) + +/* + * If the unit is specified via open, HFI choice is fixed. If port is + * specified, it's also fixed. Otherwise we try to spread contexts + * across ports and HFIs, using different algorithms. WITHIN is + * the old default, prior to this mechanism. + */ +#define HFI1_ALG_ACROSS 0 /* round robin contexts across HFIs, then + * ports; this is the default */ +#define HFI1_ALG_WITHIN 1 /* use all contexts on an HFI (round robin + * active ports within), then next HFI */ +#define HFI1_ALG_COUNT 2 /* number of algorithm choices */ + + +/* User commands. */ +#define HFI1_CMD_ASSIGN_CTXT 1 /* allocate HFI and context */ +#define HFI1_CMD_CTXT_INFO 2 /* find out what resources we got */ +#define HFI1_CMD_USER_INFO 3 /* set up userspace */ +#define HFI1_CMD_TID_UPDATE 4 /* update expected TID entries */ +#define HFI1_CMD_TID_FREE 5 /* free expected TID entries */ +#define HFI1_CMD_CREDIT_UPD 6 /* force an update of PIO credit */ +#define HFI1_CMD_SDMA_STATUS_UPD 7 /* force update of SDMA status ring */ + +#define HFI1_CMD_RECV_CTRL 8 /* control receipt of packets */ +#define HFI1_CMD_POLL_TYPE 9 /* set the kind of polling we want */ +#define HFI1_CMD_ACK_EVENT 10 /* ack & clear user status bits */ +#define HFI1_CMD_SET_PKEY 11 /* set context's pkey */ +#define HFI1_CMD_CTXT_RESET 12 /* reset context's HW send context */ +/* separate EPROM commands from normal PSM commands */ +#define HFI1_CMD_EP_INFO 64 /* read EPROM device ID */ +#define HFI1_CMD_EP_ERASE_CHIP 65 /* erase whole EPROM */ +#define HFI1_CMD_EP_ERASE_P0 66 /* erase EPROM partition 0 */ +#define HFI1_CMD_EP_ERASE_P1 67 /* erase EPROM partition 1 */ +#define HFI1_CMD_EP_READ_P0 68 /* read EPROM partition 0 */ +#define HFI1_CMD_EP_READ_P1 69 /* read EPROM partition 1 */ +#define HFI1_CMD_EP_WRITE_P0 70 /* write EPROM partition 0 */ +#define HFI1_CMD_EP_WRITE_P1 71 /* write EPROM partition 1 */ + +#define _HFI1_EVENT_FROZEN_BIT 0 +#define _HFI1_EVENT_LINKDOWN_BIT 1 +#define _HFI1_EVENT_LID_CHANGE_BIT 2 +#define _HFI1_EVENT_LMC_CHANGE_BIT 3 +#define _HFI1_EVENT_SL2VL_CHANGE_BIT 4 +#define _HFI1_MAX_EVENT_BIT _HFI1_EVENT_SL2VL_CHANGE_BIT + +#define HFI1_EVENT_FROZEN (1UL << _HFI1_EVENT_FROZEN_BIT) +#define HFI1_EVENT_LINKDOWN_BIT (1UL << _HFI1_EVENT_LINKDOWN_BIT) +#define HFI1_EVENT_LID_CHANGE_BIT (1UL << _HFI1_EVENT_LID_CHANGE_BIT) +#define HFI1_EVENT_LMC_CHANGE_BIT (1UL << _HFI1_EVENT_LMC_CHANGE_BIT) +#define HFI1_EVENT_SL2VL_CHANGE_BIT (1UL << _HFI1_EVENT_SL2VL_CHANGE_BIT) + +/* + * These are the status bits readable (in ASCII form, 64bit value) + * from the "status" sysfs file. For binary compatibility, values + * must remain as is; removed states can be reused for different + * purposes. + */ +#define HFI1_STATUS_INITTED 0x1 /* basic initialization done */ +/* Chip has been found and initialized */ +#define HFI1_STATUS_CHIP_PRESENT 0x20 +/* IB link is at ACTIVE, usable for data traffic */ +#define HFI1_STATUS_IB_READY 0x40 +/* link is configured, LID, MTU, etc. have been set */ +#define HFI1_STATUS_IB_CONF 0x80 +/* A Fatal hardware error has occurred. */ +#define HFI1_STATUS_HWERROR 0x200 + +/* + * Number of supported shared contexts. + * This is the maximum number of software contexts that can share + * a hardware send/receive context. + */ +#define HFI1_MAX_SHARED_CTXTS 8 + +/* + * Poll types + */ +#define HFI1_POLL_TYPE_ANYRCV 0x0 +#define HFI1_POLL_TYPE_URGENT 0x1 + +/* + * This structure is passed to the driver to tell it where + * user code buffers are, sizes, etc. The offsets and sizes of the + * fields must remain unchanged, for binary compatibility. It can + * be extended, if userversion is changed so user code can tell, if needed + */ +struct hfi1_user_info { + /* + * version of user software, to detect compatibility issues. + * Should be set to HFI1_USER_SWVERSION. + */ + __u32 userversion; + __u16 pad; + /* HFI selection algorithm, if unit has not selected */ + __u16 hfi1_alg; + /* + * If two or more processes wish to share a context, each process + * must set the subcontext_cnt and subcontext_id to the same + * values. The only restriction on the subcontext_id is that + * it be unique for a given node. + */ + __u16 subctxt_cnt; + __u16 subctxt_id; + /* 128bit UUID passed in by PSM. */ + __u8 uuid[16]; +}; + +struct hfi1_ctxt_info { + __u64 runtime_flags; /* chip/drv runtime flags (HFI1_CAP_*) */ + __u32 rcvegr_size; /* size of each eager buffer */ + __u16 num_active; /* number of active units */ + __u16 unit; /* unit (chip) assigned to caller */ + __u16 ctxt; /* ctxt on unit assigned to caller */ + __u16 subctxt; /* subctxt on unit assigned to caller */ + __u16 rcvtids; /* number of Rcv TIDs for this context */ + __u16 credits; /* number of PIO credits for this context */ + __u16 numa_node; /* NUMA node of the assigned device */ + __u16 rec_cpu; /* cpu # for affinity (0xffff if none) */ + __u16 send_ctxt; /* send context in use by this user context */ + __u16 egrtids; /* number of RcvArray entries for Eager Rcvs */ + __u16 rcvhdrq_cnt; /* number of RcvHdrQ entries */ + __u16 rcvhdrq_entsize; /* size (in bytes) for each RcvHdrQ entry */ + __u16 sdma_ring_size; /* number of entries in SDMA request ring */ +}; + +struct hfi1_tid_info { + /* virtual address of first page in transfer */ + __u64 vaddr; + /* pointer to tid array. this array is big enough */ + __u64 tidlist; + /* number of tids programmed by this request */ + __u32 tidcnt; + /* length of transfer buffer programmed by this request */ + __u32 length; + /* + * pointer to bitmap of TIDs used for this call; + * checked for being large enough at open + */ + __u64 tidmap; +}; + +struct hfi1_cmd { + __u32 type; /* command type */ + __u32 len; /* length of struct pointed to by add */ + __u64 addr; /* pointer to user structure */ +}; + +enum hfi1_sdma_comp_state { + FREE = 0, + QUEUED, + COMPLETE, + ERROR +}; + +/* + * SDMA completion ring entry + */ +struct hfi1_sdma_comp_entry { + __u32 status; + __u32 errcode; +}; + +/* + * Device status and notifications from driver to user-space. + */ +struct hfi1_status { + __u64 dev; /* device/hw status bits */ + __u64 port; /* port state and status bits */ + char freezemsg[0]; +}; + +/* + * This structure is returned by the driver immediately after + * open to get implementation-specific info, and info specific to this + * instance. + * + * This struct must have explicit pad fields where type sizes + * may result in different alignments between 32 and 64 bit + * programs, since the 64 bit * bit kernel requires the user code + * to have matching offsets + */ +struct hfi1_base_info { + /* version of hardware, for feature checking. */ + __u32 hw_version; + /* version of software, for feature checking. */ + __u32 sw_version; + /* Job key */ + __u16 jkey; + __u16 padding1; + /* + * The special QP (queue pair) value that identifies PSM + * protocol packet from standard IB packets. + */ + __u32 bthqp; + /* PIO credit return address, */ + __u64 sc_credits_addr; + /* + * Base address of write-only pio buffers for this process. + * Each buffer has sendpio_credits*64 bytes. + */ + __u64 pio_bufbase_sop; + /* + * Base address of write-only pio buffers for this process. + * Each buffer has sendpio_credits*64 bytes. + */ + __u64 pio_bufbase; + /* address where receive buffer queue is mapped into */ + __u64 rcvhdr_bufbase; + /* base address of Eager receive buffers. */ + __u64 rcvegr_bufbase; + /* base address of SDMA completion ring */ + __u64 sdma_comp_bufbase; + /* + * User register base for init code, not to be used directly by + * protocol or applications. Always maps real chip register space. + * the register addresses are: + * ur_rcvhdrhead, ur_rcvhdrtail, ur_rcvegrhead, ur_rcvegrtail, + * ur_rcvtidflow + */ + __u64 user_regbase; + /* notification events */ + __u64 events_bufbase; + /* status page */ + __u64 status_bufbase; + /* rcvhdrtail update */ + __u64 rcvhdrtail_base; + /* + * shared memory pages for subctxts if ctxt is shared; these cover + * all the processes in the group sharing a single context. + * all have enough space for the num_subcontexts value on this job. + */ + __u64 subctxt_uregbase; + __u64 subctxt_rcvegrbuf; + __u64 subctxt_rcvhdrbuf; +}; + +enum sdma_req_opcode { + EXPECTED = 0, + EAGER +}; + +#define HFI1_SDMA_REQ_VERSION_MASK 0xF +#define HFI1_SDMA_REQ_VERSION_SHIFT 0x0 +#define HFI1_SDMA_REQ_OPCODE_MASK 0xF +#define HFI1_SDMA_REQ_OPCODE_SHIFT 0x4 +#define HFI1_SDMA_REQ_IOVCNT_MASK 0xFF +#define HFI1_SDMA_REQ_IOVCNT_SHIFT 0x8 + +struct sdma_req_info { + /* + * bits 0-3 - version (currently unused) + * bits 4-7 - opcode (enum sdma_req_opcode) + * bits 8-15 - io vector count + */ + __u16 ctrl; + /* + * Number of fragments contained in this request. + * User-space has already computed how many + * fragment-sized packet the user buffer will be + * split into. + */ + __u16 npkts; + /* + * Size of each fragment the user buffer will be + * split into. + */ + __u16 fragsize; + /* + * Index of the slot in the SDMA completion ring + * this request should be using. User-space is + * in charge of managing its own ring. + */ + __u16 comp_idx; +} __packed; + +/* + * SW KDETH header. + * swdata is SW defined portion. + */ +struct hfi1_kdeth_header { + __le32 ver_tid_offset; + __le16 jkey; + __le16 hcrc; + __le32 swdata[7]; +} __packed; + +/* + * Structure describing the headers that User space uses. The + * structure above is a subset of this one. + */ +struct hfi1_pkt_header { + __le16 pbc[4]; + __be16 lrh[4]; + __be32 bth[3]; + struct hfi1_kdeth_header kdeth; +} __packed; + + +/* + * The list of usermode accessible registers. + */ +enum hfi1_ureg { + /* (RO) DMA RcvHdr to be used next. */ + ur_rcvhdrtail = 0, + /* (RW) RcvHdr entry to be processed next by host. */ + ur_rcvhdrhead = 1, + /* (RO) Index of next Eager index to use. */ + ur_rcvegrindextail = 2, + /* (RW) Eager TID to be processed next */ + ur_rcvegrindexhead = 3, + /* (RO) Receive Eager Offset Tail */ + ur_rcvegroffsettail = 4, + /* For internal use only; max register number. */ + ur_maxreg, + /* (RW) Receive TID flow table */ + ur_rcvtidflowtable = 256 +}; + +#endif /* _LINIUX__HFI1_USER_H */ -- GitLab From 7724105686e718ac476a6ad3304fea2fbcfcffde Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Thu, 30 Jul 2015 15:17:43 -0400 Subject: [PATCH 5682/7006] IB/hfi1: add driver files Signed-off-by: Andrew Friedley Signed-off-by: Arthur Kepner Signed-off-by: Brendan Cunningham Signed-off-by: Brian Welty Signed-off-by: Caz Yokoyama Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Signed-off-by: Easwar Hariharan Signed-off-by: Harish Chegondi Signed-off-by: Ira Weiny Signed-off-by: Jim Snow Signed-off-by: John Gregor Signed-off-by: Jubin John Signed-off-by: Kaike Wan Signed-off-by: Kevin Pine Signed-off-by: Kyle Liddell Signed-off-by: Mike Marciniszyn Signed-off-by: Mitko Haralanov Signed-off-by: Ravi Krishnaswamy Signed-off-by: Sadanand Warrier Signed-off-by: Sanath Kumar Signed-off-by: Sudeep Dutt Signed-off-by: Vlad Danushevsky Signed-off-by: Doug Ledford --- Documentation/infiniband/sysfs.txt | 20 + MAINTAINERS | 6 + drivers/staging/rdma/Kconfig | 2 + drivers/staging/rdma/Makefile | 1 + drivers/staging/rdma/hfi1/Kconfig | 37 + drivers/staging/rdma/hfi1/Makefile | 19 + drivers/staging/rdma/hfi1/TODO | 6 + drivers/staging/rdma/hfi1/chip.c | 10798 ++++++++++++++++++ drivers/staging/rdma/hfi1/chip.h | 1035 ++ drivers/staging/rdma/hfi1/chip_registers.h | 1289 +++ drivers/staging/rdma/hfi1/common.h | 415 + drivers/staging/rdma/hfi1/cq.c | 558 + drivers/staging/rdma/hfi1/debugfs.c | 899 ++ drivers/staging/rdma/hfi1/debugfs.h | 78 + drivers/staging/rdma/hfi1/device.c | 142 + drivers/staging/rdma/hfi1/device.h | 61 + drivers/staging/rdma/hfi1/diag.c | 1873 +++ drivers/staging/rdma/hfi1/dma.c | 186 + drivers/staging/rdma/hfi1/driver.c | 1241 ++ drivers/staging/rdma/hfi1/eprom.c | 475 + drivers/staging/rdma/hfi1/eprom.h | 55 + drivers/staging/rdma/hfi1/file_ops.c | 2140 ++++ drivers/staging/rdma/hfi1/firmware.c | 1620 +++ drivers/staging/rdma/hfi1/hfi.h | 1821 +++ drivers/staging/rdma/hfi1/init.c | 1722 +++ drivers/staging/rdma/hfi1/intr.c | 207 + drivers/staging/rdma/hfi1/iowait.h | 186 + drivers/staging/rdma/hfi1/keys.c | 411 + drivers/staging/rdma/hfi1/mad.c | 4257 +++++++ drivers/staging/rdma/hfi1/mad.h | 325 + drivers/staging/rdma/hfi1/mmap.c | 192 + drivers/staging/rdma/hfi1/mr.c | 546 + drivers/staging/rdma/hfi1/opa_compat.h | 129 + drivers/staging/rdma/hfi1/pcie.c | 1253 ++ drivers/staging/rdma/hfi1/pio.c | 1771 +++ drivers/staging/rdma/hfi1/pio.h | 224 + drivers/staging/rdma/hfi1/pio_copy.c | 858 ++ drivers/staging/rdma/hfi1/platform_config.h | 286 + drivers/staging/rdma/hfi1/qp.c | 1687 +++ drivers/staging/rdma/hfi1/qp.h | 235 + drivers/staging/rdma/hfi1/qsfp.c | 546 + drivers/staging/rdma/hfi1/qsfp.h | 222 + drivers/staging/rdma/hfi1/rc.c | 2426 ++++ drivers/staging/rdma/hfi1/ruc.c | 948 ++ drivers/staging/rdma/hfi1/sdma.c | 2962 +++++ drivers/staging/rdma/hfi1/sdma.h | 1123 ++ drivers/staging/rdma/hfi1/srq.c | 397 + drivers/staging/rdma/hfi1/sysfs.c | 739 ++ drivers/staging/rdma/hfi1/trace.c | 221 + drivers/staging/rdma/hfi1/trace.h | 1409 +++ drivers/staging/rdma/hfi1/twsi.c | 518 + drivers/staging/rdma/hfi1/twsi.h | 68 + drivers/staging/rdma/hfi1/uc.c | 585 + drivers/staging/rdma/hfi1/ud.c | 885 ++ drivers/staging/rdma/hfi1/user_pages.c | 156 + drivers/staging/rdma/hfi1/user_sdma.c | 1444 +++ drivers/staging/rdma/hfi1/user_sdma.h | 89 + drivers/staging/rdma/hfi1/verbs.c | 2142 ++++ drivers/staging/rdma/hfi1/verbs.h | 1149 ++ drivers/staging/rdma/hfi1/verbs_mcast.c | 385 + 60 files changed, 57480 insertions(+) create mode 100644 drivers/staging/rdma/hfi1/Kconfig create mode 100644 drivers/staging/rdma/hfi1/Makefile create mode 100644 drivers/staging/rdma/hfi1/TODO create mode 100644 drivers/staging/rdma/hfi1/chip.c create mode 100644 drivers/staging/rdma/hfi1/chip.h create mode 100644 drivers/staging/rdma/hfi1/chip_registers.h create mode 100644 drivers/staging/rdma/hfi1/common.h create mode 100644 drivers/staging/rdma/hfi1/cq.c create mode 100644 drivers/staging/rdma/hfi1/debugfs.c create mode 100644 drivers/staging/rdma/hfi1/debugfs.h create mode 100644 drivers/staging/rdma/hfi1/device.c create mode 100644 drivers/staging/rdma/hfi1/device.h create mode 100644 drivers/staging/rdma/hfi1/diag.c create mode 100644 drivers/staging/rdma/hfi1/dma.c create mode 100644 drivers/staging/rdma/hfi1/driver.c create mode 100644 drivers/staging/rdma/hfi1/eprom.c create mode 100644 drivers/staging/rdma/hfi1/eprom.h create mode 100644 drivers/staging/rdma/hfi1/file_ops.c create mode 100644 drivers/staging/rdma/hfi1/firmware.c create mode 100644 drivers/staging/rdma/hfi1/hfi.h create mode 100644 drivers/staging/rdma/hfi1/init.c create mode 100644 drivers/staging/rdma/hfi1/intr.c create mode 100644 drivers/staging/rdma/hfi1/iowait.h create mode 100644 drivers/staging/rdma/hfi1/keys.c create mode 100644 drivers/staging/rdma/hfi1/mad.c create mode 100644 drivers/staging/rdma/hfi1/mad.h create mode 100644 drivers/staging/rdma/hfi1/mmap.c create mode 100644 drivers/staging/rdma/hfi1/mr.c create mode 100644 drivers/staging/rdma/hfi1/opa_compat.h create mode 100644 drivers/staging/rdma/hfi1/pcie.c create mode 100644 drivers/staging/rdma/hfi1/pio.c create mode 100644 drivers/staging/rdma/hfi1/pio.h create mode 100644 drivers/staging/rdma/hfi1/pio_copy.c create mode 100644 drivers/staging/rdma/hfi1/platform_config.h create mode 100644 drivers/staging/rdma/hfi1/qp.c create mode 100644 drivers/staging/rdma/hfi1/qp.h create mode 100644 drivers/staging/rdma/hfi1/qsfp.c create mode 100644 drivers/staging/rdma/hfi1/qsfp.h create mode 100644 drivers/staging/rdma/hfi1/rc.c create mode 100644 drivers/staging/rdma/hfi1/ruc.c create mode 100644 drivers/staging/rdma/hfi1/sdma.c create mode 100644 drivers/staging/rdma/hfi1/sdma.h create mode 100644 drivers/staging/rdma/hfi1/srq.c create mode 100644 drivers/staging/rdma/hfi1/sysfs.c create mode 100644 drivers/staging/rdma/hfi1/trace.c create mode 100644 drivers/staging/rdma/hfi1/trace.h create mode 100644 drivers/staging/rdma/hfi1/twsi.c create mode 100644 drivers/staging/rdma/hfi1/twsi.h create mode 100644 drivers/staging/rdma/hfi1/uc.c create mode 100644 drivers/staging/rdma/hfi1/ud.c create mode 100644 drivers/staging/rdma/hfi1/user_pages.c create mode 100644 drivers/staging/rdma/hfi1/user_sdma.c create mode 100644 drivers/staging/rdma/hfi1/user_sdma.h create mode 100644 drivers/staging/rdma/hfi1/verbs.c create mode 100644 drivers/staging/rdma/hfi1/verbs.h create mode 100644 drivers/staging/rdma/hfi1/verbs_mcast.c diff --git a/Documentation/infiniband/sysfs.txt b/Documentation/infiniband/sysfs.txt index ddd519b72ee15..9028b025501a6 100644 --- a/Documentation/infiniband/sysfs.txt +++ b/Documentation/infiniband/sysfs.txt @@ -64,3 +64,23 @@ MTHCA fw_ver - Firmware version hca_type - HCA type: "MT23108", "MT25208 (MT23108 compat mode)", or "MT25208" + +HFI1 + + The hfi1 driver also creates these additional files: + + hw_rev - hardware revision + board_id - manufacturing board id + tempsense - thermal sense information + serial - board serial number + nfreectxts - number of free user contexts + nctxts - number of allowed contexts (PSM2) + chip_reset - diagnostic (root only) + boardversion - board version + ports/1/ + CMgtA/ + cc_settings_bin - CCA tables used by PSM2 + cc_table_bin + sc2v/ - 32 files (0 - 31) used to translate sl->vl + sl2sc/ - 32 files (0 - 31) used to translate sl->sc + vl2mtu/ - 16 (0 - 15) files used to determine MTU for vl diff --git a/MAINTAINERS b/MAINTAINERS index db1a523ed4938..2249ac8890763 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9809,6 +9809,12 @@ M: Arnaud Patard S: Odd Fixes F: drivers/staging/xgifb/ +HFI1 DRIVER +M: Mike Marciniszyn +L: linux-rdma@vger.kernel.org +S: Supported +F: drivers/staging/rdma/hfi1 + STARFIRE/DURALAN NETWORK DRIVER M: Ion Badulescu S: Odd Fixes diff --git a/drivers/staging/rdma/Kconfig b/drivers/staging/rdma/Kconfig index 5084088c89468..cf5fe9bb87a16 100644 --- a/drivers/staging/rdma/Kconfig +++ b/drivers/staging/rdma/Kconfig @@ -24,6 +24,8 @@ if STAGING_RDMA source "drivers/staging/rdma/amso1100/Kconfig" +source "drivers/staging/rdma/hfi1/Kconfig" + source "drivers/staging/rdma/ipath/Kconfig" endif diff --git a/drivers/staging/rdma/Makefile b/drivers/staging/rdma/Makefile index a2a459ac8d673..cbd915ac7f20a 100644 --- a/drivers/staging/rdma/Makefile +++ b/drivers/staging/rdma/Makefile @@ -1,3 +1,4 @@ # Entries for RDMA_STAGING tree obj-$(CONFIG_INFINIBAND_AMSO1100) += amso1100/ +obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/ obj-$(CONFIG_INFINIBAND_IPATH) += ipath/ diff --git a/drivers/staging/rdma/hfi1/Kconfig b/drivers/staging/rdma/hfi1/Kconfig new file mode 100644 index 0000000000000..fd25078ee923e --- /dev/null +++ b/drivers/staging/rdma/hfi1/Kconfig @@ -0,0 +1,37 @@ +config INFINIBAND_HFI1 + tristate "Intel OPA Gen1 support" + depends on X86_64 + default m + ---help--- + This is a low-level driver for Intel OPA Gen1 adapter. +config HFI1_DEBUG_SDMA_ORDER + bool "HFI1 SDMA Order debug" + depends on INFINIBAND_HFI1 + default n + ---help--- + This is a debug flag to test for out of order + sdma completions for unit testing +config HFI1_VERBS_31BIT_PSN + bool "HFI1 enable 31 bit PSN" + depends on INFINIBAND_HFI1 + default y + ---help--- + Setting this enables 31 BIT PSN + For verbs RC/UC +config SDMA_VERBOSITY + bool "Config SDMA Verbosity" + depends on INFINIBAND_HFI1 + default n + ---help--- + This is a configuration flag to enable verbose + SDMA debug +config PRESCAN_RXQ + bool "Enable prescanning of the RX queue for ECNs" + depends on INFINIBAND_HFI1 + default n + ---help--- + This option toggles the prescanning of the receive queue for + Explicit Congestion Notifications. If an ECN is detected, it + is processed as quickly as possible, the ECN is toggled off. + After the prescanning step, the receive queue is processed as + usual. diff --git a/drivers/staging/rdma/hfi1/Makefile b/drivers/staging/rdma/hfi1/Makefile new file mode 100644 index 0000000000000..2e5daa6cdcc26 --- /dev/null +++ b/drivers/staging/rdma/hfi1/Makefile @@ -0,0 +1,19 @@ +# +# HFI driver +# +# +# +# Called from the kernel module build system. +# +obj-$(CONFIG_INFINIBAND_HFI1) += hfi1.o + +hfi1-y := chip.o cq.o device.o diag.o dma.o driver.o eprom.o file_ops.o firmware.o \ + init.o intr.o keys.o mad.o mmap.o mr.o pcie.o pio.o pio_copy.o \ + qp.o qsfp.o rc.o ruc.o sdma.o srq.o sysfs.o trace.o twsi.o \ + uc.o ud.o user_pages.o user_sdma.o verbs_mcast.o verbs.o +hfi1-$(CONFIG_DEBUG_FS) += debugfs.o + +CFLAGS_trace.o = -I$(src) +ifdef MVERSION +CFLAGS_driver.o = -DHFI_DRIVER_VERSION_BASE=\"$(MVERSION)\" +endif diff --git a/drivers/staging/rdma/hfi1/TODO b/drivers/staging/rdma/hfi1/TODO new file mode 100644 index 0000000000000..05de0dad8762e --- /dev/null +++ b/drivers/staging/rdma/hfi1/TODO @@ -0,0 +1,6 @@ +July, 2015 + +- Remove unneeded file entries in sysfs +- Remove software processing of IB protocol and place in library for use + by qib, ipath (if still present), hfi1, and eventually soft-roce + diff --git a/drivers/staging/rdma/hfi1/chip.c b/drivers/staging/rdma/hfi1/chip.c new file mode 100644 index 0000000000000..654eafef1d308 --- /dev/null +++ b/drivers/staging/rdma/hfi1/chip.c @@ -0,0 +1,10798 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * This file contains all of the code that is specific to the HFI chip + */ + +#include +#include +#include +#include + +#include "hfi.h" +#include "trace.h" +#include "mad.h" +#include "pio.h" +#include "sdma.h" +#include "eprom.h" + +#define NUM_IB_PORTS 1 + +uint kdeth_qp; +module_param_named(kdeth_qp, kdeth_qp, uint, S_IRUGO); +MODULE_PARM_DESC(kdeth_qp, "Set the KDETH queue pair prefix"); + +uint num_vls = HFI1_MAX_VLS_SUPPORTED; +module_param(num_vls, uint, S_IRUGO); +MODULE_PARM_DESC(num_vls, "Set number of Virtual Lanes to use (1-8)"); + +/* + * Default time to aggregate two 10K packets from the idle state + * (timer not running). The timer starts at the end of the first packet, + * so only the time for one 10K packet and header plus a bit extra is needed. + * 10 * 1024 + 64 header byte = 10304 byte + * 10304 byte / 12.5 GB/s = 824.32ns + */ +uint rcv_intr_timeout = (824 + 16); /* 16 is for coalescing interrupt */ +module_param(rcv_intr_timeout, uint, S_IRUGO); +MODULE_PARM_DESC(rcv_intr_timeout, "Receive interrupt mitigation timeout in ns"); + +uint rcv_intr_count = 16; /* same as qib */ +module_param(rcv_intr_count, uint, S_IRUGO); +MODULE_PARM_DESC(rcv_intr_count, "Receive interrupt mitigation count"); + +ushort link_crc_mask = SUPPORTED_CRCS; +module_param(link_crc_mask, ushort, S_IRUGO); +MODULE_PARM_DESC(link_crc_mask, "CRCs to use on the link"); + +uint loopback; +module_param_named(loopback, loopback, uint, S_IRUGO); +MODULE_PARM_DESC(loopback, "Put into loopback mode (1 = serdes, 3 = external cable"); + +/* Other driver tunables */ +uint rcv_intr_dynamic = 1; /* enable dynamic mode for rcv int mitigation*/ +static ushort crc_14b_sideband = 1; +static uint use_flr = 1; +uint quick_linkup; /* skip LNI */ + +struct flag_table { + u64 flag; /* the flag */ + char *str; /* description string */ + u16 extra; /* extra information */ + u16 unused0; + u32 unused1; +}; + +/* str must be a string constant */ +#define FLAG_ENTRY(str, extra, flag) {flag, str, extra} +#define FLAG_ENTRY0(str, flag) {flag, str, 0} + +/* Send Error Consequences */ +#define SEC_WRITE_DROPPED 0x1 +#define SEC_PACKET_DROPPED 0x2 +#define SEC_SC_HALTED 0x4 /* per-context only */ +#define SEC_SPC_FREEZE 0x8 /* per-HFI only */ + +#define VL15CTXT 1 +#define MIN_KERNEL_KCTXTS 2 +#define NUM_MAP_REGS 32 + +/* Bit offset into the GUID which carries HFI id information */ +#define GUID_HFI_INDEX_SHIFT 39 + +/* extract the emulation revision */ +#define emulator_rev(dd) ((dd)->irev >> 8) +/* parallel and serial emulation versions are 3 and 4 respectively */ +#define is_emulator_p(dd) ((((dd)->irev) & 0xf) == 3) +#define is_emulator_s(dd) ((((dd)->irev) & 0xf) == 4) + +/* RSM fields */ + +/* packet type */ +#define IB_PACKET_TYPE 2ull +#define QW_SHIFT 6ull +/* QPN[7..1] */ +#define QPN_WIDTH 7ull + +/* LRH.BTH: QW 0, OFFSET 48 - for match */ +#define LRH_BTH_QW 0ull +#define LRH_BTH_BIT_OFFSET 48ull +#define LRH_BTH_OFFSET(off) ((LRH_BTH_QW << QW_SHIFT) | (off)) +#define LRH_BTH_MATCH_OFFSET LRH_BTH_OFFSET(LRH_BTH_BIT_OFFSET) +#define LRH_BTH_SELECT +#define LRH_BTH_MASK 3ull +#define LRH_BTH_VALUE 2ull + +/* LRH.SC[3..0] QW 0, OFFSET 56 - for match */ +#define LRH_SC_QW 0ull +#define LRH_SC_BIT_OFFSET 56ull +#define LRH_SC_OFFSET(off) ((LRH_SC_QW << QW_SHIFT) | (off)) +#define LRH_SC_MATCH_OFFSET LRH_SC_OFFSET(LRH_SC_BIT_OFFSET) +#define LRH_SC_MASK 128ull +#define LRH_SC_VALUE 0ull + +/* SC[n..0] QW 0, OFFSET 60 - for select */ +#define LRH_SC_SELECT_OFFSET ((LRH_SC_QW << QW_SHIFT) | (60ull)) + +/* QPN[m+n:1] QW 1, OFFSET 1 */ +#define QPN_SELECT_OFFSET ((1ull << QW_SHIFT) | (1ull)) + +/* defines to build power on SC2VL table */ +#define SC2VL_VAL( \ + num, \ + sc0, sc0val, \ + sc1, sc1val, \ + sc2, sc2val, \ + sc3, sc3val, \ + sc4, sc4val, \ + sc5, sc5val, \ + sc6, sc6val, \ + sc7, sc7val) \ +( \ + ((u64)(sc0val) << SEND_SC2VLT##num##_SC##sc0##_SHIFT) | \ + ((u64)(sc1val) << SEND_SC2VLT##num##_SC##sc1##_SHIFT) | \ + ((u64)(sc2val) << SEND_SC2VLT##num##_SC##sc2##_SHIFT) | \ + ((u64)(sc3val) << SEND_SC2VLT##num##_SC##sc3##_SHIFT) | \ + ((u64)(sc4val) << SEND_SC2VLT##num##_SC##sc4##_SHIFT) | \ + ((u64)(sc5val) << SEND_SC2VLT##num##_SC##sc5##_SHIFT) | \ + ((u64)(sc6val) << SEND_SC2VLT##num##_SC##sc6##_SHIFT) | \ + ((u64)(sc7val) << SEND_SC2VLT##num##_SC##sc7##_SHIFT) \ +) + +#define DC_SC_VL_VAL( \ + range, \ + e0, e0val, \ + e1, e1val, \ + e2, e2val, \ + e3, e3val, \ + e4, e4val, \ + e5, e5val, \ + e6, e6val, \ + e7, e7val, \ + e8, e8val, \ + e9, e9val, \ + e10, e10val, \ + e11, e11val, \ + e12, e12val, \ + e13, e13val, \ + e14, e14val, \ + e15, e15val) \ +( \ + ((u64)(e0val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e0##_SHIFT) | \ + ((u64)(e1val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e1##_SHIFT) | \ + ((u64)(e2val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e2##_SHIFT) | \ + ((u64)(e3val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e3##_SHIFT) | \ + ((u64)(e4val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e4##_SHIFT) | \ + ((u64)(e5val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e5##_SHIFT) | \ + ((u64)(e6val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e6##_SHIFT) | \ + ((u64)(e7val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e7##_SHIFT) | \ + ((u64)(e8val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e8##_SHIFT) | \ + ((u64)(e9val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e9##_SHIFT) | \ + ((u64)(e10val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e10##_SHIFT) | \ + ((u64)(e11val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e11##_SHIFT) | \ + ((u64)(e12val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e12##_SHIFT) | \ + ((u64)(e13val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e13##_SHIFT) | \ + ((u64)(e14val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e14##_SHIFT) | \ + ((u64)(e15val) << DCC_CFG_SC_VL_TABLE_##range##_ENTRY##e15##_SHIFT) \ +) + +/* all CceStatus sub-block freeze bits */ +#define ALL_FROZE (CCE_STATUS_SDMA_FROZE_SMASK \ + | CCE_STATUS_RXE_FROZE_SMASK \ + | CCE_STATUS_TXE_FROZE_SMASK \ + | CCE_STATUS_TXE_PIO_FROZE_SMASK) +/* all CceStatus sub-block TXE pause bits */ +#define ALL_TXE_PAUSE (CCE_STATUS_TXE_PIO_PAUSED_SMASK \ + | CCE_STATUS_TXE_PAUSED_SMASK \ + | CCE_STATUS_SDMA_PAUSED_SMASK) +/* all CceStatus sub-block RXE pause bits */ +#define ALL_RXE_PAUSE CCE_STATUS_RXE_PAUSED_SMASK + +/* + * CCE Error flags. + */ +static struct flag_table cce_err_status_flags[] = { +/* 0*/ FLAG_ENTRY0("CceCsrParityErr", + CCE_ERR_STATUS_CCE_CSR_PARITY_ERR_SMASK), +/* 1*/ FLAG_ENTRY0("CceCsrReadBadAddrErr", + CCE_ERR_STATUS_CCE_CSR_READ_BAD_ADDR_ERR_SMASK), +/* 2*/ FLAG_ENTRY0("CceCsrWriteBadAddrErr", + CCE_ERR_STATUS_CCE_CSR_WRITE_BAD_ADDR_ERR_SMASK), +/* 3*/ FLAG_ENTRY0("CceTrgtAsyncFifoParityErr", + CCE_ERR_STATUS_CCE_TRGT_ASYNC_FIFO_PARITY_ERR_SMASK), +/* 4*/ FLAG_ENTRY0("CceTrgtAccessErr", + CCE_ERR_STATUS_CCE_TRGT_ACCESS_ERR_SMASK), +/* 5*/ FLAG_ENTRY0("CceRspdDataParityErr", + CCE_ERR_STATUS_CCE_RSPD_DATA_PARITY_ERR_SMASK), +/* 6*/ FLAG_ENTRY0("CceCli0AsyncFifoParityErr", + CCE_ERR_STATUS_CCE_CLI0_ASYNC_FIFO_PARITY_ERR_SMASK), +/* 7*/ FLAG_ENTRY0("CceCsrCfgBusParityErr", + CCE_ERR_STATUS_CCE_CSR_CFG_BUS_PARITY_ERR_SMASK), +/* 8*/ FLAG_ENTRY0("CceCli2AsyncFifoParityErr", + CCE_ERR_STATUS_CCE_CLI2_ASYNC_FIFO_PARITY_ERR_SMASK), +/* 9*/ FLAG_ENTRY0("CceCli1AsyncFifoPioCrdtParityErr", + CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_PIO_CRDT_PARITY_ERR_SMASK), +/*10*/ FLAG_ENTRY0("CceCli1AsyncFifoPioCrdtParityErr", + CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_SDMA_HD_PARITY_ERR_SMASK), +/*11*/ FLAG_ENTRY0("CceCli1AsyncFifoRxdmaParityError", + CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_RXDMA_PARITY_ERROR_SMASK), +/*12*/ FLAG_ENTRY0("CceCli1AsyncFifoDbgParityError", + CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_DBG_PARITY_ERROR_SMASK), +/*13*/ FLAG_ENTRY0("PcicRetryMemCorErr", + CCE_ERR_STATUS_PCIC_RETRY_MEM_COR_ERR_SMASK), +/*14*/ FLAG_ENTRY0("PcicRetryMemCorErr", + CCE_ERR_STATUS_PCIC_RETRY_SOT_MEM_COR_ERR_SMASK), +/*15*/ FLAG_ENTRY0("PcicPostHdQCorErr", + CCE_ERR_STATUS_PCIC_POST_HD_QCOR_ERR_SMASK), +/*16*/ FLAG_ENTRY0("PcicPostHdQCorErr", + CCE_ERR_STATUS_PCIC_POST_DAT_QCOR_ERR_SMASK), +/*17*/ FLAG_ENTRY0("PcicPostHdQCorErr", + CCE_ERR_STATUS_PCIC_CPL_HD_QCOR_ERR_SMASK), +/*18*/ FLAG_ENTRY0("PcicCplDatQCorErr", + CCE_ERR_STATUS_PCIC_CPL_DAT_QCOR_ERR_SMASK), +/*19*/ FLAG_ENTRY0("PcicNPostHQParityErr", + CCE_ERR_STATUS_PCIC_NPOST_HQ_PARITY_ERR_SMASK), +/*20*/ FLAG_ENTRY0("PcicNPostDatQParityErr", + CCE_ERR_STATUS_PCIC_NPOST_DAT_QPARITY_ERR_SMASK), +/*21*/ FLAG_ENTRY0("PcicRetryMemUncErr", + CCE_ERR_STATUS_PCIC_RETRY_MEM_UNC_ERR_SMASK), +/*22*/ FLAG_ENTRY0("PcicRetrySotMemUncErr", + CCE_ERR_STATUS_PCIC_RETRY_SOT_MEM_UNC_ERR_SMASK), +/*23*/ FLAG_ENTRY0("PcicPostHdQUncErr", + CCE_ERR_STATUS_PCIC_POST_HD_QUNC_ERR_SMASK), +/*24*/ FLAG_ENTRY0("PcicPostDatQUncErr", + CCE_ERR_STATUS_PCIC_POST_DAT_QUNC_ERR_SMASK), +/*25*/ FLAG_ENTRY0("PcicCplHdQUncErr", + CCE_ERR_STATUS_PCIC_CPL_HD_QUNC_ERR_SMASK), +/*26*/ FLAG_ENTRY0("PcicCplDatQUncErr", + CCE_ERR_STATUS_PCIC_CPL_DAT_QUNC_ERR_SMASK), +/*27*/ FLAG_ENTRY0("PcicTransmitFrontParityErr", + CCE_ERR_STATUS_PCIC_TRANSMIT_FRONT_PARITY_ERR_SMASK), +/*28*/ FLAG_ENTRY0("PcicTransmitBackParityErr", + CCE_ERR_STATUS_PCIC_TRANSMIT_BACK_PARITY_ERR_SMASK), +/*29*/ FLAG_ENTRY0("PcicReceiveParityErr", + CCE_ERR_STATUS_PCIC_RECEIVE_PARITY_ERR_SMASK), +/*30*/ FLAG_ENTRY0("CceTrgtCplTimeoutErr", + CCE_ERR_STATUS_CCE_TRGT_CPL_TIMEOUT_ERR_SMASK), +/*31*/ FLAG_ENTRY0("LATriggered", + CCE_ERR_STATUS_LA_TRIGGERED_SMASK), +/*32*/ FLAG_ENTRY0("CceSegReadBadAddrErr", + CCE_ERR_STATUS_CCE_SEG_READ_BAD_ADDR_ERR_SMASK), +/*33*/ FLAG_ENTRY0("CceSegWriteBadAddrErr", + CCE_ERR_STATUS_CCE_SEG_WRITE_BAD_ADDR_ERR_SMASK), +/*34*/ FLAG_ENTRY0("CceRcplAsyncFifoParityErr", + CCE_ERR_STATUS_CCE_RCPL_ASYNC_FIFO_PARITY_ERR_SMASK), +/*35*/ FLAG_ENTRY0("CceRxdmaConvFifoParityErr", + CCE_ERR_STATUS_CCE_RXDMA_CONV_FIFO_PARITY_ERR_SMASK), +/*36*/ FLAG_ENTRY0("CceMsixTableCorErr", + CCE_ERR_STATUS_CCE_MSIX_TABLE_COR_ERR_SMASK), +/*37*/ FLAG_ENTRY0("CceMsixTableUncErr", + CCE_ERR_STATUS_CCE_MSIX_TABLE_UNC_ERR_SMASK), +/*38*/ FLAG_ENTRY0("CceIntMapCorErr", + CCE_ERR_STATUS_CCE_INT_MAP_COR_ERR_SMASK), +/*39*/ FLAG_ENTRY0("CceIntMapUncErr", + CCE_ERR_STATUS_CCE_INT_MAP_UNC_ERR_SMASK), +/*40*/ FLAG_ENTRY0("CceMsixCsrParityErr", + CCE_ERR_STATUS_CCE_MSIX_CSR_PARITY_ERR_SMASK), +/*41-63 reserved*/ +}; + +/* + * Misc Error flags + */ +#define MES(text) MISC_ERR_STATUS_MISC_##text##_ERR_SMASK +static struct flag_table misc_err_status_flags[] = { +/* 0*/ FLAG_ENTRY0("CSR_PARITY", MES(CSR_PARITY)), +/* 1*/ FLAG_ENTRY0("CSR_READ_BAD_ADDR", MES(CSR_READ_BAD_ADDR)), +/* 2*/ FLAG_ENTRY0("CSR_WRITE_BAD_ADDR", MES(CSR_WRITE_BAD_ADDR)), +/* 3*/ FLAG_ENTRY0("SBUS_WRITE_FAILED", MES(SBUS_WRITE_FAILED)), +/* 4*/ FLAG_ENTRY0("KEY_MISMATCH", MES(KEY_MISMATCH)), +/* 5*/ FLAG_ENTRY0("FW_AUTH_FAILED", MES(FW_AUTH_FAILED)), +/* 6*/ FLAG_ENTRY0("EFUSE_CSR_PARITY", MES(EFUSE_CSR_PARITY)), +/* 7*/ FLAG_ENTRY0("EFUSE_READ_BAD_ADDR", MES(EFUSE_READ_BAD_ADDR)), +/* 8*/ FLAG_ENTRY0("EFUSE_WRITE", MES(EFUSE_WRITE)), +/* 9*/ FLAG_ENTRY0("EFUSE_DONE_PARITY", MES(EFUSE_DONE_PARITY)), +/*10*/ FLAG_ENTRY0("INVALID_EEP_CMD", MES(INVALID_EEP_CMD)), +/*11*/ FLAG_ENTRY0("MBIST_FAIL", MES(MBIST_FAIL)), +/*12*/ FLAG_ENTRY0("PLL_LOCK_FAIL", MES(PLL_LOCK_FAIL)) +}; + +/* + * TXE PIO Error flags and consequences + */ +static struct flag_table pio_err_status_flags[] = { +/* 0*/ FLAG_ENTRY("PioWriteBadCtxt", + SEC_WRITE_DROPPED, + SEND_PIO_ERR_STATUS_PIO_WRITE_BAD_CTXT_ERR_SMASK), +/* 1*/ FLAG_ENTRY("PioWriteAddrParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_WRITE_ADDR_PARITY_ERR_SMASK), +/* 2*/ FLAG_ENTRY("PioCsrParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_CSR_PARITY_ERR_SMASK), +/* 3*/ FLAG_ENTRY("PioSbMemFifo0", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_SB_MEM_FIFO0_ERR_SMASK), +/* 4*/ FLAG_ENTRY("PioSbMemFifo1", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_SB_MEM_FIFO1_ERR_SMASK), +/* 5*/ FLAG_ENTRY("PioPccFifoParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PCC_FIFO_PARITY_ERR_SMASK), +/* 6*/ FLAG_ENTRY("PioPecFifoParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PEC_FIFO_PARITY_ERR_SMASK), +/* 7*/ FLAG_ENTRY("PioSbrdctlCrrelParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_SBRDCTL_CRREL_PARITY_ERR_SMASK), +/* 8*/ FLAG_ENTRY("PioSbrdctrlCrrelFifoParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_SBRDCTRL_CRREL_FIFO_PARITY_ERR_SMASK), +/* 9*/ FLAG_ENTRY("PioPktEvictFifoParityErr", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PKT_EVICT_FIFO_PARITY_ERR_SMASK), +/*10*/ FLAG_ENTRY("PioSmPktResetParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_SM_PKT_RESET_PARITY_ERR_SMASK), +/*11*/ FLAG_ENTRY("PioVlLenMemBank0Unc", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK0_UNC_ERR_SMASK), +/*12*/ FLAG_ENTRY("PioVlLenMemBank1Unc", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK1_UNC_ERR_SMASK), +/*13*/ FLAG_ENTRY("PioVlLenMemBank0Cor", + 0, + SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK0_COR_ERR_SMASK), +/*14*/ FLAG_ENTRY("PioVlLenMemBank1Cor", + 0, + SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK1_COR_ERR_SMASK), +/*15*/ FLAG_ENTRY("PioCreditRetFifoParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_CREDIT_RET_FIFO_PARITY_ERR_SMASK), +/*16*/ FLAG_ENTRY("PioPpmcPblFifo", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PPMC_PBL_FIFO_ERR_SMASK), +/*17*/ FLAG_ENTRY("PioInitSmIn", + 0, + SEND_PIO_ERR_STATUS_PIO_INIT_SM_IN_ERR_SMASK), +/*18*/ FLAG_ENTRY("PioPktEvictSmOrArbSm", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PKT_EVICT_SM_OR_ARB_SM_ERR_SMASK), +/*19*/ FLAG_ENTRY("PioHostAddrMemUnc", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_HOST_ADDR_MEM_UNC_ERR_SMASK), +/*20*/ FLAG_ENTRY("PioHostAddrMemCor", + 0, + SEND_PIO_ERR_STATUS_PIO_HOST_ADDR_MEM_COR_ERR_SMASK), +/*21*/ FLAG_ENTRY("PioWriteDataParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_WRITE_DATA_PARITY_ERR_SMASK), +/*22*/ FLAG_ENTRY("PioStateMachine", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_STATE_MACHINE_ERR_SMASK), +/*23*/ FLAG_ENTRY("PioWriteQwValidParity", + SEC_WRITE_DROPPED|SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_WRITE_QW_VALID_PARITY_ERR_SMASK), +/*24*/ FLAG_ENTRY("PioBlockQwCountParity", + SEC_WRITE_DROPPED|SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_BLOCK_QW_COUNT_PARITY_ERR_SMASK), +/*25*/ FLAG_ENTRY("PioVlfVlLenParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_VLF_VL_LEN_PARITY_ERR_SMASK), +/*26*/ FLAG_ENTRY("PioVlfSopParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_VLF_SOP_PARITY_ERR_SMASK), +/*27*/ FLAG_ENTRY("PioVlFifoParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_VL_FIFO_PARITY_ERR_SMASK), +/*28*/ FLAG_ENTRY("PioPpmcBqcMemParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PPMC_BQC_MEM_PARITY_ERR_SMASK), +/*29*/ FLAG_ENTRY("PioPpmcSopLen", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PPMC_SOP_LEN_ERR_SMASK), +/*30-31 reserved*/ +/*32*/ FLAG_ENTRY("PioCurrentFreeCntParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_CURRENT_FREE_CNT_PARITY_ERR_SMASK), +/*33*/ FLAG_ENTRY("PioLastReturnedCntParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_LAST_RETURNED_CNT_PARITY_ERR_SMASK), +/*34*/ FLAG_ENTRY("PioPccSopHeadParity", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PCC_SOP_HEAD_PARITY_ERR_SMASK), +/*35*/ FLAG_ENTRY("PioPecSopHeadParityErr", + SEC_SPC_FREEZE, + SEND_PIO_ERR_STATUS_PIO_PEC_SOP_HEAD_PARITY_ERR_SMASK), +/*36-63 reserved*/ +}; + +/* TXE PIO errors that cause an SPC freeze */ +#define ALL_PIO_FREEZE_ERR \ + (SEND_PIO_ERR_STATUS_PIO_WRITE_ADDR_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_CSR_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_SB_MEM_FIFO0_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_SB_MEM_FIFO1_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PCC_FIFO_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PEC_FIFO_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_SBRDCTL_CRREL_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_SBRDCTRL_CRREL_FIFO_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PKT_EVICT_FIFO_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_SM_PKT_RESET_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK0_UNC_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK1_UNC_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_CREDIT_RET_FIFO_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PPMC_PBL_FIFO_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PKT_EVICT_SM_OR_ARB_SM_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_HOST_ADDR_MEM_UNC_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_WRITE_DATA_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_STATE_MACHINE_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_WRITE_QW_VALID_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_BLOCK_QW_COUNT_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_VLF_VL_LEN_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_VLF_SOP_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_VL_FIFO_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PPMC_BQC_MEM_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PPMC_SOP_LEN_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_CURRENT_FREE_CNT_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_LAST_RETURNED_CNT_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PCC_SOP_HEAD_PARITY_ERR_SMASK \ + | SEND_PIO_ERR_STATUS_PIO_PEC_SOP_HEAD_PARITY_ERR_SMASK) + +/* + * TXE SDMA Error flags + */ +static struct flag_table sdma_err_status_flags[] = { +/* 0*/ FLAG_ENTRY0("SDmaRpyTagErr", + SEND_DMA_ERR_STATUS_SDMA_RPY_TAG_ERR_SMASK), +/* 1*/ FLAG_ENTRY0("SDmaCsrParityErr", + SEND_DMA_ERR_STATUS_SDMA_CSR_PARITY_ERR_SMASK), +/* 2*/ FLAG_ENTRY0("SDmaPcieReqTrackingUncErr", + SEND_DMA_ERR_STATUS_SDMA_PCIE_REQ_TRACKING_UNC_ERR_SMASK), +/* 3*/ FLAG_ENTRY0("SDmaPcieReqTrackingCorErr", + SEND_DMA_ERR_STATUS_SDMA_PCIE_REQ_TRACKING_COR_ERR_SMASK), +/*04-63 reserved*/ +}; + +/* TXE SDMA errors that cause an SPC freeze */ +#define ALL_SDMA_FREEZE_ERR \ + (SEND_DMA_ERR_STATUS_SDMA_RPY_TAG_ERR_SMASK \ + | SEND_DMA_ERR_STATUS_SDMA_CSR_PARITY_ERR_SMASK \ + | SEND_DMA_ERR_STATUS_SDMA_PCIE_REQ_TRACKING_UNC_ERR_SMASK) + +/* + * TXE Egress Error flags + */ +#define SEES(text) SEND_EGRESS_ERR_STATUS_##text##_ERR_SMASK +static struct flag_table egress_err_status_flags[] = { +/* 0*/ FLAG_ENTRY0("TxPktIntegrityMemCorErr", SEES(TX_PKT_INTEGRITY_MEM_COR)), +/* 1*/ FLAG_ENTRY0("TxPktIntegrityMemUncErr", SEES(TX_PKT_INTEGRITY_MEM_UNC)), +/* 2 reserved */ +/* 3*/ FLAG_ENTRY0("TxEgressFifoUnderrunOrParityErr", + SEES(TX_EGRESS_FIFO_UNDERRUN_OR_PARITY)), +/* 4*/ FLAG_ENTRY0("TxLinkdownErr", SEES(TX_LINKDOWN)), +/* 5*/ FLAG_ENTRY0("TxIncorrectLinkStateErr", SEES(TX_INCORRECT_LINK_STATE)), +/* 6 reserved */ +/* 7*/ FLAG_ENTRY0("TxPioLaunchIntfParityErr", + SEES(TX_PIO_LAUNCH_INTF_PARITY)), +/* 8*/ FLAG_ENTRY0("TxSdmaLaunchIntfParityErr", + SEES(TX_SDMA_LAUNCH_INTF_PARITY)), +/* 9-10 reserved */ +/*11*/ FLAG_ENTRY0("TxSbrdCtlStateMachineParityErr", + SEES(TX_SBRD_CTL_STATE_MACHINE_PARITY)), +/*12*/ FLAG_ENTRY0("TxIllegalVLErr", SEES(TX_ILLEGAL_VL)), +/*13*/ FLAG_ENTRY0("TxLaunchCsrParityErr", SEES(TX_LAUNCH_CSR_PARITY)), +/*14*/ FLAG_ENTRY0("TxSbrdCtlCsrParityErr", SEES(TX_SBRD_CTL_CSR_PARITY)), +/*15*/ FLAG_ENTRY0("TxConfigParityErr", SEES(TX_CONFIG_PARITY)), +/*16*/ FLAG_ENTRY0("TxSdma0DisallowedPacketErr", + SEES(TX_SDMA0_DISALLOWED_PACKET)), +/*17*/ FLAG_ENTRY0("TxSdma1DisallowedPacketErr", + SEES(TX_SDMA1_DISALLOWED_PACKET)), +/*18*/ FLAG_ENTRY0("TxSdma2DisallowedPacketErr", + SEES(TX_SDMA2_DISALLOWED_PACKET)), +/*19*/ FLAG_ENTRY0("TxSdma3DisallowedPacketErr", + SEES(TX_SDMA3_DISALLOWED_PACKET)), +/*20*/ FLAG_ENTRY0("TxSdma4DisallowedPacketErr", + SEES(TX_SDMA4_DISALLOWED_PACKET)), +/*21*/ FLAG_ENTRY0("TxSdma5DisallowedPacketErr", + SEES(TX_SDMA5_DISALLOWED_PACKET)), +/*22*/ FLAG_ENTRY0("TxSdma6DisallowedPacketErr", + SEES(TX_SDMA6_DISALLOWED_PACKET)), +/*23*/ FLAG_ENTRY0("TxSdma7DisallowedPacketErr", + SEES(TX_SDMA7_DISALLOWED_PACKET)), +/*24*/ FLAG_ENTRY0("TxSdma8DisallowedPacketErr", + SEES(TX_SDMA8_DISALLOWED_PACKET)), +/*25*/ FLAG_ENTRY0("TxSdma9DisallowedPacketErr", + SEES(TX_SDMA9_DISALLOWED_PACKET)), +/*26*/ FLAG_ENTRY0("TxSdma10DisallowedPacketErr", + SEES(TX_SDMA10_DISALLOWED_PACKET)), +/*27*/ FLAG_ENTRY0("TxSdma11DisallowedPacketErr", + SEES(TX_SDMA11_DISALLOWED_PACKET)), +/*28*/ FLAG_ENTRY0("TxSdma12DisallowedPacketErr", + SEES(TX_SDMA12_DISALLOWED_PACKET)), +/*29*/ FLAG_ENTRY0("TxSdma13DisallowedPacketErr", + SEES(TX_SDMA13_DISALLOWED_PACKET)), +/*30*/ FLAG_ENTRY0("TxSdma14DisallowedPacketErr", + SEES(TX_SDMA14_DISALLOWED_PACKET)), +/*31*/ FLAG_ENTRY0("TxSdma15DisallowedPacketErr", + SEES(TX_SDMA15_DISALLOWED_PACKET)), +/*32*/ FLAG_ENTRY0("TxLaunchFifo0UncOrParityErr", + SEES(TX_LAUNCH_FIFO0_UNC_OR_PARITY)), +/*33*/ FLAG_ENTRY0("TxLaunchFifo1UncOrParityErr", + SEES(TX_LAUNCH_FIFO1_UNC_OR_PARITY)), +/*34*/ FLAG_ENTRY0("TxLaunchFifo2UncOrParityErr", + SEES(TX_LAUNCH_FIFO2_UNC_OR_PARITY)), +/*35*/ FLAG_ENTRY0("TxLaunchFifo3UncOrParityErr", + SEES(TX_LAUNCH_FIFO3_UNC_OR_PARITY)), +/*36*/ FLAG_ENTRY0("TxLaunchFifo4UncOrParityErr", + SEES(TX_LAUNCH_FIFO4_UNC_OR_PARITY)), +/*37*/ FLAG_ENTRY0("TxLaunchFifo5UncOrParityErr", + SEES(TX_LAUNCH_FIFO5_UNC_OR_PARITY)), +/*38*/ FLAG_ENTRY0("TxLaunchFifo6UncOrParityErr", + SEES(TX_LAUNCH_FIFO6_UNC_OR_PARITY)), +/*39*/ FLAG_ENTRY0("TxLaunchFifo7UncOrParityErr", + SEES(TX_LAUNCH_FIFO7_UNC_OR_PARITY)), +/*40*/ FLAG_ENTRY0("TxLaunchFifo8UncOrParityErr", + SEES(TX_LAUNCH_FIFO8_UNC_OR_PARITY)), +/*41*/ FLAG_ENTRY0("TxCreditReturnParityErr", SEES(TX_CREDIT_RETURN_PARITY)), +/*42*/ FLAG_ENTRY0("TxSbHdrUncErr", SEES(TX_SB_HDR_UNC)), +/*43*/ FLAG_ENTRY0("TxReadSdmaMemoryUncErr", SEES(TX_READ_SDMA_MEMORY_UNC)), +/*44*/ FLAG_ENTRY0("TxReadPioMemoryUncErr", SEES(TX_READ_PIO_MEMORY_UNC)), +/*45*/ FLAG_ENTRY0("TxEgressFifoUncErr", SEES(TX_EGRESS_FIFO_UNC)), +/*46*/ FLAG_ENTRY0("TxHcrcInsertionErr", SEES(TX_HCRC_INSERTION)), +/*47*/ FLAG_ENTRY0("TxCreditReturnVLErr", SEES(TX_CREDIT_RETURN_VL)), +/*48*/ FLAG_ENTRY0("TxLaunchFifo0CorErr", SEES(TX_LAUNCH_FIFO0_COR)), +/*49*/ FLAG_ENTRY0("TxLaunchFifo1CorErr", SEES(TX_LAUNCH_FIFO1_COR)), +/*50*/ FLAG_ENTRY0("TxLaunchFifo2CorErr", SEES(TX_LAUNCH_FIFO2_COR)), +/*51*/ FLAG_ENTRY0("TxLaunchFifo3CorErr", SEES(TX_LAUNCH_FIFO3_COR)), +/*52*/ FLAG_ENTRY0("TxLaunchFifo4CorErr", SEES(TX_LAUNCH_FIFO4_COR)), +/*53*/ FLAG_ENTRY0("TxLaunchFifo5CorErr", SEES(TX_LAUNCH_FIFO5_COR)), +/*54*/ FLAG_ENTRY0("TxLaunchFifo6CorErr", SEES(TX_LAUNCH_FIFO6_COR)), +/*55*/ FLAG_ENTRY0("TxLaunchFifo7CorErr", SEES(TX_LAUNCH_FIFO7_COR)), +/*56*/ FLAG_ENTRY0("TxLaunchFifo8CorErr", SEES(TX_LAUNCH_FIFO8_COR)), +/*57*/ FLAG_ENTRY0("TxCreditOverrunErr", SEES(TX_CREDIT_OVERRUN)), +/*58*/ FLAG_ENTRY0("TxSbHdrCorErr", SEES(TX_SB_HDR_COR)), +/*59*/ FLAG_ENTRY0("TxReadSdmaMemoryCorErr", SEES(TX_READ_SDMA_MEMORY_COR)), +/*60*/ FLAG_ENTRY0("TxReadPioMemoryCorErr", SEES(TX_READ_PIO_MEMORY_COR)), +/*61*/ FLAG_ENTRY0("TxEgressFifoCorErr", SEES(TX_EGRESS_FIFO_COR)), +/*62*/ FLAG_ENTRY0("TxReadSdmaMemoryCsrUncErr", + SEES(TX_READ_SDMA_MEMORY_CSR_UNC)), +/*63*/ FLAG_ENTRY0("TxReadPioMemoryCsrUncErr", + SEES(TX_READ_PIO_MEMORY_CSR_UNC)), +}; + +/* + * TXE Egress Error Info flags + */ +#define SEEI(text) SEND_EGRESS_ERR_INFO_##text##_ERR_SMASK +static struct flag_table egress_err_info_flags[] = { +/* 0*/ FLAG_ENTRY0("Reserved", 0ull), +/* 1*/ FLAG_ENTRY0("VLErr", SEEI(VL)), +/* 2*/ FLAG_ENTRY0("JobKeyErr", SEEI(JOB_KEY)), +/* 3*/ FLAG_ENTRY0("JobKeyErr", SEEI(JOB_KEY)), +/* 4*/ FLAG_ENTRY0("PartitionKeyErr", SEEI(PARTITION_KEY)), +/* 5*/ FLAG_ENTRY0("SLIDErr", SEEI(SLID)), +/* 6*/ FLAG_ENTRY0("OpcodeErr", SEEI(OPCODE)), +/* 7*/ FLAG_ENTRY0("VLMappingErr", SEEI(VL_MAPPING)), +/* 8*/ FLAG_ENTRY0("RawErr", SEEI(RAW)), +/* 9*/ FLAG_ENTRY0("RawIPv6Err", SEEI(RAW_IPV6)), +/*10*/ FLAG_ENTRY0("GRHErr", SEEI(GRH)), +/*11*/ FLAG_ENTRY0("BypassErr", SEEI(BYPASS)), +/*12*/ FLAG_ENTRY0("KDETHPacketsErr", SEEI(KDETH_PACKETS)), +/*13*/ FLAG_ENTRY0("NonKDETHPacketsErr", SEEI(NON_KDETH_PACKETS)), +/*14*/ FLAG_ENTRY0("TooSmallIBPacketsErr", SEEI(TOO_SMALL_IB_PACKETS)), +/*15*/ FLAG_ENTRY0("TooSmallBypassPacketsErr", SEEI(TOO_SMALL_BYPASS_PACKETS)), +/*16*/ FLAG_ENTRY0("PbcTestErr", SEEI(PBC_TEST)), +/*17*/ FLAG_ENTRY0("BadPktLenErr", SEEI(BAD_PKT_LEN)), +/*18*/ FLAG_ENTRY0("TooLongIBPacketErr", SEEI(TOO_LONG_IB_PACKET)), +/*19*/ FLAG_ENTRY0("TooLongBypassPacketsErr", SEEI(TOO_LONG_BYPASS_PACKETS)), +/*20*/ FLAG_ENTRY0("PbcStaticRateControlErr", SEEI(PBC_STATIC_RATE_CONTROL)), +/*21*/ FLAG_ENTRY0("BypassBadPktLenErr", SEEI(BAD_PKT_LEN)), +}; + +/* TXE Egress errors that cause an SPC freeze */ +#define ALL_TXE_EGRESS_FREEZE_ERR \ + (SEES(TX_EGRESS_FIFO_UNDERRUN_OR_PARITY) \ + | SEES(TX_PIO_LAUNCH_INTF_PARITY) \ + | SEES(TX_SDMA_LAUNCH_INTF_PARITY) \ + | SEES(TX_SBRD_CTL_STATE_MACHINE_PARITY) \ + | SEES(TX_LAUNCH_CSR_PARITY) \ + | SEES(TX_SBRD_CTL_CSR_PARITY) \ + | SEES(TX_CONFIG_PARITY) \ + | SEES(TX_LAUNCH_FIFO0_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO1_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO2_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO3_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO4_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO5_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO6_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO7_UNC_OR_PARITY) \ + | SEES(TX_LAUNCH_FIFO8_UNC_OR_PARITY) \ + | SEES(TX_CREDIT_RETURN_PARITY)) + +/* + * TXE Send error flags + */ +#define SES(name) SEND_ERR_STATUS_SEND_##name##_ERR_SMASK +static struct flag_table send_err_status_flags[] = { +/* 0*/ FLAG_ENTRY0("SDmaRpyTagErr", SES(CSR_PARITY)), +/* 1*/ FLAG_ENTRY0("SendCsrReadBadAddrErr", SES(CSR_READ_BAD_ADDR)), +/* 2*/ FLAG_ENTRY0("SendCsrWriteBadAddrErr", SES(CSR_WRITE_BAD_ADDR)) +}; + +/* + * TXE Send Context Error flags and consequences + */ +static struct flag_table sc_err_status_flags[] = { +/* 0*/ FLAG_ENTRY("InconsistentSop", + SEC_PACKET_DROPPED | SEC_SC_HALTED, + SEND_CTXT_ERR_STATUS_PIO_INCONSISTENT_SOP_ERR_SMASK), +/* 1*/ FLAG_ENTRY("DisallowedPacket", + SEC_PACKET_DROPPED | SEC_SC_HALTED, + SEND_CTXT_ERR_STATUS_PIO_DISALLOWED_PACKET_ERR_SMASK), +/* 2*/ FLAG_ENTRY("WriteCrossesBoundary", + SEC_WRITE_DROPPED | SEC_SC_HALTED, + SEND_CTXT_ERR_STATUS_PIO_WRITE_CROSSES_BOUNDARY_ERR_SMASK), +/* 3*/ FLAG_ENTRY("WriteOverflow", + SEC_WRITE_DROPPED | SEC_SC_HALTED, + SEND_CTXT_ERR_STATUS_PIO_WRITE_OVERFLOW_ERR_SMASK), +/* 4*/ FLAG_ENTRY("WriteOutOfBounds", + SEC_WRITE_DROPPED | SEC_SC_HALTED, + SEND_CTXT_ERR_STATUS_PIO_WRITE_OUT_OF_BOUNDS_ERR_SMASK), +/* 5-63 reserved*/ +}; + +/* + * RXE Receive Error flags + */ +#define RXES(name) RCV_ERR_STATUS_RX_##name##_ERR_SMASK +static struct flag_table rxe_err_status_flags[] = { +/* 0*/ FLAG_ENTRY0("RxDmaCsrCorErr", RXES(DMA_CSR_COR)), +/* 1*/ FLAG_ENTRY0("RxDcIntfParityErr", RXES(DC_INTF_PARITY)), +/* 2*/ FLAG_ENTRY0("RxRcvHdrUncErr", RXES(RCV_HDR_UNC)), +/* 3*/ FLAG_ENTRY0("RxRcvHdrCorErr", RXES(RCV_HDR_COR)), +/* 4*/ FLAG_ENTRY0("RxRcvDataUncErr", RXES(RCV_DATA_UNC)), +/* 5*/ FLAG_ENTRY0("RxRcvDataCorErr", RXES(RCV_DATA_COR)), +/* 6*/ FLAG_ENTRY0("RxRcvQpMapTableUncErr", RXES(RCV_QP_MAP_TABLE_UNC)), +/* 7*/ FLAG_ENTRY0("RxRcvQpMapTableCorErr", RXES(RCV_QP_MAP_TABLE_COR)), +/* 8*/ FLAG_ENTRY0("RxRcvCsrParityErr", RXES(RCV_CSR_PARITY)), +/* 9*/ FLAG_ENTRY0("RxDcSopEopParityErr", RXES(DC_SOP_EOP_PARITY)), +/*10*/ FLAG_ENTRY0("RxDmaFlagUncErr", RXES(DMA_FLAG_UNC)), +/*11*/ FLAG_ENTRY0("RxDmaFlagCorErr", RXES(DMA_FLAG_COR)), +/*12*/ FLAG_ENTRY0("RxRcvFsmEncodingErr", RXES(RCV_FSM_ENCODING)), +/*13*/ FLAG_ENTRY0("RxRbufFreeListUncErr", RXES(RBUF_FREE_LIST_UNC)), +/*14*/ FLAG_ENTRY0("RxRbufFreeListCorErr", RXES(RBUF_FREE_LIST_COR)), +/*15*/ FLAG_ENTRY0("RxRbufLookupDesRegUncErr", RXES(RBUF_LOOKUP_DES_REG_UNC)), +/*16*/ FLAG_ENTRY0("RxRbufLookupDesRegUncCorErr", + RXES(RBUF_LOOKUP_DES_REG_UNC_COR)), +/*17*/ FLAG_ENTRY0("RxRbufLookupDesUncErr", RXES(RBUF_LOOKUP_DES_UNC)), +/*18*/ FLAG_ENTRY0("RxRbufLookupDesCorErr", RXES(RBUF_LOOKUP_DES_COR)), +/*19*/ FLAG_ENTRY0("RxRbufBlockListReadUncErr", + RXES(RBUF_BLOCK_LIST_READ_UNC)), +/*20*/ FLAG_ENTRY0("RxRbufBlockListReadCorErr", + RXES(RBUF_BLOCK_LIST_READ_COR)), +/*21*/ FLAG_ENTRY0("RxRbufCsrQHeadBufNumParityErr", + RXES(RBUF_CSR_QHEAD_BUF_NUM_PARITY)), +/*22*/ FLAG_ENTRY0("RxRbufCsrQEntCntParityErr", + RXES(RBUF_CSR_QENT_CNT_PARITY)), +/*23*/ FLAG_ENTRY0("RxRbufCsrQNextBufParityErr", + RXES(RBUF_CSR_QNEXT_BUF_PARITY)), +/*24*/ FLAG_ENTRY0("RxRbufCsrQVldBitParityErr", + RXES(RBUF_CSR_QVLD_BIT_PARITY)), +/*25*/ FLAG_ENTRY0("RxRbufCsrQHdPtrParityErr", RXES(RBUF_CSR_QHD_PTR_PARITY)), +/*26*/ FLAG_ENTRY0("RxRbufCsrQTlPtrParityErr", RXES(RBUF_CSR_QTL_PTR_PARITY)), +/*27*/ FLAG_ENTRY0("RxRbufCsrQNumOfPktParityErr", + RXES(RBUF_CSR_QNUM_OF_PKT_PARITY)), +/*28*/ FLAG_ENTRY0("RxRbufCsrQEOPDWParityErr", RXES(RBUF_CSR_QEOPDW_PARITY)), +/*29*/ FLAG_ENTRY0("RxRbufCtxIdParityErr", RXES(RBUF_CTX_ID_PARITY)), +/*30*/ FLAG_ENTRY0("RxRBufBadLookupErr", RXES(RBUF_BAD_LOOKUP)), +/*31*/ FLAG_ENTRY0("RxRbufFullErr", RXES(RBUF_FULL)), +/*32*/ FLAG_ENTRY0("RxRbufEmptyErr", RXES(RBUF_EMPTY)), +/*33*/ FLAG_ENTRY0("RxRbufFlRdAddrParityErr", RXES(RBUF_FL_RD_ADDR_PARITY)), +/*34*/ FLAG_ENTRY0("RxRbufFlWrAddrParityErr", RXES(RBUF_FL_WR_ADDR_PARITY)), +/*35*/ FLAG_ENTRY0("RxRbufFlInitdoneParityErr", + RXES(RBUF_FL_INITDONE_PARITY)), +/*36*/ FLAG_ENTRY0("RxRbufFlInitWrAddrParityErr", + RXES(RBUF_FL_INIT_WR_ADDR_PARITY)), +/*37*/ FLAG_ENTRY0("RxRbufNextFreeBufUncErr", RXES(RBUF_NEXT_FREE_BUF_UNC)), +/*38*/ FLAG_ENTRY0("RxRbufNextFreeBufCorErr", RXES(RBUF_NEXT_FREE_BUF_COR)), +/*39*/ FLAG_ENTRY0("RxLookupDesPart1UncErr", RXES(LOOKUP_DES_PART1_UNC)), +/*40*/ FLAG_ENTRY0("RxLookupDesPart1UncCorErr", + RXES(LOOKUP_DES_PART1_UNC_COR)), +/*41*/ FLAG_ENTRY0("RxLookupDesPart2ParityErr", + RXES(LOOKUP_DES_PART2_PARITY)), +/*42*/ FLAG_ENTRY0("RxLookupRcvArrayUncErr", RXES(LOOKUP_RCV_ARRAY_UNC)), +/*43*/ FLAG_ENTRY0("RxLookupRcvArrayCorErr", RXES(LOOKUP_RCV_ARRAY_COR)), +/*44*/ FLAG_ENTRY0("RxLookupCsrParityErr", RXES(LOOKUP_CSR_PARITY)), +/*45*/ FLAG_ENTRY0("RxHqIntrCsrParityErr", RXES(HQ_INTR_CSR_PARITY)), +/*46*/ FLAG_ENTRY0("RxHqIntrFsmErr", RXES(HQ_INTR_FSM)), +/*47*/ FLAG_ENTRY0("RxRbufDescPart1UncErr", RXES(RBUF_DESC_PART1_UNC)), +/*48*/ FLAG_ENTRY0("RxRbufDescPart1CorErr", RXES(RBUF_DESC_PART1_COR)), +/*49*/ FLAG_ENTRY0("RxRbufDescPart2UncErr", RXES(RBUF_DESC_PART2_UNC)), +/*50*/ FLAG_ENTRY0("RxRbufDescPart2CorErr", RXES(RBUF_DESC_PART2_COR)), +/*51*/ FLAG_ENTRY0("RxDmaHdrFifoRdUncErr", RXES(DMA_HDR_FIFO_RD_UNC)), +/*52*/ FLAG_ENTRY0("RxDmaHdrFifoRdCorErr", RXES(DMA_HDR_FIFO_RD_COR)), +/*53*/ FLAG_ENTRY0("RxDmaDataFifoRdUncErr", RXES(DMA_DATA_FIFO_RD_UNC)), +/*54*/ FLAG_ENTRY0("RxDmaDataFifoRdCorErr", RXES(DMA_DATA_FIFO_RD_COR)), +/*55*/ FLAG_ENTRY0("RxRbufDataUncErr", RXES(RBUF_DATA_UNC)), +/*56*/ FLAG_ENTRY0("RxRbufDataCorErr", RXES(RBUF_DATA_COR)), +/*57*/ FLAG_ENTRY0("RxDmaCsrParityErr", RXES(DMA_CSR_PARITY)), +/*58*/ FLAG_ENTRY0("RxDmaEqFsmEncodingErr", RXES(DMA_EQ_FSM_ENCODING)), +/*59*/ FLAG_ENTRY0("RxDmaDqFsmEncodingErr", RXES(DMA_DQ_FSM_ENCODING)), +/*60*/ FLAG_ENTRY0("RxDmaCsrUncErr", RXES(DMA_CSR_UNC)), +/*61*/ FLAG_ENTRY0("RxCsrReadBadAddrErr", RXES(CSR_READ_BAD_ADDR)), +/*62*/ FLAG_ENTRY0("RxCsrWriteBadAddrErr", RXES(CSR_WRITE_BAD_ADDR)), +/*63*/ FLAG_ENTRY0("RxCsrParityErr", RXES(CSR_PARITY)) +}; + +/* RXE errors that will trigger an SPC freeze */ +#define ALL_RXE_FREEZE_ERR \ + (RCV_ERR_STATUS_RX_RCV_QP_MAP_TABLE_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RCV_CSR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_FLAG_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RCV_FSM_ENCODING_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_FREE_LIST_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_REG_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_REG_UNC_COR_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_BLOCK_LIST_READ_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QHEAD_BUF_NUM_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QENT_CNT_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QNEXT_BUF_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QVLD_BIT_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QHD_PTR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QTL_PTR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QNUM_OF_PKT_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CSR_QEOPDW_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_CTX_ID_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_BAD_LOOKUP_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_FULL_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_EMPTY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_FL_RD_ADDR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_FL_WR_ADDR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_FL_INITDONE_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_FL_INIT_WR_ADDR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_NEXT_FREE_BUF_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_LOOKUP_DES_PART1_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_LOOKUP_DES_PART1_UNC_COR_ERR_SMASK \ + | RCV_ERR_STATUS_RX_LOOKUP_DES_PART2_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_LOOKUP_RCV_ARRAY_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_LOOKUP_CSR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_HQ_INTR_CSR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_HQ_INTR_FSM_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_DESC_PART1_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_DESC_PART1_COR_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_DESC_PART2_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_HDR_FIFO_RD_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_DATA_FIFO_RD_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_RBUF_DATA_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_CSR_PARITY_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_EQ_FSM_ENCODING_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_DQ_FSM_ENCODING_ERR_SMASK \ + | RCV_ERR_STATUS_RX_DMA_CSR_UNC_ERR_SMASK \ + | RCV_ERR_STATUS_RX_CSR_PARITY_ERR_SMASK) + +#define RXE_FREEZE_ABORT_MASK \ + (RCV_ERR_STATUS_RX_DMA_CSR_UNC_ERR_SMASK | \ + RCV_ERR_STATUS_RX_DMA_HDR_FIFO_RD_UNC_ERR_SMASK | \ + RCV_ERR_STATUS_RX_DMA_DATA_FIFO_RD_UNC_ERR_SMASK) + +/* + * DCC Error Flags + */ +#define DCCE(name) DCC_ERR_FLG_##name##_SMASK +static struct flag_table dcc_err_flags[] = { + FLAG_ENTRY0("bad_l2_err", DCCE(BAD_L2_ERR)), + FLAG_ENTRY0("bad_sc_err", DCCE(BAD_SC_ERR)), + FLAG_ENTRY0("bad_mid_tail_err", DCCE(BAD_MID_TAIL_ERR)), + FLAG_ENTRY0("bad_preemption_err", DCCE(BAD_PREEMPTION_ERR)), + FLAG_ENTRY0("preemption_err", DCCE(PREEMPTION_ERR)), + FLAG_ENTRY0("preemptionvl15_err", DCCE(PREEMPTIONVL15_ERR)), + FLAG_ENTRY0("bad_vl_marker_err", DCCE(BAD_VL_MARKER_ERR)), + FLAG_ENTRY0("bad_dlid_target_err", DCCE(BAD_DLID_TARGET_ERR)), + FLAG_ENTRY0("bad_lver_err", DCCE(BAD_LVER_ERR)), + FLAG_ENTRY0("uncorrectable_err", DCCE(UNCORRECTABLE_ERR)), + FLAG_ENTRY0("bad_crdt_ack_err", DCCE(BAD_CRDT_ACK_ERR)), + FLAG_ENTRY0("unsup_pkt_type", DCCE(UNSUP_PKT_TYPE)), + FLAG_ENTRY0("bad_ctrl_flit_err", DCCE(BAD_CTRL_FLIT_ERR)), + FLAG_ENTRY0("event_cntr_parity_err", DCCE(EVENT_CNTR_PARITY_ERR)), + FLAG_ENTRY0("event_cntr_rollover_err", DCCE(EVENT_CNTR_ROLLOVER_ERR)), + FLAG_ENTRY0("link_err", DCCE(LINK_ERR)), + FLAG_ENTRY0("misc_cntr_rollover_err", DCCE(MISC_CNTR_ROLLOVER_ERR)), + FLAG_ENTRY0("bad_ctrl_dist_err", DCCE(BAD_CTRL_DIST_ERR)), + FLAG_ENTRY0("bad_tail_dist_err", DCCE(BAD_TAIL_DIST_ERR)), + FLAG_ENTRY0("bad_head_dist_err", DCCE(BAD_HEAD_DIST_ERR)), + FLAG_ENTRY0("nonvl15_state_err", DCCE(NONVL15_STATE_ERR)), + FLAG_ENTRY0("vl15_multi_err", DCCE(VL15_MULTI_ERR)), + FLAG_ENTRY0("bad_pkt_length_err", DCCE(BAD_PKT_LENGTH_ERR)), + FLAG_ENTRY0("unsup_vl_err", DCCE(UNSUP_VL_ERR)), + FLAG_ENTRY0("perm_nvl15_err", DCCE(PERM_NVL15_ERR)), + FLAG_ENTRY0("slid_zero_err", DCCE(SLID_ZERO_ERR)), + FLAG_ENTRY0("dlid_zero_err", DCCE(DLID_ZERO_ERR)), + FLAG_ENTRY0("length_mtu_err", DCCE(LENGTH_MTU_ERR)), + FLAG_ENTRY0("rx_early_drop_err", DCCE(RX_EARLY_DROP_ERR)), + FLAG_ENTRY0("late_short_err", DCCE(LATE_SHORT_ERR)), + FLAG_ENTRY0("late_long_err", DCCE(LATE_LONG_ERR)), + FLAG_ENTRY0("late_ebp_err", DCCE(LATE_EBP_ERR)), + FLAG_ENTRY0("fpe_tx_fifo_ovflw_err", DCCE(FPE_TX_FIFO_OVFLW_ERR)), + FLAG_ENTRY0("fpe_tx_fifo_unflw_err", DCCE(FPE_TX_FIFO_UNFLW_ERR)), + FLAG_ENTRY0("csr_access_blocked_host", DCCE(CSR_ACCESS_BLOCKED_HOST)), + FLAG_ENTRY0("csr_access_blocked_uc", DCCE(CSR_ACCESS_BLOCKED_UC)), + FLAG_ENTRY0("tx_ctrl_parity_err", DCCE(TX_CTRL_PARITY_ERR)), + FLAG_ENTRY0("tx_ctrl_parity_mbe_err", DCCE(TX_CTRL_PARITY_MBE_ERR)), + FLAG_ENTRY0("tx_sc_parity_err", DCCE(TX_SC_PARITY_ERR)), + FLAG_ENTRY0("rx_ctrl_parity_mbe_err", DCCE(RX_CTRL_PARITY_MBE_ERR)), + FLAG_ENTRY0("csr_parity_err", DCCE(CSR_PARITY_ERR)), + FLAG_ENTRY0("csr_inval_addr", DCCE(CSR_INVAL_ADDR)), + FLAG_ENTRY0("tx_byte_shft_parity_err", DCCE(TX_BYTE_SHFT_PARITY_ERR)), + FLAG_ENTRY0("rx_byte_shft_parity_err", DCCE(RX_BYTE_SHFT_PARITY_ERR)), + FLAG_ENTRY0("fmconfig_err", DCCE(FMCONFIG_ERR)), + FLAG_ENTRY0("rcvport_err", DCCE(RCVPORT_ERR)), +}; + +/* + * LCB error flags + */ +#define LCBE(name) DC_LCB_ERR_FLG_##name##_SMASK +static struct flag_table lcb_err_flags[] = { +/* 0*/ FLAG_ENTRY0("CSR_PARITY_ERR", LCBE(CSR_PARITY_ERR)), +/* 1*/ FLAG_ENTRY0("INVALID_CSR_ADDR", LCBE(INVALID_CSR_ADDR)), +/* 2*/ FLAG_ENTRY0("RST_FOR_FAILED_DESKEW", LCBE(RST_FOR_FAILED_DESKEW)), +/* 3*/ FLAG_ENTRY0("ALL_LNS_FAILED_REINIT_TEST", + LCBE(ALL_LNS_FAILED_REINIT_TEST)), +/* 4*/ FLAG_ENTRY0("LOST_REINIT_STALL_OR_TOS", LCBE(LOST_REINIT_STALL_OR_TOS)), +/* 5*/ FLAG_ENTRY0("TX_LESS_THAN_FOUR_LNS", LCBE(TX_LESS_THAN_FOUR_LNS)), +/* 6*/ FLAG_ENTRY0("RX_LESS_THAN_FOUR_LNS", LCBE(RX_LESS_THAN_FOUR_LNS)), +/* 7*/ FLAG_ENTRY0("SEQ_CRC_ERR", LCBE(SEQ_CRC_ERR)), +/* 8*/ FLAG_ENTRY0("REINIT_FROM_PEER", LCBE(REINIT_FROM_PEER)), +/* 9*/ FLAG_ENTRY0("REINIT_FOR_LN_DEGRADE", LCBE(REINIT_FOR_LN_DEGRADE)), +/*10*/ FLAG_ENTRY0("CRC_ERR_CNT_HIT_LIMIT", LCBE(CRC_ERR_CNT_HIT_LIMIT)), +/*11*/ FLAG_ENTRY0("RCLK_STOPPED", LCBE(RCLK_STOPPED)), +/*12*/ FLAG_ENTRY0("UNEXPECTED_REPLAY_MARKER", LCBE(UNEXPECTED_REPLAY_MARKER)), +/*13*/ FLAG_ENTRY0("UNEXPECTED_ROUND_TRIP_MARKER", + LCBE(UNEXPECTED_ROUND_TRIP_MARKER)), +/*14*/ FLAG_ENTRY0("ILLEGAL_NULL_LTP", LCBE(ILLEGAL_NULL_LTP)), +/*15*/ FLAG_ENTRY0("ILLEGAL_FLIT_ENCODING", LCBE(ILLEGAL_FLIT_ENCODING)), +/*16*/ FLAG_ENTRY0("FLIT_INPUT_BUF_OFLW", LCBE(FLIT_INPUT_BUF_OFLW)), +/*17*/ FLAG_ENTRY0("VL_ACK_INPUT_BUF_OFLW", LCBE(VL_ACK_INPUT_BUF_OFLW)), +/*18*/ FLAG_ENTRY0("VL_ACK_INPUT_PARITY_ERR", LCBE(VL_ACK_INPUT_PARITY_ERR)), +/*19*/ FLAG_ENTRY0("VL_ACK_INPUT_WRONG_CRC_MODE", + LCBE(VL_ACK_INPUT_WRONG_CRC_MODE)), +/*20*/ FLAG_ENTRY0("FLIT_INPUT_BUF_MBE", LCBE(FLIT_INPUT_BUF_MBE)), +/*21*/ FLAG_ENTRY0("FLIT_INPUT_BUF_SBE", LCBE(FLIT_INPUT_BUF_SBE)), +/*22*/ FLAG_ENTRY0("REPLAY_BUF_MBE", LCBE(REPLAY_BUF_MBE)), +/*23*/ FLAG_ENTRY0("REPLAY_BUF_SBE", LCBE(REPLAY_BUF_SBE)), +/*24*/ FLAG_ENTRY0("CREDIT_RETURN_FLIT_MBE", LCBE(CREDIT_RETURN_FLIT_MBE)), +/*25*/ FLAG_ENTRY0("RST_FOR_LINK_TIMEOUT", LCBE(RST_FOR_LINK_TIMEOUT)), +/*26*/ FLAG_ENTRY0("RST_FOR_INCOMPLT_RND_TRIP", + LCBE(RST_FOR_INCOMPLT_RND_TRIP)), +/*27*/ FLAG_ENTRY0("HOLD_REINIT", LCBE(HOLD_REINIT)), +/*28*/ FLAG_ENTRY0("NEG_EDGE_LINK_TRANSFER_ACTIVE", + LCBE(NEG_EDGE_LINK_TRANSFER_ACTIVE)), +/*29*/ FLAG_ENTRY0("REDUNDANT_FLIT_PARITY_ERR", + LCBE(REDUNDANT_FLIT_PARITY_ERR)) +}; + +/* + * DC8051 Error Flags + */ +#define D8E(name) DC_DC8051_ERR_FLG_##name##_SMASK +static struct flag_table dc8051_err_flags[] = { + FLAG_ENTRY0("SET_BY_8051", D8E(SET_BY_8051)), + FLAG_ENTRY0("LOST_8051_HEART_BEAT", D8E(LOST_8051_HEART_BEAT)), + FLAG_ENTRY0("CRAM_MBE", D8E(CRAM_MBE)), + FLAG_ENTRY0("CRAM_SBE", D8E(CRAM_SBE)), + FLAG_ENTRY0("DRAM_MBE", D8E(DRAM_MBE)), + FLAG_ENTRY0("DRAM_SBE", D8E(DRAM_SBE)), + FLAG_ENTRY0("IRAM_MBE", D8E(IRAM_MBE)), + FLAG_ENTRY0("IRAM_SBE", D8E(IRAM_SBE)), + FLAG_ENTRY0("UNMATCHED_SECURE_MSG_ACROSS_BCC_LANES", + D8E(UNMATCHED_SECURE_MSG_ACROSS_BCC_LANES)), + FLAG_ENTRY0("INVALID_CSR_ADDR", D8E(INVALID_CSR_ADDR)), +}; + +/* + * DC8051 Information Error flags + * + * Flags in DC8051_DBG_ERR_INFO_SET_BY_8051.ERROR field. + */ +static struct flag_table dc8051_info_err_flags[] = { + FLAG_ENTRY0("Spico ROM check failed", SPICO_ROM_FAILED), + FLAG_ENTRY0("Unknown frame received", UNKNOWN_FRAME), + FLAG_ENTRY0("Target BER not met", TARGET_BER_NOT_MET), + FLAG_ENTRY0("Serdes internal loopback failure", + FAILED_SERDES_INTERNAL_LOOPBACK), + FLAG_ENTRY0("Failed SerDes init", FAILED_SERDES_INIT), + FLAG_ENTRY0("Failed LNI(Polling)", FAILED_LNI_POLLING), + FLAG_ENTRY0("Failed LNI(Debounce)", FAILED_LNI_DEBOUNCE), + FLAG_ENTRY0("Failed LNI(EstbComm)", FAILED_LNI_ESTBCOMM), + FLAG_ENTRY0("Failed LNI(OptEq)", FAILED_LNI_OPTEQ), + FLAG_ENTRY0("Failed LNI(VerifyCap_1)", FAILED_LNI_VERIFY_CAP1), + FLAG_ENTRY0("Failed LNI(VerifyCap_2)", FAILED_LNI_VERIFY_CAP2), + FLAG_ENTRY0("Failed LNI(ConfigLT)", FAILED_LNI_CONFIGLT) +}; + +/* + * DC8051 Information Host Information flags + * + * Flags in DC8051_DBG_ERR_INFO_SET_BY_8051.HOST_MSG field. + */ +static struct flag_table dc8051_info_host_msg_flags[] = { + FLAG_ENTRY0("Host request done", 0x0001), + FLAG_ENTRY0("BC SMA message", 0x0002), + FLAG_ENTRY0("BC PWR_MGM message", 0x0004), + FLAG_ENTRY0("BC Unknown message (BCC)", 0x0008), + FLAG_ENTRY0("BC Unknown message (LCB)", 0x0010), + FLAG_ENTRY0("External device config request", 0x0020), + FLAG_ENTRY0("VerifyCap all frames received", 0x0040), + FLAG_ENTRY0("LinkUp achieved", 0x0080), + FLAG_ENTRY0("Link going down", 0x0100), +}; + + +static u32 encoded_size(u32 size); +static u32 chip_to_opa_lstate(struct hfi1_devdata *dd, u32 chip_lstate); +static int set_physical_link_state(struct hfi1_devdata *dd, u64 state); +static void read_vc_remote_phy(struct hfi1_devdata *dd, u8 *power_management, + u8 *continuous); +static void read_vc_remote_fabric(struct hfi1_devdata *dd, u8 *vau, u8 *z, + u8 *vcu, u16 *vl15buf, u8 *crc_sizes); +static void read_vc_remote_link_width(struct hfi1_devdata *dd, + u8 *remote_tx_rate, u16 *link_widths); +static void read_vc_local_link_width(struct hfi1_devdata *dd, u8 *misc_bits, + u8 *flag_bits, u16 *link_widths); +static void read_remote_device_id(struct hfi1_devdata *dd, u16 *device_id, + u8 *device_rev); +static void read_mgmt_allowed(struct hfi1_devdata *dd, u8 *mgmt_allowed); +static void read_local_lni(struct hfi1_devdata *dd, u8 *enable_lane_rx); +static int read_tx_settings(struct hfi1_devdata *dd, u8 *enable_lane_tx, + u8 *tx_polarity_inversion, + u8 *rx_polarity_inversion, u8 *max_rate); +static void handle_sdma_eng_err(struct hfi1_devdata *dd, + unsigned int context, u64 err_status); +static void handle_qsfp_int(struct hfi1_devdata *dd, u32 source, u64 reg); +static void handle_dcc_err(struct hfi1_devdata *dd, + unsigned int context, u64 err_status); +static void handle_lcb_err(struct hfi1_devdata *dd, + unsigned int context, u64 err_status); +static void handle_8051_interrupt(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_cce_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_rxe_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_misc_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_pio_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_sdma_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_egress_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void handle_txe_err(struct hfi1_devdata *dd, u32 unused, u64 reg); +static void set_partition_keys(struct hfi1_pportdata *); +static const char *link_state_name(u32 state); +static const char *link_state_reason_name(struct hfi1_pportdata *ppd, + u32 state); +static int do_8051_command(struct hfi1_devdata *dd, u32 type, u64 in_data, + u64 *out_data); +static int read_idle_sma(struct hfi1_devdata *dd, u64 *data); +static int thermal_init(struct hfi1_devdata *dd); + +static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, + int msecs); +static void read_planned_down_reason_code(struct hfi1_devdata *dd, u8 *pdrrc); +static void handle_temp_err(struct hfi1_devdata *); +static void dc_shutdown(struct hfi1_devdata *); +static void dc_start(struct hfi1_devdata *); + +/* + * Error interrupt table entry. This is used as input to the interrupt + * "clear down" routine used for all second tier error interrupt register. + * Second tier interrupt registers have a single bit representing them + * in the top-level CceIntStatus. + */ +struct err_reg_info { + u32 status; /* status CSR offset */ + u32 clear; /* clear CSR offset */ + u32 mask; /* mask CSR offset */ + void (*handler)(struct hfi1_devdata *dd, u32 source, u64 reg); + const char *desc; +}; + +#define NUM_MISC_ERRS (IS_GENERAL_ERR_END - IS_GENERAL_ERR_START) +#define NUM_DC_ERRS (IS_DC_END - IS_DC_START) +#define NUM_VARIOUS (IS_VARIOUS_END - IS_VARIOUS_START) + +/* + * Helpers for building HFI and DC error interrupt table entries. Different + * helpers are needed because of inconsistent register names. + */ +#define EE(reg, handler, desc) \ + { reg##_STATUS, reg##_CLEAR, reg##_MASK, \ + handler, desc } +#define DC_EE1(reg, handler, desc) \ + { reg##_FLG, reg##_FLG_CLR, reg##_FLG_EN, handler, desc } +#define DC_EE2(reg, handler, desc) \ + { reg##_FLG, reg##_CLR, reg##_EN, handler, desc } + +/* + * Table of the "misc" grouping of error interrupts. Each entry refers to + * another register containing more information. + */ +static const struct err_reg_info misc_errs[NUM_MISC_ERRS] = { +/* 0*/ EE(CCE_ERR, handle_cce_err, "CceErr"), +/* 1*/ EE(RCV_ERR, handle_rxe_err, "RxeErr"), +/* 2*/ EE(MISC_ERR, handle_misc_err, "MiscErr"), +/* 3*/ { 0, 0, 0, NULL }, /* reserved */ +/* 4*/ EE(SEND_PIO_ERR, handle_pio_err, "PioErr"), +/* 5*/ EE(SEND_DMA_ERR, handle_sdma_err, "SDmaErr"), +/* 6*/ EE(SEND_EGRESS_ERR, handle_egress_err, "EgressErr"), +/* 7*/ EE(SEND_ERR, handle_txe_err, "TxeErr") + /* the rest are reserved */ +}; + +/* + * Index into the Various section of the interrupt sources + * corresponding to the Critical Temperature interrupt. + */ +#define TCRIT_INT_SOURCE 4 + +/* + * SDMA error interrupt entry - refers to another register containing more + * information. + */ +static const struct err_reg_info sdma_eng_err = + EE(SEND_DMA_ENG_ERR, handle_sdma_eng_err, "SDmaEngErr"); + +static const struct err_reg_info various_err[NUM_VARIOUS] = { +/* 0*/ { 0, 0, 0, NULL }, /* PbcInt */ +/* 1*/ { 0, 0, 0, NULL }, /* GpioAssertInt */ +/* 2*/ EE(ASIC_QSFP1, handle_qsfp_int, "QSFP1"), +/* 3*/ EE(ASIC_QSFP2, handle_qsfp_int, "QSFP2"), +/* 4*/ { 0, 0, 0, NULL }, /* TCritInt */ + /* rest are reserved */ +}; + +/* + * The DC encoding of mtu_cap for 10K MTU in the DCC_CFG_PORT_CONFIG + * register can not be derived from the MTU value because 10K is not + * a power of 2. Therefore, we need a constant. Everything else can + * be calculated. + */ +#define DCC_CFG_PORT_MTU_CAP_10240 7 + +/* + * Table of the DC grouping of error interrupts. Each entry refers to + * another register containing more information. + */ +static const struct err_reg_info dc_errs[NUM_DC_ERRS] = { +/* 0*/ DC_EE1(DCC_ERR, handle_dcc_err, "DCC Err"), +/* 1*/ DC_EE2(DC_LCB_ERR, handle_lcb_err, "LCB Err"), +/* 2*/ DC_EE2(DC_DC8051_ERR, handle_8051_interrupt, "DC8051 Interrupt"), +/* 3*/ /* dc_lbm_int - special, see is_dc_int() */ + /* the rest are reserved */ +}; + +struct cntr_entry { + /* + * counter name + */ + char *name; + + /* + * csr to read for name (if applicable) + */ + u64 csr; + + /* + * offset into dd or ppd to store the counter's value + */ + int offset; + + /* + * flags + */ + u8 flags; + + /* + * accessor for stat element, context either dd or ppd + */ + u64 (*rw_cntr)(const struct cntr_entry *, + void *context, + int vl, + int mode, + u64 data); +}; + +#define C_RCV_HDR_OVF_FIRST C_RCV_HDR_OVF_0 +#define C_RCV_HDR_OVF_LAST C_RCV_HDR_OVF_159 + +#define CNTR_ELEM(name, csr, offset, flags, accessor) \ +{ \ + name, \ + csr, \ + offset, \ + flags, \ + accessor \ +} + +/* 32bit RXE */ +#define RXE32_PORT_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + RCV_COUNTER_ARRAY32), \ + 0, flags | CNTR_32BIT, \ + port_access_u32_csr) + +#define RXE32_DEV_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + RCV_COUNTER_ARRAY32), \ + 0, flags | CNTR_32BIT, \ + dev_access_u32_csr) + +/* 64bit RXE */ +#define RXE64_PORT_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + RCV_COUNTER_ARRAY64), \ + 0, flags, \ + port_access_u64_csr) + +#define RXE64_DEV_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + RCV_COUNTER_ARRAY64), \ + 0, flags, \ + dev_access_u64_csr) + +#define OVR_LBL(ctx) C_RCV_HDR_OVF_ ## ctx +#define OVR_ELM(ctx) \ +CNTR_ELEM("RcvHdrOvr" #ctx, \ + (RCV_HDR_OVFL_CNT + ctx*0x100), \ + 0, CNTR_NORMAL, port_access_u64_csr) + +/* 32bit TXE */ +#define TXE32_PORT_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + SEND_COUNTER_ARRAY32), \ + 0, flags | CNTR_32BIT, \ + port_access_u32_csr) + +/* 64bit TXE */ +#define TXE64_PORT_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + SEND_COUNTER_ARRAY64), \ + 0, flags, \ + port_access_u64_csr) + +# define TX64_DEV_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name,\ + counter * 8 + SEND_COUNTER_ARRAY64, \ + 0, \ + flags, \ + dev_access_u64_csr) + +/* CCE */ +#define CCE_PERF_DEV_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + CCE_COUNTER_ARRAY32), \ + 0, flags | CNTR_32BIT, \ + dev_access_u32_csr) + +#define CCE_INT_DEV_CNTR_ELEM(name, counter, flags) \ +CNTR_ELEM(#name, \ + (counter * 8 + CCE_INT_COUNTER_ARRAY32), \ + 0, flags | CNTR_32BIT, \ + dev_access_u32_csr) + +/* DC */ +#define DC_PERF_CNTR(name, counter, flags) \ +CNTR_ELEM(#name, \ + counter, \ + 0, \ + flags, \ + dev_access_u64_csr) + +#define DC_PERF_CNTR_LCB(name, counter, flags) \ +CNTR_ELEM(#name, \ + counter, \ + 0, \ + flags, \ + dc_access_lcb_cntr) + +/* ibp counters */ +#define SW_IBP_CNTR(name, cntr) \ +CNTR_ELEM(#name, \ + 0, \ + 0, \ + CNTR_SYNTH, \ + access_ibp_##cntr) + +u64 read_csr(const struct hfi1_devdata *dd, u32 offset) +{ + u64 val; + + if (dd->flags & HFI1_PRESENT) { + val = readq((void __iomem *)dd->kregbase + offset); + return val; + } + return -1; +} + +void write_csr(const struct hfi1_devdata *dd, u32 offset, u64 value) +{ + if (dd->flags & HFI1_PRESENT) + writeq(value, (void __iomem *)dd->kregbase + offset); +} + +void __iomem *get_csr_addr( + struct hfi1_devdata *dd, + u32 offset) +{ + return (void __iomem *)dd->kregbase + offset; +} + +static inline u64 read_write_csr(const struct hfi1_devdata *dd, u32 csr, + int mode, u64 value) +{ + u64 ret; + + + if (mode == CNTR_MODE_R) { + ret = read_csr(dd, csr); + } else if (mode == CNTR_MODE_W) { + write_csr(dd, csr, value); + ret = value; + } else { + dd_dev_err(dd, "Invalid cntr register access mode"); + return 0; + } + + hfi1_cdbg(CNTR, "csr 0x%x val 0x%llx mode %d", csr, ret, mode); + return ret; +} + +/* Dev Access */ +static u64 dev_access_u32_csr(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + return read_write_csr(dd, entry->csr, mode, data); +} + +static u64 dev_access_u64_csr(const struct cntr_entry *entry, void *context, + int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + u64 val = 0; + u64 csr = entry->csr; + + if (entry->flags & CNTR_VL) { + if (vl == CNTR_INVALID_VL) + return 0; + csr += 8 * vl; + } else { + if (vl != CNTR_INVALID_VL) + return 0; + } + + val = read_write_csr(dd, csr, mode, data); + return val; +} + +static u64 dc_access_lcb_cntr(const struct cntr_entry *entry, void *context, + int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + u32 csr = entry->csr; + int ret = 0; + + if (vl != CNTR_INVALID_VL) + return 0; + if (mode == CNTR_MODE_R) + ret = read_lcb_csr(dd, csr, &data); + else if (mode == CNTR_MODE_W) + ret = write_lcb_csr(dd, csr, data); + + if (ret) { + dd_dev_err(dd, "Could not acquire LCB for counter 0x%x", csr); + return 0; + } + + hfi1_cdbg(CNTR, "csr 0x%x val 0x%llx mode %d", csr, data, mode); + return data; +} + +/* Port Access */ +static u64 port_access_u32_csr(const struct cntr_entry *entry, void *context, + int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + return read_write_csr(ppd->dd, entry->csr, mode, data); +} + +static u64 port_access_u64_csr(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + u64 val; + u64 csr = entry->csr; + + if (entry->flags & CNTR_VL) { + if (vl == CNTR_INVALID_VL) + return 0; + csr += 8 * vl; + } else { + if (vl != CNTR_INVALID_VL) + return 0; + } + val = read_write_csr(ppd->dd, csr, mode, data); + return val; +} + +/* Software defined */ +static inline u64 read_write_sw(struct hfi1_devdata *dd, u64 *cntr, int mode, + u64 data) +{ + u64 ret; + + if (mode == CNTR_MODE_R) { + ret = *cntr; + } else if (mode == CNTR_MODE_W) { + *cntr = data; + ret = data; + } else { + dd_dev_err(dd, "Invalid cntr sw access mode"); + return 0; + } + + hfi1_cdbg(CNTR, "val 0x%llx mode %d", ret, mode); + + return ret; +} + +static u64 access_sw_link_dn_cnt(const struct cntr_entry *entry, void *context, + int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + return read_write_sw(ppd->dd, &ppd->link_downed, mode, data); +} + +static u64 access_sw_link_up_cnt(const struct cntr_entry *entry, void *context, + int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + return read_write_sw(ppd->dd, &ppd->link_up, mode, data); +} + +static u64 access_sw_xmit_discards(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + + return read_write_sw(ppd->dd, &ppd->port_xmit_discards, mode, data); +} + +static u64 access_xmit_constraint_errs(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + + return read_write_sw(ppd->dd, &ppd->port_xmit_constraint_errors, + mode, data); +} + +static u64 access_rcv_constraint_errs(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; + + if (vl != CNTR_INVALID_VL) + return 0; + + return read_write_sw(ppd->dd, &ppd->port_rcv_constraint_errors, + mode, data); +} + +u64 get_all_cpu_total(u64 __percpu *cntr) +{ + int cpu; + u64 counter = 0; + + for_each_possible_cpu(cpu) + counter += *per_cpu_ptr(cntr, cpu); + return counter; +} + +static u64 read_write_cpu(struct hfi1_devdata *dd, u64 *z_val, + u64 __percpu *cntr, + int vl, int mode, u64 data) +{ + + u64 ret = 0; + + if (vl != CNTR_INVALID_VL) + return 0; + + if (mode == CNTR_MODE_R) { + ret = get_all_cpu_total(cntr) - *z_val; + } else if (mode == CNTR_MODE_W) { + /* A write can only zero the counter */ + if (data == 0) + *z_val = get_all_cpu_total(cntr); + else + dd_dev_err(dd, "Per CPU cntrs can only be zeroed"); + } else { + dd_dev_err(dd, "Invalid cntr sw cpu access mode"); + return 0; + } + + return ret; +} + +static u64 access_sw_cpu_intr(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + return read_write_cpu(dd, &dd->z_int_counter, dd->int_counter, vl, + mode, data); +} + +static u64 access_sw_cpu_rcv_limit(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + return read_write_cpu(dd, &dd->z_rcv_limit, dd->rcv_limit, vl, + mode, data); +} + +static u64 access_sw_pio_wait(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + return dd->verbs_dev.n_piowait; +} + +static u64 access_sw_vtx_wait(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + return dd->verbs_dev.n_txwait; +} + +static u64 access_sw_kmem_wait(const struct cntr_entry *entry, + void *context, int vl, int mode, u64 data) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)context; + + return dd->verbs_dev.n_kmem_wait; +} + +#define def_access_sw_cpu(cntr) \ +static u64 access_sw_cpu_##cntr(const struct cntr_entry *entry, \ + void *context, int vl, int mode, u64 data) \ +{ \ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; \ + return read_write_cpu(ppd->dd, &ppd->ibport_data.z_ ##cntr, \ + ppd->ibport_data.cntr, vl, \ + mode, data); \ +} + +def_access_sw_cpu(rc_acks); +def_access_sw_cpu(rc_qacks); +def_access_sw_cpu(rc_delayed_comp); + +#define def_access_ibp_counter(cntr) \ +static u64 access_ibp_##cntr(const struct cntr_entry *entry, \ + void *context, int vl, int mode, u64 data) \ +{ \ + struct hfi1_pportdata *ppd = (struct hfi1_pportdata *)context; \ + \ + if (vl != CNTR_INVALID_VL) \ + return 0; \ + \ + return read_write_sw(ppd->dd, &ppd->ibport_data.n_ ##cntr, \ + mode, data); \ +} + +def_access_ibp_counter(loop_pkts); +def_access_ibp_counter(rc_resends); +def_access_ibp_counter(rnr_naks); +def_access_ibp_counter(other_naks); +def_access_ibp_counter(rc_timeouts); +def_access_ibp_counter(pkt_drops); +def_access_ibp_counter(dmawait); +def_access_ibp_counter(rc_seqnak); +def_access_ibp_counter(rc_dupreq); +def_access_ibp_counter(rdma_seq); +def_access_ibp_counter(unaligned); +def_access_ibp_counter(seq_naks); + +static struct cntr_entry dev_cntrs[DEV_CNTR_LAST] = { +[C_RCV_OVF] = RXE32_DEV_CNTR_ELEM(RcvOverflow, RCV_BUF_OVFL_CNT, CNTR_SYNTH), +[C_RX_TID_FULL] = RXE32_DEV_CNTR_ELEM(RxTIDFullEr, RCV_TID_FULL_ERR_CNT, + CNTR_NORMAL), +[C_RX_TID_INVALID] = RXE32_DEV_CNTR_ELEM(RxTIDInvalid, RCV_TID_VALID_ERR_CNT, + CNTR_NORMAL), +[C_RX_TID_FLGMS] = RXE32_DEV_CNTR_ELEM(RxTidFLGMs, + RCV_TID_FLOW_GEN_MISMATCH_CNT, + CNTR_NORMAL), +[C_RX_CTX_RHQS] = RXE32_DEV_CNTR_ELEM(RxCtxRHQS, RCV_CONTEXT_RHQ_STALL, + CNTR_NORMAL), +[C_RX_CTX_EGRS] = RXE32_DEV_CNTR_ELEM(RxCtxEgrS, RCV_CONTEXT_EGR_STALL, + CNTR_NORMAL), +[C_RCV_TID_FLSMS] = RXE32_DEV_CNTR_ELEM(RxTidFLSMs, + RCV_TID_FLOW_SEQ_MISMATCH_CNT, CNTR_NORMAL), +[C_CCE_PCI_CR_ST] = CCE_PERF_DEV_CNTR_ELEM(CcePciCrSt, + CCE_PCIE_POSTED_CRDT_STALL_CNT, CNTR_NORMAL), +[C_CCE_PCI_TR_ST] = CCE_PERF_DEV_CNTR_ELEM(CcePciTrSt, CCE_PCIE_TRGT_STALL_CNT, + CNTR_NORMAL), +[C_CCE_PIO_WR_ST] = CCE_PERF_DEV_CNTR_ELEM(CcePioWrSt, CCE_PIO_WR_STALL_CNT, + CNTR_NORMAL), +[C_CCE_ERR_INT] = CCE_INT_DEV_CNTR_ELEM(CceErrInt, CCE_ERR_INT_CNT, + CNTR_NORMAL), +[C_CCE_SDMA_INT] = CCE_INT_DEV_CNTR_ELEM(CceSdmaInt, CCE_SDMA_INT_CNT, + CNTR_NORMAL), +[C_CCE_MISC_INT] = CCE_INT_DEV_CNTR_ELEM(CceMiscInt, CCE_MISC_INT_CNT, + CNTR_NORMAL), +[C_CCE_RCV_AV_INT] = CCE_INT_DEV_CNTR_ELEM(CceRcvAvInt, CCE_RCV_AVAIL_INT_CNT, + CNTR_NORMAL), +[C_CCE_RCV_URG_INT] = CCE_INT_DEV_CNTR_ELEM(CceRcvUrgInt, + CCE_RCV_URGENT_INT_CNT, CNTR_NORMAL), +[C_CCE_SEND_CR_INT] = CCE_INT_DEV_CNTR_ELEM(CceSndCrInt, + CCE_SEND_CREDIT_INT_CNT, CNTR_NORMAL), +[C_DC_UNC_ERR] = DC_PERF_CNTR(DcUnctblErr, DCC_ERR_UNCORRECTABLE_CNT, + CNTR_SYNTH), +[C_DC_RCV_ERR] = DC_PERF_CNTR(DcRecvErr, DCC_ERR_PORTRCV_ERR_CNT, CNTR_SYNTH), +[C_DC_FM_CFG_ERR] = DC_PERF_CNTR(DcFmCfgErr, DCC_ERR_FMCONFIG_ERR_CNT, + CNTR_SYNTH), +[C_DC_RMT_PHY_ERR] = DC_PERF_CNTR(DcRmtPhyErr, DCC_ERR_RCVREMOTE_PHY_ERR_CNT, + CNTR_SYNTH), +[C_DC_DROPPED_PKT] = DC_PERF_CNTR(DcDroppedPkt, DCC_ERR_DROPPED_PKT_CNT, + CNTR_SYNTH), +[C_DC_MC_XMIT_PKTS] = DC_PERF_CNTR(DcMcXmitPkts, + DCC_PRF_PORT_XMIT_MULTICAST_CNT, CNTR_SYNTH), +[C_DC_MC_RCV_PKTS] = DC_PERF_CNTR(DcMcRcvPkts, + DCC_PRF_PORT_RCV_MULTICAST_PKT_CNT, + CNTR_SYNTH), +[C_DC_XMIT_CERR] = DC_PERF_CNTR(DcXmitCorr, + DCC_PRF_PORT_XMIT_CORRECTABLE_CNT, CNTR_SYNTH), +[C_DC_RCV_CERR] = DC_PERF_CNTR(DcRcvCorrCnt, DCC_PRF_PORT_RCV_CORRECTABLE_CNT, + CNTR_SYNTH), +[C_DC_RCV_FCC] = DC_PERF_CNTR(DcRxFCntl, DCC_PRF_RX_FLOW_CRTL_CNT, + CNTR_SYNTH), +[C_DC_XMIT_FCC] = DC_PERF_CNTR(DcXmitFCntl, DCC_PRF_TX_FLOW_CRTL_CNT, + CNTR_SYNTH), +[C_DC_XMIT_FLITS] = DC_PERF_CNTR(DcXmitFlits, DCC_PRF_PORT_XMIT_DATA_CNT, + CNTR_SYNTH), +[C_DC_RCV_FLITS] = DC_PERF_CNTR(DcRcvFlits, DCC_PRF_PORT_RCV_DATA_CNT, + CNTR_SYNTH), +[C_DC_XMIT_PKTS] = DC_PERF_CNTR(DcXmitPkts, DCC_PRF_PORT_XMIT_PKTS_CNT, + CNTR_SYNTH), +[C_DC_RCV_PKTS] = DC_PERF_CNTR(DcRcvPkts, DCC_PRF_PORT_RCV_PKTS_CNT, + CNTR_SYNTH), +[C_DC_RX_FLIT_VL] = DC_PERF_CNTR(DcRxFlitVl, DCC_PRF_PORT_VL_RCV_DATA_CNT, + CNTR_SYNTH | CNTR_VL), +[C_DC_RX_PKT_VL] = DC_PERF_CNTR(DcRxPktVl, DCC_PRF_PORT_VL_RCV_PKTS_CNT, + CNTR_SYNTH | CNTR_VL), +[C_DC_RCV_FCN] = DC_PERF_CNTR(DcRcvFcn, DCC_PRF_PORT_RCV_FECN_CNT, CNTR_SYNTH), +[C_DC_RCV_FCN_VL] = DC_PERF_CNTR(DcRcvFcnVl, DCC_PRF_PORT_VL_RCV_FECN_CNT, + CNTR_SYNTH | CNTR_VL), +[C_DC_RCV_BCN] = DC_PERF_CNTR(DcRcvBcn, DCC_PRF_PORT_RCV_BECN_CNT, CNTR_SYNTH), +[C_DC_RCV_BCN_VL] = DC_PERF_CNTR(DcRcvBcnVl, DCC_PRF_PORT_VL_RCV_BECN_CNT, + CNTR_SYNTH | CNTR_VL), +[C_DC_RCV_BBL] = DC_PERF_CNTR(DcRcvBbl, DCC_PRF_PORT_RCV_BUBBLE_CNT, + CNTR_SYNTH), +[C_DC_RCV_BBL_VL] = DC_PERF_CNTR(DcRcvBblVl, DCC_PRF_PORT_VL_RCV_BUBBLE_CNT, + CNTR_SYNTH | CNTR_VL), +[C_DC_MARK_FECN] = DC_PERF_CNTR(DcMarkFcn, DCC_PRF_PORT_MARK_FECN_CNT, + CNTR_SYNTH), +[C_DC_MARK_FECN_VL] = DC_PERF_CNTR(DcMarkFcnVl, DCC_PRF_PORT_VL_MARK_FECN_CNT, + CNTR_SYNTH | CNTR_VL), +[C_DC_TOTAL_CRC] = + DC_PERF_CNTR_LCB(DcTotCrc, DC_LCB_ERR_INFO_TOTAL_CRC_ERR, + CNTR_SYNTH), +[C_DC_CRC_LN0] = DC_PERF_CNTR_LCB(DcCrcLn0, DC_LCB_ERR_INFO_CRC_ERR_LN0, + CNTR_SYNTH), +[C_DC_CRC_LN1] = DC_PERF_CNTR_LCB(DcCrcLn1, DC_LCB_ERR_INFO_CRC_ERR_LN1, + CNTR_SYNTH), +[C_DC_CRC_LN2] = DC_PERF_CNTR_LCB(DcCrcLn2, DC_LCB_ERR_INFO_CRC_ERR_LN2, + CNTR_SYNTH), +[C_DC_CRC_LN3] = DC_PERF_CNTR_LCB(DcCrcLn3, DC_LCB_ERR_INFO_CRC_ERR_LN3, + CNTR_SYNTH), +[C_DC_CRC_MULT_LN] = + DC_PERF_CNTR_LCB(DcMultLn, DC_LCB_ERR_INFO_CRC_ERR_MULTI_LN, + CNTR_SYNTH), +[C_DC_TX_REPLAY] = DC_PERF_CNTR_LCB(DcTxReplay, DC_LCB_ERR_INFO_TX_REPLAY_CNT, + CNTR_SYNTH), +[C_DC_RX_REPLAY] = DC_PERF_CNTR_LCB(DcRxReplay, DC_LCB_ERR_INFO_RX_REPLAY_CNT, + CNTR_SYNTH), +[C_DC_SEQ_CRC_CNT] = + DC_PERF_CNTR_LCB(DcLinkSeqCrc, DC_LCB_ERR_INFO_SEQ_CRC_CNT, + CNTR_SYNTH), +[C_DC_ESC0_ONLY_CNT] = + DC_PERF_CNTR_LCB(DcEsc0, DC_LCB_ERR_INFO_ESCAPE_0_ONLY_CNT, + CNTR_SYNTH), +[C_DC_ESC0_PLUS1_CNT] = + DC_PERF_CNTR_LCB(DcEsc1, DC_LCB_ERR_INFO_ESCAPE_0_PLUS1_CNT, + CNTR_SYNTH), +[C_DC_ESC0_PLUS2_CNT] = + DC_PERF_CNTR_LCB(DcEsc0Plus2, DC_LCB_ERR_INFO_ESCAPE_0_PLUS2_CNT, + CNTR_SYNTH), +[C_DC_REINIT_FROM_PEER_CNT] = + DC_PERF_CNTR_LCB(DcReinitPeer, DC_LCB_ERR_INFO_REINIT_FROM_PEER_CNT, + CNTR_SYNTH), +[C_DC_SBE_CNT] = DC_PERF_CNTR_LCB(DcSbe, DC_LCB_ERR_INFO_SBE_CNT, + CNTR_SYNTH), +[C_DC_MISC_FLG_CNT] = + DC_PERF_CNTR_LCB(DcMiscFlg, DC_LCB_ERR_INFO_MISC_FLG_CNT, + CNTR_SYNTH), +[C_DC_PRF_GOOD_LTP_CNT] = + DC_PERF_CNTR_LCB(DcGoodLTP, DC_LCB_PRF_GOOD_LTP_CNT, CNTR_SYNTH), +[C_DC_PRF_ACCEPTED_LTP_CNT] = + DC_PERF_CNTR_LCB(DcAccLTP, DC_LCB_PRF_ACCEPTED_LTP_CNT, + CNTR_SYNTH), +[C_DC_PRF_RX_FLIT_CNT] = + DC_PERF_CNTR_LCB(DcPrfRxFlit, DC_LCB_PRF_RX_FLIT_CNT, CNTR_SYNTH), +[C_DC_PRF_TX_FLIT_CNT] = + DC_PERF_CNTR_LCB(DcPrfTxFlit, DC_LCB_PRF_TX_FLIT_CNT, CNTR_SYNTH), +[C_DC_PRF_CLK_CNTR] = + DC_PERF_CNTR_LCB(DcPrfClk, DC_LCB_PRF_CLK_CNTR, CNTR_SYNTH), +[C_DC_PG_DBG_FLIT_CRDTS_CNT] = + DC_PERF_CNTR_LCB(DcFltCrdts, DC_LCB_PG_DBG_FLIT_CRDTS_CNT, CNTR_SYNTH), +[C_DC_PG_STS_PAUSE_COMPLETE_CNT] = + DC_PERF_CNTR_LCB(DcPauseComp, DC_LCB_PG_STS_PAUSE_COMPLETE_CNT, + CNTR_SYNTH), +[C_DC_PG_STS_TX_SBE_CNT] = + DC_PERF_CNTR_LCB(DcStsTxSbe, DC_LCB_PG_STS_TX_SBE_CNT, CNTR_SYNTH), +[C_DC_PG_STS_TX_MBE_CNT] = + DC_PERF_CNTR_LCB(DcStsTxMbe, DC_LCB_PG_STS_TX_MBE_CNT, + CNTR_SYNTH), +[C_SW_CPU_INTR] = CNTR_ELEM("Intr", 0, 0, CNTR_NORMAL, + access_sw_cpu_intr), +[C_SW_CPU_RCV_LIM] = CNTR_ELEM("RcvLimit", 0, 0, CNTR_NORMAL, + access_sw_cpu_rcv_limit), +[C_SW_VTX_WAIT] = CNTR_ELEM("vTxWait", 0, 0, CNTR_NORMAL, + access_sw_vtx_wait), +[C_SW_PIO_WAIT] = CNTR_ELEM("PioWait", 0, 0, CNTR_NORMAL, + access_sw_pio_wait), +[C_SW_KMEM_WAIT] = CNTR_ELEM("KmemWait", 0, 0, CNTR_NORMAL, + access_sw_kmem_wait), +}; + +static struct cntr_entry port_cntrs[PORT_CNTR_LAST] = { +[C_TX_UNSUP_VL] = TXE32_PORT_CNTR_ELEM(TxUnVLErr, SEND_UNSUP_VL_ERR_CNT, + CNTR_NORMAL), +[C_TX_INVAL_LEN] = TXE32_PORT_CNTR_ELEM(TxInvalLen, SEND_LEN_ERR_CNT, + CNTR_NORMAL), +[C_TX_MM_LEN_ERR] = TXE32_PORT_CNTR_ELEM(TxMMLenErr, SEND_MAX_MIN_LEN_ERR_CNT, + CNTR_NORMAL), +[C_TX_UNDERRUN] = TXE32_PORT_CNTR_ELEM(TxUnderrun, SEND_UNDERRUN_CNT, + CNTR_NORMAL), +[C_TX_FLOW_STALL] = TXE32_PORT_CNTR_ELEM(TxFlowStall, SEND_FLOW_STALL_CNT, + CNTR_NORMAL), +[C_TX_DROPPED] = TXE32_PORT_CNTR_ELEM(TxDropped, SEND_DROPPED_PKT_CNT, + CNTR_NORMAL), +[C_TX_HDR_ERR] = TXE32_PORT_CNTR_ELEM(TxHdrErr, SEND_HEADERS_ERR_CNT, + CNTR_NORMAL), +[C_TX_PKT] = TXE64_PORT_CNTR_ELEM(TxPkt, SEND_DATA_PKT_CNT, CNTR_NORMAL), +[C_TX_WORDS] = TXE64_PORT_CNTR_ELEM(TxWords, SEND_DWORD_CNT, CNTR_NORMAL), +[C_TX_WAIT] = TXE64_PORT_CNTR_ELEM(TxWait, SEND_WAIT_CNT, CNTR_SYNTH), +[C_TX_FLIT_VL] = TXE64_PORT_CNTR_ELEM(TxFlitVL, SEND_DATA_VL0_CNT, + CNTR_SYNTH | CNTR_VL), +[C_TX_PKT_VL] = TXE64_PORT_CNTR_ELEM(TxPktVL, SEND_DATA_PKT_VL0_CNT, + CNTR_SYNTH | CNTR_VL), +[C_TX_WAIT_VL] = TXE64_PORT_CNTR_ELEM(TxWaitVL, SEND_WAIT_VL0_CNT, + CNTR_SYNTH | CNTR_VL), +[C_RX_PKT] = RXE64_PORT_CNTR_ELEM(RxPkt, RCV_DATA_PKT_CNT, CNTR_NORMAL), +[C_RX_WORDS] = RXE64_PORT_CNTR_ELEM(RxWords, RCV_DWORD_CNT, CNTR_NORMAL), +[C_SW_LINK_DOWN] = CNTR_ELEM("SwLinkDown", 0, 0, CNTR_SYNTH | CNTR_32BIT, + access_sw_link_dn_cnt), +[C_SW_LINK_UP] = CNTR_ELEM("SwLinkUp", 0, 0, CNTR_SYNTH | CNTR_32BIT, + access_sw_link_up_cnt), +[C_SW_XMIT_DSCD] = CNTR_ELEM("XmitDscd", 0, 0, CNTR_SYNTH | CNTR_32BIT, + access_sw_xmit_discards), +[C_SW_XMIT_DSCD_VL] = CNTR_ELEM("XmitDscdVl", 0, 0, + CNTR_SYNTH | CNTR_32BIT | CNTR_VL, + access_sw_xmit_discards), +[C_SW_XMIT_CSTR_ERR] = CNTR_ELEM("XmitCstrErr", 0, 0, CNTR_SYNTH, + access_xmit_constraint_errs), +[C_SW_RCV_CSTR_ERR] = CNTR_ELEM("RcvCstrErr", 0, 0, CNTR_SYNTH, + access_rcv_constraint_errs), +[C_SW_IBP_LOOP_PKTS] = SW_IBP_CNTR(LoopPkts, loop_pkts), +[C_SW_IBP_RC_RESENDS] = SW_IBP_CNTR(RcResend, rc_resends), +[C_SW_IBP_RNR_NAKS] = SW_IBP_CNTR(RnrNak, rnr_naks), +[C_SW_IBP_OTHER_NAKS] = SW_IBP_CNTR(OtherNak, other_naks), +[C_SW_IBP_RC_TIMEOUTS] = SW_IBP_CNTR(RcTimeOut, rc_timeouts), +[C_SW_IBP_PKT_DROPS] = SW_IBP_CNTR(PktDrop, pkt_drops), +[C_SW_IBP_DMA_WAIT] = SW_IBP_CNTR(DmaWait, dmawait), +[C_SW_IBP_RC_SEQNAK] = SW_IBP_CNTR(RcSeqNak, rc_seqnak), +[C_SW_IBP_RC_DUPREQ] = SW_IBP_CNTR(RcDupRew, rc_dupreq), +[C_SW_IBP_RDMA_SEQ] = SW_IBP_CNTR(RdmaSeq, rdma_seq), +[C_SW_IBP_UNALIGNED] = SW_IBP_CNTR(Unaligned, unaligned), +[C_SW_IBP_SEQ_NAK] = SW_IBP_CNTR(SeqNak, seq_naks), +[C_SW_CPU_RC_ACKS] = CNTR_ELEM("RcAcks", 0, 0, CNTR_NORMAL, + access_sw_cpu_rc_acks), +[C_SW_CPU_RC_QACKS] = CNTR_ELEM("RcQacks", 0, 0, CNTR_NORMAL, + access_sw_cpu_rc_qacks), +[C_SW_CPU_RC_DELAYED_COMP] = CNTR_ELEM("RcDelayComp", 0, 0, CNTR_NORMAL, + access_sw_cpu_rc_delayed_comp), +[OVR_LBL(0)] = OVR_ELM(0), [OVR_LBL(1)] = OVR_ELM(1), +[OVR_LBL(2)] = OVR_ELM(2), [OVR_LBL(3)] = OVR_ELM(3), +[OVR_LBL(4)] = OVR_ELM(4), [OVR_LBL(5)] = OVR_ELM(5), +[OVR_LBL(6)] = OVR_ELM(6), [OVR_LBL(7)] = OVR_ELM(7), +[OVR_LBL(8)] = OVR_ELM(8), [OVR_LBL(9)] = OVR_ELM(9), +[OVR_LBL(10)] = OVR_ELM(10), [OVR_LBL(11)] = OVR_ELM(11), +[OVR_LBL(12)] = OVR_ELM(12), [OVR_LBL(13)] = OVR_ELM(13), +[OVR_LBL(14)] = OVR_ELM(14), [OVR_LBL(15)] = OVR_ELM(15), +[OVR_LBL(16)] = OVR_ELM(16), [OVR_LBL(17)] = OVR_ELM(17), +[OVR_LBL(18)] = OVR_ELM(18), [OVR_LBL(19)] = OVR_ELM(19), +[OVR_LBL(20)] = OVR_ELM(20), [OVR_LBL(21)] = OVR_ELM(21), +[OVR_LBL(22)] = OVR_ELM(22), [OVR_LBL(23)] = OVR_ELM(23), +[OVR_LBL(24)] = OVR_ELM(24), [OVR_LBL(25)] = OVR_ELM(25), +[OVR_LBL(26)] = OVR_ELM(26), [OVR_LBL(27)] = OVR_ELM(27), +[OVR_LBL(28)] = OVR_ELM(28), [OVR_LBL(29)] = OVR_ELM(29), +[OVR_LBL(30)] = OVR_ELM(30), [OVR_LBL(31)] = OVR_ELM(31), +[OVR_LBL(32)] = OVR_ELM(32), [OVR_LBL(33)] = OVR_ELM(33), +[OVR_LBL(34)] = OVR_ELM(34), [OVR_LBL(35)] = OVR_ELM(35), +[OVR_LBL(36)] = OVR_ELM(36), [OVR_LBL(37)] = OVR_ELM(37), +[OVR_LBL(38)] = OVR_ELM(38), [OVR_LBL(39)] = OVR_ELM(39), +[OVR_LBL(40)] = OVR_ELM(40), [OVR_LBL(41)] = OVR_ELM(41), +[OVR_LBL(42)] = OVR_ELM(42), [OVR_LBL(43)] = OVR_ELM(43), +[OVR_LBL(44)] = OVR_ELM(44), [OVR_LBL(45)] = OVR_ELM(45), +[OVR_LBL(46)] = OVR_ELM(46), [OVR_LBL(47)] = OVR_ELM(47), +[OVR_LBL(48)] = OVR_ELM(48), [OVR_LBL(49)] = OVR_ELM(49), +[OVR_LBL(50)] = OVR_ELM(50), [OVR_LBL(51)] = OVR_ELM(51), +[OVR_LBL(52)] = OVR_ELM(52), [OVR_LBL(53)] = OVR_ELM(53), +[OVR_LBL(54)] = OVR_ELM(54), [OVR_LBL(55)] = OVR_ELM(55), +[OVR_LBL(56)] = OVR_ELM(56), [OVR_LBL(57)] = OVR_ELM(57), +[OVR_LBL(58)] = OVR_ELM(58), [OVR_LBL(59)] = OVR_ELM(59), +[OVR_LBL(60)] = OVR_ELM(60), [OVR_LBL(61)] = OVR_ELM(61), +[OVR_LBL(62)] = OVR_ELM(62), [OVR_LBL(63)] = OVR_ELM(63), +[OVR_LBL(64)] = OVR_ELM(64), [OVR_LBL(65)] = OVR_ELM(65), +[OVR_LBL(66)] = OVR_ELM(66), [OVR_LBL(67)] = OVR_ELM(67), +[OVR_LBL(68)] = OVR_ELM(68), [OVR_LBL(69)] = OVR_ELM(69), +[OVR_LBL(70)] = OVR_ELM(70), [OVR_LBL(71)] = OVR_ELM(71), +[OVR_LBL(72)] = OVR_ELM(72), [OVR_LBL(73)] = OVR_ELM(73), +[OVR_LBL(74)] = OVR_ELM(74), [OVR_LBL(75)] = OVR_ELM(75), +[OVR_LBL(76)] = OVR_ELM(76), [OVR_LBL(77)] = OVR_ELM(77), +[OVR_LBL(78)] = OVR_ELM(78), [OVR_LBL(79)] = OVR_ELM(79), +[OVR_LBL(80)] = OVR_ELM(80), [OVR_LBL(81)] = OVR_ELM(81), +[OVR_LBL(82)] = OVR_ELM(82), [OVR_LBL(83)] = OVR_ELM(83), +[OVR_LBL(84)] = OVR_ELM(84), [OVR_LBL(85)] = OVR_ELM(85), +[OVR_LBL(86)] = OVR_ELM(86), [OVR_LBL(87)] = OVR_ELM(87), +[OVR_LBL(88)] = OVR_ELM(88), [OVR_LBL(89)] = OVR_ELM(89), +[OVR_LBL(90)] = OVR_ELM(90), [OVR_LBL(91)] = OVR_ELM(91), +[OVR_LBL(92)] = OVR_ELM(92), [OVR_LBL(93)] = OVR_ELM(93), +[OVR_LBL(94)] = OVR_ELM(94), [OVR_LBL(95)] = OVR_ELM(95), +[OVR_LBL(96)] = OVR_ELM(96), [OVR_LBL(97)] = OVR_ELM(97), +[OVR_LBL(98)] = OVR_ELM(98), [OVR_LBL(99)] = OVR_ELM(99), +[OVR_LBL(100)] = OVR_ELM(100), [OVR_LBL(101)] = OVR_ELM(101), +[OVR_LBL(102)] = OVR_ELM(102), [OVR_LBL(103)] = OVR_ELM(103), +[OVR_LBL(104)] = OVR_ELM(104), [OVR_LBL(105)] = OVR_ELM(105), +[OVR_LBL(106)] = OVR_ELM(106), [OVR_LBL(107)] = OVR_ELM(107), +[OVR_LBL(108)] = OVR_ELM(108), [OVR_LBL(109)] = OVR_ELM(109), +[OVR_LBL(110)] = OVR_ELM(110), [OVR_LBL(111)] = OVR_ELM(111), +[OVR_LBL(112)] = OVR_ELM(112), [OVR_LBL(113)] = OVR_ELM(113), +[OVR_LBL(114)] = OVR_ELM(114), [OVR_LBL(115)] = OVR_ELM(115), +[OVR_LBL(116)] = OVR_ELM(116), [OVR_LBL(117)] = OVR_ELM(117), +[OVR_LBL(118)] = OVR_ELM(118), [OVR_LBL(119)] = OVR_ELM(119), +[OVR_LBL(120)] = OVR_ELM(120), [OVR_LBL(121)] = OVR_ELM(121), +[OVR_LBL(122)] = OVR_ELM(122), [OVR_LBL(123)] = OVR_ELM(123), +[OVR_LBL(124)] = OVR_ELM(124), [OVR_LBL(125)] = OVR_ELM(125), +[OVR_LBL(126)] = OVR_ELM(126), [OVR_LBL(127)] = OVR_ELM(127), +[OVR_LBL(128)] = OVR_ELM(128), [OVR_LBL(129)] = OVR_ELM(129), +[OVR_LBL(130)] = OVR_ELM(130), [OVR_LBL(131)] = OVR_ELM(131), +[OVR_LBL(132)] = OVR_ELM(132), [OVR_LBL(133)] = OVR_ELM(133), +[OVR_LBL(134)] = OVR_ELM(134), [OVR_LBL(135)] = OVR_ELM(135), +[OVR_LBL(136)] = OVR_ELM(136), [OVR_LBL(137)] = OVR_ELM(137), +[OVR_LBL(138)] = OVR_ELM(138), [OVR_LBL(139)] = OVR_ELM(139), +[OVR_LBL(140)] = OVR_ELM(140), [OVR_LBL(141)] = OVR_ELM(141), +[OVR_LBL(142)] = OVR_ELM(142), [OVR_LBL(143)] = OVR_ELM(143), +[OVR_LBL(144)] = OVR_ELM(144), [OVR_LBL(145)] = OVR_ELM(145), +[OVR_LBL(146)] = OVR_ELM(146), [OVR_LBL(147)] = OVR_ELM(147), +[OVR_LBL(148)] = OVR_ELM(148), [OVR_LBL(149)] = OVR_ELM(149), +[OVR_LBL(150)] = OVR_ELM(150), [OVR_LBL(151)] = OVR_ELM(151), +[OVR_LBL(152)] = OVR_ELM(152), [OVR_LBL(153)] = OVR_ELM(153), +[OVR_LBL(154)] = OVR_ELM(154), [OVR_LBL(155)] = OVR_ELM(155), +[OVR_LBL(156)] = OVR_ELM(156), [OVR_LBL(157)] = OVR_ELM(157), +[OVR_LBL(158)] = OVR_ELM(158), [OVR_LBL(159)] = OVR_ELM(159), +}; + +/* ======================================================================== */ + +/* return true if this is chip revision revision a0 */ +int is_a0(struct hfi1_devdata *dd) +{ + return ((dd->revision >> CCE_REVISION_CHIP_REV_MINOR_SHIFT) + & CCE_REVISION_CHIP_REV_MINOR_MASK) == 0; +} + +/* return true if this is chip revision revision a */ +int is_ax(struct hfi1_devdata *dd) +{ + u8 chip_rev_minor = + dd->revision >> CCE_REVISION_CHIP_REV_MINOR_SHIFT + & CCE_REVISION_CHIP_REV_MINOR_MASK; + return (chip_rev_minor & 0xf0) == 0; +} + +/* return true if this is chip revision revision b */ +int is_bx(struct hfi1_devdata *dd) +{ + u8 chip_rev_minor = + dd->revision >> CCE_REVISION_CHIP_REV_MINOR_SHIFT + & CCE_REVISION_CHIP_REV_MINOR_MASK; + return !!(chip_rev_minor & 0x10); +} + +/* + * Append string s to buffer buf. Arguments curp and len are the current + * position and remaining length, respectively. + * + * return 0 on success, 1 on out of room + */ +static int append_str(char *buf, char **curp, int *lenp, const char *s) +{ + char *p = *curp; + int len = *lenp; + int result = 0; /* success */ + char c; + + /* add a comma, if first in the buffer */ + if (p != buf) { + if (len == 0) { + result = 1; /* out of room */ + goto done; + } + *p++ = ','; + len--; + } + + /* copy the string */ + while ((c = *s++) != 0) { + if (len == 0) { + result = 1; /* out of room */ + goto done; + } + *p++ = c; + len--; + } + +done: + /* write return values */ + *curp = p; + *lenp = len; + + return result; +} + +/* + * Using the given flag table, print a comma separated string into + * the buffer. End in '*' if the buffer is too short. + */ +static char *flag_string(char *buf, int buf_len, u64 flags, + struct flag_table *table, int table_size) +{ + char extra[32]; + char *p = buf; + int len = buf_len; + int no_room = 0; + int i; + + /* make sure there is at least 2 so we can form "*" */ + if (len < 2) + return ""; + + len--; /* leave room for a nul */ + for (i = 0; i < table_size; i++) { + if (flags & table[i].flag) { + no_room = append_str(buf, &p, &len, table[i].str); + if (no_room) + break; + flags &= ~table[i].flag; + } + } + + /* any undocumented bits left? */ + if (!no_room && flags) { + snprintf(extra, sizeof(extra), "bits 0x%llx", flags); + no_room = append_str(buf, &p, &len, extra); + } + + /* add * if ran out of room */ + if (no_room) { + /* may need to back up to add space for a '*' */ + if (len == 0) + --p; + *p++ = '*'; + } + + /* add final nul - space already allocated above */ + *p = 0; + return buf; +} + +/* first 8 CCE error interrupt source names */ +static const char * const cce_misc_names[] = { + "CceErrInt", /* 0 */ + "RxeErrInt", /* 1 */ + "MiscErrInt", /* 2 */ + "Reserved3", /* 3 */ + "PioErrInt", /* 4 */ + "SDmaErrInt", /* 5 */ + "EgressErrInt", /* 6 */ + "TxeErrInt" /* 7 */ +}; + +/* + * Return the miscellaneous error interrupt name. + */ +static char *is_misc_err_name(char *buf, size_t bsize, unsigned int source) +{ + if (source < ARRAY_SIZE(cce_misc_names)) + strncpy(buf, cce_misc_names[source], bsize); + else + snprintf(buf, + bsize, + "Reserved%u", + source + IS_GENERAL_ERR_START); + + return buf; +} + +/* + * Return the SDMA engine error interrupt name. + */ +static char *is_sdma_eng_err_name(char *buf, size_t bsize, unsigned int source) +{ + snprintf(buf, bsize, "SDmaEngErrInt%u", source); + return buf; +} + +/* + * Return the send context error interrupt name. + */ +static char *is_sendctxt_err_name(char *buf, size_t bsize, unsigned int source) +{ + snprintf(buf, bsize, "SendCtxtErrInt%u", source); + return buf; +} + +static const char * const various_names[] = { + "PbcInt", + "GpioAssertInt", + "Qsfp1Int", + "Qsfp2Int", + "TCritInt" +}; + +/* + * Return the various interrupt name. + */ +static char *is_various_name(char *buf, size_t bsize, unsigned int source) +{ + if (source < ARRAY_SIZE(various_names)) + strncpy(buf, various_names[source], bsize); + else + snprintf(buf, bsize, "Reserved%u", source+IS_VARIOUS_START); + return buf; +} + +/* + * Return the DC interrupt name. + */ +static char *is_dc_name(char *buf, size_t bsize, unsigned int source) +{ + static const char * const dc_int_names[] = { + "common", + "lcb", + "8051", + "lbm" /* local block merge */ + }; + + if (source < ARRAY_SIZE(dc_int_names)) + snprintf(buf, bsize, "dc_%s_int", dc_int_names[source]); + else + snprintf(buf, bsize, "DCInt%u", source); + return buf; +} + +static const char * const sdma_int_names[] = { + "SDmaInt", + "SdmaIdleInt", + "SdmaProgressInt", +}; + +/* + * Return the SDMA engine interrupt name. + */ +static char *is_sdma_eng_name(char *buf, size_t bsize, unsigned int source) +{ + /* what interrupt */ + unsigned int what = source / TXE_NUM_SDMA_ENGINES; + /* which engine */ + unsigned int which = source % TXE_NUM_SDMA_ENGINES; + + if (likely(what < 3)) + snprintf(buf, bsize, "%s%u", sdma_int_names[what], which); + else + snprintf(buf, bsize, "Invalid SDMA interrupt %u", source); + return buf; +} + +/* + * Return the receive available interrupt name. + */ +static char *is_rcv_avail_name(char *buf, size_t bsize, unsigned int source) +{ + snprintf(buf, bsize, "RcvAvailInt%u", source); + return buf; +} + +/* + * Return the receive urgent interrupt name. + */ +static char *is_rcv_urgent_name(char *buf, size_t bsize, unsigned int source) +{ + snprintf(buf, bsize, "RcvUrgentInt%u", source); + return buf; +} + +/* + * Return the send credit interrupt name. + */ +static char *is_send_credit_name(char *buf, size_t bsize, unsigned int source) +{ + snprintf(buf, bsize, "SendCreditInt%u", source); + return buf; +} + +/* + * Return the reserved interrupt name. + */ +static char *is_reserved_name(char *buf, size_t bsize, unsigned int source) +{ + snprintf(buf, bsize, "Reserved%u", source + IS_RESERVED_START); + return buf; +} + +static char *cce_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + cce_err_status_flags, ARRAY_SIZE(cce_err_status_flags)); +} + +static char *rxe_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + rxe_err_status_flags, ARRAY_SIZE(rxe_err_status_flags)); +} + +static char *misc_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, misc_err_status_flags, + ARRAY_SIZE(misc_err_status_flags)); +} + +static char *pio_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + pio_err_status_flags, ARRAY_SIZE(pio_err_status_flags)); +} + +static char *sdma_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + sdma_err_status_flags, + ARRAY_SIZE(sdma_err_status_flags)); +} + +static char *egress_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + egress_err_status_flags, ARRAY_SIZE(egress_err_status_flags)); +} + +static char *egress_err_info_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + egress_err_info_flags, ARRAY_SIZE(egress_err_info_flags)); +} + +static char *send_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + send_err_status_flags, + ARRAY_SIZE(send_err_status_flags)); +} + +static void handle_cce_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + /* + * For most these errors, there is nothing that can be done except + * report or record it. + */ + dd_dev_info(dd, "CCE Error: %s\n", + cce_err_status_string(buf, sizeof(buf), reg)); + + if ((reg & CCE_ERR_STATUS_CCE_CLI2_ASYNC_FIFO_PARITY_ERR_SMASK) + && is_a0(dd) + && (dd->icode != ICODE_FUNCTIONAL_SIMULATOR)) { + /* this error requires a manual drop into SPC freeze mode */ + /* then a fix up */ + start_freeze_handling(dd->pport, FREEZE_SELF); + } +} + +/* + * Check counters for receive errors that do not have an interrupt + * associated with them. + */ +#define RCVERR_CHECK_TIME 10 +static void update_rcverr_timer(unsigned long opaque) +{ + struct hfi1_devdata *dd = (struct hfi1_devdata *)opaque; + struct hfi1_pportdata *ppd = dd->pport; + u32 cur_ovfl_cnt = read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL); + + if (dd->rcv_ovfl_cnt < cur_ovfl_cnt && + ppd->port_error_action & OPA_PI_MASK_EX_BUFFER_OVERRUN) { + dd_dev_info(dd, "%s: PortErrorAction bounce\n", __func__); + set_link_down_reason(ppd, + OPA_LINKDOWN_REASON_EXCESSIVE_BUFFER_OVERRUN, 0, + OPA_LINKDOWN_REASON_EXCESSIVE_BUFFER_OVERRUN); + queue_work(ppd->hfi1_wq, &ppd->link_bounce_work); + } + dd->rcv_ovfl_cnt = (u32) cur_ovfl_cnt; + + mod_timer(&dd->rcverr_timer, jiffies + HZ * RCVERR_CHECK_TIME); +} + +static int init_rcverr(struct hfi1_devdata *dd) +{ + init_timer(&dd->rcverr_timer); + dd->rcverr_timer.function = update_rcverr_timer; + dd->rcverr_timer.data = (unsigned long) dd; + /* Assume the hardware counter has been reset */ + dd->rcv_ovfl_cnt = 0; + return mod_timer(&dd->rcverr_timer, jiffies + HZ * RCVERR_CHECK_TIME); +} + +static void free_rcverr(struct hfi1_devdata *dd) +{ + if (dd->rcverr_timer.data) + del_timer_sync(&dd->rcverr_timer); + dd->rcverr_timer.data = 0; +} + +static void handle_rxe_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + dd_dev_info(dd, "Receive Error: %s\n", + rxe_err_status_string(buf, sizeof(buf), reg)); + + if (reg & ALL_RXE_FREEZE_ERR) { + int flags = 0; + + /* + * Freeze mode recovery is disabled for the errors + * in RXE_FREEZE_ABORT_MASK + */ + if (is_a0(dd) && (reg & RXE_FREEZE_ABORT_MASK)) + flags = FREEZE_ABORT; + + start_freeze_handling(dd->pport, flags); + } +} + +static void handle_misc_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + dd_dev_info(dd, "Misc Error: %s", + misc_err_status_string(buf, sizeof(buf), reg)); +} + +static void handle_pio_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + dd_dev_info(dd, "PIO Error: %s\n", + pio_err_status_string(buf, sizeof(buf), reg)); + + if (reg & ALL_PIO_FREEZE_ERR) + start_freeze_handling(dd->pport, 0); +} + +static void handle_sdma_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + dd_dev_info(dd, "SDMA Error: %s\n", + sdma_err_status_string(buf, sizeof(buf), reg)); + + if (reg & ALL_SDMA_FREEZE_ERR) + start_freeze_handling(dd->pport, 0); +} + +static void count_port_inactive(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd = dd->pport; + + if (ppd->port_xmit_discards < ~(u64)0) + ppd->port_xmit_discards++; +} + +/* + * We have had a "disallowed packet" error during egress. Determine the + * integrity check which failed, and update relevant error counter, etc. + * + * Note that the SEND_EGRESS_ERR_INFO register has only a single + * bit of state per integrity check, and so we can miss the reason for an + * egress error if more than one packet fails the same integrity check + * since we cleared the corresponding bit in SEND_EGRESS_ERR_INFO. + */ +static void handle_send_egress_err_info(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd = dd->pport; + u64 src = read_csr(dd, SEND_EGRESS_ERR_SOURCE); /* read first */ + u64 info = read_csr(dd, SEND_EGRESS_ERR_INFO); + char buf[96]; + + /* clear down all observed info as quickly as possible after read */ + write_csr(dd, SEND_EGRESS_ERR_INFO, info); + + dd_dev_info(dd, + "Egress Error Info: 0x%llx, %s Egress Error Src 0x%llx\n", + info, egress_err_info_string(buf, sizeof(buf), info), src); + + /* Eventually add other counters for each bit */ + + if (info & SEND_EGRESS_ERR_INFO_TOO_LONG_IB_PACKET_ERR_SMASK) { + if (ppd->port_xmit_discards < ~(u64)0) + ppd->port_xmit_discards++; + } +} + +/* + * Input value is a bit position within the SEND_EGRESS_ERR_STATUS + * register. Does it represent a 'port inactive' error? + */ +static inline int port_inactive_err(u64 posn) +{ + return (posn >= SEES(TX_LINKDOWN) && + posn <= SEES(TX_INCORRECT_LINK_STATE)); +} + +/* + * Input value is a bit position within the SEND_EGRESS_ERR_STATUS + * register. Does it represent a 'disallowed packet' error? + */ +static inline int disallowed_pkt_err(u64 posn) +{ + return (posn >= SEES(TX_SDMA0_DISALLOWED_PACKET) && + posn <= SEES(TX_SDMA15_DISALLOWED_PACKET)); +} + +static void handle_egress_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + u64 reg_copy = reg, handled = 0; + char buf[96]; + + if (reg & ALL_TXE_EGRESS_FREEZE_ERR) + start_freeze_handling(dd->pport, 0); + if (is_a0(dd) && (reg & + SEND_EGRESS_ERR_STATUS_TX_CREDIT_RETURN_VL_ERR_SMASK) + && (dd->icode != ICODE_FUNCTIONAL_SIMULATOR)) + start_freeze_handling(dd->pport, 0); + + while (reg_copy) { + int posn = fls64(reg_copy); + /* + * fls64() returns a 1-based offset, but we generally + * want 0-based offsets. + */ + int shift = posn - 1; + + if (port_inactive_err(shift)) { + count_port_inactive(dd); + handled |= (1ULL << shift); + } else if (disallowed_pkt_err(shift)) { + handle_send_egress_err_info(dd); + handled |= (1ULL << shift); + } + clear_bit(shift, (unsigned long *)®_copy); + } + + reg &= ~handled; + + if (reg) + dd_dev_info(dd, "Egress Error: %s\n", + egress_err_status_string(buf, sizeof(buf), reg)); +} + +static void handle_txe_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + dd_dev_info(dd, "Send Error: %s\n", + send_err_status_string(buf, sizeof(buf), reg)); + +} + +/* + * The maximum number of times the error clear down will loop before + * blocking a repeating error. This value is arbitrary. + */ +#define MAX_CLEAR_COUNT 20 + +/* + * Clear and handle an error register. All error interrupts are funneled + * through here to have a central location to correctly handle single- + * or multi-shot errors. + * + * For non per-context registers, call this routine with a context value + * of 0 so the per-context offset is zero. + * + * If the handler loops too many times, assume that something is wrong + * and can't be fixed, so mask the error bits. + */ +static void interrupt_clear_down(struct hfi1_devdata *dd, + u32 context, + const struct err_reg_info *eri) +{ + u64 reg; + u32 count; + + /* read in a loop until no more errors are seen */ + count = 0; + while (1) { + reg = read_kctxt_csr(dd, context, eri->status); + if (reg == 0) + break; + write_kctxt_csr(dd, context, eri->clear, reg); + if (likely(eri->handler)) + eri->handler(dd, context, reg); + count++; + if (count > MAX_CLEAR_COUNT) { + u64 mask; + + dd_dev_err(dd, "Repeating %s bits 0x%llx - masking\n", + eri->desc, reg); + /* + * Read-modify-write so any other masked bits + * remain masked. + */ + mask = read_kctxt_csr(dd, context, eri->mask); + mask &= ~reg; + write_kctxt_csr(dd, context, eri->mask, mask); + break; + } + } +} + +/* + * CCE block "misc" interrupt. Source is < 16. + */ +static void is_misc_err_int(struct hfi1_devdata *dd, unsigned int source) +{ + const struct err_reg_info *eri = &misc_errs[source]; + + if (eri->handler) { + interrupt_clear_down(dd, 0, eri); + } else { + dd_dev_err(dd, "Unexpected misc interrupt (%u) - reserved\n", + source); + } +} + +static char *send_context_err_status_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, + sc_err_status_flags, ARRAY_SIZE(sc_err_status_flags)); +} + +/* + * Send context error interrupt. Source (hw_context) is < 160. + * + * All send context errors cause the send context to halt. The normal + * clear-down mechanism cannot be used because we cannot clear the + * error bits until several other long-running items are done first. + * This is OK because with the context halted, nothing else is going + * to happen on it anyway. + */ +static void is_sendctxt_err_int(struct hfi1_devdata *dd, + unsigned int hw_context) +{ + struct send_context_info *sci; + struct send_context *sc; + char flags[96]; + u64 status; + u32 sw_index; + + sw_index = dd->hw_to_sw[hw_context]; + if (sw_index >= dd->num_send_contexts) { + dd_dev_err(dd, + "out of range sw index %u for send context %u\n", + sw_index, hw_context); + return; + } + sci = &dd->send_contexts[sw_index]; + sc = sci->sc; + if (!sc) { + dd_dev_err(dd, "%s: context %u(%u): no sc?\n", __func__, + sw_index, hw_context); + return; + } + + /* tell the software that a halt has begun */ + sc_stop(sc, SCF_HALTED); + + status = read_kctxt_csr(dd, hw_context, SEND_CTXT_ERR_STATUS); + + dd_dev_info(dd, "Send Context %u(%u) Error: %s\n", sw_index, hw_context, + send_context_err_status_string(flags, sizeof(flags), status)); + + if (status & SEND_CTXT_ERR_STATUS_PIO_DISALLOWED_PACKET_ERR_SMASK) + handle_send_egress_err_info(dd); + + /* + * Automatically restart halted kernel contexts out of interrupt + * context. User contexts must ask the driver to restart the context. + */ + if (sc->type != SC_USER) + queue_work(dd->pport->hfi1_wq, &sc->halt_work); +} + +static void handle_sdma_eng_err(struct hfi1_devdata *dd, + unsigned int source, u64 status) +{ + struct sdma_engine *sde; + + sde = &dd->per_sdma[source]; +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", sde->this_idx, + slashstrip(__FILE__), __LINE__, __func__); + dd_dev_err(sde->dd, "CONFIG SDMA(%u) source: %u status 0x%llx\n", + sde->this_idx, source, (unsigned long long)status); +#endif + sdma_engine_error(sde, status); +} + +/* + * CCE block SDMA error interrupt. Source is < 16. + */ +static void is_sdma_eng_err_int(struct hfi1_devdata *dd, unsigned int source) +{ +#ifdef CONFIG_SDMA_VERBOSITY + struct sdma_engine *sde = &dd->per_sdma[source]; + + dd_dev_err(dd, "CONFIG SDMA(%u) %s:%d %s()\n", sde->this_idx, + slashstrip(__FILE__), __LINE__, __func__); + dd_dev_err(dd, "CONFIG SDMA(%u) source: %u\n", sde->this_idx, + source); + sdma_dumpstate(sde); +#endif + interrupt_clear_down(dd, source, &sdma_eng_err); +} + +/* + * CCE block "various" interrupt. Source is < 8. + */ +static void is_various_int(struct hfi1_devdata *dd, unsigned int source) +{ + const struct err_reg_info *eri = &various_err[source]; + + /* + * TCritInt cannot go through interrupt_clear_down() + * because it is not a second tier interrupt. The handler + * should be called directly. + */ + if (source == TCRIT_INT_SOURCE) + handle_temp_err(dd); + else if (eri->handler) + interrupt_clear_down(dd, 0, eri); + else + dd_dev_info(dd, + "%s: Unimplemented/reserved interrupt %d\n", + __func__, source); +} + +static void handle_qsfp_int(struct hfi1_devdata *dd, u32 src_ctx, u64 reg) +{ + /* source is always zero */ + struct hfi1_pportdata *ppd = dd->pport; + unsigned long flags; + u64 qsfp_int_mgmt = (u64)(QSFP_HFI0_INT_N | QSFP_HFI0_MODPRST_N); + + if (reg & QSFP_HFI0_MODPRST_N) { + + dd_dev_info(dd, "%s: ModPresent triggered QSFP interrupt\n", + __func__); + + if (!qsfp_mod_present(ppd)) { + ppd->driver_link_ready = 0; + /* + * Cable removed, reset all our information about the + * cache and cable capabilities + */ + + spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); + /* + * We don't set cache_refresh_required here as we expect + * an interrupt when a cable is inserted + */ + ppd->qsfp_info.cache_valid = 0; + ppd->qsfp_info.qsfp_interrupt_functional = 0; + spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, + flags); + write_csr(dd, + dd->hfi1_id ? + ASIC_QSFP2_INVERT : + ASIC_QSFP1_INVERT, + qsfp_int_mgmt); + if (ppd->host_link_state == HLS_DN_POLL) { + /* + * The link is still in POLL. This means + * that the normal link down processing + * will not happen. We have to do it here + * before turning the DC off. + */ + queue_work(ppd->hfi1_wq, &ppd->link_down_work); + } + } else { + spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); + ppd->qsfp_info.cache_valid = 0; + ppd->qsfp_info.cache_refresh_required = 1; + spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, + flags); + + qsfp_int_mgmt &= ~(u64)QSFP_HFI0_MODPRST_N; + write_csr(dd, + dd->hfi1_id ? + ASIC_QSFP2_INVERT : + ASIC_QSFP1_INVERT, + qsfp_int_mgmt); + } + } + + if (reg & QSFP_HFI0_INT_N) { + + dd_dev_info(dd, "%s: IntN triggered QSFP interrupt\n", + __func__); + spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); + ppd->qsfp_info.check_interrupt_flags = 1; + ppd->qsfp_info.qsfp_interrupt_functional = 1; + spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags); + } + + /* Schedule the QSFP work only if there is a cable attached. */ + if (qsfp_mod_present(ppd)) + queue_work(ppd->hfi1_wq, &ppd->qsfp_info.qsfp_work); +} + +static int request_host_lcb_access(struct hfi1_devdata *dd) +{ + int ret; + + ret = do_8051_command(dd, HCMD_MISC, + (u64)HCMD_MISC_REQUEST_LCB_ACCESS << LOAD_DATA_FIELD_ID_SHIFT, + NULL); + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, "%s: command failed with error %d\n", + __func__, ret); + } + return ret == HCMD_SUCCESS ? 0 : -EBUSY; +} + +static int request_8051_lcb_access(struct hfi1_devdata *dd) +{ + int ret; + + ret = do_8051_command(dd, HCMD_MISC, + (u64)HCMD_MISC_GRANT_LCB_ACCESS << LOAD_DATA_FIELD_ID_SHIFT, + NULL); + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, "%s: command failed with error %d\n", + __func__, ret); + } + return ret == HCMD_SUCCESS ? 0 : -EBUSY; +} + +/* + * Set the LCB selector - allow host access. The DCC selector always + * points to the host. + */ +static inline void set_host_lcb_access(struct hfi1_devdata *dd) +{ + write_csr(dd, DC_DC8051_CFG_CSR_ACCESS_SEL, + DC_DC8051_CFG_CSR_ACCESS_SEL_DCC_SMASK + | DC_DC8051_CFG_CSR_ACCESS_SEL_LCB_SMASK); +} + +/* + * Clear the LCB selector - allow 8051 access. The DCC selector always + * points to the host. + */ +static inline void set_8051_lcb_access(struct hfi1_devdata *dd) +{ + write_csr(dd, DC_DC8051_CFG_CSR_ACCESS_SEL, + DC_DC8051_CFG_CSR_ACCESS_SEL_DCC_SMASK); +} + +/* + * Acquire LCB access from the 8051. If the host already has access, + * just increment a counter. Otherwise, inform the 8051 that the + * host is taking access. + * + * Returns: + * 0 on success + * -EBUSY if the 8051 has control and cannot be disturbed + * -errno if unable to acquire access from the 8051 + */ +int acquire_lcb_access(struct hfi1_devdata *dd, int sleep_ok) +{ + struct hfi1_pportdata *ppd = dd->pport; + int ret = 0; + + /* + * Use the host link state lock so the operation of this routine + * { link state check, selector change, count increment } can occur + * as a unit against a link state change. Otherwise there is a + * race between the state change and the count increment. + */ + if (sleep_ok) { + mutex_lock(&ppd->hls_lock); + } else { + while (mutex_trylock(&ppd->hls_lock) == EBUSY) + udelay(1); + } + + /* this access is valid only when the link is up */ + if ((ppd->host_link_state & HLS_UP) == 0) { + dd_dev_info(dd, "%s: link state %s not up\n", + __func__, link_state_name(ppd->host_link_state)); + ret = -EBUSY; + goto done; + } + + if (dd->lcb_access_count == 0) { + ret = request_host_lcb_access(dd); + if (ret) { + dd_dev_err(dd, + "%s: unable to acquire LCB access, err %d\n", + __func__, ret); + goto done; + } + set_host_lcb_access(dd); + } + dd->lcb_access_count++; +done: + mutex_unlock(&ppd->hls_lock); + return ret; +} + +/* + * Release LCB access by decrementing the use count. If the count is moving + * from 1 to 0, inform 8051 that it has control back. + * + * Returns: + * 0 on success + * -errno if unable to release access to the 8051 + */ +int release_lcb_access(struct hfi1_devdata *dd, int sleep_ok) +{ + int ret = 0; + + /* + * Use the host link state lock because the acquire needed it. + * Here, we only need to keep { selector change, count decrement } + * as a unit. + */ + if (sleep_ok) { + mutex_lock(&dd->pport->hls_lock); + } else { + while (mutex_trylock(&dd->pport->hls_lock) == EBUSY) + udelay(1); + } + + if (dd->lcb_access_count == 0) { + dd_dev_err(dd, "%s: LCB access count is zero. Skipping.\n", + __func__); + goto done; + } + + if (dd->lcb_access_count == 1) { + set_8051_lcb_access(dd); + ret = request_8051_lcb_access(dd); + if (ret) { + dd_dev_err(dd, + "%s: unable to release LCB access, err %d\n", + __func__, ret); + /* restore host access if the grant didn't work */ + set_host_lcb_access(dd); + goto done; + } + } + dd->lcb_access_count--; +done: + mutex_unlock(&dd->pport->hls_lock); + return ret; +} + +/* + * Initialize LCB access variables and state. Called during driver load, + * after most of the initialization is finished. + * + * The DC default is LCB access on for the host. The driver defaults to + * leaving access to the 8051. Assign access now - this constrains the call + * to this routine to be after all LCB set-up is done. In particular, after + * hf1_init_dd() -> set_up_interrupts() -> clear_all_interrupts() + */ +static void init_lcb_access(struct hfi1_devdata *dd) +{ + dd->lcb_access_count = 0; +} + +/* + * Write a response back to a 8051 request. + */ +static void hreq_response(struct hfi1_devdata *dd, u8 return_code, u16 rsp_data) +{ + write_csr(dd, DC_DC8051_CFG_EXT_DEV_0, + DC_DC8051_CFG_EXT_DEV_0_COMPLETED_SMASK + | (u64)return_code << DC_DC8051_CFG_EXT_DEV_0_RETURN_CODE_SHIFT + | (u64)rsp_data << DC_DC8051_CFG_EXT_DEV_0_RSP_DATA_SHIFT); +} + +/* + * Handle requests from the 8051. + */ +static void handle_8051_request(struct hfi1_devdata *dd) +{ + u64 reg; + u16 data; + u8 type; + + reg = read_csr(dd, DC_DC8051_CFG_EXT_DEV_1); + if ((reg & DC_DC8051_CFG_EXT_DEV_1_REQ_NEW_SMASK) == 0) + return; /* no request */ + + /* zero out COMPLETED so the response is seen */ + write_csr(dd, DC_DC8051_CFG_EXT_DEV_0, 0); + + /* extract request details */ + type = (reg >> DC_DC8051_CFG_EXT_DEV_1_REQ_TYPE_SHIFT) + & DC_DC8051_CFG_EXT_DEV_1_REQ_TYPE_MASK; + data = (reg >> DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_SHIFT) + & DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_MASK; + + switch (type) { + case HREQ_LOAD_CONFIG: + case HREQ_SAVE_CONFIG: + case HREQ_READ_CONFIG: + case HREQ_SET_TX_EQ_ABS: + case HREQ_SET_TX_EQ_REL: + case HREQ_ENABLE: + dd_dev_info(dd, "8051 request: request 0x%x not supported\n", + type); + hreq_response(dd, HREQ_NOT_SUPPORTED, 0); + break; + + case HREQ_CONFIG_DONE: + hreq_response(dd, HREQ_SUCCESS, 0); + break; + + case HREQ_INTERFACE_TEST: + hreq_response(dd, HREQ_SUCCESS, data); + break; + + default: + dd_dev_err(dd, "8051 request: unknown request 0x%x\n", type); + hreq_response(dd, HREQ_NOT_SUPPORTED, 0); + break; + } +} + +static void write_global_credit(struct hfi1_devdata *dd, + u8 vau, u16 total, u16 shared) +{ + write_csr(dd, SEND_CM_GLOBAL_CREDIT, + ((u64)total + << SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_SHIFT) + | ((u64)shared + << SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_SHIFT) + | ((u64)vau << SEND_CM_GLOBAL_CREDIT_AU_SHIFT)); +} + +/* + * Set up initial VL15 credits of the remote. Assumes the rest of + * the CM credit registers are zero from a previous global or credit reset . + */ +void set_up_vl15(struct hfi1_devdata *dd, u8 vau, u16 vl15buf) +{ + /* leave shared count at zero for both global and VL15 */ + write_global_credit(dd, vau, vl15buf, 0); + + /* We may need some credits for another VL when sending packets + * with the snoop interface. Dividing it down the middle for VL15 + * and VL0 should suffice. + */ + if (unlikely(dd->hfi1_snoop.mode_flag == HFI1_PORT_SNOOP_MODE)) { + write_csr(dd, SEND_CM_CREDIT_VL15, (u64)(vl15buf >> 1) + << SEND_CM_CREDIT_VL15_DEDICATED_LIMIT_VL_SHIFT); + write_csr(dd, SEND_CM_CREDIT_VL, (u64)(vl15buf >> 1) + << SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SHIFT); + } else { + write_csr(dd, SEND_CM_CREDIT_VL15, (u64)vl15buf + << SEND_CM_CREDIT_VL15_DEDICATED_LIMIT_VL_SHIFT); + } +} + +/* + * Zero all credit details from the previous connection and + * reset the CM manager's internal counters. + */ +void reset_link_credits(struct hfi1_devdata *dd) +{ + int i; + + /* remove all previous VL credit limits */ + for (i = 0; i < TXE_NUM_DATA_VL; i++) + write_csr(dd, SEND_CM_CREDIT_VL + (8*i), 0); + write_csr(dd, SEND_CM_CREDIT_VL15, 0); + write_global_credit(dd, 0, 0, 0); + /* reset the CM block */ + pio_send_control(dd, PSC_CM_RESET); +} + +/* convert a vCU to a CU */ +static u32 vcu_to_cu(u8 vcu) +{ + return 1 << vcu; +} + +/* convert a CU to a vCU */ +static u8 cu_to_vcu(u32 cu) +{ + return ilog2(cu); +} + +/* convert a vAU to an AU */ +static u32 vau_to_au(u8 vau) +{ + return 8 * (1 << vau); +} + +static void set_linkup_defaults(struct hfi1_pportdata *ppd) +{ + ppd->sm_trap_qp = 0x0; + ppd->sa_qp = 0x1; +} + +/* + * Graceful LCB shutdown. This leaves the LCB FIFOs in reset. + */ +static void lcb_shutdown(struct hfi1_devdata *dd, int abort) +{ + u64 reg; + + /* clear lcb run: LCB_CFG_RUN.EN = 0 */ + write_csr(dd, DC_LCB_CFG_RUN, 0); + /* set tx fifo reset: LCB_CFG_TX_FIFOS_RESET.VAL = 1 */ + write_csr(dd, DC_LCB_CFG_TX_FIFOS_RESET, + 1ull << DC_LCB_CFG_TX_FIFOS_RESET_VAL_SHIFT); + /* set dcc reset csr: DCC_CFG_RESET.{reset_lcb,reset_rx_fpe} = 1 */ + dd->lcb_err_en = read_csr(dd, DC_LCB_ERR_EN); + reg = read_csr(dd, DCC_CFG_RESET); + write_csr(dd, DCC_CFG_RESET, + reg + | (1ull << DCC_CFG_RESET_RESET_LCB_SHIFT) + | (1ull << DCC_CFG_RESET_RESET_RX_FPE_SHIFT)); + (void) read_csr(dd, DCC_CFG_RESET); /* make sure the write completed */ + if (!abort) { + udelay(1); /* must hold for the longer of 16cclks or 20ns */ + write_csr(dd, DCC_CFG_RESET, reg); + write_csr(dd, DC_LCB_ERR_EN, dd->lcb_err_en); + } +} + +/* + * This routine should be called after the link has been transitioned to + * OFFLINE (OFFLINE state has the side effect of putting the SerDes into + * reset). + * + * The expectation is that the caller of this routine would have taken + * care of properly transitioning the link into the correct state. + */ +static void dc_shutdown(struct hfi1_devdata *dd) +{ + unsigned long flags; + + spin_lock_irqsave(&dd->dc8051_lock, flags); + if (dd->dc_shutdown) { + spin_unlock_irqrestore(&dd->dc8051_lock, flags); + return; + } + dd->dc_shutdown = 1; + spin_unlock_irqrestore(&dd->dc8051_lock, flags); + /* Shutdown the LCB */ + lcb_shutdown(dd, 1); + /* Going to OFFLINE would have causes the 8051 to put the + * SerDes into reset already. Just need to shut down the 8051, + * itself. */ + write_csr(dd, DC_DC8051_CFG_RST, 0x1); +} + +/* Calling this after the DC has been brought out of reset should not + * do any damage. */ +static void dc_start(struct hfi1_devdata *dd) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&dd->dc8051_lock, flags); + if (!dd->dc_shutdown) + goto done; + spin_unlock_irqrestore(&dd->dc8051_lock, flags); + /* Take the 8051 out of reset */ + write_csr(dd, DC_DC8051_CFG_RST, 0ull); + /* Wait until 8051 is ready */ + ret = wait_fm_ready(dd, TIMEOUT_8051_START); + if (ret) { + dd_dev_err(dd, "%s: timeout starting 8051 firmware\n", + __func__); + } + /* Take away reset for LCB and RX FPE (set in lcb_shutdown). */ + write_csr(dd, DCC_CFG_RESET, 0x10); + /* lcb_shutdown() with abort=1 does not restore these */ + write_csr(dd, DC_LCB_ERR_EN, dd->lcb_err_en); + spin_lock_irqsave(&dd->dc8051_lock, flags); + dd->dc_shutdown = 0; +done: + spin_unlock_irqrestore(&dd->dc8051_lock, flags); +} + +/* + * These LCB adjustments are for the Aurora SerDes core in the FPGA. + */ +static void adjust_lcb_for_fpga_serdes(struct hfi1_devdata *dd) +{ + u64 rx_radr, tx_radr; + u32 version; + + if (dd->icode != ICODE_FPGA_EMULATION) + return; + + /* + * These LCB defaults on emulator _s are good, nothing to do here: + * LCB_CFG_TX_FIFOS_RADR + * LCB_CFG_RX_FIFOS_RADR + * LCB_CFG_LN_DCLK + * LCB_CFG_IGNORE_LOST_RCLK + */ + if (is_emulator_s(dd)) + return; + /* else this is _p */ + + version = emulator_rev(dd); + if (!is_a0(dd)) + version = 0x2d; /* all B0 use 0x2d or higher settings */ + + if (version <= 0x12) { + /* release 0x12 and below */ + + /* + * LCB_CFG_RX_FIFOS_RADR.RST_VAL = 0x9 + * LCB_CFG_RX_FIFOS_RADR.OK_TO_JUMP_VAL = 0x9 + * LCB_CFG_RX_FIFOS_RADR.DO_NOT_JUMP_VAL = 0xa + */ + rx_radr = + 0xaull << DC_LCB_CFG_RX_FIFOS_RADR_DO_NOT_JUMP_VAL_SHIFT + | 0x9ull << DC_LCB_CFG_RX_FIFOS_RADR_OK_TO_JUMP_VAL_SHIFT + | 0x9ull << DC_LCB_CFG_RX_FIFOS_RADR_RST_VAL_SHIFT; + /* + * LCB_CFG_TX_FIFOS_RADR.ON_REINIT = 0 (default) + * LCB_CFG_TX_FIFOS_RADR.RST_VAL = 6 + */ + tx_radr = 6ull << DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT; + } else if (version <= 0x18) { + /* release 0x13 up to 0x18 */ + /* LCB_CFG_RX_FIFOS_RADR = 0x988 */ + rx_radr = + 0x9ull << DC_LCB_CFG_RX_FIFOS_RADR_DO_NOT_JUMP_VAL_SHIFT + | 0x8ull << DC_LCB_CFG_RX_FIFOS_RADR_OK_TO_JUMP_VAL_SHIFT + | 0x8ull << DC_LCB_CFG_RX_FIFOS_RADR_RST_VAL_SHIFT; + tx_radr = 7ull << DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT; + } else if (version == 0x19) { + /* release 0x19 */ + /* LCB_CFG_RX_FIFOS_RADR = 0xa99 */ + rx_radr = + 0xAull << DC_LCB_CFG_RX_FIFOS_RADR_DO_NOT_JUMP_VAL_SHIFT + | 0x9ull << DC_LCB_CFG_RX_FIFOS_RADR_OK_TO_JUMP_VAL_SHIFT + | 0x9ull << DC_LCB_CFG_RX_FIFOS_RADR_RST_VAL_SHIFT; + tx_radr = 3ull << DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT; + } else if (version == 0x1a) { + /* release 0x1a */ + /* LCB_CFG_RX_FIFOS_RADR = 0x988 */ + rx_radr = + 0x9ull << DC_LCB_CFG_RX_FIFOS_RADR_DO_NOT_JUMP_VAL_SHIFT + | 0x8ull << DC_LCB_CFG_RX_FIFOS_RADR_OK_TO_JUMP_VAL_SHIFT + | 0x8ull << DC_LCB_CFG_RX_FIFOS_RADR_RST_VAL_SHIFT; + tx_radr = 7ull << DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT; + write_csr(dd, DC_LCB_CFG_LN_DCLK, 1ull); + } else { + /* release 0x1b and higher */ + /* LCB_CFG_RX_FIFOS_RADR = 0x877 */ + rx_radr = + 0x8ull << DC_LCB_CFG_RX_FIFOS_RADR_DO_NOT_JUMP_VAL_SHIFT + | 0x7ull << DC_LCB_CFG_RX_FIFOS_RADR_OK_TO_JUMP_VAL_SHIFT + | 0x7ull << DC_LCB_CFG_RX_FIFOS_RADR_RST_VAL_SHIFT; + tx_radr = 3ull << DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT; + } + + write_csr(dd, DC_LCB_CFG_RX_FIFOS_RADR, rx_radr); + /* LCB_CFG_IGNORE_LOST_RCLK.EN = 1 */ + write_csr(dd, DC_LCB_CFG_IGNORE_LOST_RCLK, + DC_LCB_CFG_IGNORE_LOST_RCLK_EN_SMASK); + write_csr(dd, DC_LCB_CFG_TX_FIFOS_RADR, tx_radr); +} + +/* + * Handle a SMA idle message + * + * This is a work-queue function outside of the interrupt. + */ +void handle_sma_message(struct work_struct *work) +{ + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + sma_message_work); + struct hfi1_devdata *dd = ppd->dd; + u64 msg; + int ret; + + /* msg is bytes 1-4 of the 40-bit idle message - the command code + is stripped off */ + ret = read_idle_sma(dd, &msg); + if (ret) + return; + dd_dev_info(dd, "%s: SMA message 0x%llx\n", __func__, msg); + /* + * React to the SMA message. Byte[1] (0 for us) is the command. + */ + switch (msg & 0xff) { + case SMA_IDLE_ARM: + /* + * See OPAv1 table 9-14 - HFI and External Switch Ports Key + * State Transitions + * + * Only expected in INIT or ARMED, discard otherwise. + */ + if (ppd->host_link_state & (HLS_UP_INIT | HLS_UP_ARMED)) + ppd->neighbor_normal = 1; + break; + case SMA_IDLE_ACTIVE: + /* + * See OPAv1 table 9-14 - HFI and External Switch Ports Key + * State Transitions + * + * Can activate the node. Discard otherwise. + */ + if (ppd->host_link_state == HLS_UP_ARMED + && ppd->is_active_optimize_enabled) { + ppd->neighbor_normal = 1; + ret = set_link_state(ppd, HLS_UP_ACTIVE); + if (ret) + dd_dev_err( + dd, + "%s: received Active SMA idle message, couldn't set link to Active\n", + __func__); + } + break; + default: + dd_dev_err(dd, + "%s: received unexpected SMA idle message 0x%llx\n", + __func__, msg); + break; + } +} + +static void adjust_rcvctrl(struct hfi1_devdata *dd, u64 add, u64 clear) +{ + u64 rcvctrl; + unsigned long flags; + + spin_lock_irqsave(&dd->rcvctrl_lock, flags); + rcvctrl = read_csr(dd, RCV_CTRL); + rcvctrl |= add; + rcvctrl &= ~clear; + write_csr(dd, RCV_CTRL, rcvctrl); + spin_unlock_irqrestore(&dd->rcvctrl_lock, flags); +} + +static inline void add_rcvctrl(struct hfi1_devdata *dd, u64 add) +{ + adjust_rcvctrl(dd, add, 0); +} + +static inline void clear_rcvctrl(struct hfi1_devdata *dd, u64 clear) +{ + adjust_rcvctrl(dd, 0, clear); +} + +/* + * Called from all interrupt handlers to start handling an SPC freeze. + */ +void start_freeze_handling(struct hfi1_pportdata *ppd, int flags) +{ + struct hfi1_devdata *dd = ppd->dd; + struct send_context *sc; + int i; + + if (flags & FREEZE_SELF) + write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_FREEZE_SMASK); + + /* enter frozen mode */ + dd->flags |= HFI1_FROZEN; + + /* notify all SDMA engines that they are going into a freeze */ + sdma_freeze_notify(dd, !!(flags & FREEZE_LINK_DOWN)); + + /* do halt pre-handling on all enabled send contexts */ + for (i = 0; i < dd->num_send_contexts; i++) { + sc = dd->send_contexts[i].sc; + if (sc && (sc->flags & SCF_ENABLED)) + sc_stop(sc, SCF_FROZEN | SCF_HALTED); + } + + /* Send context are frozen. Notify user space */ + hfi1_set_uevent_bits(ppd, _HFI1_EVENT_FROZEN_BIT); + + if (flags & FREEZE_ABORT) { + dd_dev_err(dd, + "Aborted freeze recovery. Please REBOOT system\n"); + return; + } + /* queue non-interrupt handler */ + queue_work(ppd->hfi1_wq, &ppd->freeze_work); +} + +/* + * Wait until all 4 sub-blocks indicate that they have frozen or unfrozen, + * depending on the "freeze" parameter. + * + * No need to return an error if it times out, our only option + * is to proceed anyway. + */ +static void wait_for_freeze_status(struct hfi1_devdata *dd, int freeze) +{ + unsigned long timeout; + u64 reg; + + timeout = jiffies + msecs_to_jiffies(FREEZE_STATUS_TIMEOUT); + while (1) { + reg = read_csr(dd, CCE_STATUS); + if (freeze) { + /* waiting until all indicators are set */ + if ((reg & ALL_FROZE) == ALL_FROZE) + return; /* all done */ + } else { + /* waiting until all indicators are clear */ + if ((reg & ALL_FROZE) == 0) + return; /* all done */ + } + + if (time_after(jiffies, timeout)) { + dd_dev_err(dd, + "Time out waiting for SPC %sfreeze, bits 0x%llx, expecting 0x%llx, continuing", + freeze ? "" : "un", + reg & ALL_FROZE, + freeze ? ALL_FROZE : 0ull); + return; + } + usleep_range(80, 120); + } +} + +/* + * Do all freeze handling for the RXE block. + */ +static void rxe_freeze(struct hfi1_devdata *dd) +{ + int i; + + /* disable port */ + clear_rcvctrl(dd, RCV_CTRL_RCV_PORT_ENABLE_SMASK); + + /* disable all receive contexts */ + for (i = 0; i < dd->num_rcv_contexts; i++) + hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_DIS, i); +} + +/* + * Unfreeze handling for the RXE block - kernel contexts only. + * This will also enable the port. User contexts will do unfreeze + * handling on a per-context basis as they call into the driver. + * + */ +static void rxe_kernel_unfreeze(struct hfi1_devdata *dd) +{ + int i; + + /* enable all kernel contexts */ + for (i = 0; i < dd->n_krcv_queues; i++) + hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_ENB, i); + + /* enable port */ + add_rcvctrl(dd, RCV_CTRL_RCV_PORT_ENABLE_SMASK); +} + +/* + * Non-interrupt SPC freeze handling. + * + * This is a work-queue function outside of the triggering interrupt. + */ +void handle_freeze(struct work_struct *work) +{ + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + freeze_work); + struct hfi1_devdata *dd = ppd->dd; + + /* wait for freeze indicators on all affected blocks */ + dd_dev_info(dd, "Entering SPC freeze\n"); + wait_for_freeze_status(dd, 1); + + /* SPC is now frozen */ + + /* do send PIO freeze steps */ + pio_freeze(dd); + + /* do send DMA freeze steps */ + sdma_freeze(dd); + + /* do send egress freeze steps - nothing to do */ + + /* do receive freeze steps */ + rxe_freeze(dd); + + /* + * Unfreeze the hardware - clear the freeze, wait for each + * block's frozen bit to clear, then clear the frozen flag. + */ + write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_UNFREEZE_SMASK); + wait_for_freeze_status(dd, 0); + + if (is_a0(dd)) { + write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_FREEZE_SMASK); + wait_for_freeze_status(dd, 1); + write_csr(dd, CCE_CTRL, CCE_CTRL_SPC_UNFREEZE_SMASK); + wait_for_freeze_status(dd, 0); + } + + /* do send PIO unfreeze steps for kernel contexts */ + pio_kernel_unfreeze(dd); + + /* do send DMA unfreeze steps */ + sdma_unfreeze(dd); + + /* do send egress unfreeze steps - nothing to do */ + + /* do receive unfreeze steps for kernel contexts */ + rxe_kernel_unfreeze(dd); + + /* + * The unfreeze procedure touches global device registers when + * it disables and re-enables RXE. Mark the device unfrozen + * after all that is done so other parts of the driver waiting + * for the device to unfreeze don't do things out of order. + * + * The above implies that the meaning of HFI1_FROZEN flag is + * "Device has gone into freeze mode and freeze mode handling + * is still in progress." + * + * The flag will be removed when freeze mode processing has + * completed. + */ + dd->flags &= ~HFI1_FROZEN; + wake_up(&dd->event_queue); + + /* no longer frozen */ + dd_dev_err(dd, "Exiting SPC freeze\n"); +} + +/* + * Handle a link up interrupt from the 8051. + * + * This is a work-queue function outside of the interrupt. + */ +void handle_link_up(struct work_struct *work) +{ + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + link_up_work); + set_link_state(ppd, HLS_UP_INIT); + + /* cache the read of DC_LCB_STS_ROUND_TRIP_LTP_CNT */ + read_ltp_rtt(ppd->dd); + /* + * OPA specifies that certain counters are cleared on a transition + * to link up, so do that. + */ + clear_linkup_counters(ppd->dd); + /* + * And (re)set link up default values. + */ + set_linkup_defaults(ppd); + + /* enforce link speed enabled */ + if ((ppd->link_speed_active & ppd->link_speed_enabled) == 0) { + /* oops - current speed is not enabled, bounce */ + dd_dev_err(ppd->dd, + "Link speed active 0x%x is outside enabled 0x%x, downing link\n", + ppd->link_speed_active, ppd->link_speed_enabled); + set_link_down_reason(ppd, OPA_LINKDOWN_REASON_SPEED_POLICY, 0, + OPA_LINKDOWN_REASON_SPEED_POLICY); + set_link_state(ppd, HLS_DN_OFFLINE); + start_link(ppd); + } +} + +/* Several pieces of LNI information were cached for SMA in ppd. + * Reset these on link down */ +static void reset_neighbor_info(struct hfi1_pportdata *ppd) +{ + ppd->neighbor_guid = 0; + ppd->neighbor_port_number = 0; + ppd->neighbor_type = 0; + ppd->neighbor_fm_security = 0; +} + +/* + * Handle a link down interrupt from the 8051. + * + * This is a work-queue function outside of the interrupt. + */ +void handle_link_down(struct work_struct *work) +{ + u8 lcl_reason, neigh_reason = 0; + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + link_down_work); + + /* go offline first, then deal with reasons */ + set_link_state(ppd, HLS_DN_OFFLINE); + + lcl_reason = 0; + read_planned_down_reason_code(ppd->dd, &neigh_reason); + + /* + * If no reason, assume peer-initiated but missed + * LinkGoingDown idle flits. + */ + if (neigh_reason == 0) + lcl_reason = OPA_LINKDOWN_REASON_NEIGHBOR_UNKNOWN; + + set_link_down_reason(ppd, lcl_reason, neigh_reason, 0); + + reset_neighbor_info(ppd); + + /* disable the port */ + clear_rcvctrl(ppd->dd, RCV_CTRL_RCV_PORT_ENABLE_SMASK); + + /* If there is no cable attached, turn the DC off. Otherwise, + * start the link bring up. */ + if (!qsfp_mod_present(ppd)) + dc_shutdown(ppd->dd); + else + start_link(ppd); +} + +void handle_link_bounce(struct work_struct *work) +{ + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + link_bounce_work); + + /* + * Only do something if the link is currently up. + */ + if (ppd->host_link_state & HLS_UP) { + set_link_state(ppd, HLS_DN_OFFLINE); + start_link(ppd); + } else { + dd_dev_info(ppd->dd, "%s: link not up (%s), nothing to do\n", + __func__, link_state_name(ppd->host_link_state)); + } +} + +/* + * Mask conversion: Capability exchange to Port LTP. The capability + * exchange has an implicit 16b CRC that is mandatory. + */ +static int cap_to_port_ltp(int cap) +{ + int port_ltp = PORT_LTP_CRC_MODE_16; /* this mode is mandatory */ + + if (cap & CAP_CRC_14B) + port_ltp |= PORT_LTP_CRC_MODE_14; + if (cap & CAP_CRC_48B) + port_ltp |= PORT_LTP_CRC_MODE_48; + if (cap & CAP_CRC_12B_16B_PER_LANE) + port_ltp |= PORT_LTP_CRC_MODE_PER_LANE; + + return port_ltp; +} + +/* + * Convert an OPA Port LTP mask to capability mask + */ +int port_ltp_to_cap(int port_ltp) +{ + int cap_mask = 0; + + if (port_ltp & PORT_LTP_CRC_MODE_14) + cap_mask |= CAP_CRC_14B; + if (port_ltp & PORT_LTP_CRC_MODE_48) + cap_mask |= CAP_CRC_48B; + if (port_ltp & PORT_LTP_CRC_MODE_PER_LANE) + cap_mask |= CAP_CRC_12B_16B_PER_LANE; + + return cap_mask; +} + +/* + * Convert a single DC LCB CRC mode to an OPA Port LTP mask. + */ +static int lcb_to_port_ltp(int lcb_crc) +{ + int port_ltp = 0; + + if (lcb_crc == LCB_CRC_12B_16B_PER_LANE) + port_ltp = PORT_LTP_CRC_MODE_PER_LANE; + else if (lcb_crc == LCB_CRC_48B) + port_ltp = PORT_LTP_CRC_MODE_48; + else if (lcb_crc == LCB_CRC_14B) + port_ltp = PORT_LTP_CRC_MODE_14; + else + port_ltp = PORT_LTP_CRC_MODE_16; + + return port_ltp; +} + +/* + * Our neighbor has indicated that we are allowed to act as a fabric + * manager, so place the full management partition key in the second + * (0-based) pkey array position (see OPAv1, section 20.2.2.6.8). Note + * that we should already have the limited management partition key in + * array element 1, and also that the port is not yet up when + * add_full_mgmt_pkey() is invoked. + */ +static void add_full_mgmt_pkey(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + + /* Sanity check - ppd->pkeys[2] should be 0 */ + if (ppd->pkeys[2] != 0) + dd_dev_err(dd, "%s pkey[2] already set to 0x%x, resetting it to 0x%x\n", + __func__, ppd->pkeys[2], FULL_MGMT_P_KEY); + ppd->pkeys[2] = FULL_MGMT_P_KEY; + (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_PKEYS, 0); +} + +/* + * Convert the given link width to the OPA link width bitmask. + */ +static u16 link_width_to_bits(struct hfi1_devdata *dd, u16 width) +{ + switch (width) { + case 0: + /* + * Simulator and quick linkup do not set the width. + * Just set it to 4x without complaint. + */ + if (dd->icode == ICODE_FUNCTIONAL_SIMULATOR || quick_linkup) + return OPA_LINK_WIDTH_4X; + return 0; /* no lanes up */ + case 1: return OPA_LINK_WIDTH_1X; + case 2: return OPA_LINK_WIDTH_2X; + case 3: return OPA_LINK_WIDTH_3X; + default: + dd_dev_info(dd, "%s: invalid width %d, using 4\n", + __func__, width); + /* fall through */ + case 4: return OPA_LINK_WIDTH_4X; + } +} + +/* + * Do a population count on the bottom nibble. + */ +static const u8 bit_counts[16] = { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 +}; +static inline u8 nibble_to_count(u8 nibble) +{ + return bit_counts[nibble & 0xf]; +} + +/* + * Read the active lane information from the 8051 registers and return + * their widths. + * + * Active lane information is found in these 8051 registers: + * enable_lane_tx + * enable_lane_rx + */ +static void get_link_widths(struct hfi1_devdata *dd, u16 *tx_width, + u16 *rx_width) +{ + u16 tx, rx; + u8 enable_lane_rx; + u8 enable_lane_tx; + u8 tx_polarity_inversion; + u8 rx_polarity_inversion; + u8 max_rate; + + /* read the active lanes */ + read_tx_settings(dd, &enable_lane_tx, &tx_polarity_inversion, + &rx_polarity_inversion, &max_rate); + read_local_lni(dd, &enable_lane_rx); + + /* convert to counts */ + tx = nibble_to_count(enable_lane_tx); + rx = nibble_to_count(enable_lane_rx); + + /* + * Set link_speed_active here, overriding what was set in + * handle_verify_cap(). The ASIC 8051 firmware does not correctly + * set the max_rate field in handle_verify_cap until v0.19. + */ + if ((dd->icode == ICODE_RTL_SILICON) + && (dd->dc8051_ver < dc8051_ver(0, 19))) { + /* max_rate: 0 = 12.5G, 1 = 25G */ + switch (max_rate) { + case 0: + dd->pport[0].link_speed_active = OPA_LINK_SPEED_12_5G; + break; + default: + dd_dev_err(dd, + "%s: unexpected max rate %d, using 25Gb\n", + __func__, (int)max_rate); + /* fall through */ + case 1: + dd->pport[0].link_speed_active = OPA_LINK_SPEED_25G; + break; + } + } + + dd_dev_info(dd, + "Fabric active lanes (width): tx 0x%x (%d), rx 0x%x (%d)\n", + enable_lane_tx, tx, enable_lane_rx, rx); + *tx_width = link_width_to_bits(dd, tx); + *rx_width = link_width_to_bits(dd, rx); +} + +/* + * Read verify_cap_local_fm_link_width[1] to obtain the link widths. + * Valid after the end of VerifyCap and during LinkUp. Does not change + * after link up. I.e. look elsewhere for downgrade information. + * + * Bits are: + * + bits [7:4] contain the number of active transmitters + * + bits [3:0] contain the number of active receivers + * These are numbers 1 through 4 and can be different values if the + * link is asymmetric. + * + * verify_cap_local_fm_link_width[0] retains its original value. + */ +static void get_linkup_widths(struct hfi1_devdata *dd, u16 *tx_width, + u16 *rx_width) +{ + u16 widths, tx, rx; + u8 misc_bits, local_flags; + u16 active_tx, active_rx; + + read_vc_local_link_width(dd, &misc_bits, &local_flags, &widths); + tx = widths >> 12; + rx = (widths >> 8) & 0xf; + + *tx_width = link_width_to_bits(dd, tx); + *rx_width = link_width_to_bits(dd, rx); + + /* print the active widths */ + get_link_widths(dd, &active_tx, &active_rx); +} + +/* + * Set ppd->link_width_active and ppd->link_width_downgrade_active using + * hardware information when the link first comes up. + * + * The link width is not available until after VerifyCap.AllFramesReceived + * (the trigger for handle_verify_cap), so this is outside that routine + * and should be called when the 8051 signals linkup. + */ +void get_linkup_link_widths(struct hfi1_pportdata *ppd) +{ + u16 tx_width, rx_width; + + /* get end-of-LNI link widths */ + get_linkup_widths(ppd->dd, &tx_width, &rx_width); + + /* use tx_width as the link is supposed to be symmetric on link up */ + ppd->link_width_active = tx_width; + /* link width downgrade active (LWD.A) starts out matching LW.A */ + ppd->link_width_downgrade_tx_active = ppd->link_width_active; + ppd->link_width_downgrade_rx_active = ppd->link_width_active; + /* per OPA spec, on link up LWD.E resets to LWD.S */ + ppd->link_width_downgrade_enabled = ppd->link_width_downgrade_supported; + /* cache the active egress rate (units {10^6 bits/sec]) */ + ppd->current_egress_rate = active_egress_rate(ppd); +} + +/* + * Handle a verify capabilities interrupt from the 8051. + * + * This is a work-queue function outside of the interrupt. + */ +void handle_verify_cap(struct work_struct *work) +{ + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + link_vc_work); + struct hfi1_devdata *dd = ppd->dd; + u64 reg; + u8 power_management; + u8 continious; + u8 vcu; + u8 vau; + u8 z; + u16 vl15buf; + u16 link_widths; + u16 crc_mask; + u16 crc_val; + u16 device_id; + u16 active_tx, active_rx; + u8 partner_supported_crc; + u8 remote_tx_rate; + u8 device_rev; + + set_link_state(ppd, HLS_VERIFY_CAP); + + lcb_shutdown(dd, 0); + adjust_lcb_for_fpga_serdes(dd); + + /* + * These are now valid: + * remote VerifyCap fields in the general LNI config + * CSR DC8051_STS_REMOTE_GUID + * CSR DC8051_STS_REMOTE_NODE_TYPE + * CSR DC8051_STS_REMOTE_FM_SECURITY + * CSR DC8051_STS_REMOTE_PORT_NO + */ + + read_vc_remote_phy(dd, &power_management, &continious); + read_vc_remote_fabric( + dd, + &vau, + &z, + &vcu, + &vl15buf, + &partner_supported_crc); + read_vc_remote_link_width(dd, &remote_tx_rate, &link_widths); + read_remote_device_id(dd, &device_id, &device_rev); + /* + * And the 'MgmtAllowed' information, which is exchanged during + * LNI, is also be available at this point. + */ + read_mgmt_allowed(dd, &ppd->mgmt_allowed); + /* print the active widths */ + get_link_widths(dd, &active_tx, &active_rx); + dd_dev_info(dd, + "Peer PHY: power management 0x%x, continuous updates 0x%x\n", + (int)power_management, (int)continious); + dd_dev_info(dd, + "Peer Fabric: vAU %d, Z %d, vCU %d, vl15 credits 0x%x, CRC sizes 0x%x\n", + (int)vau, + (int)z, + (int)vcu, + (int)vl15buf, + (int)partner_supported_crc); + dd_dev_info(dd, "Peer Link Width: tx rate 0x%x, widths 0x%x\n", + (u32)remote_tx_rate, (u32)link_widths); + dd_dev_info(dd, "Peer Device ID: 0x%04x, Revision 0x%02x\n", + (u32)device_id, (u32)device_rev); + /* + * The peer vAU value just read is the peer receiver value. HFI does + * not support a transmit vAU of 0 (AU == 8). We advertised that + * with Z=1 in the fabric capabilities sent to the peer. The peer + * will see our Z=1, and, if it advertised a vAU of 0, will move its + * receive to vAU of 1 (AU == 16). Do the same here. We do not care + * about the peer Z value - our sent vAU is 3 (hardwired) and is not + * subject to the Z value exception. + */ + if (vau == 0) + vau = 1; + set_up_vl15(dd, vau, vl15buf); + + /* set up the LCB CRC mode */ + crc_mask = ppd->port_crc_mode_enabled & partner_supported_crc; + + /* order is important: use the lowest bit in common */ + if (crc_mask & CAP_CRC_14B) + crc_val = LCB_CRC_14B; + else if (crc_mask & CAP_CRC_48B) + crc_val = LCB_CRC_48B; + else if (crc_mask & CAP_CRC_12B_16B_PER_LANE) + crc_val = LCB_CRC_12B_16B_PER_LANE; + else + crc_val = LCB_CRC_16B; + + dd_dev_info(dd, "Final LCB CRC mode: %d\n", (int)crc_val); + write_csr(dd, DC_LCB_CFG_CRC_MODE, + (u64)crc_val << DC_LCB_CFG_CRC_MODE_TX_VAL_SHIFT); + + /* set (14b only) or clear sideband credit */ + reg = read_csr(dd, SEND_CM_CTRL); + if (crc_val == LCB_CRC_14B && crc_14b_sideband) { + write_csr(dd, SEND_CM_CTRL, + reg | SEND_CM_CTRL_FORCE_CREDIT_MODE_SMASK); + } else { + write_csr(dd, SEND_CM_CTRL, + reg & ~SEND_CM_CTRL_FORCE_CREDIT_MODE_SMASK); + } + + ppd->link_speed_active = 0; /* invalid value */ + if (dd->dc8051_ver < dc8051_ver(0, 20)) { + /* remote_tx_rate: 0 = 12.5G, 1 = 25G */ + switch (remote_tx_rate) { + case 0: + ppd->link_speed_active = OPA_LINK_SPEED_12_5G; + break; + case 1: + ppd->link_speed_active = OPA_LINK_SPEED_25G; + break; + } + } else { + /* actual rate is highest bit of the ANDed rates */ + u8 rate = remote_tx_rate & ppd->local_tx_rate; + + if (rate & 2) + ppd->link_speed_active = OPA_LINK_SPEED_25G; + else if (rate & 1) + ppd->link_speed_active = OPA_LINK_SPEED_12_5G; + } + if (ppd->link_speed_active == 0) { + dd_dev_err(dd, "%s: unexpected remote tx rate %d, using 25Gb\n", + __func__, (int)remote_tx_rate); + ppd->link_speed_active = OPA_LINK_SPEED_25G; + } + + /* + * Cache the values of the supported, enabled, and active + * LTP CRC modes to return in 'portinfo' queries. But the bit + * flags that are returned in the portinfo query differ from + * what's in the link_crc_mask, crc_sizes, and crc_val + * variables. Convert these here. + */ + ppd->port_ltp_crc_mode = cap_to_port_ltp(link_crc_mask) << 8; + /* supported crc modes */ + ppd->port_ltp_crc_mode |= + cap_to_port_ltp(ppd->port_crc_mode_enabled) << 4; + /* enabled crc modes */ + ppd->port_ltp_crc_mode |= lcb_to_port_ltp(crc_val); + /* active crc mode */ + + /* set up the remote credit return table */ + assign_remote_cm_au_table(dd, vcu); + + /* + * The LCB is reset on entry to handle_verify_cap(), so this must + * be applied on every link up. + * + * Adjust LCB error kill enable to kill the link if + * these RBUF errors are seen: + * REPLAY_BUF_MBE_SMASK + * FLIT_INPUT_BUF_MBE_SMASK + */ + if (is_a0(dd)) { /* fixed in B0 */ + reg = read_csr(dd, DC_LCB_CFG_LINK_KILL_EN); + reg |= DC_LCB_CFG_LINK_KILL_EN_REPLAY_BUF_MBE_SMASK + | DC_LCB_CFG_LINK_KILL_EN_FLIT_INPUT_BUF_MBE_SMASK; + write_csr(dd, DC_LCB_CFG_LINK_KILL_EN, reg); + } + + /* pull LCB fifos out of reset - all fifo clocks must be stable */ + write_csr(dd, DC_LCB_CFG_TX_FIFOS_RESET, 0); + + /* give 8051 access to the LCB CSRs */ + write_csr(dd, DC_LCB_ERR_EN, 0); /* mask LCB errors */ + set_8051_lcb_access(dd); + + ppd->neighbor_guid = + read_csr(dd, DC_DC8051_STS_REMOTE_GUID); + ppd->neighbor_port_number = read_csr(dd, DC_DC8051_STS_REMOTE_PORT_NO) & + DC_DC8051_STS_REMOTE_PORT_NO_VAL_SMASK; + ppd->neighbor_type = + read_csr(dd, DC_DC8051_STS_REMOTE_NODE_TYPE) & + DC_DC8051_STS_REMOTE_NODE_TYPE_VAL_MASK; + ppd->neighbor_fm_security = + read_csr(dd, DC_DC8051_STS_REMOTE_FM_SECURITY) & + DC_DC8051_STS_LOCAL_FM_SECURITY_DISABLED_MASK; + dd_dev_info(dd, + "Neighbor Guid: %llx Neighbor type %d MgmtAllowed %d FM security bypass %d\n", + ppd->neighbor_guid, ppd->neighbor_type, + ppd->mgmt_allowed, ppd->neighbor_fm_security); + if (ppd->mgmt_allowed) + add_full_mgmt_pkey(ppd); + + /* tell the 8051 to go to LinkUp */ + set_link_state(ppd, HLS_GOING_UP); +} + +/* + * Apply the link width downgrade enabled policy against the current active + * link widths. + * + * Called when the enabled policy changes or the active link widths change. + */ +void apply_link_downgrade_policy(struct hfi1_pportdata *ppd, int refresh_widths) +{ + int skip = 1; + int do_bounce = 0; + u16 lwde = ppd->link_width_downgrade_enabled; + u16 tx, rx; + + mutex_lock(&ppd->hls_lock); + /* only apply if the link is up */ + if (ppd->host_link_state & HLS_UP) + skip = 0; + mutex_unlock(&ppd->hls_lock); + if (skip) + return; + + if (refresh_widths) { + get_link_widths(ppd->dd, &tx, &rx); + ppd->link_width_downgrade_tx_active = tx; + ppd->link_width_downgrade_rx_active = rx; + } + + if (lwde == 0) { + /* downgrade is disabled */ + + /* bounce if not at starting active width */ + if ((ppd->link_width_active != + ppd->link_width_downgrade_tx_active) + || (ppd->link_width_active != + ppd->link_width_downgrade_rx_active)) { + dd_dev_err(ppd->dd, + "Link downgrade is disabled and link has downgraded, downing link\n"); + dd_dev_err(ppd->dd, + " original 0x%x, tx active 0x%x, rx active 0x%x\n", + ppd->link_width_active, + ppd->link_width_downgrade_tx_active, + ppd->link_width_downgrade_rx_active); + do_bounce = 1; + } + } else if ((lwde & ppd->link_width_downgrade_tx_active) == 0 + || (lwde & ppd->link_width_downgrade_rx_active) == 0) { + /* Tx or Rx is outside the enabled policy */ + dd_dev_err(ppd->dd, + "Link is outside of downgrade allowed, downing link\n"); + dd_dev_err(ppd->dd, + " enabled 0x%x, tx active 0x%x, rx active 0x%x\n", + lwde, + ppd->link_width_downgrade_tx_active, + ppd->link_width_downgrade_rx_active); + do_bounce = 1; + } + + if (do_bounce) { + set_link_down_reason(ppd, OPA_LINKDOWN_REASON_WIDTH_POLICY, 0, + OPA_LINKDOWN_REASON_WIDTH_POLICY); + set_link_state(ppd, HLS_DN_OFFLINE); + start_link(ppd); + } +} + +/* + * Handle a link downgrade interrupt from the 8051. + * + * This is a work-queue function outside of the interrupt. + */ +void handle_link_downgrade(struct work_struct *work) +{ + struct hfi1_pportdata *ppd = container_of(work, struct hfi1_pportdata, + link_downgrade_work); + + dd_dev_info(ppd->dd, "8051: Link width downgrade\n"); + apply_link_downgrade_policy(ppd, 1); +} + +static char *dcc_err_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, dcc_err_flags, + ARRAY_SIZE(dcc_err_flags)); +} + +static char *lcb_err_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, lcb_err_flags, + ARRAY_SIZE(lcb_err_flags)); +} + +static char *dc8051_err_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, dc8051_err_flags, + ARRAY_SIZE(dc8051_err_flags)); +} + +static char *dc8051_info_err_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, dc8051_info_err_flags, + ARRAY_SIZE(dc8051_info_err_flags)); +} + +static char *dc8051_info_host_msg_string(char *buf, int buf_len, u64 flags) +{ + return flag_string(buf, buf_len, flags, dc8051_info_host_msg_flags, + ARRAY_SIZE(dc8051_info_host_msg_flags)); +} + +static void handle_8051_interrupt(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + struct hfi1_pportdata *ppd = dd->pport; + u64 info, err, host_msg; + int queue_link_down = 0; + char buf[96]; + + /* look at the flags */ + if (reg & DC_DC8051_ERR_FLG_SET_BY_8051_SMASK) { + /* 8051 information set by firmware */ + /* read DC8051_DBG_ERR_INFO_SET_BY_8051 for details */ + info = read_csr(dd, DC_DC8051_DBG_ERR_INFO_SET_BY_8051); + err = (info >> DC_DC8051_DBG_ERR_INFO_SET_BY_8051_ERROR_SHIFT) + & DC_DC8051_DBG_ERR_INFO_SET_BY_8051_ERROR_MASK; + host_msg = (info >> + DC_DC8051_DBG_ERR_INFO_SET_BY_8051_HOST_MSG_SHIFT) + & DC_DC8051_DBG_ERR_INFO_SET_BY_8051_HOST_MSG_MASK; + + /* + * Handle error flags. + */ + if (err & FAILED_LNI) { + /* + * LNI error indications are cleared by the 8051 + * only when starting polling. Only pay attention + * to them when in the states that occur during + * LNI. + */ + if (ppd->host_link_state + & (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) { + queue_link_down = 1; + dd_dev_info(dd, "Link error: %s\n", + dc8051_info_err_string(buf, + sizeof(buf), + err & FAILED_LNI)); + } + err &= ~(u64)FAILED_LNI; + } + if (err) { + /* report remaining errors, but do not do anything */ + dd_dev_err(dd, "8051 info error: %s\n", + dc8051_info_err_string(buf, sizeof(buf), err)); + } + + /* + * Handle host message flags. + */ + if (host_msg & HOST_REQ_DONE) { + /* + * Presently, the driver does a busy wait for + * host requests to complete. This is only an + * informational message. + * NOTE: The 8051 clears the host message + * information *on the next 8051 command*. + * Therefore, when linkup is achieved, + * this flag will still be set. + */ + host_msg &= ~(u64)HOST_REQ_DONE; + } + if (host_msg & BC_SMA_MSG) { + queue_work(ppd->hfi1_wq, &ppd->sma_message_work); + host_msg &= ~(u64)BC_SMA_MSG; + } + if (host_msg & LINKUP_ACHIEVED) { + dd_dev_info(dd, "8051: Link up\n"); + queue_work(ppd->hfi1_wq, &ppd->link_up_work); + host_msg &= ~(u64)LINKUP_ACHIEVED; + } + if (host_msg & EXT_DEVICE_CFG_REQ) { + handle_8051_request(dd); + host_msg &= ~(u64)EXT_DEVICE_CFG_REQ; + } + if (host_msg & VERIFY_CAP_FRAME) { + queue_work(ppd->hfi1_wq, &ppd->link_vc_work); + host_msg &= ~(u64)VERIFY_CAP_FRAME; + } + if (host_msg & LINK_GOING_DOWN) { + const char *extra = ""; + /* no downgrade action needed if going down */ + if (host_msg & LINK_WIDTH_DOWNGRADED) { + host_msg &= ~(u64)LINK_WIDTH_DOWNGRADED; + extra = " (ignoring downgrade)"; + } + dd_dev_info(dd, "8051: Link down%s\n", extra); + queue_link_down = 1; + host_msg &= ~(u64)LINK_GOING_DOWN; + } + if (host_msg & LINK_WIDTH_DOWNGRADED) { + queue_work(ppd->hfi1_wq, &ppd->link_downgrade_work); + host_msg &= ~(u64)LINK_WIDTH_DOWNGRADED; + } + if (host_msg) { + /* report remaining messages, but do not do anything */ + dd_dev_info(dd, "8051 info host message: %s\n", + dc8051_info_host_msg_string(buf, sizeof(buf), + host_msg)); + } + + reg &= ~DC_DC8051_ERR_FLG_SET_BY_8051_SMASK; + } + if (reg & DC_DC8051_ERR_FLG_LOST_8051_HEART_BEAT_SMASK) { + /* + * Lost the 8051 heartbeat. If this happens, we + * receive constant interrupts about it. Disable + * the interrupt after the first. + */ + dd_dev_err(dd, "Lost 8051 heartbeat\n"); + write_csr(dd, DC_DC8051_ERR_EN, + read_csr(dd, DC_DC8051_ERR_EN) + & ~DC_DC8051_ERR_EN_LOST_8051_HEART_BEAT_SMASK); + + reg &= ~DC_DC8051_ERR_FLG_LOST_8051_HEART_BEAT_SMASK; + } + if (reg) { + /* report the error, but do not do anything */ + dd_dev_err(dd, "8051 error: %s\n", + dc8051_err_string(buf, sizeof(buf), reg)); + } + + if (queue_link_down) { + /* if the link is already going down or disabled, do not + * queue another */ + if ((ppd->host_link_state + & (HLS_GOING_OFFLINE|HLS_LINK_COOLDOWN)) + || ppd->link_enabled == 0) { + dd_dev_info(dd, "%s: not queuing link down\n", + __func__); + } else { + queue_work(ppd->hfi1_wq, &ppd->link_down_work); + } + } +} + +static const char * const fm_config_txt[] = { +[0] = + "BadHeadDist: Distance violation between two head flits", +[1] = + "BadTailDist: Distance violation between two tail flits", +[2] = + "BadCtrlDist: Distance violation between two credit control flits", +[3] = + "BadCrdAck: Credits return for unsupported VL", +[4] = + "UnsupportedVLMarker: Received VL Marker", +[5] = + "BadPreempt: Exceeded the preemption nesting level", +[6] = + "BadControlFlit: Received unsupported control flit", +/* no 7 */ +[8] = + "UnsupportedVLMarker: Received VL Marker for unconfigured or disabled VL", +}; + +static const char * const port_rcv_txt[] = { +[1] = + "BadPktLen: Illegal PktLen", +[2] = + "PktLenTooLong: Packet longer than PktLen", +[3] = + "PktLenTooShort: Packet shorter than PktLen", +[4] = + "BadSLID: Illegal SLID (0, using multicast as SLID, does not include security validation of SLID)", +[5] = + "BadDLID: Illegal DLID (0, doesn't match HFI)", +[6] = + "BadL2: Illegal L2 opcode", +[7] = + "BadSC: Unsupported SC", +[9] = + "BadRC: Illegal RC", +[11] = + "PreemptError: Preempting with same VL", +[12] = + "PreemptVL15: Preempting a VL15 packet", +}; + +#define OPA_LDR_FMCONFIG_OFFSET 16 +#define OPA_LDR_PORTRCV_OFFSET 0 +static void handle_dcc_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + u64 info, hdr0, hdr1; + const char *extra; + char buf[96]; + struct hfi1_pportdata *ppd = dd->pport; + u8 lcl_reason = 0; + int do_bounce = 0; + + if (reg & DCC_ERR_FLG_UNCORRECTABLE_ERR_SMASK) { + if (!(dd->err_info_uncorrectable & OPA_EI_STATUS_SMASK)) { + info = read_csr(dd, DCC_ERR_INFO_UNCORRECTABLE); + dd->err_info_uncorrectable = info & OPA_EI_CODE_SMASK; + /* set status bit */ + dd->err_info_uncorrectable |= OPA_EI_STATUS_SMASK; + } + reg &= ~DCC_ERR_FLG_UNCORRECTABLE_ERR_SMASK; + } + + if (reg & DCC_ERR_FLG_LINK_ERR_SMASK) { + struct hfi1_pportdata *ppd = dd->pport; + /* this counter saturates at (2^32) - 1 */ + if (ppd->link_downed < (u32)UINT_MAX) + ppd->link_downed++; + reg &= ~DCC_ERR_FLG_LINK_ERR_SMASK; + } + + if (reg & DCC_ERR_FLG_FMCONFIG_ERR_SMASK) { + u8 reason_valid = 1; + + info = read_csr(dd, DCC_ERR_INFO_FMCONFIG); + if (!(dd->err_info_fmconfig & OPA_EI_STATUS_SMASK)) { + dd->err_info_fmconfig = info & OPA_EI_CODE_SMASK; + /* set status bit */ + dd->err_info_fmconfig |= OPA_EI_STATUS_SMASK; + } + switch (info) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + extra = fm_config_txt[info]; + break; + case 8: + extra = fm_config_txt[info]; + if (ppd->port_error_action & + OPA_PI_MASK_FM_CFG_UNSUPPORTED_VL_MARKER) { + do_bounce = 1; + /* + * lcl_reason cannot be derived from info + * for this error + */ + lcl_reason = + OPA_LINKDOWN_REASON_UNSUPPORTED_VL_MARKER; + } + break; + default: + reason_valid = 0; + snprintf(buf, sizeof(buf), "reserved%lld", info); + extra = buf; + break; + } + + if (reason_valid && !do_bounce) { + do_bounce = ppd->port_error_action & + (1 << (OPA_LDR_FMCONFIG_OFFSET + info)); + lcl_reason = info + OPA_LINKDOWN_REASON_BAD_HEAD_DIST; + } + + /* just report this */ + dd_dev_info(dd, "DCC Error: fmconfig error: %s\n", extra); + reg &= ~DCC_ERR_FLG_FMCONFIG_ERR_SMASK; + } + + if (reg & DCC_ERR_FLG_RCVPORT_ERR_SMASK) { + u8 reason_valid = 1; + + info = read_csr(dd, DCC_ERR_INFO_PORTRCV); + hdr0 = read_csr(dd, DCC_ERR_INFO_PORTRCV_HDR0); + hdr1 = read_csr(dd, DCC_ERR_INFO_PORTRCV_HDR1); + if (!(dd->err_info_rcvport.status_and_code & + OPA_EI_STATUS_SMASK)) { + dd->err_info_rcvport.status_and_code = + info & OPA_EI_CODE_SMASK; + /* set status bit */ + dd->err_info_rcvport.status_and_code |= + OPA_EI_STATUS_SMASK; + /* save first 2 flits in the packet that caused + * the error */ + dd->err_info_rcvport.packet_flit1 = hdr0; + dd->err_info_rcvport.packet_flit2 = hdr1; + } + switch (info) { + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case 9: + case 11: + case 12: + extra = port_rcv_txt[info]; + break; + default: + reason_valid = 0; + snprintf(buf, sizeof(buf), "reserved%lld", info); + extra = buf; + break; + } + + if (reason_valid && !do_bounce) { + do_bounce = ppd->port_error_action & + (1 << (OPA_LDR_PORTRCV_OFFSET + info)); + lcl_reason = info + OPA_LINKDOWN_REASON_RCV_ERROR_0; + } + + /* just report this */ + dd_dev_info(dd, "DCC Error: PortRcv error: %s\n", extra); + dd_dev_info(dd, " hdr0 0x%llx, hdr1 0x%llx\n", + hdr0, hdr1); + + reg &= ~DCC_ERR_FLG_RCVPORT_ERR_SMASK; + } + + if (reg & DCC_ERR_FLG_EN_CSR_ACCESS_BLOCKED_UC_SMASK) { + /* informative only */ + dd_dev_info(dd, "8051 access to LCB blocked\n"); + reg &= ~DCC_ERR_FLG_EN_CSR_ACCESS_BLOCKED_UC_SMASK; + } + if (reg & DCC_ERR_FLG_EN_CSR_ACCESS_BLOCKED_HOST_SMASK) { + /* informative only */ + dd_dev_info(dd, "host access to LCB blocked\n"); + reg &= ~DCC_ERR_FLG_EN_CSR_ACCESS_BLOCKED_HOST_SMASK; + } + + /* report any remaining errors */ + if (reg) + dd_dev_info(dd, "DCC Error: %s\n", + dcc_err_string(buf, sizeof(buf), reg)); + + if (lcl_reason == 0) + lcl_reason = OPA_LINKDOWN_REASON_UNKNOWN; + + if (do_bounce) { + dd_dev_info(dd, "%s: PortErrorAction bounce\n", __func__); + set_link_down_reason(ppd, lcl_reason, 0, lcl_reason); + queue_work(ppd->hfi1_wq, &ppd->link_bounce_work); + } +} + +static void handle_lcb_err(struct hfi1_devdata *dd, u32 unused, u64 reg) +{ + char buf[96]; + + dd_dev_info(dd, "LCB Error: %s\n", + lcb_err_string(buf, sizeof(buf), reg)); +} + +/* + * CCE block DC interrupt. Source is < 8. + */ +static void is_dc_int(struct hfi1_devdata *dd, unsigned int source) +{ + const struct err_reg_info *eri = &dc_errs[source]; + + if (eri->handler) { + interrupt_clear_down(dd, 0, eri); + } else if (source == 3 /* dc_lbm_int */) { + /* + * This indicates that a parity error has occurred on the + * address/control lines presented to the LBM. The error + * is a single pulse, there is no associated error flag, + * and it is non-maskable. This is because if a parity + * error occurs on the request the request is dropped. + * This should never occur, but it is nice to know if it + * ever does. + */ + dd_dev_err(dd, "Parity error in DC LBM block\n"); + } else { + dd_dev_err(dd, "Invalid DC interrupt %u\n", source); + } +} + +/* + * TX block send credit interrupt. Source is < 160. + */ +static void is_send_credit_int(struct hfi1_devdata *dd, unsigned int source) +{ + sc_group_release_update(dd, source); +} + +/* + * TX block SDMA interrupt. Source is < 48. + * + * SDMA interrupts are grouped by type: + * + * 0 - N-1 = SDma + * N - 2N-1 = SDmaProgress + * 2N - 3N-1 = SDmaIdle + */ +static void is_sdma_eng_int(struct hfi1_devdata *dd, unsigned int source) +{ + /* what interrupt */ + unsigned int what = source / TXE_NUM_SDMA_ENGINES; + /* which engine */ + unsigned int which = source % TXE_NUM_SDMA_ENGINES; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(dd, "CONFIG SDMA(%u) %s:%d %s()\n", which, + slashstrip(__FILE__), __LINE__, __func__); + sdma_dumpstate(&dd->per_sdma[which]); +#endif + + if (likely(what < 3 && which < dd->num_sdma)) { + sdma_engine_interrupt(&dd->per_sdma[which], 1ull << source); + } else { + /* should not happen */ + dd_dev_err(dd, "Invalid SDMA interrupt 0x%x\n", source); + } +} + +/* + * RX block receive available interrupt. Source is < 160. + */ +static void is_rcv_avail_int(struct hfi1_devdata *dd, unsigned int source) +{ + struct hfi1_ctxtdata *rcd; + char *err_detail; + + if (likely(source < dd->num_rcv_contexts)) { + rcd = dd->rcd[source]; + if (rcd) { + if (source < dd->first_user_ctxt) + rcd->do_interrupt(rcd); + else + handle_user_interrupt(rcd); + return; /* OK */ + } + /* received an interrupt, but no rcd */ + err_detail = "dataless"; + } else { + /* received an interrupt, but are not using that context */ + err_detail = "out of range"; + } + dd_dev_err(dd, "unexpected %s receive available context interrupt %u\n", + err_detail, source); +} + +/* + * RX block receive urgent interrupt. Source is < 160. + */ +static void is_rcv_urgent_int(struct hfi1_devdata *dd, unsigned int source) +{ + struct hfi1_ctxtdata *rcd; + char *err_detail; + + if (likely(source < dd->num_rcv_contexts)) { + rcd = dd->rcd[source]; + if (rcd) { + /* only pay attention to user urgent interrupts */ + if (source >= dd->first_user_ctxt) + handle_user_interrupt(rcd); + return; /* OK */ + } + /* received an interrupt, but no rcd */ + err_detail = "dataless"; + } else { + /* received an interrupt, but are not using that context */ + err_detail = "out of range"; + } + dd_dev_err(dd, "unexpected %s receive urgent context interrupt %u\n", + err_detail, source); +} + +/* + * Reserved range interrupt. Should not be called in normal operation. + */ +static void is_reserved_int(struct hfi1_devdata *dd, unsigned int source) +{ + char name[64]; + + dd_dev_err(dd, "unexpected %s interrupt\n", + is_reserved_name(name, sizeof(name), source)); +} + +static const struct is_table is_table[] = { +/* start end + name func interrupt func */ +{ IS_GENERAL_ERR_START, IS_GENERAL_ERR_END, + is_misc_err_name, is_misc_err_int }, +{ IS_SDMAENG_ERR_START, IS_SDMAENG_ERR_END, + is_sdma_eng_err_name, is_sdma_eng_err_int }, +{ IS_SENDCTXT_ERR_START, IS_SENDCTXT_ERR_END, + is_sendctxt_err_name, is_sendctxt_err_int }, +{ IS_SDMA_START, IS_SDMA_END, + is_sdma_eng_name, is_sdma_eng_int }, +{ IS_VARIOUS_START, IS_VARIOUS_END, + is_various_name, is_various_int }, +{ IS_DC_START, IS_DC_END, + is_dc_name, is_dc_int }, +{ IS_RCVAVAIL_START, IS_RCVAVAIL_END, + is_rcv_avail_name, is_rcv_avail_int }, +{ IS_RCVURGENT_START, IS_RCVURGENT_END, + is_rcv_urgent_name, is_rcv_urgent_int }, +{ IS_SENDCREDIT_START, IS_SENDCREDIT_END, + is_send_credit_name, is_send_credit_int}, +{ IS_RESERVED_START, IS_RESERVED_END, + is_reserved_name, is_reserved_int}, +}; + +/* + * Interrupt source interrupt - called when the given source has an interrupt. + * Source is a bit index into an array of 64-bit integers. + */ +static void is_interrupt(struct hfi1_devdata *dd, unsigned int source) +{ + const struct is_table *entry; + + /* avoids a double compare by walking the table in-order */ + for (entry = &is_table[0]; entry->is_name; entry++) { + if (source < entry->end) { + trace_hfi1_interrupt(dd, entry, source); + entry->is_int(dd, source - entry->start); + return; + } + } + /* fell off the end */ + dd_dev_err(dd, "invalid interrupt source %u\n", source); +} + +/* + * General interrupt handler. This is able to correctly handle + * all interrupts in case INTx is used. + */ +static irqreturn_t general_interrupt(int irq, void *data) +{ + struct hfi1_devdata *dd = data; + u64 regs[CCE_NUM_INT_CSRS]; + u32 bit; + int i; + + this_cpu_inc(*dd->int_counter); + + /* phase 1: scan and clear all handled interrupts */ + for (i = 0; i < CCE_NUM_INT_CSRS; i++) { + if (dd->gi_mask[i] == 0) { + regs[i] = 0; /* used later */ + continue; + } + regs[i] = read_csr(dd, CCE_INT_STATUS + (8 * i)) & + dd->gi_mask[i]; + /* only clear if anything is set */ + if (regs[i]) + write_csr(dd, CCE_INT_CLEAR + (8 * i), regs[i]); + } + + /* phase 2: call the appropriate handler */ + for_each_set_bit(bit, (unsigned long *)®s[0], + CCE_NUM_INT_CSRS*64) { + is_interrupt(dd, bit); + } + + return IRQ_HANDLED; +} + +static irqreturn_t sdma_interrupt(int irq, void *data) +{ + struct sdma_engine *sde = data; + struct hfi1_devdata *dd = sde->dd; + u64 status; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(dd, "CONFIG SDMA(%u) %s:%d %s()\n", sde->this_idx, + slashstrip(__FILE__), __LINE__, __func__); + sdma_dumpstate(sde); +#endif + + this_cpu_inc(*dd->int_counter); + + /* This read_csr is really bad in the hot path */ + status = read_csr(dd, + CCE_INT_STATUS + (8*(IS_SDMA_START/64))) + & sde->imask; + if (likely(status)) { + /* clear the interrupt(s) */ + write_csr(dd, + CCE_INT_CLEAR + (8*(IS_SDMA_START/64)), + status); + + /* handle the interrupt(s) */ + sdma_engine_interrupt(sde, status); + } else + dd_dev_err(dd, "SDMA engine %u interrupt, but no status bits set\n", + sde->this_idx); + + return IRQ_HANDLED; +} + +/* + * NOTE: this routine expects to be on its own MSI-X interrupt. If + * multiple receive contexts share the same MSI-X interrupt, then this + * routine must check for who received it. + */ +static irqreturn_t receive_context_interrupt(int irq, void *data) +{ + struct hfi1_ctxtdata *rcd = data; + struct hfi1_devdata *dd = rcd->dd; + + trace_hfi1_receive_interrupt(dd, rcd->ctxt); + this_cpu_inc(*dd->int_counter); + + /* clear the interrupt */ + write_csr(rcd->dd, CCE_INT_CLEAR + (8*rcd->ireg), rcd->imask); + + /* handle the interrupt */ + rcd->do_interrupt(rcd); + + return IRQ_HANDLED; +} + +/* ========================================================================= */ + +u32 read_physical_state(struct hfi1_devdata *dd) +{ + u64 reg; + + reg = read_csr(dd, DC_DC8051_STS_CUR_STATE); + return (reg >> DC_DC8051_STS_CUR_STATE_PORT_SHIFT) + & DC_DC8051_STS_CUR_STATE_PORT_MASK; +} + +static u32 read_logical_state(struct hfi1_devdata *dd) +{ + u64 reg; + + reg = read_csr(dd, DCC_CFG_PORT_CONFIG); + return (reg >> DCC_CFG_PORT_CONFIG_LINK_STATE_SHIFT) + & DCC_CFG_PORT_CONFIG_LINK_STATE_MASK; +} + +static void set_logical_state(struct hfi1_devdata *dd, u32 chip_lstate) +{ + u64 reg; + + reg = read_csr(dd, DCC_CFG_PORT_CONFIG); + /* clear current state, set new state */ + reg &= ~DCC_CFG_PORT_CONFIG_LINK_STATE_SMASK; + reg |= (u64)chip_lstate << DCC_CFG_PORT_CONFIG_LINK_STATE_SHIFT; + write_csr(dd, DCC_CFG_PORT_CONFIG, reg); +} + +/* + * Use the 8051 to read a LCB CSR. + */ +static int read_lcb_via_8051(struct hfi1_devdata *dd, u32 addr, u64 *data) +{ + u32 regno; + int ret; + + if (dd->icode == ICODE_FUNCTIONAL_SIMULATOR) { + if (acquire_lcb_access(dd, 0) == 0) { + *data = read_csr(dd, addr); + release_lcb_access(dd, 0); + return 0; + } + return -EBUSY; + } + + /* register is an index of LCB registers: (offset - base) / 8 */ + regno = (addr - DC_LCB_CFG_RUN) >> 3; + ret = do_8051_command(dd, HCMD_READ_LCB_CSR, regno, data); + if (ret != HCMD_SUCCESS) + return -EBUSY; + return 0; +} + +/* + * Read an LCB CSR. Access may not be in host control, so check. + * Return 0 on success, -EBUSY on failure. + */ +int read_lcb_csr(struct hfi1_devdata *dd, u32 addr, u64 *data) +{ + struct hfi1_pportdata *ppd = dd->pport; + + /* if up, go through the 8051 for the value */ + if (ppd->host_link_state & HLS_UP) + return read_lcb_via_8051(dd, addr, data); + /* if going up or down, no access */ + if (ppd->host_link_state & (HLS_GOING_UP | HLS_GOING_OFFLINE)) + return -EBUSY; + /* otherwise, host has access */ + *data = read_csr(dd, addr); + return 0; +} + +/* + * Use the 8051 to write a LCB CSR. + */ +static int write_lcb_via_8051(struct hfi1_devdata *dd, u32 addr, u64 data) +{ + + if (acquire_lcb_access(dd, 0) == 0) { + write_csr(dd, addr, data); + release_lcb_access(dd, 0); + return 0; + } + return -EBUSY; +} + +/* + * Write an LCB CSR. Access may not be in host control, so check. + * Return 0 on success, -EBUSY on failure. + */ +int write_lcb_csr(struct hfi1_devdata *dd, u32 addr, u64 data) +{ + struct hfi1_pportdata *ppd = dd->pport; + + /* if up, go through the 8051 for the value */ + if (ppd->host_link_state & HLS_UP) + return write_lcb_via_8051(dd, addr, data); + /* if going up or down, no access */ + if (ppd->host_link_state & (HLS_GOING_UP | HLS_GOING_OFFLINE)) + return -EBUSY; + /* otherwise, host has access */ + write_csr(dd, addr, data); + return 0; +} + +/* + * Returns: + * < 0 = Linux error, not able to get access + * > 0 = 8051 command RETURN_CODE + */ +static int do_8051_command( + struct hfi1_devdata *dd, + u32 type, + u64 in_data, + u64 *out_data) +{ + u64 reg, completed; + int return_code; + unsigned long flags; + unsigned long timeout; + + hfi1_cdbg(DC8051, "type %d, data 0x%012llx", type, in_data); + + /* + * Alternative to holding the lock for a long time: + * - keep busy wait - have other users bounce off + */ + spin_lock_irqsave(&dd->dc8051_lock, flags); + + /* We can't send any commands to the 8051 if it's in reset */ + if (dd->dc_shutdown) { + return_code = -ENODEV; + goto fail; + } + + /* + * If an 8051 host command timed out previously, then the 8051 is + * stuck. + * + * On first timeout, attempt to reset and restart the entire DC + * block (including 8051). (Is this too big of a hammer?) + * + * If the 8051 times out a second time, the reset did not bring it + * back to healthy life. In that case, fail any subsequent commands. + */ + if (dd->dc8051_timed_out) { + if (dd->dc8051_timed_out > 1) { + dd_dev_err(dd, + "Previous 8051 host command timed out, skipping command %u\n", + type); + return_code = -ENXIO; + goto fail; + } + spin_unlock_irqrestore(&dd->dc8051_lock, flags); + dc_shutdown(dd); + dc_start(dd); + spin_lock_irqsave(&dd->dc8051_lock, flags); + } + + /* + * If there is no timeout, then the 8051 command interface is + * waiting for a command. + */ + + /* + * Do two writes: the first to stabilize the type and req_data, the + * second to activate. + */ + reg = ((u64)type & DC_DC8051_CFG_HOST_CMD_0_REQ_TYPE_MASK) + << DC_DC8051_CFG_HOST_CMD_0_REQ_TYPE_SHIFT + | (in_data & DC_DC8051_CFG_HOST_CMD_0_REQ_DATA_MASK) + << DC_DC8051_CFG_HOST_CMD_0_REQ_DATA_SHIFT; + write_csr(dd, DC_DC8051_CFG_HOST_CMD_0, reg); + reg |= DC_DC8051_CFG_HOST_CMD_0_REQ_NEW_SMASK; + write_csr(dd, DC_DC8051_CFG_HOST_CMD_0, reg); + + /* wait for completion, alternate: interrupt */ + timeout = jiffies + msecs_to_jiffies(DC8051_COMMAND_TIMEOUT); + while (1) { + reg = read_csr(dd, DC_DC8051_CFG_HOST_CMD_1); + completed = reg & DC_DC8051_CFG_HOST_CMD_1_COMPLETED_SMASK; + if (completed) + break; + if (time_after(jiffies, timeout)) { + dd->dc8051_timed_out++; + dd_dev_err(dd, "8051 host command %u timeout\n", type); + if (out_data) + *out_data = 0; + return_code = -ETIMEDOUT; + goto fail; + } + udelay(2); + } + + if (out_data) { + *out_data = (reg >> DC_DC8051_CFG_HOST_CMD_1_RSP_DATA_SHIFT) + & DC_DC8051_CFG_HOST_CMD_1_RSP_DATA_MASK; + if (type == HCMD_READ_LCB_CSR) { + /* top 16 bits are in a different register */ + *out_data |= (read_csr(dd, DC_DC8051_CFG_EXT_DEV_1) + & DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_SMASK) + << (48 + - DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_SHIFT); + } + } + return_code = (reg >> DC_DC8051_CFG_HOST_CMD_1_RETURN_CODE_SHIFT) + & DC_DC8051_CFG_HOST_CMD_1_RETURN_CODE_MASK; + dd->dc8051_timed_out = 0; + /* + * Clear command for next user. + */ + write_csr(dd, DC_DC8051_CFG_HOST_CMD_0, 0); + +fail: + spin_unlock_irqrestore(&dd->dc8051_lock, flags); + + return return_code; +} + +static int set_physical_link_state(struct hfi1_devdata *dd, u64 state) +{ + return do_8051_command(dd, HCMD_CHANGE_PHY_STATE, state, NULL); +} + +static int load_8051_config(struct hfi1_devdata *dd, u8 field_id, + u8 lane_id, u32 config_data) +{ + u64 data; + int ret; + + data = (u64)field_id << LOAD_DATA_FIELD_ID_SHIFT + | (u64)lane_id << LOAD_DATA_LANE_ID_SHIFT + | (u64)config_data << LOAD_DATA_DATA_SHIFT; + ret = do_8051_command(dd, HCMD_LOAD_CONFIG_DATA, data, NULL); + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, + "load 8051 config: field id %d, lane %d, err %d\n", + (int)field_id, (int)lane_id, ret); + } + return ret; +} + +/* + * Read the 8051 firmware "registers". Use the RAM directly. Always + * set the result, even on error. + * Return 0 on success, -errno on failure + */ +static int read_8051_config(struct hfi1_devdata *dd, u8 field_id, u8 lane_id, + u32 *result) +{ + u64 big_data; + u32 addr; + int ret; + + /* address start depends on the lane_id */ + if (lane_id < 4) + addr = (4 * NUM_GENERAL_FIELDS) + + (lane_id * 4 * NUM_LANE_FIELDS); + else + addr = 0; + addr += field_id * 4; + + /* read is in 8-byte chunks, hardware will truncate the address down */ + ret = read_8051_data(dd, addr, 8, &big_data); + + if (ret == 0) { + /* extract the 4 bytes we want */ + if (addr & 0x4) + *result = (u32)(big_data >> 32); + else + *result = (u32)big_data; + } else { + *result = 0; + dd_dev_err(dd, "%s: direct read failed, lane %d, field %d!\n", + __func__, lane_id, field_id); + } + + return ret; +} + +static int write_vc_local_phy(struct hfi1_devdata *dd, u8 power_management, + u8 continuous) +{ + u32 frame; + + frame = continuous << CONTINIOUS_REMOTE_UPDATE_SUPPORT_SHIFT + | power_management << POWER_MANAGEMENT_SHIFT; + return load_8051_config(dd, VERIFY_CAP_LOCAL_PHY, + GENERAL_CONFIG, frame); +} + +static int write_vc_local_fabric(struct hfi1_devdata *dd, u8 vau, u8 z, u8 vcu, + u16 vl15buf, u8 crc_sizes) +{ + u32 frame; + + frame = (u32)vau << VAU_SHIFT + | (u32)z << Z_SHIFT + | (u32)vcu << VCU_SHIFT + | (u32)vl15buf << VL15BUF_SHIFT + | (u32)crc_sizes << CRC_SIZES_SHIFT; + return load_8051_config(dd, VERIFY_CAP_LOCAL_FABRIC, + GENERAL_CONFIG, frame); +} + +static void read_vc_local_link_width(struct hfi1_devdata *dd, u8 *misc_bits, + u8 *flag_bits, u16 *link_widths) +{ + u32 frame; + + read_8051_config(dd, VERIFY_CAP_LOCAL_LINK_WIDTH, GENERAL_CONFIG, + &frame); + *misc_bits = (frame >> MISC_CONFIG_BITS_SHIFT) & MISC_CONFIG_BITS_MASK; + *flag_bits = (frame >> LOCAL_FLAG_BITS_SHIFT) & LOCAL_FLAG_BITS_MASK; + *link_widths = (frame >> LINK_WIDTH_SHIFT) & LINK_WIDTH_MASK; +} + +static int write_vc_local_link_width(struct hfi1_devdata *dd, + u8 misc_bits, + u8 flag_bits, + u16 link_widths) +{ + u32 frame; + + frame = (u32)misc_bits << MISC_CONFIG_BITS_SHIFT + | (u32)flag_bits << LOCAL_FLAG_BITS_SHIFT + | (u32)link_widths << LINK_WIDTH_SHIFT; + return load_8051_config(dd, VERIFY_CAP_LOCAL_LINK_WIDTH, GENERAL_CONFIG, + frame); +} + +static int write_local_device_id(struct hfi1_devdata *dd, u16 device_id, + u8 device_rev) +{ + u32 frame; + + frame = ((u32)device_id << LOCAL_DEVICE_ID_SHIFT) + | ((u32)device_rev << LOCAL_DEVICE_REV_SHIFT); + return load_8051_config(dd, LOCAL_DEVICE_ID, GENERAL_CONFIG, frame); +} + +static void read_remote_device_id(struct hfi1_devdata *dd, u16 *device_id, + u8 *device_rev) +{ + u32 frame; + + read_8051_config(dd, REMOTE_DEVICE_ID, GENERAL_CONFIG, &frame); + *device_id = (frame >> REMOTE_DEVICE_ID_SHIFT) & REMOTE_DEVICE_ID_MASK; + *device_rev = (frame >> REMOTE_DEVICE_REV_SHIFT) + & REMOTE_DEVICE_REV_MASK; +} + +void read_misc_status(struct hfi1_devdata *dd, u8 *ver_a, u8 *ver_b) +{ + u32 frame; + + read_8051_config(dd, MISC_STATUS, GENERAL_CONFIG, &frame); + *ver_a = (frame >> STS_FM_VERSION_A_SHIFT) & STS_FM_VERSION_A_MASK; + *ver_b = (frame >> STS_FM_VERSION_B_SHIFT) & STS_FM_VERSION_B_MASK; +} + +static void read_vc_remote_phy(struct hfi1_devdata *dd, u8 *power_management, + u8 *continuous) +{ + u32 frame; + + read_8051_config(dd, VERIFY_CAP_REMOTE_PHY, GENERAL_CONFIG, &frame); + *power_management = (frame >> POWER_MANAGEMENT_SHIFT) + & POWER_MANAGEMENT_MASK; + *continuous = (frame >> CONTINIOUS_REMOTE_UPDATE_SUPPORT_SHIFT) + & CONTINIOUS_REMOTE_UPDATE_SUPPORT_MASK; +} + +static void read_vc_remote_fabric(struct hfi1_devdata *dd, u8 *vau, u8 *z, + u8 *vcu, u16 *vl15buf, u8 *crc_sizes) +{ + u32 frame; + + read_8051_config(dd, VERIFY_CAP_REMOTE_FABRIC, GENERAL_CONFIG, &frame); + *vau = (frame >> VAU_SHIFT) & VAU_MASK; + *z = (frame >> Z_SHIFT) & Z_MASK; + *vcu = (frame >> VCU_SHIFT) & VCU_MASK; + *vl15buf = (frame >> VL15BUF_SHIFT) & VL15BUF_MASK; + *crc_sizes = (frame >> CRC_SIZES_SHIFT) & CRC_SIZES_MASK; +} + +static void read_vc_remote_link_width(struct hfi1_devdata *dd, + u8 *remote_tx_rate, + u16 *link_widths) +{ + u32 frame; + + read_8051_config(dd, VERIFY_CAP_REMOTE_LINK_WIDTH, GENERAL_CONFIG, + &frame); + *remote_tx_rate = (frame >> REMOTE_TX_RATE_SHIFT) + & REMOTE_TX_RATE_MASK; + *link_widths = (frame >> LINK_WIDTH_SHIFT) & LINK_WIDTH_MASK; +} + +static void read_local_lni(struct hfi1_devdata *dd, u8 *enable_lane_rx) +{ + u32 frame; + + read_8051_config(dd, LOCAL_LNI_INFO, GENERAL_CONFIG, &frame); + *enable_lane_rx = (frame >> ENABLE_LANE_RX_SHIFT) & ENABLE_LANE_RX_MASK; +} + +static void read_mgmt_allowed(struct hfi1_devdata *dd, u8 *mgmt_allowed) +{ + u32 frame; + + read_8051_config(dd, REMOTE_LNI_INFO, GENERAL_CONFIG, &frame); + *mgmt_allowed = (frame >> MGMT_ALLOWED_SHIFT) & MGMT_ALLOWED_MASK; +} + +static void read_last_local_state(struct hfi1_devdata *dd, u32 *lls) +{ + read_8051_config(dd, LAST_LOCAL_STATE_COMPLETE, GENERAL_CONFIG, lls); +} + +static void read_last_remote_state(struct hfi1_devdata *dd, u32 *lrs) +{ + read_8051_config(dd, LAST_REMOTE_STATE_COMPLETE, GENERAL_CONFIG, lrs); +} + +void hfi1_read_link_quality(struct hfi1_devdata *dd, u8 *link_quality) +{ + u32 frame; + int ret; + + *link_quality = 0; + if (dd->pport->host_link_state & HLS_UP) { + ret = read_8051_config(dd, LINK_QUALITY_INFO, GENERAL_CONFIG, + &frame); + if (ret == 0) + *link_quality = (frame >> LINK_QUALITY_SHIFT) + & LINK_QUALITY_MASK; + } +} + +static void read_planned_down_reason_code(struct hfi1_devdata *dd, u8 *pdrrc) +{ + u32 frame; + + read_8051_config(dd, LINK_QUALITY_INFO, GENERAL_CONFIG, &frame); + *pdrrc = (frame >> DOWN_REMOTE_REASON_SHIFT) & DOWN_REMOTE_REASON_MASK; +} + +static int read_tx_settings(struct hfi1_devdata *dd, + u8 *enable_lane_tx, + u8 *tx_polarity_inversion, + u8 *rx_polarity_inversion, + u8 *max_rate) +{ + u32 frame; + int ret; + + ret = read_8051_config(dd, TX_SETTINGS, GENERAL_CONFIG, &frame); + *enable_lane_tx = (frame >> ENABLE_LANE_TX_SHIFT) + & ENABLE_LANE_TX_MASK; + *tx_polarity_inversion = (frame >> TX_POLARITY_INVERSION_SHIFT) + & TX_POLARITY_INVERSION_MASK; + *rx_polarity_inversion = (frame >> RX_POLARITY_INVERSION_SHIFT) + & RX_POLARITY_INVERSION_MASK; + *max_rate = (frame >> MAX_RATE_SHIFT) & MAX_RATE_MASK; + return ret; +} + +static int write_tx_settings(struct hfi1_devdata *dd, + u8 enable_lane_tx, + u8 tx_polarity_inversion, + u8 rx_polarity_inversion, + u8 max_rate) +{ + u32 frame; + + /* no need to mask, all variable sizes match field widths */ + frame = enable_lane_tx << ENABLE_LANE_TX_SHIFT + | tx_polarity_inversion << TX_POLARITY_INVERSION_SHIFT + | rx_polarity_inversion << RX_POLARITY_INVERSION_SHIFT + | max_rate << MAX_RATE_SHIFT; + return load_8051_config(dd, TX_SETTINGS, GENERAL_CONFIG, frame); +} + +static void check_fabric_firmware_versions(struct hfi1_devdata *dd) +{ + u32 frame, version, prod_id; + int ret, lane; + + /* 4 lanes */ + for (lane = 0; lane < 4; lane++) { + ret = read_8051_config(dd, SPICO_FW_VERSION, lane, &frame); + if (ret) { + dd_dev_err( + dd, + "Unable to read lane %d firmware details\n", + lane); + continue; + } + version = (frame >> SPICO_ROM_VERSION_SHIFT) + & SPICO_ROM_VERSION_MASK; + prod_id = (frame >> SPICO_ROM_PROD_ID_SHIFT) + & SPICO_ROM_PROD_ID_MASK; + dd_dev_info(dd, + "Lane %d firmware: version 0x%04x, prod_id 0x%04x\n", + lane, version, prod_id); + } +} + +/* + * Read an idle LCB message. + * + * Returns 0 on success, -EINVAL on error + */ +static int read_idle_message(struct hfi1_devdata *dd, u64 type, u64 *data_out) +{ + int ret; + + ret = do_8051_command(dd, HCMD_READ_LCB_IDLE_MSG, + type, data_out); + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, "read idle message: type %d, err %d\n", + (u32)type, ret); + return -EINVAL; + } + dd_dev_info(dd, "%s: read idle message 0x%llx\n", __func__, *data_out); + /* return only the payload as we already know the type */ + *data_out >>= IDLE_PAYLOAD_SHIFT; + return 0; +} + +/* + * Read an idle SMA message. To be done in response to a notification from + * the 8051. + * + * Returns 0 on success, -EINVAL on error + */ +static int read_idle_sma(struct hfi1_devdata *dd, u64 *data) +{ + return read_idle_message(dd, + (u64)IDLE_SMA << IDLE_MSG_TYPE_SHIFT, data); +} + +/* + * Send an idle LCB message. + * + * Returns 0 on success, -EINVAL on error + */ +static int send_idle_message(struct hfi1_devdata *dd, u64 data) +{ + int ret; + + dd_dev_info(dd, "%s: sending idle message 0x%llx\n", __func__, data); + ret = do_8051_command(dd, HCMD_SEND_LCB_IDLE_MSG, data, NULL); + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, "send idle message: data 0x%llx, err %d\n", + data, ret); + return -EINVAL; + } + return 0; +} + +/* + * Send an idle SMA message. + * + * Returns 0 on success, -EINVAL on error + */ +int send_idle_sma(struct hfi1_devdata *dd, u64 message) +{ + u64 data; + + data = ((message & IDLE_PAYLOAD_MASK) << IDLE_PAYLOAD_SHIFT) + | ((u64)IDLE_SMA << IDLE_MSG_TYPE_SHIFT); + return send_idle_message(dd, data); +} + +/* + * Initialize the LCB then do a quick link up. This may or may not be + * in loopback. + * + * return 0 on success, -errno on error + */ +static int do_quick_linkup(struct hfi1_devdata *dd) +{ + u64 reg; + unsigned long timeout; + int ret; + + lcb_shutdown(dd, 0); + + if (loopback) { + /* LCB_CFG_LOOPBACK.VAL = 2 */ + /* LCB_CFG_LANE_WIDTH.VAL = 0 */ + write_csr(dd, DC_LCB_CFG_LOOPBACK, + IB_PACKET_TYPE << DC_LCB_CFG_LOOPBACK_VAL_SHIFT); + write_csr(dd, DC_LCB_CFG_LANE_WIDTH, 0); + } + + /* start the LCBs */ + /* LCB_CFG_TX_FIFOS_RESET.VAL = 0 */ + write_csr(dd, DC_LCB_CFG_TX_FIFOS_RESET, 0); + + /* simulator only loopback steps */ + if (loopback && dd->icode == ICODE_FUNCTIONAL_SIMULATOR) { + /* LCB_CFG_RUN.EN = 1 */ + write_csr(dd, DC_LCB_CFG_RUN, + 1ull << DC_LCB_CFG_RUN_EN_SHIFT); + + /* watch LCB_STS_LINK_TRANSFER_ACTIVE */ + timeout = jiffies + msecs_to_jiffies(10); + while (1) { + reg = read_csr(dd, + DC_LCB_STS_LINK_TRANSFER_ACTIVE); + if (reg) + break; + if (time_after(jiffies, timeout)) { + dd_dev_err(dd, + "timeout waiting for LINK_TRANSFER_ACTIVE\n"); + return -ETIMEDOUT; + } + udelay(2); + } + + write_csr(dd, DC_LCB_CFG_ALLOW_LINK_UP, + 1ull << DC_LCB_CFG_ALLOW_LINK_UP_VAL_SHIFT); + } + + if (!loopback) { + /* + * When doing quick linkup and not in loopback, both + * sides must be done with LCB set-up before either + * starts the quick linkup. Put a delay here so that + * both sides can be started and have a chance to be + * done with LCB set up before resuming. + */ + dd_dev_err(dd, + "Pausing for peer to be finished with LCB set up\n"); + msleep(5000); + dd_dev_err(dd, + "Continuing with quick linkup\n"); + } + + write_csr(dd, DC_LCB_ERR_EN, 0); /* mask LCB errors */ + set_8051_lcb_access(dd); + + /* + * State "quick" LinkUp request sets the physical link state to + * LinkUp without a verify capability sequence. + * This state is in simulator v37 and later. + */ + ret = set_physical_link_state(dd, PLS_QUICK_LINKUP); + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, + "%s: set physical link state to quick LinkUp failed with return %d\n", + __func__, ret); + + set_host_lcb_access(dd); + write_csr(dd, DC_LCB_ERR_EN, ~0ull); /* watch LCB errors */ + + if (ret >= 0) + ret = -EINVAL; + return ret; + } + + return 0; /* success */ +} + +/* + * Set the SerDes to internal loopback mode. + * Returns 0 on success, -errno on error. + */ +static int set_serdes_loopback_mode(struct hfi1_devdata *dd) +{ + int ret; + + ret = set_physical_link_state(dd, PLS_INTERNAL_SERDES_LOOPBACK); + if (ret == HCMD_SUCCESS) + return 0; + dd_dev_err(dd, + "Set physical link state to SerDes Loopback failed with return %d\n", + ret); + if (ret >= 0) + ret = -EINVAL; + return ret; +} + +/* + * Do all special steps to set up loopback. + */ +static int init_loopback(struct hfi1_devdata *dd) +{ + dd_dev_info(dd, "Entering loopback mode\n"); + + /* all loopbacks should disable self GUID check */ + write_csr(dd, DC_DC8051_CFG_MODE, + (read_csr(dd, DC_DC8051_CFG_MODE) | DISABLE_SELF_GUID_CHECK)); + + /* + * The simulator has only one loopback option - LCB. Switch + * to that option, which includes quick link up. + * + * Accept all valid loopback values. + */ + if ((dd->icode == ICODE_FUNCTIONAL_SIMULATOR) + && (loopback == LOOPBACK_SERDES + || loopback == LOOPBACK_LCB + || loopback == LOOPBACK_CABLE)) { + loopback = LOOPBACK_LCB; + quick_linkup = 1; + return 0; + } + + /* handle serdes loopback */ + if (loopback == LOOPBACK_SERDES) { + /* internal serdes loopack needs quick linkup on RTL */ + if (dd->icode == ICODE_RTL_SILICON) + quick_linkup = 1; + return set_serdes_loopback_mode(dd); + } + + /* LCB loopback - handled at poll time */ + if (loopback == LOOPBACK_LCB) { + quick_linkup = 1; /* LCB is always quick linkup */ + + /* not supported in emulation due to emulation RTL changes */ + if (dd->icode == ICODE_FPGA_EMULATION) { + dd_dev_err(dd, + "LCB loopback not supported in emulation\n"); + return -EINVAL; + } + return 0; + } + + /* external cable loopback requires no extra steps */ + if (loopback == LOOPBACK_CABLE) + return 0; + + dd_dev_err(dd, "Invalid loopback mode %d\n", loopback); + return -EINVAL; +} + +/* + * Translate from the OPA_LINK_WIDTH handed to us by the FM to bits + * used in the Verify Capability link width attribute. + */ +static u16 opa_to_vc_link_widths(u16 opa_widths) +{ + int i; + u16 result = 0; + + static const struct link_bits { + u16 from; + u16 to; + } opa_link_xlate[] = { + { OPA_LINK_WIDTH_1X, 1 << (1-1) }, + { OPA_LINK_WIDTH_2X, 1 << (2-1) }, + { OPA_LINK_WIDTH_3X, 1 << (3-1) }, + { OPA_LINK_WIDTH_4X, 1 << (4-1) }, + }; + + for (i = 0; i < ARRAY_SIZE(opa_link_xlate); i++) { + if (opa_widths & opa_link_xlate[i].from) + result |= opa_link_xlate[i].to; + } + return result; +} + +/* + * Set link attributes before moving to polling. + */ +static int set_local_link_attributes(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u8 enable_lane_tx; + u8 tx_polarity_inversion; + u8 rx_polarity_inversion; + int ret; + + /* reset our fabric serdes to clear any lingering problems */ + fabric_serdes_reset(dd); + + /* set the local tx rate - need to read-modify-write */ + ret = read_tx_settings(dd, &enable_lane_tx, &tx_polarity_inversion, + &rx_polarity_inversion, &ppd->local_tx_rate); + if (ret) + goto set_local_link_attributes_fail; + + if (dd->dc8051_ver < dc8051_ver(0, 20)) { + /* set the tx rate to the fastest enabled */ + if (ppd->link_speed_enabled & OPA_LINK_SPEED_25G) + ppd->local_tx_rate = 1; + else + ppd->local_tx_rate = 0; + } else { + /* set the tx rate to all enabled */ + ppd->local_tx_rate = 0; + if (ppd->link_speed_enabled & OPA_LINK_SPEED_25G) + ppd->local_tx_rate |= 2; + if (ppd->link_speed_enabled & OPA_LINK_SPEED_12_5G) + ppd->local_tx_rate |= 1; + } + ret = write_tx_settings(dd, enable_lane_tx, tx_polarity_inversion, + rx_polarity_inversion, ppd->local_tx_rate); + if (ret != HCMD_SUCCESS) + goto set_local_link_attributes_fail; + + /* + * DC supports continuous updates. + */ + ret = write_vc_local_phy(dd, 0 /* no power management */, + 1 /* continuous updates */); + if (ret != HCMD_SUCCESS) + goto set_local_link_attributes_fail; + + /* z=1 in the next call: AU of 0 is not supported by the hardware */ + ret = write_vc_local_fabric(dd, dd->vau, 1, dd->vcu, dd->vl15_init, + ppd->port_crc_mode_enabled); + if (ret != HCMD_SUCCESS) + goto set_local_link_attributes_fail; + + ret = write_vc_local_link_width(dd, 0, 0, + opa_to_vc_link_widths(ppd->link_width_enabled)); + if (ret != HCMD_SUCCESS) + goto set_local_link_attributes_fail; + + /* let peer know who we are */ + ret = write_local_device_id(dd, dd->pcidev->device, dd->minrev); + if (ret == HCMD_SUCCESS) + return 0; + +set_local_link_attributes_fail: + dd_dev_err(dd, + "Failed to set local link attributes, return 0x%x\n", + ret); + return ret; +} + +/* + * Call this to start the link. Schedule a retry if the cable is not + * present or if unable to start polling. Do not do anything if the + * link is disabled. Returns 0 if link is disabled or moved to polling + */ +int start_link(struct hfi1_pportdata *ppd) +{ + if (!ppd->link_enabled) { + dd_dev_info(ppd->dd, + "%s: stopping link start because link is disabled\n", + __func__); + return 0; + } + if (!ppd->driver_link_ready) { + dd_dev_info(ppd->dd, + "%s: stopping link start because driver is not ready\n", + __func__); + return 0; + } + + if (qsfp_mod_present(ppd) || loopback == LOOPBACK_SERDES || + loopback == LOOPBACK_LCB || + ppd->dd->icode == ICODE_FUNCTIONAL_SIMULATOR) + return set_link_state(ppd, HLS_DN_POLL); + + dd_dev_info(ppd->dd, + "%s: stopping link start because no cable is present\n", + __func__); + return -EAGAIN; +} + +static void reset_qsfp(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u64 mask, qsfp_mask; + + mask = (u64)QSFP_HFI0_RESET_N; + qsfp_mask = read_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_OE : ASIC_QSFP1_OE); + qsfp_mask |= mask; + write_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_OE : ASIC_QSFP1_OE, + qsfp_mask); + + qsfp_mask = read_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_OUT : ASIC_QSFP1_OUT); + qsfp_mask &= ~mask; + write_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_OUT : ASIC_QSFP1_OUT, + qsfp_mask); + + udelay(10); + + qsfp_mask |= mask; + write_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_OUT : ASIC_QSFP1_OUT, + qsfp_mask); +} + +static int handle_qsfp_error_conditions(struct hfi1_pportdata *ppd, + u8 *qsfp_interrupt_status) +{ + struct hfi1_devdata *dd = ppd->dd; + + if ((qsfp_interrupt_status[0] & QSFP_HIGH_TEMP_ALARM) || + (qsfp_interrupt_status[0] & QSFP_HIGH_TEMP_WARNING)) + dd_dev_info(dd, + "%s: QSFP cable on fire\n", + __func__); + + if ((qsfp_interrupt_status[0] & QSFP_LOW_TEMP_ALARM) || + (qsfp_interrupt_status[0] & QSFP_LOW_TEMP_WARNING)) + dd_dev_info(dd, + "%s: QSFP cable temperature too low\n", + __func__); + + if ((qsfp_interrupt_status[1] & QSFP_HIGH_VCC_ALARM) || + (qsfp_interrupt_status[1] & QSFP_HIGH_VCC_WARNING)) + dd_dev_info(dd, + "%s: QSFP supply voltage too high\n", + __func__); + + if ((qsfp_interrupt_status[1] & QSFP_LOW_VCC_ALARM) || + (qsfp_interrupt_status[1] & QSFP_LOW_VCC_WARNING)) + dd_dev_info(dd, + "%s: QSFP supply voltage too low\n", + __func__); + + /* Byte 2 is vendor specific */ + + if ((qsfp_interrupt_status[3] & QSFP_HIGH_POWER_ALARM) || + (qsfp_interrupt_status[3] & QSFP_HIGH_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable RX channel 1/2 power too high\n", + __func__); + + if ((qsfp_interrupt_status[3] & QSFP_LOW_POWER_ALARM) || + (qsfp_interrupt_status[3] & QSFP_LOW_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable RX channel 1/2 power too low\n", + __func__); + + if ((qsfp_interrupt_status[4] & QSFP_HIGH_POWER_ALARM) || + (qsfp_interrupt_status[4] & QSFP_HIGH_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable RX channel 3/4 power too high\n", + __func__); + + if ((qsfp_interrupt_status[4] & QSFP_LOW_POWER_ALARM) || + (qsfp_interrupt_status[4] & QSFP_LOW_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable RX channel 3/4 power too low\n", + __func__); + + if ((qsfp_interrupt_status[5] & QSFP_HIGH_BIAS_ALARM) || + (qsfp_interrupt_status[5] & QSFP_HIGH_BIAS_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 1/2 bias too high\n", + __func__); + + if ((qsfp_interrupt_status[5] & QSFP_LOW_BIAS_ALARM) || + (qsfp_interrupt_status[5] & QSFP_LOW_BIAS_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 1/2 bias too low\n", + __func__); + + if ((qsfp_interrupt_status[6] & QSFP_HIGH_BIAS_ALARM) || + (qsfp_interrupt_status[6] & QSFP_HIGH_BIAS_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 3/4 bias too high\n", + __func__); + + if ((qsfp_interrupt_status[6] & QSFP_LOW_BIAS_ALARM) || + (qsfp_interrupt_status[6] & QSFP_LOW_BIAS_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 3/4 bias too low\n", + __func__); + + if ((qsfp_interrupt_status[7] & QSFP_HIGH_POWER_ALARM) || + (qsfp_interrupt_status[7] & QSFP_HIGH_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 1/2 power too high\n", + __func__); + + if ((qsfp_interrupt_status[7] & QSFP_LOW_POWER_ALARM) || + (qsfp_interrupt_status[7] & QSFP_LOW_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 1/2 power too low\n", + __func__); + + if ((qsfp_interrupt_status[8] & QSFP_HIGH_POWER_ALARM) || + (qsfp_interrupt_status[8] & QSFP_HIGH_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 3/4 power too high\n", + __func__); + + if ((qsfp_interrupt_status[8] & QSFP_LOW_POWER_ALARM) || + (qsfp_interrupt_status[8] & QSFP_LOW_POWER_WARNING)) + dd_dev_info(dd, + "%s: Cable TX channel 3/4 power too low\n", + __func__); + + /* Bytes 9-10 and 11-12 are reserved */ + /* Bytes 13-15 are vendor specific */ + + return 0; +} + +static int do_pre_lni_host_behaviors(struct hfi1_pportdata *ppd) +{ + refresh_qsfp_cache(ppd, &ppd->qsfp_info); + + return 0; +} + +static int do_qsfp_intr_fallback(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u8 qsfp_interrupt_status = 0; + + if (qsfp_read(ppd, dd->hfi1_id, 2, &qsfp_interrupt_status, 1) + != 1) { + dd_dev_info(dd, + "%s: Failed to read status of QSFP module\n", + __func__); + return -EIO; + } + + /* We don't care about alarms & warnings with a non-functional INT_N */ + if (!(qsfp_interrupt_status & QSFP_DATA_NOT_READY)) + do_pre_lni_host_behaviors(ppd); + + return 0; +} + +/* This routine will only be scheduled if the QSFP module is present */ +static void qsfp_event(struct work_struct *work) +{ + struct qsfp_data *qd; + struct hfi1_pportdata *ppd; + struct hfi1_devdata *dd; + + qd = container_of(work, struct qsfp_data, qsfp_work); + ppd = qd->ppd; + dd = ppd->dd; + + /* Sanity check */ + if (!qsfp_mod_present(ppd)) + return; + + /* + * Turn DC back on after cables has been + * re-inserted. Up until now, the DC has been in + * reset to save power. + */ + dc_start(dd); + + if (qd->cache_refresh_required) { + msleep(3000); + reset_qsfp(ppd); + + /* Check for QSFP interrupt after t_init (SFF 8679) + * + extra + */ + msleep(3000); + if (!qd->qsfp_interrupt_functional) { + if (do_qsfp_intr_fallback(ppd) < 0) + dd_dev_info(dd, "%s: QSFP fallback failed\n", + __func__); + ppd->driver_link_ready = 1; + start_link(ppd); + } + } + + if (qd->check_interrupt_flags) { + u8 qsfp_interrupt_status[16] = {0,}; + + if (qsfp_read(ppd, dd->hfi1_id, 6, + &qsfp_interrupt_status[0], 16) != 16) { + dd_dev_info(dd, + "%s: Failed to read status of QSFP module\n", + __func__); + } else { + unsigned long flags; + u8 data_status; + + spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); + ppd->qsfp_info.check_interrupt_flags = 0; + spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, + flags); + + if (qsfp_read(ppd, dd->hfi1_id, 2, &data_status, 1) + != 1) { + dd_dev_info(dd, + "%s: Failed to read status of QSFP module\n", + __func__); + } + if (!(data_status & QSFP_DATA_NOT_READY)) { + do_pre_lni_host_behaviors(ppd); + start_link(ppd); + } else + handle_qsfp_error_conditions(ppd, + qsfp_interrupt_status); + } + } +} + +void init_qsfp(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u64 qsfp_mask; + + if (loopback == LOOPBACK_SERDES || loopback == LOOPBACK_LCB || + ppd->dd->icode == ICODE_FUNCTIONAL_SIMULATOR || + !HFI1_CAP_IS_KSET(QSFP_ENABLED)) { + ppd->driver_link_ready = 1; + return; + } + + ppd->qsfp_info.ppd = ppd; + INIT_WORK(&ppd->qsfp_info.qsfp_work, qsfp_event); + + qsfp_mask = (u64)(QSFP_HFI0_INT_N | QSFP_HFI0_MODPRST_N); + /* Clear current status to avoid spurious interrupts */ + write_csr(dd, + dd->hfi1_id ? + ASIC_QSFP2_CLEAR : + ASIC_QSFP1_CLEAR, + qsfp_mask); + + /* Handle active low nature of INT_N and MODPRST_N pins */ + if (qsfp_mod_present(ppd)) + qsfp_mask &= ~(u64)QSFP_HFI0_MODPRST_N; + write_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_INVERT : ASIC_QSFP1_INVERT, + qsfp_mask); + + /* Allow only INT_N and MODPRST_N to trigger QSFP interrupts */ + qsfp_mask |= (u64)QSFP_HFI0_MODPRST_N; + write_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_MASK : ASIC_QSFP1_MASK, + qsfp_mask); + + if (qsfp_mod_present(ppd)) { + msleep(3000); + reset_qsfp(ppd); + + /* Check for QSFP interrupt after t_init (SFF 8679) + * + extra + */ + msleep(3000); + if (!ppd->qsfp_info.qsfp_interrupt_functional) { + if (do_qsfp_intr_fallback(ppd) < 0) + dd_dev_info(dd, + "%s: QSFP fallback failed\n", + __func__); + ppd->driver_link_ready = 1; + } + } +} + +int bringup_serdes(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u64 guid; + int ret; + + if (HFI1_CAP_IS_KSET(EXTENDED_PSN)) + add_rcvctrl(dd, RCV_CTRL_RCV_EXTENDED_PSN_ENABLE_SMASK); + + guid = ppd->guid; + if (!guid) { + if (dd->base_guid) + guid = dd->base_guid + ppd->port - 1; + ppd->guid = guid; + } + + /* the link defaults to enabled */ + ppd->link_enabled = 1; + /* Set linkinit_reason on power up per OPA spec */ + ppd->linkinit_reason = OPA_LINKINIT_REASON_LINKUP; + + if (loopback) { + ret = init_loopback(dd); + if (ret < 0) + return ret; + } + + return start_link(ppd); +} + +void hfi1_quiet_serdes(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + + /* + * Shut down the link and keep it down. First turn off that the + * driver wants to allow the link to be up (driver_link_ready). + * Then make sure the link is not automatically restarted + * (link_enabled). Cancel any pending restart. And finally + * go offline. + */ + ppd->driver_link_ready = 0; + ppd->link_enabled = 0; + + set_link_down_reason(ppd, OPA_LINKDOWN_REASON_SMA_DISABLED, 0, + OPA_LINKDOWN_REASON_SMA_DISABLED); + set_link_state(ppd, HLS_DN_OFFLINE); + + /* disable the port */ + clear_rcvctrl(dd, RCV_CTRL_RCV_PORT_ENABLE_SMASK); +} + +static inline int init_cpu_counters(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd; + int i; + + ppd = (struct hfi1_pportdata *)(dd + 1); + for (i = 0; i < dd->num_pports; i++, ppd++) { + ppd->ibport_data.rc_acks = NULL; + ppd->ibport_data.rc_qacks = NULL; + ppd->ibport_data.rc_acks = alloc_percpu(u64); + ppd->ibport_data.rc_qacks = alloc_percpu(u64); + ppd->ibport_data.rc_delayed_comp = alloc_percpu(u64); + if ((ppd->ibport_data.rc_acks == NULL) || + (ppd->ibport_data.rc_delayed_comp == NULL) || + (ppd->ibport_data.rc_qacks == NULL)) + return -ENOMEM; + } + + return 0; +} + +static const char * const pt_names[] = { + "expected", + "eager", + "invalid" +}; + +static const char *pt_name(u32 type) +{ + return type >= ARRAY_SIZE(pt_names) ? "unknown" : pt_names[type]; +} + +/* + * index is the index into the receive array + */ +void hfi1_put_tid(struct hfi1_devdata *dd, u32 index, + u32 type, unsigned long pa, u16 order) +{ + u64 reg; + void __iomem *base = (dd->rcvarray_wc ? dd->rcvarray_wc : + (dd->kregbase + RCV_ARRAY)); + + if (!(dd->flags & HFI1_PRESENT)) + goto done; + + if (type == PT_INVALID) { + pa = 0; + } else if (type > PT_INVALID) { + dd_dev_err(dd, + "unexpected receive array type %u for index %u, not handled\n", + type, index); + goto done; + } + + hfi1_cdbg(TID, "type %s, index 0x%x, pa 0x%lx, bsize 0x%lx", + pt_name(type), index, pa, (unsigned long)order); + +#define RT_ADDR_SHIFT 12 /* 4KB kernel address boundary */ + reg = RCV_ARRAY_RT_WRITE_ENABLE_SMASK + | (u64)order << RCV_ARRAY_RT_BUF_SIZE_SHIFT + | ((pa >> RT_ADDR_SHIFT) & RCV_ARRAY_RT_ADDR_MASK) + << RCV_ARRAY_RT_ADDR_SHIFT; + writeq(reg, base + (index * 8)); + + if (type == PT_EAGER) + /* + * Eager entries are written one-by-one so we have to push them + * after we write the entry. + */ + flush_wc(); +done: + return; +} + +void hfi1_clear_tids(struct hfi1_ctxtdata *rcd) +{ + struct hfi1_devdata *dd = rcd->dd; + u32 i; + + /* this could be optimized */ + for (i = rcd->eager_base; i < rcd->eager_base + + rcd->egrbufs.alloced; i++) + hfi1_put_tid(dd, i, PT_INVALID, 0, 0); + + for (i = rcd->expected_base; + i < rcd->expected_base + rcd->expected_count; i++) + hfi1_put_tid(dd, i, PT_INVALID, 0, 0); +} + +int hfi1_get_base_kinfo(struct hfi1_ctxtdata *rcd, + struct hfi1_ctxt_info *kinfo) +{ + kinfo->runtime_flags = (HFI1_MISC_GET() << HFI1_CAP_USER_SHIFT) | + HFI1_CAP_UGET(MASK) | HFI1_CAP_KGET(K2U); + return 0; +} + +struct hfi1_message_header *hfi1_get_msgheader( + struct hfi1_devdata *dd, __le32 *rhf_addr) +{ + u32 offset = rhf_hdrq_offset(rhf_to_cpu(rhf_addr)); + + return (struct hfi1_message_header *) + (rhf_addr - dd->rhf_offset + offset); +} + +static const char * const ib_cfg_name_strings[] = { + "HFI1_IB_CFG_LIDLMC", + "HFI1_IB_CFG_LWID_DG_ENB", + "HFI1_IB_CFG_LWID_ENB", + "HFI1_IB_CFG_LWID", + "HFI1_IB_CFG_SPD_ENB", + "HFI1_IB_CFG_SPD", + "HFI1_IB_CFG_RXPOL_ENB", + "HFI1_IB_CFG_LREV_ENB", + "HFI1_IB_CFG_LINKLATENCY", + "HFI1_IB_CFG_HRTBT", + "HFI1_IB_CFG_OP_VLS", + "HFI1_IB_CFG_VL_HIGH_CAP", + "HFI1_IB_CFG_VL_LOW_CAP", + "HFI1_IB_CFG_OVERRUN_THRESH", + "HFI1_IB_CFG_PHYERR_THRESH", + "HFI1_IB_CFG_LINKDEFAULT", + "HFI1_IB_CFG_PKEYS", + "HFI1_IB_CFG_MTU", + "HFI1_IB_CFG_LSTATE", + "HFI1_IB_CFG_VL_HIGH_LIMIT", + "HFI1_IB_CFG_PMA_TICKS", + "HFI1_IB_CFG_PORT" +}; + +static const char *ib_cfg_name(int which) +{ + if (which < 0 || which >= ARRAY_SIZE(ib_cfg_name_strings)) + return "invalid"; + return ib_cfg_name_strings[which]; +} + +int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which) +{ + struct hfi1_devdata *dd = ppd->dd; + int val = 0; + + switch (which) { + case HFI1_IB_CFG_LWID_ENB: /* allowed Link-width */ + val = ppd->link_width_enabled; + break; + case HFI1_IB_CFG_LWID: /* currently active Link-width */ + val = ppd->link_width_active; + break; + case HFI1_IB_CFG_SPD_ENB: /* allowed Link speeds */ + val = ppd->link_speed_enabled; + break; + case HFI1_IB_CFG_SPD: /* current Link speed */ + val = ppd->link_speed_active; + break; + + case HFI1_IB_CFG_RXPOL_ENB: /* Auto-RX-polarity enable */ + case HFI1_IB_CFG_LREV_ENB: /* Auto-Lane-reversal enable */ + case HFI1_IB_CFG_LINKLATENCY: + goto unimplemented; + + case HFI1_IB_CFG_OP_VLS: + val = ppd->vls_operational; + break; + case HFI1_IB_CFG_VL_HIGH_CAP: /* VL arb high priority table size */ + val = VL_ARB_HIGH_PRIO_TABLE_SIZE; + break; + case HFI1_IB_CFG_VL_LOW_CAP: /* VL arb low priority table size */ + val = VL_ARB_LOW_PRIO_TABLE_SIZE; + break; + case HFI1_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */ + val = ppd->overrun_threshold; + break; + case HFI1_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */ + val = ppd->phy_error_threshold; + break; + case HFI1_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */ + val = dd->link_default; + break; + + case HFI1_IB_CFG_HRTBT: /* Heartbeat off/enable/auto */ + case HFI1_IB_CFG_PMA_TICKS: + default: +unimplemented: + if (HFI1_CAP_IS_KSET(PRINT_UNIMPL)) + dd_dev_info( + dd, + "%s: which %s: not implemented\n", + __func__, + ib_cfg_name(which)); + break; + } + + return val; +} + +/* + * The largest MAD packet size. + */ +#define MAX_MAD_PACKET 2048 + +/* + * Return the maximum header bytes that can go on the _wire_ + * for this device. This count includes the ICRC which is + * not part of the packet held in memory but it is appended + * by the HW. + * This is dependent on the device's receive header entry size. + * HFI allows this to be set per-receive context, but the + * driver presently enforces a global value. + */ +u32 lrh_max_header_bytes(struct hfi1_devdata *dd) +{ + /* + * The maximum non-payload (MTU) bytes in LRH.PktLen are + * the Receive Header Entry Size minus the PBC (or RHF) size + * plus one DW for the ICRC appended by HW. + * + * dd->rcd[0].rcvhdrqentsize is in DW. + * We use rcd[0] as all context will have the same value. Also, + * the first kernel context would have been allocated by now so + * we are guaranteed a valid value. + */ + return (dd->rcd[0]->rcvhdrqentsize - 2/*PBC/RHF*/ + 1/*ICRC*/) << 2; +} + +/* + * Set Send Length + * @ppd - per port data + * + * Set the MTU by limiting how many DWs may be sent. The SendLenCheck* + * registers compare against LRH.PktLen, so use the max bytes included + * in the LRH. + * + * This routine changes all VL values except VL15, which it maintains at + * the same value. + */ +static void set_send_length(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u32 max_hb = lrh_max_header_bytes(dd), maxvlmtu = 0, dcmtu; + u64 len1 = 0, len2 = (((dd->vld[15].mtu + max_hb) >> 2) + & SEND_LEN_CHECK1_LEN_VL15_MASK) << + SEND_LEN_CHECK1_LEN_VL15_SHIFT; + int i; + + for (i = 0; i < ppd->vls_supported; i++) { + if (dd->vld[i].mtu > maxvlmtu) + maxvlmtu = dd->vld[i].mtu; + if (i <= 3) + len1 |= (((dd->vld[i].mtu + max_hb) >> 2) + & SEND_LEN_CHECK0_LEN_VL0_MASK) << + ((i % 4) * SEND_LEN_CHECK0_LEN_VL1_SHIFT); + else + len2 |= (((dd->vld[i].mtu + max_hb) >> 2) + & SEND_LEN_CHECK1_LEN_VL4_MASK) << + ((i % 4) * SEND_LEN_CHECK1_LEN_VL5_SHIFT); + } + write_csr(dd, SEND_LEN_CHECK0, len1); + write_csr(dd, SEND_LEN_CHECK1, len2); + /* adjust kernel credit return thresholds based on new MTUs */ + /* all kernel receive contexts have the same hdrqentsize */ + for (i = 0; i < ppd->vls_supported; i++) { + sc_set_cr_threshold(dd->vld[i].sc, + sc_mtu_to_threshold(dd->vld[i].sc, dd->vld[i].mtu, + dd->rcd[0]->rcvhdrqentsize)); + } + sc_set_cr_threshold(dd->vld[15].sc, + sc_mtu_to_threshold(dd->vld[15].sc, dd->vld[15].mtu, + dd->rcd[0]->rcvhdrqentsize)); + + /* Adjust maximum MTU for the port in DC */ + dcmtu = maxvlmtu == 10240 ? DCC_CFG_PORT_MTU_CAP_10240 : + (ilog2(maxvlmtu >> 8) + 1); + len1 = read_csr(ppd->dd, DCC_CFG_PORT_CONFIG); + len1 &= ~DCC_CFG_PORT_CONFIG_MTU_CAP_SMASK; + len1 |= ((u64)dcmtu & DCC_CFG_PORT_CONFIG_MTU_CAP_MASK) << + DCC_CFG_PORT_CONFIG_MTU_CAP_SHIFT; + write_csr(ppd->dd, DCC_CFG_PORT_CONFIG, len1); +} + +static void set_lidlmc(struct hfi1_pportdata *ppd) +{ + int i; + u64 sreg = 0; + struct hfi1_devdata *dd = ppd->dd; + u32 mask = ~((1U << ppd->lmc) - 1); + u64 c1 = read_csr(ppd->dd, DCC_CFG_PORT_CONFIG1); + + if (dd->hfi1_snoop.mode_flag) + dd_dev_info(dd, "Set lid/lmc while snooping"); + + c1 &= ~(DCC_CFG_PORT_CONFIG1_TARGET_DLID_SMASK + | DCC_CFG_PORT_CONFIG1_DLID_MASK_SMASK); + c1 |= ((ppd->lid & DCC_CFG_PORT_CONFIG1_TARGET_DLID_MASK) + << DCC_CFG_PORT_CONFIG1_TARGET_DLID_SHIFT)| + ((mask & DCC_CFG_PORT_CONFIG1_DLID_MASK_MASK) + << DCC_CFG_PORT_CONFIG1_DLID_MASK_SHIFT); + write_csr(ppd->dd, DCC_CFG_PORT_CONFIG1, c1); + + /* + * Iterate over all the send contexts and set their SLID check + */ + sreg = ((mask & SEND_CTXT_CHECK_SLID_MASK_MASK) << + SEND_CTXT_CHECK_SLID_MASK_SHIFT) | + (((ppd->lid & mask) & SEND_CTXT_CHECK_SLID_VALUE_MASK) << + SEND_CTXT_CHECK_SLID_VALUE_SHIFT); + + for (i = 0; i < dd->chip_send_contexts; i++) { + hfi1_cdbg(LINKVERB, "SendContext[%d].SLID_CHECK = 0x%x", + i, (u32)sreg); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_SLID, sreg); + } + + /* Now we have to do the same thing for the sdma engines */ + sdma_update_lmc(dd, mask, ppd->lid); +} + +static int wait_phy_linkstate(struct hfi1_devdata *dd, u32 state, u32 msecs) +{ + unsigned long timeout; + u32 curr_state; + + timeout = jiffies + msecs_to_jiffies(msecs); + while (1) { + curr_state = read_physical_state(dd); + if (curr_state == state) + break; + if (time_after(jiffies, timeout)) { + dd_dev_err(dd, + "timeout waiting for phy link state 0x%x, current state is 0x%x\n", + state, curr_state); + return -ETIMEDOUT; + } + usleep_range(1950, 2050); /* sleep 2ms-ish */ + } + + return 0; +} + +/* + * Helper for set_link_state(). Do not call except from that routine. + * Expects ppd->hls_mutex to be held. + * + * @rem_reason value to be sent to the neighbor + * + * LinkDownReasons only set if transition succeeds. + */ +static int goto_offline(struct hfi1_pportdata *ppd, u8 rem_reason) +{ + struct hfi1_devdata *dd = ppd->dd; + u32 pstate, previous_state; + u32 last_local_state; + u32 last_remote_state; + int ret; + int do_transition; + int do_wait; + + previous_state = ppd->host_link_state; + ppd->host_link_state = HLS_GOING_OFFLINE; + pstate = read_physical_state(dd); + if (pstate == PLS_OFFLINE) { + do_transition = 0; /* in right state */ + do_wait = 0; /* ...no need to wait */ + } else if ((pstate & 0xff) == PLS_OFFLINE) { + do_transition = 0; /* in an offline transient state */ + do_wait = 1; /* ...wait for it to settle */ + } else { + do_transition = 1; /* need to move to offline */ + do_wait = 1; /* ...will need to wait */ + } + + if (do_transition) { + ret = set_physical_link_state(dd, + PLS_OFFLINE | (rem_reason << 8)); + + if (ret != HCMD_SUCCESS) { + dd_dev_err(dd, + "Failed to transition to Offline link state, return %d\n", + ret); + return -EINVAL; + } + if (ppd->offline_disabled_reason == OPA_LINKDOWN_REASON_NONE) + ppd->offline_disabled_reason = + OPA_LINKDOWN_REASON_TRANSIENT; + } + + if (do_wait) { + /* it can take a while for the link to go down */ + ret = wait_phy_linkstate(dd, PLS_OFFLINE, 5000); + if (ret < 0) + return ret; + } + + /* make sure the logical state is also down */ + wait_logical_linkstate(ppd, IB_PORT_DOWN, 1000); + + /* + * Now in charge of LCB - must be after the physical state is + * offline.quiet and before host_link_state is changed. + */ + set_host_lcb_access(dd); + write_csr(dd, DC_LCB_ERR_EN, ~0ull); /* watch LCB errors */ + ppd->host_link_state = HLS_LINK_COOLDOWN; /* LCB access allowed */ + + /* + * The LNI has a mandatory wait time after the physical state + * moves to Offline.Quiet. The wait time may be different + * depending on how the link went down. The 8051 firmware + * will observe the needed wait time and only move to ready + * when that is completed. The largest of the quiet timeouts + * is 2.5s, so wait that long and then a bit more. + */ + ret = wait_fm_ready(dd, 3000); + if (ret) { + dd_dev_err(dd, + "After going offline, timed out waiting for the 8051 to become ready to accept host requests\n"); + /* state is really offline, so make it so */ + ppd->host_link_state = HLS_DN_OFFLINE; + return ret; + } + + /* + * The state is now offline and the 8051 is ready to accept host + * requests. + * - change our state + * - notify others if we were previously in a linkup state + */ + ppd->host_link_state = HLS_DN_OFFLINE; + if (previous_state & HLS_UP) { + /* went down while link was up */ + handle_linkup_change(dd, 0); + } else if (previous_state + & (HLS_DN_POLL | HLS_VERIFY_CAP | HLS_GOING_UP)) { + /* went down while attempting link up */ + /* byte 1 of last_*_state is the failure reason */ + read_last_local_state(dd, &last_local_state); + read_last_remote_state(dd, &last_remote_state); + dd_dev_err(dd, + "LNI failure last states: local 0x%08x, remote 0x%08x\n", + last_local_state, last_remote_state); + } + + /* the active link width (downgrade) is 0 on link down */ + ppd->link_width_active = 0; + ppd->link_width_downgrade_tx_active = 0; + ppd->link_width_downgrade_rx_active = 0; + ppd->current_egress_rate = 0; + return 0; +} + +/* return the link state name */ +static const char *link_state_name(u32 state) +{ + const char *name; + int n = ilog2(state); + static const char * const names[] = { + [__HLS_UP_INIT_BP] = "INIT", + [__HLS_UP_ARMED_BP] = "ARMED", + [__HLS_UP_ACTIVE_BP] = "ACTIVE", + [__HLS_DN_DOWNDEF_BP] = "DOWNDEF", + [__HLS_DN_POLL_BP] = "POLL", + [__HLS_DN_DISABLE_BP] = "DISABLE", + [__HLS_DN_OFFLINE_BP] = "OFFLINE", + [__HLS_VERIFY_CAP_BP] = "VERIFY_CAP", + [__HLS_GOING_UP_BP] = "GOING_UP", + [__HLS_GOING_OFFLINE_BP] = "GOING_OFFLINE", + [__HLS_LINK_COOLDOWN_BP] = "LINK_COOLDOWN" + }; + + name = n < ARRAY_SIZE(names) ? names[n] : NULL; + return name ? name : "unknown"; +} + +/* return the link state reason name */ +static const char *link_state_reason_name(struct hfi1_pportdata *ppd, u32 state) +{ + if (state == HLS_UP_INIT) { + switch (ppd->linkinit_reason) { + case OPA_LINKINIT_REASON_LINKUP: + return "(LINKUP)"; + case OPA_LINKINIT_REASON_FLAPPING: + return "(FLAPPING)"; + case OPA_LINKINIT_OUTSIDE_POLICY: + return "(OUTSIDE_POLICY)"; + case OPA_LINKINIT_QUARANTINED: + return "(QUARANTINED)"; + case OPA_LINKINIT_INSUFIC_CAPABILITY: + return "(INSUFIC_CAPABILITY)"; + default: + break; + } + } + return ""; +} + +/* + * driver_physical_state - convert the driver's notion of a port's + * state (an HLS_*) into a physical state (a {IB,OPA}_PORTPHYSSTATE_*). + * Return -1 (converted to a u32) to indicate error. + */ +u32 driver_physical_state(struct hfi1_pportdata *ppd) +{ + switch (ppd->host_link_state) { + case HLS_UP_INIT: + case HLS_UP_ARMED: + case HLS_UP_ACTIVE: + return IB_PORTPHYSSTATE_LINKUP; + case HLS_DN_POLL: + return IB_PORTPHYSSTATE_POLLING; + case HLS_DN_DISABLE: + return IB_PORTPHYSSTATE_DISABLED; + case HLS_DN_OFFLINE: + return OPA_PORTPHYSSTATE_OFFLINE; + case HLS_VERIFY_CAP: + return IB_PORTPHYSSTATE_POLLING; + case HLS_GOING_UP: + return IB_PORTPHYSSTATE_POLLING; + case HLS_GOING_OFFLINE: + return OPA_PORTPHYSSTATE_OFFLINE; + case HLS_LINK_COOLDOWN: + return OPA_PORTPHYSSTATE_OFFLINE; + case HLS_DN_DOWNDEF: + default: + dd_dev_err(ppd->dd, "invalid host_link_state 0x%x\n", + ppd->host_link_state); + return -1; + } +} + +/* + * driver_logical_state - convert the driver's notion of a port's + * state (an HLS_*) into a logical state (a IB_PORT_*). Return -1 + * (converted to a u32) to indicate error. + */ +u32 driver_logical_state(struct hfi1_pportdata *ppd) +{ + if (ppd->host_link_state && !(ppd->host_link_state & HLS_UP)) + return IB_PORT_DOWN; + + switch (ppd->host_link_state & HLS_UP) { + case HLS_UP_INIT: + return IB_PORT_INIT; + case HLS_UP_ARMED: + return IB_PORT_ARMED; + case HLS_UP_ACTIVE: + return IB_PORT_ACTIVE; + default: + dd_dev_err(ppd->dd, "invalid host_link_state 0x%x\n", + ppd->host_link_state); + return -1; + } +} + +void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, + u8 neigh_reason, u8 rem_reason) +{ + if (ppd->local_link_down_reason.latest == 0 && + ppd->neigh_link_down_reason.latest == 0) { + ppd->local_link_down_reason.latest = lcl_reason; + ppd->neigh_link_down_reason.latest = neigh_reason; + ppd->remote_link_down_reason = rem_reason; + } +} + +/* + * Change the physical and/or logical link state. + * + * Do not call this routine while inside an interrupt. It contains + * calls to routines that can take multiple seconds to finish. + * + * Returns 0 on success, -errno on failure. + */ +int set_link_state(struct hfi1_pportdata *ppd, u32 state) +{ + struct hfi1_devdata *dd = ppd->dd; + struct ib_event event = {.device = NULL}; + int ret1, ret = 0; + int was_up, is_down; + int orig_new_state, poll_bounce; + + mutex_lock(&ppd->hls_lock); + + orig_new_state = state; + if (state == HLS_DN_DOWNDEF) + state = dd->link_default; + + /* interpret poll -> poll as a link bounce */ + poll_bounce = ppd->host_link_state == HLS_DN_POLL + && state == HLS_DN_POLL; + + dd_dev_info(dd, "%s: current %s, new %s %s%s\n", __func__, + link_state_name(ppd->host_link_state), + link_state_name(orig_new_state), + poll_bounce ? "(bounce) " : "", + link_state_reason_name(ppd, state)); + + was_up = !!(ppd->host_link_state & HLS_UP); + + /* + * If we're going to a (HLS_*) link state that implies the logical + * link state is neither of (IB_PORT_ARMED, IB_PORT_ACTIVE), then + * reset is_sm_config_started to 0. + */ + if (!(state & (HLS_UP_ARMED | HLS_UP_ACTIVE))) + ppd->is_sm_config_started = 0; + + /* + * Do nothing if the states match. Let a poll to poll link bounce + * go through. + */ + if (ppd->host_link_state == state && !poll_bounce) + goto done; + + switch (state) { + case HLS_UP_INIT: + if (ppd->host_link_state == HLS_DN_POLL && (quick_linkup + || dd->icode == ICODE_FUNCTIONAL_SIMULATOR)) { + /* + * Quick link up jumps from polling to here. + * + * Whether in normal or loopback mode, the + * simulator jumps from polling to link up. + * Accept that here. + */ + /* OK */; + } else if (ppd->host_link_state != HLS_GOING_UP) { + goto unexpected; + } + + ppd->host_link_state = HLS_UP_INIT; + ret = wait_logical_linkstate(ppd, IB_PORT_INIT, 1000); + if (ret) { + /* logical state didn't change, stay at going_up */ + ppd->host_link_state = HLS_GOING_UP; + dd_dev_err(dd, + "%s: logical state did not change to INIT\n", + __func__); + } else { + /* clear old transient LINKINIT_REASON code */ + if (ppd->linkinit_reason >= OPA_LINKINIT_REASON_CLEAR) + ppd->linkinit_reason = + OPA_LINKINIT_REASON_LINKUP; + + /* enable the port */ + add_rcvctrl(dd, RCV_CTRL_RCV_PORT_ENABLE_SMASK); + + handle_linkup_change(dd, 1); + } + break; + case HLS_UP_ARMED: + if (ppd->host_link_state != HLS_UP_INIT) + goto unexpected; + + ppd->host_link_state = HLS_UP_ARMED; + set_logical_state(dd, LSTATE_ARMED); + ret = wait_logical_linkstate(ppd, IB_PORT_ARMED, 1000); + if (ret) { + /* logical state didn't change, stay at init */ + ppd->host_link_state = HLS_UP_INIT; + dd_dev_err(dd, + "%s: logical state did not change to ARMED\n", + __func__); + } + /* + * The simulator does not currently implement SMA messages, + * so neighbor_normal is not set. Set it here when we first + * move to Armed. + */ + if (dd->icode == ICODE_FUNCTIONAL_SIMULATOR) + ppd->neighbor_normal = 1; + break; + case HLS_UP_ACTIVE: + if (ppd->host_link_state != HLS_UP_ARMED) + goto unexpected; + + ppd->host_link_state = HLS_UP_ACTIVE; + set_logical_state(dd, LSTATE_ACTIVE); + ret = wait_logical_linkstate(ppd, IB_PORT_ACTIVE, 1000); + if (ret) { + /* logical state didn't change, stay at armed */ + ppd->host_link_state = HLS_UP_ARMED; + dd_dev_err(dd, + "%s: logical state did not change to ACTIVE\n", + __func__); + } else { + + /* tell all engines to go running */ + sdma_all_running(dd); + + /* Signal the IB layer that the port has went active */ + event.device = &dd->verbs_dev.ibdev; + event.element.port_num = ppd->port; + event.event = IB_EVENT_PORT_ACTIVE; + } + break; + case HLS_DN_POLL: + if ((ppd->host_link_state == HLS_DN_DISABLE || + ppd->host_link_state == HLS_DN_OFFLINE) && + dd->dc_shutdown) + dc_start(dd); + /* Hand LED control to the DC */ + write_csr(dd, DCC_CFG_LED_CNTRL, 0); + + if (ppd->host_link_state != HLS_DN_OFFLINE) { + u8 tmp = ppd->link_enabled; + + ret = goto_offline(ppd, ppd->remote_link_down_reason); + if (ret) { + ppd->link_enabled = tmp; + break; + } + ppd->remote_link_down_reason = 0; + + if (ppd->driver_link_ready) + ppd->link_enabled = 1; + } + + ret = set_local_link_attributes(ppd); + if (ret) + break; + + ppd->port_error_action = 0; + ppd->host_link_state = HLS_DN_POLL; + + if (quick_linkup) { + /* quick linkup does not go into polling */ + ret = do_quick_linkup(dd); + } else { + ret1 = set_physical_link_state(dd, PLS_POLLING); + if (ret1 != HCMD_SUCCESS) { + dd_dev_err(dd, + "Failed to transition to Polling link state, return 0x%x\n", + ret1); + ret = -EINVAL; + } + } + ppd->offline_disabled_reason = OPA_LINKDOWN_REASON_NONE; + /* + * If an error occurred above, go back to offline. The + * caller may reschedule another attempt. + */ + if (ret) + goto_offline(ppd, 0); + break; + case HLS_DN_DISABLE: + /* link is disabled */ + ppd->link_enabled = 0; + + /* allow any state to transition to disabled */ + + /* must transition to offline first */ + if (ppd->host_link_state != HLS_DN_OFFLINE) { + ret = goto_offline(ppd, ppd->remote_link_down_reason); + if (ret) + break; + ppd->remote_link_down_reason = 0; + } + + ret1 = set_physical_link_state(dd, PLS_DISABLED); + if (ret1 != HCMD_SUCCESS) { + dd_dev_err(dd, + "Failed to transition to Disabled link state, return 0x%x\n", + ret1); + ret = -EINVAL; + break; + } + ppd->host_link_state = HLS_DN_DISABLE; + dc_shutdown(dd); + break; + case HLS_DN_OFFLINE: + if (ppd->host_link_state == HLS_DN_DISABLE) + dc_start(dd); + + /* allow any state to transition to offline */ + ret = goto_offline(ppd, ppd->remote_link_down_reason); + if (!ret) + ppd->remote_link_down_reason = 0; + break; + case HLS_VERIFY_CAP: + if (ppd->host_link_state != HLS_DN_POLL) + goto unexpected; + ppd->host_link_state = HLS_VERIFY_CAP; + break; + case HLS_GOING_UP: + if (ppd->host_link_state != HLS_VERIFY_CAP) + goto unexpected; + + ret1 = set_physical_link_state(dd, PLS_LINKUP); + if (ret1 != HCMD_SUCCESS) { + dd_dev_err(dd, + "Failed to transition to link up state, return 0x%x\n", + ret1); + ret = -EINVAL; + break; + } + ppd->host_link_state = HLS_GOING_UP; + break; + + case HLS_GOING_OFFLINE: /* transient within goto_offline() */ + case HLS_LINK_COOLDOWN: /* transient within goto_offline() */ + default: + dd_dev_info(dd, "%s: state 0x%x: not supported\n", + __func__, state); + ret = -EINVAL; + break; + } + + is_down = !!(ppd->host_link_state & (HLS_DN_POLL | + HLS_DN_DISABLE | HLS_DN_OFFLINE)); + + if (was_up && is_down && ppd->local_link_down_reason.sma == 0 && + ppd->neigh_link_down_reason.sma == 0) { + ppd->local_link_down_reason.sma = + ppd->local_link_down_reason.latest; + ppd->neigh_link_down_reason.sma = + ppd->neigh_link_down_reason.latest; + } + + goto done; + +unexpected: + dd_dev_err(dd, "%s: unexpected state transition from %s to %s\n", + __func__, link_state_name(ppd->host_link_state), + link_state_name(state)); + ret = -EINVAL; + +done: + mutex_unlock(&ppd->hls_lock); + + if (event.device) + ib_dispatch_event(&event); + + return ret; +} + +int hfi1_set_ib_cfg(struct hfi1_pportdata *ppd, int which, u32 val) +{ + u64 reg; + int ret = 0; + + switch (which) { + case HFI1_IB_CFG_LIDLMC: + set_lidlmc(ppd); + break; + case HFI1_IB_CFG_VL_HIGH_LIMIT: + /* + * The VL Arbitrator high limit is sent in units of 4k + * bytes, while HFI stores it in units of 64 bytes. + */ + val *= 4096/64; + reg = ((u64)val & SEND_HIGH_PRIORITY_LIMIT_LIMIT_MASK) + << SEND_HIGH_PRIORITY_LIMIT_LIMIT_SHIFT; + write_csr(ppd->dd, SEND_HIGH_PRIORITY_LIMIT, reg); + break; + case HFI1_IB_CFG_LINKDEFAULT: /* IB link default (sleep/poll) */ + /* HFI only supports POLL as the default link down state */ + if (val != HLS_DN_POLL) + ret = -EINVAL; + break; + case HFI1_IB_CFG_OP_VLS: + if (ppd->vls_operational != val) { + ppd->vls_operational = val; + if (!ppd->port) + ret = -EINVAL; + else + ret = sdma_map_init( + ppd->dd, + ppd->port - 1, + val, + NULL); + } + break; + /* + * For link width, link width downgrade, and speed enable, always AND + * the setting with what is actually supported. This has two benefits. + * First, enabled can't have unsupported values, no matter what the + * SM or FM might want. Second, the ALL_SUPPORTED wildcards that mean + * "fill in with your supported value" have all the bits in the + * field set, so simply ANDing with supported has the desired result. + */ + case HFI1_IB_CFG_LWID_ENB: /* set allowed Link-width */ + ppd->link_width_enabled = val & ppd->link_width_supported; + break; + case HFI1_IB_CFG_LWID_DG_ENB: /* set allowed link width downgrade */ + ppd->link_width_downgrade_enabled = + val & ppd->link_width_downgrade_supported; + break; + case HFI1_IB_CFG_SPD_ENB: /* allowed Link speeds */ + ppd->link_speed_enabled = val & ppd->link_speed_supported; + break; + case HFI1_IB_CFG_OVERRUN_THRESH: /* IB overrun threshold */ + /* + * HFI does not follow IB specs, save this value + * so we can report it, if asked. + */ + ppd->overrun_threshold = val; + break; + case HFI1_IB_CFG_PHYERR_THRESH: /* IB PHY error threshold */ + /* + * HFI does not follow IB specs, save this value + * so we can report it, if asked. + */ + ppd->phy_error_threshold = val; + break; + + case HFI1_IB_CFG_MTU: + set_send_length(ppd); + break; + + case HFI1_IB_CFG_PKEYS: + if (HFI1_CAP_IS_KSET(PKEY_CHECK)) + set_partition_keys(ppd); + break; + + default: + if (HFI1_CAP_IS_KSET(PRINT_UNIMPL)) + dd_dev_info(ppd->dd, + "%s: which %s, val 0x%x: not implemented\n", + __func__, ib_cfg_name(which), val); + break; + } + return ret; +} + +/* begin functions related to vl arbitration table caching */ +static void init_vl_arb_caches(struct hfi1_pportdata *ppd) +{ + int i; + + BUILD_BUG_ON(VL_ARB_TABLE_SIZE != + VL_ARB_LOW_PRIO_TABLE_SIZE); + BUILD_BUG_ON(VL_ARB_TABLE_SIZE != + VL_ARB_HIGH_PRIO_TABLE_SIZE); + + /* + * Note that we always return values directly from the + * 'vl_arb_cache' (and do no CSR reads) in response to a + * 'Get(VLArbTable)'. This is obviously correct after a + * 'Set(VLArbTable)', since the cache will then be up to + * date. But it's also correct prior to any 'Set(VLArbTable)' + * since then both the cache, and the relevant h/w registers + * will be zeroed. + */ + + for (i = 0; i < MAX_PRIO_TABLE; i++) + spin_lock_init(&ppd->vl_arb_cache[i].lock); +} + +/* + * vl_arb_lock_cache + * + * All other vl_arb_* functions should be called only after locking + * the cache. + */ +static inline struct vl_arb_cache * +vl_arb_lock_cache(struct hfi1_pportdata *ppd, int idx) +{ + if (idx != LO_PRIO_TABLE && idx != HI_PRIO_TABLE) + return NULL; + spin_lock(&ppd->vl_arb_cache[idx].lock); + return &ppd->vl_arb_cache[idx]; +} + +static inline void vl_arb_unlock_cache(struct hfi1_pportdata *ppd, int idx) +{ + spin_unlock(&ppd->vl_arb_cache[idx].lock); +} + +static void vl_arb_get_cache(struct vl_arb_cache *cache, + struct ib_vl_weight_elem *vl) +{ + memcpy(vl, cache->table, VL_ARB_TABLE_SIZE * sizeof(*vl)); +} + +static void vl_arb_set_cache(struct vl_arb_cache *cache, + struct ib_vl_weight_elem *vl) +{ + memcpy(cache->table, vl, VL_ARB_TABLE_SIZE * sizeof(*vl)); +} + +static int vl_arb_match_cache(struct vl_arb_cache *cache, + struct ib_vl_weight_elem *vl) +{ + return !memcmp(cache->table, vl, VL_ARB_TABLE_SIZE * sizeof(*vl)); +} +/* end functions related to vl arbitration table caching */ + +static int set_vl_weights(struct hfi1_pportdata *ppd, u32 target, + u32 size, struct ib_vl_weight_elem *vl) +{ + struct hfi1_devdata *dd = ppd->dd; + u64 reg; + unsigned int i, is_up = 0; + int drain, ret = 0; + + mutex_lock(&ppd->hls_lock); + + if (ppd->host_link_state & HLS_UP) + is_up = 1; + + drain = !is_ax(dd) && is_up; + + if (drain) + /* + * Before adjusting VL arbitration weights, empty per-VL + * FIFOs, otherwise a packet whose VL weight is being + * set to 0 could get stuck in a FIFO with no chance to + * egress. + */ + ret = stop_drain_data_vls(dd); + + if (ret) { + dd_dev_err( + dd, + "%s: cannot stop/drain VLs - refusing to change VL arbitration weights\n", + __func__); + goto err; + } + + for (i = 0; i < size; i++, vl++) { + /* + * NOTE: The low priority shift and mask are used here, but + * they are the same for both the low and high registers. + */ + reg = (((u64)vl->vl & SEND_LOW_PRIORITY_LIST_VL_MASK) + << SEND_LOW_PRIORITY_LIST_VL_SHIFT) + | (((u64)vl->weight + & SEND_LOW_PRIORITY_LIST_WEIGHT_MASK) + << SEND_LOW_PRIORITY_LIST_WEIGHT_SHIFT); + write_csr(dd, target + (i * 8), reg); + } + pio_send_control(dd, PSC_GLOBAL_VLARB_ENABLE); + + if (drain) + open_fill_data_vls(dd); /* reopen all VLs */ + +err: + mutex_unlock(&ppd->hls_lock); + + return ret; +} + +/* + * Read one credit merge VL register. + */ +static void read_one_cm_vl(struct hfi1_devdata *dd, u32 csr, + struct vl_limit *vll) +{ + u64 reg = read_csr(dd, csr); + + vll->dedicated = cpu_to_be16( + (reg >> SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SHIFT) + & SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_MASK); + vll->shared = cpu_to_be16( + (reg >> SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_SHIFT) + & SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_MASK); +} + +/* + * Read the current credit merge limits. + */ +static int get_buffer_control(struct hfi1_devdata *dd, + struct buffer_control *bc, u16 *overall_limit) +{ + u64 reg; + int i; + + /* not all entries are filled in */ + memset(bc, 0, sizeof(*bc)); + + /* OPA and HFI have a 1-1 mapping */ + for (i = 0; i < TXE_NUM_DATA_VL; i++) + read_one_cm_vl(dd, SEND_CM_CREDIT_VL + (8*i), &bc->vl[i]); + + /* NOTE: assumes that VL* and VL15 CSRs are bit-wise identical */ + read_one_cm_vl(dd, SEND_CM_CREDIT_VL15, &bc->vl[15]); + + reg = read_csr(dd, SEND_CM_GLOBAL_CREDIT); + bc->overall_shared_limit = cpu_to_be16( + (reg >> SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_SHIFT) + & SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_MASK); + if (overall_limit) + *overall_limit = (reg + >> SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_SHIFT) + & SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_MASK; + return sizeof(struct buffer_control); +} + +static int get_sc2vlnt(struct hfi1_devdata *dd, struct sc2vlnt *dp) +{ + u64 reg; + int i; + + /* each register contains 16 SC->VLnt mappings, 4 bits each */ + reg = read_csr(dd, DCC_CFG_SC_VL_TABLE_15_0); + for (i = 0; i < sizeof(u64); i++) { + u8 byte = *(((u8 *)®) + i); + + dp->vlnt[2 * i] = byte & 0xf; + dp->vlnt[(2 * i) + 1] = (byte & 0xf0) >> 4; + } + + reg = read_csr(dd, DCC_CFG_SC_VL_TABLE_31_16); + for (i = 0; i < sizeof(u64); i++) { + u8 byte = *(((u8 *)®) + i); + + dp->vlnt[16 + (2 * i)] = byte & 0xf; + dp->vlnt[16 + (2 * i) + 1] = (byte & 0xf0) >> 4; + } + return sizeof(struct sc2vlnt); +} + +static void get_vlarb_preempt(struct hfi1_devdata *dd, u32 nelems, + struct ib_vl_weight_elem *vl) +{ + unsigned int i; + + for (i = 0; i < nelems; i++, vl++) { + vl->vl = 0xf; + vl->weight = 0; + } +} + +static void set_sc2vlnt(struct hfi1_devdata *dd, struct sc2vlnt *dp) +{ + write_csr(dd, DCC_CFG_SC_VL_TABLE_15_0, + DC_SC_VL_VAL(15_0, + 0, dp->vlnt[0] & 0xf, + 1, dp->vlnt[1] & 0xf, + 2, dp->vlnt[2] & 0xf, + 3, dp->vlnt[3] & 0xf, + 4, dp->vlnt[4] & 0xf, + 5, dp->vlnt[5] & 0xf, + 6, dp->vlnt[6] & 0xf, + 7, dp->vlnt[7] & 0xf, + 8, dp->vlnt[8] & 0xf, + 9, dp->vlnt[9] & 0xf, + 10, dp->vlnt[10] & 0xf, + 11, dp->vlnt[11] & 0xf, + 12, dp->vlnt[12] & 0xf, + 13, dp->vlnt[13] & 0xf, + 14, dp->vlnt[14] & 0xf, + 15, dp->vlnt[15] & 0xf)); + write_csr(dd, DCC_CFG_SC_VL_TABLE_31_16, + DC_SC_VL_VAL(31_16, + 16, dp->vlnt[16] & 0xf, + 17, dp->vlnt[17] & 0xf, + 18, dp->vlnt[18] & 0xf, + 19, dp->vlnt[19] & 0xf, + 20, dp->vlnt[20] & 0xf, + 21, dp->vlnt[21] & 0xf, + 22, dp->vlnt[22] & 0xf, + 23, dp->vlnt[23] & 0xf, + 24, dp->vlnt[24] & 0xf, + 25, dp->vlnt[25] & 0xf, + 26, dp->vlnt[26] & 0xf, + 27, dp->vlnt[27] & 0xf, + 28, dp->vlnt[28] & 0xf, + 29, dp->vlnt[29] & 0xf, + 30, dp->vlnt[30] & 0xf, + 31, dp->vlnt[31] & 0xf)); +} + +static void nonzero_msg(struct hfi1_devdata *dd, int idx, const char *what, + u16 limit) +{ + if (limit != 0) + dd_dev_info(dd, "Invalid %s limit %d on VL %d, ignoring\n", + what, (int)limit, idx); +} + +/* change only the shared limit portion of SendCmGLobalCredit */ +static void set_global_shared(struct hfi1_devdata *dd, u16 limit) +{ + u64 reg; + + reg = read_csr(dd, SEND_CM_GLOBAL_CREDIT); + reg &= ~SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_SMASK; + reg |= (u64)limit << SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_SHIFT; + write_csr(dd, SEND_CM_GLOBAL_CREDIT, reg); +} + +/* change only the total credit limit portion of SendCmGLobalCredit */ +static void set_global_limit(struct hfi1_devdata *dd, u16 limit) +{ + u64 reg; + + reg = read_csr(dd, SEND_CM_GLOBAL_CREDIT); + reg &= ~SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_SMASK; + reg |= (u64)limit << SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_SHIFT; + write_csr(dd, SEND_CM_GLOBAL_CREDIT, reg); +} + +/* set the given per-VL shared limit */ +static void set_vl_shared(struct hfi1_devdata *dd, int vl, u16 limit) +{ + u64 reg; + u32 addr; + + if (vl < TXE_NUM_DATA_VL) + addr = SEND_CM_CREDIT_VL + (8 * vl); + else + addr = SEND_CM_CREDIT_VL15; + + reg = read_csr(dd, addr); + reg &= ~SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_SMASK; + reg |= (u64)limit << SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_SHIFT; + write_csr(dd, addr, reg); +} + +/* set the given per-VL dedicated limit */ +static void set_vl_dedicated(struct hfi1_devdata *dd, int vl, u16 limit) +{ + u64 reg; + u32 addr; + + if (vl < TXE_NUM_DATA_VL) + addr = SEND_CM_CREDIT_VL + (8 * vl); + else + addr = SEND_CM_CREDIT_VL15; + + reg = read_csr(dd, addr); + reg &= ~SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SMASK; + reg |= (u64)limit << SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SHIFT; + write_csr(dd, addr, reg); +} + +/* spin until the given per-VL status mask bits clear */ +static void wait_for_vl_status_clear(struct hfi1_devdata *dd, u64 mask, + const char *which) +{ + unsigned long timeout; + u64 reg; + + timeout = jiffies + msecs_to_jiffies(VL_STATUS_CLEAR_TIMEOUT); + while (1) { + reg = read_csr(dd, SEND_CM_CREDIT_USED_STATUS) & mask; + + if (reg == 0) + return; /* success */ + if (time_after(jiffies, timeout)) + break; /* timed out */ + udelay(1); + } + + dd_dev_err(dd, + "%s credit change status not clearing after %dms, mask 0x%llx, not clear 0x%llx\n", + which, VL_STATUS_CLEAR_TIMEOUT, mask, reg); + /* + * If this occurs, it is likely there was a credit loss on the link. + * The only recovery from that is a link bounce. + */ + dd_dev_err(dd, + "Continuing anyway. A credit loss may occur. Suggest a link bounce\n"); +} + +/* + * The number of credits on the VLs may be changed while everything + * is "live", but the following algorithm must be followed due to + * how the hardware is actually implemented. In particular, + * Return_Credit_Status[] is the only correct status check. + * + * if (reducing Global_Shared_Credit_Limit or any shared limit changing) + * set Global_Shared_Credit_Limit = 0 + * use_all_vl = 1 + * mask0 = all VLs that are changing either dedicated or shared limits + * set Shared_Limit[mask0] = 0 + * spin until Return_Credit_Status[use_all_vl ? all VL : mask0] == 0 + * if (changing any dedicated limit) + * mask1 = all VLs that are lowering dedicated limits + * lower Dedicated_Limit[mask1] + * spin until Return_Credit_Status[mask1] == 0 + * raise Dedicated_Limits + * raise Shared_Limits + * raise Global_Shared_Credit_Limit + * + * lower = if the new limit is lower, set the limit to the new value + * raise = if the new limit is higher than the current value (may be changed + * earlier in the algorithm), set the new limit to the new value + */ +static int set_buffer_control(struct hfi1_devdata *dd, + struct buffer_control *new_bc) +{ + u64 changing_mask, ld_mask, stat_mask; + int change_count; + int i, use_all_mask; + int this_shared_changing; + /* + * A0: add the variable any_shared_limit_changing below and in the + * algorithm above. If removing A0 support, it can be removed. + */ + int any_shared_limit_changing; + struct buffer_control cur_bc; + u8 changing[OPA_MAX_VLS]; + u8 lowering_dedicated[OPA_MAX_VLS]; + u16 cur_total; + u32 new_total = 0; + const u64 all_mask = + SEND_CM_CREDIT_USED_STATUS_VL0_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL1_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL2_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL3_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL4_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL5_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL6_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL7_RETURN_CREDIT_STATUS_SMASK + | SEND_CM_CREDIT_USED_STATUS_VL15_RETURN_CREDIT_STATUS_SMASK; + +#define valid_vl(idx) ((idx) < TXE_NUM_DATA_VL || (idx) == 15) +#define NUM_USABLE_VLS 16 /* look at VL15 and less */ + + + /* find the new total credits, do sanity check on unused VLs */ + for (i = 0; i < OPA_MAX_VLS; i++) { + if (valid_vl(i)) { + new_total += be16_to_cpu(new_bc->vl[i].dedicated); + continue; + } + nonzero_msg(dd, i, "dedicated", + be16_to_cpu(new_bc->vl[i].dedicated)); + nonzero_msg(dd, i, "shared", + be16_to_cpu(new_bc->vl[i].shared)); + new_bc->vl[i].dedicated = 0; + new_bc->vl[i].shared = 0; + } + new_total += be16_to_cpu(new_bc->overall_shared_limit); + if (new_total > (u32)dd->link_credits) + return -EINVAL; + /* fetch the current values */ + get_buffer_control(dd, &cur_bc, &cur_total); + + /* + * Create the masks we will use. + */ + memset(changing, 0, sizeof(changing)); + memset(lowering_dedicated, 0, sizeof(lowering_dedicated)); + /* NOTE: Assumes that the individual VL bits are adjacent and in + increasing order */ + stat_mask = + SEND_CM_CREDIT_USED_STATUS_VL0_RETURN_CREDIT_STATUS_SMASK; + changing_mask = 0; + ld_mask = 0; + change_count = 0; + any_shared_limit_changing = 0; + for (i = 0; i < NUM_USABLE_VLS; i++, stat_mask <<= 1) { + if (!valid_vl(i)) + continue; + this_shared_changing = new_bc->vl[i].shared + != cur_bc.vl[i].shared; + if (this_shared_changing) + any_shared_limit_changing = 1; + if (new_bc->vl[i].dedicated != cur_bc.vl[i].dedicated + || this_shared_changing) { + changing[i] = 1; + changing_mask |= stat_mask; + change_count++; + } + if (be16_to_cpu(new_bc->vl[i].dedicated) < + be16_to_cpu(cur_bc.vl[i].dedicated)) { + lowering_dedicated[i] = 1; + ld_mask |= stat_mask; + } + } + + /* bracket the credit change with a total adjustment */ + if (new_total > cur_total) + set_global_limit(dd, new_total); + + /* + * Start the credit change algorithm. + */ + use_all_mask = 0; + if ((be16_to_cpu(new_bc->overall_shared_limit) < + be16_to_cpu(cur_bc.overall_shared_limit)) + || (is_a0(dd) && any_shared_limit_changing)) { + set_global_shared(dd, 0); + cur_bc.overall_shared_limit = 0; + use_all_mask = 1; + } + + for (i = 0; i < NUM_USABLE_VLS; i++) { + if (!valid_vl(i)) + continue; + + if (changing[i]) { + set_vl_shared(dd, i, 0); + cur_bc.vl[i].shared = 0; + } + } + + wait_for_vl_status_clear(dd, use_all_mask ? all_mask : changing_mask, + "shared"); + + if (change_count > 0) { + for (i = 0; i < NUM_USABLE_VLS; i++) { + if (!valid_vl(i)) + continue; + + if (lowering_dedicated[i]) { + set_vl_dedicated(dd, i, + be16_to_cpu(new_bc->vl[i].dedicated)); + cur_bc.vl[i].dedicated = + new_bc->vl[i].dedicated; + } + } + + wait_for_vl_status_clear(dd, ld_mask, "dedicated"); + + /* now raise all dedicated that are going up */ + for (i = 0; i < NUM_USABLE_VLS; i++) { + if (!valid_vl(i)) + continue; + + if (be16_to_cpu(new_bc->vl[i].dedicated) > + be16_to_cpu(cur_bc.vl[i].dedicated)) + set_vl_dedicated(dd, i, + be16_to_cpu(new_bc->vl[i].dedicated)); + } + } + + /* next raise all shared that are going up */ + for (i = 0; i < NUM_USABLE_VLS; i++) { + if (!valid_vl(i)) + continue; + + if (be16_to_cpu(new_bc->vl[i].shared) > + be16_to_cpu(cur_bc.vl[i].shared)) + set_vl_shared(dd, i, be16_to_cpu(new_bc->vl[i].shared)); + } + + /* finally raise the global shared */ + if (be16_to_cpu(new_bc->overall_shared_limit) > + be16_to_cpu(cur_bc.overall_shared_limit)) + set_global_shared(dd, + be16_to_cpu(new_bc->overall_shared_limit)); + + /* bracket the credit change with a total adjustment */ + if (new_total < cur_total) + set_global_limit(dd, new_total); + return 0; +} + +/* + * Read the given fabric manager table. Return the size of the + * table (in bytes) on success, and a negative error code on + * failure. + */ +int fm_get_table(struct hfi1_pportdata *ppd, int which, void *t) + +{ + int size; + struct vl_arb_cache *vlc; + + switch (which) { + case FM_TBL_VL_HIGH_ARB: + size = 256; + /* + * OPA specifies 128 elements (of 2 bytes each), though + * HFI supports only 16 elements in h/w. + */ + vlc = vl_arb_lock_cache(ppd, HI_PRIO_TABLE); + vl_arb_get_cache(vlc, t); + vl_arb_unlock_cache(ppd, HI_PRIO_TABLE); + break; + case FM_TBL_VL_LOW_ARB: + size = 256; + /* + * OPA specifies 128 elements (of 2 bytes each), though + * HFI supports only 16 elements in h/w. + */ + vlc = vl_arb_lock_cache(ppd, LO_PRIO_TABLE); + vl_arb_get_cache(vlc, t); + vl_arb_unlock_cache(ppd, LO_PRIO_TABLE); + break; + case FM_TBL_BUFFER_CONTROL: + size = get_buffer_control(ppd->dd, t, NULL); + break; + case FM_TBL_SC2VLNT: + size = get_sc2vlnt(ppd->dd, t); + break; + case FM_TBL_VL_PREEMPT_ELEMS: + size = 256; + /* OPA specifies 128 elements, of 2 bytes each */ + get_vlarb_preempt(ppd->dd, OPA_MAX_VLS, t); + break; + case FM_TBL_VL_PREEMPT_MATRIX: + size = 256; + /* + * OPA specifies that this is the same size as the VL + * arbitration tables (i.e., 256 bytes). + */ + break; + default: + return -EINVAL; + } + return size; +} + +/* + * Write the given fabric manager table. + */ +int fm_set_table(struct hfi1_pportdata *ppd, int which, void *t) +{ + int ret = 0; + struct vl_arb_cache *vlc; + + switch (which) { + case FM_TBL_VL_HIGH_ARB: + vlc = vl_arb_lock_cache(ppd, HI_PRIO_TABLE); + if (vl_arb_match_cache(vlc, t)) { + vl_arb_unlock_cache(ppd, HI_PRIO_TABLE); + break; + } + vl_arb_set_cache(vlc, t); + vl_arb_unlock_cache(ppd, HI_PRIO_TABLE); + ret = set_vl_weights(ppd, SEND_HIGH_PRIORITY_LIST, + VL_ARB_HIGH_PRIO_TABLE_SIZE, t); + break; + case FM_TBL_VL_LOW_ARB: + vlc = vl_arb_lock_cache(ppd, LO_PRIO_TABLE); + if (vl_arb_match_cache(vlc, t)) { + vl_arb_unlock_cache(ppd, LO_PRIO_TABLE); + break; + } + vl_arb_set_cache(vlc, t); + vl_arb_unlock_cache(ppd, LO_PRIO_TABLE); + ret = set_vl_weights(ppd, SEND_LOW_PRIORITY_LIST, + VL_ARB_LOW_PRIO_TABLE_SIZE, t); + break; + case FM_TBL_BUFFER_CONTROL: + ret = set_buffer_control(ppd->dd, t); + break; + case FM_TBL_SC2VLNT: + set_sc2vlnt(ppd->dd, t); + break; + default: + ret = -EINVAL; + } + return ret; +} + +/* + * Disable all data VLs. + * + * Return 0 if disabled, non-zero if the VLs cannot be disabled. + */ +static int disable_data_vls(struct hfi1_devdata *dd) +{ + if (is_a0(dd)) + return 1; + + pio_send_control(dd, PSC_DATA_VL_DISABLE); + + return 0; +} + +/* + * open_fill_data_vls() - the counterpart to stop_drain_data_vls(). + * Just re-enables all data VLs (the "fill" part happens + * automatically - the name was chosen for symmetry with + * stop_drain_data_vls()). + * + * Return 0 if successful, non-zero if the VLs cannot be enabled. + */ +int open_fill_data_vls(struct hfi1_devdata *dd) +{ + if (is_a0(dd)) + return 1; + + pio_send_control(dd, PSC_DATA_VL_ENABLE); + + return 0; +} + +/* + * drain_data_vls() - assumes that disable_data_vls() has been called, + * wait for occupancy (of per-VL FIFOs) for all contexts, and SDMA + * engines to drop to 0. + */ +static void drain_data_vls(struct hfi1_devdata *dd) +{ + sc_wait(dd); + sdma_wait(dd); + pause_for_credit_return(dd); +} + +/* + * stop_drain_data_vls() - disable, then drain all per-VL fifos. + * + * Use open_fill_data_vls() to resume using data VLs. This pair is + * meant to be used like this: + * + * stop_drain_data_vls(dd); + * // do things with per-VL resources + * open_fill_data_vls(dd); + */ +int stop_drain_data_vls(struct hfi1_devdata *dd) +{ + int ret; + + ret = disable_data_vls(dd); + if (ret == 0) + drain_data_vls(dd); + + return ret; +} + +/* + * Convert a nanosecond time to a cclock count. No matter how slow + * the cclock, a non-zero ns will always have a non-zero result. + */ +u32 ns_to_cclock(struct hfi1_devdata *dd, u32 ns) +{ + u32 cclocks; + + if (dd->icode == ICODE_FPGA_EMULATION) + cclocks = (ns * 1000) / FPGA_CCLOCK_PS; + else /* simulation pretends to be ASIC */ + cclocks = (ns * 1000) / ASIC_CCLOCK_PS; + if (ns && !cclocks) /* if ns nonzero, must be at least 1 */ + cclocks = 1; + return cclocks; +} + +/* + * Convert a cclock count to nanoseconds. Not matter how slow + * the cclock, a non-zero cclocks will always have a non-zero result. + */ +u32 cclock_to_ns(struct hfi1_devdata *dd, u32 cclocks) +{ + u32 ns; + + if (dd->icode == ICODE_FPGA_EMULATION) + ns = (cclocks * FPGA_CCLOCK_PS) / 1000; + else /* simulation pretends to be ASIC */ + ns = (cclocks * ASIC_CCLOCK_PS) / 1000; + if (cclocks && !ns) + ns = 1; + return ns; +} + +/* + * Dynamically adjust the receive interrupt timeout for a context based on + * incoming packet rate. + * + * NOTE: Dynamic adjustment does not allow rcv_intr_count to be zero. + */ +static void adjust_rcv_timeout(struct hfi1_ctxtdata *rcd, u32 npkts) +{ + struct hfi1_devdata *dd = rcd->dd; + u32 timeout = rcd->rcvavail_timeout; + + /* + * This algorithm doubles or halves the timeout depending on whether + * the number of packets received in this interrupt were less than or + * greater equal the interrupt count. + * + * The calculations below do not allow a steady state to be achieved. + * Only at the endpoints it is possible to have an unchanging + * timeout. + */ + if (npkts < rcv_intr_count) { + /* + * Not enough packets arrived before the timeout, adjust + * timeout downward. + */ + if (timeout < 2) /* already at minimum? */ + return; + timeout >>= 1; + } else { + /* + * More than enough packets arrived before the timeout, adjust + * timeout upward. + */ + if (timeout >= dd->rcv_intr_timeout_csr) /* already at max? */ + return; + timeout = min(timeout << 1, dd->rcv_intr_timeout_csr); + } + + rcd->rcvavail_timeout = timeout; + /* timeout cannot be larger than rcv_intr_timeout_csr which has already + been verified to be in range */ + write_kctxt_csr(dd, rcd->ctxt, RCV_AVAIL_TIME_OUT, + (u64)timeout << RCV_AVAIL_TIME_OUT_TIME_OUT_RELOAD_SHIFT); +} + +void update_usrhead(struct hfi1_ctxtdata *rcd, u32 hd, u32 updegr, u32 egrhd, + u32 intr_adjust, u32 npkts) +{ + struct hfi1_devdata *dd = rcd->dd; + u64 reg; + u32 ctxt = rcd->ctxt; + + /* + * Need to write timeout register before updating RcvHdrHead to ensure + * that a new value is used when the HW decides to restart counting. + */ + if (intr_adjust) + adjust_rcv_timeout(rcd, npkts); + if (updegr) { + reg = (egrhd & RCV_EGR_INDEX_HEAD_HEAD_MASK) + << RCV_EGR_INDEX_HEAD_HEAD_SHIFT; + write_uctxt_csr(dd, ctxt, RCV_EGR_INDEX_HEAD, reg); + } + mmiowb(); + reg = ((u64)rcv_intr_count << RCV_HDR_HEAD_COUNTER_SHIFT) | + (((u64)hd & RCV_HDR_HEAD_HEAD_MASK) + << RCV_HDR_HEAD_HEAD_SHIFT); + write_uctxt_csr(dd, ctxt, RCV_HDR_HEAD, reg); + mmiowb(); +} + +u32 hdrqempty(struct hfi1_ctxtdata *rcd) +{ + u32 head, tail; + + head = (read_uctxt_csr(rcd->dd, rcd->ctxt, RCV_HDR_HEAD) + & RCV_HDR_HEAD_HEAD_SMASK) >> RCV_HDR_HEAD_HEAD_SHIFT; + + if (rcd->rcvhdrtail_kvaddr) + tail = get_rcvhdrtail(rcd); + else + tail = read_uctxt_csr(rcd->dd, rcd->ctxt, RCV_HDR_TAIL); + + return head == tail; +} + +/* + * Context Control and Receive Array encoding for buffer size: + * 0x0 invalid + * 0x1 4 KB + * 0x2 8 KB + * 0x3 16 KB + * 0x4 32 KB + * 0x5 64 KB + * 0x6 128 KB + * 0x7 256 KB + * 0x8 512 KB (Receive Array only) + * 0x9 1 MB (Receive Array only) + * 0xa 2 MB (Receive Array only) + * + * 0xB-0xF - reserved (Receive Array only) + * + * + * This routine assumes that the value has already been sanity checked. + */ +static u32 encoded_size(u32 size) +{ + switch (size) { + case 4*1024: return 0x1; + case 8*1024: return 0x2; + case 16*1024: return 0x3; + case 32*1024: return 0x4; + case 64*1024: return 0x5; + case 128*1024: return 0x6; + case 256*1024: return 0x7; + case 512*1024: return 0x8; + case 1*1024*1024: return 0x9; + case 2*1024*1024: return 0xa; + } + return 0x1; /* if invalid, go with the minimum size */ +} + +void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt) +{ + struct hfi1_ctxtdata *rcd; + u64 rcvctrl, reg; + int did_enable = 0; + + rcd = dd->rcd[ctxt]; + if (!rcd) + return; + + hfi1_cdbg(RCVCTRL, "ctxt %d op 0x%x", ctxt, op); + + rcvctrl = read_kctxt_csr(dd, ctxt, RCV_CTXT_CTRL); + /* if the context already enabled, don't do the extra steps */ + if ((op & HFI1_RCVCTRL_CTXT_ENB) + && !(rcvctrl & RCV_CTXT_CTRL_ENABLE_SMASK)) { + /* reset the tail and hdr addresses, and sequence count */ + write_kctxt_csr(dd, ctxt, RCV_HDR_ADDR, + rcd->rcvhdrq_phys); + if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) + write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR, + rcd->rcvhdrqtailaddr_phys); + rcd->seq_cnt = 1; + + /* reset the cached receive header queue head value */ + rcd->head = 0; + + /* + * Zero the receive header queue so we don't get false + * positives when checking the sequence number. The + * sequence numbers could land exactly on the same spot. + * E.g. a rcd restart before the receive header wrapped. + */ + memset(rcd->rcvhdrq, 0, rcd->rcvhdrq_size); + + /* starting timeout */ + rcd->rcvavail_timeout = dd->rcv_intr_timeout_csr; + + /* enable the context */ + rcvctrl |= RCV_CTXT_CTRL_ENABLE_SMASK; + + /* clean the egr buffer size first */ + rcvctrl &= ~RCV_CTXT_CTRL_EGR_BUF_SIZE_SMASK; + rcvctrl |= ((u64)encoded_size(rcd->egrbufs.rcvtid_size) + & RCV_CTXT_CTRL_EGR_BUF_SIZE_MASK) + << RCV_CTXT_CTRL_EGR_BUF_SIZE_SHIFT; + + /* zero RcvHdrHead - set RcvHdrHead.Counter after enable */ + write_uctxt_csr(dd, ctxt, RCV_HDR_HEAD, 0); + did_enable = 1; + + /* zero RcvEgrIndexHead */ + write_uctxt_csr(dd, ctxt, RCV_EGR_INDEX_HEAD, 0); + + /* set eager count and base index */ + reg = (((u64)(rcd->egrbufs.alloced >> RCV_SHIFT) + & RCV_EGR_CTRL_EGR_CNT_MASK) + << RCV_EGR_CTRL_EGR_CNT_SHIFT) | + (((rcd->eager_base >> RCV_SHIFT) + & RCV_EGR_CTRL_EGR_BASE_INDEX_MASK) + << RCV_EGR_CTRL_EGR_BASE_INDEX_SHIFT); + write_kctxt_csr(dd, ctxt, RCV_EGR_CTRL, reg); + + /* + * Set TID (expected) count and base index. + * rcd->expected_count is set to individual RcvArray entries, + * not pairs, and the CSR takes a pair-count in groups of + * four, so divide by 8. + */ + reg = (((rcd->expected_count >> RCV_SHIFT) + & RCV_TID_CTRL_TID_PAIR_CNT_MASK) + << RCV_TID_CTRL_TID_PAIR_CNT_SHIFT) | + (((rcd->expected_base >> RCV_SHIFT) + & RCV_TID_CTRL_TID_BASE_INDEX_MASK) + << RCV_TID_CTRL_TID_BASE_INDEX_SHIFT); + write_kctxt_csr(dd, ctxt, RCV_TID_CTRL, reg); + if (ctxt == VL15CTXT) + write_csr(dd, RCV_VL15, VL15CTXT); + } + if (op & HFI1_RCVCTRL_CTXT_DIS) { + write_csr(dd, RCV_VL15, 0); + rcvctrl &= ~RCV_CTXT_CTRL_ENABLE_SMASK; + } + if (op & HFI1_RCVCTRL_INTRAVAIL_ENB) + rcvctrl |= RCV_CTXT_CTRL_INTR_AVAIL_SMASK; + if (op & HFI1_RCVCTRL_INTRAVAIL_DIS) + rcvctrl &= ~RCV_CTXT_CTRL_INTR_AVAIL_SMASK; + if (op & HFI1_RCVCTRL_TAILUPD_ENB && rcd->rcvhdrqtailaddr_phys) + rcvctrl |= RCV_CTXT_CTRL_TAIL_UPD_SMASK; + if (op & HFI1_RCVCTRL_TAILUPD_DIS) + rcvctrl &= ~RCV_CTXT_CTRL_TAIL_UPD_SMASK; + if (op & HFI1_RCVCTRL_TIDFLOW_ENB) + rcvctrl |= RCV_CTXT_CTRL_TID_FLOW_ENABLE_SMASK; + if (op & HFI1_RCVCTRL_TIDFLOW_DIS) + rcvctrl &= ~RCV_CTXT_CTRL_TID_FLOW_ENABLE_SMASK; + if (op & HFI1_RCVCTRL_ONE_PKT_EGR_ENB) { + /* In one-packet-per-eager mode, the size comes from + the RcvArray entry. */ + rcvctrl &= ~RCV_CTXT_CTRL_EGR_BUF_SIZE_SMASK; + rcvctrl |= RCV_CTXT_CTRL_ONE_PACKET_PER_EGR_BUFFER_SMASK; + } + if (op & HFI1_RCVCTRL_ONE_PKT_EGR_DIS) + rcvctrl &= ~RCV_CTXT_CTRL_ONE_PACKET_PER_EGR_BUFFER_SMASK; + if (op & HFI1_RCVCTRL_NO_RHQ_DROP_ENB) + rcvctrl |= RCV_CTXT_CTRL_DONT_DROP_RHQ_FULL_SMASK; + if (op & HFI1_RCVCTRL_NO_RHQ_DROP_DIS) + rcvctrl &= ~RCV_CTXT_CTRL_DONT_DROP_RHQ_FULL_SMASK; + if (op & HFI1_RCVCTRL_NO_EGR_DROP_ENB) + rcvctrl |= RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK; + if (op & HFI1_RCVCTRL_NO_EGR_DROP_DIS) + rcvctrl &= ~RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK; + rcd->rcvctrl = rcvctrl; + hfi1_cdbg(RCVCTRL, "ctxt %d rcvctrl 0x%llx\n", ctxt, rcvctrl); + write_kctxt_csr(dd, ctxt, RCV_CTXT_CTRL, rcd->rcvctrl); + + /* work around sticky RcvCtxtStatus.BlockedRHQFull */ + if (did_enable + && (rcvctrl & RCV_CTXT_CTRL_DONT_DROP_RHQ_FULL_SMASK)) { + reg = read_kctxt_csr(dd, ctxt, RCV_CTXT_STATUS); + if (reg != 0) { + dd_dev_info(dd, "ctxt %d status %lld (blocked)\n", + ctxt, reg); + read_uctxt_csr(dd, ctxt, RCV_HDR_HEAD); + write_uctxt_csr(dd, ctxt, RCV_HDR_HEAD, 0x10); + write_uctxt_csr(dd, ctxt, RCV_HDR_HEAD, 0x00); + read_uctxt_csr(dd, ctxt, RCV_HDR_HEAD); + reg = read_kctxt_csr(dd, ctxt, RCV_CTXT_STATUS); + dd_dev_info(dd, "ctxt %d status %lld (%s blocked)\n", + ctxt, reg, reg == 0 ? "not" : "still"); + } + } + + if (did_enable) { + /* + * The interrupt timeout and count must be set after + * the context is enabled to take effect. + */ + /* set interrupt timeout */ + write_kctxt_csr(dd, ctxt, RCV_AVAIL_TIME_OUT, + (u64)rcd->rcvavail_timeout << + RCV_AVAIL_TIME_OUT_TIME_OUT_RELOAD_SHIFT); + + /* set RcvHdrHead.Counter, zero RcvHdrHead.Head (again) */ + reg = (u64)rcv_intr_count << RCV_HDR_HEAD_COUNTER_SHIFT; + write_uctxt_csr(dd, ctxt, RCV_HDR_HEAD, reg); + } + + if (op & (HFI1_RCVCTRL_TAILUPD_DIS | HFI1_RCVCTRL_CTXT_DIS)) + /* + * If the context has been disabled and the Tail Update has + * been cleared, clear the RCV_HDR_TAIL_ADDR CSR so + * it doesn't contain an address that is invalid. + */ + write_kctxt_csr(dd, ctxt, RCV_HDR_TAIL_ADDR, 0); +} + +u32 hfi1_read_cntrs(struct hfi1_devdata *dd, loff_t pos, char **namep, + u64 **cntrp) +{ + int ret; + u64 val = 0; + + if (namep) { + ret = dd->cntrnameslen; + if (pos != 0) { + dd_dev_err(dd, "read_cntrs does not support indexing"); + return 0; + } + *namep = dd->cntrnames; + } else { + const struct cntr_entry *entry; + int i, j; + + ret = (dd->ndevcntrs) * sizeof(u64); + if (pos != 0) { + dd_dev_err(dd, "read_cntrs does not support indexing"); + return 0; + } + + /* Get the start of the block of counters */ + *cntrp = dd->cntrs; + + /* + * Now go and fill in each counter in the block. + */ + for (i = 0; i < DEV_CNTR_LAST; i++) { + entry = &dev_cntrs[i]; + hfi1_cdbg(CNTR, "reading %s", entry->name); + if (entry->flags & CNTR_DISABLED) { + /* Nothing */ + hfi1_cdbg(CNTR, "\tDisabled\n"); + } else { + if (entry->flags & CNTR_VL) { + hfi1_cdbg(CNTR, "\tPer VL\n"); + for (j = 0; j < C_VL_COUNT; j++) { + val = entry->rw_cntr(entry, + dd, j, + CNTR_MODE_R, + 0); + hfi1_cdbg( + CNTR, + "\t\tRead 0x%llx for %d\n", + val, j); + dd->cntrs[entry->offset + j] = + val; + } + } else { + val = entry->rw_cntr(entry, dd, + CNTR_INVALID_VL, + CNTR_MODE_R, 0); + dd->cntrs[entry->offset] = val; + hfi1_cdbg(CNTR, "\tRead 0x%llx", val); + } + } + } + } + return ret; +} + +/* + * Used by sysfs to create files for hfi stats to read + */ +u32 hfi1_read_portcntrs(struct hfi1_devdata *dd, loff_t pos, u32 port, + char **namep, u64 **cntrp) +{ + int ret; + u64 val = 0; + + if (namep) { + ret = dd->portcntrnameslen; + if (pos != 0) { + dd_dev_err(dd, "index not supported"); + return 0; + } + *namep = dd->portcntrnames; + } else { + const struct cntr_entry *entry; + struct hfi1_pportdata *ppd; + int i, j; + + ret = (dd->nportcntrs) * sizeof(u64); + if (pos != 0) { + dd_dev_err(dd, "indexing not supported"); + return 0; + } + ppd = (struct hfi1_pportdata *)(dd + 1 + port); + *cntrp = ppd->cntrs; + + for (i = 0; i < PORT_CNTR_LAST; i++) { + entry = &port_cntrs[i]; + hfi1_cdbg(CNTR, "reading %s", entry->name); + if (entry->flags & CNTR_DISABLED) { + /* Nothing */ + hfi1_cdbg(CNTR, "\tDisabled\n"); + continue; + } + + if (entry->flags & CNTR_VL) { + hfi1_cdbg(CNTR, "\tPer VL"); + for (j = 0; j < C_VL_COUNT; j++) { + val = entry->rw_cntr(entry, ppd, j, + CNTR_MODE_R, + 0); + hfi1_cdbg( + CNTR, + "\t\tRead 0x%llx for %d", + val, j); + ppd->cntrs[entry->offset + j] = val; + } + } else { + val = entry->rw_cntr(entry, ppd, + CNTR_INVALID_VL, + CNTR_MODE_R, + 0); + ppd->cntrs[entry->offset] = val; + hfi1_cdbg(CNTR, "\tRead 0x%llx", val); + } + } + } + return ret; +} + +static void free_cntrs(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd; + int i; + + if (dd->synth_stats_timer.data) + del_timer_sync(&dd->synth_stats_timer); + dd->synth_stats_timer.data = 0; + ppd = (struct hfi1_pportdata *)(dd + 1); + for (i = 0; i < dd->num_pports; i++, ppd++) { + kfree(ppd->cntrs); + kfree(ppd->scntrs); + free_percpu(ppd->ibport_data.rc_acks); + free_percpu(ppd->ibport_data.rc_qacks); + free_percpu(ppd->ibport_data.rc_delayed_comp); + ppd->cntrs = NULL; + ppd->scntrs = NULL; + ppd->ibport_data.rc_acks = NULL; + ppd->ibport_data.rc_qacks = NULL; + ppd->ibport_data.rc_delayed_comp = NULL; + } + kfree(dd->portcntrnames); + dd->portcntrnames = NULL; + kfree(dd->cntrs); + dd->cntrs = NULL; + kfree(dd->scntrs); + dd->scntrs = NULL; + kfree(dd->cntrnames); + dd->cntrnames = NULL; +} + +#define CNTR_MAX 0xFFFFFFFFFFFFFFFFULL +#define CNTR_32BIT_MAX 0x00000000FFFFFFFF + +static u64 read_dev_port_cntr(struct hfi1_devdata *dd, struct cntr_entry *entry, + u64 *psval, void *context, int vl) +{ + u64 val; + u64 sval = *psval; + + if (entry->flags & CNTR_DISABLED) { + dd_dev_err(dd, "Counter %s not enabled", entry->name); + return 0; + } + + hfi1_cdbg(CNTR, "cntr: %s vl %d psval 0x%llx", entry->name, vl, *psval); + + val = entry->rw_cntr(entry, context, vl, CNTR_MODE_R, 0); + + /* If its a synthetic counter there is more work we need to do */ + if (entry->flags & CNTR_SYNTH) { + if (sval == CNTR_MAX) { + /* No need to read already saturated */ + return CNTR_MAX; + } + + if (entry->flags & CNTR_32BIT) { + /* 32bit counters can wrap multiple times */ + u64 upper = sval >> 32; + u64 lower = (sval << 32) >> 32; + + if (lower > val) { /* hw wrapped */ + if (upper == CNTR_32BIT_MAX) + val = CNTR_MAX; + else + upper++; + } + + if (val != CNTR_MAX) + val = (upper << 32) | val; + + } else { + /* If we rolled we are saturated */ + if ((val < sval) || (val > CNTR_MAX)) + val = CNTR_MAX; + } + } + + *psval = val; + + hfi1_cdbg(CNTR, "\tNew val=0x%llx", val); + + return val; +} + +static u64 write_dev_port_cntr(struct hfi1_devdata *dd, + struct cntr_entry *entry, + u64 *psval, void *context, int vl, u64 data) +{ + u64 val; + + if (entry->flags & CNTR_DISABLED) { + dd_dev_err(dd, "Counter %s not enabled", entry->name); + return 0; + } + + hfi1_cdbg(CNTR, "cntr: %s vl %d psval 0x%llx", entry->name, vl, *psval); + + if (entry->flags & CNTR_SYNTH) { + *psval = data; + if (entry->flags & CNTR_32BIT) { + val = entry->rw_cntr(entry, context, vl, CNTR_MODE_W, + (data << 32) >> 32); + val = data; /* return the full 64bit value */ + } else { + val = entry->rw_cntr(entry, context, vl, CNTR_MODE_W, + data); + } + } else { + val = entry->rw_cntr(entry, context, vl, CNTR_MODE_W, data); + } + + *psval = val; + + hfi1_cdbg(CNTR, "\tNew val=0x%llx", val); + + return val; +} + +u64 read_dev_cntr(struct hfi1_devdata *dd, int index, int vl) +{ + struct cntr_entry *entry; + u64 *sval; + + entry = &dev_cntrs[index]; + sval = dd->scntrs + entry->offset; + + if (vl != CNTR_INVALID_VL) + sval += vl; + + return read_dev_port_cntr(dd, entry, sval, dd, vl); +} + +u64 write_dev_cntr(struct hfi1_devdata *dd, int index, int vl, u64 data) +{ + struct cntr_entry *entry; + u64 *sval; + + entry = &dev_cntrs[index]; + sval = dd->scntrs + entry->offset; + + if (vl != CNTR_INVALID_VL) + sval += vl; + + return write_dev_port_cntr(dd, entry, sval, dd, vl, data); +} + +u64 read_port_cntr(struct hfi1_pportdata *ppd, int index, int vl) +{ + struct cntr_entry *entry; + u64 *sval; + + entry = &port_cntrs[index]; + sval = ppd->scntrs + entry->offset; + + if (vl != CNTR_INVALID_VL) + sval += vl; + + if ((index >= C_RCV_HDR_OVF_FIRST + ppd->dd->num_rcv_contexts) && + (index <= C_RCV_HDR_OVF_LAST)) { + /* We do not want to bother for disabled contexts */ + return 0; + } + + return read_dev_port_cntr(ppd->dd, entry, sval, ppd, vl); +} + +u64 write_port_cntr(struct hfi1_pportdata *ppd, int index, int vl, u64 data) +{ + struct cntr_entry *entry; + u64 *sval; + + entry = &port_cntrs[index]; + sval = ppd->scntrs + entry->offset; + + if (vl != CNTR_INVALID_VL) + sval += vl; + + if ((index >= C_RCV_HDR_OVF_FIRST + ppd->dd->num_rcv_contexts) && + (index <= C_RCV_HDR_OVF_LAST)) { + /* We do not want to bother for disabled contexts */ + return 0; + } + + return write_dev_port_cntr(ppd->dd, entry, sval, ppd, vl, data); +} + +static void update_synth_timer(unsigned long opaque) +{ + u64 cur_tx; + u64 cur_rx; + u64 total_flits; + u8 update = 0; + int i, j, vl; + struct hfi1_pportdata *ppd; + struct cntr_entry *entry; + + struct hfi1_devdata *dd = (struct hfi1_devdata *)opaque; + + /* + * Rather than keep beating on the CSRs pick a minimal set that we can + * check to watch for potential roll over. We can do this by looking at + * the number of flits sent/recv. If the total flits exceeds 32bits then + * we have to iterate all the counters and update. + */ + entry = &dev_cntrs[C_DC_RCV_FLITS]; + cur_rx = entry->rw_cntr(entry, dd, CNTR_INVALID_VL, CNTR_MODE_R, 0); + + entry = &dev_cntrs[C_DC_XMIT_FLITS]; + cur_tx = entry->rw_cntr(entry, dd, CNTR_INVALID_VL, CNTR_MODE_R, 0); + + hfi1_cdbg( + CNTR, + "[%d] curr tx=0x%llx rx=0x%llx :: last tx=0x%llx rx=0x%llx\n", + dd->unit, cur_tx, cur_rx, dd->last_tx, dd->last_rx); + + if ((cur_tx < dd->last_tx) || (cur_rx < dd->last_rx)) { + /* + * May not be strictly necessary to update but it won't hurt and + * simplifies the logic here. + */ + update = 1; + hfi1_cdbg(CNTR, "[%d] Tripwire counter rolled, updating", + dd->unit); + } else { + total_flits = (cur_tx - dd->last_tx) + (cur_rx - dd->last_rx); + hfi1_cdbg(CNTR, + "[%d] total flits 0x%llx limit 0x%llx\n", dd->unit, + total_flits, (u64)CNTR_32BIT_MAX); + if (total_flits >= CNTR_32BIT_MAX) { + hfi1_cdbg(CNTR, "[%d] 32bit limit hit, updating", + dd->unit); + update = 1; + } + } + + if (update) { + hfi1_cdbg(CNTR, "[%d] Updating dd and ppd counters", dd->unit); + for (i = 0; i < DEV_CNTR_LAST; i++) { + entry = &dev_cntrs[i]; + if (entry->flags & CNTR_VL) { + for (vl = 0; vl < C_VL_COUNT; vl++) + read_dev_cntr(dd, i, vl); + } else { + read_dev_cntr(dd, i, CNTR_INVALID_VL); + } + } + ppd = (struct hfi1_pportdata *)(dd + 1); + for (i = 0; i < dd->num_pports; i++, ppd++) { + for (j = 0; j < PORT_CNTR_LAST; j++) { + entry = &port_cntrs[j]; + if (entry->flags & CNTR_VL) { + for (vl = 0; vl < C_VL_COUNT; vl++) + read_port_cntr(ppd, j, vl); + } else { + read_port_cntr(ppd, j, CNTR_INVALID_VL); + } + } + } + + /* + * We want the value in the register. The goal is to keep track + * of the number of "ticks" not the counter value. In other + * words if the register rolls we want to notice it and go ahead + * and force an update. + */ + entry = &dev_cntrs[C_DC_XMIT_FLITS]; + dd->last_tx = entry->rw_cntr(entry, dd, CNTR_INVALID_VL, + CNTR_MODE_R, 0); + + entry = &dev_cntrs[C_DC_RCV_FLITS]; + dd->last_rx = entry->rw_cntr(entry, dd, CNTR_INVALID_VL, + CNTR_MODE_R, 0); + + hfi1_cdbg(CNTR, "[%d] setting last tx/rx to 0x%llx 0x%llx", + dd->unit, dd->last_tx, dd->last_rx); + + } else { + hfi1_cdbg(CNTR, "[%d] No update necessary", dd->unit); + } + +mod_timer(&dd->synth_stats_timer, jiffies + HZ * SYNTH_CNT_TIME); +} + +#define C_MAX_NAME 13 /* 12 chars + one for /0 */ +static int init_cntrs(struct hfi1_devdata *dd) +{ + int i, rcv_ctxts, index, j; + size_t sz; + char *p; + char name[C_MAX_NAME]; + struct hfi1_pportdata *ppd; + + /* set up the stats timer; the add_timer is done at the end */ + init_timer(&dd->synth_stats_timer); + dd->synth_stats_timer.function = update_synth_timer; + dd->synth_stats_timer.data = (unsigned long) dd; + + /***********************/ + /* per device counters */ + /***********************/ + + /* size names and determine how many we have*/ + dd->ndevcntrs = 0; + sz = 0; + index = 0; + + for (i = 0; i < DEV_CNTR_LAST; i++) { + hfi1_dbg_early("Init cntr %s\n", dev_cntrs[i].name); + if (dev_cntrs[i].flags & CNTR_DISABLED) { + hfi1_dbg_early("\tSkipping %s\n", dev_cntrs[i].name); + continue; + } + + if (dev_cntrs[i].flags & CNTR_VL) { + hfi1_dbg_early("\tProcessing VL cntr\n"); + dev_cntrs[i].offset = index; + for (j = 0; j < C_VL_COUNT; j++) { + memset(name, '\0', C_MAX_NAME); + snprintf(name, C_MAX_NAME, "%s%d", + dev_cntrs[i].name, + vl_from_idx(j)); + sz += strlen(name); + sz++; + hfi1_dbg_early("\t\t%s\n", name); + dd->ndevcntrs++; + index++; + } + } else { + /* +1 for newline */ + sz += strlen(dev_cntrs[i].name) + 1; + dd->ndevcntrs++; + dev_cntrs[i].offset = index; + index++; + hfi1_dbg_early("\tAdding %s\n", dev_cntrs[i].name); + } + } + + /* allocate space for the counter values */ + dd->cntrs = kcalloc(index, sizeof(u64), GFP_KERNEL); + if (!dd->cntrs) + goto bail; + + dd->scntrs = kcalloc(index, sizeof(u64), GFP_KERNEL); + if (!dd->scntrs) + goto bail; + + + /* allocate space for the counter names */ + dd->cntrnameslen = sz; + dd->cntrnames = kmalloc(sz, GFP_KERNEL); + if (!dd->cntrnames) + goto bail; + + /* fill in the names */ + for (p = dd->cntrnames, i = 0, index = 0; i < DEV_CNTR_LAST; i++) { + if (dev_cntrs[i].flags & CNTR_DISABLED) { + /* Nothing */ + } else { + if (dev_cntrs[i].flags & CNTR_VL) { + for (j = 0; j < C_VL_COUNT; j++) { + memset(name, '\0', C_MAX_NAME); + snprintf(name, C_MAX_NAME, "%s%d", + dev_cntrs[i].name, + vl_from_idx(j)); + memcpy(p, name, strlen(name)); + p += strlen(name); + *p++ = '\n'; + } + } else { + memcpy(p, dev_cntrs[i].name, + strlen(dev_cntrs[i].name)); + p += strlen(dev_cntrs[i].name); + *p++ = '\n'; + } + index++; + } + } + + /*********************/ + /* per port counters */ + /*********************/ + + /* + * Go through the counters for the overflows and disable the ones we + * don't need. This varies based on platform so we need to do it + * dynamically here. + */ + rcv_ctxts = dd->num_rcv_contexts; + for (i = C_RCV_HDR_OVF_FIRST + rcv_ctxts; + i <= C_RCV_HDR_OVF_LAST; i++) { + port_cntrs[i].flags |= CNTR_DISABLED; + } + + /* size port counter names and determine how many we have*/ + sz = 0; + dd->nportcntrs = 0; + for (i = 0; i < PORT_CNTR_LAST; i++) { + hfi1_dbg_early("Init pcntr %s\n", port_cntrs[i].name); + if (port_cntrs[i].flags & CNTR_DISABLED) { + hfi1_dbg_early("\tSkipping %s\n", port_cntrs[i].name); + continue; + } + + if (port_cntrs[i].flags & CNTR_VL) { + hfi1_dbg_early("\tProcessing VL cntr\n"); + port_cntrs[i].offset = dd->nportcntrs; + for (j = 0; j < C_VL_COUNT; j++) { + memset(name, '\0', C_MAX_NAME); + snprintf(name, C_MAX_NAME, "%s%d", + port_cntrs[i].name, + vl_from_idx(j)); + sz += strlen(name); + sz++; + hfi1_dbg_early("\t\t%s\n", name); + dd->nportcntrs++; + } + } else { + /* +1 for newline */ + sz += strlen(port_cntrs[i].name) + 1; + port_cntrs[i].offset = dd->nportcntrs; + dd->nportcntrs++; + hfi1_dbg_early("\tAdding %s\n", port_cntrs[i].name); + } + } + + /* allocate space for the counter names */ + dd->portcntrnameslen = sz; + dd->portcntrnames = kmalloc(sz, GFP_KERNEL); + if (!dd->portcntrnames) + goto bail; + + /* fill in port cntr names */ + for (p = dd->portcntrnames, i = 0; i < PORT_CNTR_LAST; i++) { + if (port_cntrs[i].flags & CNTR_DISABLED) + continue; + + if (port_cntrs[i].flags & CNTR_VL) { + for (j = 0; j < C_VL_COUNT; j++) { + memset(name, '\0', C_MAX_NAME); + snprintf(name, C_MAX_NAME, "%s%d", + port_cntrs[i].name, + vl_from_idx(j)); + memcpy(p, name, strlen(name)); + p += strlen(name); + *p++ = '\n'; + } + } else { + memcpy(p, port_cntrs[i].name, + strlen(port_cntrs[i].name)); + p += strlen(port_cntrs[i].name); + *p++ = '\n'; + } + } + + /* allocate per port storage for counter values */ + ppd = (struct hfi1_pportdata *)(dd + 1); + for (i = 0; i < dd->num_pports; i++, ppd++) { + ppd->cntrs = kcalloc(dd->nportcntrs, sizeof(u64), GFP_KERNEL); + if (!ppd->cntrs) + goto bail; + + ppd->scntrs = kcalloc(dd->nportcntrs, sizeof(u64), GFP_KERNEL); + if (!ppd->scntrs) + goto bail; + } + + /* CPU counters need to be allocated and zeroed */ + if (init_cpu_counters(dd)) + goto bail; + + mod_timer(&dd->synth_stats_timer, jiffies + HZ * SYNTH_CNT_TIME); + return 0; +bail: + free_cntrs(dd); + return -ENOMEM; +} + + +static u32 chip_to_opa_lstate(struct hfi1_devdata *dd, u32 chip_lstate) +{ + switch (chip_lstate) { + default: + dd_dev_err(dd, + "Unknown logical state 0x%x, reporting IB_PORT_DOWN\n", + chip_lstate); + /* fall through */ + case LSTATE_DOWN: + return IB_PORT_DOWN; + case LSTATE_INIT: + return IB_PORT_INIT; + case LSTATE_ARMED: + return IB_PORT_ARMED; + case LSTATE_ACTIVE: + return IB_PORT_ACTIVE; + } +} + +u32 chip_to_opa_pstate(struct hfi1_devdata *dd, u32 chip_pstate) +{ + /* look at the HFI meta-states only */ + switch (chip_pstate & 0xf0) { + default: + dd_dev_err(dd, "Unexpected chip physical state of 0x%x\n", + chip_pstate); + /* fall through */ + case PLS_DISABLED: + return IB_PORTPHYSSTATE_DISABLED; + case PLS_OFFLINE: + return OPA_PORTPHYSSTATE_OFFLINE; + case PLS_POLLING: + return IB_PORTPHYSSTATE_POLLING; + case PLS_CONFIGPHY: + return IB_PORTPHYSSTATE_TRAINING; + case PLS_LINKUP: + return IB_PORTPHYSSTATE_LINKUP; + case PLS_PHYTEST: + return IB_PORTPHYSSTATE_PHY_TEST; + } +} + +/* return the OPA port logical state name */ +const char *opa_lstate_name(u32 lstate) +{ + static const char * const port_logical_names[] = { + "PORT_NOP", + "PORT_DOWN", + "PORT_INIT", + "PORT_ARMED", + "PORT_ACTIVE", + "PORT_ACTIVE_DEFER", + }; + if (lstate < ARRAY_SIZE(port_logical_names)) + return port_logical_names[lstate]; + return "unknown"; +} + +/* return the OPA port physical state name */ +const char *opa_pstate_name(u32 pstate) +{ + static const char * const port_physical_names[] = { + "PHYS_NOP", + "reserved1", + "PHYS_POLL", + "PHYS_DISABLED", + "PHYS_TRAINING", + "PHYS_LINKUP", + "PHYS_LINK_ERR_RECOVER", + "PHYS_PHY_TEST", + "reserved8", + "PHYS_OFFLINE", + "PHYS_GANGED", + "PHYS_TEST", + }; + if (pstate < ARRAY_SIZE(port_physical_names)) + return port_physical_names[pstate]; + return "unknown"; +} + +/* + * Read the hardware link state and set the driver's cached value of it. + * Return the (new) current value. + */ +u32 get_logical_state(struct hfi1_pportdata *ppd) +{ + u32 new_state; + + new_state = chip_to_opa_lstate(ppd->dd, read_logical_state(ppd->dd)); + if (new_state != ppd->lstate) { + dd_dev_info(ppd->dd, "logical state changed to %s (0x%x)\n", + opa_lstate_name(new_state), new_state); + ppd->lstate = new_state; + } + /* + * Set port status flags in the page mapped into userspace + * memory. Do it here to ensure a reliable state - this is + * the only function called by all state handling code. + * Always set the flags due to the fact that the cache value + * might have been changed explicitly outside of this + * function. + */ + if (ppd->statusp) { + switch (ppd->lstate) { + case IB_PORT_DOWN: + case IB_PORT_INIT: + *ppd->statusp &= ~(HFI1_STATUS_IB_CONF | + HFI1_STATUS_IB_READY); + break; + case IB_PORT_ARMED: + *ppd->statusp |= HFI1_STATUS_IB_CONF; + break; + case IB_PORT_ACTIVE: + *ppd->statusp |= HFI1_STATUS_IB_READY; + break; + } + } + return ppd->lstate; +} + +/** + * wait_logical_linkstate - wait for an IB link state change to occur + * @ppd: port device + * @state: the state to wait for + * @msecs: the number of milliseconds to wait + * + * Wait up to msecs milliseconds for IB link state change to occur. + * For now, take the easy polling route. + * Returns 0 if state reached, otherwise -ETIMEDOUT. + */ +static int wait_logical_linkstate(struct hfi1_pportdata *ppd, u32 state, + int msecs) +{ + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(msecs); + while (1) { + if (get_logical_state(ppd) == state) + return 0; + if (time_after(jiffies, timeout)) + break; + msleep(20); + } + dd_dev_err(ppd->dd, "timeout waiting for link state 0x%x\n", state); + + return -ETIMEDOUT; +} + +u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd) +{ + static u32 remembered_state = 0xff; + u32 pstate; + u32 ib_pstate; + + pstate = read_physical_state(ppd->dd); + ib_pstate = chip_to_opa_pstate(ppd->dd, pstate); + if (remembered_state != ib_pstate) { + dd_dev_info(ppd->dd, + "%s: physical state changed to %s (0x%x), phy 0x%x\n", + __func__, opa_pstate_name(ib_pstate), ib_pstate, + pstate); + remembered_state = ib_pstate; + } + return ib_pstate; +} + +/* + * Read/modify/write ASIC_QSFP register bits as selected by mask + * data: 0 or 1 in the positions depending on what needs to be written + * dir: 0 for read, 1 for write + * mask: select by setting + * I2CCLK (bit 0) + * I2CDATA (bit 1) + */ +u64 hfi1_gpio_mod(struct hfi1_devdata *dd, u32 target, u32 data, u32 dir, + u32 mask) +{ + u64 qsfp_oe, target_oe; + + target_oe = target ? ASIC_QSFP2_OE : ASIC_QSFP1_OE; + if (mask) { + /* We are writing register bits, so lock access */ + dir &= mask; + data &= mask; + + qsfp_oe = read_csr(dd, target_oe); + qsfp_oe = (qsfp_oe & ~(u64)mask) | (u64)dir; + write_csr(dd, target_oe, qsfp_oe); + } + /* We are exclusively reading bits here, but it is unlikely + * we'll get valid data when we set the direction of the pin + * in the same call, so read should call this function again + * to get valid data + */ + return read_csr(dd, target ? ASIC_QSFP2_IN : ASIC_QSFP1_IN); +} + +#define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ +(r &= ~SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) + +#define SET_STATIC_RATE_CONTROL_SMASK(r) \ +(r |= SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) + +int hfi1_init_ctxt(struct send_context *sc) +{ + if (sc != NULL) { + struct hfi1_devdata *dd = sc->dd; + u64 reg; + u8 set = (sc->type == SC_USER ? + HFI1_CAP_IS_USET(STATIC_RATE_CTRL) : + HFI1_CAP_IS_KSET(STATIC_RATE_CTRL)); + reg = read_kctxt_csr(dd, sc->hw_context, + SEND_CTXT_CHECK_ENABLE); + if (set) + CLEAR_STATIC_RATE_CONTROL_SMASK(reg); + else + SET_STATIC_RATE_CONTROL_SMASK(reg); + write_kctxt_csr(dd, sc->hw_context, + SEND_CTXT_CHECK_ENABLE, reg); + } + return 0; +} + +int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp) +{ + int ret = 0; + u64 reg; + + if (dd->icode != ICODE_RTL_SILICON) { + if (HFI1_CAP_IS_KSET(PRINT_UNIMPL)) + dd_dev_info(dd, "%s: tempsense not supported by HW\n", + __func__); + return -EINVAL; + } + reg = read_csr(dd, ASIC_STS_THERM); + temp->curr = ((reg >> ASIC_STS_THERM_CURR_TEMP_SHIFT) & + ASIC_STS_THERM_CURR_TEMP_MASK); + temp->lo_lim = ((reg >> ASIC_STS_THERM_LO_TEMP_SHIFT) & + ASIC_STS_THERM_LO_TEMP_MASK); + temp->hi_lim = ((reg >> ASIC_STS_THERM_HI_TEMP_SHIFT) & + ASIC_STS_THERM_HI_TEMP_MASK); + temp->crit_lim = ((reg >> ASIC_STS_THERM_CRIT_TEMP_SHIFT) & + ASIC_STS_THERM_CRIT_TEMP_MASK); + /* triggers is a 3-bit value - 1 bit per trigger. */ + temp->triggers = (u8)((reg >> ASIC_STS_THERM_LOW_SHIFT) & 0x7); + + return ret; +} + +/* ========================================================================= */ + +/* + * Enable/disable chip from delivering interrupts. + */ +void set_intr_state(struct hfi1_devdata *dd, u32 enable) +{ + int i; + + /* + * In HFI, the mask needs to be 1 to allow interrupts. + */ + if (enable) { + u64 cce_int_mask; + const int qsfp1_int_smask = QSFP1_INT % 64; + const int qsfp2_int_smask = QSFP2_INT % 64; + + /* enable all interrupts */ + for (i = 0; i < CCE_NUM_INT_CSRS; i++) + write_csr(dd, CCE_INT_MASK + (8*i), ~(u64)0); + + /* + * disable QSFP1 interrupts for HFI1, QSFP2 interrupts for HFI0 + * Qsfp1Int and Qsfp2Int are adjacent bits in the same CSR, + * therefore just one of QSFP1_INT/QSFP2_INT can be used to find + * the index of the appropriate CSR in the CCEIntMask CSR array + */ + cce_int_mask = read_csr(dd, CCE_INT_MASK + + (8*(QSFP1_INT/64))); + if (dd->hfi1_id) { + cce_int_mask &= ~((u64)1 << qsfp1_int_smask); + write_csr(dd, CCE_INT_MASK + (8*(QSFP1_INT/64)), + cce_int_mask); + } else { + cce_int_mask &= ~((u64)1 << qsfp2_int_smask); + write_csr(dd, CCE_INT_MASK + (8*(QSFP2_INT/64)), + cce_int_mask); + } + } else { + for (i = 0; i < CCE_NUM_INT_CSRS; i++) + write_csr(dd, CCE_INT_MASK + (8*i), 0ull); + } +} + +/* + * Clear all interrupt sources on the chip. + */ +static void clear_all_interrupts(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < CCE_NUM_INT_CSRS; i++) + write_csr(dd, CCE_INT_CLEAR + (8*i), ~(u64)0); + + write_csr(dd, CCE_ERR_CLEAR, ~(u64)0); + write_csr(dd, MISC_ERR_CLEAR, ~(u64)0); + write_csr(dd, RCV_ERR_CLEAR, ~(u64)0); + write_csr(dd, SEND_ERR_CLEAR, ~(u64)0); + write_csr(dd, SEND_PIO_ERR_CLEAR, ~(u64)0); + write_csr(dd, SEND_DMA_ERR_CLEAR, ~(u64)0); + write_csr(dd, SEND_EGRESS_ERR_CLEAR, ~(u64)0); + for (i = 0; i < dd->chip_send_contexts; i++) + write_kctxt_csr(dd, i, SEND_CTXT_ERR_CLEAR, ~(u64)0); + for (i = 0; i < dd->chip_sdma_engines; i++) + write_kctxt_csr(dd, i, SEND_DMA_ENG_ERR_CLEAR, ~(u64)0); + + write_csr(dd, DCC_ERR_FLG_CLR, ~(u64)0); + write_csr(dd, DC_LCB_ERR_CLR, ~(u64)0); + write_csr(dd, DC_DC8051_ERR_CLR, ~(u64)0); +} + +/* Move to pcie.c? */ +static void disable_intx(struct pci_dev *pdev) +{ + pci_intx(pdev, 0); +} + +static void clean_up_interrupts(struct hfi1_devdata *dd) +{ + int i; + + /* remove irqs - must happen before disabling/turning off */ + if (dd->num_msix_entries) { + /* MSI-X */ + struct hfi1_msix_entry *me = dd->msix_entries; + + for (i = 0; i < dd->num_msix_entries; i++, me++) { + if (me->arg == NULL) /* => no irq, no affinity */ + break; + irq_set_affinity_hint(dd->msix_entries[i].msix.vector, + NULL); + free_irq(me->msix.vector, me->arg); + } + } else { + /* INTx */ + if (dd->requested_intx_irq) { + free_irq(dd->pcidev->irq, dd); + dd->requested_intx_irq = 0; + } + } + + /* turn off interrupts */ + if (dd->num_msix_entries) { + /* MSI-X */ + hfi1_nomsix(dd); + } else { + /* INTx */ + disable_intx(dd->pcidev); + } + + /* clean structures */ + for (i = 0; i < dd->num_msix_entries; i++) + free_cpumask_var(dd->msix_entries[i].mask); + kfree(dd->msix_entries); + dd->msix_entries = NULL; + dd->num_msix_entries = 0; +} + +/* + * Remap the interrupt source from the general handler to the given MSI-X + * interrupt. + */ +static void remap_intr(struct hfi1_devdata *dd, int isrc, int msix_intr) +{ + u64 reg; + int m, n; + + /* clear from the handled mask of the general interrupt */ + m = isrc / 64; + n = isrc % 64; + dd->gi_mask[m] &= ~((u64)1 << n); + + /* direct the chip source to the given MSI-X interrupt */ + m = isrc / 8; + n = isrc % 8; + reg = read_csr(dd, CCE_INT_MAP + (8*m)); + reg &= ~((u64)0xff << (8*n)); + reg |= ((u64)msix_intr & 0xff) << (8*n); + write_csr(dd, CCE_INT_MAP + (8*m), reg); +} + +static void remap_sdma_interrupts(struct hfi1_devdata *dd, + int engine, int msix_intr) +{ + /* + * SDMA engine interrupt sources grouped by type, rather than + * engine. Per-engine interrupts are as follows: + * SDMA + * SDMAProgress + * SDMAIdle + */ + remap_intr(dd, IS_SDMA_START + 0*TXE_NUM_SDMA_ENGINES + engine, + msix_intr); + remap_intr(dd, IS_SDMA_START + 1*TXE_NUM_SDMA_ENGINES + engine, + msix_intr); + remap_intr(dd, IS_SDMA_START + 2*TXE_NUM_SDMA_ENGINES + engine, + msix_intr); +} + +static void remap_receive_available_interrupt(struct hfi1_devdata *dd, + int rx, int msix_intr) +{ + remap_intr(dd, IS_RCVAVAIL_START + rx, msix_intr); +} + +static int request_intx_irq(struct hfi1_devdata *dd) +{ + int ret; + + snprintf(dd->intx_name, sizeof(dd->intx_name), DRIVER_NAME"_%d", + dd->unit); + ret = request_irq(dd->pcidev->irq, general_interrupt, + IRQF_SHARED, dd->intx_name, dd); + if (ret) + dd_dev_err(dd, "unable to request INTx interrupt, err %d\n", + ret); + else + dd->requested_intx_irq = 1; + return ret; +} + +static int request_msix_irqs(struct hfi1_devdata *dd) +{ + const struct cpumask *local_mask; + cpumask_var_t def, rcv; + bool def_ret, rcv_ret; + int first_general, last_general; + int first_sdma, last_sdma; + int first_rx, last_rx; + int first_cpu, restart_cpu, curr_cpu; + int rcv_cpu, sdma_cpu; + int i, ret = 0, possible; + int ht; + + /* calculate the ranges we are going to use */ + first_general = 0; + first_sdma = last_general = first_general + 1; + first_rx = last_sdma = first_sdma + dd->num_sdma; + last_rx = first_rx + dd->n_krcv_queues; + + /* + * Interrupt affinity. + * + * non-rcv avail gets a default mask that + * starts as possible cpus with threads reset + * and each rcv avail reset. + * + * rcv avail gets node relative 1 wrapping back + * to the node relative 1 as necessary. + * + */ + local_mask = cpumask_of_pcibus(dd->pcidev->bus); + /* if first cpu is invalid, use NUMA 0 */ + if (cpumask_first(local_mask) >= nr_cpu_ids) + local_mask = topology_core_cpumask(0); + + def_ret = zalloc_cpumask_var(&def, GFP_KERNEL); + rcv_ret = zalloc_cpumask_var(&rcv, GFP_KERNEL); + if (!def_ret || !rcv_ret) + goto bail; + /* use local mask as default */ + cpumask_copy(def, local_mask); + possible = cpumask_weight(def); + /* disarm threads from default */ + ht = cpumask_weight( + topology_sibling_cpumask(cpumask_first(local_mask))); + for (i = possible/ht; i < possible; i++) + cpumask_clear_cpu(i, def); + /* reset possible */ + possible = cpumask_weight(def); + /* def now has full cores on chosen node*/ + first_cpu = cpumask_first(def); + if (nr_cpu_ids >= first_cpu) + first_cpu++; + restart_cpu = first_cpu; + curr_cpu = restart_cpu; + + for (i = first_cpu; i < dd->n_krcv_queues + first_cpu; i++) { + cpumask_clear_cpu(curr_cpu, def); + cpumask_set_cpu(curr_cpu, rcv); + if (curr_cpu >= possible) + curr_cpu = restart_cpu; + else + curr_cpu++; + } + /* def mask has non-rcv, rcv has recv mask */ + rcv_cpu = cpumask_first(rcv); + sdma_cpu = cpumask_first(def); + + /* + * Sanity check - the code expects all SDMA chip source + * interrupts to be in the same CSR, starting at bit 0. Verify + * that this is true by checking the bit location of the start. + */ + BUILD_BUG_ON(IS_SDMA_START % 64); + + for (i = 0; i < dd->num_msix_entries; i++) { + struct hfi1_msix_entry *me = &dd->msix_entries[i]; + const char *err_info; + irq_handler_t handler; + void *arg; + int idx; + struct hfi1_ctxtdata *rcd = NULL; + struct sdma_engine *sde = NULL; + + /* obtain the arguments to request_irq */ + if (first_general <= i && i < last_general) { + idx = i - first_general; + handler = general_interrupt; + arg = dd; + snprintf(me->name, sizeof(me->name), + DRIVER_NAME"_%d", dd->unit); + err_info = "general"; + } else if (first_sdma <= i && i < last_sdma) { + idx = i - first_sdma; + sde = &dd->per_sdma[idx]; + handler = sdma_interrupt; + arg = sde; + snprintf(me->name, sizeof(me->name), + DRIVER_NAME"_%d sdma%d", dd->unit, idx); + err_info = "sdma"; + remap_sdma_interrupts(dd, idx, i); + } else if (first_rx <= i && i < last_rx) { + idx = i - first_rx; + rcd = dd->rcd[idx]; + /* no interrupt if no rcd */ + if (!rcd) + continue; + /* + * Set the interrupt register and mask for this + * context's interrupt. + */ + rcd->ireg = (IS_RCVAVAIL_START+idx) / 64; + rcd->imask = ((u64)1) << + ((IS_RCVAVAIL_START+idx) % 64); + handler = receive_context_interrupt; + arg = rcd; + snprintf(me->name, sizeof(me->name), + DRIVER_NAME"_%d kctxt%d", dd->unit, idx); + err_info = "receive context"; + remap_receive_available_interrupt(dd, idx, i); + } else { + /* not in our expected range - complain, then + ignore it */ + dd_dev_err(dd, + "Unexpected extra MSI-X interrupt %d\n", i); + continue; + } + /* no argument, no interrupt */ + if (arg == NULL) + continue; + /* make sure the name is terminated */ + me->name[sizeof(me->name)-1] = 0; + + ret = request_irq(me->msix.vector, handler, 0, me->name, arg); + if (ret) { + dd_dev_err(dd, + "unable to allocate %s interrupt, vector %d, index %d, err %d\n", + err_info, me->msix.vector, idx, ret); + return ret; + } + /* + * assign arg after request_irq call, so it will be + * cleaned up + */ + me->arg = arg; + + if (!zalloc_cpumask_var( + &dd->msix_entries[i].mask, + GFP_KERNEL)) + goto bail; + if (handler == sdma_interrupt) { + dd_dev_info(dd, "sdma engine %d cpu %d\n", + sde->this_idx, sdma_cpu); + cpumask_set_cpu(sdma_cpu, dd->msix_entries[i].mask); + sdma_cpu = cpumask_next(sdma_cpu, def); + if (sdma_cpu >= nr_cpu_ids) + sdma_cpu = cpumask_first(def); + } else if (handler == receive_context_interrupt) { + dd_dev_info(dd, "rcv ctxt %d cpu %d\n", + rcd->ctxt, rcv_cpu); + cpumask_set_cpu(rcv_cpu, dd->msix_entries[i].mask); + rcv_cpu = cpumask_next(rcv_cpu, rcv); + if (rcv_cpu >= nr_cpu_ids) + rcv_cpu = cpumask_first(rcv); + } else { + /* otherwise first def */ + dd_dev_info(dd, "%s cpu %d\n", + err_info, cpumask_first(def)); + cpumask_set_cpu( + cpumask_first(def), dd->msix_entries[i].mask); + } + irq_set_affinity_hint( + dd->msix_entries[i].msix.vector, + dd->msix_entries[i].mask); + } + +out: + free_cpumask_var(def); + free_cpumask_var(rcv); + return ret; +bail: + ret = -ENOMEM; + goto out; +} + +/* + * Set the general handler to accept all interrupts, remap all + * chip interrupts back to MSI-X 0. + */ +static void reset_interrupts(struct hfi1_devdata *dd) +{ + int i; + + /* all interrupts handled by the general handler */ + for (i = 0; i < CCE_NUM_INT_CSRS; i++) + dd->gi_mask[i] = ~(u64)0; + + /* all chip interrupts map to MSI-X 0 */ + for (i = 0; i < CCE_NUM_INT_MAP_CSRS; i++) + write_csr(dd, CCE_INT_MAP + (8*i), 0); +} + +static int set_up_interrupts(struct hfi1_devdata *dd) +{ + struct hfi1_msix_entry *entries; + u32 total, request; + int i, ret; + int single_interrupt = 0; /* we expect to have all the interrupts */ + + /* + * Interrupt count: + * 1 general, "slow path" interrupt (includes the SDMA engines + * slow source, SDMACleanupDone) + * N interrupts - one per used SDMA engine + * M interrupt - one per kernel receive context + */ + total = 1 + dd->num_sdma + dd->n_krcv_queues; + + entries = kcalloc(total, sizeof(*entries), GFP_KERNEL); + if (!entries) { + dd_dev_err(dd, "cannot allocate msix table\n"); + ret = -ENOMEM; + goto fail; + } + /* 1-1 MSI-X entry assignment */ + for (i = 0; i < total; i++) + entries[i].msix.entry = i; + + /* ask for MSI-X interrupts */ + request = total; + request_msix(dd, &request, entries); + + if (request == 0) { + /* using INTx */ + /* dd->num_msix_entries already zero */ + kfree(entries); + single_interrupt = 1; + dd_dev_err(dd, "MSI-X failed, using INTx interrupts\n"); + } else { + /* using MSI-X */ + dd->num_msix_entries = request; + dd->msix_entries = entries; + + if (request != total) { + /* using MSI-X, with reduced interrupts */ + dd_dev_err( + dd, + "cannot handle reduced interrupt case, want %u, got %u\n", + total, request); + ret = -EINVAL; + goto fail; + } + dd_dev_info(dd, "%u MSI-X interrupts allocated\n", total); + } + + /* mask all interrupts */ + set_intr_state(dd, 0); + /* clear all pending interrupts */ + clear_all_interrupts(dd); + + /* reset general handler mask, chip MSI-X mappings */ + reset_interrupts(dd); + + if (single_interrupt) + ret = request_intx_irq(dd); + else + ret = request_msix_irqs(dd); + if (ret) + goto fail; + + return 0; + +fail: + clean_up_interrupts(dd); + return ret; +} + +/* + * Set up context values in dd. Sets: + * + * num_rcv_contexts - number of contexts being used + * n_krcv_queues - number of kernel contexts + * first_user_ctxt - first non-kernel context in array of contexts + * freectxts - number of free user contexts + * num_send_contexts - number of PIO send contexts being used + */ +static int set_up_context_variables(struct hfi1_devdata *dd) +{ + int num_kernel_contexts; + int num_user_contexts; + int total_contexts; + int ret; + unsigned ngroups; + + /* + * Kernel contexts: (to be fixed later): + * - min or 2 or 1 context/numa + * - Context 0 - default/errors + * - Context 1 - VL15 + */ + if (n_krcvqs) + num_kernel_contexts = n_krcvqs + MIN_KERNEL_KCTXTS; + else + num_kernel_contexts = num_online_nodes(); + num_kernel_contexts = + max_t(int, MIN_KERNEL_KCTXTS, num_kernel_contexts); + /* + * Every kernel receive context needs an ACK send context. + * one send context is allocated for each VL{0-7} and VL15 + */ + if (num_kernel_contexts > (dd->chip_send_contexts - num_vls - 1)) { + dd_dev_err(dd, + "Reducing # kernel rcv contexts to: %d, from %d\n", + (int)(dd->chip_send_contexts - num_vls - 1), + (int)num_kernel_contexts); + num_kernel_contexts = dd->chip_send_contexts - num_vls - 1; + } + /* + * User contexts: (to be fixed later) + * - set to num_rcv_contexts if non-zero + * - default to 1 user context per CPU + */ + if (num_rcv_contexts) + num_user_contexts = num_rcv_contexts; + else + num_user_contexts = num_online_cpus(); + + total_contexts = num_kernel_contexts + num_user_contexts; + + /* + * Adjust the counts given a global max. + */ + if (total_contexts > dd->chip_rcv_contexts) { + dd_dev_err(dd, + "Reducing # user receive contexts to: %d, from %d\n", + (int)(dd->chip_rcv_contexts - num_kernel_contexts), + (int)num_user_contexts); + num_user_contexts = dd->chip_rcv_contexts - num_kernel_contexts; + /* recalculate */ + total_contexts = num_kernel_contexts + num_user_contexts; + } + + /* the first N are kernel contexts, the rest are user contexts */ + dd->num_rcv_contexts = total_contexts; + dd->n_krcv_queues = num_kernel_contexts; + dd->first_user_ctxt = num_kernel_contexts; + dd->freectxts = num_user_contexts; + dd_dev_info(dd, + "rcv contexts: chip %d, used %d (kernel %d, user %d)\n", + (int)dd->chip_rcv_contexts, + (int)dd->num_rcv_contexts, + (int)dd->n_krcv_queues, + (int)dd->num_rcv_contexts - dd->n_krcv_queues); + + /* + * Receive array allocation: + * All RcvArray entries are divided into groups of 8. This + * is required by the hardware and will speed up writes to + * consecutive entries by using write-combining of the entire + * cacheline. + * + * The number of groups are evenly divided among all contexts. + * any left over groups will be given to the first N user + * contexts. + */ + dd->rcv_entries.group_size = RCV_INCREMENT; + ngroups = dd->chip_rcv_array_count / dd->rcv_entries.group_size; + dd->rcv_entries.ngroups = ngroups / dd->num_rcv_contexts; + dd->rcv_entries.nctxt_extra = ngroups - + (dd->num_rcv_contexts * dd->rcv_entries.ngroups); + dd_dev_info(dd, "RcvArray groups %u, ctxts extra %u\n", + dd->rcv_entries.ngroups, + dd->rcv_entries.nctxt_extra); + if (dd->rcv_entries.ngroups * dd->rcv_entries.group_size > + MAX_EAGER_ENTRIES * 2) { + dd->rcv_entries.ngroups = (MAX_EAGER_ENTRIES * 2) / + dd->rcv_entries.group_size; + dd_dev_info(dd, + "RcvArray group count too high, change to %u\n", + dd->rcv_entries.ngroups); + dd->rcv_entries.nctxt_extra = 0; + } + /* + * PIO send contexts + */ + ret = init_sc_pools_and_sizes(dd); + if (ret >= 0) { /* success */ + dd->num_send_contexts = ret; + dd_dev_info( + dd, + "send contexts: chip %d, used %d (kernel %d, ack %d, user %d)\n", + dd->chip_send_contexts, + dd->num_send_contexts, + dd->sc_sizes[SC_KERNEL].count, + dd->sc_sizes[SC_ACK].count, + dd->sc_sizes[SC_USER].count); + ret = 0; /* success */ + } + + return ret; +} + +/* + * Set the device/port partition key table. The MAD code + * will ensure that, at least, the partial management + * partition key is present in the table. + */ +static void set_partition_keys(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + u64 reg = 0; + int i; + + dd_dev_info(dd, "Setting partition keys\n"); + for (i = 0; i < hfi1_get_npkeys(dd); i++) { + reg |= (ppd->pkeys[i] & + RCV_PARTITION_KEY_PARTITION_KEY_A_MASK) << + ((i % 4) * + RCV_PARTITION_KEY_PARTITION_KEY_B_SHIFT); + /* Each register holds 4 PKey values. */ + if ((i % 4) == 3) { + write_csr(dd, RCV_PARTITION_KEY + + ((i - 3) * 2), reg); + reg = 0; + } + } + + /* Always enable HW pkeys check when pkeys table is set */ + add_rcvctrl(dd, RCV_CTRL_RCV_PARTITION_KEY_ENABLE_SMASK); +} + +/* + * These CSRs and memories are uninitialized on reset and must be + * written before reading to set the ECC/parity bits. + * + * NOTE: All user context CSRs that are not mmaped write-only + * (e.g. the TID flows) must be initialized even if the driver never + * reads them. + */ +static void write_uninitialized_csrs_and_memories(struct hfi1_devdata *dd) +{ + int i, j; + + /* CceIntMap */ + for (i = 0; i < CCE_NUM_INT_MAP_CSRS; i++) + write_csr(dd, CCE_INT_MAP+(8*i), 0); + + /* SendCtxtCreditReturnAddr */ + for (i = 0; i < dd->chip_send_contexts; i++) + write_kctxt_csr(dd, i, SEND_CTXT_CREDIT_RETURN_ADDR, 0); + + /* PIO Send buffers */ + /* SDMA Send buffers */ + /* These are not normally read, and (presently) have no method + to be read, so are not pre-initialized */ + + /* RcvHdrAddr */ + /* RcvHdrTailAddr */ + /* RcvTidFlowTable */ + for (i = 0; i < dd->chip_rcv_contexts; i++) { + write_kctxt_csr(dd, i, RCV_HDR_ADDR, 0); + write_kctxt_csr(dd, i, RCV_HDR_TAIL_ADDR, 0); + for (j = 0; j < RXE_NUM_TID_FLOWS; j++) + write_uctxt_csr(dd, i, RCV_TID_FLOW_TABLE+(8*j), 0); + } + + /* RcvArray */ + for (i = 0; i < dd->chip_rcv_array_count; i++) + write_csr(dd, RCV_ARRAY + (8*i), + RCV_ARRAY_RT_WRITE_ENABLE_SMASK); + + /* RcvQPMapTable */ + for (i = 0; i < 32; i++) + write_csr(dd, RCV_QP_MAP_TABLE + (8 * i), 0); +} + +/* + * Use the ctrl_bits in CceCtrl to clear the status_bits in CceStatus. + */ +static void clear_cce_status(struct hfi1_devdata *dd, u64 status_bits, + u64 ctrl_bits) +{ + unsigned long timeout; + u64 reg; + + /* is the condition present? */ + reg = read_csr(dd, CCE_STATUS); + if ((reg & status_bits) == 0) + return; + + /* clear the condition */ + write_csr(dd, CCE_CTRL, ctrl_bits); + + /* wait for the condition to clear */ + timeout = jiffies + msecs_to_jiffies(CCE_STATUS_TIMEOUT); + while (1) { + reg = read_csr(dd, CCE_STATUS); + if ((reg & status_bits) == 0) + return; + if (time_after(jiffies, timeout)) { + dd_dev_err(dd, + "Timeout waiting for CceStatus to clear bits 0x%llx, remaining 0x%llx\n", + status_bits, reg & status_bits); + return; + } + udelay(1); + } +} + +/* set CCE CSRs to chip reset defaults */ +static void reset_cce_csrs(struct hfi1_devdata *dd) +{ + int i; + + /* CCE_REVISION read-only */ + /* CCE_REVISION2 read-only */ + /* CCE_CTRL - bits clear automatically */ + /* CCE_STATUS read-only, use CceCtrl to clear */ + clear_cce_status(dd, ALL_FROZE, CCE_CTRL_SPC_UNFREEZE_SMASK); + clear_cce_status(dd, ALL_TXE_PAUSE, CCE_CTRL_TXE_RESUME_SMASK); + clear_cce_status(dd, ALL_RXE_PAUSE, CCE_CTRL_RXE_RESUME_SMASK); + for (i = 0; i < CCE_NUM_SCRATCH; i++) + write_csr(dd, CCE_SCRATCH + (8 * i), 0); + /* CCE_ERR_STATUS read-only */ + write_csr(dd, CCE_ERR_MASK, 0); + write_csr(dd, CCE_ERR_CLEAR, ~0ull); + /* CCE_ERR_FORCE leave alone */ + for (i = 0; i < CCE_NUM_32_BIT_COUNTERS; i++) + write_csr(dd, CCE_COUNTER_ARRAY32 + (8 * i), 0); + write_csr(dd, CCE_DC_CTRL, CCE_DC_CTRL_RESETCSR); + /* CCE_PCIE_CTRL leave alone */ + for (i = 0; i < CCE_NUM_MSIX_VECTORS; i++) { + write_csr(dd, CCE_MSIX_TABLE_LOWER + (8 * i), 0); + write_csr(dd, CCE_MSIX_TABLE_UPPER + (8 * i), + CCE_MSIX_TABLE_UPPER_RESETCSR); + } + for (i = 0; i < CCE_NUM_MSIX_PBAS; i++) { + /* CCE_MSIX_PBA read-only */ + write_csr(dd, CCE_MSIX_INT_GRANTED, ~0ull); + write_csr(dd, CCE_MSIX_VEC_CLR_WITHOUT_INT, ~0ull); + } + for (i = 0; i < CCE_NUM_INT_MAP_CSRS; i++) + write_csr(dd, CCE_INT_MAP, 0); + for (i = 0; i < CCE_NUM_INT_CSRS; i++) { + /* CCE_INT_STATUS read-only */ + write_csr(dd, CCE_INT_MASK + (8 * i), 0); + write_csr(dd, CCE_INT_CLEAR + (8 * i), ~0ull); + /* CCE_INT_FORCE leave alone */ + /* CCE_INT_BLOCKED read-only */ + } + for (i = 0; i < CCE_NUM_32_BIT_INT_COUNTERS; i++) + write_csr(dd, CCE_INT_COUNTER_ARRAY32 + (8 * i), 0); +} + +/* set ASIC CSRs to chip reset defaults */ +static void reset_asic_csrs(struct hfi1_devdata *dd) +{ + static DEFINE_MUTEX(asic_mutex); + static int called; + int i; + + /* + * If the HFIs are shared between separate nodes or VMs, + * then more will need to be done here. One idea is a module + * parameter that returns early, letting the first power-on or + * a known first load do the reset and blocking all others. + */ + + /* + * These CSRs should only be reset once - the first one here will + * do the work. Use a mutex so that a non-first caller waits until + * the first is finished before it can proceed. + */ + mutex_lock(&asic_mutex); + if (called) + goto done; + called = 1; + + if (dd->icode != ICODE_FPGA_EMULATION) { + /* emulation does not have an SBus - leave these alone */ + /* + * All writes to ASIC_CFG_SBUS_REQUEST do something. + * Notes: + * o The reset is not zero if aimed at the core. See the + * SBus documentation for details. + * o If the SBus firmware has been updated (e.g. by the BIOS), + * will the reset revert that? + */ + /* ASIC_CFG_SBUS_REQUEST leave alone */ + write_csr(dd, ASIC_CFG_SBUS_EXECUTE, 0); + } + /* ASIC_SBUS_RESULT read-only */ + write_csr(dd, ASIC_STS_SBUS_COUNTERS, 0); + for (i = 0; i < ASIC_NUM_SCRATCH; i++) + write_csr(dd, ASIC_CFG_SCRATCH + (8 * i), 0); + write_csr(dd, ASIC_CFG_MUTEX, 0); /* this will clear it */ + write_csr(dd, ASIC_CFG_DRV_STR, 0); + write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0); + /* ASIC_STS_THERM read-only */ + /* ASIC_CFG_RESET leave alone */ + + write_csr(dd, ASIC_PCIE_SD_HOST_CMD, 0); + /* ASIC_PCIE_SD_HOST_STATUS read-only */ + write_csr(dd, ASIC_PCIE_SD_INTRPT_DATA_CODE, 0); + write_csr(dd, ASIC_PCIE_SD_INTRPT_ENABLE, 0); + /* ASIC_PCIE_SD_INTRPT_PROGRESS read-only */ + write_csr(dd, ASIC_PCIE_SD_INTRPT_STATUS, ~0ull); /* clear */ + /* ASIC_HFI0_PCIE_SD_INTRPT_RSPD_DATA read-only */ + /* ASIC_HFI1_PCIE_SD_INTRPT_RSPD_DATA read-only */ + for (i = 0; i < 16; i++) + write_csr(dd, ASIC_PCIE_SD_INTRPT_LIST + (8 * i), 0); + + /* ASIC_GPIO_IN read-only */ + write_csr(dd, ASIC_GPIO_OE, 0); + write_csr(dd, ASIC_GPIO_INVERT, 0); + write_csr(dd, ASIC_GPIO_OUT, 0); + write_csr(dd, ASIC_GPIO_MASK, 0); + /* ASIC_GPIO_STATUS read-only */ + write_csr(dd, ASIC_GPIO_CLEAR, ~0ull); + /* ASIC_GPIO_FORCE leave alone */ + + /* ASIC_QSFP1_IN read-only */ + write_csr(dd, ASIC_QSFP1_OE, 0); + write_csr(dd, ASIC_QSFP1_INVERT, 0); + write_csr(dd, ASIC_QSFP1_OUT, 0); + write_csr(dd, ASIC_QSFP1_MASK, 0); + /* ASIC_QSFP1_STATUS read-only */ + write_csr(dd, ASIC_QSFP1_CLEAR, ~0ull); + /* ASIC_QSFP1_FORCE leave alone */ + + /* ASIC_QSFP2_IN read-only */ + write_csr(dd, ASIC_QSFP2_OE, 0); + write_csr(dd, ASIC_QSFP2_INVERT, 0); + write_csr(dd, ASIC_QSFP2_OUT, 0); + write_csr(dd, ASIC_QSFP2_MASK, 0); + /* ASIC_QSFP2_STATUS read-only */ + write_csr(dd, ASIC_QSFP2_CLEAR, ~0ull); + /* ASIC_QSFP2_FORCE leave alone */ + + write_csr(dd, ASIC_EEP_CTL_STAT, ASIC_EEP_CTL_STAT_RESETCSR); + /* this also writes a NOP command, clearing paging mode */ + write_csr(dd, ASIC_EEP_ADDR_CMD, 0); + write_csr(dd, ASIC_EEP_DATA, 0); + +done: + mutex_unlock(&asic_mutex); +} + +/* set MISC CSRs to chip reset defaults */ +static void reset_misc_csrs(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < 32; i++) { + write_csr(dd, MISC_CFG_RSA_R2 + (8 * i), 0); + write_csr(dd, MISC_CFG_RSA_SIGNATURE + (8 * i), 0); + write_csr(dd, MISC_CFG_RSA_MODULUS + (8 * i), 0); + } + /* MISC_CFG_SHA_PRELOAD leave alone - always reads 0 and can + only be written 128-byte chunks */ + /* init RSA engine to clear lingering errors */ + write_csr(dd, MISC_CFG_RSA_CMD, 1); + write_csr(dd, MISC_CFG_RSA_MU, 0); + write_csr(dd, MISC_CFG_FW_CTRL, 0); + /* MISC_STS_8051_DIGEST read-only */ + /* MISC_STS_SBM_DIGEST read-only */ + /* MISC_STS_PCIE_DIGEST read-only */ + /* MISC_STS_FAB_DIGEST read-only */ + /* MISC_ERR_STATUS read-only */ + write_csr(dd, MISC_ERR_MASK, 0); + write_csr(dd, MISC_ERR_CLEAR, ~0ull); + /* MISC_ERR_FORCE leave alone */ +} + +/* set TXE CSRs to chip reset defaults */ +static void reset_txe_csrs(struct hfi1_devdata *dd) +{ + int i; + + /* + * TXE Kernel CSRs + */ + write_csr(dd, SEND_CTRL, 0); + __cm_reset(dd, 0); /* reset CM internal state */ + /* SEND_CONTEXTS read-only */ + /* SEND_DMA_ENGINES read-only */ + /* SEND_PIO_MEM_SIZE read-only */ + /* SEND_DMA_MEM_SIZE read-only */ + write_csr(dd, SEND_HIGH_PRIORITY_LIMIT, 0); + pio_reset_all(dd); /* SEND_PIO_INIT_CTXT */ + /* SEND_PIO_ERR_STATUS read-only */ + write_csr(dd, SEND_PIO_ERR_MASK, 0); + write_csr(dd, SEND_PIO_ERR_CLEAR, ~0ull); + /* SEND_PIO_ERR_FORCE leave alone */ + /* SEND_DMA_ERR_STATUS read-only */ + write_csr(dd, SEND_DMA_ERR_MASK, 0); + write_csr(dd, SEND_DMA_ERR_CLEAR, ~0ull); + /* SEND_DMA_ERR_FORCE leave alone */ + /* SEND_EGRESS_ERR_STATUS read-only */ + write_csr(dd, SEND_EGRESS_ERR_MASK, 0); + write_csr(dd, SEND_EGRESS_ERR_CLEAR, ~0ull); + /* SEND_EGRESS_ERR_FORCE leave alone */ + write_csr(dd, SEND_BTH_QP, 0); + write_csr(dd, SEND_STATIC_RATE_CONTROL, 0); + write_csr(dd, SEND_SC2VLT0, 0); + write_csr(dd, SEND_SC2VLT1, 0); + write_csr(dd, SEND_SC2VLT2, 0); + write_csr(dd, SEND_SC2VLT3, 0); + write_csr(dd, SEND_LEN_CHECK0, 0); + write_csr(dd, SEND_LEN_CHECK1, 0); + /* SEND_ERR_STATUS read-only */ + write_csr(dd, SEND_ERR_MASK, 0); + write_csr(dd, SEND_ERR_CLEAR, ~0ull); + /* SEND_ERR_FORCE read-only */ + for (i = 0; i < VL_ARB_LOW_PRIO_TABLE_SIZE; i++) + write_csr(dd, SEND_LOW_PRIORITY_LIST + (8*i), 0); + for (i = 0; i < VL_ARB_HIGH_PRIO_TABLE_SIZE; i++) + write_csr(dd, SEND_HIGH_PRIORITY_LIST + (8*i), 0); + for (i = 0; i < dd->chip_send_contexts/NUM_CONTEXTS_PER_SET; i++) + write_csr(dd, SEND_CONTEXT_SET_CTRL + (8*i), 0); + for (i = 0; i < TXE_NUM_32_BIT_COUNTER; i++) + write_csr(dd, SEND_COUNTER_ARRAY32 + (8*i), 0); + for (i = 0; i < TXE_NUM_64_BIT_COUNTER; i++) + write_csr(dd, SEND_COUNTER_ARRAY64 + (8*i), 0); + write_csr(dd, SEND_CM_CTRL, SEND_CM_CTRL_RESETCSR); + write_csr(dd, SEND_CM_GLOBAL_CREDIT, + SEND_CM_GLOBAL_CREDIT_RESETCSR); + /* SEND_CM_CREDIT_USED_STATUS read-only */ + write_csr(dd, SEND_CM_TIMER_CTRL, 0); + write_csr(dd, SEND_CM_LOCAL_AU_TABLE0_TO3, 0); + write_csr(dd, SEND_CM_LOCAL_AU_TABLE4_TO7, 0); + write_csr(dd, SEND_CM_REMOTE_AU_TABLE0_TO3, 0); + write_csr(dd, SEND_CM_REMOTE_AU_TABLE4_TO7, 0); + for (i = 0; i < TXE_NUM_DATA_VL; i++) + write_csr(dd, SEND_CM_CREDIT_VL + (8*i), 0); + write_csr(dd, SEND_CM_CREDIT_VL15, 0); + /* SEND_CM_CREDIT_USED_VL read-only */ + /* SEND_CM_CREDIT_USED_VL15 read-only */ + /* SEND_EGRESS_CTXT_STATUS read-only */ + /* SEND_EGRESS_SEND_DMA_STATUS read-only */ + write_csr(dd, SEND_EGRESS_ERR_INFO, ~0ull); + /* SEND_EGRESS_ERR_INFO read-only */ + /* SEND_EGRESS_ERR_SOURCE read-only */ + + /* + * TXE Per-Context CSRs + */ + for (i = 0; i < dd->chip_send_contexts; i++) { + write_kctxt_csr(dd, i, SEND_CTXT_CTRL, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CREDIT_CTRL, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CREDIT_RETURN_ADDR, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CREDIT_FORCE, 0); + write_kctxt_csr(dd, i, SEND_CTXT_ERR_MASK, 0); + write_kctxt_csr(dd, i, SEND_CTXT_ERR_CLEAR, ~0ull); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_ENABLE, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_VL, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_JOB_KEY, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_PARTITION_KEY, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_SLID, 0); + write_kctxt_csr(dd, i, SEND_CTXT_CHECK_OPCODE, 0); + } + + /* + * TXE Per-SDMA CSRs + */ + for (i = 0; i < dd->chip_sdma_engines; i++) { + write_kctxt_csr(dd, i, SEND_DMA_CTRL, 0); + /* SEND_DMA_STATUS read-only */ + write_kctxt_csr(dd, i, SEND_DMA_BASE_ADDR, 0); + write_kctxt_csr(dd, i, SEND_DMA_LEN_GEN, 0); + write_kctxt_csr(dd, i, SEND_DMA_TAIL, 0); + /* SEND_DMA_HEAD read-only */ + write_kctxt_csr(dd, i, SEND_DMA_HEAD_ADDR, 0); + write_kctxt_csr(dd, i, SEND_DMA_PRIORITY_THLD, 0); + /* SEND_DMA_IDLE_CNT read-only */ + write_kctxt_csr(dd, i, SEND_DMA_RELOAD_CNT, 0); + write_kctxt_csr(dd, i, SEND_DMA_DESC_CNT, 0); + /* SEND_DMA_DESC_FETCHED_CNT read-only */ + /* SEND_DMA_ENG_ERR_STATUS read-only */ + write_kctxt_csr(dd, i, SEND_DMA_ENG_ERR_MASK, 0); + write_kctxt_csr(dd, i, SEND_DMA_ENG_ERR_CLEAR, ~0ull); + /* SEND_DMA_ENG_ERR_FORCE leave alone */ + write_kctxt_csr(dd, i, SEND_DMA_CHECK_ENABLE, 0); + write_kctxt_csr(dd, i, SEND_DMA_CHECK_VL, 0); + write_kctxt_csr(dd, i, SEND_DMA_CHECK_JOB_KEY, 0); + write_kctxt_csr(dd, i, SEND_DMA_CHECK_PARTITION_KEY, 0); + write_kctxt_csr(dd, i, SEND_DMA_CHECK_SLID, 0); + write_kctxt_csr(dd, i, SEND_DMA_CHECK_OPCODE, 0); + write_kctxt_csr(dd, i, SEND_DMA_MEMORY, 0); + } +} + +/* + * Expect on entry: + * o Packet ingress is disabled, i.e. RcvCtrl.RcvPortEnable == 0 + */ +static void init_rbufs(struct hfi1_devdata *dd) +{ + u64 reg; + int count; + + /* + * Wait for DMA to stop: RxRbufPktPending and RxPktInProgress are + * clear. + */ + count = 0; + while (1) { + reg = read_csr(dd, RCV_STATUS); + if ((reg & (RCV_STATUS_RX_RBUF_PKT_PENDING_SMASK + | RCV_STATUS_RX_PKT_IN_PROGRESS_SMASK)) == 0) + break; + /* + * Give up after 1ms - maximum wait time. + * + * RBuf size is 148KiB. Slowest possible is PCIe Gen1 x1 at + * 250MB/s bandwidth. Lower rate to 66% for overhead to get: + * 148 KB / (66% * 250MB/s) = 920us + */ + if (count++ > 500) { + dd_dev_err(dd, + "%s: in-progress DMA not clearing: RcvStatus 0x%llx, continuing\n", + __func__, reg); + break; + } + udelay(2); /* do not busy-wait the CSR */ + } + + /* start the init - expect RcvCtrl to be 0 */ + write_csr(dd, RCV_CTRL, RCV_CTRL_RX_RBUF_INIT_SMASK); + + /* + * Read to force the write of Rcvtrl.RxRbufInit. There is a brief + * period after the write before RcvStatus.RxRbufInitDone is valid. + * The delay in the first run through the loop below is sufficient and + * required before the first read of RcvStatus.RxRbufInintDone. + */ + read_csr(dd, RCV_CTRL); + + /* wait for the init to finish */ + count = 0; + while (1) { + /* delay is required first time through - see above */ + udelay(2); /* do not busy-wait the CSR */ + reg = read_csr(dd, RCV_STATUS); + if (reg & (RCV_STATUS_RX_RBUF_INIT_DONE_SMASK)) + break; + + /* give up after 100us - slowest possible at 33MHz is 73us */ + if (count++ > 50) { + dd_dev_err(dd, + "%s: RcvStatus.RxRbufInit not set, continuing\n", + __func__); + break; + } + } +} + +/* set RXE CSRs to chip reset defaults */ +static void reset_rxe_csrs(struct hfi1_devdata *dd) +{ + int i, j; + + /* + * RXE Kernel CSRs + */ + write_csr(dd, RCV_CTRL, 0); + init_rbufs(dd); + /* RCV_STATUS read-only */ + /* RCV_CONTEXTS read-only */ + /* RCV_ARRAY_CNT read-only */ + /* RCV_BUF_SIZE read-only */ + write_csr(dd, RCV_BTH_QP, 0); + write_csr(dd, RCV_MULTICAST, 0); + write_csr(dd, RCV_BYPASS, 0); + write_csr(dd, RCV_VL15, 0); + /* this is a clear-down */ + write_csr(dd, RCV_ERR_INFO, + RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK); + /* RCV_ERR_STATUS read-only */ + write_csr(dd, RCV_ERR_MASK, 0); + write_csr(dd, RCV_ERR_CLEAR, ~0ull); + /* RCV_ERR_FORCE leave alone */ + for (i = 0; i < 32; i++) + write_csr(dd, RCV_QP_MAP_TABLE + (8 * i), 0); + for (i = 0; i < 4; i++) + write_csr(dd, RCV_PARTITION_KEY + (8 * i), 0); + for (i = 0; i < RXE_NUM_32_BIT_COUNTERS; i++) + write_csr(dd, RCV_COUNTER_ARRAY32 + (8 * i), 0); + for (i = 0; i < RXE_NUM_64_BIT_COUNTERS; i++) + write_csr(dd, RCV_COUNTER_ARRAY64 + (8 * i), 0); + for (i = 0; i < RXE_NUM_RSM_INSTANCES; i++) { + write_csr(dd, RCV_RSM_CFG + (8 * i), 0); + write_csr(dd, RCV_RSM_SELECT + (8 * i), 0); + write_csr(dd, RCV_RSM_MATCH + (8 * i), 0); + } + for (i = 0; i < 32; i++) + write_csr(dd, RCV_RSM_MAP_TABLE + (8 * i), 0); + + /* + * RXE Kernel and User Per-Context CSRs + */ + for (i = 0; i < dd->chip_rcv_contexts; i++) { + /* kernel */ + write_kctxt_csr(dd, i, RCV_CTXT_CTRL, 0); + /* RCV_CTXT_STATUS read-only */ + write_kctxt_csr(dd, i, RCV_EGR_CTRL, 0); + write_kctxt_csr(dd, i, RCV_TID_CTRL, 0); + write_kctxt_csr(dd, i, RCV_KEY_CTRL, 0); + write_kctxt_csr(dd, i, RCV_HDR_ADDR, 0); + write_kctxt_csr(dd, i, RCV_HDR_CNT, 0); + write_kctxt_csr(dd, i, RCV_HDR_ENT_SIZE, 0); + write_kctxt_csr(dd, i, RCV_HDR_SIZE, 0); + write_kctxt_csr(dd, i, RCV_HDR_TAIL_ADDR, 0); + write_kctxt_csr(dd, i, RCV_AVAIL_TIME_OUT, 0); + write_kctxt_csr(dd, i, RCV_HDR_OVFL_CNT, 0); + + /* user */ + /* RCV_HDR_TAIL read-only */ + write_uctxt_csr(dd, i, RCV_HDR_HEAD, 0); + /* RCV_EGR_INDEX_TAIL read-only */ + write_uctxt_csr(dd, i, RCV_EGR_INDEX_HEAD, 0); + /* RCV_EGR_OFFSET_TAIL read-only */ + for (j = 0; j < RXE_NUM_TID_FLOWS; j++) { + write_uctxt_csr(dd, i, RCV_TID_FLOW_TABLE + (8 * j), + 0); + } + } +} + +/* + * Set sc2vl tables. + * + * They power on to zeros, so to avoid send context errors + * they need to be set: + * + * SC 0-7 -> VL 0-7 (respectively) + * SC 15 -> VL 15 + * otherwise + * -> VL 0 + */ +static void init_sc2vl_tables(struct hfi1_devdata *dd) +{ + int i; + /* init per architecture spec, constrained by hardware capability */ + + /* HFI maps sent packets */ + write_csr(dd, SEND_SC2VLT0, SC2VL_VAL( + 0, + 0, 0, 1, 1, + 2, 2, 3, 3, + 4, 4, 5, 5, + 6, 6, 7, 7)); + write_csr(dd, SEND_SC2VLT1, SC2VL_VAL( + 1, + 8, 0, 9, 0, + 10, 0, 11, 0, + 12, 0, 13, 0, + 14, 0, 15, 15)); + write_csr(dd, SEND_SC2VLT2, SC2VL_VAL( + 2, + 16, 0, 17, 0, + 18, 0, 19, 0, + 20, 0, 21, 0, + 22, 0, 23, 0)); + write_csr(dd, SEND_SC2VLT3, SC2VL_VAL( + 3, + 24, 0, 25, 0, + 26, 0, 27, 0, + 28, 0, 29, 0, + 30, 0, 31, 0)); + + /* DC maps received packets */ + write_csr(dd, DCC_CFG_SC_VL_TABLE_15_0, DC_SC_VL_VAL( + 15_0, + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, + 8, 0, 9, 0, 10, 0, 11, 0, 12, 0, 13, 0, 14, 0, 15, 15)); + write_csr(dd, DCC_CFG_SC_VL_TABLE_31_16, DC_SC_VL_VAL( + 31_16, + 16, 0, 17, 0, 18, 0, 19, 0, 20, 0, 21, 0, 22, 0, 23, 0, + 24, 0, 25, 0, 26, 0, 27, 0, 28, 0, 29, 0, 30, 0, 31, 0)); + + /* initialize the cached sc2vl values consistently with h/w */ + for (i = 0; i < 32; i++) { + if (i < 8 || i == 15) + *((u8 *)(dd->sc2vl) + i) = (u8)i; + else + *((u8 *)(dd->sc2vl) + i) = 0; + } +} + +/* + * Read chip sizes and then reset parts to sane, disabled, values. We cannot + * depend on the chip going through a power-on reset - a driver may be loaded + * and unloaded many times. + * + * Do not write any CSR values to the chip in this routine - there may be + * a reset following the (possible) FLR in this routine. + * + */ +static void init_chip(struct hfi1_devdata *dd) +{ + int i; + + /* + * Put the HFI CSRs in a known state. + * Combine this with a DC reset. + * + * Stop the device from doing anything while we do a + * reset. We know there are no other active users of + * the device since we are now in charge. Turn off + * off all outbound and inbound traffic and make sure + * the device does not generate any interrupts. + */ + + /* disable send contexts and SDMA engines */ + write_csr(dd, SEND_CTRL, 0); + for (i = 0; i < dd->chip_send_contexts; i++) + write_kctxt_csr(dd, i, SEND_CTXT_CTRL, 0); + for (i = 0; i < dd->chip_sdma_engines; i++) + write_kctxt_csr(dd, i, SEND_DMA_CTRL, 0); + /* disable port (turn off RXE inbound traffic) and contexts */ + write_csr(dd, RCV_CTRL, 0); + for (i = 0; i < dd->chip_rcv_contexts; i++) + write_csr(dd, RCV_CTXT_CTRL, 0); + /* mask all interrupt sources */ + for (i = 0; i < CCE_NUM_INT_CSRS; i++) + write_csr(dd, CCE_INT_MASK + (8*i), 0ull); + + /* + * DC Reset: do a full DC reset before the register clear. + * A recommended length of time to hold is one CSR read, + * so reread the CceDcCtrl. Then, hold the DC in reset + * across the clear. + */ + write_csr(dd, CCE_DC_CTRL, CCE_DC_CTRL_DC_RESET_SMASK); + (void) read_csr(dd, CCE_DC_CTRL); + + if (use_flr) { + /* + * A FLR will reset the SPC core and part of the PCIe. + * The parts that need to be restored have already been + * saved. + */ + dd_dev_info(dd, "Resetting CSRs with FLR\n"); + + /* do the FLR, the DC reset will remain */ + hfi1_pcie_flr(dd); + + /* restore command and BARs */ + restore_pci_variables(dd); + + if (is_a0(dd)) { + dd_dev_info(dd, "Resetting CSRs with FLR\n"); + hfi1_pcie_flr(dd); + restore_pci_variables(dd); + } + + } else { + dd_dev_info(dd, "Resetting CSRs with writes\n"); + reset_cce_csrs(dd); + reset_txe_csrs(dd); + reset_rxe_csrs(dd); + reset_asic_csrs(dd); + reset_misc_csrs(dd); + } + /* clear the DC reset */ + write_csr(dd, CCE_DC_CTRL, 0); + /* Set the LED off */ + if (is_a0(dd)) + setextled(dd, 0); + /* + * Clear the QSFP reset. + * A0 leaves the out lines floating on power on, then on an FLR + * enforces a 0 on all out pins. The driver does not touch + * ASIC_QSFPn_OUT otherwise. This leaves RESET_N low and + * anything plugged constantly in reset, if it pays attention + * to RESET_N. + * A prime example of this is SiPh. For now, set all pins high. + * I2CCLK and I2CDAT will change per direction, and INT_N and + * MODPRS_N are input only and their value is ignored. + */ + if (is_a0(dd)) { + write_csr(dd, ASIC_QSFP1_OUT, 0x1f); + write_csr(dd, ASIC_QSFP2_OUT, 0x1f); + } +} + +static void init_early_variables(struct hfi1_devdata *dd) +{ + int i; + + /* assign link credit variables */ + dd->vau = CM_VAU; + dd->link_credits = CM_GLOBAL_CREDITS; + if (is_a0(dd)) + dd->link_credits--; + dd->vcu = cu_to_vcu(hfi1_cu); + /* enough room for 8 MAD packets plus header - 17K */ + dd->vl15_init = (8 * (2048 + 128)) / vau_to_au(dd->vau); + if (dd->vl15_init > dd->link_credits) + dd->vl15_init = dd->link_credits; + + write_uninitialized_csrs_and_memories(dd); + + if (HFI1_CAP_IS_KSET(PKEY_CHECK)) + for (i = 0; i < dd->num_pports; i++) { + struct hfi1_pportdata *ppd = &dd->pport[i]; + + set_partition_keys(ppd); + } + init_sc2vl_tables(dd); +} + +static void init_kdeth_qp(struct hfi1_devdata *dd) +{ + /* user changed the KDETH_QP */ + if (kdeth_qp != 0 && kdeth_qp >= 0xff) { + /* out of range or illegal value */ + dd_dev_err(dd, "Invalid KDETH queue pair prefix, ignoring"); + kdeth_qp = 0; + } + if (kdeth_qp == 0) /* not set, or failed range check */ + kdeth_qp = DEFAULT_KDETH_QP; + + write_csr(dd, SEND_BTH_QP, + (kdeth_qp & SEND_BTH_QP_KDETH_QP_MASK) + << SEND_BTH_QP_KDETH_QP_SHIFT); + + write_csr(dd, RCV_BTH_QP, + (kdeth_qp & RCV_BTH_QP_KDETH_QP_MASK) + << RCV_BTH_QP_KDETH_QP_SHIFT); +} + +/** + * init_qpmap_table + * @dd - device data + * @first_ctxt - first context + * @last_ctxt - first context + * + * This return sets the qpn mapping table that + * is indexed by qpn[8:1]. + * + * The routine will round robin the 256 settings + * from first_ctxt to last_ctxt. + * + * The first/last looks ahead to having specialized + * receive contexts for mgmt and bypass. Normal + * verbs traffic will assumed to be on a range + * of receive contexts. + */ +static void init_qpmap_table(struct hfi1_devdata *dd, + u32 first_ctxt, + u32 last_ctxt) +{ + u64 reg = 0; + u64 regno = RCV_QP_MAP_TABLE; + int i; + u64 ctxt = first_ctxt; + + for (i = 0; i < 256;) { + if (ctxt == VL15CTXT) { + ctxt++; + if (ctxt > last_ctxt) + ctxt = first_ctxt; + continue; + } + reg |= ctxt << (8 * (i % 8)); + i++; + ctxt++; + if (ctxt > last_ctxt) + ctxt = first_ctxt; + if (i % 8 == 0) { + write_csr(dd, regno, reg); + reg = 0; + regno += 8; + } + } + if (i % 8) + write_csr(dd, regno, reg); + + add_rcvctrl(dd, RCV_CTRL_RCV_QP_MAP_ENABLE_SMASK + | RCV_CTRL_RCV_BYPASS_ENABLE_SMASK); +} + +/** + * init_qos - init RX qos + * @dd - device data + * @first_context + * + * This routine initializes Rule 0 and the + * RSM map table to implement qos. + * + * If all of the limit tests succeed, + * qos is applied based on the array + * interpretation of krcvqs where + * entry 0 is VL0. + * + * The number of vl bits (n) and the number of qpn + * bits (m) are computed to feed both the RSM map table + * and the single rule. + * + */ +static void init_qos(struct hfi1_devdata *dd, u32 first_ctxt) +{ + u8 max_by_vl = 0; + unsigned qpns_per_vl, ctxt, i, qpn, n = 1, m; + u64 *rsmmap; + u64 reg; + u8 rxcontext = is_a0(dd) ? 0 : 0xff; /* 0 is default if a0 ver. */ + + /* validate */ + if (dd->n_krcv_queues <= MIN_KERNEL_KCTXTS || + num_vls == 1 || + krcvqsset <= 1) + goto bail; + for (i = 0; i < min_t(unsigned, num_vls, krcvqsset); i++) + if (krcvqs[i] > max_by_vl) + max_by_vl = krcvqs[i]; + if (max_by_vl > 32) + goto bail; + qpns_per_vl = __roundup_pow_of_two(max_by_vl); + /* determine bits vl */ + n = ilog2(num_vls); + /* determine bits for qpn */ + m = ilog2(qpns_per_vl); + if ((m + n) > 7) + goto bail; + if (num_vls * qpns_per_vl > dd->chip_rcv_contexts) + goto bail; + rsmmap = kmalloc_array(NUM_MAP_REGS, sizeof(u64), GFP_KERNEL); + memset(rsmmap, rxcontext, NUM_MAP_REGS * sizeof(u64)); + /* init the local copy of the table */ + for (i = 0, ctxt = first_ctxt; i < num_vls; i++) { + unsigned tctxt; + + for (qpn = 0, tctxt = ctxt; + krcvqs[i] && qpn < qpns_per_vl; qpn++) { + unsigned idx, regoff, regidx; + + /* generate index <= 128 */ + idx = (qpn << n) ^ i; + regoff = (idx % 8) * 8; + regidx = idx / 8; + reg = rsmmap[regidx]; + /* replace 0xff with context number */ + reg &= ~(RCV_RSM_MAP_TABLE_RCV_CONTEXT_A_MASK + << regoff); + reg |= (u64)(tctxt++) << regoff; + rsmmap[regidx] = reg; + if (tctxt == ctxt + krcvqs[i]) + tctxt = ctxt; + } + ctxt += krcvqs[i]; + } + /* flush cached copies to chip */ + for (i = 0; i < NUM_MAP_REGS; i++) + write_csr(dd, RCV_RSM_MAP_TABLE + (8 * i), rsmmap[i]); + /* add rule0 */ + write_csr(dd, RCV_RSM_CFG /* + (8 * 0) */, + RCV_RSM_CFG_ENABLE_OR_CHAIN_RSM0_MASK + << RCV_RSM_CFG_ENABLE_OR_CHAIN_RSM0_SHIFT | + 2ull << RCV_RSM_CFG_PACKET_TYPE_SHIFT); + write_csr(dd, RCV_RSM_SELECT /* + (8 * 0) */, + LRH_BTH_MATCH_OFFSET + << RCV_RSM_SELECT_FIELD1_OFFSET_SHIFT | + LRH_SC_MATCH_OFFSET << RCV_RSM_SELECT_FIELD2_OFFSET_SHIFT | + LRH_SC_SELECT_OFFSET << RCV_RSM_SELECT_INDEX1_OFFSET_SHIFT | + ((u64)n) << RCV_RSM_SELECT_INDEX1_WIDTH_SHIFT | + QPN_SELECT_OFFSET << RCV_RSM_SELECT_INDEX2_OFFSET_SHIFT | + ((u64)m + (u64)n) << RCV_RSM_SELECT_INDEX2_WIDTH_SHIFT); + write_csr(dd, RCV_RSM_MATCH /* + (8 * 0) */, + LRH_BTH_MASK << RCV_RSM_MATCH_MASK1_SHIFT | + LRH_BTH_VALUE << RCV_RSM_MATCH_VALUE1_SHIFT | + LRH_SC_MASK << RCV_RSM_MATCH_MASK2_SHIFT | + LRH_SC_VALUE << RCV_RSM_MATCH_VALUE2_SHIFT); + /* Enable RSM */ + add_rcvctrl(dd, RCV_CTRL_RCV_RSM_ENABLE_SMASK); + kfree(rsmmap); + /* map everything else (non-VL15) to context 0 */ + init_qpmap_table( + dd, + 0, + 0); + dd->qos_shift = n + 1; + return; +bail: + dd->qos_shift = 1; + init_qpmap_table( + dd, + dd->n_krcv_queues > MIN_KERNEL_KCTXTS ? MIN_KERNEL_KCTXTS : 0, + dd->n_krcv_queues - 1); +} + +static void init_rxe(struct hfi1_devdata *dd) +{ + /* enable all receive errors */ + write_csr(dd, RCV_ERR_MASK, ~0ull); + /* setup QPN map table - start where VL15 context leaves off */ + init_qos( + dd, + dd->n_krcv_queues > MIN_KERNEL_KCTXTS ? MIN_KERNEL_KCTXTS : 0); + /* + * make sure RcvCtrl.RcvWcb <= PCIe Device Control + * Register Max_Payload_Size (PCI_EXP_DEVCTL in Linux PCIe config + * space, PciCfgCap2.MaxPayloadSize in HFI). There is only one + * invalid configuration: RcvCtrl.RcvWcb set to its max of 256 and + * Max_PayLoad_Size set to its minimum of 128. + * + * Presently, RcvCtrl.RcvWcb is not modified from its default of 0 + * (64 bytes). Max_Payload_Size is possibly modified upward in + * tune_pcie_caps() which is called after this routine. + */ +} + +static void init_other(struct hfi1_devdata *dd) +{ + /* enable all CCE errors */ + write_csr(dd, CCE_ERR_MASK, ~0ull); + /* enable *some* Misc errors */ + write_csr(dd, MISC_ERR_MASK, DRIVER_MISC_MASK); + /* enable all DC errors, except LCB */ + write_csr(dd, DCC_ERR_FLG_EN, ~0ull); + write_csr(dd, DC_DC8051_ERR_EN, ~0ull); +} + +/* + * Fill out the given AU table using the given CU. A CU is defined in terms + * AUs. The table is a an encoding: given the index, how many AUs does that + * represent? + * + * NOTE: Assumes that the register layout is the same for the + * local and remote tables. + */ +static void assign_cm_au_table(struct hfi1_devdata *dd, u32 cu, + u32 csr0to3, u32 csr4to7) +{ + write_csr(dd, csr0to3, + 0ull << + SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE0_SHIFT + | 1ull << + SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE1_SHIFT + | 2ull * cu << + SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE2_SHIFT + | 4ull * cu << + SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE3_SHIFT); + write_csr(dd, csr4to7, + 8ull * cu << + SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE4_SHIFT + | 16ull * cu << + SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE5_SHIFT + | 32ull * cu << + SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE6_SHIFT + | 64ull * cu << + SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE7_SHIFT); + +} + +static void assign_local_cm_au_table(struct hfi1_devdata *dd, u8 vcu) +{ + assign_cm_au_table(dd, vcu_to_cu(vcu), SEND_CM_LOCAL_AU_TABLE0_TO3, + SEND_CM_LOCAL_AU_TABLE4_TO7); +} + +void assign_remote_cm_au_table(struct hfi1_devdata *dd, u8 vcu) +{ + assign_cm_au_table(dd, vcu_to_cu(vcu), SEND_CM_REMOTE_AU_TABLE0_TO3, + SEND_CM_REMOTE_AU_TABLE4_TO7); +} + +static void init_txe(struct hfi1_devdata *dd) +{ + int i; + + /* enable all PIO, SDMA, general, and Egress errors */ + write_csr(dd, SEND_PIO_ERR_MASK, ~0ull); + write_csr(dd, SEND_DMA_ERR_MASK, ~0ull); + write_csr(dd, SEND_ERR_MASK, ~0ull); + write_csr(dd, SEND_EGRESS_ERR_MASK, ~0ull); + + /* enable all per-context and per-SDMA engine errors */ + for (i = 0; i < dd->chip_send_contexts; i++) + write_kctxt_csr(dd, i, SEND_CTXT_ERR_MASK, ~0ull); + for (i = 0; i < dd->chip_sdma_engines; i++) + write_kctxt_csr(dd, i, SEND_DMA_ENG_ERR_MASK, ~0ull); + + /* set the local CU to AU mapping */ + assign_local_cm_au_table(dd, dd->vcu); + + /* + * Set reasonable default for Credit Return Timer + * Don't set on Simulator - causes it to choke. + */ + if (dd->icode != ICODE_FUNCTIONAL_SIMULATOR) + write_csr(dd, SEND_CM_TIMER_CTRL, HFI1_CREDIT_RETURN_RATE); +} + +int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt, u16 jkey) +{ + struct hfi1_ctxtdata *rcd = dd->rcd[ctxt]; + unsigned sctxt; + int ret = 0; + u64 reg; + + if (!rcd || !rcd->sc) { + ret = -EINVAL; + goto done; + } + sctxt = rcd->sc->hw_context; + reg = SEND_CTXT_CHECK_JOB_KEY_MASK_SMASK | /* mask is always 1's */ + ((jkey & SEND_CTXT_CHECK_JOB_KEY_VALUE_MASK) << + SEND_CTXT_CHECK_JOB_KEY_VALUE_SHIFT); + /* JOB_KEY_ALLOW_PERMISSIVE is not allowed by default */ + if (HFI1_CAP_KGET_MASK(rcd->flags, ALLOW_PERM_JKEY)) + reg |= SEND_CTXT_CHECK_JOB_KEY_ALLOW_PERMISSIVE_SMASK; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_JOB_KEY, reg); + /* + * Enable send-side J_KEY integrity check, unless this is A0 h/w + * (due to A0 erratum). + */ + if (!is_a0(dd)) { + reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE); + reg |= SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg); + } + + /* Enable J_KEY check on receive context. */ + reg = RCV_KEY_CTRL_JOB_KEY_ENABLE_SMASK | + ((jkey & RCV_KEY_CTRL_JOB_KEY_VALUE_MASK) << + RCV_KEY_CTRL_JOB_KEY_VALUE_SHIFT); + write_kctxt_csr(dd, ctxt, RCV_KEY_CTRL, reg); +done: + return ret; +} + +int hfi1_clear_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt) +{ + struct hfi1_ctxtdata *rcd = dd->rcd[ctxt]; + unsigned sctxt; + int ret = 0; + u64 reg; + + if (!rcd || !rcd->sc) { + ret = -EINVAL; + goto done; + } + sctxt = rcd->sc->hw_context; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_JOB_KEY, 0); + /* + * Disable send-side J_KEY integrity check, unless this is A0 h/w. + * This check would not have been enabled for A0 h/w, see + * set_ctxt_jkey(). + */ + if (!is_a0(dd)) { + reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE); + reg &= ~SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg); + } + /* Turn off the J_KEY on the receive side */ + write_kctxt_csr(dd, ctxt, RCV_KEY_CTRL, 0); +done: + return ret; +} + +int hfi1_set_ctxt_pkey(struct hfi1_devdata *dd, unsigned ctxt, u16 pkey) +{ + struct hfi1_ctxtdata *rcd; + unsigned sctxt; + int ret = 0; + u64 reg; + + if (ctxt < dd->num_rcv_contexts) + rcd = dd->rcd[ctxt]; + else { + ret = -EINVAL; + goto done; + } + if (!rcd || !rcd->sc) { + ret = -EINVAL; + goto done; + } + sctxt = rcd->sc->hw_context; + reg = ((u64)pkey & SEND_CTXT_CHECK_PARTITION_KEY_VALUE_MASK) << + SEND_CTXT_CHECK_PARTITION_KEY_VALUE_SHIFT; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_PARTITION_KEY, reg); + reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE); + reg |= SEND_CTXT_CHECK_ENABLE_CHECK_PARTITION_KEY_SMASK; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg); +done: + return ret; +} + +int hfi1_clear_ctxt_pkey(struct hfi1_devdata *dd, unsigned ctxt) +{ + struct hfi1_ctxtdata *rcd; + unsigned sctxt; + int ret = 0; + u64 reg; + + if (ctxt < dd->num_rcv_contexts) + rcd = dd->rcd[ctxt]; + else { + ret = -EINVAL; + goto done; + } + if (!rcd || !rcd->sc) { + ret = -EINVAL; + goto done; + } + sctxt = rcd->sc->hw_context; + reg = read_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE); + reg &= ~SEND_CTXT_CHECK_ENABLE_CHECK_PARTITION_KEY_SMASK; + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_ENABLE, reg); + write_kctxt_csr(dd, sctxt, SEND_CTXT_CHECK_PARTITION_KEY, 0); +done: + return ret; +} + +/* + * Start doing the clean up the the chip. Our clean up happens in multiple + * stages and this is just the first. + */ +void hfi1_start_cleanup(struct hfi1_devdata *dd) +{ + free_cntrs(dd); + free_rcverr(dd); + clean_up_interrupts(dd); +} + +#define HFI_BASE_GUID(dev) \ + ((dev)->base_guid & ~(1ULL << GUID_HFI_INDEX_SHIFT)) + +/* + * Certain chip functions need to be initialized only once per asic + * instead of per-device. This function finds the peer device and + * checks whether that chip initialization needs to be done by this + * device. + */ +static void asic_should_init(struct hfi1_devdata *dd) +{ + unsigned long flags; + struct hfi1_devdata *tmp, *peer = NULL; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + /* Find our peer device */ + list_for_each_entry(tmp, &hfi1_dev_list, list) { + if ((HFI_BASE_GUID(dd) == HFI_BASE_GUID(tmp)) && + dd->unit != tmp->unit) { + peer = tmp; + break; + } + } + + /* + * "Claim" the ASIC for initialization if it hasn't been + " "claimed" yet. + */ + if (!peer || !(peer->flags & HFI1_DO_INIT_ASIC)) + dd->flags |= HFI1_DO_INIT_ASIC; + spin_unlock_irqrestore(&hfi1_devs_lock, flags); +} + +/** + * Allocate an initialize the device structure for the hfi. + * @dev: the pci_dev for hfi1_ib device + * @ent: pci_device_id struct for this dev + * + * Also allocates, initializes, and returns the devdata struct for this + * device instance + * + * This is global, and is called directly at init to set up the + * chip-specific function pointers for later use. + */ +struct hfi1_devdata *hfi1_init_dd(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct hfi1_devdata *dd; + struct hfi1_pportdata *ppd; + u64 reg; + int i, ret; + static const char * const inames[] = { /* implementation names */ + "RTL silicon", + "RTL VCS simulation", + "RTL FPGA emulation", + "Functional simulator" + }; + + dd = hfi1_alloc_devdata(pdev, + NUM_IB_PORTS * sizeof(struct hfi1_pportdata)); + if (IS_ERR(dd)) + goto bail; + ppd = dd->pport; + for (i = 0; i < dd->num_pports; i++, ppd++) { + int vl; + /* init common fields */ + hfi1_init_pportdata(pdev, ppd, dd, 0, 1); + /* DC supports 4 link widths */ + ppd->link_width_supported = + OPA_LINK_WIDTH_1X | OPA_LINK_WIDTH_2X | + OPA_LINK_WIDTH_3X | OPA_LINK_WIDTH_4X; + ppd->link_width_downgrade_supported = + ppd->link_width_supported; + /* start out enabling only 4X */ + ppd->link_width_enabled = OPA_LINK_WIDTH_4X; + ppd->link_width_downgrade_enabled = + ppd->link_width_downgrade_supported; + /* link width active is 0 when link is down */ + /* link width downgrade active is 0 when link is down */ + + if (num_vls < HFI1_MIN_VLS_SUPPORTED + || num_vls > HFI1_MAX_VLS_SUPPORTED) { + hfi1_early_err(&pdev->dev, + "Invalid num_vls %u, using %u VLs\n", + num_vls, HFI1_MAX_VLS_SUPPORTED); + num_vls = HFI1_MAX_VLS_SUPPORTED; + } + ppd->vls_supported = num_vls; + ppd->vls_operational = ppd->vls_supported; + /* Set the default MTU. */ + for (vl = 0; vl < num_vls; vl++) + dd->vld[vl].mtu = hfi1_max_mtu; + dd->vld[15].mtu = MAX_MAD_PACKET; + /* + * Set the initial values to reasonable default, will be set + * for real when link is up. + */ + ppd->lstate = IB_PORT_DOWN; + ppd->overrun_threshold = 0x4; + ppd->phy_error_threshold = 0xf; + ppd->port_crc_mode_enabled = link_crc_mask; + /* initialize supported LTP CRC mode */ + ppd->port_ltp_crc_mode = cap_to_port_ltp(link_crc_mask) << 8; + /* initialize enabled LTP CRC mode */ + ppd->port_ltp_crc_mode |= cap_to_port_ltp(link_crc_mask) << 4; + /* start in offline */ + ppd->host_link_state = HLS_DN_OFFLINE; + init_vl_arb_caches(ppd); + } + + dd->link_default = HLS_DN_POLL; + + /* + * Do remaining PCIe setup and save PCIe values in dd. + * Any error printing is already done by the init code. + * On return, we have the chip mapped. + */ + ret = hfi1_pcie_ddinit(dd, pdev, ent); + if (ret < 0) + goto bail_free; + + /* verify that reads actually work, save revision for reset check */ + dd->revision = read_csr(dd, CCE_REVISION); + if (dd->revision == ~(u64)0) { + dd_dev_err(dd, "cannot read chip CSRs\n"); + ret = -EINVAL; + goto bail_cleanup; + } + dd->majrev = (dd->revision >> CCE_REVISION_CHIP_REV_MAJOR_SHIFT) + & CCE_REVISION_CHIP_REV_MAJOR_MASK; + dd->minrev = (dd->revision >> CCE_REVISION_CHIP_REV_MINOR_SHIFT) + & CCE_REVISION_CHIP_REV_MINOR_MASK; + + /* obtain the hardware ID - NOT related to unit, which is a + software enumeration */ + reg = read_csr(dd, CCE_REVISION2); + dd->hfi1_id = (reg >> CCE_REVISION2_HFI_ID_SHIFT) + & CCE_REVISION2_HFI_ID_MASK; + /* the variable size will remove unwanted bits */ + dd->icode = reg >> CCE_REVISION2_IMPL_CODE_SHIFT; + dd->irev = reg >> CCE_REVISION2_IMPL_REVISION_SHIFT; + dd_dev_info(dd, "Implementation: %s, revision 0x%x\n", + dd->icode < ARRAY_SIZE(inames) ? inames[dd->icode] : "unknown", + (int)dd->irev); + + /* speeds the hardware can support */ + dd->pport->link_speed_supported = OPA_LINK_SPEED_25G; + /* speeds allowed to run at */ + dd->pport->link_speed_enabled = dd->pport->link_speed_supported; + /* give a reasonable active value, will be set on link up */ + dd->pport->link_speed_active = OPA_LINK_SPEED_25G; + + dd->chip_rcv_contexts = read_csr(dd, RCV_CONTEXTS); + dd->chip_send_contexts = read_csr(dd, SEND_CONTEXTS); + dd->chip_sdma_engines = read_csr(dd, SEND_DMA_ENGINES); + dd->chip_pio_mem_size = read_csr(dd, SEND_PIO_MEM_SIZE); + dd->chip_sdma_mem_size = read_csr(dd, SEND_DMA_MEM_SIZE); + /* fix up link widths for emulation _p */ + ppd = dd->pport; + if (dd->icode == ICODE_FPGA_EMULATION && is_emulator_p(dd)) { + ppd->link_width_supported = + ppd->link_width_enabled = + ppd->link_width_downgrade_supported = + ppd->link_width_downgrade_enabled = + OPA_LINK_WIDTH_1X; + } + /* insure num_vls isn't larger than number of sdma engines */ + if (HFI1_CAP_IS_KSET(SDMA) && num_vls > dd->chip_sdma_engines) { + dd_dev_err(dd, "num_vls %u too large, using %u VLs\n", + num_vls, HFI1_MAX_VLS_SUPPORTED); + ppd->vls_supported = num_vls = HFI1_MAX_VLS_SUPPORTED; + ppd->vls_operational = ppd->vls_supported; + } + + /* + * Convert the ns parameter to the 64 * cclocks used in the CSR. + * Limit the max if larger than the field holds. If timeout is + * non-zero, then the calculated field will be at least 1. + * + * Must be after icode is set up - the cclock rate depends + * on knowing the hardware being used. + */ + dd->rcv_intr_timeout_csr = ns_to_cclock(dd, rcv_intr_timeout) / 64; + if (dd->rcv_intr_timeout_csr > + RCV_AVAIL_TIME_OUT_TIME_OUT_RELOAD_MASK) + dd->rcv_intr_timeout_csr = + RCV_AVAIL_TIME_OUT_TIME_OUT_RELOAD_MASK; + else if (dd->rcv_intr_timeout_csr == 0 && rcv_intr_timeout) + dd->rcv_intr_timeout_csr = 1; + + /* obtain chip sizes, reset chip CSRs */ + init_chip(dd); + + /* read in the PCIe link speed information */ + ret = pcie_speeds(dd); + if (ret) + goto bail_cleanup; + + /* needs to be done before we look for the peer device */ + read_guid(dd); + + asic_should_init(dd); + + /* read in firmware */ + ret = hfi1_firmware_init(dd); + if (ret) + goto bail_cleanup; + + /* + * In general, the PCIe Gen3 transition must occur after the + * chip has been idled (so it won't initiate any PCIe transactions + * e.g. an interrupt) and before the driver changes any registers + * (the transition will reset the registers). + * + * In particular, place this call after: + * - init_chip() - the chip will not initiate any PCIe transactions + * - pcie_speeds() - reads the current link speed + * - hfi1_firmware_init() - the needed firmware is ready to be + * downloaded + */ + ret = do_pcie_gen3_transition(dd); + if (ret) + goto bail_cleanup; + + /* start setting dd values and adjusting CSRs */ + init_early_variables(dd); + + parse_platform_config(dd); + + /* add board names as they are defined */ + dd->boardname = kmalloc(64, GFP_KERNEL); + if (!dd->boardname) + goto bail_cleanup; + snprintf(dd->boardname, 64, "Board ID 0x%llx", + dd->revision >> CCE_REVISION_BOARD_ID_LOWER_NIBBLE_SHIFT + & CCE_REVISION_BOARD_ID_LOWER_NIBBLE_MASK); + + snprintf(dd->boardversion, BOARD_VERS_MAX, + "ChipABI %u.%u, %s, ChipRev %u.%u, SW Compat %llu\n", + HFI1_CHIP_VERS_MAJ, HFI1_CHIP_VERS_MIN, + dd->boardname, + (u32)dd->majrev, + (u32)dd->minrev, + (dd->revision >> CCE_REVISION_SW_SHIFT) + & CCE_REVISION_SW_MASK); + + ret = set_up_context_variables(dd); + if (ret) + goto bail_cleanup; + + /* set initial RXE CSRs */ + init_rxe(dd); + /* set initial TXE CSRs */ + init_txe(dd); + /* set initial non-RXE, non-TXE CSRs */ + init_other(dd); + /* set up KDETH QP prefix in both RX and TX CSRs */ + init_kdeth_qp(dd); + + /* send contexts must be set up before receive contexts */ + ret = init_send_contexts(dd); + if (ret) + goto bail_cleanup; + + ret = hfi1_create_ctxts(dd); + if (ret) + goto bail_cleanup; + + dd->rcvhdrsize = DEFAULT_RCVHDRSIZE; + /* + * rcd[0] is guaranteed to be valid by this point. Also, all + * context are using the same value, as per the module parameter. + */ + dd->rhf_offset = dd->rcd[0]->rcvhdrqentsize - sizeof(u64) / sizeof(u32); + + ret = init_pervl_scs(dd); + if (ret) + goto bail_cleanup; + + /* sdma init */ + for (i = 0; i < dd->num_pports; ++i) { + ret = sdma_init(dd, i); + if (ret) + goto bail_cleanup; + } + + /* use contexts created by hfi1_create_ctxts */ + ret = set_up_interrupts(dd); + if (ret) + goto bail_cleanup; + + /* set up LCB access - must be after set_up_interrupts() */ + init_lcb_access(dd); + + snprintf(dd->serial, SERIAL_MAX, "0x%08llx\n", + dd->base_guid & 0xFFFFFF); + + dd->oui1 = dd->base_guid >> 56 & 0xFF; + dd->oui2 = dd->base_guid >> 48 & 0xFF; + dd->oui3 = dd->base_guid >> 40 & 0xFF; + + ret = load_firmware(dd); /* asymmetric with dispose_firmware() */ + if (ret) + goto bail_clear_intr; + check_fabric_firmware_versions(dd); + + thermal_init(dd); + + ret = init_cntrs(dd); + if (ret) + goto bail_clear_intr; + + ret = init_rcverr(dd); + if (ret) + goto bail_free_cntrs; + + ret = eprom_init(dd); + if (ret) + goto bail_free_rcverr; + + goto bail; + +bail_free_rcverr: + free_rcverr(dd); +bail_free_cntrs: + free_cntrs(dd); +bail_clear_intr: + clean_up_interrupts(dd); +bail_cleanup: + hfi1_pcie_ddcleanup(dd); +bail_free: + hfi1_free_devdata(dd); + dd = ERR_PTR(ret); +bail: + return dd; +} + +static u16 delay_cycles(struct hfi1_pportdata *ppd, u32 desired_egress_rate, + u32 dw_len) +{ + u32 delta_cycles; + u32 current_egress_rate = ppd->current_egress_rate; + /* rates here are in units of 10^6 bits/sec */ + + if (desired_egress_rate == -1) + return 0; /* shouldn't happen */ + + if (desired_egress_rate >= current_egress_rate) + return 0; /* we can't help go faster, only slower */ + + delta_cycles = egress_cycles(dw_len * 4, desired_egress_rate) - + egress_cycles(dw_len * 4, current_egress_rate); + + return (u16)delta_cycles; +} + + +/** + * create_pbc - build a pbc for transmission + * @flags: special case flags or-ed in built pbc + * @srate: static rate + * @vl: vl + * @dwlen: dword length (header words + data words + pbc words) + * + * Create a PBC with the given flags, rate, VL, and length. + * + * NOTE: The PBC created will not insert any HCRC - all callers but one are + * for verbs, which does not use this PSM feature. The lone other caller + * is for the diagnostic interface which calls this if the user does not + * supply their own PBC. + */ +u64 create_pbc(struct hfi1_pportdata *ppd, u64 flags, int srate_mbs, u32 vl, + u32 dw_len) +{ + u64 pbc, delay = 0; + + if (unlikely(srate_mbs)) + delay = delay_cycles(ppd, srate_mbs, dw_len); + + pbc = flags + | (delay << PBC_STATIC_RATE_CONTROL_COUNT_SHIFT) + | ((u64)PBC_IHCRC_NONE << PBC_INSERT_HCRC_SHIFT) + | (vl & PBC_VL_MASK) << PBC_VL_SHIFT + | (dw_len & PBC_LENGTH_DWS_MASK) + << PBC_LENGTH_DWS_SHIFT; + + return pbc; +} + +#define SBUS_THERMAL 0x4f +#define SBUS_THERM_MONITOR_MODE 0x1 + +#define THERM_FAILURE(dev, ret, reason) \ + dd_dev_err((dd), \ + "Thermal sensor initialization failed: %s (%d)\n", \ + (reason), (ret)) + +/* + * Initialize the Avago Thermal sensor. + * + * After initialization, enable polling of thermal sensor through + * SBus interface. In order for this to work, the SBus Master + * firmware has to be loaded due to the fact that the HW polling + * logic uses SBus interrupts, which are not supported with + * default firmware. Otherwise, no data will be returned through + * the ASIC_STS_THERM CSR. + */ +static int thermal_init(struct hfi1_devdata *dd) +{ + int ret = 0; + + if (dd->icode != ICODE_RTL_SILICON || + !(dd->flags & HFI1_DO_INIT_ASIC)) + return ret; + + acquire_hw_mutex(dd); + dd_dev_info(dd, "Initializing thermal sensor\n"); + /* Thermal Sensor Initialization */ + /* Step 1: Reset the Thermal SBus Receiver */ + ret = sbus_request_slow(dd, SBUS_THERMAL, 0x0, + RESET_SBUS_RECEIVER, 0); + if (ret) { + THERM_FAILURE(dd, ret, "Bus Reset"); + goto done; + } + /* Step 2: Set Reset bit in Thermal block */ + ret = sbus_request_slow(dd, SBUS_THERMAL, 0x0, + WRITE_SBUS_RECEIVER, 0x1); + if (ret) { + THERM_FAILURE(dd, ret, "Therm Block Reset"); + goto done; + } + /* Step 3: Write clock divider value (100MHz -> 2MHz) */ + ret = sbus_request_slow(dd, SBUS_THERMAL, 0x1, + WRITE_SBUS_RECEIVER, 0x32); + if (ret) { + THERM_FAILURE(dd, ret, "Write Clock Div"); + goto done; + } + /* Step 4: Select temperature mode */ + ret = sbus_request_slow(dd, SBUS_THERMAL, 0x3, + WRITE_SBUS_RECEIVER, + SBUS_THERM_MONITOR_MODE); + if (ret) { + THERM_FAILURE(dd, ret, "Write Mode Sel"); + goto done; + } + /* Step 5: De-assert block reset and start conversion */ + ret = sbus_request_slow(dd, SBUS_THERMAL, 0x0, + WRITE_SBUS_RECEIVER, 0x2); + if (ret) { + THERM_FAILURE(dd, ret, "Write Reset Deassert"); + goto done; + } + /* Step 5.1: Wait for first conversion (21.5ms per spec) */ + msleep(22); + + /* Enable polling of thermal readings */ + write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x1); +done: + release_hw_mutex(dd); + return ret; +} + +static void handle_temp_err(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd = &dd->pport[0]; + /* + * Thermal Critical Interrupt + * Put the device into forced freeze mode, take link down to + * offline, and put DC into reset. + */ + dd_dev_emerg(dd, + "Critical temperature reached! Forcing device into freeze mode!\n"); + dd->flags |= HFI1_FORCED_FREEZE; + start_freeze_handling(ppd, FREEZE_SELF|FREEZE_ABORT); + /* + * Shut DC down as much and as quickly as possible. + * + * Step 1: Take the link down to OFFLINE. This will cause the + * 8051 to put the Serdes in reset. However, we don't want to + * go through the entire link state machine since we want to + * shutdown ASAP. Furthermore, this is not a graceful shutdown + * but rather an attempt to save the chip. + * Code below is almost the same as quiet_serdes() but avoids + * all the extra work and the sleeps. + */ + ppd->driver_link_ready = 0; + ppd->link_enabled = 0; + set_physical_link_state(dd, PLS_OFFLINE | + (OPA_LINKDOWN_REASON_SMA_DISABLED << 8)); + /* + * Step 2: Shutdown LCB and 8051 + * After shutdown, do not restore DC_CFG_RESET value. + */ + dc_shutdown(dd); +} diff --git a/drivers/staging/rdma/hfi1/chip.h b/drivers/staging/rdma/hfi1/chip.h new file mode 100644 index 0000000000000..f89a432c7334e --- /dev/null +++ b/drivers/staging/rdma/hfi1/chip.h @@ -0,0 +1,1035 @@ +#ifndef _CHIP_H +#define _CHIP_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * This file contains all of the defines that is specific to the HFI chip + */ + +/* sizes */ +#define CCE_NUM_MSIX_VECTORS 256 +#define CCE_NUM_INT_CSRS 12 +#define CCE_NUM_INT_MAP_CSRS 96 +#define NUM_INTERRUPT_SOURCES 768 +#define RXE_NUM_CONTEXTS 160 +#define RXE_PER_CONTEXT_SIZE 0x1000 /* 4k */ +#define RXE_NUM_TID_FLOWS 32 +#define RXE_NUM_DATA_VL 8 +#define TXE_NUM_CONTEXTS 160 +#define TXE_NUM_SDMA_ENGINES 16 +#define NUM_CONTEXTS_PER_SET 8 +#define VL_ARB_HIGH_PRIO_TABLE_SIZE 16 +#define VL_ARB_LOW_PRIO_TABLE_SIZE 16 +#define VL_ARB_TABLE_SIZE 16 +#define TXE_NUM_32_BIT_COUNTER 7 +#define TXE_NUM_64_BIT_COUNTER 30 +#define TXE_NUM_DATA_VL 8 +#define TXE_PIO_SIZE (32 * 0x100000) /* 32 MB */ +#define PIO_BLOCK_SIZE 64 /* bytes */ +#define SDMA_BLOCK_SIZE 64 /* bytes */ +#define RCV_BUF_BLOCK_SIZE 64 /* bytes */ +#define PIO_CMASK 0x7ff /* counter mask for free and fill counters */ +#define MAX_EAGER_ENTRIES 2048 /* max receive eager entries */ +#define MAX_TID_PAIR_ENTRIES 1024 /* max receive expected pairs */ +/* Virtual? Allocation Unit, defined as AU = 8*2^vAU, 64 bytes, AU is fixed + at 64 bytes for all generation one devices */ +#define CM_VAU 3 +/* HFI link credit count, AKA receive buffer depth (RBUF_DEPTH) */ +#define CM_GLOBAL_CREDITS 0x940 +/* Number of PKey entries in the HW */ +#define MAX_PKEY_VALUES 16 + +#include "chip_registers.h" + +#define RXE_PER_CONTEXT_USER (RXE + RXE_PER_CONTEXT_OFFSET) +#define TXE_PIO_SEND (TXE + TXE_PIO_SEND_OFFSET) + +/* PBC flags */ +#define PBC_INTR (1ull << 31) +#define PBC_DC_INFO_SHIFT (30) +#define PBC_DC_INFO (1ull << PBC_DC_INFO_SHIFT) +#define PBC_TEST_EBP (1ull << 29) +#define PBC_PACKET_BYPASS (1ull << 28) +#define PBC_CREDIT_RETURN (1ull << 25) +#define PBC_INSERT_BYPASS_ICRC (1ull << 24) +#define PBC_TEST_BAD_ICRC (1ull << 23) +#define PBC_FECN (1ull << 22) + +/* PbcInsertHcrc field settings */ +#define PBC_IHCRC_LKDETH 0x0 /* insert @ local KDETH offset */ +#define PBC_IHCRC_GKDETH 0x1 /* insert @ global KDETH offset */ +#define PBC_IHCRC_NONE 0x2 /* no HCRC inserted */ + +/* PBC fields */ +#define PBC_STATIC_RATE_CONTROL_COUNT_SHIFT 32 +#define PBC_STATIC_RATE_CONTROL_COUNT_MASK 0xffffull +#define PBC_STATIC_RATE_CONTROL_COUNT_SMASK \ + (PBC_STATIC_RATE_CONTROL_COUNT_MASK << \ + PBC_STATIC_RATE_CONTROL_COUNT_SHIFT) + +#define PBC_INSERT_HCRC_SHIFT 26 +#define PBC_INSERT_HCRC_MASK 0x3ull +#define PBC_INSERT_HCRC_SMASK \ + (PBC_INSERT_HCRC_MASK << PBC_INSERT_HCRC_SHIFT) + +#define PBC_VL_SHIFT 12 +#define PBC_VL_MASK 0xfull +#define PBC_VL_SMASK (PBC_VL_MASK << PBC_VL_SHIFT) + +#define PBC_LENGTH_DWS_SHIFT 0 +#define PBC_LENGTH_DWS_MASK 0xfffull +#define PBC_LENGTH_DWS_SMASK \ + (PBC_LENGTH_DWS_MASK << PBC_LENGTH_DWS_SHIFT) + +/* Credit Return Fields */ +#define CR_COUNTER_SHIFT 0 +#define CR_COUNTER_MASK 0x7ffull +#define CR_COUNTER_SMASK (CR_COUNTER_MASK << CR_COUNTER_SHIFT) + +#define CR_STATUS_SHIFT 11 +#define CR_STATUS_MASK 0x1ull +#define CR_STATUS_SMASK (CR_STATUS_MASK << CR_STATUS_SHIFT) + +#define CR_CREDIT_RETURN_DUE_TO_PBC_SHIFT 12 +#define CR_CREDIT_RETURN_DUE_TO_PBC_MASK 0x1ull +#define CR_CREDIT_RETURN_DUE_TO_PBC_SMASK \ + (CR_CREDIT_RETURN_DUE_TO_PBC_MASK << \ + CR_CREDIT_RETURN_DUE_TO_PBC_SHIFT) + +#define CR_CREDIT_RETURN_DUE_TO_THRESHOLD_SHIFT 13 +#define CR_CREDIT_RETURN_DUE_TO_THRESHOLD_MASK 0x1ull +#define CR_CREDIT_RETURN_DUE_TO_THRESHOLD_SMASK \ + (CR_CREDIT_RETURN_DUE_TO_THRESHOLD_MASK << \ + CR_CREDIT_RETURN_DUE_TO_THRESHOLD_SHIFT) + +#define CR_CREDIT_RETURN_DUE_TO_ERR_SHIFT 14 +#define CR_CREDIT_RETURN_DUE_TO_ERR_MASK 0x1ull +#define CR_CREDIT_RETURN_DUE_TO_ERR_SMASK \ + (CR_CREDIT_RETURN_DUE_TO_ERR_MASK << \ + CR_CREDIT_RETURN_DUE_TO_ERR_SHIFT) + +#define CR_CREDIT_RETURN_DUE_TO_FORCE_SHIFT 15 +#define CR_CREDIT_RETURN_DUE_TO_FORCE_MASK 0x1ull +#define CR_CREDIT_RETURN_DUE_TO_FORCE_SMASK \ + (CR_CREDIT_RETURN_DUE_TO_FORCE_MASK << \ + CR_CREDIT_RETURN_DUE_TO_FORCE_SHIFT) + +/* interrupt source numbers */ +#define IS_GENERAL_ERR_START 0 +#define IS_SDMAENG_ERR_START 16 +#define IS_SENDCTXT_ERR_START 32 +#define IS_SDMA_START 192 /* includes SDmaProgress,SDmaIdle */ +#define IS_VARIOUS_START 240 +#define IS_DC_START 248 +#define IS_RCVAVAIL_START 256 +#define IS_RCVURGENT_START 416 +#define IS_SENDCREDIT_START 576 +#define IS_RESERVED_START 736 +#define IS_MAX_SOURCES 768 + +/* derived interrupt source values */ +#define IS_GENERAL_ERR_END IS_SDMAENG_ERR_START +#define IS_SDMAENG_ERR_END IS_SENDCTXT_ERR_START +#define IS_SENDCTXT_ERR_END IS_SDMA_START +#define IS_SDMA_END IS_VARIOUS_START +#define IS_VARIOUS_END IS_DC_START +#define IS_DC_END IS_RCVAVAIL_START +#define IS_RCVAVAIL_END IS_RCVURGENT_START +#define IS_RCVURGENT_END IS_SENDCREDIT_START +#define IS_SENDCREDIT_END IS_RESERVED_START +#define IS_RESERVED_END IS_MAX_SOURCES + +/* absolute interrupt numbers for QSFP1Int and QSFP2Int */ +#define QSFP1_INT 242 +#define QSFP2_INT 243 + +/* DCC_CFG_PORT_CONFIG logical link states */ +#define LSTATE_DOWN 0x1 +#define LSTATE_INIT 0x2 +#define LSTATE_ARMED 0x3 +#define LSTATE_ACTIVE 0x4 + +/* DC8051_STS_CUR_STATE port values (physical link states) */ +#define PLS_DISABLED 0x30 +#define PLS_OFFLINE 0x90 +#define PLS_OFFLINE_QUIET 0x90 +#define PLS_OFFLINE_PLANNED_DOWN_INFORM 0x91 +#define PLS_OFFLINE_READY_TO_QUIET_LT 0x92 +#define PLS_OFFLINE_REPORT_FAILURE 0x93 +#define PLS_OFFLINE_READY_TO_QUIET_BCC 0x94 +#define PLS_POLLING 0x20 +#define PLS_POLLING_QUIET 0x20 +#define PLS_POLLING_ACTIVE 0x21 +#define PLS_CONFIGPHY 0x40 +#define PLS_CONFIGPHY_DEBOUCE 0x40 +#define PLS_CONFIGPHY_ESTCOMM 0x41 +#define PLS_CONFIGPHY_ESTCOMM_TXRX_HUNT 0x42 +#define PLS_CONFIGPHY_ESTcOMM_LOCAL_COMPLETE 0x43 +#define PLS_CONFIGPHY_OPTEQ 0x44 +#define PLS_CONFIGPHY_OPTEQ_OPTIMIZING 0x44 +#define PLS_CONFIGPHY_OPTEQ_LOCAL_COMPLETE 0x45 +#define PLS_CONFIGPHY_VERIFYCAP 0x46 +#define PLS_CONFIGPHY_VERIFYCAP_EXCHANGE 0x46 +#define PLS_CONFIGPHY_VERIFYCAP_LOCAL_COMPLETE 0x47 +#define PLS_CONFIGLT 0x48 +#define PLS_CONFIGLT_CONFIGURE 0x48 +#define PLS_CONFIGLT_LINK_TRANSFER_ACTIVE 0x49 +#define PLS_LINKUP 0x50 +#define PLS_PHYTEST 0xB0 +#define PLS_INTERNAL_SERDES_LOOPBACK 0xe1 +#define PLS_QUICK_LINKUP 0xe2 + +/* DC_DC8051_CFG_HOST_CMD_0.REQ_TYPE - 8051 host commands */ +#define HCMD_LOAD_CONFIG_DATA 0x01 +#define HCMD_READ_CONFIG_DATA 0x02 +#define HCMD_CHANGE_PHY_STATE 0x03 +#define HCMD_SEND_LCB_IDLE_MSG 0x04 +#define HCMD_MISC 0x05 +#define HCMD_READ_LCB_IDLE_MSG 0x06 +#define HCMD_READ_LCB_CSR 0x07 +#define HCMD_INTERFACE_TEST 0xff + +/* DC_DC8051_CFG_HOST_CMD_1.RETURN_CODE - 8051 host command return */ +#define HCMD_SUCCESS 2 + +/* DC_DC8051_DBG_ERR_INFO_SET_BY_8051.ERROR - error flags */ +#define SPICO_ROM_FAILED (1 << 0) +#define UNKNOWN_FRAME (1 << 1) +#define TARGET_BER_NOT_MET (1 << 2) +#define FAILED_SERDES_INTERNAL_LOOPBACK (1 << 3) +#define FAILED_SERDES_INIT (1 << 4) +#define FAILED_LNI_POLLING (1 << 5) +#define FAILED_LNI_DEBOUNCE (1 << 6) +#define FAILED_LNI_ESTBCOMM (1 << 7) +#define FAILED_LNI_OPTEQ (1 << 8) +#define FAILED_LNI_VERIFY_CAP1 (1 << 9) +#define FAILED_LNI_VERIFY_CAP2 (1 << 10) +#define FAILED_LNI_CONFIGLT (1 << 11) + +#define FAILED_LNI (FAILED_LNI_POLLING | FAILED_LNI_DEBOUNCE \ + | FAILED_LNI_ESTBCOMM | FAILED_LNI_OPTEQ \ + | FAILED_LNI_VERIFY_CAP1 \ + | FAILED_LNI_VERIFY_CAP2 \ + | FAILED_LNI_CONFIGLT) + +/* DC_DC8051_DBG_ERR_INFO_SET_BY_8051.HOST_MSG - host message flags */ +#define HOST_REQ_DONE (1 << 0) +#define BC_PWR_MGM_MSG (1 << 1) +#define BC_SMA_MSG (1 << 2) +#define BC_BCC_UNKOWN_MSG (1 << 3) +#define BC_IDLE_UNKNOWN_MSG (1 << 4) +#define EXT_DEVICE_CFG_REQ (1 << 5) +#define VERIFY_CAP_FRAME (1 << 6) +#define LINKUP_ACHIEVED (1 << 7) +#define LINK_GOING_DOWN (1 << 8) +#define LINK_WIDTH_DOWNGRADED (1 << 9) + +/* DC_DC8051_CFG_EXT_DEV_1.REQ_TYPE - 8051 host requests */ +#define HREQ_LOAD_CONFIG 0x01 +#define HREQ_SAVE_CONFIG 0x02 +#define HREQ_READ_CONFIG 0x03 +#define HREQ_SET_TX_EQ_ABS 0x04 +#define HREQ_SET_TX_EQ_REL 0x05 +#define HREQ_ENABLE 0x06 +#define HREQ_CONFIG_DONE 0xfe +#define HREQ_INTERFACE_TEST 0xff + +/* DC_DC8051_CFG_EXT_DEV_0.RETURN_CODE - 8051 host request return codes */ +#define HREQ_INVALID 0x01 +#define HREQ_SUCCESS 0x02 +#define HREQ_NOT_SUPPORTED 0x03 +#define HREQ_FEATURE_NOT_SUPPORTED 0x04 /* request specific feature */ +#define HREQ_REQUEST_REJECTED 0xfe +#define HREQ_EXECUTION_ONGOING 0xff + +/* MISC host command functions */ +#define HCMD_MISC_REQUEST_LCB_ACCESS 0x1 +#define HCMD_MISC_GRANT_LCB_ACCESS 0x2 + +/* idle flit message types */ +#define IDLE_PHYSICAL_LINK_MGMT 0x1 +#define IDLE_CRU 0x2 +#define IDLE_SMA 0x3 +#define IDLE_POWER_MGMT 0x4 + +/* idle flit message send fields (both send and read) */ +#define IDLE_PAYLOAD_MASK 0xffffffffffull /* 40 bits */ +#define IDLE_PAYLOAD_SHIFT 8 +#define IDLE_MSG_TYPE_MASK 0xf +#define IDLE_MSG_TYPE_SHIFT 0 + +/* idle flit message read fields */ +#define READ_IDLE_MSG_TYPE_MASK 0xf +#define READ_IDLE_MSG_TYPE_SHIFT 0 + +/* SMA idle flit payload commands */ +#define SMA_IDLE_ARM 1 +#define SMA_IDLE_ACTIVE 2 + +/* DC_DC8051_CFG_MODE.GENERAL bits */ +#define DISABLE_SELF_GUID_CHECK 0x2 + +/* + * Eager buffer minimum and maximum sizes supported by the hardware. + * All power-of-two sizes in between are supported as well. + * MAX_EAGER_BUFFER_TOTAL is the maximum size of memory + * allocatable for Eager buffer to a single context. All others + * are limits for the RcvArray entries. + */ +#define MIN_EAGER_BUFFER (4 * 1024) +#define MAX_EAGER_BUFFER (256 * 1024) +#define MAX_EAGER_BUFFER_TOTAL (64 * (1 << 20)) /* max per ctxt 64MB */ +#define MAX_EXPECTED_BUFFER (2048 * 1024) + +/* + * Receive expected base and count and eager base and count increment - + * the CSR fields hold multiples of this value. + */ +#define RCV_SHIFT 3 +#define RCV_INCREMENT (1 << RCV_SHIFT) + +/* + * Receive header queue entry increment - the CSR holds multiples of + * this value. + */ +#define HDRQ_SIZE_SHIFT 5 +#define HDRQ_INCREMENT (1 << HDRQ_SIZE_SHIFT) + +/* + * Freeze handling flags + */ +#define FREEZE_ABORT 0x01 /* do not do recovery */ +#define FREEZE_SELF 0x02 /* initiate the freeze */ +#define FREEZE_LINK_DOWN 0x04 /* link is down */ + +/* + * Chip implementation codes. + */ +#define ICODE_RTL_SILICON 0x00 +#define ICODE_RTL_VCS_SIMULATION 0x01 +#define ICODE_FPGA_EMULATION 0x02 +#define ICODE_FUNCTIONAL_SIMULATOR 0x03 + +/* + * 8051 data memory size. + */ +#define DC8051_DATA_MEM_SIZE 0x1000 + +/* + * 8051 firmware registers + */ +#define NUM_GENERAL_FIELDS 0x17 +#define NUM_LANE_FIELDS 0x8 + +/* 8051 general register Field IDs */ +#define TX_SETTINGS 0x06 +#define VERIFY_CAP_LOCAL_PHY 0x07 +#define VERIFY_CAP_LOCAL_FABRIC 0x08 +#define VERIFY_CAP_LOCAL_LINK_WIDTH 0x09 +#define LOCAL_DEVICE_ID 0x0a +#define LOCAL_LNI_INFO 0x0c +#define REMOTE_LNI_INFO 0x0d +#define MISC_STATUS 0x0e +#define VERIFY_CAP_REMOTE_PHY 0x0f +#define VERIFY_CAP_REMOTE_FABRIC 0x10 +#define VERIFY_CAP_REMOTE_LINK_WIDTH 0x11 +#define LAST_LOCAL_STATE_COMPLETE 0x12 +#define LAST_REMOTE_STATE_COMPLETE 0x13 +#define LINK_QUALITY_INFO 0x14 +#define REMOTE_DEVICE_ID 0x15 + +/* Lane ID for general configuration registers */ +#define GENERAL_CONFIG 4 + +/* LOAD_DATA 8051 command shifts and fields */ +#define LOAD_DATA_FIELD_ID_SHIFT 40 +#define LOAD_DATA_FIELD_ID_MASK 0xfull +#define LOAD_DATA_LANE_ID_SHIFT 32 +#define LOAD_DATA_LANE_ID_MASK 0xfull +#define LOAD_DATA_DATA_SHIFT 0x0 +#define LOAD_DATA_DATA_MASK 0xffffffffull + +/* READ_DATA 8051 command shifts and fields */ +#define READ_DATA_FIELD_ID_SHIFT 40 +#define READ_DATA_FIELD_ID_MASK 0xffull +#define READ_DATA_LANE_ID_SHIFT 32 +#define READ_DATA_LANE_ID_MASK 0xffull +#define READ_DATA_DATA_SHIFT 0x0 +#define READ_DATA_DATA_MASK 0xffffffffull + +/* TX settings fields */ +#define ENABLE_LANE_TX_SHIFT 0 +#define ENABLE_LANE_TX_MASK 0xff +#define TX_POLARITY_INVERSION_SHIFT 8 +#define TX_POLARITY_INVERSION_MASK 0xff +#define RX_POLARITY_INVERSION_SHIFT 16 +#define RX_POLARITY_INVERSION_MASK 0xff +#define MAX_RATE_SHIFT 24 +#define MAX_RATE_MASK 0xff + +/* verify capability PHY fields */ +#define CONTINIOUS_REMOTE_UPDATE_SUPPORT_SHIFT 0x4 +#define CONTINIOUS_REMOTE_UPDATE_SUPPORT_MASK 0x1 +#define POWER_MANAGEMENT_SHIFT 0x0 +#define POWER_MANAGEMENT_MASK 0xf + +/* 8051 lane register Field IDs */ +#define SPICO_FW_VERSION 0x7 /* SPICO firmware version */ + +/* SPICO firmware version fields */ +#define SPICO_ROM_VERSION_SHIFT 0 +#define SPICO_ROM_VERSION_MASK 0xffff +#define SPICO_ROM_PROD_ID_SHIFT 16 +#define SPICO_ROM_PROD_ID_MASK 0xffff + +/* verify capability fabric fields */ +#define VAU_SHIFT 0 +#define VAU_MASK 0x0007 +#define Z_SHIFT 3 +#define Z_MASK 0x0001 +#define VCU_SHIFT 4 +#define VCU_MASK 0x0007 +#define VL15BUF_SHIFT 8 +#define VL15BUF_MASK 0x0fff +#define CRC_SIZES_SHIFT 20 +#define CRC_SIZES_MASK 0x7 + +/* verify capability local link width fields */ +#define LINK_WIDTH_SHIFT 0 /* also for remote link width */ +#define LINK_WIDTH_MASK 0xffff /* also for remote link width */ +#define LOCAL_FLAG_BITS_SHIFT 16 +#define LOCAL_FLAG_BITS_MASK 0xff +#define MISC_CONFIG_BITS_SHIFT 24 +#define MISC_CONFIG_BITS_MASK 0xff + +/* verify capability remote link width fields */ +#define REMOTE_TX_RATE_SHIFT 16 +#define REMOTE_TX_RATE_MASK 0xff + +/* LOCAL_DEVICE_ID fields */ +#define LOCAL_DEVICE_REV_SHIFT 0 +#define LOCAL_DEVICE_REV_MASK 0xff +#define LOCAL_DEVICE_ID_SHIFT 8 +#define LOCAL_DEVICE_ID_MASK 0xffff + +/* REMOTE_DEVICE_ID fields */ +#define REMOTE_DEVICE_REV_SHIFT 0 +#define REMOTE_DEVICE_REV_MASK 0xff +#define REMOTE_DEVICE_ID_SHIFT 8 +#define REMOTE_DEVICE_ID_MASK 0xffff + +/* local LNI link width fields */ +#define ENABLE_LANE_RX_SHIFT 16 +#define ENABLE_LANE_RX_MASK 0xff + +/* mask, shift for reading 'mgmt_enabled' value from REMOTE_LNI_INFO field */ +#define MGMT_ALLOWED_SHIFT 23 +#define MGMT_ALLOWED_MASK 0x1 + +/* mask, shift for 'link_quality' within LINK_QUALITY_INFO field */ +#define LINK_QUALITY_SHIFT 24 +#define LINK_QUALITY_MASK 0x7 + +/* + * mask, shift for reading 'planned_down_remote_reason_code' + * from LINK_QUALITY_INFO field + */ +#define DOWN_REMOTE_REASON_SHIFT 16 +#define DOWN_REMOTE_REASON_MASK 0xff + +/* verify capability PHY power management bits */ +#define PWRM_BER_CONTROL 0x1 +#define PWRM_BANDWIDTH_CONTROL 0x2 + +/* verify capability fabric CRC size bits */ +enum { + CAP_CRC_14B = (1 << 0), /* 14b CRC */ + CAP_CRC_48B = (1 << 1), /* 48b CRC */ + CAP_CRC_12B_16B_PER_LANE = (1 << 2) /* 12b-16b per lane CRC */ +}; + +#define SUPPORTED_CRCS (CAP_CRC_14B | CAP_CRC_48B) + +/* misc status version fields */ +#define STS_FM_VERSION_A_SHIFT 16 +#define STS_FM_VERSION_A_MASK 0xff +#define STS_FM_VERSION_B_SHIFT 24 +#define STS_FM_VERSION_B_MASK 0xff + +/* LCB_CFG_CRC_MODE TX_VAL and RX_VAL CRC mode values */ +#define LCB_CRC_16B 0x0 /* 16b CRC */ +#define LCB_CRC_14B 0x1 /* 14b CRC */ +#define LCB_CRC_48B 0x2 /* 48b CRC */ +#define LCB_CRC_12B_16B_PER_LANE 0x3 /* 12b-16b per lane CRC */ + +/* the following enum is (almost) a copy/paste of the definition + * in the OPA spec, section 20.2.2.6.8 (PortInfo) */ +enum { + PORT_LTP_CRC_MODE_NONE = 0, + PORT_LTP_CRC_MODE_14 = 1, /* 14-bit LTP CRC mode (optional) */ + PORT_LTP_CRC_MODE_16 = 2, /* 16-bit LTP CRC mode */ + PORT_LTP_CRC_MODE_48 = 4, + /* 48-bit overlapping LTP CRC mode (optional) */ + PORT_LTP_CRC_MODE_PER_LANE = 8 + /* 12 to 16 bit per lane LTP CRC mode (optional) */ +}; + +/* timeouts */ +#define LINK_RESTART_DELAY 1000 /* link restart delay, in ms */ +#define TIMEOUT_8051_START 5000 /* 8051 start timeout, in ms */ +#define DC8051_COMMAND_TIMEOUT 20000 /* DC8051 command timeout, in ms */ +#define FREEZE_STATUS_TIMEOUT 20 /* wait for freeze indicators, in ms */ +#define VL_STATUS_CLEAR_TIMEOUT 5000 /* per-VL status clear, in ms */ +#define CCE_STATUS_TIMEOUT 10 /* time to clear CCE Status, in ms */ + +/* cclock tick time, in picoseconds per tick: 1/speed * 10^12 */ +#define ASIC_CCLOCK_PS 1242 /* 805 MHz */ +#define FPGA_CCLOCK_PS 30300 /* 33 MHz */ + +/* + * Mask of enabled MISC errors. Do not enable the two RSA engine errors - + * see firmware.c:run_rsa() for details. + */ +#define DRIVER_MISC_MASK \ + (~(MISC_ERR_STATUS_MISC_FW_AUTH_FAILED_ERR_SMASK \ + | MISC_ERR_STATUS_MISC_KEY_MISMATCH_ERR_SMASK)) + +/* valid values for the loopback module parameter */ +#define LOOPBACK_NONE 0 /* no loopback - default */ +#define LOOPBACK_SERDES 1 +#define LOOPBACK_LCB 2 +#define LOOPBACK_CABLE 3 /* external cable */ + +/* read and write hardware registers */ +u64 read_csr(const struct hfi1_devdata *dd, u32 offset); +void write_csr(const struct hfi1_devdata *dd, u32 offset, u64 value); + +/* + * The *_kctxt_* flavor of the CSR read/write functions are for + * per-context or per-SDMA CSRs that are not mappable to user-space. + * Their spacing is not a PAGE_SIZE multiple. + */ +static inline u64 read_kctxt_csr(const struct hfi1_devdata *dd, int ctxt, + u32 offset0) +{ + /* kernel per-context CSRs are separated by 0x100 */ + return read_csr(dd, offset0 + (0x100 * ctxt)); +} + +static inline void write_kctxt_csr(struct hfi1_devdata *dd, int ctxt, + u32 offset0, u64 value) +{ + /* kernel per-context CSRs are separated by 0x100 */ + write_csr(dd, offset0 + (0x100 * ctxt), value); +} + +int read_lcb_csr(struct hfi1_devdata *dd, u32 offset, u64 *data); +int write_lcb_csr(struct hfi1_devdata *dd, u32 offset, u64 data); + +void __iomem *get_csr_addr( + struct hfi1_devdata *dd, + u32 offset); + +static inline void __iomem *get_kctxt_csr_addr( + struct hfi1_devdata *dd, + int ctxt, + u32 offset0) +{ + return get_csr_addr(dd, offset0 + (0x100 * ctxt)); +} + +/* + * The *_uctxt_* flavor of the CSR read/write functions are for + * per-context CSRs that are mappable to user space. All these CSRs + * are spaced by a PAGE_SIZE multiple in order to be mappable to + * different processes without exposing other contexts' CSRs + */ +static inline u64 read_uctxt_csr(const struct hfi1_devdata *dd, int ctxt, + u32 offset0) +{ + /* user per-context CSRs are separated by 0x1000 */ + return read_csr(dd, offset0 + (0x1000 * ctxt)); +} + +static inline void write_uctxt_csr(struct hfi1_devdata *dd, int ctxt, + u32 offset0, u64 value) +{ + /* user per-context CSRs are separated by 0x1000 */ + write_csr(dd, offset0 + (0x1000 * ctxt), value); +} + +u64 create_pbc(struct hfi1_pportdata *ppd, u64, int, u32, u32); + +/* firmware.c */ +#define NUM_PCIE_SERDES 16 /* number of PCIe serdes on the SBus */ +extern const u8 pcie_serdes_broadcast[]; +extern const u8 pcie_pcs_addrs[2][NUM_PCIE_SERDES]; +/* SBus commands */ +#define RESET_SBUS_RECEIVER 0x20 +#define WRITE_SBUS_RECEIVER 0x21 +void sbus_request(struct hfi1_devdata *dd, + u8 receiver_addr, u8 data_addr, u8 command, u32 data_in); +int sbus_request_slow(struct hfi1_devdata *dd, + u8 receiver_addr, u8 data_addr, u8 command, u32 data_in); +void set_sbus_fast_mode(struct hfi1_devdata *dd); +void clear_sbus_fast_mode(struct hfi1_devdata *dd); +int hfi1_firmware_init(struct hfi1_devdata *dd); +int load_pcie_firmware(struct hfi1_devdata *dd); +int load_firmware(struct hfi1_devdata *dd); +void dispose_firmware(void); +int acquire_hw_mutex(struct hfi1_devdata *dd); +void release_hw_mutex(struct hfi1_devdata *dd); +void fabric_serdes_reset(struct hfi1_devdata *dd); +int read_8051_data(struct hfi1_devdata *dd, u32 addr, u32 len, u64 *result); + +/* chip.c */ +void read_misc_status(struct hfi1_devdata *dd, u8 *ver_a, u8 *ver_b); +void read_guid(struct hfi1_devdata *dd); +int wait_fm_ready(struct hfi1_devdata *dd, u32 mstimeout); +void set_link_down_reason(struct hfi1_pportdata *ppd, u8 lcl_reason, + u8 neigh_reason, u8 rem_reason); +int set_link_state(struct hfi1_pportdata *, u32 state); +int port_ltp_to_cap(int port_ltp); +void handle_verify_cap(struct work_struct *work); +void handle_freeze(struct work_struct *work); +void handle_link_up(struct work_struct *work); +void handle_link_down(struct work_struct *work); +void handle_link_downgrade(struct work_struct *work); +void handle_link_bounce(struct work_struct *work); +void handle_sma_message(struct work_struct *work); +void start_freeze_handling(struct hfi1_pportdata *ppd, int flags); +int send_idle_sma(struct hfi1_devdata *dd, u64 message); +int start_link(struct hfi1_pportdata *ppd); +void init_qsfp(struct hfi1_pportdata *ppd); +int bringup_serdes(struct hfi1_pportdata *ppd); +void set_intr_state(struct hfi1_devdata *dd, u32 enable); +void apply_link_downgrade_policy(struct hfi1_pportdata *ppd, + int refresh_widths); +void update_usrhead(struct hfi1_ctxtdata *, u32, u32, u32, u32, u32); +int stop_drain_data_vls(struct hfi1_devdata *dd); +int open_fill_data_vls(struct hfi1_devdata *dd); +u32 ns_to_cclock(struct hfi1_devdata *dd, u32 ns); +u32 cclock_to_ns(struct hfi1_devdata *dd, u32 cclock); +void get_linkup_link_widths(struct hfi1_pportdata *ppd); +void read_ltp_rtt(struct hfi1_devdata *dd); +void clear_linkup_counters(struct hfi1_devdata *dd); +u32 hdrqempty(struct hfi1_ctxtdata *rcd); +int is_a0(struct hfi1_devdata *dd); +int is_ax(struct hfi1_devdata *dd); +int is_bx(struct hfi1_devdata *dd); +u32 read_physical_state(struct hfi1_devdata *dd); +u32 chip_to_opa_pstate(struct hfi1_devdata *dd, u32 chip_pstate); +u32 get_logical_state(struct hfi1_pportdata *ppd); +const char *opa_lstate_name(u32 lstate); +const char *opa_pstate_name(u32 pstate); +u32 driver_physical_state(struct hfi1_pportdata *ppd); +u32 driver_logical_state(struct hfi1_pportdata *ppd); + +int acquire_lcb_access(struct hfi1_devdata *dd, int sleep_ok); +int release_lcb_access(struct hfi1_devdata *dd, int sleep_ok); +#define LCB_START DC_LCB_CSRS +#define LCB_END DC_8051_CSRS /* next block is 8051 */ +static inline int is_lcb_offset(u32 offset) +{ + return (offset >= LCB_START && offset < LCB_END); +} + +extern uint num_vls; + +extern uint disable_integrity; +u64 read_dev_cntr(struct hfi1_devdata *dd, int index, int vl); +u64 write_dev_cntr(struct hfi1_devdata *dd, int index, int vl, u64 data); +u64 read_port_cntr(struct hfi1_pportdata *ppd, int index, int vl); +u64 write_port_cntr(struct hfi1_pportdata *ppd, int index, int vl, u64 data); + +/* Per VL indexes */ +enum { + C_VL_0 = 0, + C_VL_1, + C_VL_2, + C_VL_3, + C_VL_4, + C_VL_5, + C_VL_6, + C_VL_7, + C_VL_15, + C_VL_COUNT +}; + +static inline int vl_from_idx(int idx) +{ + return (idx == C_VL_15 ? 15 : idx); +} + +static inline int idx_from_vl(int vl) +{ + return (vl == 15 ? C_VL_15 : vl); +} + +/* Per device counter indexes */ +enum { + C_RCV_OVF = 0, + C_RX_TID_FULL, + C_RX_TID_INVALID, + C_RX_TID_FLGMS, + C_RX_CTX_RHQS, + C_RX_CTX_EGRS, + C_RCV_TID_FLSMS, + C_CCE_PCI_CR_ST, + C_CCE_PCI_TR_ST, + C_CCE_PIO_WR_ST, + C_CCE_ERR_INT, + C_CCE_SDMA_INT, + C_CCE_MISC_INT, + C_CCE_RCV_AV_INT, + C_CCE_RCV_URG_INT, + C_CCE_SEND_CR_INT, + C_DC_UNC_ERR, + C_DC_RCV_ERR, + C_DC_FM_CFG_ERR, + C_DC_RMT_PHY_ERR, + C_DC_DROPPED_PKT, + C_DC_MC_XMIT_PKTS, + C_DC_MC_RCV_PKTS, + C_DC_XMIT_CERR, + C_DC_RCV_CERR, + C_DC_RCV_FCC, + C_DC_XMIT_FCC, + C_DC_XMIT_FLITS, + C_DC_RCV_FLITS, + C_DC_XMIT_PKTS, + C_DC_RCV_PKTS, + C_DC_RX_FLIT_VL, + C_DC_RX_PKT_VL, + C_DC_RCV_FCN, + C_DC_RCV_FCN_VL, + C_DC_RCV_BCN, + C_DC_RCV_BCN_VL, + C_DC_RCV_BBL, + C_DC_RCV_BBL_VL, + C_DC_MARK_FECN, + C_DC_MARK_FECN_VL, + C_DC_TOTAL_CRC, + C_DC_CRC_LN0, + C_DC_CRC_LN1, + C_DC_CRC_LN2, + C_DC_CRC_LN3, + C_DC_CRC_MULT_LN, + C_DC_TX_REPLAY, + C_DC_RX_REPLAY, + C_DC_SEQ_CRC_CNT, + C_DC_ESC0_ONLY_CNT, + C_DC_ESC0_PLUS1_CNT, + C_DC_ESC0_PLUS2_CNT, + C_DC_REINIT_FROM_PEER_CNT, + C_DC_SBE_CNT, + C_DC_MISC_FLG_CNT, + C_DC_PRF_GOOD_LTP_CNT, + C_DC_PRF_ACCEPTED_LTP_CNT, + C_DC_PRF_RX_FLIT_CNT, + C_DC_PRF_TX_FLIT_CNT, + C_DC_PRF_CLK_CNTR, + C_DC_PG_DBG_FLIT_CRDTS_CNT, + C_DC_PG_STS_PAUSE_COMPLETE_CNT, + C_DC_PG_STS_TX_SBE_CNT, + C_DC_PG_STS_TX_MBE_CNT, + C_SW_CPU_INTR, + C_SW_CPU_RCV_LIM, + C_SW_VTX_WAIT, + C_SW_PIO_WAIT, + C_SW_KMEM_WAIT, + DEV_CNTR_LAST /* Must be kept last */ +}; + +/* Per port counter indexes */ +enum { + C_TX_UNSUP_VL = 0, + C_TX_INVAL_LEN, + C_TX_MM_LEN_ERR, + C_TX_UNDERRUN, + C_TX_FLOW_STALL, + C_TX_DROPPED, + C_TX_HDR_ERR, + C_TX_PKT, + C_TX_WORDS, + C_TX_WAIT, + C_TX_FLIT_VL, + C_TX_PKT_VL, + C_TX_WAIT_VL, + C_RX_PKT, + C_RX_WORDS, + C_SW_LINK_DOWN, + C_SW_LINK_UP, + C_SW_XMIT_DSCD, + C_SW_XMIT_DSCD_VL, + C_SW_XMIT_CSTR_ERR, + C_SW_RCV_CSTR_ERR, + C_SW_IBP_LOOP_PKTS, + C_SW_IBP_RC_RESENDS, + C_SW_IBP_RNR_NAKS, + C_SW_IBP_OTHER_NAKS, + C_SW_IBP_RC_TIMEOUTS, + C_SW_IBP_PKT_DROPS, + C_SW_IBP_DMA_WAIT, + C_SW_IBP_RC_SEQNAK, + C_SW_IBP_RC_DUPREQ, + C_SW_IBP_RDMA_SEQ, + C_SW_IBP_UNALIGNED, + C_SW_IBP_SEQ_NAK, + C_SW_CPU_RC_ACKS, + C_SW_CPU_RC_QACKS, + C_SW_CPU_RC_DELAYED_COMP, + C_RCV_HDR_OVF_0, + C_RCV_HDR_OVF_1, + C_RCV_HDR_OVF_2, + C_RCV_HDR_OVF_3, + C_RCV_HDR_OVF_4, + C_RCV_HDR_OVF_5, + C_RCV_HDR_OVF_6, + C_RCV_HDR_OVF_7, + C_RCV_HDR_OVF_8, + C_RCV_HDR_OVF_9, + C_RCV_HDR_OVF_10, + C_RCV_HDR_OVF_11, + C_RCV_HDR_OVF_12, + C_RCV_HDR_OVF_13, + C_RCV_HDR_OVF_14, + C_RCV_HDR_OVF_15, + C_RCV_HDR_OVF_16, + C_RCV_HDR_OVF_17, + C_RCV_HDR_OVF_18, + C_RCV_HDR_OVF_19, + C_RCV_HDR_OVF_20, + C_RCV_HDR_OVF_21, + C_RCV_HDR_OVF_22, + C_RCV_HDR_OVF_23, + C_RCV_HDR_OVF_24, + C_RCV_HDR_OVF_25, + C_RCV_HDR_OVF_26, + C_RCV_HDR_OVF_27, + C_RCV_HDR_OVF_28, + C_RCV_HDR_OVF_29, + C_RCV_HDR_OVF_30, + C_RCV_HDR_OVF_31, + C_RCV_HDR_OVF_32, + C_RCV_HDR_OVF_33, + C_RCV_HDR_OVF_34, + C_RCV_HDR_OVF_35, + C_RCV_HDR_OVF_36, + C_RCV_HDR_OVF_37, + C_RCV_HDR_OVF_38, + C_RCV_HDR_OVF_39, + C_RCV_HDR_OVF_40, + C_RCV_HDR_OVF_41, + C_RCV_HDR_OVF_42, + C_RCV_HDR_OVF_43, + C_RCV_HDR_OVF_44, + C_RCV_HDR_OVF_45, + C_RCV_HDR_OVF_46, + C_RCV_HDR_OVF_47, + C_RCV_HDR_OVF_48, + C_RCV_HDR_OVF_49, + C_RCV_HDR_OVF_50, + C_RCV_HDR_OVF_51, + C_RCV_HDR_OVF_52, + C_RCV_HDR_OVF_53, + C_RCV_HDR_OVF_54, + C_RCV_HDR_OVF_55, + C_RCV_HDR_OVF_56, + C_RCV_HDR_OVF_57, + C_RCV_HDR_OVF_58, + C_RCV_HDR_OVF_59, + C_RCV_HDR_OVF_60, + C_RCV_HDR_OVF_61, + C_RCV_HDR_OVF_62, + C_RCV_HDR_OVF_63, + C_RCV_HDR_OVF_64, + C_RCV_HDR_OVF_65, + C_RCV_HDR_OVF_66, + C_RCV_HDR_OVF_67, + C_RCV_HDR_OVF_68, + C_RCV_HDR_OVF_69, + C_RCV_HDR_OVF_70, + C_RCV_HDR_OVF_71, + C_RCV_HDR_OVF_72, + C_RCV_HDR_OVF_73, + C_RCV_HDR_OVF_74, + C_RCV_HDR_OVF_75, + C_RCV_HDR_OVF_76, + C_RCV_HDR_OVF_77, + C_RCV_HDR_OVF_78, + C_RCV_HDR_OVF_79, + C_RCV_HDR_OVF_80, + C_RCV_HDR_OVF_81, + C_RCV_HDR_OVF_82, + C_RCV_HDR_OVF_83, + C_RCV_HDR_OVF_84, + C_RCV_HDR_OVF_85, + C_RCV_HDR_OVF_86, + C_RCV_HDR_OVF_87, + C_RCV_HDR_OVF_88, + C_RCV_HDR_OVF_89, + C_RCV_HDR_OVF_90, + C_RCV_HDR_OVF_91, + C_RCV_HDR_OVF_92, + C_RCV_HDR_OVF_93, + C_RCV_HDR_OVF_94, + C_RCV_HDR_OVF_95, + C_RCV_HDR_OVF_96, + C_RCV_HDR_OVF_97, + C_RCV_HDR_OVF_98, + C_RCV_HDR_OVF_99, + C_RCV_HDR_OVF_100, + C_RCV_HDR_OVF_101, + C_RCV_HDR_OVF_102, + C_RCV_HDR_OVF_103, + C_RCV_HDR_OVF_104, + C_RCV_HDR_OVF_105, + C_RCV_HDR_OVF_106, + C_RCV_HDR_OVF_107, + C_RCV_HDR_OVF_108, + C_RCV_HDR_OVF_109, + C_RCV_HDR_OVF_110, + C_RCV_HDR_OVF_111, + C_RCV_HDR_OVF_112, + C_RCV_HDR_OVF_113, + C_RCV_HDR_OVF_114, + C_RCV_HDR_OVF_115, + C_RCV_HDR_OVF_116, + C_RCV_HDR_OVF_117, + C_RCV_HDR_OVF_118, + C_RCV_HDR_OVF_119, + C_RCV_HDR_OVF_120, + C_RCV_HDR_OVF_121, + C_RCV_HDR_OVF_122, + C_RCV_HDR_OVF_123, + C_RCV_HDR_OVF_124, + C_RCV_HDR_OVF_125, + C_RCV_HDR_OVF_126, + C_RCV_HDR_OVF_127, + C_RCV_HDR_OVF_128, + C_RCV_HDR_OVF_129, + C_RCV_HDR_OVF_130, + C_RCV_HDR_OVF_131, + C_RCV_HDR_OVF_132, + C_RCV_HDR_OVF_133, + C_RCV_HDR_OVF_134, + C_RCV_HDR_OVF_135, + C_RCV_HDR_OVF_136, + C_RCV_HDR_OVF_137, + C_RCV_HDR_OVF_138, + C_RCV_HDR_OVF_139, + C_RCV_HDR_OVF_140, + C_RCV_HDR_OVF_141, + C_RCV_HDR_OVF_142, + C_RCV_HDR_OVF_143, + C_RCV_HDR_OVF_144, + C_RCV_HDR_OVF_145, + C_RCV_HDR_OVF_146, + C_RCV_HDR_OVF_147, + C_RCV_HDR_OVF_148, + C_RCV_HDR_OVF_149, + C_RCV_HDR_OVF_150, + C_RCV_HDR_OVF_151, + C_RCV_HDR_OVF_152, + C_RCV_HDR_OVF_153, + C_RCV_HDR_OVF_154, + C_RCV_HDR_OVF_155, + C_RCV_HDR_OVF_156, + C_RCV_HDR_OVF_157, + C_RCV_HDR_OVF_158, + C_RCV_HDR_OVF_159, + PORT_CNTR_LAST /* Must be kept last */ +}; + +u64 get_all_cpu_total(u64 __percpu *cntr); +void hfi1_start_cleanup(struct hfi1_devdata *dd); +void hfi1_clear_tids(struct hfi1_ctxtdata *rcd); +struct hfi1_message_header *hfi1_get_msgheader( + struct hfi1_devdata *dd, __le32 *rhf_addr); +int hfi1_get_base_kinfo(struct hfi1_ctxtdata *rcd, + struct hfi1_ctxt_info *kinfo); +u64 hfi1_gpio_mod(struct hfi1_devdata *dd, u32 target, u32 data, u32 dir, + u32 mask); +int hfi1_init_ctxt(struct send_context *sc); +void hfi1_put_tid(struct hfi1_devdata *dd, u32 index, + u32 type, unsigned long pa, u16 order); +void hfi1_quiet_serdes(struct hfi1_pportdata *ppd); +void hfi1_rcvctrl(struct hfi1_devdata *dd, unsigned int op, int ctxt); +u32 hfi1_read_cntrs(struct hfi1_devdata *dd, loff_t pos, char **namep, + u64 **cntrp); +u32 hfi1_read_portcntrs(struct hfi1_devdata *dd, loff_t pos, u32 port, + char **namep, u64 **cntrp); +u8 hfi1_ibphys_portstate(struct hfi1_pportdata *ppd); +int hfi1_get_ib_cfg(struct hfi1_pportdata *ppd, int which); +int hfi1_set_ib_cfg(struct hfi1_pportdata *ppd, int which, u32 val); +int hfi1_set_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt, u16 jkey); +int hfi1_clear_ctxt_jkey(struct hfi1_devdata *dd, unsigned ctxt); +int hfi1_set_ctxt_pkey(struct hfi1_devdata *dd, unsigned ctxt, u16 pkey); +int hfi1_clear_ctxt_pkey(struct hfi1_devdata *dd, unsigned ctxt); +void hfi1_read_link_quality(struct hfi1_devdata *dd, u8 *link_quality); + +/* + * Interrupt source table. + * + * Each entry is an interrupt source "type". It is ordered by increasing + * number. + */ +struct is_table { + int start; /* interrupt source type start */ + int end; /* interrupt source type end */ + /* routine that returns the name of the interrupt source */ + char *(*is_name)(char *name, size_t size, unsigned int source); + /* routine to call when receiving an interrupt */ + void (*is_int)(struct hfi1_devdata *dd, unsigned int source); +}; + +#endif /* _CHIP_H */ diff --git a/drivers/staging/rdma/hfi1/chip_registers.h b/drivers/staging/rdma/hfi1/chip_registers.h new file mode 100644 index 0000000000000..6521030018d85 --- /dev/null +++ b/drivers/staging/rdma/hfi1/chip_registers.h @@ -0,0 +1,1289 @@ +#ifndef DEF_CHIP_REG +#define DEF_CHIP_REG + +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define CORE 0x000000000000 +#define CCE (CORE + 0x000000000000) +#define ASIC (CORE + 0x000000400000) +#define MISC (CORE + 0x000000500000) +#define DC_TOP_CSRS (CORE + 0x000000600000) +#define CHIP_DEBUG (CORE + 0x000000700000) +#define RXE (CORE + 0x000001000000) +#define TXE (CORE + 0x000001800000) +#define DCC_CSRS (DC_TOP_CSRS + 0x000000000000) +#define DC_LCB_CSRS (DC_TOP_CSRS + 0x000000001000) +#define DC_8051_CSRS (DC_TOP_CSRS + 0x000000002000) +#define PCIE 0 + +#define ASIC_NUM_SCRATCH 4 +#define CCE_ERR_INT_CNT 0 +#define CCE_MISC_INT_CNT 2 +#define CCE_NUM_32_BIT_COUNTERS 3 +#define CCE_NUM_32_BIT_INT_COUNTERS 6 +#define CCE_NUM_INT_CSRS 12 +#define CCE_NUM_INT_MAP_CSRS 96 +#define CCE_NUM_MSIX_PBAS 4 +#define CCE_NUM_MSIX_VECTORS 256 +#define CCE_NUM_SCRATCH 4 +#define CCE_PCIE_POSTED_CRDT_STALL_CNT 2 +#define CCE_PCIE_TRGT_STALL_CNT 0 +#define CCE_PIO_WR_STALL_CNT 1 +#define CCE_RCV_AVAIL_INT_CNT 3 +#define CCE_RCV_URGENT_INT_CNT 4 +#define CCE_SDMA_INT_CNT 1 +#define CCE_SEND_CREDIT_INT_CNT 5 +#define DCC_CFG_LED_CNTRL (DCC_CSRS + 0x000000000040) +#define DCC_CFG_LED_CNTRL_LED_CNTRL_SMASK 0x10ull +#define DCC_CFG_LED_CNTRL_LED_SW_BLINK_RATE_SHIFT 0 +#define DCC_CFG_LED_CNTRL_LED_SW_BLINK_RATE_SMASK 0xFull +#define DCC_CFG_PORT_CONFIG (DCC_CSRS + 0x000000000008) +#define DCC_CFG_PORT_CONFIG1 (DCC_CSRS + 0x000000000010) +#define DCC_CFG_PORT_CONFIG1_DLID_MASK_MASK 0xFFFFull +#define DCC_CFG_PORT_CONFIG1_DLID_MASK_SHIFT 16 +#define DCC_CFG_PORT_CONFIG1_DLID_MASK_SMASK 0xFFFF0000ull +#define DCC_CFG_PORT_CONFIG1_TARGET_DLID_MASK 0xFFFFull +#define DCC_CFG_PORT_CONFIG1_TARGET_DLID_SHIFT 0 +#define DCC_CFG_PORT_CONFIG1_TARGET_DLID_SMASK 0xFFFFull +#define DCC_CFG_PORT_CONFIG_LINK_STATE_MASK 0x7ull +#define DCC_CFG_PORT_CONFIG_LINK_STATE_SHIFT 48 +#define DCC_CFG_PORT_CONFIG_LINK_STATE_SMASK 0x7000000000000ull +#define DCC_CFG_PORT_CONFIG_MTU_CAP_MASK 0x7ull +#define DCC_CFG_PORT_CONFIG_MTU_CAP_SHIFT 32 +#define DCC_CFG_PORT_CONFIG_MTU_CAP_SMASK 0x700000000ull +#define DCC_CFG_RESET (DCC_CSRS + 0x000000000000) +#define DCC_CFG_RESET_RESET_LCB_SHIFT 0 +#define DCC_CFG_RESET_RESET_RX_FPE_SHIFT 2 +#define DCC_CFG_SC_VL_TABLE_15_0 (DCC_CSRS + 0x000000000028) +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY0_SHIFT 0 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY10_SHIFT 40 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY11_SHIFT 44 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY12_SHIFT 48 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY13_SHIFT 52 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY14_SHIFT 56 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY15_SHIFT 60 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY1_SHIFT 4 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY2_SHIFT 8 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY3_SHIFT 12 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY4_SHIFT 16 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY5_SHIFT 20 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY6_SHIFT 24 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY7_SHIFT 28 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY8_SHIFT 32 +#define DCC_CFG_SC_VL_TABLE_15_0_ENTRY9_SHIFT 36 +#define DCC_CFG_SC_VL_TABLE_31_16 (DCC_CSRS + 0x000000000030) +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY16_SHIFT 0 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY17_SHIFT 4 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY18_SHIFT 8 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY19_SHIFT 12 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY20_SHIFT 16 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY21_SHIFT 20 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY22_SHIFT 24 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY23_SHIFT 28 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY24_SHIFT 32 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY25_SHIFT 36 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY26_SHIFT 40 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY27_SHIFT 44 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY28_SHIFT 48 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY29_SHIFT 52 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY30_SHIFT 56 +#define DCC_CFG_SC_VL_TABLE_31_16_ENTRY31_SHIFT 60 +#define DCC_ERR_DROPPED_PKT_CNT (DCC_CSRS + 0x000000000120) +#define DCC_ERR_FLG (DCC_CSRS + 0x000000000050) +#define DCC_ERR_FLG_BAD_CRDT_ACK_ERR_SMASK 0x4000ull +#define DCC_ERR_FLG_BAD_CTRL_DIST_ERR_SMASK 0x200000ull +#define DCC_ERR_FLG_BAD_CTRL_FLIT_ERR_SMASK 0x10000ull +#define DCC_ERR_FLG_BAD_DLID_TARGET_ERR_SMASK 0x200ull +#define DCC_ERR_FLG_BAD_HEAD_DIST_ERR_SMASK 0x800000ull +#define DCC_ERR_FLG_BAD_L2_ERR_SMASK 0x2ull +#define DCC_ERR_FLG_BAD_LVER_ERR_SMASK 0x400ull +#define DCC_ERR_FLG_BAD_MID_TAIL_ERR_SMASK 0x8ull +#define DCC_ERR_FLG_BAD_PKT_LENGTH_ERR_SMASK 0x4000000ull +#define DCC_ERR_FLG_BAD_PREEMPTION_ERR_SMASK 0x10ull +#define DCC_ERR_FLG_BAD_SC_ERR_SMASK 0x4ull +#define DCC_ERR_FLG_BAD_TAIL_DIST_ERR_SMASK 0x400000ull +#define DCC_ERR_FLG_BAD_VL_MARKER_ERR_SMASK 0x80ull +#define DCC_ERR_FLG_CLR (DCC_CSRS + 0x000000000060) +#define DCC_ERR_FLG_CSR_ACCESS_BLOCKED_HOST_SMASK 0x8000000000ull +#define DCC_ERR_FLG_CSR_ACCESS_BLOCKED_UC_SMASK 0x10000000000ull +#define DCC_ERR_FLG_CSR_INVAL_ADDR_SMASK 0x400000000000ull +#define DCC_ERR_FLG_CSR_PARITY_ERR_SMASK 0x200000000000ull +#define DCC_ERR_FLG_DLID_ZERO_ERR_SMASK 0x40000000ull +#define DCC_ERR_FLG_EN (DCC_CSRS + 0x000000000058) +#define DCC_ERR_FLG_EN_CSR_ACCESS_BLOCKED_HOST_SMASK 0x8000000000ull +#define DCC_ERR_FLG_EN_CSR_ACCESS_BLOCKED_UC_SMASK 0x10000000000ull +#define DCC_ERR_FLG_EVENT_CNTR_PARITY_ERR_SMASK 0x20000ull +#define DCC_ERR_FLG_EVENT_CNTR_ROLLOVER_ERR_SMASK 0x40000ull +#define DCC_ERR_FLG_FMCONFIG_ERR_SMASK 0x40000000000000ull +#define DCC_ERR_FLG_FPE_TX_FIFO_OVFLW_ERR_SMASK 0x2000000000ull +#define DCC_ERR_FLG_FPE_TX_FIFO_UNFLW_ERR_SMASK 0x4000000000ull +#define DCC_ERR_FLG_LATE_EBP_ERR_SMASK 0x1000000000ull +#define DCC_ERR_FLG_LATE_LONG_ERR_SMASK 0x800000000ull +#define DCC_ERR_FLG_LATE_SHORT_ERR_SMASK 0x400000000ull +#define DCC_ERR_FLG_LENGTH_MTU_ERR_SMASK 0x80000000ull +#define DCC_ERR_FLG_LINK_ERR_SMASK 0x80000ull +#define DCC_ERR_FLG_MISC_CNTR_ROLLOVER_ERR_SMASK 0x100000ull +#define DCC_ERR_FLG_NONVL15_STATE_ERR_SMASK 0x1000000ull +#define DCC_ERR_FLG_PERM_NVL15_ERR_SMASK 0x10000000ull +#define DCC_ERR_FLG_PREEMPTION_ERR_SMASK 0x20ull +#define DCC_ERR_FLG_PREEMPTIONVL15_ERR_SMASK 0x40ull +#define DCC_ERR_FLG_RCVPORT_ERR_SMASK 0x80000000000000ull +#define DCC_ERR_FLG_RX_BYTE_SHFT_PARITY_ERR_SMASK 0x1000000000000ull +#define DCC_ERR_FLG_RX_CTRL_PARITY_MBE_ERR_SMASK 0x100000000000ull +#define DCC_ERR_FLG_RX_EARLY_DROP_ERR_SMASK 0x200000000ull +#define DCC_ERR_FLG_SLID_ZERO_ERR_SMASK 0x20000000ull +#define DCC_ERR_FLG_TX_BYTE_SHFT_PARITY_ERR_SMASK 0x800000000000ull +#define DCC_ERR_FLG_TX_CTRL_PARITY_ERR_SMASK 0x20000000000ull +#define DCC_ERR_FLG_TX_CTRL_PARITY_MBE_ERR_SMASK 0x40000000000ull +#define DCC_ERR_FLG_TX_SC_PARITY_ERR_SMASK 0x80000000000ull +#define DCC_ERR_FLG_UNCORRECTABLE_ERR_SMASK 0x2000ull +#define DCC_ERR_FLG_UNSUP_PKT_TYPE_SMASK 0x8000ull +#define DCC_ERR_FLG_UNSUP_VL_ERR_SMASK 0x8000000ull +#define DCC_ERR_FLG_VL15_MULTI_ERR_SMASK 0x2000000ull +#define DCC_ERR_FMCONFIG_ERR_CNT (DCC_CSRS + 0x000000000110) +#define DCC_ERR_INFO_FMCONFIG (DCC_CSRS + 0x000000000090) +#define DCC_ERR_INFO_PORTRCV (DCC_CSRS + 0x000000000078) +#define DCC_ERR_INFO_PORTRCV_HDR0 (DCC_CSRS + 0x000000000080) +#define DCC_ERR_INFO_PORTRCV_HDR1 (DCC_CSRS + 0x000000000088) +#define DCC_ERR_INFO_UNCORRECTABLE (DCC_CSRS + 0x000000000098) +#define DCC_ERR_PORTRCV_ERR_CNT (DCC_CSRS + 0x000000000108) +#define DCC_ERR_RCVREMOTE_PHY_ERR_CNT (DCC_CSRS + 0x000000000118) +#define DCC_ERR_UNCORRECTABLE_CNT (DCC_CSRS + 0x000000000100) +#define DCC_PRF_PORT_MARK_FECN_CNT (DCC_CSRS + 0x000000000330) +#define DCC_PRF_PORT_RCV_BECN_CNT (DCC_CSRS + 0x000000000290) +#define DCC_PRF_PORT_RCV_BUBBLE_CNT (DCC_CSRS + 0x0000000002E0) +#define DCC_PRF_PORT_RCV_CORRECTABLE_CNT (DCC_CSRS + 0x000000000140) +#define DCC_PRF_PORT_RCV_DATA_CNT (DCC_CSRS + 0x000000000198) +#define DCC_PRF_PORT_RCV_FECN_CNT (DCC_CSRS + 0x000000000240) +#define DCC_PRF_PORT_RCV_MULTICAST_PKT_CNT (DCC_CSRS + 0x000000000130) +#define DCC_PRF_PORT_RCV_PKTS_CNT (DCC_CSRS + 0x0000000001A8) +#define DCC_PRF_PORT_VL_MARK_FECN_CNT (DCC_CSRS + 0x000000000338) +#define DCC_PRF_PORT_VL_RCV_BECN_CNT (DCC_CSRS + 0x000000000298) +#define DCC_PRF_PORT_VL_RCV_BUBBLE_CNT (DCC_CSRS + 0x0000000002E8) +#define DCC_PRF_PORT_VL_RCV_DATA_CNT (DCC_CSRS + 0x0000000001B0) +#define DCC_PRF_PORT_VL_RCV_FECN_CNT (DCC_CSRS + 0x000000000248) +#define DCC_PRF_PORT_VL_RCV_PKTS_CNT (DCC_CSRS + 0x0000000001F8) +#define DCC_PRF_PORT_XMIT_CORRECTABLE_CNT (DCC_CSRS + 0x000000000138) +#define DCC_PRF_PORT_XMIT_DATA_CNT (DCC_CSRS + 0x000000000190) +#define DCC_PRF_PORT_XMIT_MULTICAST_CNT (DCC_CSRS + 0x000000000128) +#define DCC_PRF_PORT_XMIT_PKTS_CNT (DCC_CSRS + 0x0000000001A0) +#define DCC_PRF_RX_FLOW_CRTL_CNT (DCC_CSRS + 0x000000000180) +#define DCC_PRF_TX_FLOW_CRTL_CNT (DCC_CSRS + 0x000000000188) +#define DC_DC8051_CFG_CSR_ACCESS_SEL (DC_8051_CSRS + 0x000000000110) +#define DC_DC8051_CFG_CSR_ACCESS_SEL_DCC_SMASK 0x2ull +#define DC_DC8051_CFG_CSR_ACCESS_SEL_LCB_SMASK 0x1ull +#define DC_DC8051_CFG_EXT_DEV_0 (DC_8051_CSRS + 0x000000000118) +#define DC_DC8051_CFG_EXT_DEV_0_COMPLETED_SMASK 0x1ull +#define DC_DC8051_CFG_EXT_DEV_0_RETURN_CODE_SHIFT 8 +#define DC_DC8051_CFG_EXT_DEV_0_RSP_DATA_SHIFT 16 +#define DC_DC8051_CFG_EXT_DEV_1 (DC_8051_CSRS + 0x000000000120) +#define DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_MASK 0xFFFFull +#define DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_SHIFT 16 +#define DC_DC8051_CFG_EXT_DEV_1_REQ_DATA_SMASK 0xFFFF0000ull +#define DC_DC8051_CFG_EXT_DEV_1_REQ_NEW_SMASK 0x1ull +#define DC_DC8051_CFG_EXT_DEV_1_REQ_TYPE_MASK 0xFFull +#define DC_DC8051_CFG_EXT_DEV_1_REQ_TYPE_SHIFT 8 +#define DC_DC8051_CFG_HOST_CMD_0 (DC_8051_CSRS + 0x000000000028) +#define DC_DC8051_CFG_HOST_CMD_0_REQ_DATA_MASK 0xFFFFFFFFFFFFull +#define DC_DC8051_CFG_HOST_CMD_0_REQ_DATA_SHIFT 16 +#define DC_DC8051_CFG_HOST_CMD_0_REQ_NEW_SMASK 0x1ull +#define DC_DC8051_CFG_HOST_CMD_0_REQ_TYPE_MASK 0xFFull +#define DC_DC8051_CFG_HOST_CMD_0_REQ_TYPE_SHIFT 8 +#define DC_DC8051_CFG_HOST_CMD_1 (DC_8051_CSRS + 0x000000000030) +#define DC_DC8051_CFG_HOST_CMD_1_COMPLETED_SMASK 0x1ull +#define DC_DC8051_CFG_HOST_CMD_1_RETURN_CODE_MASK 0xFFull +#define DC_DC8051_CFG_HOST_CMD_1_RETURN_CODE_SHIFT 8 +#define DC_DC8051_CFG_HOST_CMD_1_RSP_DATA_MASK 0xFFFFFFFFFFFFull +#define DC_DC8051_CFG_HOST_CMD_1_RSP_DATA_SHIFT 16 +#define DC_DC8051_CFG_LOCAL_GUID (DC_8051_CSRS + 0x000000000038) +#define DC_DC8051_CFG_MODE (DC_8051_CSRS + 0x000000000070) +#define DC_DC8051_CFG_RAM_ACCESS_CTRL (DC_8051_CSRS + 0x000000000008) +#define DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_MASK 0x7FFFull +#define DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_SHIFT 0 +#define DC_DC8051_CFG_RAM_ACCESS_CTRL_WRITE_ENA_SMASK 0x1000000ull +#define DC_DC8051_CFG_RAM_ACCESS_CTRL_READ_ENA_SMASK 0x10000ull +#define DC_DC8051_CFG_RAM_ACCESS_SETUP (DC_8051_CSRS + 0x000000000000) +#define DC_DC8051_CFG_RAM_ACCESS_SETUP_AUTO_INCR_ADDR_SMASK 0x100ull +#define DC_DC8051_CFG_RAM_ACCESS_SETUP_RAM_SEL_SMASK 0x1ull +#define DC_DC8051_CFG_RAM_ACCESS_STATUS (DC_8051_CSRS + 0x000000000018) +#define DC_DC8051_CFG_RAM_ACCESS_STATUS_ACCESS_COMPLETED_SMASK 0x10000ull +#define DC_DC8051_CFG_RAM_ACCESS_WR_DATA (DC_8051_CSRS + 0x000000000010) +#define DC_DC8051_CFG_RAM_ACCESS_RD_DATA (DC_8051_CSRS + 0x000000000020) +#define DC_DC8051_CFG_RST (DC_8051_CSRS + 0x000000000068) +#define DC_DC8051_CFG_RST_CRAM_SMASK 0x2ull +#define DC_DC8051_CFG_RST_DRAM_SMASK 0x4ull +#define DC_DC8051_CFG_RST_IRAM_SMASK 0x8ull +#define DC_DC8051_CFG_RST_M8051W_SMASK 0x1ull +#define DC_DC8051_CFG_RST_SFR_SMASK 0x10ull +#define DC_DC8051_DBG_ERR_INFO_SET_BY_8051 (DC_8051_CSRS + 0x0000000000D8) +#define DC_DC8051_DBG_ERR_INFO_SET_BY_8051_ERROR_MASK 0xFFFFFFFFull +#define DC_DC8051_DBG_ERR_INFO_SET_BY_8051_ERROR_SHIFT 16 +#define DC_DC8051_DBG_ERR_INFO_SET_BY_8051_HOST_MSG_MASK 0xFFFFull +#define DC_DC8051_DBG_ERR_INFO_SET_BY_8051_HOST_MSG_SHIFT 0 +#define DC_DC8051_ERR_CLR (DC_8051_CSRS + 0x0000000000E8) +#define DC_DC8051_ERR_EN (DC_8051_CSRS + 0x0000000000F0) +#define DC_DC8051_ERR_EN_LOST_8051_HEART_BEAT_SMASK 0x2ull +#define DC_DC8051_ERR_FLG (DC_8051_CSRS + 0x0000000000E0) +#define DC_DC8051_ERR_FLG_CRAM_MBE_SMASK 0x4ull +#define DC_DC8051_ERR_FLG_CRAM_SBE_SMASK 0x8ull +#define DC_DC8051_ERR_FLG_DRAM_MBE_SMASK 0x10ull +#define DC_DC8051_ERR_FLG_DRAM_SBE_SMASK 0x20ull +#define DC_DC8051_ERR_FLG_INVALID_CSR_ADDR_SMASK 0x400ull +#define DC_DC8051_ERR_FLG_IRAM_MBE_SMASK 0x40ull +#define DC_DC8051_ERR_FLG_IRAM_SBE_SMASK 0x80ull +#define DC_DC8051_ERR_FLG_LOST_8051_HEART_BEAT_SMASK 0x2ull +#define DC_DC8051_ERR_FLG_SET_BY_8051_SMASK 0x1ull +#define DC_DC8051_ERR_FLG_UNMATCHED_SECURE_MSG_ACROSS_BCC_LANES_SMASK 0x100ull +#define DC_DC8051_STS_CUR_STATE (DC_8051_CSRS + 0x000000000060) +#define DC_DC8051_STS_CUR_STATE_FIRMWARE_MASK 0xFFull +#define DC_DC8051_STS_CUR_STATE_FIRMWARE_SHIFT 16 +#define DC_DC8051_STS_CUR_STATE_PORT_MASK 0xFFull +#define DC_DC8051_STS_CUR_STATE_PORT_SHIFT 0 +#define DC_DC8051_STS_LOCAL_FM_SECURITY (DC_8051_CSRS + 0x000000000050) +#define DC_DC8051_STS_LOCAL_FM_SECURITY_DISABLED_MASK 0x1ull +#define DC_DC8051_STS_REMOTE_FM_SECURITY (DC_8051_CSRS + 0x000000000058) +#define DC_DC8051_STS_REMOTE_GUID (DC_8051_CSRS + 0x000000000040) +#define DC_DC8051_STS_REMOTE_NODE_TYPE (DC_8051_CSRS + 0x000000000048) +#define DC_DC8051_STS_REMOTE_NODE_TYPE_VAL_MASK 0x3ull +#define DC_DC8051_STS_REMOTE_PORT_NO (DC_8051_CSRS + 0x000000000130) +#define DC_DC8051_STS_REMOTE_PORT_NO_VAL_SMASK 0xFFull +#define DC_LCB_CFG_ALLOW_LINK_UP (DC_LCB_CSRS + 0x000000000128) +#define DC_LCB_CFG_ALLOW_LINK_UP_VAL_SHIFT 0 +#define DC_LCB_CFG_CRC_MODE (DC_LCB_CSRS + 0x000000000058) +#define DC_LCB_CFG_CRC_MODE_TX_VAL_SHIFT 0 +#define DC_LCB_CFG_IGNORE_LOST_RCLK (DC_LCB_CSRS + 0x000000000020) +#define DC_LCB_CFG_IGNORE_LOST_RCLK_EN_SMASK 0x1ull +#define DC_LCB_CFG_LANE_WIDTH (DC_LCB_CSRS + 0x000000000100) +#define DC_LCB_CFG_LINK_KILL_EN (DC_LCB_CSRS + 0x000000000120) +#define DC_LCB_CFG_LINK_KILL_EN_FLIT_INPUT_BUF_MBE_SMASK 0x100000ull +#define DC_LCB_CFG_LINK_KILL_EN_REPLAY_BUF_MBE_SMASK 0x400000ull +#define DC_LCB_CFG_LN_DCLK (DC_LCB_CSRS + 0x000000000060) +#define DC_LCB_CFG_LOOPBACK (DC_LCB_CSRS + 0x0000000000F8) +#define DC_LCB_CFG_LOOPBACK_VAL_SHIFT 0 +#define DC_LCB_CFG_RUN (DC_LCB_CSRS + 0x000000000000) +#define DC_LCB_CFG_RUN_EN_SHIFT 0 +#define DC_LCB_CFG_RX_FIFOS_RADR (DC_LCB_CSRS + 0x000000000018) +#define DC_LCB_CFG_RX_FIFOS_RADR_DO_NOT_JUMP_VAL_SHIFT 8 +#define DC_LCB_CFG_RX_FIFOS_RADR_OK_TO_JUMP_VAL_SHIFT 4 +#define DC_LCB_CFG_RX_FIFOS_RADR_RST_VAL_SHIFT 0 +#define DC_LCB_CFG_TX_FIFOS_RADR (DC_LCB_CSRS + 0x000000000010) +#define DC_LCB_CFG_TX_FIFOS_RADR_RST_VAL_SHIFT 0 +#define DC_LCB_CFG_TX_FIFOS_RESET (DC_LCB_CSRS + 0x000000000008) +#define DC_LCB_CFG_TX_FIFOS_RESET_VAL_SHIFT 0 +#define DC_LCB_ERR_CLR (DC_LCB_CSRS + 0x000000000308) +#define DC_LCB_ERR_EN (DC_LCB_CSRS + 0x000000000310) +#define DC_LCB_ERR_FLG (DC_LCB_CSRS + 0x000000000300) +#define DC_LCB_ERR_FLG_REDUNDANT_FLIT_PARITY_ERR_SMASK 0x20000000ull +#define DC_LCB_ERR_FLG_NEG_EDGE_LINK_TRANSFER_ACTIVE_SMASK 0x10000000ull +#define DC_LCB_ERR_FLG_HOLD_REINIT_SMASK 0x8000000ull +#define DC_LCB_ERR_FLG_RST_FOR_INCOMPLT_RND_TRIP_SMASK 0x4000000ull +#define DC_LCB_ERR_FLG_RST_FOR_LINK_TIMEOUT_SMASK 0x2000000ull +#define DC_LCB_ERR_FLG_CREDIT_RETURN_FLIT_MBE_SMASK 0x1000000ull +#define DC_LCB_ERR_FLG_REPLAY_BUF_SBE_SMASK 0x800000ull +#define DC_LCB_ERR_FLG_REPLAY_BUF_MBE_SMASK 0x400000ull +#define DC_LCB_ERR_FLG_FLIT_INPUT_BUF_SBE_SMASK 0x200000ull +#define DC_LCB_ERR_FLG_FLIT_INPUT_BUF_MBE_SMASK 0x100000ull +#define DC_LCB_ERR_FLG_VL_ACK_INPUT_WRONG_CRC_MODE_SMASK 0x80000ull +#define DC_LCB_ERR_FLG_VL_ACK_INPUT_PARITY_ERR_SMASK 0x40000ull +#define DC_LCB_ERR_FLG_VL_ACK_INPUT_BUF_OFLW_SMASK 0x20000ull +#define DC_LCB_ERR_FLG_FLIT_INPUT_BUF_OFLW_SMASK 0x10000ull +#define DC_LCB_ERR_FLG_ILLEGAL_FLIT_ENCODING_SMASK 0x8000ull +#define DC_LCB_ERR_FLG_ILLEGAL_NULL_LTP_SMASK 0x4000ull +#define DC_LCB_ERR_FLG_UNEXPECTED_ROUND_TRIP_MARKER_SMASK 0x2000ull +#define DC_LCB_ERR_FLG_UNEXPECTED_REPLAY_MARKER_SMASK 0x1000ull +#define DC_LCB_ERR_FLG_RCLK_STOPPED_SMASK 0x800ull +#define DC_LCB_ERR_FLG_CRC_ERR_CNT_HIT_LIMIT_SMASK 0x400ull +#define DC_LCB_ERR_FLG_REINIT_FOR_LN_DEGRADE_SMASK 0x200ull +#define DC_LCB_ERR_FLG_REINIT_FROM_PEER_SMASK 0x100ull +#define DC_LCB_ERR_FLG_SEQ_CRC_ERR_SMASK 0x80ull +#define DC_LCB_ERR_FLG_RX_LESS_THAN_FOUR_LNS_SMASK 0x40ull +#define DC_LCB_ERR_FLG_TX_LESS_THAN_FOUR_LNS_SMASK 0x20ull +#define DC_LCB_ERR_FLG_LOST_REINIT_STALL_OR_TOS_SMASK 0x10ull +#define DC_LCB_ERR_FLG_ALL_LNS_FAILED_REINIT_TEST_SMASK 0x8ull +#define DC_LCB_ERR_FLG_RST_FOR_FAILED_DESKEW_SMASK 0x4ull +#define DC_LCB_ERR_FLG_INVALID_CSR_ADDR_SMASK 0x2ull +#define DC_LCB_ERR_FLG_CSR_PARITY_ERR_SMASK 0x1ull +#define DC_LCB_ERR_INFO_CRC_ERR_LN0 (DC_LCB_CSRS + 0x000000000328) +#define DC_LCB_ERR_INFO_CRC_ERR_LN1 (DC_LCB_CSRS + 0x000000000330) +#define DC_LCB_ERR_INFO_CRC_ERR_LN2 (DC_LCB_CSRS + 0x000000000338) +#define DC_LCB_ERR_INFO_CRC_ERR_LN3 (DC_LCB_CSRS + 0x000000000340) +#define DC_LCB_ERR_INFO_CRC_ERR_MULTI_LN (DC_LCB_CSRS + 0x000000000348) +#define DC_LCB_ERR_INFO_ESCAPE_0_ONLY_CNT (DC_LCB_CSRS + 0x000000000368) +#define DC_LCB_ERR_INFO_ESCAPE_0_PLUS1_CNT (DC_LCB_CSRS + 0x000000000370) +#define DC_LCB_ERR_INFO_ESCAPE_0_PLUS2_CNT (DC_LCB_CSRS + 0x000000000378) +#define DC_LCB_ERR_INFO_MISC_FLG_CNT (DC_LCB_CSRS + 0x000000000390) +#define DC_LCB_ERR_INFO_REINIT_FROM_PEER_CNT (DC_LCB_CSRS + 0x000000000380) +#define DC_LCB_ERR_INFO_RX_REPLAY_CNT (DC_LCB_CSRS + 0x000000000358) +#define DC_LCB_ERR_INFO_SBE_CNT (DC_LCB_CSRS + 0x000000000388) +#define DC_LCB_ERR_INFO_SEQ_CRC_CNT (DC_LCB_CSRS + 0x000000000360) +#define DC_LCB_ERR_INFO_TOTAL_CRC_ERR (DC_LCB_CSRS + 0x000000000320) +#define DC_LCB_ERR_INFO_TX_REPLAY_CNT (DC_LCB_CSRS + 0x000000000350) +#define DC_LCB_PG_DBG_FLIT_CRDTS_CNT (DC_LCB_CSRS + 0x000000000580) +#define DC_LCB_PG_STS_PAUSE_COMPLETE_CNT (DC_LCB_CSRS + 0x0000000005F8) +#define DC_LCB_PG_STS_TX_MBE_CNT (DC_LCB_CSRS + 0x000000000608) +#define DC_LCB_PG_STS_TX_SBE_CNT (DC_LCB_CSRS + 0x000000000600) +#define DC_LCB_PRF_ACCEPTED_LTP_CNT (DC_LCB_CSRS + 0x000000000408) +#define DC_LCB_PRF_CLK_CNTR (DC_LCB_CSRS + 0x000000000420) +#define DC_LCB_PRF_GOOD_LTP_CNT (DC_LCB_CSRS + 0x000000000400) +#define DC_LCB_PRF_RX_FLIT_CNT (DC_LCB_CSRS + 0x000000000410) +#define DC_LCB_PRF_TX_FLIT_CNT (DC_LCB_CSRS + 0x000000000418) +#define DC_LCB_STS_LINK_TRANSFER_ACTIVE (DC_LCB_CSRS + 0x000000000468) +#define DC_LCB_STS_ROUND_TRIP_LTP_CNT (DC_LCB_CSRS + 0x0000000004B0) +#define RCV_BUF_OVFL_CNT 10 +#define RCV_CONTEXT_EGR_STALL 22 +#define RCV_CONTEXT_RHQ_STALL 21 +#define RCV_DATA_PKT_CNT 0 +#define RCV_DWORD_CNT 1 +#define RCV_TID_FLOW_GEN_MISMATCH_CNT 20 +#define RCV_TID_FLOW_SEQ_MISMATCH_CNT 23 +#define RCV_TID_FULL_ERR_CNT 18 +#define RCV_TID_VALID_ERR_CNT 19 +#define RXE_NUM_32_BIT_COUNTERS 24 +#define RXE_NUM_64_BIT_COUNTERS 2 +#define RXE_NUM_RSM_INSTANCES 4 +#define RXE_NUM_TID_FLOWS 32 +#define RXE_PER_CONTEXT_OFFSET 0x0300000 +#define SEND_DATA_PKT_CNT 0 +#define SEND_DATA_PKT_VL0_CNT 12 +#define SEND_DATA_VL0_CNT 3 +#define SEND_DROPPED_PKT_CNT 5 +#define SEND_DWORD_CNT 1 +#define SEND_FLOW_STALL_CNT 4 +#define SEND_HEADERS_ERR_CNT 6 +#define SEND_LEN_ERR_CNT 1 +#define SEND_MAX_MIN_LEN_ERR_CNT 2 +#define SEND_UNDERRUN_CNT 3 +#define SEND_UNSUP_VL_ERR_CNT 0 +#define SEND_WAIT_CNT 2 +#define SEND_WAIT_VL0_CNT 21 +#define TXE_PIO_SEND_OFFSET 0x0800000 +#define ASIC_CFG_DRV_STR (ASIC + 0x000000000048) +#define ASIC_CFG_MUTEX (ASIC + 0x000000000040) +#define ASIC_CFG_SBUS_EXECUTE (ASIC + 0x000000000008) +#define ASIC_CFG_SBUS_EXECUTE_EXECUTE_SMASK 0x1ull +#define ASIC_CFG_SBUS_EXECUTE_FAST_MODE_SMASK 0x2ull +#define ASIC_CFG_SBUS_REQUEST (ASIC + 0x000000000000) +#define ASIC_CFG_SBUS_REQUEST_COMMAND_SHIFT 16 +#define ASIC_CFG_SBUS_REQUEST_DATA_ADDR_SHIFT 8 +#define ASIC_CFG_SBUS_REQUEST_DATA_IN_SHIFT 32 +#define ASIC_CFG_SBUS_REQUEST_RECEIVER_ADDR_SHIFT 0 +#define ASIC_CFG_SCRATCH (ASIC + 0x000000000020) +#define ASIC_CFG_THERM_POLL_EN (ASIC + 0x000000000050) +#define ASIC_EEP_ADDR_CMD (ASIC + 0x000000000308) +#define ASIC_EEP_ADDR_CMD_EP_ADDR_MASK 0xFFFFFFull +#define ASIC_EEP_CTL_STAT (ASIC + 0x000000000300) +#define ASIC_EEP_CTL_STAT_EP_RESET_SMASK 0x4ull +#define ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT 8 +#define ASIC_EEP_CTL_STAT_RESETCSR 0x0000000083818000ull +#define ASIC_EEP_DATA (ASIC + 0x000000000310) +#define ASIC_GPIO_CLEAR (ASIC + 0x000000000230) +#define ASIC_GPIO_FORCE (ASIC + 0x000000000238) +#define ASIC_GPIO_IN (ASIC + 0x000000000200) +#define ASIC_GPIO_INVERT (ASIC + 0x000000000210) +#define ASIC_GPIO_MASK (ASIC + 0x000000000220) +#define ASIC_GPIO_OE (ASIC + 0x000000000208) +#define ASIC_GPIO_OUT (ASIC + 0x000000000218) +#define ASIC_PCIE_SD_HOST_CMD (ASIC + 0x000000000100) +#define ASIC_PCIE_SD_HOST_CMD_INTRPT_CMD_SHIFT 0 +#define ASIC_PCIE_SD_HOST_CMD_SBR_MODE_SMASK 0x400ull +#define ASIC_PCIE_SD_HOST_CMD_SBUS_RCVR_ADDR_SHIFT 2 +#define ASIC_PCIE_SD_HOST_CMD_TIMER_MASK 0xFFFFFull +#define ASIC_PCIE_SD_HOST_CMD_TIMER_SHIFT 12 +#define ASIC_PCIE_SD_HOST_STATUS (ASIC + 0x000000000108) +#define ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_ERR_MASK 0x7ull +#define ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_ERR_SHIFT 2 +#define ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_STS_MASK 0x3ull +#define ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_STS_SHIFT 0 +#define ASIC_PCIE_SD_INTRPT_DATA_CODE (ASIC + 0x000000000110) +#define ASIC_PCIE_SD_INTRPT_ENABLE (ASIC + 0x000000000118) +#define ASIC_PCIE_SD_INTRPT_LIST (ASIC + 0x000000000180) +#define ASIC_PCIE_SD_INTRPT_LIST_INTRPT_CODE_SHIFT 16 +#define ASIC_PCIE_SD_INTRPT_LIST_INTRPT_DATA_SHIFT 0 +#define ASIC_PCIE_SD_INTRPT_STATUS (ASIC + 0x000000000128) +#define ASIC_QSFP1_CLEAR (ASIC + 0x000000000270) +#define ASIC_QSFP1_FORCE (ASIC + 0x000000000278) +#define ASIC_QSFP1_IN (ASIC + 0x000000000240) +#define ASIC_QSFP1_INVERT (ASIC + 0x000000000250) +#define ASIC_QSFP1_MASK (ASIC + 0x000000000260) +#define ASIC_QSFP1_OE (ASIC + 0x000000000248) +#define ASIC_QSFP1_OUT (ASIC + 0x000000000258) +#define ASIC_QSFP1_STATUS (ASIC + 0x000000000268) +#define ASIC_QSFP2_CLEAR (ASIC + 0x0000000002B0) +#define ASIC_QSFP2_FORCE (ASIC + 0x0000000002B8) +#define ASIC_QSFP2_IN (ASIC + 0x000000000280) +#define ASIC_QSFP2_INVERT (ASIC + 0x000000000290) +#define ASIC_QSFP2_MASK (ASIC + 0x0000000002A0) +#define ASIC_QSFP2_OE (ASIC + 0x000000000288) +#define ASIC_QSFP2_OUT (ASIC + 0x000000000298) +#define ASIC_QSFP2_STATUS (ASIC + 0x0000000002A8) +#define ASIC_STS_SBUS_COUNTERS (ASIC + 0x000000000018) +#define ASIC_STS_SBUS_COUNTERS_EXECUTE_CNT_MASK 0xFFFFull +#define ASIC_STS_SBUS_COUNTERS_EXECUTE_CNT_SHIFT 0 +#define ASIC_STS_SBUS_COUNTERS_RCV_DATA_VALID_CNT_MASK 0xFFFFull +#define ASIC_STS_SBUS_COUNTERS_RCV_DATA_VALID_CNT_SHIFT 16 +#define ASIC_STS_SBUS_RESULT (ASIC + 0x000000000010) +#define ASIC_STS_SBUS_RESULT_DONE_SMASK 0x1ull +#define ASIC_STS_SBUS_RESULT_RCV_DATA_VALID_SMASK 0x2ull +#define ASIC_STS_THERM (ASIC + 0x000000000058) +#define ASIC_STS_THERM_CRIT_TEMP_MASK 0x7FFull +#define ASIC_STS_THERM_CRIT_TEMP_SHIFT 18 +#define ASIC_STS_THERM_CURR_TEMP_MASK 0x7FFull +#define ASIC_STS_THERM_CURR_TEMP_SHIFT 2 +#define ASIC_STS_THERM_HI_TEMP_MASK 0x7FFull +#define ASIC_STS_THERM_HI_TEMP_SHIFT 50 +#define ASIC_STS_THERM_LO_TEMP_MASK 0x7FFull +#define ASIC_STS_THERM_LO_TEMP_SHIFT 34 +#define ASIC_STS_THERM_LOW_SHIFT 13 +#define CCE_COUNTER_ARRAY32 (CCE + 0x000000000060) +#define CCE_CTRL (CCE + 0x000000000010) +#define CCE_CTRL_RXE_RESUME_SMASK 0x800ull +#define CCE_CTRL_SPC_FREEZE_SMASK 0x100ull +#define CCE_CTRL_SPC_UNFREEZE_SMASK 0x200ull +#define CCE_CTRL_TXE_RESUME_SMASK 0x2000ull +#define CCE_DC_CTRL (CCE + 0x0000000000B8) +#define CCE_DC_CTRL_DC_RESET_SMASK 0x1ull +#define CCE_DC_CTRL_RESETCSR 0x0000000000000001ull +#define CCE_ERR_CLEAR (CCE + 0x000000000050) +#define CCE_ERR_MASK (CCE + 0x000000000048) +#define CCE_ERR_STATUS (CCE + 0x000000000040) +#define CCE_ERR_STATUS_CCE_CLI0_ASYNC_FIFO_PARITY_ERR_SMASK 0x40ull +#define CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_DBG_PARITY_ERROR_SMASK 0x1000ull +#define CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_PIO_CRDT_PARITY_ERR_SMASK \ + 0x200ull +#define CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_RXDMA_PARITY_ERROR_SMASK \ + 0x800ull +#define CCE_ERR_STATUS_CCE_CLI1_ASYNC_FIFO_SDMA_HD_PARITY_ERR_SMASK \ + 0x400ull +#define CCE_ERR_STATUS_CCE_CLI2_ASYNC_FIFO_PARITY_ERR_SMASK 0x100ull +#define CCE_ERR_STATUS_CCE_CSR_CFG_BUS_PARITY_ERR_SMASK 0x80ull +#define CCE_ERR_STATUS_CCE_CSR_PARITY_ERR_SMASK 0x1ull +#define CCE_ERR_STATUS_CCE_CSR_READ_BAD_ADDR_ERR_SMASK 0x2ull +#define CCE_ERR_STATUS_CCE_CSR_WRITE_BAD_ADDR_ERR_SMASK 0x4ull +#define CCE_ERR_STATUS_CCE_INT_MAP_COR_ERR_SMASK 0x4000000000ull +#define CCE_ERR_STATUS_CCE_INT_MAP_UNC_ERR_SMASK 0x8000000000ull +#define CCE_ERR_STATUS_CCE_MSIX_CSR_PARITY_ERR_SMASK 0x10000000000ull +#define CCE_ERR_STATUS_CCE_MSIX_TABLE_COR_ERR_SMASK 0x1000000000ull +#define CCE_ERR_STATUS_CCE_MSIX_TABLE_UNC_ERR_SMASK 0x2000000000ull +#define CCE_ERR_STATUS_CCE_RCPL_ASYNC_FIFO_PARITY_ERR_SMASK 0x400000000ull +#define CCE_ERR_STATUS_CCE_RSPD_DATA_PARITY_ERR_SMASK 0x20ull +#define CCE_ERR_STATUS_CCE_RXDMA_CONV_FIFO_PARITY_ERR_SMASK 0x800000000ull +#define CCE_ERR_STATUS_CCE_SEG_READ_BAD_ADDR_ERR_SMASK 0x100000000ull +#define CCE_ERR_STATUS_CCE_SEG_WRITE_BAD_ADDR_ERR_SMASK 0x200000000ull +#define CCE_ERR_STATUS_CCE_TRGT_ACCESS_ERR_SMASK 0x10ull +#define CCE_ERR_STATUS_CCE_TRGT_ASYNC_FIFO_PARITY_ERR_SMASK 0x8ull +#define CCE_ERR_STATUS_CCE_TRGT_CPL_TIMEOUT_ERR_SMASK 0x40000000ull +#define CCE_ERR_STATUS_LA_TRIGGERED_SMASK 0x80000000ull +#define CCE_ERR_STATUS_PCIC_CPL_DAT_QCOR_ERR_SMASK 0x40000ull +#define CCE_ERR_STATUS_PCIC_CPL_DAT_QUNC_ERR_SMASK 0x4000000ull +#define CCE_ERR_STATUS_PCIC_CPL_HD_QCOR_ERR_SMASK 0x20000ull +#define CCE_ERR_STATUS_PCIC_CPL_HD_QUNC_ERR_SMASK 0x2000000ull +#define CCE_ERR_STATUS_PCIC_NPOST_DAT_QPARITY_ERR_SMASK 0x100000ull +#define CCE_ERR_STATUS_PCIC_NPOST_HQ_PARITY_ERR_SMASK 0x80000ull +#define CCE_ERR_STATUS_PCIC_POST_DAT_QCOR_ERR_SMASK 0x10000ull +#define CCE_ERR_STATUS_PCIC_POST_DAT_QUNC_ERR_SMASK 0x1000000ull +#define CCE_ERR_STATUS_PCIC_POST_HD_QCOR_ERR_SMASK 0x8000ull +#define CCE_ERR_STATUS_PCIC_POST_HD_QUNC_ERR_SMASK 0x800000ull +#define CCE_ERR_STATUS_PCIC_RECEIVE_PARITY_ERR_SMASK 0x20000000ull +#define CCE_ERR_STATUS_PCIC_RETRY_MEM_COR_ERR_SMASK 0x2000ull +#define CCE_ERR_STATUS_PCIC_RETRY_MEM_UNC_ERR_SMASK 0x200000ull +#define CCE_ERR_STATUS_PCIC_RETRY_SOT_MEM_COR_ERR_SMASK 0x4000ull +#define CCE_ERR_STATUS_PCIC_RETRY_SOT_MEM_UNC_ERR_SMASK 0x400000ull +#define CCE_ERR_STATUS_PCIC_TRANSMIT_BACK_PARITY_ERR_SMASK 0x10000000ull +#define CCE_ERR_STATUS_PCIC_TRANSMIT_FRONT_PARITY_ERR_SMASK 0x8000000ull +#define CCE_INT_CLEAR (CCE + 0x000000110A00) +#define CCE_INT_COUNTER_ARRAY32 (CCE + 0x000000110D00) +#define CCE_INT_FORCE (CCE + 0x000000110B00) +#define CCE_INT_MAP (CCE + 0x000000110500) +#define CCE_INT_MASK (CCE + 0x000000110900) +#define CCE_INT_STATUS (CCE + 0x000000110800) +#define CCE_MSIX_INT_GRANTED (CCE + 0x000000110200) +#define CCE_MSIX_TABLE_LOWER (CCE + 0x000000100000) +#define CCE_MSIX_TABLE_UPPER (CCE + 0x000000100008) +#define CCE_MSIX_TABLE_UPPER_RESETCSR 0x0000000100000000ull +#define CCE_MSIX_VEC_CLR_WITHOUT_INT (CCE + 0x000000110400) +#define CCE_REVISION (CCE + 0x000000000000) +#define CCE_REVISION2 (CCE + 0x000000000008) +#define CCE_REVISION2_HFI_ID_MASK 0x1ull +#define CCE_REVISION2_HFI_ID_SHIFT 0 +#define CCE_REVISION2_IMPL_CODE_SHIFT 8 +#define CCE_REVISION2_IMPL_REVISION_SHIFT 16 +#define CCE_REVISION_BOARD_ID_LOWER_NIBBLE_MASK 0xFull +#define CCE_REVISION_BOARD_ID_LOWER_NIBBLE_SHIFT 32 +#define CCE_REVISION_CHIP_REV_MAJOR_MASK 0xFFull +#define CCE_REVISION_CHIP_REV_MAJOR_SHIFT 8 +#define CCE_REVISION_CHIP_REV_MINOR_MASK 0xFFull +#define CCE_REVISION_CHIP_REV_MINOR_SHIFT 0 +#define CCE_REVISION_SW_MASK 0xFFull +#define CCE_REVISION_SW_SHIFT 24 +#define CCE_SCRATCH (CCE + 0x000000000020) +#define CCE_STATUS (CCE + 0x000000000018) +#define CCE_STATUS_RXE_FROZE_SMASK 0x2ull +#define CCE_STATUS_RXE_PAUSED_SMASK 0x20ull +#define CCE_STATUS_SDMA_FROZE_SMASK 0x1ull +#define CCE_STATUS_SDMA_PAUSED_SMASK 0x10ull +#define CCE_STATUS_TXE_FROZE_SMASK 0x4ull +#define CCE_STATUS_TXE_PAUSED_SMASK 0x40ull +#define CCE_STATUS_TXE_PIO_FROZE_SMASK 0x8ull +#define CCE_STATUS_TXE_PIO_PAUSED_SMASK 0x80ull +#define MISC_CFG_FW_CTRL (MISC + 0x000000001000) +#define MISC_CFG_FW_CTRL_FW_8051_LOADED_SMASK 0x2ull +#define MISC_CFG_FW_CTRL_RSA_STATUS_SHIFT 2 +#define MISC_CFG_FW_CTRL_RSA_STATUS_SMASK 0xCull +#define MISC_CFG_RSA_CMD (MISC + 0x000000000A08) +#define MISC_CFG_RSA_MODULUS (MISC + 0x000000000400) +#define MISC_CFG_RSA_MU (MISC + 0x000000000A10) +#define MISC_CFG_RSA_R2 (MISC + 0x000000000000) +#define MISC_CFG_RSA_SIGNATURE (MISC + 0x000000000200) +#define MISC_CFG_SHA_PRELOAD (MISC + 0x000000000A00) +#define MISC_ERR_CLEAR (MISC + 0x000000002010) +#define MISC_ERR_MASK (MISC + 0x000000002008) +#define MISC_ERR_STATUS (MISC + 0x000000002000) +#define MISC_ERR_STATUS_MISC_PLL_LOCK_FAIL_ERR_SMASK 0x1000ull +#define MISC_ERR_STATUS_MISC_MBIST_FAIL_ERR_SMASK 0x800ull +#define MISC_ERR_STATUS_MISC_INVALID_EEP_CMD_ERR_SMASK 0x400ull +#define MISC_ERR_STATUS_MISC_EFUSE_DONE_PARITY_ERR_SMASK 0x200ull +#define MISC_ERR_STATUS_MISC_EFUSE_WRITE_ERR_SMASK 0x100ull +#define MISC_ERR_STATUS_MISC_EFUSE_READ_BAD_ADDR_ERR_SMASK 0x80ull +#define MISC_ERR_STATUS_MISC_EFUSE_CSR_PARITY_ERR_SMASK 0x40ull +#define MISC_ERR_STATUS_MISC_FW_AUTH_FAILED_ERR_SMASK 0x20ull +#define MISC_ERR_STATUS_MISC_KEY_MISMATCH_ERR_SMASK 0x10ull +#define MISC_ERR_STATUS_MISC_SBUS_WRITE_FAILED_ERR_SMASK 0x8ull +#define MISC_ERR_STATUS_MISC_CSR_WRITE_BAD_ADDR_ERR_SMASK 0x4ull +#define MISC_ERR_STATUS_MISC_CSR_READ_BAD_ADDR_ERR_SMASK 0x2ull +#define MISC_ERR_STATUS_MISC_CSR_PARITY_ERR_SMASK 0x1ull +#define PCI_CFG_MSIX0 (PCIE + 0x0000000000B0) +#define PCI_CFG_REG1 (PCIE + 0x000000000004) +#define PCI_CFG_REG11 (PCIE + 0x00000000002C) +#define PCIE_CFG_SPCIE1 (PCIE + 0x00000000014C) +#define PCIE_CFG_SPCIE2 (PCIE + 0x000000000150) +#define PCIE_CFG_TPH2 (PCIE + 0x000000000180) +#define RCV_ARRAY (RXE + 0x000000200000) +#define RCV_ARRAY_CNT (RXE + 0x000000000018) +#define RCV_ARRAY_RT_ADDR_MASK 0xFFFFFFFFFull +#define RCV_ARRAY_RT_ADDR_SHIFT 0 +#define RCV_ARRAY_RT_BUF_SIZE_SHIFT 36 +#define RCV_ARRAY_RT_WRITE_ENABLE_SMASK 0x8000000000000000ull +#define RCV_AVAIL_TIME_OUT (RXE + 0x000000100050) +#define RCV_AVAIL_TIME_OUT_TIME_OUT_RELOAD_MASK 0xFFull +#define RCV_AVAIL_TIME_OUT_TIME_OUT_RELOAD_SHIFT 0 +#define RCV_BTH_QP (RXE + 0x000000000028) +#define RCV_BTH_QP_KDETH_QP_MASK 0xFFull +#define RCV_BTH_QP_KDETH_QP_SHIFT 16 +#define RCV_BYPASS (RXE + 0x000000000038) +#define RCV_CONTEXTS (RXE + 0x000000000010) +#define RCV_COUNTER_ARRAY32 (RXE + 0x000000000400) +#define RCV_COUNTER_ARRAY64 (RXE + 0x000000000500) +#define RCV_CTRL (RXE + 0x000000000000) +#define RCV_CTRL_RCV_BYPASS_ENABLE_SMASK 0x10ull +#define RCV_CTRL_RCV_EXTENDED_PSN_ENABLE_SMASK 0x40ull +#define RCV_CTRL_RCV_PARTITION_KEY_ENABLE_SMASK 0x4ull +#define RCV_CTRL_RCV_PORT_ENABLE_SMASK 0x1ull +#define RCV_CTRL_RCV_QP_MAP_ENABLE_SMASK 0x2ull +#define RCV_CTRL_RCV_RSM_ENABLE_SMASK 0x20ull +#define RCV_CTRL_RX_RBUF_INIT_SMASK 0x200ull +#define RCV_CTXT_CTRL (RXE + 0x000000100000) +#define RCV_CTXT_CTRL_DONT_DROP_EGR_FULL_SMASK 0x4ull +#define RCV_CTXT_CTRL_DONT_DROP_RHQ_FULL_SMASK 0x8ull +#define RCV_CTXT_CTRL_EGR_BUF_SIZE_MASK 0x7ull +#define RCV_CTXT_CTRL_EGR_BUF_SIZE_SHIFT 8 +#define RCV_CTXT_CTRL_EGR_BUF_SIZE_SMASK 0x700ull +#define RCV_CTXT_CTRL_ENABLE_SMASK 0x1ull +#define RCV_CTXT_CTRL_INTR_AVAIL_SMASK 0x20ull +#define RCV_CTXT_CTRL_ONE_PACKET_PER_EGR_BUFFER_SMASK 0x2ull +#define RCV_CTXT_CTRL_TAIL_UPD_SMASK 0x40ull +#define RCV_CTXT_CTRL_TID_FLOW_ENABLE_SMASK 0x10ull +#define RCV_CTXT_STATUS (RXE + 0x000000100008) +#define RCV_EGR_CTRL (RXE + 0x000000100010) +#define RCV_EGR_CTRL_EGR_BASE_INDEX_MASK 0x1FFFull +#define RCV_EGR_CTRL_EGR_BASE_INDEX_SHIFT 0 +#define RCV_EGR_CTRL_EGR_CNT_MASK 0x1FFull +#define RCV_EGR_CTRL_EGR_CNT_SHIFT 32 +#define RCV_EGR_INDEX_HEAD (RXE + 0x000000300018) +#define RCV_EGR_INDEX_HEAD_HEAD_MASK 0x7FFull +#define RCV_EGR_INDEX_HEAD_HEAD_SHIFT 0 +#define RCV_ERR_CLEAR (RXE + 0x000000000070) +#define RCV_ERR_INFO (RXE + 0x000000000050) +#define RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SC_SMASK 0x1Full +#define RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK 0x20ull +#define RCV_ERR_MASK (RXE + 0x000000000068) +#define RCV_ERR_STATUS (RXE + 0x000000000060) +#define RCV_ERR_STATUS_RX_CSR_PARITY_ERR_SMASK 0x8000000000000000ull +#define RCV_ERR_STATUS_RX_CSR_READ_BAD_ADDR_ERR_SMASK 0x2000000000000000ull +#define RCV_ERR_STATUS_RX_CSR_WRITE_BAD_ADDR_ERR_SMASK \ + 0x4000000000000000ull +#define RCV_ERR_STATUS_RX_DC_INTF_PARITY_ERR_SMASK 0x2ull +#define RCV_ERR_STATUS_RX_DC_SOP_EOP_PARITY_ERR_SMASK 0x200ull +#define RCV_ERR_STATUS_RX_DMA_CSR_COR_ERR_SMASK 0x1ull +#define RCV_ERR_STATUS_RX_DMA_CSR_PARITY_ERR_SMASK 0x200000000000000ull +#define RCV_ERR_STATUS_RX_DMA_CSR_UNC_ERR_SMASK 0x1000000000000000ull +#define RCV_ERR_STATUS_RX_DMA_DATA_FIFO_RD_COR_ERR_SMASK \ + 0x40000000000000ull +#define RCV_ERR_STATUS_RX_DMA_DATA_FIFO_RD_UNC_ERR_SMASK \ + 0x20000000000000ull +#define RCV_ERR_STATUS_RX_DMA_DQ_FSM_ENCODING_ERR_SMASK \ + 0x800000000000000ull +#define RCV_ERR_STATUS_RX_DMA_EQ_FSM_ENCODING_ERR_SMASK \ + 0x400000000000000ull +#define RCV_ERR_STATUS_RX_DMA_FLAG_COR_ERR_SMASK 0x800ull +#define RCV_ERR_STATUS_RX_DMA_FLAG_UNC_ERR_SMASK 0x400ull +#define RCV_ERR_STATUS_RX_DMA_HDR_FIFO_RD_COR_ERR_SMASK 0x10000000000000ull +#define RCV_ERR_STATUS_RX_DMA_HDR_FIFO_RD_UNC_ERR_SMASK 0x8000000000000ull +#define RCV_ERR_STATUS_RX_HQ_INTR_CSR_PARITY_ERR_SMASK 0x200000000000ull +#define RCV_ERR_STATUS_RX_HQ_INTR_FSM_ERR_SMASK 0x400000000000ull +#define RCV_ERR_STATUS_RX_LOOKUP_CSR_PARITY_ERR_SMASK 0x100000000000ull +#define RCV_ERR_STATUS_RX_LOOKUP_DES_PART1_UNC_COR_ERR_SMASK \ + 0x10000000000ull +#define RCV_ERR_STATUS_RX_LOOKUP_DES_PART1_UNC_ERR_SMASK 0x8000000000ull +#define RCV_ERR_STATUS_RX_LOOKUP_DES_PART2_PARITY_ERR_SMASK \ + 0x20000000000ull +#define RCV_ERR_STATUS_RX_LOOKUP_RCV_ARRAY_COR_ERR_SMASK 0x80000000000ull +#define RCV_ERR_STATUS_RX_LOOKUP_RCV_ARRAY_UNC_ERR_SMASK 0x40000000000ull +#define RCV_ERR_STATUS_RX_RBUF_BAD_LOOKUP_ERR_SMASK 0x40000000ull +#define RCV_ERR_STATUS_RX_RBUF_BLOCK_LIST_READ_COR_ERR_SMASK 0x100000ull +#define RCV_ERR_STATUS_RX_RBUF_BLOCK_LIST_READ_UNC_ERR_SMASK 0x80000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QENT_CNT_PARITY_ERR_SMASK 0x400000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QEOPDW_PARITY_ERR_SMASK 0x10000000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QHD_PTR_PARITY_ERR_SMASK 0x2000000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QHEAD_BUF_NUM_PARITY_ERR_SMASK \ + 0x200000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QNEXT_BUF_PARITY_ERR_SMASK 0x800000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QNUM_OF_PKT_PARITY_ERR_SMASK \ + 0x8000000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QTL_PTR_PARITY_ERR_SMASK 0x4000000ull +#define RCV_ERR_STATUS_RX_RBUF_CSR_QVLD_BIT_PARITY_ERR_SMASK 0x1000000ull +#define RCV_ERR_STATUS_RX_RBUF_CTX_ID_PARITY_ERR_SMASK 0x20000000ull +#define RCV_ERR_STATUS_RX_RBUF_DATA_COR_ERR_SMASK 0x100000000000000ull +#define RCV_ERR_STATUS_RX_RBUF_DATA_UNC_ERR_SMASK 0x80000000000000ull +#define RCV_ERR_STATUS_RX_RBUF_DESC_PART1_COR_ERR_SMASK 0x1000000000000ull +#define RCV_ERR_STATUS_RX_RBUF_DESC_PART1_UNC_ERR_SMASK 0x800000000000ull +#define RCV_ERR_STATUS_RX_RBUF_DESC_PART2_COR_ERR_SMASK 0x4000000000000ull +#define RCV_ERR_STATUS_RX_RBUF_DESC_PART2_UNC_ERR_SMASK 0x2000000000000ull +#define RCV_ERR_STATUS_RX_RBUF_EMPTY_ERR_SMASK 0x100000000ull +#define RCV_ERR_STATUS_RX_RBUF_FL_INITDONE_PARITY_ERR_SMASK 0x800000000ull +#define RCV_ERR_STATUS_RX_RBUF_FL_INIT_WR_ADDR_PARITY_ERR_SMASK \ + 0x1000000000ull +#define RCV_ERR_STATUS_RX_RBUF_FL_RD_ADDR_PARITY_ERR_SMASK 0x200000000ull +#define RCV_ERR_STATUS_RX_RBUF_FL_WR_ADDR_PARITY_ERR_SMASK 0x400000000ull +#define RCV_ERR_STATUS_RX_RBUF_FREE_LIST_COR_ERR_SMASK 0x4000ull +#define RCV_ERR_STATUS_RX_RBUF_FREE_LIST_UNC_ERR_SMASK 0x2000ull +#define RCV_ERR_STATUS_RX_RBUF_FULL_ERR_SMASK 0x80000000ull +#define RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_COR_ERR_SMASK 0x40000ull +#define RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_REG_UNC_COR_ERR_SMASK 0x10000ull +#define RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_REG_UNC_ERR_SMASK 0x8000ull +#define RCV_ERR_STATUS_RX_RBUF_LOOKUP_DES_UNC_ERR_SMASK 0x20000ull +#define RCV_ERR_STATUS_RX_RBUF_NEXT_FREE_BUF_COR_ERR_SMASK 0x4000000000ull +#define RCV_ERR_STATUS_RX_RBUF_NEXT_FREE_BUF_UNC_ERR_SMASK 0x2000000000ull +#define RCV_ERR_STATUS_RX_RCV_CSR_PARITY_ERR_SMASK 0x100ull +#define RCV_ERR_STATUS_RX_RCV_DATA_COR_ERR_SMASK 0x20ull +#define RCV_ERR_STATUS_RX_RCV_DATA_UNC_ERR_SMASK 0x10ull +#define RCV_ERR_STATUS_RX_RCV_FSM_ENCODING_ERR_SMASK 0x1000ull +#define RCV_ERR_STATUS_RX_RCV_HDR_COR_ERR_SMASK 0x8ull +#define RCV_ERR_STATUS_RX_RCV_HDR_UNC_ERR_SMASK 0x4ull +#define RCV_ERR_STATUS_RX_RCV_QP_MAP_TABLE_COR_ERR_SMASK 0x80ull +#define RCV_ERR_STATUS_RX_RCV_QP_MAP_TABLE_UNC_ERR_SMASK 0x40ull +#define RCV_HDR_ADDR (RXE + 0x000000100028) +#define RCV_HDR_CNT (RXE + 0x000000100030) +#define RCV_HDR_CNT_CNT_MASK 0x1FFull +#define RCV_HDR_CNT_CNT_SHIFT 0 +#define RCV_HDR_ENT_SIZE (RXE + 0x000000100038) +#define RCV_HDR_ENT_SIZE_ENT_SIZE_MASK 0x7ull +#define RCV_HDR_ENT_SIZE_ENT_SIZE_SHIFT 0 +#define RCV_HDR_HEAD (RXE + 0x000000300008) +#define RCV_HDR_HEAD_COUNTER_MASK 0xFFull +#define RCV_HDR_HEAD_COUNTER_SHIFT 32 +#define RCV_HDR_HEAD_HEAD_MASK 0x7FFFFull +#define RCV_HDR_HEAD_HEAD_SHIFT 0 +#define RCV_HDR_HEAD_HEAD_SMASK 0x7FFFFull +#define RCV_HDR_OVFL_CNT (RXE + 0x000000100058) +#define RCV_HDR_SIZE (RXE + 0x000000100040) +#define RCV_HDR_SIZE_HDR_SIZE_MASK 0x1Full +#define RCV_HDR_SIZE_HDR_SIZE_SHIFT 0 +#define RCV_HDR_TAIL (RXE + 0x000000300000) +#define RCV_HDR_TAIL_ADDR (RXE + 0x000000100048) +#define RCV_KEY_CTRL (RXE + 0x000000100020) +#define RCV_KEY_CTRL_JOB_KEY_ENABLE_SMASK 0x200000000ull +#define RCV_KEY_CTRL_JOB_KEY_VALUE_MASK 0xFFFFull +#define RCV_KEY_CTRL_JOB_KEY_VALUE_SHIFT 0 +#define RCV_MULTICAST (RXE + 0x000000000030) +#define RCV_PARTITION_KEY (RXE + 0x000000000200) +#define RCV_PARTITION_KEY_PARTITION_KEY_A_MASK 0xFFFFull +#define RCV_PARTITION_KEY_PARTITION_KEY_B_SHIFT 16 +#define RCV_QP_MAP_TABLE (RXE + 0x000000000100) +#define RCV_RSM_CFG (RXE + 0x000000000600) +#define RCV_RSM_CFG_ENABLE_OR_CHAIN_RSM0_MASK 0x1ull +#define RCV_RSM_CFG_ENABLE_OR_CHAIN_RSM0_SHIFT 0 +#define RCV_RSM_CFG_PACKET_TYPE_SHIFT 60 +#define RCV_RSM_MAP_TABLE (RXE + 0x000000000900) +#define RCV_RSM_MAP_TABLE_RCV_CONTEXT_A_MASK 0xFFull +#define RCV_RSM_MATCH (RXE + 0x000000000800) +#define RCV_RSM_MATCH_MASK1_SHIFT 0 +#define RCV_RSM_MATCH_MASK2_SHIFT 16 +#define RCV_RSM_MATCH_VALUE1_SHIFT 8 +#define RCV_RSM_MATCH_VALUE2_SHIFT 24 +#define RCV_RSM_SELECT (RXE + 0x000000000700) +#define RCV_RSM_SELECT_FIELD1_OFFSET_SHIFT 0 +#define RCV_RSM_SELECT_FIELD2_OFFSET_SHIFT 16 +#define RCV_RSM_SELECT_INDEX1_OFFSET_SHIFT 32 +#define RCV_RSM_SELECT_INDEX1_WIDTH_SHIFT 44 +#define RCV_RSM_SELECT_INDEX2_OFFSET_SHIFT 48 +#define RCV_RSM_SELECT_INDEX2_WIDTH_SHIFT 60 +#define RCV_STATUS (RXE + 0x000000000008) +#define RCV_STATUS_RX_PKT_IN_PROGRESS_SMASK 0x1ull +#define RCV_STATUS_RX_RBUF_INIT_DONE_SMASK 0x200ull +#define RCV_STATUS_RX_RBUF_PKT_PENDING_SMASK 0x40ull +#define RCV_TID_CTRL (RXE + 0x000000100018) +#define RCV_TID_CTRL_TID_BASE_INDEX_MASK 0x1FFFull +#define RCV_TID_CTRL_TID_BASE_INDEX_SHIFT 0 +#define RCV_TID_CTRL_TID_PAIR_CNT_MASK 0x1FFull +#define RCV_TID_CTRL_TID_PAIR_CNT_SHIFT 32 +#define RCV_TID_FLOW_TABLE (RXE + 0x000000300800) +#define RCV_VL15 (RXE + 0x000000000048) +#define SEND_BTH_QP (TXE + 0x0000000000A0) +#define SEND_BTH_QP_KDETH_QP_MASK 0xFFull +#define SEND_BTH_QP_KDETH_QP_SHIFT 16 +#define SEND_CM_CREDIT_USED_STATUS (TXE + 0x000000000510) +#define SEND_CM_CREDIT_USED_STATUS_VL0_RETURN_CREDIT_STATUS_SMASK \ + 0x1000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL15_RETURN_CREDIT_STATUS_SMASK \ + 0x8000000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL1_RETURN_CREDIT_STATUS_SMASK \ + 0x2000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL2_RETURN_CREDIT_STATUS_SMASK \ + 0x4000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL3_RETURN_CREDIT_STATUS_SMASK \ + 0x8000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL4_RETURN_CREDIT_STATUS_SMASK \ + 0x10000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL5_RETURN_CREDIT_STATUS_SMASK \ + 0x20000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL6_RETURN_CREDIT_STATUS_SMASK \ + 0x40000000000000ull +#define SEND_CM_CREDIT_USED_STATUS_VL7_RETURN_CREDIT_STATUS_SMASK \ + 0x80000000000000ull +#define SEND_CM_CREDIT_VL (TXE + 0x000000000600) +#define SEND_CM_CREDIT_VL15 (TXE + 0x000000000678) +#define SEND_CM_CREDIT_VL15_DEDICATED_LIMIT_VL_SHIFT 0 +#define SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_MASK 0xFFFFull +#define SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SHIFT 0 +#define SEND_CM_CREDIT_VL_DEDICATED_LIMIT_VL_SMASK 0xFFFFull +#define SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_MASK 0xFFFFull +#define SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_SHIFT 16 +#define SEND_CM_CREDIT_VL_SHARED_LIMIT_VL_SMASK 0xFFFF0000ull +#define SEND_CM_CTRL (TXE + 0x000000000500) +#define SEND_CM_CTRL_FORCE_CREDIT_MODE_SMASK 0x8ull +#define SEND_CM_CTRL_RESETCSR 0x0000000000000020ull +#define SEND_CM_GLOBAL_CREDIT (TXE + 0x000000000508) +#define SEND_CM_GLOBAL_CREDIT_AU_SHIFT 16 +#define SEND_CM_GLOBAL_CREDIT_RESETCSR 0x0000094000030000ull +#define SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_MASK 0xFFFFull +#define SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_SHIFT 0 +#define SEND_CM_GLOBAL_CREDIT_SHARED_LIMIT_SMASK 0xFFFFull +#define SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_MASK 0xFFFFull +#define SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_SHIFT 32 +#define SEND_CM_GLOBAL_CREDIT_TOTAL_CREDIT_LIMIT_SMASK 0xFFFF00000000ull +#define SEND_CM_LOCAL_AU_TABLE0_TO3 (TXE + 0x000000000520) +#define SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE0_SHIFT 0 +#define SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE1_SHIFT 16 +#define SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE2_SHIFT 32 +#define SEND_CM_LOCAL_AU_TABLE0_TO3_LOCAL_AU_TABLE3_SHIFT 48 +#define SEND_CM_LOCAL_AU_TABLE4_TO7 (TXE + 0x000000000528) +#define SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE4_SHIFT 0 +#define SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE5_SHIFT 16 +#define SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE6_SHIFT 32 +#define SEND_CM_LOCAL_AU_TABLE4_TO7_LOCAL_AU_TABLE7_SHIFT 48 +#define SEND_CM_REMOTE_AU_TABLE0_TO3 (TXE + 0x000000000530) +#define SEND_CM_REMOTE_AU_TABLE4_TO7 (TXE + 0x000000000538) +#define SEND_CM_TIMER_CTRL (TXE + 0x000000000518) +#define SEND_CONTEXTS (TXE + 0x000000000010) +#define SEND_CONTEXT_SET_CTRL (TXE + 0x000000000200) +#define SEND_COUNTER_ARRAY32 (TXE + 0x000000000300) +#define SEND_COUNTER_ARRAY64 (TXE + 0x000000000400) +#define SEND_CTRL (TXE + 0x000000000000) +#define SEND_CTRL_CM_RESET_SMASK 0x4ull +#define SEND_CTRL_SEND_ENABLE_SMASK 0x1ull +#define SEND_CTRL_VL_ARBITER_ENABLE_SMASK 0x2ull +#define SEND_CTXT_CHECK_ENABLE (TXE + 0x000000100080) +#define SEND_CTXT_CHECK_ENABLE_CHECK_BYPASS_VL_MAPPING_SMASK 0x80ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_ENABLE_SMASK 0x1ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK 0x4ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_OPCODE_SMASK 0x20ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_PARTITION_KEY_SMASK 0x8ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_SLID_SMASK 0x10ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_VL_MAPPING_SMASK 0x40ull +#define SEND_CTXT_CHECK_ENABLE_CHECK_VL_SMASK 0x2ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_BAD_PKT_LEN_SMASK 0x20000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_BYPASS_BAD_PKT_LEN_SMASK \ + 0x200000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_BYPASS_SMASK 0x800ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_GRH_SMASK 0x400ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_KDETH_PACKETS_SMASK 0x1000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_NON_KDETH_PACKETS_SMASK 0x2000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK \ + 0x100000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_TEST_SMASK 0x10000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_RAW_IPV6_SMASK 0x200ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_RAW_SMASK 0x100ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_LONG_BYPASS_PACKETS_SMASK \ + 0x80000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_LONG_IB_PACKETS_SMASK \ + 0x40000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_SMALL_BYPASS_PACKETS_SMASK \ + 0x8000ull +#define SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_SMALL_IB_PACKETS_SMASK \ + 0x4000ull +#define SEND_CTXT_CHECK_JOB_KEY (TXE + 0x000000100090) +#define SEND_CTXT_CHECK_JOB_KEY_ALLOW_PERMISSIVE_SMASK 0x100000000ull +#define SEND_CTXT_CHECK_JOB_KEY_MASK_SMASK 0xFFFF0000ull +#define SEND_CTXT_CHECK_JOB_KEY_VALUE_MASK 0xFFFFull +#define SEND_CTXT_CHECK_JOB_KEY_VALUE_SHIFT 0 +#define SEND_CTXT_CHECK_OPCODE (TXE + 0x0000001000A8) +#define SEND_CTXT_CHECK_OPCODE_MASK_SHIFT 8 +#define SEND_CTXT_CHECK_OPCODE_VALUE_SHIFT 0 +#define SEND_CTXT_CHECK_PARTITION_KEY (TXE + 0x000000100098) +#define SEND_CTXT_CHECK_PARTITION_KEY_VALUE_MASK 0xFFFFull +#define SEND_CTXT_CHECK_PARTITION_KEY_VALUE_SHIFT 0 +#define SEND_CTXT_CHECK_SLID (TXE + 0x0000001000A0) +#define SEND_CTXT_CHECK_SLID_MASK_MASK 0xFFFFull +#define SEND_CTXT_CHECK_SLID_MASK_SHIFT 16 +#define SEND_CTXT_CHECK_SLID_VALUE_MASK 0xFFFFull +#define SEND_CTXT_CHECK_SLID_VALUE_SHIFT 0 +#define SEND_CTXT_CHECK_VL (TXE + 0x000000100088) +#define SEND_CTXT_CREDIT_CTRL (TXE + 0x000000100010) +#define SEND_CTXT_CREDIT_CTRL_CREDIT_INTR_SMASK 0x20000ull +#define SEND_CTXT_CREDIT_CTRL_EARLY_RETURN_SMASK 0x10000ull +#define SEND_CTXT_CREDIT_CTRL_THRESHOLD_MASK 0x7FFull +#define SEND_CTXT_CREDIT_CTRL_THRESHOLD_SHIFT 0 +#define SEND_CTXT_CREDIT_CTRL_THRESHOLD_SMASK 0x7FFull +#define SEND_CTXT_CREDIT_FORCE (TXE + 0x000000100028) +#define SEND_CTXT_CREDIT_FORCE_FORCE_RETURN_SMASK 0x1ull +#define SEND_CTXT_CREDIT_RETURN_ADDR (TXE + 0x000000100020) +#define SEND_CTXT_CREDIT_RETURN_ADDR_ADDRESS_SMASK 0xFFFFFFFFFFC0ull +#define SEND_CTXT_CTRL (TXE + 0x000000100000) +#define SEND_CTXT_CTRL_CTXT_BASE_MASK 0x3FFFull +#define SEND_CTXT_CTRL_CTXT_BASE_SHIFT 32 +#define SEND_CTXT_CTRL_CTXT_DEPTH_MASK 0x7FFull +#define SEND_CTXT_CTRL_CTXT_DEPTH_SHIFT 48 +#define SEND_CTXT_CTRL_CTXT_ENABLE_SMASK 0x1ull +#define SEND_CTXT_ERR_CLEAR (TXE + 0x000000100050) +#define SEND_CTXT_ERR_MASK (TXE + 0x000000100048) +#define SEND_CTXT_ERR_STATUS (TXE + 0x000000100040) +#define SEND_CTXT_ERR_STATUS_PIO_DISALLOWED_PACKET_ERR_SMASK 0x2ull +#define SEND_CTXT_ERR_STATUS_PIO_INCONSISTENT_SOP_ERR_SMASK 0x1ull +#define SEND_CTXT_ERR_STATUS_PIO_WRITE_CROSSES_BOUNDARY_ERR_SMASK 0x4ull +#define SEND_CTXT_ERR_STATUS_PIO_WRITE_OUT_OF_BOUNDS_ERR_SMASK 0x10ull +#define SEND_CTXT_ERR_STATUS_PIO_WRITE_OVERFLOW_ERR_SMASK 0x8ull +#define SEND_CTXT_STATUS (TXE + 0x000000100008) +#define SEND_CTXT_STATUS_CTXT_HALTED_SMASK 0x1ull +#define SEND_DMA_BASE_ADDR (TXE + 0x000000200010) +#define SEND_DMA_CHECK_ENABLE (TXE + 0x000000200080) +#define SEND_DMA_CHECK_ENABLE_CHECK_BYPASS_VL_MAPPING_SMASK 0x80ull +#define SEND_DMA_CHECK_ENABLE_CHECK_ENABLE_SMASK 0x1ull +#define SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK 0x4ull +#define SEND_DMA_CHECK_ENABLE_CHECK_OPCODE_SMASK 0x20ull +#define SEND_DMA_CHECK_ENABLE_CHECK_PARTITION_KEY_SMASK 0x8ull +#define SEND_DMA_CHECK_ENABLE_CHECK_SLID_SMASK 0x10ull +#define SEND_DMA_CHECK_ENABLE_CHECK_VL_MAPPING_SMASK 0x40ull +#define SEND_DMA_CHECK_ENABLE_CHECK_VL_SMASK 0x2ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_BAD_PKT_LEN_SMASK 0x20000ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_BYPASS_BAD_PKT_LEN_SMASK 0x200000ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK \ + 0x100000ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_RAW_IPV6_SMASK 0x200ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_RAW_SMASK 0x100ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_LONG_BYPASS_PACKETS_SMASK \ + 0x80000ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_LONG_IB_PACKETS_SMASK 0x40000ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_SMALL_BYPASS_PACKETS_SMASK \ + 0x8000ull +#define SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_SMALL_IB_PACKETS_SMASK 0x4000ull +#define SEND_DMA_CHECK_JOB_KEY (TXE + 0x000000200090) +#define SEND_DMA_CHECK_OPCODE (TXE + 0x0000002000A8) +#define SEND_DMA_CHECK_PARTITION_KEY (TXE + 0x000000200098) +#define SEND_DMA_CHECK_SLID (TXE + 0x0000002000A0) +#define SEND_DMA_CHECK_SLID_MASK_MASK 0xFFFFull +#define SEND_DMA_CHECK_SLID_MASK_SHIFT 16 +#define SEND_DMA_CHECK_SLID_VALUE_MASK 0xFFFFull +#define SEND_DMA_CHECK_SLID_VALUE_SHIFT 0 +#define SEND_DMA_CHECK_VL (TXE + 0x000000200088) +#define SEND_DMA_CTRL (TXE + 0x000000200000) +#define SEND_DMA_CTRL_SDMA_CLEANUP_SMASK 0x4ull +#define SEND_DMA_CTRL_SDMA_ENABLE_SMASK 0x1ull +#define SEND_DMA_CTRL_SDMA_HALT_SMASK 0x2ull +#define SEND_DMA_CTRL_SDMA_INT_ENABLE_SMASK 0x8ull +#define SEND_DMA_DESC_CNT (TXE + 0x000000200050) +#define SEND_DMA_DESC_CNT_CNT_MASK 0xFFFFull +#define SEND_DMA_DESC_CNT_CNT_SHIFT 0 +#define SEND_DMA_ENG_ERR_CLEAR (TXE + 0x000000200070) +#define SEND_DMA_ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_MASK 0x1ull +#define SEND_DMA_ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SHIFT 18 +#define SEND_DMA_ENG_ERR_MASK (TXE + 0x000000200068) +#define SEND_DMA_ENG_ERR_STATUS (TXE + 0x000000200060) +#define SEND_DMA_ENG_ERR_STATUS_SDMA_ASSEMBLY_UNC_ERR_SMASK 0x8000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_DESC_TABLE_UNC_ERR_SMASK 0x4000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_FIRST_DESC_ERR_SMASK 0x10ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_GEN_MISMATCH_ERR_SMASK 0x2ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK 0x40ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_HEADER_ADDRESS_ERR_SMASK 0x800ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_HEADER_LENGTH_ERR_SMASK 0x1000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SMASK \ + 0x40000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_HEADER_SELECT_ERR_SMASK 0x400ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_HEADER_STORAGE_UNC_ERR_SMASK \ + 0x20000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_LENGTH_MISMATCH_ERR_SMASK 0x80ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_MEM_READ_ERR_SMASK 0x20ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_PACKET_DESC_OVERFLOW_ERR_SMASK \ + 0x100ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_PACKET_TRACKING_UNC_ERR_SMASK \ + 0x10000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_TAIL_OUT_OF_BOUNDS_ERR_SMASK 0x8ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_TIMEOUT_ERR_SMASK 0x2000ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_TOO_LONG_ERR_SMASK 0x4ull +#define SEND_DMA_ENG_ERR_STATUS_SDMA_WRONG_DW_ERR_SMASK 0x1ull +#define SEND_DMA_ENGINES (TXE + 0x000000000018) +#define SEND_DMA_ERR_CLEAR (TXE + 0x000000000070) +#define SEND_DMA_ERR_MASK (TXE + 0x000000000068) +#define SEND_DMA_ERR_STATUS (TXE + 0x000000000060) +#define SEND_DMA_ERR_STATUS_SDMA_CSR_PARITY_ERR_SMASK 0x2ull +#define SEND_DMA_ERR_STATUS_SDMA_PCIE_REQ_TRACKING_COR_ERR_SMASK 0x8ull +#define SEND_DMA_ERR_STATUS_SDMA_PCIE_REQ_TRACKING_UNC_ERR_SMASK 0x4ull +#define SEND_DMA_ERR_STATUS_SDMA_RPY_TAG_ERR_SMASK 0x1ull +#define SEND_DMA_HEAD (TXE + 0x000000200028) +#define SEND_DMA_HEAD_ADDR (TXE + 0x000000200030) +#define SEND_DMA_LEN_GEN (TXE + 0x000000200018) +#define SEND_DMA_LEN_GEN_GENERATION_SHIFT 16 +#define SEND_DMA_LEN_GEN_LENGTH_SHIFT 6 +#define SEND_DMA_MEMORY (TXE + 0x0000002000B0) +#define SEND_DMA_MEMORY_SDMA_MEMORY_CNT_SHIFT 16 +#define SEND_DMA_MEMORY_SDMA_MEMORY_INDEX_SHIFT 0 +#define SEND_DMA_MEM_SIZE (TXE + 0x000000000028) +#define SEND_DMA_PRIORITY_THLD (TXE + 0x000000200038) +#define SEND_DMA_RELOAD_CNT (TXE + 0x000000200048) +#define SEND_DMA_STATUS (TXE + 0x000000200008) +#define SEND_DMA_STATUS_ENG_CLEANED_UP_SMASK 0x200000000000000ull +#define SEND_DMA_STATUS_ENG_HALTED_SMASK 0x100000000000000ull +#define SEND_DMA_TAIL (TXE + 0x000000200020) +#define SEND_EGRESS_CTXT_STATUS (TXE + 0x000000000800) +#define SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_HALT_STATUS_SMASK 0x10000ull +#define SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_PACKET_OCCUPANCY_SHIFT 0 +#define SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_PACKET_OCCUPANCY_SMASK \ + 0x3FFFull +#define SEND_EGRESS_ERR_CLEAR (TXE + 0x000000000090) +#define SEND_EGRESS_ERR_INFO (TXE + 0x000000000F00) +#define SEND_EGRESS_ERR_INFO_BAD_PKT_LEN_ERR_SMASK 0x20000ull +#define SEND_EGRESS_ERR_INFO_BYPASS_ERR_SMASK 0x800ull +#define SEND_EGRESS_ERR_INFO_GRH_ERR_SMASK 0x400ull +#define SEND_EGRESS_ERR_INFO_JOB_KEY_ERR_SMASK 0x4ull +#define SEND_EGRESS_ERR_INFO_KDETH_PACKETS_ERR_SMASK 0x1000ull +#define SEND_EGRESS_ERR_INFO_NON_KDETH_PACKETS_ERR_SMASK 0x2000ull +#define SEND_EGRESS_ERR_INFO_OPCODE_ERR_SMASK 0x20ull +#define SEND_EGRESS_ERR_INFO_PARTITION_KEY_ERR_SMASK 0x8ull +#define SEND_EGRESS_ERR_INFO_PBC_STATIC_RATE_CONTROL_ERR_SMASK 0x100000ull +#define SEND_EGRESS_ERR_INFO_PBC_TEST_ERR_SMASK 0x10000ull +#define SEND_EGRESS_ERR_INFO_RAW_ERR_SMASK 0x100ull +#define SEND_EGRESS_ERR_INFO_RAW_IPV6_ERR_SMASK 0x200ull +#define SEND_EGRESS_ERR_INFO_SLID_ERR_SMASK 0x10ull +#define SEND_EGRESS_ERR_INFO_TOO_LONG_BYPASS_PACKETS_ERR_SMASK 0x80000ull +#define SEND_EGRESS_ERR_INFO_TOO_LONG_IB_PACKET_ERR_SMASK 0x40000ull +#define SEND_EGRESS_ERR_INFO_TOO_SMALL_BYPASS_PACKETS_ERR_SMASK 0x8000ull +#define SEND_EGRESS_ERR_INFO_TOO_SMALL_IB_PACKETS_ERR_SMASK 0x4000ull +#define SEND_EGRESS_ERR_INFO_VL_ERR_SMASK 0x2ull +#define SEND_EGRESS_ERR_INFO_VL_MAPPING_ERR_SMASK 0x40ull +#define SEND_EGRESS_ERR_MASK (TXE + 0x000000000088) +#define SEND_EGRESS_ERR_SOURCE (TXE + 0x000000000F08) +#define SEND_EGRESS_ERR_STATUS (TXE + 0x000000000080) +#define SEND_EGRESS_ERR_STATUS_TX_CONFIG_PARITY_ERR_SMASK 0x8000ull +#define SEND_EGRESS_ERR_STATUS_TX_CREDIT_OVERRUN_ERR_SMASK \ + 0x200000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_CREDIT_RETURN_PARITY_ERR_SMASK \ + 0x20000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_CREDIT_RETURN_VL_ERR_SMASK \ + 0x800000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_EGRESS_FIFO_COR_ERR_SMASK \ + 0x2000000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_EGRESS_FIFO_UNC_ERR_SMASK \ + 0x200000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_EGRESS_FIFO_UNDERRUN_OR_PARITY_ERR_SMASK \ + 0x8ull +#define SEND_EGRESS_ERR_STATUS_TX_HCRC_INSERTION_ERR_SMASK \ + 0x400000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_ILLEGAL_VL_ERR_SMASK 0x1000ull +#define SEND_EGRESS_ERR_STATUS_TX_INCORRECT_LINK_STATE_ERR_SMASK 0x20ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_CSR_PARITY_ERR_SMASK 0x2000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO0_COR_ERR_SMASK \ + 0x1000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO0_UNC_OR_PARITY_ERR_SMASK \ + 0x100000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO1_COR_ERR_SMASK \ + 0x2000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO1_UNC_OR_PARITY_ERR_SMASK \ + 0x200000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO2_COR_ERR_SMASK \ + 0x4000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO2_UNC_OR_PARITY_ERR_SMASK \ + 0x400000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO3_COR_ERR_SMASK \ + 0x8000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO3_UNC_OR_PARITY_ERR_SMASK \ + 0x800000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO4_COR_ERR_SMASK \ + 0x10000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO4_UNC_OR_PARITY_ERR_SMASK \ + 0x1000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO5_COR_ERR_SMASK \ + 0x20000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO5_UNC_OR_PARITY_ERR_SMASK \ + 0x2000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO6_COR_ERR_SMASK \ + 0x40000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO6_UNC_OR_PARITY_ERR_SMASK \ + 0x4000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO7_COR_ERR_SMASK \ + 0x80000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO7_UNC_OR_PARITY_ERR_SMASK \ + 0x8000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO8_COR_ERR_SMASK \ + 0x100000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LAUNCH_FIFO8_UNC_OR_PARITY_ERR_SMASK \ + 0x10000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_LINKDOWN_ERR_SMASK 0x10ull +#define SEND_EGRESS_ERR_STATUS_TX_PIO_LAUNCH_INTF_PARITY_ERR_SMASK 0x80ull +#define SEND_EGRESS_ERR_STATUS_TX_PKT_INTEGRITY_MEM_COR_ERR_SMASK 0x1ull +#define SEND_EGRESS_ERR_STATUS_TX_PKT_INTEGRITY_MEM_UNC_ERR_SMASK 0x2ull +#define SEND_EGRESS_ERR_STATUS_TX_READ_PIO_MEMORY_COR_ERR_SMASK \ + 0x1000000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_READ_PIO_MEMORY_CSR_UNC_ERR_SMASK \ + 0x8000000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_READ_PIO_MEMORY_UNC_ERR_SMASK \ + 0x100000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_READ_SDMA_MEMORY_COR_ERR_SMASK \ + 0x800000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_READ_SDMA_MEMORY_CSR_UNC_ERR_SMASK \ + 0x4000000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_READ_SDMA_MEMORY_UNC_ERR_SMASK \ + 0x80000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SB_HDR_COR_ERR_SMASK 0x400000000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SB_HDR_UNC_ERR_SMASK 0x40000000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SBRD_CTL_CSR_PARITY_ERR_SMASK 0x4000ull +#define SEND_EGRESS_ERR_STATUS_TX_SBRD_CTL_STATE_MACHINE_PARITY_ERR_SMASK \ + 0x800ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA0_DISALLOWED_PACKET_ERR_SMASK \ + 0x10000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA10_DISALLOWED_PACKET_ERR_SMASK \ + 0x4000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA11_DISALLOWED_PACKET_ERR_SMASK \ + 0x8000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA12_DISALLOWED_PACKET_ERR_SMASK \ + 0x10000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA13_DISALLOWED_PACKET_ERR_SMASK \ + 0x20000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA14_DISALLOWED_PACKET_ERR_SMASK \ + 0x40000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA15_DISALLOWED_PACKET_ERR_SMASK \ + 0x80000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA1_DISALLOWED_PACKET_ERR_SMASK \ + 0x20000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA2_DISALLOWED_PACKET_ERR_SMASK \ + 0x40000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA3_DISALLOWED_PACKET_ERR_SMASK \ + 0x80000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA4_DISALLOWED_PACKET_ERR_SMASK \ + 0x100000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA5_DISALLOWED_PACKET_ERR_SMASK \ + 0x200000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA6_DISALLOWED_PACKET_ERR_SMASK \ + 0x400000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA7_DISALLOWED_PACKET_ERR_SMASK \ + 0x800000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA8_DISALLOWED_PACKET_ERR_SMASK \ + 0x1000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA9_DISALLOWED_PACKET_ERR_SMASK \ + 0x2000000ull +#define SEND_EGRESS_ERR_STATUS_TX_SDMA_LAUNCH_INTF_PARITY_ERR_SMASK \ + 0x100ull +#define SEND_EGRESS_SEND_DMA_STATUS (TXE + 0x000000000E00) +#define SEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT 0 +#define SEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SMASK \ + 0x3FFFull +#define SEND_ERR_CLEAR (TXE + 0x0000000000F0) +#define SEND_ERR_MASK (TXE + 0x0000000000E8) +#define SEND_ERR_STATUS (TXE + 0x0000000000E0) +#define SEND_ERR_STATUS_SEND_CSR_PARITY_ERR_SMASK 0x1ull +#define SEND_ERR_STATUS_SEND_CSR_READ_BAD_ADDR_ERR_SMASK 0x2ull +#define SEND_ERR_STATUS_SEND_CSR_WRITE_BAD_ADDR_ERR_SMASK 0x4ull +#define SEND_HIGH_PRIORITY_LIMIT (TXE + 0x000000000030) +#define SEND_HIGH_PRIORITY_LIMIT_LIMIT_MASK 0x3FFFull +#define SEND_HIGH_PRIORITY_LIMIT_LIMIT_SHIFT 0 +#define SEND_HIGH_PRIORITY_LIST (TXE + 0x000000000180) +#define SEND_LEN_CHECK0 (TXE + 0x0000000000D0) +#define SEND_LEN_CHECK0_LEN_VL0_MASK 0xFFFull +#define SEND_LEN_CHECK0_LEN_VL1_SHIFT 12 +#define SEND_LEN_CHECK1 (TXE + 0x0000000000D8) +#define SEND_LEN_CHECK1_LEN_VL15_MASK 0xFFFull +#define SEND_LEN_CHECK1_LEN_VL15_SHIFT 48 +#define SEND_LEN_CHECK1_LEN_VL4_MASK 0xFFFull +#define SEND_LEN_CHECK1_LEN_VL5_SHIFT 12 +#define SEND_LOW_PRIORITY_LIST (TXE + 0x000000000100) +#define SEND_LOW_PRIORITY_LIST_VL_MASK 0x7ull +#define SEND_LOW_PRIORITY_LIST_VL_SHIFT 16 +#define SEND_LOW_PRIORITY_LIST_WEIGHT_MASK 0xFFull +#define SEND_LOW_PRIORITY_LIST_WEIGHT_SHIFT 0 +#define SEND_PIO_ERR_CLEAR (TXE + 0x000000000050) +#define SEND_PIO_ERR_CLEAR_PIO_INIT_SM_IN_ERR_SMASK 0x20000ull +#define SEND_PIO_ERR_MASK (TXE + 0x000000000048) +#define SEND_PIO_ERR_STATUS (TXE + 0x000000000040) +#define SEND_PIO_ERR_STATUS_PIO_BLOCK_QW_COUNT_PARITY_ERR_SMASK \ + 0x1000000ull +#define SEND_PIO_ERR_STATUS_PIO_CREDIT_RET_FIFO_PARITY_ERR_SMASK 0x8000ull +#define SEND_PIO_ERR_STATUS_PIO_CSR_PARITY_ERR_SMASK 0x4ull +#define SEND_PIO_ERR_STATUS_PIO_CURRENT_FREE_CNT_PARITY_ERR_SMASK \ + 0x100000000ull +#define SEND_PIO_ERR_STATUS_PIO_HOST_ADDR_MEM_COR_ERR_SMASK 0x100000ull +#define SEND_PIO_ERR_STATUS_PIO_HOST_ADDR_MEM_UNC_ERR_SMASK 0x80000ull +#define SEND_PIO_ERR_STATUS_PIO_INIT_SM_IN_ERR_SMASK 0x20000ull +#define SEND_PIO_ERR_STATUS_PIO_LAST_RETURNED_CNT_PARITY_ERR_SMASK \ + 0x200000000ull +#define SEND_PIO_ERR_STATUS_PIO_PCC_FIFO_PARITY_ERR_SMASK 0x20ull +#define SEND_PIO_ERR_STATUS_PIO_PCC_SOP_HEAD_PARITY_ERR_SMASK \ + 0x400000000ull +#define SEND_PIO_ERR_STATUS_PIO_PEC_FIFO_PARITY_ERR_SMASK 0x40ull +#define SEND_PIO_ERR_STATUS_PIO_PEC_SOP_HEAD_PARITY_ERR_SMASK \ + 0x800000000ull +#define SEND_PIO_ERR_STATUS_PIO_PKT_EVICT_FIFO_PARITY_ERR_SMASK 0x200ull +#define SEND_PIO_ERR_STATUS_PIO_PKT_EVICT_SM_OR_ARB_SM_ERR_SMASK 0x40000ull +#define SEND_PIO_ERR_STATUS_PIO_PPMC_BQC_MEM_PARITY_ERR_SMASK 0x10000000ull +#define SEND_PIO_ERR_STATUS_PIO_PPMC_PBL_FIFO_ERR_SMASK 0x10000ull +#define SEND_PIO_ERR_STATUS_PIO_PPMC_SOP_LEN_ERR_SMASK 0x20000000ull +#define SEND_PIO_ERR_STATUS_PIO_SB_MEM_FIFO0_ERR_SMASK 0x8ull +#define SEND_PIO_ERR_STATUS_PIO_SB_MEM_FIFO1_ERR_SMASK 0x10ull +#define SEND_PIO_ERR_STATUS_PIO_SBRDCTL_CRREL_PARITY_ERR_SMASK 0x80ull +#define SEND_PIO_ERR_STATUS_PIO_SBRDCTRL_CRREL_FIFO_PARITY_ERR_SMASK \ + 0x100ull +#define SEND_PIO_ERR_STATUS_PIO_SM_PKT_RESET_PARITY_ERR_SMASK 0x400ull +#define SEND_PIO_ERR_STATUS_PIO_STATE_MACHINE_ERR_SMASK 0x400000ull +#define SEND_PIO_ERR_STATUS_PIO_VL_FIFO_PARITY_ERR_SMASK 0x8000000ull +#define SEND_PIO_ERR_STATUS_PIO_VLF_SOP_PARITY_ERR_SMASK 0x4000000ull +#define SEND_PIO_ERR_STATUS_PIO_VLF_VL_LEN_PARITY_ERR_SMASK 0x2000000ull +#define SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK0_COR_ERR_SMASK 0x2000ull +#define SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK0_UNC_ERR_SMASK 0x800ull +#define SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK1_COR_ERR_SMASK 0x4000ull +#define SEND_PIO_ERR_STATUS_PIO_VL_LEN_MEM_BANK1_UNC_ERR_SMASK 0x1000ull +#define SEND_PIO_ERR_STATUS_PIO_WRITE_ADDR_PARITY_ERR_SMASK 0x2ull +#define SEND_PIO_ERR_STATUS_PIO_WRITE_BAD_CTXT_ERR_SMASK 0x1ull +#define SEND_PIO_ERR_STATUS_PIO_WRITE_DATA_PARITY_ERR_SMASK 0x200000ull +#define SEND_PIO_ERR_STATUS_PIO_WRITE_QW_VALID_PARITY_ERR_SMASK 0x800000ull +#define SEND_PIO_INIT_CTXT (TXE + 0x000000000038) +#define SEND_PIO_INIT_CTXT_PIO_ALL_CTXT_INIT_SMASK 0x1ull +#define SEND_PIO_INIT_CTXT_PIO_CTXT_NUM_MASK 0xFFull +#define SEND_PIO_INIT_CTXT_PIO_CTXT_NUM_SHIFT 8 +#define SEND_PIO_INIT_CTXT_PIO_INIT_ERR_SMASK 0x8ull +#define SEND_PIO_INIT_CTXT_PIO_INIT_IN_PROGRESS_SMASK 0x4ull +#define SEND_PIO_INIT_CTXT_PIO_SINGLE_CTXT_INIT_SMASK 0x2ull +#define SEND_PIO_MEM_SIZE (TXE + 0x000000000020) +#define SEND_SC2VLT0 (TXE + 0x0000000000B0) +#define SEND_SC2VLT0_SC0_SHIFT 0 +#define SEND_SC2VLT0_SC1_SHIFT 8 +#define SEND_SC2VLT0_SC2_SHIFT 16 +#define SEND_SC2VLT0_SC3_SHIFT 24 +#define SEND_SC2VLT0_SC4_SHIFT 32 +#define SEND_SC2VLT0_SC5_SHIFT 40 +#define SEND_SC2VLT0_SC6_SHIFT 48 +#define SEND_SC2VLT0_SC7_SHIFT 56 +#define SEND_SC2VLT1 (TXE + 0x0000000000B8) +#define SEND_SC2VLT1_SC10_SHIFT 16 +#define SEND_SC2VLT1_SC11_SHIFT 24 +#define SEND_SC2VLT1_SC12_SHIFT 32 +#define SEND_SC2VLT1_SC13_SHIFT 40 +#define SEND_SC2VLT1_SC14_SHIFT 48 +#define SEND_SC2VLT1_SC15_SHIFT 56 +#define SEND_SC2VLT1_SC8_SHIFT 0 +#define SEND_SC2VLT1_SC9_SHIFT 8 +#define SEND_SC2VLT2 (TXE + 0x0000000000C0) +#define SEND_SC2VLT2_SC16_SHIFT 0 +#define SEND_SC2VLT2_SC17_SHIFT 8 +#define SEND_SC2VLT2_SC18_SHIFT 16 +#define SEND_SC2VLT2_SC19_SHIFT 24 +#define SEND_SC2VLT2_SC20_SHIFT 32 +#define SEND_SC2VLT2_SC21_SHIFT 40 +#define SEND_SC2VLT2_SC22_SHIFT 48 +#define SEND_SC2VLT2_SC23_SHIFT 56 +#define SEND_SC2VLT3 (TXE + 0x0000000000C8) +#define SEND_SC2VLT3_SC24_SHIFT 0 +#define SEND_SC2VLT3_SC25_SHIFT 8 +#define SEND_SC2VLT3_SC26_SHIFT 16 +#define SEND_SC2VLT3_SC27_SHIFT 24 +#define SEND_SC2VLT3_SC28_SHIFT 32 +#define SEND_SC2VLT3_SC29_SHIFT 40 +#define SEND_SC2VLT3_SC30_SHIFT 48 +#define SEND_SC2VLT3_SC31_SHIFT 56 +#define SEND_STATIC_RATE_CONTROL (TXE + 0x0000000000A8) +#define SEND_STATIC_RATE_CONTROL_CSR_SRC_RELOAD_SHIFT 0 +#define SEND_STATIC_RATE_CONTROL_CSR_SRC_RELOAD_SMASK 0xFFFFull +#define PCIE_CFG_REG_PL2 (PCIE + 0x000000000708) +#define PCIE_CFG_REG_PL102 (PCIE + 0x000000000898) +#define PCIE_CFG_REG_PL102_GEN3_EQ_POST_CURSOR_PSET_SHIFT 12 +#define PCIE_CFG_REG_PL102_GEN3_EQ_CURSOR_PSET_SHIFT 6 +#define PCIE_CFG_REG_PL102_GEN3_EQ_PRE_CURSOR_PSET_SHIFT 0 +#define PCIE_CFG_REG_PL103 (PCIE + 0x00000000089C) +#define PCIE_CFG_REG_PL105 (PCIE + 0x0000000008A4) +#define PCIE_CFG_REG_PL105_GEN3_EQ_VIOLATE_COEF_RULES_SMASK 0x1ull +#define PCIE_CFG_REG_PL2_LOW_PWR_ENT_CNT_SHIFT 24 +#define PCIE_CFG_REG_PL100 (PCIE + 0x000000000890) +#define PCIE_CFG_REG_PL100_EQ_EIEOS_CNT_SMASK 0x400ull +#define PCIE_CFG_REG_PL101 (PCIE + 0x000000000894) +#define PCIE_CFG_REG_PL101_GEN3_EQ_LOCAL_FS_SHIFT 6 +#define PCIE_CFG_REG_PL101_GEN3_EQ_LOCAL_LF_SHIFT 0 +#define PCIE_CFG_REG_PL106 (PCIE + 0x0000000008A8) +#define PCIE_CFG_REG_PL106_GEN3_EQ_PSET_REQ_VEC_SHIFT 8 +#define PCIE_CFG_REG_PL106_GEN3_EQ_EVAL2MS_DISABLE_SMASK 0x20ull +#define PCIE_CFG_REG_PL106_GEN3_EQ_PHASE23_EXIT_MODE_SMASK 0x10ull + +#endif /* DEF_CHIP_REG */ diff --git a/drivers/staging/rdma/hfi1/common.h b/drivers/staging/rdma/hfi1/common.h new file mode 100644 index 0000000000000..5f2293729cf90 --- /dev/null +++ b/drivers/staging/rdma/hfi1/common.h @@ -0,0 +1,415 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef _COMMON_H +#define _COMMON_H + +#include + +/* + * This file contains defines, structures, etc. that are used + * to communicate between kernel and user code. + */ + +/* version of protocol header (known to chip also). In the long run, + * we should be able to generate and accept a range of version numbers; + * for now we only accept one, and it's compiled in. + */ +#define IPS_PROTO_VERSION 2 + +/* + * These are compile time constants that you may want to enable or disable + * if you are trying to debug problems with code or performance. + * HFI1_VERBOSE_TRACING define as 1 if you want additional tracing in + * fast path code + * HFI1_TRACE_REGWRITES define as 1 if you want register writes to be + * traced in fast path code + * _HFI1_TRACING define as 0 if you want to remove all tracing in a + * compilation unit + */ + +/* + * If a packet's QP[23:16] bits match this value, then it is + * a PSM packet and the hardware will expect a KDETH header + * following the BTH. + */ +#define DEFAULT_KDETH_QP 0x80 + +/* driver/hw feature set bitmask */ +#define HFI1_CAP_USER_SHIFT 24 +#define HFI1_CAP_MASK ((1UL << HFI1_CAP_USER_SHIFT) - 1) +/* locked flag - if set, only HFI1_CAP_WRITABLE_MASK bits can be set */ +#define HFI1_CAP_LOCKED_SHIFT 63 +#define HFI1_CAP_LOCKED_MASK 0x1ULL +#define HFI1_CAP_LOCKED_SMASK (HFI1_CAP_LOCKED_MASK << HFI1_CAP_LOCKED_SHIFT) +/* extra bits used between kernel and user processes */ +#define HFI1_CAP_MISC_SHIFT (HFI1_CAP_USER_SHIFT * 2) +#define HFI1_CAP_MISC_MASK ((1ULL << (HFI1_CAP_LOCKED_SHIFT - \ + HFI1_CAP_MISC_SHIFT)) - 1) + +#define HFI1_CAP_KSET(cap) ({ hfi1_cap_mask |= HFI1_CAP_##cap; hfi1_cap_mask; }) +#define HFI1_CAP_KCLEAR(cap) \ + ({ \ + hfi1_cap_mask &= ~HFI1_CAP_##cap; \ + hfi1_cap_mask; \ + }) +#define HFI1_CAP_USET(cap) \ + ({ \ + hfi1_cap_mask |= (HFI1_CAP_##cap << HFI1_CAP_USER_SHIFT); \ + hfi1_cap_mask; \ + }) +#define HFI1_CAP_UCLEAR(cap) \ + ({ \ + hfi1_cap_mask &= ~(HFI1_CAP_##cap << HFI1_CAP_USER_SHIFT); \ + hfi1_cap_mask; \ + }) +#define HFI1_CAP_SET(cap) \ + ({ \ + hfi1_cap_mask |= (HFI1_CAP_##cap | (HFI1_CAP_##cap << \ + HFI1_CAP_USER_SHIFT)); \ + hfi1_cap_mask; \ + }) +#define HFI1_CAP_CLEAR(cap) \ + ({ \ + hfi1_cap_mask &= ~(HFI1_CAP_##cap | \ + (HFI1_CAP_##cap << HFI1_CAP_USER_SHIFT)); \ + hfi1_cap_mask; \ + }) +#define HFI1_CAP_LOCK() \ + ({ hfi1_cap_mask |= HFI1_CAP_LOCKED_SMASK; hfi1_cap_mask; }) +#define HFI1_CAP_LOCKED() (!!(hfi1_cap_mask & HFI1_CAP_LOCKED_SMASK)) +/* + * The set of capability bits that can be changed after initial load + * This set is the same for kernel and user contexts. However, for + * user contexts, the set can be further filtered by using the + * HFI1_CAP_RESERVED_MASK bits. + */ +#define HFI1_CAP_WRITABLE_MASK (HFI1_CAP_SDMA_AHG | \ + HFI1_CAP_HDRSUPP | \ + HFI1_CAP_MULTI_PKT_EGR | \ + HFI1_CAP_NODROP_RHQ_FULL | \ + HFI1_CAP_NODROP_EGR_FULL | \ + HFI1_CAP_ALLOW_PERM_JKEY | \ + HFI1_CAP_STATIC_RATE_CTRL | \ + HFI1_CAP_PRINT_UNIMPL) +/* + * A set of capability bits that are "global" and are not allowed to be + * set in the user bitmask. + */ +#define HFI1_CAP_RESERVED_MASK ((HFI1_CAP_SDMA | \ + HFI1_CAP_USE_SDMA_HEAD | \ + HFI1_CAP_EXTENDED_PSN | \ + HFI1_CAP_PRINT_UNIMPL | \ + HFI1_CAP_QSFP_ENABLED | \ + HFI1_CAP_NO_INTEGRITY | \ + HFI1_CAP_PKEY_CHECK) << \ + HFI1_CAP_USER_SHIFT) +/* + * Set of capabilities that need to be enabled for kernel context in + * order to be allowed for user contexts, as well. + */ +#define HFI1_CAP_MUST_HAVE_KERN (HFI1_CAP_STATIC_RATE_CTRL) +/* Default enabled capabilities (both kernel and user) */ +#define HFI1_CAP_MASK_DEFAULT (HFI1_CAP_HDRSUPP | \ + HFI1_CAP_NODROP_RHQ_FULL | \ + HFI1_CAP_NODROP_EGR_FULL | \ + HFI1_CAP_SDMA | \ + HFI1_CAP_PRINT_UNIMPL | \ + HFI1_CAP_STATIC_RATE_CTRL | \ + HFI1_CAP_QSFP_ENABLED | \ + HFI1_CAP_PKEY_CHECK | \ + HFI1_CAP_MULTI_PKT_EGR | \ + HFI1_CAP_EXTENDED_PSN | \ + ((HFI1_CAP_HDRSUPP | \ + HFI1_CAP_MULTI_PKT_EGR | \ + HFI1_CAP_STATIC_RATE_CTRL | \ + HFI1_CAP_PKEY_CHECK | \ + HFI1_CAP_EARLY_CREDIT_RETURN) << \ + HFI1_CAP_USER_SHIFT)) +/* + * A bitmask of kernel/global capabilities that should be communicated + * to user level processes. + */ +#define HFI1_CAP_K2U (HFI1_CAP_SDMA | \ + HFI1_CAP_EXTENDED_PSN | \ + HFI1_CAP_PKEY_CHECK | \ + HFI1_CAP_NO_INTEGRITY) + +#define HFI1_USER_SWVERSION ((HFI1_USER_SWMAJOR << 16) | HFI1_USER_SWMINOR) + +#ifndef HFI1_KERN_TYPE +#define HFI1_KERN_TYPE 0 +#endif + +/* + * Similarly, this is the kernel version going back to the user. It's + * slightly different, in that we want to tell if the driver was built as + * part of a Intel release, or from the driver from openfabrics.org, + * kernel.org, or a standard distribution, for support reasons. + * The high bit is 0 for non-Intel and 1 for Intel-built/supplied. + * + * It's returned by the driver to the user code during initialization in the + * spi_sw_version field of hfi1_base_info, so the user code can in turn + * check for compatibility with the kernel. +*/ +#define HFI1_KERN_SWVERSION ((HFI1_KERN_TYPE << 31) | HFI1_USER_SWVERSION) + +/* + * Define the driver version number. This is something that refers only + * to the driver itself, not the software interfaces it supports. + */ +#ifndef HFI1_DRIVER_VERSION_BASE +#define HFI1_DRIVER_VERSION_BASE "0.9-248" +#endif + +/* create the final driver version string */ +#ifdef HFI1_IDSTR +#define HFI1_DRIVER_VERSION HFI1_DRIVER_VERSION_BASE " " HFI1_IDSTR +#else +#define HFI1_DRIVER_VERSION HFI1_DRIVER_VERSION_BASE +#endif + +/* + * Diagnostics can send a packet by writing the following + * struct to the diag packet special file. + * + * This allows a custom PBC qword, so that special modes and deliberate + * changes to CRCs can be used. + */ +#define _DIAG_PKT_VERS 1 +struct diag_pkt { + __u16 version; /* structure version */ + __u16 unit; /* which device */ + __u16 sw_index; /* send sw index to use */ + __u16 len; /* data length, in bytes */ + __u16 port; /* port number */ + __u16 unused; + __u32 flags; /* call flags */ + __u64 data; /* user data pointer */ + __u64 pbc; /* PBC for the packet */ +}; + +/* diag_pkt flags */ +#define F_DIAGPKT_WAIT 0x1 /* wait until packet is sent */ + +/* + * The next set of defines are for packet headers, and chip register + * and memory bits that are visible to and/or used by user-mode software. + */ + +/* + * Receive Header Flags + */ +#define RHF_PKT_LEN_SHIFT 0 +#define RHF_PKT_LEN_MASK 0xfffull +#define RHF_PKT_LEN_SMASK (RHF_PKT_LEN_MASK << RHF_PKT_LEN_SHIFT) + +#define RHF_RCV_TYPE_SHIFT 12 +#define RHF_RCV_TYPE_MASK 0x7ull +#define RHF_RCV_TYPE_SMASK (RHF_RCV_TYPE_MASK << RHF_RCV_TYPE_SHIFT) + +#define RHF_USE_EGR_BFR_SHIFT 15 +#define RHF_USE_EGR_BFR_MASK 0x1ull +#define RHF_USE_EGR_BFR_SMASK (RHF_USE_EGR_BFR_MASK << RHF_USE_EGR_BFR_SHIFT) + +#define RHF_EGR_INDEX_SHIFT 16 +#define RHF_EGR_INDEX_MASK 0x7ffull +#define RHF_EGR_INDEX_SMASK (RHF_EGR_INDEX_MASK << RHF_EGR_INDEX_SHIFT) + +#define RHF_DC_INFO_SHIFT 27 +#define RHF_DC_INFO_MASK 0x1ull +#define RHF_DC_INFO_SMASK (RHF_DC_INFO_MASK << RHF_DC_INFO_SHIFT) + +#define RHF_RCV_SEQ_SHIFT 28 +#define RHF_RCV_SEQ_MASK 0xfull +#define RHF_RCV_SEQ_SMASK (RHF_RCV_SEQ_MASK << RHF_RCV_SEQ_SHIFT) + +#define RHF_EGR_OFFSET_SHIFT 32 +#define RHF_EGR_OFFSET_MASK 0xfffull +#define RHF_EGR_OFFSET_SMASK (RHF_EGR_OFFSET_MASK << RHF_EGR_OFFSET_SHIFT) +#define RHF_HDRQ_OFFSET_SHIFT 44 +#define RHF_HDRQ_OFFSET_MASK 0x1ffull +#define RHF_HDRQ_OFFSET_SMASK (RHF_HDRQ_OFFSET_MASK << RHF_HDRQ_OFFSET_SHIFT) +#define RHF_K_HDR_LEN_ERR (0x1ull << 53) +#define RHF_DC_UNC_ERR (0x1ull << 54) +#define RHF_DC_ERR (0x1ull << 55) +#define RHF_RCV_TYPE_ERR_SHIFT 56 +#define RHF_RCV_TYPE_ERR_MASK 0x7ul +#define RHF_RCV_TYPE_ERR_SMASK (RHF_RCV_TYPE_ERR_MASK << RHF_RCV_TYPE_ERR_SHIFT) +#define RHF_TID_ERR (0x1ull << 59) +#define RHF_LEN_ERR (0x1ull << 60) +#define RHF_ECC_ERR (0x1ull << 61) +#define RHF_VCRC_ERR (0x1ull << 62) +#define RHF_ICRC_ERR (0x1ull << 63) + +#define RHF_ERROR_SMASK 0xffe0000000000000ull /* bits 63:53 */ + +/* RHF receive types */ +#define RHF_RCV_TYPE_EXPECTED 0 +#define RHF_RCV_TYPE_EAGER 1 +#define RHF_RCV_TYPE_IB 2 /* normal IB, IB Raw, or IPv6 */ +#define RHF_RCV_TYPE_ERROR 3 +#define RHF_RCV_TYPE_BYPASS 4 +#define RHF_RCV_TYPE_INVALID5 5 +#define RHF_RCV_TYPE_INVALID6 6 +#define RHF_RCV_TYPE_INVALID7 7 + +/* RHF receive type error - expected packet errors */ +#define RHF_RTE_EXPECTED_FLOW_SEQ_ERR 0x2 +#define RHF_RTE_EXPECTED_FLOW_GEN_ERR 0x4 + +/* RHF receive type error - eager packet errors */ +#define RHF_RTE_EAGER_NO_ERR 0x0 + +/* RHF receive type error - IB packet errors */ +#define RHF_RTE_IB_NO_ERR 0x0 + +/* RHF receive type error - error packet errors */ +#define RHF_RTE_ERROR_NO_ERR 0x0 +#define RHF_RTE_ERROR_OP_CODE_ERR 0x1 +#define RHF_RTE_ERROR_KHDR_MIN_LEN_ERR 0x2 +#define RHF_RTE_ERROR_KHDR_HCRC_ERR 0x3 +#define RHF_RTE_ERROR_KHDR_KVER_ERR 0x4 +#define RHF_RTE_ERROR_CONTEXT_ERR 0x5 +#define RHF_RTE_ERROR_KHDR_TID_ERR 0x6 + +/* RHF receive type error - bypass packet errors */ +#define RHF_RTE_BYPASS_NO_ERR 0x0 + +/* + * This structure contains the first field common to all protocols + * that employ this chip. + */ +struct hfi1_message_header { + __be16 lrh[4]; +}; + +/* IB - LRH header constants */ +#define HFI1_LRH_GRH 0x0003 /* 1. word of IB LRH - next header: GRH */ +#define HFI1_LRH_BTH 0x0002 /* 1. word of IB LRH - next header: BTH */ + +/* misc. */ +#define SIZE_OF_CRC 1 + +#define LIM_MGMT_P_KEY 0x7FFF +#define FULL_MGMT_P_KEY 0xFFFF + +#define DEFAULT_P_KEY LIM_MGMT_P_KEY +#define HFI1_PERMISSIVE_LID 0xFFFF +#define HFI1_AETH_CREDIT_SHIFT 24 +#define HFI1_AETH_CREDIT_MASK 0x1F +#define HFI1_AETH_CREDIT_INVAL 0x1F +#define HFI1_MSN_MASK 0xFFFFFF +#define HFI1_QPN_MASK 0xFFFFFF +#define HFI1_FECN_SHIFT 31 +#define HFI1_FECN_MASK 1 +#define HFI1_FECN_SMASK (1 << HFI1_FECN_SHIFT) +#define HFI1_BECN_SHIFT 30 +#define HFI1_BECN_MASK 1 +#define HFI1_BECN_SMASK (1 << HFI1_BECN_SHIFT) +#define HFI1_MULTICAST_LID_BASE 0xC000 + +static inline __u64 rhf_to_cpu(const __le32 *rbuf) +{ + return __le64_to_cpu(*((__le64 *)rbuf)); +} + +static inline u64 rhf_err_flags(u64 rhf) +{ + return rhf & RHF_ERROR_SMASK; +} + +static inline u32 rhf_rcv_type(u64 rhf) +{ + return (rhf >> RHF_RCV_TYPE_SHIFT) & RHF_RCV_TYPE_MASK; +} + +static inline u32 rhf_rcv_type_err(u64 rhf) +{ + return (rhf >> RHF_RCV_TYPE_ERR_SHIFT) & RHF_RCV_TYPE_ERR_MASK; +} + +/* return size is in bytes, not DWORDs */ +static inline u32 rhf_pkt_len(u64 rhf) +{ + return ((rhf & RHF_PKT_LEN_SMASK) >> RHF_PKT_LEN_SHIFT) << 2; +} + +static inline u32 rhf_egr_index(u64 rhf) +{ + return (rhf >> RHF_EGR_INDEX_SHIFT) & RHF_EGR_INDEX_MASK; +} + +static inline u32 rhf_rcv_seq(u64 rhf) +{ + return (rhf >> RHF_RCV_SEQ_SHIFT) & RHF_RCV_SEQ_MASK; +} + +/* returned offset is in DWORDS */ +static inline u32 rhf_hdrq_offset(u64 rhf) +{ + return (rhf >> RHF_HDRQ_OFFSET_SHIFT) & RHF_HDRQ_OFFSET_MASK; +} + +static inline u64 rhf_use_egr_bfr(u64 rhf) +{ + return rhf & RHF_USE_EGR_BFR_SMASK; +} + +static inline u64 rhf_dc_info(u64 rhf) +{ + return rhf & RHF_DC_INFO_SMASK; +} + +static inline u32 rhf_egr_buf_offset(u64 rhf) +{ + return (rhf >> RHF_EGR_OFFSET_SHIFT) & RHF_EGR_OFFSET_MASK; +} +#endif /* _COMMON_H */ diff --git a/drivers/staging/rdma/hfi1/cq.c b/drivers/staging/rdma/hfi1/cq.c new file mode 100644 index 0000000000000..4f046ffe7e60c --- /dev/null +++ b/drivers/staging/rdma/hfi1/cq.c @@ -0,0 +1,558 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "verbs.h" +#include "hfi.h" + +/** + * hfi1_cq_enter - add a new entry to the completion queue + * @cq: completion queue + * @entry: work completion entry to add + * @sig: true if @entry is a solicited entry + * + * This may be called with qp->s_lock held. + */ +void hfi1_cq_enter(struct hfi1_cq *cq, struct ib_wc *entry, int solicited) +{ + struct hfi1_cq_wc *wc; + unsigned long flags; + u32 head; + u32 next; + + spin_lock_irqsave(&cq->lock, flags); + + /* + * Note that the head pointer might be writable by user processes. + * Take care to verify it is a sane value. + */ + wc = cq->queue; + head = wc->head; + if (head >= (unsigned) cq->ibcq.cqe) { + head = cq->ibcq.cqe; + next = 0; + } else + next = head + 1; + if (unlikely(next == wc->tail)) { + spin_unlock_irqrestore(&cq->lock, flags); + if (cq->ibcq.event_handler) { + struct ib_event ev; + + ev.device = cq->ibcq.device; + ev.element.cq = &cq->ibcq; + ev.event = IB_EVENT_CQ_ERR; + cq->ibcq.event_handler(&ev, cq->ibcq.cq_context); + } + return; + } + if (cq->ip) { + wc->uqueue[head].wr_id = entry->wr_id; + wc->uqueue[head].status = entry->status; + wc->uqueue[head].opcode = entry->opcode; + wc->uqueue[head].vendor_err = entry->vendor_err; + wc->uqueue[head].byte_len = entry->byte_len; + wc->uqueue[head].ex.imm_data = + (__u32 __force)entry->ex.imm_data; + wc->uqueue[head].qp_num = entry->qp->qp_num; + wc->uqueue[head].src_qp = entry->src_qp; + wc->uqueue[head].wc_flags = entry->wc_flags; + wc->uqueue[head].pkey_index = entry->pkey_index; + wc->uqueue[head].slid = entry->slid; + wc->uqueue[head].sl = entry->sl; + wc->uqueue[head].dlid_path_bits = entry->dlid_path_bits; + wc->uqueue[head].port_num = entry->port_num; + /* Make sure entry is written before the head index. */ + smp_wmb(); + } else + wc->kqueue[head] = *entry; + wc->head = next; + + if (cq->notify == IB_CQ_NEXT_COMP || + (cq->notify == IB_CQ_SOLICITED && + (solicited || entry->status != IB_WC_SUCCESS))) { + struct kthread_worker *worker; + /* + * This will cause send_complete() to be called in + * another thread. + */ + smp_read_barrier_depends(); /* see hfi1_cq_exit */ + worker = cq->dd->worker; + if (likely(worker)) { + cq->notify = IB_CQ_NONE; + cq->triggered++; + queue_kthread_work(worker, &cq->comptask); + } + } + + spin_unlock_irqrestore(&cq->lock, flags); +} + +/** + * hfi1_poll_cq - poll for work completion entries + * @ibcq: the completion queue to poll + * @num_entries: the maximum number of entries to return + * @entry: pointer to array where work completions are placed + * + * Returns the number of completion entries polled. + * + * This may be called from interrupt context. Also called by ib_poll_cq() + * in the generic verbs code. + */ +int hfi1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) +{ + struct hfi1_cq *cq = to_icq(ibcq); + struct hfi1_cq_wc *wc; + unsigned long flags; + int npolled; + u32 tail; + + /* The kernel can only poll a kernel completion queue */ + if (cq->ip) { + npolled = -EINVAL; + goto bail; + } + + spin_lock_irqsave(&cq->lock, flags); + + wc = cq->queue; + tail = wc->tail; + if (tail > (u32) cq->ibcq.cqe) + tail = (u32) cq->ibcq.cqe; + for (npolled = 0; npolled < num_entries; ++npolled, ++entry) { + if (tail == wc->head) + break; + /* The kernel doesn't need a RMB since it has the lock. */ + *entry = wc->kqueue[tail]; + if (tail >= cq->ibcq.cqe) + tail = 0; + else + tail++; + } + wc->tail = tail; + + spin_unlock_irqrestore(&cq->lock, flags); + +bail: + return npolled; +} + +static void send_complete(struct kthread_work *work) +{ + struct hfi1_cq *cq = container_of(work, struct hfi1_cq, comptask); + + /* + * The completion handler will most likely rearm the notification + * and poll for all pending entries. If a new completion entry + * is added while we are in this routine, queue_work() + * won't call us again until we return so we check triggered to + * see if we need to call the handler again. + */ + for (;;) { + u8 triggered = cq->triggered; + + /* + * IPoIB connected mode assumes the callback is from a + * soft IRQ. We simulate this by blocking "bottom halves". + * See the implementation for ipoib_cm_handle_tx_wc(), + * netif_tx_lock_bh() and netif_tx_lock(). + */ + local_bh_disable(); + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); + local_bh_enable(); + + if (cq->triggered == triggered) + return; + } +} + +/** + * hfi1_create_cq - create a completion queue + * @ibdev: the device this completion queue is attached to + * @attr: creation attributes + * @context: unused by the driver + * @udata: user data for libibverbs.so + * + * Returns a pointer to the completion queue or negative errno values + * for failure. + * + * Called by ib_create_cq() in the generic verbs code. + */ +struct ib_cq *hfi1_create_cq( + struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct hfi1_ibdev *dev = to_idev(ibdev); + struct hfi1_cq *cq; + struct hfi1_cq_wc *wc; + struct ib_cq *ret; + u32 sz; + unsigned int entries = attr->cqe; + + if (attr->flags) + return ERR_PTR(-EINVAL); + + if (entries < 1 || entries > hfi1_max_cqes) + return ERR_PTR(-EINVAL); + + /* Allocate the completion queue structure. */ + cq = kmalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) + return ERR_PTR(-ENOMEM); + + /* + * Allocate the completion queue entries and head/tail pointers. + * This is allocated separately so that it can be resized and + * also mapped into user space. + * We need to use vmalloc() in order to support mmap and large + * numbers of entries. + */ + sz = sizeof(*wc); + if (udata && udata->outlen >= sizeof(__u64)) + sz += sizeof(struct ib_uverbs_wc) * (entries + 1); + else + sz += sizeof(struct ib_wc) * (entries + 1); + wc = vmalloc_user(sz); + if (!wc) { + ret = ERR_PTR(-ENOMEM); + goto bail_cq; + } + + /* + * Return the address of the WC as the offset to mmap. + * See hfi1_mmap() for details. + */ + if (udata && udata->outlen >= sizeof(__u64)) { + int err; + + cq->ip = hfi1_create_mmap_info(dev, sz, context, wc); + if (!cq->ip) { + ret = ERR_PTR(-ENOMEM); + goto bail_wc; + } + + err = ib_copy_to_udata(udata, &cq->ip->offset, + sizeof(cq->ip->offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; + } + } else + cq->ip = NULL; + + spin_lock(&dev->n_cqs_lock); + if (dev->n_cqs_allocated == hfi1_max_cqs) { + spin_unlock(&dev->n_cqs_lock); + ret = ERR_PTR(-ENOMEM); + goto bail_ip; + } + + dev->n_cqs_allocated++; + spin_unlock(&dev->n_cqs_lock); + + if (cq->ip) { + spin_lock_irq(&dev->pending_lock); + list_add(&cq->ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + + /* + * ib_create_cq() will initialize cq->ibcq except for cq->ibcq.cqe. + * The number of entries should be >= the number requested or return + * an error. + */ + cq->dd = dd_from_dev(dev); + cq->ibcq.cqe = entries; + cq->notify = IB_CQ_NONE; + cq->triggered = 0; + spin_lock_init(&cq->lock); + init_kthread_work(&cq->comptask, send_complete); + wc->head = 0; + wc->tail = 0; + cq->queue = wc; + + ret = &cq->ibcq; + + goto done; + +bail_ip: + kfree(cq->ip); +bail_wc: + vfree(wc); +bail_cq: + kfree(cq); +done: + return ret; +} + +/** + * hfi1_destroy_cq - destroy a completion queue + * @ibcq: the completion queue to destroy. + * + * Returns 0 for success. + * + * Called by ib_destroy_cq() in the generic verbs code. + */ +int hfi1_destroy_cq(struct ib_cq *ibcq) +{ + struct hfi1_ibdev *dev = to_idev(ibcq->device); + struct hfi1_cq *cq = to_icq(ibcq); + + flush_kthread_work(&cq->comptask); + spin_lock(&dev->n_cqs_lock); + dev->n_cqs_allocated--; + spin_unlock(&dev->n_cqs_lock); + if (cq->ip) + kref_put(&cq->ip->ref, hfi1_release_mmap_info); + else + vfree(cq->queue); + kfree(cq); + + return 0; +} + +/** + * hfi1_req_notify_cq - change the notification type for a completion queue + * @ibcq: the completion queue + * @notify_flags: the type of notification to request + * + * Returns 0 for success. + * + * This may be called from interrupt context. Also called by + * ib_req_notify_cq() in the generic verbs code. + */ +int hfi1_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags notify_flags) +{ + struct hfi1_cq *cq = to_icq(ibcq); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&cq->lock, flags); + /* + * Don't change IB_CQ_NEXT_COMP to IB_CQ_SOLICITED but allow + * any other transitions (see C11-31 and C11-32 in ch. 11.4.2.2). + */ + if (cq->notify != IB_CQ_NEXT_COMP) + cq->notify = notify_flags & IB_CQ_SOLICITED_MASK; + + if ((notify_flags & IB_CQ_REPORT_MISSED_EVENTS) && + cq->queue->head != cq->queue->tail) + ret = 1; + + spin_unlock_irqrestore(&cq->lock, flags); + + return ret; +} + +/** + * hfi1_resize_cq - change the size of the CQ + * @ibcq: the completion queue + * + * Returns 0 for success. + */ +int hfi1_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata) +{ + struct hfi1_cq *cq = to_icq(ibcq); + struct hfi1_cq_wc *old_wc; + struct hfi1_cq_wc *wc; + u32 head, tail, n; + int ret; + u32 sz; + + if (cqe < 1 || cqe > hfi1_max_cqes) { + ret = -EINVAL; + goto bail; + } + + /* + * Need to use vmalloc() if we want to support large #s of entries. + */ + sz = sizeof(*wc); + if (udata && udata->outlen >= sizeof(__u64)) + sz += sizeof(struct ib_uverbs_wc) * (cqe + 1); + else + sz += sizeof(struct ib_wc) * (cqe + 1); + wc = vmalloc_user(sz); + if (!wc) { + ret = -ENOMEM; + goto bail; + } + + /* Check that we can write the offset to mmap. */ + if (udata && udata->outlen >= sizeof(__u64)) { + __u64 offset = 0; + + ret = ib_copy_to_udata(udata, &offset, sizeof(offset)); + if (ret) + goto bail_free; + } + + spin_lock_irq(&cq->lock); + /* + * Make sure head and tail are sane since they + * might be user writable. + */ + old_wc = cq->queue; + head = old_wc->head; + if (head > (u32) cq->ibcq.cqe) + head = (u32) cq->ibcq.cqe; + tail = old_wc->tail; + if (tail > (u32) cq->ibcq.cqe) + tail = (u32) cq->ibcq.cqe; + if (head < tail) + n = cq->ibcq.cqe + 1 + head - tail; + else + n = head - tail; + if (unlikely((u32)cqe < n)) { + ret = -EINVAL; + goto bail_unlock; + } + for (n = 0; tail != head; n++) { + if (cq->ip) + wc->uqueue[n] = old_wc->uqueue[tail]; + else + wc->kqueue[n] = old_wc->kqueue[tail]; + if (tail == (u32) cq->ibcq.cqe) + tail = 0; + else + tail++; + } + cq->ibcq.cqe = cqe; + wc->head = n; + wc->tail = 0; + cq->queue = wc; + spin_unlock_irq(&cq->lock); + + vfree(old_wc); + + if (cq->ip) { + struct hfi1_ibdev *dev = to_idev(ibcq->device); + struct hfi1_mmap_info *ip = cq->ip; + + hfi1_update_mmap_info(dev, ip, sz, wc); + + /* + * Return the offset to mmap. + * See hfi1_mmap() for details. + */ + if (udata && udata->outlen >= sizeof(__u64)) { + ret = ib_copy_to_udata(udata, &ip->offset, + sizeof(ip->offset)); + if (ret) + goto bail; + } + + spin_lock_irq(&dev->pending_lock); + if (list_empty(&ip->pending_mmaps)) + list_add(&ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + + ret = 0; + goto bail; + +bail_unlock: + spin_unlock_irq(&cq->lock); +bail_free: + vfree(wc); +bail: + return ret; +} + +int hfi1_cq_init(struct hfi1_devdata *dd) +{ + int ret = 0; + int cpu; + struct task_struct *task; + + if (dd->worker) + return 0; + dd->worker = kzalloc(sizeof(*dd->worker), GFP_KERNEL); + if (!dd->worker) + return -ENOMEM; + init_kthread_worker(dd->worker); + task = kthread_create_on_node( + kthread_worker_fn, + dd->worker, + dd->assigned_node_id, + "hfi1_cq%d", dd->unit); + if (IS_ERR(task)) + goto task_fail; + cpu = cpumask_first(cpumask_of_node(dd->assigned_node_id)); + kthread_bind(task, cpu); + wake_up_process(task); +out: + return ret; +task_fail: + ret = PTR_ERR(task); + kfree(dd->worker); + dd->worker = NULL; + goto out; +} + +void hfi1_cq_exit(struct hfi1_devdata *dd) +{ + struct kthread_worker *worker; + + worker = dd->worker; + if (!worker) + return; + /* blocks future queuing from send_complete() */ + dd->worker = NULL; + smp_wmb(); /* See hfi1_cq_enter */ + flush_kthread_worker(worker); + kthread_stop(worker->task); + kfree(worker); +} diff --git a/drivers/staging/rdma/hfi1/debugfs.c b/drivers/staging/rdma/hfi1/debugfs.c new file mode 100644 index 0000000000000..acd2269e9f143 --- /dev/null +++ b/drivers/staging/rdma/hfi1/debugfs.c @@ -0,0 +1,899 @@ +#ifdef CONFIG_DEBUG_FS +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include + +#include "hfi.h" +#include "debugfs.h" +#include "device.h" +#include "qp.h" +#include "sdma.h" + +static struct dentry *hfi1_dbg_root; + +#define private2dd(file) (file_inode(file)->i_private) +#define private2ppd(file) (file_inode(file)->i_private) + +#define DEBUGFS_SEQ_FILE_OPS(name) \ +static const struct seq_operations _##name##_seq_ops = { \ + .start = _##name##_seq_start, \ + .next = _##name##_seq_next, \ + .stop = _##name##_seq_stop, \ + .show = _##name##_seq_show \ +} +#define DEBUGFS_SEQ_FILE_OPEN(name) \ +static int _##name##_open(struct inode *inode, struct file *s) \ +{ \ + struct seq_file *seq; \ + int ret; \ + ret = seq_open(s, &_##name##_seq_ops); \ + if (ret) \ + return ret; \ + seq = s->private_data; \ + seq->private = inode->i_private; \ + return 0; \ +} + +#define DEBUGFS_FILE_OPS(name) \ +static const struct file_operations _##name##_file_ops = { \ + .owner = THIS_MODULE, \ + .open = _##name##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = seq_release \ +} + +#define DEBUGFS_FILE_CREATE(name, parent, data, ops, mode) \ +do { \ + struct dentry *ent; \ + ent = debugfs_create_file(name, mode, parent, \ + data, ops); \ + if (!ent) \ + pr_warn("create of %s failed\n", name); \ +} while (0) + + +#define DEBUGFS_SEQ_FILE_CREATE(name, parent, data) \ + DEBUGFS_FILE_CREATE(#name, parent, data, &_##name##_file_ops, S_IRUGO) + +static void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos) +__acquires(RCU) +{ + struct hfi1_opcode_stats_perctx *opstats; + + rcu_read_lock(); + if (*pos >= ARRAY_SIZE(opstats->stats)) + return NULL; + return pos; +} + +static void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct hfi1_opcode_stats_perctx *opstats; + + ++*pos; + if (*pos >= ARRAY_SIZE(opstats->stats)) + return NULL; + return pos; +} + + +static void _opcode_stats_seq_stop(struct seq_file *s, void *v) +__releases(RCU) +{ + rcu_read_unlock(); +} + +static int _opcode_stats_seq_show(struct seq_file *s, void *v) +{ + loff_t *spos = v; + loff_t i = *spos, j; + u64 n_packets = 0, n_bytes = 0; + struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; + struct hfi1_devdata *dd = dd_from_dev(ibd); + + for (j = 0; j < dd->first_user_ctxt; j++) { + if (!dd->rcd[j]) + continue; + n_packets += dd->rcd[j]->opstats->stats[i].n_packets; + n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes; + } + if (!n_packets && !n_bytes) + return SEQ_SKIP; + seq_printf(s, "%02llx %llu/%llu\n", i, + (unsigned long long) n_packets, + (unsigned long long) n_bytes); + + return 0; +} + +DEBUGFS_SEQ_FILE_OPS(opcode_stats); +DEBUGFS_SEQ_FILE_OPEN(opcode_stats) +DEBUGFS_FILE_OPS(opcode_stats); + +static void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos) +{ + struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; + struct hfi1_devdata *dd = dd_from_dev(ibd); + + if (!*pos) + return SEQ_START_TOKEN; + if (*pos >= dd->first_user_ctxt) + return NULL; + return pos; +} + +static void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; + struct hfi1_devdata *dd = dd_from_dev(ibd); + + if (v == SEQ_START_TOKEN) + return pos; + + ++*pos; + if (*pos >= dd->first_user_ctxt) + return NULL; + return pos; +} + +static void _ctx_stats_seq_stop(struct seq_file *s, void *v) +{ + /* nothing allocated */ +} + +static int _ctx_stats_seq_show(struct seq_file *s, void *v) +{ + loff_t *spos; + loff_t i, j; + u64 n_packets = 0; + struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; + struct hfi1_devdata *dd = dd_from_dev(ibd); + + if (v == SEQ_START_TOKEN) { + seq_puts(s, "Ctx:npkts\n"); + return 0; + } + + spos = v; + i = *spos; + + if (!dd->rcd[i]) + return SEQ_SKIP; + + for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++) + n_packets += dd->rcd[i]->opstats->stats[j].n_packets; + + if (!n_packets) + return SEQ_SKIP; + + seq_printf(s, " %llu:%llu\n", i, n_packets); + return 0; +} + +DEBUGFS_SEQ_FILE_OPS(ctx_stats); +DEBUGFS_SEQ_FILE_OPEN(ctx_stats) +DEBUGFS_FILE_OPS(ctx_stats); + +static void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos) +__acquires(RCU) +{ + struct qp_iter *iter; + loff_t n = *pos; + + rcu_read_lock(); + iter = qp_iter_init(s->private); + if (!iter) + return NULL; + + while (n--) { + if (qp_iter_next(iter)) { + kfree(iter); + return NULL; + } + } + + return iter; +} + +static void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr, + loff_t *pos) +{ + struct qp_iter *iter = iter_ptr; + + (*pos)++; + + if (qp_iter_next(iter)) { + kfree(iter); + return NULL; + } + + return iter; +} + +static void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr) +__releases(RCU) +{ + rcu_read_unlock(); +} + +static int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr) +{ + struct qp_iter *iter = iter_ptr; + + if (!iter) + return 0; + + qp_iter_print(s, iter); + + return 0; +} + +DEBUGFS_SEQ_FILE_OPS(qp_stats); +DEBUGFS_SEQ_FILE_OPEN(qp_stats) +DEBUGFS_FILE_OPS(qp_stats); + +static void *_sdes_seq_start(struct seq_file *s, loff_t *pos) +__acquires(RCU) +{ + struct hfi1_ibdev *ibd; + struct hfi1_devdata *dd; + + rcu_read_lock(); + ibd = (struct hfi1_ibdev *)s->private; + dd = dd_from_dev(ibd); + if (!dd->per_sdma || *pos >= dd->num_sdma) + return NULL; + return pos; +} + +static void *_sdes_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; + struct hfi1_devdata *dd = dd_from_dev(ibd); + + ++*pos; + if (!dd->per_sdma || *pos >= dd->num_sdma) + return NULL; + return pos; +} + + +static void _sdes_seq_stop(struct seq_file *s, void *v) +__releases(RCU) +{ + rcu_read_unlock(); +} + +static int _sdes_seq_show(struct seq_file *s, void *v) +{ + struct hfi1_ibdev *ibd = (struct hfi1_ibdev *)s->private; + struct hfi1_devdata *dd = dd_from_dev(ibd); + loff_t *spos = v; + loff_t i = *spos; + + sdma_seqfile_dump_sde(s, &dd->per_sdma[i]); + return 0; +} + +DEBUGFS_SEQ_FILE_OPS(sdes); +DEBUGFS_SEQ_FILE_OPEN(sdes) +DEBUGFS_FILE_OPS(sdes); + +/* read the per-device counters */ +static ssize_t dev_counters_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u64 *counters; + size_t avail; + struct hfi1_devdata *dd; + ssize_t rval; + + rcu_read_lock(); + dd = private2dd(file); + avail = hfi1_read_cntrs(dd, *ppos, NULL, &counters); + rval = simple_read_from_buffer(buf, count, ppos, counters, avail); + rcu_read_unlock(); + return rval; +} + +/* read the per-device counters */ +static ssize_t dev_names_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char *names; + size_t avail; + struct hfi1_devdata *dd; + ssize_t rval; + + rcu_read_lock(); + dd = private2dd(file); + avail = hfi1_read_cntrs(dd, *ppos, &names, NULL); + rval = simple_read_from_buffer(buf, count, ppos, names, avail); + rcu_read_unlock(); + return rval; +} + +struct counter_info { + char *name; + const struct file_operations ops; +}; + +/* + * Could use file_inode(file)->i_ino to figure out which file, + * instead of separate routine for each, but for now, this works... + */ + +/* read the per-port names (same for each port) */ +static ssize_t portnames_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + char *names; + size_t avail; + struct hfi1_devdata *dd; + ssize_t rval; + + rcu_read_lock(); + dd = private2dd(file); + /* port number n/a here since names are constant */ + avail = hfi1_read_portcntrs(dd, *ppos, 0, &names, NULL); + rval = simple_read_from_buffer(buf, count, ppos, names, avail); + rcu_read_unlock(); + return rval; +} + +/* read the per-port counters */ +static ssize_t portcntrs_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u64 *counters; + size_t avail; + struct hfi1_devdata *dd; + struct hfi1_pportdata *ppd; + ssize_t rval; + + rcu_read_lock(); + ppd = private2ppd(file); + dd = ppd->dd; + avail = hfi1_read_portcntrs(dd, *ppos, ppd->port - 1, NULL, &counters); + rval = simple_read_from_buffer(buf, count, ppos, counters, avail); + rcu_read_unlock(); + return rval; +} + +/* + * read the per-port QSFP data for ppd + */ +static ssize_t qsfp_debugfs_dump(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct hfi1_pportdata *ppd; + char *tmp; + int ret; + + rcu_read_lock(); + ppd = private2ppd(file); + tmp = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!tmp) { + rcu_read_unlock(); + return -ENOMEM; + } + + ret = qsfp_dump(ppd, tmp, PAGE_SIZE); + if (ret > 0) + ret = simple_read_from_buffer(buf, count, ppos, tmp, ret); + rcu_read_unlock(); + kfree(tmp); + return ret; +} + +/* Do an i2c write operation on the chain for the given HFI. */ +static ssize_t __i2c_debugfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, u32 target) +{ + struct hfi1_pportdata *ppd; + char *buff; + int ret; + int i2c_addr; + int offset; + int total_written; + + rcu_read_lock(); + ppd = private2ppd(file); + + buff = kmalloc(count, GFP_KERNEL); + if (!buff) { + ret = -ENOMEM; + goto _return; + } + + ret = copy_from_user(buff, buf, count); + if (ret > 0) { + ret = -EFAULT; + goto _free; + } + + i2c_addr = (*ppos >> 16) & 0xff; + offset = *ppos & 0xffff; + + total_written = i2c_write(ppd, target, i2c_addr, offset, buff, count); + if (total_written < 0) { + ret = total_written; + goto _free; + } + + *ppos += total_written; + + ret = total_written; + + _free: + kfree(buff); + _return: + rcu_read_unlock(); + return ret; +} + +/* Do an i2c write operation on chain for HFI 0. */ +static ssize_t i2c1_debugfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return __i2c_debugfs_write(file, buf, count, ppos, 0); +} + +/* Do an i2c write operation on chain for HFI 1. */ +static ssize_t i2c2_debugfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return __i2c_debugfs_write(file, buf, count, ppos, 1); +} + +/* Do an i2c read operation on the chain for the given HFI. */ +static ssize_t __i2c_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos, u32 target) +{ + struct hfi1_pportdata *ppd; + char *buff; + int ret; + int i2c_addr; + int offset; + int total_read; + + rcu_read_lock(); + ppd = private2ppd(file); + + buff = kmalloc(count, GFP_KERNEL); + if (!buff) { + ret = -ENOMEM; + goto _return; + } + + i2c_addr = (*ppos >> 16) & 0xff; + offset = *ppos & 0xffff; + + total_read = i2c_read(ppd, target, i2c_addr, offset, buff, count); + if (total_read < 0) { + ret = total_read; + goto _free; + } + + *ppos += total_read; + + ret = copy_to_user(buf, buff, total_read); + if (ret > 0) { + ret = -EFAULT; + goto _free; + } + + ret = total_read; + + _free: + kfree(buff); + _return: + rcu_read_unlock(); + return ret; +} + +/* Do an i2c read operation on chain for HFI 0. */ +static ssize_t i2c1_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return __i2c_debugfs_read(file, buf, count, ppos, 0); +} + +/* Do an i2c read operation on chain for HFI 1. */ +static ssize_t i2c2_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return __i2c_debugfs_read(file, buf, count, ppos, 1); +} + +/* Do a QSFP write operation on the i2c chain for the given HFI. */ +static ssize_t __qsfp_debugfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos, u32 target) +{ + struct hfi1_pportdata *ppd; + char *buff; + int ret; + int total_written; + + rcu_read_lock(); + if (*ppos + count > QSFP_PAGESIZE * 4) { /* base page + page00-page03 */ + ret = -EINVAL; + goto _return; + } + + ppd = private2ppd(file); + + buff = kmalloc(count, GFP_KERNEL); + if (!buff) { + ret = -ENOMEM; + goto _return; + } + + ret = copy_from_user(buff, buf, count); + if (ret > 0) { + ret = -EFAULT; + goto _free; + } + + total_written = qsfp_write(ppd, target, *ppos, buff, count); + if (total_written < 0) { + ret = total_written; + goto _free; + } + + *ppos += total_written; + + ret = total_written; + + _free: + kfree(buff); + _return: + rcu_read_unlock(); + return ret; +} + +/* Do a QSFP write operation on i2c chain for HFI 0. */ +static ssize_t qsfp1_debugfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return __qsfp_debugfs_write(file, buf, count, ppos, 0); +} + +/* Do a QSFP write operation on i2c chain for HFI 1. */ +static ssize_t qsfp2_debugfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + return __qsfp_debugfs_write(file, buf, count, ppos, 1); +} + +/* Do a QSFP read operation on the i2c chain for the given HFI. */ +static ssize_t __qsfp_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos, u32 target) +{ + struct hfi1_pportdata *ppd; + char *buff; + int ret; + int total_read; + + rcu_read_lock(); + if (*ppos + count > QSFP_PAGESIZE * 4) { /* base page + page00-page03 */ + ret = -EINVAL; + goto _return; + } + + ppd = private2ppd(file); + + buff = kmalloc(count, GFP_KERNEL); + if (!buff) { + ret = -ENOMEM; + goto _return; + } + + total_read = qsfp_read(ppd, target, *ppos, buff, count); + if (total_read < 0) { + ret = total_read; + goto _free; + } + + *ppos += total_read; + + ret = copy_to_user(buf, buff, total_read); + if (ret > 0) { + ret = -EFAULT; + goto _free; + } + + ret = total_read; + + _free: + kfree(buff); + _return: + rcu_read_unlock(); + return ret; +} + +/* Do a QSFP read operation on i2c chain for HFI 0. */ +static ssize_t qsfp1_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return __qsfp_debugfs_read(file, buf, count, ppos, 0); +} + +/* Do a QSFP read operation on i2c chain for HFI 1. */ +static ssize_t qsfp2_debugfs_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + return __qsfp_debugfs_read(file, buf, count, ppos, 1); +} + +#define DEBUGFS_OPS(nm, readroutine, writeroutine) \ +{ \ + .name = nm, \ + .ops = { \ + .read = readroutine, \ + .write = writeroutine, \ + .llseek = generic_file_llseek, \ + }, \ +} + +static const struct counter_info cntr_ops[] = { + DEBUGFS_OPS("counter_names", dev_names_read, NULL), + DEBUGFS_OPS("counters", dev_counters_read, NULL), + DEBUGFS_OPS("portcounter_names", portnames_read, NULL), +}; + +static const struct counter_info port_cntr_ops[] = { + DEBUGFS_OPS("port%dcounters", portcntrs_debugfs_read, NULL), + DEBUGFS_OPS("i2c1", i2c1_debugfs_read, i2c1_debugfs_write), + DEBUGFS_OPS("i2c2", i2c2_debugfs_read, i2c2_debugfs_write), + DEBUGFS_OPS("qsfp_dump%d", qsfp_debugfs_dump, NULL), + DEBUGFS_OPS("qsfp1", qsfp1_debugfs_read, qsfp1_debugfs_write), + DEBUGFS_OPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write), +}; + +void hfi1_dbg_ibdev_init(struct hfi1_ibdev *ibd) +{ + char name[sizeof("port0counters") + 1]; + char link[10]; + struct hfi1_devdata *dd = dd_from_dev(ibd); + struct hfi1_pportdata *ppd; + int unit = dd->unit; + int i, j; + + if (!hfi1_dbg_root) + return; + snprintf(name, sizeof(name), "%s_%d", class_name(), unit); + snprintf(link, sizeof(link), "%d", unit); + ibd->hfi1_ibdev_dbg = debugfs_create_dir(name, hfi1_dbg_root); + if (!ibd->hfi1_ibdev_dbg) { + pr_warn("create of %s failed\n", name); + return; + } + ibd->hfi1_ibdev_link = + debugfs_create_symlink(link, hfi1_dbg_root, name); + if (!ibd->hfi1_ibdev_link) { + pr_warn("create of %s symlink failed\n", name); + return; + } + DEBUGFS_SEQ_FILE_CREATE(opcode_stats, ibd->hfi1_ibdev_dbg, ibd); + DEBUGFS_SEQ_FILE_CREATE(ctx_stats, ibd->hfi1_ibdev_dbg, ibd); + DEBUGFS_SEQ_FILE_CREATE(qp_stats, ibd->hfi1_ibdev_dbg, ibd); + DEBUGFS_SEQ_FILE_CREATE(sdes, ibd->hfi1_ibdev_dbg, ibd); + /* dev counter files */ + for (i = 0; i < ARRAY_SIZE(cntr_ops); i++) + DEBUGFS_FILE_CREATE(cntr_ops[i].name, + ibd->hfi1_ibdev_dbg, + dd, + &cntr_ops[i].ops, S_IRUGO); + /* per port files */ + for (ppd = dd->pport, j = 0; j < dd->num_pports; j++, ppd++) + for (i = 0; i < ARRAY_SIZE(port_cntr_ops); i++) { + snprintf(name, + sizeof(name), + port_cntr_ops[i].name, + j + 1); + DEBUGFS_FILE_CREATE(name, + ibd->hfi1_ibdev_dbg, + ppd, + &port_cntr_ops[i].ops, + port_cntr_ops[i].ops.write == NULL ? + S_IRUGO : S_IRUGO|S_IWUSR); + } +} + +void hfi1_dbg_ibdev_exit(struct hfi1_ibdev *ibd) +{ + if (!hfi1_dbg_root) + goto out; + debugfs_remove(ibd->hfi1_ibdev_link); + debugfs_remove_recursive(ibd->hfi1_ibdev_dbg); +out: + ibd->hfi1_ibdev_dbg = NULL; + synchronize_rcu(); +} + +/* + * driver stats field names, one line per stat, single string. Used by + * programs like hfistats to print the stats in a way which works for + * different versions of drivers, without changing program source. + * if hfi1_ib_stats changes, this needs to change. Names need to be + * 12 chars or less (w/o newline), for proper display by hfistats utility. + */ +static const char * const hfi1_statnames[] = { + /* must be element 0*/ + "KernIntr", + "ErrorIntr", + "Tx_Errs", + "Rcv_Errs", + "H/W_Errs", + "NoPIOBufs", + "CtxtsOpen", + "RcvLen_Errs", + "EgrBufFull", + "EgrHdrFull" +}; + +static void *_driver_stats_names_seq_start(struct seq_file *s, loff_t *pos) +__acquires(RCU) +{ + rcu_read_lock(); + if (*pos >= ARRAY_SIZE(hfi1_statnames)) + return NULL; + return pos; +} + +static void *_driver_stats_names_seq_next( + struct seq_file *s, + void *v, + loff_t *pos) +{ + ++*pos; + if (*pos >= ARRAY_SIZE(hfi1_statnames)) + return NULL; + return pos; +} + +static void _driver_stats_names_seq_stop(struct seq_file *s, void *v) +__releases(RCU) +{ + rcu_read_unlock(); +} + +static int _driver_stats_names_seq_show(struct seq_file *s, void *v) +{ + loff_t *spos = v; + + seq_printf(s, "%s\n", hfi1_statnames[*spos]); + return 0; +} + +DEBUGFS_SEQ_FILE_OPS(driver_stats_names); +DEBUGFS_SEQ_FILE_OPEN(driver_stats_names) +DEBUGFS_FILE_OPS(driver_stats_names); + +static void *_driver_stats_seq_start(struct seq_file *s, loff_t *pos) +__acquires(RCU) +{ + rcu_read_lock(); + if (*pos >= ARRAY_SIZE(hfi1_statnames)) + return NULL; + return pos; +} + +static void *_driver_stats_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + ++*pos; + if (*pos >= ARRAY_SIZE(hfi1_statnames)) + return NULL; + return pos; +} + +static void _driver_stats_seq_stop(struct seq_file *s, void *v) +__releases(RCU) +{ + rcu_read_unlock(); +} + +static u64 hfi1_sps_ints(void) +{ + unsigned long flags; + struct hfi1_devdata *dd; + u64 sps_ints = 0; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + list_for_each_entry(dd, &hfi1_dev_list, list) { + sps_ints += get_all_cpu_total(dd->int_counter); + } + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + return sps_ints; +} + +static int _driver_stats_seq_show(struct seq_file *s, void *v) +{ + loff_t *spos = v; + char *buffer; + u64 *stats = (u64 *)&hfi1_stats; + size_t sz = seq_get_buf(s, &buffer); + + if (sz < sizeof(u64)) + return SEQ_SKIP; + /* special case for interrupts */ + if (*spos == 0) + *(u64 *)buffer = hfi1_sps_ints(); + else + *(u64 *)buffer = stats[*spos]; + seq_commit(s, sizeof(u64)); + return 0; +} + +DEBUGFS_SEQ_FILE_OPS(driver_stats); +DEBUGFS_SEQ_FILE_OPEN(driver_stats) +DEBUGFS_FILE_OPS(driver_stats); + +void hfi1_dbg_init(void) +{ + hfi1_dbg_root = debugfs_create_dir(DRIVER_NAME, NULL); + if (!hfi1_dbg_root) + pr_warn("init of debugfs failed\n"); + DEBUGFS_SEQ_FILE_CREATE(driver_stats_names, hfi1_dbg_root, NULL); + DEBUGFS_SEQ_FILE_CREATE(driver_stats, hfi1_dbg_root, NULL); +} + +void hfi1_dbg_exit(void) +{ + debugfs_remove_recursive(hfi1_dbg_root); + hfi1_dbg_root = NULL; +} + +#endif diff --git a/drivers/staging/rdma/hfi1/debugfs.h b/drivers/staging/rdma/hfi1/debugfs.h new file mode 100644 index 0000000000000..92d6fe1467141 --- /dev/null +++ b/drivers/staging/rdma/hfi1/debugfs.h @@ -0,0 +1,78 @@ +#ifndef _HFI1_DEBUGFS_H +#define _HFI1_DEBUGFS_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +struct hfi1_ibdev; +#ifdef CONFIG_DEBUG_FS +void hfi1_dbg_ibdev_init(struct hfi1_ibdev *ibd); +void hfi1_dbg_ibdev_exit(struct hfi1_ibdev *ibd); +void hfi1_dbg_init(void); +void hfi1_dbg_exit(void); +#else +static inline void hfi1_dbg_ibdev_init(struct hfi1_ibdev *ibd) +{ +} + +void hfi1_dbg_ibdev_exit(struct hfi1_ibdev *ibd) +{ +} + +void hfi1_dbg_init(void) +{ +} + +void hfi1_dbg_exit(void) +{ +} + +#endif + +#endif /* _HFI1_DEBUGFS_H */ diff --git a/drivers/staging/rdma/hfi1/device.c b/drivers/staging/rdma/hfi1/device.c new file mode 100644 index 0000000000000..07c87a87775fd --- /dev/null +++ b/drivers/staging/rdma/hfi1/device.c @@ -0,0 +1,142 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include + +#include "hfi.h" +#include "device.h" + +static struct class *class; +static dev_t hfi1_dev; + +int hfi1_cdev_init(int minor, const char *name, + const struct file_operations *fops, + struct cdev *cdev, struct device **devp) +{ + const dev_t dev = MKDEV(MAJOR(hfi1_dev), minor); + struct device *device = NULL; + int ret; + + cdev_init(cdev, fops); + cdev->owner = THIS_MODULE; + kobject_set_name(&cdev->kobj, name); + + ret = cdev_add(cdev, dev, 1); + if (ret < 0) { + pr_err("Could not add cdev for minor %d, %s (err %d)\n", + minor, name, -ret); + goto done; + } + + device = device_create(class, NULL, dev, NULL, "%s", name); + if (!IS_ERR(device)) + goto done; + ret = PTR_ERR(device); + device = NULL; + pr_err("Could not create device for minor %d, %s (err %d)\n", + minor, name, -ret); + cdev_del(cdev); +done: + *devp = device; + return ret; +} + +void hfi1_cdev_cleanup(struct cdev *cdev, struct device **devp) +{ + struct device *device = *devp; + + if (device) { + device_unregister(device); + *devp = NULL; + + cdev_del(cdev); + } +} + +static const char *hfi1_class_name = "hfi1"; + +const char *class_name(void) +{ + return hfi1_class_name; +} + +int __init dev_init(void) +{ + int ret; + + ret = alloc_chrdev_region(&hfi1_dev, 0, HFI1_NMINORS, DRIVER_NAME); + if (ret < 0) { + pr_err("Could not allocate chrdev region (err %d)\n", -ret); + goto done; + } + + class = class_create(THIS_MODULE, class_name()); + if (IS_ERR(class)) { + ret = PTR_ERR(class); + pr_err("Could not create device class (err %d)\n", -ret); + unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); + } + +done: + return ret; +} + +void dev_cleanup(void) +{ + if (class) { + class_destroy(class); + class = NULL; + } + + unregister_chrdev_region(hfi1_dev, HFI1_NMINORS); +} diff --git a/drivers/staging/rdma/hfi1/device.h b/drivers/staging/rdma/hfi1/device.h new file mode 100644 index 0000000000000..98caecd3d807e --- /dev/null +++ b/drivers/staging/rdma/hfi1/device.h @@ -0,0 +1,61 @@ +#ifndef _HFI1_DEVICE_H +#define _HFI1_DEVICE_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +int hfi1_cdev_init(int minor, const char *name, + const struct file_operations *fops, + struct cdev *cdev, struct device **devp); +void hfi1_cdev_cleanup(struct cdev *cdev, struct device **devp); +const char *class_name(void); +int __init dev_init(void); +void dev_cleanup(void); + +#endif /* _HFI1_DEVICE_H */ diff --git a/drivers/staging/rdma/hfi1/diag.c b/drivers/staging/rdma/hfi1/diag.c new file mode 100644 index 0000000000000..6777d6b659cf4 --- /dev/null +++ b/drivers/staging/rdma/hfi1/diag.c @@ -0,0 +1,1873 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * This file contains support for diagnostic functions. It is accessed by + * opening the hfi1_diag device, normally minor number 129. Diagnostic use + * of the chip may render the chip or board unusable until the driver + * is unloaded, or in some cases, until the system is rebooted. + * + * Accesses to the chip through this interface are not similar to going + * through the /sys/bus/pci resource mmap interface. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hfi.h" +#include "device.h" +#include "common.h" +#include "trace.h" + +#undef pr_fmt +#define pr_fmt(fmt) DRIVER_NAME ": " fmt +#define snoop_dbg(fmt, ...) \ + hfi1_cdbg(SNOOP, fmt, ##__VA_ARGS__) + +/* Snoop option mask */ +#define SNOOP_DROP_SEND (1 << 0) +#define SNOOP_USE_METADATA (1 << 1) + +static u8 snoop_flags; + +/* + * Extract packet length from LRH header. + * Why & 0x7FF? Because len is only 11 bits in case it wasn't 0'd we throw the + * bogus bits away. This is in Dwords so multiply by 4 to get size in bytes + */ +#define HFI1_GET_PKT_LEN(x) (((be16_to_cpu((x)->lrh[2]) & 0x7FF)) << 2) + +enum hfi1_filter_status { + HFI1_FILTER_HIT, + HFI1_FILTER_ERR, + HFI1_FILTER_MISS +}; + +/* snoop processing functions */ +rhf_rcv_function_ptr snoop_rhf_rcv_functions[8] = { + [RHF_RCV_TYPE_EXPECTED] = snoop_recv_handler, + [RHF_RCV_TYPE_EAGER] = snoop_recv_handler, + [RHF_RCV_TYPE_IB] = snoop_recv_handler, + [RHF_RCV_TYPE_ERROR] = snoop_recv_handler, + [RHF_RCV_TYPE_BYPASS] = snoop_recv_handler, + [RHF_RCV_TYPE_INVALID5] = process_receive_invalid, + [RHF_RCV_TYPE_INVALID6] = process_receive_invalid, + [RHF_RCV_TYPE_INVALID7] = process_receive_invalid +}; + +/* Snoop packet structure */ +struct snoop_packet { + struct list_head list; + u32 total_len; + u8 data[]; +}; + +/* Do not make these an enum or it will blow up the capture_md */ +#define PKT_DIR_EGRESS 0x0 +#define PKT_DIR_INGRESS 0x1 + +/* Packet capture metadata returned to the user with the packet. */ +struct capture_md { + u8 port; + u8 dir; + u8 reserved[6]; + union { + u64 pbc; + u64 rhf; + } u; +}; + +static atomic_t diagpkt_count = ATOMIC_INIT(0); +static struct cdev diagpkt_cdev; +static struct device *diagpkt_device; + +static ssize_t diagpkt_write(struct file *fp, const char __user *data, + size_t count, loff_t *off); + +static const struct file_operations diagpkt_file_ops = { + .owner = THIS_MODULE, + .write = diagpkt_write, + .llseek = noop_llseek, +}; + +/* + * This is used for communication with user space for snoop extended IOCTLs + */ +struct hfi1_link_info { + __be64 node_guid; + u8 port_mode; + u8 port_state; + u16 link_speed_active; + u16 link_width_active; + u16 vl15_init; + u8 port_number; + /* + * Add padding to make this a full IB SMP payload. Note: changing the + * size of this structure will make the IOCTLs created with _IOWR + * change. + * Be sure to run tests on all IOCTLs when making changes to this + * structure. + */ + u8 res[47]; +}; + +/* + * This starts our ioctl sequence numbers *way* off from the ones + * defined in ib_core. + */ +#define SNOOP_CAPTURE_VERSION 0x1 + +#define IB_IOCTL_MAGIC 0x1b /* See Documentation/ioctl-number.txt */ +#define HFI1_SNOOP_IOC_MAGIC IB_IOCTL_MAGIC +#define HFI1_SNOOP_IOC_BASE_SEQ 0x80 + +#define HFI1_SNOOP_IOCGETLINKSTATE \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ) +#define HFI1_SNOOP_IOCSETLINKSTATE \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+1) +#define HFI1_SNOOP_IOCCLEARQUEUE \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+2) +#define HFI1_SNOOP_IOCCLEARFILTER \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+3) +#define HFI1_SNOOP_IOCSETFILTER \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+4) +#define HFI1_SNOOP_IOCGETVERSION \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+5) +#define HFI1_SNOOP_IOCSET_OPTS \ + _IO(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+6) + +/* + * These offsets +6/+7 could change, but these are already known and used + * IOCTL numbers so don't change them without a good reason. + */ +#define HFI1_SNOOP_IOCGETLINKSTATE_EXTRA \ + _IOWR(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+6, \ + struct hfi1_link_info) +#define HFI1_SNOOP_IOCSETLINKSTATE_EXTRA \ + _IOWR(HFI1_SNOOP_IOC_MAGIC, HFI1_SNOOP_IOC_BASE_SEQ+7, \ + struct hfi1_link_info) + +static int hfi1_snoop_open(struct inode *in, struct file *fp); +static ssize_t hfi1_snoop_read(struct file *fp, char __user *data, + size_t pkt_len, loff_t *off); +static ssize_t hfi1_snoop_write(struct file *fp, const char __user *data, + size_t count, loff_t *off); +static long hfi1_ioctl(struct file *fp, unsigned int cmd, unsigned long arg); +static unsigned int hfi1_snoop_poll(struct file *fp, + struct poll_table_struct *wait); +static int hfi1_snoop_release(struct inode *in, struct file *fp); + +struct hfi1_packet_filter_command { + int opcode; + int length; + void *value_ptr; +}; + +/* Can't re-use PKT_DIR_*GRESS here because 0 means no packets for this */ +#define HFI1_SNOOP_INGRESS 0x1 +#define HFI1_SNOOP_EGRESS 0x2 + +enum hfi1_packet_filter_opcodes { + FILTER_BY_LID, + FILTER_BY_DLID, + FILTER_BY_MAD_MGMT_CLASS, + FILTER_BY_QP_NUMBER, + FILTER_BY_PKT_TYPE, + FILTER_BY_SERVICE_LEVEL, + FILTER_BY_PKEY, + FILTER_BY_DIRECTION, +}; + +static const struct file_operations snoop_file_ops = { + .owner = THIS_MODULE, + .open = hfi1_snoop_open, + .read = hfi1_snoop_read, + .unlocked_ioctl = hfi1_ioctl, + .poll = hfi1_snoop_poll, + .write = hfi1_snoop_write, + .release = hfi1_snoop_release +}; + +struct hfi1_filter_array { + int (*filter)(void *, void *, void *); +}; + +static int hfi1_filter_lid(void *ibhdr, void *packet_data, void *value); +static int hfi1_filter_dlid(void *ibhdr, void *packet_data, void *value); +static int hfi1_filter_mad_mgmt_class(void *ibhdr, void *packet_data, + void *value); +static int hfi1_filter_qp_number(void *ibhdr, void *packet_data, void *value); +static int hfi1_filter_ibpacket_type(void *ibhdr, void *packet_data, + void *value); +static int hfi1_filter_ib_service_level(void *ibhdr, void *packet_data, + void *value); +static int hfi1_filter_ib_pkey(void *ibhdr, void *packet_data, void *value); +static int hfi1_filter_direction(void *ibhdr, void *packet_data, void *value); + +static struct hfi1_filter_array hfi1_filters[] = { + { hfi1_filter_lid }, + { hfi1_filter_dlid }, + { hfi1_filter_mad_mgmt_class }, + { hfi1_filter_qp_number }, + { hfi1_filter_ibpacket_type }, + { hfi1_filter_ib_service_level }, + { hfi1_filter_ib_pkey }, + { hfi1_filter_direction }, +}; + +#define HFI1_MAX_FILTERS ARRAY_SIZE(hfi1_filters) +#define HFI1_DIAG_MINOR_BASE 129 + +static int hfi1_snoop_add(struct hfi1_devdata *dd, const char *name); + +int hfi1_diag_add(struct hfi1_devdata *dd) +{ + char name[16]; + int ret = 0; + + snprintf(name, sizeof(name), "%s_diagpkt%d", class_name(), + dd->unit); + /* + * Do this for each device as opposed to the normal diagpkt + * interface which is one per host + */ + ret = hfi1_snoop_add(dd, name); + if (ret) + dd_dev_err(dd, "Unable to init snoop/capture device"); + + snprintf(name, sizeof(name), "%s_diagpkt", class_name()); + if (atomic_inc_return(&diagpkt_count) == 1) { + ret = hfi1_cdev_init(HFI1_DIAGPKT_MINOR, name, + &diagpkt_file_ops, &diagpkt_cdev, + &diagpkt_device); + } + + return ret; +} + +/* this must be called w/ dd->snoop_in_lock held */ +static void drain_snoop_list(struct list_head *queue) +{ + struct list_head *pos, *q; + struct snoop_packet *packet; + + list_for_each_safe(pos, q, queue) { + packet = list_entry(pos, struct snoop_packet, list); + list_del(pos); + kfree(packet); + } +} + +static void hfi1_snoop_remove(struct hfi1_devdata *dd) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + drain_snoop_list(&dd->hfi1_snoop.queue); + hfi1_cdev_cleanup(&dd->hfi1_snoop.cdev, &dd->hfi1_snoop.class_dev); + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); +} + +void hfi1_diag_remove(struct hfi1_devdata *dd) +{ + + hfi1_snoop_remove(dd); + if (atomic_dec_and_test(&diagpkt_count)) + hfi1_cdev_cleanup(&diagpkt_cdev, &diagpkt_device); + hfi1_cdev_cleanup(&dd->diag_cdev, &dd->diag_device); +} + + +/* + * Allocated structure shared between the credit return mechanism and + * diagpkt_send(). + */ +struct diagpkt_wait { + struct completion credits_returned; + int code; + atomic_t count; +}; + +/* + * When each side is finished with the structure, they call this. + * The last user frees the structure. + */ +static void put_diagpkt_wait(struct diagpkt_wait *wait) +{ + if (atomic_dec_and_test(&wait->count)) + kfree(wait); +} + +/* + * Callback from the credit return code. Set the complete, which + * will let diapkt_send() continue. + */ +static void diagpkt_complete(void *arg, int code) +{ + struct diagpkt_wait *wait = (struct diagpkt_wait *)arg; + + wait->code = code; + complete(&wait->credits_returned); + put_diagpkt_wait(wait); /* finished with the structure */ +} + +/** + * diagpkt_send - send a packet + * @dp: diag packet descriptor + */ +static ssize_t diagpkt_send(struct diag_pkt *dp) +{ + struct hfi1_devdata *dd; + struct send_context *sc; + struct pio_buf *pbuf; + u32 *tmpbuf = NULL; + ssize_t ret = 0; + u32 pkt_len, total_len; + pio_release_cb credit_cb = NULL; + void *credit_arg = NULL; + struct diagpkt_wait *wait = NULL; + + dd = hfi1_lookup(dp->unit); + if (!dd || !(dd->flags & HFI1_PRESENT) || !dd->kregbase) { + ret = -ENODEV; + goto bail; + } + if (!(dd->flags & HFI1_INITTED)) { + /* no hardware, freeze, etc. */ + ret = -ENODEV; + goto bail; + } + + if (dp->version != _DIAG_PKT_VERS) { + dd_dev_err(dd, "Invalid version %u for diagpkt_write\n", + dp->version); + ret = -EINVAL; + goto bail; + } + + /* send count must be an exact number of dwords */ + if (dp->len & 3) { + ret = -EINVAL; + goto bail; + } + + /* there is only port 1 */ + if (dp->port != 1) { + ret = -EINVAL; + goto bail; + } + + /* need a valid context */ + if (dp->sw_index >= dd->num_send_contexts) { + ret = -EINVAL; + goto bail; + } + /* can only use kernel contexts */ + if (dd->send_contexts[dp->sw_index].type != SC_KERNEL) { + ret = -EINVAL; + goto bail; + } + /* must be allocated */ + sc = dd->send_contexts[dp->sw_index].sc; + if (!sc) { + ret = -EINVAL; + goto bail; + } + /* must be enabled */ + if (!(sc->flags & SCF_ENABLED)) { + ret = -EINVAL; + goto bail; + } + + /* allocate a buffer and copy the data in */ + tmpbuf = vmalloc(dp->len); + if (!tmpbuf) { + ret = -ENOMEM; + goto bail; + } + + if (copy_from_user(tmpbuf, + (const void __user *) (unsigned long) dp->data, + dp->len)) { + ret = -EFAULT; + goto bail; + } + + /* + * pkt_len is how much data we have to write, includes header and data. + * total_len is length of the packet in Dwords plus the PBC should not + * include the CRC. + */ + pkt_len = dp->len >> 2; + total_len = pkt_len + 2; /* PBC + packet */ + + /* if 0, fill in a default */ + if (dp->pbc == 0) { + struct hfi1_pportdata *ppd = dd->pport; + + hfi1_cdbg(PKT, "Generating PBC"); + dp->pbc = create_pbc(ppd, 0, 0, 0, total_len); + } else { + hfi1_cdbg(PKT, "Using passed in PBC"); + } + + hfi1_cdbg(PKT, "Egress PBC content is 0x%llx", dp->pbc); + + /* + * The caller wants to wait until the packet is sent and to + * check for errors. The best we can do is wait until + * the buffer credits are returned and check if any packet + * error has occurred. If there are any late errors, this + * could miss it. If there are other senders who generate + * an error, this may find it. However, in general, it + * should catch most. + */ + if (dp->flags & F_DIAGPKT_WAIT) { + /* always force a credit return */ + dp->pbc |= PBC_CREDIT_RETURN; + /* turn on credit return interrupts */ + sc_add_credit_return_intr(sc); + wait = kmalloc(sizeof(*wait), GFP_KERNEL); + if (!wait) { + ret = -ENOMEM; + goto bail; + } + init_completion(&wait->credits_returned); + atomic_set(&wait->count, 2); + wait->code = PRC_OK; + + credit_cb = diagpkt_complete; + credit_arg = wait; + } + + pbuf = sc_buffer_alloc(sc, total_len, credit_cb, credit_arg); + if (!pbuf) { + /* + * No send buffer means no credit callback. Undo + * the wait set-up that was done above. We free wait + * because the callback will never be called. + */ + if (dp->flags & F_DIAGPKT_WAIT) { + sc_del_credit_return_intr(sc); + kfree(wait); + wait = NULL; + } + ret = -ENOSPC; + goto bail; + } + + pio_copy(dd, pbuf, dp->pbc, tmpbuf, pkt_len); + /* no flush needed as the HW knows the packet size */ + + ret = sizeof(*dp); + + if (dp->flags & F_DIAGPKT_WAIT) { + /* wait for credit return */ + ret = wait_for_completion_interruptible( + &wait->credits_returned); + /* + * If the wait returns an error, the wait was interrupted, + * e.g. with a ^C in the user program. The callback is + * still pending. This is OK as the wait structure is + * kmalloc'ed and the structure will free itself when + * all users are done with it. + * + * A context disable occurs on a send context restart, so + * include that in the list of errors below to check for. + * NOTE: PRC_FILL_ERR is at best informational and cannot + * be depended on. + */ + if (!ret && (((wait->code & PRC_STATUS_ERR) + || (wait->code & PRC_FILL_ERR) + || (wait->code & PRC_SC_DISABLE)))) + ret = -EIO; + + put_diagpkt_wait(wait); /* finished with the structure */ + sc_del_credit_return_intr(sc); + } + +bail: + vfree(tmpbuf); + return ret; +} + +static ssize_t diagpkt_write(struct file *fp, const char __user *data, + size_t count, loff_t *off) +{ + struct hfi1_devdata *dd; + struct send_context *sc; + u8 vl; + + struct diag_pkt dp; + + if (count != sizeof(dp)) + return -EINVAL; + + if (copy_from_user(&dp, data, sizeof(dp))) + return -EFAULT; + + /* + * The Send Context is derived from the PbcVL value + * if PBC is populated + */ + if (dp.pbc) { + dd = hfi1_lookup(dp.unit); + if (dd == NULL) + return -ENODEV; + vl = (dp.pbc >> PBC_VL_SHIFT) & PBC_VL_MASK; + sc = dd->vld[vl].sc; + if (sc) { + dp.sw_index = sc->sw_index; + hfi1_cdbg( + PKT, + "Packet sent over VL %d via Send Context %u(%u)", + vl, sc->sw_index, sc->hw_context); + } + } + + return diagpkt_send(&dp); +} + +static int hfi1_snoop_add(struct hfi1_devdata *dd, const char *name) +{ + int ret = 0; + + dd->hfi1_snoop.mode_flag = 0; + spin_lock_init(&dd->hfi1_snoop.snoop_lock); + INIT_LIST_HEAD(&dd->hfi1_snoop.queue); + init_waitqueue_head(&dd->hfi1_snoop.waitq); + + ret = hfi1_cdev_init(HFI1_SNOOP_CAPTURE_BASE + dd->unit, name, + &snoop_file_ops, + &dd->hfi1_snoop.cdev, &dd->hfi1_snoop.class_dev); + + if (ret) { + dd_dev_err(dd, "Couldn't create %s device: %d", name, ret); + hfi1_cdev_cleanup(&dd->hfi1_snoop.cdev, + &dd->hfi1_snoop.class_dev); + } + + return ret; +} + +static struct hfi1_devdata *hfi1_dd_from_sc_inode(struct inode *in) +{ + int unit = iminor(in) - HFI1_SNOOP_CAPTURE_BASE; + struct hfi1_devdata *dd = NULL; + + dd = hfi1_lookup(unit); + return dd; + +} + +/* clear or restore send context integrity checks */ +static void adjust_integrity_checks(struct hfi1_devdata *dd) +{ + struct send_context *sc; + unsigned long sc_flags; + int i; + + spin_lock_irqsave(&dd->sc_lock, sc_flags); + for (i = 0; i < dd->num_send_contexts; i++) { + int enable; + + sc = dd->send_contexts[i].sc; + + if (!sc) + continue; /* not allocated */ + + enable = likely(!HFI1_CAP_IS_KSET(NO_INTEGRITY)) && + dd->hfi1_snoop.mode_flag != HFI1_PORT_SNOOP_MODE; + + set_pio_integrity(sc); + + if (enable) /* take HFI_CAP_* flags into account */ + hfi1_init_ctxt(sc); + } + spin_unlock_irqrestore(&dd->sc_lock, sc_flags); +} + +static int hfi1_snoop_open(struct inode *in, struct file *fp) +{ + int ret; + int mode_flag = 0; + unsigned long flags = 0; + struct hfi1_devdata *dd; + struct list_head *queue; + + mutex_lock(&hfi1_mutex); + + dd = hfi1_dd_from_sc_inode(in); + if (dd == NULL) { + ret = -ENODEV; + goto bail; + } + + /* + * File mode determines snoop or capture. Some existing user + * applications expect the capture device to be able to be opened RDWR + * because they expect a dedicated capture device. For this reason we + * support a module param to force capture mode even if the file open + * mode matches snoop. + */ + if ((fp->f_flags & O_ACCMODE) == O_RDONLY) { + snoop_dbg("Capture Enabled"); + mode_flag = HFI1_PORT_CAPTURE_MODE; + } else if ((fp->f_flags & O_ACCMODE) == O_RDWR) { + snoop_dbg("Snoop Enabled"); + mode_flag = HFI1_PORT_SNOOP_MODE; + } else { + snoop_dbg("Invalid"); + ret = -EINVAL; + goto bail; + } + queue = &dd->hfi1_snoop.queue; + + /* + * We are not supporting snoop and capture at the same time. + */ + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + if (dd->hfi1_snoop.mode_flag) { + ret = -EBUSY; + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + goto bail; + } + + dd->hfi1_snoop.mode_flag = mode_flag; + drain_snoop_list(queue); + + dd->hfi1_snoop.filter_callback = NULL; + dd->hfi1_snoop.filter_value = NULL; + + /* + * Send side packet integrity checks are not helpful when snooping so + * disable and re-enable when we stop snooping. + */ + if (mode_flag == HFI1_PORT_SNOOP_MODE) { + /* clear after snoop mode is on */ + adjust_integrity_checks(dd); /* clear */ + + /* + * We also do not want to be doing the DLID LMC check for + * ingressed packets. + */ + dd->hfi1_snoop.dcc_cfg = read_csr(dd, DCC_CFG_PORT_CONFIG1); + write_csr(dd, DCC_CFG_PORT_CONFIG1, + (dd->hfi1_snoop.dcc_cfg >> 32) << 32); + } + + /* + * As soon as we set these function pointers the recv and send handlers + * are active. This is a race condition so we must make sure to drain + * the queue and init filter values above. Technically we should add + * locking here but all that will happen is on recv a packet will get + * allocated and get stuck on the snoop_lock before getting added to the + * queue. Same goes for send. + */ + dd->rhf_rcv_function_map = snoop_rhf_rcv_functions; + dd->process_pio_send = snoop_send_pio_handler; + dd->process_dma_send = snoop_send_pio_handler; + dd->pio_inline_send = snoop_inline_pio_send; + + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + ret = 0; + +bail: + mutex_unlock(&hfi1_mutex); + + return ret; +} + +static int hfi1_snoop_release(struct inode *in, struct file *fp) +{ + unsigned long flags = 0; + struct hfi1_devdata *dd; + int mode_flag; + + dd = hfi1_dd_from_sc_inode(in); + if (dd == NULL) + return -ENODEV; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + + /* clear the snoop mode before re-adjusting send context CSRs */ + mode_flag = dd->hfi1_snoop.mode_flag; + dd->hfi1_snoop.mode_flag = 0; + + /* + * Drain the queue and clear the filters we are done with it. Don't + * forget to restore the packet integrity checks + */ + drain_snoop_list(&dd->hfi1_snoop.queue); + if (mode_flag == HFI1_PORT_SNOOP_MODE) { + /* restore after snoop mode is clear */ + adjust_integrity_checks(dd); /* restore */ + + /* + * Also should probably reset the DCC_CONFIG1 register for DLID + * checking on incoming packets again. Use the value saved when + * opening the snoop device. + */ + write_csr(dd, DCC_CFG_PORT_CONFIG1, dd->hfi1_snoop.dcc_cfg); + } + + dd->hfi1_snoop.filter_callback = NULL; + kfree(dd->hfi1_snoop.filter_value); + dd->hfi1_snoop.filter_value = NULL; + + /* + * User is done snooping and capturing, return control to the normal + * handler. Re-enable SDMA handling. + */ + dd->rhf_rcv_function_map = dd->normal_rhf_rcv_functions; + dd->process_pio_send = hfi1_verbs_send_pio; + dd->process_dma_send = hfi1_verbs_send_dma; + dd->pio_inline_send = pio_copy; + + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + + snoop_dbg("snoop/capture device released"); + + return 0; +} + +static unsigned int hfi1_snoop_poll(struct file *fp, + struct poll_table_struct *wait) +{ + int ret = 0; + unsigned long flags = 0; + + struct hfi1_devdata *dd; + + dd = hfi1_dd_from_sc_inode(fp->f_inode); + if (dd == NULL) + return -ENODEV; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + + poll_wait(fp, &dd->hfi1_snoop.waitq, wait); + if (!list_empty(&dd->hfi1_snoop.queue)) + ret |= POLLIN | POLLRDNORM; + + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + return ret; + +} + +static ssize_t hfi1_snoop_write(struct file *fp, const char __user *data, + size_t count, loff_t *off) +{ + struct diag_pkt dpkt; + struct hfi1_devdata *dd; + size_t ret; + u8 byte_two, sl, sc5, sc4, vl, byte_one; + struct send_context *sc; + u32 len; + u64 pbc; + struct hfi1_ibport *ibp; + struct hfi1_pportdata *ppd; + + dd = hfi1_dd_from_sc_inode(fp->f_inode); + if (dd == NULL) + return -ENODEV; + + ppd = dd->pport; + snoop_dbg("received %lu bytes from user", count); + + memset(&dpkt, 0, sizeof(struct diag_pkt)); + dpkt.version = _DIAG_PKT_VERS; + dpkt.unit = dd->unit; + dpkt.port = 1; + + if (likely(!(snoop_flags & SNOOP_USE_METADATA))) { + /* + * We need to generate the PBC and not let diagpkt_send do it, + * to do this we need the VL and the length in dwords. + * The VL can be determined by using the SL and looking up the + * SC. Then the SC can be converted into VL. The exception to + * this is those packets which are from an SMI queue pair. + * Since we can't detect anything about the QP here we have to + * rely on the SC. If its 0xF then we assume its SMI and + * do not look at the SL. + */ + if (copy_from_user(&byte_one, data, 1)) + return -EINVAL; + + if (copy_from_user(&byte_two, data+1, 1)) + return -EINVAL; + + sc4 = (byte_one >> 4) & 0xf; + if (sc4 == 0xF) { + snoop_dbg("Detected VL15 packet ignoring SL in packet"); + vl = sc4; + } else { + sl = (byte_two >> 4) & 0xf; + ibp = to_iport(&dd->verbs_dev.ibdev, 1); + sc5 = ibp->sl_to_sc[sl]; + vl = sc_to_vlt(dd, sc5); + if (vl != sc4) { + snoop_dbg("VL %d does not match SC %d of packet", + vl, sc4); + return -EINVAL; + } + } + + sc = dd->vld[vl].sc; /* Look up the context based on VL */ + if (sc) { + dpkt.sw_index = sc->sw_index; + snoop_dbg("Sending on context %u(%u)", sc->sw_index, + sc->hw_context); + } else { + snoop_dbg("Could not find context for vl %d", vl); + return -EINVAL; + } + + len = (count >> 2) + 2; /* Add in PBC */ + pbc = create_pbc(ppd, 0, 0, vl, len); + } else { + if (copy_from_user(&pbc, data, sizeof(pbc))) + return -EINVAL; + vl = (pbc >> PBC_VL_SHIFT) & PBC_VL_MASK; + sc = dd->vld[vl].sc; /* Look up the context based on VL */ + if (sc) { + dpkt.sw_index = sc->sw_index; + } else { + snoop_dbg("Could not find context for vl %d", vl); + return -EINVAL; + } + data += sizeof(pbc); + count -= sizeof(pbc); + } + dpkt.len = count; + dpkt.data = (unsigned long)data; + + snoop_dbg("PBC: vl=0x%llx Length=0x%llx", + (pbc >> 12) & 0xf, + (pbc & 0xfff)); + + dpkt.pbc = pbc; + ret = diagpkt_send(&dpkt); + /* + * diagpkt_send only returns number of bytes in the diagpkt so patch + * that up here before returning. + */ + if (ret == sizeof(dpkt)) + return count; + + return ret; +} + +static ssize_t hfi1_snoop_read(struct file *fp, char __user *data, + size_t pkt_len, loff_t *off) +{ + ssize_t ret = 0; + unsigned long flags = 0; + struct snoop_packet *packet = NULL; + struct hfi1_devdata *dd; + + dd = hfi1_dd_from_sc_inode(fp->f_inode); + if (dd == NULL) + return -ENODEV; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + + while (list_empty(&dd->hfi1_snoop.queue)) { + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + + if (wait_event_interruptible( + dd->hfi1_snoop.waitq, + !list_empty(&dd->hfi1_snoop.queue))) + return -EINTR; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + } + + if (!list_empty(&dd->hfi1_snoop.queue)) { + packet = list_entry(dd->hfi1_snoop.queue.next, + struct snoop_packet, list); + list_del(&packet->list); + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + if (pkt_len >= packet->total_len) { + if (copy_to_user(data, packet->data, + packet->total_len)) + ret = -EFAULT; + else + ret = packet->total_len; + } else + ret = -EINVAL; + + kfree(packet); + } else + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + + return ret; +} + +static long hfi1_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) +{ + struct hfi1_devdata *dd; + void *filter_value = NULL; + long ret = 0; + int value = 0; + u8 physState = 0; + u8 linkState = 0; + u16 devState = 0; + unsigned long flags = 0; + unsigned long *argp = NULL; + struct hfi1_packet_filter_command filter_cmd = {0}; + int mode_flag = 0; + struct hfi1_pportdata *ppd = NULL; + unsigned int index; + struct hfi1_link_info link_info; + + dd = hfi1_dd_from_sc_inode(fp->f_inode); + if (dd == NULL) + return -ENODEV; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + + mode_flag = dd->hfi1_snoop.mode_flag; + + if (((_IOC_DIR(cmd) & _IOC_READ) + && !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd))) + || ((_IOC_DIR(cmd) & _IOC_WRITE) + && !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)))) { + ret = -EFAULT; + } else if (!capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + } else if ((mode_flag & HFI1_PORT_CAPTURE_MODE) && + (cmd != HFI1_SNOOP_IOCCLEARQUEUE) && + (cmd != HFI1_SNOOP_IOCCLEARFILTER) && + (cmd != HFI1_SNOOP_IOCSETFILTER)) { + /* Capture devices are allowed only 3 operations + * 1.Clear capture queue + * 2.Clear capture filter + * 3.Set capture filter + * Other are invalid. + */ + ret = -EINVAL; + } else { + switch (cmd) { + case HFI1_SNOOP_IOCSETLINKSTATE: + snoop_dbg("HFI1_SNOOP_IOCSETLINKSTATE is not valid"); + ret = -EINVAL; + break; + + case HFI1_SNOOP_IOCSETLINKSTATE_EXTRA: + memset(&link_info, 0, sizeof(link_info)); + + ret = copy_from_user(&link_info, + (struct hfi1_link_info __user *)arg, + sizeof(link_info)); + if (ret) + break; + + value = link_info.port_state; + index = link_info.port_number; + if (index > dd->num_pports - 1) { + ret = -EINVAL; + break; + } + + ppd = &dd->pport[index]; + if (!ppd) { + ret = -EINVAL; + break; + } + + /* What we want to transition to */ + physState = (value >> 4) & 0xF; + linkState = value & 0xF; + snoop_dbg("Setting link state 0x%x", value); + + switch (linkState) { + case IB_PORT_NOP: + if (physState == 0) + break; + /* fall through */ + case IB_PORT_DOWN: + switch (physState) { + case 0: + devState = HLS_DN_DOWNDEF; + break; + case 2: + devState = HLS_DN_POLL; + break; + case 3: + devState = HLS_DN_DISABLE; + break; + default: + ret = -EINVAL; + goto done; + } + ret = set_link_state(ppd, devState); + break; + case IB_PORT_ARMED: + ret = set_link_state(ppd, HLS_UP_ARMED); + if (!ret) + send_idle_sma(dd, SMA_IDLE_ARM); + break; + case IB_PORT_ACTIVE: + ret = set_link_state(ppd, HLS_UP_ACTIVE); + if (!ret) + send_idle_sma(dd, SMA_IDLE_ACTIVE); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + break; + /* fall through */ + case HFI1_SNOOP_IOCGETLINKSTATE: + case HFI1_SNOOP_IOCGETLINKSTATE_EXTRA: + if (cmd == HFI1_SNOOP_IOCGETLINKSTATE_EXTRA) { + memset(&link_info, 0, sizeof(link_info)); + ret = copy_from_user(&link_info, + (struct hfi1_link_info __user *)arg, + sizeof(link_info)); + index = link_info.port_number; + } else { + ret = __get_user(index, (int __user *) arg); + if (ret != 0) + break; + } + + if (index > dd->num_pports - 1) { + ret = -EINVAL; + break; + } + + ppd = &dd->pport[index]; + if (!ppd) { + ret = -EINVAL; + break; + } + value = hfi1_ibphys_portstate(ppd); + value <<= 4; + value |= driver_lstate(ppd); + + snoop_dbg("Link port | Link State: %d", value); + + if ((cmd == HFI1_SNOOP_IOCGETLINKSTATE_EXTRA) || + (cmd == HFI1_SNOOP_IOCSETLINKSTATE_EXTRA)) { + link_info.port_state = value; + link_info.node_guid = cpu_to_be64(ppd->guid); + link_info.link_speed_active = + ppd->link_speed_active; + link_info.link_width_active = + ppd->link_width_active; + ret = copy_to_user( + (struct hfi1_link_info __user *)arg, + &link_info, sizeof(link_info)); + } else { + ret = __put_user(value, (int __user *)arg); + } + break; + + case HFI1_SNOOP_IOCCLEARQUEUE: + snoop_dbg("Clearing snoop queue"); + drain_snoop_list(&dd->hfi1_snoop.queue); + break; + + case HFI1_SNOOP_IOCCLEARFILTER: + snoop_dbg("Clearing filter"); + if (dd->hfi1_snoop.filter_callback) { + /* Drain packets first */ + drain_snoop_list(&dd->hfi1_snoop.queue); + dd->hfi1_snoop.filter_callback = NULL; + } + kfree(dd->hfi1_snoop.filter_value); + dd->hfi1_snoop.filter_value = NULL; + break; + + case HFI1_SNOOP_IOCSETFILTER: + snoop_dbg("Setting filter"); + /* just copy command structure */ + argp = (unsigned long *)arg; + ret = copy_from_user(&filter_cmd, (void __user *)argp, + sizeof(filter_cmd)); + if (ret < 0) { + pr_alert("Error copying filter command\n"); + break; + } + if (filter_cmd.opcode >= HFI1_MAX_FILTERS) { + pr_alert("Invalid opcode in request\n"); + ret = -EINVAL; + break; + } + + snoop_dbg("Opcode %d Len %d Ptr %p", + filter_cmd.opcode, filter_cmd.length, + filter_cmd.value_ptr); + + filter_value = kzalloc( + filter_cmd.length * sizeof(u8), + GFP_KERNEL); + if (!filter_value) { + pr_alert("Not enough memory\n"); + ret = -ENOMEM; + break; + } + /* copy remaining data from userspace */ + ret = copy_from_user((u8 *)filter_value, + (void __user *)filter_cmd.value_ptr, + filter_cmd.length); + if (ret < 0) { + kfree(filter_value); + pr_alert("Error copying filter data\n"); + break; + } + /* Drain packets first */ + drain_snoop_list(&dd->hfi1_snoop.queue); + dd->hfi1_snoop.filter_callback = + hfi1_filters[filter_cmd.opcode].filter; + /* just in case we see back to back sets */ + kfree(dd->hfi1_snoop.filter_value); + dd->hfi1_snoop.filter_value = filter_value; + + break; + case HFI1_SNOOP_IOCGETVERSION: + value = SNOOP_CAPTURE_VERSION; + snoop_dbg("Getting version: %d", value); + ret = __put_user(value, (int __user *)arg); + break; + case HFI1_SNOOP_IOCSET_OPTS: + snoop_flags = 0; + ret = __get_user(value, (int __user *) arg); + if (ret != 0) + break; + + snoop_dbg("Setting snoop option %d", value); + if (value & SNOOP_DROP_SEND) + snoop_flags |= SNOOP_DROP_SEND; + if (value & SNOOP_USE_METADATA) + snoop_flags |= SNOOP_USE_METADATA; + break; + default: + ret = -ENOTTY; + break; + } + } +done: + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + return ret; +} + +static void snoop_list_add_tail(struct snoop_packet *packet, + struct hfi1_devdata *dd) +{ + unsigned long flags = 0; + + spin_lock_irqsave(&dd->hfi1_snoop.snoop_lock, flags); + if (likely((dd->hfi1_snoop.mode_flag & HFI1_PORT_SNOOP_MODE) || + (dd->hfi1_snoop.mode_flag & HFI1_PORT_CAPTURE_MODE))) { + list_add_tail(&packet->list, &dd->hfi1_snoop.queue); + snoop_dbg("Added packet to list"); + } + + /* + * Technically we can could have closed the snoop device while waiting + * on the above lock and it is gone now. The snoop mode_flag will + * prevent us from adding the packet to the queue though. + */ + + spin_unlock_irqrestore(&dd->hfi1_snoop.snoop_lock, flags); + wake_up_interruptible(&dd->hfi1_snoop.waitq); +} + +static inline int hfi1_filter_check(void *val, const char *msg) +{ + if (!val) { + snoop_dbg("Error invalid %s value for filter", msg); + return HFI1_FILTER_ERR; + } + return 0; +} + +static int hfi1_filter_lid(void *ibhdr, void *packet_data, void *value) +{ + struct hfi1_ib_header *hdr; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + hdr = (struct hfi1_ib_header *)ibhdr; + + if (*((u16 *)value) == be16_to_cpu(hdr->lrh[3])) /* matches slid */ + return HFI1_FILTER_HIT; /* matched */ + + return HFI1_FILTER_MISS; /* Not matched */ +} + +static int hfi1_filter_dlid(void *ibhdr, void *packet_data, void *value) +{ + struct hfi1_ib_header *hdr; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + hdr = (struct hfi1_ib_header *)ibhdr; + + if (*((u16 *)value) == be16_to_cpu(hdr->lrh[1])) + return HFI1_FILTER_HIT; + + return HFI1_FILTER_MISS; +} + +/* Not valid for outgoing packets, send handler passes null for data*/ +static int hfi1_filter_mad_mgmt_class(void *ibhdr, void *packet_data, + void *value) +{ + struct hfi1_ib_header *hdr; + struct hfi1_other_headers *ohdr = NULL; + struct ib_smp *smp = NULL; + u32 qpn = 0; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(packet_data, "packet_data"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + hdr = (struct hfi1_ib_header *)ibhdr; + + /* Check for GRH */ + if ((be16_to_cpu(hdr->lrh[0]) & 3) == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; /* LRH + BTH + DETH */ + else + ohdr = &hdr->u.l.oth; /* LRH + GRH + BTH + DETH */ + + qpn = be32_to_cpu(ohdr->bth[1]) & 0x00FFFFFF; + if (qpn <= 1) { + smp = (struct ib_smp *)packet_data; + if (*((u8 *)value) == smp->mgmt_class) + return HFI1_FILTER_HIT; + else + return HFI1_FILTER_MISS; + } + return HFI1_FILTER_ERR; +} + +static int hfi1_filter_qp_number(void *ibhdr, void *packet_data, void *value) +{ + + struct hfi1_ib_header *hdr; + struct hfi1_other_headers *ohdr = NULL; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + hdr = (struct hfi1_ib_header *)ibhdr; + + /* Check for GRH */ + if ((be16_to_cpu(hdr->lrh[0]) & 3) == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; /* LRH + BTH + DETH */ + else + ohdr = &hdr->u.l.oth; /* LRH + GRH + BTH + DETH */ + if (*((u32 *)value) == (be32_to_cpu(ohdr->bth[1]) & 0x00FFFFFF)) + return HFI1_FILTER_HIT; + + return HFI1_FILTER_MISS; +} + +static int hfi1_filter_ibpacket_type(void *ibhdr, void *packet_data, + void *value) +{ + u32 lnh = 0; + u8 opcode = 0; + struct hfi1_ib_header *hdr; + struct hfi1_other_headers *ohdr = NULL; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + hdr = (struct hfi1_ib_header *)ibhdr; + + lnh = (be16_to_cpu(hdr->lrh[0]) & 3); + + if (lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else if (lnh == HFI1_LRH_GRH) + ohdr = &hdr->u.l.oth; + else + return HFI1_FILTER_ERR; + + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + + if (*((u8 *)value) == ((opcode >> 5) & 0x7)) + return HFI1_FILTER_HIT; + + return HFI1_FILTER_MISS; +} + +static int hfi1_filter_ib_service_level(void *ibhdr, void *packet_data, + void *value) +{ + struct hfi1_ib_header *hdr; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + hdr = (struct hfi1_ib_header *)ibhdr; + + if ((*((u8 *)value)) == ((be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF)) + return HFI1_FILTER_HIT; + + return HFI1_FILTER_MISS; +} + +static int hfi1_filter_ib_pkey(void *ibhdr, void *packet_data, void *value) +{ + + u32 lnh = 0; + struct hfi1_ib_header *hdr; + struct hfi1_other_headers *ohdr = NULL; + int ret; + + ret = hfi1_filter_check(ibhdr, "header"); + if (ret) + return ret; + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + hdr = (struct hfi1_ib_header *)ibhdr; + + lnh = (be16_to_cpu(hdr->lrh[0]) & 3); + if (lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else if (lnh == HFI1_LRH_GRH) + ohdr = &hdr->u.l.oth; + else + return HFI1_FILTER_ERR; + + /* P_key is 16-bit entity, however top most bit indicates + * type of membership. 0 for limited and 1 for Full. + * Limited members cannot accept information from other + * Limited members, but communication is allowed between + * every other combination of membership. + * Hence we'll omit comparing top-most bit while filtering + */ + + if ((*(u16 *)value & 0x7FFF) == + ((be32_to_cpu(ohdr->bth[0])) & 0x7FFF)) + return HFI1_FILTER_HIT; + + return HFI1_FILTER_MISS; +} + +/* + * If packet_data is NULL then this is coming from one of the send functions. + * Thus we know if its an ingressed or egressed packet. + */ +static int hfi1_filter_direction(void *ibhdr, void *packet_data, void *value) +{ + u8 user_dir = *(u8 *)value; + int ret; + + ret = hfi1_filter_check(value, "user"); + if (ret) + return ret; + + if (packet_data) { + /* Incoming packet */ + if (user_dir & HFI1_SNOOP_INGRESS) + return HFI1_FILTER_HIT; + } else { + /* Outgoing packet */ + if (user_dir & HFI1_SNOOP_EGRESS) + return HFI1_FILTER_HIT; + } + + return HFI1_FILTER_MISS; +} + +/* + * Allocate a snoop packet. The structure that is stored in the ring buffer, not + * to be confused with an hfi packet type. + */ +static struct snoop_packet *allocate_snoop_packet(u32 hdr_len, + u32 data_len, + u32 md_len) +{ + + struct snoop_packet *packet = NULL; + + packet = kzalloc(sizeof(struct snoop_packet) + hdr_len + data_len + + md_len, + GFP_ATOMIC | __GFP_NOWARN); + if (likely(packet)) + INIT_LIST_HEAD(&packet->list); + + + return packet; +} + +/* + * Instead of having snoop and capture code intermixed with the recv functions, + * both the interrupt handler and hfi1_ib_rcv() we are going to hijack the call + * and land in here for snoop/capture but if not enabled the call will go + * through as before. This gives us a single point to constrain all of the snoop + * snoop recv logic. There is nothing special that needs to happen for bypass + * packets. This routine should not try to look into the packet. It just copied + * it. There is no guarantee for filters when it comes to bypass packets as + * there is no specific support. Bottom line is this routine does now even know + * what a bypass packet is. + */ +int snoop_recv_handler(struct hfi1_packet *packet) +{ + struct hfi1_pportdata *ppd = packet->rcd->ppd; + struct hfi1_ib_header *hdr = packet->hdr; + int header_size = packet->hlen; + void *data = packet->ebuf; + u32 tlen = packet->tlen; + struct snoop_packet *s_packet = NULL; + int ret; + int snoop_mode = 0; + u32 md_len = 0; + struct capture_md md; + + snoop_dbg("PACKET IN: hdr size %d tlen %d data %p", header_size, tlen, + data); + + trace_snoop_capture(ppd->dd, header_size, hdr, tlen - header_size, + data); + + if (!ppd->dd->hfi1_snoop.filter_callback) { + snoop_dbg("filter not set"); + ret = HFI1_FILTER_HIT; + } else { + ret = ppd->dd->hfi1_snoop.filter_callback(hdr, data, + ppd->dd->hfi1_snoop.filter_value); + } + + switch (ret) { + case HFI1_FILTER_ERR: + snoop_dbg("Error in filter call"); + break; + case HFI1_FILTER_MISS: + snoop_dbg("Filter Miss"); + break; + case HFI1_FILTER_HIT: + + if (ppd->dd->hfi1_snoop.mode_flag & HFI1_PORT_SNOOP_MODE) + snoop_mode = 1; + if ((snoop_mode == 0) || + unlikely(snoop_flags & SNOOP_USE_METADATA)) + md_len = sizeof(struct capture_md); + + + s_packet = allocate_snoop_packet(header_size, + tlen - header_size, + md_len); + + if (unlikely(s_packet == NULL)) { + dd_dev_warn_ratelimited(ppd->dd, "Unable to allocate snoop/capture packet\n"); + break; + } + + if (md_len > 0) { + memset(&md, 0, sizeof(struct capture_md)); + md.port = 1; + md.dir = PKT_DIR_INGRESS; + md.u.rhf = packet->rhf; + memcpy(s_packet->data, &md, md_len); + } + + /* We should always have a header */ + if (hdr) { + memcpy(s_packet->data + md_len, hdr, header_size); + } else { + dd_dev_err(ppd->dd, "Unable to copy header to snoop/capture packet\n"); + kfree(s_packet); + break; + } + + /* + * Packets with no data are possible. If there is no data needed + * to take care of the last 4 bytes which are normally included + * with data buffers and are included in tlen. Since we kzalloc + * the buffer we do not need to set any values but if we decide + * not to use kzalloc we should zero them. + */ + if (data) + memcpy(s_packet->data + header_size + md_len, data, + tlen - header_size); + + s_packet->total_len = tlen + md_len; + snoop_list_add_tail(s_packet, ppd->dd); + + /* + * If we are snooping the packet not capturing then throw away + * after adding to the list. + */ + snoop_dbg("Capturing packet"); + if (ppd->dd->hfi1_snoop.mode_flag & HFI1_PORT_SNOOP_MODE) { + snoop_dbg("Throwing packet away"); + /* + * If we are dropping the packet we still may need to + * handle the case where error flags are set, this is + * normally done by the type specific handler but that + * won't be called in this case. + */ + if (unlikely(rhf_err_flags(packet->rhf))) + handle_eflags(packet); + + /* throw the packet on the floor */ + return RHF_RCV_CONTINUE; + } + break; + default: + break; + } + + /* + * We do not care what type of packet came in here - just pass it off + * to the normal handler. + */ + return ppd->dd->normal_rhf_rcv_functions[rhf_rcv_type(packet->rhf)] + (packet); +} + +/* + * Handle snooping and capturing packets when sdma is being used. + */ +int snoop_send_dma_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc) +{ + pr_alert("Snooping/Capture of Send DMA Packets Is Not Supported!\n"); + snoop_dbg("Unsupported Operation"); + return hfi1_verbs_send_dma(qp, ibhdr, hdrwords, ss, len, plen, dwords, + 0); +} + +/* + * Handle snooping and capturing packets when pio is being used. Does not handle + * bypass packets. The only way to send a bypass packet currently is to use the + * diagpkt interface. When that interface is enable snoop/capture is not. + */ +int snoop_send_pio_handler(struct hfi1_qp *qp, struct ahg_ib_header *ahdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct snoop_packet *s_packet = NULL; + u32 *hdr = (u32 *)&ahdr->ibh; + u32 length = 0; + struct hfi1_sge_state temp_ss; + void *data = NULL; + void *data_start = NULL; + int ret; + int snoop_mode = 0; + int md_len = 0; + struct capture_md md; + u32 vl; + u32 hdr_len = hdrwords << 2; + u32 tlen = HFI1_GET_PKT_LEN(&ahdr->ibh); + + md.u.pbc = 0; + + snoop_dbg("PACKET OUT: hdrword %u len %u plen %u dwords %u tlen %u", + hdrwords, len, plen, dwords, tlen); + if (ppd->dd->hfi1_snoop.mode_flag & HFI1_PORT_SNOOP_MODE) + snoop_mode = 1; + if ((snoop_mode == 0) || + unlikely(snoop_flags & SNOOP_USE_METADATA)) + md_len = sizeof(struct capture_md); + + /* not using ss->total_len as arg 2 b/c that does not count CRC */ + s_packet = allocate_snoop_packet(hdr_len, tlen - hdr_len, md_len); + + if (unlikely(s_packet == NULL)) { + dd_dev_warn_ratelimited(ppd->dd, "Unable to allocate snoop/capture packet\n"); + goto out; + } + + s_packet->total_len = tlen + md_len; + + if (md_len > 0) { + memset(&md, 0, sizeof(struct capture_md)); + md.port = 1; + md.dir = PKT_DIR_EGRESS; + if (likely(pbc == 0)) { + vl = be16_to_cpu(ahdr->ibh.lrh[0]) >> 12; + md.u.pbc = create_pbc(ppd, 0, qp->s_srate, vl, plen); + } else { + md.u.pbc = 0; + } + memcpy(s_packet->data, &md, md_len); + } else { + md.u.pbc = pbc; + } + + /* Copy header */ + if (likely(hdr)) { + memcpy(s_packet->data + md_len, hdr, hdr_len); + } else { + dd_dev_err(ppd->dd, + "Unable to copy header to snoop/capture packet\n"); + kfree(s_packet); + goto out; + } + + if (ss) { + data = s_packet->data + hdr_len + md_len; + data_start = data; + + /* + * Copy SGE State + * The update_sge() function below will not modify the + * individual SGEs in the array. It will make a copy each time + * and operate on that. So we only need to copy this instance + * and it won't impact PIO. + */ + temp_ss = *ss; + length = len; + + snoop_dbg("Need to copy %d bytes", length); + while (length) { + void *addr = temp_ss.sge.vaddr; + u32 slen = temp_ss.sge.length; + + if (slen > length) { + slen = length; + snoop_dbg("slen %d > len %d", slen, length); + } + snoop_dbg("copy %d to %p", slen, addr); + memcpy(data, addr, slen); + update_sge(&temp_ss, slen); + length -= slen; + data += slen; + snoop_dbg("data is now %p bytes left %d", data, length); + } + snoop_dbg("Completed SGE copy"); + } + + /* + * Why do the filter check down here? Because the event tracing has its + * own filtering and we need to have the walked the SGE list. + */ + if (!ppd->dd->hfi1_snoop.filter_callback) { + snoop_dbg("filter not set\n"); + ret = HFI1_FILTER_HIT; + } else { + ret = ppd->dd->hfi1_snoop.filter_callback( + &ahdr->ibh, + NULL, + ppd->dd->hfi1_snoop.filter_value); + } + + switch (ret) { + case HFI1_FILTER_ERR: + snoop_dbg("Error in filter call"); + /* fall through */ + case HFI1_FILTER_MISS: + snoop_dbg("Filter Miss"); + kfree(s_packet); + break; + case HFI1_FILTER_HIT: + snoop_dbg("Capturing packet"); + snoop_list_add_tail(s_packet, ppd->dd); + + if (unlikely((snoop_flags & SNOOP_DROP_SEND) && + (ppd->dd->hfi1_snoop.mode_flag & + HFI1_PORT_SNOOP_MODE))) { + unsigned long flags; + + snoop_dbg("Dropping packet"); + if (qp->s_wqe) { + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_send_complete( + qp, + qp->s_wqe, + IB_WC_SUCCESS); + spin_unlock_irqrestore(&qp->s_lock, flags); + } else if (qp->ibqp.qp_type == IB_QPT_RC) { + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_rc_send_complete(qp, &ahdr->ibh); + spin_unlock_irqrestore(&qp->s_lock, flags); + } + return 0; + } + break; + default: + kfree(s_packet); + break; + } +out: + return hfi1_verbs_send_pio(qp, ahdr, hdrwords, ss, len, plen, dwords, + md.u.pbc); +} + +/* + * Callers of this must pass a hfi1_ib_header type for the from ptr. Currently + * this can be used anywhere, but the intention is for inline ACKs for RC and + * CCA packets. We don't restrict this usage though. + */ +void snoop_inline_pio_send(struct hfi1_devdata *dd, struct pio_buf *pbuf, + u64 pbc, const void *from, size_t count) +{ + int snoop_mode = 0; + int md_len = 0; + struct capture_md md; + struct snoop_packet *s_packet = NULL; + + /* + * count is in dwords so we need to convert to bytes. + * We also need to account for CRC which would be tacked on by hardware. + */ + int packet_len = (count << 2) + 4; + int ret; + + snoop_dbg("ACK OUT: len %d", packet_len); + + if (!dd->hfi1_snoop.filter_callback) { + snoop_dbg("filter not set"); + ret = HFI1_FILTER_HIT; + } else { + ret = dd->hfi1_snoop.filter_callback( + (struct hfi1_ib_header *)from, + NULL, + dd->hfi1_snoop.filter_value); + } + + switch (ret) { + case HFI1_FILTER_ERR: + snoop_dbg("Error in filter call"); + /* fall through */ + case HFI1_FILTER_MISS: + snoop_dbg("Filter Miss"); + break; + case HFI1_FILTER_HIT: + snoop_dbg("Capturing packet"); + if (dd->hfi1_snoop.mode_flag & HFI1_PORT_SNOOP_MODE) + snoop_mode = 1; + if ((snoop_mode == 0) || + unlikely(snoop_flags & SNOOP_USE_METADATA)) + md_len = sizeof(struct capture_md); + + s_packet = allocate_snoop_packet(packet_len, 0, md_len); + + if (unlikely(s_packet == NULL)) { + dd_dev_warn_ratelimited(dd, "Unable to allocate snoop/capture packet\n"); + goto inline_pio_out; + } + + s_packet->total_len = packet_len + md_len; + + /* Fill in the metadata for the packet */ + if (md_len > 0) { + memset(&md, 0, sizeof(struct capture_md)); + md.port = 1; + md.dir = PKT_DIR_EGRESS; + md.u.pbc = pbc; + memcpy(s_packet->data, &md, md_len); + } + + /* Add the packet data which is a single buffer */ + memcpy(s_packet->data + md_len, from, packet_len); + + snoop_list_add_tail(s_packet, dd); + + if (unlikely((snoop_flags & SNOOP_DROP_SEND) && snoop_mode)) { + snoop_dbg("Dropping packet"); + return; + } + break; + default: + break; + } + +inline_pio_out: + pio_copy(dd, pbuf, pbc, from, count); + +} diff --git a/drivers/staging/rdma/hfi1/dma.c b/drivers/staging/rdma/hfi1/dma.c new file mode 100644 index 0000000000000..e03bd735173cc --- /dev/null +++ b/drivers/staging/rdma/hfi1/dma.c @@ -0,0 +1,186 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include + +#include "verbs.h" + +#define BAD_DMA_ADDRESS ((u64) 0) + +/* + * The following functions implement driver specific replacements + * for the ib_dma_*() functions. + * + * These functions return kernel virtual addresses instead of + * device bus addresses since the driver uses the CPU to copy + * data instead of using hardware DMA. + */ + +static int hfi1_mapping_error(struct ib_device *dev, u64 dma_addr) +{ + return dma_addr == BAD_DMA_ADDRESS; +} + +static u64 hfi1_dma_map_single(struct ib_device *dev, void *cpu_addr, + size_t size, enum dma_data_direction direction) +{ + if (WARN_ON(!valid_dma_direction(direction))) + return BAD_DMA_ADDRESS; + + return (u64) cpu_addr; +} + +static void hfi1_dma_unmap_single(struct ib_device *dev, u64 addr, size_t size, + enum dma_data_direction direction) +{ + /* This is a stub, nothing to be done here */ +} + +static u64 hfi1_dma_map_page(struct ib_device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction direction) +{ + u64 addr; + + if (WARN_ON(!valid_dma_direction(direction))) + return BAD_DMA_ADDRESS; + + if (offset + size > PAGE_SIZE) + return BAD_DMA_ADDRESS; + + addr = (u64) page_address(page); + if (addr) + addr += offset; + + return addr; +} + +static void hfi1_dma_unmap_page(struct ib_device *dev, u64 addr, size_t size, + enum dma_data_direction direction) +{ + /* This is a stub, nothing to be done here */ +} + +static int hfi1_map_sg(struct ib_device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction direction) +{ + struct scatterlist *sg; + u64 addr; + int i; + int ret = nents; + + if (WARN_ON(!valid_dma_direction(direction))) + return BAD_DMA_ADDRESS; + + for_each_sg(sgl, sg, nents, i) { + addr = (u64) page_address(sg_page(sg)); + if (!addr) { + ret = 0; + break; + } + sg->dma_address = addr + sg->offset; +#ifdef CONFIG_NEED_SG_DMA_LENGTH + sg->dma_length = sg->length; +#endif + } + return ret; +} + +static void hfi1_unmap_sg(struct ib_device *dev, + struct scatterlist *sg, int nents, + enum dma_data_direction direction) +{ + /* This is a stub, nothing to be done here */ +} + +static void hfi1_sync_single_for_cpu(struct ib_device *dev, u64 addr, + size_t size, enum dma_data_direction dir) +{ +} + +static void hfi1_sync_single_for_device(struct ib_device *dev, u64 addr, + size_t size, + enum dma_data_direction dir) +{ +} + +static void *hfi1_dma_alloc_coherent(struct ib_device *dev, size_t size, + u64 *dma_handle, gfp_t flag) +{ + struct page *p; + void *addr = NULL; + + p = alloc_pages(flag, get_order(size)); + if (p) + addr = page_address(p); + if (dma_handle) + *dma_handle = (u64) addr; + return addr; +} + +static void hfi1_dma_free_coherent(struct ib_device *dev, size_t size, + void *cpu_addr, u64 dma_handle) +{ + free_pages((unsigned long) cpu_addr, get_order(size)); +} + +struct ib_dma_mapping_ops hfi1_dma_mapping_ops = { + .mapping_error = hfi1_mapping_error, + .map_single = hfi1_dma_map_single, + .unmap_single = hfi1_dma_unmap_single, + .map_page = hfi1_dma_map_page, + .unmap_page = hfi1_dma_unmap_page, + .map_sg = hfi1_map_sg, + .unmap_sg = hfi1_unmap_sg, + .sync_single_for_cpu = hfi1_sync_single_for_cpu, + .sync_single_for_device = hfi1_sync_single_for_device, + .alloc_coherent = hfi1_dma_alloc_coherent, + .free_coherent = hfi1_dma_free_coherent +}; diff --git a/drivers/staging/rdma/hfi1/driver.c b/drivers/staging/rdma/hfi1/driver.c new file mode 100644 index 0000000000000..c0a59001e5cdf --- /dev/null +++ b/drivers/staging/rdma/hfi1/driver.c @@ -0,0 +1,1241 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "trace.h" +#include "qp.h" +#include "sdma.h" + +#undef pr_fmt +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +/* + * The size has to be longer than this string, so we can append + * board/chip information to it in the initialization code. + */ +const char ib_hfi1_version[] = HFI1_DRIVER_VERSION "\n"; + +DEFINE_SPINLOCK(hfi1_devs_lock); +LIST_HEAD(hfi1_dev_list); +DEFINE_MUTEX(hfi1_mutex); /* general driver use */ + +unsigned int hfi1_max_mtu = HFI1_DEFAULT_MAX_MTU; +module_param_named(max_mtu, hfi1_max_mtu, uint, S_IRUGO); +MODULE_PARM_DESC(max_mtu, "Set max MTU bytes, default is 8192"); + +unsigned int hfi1_cu = 1; +module_param_named(cu, hfi1_cu, uint, S_IRUGO); +MODULE_PARM_DESC(cu, "Credit return units"); + +unsigned long hfi1_cap_mask = HFI1_CAP_MASK_DEFAULT; +static int hfi1_caps_set(const char *, const struct kernel_param *); +static int hfi1_caps_get(char *, const struct kernel_param *); +static const struct kernel_param_ops cap_ops = { + .set = hfi1_caps_set, + .get = hfi1_caps_get +}; +module_param_cb(cap_mask, &cap_ops, &hfi1_cap_mask, S_IWUSR | S_IRUGO); +MODULE_PARM_DESC(cap_mask, "Bit mask of enabled/disabled HW features"); + +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("Intel Omni-Path Architecture driver"); +MODULE_VERSION(HFI1_DRIVER_VERSION); + +/* + * MAX_PKT_RCV is the max # if packets processed per receive interrupt. + */ +#define MAX_PKT_RECV 64 +#define EGR_HEAD_UPDATE_THRESHOLD 16 + +struct hfi1_ib_stats hfi1_stats; + +static int hfi1_caps_set(const char *val, const struct kernel_param *kp) +{ + int ret = 0; + unsigned long *cap_mask_ptr = (unsigned long *)kp->arg, + cap_mask = *cap_mask_ptr, value, diff, + write_mask = ((HFI1_CAP_WRITABLE_MASK << HFI1_CAP_USER_SHIFT) | + HFI1_CAP_WRITABLE_MASK); + + ret = kstrtoul(val, 0, &value); + if (ret) { + pr_warn("Invalid module parameter value for 'cap_mask'\n"); + goto done; + } + /* Get the changed bits (except the locked bit) */ + diff = value ^ (cap_mask & ~HFI1_CAP_LOCKED_SMASK); + + /* Remove any bits that are not allowed to change after driver load */ + if (HFI1_CAP_LOCKED() && (diff & ~write_mask)) { + pr_warn("Ignoring non-writable capability bits %#lx\n", + diff & ~write_mask); + diff &= write_mask; + } + + /* Mask off any reserved bits */ + diff &= ~HFI1_CAP_RESERVED_MASK; + /* Clear any previously set and changing bits */ + cap_mask &= ~diff; + /* Update the bits with the new capability */ + cap_mask |= (value & diff); + /* Check for any kernel/user restrictions */ + diff = (cap_mask & (HFI1_CAP_MUST_HAVE_KERN << HFI1_CAP_USER_SHIFT)) ^ + ((cap_mask & HFI1_CAP_MUST_HAVE_KERN) << HFI1_CAP_USER_SHIFT); + cap_mask &= ~diff; + /* Set the bitmask to the final set */ + *cap_mask_ptr = cap_mask; +done: + return ret; +} + +static int hfi1_caps_get(char *buffer, const struct kernel_param *kp) +{ + unsigned long cap_mask = *(unsigned long *)kp->arg; + + cap_mask &= ~HFI1_CAP_LOCKED_SMASK; + cap_mask |= ((cap_mask & HFI1_CAP_K2U) << HFI1_CAP_USER_SHIFT); + + return scnprintf(buffer, PAGE_SIZE, "0x%lx", cap_mask); +} + +const char *get_unit_name(int unit) +{ + static char iname[16]; + + snprintf(iname, sizeof(iname), DRIVER_NAME"_%u", unit); + return iname; +} + +/* + * Return count of units with at least one port ACTIVE. + */ +int hfi1_count_active_units(void) +{ + struct hfi1_devdata *dd; + struct hfi1_pportdata *ppd; + unsigned long flags; + int pidx, nunits_active = 0; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + list_for_each_entry(dd, &hfi1_dev_list, list) { + if (!(dd->flags & HFI1_PRESENT) || !dd->kregbase) + continue; + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (ppd->lid && ppd->linkup) { + nunits_active++; + break; + } + } + } + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + return nunits_active; +} + +/* + * Return count of all units, optionally return in arguments + * the number of usable (present) units, and the number of + * ports that are up. + */ +int hfi1_count_units(int *npresentp, int *nupp) +{ + int nunits = 0, npresent = 0, nup = 0; + struct hfi1_devdata *dd; + unsigned long flags; + int pidx; + struct hfi1_pportdata *ppd; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + + list_for_each_entry(dd, &hfi1_dev_list, list) { + nunits++; + if ((dd->flags & HFI1_PRESENT) && dd->kregbase) + npresent++; + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (ppd->lid && ppd->linkup) + nup++; + } + } + + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + + if (npresentp) + *npresentp = npresent; + if (nupp) + *nupp = nup; + + return nunits; +} + +/* + * Get address of eager buffer from it's index (allocated in chunks, not + * contiguous). + */ +static inline void *get_egrbuf(const struct hfi1_ctxtdata *rcd, u64 rhf, + u8 *update) +{ + u32 idx = rhf_egr_index(rhf), offset = rhf_egr_buf_offset(rhf); + + *update |= !(idx & (rcd->egrbufs.threshold - 1)) && !offset; + return (void *)(((u64)(rcd->egrbufs.rcvtids[idx].addr)) + + (offset * RCV_BUF_BLOCK_SIZE)); +} + +/* + * Validate and encode the a given RcvArray Buffer size. + * The function will check whether the given size falls within + * allowed size ranges for the respective type and, optionally, + * return the proper encoding. + */ +inline int hfi1_rcvbuf_validate(u32 size, u8 type, u16 *encoded) +{ + if (unlikely(!IS_ALIGNED(size, PAGE_SIZE))) + return 0; + if (unlikely(size < MIN_EAGER_BUFFER)) + return 0; + if (size > + (type == PT_EAGER ? MAX_EAGER_BUFFER : MAX_EXPECTED_BUFFER)) + return 0; + if (encoded) + *encoded = ilog2(size / PAGE_SIZE) + 1; + return 1; +} + +static void rcv_hdrerr(struct hfi1_ctxtdata *rcd, struct hfi1_pportdata *ppd, + struct hfi1_packet *packet) +{ + struct hfi1_message_header *rhdr = packet->hdr; + u32 rte = rhf_rcv_type_err(packet->rhf); + int lnh = be16_to_cpu(rhdr->lrh[0]) & 3; + struct hfi1_ibport *ibp = &ppd->ibport_data; + + if (packet->rhf & (RHF_VCRC_ERR | RHF_ICRC_ERR)) + return; + + if (packet->rhf & RHF_TID_ERR) { + /* For TIDERR and RC QPs preemptively schedule a NAK */ + struct hfi1_ib_header *hdr = (struct hfi1_ib_header *)rhdr; + struct hfi1_other_headers *ohdr = NULL; + u32 tlen = rhf_pkt_len(packet->rhf); /* in bytes */ + u16 lid = be16_to_cpu(hdr->lrh[1]); + u32 qp_num; + u32 rcv_flags = 0; + + /* Sanity check packet */ + if (tlen < 24) + goto drop; + + /* Check for GRH */ + if (lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else if (lnh == HFI1_LRH_GRH) { + u32 vtf; + + ohdr = &hdr->u.l.oth; + if (hdr->u.l.grh.next_hdr != IB_GRH_NEXT_HDR) + goto drop; + vtf = be32_to_cpu(hdr->u.l.grh.version_tclass_flow); + if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) + goto drop; + rcv_flags |= HFI1_HAS_GRH; + } else + goto drop; + + /* Get the destination QP number. */ + qp_num = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK; + if (lid < HFI1_MULTICAST_LID_BASE) { + struct hfi1_qp *qp; + + rcu_read_lock(); + qp = hfi1_lookup_qpn(ibp, qp_num); + if (!qp) { + rcu_read_unlock(); + goto drop; + } + + /* + * Handle only RC QPs - for other QP types drop error + * packet. + */ + spin_lock(&qp->r_lock); + + /* Check for valid receive state. */ + if (!(ib_hfi1_state_ops[qp->state] & + HFI1_PROCESS_RECV_OK)) { + ibp->n_pkt_drops++; + } + + switch (qp->ibqp.qp_type) { + case IB_QPT_RC: + hfi1_rc_hdrerr( + rcd, + hdr, + rcv_flags, + qp); + break; + default: + /* For now don't handle any other QP types */ + break; + } + + spin_unlock(&qp->r_lock); + rcu_read_unlock(); + } /* Unicast QP */ + } /* Valid packet with TIDErr */ + + /* handle "RcvTypeErr" flags */ + switch (rte) { + case RHF_RTE_ERROR_OP_CODE_ERR: + { + u32 opcode; + void *ebuf = NULL; + __be32 *bth = NULL; + + if (rhf_use_egr_bfr(packet->rhf)) + ebuf = packet->ebuf; + + if (ebuf == NULL) + goto drop; /* this should never happen */ + + if (lnh == HFI1_LRH_BTH) + bth = (__be32 *)ebuf; + else if (lnh == HFI1_LRH_GRH) + bth = (__be32 *)((char *)ebuf + sizeof(struct ib_grh)); + else + goto drop; + + opcode = be32_to_cpu(bth[0]) >> 24; + opcode &= 0xff; + + if (opcode == IB_OPCODE_CNP) { + /* + * Only in pre-B0 h/w is the CNP_OPCODE handled + * via this code path (errata 291394). + */ + struct hfi1_qp *qp = NULL; + u32 lqpn, rqpn; + u16 rlid; + u8 svc_type, sl, sc5; + + sc5 = (be16_to_cpu(rhdr->lrh[0]) >> 12) & 0xf; + if (rhf_dc_info(packet->rhf)) + sc5 |= 0x10; + sl = ibp->sc_to_sl[sc5]; + + lqpn = be32_to_cpu(bth[1]) & HFI1_QPN_MASK; + rcu_read_lock(); + qp = hfi1_lookup_qpn(ibp, lqpn); + if (qp == NULL) { + rcu_read_unlock(); + goto drop; + } + + switch (qp->ibqp.qp_type) { + case IB_QPT_UD: + rlid = 0; + rqpn = 0; + svc_type = IB_CC_SVCTYPE_UD; + break; + case IB_QPT_UC: + rlid = be16_to_cpu(rhdr->lrh[3]); + rqpn = qp->remote_qpn; + svc_type = IB_CC_SVCTYPE_UC; + break; + default: + goto drop; + } + + process_becn(ppd, sl, rlid, lqpn, rqpn, svc_type); + rcu_read_unlock(); + } + + packet->rhf &= ~RHF_RCV_TYPE_ERR_SMASK; + break; + } + default: + break; + } + +drop: + return; +} + +static inline void init_packet(struct hfi1_ctxtdata *rcd, + struct hfi1_packet *packet) +{ + + packet->rsize = rcd->rcvhdrqentsize; /* words */ + packet->maxcnt = rcd->rcvhdrq_cnt * packet->rsize; /* words */ + packet->rcd = rcd; + packet->updegr = 0; + packet->etail = -1; + packet->rhf_addr = (__le32 *) rcd->rcvhdrq + rcd->head + + rcd->dd->rhf_offset; + packet->rhf = rhf_to_cpu(packet->rhf_addr); + packet->rhqoff = rcd->head; + packet->numpkt = 0; + packet->rcv_flags = 0; +} + +#ifndef CONFIG_PRESCAN_RXQ +static void prescan_rxq(struct hfi1_packet *packet) {} +#else /* CONFIG_PRESCAN_RXQ */ +static int prescan_receive_queue; + +static void process_ecn(struct hfi1_qp *qp, struct hfi1_ib_header *hdr, + struct hfi1_other_headers *ohdr, + u64 rhf, struct ib_grh *grh) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + u32 bth1; + u8 sc5, svc_type; + int is_fecn, is_becn; + + switch (qp->ibqp.qp_type) { + case IB_QPT_UD: + svc_type = IB_CC_SVCTYPE_UD; + break; + case IB_QPT_UC: /* LATER */ + case IB_QPT_RC: /* LATER */ + default: + return; + } + + is_fecn = (be32_to_cpu(ohdr->bth[1]) >> HFI1_FECN_SHIFT) & + HFI1_FECN_MASK; + is_becn = (be32_to_cpu(ohdr->bth[1]) >> HFI1_BECN_SHIFT) & + HFI1_BECN_MASK; + + sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; + if (rhf_dc_info(rhf)) + sc5 |= 0x10; + + if (is_fecn) { + u32 src_qpn = be32_to_cpu(ohdr->u.ud.deth[1]) & HFI1_QPN_MASK; + u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]); + u16 dlid = be16_to_cpu(hdr->lrh[1]); + u16 slid = be16_to_cpu(hdr->lrh[3]); + + return_cnp(ibp, qp, src_qpn, pkey, dlid, slid, sc5, grh); + } + + if (is_becn) { + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 lqpn = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK; + u8 sl = ibp->sc_to_sl[sc5]; + + process_becn(ppd, sl, 0, lqpn, 0, svc_type); + } + + /* turn off BECN, or FECN */ + bth1 = be32_to_cpu(ohdr->bth[1]); + bth1 &= ~(HFI1_FECN_MASK << HFI1_FECN_SHIFT); + bth1 &= ~(HFI1_BECN_MASK << HFI1_BECN_SHIFT); + ohdr->bth[1] = cpu_to_be32(bth1); +} + +struct ps_mdata { + struct hfi1_ctxtdata *rcd; + u32 rsize; + u32 maxcnt; + u32 ps_head; + u32 ps_tail; + u32 ps_seq; +}; + +static inline void init_ps_mdata(struct ps_mdata *mdata, + struct hfi1_packet *packet) +{ + struct hfi1_ctxtdata *rcd = packet->rcd; + + mdata->rcd = rcd; + mdata->rsize = packet->rsize; + mdata->maxcnt = packet->maxcnt; + + if (rcd->ps_state.initialized == 0) { + mdata->ps_head = packet->rhqoff; + rcd->ps_state.initialized++; + } else + mdata->ps_head = rcd->ps_state.ps_head; + + if (HFI1_CAP_IS_KSET(DMA_RTAIL)) { + mdata->ps_tail = packet->hdrqtail; + mdata->ps_seq = 0; /* not used with DMA_RTAIL */ + } else { + mdata->ps_tail = 0; /* used only with DMA_RTAIL*/ + mdata->ps_seq = rcd->seq_cnt; + } +} + +static inline int ps_done(struct ps_mdata *mdata, u64 rhf) +{ + if (HFI1_CAP_IS_KSET(DMA_RTAIL)) + return mdata->ps_head == mdata->ps_tail; + return mdata->ps_seq != rhf_rcv_seq(rhf); +} + +static inline void update_ps_mdata(struct ps_mdata *mdata) +{ + struct hfi1_ctxtdata *rcd = mdata->rcd; + + mdata->ps_head += mdata->rsize; + if (mdata->ps_head > mdata->maxcnt) + mdata->ps_head = 0; + rcd->ps_state.ps_head = mdata->ps_head; + if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) { + if (++mdata->ps_seq > 13) + mdata->ps_seq = 1; + } +} + +/* + * prescan_rxq - search through the receive queue looking for packets + * containing Excplicit Congestion Notifications (FECNs, or BECNs). + * When an ECN is found, process the Congestion Notification, and toggle + * it off. + */ +static void prescan_rxq(struct hfi1_packet *packet) +{ + struct hfi1_ctxtdata *rcd = packet->rcd; + struct ps_mdata mdata; + + if (!prescan_receive_queue) + return; + + init_ps_mdata(&mdata, packet); + + while (1) { + struct hfi1_devdata *dd = rcd->dd; + struct hfi1_ibport *ibp = &rcd->ppd->ibport_data; + __le32 *rhf_addr = (__le32 *) rcd->rcvhdrq + mdata.ps_head + + dd->rhf_offset; + struct hfi1_qp *qp; + struct hfi1_ib_header *hdr; + struct hfi1_other_headers *ohdr; + struct ib_grh *grh = NULL; + u64 rhf = rhf_to_cpu(rhf_addr); + u32 etype = rhf_rcv_type(rhf), qpn; + int is_ecn = 0; + u8 lnh; + + if (ps_done(&mdata, rhf)) + break; + + if (etype != RHF_RCV_TYPE_IB) + goto next; + + hdr = (struct hfi1_ib_header *) + hfi1_get_msgheader(dd, rhf_addr); + lnh = be16_to_cpu(hdr->lrh[0]) & 3; + + if (lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else if (lnh == HFI1_LRH_GRH) { + ohdr = &hdr->u.l.oth; + grh = &hdr->u.l.grh; + } else + goto next; /* just in case */ + + is_ecn |= be32_to_cpu(ohdr->bth[1]) & + (HFI1_FECN_MASK << HFI1_FECN_SHIFT); + is_ecn |= be32_to_cpu(ohdr->bth[1]) & + (HFI1_BECN_MASK << HFI1_BECN_SHIFT); + + if (!is_ecn) + goto next; + + qpn = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK; + rcu_read_lock(); + qp = hfi1_lookup_qpn(ibp, qpn); + + if (qp == NULL) { + rcu_read_unlock(); + goto next; + } + + process_ecn(qp, hdr, ohdr, rhf, grh); + rcu_read_unlock(); +next: + update_ps_mdata(&mdata); + } +} +#endif /* CONFIG_PRESCAN_RXQ */ + +#define RCV_PKT_OK 0x0 +#define RCV_PKT_MAX 0x1 + +static inline int process_rcv_packet(struct hfi1_packet *packet) +{ + int ret = RCV_PKT_OK; + + packet->hdr = hfi1_get_msgheader(packet->rcd->dd, + packet->rhf_addr); + packet->hlen = (u8 *)packet->rhf_addr - (u8 *)packet->hdr; + packet->etype = rhf_rcv_type(packet->rhf); + /* total length */ + packet->tlen = rhf_pkt_len(packet->rhf); /* in bytes */ + /* retrieve eager buffer details */ + packet->ebuf = NULL; + if (rhf_use_egr_bfr(packet->rhf)) { + packet->etail = rhf_egr_index(packet->rhf); + packet->ebuf = get_egrbuf(packet->rcd, packet->rhf, + &packet->updegr); + /* + * Prefetch the contents of the eager buffer. It is + * OK to send a negative length to prefetch_range(). + * The +2 is the size of the RHF. + */ + prefetch_range(packet->ebuf, + packet->tlen - ((packet->rcd->rcvhdrqentsize - + (rhf_hdrq_offset(packet->rhf)+2)) * 4)); + } + + /* + * Call a type specific handler for the packet. We + * should be able to trust that etype won't be beyond + * the range of valid indexes. If so something is really + * wrong and we can probably just let things come + * crashing down. There is no need to eat another + * comparison in this performance critical code. + */ + packet->rcd->dd->rhf_rcv_function_map[packet->etype](packet); + packet->numpkt++; + + /* Set up for the next packet */ + packet->rhqoff += packet->rsize; + if (packet->rhqoff >= packet->maxcnt) + packet->rhqoff = 0; + + if (packet->numpkt == MAX_PKT_RECV) { + ret = RCV_PKT_MAX; + this_cpu_inc(*packet->rcd->dd->rcv_limit); + } + + packet->rhf_addr = (__le32 *) packet->rcd->rcvhdrq + packet->rhqoff + + packet->rcd->dd->rhf_offset; + packet->rhf = rhf_to_cpu(packet->rhf_addr); + + return ret; +} + +static inline void process_rcv_update(int last, struct hfi1_packet *packet) +{ + /* + * Update head regs etc., every 16 packets, if not last pkt, + * to help prevent rcvhdrq overflows, when many packets + * are processed and queue is nearly full. + * Don't request an interrupt for intermediate updates. + */ + if (!last && !(packet->numpkt & 0xf)) { + update_usrhead(packet->rcd, packet->rhqoff, packet->updegr, + packet->etail, 0, 0); + packet->updegr = 0; + } + packet->rcv_flags = 0; +} + +static inline void finish_packet(struct hfi1_packet *packet) +{ + + /* + * Nothing we need to free for the packet. + * + * The only thing we need to do is a final update and call for an + * interrupt + */ + update_usrhead(packet->rcd, packet->rcd->head, packet->updegr, + packet->etail, rcv_intr_dynamic, packet->numpkt); + +} + +static inline void process_rcv_qp_work(struct hfi1_packet *packet) +{ + + struct hfi1_ctxtdata *rcd; + struct hfi1_qp *qp, *nqp; + + rcd = packet->rcd; + rcd->head = packet->rhqoff; + + /* + * Iterate over all QPs waiting to respond. + * The list won't change since the IRQ is only run on one CPU. + */ + list_for_each_entry_safe(qp, nqp, &rcd->qp_wait_list, rspwait) { + list_del_init(&qp->rspwait); + if (qp->r_flags & HFI1_R_RSP_NAK) { + qp->r_flags &= ~HFI1_R_RSP_NAK; + hfi1_send_rc_ack(rcd, qp, 0); + } + if (qp->r_flags & HFI1_R_RSP_SEND) { + unsigned long flags; + + qp->r_flags &= ~HFI1_R_RSP_SEND; + spin_lock_irqsave(&qp->s_lock, flags); + if (ib_hfi1_state_ops[qp->state] & + HFI1_PROCESS_OR_FLUSH_SEND) + hfi1_schedule_send(qp); + spin_unlock_irqrestore(&qp->s_lock, flags); + } + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } +} + +/* + * Handle receive interrupts when using the no dma rtail option. + */ +void handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *rcd) +{ + u32 seq; + int last = 0; + struct hfi1_packet packet; + + init_packet(rcd, &packet); + seq = rhf_rcv_seq(packet.rhf); + if (seq != rcd->seq_cnt) + goto bail; + + prescan_rxq(&packet); + + while (!last) { + last = process_rcv_packet(&packet); + seq = rhf_rcv_seq(packet.rhf); + if (++rcd->seq_cnt > 13) + rcd->seq_cnt = 1; + if (seq != rcd->seq_cnt) + last = 1; + process_rcv_update(last, &packet); + } + process_rcv_qp_work(&packet); +bail: + finish_packet(&packet); +} + +void handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd) +{ + u32 hdrqtail; + int last = 0; + struct hfi1_packet packet; + + init_packet(rcd, &packet); + hdrqtail = get_rcvhdrtail(rcd); + if (packet.rhqoff == hdrqtail) + goto bail; + smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ + + prescan_rxq(&packet); + + while (!last) { + last = process_rcv_packet(&packet); + if (packet.rhqoff == hdrqtail) + last = 1; + process_rcv_update(last, &packet); + } + process_rcv_qp_work(&packet); +bail: + finish_packet(&packet); + +} + +static inline void set_all_nodma_rtail(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < dd->first_user_ctxt; i++) + dd->rcd[i]->do_interrupt = + &handle_receive_interrupt_nodma_rtail; +} + +static inline void set_all_dma_rtail(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < dd->first_user_ctxt; i++) + dd->rcd[i]->do_interrupt = + &handle_receive_interrupt_dma_rtail; +} + +/* + * handle_receive_interrupt - receive a packet + * @rcd: the context + * + * Called from interrupt handler for errors or receive interrupt. + * This is the slow path interrupt handler. + */ +void handle_receive_interrupt(struct hfi1_ctxtdata *rcd) +{ + + struct hfi1_devdata *dd = rcd->dd; + u32 hdrqtail; + int last = 0, needset = 1; + struct hfi1_packet packet; + + init_packet(rcd, &packet); + + if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) { + u32 seq = rhf_rcv_seq(packet.rhf); + + if (seq != rcd->seq_cnt) + goto bail; + hdrqtail = 0; + } else { + hdrqtail = get_rcvhdrtail(rcd); + if (packet.rhqoff == hdrqtail) + goto bail; + smp_rmb(); /* prevent speculative reads of dma'ed hdrq */ + } + + prescan_rxq(&packet); + + while (!last) { + + if (unlikely(dd->do_drop && atomic_xchg(&dd->drop_packet, + DROP_PACKET_OFF) == DROP_PACKET_ON)) { + dd->do_drop = 0; + + /* On to the next packet */ + packet.rhqoff += packet.rsize; + packet.rhf_addr = (__le32 *) rcd->rcvhdrq + + packet.rhqoff + + dd->rhf_offset; + packet.rhf = rhf_to_cpu(packet.rhf_addr); + + } else { + last = process_rcv_packet(&packet); + } + + if (!HFI1_CAP_IS_KSET(DMA_RTAIL)) { + u32 seq = rhf_rcv_seq(packet.rhf); + + if (++rcd->seq_cnt > 13) + rcd->seq_cnt = 1; + if (seq != rcd->seq_cnt) + last = 1; + if (needset) { + dd_dev_info(dd, + "Switching to NO_DMA_RTAIL\n"); + set_all_nodma_rtail(dd); + needset = 0; + } + } else { + if (packet.rhqoff == hdrqtail) + last = 1; + if (needset) { + dd_dev_info(dd, + "Switching to DMA_RTAIL\n"); + set_all_dma_rtail(dd); + needset = 0; + } + } + + process_rcv_update(last, &packet); + } + + process_rcv_qp_work(&packet); + +bail: + /* + * Always write head at end, and setup rcv interrupt, even + * if no packets were processed. + */ + finish_packet(&packet); +} + +/* + * Convert a given MTU size to the on-wire MAD packet enumeration. + * Return -1 if the size is invalid. + */ +int mtu_to_enum(u32 mtu, int default_if_bad) +{ + switch (mtu) { + case 0: return OPA_MTU_0; + case 256: return OPA_MTU_256; + case 512: return OPA_MTU_512; + case 1024: return OPA_MTU_1024; + case 2048: return OPA_MTU_2048; + case 4096: return OPA_MTU_4096; + case 8192: return OPA_MTU_8192; + case 10240: return OPA_MTU_10240; + } + return default_if_bad; +} + +u16 enum_to_mtu(int mtu) +{ + switch (mtu) { + case OPA_MTU_0: return 0; + case OPA_MTU_256: return 256; + case OPA_MTU_512: return 512; + case OPA_MTU_1024: return 1024; + case OPA_MTU_2048: return 2048; + case OPA_MTU_4096: return 4096; + case OPA_MTU_8192: return 8192; + case OPA_MTU_10240: return 10240; + default: return 0xffff; + } +} + +/* + * set_mtu - set the MTU + * @ppd: the per port data + * + * We can handle "any" incoming size, the issue here is whether we + * need to restrict our outgoing size. We do not deal with what happens + * to programs that are already running when the size changes. + */ +int set_mtu(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + int i, drain, ret = 0, is_up = 0; + + ppd->ibmtu = 0; + for (i = 0; i < ppd->vls_supported; i++) + if (ppd->ibmtu < dd->vld[i].mtu) + ppd->ibmtu = dd->vld[i].mtu; + ppd->ibmaxlen = ppd->ibmtu + lrh_max_header_bytes(ppd->dd); + + mutex_lock(&ppd->hls_lock); + if (ppd->host_link_state == HLS_UP_INIT + || ppd->host_link_state == HLS_UP_ARMED + || ppd->host_link_state == HLS_UP_ACTIVE) + is_up = 1; + + drain = !is_ax(dd) && is_up; + + if (drain) + /* + * MTU is specified per-VL. To ensure that no packet gets + * stuck (due, e.g., to the MTU for the packet's VL being + * reduced), empty the per-VL FIFOs before adjusting MTU. + */ + ret = stop_drain_data_vls(dd); + + if (ret) { + dd_dev_err(dd, "%s: cannot stop/drain VLs - refusing to change per-VL MTUs\n", + __func__); + goto err; + } + + hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_MTU, 0); + + if (drain) + open_fill_data_vls(dd); /* reopen all VLs */ + +err: + mutex_unlock(&ppd->hls_lock); + + return ret; +} + +int hfi1_set_lid(struct hfi1_pportdata *ppd, u32 lid, u8 lmc) +{ + struct hfi1_devdata *dd = ppd->dd; + + ppd->lid = lid; + ppd->lmc = lmc; + hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LIDLMC, 0); + + dd_dev_info(dd, "IB%u:%u got a lid: 0x%x\n", dd->unit, ppd->port, lid); + + return 0; +} + +/* + * Following deal with the "obviously simple" task of overriding the state + * of the LEDs, which normally indicate link physical and logical status. + * The complications arise in dealing with different hardware mappings + * and the board-dependent routine being called from interrupts. + * and then there's the requirement to _flash_ them. + */ +#define LED_OVER_FREQ_SHIFT 8 +#define LED_OVER_FREQ_MASK (0xFF<dd; + int timeoff; + int ph_idx; + + if (!(dd->flags & HFI1_INITTED)) + return; + + ph_idx = ppd->led_override_phase++ & 1; + ppd->led_override = ppd->led_override_vals[ph_idx]; + timeoff = ppd->led_override_timeoff; + + /* + * don't re-fire the timer if user asked for it to be off; we let + * it fire one more time after they turn it off to simplify + */ + if (ppd->led_override_vals[0] || ppd->led_override_vals[1]) + mod_timer(&ppd->led_override_timer, jiffies + timeoff); +} + +void hfi1_set_led_override(struct hfi1_pportdata *ppd, unsigned int val) +{ + struct hfi1_devdata *dd = ppd->dd; + int timeoff, freq; + + if (!(dd->flags & HFI1_INITTED)) + return; + + /* First check if we are blinking. If not, use 1HZ polling */ + timeoff = HZ; + freq = (val & LED_OVER_FREQ_MASK) >> LED_OVER_FREQ_SHIFT; + + if (freq) { + /* For blink, set each phase from one nybble of val */ + ppd->led_override_vals[0] = val & 0xF; + ppd->led_override_vals[1] = (val >> 4) & 0xF; + timeoff = (HZ << 4)/freq; + } else { + /* Non-blink set both phases the same. */ + ppd->led_override_vals[0] = val & 0xF; + ppd->led_override_vals[1] = val & 0xF; + } + ppd->led_override_timeoff = timeoff; + + /* + * If the timer has not already been started, do so. Use a "quick" + * timeout so the function will be called soon, to look at our request. + */ + if (atomic_inc_return(&ppd->led_override_timer_active) == 1) { + /* Need to start timer */ + init_timer(&ppd->led_override_timer); + ppd->led_override_timer.function = run_led_override; + ppd->led_override_timer.data = (unsigned long) ppd; + ppd->led_override_timer.expires = jiffies + 1; + add_timer(&ppd->led_override_timer); + } else { + if (ppd->led_override_vals[0] || ppd->led_override_vals[1]) + mod_timer(&ppd->led_override_timer, jiffies + 1); + atomic_dec(&ppd->led_override_timer_active); + } +} + +/** + * hfi1_reset_device - reset the chip if possible + * @unit: the device to reset + * + * Whether or not reset is successful, we attempt to re-initialize the chip + * (that is, much like a driver unload/reload). We clear the INITTED flag + * so that the various entry points will fail until we reinitialize. For + * now, we only allow this if no user contexts are open that use chip resources + */ +int hfi1_reset_device(int unit) +{ + int ret, i; + struct hfi1_devdata *dd = hfi1_lookup(unit); + struct hfi1_pportdata *ppd; + unsigned long flags; + int pidx; + + if (!dd) { + ret = -ENODEV; + goto bail; + } + + dd_dev_info(dd, "Reset on unit %u requested\n", unit); + + if (!dd->kregbase || !(dd->flags & HFI1_PRESENT)) { + dd_dev_info(dd, + "Invalid unit number %u or not initialized or not present\n", + unit); + ret = -ENXIO; + goto bail; + } + + spin_lock_irqsave(&dd->uctxt_lock, flags); + if (dd->rcd) + for (i = dd->first_user_ctxt; i < dd->num_rcv_contexts; i++) { + if (!dd->rcd[i] || !dd->rcd[i]->cnt) + continue; + spin_unlock_irqrestore(&dd->uctxt_lock, flags); + ret = -EBUSY; + goto bail; + } + spin_unlock_irqrestore(&dd->uctxt_lock, flags); + + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (atomic_read(&ppd->led_override_timer_active)) { + /* Need to stop LED timer, _then_ shut off LEDs */ + del_timer_sync(&ppd->led_override_timer); + atomic_set(&ppd->led_override_timer_active, 0); + } + + /* Shut off LEDs after we are sure timer is not running */ + ppd->led_override = LED_OVER_BOTH_OFF; + } + if (dd->flags & HFI1_HAS_SEND_DMA) + sdma_exit(dd); + + hfi1_reset_cpu_counters(dd); + + ret = hfi1_init(dd, 1); + + if (ret) + dd_dev_err(dd, + "Reinitialize unit %u after reset failed with %d\n", + unit, ret); + else + dd_dev_info(dd, "Reinitialized unit %u after resetting\n", + unit); + +bail: + return ret; +} + +void handle_eflags(struct hfi1_packet *packet) +{ + struct hfi1_ctxtdata *rcd = packet->rcd; + u32 rte = rhf_rcv_type_err(packet->rhf); + + dd_dev_err(rcd->dd, + "receive context %d: rhf 0x%016llx, errs [ %s%s%s%s%s%s%s%s] rte 0x%x\n", + rcd->ctxt, packet->rhf, + packet->rhf & RHF_K_HDR_LEN_ERR ? "k_hdr_len " : "", + packet->rhf & RHF_DC_UNC_ERR ? "dc_unc " : "", + packet->rhf & RHF_DC_ERR ? "dc " : "", + packet->rhf & RHF_TID_ERR ? "tid " : "", + packet->rhf & RHF_LEN_ERR ? "len " : "", + packet->rhf & RHF_ECC_ERR ? "ecc " : "", + packet->rhf & RHF_VCRC_ERR ? "vcrc " : "", + packet->rhf & RHF_ICRC_ERR ? "icrc " : "", + rte); + + rcv_hdrerr(rcd, rcd->ppd, packet); +} + +/* + * The following functions are called by the interrupt handler. They are type + * specific handlers for each packet type. + */ +int process_receive_ib(struct hfi1_packet *packet) +{ + trace_hfi1_rcvhdr(packet->rcd->ppd->dd, + packet->rcd->ctxt, + rhf_err_flags(packet->rhf), + RHF_RCV_TYPE_IB, + packet->hlen, + packet->tlen, + packet->updegr, + rhf_egr_index(packet->rhf)); + + if (unlikely(rhf_err_flags(packet->rhf))) { + handle_eflags(packet); + return RHF_RCV_CONTINUE; + } + + hfi1_ib_rcv(packet); + return RHF_RCV_CONTINUE; +} + +int process_receive_bypass(struct hfi1_packet *packet) +{ + if (unlikely(rhf_err_flags(packet->rhf))) + handle_eflags(packet); + + dd_dev_err(packet->rcd->dd, + "Bypass packets are not supported in normal operation. Dropping\n"); + return RHF_RCV_CONTINUE; +} + +int process_receive_error(struct hfi1_packet *packet) +{ + handle_eflags(packet); + + if (unlikely(rhf_err_flags(packet->rhf))) + dd_dev_err(packet->rcd->dd, + "Unhandled error packet received. Dropping.\n"); + + return RHF_RCV_CONTINUE; +} + +int kdeth_process_expected(struct hfi1_packet *packet) +{ + if (unlikely(rhf_err_flags(packet->rhf))) + handle_eflags(packet); + + dd_dev_err(packet->rcd->dd, + "Unhandled expected packet received. Dropping.\n"); + return RHF_RCV_CONTINUE; +} + +int kdeth_process_eager(struct hfi1_packet *packet) +{ + if (unlikely(rhf_err_flags(packet->rhf))) + handle_eflags(packet); + + dd_dev_err(packet->rcd->dd, + "Unhandled eager packet received. Dropping.\n"); + return RHF_RCV_CONTINUE; +} + +int process_receive_invalid(struct hfi1_packet *packet) +{ + dd_dev_err(packet->rcd->dd, "Invalid packet type %d. Dropping\n", + rhf_rcv_type(packet->rhf)); + return RHF_RCV_CONTINUE; +} diff --git a/drivers/staging/rdma/hfi1/eprom.c b/drivers/staging/rdma/hfi1/eprom.c new file mode 100644 index 0000000000000..b61d3ae93ed13 --- /dev/null +++ b/drivers/staging/rdma/hfi1/eprom.c @@ -0,0 +1,475 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include "hfi.h" +#include "common.h" +#include "eprom.h" + +/* + * The EPROM is logically divided into two partitions: + * partition 0: the first 128K, visible from PCI ROM BAR + * partition 1: the rest + */ +#define P0_SIZE (128 * 1024) +#define P1_START P0_SIZE + +/* largest erase size supported by the controller */ +#define SIZE_32KB (32 * 1024) +#define MASK_32KB (SIZE_32KB - 1) + +/* controller page size, in bytes */ +#define EP_PAGE_SIZE 256 +#define EEP_PAGE_MASK (EP_PAGE_SIZE - 1) + +/* controller commands */ +#define CMD_SHIFT 24 +#define CMD_NOP (0) +#define CMD_PAGE_PROGRAM(addr) ((0x02 << CMD_SHIFT) | addr) +#define CMD_READ_DATA(addr) ((0x03 << CMD_SHIFT) | addr) +#define CMD_READ_SR1 ((0x05 << CMD_SHIFT)) +#define CMD_WRITE_ENABLE ((0x06 << CMD_SHIFT)) +#define CMD_SECTOR_ERASE_32KB(addr) ((0x52 << CMD_SHIFT) | addr) +#define CMD_CHIP_ERASE ((0x60 << CMD_SHIFT)) +#define CMD_READ_MANUF_DEV_ID ((0x90 << CMD_SHIFT)) +#define CMD_RELEASE_POWERDOWN_NOID ((0xab << CMD_SHIFT)) + +/* controller interface speeds */ +#define EP_SPEED_FULL 0x2 /* full speed */ + +/* controller status register 1 bits */ +#define SR1_BUSY 0x1ull /* the BUSY bit in SR1 */ + +/* sleep length while waiting for controller */ +#define WAIT_SLEEP_US 100 /* must be larger than 5 (see usage) */ +#define COUNT_DELAY_SEC(n) ((n) * (1000000/WAIT_SLEEP_US)) + +/* GPIO pins */ +#define EPROM_WP_N (1ull << 14) /* EPROM write line */ + +/* + * Use the EP mutex to guard against other callers from within the driver. + * Also covers usage of eprom_available. + */ +static DEFINE_MUTEX(eprom_mutex); +static int eprom_available; /* default: not available */ + +/* + * Turn on external enable line that allows writing on the flash. + */ +static void write_enable(struct hfi1_devdata *dd) +{ + /* raise signal */ + write_csr(dd, ASIC_GPIO_OUT, + read_csr(dd, ASIC_GPIO_OUT) | EPROM_WP_N); + /* raise enable */ + write_csr(dd, ASIC_GPIO_OE, + read_csr(dd, ASIC_GPIO_OE) | EPROM_WP_N); +} + +/* + * Turn off external enable line that allows writing on the flash. + */ +static void write_disable(struct hfi1_devdata *dd) +{ + /* lower signal */ + write_csr(dd, ASIC_GPIO_OUT, + read_csr(dd, ASIC_GPIO_OUT) & ~EPROM_WP_N); + /* lower enable */ + write_csr(dd, ASIC_GPIO_OE, + read_csr(dd, ASIC_GPIO_OE) & ~EPROM_WP_N); +} + +/* + * Wait for the device to become not busy. Must be called after all + * write or erase operations. + */ +static int wait_for_not_busy(struct hfi1_devdata *dd) +{ + unsigned long count = 0; + u64 reg; + int ret = 0; + + /* starts page mode */ + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_SR1); + while (1) { + udelay(WAIT_SLEEP_US); + usleep_range(WAIT_SLEEP_US - 5, WAIT_SLEEP_US + 5); + count++; + reg = read_csr(dd, ASIC_EEP_DATA); + if ((reg & SR1_BUSY) == 0) + break; + /* 200s is the largest time for a 128Mb device */ + if (count > COUNT_DELAY_SEC(200)) { + dd_dev_err(dd, "waited too long for SPI FLASH busy to clear - failing\n"); + ret = -ETIMEDOUT; + break; /* break, not goto - must stop page mode */ + } + } + + /* stop page mode with a NOP */ + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_NOP); + + return ret; +} + +/* + * Read the device ID from the SPI controller. + */ +static u32 read_device_id(struct hfi1_devdata *dd) +{ + /* read the Manufacture Device ID */ + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_MANUF_DEV_ID); + return (u32)read_csr(dd, ASIC_EEP_DATA); +} + +/* + * Erase the whole flash. + */ +static int erase_chip(struct hfi1_devdata *dd) +{ + int ret; + + write_enable(dd); + + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_WRITE_ENABLE); + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_CHIP_ERASE); + ret = wait_for_not_busy(dd); + + write_disable(dd); + + return ret; +} + +/* + * Erase a range using the 32KB erase command. + */ +static int erase_32kb_range(struct hfi1_devdata *dd, u32 start, u32 end) +{ + int ret = 0; + + if (end < start) + return -EINVAL; + + if ((start & MASK_32KB) || (end & MASK_32KB)) { + dd_dev_err(dd, + "%s: non-aligned range (0x%x,0x%x) for a 32KB erase\n", + __func__, start, end); + return -EINVAL; + } + + write_enable(dd); + + for (; start < end; start += SIZE_32KB) { + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_WRITE_ENABLE); + write_csr(dd, ASIC_EEP_ADDR_CMD, + CMD_SECTOR_ERASE_32KB(start)); + ret = wait_for_not_busy(dd); + if (ret) + goto done; + } + +done: + write_disable(dd); + + return ret; +} + +/* + * Read a 256 byte (64 dword) EPROM page. + * All callers have verified the offset is at a page boundary. + */ +static void read_page(struct hfi1_devdata *dd, u32 offset, u32 *result) +{ + int i; + + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_READ_DATA(offset)); + for (i = 0; i < EP_PAGE_SIZE/sizeof(u32); i++) + result[i] = (u32)read_csr(dd, ASIC_EEP_DATA); + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_NOP); /* close open page */ +} + +/* + * Read length bytes starting at offset. Copy to user address addr. + */ +static int read_length(struct hfi1_devdata *dd, u32 start, u32 len, u64 addr) +{ + u32 offset; + u32 buffer[EP_PAGE_SIZE/sizeof(u32)]; + int ret = 0; + + /* reject anything not on an EPROM page boundary */ + if ((start & EEP_PAGE_MASK) || (len & EEP_PAGE_MASK)) + return -EINVAL; + + for (offset = 0; offset < len; offset += EP_PAGE_SIZE) { + read_page(dd, start + offset, buffer); + if (copy_to_user((void __user *)(addr + offset), + buffer, EP_PAGE_SIZE)) { + ret = -EFAULT; + goto done; + } + } + +done: + return ret; +} + +/* + * Write a 256 byte (64 dword) EPROM page. + * All callers have verified the offset is at a page boundary. + */ +static int write_page(struct hfi1_devdata *dd, u32 offset, u32 *data) +{ + int i; + + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_WRITE_ENABLE); + write_csr(dd, ASIC_EEP_DATA, data[0]); + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_PAGE_PROGRAM(offset)); + for (i = 1; i < EP_PAGE_SIZE/sizeof(u32); i++) + write_csr(dd, ASIC_EEP_DATA, data[i]); + /* will close the open page */ + return wait_for_not_busy(dd); +} + +/* + * Write length bytes starting at offset. Read from user address addr. + */ +static int write_length(struct hfi1_devdata *dd, u32 start, u32 len, u64 addr) +{ + u32 offset; + u32 buffer[EP_PAGE_SIZE/sizeof(u32)]; + int ret = 0; + + /* reject anything not on an EPROM page boundary */ + if ((start & EEP_PAGE_MASK) || (len & EEP_PAGE_MASK)) + return -EINVAL; + + write_enable(dd); + + for (offset = 0; offset < len; offset += EP_PAGE_SIZE) { + if (copy_from_user(buffer, (void __user *)(addr + offset), + EP_PAGE_SIZE)) { + ret = -EFAULT; + goto done; + } + ret = write_page(dd, start + offset, buffer); + if (ret) + goto done; + } + +done: + write_disable(dd); + return ret; +} + +/* + * Perform the given operation on the EPROM. Called from user space. The + * user credentials have already been checked. + * + * Return 0 on success, -ERRNO on error + */ +int handle_eprom_command(const struct hfi1_cmd *cmd) +{ + struct hfi1_devdata *dd; + u32 dev_id; + int ret = 0; + + /* + * The EPROM is per-device, so use unit 0 as that will always + * exist. + */ + dd = hfi1_lookup(0); + if (!dd) { + pr_err("%s: cannot find unit 0!\n", __func__); + return -EINVAL; + } + + /* lock against other callers touching the ASIC block */ + mutex_lock(&eprom_mutex); + + /* some platforms do not have an EPROM */ + if (!eprom_available) { + ret = -ENOSYS; + goto done_asic; + } + + /* lock against the other HFI on another OS */ + ret = acquire_hw_mutex(dd); + if (ret) { + dd_dev_err(dd, + "%s: unable to acquire hw mutex, no EPROM support\n", + __func__); + goto done_asic; + } + + dd_dev_info(dd, "%s: cmd: type %d, len 0x%x, addr 0x%016llx\n", + __func__, cmd->type, cmd->len, cmd->addr); + + switch (cmd->type) { + case HFI1_CMD_EP_INFO: + if (cmd->len != sizeof(u32)) { + ret = -ERANGE; + break; + } + dev_id = read_device_id(dd); + /* addr points to a u32 user buffer */ + if (copy_to_user((void __user *)cmd->addr, &dev_id, + sizeof(u32))) + ret = -EFAULT; + break; + case HFI1_CMD_EP_ERASE_CHIP: + ret = erase_chip(dd); + break; + case HFI1_CMD_EP_ERASE_P0: + if (cmd->len != P0_SIZE) { + ret = -ERANGE; + break; + } + ret = erase_32kb_range(dd, 0, cmd->len); + break; + case HFI1_CMD_EP_ERASE_P1: + /* check for overflow */ + if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) { + ret = -ERANGE; + break; + } + ret = erase_32kb_range(dd, P1_START, P1_START + cmd->len); + break; + case HFI1_CMD_EP_READ_P0: + if (cmd->len != P0_SIZE) { + ret = -ERANGE; + break; + } + ret = read_length(dd, 0, cmd->len, cmd->addr); + break; + case HFI1_CMD_EP_READ_P1: + /* check for overflow */ + if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) { + ret = -ERANGE; + break; + } + ret = read_length(dd, P1_START, cmd->len, cmd->addr); + break; + case HFI1_CMD_EP_WRITE_P0: + if (cmd->len > P0_SIZE) { + ret = -ERANGE; + break; + } + ret = write_length(dd, 0, cmd->len, cmd->addr); + break; + case HFI1_CMD_EP_WRITE_P1: + /* check for overflow */ + if (P1_START + cmd->len > ASIC_EEP_ADDR_CMD_EP_ADDR_MASK) { + ret = -ERANGE; + break; + } + ret = write_length(dd, P1_START, cmd->len, cmd->addr); + break; + default: + dd_dev_err(dd, "%s: unexpected command %d\n", + __func__, cmd->type); + ret = -EINVAL; + break; + } + + release_hw_mutex(dd); +done_asic: + mutex_unlock(&eprom_mutex); + return ret; +} + +/* + * Initialize the EPROM handler. + */ +int eprom_init(struct hfi1_devdata *dd) +{ + int ret = 0; + + /* only the discrete chip has an EPROM, nothing to do */ + if (dd->pcidev->device != PCI_DEVICE_ID_INTEL0) + return 0; + + /* lock against other callers */ + mutex_lock(&eprom_mutex); + if (eprom_available) /* already initialized */ + goto done_asic; + + /* + * Lock against the other HFI on another OS - the mutex above + * would have caught anything in this driver. It is OK if + * both OSes reset the EPROM - as long as they don't do it at + * the same time. + */ + ret = acquire_hw_mutex(dd); + if (ret) { + dd_dev_err(dd, + "%s: unable to acquire hw mutex, no EPROM support\n", + __func__); + goto done_asic; + } + + /* reset EPROM to be sure it is in a good state */ + + /* set reset */ + write_csr(dd, ASIC_EEP_CTL_STAT, + ASIC_EEP_CTL_STAT_EP_RESET_SMASK); + /* clear reset, set speed */ + write_csr(dd, ASIC_EEP_CTL_STAT, + EP_SPEED_FULL << ASIC_EEP_CTL_STAT_RATE_SPI_SHIFT); + + /* wake the device with command "release powerdown NoID" */ + write_csr(dd, ASIC_EEP_ADDR_CMD, CMD_RELEASE_POWERDOWN_NOID); + + eprom_available = 1; + release_hw_mutex(dd); +done_asic: + mutex_unlock(&eprom_mutex); + return ret; +} diff --git a/drivers/staging/rdma/hfi1/eprom.h b/drivers/staging/rdma/hfi1/eprom.h new file mode 100644 index 0000000000000..64a64276be819 --- /dev/null +++ b/drivers/staging/rdma/hfi1/eprom.h @@ -0,0 +1,55 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +struct hfi1_cmd; +struct hfi1_devdata; + +int eprom_init(struct hfi1_devdata *dd); +int handle_eprom_command(const struct hfi1_cmd *cmd); diff --git a/drivers/staging/rdma/hfi1/file_ops.c b/drivers/staging/rdma/hfi1/file_ops.c new file mode 100644 index 0000000000000..469861750b762 --- /dev/null +++ b/drivers/staging/rdma/hfi1/file_ops.c @@ -0,0 +1,2140 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "pio.h" +#include "device.h" +#include "common.h" +#include "trace.h" +#include "user_sdma.h" +#include "eprom.h" + +#undef pr_fmt +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +#define SEND_CTXT_HALT_TIMEOUT 1000 /* msecs */ + +/* + * File operation functions + */ +static int hfi1_file_open(struct inode *, struct file *); +static int hfi1_file_close(struct inode *, struct file *); +static ssize_t hfi1_file_write(struct file *, const char __user *, + size_t, loff_t *); +static ssize_t hfi1_write_iter(struct kiocb *, struct iov_iter *); +static unsigned int hfi1_poll(struct file *, struct poll_table_struct *); +static int hfi1_file_mmap(struct file *, struct vm_area_struct *); + +static u64 kvirt_to_phys(void *); +static int assign_ctxt(struct file *, struct hfi1_user_info *); +static int init_subctxts(struct hfi1_ctxtdata *, const struct hfi1_user_info *); +static int user_init(struct file *); +static int get_ctxt_info(struct file *, void __user *, __u32); +static int get_base_info(struct file *, void __user *, __u32); +static int setup_ctxt(struct file *); +static int setup_subctxt(struct hfi1_ctxtdata *); +static int get_user_context(struct file *, struct hfi1_user_info *, + int, unsigned); +static int find_shared_ctxt(struct file *, const struct hfi1_user_info *); +static int allocate_ctxt(struct file *, struct hfi1_devdata *, + struct hfi1_user_info *); +static unsigned int poll_urgent(struct file *, struct poll_table_struct *); +static unsigned int poll_next(struct file *, struct poll_table_struct *); +static int user_event_ack(struct hfi1_ctxtdata *, int, unsigned long); +static int set_ctxt_pkey(struct hfi1_ctxtdata *, unsigned, u16); +static int manage_rcvq(struct hfi1_ctxtdata *, unsigned, int); +static int vma_fault(struct vm_area_struct *, struct vm_fault *); +static int exp_tid_setup(struct file *, struct hfi1_tid_info *); +static int exp_tid_free(struct file *, struct hfi1_tid_info *); +static void unlock_exp_tids(struct hfi1_ctxtdata *); + +static const struct file_operations hfi1_file_ops = { + .owner = THIS_MODULE, + .write = hfi1_file_write, + .write_iter = hfi1_write_iter, + .open = hfi1_file_open, + .release = hfi1_file_close, + .poll = hfi1_poll, + .mmap = hfi1_file_mmap, + .llseek = noop_llseek, +}; + +static struct vm_operations_struct vm_ops = { + .fault = vma_fault, +}; + +/* + * Types of memories mapped into user processes' space + */ +enum mmap_types { + PIO_BUFS = 1, + PIO_BUFS_SOP, + PIO_CRED, + RCV_HDRQ, + RCV_EGRBUF, + UREGS, + EVENTS, + STATUS, + RTAIL, + SUBCTXT_UREGS, + SUBCTXT_RCV_HDRQ, + SUBCTXT_EGRBUF, + SDMA_COMP +}; + +/* + * Masks and offsets defining the mmap tokens + */ +#define HFI1_MMAP_OFFSET_MASK 0xfffULL +#define HFI1_MMAP_OFFSET_SHIFT 0 +#define HFI1_MMAP_SUBCTXT_MASK 0xfULL +#define HFI1_MMAP_SUBCTXT_SHIFT 12 +#define HFI1_MMAP_CTXT_MASK 0xffULL +#define HFI1_MMAP_CTXT_SHIFT 16 +#define HFI1_MMAP_TYPE_MASK 0xfULL +#define HFI1_MMAP_TYPE_SHIFT 24 +#define HFI1_MMAP_MAGIC_MASK 0xffffffffULL +#define HFI1_MMAP_MAGIC_SHIFT 32 + +#define HFI1_MMAP_MAGIC 0xdabbad00 + +#define HFI1_MMAP_TOKEN_SET(field, val) \ + (((val) & HFI1_MMAP_##field##_MASK) << HFI1_MMAP_##field##_SHIFT) +#define HFI1_MMAP_TOKEN_GET(field, token) \ + (((token) >> HFI1_MMAP_##field##_SHIFT) & HFI1_MMAP_##field##_MASK) +#define HFI1_MMAP_TOKEN(type, ctxt, subctxt, addr) \ + (HFI1_MMAP_TOKEN_SET(MAGIC, HFI1_MMAP_MAGIC) | \ + HFI1_MMAP_TOKEN_SET(TYPE, type) | \ + HFI1_MMAP_TOKEN_SET(CTXT, ctxt) | \ + HFI1_MMAP_TOKEN_SET(SUBCTXT, subctxt) | \ + HFI1_MMAP_TOKEN_SET(OFFSET, ((unsigned long)addr & ~PAGE_MASK))) + +#define EXP_TID_SET(field, value) \ + (((value) & EXP_TID_TID##field##_MASK) << \ + EXP_TID_TID##field##_SHIFT) +#define EXP_TID_CLEAR(tid, field) { \ + (tid) &= ~(EXP_TID_TID##field##_MASK << \ + EXP_TID_TID##field##_SHIFT); \ + } +#define EXP_TID_RESET(tid, field, value) do { \ + EXP_TID_CLEAR(tid, field); \ + (tid) |= EXP_TID_SET(field, value); \ + } while (0) + +#define dbg(fmt, ...) \ + pr_info(fmt, ##__VA_ARGS__) + + +static inline int is_valid_mmap(u64 token) +{ + return (HFI1_MMAP_TOKEN_GET(MAGIC, token) == HFI1_MMAP_MAGIC); +} + +static int hfi1_file_open(struct inode *inode, struct file *fp) +{ + /* The real work is performed later in assign_ctxt() */ + fp->private_data = kzalloc(sizeof(struct hfi1_filedata), GFP_KERNEL); + if (fp->private_data) /* no cpu affinity by default */ + ((struct hfi1_filedata *)fp->private_data)->rec_cpu_num = -1; + return fp->private_data ? 0 : -ENOMEM; +} + +static ssize_t hfi1_file_write(struct file *fp, const char __user *data, + size_t count, loff_t *offset) +{ + const struct hfi1_cmd __user *ucmd; + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_cmd cmd; + struct hfi1_user_info uinfo; + struct hfi1_tid_info tinfo; + ssize_t consumed = 0, copy = 0, ret = 0; + void *dest = NULL; + __u64 user_val = 0; + int uctxt_required = 1; + int must_be_root = 0; + + if (count < sizeof(cmd)) { + ret = -EINVAL; + goto bail; + } + + ucmd = (const struct hfi1_cmd __user *)data; + if (copy_from_user(&cmd, ucmd, sizeof(cmd))) { + ret = -EFAULT; + goto bail; + } + + consumed = sizeof(cmd); + + switch (cmd.type) { + case HFI1_CMD_ASSIGN_CTXT: + uctxt_required = 0; /* assigned user context not required */ + copy = sizeof(uinfo); + dest = &uinfo; + break; + case HFI1_CMD_SDMA_STATUS_UPD: + case HFI1_CMD_CREDIT_UPD: + copy = 0; + break; + case HFI1_CMD_TID_UPDATE: + case HFI1_CMD_TID_FREE: + copy = sizeof(tinfo); + dest = &tinfo; + break; + case HFI1_CMD_USER_INFO: + case HFI1_CMD_RECV_CTRL: + case HFI1_CMD_POLL_TYPE: + case HFI1_CMD_ACK_EVENT: + case HFI1_CMD_CTXT_INFO: + case HFI1_CMD_SET_PKEY: + case HFI1_CMD_CTXT_RESET: + copy = 0; + user_val = cmd.addr; + break; + case HFI1_CMD_EP_INFO: + case HFI1_CMD_EP_ERASE_CHIP: + case HFI1_CMD_EP_ERASE_P0: + case HFI1_CMD_EP_ERASE_P1: + case HFI1_CMD_EP_READ_P0: + case HFI1_CMD_EP_READ_P1: + case HFI1_CMD_EP_WRITE_P0: + case HFI1_CMD_EP_WRITE_P1: + uctxt_required = 0; /* assigned user context not required */ + must_be_root = 1; /* validate user */ + copy = 0; + break; + default: + ret = -EINVAL; + goto bail; + } + + /* If the command comes with user data, copy it. */ + if (copy) { + if (copy_from_user(dest, (void __user *)cmd.addr, copy)) { + ret = -EFAULT; + goto bail; + } + consumed += copy; + } + + /* + * Make sure there is a uctxt when needed. + */ + if (uctxt_required && !uctxt) { + ret = -EINVAL; + goto bail; + } + + /* only root can do these operations */ + if (must_be_root && !capable(CAP_SYS_ADMIN)) { + ret = -EPERM; + goto bail; + } + + switch (cmd.type) { + case HFI1_CMD_ASSIGN_CTXT: + ret = assign_ctxt(fp, &uinfo); + if (ret < 0) + goto bail; + ret = setup_ctxt(fp); + if (ret) + goto bail; + ret = user_init(fp); + break; + case HFI1_CMD_CTXT_INFO: + ret = get_ctxt_info(fp, (void __user *)(unsigned long) + user_val, cmd.len); + break; + case HFI1_CMD_USER_INFO: + ret = get_base_info(fp, (void __user *)(unsigned long) + user_val, cmd.len); + break; + case HFI1_CMD_SDMA_STATUS_UPD: + break; + case HFI1_CMD_CREDIT_UPD: + if (uctxt && uctxt->sc) + sc_return_credits(uctxt->sc); + break; + case HFI1_CMD_TID_UPDATE: + ret = exp_tid_setup(fp, &tinfo); + if (!ret) { + unsigned long addr; + /* + * Copy the number of tidlist entries we used + * and the length of the buffer we registered. + * These fields are adjacent in the structure so + * we can copy them at the same time. + */ + addr = (unsigned long)cmd.addr + + offsetof(struct hfi1_tid_info, tidcnt); + if (copy_to_user((void __user *)addr, &tinfo.tidcnt, + sizeof(tinfo.tidcnt) + + sizeof(tinfo.length))) + ret = -EFAULT; + } + break; + case HFI1_CMD_TID_FREE: + ret = exp_tid_free(fp, &tinfo); + break; + case HFI1_CMD_RECV_CTRL: + ret = manage_rcvq(uctxt, subctxt_fp(fp), (int)user_val); + break; + case HFI1_CMD_POLL_TYPE: + uctxt->poll_type = (typeof(uctxt->poll_type))user_val; + break; + case HFI1_CMD_ACK_EVENT: + ret = user_event_ack(uctxt, subctxt_fp(fp), user_val); + break; + case HFI1_CMD_SET_PKEY: + if (HFI1_CAP_IS_USET(PKEY_CHECK)) + ret = set_ctxt_pkey(uctxt, subctxt_fp(fp), user_val); + else + ret = -EPERM; + break; + case HFI1_CMD_CTXT_RESET: { + struct send_context *sc; + struct hfi1_devdata *dd; + + if (!uctxt || !uctxt->dd || !uctxt->sc) { + ret = -EINVAL; + break; + } + /* + * There is no protection here. User level has to + * guarantee that no one will be writing to the send + * context while it is being re-initialized. + * If user level breaks that guarantee, it will break + * it's own context and no one else's. + */ + dd = uctxt->dd; + sc = uctxt->sc; + /* + * Wait until the interrupt handler has marked the + * context as halted or frozen. Report error if we time + * out. + */ + wait_event_interruptible_timeout( + sc->halt_wait, (sc->flags & SCF_HALTED), + msecs_to_jiffies(SEND_CTXT_HALT_TIMEOUT)); + if (!(sc->flags & SCF_HALTED)) { + ret = -ENOLCK; + break; + } + /* + * If the send context was halted due to a Freeze, + * wait until the device has been "unfrozen" before + * resetting the context. + */ + if (sc->flags & SCF_FROZEN) { + wait_event_interruptible_timeout( + dd->event_queue, + !(ACCESS_ONCE(dd->flags) & HFI1_FROZEN), + msecs_to_jiffies(SEND_CTXT_HALT_TIMEOUT)); + if (dd->flags & HFI1_FROZEN) { + ret = -ENOLCK; + break; + } + if (dd->flags & HFI1_FORCED_FREEZE) { + /* Don't allow context reset if we are into + * forced freeze */ + ret = -ENODEV; + break; + } + sc_disable(sc); + ret = sc_enable(sc); + hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_ENB, + uctxt->ctxt); + } else + ret = sc_restart(sc); + if (!ret) + sc_return_credits(sc); + break; + } + case HFI1_CMD_EP_INFO: + case HFI1_CMD_EP_ERASE_CHIP: + case HFI1_CMD_EP_ERASE_P0: + case HFI1_CMD_EP_ERASE_P1: + case HFI1_CMD_EP_READ_P0: + case HFI1_CMD_EP_READ_P1: + case HFI1_CMD_EP_WRITE_P0: + case HFI1_CMD_EP_WRITE_P1: + ret = handle_eprom_command(&cmd); + break; + } + + if (ret >= 0) + ret = consumed; +bail: + return ret; +} + +static ssize_t hfi1_write_iter(struct kiocb *kiocb, struct iov_iter *from) +{ + struct hfi1_user_sdma_pkt_q *pq; + struct hfi1_user_sdma_comp_q *cq; + int ret = 0, done = 0, reqs = 0; + unsigned long dim = from->nr_segs; + + if (!user_sdma_comp_fp(kiocb->ki_filp) || + !user_sdma_pkt_fp(kiocb->ki_filp)) { + ret = -EIO; + goto done; + } + + if (!iter_is_iovec(from) || !dim) { + ret = -EINVAL; + goto done; + } + + hfi1_cdbg(SDMA, "SDMA request from %u:%u (%lu)", + ctxt_fp(kiocb->ki_filp)->ctxt, subctxt_fp(kiocb->ki_filp), + dim); + pq = user_sdma_pkt_fp(kiocb->ki_filp); + cq = user_sdma_comp_fp(kiocb->ki_filp); + + if (atomic_read(&pq->n_reqs) == pq->n_max_reqs) { + ret = -ENOSPC; + goto done; + } + + while (dim) { + unsigned long count = 0; + + ret = hfi1_user_sdma_process_request( + kiocb->ki_filp, (struct iovec *)(from->iov + done), + dim, &count); + if (ret) + goto done; + dim -= count; + done += count; + reqs++; + } +done: + return ret ? ret : reqs; +} + +static int hfi1_file_mmap(struct file *fp, struct vm_area_struct *vma) +{ + struct hfi1_ctxtdata *uctxt; + struct hfi1_devdata *dd; + unsigned long flags, pfn; + u64 token = vma->vm_pgoff << PAGE_SHIFT, + memaddr = 0; + u8 subctxt, mapio = 0, vmf = 0, type; + ssize_t memlen = 0; + int ret = 0; + u16 ctxt; + + uctxt = ctxt_fp(fp); + if (!is_valid_mmap(token) || !uctxt || + !(vma->vm_flags & VM_SHARED)) { + ret = -EINVAL; + goto done; + } + dd = uctxt->dd; + ctxt = HFI1_MMAP_TOKEN_GET(CTXT, token); + subctxt = HFI1_MMAP_TOKEN_GET(SUBCTXT, token); + type = HFI1_MMAP_TOKEN_GET(TYPE, token); + if (ctxt != uctxt->ctxt || subctxt != subctxt_fp(fp)) { + ret = -EINVAL; + goto done; + } + + flags = vma->vm_flags; + + switch (type) { + case PIO_BUFS: + case PIO_BUFS_SOP: + memaddr = ((dd->physaddr + TXE_PIO_SEND) + + /* chip pio base */ + (uctxt->sc->hw_context * (1 << 16))) + + /* 64K PIO space / ctxt */ + (type == PIO_BUFS_SOP ? + (TXE_PIO_SIZE / 2) : 0); /* sop? */ + /* + * Map only the amount allocated to the context, not the + * entire available context's PIO space. + */ + memlen = ALIGN(uctxt->sc->credits * PIO_BLOCK_SIZE, + PAGE_SIZE); + flags &= ~VM_MAYREAD; + flags |= VM_DONTCOPY | VM_DONTEXPAND; + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + mapio = 1; + break; + case PIO_CRED: + if (flags & VM_WRITE) { + ret = -EPERM; + goto done; + } + /* + * The credit return location for this context could be on the + * second or third page allocated for credit returns (if number + * of enabled contexts > 64 and 128 respectively). + */ + memaddr = dd->cr_base[uctxt->numa_id].pa + + (((u64)uctxt->sc->hw_free - + (u64)dd->cr_base[uctxt->numa_id].va) & PAGE_MASK); + memlen = PAGE_SIZE; + flags &= ~VM_MAYWRITE; + flags |= VM_DONTCOPY | VM_DONTEXPAND; + /* + * The driver has already allocated memory for credit + * returns and programmed it into the chip. Has that + * memory been flagged as non-cached? + */ + /* vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); */ + mapio = 1; + break; + case RCV_HDRQ: + memaddr = uctxt->rcvhdrq_phys; + memlen = uctxt->rcvhdrq_size; + break; + case RCV_EGRBUF: { + unsigned long addr; + int i; + /* + * The RcvEgr buffer need to be handled differently + * as multiple non-contiguous pages need to be mapped + * into the user process. + */ + memlen = uctxt->egrbufs.size; + if ((vma->vm_end - vma->vm_start) != memlen) { + dd_dev_err(dd, "Eager buffer map size invalid (%lu != %lu)\n", + (vma->vm_end - vma->vm_start), memlen); + ret = -EINVAL; + goto done; + } + if (vma->vm_flags & VM_WRITE) { + ret = -EPERM; + goto done; + } + vma->vm_flags &= ~VM_MAYWRITE; + addr = vma->vm_start; + for (i = 0 ; i < uctxt->egrbufs.numbufs; i++) { + ret = remap_pfn_range( + vma, addr, + uctxt->egrbufs.buffers[i].phys >> PAGE_SHIFT, + uctxt->egrbufs.buffers[i].len, + vma->vm_page_prot); + if (ret < 0) + goto done; + addr += uctxt->egrbufs.buffers[i].len; + } + ret = 0; + goto done; + } + case UREGS: + /* + * Map only the page that contains this context's user + * registers. + */ + memaddr = (unsigned long) + (dd->physaddr + RXE_PER_CONTEXT_USER) + + (uctxt->ctxt * RXE_PER_CONTEXT_SIZE); + /* + * TidFlow table is on the same page as the rest of the + * user registers. + */ + memlen = PAGE_SIZE; + flags |= VM_DONTCOPY | VM_DONTEXPAND; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + mapio = 1; + break; + case EVENTS: + /* + * Use the page where this context's flags are. User level + * knows where it's own bitmap is within the page. + */ + memaddr = ((unsigned long)dd->events + + ((uctxt->ctxt - dd->first_user_ctxt) * + HFI1_MAX_SHARED_CTXTS)) & PAGE_MASK; + memlen = PAGE_SIZE; + /* + * v3.7 removes VM_RESERVED but the effect is kept by + * using VM_IO. + */ + flags |= VM_IO | VM_DONTEXPAND; + vmf = 1; + break; + case STATUS: + memaddr = kvirt_to_phys((void *)dd->status); + memlen = PAGE_SIZE; + flags |= VM_IO | VM_DONTEXPAND; + break; + case RTAIL: + if (!HFI1_CAP_IS_USET(DMA_RTAIL)) { + /* + * If the memory allocation failed, the context alloc + * also would have failed, so we would never get here + */ + ret = -EINVAL; + goto done; + } + if (flags & VM_WRITE) { + ret = -EPERM; + goto done; + } + memaddr = uctxt->rcvhdrqtailaddr_phys; + memlen = PAGE_SIZE; + flags &= ~VM_MAYWRITE; + break; + case SUBCTXT_UREGS: + memaddr = (u64)uctxt->subctxt_uregbase; + memlen = PAGE_SIZE; + flags |= VM_IO | VM_DONTEXPAND; + vmf = 1; + break; + case SUBCTXT_RCV_HDRQ: + memaddr = (u64)uctxt->subctxt_rcvhdr_base; + memlen = uctxt->rcvhdrq_size * uctxt->subctxt_cnt; + flags |= VM_IO | VM_DONTEXPAND; + vmf = 1; + break; + case SUBCTXT_EGRBUF: + memaddr = (u64)uctxt->subctxt_rcvegrbuf; + memlen = uctxt->egrbufs.size * uctxt->subctxt_cnt; + flags |= VM_IO | VM_DONTEXPAND; + flags &= ~VM_MAYWRITE; + vmf = 1; + break; + case SDMA_COMP: { + struct hfi1_user_sdma_comp_q *cq; + + if (!user_sdma_comp_fp(fp)) { + ret = -EFAULT; + goto done; + } + cq = user_sdma_comp_fp(fp); + memaddr = (u64)cq->comps; + memlen = ALIGN(sizeof(*cq->comps) * cq->nentries, PAGE_SIZE); + flags |= VM_IO | VM_DONTEXPAND; + vmf = 1; + break; + } + default: + ret = -EINVAL; + break; + } + + if ((vma->vm_end - vma->vm_start) != memlen) { + hfi1_cdbg(PROC, "%u:%u Memory size mismatch %lu:%lu", + uctxt->ctxt, subctxt_fp(fp), + (vma->vm_end - vma->vm_start), memlen); + ret = -EINVAL; + goto done; + } + + vma->vm_flags = flags; + dd_dev_info(dd, + "%s: %u:%u type:%u io/vf:%d/%d, addr:0x%llx, len:%lu(%lu), flags:0x%lx\n", + __func__, ctxt, subctxt, type, mapio, vmf, memaddr, memlen, + vma->vm_end - vma->vm_start, vma->vm_flags); + pfn = (unsigned long)(memaddr >> PAGE_SHIFT); + if (vmf) { + vma->vm_pgoff = pfn; + vma->vm_ops = &vm_ops; + ret = 0; + } else if (mapio) { + ret = io_remap_pfn_range(vma, vma->vm_start, pfn, memlen, + vma->vm_page_prot); + } else { + ret = remap_pfn_range(vma, vma->vm_start, pfn, memlen, + vma->vm_page_prot); + } +done: + return ret; +} + +/* + * Local (non-chip) user memory is not mapped right away but as it is + * accessed by the user-level code. + */ +static int vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + struct page *page; + + page = vmalloc_to_page((void *)(vmf->pgoff << PAGE_SHIFT)); + if (!page) + return VM_FAULT_SIGBUS; + + get_page(page); + vmf->page = page; + + return 0; +} + +static unsigned int hfi1_poll(struct file *fp, struct poll_table_struct *pt) +{ + struct hfi1_ctxtdata *uctxt; + unsigned pollflag; + + uctxt = ctxt_fp(fp); + if (!uctxt) + pollflag = POLLERR; + else if (uctxt->poll_type == HFI1_POLL_TYPE_URGENT) + pollflag = poll_urgent(fp, pt); + else if (uctxt->poll_type == HFI1_POLL_TYPE_ANYRCV) + pollflag = poll_next(fp, pt); + else /* invalid */ + pollflag = POLLERR; + + return pollflag; +} + +static int hfi1_file_close(struct inode *inode, struct file *fp) +{ + struct hfi1_filedata *fdata = fp->private_data; + struct hfi1_ctxtdata *uctxt = fdata->uctxt; + struct hfi1_devdata *dd; + unsigned long flags, *ev; + + fp->private_data = NULL; + + if (!uctxt) + goto done; + + hfi1_cdbg(PROC, "freeing ctxt %u:%u", uctxt->ctxt, fdata->subctxt); + dd = uctxt->dd; + mutex_lock(&hfi1_mutex); + + flush_wc(); + /* drain user sdma queue */ + if (fdata->pq) + hfi1_user_sdma_free_queues(fdata); + + /* + * Clear any left over, unhandled events so the next process that + * gets this context doesn't get confused. + */ + ev = dd->events + ((uctxt->ctxt - dd->first_user_ctxt) * + HFI1_MAX_SHARED_CTXTS) + fdata->subctxt; + *ev = 0; + + if (--uctxt->cnt) { + uctxt->active_slaves &= ~(1 << fdata->subctxt); + uctxt->subpid[fdata->subctxt] = 0; + mutex_unlock(&hfi1_mutex); + goto done; + } + + spin_lock_irqsave(&dd->uctxt_lock, flags); + /* + * Disable receive context and interrupt available, reset all + * RcvCtxtCtrl bits to default values. + */ + hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_DIS | + HFI1_RCVCTRL_TIDFLOW_DIS | + HFI1_RCVCTRL_INTRAVAIL_DIS | + HFI1_RCVCTRL_ONE_PKT_EGR_DIS | + HFI1_RCVCTRL_NO_RHQ_DROP_DIS | + HFI1_RCVCTRL_NO_EGR_DROP_DIS, uctxt->ctxt); + /* Clear the context's J_KEY */ + hfi1_clear_ctxt_jkey(dd, uctxt->ctxt); + /* + * Reset context integrity checks to default. + * (writes to CSRs probably belong in chip.c) + */ + write_kctxt_csr(dd, uctxt->sc->hw_context, SEND_CTXT_CHECK_ENABLE, + hfi1_pkt_default_send_ctxt_mask(dd, uctxt->sc->type)); + sc_disable(uctxt->sc); + uctxt->pid = 0; + spin_unlock_irqrestore(&dd->uctxt_lock, flags); + + dd->rcd[uctxt->ctxt] = NULL; + uctxt->rcvwait_to = 0; + uctxt->piowait_to = 0; + uctxt->rcvnowait = 0; + uctxt->pionowait = 0; + uctxt->event_flags = 0; + + hfi1_clear_tids(uctxt); + hfi1_clear_ctxt_pkey(dd, uctxt->ctxt); + + if (uctxt->tid_pg_list) + unlock_exp_tids(uctxt); + + hfi1_stats.sps_ctxts--; + dd->freectxts++; + mutex_unlock(&hfi1_mutex); + hfi1_free_ctxtdata(dd, uctxt); +done: + kfree(fdata); + return 0; +} + +/* + * Convert kernel *virtual* addresses to physical addresses. + * This is used to vmalloc'ed addresses. + */ +static u64 kvirt_to_phys(void *addr) +{ + struct page *page; + u64 paddr = 0; + + page = vmalloc_to_page(addr); + if (page) + paddr = page_to_pfn(page) << PAGE_SHIFT; + + return paddr; +} + +static int assign_ctxt(struct file *fp, struct hfi1_user_info *uinfo) +{ + int i_minor, ret = 0; + unsigned swmajor, swminor, alg = HFI1_ALG_ACROSS; + + swmajor = uinfo->userversion >> 16; + if (swmajor != HFI1_USER_SWMAJOR) { + ret = -ENODEV; + goto done; + } + + swminor = uinfo->userversion & 0xffff; + + if (uinfo->hfi1_alg < HFI1_ALG_COUNT) + alg = uinfo->hfi1_alg; + + mutex_lock(&hfi1_mutex); + /* First, lets check if we need to setup a shared context? */ + if (uinfo->subctxt_cnt) + ret = find_shared_ctxt(fp, uinfo); + + /* + * We execute the following block if we couldn't find a + * shared context or if context sharing is not required. + */ + if (!ret) { + i_minor = iminor(file_inode(fp)) - HFI1_USER_MINOR_BASE; + ret = get_user_context(fp, uinfo, i_minor - 1, alg); + } + mutex_unlock(&hfi1_mutex); +done: + return ret; +} + +static int get_user_context(struct file *fp, struct hfi1_user_info *uinfo, + int devno, unsigned alg) +{ + struct hfi1_devdata *dd = NULL; + int ret = 0, devmax, npresent, nup, dev; + + devmax = hfi1_count_units(&npresent, &nup); + if (!npresent) { + ret = -ENXIO; + goto done; + } + if (!nup) { + ret = -ENETDOWN; + goto done; + } + if (devno >= 0) { + dd = hfi1_lookup(devno); + if (!dd) + ret = -ENODEV; + else if (!dd->freectxts) + ret = -EBUSY; + } else { + struct hfi1_devdata *pdd; + + if (alg == HFI1_ALG_ACROSS) { + unsigned free = 0U; + + for (dev = 0; dev < devmax; dev++) { + pdd = hfi1_lookup(dev); + if (pdd && pdd->freectxts && + pdd->freectxts > free) { + dd = pdd; + free = pdd->freectxts; + } + } + } else { + for (dev = 0; dev < devmax; dev++) { + pdd = hfi1_lookup(dev); + if (pdd && pdd->freectxts) { + dd = pdd; + break; + } + } + } + if (!dd) + ret = -EBUSY; + } +done: + return ret ? ret : allocate_ctxt(fp, dd, uinfo); +} + +static int find_shared_ctxt(struct file *fp, + const struct hfi1_user_info *uinfo) +{ + int devmax, ndev, i; + int ret = 0; + + devmax = hfi1_count_units(NULL, NULL); + + for (ndev = 0; ndev < devmax; ndev++) { + struct hfi1_devdata *dd = hfi1_lookup(ndev); + + /* device portion of usable() */ + if (!(dd && (dd->flags & HFI1_PRESENT) && dd->kregbase)) + continue; + for (i = dd->first_user_ctxt; i < dd->num_rcv_contexts; i++) { + struct hfi1_ctxtdata *uctxt = dd->rcd[i]; + + /* Skip ctxts which are not yet open */ + if (!uctxt || !uctxt->cnt) + continue; + /* Skip ctxt if it doesn't match the requested one */ + if (memcmp(uctxt->uuid, uinfo->uuid, + sizeof(uctxt->uuid)) || + uctxt->subctxt_id != uinfo->subctxt_id || + uctxt->subctxt_cnt != uinfo->subctxt_cnt) + continue; + + /* Verify the sharing process matches the master */ + if (uctxt->userversion != uinfo->userversion || + uctxt->cnt >= uctxt->subctxt_cnt) { + ret = -EINVAL; + goto done; + } + ctxt_fp(fp) = uctxt; + subctxt_fp(fp) = uctxt->cnt++; + uctxt->subpid[subctxt_fp(fp)] = current->pid; + uctxt->active_slaves |= 1 << subctxt_fp(fp); + ret = 1; + goto done; + } + } + +done: + return ret; +} + +static int allocate_ctxt(struct file *fp, struct hfi1_devdata *dd, + struct hfi1_user_info *uinfo) +{ + struct hfi1_ctxtdata *uctxt; + unsigned ctxt; + int ret; + + if (dd->flags & HFI1_FROZEN) { + /* + * Pick an error that is unique from all other errors + * that are returned so the user process knows that + * it tried to allocate while the SPC was frozen. It + * it should be able to retry with success in a short + * while. + */ + return -EIO; + } + + for (ctxt = dd->first_user_ctxt; ctxt < dd->num_rcv_contexts; ctxt++) + if (!dd->rcd[ctxt]) + break; + + if (ctxt == dd->num_rcv_contexts) + return -EBUSY; + + uctxt = hfi1_create_ctxtdata(dd->pport, ctxt); + if (!uctxt) { + dd_dev_err(dd, + "Unable to allocate ctxtdata memory, failing open\n"); + return -ENOMEM; + } + /* + * Allocate and enable a PIO send context. + */ + uctxt->sc = sc_alloc(dd, SC_USER, uctxt->rcvhdrqentsize, + uctxt->numa_id); + if (!uctxt->sc) + return -ENOMEM; + + dbg("allocated send context %u(%u)\n", uctxt->sc->sw_index, + uctxt->sc->hw_context); + ret = sc_enable(uctxt->sc); + if (ret) + return ret; + /* + * Setup shared context resources if the user-level has requested + * shared contexts and this is the 'master' process. + * This has to be done here so the rest of the sub-contexts find the + * proper master. + */ + if (uinfo->subctxt_cnt && !subctxt_fp(fp)) { + ret = init_subctxts(uctxt, uinfo); + /* + * On error, we don't need to disable and de-allocate the + * send context because it will be done during file close + */ + if (ret) + return ret; + } + uctxt->userversion = uinfo->userversion; + uctxt->pid = current->pid; + uctxt->flags = HFI1_CAP_UGET(MASK); + init_waitqueue_head(&uctxt->wait); + strlcpy(uctxt->comm, current->comm, sizeof(uctxt->comm)); + memcpy(uctxt->uuid, uinfo->uuid, sizeof(uctxt->uuid)); + uctxt->jkey = generate_jkey(current_uid()); + INIT_LIST_HEAD(&uctxt->sdma_queues); + spin_lock_init(&uctxt->sdma_qlock); + hfi1_stats.sps_ctxts++; + dd->freectxts--; + ctxt_fp(fp) = uctxt; + + return 0; +} + +static int init_subctxts(struct hfi1_ctxtdata *uctxt, + const struct hfi1_user_info *uinfo) +{ + int ret = 0; + unsigned num_subctxts; + + num_subctxts = uinfo->subctxt_cnt; + if (num_subctxts > HFI1_MAX_SHARED_CTXTS) { + ret = -EINVAL; + goto bail; + } + + uctxt->subctxt_cnt = uinfo->subctxt_cnt; + uctxt->subctxt_id = uinfo->subctxt_id; + uctxt->active_slaves = 1; + uctxt->redirect_seq_cnt = 1; + set_bit(HFI1_CTXT_MASTER_UNINIT, &uctxt->event_flags); +bail: + return ret; +} + +static int setup_subctxt(struct hfi1_ctxtdata *uctxt) +{ + int ret = 0; + unsigned num_subctxts = uctxt->subctxt_cnt; + + uctxt->subctxt_uregbase = vmalloc_user(PAGE_SIZE); + if (!uctxt->subctxt_uregbase) { + ret = -ENOMEM; + goto bail; + } + /* We can take the size of the RcvHdr Queue from the master */ + uctxt->subctxt_rcvhdr_base = vmalloc_user(uctxt->rcvhdrq_size * + num_subctxts); + if (!uctxt->subctxt_rcvhdr_base) { + ret = -ENOMEM; + goto bail_ureg; + } + + uctxt->subctxt_rcvegrbuf = vmalloc_user(uctxt->egrbufs.size * + num_subctxts); + if (!uctxt->subctxt_rcvegrbuf) { + ret = -ENOMEM; + goto bail_rhdr; + } + goto bail; +bail_rhdr: + vfree(uctxt->subctxt_rcvhdr_base); +bail_ureg: + vfree(uctxt->subctxt_uregbase); + uctxt->subctxt_uregbase = NULL; +bail: + return ret; +} + +static int user_init(struct file *fp) +{ + int ret; + unsigned int rcvctrl_ops = 0; + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + + /* make sure that the context has already been setup */ + if (!test_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags)) { + ret = -EFAULT; + goto done; + } + + /* + * Subctxts don't need to initialize anything since master + * has done it. + */ + if (subctxt_fp(fp)) { + ret = wait_event_interruptible(uctxt->wait, + !test_bit(HFI1_CTXT_MASTER_UNINIT, + &uctxt->event_flags)); + goto done; + } + + /* initialize poll variables... */ + uctxt->urgent = 0; + uctxt->urgent_poll = 0; + + /* + * Now enable the ctxt for receive. + * For chips that are set to DMA the tail register to memory + * when they change (and when the update bit transitions from + * 0 to 1. So for those chips, we turn it off and then back on. + * This will (very briefly) affect any other open ctxts, but the + * duration is very short, and therefore isn't an issue. We + * explicitly set the in-memory tail copy to 0 beforehand, so we + * don't have to wait to be sure the DMA update has happened + * (chip resets head/tail to 0 on transition to enable). + */ + if (uctxt->rcvhdrtail_kvaddr) + clear_rcvhdrtail(uctxt); + + /* Setup J_KEY before enabling the context */ + hfi1_set_ctxt_jkey(uctxt->dd, uctxt->ctxt, uctxt->jkey); + + rcvctrl_ops = HFI1_RCVCTRL_CTXT_ENB; + if (HFI1_CAP_KGET_MASK(uctxt->flags, HDRSUPP)) + rcvctrl_ops |= HFI1_RCVCTRL_TIDFLOW_ENB; + /* + * Ignore the bit in the flags for now until proper + * support for multiple packet per rcv array entry is + * added. + */ + if (!HFI1_CAP_KGET_MASK(uctxt->flags, MULTI_PKT_EGR)) + rcvctrl_ops |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB; + if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_EGR_FULL)) + rcvctrl_ops |= HFI1_RCVCTRL_NO_EGR_DROP_ENB; + if (HFI1_CAP_KGET_MASK(uctxt->flags, NODROP_RHQ_FULL)) + rcvctrl_ops |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB; + if (HFI1_CAP_KGET_MASK(uctxt->flags, DMA_RTAIL)) + rcvctrl_ops |= HFI1_RCVCTRL_TAILUPD_ENB; + hfi1_rcvctrl(uctxt->dd, rcvctrl_ops, uctxt->ctxt); + + /* Notify any waiting slaves */ + if (uctxt->subctxt_cnt) { + clear_bit(HFI1_CTXT_MASTER_UNINIT, &uctxt->event_flags); + wake_up(&uctxt->wait); + } + ret = 0; + +done: + return ret; +} + +static int get_ctxt_info(struct file *fp, void __user *ubase, __u32 len) +{ + struct hfi1_ctxt_info cinfo; + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_filedata *fd = fp->private_data; + int ret = 0; + + ret = hfi1_get_base_kinfo(uctxt, &cinfo); + if (ret < 0) + goto done; + cinfo.num_active = hfi1_count_active_units(); + cinfo.unit = uctxt->dd->unit; + cinfo.ctxt = uctxt->ctxt; + cinfo.subctxt = subctxt_fp(fp); + cinfo.rcvtids = roundup(uctxt->egrbufs.alloced, + uctxt->dd->rcv_entries.group_size) + + uctxt->expected_count; + cinfo.credits = uctxt->sc->credits; + cinfo.numa_node = uctxt->numa_id; + cinfo.rec_cpu = fd->rec_cpu_num; + cinfo.send_ctxt = uctxt->sc->hw_context; + + cinfo.egrtids = uctxt->egrbufs.alloced; + cinfo.rcvhdrq_cnt = uctxt->rcvhdrq_cnt; + cinfo.rcvhdrq_entsize = uctxt->rcvhdrqentsize << 2; + cinfo.sdma_ring_size = user_sdma_comp_fp(fp)->nentries; + cinfo.rcvegr_size = uctxt->egrbufs.rcvtid_size; + + trace_hfi1_ctxt_info(uctxt->dd, uctxt->ctxt, subctxt_fp(fp), cinfo); + if (copy_to_user(ubase, &cinfo, sizeof(cinfo))) + ret = -EFAULT; +done: + return ret; +} + +static int setup_ctxt(struct file *fp) +{ + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_devdata *dd = uctxt->dd; + int ret = 0; + + /* + * Context should be set up only once (including allocation and + * programming of eager buffers. This is done if context sharing + * is not requested or by the master process. + */ + if (!uctxt->subctxt_cnt || !subctxt_fp(fp)) { + ret = hfi1_init_ctxt(uctxt->sc); + if (ret) + goto done; + + /* Now allocate the RcvHdr queue and eager buffers. */ + ret = hfi1_create_rcvhdrq(dd, uctxt); + if (ret) + goto done; + ret = hfi1_setup_eagerbufs(uctxt); + if (ret) + goto done; + if (uctxt->subctxt_cnt && !subctxt_fp(fp)) { + ret = setup_subctxt(uctxt); + if (ret) + goto done; + } + /* Setup Expected Rcv memories */ + uctxt->tid_pg_list = vzalloc(uctxt->expected_count * + sizeof(struct page **)); + if (!uctxt->tid_pg_list) { + ret = -ENOMEM; + goto done; + } + uctxt->physshadow = vzalloc(uctxt->expected_count * + sizeof(*uctxt->physshadow)); + if (!uctxt->physshadow) { + ret = -ENOMEM; + goto done; + } + /* allocate expected TID map and initialize the cursor */ + atomic_set(&uctxt->tidcursor, 0); + uctxt->numtidgroups = uctxt->expected_count / + dd->rcv_entries.group_size; + uctxt->tidmapcnt = uctxt->numtidgroups / BITS_PER_LONG + + !!(uctxt->numtidgroups % BITS_PER_LONG); + uctxt->tidusemap = kzalloc_node(uctxt->tidmapcnt * + sizeof(*uctxt->tidusemap), + GFP_KERNEL, uctxt->numa_id); + if (!uctxt->tidusemap) { + ret = -ENOMEM; + goto done; + } + /* + * In case that the number of groups is not a multiple of + * 64 (the number of groups in a tidusemap element), mark + * the extra ones as used. This will effectively make them + * permanently used and should never be assigned. Otherwise, + * the code which checks how many free groups we have will + * get completely confused about the state of the bits. + */ + if (uctxt->numtidgroups % BITS_PER_LONG) + uctxt->tidusemap[uctxt->tidmapcnt - 1] = + ~((1ULL << (uctxt->numtidgroups % + BITS_PER_LONG)) - 1); + trace_hfi1_exp_tid_map(uctxt->ctxt, subctxt_fp(fp), 0, + uctxt->tidusemap, uctxt->tidmapcnt); + } + ret = hfi1_user_sdma_alloc_queues(uctxt, fp); + if (ret) + goto done; + + set_bit(HFI1_CTXT_SETUP_DONE, &uctxt->event_flags); +done: + return ret; +} + +static int get_base_info(struct file *fp, void __user *ubase, __u32 len) +{ + struct hfi1_base_info binfo; + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_devdata *dd = uctxt->dd; + ssize_t sz; + unsigned offset; + int ret = 0; + + trace_hfi1_uctxtdata(uctxt->dd, uctxt); + + memset(&binfo, 0, sizeof(binfo)); + binfo.hw_version = dd->revision; + binfo.sw_version = HFI1_KERN_SWVERSION; + binfo.bthqp = kdeth_qp; + binfo.jkey = uctxt->jkey; + /* + * If more than 64 contexts are enabled the allocated credit + * return will span two or three contiguous pages. Since we only + * map the page containing the context's credit return address, + * we need to calculate the offset in the proper page. + */ + offset = ((u64)uctxt->sc->hw_free - + (u64)dd->cr_base[uctxt->numa_id].va) % PAGE_SIZE; + binfo.sc_credits_addr = HFI1_MMAP_TOKEN(PIO_CRED, uctxt->ctxt, + subctxt_fp(fp), offset); + binfo.pio_bufbase = HFI1_MMAP_TOKEN(PIO_BUFS, uctxt->ctxt, + subctxt_fp(fp), + uctxt->sc->base_addr); + binfo.pio_bufbase_sop = HFI1_MMAP_TOKEN(PIO_BUFS_SOP, + uctxt->ctxt, + subctxt_fp(fp), + uctxt->sc->base_addr); + binfo.rcvhdr_bufbase = HFI1_MMAP_TOKEN(RCV_HDRQ, uctxt->ctxt, + subctxt_fp(fp), + uctxt->rcvhdrq); + binfo.rcvegr_bufbase = HFI1_MMAP_TOKEN(RCV_EGRBUF, uctxt->ctxt, + subctxt_fp(fp), + uctxt->egrbufs.rcvtids[0].phys); + binfo.sdma_comp_bufbase = HFI1_MMAP_TOKEN(SDMA_COMP, uctxt->ctxt, + subctxt_fp(fp), 0); + /* + * user regs are at + * (RXE_PER_CONTEXT_USER + (ctxt * RXE_PER_CONTEXT_SIZE)) + */ + binfo.user_regbase = HFI1_MMAP_TOKEN(UREGS, uctxt->ctxt, + subctxt_fp(fp), 0); + offset = ((((uctxt->ctxt - dd->first_user_ctxt) * + HFI1_MAX_SHARED_CTXTS) + subctxt_fp(fp)) * + sizeof(*dd->events)) & ~PAGE_MASK; + binfo.events_bufbase = HFI1_MMAP_TOKEN(EVENTS, uctxt->ctxt, + subctxt_fp(fp), + offset); + binfo.status_bufbase = HFI1_MMAP_TOKEN(STATUS, uctxt->ctxt, + subctxt_fp(fp), + dd->status); + if (HFI1_CAP_IS_USET(DMA_RTAIL)) + binfo.rcvhdrtail_base = HFI1_MMAP_TOKEN(RTAIL, uctxt->ctxt, + subctxt_fp(fp), 0); + if (uctxt->subctxt_cnt) { + binfo.subctxt_uregbase = HFI1_MMAP_TOKEN(SUBCTXT_UREGS, + uctxt->ctxt, + subctxt_fp(fp), 0); + binfo.subctxt_rcvhdrbuf = HFI1_MMAP_TOKEN(SUBCTXT_RCV_HDRQ, + uctxt->ctxt, + subctxt_fp(fp), 0); + binfo.subctxt_rcvegrbuf = HFI1_MMAP_TOKEN(SUBCTXT_EGRBUF, + uctxt->ctxt, + subctxt_fp(fp), 0); + } + sz = (len < sizeof(binfo)) ? len : sizeof(binfo); + if (copy_to_user(ubase, &binfo, sz)) + ret = -EFAULT; + return ret; +} + +static unsigned int poll_urgent(struct file *fp, + struct poll_table_struct *pt) +{ + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_devdata *dd = uctxt->dd; + unsigned pollflag; + + poll_wait(fp, &uctxt->wait, pt); + + spin_lock_irq(&dd->uctxt_lock); + if (uctxt->urgent != uctxt->urgent_poll) { + pollflag = POLLIN | POLLRDNORM; + uctxt->urgent_poll = uctxt->urgent; + } else { + pollflag = 0; + set_bit(HFI1_CTXT_WAITING_URG, &uctxt->event_flags); + } + spin_unlock_irq(&dd->uctxt_lock); + + return pollflag; +} + +static unsigned int poll_next(struct file *fp, + struct poll_table_struct *pt) +{ + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_devdata *dd = uctxt->dd; + unsigned pollflag; + + poll_wait(fp, &uctxt->wait, pt); + + spin_lock_irq(&dd->uctxt_lock); + if (hdrqempty(uctxt)) { + set_bit(HFI1_CTXT_WAITING_RCV, &uctxt->event_flags); + hfi1_rcvctrl(dd, HFI1_RCVCTRL_INTRAVAIL_ENB, uctxt->ctxt); + pollflag = 0; + } else + pollflag = POLLIN | POLLRDNORM; + spin_unlock_irq(&dd->uctxt_lock); + + return pollflag; +} + +/* + * Find all user contexts in use, and set the specified bit in their + * event mask. + * See also find_ctxt() for a similar use, that is specific to send buffers. + */ +int hfi1_set_uevent_bits(struct hfi1_pportdata *ppd, const int evtbit) +{ + struct hfi1_ctxtdata *uctxt; + struct hfi1_devdata *dd = ppd->dd; + unsigned ctxt; + int ret = 0; + unsigned long flags; + + if (!dd->events) { + ret = -EINVAL; + goto done; + } + + spin_lock_irqsave(&dd->uctxt_lock, flags); + for (ctxt = dd->first_user_ctxt; ctxt < dd->num_rcv_contexts; + ctxt++) { + uctxt = dd->rcd[ctxt]; + if (uctxt) { + unsigned long *evs = dd->events + + (uctxt->ctxt - dd->first_user_ctxt) * + HFI1_MAX_SHARED_CTXTS; + int i; + /* + * subctxt_cnt is 0 if not shared, so do base + * separately, first, then remaining subctxt, if any + */ + set_bit(evtbit, evs); + for (i = 1; i < uctxt->subctxt_cnt; i++) + set_bit(evtbit, evs + i); + } + } + spin_unlock_irqrestore(&dd->uctxt_lock, flags); +done: + return ret; +} + +/** + * manage_rcvq - manage a context's receive queue + * @uctxt: the context + * @subctxt: the sub-context + * @start_stop: action to carry out + * + * start_stop == 0 disables receive on the context, for use in queue + * overflow conditions. start_stop==1 re-enables, to be used to + * re-init the software copy of the head register + */ +static int manage_rcvq(struct hfi1_ctxtdata *uctxt, unsigned subctxt, + int start_stop) +{ + struct hfi1_devdata *dd = uctxt->dd; + unsigned int rcvctrl_op; + + if (subctxt) + goto bail; + /* atomically clear receive enable ctxt. */ + if (start_stop) { + /* + * On enable, force in-memory copy of the tail register to + * 0, so that protocol code doesn't have to worry about + * whether or not the chip has yet updated the in-memory + * copy or not on return from the system call. The chip + * always resets it's tail register back to 0 on a + * transition from disabled to enabled. + */ + if (uctxt->rcvhdrtail_kvaddr) + clear_rcvhdrtail(uctxt); + rcvctrl_op = HFI1_RCVCTRL_CTXT_ENB; + } else + rcvctrl_op = HFI1_RCVCTRL_CTXT_DIS; + hfi1_rcvctrl(dd, rcvctrl_op, uctxt->ctxt); + /* always; new head should be equal to new tail; see above */ +bail: + return 0; +} + +/* + * clear the event notifier events for this context. + * User process then performs actions appropriate to bit having been + * set, if desired, and checks again in future. + */ +static int user_event_ack(struct hfi1_ctxtdata *uctxt, int subctxt, + unsigned long events) +{ + int i; + struct hfi1_devdata *dd = uctxt->dd; + unsigned long *evs; + + if (!dd->events) + return 0; + + evs = dd->events + ((uctxt->ctxt - dd->first_user_ctxt) * + HFI1_MAX_SHARED_CTXTS) + subctxt; + + for (i = 0; i <= _HFI1_MAX_EVENT_BIT; i++) { + if (!test_bit(i, &events)) + continue; + clear_bit(i, evs); + } + return 0; +} + +#define num_user_pages(vaddr, len) \ + (1 + (((((unsigned long)(vaddr) + \ + (unsigned long)(len) - 1) & PAGE_MASK) - \ + ((unsigned long)vaddr & PAGE_MASK)) >> PAGE_SHIFT)) + +/** + * tzcnt - count the number of trailing zeros in a 64bit value + * @value: the value to be examined + * + * Returns the number of trailing least significant zeros in the + * the input value. If the value is zero, return the number of + * bits of the value. + */ +static inline u8 tzcnt(u64 value) +{ + return value ? __builtin_ctzl(value) : sizeof(value) * 8; +} + +static inline unsigned num_free_groups(unsigned long map, u16 *start) +{ + unsigned free; + u16 bitidx = *start; + + if (bitidx >= BITS_PER_LONG) + return 0; + /* "Turn off" any bits set before our bit index */ + map &= ~((1ULL << bitidx) - 1); + free = tzcnt(map) - bitidx; + while (!free && bitidx < BITS_PER_LONG) { + /* Zero out the last set bit so we look at the rest */ + map &= ~(1ULL << bitidx); + /* + * Account for the previously checked bits and advance + * the bit index. We don't have to check for bitidx + * getting bigger than BITS_PER_LONG here as it would + * mean extra instructions that we don't need. If it + * did happen, it would push free to a negative value + * which will break the loop. + */ + free = tzcnt(map) - ++bitidx; + } + *start = bitidx; + return free; +} + +static int exp_tid_setup(struct file *fp, struct hfi1_tid_info *tinfo) +{ + int ret = 0; + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_devdata *dd = uctxt->dd; + unsigned tid, mapped = 0, npages, ngroups, exp_groups, + tidpairs = uctxt->expected_count / 2; + struct page **pages; + unsigned long vaddr, tidmap[uctxt->tidmapcnt]; + dma_addr_t *phys; + u32 tidlist[tidpairs], pairidx = 0, tidcursor; + u16 useidx, idx, bitidx, tidcnt = 0; + + vaddr = tinfo->vaddr; + + if (vaddr & ~PAGE_MASK) { + ret = -EINVAL; + goto bail; + } + + npages = num_user_pages(vaddr, tinfo->length); + if (!npages) { + ret = -EINVAL; + goto bail; + } + if (!access_ok(VERIFY_WRITE, (void __user *)vaddr, + npages * PAGE_SIZE)) { + dd_dev_err(dd, "Fail vaddr %p, %u pages, !access_ok\n", + (void *)vaddr, npages); + ret = -EFAULT; + goto bail; + } + + memset(tidmap, 0, sizeof(tidmap[0]) * uctxt->tidmapcnt); + memset(tidlist, 0, sizeof(tidlist[0]) * tidpairs); + + exp_groups = uctxt->expected_count / dd->rcv_entries.group_size; + /* which group set do we look at first? */ + tidcursor = atomic_read(&uctxt->tidcursor); + useidx = (tidcursor >> 16) & 0xffff; + bitidx = tidcursor & 0xffff; + + /* + * Keep going until we've mapped all pages or we've exhausted all + * RcvArray entries. + * This iterates over the number of tidmaps + 1 + * (idx <= uctxt->tidmapcnt) so we check the bitmap which we + * started from one more time for any free bits before the + * starting point bit. + */ + for (mapped = 0, idx = 0; + mapped < npages && idx <= uctxt->tidmapcnt;) { + u64 i, offset = 0; + unsigned free, pinned, pmapped = 0, bits_used; + u16 grp; + + /* + * "Reserve" the needed group bits under lock so other + * processes can't step in the middle of it. Once + * reserved, we don't need the lock anymore since we + * are guaranteed the groups. + */ + spin_lock(&uctxt->exp_lock); + if (uctxt->tidusemap[useidx] == -1ULL || + bitidx >= BITS_PER_LONG) { + /* no free groups in the set, use the next */ + useidx = (useidx + 1) % uctxt->tidmapcnt; + idx++; + bitidx = 0; + spin_unlock(&uctxt->exp_lock); + continue; + } + ngroups = ((npages - mapped) / dd->rcv_entries.group_size) + + !!((npages - mapped) % dd->rcv_entries.group_size); + + /* + * If we've gotten here, the current set of groups does have + * one or more free groups. + */ + free = num_free_groups(uctxt->tidusemap[useidx], &bitidx); + if (!free) { + /* + * Despite the check above, free could still come back + * as 0 because we don't check the entire bitmap but + * we start from bitidx. + */ + spin_unlock(&uctxt->exp_lock); + continue; + } + bits_used = min(free, ngroups); + tidmap[useidx] |= ((1ULL << bits_used) - 1) << bitidx; + uctxt->tidusemap[useidx] |= tidmap[useidx]; + spin_unlock(&uctxt->exp_lock); + + /* + * At this point, we know where in the map we have free bits. + * properly offset into the various "shadow" arrays and compute + * the RcvArray entry index. + */ + offset = ((useidx * BITS_PER_LONG) + bitidx) * + dd->rcv_entries.group_size; + pages = uctxt->tid_pg_list + offset; + phys = uctxt->physshadow + offset; + tid = uctxt->expected_base + offset; + + /* Calculate how many pages we can pin based on free bits */ + pinned = min((bits_used * dd->rcv_entries.group_size), + (npages - mapped)); + /* + * Now that we know how many free RcvArray entries we have, + * we can pin that many user pages. + */ + ret = hfi1_get_user_pages(vaddr + (mapped * PAGE_SIZE), + pinned, pages); + if (ret) { + /* + * We can't continue because the pages array won't be + * initialized. This should never happen, + * unless perhaps the user has mpin'ed the pages + * themselves. + */ + dd_dev_info(dd, + "Failed to lock addr %p, %u pages: errno %d\n", + (void *) vaddr, pinned, -ret); + /* + * Let go of the bits that we reserved since we are not + * going to use them. + */ + spin_lock(&uctxt->exp_lock); + uctxt->tidusemap[useidx] &= + ~(((1ULL << bits_used) - 1) << bitidx); + spin_unlock(&uctxt->exp_lock); + goto done; + } + /* + * How many groups do we need based on how many pages we have + * pinned? + */ + ngroups = (pinned / dd->rcv_entries.group_size) + + !!(pinned % dd->rcv_entries.group_size); + /* + * Keep programming RcvArray entries for all the free + * groups. + */ + for (i = 0, grp = 0; grp < ngroups; i++, grp++) { + unsigned j; + u32 pair_size = 0, tidsize; + /* + * This inner loop will program an entire group or the + * array of pinned pages (which ever limit is hit + * first). + */ + for (j = 0; j < dd->rcv_entries.group_size && + pmapped < pinned; j++, pmapped++, tid++) { + tidsize = PAGE_SIZE; + phys[pmapped] = hfi1_map_page(dd->pcidev, + pages[pmapped], 0, + tidsize, PCI_DMA_FROMDEVICE); + trace_hfi1_exp_rcv_set(uctxt->ctxt, + subctxt_fp(fp), + tid, vaddr, + phys[pmapped], + pages[pmapped]); + /* + * Each RcvArray entry is programmed with one + * page * worth of memory. This will handle + * the 8K MTU as well as anything smaller + * due to the fact that both entries in the + * RcvTidPair are programmed with a page. + * PSM currently does not handle anything + * bigger than 8K MTU, so should we even worry + * about 10K here? + */ + hfi1_put_tid(dd, tid, PT_EXPECTED, + phys[pmapped], + ilog2(tidsize >> PAGE_SHIFT) + 1); + pair_size += tidsize >> PAGE_SHIFT; + EXP_TID_RESET(tidlist[pairidx], LEN, pair_size); + if (!(tid % 2)) { + tidlist[pairidx] |= + EXP_TID_SET(IDX, + (tid - uctxt->expected_base) + / 2); + tidlist[pairidx] |= + EXP_TID_SET(CTRL, 1); + tidcnt++; + } else { + tidlist[pairidx] |= + EXP_TID_SET(CTRL, 2); + pair_size = 0; + pairidx++; + } + } + /* + * We've programmed the entire group (or as much of the + * group as we'll use. Now, it's time to push it out... + */ + flush_wc(); + } + mapped += pinned; + atomic_set(&uctxt->tidcursor, + (((useidx & 0xffffff) << 16) | + ((bitidx + bits_used) & 0xffffff))); + } + trace_hfi1_exp_tid_map(uctxt->ctxt, subctxt_fp(fp), 0, uctxt->tidusemap, + uctxt->tidmapcnt); + +done: + /* If we've mapped anything, copy relevant info to user */ + if (mapped) { + if (copy_to_user((void __user *)(unsigned long)tinfo->tidlist, + tidlist, sizeof(tidlist[0]) * tidcnt)) { + ret = -EFAULT; + goto done; + } + /* copy TID info to user */ + if (copy_to_user((void __user *)(unsigned long)tinfo->tidmap, + tidmap, sizeof(tidmap[0]) * uctxt->tidmapcnt)) + ret = -EFAULT; + } +bail: + /* + * Calculate mapped length. New Exp TID protocol does not "unwind" and + * report an error if it can't map the entire buffer. It just reports + * the length that was mapped. + */ + tinfo->length = mapped * PAGE_SIZE; + tinfo->tidcnt = tidcnt; + return ret; +} + +static int exp_tid_free(struct file *fp, struct hfi1_tid_info *tinfo) +{ + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_devdata *dd = uctxt->dd; + unsigned long tidmap[uctxt->tidmapcnt]; + struct page **pages; + dma_addr_t *phys; + u16 idx, bitidx, tid; + int ret = 0; + + if (copy_from_user(&tidmap, (void __user *)(unsigned long) + tinfo->tidmap, + sizeof(tidmap[0]) * uctxt->tidmapcnt)) { + ret = -EFAULT; + goto done; + } + for (idx = 0; idx < uctxt->tidmapcnt; idx++) { + unsigned long map; + + bitidx = 0; + if (!tidmap[idx]) + continue; + map = tidmap[idx]; + while ((bitidx = tzcnt(map)) < BITS_PER_LONG) { + int i, pcount = 0; + struct page *pshadow[dd->rcv_entries.group_size]; + unsigned offset = ((idx * BITS_PER_LONG) + bitidx) * + dd->rcv_entries.group_size; + + pages = uctxt->tid_pg_list + offset; + phys = uctxt->physshadow + offset; + tid = uctxt->expected_base + offset; + for (i = 0; i < dd->rcv_entries.group_size; + i++, tid++) { + if (pages[i]) { + hfi1_put_tid(dd, tid, PT_INVALID, + 0, 0); + trace_hfi1_exp_rcv_free(uctxt->ctxt, + subctxt_fp(fp), + tid, phys[i], + pages[i]); + pci_unmap_page(dd->pcidev, phys[i], + PAGE_SIZE, PCI_DMA_FROMDEVICE); + pshadow[pcount] = pages[i]; + pages[i] = NULL; + pcount++; + phys[i] = 0; + } + } + flush_wc(); + hfi1_release_user_pages(pshadow, pcount); + clear_bit(bitidx, &uctxt->tidusemap[idx]); + map &= ~(1ULL<ctxt, subctxt_fp(fp), 1, uctxt->tidusemap, + uctxt->tidmapcnt); +done: + return ret; +} + +static void unlock_exp_tids(struct hfi1_ctxtdata *uctxt) +{ + struct hfi1_devdata *dd = uctxt->dd; + unsigned tid; + + dd_dev_info(dd, "ctxt %u unlocking any locked expTID pages\n", + uctxt->ctxt); + for (tid = 0; tid < uctxt->expected_count; tid++) { + struct page *p = uctxt->tid_pg_list[tid]; + dma_addr_t phys; + + if (!p) + continue; + + phys = uctxt->physshadow[tid]; + uctxt->physshadow[tid] = 0; + uctxt->tid_pg_list[tid] = NULL; + pci_unmap_page(dd->pcidev, phys, PAGE_SIZE, PCI_DMA_FROMDEVICE); + hfi1_release_user_pages(&p, 1); + } +} + +static int set_ctxt_pkey(struct hfi1_ctxtdata *uctxt, unsigned subctxt, + u16 pkey) +{ + int ret = -ENOENT, i, intable = 0; + struct hfi1_pportdata *ppd = uctxt->ppd; + struct hfi1_devdata *dd = uctxt->dd; + + if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) { + ret = -EINVAL; + goto done; + } + + for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) + if (pkey == ppd->pkeys[i]) { + intable = 1; + break; + } + + if (intable) + ret = hfi1_set_ctxt_pkey(dd, uctxt->ctxt, pkey); +done: + return ret; +} + +static int ui_open(struct inode *inode, struct file *filp) +{ + struct hfi1_devdata *dd; + + dd = container_of(inode->i_cdev, struct hfi1_devdata, ui_cdev); + filp->private_data = dd; /* for other methods */ + return 0; +} + +static int ui_release(struct inode *inode, struct file *filp) +{ + /* nothing to do */ + return 0; +} + +static loff_t ui_lseek(struct file *filp, loff_t offset, int whence) +{ + struct hfi1_devdata *dd = filp->private_data; + + switch (whence) { + case SEEK_SET: + break; + case SEEK_CUR: + offset += filp->f_pos; + break; + case SEEK_END: + offset = ((dd->kregend - dd->kregbase) + DC8051_DATA_MEM_SIZE) - + offset; + break; + default: + return -EINVAL; + } + + if (offset < 0) + return -EINVAL; + + if (offset >= (dd->kregend - dd->kregbase) + DC8051_DATA_MEM_SIZE) + return -EINVAL; + + filp->f_pos = offset; + + return filp->f_pos; +} + + +/* NOTE: assumes unsigned long is 8 bytes */ +static ssize_t ui_read(struct file *filp, char __user *buf, size_t count, + loff_t *f_pos) +{ + struct hfi1_devdata *dd = filp->private_data; + void __iomem *base = dd->kregbase; + unsigned long total, csr_off, + barlen = (dd->kregend - dd->kregbase); + u64 data; + + /* only read 8 byte quantities */ + if ((count % 8) != 0) + return -EINVAL; + /* offset must be 8-byte aligned */ + if ((*f_pos % 8) != 0) + return -EINVAL; + /* destination buffer must be 8-byte aligned */ + if ((unsigned long)buf % 8 != 0) + return -EINVAL; + /* must be in range */ + if (*f_pos + count > (barlen + DC8051_DATA_MEM_SIZE)) + return -EINVAL; + /* only set the base if we are not starting past the BAR */ + if (*f_pos < barlen) + base += *f_pos; + csr_off = *f_pos; + for (total = 0; total < count; total += 8, csr_off += 8) { + /* accessing LCB CSRs requires more checks */ + if (is_lcb_offset(csr_off)) { + if (read_lcb_csr(dd, csr_off, (u64 *)&data)) + break; /* failed */ + } + /* + * Cannot read ASIC GPIO/QSFP* clear and force CSRs without a + * false parity error. Avoid the whole issue by not reading + * them. These registers are defined as having a read value + * of 0. + */ + else if (csr_off == ASIC_GPIO_CLEAR + || csr_off == ASIC_GPIO_FORCE + || csr_off == ASIC_QSFP1_CLEAR + || csr_off == ASIC_QSFP1_FORCE + || csr_off == ASIC_QSFP2_CLEAR + || csr_off == ASIC_QSFP2_FORCE) + data = 0; + else if (csr_off >= barlen) { + /* + * read_8051_data can read more than just 8 bytes at + * a time. However, folding this into the loop and + * handling the reads in 8 byte increments allows us + * to smoothly transition from chip memory to 8051 + * memory. + */ + if (read_8051_data(dd, + (u32)(csr_off - barlen), + sizeof(data), &data)) + break; /* failed */ + } else + data = readq(base + total); + if (put_user(data, (unsigned long __user *)(buf + total))) + break; + } + *f_pos += total; + return total; +} + +/* NOTE: assumes unsigned long is 8 bytes */ +static ssize_t ui_write(struct file *filp, const char __user *buf, + size_t count, loff_t *f_pos) +{ + struct hfi1_devdata *dd = filp->private_data; + void __iomem *base; + unsigned long total, data, csr_off; + int in_lcb; + + /* only write 8 byte quantities */ + if ((count % 8) != 0) + return -EINVAL; + /* offset must be 8-byte aligned */ + if ((*f_pos % 8) != 0) + return -EINVAL; + /* source buffer must be 8-byte aligned */ + if ((unsigned long)buf % 8 != 0) + return -EINVAL; + /* must be in range */ + if (*f_pos + count > dd->kregend - dd->kregbase) + return -EINVAL; + + base = (void __iomem *)dd->kregbase + *f_pos; + csr_off = *f_pos; + in_lcb = 0; + for (total = 0; total < count; total += 8, csr_off += 8) { + if (get_user(data, (unsigned long __user *)(buf + total))) + break; + /* accessing LCB CSRs requires a special procedure */ + if (is_lcb_offset(csr_off)) { + if (!in_lcb) { + int ret = acquire_lcb_access(dd, 1); + + if (ret) + break; + in_lcb = 1; + } + } else { + if (in_lcb) { + release_lcb_access(dd, 1); + in_lcb = 0; + } + } + writeq(data, base + total); + } + if (in_lcb) + release_lcb_access(dd, 1); + *f_pos += total; + return total; +} + +static const struct file_operations ui_file_ops = { + .owner = THIS_MODULE, + .llseek = ui_lseek, + .read = ui_read, + .write = ui_write, + .open = ui_open, + .release = ui_release, +}; +#define UI_OFFSET 192 /* device minor offset for UI devices */ +static int create_ui = 1; + +static struct cdev wildcard_cdev; +static struct device *wildcard_device; + +static atomic_t user_count = ATOMIC_INIT(0); + +static void user_remove(struct hfi1_devdata *dd) +{ + if (atomic_dec_return(&user_count) == 0) + hfi1_cdev_cleanup(&wildcard_cdev, &wildcard_device); + + hfi1_cdev_cleanup(&dd->user_cdev, &dd->user_device); + hfi1_cdev_cleanup(&dd->ui_cdev, &dd->ui_device); +} + +static int user_add(struct hfi1_devdata *dd) +{ + char name[10]; + int ret; + + if (atomic_inc_return(&user_count) == 1) { + ret = hfi1_cdev_init(0, class_name(), &hfi1_file_ops, + &wildcard_cdev, &wildcard_device); + if (ret) + goto done; + } + + snprintf(name, sizeof(name), "%s_%d", class_name(), dd->unit); + ret = hfi1_cdev_init(dd->unit + 1, name, &hfi1_file_ops, + &dd->user_cdev, &dd->user_device); + if (ret) + goto done; + + if (create_ui) { + snprintf(name, sizeof(name), + "%s_ui%d", class_name(), dd->unit); + ret = hfi1_cdev_init(dd->unit + UI_OFFSET, name, &ui_file_ops, + &dd->ui_cdev, &dd->ui_device); + if (ret) + goto done; + } + + return 0; +done: + user_remove(dd); + return ret; +} + +/* + * Create per-unit files in /dev + */ +int hfi1_device_create(struct hfi1_devdata *dd) +{ + int r, ret; + + r = user_add(dd); + ret = hfi1_diag_add(dd); + if (r && !ret) + ret = r; + return ret; +} + +/* + * Remove per-unit files in /dev + * void, core kernel returns no errors for this stuff + */ +void hfi1_device_remove(struct hfi1_devdata *dd) +{ + user_remove(dd); + hfi1_diag_remove(dd); +} diff --git a/drivers/staging/rdma/hfi1/firmware.c b/drivers/staging/rdma/hfi1/firmware.c new file mode 100644 index 0000000000000..5c2f2ed8f2243 --- /dev/null +++ b/drivers/staging/rdma/hfi1/firmware.c @@ -0,0 +1,1620 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "trace.h" + +/* + * Make it easy to toggle firmware file name and if it gets loaded by + * editing the following. This may be something we do while in development + * but not necessarily something a user would ever need to use. + */ +#define DEFAULT_FW_8051_NAME_FPGA "hfi_dc8051.bin" +#define DEFAULT_FW_8051_NAME_ASIC "hfi1_dc8051.fw" +#define DEFAULT_FW_FABRIC_NAME "hfi1_fabric.fw" +#define DEFAULT_FW_SBUS_NAME "hfi1_sbus.fw" +#define DEFAULT_FW_PCIE_NAME "hfi1_pcie.fw" +#define DEFAULT_PLATFORM_CONFIG_NAME "hfi1_platform.dat" + +static uint fw_8051_load = 1; +static uint fw_fabric_serdes_load = 1; +static uint fw_pcie_serdes_load = 1; +static uint fw_sbus_load = 1; +static uint platform_config_load = 1; + +/* Firmware file names get set in hfi1_firmware_init() based on the above */ +static char *fw_8051_name; +static char *fw_fabric_serdes_name; +static char *fw_sbus_name; +static char *fw_pcie_serdes_name; +static char *platform_config_name; + +#define SBUS_MAX_POLL_COUNT 100 +#define SBUS_COUNTER(reg, name) \ + (((reg) >> ASIC_STS_SBUS_COUNTERS_##name##_CNT_SHIFT) & \ + ASIC_STS_SBUS_COUNTERS_##name##_CNT_MASK) + +/* + * Firmware security header. + */ +struct css_header { + u32 module_type; + u32 header_len; + u32 header_version; + u32 module_id; + u32 module_vendor; + u32 date; /* BCD yyyymmdd */ + u32 size; /* in DWORDs */ + u32 key_size; /* in DWORDs */ + u32 modulus_size; /* in DWORDs */ + u32 exponent_size; /* in DWORDs */ + u32 reserved[22]; +}; +/* expected field values */ +#define CSS_MODULE_TYPE 0x00000006 +#define CSS_HEADER_LEN 0x000000a1 +#define CSS_HEADER_VERSION 0x00010000 +#define CSS_MODULE_VENDOR 0x00008086 + +#define KEY_SIZE 256 +#define MU_SIZE 8 +#define EXPONENT_SIZE 4 + +/* the file itself */ +struct firmware_file { + struct css_header css_header; + u8 modulus[KEY_SIZE]; + u8 exponent[EXPONENT_SIZE]; + u8 signature[KEY_SIZE]; + u8 firmware[]; +}; + +struct augmented_firmware_file { + struct css_header css_header; + u8 modulus[KEY_SIZE]; + u8 exponent[EXPONENT_SIZE]; + u8 signature[KEY_SIZE]; + u8 r2[KEY_SIZE]; + u8 mu[MU_SIZE]; + u8 firmware[]; +}; + +/* augmented file size difference */ +#define AUGMENT_SIZE (sizeof(struct augmented_firmware_file) - \ + sizeof(struct firmware_file)) + +struct firmware_details { + /* Linux core piece */ + const struct firmware *fw; + + struct css_header *css_header; + u8 *firmware_ptr; /* pointer to binary data */ + u32 firmware_len; /* length in bytes */ + u8 *modulus; /* pointer to the modulus */ + u8 *exponent; /* pointer to the exponent */ + u8 *signature; /* pointer to the signature */ + u8 *r2; /* pointer to r2 */ + u8 *mu; /* pointer to mu */ + struct augmented_firmware_file dummy_header; +}; + +/* + * The mutex protects fw_state, fw_err, and all of the firmware_details + * variables. + */ +static DEFINE_MUTEX(fw_mutex); +enum fw_state { + FW_EMPTY, + FW_ACQUIRED, + FW_ERR +}; +static enum fw_state fw_state = FW_EMPTY; +static int fw_err; +static struct firmware_details fw_8051; +static struct firmware_details fw_fabric; +static struct firmware_details fw_pcie; +static struct firmware_details fw_sbus; +static const struct firmware *platform_config; + +/* flags for turn_off_spicos() */ +#define SPICO_SBUS 0x1 +#define SPICO_FABRIC 0x2 +#define ENABLE_SPICO_SMASK 0x1 + +/* security block commands */ +#define RSA_CMD_INIT 0x1 +#define RSA_CMD_START 0x2 + +/* security block status */ +#define RSA_STATUS_IDLE 0x0 +#define RSA_STATUS_ACTIVE 0x1 +#define RSA_STATUS_DONE 0x2 +#define RSA_STATUS_FAILED 0x3 + +/* RSA engine timeout, in ms */ +#define RSA_ENGINE_TIMEOUT 100 /* ms */ + +/* hardware mutex timeout, in ms */ +#define HM_TIMEOUT 4000 /* 4 s */ + +/* 8051 memory access timeout, in us */ +#define DC8051_ACCESS_TIMEOUT 100 /* us */ + +/* the number of fabric SerDes on the SBus */ +#define NUM_FABRIC_SERDES 4 + +/* SBus fabric SerDes addresses, one set per HFI */ +static const u8 fabric_serdes_addrs[2][NUM_FABRIC_SERDES] = { + { 0x01, 0x02, 0x03, 0x04 }, + { 0x28, 0x29, 0x2a, 0x2b } +}; + +/* SBus PCIe SerDes addresses, one set per HFI */ +static const u8 pcie_serdes_addrs[2][NUM_PCIE_SERDES] = { + { 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26 }, + { 0x2f, 0x31, 0x33, 0x35, 0x37, 0x39, 0x3b, 0x3d, + 0x3f, 0x41, 0x43, 0x45, 0x47, 0x49, 0x4b, 0x4d } +}; + +/* SBus PCIe PCS addresses, one set per HFI */ +const u8 pcie_pcs_addrs[2][NUM_PCIE_SERDES] = { + { 0x09, 0x0b, 0x0d, 0x0f, 0x11, 0x13, 0x15, 0x17, + 0x19, 0x1b, 0x1d, 0x1f, 0x21, 0x23, 0x25, 0x27 }, + { 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, + 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e } +}; + +/* SBus fabric SerDes broadcast addresses, one per HFI */ +static const u8 fabric_serdes_broadcast[2] = { 0xe4, 0xe5 }; +static const u8 all_fabric_serdes_broadcast = 0xe1; + +/* SBus PCIe SerDes broadcast addresses, one per HFI */ +const u8 pcie_serdes_broadcast[2] = { 0xe2, 0xe3 }; +static const u8 all_pcie_serdes_broadcast = 0xe0; + +/* forwards */ +static void dispose_one_firmware(struct firmware_details *fdet); + +/* + * Read a single 64-bit value from 8051 data memory. + * + * Expects: + * o caller to have already set up data read, no auto increment + * o caller to turn off read enable when finished + * + * The address argument is a byte offset. Bits 0:2 in the address are + * ignored - i.e. the hardware will always do aligned 8-byte reads as if + * the lower bits are zero. + * + * Return 0 on success, -ENXIO on a read error (timeout). + */ +static int __read_8051_data(struct hfi1_devdata *dd, u32 addr, u64 *result) +{ + u64 reg; + int count; + + /* start the read at the given address */ + reg = ((addr & DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_MASK) + << DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_SHIFT) + | DC_DC8051_CFG_RAM_ACCESS_CTRL_READ_ENA_SMASK; + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_CTRL, reg); + + /* wait until ACCESS_COMPLETED is set */ + count = 0; + while ((read_csr(dd, DC_DC8051_CFG_RAM_ACCESS_STATUS) + & DC_DC8051_CFG_RAM_ACCESS_STATUS_ACCESS_COMPLETED_SMASK) + == 0) { + count++; + if (count > DC8051_ACCESS_TIMEOUT) { + dd_dev_err(dd, "timeout reading 8051 data\n"); + return -ENXIO; + } + ndelay(10); + } + + /* gather the data */ + *result = read_csr(dd, DC_DC8051_CFG_RAM_ACCESS_RD_DATA); + + return 0; +} + +/* + * Read 8051 data starting at addr, for len bytes. Will read in 8-byte chunks. + * Return 0 on success, -errno on error. + */ +int read_8051_data(struct hfi1_devdata *dd, u32 addr, u32 len, u64 *result) +{ + unsigned long flags; + u32 done; + int ret = 0; + + spin_lock_irqsave(&dd->dc8051_memlock, flags); + + /* data read set-up, no auto-increment */ + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_SETUP, 0); + + for (done = 0; done < len; addr += 8, done += 8, result++) { + ret = __read_8051_data(dd, addr, result); + if (ret) + break; + } + + /* turn off read enable */ + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_CTRL, 0); + + spin_unlock_irqrestore(&dd->dc8051_memlock, flags); + + return ret; +} + +/* + * Write data or code to the 8051 code or data RAM. + */ +static int write_8051(struct hfi1_devdata *dd, int code, u32 start, + const u8 *data, u32 len) +{ + u64 reg; + u32 offset; + int aligned, count; + + /* check alignment */ + aligned = ((unsigned long)data & 0x7) == 0; + + /* write set-up */ + reg = (code ? DC_DC8051_CFG_RAM_ACCESS_SETUP_RAM_SEL_SMASK : 0ull) + | DC_DC8051_CFG_RAM_ACCESS_SETUP_AUTO_INCR_ADDR_SMASK; + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_SETUP, reg); + + reg = ((start & DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_MASK) + << DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_SHIFT) + | DC_DC8051_CFG_RAM_ACCESS_CTRL_WRITE_ENA_SMASK; + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_CTRL, reg); + + /* write */ + for (offset = 0; offset < len; offset += 8) { + int bytes = len - offset; + + if (bytes < 8) { + reg = 0; + memcpy(®, &data[offset], bytes); + } else if (aligned) { + reg = *(u64 *)&data[offset]; + } else { + memcpy(®, &data[offset], 8); + } + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_WR_DATA, reg); + + /* wait until ACCESS_COMPLETED is set */ + count = 0; + while ((read_csr(dd, DC_DC8051_CFG_RAM_ACCESS_STATUS) + & DC_DC8051_CFG_RAM_ACCESS_STATUS_ACCESS_COMPLETED_SMASK) + == 0) { + count++; + if (count > DC8051_ACCESS_TIMEOUT) { + dd_dev_err(dd, "timeout writing 8051 data\n"); + return -ENXIO; + } + udelay(1); + } + } + + /* turn off write access, auto increment (also sets to data access) */ + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_CTRL, 0); + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_SETUP, 0); + + return 0; +} + +/* return 0 if values match, non-zero and complain otherwise */ +static int invalid_header(struct hfi1_devdata *dd, const char *what, + u32 actual, u32 expected) +{ + if (actual == expected) + return 0; + + dd_dev_err(dd, + "invalid firmware header field %s: expected 0x%x, actual 0x%x\n", + what, expected, actual); + return 1; +} + +/* + * Verify that the static fields in the CSS header match. + */ +static int verify_css_header(struct hfi1_devdata *dd, struct css_header *css) +{ + /* verify CSS header fields (most sizes are in DW, so add /4) */ + if (invalid_header(dd, "module_type", css->module_type, CSS_MODULE_TYPE) + || invalid_header(dd, "header_len", css->header_len, + (sizeof(struct firmware_file)/4)) + || invalid_header(dd, "header_version", + css->header_version, CSS_HEADER_VERSION) + || invalid_header(dd, "module_vendor", + css->module_vendor, CSS_MODULE_VENDOR) + || invalid_header(dd, "key_size", + css->key_size, KEY_SIZE/4) + || invalid_header(dd, "modulus_size", + css->modulus_size, KEY_SIZE/4) + || invalid_header(dd, "exponent_size", + css->exponent_size, EXPONENT_SIZE/4)) { + return -EINVAL; + } + return 0; +} + +/* + * Make sure there are at least some bytes after the prefix. + */ +static int payload_check(struct hfi1_devdata *dd, const char *name, + long file_size, long prefix_size) +{ + /* make sure we have some payload */ + if (prefix_size >= file_size) { + dd_dev_err(dd, + "firmware \"%s\", size %ld, must be larger than %ld bytes\n", + name, file_size, prefix_size); + return -EINVAL; + } + + return 0; +} + +/* + * Request the firmware from the system. Extract the pieces and fill in + * fdet. If successful, the caller will need to call dispose_one_firmware(). + * Returns 0 on success, -ERRNO on error. + */ +static int obtain_one_firmware(struct hfi1_devdata *dd, const char *name, + struct firmware_details *fdet) +{ + struct css_header *css; + int ret; + + memset(fdet, 0, sizeof(*fdet)); + + ret = request_firmware(&fdet->fw, name, &dd->pcidev->dev); + if (ret) { + dd_dev_err(dd, "cannot load firmware \"%s\", err %d\n", + name, ret); + return ret; + } + + /* verify the firmware */ + if (fdet->fw->size < sizeof(struct css_header)) { + dd_dev_err(dd, "firmware \"%s\" is too small\n", name); + ret = -EINVAL; + goto done; + } + css = (struct css_header *)fdet->fw->data; + + hfi1_cdbg(FIRMWARE, "Firmware %s details:", name); + hfi1_cdbg(FIRMWARE, "file size: 0x%lx bytes", fdet->fw->size); + hfi1_cdbg(FIRMWARE, "CSS structure:"); + hfi1_cdbg(FIRMWARE, " module_type 0x%x", css->module_type); + hfi1_cdbg(FIRMWARE, " header_len 0x%03x (0x%03x bytes)", + css->header_len, 4 * css->header_len); + hfi1_cdbg(FIRMWARE, " header_version 0x%x", css->header_version); + hfi1_cdbg(FIRMWARE, " module_id 0x%x", css->module_id); + hfi1_cdbg(FIRMWARE, " module_vendor 0x%x", css->module_vendor); + hfi1_cdbg(FIRMWARE, " date 0x%x", css->date); + hfi1_cdbg(FIRMWARE, " size 0x%03x (0x%03x bytes)", + css->size, 4 * css->size); + hfi1_cdbg(FIRMWARE, " key_size 0x%03x (0x%03x bytes)", + css->key_size, 4 * css->key_size); + hfi1_cdbg(FIRMWARE, " modulus_size 0x%03x (0x%03x bytes)", + css->modulus_size, 4 * css->modulus_size); + hfi1_cdbg(FIRMWARE, " exponent_size 0x%03x (0x%03x bytes)", + css->exponent_size, 4 * css->exponent_size); + hfi1_cdbg(FIRMWARE, "firmware size: 0x%lx bytes", + fdet->fw->size - sizeof(struct firmware_file)); + + /* + * If the file does not have a valid CSS header, fail. + * Otherwise, check the CSS size field for an expected size. + * The augmented file has r2 and mu inserted after the header + * was generated, so there will be a known difference between + * the CSS header size and the actual file size. Use this + * difference to identify an augmented file. + * + * Note: css->size is in DWORDs, multiply by 4 to get bytes. + */ + ret = verify_css_header(dd, css); + if (ret) { + dd_dev_info(dd, "Invalid CSS header for \"%s\"\n", name); + } else if ((css->size*4) == fdet->fw->size) { + /* non-augmented firmware file */ + struct firmware_file *ff = (struct firmware_file *) + fdet->fw->data; + + /* make sure there are bytes in the payload */ + ret = payload_check(dd, name, fdet->fw->size, + sizeof(struct firmware_file)); + if (ret == 0) { + fdet->css_header = css; + fdet->modulus = ff->modulus; + fdet->exponent = ff->exponent; + fdet->signature = ff->signature; + fdet->r2 = fdet->dummy_header.r2; /* use dummy space */ + fdet->mu = fdet->dummy_header.mu; /* use dummy space */ + fdet->firmware_ptr = ff->firmware; + fdet->firmware_len = fdet->fw->size - + sizeof(struct firmware_file); + /* + * Header does not include r2 and mu - generate here. + * For now, fail. + */ + dd_dev_err(dd, "driver is unable to validate firmware without r2 and mu (not in firmware file)\n"); + ret = -EINVAL; + } + } else if ((css->size*4) + AUGMENT_SIZE == fdet->fw->size) { + /* augmented firmware file */ + struct augmented_firmware_file *aff = + (struct augmented_firmware_file *)fdet->fw->data; + + /* make sure there are bytes in the payload */ + ret = payload_check(dd, name, fdet->fw->size, + sizeof(struct augmented_firmware_file)); + if (ret == 0) { + fdet->css_header = css; + fdet->modulus = aff->modulus; + fdet->exponent = aff->exponent; + fdet->signature = aff->signature; + fdet->r2 = aff->r2; + fdet->mu = aff->mu; + fdet->firmware_ptr = aff->firmware; + fdet->firmware_len = fdet->fw->size - + sizeof(struct augmented_firmware_file); + } + } else { + /* css->size check failed */ + dd_dev_err(dd, + "invalid firmware header field size: expected 0x%lx or 0x%lx, actual 0x%x\n", + fdet->fw->size/4, (fdet->fw->size - AUGMENT_SIZE)/4, + css->size); + + ret = -EINVAL; + } + +done: + /* if returning an error, clean up after ourselves */ + if (ret) + dispose_one_firmware(fdet); + return ret; +} + +static void dispose_one_firmware(struct firmware_details *fdet) +{ + release_firmware(fdet->fw); + fdet->fw = NULL; +} + +/* + * Called by all HFIs when loading their firmware - i.e. device probe time. + * The first one will do the actual firmware load. Use a mutex to resolve + * any possible race condition. + * + * The call to this routine cannot be moved to driver load because the kernel + * call request_firmware() requires a device which is only available after + * the first device probe. + */ +static int obtain_firmware(struct hfi1_devdata *dd) +{ + int err = 0; + + mutex_lock(&fw_mutex); + if (fw_state == FW_ACQUIRED) { + goto done; /* already acquired */ + } else if (fw_state == FW_ERR) { + err = fw_err; + goto done; /* already tried and failed */ + } + + if (fw_8051_load) { + err = obtain_one_firmware(dd, fw_8051_name, &fw_8051); + if (err) + goto done; + } + + if (fw_fabric_serdes_load) { + err = obtain_one_firmware(dd, fw_fabric_serdes_name, + &fw_fabric); + if (err) + goto done; + } + + if (fw_sbus_load) { + err = obtain_one_firmware(dd, fw_sbus_name, &fw_sbus); + if (err) + goto done; + } + + if (fw_pcie_serdes_load) { + err = obtain_one_firmware(dd, fw_pcie_serdes_name, &fw_pcie); + if (err) + goto done; + } + + if (platform_config_load) { + platform_config = NULL; + err = request_firmware(&platform_config, platform_config_name, + &dd->pcidev->dev); + if (err) { + err = 0; + platform_config = NULL; + } + } + + /* success */ + fw_state = FW_ACQUIRED; + +done: + if (err) { + fw_err = err; + fw_state = FW_ERR; + } + mutex_unlock(&fw_mutex); + + return err; +} + +/* + * Called when the driver unloads. The timing is asymmetric with its + * counterpart, obtain_firmware(). If called at device remove time, + * then it is conceivable that another device could probe while the + * firmware is being disposed. The mutexes can be moved to do that + * safely, but then the firmware would be requested from the OS multiple + * times. + * + * No mutex is needed as the driver is unloading and there cannot be any + * other callers. + */ +void dispose_firmware(void) +{ + dispose_one_firmware(&fw_8051); + dispose_one_firmware(&fw_fabric); + dispose_one_firmware(&fw_pcie); + dispose_one_firmware(&fw_sbus); + + release_firmware(platform_config); + platform_config = NULL; + + /* retain the error state, otherwise revert to empty */ + if (fw_state != FW_ERR) + fw_state = FW_EMPTY; +} + +/* + * Write a block of data to a given array CSR. All calls will be in + * multiples of 8 bytes. + */ +static void write_rsa_data(struct hfi1_devdata *dd, int what, + const u8 *data, int nbytes) +{ + int qw_size = nbytes/8; + int i; + + if (((unsigned long)data & 0x7) == 0) { + /* aligned */ + u64 *ptr = (u64 *)data; + + for (i = 0; i < qw_size; i++, ptr++) + write_csr(dd, what + (8*i), *ptr); + } else { + /* not aligned */ + for (i = 0; i < qw_size; i++, data += 8) { + u64 value; + + memcpy(&value, data, 8); + write_csr(dd, what + (8*i), value); + } + } +} + +/* + * Write a block of data to a given CSR as a stream of writes. All calls will + * be in multiples of 8 bytes. + */ +static void write_streamed_rsa_data(struct hfi1_devdata *dd, int what, + const u8 *data, int nbytes) +{ + u64 *ptr = (u64 *)data; + int qw_size = nbytes/8; + + for (; qw_size > 0; qw_size--, ptr++) + write_csr(dd, what, *ptr); +} + +/* + * Download the signature and start the RSA mechanism. Wait for + * RSA_ENGINE_TIMEOUT before giving up. + */ +static int run_rsa(struct hfi1_devdata *dd, const char *who, + const u8 *signature) +{ + unsigned long timeout; + u64 reg; + u32 status; + int ret = 0; + + /* write the signature */ + write_rsa_data(dd, MISC_CFG_RSA_SIGNATURE, signature, KEY_SIZE); + + /* initialize RSA */ + write_csr(dd, MISC_CFG_RSA_CMD, RSA_CMD_INIT); + + /* + * Make sure the engine is idle and insert a delay between the two + * writes to MISC_CFG_RSA_CMD. + */ + status = (read_csr(dd, MISC_CFG_FW_CTRL) + & MISC_CFG_FW_CTRL_RSA_STATUS_SMASK) + >> MISC_CFG_FW_CTRL_RSA_STATUS_SHIFT; + if (status != RSA_STATUS_IDLE) { + dd_dev_err(dd, "%s security engine not idle - giving up\n", + who); + return -EBUSY; + } + + /* start RSA */ + write_csr(dd, MISC_CFG_RSA_CMD, RSA_CMD_START); + + /* + * Look for the result. + * + * The RSA engine is hooked up to two MISC errors. The driver + * masks these errors as they do not respond to the standard + * error "clear down" mechanism. Look for these errors here and + * clear them when possible. This routine will exit with the + * errors of the current run still set. + * + * MISC_FW_AUTH_FAILED_ERR + * Firmware authorization failed. This can be cleared by + * re-initializing the RSA engine, then clearing the status bit. + * Do not re-init the RSA angine immediately after a successful + * run - this will reset the current authorization. + * + * MISC_KEY_MISMATCH_ERR + * Key does not match. The only way to clear this is to load + * a matching key then clear the status bit. If this error + * is raised, it will persist outside of this routine until a + * matching key is loaded. + */ + timeout = msecs_to_jiffies(RSA_ENGINE_TIMEOUT) + jiffies; + while (1) { + status = (read_csr(dd, MISC_CFG_FW_CTRL) + & MISC_CFG_FW_CTRL_RSA_STATUS_SMASK) + >> MISC_CFG_FW_CTRL_RSA_STATUS_SHIFT; + + if (status == RSA_STATUS_IDLE) { + /* should not happen */ + dd_dev_err(dd, "%s firmware security bad idle state\n", + who); + ret = -EINVAL; + break; + } else if (status == RSA_STATUS_DONE) { + /* finished successfully */ + break; + } else if (status == RSA_STATUS_FAILED) { + /* finished unsuccessfully */ + ret = -EINVAL; + break; + } + /* else still active */ + + if (time_after(jiffies, timeout)) { + /* + * Timed out while active. We can't reset the engine + * if it is stuck active, but run through the + * error code to see what error bits are set. + */ + dd_dev_err(dd, "%s firmware security time out\n", who); + ret = -ETIMEDOUT; + break; + } + + msleep(20); + } + + /* + * Arrive here on success or failure. Clear all RSA engine + * errors. All current errors will stick - the RSA logic is keeping + * error high. All previous errors will clear - the RSA logic + * is not keeping the error high. + */ + write_csr(dd, MISC_ERR_CLEAR, + MISC_ERR_STATUS_MISC_FW_AUTH_FAILED_ERR_SMASK + | MISC_ERR_STATUS_MISC_KEY_MISMATCH_ERR_SMASK); + /* + * All that is left are the current errors. Print failure details, + * if any. + */ + reg = read_csr(dd, MISC_ERR_STATUS); + if (ret) { + if (reg & MISC_ERR_STATUS_MISC_FW_AUTH_FAILED_ERR_SMASK) + dd_dev_err(dd, "%s firmware authorization failed\n", + who); + if (reg & MISC_ERR_STATUS_MISC_KEY_MISMATCH_ERR_SMASK) + dd_dev_err(dd, "%s firmware key mismatch\n", who); + } + + return ret; +} + +static void load_security_variables(struct hfi1_devdata *dd, + struct firmware_details *fdet) +{ + /* Security variables a. Write the modulus */ + write_rsa_data(dd, MISC_CFG_RSA_MODULUS, fdet->modulus, KEY_SIZE); + /* Security variables b. Write the r2 */ + write_rsa_data(dd, MISC_CFG_RSA_R2, fdet->r2, KEY_SIZE); + /* Security variables c. Write the mu */ + write_rsa_data(dd, MISC_CFG_RSA_MU, fdet->mu, MU_SIZE); + /* Security variables d. Write the header */ + write_streamed_rsa_data(dd, MISC_CFG_SHA_PRELOAD, + (u8 *)fdet->css_header, sizeof(struct css_header)); +} + +/* return the 8051 firmware state */ +static inline u32 get_firmware_state(struct hfi1_devdata *dd) +{ + u64 reg = read_csr(dd, DC_DC8051_STS_CUR_STATE); + + return (reg >> DC_DC8051_STS_CUR_STATE_FIRMWARE_SHIFT) + & DC_DC8051_STS_CUR_STATE_FIRMWARE_MASK; +} + +/* + * Wait until the firmware is up and ready to take host requests. + * Return 0 on success, -ETIMEDOUT on timeout. + */ +int wait_fm_ready(struct hfi1_devdata *dd, u32 mstimeout) +{ + unsigned long timeout; + + /* in the simulator, the fake 8051 is always ready */ + if (dd->icode == ICODE_FUNCTIONAL_SIMULATOR) + return 0; + + timeout = msecs_to_jiffies(mstimeout) + jiffies; + while (1) { + if (get_firmware_state(dd) == 0xa0) /* ready */ + return 0; + if (time_after(jiffies, timeout)) /* timed out */ + return -ETIMEDOUT; + usleep_range(1950, 2050); /* sleep 2ms-ish */ + } +} + +/* + * Load the 8051 firmware. + */ +static int load_8051_firmware(struct hfi1_devdata *dd, + struct firmware_details *fdet) +{ + u64 reg; + int ret; + u8 ver_a, ver_b; + + /* + * DC Reset sequence + * Load DC 8051 firmware + */ + /* + * DC reset step 1: Reset DC8051 + */ + reg = DC_DC8051_CFG_RST_M8051W_SMASK + | DC_DC8051_CFG_RST_CRAM_SMASK + | DC_DC8051_CFG_RST_DRAM_SMASK + | DC_DC8051_CFG_RST_IRAM_SMASK + | DC_DC8051_CFG_RST_SFR_SMASK; + write_csr(dd, DC_DC8051_CFG_RST, reg); + + /* + * DC reset step 2 (optional): Load 8051 data memory with link + * configuration + */ + + /* + * DC reset step 3: Load DC8051 firmware + */ + /* release all but the core reset */ + reg = DC_DC8051_CFG_RST_M8051W_SMASK; + write_csr(dd, DC_DC8051_CFG_RST, reg); + + /* Firmware load step 1 */ + load_security_variables(dd, fdet); + + /* + * Firmware load step 2. Clear MISC_CFG_FW_CTRL.FW_8051_LOADED + */ + write_csr(dd, MISC_CFG_FW_CTRL, 0); + + /* Firmware load steps 3-5 */ + ret = write_8051(dd, 1/*code*/, 0, fdet->firmware_ptr, + fdet->firmware_len); + if (ret) + return ret; + + /* + * DC reset step 4. Host starts the DC8051 firmware + */ + /* + * Firmware load step 6. Set MISC_CFG_FW_CTRL.FW_8051_LOADED + */ + write_csr(dd, MISC_CFG_FW_CTRL, MISC_CFG_FW_CTRL_FW_8051_LOADED_SMASK); + + /* Firmware load steps 7-10 */ + ret = run_rsa(dd, "8051", fdet->signature); + if (ret) + return ret; + + /* clear all reset bits, releasing the 8051 */ + write_csr(dd, DC_DC8051_CFG_RST, 0ull); + + /* + * DC reset step 5. Wait for firmware to be ready to accept host + * requests. + */ + ret = wait_fm_ready(dd, TIMEOUT_8051_START); + if (ret) { /* timed out */ + dd_dev_err(dd, "8051 start timeout, current state 0x%x\n", + get_firmware_state(dd)); + return -ETIMEDOUT; + } + + read_misc_status(dd, &ver_a, &ver_b); + dd_dev_info(dd, "8051 firmware version %d.%d\n", + (int)ver_b, (int)ver_a); + dd->dc8051_ver = dc8051_ver(ver_b, ver_a); + + return 0; +} + +/* SBus Master broadcast address */ +#define SBUS_MASTER_BROADCAST 0xfd + +/* + * Write the SBus request register + * + * No need for masking - the arguments are sized exactly. + */ +void sbus_request(struct hfi1_devdata *dd, + u8 receiver_addr, u8 data_addr, u8 command, u32 data_in) +{ + write_csr(dd, ASIC_CFG_SBUS_REQUEST, + ((u64)data_in << ASIC_CFG_SBUS_REQUEST_DATA_IN_SHIFT) + | ((u64)command << ASIC_CFG_SBUS_REQUEST_COMMAND_SHIFT) + | ((u64)data_addr << ASIC_CFG_SBUS_REQUEST_DATA_ADDR_SHIFT) + | ((u64)receiver_addr + << ASIC_CFG_SBUS_REQUEST_RECEIVER_ADDR_SHIFT)); +} + +/* + * Turn off the SBus and fabric serdes spicos. + * + * + Must be called with Sbus fast mode turned on. + * + Must be called after fabric serdes broadcast is set up. + * + Must be called before the 8051 is loaded - assumes 8051 is not loaded + * when using MISC_CFG_FW_CTRL. + */ +static void turn_off_spicos(struct hfi1_devdata *dd, int flags) +{ + /* only needed on A0 */ + if (!is_a0(dd)) + return; + + dd_dev_info(dd, "Turning off spicos:%s%s\n", + flags & SPICO_SBUS ? " SBus" : "", + flags & SPICO_FABRIC ? " fabric" : ""); + + write_csr(dd, MISC_CFG_FW_CTRL, ENABLE_SPICO_SMASK); + /* disable SBus spico */ + if (flags & SPICO_SBUS) + sbus_request(dd, SBUS_MASTER_BROADCAST, 0x01, + WRITE_SBUS_RECEIVER, 0x00000040); + + /* disable the fabric serdes spicos */ + if (flags & SPICO_FABRIC) + sbus_request(dd, fabric_serdes_broadcast[dd->hfi1_id], + 0x07, WRITE_SBUS_RECEIVER, 0x00000000); + write_csr(dd, MISC_CFG_FW_CTRL, 0); +} + +/* + * Reset all of the fabric serdes for our HFI. + */ +void fabric_serdes_reset(struct hfi1_devdata *dd) +{ + u8 ra; + + if (dd->icode != ICODE_RTL_SILICON) /* only for RTL */ + return; + + ra = fabric_serdes_broadcast[dd->hfi1_id]; + + acquire_hw_mutex(dd); + set_sbus_fast_mode(dd); + /* place SerDes in reset and disable SPICO */ + sbus_request(dd, ra, 0x07, WRITE_SBUS_RECEIVER, 0x00000011); + /* wait 100 refclk cycles @ 156.25MHz => 640ns */ + udelay(1); + /* remove SerDes reset */ + sbus_request(dd, ra, 0x07, WRITE_SBUS_RECEIVER, 0x00000010); + /* turn SPICO enable on */ + sbus_request(dd, ra, 0x07, WRITE_SBUS_RECEIVER, 0x00000002); + clear_sbus_fast_mode(dd); + release_hw_mutex(dd); +} + +/* Access to the SBus in this routine should probably be serialized */ +int sbus_request_slow(struct hfi1_devdata *dd, + u8 receiver_addr, u8 data_addr, u8 command, u32 data_in) +{ + u64 reg, count = 0; + + sbus_request(dd, receiver_addr, data_addr, command, data_in); + write_csr(dd, ASIC_CFG_SBUS_EXECUTE, + ASIC_CFG_SBUS_EXECUTE_EXECUTE_SMASK); + /* Wait for both DONE and RCV_DATA_VALID to go high */ + reg = read_csr(dd, ASIC_STS_SBUS_RESULT); + while (!((reg & ASIC_STS_SBUS_RESULT_DONE_SMASK) && + (reg & ASIC_STS_SBUS_RESULT_RCV_DATA_VALID_SMASK))) { + if (count++ >= SBUS_MAX_POLL_COUNT) { + u64 counts = read_csr(dd, ASIC_STS_SBUS_COUNTERS); + /* + * If the loop has timed out, we are OK if DONE bit + * is set and RCV_DATA_VALID and EXECUTE counters + * are the same. If not, we cannot proceed. + */ + if ((reg & ASIC_STS_SBUS_RESULT_DONE_SMASK) && + (SBUS_COUNTER(counts, RCV_DATA_VALID) == + SBUS_COUNTER(counts, EXECUTE))) + break; + return -ETIMEDOUT; + } + udelay(1); + reg = read_csr(dd, ASIC_STS_SBUS_RESULT); + } + count = 0; + write_csr(dd, ASIC_CFG_SBUS_EXECUTE, 0); + /* Wait for DONE to clear after EXECUTE is cleared */ + reg = read_csr(dd, ASIC_STS_SBUS_RESULT); + while (reg & ASIC_STS_SBUS_RESULT_DONE_SMASK) { + if (count++ >= SBUS_MAX_POLL_COUNT) + return -ETIME; + udelay(1); + reg = read_csr(dd, ASIC_STS_SBUS_RESULT); + } + return 0; +} + +static int load_fabric_serdes_firmware(struct hfi1_devdata *dd, + struct firmware_details *fdet) +{ + int i, err; + const u8 ra = fabric_serdes_broadcast[dd->hfi1_id]; /* receiver addr */ + + dd_dev_info(dd, "Downloading fabric firmware\n"); + + /* step 1: load security variables */ + load_security_variables(dd, fdet); + /* step 2: place SerDes in reset and disable SPICO */ + sbus_request(dd, ra, 0x07, WRITE_SBUS_RECEIVER, 0x00000011); + /* wait 100 refclk cycles @ 156.25MHz => 640ns */ + udelay(1); + /* step 3: remove SerDes reset */ + sbus_request(dd, ra, 0x07, WRITE_SBUS_RECEIVER, 0x00000010); + /* step 4: assert IMEM override */ + sbus_request(dd, ra, 0x00, WRITE_SBUS_RECEIVER, 0x40000000); + /* step 5: download SerDes machine code */ + for (i = 0; i < fdet->firmware_len; i += 4) { + sbus_request(dd, ra, 0x0a, WRITE_SBUS_RECEIVER, + *(u32 *)&fdet->firmware_ptr[i]); + } + /* step 6: IMEM override off */ + sbus_request(dd, ra, 0x00, WRITE_SBUS_RECEIVER, 0x00000000); + /* step 7: turn ECC on */ + sbus_request(dd, ra, 0x0b, WRITE_SBUS_RECEIVER, 0x000c0000); + + /* steps 8-11: run the RSA engine */ + err = run_rsa(dd, "fabric serdes", fdet->signature); + if (err) + return err; + + /* step 12: turn SPICO enable on */ + sbus_request(dd, ra, 0x07, WRITE_SBUS_RECEIVER, 0x00000002); + /* step 13: enable core hardware interrupts */ + sbus_request(dd, ra, 0x08, WRITE_SBUS_RECEIVER, 0x00000000); + + return 0; +} + +static int load_sbus_firmware(struct hfi1_devdata *dd, + struct firmware_details *fdet) +{ + int i, err; + const u8 ra = SBUS_MASTER_BROADCAST; /* receiver address */ + + dd_dev_info(dd, "Downloading SBus firmware\n"); + + /* step 1: load security variables */ + load_security_variables(dd, fdet); + /* step 2: place SPICO into reset and enable off */ + sbus_request(dd, ra, 0x01, WRITE_SBUS_RECEIVER, 0x000000c0); + /* step 3: remove reset, enable off, IMEM_CNTRL_EN on */ + sbus_request(dd, ra, 0x01, WRITE_SBUS_RECEIVER, 0x00000240); + /* step 4: set starting IMEM address for burst download */ + sbus_request(dd, ra, 0x03, WRITE_SBUS_RECEIVER, 0x80000000); + /* step 5: download the SBus Master machine code */ + for (i = 0; i < fdet->firmware_len; i += 4) { + sbus_request(dd, ra, 0x14, WRITE_SBUS_RECEIVER, + *(u32 *)&fdet->firmware_ptr[i]); + } + /* step 6: set IMEM_CNTL_EN off */ + sbus_request(dd, ra, 0x01, WRITE_SBUS_RECEIVER, 0x00000040); + /* step 7: turn ECC on */ + sbus_request(dd, ra, 0x16, WRITE_SBUS_RECEIVER, 0x000c0000); + + /* steps 8-11: run the RSA engine */ + err = run_rsa(dd, "SBus", fdet->signature); + if (err) + return err; + + /* step 12: set SPICO_ENABLE on */ + sbus_request(dd, ra, 0x01, WRITE_SBUS_RECEIVER, 0x00000140); + + return 0; +} + +static int load_pcie_serdes_firmware(struct hfi1_devdata *dd, + struct firmware_details *fdet) +{ + int i; + const u8 ra = SBUS_MASTER_BROADCAST; /* receiver address */ + + dd_dev_info(dd, "Downloading PCIe firmware\n"); + + /* step 1: load security variables */ + load_security_variables(dd, fdet); + /* step 2: assert single step (halts the SBus Master spico) */ + sbus_request(dd, ra, 0x05, WRITE_SBUS_RECEIVER, 0x00000001); + /* step 3: enable XDMEM access */ + sbus_request(dd, ra, 0x01, WRITE_SBUS_RECEIVER, 0x00000d40); + /* step 4: load firmware into SBus Master XDMEM */ + /* NOTE: the dmem address, write_en, and wdata are all pre-packed, + we only need to pick up the bytes and write them */ + for (i = 0; i < fdet->firmware_len; i += 4) { + sbus_request(dd, ra, 0x04, WRITE_SBUS_RECEIVER, + *(u32 *)&fdet->firmware_ptr[i]); + } + /* step 5: disable XDMEM access */ + sbus_request(dd, ra, 0x01, WRITE_SBUS_RECEIVER, 0x00000140); + /* step 6: allow SBus Spico to run */ + sbus_request(dd, ra, 0x05, WRITE_SBUS_RECEIVER, 0x00000000); + + /* steps 7-11: run RSA, if it succeeds, firmware is available to + be swapped */ + return run_rsa(dd, "PCIe serdes", fdet->signature); +} + +/* + * Set the given broadcast values on the given list of devices. + */ +static void set_serdes_broadcast(struct hfi1_devdata *dd, u8 bg1, u8 bg2, + const u8 *addrs, int count) +{ + while (--count >= 0) { + /* + * Set BROADCAST_GROUP_1 and BROADCAST_GROUP_2, leave + * defaults for everything else. Do not read-modify-write, + * per instruction from the manufacturer. + * + * Register 0xfd: + * bits what + * ----- --------------------------------- + * 0 IGNORE_BROADCAST (default 0) + * 11:4 BROADCAST_GROUP_1 (default 0xff) + * 23:16 BROADCAST_GROUP_2 (default 0xff) + */ + sbus_request(dd, addrs[count], 0xfd, WRITE_SBUS_RECEIVER, + (u32)bg1 << 4 | (u32)bg2 << 16); + } +} + +int acquire_hw_mutex(struct hfi1_devdata *dd) +{ + unsigned long timeout; + int try = 0; + u8 mask = 1 << dd->hfi1_id; + u8 user; + +retry: + timeout = msecs_to_jiffies(HM_TIMEOUT) + jiffies; + while (1) { + write_csr(dd, ASIC_CFG_MUTEX, mask); + user = (u8)read_csr(dd, ASIC_CFG_MUTEX); + if (user == mask) + return 0; /* success */ + if (time_after(jiffies, timeout)) + break; /* timed out */ + msleep(20); + } + + /* timed out */ + dd_dev_err(dd, + "Unable to acquire hardware mutex, mutex mask %u, my mask %u (%s)\n", + (u32)user, (u32)mask, (try == 0) ? "retrying" : "giving up"); + + if (try == 0) { + /* break mutex and retry */ + write_csr(dd, ASIC_CFG_MUTEX, 0); + try++; + goto retry; + } + + return -EBUSY; +} + +void release_hw_mutex(struct hfi1_devdata *dd) +{ + write_csr(dd, ASIC_CFG_MUTEX, 0); +} + +void set_sbus_fast_mode(struct hfi1_devdata *dd) +{ + write_csr(dd, ASIC_CFG_SBUS_EXECUTE, + ASIC_CFG_SBUS_EXECUTE_FAST_MODE_SMASK); +} + +void clear_sbus_fast_mode(struct hfi1_devdata *dd) +{ + u64 reg, count = 0; + + reg = read_csr(dd, ASIC_STS_SBUS_COUNTERS); + while (SBUS_COUNTER(reg, EXECUTE) != + SBUS_COUNTER(reg, RCV_DATA_VALID)) { + if (count++ >= SBUS_MAX_POLL_COUNT) + break; + udelay(1); + reg = read_csr(dd, ASIC_STS_SBUS_COUNTERS); + } + write_csr(dd, ASIC_CFG_SBUS_EXECUTE, 0); +} + +int load_firmware(struct hfi1_devdata *dd) +{ + int ret; + + if (fw_sbus_load || fw_fabric_serdes_load) { + ret = acquire_hw_mutex(dd); + if (ret) + return ret; + + set_sbus_fast_mode(dd); + + /* + * The SBus contains part of the fabric firmware and so must + * also be downloaded. + */ + if (fw_sbus_load) { + turn_off_spicos(dd, SPICO_SBUS); + ret = load_sbus_firmware(dd, &fw_sbus); + if (ret) + goto clear; + } + + if (fw_fabric_serdes_load) { + set_serdes_broadcast(dd, all_fabric_serdes_broadcast, + fabric_serdes_broadcast[dd->hfi1_id], + fabric_serdes_addrs[dd->hfi1_id], + NUM_FABRIC_SERDES); + turn_off_spicos(dd, SPICO_FABRIC); + ret = load_fabric_serdes_firmware(dd, &fw_fabric); + } + +clear: + clear_sbus_fast_mode(dd); + release_hw_mutex(dd); + if (ret) + return ret; + } + + if (fw_8051_load) { + ret = load_8051_firmware(dd, &fw_8051); + if (ret) + return ret; + } + + return 0; +} + +int hfi1_firmware_init(struct hfi1_devdata *dd) +{ + /* only RTL can use these */ + if (dd->icode != ICODE_RTL_SILICON) { + fw_fabric_serdes_load = 0; + fw_pcie_serdes_load = 0; + fw_sbus_load = 0; + } + + /* no 8051 or QSFP on simulator */ + if (dd->icode == ICODE_FUNCTIONAL_SIMULATOR) { + fw_8051_load = 0; + platform_config_load = 0; + } + + if (!fw_8051_name) { + if (dd->icode == ICODE_RTL_SILICON) + fw_8051_name = DEFAULT_FW_8051_NAME_ASIC; + else + fw_8051_name = DEFAULT_FW_8051_NAME_FPGA; + } + if (!fw_fabric_serdes_name) + fw_fabric_serdes_name = DEFAULT_FW_FABRIC_NAME; + if (!fw_sbus_name) + fw_sbus_name = DEFAULT_FW_SBUS_NAME; + if (!fw_pcie_serdes_name) + fw_pcie_serdes_name = DEFAULT_FW_PCIE_NAME; + if (!platform_config_name) + platform_config_name = DEFAULT_PLATFORM_CONFIG_NAME; + + return obtain_firmware(dd); +} + +int parse_platform_config(struct hfi1_devdata *dd) +{ + struct platform_config_cache *pcfgcache = &dd->pcfg_cache; + u32 *ptr = NULL; + u32 header1 = 0, header2 = 0, magic_num = 0, crc = 0; + u32 record_idx = 0, table_type = 0, table_length_dwords = 0; + + if (platform_config == NULL) { + dd_dev_info(dd, "%s: Missing config file\n", __func__); + goto bail; + } + ptr = (u32 *)platform_config->data; + + magic_num = *ptr; + ptr++; + if (magic_num != PLATFORM_CONFIG_MAGIC_NUM) { + dd_dev_info(dd, "%s: Bad config file\n", __func__); + goto bail; + } + + while (ptr < (u32 *)(platform_config->data + platform_config->size)) { + header1 = *ptr; + header2 = *(ptr + 1); + if (header1 != ~header2) { + dd_dev_info(dd, "%s: Failed validation at offset %ld\n", + __func__, (ptr - (u32 *)platform_config->data)); + goto bail; + } + + record_idx = *ptr & + ((1 << PLATFORM_CONFIG_HEADER_RECORD_IDX_LEN_BITS) - 1); + + table_length_dwords = (*ptr >> + PLATFORM_CONFIG_HEADER_TABLE_LENGTH_SHIFT) & + ((1 << PLATFORM_CONFIG_HEADER_TABLE_LENGTH_LEN_BITS) - 1); + + table_type = (*ptr >> PLATFORM_CONFIG_HEADER_TABLE_TYPE_SHIFT) & + ((1 << PLATFORM_CONFIG_HEADER_TABLE_TYPE_LEN_BITS) - 1); + + /* Done with this set of headers */ + ptr += 2; + + if (record_idx) { + /* data table */ + switch (table_type) { + case PLATFORM_CONFIG_SYSTEM_TABLE: + pcfgcache->config_tables[table_type].num_table = + 1; + break; + case PLATFORM_CONFIG_PORT_TABLE: + pcfgcache->config_tables[table_type].num_table = + 2; + break; + case PLATFORM_CONFIG_RX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_TX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_QSFP_ATTEN_TABLE: + /* fall through */ + case PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE: + pcfgcache->config_tables[table_type].num_table = + table_length_dwords; + break; + default: + dd_dev_info(dd, + "%s: Unknown data table %d, offset %ld\n", + __func__, table_type, + (ptr - (u32 *)platform_config->data)); + goto bail; /* We don't trust this file now */ + } + pcfgcache->config_tables[table_type].table = ptr; + } else { + /* metadata table */ + switch (table_type) { + case PLATFORM_CONFIG_SYSTEM_TABLE: + /* fall through */ + case PLATFORM_CONFIG_PORT_TABLE: + /* fall through */ + case PLATFORM_CONFIG_RX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_TX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_QSFP_ATTEN_TABLE: + /* fall through */ + case PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE: + break; + default: + dd_dev_info(dd, + "%s: Unknown metadata table %d, offset %ld\n", + __func__, table_type, + (ptr - (u32 *)platform_config->data)); + goto bail; /* We don't trust this file now */ + } + pcfgcache->config_tables[table_type].table_metadata = + ptr; + } + + /* Calculate and check table crc */ + crc = crc32_le(~(u32)0, (unsigned char const *)ptr, + (table_length_dwords * 4)); + crc ^= ~(u32)0; + + /* Jump the table */ + ptr += table_length_dwords; + if (crc != *ptr) { + dd_dev_info(dd, "%s: Failed CRC check at offset %ld\n", + __func__, (ptr - (u32 *)platform_config->data)); + goto bail; + } + /* Jump the CRC DWORD */ + ptr++; + } + + pcfgcache->cache_valid = 1; + return 0; +bail: + memset(pcfgcache, 0, sizeof(struct platform_config_cache)); + return -EINVAL; +} + +static int get_platform_fw_field_metadata(struct hfi1_devdata *dd, int table, + int field, u32 *field_len_bits, u32 *field_start_bits) +{ + struct platform_config_cache *pcfgcache = &dd->pcfg_cache; + u32 *src_ptr = NULL; + + if (!pcfgcache->cache_valid) + return -EINVAL; + + switch (table) { + case PLATFORM_CONFIG_SYSTEM_TABLE: + /* fall through */ + case PLATFORM_CONFIG_PORT_TABLE: + /* fall through */ + case PLATFORM_CONFIG_RX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_TX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_QSFP_ATTEN_TABLE: + /* fall through */ + case PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE: + if (field && field < platform_config_table_limits[table]) + src_ptr = + pcfgcache->config_tables[table].table_metadata + field; + break; + default: + dd_dev_info(dd, "%s: Unknown table\n", __func__); + break; + } + + if (!src_ptr) + return -EINVAL; + + if (field_start_bits) + *field_start_bits = *src_ptr & + ((1 << METADATA_TABLE_FIELD_START_LEN_BITS) - 1); + + if (field_len_bits) + *field_len_bits = (*src_ptr >> METADATA_TABLE_FIELD_LEN_SHIFT) + & ((1 << METADATA_TABLE_FIELD_LEN_LEN_BITS) - 1); + + return 0; +} + +/* This is the central interface to getting data out of the platform config + * file. It depends on parse_platform_config() having populated the + * platform_config_cache in hfi1_devdata, and checks the cache_valid member to + * validate the sanity of the cache. + * + * The non-obvious parameters: + * @table_index: Acts as a look up key into which instance of the tables the + * relevant field is fetched from. + * + * This applies to the data tables that have multiple instances. The port table + * is an exception to this rule as each HFI only has one port and thus the + * relevant table can be distinguished by hfi_id. + * + * @data: pointer to memory that will be populated with the field requested. + * @len: length of memory pointed by @data in bytes. + */ +int get_platform_config_field(struct hfi1_devdata *dd, + enum platform_config_table_type_encoding table_type, + int table_index, int field_index, u32 *data, u32 len) +{ + int ret = 0, wlen = 0, seek = 0; + u32 field_len_bits = 0, field_start_bits = 0, *src_ptr = NULL; + struct platform_config_cache *pcfgcache = &dd->pcfg_cache; + + if (data) + memset(data, 0, len); + else + return -EINVAL; + + ret = get_platform_fw_field_metadata(dd, table_type, field_index, + &field_len_bits, &field_start_bits); + if (ret) + return -EINVAL; + + /* Convert length to bits */ + len *= 8; + + /* Our metadata function checked cache_valid and field_index for us */ + switch (table_type) { + case PLATFORM_CONFIG_SYSTEM_TABLE: + src_ptr = pcfgcache->config_tables[table_type].table; + + if (field_index != SYSTEM_TABLE_QSFP_POWER_CLASS_MAX) { + if (len < field_len_bits) + return -EINVAL; + + seek = field_start_bits/8; + wlen = field_len_bits/8; + + src_ptr = (u32 *)((u8 *)src_ptr + seek); + + /* We expect the field to be byte aligned and whole byte + * lengths if we are here */ + memcpy(data, src_ptr, wlen); + return 0; + } + break; + case PLATFORM_CONFIG_PORT_TABLE: + /* Port table is 4 DWORDS in META_VERSION 0 */ + src_ptr = dd->hfi1_id ? + pcfgcache->config_tables[table_type].table + 4 : + pcfgcache->config_tables[table_type].table; + break; + case PLATFORM_CONFIG_RX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_TX_PRESET_TABLE: + /* fall through */ + case PLATFORM_CONFIG_QSFP_ATTEN_TABLE: + /* fall through */ + case PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE: + src_ptr = pcfgcache->config_tables[table_type].table; + + if (table_index < + pcfgcache->config_tables[table_type].num_table) + src_ptr += table_index; + else + src_ptr = NULL; + break; + default: + dd_dev_info(dd, "%s: Unknown table\n", __func__); + break; + } + + if (!src_ptr || len < field_len_bits) + return -EINVAL; + + src_ptr += (field_start_bits/32); + *data = (*src_ptr >> (field_start_bits % 32)) & + ((1 << field_len_bits) - 1); + + return 0; +} + +/* + * Download the firmware needed for the Gen3 PCIe SerDes. An update + * to the SBus firmware is needed before updating the PCIe firmware. + * + * Note: caller must be holding the HW mutex. + */ +int load_pcie_firmware(struct hfi1_devdata *dd) +{ + int ret = 0; + + /* both firmware loads below use the SBus */ + set_sbus_fast_mode(dd); + + if (fw_sbus_load) { + turn_off_spicos(dd, SPICO_SBUS); + ret = load_sbus_firmware(dd, &fw_sbus); + if (ret) + goto done; + } + + if (fw_pcie_serdes_load) { + dd_dev_info(dd, "Setting PCIe SerDes broadcast\n"); + set_serdes_broadcast(dd, all_pcie_serdes_broadcast, + pcie_serdes_broadcast[dd->hfi1_id], + pcie_serdes_addrs[dd->hfi1_id], + NUM_PCIE_SERDES); + ret = load_pcie_serdes_firmware(dd, &fw_pcie); + if (ret) + goto done; + } + +done: + clear_sbus_fast_mode(dd); + + return ret; +} + +/* + * Read the GUID from the hardware, store it in dd. + */ +void read_guid(struct hfi1_devdata *dd) +{ + dd->base_guid = read_csr(dd, DC_DC8051_CFG_LOCAL_GUID); + dd_dev_info(dd, "GUID %llx", + (unsigned long long)dd->base_guid); +} diff --git a/drivers/staging/rdma/hfi1/hfi.h b/drivers/staging/rdma/hfi1/hfi.h new file mode 100644 index 0000000000000..8ca171bf3e36c --- /dev/null +++ b/drivers/staging/rdma/hfi1/hfi.h @@ -0,0 +1,1821 @@ +#ifndef _HFI1_KERNEL_H +#define _HFI1_KERNEL_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "chip_registers.h" +#include "common.h" +#include "verbs.h" +#include "pio.h" +#include "chip.h" +#include "mad.h" +#include "qsfp.h" +#include "platform_config.h" + +/* bumped 1 from s/w major version of TrueScale */ +#define HFI1_CHIP_VERS_MAJ 3U + +/* don't care about this except printing */ +#define HFI1_CHIP_VERS_MIN 0U + +/* The Organization Unique Identifier (Mfg code), and its position in GUID */ +#define HFI1_OUI 0x001175 +#define HFI1_OUI_LSB 40 + +#define DROP_PACKET_OFF 0 +#define DROP_PACKET_ON 1 + +extern unsigned long hfi1_cap_mask; +#define HFI1_CAP_KGET_MASK(mask, cap) ((mask) & HFI1_CAP_##cap) +#define HFI1_CAP_UGET_MASK(mask, cap) \ + (((mask) >> HFI1_CAP_USER_SHIFT) & HFI1_CAP_##cap) +#define HFI1_CAP_KGET(cap) (HFI1_CAP_KGET_MASK(hfi1_cap_mask, cap)) +#define HFI1_CAP_UGET(cap) (HFI1_CAP_UGET_MASK(hfi1_cap_mask, cap)) +#define HFI1_CAP_IS_KSET(cap) (!!HFI1_CAP_KGET(cap)) +#define HFI1_CAP_IS_USET(cap) (!!HFI1_CAP_UGET(cap)) +#define HFI1_MISC_GET() ((hfi1_cap_mask >> HFI1_CAP_MISC_SHIFT) & \ + HFI1_CAP_MISC_MASK) + +/* + * per driver stats, either not device nor port-specific, or + * summed over all of the devices and ports. + * They are described by name via ipathfs filesystem, so layout + * and number of elements can change without breaking compatibility. + * If members are added or deleted hfi1_statnames[] in debugfs.c must + * change to match. + */ +struct hfi1_ib_stats { + __u64 sps_ints; /* number of interrupts handled */ + __u64 sps_errints; /* number of error interrupts */ + __u64 sps_txerrs; /* tx-related packet errors */ + __u64 sps_rcverrs; /* non-crc rcv packet errors */ + __u64 sps_hwerrs; /* hardware errors reported (parity, etc.) */ + __u64 sps_nopiobufs; /* no pio bufs avail from kernel */ + __u64 sps_ctxts; /* number of contexts currently open */ + __u64 sps_lenerrs; /* number of kernel packets where RHF != LRH len */ + __u64 sps_buffull; + __u64 sps_hdrfull; +}; + +extern struct hfi1_ib_stats hfi1_stats; +extern const struct pci_error_handlers hfi1_pci_err_handler; + +/* + * First-cut criterion for "device is active" is + * two thousand dwords combined Tx, Rx traffic per + * 5-second interval. SMA packets are 64 dwords, + * and occur "a few per second", presumably each way. + */ +#define HFI1_TRAFFIC_ACTIVE_THRESHOLD (2000) + +/* + * Below contains all data related to a single context (formerly called port). + */ + +#ifdef CONFIG_DEBUG_FS +struct hfi1_opcode_stats_perctx; +#endif + +/* + * struct ps_state keeps state associated with RX queue "prescanning" + * (prescanning for FECNs, and BECNs), if prescanning is in use. + */ +struct ps_state { + u32 ps_head; + int initialized; +}; + +struct ctxt_eager_bufs { + ssize_t size; /* total size of eager buffers */ + u32 count; /* size of buffers array */ + u32 numbufs; /* number of buffers allocated */ + u32 alloced; /* number of rcvarray entries used */ + u32 rcvtid_size; /* size of each eager rcv tid */ + u32 threshold; /* head update threshold */ + struct eager_buffer { + void *addr; + dma_addr_t phys; + ssize_t len; + } *buffers; + struct { + void *addr; + dma_addr_t phys; + } *rcvtids; +}; + +struct hfi1_ctxtdata { + /* shadow the ctxt's RcvCtrl register */ + u64 rcvctrl; + /* rcvhdrq base, needs mmap before useful */ + void *rcvhdrq; + /* kernel virtual address where hdrqtail is updated */ + volatile __le64 *rcvhdrtail_kvaddr; + /* + * Shared page for kernel to signal user processes that send buffers + * need disarming. The process should call HFI1_CMD_DISARM_BUFS + * or HFI1_CMD_ACK_EVENT with IPATH_EVENT_DISARM_BUFS set. + */ + unsigned long *user_event_mask; + /* when waiting for rcv or pioavail */ + wait_queue_head_t wait; + /* rcvhdrq size (for freeing) */ + size_t rcvhdrq_size; + /* number of rcvhdrq entries */ + u16 rcvhdrq_cnt; + /* size of each of the rcvhdrq entries */ + u16 rcvhdrqentsize; + /* mmap of hdrq, must fit in 44 bits */ + dma_addr_t rcvhdrq_phys; + dma_addr_t rcvhdrqtailaddr_phys; + struct ctxt_eager_bufs egrbufs; + /* this receive context's assigned PIO ACK send context */ + struct send_context *sc; + + /* dynamic receive available interrupt timeout */ + u32 rcvavail_timeout; + /* + * number of opens (including slave sub-contexts) on this instance + * (ignoring forks, dup, etc. for now) + */ + int cnt; + /* + * how much space to leave at start of eager TID entries for + * protocol use, on each TID + */ + /* instead of calculating it */ + unsigned ctxt; + /* non-zero if ctxt is being shared. */ + u16 subctxt_cnt; + /* non-zero if ctxt is being shared. */ + u16 subctxt_id; + u8 uuid[16]; + /* job key */ + u16 jkey; + /* number of RcvArray groups for this context. */ + u32 rcv_array_groups; + /* index of first eager TID entry. */ + u32 eager_base; + /* number of expected TID entries */ + u32 expected_count; + /* index of first expected TID entry. */ + u32 expected_base; + /* cursor into the exp group sets */ + atomic_t tidcursor; + /* number of exp TID groups assigned to the ctxt */ + u16 numtidgroups; + /* size of exp TID group fields in tidusemap */ + u16 tidmapcnt; + /* exp TID group usage bitfield array */ + unsigned long *tidusemap; + /* pinned pages for exp sends, allocated at open */ + struct page **tid_pg_list; + /* dma handles for exp tid pages */ + dma_addr_t *physshadow; + /* lock protecting all Expected TID data */ + spinlock_t exp_lock; + /* number of pio bufs for this ctxt (all procs, if shared) */ + u32 piocnt; + /* first pio buffer for this ctxt */ + u32 pio_base; + /* chip offset of PIO buffers for this ctxt */ + u32 piobufs; + /* per-context configuration flags */ + u16 flags; + /* per-context event flags for fileops/intr communication */ + unsigned long event_flags; + /* WAIT_RCV that timed out, no interrupt */ + u32 rcvwait_to; + /* WAIT_PIO that timed out, no interrupt */ + u32 piowait_to; + /* WAIT_RCV already happened, no wait */ + u32 rcvnowait; + /* WAIT_PIO already happened, no wait */ + u32 pionowait; + /* total number of polled urgent packets */ + u32 urgent; + /* saved total number of polled urgent packets for poll edge trigger */ + u32 urgent_poll; + /* pid of process using this ctxt */ + pid_t pid; + pid_t subpid[HFI1_MAX_SHARED_CTXTS]; + /* same size as task_struct .comm[], command that opened context */ + char comm[16]; + /* so file ops can get at unit */ + struct hfi1_devdata *dd; + /* so functions that need physical port can get it easily */ + struct hfi1_pportdata *ppd; + /* A page of memory for rcvhdrhead, rcvegrhead, rcvegrtail * N */ + void *subctxt_uregbase; + /* An array of pages for the eager receive buffers * N */ + void *subctxt_rcvegrbuf; + /* An array of pages for the eager header queue entries * N */ + void *subctxt_rcvhdr_base; + /* The version of the library which opened this ctxt */ + u32 userversion; + /* Bitmask of active slaves */ + u32 active_slaves; + /* Type of packets or conditions we want to poll for */ + u16 poll_type; + /* receive packet sequence counter */ + u8 seq_cnt; + u8 redirect_seq_cnt; + /* ctxt rcvhdrq head offset */ + u32 head; + u32 pkt_count; + /* QPs waiting for context processing */ + struct list_head qp_wait_list; + /* interrupt handling */ + u64 imask; /* clear interrupt mask */ + int ireg; /* clear interrupt register */ + unsigned numa_id; /* numa node of this context */ + /* verbs stats per CTX */ + struct hfi1_opcode_stats_perctx *opstats; + /* + * This is the kernel thread that will keep making + * progress on the user sdma requests behind the scenes. + * There is one per context (shared contexts use the master's). + */ + struct task_struct *progress; + struct list_head sdma_queues; + spinlock_t sdma_qlock; + +#ifdef CONFIG_PRESCAN_RXQ + struct ps_state ps_state; +#endif /* CONFIG_PRESCAN_RXQ */ + + /* + * The interrupt handler for a particular receive context can vary + * throughout it's lifetime. This is not a lock protected data member so + * it must be updated atomically and the prev and new value must always + * be valid. Worst case is we process an extra interrupt and up to 64 + * packets with the wrong interrupt handler. + */ + void (*do_interrupt)(struct hfi1_ctxtdata *rcd); +}; + +/* + * Represents a single packet at a high level. Put commonly computed things in + * here so we do not have to keep doing them over and over. The rule of thumb is + * if something is used one time to derive some value, store that something in + * here. If it is used multiple times, then store the result of that derivation + * in here. + */ +struct hfi1_packet { + void *ebuf; + void *hdr; + struct hfi1_ctxtdata *rcd; + __le32 *rhf_addr; + struct hfi1_qp *qp; + struct hfi1_other_headers *ohdr; + u64 rhf; + u32 maxcnt; + u32 rhqoff; + u32 hdrqtail; + int numpkt; + u16 tlen; + u16 hlen; + s16 etail; + u16 rsize; + u8 updegr; + u8 rcv_flags; + u8 etype; +}; + +static inline bool has_sc4_bit(struct hfi1_packet *p) +{ + return !!rhf_dc_info(p->rhf); +} + +/* + * Private data for snoop/capture support. + */ +struct hfi1_snoop_data { + int mode_flag; + struct cdev cdev; + struct device *class_dev; + spinlock_t snoop_lock; + struct list_head queue; + wait_queue_head_t waitq; + void *filter_value; + int (*filter_callback)(void *hdr, void *data, void *value); + u64 dcc_cfg; /* saved value of DCC Cfg register */ +}; + +/* snoop mode_flag values */ +#define HFI1_PORT_SNOOP_MODE 1U +#define HFI1_PORT_CAPTURE_MODE 2U + +struct hfi1_sge_state; + +/* + * Get/Set IB link-level config parameters for f_get/set_ib_cfg() + * Mostly for MADs that set or query link parameters, also ipath + * config interfaces + */ +#define HFI1_IB_CFG_LIDLMC 0 /* LID (LS16b) and Mask (MS16b) */ +#define HFI1_IB_CFG_LWID_DG_ENB 1 /* allowed Link-width downgrade */ +#define HFI1_IB_CFG_LWID_ENB 2 /* allowed Link-width */ +#define HFI1_IB_CFG_LWID 3 /* currently active Link-width */ +#define HFI1_IB_CFG_SPD_ENB 4 /* allowed Link speeds */ +#define HFI1_IB_CFG_SPD 5 /* current Link spd */ +#define HFI1_IB_CFG_RXPOL_ENB 6 /* Auto-RX-polarity enable */ +#define HFI1_IB_CFG_LREV_ENB 7 /* Auto-Lane-reversal enable */ +#define HFI1_IB_CFG_LINKLATENCY 8 /* Link Latency (IB1.2 only) */ +#define HFI1_IB_CFG_HRTBT 9 /* IB heartbeat off/enable/auto; DDR/QDR only */ +#define HFI1_IB_CFG_OP_VLS 10 /* operational VLs */ +#define HFI1_IB_CFG_VL_HIGH_CAP 11 /* num of VL high priority weights */ +#define HFI1_IB_CFG_VL_LOW_CAP 12 /* num of VL low priority weights */ +#define HFI1_IB_CFG_OVERRUN_THRESH 13 /* IB overrun threshold */ +#define HFI1_IB_CFG_PHYERR_THRESH 14 /* IB PHY error threshold */ +#define HFI1_IB_CFG_LINKDEFAULT 15 /* IB link default (sleep/poll) */ +#define HFI1_IB_CFG_PKEYS 16 /* update partition keys */ +#define HFI1_IB_CFG_MTU 17 /* update MTU in IBC */ +#define HFI1_IB_CFG_VL_HIGH_LIMIT 19 +#define HFI1_IB_CFG_PMA_TICKS 20 /* PMA sample tick resolution */ +#define HFI1_IB_CFG_PORT 21 /* switch port we are connected to */ + +/* + * HFI or Host Link States + * + * These describe the states the driver thinks the logical and physical + * states are in. Used as an argument to set_link_state(). Implemented + * as bits for easy multi-state checking. The actual state can only be + * one. + */ +#define __HLS_UP_INIT_BP 0 +#define __HLS_UP_ARMED_BP 1 +#define __HLS_UP_ACTIVE_BP 2 +#define __HLS_DN_DOWNDEF_BP 3 /* link down default */ +#define __HLS_DN_POLL_BP 4 +#define __HLS_DN_DISABLE_BP 5 +#define __HLS_DN_OFFLINE_BP 6 +#define __HLS_VERIFY_CAP_BP 7 +#define __HLS_GOING_UP_BP 8 +#define __HLS_GOING_OFFLINE_BP 9 +#define __HLS_LINK_COOLDOWN_BP 10 + +#define HLS_UP_INIT (1 << __HLS_UP_INIT_BP) +#define HLS_UP_ARMED (1 << __HLS_UP_ARMED_BP) +#define HLS_UP_ACTIVE (1 << __HLS_UP_ACTIVE_BP) +#define HLS_DN_DOWNDEF (1 << __HLS_DN_DOWNDEF_BP) /* link down default */ +#define HLS_DN_POLL (1 << __HLS_DN_POLL_BP) +#define HLS_DN_DISABLE (1 << __HLS_DN_DISABLE_BP) +#define HLS_DN_OFFLINE (1 << __HLS_DN_OFFLINE_BP) +#define HLS_VERIFY_CAP (1 << __HLS_VERIFY_CAP_BP) +#define HLS_GOING_UP (1 << __HLS_GOING_UP_BP) +#define HLS_GOING_OFFLINE (1 << __HLS_GOING_OFFLINE_BP) +#define HLS_LINK_COOLDOWN (1 << __HLS_LINK_COOLDOWN_BP) + +#define HLS_UP (HLS_UP_INIT | HLS_UP_ARMED | HLS_UP_ACTIVE) + +/* use this MTU size if none other is given */ +#define HFI1_DEFAULT_ACTIVE_MTU 8192 +/* use this MTU size as the default maximum */ +#define HFI1_DEFAULT_MAX_MTU 8192 +/* default partition key */ +#define DEFAULT_PKEY 0xffff + +/* + * Possible fabric manager config parameters for fm_{get,set}_table() + */ +#define FM_TBL_VL_HIGH_ARB 1 /* Get/set VL high prio weights */ +#define FM_TBL_VL_LOW_ARB 2 /* Get/set VL low prio weights */ +#define FM_TBL_BUFFER_CONTROL 3 /* Get/set Buffer Control */ +#define FM_TBL_SC2VLNT 4 /* Get/set SC->VLnt */ +#define FM_TBL_VL_PREEMPT_ELEMS 5 /* Get (no set) VL preempt elems */ +#define FM_TBL_VL_PREEMPT_MATRIX 6 /* Get (no set) VL preempt matrix */ + +/* + * Possible "operations" for f_rcvctrl(ppd, op, ctxt) + * these are bits so they can be combined, e.g. + * HFI1_RCVCTRL_INTRAVAIL_ENB | HFI1_RCVCTRL_CTXT_ENB + */ +#define HFI1_RCVCTRL_TAILUPD_ENB 0x01 +#define HFI1_RCVCTRL_TAILUPD_DIS 0x02 +#define HFI1_RCVCTRL_CTXT_ENB 0x04 +#define HFI1_RCVCTRL_CTXT_DIS 0x08 +#define HFI1_RCVCTRL_INTRAVAIL_ENB 0x10 +#define HFI1_RCVCTRL_INTRAVAIL_DIS 0x20 +#define HFI1_RCVCTRL_PKEY_ENB 0x40 /* Note, default is enabled */ +#define HFI1_RCVCTRL_PKEY_DIS 0x80 +#define HFI1_RCVCTRL_TIDFLOW_ENB 0x0400 +#define HFI1_RCVCTRL_TIDFLOW_DIS 0x0800 +#define HFI1_RCVCTRL_ONE_PKT_EGR_ENB 0x1000 +#define HFI1_RCVCTRL_ONE_PKT_EGR_DIS 0x2000 +#define HFI1_RCVCTRL_NO_RHQ_DROP_ENB 0x4000 +#define HFI1_RCVCTRL_NO_RHQ_DROP_DIS 0x8000 +#define HFI1_RCVCTRL_NO_EGR_DROP_ENB 0x10000 +#define HFI1_RCVCTRL_NO_EGR_DROP_DIS 0x20000 + +/* partition enforcement flags */ +#define HFI1_PART_ENFORCE_IN 0x1 +#define HFI1_PART_ENFORCE_OUT 0x2 + +/* how often we check for synthetic counter wrap around */ +#define SYNTH_CNT_TIME 2 + +/* Counter flags */ +#define CNTR_NORMAL 0x0 /* Normal counters, just read register */ +#define CNTR_SYNTH 0x1 /* Synthetic counters, saturate at all 1s */ +#define CNTR_DISABLED 0x2 /* Disable this counter */ +#define CNTR_32BIT 0x4 /* Simulate 64 bits for this counter */ +#define CNTR_VL 0x8 /* Per VL counter */ +#define CNTR_INVALID_VL -1 /* Specifies invalid VL */ +#define CNTR_MODE_W 0x0 +#define CNTR_MODE_R 0x1 + +/* VLs Supported/Operational */ +#define HFI1_MIN_VLS_SUPPORTED 1 +#define HFI1_MAX_VLS_SUPPORTED 8 + +static inline void incr_cntr64(u64 *cntr) +{ + if (*cntr < (u64)-1LL) + (*cntr)++; +} + +static inline void incr_cntr32(u32 *cntr) +{ + if (*cntr < (u32)-1LL) + (*cntr)++; +} + +#define MAX_NAME_SIZE 64 +struct hfi1_msix_entry { + struct msix_entry msix; + void *arg; + char name[MAX_NAME_SIZE]; + cpumask_var_t mask; +}; + +/* per-SL CCA information */ +struct cca_timer { + struct hrtimer hrtimer; + struct hfi1_pportdata *ppd; /* read-only */ + int sl; /* read-only */ + u16 ccti; /* read/write - current value of CCTI */ +}; + +struct link_down_reason { + /* + * SMA-facing value. Should be set from .latest when + * HLS_UP_* -> HLS_DN_* transition actually occurs. + */ + u8 sma; + u8 latest; +}; + +enum { + LO_PRIO_TABLE, + HI_PRIO_TABLE, + MAX_PRIO_TABLE +}; + +struct vl_arb_cache { + spinlock_t lock; + struct ib_vl_weight_elem table[VL_ARB_TABLE_SIZE]; +}; + +/* + * The structure below encapsulates data relevant to a physical IB Port. + * Current chips support only one such port, but the separation + * clarifies things a bit. Note that to conform to IB conventions, + * port-numbers are one-based. The first or only port is port1. + */ +struct hfi1_pportdata { + struct hfi1_ibport ibport_data; + + struct hfi1_devdata *dd; + struct kobject pport_cc_kobj; + struct kobject sc2vl_kobj; + struct kobject sl2sc_kobj; + struct kobject vl2mtu_kobj; + + /* QSFP support */ + struct qsfp_data qsfp_info; + + /* GUID for this interface, in host order */ + u64 guid; + /* GUID for peer interface, in host order */ + u64 neighbor_guid; + + /* up or down physical link state */ + u32 linkup; + + /* + * this address is mapped read-only into user processes so they can + * get status cheaply, whenever they want. One qword of status per port + */ + u64 *statusp; + + /* SendDMA related entries */ + + struct workqueue_struct *hfi1_wq; + + /* move out of interrupt context */ + struct work_struct link_vc_work; + struct work_struct link_up_work; + struct work_struct link_down_work; + struct work_struct sma_message_work; + struct work_struct freeze_work; + struct work_struct link_downgrade_work; + struct work_struct link_bounce_work; + /* host link state variables */ + struct mutex hls_lock; + u32 host_link_state; + + spinlock_t sdma_alllock ____cacheline_aligned_in_smp; + + u32 lstate; /* logical link state */ + + /* these are the "32 bit" regs */ + + u32 ibmtu; /* The MTU programmed for this unit */ + /* + * Current max size IB packet (in bytes) including IB headers, that + * we can send. Changes when ibmtu changes. + */ + u32 ibmaxlen; + u32 current_egress_rate; /* units [10^6 bits/sec] */ + /* LID programmed for this instance */ + u16 lid; + /* list of pkeys programmed; 0 if not set */ + u16 pkeys[MAX_PKEY_VALUES]; + u16 link_width_supported; + u16 link_width_downgrade_supported; + u16 link_speed_supported; + u16 link_width_enabled; + u16 link_width_downgrade_enabled; + u16 link_speed_enabled; + u16 link_width_active; + u16 link_width_downgrade_tx_active; + u16 link_width_downgrade_rx_active; + u16 link_speed_active; + u8 vls_supported; + u8 vls_operational; + /* LID mask control */ + u8 lmc; + /* Rx Polarity inversion (compensate for ~tx on partner) */ + u8 rx_pol_inv; + + u8 hw_pidx; /* physical port index */ + u8 port; /* IB port number and index into dd->pports - 1 */ + /* type of neighbor node */ + u8 neighbor_type; + u8 neighbor_normal; + u8 neighbor_fm_security; /* 1 if firmware checking is disabled */ + u8 neighbor_port_number; + u8 is_sm_config_started; + u8 offline_disabled_reason; + u8 is_active_optimize_enabled; + u8 driver_link_ready; /* driver ready for active link */ + u8 link_enabled; /* link enabled? */ + u8 linkinit_reason; + u8 local_tx_rate; /* rate given to 8051 firmware */ + + /* placeholders for IB MAD packet settings */ + u8 overrun_threshold; + u8 phy_error_threshold; + + /* used to override LED behavior */ + u8 led_override; /* Substituted for normal value, if non-zero */ + u16 led_override_timeoff; /* delta to next timer event */ + u8 led_override_vals[2]; /* Alternates per blink-frame */ + u8 led_override_phase; /* Just counts, LSB picks from vals[] */ + atomic_t led_override_timer_active; + /* Used to flash LEDs in override mode */ + struct timer_list led_override_timer; + u32 sm_trap_qp; + u32 sa_qp; + + /* + * cca_timer_lock protects access to the per-SL cca_timer + * structures (specifically the ccti member). + */ + spinlock_t cca_timer_lock ____cacheline_aligned_in_smp; + struct cca_timer cca_timer[OPA_MAX_SLS]; + + /* List of congestion control table entries */ + struct ib_cc_table_entry_shadow ccti_entries[CC_TABLE_SHADOW_MAX]; + + /* congestion entries, each entry corresponding to a SL */ + struct opa_congestion_setting_entry_shadow + congestion_entries[OPA_MAX_SLS]; + + /* + * cc_state_lock protects (write) access to the per-port + * struct cc_state. + */ + spinlock_t cc_state_lock ____cacheline_aligned_in_smp; + + struct cc_state __rcu *cc_state; + + /* Total number of congestion control table entries */ + u16 total_cct_entry; + + /* Bit map identifying service level */ + u32 cc_sl_control_map; + + /* CA's max number of 64 entry units in the congestion control table */ + u8 cc_max_table_entries; + + /* begin congestion log related entries + * cc_log_lock protects all congestion log related data */ + spinlock_t cc_log_lock ____cacheline_aligned_in_smp; + u8 threshold_cong_event_map[OPA_MAX_SLS/8]; + u16 threshold_event_counter; + struct opa_hfi1_cong_log_event_internal cc_events[OPA_CONG_LOG_ELEMS]; + int cc_log_idx; /* index for logging events */ + int cc_mad_idx; /* index for reporting events */ + /* end congestion log related entries */ + + struct vl_arb_cache vl_arb_cache[MAX_PRIO_TABLE]; + + /* port relative counter buffer */ + u64 *cntrs; + /* port relative synthetic counter buffer */ + u64 *scntrs; + /* we synthesize port_xmit_discards from several egress errors */ + u64 port_xmit_discards; + u64 port_xmit_constraint_errors; + u64 port_rcv_constraint_errors; + /* count of 'link_err' interrupts from DC */ + u64 link_downed; + /* number of times link retrained successfully */ + u64 link_up; + /* port_ltp_crc_mode is returned in 'portinfo' MADs */ + u16 port_ltp_crc_mode; + /* port_crc_mode_enabled is the crc we support */ + u8 port_crc_mode_enabled; + /* mgmt_allowed is also returned in 'portinfo' MADs */ + u8 mgmt_allowed; + u8 part_enforce; /* partition enforcement flags */ + struct link_down_reason local_link_down_reason; + struct link_down_reason neigh_link_down_reason; + /* Value to be sent to link peer on LinkDown .*/ + u8 remote_link_down_reason; + /* Error events that will cause a port bounce. */ + u32 port_error_action; +}; + +typedef int (*rhf_rcv_function_ptr)(struct hfi1_packet *packet); + +typedef void (*opcode_handler)(struct hfi1_packet *packet); + +/* return values for the RHF receive functions */ +#define RHF_RCV_CONTINUE 0 /* keep going */ +#define RHF_RCV_DONE 1 /* stop, this packet processed */ +#define RHF_RCV_REPROCESS 2 /* stop. retain this packet */ + +struct rcv_array_data { + u8 group_size; + u16 ngroups; + u16 nctxt_extra; +}; + +struct per_vl_data { + u16 mtu; + struct send_context *sc; +}; + +/* 16 to directly index */ +#define PER_VL_SEND_CONTEXTS 16 + +struct err_info_rcvport { + u8 status_and_code; + u64 packet_flit1; + u64 packet_flit2; +}; + +struct err_info_constraint { + u8 status; + u16 pkey; + u32 slid; +}; + +struct hfi1_temp { + unsigned int curr; /* current temperature */ + unsigned int lo_lim; /* low temperature limit */ + unsigned int hi_lim; /* high temperature limit */ + unsigned int crit_lim; /* critical temperature limit */ + u8 triggers; /* temperature triggers */ +}; + +/* device data struct now contains only "general per-device" info. + * fields related to a physical IB port are in a hfi1_pportdata struct. + */ +struct sdma_engine; +struct sdma_vl_map; + +#define BOARD_VERS_MAX 96 /* how long the version string can be */ +#define SERIAL_MAX 16 /* length of the serial number */ + +struct hfi1_devdata { + struct hfi1_ibdev verbs_dev; /* must be first */ + struct list_head list; + /* pointers to related structs for this device */ + /* pci access data structure */ + struct pci_dev *pcidev; + struct cdev user_cdev; + struct cdev diag_cdev; + struct cdev ui_cdev; + struct device *user_device; + struct device *diag_device; + struct device *ui_device; + + /* mem-mapped pointer to base of chip regs */ + u8 __iomem *kregbase; + /* end of mem-mapped chip space excluding sendbuf and user regs */ + u8 __iomem *kregend; + /* physical address of chip for io_remap, etc. */ + resource_size_t physaddr; + /* receive context data */ + struct hfi1_ctxtdata **rcd; + /* send context data */ + struct send_context_info *send_contexts; + /* map hardware send contexts to software index */ + u8 *hw_to_sw; + /* spinlock for allocating and releasing send context resources */ + spinlock_t sc_lock; + /* Per VL data. Enough for all VLs but not all elements are set/used. */ + struct per_vl_data vld[PER_VL_SEND_CONTEXTS]; + /* seqlock for sc2vl */ + seqlock_t sc2vl_lock; + u64 sc2vl[4]; + /* Send Context initialization lock. */ + spinlock_t sc_init_lock; + + /* fields common to all SDMA engines */ + + /* default flags to last descriptor */ + u64 default_desc1; + volatile __le64 *sdma_heads_dma; /* DMA'ed by chip */ + dma_addr_t sdma_heads_phys; + void *sdma_pad_dma; /* DMA'ed by chip */ + dma_addr_t sdma_pad_phys; + /* for deallocation */ + size_t sdma_heads_size; + /* number from the chip */ + u32 chip_sdma_engines; + /* num used */ + u32 num_sdma; + /* lock for sdma_map */ + spinlock_t sde_map_lock; + /* array of engines sized by num_sdma */ + struct sdma_engine *per_sdma; + /* array of vl maps */ + struct sdma_vl_map __rcu *sdma_map; + /* SPC freeze waitqueue and variable */ + wait_queue_head_t sdma_unfreeze_wq; + atomic_t sdma_unfreeze_count; + + + /* hfi1_pportdata, points to array of (physical) port-specific + * data structs, indexed by pidx (0..n-1) + */ + struct hfi1_pportdata *pport; + + /* mem-mapped pointer to base of PIO buffers */ + void __iomem *piobase; + /* + * write-combining mem-mapped pointer to base of RcvArray + * memory. + */ + void __iomem *rcvarray_wc; + /* + * credit return base - a per-NUMA range of DMA address that + * the chip will use to update the per-context free counter + */ + struct credit_return_base *cr_base; + + /* send context numbers and sizes for each type */ + struct sc_config_sizes sc_sizes[SC_MAX]; + + u32 lcb_access_count; /* count of LCB users */ + + char *boardname; /* human readable board info */ + + /* device (not port) flags, basically device capabilities */ + u32 flags; + + /* reset value */ + u64 z_int_counter; + u64 z_rcv_limit; + /* percpu int_counter */ + u64 __percpu *int_counter; + u64 __percpu *rcv_limit; + + /* number of receive contexts in use by the driver */ + u32 num_rcv_contexts; + /* number of pio send contexts in use by the driver */ + u32 num_send_contexts; + /* + * number of ctxts available for PSM open + */ + u32 freectxts; + /* base receive interrupt timeout, in CSR units */ + u32 rcv_intr_timeout_csr; + + u64 __iomem *egrtidbase; + spinlock_t sendctrl_lock; /* protect changes to SendCtrl */ + spinlock_t rcvctrl_lock; /* protect changes to RcvCtrl */ + /* around rcd and (user ctxts) ctxt_cnt use (intr vs free) */ + spinlock_t uctxt_lock; /* rcd and user context changes */ + /* exclusive access to 8051 */ + spinlock_t dc8051_lock; + /* exclusive access to 8051 memory */ + spinlock_t dc8051_memlock; + int dc8051_timed_out; /* remember if the 8051 timed out */ + /* + * A page that will hold event notification bitmaps for all + * contexts. This page will be mapped into all processes. + */ + unsigned long *events; + /* + * per unit status, see also portdata statusp + * mapped read-only into user processes so they can get unit and + * IB link status cheaply + */ + struct hfi1_status *status; + u32 freezelen; /* max length of freezemsg */ + + /* revision register shadow */ + u64 revision; + /* Base GUID for device (network order) */ + u64 base_guid; + + /* these are the "32 bit" regs */ + + /* value we put in kr_rcvhdrsize */ + u32 rcvhdrsize; + /* number of receive contexts the chip supports */ + u32 chip_rcv_contexts; + /* number of receive array entries */ + u32 chip_rcv_array_count; + /* number of PIO send contexts the chip supports */ + u32 chip_send_contexts; + /* number of bytes in the PIO memory buffer */ + u32 chip_pio_mem_size; + /* number of bytes in the SDMA memory buffer */ + u32 chip_sdma_mem_size; + + /* size of each rcvegrbuffer */ + u32 rcvegrbufsize; + /* log2 of above */ + u16 rcvegrbufsize_shift; + /* both sides of the PCIe link are gen3 capable */ + u8 link_gen3_capable; + /* localbus width (1, 2,4,8,16,32) from config space */ + u32 lbus_width; + /* localbus speed in MHz */ + u32 lbus_speed; + int unit; /* unit # of this chip */ + int node; /* home node of this chip */ + + /* save these PCI fields to restore after a reset */ + u32 pcibar0; + u32 pcibar1; + u32 pci_rom; + u16 pci_command; + u16 pcie_devctl; + u16 pcie_lnkctl; + u16 pcie_devctl2; + u32 pci_msix0; + u32 pci_lnkctl3; + u32 pci_tph2; + + /* + * ASCII serial number, from flash, large enough for original + * all digit strings, and longer serial number format + */ + u8 serial[SERIAL_MAX]; + /* human readable board version */ + u8 boardversion[BOARD_VERS_MAX]; + u8 lbus_info[32]; /* human readable localbus info */ + /* chip major rev, from CceRevision */ + u8 majrev; + /* chip minor rev, from CceRevision */ + u8 minrev; + /* hardware ID */ + u8 hfi1_id; + /* implementation code */ + u8 icode; + /* default link down value (poll/sleep) */ + u8 link_default; + /* vAU of this device */ + u8 vau; + /* vCU of this device */ + u8 vcu; + /* link credits of this device */ + u16 link_credits; + /* initial vl15 credits to use */ + u16 vl15_init; + + /* Misc small ints */ + /* Number of physical ports available */ + u8 num_pports; + /* Lowest context number which can be used by user processes */ + u8 first_user_ctxt; + u8 n_krcv_queues; + u8 qos_shift; + u8 qpn_mask; + + u16 rhf_offset; /* offset of RHF within receive header entry */ + u16 irev; /* implementation revision */ + u16 dc8051_ver; /* 8051 firmware version */ + + struct platform_config_cache pcfg_cache; + /* control high-level access to qsfp */ + struct mutex qsfp_i2c_mutex; + + struct diag_client *diag_client; + spinlock_t hfi1_diag_trans_lock; /* protect diag observer ops */ + + u8 psxmitwait_supported; + /* cycle length of PS* counters in HW (in picoseconds) */ + u16 psxmitwait_check_rate; + /* high volume overflow errors deferred to tasklet */ + struct tasklet_struct error_tasklet; + /* per device cq worker */ + struct kthread_worker *worker; + + /* MSI-X information */ + struct hfi1_msix_entry *msix_entries; + u32 num_msix_entries; + + /* INTx information */ + u32 requested_intx_irq; /* did we request one? */ + char intx_name[MAX_NAME_SIZE]; /* INTx name */ + + /* general interrupt: mask of handled interrupts */ + u64 gi_mask[CCE_NUM_INT_CSRS]; + + struct rcv_array_data rcv_entries; + + /* + * 64 bit synthetic counters + */ + struct timer_list synth_stats_timer; + + /* + * device counters + */ + char *cntrnames; + size_t cntrnameslen; + size_t ndevcntrs; + u64 *cntrs; + u64 *scntrs; + + /* + * remembered values for synthetic counters + */ + u64 last_tx; + u64 last_rx; + + /* + * per-port counters + */ + size_t nportcntrs; + char *portcntrnames; + size_t portcntrnameslen; + + struct hfi1_snoop_data hfi1_snoop; + + struct err_info_rcvport err_info_rcvport; + struct err_info_constraint err_info_rcv_constraint; + struct err_info_constraint err_info_xmit_constraint; + u8 err_info_uncorrectable; + u8 err_info_fmconfig; + + atomic_t drop_packet; + u8 do_drop; + + /* receive interrupt functions */ + rhf_rcv_function_ptr *rhf_rcv_function_map; + rhf_rcv_function_ptr normal_rhf_rcv_functions[8]; + + /* + * Handlers for outgoing data so that snoop/capture does not + * have to have its hooks in the send path + */ + int (*process_pio_send)(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr, + u32 hdrwords, struct hfi1_sge_state *ss, + u32 len, u32 plen, u32 dwords, u64 pbc); + int (*process_dma_send)(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr, + u32 hdrwords, struct hfi1_sge_state *ss, + u32 len, u32 plen, u32 dwords, u64 pbc); + void (*pio_inline_send)(struct hfi1_devdata *dd, struct pio_buf *pbuf, + u64 pbc, const void *from, size_t count); + + /* OUI comes from the HW. Used everywhere as 3 separate bytes. */ + u8 oui1; + u8 oui2; + u8 oui3; + /* Timer and counter used to detect RcvBufOvflCnt changes */ + struct timer_list rcverr_timer; + u32 rcv_ovfl_cnt; + + int assigned_node_id; + wait_queue_head_t event_queue; + + /* Save the enabled LCB error bits */ + u64 lcb_err_en; + u8 dc_shutdown; +}; + +/* 8051 firmware version helper */ +#define dc8051_ver(a, b) ((a) << 8 | (b)) + +/* f_put_tid types */ +#define PT_EXPECTED 0 +#define PT_EAGER 1 +#define PT_INVALID 2 + +/* Private data for file operations */ +struct hfi1_filedata { + struct hfi1_ctxtdata *uctxt; + unsigned subctxt; + struct hfi1_user_sdma_comp_q *cq; + struct hfi1_user_sdma_pkt_q *pq; + /* for cpu affinity; -1 if none */ + int rec_cpu_num; +}; + +extern struct list_head hfi1_dev_list; +extern spinlock_t hfi1_devs_lock; +struct hfi1_devdata *hfi1_lookup(int unit); +extern u32 hfi1_cpulist_count; +extern unsigned long *hfi1_cpulist; + +extern unsigned int snoop_drop_send; +extern unsigned int snoop_force_capture; +int hfi1_init(struct hfi1_devdata *, int); +int hfi1_count_units(int *npresentp, int *nupp); +int hfi1_count_active_units(void); + +int hfi1_diag_add(struct hfi1_devdata *); +void hfi1_diag_remove(struct hfi1_devdata *); +void handle_linkup_change(struct hfi1_devdata *dd, u32 linkup); + +void handle_user_interrupt(struct hfi1_ctxtdata *rcd); + +int hfi1_create_rcvhdrq(struct hfi1_devdata *, struct hfi1_ctxtdata *); +int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *); +int hfi1_create_ctxts(struct hfi1_devdata *dd); +struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *, u32); +void hfi1_init_pportdata(struct pci_dev *, struct hfi1_pportdata *, + struct hfi1_devdata *, u8, u8); +void hfi1_free_ctxtdata(struct hfi1_devdata *, struct hfi1_ctxtdata *); + +void handle_receive_interrupt(struct hfi1_ctxtdata *); +void handle_receive_interrupt_nodma_rtail(struct hfi1_ctxtdata *rcd); +void handle_receive_interrupt_dma_rtail(struct hfi1_ctxtdata *rcd); +int hfi1_reset_device(int); + +/* return the driver's idea of the logical OPA port state */ +static inline u32 driver_lstate(struct hfi1_pportdata *ppd) +{ + return ppd->lstate; /* use the cached value */ +} + +static inline u16 generate_jkey(kuid_t uid) +{ + return from_kuid(current_user_ns(), uid) & 0xffff; +} + +/* + * active_egress_rate + * + * returns the active egress rate in units of [10^6 bits/sec] + */ +static inline u32 active_egress_rate(struct hfi1_pportdata *ppd) +{ + u16 link_speed = ppd->link_speed_active; + u16 link_width = ppd->link_width_active; + u32 egress_rate; + + if (link_speed == OPA_LINK_SPEED_25G) + egress_rate = 25000; + else /* assume OPA_LINK_SPEED_12_5G */ + egress_rate = 12500; + + switch (link_width) { + case OPA_LINK_WIDTH_4X: + egress_rate *= 4; + break; + case OPA_LINK_WIDTH_3X: + egress_rate *= 3; + break; + case OPA_LINK_WIDTH_2X: + egress_rate *= 2; + break; + default: + /* assume IB_WIDTH_1X */ + break; + } + + return egress_rate; +} + +/* + * egress_cycles + * + * Returns the number of 'fabric clock cycles' to egress a packet + * of length 'len' bytes, at 'rate' Mbit/s. Since the fabric clock + * rate is (approximately) 805 MHz, the units of the returned value + * are (1/805 MHz). + */ +static inline u32 egress_cycles(u32 len, u32 rate) +{ + u32 cycles; + + /* + * cycles is: + * + * (length) [bits] / (rate) [bits/sec] + * --------------------------------------------------- + * fabric_clock_period == 1 /(805 * 10^6) [cycles/sec] + */ + + cycles = len * 8; /* bits */ + cycles *= 805; + cycles /= rate; + + return cycles; +} + +void set_link_ipg(struct hfi1_pportdata *ppd); +void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn, + u32 rqpn, u8 svc_type); +void return_cnp(struct hfi1_ibport *ibp, struct hfi1_qp *qp, u32 remote_qpn, + u32 pkey, u32 slid, u32 dlid, u8 sc5, + const struct ib_grh *old_grh); + +#define PACKET_EGRESS_TIMEOUT 350 +static inline void pause_for_credit_return(struct hfi1_devdata *dd) +{ + /* Pause at least 1us, to ensure chip returns all credits */ + u32 usec = cclock_to_ns(dd, PACKET_EGRESS_TIMEOUT) / 1000; + + udelay(usec ? usec : 1); +} + +/** + * sc_to_vlt() reverse lookup sc to vl + * @dd - devdata + * @sc5 - 5 bit sc + */ +static inline u8 sc_to_vlt(struct hfi1_devdata *dd, u8 sc5) +{ + unsigned seq; + u8 rval; + + if (sc5 >= OPA_MAX_SCS) + return (u8)(0xff); + + do { + seq = read_seqbegin(&dd->sc2vl_lock); + rval = *(((u8 *)dd->sc2vl) + sc5); + } while (read_seqretry(&dd->sc2vl_lock, seq)); + + return rval; +} + +#define PKEY_MEMBER_MASK 0x8000 +#define PKEY_LOW_15_MASK 0x7fff + +/* + * ingress_pkey_matches_entry - return 1 if the pkey matches ent (ent + * being an entry from the ingress partition key table), return 0 + * otherwise. Use the matching criteria for ingress partition keys + * specified in the OPAv1 spec., section 9.10.14. + */ +static inline int ingress_pkey_matches_entry(u16 pkey, u16 ent) +{ + u16 mkey = pkey & PKEY_LOW_15_MASK; + u16 ment = ent & PKEY_LOW_15_MASK; + + if (mkey == ment) { + /* + * If pkey[15] is clear (limited partition member), + * is bit 15 in the corresponding table element + * clear (limited member)? + */ + if (!(pkey & PKEY_MEMBER_MASK)) + return !!(ent & PKEY_MEMBER_MASK); + return 1; + } + return 0; +} + +/* + * ingress_pkey_table_search - search the entire pkey table for + * an entry which matches 'pkey'. return 0 if a match is found, + * and 1 otherwise. + */ +static int ingress_pkey_table_search(struct hfi1_pportdata *ppd, u16 pkey) +{ + int i; + + for (i = 0; i < MAX_PKEY_VALUES; i++) { + if (ingress_pkey_matches_entry(pkey, ppd->pkeys[i])) + return 0; + } + return 1; +} + +/* + * ingress_pkey_table_fail - record a failure of ingress pkey validation, + * i.e., increment port_rcv_constraint_errors for the port, and record + * the 'error info' for this failure. + */ +static void ingress_pkey_table_fail(struct hfi1_pportdata *ppd, u16 pkey, + u16 slid) +{ + struct hfi1_devdata *dd = ppd->dd; + + incr_cntr64(&ppd->port_rcv_constraint_errors); + if (!(dd->err_info_rcv_constraint.status & OPA_EI_STATUS_SMASK)) { + dd->err_info_rcv_constraint.status |= OPA_EI_STATUS_SMASK; + dd->err_info_rcv_constraint.slid = slid; + dd->err_info_rcv_constraint.pkey = pkey; + } +} + +/* + * ingress_pkey_check - Return 0 if the ingress pkey is valid, return 1 + * otherwise. Use the criteria in the OPAv1 spec, section 9.10.14. idx + * is a hint as to the best place in the partition key table to begin + * searching. This function should not be called on the data path because + * of performance reasons. On datapath pkey check is expected to be done + * by HW and rcv_pkey_check function should be called instead. + */ +static inline int ingress_pkey_check(struct hfi1_pportdata *ppd, u16 pkey, + u8 sc5, u8 idx, u16 slid) +{ + if (!(ppd->part_enforce & HFI1_PART_ENFORCE_IN)) + return 0; + + /* If SC15, pkey[0:14] must be 0x7fff */ + if ((sc5 == 0xf) && ((pkey & PKEY_LOW_15_MASK) != PKEY_LOW_15_MASK)) + goto bad; + + /* Is the pkey = 0x0, or 0x8000? */ + if ((pkey & PKEY_LOW_15_MASK) == 0) + goto bad; + + /* The most likely matching pkey has index 'idx' */ + if (ingress_pkey_matches_entry(pkey, ppd->pkeys[idx])) + return 0; + + /* no match - try the whole table */ + if (!ingress_pkey_table_search(ppd, pkey)) + return 0; + +bad: + ingress_pkey_table_fail(ppd, pkey, slid); + return 1; +} + +/* + * rcv_pkey_check - Return 0 if the ingress pkey is valid, return 1 + * otherwise. It only ensures pkey is vlid for QP0. This function + * should be called on the data path instead of ingress_pkey_check + * as on data path, pkey check is done by HW (except for QP0). + */ +static inline int rcv_pkey_check(struct hfi1_pportdata *ppd, u16 pkey, + u8 sc5, u16 slid) +{ + if (!(ppd->part_enforce & HFI1_PART_ENFORCE_IN)) + return 0; + + /* If SC15, pkey[0:14] must be 0x7fff */ + if ((sc5 == 0xf) && ((pkey & PKEY_LOW_15_MASK) != PKEY_LOW_15_MASK)) + goto bad; + + return 0; +bad: + ingress_pkey_table_fail(ppd, pkey, slid); + return 1; +} + +/* MTU handling */ + +/* MTU enumeration, 256-4k match IB */ +#define OPA_MTU_0 0 +#define OPA_MTU_256 1 +#define OPA_MTU_512 2 +#define OPA_MTU_1024 3 +#define OPA_MTU_2048 4 +#define OPA_MTU_4096 5 + +u32 lrh_max_header_bytes(struct hfi1_devdata *dd); +int mtu_to_enum(u32 mtu, int default_if_bad); +u16 enum_to_mtu(int); +static inline int valid_ib_mtu(unsigned int mtu) +{ + return mtu == 256 || mtu == 512 || + mtu == 1024 || mtu == 2048 || + mtu == 4096; +} +static inline int valid_opa_max_mtu(unsigned int mtu) +{ + return mtu >= 2048 && + (valid_ib_mtu(mtu) || mtu == 8192 || mtu == 10240); +} + +int set_mtu(struct hfi1_pportdata *); + +int hfi1_set_lid(struct hfi1_pportdata *, u32, u8); +void hfi1_disable_after_error(struct hfi1_devdata *); +int hfi1_set_uevent_bits(struct hfi1_pportdata *, const int); +int hfi1_rcvbuf_validate(u32, u8, u16 *); + +int fm_get_table(struct hfi1_pportdata *, int, void *); +int fm_set_table(struct hfi1_pportdata *, int, void *); + +void set_up_vl15(struct hfi1_devdata *dd, u8 vau, u16 vl15buf); +void reset_link_credits(struct hfi1_devdata *dd); +void assign_remote_cm_au_table(struct hfi1_devdata *dd, u8 vcu); + +int snoop_recv_handler(struct hfi1_packet *packet); +int snoop_send_dma_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc); +int snoop_send_pio_handler(struct hfi1_qp *qp, struct ahg_ib_header *ibhdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc); +void snoop_inline_pio_send(struct hfi1_devdata *dd, struct pio_buf *pbuf, + u64 pbc, const void *from, size_t count); + +/* for use in system calls, where we want to know device type, etc. */ +#define ctxt_fp(fp) \ + (((struct hfi1_filedata *)(fp)->private_data)->uctxt) +#define subctxt_fp(fp) \ + (((struct hfi1_filedata *)(fp)->private_data)->subctxt) +#define tidcursor_fp(fp) \ + (((struct hfi1_filedata *)(fp)->private_data)->tidcursor) +#define user_sdma_pkt_fp(fp) \ + (((struct hfi1_filedata *)(fp)->private_data)->pq) +#define user_sdma_comp_fp(fp) \ + (((struct hfi1_filedata *)(fp)->private_data)->cq) + +static inline struct hfi1_devdata *dd_from_ppd(struct hfi1_pportdata *ppd) +{ + return ppd->dd; +} + +static inline struct hfi1_devdata *dd_from_dev(struct hfi1_ibdev *dev) +{ + return container_of(dev, struct hfi1_devdata, verbs_dev); +} + +static inline struct hfi1_devdata *dd_from_ibdev(struct ib_device *ibdev) +{ + return dd_from_dev(to_idev(ibdev)); +} + +static inline struct hfi1_pportdata *ppd_from_ibp(struct hfi1_ibport *ibp) +{ + return container_of(ibp, struct hfi1_pportdata, ibport_data); +} + +static inline struct hfi1_ibport *to_iport(struct ib_device *ibdev, u8 port) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + unsigned pidx = port - 1; /* IB number port from 1, hdw from 0 */ + + WARN_ON(pidx >= dd->num_pports); + return &dd->pport[pidx].ibport_data; +} + +/* + * Return the indexed PKEY from the port PKEY table. + */ +static inline u16 hfi1_get_pkey(struct hfi1_ibport *ibp, unsigned index) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u16 ret; + + if (index >= ARRAY_SIZE(ppd->pkeys)) + ret = 0; + else + ret = ppd->pkeys[index]; + + return ret; +} + +/* + * Readers of cc_state must call get_cc_state() under rcu_read_lock(). + * Writers of cc_state must call get_cc_state() under cc_state_lock. + */ +static inline struct cc_state *get_cc_state(struct hfi1_pportdata *ppd) +{ + return rcu_dereference(ppd->cc_state); +} + +/* + * values for dd->flags (_device_ related flags) + */ +#define HFI1_INITTED 0x1 /* chip and driver up and initted */ +#define HFI1_PRESENT 0x2 /* chip accesses can be done */ +#define HFI1_FROZEN 0x4 /* chip in SPC freeze */ +#define HFI1_HAS_SDMA_TIMEOUT 0x8 +#define HFI1_HAS_SEND_DMA 0x10 /* Supports Send DMA */ +#define HFI1_FORCED_FREEZE 0x80 /* driver forced freeze mode */ +#define HFI1_DO_INIT_ASIC 0x100 /* This device will init the ASIC */ + +/* IB dword length mask in PBC (lower 11 bits); same for all chips */ +#define HFI1_PBC_LENGTH_MASK ((1 << 11) - 1) + + +/* ctxt_flag bit offsets */ + /* context has been setup */ +#define HFI1_CTXT_SETUP_DONE 1 + /* waiting for a packet to arrive */ +#define HFI1_CTXT_WAITING_RCV 2 + /* master has not finished initializing */ +#define HFI1_CTXT_MASTER_UNINIT 4 + /* waiting for an urgent packet to arrive */ +#define HFI1_CTXT_WAITING_URG 5 + +/* free up any allocated data at closes */ +struct hfi1_devdata *hfi1_init_dd(struct pci_dev *, + const struct pci_device_id *); +void hfi1_free_devdata(struct hfi1_devdata *); +void cc_state_reclaim(struct rcu_head *rcu); +struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra); + +/* + * Set LED override, only the two LSBs have "public" meaning, but + * any non-zero value substitutes them for the Link and LinkTrain + * LED states. + */ +#define HFI1_LED_PHYS 1 /* Physical (linktraining) GREEN LED */ +#define HFI1_LED_LOG 2 /* Logical (link) YELLOW LED */ +void hfi1_set_led_override(struct hfi1_pportdata *ppd, unsigned int val); + +#define HFI1_CREDIT_RETURN_RATE (100) + +/* + * The number of words for the KDETH protocol field. If this is + * larger then the actual field used, then part of the payload + * will be in the header. + * + * Optimally, we want this sized so that a typical case will + * use full cache lines. The typical local KDETH header would + * be: + * + * Bytes Field + * 8 LRH + * 12 BHT + * ?? KDETH + * 8 RHF + * --- + * 28 + KDETH + * + * For a 64-byte cache line, KDETH would need to be 36 bytes or 9 DWORDS + */ +#define DEFAULT_RCVHDRSIZE 9 + +/* + * Maximal header byte count: + * + * Bytes Field + * 8 LRH + * 40 GRH (optional) + * 12 BTH + * ?? KDETH + * 8 RHF + * --- + * 68 + KDETH + * + * We also want to maintain a cache line alignment to assist DMA'ing + * of the header bytes. Round up to a good size. + */ +#define DEFAULT_RCVHDR_ENTSIZE 32 + +int hfi1_get_user_pages(unsigned long, size_t, struct page **); +void hfi1_release_user_pages(struct page **, size_t); + +static inline void clear_rcvhdrtail(const struct hfi1_ctxtdata *rcd) +{ + *((u64 *) rcd->rcvhdrtail_kvaddr) = 0ULL; +} + +static inline u32 get_rcvhdrtail(const struct hfi1_ctxtdata *rcd) +{ + /* + * volatile because it's a DMA target from the chip, routine is + * inlined, and don't want register caching or reordering. + */ + return (u32) le64_to_cpu(*rcd->rcvhdrtail_kvaddr); +} + +/* + * sysfs interface. + */ + +extern const char ib_hfi1_version[]; + +int hfi1_device_create(struct hfi1_devdata *); +void hfi1_device_remove(struct hfi1_devdata *); + +int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, + struct kobject *kobj); +int hfi1_verbs_register_sysfs(struct hfi1_devdata *); +void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *); +/* Hook for sysfs read of QSFP */ +int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len); + +int hfi1_pcie_init(struct pci_dev *, const struct pci_device_id *); +void hfi1_pcie_cleanup(struct pci_dev *); +int hfi1_pcie_ddinit(struct hfi1_devdata *, struct pci_dev *, + const struct pci_device_id *); +void hfi1_pcie_ddcleanup(struct hfi1_devdata *); +void hfi1_pcie_flr(struct hfi1_devdata *); +int pcie_speeds(struct hfi1_devdata *); +void request_msix(struct hfi1_devdata *, u32 *, struct hfi1_msix_entry *); +void hfi1_enable_intx(struct pci_dev *); +void hfi1_nomsix(struct hfi1_devdata *); +void restore_pci_variables(struct hfi1_devdata *dd); +int do_pcie_gen3_transition(struct hfi1_devdata *dd); +int parse_platform_config(struct hfi1_devdata *dd); +int get_platform_config_field(struct hfi1_devdata *dd, + enum platform_config_table_type_encoding table_type, + int table_index, int field_index, u32 *data, u32 len); + +dma_addr_t hfi1_map_page(struct pci_dev *, struct page *, unsigned long, + size_t, int); +const char *get_unit_name(int unit); + +/* + * Flush write combining store buffers (if present) and perform a write + * barrier. + */ +static inline void flush_wc(void) +{ + asm volatile("sfence" : : : "memory"); +} + +void handle_eflags(struct hfi1_packet *packet); +int process_receive_ib(struct hfi1_packet *packet); +int process_receive_bypass(struct hfi1_packet *packet); +int process_receive_error(struct hfi1_packet *packet); +int kdeth_process_expected(struct hfi1_packet *packet); +int kdeth_process_eager(struct hfi1_packet *packet); +int process_receive_invalid(struct hfi1_packet *packet); + +extern rhf_rcv_function_ptr snoop_rhf_rcv_functions[8]; + +void update_sge(struct hfi1_sge_state *ss, u32 length); + +/* global module parameter variables */ +extern unsigned int hfi1_max_mtu; +extern unsigned int hfi1_cu; +extern unsigned int user_credit_return_threshold; +extern uint num_rcv_contexts; +extern unsigned n_krcvqs; +extern u8 krcvqs[]; +extern int krcvqsset; +extern uint kdeth_qp; +extern uint loopback; +extern uint quick_linkup; +extern uint rcv_intr_timeout; +extern uint rcv_intr_count; +extern uint rcv_intr_dynamic; +extern ushort link_crc_mask; + +extern struct mutex hfi1_mutex; + +/* Number of seconds before our card status check... */ +#define STATUS_TIMEOUT 60 + +#define DRIVER_NAME "hfi1" +#define HFI1_USER_MINOR_BASE 0 +#define HFI1_TRACE_MINOR 127 +#define HFI1_DIAGPKT_MINOR 128 +#define HFI1_DIAG_MINOR_BASE 129 +#define HFI1_SNOOP_CAPTURE_BASE 200 +#define HFI1_NMINORS 255 + +#define PCI_VENDOR_ID_INTEL 0x8086 +#define PCI_DEVICE_ID_INTEL0 0x24f0 +#define PCI_DEVICE_ID_INTEL1 0x24f1 + +#define HFI1_PKT_USER_SC_INTEGRITY \ + (SEND_CTXT_CHECK_ENABLE_DISALLOW_NON_KDETH_PACKETS_SMASK \ + | SEND_CTXT_CHECK_ENABLE_DISALLOW_BYPASS_SMASK \ + | SEND_CTXT_CHECK_ENABLE_DISALLOW_GRH_SMASK) + +#define HFI1_PKT_KERNEL_SC_INTEGRITY \ + (SEND_CTXT_CHECK_ENABLE_DISALLOW_KDETH_PACKETS_SMASK) + +static inline u64 hfi1_pkt_default_send_ctxt_mask(struct hfi1_devdata *dd, + u16 ctxt_type) +{ + u64 base_sc_integrity = + SEND_CTXT_CHECK_ENABLE_DISALLOW_BYPASS_BAD_PKT_LEN_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_LONG_BYPASS_PACKETS_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_LONG_IB_PACKETS_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_BAD_PKT_LEN_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_PBC_TEST_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_SMALL_BYPASS_PACKETS_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_TOO_SMALL_IB_PACKETS_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_RAW_IPV6_SMASK + | SEND_CTXT_CHECK_ENABLE_DISALLOW_RAW_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_BYPASS_VL_MAPPING_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_VL_MAPPING_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_OPCODE_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_SLID_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_VL_SMASK + | SEND_CTXT_CHECK_ENABLE_CHECK_ENABLE_SMASK; + + if (ctxt_type == SC_USER) + base_sc_integrity |= HFI1_PKT_USER_SC_INTEGRITY; + else + base_sc_integrity |= HFI1_PKT_KERNEL_SC_INTEGRITY; + + if (is_a0(dd)) + /* turn off send-side job key checks - A0 erratum */ + return base_sc_integrity & + ~SEND_CTXT_CHECK_ENABLE_CHECK_JOB_KEY_SMASK; + return base_sc_integrity; +} + +static inline u64 hfi1_pkt_base_sdma_integrity(struct hfi1_devdata *dd) +{ + u64 base_sdma_integrity = + SEND_DMA_CHECK_ENABLE_DISALLOW_BYPASS_BAD_PKT_LEN_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_LONG_BYPASS_PACKETS_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_LONG_IB_PACKETS_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_BAD_PKT_LEN_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_SMALL_BYPASS_PACKETS_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_TOO_SMALL_IB_PACKETS_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_RAW_IPV6_SMASK + | SEND_DMA_CHECK_ENABLE_DISALLOW_RAW_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_BYPASS_VL_MAPPING_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_VL_MAPPING_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_OPCODE_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_SLID_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_VL_SMASK + | SEND_DMA_CHECK_ENABLE_CHECK_ENABLE_SMASK; + + if (is_a0(dd)) + /* turn off send-side job key checks - A0 erratum */ + return base_sdma_integrity & + ~SEND_DMA_CHECK_ENABLE_CHECK_JOB_KEY_SMASK; + return base_sdma_integrity; +} + +/* + * hfi1_early_err is used (only!) to print early errors before devdata is + * allocated, or when dd->pcidev may not be valid, and at the tail end of + * cleanup when devdata may have been freed, etc. hfi1_dev_porterr is + * the same as dd_dev_err, but is used when the message really needs + * the IB port# to be definitive as to what's happening.. + */ +#define hfi1_early_err(dev, fmt, ...) \ + dev_err(dev, fmt, ##__VA_ARGS__) + +#define hfi1_early_info(dev, fmt, ...) \ + dev_info(dev, fmt, ##__VA_ARGS__) + +#define dd_dev_emerg(dd, fmt, ...) \ + dev_emerg(&(dd)->pcidev->dev, "%s: " fmt, \ + get_unit_name((dd)->unit), ##__VA_ARGS__) +#define dd_dev_err(dd, fmt, ...) \ + dev_err(&(dd)->pcidev->dev, "%s: " fmt, \ + get_unit_name((dd)->unit), ##__VA_ARGS__) +#define dd_dev_warn(dd, fmt, ...) \ + dev_warn(&(dd)->pcidev->dev, "%s: " fmt, \ + get_unit_name((dd)->unit), ##__VA_ARGS__) + +#define dd_dev_warn_ratelimited(dd, fmt, ...) \ + dev_warn_ratelimited(&(dd)->pcidev->dev, "%s: " fmt, \ + get_unit_name((dd)->unit), ##__VA_ARGS__) + +#define dd_dev_info(dd, fmt, ...) \ + dev_info(&(dd)->pcidev->dev, "%s: " fmt, \ + get_unit_name((dd)->unit), ##__VA_ARGS__) + +#define hfi1_dev_porterr(dd, port, fmt, ...) \ + dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \ + get_unit_name((dd)->unit), (dd)->unit, (port), \ + ##__VA_ARGS__) + +/* + * this is used for formatting hw error messages... + */ +struct hfi1_hwerror_msgs { + u64 mask; + const char *msg; + size_t sz; +}; + +/* in intr.c... */ +void hfi1_format_hwerrors(u64 hwerrs, + const struct hfi1_hwerror_msgs *hwerrmsgs, + size_t nhwerrmsgs, char *msg, size_t lmsg); + +#define USER_OPCODE_CHECK_VAL 0xC0 +#define USER_OPCODE_CHECK_MASK 0xC0 +#define OPCODE_CHECK_VAL_DISABLED 0x0 +#define OPCODE_CHECK_MASK_DISABLED 0x0 + +static inline void hfi1_reset_cpu_counters(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd; + int i; + + dd->z_int_counter = get_all_cpu_total(dd->int_counter); + dd->z_rcv_limit = get_all_cpu_total(dd->rcv_limit); + + ppd = (struct hfi1_pportdata *)(dd + 1); + for (i = 0; i < dd->num_pports; i++, ppd++) { + ppd->ibport_data.z_rc_acks = + get_all_cpu_total(ppd->ibport_data.rc_acks); + ppd->ibport_data.z_rc_qacks = + get_all_cpu_total(ppd->ibport_data.rc_qacks); + } +} + +/* Control LED state */ +static inline void setextled(struct hfi1_devdata *dd, u32 on) +{ + if (on) + write_csr(dd, DCC_CFG_LED_CNTRL, 0x1F); + else + write_csr(dd, DCC_CFG_LED_CNTRL, 0x10); +} + +int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp); + +#endif /* _HFI1_KERNEL_H */ diff --git a/drivers/staging/rdma/hfi1/init.c b/drivers/staging/rdma/hfi1/init.c new file mode 100644 index 0000000000000..a877eda8c13c7 --- /dev/null +++ b/drivers/staging/rdma/hfi1/init.c @@ -0,0 +1,1722 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "device.h" +#include "common.h" +#include "mad.h" +#include "sdma.h" +#include "debugfs.h" +#include "verbs.h" + +#undef pr_fmt +#define pr_fmt(fmt) DRIVER_NAME ": " fmt + +/* + * min buffers we want to have per context, after driver + */ +#define HFI1_MIN_USER_CTXT_BUFCNT 7 + +#define HFI1_MIN_HDRQ_EGRBUF_CNT 2 +#define HFI1_MIN_EAGER_BUFFER_SIZE (4 * 1024) /* 4KB */ +#define HFI1_MAX_EAGER_BUFFER_SIZE (256 * 1024) /* 256KB */ + +/* + * Number of user receive contexts we are configured to use (to allow for more + * pio buffers per ctxt, etc.) Zero means use one user context per CPU. + */ +uint num_rcv_contexts; +module_param_named(num_rcv_contexts, num_rcv_contexts, uint, S_IRUGO); +MODULE_PARM_DESC( + num_rcv_contexts, "Set max number of user receive contexts to use"); + +u8 krcvqs[RXE_NUM_DATA_VL]; +int krcvqsset; +module_param_array(krcvqs, byte, &krcvqsset, S_IRUGO); +MODULE_PARM_DESC(krcvqs, "Array of the number of kernel receive queues by VL"); + +/* computed based on above array */ +unsigned n_krcvqs; + +static unsigned hfi1_rcvarr_split = 25; +module_param_named(rcvarr_split, hfi1_rcvarr_split, uint, S_IRUGO); +MODULE_PARM_DESC(rcvarr_split, "Percent of context's RcvArray entries used for Eager buffers"); + +static uint eager_buffer_size = (2 << 20); /* 2MB */ +module_param(eager_buffer_size, uint, S_IRUGO); +MODULE_PARM_DESC(eager_buffer_size, "Size of the eager buffers, default: 2MB"); + +static uint rcvhdrcnt = 2048; /* 2x the max eager buffer count */ +module_param_named(rcvhdrcnt, rcvhdrcnt, uint, S_IRUGO); +MODULE_PARM_DESC(rcvhdrcnt, "Receive header queue count (default 2048)"); + +static uint hfi1_hdrq_entsize = 32; +module_param_named(hdrq_entsize, hfi1_hdrq_entsize, uint, S_IRUGO); +MODULE_PARM_DESC(hdrq_entsize, "Size of header queue entries: 2 - 8B, 16 - 64B (default), 32 - 128B"); + +unsigned int user_credit_return_threshold = 33; /* default is 33% */ +module_param(user_credit_return_threshold, uint, S_IRUGO); +MODULE_PARM_DESC(user_credit_return_theshold, "Credit return threshold for user send contexts, return when unreturned credits passes this many blocks (in percent of allocated blocks, 0 is off)"); + +static inline u64 encode_rcv_header_entry_size(u16); + +static struct idr hfi1_unit_table; +u32 hfi1_cpulist_count; +unsigned long *hfi1_cpulist; + +/* + * Common code for creating the receive context array. + */ +int hfi1_create_ctxts(struct hfi1_devdata *dd) +{ + unsigned i; + int ret; + int local_node_id = pcibus_to_node(dd->pcidev->bus); + + if (local_node_id < 0) + local_node_id = numa_node_id(); + dd->assigned_node_id = local_node_id; + + dd->rcd = kcalloc(dd->num_rcv_contexts, sizeof(*dd->rcd), GFP_KERNEL); + if (!dd->rcd) { + dd_dev_err(dd, + "Unable to allocate receive context array, failing\n"); + goto nomem; + } + + /* create one or more kernel contexts */ + for (i = 0; i < dd->first_user_ctxt; ++i) { + struct hfi1_pportdata *ppd; + struct hfi1_ctxtdata *rcd; + + ppd = dd->pport + (i % dd->num_pports); + rcd = hfi1_create_ctxtdata(ppd, i); + if (!rcd) { + dd_dev_err(dd, + "Unable to allocate kernel receive context, failing\n"); + goto nomem; + } + /* + * Set up the kernel context flags here and now because they + * use default values for all receive side memories. User + * contexts will be handled as they are created. + */ + rcd->flags = HFI1_CAP_KGET(MULTI_PKT_EGR) | + HFI1_CAP_KGET(NODROP_RHQ_FULL) | + HFI1_CAP_KGET(NODROP_EGR_FULL) | + HFI1_CAP_KGET(DMA_RTAIL); + rcd->seq_cnt = 1; + + rcd->sc = sc_alloc(dd, SC_ACK, rcd->rcvhdrqentsize, dd->node); + if (!rcd->sc) { + dd_dev_err(dd, + "Unable to allocate kernel send context, failing\n"); + dd->rcd[rcd->ctxt] = NULL; + hfi1_free_ctxtdata(dd, rcd); + goto nomem; + } + + ret = hfi1_init_ctxt(rcd->sc); + if (ret < 0) { + dd_dev_err(dd, + "Failed to setup kernel receive context, failing\n"); + sc_free(rcd->sc); + dd->rcd[rcd->ctxt] = NULL; + hfi1_free_ctxtdata(dd, rcd); + ret = -EFAULT; + goto bail; + } + } + + return 0; +nomem: + ret = -ENOMEM; +bail: + kfree(dd->rcd); + dd->rcd = NULL; + return ret; +} + +/* + * Common code for user and kernel context setup. + */ +struct hfi1_ctxtdata *hfi1_create_ctxtdata(struct hfi1_pportdata *ppd, u32 ctxt) +{ + struct hfi1_devdata *dd = ppd->dd; + struct hfi1_ctxtdata *rcd; + unsigned kctxt_ngroups = 0; + u32 base; + + if (dd->rcv_entries.nctxt_extra > + dd->num_rcv_contexts - dd->first_user_ctxt) + kctxt_ngroups = (dd->rcv_entries.nctxt_extra - + (dd->num_rcv_contexts - dd->first_user_ctxt)); + rcd = kzalloc(sizeof(*rcd), GFP_KERNEL); + if (rcd) { + u32 rcvtids, max_entries; + + dd_dev_info(dd, "%s: setting up context %u\n", __func__, ctxt); + + INIT_LIST_HEAD(&rcd->qp_wait_list); + rcd->ppd = ppd; + rcd->dd = dd; + rcd->cnt = 1; + rcd->ctxt = ctxt; + dd->rcd[ctxt] = rcd; + rcd->numa_id = numa_node_id(); + rcd->rcv_array_groups = dd->rcv_entries.ngroups; + + spin_lock_init(&rcd->exp_lock); + + /* + * Calculate the context's RcvArray entry starting point. + * We do this here because we have to take into account all + * the RcvArray entries that previous context would have + * taken and we have to account for any extra groups + * assigned to the kernel or user contexts. + */ + if (ctxt < dd->first_user_ctxt) { + if (ctxt < kctxt_ngroups) { + base = ctxt * (dd->rcv_entries.ngroups + 1); + rcd->rcv_array_groups++; + } else + base = kctxt_ngroups + + (ctxt * dd->rcv_entries.ngroups); + } else { + u16 ct = ctxt - dd->first_user_ctxt; + + base = ((dd->n_krcv_queues * dd->rcv_entries.ngroups) + + kctxt_ngroups); + if (ct < dd->rcv_entries.nctxt_extra) { + base += ct * (dd->rcv_entries.ngroups + 1); + rcd->rcv_array_groups++; + } else + base += dd->rcv_entries.nctxt_extra + + (ct * dd->rcv_entries.ngroups); + } + rcd->eager_base = base * dd->rcv_entries.group_size; + + /* Validate and initialize Rcv Hdr Q variables */ + if (rcvhdrcnt % HDRQ_INCREMENT) { + dd_dev_err(dd, + "ctxt%u: header queue count %d must be divisible by %d\n", + rcd->ctxt, rcvhdrcnt, HDRQ_INCREMENT); + goto bail; + } + rcd->rcvhdrq_cnt = rcvhdrcnt; + rcd->rcvhdrqentsize = hfi1_hdrq_entsize; + /* + * Simple Eager buffer allocation: we have already pre-allocated + * the number of RcvArray entry groups. Each ctxtdata structure + * holds the number of groups for that context. + * + * To follow CSR requirements and maintain cacheline alignment, + * make sure all sizes and bases are multiples of group_size. + * + * The expected entry count is what is left after assigning + * eager. + */ + max_entries = rcd->rcv_array_groups * + dd->rcv_entries.group_size; + rcvtids = ((max_entries * hfi1_rcvarr_split) / 100); + rcd->egrbufs.count = round_down(rcvtids, + dd->rcv_entries.group_size); + if (rcd->egrbufs.count > MAX_EAGER_ENTRIES) { + dd_dev_err(dd, "ctxt%u: requested too many RcvArray entries.\n", + rcd->ctxt); + rcd->egrbufs.count = MAX_EAGER_ENTRIES; + } + dd_dev_info(dd, "ctxt%u: max Eager buffer RcvArray entries: %u\n", + rcd->ctxt, rcd->egrbufs.count); + + /* + * Allocate array that will hold the eager buffer accounting + * data. + * This will allocate the maximum possible buffer count based + * on the value of the RcvArray split parameter. + * The resulting value will be rounded down to the closest + * multiple of dd->rcv_entries.group_size. + */ + rcd->egrbufs.buffers = kzalloc(sizeof(*rcd->egrbufs.buffers) * + rcd->egrbufs.count, GFP_KERNEL); + if (!rcd->egrbufs.buffers) + goto bail; + rcd->egrbufs.rcvtids = kzalloc(sizeof(*rcd->egrbufs.rcvtids) * + rcd->egrbufs.count, GFP_KERNEL); + if (!rcd->egrbufs.rcvtids) + goto bail; + rcd->egrbufs.size = eager_buffer_size; + /* + * The size of the buffers programmed into the RcvArray + * entries needs to be big enough to handle the highest + * MTU supported. + */ + if (rcd->egrbufs.size < hfi1_max_mtu) { + rcd->egrbufs.size = __roundup_pow_of_two(hfi1_max_mtu); + dd_dev_info(dd, + "ctxt%u: eager bufs size too small. Adjusting to %zu\n", + rcd->ctxt, rcd->egrbufs.size); + } + rcd->egrbufs.rcvtid_size = HFI1_MAX_EAGER_BUFFER_SIZE; + + if (ctxt < dd->first_user_ctxt) { /* N/A for PSM contexts */ + rcd->opstats = kzalloc(sizeof(*rcd->opstats), + GFP_KERNEL); + if (!rcd->opstats) { + dd_dev_err(dd, + "ctxt%u: Unable to allocate per ctxt stats buffer\n", + rcd->ctxt); + goto bail; + } + } + } + return rcd; +bail: + kfree(rcd->opstats); + kfree(rcd->egrbufs.rcvtids); + kfree(rcd->egrbufs.buffers); + kfree(rcd); + return NULL; +} + +/* + * Convert a receive header entry size that to the encoding used in the CSR. + * + * Return a zero if the given size is invalid. + */ +static inline u64 encode_rcv_header_entry_size(u16 size) +{ + /* there are only 3 valid receive header entry sizes */ + if (size == 2) + return 1; + if (size == 16) + return 2; + else if (size == 32) + return 4; + return 0; /* invalid */ +} + +/* + * Select the largest ccti value over all SLs to determine the intra- + * packet gap for the link. + * + * called with cca_timer_lock held (to protect access to cca_timer + * array), and rcu_read_lock() (to protect access to cc_state). + */ +void set_link_ipg(struct hfi1_pportdata *ppd) +{ + struct hfi1_devdata *dd = ppd->dd; + struct cc_state *cc_state; + int i; + u16 cce, ccti_limit, max_ccti = 0; + u16 shift, mult; + u64 src; + u32 current_egress_rate; /* Mbits /sec */ + u32 max_pkt_time; + /* + * max_pkt_time is the maximum packet egress time in units + * of the fabric clock period 1/(805 MHz). + */ + + cc_state = get_cc_state(ppd); + + if (cc_state == NULL) + /* + * This should _never_ happen - rcu_read_lock() is held, + * and set_link_ipg() should not be called if cc_state + * is NULL. + */ + return; + + for (i = 0; i < OPA_MAX_SLS; i++) { + u16 ccti = ppd->cca_timer[i].ccti; + + if (ccti > max_ccti) + max_ccti = ccti; + } + + ccti_limit = cc_state->cct.ccti_limit; + if (max_ccti > ccti_limit) + max_ccti = ccti_limit; + + cce = cc_state->cct.entries[max_ccti].entry; + shift = (cce & 0xc000) >> 14; + mult = (cce & 0x3fff); + + current_egress_rate = active_egress_rate(ppd); + + max_pkt_time = egress_cycles(ppd->ibmaxlen, current_egress_rate); + + src = (max_pkt_time >> shift) * mult; + + src &= SEND_STATIC_RATE_CONTROL_CSR_SRC_RELOAD_SMASK; + src <<= SEND_STATIC_RATE_CONTROL_CSR_SRC_RELOAD_SHIFT; + + write_csr(dd, SEND_STATIC_RATE_CONTROL, src); +} + +static enum hrtimer_restart cca_timer_fn(struct hrtimer *t) +{ + struct cca_timer *cca_timer; + struct hfi1_pportdata *ppd; + int sl; + u16 ccti, ccti_timer, ccti_min; + struct cc_state *cc_state; + + cca_timer = container_of(t, struct cca_timer, hrtimer); + ppd = cca_timer->ppd; + sl = cca_timer->sl; + + rcu_read_lock(); + + cc_state = get_cc_state(ppd); + + if (cc_state == NULL) { + rcu_read_unlock(); + return HRTIMER_NORESTART; + } + + /* + * 1) decrement ccti for SL + * 2) calculate IPG for link (set_link_ipg()) + * 3) restart timer, unless ccti is at min value + */ + + ccti_min = cc_state->cong_setting.entries[sl].ccti_min; + ccti_timer = cc_state->cong_setting.entries[sl].ccti_timer; + + spin_lock(&ppd->cca_timer_lock); + + ccti = cca_timer->ccti; + + if (ccti > ccti_min) { + cca_timer->ccti--; + set_link_ipg(ppd); + } + + spin_unlock(&ppd->cca_timer_lock); + + rcu_read_unlock(); + + if (ccti > ccti_min) { + unsigned long nsec = 1024 * ccti_timer; + /* ccti_timer is in units of 1.024 usec */ + hrtimer_forward_now(t, ns_to_ktime(nsec)); + return HRTIMER_RESTART; + } + return HRTIMER_NORESTART; +} + +/* + * Common code for initializing the physical port structure. + */ +void hfi1_init_pportdata(struct pci_dev *pdev, struct hfi1_pportdata *ppd, + struct hfi1_devdata *dd, u8 hw_pidx, u8 port) +{ + int i, size; + uint default_pkey_idx; + + ppd->dd = dd; + ppd->hw_pidx = hw_pidx; + ppd->port = port; /* IB port number, not index */ + + default_pkey_idx = 1; + + ppd->pkeys[default_pkey_idx] = DEFAULT_P_KEY; + if (loopback) { + hfi1_early_err(&pdev->dev, + "Faking data partition 0x8001 in idx %u\n", + !default_pkey_idx); + ppd->pkeys[!default_pkey_idx] = 0x8001; + } + + INIT_WORK(&ppd->link_vc_work, handle_verify_cap); + INIT_WORK(&ppd->link_up_work, handle_link_up); + INIT_WORK(&ppd->link_down_work, handle_link_down); + INIT_WORK(&ppd->freeze_work, handle_freeze); + INIT_WORK(&ppd->link_downgrade_work, handle_link_downgrade); + INIT_WORK(&ppd->sma_message_work, handle_sma_message); + INIT_WORK(&ppd->link_bounce_work, handle_link_bounce); + mutex_init(&ppd->hls_lock); + spin_lock_init(&ppd->sdma_alllock); + spin_lock_init(&ppd->qsfp_info.qsfp_lock); + + ppd->sm_trap_qp = 0x0; + ppd->sa_qp = 0x1; + + ppd->hfi1_wq = NULL; + + spin_lock_init(&ppd->cca_timer_lock); + + for (i = 0; i < OPA_MAX_SLS; i++) { + hrtimer_init(&ppd->cca_timer[i].hrtimer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + ppd->cca_timer[i].ppd = ppd; + ppd->cca_timer[i].sl = i; + ppd->cca_timer[i].ccti = 0; + ppd->cca_timer[i].hrtimer.function = cca_timer_fn; + } + + ppd->cc_max_table_entries = IB_CC_TABLE_CAP_DEFAULT; + + spin_lock_init(&ppd->cc_state_lock); + spin_lock_init(&ppd->cc_log_lock); + size = sizeof(struct cc_state); + RCU_INIT_POINTER(ppd->cc_state, kzalloc(size, GFP_KERNEL)); + if (!rcu_dereference(ppd->cc_state)) + goto bail; + return; + +bail: + + hfi1_early_err(&pdev->dev, + "Congestion Control Agent disabled for port %d\n", port); +} + +/* + * Do initialization for device that is only needed on + * first detect, not on resets. + */ +static int loadtime_init(struct hfi1_devdata *dd) +{ + return 0; +} + +/** + * init_after_reset - re-initialize after a reset + * @dd: the hfi1_ib device + * + * sanity check at least some of the values after reset, and + * ensure no receive or transmit (explicitly, in case reset + * failed + */ +static int init_after_reset(struct hfi1_devdata *dd) +{ + int i; + + /* + * Ensure chip does no sends or receives, tail updates, or + * pioavail updates while we re-initialize. This is mostly + * for the driver data structures, not chip registers. + */ + for (i = 0; i < dd->num_rcv_contexts; i++) + hfi1_rcvctrl(dd, HFI1_RCVCTRL_CTXT_DIS | + HFI1_RCVCTRL_INTRAVAIL_DIS | + HFI1_RCVCTRL_TAILUPD_DIS, i); + pio_send_control(dd, PSC_GLOBAL_DISABLE); + for (i = 0; i < dd->num_send_contexts; i++) + sc_disable(dd->send_contexts[i].sc); + + return 0; +} + +static void enable_chip(struct hfi1_devdata *dd) +{ + u32 rcvmask; + u32 i; + + /* enable PIO send */ + pio_send_control(dd, PSC_GLOBAL_ENABLE); + + /* + * Enable kernel ctxts' receive and receive interrupt. + * Other ctxts done as user opens and initializes them. + */ + rcvmask = HFI1_RCVCTRL_CTXT_ENB | HFI1_RCVCTRL_INTRAVAIL_ENB; + for (i = 0; i < dd->first_user_ctxt; ++i) { + rcvmask |= HFI1_CAP_KGET_MASK(dd->rcd[i]->flags, DMA_RTAIL) ? + HFI1_RCVCTRL_TAILUPD_ENB : HFI1_RCVCTRL_TAILUPD_DIS; + if (!HFI1_CAP_KGET_MASK(dd->rcd[i]->flags, MULTI_PKT_EGR)) + rcvmask |= HFI1_RCVCTRL_ONE_PKT_EGR_ENB; + if (HFI1_CAP_KGET_MASK(dd->rcd[i]->flags, NODROP_RHQ_FULL)) + rcvmask |= HFI1_RCVCTRL_NO_RHQ_DROP_ENB; + if (HFI1_CAP_KGET_MASK(dd->rcd[i]->flags, NODROP_EGR_FULL)) + rcvmask |= HFI1_RCVCTRL_NO_EGR_DROP_ENB; + hfi1_rcvctrl(dd, rcvmask, i); + sc_enable(dd->rcd[i]->sc); + } +} + +/** + * create_workqueues - create per port workqueues + * @dd: the hfi1_ib device + */ +static int create_workqueues(struct hfi1_devdata *dd) +{ + int pidx; + struct hfi1_pportdata *ppd; + + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (!ppd->hfi1_wq) { + char wq_name[8]; /* 3 + 2 + 1 + 1 + 1 */ + + snprintf(wq_name, sizeof(wq_name), "hfi%d_%d", + dd->unit, pidx); + ppd->hfi1_wq = + create_singlethread_workqueue(wq_name); + if (!ppd->hfi1_wq) + goto wq_error; + } + } + return 0; +wq_error: + pr_err("create_singlethread_workqueue failed for port %d\n", + pidx + 1); + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (ppd->hfi1_wq) { + destroy_workqueue(ppd->hfi1_wq); + ppd->hfi1_wq = NULL; + } + } + return -ENOMEM; +} + +/** + * hfi1_init - do the actual initialization sequence on the chip + * @dd: the hfi1_ib device + * @reinit: re-initializing, so don't allocate new memory + * + * Do the actual initialization sequence on the chip. This is done + * both from the init routine called from the PCI infrastructure, and + * when we reset the chip, or detect that it was reset internally, + * or it's administratively re-enabled. + * + * Memory allocation here and in called routines is only done in + * the first case (reinit == 0). We have to be careful, because even + * without memory allocation, we need to re-write all the chip registers + * TIDs, etc. after the reset or enable has completed. + */ +int hfi1_init(struct hfi1_devdata *dd, int reinit) +{ + int ret = 0, pidx, lastfail = 0; + unsigned i, len; + struct hfi1_ctxtdata *rcd; + struct hfi1_pportdata *ppd; + + /* Set up recv low level handlers */ + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_EXPECTED] = + kdeth_process_expected; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_EAGER] = + kdeth_process_eager; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_IB] = process_receive_ib; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_ERROR] = + process_receive_error; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_BYPASS] = + process_receive_bypass; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_INVALID5] = + process_receive_invalid; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_INVALID6] = + process_receive_invalid; + dd->normal_rhf_rcv_functions[RHF_RCV_TYPE_INVALID7] = + process_receive_invalid; + dd->rhf_rcv_function_map = dd->normal_rhf_rcv_functions; + + /* Set up send low level handlers */ + dd->process_pio_send = hfi1_verbs_send_pio; + dd->process_dma_send = hfi1_verbs_send_dma; + dd->pio_inline_send = pio_copy; + + if (is_a0(dd)) { + atomic_set(&dd->drop_packet, DROP_PACKET_ON); + dd->do_drop = 1; + } else { + atomic_set(&dd->drop_packet, DROP_PACKET_OFF); + dd->do_drop = 0; + } + + /* make sure the link is not "up" */ + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + ppd->linkup = 0; + } + + if (reinit) + ret = init_after_reset(dd); + else + ret = loadtime_init(dd); + if (ret) + goto done; + + /* dd->rcd can be NULL if early initialization failed */ + for (i = 0; dd->rcd && i < dd->first_user_ctxt; ++i) { + /* + * Set up the (kernel) rcvhdr queue and egr TIDs. If doing + * re-init, the simplest way to handle this is to free + * existing, and re-allocate. + * Need to re-create rest of ctxt 0 ctxtdata as well. + */ + rcd = dd->rcd[i]; + if (!rcd) + continue; + + rcd->do_interrupt = &handle_receive_interrupt; + + lastfail = hfi1_create_rcvhdrq(dd, rcd); + if (!lastfail) + lastfail = hfi1_setup_eagerbufs(rcd); + if (lastfail) + dd_dev_err(dd, + "failed to allocate kernel ctxt's rcvhdrq and/or egr bufs\n"); + } + if (lastfail) + ret = lastfail; + + /* Allocate enough memory for user event notification. */ + len = ALIGN(dd->chip_rcv_contexts * HFI1_MAX_SHARED_CTXTS * + sizeof(*dd->events), PAGE_SIZE); + dd->events = vmalloc_user(len); + if (!dd->events) + dd_dev_err(dd, "Failed to allocate user events page\n"); + /* + * Allocate a page for device and port status. + * Page will be shared amongst all user processes. + */ + dd->status = vmalloc_user(PAGE_SIZE); + if (!dd->status) + dd_dev_err(dd, "Failed to allocate dev status page\n"); + else + dd->freezelen = PAGE_SIZE - (sizeof(*dd->status) - + sizeof(dd->status->freezemsg)); + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (dd->status) + /* Currently, we only have one port */ + ppd->statusp = &dd->status->port; + + set_mtu(ppd); + } + + /* enable chip even if we have an error, so we can debug cause */ + enable_chip(dd); + + ret = hfi1_cq_init(dd); +done: + /* + * Set status even if port serdes is not initialized + * so that diags will work. + */ + if (dd->status) + dd->status->dev |= HFI1_STATUS_CHIP_PRESENT | + HFI1_STATUS_INITTED; + if (!ret) { + /* enable all interrupts from the chip */ + set_intr_state(dd, 1); + + /* chip is OK for user apps; mark it as initialized */ + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + + /* initialize the qsfp if it exists + * Requires interrupts to be enabled so we are notified + * when the QSFP completes reset, and has + * to be done before bringing up the SERDES + */ + init_qsfp(ppd); + + /* start the serdes - must be after interrupts are + enabled so we are notified when the link goes up */ + lastfail = bringup_serdes(ppd); + if (lastfail) + dd_dev_info(dd, + "Failed to bring up port %u\n", + ppd->port); + + /* + * Set status even if port serdes is not initialized + * so that diags will work. + */ + if (ppd->statusp) + *ppd->statusp |= HFI1_STATUS_CHIP_PRESENT | + HFI1_STATUS_INITTED; + if (!ppd->link_speed_enabled) + continue; + } + } + + /* if ret is non-zero, we probably should do some cleanup here... */ + return ret; +} + +static inline struct hfi1_devdata *__hfi1_lookup(int unit) +{ + return idr_find(&hfi1_unit_table, unit); +} + +struct hfi1_devdata *hfi1_lookup(int unit) +{ + struct hfi1_devdata *dd; + unsigned long flags; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + dd = __hfi1_lookup(unit); + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + + return dd; +} + +/* + * Stop the timers during unit shutdown, or after an error late + * in initialization. + */ +static void stop_timers(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd; + int pidx; + + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + if (ppd->led_override_timer.data) { + del_timer_sync(&ppd->led_override_timer); + atomic_set(&ppd->led_override_timer_active, 0); + } + } +} + +/** + * shutdown_device - shut down a device + * @dd: the hfi1_ib device + * + * This is called to make the device quiet when we are about to + * unload the driver, and also when the device is administratively + * disabled. It does not free any data structures. + * Everything it does has to be setup again by hfi1_init(dd, 1) + */ +static void shutdown_device(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd; + unsigned pidx; + int i; + + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + + ppd->linkup = 0; + if (ppd->statusp) + *ppd->statusp &= ~(HFI1_STATUS_IB_CONF | + HFI1_STATUS_IB_READY); + } + dd->flags &= ~HFI1_INITTED; + + /* mask interrupts, but not errors */ + set_intr_state(dd, 0); + + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + for (i = 0; i < dd->num_rcv_contexts; i++) + hfi1_rcvctrl(dd, HFI1_RCVCTRL_TAILUPD_DIS | + HFI1_RCVCTRL_CTXT_DIS | + HFI1_RCVCTRL_INTRAVAIL_DIS | + HFI1_RCVCTRL_PKEY_DIS | + HFI1_RCVCTRL_ONE_PKT_EGR_DIS, i); + /* + * Gracefully stop all sends allowing any in progress to + * trickle out first. + */ + for (i = 0; i < dd->num_send_contexts; i++) + sc_flush(dd->send_contexts[i].sc); + } + + /* + * Enough for anything that's going to trickle out to have actually + * done so. + */ + udelay(20); + + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + ppd = dd->pport + pidx; + + /* disable all contexts */ + for (i = 0; i < dd->num_send_contexts; i++) + sc_disable(dd->send_contexts[i].sc); + /* disable the send device */ + pio_send_control(dd, PSC_GLOBAL_DISABLE); + + /* + * Clear SerdesEnable. + * We can't count on interrupts since we are stopping. + */ + hfi1_quiet_serdes(ppd); + + if (ppd->hfi1_wq) { + destroy_workqueue(ppd->hfi1_wq); + ppd->hfi1_wq = NULL; + } + } + sdma_exit(dd); +} + +/** + * hfi1_free_ctxtdata - free a context's allocated data + * @dd: the hfi1_ib device + * @rcd: the ctxtdata structure + * + * free up any allocated data for a context + * This should not touch anything that would affect a simultaneous + * re-allocation of context data, because it is called after hfi1_mutex + * is released (and can be called from reinit as well). + * It should never change any chip state, or global driver state. + */ +void hfi1_free_ctxtdata(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) +{ + unsigned e; + + if (!rcd) + return; + + if (rcd->rcvhdrq) { + dma_free_coherent(&dd->pcidev->dev, rcd->rcvhdrq_size, + rcd->rcvhdrq, rcd->rcvhdrq_phys); + rcd->rcvhdrq = NULL; + if (rcd->rcvhdrtail_kvaddr) { + dma_free_coherent(&dd->pcidev->dev, PAGE_SIZE, + (void *)rcd->rcvhdrtail_kvaddr, + rcd->rcvhdrqtailaddr_phys); + rcd->rcvhdrtail_kvaddr = NULL; + } + } + + /* all the RcvArray entries should have been cleared by now */ + kfree(rcd->egrbufs.rcvtids); + + for (e = 0; e < rcd->egrbufs.alloced; e++) { + if (rcd->egrbufs.buffers[e].phys) + dma_free_coherent(&dd->pcidev->dev, + rcd->egrbufs.buffers[e].len, + rcd->egrbufs.buffers[e].addr, + rcd->egrbufs.buffers[e].phys); + } + kfree(rcd->egrbufs.buffers); + + sc_free(rcd->sc); + vfree(rcd->physshadow); + vfree(rcd->tid_pg_list); + vfree(rcd->user_event_mask); + vfree(rcd->subctxt_uregbase); + vfree(rcd->subctxt_rcvegrbuf); + vfree(rcd->subctxt_rcvhdr_base); + kfree(rcd->tidusemap); + kfree(rcd->opstats); + kfree(rcd); +} + +void hfi1_free_devdata(struct hfi1_devdata *dd) +{ + unsigned long flags; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + idr_remove(&hfi1_unit_table, dd->unit); + list_del(&dd->list); + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + hfi1_dbg_ibdev_exit(&dd->verbs_dev); + rcu_barrier(); /* wait for rcu callbacks to complete */ + free_percpu(dd->int_counter); + free_percpu(dd->rcv_limit); + ib_dealloc_device(&dd->verbs_dev.ibdev); +} + +/* + * Allocate our primary per-unit data structure. Must be done via verbs + * allocator, because the verbs cleanup process both does cleanup and + * free of the data structure. + * "extra" is for chip-specific data. + * + * Use the idr mechanism to get a unit number for this unit. + */ +struct hfi1_devdata *hfi1_alloc_devdata(struct pci_dev *pdev, size_t extra) +{ + unsigned long flags; + struct hfi1_devdata *dd; + int ret; + + dd = (struct hfi1_devdata *)ib_alloc_device(sizeof(*dd) + extra); + if (!dd) + return ERR_PTR(-ENOMEM); + /* extra is * number of ports */ + dd->num_pports = extra / sizeof(struct hfi1_pportdata); + dd->pport = (struct hfi1_pportdata *)(dd + 1); + + INIT_LIST_HEAD(&dd->list); + dd->node = dev_to_node(&pdev->dev); + if (dd->node < 0) + dd->node = 0; + idr_preload(GFP_KERNEL); + spin_lock_irqsave(&hfi1_devs_lock, flags); + + ret = idr_alloc(&hfi1_unit_table, dd, 0, 0, GFP_NOWAIT); + if (ret >= 0) { + dd->unit = ret; + list_add(&dd->list, &hfi1_dev_list); + } + + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + idr_preload_end(); + + if (ret < 0) { + hfi1_early_err(&pdev->dev, + "Could not allocate unit ID: error %d\n", -ret); + goto bail; + } + /* + * Initialize all locks for the device. This needs to be as early as + * possible so locks are usable. + */ + spin_lock_init(&dd->sc_lock); + spin_lock_init(&dd->sendctrl_lock); + spin_lock_init(&dd->rcvctrl_lock); + spin_lock_init(&dd->uctxt_lock); + spin_lock_init(&dd->hfi1_diag_trans_lock); + spin_lock_init(&dd->sc_init_lock); + spin_lock_init(&dd->dc8051_lock); + spin_lock_init(&dd->dc8051_memlock); + mutex_init(&dd->qsfp_i2c_mutex); + seqlock_init(&dd->sc2vl_lock); + spin_lock_init(&dd->sde_map_lock); + init_waitqueue_head(&dd->event_queue); + + dd->int_counter = alloc_percpu(u64); + if (!dd->int_counter) { + ret = -ENOMEM; + hfi1_early_err(&pdev->dev, + "Could not allocate per-cpu int_counter\n"); + goto bail; + } + + dd->rcv_limit = alloc_percpu(u64); + if (!dd->rcv_limit) { + ret = -ENOMEM; + hfi1_early_err(&pdev->dev, + "Could not allocate per-cpu rcv_limit\n"); + goto bail; + } + + if (!hfi1_cpulist_count) { + u32 count = num_online_cpus(); + + hfi1_cpulist = kzalloc(BITS_TO_LONGS(count) * + sizeof(long), GFP_KERNEL); + if (hfi1_cpulist) + hfi1_cpulist_count = count; + else + hfi1_early_err( + &pdev->dev, + "Could not alloc cpulist info, cpu affinity might be wrong\n"); + } + hfi1_dbg_ibdev_init(&dd->verbs_dev); + return dd; + +bail: + if (!list_empty(&dd->list)) + list_del_init(&dd->list); + ib_dealloc_device(&dd->verbs_dev.ibdev); + return ERR_PTR(ret); +} + +/* + * Called from freeze mode handlers, and from PCI error + * reporting code. Should be paranoid about state of + * system and data structures. + */ +void hfi1_disable_after_error(struct hfi1_devdata *dd) +{ + if (dd->flags & HFI1_INITTED) { + u32 pidx; + + dd->flags &= ~HFI1_INITTED; + if (dd->pport) + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + struct hfi1_pportdata *ppd; + + ppd = dd->pport + pidx; + if (dd->flags & HFI1_PRESENT) + set_link_state(ppd, HLS_DN_DISABLE); + + if (ppd->statusp) + *ppd->statusp &= ~HFI1_STATUS_IB_READY; + } + } + + /* + * Mark as having had an error for driver, and also + * for /sys and status word mapped to user programs. + * This marks unit as not usable, until reset. + */ + if (dd->status) + dd->status->dev |= HFI1_STATUS_HWERROR; +} + +static void remove_one(struct pci_dev *); +static int init_one(struct pci_dev *, const struct pci_device_id *); + +#define DRIVER_LOAD_MSG "Intel " DRIVER_NAME " loaded: " +#define PFX DRIVER_NAME ": " + +static const struct pci_device_id hfi1_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL0) }, + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL1) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, hfi1_pci_tbl); + +static struct pci_driver hfi1_pci_driver = { + .name = DRIVER_NAME, + .probe = init_one, + .remove = remove_one, + .id_table = hfi1_pci_tbl, + .err_handler = &hfi1_pci_err_handler, +}; + +static void __init compute_krcvqs(void) +{ + int i; + + for (i = 0; i < krcvqsset; i++) + n_krcvqs += krcvqs[i]; +} + +/* + * Do all the generic driver unit- and chip-independent memory + * allocation and initialization. + */ +static int __init hfi1_mod_init(void) +{ + int ret; + + ret = dev_init(); + if (ret) + goto bail; + + /* validate max MTU before any devices start */ + if (!valid_opa_max_mtu(hfi1_max_mtu)) { + pr_err("Invalid max_mtu 0x%x, using 0x%x instead\n", + hfi1_max_mtu, HFI1_DEFAULT_MAX_MTU); + hfi1_max_mtu = HFI1_DEFAULT_MAX_MTU; + } + /* valid CUs run from 1-128 in powers of 2 */ + if (hfi1_cu > 128 || !is_power_of_2(hfi1_cu)) + hfi1_cu = 1; + /* valid credit return threshold is 0-100, variable is unsigned */ + if (user_credit_return_threshold > 100) + user_credit_return_threshold = 100; + + compute_krcvqs(); + /* sanitize receive interrupt count, time must wait until after + the hardware type is known */ + if (rcv_intr_count > RCV_HDR_HEAD_COUNTER_MASK) + rcv_intr_count = RCV_HDR_HEAD_COUNTER_MASK; + /* reject invalid combinations */ + if (rcv_intr_count == 0 && rcv_intr_timeout == 0) { + pr_err("Invalid mode: both receive interrupt count and available timeout are zero - setting interrupt count to 1\n"); + rcv_intr_count = 1; + } + if (rcv_intr_count > 1 && rcv_intr_timeout == 0) { + /* + * Avoid indefinite packet delivery by requiring a timeout + * if count is > 1. + */ + pr_err("Invalid mode: receive interrupt count greater than 1 and available timeout is zero - setting available timeout to 1\n"); + rcv_intr_timeout = 1; + } + if (rcv_intr_dynamic && !(rcv_intr_count > 1 && rcv_intr_timeout > 0)) { + /* + * The dynamic algorithm expects a non-zero timeout + * and a count > 1. + */ + pr_err("Invalid mode: dynamic receive interrupt mitigation with invalid count and timeout - turning dynamic off\n"); + rcv_intr_dynamic = 0; + } + + /* sanitize link CRC options */ + link_crc_mask &= SUPPORTED_CRCS; + + /* + * These must be called before the driver is registered with + * the PCI subsystem. + */ + idr_init(&hfi1_unit_table); + + hfi1_dbg_init(); + ret = pci_register_driver(&hfi1_pci_driver); + if (ret < 0) { + pr_err("Unable to register driver: error %d\n", -ret); + goto bail_dev; + } + goto bail; /* all OK */ + +bail_dev: + hfi1_dbg_exit(); + idr_destroy(&hfi1_unit_table); + dev_cleanup(); +bail: + return ret; +} + +module_init(hfi1_mod_init); + +/* + * Do the non-unit driver cleanup, memory free, etc. at unload. + */ +static void __exit hfi1_mod_cleanup(void) +{ + pci_unregister_driver(&hfi1_pci_driver); + hfi1_dbg_exit(); + hfi1_cpulist_count = 0; + kfree(hfi1_cpulist); + + idr_destroy(&hfi1_unit_table); + dispose_firmware(); /* asymmetric with obtain_firmware() */ + dev_cleanup(); +} + +module_exit(hfi1_mod_cleanup); + +/* this can only be called after a successful initialization */ +static void cleanup_device_data(struct hfi1_devdata *dd) +{ + int ctxt; + int pidx; + struct hfi1_ctxtdata **tmp; + unsigned long flags; + + /* users can't do anything more with chip */ + for (pidx = 0; pidx < dd->num_pports; ++pidx) { + struct hfi1_pportdata *ppd = &dd->pport[pidx]; + struct cc_state *cc_state; + int i; + + if (ppd->statusp) + *ppd->statusp &= ~HFI1_STATUS_CHIP_PRESENT; + + for (i = 0; i < OPA_MAX_SLS; i++) + hrtimer_cancel(&ppd->cca_timer[i].hrtimer); + + spin_lock(&ppd->cc_state_lock); + cc_state = get_cc_state(ppd); + rcu_assign_pointer(ppd->cc_state, NULL); + spin_unlock(&ppd->cc_state_lock); + + if (cc_state) + call_rcu(&cc_state->rcu, cc_state_reclaim); + } + + free_credit_return(dd); + + /* + * Free any resources still in use (usually just kernel contexts) + * at unload; we do for ctxtcnt, because that's what we allocate. + * We acquire lock to be really paranoid that rcd isn't being + * accessed from some interrupt-related code (that should not happen, + * but best to be sure). + */ + spin_lock_irqsave(&dd->uctxt_lock, flags); + tmp = dd->rcd; + dd->rcd = NULL; + spin_unlock_irqrestore(&dd->uctxt_lock, flags); + for (ctxt = 0; tmp && ctxt < dd->num_rcv_contexts; ctxt++) { + struct hfi1_ctxtdata *rcd = tmp[ctxt]; + + tmp[ctxt] = NULL; /* debugging paranoia */ + if (rcd) { + hfi1_clear_tids(rcd); + hfi1_free_ctxtdata(dd, rcd); + } + } + kfree(tmp); + /* must follow rcv context free - need to remove rcv's hooks */ + for (ctxt = 0; ctxt < dd->num_send_contexts; ctxt++) + sc_free(dd->send_contexts[ctxt].sc); + dd->num_send_contexts = 0; + kfree(dd->send_contexts); + dd->send_contexts = NULL; + kfree(dd->boardname); + vfree(dd->events); + vfree(dd->status); + hfi1_cq_exit(dd); +} + +/* + * Clean up on unit shutdown, or error during unit load after + * successful initialization. + */ +static void postinit_cleanup(struct hfi1_devdata *dd) +{ + hfi1_start_cleanup(dd); + + hfi1_pcie_ddcleanup(dd); + hfi1_pcie_cleanup(dd->pcidev); + + cleanup_device_data(dd); + + hfi1_free_devdata(dd); +} + +static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int ret = 0, j, pidx, initfail; + struct hfi1_devdata *dd = NULL; + + /* First, lock the non-writable module parameters */ + HFI1_CAP_LOCK(); + + /* Validate some global module parameters */ + if (rcvhdrcnt <= HFI1_MIN_HDRQ_EGRBUF_CNT) { + hfi1_early_err(&pdev->dev, "Header queue count too small\n"); + ret = -EINVAL; + goto bail; + } + /* use the encoding function as a sanitization check */ + if (!encode_rcv_header_entry_size(hfi1_hdrq_entsize)) { + hfi1_early_err(&pdev->dev, "Invalid HdrQ Entry size %u\n", + hfi1_hdrq_entsize); + goto bail; + } + + /* The receive eager buffer size must be set before the receive + * contexts are created. + * + * Set the eager buffer size. Validate that it falls in a range + * allowed by the hardware - all powers of 2 between the min and + * max. The maximum valid MTU is within the eager buffer range + * so we do not need to cap the max_mtu by an eager buffer size + * setting. + */ + if (eager_buffer_size) { + if (!is_power_of_2(eager_buffer_size)) + eager_buffer_size = + roundup_pow_of_two(eager_buffer_size); + eager_buffer_size = + clamp_val(eager_buffer_size, + MIN_EAGER_BUFFER * 8, + MAX_EAGER_BUFFER_TOTAL); + hfi1_early_info(&pdev->dev, "Eager buffer size %u\n", + eager_buffer_size); + } else { + hfi1_early_err(&pdev->dev, "Invalid Eager buffer size of 0\n"); + ret = -EINVAL; + goto bail; + } + + /* restrict value of hfi1_rcvarr_split */ + hfi1_rcvarr_split = clamp_val(hfi1_rcvarr_split, 0, 100); + + ret = hfi1_pcie_init(pdev, ent); + if (ret) + goto bail; + + /* + * Do device-specific initialization, function table setup, dd + * allocation, etc. + */ + switch (ent->device) { + case PCI_DEVICE_ID_INTEL0: + case PCI_DEVICE_ID_INTEL1: + dd = hfi1_init_dd(pdev, ent); + break; + default: + hfi1_early_err(&pdev->dev, + "Failing on unknown Intel deviceid 0x%x\n", + ent->device); + ret = -ENODEV; + } + + if (IS_ERR(dd)) + ret = PTR_ERR(dd); + if (ret) + goto clean_bail; /* error already printed */ + + ret = create_workqueues(dd); + if (ret) + goto clean_bail; + + /* do the generic initialization */ + initfail = hfi1_init(dd, 0); + + ret = hfi1_register_ib_device(dd); + + /* + * Now ready for use. this should be cleared whenever we + * detect a reset, or initiate one. If earlier failure, + * we still create devices, so diags, etc. can be used + * to determine cause of problem. + */ + if (!initfail && !ret) + dd->flags |= HFI1_INITTED; + + j = hfi1_device_create(dd); + if (j) + dd_dev_err(dd, "Failed to create /dev devices: %d\n", -j); + + if (initfail || ret) { + stop_timers(dd); + flush_workqueue(ib_wq); + for (pidx = 0; pidx < dd->num_pports; ++pidx) + hfi1_quiet_serdes(dd->pport + pidx); + if (!j) + hfi1_device_remove(dd); + if (!ret) + hfi1_unregister_ib_device(dd); + postinit_cleanup(dd); + if (initfail) + ret = initfail; + goto bail; /* everything already cleaned */ + } + + sdma_start(dd); + + return 0; + +clean_bail: + hfi1_pcie_cleanup(pdev); +bail: + return ret; +} + +static void remove_one(struct pci_dev *pdev) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + + /* unregister from IB core */ + hfi1_unregister_ib_device(dd); + + /* + * Disable the IB link, disable interrupts on the device, + * clear dma engines, etc. + */ + shutdown_device(dd); + + stop_timers(dd); + + /* wait until all of our (qsfp) queue_work() calls complete */ + flush_workqueue(ib_wq); + + hfi1_device_remove(dd); + + postinit_cleanup(dd); +} + +/** + * hfi1_create_rcvhdrq - create a receive header queue + * @dd: the hfi1_ib device + * @rcd: the context data + * + * This must be contiguous memory (from an i/o perspective), and must be + * DMA'able (which means for some systems, it will go through an IOMMU, + * or be forced into a low address range). + */ +int hfi1_create_rcvhdrq(struct hfi1_devdata *dd, struct hfi1_ctxtdata *rcd) +{ + unsigned amt; + u64 reg; + + if (!rcd->rcvhdrq) { + dma_addr_t phys_hdrqtail; + gfp_t gfp_flags; + + /* + * rcvhdrqentsize is in DWs, so we have to convert to bytes + * (* sizeof(u32)). + */ + amt = ALIGN(rcd->rcvhdrq_cnt * rcd->rcvhdrqentsize * + sizeof(u32), PAGE_SIZE); + + gfp_flags = (rcd->ctxt >= dd->first_user_ctxt) ? + GFP_USER : GFP_KERNEL; + rcd->rcvhdrq = dma_zalloc_coherent( + &dd->pcidev->dev, amt, &rcd->rcvhdrq_phys, + gfp_flags | __GFP_COMP); + + if (!rcd->rcvhdrq) { + dd_dev_err(dd, + "attempt to allocate %d bytes for ctxt %u rcvhdrq failed\n", + amt, rcd->ctxt); + goto bail; + } + + /* Event mask is per device now and is in hfi1_devdata */ + /*if (rcd->ctxt >= dd->first_user_ctxt) { + rcd->user_event_mask = vmalloc_user(PAGE_SIZE); + if (!rcd->user_event_mask) + goto bail_free_hdrq; + }*/ + + if (HFI1_CAP_KGET_MASK(rcd->flags, DMA_RTAIL)) { + rcd->rcvhdrtail_kvaddr = dma_zalloc_coherent( + &dd->pcidev->dev, PAGE_SIZE, &phys_hdrqtail, + gfp_flags); + if (!rcd->rcvhdrtail_kvaddr) + goto bail_free; + rcd->rcvhdrqtailaddr_phys = phys_hdrqtail; + } + + rcd->rcvhdrq_size = amt; + } + /* + * These values are per-context: + * RcvHdrCnt + * RcvHdrEntSize + * RcvHdrSize + */ + reg = ((u64)(rcd->rcvhdrq_cnt >> HDRQ_SIZE_SHIFT) + & RCV_HDR_CNT_CNT_MASK) + << RCV_HDR_CNT_CNT_SHIFT; + write_kctxt_csr(dd, rcd->ctxt, RCV_HDR_CNT, reg); + reg = (encode_rcv_header_entry_size(rcd->rcvhdrqentsize) + & RCV_HDR_ENT_SIZE_ENT_SIZE_MASK) + << RCV_HDR_ENT_SIZE_ENT_SIZE_SHIFT; + write_kctxt_csr(dd, rcd->ctxt, RCV_HDR_ENT_SIZE, reg); + reg = (dd->rcvhdrsize & RCV_HDR_SIZE_HDR_SIZE_MASK) + << RCV_HDR_SIZE_HDR_SIZE_SHIFT; + write_kctxt_csr(dd, rcd->ctxt, RCV_HDR_SIZE, reg); + return 0; + +bail_free: + dd_dev_err(dd, + "attempt to allocate 1 page for ctxt %u rcvhdrqtailaddr failed\n", + rcd->ctxt); + vfree(rcd->user_event_mask); + rcd->user_event_mask = NULL; + dma_free_coherent(&dd->pcidev->dev, amt, rcd->rcvhdrq, + rcd->rcvhdrq_phys); + rcd->rcvhdrq = NULL; +bail: + return -ENOMEM; +} + +/** + * allocate eager buffers, both kernel and user contexts. + * @rcd: the context we are setting up. + * + * Allocate the eager TID buffers and program them into hip. + * They are no longer completely contiguous, we do multiple allocation + * calls. Otherwise we get the OOM code involved, by asking for too + * much per call, with disastrous results on some kernels. + */ +int hfi1_setup_eagerbufs(struct hfi1_ctxtdata *rcd) +{ + struct hfi1_devdata *dd = rcd->dd; + u32 max_entries, egrtop, alloced_bytes = 0, idx = 0; + gfp_t gfp_flags; + u16 order; + int ret = 0; + u16 round_mtu = roundup_pow_of_two(hfi1_max_mtu); + + /* + * GFP_USER, but without GFP_FS, so buffer cache can be + * coalesced (we hope); otherwise, even at order 4, + * heavy filesystem activity makes these fail, and we can + * use compound pages. + */ + gfp_flags = __GFP_WAIT | __GFP_IO | __GFP_COMP; + + /* + * The minimum size of the eager buffers is a groups of MTU-sized + * buffers. + * The global eager_buffer_size parameter is checked against the + * theoretical lower limit of the value. Here, we check against the + * MTU. + */ + if (rcd->egrbufs.size < (round_mtu * dd->rcv_entries.group_size)) + rcd->egrbufs.size = round_mtu * dd->rcv_entries.group_size; + /* + * If using one-pkt-per-egr-buffer, lower the eager buffer + * size to the max MTU (page-aligned). + */ + if (!HFI1_CAP_KGET_MASK(rcd->flags, MULTI_PKT_EGR)) + rcd->egrbufs.rcvtid_size = round_mtu; + + /* + * Eager buffers sizes of 1MB or less require smaller TID sizes + * to satisfy the "multiple of 8 RcvArray entries" requirement. + */ + if (rcd->egrbufs.size <= (1 << 20)) + rcd->egrbufs.rcvtid_size = max((unsigned long)round_mtu, + rounddown_pow_of_two(rcd->egrbufs.size / 8)); + + while (alloced_bytes < rcd->egrbufs.size && + rcd->egrbufs.alloced < rcd->egrbufs.count) { + rcd->egrbufs.buffers[idx].addr = + dma_zalloc_coherent(&dd->pcidev->dev, + rcd->egrbufs.rcvtid_size, + &rcd->egrbufs.buffers[idx].phys, + gfp_flags); + if (rcd->egrbufs.buffers[idx].addr) { + rcd->egrbufs.buffers[idx].len = + rcd->egrbufs.rcvtid_size; + rcd->egrbufs.rcvtids[rcd->egrbufs.alloced].addr = + rcd->egrbufs.buffers[idx].addr; + rcd->egrbufs.rcvtids[rcd->egrbufs.alloced].phys = + rcd->egrbufs.buffers[idx].phys; + rcd->egrbufs.alloced++; + alloced_bytes += rcd->egrbufs.rcvtid_size; + idx++; + } else { + u32 new_size, i, j; + u64 offset = 0; + + /* + * Fail the eager buffer allocation if: + * - we are already using the lowest acceptable size + * - we are using one-pkt-per-egr-buffer (this implies + * that we are accepting only one size) + */ + if (rcd->egrbufs.rcvtid_size == round_mtu || + !HFI1_CAP_KGET_MASK(rcd->flags, MULTI_PKT_EGR)) { + dd_dev_err(dd, "ctxt%u: Failed to allocate eager buffers\n", + rcd->ctxt); + goto bail_rcvegrbuf_phys; + } + + new_size = rcd->egrbufs.rcvtid_size / 2; + + /* + * If the first attempt to allocate memory failed, don't + * fail everything but continue with the next lower + * size. + */ + if (idx == 0) { + rcd->egrbufs.rcvtid_size = new_size; + continue; + } + + /* + * Re-partition already allocated buffers to a smaller + * size. + */ + rcd->egrbufs.alloced = 0; + for (i = 0, j = 0, offset = 0; j < idx; i++) { + if (i >= rcd->egrbufs.count) + break; + rcd->egrbufs.rcvtids[i].phys = + rcd->egrbufs.buffers[j].phys + offset; + rcd->egrbufs.rcvtids[i].addr = + rcd->egrbufs.buffers[j].addr + offset; + rcd->egrbufs.alloced++; + if ((rcd->egrbufs.buffers[j].phys + offset + + new_size) == + (rcd->egrbufs.buffers[j].phys + + rcd->egrbufs.buffers[j].len)) { + j++; + offset = 0; + } else + offset += new_size; + } + rcd->egrbufs.rcvtid_size = new_size; + } + } + rcd->egrbufs.numbufs = idx; + rcd->egrbufs.size = alloced_bytes; + + dd_dev_info(dd, "ctxt%u: Alloced %u rcv tid entries @ %uKB, total %zuKB\n", + rcd->ctxt, rcd->egrbufs.alloced, rcd->egrbufs.rcvtid_size, + rcd->egrbufs.size); + + /* + * Set the contexts rcv array head update threshold to the closest + * power of 2 (so we can use a mask instead of modulo) below half + * the allocated entries. + */ + rcd->egrbufs.threshold = + rounddown_pow_of_two(rcd->egrbufs.alloced / 2); + /* + * Compute the expected RcvArray entry base. This is done after + * allocating the eager buffers in order to maximize the + * expected RcvArray entries for the context. + */ + max_entries = rcd->rcv_array_groups * dd->rcv_entries.group_size; + egrtop = roundup(rcd->egrbufs.alloced, dd->rcv_entries.group_size); + rcd->expected_count = max_entries - egrtop; + if (rcd->expected_count > MAX_TID_PAIR_ENTRIES * 2) + rcd->expected_count = MAX_TID_PAIR_ENTRIES * 2; + + rcd->expected_base = rcd->eager_base + egrtop; + dd_dev_info(dd, "ctxt%u: eager:%u, exp:%u, egrbase:%u, expbase:%u\n", + rcd->ctxt, rcd->egrbufs.alloced, rcd->expected_count, + rcd->eager_base, rcd->expected_base); + + if (!hfi1_rcvbuf_validate(rcd->egrbufs.rcvtid_size, PT_EAGER, &order)) { + dd_dev_err(dd, "ctxt%u: current Eager buffer size is invalid %u\n", + rcd->ctxt, rcd->egrbufs.rcvtid_size); + ret = -EINVAL; + goto bail; + } + + for (idx = 0; idx < rcd->egrbufs.alloced; idx++) { + hfi1_put_tid(dd, rcd->eager_base + idx, PT_EAGER, + rcd->egrbufs.rcvtids[idx].phys, order); + cond_resched(); + } + goto bail; + +bail_rcvegrbuf_phys: + for (idx = 0; idx < rcd->egrbufs.alloced && + rcd->egrbufs.buffers[idx].addr; + idx++) { + dma_free_coherent(&dd->pcidev->dev, + rcd->egrbufs.buffers[idx].len, + rcd->egrbufs.buffers[idx].addr, + rcd->egrbufs.buffers[idx].phys); + rcd->egrbufs.buffers[idx].addr = NULL; + rcd->egrbufs.buffers[idx].phys = 0; + rcd->egrbufs.buffers[idx].len = 0; + } +bail: + return ret; +} diff --git a/drivers/staging/rdma/hfi1/intr.c b/drivers/staging/rdma/hfi1/intr.c new file mode 100644 index 0000000000000..426582b9ab651 --- /dev/null +++ b/drivers/staging/rdma/hfi1/intr.c @@ -0,0 +1,207 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "hfi.h" +#include "common.h" +#include "sdma.h" + +/** + * format_hwmsg - format a single hwerror message + * @msg message buffer + * @msgl length of message buffer + * @hwmsg message to add to message buffer + */ +static void format_hwmsg(char *msg, size_t msgl, const char *hwmsg) +{ + strlcat(msg, "[", msgl); + strlcat(msg, hwmsg, msgl); + strlcat(msg, "]", msgl); +} + +/** + * hfi1_format_hwerrors - format hardware error messages for display + * @hwerrs hardware errors bit vector + * @hwerrmsgs hardware error descriptions + * @nhwerrmsgs number of hwerrmsgs + * @msg message buffer + * @msgl message buffer length + */ +void hfi1_format_hwerrors(u64 hwerrs, const struct hfi1_hwerror_msgs *hwerrmsgs, + size_t nhwerrmsgs, char *msg, size_t msgl) +{ + int i; + + for (i = 0; i < nhwerrmsgs; i++) + if (hwerrs & hwerrmsgs[i].mask) + format_hwmsg(msg, msgl, hwerrmsgs[i].msg); +} + +static void signal_ib_event(struct hfi1_pportdata *ppd, enum ib_event_type ev) +{ + struct ib_event event; + struct hfi1_devdata *dd = ppd->dd; + + /* + * Only call ib_dispatch_event() if the IB device has been + * registered. HFI1_INITED is set iff the driver has successfully + * registered with the IB core. + */ + if (!(dd->flags & HFI1_INITTED)) + return; + event.device = &dd->verbs_dev.ibdev; + event.element.port_num = ppd->port; + event.event = ev; + ib_dispatch_event(&event); +} + +/* + * Handle a linkup or link down notification. + * This is called outside an interrupt. + */ +void handle_linkup_change(struct hfi1_devdata *dd, u32 linkup) +{ + struct hfi1_pportdata *ppd = &dd->pport[0]; + enum ib_event_type ev; + + if (!(ppd->linkup ^ !!linkup)) + return; /* no change, nothing to do */ + + if (linkup) { + /* + * Quick linkup and all link up on the simulator does not + * trigger or implement: + * - VerifyCap interrupt + * - VerifyCap frames + * But rather moves directly to LinkUp. + * + * Do the work of the VerifyCap interrupt handler, + * handle_verify_cap(), but do not try moving the state to + * LinkUp as we are already there. + * + * NOTE: This uses this device's vAU, vCU, and vl15_init for + * the remote values. Both sides must be using the values. + */ + if (quick_linkup + || dd->icode == ICODE_FUNCTIONAL_SIMULATOR) { + set_up_vl15(dd, dd->vau, dd->vl15_init); + assign_remote_cm_au_table(dd, dd->vcu); + ppd->neighbor_guid = + read_csr(dd, + DC_DC8051_STS_REMOTE_GUID); + ppd->neighbor_type = + read_csr(dd, DC_DC8051_STS_REMOTE_NODE_TYPE) & + DC_DC8051_STS_REMOTE_NODE_TYPE_VAL_MASK; + ppd->neighbor_port_number = + read_csr(dd, DC_DC8051_STS_REMOTE_PORT_NO) & + DC_DC8051_STS_REMOTE_PORT_NO_VAL_SMASK; + dd_dev_info(dd, + "Neighbor GUID: %llx Neighbor type %d\n", + ppd->neighbor_guid, + ppd->neighbor_type); + } + + /* physical link went up */ + ppd->linkup = 1; + ppd->offline_disabled_reason = OPA_LINKDOWN_REASON_NONE; + + /* link widths are not available until the link is fully up */ + get_linkup_link_widths(ppd); + + } else { + /* physical link went down */ + ppd->linkup = 0; + + /* clear HW details of the previous connection */ + reset_link_credits(dd); + + /* freeze after a link down to guarantee a clean egress */ + start_freeze_handling(ppd, FREEZE_SELF|FREEZE_LINK_DOWN); + + ev = IB_EVENT_PORT_ERR; + + hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LINKDOWN_BIT); + + /* if we are down, the neighbor is down */ + ppd->neighbor_normal = 0; + + /* notify IB of the link change */ + signal_ib_event(ppd, ev); + } + + +} + +/* + * Handle receive or urgent interrupts for user contexts. This means a user + * process was waiting for a packet to arrive, and didn't want to poll. + */ +void handle_user_interrupt(struct hfi1_ctxtdata *rcd) +{ + struct hfi1_devdata *dd = rcd->dd; + unsigned long flags; + + spin_lock_irqsave(&dd->uctxt_lock, flags); + if (!rcd->cnt) + goto done; + + if (test_and_clear_bit(HFI1_CTXT_WAITING_RCV, &rcd->event_flags)) { + wake_up_interruptible(&rcd->wait); + hfi1_rcvctrl(dd, HFI1_RCVCTRL_INTRAVAIL_DIS, rcd->ctxt); + } else if (test_and_clear_bit(HFI1_CTXT_WAITING_URG, + &rcd->event_flags)) { + rcd->urgent++; + wake_up_interruptible(&rcd->wait); + } +done: + spin_unlock_irqrestore(&dd->uctxt_lock, flags); +} diff --git a/drivers/staging/rdma/hfi1/iowait.h b/drivers/staging/rdma/hfi1/iowait.h new file mode 100644 index 0000000000000..fa361b4058514 --- /dev/null +++ b/drivers/staging/rdma/hfi1/iowait.h @@ -0,0 +1,186 @@ +#ifndef _HFI1_IOWAIT_H +#define _HFI1_IOWAIT_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +/* + * typedef (*restart_t)() - restart callback + * @work: pointer to work structure + */ +typedef void (*restart_t)(struct work_struct *work); + +struct sdma_txreq; +struct sdma_engine; +/** + * struct iowait - linkage for delayed progress/waiting + * @list: used to add/insert into QP/PQ wait lists + * @tx_head: overflow list of sdma_txreq's + * @sleep: no space callback + * @wakeup: space callback + * @iowork: workqueue overhead + * @wait_dma: wait for sdma_busy == 0 + * @sdma_busy: # of packets in flight + * @count: total number of descriptors in tx_head'ed list + * @tx_limit: limit for overflow queuing + * @tx_count: number of tx entry's in tx_head'ed list + * + * This is to be embedded in user's state structure + * (QP or PQ). + * + * The sleep and wakeup members are a + * bit misnamed. They do not strictly + * speaking sleep or wake up, but they + * are callbacks for the ULP to implement + * what ever queuing/dequeuing of + * the embedded iowait and its containing struct + * when a resource shortage like SDMA ring space is seen. + * + * Both potentially have locks help + * so sleeping is not allowed. + * + * The wait_dma member along with the iow + */ + +struct iowait { + struct list_head list; + struct list_head tx_head; + int (*sleep)( + struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *tx, + unsigned seq); + void (*wakeup)(struct iowait *wait, int reason); + struct work_struct iowork; + wait_queue_head_t wait_dma; + atomic_t sdma_busy; + u32 count; + u32 tx_limit; + u32 tx_count; +}; + +#define SDMA_AVAIL_REASON 0 + +/** + * iowait_init() - initialize wait structure + * @wait: wait struct to initialize + * @tx_limit: limit for overflow queuing + * @func: restart function for workqueue + * @sleep: sleep function for no space + * @wakeup: wakeup function for no space + * + * This function initializes the iowait + * structure embedded in the QP or PQ. + * + */ + +static inline void iowait_init( + struct iowait *wait, + u32 tx_limit, + void (*func)(struct work_struct *work), + int (*sleep)( + struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *tx, + unsigned seq), + void (*wakeup)(struct iowait *wait, int reason)) +{ + wait->count = 0; + INIT_LIST_HEAD(&wait->list); + INIT_LIST_HEAD(&wait->tx_head); + INIT_WORK(&wait->iowork, func); + init_waitqueue_head(&wait->wait_dma); + atomic_set(&wait->sdma_busy, 0); + wait->tx_limit = tx_limit; + wait->sleep = sleep; + wait->wakeup = wakeup; +} + +/** + * iowait_schedule() - initialize wait structure + * @wait: wait struct to schedule + * @wq: workqueue for schedule + */ +static inline void iowait_schedule( + struct iowait *wait, + struct workqueue_struct *wq) +{ + queue_work(wq, &wait->iowork); +} + +/** + * iowait_sdma_drain() - wait for DMAs to drain + * + * @wait: iowait structure + * + * This will delay until the iowait sdmas have + * completed. + */ +static inline void iowait_sdma_drain(struct iowait *wait) +{ + wait_event(wait->wait_dma, !atomic_read(&wait->sdma_busy)); +} + +/** + * iowait_drain_wakeup() - trigger iowait_drain() waiter + * + * @wait: iowait structure + * + * This will trigger any waiters. + */ +static inline void iowait_drain_wakeup(struct iowait *wait) +{ + wake_up(&wait->wait_dma); +} + +#endif diff --git a/drivers/staging/rdma/hfi1/keys.c b/drivers/staging/rdma/hfi1/keys.c new file mode 100644 index 0000000000000..f6eff177ace1e --- /dev/null +++ b/drivers/staging/rdma/hfi1/keys.c @@ -0,0 +1,411 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "hfi.h" + +/** + * hfi1_alloc_lkey - allocate an lkey + * @mr: memory region that this lkey protects + * @dma_region: 0->normal key, 1->restricted DMA key + * + * Returns 0 if successful, otherwise returns -errno. + * + * Increments mr reference count as required. + * + * Sets the lkey field mr for non-dma regions. + * + */ + +int hfi1_alloc_lkey(struct hfi1_mregion *mr, int dma_region) +{ + unsigned long flags; + u32 r; + u32 n; + int ret = 0; + struct hfi1_ibdev *dev = to_idev(mr->pd->device); + struct hfi1_lkey_table *rkt = &dev->lk_table; + + hfi1_get_mr(mr); + spin_lock_irqsave(&rkt->lock, flags); + + /* special case for dma_mr lkey == 0 */ + if (dma_region) { + struct hfi1_mregion *tmr; + + tmr = rcu_access_pointer(dev->dma_mr); + if (!tmr) { + rcu_assign_pointer(dev->dma_mr, mr); + mr->lkey_published = 1; + } else { + hfi1_put_mr(mr); + } + goto success; + } + + /* Find the next available LKEY */ + r = rkt->next; + n = r; + for (;;) { + if (!rcu_access_pointer(rkt->table[r])) + break; + r = (r + 1) & (rkt->max - 1); + if (r == n) + goto bail; + } + rkt->next = (r + 1) & (rkt->max - 1); + /* + * Make sure lkey is never zero which is reserved to indicate an + * unrestricted LKEY. + */ + rkt->gen++; + /* + * bits are capped in verbs.c to ensure enough bits for + * generation number + */ + mr->lkey = (r << (32 - hfi1_lkey_table_size)) | + ((((1 << (24 - hfi1_lkey_table_size)) - 1) & rkt->gen) + << 8); + if (mr->lkey == 0) { + mr->lkey |= 1 << 8; + rkt->gen++; + } + rcu_assign_pointer(rkt->table[r], mr); + mr->lkey_published = 1; +success: + spin_unlock_irqrestore(&rkt->lock, flags); +out: + return ret; +bail: + hfi1_put_mr(mr); + spin_unlock_irqrestore(&rkt->lock, flags); + ret = -ENOMEM; + goto out; +} + +/** + * hfi1_free_lkey - free an lkey + * @mr: mr to free from tables + */ +void hfi1_free_lkey(struct hfi1_mregion *mr) +{ + unsigned long flags; + u32 lkey = mr->lkey; + u32 r; + struct hfi1_ibdev *dev = to_idev(mr->pd->device); + struct hfi1_lkey_table *rkt = &dev->lk_table; + int freed = 0; + + spin_lock_irqsave(&rkt->lock, flags); + if (!mr->lkey_published) + goto out; + if (lkey == 0) + RCU_INIT_POINTER(dev->dma_mr, NULL); + else { + r = lkey >> (32 - hfi1_lkey_table_size); + RCU_INIT_POINTER(rkt->table[r], NULL); + } + mr->lkey_published = 0; + freed++; +out: + spin_unlock_irqrestore(&rkt->lock, flags); + if (freed) { + synchronize_rcu(); + hfi1_put_mr(mr); + } +} + +/** + * hfi1_lkey_ok - check IB SGE for validity and initialize + * @rkt: table containing lkey to check SGE against + * @pd: protection domain + * @isge: outgoing internal SGE + * @sge: SGE to check + * @acc: access flags + * + * Return 1 if valid and successful, otherwise returns 0. + * + * increments the reference count upon success + * + * Check the IB SGE for validity and initialize our internal version + * of it. + */ +int hfi1_lkey_ok(struct hfi1_lkey_table *rkt, struct hfi1_pd *pd, + struct hfi1_sge *isge, struct ib_sge *sge, int acc) +{ + struct hfi1_mregion *mr; + unsigned n, m; + size_t off; + + /* + * We use LKEY == zero for kernel virtual addresses + * (see hfi1_get_dma_mr and dma.c). + */ + rcu_read_lock(); + if (sge->lkey == 0) { + struct hfi1_ibdev *dev = to_idev(pd->ibpd.device); + + if (pd->user) + goto bail; + mr = rcu_dereference(dev->dma_mr); + if (!mr) + goto bail; + atomic_inc(&mr->refcount); + rcu_read_unlock(); + + isge->mr = mr; + isge->vaddr = (void *) sge->addr; + isge->length = sge->length; + isge->sge_length = sge->length; + isge->m = 0; + isge->n = 0; + goto ok; + } + mr = rcu_dereference( + rkt->table[(sge->lkey >> (32 - hfi1_lkey_table_size))]); + if (unlikely(!mr || mr->lkey != sge->lkey || mr->pd != &pd->ibpd)) + goto bail; + + off = sge->addr - mr->user_base; + if (unlikely(sge->addr < mr->user_base || + off + sge->length > mr->length || + (mr->access_flags & acc) != acc)) + goto bail; + atomic_inc(&mr->refcount); + rcu_read_unlock(); + + off += mr->offset; + if (mr->page_shift) { + /* + page sizes are uniform power of 2 so no loop is necessary + entries_spanned_by_off is the number of times the loop below + would have executed. + */ + size_t entries_spanned_by_off; + + entries_spanned_by_off = off >> mr->page_shift; + off -= (entries_spanned_by_off << mr->page_shift); + m = entries_spanned_by_off / HFI1_SEGSZ; + n = entries_spanned_by_off % HFI1_SEGSZ; + } else { + m = 0; + n = 0; + while (off >= mr->map[m]->segs[n].length) { + off -= mr->map[m]->segs[n].length; + n++; + if (n >= HFI1_SEGSZ) { + m++; + n = 0; + } + } + } + isge->mr = mr; + isge->vaddr = mr->map[m]->segs[n].vaddr + off; + isge->length = mr->map[m]->segs[n].length - off; + isge->sge_length = sge->length; + isge->m = m; + isge->n = n; +ok: + return 1; +bail: + rcu_read_unlock(); + return 0; +} + +/** + * hfi1_rkey_ok - check the IB virtual address, length, and RKEY + * @qp: qp for validation + * @sge: SGE state + * @len: length of data + * @vaddr: virtual address to place data + * @rkey: rkey to check + * @acc: access flags + * + * Return 1 if successful, otherwise 0. + * + * increments the reference count upon success + */ +int hfi1_rkey_ok(struct hfi1_qp *qp, struct hfi1_sge *sge, + u32 len, u64 vaddr, u32 rkey, int acc) +{ + struct hfi1_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table; + struct hfi1_mregion *mr; + unsigned n, m; + size_t off; + + /* + * We use RKEY == zero for kernel virtual addresses + * (see hfi1_get_dma_mr and dma.c). + */ + rcu_read_lock(); + if (rkey == 0) { + struct hfi1_pd *pd = to_ipd(qp->ibqp.pd); + struct hfi1_ibdev *dev = to_idev(pd->ibpd.device); + + if (pd->user) + goto bail; + mr = rcu_dereference(dev->dma_mr); + if (!mr) + goto bail; + atomic_inc(&mr->refcount); + rcu_read_unlock(); + + sge->mr = mr; + sge->vaddr = (void *) vaddr; + sge->length = len; + sge->sge_length = len; + sge->m = 0; + sge->n = 0; + goto ok; + } + + mr = rcu_dereference( + rkt->table[(rkey >> (32 - hfi1_lkey_table_size))]); + if (unlikely(!mr || mr->lkey != rkey || qp->ibqp.pd != mr->pd)) + goto bail; + + off = vaddr - mr->iova; + if (unlikely(vaddr < mr->iova || off + len > mr->length || + (mr->access_flags & acc) == 0)) + goto bail; + atomic_inc(&mr->refcount); + rcu_read_unlock(); + + off += mr->offset; + if (mr->page_shift) { + /* + page sizes are uniform power of 2 so no loop is necessary + entries_spanned_by_off is the number of times the loop below + would have executed. + */ + size_t entries_spanned_by_off; + + entries_spanned_by_off = off >> mr->page_shift; + off -= (entries_spanned_by_off << mr->page_shift); + m = entries_spanned_by_off / HFI1_SEGSZ; + n = entries_spanned_by_off % HFI1_SEGSZ; + } else { + m = 0; + n = 0; + while (off >= mr->map[m]->segs[n].length) { + off -= mr->map[m]->segs[n].length; + n++; + if (n >= HFI1_SEGSZ) { + m++; + n = 0; + } + } + } + sge->mr = mr; + sge->vaddr = mr->map[m]->segs[n].vaddr + off; + sge->length = mr->map[m]->segs[n].length - off; + sge->sge_length = len; + sge->m = m; + sge->n = n; +ok: + return 1; +bail: + rcu_read_unlock(); + return 0; +} + +/* + * Initialize the memory region specified by the work request. + */ +int hfi1_fast_reg_mr(struct hfi1_qp *qp, struct ib_send_wr *wr) +{ + struct hfi1_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table; + struct hfi1_pd *pd = to_ipd(qp->ibqp.pd); + struct hfi1_mregion *mr; + u32 rkey = wr->wr.fast_reg.rkey; + unsigned i, n, m; + int ret = -EINVAL; + unsigned long flags; + u64 *page_list; + size_t ps; + + spin_lock_irqsave(&rkt->lock, flags); + if (pd->user || rkey == 0) + goto bail; + + mr = rcu_dereference_protected( + rkt->table[(rkey >> (32 - hfi1_lkey_table_size))], + lockdep_is_held(&rkt->lock)); + if (unlikely(mr == NULL || qp->ibqp.pd != mr->pd)) + goto bail; + + if (wr->wr.fast_reg.page_list_len > mr->max_segs) + goto bail; + + ps = 1UL << wr->wr.fast_reg.page_shift; + if (wr->wr.fast_reg.length > ps * wr->wr.fast_reg.page_list_len) + goto bail; + + mr->user_base = wr->wr.fast_reg.iova_start; + mr->iova = wr->wr.fast_reg.iova_start; + mr->lkey = rkey; + mr->length = wr->wr.fast_reg.length; + mr->access_flags = wr->wr.fast_reg.access_flags; + page_list = wr->wr.fast_reg.page_list->page_list; + m = 0; + n = 0; + for (i = 0; i < wr->wr.fast_reg.page_list_len; i++) { + mr->map[m]->segs[n].vaddr = (void *) page_list[i]; + mr->map[m]->segs[n].length = ps; + if (++n == HFI1_SEGSZ) { + m++; + n = 0; + } + } + + ret = 0; +bail: + spin_unlock_irqrestore(&rkt->lock, flags); + return ret; +} diff --git a/drivers/staging/rdma/hfi1/mad.c b/drivers/staging/rdma/hfi1/mad.c new file mode 100644 index 0000000000000..0a18fee464323 --- /dev/null +++ b/drivers/staging/rdma/hfi1/mad.c @@ -0,0 +1,4257 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#define OPA_NUM_PKEY_BLOCKS_PER_SMP (OPA_SMP_DR_DATA_SIZE \ + / (OPA_PARTITION_TABLE_BLK_SIZE * sizeof(u16))) + +#include "hfi.h" +#include "mad.h" +#include "trace.h" + +/* the reset value from the FM is supposed to be 0xffff, handle both */ +#define OPA_LINK_WIDTH_RESET_OLD 0x0fff +#define OPA_LINK_WIDTH_RESET 0xffff + +static int reply(struct ib_mad_hdr *smp) +{ + /* + * The verbs framework will handle the directed/LID route + * packet changes. + */ + smp->method = IB_MGMT_METHOD_GET_RESP; + if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + smp->status |= IB_SMP_DIRECTION; + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY; +} + +static inline void clear_opa_smp_data(struct opa_smp *smp) +{ + void *data = opa_get_smp_data(smp); + size_t size = opa_get_smp_data_size(smp); + + memset(data, 0, size); +} + +static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len) +{ + struct ib_mad_send_buf *send_buf; + struct ib_mad_agent *agent; + struct ib_smp *smp; + int ret; + unsigned long flags; + unsigned long timeout; + int pkey_idx; + u32 qpn = ppd_from_ibp(ibp)->sm_trap_qp; + + agent = ibp->send_agent; + if (!agent) + return; + + /* o14-3.2.1 */ + if (ppd_from_ibp(ibp)->lstate != IB_PORT_ACTIVE) + return; + + /* o14-2 */ + if (ibp->trap_timeout && time_before(jiffies, ibp->trap_timeout)) + return; + + pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); + if (pkey_idx < 0) { + pr_warn("%s: failed to find limited mgmt pkey, defaulting 0x%x\n", + __func__, hfi1_get_pkey(ibp, 1)); + pkey_idx = 1; + } + + send_buf = ib_create_send_mad(agent, qpn, pkey_idx, 0, + IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, + GFP_ATOMIC, IB_MGMT_BASE_VERSION); + if (IS_ERR(send_buf)) + return; + + smp = send_buf->mad; + smp->base_version = IB_MGMT_BASE_VERSION; + smp->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; + smp->class_version = 1; + smp->method = IB_MGMT_METHOD_TRAP; + ibp->tid++; + smp->tid = cpu_to_be64(ibp->tid); + smp->attr_id = IB_SMP_ATTR_NOTICE; + /* o14-1: smp->mkey = 0; */ + memcpy(smp->data, data, len); + + spin_lock_irqsave(&ibp->lock, flags); + if (!ibp->sm_ah) { + if (ibp->sm_lid != be16_to_cpu(IB_LID_PERMISSIVE)) { + struct ib_ah *ah; + + ah = hfi1_create_qp0_ah(ibp, ibp->sm_lid); + if (IS_ERR(ah)) + ret = PTR_ERR(ah); + else { + send_buf->ah = ah; + ibp->sm_ah = to_iah(ah); + ret = 0; + } + } else + ret = -EINVAL; + } else { + send_buf->ah = &ibp->sm_ah->ibah; + ret = 0; + } + spin_unlock_irqrestore(&ibp->lock, flags); + + if (!ret) + ret = ib_post_send_mad(send_buf, NULL); + if (!ret) { + /* 4.096 usec. */ + timeout = (4096 * (1UL << ibp->subnet_timeout)) / 1000; + ibp->trap_timeout = jiffies + usecs_to_jiffies(timeout); + } else { + ib_free_send_mad(send_buf); + ibp->trap_timeout = 0; + } +} + +/* + * Send a bad [PQ]_Key trap (ch. 14.3.8). + */ +void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl, + u32 qp1, u32 qp2, __be16 lid1, __be16 lid2) +{ + struct ib_mad_notice_attr data; + + if (trap_num == IB_NOTICE_TRAP_BAD_PKEY) + ibp->pkey_violations++; + else + ibp->qkey_violations++; + ibp->n_pkt_drops++; + + /* Send violation trap */ + data.generic_type = IB_NOTICE_TYPE_SECURITY; + data.prod_type_msb = 0; + data.prod_type_lsb = IB_NOTICE_PROD_CA; + data.trap_num = trap_num; + data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid); + data.toggle_count = 0; + memset(&data.details, 0, sizeof(data.details)); + data.details.ntc_257_258.lid1 = lid1; + data.details.ntc_257_258.lid2 = lid2; + data.details.ntc_257_258.key = cpu_to_be32(key); + data.details.ntc_257_258.sl_qp1 = cpu_to_be32((sl << 28) | qp1); + data.details.ntc_257_258.qp2 = cpu_to_be32(qp2); + + send_trap(ibp, &data, sizeof(data)); +} + +/* + * Send a bad M_Key trap (ch. 14.3.9). + */ +static void bad_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, + __be64 mkey, __be32 dr_slid, u8 return_path[], u8 hop_cnt) +{ + struct ib_mad_notice_attr data; + + /* Send violation trap */ + data.generic_type = IB_NOTICE_TYPE_SECURITY; + data.prod_type_msb = 0; + data.prod_type_lsb = IB_NOTICE_PROD_CA; + data.trap_num = IB_NOTICE_TRAP_BAD_MKEY; + data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid); + data.toggle_count = 0; + memset(&data.details, 0, sizeof(data.details)); + data.details.ntc_256.lid = data.issuer_lid; + data.details.ntc_256.method = mad->method; + data.details.ntc_256.attr_id = mad->attr_id; + data.details.ntc_256.attr_mod = mad->attr_mod; + data.details.ntc_256.mkey = mkey; + if (mad->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + + data.details.ntc_256.dr_slid = (__force __be16)dr_slid; + data.details.ntc_256.dr_trunc_hop = IB_NOTICE_TRAP_DR_NOTICE; + if (hop_cnt > ARRAY_SIZE(data.details.ntc_256.dr_rtn_path)) { + data.details.ntc_256.dr_trunc_hop |= + IB_NOTICE_TRAP_DR_TRUNC; + hop_cnt = ARRAY_SIZE(data.details.ntc_256.dr_rtn_path); + } + data.details.ntc_256.dr_trunc_hop |= hop_cnt; + memcpy(data.details.ntc_256.dr_rtn_path, return_path, + hop_cnt); + } + + send_trap(ibp, &data, sizeof(data)); +} + +/* + * Send a Port Capability Mask Changed trap (ch. 14.3.11). + */ +void hfi1_cap_mask_chg(struct hfi1_ibport *ibp) +{ + struct ib_mad_notice_attr data; + + data.generic_type = IB_NOTICE_TYPE_INFO; + data.prod_type_msb = 0; + data.prod_type_lsb = IB_NOTICE_PROD_CA; + data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG; + data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid); + data.toggle_count = 0; + memset(&data.details, 0, sizeof(data.details)); + data.details.ntc_144.lid = data.issuer_lid; + data.details.ntc_144.new_cap_mask = cpu_to_be32(ibp->port_cap_flags); + + send_trap(ibp, &data, sizeof(data)); +} + +/* + * Send a System Image GUID Changed trap (ch. 14.3.12). + */ +void hfi1_sys_guid_chg(struct hfi1_ibport *ibp) +{ + struct ib_mad_notice_attr data; + + data.generic_type = IB_NOTICE_TYPE_INFO; + data.prod_type_msb = 0; + data.prod_type_lsb = IB_NOTICE_PROD_CA; + data.trap_num = IB_NOTICE_TRAP_SYS_GUID_CHG; + data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid); + data.toggle_count = 0; + memset(&data.details, 0, sizeof(data.details)); + data.details.ntc_145.lid = data.issuer_lid; + data.details.ntc_145.new_sys_guid = ib_hfi1_sys_image_guid; + + send_trap(ibp, &data, sizeof(data)); +} + +/* + * Send a Node Description Changed trap (ch. 14.3.13). + */ +void hfi1_node_desc_chg(struct hfi1_ibport *ibp) +{ + struct ib_mad_notice_attr data; + + data.generic_type = IB_NOTICE_TYPE_INFO; + data.prod_type_msb = 0; + data.prod_type_lsb = IB_NOTICE_PROD_CA; + data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG; + data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid); + data.toggle_count = 0; + memset(&data.details, 0, sizeof(data.details)); + data.details.ntc_144.lid = data.issuer_lid; + data.details.ntc_144.local_changes = 1; + data.details.ntc_144.change_flags = IB_NOTICE_TRAP_NODE_DESC_CHG; + + send_trap(ibp, &data, sizeof(data)); +} + +static int __subn_get_opa_nodedesc(struct opa_smp *smp, u32 am, + u8 *data, struct ib_device *ibdev, + u8 port, u32 *resp_len) +{ + struct opa_node_description *nd; + + if (am) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + nd = (struct opa_node_description *)data; + + memcpy(nd->data, ibdev->node_desc, sizeof(nd->data)); + + if (resp_len) + *resp_len += sizeof(*nd); + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct opa_node_info *ni; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + unsigned pidx = port - 1; /* IB number port from 1, hw from 0 */ + + ni = (struct opa_node_info *)data; + + /* GUID 0 is illegal */ + if (am || pidx >= dd->num_pports || dd->pport[pidx].guid == 0) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ni->port_guid = cpu_to_be64(dd->pport[pidx].guid); + ni->base_version = OPA_MGMT_BASE_VERSION; + ni->class_version = OPA_SMI_CLASS_VERSION; + ni->node_type = 1; /* channel adapter */ + ni->num_ports = ibdev->phys_port_cnt; + /* This is already in network order */ + ni->system_image_guid = ib_hfi1_sys_image_guid; + /* Use first-port GUID as node */ + ni->node_guid = cpu_to_be64(dd->pport->guid); + ni->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); + ni->device_id = cpu_to_be16(dd->pcidev->device); + ni->revision = cpu_to_be32(dd->minrev); + ni->local_port_num = port; + ni->vendor_id[0] = dd->oui1; + ni->vendor_id[1] = dd->oui2; + ni->vendor_id[2] = dd->oui3; + + if (resp_len) + *resp_len += sizeof(*ni); + + return reply((struct ib_mad_hdr *)smp); +} + +static int subn_get_nodeinfo(struct ib_smp *smp, struct ib_device *ibdev, + u8 port) +{ + struct ib_node_info *nip = (struct ib_node_info *)&smp->data; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + unsigned pidx = port - 1; /* IB number port from 1, hw from 0 */ + + /* GUID 0 is illegal */ + if (smp->attr_mod || pidx >= dd->num_pports || + dd->pport[pidx].guid == 0) + smp->status |= IB_SMP_INVALID_FIELD; + else + nip->port_guid = cpu_to_be64(dd->pport[pidx].guid); + + nip->base_version = OPA_MGMT_BASE_VERSION; + nip->class_version = OPA_SMI_CLASS_VERSION; + nip->node_type = 1; /* channel adapter */ + nip->num_ports = ibdev->phys_port_cnt; + /* This is already in network order */ + nip->sys_guid = ib_hfi1_sys_image_guid; + /* Use first-port GUID as node */ + nip->node_guid = cpu_to_be64(dd->pport->guid); + nip->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); + nip->device_id = cpu_to_be16(dd->pcidev->device); + nip->revision = cpu_to_be32(dd->minrev); + nip->local_port_num = port; + nip->vendor_id[0] = dd->oui1; + nip->vendor_id[1] = dd->oui2; + nip->vendor_id[2] = dd->oui3; + + return reply((struct ib_mad_hdr *)smp); +} + +static void set_link_width_enabled(struct hfi1_pportdata *ppd, u32 w) +{ + (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LWID_ENB, w); +} + +static void set_link_width_downgrade_enabled(struct hfi1_pportdata *ppd, u32 w) +{ + (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_LWID_DG_ENB, w); +} + +static void set_link_speed_enabled(struct hfi1_pportdata *ppd, u32 s) +{ + (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_SPD_ENB, s); +} + +static int check_mkey(struct hfi1_ibport *ibp, struct ib_mad_hdr *mad, + int mad_flags, __be64 mkey, __be32 dr_slid, + u8 return_path[], u8 hop_cnt) +{ + int valid_mkey = 0; + int ret = 0; + + /* Is the mkey in the process of expiring? */ + if (ibp->mkey_lease_timeout && + time_after_eq(jiffies, ibp->mkey_lease_timeout)) { + /* Clear timeout and mkey protection field. */ + ibp->mkey_lease_timeout = 0; + ibp->mkeyprot = 0; + } + + if ((mad_flags & IB_MAD_IGNORE_MKEY) || ibp->mkey == 0 || + ibp->mkey == mkey) + valid_mkey = 1; + + /* Unset lease timeout on any valid Get/Set/TrapRepress */ + if (valid_mkey && ibp->mkey_lease_timeout && + (mad->method == IB_MGMT_METHOD_GET || + mad->method == IB_MGMT_METHOD_SET || + mad->method == IB_MGMT_METHOD_TRAP_REPRESS)) + ibp->mkey_lease_timeout = 0; + + if (!valid_mkey) { + switch (mad->method) { + case IB_MGMT_METHOD_GET: + /* Bad mkey not a violation below level 2 */ + if (ibp->mkeyprot < 2) + break; + case IB_MGMT_METHOD_SET: + case IB_MGMT_METHOD_TRAP_REPRESS: + if (ibp->mkey_violations != 0xFFFF) + ++ibp->mkey_violations; + if (!ibp->mkey_lease_timeout && ibp->mkey_lease_period) + ibp->mkey_lease_timeout = jiffies + + ibp->mkey_lease_period * HZ; + /* Generate a trap notice. */ + bad_mkey(ibp, mad, mkey, dr_slid, return_path, + hop_cnt); + ret = 1; + } + } + + return ret; +} + +/* + * The SMA caches reads from LCB registers in case the LCB is unavailable. + * (The LCB is unavailable in certain link states, for example.) + */ +struct lcb_datum { + u32 off; + u64 val; +}; + +static struct lcb_datum lcb_cache[] = { + { DC_LCB_STS_ROUND_TRIP_LTP_CNT, 0 }, +}; + +static int write_lcb_cache(u32 off, u64 val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) { + if (lcb_cache[i].off == off) { + lcb_cache[i].val = val; + return 0; + } + } + + pr_warn("%s bad offset 0x%x\n", __func__, off); + return -1; +} + +static int read_lcb_cache(u32 off, u64 *val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(lcb_cache); i++) { + if (lcb_cache[i].off == off) { + *val = lcb_cache[i].val; + return 0; + } + } + + pr_warn("%s bad offset 0x%x\n", __func__, off); + return -1; +} + +void read_ltp_rtt(struct hfi1_devdata *dd) +{ + u64 reg; + + if (read_lcb_csr(dd, DC_LCB_STS_ROUND_TRIP_LTP_CNT, ®)) + dd_dev_err(dd, "%s: unable to read LTP RTT\n", __func__); + else + write_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, reg); +} + +static u8 __opa_porttype(struct hfi1_pportdata *ppd) +{ + if (qsfp_mod_present(ppd)) { + if (ppd->qsfp_info.cache_valid) + return OPA_PORT_TYPE_STANDARD; + return OPA_PORT_TYPE_DISCONNECTED; + } + return OPA_PORT_TYPE_UNKNOWN; +} + +static int __subn_get_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + int i; + struct hfi1_devdata *dd; + struct hfi1_pportdata *ppd; + struct hfi1_ibport *ibp; + struct opa_port_info *pi = (struct opa_port_info *)data; + u8 mtu; + u8 credit_rate; + u32 state; + u32 num_ports = OPA_AM_NPORT(am); + u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); + u32 buffer_units; + u64 tmp = 0; + + if (num_ports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + dd = dd_from_ibdev(ibdev); + /* IB numbers ports from 1, hw from 0 */ + ppd = dd->pport + (port - 1); + ibp = &ppd->ibport_data; + + if (ppd->vls_supported/2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) || + ppd->vls_supported > ARRAY_SIZE(dd->vld)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + pi->lid = cpu_to_be32(ppd->lid); + + /* Only return the mkey if the protection field allows it. */ + if (!(smp->method == IB_MGMT_METHOD_GET && + ibp->mkey != smp->mkey && + ibp->mkeyprot == 1)) + pi->mkey = ibp->mkey; + + pi->subnet_prefix = ibp->gid_prefix; + pi->sm_lid = cpu_to_be32(ibp->sm_lid); + pi->ib_cap_mask = cpu_to_be32(ibp->port_cap_flags); + pi->mkey_lease_period = cpu_to_be16(ibp->mkey_lease_period); + pi->sm_trap_qp = cpu_to_be32(ppd->sm_trap_qp); + pi->sa_qp = cpu_to_be32(ppd->sa_qp); + + pi->link_width.enabled = cpu_to_be16(ppd->link_width_enabled); + pi->link_width.supported = cpu_to_be16(ppd->link_width_supported); + pi->link_width.active = cpu_to_be16(ppd->link_width_active); + + pi->link_width_downgrade.supported = + cpu_to_be16(ppd->link_width_downgrade_supported); + pi->link_width_downgrade.enabled = + cpu_to_be16(ppd->link_width_downgrade_enabled); + pi->link_width_downgrade.tx_active = + cpu_to_be16(ppd->link_width_downgrade_tx_active); + pi->link_width_downgrade.rx_active = + cpu_to_be16(ppd->link_width_downgrade_rx_active); + + pi->link_speed.supported = cpu_to_be16(ppd->link_speed_supported); + pi->link_speed.active = cpu_to_be16(ppd->link_speed_active); + pi->link_speed.enabled = cpu_to_be16(ppd->link_speed_enabled); + + state = driver_lstate(ppd); + + if (start_of_sm_config && (state == IB_PORT_INIT)) + ppd->is_sm_config_started = 1; + + pi->port_phys_conf = __opa_porttype(ppd) & 0xf; + +#if PI_LED_ENABLE_SUP + pi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; + pi->port_states.ledenable_offlinereason |= + ppd->is_sm_config_started << 5; + pi->port_states.ledenable_offlinereason |= + ppd->offline_disabled_reason & OPA_PI_MASK_OFFLINE_REASON; +#else + pi->port_states.offline_reason = ppd->neighbor_normal << 4; + pi->port_states.offline_reason |= ppd->is_sm_config_started << 5; + pi->port_states.offline_reason |= ppd->offline_disabled_reason & + OPA_PI_MASK_OFFLINE_REASON; +#endif /* PI_LED_ENABLE_SUP */ + + pi->port_states.portphysstate_portstate = + (hfi1_ibphys_portstate(ppd) << 4) | state; + + pi->mkeyprotect_lmc = (ibp->mkeyprot << 6) | ppd->lmc; + + memset(pi->neigh_mtu.pvlx_to_mtu, 0, sizeof(pi->neigh_mtu.pvlx_to_mtu)); + for (i = 0; i < ppd->vls_supported; i++) { + mtu = mtu_to_enum(dd->vld[i].mtu, HFI1_DEFAULT_ACTIVE_MTU); + if ((i % 2) == 0) + pi->neigh_mtu.pvlx_to_mtu[i/2] |= (mtu << 4); + else + pi->neigh_mtu.pvlx_to_mtu[i/2] |= mtu; + } + /* don't forget VL 15 */ + mtu = mtu_to_enum(dd->vld[15].mtu, 2048); + pi->neigh_mtu.pvlx_to_mtu[15/2] |= mtu; + pi->smsl = ibp->sm_sl & OPA_PI_MASK_SMSL; + pi->operational_vls = hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_OP_VLS); + pi->partenforce_filterraw |= + (ppd->linkinit_reason & OPA_PI_MASK_LINKINIT_REASON); + if (ppd->part_enforce & HFI1_PART_ENFORCE_IN) + pi->partenforce_filterraw |= OPA_PI_MASK_PARTITION_ENFORCE_IN; + if (ppd->part_enforce & HFI1_PART_ENFORCE_OUT) + pi->partenforce_filterraw |= OPA_PI_MASK_PARTITION_ENFORCE_OUT; + pi->mkey_violations = cpu_to_be16(ibp->mkey_violations); + /* P_KeyViolations are counted by hardware. */ + pi->pkey_violations = cpu_to_be16(ibp->pkey_violations); + pi->qkey_violations = cpu_to_be16(ibp->qkey_violations); + + pi->vl.cap = ppd->vls_supported; + pi->vl.high_limit = cpu_to_be16(ibp->vl_high_limit); + pi->vl.arb_high_cap = (u8)hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_VL_HIGH_CAP); + pi->vl.arb_low_cap = (u8)hfi1_get_ib_cfg(ppd, HFI1_IB_CFG_VL_LOW_CAP); + + pi->clientrereg_subnettimeout = ibp->subnet_timeout; + + pi->port_link_mode = cpu_to_be16(OPA_PORT_LINK_MODE_OPA << 10 | + OPA_PORT_LINK_MODE_OPA << 5 | + OPA_PORT_LINK_MODE_OPA); + + pi->port_ltp_crc_mode = cpu_to_be16(ppd->port_ltp_crc_mode); + + pi->port_mode = cpu_to_be16( + ppd->is_active_optimize_enabled ? + OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE : 0); + + pi->port_packet_format.supported = + cpu_to_be16(OPA_PORT_PACKET_FORMAT_9B); + pi->port_packet_format.enabled = + cpu_to_be16(OPA_PORT_PACKET_FORMAT_9B); + + /* flit_control.interleave is (OPA V1, version .76): + * bits use + * ---- --- + * 2 res + * 2 DistanceSupported + * 2 DistanceEnabled + * 5 MaxNextLevelTxEnabled + * 5 MaxNestLevelRxSupported + * + * HFI supports only "distance mode 1" (see OPA V1, version .76, + * section 9.6.2), so set DistanceSupported, DistanceEnabled + * to 0x1. + */ + pi->flit_control.interleave = cpu_to_be16(0x1400); + + pi->link_down_reason = ppd->local_link_down_reason.sma; + pi->neigh_link_down_reason = ppd->neigh_link_down_reason.sma; + pi->port_error_action = cpu_to_be32(ppd->port_error_action); + pi->mtucap = mtu_to_enum(hfi1_max_mtu, IB_MTU_4096); + + /* 32.768 usec. response time (guessing) */ + pi->resptimevalue = 3; + + pi->local_port_num = port; + + /* buffer info for FM */ + pi->overall_buffer_space = cpu_to_be16(dd->link_credits); + + pi->neigh_node_guid = cpu_to_be64(ppd->neighbor_guid); + pi->neigh_port_num = ppd->neighbor_port_number; + pi->port_neigh_mode = + (ppd->neighbor_type & OPA_PI_MASK_NEIGH_NODE_TYPE) | + (ppd->mgmt_allowed ? OPA_PI_MASK_NEIGH_MGMT_ALLOWED : 0) | + (ppd->neighbor_fm_security ? + OPA_PI_MASK_NEIGH_FW_AUTH_BYPASS : 0); + + /* HFIs shall always return VL15 credits to their + * neighbor in a timely manner, without any credit return pacing. + */ + credit_rate = 0; + buffer_units = (dd->vau) & OPA_PI_MASK_BUF_UNIT_BUF_ALLOC; + buffer_units |= (dd->vcu << 3) & OPA_PI_MASK_BUF_UNIT_CREDIT_ACK; + buffer_units |= (credit_rate << 6) & + OPA_PI_MASK_BUF_UNIT_VL15_CREDIT_RATE; + buffer_units |= (dd->vl15_init << 11) & OPA_PI_MASK_BUF_UNIT_VL15_INIT; + pi->buffer_units = cpu_to_be32(buffer_units); + + pi->opa_cap_mask = cpu_to_be16(OPA_CAP_MASK3_IsSharedSpaceSupported); + + /* HFI supports a replay buffer 128 LTPs in size */ + pi->replay_depth.buffer = 0x80; + /* read the cached value of DC_LCB_STS_ROUND_TRIP_LTP_CNT */ + read_lcb_cache(DC_LCB_STS_ROUND_TRIP_LTP_CNT, &tmp); + + /* this counter is 16 bits wide, but the replay_depth.wire + * variable is only 8 bits */ + if (tmp > 0xff) + tmp = 0xff; + pi->replay_depth.wire = tmp; + + if (resp_len) + *resp_len += sizeof(struct opa_port_info); + + return reply((struct ib_mad_hdr *)smp); +} + +/** + * get_pkeys - return the PKEY table + * @dd: the hfi1_ib device + * @port: the IB port number + * @pkeys: the pkey table is placed here + */ +static int get_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys) +{ + struct hfi1_pportdata *ppd = dd->pport + port - 1; + + memcpy(pkeys, ppd->pkeys, sizeof(ppd->pkeys)); + + return 0; +} + +static int __subn_get_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + u32 n_blocks_req = OPA_AM_NBLK(am); + u32 start_block = am & 0x7ff; + __be16 *p; + u16 *q; + int i; + u16 n_blocks_avail; + unsigned npkeys = hfi1_get_npkeys(dd); + size_t size; + + if (n_blocks_req == 0) { + pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n", + port, start_block, n_blocks_req); + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + n_blocks_avail = (u16) (npkeys/OPA_PARTITION_TABLE_BLK_SIZE) + 1; + + size = (n_blocks_req * OPA_PARTITION_TABLE_BLK_SIZE) * sizeof(u16); + + if (start_block + n_blocks_req > n_blocks_avail || + n_blocks_req > OPA_NUM_PKEY_BLOCKS_PER_SMP) { + pr_warn("OPA Get PKey AM Invalid : s 0x%x; req 0x%x; " + "avail 0x%x; blk/smp 0x%lx\n", + start_block, n_blocks_req, n_blocks_avail, + OPA_NUM_PKEY_BLOCKS_PER_SMP); + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + p = (__be16 *) data; + q = (u16 *)data; + /* get the real pkeys if we are requesting the first block */ + if (start_block == 0) { + get_pkeys(dd, port, q); + for (i = 0; i < npkeys; i++) + p[i] = cpu_to_be16(q[i]); + if (resp_len) + *resp_len += size; + } else + smp->status |= IB_SMP_INVALID_FIELD; + + return reply((struct ib_mad_hdr *)smp); +} + +enum { + HFI_TRANSITION_DISALLOWED, + HFI_TRANSITION_IGNORED, + HFI_TRANSITION_ALLOWED, + HFI_TRANSITION_UNDEFINED, +}; + +/* + * Use shortened names to improve readability of + * {logical,physical}_state_transitions + */ +enum { + __D = HFI_TRANSITION_DISALLOWED, + __I = HFI_TRANSITION_IGNORED, + __A = HFI_TRANSITION_ALLOWED, + __U = HFI_TRANSITION_UNDEFINED, +}; + +/* + * IB_PORTPHYSSTATE_POLLING (2) through OPA_PORTPHYSSTATE_MAX (11) are + * represented in physical_state_transitions. + */ +#define __N_PHYSTATES (OPA_PORTPHYSSTATE_MAX - IB_PORTPHYSSTATE_POLLING + 1) + +/* + * Within physical_state_transitions, rows represent "old" states, + * columns "new" states, and physical_state_transitions.allowed[old][new] + * indicates if the transition from old state to new state is legal (see + * OPAg1v1, Table 6-4). + */ +static const struct { + u8 allowed[__N_PHYSTATES][__N_PHYSTATES]; +} physical_state_transitions = { + { + /* 2 3 4 5 6 7 8 9 10 11 */ + /* 2 */ { __A, __A, __D, __D, __D, __D, __D, __D, __D, __D }, + /* 3 */ { __A, __I, __D, __D, __D, __D, __D, __D, __D, __A }, + /* 4 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, + /* 5 */ { __A, __A, __D, __I, __D, __D, __D, __D, __D, __D }, + /* 6 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, + /* 7 */ { __D, __A, __D, __D, __D, __I, __D, __D, __D, __D }, + /* 8 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, + /* 9 */ { __I, __A, __D, __D, __D, __D, __D, __I, __D, __D }, + /*10 */ { __U, __U, __U, __U, __U, __U, __U, __U, __U, __U }, + /*11 */ { __D, __A, __D, __D, __D, __D, __D, __D, __D, __I }, + } +}; + +/* + * IB_PORT_DOWN (1) through IB_PORT_ACTIVE_DEFER (5) are represented + * logical_state_transitions + */ + +#define __N_LOGICAL_STATES (IB_PORT_ACTIVE_DEFER - IB_PORT_DOWN + 1) + +/* + * Within logical_state_transitions rows represent "old" states, + * columns "new" states, and logical_state_transitions.allowed[old][new] + * indicates if the transition from old state to new state is legal (see + * OPAg1v1, Table 9-12). + */ +static const struct { + u8 allowed[__N_LOGICAL_STATES][__N_LOGICAL_STATES]; +} logical_state_transitions = { + { + /* 1 2 3 4 5 */ + /* 1 */ { __I, __D, __D, __D, __U}, + /* 2 */ { __D, __I, __A, __D, __U}, + /* 3 */ { __D, __D, __I, __A, __U}, + /* 4 */ { __D, __D, __I, __I, __U}, + /* 5 */ { __U, __U, __U, __U, __U}, + } +}; + +static int logical_transition_allowed(int old, int new) +{ + if (old < IB_PORT_NOP || old > IB_PORT_ACTIVE_DEFER || + new < IB_PORT_NOP || new > IB_PORT_ACTIVE_DEFER) { + pr_warn("invalid logical state(s) (old %d new %d)\n", + old, new); + return HFI_TRANSITION_UNDEFINED; + } + + if (new == IB_PORT_NOP) + return HFI_TRANSITION_ALLOWED; /* always allowed */ + + /* adjust states for indexing into logical_state_transitions */ + old -= IB_PORT_DOWN; + new -= IB_PORT_DOWN; + + if (old < 0 || new < 0) + return HFI_TRANSITION_UNDEFINED; + return logical_state_transitions.allowed[old][new]; +} + +static int physical_transition_allowed(int old, int new) +{ + if (old < IB_PORTPHYSSTATE_NOP || old > OPA_PORTPHYSSTATE_MAX || + new < IB_PORTPHYSSTATE_NOP || new > OPA_PORTPHYSSTATE_MAX) { + pr_warn("invalid physical state(s) (old %d new %d)\n", + old, new); + return HFI_TRANSITION_UNDEFINED; + } + + if (new == IB_PORTPHYSSTATE_NOP) + return HFI_TRANSITION_ALLOWED; /* always allowed */ + + /* adjust states for indexing into physical_state_transitions */ + old -= IB_PORTPHYSSTATE_POLLING; + new -= IB_PORTPHYSSTATE_POLLING; + + if (old < 0 || new < 0) + return HFI_TRANSITION_UNDEFINED; + return physical_state_transitions.allowed[old][new]; +} + +static int port_states_transition_allowed(struct hfi1_pportdata *ppd, + u32 logical_new, u32 physical_new) +{ + u32 physical_old = driver_physical_state(ppd); + u32 logical_old = driver_logical_state(ppd); + int ret, logical_allowed, physical_allowed; + + logical_allowed = ret = + logical_transition_allowed(logical_old, logical_new); + + if (ret == HFI_TRANSITION_DISALLOWED || + ret == HFI_TRANSITION_UNDEFINED) { + pr_warn("invalid logical state transition %s -> %s\n", + opa_lstate_name(logical_old), + opa_lstate_name(logical_new)); + return ret; + } + + physical_allowed = ret = + physical_transition_allowed(physical_old, physical_new); + + if (ret == HFI_TRANSITION_DISALLOWED || + ret == HFI_TRANSITION_UNDEFINED) { + pr_warn("invalid physical state transition %s -> %s\n", + opa_pstate_name(physical_old), + opa_pstate_name(physical_new)); + return ret; + } + + if (logical_allowed == HFI_TRANSITION_IGNORED && + physical_allowed == HFI_TRANSITION_IGNORED) + return HFI_TRANSITION_IGNORED; + + /* + * Either physical_allowed or logical_allowed is + * HFI_TRANSITION_ALLOWED. + */ + return HFI_TRANSITION_ALLOWED; +} + +static int set_port_states(struct hfi1_pportdata *ppd, struct opa_smp *smp, + u32 logical_state, u32 phys_state, + int suppress_idle_sma) +{ + struct hfi1_devdata *dd = ppd->dd; + u32 link_state; + int ret; + + ret = port_states_transition_allowed(ppd, logical_state, phys_state); + if (ret == HFI_TRANSITION_DISALLOWED || + ret == HFI_TRANSITION_UNDEFINED) { + /* error message emitted above */ + smp->status |= IB_SMP_INVALID_FIELD; + return 0; + } + + if (ret == HFI_TRANSITION_IGNORED) + return 0; + + if ((phys_state != IB_PORTPHYSSTATE_NOP) && + !(logical_state == IB_PORT_DOWN || + logical_state == IB_PORT_NOP)){ + pr_warn("SubnSet(OPA_PortInfo) port state invalid: logical_state 0x%x physical_state 0x%x\n", + logical_state, phys_state); + smp->status |= IB_SMP_INVALID_FIELD; + } + + /* + * Logical state changes are summarized in OPAv1g1 spec., + * Table 9-12; physical state changes are summarized in + * OPAv1g1 spec., Table 6.4. + */ + switch (logical_state) { + case IB_PORT_NOP: + if (phys_state == IB_PORTPHYSSTATE_NOP) + break; + /* FALLTHROUGH */ + case IB_PORT_DOWN: + if (phys_state == IB_PORTPHYSSTATE_NOP) + link_state = HLS_DN_DOWNDEF; + else if (phys_state == IB_PORTPHYSSTATE_POLLING) { + link_state = HLS_DN_POLL; + set_link_down_reason(ppd, + OPA_LINKDOWN_REASON_FM_BOUNCE, 0, + OPA_LINKDOWN_REASON_FM_BOUNCE); + } else if (phys_state == IB_PORTPHYSSTATE_DISABLED) + link_state = HLS_DN_DISABLE; + else { + pr_warn("SubnSet(OPA_PortInfo) invalid physical state 0x%x\n", + phys_state); + smp->status |= IB_SMP_INVALID_FIELD; + break; + } + + set_link_state(ppd, link_state); + if (link_state == HLS_DN_DISABLE && + (ppd->offline_disabled_reason > + OPA_LINKDOWN_REASON_SMA_DISABLED || + ppd->offline_disabled_reason == + OPA_LINKDOWN_REASON_NONE)) + ppd->offline_disabled_reason = + OPA_LINKDOWN_REASON_SMA_DISABLED; + /* + * Don't send a reply if the response would be sent + * through the disabled port. + */ + if (link_state == HLS_DN_DISABLE && smp->hop_cnt) + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + break; + case IB_PORT_ARMED: + ret = set_link_state(ppd, HLS_UP_ARMED); + if ((ret == 0) && (suppress_idle_sma == 0)) + send_idle_sma(dd, SMA_IDLE_ARM); + break; + case IB_PORT_ACTIVE: + if (ppd->neighbor_normal) { + ret = set_link_state(ppd, HLS_UP_ACTIVE); + if (ret == 0) + send_idle_sma(dd, SMA_IDLE_ACTIVE); + } else { + pr_warn("SubnSet(OPA_PortInfo) Cannot move to Active with NeighborNormal 0\n"); + smp->status |= IB_SMP_INVALID_FIELD; + } + break; + default: + pr_warn("SubnSet(OPA_PortInfo) invalid logical state 0x%x\n", + logical_state); + smp->status |= IB_SMP_INVALID_FIELD; + } + + return 0; +} + +/** + * subn_set_opa_portinfo - set port information + * @smp: the incoming SM packet + * @ibdev: the infiniband device + * @port: the port on the device + * + */ +static int __subn_set_opa_portinfo(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct opa_port_info *pi = (struct opa_port_info *)data; + struct ib_event event; + struct hfi1_devdata *dd; + struct hfi1_pportdata *ppd; + struct hfi1_ibport *ibp; + u8 clientrereg; + unsigned long flags; + u32 smlid, opa_lid; /* tmp vars to hold LID values */ + u16 lid; + u8 ls_old, ls_new, ps_new; + u8 vls; + u8 msl; + u8 crc_enabled; + u16 lse, lwe, mtu; + u32 num_ports = OPA_AM_NPORT(am); + u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); + int ret, i, invalid = 0, call_set_mtu = 0; + int call_link_downgrade_policy = 0; + + if (num_ports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + opa_lid = be32_to_cpu(pi->lid); + if (opa_lid & 0xFFFF0000) { + pr_warn("OPA_PortInfo lid out of range: %X\n", opa_lid); + smp->status |= IB_SMP_INVALID_FIELD; + goto get_only; + } + + lid = (u16)(opa_lid & 0x0000FFFF); + + smlid = be32_to_cpu(pi->sm_lid); + if (smlid & 0xFFFF0000) { + pr_warn("OPA_PortInfo SM lid out of range: %X\n", smlid); + smp->status |= IB_SMP_INVALID_FIELD; + goto get_only; + } + smlid &= 0x0000FFFF; + + clientrereg = (pi->clientrereg_subnettimeout & + OPA_PI_MASK_CLIENT_REREGISTER); + + dd = dd_from_ibdev(ibdev); + /* IB numbers ports from 1, hw from 0 */ + ppd = dd->pport + (port - 1); + ibp = &ppd->ibport_data; + event.device = ibdev; + event.element.port_num = port; + + ls_old = driver_lstate(ppd); + + ibp->mkey = pi->mkey; + ibp->gid_prefix = pi->subnet_prefix; + ibp->mkey_lease_period = be16_to_cpu(pi->mkey_lease_period); + + /* Must be a valid unicast LID address. */ + if ((lid == 0 && ls_old > IB_PORT_INIT) || + lid >= HFI1_MULTICAST_LID_BASE) { + smp->status |= IB_SMP_INVALID_FIELD; + pr_warn("SubnSet(OPA_PortInfo) lid invalid 0x%x\n", + lid); + } else if (ppd->lid != lid || + ppd->lmc != (pi->mkeyprotect_lmc & OPA_PI_MASK_LMC)) { + if (ppd->lid != lid) + hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LID_CHANGE_BIT); + if (ppd->lmc != (pi->mkeyprotect_lmc & OPA_PI_MASK_LMC)) + hfi1_set_uevent_bits(ppd, _HFI1_EVENT_LMC_CHANGE_BIT); + hfi1_set_lid(ppd, lid, pi->mkeyprotect_lmc & OPA_PI_MASK_LMC); + event.event = IB_EVENT_LID_CHANGE; + ib_dispatch_event(&event); + } + + msl = pi->smsl & OPA_PI_MASK_SMSL; + if (pi->partenforce_filterraw & OPA_PI_MASK_LINKINIT_REASON) + ppd->linkinit_reason = + (pi->partenforce_filterraw & + OPA_PI_MASK_LINKINIT_REASON); + /* enable/disable SW pkey checking as per FM control */ + if (pi->partenforce_filterraw & OPA_PI_MASK_PARTITION_ENFORCE_IN) + ppd->part_enforce |= HFI1_PART_ENFORCE_IN; + else + ppd->part_enforce &= ~HFI1_PART_ENFORCE_IN; + + if (pi->partenforce_filterraw & OPA_PI_MASK_PARTITION_ENFORCE_OUT) + ppd->part_enforce |= HFI1_PART_ENFORCE_OUT; + else + ppd->part_enforce &= ~HFI1_PART_ENFORCE_OUT; + + /* Must be a valid unicast LID address. */ + if ((smlid == 0 && ls_old > IB_PORT_INIT) || + smlid >= HFI1_MULTICAST_LID_BASE) { + smp->status |= IB_SMP_INVALID_FIELD; + pr_warn("SubnSet(OPA_PortInfo) smlid invalid 0x%x\n", smlid); + } else if (smlid != ibp->sm_lid || msl != ibp->sm_sl) { + pr_warn("SubnSet(OPA_PortInfo) smlid 0x%x\n", smlid); + spin_lock_irqsave(&ibp->lock, flags); + if (ibp->sm_ah) { + if (smlid != ibp->sm_lid) + ibp->sm_ah->attr.dlid = smlid; + if (msl != ibp->sm_sl) + ibp->sm_ah->attr.sl = msl; + } + spin_unlock_irqrestore(&ibp->lock, flags); + if (smlid != ibp->sm_lid) + ibp->sm_lid = smlid; + if (msl != ibp->sm_sl) + ibp->sm_sl = msl; + event.event = IB_EVENT_SM_CHANGE; + ib_dispatch_event(&event); + } + + if (pi->link_down_reason == 0) { + ppd->local_link_down_reason.sma = 0; + ppd->local_link_down_reason.latest = 0; + } + + if (pi->neigh_link_down_reason == 0) { + ppd->neigh_link_down_reason.sma = 0; + ppd->neigh_link_down_reason.latest = 0; + } + + ppd->sm_trap_qp = be32_to_cpu(pi->sm_trap_qp); + ppd->sa_qp = be32_to_cpu(pi->sa_qp); + + ppd->port_error_action = be32_to_cpu(pi->port_error_action); + lwe = be16_to_cpu(pi->link_width.enabled); + if (lwe) { + if (lwe == OPA_LINK_WIDTH_RESET + || lwe == OPA_LINK_WIDTH_RESET_OLD) + set_link_width_enabled(ppd, ppd->link_width_supported); + else if ((lwe & ~ppd->link_width_supported) == 0) + set_link_width_enabled(ppd, lwe); + else + smp->status |= IB_SMP_INVALID_FIELD; + } + lwe = be16_to_cpu(pi->link_width_downgrade.enabled); + /* LWD.E is always applied - 0 means "disabled" */ + if (lwe == OPA_LINK_WIDTH_RESET + || lwe == OPA_LINK_WIDTH_RESET_OLD) { + set_link_width_downgrade_enabled(ppd, + ppd->link_width_downgrade_supported); + } else if ((lwe & ~ppd->link_width_downgrade_supported) == 0) { + /* only set and apply if something changed */ + if (lwe != ppd->link_width_downgrade_enabled) { + set_link_width_downgrade_enabled(ppd, lwe); + call_link_downgrade_policy = 1; + } + } else + smp->status |= IB_SMP_INVALID_FIELD; + + lse = be16_to_cpu(pi->link_speed.enabled); + if (lse) { + if (lse & be16_to_cpu(pi->link_speed.supported)) + set_link_speed_enabled(ppd, lse); + else + smp->status |= IB_SMP_INVALID_FIELD; + } + + ibp->mkeyprot = (pi->mkeyprotect_lmc & OPA_PI_MASK_MKEY_PROT_BIT) >> 6; + ibp->vl_high_limit = be16_to_cpu(pi->vl.high_limit) & 0xFF; + (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_VL_HIGH_LIMIT, + ibp->vl_high_limit); + + if (ppd->vls_supported/2 > ARRAY_SIZE(pi->neigh_mtu.pvlx_to_mtu) || + ppd->vls_supported > ARRAY_SIZE(dd->vld)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + for (i = 0; i < ppd->vls_supported; i++) { + if ((i % 2) == 0) + mtu = enum_to_mtu((pi->neigh_mtu.pvlx_to_mtu[i/2] >> 4) + & 0xF); + else + mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[i/2] & 0xF); + if (mtu == 0xffff) { + pr_warn("SubnSet(OPA_PortInfo) mtu invalid %d (0x%x)\n", + mtu, + (pi->neigh_mtu.pvlx_to_mtu[0] >> 4) & 0xF); + smp->status |= IB_SMP_INVALID_FIELD; + mtu = hfi1_max_mtu; /* use a valid MTU */ + } + if (dd->vld[i].mtu != mtu) { + dd_dev_info(dd, + "MTU change on vl %d from %d to %d\n", + i, dd->vld[i].mtu, mtu); + dd->vld[i].mtu = mtu; + call_set_mtu++; + } + } + /* As per OPAV1 spec: VL15 must support and be configured + * for operation with a 2048 or larger MTU. + */ + mtu = enum_to_mtu(pi->neigh_mtu.pvlx_to_mtu[15/2] & 0xF); + if (mtu < 2048 || mtu == 0xffff) + mtu = 2048; + if (dd->vld[15].mtu != mtu) { + dd_dev_info(dd, + "MTU change on vl 15 from %d to %d\n", + dd->vld[15].mtu, mtu); + dd->vld[15].mtu = mtu; + call_set_mtu++; + } + if (call_set_mtu) + set_mtu(ppd); + + /* Set operational VLs */ + vls = pi->operational_vls & OPA_PI_MASK_OPERATIONAL_VL; + if (vls) { + if (vls > ppd->vls_supported) { + pr_warn("SubnSet(OPA_PortInfo) VL's supported invalid %d\n", + pi->operational_vls); + smp->status |= IB_SMP_INVALID_FIELD; + } else { + if (hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_OP_VLS, + vls) == -EINVAL) + smp->status |= IB_SMP_INVALID_FIELD; + } + } + + if (pi->mkey_violations == 0) + ibp->mkey_violations = 0; + + if (pi->pkey_violations == 0) + ibp->pkey_violations = 0; + + if (pi->qkey_violations == 0) + ibp->qkey_violations = 0; + + ibp->subnet_timeout = + pi->clientrereg_subnettimeout & OPA_PI_MASK_SUBNET_TIMEOUT; + + crc_enabled = be16_to_cpu(pi->port_ltp_crc_mode); + crc_enabled >>= 4; + crc_enabled &= 0xf; + + if (crc_enabled != 0) + ppd->port_crc_mode_enabled = port_ltp_to_cap(crc_enabled); + + ppd->is_active_optimize_enabled = + !!(be16_to_cpu(pi->port_mode) + & OPA_PI_MASK_PORT_ACTIVE_OPTOMIZE); + + ls_new = pi->port_states.portphysstate_portstate & + OPA_PI_MASK_PORT_STATE; + ps_new = (pi->port_states.portphysstate_portstate & + OPA_PI_MASK_PORT_PHYSICAL_STATE) >> 4; + + if (ls_old == IB_PORT_INIT) { + if (start_of_sm_config) { + if (ls_new == ls_old || (ls_new == IB_PORT_ARMED)) + ppd->is_sm_config_started = 1; + } else if (ls_new == IB_PORT_ARMED) { + if (ppd->is_sm_config_started == 0) + invalid = 1; + } + } + + /* Handle CLIENT_REREGISTER event b/c SM asked us for it */ + if (clientrereg) { + event.event = IB_EVENT_CLIENT_REREGISTER; + ib_dispatch_event(&event); + } + + /* + * Do the port state change now that the other link parameters + * have been set. + * Changing the port physical state only makes sense if the link + * is down or is being set to down. + */ + + ret = set_port_states(ppd, smp, ls_new, ps_new, invalid); + if (ret) + return ret; + + ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len); + + /* restore re-reg bit per o14-12.2.1 */ + pi->clientrereg_subnettimeout |= clientrereg; + + /* + * Apply the new link downgrade policy. This may result in a link + * bounce. Do this after everything else so things are settled. + * Possible problem: if setting the port state above fails, then + * the policy change is not applied. + */ + if (call_link_downgrade_policy) + apply_link_downgrade_policy(ppd, 0); + + return ret; + +get_only: + return __subn_get_opa_portinfo(smp, am, data, ibdev, port, resp_len); +} + +/** + * set_pkeys - set the PKEY table for ctxt 0 + * @dd: the hfi1_ib device + * @port: the IB port number + * @pkeys: the PKEY table + */ +static int set_pkeys(struct hfi1_devdata *dd, u8 port, u16 *pkeys) +{ + struct hfi1_pportdata *ppd; + int i; + int changed = 0; + int update_includes_mgmt_partition = 0; + + /* + * IB port one/two always maps to context zero/one, + * always a kernel context, no locking needed + * If we get here with ppd setup, no need to check + * that rcd is valid. + */ + ppd = dd->pport + (port - 1); + /* + * If the update does not include the management pkey, don't do it. + */ + for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { + if (pkeys[i] == LIM_MGMT_P_KEY) { + update_includes_mgmt_partition = 1; + break; + } + } + + if (!update_includes_mgmt_partition) + return 1; + + for (i = 0; i < ARRAY_SIZE(ppd->pkeys); i++) { + u16 key = pkeys[i]; + u16 okey = ppd->pkeys[i]; + + if (key == okey) + continue; + /* + * The SM gives us the complete PKey table. We have + * to ensure that we put the PKeys in the matching + * slots. + */ + ppd->pkeys[i] = key; + changed = 1; + } + + if (changed) { + struct ib_event event; + + (void)hfi1_set_ib_cfg(ppd, HFI1_IB_CFG_PKEYS, 0); + + event.event = IB_EVENT_PKEY_CHANGE; + event.device = &dd->verbs_dev.ibdev; + event.element.port_num = port; + ib_dispatch_event(&event); + } + return 0; +} + +static int __subn_set_opa_pkeytable(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + u32 n_blocks_sent = OPA_AM_NBLK(am); + u32 start_block = am & 0x7ff; + u16 *p = (u16 *) data; + __be16 *q = (__be16 *)data; + int i; + u16 n_blocks_avail; + unsigned npkeys = hfi1_get_npkeys(dd); + + if (n_blocks_sent == 0) { + pr_warn("OPA Get PKey AM Invalid : P = %d; B = 0x%x; N = 0x%x\n", + port, start_block, n_blocks_sent); + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + n_blocks_avail = (u16)(npkeys/OPA_PARTITION_TABLE_BLK_SIZE) + 1; + + if (start_block + n_blocks_sent > n_blocks_avail || + n_blocks_sent > OPA_NUM_PKEY_BLOCKS_PER_SMP) { + pr_warn("OPA Set PKey AM Invalid : s 0x%x; req 0x%x; avail 0x%x; blk/smp 0x%lx\n", + start_block, n_blocks_sent, n_blocks_avail, + OPA_NUM_PKEY_BLOCKS_PER_SMP); + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < n_blocks_sent * OPA_PARTITION_TABLE_BLK_SIZE; i++) + p[i] = be16_to_cpu(q[i]); + + if (start_block == 0 && set_pkeys(dd, port, p) != 0) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + return __subn_get_opa_pkeytable(smp, am, data, ibdev, port, resp_len); +} + +static int get_sc2vlt_tables(struct hfi1_devdata *dd, void *data) +{ + u64 *val = (u64 *)data; + + *val++ = read_csr(dd, SEND_SC2VLT0); + *val++ = read_csr(dd, SEND_SC2VLT1); + *val++ = read_csr(dd, SEND_SC2VLT2); + *val++ = read_csr(dd, SEND_SC2VLT3); + return 0; +} + +#define ILLEGAL_VL 12 +/* + * filter_sc2vlt changes mappings to VL15 to ILLEGAL_VL (except + * for SC15, which must map to VL15). If we don't remap things this + * way it is possible for VL15 counters to increment when we try to + * send on a SC which is mapped to an invalid VL. + */ +static void filter_sc2vlt(void *data) +{ + int i; + u8 *pd = (u8 *)data; + + for (i = 0; i < OPA_MAX_SCS; i++) { + if (i == 15) + continue; + if ((pd[i] & 0x1f) == 0xf) + pd[i] = ILLEGAL_VL; + } +} + +static int set_sc2vlt_tables(struct hfi1_devdata *dd, void *data) +{ + u64 *val = (u64 *)data; + + filter_sc2vlt(data); + + write_csr(dd, SEND_SC2VLT0, *val++); + write_csr(dd, SEND_SC2VLT1, *val++); + write_csr(dd, SEND_SC2VLT2, *val++); + write_csr(dd, SEND_SC2VLT3, *val++); + write_seqlock_irq(&dd->sc2vl_lock); + memcpy(dd->sc2vl, (u64 *)data, sizeof(dd->sc2vl)); + write_sequnlock_irq(&dd->sc2vl_lock); + return 0; +} + +static int __subn_get_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, port); + u8 *p = (u8 *)data; + size_t size = ARRAY_SIZE(ibp->sl_to_sc); /* == 32 */ + unsigned i; + + if (am) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < ARRAY_SIZE(ibp->sl_to_sc); i++) + *p++ = ibp->sl_to_sc[i]; + + if (resp_len) + *resp_len += size; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_sl_to_sc(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, port); + u8 *p = (u8 *)data; + int i; + + if (am) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < ARRAY_SIZE(ibp->sl_to_sc); i++) + ibp->sl_to_sc[i] = *p++; + + return __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, resp_len); +} + +static int __subn_get_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, port); + u8 *p = (u8 *)data; + size_t size = ARRAY_SIZE(ibp->sc_to_sl); /* == 32 */ + unsigned i; + + if (am) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++) + *p++ = ibp->sc_to_sl[i]; + + if (resp_len) + *resp_len += size; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_sc_to_sl(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, port); + u8 *p = (u8 *)data; + int i; + + if (am) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < ARRAY_SIZE(ibp->sc_to_sl); i++) + ibp->sc_to_sl[i] = *p++; + + return __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, resp_len); +} + +static int __subn_get_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + u32 n_blocks = OPA_AM_NBLK(am); + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + void *vp = (void *) data; + size_t size = 4 * sizeof(u64); + + if (n_blocks != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + get_sc2vlt_tables(dd, vp); + + if (resp_len) + *resp_len += size; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_sc_to_vlt(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + u32 n_blocks = OPA_AM_NBLK(am); + int async_update = OPA_AM_ASYNC(am); + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + void *vp = (void *) data; + struct hfi1_pportdata *ppd; + int lstate; + + if (n_blocks != 1 || async_update) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + /* IB numbers ports from 1, hw from 0 */ + ppd = dd->pport + (port - 1); + lstate = driver_lstate(ppd); + /* it's known that async_update is 0 by this point, but include + * the explicit check for clarity */ + if (!async_update && + (lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + set_sc2vlt_tables(dd, vp); + + return __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, resp_len); +} + +static int __subn_get_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + u32 n_blocks = OPA_AM_NPORT(am); + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_pportdata *ppd; + void *vp = (void *) data; + int size; + + if (n_blocks != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ppd = dd->pport + (port - 1); + + size = fm_get_table(ppd, FM_TBL_SC2VLNT, vp); + + if (resp_len) + *resp_len += size; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_sc_to_vlnt(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + u32 n_blocks = OPA_AM_NPORT(am); + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_pportdata *ppd; + void *vp = (void *) data; + int lstate; + + if (n_blocks != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + /* IB numbers ports from 1, hw from 0 */ + ppd = dd->pport + (port - 1); + lstate = driver_lstate(ppd); + if (lstate == IB_PORT_ARMED || lstate == IB_PORT_ACTIVE) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ppd = dd->pport + (port - 1); + + fm_set_table(ppd, FM_TBL_SC2VLNT, vp); + + return __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port, + resp_len); +} + +static int __subn_get_opa_psi(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + u32 nports = OPA_AM_NPORT(am); + u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); + u32 lstate; + struct hfi1_ibport *ibp; + struct hfi1_pportdata *ppd; + struct opa_port_state_info *psi = (struct opa_port_state_info *) data; + + if (nports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ibp = to_iport(ibdev, port); + ppd = ppd_from_ibp(ibp); + + lstate = driver_lstate(ppd); + + if (start_of_sm_config && (lstate == IB_PORT_INIT)) + ppd->is_sm_config_started = 1; + +#if PI_LED_ENABLE_SUP + psi->port_states.ledenable_offlinereason = ppd->neighbor_normal << 4; + psi->port_states.ledenable_offlinereason |= + ppd->is_sm_config_started << 5; + psi->port_states.ledenable_offlinereason |= + ppd->offline_disabled_reason & OPA_PI_MASK_OFFLINE_REASON; +#else + psi->port_states.offline_reason = ppd->neighbor_normal << 4; + psi->port_states.offline_reason |= ppd->is_sm_config_started << 5; + psi->port_states.offline_reason |= ppd->offline_disabled_reason & + OPA_PI_MASK_OFFLINE_REASON; +#endif /* PI_LED_ENABLE_SUP */ + + psi->port_states.portphysstate_portstate = + (hfi1_ibphys_portstate(ppd) << 4) | (lstate & 0xf); + psi->link_width_downgrade_tx_active = + ppd->link_width_downgrade_tx_active; + psi->link_width_downgrade_rx_active = + ppd->link_width_downgrade_rx_active; + if (resp_len) + *resp_len += sizeof(struct opa_port_state_info); + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_psi(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + u32 nports = OPA_AM_NPORT(am); + u32 start_of_sm_config = OPA_AM_START_SM_CFG(am); + u32 ls_old; + u8 ls_new, ps_new; + struct hfi1_ibport *ibp; + struct hfi1_pportdata *ppd; + struct opa_port_state_info *psi = (struct opa_port_state_info *) data; + int ret, invalid = 0; + + if (nports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ibp = to_iport(ibdev, port); + ppd = ppd_from_ibp(ibp); + + ls_old = driver_lstate(ppd); + + ls_new = port_states_to_logical_state(&psi->port_states); + ps_new = port_states_to_phys_state(&psi->port_states); + + if (ls_old == IB_PORT_INIT) { + if (start_of_sm_config) { + if (ls_new == ls_old || (ls_new == IB_PORT_ARMED)) + ppd->is_sm_config_started = 1; + } else if (ls_new == IB_PORT_ARMED) { + if (ppd->is_sm_config_started == 0) + invalid = 1; + } + } + + ret = set_port_states(ppd, smp, ls_new, ps_new, invalid); + if (ret) + return ret; + + if (invalid) + smp->status |= IB_SMP_INVALID_FIELD; + + return __subn_get_opa_psi(smp, am, data, ibdev, port, resp_len); +} + +static int __subn_get_opa_cable_info(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + u32 addr = OPA_AM_CI_ADDR(am); + u32 len = OPA_AM_CI_LEN(am) + 1; + int ret; + +#define __CI_PAGE_SIZE (1 << 7) /* 128 bytes */ +#define __CI_PAGE_MASK ~(__CI_PAGE_SIZE - 1) +#define __CI_PAGE_NUM(a) ((a) & __CI_PAGE_MASK) + + /* check that addr is within spec, and + * addr and (addr + len - 1) are on the same "page" */ + if (addr >= 4096 || + (__CI_PAGE_NUM(addr) != __CI_PAGE_NUM(addr + len - 1))) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ret = get_cable_info(dd, port, addr, len, data); + + if (ret == -ENODEV) { + smp->status |= IB_SMP_UNSUP_METH_ATTR; + return reply((struct ib_mad_hdr *)smp); + } + + /* The address range for the CableInfo SMA query is wider than the + * memory available on the QSFP cable. We want to return a valid + * response, albeit zeroed out, for address ranges beyond available + * memory but that are within the CableInfo query spec + */ + if (ret < 0 && ret != -ERANGE) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + if (resp_len) + *resp_len += len; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_get_opa_bct(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + u32 num_ports = OPA_AM_NPORT(am); + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_pportdata *ppd; + struct buffer_control *p = (struct buffer_control *) data; + int size; + + if (num_ports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + ppd = dd->pport + (port - 1); + size = fm_get_table(ppd, FM_TBL_BUFFER_CONTROL, p); + trace_bct_get(dd, p); + if (resp_len) + *resp_len += size; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_bct(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + u32 num_ports = OPA_AM_NPORT(am); + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_pportdata *ppd; + struct buffer_control *p = (struct buffer_control *) data; + + if (num_ports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + ppd = dd->pport + (port - 1); + trace_bct_set(dd, p); + if (fm_set_table(ppd, FM_TBL_BUFFER_CONTROL, p) < 0) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + return __subn_get_opa_bct(smp, am, data, ibdev, port, resp_len); +} + +static int __subn_get_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port)); + u32 num_ports = OPA_AM_NPORT(am); + u8 section = (am & 0x00ff0000) >> 16; + u8 *p = data; + int size = 0; + + if (num_ports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + switch (section) { + case OPA_VLARB_LOW_ELEMENTS: + size = fm_get_table(ppd, FM_TBL_VL_LOW_ARB, p); + break; + case OPA_VLARB_HIGH_ELEMENTS: + size = fm_get_table(ppd, FM_TBL_VL_HIGH_ARB, p); + break; + case OPA_VLARB_PREEMPT_ELEMENTS: + size = fm_get_table(ppd, FM_TBL_VL_PREEMPT_ELEMS, p); + break; + case OPA_VLARB_PREEMPT_MATRIX: + size = fm_get_table(ppd, FM_TBL_VL_PREEMPT_MATRIX, p); + break; + default: + pr_warn("OPA SubnGet(VL Arb) AM Invalid : 0x%x\n", + be32_to_cpu(smp->attr_mod)); + smp->status |= IB_SMP_INVALID_FIELD; + break; + } + + if (size > 0 && resp_len) + *resp_len += size; + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_vl_arb(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(to_iport(ibdev, port)); + u32 num_ports = OPA_AM_NPORT(am); + u8 section = (am & 0x00ff0000) >> 16; + u8 *p = data; + + if (num_ports != 1) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + switch (section) { + case OPA_VLARB_LOW_ELEMENTS: + (void) fm_set_table(ppd, FM_TBL_VL_LOW_ARB, p); + break; + case OPA_VLARB_HIGH_ELEMENTS: + (void) fm_set_table(ppd, FM_TBL_VL_HIGH_ARB, p); + break; + /* neither OPA_VLARB_PREEMPT_ELEMENTS, or OPA_VLARB_PREEMPT_MATRIX + * can be changed from the default values */ + case OPA_VLARB_PREEMPT_ELEMENTS: + /* FALLTHROUGH */ + case OPA_VLARB_PREEMPT_MATRIX: + smp->status |= IB_SMP_UNSUP_METH_ATTR; + break; + default: + pr_warn("OPA SubnSet(VL Arb) AM Invalid : 0x%x\n", + be32_to_cpu(smp->attr_mod)); + smp->status |= IB_SMP_INVALID_FIELD; + break; + } + + return __subn_get_opa_vl_arb(smp, am, data, ibdev, port, resp_len); +} + +struct opa_pma_mad { + struct ib_mad_hdr mad_hdr; + u8 data[2024]; +} __packed; + +struct opa_class_port_info { + u8 base_version; + u8 class_version; + __be16 cap_mask; + __be32 cap_mask2_resp_time; + + u8 redirect_gid[16]; + __be32 redirect_tc_fl; + __be32 redirect_lid; + __be32 redirect_sl_qp; + __be32 redirect_qkey; + + u8 trap_gid[16]; + __be32 trap_tc_fl; + __be32 trap_lid; + __be32 trap_hl_qp; + __be32 trap_qkey; + + __be16 trap_pkey; + __be16 redirect_pkey; + + u8 trap_sl_rsvd; + u8 reserved[3]; +} __packed; + +struct opa_port_status_req { + __u8 port_num; + __u8 reserved[3]; + __be32 vl_select_mask; +}; + +#define VL_MASK_ALL 0x000080ff + +struct opa_port_status_rsp { + __u8 port_num; + __u8 reserved[3]; + __be32 vl_select_mask; + + /* Data counters */ + __be64 port_xmit_data; + __be64 port_rcv_data; + __be64 port_xmit_pkts; + __be64 port_rcv_pkts; + __be64 port_multicast_xmit_pkts; + __be64 port_multicast_rcv_pkts; + __be64 port_xmit_wait; + __be64 sw_port_congestion; + __be64 port_rcv_fecn; + __be64 port_rcv_becn; + __be64 port_xmit_time_cong; + __be64 port_xmit_wasted_bw; + __be64 port_xmit_wait_data; + __be64 port_rcv_bubble; + __be64 port_mark_fecn; + /* Error counters */ + __be64 port_rcv_constraint_errors; + __be64 port_rcv_switch_relay_errors; + __be64 port_xmit_discards; + __be64 port_xmit_constraint_errors; + __be64 port_rcv_remote_physical_errors; + __be64 local_link_integrity_errors; + __be64 port_rcv_errors; + __be64 excessive_buffer_overruns; + __be64 fm_config_errors; + __be32 link_error_recovery; + __be32 link_downed; + u8 uncorrectable_errors; + + u8 link_quality_indicator; /* 5res, 3bit */ + u8 res2[6]; + struct _vls_pctrs { + /* per-VL Data counters */ + __be64 port_vl_xmit_data; + __be64 port_vl_rcv_data; + __be64 port_vl_xmit_pkts; + __be64 port_vl_rcv_pkts; + __be64 port_vl_xmit_wait; + __be64 sw_port_vl_congestion; + __be64 port_vl_rcv_fecn; + __be64 port_vl_rcv_becn; + __be64 port_xmit_time_cong; + __be64 port_vl_xmit_wasted_bw; + __be64 port_vl_xmit_wait_data; + __be64 port_vl_rcv_bubble; + __be64 port_vl_mark_fecn; + __be64 port_vl_xmit_discards; + } vls[0]; /* real array size defined by # bits set in vl_select_mask */ +}; + +enum counter_selects { + CS_PORT_XMIT_DATA = (1 << 31), + CS_PORT_RCV_DATA = (1 << 30), + CS_PORT_XMIT_PKTS = (1 << 29), + CS_PORT_RCV_PKTS = (1 << 28), + CS_PORT_MCAST_XMIT_PKTS = (1 << 27), + CS_PORT_MCAST_RCV_PKTS = (1 << 26), + CS_PORT_XMIT_WAIT = (1 << 25), + CS_SW_PORT_CONGESTION = (1 << 24), + CS_PORT_RCV_FECN = (1 << 23), + CS_PORT_RCV_BECN = (1 << 22), + CS_PORT_XMIT_TIME_CONG = (1 << 21), + CS_PORT_XMIT_WASTED_BW = (1 << 20), + CS_PORT_XMIT_WAIT_DATA = (1 << 19), + CS_PORT_RCV_BUBBLE = (1 << 18), + CS_PORT_MARK_FECN = (1 << 17), + CS_PORT_RCV_CONSTRAINT_ERRORS = (1 << 16), + CS_PORT_RCV_SWITCH_RELAY_ERRORS = (1 << 15), + CS_PORT_XMIT_DISCARDS = (1 << 14), + CS_PORT_XMIT_CONSTRAINT_ERRORS = (1 << 13), + CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS = (1 << 12), + CS_LOCAL_LINK_INTEGRITY_ERRORS = (1 << 11), + CS_PORT_RCV_ERRORS = (1 << 10), + CS_EXCESSIVE_BUFFER_OVERRUNS = (1 << 9), + CS_FM_CONFIG_ERRORS = (1 << 8), + CS_LINK_ERROR_RECOVERY = (1 << 7), + CS_LINK_DOWNED = (1 << 6), + CS_UNCORRECTABLE_ERRORS = (1 << 5), +}; + +struct opa_clear_port_status { + __be64 port_select_mask[4]; + __be32 counter_select_mask; +}; + +struct opa_aggregate { + __be16 attr_id; + __be16 err_reqlength; /* 1 bit, 8 res, 7 bit */ + __be32 attr_mod; + u8 data[0]; +}; + +/* Request contains first two fields, response contains those plus the rest */ +struct opa_port_data_counters_msg { + __be64 port_select_mask[4]; + __be32 vl_select_mask; + + /* Response fields follow */ + __be32 reserved1; + struct _port_dctrs { + u8 port_number; + u8 reserved2[3]; + __be32 link_quality_indicator; /* 29res, 3bit */ + + /* Data counters */ + __be64 port_xmit_data; + __be64 port_rcv_data; + __be64 port_xmit_pkts; + __be64 port_rcv_pkts; + __be64 port_multicast_xmit_pkts; + __be64 port_multicast_rcv_pkts; + __be64 port_xmit_wait; + __be64 sw_port_congestion; + __be64 port_rcv_fecn; + __be64 port_rcv_becn; + __be64 port_xmit_time_cong; + __be64 port_xmit_wasted_bw; + __be64 port_xmit_wait_data; + __be64 port_rcv_bubble; + __be64 port_mark_fecn; + + __be64 port_error_counter_summary; + /* Sum of error counts/port */ + + struct _vls_dctrs { + /* per-VL Data counters */ + __be64 port_vl_xmit_data; + __be64 port_vl_rcv_data; + __be64 port_vl_xmit_pkts; + __be64 port_vl_rcv_pkts; + __be64 port_vl_xmit_wait; + __be64 sw_port_vl_congestion; + __be64 port_vl_rcv_fecn; + __be64 port_vl_rcv_becn; + __be64 port_xmit_time_cong; + __be64 port_vl_xmit_wasted_bw; + __be64 port_vl_xmit_wait_data; + __be64 port_vl_rcv_bubble; + __be64 port_vl_mark_fecn; + } vls[0]; + /* array size defined by #bits set in vl_select_mask*/ + } port[1]; /* array size defined by #ports in attribute modifier */ +}; + +struct opa_port_error_counters64_msg { + /* Request contains first two fields, response contains the + * whole magilla */ + __be64 port_select_mask[4]; + __be32 vl_select_mask; + + /* Response-only fields follow */ + __be32 reserved1; + struct _port_ectrs { + u8 port_number; + u8 reserved2[7]; + __be64 port_rcv_constraint_errors; + __be64 port_rcv_switch_relay_errors; + __be64 port_xmit_discards; + __be64 port_xmit_constraint_errors; + __be64 port_rcv_remote_physical_errors; + __be64 local_link_integrity_errors; + __be64 port_rcv_errors; + __be64 excessive_buffer_overruns; + __be64 fm_config_errors; + __be32 link_error_recovery; + __be32 link_downed; + u8 uncorrectable_errors; + u8 reserved3[7]; + struct _vls_ectrs { + __be64 port_vl_xmit_discards; + } vls[0]; + /* array size defined by #bits set in vl_select_mask */ + } port[1]; /* array size defined by #ports in attribute modifier */ +}; + +struct opa_port_error_info_msg { + __be64 port_select_mask[4]; + __be32 error_info_select_mask; + __be32 reserved1; + struct _port_ei { + + u8 port_number; + u8 reserved2[7]; + + /* PortRcvErrorInfo */ + struct { + u8 status_and_code; + union { + u8 raw[17]; + struct { + /* EI1to12 format */ + u8 packet_flit1[8]; + u8 packet_flit2[8]; + u8 remaining_flit_bits12; + } ei1to12; + struct { + u8 packet_bytes[8]; + u8 remaining_flit_bits; + } ei13; + } ei; + u8 reserved3[6]; + } __packed port_rcv_ei; + + /* ExcessiveBufferOverrunInfo */ + struct { + u8 status_and_sc; + u8 reserved4[7]; + } __packed excessive_buffer_overrun_ei; + + /* PortXmitConstraintErrorInfo */ + struct { + u8 status; + u8 reserved5; + __be16 pkey; + __be32 slid; + } __packed port_xmit_constraint_ei; + + /* PortRcvConstraintErrorInfo */ + struct { + u8 status; + u8 reserved6; + __be16 pkey; + __be32 slid; + } __packed port_rcv_constraint_ei; + + /* PortRcvSwitchRelayErrorInfo */ + struct { + u8 status_and_code; + u8 reserved7[3]; + __u32 error_info; + } __packed port_rcv_switch_relay_ei; + + /* UncorrectableErrorInfo */ + struct { + u8 status_and_code; + u8 reserved8; + } __packed uncorrectable_ei; + + /* FMConfigErrorInfo */ + struct { + u8 status_and_code; + u8 error_info; + } __packed fm_config_ei; + __u32 reserved9; + } port[1]; /* actual array size defined by #ports in attr modifier */ +}; + +/* opa_port_error_info_msg error_info_select_mask bit definitions */ +enum error_info_selects { + ES_PORT_RCV_ERROR_INFO = (1 << 31), + ES_EXCESSIVE_BUFFER_OVERRUN_INFO = (1 << 30), + ES_PORT_XMIT_CONSTRAINT_ERROR_INFO = (1 << 29), + ES_PORT_RCV_CONSTRAINT_ERROR_INFO = (1 << 28), + ES_PORT_RCV_SWITCH_RELAY_ERROR_INFO = (1 << 27), + ES_UNCORRECTABLE_ERROR_INFO = (1 << 26), + ES_FM_CONFIG_ERROR_INFO = (1 << 25) +}; + +static int pma_get_opa_classportinfo(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u32 *resp_len) +{ + struct opa_class_port_info *p = + (struct opa_class_port_info *)pmp->data; + + memset(pmp->data, 0, sizeof(pmp->data)); + + if (pmp->mad_hdr.attr_mod != 0) + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + + p->base_version = OPA_MGMT_BASE_VERSION; + p->class_version = OPA_SMI_CLASS_VERSION; + /* + * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec. + */ + p->cap_mask2_resp_time = cpu_to_be32(18); + + if (resp_len) + *resp_len += sizeof(*p); + + return reply((struct ib_mad_hdr *)pmp); +} + +static void a0_portstatus(struct hfi1_pportdata *ppd, + struct opa_port_status_rsp *rsp, u32 vl_select_mask) +{ + if (!is_bx(ppd->dd)) { + unsigned long vl; + int vfi = 0; + u64 max_vl_xmit_wait = 0, tmp; + u32 vl_all_mask = VL_MASK_ALL; + u64 rcv_data, rcv_bubble; + + rcv_data = be64_to_cpu(rsp->port_rcv_data); + rcv_bubble = be64_to_cpu(rsp->port_rcv_bubble); + /* In the measured time period, calculate the total number + * of flits that were received. Subtract out one false + * rcv_bubble increment for every 32 received flits but + * don't let the number go negative. + */ + if (rcv_bubble >= (rcv_data>>5)) { + rcv_bubble -= (rcv_data>>5); + rsp->port_rcv_bubble = cpu_to_be64(rcv_bubble); + } + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(vl_select_mask)) { + rcv_data = be64_to_cpu(rsp->vls[vfi].port_vl_rcv_data); + rcv_bubble = + be64_to_cpu(rsp->vls[vfi].port_vl_rcv_bubble); + if (rcv_bubble >= (rcv_data>>5)) { + rcv_bubble -= (rcv_data>>5); + rsp->vls[vfi].port_vl_rcv_bubble = + cpu_to_be64(rcv_bubble); + } + vfi++; + } + + for_each_set_bit(vl, (unsigned long *)&(vl_all_mask), + 8 * sizeof(vl_all_mask)) { + tmp = read_port_cntr(ppd, C_TX_WAIT_VL, + idx_from_vl(vl)); + if (tmp > max_vl_xmit_wait) + max_vl_xmit_wait = tmp; + } + rsp->port_xmit_wait = cpu_to_be64(max_vl_xmit_wait); + } +} + + +static int pma_get_opa_portstatus(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + struct opa_port_status_req *req = + (struct opa_port_status_req *)pmp->data; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct opa_port_status_rsp *rsp; + u32 vl_select_mask = be32_to_cpu(req->vl_select_mask); + unsigned long vl; + size_t response_data_size; + u32 nports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; + u8 port_num = req->port_num; + u8 num_vls = hweight32(vl_select_mask); + struct _vls_pctrs *vlinfo; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + int vfi; + u64 tmp, tmp2; + + response_data_size = sizeof(struct opa_port_status_rsp) + + num_vls * sizeof(struct _vls_pctrs); + if (response_data_size > sizeof(pmp->data)) { + pmp->mad_hdr.status |= OPA_PM_STATUS_REQUEST_TOO_LARGE; + return reply((struct ib_mad_hdr *)pmp); + } + + if (nports != 1 || (port_num && port_num != port) + || num_vls > OPA_MAX_VLS || (vl_select_mask & ~VL_MASK_ALL)) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + memset(pmp->data, 0, sizeof(pmp->data)); + + rsp = (struct opa_port_status_rsp *)pmp->data; + if (port_num) + rsp->port_num = port_num; + else + rsp->port_num = port; + + rsp->port_rcv_constraint_errors = + cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, + CNTR_INVALID_VL)); + + hfi1_read_link_quality(dd, &rsp->link_quality_indicator); + + rsp->vl_select_mask = cpu_to_be32(vl_select_mask); + rsp->port_xmit_data = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_FLITS, + CNTR_INVALID_VL)); + rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS, + CNTR_INVALID_VL)); + rsp->port_rcv_bubble = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL)); + rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS, + CNTR_INVALID_VL)); + rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS, + CNTR_INVALID_VL)); + rsp->port_multicast_xmit_pkts = + cpu_to_be64(read_dev_cntr(dd, C_DC_MC_XMIT_PKTS, + CNTR_INVALID_VL)); + rsp->port_multicast_rcv_pkts = + cpu_to_be64(read_dev_cntr(dd, C_DC_MC_RCV_PKTS, + CNTR_INVALID_VL)); + rsp->port_xmit_wait = + cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL)); + rsp->port_rcv_fecn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL)); + rsp->port_rcv_becn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL)); + rsp->port_xmit_discards = + cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD, + CNTR_INVALID_VL)); + rsp->port_xmit_constraint_errors = + cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, + CNTR_INVALID_VL)); + rsp->port_rcv_remote_physical_errors = + cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, + CNTR_INVALID_VL)); + tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL); + tmp2 = tmp + read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL); + if (tmp2 < tmp) { + /* overflow/wrapped */ + rsp->local_link_integrity_errors = cpu_to_be64(~0); + } else { + rsp->local_link_integrity_errors = cpu_to_be64(tmp2); + } + tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); + tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, + CNTR_INVALID_VL); + if (tmp2 > (u32)UINT_MAX || tmp2 < tmp) { + /* overflow/wrapped */ + rsp->link_error_recovery = cpu_to_be32(~0); + } else { + rsp->link_error_recovery = cpu_to_be32(tmp2); + } + rsp->port_rcv_errors = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL)); + rsp->excessive_buffer_overruns = + cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); + rsp->fm_config_errors = + cpu_to_be64(read_dev_cntr(dd, C_DC_FM_CFG_ERR, + CNTR_INVALID_VL)); + rsp->link_downed = cpu_to_be32(read_port_cntr(ppd, C_SW_LINK_DOWN, + CNTR_INVALID_VL)); + + /* rsp->uncorrectable_errors is 8 bits wide, and it pegs at 0xff */ + tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); + rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; + + vlinfo = &(rsp->vls[0]); + vfi = 0; + /* The vl_select_mask has been checked above, and we know + * that it contains only entries which represent valid VLs. + * So in the for_each_set_bit() loop below, we don't need + * any additional checks for vl. + */ + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(vl_select_mask)) { + memset(vlinfo, 0, sizeof(*vlinfo)); + + tmp = read_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl)); + rsp->vls[vfi].port_vl_rcv_data = cpu_to_be64(tmp); + rsp->vls[vfi].port_vl_rcv_bubble = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_rcv_pkts = + cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_xmit_data = + cpu_to_be64(read_port_cntr(ppd, C_TX_FLIT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_xmit_pkts = + cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_xmit_wait = + cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_rcv_fecn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_rcv_becn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, + idx_from_vl(vl))); + + vlinfo++; + vfi++; + } + + a0_portstatus(ppd, rsp, vl_select_mask); + + if (resp_len) + *resp_len += response_data_size; + + return reply((struct ib_mad_hdr *)pmp); +} + +static u64 get_error_counter_summary(struct ib_device *ibdev, u8 port) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u64 error_counter_summary = 0, tmp; + + error_counter_summary += read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, + CNTR_INVALID_VL); + /* port_rcv_switch_relay_errors is 0 for HFIs */ + error_counter_summary += read_port_cntr(ppd, C_SW_XMIT_DSCD, + CNTR_INVALID_VL); + error_counter_summary += read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_RMT_PHY_ERR, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_TX_REPLAY, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_RX_REPLAY, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_RCV_ERR, + CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL); + error_counter_summary += read_dev_cntr(dd, C_DC_FM_CFG_ERR, + CNTR_INVALID_VL); + /* ppd->link_downed is a 32-bit value */ + error_counter_summary += read_port_cntr(ppd, C_SW_LINK_DOWN, + CNTR_INVALID_VL); + tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); + /* this is an 8-bit quantity */ + error_counter_summary += tmp < 0x100 ? (tmp & 0xff) : 0xff; + + return error_counter_summary; +} + +static void a0_datacounters(struct hfi1_devdata *dd, struct _port_dctrs *rsp, + u32 vl_select_mask) +{ + if (!is_bx(dd)) { + unsigned long vl; + int vfi = 0; + u64 rcv_data, rcv_bubble, sum_vl_xmit_wait = 0; + + rcv_data = be64_to_cpu(rsp->port_rcv_data); + rcv_bubble = be64_to_cpu(rsp->port_rcv_bubble); + /* In the measured time period, calculate the total number + * of flits that were received. Subtract out one false + * rcv_bubble increment for every 32 received flits but + * don't let the number go negative. + */ + if (rcv_bubble >= (rcv_data>>5)) { + rcv_bubble -= (rcv_data>>5); + rsp->port_rcv_bubble = cpu_to_be64(rcv_bubble); + } + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(vl_select_mask)) { + rcv_data = be64_to_cpu(rsp->vls[vfi].port_vl_rcv_data); + rcv_bubble = + be64_to_cpu(rsp->vls[vfi].port_vl_rcv_bubble); + if (rcv_bubble >= (rcv_data>>5)) { + rcv_bubble -= (rcv_data>>5); + rsp->vls[vfi].port_vl_rcv_bubble = + cpu_to_be64(rcv_bubble); + } + vfi++; + } + vfi = 0; + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(vl_select_mask)) { + u64 tmp = sum_vl_xmit_wait + + be64_to_cpu(rsp->vls[vfi++].port_vl_xmit_wait); + if (tmp < sum_vl_xmit_wait) { + /* we wrapped */ + sum_vl_xmit_wait = (u64) ~0; + break; + } + sum_vl_xmit_wait = tmp; + } + if (be64_to_cpu(rsp->port_xmit_wait) > sum_vl_xmit_wait) + rsp->port_xmit_wait = cpu_to_be64(sum_vl_xmit_wait); + } +} + +static int pma_get_opa_datacounters(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + struct opa_port_data_counters_msg *req = + (struct opa_port_data_counters_msg *)pmp->data; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct _port_dctrs *rsp; + struct _vls_dctrs *vlinfo; + size_t response_data_size; + u32 num_ports; + u8 num_pslm; + u8 lq, num_vls; + u64 port_mask; + unsigned long port_num; + unsigned long vl; + u32 vl_select_mask; + int vfi; + + num_ports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; + num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); + num_vls = hweight32(be32_to_cpu(req->vl_select_mask)); + vl_select_mask = be32_to_cpu(req->vl_select_mask); + + if (num_ports != 1 || (vl_select_mask & ~VL_MASK_ALL)) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + /* Sanity check */ + response_data_size = sizeof(struct opa_port_data_counters_msg) + + num_vls * sizeof(struct _vls_dctrs); + + if (response_data_size > sizeof(pmp->data)) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + /* + * The bit set in the mask needs to be consistent with the + * port the request came in on. + */ + port_mask = be64_to_cpu(req->port_select_mask[3]); + port_num = find_first_bit((unsigned long *)&port_mask, + sizeof(port_mask)); + + if ((u8)port_num != port) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + rsp = (struct _port_dctrs *)&(req->port[0]); + memset(rsp, 0, sizeof(*rsp)); + + rsp->port_number = port; + /* + * Note that link_quality_indicator is a 32 bit quantity in + * 'datacounters' queries (as opposed to 'portinfo' queries, + * where it's a byte). + */ + hfi1_read_link_quality(dd, &lq); + rsp->link_quality_indicator = cpu_to_be32((u32)lq); + + /* rsp->sw_port_congestion is 0 for HFIs */ + /* rsp->port_xmit_time_cong is 0 for HFIs */ + /* rsp->port_xmit_wasted_bw ??? */ + /* rsp->port_xmit_wait_data ??? */ + /* rsp->port_mark_fecn is 0 for HFIs */ + + rsp->port_xmit_data = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_FLITS, + CNTR_INVALID_VL)); + rsp->port_rcv_data = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FLITS, + CNTR_INVALID_VL)); + rsp->port_rcv_bubble = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL)); + rsp->port_xmit_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_XMIT_PKTS, + CNTR_INVALID_VL)); + rsp->port_rcv_pkts = cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_PKTS, + CNTR_INVALID_VL)); + rsp->port_multicast_xmit_pkts = + cpu_to_be64(read_dev_cntr(dd, C_DC_MC_XMIT_PKTS, + CNTR_INVALID_VL)); + rsp->port_multicast_rcv_pkts = + cpu_to_be64(read_dev_cntr(dd, C_DC_MC_RCV_PKTS, + CNTR_INVALID_VL)); + rsp->port_xmit_wait = + cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL)); + rsp->port_rcv_fecn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL)); + rsp->port_rcv_becn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL)); + + rsp->port_error_counter_summary = + cpu_to_be64(get_error_counter_summary(ibdev, port)); + + vlinfo = &(rsp->vls[0]); + vfi = 0; + /* The vl_select_mask has been checked above, and we know + * that it contains only entries which represent valid VLs. + * So in the for_each_set_bit() loop below, we don't need + * any additional checks for vl. + */ + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(req->vl_select_mask)) { + memset(vlinfo, 0, sizeof(*vlinfo)); + + rsp->vls[vfi].port_vl_xmit_data = + cpu_to_be64(read_port_cntr(ppd, C_TX_FLIT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_rcv_data = + cpu_to_be64(read_dev_cntr(dd, C_DC_RX_FLIT_VL, + idx_from_vl(vl))); + rsp->vls[vfi].port_vl_rcv_bubble = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BBL_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_xmit_pkts = + cpu_to_be64(read_port_cntr(ppd, C_TX_PKT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_rcv_pkts = + cpu_to_be64(read_dev_cntr(dd, C_DC_RX_PKT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_xmit_wait = + cpu_to_be64(read_port_cntr(ppd, C_TX_WAIT_VL, + idx_from_vl(vl))); + + rsp->vls[vfi].port_vl_rcv_fecn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_FCN_VL, + idx_from_vl(vl))); + rsp->vls[vfi].port_vl_rcv_becn = + cpu_to_be64(read_dev_cntr(dd, C_DC_RCV_BCN_VL, + idx_from_vl(vl))); + + /* rsp->port_vl_xmit_time_cong is 0 for HFIs */ + /* rsp->port_vl_xmit_wasted_bw ??? */ + /* port_vl_xmit_wait_data - TXE (table 13-9 HFI spec) ??? + * does this differ from rsp->vls[vfi].port_vl_xmit_wait */ + /*rsp->vls[vfi].port_vl_mark_fecn = + cpu_to_be64(read_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + + offset)); + */ + vlinfo++; + vfi++; + } + + a0_datacounters(dd, rsp, vl_select_mask); + + if (resp_len) + *resp_len += response_data_size; + + return reply((struct ib_mad_hdr *)pmp); +} + +static int pma_get_opa_porterrors(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + size_t response_data_size; + struct _port_ectrs *rsp; + unsigned long port_num; + struct opa_port_error_counters64_msg *req; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + u32 num_ports; + u8 num_pslm; + u8 num_vls; + struct hfi1_ibport *ibp; + struct hfi1_pportdata *ppd; + struct _vls_ectrs *vlinfo; + unsigned long vl; + u64 port_mask, tmp, tmp2; + u32 vl_select_mask; + int vfi; + + req = (struct opa_port_error_counters64_msg *)pmp->data; + + num_ports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; + + num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); + num_vls = hweight32(be32_to_cpu(req->vl_select_mask)); + + if (num_ports != 1 || num_ports != num_pslm) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + response_data_size = sizeof(struct opa_port_error_counters64_msg) + + num_vls * sizeof(struct _vls_ectrs); + + if (response_data_size > sizeof(pmp->data)) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + /* + * The bit set in the mask needs to be consistent with the + * port the request came in on. + */ + port_mask = be64_to_cpu(req->port_select_mask[3]); + port_num = find_first_bit((unsigned long *)&port_mask, + sizeof(port_mask)); + + if ((u8)port_num != port) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + rsp = (struct _port_ectrs *)&(req->port[0]); + + ibp = to_iport(ibdev, port_num); + ppd = ppd_from_ibp(ibp); + + memset(rsp, 0, sizeof(*rsp)); + rsp->port_number = (u8)port_num; + + rsp->port_rcv_constraint_errors = + cpu_to_be64(read_port_cntr(ppd, C_SW_RCV_CSTR_ERR, + CNTR_INVALID_VL)); + /* port_rcv_switch_relay_errors is 0 for HFIs */ + rsp->port_xmit_discards = + cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_DSCD, + CNTR_INVALID_VL)); + rsp->port_rcv_remote_physical_errors = + cpu_to_be64(read_dev_cntr(dd, C_DC_RMT_PHY_ERR, + CNTR_INVALID_VL)); + tmp = read_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL); + tmp2 = tmp + read_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL); + if (tmp2 < tmp) { + /* overflow/wrapped */ + rsp->local_link_integrity_errors = cpu_to_be64(~0); + } else { + rsp->local_link_integrity_errors = cpu_to_be64(tmp2); + } + tmp = read_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL); + tmp2 = tmp + read_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, + CNTR_INVALID_VL); + if (tmp2 > (u32)UINT_MAX || tmp2 < tmp) { + /* overflow/wrapped */ + rsp->link_error_recovery = cpu_to_be32(~0); + } else { + rsp->link_error_recovery = cpu_to_be32(tmp2); + } + rsp->port_xmit_constraint_errors = + cpu_to_be64(read_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, + CNTR_INVALID_VL)); + rsp->excessive_buffer_overruns = + cpu_to_be64(read_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL)); + rsp->fm_config_errors = + cpu_to_be64(read_dev_cntr(dd, C_DC_FM_CFG_ERR, + CNTR_INVALID_VL)); + rsp->link_downed = cpu_to_be32(read_port_cntr(ppd, C_SW_LINK_DOWN, + CNTR_INVALID_VL)); + tmp = read_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL); + rsp->uncorrectable_errors = tmp < 0x100 ? (tmp & 0xff) : 0xff; + + vlinfo = (struct _vls_ectrs *)&(rsp->vls[0]); + vfi = 0; + vl_select_mask = be32_to_cpu(req->vl_select_mask); + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(req->vl_select_mask)) { + memset(vlinfo, 0, sizeof(*vlinfo)); + /* vlinfo->vls[vfi].port_vl_xmit_discards ??? */ + vlinfo += 1; + vfi++; + } + + if (resp_len) + *resp_len += response_data_size; + + return reply((struct ib_mad_hdr *)pmp); +} + +static int pma_get_opa_errorinfo(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + size_t response_data_size; + struct _port_ei *rsp; + struct opa_port_error_info_msg *req; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + u64 port_mask; + u32 num_ports; + unsigned long port_num; + u8 num_pslm; + u64 reg; + + req = (struct opa_port_error_info_msg *)pmp->data; + rsp = (struct _port_ei *)&(req->port[0]); + + num_ports = OPA_AM_NPORT(be32_to_cpu(pmp->mad_hdr.attr_mod)); + num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); + + memset(rsp, 0, sizeof(*rsp)); + + if (num_ports != 1 || num_ports != num_pslm) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + /* Sanity check */ + response_data_size = sizeof(struct opa_port_error_info_msg); + + if (response_data_size > sizeof(pmp->data)) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + /* + * The bit set in the mask needs to be consistent with the port + * the request came in on. + */ + port_mask = be64_to_cpu(req->port_select_mask[3]); + port_num = find_first_bit((unsigned long *)&port_mask, + sizeof(port_mask)); + + if ((u8)port_num != port) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + /* PortRcvErrorInfo */ + rsp->port_rcv_ei.status_and_code = + dd->err_info_rcvport.status_and_code; + memcpy(&rsp->port_rcv_ei.ei.ei1to12.packet_flit1, + &dd->err_info_rcvport.packet_flit1, sizeof(u64)); + memcpy(&rsp->port_rcv_ei.ei.ei1to12.packet_flit2, + &dd->err_info_rcvport.packet_flit2, sizeof(u64)); + + /* ExcessiverBufferOverrunInfo */ + reg = read_csr(dd, RCV_ERR_INFO); + if (reg & RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK) { + /* if the RcvExcessBufferOverrun bit is set, save SC of + * first pkt that encountered an excess buffer overrun */ + u8 tmp = (u8)reg; + + tmp &= RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SC_SMASK; + tmp <<= 2; + rsp->excessive_buffer_overrun_ei.status_and_sc = tmp; + /* set the status bit */ + rsp->excessive_buffer_overrun_ei.status_and_sc |= 0x80; + } + + rsp->port_xmit_constraint_ei.status = + dd->err_info_xmit_constraint.status; + rsp->port_xmit_constraint_ei.pkey = + cpu_to_be16(dd->err_info_xmit_constraint.pkey); + rsp->port_xmit_constraint_ei.slid = + cpu_to_be32(dd->err_info_xmit_constraint.slid); + + rsp->port_rcv_constraint_ei.status = + dd->err_info_rcv_constraint.status; + rsp->port_rcv_constraint_ei.pkey = + cpu_to_be16(dd->err_info_rcv_constraint.pkey); + rsp->port_rcv_constraint_ei.slid = + cpu_to_be32(dd->err_info_rcv_constraint.slid); + + /* UncorrectableErrorInfo */ + rsp->uncorrectable_ei.status_and_code = dd->err_info_uncorrectable; + + /* FMConfigErrorInfo */ + rsp->fm_config_ei.status_and_code = dd->err_info_fmconfig; + + if (resp_len) + *resp_len += response_data_size; + + return reply((struct ib_mad_hdr *)pmp); +} + +static int pma_set_opa_portstatus(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + struct opa_clear_port_status *req = + (struct opa_clear_port_status *)pmp->data; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 nports = be32_to_cpu(pmp->mad_hdr.attr_mod) >> 24; + u64 portn = be64_to_cpu(req->port_select_mask[3]); + u32 counter_select = be32_to_cpu(req->counter_select_mask); + u32 vl_select_mask = VL_MASK_ALL; /* clear all per-vl cnts */ + unsigned long vl; + + if ((nports != 1) || (portn != 1 << port)) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + /* + * only counters returned by pma_get_opa_portstatus() are + * handled, so when pma_get_opa_portstatus() gets a fix, + * the corresponding change should be made here as well. + */ + + if (counter_select & CS_PORT_XMIT_DATA) + write_dev_cntr(dd, C_DC_XMIT_FLITS, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_RCV_DATA) + write_dev_cntr(dd, C_DC_RCV_FLITS, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_XMIT_PKTS) + write_dev_cntr(dd, C_DC_XMIT_PKTS, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_RCV_PKTS) + write_dev_cntr(dd, C_DC_RCV_PKTS, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_MCAST_XMIT_PKTS) + write_dev_cntr(dd, C_DC_MC_XMIT_PKTS, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_MCAST_RCV_PKTS) + write_dev_cntr(dd, C_DC_MC_RCV_PKTS, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_XMIT_WAIT) + write_port_cntr(ppd, C_TX_WAIT, CNTR_INVALID_VL, 0); + + /* ignore cs_sw_portCongestion for HFIs */ + + if (counter_select & CS_PORT_RCV_FECN) + write_dev_cntr(dd, C_DC_RCV_FCN, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_RCV_BECN) + write_dev_cntr(dd, C_DC_RCV_BCN, CNTR_INVALID_VL, 0); + + /* ignore cs_port_xmit_time_cong for HFIs */ + /* ignore cs_port_xmit_wasted_bw for now */ + /* ignore cs_port_xmit_wait_data for now */ + if (counter_select & CS_PORT_RCV_BUBBLE) + write_dev_cntr(dd, C_DC_RCV_BBL, CNTR_INVALID_VL, 0); + + /* Only applicable for switch */ + /*if (counter_select & CS_PORT_MARK_FECN) + write_csr(dd, DCC_PRF_PORT_MARK_FECN_CNT, 0);*/ + + if (counter_select & CS_PORT_RCV_CONSTRAINT_ERRORS) + write_port_cntr(ppd, C_SW_RCV_CSTR_ERR, CNTR_INVALID_VL, 0); + + /* ignore cs_port_rcv_switch_relay_errors for HFIs */ + if (counter_select & CS_PORT_XMIT_DISCARDS) + write_port_cntr(ppd, C_SW_XMIT_DSCD, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_XMIT_CONSTRAINT_ERRORS) + write_port_cntr(ppd, C_SW_XMIT_CSTR_ERR, CNTR_INVALID_VL, 0); + + if (counter_select & CS_PORT_RCV_REMOTE_PHYSICAL_ERRORS) + write_dev_cntr(dd, C_DC_RMT_PHY_ERR, CNTR_INVALID_VL, 0); + + if (counter_select & CS_LOCAL_LINK_INTEGRITY_ERRORS) { + write_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL, 0); + write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); + } + + if (counter_select & CS_LINK_ERROR_RECOVERY) { + write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); + write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, + CNTR_INVALID_VL, 0); + } + + if (counter_select & CS_PORT_RCV_ERRORS) + write_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL, 0); + + if (counter_select & CS_EXCESSIVE_BUFFER_OVERRUNS) { + write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); + dd->rcv_ovfl_cnt = 0; + } + + if (counter_select & CS_FM_CONFIG_ERRORS) + write_dev_cntr(dd, C_DC_FM_CFG_ERR, CNTR_INVALID_VL, 0); + + if (counter_select & CS_LINK_DOWNED) + write_port_cntr(ppd, C_SW_LINK_DOWN, CNTR_INVALID_VL, 0); + + if (counter_select & CS_UNCORRECTABLE_ERRORS) + write_dev_cntr(dd, C_DC_UNC_ERR, CNTR_INVALID_VL, 0); + + for_each_set_bit(vl, (unsigned long *)&(vl_select_mask), + 8 * sizeof(vl_select_mask)) { + + if (counter_select & CS_PORT_XMIT_DATA) + write_port_cntr(ppd, C_TX_FLIT_VL, idx_from_vl(vl), 0); + + if (counter_select & CS_PORT_RCV_DATA) + write_dev_cntr(dd, C_DC_RX_FLIT_VL, idx_from_vl(vl), 0); + + if (counter_select & CS_PORT_XMIT_PKTS) + write_port_cntr(ppd, C_TX_PKT_VL, idx_from_vl(vl), 0); + + if (counter_select & CS_PORT_RCV_PKTS) + write_dev_cntr(dd, C_DC_RX_PKT_VL, idx_from_vl(vl), 0); + + if (counter_select & CS_PORT_XMIT_WAIT) + write_port_cntr(ppd, C_TX_WAIT_VL, idx_from_vl(vl), 0); + + /* sw_port_vl_congestion is 0 for HFIs */ + if (counter_select & CS_PORT_RCV_FECN) + write_dev_cntr(dd, C_DC_RCV_FCN_VL, idx_from_vl(vl), 0); + + if (counter_select & CS_PORT_RCV_BECN) + write_dev_cntr(dd, C_DC_RCV_BCN_VL, idx_from_vl(vl), 0); + + /* port_vl_xmit_time_cong is 0 for HFIs */ + /* port_vl_xmit_wasted_bw ??? */ + /* port_vl_xmit_wait_data - TXE (table 13-9 HFI spec) ??? */ + if (counter_select & CS_PORT_RCV_BUBBLE) + write_dev_cntr(dd, C_DC_RCV_BBL_VL, idx_from_vl(vl), 0); + + /*if (counter_select & CS_PORT_MARK_FECN) + write_csr(dd, DCC_PRF_PORT_VL_MARK_FECN_CNT + offset, 0); + */ + /* port_vl_xmit_discards ??? */ + } + + if (resp_len) + *resp_len += sizeof(*req); + + return reply((struct ib_mad_hdr *)pmp); +} + +static int pma_set_opa_errorinfo(struct opa_pma_mad *pmp, + struct ib_device *ibdev, u8 port, u32 *resp_len) +{ + struct _port_ei *rsp; + struct opa_port_error_info_msg *req; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + u64 port_mask; + u32 num_ports; + unsigned long port_num; + u8 num_pslm; + u32 error_info_select; + + req = (struct opa_port_error_info_msg *)pmp->data; + rsp = (struct _port_ei *)&(req->port[0]); + + num_ports = OPA_AM_NPORT(be32_to_cpu(pmp->mad_hdr.attr_mod)); + num_pslm = hweight64(be64_to_cpu(req->port_select_mask[3])); + + memset(rsp, 0, sizeof(*rsp)); + + if (num_ports != 1 || num_ports != num_pslm) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + /* + * The bit set in the mask needs to be consistent with the port + * the request came in on. + */ + port_mask = be64_to_cpu(req->port_select_mask[3]); + port_num = find_first_bit((unsigned long *)&port_mask, + sizeof(port_mask)); + + if ((u8)port_num != port) { + pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)pmp); + } + + error_info_select = be32_to_cpu(req->error_info_select_mask); + + /* PortRcvErrorInfo */ + if (error_info_select & ES_PORT_RCV_ERROR_INFO) + /* turn off status bit */ + dd->err_info_rcvport.status_and_code &= ~OPA_EI_STATUS_SMASK; + + /* ExcessiverBufferOverrunInfo */ + if (error_info_select & ES_EXCESSIVE_BUFFER_OVERRUN_INFO) + /* status bit is essentially kept in the h/w - bit 5 of + * RCV_ERR_INFO */ + write_csr(dd, RCV_ERR_INFO, + RCV_ERR_INFO_RCV_EXCESS_BUFFER_OVERRUN_SMASK); + + if (error_info_select & ES_PORT_XMIT_CONSTRAINT_ERROR_INFO) + dd->err_info_xmit_constraint.status &= ~OPA_EI_STATUS_SMASK; + + if (error_info_select & ES_PORT_RCV_CONSTRAINT_ERROR_INFO) + dd->err_info_rcv_constraint.status &= ~OPA_EI_STATUS_SMASK; + + /* UncorrectableErrorInfo */ + if (error_info_select & ES_UNCORRECTABLE_ERROR_INFO) + /* turn off status bit */ + dd->err_info_uncorrectable &= ~OPA_EI_STATUS_SMASK; + + /* FMConfigErrorInfo */ + if (error_info_select & ES_FM_CONFIG_ERROR_INFO) + /* turn off status bit */ + dd->err_info_fmconfig &= ~OPA_EI_STATUS_SMASK; + + if (resp_len) + *resp_len += sizeof(*req); + + return reply((struct ib_mad_hdr *)pmp); +} + +struct opa_congestion_info_attr { + __be16 congestion_info; + u8 control_table_cap; /* Multiple of 64 entry unit CCTs */ + u8 congestion_log_length; +} __packed; + +static int __subn_get_opa_cong_info(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct opa_congestion_info_attr *p = + (struct opa_congestion_info_attr *)data; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + p->congestion_info = 0; + p->control_table_cap = ppd->cc_max_table_entries; + p->congestion_log_length = OPA_CONG_LOG_ELEMS; + + if (resp_len) + *resp_len += sizeof(*p); + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_get_opa_cong_setting(struct opa_smp *smp, u32 am, + u8 *data, + struct ib_device *ibdev, + u8 port, u32 *resp_len) +{ + int i; + struct opa_congestion_setting_attr *p = + (struct opa_congestion_setting_attr *) data; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct opa_congestion_setting_entry_shadow *entries; + struct cc_state *cc_state; + + rcu_read_lock(); + + cc_state = get_cc_state(ppd); + + if (cc_state == NULL) { + rcu_read_unlock(); + return reply((struct ib_mad_hdr *)smp); + } + + entries = cc_state->cong_setting.entries; + p->port_control = cpu_to_be16(cc_state->cong_setting.port_control); + p->control_map = cpu_to_be32(cc_state->cong_setting.control_map); + for (i = 0; i < OPA_MAX_SLS; i++) { + p->entries[i].ccti_increase = entries[i].ccti_increase; + p->entries[i].ccti_timer = cpu_to_be16(entries[i].ccti_timer); + p->entries[i].trigger_threshold = + entries[i].trigger_threshold; + p->entries[i].ccti_min = entries[i].ccti_min; + } + + rcu_read_unlock(); + + if (resp_len) + *resp_len += sizeof(*p); + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_cong_setting(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct opa_congestion_setting_attr *p = + (struct opa_congestion_setting_attr *) data; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct opa_congestion_setting_entry_shadow *entries; + int i; + + ppd->cc_sl_control_map = be32_to_cpu(p->control_map); + + entries = ppd->congestion_entries; + for (i = 0; i < OPA_MAX_SLS; i++) { + entries[i].ccti_increase = p->entries[i].ccti_increase; + entries[i].ccti_timer = be16_to_cpu(p->entries[i].ccti_timer); + entries[i].trigger_threshold = + p->entries[i].trigger_threshold; + entries[i].ccti_min = p->entries[i].ccti_min; + } + + return __subn_get_opa_cong_setting(smp, am, data, ibdev, port, + resp_len); +} + +static int __subn_get_opa_hfi1_cong_log(struct opa_smp *smp, u32 am, + u8 *data, struct ib_device *ibdev, + u8 port, u32 *resp_len) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct opa_hfi1_cong_log *cong_log = (struct opa_hfi1_cong_log *)data; + s64 ts; + int i; + + if (am != 0) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + spin_lock(&ppd->cc_log_lock); + + cong_log->log_type = OPA_CC_LOG_TYPE_HFI; + cong_log->congestion_flags = 0; + cong_log->threshold_event_counter = + cpu_to_be16(ppd->threshold_event_counter); + memcpy(cong_log->threshold_cong_event_map, + ppd->threshold_cong_event_map, + sizeof(cong_log->threshold_cong_event_map)); + /* keep timestamp in units of 1.024 usec */ + ts = ktime_to_ns(ktime_get()) / 1024; + cong_log->current_time_stamp = cpu_to_be32(ts); + for (i = 0; i < OPA_CONG_LOG_ELEMS; i++) { + struct opa_hfi1_cong_log_event_internal *cce = + &ppd->cc_events[ppd->cc_mad_idx++]; + if (ppd->cc_mad_idx == OPA_CONG_LOG_ELEMS) + ppd->cc_mad_idx = 0; + /* + * Entries which are older than twice the time + * required to wrap the counter are supposed to + * be zeroed (CA10-49 IBTA, release 1.2.1, V1). + */ + if ((u64)(ts - cce->timestamp) > (2 * UINT_MAX)) + continue; + memcpy(cong_log->events[i].local_qp_cn_entry, &cce->lqpn, 3); + memcpy(cong_log->events[i].remote_qp_number_cn_entry, + &cce->rqpn, 3); + cong_log->events[i].sl_svc_type_cn_entry = + ((cce->sl & 0x1f) << 3) | (cce->svc_type & 0x7); + cong_log->events[i].remote_lid_cn_entry = + cpu_to_be32(cce->rlid); + cong_log->events[i].timestamp_cn_entry = + cpu_to_be32(cce->timestamp); + } + + /* + * Reset threshold_cong_event_map, and threshold_event_counter + * to 0 when log is read. + */ + memset(ppd->threshold_cong_event_map, 0x0, + sizeof(ppd->threshold_cong_event_map)); + ppd->threshold_event_counter = 0; + + spin_unlock(&ppd->cc_log_lock); + + if (resp_len) + *resp_len += sizeof(struct opa_hfi1_cong_log); + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_get_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct ib_cc_table_attr *cc_table_attr = + (struct ib_cc_table_attr *) data; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 start_block = OPA_AM_START_BLK(am); + u32 n_blocks = OPA_AM_NBLK(am); + struct ib_cc_table_entry_shadow *entries; + int i, j; + u32 sentry, eentry; + struct cc_state *cc_state; + + /* sanity check n_blocks, start_block */ + if (n_blocks == 0 || + start_block + n_blocks > ppd->cc_max_table_entries) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + rcu_read_lock(); + + cc_state = get_cc_state(ppd); + + if (cc_state == NULL) { + rcu_read_unlock(); + return reply((struct ib_mad_hdr *)smp); + } + + sentry = start_block * IB_CCT_ENTRIES; + eentry = sentry + (IB_CCT_ENTRIES * n_blocks); + + cc_table_attr->ccti_limit = cpu_to_be16(cc_state->cct.ccti_limit); + + entries = cc_state->cct.entries; + + /* return n_blocks, though the last block may not be full */ + for (j = 0, i = sentry; i < eentry; j++, i++) + cc_table_attr->ccti_entries[j].entry = + cpu_to_be16(entries[i].entry); + + rcu_read_unlock(); + + if (resp_len) + *resp_len += sizeof(u16)*(IB_CCT_ENTRIES * n_blocks + 1); + + return reply((struct ib_mad_hdr *)smp); +} + +void cc_state_reclaim(struct rcu_head *rcu) +{ + struct cc_state *cc_state = container_of(rcu, struct cc_state, rcu); + + kfree(cc_state); +} + +static int __subn_set_opa_cc_table(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct ib_cc_table_attr *p = (struct ib_cc_table_attr *) data; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 start_block = OPA_AM_START_BLK(am); + u32 n_blocks = OPA_AM_NBLK(am); + struct ib_cc_table_entry_shadow *entries; + int i, j; + u32 sentry, eentry; + u16 ccti_limit; + struct cc_state *old_cc_state, *new_cc_state; + + /* sanity check n_blocks, start_block */ + if (n_blocks == 0 || + start_block + n_blocks > ppd->cc_max_table_entries) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + sentry = start_block * IB_CCT_ENTRIES; + eentry = sentry + ((n_blocks - 1) * IB_CCT_ENTRIES) + + (be16_to_cpu(p->ccti_limit)) % IB_CCT_ENTRIES + 1; + + /* sanity check ccti_limit */ + ccti_limit = be16_to_cpu(p->ccti_limit); + if (ccti_limit + 1 > eentry) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + new_cc_state = kzalloc(sizeof(*new_cc_state), GFP_KERNEL); + if (new_cc_state == NULL) + goto getit; + + spin_lock(&ppd->cc_state_lock); + + old_cc_state = get_cc_state(ppd); + + if (old_cc_state == NULL) { + spin_unlock(&ppd->cc_state_lock); + kfree(new_cc_state); + return reply((struct ib_mad_hdr *)smp); + } + + *new_cc_state = *old_cc_state; + + new_cc_state->cct.ccti_limit = ccti_limit; + + entries = ppd->ccti_entries; + ppd->total_cct_entry = ccti_limit + 1; + + for (j = 0, i = sentry; i < eentry; j++, i++) + entries[i].entry = be16_to_cpu(p->ccti_entries[j].entry); + + memcpy(new_cc_state->cct.entries, entries, + eentry * sizeof(struct ib_cc_table_entry)); + + new_cc_state->cong_setting.port_control = IB_CC_CCS_PC_SL_BASED; + new_cc_state->cong_setting.control_map = ppd->cc_sl_control_map; + memcpy(new_cc_state->cong_setting.entries, ppd->congestion_entries, + OPA_MAX_SLS * sizeof(struct opa_congestion_setting_entry)); + + rcu_assign_pointer(ppd->cc_state, new_cc_state); + + spin_unlock(&ppd->cc_state_lock); + + call_rcu(&old_cc_state->rcu, cc_state_reclaim); + +getit: + return __subn_get_opa_cc_table(smp, am, data, ibdev, port, resp_len); +} + +struct opa_led_info { + __be32 rsvd_led_mask; + __be32 rsvd; +}; + +#define OPA_LED_SHIFT 31 +#define OPA_LED_MASK (1 << OPA_LED_SHIFT) + +static int __subn_get_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct opa_led_info *p = (struct opa_led_info *) data; + u32 nport = OPA_AM_NPORT(am); + u64 reg; + + if (nport != 1 || OPA_AM_PORTNUM(am)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + reg = read_csr(dd, DCC_CFG_LED_CNTRL); + if ((reg & DCC_CFG_LED_CNTRL_LED_CNTRL_SMASK) && + ((reg & DCC_CFG_LED_CNTRL_LED_SW_BLINK_RATE_SMASK) == 0xf)) + p->rsvd_led_mask = cpu_to_be32(OPA_LED_MASK); + + if (resp_len) + *resp_len += sizeof(struct opa_led_info); + + return reply((struct ib_mad_hdr *)smp); +} + +static int __subn_set_opa_led_info(struct opa_smp *smp, u32 am, u8 *data, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct opa_led_info *p = (struct opa_led_info *) data; + u32 nport = OPA_AM_NPORT(am); + int on = !!(be32_to_cpu(p->rsvd_led_mask) & OPA_LED_MASK); + + if (nport != 1 || OPA_AM_PORTNUM(am)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + setextled(dd, on); + + return __subn_get_opa_led_info(smp, am, data, ibdev, port, resp_len); +} + +static int subn_get_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am, + u8 *data, struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + int ret; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + + switch (attr_id) { + case IB_SMP_ATTR_NODE_DESC: + ret = __subn_get_opa_nodedesc(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_NODE_INFO: + ret = __subn_get_opa_nodeinfo(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_PORT_INFO: + ret = __subn_get_opa_portinfo(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_PKEY_TABLE: + ret = __subn_get_opa_pkeytable(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SL_TO_SC_MAP: + ret = __subn_get_opa_sl_to_sc(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SC_TO_SL_MAP: + ret = __subn_get_opa_sc_to_sl(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SC_TO_VLT_MAP: + ret = __subn_get_opa_sc_to_vlt(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SC_TO_VLNT_MAP: + ret = __subn_get_opa_sc_to_vlnt(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_PORT_STATE_INFO: + ret = __subn_get_opa_psi(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE: + ret = __subn_get_opa_bct(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_CABLE_INFO: + ret = __subn_get_opa_cable_info(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_VL_ARB_TABLE: + ret = __subn_get_opa_vl_arb(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_CONGESTION_INFO: + ret = __subn_get_opa_cong_info(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING: + ret = __subn_get_opa_cong_setting(smp, am, data, ibdev, + port, resp_len); + break; + case OPA_ATTRIB_ID_HFI_CONGESTION_LOG: + ret = __subn_get_opa_hfi1_cong_log(smp, am, data, ibdev, + port, resp_len); + break; + case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE: + ret = __subn_get_opa_cc_table(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_LED_INFO: + ret = __subn_get_opa_led_info(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_SM_INFO: + if (ibp->port_cap_flags & IB_PORT_SM_DISABLED) + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + if (ibp->port_cap_flags & IB_PORT_SM) + return IB_MAD_RESULT_SUCCESS; + /* FALLTHROUGH */ + default: + smp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_mad_hdr *)smp); + break; + } + return ret; +} + +static int subn_set_opa_sma(__be16 attr_id, struct opa_smp *smp, u32 am, + u8 *data, struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + int ret; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + + switch (attr_id) { + case IB_SMP_ATTR_PORT_INFO: + ret = __subn_set_opa_portinfo(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_PKEY_TABLE: + ret = __subn_set_opa_pkeytable(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SL_TO_SC_MAP: + ret = __subn_set_opa_sl_to_sc(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SC_TO_SL_MAP: + ret = __subn_set_opa_sc_to_sl(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SC_TO_VLT_MAP: + ret = __subn_set_opa_sc_to_vlt(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_SC_TO_VLNT_MAP: + ret = __subn_set_opa_sc_to_vlnt(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_PORT_STATE_INFO: + ret = __subn_set_opa_psi(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_BUFFER_CONTROL_TABLE: + ret = __subn_set_opa_bct(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_VL_ARB_TABLE: + ret = __subn_set_opa_vl_arb(smp, am, data, ibdev, port, + resp_len); + break; + case OPA_ATTRIB_ID_HFI_CONGESTION_SETTING: + ret = __subn_set_opa_cong_setting(smp, am, data, ibdev, + port, resp_len); + break; + case OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE: + ret = __subn_set_opa_cc_table(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_LED_INFO: + ret = __subn_set_opa_led_info(smp, am, data, ibdev, port, + resp_len); + break; + case IB_SMP_ATTR_SM_INFO: + if (ibp->port_cap_flags & IB_PORT_SM_DISABLED) + return IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_CONSUMED; + if (ibp->port_cap_flags & IB_PORT_SM) + return IB_MAD_RESULT_SUCCESS; + /* FALLTHROUGH */ + default: + smp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_mad_hdr *)smp); + break; + } + return ret; +} + +static inline void set_aggr_error(struct opa_aggregate *ag) +{ + ag->err_reqlength |= cpu_to_be16(0x8000); +} + +static int subn_get_opa_aggregate(struct opa_smp *smp, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + int i; + u32 num_attr = be32_to_cpu(smp->attr_mod) & 0x000000ff; + u8 *next_smp = opa_get_smp_data(smp); + + if (num_attr < 1 || num_attr > 117) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < num_attr; i++) { + struct opa_aggregate *agg; + size_t agg_data_len; + size_t agg_size; + u32 am; + + agg = (struct opa_aggregate *)next_smp; + agg_data_len = (be16_to_cpu(agg->err_reqlength) & 0x007f) * 8; + agg_size = sizeof(*agg) + agg_data_len; + am = be32_to_cpu(agg->attr_mod); + + *resp_len += agg_size; + + if (next_smp + agg_size > ((u8 *)smp) + sizeof(*smp)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + /* zero the payload for this segment */ + memset(next_smp + sizeof(*agg), 0, agg_data_len); + + (void) subn_get_opa_sma(agg->attr_id, smp, am, agg->data, + ibdev, port, NULL); + if (smp->status & ~IB_SMP_DIRECTION) { + set_aggr_error(agg); + return reply((struct ib_mad_hdr *)smp); + } + next_smp += agg_size; + + } + + return reply((struct ib_mad_hdr *)smp); +} + +static int subn_set_opa_aggregate(struct opa_smp *smp, + struct ib_device *ibdev, u8 port, + u32 *resp_len) +{ + int i; + u32 num_attr = be32_to_cpu(smp->attr_mod) & 0x000000ff; + u8 *next_smp = opa_get_smp_data(smp); + + if (num_attr < 1 || num_attr > 117) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + for (i = 0; i < num_attr; i++) { + struct opa_aggregate *agg; + size_t agg_data_len; + size_t agg_size; + u32 am; + + agg = (struct opa_aggregate *)next_smp; + agg_data_len = (be16_to_cpu(agg->err_reqlength) & 0x007f) * 8; + agg_size = sizeof(*agg) + agg_data_len; + am = be32_to_cpu(agg->attr_mod); + + *resp_len += agg_size; + + if (next_smp + agg_size > ((u8 *)smp) + sizeof(*smp)) { + smp->status |= IB_SMP_INVALID_FIELD; + return reply((struct ib_mad_hdr *)smp); + } + + (void) subn_set_opa_sma(agg->attr_id, smp, am, agg->data, + ibdev, port, NULL); + if (smp->status & ~IB_SMP_DIRECTION) { + set_aggr_error(agg); + return reply((struct ib_mad_hdr *)smp); + } + next_smp += agg_size; + + } + + return reply((struct ib_mad_hdr *)smp); +} + +/* + * OPAv1 specifies that, on the transition to link up, these counters + * are cleared: + * PortRcvErrors [*] + * LinkErrorRecovery + * LocalLinkIntegrityErrors + * ExcessiveBufferOverruns [*] + * + * [*] Error info associated with these counters is retained, but the + * error info status is reset to 0. + */ +void clear_linkup_counters(struct hfi1_devdata *dd) +{ + /* PortRcvErrors */ + write_dev_cntr(dd, C_DC_RCV_ERR, CNTR_INVALID_VL, 0); + dd->err_info_rcvport.status_and_code &= ~OPA_EI_STATUS_SMASK; + /* LinkErrorRecovery */ + write_dev_cntr(dd, C_DC_SEQ_CRC_CNT, CNTR_INVALID_VL, 0); + write_dev_cntr(dd, C_DC_REINIT_FROM_PEER_CNT, CNTR_INVALID_VL, 0); + /* LocalLinkIntegrityErrors */ + write_dev_cntr(dd, C_DC_TX_REPLAY, CNTR_INVALID_VL, 0); + write_dev_cntr(dd, C_DC_RX_REPLAY, CNTR_INVALID_VL, 0); + /* ExcessiveBufferOverruns */ + write_dev_cntr(dd, C_RCV_OVF, CNTR_INVALID_VL, 0); + dd->rcv_ovfl_cnt = 0; + dd->err_info_xmit_constraint.status &= ~OPA_EI_STATUS_SMASK; +} + +/* + * is_local_mad() returns 1 if 'mad' is sent from, and destined to the + * local node, 0 otherwise. + */ +static int is_local_mad(struct hfi1_ibport *ibp, const struct opa_mad *mad, + const struct ib_wc *in_wc) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + const struct opa_smp *smp = (const struct opa_smp *)mad; + + if (smp->mgmt_class == IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) { + return (smp->hop_cnt == 0 && + smp->route.dr.dr_slid == OPA_LID_PERMISSIVE && + smp->route.dr.dr_dlid == OPA_LID_PERMISSIVE); + } + + return (in_wc->slid == ppd->lid); +} + +/* + * opa_local_smp_check() should only be called on MADs for which + * is_local_mad() returns true. It applies the SMP checks that are + * specific to SMPs which are sent from, and destined to this node. + * opa_local_smp_check() returns 0 if the SMP passes its checks, 1 + * otherwise. + * + * SMPs which arrive from other nodes are instead checked by + * opa_smp_check(). + */ +static int opa_local_smp_check(struct hfi1_ibport *ibp, + const struct ib_wc *in_wc) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u16 slid = in_wc->slid; + u16 pkey; + + if (in_wc->pkey_index >= ARRAY_SIZE(ppd->pkeys)) + return 1; + + pkey = ppd->pkeys[in_wc->pkey_index]; + /* + * We need to do the "node-local" checks specified in OPAv1, + * rev 0.90, section 9.10.26, which are: + * - pkey is 0x7fff, or 0xffff + * - Source QPN == 0 || Destination QPN == 0 + * - the MAD header's management class is either + * IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE or + * IB_MGMT_CLASS_SUBN_LID_ROUTED + * - SLID != 0 + * + * However, we know (and so don't need to check again) that, + * for local SMPs, the MAD stack passes MADs with: + * - Source QPN of 0 + * - MAD mgmt_class is IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE + * - SLID is either: OPA_LID_PERMISSIVE (0xFFFFFFFF), or + * our own port's lid + * + */ + if (pkey == LIM_MGMT_P_KEY || pkey == FULL_MGMT_P_KEY) + return 0; + ingress_pkey_table_fail(ppd, pkey, slid); + return 1; +} + +static int process_subn_opa(struct ib_device *ibdev, int mad_flags, + u8 port, const struct opa_mad *in_mad, + struct opa_mad *out_mad, + u32 *resp_len) +{ + struct opa_smp *smp = (struct opa_smp *)out_mad; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + u8 *data; + u32 am; + __be16 attr_id; + int ret; + + *out_mad = *in_mad; + data = opa_get_smp_data(smp); + + am = be32_to_cpu(smp->attr_mod); + attr_id = smp->attr_id; + if (smp->class_version != OPA_SMI_CLASS_VERSION) { + smp->status |= IB_SMP_UNSUP_VERSION; + ret = reply((struct ib_mad_hdr *)smp); + goto bail; + } + ret = check_mkey(ibp, (struct ib_mad_hdr *)smp, mad_flags, smp->mkey, + smp->route.dr.dr_slid, smp->route.dr.return_path, + smp->hop_cnt); + if (ret) { + u32 port_num = be32_to_cpu(smp->attr_mod); + + /* + * If this is a get/set portinfo, we already check the + * M_Key if the MAD is for another port and the M_Key + * is OK on the receiving port. This check is needed + * to increment the error counters when the M_Key + * fails to match on *both* ports. + */ + if (attr_id == IB_SMP_ATTR_PORT_INFO && + (smp->method == IB_MGMT_METHOD_GET || + smp->method == IB_MGMT_METHOD_SET) && + port_num && port_num <= ibdev->phys_port_cnt && + port != port_num) + (void) check_mkey(to_iport(ibdev, port_num), + (struct ib_mad_hdr *)smp, 0, + smp->mkey, smp->route.dr.dr_slid, + smp->route.dr.return_path, + smp->hop_cnt); + ret = IB_MAD_RESULT_FAILURE; + goto bail; + } + + *resp_len = opa_get_smp_header_size(smp); + + switch (smp->method) { + case IB_MGMT_METHOD_GET: + switch (attr_id) { + default: + clear_opa_smp_data(smp); + ret = subn_get_opa_sma(attr_id, smp, am, data, + ibdev, port, resp_len); + goto bail; + case OPA_ATTRIB_ID_AGGREGATE: + ret = subn_get_opa_aggregate(smp, ibdev, port, + resp_len); + goto bail; + } + case IB_MGMT_METHOD_SET: + switch (attr_id) { + default: + ret = subn_set_opa_sma(attr_id, smp, am, data, + ibdev, port, resp_len); + goto bail; + case OPA_ATTRIB_ID_AGGREGATE: + ret = subn_set_opa_aggregate(smp, ibdev, port, + resp_len); + goto bail; + } + case IB_MGMT_METHOD_TRAP: + case IB_MGMT_METHOD_REPORT: + case IB_MGMT_METHOD_REPORT_RESP: + case IB_MGMT_METHOD_GET_RESP: + /* + * The ib_mad module will call us to process responses + * before checking for other consumers. + * Just tell the caller to process it normally. + */ + ret = IB_MAD_RESULT_SUCCESS; + goto bail; + default: + smp->status |= IB_SMP_UNSUP_METHOD; + ret = reply((struct ib_mad_hdr *)smp); + } + +bail: + return ret; +} + +static int process_subn(struct ib_device *ibdev, int mad_flags, + u8 port, const struct ib_mad *in_mad, + struct ib_mad *out_mad) +{ + struct ib_smp *smp = (struct ib_smp *)out_mad; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + int ret; + + *out_mad = *in_mad; + if (smp->class_version != 1) { + smp->status |= IB_SMP_UNSUP_VERSION; + ret = reply((struct ib_mad_hdr *)smp); + goto bail; + } + + ret = check_mkey(ibp, (struct ib_mad_hdr *)smp, mad_flags, + smp->mkey, (__force __be32)smp->dr_slid, + smp->return_path, smp->hop_cnt); + if (ret) { + u32 port_num = be32_to_cpu(smp->attr_mod); + + /* + * If this is a get/set portinfo, we already check the + * M_Key if the MAD is for another port and the M_Key + * is OK on the receiving port. This check is needed + * to increment the error counters when the M_Key + * fails to match on *both* ports. + */ + if (in_mad->mad_hdr.attr_id == IB_SMP_ATTR_PORT_INFO && + (smp->method == IB_MGMT_METHOD_GET || + smp->method == IB_MGMT_METHOD_SET) && + port_num && port_num <= ibdev->phys_port_cnt && + port != port_num) + (void) check_mkey(to_iport(ibdev, port_num), + (struct ib_mad_hdr *)smp, 0, + smp->mkey, + (__force __be32)smp->dr_slid, + smp->return_path, smp->hop_cnt); + ret = IB_MAD_RESULT_FAILURE; + goto bail; + } + + switch (smp->method) { + case IB_MGMT_METHOD_GET: + switch (smp->attr_id) { + case IB_SMP_ATTR_NODE_INFO: + ret = subn_get_nodeinfo(smp, ibdev, port); + goto bail; + default: + smp->status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_mad_hdr *)smp); + goto bail; + } + } + +bail: + return ret; +} + +static int process_perf_opa(struct ib_device *ibdev, u8 port, + const struct opa_mad *in_mad, + struct opa_mad *out_mad, u32 *resp_len) +{ + struct opa_pma_mad *pmp = (struct opa_pma_mad *)out_mad; + int ret; + + *out_mad = *in_mad; + + if (pmp->mad_hdr.class_version != OPA_SMI_CLASS_VERSION) { + pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION; + return reply((struct ib_mad_hdr *)pmp); + } + + *resp_len = sizeof(pmp->mad_hdr); + + switch (pmp->mad_hdr.method) { + case IB_MGMT_METHOD_GET: + switch (pmp->mad_hdr.attr_id) { + case IB_PMA_CLASS_PORT_INFO: + ret = pma_get_opa_classportinfo(pmp, ibdev, resp_len); + goto bail; + case OPA_PM_ATTRIB_ID_PORT_STATUS: + ret = pma_get_opa_portstatus(pmp, ibdev, port, + resp_len); + goto bail; + case OPA_PM_ATTRIB_ID_DATA_PORT_COUNTERS: + ret = pma_get_opa_datacounters(pmp, ibdev, port, + resp_len); + goto bail; + case OPA_PM_ATTRIB_ID_ERROR_PORT_COUNTERS: + ret = pma_get_opa_porterrors(pmp, ibdev, port, + resp_len); + goto bail; + case OPA_PM_ATTRIB_ID_ERROR_INFO: + ret = pma_get_opa_errorinfo(pmp, ibdev, port, + resp_len); + goto bail; + default: + pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_mad_hdr *)pmp); + goto bail; + } + + case IB_MGMT_METHOD_SET: + switch (pmp->mad_hdr.attr_id) { + case OPA_PM_ATTRIB_ID_CLEAR_PORT_STATUS: + ret = pma_set_opa_portstatus(pmp, ibdev, port, + resp_len); + goto bail; + case OPA_PM_ATTRIB_ID_ERROR_INFO: + ret = pma_set_opa_errorinfo(pmp, ibdev, port, + resp_len); + goto bail; + default: + pmp->mad_hdr.status |= IB_SMP_UNSUP_METH_ATTR; + ret = reply((struct ib_mad_hdr *)pmp); + goto bail; + } + + case IB_MGMT_METHOD_TRAP: + case IB_MGMT_METHOD_GET_RESP: + /* + * The ib_mad module will call us to process responses + * before checking for other consumers. + * Just tell the caller to process it normally. + */ + ret = IB_MAD_RESULT_SUCCESS; + goto bail; + + default: + pmp->mad_hdr.status |= IB_SMP_UNSUP_METHOD; + ret = reply((struct ib_mad_hdr *)pmp); + } + +bail: + return ret; +} + +static int hfi1_process_opa_mad(struct ib_device *ibdev, int mad_flags, + u8 port, const struct ib_wc *in_wc, + const struct ib_grh *in_grh, + const struct opa_mad *in_mad, + struct opa_mad *out_mad, size_t *out_mad_size, + u16 *out_mad_pkey_index) +{ + int ret; + int pkey_idx; + u32 resp_len = 0; + struct hfi1_ibport *ibp = to_iport(ibdev, port); + + pkey_idx = hfi1_lookup_pkey_idx(ibp, LIM_MGMT_P_KEY); + if (pkey_idx < 0) { + pr_warn("failed to find limited mgmt pkey, defaulting 0x%x\n", + hfi1_get_pkey(ibp, 1)); + pkey_idx = 1; + } + *out_mad_pkey_index = (u16)pkey_idx; + + switch (in_mad->mad_hdr.mgmt_class) { + case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: + case IB_MGMT_CLASS_SUBN_LID_ROUTED: + if (is_local_mad(ibp, in_mad, in_wc)) { + ret = opa_local_smp_check(ibp, in_wc); + if (ret) + return IB_MAD_RESULT_FAILURE; + } + ret = process_subn_opa(ibdev, mad_flags, port, in_mad, + out_mad, &resp_len); + goto bail; + case IB_MGMT_CLASS_PERF_MGMT: + ret = process_perf_opa(ibdev, port, in_mad, out_mad, + &resp_len); + goto bail; + + default: + ret = IB_MAD_RESULT_SUCCESS; + } + +bail: + if (ret & IB_MAD_RESULT_REPLY) + *out_mad_size = round_up(resp_len, 8); + else if (ret & IB_MAD_RESULT_SUCCESS) + *out_mad_size = in_wc->byte_len - sizeof(struct ib_grh); + + return ret; +} + +static int hfi1_process_ib_mad(struct ib_device *ibdev, int mad_flags, u8 port, + const struct ib_wc *in_wc, + const struct ib_grh *in_grh, + const struct ib_mad *in_mad, + struct ib_mad *out_mad) +{ + int ret; + + switch (in_mad->mad_hdr.mgmt_class) { + case IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE: + case IB_MGMT_CLASS_SUBN_LID_ROUTED: + ret = process_subn(ibdev, mad_flags, port, in_mad, out_mad); + goto bail; + default: + ret = IB_MAD_RESULT_SUCCESS; + } + +bail: + return ret; +} + +/** + * hfi1_process_mad - process an incoming MAD packet + * @ibdev: the infiniband device this packet came in on + * @mad_flags: MAD flags + * @port: the port number this packet came in on + * @in_wc: the work completion entry for this packet + * @in_grh: the global route header for this packet + * @in_mad: the incoming MAD + * @out_mad: any outgoing MAD reply + * + * Returns IB_MAD_RESULT_SUCCESS if this is a MAD that we are not + * interested in processing. + * + * Note that the verbs framework has already done the MAD sanity checks, + * and hop count/pointer updating for IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE + * MADs. + * + * This is called by the ib_mad module. + */ +int hfi1_process_mad(struct ib_device *ibdev, int mad_flags, u8 port, + const struct ib_wc *in_wc, const struct ib_grh *in_grh, + const struct ib_mad_hdr *in_mad, size_t in_mad_size, + struct ib_mad_hdr *out_mad, size_t *out_mad_size, + u16 *out_mad_pkey_index) +{ + switch (in_mad->base_version) { + case OPA_MGMT_BASE_VERSION: + if (unlikely(in_mad_size != sizeof(struct opa_mad))) { + dev_err(ibdev->dma_device, "invalid in_mad_size\n"); + return IB_MAD_RESULT_FAILURE; + } + return hfi1_process_opa_mad(ibdev, mad_flags, port, + in_wc, in_grh, + (struct opa_mad *)in_mad, + (struct opa_mad *)out_mad, + out_mad_size, + out_mad_pkey_index); + case IB_MGMT_BASE_VERSION: + return hfi1_process_ib_mad(ibdev, mad_flags, port, + in_wc, in_grh, + (const struct ib_mad *)in_mad, + (struct ib_mad *)out_mad); + default: + break; + } + + return IB_MAD_RESULT_FAILURE; +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc) +{ + ib_free_send_mad(mad_send_wc->send_buf); +} + +int hfi1_create_agents(struct hfi1_ibdev *dev) +{ + struct hfi1_devdata *dd = dd_from_dev(dev); + struct ib_mad_agent *agent; + struct hfi1_ibport *ibp; + int p; + int ret; + + for (p = 0; p < dd->num_pports; p++) { + ibp = &dd->pport[p].ibport_data; + agent = ib_register_mad_agent(&dev->ibdev, p + 1, IB_QPT_SMI, + NULL, 0, send_handler, + NULL, NULL, 0); + if (IS_ERR(agent)) { + ret = PTR_ERR(agent); + goto err; + } + + ibp->send_agent = agent; + } + + return 0; + +err: + for (p = 0; p < dd->num_pports; p++) { + ibp = &dd->pport[p].ibport_data; + if (ibp->send_agent) { + agent = ibp->send_agent; + ibp->send_agent = NULL; + ib_unregister_mad_agent(agent); + } + } + + return ret; +} + +void hfi1_free_agents(struct hfi1_ibdev *dev) +{ + struct hfi1_devdata *dd = dd_from_dev(dev); + struct ib_mad_agent *agent; + struct hfi1_ibport *ibp; + int p; + + for (p = 0; p < dd->num_pports; p++) { + ibp = &dd->pport[p].ibport_data; + if (ibp->send_agent) { + agent = ibp->send_agent; + ibp->send_agent = NULL; + ib_unregister_mad_agent(agent); + } + if (ibp->sm_ah) { + ib_destroy_ah(&ibp->sm_ah->ibah); + ibp->sm_ah = NULL; + } + } +} diff --git a/drivers/staging/rdma/hfi1/mad.h b/drivers/staging/rdma/hfi1/mad.h new file mode 100644 index 0000000000000..47457501c0440 --- /dev/null +++ b/drivers/staging/rdma/hfi1/mad.h @@ -0,0 +1,325 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef _HFI1_MAD_H +#define _HFI1_MAD_H + +#include +#define USE_PI_LED_ENABLE 1 /* use led enabled bit in struct + * opa_port_states, if available */ +#include +#include +#ifndef PI_LED_ENABLE_SUP +#define PI_LED_ENABLE_SUP 0 +#endif +#include "opa_compat.h" + + + +#define IB_VLARB_LOWPRI_0_31 1 +#define IB_VLARB_LOWPRI_32_63 2 +#define IB_VLARB_HIGHPRI_0_31 3 +#define IB_VLARB_HIGHPRI_32_63 4 + +#define OPA_MAX_PREEMPT_CAP 32 +#define OPA_VLARB_LOW_ELEMENTS 0 +#define OPA_VLARB_HIGH_ELEMENTS 1 +#define OPA_VLARB_PREEMPT_ELEMENTS 2 +#define OPA_VLARB_PREEMPT_MATRIX 3 + +#define IB_PMA_PORT_COUNTERS_CONG cpu_to_be16(0xFF00) + +struct ib_pma_portcounters_cong { + u8 reserved; + u8 reserved1; + __be16 port_check_rate; + __be16 symbol_error_counter; + u8 link_error_recovery_counter; + u8 link_downed_counter; + __be16 port_rcv_errors; + __be16 port_rcv_remphys_errors; + __be16 port_rcv_switch_relay_errors; + __be16 port_xmit_discards; + u8 port_xmit_constraint_errors; + u8 port_rcv_constraint_errors; + u8 reserved2; + u8 link_overrun_errors; /* LocalLink: 7:4, BufferOverrun: 3:0 */ + __be16 reserved3; + __be16 vl15_dropped; + __be64 port_xmit_data; + __be64 port_rcv_data; + __be64 port_xmit_packets; + __be64 port_rcv_packets; + __be64 port_xmit_wait; + __be64 port_adr_events; +} __packed; + +#define IB_SMP_UNSUP_VERSION cpu_to_be16(0x0004) +#define IB_SMP_UNSUP_METHOD cpu_to_be16(0x0008) +#define IB_SMP_UNSUP_METH_ATTR cpu_to_be16(0x000C) +#define IB_SMP_INVALID_FIELD cpu_to_be16(0x001C) + +#define OPA_MAX_PREEMPT_CAP 32 +#define OPA_VLARB_LOW_ELEMENTS 0 +#define OPA_VLARB_HIGH_ELEMENTS 1 +#define OPA_VLARB_PREEMPT_ELEMENTS 2 +#define OPA_VLARB_PREEMPT_MATRIX 3 + +#define HFI1_XMIT_RATE_UNSUPPORTED 0x0 +#define HFI1_XMIT_RATE_PICO 0x7 +/* number of 4nsec cycles equaling 2secs */ +#define HFI1_CONG_TIMER_PSINTERVAL 0x1DCD64EC + +#define IB_CC_SVCTYPE_RC 0x0 +#define IB_CC_SVCTYPE_UC 0x1 +#define IB_CC_SVCTYPE_RD 0x2 +#define IB_CC_SVCTYPE_UD 0x3 + + +/* + * There should be an equivalent IB #define for the following, but + * I cannot find it. + */ +#define OPA_CC_LOG_TYPE_HFI 2 + +struct opa_hfi1_cong_log_event_internal { + u32 lqpn; + u32 rqpn; + u8 sl; + u8 svc_type; + u32 rlid; + s64 timestamp; /* wider than 32 bits to detect 32 bit rollover */ +}; + +struct opa_hfi1_cong_log_event { + u8 local_qp_cn_entry[3]; + u8 remote_qp_number_cn_entry[3]; + u8 sl_svc_type_cn_entry; /* 5 bits SL, 3 bits svc type */ + u8 reserved; + __be32 remote_lid_cn_entry; + __be32 timestamp_cn_entry; +} __packed; + +#define OPA_CONG_LOG_ELEMS 96 + +struct opa_hfi1_cong_log { + u8 log_type; + u8 congestion_flags; + __be16 threshold_event_counter; + __be32 current_time_stamp; + u8 threshold_cong_event_map[OPA_MAX_SLS/8]; + struct opa_hfi1_cong_log_event events[OPA_CONG_LOG_ELEMS]; +} __packed; + +#define IB_CC_TABLE_CAP_DEFAULT 31 + +/* Port control flags */ +#define IB_CC_CCS_PC_SL_BASED 0x01 + +struct opa_congestion_setting_entry { + u8 ccti_increase; + u8 reserved; + __be16 ccti_timer; + u8 trigger_threshold; + u8 ccti_min; /* min CCTI for cc table */ +} __packed; + +struct opa_congestion_setting_entry_shadow { + u8 ccti_increase; + u8 reserved; + u16 ccti_timer; + u8 trigger_threshold; + u8 ccti_min; /* min CCTI for cc table */ +} __packed; + +struct opa_congestion_setting_attr { + __be32 control_map; + __be16 port_control; + struct opa_congestion_setting_entry entries[OPA_MAX_SLS]; +} __packed; + +struct opa_congestion_setting_attr_shadow { + u32 control_map; + u16 port_control; + struct opa_congestion_setting_entry_shadow entries[OPA_MAX_SLS]; +} __packed; + +#define IB_CC_TABLE_ENTRY_INCREASE_DEFAULT 1 +#define IB_CC_TABLE_ENTRY_TIMER_DEFAULT 1 + +/* 64 Congestion Control table entries in a single MAD */ +#define IB_CCT_ENTRIES 64 +#define IB_CCT_MIN_ENTRIES (IB_CCT_ENTRIES * 2) + +struct ib_cc_table_entry { + __be16 entry; /* shift:2, multiplier:14 */ +}; + +struct ib_cc_table_entry_shadow { + u16 entry; /* shift:2, multiplier:14 */ +}; + +struct ib_cc_table_attr { + __be16 ccti_limit; /* max CCTI for cc table */ + struct ib_cc_table_entry ccti_entries[IB_CCT_ENTRIES]; +} __packed; + +struct ib_cc_table_attr_shadow { + u16 ccti_limit; /* max CCTI for cc table */ + struct ib_cc_table_entry_shadow ccti_entries[IB_CCT_ENTRIES]; +} __packed; + +#define CC_TABLE_SHADOW_MAX \ + (IB_CC_TABLE_CAP_DEFAULT * IB_CCT_ENTRIES) + +struct cc_table_shadow { + u16 ccti_limit; /* max CCTI for cc table */ + struct ib_cc_table_entry_shadow entries[CC_TABLE_SHADOW_MAX]; +} __packed; + +/* + * struct cc_state combines the (active) per-port congestion control + * table, and the (active) per-SL congestion settings. cc_state data + * may need to be read in code paths that we want to be fast, so it + * is an RCU protected structure. + */ +struct cc_state { + struct rcu_head rcu; + struct cc_table_shadow cct; + struct opa_congestion_setting_attr_shadow cong_setting; +}; + +/* + * OPA BufferControl MAD + */ + +/* attribute modifier macros */ +#define OPA_AM_NPORT_SHIFT 24 +#define OPA_AM_NPORT_MASK 0xff +#define OPA_AM_NPORT_SMASK (OPA_AM_NPORT_MASK << OPA_AM_NPORT_SHIFT) +#define OPA_AM_NPORT(am) (((am) >> OPA_AM_NPORT_SHIFT) & \ + OPA_AM_NPORT_MASK) + +#define OPA_AM_NBLK_SHIFT 24 +#define OPA_AM_NBLK_MASK 0xff +#define OPA_AM_NBLK_SMASK (OPA_AM_NBLK_MASK << OPA_AM_NBLK_SHIFT) +#define OPA_AM_NBLK(am) (((am) >> OPA_AM_NBLK_SHIFT) & \ + OPA_AM_NBLK_MASK) + +#define OPA_AM_START_BLK_SHIFT 0 +#define OPA_AM_START_BLK_MASK 0xff +#define OPA_AM_START_BLK_SMASK (OPA_AM_START_BLK_MASK << \ + OPA_AM_START_BLK_SHIFT) +#define OPA_AM_START_BLK(am) (((am) >> OPA_AM_START_BLK_SHIFT) & \ + OPA_AM_START_BLK_MASK) + +#define OPA_AM_PORTNUM_SHIFT 0 +#define OPA_AM_PORTNUM_MASK 0xff +#define OPA_AM_PORTNUM_SMASK (OPA_AM_PORTNUM_MASK << OPA_AM_PORTNUM_SHIFT) +#define OPA_AM_PORTNUM(am) (((am) >> OPA_AM_PORTNUM_SHIFT) & \ + OPA_AM_PORTNUM_MASK) + +#define OPA_AM_ASYNC_SHIFT 12 +#define OPA_AM_ASYNC_MASK 0x1 +#define OPA_AM_ASYNC_SMASK (OPA_AM_ASYNC_MASK << OPA_AM_ASYNC_SHIFT) +#define OPA_AM_ASYNC(am) (((am) >> OPA_AM_ASYNC_SHIFT) & \ + OPA_AM_ASYNC_MASK) + +#define OPA_AM_START_SM_CFG_SHIFT 9 +#define OPA_AM_START_SM_CFG_MASK 0x1 +#define OPA_AM_START_SM_CFG_SMASK (OPA_AM_START_SM_CFG_MASK << \ + OPA_AM_START_SM_CFG_SHIFT) +#define OPA_AM_START_SM_CFG(am) (((am) >> OPA_AM_START_SM_CFG_SHIFT) \ + & OPA_AM_START_SM_CFG_MASK) + +#define OPA_AM_CI_ADDR_SHIFT 19 +#define OPA_AM_CI_ADDR_MASK 0xfff +#define OPA_AM_CI_ADDR_SMASK (OPA_AM_CI_ADDR_MASK << OPA_CI_ADDR_SHIFT) +#define OPA_AM_CI_ADDR(am) (((am) >> OPA_AM_CI_ADDR_SHIFT) & \ + OPA_AM_CI_ADDR_MASK) + +#define OPA_AM_CI_LEN_SHIFT 13 +#define OPA_AM_CI_LEN_MASK 0x3f +#define OPA_AM_CI_LEN_SMASK (OPA_AM_CI_LEN_MASK << OPA_CI_LEN_SHIFT) +#define OPA_AM_CI_LEN(am) (((am) >> OPA_AM_CI_LEN_SHIFT) & \ + OPA_AM_CI_LEN_MASK) + +/* error info macros */ +#define OPA_EI_STATUS_SMASK 0x80 +#define OPA_EI_CODE_SMASK 0x0f + +struct vl_limit { + __be16 dedicated; + __be16 shared; +}; + +struct buffer_control { + __be16 reserved; + __be16 overall_shared_limit; + struct vl_limit vl[OPA_MAX_VLS]; +}; + +struct sc2vlnt { + u8 vlnt[32]; /* 5 bit VL, 3 bits reserved */ +}; + +/* + * The PortSamplesControl.CounterMasks field is an array of 3 bit fields + * which specify the N'th counter's capabilities. See ch. 16.1.3.2. + * We support 5 counters which only count the mandatory quantities. + */ +#define COUNTER_MASK(q, n) (q << ((9 - n) * 3)) +#define COUNTER_MASK0_9 \ + cpu_to_be32(COUNTER_MASK(1, 0) | \ + COUNTER_MASK(1, 1) | \ + COUNTER_MASK(1, 2) | \ + COUNTER_MASK(1, 3) | \ + COUNTER_MASK(1, 4)) + +#endif /* _HFI1_MAD_H */ diff --git a/drivers/staging/rdma/hfi1/mmap.c b/drivers/staging/rdma/hfi1/mmap.c new file mode 100644 index 0000000000000..5173b1c60b3d3 --- /dev/null +++ b/drivers/staging/rdma/hfi1/mmap.c @@ -0,0 +1,192 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "verbs.h" + +/** + * hfi1_release_mmap_info - free mmap info structure + * @ref: a pointer to the kref within struct hfi1_mmap_info + */ +void hfi1_release_mmap_info(struct kref *ref) +{ + struct hfi1_mmap_info *ip = + container_of(ref, struct hfi1_mmap_info, ref); + struct hfi1_ibdev *dev = to_idev(ip->context->device); + + spin_lock_irq(&dev->pending_lock); + list_del(&ip->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + + vfree(ip->obj); + kfree(ip); +} + +/* + * open and close keep track of how many times the CQ is mapped, + * to avoid releasing it. + */ +static void hfi1_vma_open(struct vm_area_struct *vma) +{ + struct hfi1_mmap_info *ip = vma->vm_private_data; + + kref_get(&ip->ref); +} + +static void hfi1_vma_close(struct vm_area_struct *vma) +{ + struct hfi1_mmap_info *ip = vma->vm_private_data; + + kref_put(&ip->ref, hfi1_release_mmap_info); +} + +static struct vm_operations_struct hfi1_vm_ops = { + .open = hfi1_vma_open, + .close = hfi1_vma_close, +}; + +/** + * hfi1_mmap - create a new mmap region + * @context: the IB user context of the process making the mmap() call + * @vma: the VMA to be initialized + * Return zero if the mmap is OK. Otherwise, return an errno. + */ +int hfi1_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) +{ + struct hfi1_ibdev *dev = to_idev(context->device); + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + unsigned long size = vma->vm_end - vma->vm_start; + struct hfi1_mmap_info *ip, *pp; + int ret = -EINVAL; + + /* + * Search the device's list of objects waiting for a mmap call. + * Normally, this list is very short since a call to create a + * CQ, QP, or SRQ is soon followed by a call to mmap(). + */ + spin_lock_irq(&dev->pending_lock); + list_for_each_entry_safe(ip, pp, &dev->pending_mmaps, + pending_mmaps) { + /* Only the creator is allowed to mmap the object */ + if (context != ip->context || (__u64) offset != ip->offset) + continue; + /* Don't allow a mmap larger than the object. */ + if (size > ip->size) + break; + + list_del_init(&ip->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + + ret = remap_vmalloc_range(vma, ip->obj, 0); + if (ret) + goto done; + vma->vm_ops = &hfi1_vm_ops; + vma->vm_private_data = ip; + hfi1_vma_open(vma); + goto done; + } + spin_unlock_irq(&dev->pending_lock); +done: + return ret; +} + +/* + * Allocate information for hfi1_mmap + */ +struct hfi1_mmap_info *hfi1_create_mmap_info(struct hfi1_ibdev *dev, + u32 size, + struct ib_ucontext *context, + void *obj) { + struct hfi1_mmap_info *ip; + + ip = kmalloc(sizeof(*ip), GFP_KERNEL); + if (!ip) + goto bail; + + size = PAGE_ALIGN(size); + + spin_lock_irq(&dev->mmap_offset_lock); + if (dev->mmap_offset == 0) + dev->mmap_offset = PAGE_SIZE; + ip->offset = dev->mmap_offset; + dev->mmap_offset += size; + spin_unlock_irq(&dev->mmap_offset_lock); + + INIT_LIST_HEAD(&ip->pending_mmaps); + ip->size = size; + ip->context = context; + ip->obj = obj; + kref_init(&ip->ref); + +bail: + return ip; +} + +void hfi1_update_mmap_info(struct hfi1_ibdev *dev, struct hfi1_mmap_info *ip, + u32 size, void *obj) +{ + size = PAGE_ALIGN(size); + + spin_lock_irq(&dev->mmap_offset_lock); + if (dev->mmap_offset == 0) + dev->mmap_offset = PAGE_SIZE; + ip->offset = dev->mmap_offset; + dev->mmap_offset += size; + spin_unlock_irq(&dev->mmap_offset_lock); + + ip->size = size; + ip->obj = obj; +} diff --git a/drivers/staging/rdma/hfi1/mr.c b/drivers/staging/rdma/hfi1/mr.c new file mode 100644 index 0000000000000..23567f83c8725 --- /dev/null +++ b/drivers/staging/rdma/hfi1/mr.c @@ -0,0 +1,546 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "hfi.h" + +/* Fast memory region */ +struct hfi1_fmr { + struct ib_fmr ibfmr; + struct hfi1_mregion mr; /* must be last */ +}; + +static inline struct hfi1_fmr *to_ifmr(struct ib_fmr *ibfmr) +{ + return container_of(ibfmr, struct hfi1_fmr, ibfmr); +} + +static int init_mregion(struct hfi1_mregion *mr, struct ib_pd *pd, + int count) +{ + int m, i = 0; + int rval = 0; + + m = (count + HFI1_SEGSZ - 1) / HFI1_SEGSZ; + for (; i < m; i++) { + mr->map[i] = kzalloc(sizeof(*mr->map[0]), GFP_KERNEL); + if (!mr->map[i]) + goto bail; + } + mr->mapsz = m; + init_completion(&mr->comp); + /* count returning the ptr to user */ + atomic_set(&mr->refcount, 1); + mr->pd = pd; + mr->max_segs = count; +out: + return rval; +bail: + while (i) + kfree(mr->map[--i]); + rval = -ENOMEM; + goto out; +} + +static void deinit_mregion(struct hfi1_mregion *mr) +{ + int i = mr->mapsz; + + mr->mapsz = 0; + while (i) + kfree(mr->map[--i]); +} + + +/** + * hfi1_get_dma_mr - get a DMA memory region + * @pd: protection domain for this memory region + * @acc: access flags + * + * Returns the memory region on success, otherwise returns an errno. + * Note that all DMA addresses should be created via the + * struct ib_dma_mapping_ops functions (see dma.c). + */ +struct ib_mr *hfi1_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct hfi1_mr *mr = NULL; + struct ib_mr *ret; + int rval; + + if (to_ipd(pd)->user) { + ret = ERR_PTR(-EPERM); + goto bail; + } + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + rval = init_mregion(&mr->mr, pd, 0); + if (rval) { + ret = ERR_PTR(rval); + goto bail; + } + + + rval = hfi1_alloc_lkey(&mr->mr, 1); + if (rval) { + ret = ERR_PTR(rval); + goto bail_mregion; + } + + mr->mr.access_flags = acc; + ret = &mr->ibmr; +done: + return ret; + +bail_mregion: + deinit_mregion(&mr->mr); +bail: + kfree(mr); + goto done; +} + +static struct hfi1_mr *alloc_mr(int count, struct ib_pd *pd) +{ + struct hfi1_mr *mr; + int rval = -ENOMEM; + int m; + + /* Allocate struct plus pointers to first level page tables. */ + m = (count + HFI1_SEGSZ - 1) / HFI1_SEGSZ; + mr = kzalloc(sizeof(*mr) + m * sizeof(mr->mr.map[0]), GFP_KERNEL); + if (!mr) + goto bail; + + rval = init_mregion(&mr->mr, pd, count); + if (rval) + goto bail; + /* + * ib_reg_phys_mr() will initialize mr->ibmr except for + * lkey and rkey. + */ + rval = hfi1_alloc_lkey(&mr->mr, 0); + if (rval) + goto bail_mregion; + mr->ibmr.lkey = mr->mr.lkey; + mr->ibmr.rkey = mr->mr.lkey; +done: + return mr; + +bail_mregion: + deinit_mregion(&mr->mr); +bail: + kfree(mr); + mr = ERR_PTR(rval); + goto done; +} + +/** + * hfi1_reg_phys_mr - register a physical memory region + * @pd: protection domain for this memory region + * @buffer_list: pointer to the list of physical buffers to register + * @num_phys_buf: the number of physical buffers to register + * @iova_start: the starting address passed over IB which maps to this MR + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_mr *hfi1_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, int acc, u64 *iova_start) +{ + struct hfi1_mr *mr; + int n, m, i; + struct ib_mr *ret; + + mr = alloc_mr(num_phys_buf, pd); + if (IS_ERR(mr)) { + ret = (struct ib_mr *)mr; + goto bail; + } + + mr->mr.user_base = *iova_start; + mr->mr.iova = *iova_start; + mr->mr.access_flags = acc; + + m = 0; + n = 0; + for (i = 0; i < num_phys_buf; i++) { + mr->mr.map[m]->segs[n].vaddr = (void *) buffer_list[i].addr; + mr->mr.map[m]->segs[n].length = buffer_list[i].size; + mr->mr.length += buffer_list[i].size; + n++; + if (n == HFI1_SEGSZ) { + m++; + n = 0; + } + } + + ret = &mr->ibmr; + +bail: + return ret; +} + +/** + * hfi1_reg_user_mr - register a userspace memory region + * @pd: protection domain for this memory region + * @start: starting userspace address + * @length: length of region to register + * @mr_access_flags: access flags for this memory region + * @udata: unused by the driver + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_mr *hfi1_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int mr_access_flags, + struct ib_udata *udata) +{ + struct hfi1_mr *mr; + struct ib_umem *umem; + struct scatterlist *sg; + int n, m, entry; + struct ib_mr *ret; + + if (length == 0) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + + umem = ib_umem_get(pd->uobject->context, start, length, + mr_access_flags, 0); + if (IS_ERR(umem)) + return (void *) umem; + + n = umem->nmap; + + mr = alloc_mr(n, pd); + if (IS_ERR(mr)) { + ret = (struct ib_mr *)mr; + ib_umem_release(umem); + goto bail; + } + + mr->mr.user_base = start; + mr->mr.iova = virt_addr; + mr->mr.length = length; + mr->mr.offset = ib_umem_offset(umem); + mr->mr.access_flags = mr_access_flags; + mr->umem = umem; + + if (is_power_of_2(umem->page_size)) + mr->mr.page_shift = ilog2(umem->page_size); + m = 0; + n = 0; + for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { + void *vaddr; + + vaddr = page_address(sg_page(sg)); + if (!vaddr) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + mr->mr.map[m]->segs[n].vaddr = vaddr; + mr->mr.map[m]->segs[n].length = umem->page_size; + n++; + if (n == HFI1_SEGSZ) { + m++; + n = 0; + } + } + ret = &mr->ibmr; + +bail: + return ret; +} + +/** + * hfi1_dereg_mr - unregister and free a memory region + * @ibmr: the memory region to free + * + * Returns 0 on success. + * + * Note that this is called to free MRs created by hfi1_get_dma_mr() + * or hfi1_reg_user_mr(). + */ +int hfi1_dereg_mr(struct ib_mr *ibmr) +{ + struct hfi1_mr *mr = to_imr(ibmr); + int ret = 0; + unsigned long timeout; + + hfi1_free_lkey(&mr->mr); + + hfi1_put_mr(&mr->mr); /* will set completion if last */ + timeout = wait_for_completion_timeout(&mr->mr.comp, + 5 * HZ); + if (!timeout) { + dd_dev_err( + dd_from_ibdev(mr->mr.pd->device), + "hfi1_dereg_mr timeout mr %p pd %p refcount %u\n", + mr, mr->mr.pd, atomic_read(&mr->mr.refcount)); + hfi1_get_mr(&mr->mr); + ret = -EBUSY; + goto out; + } + deinit_mregion(&mr->mr); + if (mr->umem) + ib_umem_release(mr->umem); + kfree(mr); +out: + return ret; +} + +/* + * Allocate a memory region usable with the + * IB_WR_FAST_REG_MR send work request. + * + * Return the memory region on success, otherwise return an errno. + */ +struct ib_mr *hfi1_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) +{ + struct hfi1_mr *mr; + + mr = alloc_mr(max_page_list_len, pd); + if (IS_ERR(mr)) + return (struct ib_mr *)mr; + + return &mr->ibmr; +} + +struct ib_fast_reg_page_list * +hfi1_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len) +{ + unsigned size = page_list_len * sizeof(u64); + struct ib_fast_reg_page_list *pl; + + if (size > PAGE_SIZE) + return ERR_PTR(-EINVAL); + + pl = kzalloc(sizeof(*pl), GFP_KERNEL); + if (!pl) + return ERR_PTR(-ENOMEM); + + pl->page_list = kzalloc(size, GFP_KERNEL); + if (!pl->page_list) + goto err_free; + + return pl; + +err_free: + kfree(pl); + return ERR_PTR(-ENOMEM); +} + +void hfi1_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl) +{ + kfree(pl->page_list); + kfree(pl); +} + +/** + * hfi1_alloc_fmr - allocate a fast memory region + * @pd: the protection domain for this memory region + * @mr_access_flags: access flags for this memory region + * @fmr_attr: fast memory region attributes + * + * Returns the memory region on success, otherwise returns an errno. + */ +struct ib_fmr *hfi1_alloc_fmr(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr) +{ + struct hfi1_fmr *fmr; + int m; + struct ib_fmr *ret; + int rval = -ENOMEM; + + /* Allocate struct plus pointers to first level page tables. */ + m = (fmr_attr->max_pages + HFI1_SEGSZ - 1) / HFI1_SEGSZ; + fmr = kzalloc(sizeof(*fmr) + m * sizeof(fmr->mr.map[0]), GFP_KERNEL); + if (!fmr) + goto bail; + + rval = init_mregion(&fmr->mr, pd, fmr_attr->max_pages); + if (rval) + goto bail; + + /* + * ib_alloc_fmr() will initialize fmr->ibfmr except for lkey & + * rkey. + */ + rval = hfi1_alloc_lkey(&fmr->mr, 0); + if (rval) + goto bail_mregion; + fmr->ibfmr.rkey = fmr->mr.lkey; + fmr->ibfmr.lkey = fmr->mr.lkey; + /* + * Resources are allocated but no valid mapping (RKEY can't be + * used). + */ + fmr->mr.access_flags = mr_access_flags; + fmr->mr.max_segs = fmr_attr->max_pages; + fmr->mr.page_shift = fmr_attr->page_shift; + + ret = &fmr->ibfmr; +done: + return ret; + +bail_mregion: + deinit_mregion(&fmr->mr); +bail: + kfree(fmr); + ret = ERR_PTR(rval); + goto done; +} + +/** + * hfi1_map_phys_fmr - set up a fast memory region + * @ibmfr: the fast memory region to set up + * @page_list: the list of pages to associate with the fast memory region + * @list_len: the number of pages to associate with the fast memory region + * @iova: the virtual address of the start of the fast memory region + * + * This may be called from interrupt context. + */ + +int hfi1_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova) +{ + struct hfi1_fmr *fmr = to_ifmr(ibfmr); + struct hfi1_lkey_table *rkt; + unsigned long flags; + int m, n, i; + u32 ps; + int ret; + + i = atomic_read(&fmr->mr.refcount); + if (i > 2) + return -EBUSY; + + if (list_len > fmr->mr.max_segs) { + ret = -EINVAL; + goto bail; + } + rkt = &to_idev(ibfmr->device)->lk_table; + spin_lock_irqsave(&rkt->lock, flags); + fmr->mr.user_base = iova; + fmr->mr.iova = iova; + ps = 1 << fmr->mr.page_shift; + fmr->mr.length = list_len * ps; + m = 0; + n = 0; + for (i = 0; i < list_len; i++) { + fmr->mr.map[m]->segs[n].vaddr = (void *) page_list[i]; + fmr->mr.map[m]->segs[n].length = ps; + if (++n == HFI1_SEGSZ) { + m++; + n = 0; + } + } + spin_unlock_irqrestore(&rkt->lock, flags); + ret = 0; + +bail: + return ret; +} + +/** + * hfi1_unmap_fmr - unmap fast memory regions + * @fmr_list: the list of fast memory regions to unmap + * + * Returns 0 on success. + */ +int hfi1_unmap_fmr(struct list_head *fmr_list) +{ + struct hfi1_fmr *fmr; + struct hfi1_lkey_table *rkt; + unsigned long flags; + + list_for_each_entry(fmr, fmr_list, ibfmr.list) { + rkt = &to_idev(fmr->ibfmr.device)->lk_table; + spin_lock_irqsave(&rkt->lock, flags); + fmr->mr.user_base = 0; + fmr->mr.iova = 0; + fmr->mr.length = 0; + spin_unlock_irqrestore(&rkt->lock, flags); + } + return 0; +} + +/** + * hfi1_dealloc_fmr - deallocate a fast memory region + * @ibfmr: the fast memory region to deallocate + * + * Returns 0 on success. + */ +int hfi1_dealloc_fmr(struct ib_fmr *ibfmr) +{ + struct hfi1_fmr *fmr = to_ifmr(ibfmr); + int ret = 0; + unsigned long timeout; + + hfi1_free_lkey(&fmr->mr); + hfi1_put_mr(&fmr->mr); /* will set completion if last */ + timeout = wait_for_completion_timeout(&fmr->mr.comp, + 5 * HZ); + if (!timeout) { + hfi1_get_mr(&fmr->mr); + ret = -EBUSY; + goto out; + } + deinit_mregion(&fmr->mr); + kfree(fmr); +out: + return ret; +} diff --git a/drivers/staging/rdma/hfi1/opa_compat.h b/drivers/staging/rdma/hfi1/opa_compat.h new file mode 100644 index 0000000000000..f64eec1c29519 --- /dev/null +++ b/drivers/staging/rdma/hfi1/opa_compat.h @@ -0,0 +1,129 @@ +#ifndef _LINUX_H +#define _LINUX_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +/* + * This header file is for OPA-specific definitions which are + * required by the HFI driver, and which aren't yet in the Linux + * IB core. We'll collect these all here, then merge them into + * the kernel when that's convenient. + */ + +/* OPA SMA attribute IDs */ +#define OPA_ATTRIB_ID_CONGESTION_INFO cpu_to_be16(0x008b) +#define OPA_ATTRIB_ID_HFI_CONGESTION_LOG cpu_to_be16(0x008f) +#define OPA_ATTRIB_ID_HFI_CONGESTION_SETTING cpu_to_be16(0x0090) +#define OPA_ATTRIB_ID_CONGESTION_CONTROL_TABLE cpu_to_be16(0x0091) + +/* OPA PMA attribute IDs */ +#define OPA_PM_ATTRIB_ID_PORT_STATUS cpu_to_be16(0x0040) +#define OPA_PM_ATTRIB_ID_CLEAR_PORT_STATUS cpu_to_be16(0x0041) +#define OPA_PM_ATTRIB_ID_DATA_PORT_COUNTERS cpu_to_be16(0x0042) +#define OPA_PM_ATTRIB_ID_ERROR_PORT_COUNTERS cpu_to_be16(0x0043) +#define OPA_PM_ATTRIB_ID_ERROR_INFO cpu_to_be16(0x0044) + +/* OPA status codes */ +#define OPA_PM_STATUS_REQUEST_TOO_LARGE cpu_to_be16(0x100) + +static inline u8 port_states_to_logical_state(struct opa_port_states *ps) +{ + return ps->portphysstate_portstate & OPA_PI_MASK_PORT_STATE; +} + +static inline u8 port_states_to_phys_state(struct opa_port_states *ps) +{ + return ((ps->portphysstate_portstate & + OPA_PI_MASK_PORT_PHYSICAL_STATE) >> 4) & 0xf; +} + +/* + * OPA port physical states + * IB Volume 1, Table 146 PortInfo/IB Volume 2 Section 5.4.2(1) PortPhysState + * values. + * + * When writing, only values 0-3 are valid, other values are ignored. + * When reading, 0 is reserved. + * + * Returned by the ibphys_portstate() routine. + */ +enum opa_port_phys_state { + IB_PORTPHYSSTATE_NOP = 0, + /* 1 is reserved */ + IB_PORTPHYSSTATE_POLLING = 2, + IB_PORTPHYSSTATE_DISABLED = 3, + IB_PORTPHYSSTATE_TRAINING = 4, + IB_PORTPHYSSTATE_LINKUP = 5, + IB_PORTPHYSSTATE_LINK_ERROR_RECOVERY = 6, + IB_PORTPHYSSTATE_PHY_TEST = 7, + /* 8 is reserved */ + OPA_PORTPHYSSTATE_OFFLINE = 9, + OPA_PORTPHYSSTATE_GANGED = 10, + OPA_PORTPHYSSTATE_TEST = 11, + OPA_PORTPHYSSTATE_MAX = 11, + /* values 12-15 are reserved/ignored */ +}; + +/* OPA_PORT_TYPE_* definitions - these belong in opa_port_info.h */ +#define OPA_PORT_TYPE_UNKNOWN 0 +#define OPA_PORT_TYPE_DISCONNECTED 1 +/* port is not currently usable, CableInfo not available */ +#define OPA_PORT_TYPE_FIXED 2 +/* A fixed backplane port in a director class switch. All OPA ASICS */ +#define OPA_PORT_TYPE_VARIABLE 3 +/* A backplane port in a blade system, possibly mixed configuration */ +#define OPA_PORT_TYPE_STANDARD 4 +/* implies a SFF-8636 defined format for CableInfo (QSFP) */ +#define OPA_PORT_TYPE_SI_PHOTONICS 5 +/* A silicon photonics module implies TBD defined format for CableInfo + * as defined by Intel SFO group */ +/* 6 - 15 are reserved */ + +#endif /* _LINUX_H */ diff --git a/drivers/staging/rdma/hfi1/pcie.c b/drivers/staging/rdma/hfi1/pcie.c new file mode 100644 index 0000000000000..ac5653c0f65e0 --- /dev/null +++ b/drivers/staging/rdma/hfi1/pcie.c @@ -0,0 +1,1253 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "chip_registers.h" + +/* link speed vector for Gen3 speed - not in Linux headers */ +#define GEN1_SPEED_VECTOR 0x1 +#define GEN2_SPEED_VECTOR 0x2 +#define GEN3_SPEED_VECTOR 0x3 + +/* + * This file contains PCIe utility routines. + */ + +/* + * Code to adjust PCIe capabilities. + */ +static void tune_pcie_caps(struct hfi1_devdata *); + +/* + * Do all the common PCIe setup and initialization. + * devdata is not yet allocated, and is not allocated until after this + * routine returns success. Therefore dd_dev_err() can't be used for error + * printing. + */ +int hfi1_pcie_init(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + int ret; + + ret = pci_enable_device(pdev); + if (ret) { + /* + * This can happen (in theory) iff: + * We did a chip reset, and then failed to reprogram the + * BAR, or the chip reset due to an internal error. We then + * unloaded the driver and reloaded it. + * + * Both reset cases set the BAR back to initial state. For + * the latter case, the AER sticky error bit at offset 0x718 + * should be set, but the Linux kernel doesn't yet know + * about that, it appears. If the original BAR was retained + * in the kernel data structures, this may be OK. + */ + hfi1_early_err(&pdev->dev, "pci enable failed: error %d\n", + -ret); + goto done; + } + + ret = pci_request_regions(pdev, DRIVER_NAME); + if (ret) { + hfi1_early_err(&pdev->dev, + "pci_request_regions fails: err %d\n", -ret); + goto bail; + } + + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) { + /* + * If the 64 bit setup fails, try 32 bit. Some systems + * do not setup 64 bit maps on systems with 2GB or less + * memory installed. + */ + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret) { + hfi1_early_err(&pdev->dev, + "Unable to set DMA mask: %d\n", ret); + goto bail; + } + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + } else + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret) { + hfi1_early_err(&pdev->dev, + "Unable to set DMA consistent mask: %d\n", ret); + goto bail; + } + + pci_set_master(pdev); + ret = pci_enable_pcie_error_reporting(pdev); + if (ret) { + hfi1_early_err(&pdev->dev, + "Unable to enable pcie error reporting: %d\n", + ret); + ret = 0; + } + goto done; + +bail: + hfi1_pcie_cleanup(pdev); +done: + return ret; +} + +/* + * Clean what was done in hfi1_pcie_init() + */ +void hfi1_pcie_cleanup(struct pci_dev *pdev) +{ + pci_disable_device(pdev); + /* + * Release regions should be called after the disable. OK to + * call if request regions has not been called or failed. + */ + pci_release_regions(pdev); +} + +/* + * Do remaining PCIe setup, once dd is allocated, and save away + * fields required to re-initialize after a chip reset, or for + * various other purposes + */ +int hfi1_pcie_ddinit(struct hfi1_devdata *dd, struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + unsigned long len; + resource_size_t addr; + + dd->pcidev = pdev; + pci_set_drvdata(pdev, dd); + + addr = pci_resource_start(pdev, 0); + len = pci_resource_len(pdev, 0); + + /* + * The TXE PIO buffers are at the tail end of the chip space. + * Cut them off and map them separately. + */ + + /* sanity check vs expectations */ + if (len != TXE_PIO_SEND + TXE_PIO_SIZE) { + dd_dev_err(dd, "chip PIO range does not match\n"); + return -EINVAL; + } + + dd->kregbase = ioremap_nocache(addr, TXE_PIO_SEND); + if (!dd->kregbase) + return -ENOMEM; + + dd->piobase = ioremap_wc(addr + TXE_PIO_SEND, TXE_PIO_SIZE); + if (!dd->piobase) { + iounmap(dd->kregbase); + return -ENOMEM; + } + + dd->flags |= HFI1_PRESENT; /* now register routines work */ + + dd->kregend = dd->kregbase + TXE_PIO_SEND; + dd->physaddr = addr; /* used for io_remap, etc. */ + + /* + * Re-map the chip's RcvArray as write-combining to allow us + * to write an entire cacheline worth of entries in one shot. + * If this re-map fails, just continue - the RcvArray programming + * function will handle both cases. + */ + dd->chip_rcv_array_count = read_csr(dd, RCV_ARRAY_CNT); + dd->rcvarray_wc = ioremap_wc(addr + RCV_ARRAY, + dd->chip_rcv_array_count * 8); + dd_dev_info(dd, "WC Remapped RcvArray: %p\n", dd->rcvarray_wc); + /* + * Save BARs and command to rewrite after device reset. + */ + dd->pcibar0 = addr; + dd->pcibar1 = addr >> 32; + pci_read_config_dword(dd->pcidev, PCI_ROM_ADDRESS, &dd->pci_rom); + pci_read_config_word(dd->pcidev, PCI_COMMAND, &dd->pci_command); + pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL, &dd->pcie_devctl); + pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKCTL, &dd->pcie_lnkctl); + pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVCTL2, + &dd->pcie_devctl2); + pci_read_config_dword(dd->pcidev, PCI_CFG_MSIX0, &dd->pci_msix0); + pci_read_config_dword(dd->pcidev, PCIE_CFG_SPCIE1, + &dd->pci_lnkctl3); + pci_read_config_dword(dd->pcidev, PCIE_CFG_TPH2, &dd->pci_tph2); + + return 0; +} + +/* + * Do PCIe cleanup related to dd, after chip-specific cleanup, etc. Just prior + * to releasing the dd memory. + * Void because all of the core pcie cleanup functions are void. + */ +void hfi1_pcie_ddcleanup(struct hfi1_devdata *dd) +{ + u64 __iomem *base = (void __iomem *) dd->kregbase; + + dd->flags &= ~HFI1_PRESENT; + dd->kregbase = NULL; + iounmap(base); + if (dd->rcvarray_wc) + iounmap(dd->rcvarray_wc); + if (dd->piobase) + iounmap(dd->piobase); + + pci_set_drvdata(dd->pcidev, NULL); +} + +/* + * Do a Function Level Reset (FLR) on the device. + * Based on static function drivers/pci/pci.c:pcie_flr(). + */ +void hfi1_pcie_flr(struct hfi1_devdata *dd) +{ + int i; + u16 status; + + /* no need to check for the capability - we know the device has it */ + + /* wait for Transaction Pending bit to clear, at most a few ms */ + for (i = 0; i < 4; i++) { + if (i) + msleep((1 << (i - 1)) * 100); + + pcie_capability_read_word(dd->pcidev, PCI_EXP_DEVSTA, &status); + if (!(status & PCI_EXP_DEVSTA_TRPND)) + goto clear; + } + + dd_dev_err(dd, "Transaction Pending bit is not clearing, proceeding with reset anyway\n"); + +clear: + pcie_capability_set_word(dd->pcidev, PCI_EXP_DEVCTL, + PCI_EXP_DEVCTL_BCR_FLR); + /* PCIe spec requires the function to be back within 100ms */ + msleep(100); +} + +static void msix_setup(struct hfi1_devdata *dd, int pos, u32 *msixcnt, + struct hfi1_msix_entry *hfi1_msix_entry) +{ + int ret; + int nvec = *msixcnt; + struct msix_entry *msix_entry; + int i; + + /* We can't pass hfi1_msix_entry array to msix_setup + * so use a dummy msix_entry array and copy the allocated + * irq back to the hfi1_msix_entry array. */ + msix_entry = kmalloc_array(nvec, sizeof(*msix_entry), GFP_KERNEL); + if (!msix_entry) { + ret = -ENOMEM; + goto do_intx; + } + + for (i = 0; i < nvec; i++) + msix_entry[i] = hfi1_msix_entry[i].msix; + + ret = pci_enable_msix_range(dd->pcidev, msix_entry, 1, nvec); + if (ret < 0) + goto free_msix_entry; + nvec = ret; + + for (i = 0; i < nvec; i++) + hfi1_msix_entry[i].msix = msix_entry[i]; + + kfree(msix_entry); + *msixcnt = nvec; + return; + +free_msix_entry: + kfree(msix_entry); + +do_intx: + dd_dev_err(dd, "pci_enable_msix_range %d vectors failed: %d, falling back to INTx\n", + nvec, ret); + *msixcnt = 0; + hfi1_enable_intx(dd->pcidev); + +} + +/* return the PCIe link speed from the given link status */ +static u32 extract_speed(u16 linkstat) +{ + u32 speed; + + switch (linkstat & PCI_EXP_LNKSTA_CLS) { + default: /* not defined, assume Gen1 */ + case PCI_EXP_LNKSTA_CLS_2_5GB: + speed = 2500; /* Gen 1, 2.5GHz */ + break; + case PCI_EXP_LNKSTA_CLS_5_0GB: + speed = 5000; /* Gen 2, 5GHz */ + break; + case GEN3_SPEED_VECTOR: + speed = 8000; /* Gen 3, 8GHz */ + break; + } + return speed; +} + +/* return the PCIe link speed from the given link status */ +static u32 extract_width(u16 linkstat) +{ + return (linkstat & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT; +} + +/* read the link status and set dd->{lbus_width,lbus_speed,lbus_info} */ +static void update_lbus_info(struct hfi1_devdata *dd) +{ + u16 linkstat; + + pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKSTA, &linkstat); + dd->lbus_width = extract_width(linkstat); + dd->lbus_speed = extract_speed(linkstat); + snprintf(dd->lbus_info, sizeof(dd->lbus_info), + "PCIe,%uMHz,x%u", dd->lbus_speed, dd->lbus_width); +} + +/* + * Read in the current PCIe link width and speed. Find if the link is + * Gen3 capable. + */ +int pcie_speeds(struct hfi1_devdata *dd) +{ + u32 linkcap; + + if (!pci_is_pcie(dd->pcidev)) { + dd_dev_err(dd, "Can't find PCI Express capability!\n"); + return -EINVAL; + } + + /* find if our max speed is Gen3 and parent supports Gen3 speeds */ + dd->link_gen3_capable = 1; + + pcie_capability_read_dword(dd->pcidev, PCI_EXP_LNKCAP, &linkcap); + if ((linkcap & PCI_EXP_LNKCAP_SLS) != GEN3_SPEED_VECTOR) { + dd_dev_info(dd, + "This HFI is not Gen3 capable, max speed 0x%x, need 0x3\n", + linkcap & PCI_EXP_LNKCAP_SLS); + dd->link_gen3_capable = 0; + } + + /* + * bus->max_bus_speed is set from the bridge's linkcap Max Link Speed + */ + if (dd->pcidev->bus->max_bus_speed != PCIE_SPEED_8_0GT) { + dd_dev_info(dd, "Parent PCIe bridge does not support Gen3\n"); + dd->link_gen3_capable = 0; + } + + /* obtain the link width and current speed */ + update_lbus_info(dd); + + /* check against expected pcie width and complain if "wrong" */ + if (dd->lbus_width < 16) + dd_dev_err(dd, "PCIe width %u (x16 HFI)\n", dd->lbus_width); + + return 0; +} + +/* + * Returns in *nent: + * - actual number of interrupts allocated + * - 0 if fell back to INTx. + */ +void request_msix(struct hfi1_devdata *dd, u32 *nent, + struct hfi1_msix_entry *entry) +{ + int pos; + + pos = dd->pcidev->msix_cap; + if (*nent && pos) { + msix_setup(dd, pos, nent, entry); + /* did it, either MSI-X or INTx */ + } else { + *nent = 0; + hfi1_enable_intx(dd->pcidev); + } + + tune_pcie_caps(dd); +} + +/* + * Disable MSI-X. + */ +void hfi1_nomsix(struct hfi1_devdata *dd) +{ + pci_disable_msix(dd->pcidev); +} + +void hfi1_enable_intx(struct pci_dev *pdev) +{ + /* first, turn on INTx */ + pci_intx(pdev, 1); + /* then turn off MSI-X */ + pci_disable_msix(pdev); +} + +/* restore command and BARs after a reset has wiped them out */ +void restore_pci_variables(struct hfi1_devdata *dd) +{ + pci_write_config_word(dd->pcidev, PCI_COMMAND, dd->pci_command); + pci_write_config_dword(dd->pcidev, + PCI_BASE_ADDRESS_0, dd->pcibar0); + pci_write_config_dword(dd->pcidev, + PCI_BASE_ADDRESS_1, dd->pcibar1); + pci_write_config_dword(dd->pcidev, + PCI_ROM_ADDRESS, dd->pci_rom); + pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL, dd->pcie_devctl); + pcie_capability_write_word(dd->pcidev, PCI_EXP_LNKCTL, dd->pcie_lnkctl); + pcie_capability_write_word(dd->pcidev, PCI_EXP_DEVCTL2, + dd->pcie_devctl2); + pci_write_config_dword(dd->pcidev, PCI_CFG_MSIX0, dd->pci_msix0); + pci_write_config_dword(dd->pcidev, PCIE_CFG_SPCIE1, + dd->pci_lnkctl3); + pci_write_config_dword(dd->pcidev, PCIE_CFG_TPH2, dd->pci_tph2); +} + + +/* + * BIOS may not set PCIe bus-utilization parameters for best performance. + * Check and optionally adjust them to maximize our throughput. + */ +static int hfi1_pcie_caps; +module_param_named(pcie_caps, hfi1_pcie_caps, int, S_IRUGO); +MODULE_PARM_DESC(pcie_caps, "Max PCIe tuning: Payload (0..3), ReadReq (4..7)"); + +static void tune_pcie_caps(struct hfi1_devdata *dd) +{ + struct pci_dev *parent; + u16 rc_mpss, rc_mps, ep_mpss, ep_mps; + u16 rc_mrrs, ep_mrrs, max_mrrs; + + /* Find out supported and configured values for parent (root) */ + parent = dd->pcidev->bus->self; + if (!pci_is_root_bus(parent->bus)) { + dd_dev_info(dd, "Parent not root\n"); + return; + } + + if (!pci_is_pcie(parent) || !pci_is_pcie(dd->pcidev)) + return; + rc_mpss = parent->pcie_mpss; + rc_mps = ffs(pcie_get_mps(parent)) - 8; + /* Find out supported and configured values for endpoint (us) */ + ep_mpss = dd->pcidev->pcie_mpss; + ep_mps = ffs(pcie_get_mps(dd->pcidev)) - 8; + + /* Find max payload supported by root, endpoint */ + if (rc_mpss > ep_mpss) + rc_mpss = ep_mpss; + + /* If Supported greater than limit in module param, limit it */ + if (rc_mpss > (hfi1_pcie_caps & 7)) + rc_mpss = hfi1_pcie_caps & 7; + /* If less than (allowed, supported), bump root payload */ + if (rc_mpss > rc_mps) { + rc_mps = rc_mpss; + pcie_set_mps(parent, 128 << rc_mps); + } + /* If less than (allowed, supported), bump endpoint payload */ + if (rc_mpss > ep_mps) { + ep_mps = rc_mpss; + pcie_set_mps(dd->pcidev, 128 << ep_mps); + } + + /* + * Now the Read Request size. + * No field for max supported, but PCIe spec limits it to 4096, + * which is code '5' (log2(4096) - 7) + */ + max_mrrs = 5; + if (max_mrrs > ((hfi1_pcie_caps >> 4) & 7)) + max_mrrs = (hfi1_pcie_caps >> 4) & 7; + + max_mrrs = 128 << max_mrrs; + rc_mrrs = pcie_get_readrq(parent); + ep_mrrs = pcie_get_readrq(dd->pcidev); + + if (max_mrrs > rc_mrrs) { + rc_mrrs = max_mrrs; + pcie_set_readrq(parent, rc_mrrs); + } + if (max_mrrs > ep_mrrs) { + ep_mrrs = max_mrrs; + pcie_set_readrq(dd->pcidev, ep_mrrs); + } +} +/* End of PCIe capability tuning */ + +/* + * From here through hfi1_pci_err_handler definition is invoked via + * PCI error infrastructure, registered via pci + */ +static pci_ers_result_t +pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED; + + switch (state) { + case pci_channel_io_normal: + dd_dev_info(dd, "State Normal, ignoring\n"); + break; + + case pci_channel_io_frozen: + dd_dev_info(dd, "State Frozen, requesting reset\n"); + pci_disable_device(pdev); + ret = PCI_ERS_RESULT_NEED_RESET; + break; + + case pci_channel_io_perm_failure: + if (dd) { + dd_dev_info(dd, "State Permanent Failure, disabling\n"); + /* no more register accesses! */ + dd->flags &= ~HFI1_PRESENT; + hfi1_disable_after_error(dd); + } + /* else early, or other problem */ + ret = PCI_ERS_RESULT_DISCONNECT; + break; + + default: /* shouldn't happen */ + dd_dev_info(dd, "HFI1 PCI errors detected (state %d)\n", + state); + break; + } + return ret; +} + +static pci_ers_result_t +pci_mmio_enabled(struct pci_dev *pdev) +{ + u64 words = 0U; + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + pci_ers_result_t ret = PCI_ERS_RESULT_RECOVERED; + + if (dd && dd->pport) { + words = read_port_cntr(dd->pport, C_RX_WORDS, CNTR_INVALID_VL); + if (words == ~0ULL) + ret = PCI_ERS_RESULT_NEED_RESET; + dd_dev_info(dd, + "HFI1 mmio_enabled function called, read wordscntr %Lx, returning %d\n", + words, ret); + } + return ret; +} + +static pci_ers_result_t +pci_slot_reset(struct pci_dev *pdev) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + + dd_dev_info(dd, "HFI1 slot_reset function called, ignored\n"); + return PCI_ERS_RESULT_CAN_RECOVER; +} + +static pci_ers_result_t +pci_link_reset(struct pci_dev *pdev) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + + dd_dev_info(dd, "HFI1 link_reset function called, ignored\n"); + return PCI_ERS_RESULT_CAN_RECOVER; +} + +static void +pci_resume(struct pci_dev *pdev) +{ + struct hfi1_devdata *dd = pci_get_drvdata(pdev); + + dd_dev_info(dd, "HFI1 resume function called\n"); + pci_cleanup_aer_uncorrect_error_status(pdev); + /* + * Running jobs will fail, since it's asynchronous + * unlike sysfs-requested reset. Better than + * doing nothing. + */ + hfi1_init(dd, 1); /* same as re-init after reset */ +} + +const struct pci_error_handlers hfi1_pci_err_handler = { + .error_detected = pci_error_detected, + .mmio_enabled = pci_mmio_enabled, + .link_reset = pci_link_reset, + .slot_reset = pci_slot_reset, + .resume = pci_resume, +}; + +/*============================================================================*/ +/* PCIe Gen3 support */ + +/* + * This code is separated out because it is expected to be removed in the + * final shipping product. If not, then it will be revisited and items + * will be moved to more standard locations. + */ + +/* ASIC_PCI_SD_HOST_STATUS.FW_DNLD_STS field values */ +#define DL_STATUS_HFI0 0x1 /* hfi0 firmware download complete */ +#define DL_STATUS_HFI1 0x2 /* hfi1 firmware download complete */ +#define DL_STATUS_BOTH 0x3 /* hfi0 and hfi1 firmware download complete */ + +/* ASIC_PCI_SD_HOST_STATUS.FW_DNLD_ERR field values */ +#define DL_ERR_NONE 0x0 /* no error */ +#define DL_ERR_SWAP_PARITY 0x1 /* parity error in SerDes interrupt */ + /* or response data */ +#define DL_ERR_DISABLED 0x2 /* hfi disabled */ +#define DL_ERR_SECURITY 0x3 /* security check failed */ +#define DL_ERR_SBUS 0x4 /* SBus status error */ +#define DL_ERR_XFR_PARITY 0x5 /* parity error during ROM transfer*/ + +/* gasket block secondary bus reset delay */ +#define SBR_DELAY_US 200000 /* 200ms */ + +/* mask for PCIe capability register lnkctl2 target link speed */ +#define LNKCTL2_TARGET_LINK_SPEED_MASK 0xf + +static uint pcie_target = 3; +module_param(pcie_target, uint, S_IRUGO); +MODULE_PARM_DESC(pcie_target, "PCIe target speed (0 skip, 1-3 Gen1-3)"); + +static uint pcie_force; +module_param(pcie_force, uint, S_IRUGO); +MODULE_PARM_DESC(pcie_force, "Force driver to do a PCIe firmware download even if already at target speed"); + +static uint pcie_retry = 5; +module_param(pcie_retry, uint, S_IRUGO); +MODULE_PARM_DESC(pcie_retry, "Driver will try this many times to reach requested speed"); + +#define UNSET_PSET 255 +#define DEFAULT_DISCRETE_PSET 2 /* discrete HFI */ +#define DEFAULT_MCP_PSET 4 /* MCP HFI */ +static uint pcie_pset = UNSET_PSET; +module_param(pcie_pset, uint, S_IRUGO); +MODULE_PARM_DESC(pcie_pset, "PCIe Eq Pset value to use, range is 0-10"); + +/* equalization columns */ +#define PREC 0 +#define ATTN 1 +#define POST 2 + +/* discrete silicon preliminary equalization values */ +static const u8 discrete_preliminary_eq[11][3] = { + /* prec attn post */ + { 0x00, 0x00, 0x12 }, /* p0 */ + { 0x00, 0x00, 0x0c }, /* p1 */ + { 0x00, 0x00, 0x0f }, /* p2 */ + { 0x00, 0x00, 0x09 }, /* p3 */ + { 0x00, 0x00, 0x00 }, /* p4 */ + { 0x06, 0x00, 0x00 }, /* p5 */ + { 0x09, 0x00, 0x00 }, /* p6 */ + { 0x06, 0x00, 0x0f }, /* p7 */ + { 0x09, 0x00, 0x09 }, /* p8 */ + { 0x0c, 0x00, 0x00 }, /* p9 */ + { 0x00, 0x00, 0x18 }, /* p10 */ +}; + +/* integrated silicon preliminary equalization values */ +static const u8 integrated_preliminary_eq[11][3] = { + /* prec attn post */ + { 0x00, 0x1e, 0x07 }, /* p0 */ + { 0x00, 0x1e, 0x05 }, /* p1 */ + { 0x00, 0x1e, 0x06 }, /* p2 */ + { 0x00, 0x1e, 0x04 }, /* p3 */ + { 0x00, 0x1e, 0x00 }, /* p4 */ + { 0x03, 0x1e, 0x00 }, /* p5 */ + { 0x04, 0x1e, 0x00 }, /* p6 */ + { 0x03, 0x1e, 0x06 }, /* p7 */ + { 0x03, 0x1e, 0x04 }, /* p8 */ + { 0x05, 0x1e, 0x00 }, /* p9 */ + { 0x00, 0x1e, 0x0a }, /* p10 */ +}; + +/* helper to format the value to write to hardware */ +#define eq_value(pre, curr, post) \ + ((((u32)(pre)) << \ + PCIE_CFG_REG_PL102_GEN3_EQ_PRE_CURSOR_PSET_SHIFT) \ + | (((u32)(curr)) << PCIE_CFG_REG_PL102_GEN3_EQ_CURSOR_PSET_SHIFT) \ + | (((u32)(post)) << \ + PCIE_CFG_REG_PL102_GEN3_EQ_POST_CURSOR_PSET_SHIFT)) + +/* + * Load the given EQ preset table into the PCIe hardware. + */ +static int load_eq_table(struct hfi1_devdata *dd, const u8 eq[11][3], u8 fs, + u8 div) +{ + struct pci_dev *pdev = dd->pcidev; + u32 hit_error = 0; + u32 violation; + u32 i; + u8 c_minus1, c0, c_plus1; + + for (i = 0; i < 11; i++) { + /* set index */ + pci_write_config_dword(pdev, PCIE_CFG_REG_PL103, i); + /* write the value */ + c_minus1 = eq[i][PREC] / div; + c0 = fs - (eq[i][PREC] / div) - (eq[i][POST] / div); + c_plus1 = eq[i][POST] / div; + pci_write_config_dword(pdev, PCIE_CFG_REG_PL102, + eq_value(c_minus1, c0, c_plus1)); + /* check if these coefficients violate EQ rules */ + pci_read_config_dword(dd->pcidev, PCIE_CFG_REG_PL105, + &violation); + if (violation + & PCIE_CFG_REG_PL105_GEN3_EQ_VIOLATE_COEF_RULES_SMASK){ + if (hit_error == 0) { + dd_dev_err(dd, + "Gen3 EQ Table Coefficient rule violations\n"); + dd_dev_err(dd, " prec attn post\n"); + } + dd_dev_err(dd, " p%02d: %02x %02x %02x\n", + i, (u32)eq[i][0], (u32)eq[i][1], (u32)eq[i][2]); + dd_dev_err(dd, " %02x %02x %02x\n", + (u32)c_minus1, (u32)c0, (u32)c_plus1); + hit_error = 1; + } + } + if (hit_error) + return -EINVAL; + return 0; +} + +/* + * Steps to be done after the PCIe firmware is downloaded and + * before the SBR for the Pcie Gen3. + * The hardware mutex is already being held. + */ +static void pcie_post_steps(struct hfi1_devdata *dd) +{ + int i; + + set_sbus_fast_mode(dd); + /* + * Write to the PCIe PCSes to set the G3_LOCKED_NEXT bits to 1. + * This avoids a spurious framing error that can otherwise be + * generated by the MAC layer. + * + * Use individual addresses since no broadcast is set up. + */ + for (i = 0; i < NUM_PCIE_SERDES; i++) { + sbus_request(dd, pcie_pcs_addrs[dd->hfi1_id][i], + 0x03, WRITE_SBUS_RECEIVER, 0x00022132); + } + + clear_sbus_fast_mode(dd); +} + +/* + * Trigger a secondary bus reset (SBR) on ourselves using our parent. + * + * Based on pci_parent_bus_reset() which is not exported by the + * kernel core. + */ +static int trigger_sbr(struct hfi1_devdata *dd) +{ + struct pci_dev *dev = dd->pcidev; + struct pci_dev *pdev; + + /* need a parent */ + if (!dev->bus->self) { + dd_dev_err(dd, "%s: no parent device\n", __func__); + return -ENOTTY; + } + + /* should not be anyone else on the bus */ + list_for_each_entry(pdev, &dev->bus->devices, bus_list) + if (pdev != dev) { + dd_dev_err(dd, + "%s: another device is on the same bus\n", + __func__); + return -ENOTTY; + } + + /* + * A secondary bus reset (SBR) issues a hot reset to our device. + * The following routine does a 1s wait after the reset is dropped + * per PCI Trhfa (recovery time). PCIe 3.0 section 6.6.1 - + * Conventional Reset, paragraph 3, line 35 also says that a 1s + * delay after a reset is required. Per spec requirements, + * the link is either working or not after that point. + */ + pci_reset_bridge_secondary_bus(dev->bus->self); + + return 0; +} + +/* + * Write the given gasket interrupt register. + */ +static void write_gasket_interrupt(struct hfi1_devdata *dd, int index, + u16 code, u16 data) +{ + write_csr(dd, ASIC_PCIE_SD_INTRPT_LIST + (index * 8), + (((u64)code << ASIC_PCIE_SD_INTRPT_LIST_INTRPT_CODE_SHIFT) + |((u64)data << ASIC_PCIE_SD_INTRPT_LIST_INTRPT_DATA_SHIFT))); +} + +/* + * Tell the gasket logic how to react to the reset. + */ +static void arm_gasket_logic(struct hfi1_devdata *dd) +{ + u64 reg; + + reg = (((u64)1 << dd->hfi1_id) + << ASIC_PCIE_SD_HOST_CMD_INTRPT_CMD_SHIFT) + | ((u64)pcie_serdes_broadcast[dd->hfi1_id] + << ASIC_PCIE_SD_HOST_CMD_SBUS_RCVR_ADDR_SHIFT + | ASIC_PCIE_SD_HOST_CMD_SBR_MODE_SMASK + | ((u64)SBR_DELAY_US & ASIC_PCIE_SD_HOST_CMD_TIMER_MASK) + << ASIC_PCIE_SD_HOST_CMD_TIMER_SHIFT + ); + write_csr(dd, ASIC_PCIE_SD_HOST_CMD, reg); + /* read back to push the write */ + read_csr(dd, ASIC_PCIE_SD_HOST_CMD); +} + +/* + * Do all the steps needed to transition the PCIe link to Gen3 speed. + */ +int do_pcie_gen3_transition(struct hfi1_devdata *dd) +{ + struct pci_dev *parent; + u64 fw_ctrl; + u64 reg, therm; + u32 reg32, fs, lf; + u32 status, err; + int ret; + int do_retry, retry_count = 0; + uint default_pset; + u16 target_vector, target_speed; + u16 lnkctl, lnkctl2, vendor; + u8 nsbr = 1; + u8 div; + const u8 (*eq)[3]; + int return_error = 0; + + /* PCIe Gen3 is for the ASIC only */ + if (dd->icode != ICODE_RTL_SILICON) + return 0; + + if (pcie_target == 1) { /* target Gen1 */ + target_vector = GEN1_SPEED_VECTOR; + target_speed = 2500; + } else if (pcie_target == 2) { /* target Gen2 */ + target_vector = GEN2_SPEED_VECTOR; + target_speed = 5000; + } else if (pcie_target == 3) { /* target Gen3 */ + target_vector = GEN3_SPEED_VECTOR; + target_speed = 8000; + } else { + /* off or invalid target - skip */ + dd_dev_info(dd, "%s: Skipping PCIe transition\n", __func__); + return 0; + } + + /* if already at target speed, done (unless forced) */ + if (dd->lbus_speed == target_speed) { + dd_dev_info(dd, "%s: PCIe already at gen%d, %s\n", __func__, + pcie_target, + pcie_force ? "re-doing anyway" : "skipping"); + if (!pcie_force) + return 0; + } + + /* + * A0 needs an additional SBR + */ + if (is_a0(dd)) + nsbr++; + + /* + * Do the Gen3 transition. Steps are those of the PCIe Gen3 + * recipe. + */ + + /* step 1: pcie link working in gen1/gen2 */ + + /* step 2: if either side is not capable of Gen3, done */ + if (pcie_target == 3 && !dd->link_gen3_capable) { + dd_dev_err(dd, "The PCIe link is not Gen3 capable\n"); + ret = -ENOSYS; + goto done_no_mutex; + } + + /* hold the HW mutex across the firmware download and SBR */ + ret = acquire_hw_mutex(dd); + if (ret) + return ret; + + /* make sure thermal polling is not causing interrupts */ + therm = read_csr(dd, ASIC_CFG_THERM_POLL_EN); + if (therm) { + write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x0); + msleep(100); + dd_dev_info(dd, "%s: Disabled therm polling\n", + __func__); + } + + /* step 3: download SBus Master firmware */ + /* step 4: download PCIe Gen3 SerDes firmware */ +retry: + dd_dev_info(dd, "%s: downloading firmware\n", __func__); + ret = load_pcie_firmware(dd); + if (ret) + goto done; + + /* step 5: set up device parameter settings */ + dd_dev_info(dd, "%s: setting PCIe registers\n", __func__); + + /* + * PcieCfgSpcie1 - Link Control 3 + * Leave at reset value. No need to set PerfEq - link equalization + * will be performed automatically after the SBR when the target + * speed is 8GT/s. + */ + + /* clear all 16 per-lane error bits (PCIe: Lane Error Status) */ + pci_write_config_dword(dd->pcidev, PCIE_CFG_SPCIE2, 0xffff); + + /* step 5a: Set Synopsys Port Logic registers */ + + /* + * PcieCfgRegPl2 - Port Force Link + * + * Set the low power field to 0x10 to avoid unnecessary power + * management messages. All other fields are zero. + */ + reg32 = 0x10ul << PCIE_CFG_REG_PL2_LOW_PWR_ENT_CNT_SHIFT; + pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL2, reg32); + + /* + * PcieCfgRegPl100 - Gen3 Control + * + * turn off PcieCfgRegPl100.Gen3ZRxDcNonCompl + * turn on PcieCfgRegPl100.EqEieosCnt (erratum) + * Everything else zero. + */ + reg32 = PCIE_CFG_REG_PL100_EQ_EIEOS_CNT_SMASK; + pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL100, reg32); + + /* + * PcieCfgRegPl101 - Gen3 EQ FS and LF + * PcieCfgRegPl102 - Gen3 EQ Presets to Coefficients Mapping + * PcieCfgRegPl103 - Gen3 EQ Preset Index + * PcieCfgRegPl105 - Gen3 EQ Status + * + * Give initial EQ settings. + */ + if (dd->pcidev->device == PCI_DEVICE_ID_INTEL0) { /* discrete */ + /* 1000mV, FS=24, LF = 8 */ + fs = 24; + lf = 8; + div = 3; + eq = discrete_preliminary_eq; + default_pset = DEFAULT_DISCRETE_PSET; + } else { + /* 400mV, FS=29, LF = 9 */ + fs = 29; + lf = 9; + div = 1; + eq = integrated_preliminary_eq; + default_pset = DEFAULT_MCP_PSET; + } + pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL101, + (fs << PCIE_CFG_REG_PL101_GEN3_EQ_LOCAL_FS_SHIFT) + | (lf << PCIE_CFG_REG_PL101_GEN3_EQ_LOCAL_LF_SHIFT)); + ret = load_eq_table(dd, eq, fs, div); + if (ret) + goto done; + + /* + * PcieCfgRegPl106 - Gen3 EQ Control + * + * Set Gen3EqPsetReqVec, leave other fields 0. + */ + if (pcie_pset == UNSET_PSET) + pcie_pset = default_pset; + if (pcie_pset > 10) { /* valid range is 0-10, inclusive */ + dd_dev_err(dd, "%s: Invalid Eq Pset %u, setting to %d\n", + __func__, pcie_pset, default_pset); + pcie_pset = default_pset; + } + dd_dev_info(dd, "%s: using EQ Pset %u\n", __func__, pcie_pset); + pci_write_config_dword(dd->pcidev, PCIE_CFG_REG_PL106, + ((1 << pcie_pset) + << PCIE_CFG_REG_PL106_GEN3_EQ_PSET_REQ_VEC_SHIFT) + | PCIE_CFG_REG_PL106_GEN3_EQ_EVAL2MS_DISABLE_SMASK + | PCIE_CFG_REG_PL106_GEN3_EQ_PHASE23_EXIT_MODE_SMASK); + + /* + * step 5b: Do post firmware download steps via SBus + */ + dd_dev_info(dd, "%s: doing pcie post steps\n", __func__); + pcie_post_steps(dd); + + /* + * step 5c: Program gasket interrupts + */ + /* set the Rx Bit Rate to REFCLK ratio */ + write_gasket_interrupt(dd, 0, 0x0006, 0x0050); + /* disable pCal for PCIe Gen3 RX equalization */ + write_gasket_interrupt(dd, 1, 0x0026, 0x5b01); + /* + * Enable iCal for PCIe Gen3 RX equalization, and set which + * evaluation of RX_EQ_EVAL will launch the iCal procedure. + */ + write_gasket_interrupt(dd, 2, 0x0026, 0x5202); + /* terminate list */ + write_gasket_interrupt(dd, 3, 0x0000, 0x0000); + + /* + * step 5d: program XMT margin + * Right now, leave the default alone. To change, do a + * read-modify-write of: + * CcePcieCtrl.XmtMargin + * CcePcieCtrl.XmitMarginOverwriteEnable + */ + + /* step 5e: disable active state power management (ASPM) */ + dd_dev_info(dd, "%s: clearing ASPM\n", __func__); + pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKCTL, &lnkctl); + lnkctl &= ~PCI_EXP_LNKCTL_ASPMC; + pcie_capability_write_word(dd->pcidev, PCI_EXP_LNKCTL, lnkctl); + + /* + * step 5f: clear DirectSpeedChange + * PcieCfgRegPl67.DirectSpeedChange must be zero to prevent the + * change in the speed target from starting before we are ready. + * This field defaults to 0 and we are not changing it, so nothing + * needs to be done. + */ + + /* step 5g: Set target link speed */ + /* + * Set target link speed to be target on both device and parent. + * On setting the parent: Some system BIOSs "helpfully" set the + * parent target speed to Gen2 to match the ASIC's initial speed. + * We can set the target Gen3 because we have already checked + * that it is Gen3 capable earlier. + */ + dd_dev_info(dd, "%s: setting parent target link speed\n", __func__); + parent = dd->pcidev->bus->self; + pcie_capability_read_word(parent, PCI_EXP_LNKCTL2, &lnkctl2); + dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__, + (u32)lnkctl2); + /* only write to parent if target is not as high as ours */ + if ((lnkctl2 & LNKCTL2_TARGET_LINK_SPEED_MASK) < target_vector) { + lnkctl2 &= ~LNKCTL2_TARGET_LINK_SPEED_MASK; + lnkctl2 |= target_vector; + dd_dev_info(dd, "%s: ..new link control2: 0x%x\n", __func__, + (u32)lnkctl2); + pcie_capability_write_word(parent, PCI_EXP_LNKCTL2, lnkctl2); + } else { + dd_dev_info(dd, "%s: ..target speed is OK\n", __func__); + } + + dd_dev_info(dd, "%s: setting target link speed\n", __func__); + pcie_capability_read_word(dd->pcidev, PCI_EXP_LNKCTL2, &lnkctl2); + dd_dev_info(dd, "%s: ..old link control2: 0x%x\n", __func__, + (u32)lnkctl2); + lnkctl2 &= ~LNKCTL2_TARGET_LINK_SPEED_MASK; + lnkctl2 |= target_vector; + dd_dev_info(dd, "%s: ..new link control2: 0x%x\n", __func__, + (u32)lnkctl2); + pcie_capability_write_word(dd->pcidev, PCI_EXP_LNKCTL2, lnkctl2); + + /* step 5h: arm gasket logic */ + /* hold DC in reset across the SBR */ + write_csr(dd, CCE_DC_CTRL, CCE_DC_CTRL_DC_RESET_SMASK); + (void) read_csr(dd, CCE_DC_CTRL); /* DC reset hold */ + /* save firmware control across the SBR */ + fw_ctrl = read_csr(dd, MISC_CFG_FW_CTRL); + + dd_dev_info(dd, "%s: arming gasket logic\n", __func__); + arm_gasket_logic(dd); + + /* + * step 6: quiesce PCIe link + * The chip has already been reset, so there will be no traffic + * from the chip. Linux has no easy way to enforce that it will + * not try to access the device, so we just need to hope it doesn't + * do it while we are doing the reset. + */ + + /* + * step 7: initiate the secondary bus reset (SBR) + * step 8: hardware brings the links back up + * step 9: wait for link speed transition to be complete + */ + dd_dev_info(dd, "%s: calling trigger_sbr\n", __func__); + ret = trigger_sbr(dd); + if (ret) + goto done; + + /* step 10: decide what to do next */ + + /* check if we can read PCI space */ + ret = pci_read_config_word(dd->pcidev, PCI_VENDOR_ID, &vendor); + if (ret) { + dd_dev_info(dd, + "%s: read of VendorID failed after SBR, err %d\n", + __func__, ret); + return_error = 1; + goto done; + } + if (vendor == 0xffff) { + dd_dev_info(dd, "%s: VendorID is all 1s after SBR\n", __func__); + return_error = 1; + ret = -EIO; + goto done; + } + + /* restore PCI space registers we know were reset */ + dd_dev_info(dd, "%s: calling restore_pci_variables\n", __func__); + restore_pci_variables(dd); + /* restore firmware control */ + write_csr(dd, MISC_CFG_FW_CTRL, fw_ctrl); + + /* + * Check the gasket block status. + * + * This is the first CSR read after the SBR. If the read returns + * all 1s (fails), the link did not make it back. + * + * Once we're sure we can read and write, clear the DC reset after + * the SBR. Then check for any per-lane errors. Then look over + * the status. + */ + reg = read_csr(dd, ASIC_PCIE_SD_HOST_STATUS); + dd_dev_info(dd, "%s: gasket block status: 0x%llx\n", __func__, reg); + if (reg == ~0ull) { /* PCIe read failed/timeout */ + dd_dev_err(dd, "SBR failed - unable to read from device\n"); + return_error = 1; + ret = -ENOSYS; + goto done; + } + + /* clear the DC reset */ + write_csr(dd, CCE_DC_CTRL, 0); + /* Set the LED off */ + if (is_a0(dd)) + setextled(dd, 0); + + /* check for any per-lane errors */ + pci_read_config_dword(dd->pcidev, PCIE_CFG_SPCIE2, ®32); + dd_dev_info(dd, "%s: per-lane errors: 0x%x\n", __func__, reg32); + + /* extract status, look for our HFI */ + status = (reg >> ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_STS_SHIFT) + & ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_STS_MASK; + if ((status & (1 << dd->hfi1_id)) == 0) { + dd_dev_err(dd, + "%s: gasket status 0x%x, expecting 0x%x\n", + __func__, status, 1 << dd->hfi1_id); + ret = -EIO; + goto done; + } + + /* extract error */ + err = (reg >> ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_ERR_SHIFT) + & ASIC_PCIE_SD_HOST_STATUS_FW_DNLD_ERR_MASK; + if (err) { + dd_dev_err(dd, "%s: gasket error %d\n", __func__, err); + ret = -EIO; + goto done; + } + + /* update our link information cache */ + update_lbus_info(dd); + dd_dev_info(dd, "%s: new speed and width: %s\n", __func__, + dd->lbus_info); + + if (dd->lbus_speed != target_speed) { /* not target */ + /* maybe retry */ + do_retry = retry_count < pcie_retry; + dd_dev_err(dd, "PCIe link speed did not switch to Gen%d%s\n", + pcie_target, do_retry ? ", retrying" : ""); + retry_count++; + if (do_retry) { + msleep(100); /* allow time to settle */ + goto retry; + } + ret = -EIO; + } + +done: + if (therm) { + write_csr(dd, ASIC_CFG_THERM_POLL_EN, 0x1); + msleep(100); + dd_dev_info(dd, "%s: Re-enable therm polling\n", + __func__); + } + release_hw_mutex(dd); +done_no_mutex: + /* return no error if it is OK to be at current speed */ + if (ret && !return_error) { + dd_dev_err(dd, "Proceeding at current speed PCIe speed\n"); + ret = 0; + } + + dd_dev_info(dd, "%s: done\n", __func__); + return ret; +} diff --git a/drivers/staging/rdma/hfi1/pio.c b/drivers/staging/rdma/hfi1/pio.c new file mode 100644 index 0000000000000..9991814a8f05d --- /dev/null +++ b/drivers/staging/rdma/hfi1/pio.c @@ -0,0 +1,1771 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include "hfi.h" +#include "qp.h" +#include "trace.h" + +#define SC_CTXT_PACKET_EGRESS_TIMEOUT 350 /* in chip cycles */ + +#define SC(name) SEND_CTXT_##name +/* + * Send Context functions + */ +static void sc_wait_for_packet_egress(struct send_context *sc, int pause); + +/* + * Set the CM reset bit and wait for it to clear. Use the provided + * sendctrl register. This routine has no locking. + */ +void __cm_reset(struct hfi1_devdata *dd, u64 sendctrl) +{ + write_csr(dd, SEND_CTRL, sendctrl | SEND_CTRL_CM_RESET_SMASK); + while (1) { + udelay(1); + sendctrl = read_csr(dd, SEND_CTRL); + if ((sendctrl & SEND_CTRL_CM_RESET_SMASK) == 0) + break; + } +} + +/* defined in header release 48 and higher */ +#ifndef SEND_CTRL_UNSUPPORTED_VL_SHIFT +#define SEND_CTRL_UNSUPPORTED_VL_SHIFT 3 +#define SEND_CTRL_UNSUPPORTED_VL_MASK 0xffull +#define SEND_CTRL_UNSUPPORTED_VL_SMASK (SEND_CTRL_UNSUPPORTED_VL_MASK \ + << SEND_CTRL_UNSUPPORTED_VL_SHIFT) +#endif + +/* global control of PIO send */ +void pio_send_control(struct hfi1_devdata *dd, int op) +{ + u64 reg, mask; + unsigned long flags; + int write = 1; /* write sendctrl back */ + int flush = 0; /* re-read sendctrl to make sure it is flushed */ + + spin_lock_irqsave(&dd->sendctrl_lock, flags); + + reg = read_csr(dd, SEND_CTRL); + switch (op) { + case PSC_GLOBAL_ENABLE: + reg |= SEND_CTRL_SEND_ENABLE_SMASK; + /* Fall through */ + case PSC_DATA_VL_ENABLE: + /* Disallow sending on VLs not enabled */ + mask = (((~0ull)<sendctrl_lock, flags); +} + +/* number of send context memory pools */ +#define NUM_SC_POOLS 2 + +/* Send Context Size (SCS) wildcards */ +#define SCS_POOL_0 -1 +#define SCS_POOL_1 -2 +/* Send Context Count (SCC) wildcards */ +#define SCC_PER_VL -1 +#define SCC_PER_CPU -2 + +#define SCC_PER_KRCVQ -3 +#define SCC_ACK_CREDITS 32 + +#define PIO_WAIT_BATCH_SIZE 5 + +/* default send context sizes */ +static struct sc_config_sizes sc_config_sizes[SC_MAX] = { + [SC_KERNEL] = { .size = SCS_POOL_0, /* even divide, pool 0 */ + .count = SCC_PER_VL },/* one per NUMA */ + [SC_ACK] = { .size = SCC_ACK_CREDITS, + .count = SCC_PER_KRCVQ }, + [SC_USER] = { .size = SCS_POOL_0, /* even divide, pool 0 */ + .count = SCC_PER_CPU }, /* one per CPU */ + +}; + +/* send context memory pool configuration */ +struct mem_pool_config { + int centipercent; /* % of memory, in 100ths of 1% */ + int absolute_blocks; /* absolute block count */ +}; + +/* default memory pool configuration: 100% in pool 0 */ +static struct mem_pool_config sc_mem_pool_config[NUM_SC_POOLS] = { + /* centi%, abs blocks */ + { 10000, -1 }, /* pool 0 */ + { 0, -1 }, /* pool 1 */ +}; + +/* memory pool information, used when calculating final sizes */ +struct mem_pool_info { + int centipercent; /* 100th of 1% of memory to use, -1 if blocks + already set */ + int count; /* count of contexts in the pool */ + int blocks; /* block size of the pool */ + int size; /* context size, in blocks */ +}; + +/* + * Convert a pool wildcard to a valid pool index. The wildcards + * start at -1 and increase negatively. Map them as: + * -1 => 0 + * -2 => 1 + * etc. + * + * Return -1 on non-wildcard input, otherwise convert to a pool number. + */ +static int wildcard_to_pool(int wc) +{ + if (wc >= 0) + return -1; /* non-wildcard */ + return -wc - 1; +} + +static const char *sc_type_names[SC_MAX] = { + "kernel", + "ack", + "user" +}; + +static const char *sc_type_name(int index) +{ + if (index < 0 || index >= SC_MAX) + return "unknown"; + return sc_type_names[index]; +} + +/* + * Read the send context memory pool configuration and send context + * size configuration. Replace any wildcards and come up with final + * counts and sizes for the send context types. + */ +int init_sc_pools_and_sizes(struct hfi1_devdata *dd) +{ + struct mem_pool_info mem_pool_info[NUM_SC_POOLS] = { { 0 } }; + int total_blocks = (dd->chip_pio_mem_size / PIO_BLOCK_SIZE) - 1; + int total_contexts = 0; + int fixed_blocks; + int pool_blocks; + int used_blocks; + int cp_total; /* centipercent total */ + int ab_total; /* absolute block total */ + int extra; + int i; + + /* + * Step 0: + * - copy the centipercents/absolute sizes from the pool config + * - sanity check these values + * - add up centipercents, then later check for full value + * - add up absolute blocks, then later check for over-commit + */ + cp_total = 0; + ab_total = 0; + for (i = 0; i < NUM_SC_POOLS; i++) { + int cp = sc_mem_pool_config[i].centipercent; + int ab = sc_mem_pool_config[i].absolute_blocks; + + /* + * A negative value is "unused" or "invalid". Both *can* + * be valid, but centipercent wins, so check that first + */ + if (cp >= 0) { /* centipercent valid */ + cp_total += cp; + } else if (ab >= 0) { /* absolute blocks valid */ + ab_total += ab; + } else { /* neither valid */ + dd_dev_err( + dd, + "Send context memory pool %d: both the block count and centipercent are invalid\n", + i); + return -EINVAL; + } + + mem_pool_info[i].centipercent = cp; + mem_pool_info[i].blocks = ab; + } + + /* do not use both % and absolute blocks for different pools */ + if (cp_total != 0 && ab_total != 0) { + dd_dev_err( + dd, + "All send context memory pools must be described as either centipercent or blocks, no mixing between pools\n"); + return -EINVAL; + } + + /* if any percentages are present, they must add up to 100% x 100 */ + if (cp_total != 0 && cp_total != 10000) { + dd_dev_err( + dd, + "Send context memory pool centipercent is %d, expecting 10000\n", + cp_total); + return -EINVAL; + } + + /* the absolute pool total cannot be more than the mem total */ + if (ab_total > total_blocks) { + dd_dev_err( + dd, + "Send context memory pool absolute block count %d is larger than the memory size %d\n", + ab_total, total_blocks); + return -EINVAL; + } + + /* + * Step 2: + * - copy from the context size config + * - replace context type wildcard counts with real values + * - add up non-memory pool block sizes + * - add up memory pool user counts + */ + fixed_blocks = 0; + for (i = 0; i < SC_MAX; i++) { + int count = sc_config_sizes[i].count; + int size = sc_config_sizes[i].size; + int pool; + + /* + * Sanity check count: Either a positive value or + * one of the expected wildcards is valid. The positive + * value is checked later when we compare against total + * memory available. + */ + if (i == SC_ACK) { + count = dd->n_krcv_queues; + } else if (i == SC_KERNEL) { + count = num_vls + 1 /* VL15 */; + } else if (count == SCC_PER_CPU) { + count = dd->num_rcv_contexts - dd->n_krcv_queues; + } else if (count < 0) { + dd_dev_err( + dd, + "%s send context invalid count wildcard %d\n", + sc_type_name(i), count); + return -EINVAL; + } + if (total_contexts + count > dd->chip_send_contexts) + count = dd->chip_send_contexts - total_contexts; + + total_contexts += count; + + /* + * Sanity check pool: The conversion will return a pool + * number or -1 if a fixed (non-negative) value. The fixed + * value is checked later when we compare against + * total memory available. + */ + pool = wildcard_to_pool(size); + if (pool == -1) { /* non-wildcard */ + fixed_blocks += size * count; + } else if (pool < NUM_SC_POOLS) { /* valid wildcard */ + mem_pool_info[pool].count += count; + } else { /* invalid wildcard */ + dd_dev_err( + dd, + "%s send context invalid pool wildcard %d\n", + sc_type_name(i), size); + return -EINVAL; + } + + dd->sc_sizes[i].count = count; + dd->sc_sizes[i].size = size; + } + if (fixed_blocks > total_blocks) { + dd_dev_err( + dd, + "Send context fixed block count, %u, larger than total block count %u\n", + fixed_blocks, total_blocks); + return -EINVAL; + } + + /* step 3: calculate the blocks in the pools, and pool context sizes */ + pool_blocks = total_blocks - fixed_blocks; + if (ab_total > pool_blocks) { + dd_dev_err( + dd, + "Send context fixed pool sizes, %u, larger than pool block count %u\n", + ab_total, pool_blocks); + return -EINVAL; + } + /* subtract off the fixed pool blocks */ + pool_blocks -= ab_total; + + for (i = 0; i < NUM_SC_POOLS; i++) { + struct mem_pool_info *pi = &mem_pool_info[i]; + + /* % beats absolute blocks */ + if (pi->centipercent >= 0) + pi->blocks = (pool_blocks * pi->centipercent) / 10000; + + if (pi->blocks == 0 && pi->count != 0) { + dd_dev_err( + dd, + "Send context memory pool %d has %u contexts, but no blocks\n", + i, pi->count); + return -EINVAL; + } + if (pi->count == 0) { + /* warn about wasted blocks */ + if (pi->blocks != 0) + dd_dev_err( + dd, + "Send context memory pool %d has %u blocks, but zero contexts\n", + i, pi->blocks); + pi->size = 0; + } else { + pi->size = pi->blocks / pi->count; + } + } + + /* step 4: fill in the context type sizes from the pool sizes */ + used_blocks = 0; + for (i = 0; i < SC_MAX; i++) { + if (dd->sc_sizes[i].size < 0) { + unsigned pool = wildcard_to_pool(dd->sc_sizes[i].size); + + WARN_ON_ONCE(pool >= NUM_SC_POOLS); + dd->sc_sizes[i].size = mem_pool_info[pool].size; + } + /* make sure we are not larger than what is allowed by the HW */ +#define PIO_MAX_BLOCKS 1024 + if (dd->sc_sizes[i].size > PIO_MAX_BLOCKS) + dd->sc_sizes[i].size = PIO_MAX_BLOCKS; + + /* calculate our total usage */ + used_blocks += dd->sc_sizes[i].size * dd->sc_sizes[i].count; + } + extra = total_blocks - used_blocks; + if (extra != 0) + dd_dev_info(dd, "unused send context blocks: %d\n", extra); + + return total_contexts; +} + +int init_send_contexts(struct hfi1_devdata *dd) +{ + u16 base; + int ret, i, j, context; + + ret = init_credit_return(dd); + if (ret) + return ret; + + dd->hw_to_sw = kmalloc_array(TXE_NUM_CONTEXTS, sizeof(u8), + GFP_KERNEL); + dd->send_contexts = kcalloc(dd->num_send_contexts, + sizeof(struct send_context_info), + GFP_KERNEL); + if (!dd->send_contexts || !dd->hw_to_sw) { + dd_dev_err(dd, "Unable to allocate send context arrays\n"); + kfree(dd->hw_to_sw); + kfree(dd->send_contexts); + free_credit_return(dd); + return -ENOMEM; + } + + /* hardware context map starts with invalid send context indices */ + for (i = 0; i < TXE_NUM_CONTEXTS; i++) + dd->hw_to_sw[i] = INVALID_SCI; + + /* + * All send contexts have their credit sizes. Allocate credits + * for each context one after another from the global space. + */ + context = 0; + base = 1; + for (i = 0; i < SC_MAX; i++) { + struct sc_config_sizes *scs = &dd->sc_sizes[i]; + + for (j = 0; j < scs->count; j++) { + struct send_context_info *sci = + &dd->send_contexts[context]; + sci->type = i; + sci->base = base; + sci->credits = scs->size; + + context++; + base += scs->size; + } + } + + return 0; +} + +/* + * Allocate a software index and hardware context of the given type. + * + * Must be called with dd->sc_lock held. + */ +static int sc_hw_alloc(struct hfi1_devdata *dd, int type, u32 *sw_index, + u32 *hw_context) +{ + struct send_context_info *sci; + u32 index; + u32 context; + + for (index = 0, sci = &dd->send_contexts[0]; + index < dd->num_send_contexts; index++, sci++) { + if (sci->type == type && sci->allocated == 0) { + sci->allocated = 1; + /* use a 1:1 mapping, but make them non-equal */ + context = dd->chip_send_contexts - index - 1; + dd->hw_to_sw[context] = index; + *sw_index = index; + *hw_context = context; + return 0; /* success */ + } + } + dd_dev_err(dd, "Unable to locate a free type %d send context\n", type); + return -ENOSPC; +} + +/* + * Free the send context given by its software index. + * + * Must be called with dd->sc_lock held. + */ +static void sc_hw_free(struct hfi1_devdata *dd, u32 sw_index, u32 hw_context) +{ + struct send_context_info *sci; + + sci = &dd->send_contexts[sw_index]; + if (!sci->allocated) { + dd_dev_err(dd, "%s: sw_index %u not allocated? hw_context %u\n", + __func__, sw_index, hw_context); + } + sci->allocated = 0; + dd->hw_to_sw[hw_context] = INVALID_SCI; +} + +/* return the base context of a context in a group */ +static inline u32 group_context(u32 context, u32 group) +{ + return (context >> group) << group; +} + +/* return the size of a group */ +static inline u32 group_size(u32 group) +{ + return 1 << group; +} + +/* + * Obtain the credit return addresses, kernel virtual and physical, for the + * given sc. + * + * To understand this routine: + * o va and pa are arrays of struct credit_return. One for each physical + * send context, per NUMA. + * o Each send context always looks in its relative location in a struct + * credit_return for its credit return. + * o Each send context in a group must have its return address CSR programmed + * with the same value. Use the address of the first send context in the + * group. + */ +static void cr_group_addresses(struct send_context *sc, dma_addr_t *pa) +{ + u32 gc = group_context(sc->hw_context, sc->group); + u32 index = sc->hw_context & 0x7; + + sc->hw_free = &sc->dd->cr_base[sc->node].va[gc].cr[index]; + *pa = (unsigned long) + &((struct credit_return *)sc->dd->cr_base[sc->node].pa)[gc]; +} + +/* + * Work queue function triggered in error interrupt routine for + * kernel contexts. + */ +static void sc_halted(struct work_struct *work) +{ + struct send_context *sc; + + sc = container_of(work, struct send_context, halt_work); + sc_restart(sc); +} + +/* + * Calculate PIO block threshold for this send context using the given MTU. + * Trigger a return when one MTU plus optional header of credits remain. + * + * Parameter mtu is in bytes. + * Parameter hdrqentsize is in DWORDs. + * + * Return value is what to write into the CSR: trigger return when + * unreturned credits pass this count. + */ +u32 sc_mtu_to_threshold(struct send_context *sc, u32 mtu, u32 hdrqentsize) +{ + u32 release_credits; + u32 threshold; + + /* add in the header size, then divide by the PIO block size */ + mtu += hdrqentsize << 2; + release_credits = DIV_ROUND_UP(mtu, PIO_BLOCK_SIZE); + + /* check against this context's credits */ + if (sc->credits <= release_credits) + threshold = 1; + else + threshold = sc->credits - release_credits; + + return threshold; +} + +/* + * Calculate credit threshold in terms of percent of the allocated credits. + * Trigger when unreturned credits equal or exceed the percentage of the whole. + * + * Return value is what to write into the CSR: trigger return when + * unreturned credits pass this count. + */ +static u32 sc_percent_to_threshold(struct send_context *sc, u32 percent) +{ + return (sc->credits * percent) / 100; +} + +/* + * Set the credit return threshold. + */ +void sc_set_cr_threshold(struct send_context *sc, u32 new_threshold) +{ + unsigned long flags; + u32 old_threshold; + int force_return = 0; + + spin_lock_irqsave(&sc->credit_ctrl_lock, flags); + + old_threshold = (sc->credit_ctrl >> + SC(CREDIT_CTRL_THRESHOLD_SHIFT)) + & SC(CREDIT_CTRL_THRESHOLD_MASK); + + if (new_threshold != old_threshold) { + sc->credit_ctrl = + (sc->credit_ctrl + & ~SC(CREDIT_CTRL_THRESHOLD_SMASK)) + | ((new_threshold + & SC(CREDIT_CTRL_THRESHOLD_MASK)) + << SC(CREDIT_CTRL_THRESHOLD_SHIFT)); + write_kctxt_csr(sc->dd, sc->hw_context, + SC(CREDIT_CTRL), sc->credit_ctrl); + + /* force a credit return on change to avoid a possible stall */ + force_return = 1; + } + + spin_unlock_irqrestore(&sc->credit_ctrl_lock, flags); + + if (force_return) + sc_return_credits(sc); +} + +/* + * set_pio_integrity + * + * Set the CHECK_ENABLE register for the send context 'sc'. + */ +void set_pio_integrity(struct send_context *sc) +{ + struct hfi1_devdata *dd = sc->dd; + u64 reg = 0; + u32 hw_context = sc->hw_context; + int type = sc->type; + + /* + * No integrity checks if HFI1_CAP_NO_INTEGRITY is set, or if + * we're snooping. + */ + if (likely(!HFI1_CAP_IS_KSET(NO_INTEGRITY)) && + dd->hfi1_snoop.mode_flag != HFI1_PORT_SNOOP_MODE) + reg = hfi1_pkt_default_send_ctxt_mask(dd, type); + + write_kctxt_csr(dd, hw_context, SC(CHECK_ENABLE), reg); +} + +/* + * Allocate a NUMA relative send context structure of the given type along + * with a HW context. + */ +struct send_context *sc_alloc(struct hfi1_devdata *dd, int type, + uint hdrqentsize, int numa) +{ + struct send_context_info *sci; + struct send_context *sc; + dma_addr_t pa; + unsigned long flags; + u64 reg; + u32 thresh; + u32 sw_index; + u32 hw_context; + int ret; + u8 opval, opmask; + + /* do not allocate while frozen */ + if (dd->flags & HFI1_FROZEN) + return NULL; + + sc = kzalloc_node(sizeof(struct send_context), GFP_KERNEL, numa); + if (!sc) { + dd_dev_err(dd, "Cannot allocate send context structure\n"); + return NULL; + } + + spin_lock_irqsave(&dd->sc_lock, flags); + ret = sc_hw_alloc(dd, type, &sw_index, &hw_context); + if (ret) { + spin_unlock_irqrestore(&dd->sc_lock, flags); + kfree(sc); + return NULL; + } + + sci = &dd->send_contexts[sw_index]; + sci->sc = sc; + + sc->dd = dd; + sc->node = numa; + sc->type = type; + spin_lock_init(&sc->alloc_lock); + spin_lock_init(&sc->release_lock); + spin_lock_init(&sc->credit_ctrl_lock); + INIT_LIST_HEAD(&sc->piowait); + INIT_WORK(&sc->halt_work, sc_halted); + atomic_set(&sc->buffers_allocated, 0); + init_waitqueue_head(&sc->halt_wait); + + /* grouping is always single context for now */ + sc->group = 0; + + sc->sw_index = sw_index; + sc->hw_context = hw_context; + cr_group_addresses(sc, &pa); + sc->credits = sci->credits; + +/* PIO Send Memory Address details */ +#define PIO_ADDR_CONTEXT_MASK 0xfful +#define PIO_ADDR_CONTEXT_SHIFT 16 + sc->base_addr = dd->piobase + ((hw_context & PIO_ADDR_CONTEXT_MASK) + << PIO_ADDR_CONTEXT_SHIFT); + + /* set base and credits */ + reg = ((sci->credits & SC(CTRL_CTXT_DEPTH_MASK)) + << SC(CTRL_CTXT_DEPTH_SHIFT)) + | ((sci->base & SC(CTRL_CTXT_BASE_MASK)) + << SC(CTRL_CTXT_BASE_SHIFT)); + write_kctxt_csr(dd, hw_context, SC(CTRL), reg); + + set_pio_integrity(sc); + + /* unmask all errors */ + write_kctxt_csr(dd, hw_context, SC(ERR_MASK), (u64)-1); + + /* set the default partition key */ + write_kctxt_csr(dd, hw_context, SC(CHECK_PARTITION_KEY), + (DEFAULT_PKEY & + SC(CHECK_PARTITION_KEY_VALUE_MASK)) + << SC(CHECK_PARTITION_KEY_VALUE_SHIFT)); + + /* per context type checks */ + if (type == SC_USER) { + opval = USER_OPCODE_CHECK_VAL; + opmask = USER_OPCODE_CHECK_MASK; + } else { + opval = OPCODE_CHECK_VAL_DISABLED; + opmask = OPCODE_CHECK_MASK_DISABLED; + } + + /* set the send context check opcode mask and value */ + write_kctxt_csr(dd, hw_context, SC(CHECK_OPCODE), + ((u64)opmask << SC(CHECK_OPCODE_MASK_SHIFT)) | + ((u64)opval << SC(CHECK_OPCODE_VALUE_SHIFT))); + + /* set up credit return */ + reg = pa & SC(CREDIT_RETURN_ADDR_ADDRESS_SMASK); + write_kctxt_csr(dd, hw_context, SC(CREDIT_RETURN_ADDR), reg); + + /* + * Calculate the initial credit return threshold. + * + * For Ack contexts, set a threshold for half the credits. + * For User contexts use the given percentage. This has been + * sanitized on driver start-up. + * For Kernel contexts, use the default MTU plus a header. + */ + if (type == SC_ACK) { + thresh = sc_percent_to_threshold(sc, 50); + } else if (type == SC_USER) { + thresh = sc_percent_to_threshold(sc, + user_credit_return_threshold); + } else { /* kernel */ + thresh = sc_mtu_to_threshold(sc, hfi1_max_mtu, hdrqentsize); + } + reg = thresh << SC(CREDIT_CTRL_THRESHOLD_SHIFT); + /* add in early return */ + if (type == SC_USER && HFI1_CAP_IS_USET(EARLY_CREDIT_RETURN)) + reg |= SC(CREDIT_CTRL_EARLY_RETURN_SMASK); + else if (HFI1_CAP_IS_KSET(EARLY_CREDIT_RETURN)) /* kernel, ack */ + reg |= SC(CREDIT_CTRL_EARLY_RETURN_SMASK); + + /* set up write-through credit_ctrl */ + sc->credit_ctrl = reg; + write_kctxt_csr(dd, hw_context, SC(CREDIT_CTRL), reg); + + /* User send contexts should not allow sending on VL15 */ + if (type == SC_USER) { + reg = 1ULL << 15; + write_kctxt_csr(dd, hw_context, SC(CHECK_VL), reg); + } + + spin_unlock_irqrestore(&dd->sc_lock, flags); + + /* + * Allocate shadow ring to track outstanding PIO buffers _after_ + * unlocking. We don't know the size until the lock is held and + * we can't allocate while the lock is held. No one is using + * the context yet, so allocate it now. + * + * User contexts do not get a shadow ring. + */ + if (type != SC_USER) { + /* + * Size the shadow ring 1 larger than the number of credits + * so head == tail can mean empty. + */ + sc->sr_size = sci->credits + 1; + sc->sr = kzalloc_node(sizeof(union pio_shadow_ring) * + sc->sr_size, GFP_KERNEL, numa); + if (!sc->sr) { + dd_dev_err(dd, + "Cannot allocate send context shadow ring structure\n"); + sc_free(sc); + return NULL; + } + } + + dd_dev_info(dd, + "Send context %u(%u) %s group %u credits %u credit_ctrl 0x%llx threshold %u\n", + sw_index, + hw_context, + sc_type_name(type), + sc->group, + sc->credits, + sc->credit_ctrl, + thresh); + + return sc; +} + +/* free a per-NUMA send context structure */ +void sc_free(struct send_context *sc) +{ + struct hfi1_devdata *dd; + unsigned long flags; + u32 sw_index; + u32 hw_context; + + if (!sc) + return; + + sc->flags |= SCF_IN_FREE; /* ensure no restarts */ + dd = sc->dd; + if (!list_empty(&sc->piowait)) + dd_dev_err(dd, "piowait list not empty!\n"); + sw_index = sc->sw_index; + hw_context = sc->hw_context; + sc_disable(sc); /* make sure the HW is disabled */ + flush_work(&sc->halt_work); + + spin_lock_irqsave(&dd->sc_lock, flags); + dd->send_contexts[sw_index].sc = NULL; + + /* clear/disable all registers set in sc_alloc */ + write_kctxt_csr(dd, hw_context, SC(CTRL), 0); + write_kctxt_csr(dd, hw_context, SC(CHECK_ENABLE), 0); + write_kctxt_csr(dd, hw_context, SC(ERR_MASK), 0); + write_kctxt_csr(dd, hw_context, SC(CHECK_PARTITION_KEY), 0); + write_kctxt_csr(dd, hw_context, SC(CHECK_OPCODE), 0); + write_kctxt_csr(dd, hw_context, SC(CREDIT_RETURN_ADDR), 0); + write_kctxt_csr(dd, hw_context, SC(CREDIT_CTRL), 0); + + /* release the index and context for re-use */ + sc_hw_free(dd, sw_index, hw_context); + spin_unlock_irqrestore(&dd->sc_lock, flags); + + kfree(sc->sr); + kfree(sc); +} + +/* disable the context */ +void sc_disable(struct send_context *sc) +{ + u64 reg; + unsigned long flags; + struct pio_buf *pbuf; + + if (!sc) + return; + + /* do all steps, even if already disabled */ + spin_lock_irqsave(&sc->alloc_lock, flags); + reg = read_kctxt_csr(sc->dd, sc->hw_context, SC(CTRL)); + reg &= ~SC(CTRL_CTXT_ENABLE_SMASK); + sc->flags &= ~SCF_ENABLED; + sc_wait_for_packet_egress(sc, 1); + write_kctxt_csr(sc->dd, sc->hw_context, SC(CTRL), reg); + spin_unlock_irqrestore(&sc->alloc_lock, flags); + + /* + * Flush any waiters. Once the context is disabled, + * credit return interrupts are stopped (although there + * could be one in-process when the context is disabled). + * Wait one microsecond for any lingering interrupts, then + * proceed with the flush. + */ + udelay(1); + spin_lock_irqsave(&sc->release_lock, flags); + if (sc->sr) { /* this context has a shadow ring */ + while (sc->sr_tail != sc->sr_head) { + pbuf = &sc->sr[sc->sr_tail].pbuf; + if (pbuf->cb) + (*pbuf->cb)(pbuf->arg, PRC_SC_DISABLE); + sc->sr_tail++; + if (sc->sr_tail >= sc->sr_size) + sc->sr_tail = 0; + } + } + spin_unlock_irqrestore(&sc->release_lock, flags); +} + +/* return SendEgressCtxtStatus.PacketOccupancy */ +#define packet_occupancy(r) \ + (((r) & SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_PACKET_OCCUPANCY_SMASK)\ + >> SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_PACKET_OCCUPANCY_SHIFT) + +/* is egress halted on the context? */ +#define egress_halted(r) \ + ((r) & SEND_EGRESS_CTXT_STATUS_CTXT_EGRESS_HALT_STATUS_SMASK) + +/* wait for packet egress, optionally pause for credit return */ +static void sc_wait_for_packet_egress(struct send_context *sc, int pause) +{ + struct hfi1_devdata *dd = sc->dd; + u64 reg; + u32 loop = 0; + + while (1) { + reg = read_csr(dd, sc->hw_context * 8 + + SEND_EGRESS_CTXT_STATUS); + /* done if egress is stopped */ + if (egress_halted(reg)) + break; + reg = packet_occupancy(reg); + if (reg == 0) + break; + if (loop > 100) { + dd_dev_err(dd, + "%s: context %u(%u) timeout waiting for packets to egress, remaining count %u\n", + __func__, sc->sw_index, + sc->hw_context, (u32)reg); + break; + } + loop++; + udelay(1); + } + + if (pause) + /* Add additional delay to ensure chip returns all credits */ + pause_for_credit_return(dd); +} + +void sc_wait(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < dd->num_send_contexts; i++) { + struct send_context *sc = dd->send_contexts[i].sc; + + if (!sc) + continue; + sc_wait_for_packet_egress(sc, 0); + } +} + +/* + * Restart a context after it has been halted due to error. + * + * If the first step fails - wait for the halt to be asserted, return early. + * Otherwise complain about timeouts but keep going. + * + * It is expected that allocations (enabled flag bit) have been shut off + * already (only applies to kernel contexts). + */ +int sc_restart(struct send_context *sc) +{ + struct hfi1_devdata *dd = sc->dd; + u64 reg; + u32 loop; + int count; + + /* bounce off if not halted, or being free'd */ + if (!(sc->flags & SCF_HALTED) || (sc->flags & SCF_IN_FREE)) + return -EINVAL; + + dd_dev_info(dd, "restarting send context %u(%u)\n", sc->sw_index, + sc->hw_context); + + /* + * Step 1: Wait for the context to actually halt. + * + * The error interrupt is asynchronous to actually setting halt + * on the context. + */ + loop = 0; + while (1) { + reg = read_kctxt_csr(dd, sc->hw_context, SC(STATUS)); + if (reg & SC(STATUS_CTXT_HALTED_SMASK)) + break; + if (loop > 100) { + dd_dev_err(dd, "%s: context %u(%u) not halting, skipping\n", + __func__, sc->sw_index, sc->hw_context); + return -ETIME; + } + loop++; + udelay(1); + } + + /* + * Step 2: Ensure no users are still trying to write to PIO. + * + * For kernel contexts, we have already turned off buffer allocation. + * Now wait for the buffer count to go to zero. + * + * For user contexts, the user handling code has cut off write access + * to the context's PIO pages before calling this routine and will + * restore write access after this routine returns. + */ + if (sc->type != SC_USER) { + /* kernel context */ + loop = 0; + while (1) { + count = atomic_read(&sc->buffers_allocated); + if (count == 0) + break; + if (loop > 100) { + dd_dev_err(dd, + "%s: context %u(%u) timeout waiting for PIO buffers to zero, remaining %d\n", + __func__, sc->sw_index, + sc->hw_context, count); + } + loop++; + udelay(1); + } + } + + /* + * Step 3: Wait for all packets to egress. + * This is done while disabling the send context + * + * Step 4: Disable the context + * + * This is a superset of the halt. After the disable, the + * errors can be cleared. + */ + sc_disable(sc); + + /* + * Step 5: Enable the context + * + * This enable will clear the halted flag and per-send context + * error flags. + */ + return sc_enable(sc); +} + +/* + * PIO freeze processing. To be called after the TXE block is fully frozen. + * Go through all frozen send contexts and disable them. The contexts are + * already stopped by the freeze. + */ +void pio_freeze(struct hfi1_devdata *dd) +{ + struct send_context *sc; + int i; + + for (i = 0; i < dd->num_send_contexts; i++) { + sc = dd->send_contexts[i].sc; + /* + * Don't disable unallocated, unfrozen, or user send contexts. + * User send contexts will be disabled when the process + * calls into the driver to reset its context. + */ + if (!sc || !(sc->flags & SCF_FROZEN) || sc->type == SC_USER) + continue; + + /* only need to disable, the context is already stopped */ + sc_disable(sc); + } +} + +/* + * Unfreeze PIO for kernel send contexts. The precondition for calling this + * is that all PIO send contexts have been disabled and the SPC freeze has + * been cleared. Now perform the last step and re-enable each kernel context. + * User (PSM) processing will occur when PSM calls into the kernel to + * acknowledge the freeze. + */ +void pio_kernel_unfreeze(struct hfi1_devdata *dd) +{ + struct send_context *sc; + int i; + + for (i = 0; i < dd->num_send_contexts; i++) { + sc = dd->send_contexts[i].sc; + if (!sc || !(sc->flags & SCF_FROZEN) || sc->type == SC_USER) + continue; + + sc_enable(sc); /* will clear the sc frozen flag */ + } +} + +/* + * Wait for the SendPioInitCtxt.PioInitInProgress bit to clear. + * Returns: + * -ETIMEDOUT - if we wait too long + * -EIO - if there was an error + */ +static int pio_init_wait_progress(struct hfi1_devdata *dd) +{ + u64 reg; + int max, count = 0; + + /* max is the longest possible HW init time / delay */ + max = (dd->icode == ICODE_FPGA_EMULATION) ? 120 : 5; + while (1) { + reg = read_csr(dd, SEND_PIO_INIT_CTXT); + if (!(reg & SEND_PIO_INIT_CTXT_PIO_INIT_IN_PROGRESS_SMASK)) + break; + if (count >= max) + return -ETIMEDOUT; + udelay(5); + count++; + } + + return reg & SEND_PIO_INIT_CTXT_PIO_INIT_ERR_SMASK ? -EIO : 0; +} + +/* + * Reset all of the send contexts to their power-on state. Used + * only during manual init - no lock against sc_enable needed. + */ +void pio_reset_all(struct hfi1_devdata *dd) +{ + int ret; + + /* make sure the init engine is not busy */ + ret = pio_init_wait_progress(dd); + /* ignore any timeout */ + if (ret == -EIO) { + /* clear the error */ + write_csr(dd, SEND_PIO_ERR_CLEAR, + SEND_PIO_ERR_CLEAR_PIO_INIT_SM_IN_ERR_SMASK); + } + + /* reset init all */ + write_csr(dd, SEND_PIO_INIT_CTXT, + SEND_PIO_INIT_CTXT_PIO_ALL_CTXT_INIT_SMASK); + udelay(2); + ret = pio_init_wait_progress(dd); + if (ret < 0) { + dd_dev_err(dd, + "PIO send context init %s while initializing all PIO blocks\n", + ret == -ETIMEDOUT ? "is stuck" : "had an error"); + } +} + +/* enable the context */ +int sc_enable(struct send_context *sc) +{ + u64 sc_ctrl, reg, pio; + struct hfi1_devdata *dd; + unsigned long flags; + int ret = 0; + + if (!sc) + return -EINVAL; + dd = sc->dd; + + /* + * Obtain the allocator lock to guard against any allocation + * attempts (which should not happen prior to context being + * enabled). On the release/disable side we don't need to + * worry about locking since the releaser will not do anything + * if the context accounting values have not changed. + */ + spin_lock_irqsave(&sc->alloc_lock, flags); + sc_ctrl = read_kctxt_csr(dd, sc->hw_context, SC(CTRL)); + if ((sc_ctrl & SC(CTRL_CTXT_ENABLE_SMASK))) + goto unlock; /* already enabled */ + + /* IMPORTANT: only clear free and fill if transitioning 0 -> 1 */ + + *sc->hw_free = 0; + sc->free = 0; + sc->alloc_free = 0; + sc->fill = 0; + sc->sr_head = 0; + sc->sr_tail = 0; + sc->flags = 0; + atomic_set(&sc->buffers_allocated, 0); + + /* + * Clear all per-context errors. Some of these will be set when + * we are re-enabling after a context halt. Now that the context + * is disabled, the halt will not clear until after the PIO init + * engine runs below. + */ + reg = read_kctxt_csr(dd, sc->hw_context, SC(ERR_STATUS)); + if (reg) + write_kctxt_csr(dd, sc->hw_context, SC(ERR_CLEAR), + reg); + + /* + * The HW PIO initialization engine can handle only one init + * request at a time. Serialize access to each device's engine. + */ + spin_lock(&dd->sc_init_lock); + /* + * Since access to this code block is serialized and + * each access waits for the initialization to complete + * before releasing the lock, the PIO initialization engine + * should not be in use, so we don't have to wait for the + * InProgress bit to go down. + */ + pio = ((sc->hw_context & SEND_PIO_INIT_CTXT_PIO_CTXT_NUM_MASK) << + SEND_PIO_INIT_CTXT_PIO_CTXT_NUM_SHIFT) | + SEND_PIO_INIT_CTXT_PIO_SINGLE_CTXT_INIT_SMASK; + write_csr(dd, SEND_PIO_INIT_CTXT, pio); + /* + * Wait until the engine is done. Give the chip the required time + * so, hopefully, we read the register just once. + */ + udelay(2); + ret = pio_init_wait_progress(dd); + spin_unlock(&dd->sc_init_lock); + if (ret) { + dd_dev_err(dd, + "sctxt%u(%u): Context not enabled due to init failure %d\n", + sc->sw_index, sc->hw_context, ret); + goto unlock; + } + + /* + * All is well. Enable the context. + */ + sc_ctrl |= SC(CTRL_CTXT_ENABLE_SMASK); + write_kctxt_csr(dd, sc->hw_context, SC(CTRL), sc_ctrl); + /* + * Read SendCtxtCtrl to force the write out and prevent a timing + * hazard where a PIO write may reach the context before the enable. + */ + read_kctxt_csr(dd, sc->hw_context, SC(CTRL)); + sc->flags |= SCF_ENABLED; + +unlock: + spin_unlock_irqrestore(&sc->alloc_lock, flags); + + return ret; +} + +/* force a credit return on the context */ +void sc_return_credits(struct send_context *sc) +{ + if (!sc) + return; + + /* a 0->1 transition schedules a credit return */ + write_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_FORCE), + SC(CREDIT_FORCE_FORCE_RETURN_SMASK)); + /* + * Ensure that the write is flushed and the credit return is + * scheduled. We care more about the 0 -> 1 transition. + */ + read_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_FORCE)); + /* set back to 0 for next time */ + write_kctxt_csr(sc->dd, sc->hw_context, SC(CREDIT_FORCE), 0); +} + +/* allow all in-flight packets to drain on the context */ +void sc_flush(struct send_context *sc) +{ + if (!sc) + return; + + sc_wait_for_packet_egress(sc, 1); +} + +/* drop all packets on the context, no waiting until they are sent */ +void sc_drop(struct send_context *sc) +{ + if (!sc) + return; + + dd_dev_info(sc->dd, "%s: context %u(%u) - not implemented\n", + __func__, sc->sw_index, sc->hw_context); +} + +/* + * Start the software reaction to a context halt or SPC freeze: + * - mark the context as halted or frozen + * - stop buffer allocations + * + * Called from the error interrupt. Other work is deferred until + * out of the interrupt. + */ +void sc_stop(struct send_context *sc, int flag) +{ + unsigned long flags; + + /* mark the context */ + sc->flags |= flag; + + /* stop buffer allocations */ + spin_lock_irqsave(&sc->alloc_lock, flags); + sc->flags &= ~SCF_ENABLED; + spin_unlock_irqrestore(&sc->alloc_lock, flags); + wake_up(&sc->halt_wait); +} + +#define BLOCK_DWORDS (PIO_BLOCK_SIZE/sizeof(u32)) +#define dwords_to_blocks(x) DIV_ROUND_UP(x, BLOCK_DWORDS) + +/* + * The send context buffer "allocator". + * + * @sc: the PIO send context we are allocating from + * @len: length of whole packet - including PBC - in dwords + * @cb: optional callback to call when the buffer is finished sending + * @arg: argument for cb + * + * Return a pointer to a PIO buffer if successful, NULL if not enough room. + */ +struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len, + pio_release_cb cb, void *arg) +{ + struct pio_buf *pbuf = NULL; + unsigned long flags; + unsigned long avail; + unsigned long blocks = dwords_to_blocks(dw_len); + unsigned long start_fill; + int trycount = 0; + u32 head, next; + + spin_lock_irqsave(&sc->alloc_lock, flags); + if (!(sc->flags & SCF_ENABLED)) { + spin_unlock_irqrestore(&sc->alloc_lock, flags); + goto done; + } + +retry: + avail = (unsigned long)sc->credits - (sc->fill - sc->alloc_free); + if (blocks > avail) { + /* not enough room */ + if (unlikely(trycount)) { /* already tried to get more room */ + spin_unlock_irqrestore(&sc->alloc_lock, flags); + goto done; + } + /* copy from receiver cache line and recalculate */ + sc->alloc_free = ACCESS_ONCE(sc->free); + avail = + (unsigned long)sc->credits - + (sc->fill - sc->alloc_free); + if (blocks > avail) { + /* still no room, actively update */ + spin_unlock_irqrestore(&sc->alloc_lock, flags); + sc_release_update(sc); + spin_lock_irqsave(&sc->alloc_lock, flags); + sc->alloc_free = ACCESS_ONCE(sc->free); + trycount++; + goto retry; + } + } + + /* there is enough room */ + + atomic_inc(&sc->buffers_allocated); + + /* read this once */ + head = sc->sr_head; + + /* "allocate" the buffer */ + start_fill = sc->fill; + sc->fill += blocks; + + /* + * Fill the parts that the releaser looks at before moving the head. + * The only necessary piece is the sent_at field. The credits + * we have just allocated cannot have been returned yet, so the + * cb and arg will not be looked at for a "while". Put them + * on this side of the memory barrier anyway. + */ + pbuf = &sc->sr[head].pbuf; + pbuf->sent_at = sc->fill; + pbuf->cb = cb; + pbuf->arg = arg; + pbuf->sc = sc; /* could be filled in at sc->sr init time */ + /* make sure this is in memory before updating the head */ + + /* calculate next head index, do not store */ + next = head + 1; + if (next >= sc->sr_size) + next = 0; + /* update the head - must be last! - the releaser can look at fields + in pbuf once we move the head */ + smp_wmb(); + sc->sr_head = next; + spin_unlock_irqrestore(&sc->alloc_lock, flags); + + /* finish filling in the buffer outside the lock */ + pbuf->start = sc->base_addr + ((start_fill % sc->credits) + * PIO_BLOCK_SIZE); + pbuf->size = sc->credits * PIO_BLOCK_SIZE; + pbuf->end = sc->base_addr + pbuf->size; + pbuf->block_count = blocks; + pbuf->qw_written = 0; + pbuf->carry_bytes = 0; + pbuf->carry.val64 = 0; +done: + return pbuf; +} + +/* + * There are at least two entities that can turn on credit return + * interrupts and they can overlap. Avoid problems by implementing + * a count scheme that is enforced by a lock. The lock is needed because + * the count and CSR write must be paired. + */ + +/* + * Start credit return interrupts. This is managed by a count. If already + * on, just increment the count. + */ +void sc_add_credit_return_intr(struct send_context *sc) +{ + unsigned long flags; + + /* lock must surround both the count change and the CSR update */ + spin_lock_irqsave(&sc->credit_ctrl_lock, flags); + if (sc->credit_intr_count == 0) { + sc->credit_ctrl |= SC(CREDIT_CTRL_CREDIT_INTR_SMASK); + write_kctxt_csr(sc->dd, sc->hw_context, + SC(CREDIT_CTRL), sc->credit_ctrl); + } + sc->credit_intr_count++; + spin_unlock_irqrestore(&sc->credit_ctrl_lock, flags); +} + +/* + * Stop credit return interrupts. This is managed by a count. Decrement the + * count, if the last user, then turn the credit interrupts off. + */ +void sc_del_credit_return_intr(struct send_context *sc) +{ + unsigned long flags; + + WARN_ON(sc->credit_intr_count == 0); + + /* lock must surround both the count change and the CSR update */ + spin_lock_irqsave(&sc->credit_ctrl_lock, flags); + sc->credit_intr_count--; + if (sc->credit_intr_count == 0) { + sc->credit_ctrl &= ~SC(CREDIT_CTRL_CREDIT_INTR_SMASK); + write_kctxt_csr(sc->dd, sc->hw_context, + SC(CREDIT_CTRL), sc->credit_ctrl); + } + spin_unlock_irqrestore(&sc->credit_ctrl_lock, flags); +} + +/* + * The caller must be careful when calling this. All needint calls + * must be paired with !needint. + */ +void hfi1_sc_wantpiobuf_intr(struct send_context *sc, u32 needint) +{ + if (needint) + sc_add_credit_return_intr(sc); + else + sc_del_credit_return_intr(sc); + trace_hfi1_wantpiointr(sc, needint, sc->credit_ctrl); + if (needint) { + mmiowb(); + sc_return_credits(sc); + } +} + +/** + * sc_piobufavail - callback when a PIO buffer is available + * @sc: the send context + * + * This is called from the interrupt handler when a PIO buffer is + * available after hfi1_verbs_send() returned an error that no buffers were + * available. Disable the interrupt if there are no more QPs waiting. + */ +static void sc_piobufavail(struct send_context *sc) +{ + struct hfi1_devdata *dd = sc->dd; + struct hfi1_ibdev *dev = &dd->verbs_dev; + struct list_head *list; + struct hfi1_qp *qps[PIO_WAIT_BATCH_SIZE]; + struct hfi1_qp *qp; + unsigned long flags; + unsigned i, n = 0; + + if (dd->send_contexts[sc->sw_index].type != SC_KERNEL) + return; + list = &sc->piowait; + /* + * Note: checking that the piowait list is empty and clearing + * the buffer available interrupt needs to be atomic or we + * could end up with QPs on the wait list with the interrupt + * disabled. + */ + write_seqlock_irqsave(&dev->iowait_lock, flags); + while (!list_empty(list)) { + struct iowait *wait; + + if (n == ARRAY_SIZE(qps)) + goto full; + wait = list_first_entry(list, struct iowait, list); + qp = container_of(wait, struct hfi1_qp, s_iowait); + list_del_init(&qp->s_iowait.list); + /* refcount held until actual wake up */ + qps[n++] = qp; + } + /* + * Counting: only call wantpiobuf_intr() if there were waiters and they + * are now all gone. + */ + if (n) + hfi1_sc_wantpiobuf_intr(sc, 0); +full: + write_sequnlock_irqrestore(&dev->iowait_lock, flags); + + for (i = 0; i < n; i++) + hfi1_qp_wakeup(qps[i], HFI1_S_WAIT_PIO); +} + +/* translate a send credit update to a bit code of reasons */ +static inline int fill_code(u64 hw_free) +{ + int code = 0; + + if (hw_free & CR_STATUS_SMASK) + code |= PRC_STATUS_ERR; + if (hw_free & CR_CREDIT_RETURN_DUE_TO_PBC_SMASK) + code |= PRC_PBC; + if (hw_free & CR_CREDIT_RETURN_DUE_TO_THRESHOLD_SMASK) + code |= PRC_THRESHOLD; + if (hw_free & CR_CREDIT_RETURN_DUE_TO_ERR_SMASK) + code |= PRC_FILL_ERR; + if (hw_free & CR_CREDIT_RETURN_DUE_TO_FORCE_SMASK) + code |= PRC_SC_DISABLE; + return code; +} + +/* use the jiffies compare to get the wrap right */ +#define sent_before(a, b) time_before(a, b) /* a < b */ + +/* + * The send context buffer "releaser". + */ +void sc_release_update(struct send_context *sc) +{ + struct pio_buf *pbuf; + u64 hw_free; + u32 head, tail; + unsigned long old_free; + unsigned long extra; + unsigned long flags; + int code; + + if (!sc) + return; + + spin_lock_irqsave(&sc->release_lock, flags); + /* update free */ + hw_free = le64_to_cpu(*sc->hw_free); /* volatile read */ + old_free = sc->free; + extra = (((hw_free & CR_COUNTER_SMASK) >> CR_COUNTER_SHIFT) + - (old_free & CR_COUNTER_MASK)) + & CR_COUNTER_MASK; + sc->free = old_free + extra; + trace_hfi1_piofree(sc, extra); + + /* call sent buffer callbacks */ + code = -1; /* code not yet set */ + head = ACCESS_ONCE(sc->sr_head); /* snapshot the head */ + tail = sc->sr_tail; + while (head != tail) { + pbuf = &sc->sr[tail].pbuf; + + if (sent_before(sc->free, pbuf->sent_at)) { + /* not sent yet */ + break; + } + if (pbuf->cb) { + if (code < 0) /* fill in code on first user */ + code = fill_code(hw_free); + (*pbuf->cb)(pbuf->arg, code); + } + + tail++; + if (tail >= sc->sr_size) + tail = 0; + } + /* update tail, in case we moved it */ + sc->sr_tail = tail; + spin_unlock_irqrestore(&sc->release_lock, flags); + sc_piobufavail(sc); +} + +/* + * Send context group releaser. Argument is the send context that caused + * the interrupt. Called from the send context interrupt handler. + * + * Call release on all contexts in the group. + * + * This routine takes the sc_lock without an irqsave because it is only + * called from an interrupt handler. Adjust if that changes. + */ +void sc_group_release_update(struct hfi1_devdata *dd, u32 hw_context) +{ + struct send_context *sc; + u32 sw_index; + u32 gc, gc_end; + + spin_lock(&dd->sc_lock); + sw_index = dd->hw_to_sw[hw_context]; + if (unlikely(sw_index >= dd->num_send_contexts)) { + dd_dev_err(dd, "%s: invalid hw (%u) to sw (%u) mapping\n", + __func__, hw_context, sw_index); + goto done; + } + sc = dd->send_contexts[sw_index].sc; + if (unlikely(!sc)) + goto done; + + gc = group_context(hw_context, sc->group); + gc_end = gc + group_size(sc->group); + for (; gc < gc_end; gc++) { + sw_index = dd->hw_to_sw[gc]; + if (unlikely(sw_index >= dd->num_send_contexts)) { + dd_dev_err(dd, + "%s: invalid hw (%u) to sw (%u) mapping\n", + __func__, hw_context, sw_index); + continue; + } + sc_release_update(dd->send_contexts[sw_index].sc); + } +done: + spin_unlock(&dd->sc_lock); +} + +int init_pervl_scs(struct hfi1_devdata *dd) +{ + int i; + u64 mask, all_vl_mask = (u64) 0x80ff; /* VLs 0-7, 15 */ + u32 ctxt; + + dd->vld[15].sc = sc_alloc(dd, SC_KERNEL, + dd->rcd[0]->rcvhdrqentsize, dd->node); + if (!dd->vld[15].sc) + goto nomem; + hfi1_init_ctxt(dd->vld[15].sc); + dd->vld[15].mtu = enum_to_mtu(OPA_MTU_2048); + for (i = 0; i < num_vls; i++) { + /* + * Since this function does not deal with a specific + * receive context but we need the RcvHdrQ entry size, + * use the size from rcd[0]. It is guaranteed to be + * valid at this point and will remain the same for all + * receive contexts. + */ + dd->vld[i].sc = sc_alloc(dd, SC_KERNEL, + dd->rcd[0]->rcvhdrqentsize, dd->node); + if (!dd->vld[i].sc) + goto nomem; + + hfi1_init_ctxt(dd->vld[i].sc); + + /* non VL15 start with the max MTU */ + dd->vld[i].mtu = hfi1_max_mtu; + } + sc_enable(dd->vld[15].sc); + ctxt = dd->vld[15].sc->hw_context; + mask = all_vl_mask & ~(1LL << 15); + write_kctxt_csr(dd, ctxt, SC(CHECK_VL), mask); + dd_dev_info(dd, + "Using send context %u(%u) for VL15\n", + dd->vld[15].sc->sw_index, ctxt); + for (i = 0; i < num_vls; i++) { + sc_enable(dd->vld[i].sc); + ctxt = dd->vld[i].sc->hw_context; + mask = all_vl_mask & ~(1LL << i); + write_kctxt_csr(dd, ctxt, SC(CHECK_VL), mask); + } + return 0; +nomem: + sc_free(dd->vld[15].sc); + for (i = 0; i < num_vls; i++) + sc_free(dd->vld[i].sc); + return -ENOMEM; +} + +int init_credit_return(struct hfi1_devdata *dd) +{ + int ret; + int num_numa; + int i; + + num_numa = num_online_nodes(); + /* enforce the expectation that the numas are compact */ + for (i = 0; i < num_numa; i++) { + if (!node_online(i)) { + dd_dev_err(dd, "NUMA nodes are not compact\n"); + ret = -EINVAL; + goto done; + } + } + + dd->cr_base = kcalloc( + num_numa, + sizeof(struct credit_return_base), + GFP_KERNEL); + if (!dd->cr_base) { + dd_dev_err(dd, "Unable to allocate credit return base\n"); + ret = -ENOMEM; + goto done; + } + for (i = 0; i < num_numa; i++) { + int bytes = TXE_NUM_CONTEXTS * sizeof(struct credit_return); + + set_dev_node(&dd->pcidev->dev, i); + dd->cr_base[i].va = dma_zalloc_coherent( + &dd->pcidev->dev, + bytes, + &dd->cr_base[i].pa, + GFP_KERNEL); + if (dd->cr_base[i].va == NULL) { + set_dev_node(&dd->pcidev->dev, dd->node); + dd_dev_err(dd, + "Unable to allocate credit return DMA range for NUMA %d\n", + i); + ret = -ENOMEM; + goto done; + } + } + set_dev_node(&dd->pcidev->dev, dd->node); + + ret = 0; +done: + return ret; +} + +void free_credit_return(struct hfi1_devdata *dd) +{ + int num_numa; + int i; + + if (!dd->cr_base) + return; + + num_numa = num_online_nodes(); + for (i = 0; i < num_numa; i++) { + if (dd->cr_base[i].va) { + dma_free_coherent(&dd->pcidev->dev, + TXE_NUM_CONTEXTS + * sizeof(struct credit_return), + dd->cr_base[i].va, + dd->cr_base[i].pa); + } + } + kfree(dd->cr_base); + dd->cr_base = NULL; +} diff --git a/drivers/staging/rdma/hfi1/pio.h b/drivers/staging/rdma/hfi1/pio.h new file mode 100644 index 0000000000000..0bb885ca3cfb9 --- /dev/null +++ b/drivers/staging/rdma/hfi1/pio.h @@ -0,0 +1,224 @@ +#ifndef _PIO_H +#define _PIO_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + + +/* send context types */ +#define SC_KERNEL 0 +#define SC_ACK 1 +#define SC_USER 2 +#define SC_MAX 3 + +/* invalid send context index */ +#define INVALID_SCI 0xff + +/* PIO buffer release callback function */ +typedef void (*pio_release_cb)(void *arg, int code); + +/* PIO release codes - in bits, as there could more than one that apply */ +#define PRC_OK 0 /* no known error */ +#define PRC_STATUS_ERR 0x01 /* credit return due to status error */ +#define PRC_PBC 0x02 /* credit return due to PBC */ +#define PRC_THRESHOLD 0x04 /* credit return due to threshold */ +#define PRC_FILL_ERR 0x08 /* credit return due fill error */ +#define PRC_FORCE 0x10 /* credit return due credit force */ +#define PRC_SC_DISABLE 0x20 /* clean-up after a context disable */ + +/* byte helper */ +union mix { + u64 val64; + u32 val32[2]; + u8 val8[8]; +}; + +/* an allocated PIO buffer */ +struct pio_buf { + struct send_context *sc;/* back pointer to owning send context */ + pio_release_cb cb; /* called when the buffer is released */ + void *arg; /* argument for cb */ + void __iomem *start; /* buffer start address */ + void __iomem *end; /* context end address */ + unsigned long size; /* context size, in bytes */ + unsigned long sent_at; /* buffer is sent when <= free */ + u32 block_count; /* size of buffer, in blocks */ + u32 qw_written; /* QW written so far */ + u32 carry_bytes; /* number of valid bytes in carry */ + union mix carry; /* pending unwritten bytes */ +}; + +/* cache line aligned pio buffer array */ +union pio_shadow_ring { + struct pio_buf pbuf; + u64 unused[16]; /* cache line spacer */ +} ____cacheline_aligned; + +/* per-NUMA send context */ +struct send_context { + /* read-only after init */ + struct hfi1_devdata *dd; /* device */ + void __iomem *base_addr; /* start of PIO memory */ + union pio_shadow_ring *sr; /* shadow ring */ + volatile __le64 *hw_free; /* HW free counter */ + struct work_struct halt_work; /* halted context work queue entry */ + unsigned long flags; /* flags */ + int node; /* context home node */ + int type; /* context type */ + u32 sw_index; /* software index number */ + u32 hw_context; /* hardware context number */ + u32 credits; /* number of blocks in context */ + u32 sr_size; /* size of the shadow ring */ + u32 group; /* credit return group */ + /* allocator fields */ + spinlock_t alloc_lock ____cacheline_aligned_in_smp; + unsigned long fill; /* official alloc count */ + unsigned long alloc_free; /* copy of free (less cache thrash) */ + u32 sr_head; /* shadow ring head */ + /* releaser fields */ + spinlock_t release_lock ____cacheline_aligned_in_smp; + unsigned long free; /* official free count */ + u32 sr_tail; /* shadow ring tail */ + /* list for PIO waiters */ + struct list_head piowait ____cacheline_aligned_in_smp; + spinlock_t credit_ctrl_lock ____cacheline_aligned_in_smp; + u64 credit_ctrl; /* cache for credit control */ + u32 credit_intr_count; /* count of credit intr users */ + atomic_t buffers_allocated; /* count of buffers allocated */ + wait_queue_head_t halt_wait; /* wait until kernel sees interrupt */ +}; + +/* send context flags */ +#define SCF_ENABLED 0x01 +#define SCF_IN_FREE 0x02 +#define SCF_HALTED 0x04 +#define SCF_FROZEN 0x08 + +struct send_context_info { + struct send_context *sc; /* allocated working context */ + u16 allocated; /* has this been allocated? */ + u16 type; /* context type */ + u16 base; /* base in PIO array */ + u16 credits; /* size in PIO array */ +}; + +/* DMA credit return, index is always (context & 0x7) */ +struct credit_return { + volatile __le64 cr[8]; +}; + +/* NUMA indexed credit return array */ +struct credit_return_base { + struct credit_return *va; + dma_addr_t pa; +}; + +/* send context configuration sizes (one per type) */ +struct sc_config_sizes { + short int size; + short int count; +}; + +/* send context functions */ +int init_credit_return(struct hfi1_devdata *dd); +void free_credit_return(struct hfi1_devdata *dd); +int init_sc_pools_and_sizes(struct hfi1_devdata *dd); +int init_send_contexts(struct hfi1_devdata *dd); +int init_credit_return(struct hfi1_devdata *dd); +int init_pervl_scs(struct hfi1_devdata *dd); +struct send_context *sc_alloc(struct hfi1_devdata *dd, int type, + uint hdrqentsize, int numa); +void sc_free(struct send_context *sc); +int sc_enable(struct send_context *sc); +void sc_disable(struct send_context *sc); +int sc_restart(struct send_context *sc); +void sc_return_credits(struct send_context *sc); +void sc_flush(struct send_context *sc); +void sc_drop(struct send_context *sc); +void sc_stop(struct send_context *sc, int bit); +struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len, + pio_release_cb cb, void *arg); +void sc_release_update(struct send_context *sc); +void sc_return_credits(struct send_context *sc); +void sc_group_release_update(struct hfi1_devdata *dd, u32 hw_context); +void sc_add_credit_return_intr(struct send_context *sc); +void sc_del_credit_return_intr(struct send_context *sc); +void sc_set_cr_threshold(struct send_context *sc, u32 new_threshold); +u32 sc_mtu_to_threshold(struct send_context *sc, u32 mtu, u32 hdrqentsize); +void hfi1_sc_wantpiobuf_intr(struct send_context *sc, u32 needint); +void sc_wait(struct hfi1_devdata *dd); +void set_pio_integrity(struct send_context *sc); + +/* support functions */ +void pio_reset_all(struct hfi1_devdata *dd); +void pio_freeze(struct hfi1_devdata *dd); +void pio_kernel_unfreeze(struct hfi1_devdata *dd); + +/* global PIO send control operations */ +#define PSC_GLOBAL_ENABLE 0 +#define PSC_GLOBAL_DISABLE 1 +#define PSC_GLOBAL_VLARB_ENABLE 2 +#define PSC_GLOBAL_VLARB_DISABLE 3 +#define PSC_CM_RESET 4 +#define PSC_DATA_VL_ENABLE 5 +#define PSC_DATA_VL_DISABLE 6 + +void __cm_reset(struct hfi1_devdata *dd, u64 sendctrl); +void pio_send_control(struct hfi1_devdata *dd, int op); + + +/* PIO copy routines */ +void pio_copy(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc, + const void *from, size_t count); +void seg_pio_copy_start(struct pio_buf *pbuf, u64 pbc, + const void *from, size_t nbytes); +void seg_pio_copy_mid(struct pio_buf *pbuf, const void *from, size_t nbytes); +void seg_pio_copy_end(struct pio_buf *pbuf); + +#endif /* _PIO_H */ diff --git a/drivers/staging/rdma/hfi1/pio_copy.c b/drivers/staging/rdma/hfi1/pio_copy.c new file mode 100644 index 0000000000000..8972bbc020385 --- /dev/null +++ b/drivers/staging/rdma/hfi1/pio_copy.c @@ -0,0 +1,858 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "hfi.h" + +/* additive distance between non-SOP and SOP space */ +#define SOP_DISTANCE (TXE_PIO_SIZE / 2) +#define PIO_BLOCK_MASK (PIO_BLOCK_SIZE-1) +/* number of QUADWORDs in a block */ +#define PIO_BLOCK_QWS (PIO_BLOCK_SIZE/sizeof(u64)) + +/** + * pio_copy - copy data block to MMIO space + * @pbuf: a number of blocks allocated within a PIO send context + * @pbc: PBC to send + * @from: source, must be 8 byte aligned + * @count: number of DWORD (32-bit) quantities to copy from source + * + * Copy data from source to PIO Send Buffer memory, 8 bytes at a time. + * Must always write full BLOCK_SIZE bytes blocks. The first block must + * be written to the corresponding SOP=1 address. + * + * Known: + * o pbuf->start always starts on a block boundary + * o pbuf can wrap only at a block boundary + */ +void pio_copy(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc, + const void *from, size_t count) +{ + void __iomem *dest = pbuf->start + SOP_DISTANCE; + void __iomem *send = dest + PIO_BLOCK_SIZE; + void __iomem *dend; /* 8-byte data end */ + + /* write the PBC */ + writeq(pbc, dest); + dest += sizeof(u64); + + /* calculate where the QWORD data ends - in SOP=1 space */ + dend = dest + ((count>>1) * sizeof(u64)); + + if (dend < send) { + /* all QWORD data is within the SOP block, does *not* + reach the end of the SOP block */ + + while (dest < dend) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + /* + * No boundary checks are needed here: + * 0. We're not on the SOP block boundary + * 1. The possible DWORD dangle will still be within + * the SOP block + * 2. We cannot wrap except on a block boundary. + */ + } else { + /* QWORD data extends _to_ or beyond the SOP block */ + + /* write 8-byte SOP chunk data */ + while (dest < send) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + /* drop out of the SOP range */ + dest -= SOP_DISTANCE; + dend -= SOP_DISTANCE; + + /* + * If the wrap comes before or matches the data end, + * copy until until the wrap, then wrap. + * + * If the data ends at the end of the SOP above and + * the buffer wraps, then pbuf->end == dend == dest + * and nothing will get written, but we will wrap in + * case there is a dangling DWORD. + */ + if (pbuf->end <= dend) { + while (dest < pbuf->end) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + + dest -= pbuf->size; + dend -= pbuf->size; + } + + /* write 8-byte non-SOP, non-wrap chunk data */ + while (dest < dend) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + } + /* at this point we have wrapped if we are going to wrap */ + + /* write dangling u32, if any */ + if (count & 1) { + union mix val; + + val.val64 = 0; + val.val32[0] = *(u32 *)from; + writeq(val.val64, dest); + dest += sizeof(u64); + } + /* fill in rest of block, no need to check pbuf->end + as we only wrap on a block boundary */ + while (((unsigned long)dest & PIO_BLOCK_MASK) != 0) { + writeq(0, dest); + dest += sizeof(u64); + } + + /* finished with this buffer */ + atomic_dec(&pbuf->sc->buffers_allocated); +} + +/* USE_SHIFTS is faster in user-space tests on a Xeon X5570 @ 2.93GHz */ +#define USE_SHIFTS 1 +#ifdef USE_SHIFTS +/* + * Handle carry bytes using shifts and masks. + * + * NOTE: the value the unused portion of carry is expected to always be zero. + */ + +/* + * "zero" shift - bit shift used to zero out upper bytes. Input is + * the count of LSB bytes to preserve. + */ +#define zshift(x) (8 * (8-(x))) + +/* + * "merge" shift - bit shift used to merge with carry bytes. Input is + * the LSB byte count to move beyond. + */ +#define mshift(x) (8 * (x)) + +/* + * Read nbytes bytes from "from" and return them in the LSB bytes + * of pbuf->carry. Other bytes are zeroed. Any previous value + * pbuf->carry is lost. + * + * NOTES: + * o do not read from from if nbytes is zero + * o from may _not_ be u64 aligned + * o nbytes must not span a QW boundary + */ +static inline void read_low_bytes(struct pio_buf *pbuf, const void *from, + unsigned int nbytes) +{ + unsigned long off; + + if (nbytes == 0) { + pbuf->carry.val64 = 0; + } else { + /* align our pointer */ + off = (unsigned long)from & 0x7; + from = (void *)((unsigned long)from & ~0x7l); + pbuf->carry.val64 = ((*(u64 *)from) + << zshift(nbytes + off))/* zero upper bytes */ + >> zshift(nbytes); /* place at bottom */ + } + pbuf->carry_bytes = nbytes; +} + +/* + * Read nbytes bytes from "from" and put them at the next significant bytes + * of pbuf->carry. Unused bytes are zeroed. It is expected that the extra + * read does not overfill carry. + * + * NOTES: + * o from may _not_ be u64 aligned + * o nbytes may span a QW boundary + */ +static inline void read_extra_bytes(struct pio_buf *pbuf, + const void *from, unsigned int nbytes) +{ + unsigned long off = (unsigned long)from & 0x7; + unsigned int room, xbytes; + + /* align our pointer */ + from = (void *)((unsigned long)from & ~0x7l); + + /* check count first - don't read anything if count is zero */ + while (nbytes) { + /* find the number of bytes in this u64 */ + room = 8 - off; /* this u64 has room for this many bytes */ + xbytes = nbytes > room ? room : nbytes; + + /* + * shift down to zero lower bytes, shift up to zero upper + * bytes, shift back down to move into place + */ + pbuf->carry.val64 |= (((*(u64 *)from) + >> mshift(off)) + << zshift(xbytes)) + >> zshift(xbytes+pbuf->carry_bytes); + off = 0; + pbuf->carry_bytes += xbytes; + nbytes -= xbytes; + from += sizeof(u64); + } +} + +/* + * Zero extra bytes from the end of pbuf->carry. + * + * NOTES: + * o zbytes <= old_bytes + */ +static inline void zero_extra_bytes(struct pio_buf *pbuf, unsigned int zbytes) +{ + unsigned int remaining; + + if (zbytes == 0) /* nothing to do */ + return; + + remaining = pbuf->carry_bytes - zbytes; /* remaining bytes */ + + /* NOTE: zshift only guaranteed to work if remaining != 0 */ + if (remaining) + pbuf->carry.val64 = (pbuf->carry.val64 << zshift(remaining)) + >> zshift(remaining); + else + pbuf->carry.val64 = 0; + pbuf->carry_bytes = remaining; +} + +/* + * Write a quad word using parts of pbuf->carry and the next 8 bytes of src. + * Put the unused part of the next 8 bytes of src into the LSB bytes of + * pbuf->carry with the upper bytes zeroed.. + * + * NOTES: + * o result must keep unused bytes zeroed + * o src must be u64 aligned + */ +static inline void merge_write8( + struct pio_buf *pbuf, + void __iomem *dest, + const void *src) +{ + u64 new, temp; + + new = *(u64 *)src; + temp = pbuf->carry.val64 | (new << mshift(pbuf->carry_bytes)); + writeq(temp, dest); + pbuf->carry.val64 = new >> zshift(pbuf->carry_bytes); +} + +/* + * Write a quad word using all bytes of carry. + */ +static inline void carry8_write8(union mix carry, void __iomem *dest) +{ + writeq(carry.val64, dest); +} + +/* + * Write a quad word using all the valid bytes of carry. If carry + * has zero valid bytes, nothing is written. + * Returns 0 on nothing written, non-zero on quad word written. + */ +static inline int carry_write8(struct pio_buf *pbuf, void __iomem *dest) +{ + if (pbuf->carry_bytes) { + /* unused bytes are always kept zeroed, so just write */ + writeq(pbuf->carry.val64, dest); + return 1; + } + + return 0; +} + +#else /* USE_SHIFTS */ +/* + * Handle carry bytes using byte copies. + * + * NOTE: the value the unused portion of carry is left uninitialized. + */ + +/* + * Jump copy - no-loop copy for < 8 bytes. + */ +static inline void jcopy(u8 *dest, const u8 *src, u32 n) +{ + switch (n) { + case 7: + *dest++ = *src++; + case 6: + *dest++ = *src++; + case 5: + *dest++ = *src++; + case 4: + *dest++ = *src++; + case 3: + *dest++ = *src++; + case 2: + *dest++ = *src++; + case 1: + *dest++ = *src++; + } +} + +/* + * Read nbytes from "from" and and place them in the low bytes + * of pbuf->carry. Other bytes are left as-is. Any previous + * value in pbuf->carry is lost. + * + * NOTES: + * o do not read from from if nbytes is zero + * o from may _not_ be u64 aligned. + */ +static inline void read_low_bytes(struct pio_buf *pbuf, const void *from, + unsigned int nbytes) +{ + jcopy(&pbuf->carry.val8[0], from, nbytes); + pbuf->carry_bytes = nbytes; +} + +/* + * Read nbytes bytes from "from" and put them at the end of pbuf->carry. + * It is expected that the extra read does not overfill carry. + * + * NOTES: + * o from may _not_ be u64 aligned + * o nbytes may span a QW boundary + */ +static inline void read_extra_bytes(struct pio_buf *pbuf, + const void *from, unsigned int nbytes) +{ + jcopy(&pbuf->carry.val8[pbuf->carry_bytes], from, nbytes); + pbuf->carry_bytes += nbytes; +} + +/* + * Zero extra bytes from the end of pbuf->carry. + * + * We do not care about the value of unused bytes in carry, so just + * reduce the byte count. + * + * NOTES: + * o zbytes <= old_bytes + */ +static inline void zero_extra_bytes(struct pio_buf *pbuf, unsigned int zbytes) +{ + pbuf->carry_bytes -= zbytes; +} + +/* + * Write a quad word using parts of pbuf->carry and the next 8 bytes of src. + * Put the unused part of the next 8 bytes of src into the low bytes of + * pbuf->carry. + */ +static inline void merge_write8( + struct pio_buf *pbuf, + void *dest, + const void *src) +{ + u32 remainder = 8 - pbuf->carry_bytes; + + jcopy(&pbuf->carry.val8[pbuf->carry_bytes], src, remainder); + writeq(pbuf->carry.val64, dest); + jcopy(&pbuf->carry.val8[0], src+remainder, pbuf->carry_bytes); +} + +/* + * Write a quad word using all bytes of carry. + */ +static inline void carry8_write8(union mix carry, void *dest) +{ + writeq(carry.val64, dest); +} + +/* + * Write a quad word using all the valid bytes of carry. If carry + * has zero valid bytes, nothing is written. + * Returns 0 on nothing written, non-zero on quad word written. + */ +static inline int carry_write8(struct pio_buf *pbuf, void *dest) +{ + if (pbuf->carry_bytes) { + u64 zero = 0; + + jcopy(&pbuf->carry.val8[pbuf->carry_bytes], (u8 *)&zero, + 8 - pbuf->carry_bytes); + writeq(pbuf->carry.val64, dest); + return 1; + } + + return 0; +} +#endif /* USE_SHIFTS */ + +/* + * Segmented PIO Copy - start + * + * Start a PIO copy. + * + * @pbuf: destination buffer + * @pbc: the PBC for the PIO buffer + * @from: data source, QWORD aligned + * @nbytes: bytes to copy + */ +void seg_pio_copy_start(struct pio_buf *pbuf, u64 pbc, + const void *from, size_t nbytes) +{ + void __iomem *dest = pbuf->start + SOP_DISTANCE; + void __iomem *send = dest + PIO_BLOCK_SIZE; + void __iomem *dend; /* 8-byte data end */ + + writeq(pbc, dest); + dest += sizeof(u64); + + /* calculate where the QWORD data ends - in SOP=1 space */ + dend = dest + ((nbytes>>3) * sizeof(u64)); + + if (dend < send) { + /* all QWORD data is within the SOP block, does *not* + reach the end of the SOP block */ + + while (dest < dend) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + /* + * No boundary checks are needed here: + * 0. We're not on the SOP block boundary + * 1. The possible DWORD dangle will still be within + * the SOP block + * 2. We cannot wrap except on a block boundary. + */ + } else { + /* QWORD data extends _to_ or beyond the SOP block */ + + /* write 8-byte SOP chunk data */ + while (dest < send) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + /* drop out of the SOP range */ + dest -= SOP_DISTANCE; + dend -= SOP_DISTANCE; + + /* + * If the wrap comes before or matches the data end, + * copy until until the wrap, then wrap. + * + * If the data ends at the end of the SOP above and + * the buffer wraps, then pbuf->end == dend == dest + * and nothing will get written, but we will wrap in + * case there is a dangling DWORD. + */ + if (pbuf->end <= dend) { + while (dest < pbuf->end) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + + dest -= pbuf->size; + dend -= pbuf->size; + } + + /* write 8-byte non-SOP, non-wrap chunk data */ + while (dest < dend) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + } + /* at this point we have wrapped if we are going to wrap */ + + /* ...but it doesn't matter as we're done writing */ + + /* save dangling bytes, if any */ + read_low_bytes(pbuf, from, nbytes & 0x7); + + pbuf->qw_written = 1 /*PBC*/ + (nbytes >> 3); +} + +/* + * Mid copy helper, "mixed case" - source is 64-bit aligned but carry + * bytes are non-zero. + * + * Whole u64s must be written to the chip, so bytes must be manually merged. + * + * @pbuf: destination buffer + * @from: data source, is QWORD aligned. + * @nbytes: bytes to copy + * + * Must handle nbytes < 8. + */ +static void mid_copy_mix(struct pio_buf *pbuf, const void *from, size_t nbytes) +{ + void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64)); + void __iomem *dend; /* 8-byte data end */ + unsigned long qw_to_write = (pbuf->carry_bytes + nbytes) >> 3; + unsigned long bytes_left = (pbuf->carry_bytes + nbytes) & 0x7; + + /* calculate 8-byte data end */ + dend = dest + (qw_to_write * sizeof(u64)); + + if (pbuf->qw_written < PIO_BLOCK_QWS) { + /* + * Still within SOP block. We don't need to check for + * wrap because we are still in the first block and + * can only wrap on block boundaries. + */ + void __iomem *send; /* SOP end */ + void __iomem *xend; + + /* calculate the end of data or end of block, whichever + comes first */ + send = pbuf->start + PIO_BLOCK_SIZE; + xend = send < dend ? send : dend; + + /* shift up to SOP=1 space */ + dest += SOP_DISTANCE; + xend += SOP_DISTANCE; + + /* write 8-byte chunk data */ + while (dest < xend) { + merge_write8(pbuf, dest, from); + from += sizeof(u64); + dest += sizeof(u64); + } + + /* shift down to SOP=0 space */ + dest -= SOP_DISTANCE; + } + /* + * At this point dest could be (either, both, or neither): + * - at dend + * - at the wrap + */ + + /* + * If the wrap comes before or matches the data end, + * copy until until the wrap, then wrap. + * + * If dest is at the wrap, we will fall into the if, + * not do the loop, when wrap. + * + * If the data ends at the end of the SOP above and + * the buffer wraps, then pbuf->end == dend == dest + * and nothing will get written. + */ + if (pbuf->end <= dend) { + while (dest < pbuf->end) { + merge_write8(pbuf, dest, from); + from += sizeof(u64); + dest += sizeof(u64); + } + + dest -= pbuf->size; + dend -= pbuf->size; + } + + /* write 8-byte non-SOP, non-wrap chunk data */ + while (dest < dend) { + merge_write8(pbuf, dest, from); + from += sizeof(u64); + dest += sizeof(u64); + } + + /* adjust carry */ + if (pbuf->carry_bytes < bytes_left) { + /* need to read more */ + read_extra_bytes(pbuf, from, bytes_left - pbuf->carry_bytes); + } else { + /* remove invalid bytes */ + zero_extra_bytes(pbuf, pbuf->carry_bytes - bytes_left); + } + + pbuf->qw_written += qw_to_write; +} + +/* + * Mid copy helper, "straight case" - source pointer is 64-bit aligned + * with no carry bytes. + * + * @pbuf: destination buffer + * @from: data source, is QWORD aligned + * @nbytes: bytes to copy + * + * Must handle nbytes < 8. + */ +static void mid_copy_straight(struct pio_buf *pbuf, + const void *from, size_t nbytes) +{ + void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64)); + void __iomem *dend; /* 8-byte data end */ + + /* calculate 8-byte data end */ + dend = dest + ((nbytes>>3) * sizeof(u64)); + + if (pbuf->qw_written < PIO_BLOCK_QWS) { + /* + * Still within SOP block. We don't need to check for + * wrap because we are still in the first block and + * can only wrap on block boundaries. + */ + void __iomem *send; /* SOP end */ + void __iomem *xend; + + /* calculate the end of data or end of block, whichever + comes first */ + send = pbuf->start + PIO_BLOCK_SIZE; + xend = send < dend ? send : dend; + + /* shift up to SOP=1 space */ + dest += SOP_DISTANCE; + xend += SOP_DISTANCE; + + /* write 8-byte chunk data */ + while (dest < xend) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + + /* shift down to SOP=0 space */ + dest -= SOP_DISTANCE; + } + /* + * At this point dest could be (either, both, or neither): + * - at dend + * - at the wrap + */ + + /* + * If the wrap comes before or matches the data end, + * copy until until the wrap, then wrap. + * + * If dest is at the wrap, we will fall into the if, + * not do the loop, when wrap. + * + * If the data ends at the end of the SOP above and + * the buffer wraps, then pbuf->end == dend == dest + * and nothing will get written. + */ + if (pbuf->end <= dend) { + while (dest < pbuf->end) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + + dest -= pbuf->size; + dend -= pbuf->size; + } + + /* write 8-byte non-SOP, non-wrap chunk data */ + while (dest < dend) { + writeq(*(u64 *)from, dest); + from += sizeof(u64); + dest += sizeof(u64); + } + + /* we know carry_bytes was zero on entry to this routine */ + read_low_bytes(pbuf, from, nbytes & 0x7); + + pbuf->qw_written += nbytes>>3; +} + +/* + * Segmented PIO Copy - middle + * + * Must handle any aligned tail and any aligned source with any byte count. + * + * @pbuf: a number of blocks allocated within a PIO send context + * @from: data source + * @nbytes: number of bytes to copy + */ +void seg_pio_copy_mid(struct pio_buf *pbuf, const void *from, size_t nbytes) +{ + unsigned long from_align = (unsigned long)from & 0x7; + + if (pbuf->carry_bytes + nbytes < 8) { + /* not enough bytes to fill a QW */ + read_extra_bytes(pbuf, from, nbytes); + return; + } + + if (from_align) { + /* misaligned source pointer - align it */ + unsigned long to_align; + + /* bytes to read to align "from" */ + to_align = 8 - from_align; + + /* + * In the advance-to-alignment logic below, we do not need + * to check if we are using more than nbytes. This is because + * if we are here, we already know that carry+nbytes will + * fill at least one QW. + */ + if (pbuf->carry_bytes + to_align < 8) { + /* not enough align bytes to fill a QW */ + read_extra_bytes(pbuf, from, to_align); + from += to_align; + nbytes -= to_align; + } else { + /* bytes to fill carry */ + unsigned long to_fill = 8 - pbuf->carry_bytes; + /* bytes left over to be read */ + unsigned long extra = to_align - to_fill; + void __iomem *dest; + + /* fill carry... */ + read_extra_bytes(pbuf, from, to_fill); + from += to_fill; + nbytes -= to_fill; + + /* ...now write carry */ + dest = pbuf->start + (pbuf->qw_written * sizeof(u64)); + + /* + * The two checks immediately below cannot both be + * true, hence the else. If we have wrapped, we + * cannot still be within the first block. + * Conversely, if we are still in the first block, we + * cannot have wrapped. We do the wrap check first + * as that is more likely. + */ + /* adjust if we've wrapped */ + if (dest >= pbuf->end) + dest -= pbuf->size; + /* jump to SOP range if within the first block */ + else if (pbuf->qw_written < PIO_BLOCK_QWS) + dest += SOP_DISTANCE; + + carry8_write8(pbuf->carry, dest); + pbuf->qw_written++; + + /* read any extra bytes to do final alignment */ + /* this will overwrite anything in pbuf->carry */ + read_low_bytes(pbuf, from, extra); + from += extra; + nbytes -= extra; + } + + /* at this point, from is QW aligned */ + } + + if (pbuf->carry_bytes) + mid_copy_mix(pbuf, from, nbytes); + else + mid_copy_straight(pbuf, from, nbytes); +} + +/* + * Segmented PIO Copy - end + * + * Write any remainder (in pbuf->carry) and finish writing the whole block. + * + * @pbuf: a number of blocks allocated within a PIO send context + */ +void seg_pio_copy_end(struct pio_buf *pbuf) +{ + void __iomem *dest = pbuf->start + (pbuf->qw_written * sizeof(u64)); + + /* + * The two checks immediately below cannot both be true, hence the + * else. If we have wrapped, we cannot still be within the first + * block. Conversely, if we are still in the first block, we + * cannot have wrapped. We do the wrap check first as that is + * more likely. + */ + /* adjust if we have wrapped */ + if (dest >= pbuf->end) + dest -= pbuf->size; + /* jump to the SOP range if within the first block */ + else if (pbuf->qw_written < PIO_BLOCK_QWS) + dest += SOP_DISTANCE; + + /* write final bytes, if any */ + if (carry_write8(pbuf, dest)) { + dest += sizeof(u64); + /* + * NOTE: We do not need to recalculate whether dest needs + * SOP_DISTANCE or not. + * + * If we are in the first block and the dangle write + * keeps us in the same block, dest will need + * to retain SOP_DISTANCE in the loop below. + * + * If we are in the first block and the dangle write pushes + * us to the next block, then loop below will not run + * and dest is not used. Hence we do not need to update + * it. + * + * If we are past the first block, then SOP_DISTANCE + * was never added, so there is nothing to do. + */ + } + + /* fill in rest of block */ + while (((unsigned long)dest & PIO_BLOCK_MASK) != 0) { + writeq(0, dest); + dest += sizeof(u64); + } + + /* finished with this buffer */ + atomic_dec(&pbuf->sc->buffers_allocated); +} diff --git a/drivers/staging/rdma/hfi1/platform_config.h b/drivers/staging/rdma/hfi1/platform_config.h new file mode 100644 index 0000000000000..8a94a83420526 --- /dev/null +++ b/drivers/staging/rdma/hfi1/platform_config.h @@ -0,0 +1,286 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#ifndef __PLATFORM_CONFIG_H +#define __PLATFORM_CONFIG_H + +#define METADATA_TABLE_FIELD_START_SHIFT 0 +#define METADATA_TABLE_FIELD_START_LEN_BITS 15 +#define METADATA_TABLE_FIELD_LEN_SHIFT 16 +#define METADATA_TABLE_FIELD_LEN_LEN_BITS 16 + +/* Header structure */ +#define PLATFORM_CONFIG_HEADER_RECORD_IDX_SHIFT 0 +#define PLATFORM_CONFIG_HEADER_RECORD_IDX_LEN_BITS 6 +#define PLATFORM_CONFIG_HEADER_TABLE_LENGTH_SHIFT 16 +#define PLATFORM_CONFIG_HEADER_TABLE_LENGTH_LEN_BITS 12 +#define PLATFORM_CONFIG_HEADER_TABLE_TYPE_SHIFT 28 +#define PLATFORM_CONFIG_HEADER_TABLE_TYPE_LEN_BITS 4 + +enum platform_config_table_type_encoding { + PLATFORM_CONFIG_TABLE_RESERVED, + PLATFORM_CONFIG_SYSTEM_TABLE, + PLATFORM_CONFIG_PORT_TABLE, + PLATFORM_CONFIG_RX_PRESET_TABLE, + PLATFORM_CONFIG_TX_PRESET_TABLE, + PLATFORM_CONFIG_QSFP_ATTEN_TABLE, + PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE, + PLATFORM_CONFIG_TABLE_MAX +}; + +enum platform_config_system_table_fields { + SYSTEM_TABLE_RESERVED, + SYSTEM_TABLE_NODE_STRING, + SYSTEM_TABLE_SYSTEM_IMAGE_GUID, + SYSTEM_TABLE_NODE_GUID, + SYSTEM_TABLE_REVISION, + SYSTEM_TABLE_VENDOR_OUI, + SYSTEM_TABLE_META_VERSION, + SYSTEM_TABLE_DEVICE_ID, + SYSTEM_TABLE_PARTITION_ENFORCEMENT_CAP, + SYSTEM_TABLE_QSFP_POWER_CLASS_MAX, + SYSTEM_TABLE_QSFP_ATTENUATION_DEFAULT_12G, + SYSTEM_TABLE_QSFP_ATTENUATION_DEFAULT_25G, + SYSTEM_TABLE_VARIABLE_TABLE_ENTRIES_PER_PORT, + SYSTEM_TABLE_MAX +}; + +enum platform_config_port_table_fields { + PORT_TABLE_RESERVED, + PORT_TABLE_PORT_TYPE, + PORT_TABLE_ATTENUATION_12G, + PORT_TABLE_ATTENUATION_25G, + PORT_TABLE_LINK_SPEED_SUPPORTED, + PORT_TABLE_LINK_WIDTH_SUPPORTED, + PORT_TABLE_VL_CAP, + PORT_TABLE_MTU_CAP, + PORT_TABLE_TX_LANE_ENABLE_MASK, + PORT_TABLE_LOCAL_MAX_TIMEOUT, + PORT_TABLE_AUTO_LANE_SHEDDING_ENABLED, + PORT_TABLE_EXTERNAL_LOOPBACK_ALLOWED, + PORT_TABLE_TX_PRESET_IDX_PASSIVE_CU, + PORT_TABLE_TX_PRESET_IDX_ACTIVE_NO_EQ, + PORT_TABLE_TX_PRESET_IDX_ACTIVE_EQ, + PORT_TABLE_RX_PRESET_IDX, + PORT_TABLE_CABLE_REACH_CLASS, + PORT_TABLE_MAX +}; + +enum platform_config_rx_preset_table_fields { + RX_PRESET_TABLE_RESERVED, + RX_PRESET_TABLE_QSFP_RX_CDR_APPLY, + RX_PRESET_TABLE_QSFP_RX_EQ_APPLY, + RX_PRESET_TABLE_QSFP_RX_AMP_APPLY, + RX_PRESET_TABLE_QSFP_RX_CDR, + RX_PRESET_TABLE_QSFP_RX_EQ, + RX_PRESET_TABLE_QSFP_RX_AMP, + RX_PRESET_TABLE_MAX +}; + +enum platform_config_tx_preset_table_fields { + TX_PRESET_TABLE_RESERVED, + TX_PRESET_TABLE_PRECUR, + TX_PRESET_TABLE_ATTN, + TX_PRESET_TABLE_POSTCUR, + TX_PRESET_TABLE_QSFP_TX_CDR_APPLY, + TX_PRESET_TABLE_QSFP_TX_EQ_APPLY, + TX_PRESET_TABLE_QSFP_TX_CDR, + TX_PRESET_TABLE_QSFP_TX_EQ, + TX_PRESET_TABLE_MAX +}; + +enum platform_config_qsfp_attn_table_fields { + QSFP_ATTEN_TABLE_RESERVED, + QSFP_ATTEN_TABLE_TX_PRESET_IDX, + QSFP_ATTEN_TABLE_RX_PRESET_IDX, + QSFP_ATTEN_TABLE_MAX +}; + +enum platform_config_variable_settings_table_fields { + VARIABLE_SETTINGS_TABLE_RESERVED, + VARIABLE_SETTINGS_TABLE_TX_PRESET_IDX, + VARIABLE_SETTINGS_TABLE_RX_PRESET_IDX, + VARIABLE_SETTINGS_TABLE_MAX +}; + +struct platform_config_data { + u32 *table; + u32 *table_metadata; + u32 num_table; +}; + +/* + * This struct acts as a quick reference into the platform_data binary image + * and is populated by parse_platform_config(...) depending on the specific + * META_VERSION + */ +struct platform_config_cache { + u8 cache_valid; + struct platform_config_data config_tables[PLATFORM_CONFIG_TABLE_MAX]; +}; + +static const u32 platform_config_table_limits[PLATFORM_CONFIG_TABLE_MAX] = { + 0, + SYSTEM_TABLE_MAX, + PORT_TABLE_MAX, + RX_PRESET_TABLE_MAX, + TX_PRESET_TABLE_MAX, + QSFP_ATTEN_TABLE_MAX, + VARIABLE_SETTINGS_TABLE_MAX +}; + +/* This section defines default values and encodings for the + * fields defined for each table above + */ + +/*===================================================== + * System table encodings + *====================================================*/ +#define PLATFORM_CONFIG_MAGIC_NUM 0x3d4f5041 +#define PLATFORM_CONFIG_MAGIC_NUMBER_LEN 4 + +/* + * These power classes are the same as defined in SFF 8636 spec rev 2.4 + * describing byte 129 in table 6-16, except enumerated in a different order + */ +enum platform_config_qsfp_power_class_encoding { + QSFP_POWER_CLASS_1 = 1, + QSFP_POWER_CLASS_2, + QSFP_POWER_CLASS_3, + QSFP_POWER_CLASS_4, + QSFP_POWER_CLASS_5, + QSFP_POWER_CLASS_6, + QSFP_POWER_CLASS_7 +}; + + +/*===================================================== + * Port table encodings + *==================================================== */ +enum platform_config_port_type_encoding { + PORT_TYPE_RESERVED, + PORT_TYPE_DISCONNECTED, + PORT_TYPE_FIXED, + PORT_TYPE_VARIABLE, + PORT_TYPE_QSFP, + PORT_TYPE_MAX +}; + +enum platform_config_link_speed_supported_encoding { + LINK_SPEED_SUPP_12G = 1, + LINK_SPEED_SUPP_25G, + LINK_SPEED_SUPP_12G_25G, + LINK_SPEED_SUPP_MAX +}; + +/* + * This is a subset (not strict) of the link downgrades + * supported. The link downgrades supported are expected + * to be supplied to the driver by another entity such as + * the fabric manager + */ +enum platform_config_link_width_supported_encoding { + LINK_WIDTH_SUPP_1X = 1, + LINK_WIDTH_SUPP_2X, + LINK_WIDTH_SUPP_2X_1X, + LINK_WIDTH_SUPP_3X, + LINK_WIDTH_SUPP_3X_1X, + LINK_WIDTH_SUPP_3X_2X, + LINK_WIDTH_SUPP_3X_2X_1X, + LINK_WIDTH_SUPP_4X, + LINK_WIDTH_SUPP_4X_1X, + LINK_WIDTH_SUPP_4X_2X, + LINK_WIDTH_SUPP_4X_2X_1X, + LINK_WIDTH_SUPP_4X_3X, + LINK_WIDTH_SUPP_4X_3X_1X, + LINK_WIDTH_SUPP_4X_3X_2X, + LINK_WIDTH_SUPP_4X_3X_2X_1X, + LINK_WIDTH_SUPP_MAX +}; + +enum platform_config_virtual_lane_capability_encoding { + VL_CAP_VL0 = 1, + VL_CAP_VL0_1, + VL_CAP_VL0_2, + VL_CAP_VL0_3, + VL_CAP_VL0_4, + VL_CAP_VL0_5, + VL_CAP_VL0_6, + VL_CAP_VL0_7, + VL_CAP_VL0_8, + VL_CAP_VL0_9, + VL_CAP_VL0_10, + VL_CAP_VL0_11, + VL_CAP_VL0_12, + VL_CAP_VL0_13, + VL_CAP_VL0_14, + VL_CAP_MAX +}; + +/* Max MTU */ +enum platform_config_mtu_capability_encoding { + MTU_CAP_256 = 1, + MTU_CAP_512 = 2, + MTU_CAP_1024 = 3, + MTU_CAP_2048 = 4, + MTU_CAP_4096 = 5, + MTU_CAP_8192 = 6, + MTU_CAP_10240 = 7 +}; + +enum platform_config_local_max_timeout_encoding { + LOCAL_MAX_TIMEOUT_10_MS = 1, + LOCAL_MAX_TIMEOUT_100_MS, + LOCAL_MAX_TIMEOUT_1_S, + LOCAL_MAX_TIMEOUT_10_S, + LOCAL_MAX_TIMEOUT_100_S, + LOCAL_MAX_TIMEOUT_1000_S +}; + +#endif /*__PLATFORM_CONFIG_H*/ diff --git a/drivers/staging/rdma/hfi1/qp.c b/drivers/staging/rdma/hfi1/qp.c new file mode 100644 index 0000000000000..df1fa56eaf851 --- /dev/null +++ b/drivers/staging/rdma/hfi1/qp.c @@ -0,0 +1,1687 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "qp.h" +#include "trace.h" +#include "sdma.h" + +#define BITS_PER_PAGE (PAGE_SIZE*BITS_PER_BYTE) +#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) + +static unsigned int hfi1_qp_table_size = 256; +module_param_named(qp_table_size, hfi1_qp_table_size, uint, S_IRUGO); +MODULE_PARM_DESC(qp_table_size, "QP table size"); + +static void flush_tx_list(struct hfi1_qp *qp); +static int iowait_sleep( + struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *stx, + unsigned seq); +static void iowait_wakeup(struct iowait *wait, int reason); + +static inline unsigned mk_qpn(struct hfi1_qpn_table *qpt, + struct qpn_map *map, unsigned off) +{ + return (map - qpt->map) * BITS_PER_PAGE + off; +} + +/* + * Convert the AETH credit code into the number of credits. + */ +static const u16 credit_table[31] = { + 0, /* 0 */ + 1, /* 1 */ + 2, /* 2 */ + 3, /* 3 */ + 4, /* 4 */ + 6, /* 5 */ + 8, /* 6 */ + 12, /* 7 */ + 16, /* 8 */ + 24, /* 9 */ + 32, /* A */ + 48, /* B */ + 64, /* C */ + 96, /* D */ + 128, /* E */ + 192, /* F */ + 256, /* 10 */ + 384, /* 11 */ + 512, /* 12 */ + 768, /* 13 */ + 1024, /* 14 */ + 1536, /* 15 */ + 2048, /* 16 */ + 3072, /* 17 */ + 4096, /* 18 */ + 6144, /* 19 */ + 8192, /* 1A */ + 12288, /* 1B */ + 16384, /* 1C */ + 24576, /* 1D */ + 32768 /* 1E */ +}; + +static void get_map_page(struct hfi1_qpn_table *qpt, struct qpn_map *map) +{ + unsigned long page = get_zeroed_page(GFP_KERNEL); + + /* + * Free the page if someone raced with us installing it. + */ + + spin_lock(&qpt->lock); + if (map->page) + free_page(page); + else + map->page = (void *)page; + spin_unlock(&qpt->lock); +} + +/* + * Allocate the next available QPN or + * zero/one for QP type IB_QPT_SMI/IB_QPT_GSI. + */ +static int alloc_qpn(struct hfi1_devdata *dd, struct hfi1_qpn_table *qpt, + enum ib_qp_type type, u8 port) +{ + u32 i, offset, max_scan, qpn; + struct qpn_map *map; + u32 ret; + + if (type == IB_QPT_SMI || type == IB_QPT_GSI) { + unsigned n; + + ret = type == IB_QPT_GSI; + n = 1 << (ret + 2 * (port - 1)); + spin_lock(&qpt->lock); + if (qpt->flags & n) + ret = -EINVAL; + else + qpt->flags |= n; + spin_unlock(&qpt->lock); + goto bail; + } + + qpn = qpt->last + qpt->incr; + if (qpn >= QPN_MAX) + qpn = qpt->incr | ((qpt->last & 1) ^ 1); + /* offset carries bit 0 */ + offset = qpn & BITS_PER_PAGE_MASK; + map = &qpt->map[qpn / BITS_PER_PAGE]; + max_scan = qpt->nmaps - !offset; + for (i = 0;;) { + if (unlikely(!map->page)) { + get_map_page(qpt, map); + if (unlikely(!map->page)) + break; + } + do { + if (!test_and_set_bit(offset, map->page)) { + qpt->last = qpn; + ret = qpn; + goto bail; + } + offset += qpt->incr; + /* + * This qpn might be bogus if offset >= BITS_PER_PAGE. + * That is OK. It gets re-assigned below + */ + qpn = mk_qpn(qpt, map, offset); + } while (offset < BITS_PER_PAGE && qpn < QPN_MAX); + /* + * In order to keep the number of pages allocated to a + * minimum, we scan the all existing pages before increasing + * the size of the bitmap table. + */ + if (++i > max_scan) { + if (qpt->nmaps == QPNMAP_ENTRIES) + break; + map = &qpt->map[qpt->nmaps++]; + /* start at incr with current bit 0 */ + offset = qpt->incr | (offset & 1); + } else if (map < &qpt->map[qpt->nmaps]) { + ++map; + /* start at incr with current bit 0 */ + offset = qpt->incr | (offset & 1); + } else { + map = &qpt->map[0]; + /* wrap to first map page, invert bit 0 */ + offset = qpt->incr | ((offset & 1) ^ 1); + } + /* there can be no bits at shift and below */ + WARN_ON(offset & (dd->qos_shift - 1)); + qpn = mk_qpn(qpt, map, offset); + } + + ret = -ENOMEM; + +bail: + return ret; +} + +static void free_qpn(struct hfi1_qpn_table *qpt, u32 qpn) +{ + struct qpn_map *map; + + map = qpt->map + qpn / BITS_PER_PAGE; + if (map->page) + clear_bit(qpn & BITS_PER_PAGE_MASK, map->page); +} + +/* + * Put the QP into the hash table. + * The hash table holds a reference to the QP. + */ +static void insert_qp(struct hfi1_ibdev *dev, struct hfi1_qp *qp) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + unsigned long flags; + + atomic_inc(&qp->refcount); + spin_lock_irqsave(&dev->qp_dev->qpt_lock, flags); + + if (qp->ibqp.qp_num <= 1) { + rcu_assign_pointer(ibp->qp[qp->ibqp.qp_num], qp); + } else { + u32 n = qpn_hash(dev->qp_dev, qp->ibqp.qp_num); + + qp->next = dev->qp_dev->qp_table[n]; + rcu_assign_pointer(dev->qp_dev->qp_table[n], qp); + trace_hfi1_qpinsert(qp, n); + } + + spin_unlock_irqrestore(&dev->qp_dev->qpt_lock, flags); +} + +/* + * Remove the QP from the table so it can't be found asynchronously by + * the receive interrupt routine. + */ +static void remove_qp(struct hfi1_ibdev *dev, struct hfi1_qp *qp) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + u32 n = qpn_hash(dev->qp_dev, qp->ibqp.qp_num); + unsigned long flags; + int removed = 1; + + spin_lock_irqsave(&dev->qp_dev->qpt_lock, flags); + + if (rcu_dereference_protected(ibp->qp[0], + lockdep_is_held(&dev->qp_dev->qpt_lock)) == qp) { + RCU_INIT_POINTER(ibp->qp[0], NULL); + } else if (rcu_dereference_protected(ibp->qp[1], + lockdep_is_held(&dev->qp_dev->qpt_lock)) == qp) { + RCU_INIT_POINTER(ibp->qp[1], NULL); + } else { + struct hfi1_qp *q; + struct hfi1_qp __rcu **qpp; + + removed = 0; + qpp = &dev->qp_dev->qp_table[n]; + for (; (q = rcu_dereference_protected(*qpp, + lockdep_is_held(&dev->qp_dev->qpt_lock))) + != NULL; + qpp = &q->next) + if (q == qp) { + RCU_INIT_POINTER(*qpp, + rcu_dereference_protected(qp->next, + lockdep_is_held(&dev->qp_dev->qpt_lock))); + removed = 1; + trace_hfi1_qpremove(qp, n); + break; + } + } + + spin_unlock_irqrestore(&dev->qp_dev->qpt_lock, flags); + if (removed) { + synchronize_rcu(); + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } +} + +/** + * free_all_qps - check for QPs still in use + * @qpt: the QP table to empty + * + * There should not be any QPs still in use. + * Free memory for table. + */ +static unsigned free_all_qps(struct hfi1_devdata *dd) +{ + struct hfi1_ibdev *dev = &dd->verbs_dev; + unsigned long flags; + struct hfi1_qp *qp; + unsigned n, qp_inuse = 0; + + for (n = 0; n < dd->num_pports; n++) { + struct hfi1_ibport *ibp = &dd->pport[n].ibport_data; + + if (!hfi1_mcast_tree_empty(ibp)) + qp_inuse++; + rcu_read_lock(); + if (rcu_dereference(ibp->qp[0])) + qp_inuse++; + if (rcu_dereference(ibp->qp[1])) + qp_inuse++; + rcu_read_unlock(); + } + + if (!dev->qp_dev) + goto bail; + spin_lock_irqsave(&dev->qp_dev->qpt_lock, flags); + for (n = 0; n < dev->qp_dev->qp_table_size; n++) { + qp = rcu_dereference_protected(dev->qp_dev->qp_table[n], + lockdep_is_held(&dev->qp_dev->qpt_lock)); + RCU_INIT_POINTER(dev->qp_dev->qp_table[n], NULL); + + for (; qp; qp = rcu_dereference_protected(qp->next, + lockdep_is_held(&dev->qp_dev->qpt_lock))) + qp_inuse++; + } + spin_unlock_irqrestore(&dev->qp_dev->qpt_lock, flags); + synchronize_rcu(); +bail: + return qp_inuse; +} + +/** + * reset_qp - initialize the QP state to the reset state + * @qp: the QP to reset + * @type: the QP type + */ +static void reset_qp(struct hfi1_qp *qp, enum ib_qp_type type) +{ + qp->remote_qpn = 0; + qp->qkey = 0; + qp->qp_access_flags = 0; + iowait_init( + &qp->s_iowait, + 1, + hfi1_do_send, + iowait_sleep, + iowait_wakeup); + qp->s_flags &= HFI1_S_SIGNAL_REQ_WR; + qp->s_hdrwords = 0; + qp->s_wqe = NULL; + qp->s_draining = 0; + qp->s_next_psn = 0; + qp->s_last_psn = 0; + qp->s_sending_psn = 0; + qp->s_sending_hpsn = 0; + qp->s_psn = 0; + qp->r_psn = 0; + qp->r_msn = 0; + if (type == IB_QPT_RC) { + qp->s_state = IB_OPCODE_RC_SEND_LAST; + qp->r_state = IB_OPCODE_RC_SEND_LAST; + } else { + qp->s_state = IB_OPCODE_UC_SEND_LAST; + qp->r_state = IB_OPCODE_UC_SEND_LAST; + } + qp->s_ack_state = IB_OPCODE_RC_ACKNOWLEDGE; + qp->r_nak_state = 0; + qp->r_aflags = 0; + qp->r_flags = 0; + qp->s_head = 0; + qp->s_tail = 0; + qp->s_cur = 0; + qp->s_acked = 0; + qp->s_last = 0; + qp->s_ssn = 1; + qp->s_lsn = 0; + clear_ahg(qp); + qp->s_mig_state = IB_MIG_MIGRATED; + memset(qp->s_ack_queue, 0, sizeof(qp->s_ack_queue)); + qp->r_head_ack_queue = 0; + qp->s_tail_ack_queue = 0; + qp->s_num_rd_atomic = 0; + if (qp->r_rq.wq) { + qp->r_rq.wq->head = 0; + qp->r_rq.wq->tail = 0; + } + qp->r_sge.num_sge = 0; +} + +static void clear_mr_refs(struct hfi1_qp *qp, int clr_sends) +{ + unsigned n; + + if (test_and_clear_bit(HFI1_R_REWIND_SGE, &qp->r_aflags)) + hfi1_put_ss(&qp->s_rdma_read_sge); + + hfi1_put_ss(&qp->r_sge); + + if (clr_sends) { + while (qp->s_last != qp->s_head) { + struct hfi1_swqe *wqe = get_swqe_ptr(qp, qp->s_last); + unsigned i; + + for (i = 0; i < wqe->wr.num_sge; i++) { + struct hfi1_sge *sge = &wqe->sg_list[i]; + + hfi1_put_mr(sge->mr); + } + if (qp->ibqp.qp_type == IB_QPT_UD || + qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI) + atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount); + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + } + if (qp->s_rdma_mr) { + hfi1_put_mr(qp->s_rdma_mr); + qp->s_rdma_mr = NULL; + } + } + + if (qp->ibqp.qp_type != IB_QPT_RC) + return; + + for (n = 0; n < ARRAY_SIZE(qp->s_ack_queue); n++) { + struct hfi1_ack_entry *e = &qp->s_ack_queue[n]; + + if (e->opcode == IB_OPCODE_RC_RDMA_READ_REQUEST && + e->rdma_sge.mr) { + hfi1_put_mr(e->rdma_sge.mr); + e->rdma_sge.mr = NULL; + } + } +} + +/** + * hfi1_error_qp - put a QP into the error state + * @qp: the QP to put into the error state + * @err: the receive completion error to signal if a RWQE is active + * + * Flushes both send and receive work queues. + * Returns true if last WQE event should be generated. + * The QP r_lock and s_lock should be held and interrupts disabled. + * If we are already in error state, just return. + */ +int hfi1_error_qp(struct hfi1_qp *qp, enum ib_wc_status err) +{ + struct hfi1_ibdev *dev = to_idev(qp->ibqp.device); + struct ib_wc wc; + int ret = 0; + + if (qp->state == IB_QPS_ERR || qp->state == IB_QPS_RESET) + goto bail; + + qp->state = IB_QPS_ERR; + + if (qp->s_flags & (HFI1_S_TIMER | HFI1_S_WAIT_RNR)) { + qp->s_flags &= ~(HFI1_S_TIMER | HFI1_S_WAIT_RNR); + del_timer(&qp->s_timer); + } + + if (qp->s_flags & HFI1_S_ANY_WAIT_SEND) + qp->s_flags &= ~HFI1_S_ANY_WAIT_SEND; + + write_seqlock(&dev->iowait_lock); + if (!list_empty(&qp->s_iowait.list) && !(qp->s_flags & HFI1_S_BUSY)) { + qp->s_flags &= ~HFI1_S_ANY_WAIT_IO; + list_del_init(&qp->s_iowait.list); + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } + write_sequnlock(&dev->iowait_lock); + + if (!(qp->s_flags & HFI1_S_BUSY)) { + qp->s_hdrwords = 0; + if (qp->s_rdma_mr) { + hfi1_put_mr(qp->s_rdma_mr); + qp->s_rdma_mr = NULL; + } + flush_tx_list(qp); + } + + /* Schedule the sending tasklet to drain the send work queue. */ + if (qp->s_last != qp->s_head) + hfi1_schedule_send(qp); + + clear_mr_refs(qp, 0); + + memset(&wc, 0, sizeof(wc)); + wc.qp = &qp->ibqp; + wc.opcode = IB_WC_RECV; + + if (test_and_clear_bit(HFI1_R_WRID_VALID, &qp->r_aflags)) { + wc.wr_id = qp->r_wr_id; + wc.status = err; + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); + } + wc.status = IB_WC_WR_FLUSH_ERR; + + if (qp->r_rq.wq) { + struct hfi1_rwq *wq; + u32 head; + u32 tail; + + spin_lock(&qp->r_rq.lock); + + /* sanity check pointers before trusting them */ + wq = qp->r_rq.wq; + head = wq->head; + if (head >= qp->r_rq.size) + head = 0; + tail = wq->tail; + if (tail >= qp->r_rq.size) + tail = 0; + while (tail != head) { + wc.wr_id = get_rwqe_ptr(&qp->r_rq, tail)->wr_id; + if (++tail >= qp->r_rq.size) + tail = 0; + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); + } + wq->tail = tail; + + spin_unlock(&qp->r_rq.lock); + } else if (qp->ibqp.event_handler) + ret = 1; + +bail: + return ret; +} + +static void flush_tx_list(struct hfi1_qp *qp) +{ + while (!list_empty(&qp->s_iowait.tx_head)) { + struct sdma_txreq *tx; + + tx = list_first_entry( + &qp->s_iowait.tx_head, + struct sdma_txreq, + list); + list_del_init(&tx->list); + hfi1_put_txreq( + container_of(tx, struct verbs_txreq, txreq)); + } +} + +static void flush_iowait(struct hfi1_qp *qp) +{ + struct hfi1_ibdev *dev = to_idev(qp->ibqp.device); + unsigned long flags; + + write_seqlock_irqsave(&dev->iowait_lock, flags); + if (!list_empty(&qp->s_iowait.list)) { + list_del_init(&qp->s_iowait.list); + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + } + write_sequnlock_irqrestore(&dev->iowait_lock, flags); +} + +static inline int opa_mtu_enum_to_int(int mtu) +{ + switch (mtu) { + case OPA_MTU_8192: return 8192; + case OPA_MTU_10240: return 10240; + default: return -1; + } +} + +/** + * This function is what we would push to the core layer if we wanted to be a + * "first class citizen". Instead we hide this here and rely on Verbs ULPs + * to blindly pass the MTU enum value from the PathRecord to us. + * + * The actual flag used to determine "8k MTU" will change and is currently + * unknown. + */ +static inline int verbs_mtu_enum_to_int(struct ib_device *dev, enum ib_mtu mtu) +{ + int val = opa_mtu_enum_to_int((int)mtu); + + if (val > 0) + return val; + return ib_mtu_enum_to_int(mtu); +} + + +/** + * hfi1_modify_qp - modify the attributes of a queue pair + * @ibqp: the queue pair who's attributes we're modifying + * @attr: the new attributes + * @attr_mask: the mask of attributes to modify + * @udata: user data for libibverbs.so + * + * Returns 0 on success, otherwise returns an errno. + */ +int hfi1_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + struct hfi1_ibdev *dev = to_idev(ibqp->device); + struct hfi1_qp *qp = to_iqp(ibqp); + enum ib_qp_state cur_state, new_state; + struct ib_event ev; + int lastwqe = 0; + int mig = 0; + int ret; + u32 pmtu = 0; /* for gcc warning only */ + struct hfi1_devdata *dd; + + spin_lock_irq(&qp->r_lock); + spin_lock(&qp->s_lock); + + cur_state = attr_mask & IB_QP_CUR_STATE ? + attr->cur_qp_state : qp->state; + new_state = attr_mask & IB_QP_STATE ? attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, new_state, ibqp->qp_type, + attr_mask, IB_LINK_LAYER_UNSPECIFIED)) + goto inval; + + if (attr_mask & IB_QP_AV) { + if (attr->ah_attr.dlid >= HFI1_MULTICAST_LID_BASE) + goto inval; + if (hfi1_check_ah(qp->ibqp.device, &attr->ah_attr)) + goto inval; + } + + if (attr_mask & IB_QP_ALT_PATH) { + if (attr->alt_ah_attr.dlid >= HFI1_MULTICAST_LID_BASE) + goto inval; + if (hfi1_check_ah(qp->ibqp.device, &attr->alt_ah_attr)) + goto inval; + if (attr->alt_pkey_index >= hfi1_get_npkeys(dd_from_dev(dev))) + goto inval; + } + + if (attr_mask & IB_QP_PKEY_INDEX) + if (attr->pkey_index >= hfi1_get_npkeys(dd_from_dev(dev))) + goto inval; + + if (attr_mask & IB_QP_MIN_RNR_TIMER) + if (attr->min_rnr_timer > 31) + goto inval; + + if (attr_mask & IB_QP_PORT) + if (qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI || + attr->port_num == 0 || + attr->port_num > ibqp->device->phys_port_cnt) + goto inval; + + if (attr_mask & IB_QP_DEST_QPN) + if (attr->dest_qp_num > HFI1_QPN_MASK) + goto inval; + + if (attr_mask & IB_QP_RETRY_CNT) + if (attr->retry_cnt > 7) + goto inval; + + if (attr_mask & IB_QP_RNR_RETRY) + if (attr->rnr_retry > 7) + goto inval; + + /* + * Don't allow invalid path_mtu values. OK to set greater + * than the active mtu (or even the max_cap, if we have tuned + * that to a small mtu. We'll set qp->path_mtu + * to the lesser of requested attribute mtu and active, + * for packetizing messages. + * Note that the QP port has to be set in INIT and MTU in RTR. + */ + if (attr_mask & IB_QP_PATH_MTU) { + int mtu, pidx = qp->port_num - 1; + + dd = dd_from_dev(dev); + mtu = verbs_mtu_enum_to_int(ibqp->device, attr->path_mtu); + if (mtu == -1) + goto inval; + + if (mtu > dd->pport[pidx].ibmtu) + pmtu = mtu_to_enum(dd->pport[pidx].ibmtu, IB_MTU_2048); + else + pmtu = attr->path_mtu; + } + + if (attr_mask & IB_QP_PATH_MIG_STATE) { + if (attr->path_mig_state == IB_MIG_REARM) { + if (qp->s_mig_state == IB_MIG_ARMED) + goto inval; + if (new_state != IB_QPS_RTS) + goto inval; + } else if (attr->path_mig_state == IB_MIG_MIGRATED) { + if (qp->s_mig_state == IB_MIG_REARM) + goto inval; + if (new_state != IB_QPS_RTS && new_state != IB_QPS_SQD) + goto inval; + if (qp->s_mig_state == IB_MIG_ARMED) + mig = 1; + } else + goto inval; + } + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + if (attr->max_dest_rd_atomic > HFI1_MAX_RDMA_ATOMIC) + goto inval; + + switch (new_state) { + case IB_QPS_RESET: + if (qp->state != IB_QPS_RESET) { + qp->state = IB_QPS_RESET; + flush_iowait(qp); + qp->s_flags &= ~(HFI1_S_TIMER | HFI1_S_ANY_WAIT); + spin_unlock(&qp->s_lock); + spin_unlock_irq(&qp->r_lock); + /* Stop the sending work queue and retry timer */ + cancel_work_sync(&qp->s_iowait.iowork); + del_timer_sync(&qp->s_timer); + iowait_sdma_drain(&qp->s_iowait); + flush_tx_list(qp); + remove_qp(dev, qp); + wait_event(qp->wait, !atomic_read(&qp->refcount)); + spin_lock_irq(&qp->r_lock); + spin_lock(&qp->s_lock); + clear_mr_refs(qp, 1); + clear_ahg(qp); + reset_qp(qp, ibqp->qp_type); + } + break; + + case IB_QPS_RTR: + /* Allow event to re-trigger if QP set to RTR more than once */ + qp->r_flags &= ~HFI1_R_COMM_EST; + qp->state = new_state; + break; + + case IB_QPS_SQD: + qp->s_draining = qp->s_last != qp->s_cur; + qp->state = new_state; + break; + + case IB_QPS_SQE: + if (qp->ibqp.qp_type == IB_QPT_RC) + goto inval; + qp->state = new_state; + break; + + case IB_QPS_ERR: + lastwqe = hfi1_error_qp(qp, IB_WC_WR_FLUSH_ERR); + break; + + default: + qp->state = new_state; + break; + } + + if (attr_mask & IB_QP_PKEY_INDEX) + qp->s_pkey_index = attr->pkey_index; + + if (attr_mask & IB_QP_PORT) + qp->port_num = attr->port_num; + + if (attr_mask & IB_QP_DEST_QPN) + qp->remote_qpn = attr->dest_qp_num; + + if (attr_mask & IB_QP_SQ_PSN) { + qp->s_next_psn = attr->sq_psn & PSN_MODIFY_MASK; + qp->s_psn = qp->s_next_psn; + qp->s_sending_psn = qp->s_next_psn; + qp->s_last_psn = qp->s_next_psn - 1; + qp->s_sending_hpsn = qp->s_last_psn; + } + + if (attr_mask & IB_QP_RQ_PSN) + qp->r_psn = attr->rq_psn & PSN_MODIFY_MASK; + + if (attr_mask & IB_QP_ACCESS_FLAGS) + qp->qp_access_flags = attr->qp_access_flags; + + if (attr_mask & IB_QP_AV) { + qp->remote_ah_attr = attr->ah_attr; + qp->s_srate = attr->ah_attr.static_rate; + qp->srate_mbps = ib_rate_to_mbps(qp->s_srate); + } + + if (attr_mask & IB_QP_ALT_PATH) { + qp->alt_ah_attr = attr->alt_ah_attr; + qp->s_alt_pkey_index = attr->alt_pkey_index; + } + + if (attr_mask & IB_QP_PATH_MIG_STATE) { + qp->s_mig_state = attr->path_mig_state; + if (mig) { + qp->remote_ah_attr = qp->alt_ah_attr; + qp->port_num = qp->alt_ah_attr.port_num; + qp->s_pkey_index = qp->s_alt_pkey_index; + qp->s_flags |= HFI1_S_AHG_CLEAR; + } + } + + if (attr_mask & IB_QP_PATH_MTU) { + struct hfi1_ibport *ibp; + u8 sc, vl; + u32 mtu; + + dd = dd_from_dev(dev); + ibp = &dd->pport[qp->port_num - 1].ibport_data; + + sc = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + vl = sc_to_vlt(dd, sc); + + mtu = verbs_mtu_enum_to_int(ibqp->device, pmtu); + if (vl < PER_VL_SEND_CONTEXTS) + mtu = min_t(u32, mtu, dd->vld[vl].mtu); + pmtu = mtu_to_enum(mtu, OPA_MTU_8192); + + qp->path_mtu = pmtu; + qp->pmtu = mtu; + } + + if (attr_mask & IB_QP_RETRY_CNT) { + qp->s_retry_cnt = attr->retry_cnt; + qp->s_retry = attr->retry_cnt; + } + + if (attr_mask & IB_QP_RNR_RETRY) { + qp->s_rnr_retry_cnt = attr->rnr_retry; + qp->s_rnr_retry = attr->rnr_retry; + } + + if (attr_mask & IB_QP_MIN_RNR_TIMER) + qp->r_min_rnr_timer = attr->min_rnr_timer; + + if (attr_mask & IB_QP_TIMEOUT) { + qp->timeout = attr->timeout; + qp->timeout_jiffies = + usecs_to_jiffies((4096UL * (1UL << qp->timeout)) / + 1000UL); + } + + if (attr_mask & IB_QP_QKEY) + qp->qkey = attr->qkey; + + if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) + qp->r_max_rd_atomic = attr->max_dest_rd_atomic; + + if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) + qp->s_max_rd_atomic = attr->max_rd_atomic; + + spin_unlock(&qp->s_lock); + spin_unlock_irq(&qp->r_lock); + + if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) + insert_qp(dev, qp); + + if (lastwqe) { + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } + if (mig) { + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_PATH_MIG; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } + ret = 0; + goto bail; + +inval: + spin_unlock(&qp->s_lock); + spin_unlock_irq(&qp->r_lock); + ret = -EINVAL; + +bail: + return ret; +} + +int hfi1_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_qp_init_attr *init_attr) +{ + struct hfi1_qp *qp = to_iqp(ibqp); + + attr->qp_state = qp->state; + attr->cur_qp_state = attr->qp_state; + attr->path_mtu = qp->path_mtu; + attr->path_mig_state = qp->s_mig_state; + attr->qkey = qp->qkey; + attr->rq_psn = mask_psn(qp->r_psn); + attr->sq_psn = mask_psn(qp->s_next_psn); + attr->dest_qp_num = qp->remote_qpn; + attr->qp_access_flags = qp->qp_access_flags; + attr->cap.max_send_wr = qp->s_size - 1; + attr->cap.max_recv_wr = qp->ibqp.srq ? 0 : qp->r_rq.size - 1; + attr->cap.max_send_sge = qp->s_max_sge; + attr->cap.max_recv_sge = qp->r_rq.max_sge; + attr->cap.max_inline_data = 0; + attr->ah_attr = qp->remote_ah_attr; + attr->alt_ah_attr = qp->alt_ah_attr; + attr->pkey_index = qp->s_pkey_index; + attr->alt_pkey_index = qp->s_alt_pkey_index; + attr->en_sqd_async_notify = 0; + attr->sq_draining = qp->s_draining; + attr->max_rd_atomic = qp->s_max_rd_atomic; + attr->max_dest_rd_atomic = qp->r_max_rd_atomic; + attr->min_rnr_timer = qp->r_min_rnr_timer; + attr->port_num = qp->port_num; + attr->timeout = qp->timeout; + attr->retry_cnt = qp->s_retry_cnt; + attr->rnr_retry = qp->s_rnr_retry_cnt; + attr->alt_port_num = qp->alt_ah_attr.port_num; + attr->alt_timeout = qp->alt_timeout; + + init_attr->event_handler = qp->ibqp.event_handler; + init_attr->qp_context = qp->ibqp.qp_context; + init_attr->send_cq = qp->ibqp.send_cq; + init_attr->recv_cq = qp->ibqp.recv_cq; + init_attr->srq = qp->ibqp.srq; + init_attr->cap = attr->cap; + if (qp->s_flags & HFI1_S_SIGNAL_REQ_WR) + init_attr->sq_sig_type = IB_SIGNAL_REQ_WR; + else + init_attr->sq_sig_type = IB_SIGNAL_ALL_WR; + init_attr->qp_type = qp->ibqp.qp_type; + init_attr->port_num = qp->port_num; + return 0; +} + +/** + * hfi1_compute_aeth - compute the AETH (syndrome + MSN) + * @qp: the queue pair to compute the AETH for + * + * Returns the AETH. + */ +__be32 hfi1_compute_aeth(struct hfi1_qp *qp) +{ + u32 aeth = qp->r_msn & HFI1_MSN_MASK; + + if (qp->ibqp.srq) { + /* + * Shared receive queues don't generate credits. + * Set the credit field to the invalid value. + */ + aeth |= HFI1_AETH_CREDIT_INVAL << HFI1_AETH_CREDIT_SHIFT; + } else { + u32 min, max, x; + u32 credits; + struct hfi1_rwq *wq = qp->r_rq.wq; + u32 head; + u32 tail; + + /* sanity check pointers before trusting them */ + head = wq->head; + if (head >= qp->r_rq.size) + head = 0; + tail = wq->tail; + if (tail >= qp->r_rq.size) + tail = 0; + /* + * Compute the number of credits available (RWQEs). + * There is a small chance that the pair of reads are + * not atomic, which is OK, since the fuzziness is + * resolved as further ACKs go out. + */ + credits = head - tail; + if ((int)credits < 0) + credits += qp->r_rq.size; + /* + * Binary search the credit table to find the code to + * use. + */ + min = 0; + max = 31; + for (;;) { + x = (min + max) / 2; + if (credit_table[x] == credits) + break; + if (credit_table[x] > credits) + max = x; + else if (min == x) + break; + else + min = x; + } + aeth |= x << HFI1_AETH_CREDIT_SHIFT; + } + return cpu_to_be32(aeth); +} + +/** + * hfi1_create_qp - create a queue pair for a device + * @ibpd: the protection domain who's device we create the queue pair for + * @init_attr: the attributes of the queue pair + * @udata: user data for libibverbs.so + * + * Returns the queue pair on success, otherwise returns an errno. + * + * Called by the ib_create_qp() core verbs function. + */ +struct ib_qp *hfi1_create_qp(struct ib_pd *ibpd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + struct hfi1_qp *qp; + int err; + struct hfi1_swqe *swq = NULL; + struct hfi1_ibdev *dev; + struct hfi1_devdata *dd; + size_t sz; + size_t sg_list_sz; + struct ib_qp *ret; + + if (init_attr->cap.max_send_sge > hfi1_max_sges || + init_attr->cap.max_send_wr > hfi1_max_qp_wrs || + init_attr->create_flags) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + + /* Check receive queue parameters if no SRQ is specified. */ + if (!init_attr->srq) { + if (init_attr->cap.max_recv_sge > hfi1_max_sges || + init_attr->cap.max_recv_wr > hfi1_max_qp_wrs) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + if (init_attr->cap.max_send_sge + + init_attr->cap.max_send_wr + + init_attr->cap.max_recv_sge + + init_attr->cap.max_recv_wr == 0) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + } + + switch (init_attr->qp_type) { + case IB_QPT_SMI: + case IB_QPT_GSI: + if (init_attr->port_num == 0 || + init_attr->port_num > ibpd->device->phys_port_cnt) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + case IB_QPT_UC: + case IB_QPT_RC: + case IB_QPT_UD: + sz = sizeof(struct hfi1_sge) * + init_attr->cap.max_send_sge + + sizeof(struct hfi1_swqe); + swq = vmalloc((init_attr->cap.max_send_wr + 1) * sz); + if (swq == NULL) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + sz = sizeof(*qp); + sg_list_sz = 0; + if (init_attr->srq) { + struct hfi1_srq *srq = to_isrq(init_attr->srq); + + if (srq->rq.max_sge > 1) + sg_list_sz = sizeof(*qp->r_sg_list) * + (srq->rq.max_sge - 1); + } else if (init_attr->cap.max_recv_sge > 1) + sg_list_sz = sizeof(*qp->r_sg_list) * + (init_attr->cap.max_recv_sge - 1); + qp = kzalloc(sz + sg_list_sz, GFP_KERNEL); + if (!qp) { + ret = ERR_PTR(-ENOMEM); + goto bail_swq; + } + RCU_INIT_POINTER(qp->next, NULL); + qp->s_hdr = kzalloc(sizeof(*qp->s_hdr), GFP_KERNEL); + if (!qp->s_hdr) { + ret = ERR_PTR(-ENOMEM); + goto bail_qp; + } + qp->timeout_jiffies = + usecs_to_jiffies((4096UL * (1UL << qp->timeout)) / + 1000UL); + if (init_attr->srq) + sz = 0; + else { + qp->r_rq.size = init_attr->cap.max_recv_wr + 1; + qp->r_rq.max_sge = init_attr->cap.max_recv_sge; + sz = (sizeof(struct ib_sge) * qp->r_rq.max_sge) + + sizeof(struct hfi1_rwqe); + qp->r_rq.wq = vmalloc_user(sizeof(struct hfi1_rwq) + + qp->r_rq.size * sz); + if (!qp->r_rq.wq) { + ret = ERR_PTR(-ENOMEM); + goto bail_qp; + } + } + + /* + * ib_create_qp() will initialize qp->ibqp + * except for qp->ibqp.qp_num. + */ + spin_lock_init(&qp->r_lock); + spin_lock_init(&qp->s_lock); + spin_lock_init(&qp->r_rq.lock); + atomic_set(&qp->refcount, 0); + init_waitqueue_head(&qp->wait); + init_timer(&qp->s_timer); + qp->s_timer.data = (unsigned long)qp; + INIT_LIST_HEAD(&qp->rspwait); + qp->state = IB_QPS_RESET; + qp->s_wq = swq; + qp->s_size = init_attr->cap.max_send_wr + 1; + qp->s_max_sge = init_attr->cap.max_send_sge; + if (init_attr->sq_sig_type == IB_SIGNAL_REQ_WR) + qp->s_flags = HFI1_S_SIGNAL_REQ_WR; + dev = to_idev(ibpd->device); + dd = dd_from_dev(dev); + err = alloc_qpn(dd, &dev->qp_dev->qpn_table, init_attr->qp_type, + init_attr->port_num); + if (err < 0) { + ret = ERR_PTR(err); + vfree(qp->r_rq.wq); + goto bail_qp; + } + qp->ibqp.qp_num = err; + qp->port_num = init_attr->port_num; + reset_qp(qp, init_attr->qp_type); + + break; + + default: + /* Don't support raw QPs */ + ret = ERR_PTR(-ENOSYS); + goto bail; + } + + init_attr->cap.max_inline_data = 0; + + /* + * Return the address of the RWQ as the offset to mmap. + * See hfi1_mmap() for details. + */ + if (udata && udata->outlen >= sizeof(__u64)) { + if (!qp->r_rq.wq) { + __u64 offset = 0; + + err = ib_copy_to_udata(udata, &offset, + sizeof(offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; + } + } else { + u32 s = sizeof(struct hfi1_rwq) + qp->r_rq.size * sz; + + qp->ip = hfi1_create_mmap_info(dev, s, + ibpd->uobject->context, + qp->r_rq.wq); + if (!qp->ip) { + ret = ERR_PTR(-ENOMEM); + goto bail_ip; + } + + err = ib_copy_to_udata(udata, &(qp->ip->offset), + sizeof(qp->ip->offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; + } + } + } + + spin_lock(&dev->n_qps_lock); + if (dev->n_qps_allocated == hfi1_max_qps) { + spin_unlock(&dev->n_qps_lock); + ret = ERR_PTR(-ENOMEM); + goto bail_ip; + } + + dev->n_qps_allocated++; + spin_unlock(&dev->n_qps_lock); + + if (qp->ip) { + spin_lock_irq(&dev->pending_lock); + list_add(&qp->ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + + ret = &qp->ibqp; + + /* + * We have our QP and its good, now keep track of what types of opcodes + * can be processed on this QP. We do this by keeping track of what the + * 3 high order bits of the opcode are. + */ + switch (init_attr->qp_type) { + case IB_QPT_SMI: + case IB_QPT_GSI: + case IB_QPT_UD: + qp->allowed_ops = IB_OPCODE_UD_SEND_ONLY & OPCODE_QP_MASK; + break; + case IB_QPT_RC: + qp->allowed_ops = IB_OPCODE_RC_SEND_ONLY & OPCODE_QP_MASK; + break; + case IB_QPT_UC: + qp->allowed_ops = IB_OPCODE_UC_SEND_ONLY & OPCODE_QP_MASK; + break; + default: + ret = ERR_PTR(-EINVAL); + goto bail_ip; + } + + goto bail; + +bail_ip: + if (qp->ip) + kref_put(&qp->ip->ref, hfi1_release_mmap_info); + else + vfree(qp->r_rq.wq); + free_qpn(&dev->qp_dev->qpn_table, qp->ibqp.qp_num); +bail_qp: + kfree(qp->s_hdr); + kfree(qp); +bail_swq: + vfree(swq); +bail: + return ret; +} + +/** + * hfi1_destroy_qp - destroy a queue pair + * @ibqp: the queue pair to destroy + * + * Returns 0 on success. + * + * Note that this can be called while the QP is actively sending or + * receiving! + */ +int hfi1_destroy_qp(struct ib_qp *ibqp) +{ + struct hfi1_qp *qp = to_iqp(ibqp); + struct hfi1_ibdev *dev = to_idev(ibqp->device); + + /* Make sure HW and driver activity is stopped. */ + spin_lock_irq(&qp->r_lock); + spin_lock(&qp->s_lock); + if (qp->state != IB_QPS_RESET) { + qp->state = IB_QPS_RESET; + flush_iowait(qp); + qp->s_flags &= ~(HFI1_S_TIMER | HFI1_S_ANY_WAIT); + spin_unlock(&qp->s_lock); + spin_unlock_irq(&qp->r_lock); + cancel_work_sync(&qp->s_iowait.iowork); + del_timer_sync(&qp->s_timer); + iowait_sdma_drain(&qp->s_iowait); + flush_tx_list(qp); + remove_qp(dev, qp); + wait_event(qp->wait, !atomic_read(&qp->refcount)); + spin_lock_irq(&qp->r_lock); + spin_lock(&qp->s_lock); + clear_mr_refs(qp, 1); + clear_ahg(qp); + } + spin_unlock(&qp->s_lock); + spin_unlock_irq(&qp->r_lock); + + /* all user's cleaned up, mark it available */ + free_qpn(&dev->qp_dev->qpn_table, qp->ibqp.qp_num); + spin_lock(&dev->n_qps_lock); + dev->n_qps_allocated--; + spin_unlock(&dev->n_qps_lock); + + if (qp->ip) + kref_put(&qp->ip->ref, hfi1_release_mmap_info); + else + vfree(qp->r_rq.wq); + vfree(qp->s_wq); + kfree(qp->s_hdr); + kfree(qp); + return 0; +} + +/** + * init_qpn_table - initialize the QP number table for a device + * @qpt: the QPN table + */ +static int init_qpn_table(struct hfi1_devdata *dd, struct hfi1_qpn_table *qpt) +{ + u32 offset, qpn, i; + struct qpn_map *map; + int ret = 0; + + spin_lock_init(&qpt->lock); + + qpt->last = 0; + qpt->incr = 1 << dd->qos_shift; + + /* insure we don't assign QPs from KDETH 64K window */ + qpn = kdeth_qp << 16; + qpt->nmaps = qpn / BITS_PER_PAGE; + /* This should always be zero */ + offset = qpn & BITS_PER_PAGE_MASK; + map = &qpt->map[qpt->nmaps]; + dd_dev_info(dd, "Reserving QPNs for KDETH window from 0x%x to 0x%x\n", + qpn, qpn + 65535); + for (i = 0; i < 65536; i++) { + if (!map->page) { + get_map_page(qpt, map); + if (!map->page) { + ret = -ENOMEM; + break; + } + } + set_bit(offset, map->page); + offset++; + if (offset == BITS_PER_PAGE) { + /* next page */ + qpt->nmaps++; + map++; + offset = 0; + } + } + return ret; +} + +/** + * free_qpn_table - free the QP number table for a device + * @qpt: the QPN table + */ +static void free_qpn_table(struct hfi1_qpn_table *qpt) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qpt->map); i++) + free_page((unsigned long) qpt->map[i].page); +} + +/** + * hfi1_get_credit - flush the send work queue of a QP + * @qp: the qp who's send work queue to flush + * @aeth: the Acknowledge Extended Transport Header + * + * The QP s_lock should be held. + */ +void hfi1_get_credit(struct hfi1_qp *qp, u32 aeth) +{ + u32 credit = (aeth >> HFI1_AETH_CREDIT_SHIFT) & HFI1_AETH_CREDIT_MASK; + + /* + * If the credit is invalid, we can send + * as many packets as we like. Otherwise, we have to + * honor the credit field. + */ + if (credit == HFI1_AETH_CREDIT_INVAL) { + if (!(qp->s_flags & HFI1_S_UNLIMITED_CREDIT)) { + qp->s_flags |= HFI1_S_UNLIMITED_CREDIT; + if (qp->s_flags & HFI1_S_WAIT_SSN_CREDIT) { + qp->s_flags &= ~HFI1_S_WAIT_SSN_CREDIT; + hfi1_schedule_send(qp); + } + } + } else if (!(qp->s_flags & HFI1_S_UNLIMITED_CREDIT)) { + /* Compute new LSN (i.e., MSN + credit) */ + credit = (aeth + credit_table[credit]) & HFI1_MSN_MASK; + if (cmp_msn(credit, qp->s_lsn) > 0) { + qp->s_lsn = credit; + if (qp->s_flags & HFI1_S_WAIT_SSN_CREDIT) { + qp->s_flags &= ~HFI1_S_WAIT_SSN_CREDIT; + hfi1_schedule_send(qp); + } + } + } +} + +void hfi1_qp_wakeup(struct hfi1_qp *qp, u32 flag) +{ + unsigned long flags; + + spin_lock_irqsave(&qp->s_lock, flags); + if (qp->s_flags & flag) { + qp->s_flags &= ~flag; + trace_hfi1_qpwakeup(qp, flag); + hfi1_schedule_send(qp); + } + spin_unlock_irqrestore(&qp->s_lock, flags); + /* Notify hfi1_destroy_qp() if it is waiting. */ + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); +} + +static int iowait_sleep( + struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *stx, + unsigned seq) +{ + struct verbs_txreq *tx = container_of(stx, struct verbs_txreq, txreq); + struct hfi1_qp *qp; + unsigned long flags; + int ret = 0; + struct hfi1_ibdev *dev; + + qp = tx->qp; + + spin_lock_irqsave(&qp->s_lock, flags); + if (ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK) { + + /* + * If we couldn't queue the DMA request, save the info + * and try again later rather than destroying the + * buffer and undoing the side effects of the copy. + */ + /* Make a common routine? */ + dev = &sde->dd->verbs_dev; + list_add_tail(&stx->list, &wait->tx_head); + write_seqlock(&dev->iowait_lock); + if (sdma_progress(sde, seq, stx)) + goto eagain; + if (list_empty(&qp->s_iowait.list)) { + struct hfi1_ibport *ibp = + to_iport(qp->ibqp.device, qp->port_num); + + ibp->n_dmawait++; + qp->s_flags |= HFI1_S_WAIT_DMA_DESC; + list_add_tail(&qp->s_iowait.list, &sde->dmawait); + trace_hfi1_qpsleep(qp, HFI1_S_WAIT_DMA_DESC); + atomic_inc(&qp->refcount); + } + write_sequnlock(&dev->iowait_lock); + qp->s_flags &= ~HFI1_S_BUSY; + spin_unlock_irqrestore(&qp->s_lock, flags); + ret = -EBUSY; + } else { + spin_unlock_irqrestore(&qp->s_lock, flags); + hfi1_put_txreq(tx); + } + return ret; +eagain: + write_sequnlock(&dev->iowait_lock); + spin_unlock_irqrestore(&qp->s_lock, flags); + list_del_init(&stx->list); + return -EAGAIN; +} + +static void iowait_wakeup(struct iowait *wait, int reason) +{ + struct hfi1_qp *qp = container_of(wait, struct hfi1_qp, s_iowait); + + WARN_ON(reason != SDMA_AVAIL_REASON); + hfi1_qp_wakeup(qp, HFI1_S_WAIT_DMA_DESC); +} + +int hfi1_qp_init(struct hfi1_ibdev *dev) +{ + struct hfi1_devdata *dd = dd_from_dev(dev); + int i; + int ret = -ENOMEM; + + /* allocate parent object */ + dev->qp_dev = kzalloc(sizeof(*dev->qp_dev), GFP_KERNEL); + if (!dev->qp_dev) + goto nomem; + /* allocate hash table */ + dev->qp_dev->qp_table_size = hfi1_qp_table_size; + dev->qp_dev->qp_table_bits = ilog2(hfi1_qp_table_size); + dev->qp_dev->qp_table = + kmalloc(dev->qp_dev->qp_table_size * + sizeof(*dev->qp_dev->qp_table), + GFP_KERNEL); + if (!dev->qp_dev->qp_table) + goto nomem; + for (i = 0; i < dev->qp_dev->qp_table_size; i++) + RCU_INIT_POINTER(dev->qp_dev->qp_table[i], NULL); + spin_lock_init(&dev->qp_dev->qpt_lock); + /* initialize qpn map */ + ret = init_qpn_table(dd, &dev->qp_dev->qpn_table); + if (ret) + goto nomem; + return ret; +nomem: + if (dev->qp_dev) { + kfree(dev->qp_dev->qp_table); + free_qpn_table(&dev->qp_dev->qpn_table); + kfree(dev->qp_dev); + } + return ret; +} + +void hfi1_qp_exit(struct hfi1_ibdev *dev) +{ + struct hfi1_devdata *dd = dd_from_dev(dev); + u32 qps_inuse; + + qps_inuse = free_all_qps(dd); + if (qps_inuse) + dd_dev_err(dd, "QP memory leak! %u still in use\n", + qps_inuse); + if (dev->qp_dev) { + kfree(dev->qp_dev->qp_table); + free_qpn_table(&dev->qp_dev->qpn_table); + kfree(dev->qp_dev); + } +} + +/** + * + * qp_to_sdma_engine - map a qp to a send engine + * @qp: the QP + * @sc5: the 5 bit sc + * + * Return: + * A send engine for the qp or NULL for SMI type qp. + */ +struct sdma_engine *qp_to_sdma_engine(struct hfi1_qp *qp, u8 sc5) +{ + struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device); + struct sdma_engine *sde; + + if (!(dd->flags & HFI1_HAS_SEND_DMA)) + return NULL; + switch (qp->ibqp.qp_type) { + case IB_QPT_UC: + case IB_QPT_RC: + break; + case IB_QPT_SMI: + return NULL; + default: + break; + } + sde = sdma_select_engine_sc(dd, qp->ibqp.qp_num >> dd->qos_shift, sc5); + return sde; +} + +struct qp_iter { + struct hfi1_ibdev *dev; + struct hfi1_qp *qp; + int specials; + int n; +}; + +struct qp_iter *qp_iter_init(struct hfi1_ibdev *dev) +{ + struct qp_iter *iter; + + iter = kzalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return NULL; + + iter->dev = dev; + iter->specials = dev->ibdev.phys_port_cnt * 2; + if (qp_iter_next(iter)) { + kfree(iter); + return NULL; + } + + return iter; +} + +int qp_iter_next(struct qp_iter *iter) +{ + struct hfi1_ibdev *dev = iter->dev; + int n = iter->n; + int ret = 1; + struct hfi1_qp *pqp = iter->qp; + struct hfi1_qp *qp; + + /* + * The approach is to consider the special qps + * as an additional table entries before the + * real hash table. Since the qp code sets + * the qp->next hash link to NULL, this works just fine. + * + * iter->specials is 2 * # ports + * + * n = 0..iter->specials is the special qp indices + * + * n = iter->specials..dev->qp_dev->qp_table_size+iter->specials are + * the potential hash bucket entries + * + */ + for (; n < dev->qp_dev->qp_table_size + iter->specials; n++) { + if (pqp) { + qp = rcu_dereference(pqp->next); + } else { + if (n < iter->specials) { + struct hfi1_pportdata *ppd; + struct hfi1_ibport *ibp; + int pidx; + + pidx = n % dev->ibdev.phys_port_cnt; + ppd = &dd_from_dev(dev)->pport[pidx]; + ibp = &ppd->ibport_data; + + if (!(n & 1)) + qp = rcu_dereference(ibp->qp[0]); + else + qp = rcu_dereference(ibp->qp[1]); + } else { + qp = rcu_dereference( + dev->qp_dev->qp_table[ + (n - iter->specials)]); + } + } + pqp = qp; + if (qp) { + iter->qp = qp; + iter->n = n; + return 0; + } + } + return ret; +} + +static const char * const qp_type_str[] = { + "SMI", "GSI", "RC", "UC", "UD", +}; + +static int qp_idle(struct hfi1_qp *qp) +{ + return + qp->s_last == qp->s_acked && + qp->s_acked == qp->s_cur && + qp->s_cur == qp->s_tail && + qp->s_tail == qp->s_head; +} + +void qp_iter_print(struct seq_file *s, struct qp_iter *iter) +{ + struct hfi1_swqe *wqe; + struct hfi1_qp *qp = iter->qp; + struct sdma_engine *sde; + + sde = qp_to_sdma_engine(qp, qp->s_sc); + wqe = get_swqe_ptr(qp, qp->s_last); + seq_printf(s, + "N %d %s QP%u R %u %s %u %u %u f=%x %u %u %u %u %u PSN %x %x %x %x %x (%u %u %u %u %u %u) QP%u LID %x SL %u MTU %d %u %u %u SDE %p,%u\n", + iter->n, + qp_idle(qp) ? "I" : "B", + qp->ibqp.qp_num, + atomic_read(&qp->refcount), + qp_type_str[qp->ibqp.qp_type], + qp->state, + wqe ? wqe->wr.opcode : 0, + qp->s_hdrwords, + qp->s_flags, + atomic_read(&qp->s_iowait.sdma_busy), + !list_empty(&qp->s_iowait.list), + qp->timeout, + wqe ? wqe->ssn : 0, + qp->s_lsn, + qp->s_last_psn, + qp->s_psn, qp->s_next_psn, + qp->s_sending_psn, qp->s_sending_hpsn, + qp->s_last, qp->s_acked, qp->s_cur, + qp->s_tail, qp->s_head, qp->s_size, + qp->remote_qpn, + qp->remote_ah_attr.dlid, + qp->remote_ah_attr.sl, + qp->pmtu, + qp->s_retry_cnt, + qp->timeout, + qp->s_rnr_retry_cnt, + sde, + sde ? sde->this_idx : 0); +} + +void qp_comm_est(struct hfi1_qp *qp) +{ + qp->r_flags |= HFI1_R_COMM_EST; + if (qp->ibqp.event_handler) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_COMM_EST; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } +} diff --git a/drivers/staging/rdma/hfi1/qp.h b/drivers/staging/rdma/hfi1/qp.h new file mode 100644 index 0000000000000..6b505859b59c8 --- /dev/null +++ b/drivers/staging/rdma/hfi1/qp.h @@ -0,0 +1,235 @@ +#ifndef _QP_H +#define _QP_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include "verbs.h" + +#define QPN_MAX (1 << 24) +#define QPNMAP_ENTRIES (QPN_MAX / PAGE_SIZE / BITS_PER_BYTE) + +/* + * QPN-map pages start out as NULL, they get allocated upon + * first use and are never deallocated. This way, + * large bitmaps are not allocated unless large numbers of QPs are used. + */ +struct qpn_map { + void *page; +}; + +struct hfi1_qpn_table { + spinlock_t lock; /* protect changes in this struct */ + unsigned flags; /* flags for QP0/1 allocated for each port */ + u32 last; /* last QP number allocated */ + u32 nmaps; /* size of the map table */ + u16 limit; + u8 incr; + /* bit map of free QP numbers other than 0/1 */ + struct qpn_map map[QPNMAP_ENTRIES]; +}; + +struct hfi1_qp_ibdev { + u32 qp_table_size; + u32 qp_table_bits; + struct hfi1_qp __rcu **qp_table; + spinlock_t qpt_lock; + struct hfi1_qpn_table qpn_table; +}; + +static inline u32 qpn_hash(struct hfi1_qp_ibdev *dev, u32 qpn) +{ + return hash_32(qpn, dev->qp_table_bits); +} + +/** + * hfi1_lookup_qpn - return the QP with the given QPN + * @ibp: the ibport + * @qpn: the QP number to look up + * + * The caller must hold the rcu_read_lock(), and keep the lock until + * the returned qp is no longer in use. + */ +static inline struct hfi1_qp *hfi1_lookup_qpn(struct hfi1_ibport *ibp, + u32 qpn) __must_hold(RCU) +{ + struct hfi1_qp *qp = NULL; + + if (unlikely(qpn <= 1)) { + qp = rcu_dereference(ibp->qp[qpn]); + } else { + struct hfi1_ibdev *dev = &ppd_from_ibp(ibp)->dd->verbs_dev; + u32 n = qpn_hash(dev->qp_dev, qpn); + + for (qp = rcu_dereference(dev->qp_dev->qp_table[n]); qp; + qp = rcu_dereference(qp->next)) + if (qp->ibqp.qp_num == qpn) + break; + } + return qp; +} + +/** + * hfi1_error_qp - put a QP into the error state + * @qp: the QP to put into the error state + * @err: the receive completion error to signal if a RWQE is active + * + * Flushes both send and receive work queues. + * Returns true if last WQE event should be generated. + * The QP r_lock and s_lock should be held and interrupts disabled. + * If we are already in error state, just return. + */ +int hfi1_error_qp(struct hfi1_qp *qp, enum ib_wc_status err); + +/** + * hfi1_modify_qp - modify the attributes of a queue pair + * @ibqp: the queue pair who's attributes we're modifying + * @attr: the new attributes + * @attr_mask: the mask of attributes to modify + * @udata: user data for libibverbs.so + * + * Returns 0 on success, otherwise returns an errno. + */ +int hfi1_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata); + +int hfi1_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_qp_init_attr *init_attr); + +/** + * hfi1_compute_aeth - compute the AETH (syndrome + MSN) + * @qp: the queue pair to compute the AETH for + * + * Returns the AETH. + */ +__be32 hfi1_compute_aeth(struct hfi1_qp *qp); + +/** + * hfi1_create_qp - create a queue pair for a device + * @ibpd: the protection domain who's device we create the queue pair for + * @init_attr: the attributes of the queue pair + * @udata: user data for libibverbs.so + * + * Returns the queue pair on success, otherwise returns an errno. + * + * Called by the ib_create_qp() core verbs function. + */ +struct ib_qp *hfi1_create_qp(struct ib_pd *ibpd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata); +/** + * hfi1_destroy_qp - destroy a queue pair + * @ibqp: the queue pair to destroy + * + * Returns 0 on success. + * + * Note that this can be called while the QP is actively sending or + * receiving! + */ +int hfi1_destroy_qp(struct ib_qp *ibqp); + +/** + * hfi1_get_credit - flush the send work queue of a QP + * @qp: the qp who's send work queue to flush + * @aeth: the Acknowledge Extended Transport Header + * + * The QP s_lock should be held. + */ +void hfi1_get_credit(struct hfi1_qp *qp, u32 aeth); + +/** + * hfi1_qp_init - allocate QP tables + * @dev: a pointer to the hfi1_ibdev + */ +int hfi1_qp_init(struct hfi1_ibdev *dev); + +/** + * hfi1_qp_exit - free the QP related structures + * @dev: a pointer to the hfi1_ibdev + */ +void hfi1_qp_exit(struct hfi1_ibdev *dev); + +/** + * hfi1_qp_waitup - wake up on the indicated event + * @qp: the QP + * @flag: flag the qp on which the qp is stalled + */ +void hfi1_qp_wakeup(struct hfi1_qp *qp, u32 flag); + +struct sdma_engine *qp_to_sdma_engine(struct hfi1_qp *qp, u8 sc5); + +struct qp_iter; + +/** + * qp_iter_init - wake up on the indicated event + * @dev: the hfi1_ibdev + */ +struct qp_iter *qp_iter_init(struct hfi1_ibdev *dev); + +/** + * qp_iter_next - wakeup on the indicated event + * @iter: the iterator for the qp hash list + */ +int qp_iter_next(struct qp_iter *iter); + +/** + * qp_iter_next - wake up on the indicated event + * @s: the seq_file to emit the qp information on + * @iter: the iterator for the qp hash list + */ +void qp_iter_print(struct seq_file *s, struct qp_iter *iter); + +/** + * qp_comm_est - handle trap with QP established + * @qp: the QP + */ +void qp_comm_est(struct hfi1_qp *qp); + +#endif /* _QP_H */ diff --git a/drivers/staging/rdma/hfi1/qsfp.c b/drivers/staging/rdma/hfi1/qsfp.c new file mode 100644 index 0000000000000..3138936157dbd --- /dev/null +++ b/drivers/staging/rdma/hfi1/qsfp.c @@ -0,0 +1,546 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "hfi.h" +#include "twsi.h" + +/* + * QSFP support for hfi driver, using "Two Wire Serial Interface" driver + * in twsi.c + */ +#define I2C_MAX_RETRY 4 + +/* + * Unlocked i2c write. Must hold dd->qsfp_i2c_mutex. + */ +static int __i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, + int offset, void *bp, int len) +{ + struct hfi1_devdata *dd = ppd->dd; + int ret, cnt; + u8 *buff = bp; + + /* Make sure TWSI bus is in sane state. */ + ret = hfi1_twsi_reset(dd, target); + if (ret) { + hfi1_dev_porterr(dd, ppd->port, + "I2C interface Reset for write failed\n"); + return -EIO; + } + + cnt = 0; + while (cnt < len) { + int wlen = len - cnt; + + ret = hfi1_twsi_blk_wr(dd, target, i2c_addr, offset, + buff + cnt, wlen); + if (ret) { + /* hfi1_twsi_blk_wr() 1 for error, else 0 */ + return -EIO; + } + offset += wlen; + cnt += wlen; + } + + /* Must wait min 20us between qsfp i2c transactions */ + udelay(20); + + return cnt; +} + +int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, + void *bp, int len) +{ + struct hfi1_devdata *dd = ppd->dd; + int ret; + + ret = mutex_lock_interruptible(&dd->qsfp_i2c_mutex); + if (!ret) { + ret = __i2c_write(ppd, target, i2c_addr, offset, bp, len); + mutex_unlock(&dd->qsfp_i2c_mutex); + } + + return ret; +} + +/* + * Unlocked i2c read. Must hold dd->qsfp_i2c_mutex. + */ +static int __i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, + int offset, void *bp, int len) +{ + struct hfi1_devdata *dd = ppd->dd; + int ret, cnt, pass = 0; + int stuck = 0; + u8 *buff = bp; + + /* Make sure TWSI bus is in sane state. */ + ret = hfi1_twsi_reset(dd, target); + if (ret) { + hfi1_dev_porterr(dd, ppd->port, + "I2C interface Reset for read failed\n"); + ret = -EIO; + stuck = 1; + goto exit; + } + + cnt = 0; + while (cnt < len) { + int rlen = len - cnt; + + ret = hfi1_twsi_blk_rd(dd, target, i2c_addr, offset, + buff + cnt, rlen); + /* Some QSFP's fail first try. Retry as experiment */ + if (ret && cnt == 0 && ++pass < I2C_MAX_RETRY) + continue; + if (ret) { + /* hfi1_twsi_blk_rd() 1 for error, else 0 */ + ret = -EIO; + goto exit; + } + offset += rlen; + cnt += rlen; + } + + ret = cnt; + +exit: + if (stuck) + dd_dev_err(dd, "I2C interface bus stuck non-idle\n"); + + if (pass >= I2C_MAX_RETRY && ret) + hfi1_dev_porterr(dd, ppd->port, + "I2C failed even retrying\n"); + else if (pass) + hfi1_dev_porterr(dd, ppd->port, "I2C retries: %d\n", pass); + + /* Must wait min 20us between qsfp i2c transactions */ + udelay(20); + + return ret; +} + +int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, int offset, + void *bp, int len) +{ + struct hfi1_devdata *dd = ppd->dd; + int ret; + + ret = mutex_lock_interruptible(&dd->qsfp_i2c_mutex); + if (!ret) { + ret = __i2c_read(ppd, target, i2c_addr, offset, bp, len); + mutex_unlock(&dd->qsfp_i2c_mutex); + } + + return ret; +} + +int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, + int len) +{ + int count = 0; + int offset; + int nwrite; + int ret; + u8 page; + + ret = mutex_lock_interruptible(&ppd->dd->qsfp_i2c_mutex); + if (ret) + return ret; + + while (count < len) { + /* + * Set the qsfp page based on a zero-based addresss + * and a page size of QSFP_PAGESIZE bytes. + */ + page = (u8)(addr / QSFP_PAGESIZE); + + ret = __i2c_write(ppd, target, QSFP_DEV, + QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1); + if (ret != 1) { + hfi1_dev_porterr( + ppd->dd, + ppd->port, + "can't write QSFP_PAGE_SELECT_BYTE: %d\n", ret); + ret = -EIO; + break; + } + + /* truncate write to end of page if crossing page boundary */ + offset = addr % QSFP_PAGESIZE; + nwrite = len - count; + if ((offset + nwrite) > QSFP_PAGESIZE) + nwrite = QSFP_PAGESIZE - offset; + + ret = __i2c_write(ppd, target, QSFP_DEV, offset, bp + count, + nwrite); + if (ret <= 0) /* stop on error or nothing read */ + break; + + count += ret; + addr += ret; + } + + mutex_unlock(&ppd->dd->qsfp_i2c_mutex); + + if (ret < 0) + return ret; + return count; +} + +int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, + int len) +{ + int count = 0; + int offset; + int nread; + int ret; + u8 page; + + ret = mutex_lock_interruptible(&ppd->dd->qsfp_i2c_mutex); + if (ret) + return ret; + + while (count < len) { + /* + * Set the qsfp page based on a zero-based address + * and a page size of QSFP_PAGESIZE bytes. + */ + page = (u8)(addr / QSFP_PAGESIZE); + ret = __i2c_write(ppd, target, QSFP_DEV, + QSFP_PAGE_SELECT_BYTE_OFFS, &page, 1); + if (ret != 1) { + hfi1_dev_porterr( + ppd->dd, + ppd->port, + "can't write QSFP_PAGE_SELECT_BYTE: %d\n", ret); + ret = -EIO; + break; + } + + /* truncate read to end of page if crossing page boundary */ + offset = addr % QSFP_PAGESIZE; + nread = len - count; + if ((offset + nread) > QSFP_PAGESIZE) + nread = QSFP_PAGESIZE - offset; + + ret = __i2c_read(ppd, target, QSFP_DEV, offset, bp + count, + nread); + if (ret <= 0) /* stop on error or nothing read */ + break; + + count += ret; + addr += ret; + } + + mutex_unlock(&ppd->dd->qsfp_i2c_mutex); + + if (ret < 0) + return ret; + return count; +} + +/* + * This function caches the QSFP memory range in 128 byte chunks. + * As an example, the next byte after address 255 is byte 128 from + * upper page 01H (if existing) rather than byte 0 from lower page 00H. + */ +int refresh_qsfp_cache(struct hfi1_pportdata *ppd, struct qsfp_data *cp) +{ + u32 target = ppd->dd->hfi1_id; + int ret; + unsigned long flags; + u8 *cache = &cp->cache[0]; + + /* ensure sane contents on invalid reads, for cable swaps */ + memset(cache, 0, (QSFP_MAX_NUM_PAGES*128)); + dd_dev_info(ppd->dd, "%s: called\n", __func__); + if (!qsfp_mod_present(ppd)) { + ret = -ENODEV; + goto bail; + } + + ret = qsfp_read(ppd, target, 0, cache, 256); + if (ret != 256) { + dd_dev_info(ppd->dd, + "%s: Read of pages 00H failed, expected 256, got %d\n", + __func__, ret); + goto bail; + } + + if (cache[0] != 0x0C && cache[0] != 0x0D) + goto bail; + + /* Is paging enabled? */ + if (!(cache[2] & 4)) { + + /* Paging enabled, page 03 required */ + if ((cache[195] & 0xC0) == 0xC0) { + /* all */ + ret = qsfp_read(ppd, target, 384, cache + 256, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + ret = qsfp_read(ppd, target, 640, cache + 384, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + ret = qsfp_read(ppd, target, 896, cache + 512, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + } else if ((cache[195] & 0x80) == 0x80) { + /* only page 2 and 3 */ + ret = qsfp_read(ppd, target, 640, cache + 384, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + ret = qsfp_read(ppd, target, 896, cache + 512, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + } else if ((cache[195] & 0x40) == 0x40) { + /* only page 1 and 3 */ + ret = qsfp_read(ppd, target, 384, cache + 256, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + ret = qsfp_read(ppd, target, 896, cache + 512, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + } else { + /* only page 3 */ + ret = qsfp_read(ppd, target, 896, cache + 512, 128); + if (ret <= 0 || ret != 128) { + dd_dev_info(ppd->dd, "%s: failed\n", __func__); + goto bail; + } + } + } + + spin_lock_irqsave(&ppd->qsfp_info.qsfp_lock, flags); + ppd->qsfp_info.cache_valid = 1; + ppd->qsfp_info.cache_refresh_required = 0; + spin_unlock_irqrestore(&ppd->qsfp_info.qsfp_lock, flags); + + return 0; + +bail: + memset(cache, 0, (QSFP_MAX_NUM_PAGES*128)); + return ret; +} + +const char * const hfi1_qsfp_devtech[16] = { + "850nm VCSEL", "1310nm VCSEL", "1550nm VCSEL", "1310nm FP", + "1310nm DFB", "1550nm DFB", "1310nm EML", "1550nm EML", + "Cu Misc", "1490nm DFB", "Cu NoEq", "Cu Eq", + "Undef", "Cu Active BothEq", "Cu FarEq", "Cu NearEq" +}; + +#define QSFP_DUMP_CHUNK 16 /* Holds longest string */ +#define QSFP_DEFAULT_HDR_CNT 224 + +static const char *pwr_codes = "1.5W2.0W2.5W3.5W"; + +int qsfp_mod_present(struct hfi1_pportdata *ppd) +{ + if (HFI1_CAP_IS_KSET(QSFP_ENABLED)) { + struct hfi1_devdata *dd = ppd->dd; + u64 reg; + + reg = read_csr(dd, + dd->hfi1_id ? ASIC_QSFP2_IN : ASIC_QSFP1_IN); + return !(reg & QSFP_HFI0_MODPRST_N); + } + /* always return cable present */ + return 1; +} + +/* + * This function maps QSFP memory addresses in 128 byte chunks in the following + * fashion per the CableInfo SMA query definition in the IBA 1.3 spec/OPA Gen 1 + * spec + * For addr 000-127, lower page 00h + * For addr 128-255, upper page 00h + * For addr 256-383, upper page 01h + * For addr 384-511, upper page 02h + * For addr 512-639, upper page 03h + * + * For addresses beyond this range, it returns the invalid range of data buffer + * set to 0. + * For upper pages that are optional, if they are not valid, returns the + * particular range of bytes in the data buffer set to 0. + */ +int get_cable_info(struct hfi1_devdata *dd, u32 port_num, u32 addr, u32 len, + u8 *data) +{ + struct hfi1_pportdata *ppd; + u32 excess_len = 0; + int ret = 0; + + if (port_num > dd->num_pports || port_num < 1) { + dd_dev_info(dd, "%s: Invalid port number %d\n", + __func__, port_num); + ret = -EINVAL; + goto set_zeroes; + } + + ppd = dd->pport + (port_num - 1); + if (!qsfp_mod_present(ppd)) { + ret = -ENODEV; + goto set_zeroes; + } + + if (!ppd->qsfp_info.cache_valid) { + ret = -EINVAL; + goto set_zeroes; + } + + if (addr >= (QSFP_MAX_NUM_PAGES * 128)) { + ret = -ERANGE; + goto set_zeroes; + } + + if ((addr + len) > (QSFP_MAX_NUM_PAGES * 128)) { + excess_len = (addr + len) - (QSFP_MAX_NUM_PAGES * 128); + memcpy(data, &ppd->qsfp_info.cache[addr], (len - excess_len)); + data += (len - excess_len); + goto set_zeroes; + } + + memcpy(data, &ppd->qsfp_info.cache[addr], len); + return 0; + +set_zeroes: + memset(data, 0, excess_len); + return ret; +} + +int qsfp_dump(struct hfi1_pportdata *ppd, char *buf, int len) +{ + u8 *cache = &ppd->qsfp_info.cache[0]; + u8 bin_buff[QSFP_DUMP_CHUNK]; + char lenstr[6]; + int sofar, ret; + int bidx = 0; + u8 *atten = &cache[QSFP_ATTEN_OFFS]; + u8 *vendor_oui = &cache[QSFP_VOUI_OFFS]; + + sofar = 0; + lenstr[0] = ' '; + lenstr[1] = '\0'; + + if (ppd->qsfp_info.cache_valid) { + + if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS])) + sprintf(lenstr, "%dM ", cache[QSFP_MOD_LEN_OFFS]); + + sofar += scnprintf(buf + sofar, len - sofar, "PWR:%.3sW\n", + pwr_codes + + (QSFP_PWR(cache[QSFP_MOD_PWR_OFFS]) * 4)); + + sofar += scnprintf(buf + sofar, len - sofar, "TECH:%s%s\n", + lenstr, + hfi1_qsfp_devtech[(cache[QSFP_MOD_TECH_OFFS]) >> 4]); + + sofar += scnprintf(buf + sofar, len - sofar, "Vendor:%.*s\n", + QSFP_VEND_LEN, &cache[QSFP_VEND_OFFS]); + + sofar += scnprintf(buf + sofar, len - sofar, "OUI:%06X\n", + QSFP_OUI(vendor_oui)); + + sofar += scnprintf(buf + sofar, len - sofar, "Part#:%.*s\n", + QSFP_PN_LEN, &cache[QSFP_PN_OFFS]); + + sofar += scnprintf(buf + sofar, len - sofar, "Rev:%.*s\n", + QSFP_REV_LEN, &cache[QSFP_REV_OFFS]); + + if (QSFP_IS_CU(cache[QSFP_MOD_TECH_OFFS])) + sofar += scnprintf(buf + sofar, len - sofar, + "Atten:%d, %d\n", + QSFP_ATTEN_SDR(atten), + QSFP_ATTEN_DDR(atten)); + + sofar += scnprintf(buf + sofar, len - sofar, "Serial:%.*s\n", + QSFP_SN_LEN, &cache[QSFP_SN_OFFS]); + + sofar += scnprintf(buf + sofar, len - sofar, "Date:%.*s\n", + QSFP_DATE_LEN, &cache[QSFP_DATE_OFFS]); + + sofar += scnprintf(buf + sofar, len - sofar, "Lot:%.*s\n", + QSFP_LOT_LEN, &cache[QSFP_LOT_OFFS]); + + while (bidx < QSFP_DEFAULT_HDR_CNT) { + int iidx; + + memcpy(bin_buff, &cache[bidx], QSFP_DUMP_CHUNK); + for (iidx = 0; iidx < QSFP_DUMP_CHUNK; ++iidx) { + sofar += scnprintf(buf + sofar, len-sofar, + " %02X", bin_buff[iidx]); + } + sofar += scnprintf(buf + sofar, len - sofar, "\n"); + bidx += QSFP_DUMP_CHUNK; + } + } + ret = sofar; + return ret; +} diff --git a/drivers/staging/rdma/hfi1/qsfp.h b/drivers/staging/rdma/hfi1/qsfp.h new file mode 100644 index 0000000000000..d30c2a6baa0b8 --- /dev/null +++ b/drivers/staging/rdma/hfi1/qsfp.h @@ -0,0 +1,222 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +/* QSFP support common definitions, for hfi driver */ + +#define QSFP_DEV 0xA0 +#define QSFP_PWR_LAG_MSEC 2000 +#define QSFP_MODPRS_LAG_MSEC 20 +/* 128 byte pages, per SFF 8636 rev 2.4 */ +#define QSFP_MAX_NUM_PAGES 5 + +/* + * Below are masks for QSFP pins. Pins are the same for HFI0 and HFI1. + * _N means asserted low + */ +#define QSFP_HFI0_I2CCLK (1 << 0) +#define QSFP_HFI0_I2CDAT (1 << 1) +#define QSFP_HFI0_RESET_N (1 << 2) +#define QSFP_HFI0_INT_N (1 << 3) +#define QSFP_HFI0_MODPRST_N (1 << 4) + +/* QSFP is paged at 256 bytes */ +#define QSFP_PAGESIZE 256 + +/* Defined fields that Intel requires of qualified cables */ +/* Byte 0 is Identifier, not checked */ +/* Byte 1 is reserved "status MSB" */ +/* Byte 2 is "status LSB" We only care that D2 "Flat Mem" is set. */ +/* + * Rest of first 128 not used, although 127 is reserved for page select + * if module is not "Flat memory". + */ +#define QSFP_PAGE_SELECT_BYTE_OFFS 127 +/* Byte 128 is Identifier: must be 0x0c for QSFP, or 0x0d for QSFP+ */ +#define QSFP_MOD_ID_OFFS 128 +/* + * Byte 129 is "Extended Identifier". We only care about D7,D6: Power class + * 0:1.5W, 1:2.0W, 2:2.5W, 3:3.5W + */ +#define QSFP_MOD_PWR_OFFS 129 +/* Byte 130 is Connector type. Not Intel req'd */ +/* Bytes 131..138 are Transceiver types, bit maps for various tech, none IB */ +/* Byte 139 is encoding. code 0x01 is 8b10b. Not Intel req'd */ +/* byte 140 is nominal bit-rate, in units of 100Mbits/sec Not Intel req'd */ +/* Byte 141 is Extended Rate Select. Not Intel req'd */ +/* Bytes 142..145 are lengths for various fiber types. Not Intel req'd */ +/* Byte 146 is length for Copper. Units of 1 meter */ +#define QSFP_MOD_LEN_OFFS 146 +/* + * Byte 147 is Device technology. D0..3 not Intel req'd + * D4..7 select from 15 choices, translated by table: + */ +#define QSFP_MOD_TECH_OFFS 147 +extern const char *const hfi1_qsfp_devtech[16]; +/* Active Equalization includes fiber, copper full EQ, and copper near Eq */ +#define QSFP_IS_ACTIVE(tech) ((0xA2FF >> ((tech) >> 4)) & 1) +/* Active Equalization includes fiber, copper full EQ, and copper far Eq */ +#define QSFP_IS_ACTIVE_FAR(tech) ((0x32FF >> ((tech) >> 4)) & 1) +/* Attenuation should be valid for copper other than full/near Eq */ +#define QSFP_HAS_ATTEN(tech) ((0x4D00 >> ((tech) >> 4)) & 1) +/* Length is only valid if technology is "copper" */ +#define QSFP_IS_CU(tech) ((0xED00 >> ((tech) >> 4)) & 1) +#define QSFP_TECH_1490 9 + +#define QSFP_OUI(oui) (((unsigned)oui[0] << 16) | ((unsigned)oui[1] << 8) | \ + oui[2]) +#define QSFP_OUI_AMPHENOL 0x415048 +#define QSFP_OUI_FINISAR 0x009065 +#define QSFP_OUI_GORE 0x002177 + +/* Bytes 148..163 are Vendor Name, Left-justified Blank-filled */ +#define QSFP_VEND_OFFS 148 +#define QSFP_VEND_LEN 16 +/* Byte 164 is IB Extended transceiver codes Bits D0..3 are SDR,DDR,QDR,EDR */ +#define QSFP_IBXCV_OFFS 164 +/* Bytes 165..167 are Vendor OUI number */ +#define QSFP_VOUI_OFFS 165 +#define QSFP_VOUI_LEN 3 +/* Bytes 168..183 are Vendor Part Number, string */ +#define QSFP_PN_OFFS 168 +#define QSFP_PN_LEN 16 +/* Bytes 184,185 are Vendor Rev. Left Justified, Blank-filled */ +#define QSFP_REV_OFFS 184 +#define QSFP_REV_LEN 2 +/* + * Bytes 186,187 are Wavelength, if Optical. Not Intel req'd + * If copper, they are attenuation in dB: + * Byte 186 is at 2.5Gb/sec (SDR), Byte 187 at 5.0Gb/sec (DDR) + */ +#define QSFP_ATTEN_OFFS 186 +#define QSFP_ATTEN_LEN 2 +/* Bytes 188,189 are Wavelength tolerance, not Intel req'd */ +/* Byte 190 is Max Case Temp. Not Intel req'd */ +/* Byte 191 is LSB of sum of bytes 128..190. Not Intel req'd */ +#define QSFP_CC_OFFS 191 +/* Bytes 192..195 are Options implemented in qsfp. Not Intel req'd */ +/* Bytes 196..211 are Serial Number, String */ +#define QSFP_SN_OFFS 196 +#define QSFP_SN_LEN 16 +/* Bytes 212..219 are date-code YYMMDD (MM==1 for Jan) */ +#define QSFP_DATE_OFFS 212 +#define QSFP_DATE_LEN 6 +/* Bytes 218,219 are optional lot-code, string */ +#define QSFP_LOT_OFFS 218 +#define QSFP_LOT_LEN 2 +/* Bytes 220, 221 indicate monitoring options, Not Intel req'd */ +/* Byte 223 is LSB of sum of bytes 192..222 */ +#define QSFP_CC_EXT_OFFS 223 + +/* + * Interrupt flag masks + */ +#define QSFP_DATA_NOT_READY 0x01 + +#define QSFP_HIGH_TEMP_ALARM 0x80 +#define QSFP_LOW_TEMP_ALARM 0x40 +#define QSFP_HIGH_TEMP_WARNING 0x20 +#define QSFP_LOW_TEMP_WARNING 0x10 + +#define QSFP_HIGH_VCC_ALARM 0x80 +#define QSFP_LOW_VCC_ALARM 0x40 +#define QSFP_HIGH_VCC_WARNING 0x20 +#define QSFP_LOW_VCC_WARNING 0x10 + +#define QSFP_HIGH_POWER_ALARM 0x88 +#define QSFP_LOW_POWER_ALARM 0x44 +#define QSFP_HIGH_POWER_WARNING 0x22 +#define QSFP_LOW_POWER_WARNING 0x11 + +#define QSFP_HIGH_BIAS_ALARM 0x88 +#define QSFP_LOW_BIAS_ALARM 0x44 +#define QSFP_HIGH_BIAS_WARNING 0x22 +#define QSFP_LOW_BIAS_WARNING 0x11 + +/* + * struct qsfp_data encapsulates state of QSFP device for one port. + * it will be part of port-specific data if a board supports QSFP. + * + * Since multiple board-types use QSFP, and their pport_data structs + * differ (in the chip-specific section), we need a pointer to its head. + * + * Avoiding premature optimization, we will have one work_struct per port, + * and let the qsfp_lock arbitrate access to common resources. + * + */ + +#define QSFP_PWR(pbyte) (((pbyte) >> 6) & 3) +#define QSFP_ATTEN_SDR(attenarray) (attenarray[0]) +#define QSFP_ATTEN_DDR(attenarray) (attenarray[1]) + +struct qsfp_data { + /* Helps to find our way */ + struct hfi1_pportdata *ppd; + struct work_struct qsfp_work; + u8 cache[QSFP_MAX_NUM_PAGES*128]; + spinlock_t qsfp_lock; + u8 check_interrupt_flags; + u8 qsfp_interrupt_functional; + u8 cache_valid; + u8 cache_refresh_required; +}; + +int refresh_qsfp_cache(struct hfi1_pportdata *ppd, + struct qsfp_data *cp); +int qsfp_mod_present(struct hfi1_pportdata *ppd); +int get_cable_info(struct hfi1_devdata *dd, u32 port_num, u32 addr, + u32 len, u8 *data); + +int i2c_write(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, + int offset, void *bp, int len); +int i2c_read(struct hfi1_pportdata *ppd, u32 target, int i2c_addr, + int offset, void *bp, int len); +int qsfp_write(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, + int len); +int qsfp_read(struct hfi1_pportdata *ppd, u32 target, int addr, void *bp, + int len); diff --git a/drivers/staging/rdma/hfi1/rc.c b/drivers/staging/rdma/hfi1/rc.c new file mode 100644 index 0000000000000..632dd5ba7dfdb --- /dev/null +++ b/drivers/staging/rdma/hfi1/rc.c @@ -0,0 +1,2426 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "hfi.h" +#include "qp.h" +#include "sdma.h" +#include "trace.h" + +/* cut down ridiculously long IB macro names */ +#define OP(x) IB_OPCODE_RC_##x + +static void rc_timeout(unsigned long arg); + +static u32 restart_sge(struct hfi1_sge_state *ss, struct hfi1_swqe *wqe, + u32 psn, u32 pmtu) +{ + u32 len; + + len = delta_psn(psn, wqe->psn) * pmtu; + ss->sge = wqe->sg_list[0]; + ss->sg_list = wqe->sg_list + 1; + ss->num_sge = wqe->wr.num_sge; + ss->total_len = wqe->length; + hfi1_skip_sge(ss, len, 0); + return wqe->length - len; +} + +static void start_timer(struct hfi1_qp *qp) +{ + qp->s_flags |= HFI1_S_TIMER; + qp->s_timer.function = rc_timeout; + /* 4.096 usec. * (1 << qp->timeout) */ + qp->s_timer.expires = jiffies + qp->timeout_jiffies; + add_timer(&qp->s_timer); +} + +/** + * make_rc_ack - construct a response packet (ACK, NAK, or RDMA read) + * @dev: the device for this QP + * @qp: a pointer to the QP + * @ohdr: a pointer to the IB header being constructed + * @pmtu: the path MTU + * + * Return 1 if constructed; otherwise, return 0. + * Note that we are in the responder's side of the QP context. + * Note the QP s_lock must be held. + */ +static int make_rc_ack(struct hfi1_ibdev *dev, struct hfi1_qp *qp, + struct hfi1_other_headers *ohdr, u32 pmtu) +{ + struct hfi1_ack_entry *e; + u32 hwords; + u32 len; + u32 bth0; + u32 bth2; + int middle = 0; + + /* Don't send an ACK if we aren't supposed to. */ + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK)) + goto bail; + + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ + hwords = 5; + + switch (qp->s_ack_state) { + case OP(RDMA_READ_RESPONSE_LAST): + case OP(RDMA_READ_RESPONSE_ONLY): + e = &qp->s_ack_queue[qp->s_tail_ack_queue]; + if (e->rdma_sge.mr) { + hfi1_put_mr(e->rdma_sge.mr); + e->rdma_sge.mr = NULL; + } + /* FALLTHROUGH */ + case OP(ATOMIC_ACKNOWLEDGE): + /* + * We can increment the tail pointer now that the last + * response has been sent instead of only being + * constructed. + */ + if (++qp->s_tail_ack_queue > HFI1_MAX_RDMA_ATOMIC) + qp->s_tail_ack_queue = 0; + /* FALLTHROUGH */ + case OP(SEND_ONLY): + case OP(ACKNOWLEDGE): + /* Check for no next entry in the queue. */ + if (qp->r_head_ack_queue == qp->s_tail_ack_queue) { + if (qp->s_flags & HFI1_S_ACK_PENDING) + goto normal; + goto bail; + } + + e = &qp->s_ack_queue[qp->s_tail_ack_queue]; + if (e->opcode == OP(RDMA_READ_REQUEST)) { + /* + * If a RDMA read response is being resent and + * we haven't seen the duplicate request yet, + * then stop sending the remaining responses the + * responder has seen until the requester re-sends it. + */ + len = e->rdma_sge.sge_length; + if (len && !e->rdma_sge.mr) { + qp->s_tail_ack_queue = qp->r_head_ack_queue; + goto bail; + } + /* Copy SGE state in case we need to resend */ + qp->s_rdma_mr = e->rdma_sge.mr; + if (qp->s_rdma_mr) + hfi1_get_mr(qp->s_rdma_mr); + qp->s_ack_rdma_sge.sge = e->rdma_sge; + qp->s_ack_rdma_sge.num_sge = 1; + qp->s_cur_sge = &qp->s_ack_rdma_sge; + if (len > pmtu) { + len = pmtu; + qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); + } else { + qp->s_ack_state = OP(RDMA_READ_RESPONSE_ONLY); + e->sent = 1; + } + ohdr->u.aeth = hfi1_compute_aeth(qp); + hwords++; + qp->s_ack_rdma_psn = e->psn; + bth2 = mask_psn(qp->s_ack_rdma_psn++); + } else { + /* COMPARE_SWAP or FETCH_ADD */ + qp->s_cur_sge = NULL; + len = 0; + qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE); + ohdr->u.at.aeth = hfi1_compute_aeth(qp); + ohdr->u.at.atomic_ack_eth[0] = + cpu_to_be32(e->atomic_data >> 32); + ohdr->u.at.atomic_ack_eth[1] = + cpu_to_be32(e->atomic_data); + hwords += sizeof(ohdr->u.at) / sizeof(u32); + bth2 = mask_psn(e->psn); + e->sent = 1; + } + bth0 = qp->s_ack_state << 24; + break; + + case OP(RDMA_READ_RESPONSE_FIRST): + qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE); + /* FALLTHROUGH */ + case OP(RDMA_READ_RESPONSE_MIDDLE): + qp->s_cur_sge = &qp->s_ack_rdma_sge; + qp->s_rdma_mr = qp->s_ack_rdma_sge.sge.mr; + if (qp->s_rdma_mr) + hfi1_get_mr(qp->s_rdma_mr); + len = qp->s_ack_rdma_sge.sge.sge_length; + if (len > pmtu) { + len = pmtu; + middle = HFI1_CAP_IS_KSET(SDMA_AHG); + } else { + ohdr->u.aeth = hfi1_compute_aeth(qp); + hwords++; + qp->s_ack_state = OP(RDMA_READ_RESPONSE_LAST); + e = &qp->s_ack_queue[qp->s_tail_ack_queue]; + e->sent = 1; + } + bth0 = qp->s_ack_state << 24; + bth2 = mask_psn(qp->s_ack_rdma_psn++); + break; + + default: +normal: + /* + * Send a regular ACK. + * Set the s_ack_state so we wait until after sending + * the ACK before setting s_ack_state to ACKNOWLEDGE + * (see above). + */ + qp->s_ack_state = OP(SEND_ONLY); + qp->s_flags &= ~HFI1_S_ACK_PENDING; + qp->s_cur_sge = NULL; + if (qp->s_nak_state) + ohdr->u.aeth = + cpu_to_be32((qp->r_msn & HFI1_MSN_MASK) | + (qp->s_nak_state << + HFI1_AETH_CREDIT_SHIFT)); + else + ohdr->u.aeth = hfi1_compute_aeth(qp); + hwords++; + len = 0; + bth0 = OP(ACKNOWLEDGE) << 24; + bth2 = mask_psn(qp->s_ack_psn); + } + qp->s_rdma_ack_cnt++; + qp->s_hdrwords = hwords; + qp->s_cur_size = len; + hfi1_make_ruc_header(qp, ohdr, bth0, bth2, middle); + return 1; + +bail: + qp->s_ack_state = OP(ACKNOWLEDGE); + /* + * Ensure s_rdma_ack_cnt changes are committed prior to resetting + * HFI1_S_RESP_PENDING + */ + smp_wmb(); + qp->s_flags &= ~(HFI1_S_RESP_PENDING + | HFI1_S_ACK_PENDING + | HFI1_S_AHG_VALID); + return 0; +} + +/** + * hfi1_make_rc_req - construct a request packet (SEND, RDMA r/w, ATOMIC) + * @qp: a pointer to the QP + * + * Return 1 if constructed; otherwise, return 0. + */ +int hfi1_make_rc_req(struct hfi1_qp *qp) +{ + struct hfi1_ibdev *dev = to_idev(qp->ibqp.device); + struct hfi1_other_headers *ohdr; + struct hfi1_sge_state *ss; + struct hfi1_swqe *wqe; + /* header size in 32-bit words LRH+BTH = (8+12)/4. */ + u32 hwords = 5; + u32 len; + u32 bth0 = 0; + u32 bth2; + u32 pmtu = qp->pmtu; + char newreq; + unsigned long flags; + int ret = 0; + int middle = 0; + int delta; + + ohdr = &qp->s_hdr->ibh.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr->ibh.u.l.oth; + + /* + * The lock is needed to synchronize between the sending tasklet, + * the receive interrupt handler, and timeout re-sends. + */ + spin_lock_irqsave(&qp->s_lock, flags); + + /* Sending responses has higher priority over sending requests. */ + if ((qp->s_flags & HFI1_S_RESP_PENDING) && + make_rc_ack(dev, qp, ohdr, pmtu)) + goto done; + + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_SEND_OK)) { + if (!(ib_hfi1_state_ops[qp->state] & HFI1_FLUSH_SEND)) + goto bail; + /* We are in the error state, flush the work request. */ + if (qp->s_last == qp->s_head) + goto bail; + /* If DMAs are in progress, we can't flush immediately. */ + if (atomic_read(&qp->s_iowait.sdma_busy)) { + qp->s_flags |= HFI1_S_WAIT_DMA; + goto bail; + } + clear_ahg(qp); + wqe = get_swqe_ptr(qp, qp->s_last); + hfi1_send_complete(qp, wqe, qp->s_last != qp->s_acked ? + IB_WC_SUCCESS : IB_WC_WR_FLUSH_ERR); + /* will get called again */ + goto done; + } + + if (qp->s_flags & (HFI1_S_WAIT_RNR | HFI1_S_WAIT_ACK)) + goto bail; + + if (cmp_psn(qp->s_psn, qp->s_sending_hpsn) <= 0) { + if (cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) <= 0) { + qp->s_flags |= HFI1_S_WAIT_PSN; + goto bail; + } + qp->s_sending_psn = qp->s_psn; + qp->s_sending_hpsn = qp->s_psn - 1; + } + + /* Send a request. */ + wqe = get_swqe_ptr(qp, qp->s_cur); + switch (qp->s_state) { + default: + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_NEXT_SEND_OK)) + goto bail; + /* + * Resend an old request or start a new one. + * + * We keep track of the current SWQE so that + * we don't reset the "furthest progress" state + * if we need to back up. + */ + newreq = 0; + if (qp->s_cur == qp->s_tail) { + /* Check if send work queue is empty. */ + if (qp->s_tail == qp->s_head) { + clear_ahg(qp); + goto bail; + } + /* + * If a fence is requested, wait for previous + * RDMA read and atomic operations to finish. + */ + if ((wqe->wr.send_flags & IB_SEND_FENCE) && + qp->s_num_rd_atomic) { + qp->s_flags |= HFI1_S_WAIT_FENCE; + goto bail; + } + wqe->psn = qp->s_next_psn; + newreq = 1; + } + /* + * Note that we have to be careful not to modify the + * original work request since we may need to resend + * it. + */ + len = wqe->length; + ss = &qp->s_sge; + bth2 = mask_psn(qp->s_psn); + switch (wqe->wr.opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + /* If no credit, return. */ + if (!(qp->s_flags & HFI1_S_UNLIMITED_CREDIT) && + cmp_msn(wqe->ssn, qp->s_lsn + 1) > 0) { + qp->s_flags |= HFI1_S_WAIT_SSN_CREDIT; + goto bail; + } + wqe->lpsn = wqe->psn; + if (len > pmtu) { + wqe->lpsn += (len - 1) / pmtu; + qp->s_state = OP(SEND_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_ONLY); + else { + qp->s_state = OP(SEND_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + bth2 |= IB_BTH_REQ_ACK; + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_RDMA_WRITE: + if (newreq && !(qp->s_flags & HFI1_S_UNLIMITED_CREDIT)) + qp->s_lsn++; + /* FALLTHROUGH */ + case IB_WR_RDMA_WRITE_WITH_IMM: + /* If no credit, return. */ + if (!(qp->s_flags & HFI1_S_UNLIMITED_CREDIT) && + cmp_msn(wqe->ssn, qp->s_lsn + 1) > 0) { + qp->s_flags |= HFI1_S_WAIT_SSN_CREDIT; + goto bail; + } + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + hwords += sizeof(struct ib_reth) / sizeof(u32); + wqe->lpsn = wqe->psn; + if (len > pmtu) { + wqe->lpsn += (len - 1) / pmtu; + qp->s_state = OP(RDMA_WRITE_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_ONLY); + else { + qp->s_state = + OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after RETH */ + ohdr->u.rc.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + } + bth2 |= IB_BTH_REQ_ACK; + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_RDMA_READ: + /* + * Don't allow more operations to be started + * than the QP limits allow. + */ + if (newreq) { + if (qp->s_num_rd_atomic >= + qp->s_max_rd_atomic) { + qp->s_flags |= HFI1_S_WAIT_RDMAR; + goto bail; + } + qp->s_num_rd_atomic++; + if (!(qp->s_flags & HFI1_S_UNLIMITED_CREDIT)) + qp->s_lsn++; + /* + * Adjust s_next_psn to count the + * expected number of responses. + */ + if (len > pmtu) + qp->s_next_psn += (len - 1) / pmtu; + wqe->lpsn = qp->s_next_psn++; + } + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + qp->s_state = OP(RDMA_READ_REQUEST); + hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32); + ss = NULL; + len = 0; + bth2 |= IB_BTH_REQ_ACK; + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + /* + * Don't allow more operations to be started + * than the QP limits allow. + */ + if (newreq) { + if (qp->s_num_rd_atomic >= + qp->s_max_rd_atomic) { + qp->s_flags |= HFI1_S_WAIT_RDMAR; + goto bail; + } + qp->s_num_rd_atomic++; + if (!(qp->s_flags & HFI1_S_UNLIMITED_CREDIT)) + qp->s_lsn++; + wqe->lpsn = wqe->psn; + } + if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP) { + qp->s_state = OP(COMPARE_SWAP); + ohdr->u.atomic_eth.swap_data = cpu_to_be64( + wqe->wr.wr.atomic.swap); + ohdr->u.atomic_eth.compare_data = cpu_to_be64( + wqe->wr.wr.atomic.compare_add); + } else { + qp->s_state = OP(FETCH_ADD); + ohdr->u.atomic_eth.swap_data = cpu_to_be64( + wqe->wr.wr.atomic.compare_add); + ohdr->u.atomic_eth.compare_data = 0; + } + ohdr->u.atomic_eth.vaddr[0] = cpu_to_be32( + wqe->wr.wr.atomic.remote_addr >> 32); + ohdr->u.atomic_eth.vaddr[1] = cpu_to_be32( + wqe->wr.wr.atomic.remote_addr); + ohdr->u.atomic_eth.rkey = cpu_to_be32( + wqe->wr.wr.atomic.rkey); + hwords += sizeof(struct ib_atomic_eth) / sizeof(u32); + ss = NULL; + len = 0; + bth2 |= IB_BTH_REQ_ACK; + if (++qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + + default: + goto bail; + } + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + qp->s_sge.total_len = wqe->length; + qp->s_len = wqe->length; + if (newreq) { + qp->s_tail++; + if (qp->s_tail >= qp->s_size) + qp->s_tail = 0; + } + if (wqe->wr.opcode == IB_WR_RDMA_READ) + qp->s_psn = wqe->lpsn + 1; + else { + qp->s_psn++; + if (cmp_psn(qp->s_psn, qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + } + break; + + case OP(RDMA_READ_RESPONSE_FIRST): + /* + * qp->s_state is normally set to the opcode of the + * last packet constructed for new requests and therefore + * is never set to RDMA read response. + * RDMA_READ_RESPONSE_FIRST is used by the ACK processing + * thread to indicate a SEND needs to be restarted from an + * earlier PSN without interfering with the sending thread. + * See restart_rc(). + */ + qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, pmtu); + /* FALLTHROUGH */ + case OP(SEND_FIRST): + qp->s_state = OP(SEND_MIDDLE); + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + bth2 = mask_psn(qp->s_psn++); + if (cmp_psn(qp->s_psn, qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + ss = &qp->s_sge; + len = qp->s_len; + if (len > pmtu) { + len = pmtu; + middle = HFI1_CAP_IS_KSET(SDMA_AHG); + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_LAST); + else { + qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + bth2 |= IB_BTH_REQ_ACK; + qp->s_cur++; + if (qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + case OP(RDMA_READ_RESPONSE_LAST): + /* + * qp->s_state is normally set to the opcode of the + * last packet constructed for new requests and therefore + * is never set to RDMA read response. + * RDMA_READ_RESPONSE_LAST is used by the ACK processing + * thread to indicate a RDMA write needs to be restarted from + * an earlier PSN without interfering with the sending thread. + * See restart_rc(). + */ + qp->s_len = restart_sge(&qp->s_sge, wqe, qp->s_psn, pmtu); + /* FALLTHROUGH */ + case OP(RDMA_WRITE_FIRST): + qp->s_state = OP(RDMA_WRITE_MIDDLE); + /* FALLTHROUGH */ + case OP(RDMA_WRITE_MIDDLE): + bth2 = mask_psn(qp->s_psn++); + if (cmp_psn(qp->s_psn, qp->s_next_psn) > 0) + qp->s_next_psn = qp->s_psn; + ss = &qp->s_sge; + len = qp->s_len; + if (len > pmtu) { + len = pmtu; + middle = HFI1_CAP_IS_KSET(SDMA_AHG); + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_LAST); + else { + qp->s_state = OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + } + bth2 |= IB_BTH_REQ_ACK; + qp->s_cur++; + if (qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + case OP(RDMA_READ_RESPONSE_MIDDLE): + /* + * qp->s_state is normally set to the opcode of the + * last packet constructed for new requests and therefore + * is never set to RDMA read response. + * RDMA_READ_RESPONSE_MIDDLE is used by the ACK processing + * thread to indicate a RDMA read needs to be restarted from + * an earlier PSN without interfering with the sending thread. + * See restart_rc(). + */ + len = (delta_psn(qp->s_psn, wqe->psn)) * pmtu; + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr + len); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(wqe->length - len); + qp->s_state = OP(RDMA_READ_REQUEST); + hwords += sizeof(ohdr->u.rc.reth) / sizeof(u32); + bth2 = mask_psn(qp->s_psn) | IB_BTH_REQ_ACK; + qp->s_psn = wqe->lpsn + 1; + ss = NULL; + len = 0; + qp->s_cur++; + if (qp->s_cur == qp->s_size) + qp->s_cur = 0; + break; + } + qp->s_sending_hpsn = bth2; + delta = delta_psn(bth2, wqe->psn); + if (delta && delta % HFI1_PSN_CREDIT == 0) + bth2 |= IB_BTH_REQ_ACK; + if (qp->s_flags & HFI1_S_SEND_ONE) { + qp->s_flags &= ~HFI1_S_SEND_ONE; + qp->s_flags |= HFI1_S_WAIT_ACK; + bth2 |= IB_BTH_REQ_ACK; + } + qp->s_len -= len; + qp->s_hdrwords = hwords; + qp->s_cur_sge = ss; + qp->s_cur_size = len; + hfi1_make_ruc_header( + qp, + ohdr, + bth0 | (qp->s_state << 24), + bth2, + middle); +done: + ret = 1; + goto unlock; + +bail: + qp->s_flags &= ~HFI1_S_BUSY; +unlock: + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; +} + +/** + * hfi1_send_rc_ack - Construct an ACK packet and send it + * @qp: a pointer to the QP + * + * This is called from hfi1_rc_rcv() and handle_receive_interrupt(). + * Note that RDMA reads and atomics are handled in the + * send side QP state and tasklet. + */ +void hfi1_send_rc_ack(struct hfi1_ctxtdata *rcd, struct hfi1_qp *qp, + int is_fecn) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u64 pbc, pbc_flags = 0; + u16 lrh0; + u16 sc5; + u32 bth0; + u32 hwords; + u32 vl, plen; + struct send_context *sc; + struct pio_buf *pbuf; + struct hfi1_ib_header hdr; + struct hfi1_other_headers *ohdr; + + /* Don't send ACK or NAK if a RDMA read or atomic is pending. */ + if (qp->s_flags & HFI1_S_RESP_PENDING) + goto queue_ack; + + /* Ensure s_rdma_ack_cnt changes are committed */ + smp_read_barrier_depends(); + if (qp->s_rdma_ack_cnt) + goto queue_ack; + + /* Construct the header */ + /* header size in 32-bit words LRH+BTH+AETH = (8+12+4)/4 */ + hwords = 6; + if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { + hwords += hfi1_make_grh(ibp, &hdr.u.l.grh, + &qp->remote_ah_attr.grh, hwords, 0); + ohdr = &hdr.u.l.oth; + lrh0 = HFI1_LRH_GRH; + } else { + ohdr = &hdr.u.oth; + lrh0 = HFI1_LRH_BTH; + } + /* read pkey_index w/o lock (its atomic) */ + bth0 = hfi1_get_pkey(ibp, qp->s_pkey_index) | (OP(ACKNOWLEDGE) << 24); + if (qp->s_mig_state == IB_MIG_MIGRATED) + bth0 |= IB_BTH_MIG_REQ; + if (qp->r_nak_state) + ohdr->u.aeth = cpu_to_be32((qp->r_msn & HFI1_MSN_MASK) | + (qp->r_nak_state << + HFI1_AETH_CREDIT_SHIFT)); + else + ohdr->u.aeth = hfi1_compute_aeth(qp); + sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + /* set PBC_DC_INFO bit (aka SC[4]) in pbc_flags */ + pbc_flags |= ((!!(sc5 & 0x10)) << PBC_DC_INFO_SHIFT); + lrh0 |= (sc5 & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4; + hdr.lrh[0] = cpu_to_be16(lrh0); + hdr.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); + hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC); + hdr.lrh[3] = cpu_to_be16(ppd->lid | qp->remote_ah_attr.src_path_bits); + ohdr->bth[0] = cpu_to_be32(bth0); + ohdr->bth[1] = cpu_to_be32(qp->remote_qpn); + ohdr->bth[1] |= cpu_to_be32((!!is_fecn) << HFI1_BECN_SHIFT); + ohdr->bth[2] = cpu_to_be32(mask_psn(qp->r_ack_psn)); + + /* Don't try to send ACKs if the link isn't ACTIVE */ + if (driver_lstate(ppd) != IB_PORT_ACTIVE) + return; + + sc = rcd->sc; + plen = 2 /* PBC */ + hwords; + vl = sc_to_vlt(ppd->dd, sc5); + pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen); + + pbuf = sc_buffer_alloc(sc, plen, NULL, NULL); + if (!pbuf) { + /* + * We have no room to send at the moment. Pass + * responsibility for sending the ACK to the send tasklet + * so that when enough buffer space becomes available, + * the ACK is sent ahead of other outgoing packets. + */ + goto queue_ack; + } + + trace_output_ibhdr(dd_from_ibdev(qp->ibqp.device), &hdr); + + /* write the pbc and data */ + ppd->dd->pio_inline_send(ppd->dd, pbuf, pbc, &hdr, hwords); + + return; + +queue_ack: + this_cpu_inc(*ibp->rc_qacks); + spin_lock(&qp->s_lock); + qp->s_flags |= HFI1_S_ACK_PENDING | HFI1_S_RESP_PENDING; + qp->s_nak_state = qp->r_nak_state; + qp->s_ack_psn = qp->r_ack_psn; + if (is_fecn) + qp->s_flags |= HFI1_S_ECN; + + /* Schedule the send tasklet. */ + hfi1_schedule_send(qp); + spin_unlock(&qp->s_lock); +} + +/** + * reset_psn - reset the QP state to send starting from PSN + * @qp: the QP + * @psn: the packet sequence number to restart at + * + * This is called from hfi1_rc_rcv() to process an incoming RC ACK + * for the given QP. + * Called at interrupt level with the QP s_lock held. + */ +static void reset_psn(struct hfi1_qp *qp, u32 psn) +{ + u32 n = qp->s_acked; + struct hfi1_swqe *wqe = get_swqe_ptr(qp, n); + u32 opcode; + + qp->s_cur = n; + + /* + * If we are starting the request from the beginning, + * let the normal send code handle initialization. + */ + if (cmp_psn(psn, wqe->psn) <= 0) { + qp->s_state = OP(SEND_LAST); + goto done; + } + + /* Find the work request opcode corresponding to the given PSN. */ + opcode = wqe->wr.opcode; + for (;;) { + int diff; + + if (++n == qp->s_size) + n = 0; + if (n == qp->s_tail) + break; + wqe = get_swqe_ptr(qp, n); + diff = cmp_psn(psn, wqe->psn); + if (diff < 0) + break; + qp->s_cur = n; + /* + * If we are starting the request from the beginning, + * let the normal send code handle initialization. + */ + if (diff == 0) { + qp->s_state = OP(SEND_LAST); + goto done; + } + opcode = wqe->wr.opcode; + } + + /* + * Set the state to restart in the middle of a request. + * Don't change the s_sge, s_cur_sge, or s_cur_size. + * See hfi1_make_rc_req(). + */ + switch (opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + qp->s_state = OP(RDMA_READ_RESPONSE_FIRST); + break; + + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + qp->s_state = OP(RDMA_READ_RESPONSE_LAST); + break; + + case IB_WR_RDMA_READ: + qp->s_state = OP(RDMA_READ_RESPONSE_MIDDLE); + break; + + default: + /* + * This case shouldn't happen since its only + * one PSN per req. + */ + qp->s_state = OP(SEND_LAST); + } +done: + qp->s_psn = psn; + /* + * Set HFI1_S_WAIT_PSN as rc_complete() may start the timer + * asynchronously before the send tasklet can get scheduled. + * Doing it in hfi1_make_rc_req() is too late. + */ + if ((cmp_psn(qp->s_psn, qp->s_sending_hpsn) <= 0) && + (cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) <= 0)) + qp->s_flags |= HFI1_S_WAIT_PSN; + qp->s_flags &= ~HFI1_S_AHG_VALID; +} + +/* + * Back up requester to resend the last un-ACKed request. + * The QP r_lock and s_lock should be held and interrupts disabled. + */ +static void restart_rc(struct hfi1_qp *qp, u32 psn, int wait) +{ + struct hfi1_swqe *wqe = get_swqe_ptr(qp, qp->s_acked); + struct hfi1_ibport *ibp; + + if (qp->s_retry == 0) { + if (qp->s_mig_state == IB_MIG_ARMED) { + hfi1_migrate_qp(qp); + qp->s_retry = qp->s_retry_cnt; + } else if (qp->s_last == qp->s_acked) { + hfi1_send_complete(qp, wqe, IB_WC_RETRY_EXC_ERR); + hfi1_error_qp(qp, IB_WC_WR_FLUSH_ERR); + return; + } else /* need to handle delayed completion */ + return; + } else + qp->s_retry--; + + ibp = to_iport(qp->ibqp.device, qp->port_num); + if (wqe->wr.opcode == IB_WR_RDMA_READ) + ibp->n_rc_resends++; + else + ibp->n_rc_resends += delta_psn(qp->s_psn, psn); + + qp->s_flags &= ~(HFI1_S_WAIT_FENCE | HFI1_S_WAIT_RDMAR | + HFI1_S_WAIT_SSN_CREDIT | HFI1_S_WAIT_PSN | + HFI1_S_WAIT_ACK); + if (wait) + qp->s_flags |= HFI1_S_SEND_ONE; + reset_psn(qp, psn); +} + +/* + * This is called from s_timer for missing responses. + */ +static void rc_timeout(unsigned long arg) +{ + struct hfi1_qp *qp = (struct hfi1_qp *)arg; + struct hfi1_ibport *ibp; + unsigned long flags; + + spin_lock_irqsave(&qp->r_lock, flags); + spin_lock(&qp->s_lock); + if (qp->s_flags & HFI1_S_TIMER) { + ibp = to_iport(qp->ibqp.device, qp->port_num); + ibp->n_rc_timeouts++; + qp->s_flags &= ~HFI1_S_TIMER; + del_timer(&qp->s_timer); + restart_rc(qp, qp->s_last_psn + 1, 1); + hfi1_schedule_send(qp); + } + spin_unlock(&qp->s_lock); + spin_unlock_irqrestore(&qp->r_lock, flags); +} + +/* + * This is called from s_timer for RNR timeouts. + */ +void hfi1_rc_rnr_retry(unsigned long arg) +{ + struct hfi1_qp *qp = (struct hfi1_qp *)arg; + unsigned long flags; + + spin_lock_irqsave(&qp->s_lock, flags); + if (qp->s_flags & HFI1_S_WAIT_RNR) { + qp->s_flags &= ~HFI1_S_WAIT_RNR; + del_timer(&qp->s_timer); + hfi1_schedule_send(qp); + } + spin_unlock_irqrestore(&qp->s_lock, flags); +} + +/* + * Set qp->s_sending_psn to the next PSN after the given one. + * This would be psn+1 except when RDMA reads are present. + */ +static void reset_sending_psn(struct hfi1_qp *qp, u32 psn) +{ + struct hfi1_swqe *wqe; + u32 n = qp->s_last; + + /* Find the work request corresponding to the given PSN. */ + for (;;) { + wqe = get_swqe_ptr(qp, n); + if (cmp_psn(psn, wqe->lpsn) <= 0) { + if (wqe->wr.opcode == IB_WR_RDMA_READ) + qp->s_sending_psn = wqe->lpsn + 1; + else + qp->s_sending_psn = psn + 1; + break; + } + if (++n == qp->s_size) + n = 0; + if (n == qp->s_tail) + break; + } +} + +/* + * This should be called with the QP s_lock held and interrupts disabled. + */ +void hfi1_rc_send_complete(struct hfi1_qp *qp, struct hfi1_ib_header *hdr) +{ + struct hfi1_other_headers *ohdr; + struct hfi1_swqe *wqe; + struct ib_wc wc; + unsigned i; + u32 opcode; + u32 psn; + + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_OR_FLUSH_SEND)) + return; + + /* Find out where the BTH is */ + if ((be16_to_cpu(hdr->lrh[0]) & 3) == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else + ohdr = &hdr->u.l.oth; + + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) && + opcode <= OP(ATOMIC_ACKNOWLEDGE)) { + WARN_ON(!qp->s_rdma_ack_cnt); + qp->s_rdma_ack_cnt--; + return; + } + + psn = be32_to_cpu(ohdr->bth[2]); + reset_sending_psn(qp, psn); + + /* + * Start timer after a packet requesting an ACK has been sent and + * there are still requests that haven't been acked. + */ + if ((psn & IB_BTH_REQ_ACK) && qp->s_acked != qp->s_tail && + !(qp->s_flags & + (HFI1_S_TIMER | HFI1_S_WAIT_RNR | HFI1_S_WAIT_PSN)) && + (ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK)) + start_timer(qp); + + while (qp->s_last != qp->s_acked) { + wqe = get_swqe_ptr(qp, qp->s_last); + if (cmp_psn(wqe->lpsn, qp->s_sending_psn) >= 0 && + cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) <= 0) + break; + for (i = 0; i < wqe->wr.num_sge; i++) { + struct hfi1_sge *sge = &wqe->sg_list[i]; + + hfi1_put_mr(sge->mr); + } + /* Post a send completion queue entry if requested. */ + if (!(qp->s_flags & HFI1_S_SIGNAL_REQ_WR) || + (wqe->wr.send_flags & IB_SEND_SIGNALED)) { + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wqe->wr.wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = ib_hfi1_wc_opcode[wqe->wr.opcode]; + wc.byte_len = wqe->length; + wc.qp = &qp->ibqp; + hfi1_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); + } + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + } + /* + * If we were waiting for sends to complete before re-sending, + * and they are now complete, restart sending. + */ + trace_hfi1_rc_sendcomplete(qp, psn); + if (qp->s_flags & HFI1_S_WAIT_PSN && + cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) { + qp->s_flags &= ~HFI1_S_WAIT_PSN; + qp->s_sending_psn = qp->s_psn; + qp->s_sending_hpsn = qp->s_psn - 1; + hfi1_schedule_send(qp); + } +} + +static inline void update_last_psn(struct hfi1_qp *qp, u32 psn) +{ + qp->s_last_psn = psn; +} + +/* + * Generate a SWQE completion. + * This is similar to hfi1_send_complete but has to check to be sure + * that the SGEs are not being referenced if the SWQE is being resent. + */ +static struct hfi1_swqe *do_rc_completion(struct hfi1_qp *qp, + struct hfi1_swqe *wqe, + struct hfi1_ibport *ibp) +{ + struct ib_wc wc; + unsigned i; + + /* + * Don't decrement refcount and don't generate a + * completion if the SWQE is being resent until the send + * is finished. + */ + if (cmp_psn(wqe->lpsn, qp->s_sending_psn) < 0 || + cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) { + for (i = 0; i < wqe->wr.num_sge; i++) { + struct hfi1_sge *sge = &wqe->sg_list[i]; + + hfi1_put_mr(sge->mr); + } + /* Post a send completion queue entry if requested. */ + if (!(qp->s_flags & HFI1_S_SIGNAL_REQ_WR) || + (wqe->wr.send_flags & IB_SEND_SIGNALED)) { + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wqe->wr.wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = ib_hfi1_wc_opcode[wqe->wr.opcode]; + wc.byte_len = wqe->length; + wc.qp = &qp->ibqp; + hfi1_cq_enter(to_icq(qp->ibqp.send_cq), &wc, 0); + } + if (++qp->s_last >= qp->s_size) + qp->s_last = 0; + } else { + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + this_cpu_inc(*ibp->rc_delayed_comp); + /* + * If send progress not running attempt to progress + * SDMA queue. + */ + if (ppd->dd->flags & HFI1_HAS_SEND_DMA) { + struct sdma_engine *engine; + u8 sc5; + + /* For now use sc to find engine */ + sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + engine = qp_to_sdma_engine(qp, sc5); + sdma_engine_progress_schedule(engine); + } + } + + qp->s_retry = qp->s_retry_cnt; + update_last_psn(qp, wqe->lpsn); + + /* + * If we are completing a request which is in the process of + * being resent, we can stop re-sending it since we know the + * responder has already seen it. + */ + if (qp->s_acked == qp->s_cur) { + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + qp->s_acked = qp->s_cur; + wqe = get_swqe_ptr(qp, qp->s_cur); + if (qp->s_acked != qp->s_tail) { + qp->s_state = OP(SEND_LAST); + qp->s_psn = wqe->psn; + } + } else { + if (++qp->s_acked >= qp->s_size) + qp->s_acked = 0; + if (qp->state == IB_QPS_SQD && qp->s_acked == qp->s_cur) + qp->s_draining = 0; + wqe = get_swqe_ptr(qp, qp->s_acked); + } + return wqe; +} + +/** + * do_rc_ack - process an incoming RC ACK + * @qp: the QP the ACK came in on + * @psn: the packet sequence number of the ACK + * @opcode: the opcode of the request that resulted in the ACK + * + * This is called from rc_rcv_resp() to process an incoming RC ACK + * for the given QP. + * Called at interrupt level with the QP s_lock held. + * Returns 1 if OK, 0 if current operation should be aborted (NAK). + */ +static int do_rc_ack(struct hfi1_qp *qp, u32 aeth, u32 psn, int opcode, + u64 val, struct hfi1_ctxtdata *rcd) +{ + struct hfi1_ibport *ibp; + enum ib_wc_status status; + struct hfi1_swqe *wqe; + int ret = 0; + u32 ack_psn; + int diff; + + /* Remove QP from retry timer */ + if (qp->s_flags & (HFI1_S_TIMER | HFI1_S_WAIT_RNR)) { + qp->s_flags &= ~(HFI1_S_TIMER | HFI1_S_WAIT_RNR); + del_timer(&qp->s_timer); + } + + /* + * Note that NAKs implicitly ACK outstanding SEND and RDMA write + * requests and implicitly NAK RDMA read and atomic requests issued + * before the NAK'ed request. The MSN won't include the NAK'ed + * request but will include an ACK'ed request(s). + */ + ack_psn = psn; + if (aeth >> 29) + ack_psn--; + wqe = get_swqe_ptr(qp, qp->s_acked); + ibp = to_iport(qp->ibqp.device, qp->port_num); + + /* + * The MSN might be for a later WQE than the PSN indicates so + * only complete WQEs that the PSN finishes. + */ + while ((diff = delta_psn(ack_psn, wqe->lpsn)) >= 0) { + /* + * RDMA_READ_RESPONSE_ONLY is a special case since + * we want to generate completion events for everything + * before the RDMA read, copy the data, then generate + * the completion for the read. + */ + if (wqe->wr.opcode == IB_WR_RDMA_READ && + opcode == OP(RDMA_READ_RESPONSE_ONLY) && + diff == 0) { + ret = 1; + goto bail; + } + /* + * If this request is a RDMA read or atomic, and the ACK is + * for a later operation, this ACK NAKs the RDMA read or + * atomic. In other words, only a RDMA_READ_LAST or ONLY + * can ACK a RDMA read and likewise for atomic ops. Note + * that the NAK case can only happen if relaxed ordering is + * used and requests are sent after an RDMA read or atomic + * is sent but before the response is received. + */ + if ((wqe->wr.opcode == IB_WR_RDMA_READ && + (opcode != OP(RDMA_READ_RESPONSE_LAST) || diff != 0)) || + ((wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) && + (opcode != OP(ATOMIC_ACKNOWLEDGE) || diff != 0))) { + /* Retry this request. */ + if (!(qp->r_flags & HFI1_R_RDMAR_SEQ)) { + qp->r_flags |= HFI1_R_RDMAR_SEQ; + restart_rc(qp, qp->s_last_psn + 1, 0); + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_SEND; + atomic_inc(&qp->refcount); + list_add_tail(&qp->rspwait, + &rcd->qp_wait_list); + } + } + /* + * No need to process the ACK/NAK since we are + * restarting an earlier request. + */ + goto bail; + } + if (wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) { + u64 *vaddr = wqe->sg_list[0].vaddr; + *vaddr = val; + } + if (qp->s_num_rd_atomic && + (wqe->wr.opcode == IB_WR_RDMA_READ || + wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD)) { + qp->s_num_rd_atomic--; + /* Restart sending task if fence is complete */ + if ((qp->s_flags & HFI1_S_WAIT_FENCE) && + !qp->s_num_rd_atomic) { + qp->s_flags &= ~(HFI1_S_WAIT_FENCE | + HFI1_S_WAIT_ACK); + hfi1_schedule_send(qp); + } else if (qp->s_flags & HFI1_S_WAIT_RDMAR) { + qp->s_flags &= ~(HFI1_S_WAIT_RDMAR | + HFI1_S_WAIT_ACK); + hfi1_schedule_send(qp); + } + } + wqe = do_rc_completion(qp, wqe, ibp); + if (qp->s_acked == qp->s_tail) + break; + } + + switch (aeth >> 29) { + case 0: /* ACK */ + this_cpu_inc(*ibp->rc_acks); + if (qp->s_acked != qp->s_tail) { + /* + * We are expecting more ACKs so + * reset the re-transmit timer. + */ + start_timer(qp); + /* + * We can stop re-sending the earlier packets and + * continue with the next packet the receiver wants. + */ + if (cmp_psn(qp->s_psn, psn) <= 0) + reset_psn(qp, psn + 1); + } else if (cmp_psn(qp->s_psn, psn) <= 0) { + qp->s_state = OP(SEND_LAST); + qp->s_psn = psn + 1; + } + if (qp->s_flags & HFI1_S_WAIT_ACK) { + qp->s_flags &= ~HFI1_S_WAIT_ACK; + hfi1_schedule_send(qp); + } + hfi1_get_credit(qp, aeth); + qp->s_rnr_retry = qp->s_rnr_retry_cnt; + qp->s_retry = qp->s_retry_cnt; + update_last_psn(qp, psn); + ret = 1; + goto bail; + + case 1: /* RNR NAK */ + ibp->n_rnr_naks++; + if (qp->s_acked == qp->s_tail) + goto bail; + if (qp->s_flags & HFI1_S_WAIT_RNR) + goto bail; + if (qp->s_rnr_retry == 0) { + status = IB_WC_RNR_RETRY_EXC_ERR; + goto class_b; + } + if (qp->s_rnr_retry_cnt < 7) + qp->s_rnr_retry--; + + /* The last valid PSN is the previous PSN. */ + update_last_psn(qp, psn - 1); + + ibp->n_rc_resends += delta_psn(qp->s_psn, psn); + + reset_psn(qp, psn); + + qp->s_flags &= ~(HFI1_S_WAIT_SSN_CREDIT | HFI1_S_WAIT_ACK); + qp->s_flags |= HFI1_S_WAIT_RNR; + qp->s_timer.function = hfi1_rc_rnr_retry; + qp->s_timer.expires = jiffies + usecs_to_jiffies( + ib_hfi1_rnr_table[(aeth >> HFI1_AETH_CREDIT_SHIFT) & + HFI1_AETH_CREDIT_MASK]); + add_timer(&qp->s_timer); + goto bail; + + case 3: /* NAK */ + if (qp->s_acked == qp->s_tail) + goto bail; + /* The last valid PSN is the previous PSN. */ + update_last_psn(qp, psn - 1); + switch ((aeth >> HFI1_AETH_CREDIT_SHIFT) & + HFI1_AETH_CREDIT_MASK) { + case 0: /* PSN sequence error */ + ibp->n_seq_naks++; + /* + * Back up to the responder's expected PSN. + * Note that we might get a NAK in the middle of an + * RDMA READ response which terminates the RDMA + * READ. + */ + restart_rc(qp, psn, 0); + hfi1_schedule_send(qp); + break; + + case 1: /* Invalid Request */ + status = IB_WC_REM_INV_REQ_ERR; + ibp->n_other_naks++; + goto class_b; + + case 2: /* Remote Access Error */ + status = IB_WC_REM_ACCESS_ERR; + ibp->n_other_naks++; + goto class_b; + + case 3: /* Remote Operation Error */ + status = IB_WC_REM_OP_ERR; + ibp->n_other_naks++; +class_b: + if (qp->s_last == qp->s_acked) { + hfi1_send_complete(qp, wqe, status); + hfi1_error_qp(qp, IB_WC_WR_FLUSH_ERR); + } + break; + + default: + /* Ignore other reserved NAK error codes */ + goto reserved; + } + qp->s_retry = qp->s_retry_cnt; + qp->s_rnr_retry = qp->s_rnr_retry_cnt; + goto bail; + + default: /* 2: reserved */ +reserved: + /* Ignore reserved NAK codes. */ + goto bail; + } + +bail: + return ret; +} + +/* + * We have seen an out of sequence RDMA read middle or last packet. + * This ACKs SENDs and RDMA writes up to the first RDMA read or atomic SWQE. + */ +static void rdma_seq_err(struct hfi1_qp *qp, struct hfi1_ibport *ibp, u32 psn, + struct hfi1_ctxtdata *rcd) +{ + struct hfi1_swqe *wqe; + + /* Remove QP from retry timer */ + if (qp->s_flags & (HFI1_S_TIMER | HFI1_S_WAIT_RNR)) { + qp->s_flags &= ~(HFI1_S_TIMER | HFI1_S_WAIT_RNR); + del_timer(&qp->s_timer); + } + + wqe = get_swqe_ptr(qp, qp->s_acked); + + while (cmp_psn(psn, wqe->lpsn) > 0) { + if (wqe->wr.opcode == IB_WR_RDMA_READ || + wqe->wr.opcode == IB_WR_ATOMIC_CMP_AND_SWP || + wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) + break; + wqe = do_rc_completion(qp, wqe, ibp); + } + + ibp->n_rdma_seq++; + qp->r_flags |= HFI1_R_RDMAR_SEQ; + restart_rc(qp, qp->s_last_psn + 1, 0); + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_SEND; + atomic_inc(&qp->refcount); + list_add_tail(&qp->rspwait, &rcd->qp_wait_list); + } +} + +/** + * rc_rcv_resp - process an incoming RC response packet + * @ibp: the port this packet came in on + * @ohdr: the other headers for this packet + * @data: the packet data + * @tlen: the packet length + * @qp: the QP for this packet + * @opcode: the opcode for this packet + * @psn: the packet sequence number for this packet + * @hdrsize: the header length + * @pmtu: the path MTU + * + * This is called from hfi1_rc_rcv() to process an incoming RC response + * packet for the given QP. + * Called at interrupt level. + */ +static void rc_rcv_resp(struct hfi1_ibport *ibp, + struct hfi1_other_headers *ohdr, + void *data, u32 tlen, struct hfi1_qp *qp, + u32 opcode, u32 psn, u32 hdrsize, u32 pmtu, + struct hfi1_ctxtdata *rcd) +{ + struct hfi1_swqe *wqe; + enum ib_wc_status status; + unsigned long flags; + int diff; + u32 pad; + u32 aeth; + u64 val; + + spin_lock_irqsave(&qp->s_lock, flags); + + /* Ignore invalid responses. */ + if (cmp_psn(psn, qp->s_next_psn) >= 0) + goto ack_done; + + /* Ignore duplicate responses. */ + diff = cmp_psn(psn, qp->s_last_psn); + if (unlikely(diff <= 0)) { + /* Update credits for "ghost" ACKs */ + if (diff == 0 && opcode == OP(ACKNOWLEDGE)) { + aeth = be32_to_cpu(ohdr->u.aeth); + if ((aeth >> 29) == 0) + hfi1_get_credit(qp, aeth); + } + goto ack_done; + } + + /* + * Skip everything other than the PSN we expect, if we are waiting + * for a reply to a restarted RDMA read or atomic op. + */ + if (qp->r_flags & HFI1_R_RDMAR_SEQ) { + if (cmp_psn(psn, qp->s_last_psn + 1) != 0) + goto ack_done; + qp->r_flags &= ~HFI1_R_RDMAR_SEQ; + } + + if (unlikely(qp->s_acked == qp->s_tail)) + goto ack_done; + wqe = get_swqe_ptr(qp, qp->s_acked); + status = IB_WC_SUCCESS; + + switch (opcode) { + case OP(ACKNOWLEDGE): + case OP(ATOMIC_ACKNOWLEDGE): + case OP(RDMA_READ_RESPONSE_FIRST): + aeth = be32_to_cpu(ohdr->u.aeth); + if (opcode == OP(ATOMIC_ACKNOWLEDGE)) { + __be32 *p = ohdr->u.at.atomic_ack_eth; + + val = ((u64) be32_to_cpu(p[0]) << 32) | + be32_to_cpu(p[1]); + } else + val = 0; + if (!do_rc_ack(qp, aeth, psn, opcode, val, rcd) || + opcode != OP(RDMA_READ_RESPONSE_FIRST)) + goto ack_done; + wqe = get_swqe_ptr(qp, qp->s_acked); + if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) + goto ack_op_err; + /* + * If this is a response to a resent RDMA read, we + * have to be careful to copy the data to the right + * location. + */ + qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge, + wqe, psn, pmtu); + goto read_middle; + + case OP(RDMA_READ_RESPONSE_MIDDLE): + /* no AETH, no ACK */ + if (unlikely(cmp_psn(psn, qp->s_last_psn + 1))) + goto ack_seq_err; + if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) + goto ack_op_err; +read_middle: + if (unlikely(tlen != (hdrsize + pmtu + 4))) + goto ack_len_err; + if (unlikely(pmtu >= qp->s_rdma_read_len)) + goto ack_len_err; + + /* + * We got a response so update the timeout. + * 4.096 usec. * (1 << qp->timeout) + */ + qp->s_flags |= HFI1_S_TIMER; + mod_timer(&qp->s_timer, jiffies + qp->timeout_jiffies); + if (qp->s_flags & HFI1_S_WAIT_ACK) { + qp->s_flags &= ~HFI1_S_WAIT_ACK; + hfi1_schedule_send(qp); + } + + if (opcode == OP(RDMA_READ_RESPONSE_MIDDLE)) + qp->s_retry = qp->s_retry_cnt; + + /* + * Update the RDMA receive state but do the copy w/o + * holding the locks and blocking interrupts. + */ + qp->s_rdma_read_len -= pmtu; + update_last_psn(qp, psn); + spin_unlock_irqrestore(&qp->s_lock, flags); + hfi1_copy_sge(&qp->s_rdma_read_sge, data, pmtu, 0); + goto bail; + + case OP(RDMA_READ_RESPONSE_ONLY): + aeth = be32_to_cpu(ohdr->u.aeth); + if (!do_rc_ack(qp, aeth, psn, opcode, 0, rcd)) + goto ack_done; + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* + * Check that the data size is >= 0 && <= pmtu. + * Remember to account for ICRC (4). + */ + if (unlikely(tlen < (hdrsize + pad + 4))) + goto ack_len_err; + /* + * If this is a response to a resent RDMA read, we + * have to be careful to copy the data to the right + * location. + */ + wqe = get_swqe_ptr(qp, qp->s_acked); + qp->s_rdma_read_len = restart_sge(&qp->s_rdma_read_sge, + wqe, psn, pmtu); + goto read_last; + + case OP(RDMA_READ_RESPONSE_LAST): + /* ACKs READ req. */ + if (unlikely(cmp_psn(psn, qp->s_last_psn + 1))) + goto ack_seq_err; + if (unlikely(wqe->wr.opcode != IB_WR_RDMA_READ)) + goto ack_op_err; + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* + * Check that the data size is >= 1 && <= pmtu. + * Remember to account for ICRC (4). + */ + if (unlikely(tlen <= (hdrsize + pad + 4))) + goto ack_len_err; +read_last: + tlen -= hdrsize + pad + 4; + if (unlikely(tlen != qp->s_rdma_read_len)) + goto ack_len_err; + aeth = be32_to_cpu(ohdr->u.aeth); + hfi1_copy_sge(&qp->s_rdma_read_sge, data, tlen, 0); + WARN_ON(qp->s_rdma_read_sge.num_sge); + (void) do_rc_ack(qp, aeth, psn, + OP(RDMA_READ_RESPONSE_LAST), 0, rcd); + goto ack_done; + } + +ack_op_err: + status = IB_WC_LOC_QP_OP_ERR; + goto ack_err; + +ack_seq_err: + rdma_seq_err(qp, ibp, psn, rcd); + goto ack_done; + +ack_len_err: + status = IB_WC_LOC_LEN_ERR; +ack_err: + if (qp->s_last == qp->s_acked) { + hfi1_send_complete(qp, wqe, status); + hfi1_error_qp(qp, IB_WC_WR_FLUSH_ERR); + } +ack_done: + spin_unlock_irqrestore(&qp->s_lock, flags); +bail: + return; +} + +/** + * rc_rcv_error - process an incoming duplicate or error RC packet + * @ohdr: the other headers for this packet + * @data: the packet data + * @qp: the QP for this packet + * @opcode: the opcode for this packet + * @psn: the packet sequence number for this packet + * @diff: the difference between the PSN and the expected PSN + * + * This is called from hfi1_rc_rcv() to process an unexpected + * incoming RC packet for the given QP. + * Called at interrupt level. + * Return 1 if no more processing is needed; otherwise return 0 to + * schedule a response to be sent. + */ +static noinline int rc_rcv_error(struct hfi1_other_headers *ohdr, void *data, + struct hfi1_qp *qp, u32 opcode, u32 psn, int diff, + struct hfi1_ctxtdata *rcd) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_ack_entry *e; + unsigned long flags; + u8 i, prev; + int old_req; + + if (diff > 0) { + /* + * Packet sequence error. + * A NAK will ACK earlier sends and RDMA writes. + * Don't queue the NAK if we already sent one. + */ + if (!qp->r_nak_state) { + ibp->n_rc_seqnak++; + qp->r_nak_state = IB_NAK_PSN_ERROR; + /* Use the expected PSN. */ + qp->r_ack_psn = qp->r_psn; + /* + * Wait to send the sequence NAK until all packets + * in the receive queue have been processed. + * Otherwise, we end up propagating congestion. + */ + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_NAK; + atomic_inc(&qp->refcount); + list_add_tail(&qp->rspwait, &rcd->qp_wait_list); + } + } + goto done; + } + + /* + * Handle a duplicate request. Don't re-execute SEND, RDMA + * write or atomic op. Don't NAK errors, just silently drop + * the duplicate request. Note that r_sge, r_len, and + * r_rcv_len may be in use so don't modify them. + * + * We are supposed to ACK the earliest duplicate PSN but we + * can coalesce an outstanding duplicate ACK. We have to + * send the earliest so that RDMA reads can be restarted at + * the requester's expected PSN. + * + * First, find where this duplicate PSN falls within the + * ACKs previously sent. + * old_req is true if there is an older response that is scheduled + * to be sent before sending this one. + */ + e = NULL; + old_req = 1; + ibp->n_rc_dupreq++; + + spin_lock_irqsave(&qp->s_lock, flags); + + for (i = qp->r_head_ack_queue; ; i = prev) { + if (i == qp->s_tail_ack_queue) + old_req = 0; + if (i) + prev = i - 1; + else + prev = HFI1_MAX_RDMA_ATOMIC; + if (prev == qp->r_head_ack_queue) { + e = NULL; + break; + } + e = &qp->s_ack_queue[prev]; + if (!e->opcode) { + e = NULL; + break; + } + if (cmp_psn(psn, e->psn) >= 0) { + if (prev == qp->s_tail_ack_queue && + cmp_psn(psn, e->lpsn) <= 0) + old_req = 0; + break; + } + } + switch (opcode) { + case OP(RDMA_READ_REQUEST): { + struct ib_reth *reth; + u32 offset; + u32 len; + + /* + * If we didn't find the RDMA read request in the ack queue, + * we can ignore this request. + */ + if (!e || e->opcode != OP(RDMA_READ_REQUEST)) + goto unlock_done; + /* RETH comes after BTH */ + reth = &ohdr->u.rc.reth; + /* + * Address range must be a subset of the original + * request and start on pmtu boundaries. + * We reuse the old ack_queue slot since the requester + * should not back up and request an earlier PSN for the + * same request. + */ + offset = delta_psn(psn, e->psn) * qp->pmtu; + len = be32_to_cpu(reth->length); + if (unlikely(offset + len != e->rdma_sge.sge_length)) + goto unlock_done; + if (e->rdma_sge.mr) { + hfi1_put_mr(e->rdma_sge.mr); + e->rdma_sge.mr = NULL; + } + if (len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + ok = hfi1_rkey_ok(qp, &e->rdma_sge, len, vaddr, rkey, + IB_ACCESS_REMOTE_READ); + if (unlikely(!ok)) + goto unlock_done; + } else { + e->rdma_sge.vaddr = NULL; + e->rdma_sge.length = 0; + e->rdma_sge.sge_length = 0; + } + e->psn = psn; + if (old_req) + goto unlock_done; + qp->s_tail_ack_queue = prev; + break; + } + + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): { + /* + * If we didn't find the atomic request in the ack queue + * or the send tasklet is already backed up to send an + * earlier entry, we can ignore this request. + */ + if (!e || e->opcode != (u8) opcode || old_req) + goto unlock_done; + qp->s_tail_ack_queue = prev; + break; + } + + default: + /* + * Ignore this operation if it doesn't request an ACK + * or an earlier RDMA read or atomic is going to be resent. + */ + if (!(psn & IB_BTH_REQ_ACK) || old_req) + goto unlock_done; + /* + * Resend the most recent ACK if this request is + * after all the previous RDMA reads and atomics. + */ + if (i == qp->r_head_ack_queue) { + spin_unlock_irqrestore(&qp->s_lock, flags); + qp->r_nak_state = 0; + qp->r_ack_psn = qp->r_psn - 1; + goto send_ack; + } + + /* + * Resend the RDMA read or atomic op which + * ACKs this duplicate request. + */ + qp->s_tail_ack_queue = i; + break; + } + qp->s_ack_state = OP(ACKNOWLEDGE); + qp->s_flags |= HFI1_S_RESP_PENDING; + qp->r_nak_state = 0; + hfi1_schedule_send(qp); + +unlock_done: + spin_unlock_irqrestore(&qp->s_lock, flags); +done: + return 1; + +send_ack: + return 0; +} + +void hfi1_rc_error(struct hfi1_qp *qp, enum ib_wc_status err) +{ + unsigned long flags; + int lastwqe; + + spin_lock_irqsave(&qp->s_lock, flags); + lastwqe = hfi1_error_qp(qp, err); + spin_unlock_irqrestore(&qp->s_lock, flags); + + if (lastwqe) { + struct ib_event ev; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); + } +} + +static inline void update_ack_queue(struct hfi1_qp *qp, unsigned n) +{ + unsigned next; + + next = n + 1; + if (next > HFI1_MAX_RDMA_ATOMIC) + next = 0; + qp->s_tail_ack_queue = next; + qp->s_ack_state = OP(ACKNOWLEDGE); +} + +static void log_cca_event(struct hfi1_pportdata *ppd, u8 sl, u32 rlid, + u32 lqpn, u32 rqpn, u8 svc_type) +{ + struct opa_hfi1_cong_log_event_internal *cc_event; + + if (sl >= OPA_MAX_SLS) + return; + + spin_lock(&ppd->cc_log_lock); + + ppd->threshold_cong_event_map[sl/8] |= 1 << (sl % 8); + ppd->threshold_event_counter++; + + cc_event = &ppd->cc_events[ppd->cc_log_idx++]; + if (ppd->cc_log_idx == OPA_CONG_LOG_ELEMS) + ppd->cc_log_idx = 0; + cc_event->lqpn = lqpn & HFI1_QPN_MASK; + cc_event->rqpn = rqpn & HFI1_QPN_MASK; + cc_event->sl = sl; + cc_event->svc_type = svc_type; + cc_event->rlid = rlid; + /* keep timestamp in units of 1.024 usec */ + cc_event->timestamp = ktime_to_ns(ktime_get()) / 1024; + + spin_unlock(&ppd->cc_log_lock); +} + +void process_becn(struct hfi1_pportdata *ppd, u8 sl, u16 rlid, u32 lqpn, + u32 rqpn, u8 svc_type) +{ + struct cca_timer *cca_timer; + u16 ccti, ccti_incr, ccti_timer, ccti_limit; + u8 trigger_threshold; + struct cc_state *cc_state; + + if (sl >= OPA_MAX_SLS) + return; + + cca_timer = &ppd->cca_timer[sl]; + + cc_state = get_cc_state(ppd); + + if (cc_state == NULL) + return; + + /* + * 1) increase CCTI (for this SL) + * 2) select IPG (i.e., call set_link_ipg()) + * 3) start timer + */ + ccti_limit = cc_state->cct.ccti_limit; + ccti_incr = cc_state->cong_setting.entries[sl].ccti_increase; + ccti_timer = cc_state->cong_setting.entries[sl].ccti_timer; + trigger_threshold = + cc_state->cong_setting.entries[sl].trigger_threshold; + + spin_lock(&ppd->cca_timer_lock); + + if (cca_timer->ccti < ccti_limit) { + if (cca_timer->ccti + ccti_incr <= ccti_limit) + cca_timer->ccti += ccti_incr; + else + cca_timer->ccti = ccti_limit; + set_link_ipg(ppd); + } + + spin_unlock(&ppd->cca_timer_lock); + + ccti = cca_timer->ccti; + + if (!hrtimer_active(&cca_timer->hrtimer)) { + /* ccti_timer is in units of 1.024 usec */ + unsigned long nsec = 1024 * ccti_timer; + + hrtimer_start(&cca_timer->hrtimer, ns_to_ktime(nsec), + HRTIMER_MODE_REL); + } + + if ((trigger_threshold != 0) && (ccti >= trigger_threshold)) + log_cca_event(ppd, sl, rlid, lqpn, rqpn, svc_type); +} + +/** + * hfi1_rc_rcv - process an incoming RC packet + * @rcd: the context pointer + * @hdr: the header of this packet + * @rcv_flags: flags relevant to rcv processing + * @data: the packet data + * @tlen: the packet length + * @qp: the QP for this packet + * + * This is called from qp_rcv() to process an incoming RC packet + * for the given QP. + * Called at interrupt level. + */ +void hfi1_rc_rcv(struct hfi1_packet *packet) +{ + struct hfi1_ctxtdata *rcd = packet->rcd; + struct hfi1_ib_header *hdr = packet->hdr; + u32 rcv_flags = packet->rcv_flags; + void *data = packet->ebuf; + u32 tlen = packet->tlen; + struct hfi1_qp *qp = packet->qp; + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct hfi1_other_headers *ohdr = packet->ohdr; + u32 bth0, opcode; + u32 hdrsize = packet->hlen; + u32 psn; + u32 pad; + struct ib_wc wc; + u32 pmtu = qp->pmtu; + int diff; + struct ib_reth *reth; + unsigned long flags; + u32 bth1; + int ret, is_fecn = 0; + + bth0 = be32_to_cpu(ohdr->bth[0]); + if (hfi1_ruc_check_hdr(ibp, hdr, rcv_flags & HFI1_HAS_GRH, qp, bth0)) + return; + + bth1 = be32_to_cpu(ohdr->bth[1]); + if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) { + if (bth1 & HFI1_BECN_SMASK) { + u16 rlid = qp->remote_ah_attr.dlid; + u32 lqpn, rqpn; + + lqpn = qp->ibqp.qp_num; + rqpn = qp->remote_qpn; + process_becn( + ppd, + qp->remote_ah_attr.sl, + rlid, lqpn, rqpn, + IB_CC_SVCTYPE_RC); + } + is_fecn = bth1 & HFI1_FECN_SMASK; + } + + psn = be32_to_cpu(ohdr->bth[2]); + opcode = bth0 >> 24; + + /* + * Process responses (ACKs) before anything else. Note that the + * packet sequence number will be for something in the send work + * queue rather than the expected receive packet sequence number. + * In other words, this QP is the requester. + */ + if (opcode >= OP(RDMA_READ_RESPONSE_FIRST) && + opcode <= OP(ATOMIC_ACKNOWLEDGE)) { + rc_rcv_resp(ibp, ohdr, data, tlen, qp, opcode, psn, + hdrsize, pmtu, rcd); + if (is_fecn) + goto send_ack; + return; + } + + /* Compute 24 bits worth of difference. */ + diff = delta_psn(psn, qp->r_psn); + if (unlikely(diff)) { + if (rc_rcv_error(ohdr, data, qp, opcode, psn, diff, rcd)) + return; + goto send_ack; + } + + /* Check for opcode sequence errors. */ + switch (qp->r_state) { + case OP(SEND_FIRST): + case OP(SEND_MIDDLE): + if (opcode == OP(SEND_MIDDLE) || + opcode == OP(SEND_LAST) || + opcode == OP(SEND_LAST_WITH_IMMEDIATE)) + break; + goto nack_inv; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_MIDDLE): + if (opcode == OP(RDMA_WRITE_MIDDLE) || + opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) + break; + goto nack_inv; + + default: + if (opcode == OP(SEND_MIDDLE) || + opcode == OP(SEND_LAST) || + opcode == OP(SEND_LAST_WITH_IMMEDIATE) || + opcode == OP(RDMA_WRITE_MIDDLE) || + opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) + goto nack_inv; + /* + * Note that it is up to the requester to not send a new + * RDMA read or atomic operation before receiving an ACK + * for the previous operation. + */ + break; + } + + if (qp->state == IB_QPS_RTR && !(qp->r_flags & HFI1_R_COMM_EST)) + qp_comm_est(qp); + + /* OK, process the packet. */ + switch (opcode) { + case OP(SEND_FIRST): + ret = hfi1_get_rwqe(qp, 0); + if (ret < 0) + goto nack_op_err; + if (!ret) + goto rnr_nak; + qp->r_rcv_len = 0; + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + case OP(RDMA_WRITE_MIDDLE): +send_middle: + /* Check for invalid length PMTU or posted rwqe len. */ + if (unlikely(tlen != (hdrsize + pmtu + 4))) + goto nack_inv; + qp->r_rcv_len += pmtu; + if (unlikely(qp->r_rcv_len > qp->r_len)) + goto nack_inv; + hfi1_copy_sge(&qp->r_sge, data, pmtu, 1); + break; + + case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): + /* consume RWQE */ + ret = hfi1_get_rwqe(qp, 1); + if (ret < 0) + goto nack_op_err; + if (!ret) + goto rnr_nak; + goto send_last_imm; + + case OP(SEND_ONLY): + case OP(SEND_ONLY_WITH_IMMEDIATE): + ret = hfi1_get_rwqe(qp, 0); + if (ret < 0) + goto nack_op_err; + if (!ret) + goto rnr_nak; + qp->r_rcv_len = 0; + if (opcode == OP(SEND_ONLY)) + goto no_immediate_data; + /* FALLTHROUGH for SEND_ONLY_WITH_IMMEDIATE */ + case OP(SEND_LAST_WITH_IMMEDIATE): +send_last_imm: + wc.ex.imm_data = ohdr->u.imm_data; + wc.wc_flags = IB_WC_WITH_IMM; + goto send_last; + case OP(SEND_LAST): + case OP(RDMA_WRITE_LAST): +no_immediate_data: + wc.wc_flags = 0; + wc.ex.imm_data = 0; +send_last: + /* Get the number of bytes the message was padded by. */ + pad = (bth0 >> 20) & 3; + /* Check for invalid length. */ + /* LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) + goto nack_inv; + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + wc.byte_len = tlen + qp->r_rcv_len; + if (unlikely(wc.byte_len > qp->r_len)) + goto nack_inv; + hfi1_copy_sge(&qp->r_sge, data, tlen, 1); + hfi1_put_ss(&qp->r_sge); + qp->r_msn++; + if (!test_and_clear_bit(HFI1_R_WRID_VALID, &qp->r_aflags)) + break; + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + if (opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE) || + opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) + wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; + else + wc.opcode = IB_WC_RECV; + wc.qp = &qp->ibqp; + wc.src_qp = qp->remote_qpn; + wc.slid = qp->remote_ah_attr.dlid; + /* + * It seems that IB mandates the presence of an SL in a + * work completion only for the UD transport (see section + * 11.4.2 of IBTA Vol. 1). + * + * However, the way the SL is chosen below is consistent + * with the way that IB/qib works and is trying avoid + * introducing incompatibilities. + * + * See also OPA Vol. 1, section 9.7.6, and table 9-17. + */ + wc.sl = qp->remote_ah_attr.sl; + /* zero fields that are N/A */ + wc.vendor_err = 0; + wc.pkey_index = 0; + wc.dlid_path_bits = 0; + wc.port_num = 0; + /* Signal completion event if the solicited bit is set. */ + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + (bth0 & IB_BTH_SOLICITED) != 0); + break; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_ONLY): + case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) + goto nack_inv; + /* consume RWQE */ + reth = &ohdr->u.rc.reth; + qp->r_len = be32_to_cpu(reth->length); + qp->r_rcv_len = 0; + qp->r_sge.sg_list = NULL; + if (qp->r_len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + /* Check rkey & NAK */ + ok = hfi1_rkey_ok(qp, &qp->r_sge.sge, qp->r_len, vaddr, + rkey, IB_ACCESS_REMOTE_WRITE); + if (unlikely(!ok)) + goto nack_acc; + qp->r_sge.num_sge = 1; + } else { + qp->r_sge.num_sge = 0; + qp->r_sge.sge.mr = NULL; + qp->r_sge.sge.vaddr = NULL; + qp->r_sge.sge.length = 0; + qp->r_sge.sge.sge_length = 0; + } + if (opcode == OP(RDMA_WRITE_FIRST)) + goto send_middle; + else if (opcode == OP(RDMA_WRITE_ONLY)) + goto no_immediate_data; + ret = hfi1_get_rwqe(qp, 1); + if (ret < 0) + goto nack_op_err; + if (!ret) + goto rnr_nak; + wc.ex.imm_data = ohdr->u.rc.imm_data; + wc.wc_flags = IB_WC_WITH_IMM; + goto send_last; + + case OP(RDMA_READ_REQUEST): { + struct hfi1_ack_entry *e; + u32 len; + u8 next; + + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) + goto nack_inv; + next = qp->r_head_ack_queue + 1; + /* s_ack_queue is size HFI1_MAX_RDMA_ATOMIC+1 so use > not >= */ + if (next > HFI1_MAX_RDMA_ATOMIC) + next = 0; + spin_lock_irqsave(&qp->s_lock, flags); + if (unlikely(next == qp->s_tail_ack_queue)) { + if (!qp->s_ack_queue[next].sent) + goto nack_inv_unlck; + update_ack_queue(qp, next); + } + e = &qp->s_ack_queue[qp->r_head_ack_queue]; + if (e->opcode == OP(RDMA_READ_REQUEST) && e->rdma_sge.mr) { + hfi1_put_mr(e->rdma_sge.mr); + e->rdma_sge.mr = NULL; + } + reth = &ohdr->u.rc.reth; + len = be32_to_cpu(reth->length); + if (len) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + /* Check rkey & NAK */ + ok = hfi1_rkey_ok(qp, &e->rdma_sge, len, vaddr, + rkey, IB_ACCESS_REMOTE_READ); + if (unlikely(!ok)) + goto nack_acc_unlck; + /* + * Update the next expected PSN. We add 1 later + * below, so only add the remainder here. + */ + if (len > pmtu) + qp->r_psn += (len - 1) / pmtu; + } else { + e->rdma_sge.mr = NULL; + e->rdma_sge.vaddr = NULL; + e->rdma_sge.length = 0; + e->rdma_sge.sge_length = 0; + } + e->opcode = opcode; + e->sent = 0; + e->psn = psn; + e->lpsn = qp->r_psn; + /* + * We need to increment the MSN here instead of when we + * finish sending the result since a duplicate request would + * increment it more than once. + */ + qp->r_msn++; + qp->r_psn++; + qp->r_state = opcode; + qp->r_nak_state = 0; + qp->r_head_ack_queue = next; + + /* Schedule the send tasklet. */ + qp->s_flags |= HFI1_S_RESP_PENDING; + hfi1_schedule_send(qp); + + spin_unlock_irqrestore(&qp->s_lock, flags); + if (is_fecn) + goto send_ack; + return; + } + + case OP(COMPARE_SWAP): + case OP(FETCH_ADD): { + struct ib_atomic_eth *ateth; + struct hfi1_ack_entry *e; + u64 vaddr; + atomic64_t *maddr; + u64 sdata; + u32 rkey; + u8 next; + + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) + goto nack_inv; + next = qp->r_head_ack_queue + 1; + if (next > HFI1_MAX_RDMA_ATOMIC) + next = 0; + spin_lock_irqsave(&qp->s_lock, flags); + if (unlikely(next == qp->s_tail_ack_queue)) { + if (!qp->s_ack_queue[next].sent) + goto nack_inv_unlck; + update_ack_queue(qp, next); + } + e = &qp->s_ack_queue[qp->r_head_ack_queue]; + if (e->opcode == OP(RDMA_READ_REQUEST) && e->rdma_sge.mr) { + hfi1_put_mr(e->rdma_sge.mr); + e->rdma_sge.mr = NULL; + } + ateth = &ohdr->u.atomic_eth; + vaddr = ((u64) be32_to_cpu(ateth->vaddr[0]) << 32) | + be32_to_cpu(ateth->vaddr[1]); + if (unlikely(vaddr & (sizeof(u64) - 1))) + goto nack_inv_unlck; + rkey = be32_to_cpu(ateth->rkey); + /* Check rkey & NAK */ + if (unlikely(!hfi1_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), + vaddr, rkey, + IB_ACCESS_REMOTE_ATOMIC))) + goto nack_acc_unlck; + /* Perform atomic OP and save result. */ + maddr = (atomic64_t *) qp->r_sge.sge.vaddr; + sdata = be64_to_cpu(ateth->swap_data); + e->atomic_data = (opcode == OP(FETCH_ADD)) ? + (u64) atomic64_add_return(sdata, maddr) - sdata : + (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, + be64_to_cpu(ateth->compare_data), + sdata); + hfi1_put_mr(qp->r_sge.sge.mr); + qp->r_sge.num_sge = 0; + e->opcode = opcode; + e->sent = 0; + e->psn = psn; + e->lpsn = psn; + qp->r_msn++; + qp->r_psn++; + qp->r_state = opcode; + qp->r_nak_state = 0; + qp->r_head_ack_queue = next; + + /* Schedule the send tasklet. */ + qp->s_flags |= HFI1_S_RESP_PENDING; + hfi1_schedule_send(qp); + + spin_unlock_irqrestore(&qp->s_lock, flags); + if (is_fecn) + goto send_ack; + return; + } + + default: + /* NAK unknown opcodes. */ + goto nack_inv; + } + qp->r_psn++; + qp->r_state = opcode; + qp->r_ack_psn = psn; + qp->r_nak_state = 0; + /* Send an ACK if requested or required. */ + if (psn & (1 << 31)) + goto send_ack; + return; + +rnr_nak: + qp->r_nak_state = IB_RNR_NAK | qp->r_min_rnr_timer; + qp->r_ack_psn = qp->r_psn; + /* Queue RNR NAK for later */ + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_NAK; + atomic_inc(&qp->refcount); + list_add_tail(&qp->rspwait, &rcd->qp_wait_list); + } + return; + +nack_op_err: + hfi1_rc_error(qp, IB_WC_LOC_QP_OP_ERR); + qp->r_nak_state = IB_NAK_REMOTE_OPERATIONAL_ERROR; + qp->r_ack_psn = qp->r_psn; + /* Queue NAK for later */ + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_NAK; + atomic_inc(&qp->refcount); + list_add_tail(&qp->rspwait, &rcd->qp_wait_list); + } + return; + +nack_inv_unlck: + spin_unlock_irqrestore(&qp->s_lock, flags); +nack_inv: + hfi1_rc_error(qp, IB_WC_LOC_QP_OP_ERR); + qp->r_nak_state = IB_NAK_INVALID_REQUEST; + qp->r_ack_psn = qp->r_psn; + /* Queue NAK for later */ + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_NAK; + atomic_inc(&qp->refcount); + list_add_tail(&qp->rspwait, &rcd->qp_wait_list); + } + return; + +nack_acc_unlck: + spin_unlock_irqrestore(&qp->s_lock, flags); +nack_acc: + hfi1_rc_error(qp, IB_WC_LOC_PROT_ERR); + qp->r_nak_state = IB_NAK_REMOTE_ACCESS_ERROR; + qp->r_ack_psn = qp->r_psn; +send_ack: + hfi1_send_rc_ack(rcd, qp, is_fecn); +} + +void hfi1_rc_hdrerr( + struct hfi1_ctxtdata *rcd, + struct hfi1_ib_header *hdr, + u32 rcv_flags, + struct hfi1_qp *qp) +{ + int has_grh = rcv_flags & HFI1_HAS_GRH; + struct hfi1_other_headers *ohdr; + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + int diff; + u8 opcode; + u32 psn; + + /* Check for GRH */ + ohdr = &hdr->u.oth; + if (has_grh) + ohdr = &hdr->u.l.oth; + + opcode = be32_to_cpu(ohdr->bth[0]); + if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode)) + return; + + psn = be32_to_cpu(ohdr->bth[2]); + opcode >>= 24; + + /* Only deal with RDMA Writes for now */ + if (opcode < IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST) { + diff = delta_psn(psn, qp->r_psn); + if (!qp->r_nak_state && diff >= 0) { + ibp->n_rc_seqnak++; + qp->r_nak_state = IB_NAK_PSN_ERROR; + /* Use the expected PSN. */ + qp->r_ack_psn = qp->r_psn; + /* + * Wait to send the sequence + * NAK until all packets + * in the receive queue have + * been processed. + * Otherwise, we end up + * propagating congestion. + */ + if (list_empty(&qp->rspwait)) { + qp->r_flags |= HFI1_R_RSP_NAK; + atomic_inc(&qp->refcount); + list_add_tail( + &qp->rspwait, + &rcd->qp_wait_list); + } + } /* Out of sequence NAK */ + } /* QP Request NAKs */ +} diff --git a/drivers/staging/rdma/hfi1/ruc.c b/drivers/staging/rdma/hfi1/ruc.c new file mode 100644 index 0000000000000..a4115288db666 --- /dev/null +++ b/drivers/staging/rdma/hfi1/ruc.c @@ -0,0 +1,948 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "hfi.h" +#include "mad.h" +#include "qp.h" +#include "sdma.h" + +/* + * Convert the AETH RNR timeout code into the number of microseconds. + */ +const u32 ib_hfi1_rnr_table[32] = { + 655360, /* 00: 655.36 */ + 10, /* 01: .01 */ + 20, /* 02 .02 */ + 30, /* 03: .03 */ + 40, /* 04: .04 */ + 60, /* 05: .06 */ + 80, /* 06: .08 */ + 120, /* 07: .12 */ + 160, /* 08: .16 */ + 240, /* 09: .24 */ + 320, /* 0A: .32 */ + 480, /* 0B: .48 */ + 640, /* 0C: .64 */ + 960, /* 0D: .96 */ + 1280, /* 0E: 1.28 */ + 1920, /* 0F: 1.92 */ + 2560, /* 10: 2.56 */ + 3840, /* 11: 3.84 */ + 5120, /* 12: 5.12 */ + 7680, /* 13: 7.68 */ + 10240, /* 14: 10.24 */ + 15360, /* 15: 15.36 */ + 20480, /* 16: 20.48 */ + 30720, /* 17: 30.72 */ + 40960, /* 18: 40.96 */ + 61440, /* 19: 61.44 */ + 81920, /* 1A: 81.92 */ + 122880, /* 1B: 122.88 */ + 163840, /* 1C: 163.84 */ + 245760, /* 1D: 245.76 */ + 327680, /* 1E: 327.68 */ + 491520 /* 1F: 491.52 */ +}; + +/* + * Validate a RWQE and fill in the SGE state. + * Return 1 if OK. + */ +static int init_sge(struct hfi1_qp *qp, struct hfi1_rwqe *wqe) +{ + int i, j, ret; + struct ib_wc wc; + struct hfi1_lkey_table *rkt; + struct hfi1_pd *pd; + struct hfi1_sge_state *ss; + + rkt = &to_idev(qp->ibqp.device)->lk_table; + pd = to_ipd(qp->ibqp.srq ? qp->ibqp.srq->pd : qp->ibqp.pd); + ss = &qp->r_sge; + ss->sg_list = qp->r_sg_list; + qp->r_len = 0; + for (i = j = 0; i < wqe->num_sge; i++) { + if (wqe->sg_list[i].length == 0) + continue; + /* Check LKEY */ + if (!hfi1_lkey_ok(rkt, pd, j ? &ss->sg_list[j - 1] : &ss->sge, + &wqe->sg_list[i], IB_ACCESS_LOCAL_WRITE)) + goto bad_lkey; + qp->r_len += wqe->sg_list[i].length; + j++; + } + ss->num_sge = j; + ss->total_len = qp->r_len; + ret = 1; + goto bail; + +bad_lkey: + while (j) { + struct hfi1_sge *sge = --j ? &ss->sg_list[j - 1] : &ss->sge; + + hfi1_put_mr(sge->mr); + } + ss->num_sge = 0; + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wqe->wr_id; + wc.status = IB_WC_LOC_PROT_ERR; + wc.opcode = IB_WC_RECV; + wc.qp = &qp->ibqp; + /* Signal solicited completion event. */ + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, 1); + ret = 0; +bail: + return ret; +} + +/** + * hfi1_get_rwqe - copy the next RWQE into the QP's RWQE + * @qp: the QP + * @wr_id_only: update qp->r_wr_id only, not qp->r_sge + * + * Return -1 if there is a local error, 0 if no RWQE is available, + * otherwise return 1. + * + * Can be called from interrupt level. + */ +int hfi1_get_rwqe(struct hfi1_qp *qp, int wr_id_only) +{ + unsigned long flags; + struct hfi1_rq *rq; + struct hfi1_rwq *wq; + struct hfi1_srq *srq; + struct hfi1_rwqe *wqe; + void (*handler)(struct ib_event *, void *); + u32 tail; + int ret; + + if (qp->ibqp.srq) { + srq = to_isrq(qp->ibqp.srq); + handler = srq->ibsrq.event_handler; + rq = &srq->rq; + } else { + srq = NULL; + handler = NULL; + rq = &qp->r_rq; + } + + spin_lock_irqsave(&rq->lock, flags); + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK)) { + ret = 0; + goto unlock; + } + + wq = rq->wq; + tail = wq->tail; + /* Validate tail before using it since it is user writable. */ + if (tail >= rq->size) + tail = 0; + if (unlikely(tail == wq->head)) { + ret = 0; + goto unlock; + } + /* Make sure entry is read after head index is read. */ + smp_rmb(); + wqe = get_rwqe_ptr(rq, tail); + /* + * Even though we update the tail index in memory, the verbs + * consumer is not supposed to post more entries until a + * completion is generated. + */ + if (++tail >= rq->size) + tail = 0; + wq->tail = tail; + if (!wr_id_only && !init_sge(qp, wqe)) { + ret = -1; + goto unlock; + } + qp->r_wr_id = wqe->wr_id; + + ret = 1; + set_bit(HFI1_R_WRID_VALID, &qp->r_aflags); + if (handler) { + u32 n; + + /* + * Validate head pointer value and compute + * the number of remaining WQEs. + */ + n = wq->head; + if (n >= rq->size) + n = 0; + if (n < tail) + n += rq->size - tail; + else + n -= tail; + if (n < srq->limit) { + struct ib_event ev; + + srq->limit = 0; + spin_unlock_irqrestore(&rq->lock, flags); + ev.device = qp->ibqp.device; + ev.element.srq = qp->ibqp.srq; + ev.event = IB_EVENT_SRQ_LIMIT_REACHED; + handler(&ev, srq->ibsrq.srq_context); + goto bail; + } + } +unlock: + spin_unlock_irqrestore(&rq->lock, flags); +bail: + return ret; +} + +/* + * Switch to alternate path. + * The QP s_lock should be held and interrupts disabled. + */ +void hfi1_migrate_qp(struct hfi1_qp *qp) +{ + struct ib_event ev; + + qp->s_mig_state = IB_MIG_MIGRATED; + qp->remote_ah_attr = qp->alt_ah_attr; + qp->port_num = qp->alt_ah_attr.port_num; + qp->s_pkey_index = qp->s_alt_pkey_index; + qp->s_flags |= HFI1_S_AHG_CLEAR; + + ev.device = qp->ibqp.device; + ev.element.qp = &qp->ibqp; + ev.event = IB_EVENT_PATH_MIG; + qp->ibqp.event_handler(&ev, qp->ibqp.qp_context); +} + +static __be64 get_sguid(struct hfi1_ibport *ibp, unsigned index) +{ + if (!index) { + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + return cpu_to_be64(ppd->guid); + } + return ibp->guids[index - 1]; +} + +static int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id) +{ + return (gid->global.interface_id == id && + (gid->global.subnet_prefix == gid_prefix || + gid->global.subnet_prefix == IB_DEFAULT_GID_PREFIX)); +} + +/* + * + * This should be called with the QP r_lock held. + * + * The s_lock will be acquired around the hfi1_migrate_qp() call. + */ +int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_ib_header *hdr, + int has_grh, struct hfi1_qp *qp, u32 bth0) +{ + __be64 guid; + unsigned long flags; + u8 sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + + if (qp->s_mig_state == IB_MIG_ARMED && (bth0 & IB_BTH_MIG_REQ)) { + if (!has_grh) { + if (qp->alt_ah_attr.ah_flags & IB_AH_GRH) + goto err; + } else { + if (!(qp->alt_ah_attr.ah_flags & IB_AH_GRH)) + goto err; + guid = get_sguid(ibp, qp->alt_ah_attr.grh.sgid_index); + if (!gid_ok(&hdr->u.l.grh.dgid, ibp->gid_prefix, guid)) + goto err; + if (!gid_ok(&hdr->u.l.grh.sgid, + qp->alt_ah_attr.grh.dgid.global.subnet_prefix, + qp->alt_ah_attr.grh.dgid.global.interface_id)) + goto err; + } + if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), (u16)bth0, + sc5, be16_to_cpu(hdr->lrh[3])))) { + hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY, + (u16)bth0, + (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF, + 0, qp->ibqp.qp_num, + hdr->lrh[3], hdr->lrh[1]); + goto err; + } + /* Validate the SLID. See Ch. 9.6.1.5 and 17.2.8 */ + if (be16_to_cpu(hdr->lrh[3]) != qp->alt_ah_attr.dlid || + ppd_from_ibp(ibp)->port != qp->alt_ah_attr.port_num) + goto err; + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_migrate_qp(qp); + spin_unlock_irqrestore(&qp->s_lock, flags); + } else { + if (!has_grh) { + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + goto err; + } else { + if (!(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) + goto err; + guid = get_sguid(ibp, + qp->remote_ah_attr.grh.sgid_index); + if (!gid_ok(&hdr->u.l.grh.dgid, ibp->gid_prefix, guid)) + goto err; + if (!gid_ok(&hdr->u.l.grh.sgid, + qp->remote_ah_attr.grh.dgid.global.subnet_prefix, + qp->remote_ah_attr.grh.dgid.global.interface_id)) + goto err; + } + if (unlikely(rcv_pkey_check(ppd_from_ibp(ibp), (u16)bth0, + sc5, be16_to_cpu(hdr->lrh[3])))) { + hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY, + (u16)bth0, + (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF, + 0, qp->ibqp.qp_num, + hdr->lrh[3], hdr->lrh[1]); + goto err; + } + /* Validate the SLID. See Ch. 9.6.1.5 */ + if (be16_to_cpu(hdr->lrh[3]) != qp->remote_ah_attr.dlid || + ppd_from_ibp(ibp)->port != qp->port_num) + goto err; + if (qp->s_mig_state == IB_MIG_REARM && + !(bth0 & IB_BTH_MIG_REQ)) + qp->s_mig_state = IB_MIG_ARMED; + } + + return 0; + +err: + return 1; +} + +/** + * ruc_loopback - handle UC and RC loopback requests + * @sqp: the sending QP + * + * This is called from hfi1_do_send() to + * forward a WQE addressed to the same HFI. + * Note that although we are single threaded due to the tasklet, we still + * have to protect against post_send(). We don't have to worry about + * receive interrupts since this is a connected protocol and all packets + * will pass through here. + */ +static void ruc_loopback(struct hfi1_qp *sqp) +{ + struct hfi1_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num); + struct hfi1_qp *qp; + struct hfi1_swqe *wqe; + struct hfi1_sge *sge; + unsigned long flags; + struct ib_wc wc; + u64 sdata; + atomic64_t *maddr; + enum ib_wc_status send_status; + int release; + int ret; + + rcu_read_lock(); + + /* + * Note that we check the responder QP state after + * checking the requester's state. + */ + qp = hfi1_lookup_qpn(ibp, sqp->remote_qpn); + + spin_lock_irqsave(&sqp->s_lock, flags); + + /* Return if we are already busy processing a work request. */ + if ((sqp->s_flags & (HFI1_S_BUSY | HFI1_S_ANY_WAIT)) || + !(ib_hfi1_state_ops[sqp->state] & HFI1_PROCESS_OR_FLUSH_SEND)) + goto unlock; + + sqp->s_flags |= HFI1_S_BUSY; + +again: + if (sqp->s_last == sqp->s_head) + goto clr_busy; + wqe = get_swqe_ptr(sqp, sqp->s_last); + + /* Return if it is not OK to start a new work request. */ + if (!(ib_hfi1_state_ops[sqp->state] & HFI1_PROCESS_NEXT_SEND_OK)) { + if (!(ib_hfi1_state_ops[sqp->state] & HFI1_FLUSH_SEND)) + goto clr_busy; + /* We are in the error state, flush the work request. */ + send_status = IB_WC_WR_FLUSH_ERR; + goto flush_send; + } + + /* + * We can rely on the entry not changing without the s_lock + * being held until we update s_last. + * We increment s_cur to indicate s_last is in progress. + */ + if (sqp->s_last == sqp->s_cur) { + if (++sqp->s_cur >= sqp->s_size) + sqp->s_cur = 0; + } + spin_unlock_irqrestore(&sqp->s_lock, flags); + + if (!qp || !(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK) || + qp->ibqp.qp_type != sqp->ibqp.qp_type) { + ibp->n_pkt_drops++; + /* + * For RC, the requester would timeout and retry so + * shortcut the timeouts and just signal too many retries. + */ + if (sqp->ibqp.qp_type == IB_QPT_RC) + send_status = IB_WC_RETRY_EXC_ERR; + else + send_status = IB_WC_SUCCESS; + goto serr; + } + + memset(&wc, 0, sizeof(wc)); + send_status = IB_WC_SUCCESS; + + release = 1; + sqp->s_sge.sge = wqe->sg_list[0]; + sqp->s_sge.sg_list = wqe->sg_list + 1; + sqp->s_sge.num_sge = wqe->wr.num_sge; + sqp->s_len = wqe->length; + switch (wqe->wr.opcode) { + case IB_WR_SEND_WITH_IMM: + wc.wc_flags = IB_WC_WITH_IMM; + wc.ex.imm_data = wqe->wr.ex.imm_data; + /* FALLTHROUGH */ + case IB_WR_SEND: + ret = hfi1_get_rwqe(qp, 0); + if (ret < 0) + goto op_err; + if (!ret) + goto rnr_nak; + break; + + case IB_WR_RDMA_WRITE_WITH_IMM: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) + goto inv_err; + wc.wc_flags = IB_WC_WITH_IMM; + wc.ex.imm_data = wqe->wr.ex.imm_data; + ret = hfi1_get_rwqe(qp, 1); + if (ret < 0) + goto op_err; + if (!ret) + goto rnr_nak; + /* FALLTHROUGH */ + case IB_WR_RDMA_WRITE: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_WRITE))) + goto inv_err; + if (wqe->length == 0) + break; + if (unlikely(!hfi1_rkey_ok(qp, &qp->r_sge.sge, wqe->length, + wqe->wr.wr.rdma.remote_addr, + wqe->wr.wr.rdma.rkey, + IB_ACCESS_REMOTE_WRITE))) + goto acc_err; + qp->r_sge.sg_list = NULL; + qp->r_sge.num_sge = 1; + qp->r_sge.total_len = wqe->length; + break; + + case IB_WR_RDMA_READ: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_READ))) + goto inv_err; + if (unlikely(!hfi1_rkey_ok(qp, &sqp->s_sge.sge, wqe->length, + wqe->wr.wr.rdma.remote_addr, + wqe->wr.wr.rdma.rkey, + IB_ACCESS_REMOTE_READ))) + goto acc_err; + release = 0; + sqp->s_sge.sg_list = NULL; + sqp->s_sge.num_sge = 1; + qp->r_sge.sge = wqe->sg_list[0]; + qp->r_sge.sg_list = wqe->sg_list + 1; + qp->r_sge.num_sge = wqe->wr.num_sge; + qp->r_sge.total_len = wqe->length; + break; + + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + if (unlikely(!(qp->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC))) + goto inv_err; + if (unlikely(!hfi1_rkey_ok(qp, &qp->r_sge.sge, sizeof(u64), + wqe->wr.wr.atomic.remote_addr, + wqe->wr.wr.atomic.rkey, + IB_ACCESS_REMOTE_ATOMIC))) + goto acc_err; + /* Perform atomic OP and save result. */ + maddr = (atomic64_t *) qp->r_sge.sge.vaddr; + sdata = wqe->wr.wr.atomic.compare_add; + *(u64 *) sqp->s_sge.sge.vaddr = + (wqe->wr.opcode == IB_WR_ATOMIC_FETCH_AND_ADD) ? + (u64) atomic64_add_return(sdata, maddr) - sdata : + (u64) cmpxchg((u64 *) qp->r_sge.sge.vaddr, + sdata, wqe->wr.wr.atomic.swap); + hfi1_put_mr(qp->r_sge.sge.mr); + qp->r_sge.num_sge = 0; + goto send_comp; + + default: + send_status = IB_WC_LOC_QP_OP_ERR; + goto serr; + } + + sge = &sqp->s_sge.sge; + while (sqp->s_len) { + u32 len = sqp->s_len; + + if (len > sge->length) + len = sge->length; + if (len > sge->sge_length) + len = sge->sge_length; + WARN_ON_ONCE(len == 0); + hfi1_copy_sge(&qp->r_sge, sge->vaddr, len, release); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (!release) + hfi1_put_mr(sge->mr); + if (--sqp->s_sge.num_sge) + *sge = *sqp->s_sge.sg_list++; + } else if (sge->length == 0 && sge->mr->lkey) { + if (++sge->n >= HFI1_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + sqp->s_len -= len; + } + if (release) + hfi1_put_ss(&qp->r_sge); + + if (!test_and_clear_bit(HFI1_R_WRID_VALID, &qp->r_aflags)) + goto send_comp; + + if (wqe->wr.opcode == IB_WR_RDMA_WRITE_WITH_IMM) + wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; + else + wc.opcode = IB_WC_RECV; + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.byte_len = wqe->length; + wc.qp = &qp->ibqp; + wc.src_qp = qp->remote_qpn; + wc.slid = qp->remote_ah_attr.dlid; + wc.sl = qp->remote_ah_attr.sl; + wc.port_num = 1; + /* Signal completion event if the solicited bit is set. */ + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + wqe->wr.send_flags & IB_SEND_SOLICITED); + +send_comp: + spin_lock_irqsave(&sqp->s_lock, flags); + ibp->n_loop_pkts++; +flush_send: + sqp->s_rnr_retry = sqp->s_rnr_retry_cnt; + hfi1_send_complete(sqp, wqe, send_status); + goto again; + +rnr_nak: + /* Handle RNR NAK */ + if (qp->ibqp.qp_type == IB_QPT_UC) + goto send_comp; + ibp->n_rnr_naks++; + /* + * Note: we don't need the s_lock held since the BUSY flag + * makes this single threaded. + */ + if (sqp->s_rnr_retry == 0) { + send_status = IB_WC_RNR_RETRY_EXC_ERR; + goto serr; + } + if (sqp->s_rnr_retry_cnt < 7) + sqp->s_rnr_retry--; + spin_lock_irqsave(&sqp->s_lock, flags); + if (!(ib_hfi1_state_ops[sqp->state] & HFI1_PROCESS_RECV_OK)) + goto clr_busy; + sqp->s_flags |= HFI1_S_WAIT_RNR; + sqp->s_timer.function = hfi1_rc_rnr_retry; + sqp->s_timer.expires = jiffies + + usecs_to_jiffies(ib_hfi1_rnr_table[qp->r_min_rnr_timer]); + add_timer(&sqp->s_timer); + goto clr_busy; + +op_err: + send_status = IB_WC_REM_OP_ERR; + wc.status = IB_WC_LOC_QP_OP_ERR; + goto err; + +inv_err: + send_status = IB_WC_REM_INV_REQ_ERR; + wc.status = IB_WC_LOC_QP_OP_ERR; + goto err; + +acc_err: + send_status = IB_WC_REM_ACCESS_ERR; + wc.status = IB_WC_LOC_PROT_ERR; +err: + /* responder goes to error state */ + hfi1_rc_error(qp, wc.status); + +serr: + spin_lock_irqsave(&sqp->s_lock, flags); + hfi1_send_complete(sqp, wqe, send_status); + if (sqp->ibqp.qp_type == IB_QPT_RC) { + int lastwqe = hfi1_error_qp(sqp, IB_WC_WR_FLUSH_ERR); + + sqp->s_flags &= ~HFI1_S_BUSY; + spin_unlock_irqrestore(&sqp->s_lock, flags); + if (lastwqe) { + struct ib_event ev; + + ev.device = sqp->ibqp.device; + ev.element.qp = &sqp->ibqp; + ev.event = IB_EVENT_QP_LAST_WQE_REACHED; + sqp->ibqp.event_handler(&ev, sqp->ibqp.qp_context); + } + goto done; + } +clr_busy: + sqp->s_flags &= ~HFI1_S_BUSY; +unlock: + spin_unlock_irqrestore(&sqp->s_lock, flags); +done: + rcu_read_unlock(); +} + +/** + * hfi1_make_grh - construct a GRH header + * @ibp: a pointer to the IB port + * @hdr: a pointer to the GRH header being constructed + * @grh: the global route address to send to + * @hwords: the number of 32 bit words of header being sent + * @nwords: the number of 32 bit words of data being sent + * + * Return the size of the header in 32 bit words. + */ +u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr, + struct ib_global_route *grh, u32 hwords, u32 nwords) +{ + hdr->version_tclass_flow = + cpu_to_be32((IB_GRH_VERSION << IB_GRH_VERSION_SHIFT) | + (grh->traffic_class << IB_GRH_TCLASS_SHIFT) | + (grh->flow_label << IB_GRH_FLOW_SHIFT)); + hdr->paylen = cpu_to_be16((hwords - 2 + nwords + SIZE_OF_CRC) << 2); + /* next_hdr is defined by C8-7 in ch. 8.4.1 */ + hdr->next_hdr = IB_GRH_NEXT_HDR; + hdr->hop_limit = grh->hop_limit; + /* The SGID is 32-bit aligned. */ + hdr->sgid.global.subnet_prefix = ibp->gid_prefix; + hdr->sgid.global.interface_id = + grh->sgid_index && grh->sgid_index < ARRAY_SIZE(ibp->guids) ? + ibp->guids[grh->sgid_index - 1] : + cpu_to_be64(ppd_from_ibp(ibp)->guid); + hdr->dgid = grh->dgid; + + /* GRH header size in 32-bit words. */ + return sizeof(struct ib_grh) / sizeof(u32); +} + +/* + * free_ahg - clear ahg from QP + */ +void clear_ahg(struct hfi1_qp *qp) +{ + qp->s_hdr->ahgcount = 0; + qp->s_flags &= ~(HFI1_S_AHG_VALID | HFI1_S_AHG_CLEAR); + if (qp->s_sde) + sdma_ahg_free(qp->s_sde, qp->s_ahgidx); + qp->s_ahgidx = -1; + qp->s_sde = NULL; +} + +#define BTH2_OFFSET (offsetof(struct hfi1_pio_header, hdr.u.oth.bth[2]) / 4) + +/** + * build_ahg - create ahg in s_hdr + * @qp: a pointer to QP + * @npsn: the next PSN for the request/response + * + * This routine handles the AHG by allocating an ahg entry and causing the + * copy of the first middle. + * + * Subsequent middles use the copied entry, editing the + * PSN with 1 or 2 edits. + */ +static inline void build_ahg(struct hfi1_qp *qp, u32 npsn) +{ + if (unlikely(qp->s_flags & HFI1_S_AHG_CLEAR)) + clear_ahg(qp); + if (!(qp->s_flags & HFI1_S_AHG_VALID)) { + /* first middle that needs copy */ + if (qp->s_ahgidx < 0) { + if (!qp->s_sde) + qp->s_sde = qp_to_sdma_engine(qp, qp->s_sc); + qp->s_ahgidx = sdma_ahg_alloc(qp->s_sde); + } + if (qp->s_ahgidx >= 0) { + qp->s_ahgpsn = npsn; + qp->s_hdr->tx_flags |= SDMA_TXREQ_F_AHG_COPY; + /* save to protect a change in another thread */ + qp->s_hdr->sde = qp->s_sde; + qp->s_hdr->ahgidx = qp->s_ahgidx; + qp->s_flags |= HFI1_S_AHG_VALID; + } + } else { + /* subsequent middle after valid */ + if (qp->s_ahgidx >= 0) { + qp->s_hdr->tx_flags |= SDMA_TXREQ_F_USE_AHG; + qp->s_hdr->ahgidx = qp->s_ahgidx; + qp->s_hdr->ahgcount++; + qp->s_hdr->ahgdesc[0] = + sdma_build_ahg_descriptor( + (__force u16)cpu_to_be16((u16)npsn), + BTH2_OFFSET, + 16, + 16); + if ((npsn & 0xffff0000) != + (qp->s_ahgpsn & 0xffff0000)) { + qp->s_hdr->ahgcount++; + qp->s_hdr->ahgdesc[1] = + sdma_build_ahg_descriptor( + (__force u16)cpu_to_be16( + (u16)(npsn >> 16)), + BTH2_OFFSET, + 0, + 16); + } + } + } +} + +void hfi1_make_ruc_header(struct hfi1_qp *qp, struct hfi1_other_headers *ohdr, + u32 bth0, u32 bth2, int middle) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + u16 lrh0; + u32 nwords; + u32 extra_bytes; + u8 sc5; + u32 bth1; + + /* Construct the header. */ + extra_bytes = -qp->s_cur_size & 3; + nwords = (qp->s_cur_size + extra_bytes) >> 2; + lrh0 = HFI1_LRH_BTH; + if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { + qp->s_hdrwords += hfi1_make_grh(ibp, &qp->s_hdr->ibh.u.l.grh, + &qp->remote_ah_attr.grh, + qp->s_hdrwords, nwords); + lrh0 = HFI1_LRH_GRH; + middle = 0; + } + sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + lrh0 |= (sc5 & 0xf) << 12 | (qp->remote_ah_attr.sl & 0xf) << 4; + qp->s_sc = sc5; + /* + * reset s_hdr/AHG fields + * + * This insures that the ahgentry/ahgcount + * are at a non-AHG default to protect + * build_verbs_tx_desc() from using + * an include ahgidx. + * + * build_ahg() will modify as appropriate + * to use the AHG feature. + */ + qp->s_hdr->tx_flags = 0; + qp->s_hdr->ahgcount = 0; + qp->s_hdr->ahgidx = 0; + qp->s_hdr->sde = NULL; + if (qp->s_mig_state == IB_MIG_MIGRATED) + bth0 |= IB_BTH_MIG_REQ; + else + middle = 0; + if (middle) + build_ahg(qp, bth2); + else + qp->s_flags &= ~HFI1_S_AHG_VALID; + qp->s_hdr->ibh.lrh[0] = cpu_to_be16(lrh0); + qp->s_hdr->ibh.lrh[1] = cpu_to_be16(qp->remote_ah_attr.dlid); + qp->s_hdr->ibh.lrh[2] = + cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC); + qp->s_hdr->ibh.lrh[3] = cpu_to_be16(ppd_from_ibp(ibp)->lid | + qp->remote_ah_attr.src_path_bits); + bth0 |= hfi1_get_pkey(ibp, qp->s_pkey_index); + bth0 |= extra_bytes << 20; + ohdr->bth[0] = cpu_to_be32(bth0); + bth1 = qp->remote_qpn; + if (qp->s_flags & HFI1_S_ECN) { + qp->s_flags &= ~HFI1_S_ECN; + /* we recently received a FECN, so return a BECN */ + bth1 |= (HFI1_BECN_MASK << HFI1_BECN_SHIFT); + } + ohdr->bth[1] = cpu_to_be32(bth1); + ohdr->bth[2] = cpu_to_be32(bth2); +} + +/** + * hfi1_do_send - perform a send on a QP + * @work: contains a pointer to the QP + * + * Process entries in the send work queue until credit or queue is + * exhausted. Only allow one CPU to send a packet per QP (tasklet). + * Otherwise, two threads could send packets out of order. + */ +void hfi1_do_send(struct work_struct *work) +{ + struct iowait *wait = container_of(work, struct iowait, iowork); + struct hfi1_qp *qp = container_of(wait, struct hfi1_qp, s_iowait); + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + int (*make_req)(struct hfi1_qp *qp); + unsigned long flags; + + if ((qp->ibqp.qp_type == IB_QPT_RC || + qp->ibqp.qp_type == IB_QPT_UC) && + !loopback && + (qp->remote_ah_attr.dlid & ~((1 << ppd->lmc) - 1)) == ppd->lid) { + ruc_loopback(qp); + return; + } + + if (qp->ibqp.qp_type == IB_QPT_RC) + make_req = hfi1_make_rc_req; + else if (qp->ibqp.qp_type == IB_QPT_UC) + make_req = hfi1_make_uc_req; + else + make_req = hfi1_make_ud_req; + + spin_lock_irqsave(&qp->s_lock, flags); + + /* Return if we are already busy processing a work request. */ + if (!hfi1_send_ok(qp)) { + spin_unlock_irqrestore(&qp->s_lock, flags); + return; + } + + qp->s_flags |= HFI1_S_BUSY; + + spin_unlock_irqrestore(&qp->s_lock, flags); + + do { + /* Check for a constructed packet to be sent. */ + if (qp->s_hdrwords != 0) { + /* + * If the packet cannot be sent now, return and + * the send tasklet will be woken up later. + */ + if (hfi1_verbs_send(qp, qp->s_hdr, qp->s_hdrwords, + qp->s_cur_sge, qp->s_cur_size)) + break; + /* Record that s_hdr is empty. */ + qp->s_hdrwords = 0; + } + } while (make_req(qp)); +} + +/* + * This should be called with s_lock held. + */ +void hfi1_send_complete(struct hfi1_qp *qp, struct hfi1_swqe *wqe, + enum ib_wc_status status) +{ + u32 old_last, last; + unsigned i; + + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_OR_FLUSH_SEND)) + return; + + for (i = 0; i < wqe->wr.num_sge; i++) { + struct hfi1_sge *sge = &wqe->sg_list[i]; + + hfi1_put_mr(sge->mr); + } + if (qp->ibqp.qp_type == IB_QPT_UD || + qp->ibqp.qp_type == IB_QPT_SMI || + qp->ibqp.qp_type == IB_QPT_GSI) + atomic_dec(&to_iah(wqe->wr.wr.ud.ah)->refcount); + + /* See ch. 11.2.4.1 and 10.7.3.1 */ + if (!(qp->s_flags & HFI1_S_SIGNAL_REQ_WR) || + (wqe->wr.send_flags & IB_SEND_SIGNALED) || + status != IB_WC_SUCCESS) { + struct ib_wc wc; + + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wqe->wr.wr_id; + wc.status = status; + wc.opcode = ib_hfi1_wc_opcode[wqe->wr.opcode]; + wc.qp = &qp->ibqp; + if (status == IB_WC_SUCCESS) + wc.byte_len = wqe->length; + hfi1_cq_enter(to_icq(qp->ibqp.send_cq), &wc, + status != IB_WC_SUCCESS); + } + + last = qp->s_last; + old_last = last; + if (++last >= qp->s_size) + last = 0; + qp->s_last = last; + if (qp->s_acked == old_last) + qp->s_acked = last; + if (qp->s_cur == old_last) + qp->s_cur = last; + if (qp->s_tail == old_last) + qp->s_tail = last; + if (qp->state == IB_QPS_SQD && last == qp->s_cur) + qp->s_draining = 0; +} diff --git a/drivers/staging/rdma/hfi1/sdma.c b/drivers/staging/rdma/hfi1/sdma.c new file mode 100644 index 0000000000000..37bd767d6bc01 --- /dev/null +++ b/drivers/staging/rdma/hfi1/sdma.c @@ -0,0 +1,2962 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "common.h" +#include "qp.h" +#include "sdma.h" +#include "iowait.h" +#include "trace.h" + +/* must be a power of 2 >= 64 <= 32768 */ +#define SDMA_DESCQ_CNT 1024 +#define INVALID_TAIL 0xffff + +static uint sdma_descq_cnt = SDMA_DESCQ_CNT; +module_param(sdma_descq_cnt, uint, S_IRUGO); +MODULE_PARM_DESC(sdma_descq_cnt, "Number of SDMA descq entries"); + +static uint sdma_idle_cnt = 250; +module_param(sdma_idle_cnt, uint, S_IRUGO); +MODULE_PARM_DESC(sdma_idle_cnt, "sdma interrupt idle delay (ns,default 250)"); + +uint mod_num_sdma; +module_param_named(num_sdma, mod_num_sdma, uint, S_IRUGO); +MODULE_PARM_DESC(num_sdma, "Set max number SDMA engines to use"); + +#define SDMA_WAIT_BATCH_SIZE 20 +/* max wait time for a SDMA engine to indicate it has halted */ +#define SDMA_ERR_HALT_TIMEOUT 10 /* ms */ +/* all SDMA engine errors that cause a halt */ + +#define SD(name) SEND_DMA_##name +#define ALL_SDMA_ENG_HALT_ERRS \ + (SD(ENG_ERR_STATUS_SDMA_WRONG_DW_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_GEN_MISMATCH_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_TOO_LONG_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_TAIL_OUT_OF_BOUNDS_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_FIRST_DESC_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_MEM_READ_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_LENGTH_MISMATCH_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_PACKET_DESC_OVERFLOW_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_HEADER_SELECT_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_HEADER_ADDRESS_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_HEADER_LENGTH_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_TIMEOUT_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_DESC_TABLE_UNC_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_ASSEMBLY_UNC_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_PACKET_TRACKING_UNC_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_HEADER_STORAGE_UNC_ERR_SMASK) \ + | SD(ENG_ERR_STATUS_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SMASK)) + +/* sdma_sendctrl operations */ +#define SDMA_SENDCTRL_OP_ENABLE (1U << 0) +#define SDMA_SENDCTRL_OP_INTENABLE (1U << 1) +#define SDMA_SENDCTRL_OP_HALT (1U << 2) +#define SDMA_SENDCTRL_OP_CLEANUP (1U << 3) + +/* handle long defines */ +#define SDMA_EGRESS_PACKET_OCCUPANCY_SMASK \ +SEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SMASK +#define SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT \ +SEND_EGRESS_SEND_DMA_STATUS_SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT + +static const char * const sdma_state_names[] = { + [sdma_state_s00_hw_down] = "s00_HwDown", + [sdma_state_s10_hw_start_up_halt_wait] = "s10_HwStartUpHaltWait", + [sdma_state_s15_hw_start_up_clean_wait] = "s15_HwStartUpCleanWait", + [sdma_state_s20_idle] = "s20_Idle", + [sdma_state_s30_sw_clean_up_wait] = "s30_SwCleanUpWait", + [sdma_state_s40_hw_clean_up_wait] = "s40_HwCleanUpWait", + [sdma_state_s50_hw_halt_wait] = "s50_HwHaltWait", + [sdma_state_s60_idle_halt_wait] = "s60_IdleHaltWait", + [sdma_state_s80_hw_freeze] = "s80_HwFreeze", + [sdma_state_s82_freeze_sw_clean] = "s82_FreezeSwClean", + [sdma_state_s99_running] = "s99_Running", +}; + +static const char * const sdma_event_names[] = { + [sdma_event_e00_go_hw_down] = "e00_GoHwDown", + [sdma_event_e10_go_hw_start] = "e10_GoHwStart", + [sdma_event_e15_hw_halt_done] = "e15_HwHaltDone", + [sdma_event_e25_hw_clean_up_done] = "e25_HwCleanUpDone", + [sdma_event_e30_go_running] = "e30_GoRunning", + [sdma_event_e40_sw_cleaned] = "e40_SwCleaned", + [sdma_event_e50_hw_cleaned] = "e50_HwCleaned", + [sdma_event_e60_hw_halted] = "e60_HwHalted", + [sdma_event_e70_go_idle] = "e70_GoIdle", + [sdma_event_e80_hw_freeze] = "e80_HwFreeze", + [sdma_event_e81_hw_frozen] = "e81_HwFrozen", + [sdma_event_e82_hw_unfreeze] = "e82_HwUnfreeze", + [sdma_event_e85_link_down] = "e85_LinkDown", + [sdma_event_e90_sw_halted] = "e90_SwHalted", +}; + +static const struct sdma_set_state_action sdma_action_table[] = { + [sdma_state_s00_hw_down] = { + .go_s99_running_tofalse = 1, + .op_enable = 0, + .op_intenable = 0, + .op_halt = 0, + .op_cleanup = 0, + }, + [sdma_state_s10_hw_start_up_halt_wait] = { + .op_enable = 0, + .op_intenable = 0, + .op_halt = 1, + .op_cleanup = 0, + }, + [sdma_state_s15_hw_start_up_clean_wait] = { + .op_enable = 0, + .op_intenable = 1, + .op_halt = 0, + .op_cleanup = 1, + }, + [sdma_state_s20_idle] = { + .op_enable = 0, + .op_intenable = 1, + .op_halt = 0, + .op_cleanup = 0, + }, + [sdma_state_s30_sw_clean_up_wait] = { + .op_enable = 0, + .op_intenable = 0, + .op_halt = 0, + .op_cleanup = 0, + }, + [sdma_state_s40_hw_clean_up_wait] = { + .op_enable = 0, + .op_intenable = 0, + .op_halt = 0, + .op_cleanup = 1, + }, + [sdma_state_s50_hw_halt_wait] = { + .op_enable = 0, + .op_intenable = 0, + .op_halt = 0, + .op_cleanup = 0, + }, + [sdma_state_s60_idle_halt_wait] = { + .go_s99_running_tofalse = 1, + .op_enable = 0, + .op_intenable = 0, + .op_halt = 1, + .op_cleanup = 0, + }, + [sdma_state_s80_hw_freeze] = { + .op_enable = 0, + .op_intenable = 0, + .op_halt = 0, + .op_cleanup = 0, + }, + [sdma_state_s82_freeze_sw_clean] = { + .op_enable = 0, + .op_intenable = 0, + .op_halt = 0, + .op_cleanup = 0, + }, + [sdma_state_s99_running] = { + .op_enable = 1, + .op_intenable = 1, + .op_halt = 0, + .op_cleanup = 0, + .go_s99_running_totrue = 1, + }, +}; + +#define SDMA_TAIL_UPDATE_THRESH 0x1F + +/* declare all statics here rather than keep sorting */ +static void sdma_complete(struct kref *); +static void sdma_finalput(struct sdma_state *); +static void sdma_get(struct sdma_state *); +static void sdma_hw_clean_up_task(unsigned long); +static void sdma_put(struct sdma_state *); +static void sdma_set_state(struct sdma_engine *, enum sdma_states); +static void sdma_start_hw_clean_up(struct sdma_engine *); +static void sdma_start_sw_clean_up(struct sdma_engine *); +static void sdma_sw_clean_up_task(unsigned long); +static void sdma_sendctrl(struct sdma_engine *, unsigned); +static void init_sdma_regs(struct sdma_engine *, u32, uint); +static void sdma_process_event( + struct sdma_engine *sde, + enum sdma_events event); +static void __sdma_process_event( + struct sdma_engine *sde, + enum sdma_events event); +static void dump_sdma_state(struct sdma_engine *sde); +static void sdma_make_progress(struct sdma_engine *sde, u64 status); +static void sdma_desc_avail(struct sdma_engine *sde, unsigned avail); +static void sdma_flush_descq(struct sdma_engine *sde); + +/** + * sdma_state_name() - return state string from enum + * @state: state + */ +static const char *sdma_state_name(enum sdma_states state) +{ + return sdma_state_names[state]; +} + +static void sdma_get(struct sdma_state *ss) +{ + kref_get(&ss->kref); +} + +static void sdma_complete(struct kref *kref) +{ + struct sdma_state *ss = + container_of(kref, struct sdma_state, kref); + + complete(&ss->comp); +} + +static void sdma_put(struct sdma_state *ss) +{ + kref_put(&ss->kref, sdma_complete); +} + +static void sdma_finalput(struct sdma_state *ss) +{ + sdma_put(ss); + wait_for_completion(&ss->comp); +} + +static inline void write_sde_csr( + struct sdma_engine *sde, + u32 offset0, + u64 value) +{ + write_kctxt_csr(sde->dd, sde->this_idx, offset0, value); +} + +static inline u64 read_sde_csr( + struct sdma_engine *sde, + u32 offset0) +{ + return read_kctxt_csr(sde->dd, sde->this_idx, offset0); +} + +/* + * sdma_wait_for_packet_egress() - wait for the VL FIFO occupancy for + * sdma engine 'sde' to drop to 0. + */ +static void sdma_wait_for_packet_egress(struct sdma_engine *sde, + int pause) +{ + u64 off = 8 * sde->this_idx; + struct hfi1_devdata *dd = sde->dd; + int lcnt = 0; + + while (1) { + u64 reg = read_csr(dd, off + SEND_EGRESS_SEND_DMA_STATUS); + + reg &= SDMA_EGRESS_PACKET_OCCUPANCY_SMASK; + reg >>= SDMA_EGRESS_PACKET_OCCUPANCY_SHIFT; + if (reg == 0) + break; + if (lcnt++ > 100) { + dd_dev_err(dd, "%s: engine %u timeout waiting for packets to egress, remaining count %u\n", + __func__, sde->this_idx, (u32)reg); + break; + } + udelay(1); + } +} + +/* + * sdma_wait() - wait for packet egress to complete for all SDMA engines, + * and pause for credit return. + */ +void sdma_wait(struct hfi1_devdata *dd) +{ + int i; + + for (i = 0; i < dd->num_sdma; i++) { + struct sdma_engine *sde = &dd->per_sdma[i]; + + sdma_wait_for_packet_egress(sde, 0); + } +} + +static inline void sdma_set_desc_cnt(struct sdma_engine *sde, unsigned cnt) +{ + u64 reg; + + if (!(sde->dd->flags & HFI1_HAS_SDMA_TIMEOUT)) + return; + reg = cnt; + reg &= SD(DESC_CNT_CNT_MASK); + reg <<= SD(DESC_CNT_CNT_SHIFT); + write_sde_csr(sde, SD(DESC_CNT), reg); +} + +/* + * Complete all the sdma requests with a SDMA_TXREQ_S_ABORTED status + * + * Depending on timing there can be txreqs in two places: + * - in the descq ring + * - in the flush list + * + * To avoid ordering issues the descq ring needs to be flushed + * first followed by the flush list. + * + * This routine is called from two places + * - From a work queue item + * - Directly from the state machine just before setting the + * state to running + * + * Must be called with head_lock held + * + */ +static void sdma_flush(struct sdma_engine *sde) +{ + struct sdma_txreq *txp, *txp_next; + LIST_HEAD(flushlist); + + /* flush from head to tail */ + sdma_flush_descq(sde); + spin_lock(&sde->flushlist_lock); + /* copy flush list */ + list_for_each_entry_safe(txp, txp_next, &sde->flushlist, list) { + list_del_init(&txp->list); + list_add_tail(&txp->list, &flushlist); + } + spin_unlock(&sde->flushlist_lock); + /* flush from flush list */ + list_for_each_entry_safe(txp, txp_next, &flushlist, list) { + int drained = 0; + /* protect against complete modifying */ + struct iowait *wait = txp->wait; + + list_del_init(&txp->list); +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER + trace_hfi1_sdma_out_sn(sde, txp->sn); + if (WARN_ON_ONCE(sde->head_sn != txp->sn)) + dd_dev_err(sde->dd, "expected %llu got %llu\n", + sde->head_sn, txp->sn); + sde->head_sn++; +#endif + sdma_txclean(sde->dd, txp); + if (wait) + drained = atomic_dec_and_test(&wait->sdma_busy); + if (txp->complete) + (*txp->complete)(txp, SDMA_TXREQ_S_ABORTED, drained); + if (wait && drained) + iowait_drain_wakeup(wait); + } +} + +/* + * Fields a work request for flushing the descq ring + * and the flush list + * + * If the engine has been brought to running during + * the scheduling delay, the flush is ignored, assuming + * that the process of bringing the engine to running + * would have done this flush prior to going to running. + * + */ +static void sdma_field_flush(struct work_struct *work) +{ + unsigned long flags; + struct sdma_engine *sde = + container_of(work, struct sdma_engine, flush_worker); + + write_seqlock_irqsave(&sde->head_lock, flags); + if (!__sdma_running(sde)) + sdma_flush(sde); + write_sequnlock_irqrestore(&sde->head_lock, flags); +} + +static void sdma_err_halt_wait(struct work_struct *work) +{ + struct sdma_engine *sde = container_of(work, struct sdma_engine, + err_halt_worker); + u64 statuscsr; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(SDMA_ERR_HALT_TIMEOUT); + while (1) { + statuscsr = read_sde_csr(sde, SD(STATUS)); + statuscsr &= SD(STATUS_ENG_HALTED_SMASK); + if (statuscsr) + break; + if (time_after(jiffies, timeout)) { + dd_dev_err(sde->dd, + "SDMA engine %d - timeout waiting for engine to halt\n", + sde->this_idx); + /* + * Continue anyway. This could happen if there was + * an uncorrectable error in the wrong spot. + */ + break; + } + usleep_range(80, 120); + } + + sdma_process_event(sde, sdma_event_e15_hw_halt_done); +} + +static void sdma_start_err_halt_wait(struct sdma_engine *sde) +{ + schedule_work(&sde->err_halt_worker); +} + + +static void sdma_err_progress_check_schedule(struct sdma_engine *sde) +{ + if (!is_bx(sde->dd) && HFI1_CAP_IS_KSET(SDMA_AHG)) { + + unsigned index; + struct hfi1_devdata *dd = sde->dd; + + for (index = 0; index < dd->num_sdma; index++) { + struct sdma_engine *curr_sdma = &dd->per_sdma[index]; + + if (curr_sdma != sde) + curr_sdma->progress_check_head = + curr_sdma->descq_head; + } + dd_dev_err(sde->dd, + "SDMA engine %d - check scheduled\n", + sde->this_idx); + mod_timer(&sde->err_progress_check_timer, jiffies + 10); + } +} + +static void sdma_err_progress_check(unsigned long data) +{ + unsigned index; + struct sdma_engine *sde = (struct sdma_engine *)data; + + dd_dev_err(sde->dd, "SDE progress check event\n"); + for (index = 0; index < sde->dd->num_sdma; index++) { + struct sdma_engine *curr_sde = &sde->dd->per_sdma[index]; + unsigned long flags; + + /* check progress on each engine except the current one */ + if (curr_sde == sde) + continue; + /* + * We must lock interrupts when acquiring sde->lock, + * to avoid a deadlock if interrupt triggers and spins on + * the same lock on same CPU + */ + spin_lock_irqsave(&curr_sde->tail_lock, flags); + write_seqlock(&curr_sde->head_lock); + + /* skip non-running queues */ + if (curr_sde->state.current_state != sdma_state_s99_running) { + write_sequnlock(&curr_sde->head_lock); + spin_unlock_irqrestore(&curr_sde->tail_lock, flags); + continue; + } + + if ((curr_sde->descq_head != curr_sde->descq_tail) && + (curr_sde->descq_head == + curr_sde->progress_check_head)) + __sdma_process_event(curr_sde, + sdma_event_e90_sw_halted); + write_sequnlock(&curr_sde->head_lock); + spin_unlock_irqrestore(&curr_sde->tail_lock, flags); + } + schedule_work(&sde->err_halt_worker); +} + +static void sdma_hw_clean_up_task(unsigned long opaque) +{ + struct sdma_engine *sde = (struct sdma_engine *) opaque; + u64 statuscsr; + + while (1) { +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", + sde->this_idx, slashstrip(__FILE__), __LINE__, + __func__); +#endif + statuscsr = read_sde_csr(sde, SD(STATUS)); + statuscsr &= SD(STATUS_ENG_CLEANED_UP_SMASK); + if (statuscsr) + break; + udelay(10); + } + + sdma_process_event(sde, sdma_event_e25_hw_clean_up_done); +} + +static inline struct sdma_txreq *get_txhead(struct sdma_engine *sde) +{ + smp_read_barrier_depends(); /* see sdma_update_tail() */ + return sde->tx_ring[sde->tx_head & sde->sdma_mask]; +} + +/* + * flush ring for recovery + */ +static void sdma_flush_descq(struct sdma_engine *sde) +{ + u16 head, tail; + int progress = 0; + struct sdma_txreq *txp = get_txhead(sde); + + /* The reason for some of the complexity of this code is that + * not all descriptors have corresponding txps. So, we have to + * be able to skip over descs until we wander into the range of + * the next txp on the list. + */ + head = sde->descq_head & sde->sdma_mask; + tail = sde->descq_tail & sde->sdma_mask; + while (head != tail) { + /* advance head, wrap if needed */ + head = ++sde->descq_head & sde->sdma_mask; + /* if now past this txp's descs, do the callback */ + if (txp && txp->next_descq_idx == head) { + int drained = 0; + /* protect against complete modifying */ + struct iowait *wait = txp->wait; + + /* remove from list */ + sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL; + if (wait) + drained = atomic_dec_and_test(&wait->sdma_busy); +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER + trace_hfi1_sdma_out_sn(sde, txp->sn); + if (WARN_ON_ONCE(sde->head_sn != txp->sn)) + dd_dev_err(sde->dd, "expected %llu got %llu\n", + sde->head_sn, txp->sn); + sde->head_sn++; +#endif + sdma_txclean(sde->dd, txp); + trace_hfi1_sdma_progress(sde, head, tail, txp); + if (txp->complete) + (*txp->complete)( + txp, + SDMA_TXREQ_S_ABORTED, + drained); + if (wait && drained) + iowait_drain_wakeup(wait); + /* see if there is another txp */ + txp = get_txhead(sde); + } + progress++; + } + if (progress) + sdma_desc_avail(sde, sdma_descq_freecnt(sde)); +} + +static void sdma_sw_clean_up_task(unsigned long opaque) +{ + struct sdma_engine *sde = (struct sdma_engine *) opaque; + unsigned long flags; + + spin_lock_irqsave(&sde->tail_lock, flags); + write_seqlock(&sde->head_lock); + + /* + * At this point, the following should always be true: + * - We are halted, so no more descriptors are getting retired. + * - We are not running, so no one is submitting new work. + * - Only we can send the e40_sw_cleaned, so we can't start + * running again until we say so. So, the active list and + * descq are ours to play with. + */ + + + /* + * In the error clean up sequence, software clean must be called + * before the hardware clean so we can use the hardware head in + * the progress routine. A hardware clean or SPC unfreeze will + * reset the hardware head. + * + * Process all retired requests. The progress routine will use the + * latest physical hardware head - we are not running so speed does + * not matter. + */ + sdma_make_progress(sde, 0); + + sdma_flush(sde); + + /* + * Reset our notion of head and tail. + * Note that the HW registers have been reset via an earlier + * clean up. + */ + sde->descq_tail = 0; + sde->descq_head = 0; + sde->desc_avail = sdma_descq_freecnt(sde); + *sde->head_dma = 0; + + __sdma_process_event(sde, sdma_event_e40_sw_cleaned); + + write_sequnlock(&sde->head_lock); + spin_unlock_irqrestore(&sde->tail_lock, flags); +} + +static void sdma_sw_tear_down(struct sdma_engine *sde) +{ + struct sdma_state *ss = &sde->state; + + /* Releasing this reference means the state machine has stopped. */ + sdma_put(ss); + + /* stop waiting for all unfreeze events to complete */ + atomic_set(&sde->dd->sdma_unfreeze_count, -1); + wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); +} + +static void sdma_start_hw_clean_up(struct sdma_engine *sde) +{ + tasklet_hi_schedule(&sde->sdma_hw_clean_up_task); +} + +static void sdma_start_sw_clean_up(struct sdma_engine *sde) +{ + tasklet_hi_schedule(&sde->sdma_sw_clean_up_task); +} + +static void sdma_set_state(struct sdma_engine *sde, + enum sdma_states next_state) +{ + struct sdma_state *ss = &sde->state; + const struct sdma_set_state_action *action = sdma_action_table; + unsigned op = 0; + + trace_hfi1_sdma_state( + sde, + sdma_state_names[ss->current_state], + sdma_state_names[next_state]); + + /* debugging bookkeeping */ + ss->previous_state = ss->current_state; + ss->previous_op = ss->current_op; + ss->current_state = next_state; + + if (ss->previous_state != sdma_state_s99_running + && next_state == sdma_state_s99_running) + sdma_flush(sde); + + if (action[next_state].op_enable) + op |= SDMA_SENDCTRL_OP_ENABLE; + + if (action[next_state].op_intenable) + op |= SDMA_SENDCTRL_OP_INTENABLE; + + if (action[next_state].op_halt) + op |= SDMA_SENDCTRL_OP_HALT; + + if (action[next_state].op_cleanup) + op |= SDMA_SENDCTRL_OP_CLEANUP; + + if (action[next_state].go_s99_running_tofalse) + ss->go_s99_running = 0; + + if (action[next_state].go_s99_running_totrue) + ss->go_s99_running = 1; + + ss->current_op = op; + sdma_sendctrl(sde, ss->current_op); +} + +/** + * sdma_get_descq_cnt() - called when device probed + * + * Return a validated descq count. + * + * This is currently only used in the verbs initialization to build the tx + * list. + * + * This will probably be deleted in favor of a more scalable approach to + * alloc tx's. + * + */ +u16 sdma_get_descq_cnt(void) +{ + u16 count = sdma_descq_cnt; + + if (!count) + return SDMA_DESCQ_CNT; + /* count must be a power of 2 greater than 64 and less than + * 32768. Otherwise return default. + */ + if (!is_power_of_2(count)) + return SDMA_DESCQ_CNT; + if (count < 64 && count > 32768) + return SDMA_DESCQ_CNT; + return count; +} +/** + * sdma_select_engine_vl() - select sdma engine + * @dd: devdata + * @selector: a spreading factor + * @vl: this vl + * + * + * This function returns an engine based on the selector and a vl. The + * mapping fields are protected by RCU. + */ +struct sdma_engine *sdma_select_engine_vl( + struct hfi1_devdata *dd, + u32 selector, + u8 vl) +{ + struct sdma_vl_map *m; + struct sdma_map_elem *e; + struct sdma_engine *rval; + + if (WARN_ON(vl > 8)) + return NULL; + + rcu_read_lock(); + m = rcu_dereference(dd->sdma_map); + if (unlikely(!m)) { + rcu_read_unlock(); + return NULL; + } + e = m->map[vl & m->mask]; + rval = e->sde[selector & e->mask]; + rcu_read_unlock(); + + trace_hfi1_sdma_engine_select(dd, selector, vl, rval->this_idx); + return rval; +} + +/** + * sdma_select_engine_sc() - select sdma engine + * @dd: devdata + * @selector: a spreading factor + * @sc5: the 5 bit sc + * + * + * This function returns an engine based on the selector and an sc. + */ +struct sdma_engine *sdma_select_engine_sc( + struct hfi1_devdata *dd, + u32 selector, + u8 sc5) +{ + u8 vl = sc_to_vlt(dd, sc5); + + return sdma_select_engine_vl(dd, selector, vl); +} + +/* + * Free the indicated map struct + */ +static void sdma_map_free(struct sdma_vl_map *m) +{ + int i; + + for (i = 0; m && i < m->actual_vls; i++) + kfree(m->map[i]); + kfree(m); +} + +/* + * Handle RCU callback + */ +static void sdma_map_rcu_callback(struct rcu_head *list) +{ + struct sdma_vl_map *m = container_of(list, struct sdma_vl_map, list); + + sdma_map_free(m); +} + +/** + * sdma_map_init - called when # vls change + * @dd: hfi1_devdata + * @port: port number + * @num_vls: number of vls + * @vl_engines: per vl engine mapping (optional) + * + * This routine changes the mapping based on the number of vls. + * + * vl_engines is used to specify a non-uniform vl/engine loading. NULL + * implies auto computing the loading and giving each VLs a uniform + * distribution of engines per VL. + * + * The auto algorithm computes the sde_per_vl and the number of extra + * engines. Any extra engines are added from the last VL on down. + * + * rcu locking is used here to control access to the mapping fields. + * + * If either the num_vls or num_sdma are non-power of 2, the array sizes + * in the struct sdma_vl_map and the struct sdma_map_elem are rounded + * up to the next highest power of 2 and the first entry is reused + * in a round robin fashion. + * + * If an error occurs the map change is not done and the mapping is + * not changed. + * + */ +int sdma_map_init(struct hfi1_devdata *dd, u8 port, u8 num_vls, u8 *vl_engines) +{ + int i, j; + int extra, sde_per_vl; + int engine = 0; + u8 lvl_engines[OPA_MAX_VLS]; + struct sdma_vl_map *oldmap, *newmap; + + if (!(dd->flags & HFI1_HAS_SEND_DMA)) + return 0; + + if (!vl_engines) { + /* truncate divide */ + sde_per_vl = dd->num_sdma / num_vls; + /* extras */ + extra = dd->num_sdma % num_vls; + vl_engines = lvl_engines; + /* add extras from last vl down */ + for (i = num_vls - 1; i >= 0; i--, extra--) + vl_engines[i] = sde_per_vl + (extra > 0 ? 1 : 0); + } + /* build new map */ + newmap = kzalloc( + sizeof(struct sdma_vl_map) + + roundup_pow_of_two(num_vls) * + sizeof(struct sdma_map_elem *), + GFP_KERNEL); + if (!newmap) + goto bail; + newmap->actual_vls = num_vls; + newmap->vls = roundup_pow_of_two(num_vls); + newmap->mask = (1 << ilog2(newmap->vls)) - 1; + for (i = 0; i < newmap->vls; i++) { + /* save for wrap around */ + int first_engine = engine; + + if (i < newmap->actual_vls) { + int sz = roundup_pow_of_two(vl_engines[i]); + + /* only allocate once */ + newmap->map[i] = kzalloc( + sizeof(struct sdma_map_elem) + + sz * sizeof(struct sdma_engine *), + GFP_KERNEL); + if (!newmap->map[i]) + goto bail; + newmap->map[i]->mask = (1 << ilog2(sz)) - 1; + /* assign engines */ + for (j = 0; j < sz; j++) { + newmap->map[i]->sde[j] = + &dd->per_sdma[engine]; + if (++engine >= first_engine + vl_engines[i]) + /* wrap back to first engine */ + engine = first_engine; + } + } else { + /* just re-use entry without allocating */ + newmap->map[i] = newmap->map[i % num_vls]; + } + engine = first_engine + vl_engines[i]; + } + /* newmap in hand, save old map */ + spin_lock_irq(&dd->sde_map_lock); + oldmap = rcu_dereference_protected(dd->sdma_map, + lockdep_is_held(&dd->sde_map_lock)); + + /* publish newmap */ + rcu_assign_pointer(dd->sdma_map, newmap); + + spin_unlock_irq(&dd->sde_map_lock); + /* success, free any old map after grace period */ + if (oldmap) + call_rcu(&oldmap->list, sdma_map_rcu_callback); + return 0; +bail: + /* free any partial allocation */ + sdma_map_free(newmap); + return -ENOMEM; +} + +/* + * Clean up allocated memory. + * + * This routine is can be called regardless of the success of sdma_init() + * + */ +static void sdma_clean(struct hfi1_devdata *dd, size_t num_engines) +{ + size_t i; + struct sdma_engine *sde; + + if (dd->sdma_pad_dma) { + dma_free_coherent(&dd->pcidev->dev, 4, + (void *)dd->sdma_pad_dma, + dd->sdma_pad_phys); + dd->sdma_pad_dma = NULL; + dd->sdma_pad_phys = 0; + } + if (dd->sdma_heads_dma) { + dma_free_coherent(&dd->pcidev->dev, dd->sdma_heads_size, + (void *)dd->sdma_heads_dma, + dd->sdma_heads_phys); + dd->sdma_heads_dma = NULL; + dd->sdma_heads_phys = 0; + } + for (i = 0; dd->per_sdma && i < num_engines; ++i) { + sde = &dd->per_sdma[i]; + + sde->head_dma = NULL; + sde->head_phys = 0; + + if (sde->descq) { + dma_free_coherent( + &dd->pcidev->dev, + sde->descq_cnt * sizeof(u64[2]), + sde->descq, + sde->descq_phys + ); + sde->descq = NULL; + sde->descq_phys = 0; + } + if (is_vmalloc_addr(sde->tx_ring)) + vfree(sde->tx_ring); + else + kfree(sde->tx_ring); + sde->tx_ring = NULL; + } + spin_lock_irq(&dd->sde_map_lock); + kfree(rcu_access_pointer(dd->sdma_map)); + RCU_INIT_POINTER(dd->sdma_map, NULL); + spin_unlock_irq(&dd->sde_map_lock); + synchronize_rcu(); + kfree(dd->per_sdma); + dd->per_sdma = NULL; +} + +/** + * sdma_init() - called when device probed + * @dd: hfi1_devdata + * @port: port number (currently only zero) + * + * sdma_init initializes the specified number of engines. + * + * The code initializes each sde, its csrs. Interrupts + * are not required to be enabled. + * + * Returns: + * 0 - success, -errno on failure + */ +int sdma_init(struct hfi1_devdata *dd, u8 port) +{ + unsigned this_idx; + struct sdma_engine *sde; + u16 descq_cnt; + void *curr_head; + struct hfi1_pportdata *ppd = dd->pport + port; + u32 per_sdma_credits; + uint idle_cnt = sdma_idle_cnt; + size_t num_engines = dd->chip_sdma_engines; + + if (!HFI1_CAP_IS_KSET(SDMA)) { + HFI1_CAP_CLEAR(SDMA_AHG); + return 0; + } + if (mod_num_sdma && + /* can't exceed chip support */ + mod_num_sdma <= dd->chip_sdma_engines && + /* count must be >= vls */ + mod_num_sdma >= num_vls) + num_engines = mod_num_sdma; + + dd_dev_info(dd, "SDMA mod_num_sdma: %u\n", mod_num_sdma); + dd_dev_info(dd, "SDMA chip_sdma_engines: %u\n", dd->chip_sdma_engines); + dd_dev_info(dd, "SDMA chip_sdma_mem_size: %u\n", + dd->chip_sdma_mem_size); + + per_sdma_credits = + dd->chip_sdma_mem_size/(num_engines * SDMA_BLOCK_SIZE); + + /* set up freeze waitqueue */ + init_waitqueue_head(&dd->sdma_unfreeze_wq); + atomic_set(&dd->sdma_unfreeze_count, 0); + + descq_cnt = sdma_get_descq_cnt(); + dd_dev_info(dd, "SDMA engines %zu descq_cnt %u\n", + num_engines, descq_cnt); + + /* alloc memory for array of send engines */ + dd->per_sdma = kcalloc(num_engines, sizeof(*dd->per_sdma), GFP_KERNEL); + if (!dd->per_sdma) + return -ENOMEM; + + idle_cnt = ns_to_cclock(dd, idle_cnt); + /* Allocate memory for SendDMA descriptor FIFOs */ + for (this_idx = 0; this_idx < num_engines; ++this_idx) { + sde = &dd->per_sdma[this_idx]; + sde->dd = dd; + sde->ppd = ppd; + sde->this_idx = this_idx; + sde->descq_cnt = descq_cnt; + sde->desc_avail = sdma_descq_freecnt(sde); + sde->sdma_shift = ilog2(descq_cnt); + sde->sdma_mask = (1 << sde->sdma_shift) - 1; + sde->descq_full_count = 0; + + /* Create a mask for all 3 chip interrupt sources */ + sde->imask = (u64)1 << (0*TXE_NUM_SDMA_ENGINES + this_idx) + | (u64)1 << (1*TXE_NUM_SDMA_ENGINES + this_idx) + | (u64)1 << (2*TXE_NUM_SDMA_ENGINES + this_idx); + /* Create a mask specifically for sdma_idle */ + sde->idle_mask = + (u64)1 << (2*TXE_NUM_SDMA_ENGINES + this_idx); + /* Create a mask specifically for sdma_progress */ + sde->progress_mask = + (u64)1 << (TXE_NUM_SDMA_ENGINES + this_idx); + spin_lock_init(&sde->tail_lock); + seqlock_init(&sde->head_lock); + spin_lock_init(&sde->senddmactrl_lock); + spin_lock_init(&sde->flushlist_lock); + /* insure there is always a zero bit */ + sde->ahg_bits = 0xfffffffe00000000ULL; + + sdma_set_state(sde, sdma_state_s00_hw_down); + + /* set up reference counting */ + kref_init(&sde->state.kref); + init_completion(&sde->state.comp); + + INIT_LIST_HEAD(&sde->flushlist); + INIT_LIST_HEAD(&sde->dmawait); + + sde->tail_csr = + get_kctxt_csr_addr(dd, this_idx, SD(TAIL)); + + if (idle_cnt) + dd->default_desc1 = + SDMA_DESC1_HEAD_TO_HOST_FLAG; + else + dd->default_desc1 = + SDMA_DESC1_INT_REQ_FLAG; + + tasklet_init(&sde->sdma_hw_clean_up_task, sdma_hw_clean_up_task, + (unsigned long)sde); + + tasklet_init(&sde->sdma_sw_clean_up_task, sdma_sw_clean_up_task, + (unsigned long)sde); + INIT_WORK(&sde->err_halt_worker, sdma_err_halt_wait); + INIT_WORK(&sde->flush_worker, sdma_field_flush); + + sde->progress_check_head = 0; + + init_timer(&sde->err_progress_check_timer); + sde->err_progress_check_timer.function = + sdma_err_progress_check; + sde->err_progress_check_timer.data = (unsigned long)sde; + + sde->descq = dma_zalloc_coherent( + &dd->pcidev->dev, + descq_cnt * sizeof(u64[2]), + &sde->descq_phys, + GFP_KERNEL + ); + if (!sde->descq) + goto bail; + sde->tx_ring = + kcalloc(descq_cnt, sizeof(struct sdma_txreq *), + GFP_KERNEL); + if (!sde->tx_ring) + sde->tx_ring = + vzalloc( + sizeof(struct sdma_txreq *) * + descq_cnt); + if (!sde->tx_ring) + goto bail; + } + + dd->sdma_heads_size = L1_CACHE_BYTES * num_engines; + /* Allocate memory for DMA of head registers to memory */ + dd->sdma_heads_dma = dma_zalloc_coherent( + &dd->pcidev->dev, + dd->sdma_heads_size, + &dd->sdma_heads_phys, + GFP_KERNEL + ); + if (!dd->sdma_heads_dma) { + dd_dev_err(dd, "failed to allocate SendDMA head memory\n"); + goto bail; + } + + /* Allocate memory for pad */ + dd->sdma_pad_dma = dma_zalloc_coherent( + &dd->pcidev->dev, + sizeof(u32), + &dd->sdma_pad_phys, + GFP_KERNEL + ); + if (!dd->sdma_pad_dma) { + dd_dev_err(dd, "failed to allocate SendDMA pad memory\n"); + goto bail; + } + + /* assign each engine to different cacheline and init registers */ + curr_head = (void *)dd->sdma_heads_dma; + for (this_idx = 0; this_idx < num_engines; ++this_idx) { + unsigned long phys_offset; + + sde = &dd->per_sdma[this_idx]; + + sde->head_dma = curr_head; + curr_head += L1_CACHE_BYTES; + phys_offset = (unsigned long)sde->head_dma - + (unsigned long)dd->sdma_heads_dma; + sde->head_phys = dd->sdma_heads_phys + phys_offset; + init_sdma_regs(sde, per_sdma_credits, idle_cnt); + } + dd->flags |= HFI1_HAS_SEND_DMA; + dd->flags |= idle_cnt ? HFI1_HAS_SDMA_TIMEOUT : 0; + dd->num_sdma = num_engines; + if (sdma_map_init(dd, port, ppd->vls_operational, NULL)) + goto bail; + dd_dev_info(dd, "SDMA num_sdma: %u\n", dd->num_sdma); + return 0; + +bail: + sdma_clean(dd, num_engines); + return -ENOMEM; +} + +/** + * sdma_all_running() - called when the link goes up + * @dd: hfi1_devdata + * + * This routine moves all engines to the running state. + */ +void sdma_all_running(struct hfi1_devdata *dd) +{ + struct sdma_engine *sde; + unsigned int i; + + /* move all engines to running */ + for (i = 0; i < dd->num_sdma; ++i) { + sde = &dd->per_sdma[i]; + sdma_process_event(sde, sdma_event_e30_go_running); + } +} + +/** + * sdma_all_idle() - called when the link goes down + * @dd: hfi1_devdata + * + * This routine moves all engines to the idle state. + */ +void sdma_all_idle(struct hfi1_devdata *dd) +{ + struct sdma_engine *sde; + unsigned int i; + + /* idle all engines */ + for (i = 0; i < dd->num_sdma; ++i) { + sde = &dd->per_sdma[i]; + sdma_process_event(sde, sdma_event_e70_go_idle); + } +} + +/** + * sdma_start() - called to kick off state processing for all engines + * @dd: hfi1_devdata + * + * This routine is for kicking off the state processing for all required + * sdma engines. Interrupts need to be working at this point. + * + */ +void sdma_start(struct hfi1_devdata *dd) +{ + unsigned i; + struct sdma_engine *sde; + + /* kick off the engines state processing */ + for (i = 0; i < dd->num_sdma; ++i) { + sde = &dd->per_sdma[i]; + sdma_process_event(sde, sdma_event_e10_go_hw_start); + } +} + +/** + * sdma_exit() - used when module is removed + * @dd: hfi1_devdata + */ +void sdma_exit(struct hfi1_devdata *dd) +{ + unsigned this_idx; + struct sdma_engine *sde; + + for (this_idx = 0; dd->per_sdma && this_idx < dd->num_sdma; + ++this_idx) { + + sde = &dd->per_sdma[this_idx]; + if (!list_empty(&sde->dmawait)) + dd_dev_err(dd, "sde %u: dmawait list not empty!\n", + sde->this_idx); + sdma_process_event(sde, sdma_event_e00_go_hw_down); + + del_timer_sync(&sde->err_progress_check_timer); + + /* + * This waits for the state machine to exit so it is not + * necessary to kill the sdma_sw_clean_up_task to make sure + * it is not running. + */ + sdma_finalput(&sde->state); + } + sdma_clean(dd, dd->num_sdma); +} + +/* + * unmap the indicated descriptor + */ +static inline void sdma_unmap_desc( + struct hfi1_devdata *dd, + struct sdma_desc *descp) +{ + switch (sdma_mapping_type(descp)) { + case SDMA_MAP_SINGLE: + dma_unmap_single( + &dd->pcidev->dev, + sdma_mapping_addr(descp), + sdma_mapping_len(descp), + DMA_TO_DEVICE); + break; + case SDMA_MAP_PAGE: + dma_unmap_page( + &dd->pcidev->dev, + sdma_mapping_addr(descp), + sdma_mapping_len(descp), + DMA_TO_DEVICE); + break; + } +} + +/* + * return the mode as indicated by the first + * descriptor in the tx. + */ +static inline u8 ahg_mode(struct sdma_txreq *tx) +{ + return (tx->descp[0].qw[1] & SDMA_DESC1_HEADER_MODE_SMASK) + >> SDMA_DESC1_HEADER_MODE_SHIFT; +} + +/** + * sdma_txclean() - clean tx of mappings, descp *kmalloc's + * @dd: hfi1_devdata for unmapping + * @tx: tx request to clean + * + * This is used in the progress routine to clean the tx or + * by the ULP to toss an in-process tx build. + * + * The code can be called multiple times without issue. + * + */ +void sdma_txclean( + struct hfi1_devdata *dd, + struct sdma_txreq *tx) +{ + u16 i; + + if (tx->num_desc) { + u8 skip = 0, mode = ahg_mode(tx); + + /* unmap first */ + sdma_unmap_desc(dd, &tx->descp[0]); + /* determine number of AHG descriptors to skip */ + if (mode > SDMA_AHG_APPLY_UPDATE1) + skip = mode >> 1; + for (i = 1 + skip; i < tx->num_desc; i++) + sdma_unmap_desc(dd, &tx->descp[i]); + tx->num_desc = 0; + } + kfree(tx->coalesce_buf); + tx->coalesce_buf = NULL; + /* kmalloc'ed descp */ + if (unlikely(tx->desc_limit > ARRAY_SIZE(tx->descs))) { + tx->desc_limit = ARRAY_SIZE(tx->descs); + kfree(tx->descp); + } +} + +static inline u16 sdma_gethead(struct sdma_engine *sde) +{ + struct hfi1_devdata *dd = sde->dd; + int use_dmahead; + u16 hwhead; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", + sde->this_idx, slashstrip(__FILE__), __LINE__, __func__); +#endif + +retry: + use_dmahead = HFI1_CAP_IS_KSET(USE_SDMA_HEAD) && __sdma_running(sde) && + (dd->flags & HFI1_HAS_SDMA_TIMEOUT); + hwhead = use_dmahead ? + (u16) le64_to_cpu(*sde->head_dma) : + (u16) read_sde_csr(sde, SD(HEAD)); + + if (unlikely(HFI1_CAP_IS_KSET(SDMA_HEAD_CHECK))) { + u16 cnt; + u16 swtail; + u16 swhead; + int sane; + + swhead = sde->descq_head & sde->sdma_mask; + /* this code is really bad for cache line trading */ + swtail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask; + cnt = sde->descq_cnt; + + if (swhead < swtail) + /* not wrapped */ + sane = (hwhead >= swhead) & (hwhead <= swtail); + else if (swhead > swtail) + /* wrapped around */ + sane = ((hwhead >= swhead) && (hwhead < cnt)) || + (hwhead <= swtail); + else + /* empty */ + sane = (hwhead == swhead); + + if (unlikely(!sane)) { + dd_dev_err(dd, "SDMA(%u) bad head (%s) hwhd=%hu swhd=%hu swtl=%hu cnt=%hu\n", + sde->this_idx, + use_dmahead ? "dma" : "kreg", + hwhead, swhead, swtail, cnt); + if (use_dmahead) { + /* try one more time, using csr */ + use_dmahead = 0; + goto retry; + } + /* proceed as if no progress */ + hwhead = swhead; + } + } + return hwhead; +} + +/* + * This is called when there are send DMA descriptors that might be + * available. + * + * This is called with head_lock held. + */ +static void sdma_desc_avail(struct sdma_engine *sde, unsigned avail) +{ + struct iowait *wait, *nw; + struct iowait *waits[SDMA_WAIT_BATCH_SIZE]; + unsigned i, n = 0, seq; + struct sdma_txreq *stx; + struct hfi1_ibdev *dev = &sde->dd->verbs_dev; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", sde->this_idx, + slashstrip(__FILE__), __LINE__, __func__); + dd_dev_err(sde->dd, "avail: %u\n", avail); +#endif + + do { + seq = read_seqbegin(&dev->iowait_lock); + if (!list_empty(&sde->dmawait)) { + /* at least one item */ + write_seqlock(&dev->iowait_lock); + /* Harvest waiters wanting DMA descriptors */ + list_for_each_entry_safe( + wait, + nw, + &sde->dmawait, + list) { + u16 num_desc = 0; + + if (!wait->wakeup) + continue; + if (n == ARRAY_SIZE(waits)) + break; + if (!list_empty(&wait->tx_head)) { + stx = list_first_entry( + &wait->tx_head, + struct sdma_txreq, + list); + num_desc = stx->num_desc; + } + if (num_desc > avail) + break; + avail -= num_desc; + list_del_init(&wait->list); + waits[n++] = wait; + } + write_sequnlock(&dev->iowait_lock); + break; + } + } while (read_seqretry(&dev->iowait_lock, seq)); + + for (i = 0; i < n; i++) + waits[i]->wakeup(waits[i], SDMA_AVAIL_REASON); +} + +/* head_lock must be held */ +static void sdma_make_progress(struct sdma_engine *sde, u64 status) +{ + struct sdma_txreq *txp = NULL; + int progress = 0; + u16 hwhead, swhead, swtail; + int idle_check_done = 0; + + hwhead = sdma_gethead(sde); + + /* The reason for some of the complexity of this code is that + * not all descriptors have corresponding txps. So, we have to + * be able to skip over descs until we wander into the range of + * the next txp on the list. + */ + +retry: + txp = get_txhead(sde); + swhead = sde->descq_head & sde->sdma_mask; + trace_hfi1_sdma_progress(sde, hwhead, swhead, txp); + while (swhead != hwhead) { + /* advance head, wrap if needed */ + swhead = ++sde->descq_head & sde->sdma_mask; + + /* if now past this txp's descs, do the callback */ + if (txp && txp->next_descq_idx == swhead) { + int drained = 0; + /* protect against complete modifying */ + struct iowait *wait = txp->wait; + + /* remove from list */ + sde->tx_ring[sde->tx_head++ & sde->sdma_mask] = NULL; + if (wait) + drained = atomic_dec_and_test(&wait->sdma_busy); +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER + trace_hfi1_sdma_out_sn(sde, txp->sn); + if (WARN_ON_ONCE(sde->head_sn != txp->sn)) + dd_dev_err(sde->dd, "expected %llu got %llu\n", + sde->head_sn, txp->sn); + sde->head_sn++; +#endif + sdma_txclean(sde->dd, txp); + if (txp->complete) + (*txp->complete)( + txp, + SDMA_TXREQ_S_OK, + drained); + if (wait && drained) + iowait_drain_wakeup(wait); + /* see if there is another txp */ + txp = get_txhead(sde); + } + trace_hfi1_sdma_progress(sde, hwhead, swhead, txp); + progress++; + } + + /* + * The SDMA idle interrupt is not guaranteed to be ordered with respect + * to updates to the the dma_head location in host memory. The head + * value read might not be fully up to date. If there are pending + * descriptors and the SDMA idle interrupt fired then read from the + * CSR SDMA head instead to get the latest value from the hardware. + * The hardware SDMA head should be read at most once in this invocation + * of sdma_make_progress(..) which is ensured by idle_check_done flag + */ + if ((status & sde->idle_mask) && !idle_check_done) { + swtail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask; + if (swtail != hwhead) { + hwhead = (u16)read_sde_csr(sde, SD(HEAD)); + idle_check_done = 1; + goto retry; + } + } + + sde->last_status = status; + if (progress) + sdma_desc_avail(sde, sdma_descq_freecnt(sde)); +} + +/* + * sdma_engine_interrupt() - interrupt handler for engine + * @sde: sdma engine + * @status: sdma interrupt reason + * + * Status is a mask of the 3 possible interrupts for this engine. It will + * contain bits _only_ for this SDMA engine. It will contain at least one + * bit, it may contain more. + */ +void sdma_engine_interrupt(struct sdma_engine *sde, u64 status) +{ + trace_hfi1_sdma_engine_interrupt(sde, status); + write_seqlock(&sde->head_lock); + sdma_set_desc_cnt(sde, sde->descq_cnt / 2); + sdma_make_progress(sde, status); + write_sequnlock(&sde->head_lock); +} + +/** + * sdma_engine_error() - error handler for engine + * @sde: sdma engine + * @status: sdma interrupt reason + */ +void sdma_engine_error(struct sdma_engine *sde, u64 status) +{ + unsigned long flags; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) error status 0x%llx state %s\n", + sde->this_idx, + (unsigned long long)status, + sdma_state_names[sde->state.current_state]); +#endif + spin_lock_irqsave(&sde->tail_lock, flags); + write_seqlock(&sde->head_lock); + if (status & ALL_SDMA_ENG_HALT_ERRS) + __sdma_process_event(sde, sdma_event_e60_hw_halted); + if (status & ~SD(ENG_ERR_STATUS_SDMA_HALT_ERR_SMASK)) { + dd_dev_err(sde->dd, + "SDMA (%u) engine error: 0x%llx state %s\n", + sde->this_idx, + (unsigned long long)status, + sdma_state_names[sde->state.current_state]); + dump_sdma_state(sde); + } + write_sequnlock(&sde->head_lock); + spin_unlock_irqrestore(&sde->tail_lock, flags); +} + +static void sdma_sendctrl(struct sdma_engine *sde, unsigned op) +{ + u64 set_senddmactrl = 0; + u64 clr_senddmactrl = 0; + unsigned long flags; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) senddmactrl E=%d I=%d H=%d C=%d\n", + sde->this_idx, + (op & SDMA_SENDCTRL_OP_ENABLE) ? 1 : 0, + (op & SDMA_SENDCTRL_OP_INTENABLE) ? 1 : 0, + (op & SDMA_SENDCTRL_OP_HALT) ? 1 : 0, + (op & SDMA_SENDCTRL_OP_CLEANUP) ? 1 : 0); +#endif + + if (op & SDMA_SENDCTRL_OP_ENABLE) + set_senddmactrl |= SD(CTRL_SDMA_ENABLE_SMASK); + else + clr_senddmactrl |= SD(CTRL_SDMA_ENABLE_SMASK); + + if (op & SDMA_SENDCTRL_OP_INTENABLE) + set_senddmactrl |= SD(CTRL_SDMA_INT_ENABLE_SMASK); + else + clr_senddmactrl |= SD(CTRL_SDMA_INT_ENABLE_SMASK); + + if (op & SDMA_SENDCTRL_OP_HALT) + set_senddmactrl |= SD(CTRL_SDMA_HALT_SMASK); + else + clr_senddmactrl |= SD(CTRL_SDMA_HALT_SMASK); + + spin_lock_irqsave(&sde->senddmactrl_lock, flags); + + sde->p_senddmactrl |= set_senddmactrl; + sde->p_senddmactrl &= ~clr_senddmactrl; + + if (op & SDMA_SENDCTRL_OP_CLEANUP) + write_sde_csr(sde, SD(CTRL), + sde->p_senddmactrl | + SD(CTRL_SDMA_CLEANUP_SMASK)); + else + write_sde_csr(sde, SD(CTRL), sde->p_senddmactrl); + + spin_unlock_irqrestore(&sde->senddmactrl_lock, flags); + +#ifdef CONFIG_SDMA_VERBOSITY + sdma_dumpstate(sde); +#endif +} + +static void sdma_setlengen(struct sdma_engine *sde) +{ +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", + sde->this_idx, slashstrip(__FILE__), __LINE__, __func__); +#endif + + /* + * Set SendDmaLenGen and clear-then-set the MSB of the generation + * count to enable generation checking and load the internal + * generation counter. + */ + write_sde_csr(sde, SD(LEN_GEN), + (sde->descq_cnt/64) << SD(LEN_GEN_LENGTH_SHIFT) + ); + write_sde_csr(sde, SD(LEN_GEN), + ((sde->descq_cnt/64) << SD(LEN_GEN_LENGTH_SHIFT)) + | (4ULL << SD(LEN_GEN_GENERATION_SHIFT)) + ); +} + +static inline void sdma_update_tail(struct sdma_engine *sde, u16 tail) +{ + /* Commit writes to memory and advance the tail on the chip */ + smp_wmb(); /* see get_txhead() */ + writeq(tail, sde->tail_csr); +} + +/* + * This is called when changing to state s10_hw_start_up_halt_wait as + * a result of send buffer errors or send DMA descriptor errors. + */ +static void sdma_hw_start_up(struct sdma_engine *sde) +{ + u64 reg; + +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) %s:%d %s()\n", + sde->this_idx, slashstrip(__FILE__), __LINE__, __func__); +#endif + + sdma_setlengen(sde); + sdma_update_tail(sde, 0); /* Set SendDmaTail */ + *sde->head_dma = 0; + + reg = SD(ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_MASK) << + SD(ENG_ERR_CLEAR_SDMA_HEADER_REQUEST_FIFO_UNC_ERR_SHIFT); + write_sde_csr(sde, SD(ENG_ERR_CLEAR), reg); +} + +#define CLEAR_STATIC_RATE_CONTROL_SMASK(r) \ +(r &= ~SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) + +#define SET_STATIC_RATE_CONTROL_SMASK(r) \ +(r |= SEND_DMA_CHECK_ENABLE_DISALLOW_PBC_STATIC_RATE_CONTROL_SMASK) +/* + * set_sdma_integrity + * + * Set the SEND_DMA_CHECK_ENABLE register for send DMA engine 'sde'. + */ +static void set_sdma_integrity(struct sdma_engine *sde) +{ + struct hfi1_devdata *dd = sde->dd; + u64 reg; + + if (unlikely(HFI1_CAP_IS_KSET(NO_INTEGRITY))) + return; + + reg = hfi1_pkt_base_sdma_integrity(dd); + + if (HFI1_CAP_IS_KSET(STATIC_RATE_CTRL)) + CLEAR_STATIC_RATE_CONTROL_SMASK(reg); + else + SET_STATIC_RATE_CONTROL_SMASK(reg); + + write_sde_csr(sde, SD(CHECK_ENABLE), reg); +} + + +static void init_sdma_regs( + struct sdma_engine *sde, + u32 credits, + uint idle_cnt) +{ + u8 opval, opmask; +#ifdef CONFIG_SDMA_VERBOSITY + struct hfi1_devdata *dd = sde->dd; + + dd_dev_err(dd, "CONFIG SDMA(%u) %s:%d %s()\n", + sde->this_idx, slashstrip(__FILE__), __LINE__, __func__); +#endif + + write_sde_csr(sde, SD(BASE_ADDR), sde->descq_phys); + sdma_setlengen(sde); + sdma_update_tail(sde, 0); /* Set SendDmaTail */ + write_sde_csr(sde, SD(RELOAD_CNT), idle_cnt); + write_sde_csr(sde, SD(DESC_CNT), 0); + write_sde_csr(sde, SD(HEAD_ADDR), sde->head_phys); + write_sde_csr(sde, SD(MEMORY), + ((u64)credits << + SD(MEMORY_SDMA_MEMORY_CNT_SHIFT)) | + ((u64)(credits * sde->this_idx) << + SD(MEMORY_SDMA_MEMORY_INDEX_SHIFT))); + write_sde_csr(sde, SD(ENG_ERR_MASK), ~0ull); + set_sdma_integrity(sde); + opmask = OPCODE_CHECK_MASK_DISABLED; + opval = OPCODE_CHECK_VAL_DISABLED; + write_sde_csr(sde, SD(CHECK_OPCODE), + (opmask << SEND_CTXT_CHECK_OPCODE_MASK_SHIFT) | + (opval << SEND_CTXT_CHECK_OPCODE_VALUE_SHIFT)); +} + +#ifdef CONFIG_SDMA_VERBOSITY + +#define sdma_dumpstate_helper0(reg) do { \ + csr = read_csr(sde->dd, reg); \ + dd_dev_err(sde->dd, "%36s 0x%016llx\n", #reg, csr); \ + } while (0) + +#define sdma_dumpstate_helper(reg) do { \ + csr = read_sde_csr(sde, reg); \ + dd_dev_err(sde->dd, "%36s[%02u] 0x%016llx\n", \ + #reg, sde->this_idx, csr); \ + } while (0) + +#define sdma_dumpstate_helper2(reg) do { \ + csr = read_csr(sde->dd, reg + (8 * i)); \ + dd_dev_err(sde->dd, "%33s_%02u 0x%016llx\n", \ + #reg, i, csr); \ + } while (0) + +void sdma_dumpstate(struct sdma_engine *sde) +{ + u64 csr; + unsigned i; + + sdma_dumpstate_helper(SD(CTRL)); + sdma_dumpstate_helper(SD(STATUS)); + sdma_dumpstate_helper0(SD(ERR_STATUS)); + sdma_dumpstate_helper0(SD(ERR_MASK)); + sdma_dumpstate_helper(SD(ENG_ERR_STATUS)); + sdma_dumpstate_helper(SD(ENG_ERR_MASK)); + + for (i = 0; i < CCE_NUM_INT_CSRS; ++i) { + sdma_dumpstate_helper2(CCE_INT_STATUS)); + sdma_dumpstate_helper2(CCE_INT_MASK); + sdma_dumpstate_helper2(CCE_INT_BLOCKED); + } + + sdma_dumpstate_helper(SD(TAIL)); + sdma_dumpstate_helper(SD(HEAD)); + sdma_dumpstate_helper(SD(PRIORITY_THLD)); + sdma_dumpstate_helper(SD(IDLE_CNT); + sdma_dumpstate_helper(SD(RELOAD_CNT)); + sdma_dumpstate_helper(SD(DESC_CNT)); + sdma_dumpstate_helper(SD(DESC_FETCHED_CNT)); + sdma_dumpstate_helper(SD(MEMORY)); + sdma_dumpstate_helper0(SD(ENGINES)); + sdma_dumpstate_helper0(SD(MEM_SIZE)); + /* sdma_dumpstate_helper(SEND_EGRESS_SEND_DMA_STATUS); */ + sdma_dumpstate_helper(SD(BASE_ADDR)); + sdma_dumpstate_helper(SD(LEN_GEN)); + sdma_dumpstate_helper(SD(HEAD_ADDR)); + sdma_dumpstate_helper(SD(CHECK_ENABLE)); + sdma_dumpstate_helper(SD(CHECK_VL)); + sdma_dumpstate_helper(SD(CHECK_JOB_KEY)); + sdma_dumpstate_helper(SD(CHECK_PARTITION_KEY)); + sdma_dumpstate_helper(SD(CHECK_SLID)); + sdma_dumpstate_helper(SD(CHECK_OPCODE)); +} +#endif + +static void dump_sdma_state(struct sdma_engine *sde) +{ + struct hw_sdma_desc *descq; + struct hw_sdma_desc *descqp; + u64 desc[2]; + u64 addr; + u8 gen; + u16 len; + u16 head, tail, cnt; + + head = sde->descq_head & sde->sdma_mask; + tail = sde->descq_tail & sde->sdma_mask; + cnt = sdma_descq_freecnt(sde); + descq = sde->descq; + + dd_dev_err(sde->dd, + "SDMA (%u) descq_head: %u descq_tail: %u freecnt: %u FLE %d\n", + sde->this_idx, + head, + tail, + cnt, + !list_empty(&sde->flushlist)); + + /* print info for each entry in the descriptor queue */ + while (head != tail) { + char flags[6] = { 'x', 'x', 'x', 'x', 0 }; + + descqp = &sde->descq[head]; + desc[0] = le64_to_cpu(descqp->qw[0]); + desc[1] = le64_to_cpu(descqp->qw[1]); + flags[0] = (desc[1] & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-'; + flags[1] = (desc[1] & SDMA_DESC1_HEAD_TO_HOST_FLAG) ? + 'H' : '-'; + flags[2] = (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-'; + flags[3] = (desc[0] & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-'; + addr = (desc[0] >> SDMA_DESC0_PHY_ADDR_SHIFT) + & SDMA_DESC0_PHY_ADDR_MASK; + gen = (desc[1] >> SDMA_DESC1_GENERATION_SHIFT) + & SDMA_DESC1_GENERATION_MASK; + len = (desc[0] >> SDMA_DESC0_BYTE_COUNT_SHIFT) + & SDMA_DESC0_BYTE_COUNT_MASK; + dd_dev_err(sde->dd, + "SDMA sdmadesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes\n", + head, flags, addr, gen, len); + dd_dev_err(sde->dd, + "\tdesc0:0x%016llx desc1 0x%016llx\n", + desc[0], desc[1]); + if (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) + dd_dev_err(sde->dd, + "\taidx: %u amode: %u alen: %u\n", + (u8)((desc[1] & SDMA_DESC1_HEADER_INDEX_SMASK) + >> SDMA_DESC1_HEADER_INDEX_MASK), + (u8)((desc[1] & SDMA_DESC1_HEADER_MODE_SMASK) + >> SDMA_DESC1_HEADER_MODE_SHIFT), + (u8)((desc[1] & SDMA_DESC1_HEADER_DWS_SMASK) + >> SDMA_DESC1_HEADER_DWS_SHIFT)); + head++; + head &= sde->sdma_mask; + } +} + +#define SDE_FMT \ + "SDE %u STE %s C 0x%llx S 0x%016llx E 0x%llx T(HW) 0x%llx T(SW) 0x%x H(HW) 0x%llx H(SW) 0x%x H(D) 0x%llx DM 0x%llx GL 0x%llx R 0x%llx LIS 0x%llx AHGI 0x%llx TXT %u TXH %u DT %u DH %u FLNE %d DQF %u SLC 0x%llx\n" +/** + * sdma_seqfile_dump_sde() - debugfs dump of sde + * @s: seq file + * @sde: send dma engine to dump + * + * This routine dumps the sde to the indicated seq file. + */ +void sdma_seqfile_dump_sde(struct seq_file *s, struct sdma_engine *sde) +{ + u16 head, tail; + struct hw_sdma_desc *descqp; + u64 desc[2]; + u64 addr; + u8 gen; + u16 len; + + head = sde->descq_head & sde->sdma_mask; + tail = ACCESS_ONCE(sde->descq_tail) & sde->sdma_mask; + seq_printf(s, SDE_FMT, sde->this_idx, + sdma_state_name(sde->state.current_state), + (unsigned long long)read_sde_csr(sde, SD(CTRL)), + (unsigned long long)read_sde_csr(sde, SD(STATUS)), + (unsigned long long)read_sde_csr(sde, + SD(ENG_ERR_STATUS)), + (unsigned long long)read_sde_csr(sde, SD(TAIL)), + tail, + (unsigned long long)read_sde_csr(sde, SD(HEAD)), + head, + (unsigned long long)le64_to_cpu(*sde->head_dma), + (unsigned long long)read_sde_csr(sde, SD(MEMORY)), + (unsigned long long)read_sde_csr(sde, SD(LEN_GEN)), + (unsigned long long)read_sde_csr(sde, SD(RELOAD_CNT)), + (unsigned long long)sde->last_status, + (unsigned long long)sde->ahg_bits, + sde->tx_tail, + sde->tx_head, + sde->descq_tail, + sde->descq_head, + !list_empty(&sde->flushlist), + sde->descq_full_count, + (unsigned long long)read_sde_csr(sde, SEND_DMA_CHECK_SLID)); + + /* print info for each entry in the descriptor queue */ + while (head != tail) { + char flags[6] = { 'x', 'x', 'x', 'x', 0 }; + + descqp = &sde->descq[head]; + desc[0] = le64_to_cpu(descqp->qw[0]); + desc[1] = le64_to_cpu(descqp->qw[1]); + flags[0] = (desc[1] & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-'; + flags[1] = (desc[1] & SDMA_DESC1_HEAD_TO_HOST_FLAG) ? + 'H' : '-'; + flags[2] = (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-'; + flags[3] = (desc[0] & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-'; + addr = (desc[0] >> SDMA_DESC0_PHY_ADDR_SHIFT) + & SDMA_DESC0_PHY_ADDR_MASK; + gen = (desc[1] >> SDMA_DESC1_GENERATION_SHIFT) + & SDMA_DESC1_GENERATION_MASK; + len = (desc[0] >> SDMA_DESC0_BYTE_COUNT_SHIFT) + & SDMA_DESC0_BYTE_COUNT_MASK; + seq_printf(s, + "\tdesc[%u]: flags:%s addr:0x%016llx gen:%u len:%u bytes\n", + head, flags, addr, gen, len); + if (desc[0] & SDMA_DESC0_FIRST_DESC_FLAG) + seq_printf(s, "\t\tahgidx: %u ahgmode: %u\n", + (u8)((desc[1] & SDMA_DESC1_HEADER_INDEX_SMASK) + >> SDMA_DESC1_HEADER_INDEX_MASK), + (u8)((desc[1] & SDMA_DESC1_HEADER_MODE_SMASK) + >> SDMA_DESC1_HEADER_MODE_SHIFT)); + head = (head + 1) & sde->sdma_mask; + } +} + +/* + * add the generation number into + * the qw1 and return + */ +static inline u64 add_gen(struct sdma_engine *sde, u64 qw1) +{ + u8 generation = (sde->descq_tail >> sde->sdma_shift) & 3; + + qw1 &= ~SDMA_DESC1_GENERATION_SMASK; + qw1 |= ((u64)generation & SDMA_DESC1_GENERATION_MASK) + << SDMA_DESC1_GENERATION_SHIFT; + return qw1; +} + +/* + * This routine submits the indicated tx + * + * Space has already been guaranteed and + * tail side of ring is locked. + * + * The hardware tail update is done + * in the caller and that is facilitated + * by returning the new tail. + * + * There is special case logic for ahg + * to not add the generation number for + * up to 2 descriptors that follow the + * first descriptor. + * + */ +static inline u16 submit_tx(struct sdma_engine *sde, struct sdma_txreq *tx) +{ + int i; + u16 tail; + struct sdma_desc *descp = tx->descp; + u8 skip = 0, mode = ahg_mode(tx); + + tail = sde->descq_tail & sde->sdma_mask; + sde->descq[tail].qw[0] = cpu_to_le64(descp->qw[0]); + sde->descq[tail].qw[1] = cpu_to_le64(add_gen(sde, descp->qw[1])); + trace_hfi1_sdma_descriptor(sde, descp->qw[0], descp->qw[1], + tail, &sde->descq[tail]); + tail = ++sde->descq_tail & sde->sdma_mask; + descp++; + if (mode > SDMA_AHG_APPLY_UPDATE1) + skip = mode >> 1; + for (i = 1; i < tx->num_desc; i++, descp++) { + u64 qw1; + + sde->descq[tail].qw[0] = cpu_to_le64(descp->qw[0]); + if (skip) { + /* edits don't have generation */ + qw1 = descp->qw[1]; + skip--; + } else { + /* replace generation with real one for non-edits */ + qw1 = add_gen(sde, descp->qw[1]); + } + sde->descq[tail].qw[1] = cpu_to_le64(qw1); + trace_hfi1_sdma_descriptor(sde, descp->qw[0], qw1, + tail, &sde->descq[tail]); + tail = ++sde->descq_tail & sde->sdma_mask; + } + tx->next_descq_idx = tail; +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER + tx->sn = sde->tail_sn++; + trace_hfi1_sdma_in_sn(sde, tx->sn); + WARN_ON_ONCE(sde->tx_ring[sde->tx_tail & sde->sdma_mask]); +#endif + sde->tx_ring[sde->tx_tail++ & sde->sdma_mask] = tx; + sde->desc_avail -= tx->num_desc; + return tail; +} + +/* + * Check for progress + */ +static int sdma_check_progress( + struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *tx) +{ + int ret; + + sde->desc_avail = sdma_descq_freecnt(sde); + if (tx->num_desc <= sde->desc_avail) + return -EAGAIN; + /* pulse the head_lock */ + if (wait && wait->sleep) { + unsigned seq; + + seq = raw_seqcount_begin( + (const seqcount_t *)&sde->head_lock.seqcount); + ret = wait->sleep(sde, wait, tx, seq); + if (ret == -EAGAIN) + sde->desc_avail = sdma_descq_freecnt(sde); + } else + ret = -EBUSY; + return ret; +} + +/** + * sdma_send_txreq() - submit a tx req to ring + * @sde: sdma engine to use + * @wait: wait structure to use when full (may be NULL) + * @tx: sdma_txreq to submit + * + * The call submits the tx into the ring. If a iowait structure is non-NULL + * the packet will be queued to the list in wait. + * + * Return: + * 0 - Success, -EINVAL - sdma_txreq incomplete, -EBUSY - no space in + * ring (wait == NULL) + * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state + */ +int sdma_send_txreq(struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *tx) +{ + int ret = 0; + u16 tail; + unsigned long flags; + + /* user should have supplied entire packet */ + if (unlikely(tx->tlen)) + return -EINVAL; + tx->wait = wait; + spin_lock_irqsave(&sde->tail_lock, flags); +retry: + if (unlikely(!__sdma_running(sde))) + goto unlock_noconn; + if (unlikely(tx->num_desc > sde->desc_avail)) + goto nodesc; + tail = submit_tx(sde, tx); + if (wait) + atomic_inc(&wait->sdma_busy); + sdma_update_tail(sde, tail); +unlock: + spin_unlock_irqrestore(&sde->tail_lock, flags); + return ret; +unlock_noconn: + if (wait) + atomic_inc(&wait->sdma_busy); + tx->next_descq_idx = 0; +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER + tx->sn = sde->tail_sn++; + trace_hfi1_sdma_in_sn(sde, tx->sn); +#endif + spin_lock(&sde->flushlist_lock); + list_add_tail(&tx->list, &sde->flushlist); + spin_unlock(&sde->flushlist_lock); + if (wait) { + wait->tx_count++; + wait->count += tx->num_desc; + } + schedule_work(&sde->flush_worker); + ret = -ECOMM; + goto unlock; +nodesc: + ret = sdma_check_progress(sde, wait, tx); + if (ret == -EAGAIN) { + ret = 0; + goto retry; + } + sde->descq_full_count++; + goto unlock; +} + +/** + * sdma_send_txlist() - submit a list of tx req to ring + * @sde: sdma engine to use + * @wait: wait structure to use when full (may be NULL) + * @tx_list: list of sdma_txreqs to submit + * + * The call submits the list into the ring. + * + * If the iowait structure is non-NULL and not equal to the iowait list + * the unprocessed part of the list will be appended to the list in wait. + * + * In all cases, the tx_list will be updated so the head of the tx_list is + * the list of descriptors that have yet to be transmitted. + * + * The intent of this call is to provide a more efficient + * way of submitting multiple packets to SDMA while holding the tail + * side locking. + * + * Return: + * 0 - Success, -EINVAL - sdma_txreq incomplete, -EBUSY - no space in ring + * (wait == NULL) + * -EIOCBQUEUED - tx queued to iowait, -ECOMM bad sdma state + */ +int sdma_send_txlist(struct sdma_engine *sde, + struct iowait *wait, + struct list_head *tx_list) +{ + struct sdma_txreq *tx, *tx_next; + int ret = 0; + unsigned long flags; + u16 tail = INVALID_TAIL; + int count = 0; + + spin_lock_irqsave(&sde->tail_lock, flags); +retry: + list_for_each_entry_safe(tx, tx_next, tx_list, list) { + tx->wait = wait; + if (unlikely(!__sdma_running(sde))) + goto unlock_noconn; + if (unlikely(tx->num_desc > sde->desc_avail)) + goto nodesc; + if (unlikely(tx->tlen)) { + ret = -EINVAL; + goto update_tail; + } + list_del_init(&tx->list); + tail = submit_tx(sde, tx); + count++; + if (tail != INVALID_TAIL && + (count & SDMA_TAIL_UPDATE_THRESH) == 0) { + sdma_update_tail(sde, tail); + tail = INVALID_TAIL; + } + } +update_tail: + if (wait) + atomic_add(count, &wait->sdma_busy); + if (tail != INVALID_TAIL) + sdma_update_tail(sde, tail); + spin_unlock_irqrestore(&sde->tail_lock, flags); + return ret; +unlock_noconn: + spin_lock(&sde->flushlist_lock); + list_for_each_entry_safe(tx, tx_next, tx_list, list) { + tx->wait = wait; + list_del_init(&tx->list); + if (wait) + atomic_inc(&wait->sdma_busy); + tx->next_descq_idx = 0; +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER + tx->sn = sde->tail_sn++; + trace_hfi1_sdma_in_sn(sde, tx->sn); +#endif + list_add_tail(&tx->list, &sde->flushlist); + if (wait) { + wait->tx_count++; + wait->count += tx->num_desc; + } + } + spin_unlock(&sde->flushlist_lock); + schedule_work(&sde->flush_worker); + ret = -ECOMM; + goto update_tail; +nodesc: + ret = sdma_check_progress(sde, wait, tx); + if (ret == -EAGAIN) { + ret = 0; + goto retry; + } + sde->descq_full_count++; + goto update_tail; +} + +static void sdma_process_event(struct sdma_engine *sde, + enum sdma_events event) +{ + unsigned long flags; + + spin_lock_irqsave(&sde->tail_lock, flags); + write_seqlock(&sde->head_lock); + + __sdma_process_event(sde, event); + + if (sde->state.current_state == sdma_state_s99_running) + sdma_desc_avail(sde, sdma_descq_freecnt(sde)); + + write_sequnlock(&sde->head_lock); + spin_unlock_irqrestore(&sde->tail_lock, flags); +} + +static void __sdma_process_event(struct sdma_engine *sde, + enum sdma_events event) +{ + struct sdma_state *ss = &sde->state; + int need_progress = 0; + + /* CONFIG SDMA temporary */ +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(sde->dd, "CONFIG SDMA(%u) [%s] %s\n", sde->this_idx, + sdma_state_names[ss->current_state], + sdma_event_names[event]); +#endif + + switch (ss->current_state) { + case sdma_state_s00_hw_down: + switch (event) { + case sdma_event_e00_go_hw_down: + break; + case sdma_event_e30_go_running: + /* + * If down, but running requested (usually result + * of link up, then we need to start up. + * This can happen when hw down is requested while + * bringing the link up with traffic active on + * 7220, e.g. */ + ss->go_s99_running = 1; + /* fall through and start dma engine */ + case sdma_event_e10_go_hw_start: + /* This reference means the state machine is started */ + sdma_get(&sde->state); + sdma_set_state(sde, + sdma_state_s10_hw_start_up_halt_wait); + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e40_sw_cleaned: + sdma_sw_tear_down(sde); + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + break; + case sdma_event_e70_go_idle: + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s10_hw_start_up_halt_wait: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_sw_tear_down(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + sdma_set_state(sde, + sdma_state_s15_hw_start_up_clean_wait); + sdma_start_hw_clean_up(sde); + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + sdma_start_err_halt_wait(sde); + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s15_hw_start_up_clean_wait: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_sw_tear_down(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + sdma_hw_start_up(sde); + sdma_set_state(sde, ss->go_s99_running ? + sdma_state_s99_running : + sdma_state_s20_idle); + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s20_idle: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_sw_tear_down(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + sdma_set_state(sde, sdma_state_s99_running); + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + sdma_set_state(sde, sdma_state_s50_hw_halt_wait); + sdma_start_err_halt_wait(sde); + break; + case sdma_event_e70_go_idle: + break; + case sdma_event_e85_link_down: + /* fall through */ + case sdma_event_e80_hw_freeze: + sdma_set_state(sde, sdma_state_s80_hw_freeze); + atomic_dec(&sde->dd->sdma_unfreeze_count); + wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s30_sw_clean_up_wait: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + sdma_set_state(sde, sdma_state_s40_hw_clean_up_wait); + sdma_start_hw_clean_up(sde); + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + ss->go_s99_running = 0; + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s40_hw_clean_up_wait: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + sdma_hw_start_up(sde); + sdma_set_state(sde, ss->go_s99_running ? + sdma_state_s99_running : + sdma_state_s20_idle); + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + ss->go_s99_running = 0; + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s50_hw_halt_wait: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + sdma_start_err_halt_wait(sde); + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + ss->go_s99_running = 0; + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s60_idle_halt_wait: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + sdma_set_state(sde, sdma_state_s30_sw_clean_up_wait); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + sdma_start_err_halt_wait(sde); + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s80_hw_freeze: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + sdma_set_state(sde, sdma_state_s82_freeze_sw_clean); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e82_hw_unfreeze: + break; + case sdma_event_e85_link_down: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s82_freeze_sw_clean: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + ss->go_s99_running = 1; + break; + case sdma_event_e40_sw_cleaned: + /* notify caller this engine is done cleaning */ + atomic_dec(&sde->dd->sdma_unfreeze_count); + wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + break; + case sdma_event_e70_go_idle: + ss->go_s99_running = 0; + break; + case sdma_event_e80_hw_freeze: + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + sdma_hw_start_up(sde); + sdma_set_state(sde, ss->go_s99_running ? + sdma_state_s99_running : + sdma_state_s20_idle); + break; + case sdma_event_e85_link_down: + break; + case sdma_event_e90_sw_halted: + break; + } + break; + + case sdma_state_s99_running: + switch (event) { + case sdma_event_e00_go_hw_down: + sdma_set_state(sde, sdma_state_s00_hw_down); + sdma_start_sw_clean_up(sde); + break; + case sdma_event_e10_go_hw_start: + break; + case sdma_event_e15_hw_halt_done: + break; + case sdma_event_e25_hw_clean_up_done: + break; + case sdma_event_e30_go_running: + break; + case sdma_event_e40_sw_cleaned: + break; + case sdma_event_e50_hw_cleaned: + break; + case sdma_event_e60_hw_halted: + need_progress = 1; + sdma_err_progress_check_schedule(sde); + case sdma_event_e90_sw_halted: + /* + * SW initiated halt does not perform engines + * progress check + */ + sdma_set_state(sde, sdma_state_s50_hw_halt_wait); + sdma_start_err_halt_wait(sde); + break; + case sdma_event_e70_go_idle: + sdma_set_state(sde, sdma_state_s60_idle_halt_wait); + break; + case sdma_event_e85_link_down: + ss->go_s99_running = 0; + /* fall through */ + case sdma_event_e80_hw_freeze: + sdma_set_state(sde, sdma_state_s80_hw_freeze); + atomic_dec(&sde->dd->sdma_unfreeze_count); + wake_up_interruptible(&sde->dd->sdma_unfreeze_wq); + break; + case sdma_event_e81_hw_frozen: + break; + case sdma_event_e82_hw_unfreeze: + break; + } + break; + } + + ss->last_event = event; + if (need_progress) + sdma_make_progress(sde, 0); +} + +/* + * _extend_sdma_tx_descs() - helper to extend txreq + * + * This is called once the initial nominal allocation + * of descriptors in the sdma_txreq is exhausted. + * + * The code will bump the allocation up to the max + * of MAX_DESC (64) descriptors. There doesn't seem + * much point in an interim step. + * + */ +int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) +{ + int i; + + tx->descp = kmalloc_array( + MAX_DESC, + sizeof(struct sdma_desc), + GFP_ATOMIC); + if (!tx->descp) + return -ENOMEM; + tx->desc_limit = MAX_DESC; + /* copy ones already built */ + for (i = 0; i < tx->num_desc; i++) + tx->descp[i] = tx->descs[i]; + return 0; +} + +/* Update sdes when the lmc changes */ +void sdma_update_lmc(struct hfi1_devdata *dd, u64 mask, u32 lid) +{ + struct sdma_engine *sde; + int i; + u64 sreg; + + sreg = ((mask & SD(CHECK_SLID_MASK_MASK)) << + SD(CHECK_SLID_MASK_SHIFT)) | + (((lid & mask) & SD(CHECK_SLID_VALUE_MASK)) << + SD(CHECK_SLID_VALUE_SHIFT)); + + for (i = 0; i < dd->num_sdma; i++) { + hfi1_cdbg(LINKVERB, "SendDmaEngine[%d].SLID_CHECK = 0x%x", + i, (u32)sreg); + sde = &dd->per_sdma[i]; + write_sde_csr(sde, SD(CHECK_SLID), sreg); + } +} + +/* tx not dword sized - pad */ +int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) +{ + int rval = 0; + + if ((unlikely(tx->num_desc == tx->desc_limit))) { + rval = _extend_sdma_tx_descs(dd, tx); + if (rval) + return rval; + } + /* finish the one just added */ + tx->num_desc++; + make_tx_sdma_desc( + tx, + SDMA_MAP_NONE, + dd->sdma_pad_phys, + sizeof(u32) - (tx->packet_len & (sizeof(u32) - 1))); + _sdma_close_tx(dd, tx); + return rval; +} + +/* + * Add ahg to the sdma_txreq + * + * The logic will consume up to 3 + * descriptors at the beginning of + * sdma_txreq. + */ +void _sdma_txreq_ahgadd( + struct sdma_txreq *tx, + u8 num_ahg, + u8 ahg_entry, + u32 *ahg, + u8 ahg_hlen) +{ + u32 i, shift = 0, desc = 0; + u8 mode; + + WARN_ON_ONCE(num_ahg > 9 || (ahg_hlen & 3) || ahg_hlen == 4); + /* compute mode */ + if (num_ahg == 1) + mode = SDMA_AHG_APPLY_UPDATE1; + else if (num_ahg <= 5) + mode = SDMA_AHG_APPLY_UPDATE2; + else + mode = SDMA_AHG_APPLY_UPDATE3; + tx->num_desc++; + /* initialize to consumed descriptors to zero */ + switch (mode) { + case SDMA_AHG_APPLY_UPDATE3: + tx->num_desc++; + tx->descs[2].qw[0] = 0; + tx->descs[2].qw[1] = 0; + /* FALLTHROUGH */ + case SDMA_AHG_APPLY_UPDATE2: + tx->num_desc++; + tx->descs[1].qw[0] = 0; + tx->descs[1].qw[1] = 0; + break; + } + ahg_hlen >>= 2; + tx->descs[0].qw[1] |= + (((u64)ahg_entry & SDMA_DESC1_HEADER_INDEX_MASK) + << SDMA_DESC1_HEADER_INDEX_SHIFT) | + (((u64)ahg_hlen & SDMA_DESC1_HEADER_DWS_MASK) + << SDMA_DESC1_HEADER_DWS_SHIFT) | + (((u64)mode & SDMA_DESC1_HEADER_MODE_MASK) + << SDMA_DESC1_HEADER_MODE_SHIFT) | + (((u64)ahg[0] & SDMA_DESC1_HEADER_UPDATE1_MASK) + << SDMA_DESC1_HEADER_UPDATE1_SHIFT); + for (i = 0; i < (num_ahg - 1); i++) { + if (!shift && !(i & 2)) + desc++; + tx->descs[desc].qw[!!(i & 2)] |= + (((u64)ahg[i + 1]) + << shift); + shift = (shift + 32) & 63; + } +} + +/** + * sdma_ahg_alloc - allocate an AHG entry + * @sde: engine to allocate from + * + * Return: + * 0-31 when successful, -EOPNOTSUPP if AHG is not enabled, + * -ENOSPC if an entry is not available + */ +int sdma_ahg_alloc(struct sdma_engine *sde) +{ + int nr; + int oldbit; + + if (!sde) { + trace_hfi1_ahg_allocate(sde, -EINVAL); + return -EINVAL; + } + while (1) { + nr = ffz(ACCESS_ONCE(sde->ahg_bits)); + if (nr > 31) { + trace_hfi1_ahg_allocate(sde, -ENOSPC); + return -ENOSPC; + } + oldbit = test_and_set_bit(nr, &sde->ahg_bits); + if (!oldbit) + break; + cpu_relax(); + } + trace_hfi1_ahg_allocate(sde, nr); + return nr; +} + +/** + * sdma_ahg_free - free an AHG entry + * @sde: engine to return AHG entry + * @ahg_index: index to free + * + * This routine frees the indicate AHG entry. + */ +void sdma_ahg_free(struct sdma_engine *sde, int ahg_index) +{ + if (!sde) + return; + trace_hfi1_ahg_deallocate(sde, ahg_index); + if (ahg_index < 0 || ahg_index > 31) + return; + clear_bit(ahg_index, &sde->ahg_bits); +} + +/* + * SPC freeze handling for SDMA engines. Called when the driver knows + * the SPC is going into a freeze but before the freeze is fully + * settled. Generally an error interrupt. + * + * This event will pull the engine out of running so no more entries can be + * added to the engine's queue. + */ +void sdma_freeze_notify(struct hfi1_devdata *dd, int link_down) +{ + int i; + enum sdma_events event = link_down ? sdma_event_e85_link_down : + sdma_event_e80_hw_freeze; + + /* set up the wait but do not wait here */ + atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma); + + /* tell all engines to stop running and wait */ + for (i = 0; i < dd->num_sdma; i++) + sdma_process_event(&dd->per_sdma[i], event); + + /* sdma_freeze() will wait for all engines to have stopped */ +} + +/* + * SPC freeze handling for SDMA engines. Called when the driver knows + * the SPC is fully frozen. + */ +void sdma_freeze(struct hfi1_devdata *dd) +{ + int i; + int ret; + + /* + * Make sure all engines have moved out of the running state before + * continuing. + */ + ret = wait_event_interruptible(dd->sdma_unfreeze_wq, + atomic_read(&dd->sdma_unfreeze_count) <= 0); + /* interrupted or count is negative, then unloading - just exit */ + if (ret || atomic_read(&dd->sdma_unfreeze_count) < 0) + return; + + /* set up the count for the next wait */ + atomic_set(&dd->sdma_unfreeze_count, dd->num_sdma); + + /* tell all engines that the SPC is frozen, they can start cleaning */ + for (i = 0; i < dd->num_sdma; i++) + sdma_process_event(&dd->per_sdma[i], sdma_event_e81_hw_frozen); + + /* + * Wait for everyone to finish software clean before exiting. The + * software clean will read engine CSRs, so must be completed before + * the next step, which will clear the engine CSRs. + */ + (void) wait_event_interruptible(dd->sdma_unfreeze_wq, + atomic_read(&dd->sdma_unfreeze_count) <= 0); + /* no need to check results - done no matter what */ +} + +/* + * SPC freeze handling for the SDMA engines. Called after the SPC is unfrozen. + * + * The SPC freeze acts like a SDMA halt and a hardware clean combined. All + * that is left is a software clean. We could do it after the SPC is fully + * frozen, but then we'd have to add another state to wait for the unfreeze. + * Instead, just defer the software clean until the unfreeze step. + */ +void sdma_unfreeze(struct hfi1_devdata *dd) +{ + int i; + + /* tell all engines start freeze clean up */ + for (i = 0; i < dd->num_sdma; i++) + sdma_process_event(&dd->per_sdma[i], + sdma_event_e82_hw_unfreeze); +} + +/** + * _sdma_engine_progress_schedule() - schedule progress on engine + * @sde: sdma_engine to schedule progress + * + */ +void _sdma_engine_progress_schedule( + struct sdma_engine *sde) +{ + trace_hfi1_sdma_engine_progress(sde, sde->progress_mask); + /* assume we have selected a good cpu */ + write_csr(sde->dd, + CCE_INT_FORCE + (8*(IS_SDMA_START/64)), sde->progress_mask); +} diff --git a/drivers/staging/rdma/hfi1/sdma.h b/drivers/staging/rdma/hfi1/sdma.h new file mode 100644 index 0000000000000..1e613fcd8f4ca --- /dev/null +++ b/drivers/staging/rdma/hfi1/sdma.h @@ -0,0 +1,1123 @@ +#ifndef _HFI1_SDMA_H +#define _HFI1_SDMA_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "verbs.h" + +/* increased for AHG */ +#define NUM_DESC 6 +/* Hardware limit */ +#define MAX_DESC 64 +/* Hardware limit for SDMA packet size */ +#define MAX_SDMA_PKT_SIZE ((16 * 1024) - 1) + + +#define SDMA_TXREQ_S_OK 0 +#define SDMA_TXREQ_S_SENDERROR 1 +#define SDMA_TXREQ_S_ABORTED 2 +#define SDMA_TXREQ_S_SHUTDOWN 3 + +/* flags bits */ +#define SDMA_TXREQ_F_URGENT 0x0001 +#define SDMA_TXREQ_F_AHG_COPY 0x0002 +#define SDMA_TXREQ_F_USE_AHG 0x0004 + +#define SDMA_MAP_NONE 0 +#define SDMA_MAP_SINGLE 1 +#define SDMA_MAP_PAGE 2 + +#define SDMA_AHG_VALUE_MASK 0xffff +#define SDMA_AHG_VALUE_SHIFT 0 +#define SDMA_AHG_INDEX_MASK 0xf +#define SDMA_AHG_INDEX_SHIFT 16 +#define SDMA_AHG_FIELD_LEN_MASK 0xf +#define SDMA_AHG_FIELD_LEN_SHIFT 20 +#define SDMA_AHG_FIELD_START_MASK 0x1f +#define SDMA_AHG_FIELD_START_SHIFT 24 +#define SDMA_AHG_UPDATE_ENABLE_MASK 0x1 +#define SDMA_AHG_UPDATE_ENABLE_SHIFT 31 + +/* AHG modes */ + +/* + * Be aware the ordering and values + * for SDMA_AHG_APPLY_UPDATE[123] + * are assumed in generating a skip + * count in submit_tx() in sdma.c + */ +#define SDMA_AHG_NO_AHG 0 +#define SDMA_AHG_COPY 1 +#define SDMA_AHG_APPLY_UPDATE1 2 +#define SDMA_AHG_APPLY_UPDATE2 3 +#define SDMA_AHG_APPLY_UPDATE3 4 + +/* + * Bits defined in the send DMA descriptor. + */ +#define SDMA_DESC0_FIRST_DESC_FLAG (1ULL<<63) +#define SDMA_DESC0_LAST_DESC_FLAG (1ULL<<62) +#define SDMA_DESC0_BYTE_COUNT_SHIFT 48 +#define SDMA_DESC0_BYTE_COUNT_WIDTH 14 +#define SDMA_DESC0_BYTE_COUNT_MASK \ + ((1ULL<descq_tail == sde->descq_head; +} + +static inline u16 sdma_descq_freecnt(struct sdma_engine *sde) +{ + return sde->descq_cnt - + (sde->descq_tail - + ACCESS_ONCE(sde->descq_head)) - 1; +} + +static inline u16 sdma_descq_inprocess(struct sdma_engine *sde) +{ + return sde->descq_cnt - sdma_descq_freecnt(sde); +} + +/* + * Either head_lock or tail lock required to see + * a steady state. + */ +static inline int __sdma_running(struct sdma_engine *engine) +{ + return engine->state.current_state == sdma_state_s99_running; +} + + +/** + * sdma_running() - state suitability test + * @engine: sdma engine + * + * sdma_running probes the internal state to determine if it is suitable + * for submitting packets. + * + * Return: + * 1 - ok to submit, 0 - not ok to submit + * + */ +static inline int sdma_running(struct sdma_engine *engine) +{ + unsigned long flags; + int ret; + + spin_lock_irqsave(&engine->tail_lock, flags); + ret = __sdma_running(engine); + spin_unlock_irqrestore(&engine->tail_lock, flags); + return ret; +} + +void _sdma_txreq_ahgadd( + struct sdma_txreq *tx, + u8 num_ahg, + u8 ahg_entry, + u32 *ahg, + u8 ahg_hlen); + + +/** + * sdma_txinit_ahg() - initialize an sdma_txreq struct with AHG + * @tx: tx request to initialize + * @flags: flags to key last descriptor additions + * @tlen: total packet length (pbc + headers + data) + * @ahg_entry: ahg entry to use (0 - 31) + * @num_ahg: ahg descriptor for first descriptor (0 - 9) + * @ahg: array of AHG descriptors (up to 9 entries) + * @ahg_hlen: number of bytes from ASIC entry to use + * @cb: callback + * + * The allocation of the sdma_txreq and it enclosing structure is user + * dependent. This routine must be called to initialize the user independent + * fields. + * + * The currently supported flags are SDMA_TXREQ_F_URGENT, + * SDMA_TXREQ_F_AHG_COPY, and SDMA_TXREQ_F_USE_AHG. + * + * SDMA_TXREQ_F_URGENT is used for latency sensitive situations where the + * completion is desired as soon as possible. + * + * SDMA_TXREQ_F_AHG_COPY causes the header in the first descriptor to be + * copied to chip entry. SDMA_TXREQ_F_USE_AHG causes the code to add in + * the AHG descriptors into the first 1 to 3 descriptors. + * + * Completions of submitted requests can be gotten on selected + * txreqs by giving a completion routine callback to sdma_txinit() or + * sdma_txinit_ahg(). The environment in which the callback runs + * can be from an ISR, a tasklet, or a thread, so no sleeping + * kernel routines can be used. Aspects of the sdma ring may + * be locked so care should be taken with locking. + * + * The callback pointer can be NULL to avoid any callback for the packet + * being submitted. The callback will be provided this tx, a status, and a flag. + * + * The status will be one of SDMA_TXREQ_S_OK, SDMA_TXREQ_S_SENDERROR, + * SDMA_TXREQ_S_ABORTED, or SDMA_TXREQ_S_SHUTDOWN. + * + * The flag, if the is the iowait had been used, indicates the iowait + * sdma_busy count has reached zero. + * + * user data portion of tlen should be precise. The sdma_txadd_* entrances + * will pad with a descriptor references 1 - 3 bytes when the number of bytes + * specified in tlen have been supplied to the sdma_txreq. + * + * ahg_hlen is used to determine the number of on-chip entry bytes to + * use as the header. This is for cases where the stored header is + * larger than the header to be used in a packet. This is typical + * for verbs where an RDMA_WRITE_FIRST is larger than the packet in + * and RDMA_WRITE_MIDDLE. + * + */ +static inline int sdma_txinit_ahg( + struct sdma_txreq *tx, + u16 flags, + u16 tlen, + u8 ahg_entry, + u8 num_ahg, + u32 *ahg, + u8 ahg_hlen, + void (*cb)(struct sdma_txreq *, int, int)) +{ + if (tlen == 0) + return -ENODATA; + if (tlen > MAX_SDMA_PKT_SIZE) + return -EMSGSIZE; + tx->desc_limit = ARRAY_SIZE(tx->descs); + tx->descp = &tx->descs[0]; + INIT_LIST_HEAD(&tx->list); + tx->num_desc = 0; + tx->flags = flags; + tx->complete = cb; + tx->coalesce_buf = NULL; + tx->wait = NULL; + tx->tlen = tx->packet_len = tlen; + tx->descs[0].qw[0] = SDMA_DESC0_FIRST_DESC_FLAG; + tx->descs[0].qw[1] = 0; + if (flags & SDMA_TXREQ_F_AHG_COPY) + tx->descs[0].qw[1] |= + (((u64)ahg_entry & SDMA_DESC1_HEADER_INDEX_MASK) + << SDMA_DESC1_HEADER_INDEX_SHIFT) | + (((u64)SDMA_AHG_COPY & SDMA_DESC1_HEADER_MODE_MASK) + << SDMA_DESC1_HEADER_MODE_SHIFT); + else if (flags & SDMA_TXREQ_F_USE_AHG && num_ahg) + _sdma_txreq_ahgadd(tx, num_ahg, ahg_entry, ahg, ahg_hlen); + return 0; +} + +/** + * sdma_txinit() - initialize an sdma_txreq struct (no AHG) + * @tx: tx request to initialize + * @flags: flags to key last descriptor additions + * @tlen: total packet length (pbc + headers + data) + * @cb: callback pointer + * + * The allocation of the sdma_txreq and it enclosing structure is user + * dependent. This routine must be called to initialize the user + * independent fields. + * + * The currently supported flags is SDMA_TXREQ_F_URGENT. + * + * SDMA_TXREQ_F_URGENT is used for latency sensitive situations where the + * completion is desired as soon as possible. + * + * Completions of submitted requests can be gotten on selected + * txreqs by giving a completion routine callback to sdma_txinit() or + * sdma_txinit_ahg(). The environment in which the callback runs + * can be from an ISR, a tasklet, or a thread, so no sleeping + * kernel routines can be used. The head size of the sdma ring may + * be locked so care should be taken with locking. + * + * The callback pointer can be NULL to avoid any callback for the packet + * being submitted. + * + * The callback, if non-NULL, will be provided this tx and a status. The + * status will be one of SDMA_TXREQ_S_OK, SDMA_TXREQ_S_SENDERROR, + * SDMA_TXREQ_S_ABORTED, or SDMA_TXREQ_S_SHUTDOWN. + * + */ +static inline int sdma_txinit( + struct sdma_txreq *tx, + u16 flags, + u16 tlen, + void (*cb)(struct sdma_txreq *, int, int)) +{ + return sdma_txinit_ahg(tx, flags, tlen, 0, 0, NULL, 0, cb); +} + +/* helpers - don't use */ +static inline int sdma_mapping_type(struct sdma_desc *d) +{ + return (d->qw[1] & SDMA_DESC1_GENERATION_SMASK) + >> SDMA_DESC1_GENERATION_SHIFT; +} + +static inline size_t sdma_mapping_len(struct sdma_desc *d) +{ + return (d->qw[0] & SDMA_DESC0_BYTE_COUNT_SMASK) + >> SDMA_DESC0_BYTE_COUNT_SHIFT; +} + +static inline dma_addr_t sdma_mapping_addr(struct sdma_desc *d) +{ + return (d->qw[0] & SDMA_DESC0_PHY_ADDR_SMASK) + >> SDMA_DESC0_PHY_ADDR_SHIFT; +} + +static inline void make_tx_sdma_desc( + struct sdma_txreq *tx, + int type, + dma_addr_t addr, + size_t len) +{ + struct sdma_desc *desc = &tx->descp[tx->num_desc]; + + if (!tx->num_desc) { + /* qw[0] zero; qw[1] first, ahg mode already in from init */ + desc->qw[1] |= ((u64)type & SDMA_DESC1_GENERATION_MASK) + << SDMA_DESC1_GENERATION_SHIFT; + } else { + desc->qw[0] = 0; + desc->qw[1] = ((u64)type & SDMA_DESC1_GENERATION_MASK) + << SDMA_DESC1_GENERATION_SHIFT; + } + desc->qw[0] |= (((u64)addr & SDMA_DESC0_PHY_ADDR_MASK) + << SDMA_DESC0_PHY_ADDR_SHIFT) | + (((u64)len & SDMA_DESC0_BYTE_COUNT_MASK) + << SDMA_DESC0_BYTE_COUNT_SHIFT); +} + +/* helper to extend txreq */ +int _extend_sdma_tx_descs(struct hfi1_devdata *, struct sdma_txreq *); +int _pad_sdma_tx_descs(struct hfi1_devdata *, struct sdma_txreq *); +void sdma_txclean(struct hfi1_devdata *, struct sdma_txreq *); + +/* helpers used by public routines */ +static inline void _sdma_close_tx(struct hfi1_devdata *dd, + struct sdma_txreq *tx) +{ + tx->descp[tx->num_desc].qw[0] |= + SDMA_DESC0_LAST_DESC_FLAG; + tx->descp[tx->num_desc].qw[1] |= + dd->default_desc1; + if (tx->flags & SDMA_TXREQ_F_URGENT) + tx->descp[tx->num_desc].qw[1] |= + (SDMA_DESC1_HEAD_TO_HOST_FLAG| + SDMA_DESC1_INT_REQ_FLAG); +} + +static inline int _sdma_txadd_daddr( + struct hfi1_devdata *dd, + int type, + struct sdma_txreq *tx, + dma_addr_t addr, + u16 len) +{ + int rval = 0; + + if ((unlikely(tx->num_desc == tx->desc_limit))) { + rval = _extend_sdma_tx_descs(dd, tx); + if (rval) + return rval; + } + make_tx_sdma_desc( + tx, + type, + addr, len); + WARN_ON(len > tx->tlen); + tx->tlen -= len; + /* special cases for last */ + if (!tx->tlen) { + if (tx->packet_len & (sizeof(u32) - 1)) + rval = _pad_sdma_tx_descs(dd, tx); + else + _sdma_close_tx(dd, tx); + } + tx->num_desc++; + return rval; +} + +/** + * sdma_txadd_page() - add a page to the sdma_txreq + * @dd: the device to use for mapping + * @tx: tx request to which the page is added + * @page: page to map + * @offset: offset within the page + * @len: length in bytes + * + * This is used to add a page/offset/length descriptor. + * + * The mapping/unmapping of the page/offset/len is automatically handled. + * + * Return: + * 0 - success, -ENOSPC - mapping fail, -ENOMEM - couldn't + * extend descriptor array or couldn't allocate coalesce + * buffer. + * + */ +static inline int sdma_txadd_page( + struct hfi1_devdata *dd, + struct sdma_txreq *tx, + struct page *page, + unsigned long offset, + u16 len) +{ + dma_addr_t addr = + dma_map_page( + &dd->pcidev->dev, + page, + offset, + len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) { + sdma_txclean(dd, tx); + return -ENOSPC; + } + return _sdma_txadd_daddr( + dd, SDMA_MAP_PAGE, tx, addr, len); +} + +/** + * sdma_txadd_daddr() - add a dma address to the sdma_txreq + * @dd: the device to use for mapping + * @tx: sdma_txreq to which the page is added + * @addr: dma address mapped by caller + * @len: length in bytes + * + * This is used to add a descriptor for memory that is already dma mapped. + * + * In this case, there is no unmapping as part of the progress processing for + * this memory location. + * + * Return: + * 0 - success, -ENOMEM - couldn't extend descriptor array + */ + +static inline int sdma_txadd_daddr( + struct hfi1_devdata *dd, + struct sdma_txreq *tx, + dma_addr_t addr, + u16 len) +{ + return _sdma_txadd_daddr(dd, SDMA_MAP_NONE, tx, addr, len); +} + +/** + * sdma_txadd_kvaddr() - add a kernel virtual address to sdma_txreq + * @dd: the device to use for mapping + * @tx: sdma_txreq to which the page is added + * @kvaddr: the kernel virtual address + * @len: length in bytes + * + * This is used to add a descriptor referenced by the indicated kvaddr and + * len. + * + * The mapping/unmapping of the kvaddr and len is automatically handled. + * + * Return: + * 0 - success, -ENOSPC - mapping fail, -ENOMEM - couldn't extend + * descriptor array + */ +static inline int sdma_txadd_kvaddr( + struct hfi1_devdata *dd, + struct sdma_txreq *tx, + void *kvaddr, + u16 len) +{ + dma_addr_t addr = + dma_map_single( + &dd->pcidev->dev, + kvaddr, + len, + DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) { + sdma_txclean(dd, tx); + return -ENOSPC; + } + return _sdma_txadd_daddr( + dd, SDMA_MAP_SINGLE, tx, addr, len); +} + +struct iowait; + +int sdma_send_txreq(struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *tx); +int sdma_send_txlist(struct sdma_engine *sde, + struct iowait *wait, + struct list_head *tx_list); + +int sdma_ahg_alloc(struct sdma_engine *sde); +void sdma_ahg_free(struct sdma_engine *sde, int ahg_index); + +/** + * sdma_build_ahg - build ahg descriptor + * @data + * @dwindex + * @startbit + * @bits + * + * Build and return a 32 bit descriptor. + */ +static inline u32 sdma_build_ahg_descriptor( + u16 data, + u8 dwindex, + u8 startbit, + u8 bits) +{ + return (u32)(1UL << SDMA_AHG_UPDATE_ENABLE_SHIFT | + ((startbit & SDMA_AHG_FIELD_START_MASK) << + SDMA_AHG_FIELD_START_SHIFT) | + ((bits & SDMA_AHG_FIELD_LEN_MASK) << + SDMA_AHG_FIELD_LEN_SHIFT) | + ((dwindex & SDMA_AHG_INDEX_MASK) << + SDMA_AHG_INDEX_SHIFT) | + ((data & SDMA_AHG_VALUE_MASK) << + SDMA_AHG_VALUE_SHIFT)); +} + +/** + * sdma_progress - use seq number of detect head progress + * @sde: sdma_engine to check + * @seq: base seq count + * @tx: txreq for which we need to check descriptor availability + * + * This is used in the appropriate spot in the sleep routine + * to check for potential ring progress. This routine gets the + * seqcount before queuing the iowait structure for progress. + * + * If the seqcount indicates that progress needs to be checked, + * re-submission is detected by checking whether the descriptor + * queue has enough descriptor for the txreq. + */ +static inline unsigned sdma_progress(struct sdma_engine *sde, unsigned seq, + struct sdma_txreq *tx) +{ + if (read_seqretry(&sde->head_lock, seq)) { + sde->desc_avail = sdma_descq_freecnt(sde); + if (tx->num_desc > sde->desc_avail) + return 0; + return 1; + } + return 0; +} + +/** + * sdma_iowait_schedule() - initialize wait structure + * @sde: sdma_engine to schedule + * @wait: wait struct to schedule + * + * This function initializes the iowait + * structure embedded in the QP or PQ. + * + */ +static inline void sdma_iowait_schedule( + struct sdma_engine *sde, + struct iowait *wait) +{ + iowait_schedule(wait, sde->wq); +} + +/* for use by interrupt handling */ +void sdma_engine_error(struct sdma_engine *sde, u64 status); +void sdma_engine_interrupt(struct sdma_engine *sde, u64 status); + +/* + * + * The diagram below details the relationship of the mapping structures + * + * Since the mapping now allows for non-uniform engines per vl, the + * number of engines for a vl is either the vl_engines[vl] or + * a computation based on num_sdma/num_vls: + * + * For example: + * nactual = vl_engines ? vl_engines[vl] : num_sdma/num_vls + * + * n = roundup to next highest power of 2 using nactual + * + * In the case where there are num_sdma/num_vls doesn't divide + * evenly, the extras are added from the last vl downward. + * + * For the case where n > nactual, the engines are assigned + * in a round robin fashion wrapping back to the first engine + * for a particular vl. + * + * dd->sdma_map + * | sdma_map_elem[0] + * | +--------------------+ + * v | mask | + * sdma_vl_map |--------------------| + * +--------------------------+ | sde[0] -> eng 1 | + * | list (RCU) | |--------------------| + * |--------------------------| ->| sde[1] -> eng 2 | + * | mask | --/ |--------------------| + * |--------------------------| -/ | * | + * | actual_vls (max 8) | -/ |--------------------| + * |--------------------------| --/ | sde[n] -> eng n | + * | vls (max 8) | -/ +--------------------+ + * |--------------------------| --/ + * | map[0] |-/ + * |--------------------------| +--------------------+ + * | map[1] |--- | mask | + * |--------------------------| \---- |--------------------| + * | * | \-- | sde[0] -> eng 1+n | + * | * | \---- |--------------------| + * | * | \->| sde[1] -> eng 2+n | + * |--------------------------| |--------------------| + * | map[vls - 1] |- | * | + * +--------------------------+ \- |--------------------| + * \- | sde[m] -> eng m+n | + * \ +--------------------+ + * \- + * \ + * \- +--------------------+ + * \- | mask | + * \ |--------------------| + * \- | sde[0] -> eng 1+m+n| + * \- |--------------------| + * >| sde[1] -> eng 2+m+n| + * |--------------------| + * | * | + * |--------------------| + * | sde[o] -> eng o+m+n| + * +--------------------+ + * + */ + +/** + * struct sdma_map_elem - mapping for a vl + * @mask - selector mask + * @sde - array of engines for this vl + * + * The mask is used to "mod" the selector + * to produce index into the trailing + * array of sdes. + */ +struct sdma_map_elem { + u32 mask; + struct sdma_engine *sde[0]; +}; + +/** + * struct sdma_map_el - mapping for a vl + * @list - rcu head for free callback + * @mask - vl mask to "mod" the vl to produce an index to map array + * @actual_vls - number of vls + * @vls - number of vls rounded to next power of 2 + * @map - array of sdma_map_elem entries + * + * This is the parent mapping structure. The trailing + * members of the struct point to sdma_map_elem entries, which + * in turn point to an array of sde's for that vl. + */ +struct sdma_vl_map { + struct rcu_head list; + u32 mask; + u8 actual_vls; + u8 vls; + struct sdma_map_elem *map[0]; +}; + +int sdma_map_init( + struct hfi1_devdata *dd, + u8 port, + u8 num_vls, + u8 *vl_engines); + +/* slow path */ +void _sdma_engine_progress_schedule(struct sdma_engine *sde); + +/** + * sdma_engine_progress_schedule() - schedule progress on engine + * @sde: sdma_engine to schedule progress + * + * This is the fast path. + * + */ +static inline void sdma_engine_progress_schedule( + struct sdma_engine *sde) +{ + if (!sde || sdma_descq_inprocess(sde) < (sde->descq_cnt / 8)) + return; + _sdma_engine_progress_schedule(sde); +} + +struct sdma_engine *sdma_select_engine_sc( + struct hfi1_devdata *dd, + u32 selector, + u8 sc5); + +struct sdma_engine *sdma_select_engine_vl( + struct hfi1_devdata *dd, + u32 selector, + u8 vl); + +void sdma_seqfile_dump_sde(struct seq_file *s, struct sdma_engine *); + +#ifdef CONFIG_SDMA_VERBOSITY +void sdma_dumpstate(struct sdma_engine *); +#endif +static inline char *slashstrip(char *s) +{ + char *r = s; + + while (*s) + if (*s++ == '/') + r = s; + return r; +} + +u16 sdma_get_descq_cnt(void); + +extern uint mod_num_sdma; + +void sdma_update_lmc(struct hfi1_devdata *dd, u64 mask, u32 lid); + +#endif diff --git a/drivers/staging/rdma/hfi1/srq.c b/drivers/staging/rdma/hfi1/srq.c new file mode 100644 index 0000000000000..67786d4174936 --- /dev/null +++ b/drivers/staging/rdma/hfi1/srq.c @@ -0,0 +1,397 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "verbs.h" + +/** + * hfi1_post_srq_receive - post a receive on a shared receive queue + * @ibsrq: the SRQ to post the receive on + * @wr: the list of work requests to post + * @bad_wr: A pointer to the first WR to cause a problem is put here + * + * This may be called from interrupt context. + */ +int hfi1_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct hfi1_srq *srq = to_isrq(ibsrq); + struct hfi1_rwq *wq; + unsigned long flags; + int ret; + + for (; wr; wr = wr->next) { + struct hfi1_rwqe *wqe; + u32 next; + int i; + + if ((unsigned) wr->num_sge > srq->rq.max_sge) { + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + + spin_lock_irqsave(&srq->rq.lock, flags); + wq = srq->rq.wq; + next = wq->head + 1; + if (next >= srq->rq.size) + next = 0; + if (next == wq->tail) { + spin_unlock_irqrestore(&srq->rq.lock, flags); + *bad_wr = wr; + ret = -ENOMEM; + goto bail; + } + + wqe = get_rwqe_ptr(&srq->rq, wq->head); + wqe->wr_id = wr->wr_id; + wqe->num_sge = wr->num_sge; + for (i = 0; i < wr->num_sge; i++) + wqe->sg_list[i] = wr->sg_list[i]; + /* Make sure queue entry is written before the head index. */ + smp_wmb(); + wq->head = next; + spin_unlock_irqrestore(&srq->rq.lock, flags); + } + ret = 0; + +bail: + return ret; +} + +/** + * hfi1_create_srq - create a shared receive queue + * @ibpd: the protection domain of the SRQ to create + * @srq_init_attr: the attributes of the SRQ + * @udata: data from libibverbs when creating a user SRQ + */ +struct ib_srq *hfi1_create_srq(struct ib_pd *ibpd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata) +{ + struct hfi1_ibdev *dev = to_idev(ibpd->device); + struct hfi1_srq *srq; + u32 sz; + struct ib_srq *ret; + + if (srq_init_attr->srq_type != IB_SRQT_BASIC) { + ret = ERR_PTR(-ENOSYS); + goto done; + } + + if (srq_init_attr->attr.max_sge == 0 || + srq_init_attr->attr.max_sge > hfi1_max_srq_sges || + srq_init_attr->attr.max_wr == 0 || + srq_init_attr->attr.max_wr > hfi1_max_srq_wrs) { + ret = ERR_PTR(-EINVAL); + goto done; + } + + srq = kmalloc(sizeof(*srq), GFP_KERNEL); + if (!srq) { + ret = ERR_PTR(-ENOMEM); + goto done; + } + + /* + * Need to use vmalloc() if we want to support large #s of entries. + */ + srq->rq.size = srq_init_attr->attr.max_wr + 1; + srq->rq.max_sge = srq_init_attr->attr.max_sge; + sz = sizeof(struct ib_sge) * srq->rq.max_sge + + sizeof(struct hfi1_rwqe); + srq->rq.wq = vmalloc_user(sizeof(struct hfi1_rwq) + srq->rq.size * sz); + if (!srq->rq.wq) { + ret = ERR_PTR(-ENOMEM); + goto bail_srq; + } + + /* + * Return the address of the RWQ as the offset to mmap. + * See hfi1_mmap() for details. + */ + if (udata && udata->outlen >= sizeof(__u64)) { + int err; + u32 s = sizeof(struct hfi1_rwq) + srq->rq.size * sz; + + srq->ip = + hfi1_create_mmap_info(dev, s, ibpd->uobject->context, + srq->rq.wq); + if (!srq->ip) { + ret = ERR_PTR(-ENOMEM); + goto bail_wq; + } + + err = ib_copy_to_udata(udata, &srq->ip->offset, + sizeof(srq->ip->offset)); + if (err) { + ret = ERR_PTR(err); + goto bail_ip; + } + } else + srq->ip = NULL; + + /* + * ib_create_srq() will initialize srq->ibsrq. + */ + spin_lock_init(&srq->rq.lock); + srq->rq.wq->head = 0; + srq->rq.wq->tail = 0; + srq->limit = srq_init_attr->attr.srq_limit; + + spin_lock(&dev->n_srqs_lock); + if (dev->n_srqs_allocated == hfi1_max_srqs) { + spin_unlock(&dev->n_srqs_lock); + ret = ERR_PTR(-ENOMEM); + goto bail_ip; + } + + dev->n_srqs_allocated++; + spin_unlock(&dev->n_srqs_lock); + + if (srq->ip) { + spin_lock_irq(&dev->pending_lock); + list_add(&srq->ip->pending_mmaps, &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + + ret = &srq->ibsrq; + goto done; + +bail_ip: + kfree(srq->ip); +bail_wq: + vfree(srq->rq.wq); +bail_srq: + kfree(srq); +done: + return ret; +} + +/** + * hfi1_modify_srq - modify a shared receive queue + * @ibsrq: the SRQ to modify + * @attr: the new attributes of the SRQ + * @attr_mask: indicates which attributes to modify + * @udata: user data for libibverbs.so + */ +int hfi1_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, + struct ib_udata *udata) +{ + struct hfi1_srq *srq = to_isrq(ibsrq); + struct hfi1_rwq *wq; + int ret = 0; + + if (attr_mask & IB_SRQ_MAX_WR) { + struct hfi1_rwq *owq; + struct hfi1_rwqe *p; + u32 sz, size, n, head, tail; + + /* Check that the requested sizes are below the limits. */ + if ((attr->max_wr > hfi1_max_srq_wrs) || + ((attr_mask & IB_SRQ_LIMIT) ? + attr->srq_limit : srq->limit) > attr->max_wr) { + ret = -EINVAL; + goto bail; + } + + sz = sizeof(struct hfi1_rwqe) + + srq->rq.max_sge * sizeof(struct ib_sge); + size = attr->max_wr + 1; + wq = vmalloc_user(sizeof(struct hfi1_rwq) + size * sz); + if (!wq) { + ret = -ENOMEM; + goto bail; + } + + /* Check that we can write the offset to mmap. */ + if (udata && udata->inlen >= sizeof(__u64)) { + __u64 offset_addr; + __u64 offset = 0; + + ret = ib_copy_from_udata(&offset_addr, udata, + sizeof(offset_addr)); + if (ret) + goto bail_free; + udata->outbuf = + (void __user *) (unsigned long) offset_addr; + ret = ib_copy_to_udata(udata, &offset, + sizeof(offset)); + if (ret) + goto bail_free; + } + + spin_lock_irq(&srq->rq.lock); + /* + * validate head and tail pointer values and compute + * the number of remaining WQEs. + */ + owq = srq->rq.wq; + head = owq->head; + tail = owq->tail; + if (head >= srq->rq.size || tail >= srq->rq.size) { + ret = -EINVAL; + goto bail_unlock; + } + n = head; + if (n < tail) + n += srq->rq.size - tail; + else + n -= tail; + if (size <= n) { + ret = -EINVAL; + goto bail_unlock; + } + n = 0; + p = wq->wq; + while (tail != head) { + struct hfi1_rwqe *wqe; + int i; + + wqe = get_rwqe_ptr(&srq->rq, tail); + p->wr_id = wqe->wr_id; + p->num_sge = wqe->num_sge; + for (i = 0; i < wqe->num_sge; i++) + p->sg_list[i] = wqe->sg_list[i]; + n++; + p = (struct hfi1_rwqe *)((char *)p + sz); + if (++tail >= srq->rq.size) + tail = 0; + } + srq->rq.wq = wq; + srq->rq.size = size; + wq->head = n; + wq->tail = 0; + if (attr_mask & IB_SRQ_LIMIT) + srq->limit = attr->srq_limit; + spin_unlock_irq(&srq->rq.lock); + + vfree(owq); + + if (srq->ip) { + struct hfi1_mmap_info *ip = srq->ip; + struct hfi1_ibdev *dev = to_idev(srq->ibsrq.device); + u32 s = sizeof(struct hfi1_rwq) + size * sz; + + hfi1_update_mmap_info(dev, ip, s, wq); + + /* + * Return the offset to mmap. + * See hfi1_mmap() for details. + */ + if (udata && udata->inlen >= sizeof(__u64)) { + ret = ib_copy_to_udata(udata, &ip->offset, + sizeof(ip->offset)); + if (ret) + goto bail; + } + + /* + * Put user mapping info onto the pending list + * unless it already is on the list. + */ + spin_lock_irq(&dev->pending_lock); + if (list_empty(&ip->pending_mmaps)) + list_add(&ip->pending_mmaps, + &dev->pending_mmaps); + spin_unlock_irq(&dev->pending_lock); + } + } else if (attr_mask & IB_SRQ_LIMIT) { + spin_lock_irq(&srq->rq.lock); + if (attr->srq_limit >= srq->rq.size) + ret = -EINVAL; + else + srq->limit = attr->srq_limit; + spin_unlock_irq(&srq->rq.lock); + } + goto bail; + +bail_unlock: + spin_unlock_irq(&srq->rq.lock); +bail_free: + vfree(wq); +bail: + return ret; +} + +int hfi1_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr) +{ + struct hfi1_srq *srq = to_isrq(ibsrq); + + attr->max_wr = srq->rq.size - 1; + attr->max_sge = srq->rq.max_sge; + attr->srq_limit = srq->limit; + return 0; +} + +/** + * hfi1_destroy_srq - destroy a shared receive queue + * @ibsrq: the SRQ to destroy + */ +int hfi1_destroy_srq(struct ib_srq *ibsrq) +{ + struct hfi1_srq *srq = to_isrq(ibsrq); + struct hfi1_ibdev *dev = to_idev(ibsrq->device); + + spin_lock(&dev->n_srqs_lock); + dev->n_srqs_allocated--; + spin_unlock(&dev->n_srqs_lock); + if (srq->ip) + kref_put(&srq->ip->ref, hfi1_release_mmap_info); + else + vfree(srq->rq.wq); + kfree(srq); + + return 0; +} diff --git a/drivers/staging/rdma/hfi1/sysfs.c b/drivers/staging/rdma/hfi1/sysfs.c new file mode 100644 index 0000000000000..b78c72861ef9e --- /dev/null +++ b/drivers/staging/rdma/hfi1/sysfs.c @@ -0,0 +1,739 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include + +#include "hfi.h" +#include "mad.h" +#include "trace.h" + + +/* + * Start of per-port congestion control structures and support code + */ + +/* + * Congestion control table size followed by table entries + */ +static ssize_t read_cc_table_bin(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + int ret; + struct hfi1_pportdata *ppd = + container_of(kobj, struct hfi1_pportdata, pport_cc_kobj); + struct cc_state *cc_state; + + ret = ppd->total_cct_entry * sizeof(struct ib_cc_table_entry_shadow) + + sizeof(__be16); + + if (pos > ret) + return -EINVAL; + + if (count > ret - pos) + count = ret - pos; + + if (!count) + return count; + + rcu_read_lock(); + cc_state = get_cc_state(ppd); + if (cc_state == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + memcpy(buf, &cc_state->cct, count); + rcu_read_unlock(); + + return count; +} + +static void port_release(struct kobject *kobj) +{ + /* nothing to do since memory is freed by hfi1_free_devdata() */ +} + +static struct kobj_type port_cc_ktype = { + .release = port_release, +}; + +static struct bin_attribute cc_table_bin_attr = { + .attr = {.name = "cc_table_bin", .mode = 0444}, + .read = read_cc_table_bin, + .size = PAGE_SIZE, +}; + +/* + * Congestion settings: port control, control map and an array of 16 + * entries for the congestion entries - increase, timer, event log + * trigger threshold and the minimum injection rate delay. + */ +static ssize_t read_cc_setting_bin(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t pos, size_t count) +{ + int ret; + struct hfi1_pportdata *ppd = + container_of(kobj, struct hfi1_pportdata, pport_cc_kobj); + struct cc_state *cc_state; + + ret = sizeof(struct opa_congestion_setting_attr_shadow); + + if (pos > ret) + return -EINVAL; + if (count > ret - pos) + count = ret - pos; + + if (!count) + return count; + + rcu_read_lock(); + cc_state = get_cc_state(ppd); + if (cc_state == NULL) { + rcu_read_unlock(); + return -EINVAL; + } + memcpy(buf, &cc_state->cong_setting, count); + rcu_read_unlock(); + + return count; +} + +static struct bin_attribute cc_setting_bin_attr = { + .attr = {.name = "cc_settings_bin", .mode = 0444}, + .read = read_cc_setting_bin, + .size = PAGE_SIZE, +}; + +/* Start sc2vl */ +#define HFI1_SC2VL_ATTR(N) \ + static struct hfi1_sc2vl_attr hfi1_sc2vl_attr_##N = { \ + .attr = { .name = __stringify(N), .mode = 0444 }, \ + .sc = N \ + } + +struct hfi1_sc2vl_attr { + struct attribute attr; + int sc; +}; + +HFI1_SC2VL_ATTR(0); +HFI1_SC2VL_ATTR(1); +HFI1_SC2VL_ATTR(2); +HFI1_SC2VL_ATTR(3); +HFI1_SC2VL_ATTR(4); +HFI1_SC2VL_ATTR(5); +HFI1_SC2VL_ATTR(6); +HFI1_SC2VL_ATTR(7); +HFI1_SC2VL_ATTR(8); +HFI1_SC2VL_ATTR(9); +HFI1_SC2VL_ATTR(10); +HFI1_SC2VL_ATTR(11); +HFI1_SC2VL_ATTR(12); +HFI1_SC2VL_ATTR(13); +HFI1_SC2VL_ATTR(14); +HFI1_SC2VL_ATTR(15); +HFI1_SC2VL_ATTR(16); +HFI1_SC2VL_ATTR(17); +HFI1_SC2VL_ATTR(18); +HFI1_SC2VL_ATTR(19); +HFI1_SC2VL_ATTR(20); +HFI1_SC2VL_ATTR(21); +HFI1_SC2VL_ATTR(22); +HFI1_SC2VL_ATTR(23); +HFI1_SC2VL_ATTR(24); +HFI1_SC2VL_ATTR(25); +HFI1_SC2VL_ATTR(26); +HFI1_SC2VL_ATTR(27); +HFI1_SC2VL_ATTR(28); +HFI1_SC2VL_ATTR(29); +HFI1_SC2VL_ATTR(30); +HFI1_SC2VL_ATTR(31); + + +static struct attribute *sc2vl_default_attributes[] = { + &hfi1_sc2vl_attr_0.attr, + &hfi1_sc2vl_attr_1.attr, + &hfi1_sc2vl_attr_2.attr, + &hfi1_sc2vl_attr_3.attr, + &hfi1_sc2vl_attr_4.attr, + &hfi1_sc2vl_attr_5.attr, + &hfi1_sc2vl_attr_6.attr, + &hfi1_sc2vl_attr_7.attr, + &hfi1_sc2vl_attr_8.attr, + &hfi1_sc2vl_attr_9.attr, + &hfi1_sc2vl_attr_10.attr, + &hfi1_sc2vl_attr_11.attr, + &hfi1_sc2vl_attr_12.attr, + &hfi1_sc2vl_attr_13.attr, + &hfi1_sc2vl_attr_14.attr, + &hfi1_sc2vl_attr_15.attr, + &hfi1_sc2vl_attr_16.attr, + &hfi1_sc2vl_attr_17.attr, + &hfi1_sc2vl_attr_18.attr, + &hfi1_sc2vl_attr_19.attr, + &hfi1_sc2vl_attr_20.attr, + &hfi1_sc2vl_attr_21.attr, + &hfi1_sc2vl_attr_22.attr, + &hfi1_sc2vl_attr_23.attr, + &hfi1_sc2vl_attr_24.attr, + &hfi1_sc2vl_attr_25.attr, + &hfi1_sc2vl_attr_26.attr, + &hfi1_sc2vl_attr_27.attr, + &hfi1_sc2vl_attr_28.attr, + &hfi1_sc2vl_attr_29.attr, + &hfi1_sc2vl_attr_30.attr, + &hfi1_sc2vl_attr_31.attr, + NULL +}; + +static ssize_t sc2vl_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct hfi1_sc2vl_attr *sattr = + container_of(attr, struct hfi1_sc2vl_attr, attr); + struct hfi1_pportdata *ppd = + container_of(kobj, struct hfi1_pportdata, sc2vl_kobj); + struct hfi1_devdata *dd = ppd->dd; + + return sprintf(buf, "%u\n", *((u8 *)dd->sc2vl + sattr->sc)); +} + +static const struct sysfs_ops hfi1_sc2vl_ops = { + .show = sc2vl_attr_show, +}; + +static struct kobj_type hfi1_sc2vl_ktype = { + .release = port_release, + .sysfs_ops = &hfi1_sc2vl_ops, + .default_attrs = sc2vl_default_attributes +}; + +/* End sc2vl */ + +/* Start sl2sc */ +#define HFI1_SL2SC_ATTR(N) \ + static struct hfi1_sl2sc_attr hfi1_sl2sc_attr_##N = { \ + .attr = { .name = __stringify(N), .mode = 0444 }, \ + .sl = N \ + } + +struct hfi1_sl2sc_attr { + struct attribute attr; + int sl; +}; + +HFI1_SL2SC_ATTR(0); +HFI1_SL2SC_ATTR(1); +HFI1_SL2SC_ATTR(2); +HFI1_SL2SC_ATTR(3); +HFI1_SL2SC_ATTR(4); +HFI1_SL2SC_ATTR(5); +HFI1_SL2SC_ATTR(6); +HFI1_SL2SC_ATTR(7); +HFI1_SL2SC_ATTR(8); +HFI1_SL2SC_ATTR(9); +HFI1_SL2SC_ATTR(10); +HFI1_SL2SC_ATTR(11); +HFI1_SL2SC_ATTR(12); +HFI1_SL2SC_ATTR(13); +HFI1_SL2SC_ATTR(14); +HFI1_SL2SC_ATTR(15); +HFI1_SL2SC_ATTR(16); +HFI1_SL2SC_ATTR(17); +HFI1_SL2SC_ATTR(18); +HFI1_SL2SC_ATTR(19); +HFI1_SL2SC_ATTR(20); +HFI1_SL2SC_ATTR(21); +HFI1_SL2SC_ATTR(22); +HFI1_SL2SC_ATTR(23); +HFI1_SL2SC_ATTR(24); +HFI1_SL2SC_ATTR(25); +HFI1_SL2SC_ATTR(26); +HFI1_SL2SC_ATTR(27); +HFI1_SL2SC_ATTR(28); +HFI1_SL2SC_ATTR(29); +HFI1_SL2SC_ATTR(30); +HFI1_SL2SC_ATTR(31); + + +static struct attribute *sl2sc_default_attributes[] = { + &hfi1_sl2sc_attr_0.attr, + &hfi1_sl2sc_attr_1.attr, + &hfi1_sl2sc_attr_2.attr, + &hfi1_sl2sc_attr_3.attr, + &hfi1_sl2sc_attr_4.attr, + &hfi1_sl2sc_attr_5.attr, + &hfi1_sl2sc_attr_6.attr, + &hfi1_sl2sc_attr_7.attr, + &hfi1_sl2sc_attr_8.attr, + &hfi1_sl2sc_attr_9.attr, + &hfi1_sl2sc_attr_10.attr, + &hfi1_sl2sc_attr_11.attr, + &hfi1_sl2sc_attr_12.attr, + &hfi1_sl2sc_attr_13.attr, + &hfi1_sl2sc_attr_14.attr, + &hfi1_sl2sc_attr_15.attr, + &hfi1_sl2sc_attr_16.attr, + &hfi1_sl2sc_attr_17.attr, + &hfi1_sl2sc_attr_18.attr, + &hfi1_sl2sc_attr_19.attr, + &hfi1_sl2sc_attr_20.attr, + &hfi1_sl2sc_attr_21.attr, + &hfi1_sl2sc_attr_22.attr, + &hfi1_sl2sc_attr_23.attr, + &hfi1_sl2sc_attr_24.attr, + &hfi1_sl2sc_attr_25.attr, + &hfi1_sl2sc_attr_26.attr, + &hfi1_sl2sc_attr_27.attr, + &hfi1_sl2sc_attr_28.attr, + &hfi1_sl2sc_attr_29.attr, + &hfi1_sl2sc_attr_30.attr, + &hfi1_sl2sc_attr_31.attr, + NULL +}; + +static ssize_t sl2sc_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct hfi1_sl2sc_attr *sattr = + container_of(attr, struct hfi1_sl2sc_attr, attr); + struct hfi1_pportdata *ppd = + container_of(kobj, struct hfi1_pportdata, sl2sc_kobj); + struct hfi1_ibport *ibp = &ppd->ibport_data; + + return sprintf(buf, "%u\n", ibp->sl_to_sc[sattr->sl]); +} + +static const struct sysfs_ops hfi1_sl2sc_ops = { + .show = sl2sc_attr_show, +}; + +static struct kobj_type hfi1_sl2sc_ktype = { + .release = port_release, + .sysfs_ops = &hfi1_sl2sc_ops, + .default_attrs = sl2sc_default_attributes +}; + +/* End sl2sc */ + +/* Start vl2mtu */ + +#define HFI1_VL2MTU_ATTR(N) \ + static struct hfi1_vl2mtu_attr hfi1_vl2mtu_attr_##N = { \ + .attr = { .name = __stringify(N), .mode = 0444 }, \ + .vl = N \ + } + +struct hfi1_vl2mtu_attr { + struct attribute attr; + int vl; +}; + +HFI1_VL2MTU_ATTR(0); +HFI1_VL2MTU_ATTR(1); +HFI1_VL2MTU_ATTR(2); +HFI1_VL2MTU_ATTR(3); +HFI1_VL2MTU_ATTR(4); +HFI1_VL2MTU_ATTR(5); +HFI1_VL2MTU_ATTR(6); +HFI1_VL2MTU_ATTR(7); +HFI1_VL2MTU_ATTR(8); +HFI1_VL2MTU_ATTR(9); +HFI1_VL2MTU_ATTR(10); +HFI1_VL2MTU_ATTR(11); +HFI1_VL2MTU_ATTR(12); +HFI1_VL2MTU_ATTR(13); +HFI1_VL2MTU_ATTR(14); +HFI1_VL2MTU_ATTR(15); + +static struct attribute *vl2mtu_default_attributes[] = { + &hfi1_vl2mtu_attr_0.attr, + &hfi1_vl2mtu_attr_1.attr, + &hfi1_vl2mtu_attr_2.attr, + &hfi1_vl2mtu_attr_3.attr, + &hfi1_vl2mtu_attr_4.attr, + &hfi1_vl2mtu_attr_5.attr, + &hfi1_vl2mtu_attr_6.attr, + &hfi1_vl2mtu_attr_7.attr, + &hfi1_vl2mtu_attr_8.attr, + &hfi1_vl2mtu_attr_9.attr, + &hfi1_vl2mtu_attr_10.attr, + &hfi1_vl2mtu_attr_11.attr, + &hfi1_vl2mtu_attr_12.attr, + &hfi1_vl2mtu_attr_13.attr, + &hfi1_vl2mtu_attr_14.attr, + &hfi1_vl2mtu_attr_15.attr, + NULL +}; + +static ssize_t vl2mtu_attr_show(struct kobject *kobj, struct attribute *attr, + char *buf) +{ + struct hfi1_vl2mtu_attr *vlattr = + container_of(attr, struct hfi1_vl2mtu_attr, attr); + struct hfi1_pportdata *ppd = + container_of(kobj, struct hfi1_pportdata, vl2mtu_kobj); + struct hfi1_devdata *dd = ppd->dd; + + return sprintf(buf, "%u\n", dd->vld[vlattr->vl].mtu); +} + +static const struct sysfs_ops hfi1_vl2mtu_ops = { + .show = vl2mtu_attr_show, +}; + +static struct kobj_type hfi1_vl2mtu_ktype = { + .release = port_release, + .sysfs_ops = &hfi1_vl2mtu_ops, + .default_attrs = vl2mtu_default_attributes +}; + + +/* end of per-port file structures and support code */ + +/* + * Start of per-unit (or driver, in some cases, but replicated + * per unit) functions (these get a device *) + */ +static ssize_t show_rev(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + + return sprintf(buf, "%x\n", dd_from_dev(dev)->minrev); +} + +static ssize_t show_hfi(struct device *device, struct device_attribute *attr, + char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + int ret; + + if (!dd->boardname) + ret = -EINVAL; + else + ret = scnprintf(buf, PAGE_SIZE, "%s\n", dd->boardname); + return ret; +} + +static ssize_t show_boardversion(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + + /* The string printed here is already newline-terminated. */ + return scnprintf(buf, PAGE_SIZE, "%s", dd->boardversion); +} + + +static ssize_t show_nctxts(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + + /* + * Return the smaller of send and receive contexts. + * Normally, user level applications would require both a send + * and a receive context, so returning the smaller of the two counts + * give a more accurate picture of total contexts available. + */ + return scnprintf(buf, PAGE_SIZE, "%u\n", + min(dd->num_rcv_contexts - dd->first_user_ctxt, + (u32)dd->sc_sizes[SC_USER].count)); +} + +static ssize_t show_nfreectxts(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + + /* Return the number of free user ports (contexts) available. */ + return scnprintf(buf, PAGE_SIZE, "%u\n", dd->freectxts); +} + +static ssize_t show_serial(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + + return scnprintf(buf, PAGE_SIZE, "%s", dd->serial); + +} + +static ssize_t store_chip_reset(struct device *device, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + int ret; + + if (count < 5 || memcmp(buf, "reset", 5) || !dd->diag_client) { + ret = -EINVAL; + goto bail; + } + + ret = hfi1_reset_device(dd->unit); +bail: + return ret < 0 ? ret : count; +} + +/* + * Convert the reported temperature from an integer (reported in + * units of 0.25C) to a floating point number. + */ +#define temp2str(temp, buf, size, idx) \ + scnprintf((buf) + (idx), (size) - (idx), "%u.%02u ", \ + ((temp) >> 2), ((temp) & 0x3) * 25) + +/* + * Dump tempsense values, in decimal, to ease shell-scripts. + */ +static ssize_t show_tempsense(struct device *device, + struct device_attribute *attr, char *buf) +{ + struct hfi1_ibdev *dev = + container_of(device, struct hfi1_ibdev, ibdev.dev); + struct hfi1_devdata *dd = dd_from_dev(dev); + struct hfi1_temp temp; + int ret = -ENXIO; + + ret = hfi1_tempsense_rd(dd, &temp); + if (!ret) { + int idx = 0; + + idx += temp2str(temp.curr, buf, PAGE_SIZE, idx); + idx += temp2str(temp.lo_lim, buf, PAGE_SIZE, idx); + idx += temp2str(temp.hi_lim, buf, PAGE_SIZE, idx); + idx += temp2str(temp.crit_lim, buf, PAGE_SIZE, idx); + idx += scnprintf(buf + idx, PAGE_SIZE - idx, + "%u %u %u\n", temp.triggers & 0x1, + temp.triggers & 0x2, temp.triggers & 0x4); + ret = idx; + } + return ret; +} + +/* + * end of per-unit (or driver, in some cases, but replicated + * per unit) functions + */ + +/* start of per-unit file structures and support code */ +static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static DEVICE_ATTR(board_id, S_IRUGO, show_hfi, NULL); +static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL); +static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL); +static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL); +static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL); +static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL); +static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset); + +static struct device_attribute *hfi1_attributes[] = { + &dev_attr_hw_rev, + &dev_attr_board_id, + &dev_attr_nctxts, + &dev_attr_nfreectxts, + &dev_attr_serial, + &dev_attr_boardversion, + &dev_attr_tempsense, + &dev_attr_chip_reset, +}; + +int hfi1_create_port_files(struct ib_device *ibdev, u8 port_num, + struct kobject *kobj) +{ + struct hfi1_pportdata *ppd; + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + int ret; + + if (!port_num || port_num > dd->num_pports) { + dd_dev_err(dd, + "Skipping infiniband class with invalid port %u\n", + port_num); + return -ENODEV; + } + ppd = &dd->pport[port_num - 1]; + + ret = kobject_init_and_add(&ppd->sc2vl_kobj, &hfi1_sc2vl_ktype, kobj, + "sc2vl"); + if (ret) { + dd_dev_err(dd, + "Skipping sc2vl sysfs info, (err %d) port %u\n", + ret, port_num); + goto bail; + } + kobject_uevent(&ppd->sc2vl_kobj, KOBJ_ADD); + + ret = kobject_init_and_add(&ppd->sl2sc_kobj, &hfi1_sl2sc_ktype, kobj, + "sl2sc"); + if (ret) { + dd_dev_err(dd, + "Skipping sl2sc sysfs info, (err %d) port %u\n", + ret, port_num); + goto bail_sc2vl; + } + kobject_uevent(&ppd->sl2sc_kobj, KOBJ_ADD); + + ret = kobject_init_and_add(&ppd->vl2mtu_kobj, &hfi1_vl2mtu_ktype, kobj, + "vl2mtu"); + if (ret) { + dd_dev_err(dd, + "Skipping vl2mtu sysfs info, (err %d) port %u\n", + ret, port_num); + goto bail_sl2sc; + } + kobject_uevent(&ppd->vl2mtu_kobj, KOBJ_ADD); + + + ret = kobject_init_and_add(&ppd->pport_cc_kobj, &port_cc_ktype, + kobj, "CCMgtA"); + if (ret) { + dd_dev_err(dd, + "Skipping Congestion Control sysfs info, (err %d) port %u\n", + ret, port_num); + goto bail_vl2mtu; + } + + kobject_uevent(&ppd->pport_cc_kobj, KOBJ_ADD); + + ret = sysfs_create_bin_file(&ppd->pport_cc_kobj, + &cc_setting_bin_attr); + if (ret) { + dd_dev_err(dd, + "Skipping Congestion Control setting sysfs info, (err %d) port %u\n", + ret, port_num); + goto bail_cc; + } + + ret = sysfs_create_bin_file(&ppd->pport_cc_kobj, + &cc_table_bin_attr); + if (ret) { + dd_dev_err(dd, + "Skipping Congestion Control table sysfs info, (err %d) port %u\n", + ret, port_num); + goto bail_cc_entry_bin; + } + + dd_dev_info(dd, + "IB%u: Congestion Control Agent enabled for port %d\n", + dd->unit, port_num); + + return 0; + +bail_cc_entry_bin: + sysfs_remove_bin_file(&ppd->pport_cc_kobj, + &cc_setting_bin_attr); +bail_cc: + kobject_put(&ppd->pport_cc_kobj); +bail_vl2mtu: + kobject_put(&ppd->vl2mtu_kobj); +bail_sl2sc: + kobject_put(&ppd->sl2sc_kobj); +bail_sc2vl: + kobject_put(&ppd->sc2vl_kobj); +bail: + return ret; +} + +/* + * Register and create our files in /sys/class/infiniband. + */ +int hfi1_verbs_register_sysfs(struct hfi1_devdata *dd) +{ + struct ib_device *dev = &dd->verbs_dev.ibdev; + int i, ret; + + for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i) { + ret = device_create_file(&dev->dev, hfi1_attributes[i]); + if (ret) + goto bail; + } + + return 0; +bail: + for (i = 0; i < ARRAY_SIZE(hfi1_attributes); ++i) + device_remove_file(&dev->dev, hfi1_attributes[i]); + return ret; +} + +/* + * Unregister and remove our files in /sys/class/infiniband. + */ +void hfi1_verbs_unregister_sysfs(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd; + int i; + + for (i = 0; i < dd->num_pports; i++) { + ppd = &dd->pport[i]; + + sysfs_remove_bin_file(&ppd->pport_cc_kobj, + &cc_setting_bin_attr); + sysfs_remove_bin_file(&ppd->pport_cc_kobj, + &cc_table_bin_attr); + kobject_put(&ppd->pport_cc_kobj); + kobject_put(&ppd->vl2mtu_kobj); + kobject_put(&ppd->sl2sc_kobj); + kobject_put(&ppd->sc2vl_kobj); + } +} diff --git a/drivers/staging/rdma/hfi1/trace.c b/drivers/staging/rdma/hfi1/trace.c new file mode 100644 index 0000000000000..70ad7b9fc1ce9 --- /dev/null +++ b/drivers/staging/rdma/hfi1/trace.c @@ -0,0 +1,221 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#define CREATE_TRACE_POINTS +#include "trace.h" + +u8 ibhdr_exhdr_len(struct hfi1_ib_header *hdr) +{ + struct hfi1_other_headers *ohdr; + u8 opcode; + u8 lnh = (u8)(be16_to_cpu(hdr->lrh[0]) & 3); + + if (lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else + ohdr = &hdr->u.l.oth; + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + return hdr_len_by_opcode[opcode] == 0 ? + 0 : hdr_len_by_opcode[opcode] - (12 + 8); +} + +#define IMM_PRN "imm %d" +#define RETH_PRN "reth vaddr 0x%.16llx rkey 0x%.8x dlen 0x%.8x" +#define AETH_PRN "aeth syn 0x%.2x msn 0x%.8x" +#define DETH_PRN "deth qkey 0x%.8x sqpn 0x%.6x" +#define ATOMICACKETH_PRN "origdata %lld" +#define ATOMICETH_PRN "vaddr 0x%llx rkey 0x%.8x sdata %lld cdata %lld" + +#define OP(transport, op) IB_OPCODE_## transport ## _ ## op + +static u64 ib_u64_get(__be32 *p) +{ + return ((u64)be32_to_cpu(p[0]) << 32) | be32_to_cpu(p[1]); +} + +const char *parse_everbs_hdrs( + struct trace_seq *p, + u8 opcode, + void *ehdrs) +{ + union ib_ehdrs *eh = ehdrs; + const char *ret = trace_seq_buffer_ptr(p); + + switch (opcode) { + /* imm */ + case OP(RC, SEND_LAST_WITH_IMMEDIATE): + case OP(UC, SEND_LAST_WITH_IMMEDIATE): + case OP(RC, SEND_ONLY_WITH_IMMEDIATE): + case OP(UC, SEND_ONLY_WITH_IMMEDIATE): + case OP(RC, RDMA_WRITE_LAST_WITH_IMMEDIATE): + case OP(UC, RDMA_WRITE_LAST_WITH_IMMEDIATE): + trace_seq_printf(p, IMM_PRN, + be32_to_cpu(eh->imm_data)); + break; + /* reth + imm */ + case OP(RC, RDMA_WRITE_ONLY_WITH_IMMEDIATE): + case OP(UC, RDMA_WRITE_ONLY_WITH_IMMEDIATE): + trace_seq_printf(p, RETH_PRN " " IMM_PRN, + (unsigned long long)ib_u64_get( + (__be32 *)&eh->rc.reth.vaddr), + be32_to_cpu(eh->rc.reth.rkey), + be32_to_cpu(eh->rc.reth.length), + be32_to_cpu(eh->rc.imm_data)); + break; + /* reth */ + case OP(RC, RDMA_READ_REQUEST): + case OP(RC, RDMA_WRITE_FIRST): + case OP(UC, RDMA_WRITE_FIRST): + case OP(RC, RDMA_WRITE_ONLY): + case OP(UC, RDMA_WRITE_ONLY): + trace_seq_printf(p, RETH_PRN, + (unsigned long long)ib_u64_get( + (__be32 *)&eh->rc.reth.vaddr), + be32_to_cpu(eh->rc.reth.rkey), + be32_to_cpu(eh->rc.reth.length)); + break; + case OP(RC, RDMA_READ_RESPONSE_FIRST): + case OP(RC, RDMA_READ_RESPONSE_LAST): + case OP(RC, RDMA_READ_RESPONSE_ONLY): + case OP(RC, ACKNOWLEDGE): + trace_seq_printf(p, AETH_PRN, + be32_to_cpu(eh->aeth) >> 24, + be32_to_cpu(eh->aeth) & HFI1_QPN_MASK); + break; + /* aeth + atomicacketh */ + case OP(RC, ATOMIC_ACKNOWLEDGE): + trace_seq_printf(p, AETH_PRN " " ATOMICACKETH_PRN, + (be32_to_cpu(eh->at.aeth) >> 24) & 0xff, + be32_to_cpu(eh->at.aeth) & HFI1_QPN_MASK, + (unsigned long long)ib_u64_get(eh->at.atomic_ack_eth)); + break; + /* atomiceth */ + case OP(RC, COMPARE_SWAP): + case OP(RC, FETCH_ADD): + trace_seq_printf(p, ATOMICETH_PRN, + (unsigned long long)ib_u64_get(eh->atomic_eth.vaddr), + eh->atomic_eth.rkey, + (unsigned long long)ib_u64_get( + (__be32 *)&eh->atomic_eth.swap_data), + (unsigned long long) ib_u64_get( + (__be32 *)&eh->atomic_eth.compare_data)); + break; + /* deth */ + case OP(UD, SEND_ONLY): + case OP(UD, SEND_ONLY_WITH_IMMEDIATE): + trace_seq_printf(p, DETH_PRN, + be32_to_cpu(eh->ud.deth[0]), + be32_to_cpu(eh->ud.deth[1]) & HFI1_QPN_MASK); + break; + } + trace_seq_putc(p, 0); + return ret; +} + +const char *parse_sdma_flags( + struct trace_seq *p, + u64 desc0, u64 desc1) +{ + const char *ret = trace_seq_buffer_ptr(p); + char flags[5] = { 'x', 'x', 'x', 'x', 0 }; + + flags[0] = (desc1 & SDMA_DESC1_INT_REQ_FLAG) ? 'I' : '-'; + flags[1] = (desc1 & SDMA_DESC1_HEAD_TO_HOST_FLAG) ? 'H' : '-'; + flags[2] = (desc0 & SDMA_DESC0_FIRST_DESC_FLAG) ? 'F' : '-'; + flags[3] = (desc0 & SDMA_DESC0_LAST_DESC_FLAG) ? 'L' : '-'; + trace_seq_printf(p, "%s", flags); + if (desc0 & SDMA_DESC0_FIRST_DESC_FLAG) + trace_seq_printf(p, " amode:%u aidx:%u alen:%u", + (u8)((desc1 >> SDMA_DESC1_HEADER_MODE_SHIFT) + & SDMA_DESC1_HEADER_MODE_MASK), + (u8)((desc1 >> SDMA_DESC1_HEADER_INDEX_SHIFT) + & SDMA_DESC1_HEADER_INDEX_MASK), + (u8)((desc1 >> SDMA_DESC1_HEADER_DWS_SHIFT) + & SDMA_DESC1_HEADER_DWS_MASK)); + return ret; +} + +const char *print_u32_array( + struct trace_seq *p, + u32 *arr, int len) +{ + int i; + const char *ret = trace_seq_buffer_ptr(p); + + for (i = 0; i < len ; i++) + trace_seq_printf(p, "%s%#x", i == 0 ? "" : " ", arr[i]); + trace_seq_putc(p, 0); + return ret; +} + +const char *print_u64_array( + struct trace_seq *p, + u64 *arr, int len) +{ + int i; + const char *ret = trace_seq_buffer_ptr(p); + + for (i = 0; i < len; i++) + trace_seq_printf(p, "%s0x%016llx", i == 0 ? "" : " ", arr[i]); + trace_seq_putc(p, 0); + return ret; +} + +__hfi1_trace_fn(PKT); +__hfi1_trace_fn(PROC); +__hfi1_trace_fn(SDMA); +__hfi1_trace_fn(LINKVERB); +__hfi1_trace_fn(DEBUG); +__hfi1_trace_fn(SNOOP); +__hfi1_trace_fn(CNTR); +__hfi1_trace_fn(PIO); +__hfi1_trace_fn(DC8051); +__hfi1_trace_fn(FIRMWARE); +__hfi1_trace_fn(RCVCTRL); +__hfi1_trace_fn(TID); diff --git a/drivers/staging/rdma/hfi1/trace.h b/drivers/staging/rdma/hfi1/trace.h new file mode 100644 index 0000000000000..d7851c0a01713 --- /dev/null +++ b/drivers/staging/rdma/hfi1/trace.h @@ -0,0 +1,1409 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#undef TRACE_SYSTEM_VAR +#define TRACE_SYSTEM_VAR hfi1 + +#if !defined(__HFI1_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) +#define __HFI1_TRACE_H + +#include +#include + +#include "hfi.h" +#include "mad.h" +#include "sdma.h" + +#define DD_DEV_ENTRY(dd) __string(dev, dev_name(&(dd)->pcidev->dev)) +#define DD_DEV_ASSIGN(dd) __assign_str(dev, dev_name(&(dd)->pcidev->dev)) + +#define packettype_name(etype) { RHF_RCV_TYPE_##etype, #etype } +#define show_packettype(etype) \ +__print_symbolic(etype, \ + packettype_name(EXPECTED), \ + packettype_name(EAGER), \ + packettype_name(IB), \ + packettype_name(ERROR), \ + packettype_name(BYPASS)) + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_rx + +TRACE_EVENT(hfi1_rcvhdr, + TP_PROTO(struct hfi1_devdata *dd, + u64 eflags, + u32 ctxt, + u32 etype, + u32 hlen, + u32 tlen, + u32 updegr, + u32 etail), + TP_ARGS(dd, ctxt, eflags, etype, hlen, tlen, updegr, etail), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u64, eflags) + __field(u32, ctxt) + __field(u32, etype) + __field(u32, hlen) + __field(u32, tlen) + __field(u32, updegr) + __field(u32, etail) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->eflags = eflags; + __entry->ctxt = ctxt; + __entry->etype = etype; + __entry->hlen = hlen; + __entry->tlen = tlen; + __entry->updegr = updegr; + __entry->etail = etail; + ), + TP_printk( +"[%s] ctxt %d eflags 0x%llx etype %d,%s hlen %d tlen %d updegr %d etail %d", + __get_str(dev), + __entry->ctxt, + __entry->eflags, + __entry->etype, show_packettype(__entry->etype), + __entry->hlen, + __entry->tlen, + __entry->updegr, + __entry->etail + ) +); + +TRACE_EVENT(hfi1_receive_interrupt, + TP_PROTO(struct hfi1_devdata *dd, u32 ctxt), + TP_ARGS(dd, ctxt), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u32, ctxt) + __field(u8, slow_path) + __field(u8, dma_rtail) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->ctxt = ctxt; + if (dd->rcd[ctxt]->do_interrupt == + &handle_receive_interrupt) { + __entry->slow_path = 1; + __entry->dma_rtail = 0xFF; + } else if (dd->rcd[ctxt]->do_interrupt == + &handle_receive_interrupt_dma_rtail){ + __entry->dma_rtail = 1; + __entry->slow_path = 0; + } else if (dd->rcd[ctxt]->do_interrupt == + &handle_receive_interrupt_nodma_rtail) { + __entry->dma_rtail = 0; + __entry->slow_path = 0; + } + ), + TP_printk( + "[%s] ctxt %d SlowPath: %d DmaRtail: %d", + __get_str(dev), + __entry->ctxt, + __entry->slow_path, + __entry->dma_rtail + ) +); + +const char *print_u64_array(struct trace_seq *, u64 *, int); + +TRACE_EVENT(hfi1_exp_tid_map, + TP_PROTO(unsigned ctxt, u16 subctxt, int dir, + unsigned long *maps, u16 count), + TP_ARGS(ctxt, subctxt, dir, maps, count), + TP_STRUCT__entry( + __field(unsigned, ctxt) + __field(u16, subctxt) + __field(int, dir) + __field(u16, count) + __dynamic_array(unsigned long, maps, sizeof(*maps) * count) + ), + TP_fast_assign( + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->dir = dir; + __entry->count = count; + memcpy(__get_dynamic_array(maps), maps, + sizeof(*maps) * count); + ), + TP_printk("[%3u:%02u] %s tidmaps %s", + __entry->ctxt, + __entry->subctxt, + (__entry->dir ? ">" : "<"), + print_u64_array(p, __get_dynamic_array(maps), + __entry->count) + ) + ); + +TRACE_EVENT(hfi1_exp_rcv_set, + TP_PROTO(unsigned ctxt, u16 subctxt, u32 tid, + unsigned long vaddr, u64 phys_addr, void *page), + TP_ARGS(ctxt, subctxt, tid, vaddr, phys_addr, page), + TP_STRUCT__entry( + __field(unsigned, ctxt) + __field(u16, subctxt) + __field(u32, tid) + __field(unsigned long, vaddr) + __field(u64, phys_addr) + __field(void *, page) + ), + TP_fast_assign( + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->tid = tid; + __entry->vaddr = vaddr; + __entry->phys_addr = phys_addr; + __entry->page = page; + ), + TP_printk("[%u:%u] TID %u, vaddrs 0x%lx, physaddr 0x%llx, pgp %p", + __entry->ctxt, + __entry->subctxt, + __entry->tid, + __entry->vaddr, + __entry->phys_addr, + __entry->page + ) + ); + +TRACE_EVENT(hfi1_exp_rcv_free, + TP_PROTO(unsigned ctxt, u16 subctxt, u32 tid, + unsigned long phys, void *page), + TP_ARGS(ctxt, subctxt, tid, phys, page), + TP_STRUCT__entry( + __field(unsigned, ctxt) + __field(u16, subctxt) + __field(u32, tid) + __field(unsigned long, phys) + __field(void *, page) + ), + TP_fast_assign( + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->tid = tid; + __entry->phys = phys; + __entry->page = page; + ), + TP_printk("[%u:%u] freeing TID %u, 0x%lx, pgp %p", + __entry->ctxt, + __entry->subctxt, + __entry->tid, + __entry->phys, + __entry->page + ) + ); +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_tx + +TRACE_EVENT(hfi1_piofree, + TP_PROTO(struct send_context *sc, int extra), + TP_ARGS(sc, extra), + TP_STRUCT__entry( + DD_DEV_ENTRY(sc->dd) + __field(u32, sw_index) + __field(u32, hw_context) + __field(int, extra) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sc->dd); + __entry->sw_index = sc->sw_index; + __entry->hw_context = sc->hw_context; + __entry->extra = extra; + ), + TP_printk( + "[%s] ctxt %u(%u) extra %d", + __get_str(dev), + __entry->sw_index, + __entry->hw_context, + __entry->extra + ) +); + +TRACE_EVENT(hfi1_wantpiointr, + TP_PROTO(struct send_context *sc, u32 needint, u64 credit_ctrl), + TP_ARGS(sc, needint, credit_ctrl), + TP_STRUCT__entry( + DD_DEV_ENTRY(sc->dd) + __field(u32, sw_index) + __field(u32, hw_context) + __field(u32, needint) + __field(u64, credit_ctrl) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sc->dd); + __entry->sw_index = sc->sw_index; + __entry->hw_context = sc->hw_context; + __entry->needint = needint; + __entry->credit_ctrl = credit_ctrl; + ), + TP_printk( + "[%s] ctxt %u(%u) on %d credit_ctrl 0x%llx", + __get_str(dev), + __entry->sw_index, + __entry->hw_context, + __entry->needint, + (unsigned long long)__entry->credit_ctrl + ) +); + +DECLARE_EVENT_CLASS(hfi1_qpsleepwakeup_template, + TP_PROTO(struct hfi1_qp *qp, u32 flags), + TP_ARGS(qp, flags), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device)) + __field(u32, qpn) + __field(u32, flags) + __field(u32, s_flags) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device)) + __entry->flags = flags; + __entry->qpn = qp->ibqp.qp_num; + __entry->s_flags = qp->s_flags; + ), + TP_printk( + "[%s] qpn 0x%x flags 0x%x s_flags 0x%x", + __get_str(dev), + __entry->qpn, + __entry->flags, + __entry->s_flags + ) +); + +DEFINE_EVENT(hfi1_qpsleepwakeup_template, hfi1_qpwakeup, + TP_PROTO(struct hfi1_qp *qp, u32 flags), + TP_ARGS(qp, flags)); + +DEFINE_EVENT(hfi1_qpsleepwakeup_template, hfi1_qpsleep, + TP_PROTO(struct hfi1_qp *qp, u32 flags), + TP_ARGS(qp, flags)); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_qphash +DECLARE_EVENT_CLASS(hfi1_qphash_template, + TP_PROTO(struct hfi1_qp *qp, u32 bucket), + TP_ARGS(qp, bucket), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device)) + __field(u32, qpn) + __field(u32, bucket) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device)) + __entry->qpn = qp->ibqp.qp_num; + __entry->bucket = bucket; + ), + TP_printk( + "[%s] qpn 0x%x bucket %u", + __get_str(dev), + __entry->qpn, + __entry->bucket + ) +); + +DEFINE_EVENT(hfi1_qphash_template, hfi1_qpinsert, + TP_PROTO(struct hfi1_qp *qp, u32 bucket), + TP_ARGS(qp, bucket)); + +DEFINE_EVENT(hfi1_qphash_template, hfi1_qpremove, + TP_PROTO(struct hfi1_qp *qp, u32 bucket), + TP_ARGS(qp, bucket)); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_ibhdrs + +u8 ibhdr_exhdr_len(struct hfi1_ib_header *hdr); +const char *parse_everbs_hdrs( + struct trace_seq *p, + u8 opcode, + void *ehdrs); + +#define __parse_ib_ehdrs(op, ehdrs) parse_everbs_hdrs(p, op, ehdrs) + +const char *parse_sdma_flags( + struct trace_seq *p, + u64 desc0, u64 desc1); + +#define __parse_sdma_flags(desc0, desc1) parse_sdma_flags(p, desc0, desc1) + + +#define lrh_name(lrh) { HFI1_##lrh, #lrh } +#define show_lnh(lrh) \ +__print_symbolic(lrh, \ + lrh_name(LRH_BTH), \ + lrh_name(LRH_GRH)) + +#define ib_opcode_name(opcode) { IB_OPCODE_##opcode, #opcode } +#define show_ib_opcode(opcode) \ +__print_symbolic(opcode, \ + ib_opcode_name(RC_SEND_FIRST), \ + ib_opcode_name(RC_SEND_MIDDLE), \ + ib_opcode_name(RC_SEND_LAST), \ + ib_opcode_name(RC_SEND_LAST_WITH_IMMEDIATE), \ + ib_opcode_name(RC_SEND_ONLY), \ + ib_opcode_name(RC_SEND_ONLY_WITH_IMMEDIATE), \ + ib_opcode_name(RC_RDMA_WRITE_FIRST), \ + ib_opcode_name(RC_RDMA_WRITE_MIDDLE), \ + ib_opcode_name(RC_RDMA_WRITE_LAST), \ + ib_opcode_name(RC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \ + ib_opcode_name(RC_RDMA_WRITE_ONLY), \ + ib_opcode_name(RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \ + ib_opcode_name(RC_RDMA_READ_REQUEST), \ + ib_opcode_name(RC_RDMA_READ_RESPONSE_FIRST), \ + ib_opcode_name(RC_RDMA_READ_RESPONSE_MIDDLE), \ + ib_opcode_name(RC_RDMA_READ_RESPONSE_LAST), \ + ib_opcode_name(RC_RDMA_READ_RESPONSE_ONLY), \ + ib_opcode_name(RC_ACKNOWLEDGE), \ + ib_opcode_name(RC_ATOMIC_ACKNOWLEDGE), \ + ib_opcode_name(RC_COMPARE_SWAP), \ + ib_opcode_name(RC_FETCH_ADD), \ + ib_opcode_name(UC_SEND_FIRST), \ + ib_opcode_name(UC_SEND_MIDDLE), \ + ib_opcode_name(UC_SEND_LAST), \ + ib_opcode_name(UC_SEND_LAST_WITH_IMMEDIATE), \ + ib_opcode_name(UC_SEND_ONLY), \ + ib_opcode_name(UC_SEND_ONLY_WITH_IMMEDIATE), \ + ib_opcode_name(UC_RDMA_WRITE_FIRST), \ + ib_opcode_name(UC_RDMA_WRITE_MIDDLE), \ + ib_opcode_name(UC_RDMA_WRITE_LAST), \ + ib_opcode_name(UC_RDMA_WRITE_LAST_WITH_IMMEDIATE), \ + ib_opcode_name(UC_RDMA_WRITE_ONLY), \ + ib_opcode_name(UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE), \ + ib_opcode_name(UD_SEND_ONLY), \ + ib_opcode_name(UD_SEND_ONLY_WITH_IMMEDIATE)) + + +#define LRH_PRN "vl %d lver %d sl %d lnh %d,%s dlid %.4x len %d slid %.4x" +#define BTH_PRN \ + "op 0x%.2x,%s se %d m %d pad %d tver %d pkey 0x%.4x " \ + "f %d b %d qpn 0x%.6x a %d psn 0x%.8x" +#define EHDR_PRN "%s" + +DECLARE_EVENT_CLASS(hfi1_ibhdr_template, + TP_PROTO(struct hfi1_devdata *dd, + struct hfi1_ib_header *hdr), + TP_ARGS(dd, hdr), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + /* LRH */ + __field(u8, vl) + __field(u8, lver) + __field(u8, sl) + __field(u8, lnh) + __field(u16, dlid) + __field(u16, len) + __field(u16, slid) + /* BTH */ + __field(u8, opcode) + __field(u8, se) + __field(u8, m) + __field(u8, pad) + __field(u8, tver) + __field(u16, pkey) + __field(u8, f) + __field(u8, b) + __field(u32, qpn) + __field(u8, a) + __field(u32, psn) + /* extended headers */ + __dynamic_array(u8, ehdrs, ibhdr_exhdr_len(hdr)) + ), + TP_fast_assign( + struct hfi1_other_headers *ohdr; + + DD_DEV_ASSIGN(dd); + /* LRH */ + __entry->vl = + (u8)(be16_to_cpu(hdr->lrh[0]) >> 12); + __entry->lver = + (u8)(be16_to_cpu(hdr->lrh[0]) >> 8) & 0xf; + __entry->sl = + (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf; + __entry->lnh = + (u8)(be16_to_cpu(hdr->lrh[0]) & 3); + __entry->dlid = + be16_to_cpu(hdr->lrh[1]); + /* allow for larger len */ + __entry->len = + be16_to_cpu(hdr->lrh[2]); + __entry->slid = + be16_to_cpu(hdr->lrh[3]); + /* BTH */ + if (__entry->lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else + ohdr = &hdr->u.l.oth; + __entry->opcode = + (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff; + __entry->se = + (be32_to_cpu(ohdr->bth[0]) >> 23) & 1; + __entry->m = + (be32_to_cpu(ohdr->bth[0]) >> 22) & 1; + __entry->pad = + (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + __entry->tver = + (be32_to_cpu(ohdr->bth[0]) >> 16) & 0xf; + __entry->pkey = + be32_to_cpu(ohdr->bth[0]) & 0xffff; + __entry->f = + (be32_to_cpu(ohdr->bth[1]) >> HFI1_FECN_SHIFT) + & HFI1_FECN_MASK; + __entry->b = + (be32_to_cpu(ohdr->bth[1]) >> HFI1_BECN_SHIFT) + & HFI1_BECN_MASK; + __entry->qpn = + be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK; + __entry->a = + (be32_to_cpu(ohdr->bth[2]) >> 31) & 1; + /* allow for larger PSN */ + __entry->psn = + be32_to_cpu(ohdr->bth[2]) & 0x7fffffff; + /* extended headers */ + memcpy( + __get_dynamic_array(ehdrs), + &ohdr->u, + ibhdr_exhdr_len(hdr)); + ), + TP_printk("[%s] " LRH_PRN " " BTH_PRN " " EHDR_PRN, + __get_str(dev), + /* LRH */ + __entry->vl, + __entry->lver, + __entry->sl, + __entry->lnh, show_lnh(__entry->lnh), + __entry->dlid, + __entry->len, + __entry->slid, + /* BTH */ + __entry->opcode, show_ib_opcode(__entry->opcode), + __entry->se, + __entry->m, + __entry->pad, + __entry->tver, + __entry->pkey, + __entry->f, + __entry->b, + __entry->qpn, + __entry->a, + __entry->psn, + /* extended headers */ + __parse_ib_ehdrs( + __entry->opcode, + (void *)__get_dynamic_array(ehdrs)) + ) +); + +DEFINE_EVENT(hfi1_ibhdr_template, input_ibhdr, + TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr), + TP_ARGS(dd, hdr)); + +DEFINE_EVENT(hfi1_ibhdr_template, output_ibhdr, + TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ib_header *hdr), + TP_ARGS(dd, hdr)); + +#define SNOOP_PRN \ + "slid %.4x dlid %.4x qpn 0x%.6x opcode 0x%.2x,%s " \ + "svc lvl %d pkey 0x%.4x [header = %d bytes] [data = %d bytes]" + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_snoop + + +TRACE_EVENT(snoop_capture, + TP_PROTO(struct hfi1_devdata *dd, + int hdr_len, + struct hfi1_ib_header *hdr, + int data_len, + void *data), + TP_ARGS(dd, hdr_len, hdr, data_len, data), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u16, slid) + __field(u16, dlid) + __field(u32, qpn) + __field(u8, opcode) + __field(u8, sl) + __field(u16, pkey) + __field(u32, hdr_len) + __field(u32, data_len) + __field(u8, lnh) + __dynamic_array(u8, raw_hdr, hdr_len) + __dynamic_array(u8, raw_pkt, data_len) + ), + TP_fast_assign( + struct hfi1_other_headers *ohdr; + + __entry->lnh = (u8)(be16_to_cpu(hdr->lrh[0]) & 3); + if (__entry->lnh == HFI1_LRH_BTH) + ohdr = &hdr->u.oth; + else + ohdr = &hdr->u.l.oth; + DD_DEV_ASSIGN(dd); + __entry->slid = be16_to_cpu(hdr->lrh[3]); + __entry->dlid = be16_to_cpu(hdr->lrh[1]); + __entry->qpn = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK; + __entry->opcode = (be32_to_cpu(ohdr->bth[0]) >> 24) & 0xff; + __entry->sl = (u8)(be16_to_cpu(hdr->lrh[0]) >> 4) & 0xf; + __entry->pkey = be32_to_cpu(ohdr->bth[0]) & 0xffff; + __entry->hdr_len = hdr_len; + __entry->data_len = data_len; + memcpy(__get_dynamic_array(raw_hdr), hdr, hdr_len); + memcpy(__get_dynamic_array(raw_pkt), data, data_len); + ), + TP_printk("[%s] " SNOOP_PRN, + __get_str(dev), + __entry->slid, + __entry->dlid, + __entry->qpn, + __entry->opcode, + show_ib_opcode(__entry->opcode), + __entry->sl, + __entry->pkey, + __entry->hdr_len, + __entry->data_len + ) +); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_ctxts + +#define UCTXT_FMT \ + "cred:%u, credaddr:0x%llx, piobase:0x%llx, rcvhdr_cnt:%u, " \ + "rcvbase:0x%llx, rcvegrc:%u, rcvegrb:0x%llx" +TRACE_EVENT(hfi1_uctxtdata, + TP_PROTO(struct hfi1_devdata *dd, struct hfi1_ctxtdata *uctxt), + TP_ARGS(dd, uctxt), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(unsigned, ctxt) + __field(u32, credits) + __field(u64, hw_free) + __field(u64, piobase) + __field(u16, rcvhdrq_cnt) + __field(u64, rcvhdrq_phys) + __field(u32, eager_cnt) + __field(u64, rcvegr_phys) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->ctxt = uctxt->ctxt; + __entry->credits = uctxt->sc->credits; + __entry->hw_free = (u64)uctxt->sc->hw_free; + __entry->piobase = (u64)uctxt->sc->base_addr; + __entry->rcvhdrq_cnt = uctxt->rcvhdrq_cnt; + __entry->rcvhdrq_phys = uctxt->rcvhdrq_phys; + __entry->eager_cnt = uctxt->egrbufs.alloced; + __entry->rcvegr_phys = uctxt->egrbufs.rcvtids[0].phys; + ), + TP_printk( + "[%s] ctxt %u " UCTXT_FMT, + __get_str(dev), + __entry->ctxt, + __entry->credits, + __entry->hw_free, + __entry->piobase, + __entry->rcvhdrq_cnt, + __entry->rcvhdrq_phys, + __entry->eager_cnt, + __entry->rcvegr_phys + ) + ); + +#define CINFO_FMT \ + "egrtids:%u, egr_size:%u, hdrq_cnt:%u, hdrq_size:%u, sdma_ring_size:%u" +TRACE_EVENT(hfi1_ctxt_info, + TP_PROTO(struct hfi1_devdata *dd, unsigned ctxt, unsigned subctxt, + struct hfi1_ctxt_info cinfo), + TP_ARGS(dd, ctxt, subctxt, cinfo), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(unsigned, ctxt) + __field(unsigned, subctxt) + __field(u16, egrtids) + __field(u16, rcvhdrq_cnt) + __field(u16, rcvhdrq_size) + __field(u16, sdma_ring_size) + __field(u32, rcvegr_size) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->egrtids = cinfo.egrtids; + __entry->rcvhdrq_cnt = cinfo.rcvhdrq_cnt; + __entry->rcvhdrq_size = cinfo.rcvhdrq_entsize; + __entry->sdma_ring_size = cinfo.sdma_ring_size; + __entry->rcvegr_size = cinfo.rcvegr_size; + ), + TP_printk( + "[%s] ctxt %u:%u " CINFO_FMT, + __get_str(dev), + __entry->ctxt, + __entry->subctxt, + __entry->egrtids, + __entry->rcvegr_size, + __entry->rcvhdrq_cnt, + __entry->rcvhdrq_size, + __entry->sdma_ring_size + ) + ); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_sma + +#define BCT_FORMAT \ + "shared_limit %x vls 0-7 [%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x][%x,%x] 15 [%x,%x]" + +#define BCT(field) \ + be16_to_cpu( \ + ((struct buffer_control *)__get_dynamic_array(bct))->field \ + ) + +DECLARE_EVENT_CLASS(hfi1_bct_template, + TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc), + TP_ARGS(dd, bc), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __dynamic_array(u8, bct, sizeof(*bc)) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + memcpy( + __get_dynamic_array(bct), + bc, + sizeof(*bc)); + ), + TP_printk(BCT_FORMAT, + BCT(overall_shared_limit), + + BCT(vl[0].dedicated), + BCT(vl[0].shared), + + BCT(vl[1].dedicated), + BCT(vl[1].shared), + + BCT(vl[2].dedicated), + BCT(vl[2].shared), + + BCT(vl[3].dedicated), + BCT(vl[3].shared), + + BCT(vl[4].dedicated), + BCT(vl[4].shared), + + BCT(vl[5].dedicated), + BCT(vl[5].shared), + + BCT(vl[6].dedicated), + BCT(vl[6].shared), + + BCT(vl[7].dedicated), + BCT(vl[7].shared), + + BCT(vl[15].dedicated), + BCT(vl[15].shared) + ) +); + + +DEFINE_EVENT(hfi1_bct_template, bct_set, + TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc), + TP_ARGS(dd, bc)); + +DEFINE_EVENT(hfi1_bct_template, bct_get, + TP_PROTO(struct hfi1_devdata *dd, struct buffer_control *bc), + TP_ARGS(dd, bc)); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_sdma + +TRACE_EVENT(hfi1_sdma_descriptor, + TP_PROTO( + struct sdma_engine *sde, + u64 desc0, + u64 desc1, + u16 e, + void *descp), + TP_ARGS(sde, desc0, desc1, e, descp), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __field(void *, descp) + __field(u64, desc0) + __field(u64, desc1) + __field(u16, e) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __entry->desc0 = desc0; + __entry->desc1 = desc1; + __entry->idx = sde->this_idx; + __entry->descp = descp; + __entry->e = e; + ), + TP_printk( + "[%s] SDE(%u) flags:%s addr:0x%016llx gen:%u len:%u d0:%016llx d1:%016llx to %p,%u", + __get_str(dev), + __entry->idx, + __parse_sdma_flags(__entry->desc0, __entry->desc1), + (__entry->desc0 >> SDMA_DESC0_PHY_ADDR_SHIFT) + & SDMA_DESC0_PHY_ADDR_MASK, + (u8)((__entry->desc1 >> SDMA_DESC1_GENERATION_SHIFT) + & SDMA_DESC1_GENERATION_MASK), + (u16)((__entry->desc0 >> SDMA_DESC0_BYTE_COUNT_SHIFT) + & SDMA_DESC0_BYTE_COUNT_MASK), + __entry->desc0, + __entry->desc1, + __entry->descp, + __entry->e + ) +); + +TRACE_EVENT(hfi1_sdma_engine_select, + TP_PROTO(struct hfi1_devdata *dd, u32 sel, u8 vl, u8 idx), + TP_ARGS(dd, sel, vl, idx), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u32, sel) + __field(u8, vl) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->sel = sel; + __entry->vl = vl; + __entry->idx = idx; + ), + TP_printk( + "[%s] selecting SDE %u sel 0x%x vl %u", + __get_str(dev), + __entry->idx, + __entry->sel, + __entry->vl + ) +); + +DECLARE_EVENT_CLASS(hfi1_sdma_engine_class, + TP_PROTO( + struct sdma_engine *sde, + u64 status + ), + TP_ARGS(sde, status), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __field(u64, status) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __entry->status = status; + __entry->idx = sde->this_idx; + ), + TP_printk( + "[%s] SDE(%u) status %llx", + __get_str(dev), + __entry->idx, + (unsigned long long)__entry->status + ) +); + +DEFINE_EVENT(hfi1_sdma_engine_class, hfi1_sdma_engine_interrupt, + TP_PROTO( + struct sdma_engine *sde, + u64 status + ), + TP_ARGS(sde, status) +); + +DEFINE_EVENT(hfi1_sdma_engine_class, hfi1_sdma_engine_progress, + TP_PROTO( + struct sdma_engine *sde, + u64 status + ), + TP_ARGS(sde, status) +); + +DECLARE_EVENT_CLASS(hfi1_sdma_ahg_ad, + TP_PROTO( + struct sdma_engine *sde, + int aidx + ), + TP_ARGS(sde, aidx), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __field(int, aidx) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __entry->idx = sde->this_idx; + __entry->aidx = aidx; + ), + TP_printk( + "[%s] SDE(%u) aidx %d", + __get_str(dev), + __entry->idx, + __entry->aidx + ) +); + +DEFINE_EVENT(hfi1_sdma_ahg_ad, hfi1_ahg_allocate, + TP_PROTO( + struct sdma_engine *sde, + int aidx + ), + TP_ARGS(sde, aidx)); + +DEFINE_EVENT(hfi1_sdma_ahg_ad, hfi1_ahg_deallocate, + TP_PROTO( + struct sdma_engine *sde, + int aidx + ), + TP_ARGS(sde, aidx)); + +#ifdef CONFIG_HFI1_DEBUG_SDMA_ORDER +TRACE_EVENT(hfi1_sdma_progress, + TP_PROTO( + struct sdma_engine *sde, + u16 hwhead, + u16 swhead, + struct sdma_txreq *txp + ), + TP_ARGS(sde, hwhead, swhead, txp), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __field(u64, sn) + __field(u16, hwhead) + __field(u16, swhead) + __field(u16, txnext) + __field(u16, tx_tail) + __field(u16, tx_head) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __entry->hwhead = hwhead; + __entry->swhead = swhead; + __entry->tx_tail = sde->tx_tail; + __entry->tx_head = sde->tx_head; + __entry->txnext = txp ? txp->next_descq_idx : ~0; + __entry->idx = sde->this_idx; + __entry->sn = txp ? txp->sn : ~0; + ), + TP_printk( + "[%s] SDE(%u) sn %llu hwhead %u swhead %u next_descq_idx %u tx_head %u tx_tail %u", + __get_str(dev), + __entry->idx, + __entry->sn, + __entry->hwhead, + __entry->swhead, + __entry->txnext, + __entry->tx_head, + __entry->tx_tail + ) +); +#else +TRACE_EVENT(hfi1_sdma_progress, + TP_PROTO( + struct sdma_engine *sde, + u16 hwhead, + u16 swhead, + struct sdma_txreq *txp + ), + TP_ARGS(sde, hwhead, swhead, txp), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __field(u16, hwhead) + __field(u16, swhead) + __field(u16, txnext) + __field(u16, tx_tail) + __field(u16, tx_head) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __entry->hwhead = hwhead; + __entry->swhead = swhead; + __entry->tx_tail = sde->tx_tail; + __entry->tx_head = sde->tx_head; + __entry->txnext = txp ? txp->next_descq_idx : ~0; + __entry->idx = sde->this_idx; + ), + TP_printk( + "[%s] SDE(%u) hwhead %u swhead %u next_descq_idx %u tx_head %u tx_tail %u", + __get_str(dev), + __entry->idx, + __entry->hwhead, + __entry->swhead, + __entry->txnext, + __entry->tx_head, + __entry->tx_tail + ) +); +#endif + +DECLARE_EVENT_CLASS(hfi1_sdma_sn, + TP_PROTO( + struct sdma_engine *sde, + u64 sn + ), + TP_ARGS(sde, sn), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __field(u64, sn) + __field(u8, idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __entry->sn = sn; + __entry->idx = sde->this_idx; + ), + TP_printk( + "[%s] SDE(%u) sn %llu", + __get_str(dev), + __entry->idx, + __entry->sn + ) +); + +DEFINE_EVENT(hfi1_sdma_sn, hfi1_sdma_out_sn, + TP_PROTO( + struct sdma_engine *sde, + u64 sn + ), + TP_ARGS(sde, sn) +); + +DEFINE_EVENT(hfi1_sdma_sn, hfi1_sdma_in_sn, + TP_PROTO( + struct sdma_engine *sde, + u64 sn + ), + TP_ARGS(sde, sn) +); + +#define USDMA_HDR_FORMAT \ + "[%s:%u:%u:%u] PBC=(0x%x 0x%x) LRH=(0x%x 0x%x) BTH=(0x%x 0x%x 0x%x) KDETH=(0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x) TIDVal=0x%x" + +TRACE_EVENT(hfi1_sdma_user_header, + TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 req, + struct hfi1_pkt_header *hdr, u32 tidval), + TP_ARGS(dd, ctxt, subctxt, req, hdr, tidval), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u16, ctxt) + __field(u8, subctxt) + __field(u16, req) + __field(__le32, pbc0) + __field(__le32, pbc1) + __field(__be32, lrh0) + __field(__be32, lrh1) + __field(__be32, bth0) + __field(__be32, bth1) + __field(__be32, bth2) + __field(__le32, kdeth0) + __field(__le32, kdeth1) + __field(__le32, kdeth2) + __field(__le32, kdeth3) + __field(__le32, kdeth4) + __field(__le32, kdeth5) + __field(__le32, kdeth6) + __field(__le32, kdeth7) + __field(__le32, kdeth8) + __field(u32, tidval) + ), + TP_fast_assign( + __le32 *pbc = (__le32 *)hdr->pbc; + __be32 *lrh = (__be32 *)hdr->lrh; + __be32 *bth = (__be32 *)hdr->bth; + __le32 *kdeth = (__le32 *)&hdr->kdeth; + + DD_DEV_ASSIGN(dd); + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->req = req; + __entry->pbc0 = pbc[0]; + __entry->pbc1 = pbc[1]; + __entry->lrh0 = be32_to_cpu(lrh[0]); + __entry->lrh1 = be32_to_cpu(lrh[1]); + __entry->bth0 = be32_to_cpu(bth[0]); + __entry->bth1 = be32_to_cpu(bth[1]); + __entry->bth2 = be32_to_cpu(bth[2]); + __entry->kdeth0 = kdeth[0]; + __entry->kdeth1 = kdeth[1]; + __entry->kdeth2 = kdeth[2]; + __entry->kdeth3 = kdeth[3]; + __entry->kdeth4 = kdeth[4]; + __entry->kdeth5 = kdeth[5]; + __entry->kdeth6 = kdeth[6]; + __entry->kdeth7 = kdeth[7]; + __entry->kdeth8 = kdeth[8]; + __entry->tidval = tidval; + ), + TP_printk(USDMA_HDR_FORMAT, + __get_str(dev), + __entry->ctxt, + __entry->subctxt, + __entry->req, + __entry->pbc1, + __entry->pbc0, + __entry->lrh0, + __entry->lrh1, + __entry->bth0, + __entry->bth1, + __entry->bth2, + __entry->kdeth0, + __entry->kdeth1, + __entry->kdeth2, + __entry->kdeth3, + __entry->kdeth4, + __entry->kdeth5, + __entry->kdeth6, + __entry->kdeth7, + __entry->kdeth8, + __entry->tidval + ) + ); + +#define SDMA_UREQ_FMT \ + "[%s:%u:%u] ver/op=0x%x, iovcnt=%u, npkts=%u, frag=%u, idx=%u" +TRACE_EVENT(hfi1_sdma_user_reqinfo, + TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 *i), + TP_ARGS(dd, ctxt, subctxt, i), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd); + __field(u16, ctxt) + __field(u8, subctxt) + __field(u8, ver_opcode) + __field(u8, iovcnt) + __field(u16, npkts) + __field(u16, fragsize) + __field(u16, comp_idx) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->ver_opcode = i[0] & 0xff; + __entry->iovcnt = (i[0] >> 8) & 0xff; + __entry->npkts = i[1]; + __entry->fragsize = i[2]; + __entry->comp_idx = i[3]; + ), + TP_printk(SDMA_UREQ_FMT, + __get_str(dev), + __entry->ctxt, + __entry->subctxt, + __entry->ver_opcode, + __entry->iovcnt, + __entry->npkts, + __entry->fragsize, + __entry->comp_idx + ) + ); + +#define usdma_complete_name(st) { st, #st } +#define show_usdma_complete_state(st) \ + __print_symbolic(st, \ + usdma_complete_name(FREE), \ + usdma_complete_name(QUEUED), \ + usdma_complete_name(COMPLETE), \ + usdma_complete_name(ERROR)) + +TRACE_EVENT(hfi1_sdma_user_completion, + TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 idx, + u8 state, int code), + TP_ARGS(dd, ctxt, subctxt, idx, state, code), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u16, ctxt) + __field(u8, subctxt) + __field(u16, idx) + __field(u8, state) + __field(int, code) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->idx = idx; + __entry->state = state; + __entry->code = code; + ), + TP_printk("[%s:%u:%u:%u] SDMA completion state %s (%d)", + __get_str(dev), __entry->ctxt, __entry->subctxt, + __entry->idx, show_usdma_complete_state(__entry->state), + __entry->code) + ); + +const char *print_u32_array(struct trace_seq *, u32 *, int); +#define __print_u32_hex(arr, len) print_u32_array(p, arr, len) + +TRACE_EVENT(hfi1_sdma_user_header_ahg, + TP_PROTO(struct hfi1_devdata *dd, u16 ctxt, u8 subctxt, u16 req, + u8 sde, u8 ahgidx, u32 *ahg, int len, u32 tidval), + TP_ARGS(dd, ctxt, subctxt, req, sde, ahgidx, ahg, len, tidval), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __field(u16, ctxt) + __field(u8, subctxt) + __field(u16, req) + __field(u8, sde) + __field(u8, idx) + __field(int, len) + __field(u32, tidval) + __array(u32, ahg, 10) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd); + __entry->ctxt = ctxt; + __entry->subctxt = subctxt; + __entry->req = req; + __entry->sde = sde; + __entry->idx = ahgidx; + __entry->len = len; + __entry->tidval = tidval; + memcpy(__entry->ahg, ahg, len * sizeof(u32)); + ), + TP_printk("[%s:%u:%u:%u] (SDE%u/AHG%u) ahg[0-%d]=(%s) TIDVal=0x%x", + __get_str(dev), + __entry->ctxt, + __entry->subctxt, + __entry->req, + __entry->sde, + __entry->idx, + __entry->len - 1, + __print_u32_hex(__entry->ahg, __entry->len), + __entry->tidval + ) + ); + +TRACE_EVENT(hfi1_sdma_state, + TP_PROTO( + struct sdma_engine *sde, + const char *cstate, + const char *nstate + ), + TP_ARGS(sde, cstate, nstate), + TP_STRUCT__entry( + DD_DEV_ENTRY(sde->dd) + __string(curstate, cstate) + __string(newstate, nstate) + ), + TP_fast_assign( + DD_DEV_ASSIGN(sde->dd); + __assign_str(curstate, cstate); + __assign_str(newstate, nstate); + ), + TP_printk("[%s] current state %s new state %s", + __get_str(dev), + __get_str(curstate), + __get_str(newstate) + ) +); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_rc + +DECLARE_EVENT_CLASS(hfi1_sdma_rc, + TP_PROTO(struct hfi1_qp *qp, u32 psn), + TP_ARGS(qp, psn), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd_from_ibdev(qp->ibqp.device)) + __field(u32, qpn) + __field(u32, flags) + __field(u32, psn) + __field(u32, sending_psn) + __field(u32, sending_hpsn) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd_from_ibdev(qp->ibqp.device)) + __entry->qpn = qp->ibqp.qp_num; + __entry->flags = qp->s_flags; + __entry->psn = psn; + __entry->sending_psn = qp->s_sending_psn; + __entry->sending_hpsn = qp->s_sending_hpsn; + ), + TP_printk( + "[%s] qpn 0x%x flags 0x%x psn 0x%x sending_psn 0x%x sending_hpsn 0x%x", + __get_str(dev), + __entry->qpn, + __entry->flags, + __entry->psn, + __entry->sending_psn, + __entry->sending_psn + ) +); + +DEFINE_EVENT(hfi1_sdma_rc, hfi1_rc_sendcomplete, + TP_PROTO(struct hfi1_qp *qp, u32 psn), + TP_ARGS(qp, psn) +); + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_misc + +TRACE_EVENT(hfi1_interrupt, + TP_PROTO(struct hfi1_devdata *dd, const struct is_table *is_entry, + int src), + TP_ARGS(dd, is_entry, src), + TP_STRUCT__entry( + DD_DEV_ENTRY(dd) + __array(char, buf, 64) + __field(int, src) + ), + TP_fast_assign( + DD_DEV_ASSIGN(dd) + is_entry->is_name(__entry->buf, 64, src - is_entry->start); + __entry->src = src; + ), + TP_printk("[%s] source: %s [%d]", __get_str(dev), __entry->buf, + __entry->src) +); + +/* + * Note: + * This produces a REALLY ugly trace in the console output when the string is + * too long. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hfi1_trace + +#define MAX_MSG_LEN 512 + +DECLARE_EVENT_CLASS(hfi1_trace_template, + TP_PROTO(const char *function, struct va_format *vaf), + TP_ARGS(function, vaf), + TP_STRUCT__entry( + __string(function, function) + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + TP_fast_assign( + __assign_str(function, function); + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + TP_printk("(%s) %s", + __get_str(function), + __get_str(msg)) +); + +/* + * It may be nice to macroize the __hfi1_trace but the va_* stuff requires an + * actual function to work and can not be in a macro. + */ +#define __hfi1_trace_def(lvl) \ +void __hfi1_trace_##lvl(const char *funct, char *fmt, ...); \ + \ +DEFINE_EVENT(hfi1_trace_template, hfi1_ ##lvl, \ + TP_PROTO(const char *function, struct va_format *vaf), \ + TP_ARGS(function, vaf)) + +#define __hfi1_trace_fn(lvl) \ +void __hfi1_trace_##lvl(const char *func, char *fmt, ...) \ +{ \ + struct va_format vaf = { \ + .fmt = fmt, \ + }; \ + va_list args; \ + \ + va_start(args, fmt); \ + vaf.va = &args; \ + trace_hfi1_ ##lvl(func, &vaf); \ + va_end(args); \ + return; \ +} + +/* + * To create a new trace level simply define it below and as a __hfi1_trace_fn + * in trace.c. This will create all the hooks for calling + * hfi1_cdbg(LVL, fmt, ...); as well as take care of all + * the debugfs stuff. + */ +__hfi1_trace_def(PKT); +__hfi1_trace_def(PROC); +__hfi1_trace_def(SDMA); +__hfi1_trace_def(LINKVERB); +__hfi1_trace_def(DEBUG); +__hfi1_trace_def(SNOOP); +__hfi1_trace_def(CNTR); +__hfi1_trace_def(PIO); +__hfi1_trace_def(DC8051); +__hfi1_trace_def(FIRMWARE); +__hfi1_trace_def(RCVCTRL); +__hfi1_trace_def(TID); + +#define hfi1_cdbg(which, fmt, ...) \ + __hfi1_trace_##which(__func__, fmt, ##__VA_ARGS__) + +#define hfi1_dbg(fmt, ...) \ + hfi1_cdbg(DEBUG, fmt, ##__VA_ARGS__) + +/* + * Define HFI1_EARLY_DBG at compile time or here to enable early trace + * messages. Do not check in an enablement for this. + */ + +#ifdef HFI1_EARLY_DBG +#define hfi1_dbg_early(fmt, ...) \ + trace_printk(fmt, ##__VA_ARGS__) +#else +#define hfi1_dbg_early(fmt, ...) +#endif + +#endif /* __HFI1_TRACE_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace +#include diff --git a/drivers/staging/rdma/hfi1/twsi.c b/drivers/staging/rdma/hfi1/twsi.c new file mode 100644 index 0000000000000..ea54fd2700adc --- /dev/null +++ b/drivers/staging/rdma/hfi1/twsi.c @@ -0,0 +1,518 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include + +#include "hfi.h" +#include "twsi.h" + +/* + * "Two Wire Serial Interface" support. + * + * Originally written for a not-quite-i2c serial eeprom, which is + * still used on some supported boards. Later boards have added a + * variety of other uses, most board-specific, so the bit-boffing + * part has been split off to this file, while the other parts + * have been moved to chip-specific files. + * + * We have also dropped all pretense of fully generic (e.g. pretend + * we don't know whether '1' is the higher voltage) interface, as + * the restrictions of the generic i2c interface (e.g. no access from + * driver itself) make it unsuitable for this use. + */ + +#define READ_CMD 1 +#define WRITE_CMD 0 + +/** + * i2c_wait_for_writes - wait for a write + * @dd: the hfi1_ib device + * + * We use this instead of udelay directly, so we can make sure + * that previous register writes have been flushed all the way + * to the chip. Since we are delaying anyway, the cost doesn't + * hurt, and makes the bit twiddling more regular + */ +static void i2c_wait_for_writes(struct hfi1_devdata *dd, u32 target) +{ + /* + * implicit read of EXTStatus is as good as explicit + * read of scratch, if all we want to do is flush + * writes. + */ + hfi1_gpio_mod(dd, target, 0, 0, 0); + rmb(); /* inlined, so prevent compiler reordering */ +} + +/* + * QSFP modules are allowed to hold SCL low for 500uSec. Allow twice that + * for "almost compliant" modules + */ +#define SCL_WAIT_USEC 1000 + +/* BUF_WAIT is time bus must be free between STOP or ACK and to next START. + * Should be 20, but some chips need more. + */ +#define TWSI_BUF_WAIT_USEC 60 + +static void scl_out(struct hfi1_devdata *dd, u32 target, u8 bit) +{ + u32 mask; + + udelay(1); + + mask = QSFP_HFI0_I2CCLK; + + /* SCL is meant to be bare-drain, so never set "OUT", just DIR */ + hfi1_gpio_mod(dd, target, 0, bit ? 0 : mask, mask); + + /* + * Allow for slow slaves by simple + * delay for falling edge, sampling on rise. + */ + if (!bit) + udelay(2); + else { + int rise_usec; + + for (rise_usec = SCL_WAIT_USEC; rise_usec > 0; rise_usec -= 2) { + if (mask & hfi1_gpio_mod(dd, target, 0, 0, 0)) + break; + udelay(2); + } + if (rise_usec <= 0) + dd_dev_err(dd, "SCL interface stuck low > %d uSec\n", + SCL_WAIT_USEC); + } + i2c_wait_for_writes(dd, target); +} + +static void sda_out(struct hfi1_devdata *dd, u32 target, u8 bit) +{ + u32 mask; + + mask = QSFP_HFI0_I2CDAT; + + /* SDA is meant to be bare-drain, so never set "OUT", just DIR */ + hfi1_gpio_mod(dd, target, 0, bit ? 0 : mask, mask); + + i2c_wait_for_writes(dd, target); + udelay(2); +} + +static u8 sda_in(struct hfi1_devdata *dd, u32 target, int wait) +{ + u32 read_val, mask; + + mask = QSFP_HFI0_I2CDAT; + /* SDA is meant to be bare-drain, so never set "OUT", just DIR */ + hfi1_gpio_mod(dd, target, 0, 0, mask); + read_val = hfi1_gpio_mod(dd, target, 0, 0, 0); + if (wait) + i2c_wait_for_writes(dd, target); + return (read_val & mask) >> GPIO_SDA_NUM; +} + +/** + * i2c_ackrcv - see if ack following write is true + * @dd: the hfi1_ib device + */ +static int i2c_ackrcv(struct hfi1_devdata *dd, u32 target) +{ + u8 ack_received; + + /* AT ENTRY SCL = LOW */ + /* change direction, ignore data */ + ack_received = sda_in(dd, target, 1); + scl_out(dd, target, 1); + ack_received = sda_in(dd, target, 1) == 0; + scl_out(dd, target, 0); + return ack_received; +} + +static void stop_cmd(struct hfi1_devdata *dd, u32 target); + +/** + * rd_byte - read a byte, sending STOP on last, else ACK + * @dd: the hfi1_ib device + * + * Returns byte shifted out of device + */ +static int rd_byte(struct hfi1_devdata *dd, u32 target, int last) +{ + int bit_cntr, data; + + data = 0; + + for (bit_cntr = 7; bit_cntr >= 0; --bit_cntr) { + data <<= 1; + scl_out(dd, target, 1); + data |= sda_in(dd, target, 0); + scl_out(dd, target, 0); + } + if (last) { + scl_out(dd, target, 1); + stop_cmd(dd, target); + } else { + sda_out(dd, target, 0); + scl_out(dd, target, 1); + scl_out(dd, target, 0); + sda_out(dd, target, 1); + } + return data; +} + +/** + * wr_byte - write a byte, one bit at a time + * @dd: the hfi1_ib device + * @data: the byte to write + * + * Returns 0 if we got the following ack, otherwise 1 + */ +static int wr_byte(struct hfi1_devdata *dd, u32 target, u8 data) +{ + int bit_cntr; + u8 bit; + + for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) { + bit = (data >> bit_cntr) & 1; + sda_out(dd, target, bit); + scl_out(dd, target, 1); + scl_out(dd, target, 0); + } + return (!i2c_ackrcv(dd, target)) ? 1 : 0; +} + +/* + * issue TWSI start sequence: + * (both clock/data high, clock high, data low while clock is high) + */ +static void start_seq(struct hfi1_devdata *dd, u32 target) +{ + sda_out(dd, target, 1); + scl_out(dd, target, 1); + sda_out(dd, target, 0); + udelay(1); + scl_out(dd, target, 0); +} + +/** + * stop_seq - transmit the stop sequence + * @dd: the hfi1_ib device + * + * (both clock/data low, clock high, data high while clock is high) + */ +static void stop_seq(struct hfi1_devdata *dd, u32 target) +{ + scl_out(dd, target, 0); + sda_out(dd, target, 0); + scl_out(dd, target, 1); + sda_out(dd, target, 1); +} + +/** + * stop_cmd - transmit the stop condition + * @dd: the hfi1_ib device + * + * (both clock/data low, clock high, data high while clock is high) + */ +static void stop_cmd(struct hfi1_devdata *dd, u32 target) +{ + stop_seq(dd, target); + udelay(TWSI_BUF_WAIT_USEC); +} + +/** + * hfi1_twsi_reset - reset I2C communication + * @dd: the hfi1_ib device + */ + +int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target) +{ + int clock_cycles_left = 9; + int was_high = 0; + u32 pins, mask; + + /* Both SCL and SDA should be high. If not, there + * is something wrong. + */ + mask = QSFP_HFI0_I2CCLK | QSFP_HFI0_I2CDAT; + + /* + * Force pins to desired innocuous state. + * This is the default power-on state with out=0 and dir=0, + * So tri-stated and should be floating high (barring HW problems) + */ + hfi1_gpio_mod(dd, target, 0, 0, mask); + + /* + * Clock nine times to get all listeners into a sane state. + * If SDA does not go high at any point, we are wedged. + * One vendor recommends then issuing START followed by STOP. + * we cannot use our "normal" functions to do that, because + * if SCL drops between them, another vendor's part will + * wedge, dropping SDA and keeping it low forever, at the end of + * the next transaction (even if it was not the device addressed). + * So our START and STOP take place with SCL held high. + */ + while (clock_cycles_left--) { + scl_out(dd, target, 0); + scl_out(dd, target, 1); + /* Note if SDA is high, but keep clocking to sync slave */ + was_high |= sda_in(dd, target, 0); + } + + if (was_high) { + /* + * We saw a high, which we hope means the slave is sync'd. + * Issue START, STOP, pause for T_BUF. + */ + + pins = hfi1_gpio_mod(dd, target, 0, 0, 0); + if ((pins & mask) != mask) + dd_dev_err(dd, "GPIO pins not at rest: %d\n", + pins & mask); + /* Drop SDA to issue START */ + udelay(1); /* Guarantee .6 uSec setup */ + sda_out(dd, target, 0); + udelay(1); /* Guarantee .6 uSec hold */ + /* At this point, SCL is high, SDA low. Raise SDA for STOP */ + sda_out(dd, target, 1); + udelay(TWSI_BUF_WAIT_USEC); + } + + return !was_high; +} + +#define HFI1_TWSI_START 0x100 +#define HFI1_TWSI_STOP 0x200 + +/* Write byte to TWSI, optionally prefixed with START or suffixed with + * STOP. + * returns 0 if OK (ACK received), else != 0 + */ +static int twsi_wr(struct hfi1_devdata *dd, u32 target, int data, int flags) +{ + int ret = 1; + + if (flags & HFI1_TWSI_START) + start_seq(dd, target); + + /* Leaves SCL low (from i2c_ackrcv()) */ + ret = wr_byte(dd, target, data); + + if (flags & HFI1_TWSI_STOP) + stop_cmd(dd, target); + return ret; +} + +/* Added functionality for IBA7220-based cards */ +#define HFI1_TEMP_DEV 0x98 + +/* + * hfi1_twsi_blk_rd + * General interface for data transfer from twsi devices. + * One vestige of its former role is that it recognizes a device + * HFI1_TWSI_NO_DEV and does the correct operation for the legacy part, + * which responded to all TWSI device codes, interpreting them as + * address within device. On all other devices found on board handled by + * this driver, the device is followed by a one-byte "address" which selects + * the "register" or "offset" within the device from which data should + * be read. + */ +int hfi1_twsi_blk_rd(struct hfi1_devdata *dd, u32 target, int dev, int addr, + void *buffer, int len) +{ + int ret; + u8 *bp = buffer; + + ret = 1; + + if (dev == HFI1_TWSI_NO_DEV) { + /* legacy not-really-I2C */ + addr = (addr << 1) | READ_CMD; + ret = twsi_wr(dd, target, addr, HFI1_TWSI_START); + } else { + /* Actual I2C */ + ret = twsi_wr(dd, target, dev | WRITE_CMD, HFI1_TWSI_START); + if (ret) { + stop_cmd(dd, target); + ret = 1; + goto bail; + } + /* + * SFF spec claims we do _not_ stop after the addr + * but simply issue a start with the "read" dev-addr. + * Since we are implicitly waiting for ACK here, + * we need t_buf (nominally 20uSec) before that start, + * and cannot rely on the delay built in to the STOP + */ + ret = twsi_wr(dd, target, addr, 0); + udelay(TWSI_BUF_WAIT_USEC); + + if (ret) { + dd_dev_err(dd, + "Failed to write interface read addr %02X\n", + addr); + ret = 1; + goto bail; + } + ret = twsi_wr(dd, target, dev | READ_CMD, HFI1_TWSI_START); + } + if (ret) { + stop_cmd(dd, target); + ret = 1; + goto bail; + } + + /* + * block devices keeps clocking data out as long as we ack, + * automatically incrementing the address. Some have "pages" + * whose boundaries will not be crossed, but the handling + * of these is left to the caller, who is in a better + * position to know. + */ + while (len-- > 0) { + /* + * Get and store data, sending ACK if length remaining, + * else STOP + */ + *bp++ = rd_byte(dd, target, !len); + } + + ret = 0; + +bail: + return ret; +} + +/* + * hfi1_twsi_blk_wr + * General interface for data transfer to twsi devices. + * One vestige of its former role is that it recognizes a device + * HFI1_TWSI_NO_DEV and does the correct operation for the legacy part, + * which responded to all TWSI device codes, interpreting them as + * address within device. On all other devices found on board handled by + * this driver, the device is followed by a one-byte "address" which selects + * the "register" or "offset" within the device to which data should + * be written. + */ +int hfi1_twsi_blk_wr(struct hfi1_devdata *dd, u32 target, int dev, int addr, + const void *buffer, int len) +{ + int sub_len; + const u8 *bp = buffer; + int max_wait_time, i; + int ret = 1; + + while (len > 0) { + if (dev == HFI1_TWSI_NO_DEV) { + if (twsi_wr(dd, target, (addr << 1) | WRITE_CMD, + HFI1_TWSI_START)) { + goto failed_write; + } + } else { + /* Real I2C */ + if (twsi_wr(dd, target, + dev | WRITE_CMD, HFI1_TWSI_START)) + goto failed_write; + ret = twsi_wr(dd, target, addr, 0); + if (ret) { + dd_dev_err(dd, + "Failed to write interface write addr %02X\n", + addr); + goto failed_write; + } + } + + sub_len = min(len, 4); + addr += sub_len; + len -= sub_len; + + for (i = 0; i < sub_len; i++) + if (twsi_wr(dd, target, *bp++, 0)) + goto failed_write; + + stop_cmd(dd, target); + + /* + * Wait for write complete by waiting for a successful + * read (the chip replies with a zero after the write + * cmd completes, and before it writes to the eeprom. + * The startcmd for the read will fail the ack until + * the writes have completed. We do this inline to avoid + * the debug prints that are in the real read routine + * if the startcmd fails. + * We also use the proper device address, so it doesn't matter + * whether we have real eeprom_dev. Legacy likes any address. + */ + max_wait_time = 100; + while (twsi_wr(dd, target, + dev | READ_CMD, HFI1_TWSI_START)) { + stop_cmd(dd, target); + if (!--max_wait_time) + goto failed_write; + } + /* now read (and ignore) the resulting byte */ + rd_byte(dd, target, 1); + } + + ret = 0; + goto bail; + +failed_write: + stop_cmd(dd, target); + ret = 1; + +bail: + return ret; +} diff --git a/drivers/staging/rdma/hfi1/twsi.h b/drivers/staging/rdma/hfi1/twsi.h new file mode 100644 index 0000000000000..5907e029613d6 --- /dev/null +++ b/drivers/staging/rdma/hfi1/twsi.h @@ -0,0 +1,68 @@ +#ifndef _TWSI_H +#define _TWSI_H +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define HFI1_TWSI_NO_DEV 0xFF + +struct hfi1_devdata; + +/* Bit position of SDA pin in ASIC_QSFP* registers */ +#define GPIO_SDA_NUM 1 + +/* these functions must be called with qsfp_lock held */ +int hfi1_twsi_reset(struct hfi1_devdata *dd, u32 target); +int hfi1_twsi_blk_rd(struct hfi1_devdata *dd, u32 target, int dev, int addr, + void *buffer, int len); +int hfi1_twsi_blk_wr(struct hfi1_devdata *dd, u32 target, int dev, int addr, + const void *buffer, int len); + + +#endif /* _TWSI_H */ diff --git a/drivers/staging/rdma/hfi1/uc.c b/drivers/staging/rdma/hfi1/uc.c new file mode 100644 index 0000000000000..b536f397737c7 --- /dev/null +++ b/drivers/staging/rdma/hfi1/uc.c @@ -0,0 +1,585 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "hfi.h" +#include "sdma.h" +#include "qp.h" + +/* cut down ridiculously long IB macro names */ +#define OP(x) IB_OPCODE_UC_##x + +/** + * hfi1_make_uc_req - construct a request packet (SEND, RDMA write) + * @qp: a pointer to the QP + * + * Return 1 if constructed; otherwise, return 0. + */ +int hfi1_make_uc_req(struct hfi1_qp *qp) +{ + struct hfi1_other_headers *ohdr; + struct hfi1_swqe *wqe; + unsigned long flags; + u32 hwords = 5; + u32 bth0 = 0; + u32 len; + u32 pmtu = qp->pmtu; + int ret = 0; + int middle = 0; + + spin_lock_irqsave(&qp->s_lock, flags); + + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_SEND_OK)) { + if (!(ib_hfi1_state_ops[qp->state] & HFI1_FLUSH_SEND)) + goto bail; + /* We are in the error state, flush the work request. */ + if (qp->s_last == qp->s_head) + goto bail; + /* If DMAs are in progress, we can't flush immediately. */ + if (atomic_read(&qp->s_iowait.sdma_busy)) { + qp->s_flags |= HFI1_S_WAIT_DMA; + goto bail; + } + clear_ahg(qp); + wqe = get_swqe_ptr(qp, qp->s_last); + hfi1_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + goto done; + } + + ohdr = &qp->s_hdr->ibh.u.oth; + if (qp->remote_ah_attr.ah_flags & IB_AH_GRH) + ohdr = &qp->s_hdr->ibh.u.l.oth; + + /* Get the next send request. */ + wqe = get_swqe_ptr(qp, qp->s_cur); + qp->s_wqe = NULL; + switch (qp->s_state) { + default: + if (!(ib_hfi1_state_ops[qp->state] & + HFI1_PROCESS_NEXT_SEND_OK)) + goto bail; + /* Check if send work queue is empty. */ + if (qp->s_cur == qp->s_head) { + clear_ahg(qp); + goto bail; + } + /* + * Start a new request. + */ + wqe->psn = qp->s_next_psn; + qp->s_psn = qp->s_next_psn; + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + qp->s_sge.total_len = wqe->length; + len = wqe->length; + qp->s_len = len; + switch (wqe->wr.opcode) { + case IB_WR_SEND: + case IB_WR_SEND_WITH_IMM: + if (len > pmtu) { + qp->s_state = OP(SEND_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_ONLY); + else { + qp->s_state = + OP(SEND_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + ohdr->u.rc.reth.vaddr = + cpu_to_be64(wqe->wr.wr.rdma.remote_addr); + ohdr->u.rc.reth.rkey = + cpu_to_be32(wqe->wr.wr.rdma.rkey); + ohdr->u.rc.reth.length = cpu_to_be32(len); + hwords += sizeof(struct ib_reth) / 4; + if (len > pmtu) { + qp->s_state = OP(RDMA_WRITE_FIRST); + len = pmtu; + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_ONLY); + else { + qp->s_state = + OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE); + /* Immediate data comes after the RETH */ + ohdr->u.rc.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + } + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + default: + goto bail; + } + break; + + case OP(SEND_FIRST): + qp->s_state = OP(SEND_MIDDLE); + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + len = qp->s_len; + if (len > pmtu) { + len = pmtu; + middle = HFI1_CAP_IS_KSET(SDMA_AHG); + break; + } + if (wqe->wr.opcode == IB_WR_SEND) + qp->s_state = OP(SEND_LAST); + else { + qp->s_state = OP(SEND_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + + case OP(RDMA_WRITE_FIRST): + qp->s_state = OP(RDMA_WRITE_MIDDLE); + /* FALLTHROUGH */ + case OP(RDMA_WRITE_MIDDLE): + len = qp->s_len; + if (len > pmtu) { + len = pmtu; + middle = HFI1_CAP_IS_KSET(SDMA_AHG); + break; + } + if (wqe->wr.opcode == IB_WR_RDMA_WRITE) + qp->s_state = OP(RDMA_WRITE_LAST); + else { + qp->s_state = + OP(RDMA_WRITE_LAST_WITH_IMMEDIATE); + /* Immediate data comes after the BTH */ + ohdr->u.imm_data = wqe->wr.ex.imm_data; + hwords += 1; + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + } + qp->s_wqe = wqe; + if (++qp->s_cur >= qp->s_size) + qp->s_cur = 0; + break; + } + qp->s_len -= len; + qp->s_hdrwords = hwords; + qp->s_cur_sge = &qp->s_sge; + qp->s_cur_size = len; + hfi1_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), + mask_psn(qp->s_next_psn++), middle); +done: + ret = 1; + goto unlock; + +bail: + qp->s_flags &= ~HFI1_S_BUSY; +unlock: + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; +} + +/** + * hfi1_uc_rcv - handle an incoming UC packet + * @ibp: the port the packet came in on + * @hdr: the header of the packet + * @rcv_flags: flags relevant to rcv processing + * @data: the packet data + * @tlen: the length of the packet + * @qp: the QP for this packet. + * + * This is called from qp_rcv() to process an incoming UC packet + * for the given QP. + * Called at interrupt level. + */ +void hfi1_uc_rcv(struct hfi1_packet *packet) +{ + struct hfi1_ibport *ibp = &packet->rcd->ppd->ibport_data; + struct hfi1_ib_header *hdr = packet->hdr; + u32 rcv_flags = packet->rcv_flags; + void *data = packet->ebuf; + u32 tlen = packet->tlen; + struct hfi1_qp *qp = packet->qp; + struct hfi1_other_headers *ohdr = packet->ohdr; + u32 opcode; + u32 hdrsize = packet->hlen; + u32 psn; + u32 pad; + struct ib_wc wc; + u32 pmtu = qp->pmtu; + struct ib_reth *reth; + int has_grh = rcv_flags & HFI1_HAS_GRH; + int ret; + u32 bth1; + struct ib_grh *grh = NULL; + + opcode = be32_to_cpu(ohdr->bth[0]); + if (hfi1_ruc_check_hdr(ibp, hdr, has_grh, qp, opcode)) + return; + + bth1 = be32_to_cpu(ohdr->bth[1]); + if (unlikely(bth1 & (HFI1_BECN_SMASK | HFI1_FECN_SMASK))) { + if (bth1 & HFI1_BECN_SMASK) { + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 rqpn, lqpn; + u16 rlid = be16_to_cpu(hdr->lrh[3]); + u8 sl, sc5; + + lqpn = bth1 & HFI1_QPN_MASK; + rqpn = qp->remote_qpn; + + sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + sl = ibp->sc_to_sl[sc5]; + + process_becn(ppd, sl, rlid, lqpn, rqpn, + IB_CC_SVCTYPE_UC); + } + + if (bth1 & HFI1_FECN_SMASK) { + u16 pkey = (u16)be32_to_cpu(ohdr->bth[0]); + u16 slid = be16_to_cpu(hdr->lrh[3]); + u16 dlid = be16_to_cpu(hdr->lrh[1]); + u32 src_qp = qp->remote_qpn; + u8 sc5; + + sc5 = ibp->sl_to_sc[qp->remote_ah_attr.sl]; + + return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5, grh); + } + } + + psn = be32_to_cpu(ohdr->bth[2]); + opcode >>= 24; + + /* Compare the PSN verses the expected PSN. */ + if (unlikely(cmp_psn(psn, qp->r_psn) != 0)) { + /* + * Handle a sequence error. + * Silently drop any current message. + */ + qp->r_psn = psn; +inv: + if (qp->r_state == OP(SEND_FIRST) || + qp->r_state == OP(SEND_MIDDLE)) { + set_bit(HFI1_R_REWIND_SGE, &qp->r_aflags); + qp->r_sge.num_sge = 0; + } else + hfi1_put_ss(&qp->r_sge); + qp->r_state = OP(SEND_LAST); + switch (opcode) { + case OP(SEND_FIRST): + case OP(SEND_ONLY): + case OP(SEND_ONLY_WITH_IMMEDIATE): + goto send_first; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_ONLY): + case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): + goto rdma_first; + + default: + goto drop; + } + } + + /* Check for opcode sequence errors. */ + switch (qp->r_state) { + case OP(SEND_FIRST): + case OP(SEND_MIDDLE): + if (opcode == OP(SEND_MIDDLE) || + opcode == OP(SEND_LAST) || + opcode == OP(SEND_LAST_WITH_IMMEDIATE)) + break; + goto inv; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_MIDDLE): + if (opcode == OP(RDMA_WRITE_MIDDLE) || + opcode == OP(RDMA_WRITE_LAST) || + opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE)) + break; + goto inv; + + default: + if (opcode == OP(SEND_FIRST) || + opcode == OP(SEND_ONLY) || + opcode == OP(SEND_ONLY_WITH_IMMEDIATE) || + opcode == OP(RDMA_WRITE_FIRST) || + opcode == OP(RDMA_WRITE_ONLY) || + opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) + break; + goto inv; + } + + if (qp->state == IB_QPS_RTR && !(qp->r_flags & HFI1_R_COMM_EST)) + qp_comm_est(qp); + + /* OK, process the packet. */ + switch (opcode) { + case OP(SEND_FIRST): + case OP(SEND_ONLY): + case OP(SEND_ONLY_WITH_IMMEDIATE): +send_first: + if (test_and_clear_bit(HFI1_R_REWIND_SGE, &qp->r_aflags)) + qp->r_sge = qp->s_rdma_read_sge; + else { + ret = hfi1_get_rwqe(qp, 0); + if (ret < 0) + goto op_err; + if (!ret) + goto drop; + /* + * qp->s_rdma_read_sge will be the owner + * of the mr references. + */ + qp->s_rdma_read_sge = qp->r_sge; + } + qp->r_rcv_len = 0; + if (opcode == OP(SEND_ONLY)) + goto no_immediate_data; + else if (opcode == OP(SEND_ONLY_WITH_IMMEDIATE)) + goto send_last_imm; + /* FALLTHROUGH */ + case OP(SEND_MIDDLE): + /* Check for invalid length PMTU or posted rwqe len. */ + if (unlikely(tlen != (hdrsize + pmtu + 4))) + goto rewind; + qp->r_rcv_len += pmtu; + if (unlikely(qp->r_rcv_len > qp->r_len)) + goto rewind; + hfi1_copy_sge(&qp->r_sge, data, pmtu, 0); + break; + + case OP(SEND_LAST_WITH_IMMEDIATE): +send_last_imm: + wc.ex.imm_data = ohdr->u.imm_data; + wc.wc_flags = IB_WC_WITH_IMM; + goto send_last; + case OP(SEND_LAST): +no_immediate_data: + wc.ex.imm_data = 0; + wc.wc_flags = 0; +send_last: + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) + goto rewind; + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + wc.byte_len = tlen + qp->r_rcv_len; + if (unlikely(wc.byte_len > qp->r_len)) + goto rewind; + wc.opcode = IB_WC_RECV; + hfi1_copy_sge(&qp->r_sge, data, tlen, 0); + hfi1_put_ss(&qp->s_rdma_read_sge); +last_imm: + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.qp = &qp->ibqp; + wc.src_qp = qp->remote_qpn; + wc.slid = qp->remote_ah_attr.dlid; + /* + * It seems that IB mandates the presence of an SL in a + * work completion only for the UD transport (see section + * 11.4.2 of IBTA Vol. 1). + * + * However, the way the SL is chosen below is consistent + * with the way that IB/qib works and is trying avoid + * introducing incompatibilities. + * + * See also OPA Vol. 1, section 9.7.6, and table 9-17. + */ + wc.sl = qp->remote_ah_attr.sl; + /* zero fields that are N/A */ + wc.vendor_err = 0; + wc.pkey_index = 0; + wc.dlid_path_bits = 0; + wc.port_num = 0; + /* Signal completion event if the solicited bit is set. */ + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + (ohdr->bth[0] & + cpu_to_be32(IB_BTH_SOLICITED)) != 0); + break; + + case OP(RDMA_WRITE_FIRST): + case OP(RDMA_WRITE_ONLY): + case OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE): /* consume RWQE */ +rdma_first: + if (unlikely(!(qp->qp_access_flags & + IB_ACCESS_REMOTE_WRITE))) { + goto drop; + } + reth = &ohdr->u.rc.reth; + qp->r_len = be32_to_cpu(reth->length); + qp->r_rcv_len = 0; + qp->r_sge.sg_list = NULL; + if (qp->r_len != 0) { + u32 rkey = be32_to_cpu(reth->rkey); + u64 vaddr = be64_to_cpu(reth->vaddr); + int ok; + + /* Check rkey */ + ok = hfi1_rkey_ok(qp, &qp->r_sge.sge, qp->r_len, + vaddr, rkey, IB_ACCESS_REMOTE_WRITE); + if (unlikely(!ok)) + goto drop; + qp->r_sge.num_sge = 1; + } else { + qp->r_sge.num_sge = 0; + qp->r_sge.sge.mr = NULL; + qp->r_sge.sge.vaddr = NULL; + qp->r_sge.sge.length = 0; + qp->r_sge.sge.sge_length = 0; + } + if (opcode == OP(RDMA_WRITE_ONLY)) + goto rdma_last; + else if (opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE)) { + wc.ex.imm_data = ohdr->u.rc.imm_data; + goto rdma_last_imm; + } + /* FALLTHROUGH */ + case OP(RDMA_WRITE_MIDDLE): + /* Check for invalid length PMTU or posted rwqe len. */ + if (unlikely(tlen != (hdrsize + pmtu + 4))) + goto drop; + qp->r_rcv_len += pmtu; + if (unlikely(qp->r_rcv_len > qp->r_len)) + goto drop; + hfi1_copy_sge(&qp->r_sge, data, pmtu, 1); + break; + + case OP(RDMA_WRITE_LAST_WITH_IMMEDIATE): + wc.ex.imm_data = ohdr->u.imm_data; +rdma_last_imm: + wc.wc_flags = IB_WC_WITH_IMM; + + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) + goto drop; + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) + goto drop; + if (test_and_clear_bit(HFI1_R_REWIND_SGE, &qp->r_aflags)) + hfi1_put_ss(&qp->s_rdma_read_sge); + else { + ret = hfi1_get_rwqe(qp, 1); + if (ret < 0) + goto op_err; + if (!ret) + goto drop; + } + wc.byte_len = qp->r_len; + wc.opcode = IB_WC_RECV_RDMA_WITH_IMM; + hfi1_copy_sge(&qp->r_sge, data, tlen, 1); + hfi1_put_ss(&qp->r_sge); + goto last_imm; + + case OP(RDMA_WRITE_LAST): +rdma_last: + /* Get the number of bytes the message was padded by. */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + /* Check for invalid length. */ + /* LAST len should be >= 1 */ + if (unlikely(tlen < (hdrsize + pad + 4))) + goto drop; + /* Don't count the CRC. */ + tlen -= (hdrsize + pad + 4); + if (unlikely(tlen + qp->r_rcv_len != qp->r_len)) + goto drop; + hfi1_copy_sge(&qp->r_sge, data, tlen, 1); + hfi1_put_ss(&qp->r_sge); + break; + + default: + /* Drop packet for unknown opcodes. */ + goto drop; + } + qp->r_psn++; + qp->r_state = opcode; + return; + +rewind: + set_bit(HFI1_R_REWIND_SGE, &qp->r_aflags); + qp->r_sge.num_sge = 0; +drop: + ibp->n_pkt_drops++; + return; + +op_err: + hfi1_rc_error(qp, IB_WC_LOC_QP_OP_ERR); + return; + +} diff --git a/drivers/staging/rdma/hfi1/ud.c b/drivers/staging/rdma/hfi1/ud.c new file mode 100644 index 0000000000000..d40d1a1e10aa9 --- /dev/null +++ b/drivers/staging/rdma/hfi1/ud.c @@ -0,0 +1,885 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "hfi.h" +#include "mad.h" +#include "qp.h" + +/** + * ud_loopback - handle send on loopback QPs + * @sqp: the sending QP + * @swqe: the send work request + * + * This is called from hfi1_make_ud_req() to forward a WQE addressed + * to the same HFI. + * Note that the receive interrupt handler may be calling hfi1_ud_rcv() + * while this is being called. + */ +static void ud_loopback(struct hfi1_qp *sqp, struct hfi1_swqe *swqe) +{ + struct hfi1_ibport *ibp = to_iport(sqp->ibqp.device, sqp->port_num); + struct hfi1_pportdata *ppd; + struct hfi1_qp *qp; + struct ib_ah_attr *ah_attr; + unsigned long flags; + struct hfi1_sge_state ssge; + struct hfi1_sge *sge; + struct ib_wc wc; + u32 length; + enum ib_qp_type sqptype, dqptype; + + rcu_read_lock(); + + qp = hfi1_lookup_qpn(ibp, swqe->wr.wr.ud.remote_qpn); + if (!qp) { + ibp->n_pkt_drops++; + rcu_read_unlock(); + return; + } + + sqptype = sqp->ibqp.qp_type == IB_QPT_GSI ? + IB_QPT_UD : sqp->ibqp.qp_type; + dqptype = qp->ibqp.qp_type == IB_QPT_GSI ? + IB_QPT_UD : qp->ibqp.qp_type; + + if (dqptype != sqptype || + !(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK)) { + ibp->n_pkt_drops++; + goto drop; + } + + ah_attr = &to_iah(swqe->wr.wr.ud.ah)->attr; + ppd = ppd_from_ibp(ibp); + + if (qp->ibqp.qp_num > 1) { + u16 pkey; + u16 slid; + u8 sc5 = ibp->sl_to_sc[ah_attr->sl]; + + pkey = hfi1_get_pkey(ibp, sqp->s_pkey_index); + slid = ppd->lid | (ah_attr->src_path_bits & + ((1 << ppd->lmc) - 1)); + if (unlikely(ingress_pkey_check(ppd, pkey, sc5, + qp->s_pkey_index, slid))) { + hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY, pkey, + ah_attr->sl, + sqp->ibqp.qp_num, qp->ibqp.qp_num, + cpu_to_be16(slid), + cpu_to_be16(ah_attr->dlid)); + goto drop; + } + } + + /* + * Check that the qkey matches (except for QP0, see 9.6.1.4.1). + * Qkeys with the high order bit set mean use the + * qkey from the QP context instead of the WR (see 10.2.5). + */ + if (qp->ibqp.qp_num) { + u32 qkey; + + qkey = (int)swqe->wr.wr.ud.remote_qkey < 0 ? + sqp->qkey : swqe->wr.wr.ud.remote_qkey; + if (unlikely(qkey != qp->qkey)) { + u16 lid; + + lid = ppd->lid | (ah_attr->src_path_bits & + ((1 << ppd->lmc) - 1)); + hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_QKEY, qkey, + ah_attr->sl, + sqp->ibqp.qp_num, qp->ibqp.qp_num, + cpu_to_be16(lid), + cpu_to_be16(ah_attr->dlid)); + goto drop; + } + } + + /* + * A GRH is expected to precede the data even if not + * present on the wire. + */ + length = swqe->length; + memset(&wc, 0, sizeof(wc)); + wc.byte_len = length + sizeof(struct ib_grh); + + if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + wc.wc_flags = IB_WC_WITH_IMM; + wc.ex.imm_data = swqe->wr.ex.imm_data; + } + + spin_lock_irqsave(&qp->r_lock, flags); + + /* + * Get the next work request entry to find where to put the data. + */ + if (qp->r_flags & HFI1_R_REUSE_SGE) + qp->r_flags &= ~HFI1_R_REUSE_SGE; + else { + int ret; + + ret = hfi1_get_rwqe(qp, 0); + if (ret < 0) { + hfi1_rc_error(qp, IB_WC_LOC_QP_OP_ERR); + goto bail_unlock; + } + if (!ret) { + if (qp->ibqp.qp_num == 0) + ibp->n_vl15_dropped++; + goto bail_unlock; + } + } + /* Silently drop packets which are too big. */ + if (unlikely(wc.byte_len > qp->r_len)) { + qp->r_flags |= HFI1_R_REUSE_SGE; + ibp->n_pkt_drops++; + goto bail_unlock; + } + + if (ah_attr->ah_flags & IB_AH_GRH) { + hfi1_copy_sge(&qp->r_sge, &ah_attr->grh, + sizeof(struct ib_grh), 1); + wc.wc_flags |= IB_WC_GRH; + } else + hfi1_skip_sge(&qp->r_sge, sizeof(struct ib_grh), 1); + ssge.sg_list = swqe->sg_list + 1; + ssge.sge = *swqe->sg_list; + ssge.num_sge = swqe->wr.num_sge; + sge = &ssge.sge; + while (length) { + u32 len = sge->length; + + if (len > length) + len = length; + if (len > sge->sge_length) + len = sge->sge_length; + WARN_ON_ONCE(len == 0); + hfi1_copy_sge(&qp->r_sge, sge->vaddr, len, 1); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (--ssge.num_sge) + *sge = *ssge.sg_list++; + } else if (sge->length == 0 && sge->mr->lkey) { + if (++sge->n >= HFI1_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + length -= len; + } + hfi1_put_ss(&qp->r_sge); + if (!test_and_clear_bit(HFI1_R_WRID_VALID, &qp->r_aflags)) + goto bail_unlock; + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.qp = &qp->ibqp; + wc.src_qp = sqp->ibqp.qp_num; + if (qp->ibqp.qp_type == IB_QPT_GSI || qp->ibqp.qp_type == IB_QPT_SMI) { + if (sqp->ibqp.qp_type == IB_QPT_GSI || + sqp->ibqp.qp_type == IB_QPT_SMI) + wc.pkey_index = swqe->wr.wr.ud.pkey_index; + else + wc.pkey_index = sqp->s_pkey_index; + } else { + wc.pkey_index = 0; + } + wc.slid = ppd->lid | (ah_attr->src_path_bits & ((1 << ppd->lmc) - 1)); + /* Check for loopback when the port lid is not set */ + if (wc.slid == 0 && sqp->ibqp.qp_type == IB_QPT_GSI) + wc.slid = HFI1_PERMISSIVE_LID; + wc.sl = ah_attr->sl; + wc.dlid_path_bits = ah_attr->dlid & ((1 << ppd->lmc) - 1); + wc.port_num = qp->port_num; + /* Signal completion event if the solicited bit is set. */ + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + swqe->wr.send_flags & IB_SEND_SOLICITED); + ibp->n_loop_pkts++; +bail_unlock: + spin_unlock_irqrestore(&qp->r_lock, flags); +drop: + rcu_read_unlock(); +} + +/** + * hfi1_make_ud_req - construct a UD request packet + * @qp: the QP + * + * Return 1 if constructed; otherwise, return 0. + */ +int hfi1_make_ud_req(struct hfi1_qp *qp) +{ + struct hfi1_other_headers *ohdr; + struct ib_ah_attr *ah_attr; + struct hfi1_pportdata *ppd; + struct hfi1_ibport *ibp; + struct hfi1_swqe *wqe; + unsigned long flags; + u32 nwords; + u32 extra_bytes; + u32 bth0; + u16 lrh0; + u16 lid; + int ret = 0; + int next_cur; + u8 sc5; + + spin_lock_irqsave(&qp->s_lock, flags); + + if (!(ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_NEXT_SEND_OK)) { + if (!(ib_hfi1_state_ops[qp->state] & HFI1_FLUSH_SEND)) + goto bail; + /* We are in the error state, flush the work request. */ + if (qp->s_last == qp->s_head) + goto bail; + /* If DMAs are in progress, we can't flush immediately. */ + if (atomic_read(&qp->s_iowait.sdma_busy)) { + qp->s_flags |= HFI1_S_WAIT_DMA; + goto bail; + } + wqe = get_swqe_ptr(qp, qp->s_last); + hfi1_send_complete(qp, wqe, IB_WC_WR_FLUSH_ERR); + goto done; + } + + if (qp->s_cur == qp->s_head) + goto bail; + + wqe = get_swqe_ptr(qp, qp->s_cur); + next_cur = qp->s_cur + 1; + if (next_cur >= qp->s_size) + next_cur = 0; + + /* Construct the header. */ + ibp = to_iport(qp->ibqp.device, qp->port_num); + ppd = ppd_from_ibp(ibp); + ah_attr = &to_iah(wqe->wr.wr.ud.ah)->attr; + if (ah_attr->dlid < HFI1_MULTICAST_LID_BASE || + ah_attr->dlid == HFI1_PERMISSIVE_LID) { + lid = ah_attr->dlid & ~((1 << ppd->lmc) - 1); + if (unlikely(!loopback && (lid == ppd->lid || + (lid == HFI1_PERMISSIVE_LID && + qp->ibqp.qp_type == IB_QPT_GSI)))) { + /* + * If DMAs are in progress, we can't generate + * a completion for the loopback packet since + * it would be out of order. + * Instead of waiting, we could queue a + * zero length descriptor so we get a callback. + */ + if (atomic_read(&qp->s_iowait.sdma_busy)) { + qp->s_flags |= HFI1_S_WAIT_DMA; + goto bail; + } + qp->s_cur = next_cur; + spin_unlock_irqrestore(&qp->s_lock, flags); + ud_loopback(qp, wqe); + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_send_complete(qp, wqe, IB_WC_SUCCESS); + goto done; + } + } + + qp->s_cur = next_cur; + extra_bytes = -wqe->length & 3; + nwords = (wqe->length + extra_bytes) >> 2; + + /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ + qp->s_hdrwords = 7; + qp->s_cur_size = wqe->length; + qp->s_cur_sge = &qp->s_sge; + qp->s_srate = ah_attr->static_rate; + qp->srate_mbps = ib_rate_to_mbps(qp->s_srate); + qp->s_wqe = wqe; + qp->s_sge.sge = wqe->sg_list[0]; + qp->s_sge.sg_list = wqe->sg_list + 1; + qp->s_sge.num_sge = wqe->wr.num_sge; + qp->s_sge.total_len = wqe->length; + + if (ah_attr->ah_flags & IB_AH_GRH) { + /* Header size in 32-bit words. */ + qp->s_hdrwords += hfi1_make_grh(ibp, &qp->s_hdr->ibh.u.l.grh, + &ah_attr->grh, + qp->s_hdrwords, nwords); + lrh0 = HFI1_LRH_GRH; + ohdr = &qp->s_hdr->ibh.u.l.oth; + /* + * Don't worry about sending to locally attached multicast + * QPs. It is unspecified by the spec. what happens. + */ + } else { + /* Header size in 32-bit words. */ + lrh0 = HFI1_LRH_BTH; + ohdr = &qp->s_hdr->ibh.u.oth; + } + if (wqe->wr.opcode == IB_WR_SEND_WITH_IMM) { + qp->s_hdrwords++; + ohdr->u.ud.imm_data = wqe->wr.ex.imm_data; + bth0 = IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE << 24; + } else + bth0 = IB_OPCODE_UD_SEND_ONLY << 24; + sc5 = ibp->sl_to_sc[ah_attr->sl]; + lrh0 |= (ah_attr->sl & 0xf) << 4; + if (qp->ibqp.qp_type == IB_QPT_SMI) { + lrh0 |= 0xF000; /* Set VL (see ch. 13.5.3.1) */ + qp->s_sc = 0xf; + } else { + lrh0 |= (sc5 & 0xf) << 12; + qp->s_sc = sc5; + } + qp->s_hdr->ibh.lrh[0] = cpu_to_be16(lrh0); + qp->s_hdr->ibh.lrh[1] = cpu_to_be16(ah_attr->dlid); /* DEST LID */ + qp->s_hdr->ibh.lrh[2] = + cpu_to_be16(qp->s_hdrwords + nwords + SIZE_OF_CRC); + if (ah_attr->dlid == be16_to_cpu(IB_LID_PERMISSIVE)) + qp->s_hdr->ibh.lrh[3] = IB_LID_PERMISSIVE; + else { + lid = ppd->lid; + if (lid) { + lid |= ah_attr->src_path_bits & ((1 << ppd->lmc) - 1); + qp->s_hdr->ibh.lrh[3] = cpu_to_be16(lid); + } else + qp->s_hdr->ibh.lrh[3] = IB_LID_PERMISSIVE; + } + if (wqe->wr.send_flags & IB_SEND_SOLICITED) + bth0 |= IB_BTH_SOLICITED; + bth0 |= extra_bytes << 20; + if (qp->ibqp.qp_type == IB_QPT_GSI || qp->ibqp.qp_type == IB_QPT_SMI) + bth0 |= hfi1_get_pkey(ibp, wqe->wr.wr.ud.pkey_index); + else + bth0 |= hfi1_get_pkey(ibp, qp->s_pkey_index); + ohdr->bth[0] = cpu_to_be32(bth0); + ohdr->bth[1] = cpu_to_be32(wqe->wr.wr.ud.remote_qpn); + ohdr->bth[2] = cpu_to_be32(mask_psn(qp->s_next_psn++)); + /* + * Qkeys with the high order bit set mean use the + * qkey from the QP context instead of the WR (see 10.2.5). + */ + ohdr->u.ud.deth[0] = cpu_to_be32((int)wqe->wr.wr.ud.remote_qkey < 0 ? + qp->qkey : wqe->wr.wr.ud.remote_qkey); + ohdr->u.ud.deth[1] = cpu_to_be32(qp->ibqp.qp_num); + /* disarm any ahg */ + qp->s_hdr->ahgcount = 0; + qp->s_hdr->ahgidx = 0; + qp->s_hdr->tx_flags = 0; + qp->s_hdr->sde = NULL; + +done: + ret = 1; + goto unlock; + +bail: + qp->s_flags &= ~HFI1_S_BUSY; +unlock: + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; +} + +/* + * Hardware can't check this so we do it here. + * + * This is a slightly different algorithm than the standard pkey check. It + * special cases the management keys and allows for 0x7fff and 0xffff to be in + * the table at the same time. + * + * @returns the index found or -1 if not found + */ +int hfi1_lookup_pkey_idx(struct hfi1_ibport *ibp, u16 pkey) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + unsigned i; + + if (pkey == FULL_MGMT_P_KEY || pkey == LIM_MGMT_P_KEY) { + unsigned lim_idx = -1; + + for (i = 0; i < ARRAY_SIZE(ppd->pkeys); ++i) { + /* here we look for an exact match */ + if (ppd->pkeys[i] == pkey) + return i; + if (ppd->pkeys[i] == LIM_MGMT_P_KEY) + lim_idx = i; + } + + /* did not find 0xffff return 0x7fff idx if found */ + if (pkey == FULL_MGMT_P_KEY) + return lim_idx; + + /* no match... */ + return -1; + } + + pkey &= 0x7fff; /* remove limited/full membership bit */ + + for (i = 0; i < ARRAY_SIZE(ppd->pkeys); ++i) + if ((ppd->pkeys[i] & 0x7fff) == pkey) + return i; + + /* + * Should not get here, this means hardware failed to validate pkeys. + */ + return -1; +} + +void return_cnp(struct hfi1_ibport *ibp, struct hfi1_qp *qp, u32 remote_qpn, + u32 pkey, u32 slid, u32 dlid, u8 sc5, + const struct ib_grh *old_grh) +{ + u64 pbc, pbc_flags = 0; + u32 bth0, plen, vl, hwords = 5; + u16 lrh0; + u8 sl = ibp->sc_to_sl[sc5]; + struct hfi1_ib_header hdr; + struct hfi1_other_headers *ohdr; + struct pio_buf *pbuf; + struct send_context *ctxt = qp_to_send_context(qp, sc5); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + if (old_grh) { + struct ib_grh *grh = &hdr.u.l.grh; + + grh->version_tclass_flow = old_grh->version_tclass_flow; + grh->paylen = cpu_to_be16((hwords - 2 + SIZE_OF_CRC) << 2); + grh->hop_limit = 0xff; + grh->sgid = old_grh->dgid; + grh->dgid = old_grh->sgid; + ohdr = &hdr.u.l.oth; + lrh0 = HFI1_LRH_GRH; + hwords += sizeof(struct ib_grh) / sizeof(u32); + } else { + ohdr = &hdr.u.oth; + lrh0 = HFI1_LRH_BTH; + } + + lrh0 |= (sc5 & 0xf) << 12 | sl << 4; + + bth0 = pkey | (IB_OPCODE_CNP << 24); + ohdr->bth[0] = cpu_to_be32(bth0); + + ohdr->bth[1] = cpu_to_be32(remote_qpn | (1 << HFI1_BECN_SHIFT)); + ohdr->bth[2] = 0; /* PSN 0 */ + + hdr.lrh[0] = cpu_to_be16(lrh0); + hdr.lrh[1] = cpu_to_be16(dlid); + hdr.lrh[2] = cpu_to_be16(hwords + SIZE_OF_CRC); + hdr.lrh[3] = cpu_to_be16(slid); + + plen = 2 /* PBC */ + hwords; + pbc_flags |= (!!(sc5 & 0x10)) << PBC_DC_INFO_SHIFT; + vl = sc_to_vlt(ppd->dd, sc5); + pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen); + if (ctxt) { + pbuf = sc_buffer_alloc(ctxt, plen, NULL, NULL); + if (pbuf) + ppd->dd->pio_inline_send(ppd->dd, pbuf, pbc, + &hdr, hwords); + } +} + +/* + * opa_smp_check() - Do the regular pkey checking, and the additional + * checks for SMPs specified in OPAv1 rev 0.90, section 9.10.26 + * ("SMA Packet Checks"). + * + * Note that: + * - Checks are done using the pkey directly from the packet's BTH, + * and specifically _not_ the pkey that we attach to the completion, + * which may be different. + * - These checks are specifically for "non-local" SMPs (i.e., SMPs + * which originated on another node). SMPs which are sent from, and + * destined to this node are checked in opa_local_smp_check(). + * + * At the point where opa_smp_check() is called, we know: + * - destination QP is QP0 + * + * opa_smp_check() returns 0 if all checks succeed, 1 otherwise. + */ +static int opa_smp_check(struct hfi1_ibport *ibp, u16 pkey, u8 sc5, + struct hfi1_qp *qp, u16 slid, struct opa_smp *smp) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + /* + * I don't think it's possible for us to get here with sc != 0xf, + * but check it to be certain. + */ + if (sc5 != 0xf) + return 1; + + if (rcv_pkey_check(ppd, pkey, sc5, slid)) + return 1; + + /* + * At this point we know (and so don't need to check again) that + * the pkey is either LIM_MGMT_P_KEY, or FULL_MGMT_P_KEY + * (see ingress_pkey_check). + */ + if (smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE && + smp->mgmt_class != IB_MGMT_CLASS_SUBN_LID_ROUTED) { + ingress_pkey_table_fail(ppd, pkey, slid); + return 1; + } + + /* + * SMPs fall into one of four (disjoint) categories: + * SMA request, SMA response, trap, or trap repress. + * Our response depends, in part, on which type of + * SMP we're processing. + * + * If this is not an SMA request, or trap repress: + * - accept MAD if the port is running an SM + * - pkey == FULL_MGMT_P_KEY => + * reply with unsupported method (i.e., just mark + * the smp's status field here, and let it be + * processed normally) + * - pkey != LIM_MGMT_P_KEY => + * increment port recv constraint errors, drop MAD + * If this is an SMA request or trap repress: + * - pkey != FULL_MGMT_P_KEY => + * increment port recv constraint errors, drop MAD + */ + switch (smp->method) { + case IB_MGMT_METHOD_GET: + case IB_MGMT_METHOD_SET: + case IB_MGMT_METHOD_REPORT: + case IB_MGMT_METHOD_TRAP_REPRESS: + if (pkey != FULL_MGMT_P_KEY) { + ingress_pkey_table_fail(ppd, pkey, slid); + return 1; + } + break; + case IB_MGMT_METHOD_SEND: + case IB_MGMT_METHOD_TRAP: + case IB_MGMT_METHOD_GET_RESP: + case IB_MGMT_METHOD_REPORT_RESP: + if (ibp->port_cap_flags & IB_PORT_SM) + return 0; + if (pkey == FULL_MGMT_P_KEY) { + smp->status |= IB_SMP_UNSUP_METHOD; + return 0; + } + if (pkey != LIM_MGMT_P_KEY) { + ingress_pkey_table_fail(ppd, pkey, slid); + return 1; + } + break; + default: + break; + } + return 0; +} + + +/** + * hfi1_ud_rcv - receive an incoming UD packet + * @ibp: the port the packet came in on + * @hdr: the packet header + * @rcv_flags: flags relevant to rcv processing + * @data: the packet data + * @tlen: the packet length + * @qp: the QP the packet came on + * + * This is called from qp_rcv() to process an incoming UD packet + * for the given QP. + * Called at interrupt level. + */ +void hfi1_ud_rcv(struct hfi1_packet *packet) +{ + struct hfi1_other_headers *ohdr = packet->ohdr; + int opcode; + u32 hdrsize = packet->hlen; + u32 pad; + struct ib_wc wc; + u32 qkey; + u32 src_qp; + u16 dlid, pkey; + int mgmt_pkey_idx = -1; + struct hfi1_ibport *ibp = &packet->rcd->ppd->ibport_data; + struct hfi1_ib_header *hdr = packet->hdr; + u32 rcv_flags = packet->rcv_flags; + void *data = packet->ebuf; + u32 tlen = packet->tlen; + struct hfi1_qp *qp = packet->qp; + bool has_grh = rcv_flags & HFI1_HAS_GRH; + bool sc4_bit = has_sc4_bit(packet); + u8 sc; + u32 bth1; + int is_mcast; + struct ib_grh *grh = NULL; + + qkey = be32_to_cpu(ohdr->u.ud.deth[0]); + src_qp = be32_to_cpu(ohdr->u.ud.deth[1]) & HFI1_QPN_MASK; + dlid = be16_to_cpu(hdr->lrh[1]); + is_mcast = (dlid > HFI1_MULTICAST_LID_BASE) && + (dlid != HFI1_PERMISSIVE_LID); + bth1 = be32_to_cpu(ohdr->bth[1]); + if (unlikely(bth1 & HFI1_BECN_SMASK)) { + /* + * In pre-B0 h/w the CNP_OPCODE is handled via an + * error path (errata 291394). + */ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 lqpn = be32_to_cpu(ohdr->bth[1]) & HFI1_QPN_MASK; + u8 sl, sc5; + + sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; + sc5 |= sc4_bit; + sl = ibp->sc_to_sl[sc5]; + + process_becn(ppd, sl, 0, lqpn, 0, IB_CC_SVCTYPE_UD); + } + + /* + * The opcode is in the low byte when its in network order + * (top byte when in host order). + */ + opcode = be32_to_cpu(ohdr->bth[0]) >> 24; + opcode &= 0xff; + + pkey = (u16)be32_to_cpu(ohdr->bth[0]); + + if (!is_mcast && (opcode != IB_OPCODE_CNP) && bth1 & HFI1_FECN_SMASK) { + u16 slid = be16_to_cpu(hdr->lrh[3]); + u8 sc5; + + sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; + sc5 |= sc4_bit; + + return_cnp(ibp, qp, src_qp, pkey, dlid, slid, sc5, grh); + } + /* + * Get the number of bytes the message was padded by + * and drop incomplete packets. + */ + pad = (be32_to_cpu(ohdr->bth[0]) >> 20) & 3; + if (unlikely(tlen < (hdrsize + pad + 4))) + goto drop; + + tlen -= hdrsize + pad + 4; + + /* + * Check that the permissive LID is only used on QP0 + * and the QKEY matches (see 9.6.1.4.1 and 9.6.1.5.1). + */ + if (qp->ibqp.qp_num) { + if (unlikely(hdr->lrh[1] == IB_LID_PERMISSIVE || + hdr->lrh[3] == IB_LID_PERMISSIVE)) + goto drop; + if (qp->ibqp.qp_num > 1) { + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u16 slid; + u8 sc5; + + sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; + sc5 |= sc4_bit; + + slid = be16_to_cpu(hdr->lrh[3]); + if (unlikely(rcv_pkey_check(ppd, pkey, sc5, slid))) { + /* + * Traps will not be sent for packets dropped + * by the HW. This is fine, as sending trap + * for invalid pkeys is optional according to + * IB spec (release 1.3, section 10.9.4) + */ + hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_PKEY, + pkey, + (be16_to_cpu(hdr->lrh[0]) >> 4) & + 0xF, + src_qp, qp->ibqp.qp_num, + hdr->lrh[3], hdr->lrh[1]); + return; + } + } else { + /* GSI packet */ + mgmt_pkey_idx = hfi1_lookup_pkey_idx(ibp, pkey); + if (mgmt_pkey_idx < 0) + goto drop; + + } + if (unlikely(qkey != qp->qkey)) { + hfi1_bad_pqkey(ibp, IB_NOTICE_TRAP_BAD_QKEY, qkey, + (be16_to_cpu(hdr->lrh[0]) >> 4) & 0xF, + src_qp, qp->ibqp.qp_num, + hdr->lrh[3], hdr->lrh[1]); + return; + } + /* Drop invalid MAD packets (see 13.5.3.1). */ + if (unlikely(qp->ibqp.qp_num == 1 && + (tlen > 2048 || + (be16_to_cpu(hdr->lrh[0]) >> 12) == 15))) + goto drop; + } else { + /* Received on QP0, and so by definition, this is an SMP */ + struct opa_smp *smp = (struct opa_smp *)data; + u16 slid = be16_to_cpu(hdr->lrh[3]); + u8 sc5; + + sc5 = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; + sc5 |= sc4_bit; + + if (opa_smp_check(ibp, pkey, sc5, qp, slid, smp)) + goto drop; + + if (tlen > 2048) + goto drop; + if ((hdr->lrh[1] == IB_LID_PERMISSIVE || + hdr->lrh[3] == IB_LID_PERMISSIVE) && + smp->mgmt_class != IB_MGMT_CLASS_SUBN_DIRECTED_ROUTE) + goto drop; + + /* look up SMI pkey */ + mgmt_pkey_idx = hfi1_lookup_pkey_idx(ibp, pkey); + if (mgmt_pkey_idx < 0) + goto drop; + + } + + if (qp->ibqp.qp_num > 1 && + opcode == IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE) { + wc.ex.imm_data = ohdr->u.ud.imm_data; + wc.wc_flags = IB_WC_WITH_IMM; + tlen -= sizeof(u32); + } else if (opcode == IB_OPCODE_UD_SEND_ONLY) { + wc.ex.imm_data = 0; + wc.wc_flags = 0; + } else + goto drop; + + /* + * A GRH is expected to precede the data even if not + * present on the wire. + */ + wc.byte_len = tlen + sizeof(struct ib_grh); + + /* + * Get the next work request entry to find where to put the data. + */ + if (qp->r_flags & HFI1_R_REUSE_SGE) + qp->r_flags &= ~HFI1_R_REUSE_SGE; + else { + int ret; + + ret = hfi1_get_rwqe(qp, 0); + if (ret < 0) { + hfi1_rc_error(qp, IB_WC_LOC_QP_OP_ERR); + return; + } + if (!ret) { + if (qp->ibqp.qp_num == 0) + ibp->n_vl15_dropped++; + return; + } + } + /* Silently drop packets which are too big. */ + if (unlikely(wc.byte_len > qp->r_len)) { + qp->r_flags |= HFI1_R_REUSE_SGE; + goto drop; + } + if (has_grh) { + hfi1_copy_sge(&qp->r_sge, &hdr->u.l.grh, + sizeof(struct ib_grh), 1); + wc.wc_flags |= IB_WC_GRH; + } else + hfi1_skip_sge(&qp->r_sge, sizeof(struct ib_grh), 1); + hfi1_copy_sge(&qp->r_sge, data, wc.byte_len - sizeof(struct ib_grh), 1); + hfi1_put_ss(&qp->r_sge); + if (!test_and_clear_bit(HFI1_R_WRID_VALID, &qp->r_aflags)) + return; + wc.wr_id = qp->r_wr_id; + wc.status = IB_WC_SUCCESS; + wc.opcode = IB_WC_RECV; + wc.vendor_err = 0; + wc.qp = &qp->ibqp; + wc.src_qp = src_qp; + + if (qp->ibqp.qp_type == IB_QPT_GSI || + qp->ibqp.qp_type == IB_QPT_SMI) { + if (mgmt_pkey_idx < 0) { + if (net_ratelimit()) { + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct hfi1_devdata *dd = ppd->dd; + + dd_dev_err(dd, "QP type %d mgmt_pkey_idx < 0 and packet not dropped???\n", + qp->ibqp.qp_type); + mgmt_pkey_idx = 0; + } + } + wc.pkey_index = (unsigned)mgmt_pkey_idx; + } else + wc.pkey_index = 0; + + wc.slid = be16_to_cpu(hdr->lrh[3]); + sc = (be16_to_cpu(hdr->lrh[0]) >> 12) & 0xf; + sc |= sc4_bit; + wc.sl = ibp->sc_to_sl[sc]; + + /* + * Save the LMC lower bits if the destination LID is a unicast LID. + */ + wc.dlid_path_bits = dlid >= HFI1_MULTICAST_LID_BASE ? 0 : + dlid & ((1 << ppd_from_ibp(ibp)->lmc) - 1); + wc.port_num = qp->port_num; + /* Signal completion event if the solicited bit is set. */ + hfi1_cq_enter(to_icq(qp->ibqp.recv_cq), &wc, + (ohdr->bth[0] & + cpu_to_be32(IB_BTH_SOLICITED)) != 0); + return; + +drop: + ibp->n_pkt_drops++; +} diff --git a/drivers/staging/rdma/hfi1/user_pages.c b/drivers/staging/rdma/hfi1/user_pages.c new file mode 100644 index 0000000000000..9071afbd7bf44 --- /dev/null +++ b/drivers/staging/rdma/hfi1/user_pages.c @@ -0,0 +1,156 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include "hfi.h" + +static void __hfi1_release_user_pages(struct page **p, size_t num_pages, + int dirty) +{ + size_t i; + + for (i = 0; i < num_pages; i++) { + if (dirty) + set_page_dirty_lock(p[i]); + put_page(p[i]); + } +} + +/* + * Call with current->mm->mmap_sem held. + */ +static int __hfi1_get_user_pages(unsigned long start_page, size_t num_pages, + struct page **p) +{ + unsigned long lock_limit; + size_t got; + int ret; + + lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + + if (num_pages > lock_limit && !capable(CAP_IPC_LOCK)) { + ret = -ENOMEM; + goto bail; + } + + for (got = 0; got < num_pages; got += ret) { + ret = get_user_pages(current, current->mm, + start_page + got * PAGE_SIZE, + num_pages - got, 1, 1, + p + got, NULL); + if (ret < 0) + goto bail_release; + } + + current->mm->pinned_vm += num_pages; + + ret = 0; + goto bail; + +bail_release: + __hfi1_release_user_pages(p, got, 0); +bail: + return ret; +} + +/** + * hfi1_map_page - a safety wrapper around pci_map_page() + * + */ +dma_addr_t hfi1_map_page(struct pci_dev *hwdev, struct page *page, + unsigned long offset, size_t size, int direction) +{ + dma_addr_t phys; + + phys = pci_map_page(hwdev, page, offset, size, direction); + + return phys; +} + +/** + * hfi1_get_user_pages - lock user pages into memory + * @start_page: the start page + * @num_pages: the number of pages + * @p: the output page structures + * + * This function takes a given start page (page aligned user virtual + * address) and pins it and the following specified number of pages. For + * now, num_pages is always 1, but that will probably change at some point + * (because caller is doing expected sends on a single virtually contiguous + * buffer, so we can do all pages at once). + */ +int hfi1_get_user_pages(unsigned long start_page, size_t num_pages, + struct page **p) +{ + int ret; + + down_write(¤t->mm->mmap_sem); + + ret = __hfi1_get_user_pages(start_page, num_pages, p); + + up_write(¤t->mm->mmap_sem); + + return ret; +} + +void hfi1_release_user_pages(struct page **p, size_t num_pages) +{ + if (current->mm) /* during close after signal, mm can be NULL */ + down_write(¤t->mm->mmap_sem); + + __hfi1_release_user_pages(p, num_pages, 1); + + if (current->mm) { + current->mm->pinned_vm -= num_pages; + up_write(¤t->mm->mmap_sem); + } +} diff --git a/drivers/staging/rdma/hfi1/user_sdma.c b/drivers/staging/rdma/hfi1/user_sdma.c new file mode 100644 index 0000000000000..55526613a522a --- /dev/null +++ b/drivers/staging/rdma/hfi1/user_sdma.c @@ -0,0 +1,1444 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "sdma.h" +#include "user_sdma.h" +#include "sdma.h" +#include "verbs.h" /* for the headers */ +#include "common.h" /* for struct hfi1_tid_info */ +#include "trace.h" + +static uint hfi1_sdma_comp_ring_size = 128; +module_param_named(sdma_comp_size, hfi1_sdma_comp_ring_size, uint, S_IRUGO); +MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 128"); + +/* The maximum number of Data io vectors per message/request */ +#define MAX_VECTORS_PER_REQ 8 +/* + * Maximum number of packet to send from each message/request + * before moving to the next one. + */ +#define MAX_PKTS_PER_QUEUE 16 + +#define num_pages(x) (1 + ((((x) - 1) & PAGE_MASK) >> PAGE_SHIFT)) + +#define req_opcode(x) \ + (((x) >> HFI1_SDMA_REQ_OPCODE_SHIFT) & HFI1_SDMA_REQ_OPCODE_MASK) +#define req_version(x) \ + (((x) >> HFI1_SDMA_REQ_VERSION_SHIFT) & HFI1_SDMA_REQ_OPCODE_MASK) +#define req_iovcnt(x) \ + (((x) >> HFI1_SDMA_REQ_IOVCNT_SHIFT) & HFI1_SDMA_REQ_IOVCNT_MASK) + +/* Number of BTH.PSN bits used for sequence number in expected rcvs */ +#define BTH_SEQ_MASK 0x7ffull + +/* + * Define fields in the KDETH header so we can update the header + * template. + */ +#define KDETH_OFFSET_SHIFT 0 +#define KDETH_OFFSET_MASK 0x7fff +#define KDETH_OM_SHIFT 15 +#define KDETH_OM_MASK 0x1 +#define KDETH_TID_SHIFT 16 +#define KDETH_TID_MASK 0x3ff +#define KDETH_TIDCTRL_SHIFT 26 +#define KDETH_TIDCTRL_MASK 0x3 +#define KDETH_INTR_SHIFT 28 +#define KDETH_INTR_MASK 0x1 +#define KDETH_SH_SHIFT 29 +#define KDETH_SH_MASK 0x1 +#define KDETH_HCRC_UPPER_SHIFT 16 +#define KDETH_HCRC_UPPER_MASK 0xff +#define KDETH_HCRC_LOWER_SHIFT 24 +#define KDETH_HCRC_LOWER_MASK 0xff + +#define PBC2LRH(x) ((((x) & 0xfff) << 2) - 4) +#define LRH2PBC(x) ((((x) >> 2) + 1) & 0xfff) + +#define KDETH_GET(val, field) \ + (((le32_to_cpu((val))) >> KDETH_##field##_SHIFT) & KDETH_##field##_MASK) +#define KDETH_SET(dw, field, val) do { \ + u32 dwval = le32_to_cpu(dw); \ + dwval &= ~(KDETH_##field##_MASK << KDETH_##field##_SHIFT); \ + dwval |= (((val) & KDETH_##field##_MASK) << \ + KDETH_##field##_SHIFT); \ + dw = cpu_to_le32(dwval); \ + } while (0) + +#define AHG_HEADER_SET(arr, idx, dw, bit, width, value) \ + do { \ + if ((idx) < ARRAY_SIZE((arr))) \ + (arr)[(idx++)] = sdma_build_ahg_descriptor( \ + (__force u16)(value), (dw), (bit), \ + (width)); \ + else \ + return -ERANGE; \ + } while (0) + +/* KDETH OM multipliers and switch over point */ +#define KDETH_OM_SMALL 4 +#define KDETH_OM_LARGE 64 +#define KDETH_OM_MAX_SIZE (1 << ((KDETH_OM_LARGE / KDETH_OM_SMALL) + 1)) + +/* Last packet in the request */ +#define USER_SDMA_TXREQ_FLAGS_LAST_PKT (1 << 0) + +#define SDMA_REQ_IN_USE 0 +#define SDMA_REQ_FOR_THREAD 1 +#define SDMA_REQ_SEND_DONE 2 +#define SDMA_REQ_HAVE_AHG 3 +#define SDMA_REQ_HAS_ERROR 4 +#define SDMA_REQ_DONE_ERROR 5 + +#define SDMA_PKT_Q_INACTIVE (1 << 0) +#define SDMA_PKT_Q_ACTIVE (1 << 1) +#define SDMA_PKT_Q_DEFERRED (1 << 2) + +/* + * Maximum retry attempts to submit a TX request + * before putting the process to sleep. + */ +#define MAX_DEFER_RETRY_COUNT 1 + +static unsigned initial_pkt_count = 8; + +#define SDMA_IOWAIT_TIMEOUT 1000 /* in milliseconds */ + +struct user_sdma_iovec { + struct iovec iov; + /* number of pages in this vector */ + unsigned npages; + /* array of pinned pages for this vector */ + struct page **pages; + /* offset into the virtual address space of the vector at + * which we last left off. */ + u64 offset; +}; + +struct user_sdma_request { + struct sdma_req_info info; + struct hfi1_user_sdma_pkt_q *pq; + struct hfi1_user_sdma_comp_q *cq; + /* This is the original header from user space */ + struct hfi1_pkt_header hdr; + /* + * Pointer to the SDMA engine for this request. + * Since different request could be on different VLs, + * each request will need it's own engine pointer. + */ + struct sdma_engine *sde; + u8 ahg_idx; + u32 ahg[9]; + /* + * KDETH.Offset (Eager) field + * We need to remember the initial value so the headers + * can be updated properly. + */ + u32 koffset; + /* + * KDETH.OFFSET (TID) field + * The offset can cover multiple packets, depending on the + * size of the TID entry. + */ + u32 tidoffset; + /* + * KDETH.OM + * Remember this because the header template always sets it + * to 0. + */ + u8 omfactor; + /* + * pointer to the user's task_struct. We are going to + * get a reference to it so we can process io vectors + * at a later time. + */ + struct task_struct *user_proc; + /* + * pointer to the user's mm_struct. We are going to + * get a reference to it so it doesn't get freed + * since we might not be in process context when we + * are processing the iov's. + * Using this mm_struct, we can get vma based on the + * iov's address (find_vma()). + */ + struct mm_struct *user_mm; + /* + * We copy the iovs for this request (based on + * info.iovcnt). These are only the data vectors + */ + unsigned data_iovs; + /* total length of the data in the request */ + u32 data_len; + /* progress index moving along the iovs array */ + unsigned iov_idx; + struct user_sdma_iovec iovs[MAX_VECTORS_PER_REQ]; + /* number of elements copied to the tids array */ + u16 n_tids; + /* TID array values copied from the tid_iov vector */ + u32 *tids; + u16 tididx; + u32 sent; + u64 seqnum; + spinlock_t list_lock; + struct list_head txps; + unsigned long flags; +}; + +struct user_sdma_txreq { + /* Packet header for the txreq */ + struct hfi1_pkt_header hdr; + struct sdma_txreq txreq; + struct user_sdma_request *req; + struct user_sdma_iovec *iovec1; + struct user_sdma_iovec *iovec2; + u16 flags; + unsigned busycount; + u64 seqnum; +}; + +#define SDMA_DBG(req, fmt, ...) \ + hfi1_cdbg(SDMA, "[%u:%u:%u:%u] " fmt, (req)->pq->dd->unit, \ + (req)->pq->ctxt, (req)->pq->subctxt, (req)->info.comp_idx, \ + ##__VA_ARGS__) +#define SDMA_Q_DBG(pq, fmt, ...) \ + hfi1_cdbg(SDMA, "[%u:%u:%u] " fmt, (pq)->dd->unit, (pq)->ctxt, \ + (pq)->subctxt, ##__VA_ARGS__) + +static int user_sdma_send_pkts(struct user_sdma_request *, unsigned); +static int num_user_pages(const struct iovec *); +static void user_sdma_txreq_cb(struct sdma_txreq *, int, int); +static void user_sdma_free_request(struct user_sdma_request *); +static int pin_vector_pages(struct user_sdma_request *, + struct user_sdma_iovec *); +static void unpin_vector_pages(struct user_sdma_iovec *); +static int check_header_template(struct user_sdma_request *, + struct hfi1_pkt_header *, u32, u32); +static int set_txreq_header(struct user_sdma_request *, + struct user_sdma_txreq *, u32); +static int set_txreq_header_ahg(struct user_sdma_request *, + struct user_sdma_txreq *, u32); +static inline void set_comp_state(struct user_sdma_request *, + enum hfi1_sdma_comp_state, int); +static inline u32 set_pkt_bth_psn(__be32, u8, u32); +static inline u32 get_lrh_len(struct hfi1_pkt_header, u32 len); + +static int defer_packet_queue( + struct sdma_engine *, + struct iowait *, + struct sdma_txreq *, + unsigned seq); +static void activate_packet_queue(struct iowait *, int); + +static inline int iovec_may_free(struct user_sdma_iovec *iovec, + void (*free)(struct user_sdma_iovec *)) +{ + if (ACCESS_ONCE(iovec->offset) == iovec->iov.iov_len) { + free(iovec); + return 1; + } + return 0; +} + +static inline void iovec_set_complete(struct user_sdma_iovec *iovec) +{ + iovec->offset = iovec->iov.iov_len; +} + +static int defer_packet_queue( + struct sdma_engine *sde, + struct iowait *wait, + struct sdma_txreq *txreq, + unsigned seq) +{ + struct hfi1_user_sdma_pkt_q *pq = + container_of(wait, struct hfi1_user_sdma_pkt_q, busy); + struct hfi1_ibdev *dev = &pq->dd->verbs_dev; + struct user_sdma_txreq *tx = + container_of(txreq, struct user_sdma_txreq, txreq); + + if (sdma_progress(sde, seq, txreq)) { + if (tx->busycount++ < MAX_DEFER_RETRY_COUNT) + goto eagain; + } + /* + * We are assuming that if the list is enqueued somewhere, it + * is to the dmawait list since that is the only place where + * it is supposed to be enqueued. + */ + xchg(&pq->state, SDMA_PKT_Q_DEFERRED); + write_seqlock(&dev->iowait_lock); + if (list_empty(&pq->busy.list)) + list_add_tail(&pq->busy.list, &sde->dmawait); + write_sequnlock(&dev->iowait_lock); + return -EBUSY; +eagain: + return -EAGAIN; +} + +static void activate_packet_queue(struct iowait *wait, int reason) +{ + struct hfi1_user_sdma_pkt_q *pq = + container_of(wait, struct hfi1_user_sdma_pkt_q, busy); + xchg(&pq->state, SDMA_PKT_Q_ACTIVE); + wake_up(&wait->wait_dma); +}; + +static void sdma_kmem_cache_ctor(void *obj) +{ + struct user_sdma_txreq *tx = (struct user_sdma_txreq *)obj; + + memset(tx, 0, sizeof(*tx)); +} + +int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *uctxt, struct file *fp) +{ + int ret = 0; + unsigned memsize; + char buf[64]; + struct hfi1_devdata *dd; + struct hfi1_user_sdma_comp_q *cq; + struct hfi1_user_sdma_pkt_q *pq; + unsigned long flags; + + if (!uctxt || !fp) { + ret = -EBADF; + goto done; + } + + if (!hfi1_sdma_comp_ring_size) { + ret = -EINVAL; + goto done; + } + + dd = uctxt->dd; + + pq = kzalloc(sizeof(*pq), GFP_KERNEL); + if (!pq) { + dd_dev_err(dd, + "[%u:%u] Failed to allocate SDMA request struct\n", + uctxt->ctxt, subctxt_fp(fp)); + goto pq_nomem; + } + memsize = sizeof(*pq->reqs) * hfi1_sdma_comp_ring_size; + pq->reqs = kmalloc(memsize, GFP_KERNEL); + if (!pq->reqs) { + dd_dev_err(dd, + "[%u:%u] Failed to allocate SDMA request queue (%u)\n", + uctxt->ctxt, subctxt_fp(fp), memsize); + goto pq_reqs_nomem; + } + INIT_LIST_HEAD(&pq->list); + pq->dd = dd; + pq->ctxt = uctxt->ctxt; + pq->subctxt = subctxt_fp(fp); + pq->n_max_reqs = hfi1_sdma_comp_ring_size; + pq->state = SDMA_PKT_Q_INACTIVE; + atomic_set(&pq->n_reqs, 0); + + iowait_init(&pq->busy, 0, NULL, defer_packet_queue, + activate_packet_queue); + pq->reqidx = 0; + snprintf(buf, 64, "txreq-kmem-cache-%u-%u-%u", dd->unit, uctxt->ctxt, + subctxt_fp(fp)); + pq->txreq_cache = kmem_cache_create(buf, + sizeof(struct user_sdma_txreq), + L1_CACHE_BYTES, + SLAB_HWCACHE_ALIGN, + sdma_kmem_cache_ctor); + if (!pq->txreq_cache) { + dd_dev_err(dd, "[%u] Failed to allocate TxReq cache\n", + uctxt->ctxt); + goto pq_txreq_nomem; + } + user_sdma_pkt_fp(fp) = pq; + cq = kzalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) { + dd_dev_err(dd, + "[%u:%u] Failed to allocate SDMA completion queue\n", + uctxt->ctxt, subctxt_fp(fp)); + goto cq_nomem; + } + + memsize = ALIGN(sizeof(*cq->comps) * hfi1_sdma_comp_ring_size, + PAGE_SIZE); + cq->comps = vmalloc_user(memsize); + if (!cq->comps) { + dd_dev_err(dd, + "[%u:%u] Failed to allocate SDMA completion queue entries\n", + uctxt->ctxt, subctxt_fp(fp)); + goto cq_comps_nomem; + } + cq->nentries = hfi1_sdma_comp_ring_size; + user_sdma_comp_fp(fp) = cq; + + spin_lock_irqsave(&uctxt->sdma_qlock, flags); + list_add(&pq->list, &uctxt->sdma_queues); + spin_unlock_irqrestore(&uctxt->sdma_qlock, flags); + goto done; + +cq_comps_nomem: + kfree(cq); +cq_nomem: + kmem_cache_destroy(pq->txreq_cache); +pq_txreq_nomem: + kfree(pq->reqs); +pq_reqs_nomem: + kfree(pq); + user_sdma_pkt_fp(fp) = NULL; +pq_nomem: + ret = -ENOMEM; +done: + return ret; +} + +int hfi1_user_sdma_free_queues(struct hfi1_filedata *fd) +{ + struct hfi1_ctxtdata *uctxt = fd->uctxt; + struct hfi1_user_sdma_pkt_q *pq; + unsigned long flags; + + hfi1_cdbg(SDMA, "[%u:%u:%u] Freeing user SDMA queues", uctxt->dd->unit, + uctxt->ctxt, fd->subctxt); + pq = fd->pq; + if (pq) { + u16 i, j; + + spin_lock_irqsave(&uctxt->sdma_qlock, flags); + if (!list_empty(&pq->list)) + list_del_init(&pq->list); + spin_unlock_irqrestore(&uctxt->sdma_qlock, flags); + iowait_sdma_drain(&pq->busy); + if (pq->reqs) { + for (i = 0, j = 0; i < atomic_read(&pq->n_reqs) && + j < pq->n_max_reqs; j++) { + struct user_sdma_request *req = &pq->reqs[j]; + + if (test_bit(SDMA_REQ_IN_USE, &req->flags)) { + set_comp_state(req, ERROR, -ECOMM); + user_sdma_free_request(req); + i++; + } + } + kfree(pq->reqs); + } + if (pq->txreq_cache) + kmem_cache_destroy(pq->txreq_cache); + kfree(pq); + fd->pq = NULL; + } + if (fd->cq) { + if (fd->cq->comps) + vfree(fd->cq->comps); + kfree(fd->cq); + fd->cq = NULL; + } + return 0; +} + +int hfi1_user_sdma_process_request(struct file *fp, struct iovec *iovec, + unsigned long dim, unsigned long *count) +{ + int ret = 0, i = 0, sent; + struct hfi1_ctxtdata *uctxt = ctxt_fp(fp); + struct hfi1_user_sdma_pkt_q *pq = user_sdma_pkt_fp(fp); + struct hfi1_user_sdma_comp_q *cq = user_sdma_comp_fp(fp); + struct hfi1_devdata *dd = pq->dd; + unsigned long idx = 0; + u8 pcount = initial_pkt_count; + struct sdma_req_info info; + struct user_sdma_request *req; + u8 opcode, sc, vl; + + if (iovec[idx].iov_len < sizeof(info) + sizeof(req->hdr)) { + hfi1_cdbg( + SDMA, + "[%u:%u:%u] First vector not big enough for header %lu/%lu", + dd->unit, uctxt->ctxt, subctxt_fp(fp), + iovec[idx].iov_len, sizeof(info) + sizeof(req->hdr)); + ret = -EINVAL; + goto done; + } + ret = copy_from_user(&info, iovec[idx].iov_base, sizeof(info)); + if (ret) { + hfi1_cdbg(SDMA, "[%u:%u:%u] Failed to copy info QW (%d)", + dd->unit, uctxt->ctxt, subctxt_fp(fp), ret); + ret = -EFAULT; + goto done; + } + trace_hfi1_sdma_user_reqinfo(dd, uctxt->ctxt, subctxt_fp(fp), + (u16 *)&info); + if (cq->comps[info.comp_idx].status == QUEUED) { + hfi1_cdbg(SDMA, "[%u:%u:%u] Entry %u is in QUEUED state", + dd->unit, uctxt->ctxt, subctxt_fp(fp), + info.comp_idx); + ret = -EBADSLT; + goto done; + } + if (!info.fragsize) { + hfi1_cdbg(SDMA, + "[%u:%u:%u:%u] Request does not specify fragsize", + dd->unit, uctxt->ctxt, subctxt_fp(fp), info.comp_idx); + ret = -EINVAL; + goto done; + } + /* + * We've done all the safety checks that we can up to this point, + * "allocate" the request entry. + */ + hfi1_cdbg(SDMA, "[%u:%u:%u] Using req/comp entry %u\n", dd->unit, + uctxt->ctxt, subctxt_fp(fp), info.comp_idx); + req = pq->reqs + info.comp_idx; + memset(req, 0, sizeof(*req)); + /* Mark the request as IN_USE before we start filling it in. */ + set_bit(SDMA_REQ_IN_USE, &req->flags); + req->data_iovs = req_iovcnt(info.ctrl) - 1; + req->pq = pq; + req->cq = cq; + INIT_LIST_HEAD(&req->txps); + spin_lock_init(&req->list_lock); + memcpy(&req->info, &info, sizeof(info)); + + if (req_opcode(info.ctrl) == EXPECTED) + req->data_iovs--; + + if (!info.npkts || req->data_iovs > MAX_VECTORS_PER_REQ) { + SDMA_DBG(req, "Too many vectors (%u/%u)", req->data_iovs, + MAX_VECTORS_PER_REQ); + ret = -EINVAL; + goto done; + } + /* Copy the header from the user buffer */ + ret = copy_from_user(&req->hdr, iovec[idx].iov_base + sizeof(info), + sizeof(req->hdr)); + if (ret) { + SDMA_DBG(req, "Failed to copy header template (%d)", ret); + ret = -EFAULT; + goto free_req; + } + + /* If Static rate control is not enabled, sanitize the header. */ + if (!HFI1_CAP_IS_USET(STATIC_RATE_CTRL)) + req->hdr.pbc[2] = 0; + + /* Validate the opcode. Do not trust packets from user space blindly. */ + opcode = (be32_to_cpu(req->hdr.bth[0]) >> 24) & 0xff; + if ((opcode & USER_OPCODE_CHECK_MASK) != + USER_OPCODE_CHECK_VAL) { + SDMA_DBG(req, "Invalid opcode (%d)", opcode); + ret = -EINVAL; + goto free_req; + } + /* + * Validate the vl. Do not trust packets from user space blindly. + * VL comes from PBC, SC comes from LRH, and the VL needs to + * match the SC look up. + */ + vl = (le16_to_cpu(req->hdr.pbc[0]) >> 12) & 0xF; + sc = (((be16_to_cpu(req->hdr.lrh[0]) >> 12) & 0xF) | + (((le16_to_cpu(req->hdr.pbc[1]) >> 14) & 0x1) << 4)); + if (vl >= dd->pport->vls_operational || + vl != sc_to_vlt(dd, sc)) { + SDMA_DBG(req, "Invalid SC(%u)/VL(%u)", sc, vl); + ret = -EINVAL; + goto free_req; + } + + /* + * Also should check the BTH.lnh. If it says the next header is GRH then + * the RXE parsing will be off and will land in the middle of the KDETH + * or miss it entirely. + */ + if ((be16_to_cpu(req->hdr.lrh[0]) & 0x3) == HFI1_LRH_GRH) { + SDMA_DBG(req, "User tried to pass in a GRH"); + ret = -EINVAL; + goto free_req; + } + + req->koffset = le32_to_cpu(req->hdr.kdeth.swdata[6]); + /* Calculate the initial TID offset based on the values of + KDETH.OFFSET and KDETH.OM that are passed in. */ + req->tidoffset = KDETH_GET(req->hdr.kdeth.ver_tid_offset, OFFSET) * + (KDETH_GET(req->hdr.kdeth.ver_tid_offset, OM) ? + KDETH_OM_LARGE : KDETH_OM_SMALL); + SDMA_DBG(req, "Initial TID offset %u", req->tidoffset); + idx++; + + /* Save all the IO vector structures */ + while (i < req->data_iovs) { + memcpy(&req->iovs[i].iov, iovec + idx++, sizeof(struct iovec)); + req->iovs[i].offset = 0; + req->data_len += req->iovs[i++].iov.iov_len; + } + SDMA_DBG(req, "total data length %u", req->data_len); + + if (pcount > req->info.npkts) + pcount = req->info.npkts; + /* + * Copy any TID info + * User space will provide the TID info only when the + * request type is EXPECTED. This is true even if there is + * only one packet in the request and the header is already + * setup. The reason for the singular TID case is that the + * driver needs to perform safety checks. + */ + if (req_opcode(req->info.ctrl) == EXPECTED) { + u16 ntids = iovec[idx].iov_len / sizeof(*req->tids); + + if (!ntids || ntids > MAX_TID_PAIR_ENTRIES) { + ret = -EINVAL; + goto free_req; + } + req->tids = kcalloc(ntids, sizeof(*req->tids), GFP_KERNEL); + if (!req->tids) { + ret = -ENOMEM; + goto free_req; + } + /* + * We have to copy all of the tids because they may vary + * in size and, therefore, the TID count might not be + * equal to the pkt count. However, there is no way to + * tell at this point. + */ + ret = copy_from_user(req->tids, iovec[idx].iov_base, + ntids * sizeof(*req->tids)); + if (ret) { + SDMA_DBG(req, "Failed to copy %d TIDs (%d)", + ntids, ret); + ret = -EFAULT; + goto free_req; + } + req->n_tids = ntids; + idx++; + } + + /* Have to select the engine */ + req->sde = sdma_select_engine_vl(dd, + (u32)(uctxt->ctxt + subctxt_fp(fp)), + vl); + if (!req->sde || !sdma_running(req->sde)) { + ret = -ECOMM; + goto free_req; + } + + /* We don't need an AHG entry if the request contains only one packet */ + if (req->info.npkts > 1 && HFI1_CAP_IS_USET(SDMA_AHG)) { + int ahg = sdma_ahg_alloc(req->sde); + + if (likely(ahg >= 0)) { + req->ahg_idx = (u8)ahg; + set_bit(SDMA_REQ_HAVE_AHG, &req->flags); + } + } + + set_comp_state(req, QUEUED, 0); + /* Send the first N packets in the request to buy us some time */ + sent = user_sdma_send_pkts(req, pcount); + if (unlikely(sent < 0)) { + if (sent != -EBUSY) { + ret = sent; + goto send_err; + } else + sent = 0; + } + atomic_inc(&pq->n_reqs); + + if (sent < req->info.npkts) { + /* Take the references to the user's task and mm_struct */ + get_task_struct(current); + req->user_proc = current; + + /* + * This is a somewhat blocking send implementation. + * The driver will block the caller until all packets of the + * request have been submitted to the SDMA engine. However, it + * will not wait for send completions. + */ + while (!test_bit(SDMA_REQ_SEND_DONE, &req->flags)) { + ret = user_sdma_send_pkts(req, pcount); + if (ret < 0) { + if (ret != -EBUSY) + goto send_err; + wait_event_interruptible_timeout( + pq->busy.wait_dma, + (pq->state == SDMA_PKT_Q_ACTIVE), + msecs_to_jiffies( + SDMA_IOWAIT_TIMEOUT)); + } + } + + } + ret = 0; + *count += idx; + goto done; +send_err: + set_comp_state(req, ERROR, ret); +free_req: + user_sdma_free_request(req); +done: + return ret; +} + +static inline u32 compute_data_length(struct user_sdma_request *req, + struct user_sdma_txreq *tx) +{ + /* + * Determine the proper size of the packet data. + * The size of the data of the first packet is in the header + * template. However, it includes the header and ICRC, which need + * to be subtracted. + * The size of the remaining packets is the minimum of the frag + * size (MTU) or remaining data in the request. + */ + u32 len; + + if (!req->seqnum) { + len = ((be16_to_cpu(req->hdr.lrh[2]) << 2) - + (sizeof(tx->hdr) - 4)); + } else if (req_opcode(req->info.ctrl) == EXPECTED) { + u32 tidlen = EXP_TID_GET(req->tids[req->tididx], LEN) * + PAGE_SIZE; + /* Get the data length based on the remaining space in the + * TID pair. */ + len = min(tidlen - req->tidoffset, (u32)req->info.fragsize); + /* If we've filled up the TID pair, move to the next one. */ + if (unlikely(!len) && ++req->tididx < req->n_tids && + req->tids[req->tididx]) { + tidlen = EXP_TID_GET(req->tids[req->tididx], + LEN) * PAGE_SIZE; + req->tidoffset = 0; + len = min_t(u32, tidlen, req->info.fragsize); + } + /* Since the TID pairs map entire pages, make sure that we + * are not going to try to send more data that we have + * remaining. */ + len = min(len, req->data_len - req->sent); + } else + len = min(req->data_len - req->sent, (u32)req->info.fragsize); + SDMA_DBG(req, "Data Length = %u", len); + return len; +} + +static inline u32 get_lrh_len(struct hfi1_pkt_header hdr, u32 len) +{ + /* (Size of complete header - size of PBC) + 4B ICRC + data length */ + return ((sizeof(hdr) - sizeof(hdr.pbc)) + 4 + len); +} + +static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) +{ + int ret = 0; + unsigned npkts = 0; + struct user_sdma_txreq *tx = NULL; + struct hfi1_user_sdma_pkt_q *pq = NULL; + struct user_sdma_iovec *iovec = NULL; + + if (!req->pq) { + ret = -EINVAL; + goto done; + } + + pq = req->pq; + + /* + * Check if we might have sent the entire request already + */ + if (unlikely(req->seqnum == req->info.npkts)) { + if (!list_empty(&req->txps)) + goto dosend; + goto done; + } + + if (!maxpkts || maxpkts > req->info.npkts - req->seqnum) + maxpkts = req->info.npkts - req->seqnum; + + while (npkts < maxpkts) { + u32 datalen = 0, queued = 0, data_sent = 0; + u64 iov_offset = 0; + + /* + * Check whether any of the completions have come back + * with errors. If so, we are not going to process any + * more packets from this request. + */ + if (test_bit(SDMA_REQ_HAS_ERROR, &req->flags)) { + set_bit(SDMA_REQ_DONE_ERROR, &req->flags); + ret = -EFAULT; + goto done; + } + + tx = kmem_cache_alloc(pq->txreq_cache, GFP_KERNEL); + if (!tx) { + ret = -ENOMEM; + goto done; + } + tx->flags = 0; + tx->req = req; + tx->busycount = 0; + tx->iovec1 = NULL; + tx->iovec2 = NULL; + + if (req->seqnum == req->info.npkts - 1) + tx->flags |= USER_SDMA_TXREQ_FLAGS_LAST_PKT; + + /* + * Calculate the payload size - this is min of the fragment + * (MTU) size or the remaining bytes in the request but only + * if we have payload data. + */ + if (req->data_len) { + iovec = &req->iovs[req->iov_idx]; + if (ACCESS_ONCE(iovec->offset) == iovec->iov.iov_len) { + if (++req->iov_idx == req->data_iovs) { + ret = -EFAULT; + goto free_txreq; + } + iovec = &req->iovs[req->iov_idx]; + WARN_ON(iovec->offset); + } + + /* + * This request might include only a header and no user + * data, so pin pages only if there is data and it the + * pages have not been pinned already. + */ + if (unlikely(!iovec->pages && iovec->iov.iov_len)) { + ret = pin_vector_pages(req, iovec); + if (ret) + goto free_tx; + } + + tx->iovec1 = iovec; + datalen = compute_data_length(req, tx); + if (!datalen) { + SDMA_DBG(req, + "Request has data but pkt len is 0"); + ret = -EFAULT; + goto free_tx; + } + } + + if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags)) { + if (!req->seqnum) { + u16 pbclen = le16_to_cpu(req->hdr.pbc[0]); + u32 lrhlen = get_lrh_len(req->hdr, datalen); + /* + * Copy the request header into the tx header + * because the HW needs a cacheline-aligned + * address. + * This copy can be optimized out if the hdr + * member of user_sdma_request were also + * cacheline aligned. + */ + memcpy(&tx->hdr, &req->hdr, sizeof(tx->hdr)); + if (PBC2LRH(pbclen) != lrhlen) { + pbclen = (pbclen & 0xf000) | + LRH2PBC(lrhlen); + tx->hdr.pbc[0] = cpu_to_le16(pbclen); + } + ret = sdma_txinit_ahg(&tx->txreq, + SDMA_TXREQ_F_AHG_COPY, + sizeof(tx->hdr) + datalen, + req->ahg_idx, 0, NULL, 0, + user_sdma_txreq_cb); + if (ret) + goto free_tx; + ret = sdma_txadd_kvaddr(pq->dd, &tx->txreq, + &tx->hdr, + sizeof(tx->hdr)); + if (ret) + goto free_txreq; + } else { + int changes; + + changes = set_txreq_header_ahg(req, tx, + datalen); + if (changes < 0) + goto free_tx; + sdma_txinit_ahg(&tx->txreq, + SDMA_TXREQ_F_USE_AHG, + datalen, req->ahg_idx, changes, + req->ahg, sizeof(req->hdr), + user_sdma_txreq_cb); + } + } else { + ret = sdma_txinit(&tx->txreq, 0, sizeof(req->hdr) + + datalen, user_sdma_txreq_cb); + if (ret) + goto free_tx; + /* + * Modify the header for this packet. This only needs + * to be done if we are not going to use AHG. Otherwise, + * the HW will do it based on the changes we gave it + * during sdma_txinit_ahg(). + */ + ret = set_txreq_header(req, tx, datalen); + if (ret) + goto free_txreq; + } + + /* + * If the request contains any data vectors, add up to + * fragsize bytes to the descriptor. + */ + while (queued < datalen && + (req->sent + data_sent) < req->data_len) { + unsigned long base, offset; + unsigned pageidx, len; + + base = (unsigned long)iovec->iov.iov_base; + offset = ((base + iovec->offset + iov_offset) & + ~PAGE_MASK); + pageidx = (((iovec->offset + iov_offset + + base) - (base & PAGE_MASK)) >> PAGE_SHIFT); + len = offset + req->info.fragsize > PAGE_SIZE ? + PAGE_SIZE - offset : req->info.fragsize; + len = min((datalen - queued), len); + ret = sdma_txadd_page(pq->dd, &tx->txreq, + iovec->pages[pageidx], + offset, len); + if (ret) { + dd_dev_err(pq->dd, + "SDMA txreq add page failed %d\n", + ret); + iovec_set_complete(iovec); + goto free_txreq; + } + iov_offset += len; + queued += len; + data_sent += len; + if (unlikely(queued < datalen && + pageidx == iovec->npages && + req->iov_idx < req->data_iovs - 1)) { + iovec->offset += iov_offset; + iovec = &req->iovs[++req->iov_idx]; + if (!iovec->pages) { + ret = pin_vector_pages(req, iovec); + if (ret) + goto free_txreq; + } + iov_offset = 0; + tx->iovec2 = iovec; + + } + } + /* + * The txreq was submitted successfully so we can update + * the counters. + */ + req->koffset += datalen; + if (req_opcode(req->info.ctrl) == EXPECTED) + req->tidoffset += datalen; + req->sent += data_sent; + if (req->data_len) { + if (tx->iovec1 && !tx->iovec2) + tx->iovec1->offset += iov_offset; + else if (tx->iovec2) + tx->iovec2->offset += iov_offset; + } + /* + * It is important to increment this here as it is used to + * generate the BTH.PSN and, therefore, can't be bulk-updated + * outside of the loop. + */ + tx->seqnum = req->seqnum++; + list_add_tail(&tx->txreq.list, &req->txps); + npkts++; + } +dosend: + ret = sdma_send_txlist(req->sde, &pq->busy, &req->txps); + if (list_empty(&req->txps)) + if (req->seqnum == req->info.npkts) { + set_bit(SDMA_REQ_SEND_DONE, &req->flags); + /* + * The txreq has already been submitted to the HW queue + * so we can free the AHG entry now. Corruption will not + * happen due to the sequential manner in which + * descriptors are processed. + */ + if (test_bit(SDMA_REQ_HAVE_AHG, &req->flags)) + sdma_ahg_free(req->sde, req->ahg_idx); + } + goto done; +free_txreq: + sdma_txclean(pq->dd, &tx->txreq); +free_tx: + kmem_cache_free(pq->txreq_cache, tx); +done: + return ret; +} + +/* + * How many pages in this iovec element? + */ +static inline int num_user_pages(const struct iovec *iov) +{ + const unsigned long addr = (unsigned long) iov->iov_base; + const unsigned long len = iov->iov_len; + const unsigned long spage = addr & PAGE_MASK; + const unsigned long epage = (addr + len - 1) & PAGE_MASK; + + return 1 + ((epage - spage) >> PAGE_SHIFT); +} + +static int pin_vector_pages(struct user_sdma_request *req, + struct user_sdma_iovec *iovec) { + int ret = 0; + unsigned pinned; + + iovec->npages = num_user_pages(&iovec->iov); + iovec->pages = kzalloc(sizeof(*iovec->pages) * + iovec->npages, GFP_KERNEL); + if (!iovec->pages) { + SDMA_DBG(req, "Failed page array alloc"); + ret = -ENOMEM; + goto done; + } + /* If called by the kernel thread, use the user's mm */ + if (current->flags & PF_KTHREAD) + use_mm(req->user_proc->mm); + pinned = get_user_pages_fast( + (unsigned long)iovec->iov.iov_base, + iovec->npages, 0, iovec->pages); + /* If called by the kernel thread, unuse the user's mm */ + if (current->flags & PF_KTHREAD) + unuse_mm(req->user_proc->mm); + if (pinned != iovec->npages) { + SDMA_DBG(req, "Failed to pin pages (%u/%u)", pinned, + iovec->npages); + ret = -EFAULT; + goto pfree; + } + goto done; +pfree: + unpin_vector_pages(iovec); +done: + return ret; +} + +static void unpin_vector_pages(struct user_sdma_iovec *iovec) +{ + unsigned i; + + if (ACCESS_ONCE(iovec->offset) != iovec->iov.iov_len) { + hfi1_cdbg(SDMA, + "the complete vector has not been sent yet %llu %zu", + iovec->offset, iovec->iov.iov_len); + return; + } + for (i = 0; i < iovec->npages; i++) + if (iovec->pages[i]) + put_page(iovec->pages[i]); + kfree(iovec->pages); + iovec->pages = NULL; + iovec->npages = 0; + iovec->offset = 0; +} + +static int check_header_template(struct user_sdma_request *req, + struct hfi1_pkt_header *hdr, u32 lrhlen, + u32 datalen) +{ + /* + * Perform safety checks for any type of packet: + * - transfer size is multiple of 64bytes + * - packet length is multiple of 4bytes + * - entire request length is multiple of 4bytes + * - packet length is not larger than MTU size + * + * These checks are only done for the first packet of the + * transfer since the header is "given" to us by user space. + * For the remainder of the packets we compute the values. + */ + if (req->info.fragsize % PIO_BLOCK_SIZE || + lrhlen & 0x3 || req->data_len & 0x3 || + lrhlen > get_lrh_len(*hdr, req->info.fragsize)) + return -EINVAL; + + if (req_opcode(req->info.ctrl) == EXPECTED) { + /* + * The header is checked only on the first packet. Furthermore, + * we ensure that at least one TID entry is copied when the + * request is submitted. Therefore, we don't have to verify that + * tididx points to something sane. + */ + u32 tidval = req->tids[req->tididx], + tidlen = EXP_TID_GET(tidval, LEN) * PAGE_SIZE, + tididx = EXP_TID_GET(tidval, IDX), + tidctrl = EXP_TID_GET(tidval, CTRL), + tidoff; + __le32 kval = hdr->kdeth.ver_tid_offset; + + tidoff = KDETH_GET(kval, OFFSET) * + (KDETH_GET(req->hdr.kdeth.ver_tid_offset, OM) ? + KDETH_OM_LARGE : KDETH_OM_SMALL); + /* + * Expected receive packets have the following + * additional checks: + * - offset is not larger than the TID size + * - TIDCtrl values match between header and TID array + * - TID indexes match between header and TID array + */ + if ((tidoff + datalen > tidlen) || + KDETH_GET(kval, TIDCTRL) != tidctrl || + KDETH_GET(kval, TID) != tididx) + return -EINVAL; + } + return 0; +} + +/* + * Correctly set the BTH.PSN field based on type of + * transfer - eager packets can just increment the PSN but + * expected packets encode generation and sequence in the + * BTH.PSN field so just incrementing will result in errors. + */ +static inline u32 set_pkt_bth_psn(__be32 bthpsn, u8 expct, u32 frags) +{ + u32 val = be32_to_cpu(bthpsn), + mask = (HFI1_CAP_IS_KSET(EXTENDED_PSN) ? 0x7fffffffull : + 0xffffffull), + psn = val & mask; + if (expct) + psn = (psn & ~BTH_SEQ_MASK) | ((psn + frags) & BTH_SEQ_MASK); + else + psn = psn + frags; + return psn & mask; +} + +static int set_txreq_header(struct user_sdma_request *req, + struct user_sdma_txreq *tx, u32 datalen) +{ + struct hfi1_user_sdma_pkt_q *pq = req->pq; + struct hfi1_pkt_header *hdr = &tx->hdr; + u16 pbclen; + int ret; + u32 tidval = 0, lrhlen = get_lrh_len(*hdr, datalen); + + /* Copy the header template to the request before modification */ + memcpy(hdr, &req->hdr, sizeof(*hdr)); + + /* + * Check if the PBC and LRH length are mismatched. If so + * adjust both in the header. + */ + pbclen = le16_to_cpu(hdr->pbc[0]); + if (PBC2LRH(pbclen) != lrhlen) { + pbclen = (pbclen & 0xf000) | LRH2PBC(lrhlen); + hdr->pbc[0] = cpu_to_le16(pbclen); + hdr->lrh[2] = cpu_to_be16(lrhlen >> 2); + /* + * Third packet + * This is the first packet in the sequence that has + * a "static" size that can be used for the rest of + * the packets (besides the last one). + */ + if (unlikely(req->seqnum == 2)) { + /* + * From this point on the lengths in both the + * PBC and LRH are the same until the last + * packet. + * Adjust the template so we don't have to update + * every packet + */ + req->hdr.pbc[0] = hdr->pbc[0]; + req->hdr.lrh[2] = hdr->lrh[2]; + } + } + /* + * We only have to modify the header if this is not the + * first packet in the request. Otherwise, we use the + * header given to us. + */ + if (unlikely(!req->seqnum)) { + ret = check_header_template(req, hdr, lrhlen, datalen); + if (ret) + return ret; + goto done; + + } + + hdr->bth[2] = cpu_to_be32( + set_pkt_bth_psn(hdr->bth[2], + (req_opcode(req->info.ctrl) == EXPECTED), + req->seqnum)); + + /* Set ACK request on last packet */ + if (unlikely(tx->flags & USER_SDMA_TXREQ_FLAGS_LAST_PKT)) + hdr->bth[2] |= cpu_to_be32(1UL<<31); + + /* Set the new offset */ + hdr->kdeth.swdata[6] = cpu_to_le32(req->koffset); + /* Expected packets have to fill in the new TID information */ + if (req_opcode(req->info.ctrl) == EXPECTED) { + tidval = req->tids[req->tididx]; + /* + * If the offset puts us at the end of the current TID, + * advance everything. + */ + if ((req->tidoffset) == (EXP_TID_GET(tidval, LEN) * + PAGE_SIZE)) { + req->tidoffset = 0; + /* Since we don't copy all the TIDs, all at once, + * we have to check again. */ + if (++req->tididx > req->n_tids - 1 || + !req->tids[req->tididx]) { + return -EINVAL; + } + tidval = req->tids[req->tididx]; + } + req->omfactor = EXP_TID_GET(tidval, LEN) * PAGE_SIZE >= + KDETH_OM_MAX_SIZE ? KDETH_OM_LARGE : KDETH_OM_SMALL; + /* Set KDETH.TIDCtrl based on value for this TID. */ + KDETH_SET(hdr->kdeth.ver_tid_offset, TIDCTRL, + EXP_TID_GET(tidval, CTRL)); + /* Set KDETH.TID based on value for this TID */ + KDETH_SET(hdr->kdeth.ver_tid_offset, TID, + EXP_TID_GET(tidval, IDX)); + /* Clear KDETH.SH only on the last packet */ + if (unlikely(tx->flags & USER_SDMA_TXREQ_FLAGS_LAST_PKT)) + KDETH_SET(hdr->kdeth.ver_tid_offset, SH, 0); + /* + * Set the KDETH.OFFSET and KDETH.OM based on size of + * transfer. + */ + SDMA_DBG(req, "TID offset %ubytes %uunits om%u", + req->tidoffset, req->tidoffset / req->omfactor, + !!(req->omfactor - KDETH_OM_SMALL)); + KDETH_SET(hdr->kdeth.ver_tid_offset, OFFSET, + req->tidoffset / req->omfactor); + KDETH_SET(hdr->kdeth.ver_tid_offset, OM, + !!(req->omfactor - KDETH_OM_SMALL)); + } +done: + trace_hfi1_sdma_user_header(pq->dd, pq->ctxt, pq->subctxt, + req->info.comp_idx, hdr, tidval); + return sdma_txadd_kvaddr(pq->dd, &tx->txreq, hdr, sizeof(*hdr)); +} + +static int set_txreq_header_ahg(struct user_sdma_request *req, + struct user_sdma_txreq *tx, u32 len) +{ + int diff = 0; + struct hfi1_user_sdma_pkt_q *pq = req->pq; + struct hfi1_pkt_header *hdr = &req->hdr; + u16 pbclen = le16_to_cpu(hdr->pbc[0]); + u32 val32, tidval = 0, lrhlen = get_lrh_len(*hdr, len); + + if (PBC2LRH(pbclen) != lrhlen) { + /* PBC.PbcLengthDWs */ + AHG_HEADER_SET(req->ahg, diff, 0, 0, 12, + cpu_to_le16(LRH2PBC(lrhlen))); + /* LRH.PktLen (we need the full 16 bits due to byte swap) */ + AHG_HEADER_SET(req->ahg, diff, 3, 0, 16, + cpu_to_be16(lrhlen >> 2)); + } + + /* + * Do the common updates + */ + /* BTH.PSN and BTH.A */ + val32 = (be32_to_cpu(hdr->bth[2]) + req->seqnum) & + (HFI1_CAP_IS_KSET(EXTENDED_PSN) ? 0x7fffffff : 0xffffff); + if (unlikely(tx->flags & USER_SDMA_TXREQ_FLAGS_LAST_PKT)) + val32 |= 1UL << 31; + AHG_HEADER_SET(req->ahg, diff, 6, 0, 16, cpu_to_be16(val32 >> 16)); + AHG_HEADER_SET(req->ahg, diff, 6, 16, 16, cpu_to_be16(val32 & 0xffff)); + /* KDETH.Offset */ + AHG_HEADER_SET(req->ahg, diff, 15, 0, 16, + cpu_to_le16(req->koffset & 0xffff)); + AHG_HEADER_SET(req->ahg, diff, 15, 16, 16, + cpu_to_le16(req->koffset >> 16)); + if (req_opcode(req->info.ctrl) == EXPECTED) { + __le16 val; + + tidval = req->tids[req->tididx]; + + /* + * If the offset puts us at the end of the current TID, + * advance everything. + */ + if ((req->tidoffset) == (EXP_TID_GET(tidval, LEN) * + PAGE_SIZE)) { + req->tidoffset = 0; + /* Since we don't copy all the TIDs, all at once, + * we have to check again. */ + if (++req->tididx > req->n_tids - 1 || + !req->tids[req->tididx]) { + return -EINVAL; + } + tidval = req->tids[req->tididx]; + } + req->omfactor = ((EXP_TID_GET(tidval, LEN) * + PAGE_SIZE) >= + KDETH_OM_MAX_SIZE) ? KDETH_OM_LARGE : + KDETH_OM_SMALL; + /* KDETH.OM and KDETH.OFFSET (TID) */ + AHG_HEADER_SET(req->ahg, diff, 7, 0, 16, + ((!!(req->omfactor - KDETH_OM_SMALL)) << 15 | + ((req->tidoffset / req->omfactor) & 0x7fff))); + /* KDETH.TIDCtrl, KDETH.TID */ + val = cpu_to_le16(((EXP_TID_GET(tidval, CTRL) & 0x3) << 10) | + (EXP_TID_GET(tidval, IDX) & 0x3ff)); + /* Clear KDETH.SH on last packet */ + if (unlikely(tx->flags & USER_SDMA_TXREQ_FLAGS_LAST_PKT)) { + val |= cpu_to_le16(KDETH_GET(hdr->kdeth.ver_tid_offset, + INTR) >> 16); + val &= cpu_to_le16(~(1U << 13)); + AHG_HEADER_SET(req->ahg, diff, 7, 16, 14, val); + } else + AHG_HEADER_SET(req->ahg, diff, 7, 16, 12, val); + } + + trace_hfi1_sdma_user_header_ahg(pq->dd, pq->ctxt, pq->subctxt, + req->info.comp_idx, req->sde->this_idx, + req->ahg_idx, req->ahg, diff, tidval); + return diff; +} + +static void user_sdma_txreq_cb(struct sdma_txreq *txreq, int status, + int drain) +{ + struct user_sdma_txreq *tx = + container_of(txreq, struct user_sdma_txreq, txreq); + struct user_sdma_request *req = tx->req; + struct hfi1_user_sdma_pkt_q *pq = req ? req->pq : NULL; + u64 tx_seqnum; + + if (unlikely(!req || !pq)) + return; + + if (tx->iovec1) + iovec_may_free(tx->iovec1, unpin_vector_pages); + if (tx->iovec2) + iovec_may_free(tx->iovec2, unpin_vector_pages); + + tx_seqnum = tx->seqnum; + kmem_cache_free(pq->txreq_cache, tx); + + if (status != SDMA_TXREQ_S_OK) { + dd_dev_err(pq->dd, "SDMA completion with error %d", status); + set_comp_state(req, ERROR, status); + set_bit(SDMA_REQ_HAS_ERROR, &req->flags); + /* Do not free the request until the sender loop has ack'ed + * the error and we've seen all txreqs. */ + if (tx_seqnum == ACCESS_ONCE(req->seqnum) && + test_bit(SDMA_REQ_DONE_ERROR, &req->flags)) { + atomic_dec(&pq->n_reqs); + user_sdma_free_request(req); + } + } else { + if (tx_seqnum == req->info.npkts - 1) { + /* We've sent and completed all packets in this + * request. Signal completion to the user */ + atomic_dec(&pq->n_reqs); + set_comp_state(req, COMPLETE, 0); + user_sdma_free_request(req); + } + } + if (!atomic_read(&pq->n_reqs)) + xchg(&pq->state, SDMA_PKT_Q_INACTIVE); +} + +static void user_sdma_free_request(struct user_sdma_request *req) +{ + if (!list_empty(&req->txps)) { + struct sdma_txreq *t, *p; + + list_for_each_entry_safe(t, p, &req->txps, list) { + struct user_sdma_txreq *tx = + container_of(t, struct user_sdma_txreq, txreq); + list_del_init(&t->list); + sdma_txclean(req->pq->dd, t); + kmem_cache_free(req->pq->txreq_cache, tx); + } + } + if (req->data_iovs) { + int i; + + for (i = 0; i < req->data_iovs; i++) + if (req->iovs[i].npages && req->iovs[i].pages) + unpin_vector_pages(&req->iovs[i]); + } + if (req->user_proc) + put_task_struct(req->user_proc); + kfree(req->tids); + clear_bit(SDMA_REQ_IN_USE, &req->flags); +} + +static inline void set_comp_state(struct user_sdma_request *req, + enum hfi1_sdma_comp_state state, + int ret) +{ + SDMA_DBG(req, "Setting completion status %u %d", state, ret); + req->cq->comps[req->info.comp_idx].status = state; + if (state == ERROR) + req->cq->comps[req->info.comp_idx].errcode = -ret; + trace_hfi1_sdma_user_completion(req->pq->dd, req->pq->ctxt, + req->pq->subctxt, req->info.comp_idx, + state, ret); +} diff --git a/drivers/staging/rdma/hfi1/user_sdma.h b/drivers/staging/rdma/hfi1/user_sdma.h new file mode 100644 index 0000000000000..fa4422553e23c --- /dev/null +++ b/drivers/staging/rdma/hfi1/user_sdma.h @@ -0,0 +1,89 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#include +#include + +#include "common.h" +#include "iowait.h" + +#define EXP_TID_TIDLEN_MASK 0x7FFULL +#define EXP_TID_TIDLEN_SHIFT 0 +#define EXP_TID_TIDCTRL_MASK 0x3ULL +#define EXP_TID_TIDCTRL_SHIFT 20 +#define EXP_TID_TIDIDX_MASK 0x7FFULL +#define EXP_TID_TIDIDX_SHIFT 22 +#define EXP_TID_GET(tid, field) \ + (((tid) >> EXP_TID_TID##field##_SHIFT) & EXP_TID_TID##field##_MASK) + +extern uint extended_psn; + +struct hfi1_user_sdma_pkt_q { + struct list_head list; + unsigned ctxt; + unsigned subctxt; + u16 n_max_reqs; + atomic_t n_reqs; + u16 reqidx; + struct hfi1_devdata *dd; + struct kmem_cache *txreq_cache; + struct user_sdma_request *reqs; + struct iowait busy; + unsigned state; +}; + +struct hfi1_user_sdma_comp_q { + u16 nentries; + struct hfi1_sdma_comp_entry *comps; +}; + +int hfi1_user_sdma_alloc_queues(struct hfi1_ctxtdata *, struct file *); +int hfi1_user_sdma_free_queues(struct hfi1_filedata *); +int hfi1_user_sdma_process_request(struct file *, struct iovec *, unsigned long, + unsigned long *); diff --git a/drivers/staging/rdma/hfi1/verbs.c b/drivers/staging/rdma/hfi1/verbs.c new file mode 100644 index 0000000000000..5f4b6617677a0 --- /dev/null +++ b/drivers/staging/rdma/hfi1/verbs.c @@ -0,0 +1,2142 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hfi.h" +#include "common.h" +#include "device.h" +#include "trace.h" +#include "qp.h" +#include "sdma.h" + +unsigned int hfi1_lkey_table_size = 16; +module_param_named(lkey_table_size, hfi1_lkey_table_size, uint, + S_IRUGO); +MODULE_PARM_DESC(lkey_table_size, + "LKEY table size in bits (2^n, 1 <= n <= 23)"); + +static unsigned int hfi1_max_pds = 0xFFFF; +module_param_named(max_pds, hfi1_max_pds, uint, S_IRUGO); +MODULE_PARM_DESC(max_pds, + "Maximum number of protection domains to support"); + +static unsigned int hfi1_max_ahs = 0xFFFF; +module_param_named(max_ahs, hfi1_max_ahs, uint, S_IRUGO); +MODULE_PARM_DESC(max_ahs, "Maximum number of address handles to support"); + +unsigned int hfi1_max_cqes = 0x2FFFF; +module_param_named(max_cqes, hfi1_max_cqes, uint, S_IRUGO); +MODULE_PARM_DESC(max_cqes, + "Maximum number of completion queue entries to support"); + +unsigned int hfi1_max_cqs = 0x1FFFF; +module_param_named(max_cqs, hfi1_max_cqs, uint, S_IRUGO); +MODULE_PARM_DESC(max_cqs, "Maximum number of completion queues to support"); + +unsigned int hfi1_max_qp_wrs = 0x3FFF; +module_param_named(max_qp_wrs, hfi1_max_qp_wrs, uint, S_IRUGO); +MODULE_PARM_DESC(max_qp_wrs, "Maximum number of QP WRs to support"); + +unsigned int hfi1_max_qps = 16384; +module_param_named(max_qps, hfi1_max_qps, uint, S_IRUGO); +MODULE_PARM_DESC(max_qps, "Maximum number of QPs to support"); + +unsigned int hfi1_max_sges = 0x60; +module_param_named(max_sges, hfi1_max_sges, uint, S_IRUGO); +MODULE_PARM_DESC(max_sges, "Maximum number of SGEs to support"); + +unsigned int hfi1_max_mcast_grps = 16384; +module_param_named(max_mcast_grps, hfi1_max_mcast_grps, uint, S_IRUGO); +MODULE_PARM_DESC(max_mcast_grps, + "Maximum number of multicast groups to support"); + +unsigned int hfi1_max_mcast_qp_attached = 16; +module_param_named(max_mcast_qp_attached, hfi1_max_mcast_qp_attached, + uint, S_IRUGO); +MODULE_PARM_DESC(max_mcast_qp_attached, + "Maximum number of attached QPs to support"); + +unsigned int hfi1_max_srqs = 1024; +module_param_named(max_srqs, hfi1_max_srqs, uint, S_IRUGO); +MODULE_PARM_DESC(max_srqs, "Maximum number of SRQs to support"); + +unsigned int hfi1_max_srq_sges = 128; +module_param_named(max_srq_sges, hfi1_max_srq_sges, uint, S_IRUGO); +MODULE_PARM_DESC(max_srq_sges, "Maximum number of SRQ SGEs to support"); + +unsigned int hfi1_max_srq_wrs = 0x1FFFF; +module_param_named(max_srq_wrs, hfi1_max_srq_wrs, uint, S_IRUGO); +MODULE_PARM_DESC(max_srq_wrs, "Maximum number of SRQ WRs support"); + +static void verbs_sdma_complete( + struct sdma_txreq *cookie, + int status, + int drained); + +/* + * Note that it is OK to post send work requests in the SQE and ERR + * states; hfi1_do_send() will process them and generate error + * completions as per IB 1.2 C10-96. + */ +const int ib_hfi1_state_ops[IB_QPS_ERR + 1] = { + [IB_QPS_RESET] = 0, + [IB_QPS_INIT] = HFI1_POST_RECV_OK, + [IB_QPS_RTR] = HFI1_POST_RECV_OK | HFI1_PROCESS_RECV_OK, + [IB_QPS_RTS] = HFI1_POST_RECV_OK | HFI1_PROCESS_RECV_OK | + HFI1_POST_SEND_OK | HFI1_PROCESS_SEND_OK | + HFI1_PROCESS_NEXT_SEND_OK, + [IB_QPS_SQD] = HFI1_POST_RECV_OK | HFI1_PROCESS_RECV_OK | + HFI1_POST_SEND_OK | HFI1_PROCESS_SEND_OK, + [IB_QPS_SQE] = HFI1_POST_RECV_OK | HFI1_PROCESS_RECV_OK | + HFI1_POST_SEND_OK | HFI1_FLUSH_SEND, + [IB_QPS_ERR] = HFI1_POST_RECV_OK | HFI1_FLUSH_RECV | + HFI1_POST_SEND_OK | HFI1_FLUSH_SEND, +}; + +struct hfi1_ucontext { + struct ib_ucontext ibucontext; +}; + +static inline struct hfi1_ucontext *to_iucontext(struct ib_ucontext + *ibucontext) +{ + return container_of(ibucontext, struct hfi1_ucontext, ibucontext); +} + +/* + * Translate ib_wr_opcode into ib_wc_opcode. + */ +const enum ib_wc_opcode ib_hfi1_wc_opcode[] = { + [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, + [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, + [IB_WR_SEND] = IB_WC_SEND, + [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, + [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, + [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, + [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD +}; + +/* + * Length of header by opcode, 0 --> not supported + */ +const u8 hdr_len_by_opcode[256] = { + /* RC */ + [IB_OPCODE_RC_SEND_FIRST] = 12 + 8, + [IB_OPCODE_RC_SEND_MIDDLE] = 12 + 8, + [IB_OPCODE_RC_SEND_LAST] = 12 + 8, + [IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE] = 12 + 8 + 4, + [IB_OPCODE_RC_SEND_ONLY] = 12 + 8, + [IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE] = 12 + 8 + 4, + [IB_OPCODE_RC_RDMA_WRITE_FIRST] = 12 + 8 + 16, + [IB_OPCODE_RC_RDMA_WRITE_MIDDLE] = 12 + 8, + [IB_OPCODE_RC_RDMA_WRITE_LAST] = 12 + 8, + [IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE] = 12 + 8 + 4, + [IB_OPCODE_RC_RDMA_WRITE_ONLY] = 12 + 8 + 16, + [IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE] = 12 + 8 + 20, + [IB_OPCODE_RC_RDMA_READ_REQUEST] = 12 + 8 + 16, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST] = 12 + 8 + 4, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE] = 12 + 8, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST] = 12 + 8 + 4, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY] = 12 + 8 + 4, + [IB_OPCODE_RC_ACKNOWLEDGE] = 12 + 8 + 4, + [IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE] = 12 + 8 + 4, + [IB_OPCODE_RC_COMPARE_SWAP] = 12 + 8 + 28, + [IB_OPCODE_RC_FETCH_ADD] = 12 + 8 + 28, + /* UC */ + [IB_OPCODE_UC_SEND_FIRST] = 12 + 8, + [IB_OPCODE_UC_SEND_MIDDLE] = 12 + 8, + [IB_OPCODE_UC_SEND_LAST] = 12 + 8, + [IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE] = 12 + 8 + 4, + [IB_OPCODE_UC_SEND_ONLY] = 12 + 8, + [IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE] = 12 + 8 + 4, + [IB_OPCODE_UC_RDMA_WRITE_FIRST] = 12 + 8 + 16, + [IB_OPCODE_UC_RDMA_WRITE_MIDDLE] = 12 + 8, + [IB_OPCODE_UC_RDMA_WRITE_LAST] = 12 + 8, + [IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE] = 12 + 8 + 4, + [IB_OPCODE_UC_RDMA_WRITE_ONLY] = 12 + 8 + 16, + [IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE] = 12 + 8 + 20, + /* UD */ + [IB_OPCODE_UD_SEND_ONLY] = 12 + 8 + 8, + [IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE] = 12 + 8 + 12 +}; + +static const opcode_handler opcode_handler_tbl[256] = { + /* RC */ + [IB_OPCODE_RC_SEND_FIRST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_SEND_MIDDLE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_SEND_LAST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_SEND_LAST_WITH_IMMEDIATE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_SEND_ONLY] = &hfi1_rc_rcv, + [IB_OPCODE_RC_SEND_ONLY_WITH_IMMEDIATE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_WRITE_FIRST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_WRITE_MIDDLE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_WRITE_LAST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_WRITE_LAST_WITH_IMMEDIATE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_WRITE_ONLY] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_WRITE_ONLY_WITH_IMMEDIATE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_READ_REQUEST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_FIRST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_MIDDLE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_LAST] = &hfi1_rc_rcv, + [IB_OPCODE_RC_RDMA_READ_RESPONSE_ONLY] = &hfi1_rc_rcv, + [IB_OPCODE_RC_ACKNOWLEDGE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_ATOMIC_ACKNOWLEDGE] = &hfi1_rc_rcv, + [IB_OPCODE_RC_COMPARE_SWAP] = &hfi1_rc_rcv, + [IB_OPCODE_RC_FETCH_ADD] = &hfi1_rc_rcv, + /* UC */ + [IB_OPCODE_UC_SEND_FIRST] = &hfi1_uc_rcv, + [IB_OPCODE_UC_SEND_MIDDLE] = &hfi1_uc_rcv, + [IB_OPCODE_UC_SEND_LAST] = &hfi1_uc_rcv, + [IB_OPCODE_UC_SEND_LAST_WITH_IMMEDIATE] = &hfi1_uc_rcv, + [IB_OPCODE_UC_SEND_ONLY] = &hfi1_uc_rcv, + [IB_OPCODE_UC_SEND_ONLY_WITH_IMMEDIATE] = &hfi1_uc_rcv, + [IB_OPCODE_UC_RDMA_WRITE_FIRST] = &hfi1_uc_rcv, + [IB_OPCODE_UC_RDMA_WRITE_MIDDLE] = &hfi1_uc_rcv, + [IB_OPCODE_UC_RDMA_WRITE_LAST] = &hfi1_uc_rcv, + [IB_OPCODE_UC_RDMA_WRITE_LAST_WITH_IMMEDIATE] = &hfi1_uc_rcv, + [IB_OPCODE_UC_RDMA_WRITE_ONLY] = &hfi1_uc_rcv, + [IB_OPCODE_UC_RDMA_WRITE_ONLY_WITH_IMMEDIATE] = &hfi1_uc_rcv, + /* UD */ + [IB_OPCODE_UD_SEND_ONLY] = &hfi1_ud_rcv, + [IB_OPCODE_UD_SEND_ONLY_WITH_IMMEDIATE] = &hfi1_ud_rcv, + /* CNP */ + [IB_OPCODE_CNP] = &hfi1_cnp_rcv +}; + +/* + * System image GUID. + */ +__be64 ib_hfi1_sys_image_guid; + +/** + * hfi1_copy_sge - copy data to SGE memory + * @ss: the SGE state + * @data: the data to copy + * @length: the length of the data + */ +void hfi1_copy_sge( + struct hfi1_sge_state *ss, + void *data, u32 length, + int release) +{ + struct hfi1_sge *sge = &ss->sge; + + while (length) { + u32 len = sge->length; + + if (len > length) + len = length; + if (len > sge->sge_length) + len = sge->sge_length; + WARN_ON_ONCE(len == 0); + memcpy(sge->vaddr, data, len); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (release) + hfi1_put_mr(sge->mr); + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr->lkey) { + if (++sge->n >= HFI1_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + data += len; + length -= len; + } +} + +/** + * hfi1_skip_sge - skip over SGE memory + * @ss: the SGE state + * @length: the number of bytes to skip + */ +void hfi1_skip_sge(struct hfi1_sge_state *ss, u32 length, int release) +{ + struct hfi1_sge *sge = &ss->sge; + + while (length) { + u32 len = sge->length; + + if (len > length) + len = length; + if (len > sge->sge_length) + len = sge->sge_length; + WARN_ON_ONCE(len == 0); + sge->vaddr += len; + sge->length -= len; + sge->sge_length -= len; + if (sge->sge_length == 0) { + if (release) + hfi1_put_mr(sge->mr); + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr->lkey) { + if (++sge->n >= HFI1_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + break; + sge->n = 0; + } + sge->vaddr = + sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = + sge->mr->map[sge->m]->segs[sge->n].length; + } + length -= len; + } +} + +/** + * post_one_send - post one RC, UC, or UD send work request + * @qp: the QP to post on + * @wr: the work request to send + */ +static int post_one_send(struct hfi1_qp *qp, struct ib_send_wr *wr) +{ + struct hfi1_swqe *wqe; + u32 next; + int i; + int j; + int acc; + struct hfi1_lkey_table *rkt; + struct hfi1_pd *pd; + struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device); + struct hfi1_pportdata *ppd; + struct hfi1_ibport *ibp; + + /* IB spec says that num_sge == 0 is OK. */ + if (unlikely(wr->num_sge > qp->s_max_sge)) + return -EINVAL; + + ppd = &dd->pport[qp->port_num - 1]; + ibp = &ppd->ibport_data; + + /* + * Don't allow RDMA reads or atomic operations on UC or + * undefined operations. + * Make sure buffer is large enough to hold the result for atomics. + */ + if (wr->opcode == IB_WR_FAST_REG_MR) { + return -EINVAL; + } else if (qp->ibqp.qp_type == IB_QPT_UC) { + if ((unsigned) wr->opcode >= IB_WR_RDMA_READ) + return -EINVAL; + } else if (qp->ibqp.qp_type != IB_QPT_RC) { + /* Check IB_QPT_SMI, IB_QPT_GSI, IB_QPT_UD opcode */ + if (wr->opcode != IB_WR_SEND && + wr->opcode != IB_WR_SEND_WITH_IMM) + return -EINVAL; + /* Check UD destination address PD */ + if (qp->ibqp.pd != wr->wr.ud.ah->pd) + return -EINVAL; + } else if ((unsigned) wr->opcode > IB_WR_ATOMIC_FETCH_AND_ADD) + return -EINVAL; + else if (wr->opcode >= IB_WR_ATOMIC_CMP_AND_SWP && + (wr->num_sge == 0 || + wr->sg_list[0].length < sizeof(u64) || + wr->sg_list[0].addr & (sizeof(u64) - 1))) + return -EINVAL; + else if (wr->opcode >= IB_WR_RDMA_READ && !qp->s_max_rd_atomic) + return -EINVAL; + + next = qp->s_head + 1; + if (next >= qp->s_size) + next = 0; + if (next == qp->s_last) + return -ENOMEM; + + rkt = &to_idev(qp->ibqp.device)->lk_table; + pd = to_ipd(qp->ibqp.pd); + wqe = get_swqe_ptr(qp, qp->s_head); + wqe->wr = *wr; + wqe->length = 0; + j = 0; + if (wr->num_sge) { + acc = wr->opcode >= IB_WR_RDMA_READ ? + IB_ACCESS_LOCAL_WRITE : 0; + for (i = 0; i < wr->num_sge; i++) { + u32 length = wr->sg_list[i].length; + int ok; + + if (length == 0) + continue; + ok = hfi1_lkey_ok(rkt, pd, &wqe->sg_list[j], + &wr->sg_list[i], acc); + if (!ok) + goto bail_inval_free; + wqe->length += length; + j++; + } + wqe->wr.num_sge = j; + } + if (qp->ibqp.qp_type == IB_QPT_UC || + qp->ibqp.qp_type == IB_QPT_RC) { + if (wqe->length > 0x80000000U) + goto bail_inval_free; + } else { + struct hfi1_ah *ah = to_iah(wr->wr.ud.ah); + + atomic_inc(&ah->refcount); + } + wqe->ssn = qp->s_ssn++; + qp->s_head = next; + + return 0; + +bail_inval_free: + /* release mr holds */ + while (j) { + struct hfi1_sge *sge = &wqe->sg_list[--j]; + + hfi1_put_mr(sge->mr); + } + return -EINVAL; +} + +/** + * post_send - post a send on a QP + * @ibqp: the QP to post the send on + * @wr: the list of work requests to post + * @bad_wr: the first bad WR is put here + * + * This may be called from interrupt context. + */ +static int post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct hfi1_qp *qp = to_iqp(ibqp); + int err = 0; + int call_send; + unsigned long flags; + unsigned nreq = 0; + + spin_lock_irqsave(&qp->s_lock, flags); + + /* Check that state is OK to post send. */ + if (unlikely(!(ib_hfi1_state_ops[qp->state] & HFI1_POST_SEND_OK))) { + spin_unlock_irqrestore(&qp->s_lock, flags); + return -EINVAL; + } + + /* sq empty and not list -> call send */ + call_send = qp->s_head == qp->s_last && !wr->next; + + for (; wr; wr = wr->next) { + err = post_one_send(qp, wr); + if (unlikely(err)) { + *bad_wr = wr; + goto bail; + } + nreq++; + } +bail: + if (nreq && !call_send) + hfi1_schedule_send(qp); + spin_unlock_irqrestore(&qp->s_lock, flags); + if (nreq && call_send) + hfi1_do_send(&qp->s_iowait.iowork); + return err; +} + +/** + * post_receive - post a receive on a QP + * @ibqp: the QP to post the receive on + * @wr: the WR to post + * @bad_wr: the first bad WR is put here + * + * This may be called from interrupt context. + */ +static int post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct hfi1_qp *qp = to_iqp(ibqp); + struct hfi1_rwq *wq = qp->r_rq.wq; + unsigned long flags; + int ret; + + /* Check that state is OK to post receive. */ + if (!(ib_hfi1_state_ops[qp->state] & HFI1_POST_RECV_OK) || !wq) { + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + + for (; wr; wr = wr->next) { + struct hfi1_rwqe *wqe; + u32 next; + int i; + + if ((unsigned) wr->num_sge > qp->r_rq.max_sge) { + *bad_wr = wr; + ret = -EINVAL; + goto bail; + } + + spin_lock_irqsave(&qp->r_rq.lock, flags); + next = wq->head + 1; + if (next >= qp->r_rq.size) + next = 0; + if (next == wq->tail) { + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + *bad_wr = wr; + ret = -ENOMEM; + goto bail; + } + + wqe = get_rwqe_ptr(&qp->r_rq, wq->head); + wqe->wr_id = wr->wr_id; + wqe->num_sge = wr->num_sge; + for (i = 0; i < wr->num_sge; i++) + wqe->sg_list[i] = wr->sg_list[i]; + /* Make sure queue entry is written before the head index. */ + smp_wmb(); + wq->head = next; + spin_unlock_irqrestore(&qp->r_rq.lock, flags); + } + ret = 0; + +bail: + return ret; +} + +/* + * Make sure the QP is ready and able to accept the given opcode. + */ +static inline int qp_ok(int opcode, struct hfi1_packet *packet) +{ + struct hfi1_ibport *ibp; + + if (!(ib_hfi1_state_ops[packet->qp->state] & HFI1_PROCESS_RECV_OK)) + goto dropit; + if (((opcode & OPCODE_QP_MASK) == packet->qp->allowed_ops) || + (opcode == IB_OPCODE_CNP)) + return 1; +dropit: + ibp = &packet->rcd->ppd->ibport_data; + ibp->n_pkt_drops++; + return 0; +} + + +/** + * hfi1_ib_rcv - process an incoming packet + * @packet: data packet information + * + * This is called to process an incoming packet at interrupt level. + * + * Tlen is the length of the header + data + CRC in bytes. + */ +void hfi1_ib_rcv(struct hfi1_packet *packet) +{ + struct hfi1_ctxtdata *rcd = packet->rcd; + struct hfi1_ib_header *hdr = packet->hdr; + u32 tlen = packet->tlen; + struct hfi1_pportdata *ppd = rcd->ppd; + struct hfi1_ibport *ibp = &ppd->ibport_data; + u32 qp_num; + int lnh; + u8 opcode; + u16 lid; + + /* Check for GRH */ + lnh = be16_to_cpu(hdr->lrh[0]) & 3; + if (lnh == HFI1_LRH_BTH) + packet->ohdr = &hdr->u.oth; + else if (lnh == HFI1_LRH_GRH) { + u32 vtf; + + packet->ohdr = &hdr->u.l.oth; + if (hdr->u.l.grh.next_hdr != IB_GRH_NEXT_HDR) + goto drop; + vtf = be32_to_cpu(hdr->u.l.grh.version_tclass_flow); + if ((vtf >> IB_GRH_VERSION_SHIFT) != IB_GRH_VERSION) + goto drop; + packet->rcv_flags |= HFI1_HAS_GRH; + } else + goto drop; + + trace_input_ibhdr(rcd->dd, hdr); + + opcode = (be32_to_cpu(packet->ohdr->bth[0]) >> 24); + inc_opstats(tlen, &rcd->opstats->stats[opcode]); + + /* Get the destination QP number. */ + qp_num = be32_to_cpu(packet->ohdr->bth[1]) & HFI1_QPN_MASK; + lid = be16_to_cpu(hdr->lrh[1]); + if (unlikely((lid >= HFI1_MULTICAST_LID_BASE) && + (lid != HFI1_PERMISSIVE_LID))) { + struct hfi1_mcast *mcast; + struct hfi1_mcast_qp *p; + + if (lnh != HFI1_LRH_GRH) + goto drop; + mcast = hfi1_mcast_find(ibp, &hdr->u.l.grh.dgid); + if (mcast == NULL) + goto drop; + list_for_each_entry_rcu(p, &mcast->qp_list, list) { + packet->qp = p->qp; + spin_lock(&packet->qp->r_lock); + if (likely((qp_ok(opcode, packet)))) + opcode_handler_tbl[opcode](packet); + spin_unlock(&packet->qp->r_lock); + } + /* + * Notify hfi1_multicast_detach() if it is waiting for us + * to finish. + */ + if (atomic_dec_return(&mcast->refcount) <= 1) + wake_up(&mcast->wait); + } else { + rcu_read_lock(); + packet->qp = hfi1_lookup_qpn(ibp, qp_num); + if (!packet->qp) { + rcu_read_unlock(); + goto drop; + } + spin_lock(&packet->qp->r_lock); + if (likely((qp_ok(opcode, packet)))) + opcode_handler_tbl[opcode](packet); + spin_unlock(&packet->qp->r_lock); + rcu_read_unlock(); + } + return; + +drop: + ibp->n_pkt_drops++; +} + +/* + * This is called from a timer to check for QPs + * which need kernel memory in order to send a packet. + */ +static void mem_timer(unsigned long data) +{ + struct hfi1_ibdev *dev = (struct hfi1_ibdev *)data; + struct list_head *list = &dev->memwait; + struct hfi1_qp *qp = NULL; + struct iowait *wait; + unsigned long flags; + + write_seqlock_irqsave(&dev->iowait_lock, flags); + if (!list_empty(list)) { + wait = list_first_entry(list, struct iowait, list); + qp = container_of(wait, struct hfi1_qp, s_iowait); + list_del_init(&qp->s_iowait.list); + /* refcount held until actual wake up */ + if (!list_empty(list)) + mod_timer(&dev->mem_timer, jiffies + 1); + } + write_sequnlock_irqrestore(&dev->iowait_lock, flags); + + if (qp) + hfi1_qp_wakeup(qp, HFI1_S_WAIT_KMEM); +} + +void update_sge(struct hfi1_sge_state *ss, u32 length) +{ + struct hfi1_sge *sge = &ss->sge; + + sge->vaddr += length; + sge->length -= length; + sge->sge_length -= length; + if (sge->sge_length == 0) { + if (--ss->num_sge) + *sge = *ss->sg_list++; + } else if (sge->length == 0 && sge->mr->lkey) { + if (++sge->n >= HFI1_SEGSZ) { + if (++sge->m >= sge->mr->mapsz) + return; + sge->n = 0; + } + sge->vaddr = sge->mr->map[sge->m]->segs[sge->n].vaddr; + sge->length = sge->mr->map[sge->m]->segs[sge->n].length; + } +} + +static noinline struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, + struct hfi1_qp *qp) +{ + struct verbs_txreq *tx; + unsigned long flags; + + tx = kmem_cache_alloc(dev->verbs_txreq_cache, GFP_ATOMIC); + if (!tx) { + spin_lock_irqsave(&qp->s_lock, flags); + write_seqlock(&dev->iowait_lock); + if (ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK && + list_empty(&qp->s_iowait.list)) { + dev->n_txwait++; + qp->s_flags |= HFI1_S_WAIT_TX; + list_add_tail(&qp->s_iowait.list, &dev->txwait); + trace_hfi1_qpsleep(qp, HFI1_S_WAIT_TX); + atomic_inc(&qp->refcount); + } + qp->s_flags &= ~HFI1_S_BUSY; + write_sequnlock(&dev->iowait_lock); + spin_unlock_irqrestore(&qp->s_lock, flags); + tx = ERR_PTR(-EBUSY); + } + return tx; +} + +static inline struct verbs_txreq *get_txreq(struct hfi1_ibdev *dev, + struct hfi1_qp *qp) +{ + struct verbs_txreq *tx; + + tx = kmem_cache_alloc(dev->verbs_txreq_cache, GFP_ATOMIC); + if (!tx) + /* call slow path to get the lock */ + tx = __get_txreq(dev, qp); + if (tx) + tx->qp = qp; + return tx; +} + +void hfi1_put_txreq(struct verbs_txreq *tx) +{ + struct hfi1_ibdev *dev; + struct hfi1_qp *qp; + unsigned long flags; + unsigned int seq; + + qp = tx->qp; + dev = to_idev(qp->ibqp.device); + + if (tx->mr) { + hfi1_put_mr(tx->mr); + tx->mr = NULL; + } + sdma_txclean(dd_from_dev(dev), &tx->txreq); + + /* Free verbs_txreq and return to slab cache */ + kmem_cache_free(dev->verbs_txreq_cache, tx); + + do { + seq = read_seqbegin(&dev->iowait_lock); + if (!list_empty(&dev->txwait)) { + struct iowait *wait; + + write_seqlock_irqsave(&dev->iowait_lock, flags); + /* Wake up first QP wanting a free struct */ + wait = list_first_entry(&dev->txwait, struct iowait, + list); + qp = container_of(wait, struct hfi1_qp, s_iowait); + list_del_init(&qp->s_iowait.list); + /* refcount held until actual wake up */ + write_sequnlock_irqrestore(&dev->iowait_lock, flags); + hfi1_qp_wakeup(qp, HFI1_S_WAIT_TX); + break; + } + } while (read_seqretry(&dev->iowait_lock, seq)); +} + +/* + * This is called with progress side lock held. + */ +/* New API */ +static void verbs_sdma_complete( + struct sdma_txreq *cookie, + int status, + int drained) +{ + struct verbs_txreq *tx = + container_of(cookie, struct verbs_txreq, txreq); + struct hfi1_qp *qp = tx->qp; + + spin_lock(&qp->s_lock); + if (tx->wqe) + hfi1_send_complete(qp, tx->wqe, IB_WC_SUCCESS); + else if (qp->ibqp.qp_type == IB_QPT_RC) { + struct hfi1_ib_header *hdr; + + hdr = &tx->phdr.hdr; + hfi1_rc_send_complete(qp, hdr); + } + if (drained) { + /* + * This happens when the send engine notes + * a QP in the error state and cannot + * do the flush work until that QP's + * sdma work has finished. + */ + if (qp->s_flags & HFI1_S_WAIT_DMA) { + qp->s_flags &= ~HFI1_S_WAIT_DMA; + hfi1_schedule_send(qp); + } + } + spin_unlock(&qp->s_lock); + + hfi1_put_txreq(tx); +} + +static int wait_kmem(struct hfi1_ibdev *dev, struct hfi1_qp *qp) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&qp->s_lock, flags); + if (ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK) { + write_seqlock(&dev->iowait_lock); + if (list_empty(&qp->s_iowait.list)) { + if (list_empty(&dev->memwait)) + mod_timer(&dev->mem_timer, jiffies + 1); + qp->s_flags |= HFI1_S_WAIT_KMEM; + list_add_tail(&qp->s_iowait.list, &dev->memwait); + trace_hfi1_qpsleep(qp, HFI1_S_WAIT_KMEM); + atomic_inc(&qp->refcount); + } + write_sequnlock(&dev->iowait_lock); + qp->s_flags &= ~HFI1_S_BUSY; + ret = -EBUSY; + } + spin_unlock_irqrestore(&qp->s_lock, flags); + + return ret; +} + +/* + * This routine calls txadds for each sg entry. + * + * Add failures will revert the sge cursor + */ +static int build_verbs_ulp_payload( + struct sdma_engine *sde, + struct hfi1_sge_state *ss, + u32 length, + struct verbs_txreq *tx) +{ + struct hfi1_sge *sg_list = ss->sg_list; + struct hfi1_sge sge = ss->sge; + u8 num_sge = ss->num_sge; + u32 len; + int ret = 0; + + while (length) { + len = ss->sge.length; + if (len > length) + len = length; + if (len > ss->sge.sge_length) + len = ss->sge.sge_length; + WARN_ON_ONCE(len == 0); + ret = sdma_txadd_kvaddr( + sde->dd, + &tx->txreq, + ss->sge.vaddr, + len); + if (ret) + goto bail_txadd; + update_sge(ss, len); + length -= len; + } + return ret; +bail_txadd: + /* unwind cursor */ + ss->sge = sge; + ss->num_sge = num_sge; + ss->sg_list = sg_list; + return ret; +} + +/* + * Build the number of DMA descriptors needed to send length bytes of data. + * + * NOTE: DMA mapping is held in the tx until completed in the ring or + * the tx desc is freed without having been submitted to the ring + * + * This routine insures the following all the helper routine + * calls succeed. + */ +/* New API */ +static int build_verbs_tx_desc( + struct sdma_engine *sde, + struct hfi1_sge_state *ss, + u32 length, + struct verbs_txreq *tx, + struct ahg_ib_header *ahdr, + u64 pbc) +{ + int ret = 0; + struct hfi1_pio_header *phdr; + u16 hdrbytes = tx->hdr_dwords << 2; + + phdr = &tx->phdr; + if (!ahdr->ahgcount) { + ret = sdma_txinit_ahg( + &tx->txreq, + ahdr->tx_flags, + hdrbytes + length, + ahdr->ahgidx, + 0, + NULL, + 0, + verbs_sdma_complete); + if (ret) + goto bail_txadd; + phdr->pbc = cpu_to_le64(pbc); + memcpy(&phdr->hdr, &ahdr->ibh, hdrbytes - sizeof(phdr->pbc)); + /* add the header */ + ret = sdma_txadd_kvaddr( + sde->dd, + &tx->txreq, + &tx->phdr, + tx->hdr_dwords << 2); + if (ret) + goto bail_txadd; + } else { + struct hfi1_other_headers *sohdr = &ahdr->ibh.u.oth; + struct hfi1_other_headers *dohdr = &phdr->hdr.u.oth; + + /* needed in rc_send_complete() */ + phdr->hdr.lrh[0] = ahdr->ibh.lrh[0]; + if ((be16_to_cpu(phdr->hdr.lrh[0]) & 3) == HFI1_LRH_GRH) { + sohdr = &ahdr->ibh.u.l.oth; + dohdr = &phdr->hdr.u.l.oth; + } + /* opcode */ + dohdr->bth[0] = sohdr->bth[0]; + /* PSN/ACK */ + dohdr->bth[2] = sohdr->bth[2]; + ret = sdma_txinit_ahg( + &tx->txreq, + ahdr->tx_flags, + length, + ahdr->ahgidx, + ahdr->ahgcount, + ahdr->ahgdesc, + hdrbytes, + verbs_sdma_complete); + if (ret) + goto bail_txadd; + } + + /* add the ulp payload - if any. ss can be NULL for acks */ + if (ss) + ret = build_verbs_ulp_payload(sde, ss, length, tx); +bail_txadd: + return ret; +} + +int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct ahg_ib_header *ahdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc) +{ + struct hfi1_ibdev *dev = to_idev(qp->ibqp.device); + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + struct verbs_txreq *tx; + struct sdma_txreq *stx; + u64 pbc_flags = 0; + struct sdma_engine *sde; + u8 sc5 = qp->s_sc; + int ret; + + if (!list_empty(&qp->s_iowait.tx_head)) { + stx = list_first_entry( + &qp->s_iowait.tx_head, + struct sdma_txreq, + list); + list_del_init(&stx->list); + tx = container_of(stx, struct verbs_txreq, txreq); + ret = sdma_send_txreq(tx->sde, &qp->s_iowait, stx); + if (unlikely(ret == -ECOMM)) + goto bail_ecomm; + return ret; + } + + tx = get_txreq(dev, qp); + if (IS_ERR(tx)) + goto bail_tx; + + if (!qp->s_hdr->sde) { + tx->sde = sde = qp_to_sdma_engine(qp, sc5); + if (!sde) + goto bail_no_sde; + } else + tx->sde = sde = qp->s_hdr->sde; + + if (likely(pbc == 0)) { + u32 vl = sc_to_vlt(dd_from_ibdev(qp->ibqp.device), sc5); + /* No vl15 here */ + /* set PBC_DC_INFO bit (aka SC[4]) in pbc_flags */ + pbc_flags |= (!!(sc5 & 0x10)) << PBC_DC_INFO_SHIFT; + + pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen); + } + tx->wqe = qp->s_wqe; + tx->mr = qp->s_rdma_mr; + if (qp->s_rdma_mr) + qp->s_rdma_mr = NULL; + tx->hdr_dwords = hdrwords + 2; + ret = build_verbs_tx_desc(sde, ss, len, tx, ahdr, pbc); + if (unlikely(ret)) + goto bail_build; + trace_output_ibhdr(dd_from_ibdev(qp->ibqp.device), &ahdr->ibh); + ret = sdma_send_txreq(sde, &qp->s_iowait, &tx->txreq); + if (unlikely(ret == -ECOMM)) + goto bail_ecomm; + return ret; + +bail_no_sde: + hfi1_put_txreq(tx); +bail_ecomm: + /* The current one got "sent" */ + return 0; +bail_build: + /* kmalloc or mapping fail */ + hfi1_put_txreq(tx); + return wait_kmem(dev, qp); +bail_tx: + return PTR_ERR(tx); +} + +/* + * If we are now in the error state, return zero to flush the + * send work request. + */ +static int no_bufs_available(struct hfi1_qp *qp, struct send_context *sc) +{ + struct hfi1_devdata *dd = sc->dd; + struct hfi1_ibdev *dev = &dd->verbs_dev; + unsigned long flags; + int ret = 0; + + /* + * Note that as soon as want_buffer() is called and + * possibly before it returns, sc_piobufavail() + * could be called. Therefore, put QP on the I/O wait list before + * enabling the PIO avail interrupt. + */ + spin_lock_irqsave(&qp->s_lock, flags); + if (ib_hfi1_state_ops[qp->state] & HFI1_PROCESS_RECV_OK) { + write_seqlock(&dev->iowait_lock); + if (list_empty(&qp->s_iowait.list)) { + struct hfi1_ibdev *dev = &dd->verbs_dev; + int was_empty; + + dev->n_piowait++; + qp->s_flags |= HFI1_S_WAIT_PIO; + was_empty = list_empty(&sc->piowait); + list_add_tail(&qp->s_iowait.list, &sc->piowait); + trace_hfi1_qpsleep(qp, HFI1_S_WAIT_PIO); + atomic_inc(&qp->refcount); + /* counting: only call wantpiobuf_intr if first user */ + if (was_empty) + hfi1_sc_wantpiobuf_intr(sc, 1); + } + write_sequnlock(&dev->iowait_lock); + qp->s_flags &= ~HFI1_S_BUSY; + ret = -EBUSY; + } + spin_unlock_irqrestore(&qp->s_lock, flags); + return ret; +} + +struct send_context *qp_to_send_context(struct hfi1_qp *qp, u8 sc5) +{ + struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device); + struct hfi1_pportdata *ppd = dd->pport + (qp->port_num - 1); + u8 vl; + + vl = sc_to_vlt(dd, sc5); + if (vl >= ppd->vls_supported && vl != 15) + return NULL; + return dd->vld[vl].sc; +} + +int hfi1_verbs_send_pio(struct hfi1_qp *qp, struct ahg_ib_header *ahdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc) +{ + struct hfi1_ibport *ibp = to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u32 *hdr = (u32 *)&ahdr->ibh; + u64 pbc_flags = 0; + u32 sc5; + unsigned long flags = 0; + struct send_context *sc; + struct pio_buf *pbuf; + int wc_status = IB_WC_SUCCESS; + + /* vl15 special case taken care of in ud.c */ + sc5 = qp->s_sc; + sc = qp_to_send_context(qp, sc5); + + if (!sc) + return -EINVAL; + if (likely(pbc == 0)) { + u32 vl = sc_to_vlt(dd_from_ibdev(qp->ibqp.device), sc5); + /* set PBC_DC_INFO bit (aka SC[4]) in pbc_flags */ + pbc_flags |= (!!(sc5 & 0x10)) << PBC_DC_INFO_SHIFT; + pbc = create_pbc(ppd, pbc_flags, qp->srate_mbps, vl, plen); + } + pbuf = sc_buffer_alloc(sc, plen, NULL, NULL); + if (unlikely(pbuf == NULL)) { + if (ppd->host_link_state != HLS_UP_ACTIVE) { + /* + * If we have filled the PIO buffers to capacity and are + * not in an active state this request is not going to + * go out to so just complete it with an error or else a + * ULP or the core may be stuck waiting. + */ + hfi1_cdbg( + PIO, + "alloc failed. state not active, completing"); + wc_status = IB_WC_GENERAL_ERR; + goto pio_bail; + } else { + /* + * This is a normal occurrence. The PIO buffs are full + * up but we are still happily sending, well we could be + * so lets continue to queue the request. + */ + hfi1_cdbg(PIO, "alloc failed. state active, queuing"); + return no_bufs_available(qp, sc); + } + } + + if (len == 0) { + pio_copy(ppd->dd, pbuf, pbc, hdr, hdrwords); + } else { + if (ss) { + seg_pio_copy_start(pbuf, pbc, hdr, hdrwords*4); + while (len) { + void *addr = ss->sge.vaddr; + u32 slen = ss->sge.length; + + if (slen > len) + slen = len; + update_sge(ss, slen); + seg_pio_copy_mid(pbuf, addr, slen); + len -= slen; + } + seg_pio_copy_end(pbuf); + } + } + + trace_output_ibhdr(dd_from_ibdev(qp->ibqp.device), &ahdr->ibh); + + if (qp->s_rdma_mr) { + hfi1_put_mr(qp->s_rdma_mr); + qp->s_rdma_mr = NULL; + } + +pio_bail: + if (qp->s_wqe) { + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_send_complete(qp, qp->s_wqe, wc_status); + spin_unlock_irqrestore(&qp->s_lock, flags); + } else if (qp->ibqp.qp_type == IB_QPT_RC) { + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_rc_send_complete(qp, &ahdr->ibh); + spin_unlock_irqrestore(&qp->s_lock, flags); + } + return 0; +} +/* + * egress_pkey_matches_entry - return 1 if the pkey matches ent (ent + * being an entry from the ingress partition key table), return 0 + * otherwise. Use the matching criteria for egress partition keys + * specified in the OPAv1 spec., section 9.1l.7. + */ +static inline int egress_pkey_matches_entry(u16 pkey, u16 ent) +{ + u16 mkey = pkey & PKEY_LOW_15_MASK; + u16 ment = ent & PKEY_LOW_15_MASK; + + if (mkey == ment) { + /* + * If pkey[15] is set (full partition member), + * is bit 15 in the corresponding table element + * clear (limited member)? + */ + if (pkey & PKEY_MEMBER_MASK) + return !!(ent & PKEY_MEMBER_MASK); + return 1; + } + return 0; +} + +/* + * egress_pkey_check - return 0 if hdr's pkey matches according to the + * criteria in the OPAv1 spec., section 9.11.7. + */ +static inline int egress_pkey_check(struct hfi1_pportdata *ppd, + struct hfi1_ib_header *hdr, + struct hfi1_qp *qp) +{ + struct hfi1_other_headers *ohdr; + struct hfi1_devdata *dd; + int i = 0; + u16 pkey; + u8 lnh, sc5 = qp->s_sc; + + if (!(ppd->part_enforce & HFI1_PART_ENFORCE_OUT)) + return 0; + + /* locate the pkey within the headers */ + lnh = be16_to_cpu(hdr->lrh[0]) & 3; + if (lnh == HFI1_LRH_GRH) + ohdr = &hdr->u.l.oth; + else + ohdr = &hdr->u.oth; + + pkey = (u16)be32_to_cpu(ohdr->bth[0]); + + /* If SC15, pkey[0:14] must be 0x7fff */ + if ((sc5 == 0xf) && ((pkey & PKEY_LOW_15_MASK) != PKEY_LOW_15_MASK)) + goto bad; + + + /* Is the pkey = 0x0, or 0x8000? */ + if ((pkey & PKEY_LOW_15_MASK) == 0) + goto bad; + + /* The most likely matching pkey has index qp->s_pkey_index */ + if (unlikely(!egress_pkey_matches_entry(pkey, + ppd->pkeys[qp->s_pkey_index]))) { + /* no match - try the entire table */ + for (; i < MAX_PKEY_VALUES; i++) { + if (egress_pkey_matches_entry(pkey, ppd->pkeys[i])) + break; + } + } + + if (i < MAX_PKEY_VALUES) + return 0; +bad: + incr_cntr64(&ppd->port_xmit_constraint_errors); + dd = ppd->dd; + if (!(dd->err_info_xmit_constraint.status & OPA_EI_STATUS_SMASK)) { + u16 slid = be16_to_cpu(hdr->lrh[3]); + + dd->err_info_xmit_constraint.status |= OPA_EI_STATUS_SMASK; + dd->err_info_xmit_constraint.slid = slid; + dd->err_info_xmit_constraint.pkey = pkey; + } + return 1; +} + +/** + * hfi1_verbs_send - send a packet + * @qp: the QP to send on + * @ahdr: the packet header + * @hdrwords: the number of 32-bit words in the header + * @ss: the SGE to send + * @len: the length of the packet in bytes + * + * Return zero if packet is sent or queued OK. + * Return non-zero and clear qp->s_flags HFI1_S_BUSY otherwise. + */ +int hfi1_verbs_send(struct hfi1_qp *qp, struct ahg_ib_header *ahdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len) +{ + struct hfi1_devdata *dd = dd_from_ibdev(qp->ibqp.device); + u32 plen; + int ret; + int pio = 0; + unsigned long flags = 0; + u32 dwords = (len + 3) >> 2; + + /* + * VL15 packets (IB_QPT_SMI) will always use PIO, so we + * can defer SDMA restart until link goes ACTIVE without + * worrying about just how we got there. + */ + if ((qp->ibqp.qp_type == IB_QPT_SMI) || + !(dd->flags & HFI1_HAS_SEND_DMA)) + pio = 1; + + ret = egress_pkey_check(dd->pport, &ahdr->ibh, qp); + if (unlikely(ret)) { + /* + * The value we are returning here does not get propagated to + * the verbs caller. Thus we need to complete the request with + * error otherwise the caller could be sitting waiting on the + * completion event. Only do this for PIO. SDMA has its own + * mechanism for handling the errors. So for SDMA we can just + * return. + */ + if (pio) { + hfi1_cdbg(PIO, "%s() Failed. Completing with err", + __func__); + spin_lock_irqsave(&qp->s_lock, flags); + hfi1_send_complete(qp, qp->s_wqe, IB_WC_GENERAL_ERR); + spin_unlock_irqrestore(&qp->s_lock, flags); + } + return -EINVAL; + } + + /* + * Calculate the send buffer trigger address. + * The +2 counts for the pbc control qword + */ + plen = hdrwords + dwords + 2; + + if (pio) { + ret = dd->process_pio_send( + qp, ahdr, hdrwords, ss, len, plen, dwords, 0); + } else { +#ifdef CONFIG_SDMA_VERBOSITY + dd_dev_err(dd, "CONFIG SDMA %s:%d %s()\n", + slashstrip(__FILE__), __LINE__, __func__); + dd_dev_err(dd, "SDMA hdrwords = %u, len = %u\n", hdrwords, len); +#endif + ret = dd->process_dma_send( + qp, ahdr, hdrwords, ss, len, plen, dwords, 0); + } + + return ret; +} + +static int query_device(struct ib_device *ibdev, + struct ib_device_attr *props, + struct ib_udata *uhw) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_ibdev *dev = to_idev(ibdev); + + if (uhw->inlen || uhw->outlen) + return -EINVAL; + memset(props, 0, sizeof(*props)); + + props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR | + IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT | + IB_DEVICE_SYS_IMAGE_GUID | IB_DEVICE_RC_RNR_NAK_GEN | + IB_DEVICE_PORT_ACTIVE_EVENT | IB_DEVICE_SRQ_RESIZE; + + props->page_size_cap = PAGE_SIZE; + props->vendor_id = + dd->oui1 << 16 | dd->oui2 << 8 | dd->oui3; + props->vendor_part_id = dd->pcidev->device; + props->hw_ver = dd->minrev; + props->sys_image_guid = ib_hfi1_sys_image_guid; + props->max_mr_size = ~0ULL; + props->max_qp = hfi1_max_qps; + props->max_qp_wr = hfi1_max_qp_wrs; + props->max_sge = hfi1_max_sges; + props->max_sge_rd = hfi1_max_sges; + props->max_cq = hfi1_max_cqs; + props->max_ah = hfi1_max_ahs; + props->max_cqe = hfi1_max_cqes; + props->max_mr = dev->lk_table.max; + props->max_fmr = dev->lk_table.max; + props->max_map_per_fmr = 32767; + props->max_pd = hfi1_max_pds; + props->max_qp_rd_atom = HFI1_MAX_RDMA_ATOMIC; + props->max_qp_init_rd_atom = 255; + /* props->max_res_rd_atom */ + props->max_srq = hfi1_max_srqs; + props->max_srq_wr = hfi1_max_srq_wrs; + props->max_srq_sge = hfi1_max_srq_sges; + /* props->local_ca_ack_delay */ + props->atomic_cap = IB_ATOMIC_GLOB; + props->max_pkeys = hfi1_get_npkeys(dd); + props->max_mcast_grp = hfi1_max_mcast_grps; + props->max_mcast_qp_attach = hfi1_max_mcast_qp_attached; + props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * + props->max_mcast_grp; + + return 0; +} + +static inline u16 opa_speed_to_ib(u16 in) +{ + u16 out = 0; + + if (in & OPA_LINK_SPEED_25G) + out |= IB_SPEED_EDR; + if (in & OPA_LINK_SPEED_12_5G) + out |= IB_SPEED_FDR; + + return out; +} + +/* + * Convert a single OPA link width (no multiple flags) to an IB value. + * A zero OPA link width means link down, which means the IB width value + * is a don't care. + */ +static inline u16 opa_width_to_ib(u16 in) +{ + switch (in) { + case OPA_LINK_WIDTH_1X: + /* map 2x and 3x to 1x as they don't exist in IB */ + case OPA_LINK_WIDTH_2X: + case OPA_LINK_WIDTH_3X: + return IB_WIDTH_1X; + default: /* link down or unknown, return our largest width */ + case OPA_LINK_WIDTH_4X: + return IB_WIDTH_4X; + } +} + +static int query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + u16 lid = ppd->lid; + + memset(props, 0, sizeof(*props)); + props->lid = lid ? lid : 0; + props->lmc = ppd->lmc; + props->sm_lid = ibp->sm_lid; + props->sm_sl = ibp->sm_sl; + /* OPA logical states match IB logical states */ + props->state = driver_lstate(ppd); + props->phys_state = hfi1_ibphys_portstate(ppd); + props->port_cap_flags = ibp->port_cap_flags; + props->gid_tbl_len = HFI1_GUIDS_PER_PORT; + props->max_msg_sz = 0x80000000; + props->pkey_tbl_len = hfi1_get_npkeys(dd); + props->bad_pkey_cntr = ibp->pkey_violations; + props->qkey_viol_cntr = ibp->qkey_violations; + props->active_width = (u8)opa_width_to_ib(ppd->link_width_active); + /* see rate_show() in ib core/sysfs.c */ + props->active_speed = (u8)opa_speed_to_ib(ppd->link_speed_active); + props->max_vl_num = ppd->vls_supported; + props->init_type_reply = 0; + + /* Once we are a "first class" citizen and have added the OPA MTUs to + * the core we can advertise the larger MTU enum to the ULPs, for now + * advertise only 4K. + * + * Those applications which are either OPA aware or pass the MTU enum + * from the Path Records to us will get the new 8k MTU. Those that + * attempt to process the MTU enum may fail in various ways. + */ + props->max_mtu = mtu_to_enum((!valid_ib_mtu(hfi1_max_mtu) ? + 4096 : hfi1_max_mtu), IB_MTU_4096); + props->active_mtu = !valid_ib_mtu(ppd->ibmtu) ? props->max_mtu : + mtu_to_enum(ppd->ibmtu, IB_MTU_2048); + props->subnet_timeout = ibp->subnet_timeout; + + return 0; +} + +static int port_immutable(struct ib_device *ibdev, u8 port_num, + struct ib_port_immutable *immutable) +{ + struct ib_port_attr attr; + int err; + + err = query_port(ibdev, port_num, &attr); + if (err) + return err; + + memset(immutable, 0, sizeof(*immutable)); + + immutable->pkey_tbl_len = attr.pkey_tbl_len; + immutable->gid_tbl_len = attr.gid_tbl_len; + immutable->core_cap_flags = RDMA_CORE_PORT_INTEL_OPA; + immutable->max_mad_size = OPA_MGMT_MAD_SIZE; + + return 0; +} + +static int modify_device(struct ib_device *device, + int device_modify_mask, + struct ib_device_modify *device_modify) +{ + struct hfi1_devdata *dd = dd_from_ibdev(device); + unsigned i; + int ret; + + if (device_modify_mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | + IB_DEVICE_MODIFY_NODE_DESC)) { + ret = -EOPNOTSUPP; + goto bail; + } + + if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC) { + memcpy(device->node_desc, device_modify->node_desc, 64); + for (i = 0; i < dd->num_pports; i++) { + struct hfi1_ibport *ibp = &dd->pport[i].ibport_data; + + hfi1_node_desc_chg(ibp); + } + } + + if (device_modify_mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) { + ib_hfi1_sys_image_guid = + cpu_to_be64(device_modify->sys_image_guid); + for (i = 0; i < dd->num_pports; i++) { + struct hfi1_ibport *ibp = &dd->pport[i].ibport_data; + + hfi1_sys_guid_chg(ibp); + } + } + + ret = 0; + +bail: + return ret; +} + +static int modify_port(struct ib_device *ibdev, u8 port, + int port_modify_mask, struct ib_port_modify *props) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + int ret = 0; + + ibp->port_cap_flags |= props->set_port_cap_mask; + ibp->port_cap_flags &= ~props->clr_port_cap_mask; + if (props->set_port_cap_mask || props->clr_port_cap_mask) + hfi1_cap_mask_chg(ibp); + if (port_modify_mask & IB_PORT_SHUTDOWN) { + set_link_down_reason(ppd, OPA_LINKDOWN_REASON_UNKNOWN, 0, + OPA_LINKDOWN_REASON_UNKNOWN); + ret = set_link_state(ppd, HLS_DN_DOWNDEF); + } + if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR) + ibp->qkey_violations = 0; + return ret; +} + +static int query_gid(struct ib_device *ibdev, u8 port, + int index, union ib_gid *gid) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + int ret = 0; + + if (!port || port > dd->num_pports) + ret = -EINVAL; + else { + struct hfi1_ibport *ibp = to_iport(ibdev, port); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + gid->global.subnet_prefix = ibp->gid_prefix; + if (index == 0) + gid->global.interface_id = cpu_to_be64(ppd->guid); + else if (index < HFI1_GUIDS_PER_PORT) + gid->global.interface_id = ibp->guids[index - 1]; + else + ret = -EINVAL; + } + + return ret; +} + +static struct ib_pd *alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct hfi1_ibdev *dev = to_idev(ibdev); + struct hfi1_pd *pd; + struct ib_pd *ret; + + /* + * This is actually totally arbitrary. Some correctness tests + * assume there's a maximum number of PDs that can be allocated. + * We don't actually have this limit, but we fail the test if + * we allow allocations of more than we report for this value. + */ + + pd = kmalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + spin_lock(&dev->n_pds_lock); + if (dev->n_pds_allocated == hfi1_max_pds) { + spin_unlock(&dev->n_pds_lock); + kfree(pd); + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + dev->n_pds_allocated++; + spin_unlock(&dev->n_pds_lock); + + /* ib_alloc_pd() will initialize pd->ibpd. */ + pd->user = udata != NULL; + + ret = &pd->ibpd; + +bail: + return ret; +} + +static int dealloc_pd(struct ib_pd *ibpd) +{ + struct hfi1_pd *pd = to_ipd(ibpd); + struct hfi1_ibdev *dev = to_idev(ibpd->device); + + spin_lock(&dev->n_pds_lock); + dev->n_pds_allocated--; + spin_unlock(&dev->n_pds_lock); + + kfree(pd); + + return 0; +} + +/* + * convert ah port,sl to sc + */ +u8 ah_to_sc(struct ib_device *ibdev, struct ib_ah_attr *ah) +{ + struct hfi1_ibport *ibp = to_iport(ibdev, ah->port_num); + + return ibp->sl_to_sc[ah->sl]; +} + +int hfi1_check_ah(struct ib_device *ibdev, struct ib_ah_attr *ah_attr) +{ + struct hfi1_ibport *ibp; + struct hfi1_pportdata *ppd; + struct hfi1_devdata *dd; + u8 sc5; + + /* A multicast address requires a GRH (see ch. 8.4.1). */ + if (ah_attr->dlid >= HFI1_MULTICAST_LID_BASE && + ah_attr->dlid != HFI1_PERMISSIVE_LID && + !(ah_attr->ah_flags & IB_AH_GRH)) + goto bail; + if ((ah_attr->ah_flags & IB_AH_GRH) && + ah_attr->grh.sgid_index >= HFI1_GUIDS_PER_PORT) + goto bail; + if (ah_attr->dlid == 0) + goto bail; + if (ah_attr->port_num < 1 || + ah_attr->port_num > ibdev->phys_port_cnt) + goto bail; + if (ah_attr->static_rate != IB_RATE_PORT_CURRENT && + ib_rate_to_mbps(ah_attr->static_rate) < 0) + goto bail; + if (ah_attr->sl >= OPA_MAX_SLS) + goto bail; + /* test the mapping for validity */ + ibp = to_iport(ibdev, ah_attr->port_num); + ppd = ppd_from_ibp(ibp); + sc5 = ibp->sl_to_sc[ah_attr->sl]; + dd = dd_from_ppd(ppd); + if (sc_to_vlt(dd, sc5) > num_vls && sc_to_vlt(dd, sc5) != 0xf) + goto bail; + return 0; +bail: + return -EINVAL; +} + +/** + * create_ah - create an address handle + * @pd: the protection domain + * @ah_attr: the attributes of the AH + * + * This may be called from interrupt context. + */ +static struct ib_ah *create_ah(struct ib_pd *pd, + struct ib_ah_attr *ah_attr) +{ + struct hfi1_ah *ah; + struct ib_ah *ret; + struct hfi1_ibdev *dev = to_idev(pd->device); + unsigned long flags; + + if (hfi1_check_ah(pd->device, ah_attr)) { + ret = ERR_PTR(-EINVAL); + goto bail; + } + + ah = kmalloc(sizeof(*ah), GFP_ATOMIC); + if (!ah) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + spin_lock_irqsave(&dev->n_ahs_lock, flags); + if (dev->n_ahs_allocated == hfi1_max_ahs) { + spin_unlock_irqrestore(&dev->n_ahs_lock, flags); + kfree(ah); + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + dev->n_ahs_allocated++; + spin_unlock_irqrestore(&dev->n_ahs_lock, flags); + + /* ib_create_ah() will initialize ah->ibah. */ + ah->attr = *ah_attr; + atomic_set(&ah->refcount, 0); + + ret = &ah->ibah; + +bail: + return ret; +} + +struct ib_ah *hfi1_create_qp0_ah(struct hfi1_ibport *ibp, u16 dlid) +{ + struct ib_ah_attr attr; + struct ib_ah *ah = ERR_PTR(-EINVAL); + struct hfi1_qp *qp0; + + memset(&attr, 0, sizeof(attr)); + attr.dlid = dlid; + attr.port_num = ppd_from_ibp(ibp)->port; + rcu_read_lock(); + qp0 = rcu_dereference(ibp->qp[0]); + if (qp0) + ah = ib_create_ah(qp0->ibqp.pd, &attr); + rcu_read_unlock(); + return ah; +} + +/** + * destroy_ah - destroy an address handle + * @ibah: the AH to destroy + * + * This may be called from interrupt context. + */ +static int destroy_ah(struct ib_ah *ibah) +{ + struct hfi1_ibdev *dev = to_idev(ibah->device); + struct hfi1_ah *ah = to_iah(ibah); + unsigned long flags; + + if (atomic_read(&ah->refcount) != 0) + return -EBUSY; + + spin_lock_irqsave(&dev->n_ahs_lock, flags); + dev->n_ahs_allocated--; + spin_unlock_irqrestore(&dev->n_ahs_lock, flags); + + kfree(ah); + + return 0; +} + +static int modify_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) +{ + struct hfi1_ah *ah = to_iah(ibah); + + if (hfi1_check_ah(ibah->device, ah_attr)) + return -EINVAL; + + ah->attr = *ah_attr; + + return 0; +} + +static int query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) +{ + struct hfi1_ah *ah = to_iah(ibah); + + *ah_attr = ah->attr; + + return 0; +} + +/** + * hfi1_get_npkeys - return the size of the PKEY table for context 0 + * @dd: the hfi1_ib device + */ +unsigned hfi1_get_npkeys(struct hfi1_devdata *dd) +{ + return ARRAY_SIZE(dd->pport[0].pkeys); +} + +static int query_pkey(struct ib_device *ibdev, u8 port, u16 index, + u16 *pkey) +{ + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + int ret; + + if (index >= hfi1_get_npkeys(dd)) { + ret = -EINVAL; + goto bail; + } + + *pkey = hfi1_get_pkey(to_iport(ibdev, port), index); + ret = 0; + +bail: + return ret; +} + +/** + * alloc_ucontext - allocate a ucontest + * @ibdev: the infiniband device + * @udata: not used by the driver + */ + +static struct ib_ucontext *alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct hfi1_ucontext *context; + struct ib_ucontext *ret; + + context = kmalloc(sizeof(*context), GFP_KERNEL); + if (!context) { + ret = ERR_PTR(-ENOMEM); + goto bail; + } + + ret = &context->ibucontext; + +bail: + return ret; +} + +static int dealloc_ucontext(struct ib_ucontext *context) +{ + kfree(to_iucontext(context)); + return 0; +} + +static void init_ibport(struct hfi1_pportdata *ppd) +{ + struct hfi1_ibport *ibp = &ppd->ibport_data; + size_t sz = ARRAY_SIZE(ibp->sl_to_sc); + int i; + + for (i = 0; i < sz; i++) { + ibp->sl_to_sc[i] = i; + ibp->sc_to_sl[i] = i; + } + + spin_lock_init(&ibp->lock); + /* Set the prefix to the default value (see ch. 4.1.1) */ + ibp->gid_prefix = IB_DEFAULT_GID_PREFIX; + ibp->sm_lid = 0; + /* Below should only set bits defined in OPA PortInfo.CapabilityMask */ + ibp->port_cap_flags = IB_PORT_AUTO_MIGR_SUP | + IB_PORT_CAP_MASK_NOTICE_SUP; + ibp->pma_counter_select[0] = IB_PMA_PORT_XMIT_DATA; + ibp->pma_counter_select[1] = IB_PMA_PORT_RCV_DATA; + ibp->pma_counter_select[2] = IB_PMA_PORT_XMIT_PKTS; + ibp->pma_counter_select[3] = IB_PMA_PORT_RCV_PKTS; + ibp->pma_counter_select[4] = IB_PMA_PORT_XMIT_WAIT; + + RCU_INIT_POINTER(ibp->qp[0], NULL); + RCU_INIT_POINTER(ibp->qp[1], NULL); +} + +static void verbs_txreq_kmem_cache_ctor(void *obj) +{ + struct verbs_txreq *tx = (struct verbs_txreq *)obj; + + memset(tx, 0, sizeof(*tx)); +} + +/** + * hfi1_register_ib_device - register our device with the infiniband core + * @dd: the device data structure + * Return 0 if successful, errno if unsuccessful. + */ +int hfi1_register_ib_device(struct hfi1_devdata *dd) +{ + struct hfi1_ibdev *dev = &dd->verbs_dev; + struct ib_device *ibdev = &dev->ibdev; + struct hfi1_pportdata *ppd = dd->pport; + unsigned i, lk_tab_size; + int ret; + size_t lcpysz = IB_DEVICE_NAME_MAX; + u16 descq_cnt; + + ret = hfi1_qp_init(dev); + if (ret) + goto err_qp_init; + + + for (i = 0; i < dd->num_pports; i++) + init_ibport(ppd + i); + + /* Only need to initialize non-zero fields. */ + spin_lock_init(&dev->n_pds_lock); + spin_lock_init(&dev->n_ahs_lock); + spin_lock_init(&dev->n_cqs_lock); + spin_lock_init(&dev->n_qps_lock); + spin_lock_init(&dev->n_srqs_lock); + spin_lock_init(&dev->n_mcast_grps_lock); + init_timer(&dev->mem_timer); + dev->mem_timer.function = mem_timer; + dev->mem_timer.data = (unsigned long) dev; + + /* + * The top hfi1_lkey_table_size bits are used to index the + * table. The lower 8 bits can be owned by the user (copied from + * the LKEY). The remaining bits act as a generation number or tag. + */ + spin_lock_init(&dev->lk_table.lock); + dev->lk_table.max = 1 << hfi1_lkey_table_size; + /* ensure generation is at least 4 bits (keys.c) */ + if (hfi1_lkey_table_size > MAX_LKEY_TABLE_BITS) { + dd_dev_warn(dd, "lkey bits %u too large, reduced to %u\n", + hfi1_lkey_table_size, MAX_LKEY_TABLE_BITS); + hfi1_lkey_table_size = MAX_LKEY_TABLE_BITS; + } + lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); + dev->lk_table.table = (struct hfi1_mregion __rcu **) + vmalloc(lk_tab_size); + if (dev->lk_table.table == NULL) { + ret = -ENOMEM; + goto err_lk; + } + RCU_INIT_POINTER(dev->dma_mr, NULL); + for (i = 0; i < dev->lk_table.max; i++) + RCU_INIT_POINTER(dev->lk_table.table[i], NULL); + INIT_LIST_HEAD(&dev->pending_mmaps); + spin_lock_init(&dev->pending_lock); + seqlock_init(&dev->iowait_lock); + dev->mmap_offset = PAGE_SIZE; + spin_lock_init(&dev->mmap_offset_lock); + INIT_LIST_HEAD(&dev->txwait); + INIT_LIST_HEAD(&dev->memwait); + + descq_cnt = sdma_get_descq_cnt(); + + /* SLAB_HWCACHE_ALIGN for AHG */ + dev->verbs_txreq_cache = kmem_cache_create("hfi1_vtxreq_cache", + sizeof(struct verbs_txreq), + 0, SLAB_HWCACHE_ALIGN, + verbs_txreq_kmem_cache_ctor); + if (!dev->verbs_txreq_cache) { + ret = -ENOMEM; + goto err_verbs_txreq; + } + + /* + * The system image GUID is supposed to be the same for all + * HFIs in a single system but since there can be other + * device types in the system, we can't be sure this is unique. + */ + if (!ib_hfi1_sys_image_guid) + ib_hfi1_sys_image_guid = cpu_to_be64(ppd->guid); + lcpysz = strlcpy(ibdev->name, class_name(), lcpysz); + strlcpy(ibdev->name + lcpysz, "_%d", IB_DEVICE_NAME_MAX - lcpysz); + ibdev->owner = THIS_MODULE; + ibdev->node_guid = cpu_to_be64(ppd->guid); + ibdev->uverbs_abi_ver = HFI1_UVERBS_ABI_VERSION; + ibdev->uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_CREATE_AH) | + (1ull << IB_USER_VERBS_CMD_MODIFY_AH) | + (1ull << IB_USER_VERBS_CMD_QUERY_AH) | + (1ull << IB_USER_VERBS_CMD_DESTROY_AH) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_POLL_CQ) | + (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_POST_SEND) | + (1ull << IB_USER_VERBS_CMD_POST_RECV) | + (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | + (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | + (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | + (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | + (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV); + ibdev->node_type = RDMA_NODE_IB_CA; + ibdev->phys_port_cnt = dd->num_pports; + ibdev->num_comp_vectors = 1; + ibdev->dma_device = &dd->pcidev->dev; + ibdev->query_device = query_device; + ibdev->modify_device = modify_device; + ibdev->query_port = query_port; + ibdev->modify_port = modify_port; + ibdev->query_pkey = query_pkey; + ibdev->query_gid = query_gid; + ibdev->alloc_ucontext = alloc_ucontext; + ibdev->dealloc_ucontext = dealloc_ucontext; + ibdev->alloc_pd = alloc_pd; + ibdev->dealloc_pd = dealloc_pd; + ibdev->create_ah = create_ah; + ibdev->destroy_ah = destroy_ah; + ibdev->modify_ah = modify_ah; + ibdev->query_ah = query_ah; + ibdev->create_srq = hfi1_create_srq; + ibdev->modify_srq = hfi1_modify_srq; + ibdev->query_srq = hfi1_query_srq; + ibdev->destroy_srq = hfi1_destroy_srq; + ibdev->create_qp = hfi1_create_qp; + ibdev->modify_qp = hfi1_modify_qp; + ibdev->query_qp = hfi1_query_qp; + ibdev->destroy_qp = hfi1_destroy_qp; + ibdev->post_send = post_send; + ibdev->post_recv = post_receive; + ibdev->post_srq_recv = hfi1_post_srq_receive; + ibdev->create_cq = hfi1_create_cq; + ibdev->destroy_cq = hfi1_destroy_cq; + ibdev->resize_cq = hfi1_resize_cq; + ibdev->poll_cq = hfi1_poll_cq; + ibdev->req_notify_cq = hfi1_req_notify_cq; + ibdev->get_dma_mr = hfi1_get_dma_mr; + ibdev->reg_phys_mr = hfi1_reg_phys_mr; + ibdev->reg_user_mr = hfi1_reg_user_mr; + ibdev->dereg_mr = hfi1_dereg_mr; + ibdev->alloc_fast_reg_page_list = hfi1_alloc_fast_reg_page_list; + ibdev->free_fast_reg_page_list = hfi1_free_fast_reg_page_list; + ibdev->alloc_fmr = hfi1_alloc_fmr; + ibdev->map_phys_fmr = hfi1_map_phys_fmr; + ibdev->unmap_fmr = hfi1_unmap_fmr; + ibdev->dealloc_fmr = hfi1_dealloc_fmr; + ibdev->attach_mcast = hfi1_multicast_attach; + ibdev->detach_mcast = hfi1_multicast_detach; + ibdev->process_mad = hfi1_process_mad; + ibdev->mmap = hfi1_mmap; + ibdev->dma_ops = &hfi1_dma_mapping_ops; + ibdev->get_port_immutable = port_immutable; + + strncpy(ibdev->node_desc, init_utsname()->nodename, + sizeof(ibdev->node_desc)); + + ret = ib_register_device(ibdev, hfi1_create_port_files); + if (ret) + goto err_reg; + + ret = hfi1_create_agents(dev); + if (ret) + goto err_agents; + + ret = hfi1_verbs_register_sysfs(dd); + if (ret) + goto err_class; + + goto bail; + +err_class: + hfi1_free_agents(dev); +err_agents: + ib_unregister_device(ibdev); +err_reg: +err_verbs_txreq: + kmem_cache_destroy(dev->verbs_txreq_cache); + vfree(dev->lk_table.table); +err_lk: + hfi1_qp_exit(dev); +err_qp_init: + dd_dev_err(dd, "cannot register verbs: %d!\n", -ret); +bail: + return ret; +} + +void hfi1_unregister_ib_device(struct hfi1_devdata *dd) +{ + struct hfi1_ibdev *dev = &dd->verbs_dev; + struct ib_device *ibdev = &dev->ibdev; + + hfi1_verbs_unregister_sysfs(dd); + + hfi1_free_agents(dev); + + ib_unregister_device(ibdev); + + if (!list_empty(&dev->txwait)) + dd_dev_err(dd, "txwait list not empty!\n"); + if (!list_empty(&dev->memwait)) + dd_dev_err(dd, "memwait list not empty!\n"); + if (dev->dma_mr) + dd_dev_err(dd, "DMA MR not NULL!\n"); + + hfi1_qp_exit(dev); + del_timer_sync(&dev->mem_timer); + kmem_cache_destroy(dev->verbs_txreq_cache); + vfree(dev->lk_table.table); +} + +/* + * This must be called with s_lock held. + */ +void hfi1_schedule_send(struct hfi1_qp *qp) +{ + if (hfi1_send_ok(qp)) { + struct hfi1_ibport *ibp = + to_iport(qp->ibqp.device, qp->port_num); + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + iowait_schedule(&qp->s_iowait, ppd->hfi1_wq); + } +} + +void hfi1_cnp_rcv(struct hfi1_packet *packet) +{ + struct hfi1_ibport *ibp = &packet->rcd->ppd->ibport_data; + + if (packet->qp->ibqp.qp_type == IB_QPT_UC) + hfi1_uc_rcv(packet); + else if (packet->qp->ibqp.qp_type == IB_QPT_UD) + hfi1_ud_rcv(packet); + else + ibp->n_pkt_drops++; +} diff --git a/drivers/staging/rdma/hfi1/verbs.h b/drivers/staging/rdma/hfi1/verbs.h new file mode 100644 index 0000000000000..812536194190e --- /dev/null +++ b/drivers/staging/rdma/hfi1/verbs.h @@ -0,0 +1,1149 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef HFI1_VERBS_H +#define HFI1_VERBS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct hfi1_ctxtdata; +struct hfi1_pportdata; +struct hfi1_devdata; +struct hfi1_packet; + +#include "iowait.h" + +#define HFI1_MAX_RDMA_ATOMIC 16 +#define HFI1_GUIDS_PER_PORT 5 + +/* + * Increment this value if any changes that break userspace ABI + * compatibility are made. + */ +#define HFI1_UVERBS_ABI_VERSION 2 + +/* + * Define an ib_cq_notify value that is not valid so we know when CQ + * notifications are armed. + */ +#define IB_CQ_NONE (IB_CQ_NEXT_COMP + 1) + +#define IB_SEQ_NAK (3 << 29) + +/* AETH NAK opcode values */ +#define IB_RNR_NAK 0x20 +#define IB_NAK_PSN_ERROR 0x60 +#define IB_NAK_INVALID_REQUEST 0x61 +#define IB_NAK_REMOTE_ACCESS_ERROR 0x62 +#define IB_NAK_REMOTE_OPERATIONAL_ERROR 0x63 +#define IB_NAK_INVALID_RD_REQUEST 0x64 + +/* Flags for checking QP state (see ib_hfi1_state_ops[]) */ +#define HFI1_POST_SEND_OK 0x01 +#define HFI1_POST_RECV_OK 0x02 +#define HFI1_PROCESS_RECV_OK 0x04 +#define HFI1_PROCESS_SEND_OK 0x08 +#define HFI1_PROCESS_NEXT_SEND_OK 0x10 +#define HFI1_FLUSH_SEND 0x20 +#define HFI1_FLUSH_RECV 0x40 +#define HFI1_PROCESS_OR_FLUSH_SEND \ + (HFI1_PROCESS_SEND_OK | HFI1_FLUSH_SEND) + +/* IB Performance Manager status values */ +#define IB_PMA_SAMPLE_STATUS_DONE 0x00 +#define IB_PMA_SAMPLE_STATUS_STARTED 0x01 +#define IB_PMA_SAMPLE_STATUS_RUNNING 0x02 + +/* Mandatory IB performance counter select values. */ +#define IB_PMA_PORT_XMIT_DATA cpu_to_be16(0x0001) +#define IB_PMA_PORT_RCV_DATA cpu_to_be16(0x0002) +#define IB_PMA_PORT_XMIT_PKTS cpu_to_be16(0x0003) +#define IB_PMA_PORT_RCV_PKTS cpu_to_be16(0x0004) +#define IB_PMA_PORT_XMIT_WAIT cpu_to_be16(0x0005) + +#define HFI1_VENDOR_IPG cpu_to_be16(0xFFA0) + +#define IB_BTH_REQ_ACK (1 << 31) +#define IB_BTH_SOLICITED (1 << 23) +#define IB_BTH_MIG_REQ (1 << 22) + +#define IB_GRH_VERSION 6 +#define IB_GRH_VERSION_MASK 0xF +#define IB_GRH_VERSION_SHIFT 28 +#define IB_GRH_TCLASS_MASK 0xFF +#define IB_GRH_TCLASS_SHIFT 20 +#define IB_GRH_FLOW_MASK 0xFFFFF +#define IB_GRH_FLOW_SHIFT 0 +#define IB_GRH_NEXT_HDR 0x1B + +#define IB_DEFAULT_GID_PREFIX cpu_to_be64(0xfe80000000000000ULL) + +/* flags passed by hfi1_ib_rcv() */ +enum { + HFI1_HAS_GRH = (1 << 0), +}; + +struct ib_reth { + __be64 vaddr; + __be32 rkey; + __be32 length; +} __packed; + +struct ib_atomic_eth { + __be32 vaddr[2]; /* unaligned so access as 2 32-bit words */ + __be32 rkey; + __be64 swap_data; + __be64 compare_data; +} __packed; + +union ib_ehdrs { + struct { + __be32 deth[2]; + __be32 imm_data; + } ud; + struct { + struct ib_reth reth; + __be32 imm_data; + } rc; + struct { + __be32 aeth; + __be32 atomic_ack_eth[2]; + } at; + __be32 imm_data; + __be32 aeth; + struct ib_atomic_eth atomic_eth; +} __packed; + +struct hfi1_other_headers { + __be32 bth[3]; + union ib_ehdrs u; +} __packed; + +/* + * Note that UD packets with a GRH header are 8+40+12+8 = 68 bytes + * long (72 w/ imm_data). Only the first 56 bytes of the IB header + * will be in the eager header buffer. The remaining 12 or 16 bytes + * are in the data buffer. + */ +struct hfi1_ib_header { + __be16 lrh[4]; + union { + struct { + struct ib_grh grh; + struct hfi1_other_headers oth; + } l; + struct hfi1_other_headers oth; + } u; +} __packed; + +struct ahg_ib_header { + struct sdma_engine *sde; + u32 ahgdesc[2]; + u16 tx_flags; + u8 ahgcount; + u8 ahgidx; + struct hfi1_ib_header ibh; +}; + +struct hfi1_pio_header { + __le64 pbc; + struct hfi1_ib_header hdr; +} __packed; + +/* + * used for force cacheline alignment for AHG + */ +struct tx_pio_header { + struct hfi1_pio_header phdr; +} ____cacheline_aligned; + +/* + * There is one struct hfi1_mcast for each multicast GID. + * All attached QPs are then stored as a list of + * struct hfi1_mcast_qp. + */ +struct hfi1_mcast_qp { + struct list_head list; + struct hfi1_qp *qp; +}; + +struct hfi1_mcast { + struct rb_node rb_node; + union ib_gid mgid; + struct list_head qp_list; + wait_queue_head_t wait; + atomic_t refcount; + int n_attached; +}; + +/* Protection domain */ +struct hfi1_pd { + struct ib_pd ibpd; + int user; /* non-zero if created from user space */ +}; + +/* Address Handle */ +struct hfi1_ah { + struct ib_ah ibah; + struct ib_ah_attr attr; + atomic_t refcount; +}; + +/* + * This structure is used by hfi1_mmap() to validate an offset + * when an mmap() request is made. The vm_area_struct then uses + * this as its vm_private_data. + */ +struct hfi1_mmap_info { + struct list_head pending_mmaps; + struct ib_ucontext *context; + void *obj; + __u64 offset; + struct kref ref; + unsigned size; +}; + +/* + * This structure is used to contain the head pointer, tail pointer, + * and completion queue entries as a single memory allocation so + * it can be mmap'ed into user space. + */ +struct hfi1_cq_wc { + u32 head; /* index of next entry to fill */ + u32 tail; /* index of next ib_poll_cq() entry */ + union { + /* these are actually size ibcq.cqe + 1 */ + struct ib_uverbs_wc uqueue[0]; + struct ib_wc kqueue[0]; + }; +}; + +/* + * The completion queue structure. + */ +struct hfi1_cq { + struct ib_cq ibcq; + struct kthread_work comptask; + struct hfi1_devdata *dd; + spinlock_t lock; /* protect changes in this struct */ + u8 notify; + u8 triggered; + struct hfi1_cq_wc *queue; + struct hfi1_mmap_info *ip; +}; + +/* + * A segment is a linear region of low physical memory. + * Used by the verbs layer. + */ +struct hfi1_seg { + void *vaddr; + size_t length; +}; + +/* The number of hfi1_segs that fit in a page. */ +#define HFI1_SEGSZ (PAGE_SIZE / sizeof(struct hfi1_seg)) + +struct hfi1_segarray { + struct hfi1_seg segs[HFI1_SEGSZ]; +}; + +struct hfi1_mregion { + struct ib_pd *pd; /* shares refcnt of ibmr.pd */ + u64 user_base; /* User's address for this region */ + u64 iova; /* IB start address of this region */ + size_t length; + u32 lkey; + u32 offset; /* offset (bytes) to start of region */ + int access_flags; + u32 max_segs; /* number of hfi1_segs in all the arrays */ + u32 mapsz; /* size of the map array */ + u8 page_shift; /* 0 - non unform/non powerof2 sizes */ + u8 lkey_published; /* in global table */ + struct completion comp; /* complete when refcount goes to zero */ + atomic_t refcount; + struct hfi1_segarray *map[0]; /* the segments */ +}; + +/* + * These keep track of the copy progress within a memory region. + * Used by the verbs layer. + */ +struct hfi1_sge { + struct hfi1_mregion *mr; + void *vaddr; /* kernel virtual address of segment */ + u32 sge_length; /* length of the SGE */ + u32 length; /* remaining length of the segment */ + u16 m; /* current index: mr->map[m] */ + u16 n; /* current index: mr->map[m]->segs[n] */ +}; + +/* Memory region */ +struct hfi1_mr { + struct ib_mr ibmr; + struct ib_umem *umem; + struct hfi1_mregion mr; /* must be last */ +}; + +/* + * Send work request queue entry. + * The size of the sg_list is determined when the QP is created and stored + * in qp->s_max_sge. + */ +struct hfi1_swqe { + struct ib_send_wr wr; /* don't use wr.sg_list */ + u32 psn; /* first packet sequence number */ + u32 lpsn; /* last packet sequence number */ + u32 ssn; /* send sequence number */ + u32 length; /* total length of data in sg_list */ + struct hfi1_sge sg_list[0]; +}; + +/* + * Receive work request queue entry. + * The size of the sg_list is determined when the QP (or SRQ) is created + * and stored in qp->r_rq.max_sge (or srq->rq.max_sge). + */ +struct hfi1_rwqe { + u64 wr_id; + u8 num_sge; + struct ib_sge sg_list[0]; +}; + +/* + * This structure is used to contain the head pointer, tail pointer, + * and receive work queue entries as a single memory allocation so + * it can be mmap'ed into user space. + * Note that the wq array elements are variable size so you can't + * just index into the array to get the N'th element; + * use get_rwqe_ptr() instead. + */ +struct hfi1_rwq { + u32 head; /* new work requests posted to the head */ + u32 tail; /* receives pull requests from here. */ + struct hfi1_rwqe wq[0]; +}; + +struct hfi1_rq { + struct hfi1_rwq *wq; + u32 size; /* size of RWQE array */ + u8 max_sge; + /* protect changes in this struct */ + spinlock_t lock ____cacheline_aligned_in_smp; +}; + +struct hfi1_srq { + struct ib_srq ibsrq; + struct hfi1_rq rq; + struct hfi1_mmap_info *ip; + /* send signal when number of RWQEs < limit */ + u32 limit; +}; + +struct hfi1_sge_state { + struct hfi1_sge *sg_list; /* next SGE to be used if any */ + struct hfi1_sge sge; /* progress state for the current SGE */ + u32 total_len; + u8 num_sge; +}; + +/* + * This structure holds the information that the send tasklet needs + * to send a RDMA read response or atomic operation. + */ +struct hfi1_ack_entry { + u8 opcode; + u8 sent; + u32 psn; + u32 lpsn; + union { + struct hfi1_sge rdma_sge; + u64 atomic_data; + }; +}; + +/* + * Variables prefixed with s_ are for the requester (sender). + * Variables prefixed with r_ are for the responder (receiver). + * Variables prefixed with ack_ are for responder replies. + * + * Common variables are protected by both r_rq.lock and s_lock in that order + * which only happens in modify_qp() or changing the QP 'state'. + */ +struct hfi1_qp { + struct ib_qp ibqp; + /* read mostly fields above and below */ + struct ib_ah_attr remote_ah_attr; + struct ib_ah_attr alt_ah_attr; + struct hfi1_qp __rcu *next; /* link list for QPN hash table */ + struct hfi1_swqe *s_wq; /* send work queue */ + struct hfi1_mmap_info *ip; + struct ahg_ib_header *s_hdr; /* next packet header to send */ + u8 s_sc; /* SC[0..4] for next packet */ + unsigned long timeout_jiffies; /* computed from timeout */ + + enum ib_mtu path_mtu; + int srate_mbps; /* s_srate (below) converted to Mbit/s */ + u32 remote_qpn; + u32 pmtu; /* decoded from path_mtu */ + u32 qkey; /* QKEY for this QP (for UD or RD) */ + u32 s_size; /* send work queue size */ + u32 s_rnr_timeout; /* number of milliseconds for RNR timeout */ + u32 s_ahgpsn; /* set to the psn in the copy of the header */ + + u8 state; /* QP state */ + u8 allowed_ops; /* high order bits of allowed opcodes */ + u8 qp_access_flags; + u8 alt_timeout; /* Alternate path timeout for this QP */ + u8 timeout; /* Timeout for this QP */ + u8 s_srate; + u8 s_mig_state; + u8 port_num; + u8 s_pkey_index; /* PKEY index to use */ + u8 s_alt_pkey_index; /* Alternate path PKEY index to use */ + u8 r_max_rd_atomic; /* max number of RDMA read/atomic to receive */ + u8 s_max_rd_atomic; /* max number of RDMA read/atomic to send */ + u8 s_retry_cnt; /* number of times to retry */ + u8 s_rnr_retry_cnt; + u8 r_min_rnr_timer; /* retry timeout value for RNR NAKs */ + u8 s_max_sge; /* size of s_wq->sg_list */ + u8 s_draining; + + /* start of read/write fields */ + atomic_t refcount ____cacheline_aligned_in_smp; + wait_queue_head_t wait; + + + struct hfi1_ack_entry s_ack_queue[HFI1_MAX_RDMA_ATOMIC + 1] + ____cacheline_aligned_in_smp; + struct hfi1_sge_state s_rdma_read_sge; + + spinlock_t r_lock ____cacheline_aligned_in_smp; /* used for APM */ + unsigned long r_aflags; + u64 r_wr_id; /* ID for current receive WQE */ + u32 r_ack_psn; /* PSN for next ACK or atomic ACK */ + u32 r_len; /* total length of r_sge */ + u32 r_rcv_len; /* receive data len processed */ + u32 r_psn; /* expected rcv packet sequence number */ + u32 r_msn; /* message sequence number */ + + u8 r_state; /* opcode of last packet received */ + u8 r_flags; + u8 r_head_ack_queue; /* index into s_ack_queue[] */ + + struct list_head rspwait; /* link for waiting to respond */ + + struct hfi1_sge_state r_sge; /* current receive data */ + struct hfi1_rq r_rq; /* receive work queue */ + + spinlock_t s_lock ____cacheline_aligned_in_smp; + struct hfi1_sge_state *s_cur_sge; + u32 s_flags; + struct hfi1_swqe *s_wqe; + struct hfi1_sge_state s_sge; /* current send request data */ + struct hfi1_mregion *s_rdma_mr; + struct sdma_engine *s_sde; /* current sde */ + u32 s_cur_size; /* size of send packet in bytes */ + u32 s_len; /* total length of s_sge */ + u32 s_rdma_read_len; /* total length of s_rdma_read_sge */ + u32 s_next_psn; /* PSN for next request */ + u32 s_last_psn; /* last response PSN processed */ + u32 s_sending_psn; /* lowest PSN that is being sent */ + u32 s_sending_hpsn; /* highest PSN that is being sent */ + u32 s_psn; /* current packet sequence number */ + u32 s_ack_rdma_psn; /* PSN for sending RDMA read responses */ + u32 s_ack_psn; /* PSN for acking sends and RDMA writes */ + u32 s_head; /* new entries added here */ + u32 s_tail; /* next entry to process */ + u32 s_cur; /* current work queue entry */ + u32 s_acked; /* last un-ACK'ed entry */ + u32 s_last; /* last completed entry */ + u32 s_ssn; /* SSN of tail entry */ + u32 s_lsn; /* limit sequence number (credit) */ + u16 s_hdrwords; /* size of s_hdr in 32 bit words */ + u16 s_rdma_ack_cnt; + s8 s_ahgidx; + u8 s_state; /* opcode of last packet sent */ + u8 s_ack_state; /* opcode of packet to ACK */ + u8 s_nak_state; /* non-zero if NAK is pending */ + u8 r_nak_state; /* non-zero if NAK is pending */ + u8 s_retry; /* requester retry counter */ + u8 s_rnr_retry; /* requester RNR retry counter */ + u8 s_num_rd_atomic; /* number of RDMA read/atomic pending */ + u8 s_tail_ack_queue; /* index into s_ack_queue[] */ + + struct hfi1_sge_state s_ack_rdma_sge; + struct timer_list s_timer; + + struct iowait s_iowait; + + struct hfi1_sge r_sg_list[0] /* verified SGEs */ + ____cacheline_aligned_in_smp; +}; + +/* + * Atomic bit definitions for r_aflags. + */ +#define HFI1_R_WRID_VALID 0 +#define HFI1_R_REWIND_SGE 1 + +/* + * Bit definitions for r_flags. + */ +#define HFI1_R_REUSE_SGE 0x01 +#define HFI1_R_RDMAR_SEQ 0x02 +#define HFI1_R_RSP_NAK 0x04 +#define HFI1_R_RSP_SEND 0x08 +#define HFI1_R_COMM_EST 0x10 + +/* + * Bit definitions for s_flags. + * + * HFI1_S_SIGNAL_REQ_WR - set if QP send WRs contain completion signaled + * HFI1_S_BUSY - send tasklet is processing the QP + * HFI1_S_TIMER - the RC retry timer is active + * HFI1_S_ACK_PENDING - an ACK is waiting to be sent after RDMA read/atomics + * HFI1_S_WAIT_FENCE - waiting for all prior RDMA read or atomic SWQEs + * before processing the next SWQE + * HFI1_S_WAIT_RDMAR - waiting for a RDMA read or atomic SWQE to complete + * before processing the next SWQE + * HFI1_S_WAIT_RNR - waiting for RNR timeout + * HFI1_S_WAIT_SSN_CREDIT - waiting for RC credits to process next SWQE + * HFI1_S_WAIT_DMA - waiting for send DMA queue to drain before generating + * next send completion entry not via send DMA + * HFI1_S_WAIT_PIO - waiting for a send buffer to be available + * HFI1_S_WAIT_TX - waiting for a struct verbs_txreq to be available + * HFI1_S_WAIT_DMA_DESC - waiting for DMA descriptors to be available + * HFI1_S_WAIT_KMEM - waiting for kernel memory to be available + * HFI1_S_WAIT_PSN - waiting for a packet to exit the send DMA queue + * HFI1_S_WAIT_ACK - waiting for an ACK packet before sending more requests + * HFI1_S_SEND_ONE - send one packet, request ACK, then wait for ACK + * HFI1_S_ECN - a BECN was queued to the send engine + */ +#define HFI1_S_SIGNAL_REQ_WR 0x0001 +#define HFI1_S_BUSY 0x0002 +#define HFI1_S_TIMER 0x0004 +#define HFI1_S_RESP_PENDING 0x0008 +#define HFI1_S_ACK_PENDING 0x0010 +#define HFI1_S_WAIT_FENCE 0x0020 +#define HFI1_S_WAIT_RDMAR 0x0040 +#define HFI1_S_WAIT_RNR 0x0080 +#define HFI1_S_WAIT_SSN_CREDIT 0x0100 +#define HFI1_S_WAIT_DMA 0x0200 +#define HFI1_S_WAIT_PIO 0x0400 +#define HFI1_S_WAIT_TX 0x0800 +#define HFI1_S_WAIT_DMA_DESC 0x1000 +#define HFI1_S_WAIT_KMEM 0x2000 +#define HFI1_S_WAIT_PSN 0x4000 +#define HFI1_S_WAIT_ACK 0x8000 +#define HFI1_S_SEND_ONE 0x10000 +#define HFI1_S_UNLIMITED_CREDIT 0x20000 +#define HFI1_S_AHG_VALID 0x40000 +#define HFI1_S_AHG_CLEAR 0x80000 +#define HFI1_S_ECN 0x100000 + +/* + * Wait flags that would prevent any packet type from being sent. + */ +#define HFI1_S_ANY_WAIT_IO (HFI1_S_WAIT_PIO | HFI1_S_WAIT_TX | \ + HFI1_S_WAIT_DMA_DESC | HFI1_S_WAIT_KMEM) + +/* + * Wait flags that would prevent send work requests from making progress. + */ +#define HFI1_S_ANY_WAIT_SEND (HFI1_S_WAIT_FENCE | HFI1_S_WAIT_RDMAR | \ + HFI1_S_WAIT_RNR | HFI1_S_WAIT_SSN_CREDIT | HFI1_S_WAIT_DMA | \ + HFI1_S_WAIT_PSN | HFI1_S_WAIT_ACK) + +#define HFI1_S_ANY_WAIT (HFI1_S_ANY_WAIT_IO | HFI1_S_ANY_WAIT_SEND) + +#define HFI1_PSN_CREDIT 16 + +/* + * Since struct hfi1_swqe is not a fixed size, we can't simply index into + * struct hfi1_qp.s_wq. This function does the array index computation. + */ +static inline struct hfi1_swqe *get_swqe_ptr(struct hfi1_qp *qp, + unsigned n) +{ + return (struct hfi1_swqe *)((char *)qp->s_wq + + (sizeof(struct hfi1_swqe) + + qp->s_max_sge * + sizeof(struct hfi1_sge)) * n); +} + +/* + * Since struct hfi1_rwqe is not a fixed size, we can't simply index into + * struct hfi1_rwq.wq. This function does the array index computation. + */ +static inline struct hfi1_rwqe *get_rwqe_ptr(struct hfi1_rq *rq, unsigned n) +{ + return (struct hfi1_rwqe *) + ((char *) rq->wq->wq + + (sizeof(struct hfi1_rwqe) + + rq->max_sge * sizeof(struct ib_sge)) * n); +} + +#define MAX_LKEY_TABLE_BITS 23 + +struct hfi1_lkey_table { + spinlock_t lock; /* protect changes in this struct */ + u32 next; /* next unused index (speeds search) */ + u32 gen; /* generation count */ + u32 max; /* size of the table */ + struct hfi1_mregion __rcu **table; +}; + +struct hfi1_opcode_stats { + u64 n_packets; /* number of packets */ + u64 n_bytes; /* total number of bytes */ +}; + +struct hfi1_opcode_stats_perctx { + struct hfi1_opcode_stats stats[256]; +}; + +static inline void inc_opstats( + u32 tlen, + struct hfi1_opcode_stats *stats) +{ +#ifdef CONFIG_DEBUG_FS + stats->n_bytes += tlen; + stats->n_packets++; +#endif +} + +struct hfi1_ibport { + struct hfi1_qp __rcu *qp[2]; + struct ib_mad_agent *send_agent; /* agent for SMI (traps) */ + struct hfi1_ah *sm_ah; + struct hfi1_ah *smi_ah; + struct rb_root mcast_tree; + spinlock_t lock; /* protect changes in this struct */ + + /* non-zero when timer is set */ + unsigned long mkey_lease_timeout; + unsigned long trap_timeout; + __be64 gid_prefix; /* in network order */ + __be64 mkey; + __be64 guids[HFI1_GUIDS_PER_PORT - 1]; /* writable GUIDs */ + u64 tid; /* TID for traps */ + u64 n_rc_resends; + u64 n_seq_naks; + u64 n_rdma_seq; + u64 n_rnr_naks; + u64 n_other_naks; + u64 n_loop_pkts; + u64 n_pkt_drops; + u64 n_vl15_dropped; + u64 n_rc_timeouts; + u64 n_dmawait; + u64 n_unaligned; + u64 n_rc_dupreq; + u64 n_rc_seqnak; + + /* Hot-path per CPU counters to avoid cacheline trading to update */ + u64 z_rc_acks; + u64 z_rc_qacks; + u64 z_rc_delayed_comp; + u64 __percpu *rc_acks; + u64 __percpu *rc_qacks; + u64 __percpu *rc_delayed_comp; + + u32 port_cap_flags; + u32 pma_sample_start; + u32 pma_sample_interval; + __be16 pma_counter_select[5]; + u16 pma_tag; + u16 pkey_violations; + u16 qkey_violations; + u16 mkey_violations; + u16 mkey_lease_period; + u16 sm_lid; + u16 repress_traps; + u8 sm_sl; + u8 mkeyprot; + u8 subnet_timeout; + u8 vl_high_limit; + /* the first 16 entries are sl_to_vl for !OPA */ + u8 sl_to_sc[32]; + u8 sc_to_sl[32]; +}; + + +struct hfi1_qp_ibdev; +struct hfi1_ibdev { + struct ib_device ibdev; + struct list_head pending_mmaps; + spinlock_t mmap_offset_lock; /* protect mmap_offset */ + u32 mmap_offset; + struct hfi1_mregion __rcu *dma_mr; + + struct hfi1_qp_ibdev *qp_dev; + + /* QP numbers are shared by all IB ports */ + struct hfi1_lkey_table lk_table; + /* protect wait lists */ + seqlock_t iowait_lock; + struct list_head txwait; /* list for wait verbs_txreq */ + struct list_head memwait; /* list for wait kernel memory */ + struct list_head txreq_free; + struct kmem_cache *verbs_txreq_cache; + struct timer_list mem_timer; + + /* other waiters */ + spinlock_t pending_lock; + + u64 n_piowait; + u64 n_txwait; + u64 n_kmem_wait; + + u32 n_pds_allocated; /* number of PDs allocated for device */ + spinlock_t n_pds_lock; + u32 n_ahs_allocated; /* number of AHs allocated for device */ + spinlock_t n_ahs_lock; + u32 n_cqs_allocated; /* number of CQs allocated for device */ + spinlock_t n_cqs_lock; + u32 n_qps_allocated; /* number of QPs allocated for device */ + spinlock_t n_qps_lock; + u32 n_srqs_allocated; /* number of SRQs allocated for device */ + spinlock_t n_srqs_lock; + u32 n_mcast_grps_allocated; /* number of mcast groups allocated */ + spinlock_t n_mcast_grps_lock; +#ifdef CONFIG_DEBUG_FS + /* per HFI debugfs */ + struct dentry *hfi1_ibdev_dbg; + /* per HFI symlinks to above */ + struct dentry *hfi1_ibdev_link; +#endif +}; + +struct hfi1_verbs_counters { + u64 symbol_error_counter; + u64 link_error_recovery_counter; + u64 link_downed_counter; + u64 port_rcv_errors; + u64 port_rcv_remphys_errors; + u64 port_xmit_discards; + u64 port_xmit_data; + u64 port_rcv_data; + u64 port_xmit_packets; + u64 port_rcv_packets; + u32 local_link_integrity_errors; + u32 excessive_buffer_overrun_errors; + u32 vl15_dropped; +}; + +static inline struct hfi1_mr *to_imr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct hfi1_mr, ibmr); +} + +static inline struct hfi1_pd *to_ipd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct hfi1_pd, ibpd); +} + +static inline struct hfi1_ah *to_iah(struct ib_ah *ibah) +{ + return container_of(ibah, struct hfi1_ah, ibah); +} + +static inline struct hfi1_cq *to_icq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct hfi1_cq, ibcq); +} + +static inline struct hfi1_srq *to_isrq(struct ib_srq *ibsrq) +{ + return container_of(ibsrq, struct hfi1_srq, ibsrq); +} + +static inline struct hfi1_qp *to_iqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct hfi1_qp, ibqp); +} + +static inline struct hfi1_ibdev *to_idev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct hfi1_ibdev, ibdev); +} + +/* + * Send if not busy or waiting for I/O and either + * a RC response is pending or we can process send work requests. + */ +static inline int hfi1_send_ok(struct hfi1_qp *qp) +{ + return !(qp->s_flags & (HFI1_S_BUSY | HFI1_S_ANY_WAIT_IO)) && + (qp->s_hdrwords || (qp->s_flags & HFI1_S_RESP_PENDING) || + !(qp->s_flags & HFI1_S_ANY_WAIT_SEND)); +} + +/* + * This must be called with s_lock held. + */ +void hfi1_schedule_send(struct hfi1_qp *qp); +void hfi1_bad_pqkey(struct hfi1_ibport *ibp, __be16 trap_num, u32 key, u32 sl, + u32 qp1, u32 qp2, __be16 lid1, __be16 lid2); +void hfi1_cap_mask_chg(struct hfi1_ibport *ibp); +void hfi1_sys_guid_chg(struct hfi1_ibport *ibp); +void hfi1_node_desc_chg(struct hfi1_ibport *ibp); +int hfi1_process_mad(struct ib_device *ibdev, int mad_flags, u8 port, + const struct ib_wc *in_wc, const struct ib_grh *in_grh, + const struct ib_mad_hdr *in_mad, size_t in_mad_size, + struct ib_mad_hdr *out_mad, size_t *out_mad_size, + u16 *out_mad_pkey_index); +int hfi1_create_agents(struct hfi1_ibdev *dev); +void hfi1_free_agents(struct hfi1_ibdev *dev); + +/* + * The PSN_MASK and PSN_SHIFT allow for + * 1) comparing two PSNs + * 2) returning the PSN with any upper bits masked + * 3) returning the difference between to PSNs + * + * The number of significant bits in the PSN must + * necessarily be at least one bit less than + * the container holding the PSN. + */ +#ifndef CONFIG_HFI1_VERBS_31BIT_PSN +#define PSN_MASK 0xFFFFFF +#define PSN_SHIFT 8 +#else +#define PSN_MASK 0x7FFFFFFF +#define PSN_SHIFT 1 +#endif +#define PSN_MODIFY_MASK 0xFFFFFF + +/* Number of bits to pay attention to in the opcode for checking qp type */ +#define OPCODE_QP_MASK 0xE0 + +/* + * Compare the lower 24 bits of the msn values. + * Returns an integer <, ==, or > than zero. + */ +static inline int cmp_msn(u32 a, u32 b) +{ + return (((int) a) - ((int) b)) << 8; +} + +/* + * Compare two PSNs + * Returns an integer <, ==, or > than zero. + */ +static inline int cmp_psn(u32 a, u32 b) +{ + return (((int) a) - ((int) b)) << PSN_SHIFT; +} + +/* + * Return masked PSN + */ +static inline u32 mask_psn(u32 a) +{ + return a & PSN_MASK; +} + +/* + * Return delta between two PSNs + */ +static inline u32 delta_psn(u32 a, u32 b) +{ + return (((int)a - (int)b) << PSN_SHIFT) >> PSN_SHIFT; +} + +struct hfi1_mcast *hfi1_mcast_find(struct hfi1_ibport *ibp, union ib_gid *mgid); + +int hfi1_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); + +int hfi1_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid); + +int hfi1_mcast_tree_empty(struct hfi1_ibport *ibp); + +struct verbs_txreq; +void hfi1_put_txreq(struct verbs_txreq *tx); + +int hfi1_verbs_send(struct hfi1_qp *qp, struct ahg_ib_header *ahdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len); + +void hfi1_copy_sge(struct hfi1_sge_state *ss, void *data, u32 length, + int release); + +void hfi1_skip_sge(struct hfi1_sge_state *ss, u32 length, int release); + +void hfi1_cnp_rcv(struct hfi1_packet *packet); + +void hfi1_uc_rcv(struct hfi1_packet *packet); + +void hfi1_rc_rcv(struct hfi1_packet *packet); + +void hfi1_rc_hdrerr( + struct hfi1_ctxtdata *rcd, + struct hfi1_ib_header *hdr, + u32 rcv_flags, + struct hfi1_qp *qp); + +u8 ah_to_sc(struct ib_device *ibdev, struct ib_ah_attr *ah_attr); + +int hfi1_check_ah(struct ib_device *ibdev, struct ib_ah_attr *ah_attr); + +struct ib_ah *hfi1_create_qp0_ah(struct hfi1_ibport *ibp, u16 dlid); + +void hfi1_rc_rnr_retry(unsigned long arg); + +void hfi1_rc_send_complete(struct hfi1_qp *qp, struct hfi1_ib_header *hdr); + +void hfi1_rc_error(struct hfi1_qp *qp, enum ib_wc_status err); + +void hfi1_ud_rcv(struct hfi1_packet *packet); + +int hfi1_lookup_pkey_idx(struct hfi1_ibport *ibp, u16 pkey); + +int hfi1_alloc_lkey(struct hfi1_mregion *mr, int dma_region); + +void hfi1_free_lkey(struct hfi1_mregion *mr); + +int hfi1_lkey_ok(struct hfi1_lkey_table *rkt, struct hfi1_pd *pd, + struct hfi1_sge *isge, struct ib_sge *sge, int acc); + +int hfi1_rkey_ok(struct hfi1_qp *qp, struct hfi1_sge *sge, + u32 len, u64 vaddr, u32 rkey, int acc); + +int hfi1_post_srq_receive(struct ib_srq *ibsrq, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); + +struct ib_srq *hfi1_create_srq(struct ib_pd *ibpd, + struct ib_srq_init_attr *srq_init_attr, + struct ib_udata *udata); + +int hfi1_modify_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr, + enum ib_srq_attr_mask attr_mask, + struct ib_udata *udata); + +int hfi1_query_srq(struct ib_srq *ibsrq, struct ib_srq_attr *attr); + +int hfi1_destroy_srq(struct ib_srq *ibsrq); + +int hfi1_cq_init(struct hfi1_devdata *dd); + +void hfi1_cq_exit(struct hfi1_devdata *dd); + +void hfi1_cq_enter(struct hfi1_cq *cq, struct ib_wc *entry, int sig); + +int hfi1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry); + +struct ib_cq *hfi1_create_cq( + struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *context, + struct ib_udata *udata); + +int hfi1_destroy_cq(struct ib_cq *ibcq); + +int hfi1_req_notify_cq( + struct ib_cq *ibcq, + enum ib_cq_notify_flags notify_flags); + +int hfi1_resize_cq(struct ib_cq *ibcq, int cqe, struct ib_udata *udata); + +struct ib_mr *hfi1_get_dma_mr(struct ib_pd *pd, int acc); + +struct ib_mr *hfi1_reg_phys_mr(struct ib_pd *pd, + struct ib_phys_buf *buffer_list, + int num_phys_buf, int acc, u64 *iova_start); + +struct ib_mr *hfi1_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int mr_access_flags, + struct ib_udata *udata); + +int hfi1_dereg_mr(struct ib_mr *ibmr); + +struct ib_mr *hfi1_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); + +struct ib_fast_reg_page_list *hfi1_alloc_fast_reg_page_list( + struct ib_device *ibdev, int page_list_len); + +void hfi1_free_fast_reg_page_list(struct ib_fast_reg_page_list *pl); + +int hfi1_fast_reg_mr(struct hfi1_qp *qp, struct ib_send_wr *wr); + +struct ib_fmr *hfi1_alloc_fmr(struct ib_pd *pd, int mr_access_flags, + struct ib_fmr_attr *fmr_attr); + +int hfi1_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, + int list_len, u64 iova); + +int hfi1_unmap_fmr(struct list_head *fmr_list); + +int hfi1_dealloc_fmr(struct ib_fmr *ibfmr); + +static inline void hfi1_get_mr(struct hfi1_mregion *mr) +{ + atomic_inc(&mr->refcount); +} + +static inline void hfi1_put_mr(struct hfi1_mregion *mr) +{ + if (unlikely(atomic_dec_and_test(&mr->refcount))) + complete(&mr->comp); +} + +static inline void hfi1_put_ss(struct hfi1_sge_state *ss) +{ + while (ss->num_sge) { + hfi1_put_mr(ss->sge.mr); + if (--ss->num_sge) + ss->sge = *ss->sg_list++; + } +} + +void hfi1_release_mmap_info(struct kref *ref); + +struct hfi1_mmap_info *hfi1_create_mmap_info(struct hfi1_ibdev *dev, u32 size, + struct ib_ucontext *context, + void *obj); + +void hfi1_update_mmap_info(struct hfi1_ibdev *dev, struct hfi1_mmap_info *ip, + u32 size, void *obj); + +int hfi1_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); + +int hfi1_get_rwqe(struct hfi1_qp *qp, int wr_id_only); + +void hfi1_migrate_qp(struct hfi1_qp *qp); + +int hfi1_ruc_check_hdr(struct hfi1_ibport *ibp, struct hfi1_ib_header *hdr, + int has_grh, struct hfi1_qp *qp, u32 bth0); + +u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr, + struct ib_global_route *grh, u32 hwords, u32 nwords); + +void clear_ahg(struct hfi1_qp *qp); + +void hfi1_make_ruc_header(struct hfi1_qp *qp, struct hfi1_other_headers *ohdr, + u32 bth0, u32 bth2, int middle); + +void hfi1_do_send(struct work_struct *work); + +void hfi1_send_complete(struct hfi1_qp *qp, struct hfi1_swqe *wqe, + enum ib_wc_status status); + +void hfi1_send_rc_ack(struct hfi1_ctxtdata *, struct hfi1_qp *qp, int is_fecn); + +int hfi1_make_rc_req(struct hfi1_qp *qp); + +int hfi1_make_uc_req(struct hfi1_qp *qp); + +int hfi1_make_ud_req(struct hfi1_qp *qp); + +int hfi1_register_ib_device(struct hfi1_devdata *); + +void hfi1_unregister_ib_device(struct hfi1_devdata *); + +void hfi1_ib_rcv(struct hfi1_packet *packet); + +unsigned hfi1_get_npkeys(struct hfi1_devdata *); + +int hfi1_verbs_send_dma(struct hfi1_qp *qp, struct ahg_ib_header *hdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc); + +int hfi1_verbs_send_pio(struct hfi1_qp *qp, struct ahg_ib_header *hdr, + u32 hdrwords, struct hfi1_sge_state *ss, u32 len, + u32 plen, u32 dwords, u64 pbc); + +struct send_context *qp_to_send_context(struct hfi1_qp *qp, u8 sc5); + +extern const enum ib_wc_opcode ib_hfi1_wc_opcode[]; + +extern const u8 hdr_len_by_opcode[]; + +extern const int ib_hfi1_state_ops[]; + +extern __be64 ib_hfi1_sys_image_guid; /* in network order */ + +extern unsigned int hfi1_lkey_table_size; + +extern unsigned int hfi1_max_cqes; + +extern unsigned int hfi1_max_cqs; + +extern unsigned int hfi1_max_qp_wrs; + +extern unsigned int hfi1_max_qps; + +extern unsigned int hfi1_max_sges; + +extern unsigned int hfi1_max_mcast_grps; + +extern unsigned int hfi1_max_mcast_qp_attached; + +extern unsigned int hfi1_max_srqs; + +extern unsigned int hfi1_max_srq_sges; + +extern unsigned int hfi1_max_srq_wrs; + +extern const u32 ib_hfi1_rnr_table[]; + +extern struct ib_dma_mapping_ops hfi1_dma_mapping_ops; + +#endif /* HFI1_VERBS_H */ diff --git a/drivers/staging/rdma/hfi1/verbs_mcast.c b/drivers/staging/rdma/hfi1/verbs_mcast.c new file mode 100644 index 0000000000000..afc6b4c61a1d3 --- /dev/null +++ b/drivers/staging/rdma/hfi1/verbs_mcast.c @@ -0,0 +1,385 @@ +/* + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * Copyright(c) 2015 Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Copyright(c) 2015 Intel Corporation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "hfi.h" + +/** + * mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct + * @qp: the QP to link + */ +static struct hfi1_mcast_qp *mcast_qp_alloc(struct hfi1_qp *qp) +{ + struct hfi1_mcast_qp *mqp; + + mqp = kmalloc(sizeof(*mqp), GFP_KERNEL); + if (!mqp) + goto bail; + + mqp->qp = qp; + atomic_inc(&qp->refcount); + +bail: + return mqp; +} + +static void mcast_qp_free(struct hfi1_mcast_qp *mqp) +{ + struct hfi1_qp *qp = mqp->qp; + + /* Notify hfi1_destroy_qp() if it is waiting. */ + if (atomic_dec_and_test(&qp->refcount)) + wake_up(&qp->wait); + + kfree(mqp); +} + +/** + * mcast_alloc - allocate the multicast GID structure + * @mgid: the multicast GID + * + * A list of QPs will be attached to this structure. + */ +static struct hfi1_mcast *mcast_alloc(union ib_gid *mgid) +{ + struct hfi1_mcast *mcast; + + mcast = kmalloc(sizeof(*mcast), GFP_KERNEL); + if (!mcast) + goto bail; + + mcast->mgid = *mgid; + INIT_LIST_HEAD(&mcast->qp_list); + init_waitqueue_head(&mcast->wait); + atomic_set(&mcast->refcount, 0); + mcast->n_attached = 0; + +bail: + return mcast; +} + +static void mcast_free(struct hfi1_mcast *mcast) +{ + struct hfi1_mcast_qp *p, *tmp; + + list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) + mcast_qp_free(p); + + kfree(mcast); +} + +/** + * hfi1_mcast_find - search the global table for the given multicast GID + * @ibp: the IB port structure + * @mgid: the multicast GID to search for + * + * Returns NULL if not found. + * + * The caller is responsible for decrementing the reference count if found. + */ +struct hfi1_mcast *hfi1_mcast_find(struct hfi1_ibport *ibp, union ib_gid *mgid) +{ + struct rb_node *n; + unsigned long flags; + struct hfi1_mcast *mcast; + + spin_lock_irqsave(&ibp->lock, flags); + n = ibp->mcast_tree.rb_node; + while (n) { + int ret; + + mcast = rb_entry(n, struct hfi1_mcast, rb_node); + + ret = memcmp(mgid->raw, mcast->mgid.raw, + sizeof(union ib_gid)); + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else { + atomic_inc(&mcast->refcount); + spin_unlock_irqrestore(&ibp->lock, flags); + goto bail; + } + } + spin_unlock_irqrestore(&ibp->lock, flags); + + mcast = NULL; + +bail: + return mcast; +} + +/** + * mcast_add - insert mcast GID into table and attach QP struct + * @mcast: the mcast GID table + * @mqp: the QP to attach + * + * Return zero if both were added. Return EEXIST if the GID was already in + * the table but the QP was added. Return ESRCH if the QP was already + * attached and neither structure was added. + */ +static int mcast_add(struct hfi1_ibdev *dev, struct hfi1_ibport *ibp, + struct hfi1_mcast *mcast, struct hfi1_mcast_qp *mqp) +{ + struct rb_node **n = &ibp->mcast_tree.rb_node; + struct rb_node *pn = NULL; + int ret; + + spin_lock_irq(&ibp->lock); + + while (*n) { + struct hfi1_mcast *tmcast; + struct hfi1_mcast_qp *p; + + pn = *n; + tmcast = rb_entry(pn, struct hfi1_mcast, rb_node); + + ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw, + sizeof(union ib_gid)); + if (ret < 0) { + n = &pn->rb_left; + continue; + } + if (ret > 0) { + n = &pn->rb_right; + continue; + } + + /* Search the QP list to see if this is already there. */ + list_for_each_entry_rcu(p, &tmcast->qp_list, list) { + if (p->qp == mqp->qp) { + ret = ESRCH; + goto bail; + } + } + if (tmcast->n_attached == hfi1_max_mcast_qp_attached) { + ret = ENOMEM; + goto bail; + } + + tmcast->n_attached++; + + list_add_tail_rcu(&mqp->list, &tmcast->qp_list); + ret = EEXIST; + goto bail; + } + + spin_lock(&dev->n_mcast_grps_lock); + if (dev->n_mcast_grps_allocated == hfi1_max_mcast_grps) { + spin_unlock(&dev->n_mcast_grps_lock); + ret = ENOMEM; + goto bail; + } + + dev->n_mcast_grps_allocated++; + spin_unlock(&dev->n_mcast_grps_lock); + + mcast->n_attached++; + + list_add_tail_rcu(&mqp->list, &mcast->qp_list); + + atomic_inc(&mcast->refcount); + rb_link_node(&mcast->rb_node, pn, n); + rb_insert_color(&mcast->rb_node, &ibp->mcast_tree); + + ret = 0; + +bail: + spin_unlock_irq(&ibp->lock); + + return ret; +} + +int hfi1_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct hfi1_qp *qp = to_iqp(ibqp); + struct hfi1_ibdev *dev = to_idev(ibqp->device); + struct hfi1_ibport *ibp; + struct hfi1_mcast *mcast; + struct hfi1_mcast_qp *mqp; + int ret; + + if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) { + ret = -EINVAL; + goto bail; + } + + /* + * Allocate data structures since its better to do this outside of + * spin locks and it will most likely be needed. + */ + mcast = mcast_alloc(gid); + if (mcast == NULL) { + ret = -ENOMEM; + goto bail; + } + mqp = mcast_qp_alloc(qp); + if (mqp == NULL) { + mcast_free(mcast); + ret = -ENOMEM; + goto bail; + } + ibp = to_iport(ibqp->device, qp->port_num); + switch (mcast_add(dev, ibp, mcast, mqp)) { + case ESRCH: + /* Neither was used: OK to attach the same QP twice. */ + mcast_qp_free(mqp); + mcast_free(mcast); + break; + + case EEXIST: /* The mcast wasn't used */ + mcast_free(mcast); + break; + + case ENOMEM: + /* Exceeded the maximum number of mcast groups. */ + mcast_qp_free(mqp); + mcast_free(mcast); + ret = -ENOMEM; + goto bail; + + default: + break; + } + + ret = 0; + +bail: + return ret; +} + +int hfi1_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) +{ + struct hfi1_qp *qp = to_iqp(ibqp); + struct hfi1_ibdev *dev = to_idev(ibqp->device); + struct hfi1_ibport *ibp = to_iport(ibqp->device, qp->port_num); + struct hfi1_mcast *mcast = NULL; + struct hfi1_mcast_qp *p, *tmp; + struct rb_node *n; + int last = 0; + int ret; + + if (ibqp->qp_num <= 1 || qp->state == IB_QPS_RESET) { + ret = -EINVAL; + goto bail; + } + + spin_lock_irq(&ibp->lock); + + /* Find the GID in the mcast table. */ + n = ibp->mcast_tree.rb_node; + while (1) { + if (n == NULL) { + spin_unlock_irq(&ibp->lock); + ret = -EINVAL; + goto bail; + } + + mcast = rb_entry(n, struct hfi1_mcast, rb_node); + ret = memcmp(gid->raw, mcast->mgid.raw, + sizeof(union ib_gid)); + if (ret < 0) + n = n->rb_left; + else if (ret > 0) + n = n->rb_right; + else + break; + } + + /* Search the QP list. */ + list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) { + if (p->qp != qp) + continue; + /* + * We found it, so remove it, but don't poison the forward + * link until we are sure there are no list walkers. + */ + list_del_rcu(&p->list); + mcast->n_attached--; + + /* If this was the last attached QP, remove the GID too. */ + if (list_empty(&mcast->qp_list)) { + rb_erase(&mcast->rb_node, &ibp->mcast_tree); + last = 1; + } + break; + } + + spin_unlock_irq(&ibp->lock); + + if (p) { + /* + * Wait for any list walkers to finish before freeing the + * list element. + */ + wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); + mcast_qp_free(p); + } + if (last) { + atomic_dec(&mcast->refcount); + wait_event(mcast->wait, !atomic_read(&mcast->refcount)); + mcast_free(mcast); + spin_lock_irq(&dev->n_mcast_grps_lock); + dev->n_mcast_grps_allocated--; + spin_unlock_irq(&dev->n_mcast_grps_lock); + } + + ret = 0; + +bail: + return ret; +} + +int hfi1_mcast_tree_empty(struct hfi1_ibport *ibp) +{ + return ibp->mcast_tree.rb_node == NULL; +} -- GitLab From a724648e8a8f7ff874f0d58491b39517718c7237 Mon Sep 17 00:00:00 2001 From: Jeff Becker Date: Fri, 21 Aug 2015 12:26:22 -0700 Subject: [PATCH 5683/7006] staging/hfi1: replace indent spaces with tabs Running checkpatch.pl on mad.c produces several "ERROR: code indent should use tabs where possible" messages. This patch fixes these. Signed-off-by: Jeff Becker Signed-off-by: Doug Ledford --- drivers/staging/rdma/hfi1/mad.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/staging/rdma/hfi1/mad.c b/drivers/staging/rdma/hfi1/mad.c index 0a18fee464323..37269eb90c346 100644 --- a/drivers/staging/rdma/hfi1/mad.c +++ b/drivers/staging/rdma/hfi1/mad.c @@ -4075,11 +4075,11 @@ bail: } static int hfi1_process_opa_mad(struct ib_device *ibdev, int mad_flags, - u8 port, const struct ib_wc *in_wc, - const struct ib_grh *in_grh, - const struct opa_mad *in_mad, - struct opa_mad *out_mad, size_t *out_mad_size, - u16 *out_mad_pkey_index) + u8 port, const struct ib_wc *in_wc, + const struct ib_grh *in_grh, + const struct opa_mad *in_mad, + struct opa_mad *out_mad, size_t *out_mad_size, + u16 *out_mad_pkey_index) { int ret; int pkey_idx; -- GitLab From 18ebd40773bf500054a5e079e71cd13aafd1b6eb Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 27 Jul 2015 18:10:01 -0500 Subject: [PATCH 5684/7006] mlx4, mlx5, mthca: Expose max_sge_rd correctly Applications must not assume that max_sge and max_sge_rd are the same, Hence expose max_sge_rd correctly as well. Reported-by: Steve Wise Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 1 + drivers/infiniband/hw/mlx5/main.c | 1 + drivers/infiniband/hw/mthca/mthca_provider.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 8be6db8164604..05166b7d8ca70 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -229,6 +229,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->max_qp_wr = dev->dev->caps.max_wqes - MLX4_IB_SQ_MAX_SPARE; props->max_sge = min(dev->dev->caps.max_sq_sg, dev->dev->caps.max_rq_sg); + props->max_sge_rd = props->max_sge; props->max_cq = dev->dev->quotas.cq; props->max_cqe = dev->dev->caps.max_cqes; props->max_mr = dev->dev->quotas.mpt; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 1ece3a7debd59..bac5f98965d0a 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -274,6 +274,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, sizeof(struct mlx5_wqe_ctrl_seg)) / sizeof(struct mlx5_wqe_data_seg); props->max_sge = min(max_rq_sg, max_sq_sg); + props->max_sge_rd = props->max_sge; props->max_cq = 1 << MLX5_CAP_GEN(mdev, log_max_cq); props->max_cqe = (1 << MLX5_CAP_GEN(mdev, log_max_eq_sz)) - 1; props->max_mr = 1 << MLX5_CAP_GEN(mdev, log_max_mkey); diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 93ae51dcf2ffa..dc2d48c59e627 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -97,6 +97,7 @@ static int mthca_query_device(struct ib_device *ibdev, struct ib_device_attr *pr props->max_qp = mdev->limits.num_qps - mdev->limits.reserved_qps; props->max_qp_wr = mdev->limits.max_wqes; props->max_sge = mdev->limits.max_sg; + props->max_sge_rd = props->max_sge; props->max_cq = mdev->limits.num_cqs - mdev->limits.reserved_cqs; props->max_cqe = mdev->limits.max_cqes; props->max_mr = mdev->limits.num_mpts - mdev->limits.reserved_mrws; -- GitLab From aaae91f4f05c39f02e36e89b00ad84465f8eb02b Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 27 Jul 2015 18:10:07 -0500 Subject: [PATCH 5685/7006] ipath,qib: Expose max_sge_rd correctly Applications must not assume that max_sge and max_sge_rd are the same, Hence expose max_sge_rd correctly as well. Signed-off-by: Steve Wise Acked-by: Mike Marciniszyn Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_verbs.c | 1 + drivers/staging/rdma/ipath/ipath_verbs.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 77e981abfce47..bc0599ca140a1 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -1575,6 +1575,7 @@ static int qib_query_device(struct ib_device *ibdev, struct ib_device_attr *prop props->max_qp = ib_qib_max_qps; props->max_qp_wr = ib_qib_max_qp_wrs; props->max_sge = ib_qib_max_sges; + props->max_sge_rd = ib_qib_max_sges; props->max_cq = ib_qib_max_cqs; props->max_ah = ib_qib_max_ahs; props->max_cqe = ib_qib_max_cqes; diff --git a/drivers/staging/rdma/ipath/ipath_verbs.c b/drivers/staging/rdma/ipath/ipath_verbs.c index 30ba49c4a98c0..ed2bbc2f7eaeb 100644 --- a/drivers/staging/rdma/ipath/ipath_verbs.c +++ b/drivers/staging/rdma/ipath/ipath_verbs.c @@ -1521,6 +1521,7 @@ static int ipath_query_device(struct ib_device *ibdev, struct ib_device_attr *pr props->max_qp = ib_ipath_max_qps; props->max_qp_wr = ib_ipath_max_qp_wrs; props->max_sge = ib_ipath_max_sges; + props->max_sge_rd = ib_ipath_max_sges; props->max_cq = ib_ipath_max_cqs; props->max_ah = ib_ipath_max_ahs; props->max_cqe = ib_ipath_max_cqes; -- GitLab From bc3fe2e3769874dfa8674791e84c4a901ba9e48b Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 27 Jul 2015 18:10:12 -0500 Subject: [PATCH 5686/7006] svcrdma: Use max_sge_rd for destination read depths Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- include/linux/sunrpc/svc_rdma.h | 1 + net/sunrpc/xprtrdma/svc_rdma_recvfrom.c | 12 +----------- net/sunrpc/xprtrdma/svc_rdma_transport.c | 4 ++++ 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/include/linux/sunrpc/svc_rdma.h b/include/linux/sunrpc/svc_rdma.h index cb94ee4181d49..83211bc9219e4 100644 --- a/include/linux/sunrpc/svc_rdma.h +++ b/include/linux/sunrpc/svc_rdma.h @@ -132,6 +132,7 @@ struct svcxprt_rdma { struct list_head sc_accept_q; /* Conn. waiting accept */ int sc_ord; /* RDMA read limit */ int sc_max_sge; + int sc_max_sge_rd; /* max sge for read target */ int sc_sq_depth; /* Depth of SQ */ atomic_t sc_sq_count; /* Number of SQ WR on queue */ diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index 2e1348bde325d..cb51742840740 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -115,15 +115,6 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp, rqstp->rq_arg.tail[0].iov_len = 0; } -static int rdma_read_max_sge(struct svcxprt_rdma *xprt, int sge_count) -{ - if (!rdma_cap_read_multi_sge(xprt->sc_cm_id->device, - xprt->sc_cm_id->port_num)) - return 1; - else - return min_t(int, sge_count, xprt->sc_max_sge); -} - /* Issue an RDMA_READ using the local lkey to map the data sink */ int rdma_read_chunk_lcl(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp, @@ -144,8 +135,7 @@ int rdma_read_chunk_lcl(struct svcxprt_rdma *xprt, ctxt->direction = DMA_FROM_DEVICE; ctxt->read_hdr = head; - pages_needed = - min_t(int, pages_needed, rdma_read_max_sge(xprt, pages_needed)); + pages_needed = min_t(int, pages_needed, xprt->sc_max_sge_rd); read = min_t(int, pages_needed << PAGE_SHIFT, rs_length); for (pno = 0; pno < pages_needed; pno++) { diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 6b36279e42885..fdc850ffc26c4 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -872,6 +872,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) * capabilities of this particular device */ newxprt->sc_max_sge = min((size_t)devattr.max_sge, (size_t)RPCSVC_MAXPAGES); + newxprt->sc_max_sge_rd = min_t(size_t, devattr.max_sge_rd, + RPCSVC_MAXPAGES); newxprt->sc_max_requests = min((size_t)devattr.max_qp_wr, (size_t)svcrdma_max_requests); newxprt->sc_sq_depth = RPCRDMA_SQ_DEPTH_MULT * newxprt->sc_max_requests; @@ -1046,6 +1048,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) " remote_ip : %pI4\n" " remote_port : %d\n" " max_sge : %d\n" + " max_sge_rd : %d\n" " sq_depth : %d\n" " max_requests : %d\n" " ord : %d\n", @@ -1059,6 +1062,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id-> route.addr.dst_addr)->sin_port), newxprt->sc_max_sge, + newxprt->sc_max_sge_rd, newxprt->sc_sq_depth, newxprt->sc_max_requests, newxprt->sc_ord); -- GitLab From 3403051ebbd486a342272a404f16e7f1aca8758e Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Mon, 27 Jul 2015 18:10:18 -0500 Subject: [PATCH 5687/7006] RDMA/Core: remove rdma_cap_read_multi_sge() helper This functionality already exists via the max_sge_rd device capability. Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- include/rdma/ib_verbs.h | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index b0f898e3b2e73..7448a2740287c 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2070,34 +2070,6 @@ static inline bool rdma_cap_eth_ah(const struct ib_device *device, u8 port_num) return device->port_immutable[port_num].core_cap_flags & RDMA_CORE_CAP_ETH_AH; } -/** - * rdma_cap_read_multi_sge - Check if the port of device has the capability - * RDMA Read Multiple Scatter-Gather Entries. - * @device: Device to check - * @port_num: Port number to check - * - * iWARP has a restriction that RDMA READ requests may only have a single - * Scatter/Gather Entry (SGE) in the work request. - * - * NOTE: although the linux kernel currently assumes all devices are either - * single SGE RDMA READ devices or identical SGE maximums for RDMA READs and - * WRITEs, according to Tom Talpey, this is not accurate. There are some - * devices out there that support more than a single SGE on RDMA READ - * requests, but do not support the same number of SGEs as they do on - * RDMA WRITE requests. The linux kernel would need rearchitecting to - * support these imbalanced READ/WRITE SGEs allowed devices. So, for now, - * suffice with either the device supports the same READ/WRITE SGEs, or - * it only gets one READ sge. - * - * Return: true for any device that allows more than one SGE in RDMA READ - * requests. - */ -static inline bool rdma_cap_read_multi_sge(struct ib_device *device, - u8 port_num) -{ - return !(device->port_immutable[port_num].core_cap_flags & RDMA_CORE_CAP_PROT_IWARP); -} - /** * rdma_max_mad_size - Return the max MAD size required by this RDMA Port. * -- GitLab From e1455744b27c9e6115c3508a7b2902157c2c4347 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 30 Jul 2015 17:57:47 -0400 Subject: [PATCH 5688/7006] libnvdimm, pfn: 'struct page' provider infrastructure Implement the base infrastructure for libnvdimm PFN devices. Similar to BTT devices they take a namespace as a backing device and layer functionality on top. In this case the functionality is reserving space for an array of 'struct page' entries to be handed out through pfn_to_page(). For now this is just the basic libnvdimm-device-model for configuring the base PFN device. As the namespace claiming mechanism for PFN devices is mostly identical to BTT devices drivers/nvdimm/claim.c is created to house the common bits. Cc: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/Kconfig | 22 +++ drivers/nvdimm/Makefile | 2 + drivers/nvdimm/btt.c | 6 +- drivers/nvdimm/btt_devs.c | 172 +--------------- drivers/nvdimm/claim.c | 201 +++++++++++++++++++ drivers/nvdimm/namespace_devs.c | 34 +++- drivers/nvdimm/nd-core.h | 9 + drivers/nvdimm/nd.h | 56 +++++- drivers/nvdimm/pfn.h | 35 ++++ drivers/nvdimm/pfn_devs.c | 336 ++++++++++++++++++++++++++++++++ drivers/nvdimm/region.c | 2 + drivers/nvdimm/region_devs.c | 19 ++ tools/testing/nvdimm/Kbuild | 2 + 13 files changed, 719 insertions(+), 177 deletions(-) create mode 100644 drivers/nvdimm/claim.c create mode 100644 drivers/nvdimm/pfn.h create mode 100644 drivers/nvdimm/pfn_devs.c diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index 72226acb5c0fb..ace25b53b7556 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -21,6 +21,7 @@ config BLK_DEV_PMEM default LIBNVDIMM depends on HAS_IOMEM select ND_BTT if BTT + select ND_PFN if NVDIMM_PFN help Memory ranges for PMEM are described by either an NFIT (NVDIMM Firmware Interface Table, see CONFIG_NFIT_ACPI), a @@ -47,12 +48,16 @@ config ND_BLK (CONFIG_ACPI_NFIT), or otherwise exposes BLK-mode capabilities. +config ND_CLAIM + bool + config ND_BTT tristate config BTT bool "BTT: Block Translation Table (atomic sector updates)" default y if LIBNVDIMM + select ND_CLAIM help The Block Translation Table (BTT) provides atomic sector update semantics for persistent memory devices, so that @@ -65,4 +70,21 @@ config BTT Select Y if unsure +config ND_PFN + tristate + +config NVDIMM_PFN + bool "PFN: Map persistent (device) memory" + default LIBNVDIMM + select ND_CLAIM + help + Map persistent memory, i.e. advertise it to the memory + management sub-system. By default persistent memory does + not support direct I/O, RDMA, or any other usage that + requires a 'struct page' to mediate an I/O request. This + driver allocates and initializes the infrastructure needed + to support those use cases. + + Select Y if unsure + endif diff --git a/drivers/nvdimm/Makefile b/drivers/nvdimm/Makefile index 9bf15db52dee4..ea84d3c4e8e5a 100644 --- a/drivers/nvdimm/Makefile +++ b/drivers/nvdimm/Makefile @@ -20,4 +20,6 @@ libnvdimm-y += region_devs.o libnvdimm-y += region.o libnvdimm-y += namespace_devs.o libnvdimm-y += label.o +libnvdimm-$(CONFIG_ND_CLAIM) += claim.o libnvdimm-$(CONFIG_BTT) += btt_devs.o +libnvdimm-$(CONFIG_NVDIMM_PFN) += pfn_devs.o diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 19588291550b5..028d2d137bc58 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -731,6 +731,7 @@ static int create_arenas(struct btt *btt) static int btt_arena_write_layout(struct arena_info *arena) { int ret; + u64 sum; struct btt_sb *super; struct nd_btt *nd_btt = arena->nd_btt; const u8 *parent_uuid = nd_dev_to_uuid(&nd_btt->ndns->dev); @@ -770,7 +771,8 @@ static int btt_arena_write_layout(struct arena_info *arena) super->info2off = cpu_to_le64(arena->info2off - arena->infooff); super->flags = 0; - super->checksum = cpu_to_le64(nd_btt_sb_checksum(super)); + sum = nd_sb_checksum((struct nd_gen_sb *) super); + super->checksum = cpu_to_le64(sum); ret = btt_info_write(arena, super); @@ -1422,8 +1424,6 @@ static int __init nd_btt_init(void) { int rc; - BUILD_BUG_ON(sizeof(struct btt_sb) != SZ_4K); - btt_major = register_blkdev(0, "btt"); if (btt_major < 0) return btt_major; diff --git a/drivers/nvdimm/btt_devs.c b/drivers/nvdimm/btt_devs.c index 242ae1c550ad6..59ad54a63d9fa 100644 --- a/drivers/nvdimm/btt_devs.c +++ b/drivers/nvdimm/btt_devs.c @@ -21,63 +21,13 @@ #include "btt.h" #include "nd.h" -static void __nd_btt_detach_ndns(struct nd_btt *nd_btt) -{ - struct nd_namespace_common *ndns = nd_btt->ndns; - - dev_WARN_ONCE(&nd_btt->dev, !mutex_is_locked(&ndns->dev.mutex) - || ndns->claim != &nd_btt->dev, - "%s: invalid claim\n", __func__); - ndns->claim = NULL; - nd_btt->ndns = NULL; - put_device(&ndns->dev); -} - -static void nd_btt_detach_ndns(struct nd_btt *nd_btt) -{ - struct nd_namespace_common *ndns = nd_btt->ndns; - - if (!ndns) - return; - get_device(&ndns->dev); - device_lock(&ndns->dev); - __nd_btt_detach_ndns(nd_btt); - device_unlock(&ndns->dev); - put_device(&ndns->dev); -} - -static bool __nd_btt_attach_ndns(struct nd_btt *nd_btt, - struct nd_namespace_common *ndns) -{ - if (ndns->claim) - return false; - dev_WARN_ONCE(&nd_btt->dev, !mutex_is_locked(&ndns->dev.mutex) - || nd_btt->ndns, - "%s: invalid claim\n", __func__); - ndns->claim = &nd_btt->dev; - nd_btt->ndns = ndns; - get_device(&ndns->dev); - return true; -} - -static bool nd_btt_attach_ndns(struct nd_btt *nd_btt, - struct nd_namespace_common *ndns) -{ - bool claimed; - - device_lock(&ndns->dev); - claimed = __nd_btt_attach_ndns(nd_btt, ndns); - device_unlock(&ndns->dev); - return claimed; -} - static void nd_btt_release(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); struct nd_btt *nd_btt = to_nd_btt(dev); dev_dbg(dev, "%s\n", __func__); - nd_btt_detach_ndns(nd_btt); + nd_detach_ndns(&nd_btt->dev, &nd_btt->ndns); ida_simple_remove(&nd_region->btt_ida, nd_btt->id); kfree(nd_btt->uuid); kfree(nd_btt); @@ -172,104 +122,15 @@ static ssize_t namespace_show(struct device *dev, return rc; } -static int namespace_match(struct device *dev, void *data) -{ - char *name = data; - - return strcmp(name, dev_name(dev)) == 0; -} - -static bool is_nd_btt_idle(struct device *dev) -{ - struct nd_region *nd_region = to_nd_region(dev->parent); - struct nd_btt *nd_btt = to_nd_btt(dev); - - if (nd_region->btt_seed == dev || nd_btt->ndns || dev->driver) - return false; - return true; -} - -static ssize_t __namespace_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t len) -{ - struct nd_btt *nd_btt = to_nd_btt(dev); - struct nd_namespace_common *ndns; - struct device *found; - char *name; - - if (dev->driver) { - dev_dbg(dev, "%s: -EBUSY\n", __func__); - return -EBUSY; - } - - name = kstrndup(buf, len, GFP_KERNEL); - if (!name) - return -ENOMEM; - strim(name); - - if (strncmp(name, "namespace", 9) == 0 || strcmp(name, "") == 0) - /* pass */; - else { - len = -EINVAL; - goto out; - } - - ndns = nd_btt->ndns; - if (strcmp(name, "") == 0) { - /* detach the namespace and destroy / reset the btt device */ - nd_btt_detach_ndns(nd_btt); - if (is_nd_btt_idle(dev)) - nd_device_unregister(dev, ND_ASYNC); - else { - nd_btt->lbasize = 0; - kfree(nd_btt->uuid); - nd_btt->uuid = NULL; - } - goto out; - } else if (ndns) { - dev_dbg(dev, "namespace already set to: %s\n", - dev_name(&ndns->dev)); - len = -EBUSY; - goto out; - } - - found = device_find_child(dev->parent, name, namespace_match); - if (!found) { - dev_dbg(dev, "'%s' not found under %s\n", name, - dev_name(dev->parent)); - len = -ENODEV; - goto out; - } - - ndns = to_ndns(found); - if (__nvdimm_namespace_capacity(ndns) < SZ_16M) { - dev_dbg(dev, "%s too small to host btt\n", name); - len = -ENXIO; - goto out_attach; - } - - WARN_ON_ONCE(!is_nvdimm_bus_locked(&nd_btt->dev)); - if (!nd_btt_attach_ndns(nd_btt, ndns)) { - dev_dbg(dev, "%s already claimed\n", - dev_name(&ndns->dev)); - len = -EBUSY; - } - - out_attach: - put_device(&ndns->dev); /* from device_find_child */ - out: - kfree(name); - return len; -} - static ssize_t namespace_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { + struct nd_btt *nd_btt = to_nd_btt(dev); ssize_t rc; nvdimm_bus_lock(dev); device_lock(dev); - rc = __namespace_store(dev, attr, buf, len); + rc = nd_namespace_store(dev, &nd_btt->ndns, buf, len); dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, rc, buf, buf[len - 1] == '\n' ? "" : "\n"); device_unlock(dev); @@ -324,7 +185,7 @@ static struct device *__nd_btt_create(struct nd_region *nd_region, dev->type = &nd_btt_device_type; dev->groups = nd_btt_attribute_groups; device_initialize(&nd_btt->dev); - if (ndns && !__nd_btt_attach_ndns(nd_btt, ndns)) { + if (ndns && !__nd_attach_ndns(&nd_btt->dev, ndns, &nd_btt->ndns)) { dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n", __func__, dev_name(ndns->claim)); put_device(dev); @@ -375,7 +236,7 @@ bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super) checksum = le64_to_cpu(super->checksum); super->checksum = 0; - if (checksum != nd_btt_sb_checksum(super)) + if (checksum != nd_sb_checksum((struct nd_gen_sb *) super)) return false; super->checksum = cpu_to_le64(checksum); @@ -387,25 +248,6 @@ bool nd_btt_arena_is_valid(struct nd_btt *nd_btt, struct btt_sb *super) } EXPORT_SYMBOL(nd_btt_arena_is_valid); -/* - * nd_btt_sb_checksum: compute checksum for btt info block - * - * Returns a fletcher64 checksum of everything in the given info block - * except the last field (since that's where the checksum lives). - */ -u64 nd_btt_sb_checksum(struct btt_sb *btt_sb) -{ - u64 sum; - __le64 sum_save; - - sum_save = btt_sb->checksum; - btt_sb->checksum = 0; - sum = nd_fletcher64(btt_sb, sizeof(*btt_sb), 1); - btt_sb->checksum = sum_save; - return sum; -} -EXPORT_SYMBOL(nd_btt_sb_checksum); - static int __nd_btt_probe(struct nd_btt *nd_btt, struct nd_namespace_common *ndns, struct btt_sb *btt_sb) { @@ -453,7 +295,9 @@ int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata) dev_dbg(&ndns->dev, "%s: btt: %s\n", __func__, rc == 0 ? dev_name(dev) : ""); if (rc < 0) { - __nd_btt_detach_ndns(to_nd_btt(dev)); + struct nd_btt *nd_btt = to_nd_btt(dev); + + __nd_detach_ndns(dev, &nd_btt->ndns); put_device(dev); } diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c new file mode 100644 index 0000000000000..e8f03b0e95e4a --- /dev/null +++ b/drivers/nvdimm/claim.c @@ -0,0 +1,201 @@ +/* + * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include "nd-core.h" +#include "pfn.h" +#include "btt.h" +#include "nd.h" + +void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns) +{ + struct nd_namespace_common *ndns = *_ndns; + + dev_WARN_ONCE(dev, !mutex_is_locked(&ndns->dev.mutex) + || ndns->claim != dev, + "%s: invalid claim\n", __func__); + ndns->claim = NULL; + *_ndns = NULL; + put_device(&ndns->dev); +} + +void nd_detach_ndns(struct device *dev, + struct nd_namespace_common **_ndns) +{ + struct nd_namespace_common *ndns = *_ndns; + + if (!ndns) + return; + get_device(&ndns->dev); + device_lock(&ndns->dev); + __nd_detach_ndns(dev, _ndns); + device_unlock(&ndns->dev); + put_device(&ndns->dev); +} + +bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, + struct nd_namespace_common **_ndns) +{ + if (attach->claim) + return false; + dev_WARN_ONCE(dev, !mutex_is_locked(&attach->dev.mutex) + || *_ndns, + "%s: invalid claim\n", __func__); + attach->claim = dev; + *_ndns = attach; + get_device(&attach->dev); + return true; +} + +bool nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, + struct nd_namespace_common **_ndns) +{ + bool claimed; + + device_lock(&attach->dev); + claimed = __nd_attach_ndns(dev, attach, _ndns); + device_unlock(&attach->dev); + return claimed; +} + +static int namespace_match(struct device *dev, void *data) +{ + char *name = data; + + return strcmp(name, dev_name(dev)) == 0; +} + +static bool is_idle(struct device *dev, struct nd_namespace_common *ndns) +{ + struct nd_region *nd_region = to_nd_region(dev->parent); + struct device *seed = NULL; + + if (is_nd_btt(dev)) + seed = nd_region->btt_seed; + else if (is_nd_pfn(dev)) + seed = nd_region->pfn_seed; + + if (seed == dev || ndns || dev->driver) + return false; + return true; +} + +static void nd_detach_and_reset(struct device *dev, + struct nd_namespace_common **_ndns) +{ + /* detach the namespace and destroy / reset the device */ + nd_detach_ndns(dev, _ndns); + if (is_idle(dev, *_ndns)) { + nd_device_unregister(dev, ND_ASYNC); + } else if (is_nd_btt(dev)) { + struct nd_btt *nd_btt = to_nd_btt(dev); + + nd_btt->lbasize = 0; + kfree(nd_btt->uuid); + nd_btt->uuid = NULL; + } else if (is_nd_pfn(dev)) { + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + + kfree(nd_pfn->uuid); + nd_pfn->uuid = NULL; + nd_pfn->mode = PFN_MODE_NONE; + } +} + +ssize_t nd_namespace_store(struct device *dev, + struct nd_namespace_common **_ndns, const char *buf, + size_t len) +{ + struct nd_namespace_common *ndns; + struct device *found; + char *name; + + if (dev->driver) { + dev_dbg(dev, "%s: -EBUSY\n", __func__); + return -EBUSY; + } + + name = kstrndup(buf, len, GFP_KERNEL); + if (!name) + return -ENOMEM; + strim(name); + + if (strncmp(name, "namespace", 9) == 0 || strcmp(name, "") == 0) + /* pass */; + else { + len = -EINVAL; + goto out; + } + + ndns = *_ndns; + if (strcmp(name, "") == 0) { + nd_detach_and_reset(dev, _ndns); + goto out; + } else if (ndns) { + dev_dbg(dev, "namespace already set to: %s\n", + dev_name(&ndns->dev)); + len = -EBUSY; + goto out; + } + + found = device_find_child(dev->parent, name, namespace_match); + if (!found) { + dev_dbg(dev, "'%s' not found under %s\n", name, + dev_name(dev->parent)); + len = -ENODEV; + goto out; + } + + ndns = to_ndns(found); + if (__nvdimm_namespace_capacity(ndns) < SZ_16M) { + dev_dbg(dev, "%s too small to host\n", name); + len = -ENXIO; + goto out_attach; + } + + WARN_ON_ONCE(!is_nvdimm_bus_locked(dev)); + if (!nd_attach_ndns(dev, ndns, _ndns)) { + dev_dbg(dev, "%s already claimed\n", + dev_name(&ndns->dev)); + len = -EBUSY; + } + + out_attach: + put_device(&ndns->dev); /* from device_find_child */ + out: + kfree(name); + return len; +} + +/* + * nd_sb_checksum: compute checksum for a generic info block + * + * Returns a fletcher64 checksum of everything in the given info block + * except the last field (since that's where the checksum lives). + */ +u64 nd_sb_checksum(struct nd_gen_sb *nd_gen_sb) +{ + u64 sum; + __le64 sum_save; + + BUILD_BUG_ON(sizeof(struct btt_sb) != SZ_4K); + BUILD_BUG_ON(sizeof(struct nd_pfn_sb) != SZ_4K); + BUILD_BUG_ON(sizeof(struct nd_gen_sb) != SZ_4K); + + sum_save = nd_gen_sb->checksum; + nd_gen_sb->checksum = 0; + sum = nd_fletcher64(nd_gen_sb, sizeof(*nd_gen_sb), 1); + nd_gen_sb->checksum = sum_save; + return sum; +} +EXPORT_SYMBOL(nd_sb_checksum); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index b18ffea9d85be..9303ca29be9b6 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -82,8 +82,16 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, struct nd_region *nd_region = to_nd_region(ndns->dev.parent); const char *suffix = ""; - if (ndns->claim && is_nd_btt(ndns->claim)) - suffix = "s"; + if (ndns->claim) { + if (is_nd_btt(ndns->claim)) + suffix = "s"; + else if (is_nd_pfn(ndns->claim)) + suffix = "m"; + else + dev_WARN_ONCE(&ndns->dev, 1, + "unknown claim type by %s\n", + dev_name(ndns->claim)); + } if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) sprintf(name, "pmem%d%s", nd_region->id, suffix); @@ -1255,12 +1263,22 @@ static const struct attribute_group *nd_namespace_attribute_groups[] = { struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev) { struct nd_btt *nd_btt = is_nd_btt(dev) ? to_nd_btt(dev) : NULL; + struct nd_pfn *nd_pfn = is_nd_pfn(dev) ? to_nd_pfn(dev) : NULL; struct nd_namespace_common *ndns; resource_size_t size; - if (nd_btt) { - ndns = nd_btt->ndns; - if (!ndns) + if (nd_btt || nd_pfn) { + struct device *host = NULL; + + if (nd_btt) { + host = &nd_btt->dev; + ndns = nd_btt->ndns; + } else if (nd_pfn) { + host = &nd_pfn->dev; + ndns = nd_pfn->ndns; + } + + if (!ndns || !host) return ERR_PTR(-ENODEV); /* @@ -1271,12 +1289,12 @@ struct nd_namespace_common *nvdimm_namespace_common_probe(struct device *dev) device_unlock(&ndns->dev); if (ndns->dev.driver) { dev_dbg(&ndns->dev, "is active, can't bind %s\n", - dev_name(&nd_btt->dev)); + dev_name(host)); return ERR_PTR(-EBUSY); } - if (dev_WARN_ONCE(&ndns->dev, ndns->claim != &nd_btt->dev, + if (dev_WARN_ONCE(&ndns->dev, ndns->claim != host, "host (%s) vs claim (%s) mismatch\n", - dev_name(&nd_btt->dev), + dev_name(host), dev_name(ndns->claim))) return ERR_PTR(-ENXIO); } else { diff --git a/drivers/nvdimm/nd-core.h b/drivers/nvdimm/nd-core.h index e1970c71ad1c5..159aed5320424 100644 --- a/drivers/nvdimm/nd-core.h +++ b/drivers/nvdimm/nd-core.h @@ -80,4 +80,13 @@ struct resource *nsblk_add_resource(struct nd_region *nd_region, int nvdimm_num_label_slots(struct nvdimm_drvdata *ndd); void get_ndd(struct nvdimm_drvdata *ndd); resource_size_t __nvdimm_namespace_capacity(struct nd_namespace_common *ndns); +void nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns); +void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns); +bool nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, + struct nd_namespace_common **_ndns); +bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, + struct nd_namespace_common **_ndns); +ssize_t nd_namespace_store(struct device *dev, + struct nd_namespace_common **_ndns, const char *buf, + size_t len); #endif /* __ND_CORE_H__ */ diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index f9615824947bd..8da2be1cecb8c 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -29,6 +29,13 @@ enum { ND_MAX_LANES = 256, SECTOR_SHIFT = 9, INT_LBASIZE_ALIGNMENT = 64, +#if IS_ENABLED(CONFIG_NVDIMM_PFN) + ND_PFN_ALIGN = PAGES_PER_SECTION * PAGE_SIZE, + ND_PFN_MASK = ND_PFN_ALIGN - 1, +#else + ND_PFN_ALIGN = 0, + ND_PFN_MASK = 0, +#endif }; struct nvdimm_drvdata { @@ -92,8 +99,10 @@ struct nd_region { struct device dev; struct ida ns_ida; struct ida btt_ida; + struct ida pfn_ida; struct device *ns_seed; struct device *btt_seed; + struct device *pfn_seed; u16 ndr_mappings; u64 ndr_size; u64 ndr_start; @@ -133,6 +142,22 @@ struct nd_btt { int id; }; +enum nd_pfn_mode { + PFN_MODE_NONE, + PFN_MODE_RAM, + PFN_MODE_PMEM, +}; + +struct nd_pfn { + int id; + u8 *uuid; + struct device dev; + unsigned long npfns; + enum nd_pfn_mode mode; + struct nd_pfn_sb *pfn_sb; + struct nd_namespace_common *ndns; +}; + enum nd_async_mode { ND_SYNC, ND_ASYNC, @@ -159,8 +184,13 @@ int nvdimm_init_config_data(struct nvdimm_drvdata *ndd); int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, void *buf, size_t len); struct nd_btt *to_nd_btt(struct device *dev); -struct btt_sb; -u64 nd_btt_sb_checksum(struct btt_sb *btt_sb); + +struct nd_gen_sb { + char reserved[SZ_4K - 8]; + __le64 checksum; +}; + +u64 nd_sb_checksum(struct nd_gen_sb *sb); #if IS_ENABLED(CONFIG_BTT) int nd_btt_probe(struct nd_namespace_common *ndns, void *drvdata); bool is_nd_btt(struct device *dev); @@ -180,8 +210,30 @@ static inline struct device *nd_btt_create(struct nd_region *nd_region) { return NULL; } +#endif +struct nd_pfn *to_nd_pfn(struct device *dev); +#if IS_ENABLED(CONFIG_NVDIMM_PFN) +int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata); +bool is_nd_pfn(struct device *dev); +struct device *nd_pfn_create(struct nd_region *nd_region); +#else +static inline int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata) +{ + return -ENODEV; +} + +static inline bool is_nd_pfn(struct device *dev) +{ + return false; +} + +static inline struct device *nd_pfn_create(struct nd_region *nd_region) +{ + return NULL; +} #endif + struct nd_region *to_nd_region(struct device *dev); int nd_region_to_nstype(struct nd_region *nd_region); int nd_region_register_namespaces(struct nd_region *nd_region, int *err); diff --git a/drivers/nvdimm/pfn.h b/drivers/nvdimm/pfn.h new file mode 100644 index 0000000000000..cc243754acef0 --- /dev/null +++ b/drivers/nvdimm/pfn.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014-2015, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __NVDIMM_PFN_H +#define __NVDIMM_PFN_H + +#include + +#define PFN_SIG_LEN 16 +#define PFN_SIG "NVDIMM_PFN_INFO\0" + +struct nd_pfn_sb { + u8 signature[PFN_SIG_LEN]; + u8 uuid[16]; + u8 parent_uuid[16]; + __le32 flags; + __le16 version_major; + __le16 version_minor; + __le64 dataoff; + __le64 npfns; + __le32 mode; + u8 padding[4012]; + __le64 checksum; +}; +#endif /* __NVDIMM_PFN_H */ diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c new file mode 100644 index 0000000000000..f708d63709a5d --- /dev/null +++ b/drivers/nvdimm/pfn_devs.c @@ -0,0 +1,336 @@ +/* + * Copyright(c) 2013-2015 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include "nd-core.h" +#include "pfn.h" +#include "nd.h" + +static void nd_pfn_release(struct device *dev) +{ + struct nd_region *nd_region = to_nd_region(dev->parent); + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + + dev_dbg(dev, "%s\n", __func__); + nd_detach_ndns(&nd_pfn->dev, &nd_pfn->ndns); + ida_simple_remove(&nd_region->pfn_ida, nd_pfn->id); + kfree(nd_pfn->uuid); + kfree(nd_pfn); +} + +static struct device_type nd_pfn_device_type = { + .name = "nd_pfn", + .release = nd_pfn_release, +}; + +bool is_nd_pfn(struct device *dev) +{ + return dev ? dev->type == &nd_pfn_device_type : false; +} +EXPORT_SYMBOL(is_nd_pfn); + +struct nd_pfn *to_nd_pfn(struct device *dev) +{ + struct nd_pfn *nd_pfn = container_of(dev, struct nd_pfn, dev); + + WARN_ON(!is_nd_pfn(dev)); + return nd_pfn; +} +EXPORT_SYMBOL(to_nd_pfn); + +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + + switch (nd_pfn->mode) { + case PFN_MODE_RAM: + return sprintf(buf, "ram\n"); + case PFN_MODE_PMEM: + return sprintf(buf, "pmem\n"); + default: + return sprintf(buf, "none\n"); + } +} + +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + ssize_t rc = 0; + + device_lock(dev); + nvdimm_bus_lock(dev); + if (dev->driver) + rc = -EBUSY; + else { + size_t n = len - 1; + + if (strncmp(buf, "pmem\n", n) == 0 + || strncmp(buf, "pmem", n) == 0) { + /* TODO: allocate from PMEM support */ + rc = -ENOTTY; + } else if (strncmp(buf, "ram\n", n) == 0 + || strncmp(buf, "ram", n) == 0) + nd_pfn->mode = PFN_MODE_RAM; + else if (strncmp(buf, "none\n", n) == 0 + || strncmp(buf, "none", n) == 0) + nd_pfn->mode = PFN_MODE_NONE; + else + rc = -EINVAL; + } + dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, + rc, buf, buf[len - 1] == '\n' ? "" : "\n"); + nvdimm_bus_unlock(dev); + device_unlock(dev); + + return rc ? rc : len; +} +static DEVICE_ATTR_RW(mode); + +static ssize_t uuid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + + if (nd_pfn->uuid) + return sprintf(buf, "%pUb\n", nd_pfn->uuid); + return sprintf(buf, "\n"); +} + +static ssize_t uuid_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + ssize_t rc; + + device_lock(dev); + rc = nd_uuid_store(dev, &nd_pfn->uuid, buf, len); + dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, + rc, buf, buf[len - 1] == '\n' ? "" : "\n"); + device_unlock(dev); + + return rc ? rc : len; +} +static DEVICE_ATTR_RW(uuid); + +static ssize_t namespace_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + ssize_t rc; + + nvdimm_bus_lock(dev); + rc = sprintf(buf, "%s\n", nd_pfn->ndns + ? dev_name(&nd_pfn->ndns->dev) : ""); + nvdimm_bus_unlock(dev); + return rc; +} + +static ssize_t namespace_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(dev); + ssize_t rc; + + nvdimm_bus_lock(dev); + device_lock(dev); + rc = nd_namespace_store(dev, &nd_pfn->ndns, buf, len); + dev_dbg(dev, "%s: result: %zd wrote: %s%s", __func__, + rc, buf, buf[len - 1] == '\n' ? "" : "\n"); + device_unlock(dev); + nvdimm_bus_unlock(dev); + + return rc; +} +static DEVICE_ATTR_RW(namespace); + +static struct attribute *nd_pfn_attributes[] = { + &dev_attr_mode.attr, + &dev_attr_namespace.attr, + &dev_attr_uuid.attr, + NULL, +}; + +static struct attribute_group nd_pfn_attribute_group = { + .attrs = nd_pfn_attributes, +}; + +static const struct attribute_group *nd_pfn_attribute_groups[] = { + &nd_pfn_attribute_group, + &nd_device_attribute_group, + &nd_numa_attribute_group, + NULL, +}; + +static struct device *__nd_pfn_create(struct nd_region *nd_region, + u8 *uuid, enum nd_pfn_mode mode, + struct nd_namespace_common *ndns) +{ + struct nd_pfn *nd_pfn; + struct device *dev; + + /* we can only create pages for contiguous ranged of pmem */ + if (!is_nd_pmem(&nd_region->dev)) + return NULL; + + nd_pfn = kzalloc(sizeof(*nd_pfn), GFP_KERNEL); + if (!nd_pfn) + return NULL; + + nd_pfn->id = ida_simple_get(&nd_region->pfn_ida, 0, 0, GFP_KERNEL); + if (nd_pfn->id < 0) { + kfree(nd_pfn); + return NULL; + } + + nd_pfn->mode = mode; + if (uuid) + uuid = kmemdup(uuid, 16, GFP_KERNEL); + nd_pfn->uuid = uuid; + dev = &nd_pfn->dev; + dev_set_name(dev, "pfn%d.%d", nd_region->id, nd_pfn->id); + dev->parent = &nd_region->dev; + dev->type = &nd_pfn_device_type; + dev->groups = nd_pfn_attribute_groups; + device_initialize(&nd_pfn->dev); + if (ndns && !__nd_attach_ndns(&nd_pfn->dev, ndns, &nd_pfn->ndns)) { + dev_dbg(&ndns->dev, "%s failed, already claimed by %s\n", + __func__, dev_name(ndns->claim)); + put_device(dev); + return NULL; + } + return dev; +} + +struct device *nd_pfn_create(struct nd_region *nd_region) +{ + struct device *dev = __nd_pfn_create(nd_region, NULL, PFN_MODE_NONE, + NULL); + + if (dev) + __nd_device_register(dev); + return dev; +} + +static int nd_pfn_validate(struct nd_pfn *nd_pfn) +{ + struct nd_namespace_common *ndns = nd_pfn->ndns; + struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; + struct nd_namespace_io *nsio; + u64 checksum, offset; + + if (!pfn_sb || !ndns) + return -ENODEV; + + if (!is_nd_pmem(nd_pfn->dev.parent)) + return -ENODEV; + + /* section alignment for simple hotplug */ + if (nvdimm_namespace_capacity(ndns) < ND_PFN_ALIGN) + return -ENODEV; + + if (nvdimm_read_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb))) + return -ENXIO; + + if (memcmp(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN) != 0) + return -ENODEV; + + checksum = le64_to_cpu(pfn_sb->checksum); + pfn_sb->checksum = 0; + if (checksum != nd_sb_checksum((struct nd_gen_sb *) pfn_sb)) + return -ENODEV; + pfn_sb->checksum = cpu_to_le64(checksum); + + switch (le32_to_cpu(pfn_sb->mode)) { + case PFN_MODE_RAM: + break; + case PFN_MODE_PMEM: + /* TODO: allocate from PMEM support */ + return -ENOTTY; + default: + return -ENXIO; + } + + if (!nd_pfn->uuid) { + /* from probe we allocate */ + nd_pfn->uuid = kmemdup(pfn_sb->uuid, 16, GFP_KERNEL); + if (!nd_pfn->uuid) + return -ENOMEM; + } else { + /* from init we validate */ + if (memcmp(nd_pfn->uuid, pfn_sb->uuid, 16) != 0) + return -EINVAL; + } + + /* + * These warnings are verbose because they can only trigger in + * the case where the physical address alignment of the + * namespace has changed since the pfn superblock was + * established. + */ + offset = le64_to_cpu(pfn_sb->dataoff); + nsio = to_nd_namespace_io(&ndns->dev); + if ((nsio->res.start + offset) & (ND_PFN_ALIGN - 1)) { + dev_err(&nd_pfn->dev, + "init failed: %s with offset %#llx not section aligned\n", + dev_name(&ndns->dev), offset); + return -EBUSY; + } else if (offset >= resource_size(&nsio->res)) { + dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n", + dev_name(&ndns->dev)); + return -EBUSY; + } + + return 0; +} + +int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata) +{ + int rc; + struct device *dev; + struct nd_pfn *nd_pfn; + struct nd_pfn_sb *pfn_sb; + struct nd_region *nd_region = to_nd_region(ndns->dev.parent); + + if (ndns->force_raw) + return -ENODEV; + + nvdimm_bus_lock(&ndns->dev); + dev = __nd_pfn_create(nd_region, NULL, PFN_MODE_NONE, ndns); + nvdimm_bus_unlock(&ndns->dev); + if (!dev) + return -ENOMEM; + dev_set_drvdata(dev, drvdata); + pfn_sb = kzalloc(sizeof(*pfn_sb), GFP_KERNEL); + nd_pfn = to_nd_pfn(dev); + nd_pfn->pfn_sb = pfn_sb; + rc = nd_pfn_validate(nd_pfn); + nd_pfn->pfn_sb = NULL; + kfree(pfn_sb); + dev_dbg(&ndns->dev, "%s: pfn: %s\n", __func__, + rc == 0 ? dev_name(dev) : ""); + if (rc < 0) { + __nd_detach_ndns(dev, &nd_pfn->ndns); + put_device(dev); + } else + __nd_device_register(&nd_pfn->dev); + + return rc; +} +EXPORT_SYMBOL(nd_pfn_probe); diff --git a/drivers/nvdimm/region.c b/drivers/nvdimm/region.c index f28f78ccff190..7da63eac78eec 100644 --- a/drivers/nvdimm/region.c +++ b/drivers/nvdimm/region.c @@ -53,6 +53,7 @@ static int nd_region_probe(struct device *dev) return -ENODEV; nd_region->btt_seed = nd_btt_create(nd_region); + nd_region->pfn_seed = nd_pfn_create(nd_region); if (err == 0) return 0; @@ -84,6 +85,7 @@ static int nd_region_remove(struct device *dev) nvdimm_bus_lock(dev); nd_region->ns_seed = NULL; nd_region->btt_seed = NULL; + nd_region->pfn_seed = NULL; dev_set_drvdata(dev, NULL); nvdimm_bus_unlock(dev); diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 7384455792bfb..da4338154ad21 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -345,6 +345,23 @@ static ssize_t btt_seed_show(struct device *dev, } static DEVICE_ATTR_RO(btt_seed); +static ssize_t pfn_seed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct nd_region *nd_region = to_nd_region(dev); + ssize_t rc; + + nvdimm_bus_lock(dev); + if (nd_region->pfn_seed) + rc = sprintf(buf, "%s\n", dev_name(nd_region->pfn_seed)); + else + rc = sprintf(buf, "\n"); + nvdimm_bus_unlock(dev); + + return rc; +} +static DEVICE_ATTR_RO(pfn_seed); + static ssize_t read_only_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -373,6 +390,7 @@ static struct attribute *nd_region_attributes[] = { &dev_attr_nstype.attr, &dev_attr_mappings.attr, &dev_attr_btt_seed.attr, + &dev_attr_pfn_seed.attr, &dev_attr_read_only.attr, &dev_attr_set_cookie.attr, &dev_attr_available_size.attr, @@ -744,6 +762,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, nd_region->numa_node = ndr_desc->numa_node; ida_init(&nd_region->ns_ida); ida_init(&nd_region->btt_ida); + ida_init(&nd_region->pfn_ida); dev = &nd_region->dev; dev_set_name(dev, "region%d", nd_region->id); dev->parent = &nvdimm_bus->dev; diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 98f2881ba6a28..99e70f0729be1 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -43,7 +43,9 @@ libnvdimm-y += $(NVDIMM_SRC)/region_devs.o libnvdimm-y += $(NVDIMM_SRC)/region.o libnvdimm-y += $(NVDIMM_SRC)/namespace_devs.o libnvdimm-y += $(NVDIMM_SRC)/label.o +libnvdimm-$(CONFIG_ND_CLAIM) += $(NVDIMM_SRC)/claim.o libnvdimm-$(CONFIG_BTT) += $(NVDIMM_SRC)/btt_devs.o +libnvdimm-$(CONFIG_NVDIMM_PFN) += $(NVDIMM_SRC)/pfn_devs.o libnvdimm-y += config_check.o obj-m += test/ -- GitLab From 32ab0a3f51701cb37ab960635254d5f84ec3de0a Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 1 Aug 2015 02:16:37 -0400 Subject: [PATCH 5689/7006] libnvdimm, pmem: 'struct page' for pmem Enable the pmem driver to handle PFN device instances. Attaching a pmem namespace to a pfn device triggers the driver to allocate and initialize struct page entries for pmem. Memory capacity for this allocation comes exclusively from RAM for now which is suitable for low PMEM to RAM ratios. This mechanism will be expanded later for setting an "allocate from PMEM" policy. Cc: Boaz Harrosh Cc: Ross Zwisler Cc: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/nvdimm/Kconfig | 1 + drivers/nvdimm/nd.h | 6 + drivers/nvdimm/pfn_devs.c | 9 +- drivers/nvdimm/pmem.c | 203 ++++++++++++++++++++++++++++-- tools/testing/nvdimm/Kbuild | 1 + tools/testing/nvdimm/test/iomap.c | 13 ++ 6 files changed, 216 insertions(+), 17 deletions(-) diff --git a/drivers/nvdimm/Kconfig b/drivers/nvdimm/Kconfig index ace25b53b7556..53c11621d5b16 100644 --- a/drivers/nvdimm/Kconfig +++ b/drivers/nvdimm/Kconfig @@ -76,6 +76,7 @@ config ND_PFN config NVDIMM_PFN bool "PFN: Map persistent (device) memory" default LIBNVDIMM + depends on ZONE_DEVICE select ND_CLAIM help Map persistent memory, i.e. advertise it to the memory diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 8da2be1cecb8c..83e5d09350123 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -217,6 +217,7 @@ struct nd_pfn *to_nd_pfn(struct device *dev); int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata); bool is_nd_pfn(struct device *dev); struct device *nd_pfn_create(struct nd_region *nd_region); +int nd_pfn_validate(struct nd_pfn *nd_pfn); #else static inline int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata) { @@ -232,6 +233,11 @@ static inline struct device *nd_pfn_create(struct nd_region *nd_region) { return NULL; } + +static inline int nd_pfn_validate(struct nd_pfn *nd_pfn) +{ + return -ENODEV; +} #endif struct nd_region *to_nd_region(struct device *dev); diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index f708d63709a5d..3fd7d0d81a470 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -228,7 +228,7 @@ struct device *nd_pfn_create(struct nd_region *nd_region) return dev; } -static int nd_pfn_validate(struct nd_pfn *nd_pfn) +int nd_pfn_validate(struct nd_pfn *nd_pfn) { struct nd_namespace_common *ndns = nd_pfn->ndns; struct nd_pfn_sb *pfn_sb = nd_pfn->pfn_sb; @@ -286,10 +286,10 @@ static int nd_pfn_validate(struct nd_pfn *nd_pfn) */ offset = le64_to_cpu(pfn_sb->dataoff); nsio = to_nd_namespace_io(&ndns->dev); - if ((nsio->res.start + offset) & (ND_PFN_ALIGN - 1)) { + if (nsio->res.start & ND_PFN_MASK) { dev_err(&nd_pfn->dev, - "init failed: %s with offset %#llx not section aligned\n", - dev_name(&ndns->dev), offset); + "init failed: %s not section aligned\n", + dev_name(&ndns->dev)); return -EBUSY; } else if (offset >= resource_size(&nsio->res)) { dev_err(&nd_pfn->dev, "pfn array size exceeds capacity of %s\n", @@ -299,6 +299,7 @@ static int nd_pfn_validate(struct nd_pfn *nd_pfn) return 0; } +EXPORT_SYMBOL(nd_pfn_validate); int nd_pfn_probe(struct nd_namespace_common *ndns, void *drvdata) { diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 20bf122328da5..2f885e5d9c365 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -21,18 +21,24 @@ #include #include #include +#include #include +#include #include #include #include +#include "pfn.h" #include "nd.h" struct pmem_device { struct request_queue *pmem_queue; struct gendisk *pmem_disk; + struct nd_namespace_common *ndns; /* One contiguous memory region per device */ phys_addr_t phys_addr; + /* when non-zero this device is hosting a 'pfn' instance */ + phys_addr_t data_offset; void __pmem *virt_addr; size_t size; }; @@ -44,7 +50,7 @@ static void pmem_do_bvec(struct pmem_device *pmem, struct page *page, sector_t sector) { void *mem = kmap_atomic(page); - size_t pmem_off = sector << 9; + phys_addr_t pmem_off = sector * 512 + pmem->data_offset; void __pmem *pmem_addr = pmem->virt_addr + pmem_off; if (rw == READ) { @@ -95,16 +101,23 @@ static long pmem_direct_access(struct block_device *bdev, sector_t sector, void __pmem **kaddr, unsigned long *pfn) { struct pmem_device *pmem = bdev->bd_disk->private_data; - size_t offset = sector << 9; - - if (!pmem) - return -ENODEV; + resource_size_t offset = sector * 512 + pmem->data_offset; + resource_size_t size; + + if (pmem->data_offset) { + /* + * Limit the direct_access() size to what is covered by + * the memmap + */ + size = (pmem->size - offset) & ~ND_PFN_MASK; + } else + size = pmem->size - offset; /* FIXME convert DAX to comprehend that this mapping has a lifetime */ *kaddr = pmem->virt_addr + offset; *pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT; - return pmem->size - offset; + return size; } static const struct block_device_operations pmem_fops = { @@ -144,13 +157,16 @@ static struct pmem_device *pmem_alloc(struct device *dev, static void pmem_detach_disk(struct pmem_device *pmem) { + if (!pmem->pmem_disk) + return; + del_gendisk(pmem->pmem_disk); put_disk(pmem->pmem_disk); blk_cleanup_queue(pmem->pmem_queue); } -static int pmem_attach_disk(struct nd_namespace_common *ndns, - struct pmem_device *pmem) +static int pmem_attach_disk(struct device *dev, + struct nd_namespace_common *ndns, struct pmem_device *pmem) { struct gendisk *disk; @@ -177,8 +193,8 @@ static int pmem_attach_disk(struct nd_namespace_common *ndns, disk->queue = pmem->pmem_queue; disk->flags = GENHD_FL_EXT_DEVT; nvdimm_namespace_disk_name(ndns, disk->disk_name); - disk->driverfs_dev = &ndns->dev; - set_capacity(disk, pmem->size >> 9); + disk->driverfs_dev = dev; + set_capacity(disk, (pmem->size - pmem->data_offset) / 512); pmem->pmem_disk = disk; add_disk(disk); @@ -207,6 +223,154 @@ static int pmem_rw_bytes(struct nd_namespace_common *ndns, return 0; } +static int nd_pfn_init(struct nd_pfn *nd_pfn) +{ + struct nd_pfn_sb *pfn_sb = kzalloc(sizeof(*pfn_sb), GFP_KERNEL); + struct pmem_device *pmem = dev_get_drvdata(&nd_pfn->dev); + struct nd_namespace_common *ndns = nd_pfn->ndns; + struct nd_region *nd_region; + unsigned long npfns; + phys_addr_t offset; + u64 checksum; + int rc; + + if (!pfn_sb) + return -ENOMEM; + + nd_pfn->pfn_sb = pfn_sb; + rc = nd_pfn_validate(nd_pfn); + if (rc == 0 || rc == -EBUSY) + return rc; + + /* section alignment for simple hotplug */ + if (nvdimm_namespace_capacity(ndns) < ND_PFN_ALIGN + || pmem->phys_addr & ND_PFN_MASK) + return -ENODEV; + + nd_region = to_nd_region(nd_pfn->dev.parent); + if (nd_region->ro) { + dev_info(&nd_pfn->dev, + "%s is read-only, unable to init metadata\n", + dev_name(&nd_region->dev)); + goto err; + } + + memset(pfn_sb, 0, sizeof(*pfn_sb)); + npfns = (pmem->size - SZ_8K) / SZ_4K; + /* + * Note, we use 64 here for the standard size of struct page, + * debugging options may cause it to be larger in which case the + * implementation will limit the pfns advertised through + * ->direct_access() to those that are included in the memmap. + */ + if (nd_pfn->mode == PFN_MODE_PMEM) + offset = ALIGN(SZ_8K + 64 * npfns, PMD_SIZE); + else if (nd_pfn->mode == PFN_MODE_RAM) + offset = SZ_8K; + else + goto err; + + npfns = (pmem->size - offset) / SZ_4K; + pfn_sb->mode = cpu_to_le32(nd_pfn->mode); + pfn_sb->dataoff = cpu_to_le64(offset); + pfn_sb->npfns = cpu_to_le64(npfns); + memcpy(pfn_sb->signature, PFN_SIG, PFN_SIG_LEN); + memcpy(pfn_sb->uuid, nd_pfn->uuid, 16); + pfn_sb->version_major = cpu_to_le16(1); + checksum = nd_sb_checksum((struct nd_gen_sb *) pfn_sb); + pfn_sb->checksum = cpu_to_le64(checksum); + + rc = nvdimm_write_bytes(ndns, SZ_4K, pfn_sb, sizeof(*pfn_sb)); + if (rc) + goto err; + + return 0; + err: + nd_pfn->pfn_sb = NULL; + kfree(pfn_sb); + return -ENXIO; +} + +static int nvdimm_namespace_detach_pfn(struct nd_namespace_common *ndns) +{ + struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim); + struct pmem_device *pmem; + + /* free pmem disk */ + pmem = dev_get_drvdata(&nd_pfn->dev); + pmem_detach_disk(pmem); + + /* release nd_pfn resources */ + kfree(nd_pfn->pfn_sb); + nd_pfn->pfn_sb = NULL; + + return 0; +} + +static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns) +{ + struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); + struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim); + struct device *dev = &nd_pfn->dev; + struct vmem_altmap *altmap; + struct nd_region *nd_region; + struct nd_pfn_sb *pfn_sb; + struct pmem_device *pmem; + phys_addr_t offset; + int rc; + + if (!nd_pfn->uuid || !nd_pfn->ndns) + return -ENODEV; + + nd_region = to_nd_region(dev->parent); + rc = nd_pfn_init(nd_pfn); + if (rc) + return rc; + + if (PAGE_SIZE != SZ_4K) { + dev_err(dev, "only supported on systems with 4K PAGE_SIZE\n"); + return -ENXIO; + } + if (nsio->res.start & ND_PFN_MASK) { + dev_err(dev, "%s not memory hotplug section aligned\n", + dev_name(&ndns->dev)); + return -ENXIO; + } + + pfn_sb = nd_pfn->pfn_sb; + offset = le64_to_cpu(pfn_sb->dataoff); + nd_pfn->mode = le32_to_cpu(nd_pfn->pfn_sb->mode); + if (nd_pfn->mode == PFN_MODE_RAM) { + if (offset != SZ_8K) + return -EINVAL; + nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns); + altmap = NULL; + } else { + rc = -ENXIO; + goto err; + } + + /* establish pfn range for lookup, and switch to direct map */ + pmem = dev_get_drvdata(dev); + memunmap_pmem(dev, pmem->virt_addr); + pmem->virt_addr = (void __pmem *)devm_memremap_pages(dev, &nsio->res); + if (IS_ERR(pmem->virt_addr)) { + rc = PTR_ERR(pmem->virt_addr); + goto err; + } + + /* attach pmem disk in "pfn-mode" */ + pmem->data_offset = offset; + rc = pmem_attach_disk(dev, ndns, pmem); + if (rc) + goto err; + + return rc; + err: + nvdimm_namespace_detach_pfn(ndns); + return rc; +} + static int nd_pmem_probe(struct device *dev) { struct nd_region *nd_region = to_nd_region(dev->parent); @@ -223,16 +387,27 @@ static int nd_pmem_probe(struct device *dev) if (IS_ERR(pmem)) return PTR_ERR(pmem); + pmem->ndns = ndns; dev_set_drvdata(dev, pmem); ndns->rw_bytes = pmem_rw_bytes; if (is_nd_btt(dev)) return nvdimm_namespace_attach_btt(ndns); - if (nd_btt_probe(ndns, pmem) == 0) + if (is_nd_pfn(dev)) + return nvdimm_namespace_attach_pfn(ndns); + + if (nd_btt_probe(ndns, pmem) == 0) { /* we'll come back as btt-pmem */ return -ENXIO; - return pmem_attach_disk(ndns, pmem); + } + + if (nd_pfn_probe(ndns, pmem) == 0) { + /* we'll come back as pfn-pmem */ + return -ENXIO; + } + + return pmem_attach_disk(dev, ndns, pmem); } static int nd_pmem_remove(struct device *dev) @@ -240,7 +415,9 @@ static int nd_pmem_remove(struct device *dev) struct pmem_device *pmem = dev_get_drvdata(dev); if (is_nd_btt(dev)) - nvdimm_namespace_detach_btt(to_nd_btt(dev)->ndns); + nvdimm_namespace_detach_btt(pmem->ndns); + else if (is_nd_pfn(dev)) + nvdimm_namespace_detach_pfn(pmem->ndns); else pmem_detach_disk(pmem); diff --git a/tools/testing/nvdimm/Kbuild b/tools/testing/nvdimm/Kbuild index 99e70f0729be1..38b00ecb2ed55 100644 --- a/tools/testing/nvdimm/Kbuild +++ b/tools/testing/nvdimm/Kbuild @@ -2,6 +2,7 @@ ldflags-y += --wrap=ioremap_wc ldflags-y += --wrap=memremap ldflags-y += --wrap=devm_ioremap_nocache ldflags-y += --wrap=devm_memremap +ldflags-y += --wrap=devm_memunmap ldflags-y += --wrap=ioremap_nocache ldflags-y += --wrap=iounmap ldflags-y += --wrap=memunmap diff --git a/tools/testing/nvdimm/test/iomap.c b/tools/testing/nvdimm/test/iomap.c index 179d2289f3a82..b7251314bbc03 100644 --- a/tools/testing/nvdimm/test/iomap.c +++ b/tools/testing/nvdimm/test/iomap.c @@ -108,6 +108,19 @@ void *__wrap_memremap(resource_size_t offset, size_t size, } EXPORT_SYMBOL(__wrap_memremap); +void __wrap_devm_memunmap(struct device *dev, void *addr) +{ + struct nfit_test_resource *nfit_res; + + rcu_read_lock(); + nfit_res = get_nfit_res((unsigned long) addr); + rcu_read_unlock(); + if (nfit_res) + return; + return devm_memunmap(dev, addr); +} +EXPORT_SYMBOL(__wrap_devm_memunmap); + void __iomem *__wrap_ioremap_nocache(resource_size_t offset, unsigned long size) { return __nfit_test_ioremap(offset, size, ioremap_nocache); -- GitLab From 004f1afbe199e6ab20805b95aefd83ccd24bc5c7 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 24 Aug 2015 19:20:23 -0400 Subject: [PATCH 5690/7006] libnvdimm, pmem: direct map legacy pmem by default The expectation is that the legacy / non-standard pmem discovery method (e820 type-12) will only ever be used to describe small quantities of persistent memory. Larger capacities will be described via the ACPI NFIT. When "allocate struct page from pmem" support is added this default policy can be overridden by assigning a legacy pmem namespace to a pfn device, however this would be only be necessary if a platform used the legacy mechanism to define a very large range. Cc: Christoph Hellwig Signed-off-by: Dan Williams --- drivers/nvdimm/e820.c | 1 + drivers/nvdimm/namespace_devs.c | 35 ++++++++++++++++++++++++++++----- drivers/nvdimm/nd.h | 2 ++ drivers/nvdimm/pmem.c | 15 +++++++++++--- drivers/nvdimm/region_devs.c | 1 + include/linux/libnvdimm.h | 4 ++++ 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 1b5743ad92db3..8282db2ef99ea 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c @@ -49,6 +49,7 @@ static int e820_pmem_probe(struct platform_device *pdev) ndr_desc.res = p; ndr_desc.attr_groups = e820_pmem_region_attribute_groups; ndr_desc.numa_node = NUMA_NO_NODE; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); if (!nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc)) goto err; } diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 9303ca29be9b6..0955b2cb10fe8 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "nd-core.h" #include "nd.h" @@ -76,11 +77,32 @@ static bool is_namespace_io(struct device *dev) return dev ? dev->type == &namespace_io_device_type : false; } +bool pmem_should_map_pages(struct device *dev) +{ + struct nd_region *nd_region = to_nd_region(dev->parent); + + if (!IS_ENABLED(CONFIG_ZONE_DEVICE)) + return false; + + if (!test_bit(ND_REGION_PAGEMAP, &nd_region->flags)) + return false; + + if (is_nd_pfn(dev) || is_nd_btt(dev)) + return false; + +#ifdef ARCH_MEMREMAP_PMEM + return ARCH_MEMREMAP_PMEM == MEMREMAP_WB; +#else + return false; +#endif +} +EXPORT_SYMBOL(pmem_should_map_pages); + const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, char *name) { struct nd_region *nd_region = to_nd_region(ndns->dev.parent); - const char *suffix = ""; + const char *suffix = NULL; if (ndns->claim) { if (is_nd_btt(ndns->claim)) @@ -93,13 +115,16 @@ const char *nvdimm_namespace_disk_name(struct nd_namespace_common *ndns, dev_name(ndns->claim)); } - if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) - sprintf(name, "pmem%d%s", nd_region->id, suffix); - else if (is_namespace_blk(&ndns->dev)) { + if (is_namespace_pmem(&ndns->dev) || is_namespace_io(&ndns->dev)) { + if (!suffix && pmem_should_map_pages(&ndns->dev)) + suffix = "m"; + sprintf(name, "pmem%d%s", nd_region->id, suffix ? suffix : ""); + } else if (is_namespace_blk(&ndns->dev)) { struct nd_namespace_blk *nsblk; nsblk = to_nd_namespace_blk(&ndns->dev); - sprintf(name, "ndblk%d.%d%s", nd_region->id, nsblk->id, suffix); + sprintf(name, "ndblk%d.%d%s", nd_region->id, nsblk->id, + suffix ? suffix : ""); } else { return NULL; } diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 83e5d09350123..417e521d299cb 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -100,6 +100,7 @@ struct nd_region { struct ida ns_ida; struct ida btt_ida; struct ida pfn_ida; + unsigned long flags; struct device *ns_seed; struct device *btt_seed; struct device *pfn_seed; @@ -276,4 +277,5 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start) void nd_iostat_end(struct bio *bio, unsigned long start); resource_size_t nd_namespace_blk_validate(struct nd_namespace_blk *nsblk); const u8 *nd_dev_to_uuid(struct device *dev); +bool pmem_should_map_pages(struct device *dev); #endif /* __ND_H__ */ diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 2f885e5d9c365..c5ae2e5792882 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -148,9 +148,18 @@ static struct pmem_device *pmem_alloc(struct device *dev, return ERR_PTR(-EBUSY); } - pmem->virt_addr = memremap_pmem(dev, pmem->phys_addr, pmem->size); - if (!pmem->virt_addr) - return ERR_PTR(-ENXIO); + if (pmem_should_map_pages(dev)) { + void *addr = devm_memremap_pages(dev, res); + + if (IS_ERR(addr)) + return addr; + pmem->virt_addr = (void __pmem *) addr; + } else { + pmem->virt_addr = memremap_pmem(dev, pmem->phys_addr, + pmem->size); + if (!pmem->virt_addr) + return ERR_PTR(-ENXIO); + } return pmem; } diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index da4338154ad21..529f3f02e7b2d 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -758,6 +758,7 @@ static struct nd_region *nd_region_create(struct nvdimm_bus *nvdimm_bus, nd_region->provider_data = ndr_desc->provider_data; nd_region->nd_set = ndr_desc->nd_set; nd_region->num_lanes = ndr_desc->num_lanes; + nd_region->flags = ndr_desc->flags; nd_region->ro = ro; nd_region->numa_node = ndr_desc->numa_node; ida_init(&nd_region->ns_ida); diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 75e3af01ee325..3f021dc5da8c3 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -31,6 +31,9 @@ enum { ND_CMD_ARS_STATUS_MAX = SZ_4K, ND_MAX_MAPPINGS = 32, + /* region flag indicating to direct-map persistent memory by default */ + ND_REGION_PAGEMAP = 0, + /* mark newly adjusted resources as requiring a label update */ DPA_RESOURCE_ADJUSTED = 1 << 0, }; @@ -91,6 +94,7 @@ struct nd_region_desc { void *provider_data; int num_lanes; int numa_node; + unsigned long flags; }; struct nvdimm_bus; -- GitLab From 0d5cdef8d5dd0a6819fd85305adb448f5ba56f24 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Fri, 28 Aug 2015 19:22:11 -0700 Subject: [PATCH 5691/7006] openvswitch: Fix conntrack compilation without mark. Fix build with !CONFIG_NF_CONNTRACK_MARK && CONFIG_OPENVSWITCH_CONNTRACK Fixes: 182e304 ("openvswitch: Allow matching on conntrack mark") Reported-by: Simon Horman Signed-off-by: Joe Stringer Tested-by: Simon Horman Signed-off-by: David S. Miller --- net/openvswitch/conntrack.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/net/openvswitch/conntrack.c b/net/openvswitch/conntrack.c index 886bd27585025..e8e524ad8a01c 100644 --- a/net/openvswitch/conntrack.c +++ b/net/openvswitch/conntrack.c @@ -100,6 +100,15 @@ static u8 ovs_ct_get_state(enum ip_conntrack_info ctinfo) return ct_state; } +static u32 ovs_ct_get_mark(const struct nf_conn *ct) +{ +#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) + return ct ? ct->mark : 0; +#else + return 0; +#endif +} + static void ovs_ct_get_label(const struct nf_conn *ct, struct ovs_key_ct_label *label) { @@ -124,7 +133,7 @@ static void __ovs_ct_update_key(struct sw_flow_key *key, u8 state, { key->ct.state = state; key->ct.zone = zone->id; - key->ct.mark = ct ? ct->mark : 0; + key->ct.mark = ovs_ct_get_mark(ct); ovs_ct_get_label(ct, &key->ct.label); } @@ -180,12 +189,11 @@ int ovs_ct_put_key(const struct sw_flow_key *key, struct sk_buff *skb) static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key, u32 ct_mark, u32 mask) { +#if IS_ENABLED(CONFIG_NF_CONNTRACK_MARK) enum ip_conntrack_info ctinfo; struct nf_conn *ct; u32 new_mark; - if (!IS_ENABLED(CONFIG_NF_CONNTRACK_MARK)) - return -ENOTSUPP; /* The connection could be invalid, in which case set_mark is no-op. */ ct = nf_ct_get(skb, &ctinfo); @@ -200,6 +208,9 @@ static int ovs_ct_set_mark(struct sk_buff *skb, struct sw_flow_key *key, } return 0; +#else + return -ENOTSUPP; +#endif } static int ovs_ct_set_label(struct sk_buff *skb, struct sw_flow_key *key, -- GitLab From 0a6a3a23ea6efde079a5b77688541a98bf202721 Mon Sep 17 00:00:00 2001 From: Christophe Ricard Date: Fri, 28 Aug 2015 07:07:48 +0200 Subject: [PATCH 5692/7006] netlink: add NETLINK_CAP_ACK socket option Since commit c05cdb1b864f ("netlink: allow large data transfers from user-space"), the kernel may fail to allocate the necessary room for the acknowledgment message back to userspace. This patch introduces a new socket option that trims off the payload of the original netlink message. The netlink message header is still included, so the user can guess from the sequence number what is the message that has triggered the acknowledgment. Signed-off-by: Pablo Neira Ayuso Signed-off-by: Christophe Ricard Signed-off-by: David S. Miller --- include/uapi/linux/netlink.h | 1 + net/netlink/af_netlink.c | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index cf6a65cccbdf5..6f3fe16cd22a2 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -110,6 +110,7 @@ struct nlmsgerr { #define NETLINK_TX_RING 7 #define NETLINK_LISTEN_ALL_NSID 8 #define NETLINK_LIST_MEMBERSHIPS 9 +#define NETLINK_CAP_ACK 10 struct nl_pktinfo { __u32 group; diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index a774985489e21..3eea0b2a3239b 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -84,6 +84,7 @@ struct listeners { #define NETLINK_F_BROADCAST_SEND_ERROR 0x4 #define NETLINK_F_RECV_NO_ENOBUFS 0x8 #define NETLINK_F_LISTEN_ALL_NSID 0x10 +#define NETLINK_F_CAP_ACK 0x20 static inline int netlink_is_kernel(struct sock *sk) { @@ -2258,6 +2259,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID; err = 0; break; + case NETLINK_CAP_ACK: + if (val) + nlk->flags |= NETLINK_F_CAP_ACK; + else + nlk->flags &= ~NETLINK_F_CAP_ACK; + err = 0; + break; default: err = -ENOPROTOOPT; } @@ -2332,6 +2340,16 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname, netlink_table_ungrab(); break; } + case NETLINK_CAP_ACK: + if (len < sizeof(int)) + return -EINVAL; + len = sizeof(int); + val = nlk->flags & NETLINK_F_CAP_ACK ? 1 : 0; + if (put_user(len, optlen) || + put_user(val, optval)) + return -EFAULT; + err = 0; + break; default: err = -ENOPROTOOPT; } @@ -2873,9 +2891,12 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) struct nlmsghdr *rep; struct nlmsgerr *errmsg; size_t payload = sizeof(*errmsg); + struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk); - /* error messages get the original request appened */ - if (err) + /* Error messages get the original request appened, unless the user + * requests to cap the error message. + */ + if (!(nlk->flags & NETLINK_F_CAP_ACK) && err) payload += nlmsg_len(nlh); skb = netlink_alloc_skb(in_skb->sk, nlmsg_total_size(payload), @@ -2898,7 +2919,7 @@ void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) NLMSG_ERROR, payload, 0); errmsg = nlmsg_data(rep); errmsg->error = err; - memcpy(&errmsg->msg, nlh, err ? nlh->nlmsg_len : sizeof(*nlh)); + memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh)); netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT); } EXPORT_SYMBOL(netlink_ack); -- GitLab From 7084a315897715776d1764f5fd9250609e515beb Mon Sep 17 00:00:00 2001 From: Ken-ichirou MATSUZAWA Date: Fri, 28 Aug 2015 16:05:20 +0900 Subject: [PATCH 5693/7006] netlink: mmap: fix lookup frame position __netlink_lookup_frame() was always called with the same "pos" value in netlink_forward_ring(). It will look at the same ring entry header over and over again, every time through this loop. Then cycle through the whole ring, advancing ring->head, not "pos" until it equals the "ring->head != head" loop test fails. Signed-off-by: Ken-ichirou MATSUZAWA Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 3eea0b2a3239b..7965ca7c461d3 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -611,11 +611,11 @@ static void netlink_increment_head(struct netlink_ring *ring) static void netlink_forward_ring(struct netlink_ring *ring) { - unsigned int head = ring->head, pos = head; + unsigned int head = ring->head; const struct nl_mmap_hdr *hdr; do { - hdr = __netlink_lookup_frame(ring, pos); + hdr = __netlink_lookup_frame(ring, ring->head); if (hdr->nm_status == NL_MMAP_STATUS_UNUSED) break; if (hdr->nm_status != NL_MMAP_STATUS_SKIP) -- GitLab From 7c5a9461812b21e1a1b7a09a83e97530b8867459 Mon Sep 17 00:00:00 2001 From: lucien Date: Fri, 28 Aug 2015 17:45:58 +0800 Subject: [PATCH 5694/7006] sctp: ASCONF-ACK with Unresolvable Address should be sent RFC 5061: This is an opaque integer assigned by the sender to identify each request parameter. The receiver of the ASCONF Chunk will copy this 32-bit value into the ASCONF Response Correlation ID field of the ASCONF-ACK response parameter. The sender of the ASCONF can use this same value in the ASCONF-ACK to find which request the response is for. Note that the receiver MUST NOT change this 32-bit value. Address Parameter: TLV This field contains an IPv4 or IPv6 address parameter, as described in Section 3.3.2.1 of [RFC4960]. ASCONF chunk with Error Cause Indication Parameter (Unresolvable Address) should be sent if the Delete IP Address is not part of the association. Endpoint A Endpoint B (ESTABLISHED) (ESTABLISHED) ASCONF -----------------> (Delete IP Address) <----------------- ASCONF-ACK (Unresolvable Address) Signed-off-by: Xin Long Acked-by: Vlad Yasevich Acked-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/sm_make_chunk.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index a655ddc3f3530..7954c52e17944 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -3090,8 +3090,19 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, sctp_assoc_set_primary(asoc, asconf->transport); sctp_assoc_del_nonprimary_peers(asoc, asconf->transport); - } else - sctp_assoc_del_peer(asoc, &addr); + return SCTP_ERROR_NO_ERROR; + } + + /* If the address is not part of the association, the + * ASCONF-ACK with Error Cause Indication Parameter + * which including cause of Unresolvable Address should + * be sent. + */ + peer = sctp_assoc_lookup_paddr(asoc, &addr); + if (!peer) + return SCTP_ERROR_DNS_FAILED; + + sctp_assoc_rm_peer(asoc, peer); break; case SCTP_PARAM_SET_PRIMARY: /* ADDIP Section 4.2.4 -- GitLab From f375339e497582ea0bc8806a0552add1cabb6d4e Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 28 Aug 2015 16:55:10 +0300 Subject: [PATCH 5695/7006] ravb: propagate platform_get_irq() error upstream The driver overrides the error returned by platform_get_irq() with -ENODEV which e.g. precludes the deferred probing from working. Propagate the real error code to the driver core instead. Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/ravb_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/renesas/ravb_main.c b/drivers/net/ethernet/renesas/ravb_main.c index 78849dd4ef8e9..44b37141d1255 100644 --- a/drivers/net/ethernet/renesas/ravb_main.c +++ b/drivers/net/ethernet/renesas/ravb_main.c @@ -1643,7 +1643,7 @@ static int ravb_probe(struct platform_device *pdev) ndev->dma = -1; irq = platform_get_irq(pdev, 0); if (irq < 0) { - error = -ENODEV; + error = irq; goto out_release; } ndev->irq = irq; -- GitLab From 7a468ac624c80bda76957d8cbc28024f4f68e316 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Fri, 28 Aug 2015 16:56:01 +0300 Subject: [PATCH 5696/7006] sh_eth: propagate platform_get_irq() error upstream The driver overrides the error returned by platform_get_irq() with -ENODEV which e.g. precludes the deferred probing from working. Propagate the real error code to the driver core instead. Signed-off-by: Sergei Shtylyov Acked-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/ethernet/renesas/sh_eth.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c index 7fb244f565b28..257ea713b4c15 100644 --- a/drivers/net/ethernet/renesas/sh_eth.c +++ b/drivers/net/ethernet/renesas/sh_eth.c @@ -3089,10 +3089,8 @@ static int sh_eth_drv_probe(struct platform_device *pdev) ndev->dma = -1; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - ret = -ENODEV; + if (ret < 0) goto out_release; - } ndev->irq = ret; SET_NETDEV_DEV(ndev, &pdev->dev); -- GitLab From b0d4943eec9a42c7ba2065f6cfa949894204dd4a Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Fri, 28 Aug 2015 15:05:32 -0700 Subject: [PATCH 5697/7006] bonding: fix bond_poll_controller bh_enable warning The problem is rcu_read_unlock_bh() which triggers a warning when irqs are disabled. ndo_poll_controller should run with irqs disabled always so we can drop the rcu_read_lock_bh. [ 98.502922] bond0: making interface eth1 the new active one [ 98.503039] ------------[ cut here ]------------ [ 98.503039] WARNING: CPU: 0 PID: 1744 at kernel/softirq.c:150 __local_bh_enable_ip+0x96/0xc0() [ 98.503039] Modules linked in: bonding(OE) rpcsec_gss_krb5 nfsv4 dns_resolver nfs fscache netconsole ppdev joydev parport_pc serio_raw parport i2c_piix4 video acpi_cpufreq nfsd auth_rpcgss nfs_acl lockd grace sunrpc virtio_net e1000 ata_generic pcnet32 mii virtio_pci virtio_ring virtio pata_acpi [ 98.503039] CPU: 0 PID: 1744 Comm: ifenslave Tainted: G OE 4.2.0-rc7+ #56 [ 98.503039] Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 [ 98.503039] 0000000000000000 00000000e96ba230 ffff880020c236b8 ffffffff8183f105 [ 98.503039] 0000000000000000 0000000000000000 ffff880020c236f8 ffffffff810a9496 [ 98.503039] ffff88002ea99e08 0000000000000200 ffffffffa02a8e06 ffff88002ea99e08 [ 98.503039] Call Trace: [ 98.503039] [] dump_stack+0x4c/0x65 [ 98.503039] [] warn_slowpath_common+0x86/0xc0 [ 98.503039] [] ? bond_poll_controller+0x146/0x250 [bonding] [ 98.503039] [] warn_slowpath_null+0x1a/0x20 [ 98.503039] [] __local_bh_enable_ip+0x96/0xc0 [ 98.503039] [] bond_poll_controller+0x16f/0x250 [bonding] [ 98.503039] [] ? bond_poll_controller+0x33/0x250 [bonding] [ 98.503039] [] ? trace_hardirqs_off+0xd/0x10 [ 98.503039] [] ? _raw_spin_unlock_irqrestore+0x5b/0x60 [ 98.503039] [] netpoll_poll_dev+0x6e/0x350 [ 98.503039] [] ? netpoll_start_xmit+0x137/0x1d0 [ 98.503039] [] ? __alloc_skb+0x5b/0x210 [ 98.503039] [] netpoll_send_skb_on_dev+0x12d/0x2a0 [ 98.503039] [] netpoll_send_udp+0x2ce/0x430 [ 98.503039] [] write_msg+0xb0/0xf0 [netconsole] [ 98.503039] [] call_console_drivers.constprop.25+0x133/0x260 [ 98.503039] [] console_unlock+0x2f4/0x580 [ 98.503039] [] ? vprintk_emit+0x2e5/0x630 [ 98.503039] [] vprintk_emit+0x325/0x630 [ 98.503039] [] vprintk_default+0x29/0x40 [ 98.503039] [] printk+0x55/0x6b [ 98.503039] [] __netdev_printk+0x16c/0x260 [ 98.503039] [] netdev_info+0x62/0x80 [ 98.503039] [] bond_change_active_slave+0x134/0x6a0 [bonding] [ 98.503039] [] bond_select_active_slave+0xc5/0x310 [bonding] [ 98.503039] [] bond_enslave+0x1088/0x10c0 [bonding] [ 98.503039] [] bond_do_ioctl+0x37b/0x400 [bonding] [ 98.503039] [] ? trace_hardirqs_on+0xd/0x10 [ 98.503039] [] ? rtnl_lock+0x17/0x20 [ 98.503039] [] dev_ifsioc+0x331/0x3e0 [ 98.503039] [] dev_ioctl+0xec/0x6c0 [ 98.503039] [] sock_do_ioctl+0x4a/0x60 [ 98.503039] [] sock_ioctl+0x1c0/0x250 [ 98.503039] [] do_vfs_ioctl+0x2ee/0x540 [ 98.503039] [] ? up_read+0x23/0x40 [ 98.503039] [] ? __do_page_fault+0x1d3/0x420 [ 98.503039] [] ? __fget_light+0x66/0x90 [ 98.503039] [] SyS_ioctl+0x79/0x90 [ 98.503039] [] entry_SYSCALL_64_fastpath+0x12/0x76 [ 98.503039] ---[ end trace 00cfa804b0670051 ]--- Fixes: 616f45416ca0 ("bonding: implement bond_poll_controller()") Signed-off-by: Nikolay Aleksandrov Acked-by: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a98dd4f1b0e33..7ab72692d7fda 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -979,7 +979,6 @@ static void bond_poll_controller(struct net_device *bond_dev) if (bond_3ad_get_active_agg_info(bond, &ad_info)) return; - rcu_read_lock_bh(); bond_for_each_slave_rcu(bond, slave, iter) { ops = slave->dev->netdev_ops; if (!bond_slave_is_up(slave) || !ops->ndo_poll_controller) @@ -1000,7 +999,6 @@ static void bond_poll_controller(struct net_device *bond_dev) ops->ndo_poll_controller(slave->dev); up(&ni->dev_lock); } - rcu_read_unlock_bh(); } static void bond_netpoll_cleanup(struct net_device *bond_dev) -- GitLab From 73e6742027f5cb5a7c747d9abab5351b01fd4c74 Mon Sep 17 00:00:00 2001 From: Vlad Yasevich Date: Fri, 28 Aug 2015 21:23:39 -0400 Subject: [PATCH 5698/7006] sctp: Do not try to search for the transport twice When removing an non-primary transport during ASCONF processing, we end up traversing the transport list twice: once in sctp_cmd_del_non_primary, and once in sctp_assoc_del_peer. We can avoid the second search and call sctp_assoc_rm_peer() instead. Found by code inspection during code reviews. Signed-off-by: Vladislav Yasevich Signed-off-by: David S. Miller --- net/sctp/sm_sideeffect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 85e6f03aeb700..35df1266bf073 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -954,7 +954,7 @@ static void sctp_cmd_del_non_primary(struct sctp_association *asoc) t = list_entry(pos, struct sctp_transport, transports); if (!sctp_cmp_addr_exact(&t->ipaddr, &asoc->peer.primary_addr)) { - sctp_assoc_del_peer(asoc, &t->ipaddr); + sctp_assoc_rm_peer(asoc, t); } } } -- GitLab From 22c103cd3dfadff340b3b639e477a3c161cb2104 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Sat, 29 Aug 2015 10:38:46 +0900 Subject: [PATCH 5699/7006] ALSA: fireworks/bebob/dice/oxfw: fix substreams counting at vmalloc failure In PCM core, when hw_params() in each driver returns error, the state of PCM substream is kept as 'open'. In this case, current drivers for sound units on IEEE 1394 bus doesn't decrement substream counter in hw_free() correctly. This causes these drivers to keep streams even if not required. This commit fixes this bug. When snd_pcm_lib_alloc_vmalloc_buffer() fails, hw_params function in each driver returns without incrementing the counter. Reported-by: Takashi Iwai Signed-off-by: Takashi Sakamoto Acked-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/firewire/bebob/bebob_pcm.c | 20 ++++++++++++++++---- sound/firewire/dice/dice-pcm.c | 18 ++++++++++++++---- sound/firewire/fireworks/fireworks_pcm.c | 18 ++++++++++++++---- sound/firewire/oxfw/oxfw-pcm.c | 17 +++++++++++++---- 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/sound/firewire/bebob/bebob_pcm.c b/sound/firewire/bebob/bebob_pcm.c index 7a2c1f53bc443..c0f018a61fdc0 100644 --- a/sound/firewire/bebob/bebob_pcm.c +++ b/sound/firewire/bebob/bebob_pcm.c @@ -211,26 +211,38 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_bebob *bebob = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&bebob->substreams_counter); amdtp_stream_set_pcm_format(&bebob->tx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + + return 0; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_bebob *bebob = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&bebob->substreams_counter); amdtp_stream_set_pcm_format(&bebob->rx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + + return 0; } static int diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index f77714511f8b5..4e67b1da0fe6f 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c @@ -230,6 +230,12 @@ static int capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&dice->mutex); @@ -240,13 +246,18 @@ static int capture_hw_params(struct snd_pcm_substream *substream, amdtp_stream_set_pcm_format(&dice->tx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return 0; } static int playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_dice *dice = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&dice->mutex); @@ -257,8 +268,7 @@ static int playback_hw_params(struct snd_pcm_substream *substream, amdtp_stream_set_pcm_format(&dice->rx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return 0; } static int capture_hw_free(struct snd_pcm_substream *substream) diff --git a/sound/firewire/fireworks/fireworks_pcm.c b/sound/firewire/fireworks/fireworks_pcm.c index 8a34753de2108..c30b2ffa8dfb1 100644 --- a/sound/firewire/fireworks/fireworks_pcm.c +++ b/sound/firewire/fireworks/fireworks_pcm.c @@ -244,25 +244,35 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_efw *efw = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&efw->capture_substreams); amdtp_stream_set_pcm_format(&efw->tx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return 0; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_efw *efw = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) atomic_inc(&efw->playback_substreams); amdtp_stream_set_pcm_format(&efw->rx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return 0; } static int pcm_capture_hw_free(struct snd_pcm_substream *substream) diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c index 67ade0775a5b2..9c73930d02788 100644 --- a/sound/firewire/oxfw/oxfw-pcm.c +++ b/sound/firewire/oxfw/oxfw-pcm.c @@ -231,7 +231,12 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_oxfw *oxfw = substream->private_data; + int err; + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&oxfw->mutex); @@ -241,13 +246,18 @@ static int pcm_capture_hw_params(struct snd_pcm_substream *substream, amdtp_stream_set_pcm_format(&oxfw->tx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return 0; } static int pcm_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { struct snd_oxfw *oxfw = substream->private_data; + int err; + + err = snd_pcm_lib_alloc_vmalloc_buffer(substream, + params_buffer_bytes(hw_params)); + if (err < 0) + return err; if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) { mutex_lock(&oxfw->mutex); @@ -257,8 +267,7 @@ static int pcm_playback_hw_params(struct snd_pcm_substream *substream, amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params)); - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); + return 0; } static int pcm_capture_hw_free(struct snd_pcm_substream *substream) -- GitLab From f6d3c19274c74ff17174df8078e0a14df003667f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Fri, 28 Aug 2015 08:42:09 -0700 Subject: [PATCH 5700/7006] net: FIB tracepoints A few useful tracepoints developing VRF driver. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/trace/events/fib.h | 111 +++++++++++++++++++++++++++++++++++++ net/core/net-traces.c | 1 + net/ipv4/fib_frontend.c | 3 + net/ipv4/fib_trie.c | 5 ++ 4 files changed, 120 insertions(+) create mode 100644 include/trace/events/fib.h diff --git a/include/trace/events/fib.h b/include/trace/events/fib.h new file mode 100644 index 0000000000000..4030f75410d72 --- /dev/null +++ b/include/trace/events/fib.h @@ -0,0 +1,111 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM fib + +#if !defined(_TRACE_FIB_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_FIB_H + +#include +#include +#include +#include + +TRACE_EVENT(fib_table_lookup, + + TP_PROTO(int tb_id, const struct flowi4 *flp), + + TP_ARGS(tb_id, flp), + + TP_STRUCT__entry( + __field( int, tb_id ) + __field( int, oif ) + __field( int, iif ) + __field( __u8, tos ) + __field( __u8, scope ) + __field( __u8, flags ) + __array( __u8, src, 4 ) + __array( __u8, dst, 4 ) + ), + + TP_fast_assign( + __be32 *p32; + + __entry->tb_id = tb_id; + __entry->oif = flp->flowi4_oif; + __entry->iif = flp->flowi4_iif; + __entry->tos = flp->flowi4_tos; + __entry->scope = flp->flowi4_scope; + __entry->flags = flp->flowi4_flags; + + p32 = (__be32 *) __entry->src; + *p32 = flp->saddr; + + p32 = (__be32 *) __entry->dst; + *p32 = flp->daddr; + ), + + TP_printk("table %d oif %d iif %d src %pI4 dst %pI4 tos %d scope %d flags %x", + __entry->tb_id, __entry->oif, __entry->iif, + __entry->src, __entry->dst, __entry->tos, __entry->scope, + __entry->flags) +); + +TRACE_EVENT(fib_table_lookup_nh, + + TP_PROTO(const struct fib_nh *nh), + + TP_ARGS(nh), + + TP_STRUCT__entry( + __string( name, nh->nh_dev->name) + __field( int, oif ) + __array( __u8, src, 4 ) + ), + + TP_fast_assign( + __be32 *p32 = (__be32 *) __entry->src; + + __assign_str(name, nh->nh_dev ? nh->nh_dev->name : "not set"); + __entry->oif = nh->nh_oif; + *p32 = nh->nh_saddr; + ), + + TP_printk("nexthop dev %s oif %d src %pI4", + __get_str(name), __entry->oif, __entry->src) +); + +TRACE_EVENT(fib_validate_source, + + TP_PROTO(const struct net_device *dev, const struct flowi4 *flp), + + TP_ARGS(dev, flp), + + TP_STRUCT__entry( + __string( name, dev->name ) + __field( int, oif ) + __field( int, iif ) + __array( __u8, src, 4 ) + __array( __u8, dst, 4 ) + ), + + TP_fast_assign( + __be32 *p32; + + __assign_str(name, dev ? dev->name : "not set"); + __entry->oif = flp->flowi4_oif; + __entry->iif = flp->flowi4_iif; + + p32 = (__be32 *) __entry->src; + *p32 = flp->saddr; + + p32 = (__be32 *) __entry->dst; + *p32 = flp->daddr; + ), + + TP_printk("dev %s oif %d iif %d src %pI4 dst %pI4", + __get_str(name), __entry->oif, __entry->iif, + __entry->src, __entry->dst) +); +#endif /* _TRACE_FIB_H */ + +/* This part must be outside protection */ +#include diff --git a/net/core/net-traces.c b/net/core/net-traces.c index ba3c0120786c8..adef015b2f417 100644 --- a/net/core/net-traces.c +++ b/net/core/net-traces.c @@ -31,6 +31,7 @@ #include #include #include +#include EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb); diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 7fa277176c33b..4036c94dfbe14 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -46,6 +46,7 @@ #include #include #include +#include #ifndef CONFIG_IP_MULTIPLE_TABLES @@ -344,6 +345,8 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0; + trace_fib_validate_source(dev, &fl4); + net = dev_net(dev); if (fib_lookup(net, &fl4, &res, 0)) goto last_resort; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5154f81c53266..26d6ffb6d23cd 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -81,6 +81,7 @@ #include #include #include +#include #include "fib_lookup.h" #define MAX_STAT_DEPTH 32 @@ -1278,6 +1279,8 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, unsigned long index; t_key cindex; + trace_fib_table_lookup(tb->tb_id, flp); + pn = t->kv; cindex = 0; @@ -1442,6 +1445,8 @@ found: #ifdef CONFIG_IP_FIB_TRIE_STATS this_cpu_inc(stats->semantic_match_passed); #endif + trace_fib_table_lookup_nh(nh); + return err; } } -- GitLab From 46fa062ad63146dd138ec0f017e71224471e8ea5 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 28 Aug 2015 20:48:19 +0200 Subject: [PATCH 5701/7006] ip_tunnels: convert the mode field of ip_tunnel_info to flags The mode field holds a single bit of information only (whether the ip_tunnel_info struct is for rx or tx). Change the mode field to bit flags. This allows more mode flags to be added. Signed-off-by: Jiri Benc Acked-by: Alexei Starovoitov Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/geneve.c | 2 +- drivers/net/vxlan.c | 2 +- include/net/dst_metadata.h | 1 - include/net/ip_tunnels.h | 9 ++------- net/ipv4/ip_gre.c | 2 +- net/ipv4/route.c | 2 +- net/ipv6/route.c | 2 +- 7 files changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 4357bae732d73..4a39c09f144c0 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -623,7 +623,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) if (geneve->collect_md) { info = skb_tunnel_info(skb); - if (unlikely(info && info->mode != IP_TUNNEL_INFO_TX)) { + if (unlikely(info && !(info->mode & IP_TUNNEL_INFO_TX))) { netdev_dbg(dev, "no tunnel metadata\n"); goto tx_error; } diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 30e56cb588849..bd1b8cdf2bf6f 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2113,7 +2113,7 @@ static netdev_tx_t vxlan_xmit(struct sk_buff *skb, struct net_device *dev) } if (vxlan->flags & VXLAN_F_COLLECT_METADATA && - info && info->mode == IP_TUNNEL_INFO_TX) { + info && info->mode & IP_TUNNEL_INFO_TX) { vxlan_xmit_one(skb, dev, NULL, false); return NETDEV_TX_OK; } diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 60c03326c0876..2b83f0d232e09 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -59,7 +59,6 @@ static inline struct metadata_dst *tun_rx_dst(__be16 flags, return NULL; info = &tun_dst->u.tun_info; - info->mode = IP_TUNNEL_INFO_RX; info->key.tun_flags = flags; info->key.tun_id = tunnel_id; info->key.tp_src = 0; diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 224e4ecec91b7..9bdb3948798fd 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -50,13 +50,8 @@ struct ip_tunnel_key { __be16 tp_dst; }; -/* Indicates whether the tunnel info structure represents receive - * or transmit tunnel parameters. - */ -enum { - IP_TUNNEL_INFO_RX, - IP_TUNNEL_INFO_TX, -}; +/* Flags for ip_tunnel_info mode. */ +#define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */ struct ip_tunnel_info { struct ip_tunnel_key key; diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index faf1cde6f8da2..1e813a9f9378f 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -511,7 +511,7 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) int err; tun_info = skb_tunnel_info(skb); - if (unlikely(!tun_info || tun_info->mode != IP_TUNNEL_INFO_TX)) + if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX))) goto err_free_skb; key = &tun_info->key; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 6b91879e9cbe5..5f4a5565ad8b3 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -1696,7 +1696,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, */ tun_info = skb_tunnel_info(skb); - if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX) + if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX)) fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id; else fl4.flowi4_tun_key.tun_id = 0; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index df3e353a012d0..308dd5f9158f1 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1174,7 +1174,7 @@ void ip6_route_input(struct sk_buff *skb) }; tun_info = skb_tunnel_info(skb); - if (tun_info && tun_info->mode == IP_TUNNEL_INFO_RX) + if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX)) fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id; skb_dst_drop(skb); skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags)); -- GitLab From 7f9562a1f405306eacb97f95d78cb996e33f27f5 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 28 Aug 2015 20:48:20 +0200 Subject: [PATCH 5702/7006] ip_tunnels: record IP version in tunnel info There's currently nothing preventing directing packets with IPv6 encapsulation data to IPv4 tunnels (and vice versa). If this happens, IPv6 addresses are incorrectly interpreted as IPv4 ones. Track whether the given ip_tunnel_key contains IPv4 or IPv6 data. Store this in ip_tunnel_info. Reject packets at appropriate places if they are supposed to be encapsulated into an incompatible protocol. Signed-off-by: Jiri Benc Acked-by: Alexei Starovoitov Acked-by: Thomas Graf Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- drivers/net/geneve.c | 2 ++ drivers/net/vxlan.c | 2 ++ include/net/dst_metadata.h | 1 + include/net/ip_tunnels.h | 10 ++++++++++ net/core/filter.c | 2 ++ net/ipv4/ip_gre.c | 3 ++- net/ipv4/ip_tunnel_core.c | 2 +- net/openvswitch/flow.c | 2 ++ net/openvswitch/vport.c | 2 ++ 9 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 4a39c09f144c0..3908a22f23d18 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -627,6 +627,8 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) netdev_dbg(dev, "no tunnel metadata\n"); goto tx_error; } + if (info && ip_tunnel_info_af(info) != AF_INET) + goto tx_error; } rt = geneve_get_rt(skb, dev, &fl4, info); diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index bd1b8cdf2bf6f..e3adfe0ef66b3 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1903,6 +1903,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, dev->name); goto drop; } + if (family != ip_tunnel_info_af(info)) + goto drop; dst_port = info->key.tp_dst ? : vxlan->cfg.dst_port; vni = be64_to_cpu(info->key.tun_id); diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 2b83f0d232e09..d32f49cc621d2 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -105,6 +105,7 @@ static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb, info->key.u.ipv6.dst = ip6h->daddr; info->key.tos = ipv6_get_dsfield(ip6h); info->key.ttl = ip6h->hop_limit; + info->mode = IP_TUNNEL_INFO_IPV6; return tun_dst; } diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 9bdb3948798fd..2b4fa06e91bde 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,7 @@ struct ip_tunnel_key { /* Flags for ip_tunnel_info mode. */ #define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */ +#define IP_TUNNEL_INFO_IPV6 0x02 /* key contains IPv6 addresses */ struct ip_tunnel_info { struct ip_tunnel_key key; @@ -208,6 +210,8 @@ static inline void __ip_tunnel_info_init(struct ip_tunnel_info *tun_info, tun_info->options = opts; tun_info->options_len = opts_len; + + tun_info->mode = 0; } static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info, @@ -221,6 +225,12 @@ static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info, tun_id, tun_flags, opts, opts_len); } +static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info + *tun_info) +{ + return tun_info->mode & IP_TUNNEL_INFO_IPV6 ? AF_INET6 : AF_INET; +} + #ifdef CONFIG_INET int ip_tunnel_init(struct net_device *dev); diff --git a/net/core/filter.c b/net/core/filter.c index 66500d4909951..13079f03902e7 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -1493,6 +1493,8 @@ static u64 bpf_skb_get_tunnel_key(u64 r1, u64 r2, u64 size, u64 flags, u64 r5) if (unlikely(size != sizeof(struct bpf_tunnel_key) || flags || !info)) return -EINVAL; + if (ip_tunnel_info_af(info) != AF_INET) + return -EINVAL; to->tunnel_id = be64_to_cpu(info->key.tun_id); to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src); diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 1e813a9f9378f..bd0679d90519b 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -511,7 +511,8 @@ static void gre_fb_xmit(struct sk_buff *skb, struct net_device *dev) int err; tun_info = skb_tunnel_info(skb); - if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX))) + if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || + ip_tunnel_info_af(tun_info) != AF_INET)) goto err_free_skb; key = &tun_info->key; diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 934f2ac8ad610..0c756ade1cf71 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -356,7 +356,7 @@ static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr, if (tb[LWTUNNEL_IP6_FLAGS]) tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]); - tun_info->mode = IP_TUNNEL_INFO_TX; + tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6; tun_info->options = NULL; tun_info->options_len = 0; diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 5a3195e538ce5..9760dc43bdb99 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -688,6 +688,8 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, { /* Extract metadata from packet. */ if (tun_info) { + if (ip_tunnel_info_af(tun_info) != AF_INET) + return -EINVAL; memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key)); if (tun_info->options) { diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index e2dc9dac59e68..40164037928e7 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -587,6 +587,8 @@ int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, if (unlikely(!tun_info)) return -EINVAL; + if (ip_tunnel_info_af(tun_info) != AF_INET) + return -EINVAL; tun_key = &tun_info->key; -- GitLab From b9b6695cf0e1afebc207e28c7e9350c90547a426 Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 28 Aug 2015 20:48:21 +0200 Subject: [PATCH 5703/7006] fou: reject IPv6 config fou does not really support IPv6 encapsulation. After an UDP socket is created in fou_create, the encap_rcv callback is set either to fou_udp_recv or to gue_udp_recv. Both of those unconditionally assume that the received packet has an IPv4 header and access the data at network_header as it was an IPv4 header. This leads to IPv6 flow label being interpreted as IP packet length, etc. Disallow fou tunnel to be configured as IPv6 until real IPv6 support is added to fou. CC: Tom Herbert Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- net/ipv4/fou.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 2d1646cff0572..e0fcbbbcfe54d 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c @@ -566,7 +566,7 @@ static int parse_nl_config(struct genl_info *info, if (info->attrs[FOU_ATTR_AF]) { u8 family = nla_get_u8(info->attrs[FOU_ATTR_AF]); - if (family != AF_INET && family != AF_INET6) + if (family != AF_INET) return -EINVAL; cfg->udp_config.family = family; -- GitLab From a43a9ef6a2e510fec61176ff2c34fab3e7d581da Mon Sep 17 00:00:00 2001 From: Jiri Benc Date: Fri, 28 Aug 2015 20:48:22 +0200 Subject: [PATCH 5704/7006] vxlan: do not receive IPv4 packets on IPv6 socket By default (subject to the sysctl settings), IPv6 sockets listen also for IPv4 traffic. Vxlan is not prepared for that and expects IPv6 header in packets received through an IPv6 socket. In addition, it's currently not possible to have both IPv4 and IPv6 vxlan tunnel on the same port (unless bindv6only sysctl is enabled), as it's not possible to create and bind both IPv4 and IPv6 vxlan interfaces and there's no way to specify both IPv4 and IPv6 remote/group IP addresses. Set IPV6_V6ONLY on vxlan sockets to fix both of these issues. This is not done globally in udp_tunnel, as l2tp and tipc seems to work okay when receiving IPv4 packets on IPv6 socket and people may rely on this behavior. The other tunnels (geneve and fou) do not support IPv6. Signed-off-by: Jiri Benc Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 1 + include/net/udp_tunnel.h | 3 ++- net/ipv6/ip6_udp_tunnel.c | 9 +++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index e3adfe0ef66b3..6c5269aea5447 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -2530,6 +2530,7 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6, udp_conf.family = AF_INET6; udp_conf.use_udp6_rx_checksums = !(flags & VXLAN_F_UDP_ZERO_CSUM6_RX); + udp_conf.ipv6_v6only = 1; } else { udp_conf.family = AF_INET; } diff --git a/include/net/udp_tunnel.h b/include/net/udp_tunnel.h index 35041d0fc21ed..cb2f89f20f5c9 100644 --- a/include/net/udp_tunnel.h +++ b/include/net/udp_tunnel.h @@ -31,7 +31,8 @@ struct udp_port_cfg { __be16 peer_udp_port; unsigned int use_udp_checksums:1, use_udp6_tx_checksums:1, - use_udp6_rx_checksums:1; + use_udp6_rx_checksums:1, + ipv6_v6only:1; }; int udp_sock_create4(struct net *net, struct udp_port_cfg *cfg, diff --git a/net/ipv6/ip6_udp_tunnel.c b/net/ipv6/ip6_udp_tunnel.c index e1a1136bda7c8..14dacf1df529d 100644 --- a/net/ipv6/ip6_udp_tunnel.c +++ b/net/ipv6/ip6_udp_tunnel.c @@ -23,6 +23,15 @@ int udp_sock_create6(struct net *net, struct udp_port_cfg *cfg, if (err < 0) goto error; + if (cfg->ipv6_v6only) { + int val = 1; + + err = kernel_setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (char *) &val, sizeof(val)); + if (err < 0) + goto error; + } + udp6_addr.sin6_family = AF_INET6; memcpy(&udp6_addr.sin6_addr, &cfg->local_ip6, sizeof(udp6_addr.sin6_addr)); -- GitLab From f892a84cc890aaaba7bc42daf2e2ee86b0961884 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Fri, 28 Aug 2015 11:50:15 -0700 Subject: [PATCH 5705/7006] net/smsc911x: Fix deferred probe for interrupt The interrupt handler may not be available when smsc911x probes if the interrupt handler is a GPIO controller for example. Let's fix that by adding handling for -EPROBE_DEFER. Cc: Steve Glendinning Signed-off-by: Tony Lindgren Signed-off-by: David S. Miller --- drivers/net/ethernet/smsc/smsc911x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/smsc/smsc911x.c b/drivers/net/ethernet/smsc/smsc911x.c index 959aeeade0c97..cb9f166f907ea 100644 --- a/drivers/net/ethernet/smsc/smsc911x.c +++ b/drivers/net/ethernet/smsc/smsc911x.c @@ -2435,7 +2435,10 @@ static int smsc911x_drv_probe(struct platform_device *pdev) res_size = resource_size(res); irq = platform_get_irq(pdev, 0); - if (irq <= 0) { + if (irq == -EPROBE_DEFER) { + retval = -EPROBE_DEFER; + goto out_0; + } else if (irq <= 0) { pr_warn("Could not allocate irq resource\n"); retval = -ENODEV; goto out_0; -- GitLab From c30da497893718abc6cec4f1d34d35875200edee Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Sat, 29 Aug 2015 09:02:21 +0900 Subject: [PATCH 5706/7006] openvswitch: retain parsed IPv6 header fields in flow on error skipping extension headers When an error occurs skipping IPv6 extension headers retain the already parsed IP protocol and IPv6 addresses in the flow. Also assume that the packet is not a fragment in the absence of information to the contrary; that is always use the frag_off value set by ipv6_skip_exthdr(). This allows matching on the IP protocol and IPv6 addresses of packets with malformed extension headers. Signed-off-by: Simon Horman Signed-off-by: David S. Miller --- net/openvswitch/flow.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 9760dc43bdb99..9db87331e2111 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -272,8 +272,6 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) key->ipv6.addr.dst = nh->daddr; payload_ofs = ipv6_skip_exthdr(skb, payload_ofs, &nexthdr, &frag_off); - if (unlikely(payload_ofs < 0)) - return -EINVAL; if (frag_off) { if (frag_off & htons(~0x7)) @@ -284,6 +282,13 @@ static int parse_ipv6hdr(struct sk_buff *skb, struct sw_flow_key *key) key->ip.frag = OVS_FRAG_TYPE_NONE; } + /* Delayed handling of error in ipv6_skip_exthdr() as it + * always sets frag_off to a valid value which may be + * used to set key->ip.frag above. + */ + if (unlikely(payload_ofs < 0)) + return -EPROTO; + nh_len = payload_ofs - nh_ofs; skb_set_transport_header(skb, nh_ofs + nh_len); key->ip.proto = nexthdr; @@ -623,12 +628,16 @@ static int key_extract(struct sk_buff *skb, struct sw_flow_key *key) nh_len = parse_ipv6hdr(skb, key); if (unlikely(nh_len < 0)) { - memset(&key->ip, 0, sizeof(key->ip)); - memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr)); - if (nh_len == -EINVAL) { + switch (nh_len) { + case -EINVAL: + memset(&key->ip, 0, sizeof(key->ip)); + memset(&key->ipv6.addr, 0, sizeof(key->ipv6.addr)); + /* fall-through */ + case -EPROTO: skb->transport_header = skb->network_header; error = 0; - } else { + break; + default: error = nh_len; } return error; -- GitLab From 0c78789e3a030615c6650fde89546cadf40ec2cc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 29 Aug 2015 13:36:30 -0700 Subject: [PATCH 5707/7006] SUNRPC: xs_reset_transport must mark the connection as disconnected In case the reconnection attempt fails. Cc: stable@vger.kernel.org Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 723df7cb096df..214ca9dfb14ec 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -829,6 +829,7 @@ static void xs_reset_transport(struct sock_xprt *transport) sk->sk_user_data = NULL; xs_restore_old_callbacks(transport, sk); + xprt_clear_connected(xprt); write_unlock_bh(&sk->sk_callback_lock); xs_sock_reset_connection_flags(xprt); -- GitLab From 8e816df87997bb0c40122d5df621423b445c4fe6 Mon Sep 17 00:00:00 2001 From: Jesse Gross Date: Fri, 28 Aug 2015 16:54:40 -0700 Subject: [PATCH 5708/7006] geneve: Use GRO cells infrastructure. Geneve can benefit from GRO at the device level in a manner similar to other tunnels, especially as hardware offloads are still emerging. After this patch, aggregated frames are seen on the tunnel interface. Single stream throughput nearly doubles in ideal circumstances (on old hardware). Signed-off-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/geneve.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 3908a22f23d18..68b0f0325fc70 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ struct geneve_dev { struct list_head next; /* geneve's per namespace list */ __be16 dst_port; bool collect_md; + struct gro_cells gro_cells; }; struct geneve_sock { @@ -199,7 +201,7 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) stats->rx_bytes += skb->len; u64_stats_update_end(&stats->syncp); - netif_rx(skb); + gro_cells_receive(&geneve->gro_cells, skb); return; drop: /* Consume bad packet */ @@ -209,14 +211,27 @@ drop: /* Setup stats when device is created */ static int geneve_init(struct net_device *dev) { + struct geneve_dev *geneve = netdev_priv(dev); + int err; + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; + + err = gro_cells_init(&geneve->gro_cells, dev); + if (err) { + free_percpu(dev->tstats); + return err; + } + return 0; } static void geneve_uninit(struct net_device *dev) { + struct geneve_dev *geneve = netdev_priv(dev); + + gro_cells_destroy(&geneve->gro_cells); free_percpu(dev->tstats); } -- GitLab From 24d43f32d86026a0e318fee736380e164d85eefa Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sat, 29 Aug 2015 17:44:05 -0700 Subject: [PATCH 5709/7006] openvswitch: Remove vport get_name() Remove unused get_name() function pointer from vport ops. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/vport.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index b88b3ee86f079..2f352446b6a8f 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -157,7 +157,6 @@ struct vport_parms { * @get_options: Appends vport-specific attributes for the configuration of an * existing vport to a &struct sk_buff. May be %NULL for a vport that does not * have any configuration. - * @get_name: Get the device's name. * @send: Send a packet on the device. Returns the length of the packet sent, * zero for dropped packets or negative for error. * @get_egress_tun_info: Get the egress tunnel 5-tuple and other info for @@ -173,9 +172,6 @@ struct vport_ops { int (*set_options)(struct vport *, struct nlattr *); int (*get_options)(const struct vport *, struct sk_buff *); - /* Called with rcu_read_lock or ovs_mutex. */ - const char *(*get_name)(const struct vport *); - int (*send)(struct vport *, struct sk_buff *); int (*get_egress_tun_info)(struct vport *, struct sk_buff *, struct ip_tunnel_info *); @@ -239,7 +235,7 @@ static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, static inline const char *ovs_vport_name(struct vport *vport) { - return vport->dev ? vport->dev->name : vport->ops->get_name(vport); + return vport->dev->name; } int ovs_vport_ops_register(struct vport_ops *ops); -- GitLab From 3eedb41fb43461b5fde3f72fd00a7706f0b90103 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sat, 29 Aug 2015 17:44:06 -0700 Subject: [PATCH 5710/7006] openvswitch: Remove egress_tun_info. tun info is passed using skb-dst pointer. Now we have converted all vports to netdev based implementation so Now we can remove redundant pointer to tun-info from OVS_CB. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/actions.c | 5 ----- net/openvswitch/datapath.c | 1 - net/openvswitch/datapath.h | 3 --- net/openvswitch/vport-geneve.c | 3 +-- net/openvswitch/vport-gre.c | 3 +-- net/openvswitch/vport-vxlan.c | 3 +-- net/openvswitch/vport.c | 6 +++--- net/openvswitch/vport.h | 3 +-- 8 files changed, 7 insertions(+), 20 deletions(-) diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 4487543806bbe..090d9e3a460c2 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -896,10 +896,6 @@ static int execute_set_action(struct sk_buff *skb, skb_dst_drop(skb); dst_hold((struct dst_entry *)tun->tun_dst); skb_dst_set(skb, (struct dst_entry *)tun->tun_dst); - - /* FIXME: Remove when all vports have been converted */ - OVS_CB(skb)->egress_tun_info = &tun->tun_dst->u.tun_info; - return 0; } @@ -1159,7 +1155,6 @@ int ovs_execute_actions(struct datapath *dp, struct sk_buff *skb, int err; this_cpu_inc(exec_actions_level); - OVS_CB(skb)->egress_tun_info = NULL; err = do_execute_actions(dp, skb, key, acts->actions, acts->actions_len); diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index ec0f8d9cee731..60c2ab8e6bc30 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -610,7 +610,6 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, struct genl_info *info) goto err_flow_free; rcu_assign_pointer(flow->sf_acts, acts); - OVS_CB(packet)->egress_tun_info = NULL; packet->priority = flow->key.phy.priority; packet->mark = flow->key.phy.skb_mark; diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index 4e785ab889732..da15fd3f3c340 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -94,15 +94,12 @@ struct datapath { /** * struct ovs_skb_cb - OVS data in skb CB - * @egress_tun_key: Tunnel information about this packet on egress path. - * NULL if the packet is not being tunneled. * @input_vport: The original vport packet came in on. This value is cached * when a packet is received by OVS. * @mru: The maximum received fragement size; 0 if the packet is not * fragmented. */ struct ovs_skb_cb { - struct ip_tunnel_info *egress_tun_info; struct vport *input_vport; u16 mru; }; diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index fa37c95f73394..24c56e56feddb 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -62,8 +62,7 @@ static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), - OVS_CB(skb)->egress_tun_info, - IPPROTO_UDP, skb->mark, sport, dport); + skb, IPPROTO_UDP, sport, dport); } static struct vport *geneve_tnl_create(const struct vport_parms *parms) diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index 871801d2ac23e..36c39843607ef 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -89,8 +89,7 @@ static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, { return ovs_tunnel_get_egress_info(egress_tun_info, ovs_dp_get_net(vport->dp), - OVS_CB(skb)->egress_tun_info, - IPPROTO_GRE, skb->mark, 0, 0); + skb, IPPROTO_GRE, 0, 0); } static struct vport_ops ovs_gre_vport_ops = { diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index 1e8b00a23a239..ed7b23f443ec9 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -160,8 +160,7 @@ static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, src_port = udp_flow_src_port(net, skb, 0, 0, true); return ovs_tunnel_get_egress_info(egress_tun_info, net, - OVS_CB(skb)->egress_tun_info, - IPPROTO_UDP, skb->mark, + skb, IPPROTO_UDP, src_port, dst_port); } diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 40164037928e7..e658439a0bdd7 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -483,7 +483,6 @@ void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, u64_stats_update_end(&stats->syncp); OVS_CB(skb)->input_vport = vport; - OVS_CB(skb)->egress_tun_info = NULL; OVS_CB(skb)->mru = 0; /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_key_extract(tun_info, skb, &key); @@ -575,13 +574,14 @@ EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, struct net *net, - const struct ip_tunnel_info *tun_info, + struct sk_buff *skb, u8 ipproto, - u32 skb_mark, __be16 tp_src, __be16 tp_dst) { + const struct ip_tunnel_info *tun_info = skb_tunnel_info(skb); const struct ip_tunnel_key *tun_key; + u32 skb_mark = skb->mark; struct rtable *rt; struct flowi4 fl; diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 2f352446b6a8f..a36aef22af7fe 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -61,9 +61,8 @@ int ovs_vport_send(struct vport *, struct sk_buff *); int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, struct net *net, - const struct ip_tunnel_info *tun_info, + struct sk_buff *, u8 ipproto, - u32 skb_mark, __be16 tp_src, __be16 tp_dst); int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, -- GitLab From 8c876639c98501b049269b554bf4ecbb8f9c012f Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sat, 29 Aug 2015 17:44:07 -0700 Subject: [PATCH 5711/7006] openvswitch: Remove vport stats. Since all vport types are now backed by netdev, we can directly use netdev stats. Following patch removes redundant stat from vport. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/vport-internal_dev.c | 57 ++++++-------- net/openvswitch/vport-netdev.c | 22 ++---- net/openvswitch/vport-netdev.h | 2 +- net/openvswitch/vport.c | 109 +++------------------------ net/openvswitch/vport.h | 36 +++------ 5 files changed, 56 insertions(+), 170 deletions(-) diff --git a/net/openvswitch/vport-internal_dev.c b/net/openvswitch/vport-internal_dev.c index 80b3e12ec8827..388b8a6bf1129 100644 --- a/net/openvswitch/vport-internal_dev.c +++ b/net/openvswitch/vport-internal_dev.c @@ -43,35 +43,26 @@ static struct internal_dev *internal_dev_priv(struct net_device *netdev) return netdev_priv(netdev); } -/* This function is only called by the kernel network layer.*/ -static struct rtnl_link_stats64 *internal_dev_get_stats(struct net_device *netdev, - struct rtnl_link_stats64 *stats) -{ - struct vport *vport = ovs_internal_dev_get_vport(netdev); - struct ovs_vport_stats vport_stats; - - ovs_vport_get_stats(vport, &vport_stats); - - /* The tx and rx stats need to be swapped because the - * switch and host OS have opposite perspectives. */ - stats->rx_packets = vport_stats.tx_packets; - stats->tx_packets = vport_stats.rx_packets; - stats->rx_bytes = vport_stats.tx_bytes; - stats->tx_bytes = vport_stats.rx_bytes; - stats->rx_errors = vport_stats.tx_errors; - stats->tx_errors = vport_stats.rx_errors; - stats->rx_dropped = vport_stats.tx_dropped; - stats->tx_dropped = vport_stats.rx_dropped; - - return stats; -} - /* Called with rcu_read_lock_bh. */ static int internal_dev_xmit(struct sk_buff *skb, struct net_device *netdev) { + int len, err; + + len = skb->len; rcu_read_lock(); - ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL); + err = ovs_vport_receive(internal_dev_priv(netdev)->vport, skb, NULL); rcu_read_unlock(); + + if (likely(!err)) { + struct pcpu_sw_netstats *tstats = this_cpu_ptr(netdev->tstats); + + u64_stats_update_begin(&tstats->syncp); + tstats->tx_bytes += len; + tstats->tx_packets++; + u64_stats_update_end(&tstats->syncp); + } else { + netdev->stats.tx_errors++; + } return 0; } @@ -121,7 +112,6 @@ static const struct net_device_ops internal_dev_netdev_ops = { .ndo_start_xmit = internal_dev_xmit, .ndo_set_mac_address = eth_mac_addr, .ndo_change_mtu = internal_dev_change_mtu, - .ndo_get_stats64 = internal_dev_get_stats, }; static struct rtnl_link_ops internal_dev_link_ops __read_mostly = { @@ -212,18 +202,17 @@ static void internal_dev_destroy(struct vport *vport) rtnl_unlock(); } -static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) +static void internal_dev_recv(struct vport *vport, struct sk_buff *skb) { struct net_device *netdev = vport->dev; - int len; + struct pcpu_sw_netstats *stats; if (unlikely(!(netdev->flags & IFF_UP))) { kfree_skb(skb); - return 0; + netdev->stats.rx_dropped++; + return; } - len = skb->len; - skb_dst_drop(skb); nf_reset(skb); secpath_reset(skb); @@ -233,9 +222,13 @@ static int internal_dev_recv(struct vport *vport, struct sk_buff *skb) skb->protocol = eth_type_trans(skb, netdev); skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); - netif_rx(skb); + stats = this_cpu_ptr(netdev->tstats); + u64_stats_update_begin(&stats->syncp); + stats->rx_packets++; + stats->rx_bytes += skb->len; + u64_stats_update_end(&stats->syncp); - return len; + netif_rx(skb); } static struct vport_ops ovs_internal_vport_ops = { diff --git a/net/openvswitch/vport-netdev.c b/net/openvswitch/vport-netdev.c index a750115050392..f7e8dcce7adae 100644 --- a/net/openvswitch/vport-netdev.c +++ b/net/openvswitch/vport-netdev.c @@ -39,8 +39,11 @@ static struct vport_ops ovs_netdev_vport_ops; /* Must be called with rcu_read_lock. */ -static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) +static void netdev_port_receive(struct sk_buff *skb) { + struct vport *vport; + + vport = ovs_netdev_get_vport(skb->dev); if (unlikely(!vport)) goto error; @@ -56,10 +59,8 @@ static void netdev_port_receive(struct vport *vport, struct sk_buff *skb) skb_push(skb, ETH_HLEN); ovs_skb_postpush_rcsum(skb, skb->data, ETH_HLEN); - ovs_vport_receive(vport, skb, skb_tunnel_info(skb)); return; - error: kfree_skb(skb); } @@ -68,15 +69,11 @@ error: static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb) { struct sk_buff *skb = *pskb; - struct vport *vport; if (unlikely(skb->pkt_type == PACKET_LOOPBACK)) return RX_HANDLER_PASS; - vport = ovs_netdev_get_vport(skb->dev); - - netdev_port_receive(vport, skb); - + netdev_port_receive(skb); return RX_HANDLER_CONSUMED; } @@ -203,27 +200,24 @@ static unsigned int packet_length(const struct sk_buff *skb) return length; } -int ovs_netdev_send(struct vport *vport, struct sk_buff *skb) +void ovs_netdev_send(struct vport *vport, struct sk_buff *skb) { int mtu = vport->dev->mtu; - int len; if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) { net_warn_ratelimited("%s: dropped over-mtu packet: %d > %d\n", vport->dev->name, packet_length(skb), mtu); + vport->dev->stats.tx_errors++; goto drop; } skb->dev = vport->dev; - len = skb->len; dev_queue_xmit(skb); - - return len; + return; drop: kfree_skb(skb); - return 0; } EXPORT_SYMBOL_GPL(ovs_netdev_send); diff --git a/net/openvswitch/vport-netdev.h b/net/openvswitch/vport-netdev.h index 497cc81f1aca8..bf22fcedbc69c 100644 --- a/net/openvswitch/vport-netdev.h +++ b/net/openvswitch/vport-netdev.h @@ -27,7 +27,7 @@ struct vport *ovs_netdev_get_vport(struct net_device *dev); struct vport *ovs_netdev_link(struct vport *vport, const char *name); -int ovs_netdev_send(struct vport *vport, struct sk_buff *skb); +void ovs_netdev_send(struct vport *vport, struct sk_buff *skb); void ovs_netdev_detach_dev(struct vport *); int __init ovs_netdev_init(void); diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index e658439a0bdd7..1679dea7c6bca 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -34,9 +34,6 @@ #include "vport.h" #include "vport-internal_dev.h" -static void ovs_vport_record_error(struct vport *, - enum vport_err_type err_type); - static LIST_HEAD(vport_ops_list); /* Protected by RCU read lock for reading, ovs_mutex for writing. */ @@ -157,12 +154,6 @@ struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *ops, return ERR_PTR(-EINVAL); } - vport->percpu_stats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!vport->percpu_stats) { - kfree(vport); - return ERR_PTR(-ENOMEM); - } - return vport; } EXPORT_SYMBOL_GPL(ovs_vport_alloc); @@ -183,7 +174,6 @@ void ovs_vport_free(struct vport *vport) * it is safe to use raw dereference. */ kfree(rcu_dereference_raw(vport->upcall_portids)); - free_percpu(vport->percpu_stats); kfree(vport); } EXPORT_SYMBOL_GPL(ovs_vport_free); @@ -290,30 +280,24 @@ void ovs_vport_del(struct vport *vport) */ void ovs_vport_get_stats(struct vport *vport, struct ovs_vport_stats *stats) { + struct net_device *dev = vport->dev; int i; memset(stats, 0, sizeof(*stats)); + stats->rx_errors = dev->stats.rx_errors; + stats->tx_errors = dev->stats.tx_errors; + stats->tx_dropped = dev->stats.tx_dropped; + stats->rx_dropped = dev->stats.rx_dropped; - /* We potentially have 2 sources of stats that need to be combined: - * those we have collected (split into err_stats and percpu_stats) from - * set_stats() and device error stats from netdev->get_stats() (for - * errors that happen downstream and therefore aren't reported through - * our vport_record_error() function). - * Stats from first source are reported by ovs (OVS_VPORT_ATTR_STATS). - * netdev-stats can be directly read over netlink-ioctl. - */ - - stats->rx_errors = atomic_long_read(&vport->err_stats.rx_errors); - stats->tx_errors = atomic_long_read(&vport->err_stats.tx_errors); - stats->tx_dropped = atomic_long_read(&vport->err_stats.tx_dropped); - stats->rx_dropped = atomic_long_read(&vport->err_stats.rx_dropped); + stats->rx_dropped += atomic_long_read(&dev->rx_dropped); + stats->tx_dropped += atomic_long_read(&dev->tx_dropped); for_each_possible_cpu(i) { const struct pcpu_sw_netstats *percpu_stats; struct pcpu_sw_netstats local_stats; unsigned int start; - percpu_stats = per_cpu_ptr(vport->percpu_stats, i); + percpu_stats = per_cpu_ptr(dev->tstats, i); do { start = u64_stats_fetch_begin_irq(&percpu_stats->syncp); @@ -468,94 +452,25 @@ u32 ovs_vport_find_upcall_portid(const struct vport *vport, struct sk_buff *skb) * Must be called with rcu_read_lock. The packet cannot be shared and * skb->data should point to the Ethernet header. */ -void ovs_vport_receive(struct vport *vport, struct sk_buff *skb, - const struct ip_tunnel_info *tun_info) +int ovs_vport_receive(struct vport *vport, struct sk_buff *skb, + const struct ip_tunnel_info *tun_info) { - struct pcpu_sw_netstats *stats; struct sw_flow_key key; int error; - stats = this_cpu_ptr(vport->percpu_stats); - u64_stats_update_begin(&stats->syncp); - stats->rx_packets++; - stats->rx_bytes += skb->len + - (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0); - u64_stats_update_end(&stats->syncp); - OVS_CB(skb)->input_vport = vport; OVS_CB(skb)->mru = 0; /* Extract flow from 'skb' into 'key'. */ error = ovs_flow_key_extract(tun_info, skb, &key); if (unlikely(error)) { kfree_skb(skb); - return; + return error; } ovs_dp_process_packet(skb, &key); + return 0; } EXPORT_SYMBOL_GPL(ovs_vport_receive); -/** - * ovs_vport_send - send a packet on a device - * - * @vport: vport on which to send the packet - * @skb: skb to send - * - * Sends the given packet and returns the length of data sent. Either ovs - * lock or rcu_read_lock must be held. - */ -int ovs_vport_send(struct vport *vport, struct sk_buff *skb) -{ - int sent = vport->ops->send(vport, skb); - - if (likely(sent > 0)) { - struct pcpu_sw_netstats *stats; - - stats = this_cpu_ptr(vport->percpu_stats); - - u64_stats_update_begin(&stats->syncp); - stats->tx_packets++; - stats->tx_bytes += sent; - u64_stats_update_end(&stats->syncp); - } else if (sent < 0) { - ovs_vport_record_error(vport, VPORT_E_TX_ERROR); - } else { - ovs_vport_record_error(vport, VPORT_E_TX_DROPPED); - } - return sent; -} - -/** - * ovs_vport_record_error - indicate device error to generic stats layer - * - * @vport: vport that encountered the error - * @err_type: one of enum vport_err_type types to indicate the error type - * - * If using the vport generic stats layer indicate that an error of the given - * type has occurred. - */ -static void ovs_vport_record_error(struct vport *vport, - enum vport_err_type err_type) -{ - switch (err_type) { - case VPORT_E_RX_DROPPED: - atomic_long_inc(&vport->err_stats.rx_dropped); - break; - - case VPORT_E_RX_ERROR: - atomic_long_inc(&vport->err_stats.rx_errors); - break; - - case VPORT_E_TX_DROPPED: - atomic_long_inc(&vport->err_stats.tx_dropped); - break; - - case VPORT_E_TX_ERROR: - atomic_long_inc(&vport->err_stats.tx_errors); - break; - } - -} - static void free_vport_rcu(struct rcu_head *rcu) { struct vport *vport = container_of(rcu, struct vport, rcu); diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index a36aef22af7fe..30615edc084bb 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -57,8 +57,6 @@ int ovs_vport_set_upcall_portids(struct vport *, const struct nlattr *pids); int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); -int ovs_vport_send(struct vport *, struct sk_buff *); - int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, struct net *net, struct sk_buff *, @@ -68,14 +66,6 @@ int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, struct ip_tunnel_info *info); -/* The following definitions are for implementers of vport devices: */ - -struct vport_err_stats { - atomic_long_t rx_dropped; - atomic_long_t rx_errors; - atomic_long_t tx_dropped; - atomic_long_t tx_errors; -}; /** * struct vport_portids - array of netlink portids of a vport. * must be protected by rcu. @@ -101,8 +91,6 @@ struct vport_portids { * @hash_node: Element in @dev_table hash table in vport.c. * @dp_hash_node: Element in @datapath->ports hash table in datapath.c. * @ops: Class structure. - * @percpu_stats: Points to per-CPU statistics used and maintained by vport - * @err_stats: Points to error statistics used and maintained by vport * @detach_list: list used for detaching vport in net-exit call. */ struct vport { @@ -115,9 +103,6 @@ struct vport { struct hlist_node dp_hash_node; const struct vport_ops *ops; - struct pcpu_sw_netstats __percpu *percpu_stats; - - struct vport_err_stats err_stats; struct list_head detach_list; struct rcu_head rcu; }; @@ -156,7 +141,7 @@ struct vport_parms { * @get_options: Appends vport-specific attributes for the configuration of an * existing vport to a &struct sk_buff. May be %NULL for a vport that does not * have any configuration. - * @send: Send a packet on the device. Returns the length of the packet sent, + * @send: Send a packet on the device. * zero for dropped packets or negative for error. * @get_egress_tun_info: Get the egress tunnel 5-tuple and other info for * a packet. @@ -171,7 +156,7 @@ struct vport_ops { int (*set_options)(struct vport *, struct nlattr *); int (*get_options)(const struct vport *, struct sk_buff *); - int (*send)(struct vport *, struct sk_buff *); + void (*send)(struct vport *, struct sk_buff *); int (*get_egress_tun_info)(struct vport *, struct sk_buff *, struct ip_tunnel_info *); @@ -179,13 +164,6 @@ struct vport_ops { struct list_head list; }; -enum vport_err_type { - VPORT_E_RX_DROPPED, - VPORT_E_RX_ERROR, - VPORT_E_TX_DROPPED, - VPORT_E_TX_ERROR, -}; - struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *, const struct vport_parms *); void ovs_vport_free(struct vport *); @@ -222,8 +200,8 @@ static inline struct vport *vport_from_priv(void *priv) return (struct vport *)((u8 *)priv - ALIGN(sizeof(struct vport), VPORT_ALIGN)); } -void ovs_vport_receive(struct vport *, struct sk_buff *, - const struct ip_tunnel_info *); +int ovs_vport_receive(struct vport *, struct sk_buff *, + const struct ip_tunnel_info *); static inline void ovs_skb_postpush_rcsum(struct sk_buff *skb, const void *start, unsigned int len) @@ -258,4 +236,10 @@ static inline struct rtable *ovs_tunnel_route_lookup(struct net *net, rt = ip_route_output_key(net, fl); return rt; } + +static inline void ovs_vport_send(struct vport *vport, struct sk_buff *skb) +{ + vport->ops->send(vport, skb); +} + #endif /* vport.h */ -- GitLab From a581b96dbfc52b6b498552525ec929aa635680ed Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sat, 29 Aug 2015 17:44:08 -0700 Subject: [PATCH 5712/7006] openvswitch: Remove vport-net This structure is not used anymore. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/datapath.h | 2 -- net/openvswitch/flow.c | 3 ++- net/openvswitch/vport.h | 4 ---- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index da15fd3f3c340..c05b7d9e7bf22 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -30,7 +30,6 @@ #include "conntrack.h" #include "flow.h" #include "flow_table.h" -#include "vport.h" #define DP_MAX_PORTS USHRT_MAX #define DP_VPORT_HASH_BUCKETS 1024 @@ -134,7 +133,6 @@ struct dp_upcall_info { struct ovs_net { struct list_head dps; struct work_struct dp_notify_work; - struct vport_net vport_net; /* Module reference for configuring conntrack. */ bool xt_label; diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index 9db87331e2111..bed8d09230cdb 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -46,10 +46,11 @@ #include #include +#include "conntrack.h" #include "datapath.h" #include "flow.h" #include "flow_netlink.h" -#include "conntrack.h" +#include "vport.h" u64 ovs_flow_used_time(unsigned long flow_jiffies) { diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 30615edc084bb..4b6f4a5296c3f 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -36,10 +36,6 @@ struct vport_parms; /* The following definitions are for users of the vport subsytem: */ -struct vport_net { - struct vport __rcu *gre_vport; -}; - int ovs_vport_init(void); void ovs_vport_exit(void); -- GitLab From 099392048cd443349c50310f7fdc96070e40f4e7 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 29 Aug 2015 19:11:21 -0700 Subject: [PATCH 5713/7006] SUNRPC: Prevent SYN+SYNACK+RST storms Add a shutdown() call before we release the socket in order to ensure the reset is sent before we try to reconnect. Signed-off-by: Trond Myklebust --- net/sunrpc/xprtsock.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 214ca9dfb14ec..7be90bc1a7c26 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -822,6 +822,8 @@ static void xs_reset_transport(struct sock_xprt *transport) if (atomic_read(&transport->xprt.swapper)) sk_clear_memalloc(sk); + kernel_sock_shutdown(sock, SHUT_RDWR); + write_lock_bh(&sk->sk_callback_lock); transport->inet = NULL; transport->sock = NULL; -- GitLab From af2a50bb0ce1ca7a9c4784813419c922bf2285df Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 27 Aug 2015 19:50:18 +1000 Subject: [PATCH 5714/7006] cxl: Fix + cleanup error paths in cxl_dev_context_init If the cxl_context_alloc() call fails, we return immediately without releasing the reference on the AFU device, allowing it to leak. This patch switches to using goto style error handling so that the device is released in common code for both error paths, and will also simplify things if we add additional initialisation in this function in the future. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index f49e3e5db58d5..005adc7d33a29 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -25,19 +25,24 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) get_device(&afu->dev); ctx = cxl_context_alloc(); - if (IS_ERR(ctx)) - return ctx; + if (IS_ERR(ctx)) { + rc = PTR_ERR(ctx); + goto err_dev; + } /* Make it a slave context. We can promote it later? */ rc = cxl_context_init(ctx, afu, false, NULL); - if (rc) { - kfree(ctx); - put_device(&afu->dev); - return ERR_PTR(-ENOMEM); - } + if (rc) + goto err_ctx; cxl_assign_psn_space(ctx); return ctx; + +err_ctx: + kfree(ctx); +err_dev: + put_device(&afu->dev); + return ERR_PTR(rc); } EXPORT_SYMBOL_GPL(cxl_dev_context_init); -- GitLab From 55e07668fbba9466e6a9ef7650718356cda38406 Mon Sep 17 00:00:00 2001 From: Ian Munsie Date: Thu, 27 Aug 2015 19:50:19 +1000 Subject: [PATCH 5715/7006] cxl: Fix force unmapping mmaps of contexts allocated through the kernel api The cxl user api uses the address_space associated with the file when we need to force unmap all cxl mmap regions (e.g. on eeh, driver detach, etc). Currently, contexts allocated through the kernel api do not do this and instead skip the mmap invalidation, potentially allowing them to poke at the hardware after such an event, which may cause all sorts of trouble. This patch allocates an address_space for cxl contexts allocated through the kernel api so that the same invalidate path will for these contexts as well. We don't use the anonymous inode's address_space, as doing so could invalidate any mmaps of completely unrelated drivers using anonymous file descriptors. This patch also introduces a kernelapi flag, so we know when freeing the context if the address_space was allocated by us and needs to be freed. Signed-off-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 33 ++++++++++++++++++++++++++++++--- drivers/misc/cxl/context.c | 2 ++ drivers/misc/cxl/cxl.h | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 005adc7d33a29..8af12c884b04e 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -12,11 +12,13 @@ #include #include #include +#include #include "cxl.h" struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) { + struct address_space *mapping; struct cxl_afu *afu; struct cxl_context *ctx; int rc; @@ -30,14 +32,32 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) goto err_dev; } + ctx->kernelapi = true; + + /* + * Make our own address space since we won't have one from the + * filesystem like the user api has, and even if we do associate a file + * with this context we don't want to use the global anonymous inode's + * address space as that can invalidate unrelated users: + */ + mapping = kmalloc(sizeof(struct address_space), GFP_KERNEL); + if (!mapping) { + rc = -ENOMEM; + goto err_ctx; + } + address_space_init_once(mapping); + /* Make it a slave context. We can promote it later? */ - rc = cxl_context_init(ctx, afu, false, NULL); + rc = cxl_context_init(ctx, afu, false, mapping); if (rc) - goto err_ctx; + goto err_mapping; + cxl_assign_psn_space(ctx); return ctx; +err_mapping: + kfree(mapping); err_ctx: kfree(ctx); err_dev: @@ -260,9 +280,16 @@ struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops, file = anon_inode_getfile("cxl", fops, ctx, flags); if (IS_ERR(file)) - put_unused_fd(fdtmp); + goto err_fd; + + file->f_mapping = ctx->mapping; + *fd = fdtmp; return file; + +err_fd: + put_unused_fd(fdtmp); + return NULL; } EXPORT_SYMBOL_GPL(cxl_get_fd); diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 941fda04aa9a3..e762f85ee233a 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -272,6 +272,8 @@ static void reclaim_ctx(struct rcu_head *rcu) if (ctx->ff_page) __free_page(ctx->ff_page); ctx->sstp = NULL; + if (ctx->kernelapi) + kfree(ctx->mapping); kfree(ctx); } diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index e7af256f60c54..d6566c60bcb09 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -420,6 +420,7 @@ struct cxl_context { struct mutex mapping_lock; struct page *ff_page; bool mmio_err_ff; + bool kernelapi; spinlock_t sste_lock; /* Protects segment table entries */ struct cxl_sste *sstp; -- GitLab From 390fd5929f52bdfb9dfcc03820041ba556780f4a Mon Sep 17 00:00:00 2001 From: Philippe Bergheaud Date: Fri, 28 Aug 2015 09:37:36 +0200 Subject: [PATCH 5716/7006] cxl: Set up and enable PSL Timebase This patch configures the PSL Timebase function and enables it, after the CAPP has been initialized by OPAL. Acked-by: Ian Munsie Signed-off-by: Philippe Bergheaud Signed-off-by: Michael Ellerman --- drivers/misc/cxl/cxl.h | 5 ++++ drivers/misc/cxl/pci.c | 57 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index d6566c60bcb09..1c30ef77073d6 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -83,8 +83,10 @@ static const cxl_p1_reg_t CXL_PSL_AFUSEL = {0x00B0}; /* 0x00C0:7EFF Implementation dependent area */ static const cxl_p1_reg_t CXL_PSL_FIR1 = {0x0100}; static const cxl_p1_reg_t CXL_PSL_FIR2 = {0x0108}; +static const cxl_p1_reg_t CXL_PSL_Timebase = {0x0110}; static const cxl_p1_reg_t CXL_PSL_VERSION = {0x0118}; static const cxl_p1_reg_t CXL_PSL_RESLCKTO = {0x0128}; +static const cxl_p1_reg_t CXL_PSL_TB_CTLSTAT = {0x0140}; static const cxl_p1_reg_t CXL_PSL_FIR_CNTL = {0x0148}; static const cxl_p1_reg_t CXL_PSL_DSNDCTL = {0x0150}; static const cxl_p1_reg_t CXL_PSL_SNWRALLOC = {0x0158}; @@ -152,6 +154,9 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0}; #define CXL_PSL_SPAP_Size_Shift 4 #define CXL_PSL_SPAP_V 0x0000000000000001ULL +/****** CXL_PSL_Control ****************************************************/ +#define CXL_PSL_Control_tb 0x0000000000000001ULL + /****** CXL_PSL_DLCNTL *****************************************************/ #define CXL_PSL_DLCNTL_D (0x1ull << (63-28)) #define CXL_PSL_DLCNTL_C (0x1ull << (63-29)) diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index 6ca7c3d0ef9b4..02c85160bfe9f 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -370,6 +370,55 @@ static int init_implementation_adapter_regs(struct cxl *adapter, struct pci_dev return 0; } +#define TBSYNC_CNT(n) (((u64)n & 0x7) << (63-6)) +#define _2048_250MHZ_CYCLES 1 + +static int cxl_setup_psl_timebase(struct cxl *adapter, struct pci_dev *dev) +{ + u64 psl_tb; + int delta; + unsigned int retry = 0; + struct device_node *np; + + if (!(np = pnv_pci_get_phb_node(dev))) + return -ENODEV; + + /* Do not fail when CAPP timebase sync is not supported by OPAL */ + of_node_get(np); + if (! of_get_property(np, "ibm,capp-timebase-sync", NULL)) { + of_node_put(np); + pr_err("PSL: Timebase sync: OPAL support missing\n"); + return 0; + } + of_node_put(np); + + /* + * Setup PSL Timebase Control and Status register + * with the recommended Timebase Sync Count value + */ + cxl_p1_write(adapter, CXL_PSL_TB_CTLSTAT, + TBSYNC_CNT(2 * _2048_250MHZ_CYCLES)); + + /* Enable PSL Timebase */ + cxl_p1_write(adapter, CXL_PSL_Control, 0x0000000000000000); + cxl_p1_write(adapter, CXL_PSL_Control, CXL_PSL_Control_tb); + + /* Wait until CORE TB and PSL TB difference <= 16usecs */ + do { + msleep(1); + if (retry++ > 5) { + pr_err("PSL: Timebase sync: giving up!\n"); + return -EIO; + } + psl_tb = cxl_p1_read(adapter, CXL_PSL_Timebase); + delta = mftb() - psl_tb; + if (delta < 0) + delta = -delta; + } while (cputime_to_usecs(delta) > 16); + + return 0; +} + static int init_implementation_afu_regs(struct cxl_afu *afu) { /* read/write masks for this slice */ @@ -1053,9 +1102,12 @@ err1: return NULL; } +#define CXL_PSL_ErrIVTE_tberror (0x1ull << (63-31)) + static int sanitise_adapter_regs(struct cxl *adapter) { - cxl_p1_write(adapter, CXL_PSL_ErrIVTE, 0x0000000000000000); + /* Clear PSL tberror bit by writing 1 to it */ + cxl_p1_write(adapter, CXL_PSL_ErrIVTE, CXL_PSL_ErrIVTE_tberror); return cxl_tlb_slb_invalidate(adapter); } @@ -1108,6 +1160,9 @@ static int cxl_configure_adapter(struct cxl *adapter, struct pci_dev *dev) if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON))) goto err; + if ((rc = cxl_setup_psl_timebase(adapter, dev))) + goto err; + if ((rc = cxl_register_psl_err_irq(adapter))) goto err; -- GitLab From adaac459759db4a1fd35baddbe47bac700095496 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sun, 30 Aug 2015 09:33:53 +0200 Subject: [PATCH 5717/7006] regmap: Introduce max_raw_read/write for regmap_bulk_read/write There are some buses which have a limit on the maximum number of bytes that can be send/received. An example for this is I2C_FUNC_SMBUS_I2C_BLOCK which does not support any reads/writes of more than 32 bytes. The regmap_bulk operations should still be able to utilize the full 32 bytes in this case. Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown --- drivers/base/regmap/internal.h | 4 ++ drivers/base/regmap/regmap.c | 85 ++++++++++++++++++++++++++++------ include/linux/regmap.h | 4 ++ 3 files changed, 78 insertions(+), 15 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index d744ae3926dd1..fc554e357c5dd 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -146,6 +146,10 @@ struct regmap { /* if set, the device supports multi write mode */ bool can_multi_write; + /* if set, raw reads/writes are limited to this size */ + size_t max_raw_read; + size_t max_raw_write; + struct rb_root range_tree; void *selector_work_buf; /* Scratch buffer used for selector */ }; diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index a6b6f7ee87eef..7cbe42680877f 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -579,6 +579,8 @@ struct regmap *regmap_init(struct device *dev, map->use_single_read = config->use_single_rw || !bus || !bus->read; map->use_single_write = config->use_single_rw || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; + map->max_raw_read = bus->max_raw_read; + map->max_raw_write = bus->max_raw_write; map->dev = dev; map->bus = bus; map->bus_context = bus_context; @@ -1674,6 +1676,7 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, { int ret = 0, i; size_t val_bytes = map->format.val_bytes; + size_t total_size = val_bytes * val_count; if (map->bus && !map->format.parse_inplace) return -EINVAL; @@ -1722,16 +1725,37 @@ int regmap_bulk_write(struct regmap *map, unsigned int reg, const void *val, } out: map->unlock(map->lock_arg); - } else if (map->use_single_write) { + } else if (map->use_single_write || + (map->max_raw_write && map->max_raw_write < total_size)) { + int chunk_stride = map->reg_stride; + size_t chunk_size = val_bytes; + size_t chunk_count = val_count; + + if (!map->use_single_write) { + chunk_size = map->max_raw_write; + if (chunk_size % val_bytes) + chunk_size -= chunk_size % val_bytes; + chunk_count = total_size / chunk_size; + chunk_stride *= chunk_size / val_bytes; + } + map->lock(map->lock_arg); - for (i = 0; i < val_count; i++) { + /* Write as many bytes as possible with chunk_size */ + for (i = 0; i < chunk_count; i++) { ret = _regmap_raw_write(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); + reg + (i * chunk_stride), + val + (i * chunk_size), + chunk_size); if (ret) break; } + + /* Write remaining bytes */ + if (!ret && chunk_size * i < total_size) { + ret = _regmap_raw_write(map, reg + (i * chunk_stride), + val + (i * chunk_size), + total_size - i * chunk_size); + } map->unlock(map->lock_arg); } else { void *wval; @@ -2319,20 +2343,51 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, * Some devices does not support bulk read, for * them we have a series of single read operations. */ - if (map->use_single_read) { - for (i = 0; i < val_count; i++) { - ret = regmap_raw_read(map, - reg + (i * map->reg_stride), - val + (i * val_bytes), - val_bytes); - if (ret != 0) - return ret; - } - } else { + size_t total_size = val_bytes * val_count; + + if (!map->use_single_read && + (!map->max_raw_read || map->max_raw_read > total_size)) { ret = regmap_raw_read(map, reg, val, val_bytes * val_count); if (ret != 0) return ret; + } else { + /* + * Some devices do not support bulk read or do not + * support large bulk reads, for them we have a series + * of read operations. + */ + int chunk_stride = map->reg_stride; + size_t chunk_size = val_bytes; + size_t chunk_count = val_count; + + if (!map->use_single_read) { + chunk_size = map->max_raw_read; + if (chunk_size % val_bytes) + chunk_size -= chunk_size % val_bytes; + chunk_count = total_size / chunk_size; + chunk_stride *= chunk_size / val_bytes; + } + + /* Read bytes that fit into a multiple of chunk_size */ + for (i = 0; i < chunk_count; i++) { + ret = regmap_raw_read(map, + reg + (i * chunk_stride), + val + (i * chunk_size), + chunk_size); + if (ret != 0) + return ret; + } + + /* Read remaining bytes */ + if (chunk_size * i < total_size) { + ret = regmap_raw_read(map, + reg + (i * chunk_stride), + val + (i * chunk_size), + total_size - i * chunk_size); + if (ret != 0) + return ret; + } } for (i = 0; i < val_count * val_bytes; i += val_bytes) diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 73fc34d0c4c2a..327b8f291d3f5 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -311,6 +311,8 @@ typedef void (*regmap_hw_free_context)(void *context); * @val_format_endian_default: Default endianness for formatted register * values. Used when the regmap_config specifies DEFAULT. If this is * DEFAULT, BIG is assumed. + * @max_raw_read: Max raw read size that can be used on the bus. + * @max_raw_write: Max raw write size that can be used on the bus. */ struct regmap_bus { bool fast_io; @@ -325,6 +327,8 @@ struct regmap_bus { u8 read_flag_mask; enum regmap_endian reg_format_endian_default; enum regmap_endian val_format_endian_default; + size_t max_raw_read; + size_t max_raw_write; }; struct regmap *regmap_init(struct device *dev, -- GitLab From f50c9eb4e9304cf555206c93152f580c0e7213b2 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sun, 30 Aug 2015 09:33:54 +0200 Subject: [PATCH 5718/7006] regmap: regmap max_raw_read/write getter functions Add functions to access the maximum size we can read/write using regmap_raw_read/write(). This helps drivers that need to know how much they can write with the raw functions without problems. There are some devices (e.g. bmc150) that have fifos as registers which need to be read in specific chunks otherwise samples are dropped. Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 22 ++++++++++++++++++++++ include/linux/regmap.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 7cbe42680877f..47210101e308f 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1393,6 +1393,28 @@ bool regmap_can_raw_write(struct regmap *map) } EXPORT_SYMBOL_GPL(regmap_can_raw_write); +/** + * regmap_get_raw_read_max - Get the maximum size we can read + * + * @map: Map to check. + */ +size_t regmap_get_raw_read_max(struct regmap *map) +{ + return map->max_raw_read; +} +EXPORT_SYMBOL_GPL(regmap_get_raw_read_max); + +/** + * regmap_get_raw_write_max - Get the maximum size we can read + * + * @map: Map to check. + */ +size_t regmap_get_raw_write_max(struct regmap *map) +{ + return map->max_raw_write; +} +EXPORT_SYMBOL_GPL(regmap_get_raw_write_max); + static int _regmap_bus_formatted_write(void *context, unsigned int reg, unsigned int val) { diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 327b8f291d3f5..6724d0e3819ee 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -444,6 +444,8 @@ int regmap_get_max_register(struct regmap *map); int regmap_get_reg_stride(struct regmap *map); int regmap_async_complete(struct regmap *map); bool regmap_can_raw_write(struct regmap *map); +size_t regmap_get_raw_read_max(struct regmap *map); +size_t regmap_get_raw_write_max(struct regmap *map); int regcache_sync(struct regmap *map); int regcache_sync_region(struct regmap *map, unsigned int min, -- GitLab From c335931ed9d22c30017cf957518262c2fe6502ce Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sun, 30 Aug 2015 09:33:55 +0200 Subject: [PATCH 5719/7006] regmap: Add raw_write/read checks for max_raw_write/read sizes Check in regmap_raw_read() and regmap_raw_write() for correct maximum sizes of the operations. Return -E2BIG if this size is not supported because it is too big. Also this patch causes an uninitialized variable warning so it initializes ret (although not necessary). Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 47210101e308f..d2efa4b332943 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1584,6 +1584,8 @@ int regmap_raw_write(struct regmap *map, unsigned int reg, return -EINVAL; if (val_len % map->format.val_bytes) return -EINVAL; + if (map->max_raw_write && map->max_raw_write > val_len) + return -E2BIG; map->lock(map->lock_arg); @@ -2256,6 +2258,10 @@ int regmap_raw_read(struct regmap *map, unsigned int reg, void *val, ret = -ENOTSUPP; goto out; } + if (map->max_raw_read && map->max_raw_read < val_len) { + ret = -E2BIG; + goto out; + } /* Physical block read if there's no cache involved */ ret = _regmap_raw_read(map, reg, val, val_len); -- GitLab From 29332534e2b68b5889a40ccb6606ba0d06750a69 Mon Sep 17 00:00:00 2001 From: Markus Pargmann Date: Sun, 30 Aug 2015 09:33:56 +0200 Subject: [PATCH 5720/7006] regmap-i2c: Add smbus i2c block support This allows to read/write up to 32 bytes of data and is to be prefered if supported before the register read/write smbus support. Signed-off-by: Markus Pargmann Signed-off-by: Mark Brown --- drivers/base/regmap/regmap-i2c.c | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c index 4b76e33110a2d..ddb9b0efb7242 100644 --- a/drivers/base/regmap/regmap-i2c.c +++ b/drivers/base/regmap/regmap-i2c.c @@ -209,11 +209,60 @@ static struct regmap_bus regmap_i2c = { .val_format_endian_default = REGMAP_ENDIAN_BIG, }; +static int regmap_i2c_smbus_i2c_write(void *context, const void *data, + size_t count) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + + if (count < 1) + return -EINVAL; + if (count >= I2C_SMBUS_BLOCK_MAX) + return -E2BIG; + + --count; + return i2c_smbus_write_i2c_block_data(i2c, ((u8 *)data)[0], count, + ((u8 *)data + 1)); +} + +static int regmap_i2c_smbus_i2c_read(void *context, const void *reg, + size_t reg_size, void *val, + size_t val_size) +{ + struct device *dev = context; + struct i2c_client *i2c = to_i2c_client(dev); + int ret; + + if (reg_size != 1 || val_size < 1) + return -EINVAL; + if (val_size >= I2C_SMBUS_BLOCK_MAX) + return -E2BIG; + + ret = i2c_smbus_read_i2c_block_data(i2c, ((u8 *)reg)[0], val_size, val); + if (ret == val_size) + return 0; + else if (ret < 0) + return ret; + else + return -EIO; +} + +static struct regmap_bus regmap_i2c_smbus_i2c_block = { + .write = regmap_i2c_smbus_i2c_write, + .read = regmap_i2c_smbus_i2c_read, + .max_raw_read = I2C_SMBUS_BLOCK_MAX, + .max_raw_write = I2C_SMBUS_BLOCK_MAX, +}; + static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c, const struct regmap_config *config) { if (i2c_check_functionality(i2c->adapter, I2C_FUNC_I2C)) return ®map_i2c; + else if (config->reg_bits == 8 && + i2c_check_functionality(i2c->adapter, + I2C_FUNC_SMBUS_I2C_BLOCK)) + return ®map_i2c_smbus_i2c_block; else if (config->val_bits == 16 && config->reg_bits == 8 && i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_WORD_DATA)) -- GitLab From 2497ee721524be80a7690dac0956d04c0ee954f0 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 28 Aug 2015 09:27:16 +0200 Subject: [PATCH 5721/7006] amdkfd: use instead of The latter is a default version of and not for driver use. Signed-off-by: Christoph Hellwig Signed-off-by: Oded Gabbay --- drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 2 +- drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c index c991973019d0b..c6a1b4cc64581 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include "kfd_priv.h" #include "kfd_device_queue_manager.h" diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c index 35b9875746330..2b655103ba796 100644 --- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c +++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c @@ -33,7 +33,7 @@ #include #include "kfd_priv.h" #include -#include +#include #include /* -- GitLab From 2c3f4b97eea5ce405baf2591715445da6ed05851 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 08:08:15 +0800 Subject: [PATCH 5722/7006] ASoC: spear_pcm: Use devm_snd_dmaengine_pcm_register to fix resource leak All the callers assume devm_spear_pcm_platform_register is a devm_ API, so use devm_snd_dmaengine_pcm_register in devm_spear_pcm_platform_register. Fixes: e1771bcf99b0 ("ASoC: SPEAr: remove custom DMA alloc compat function") Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/spear/spear_pcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/soc/spear/spear_pcm.c b/sound/soc/spear/spear_pcm.c index a7dc3c56f44d9..e8476da157cd2 100644 --- a/sound/soc/spear/spear_pcm.c +++ b/sound/soc/spear/spear_pcm.c @@ -44,7 +44,7 @@ int devm_spear_pcm_platform_register(struct device *dev, *config = spear_dmaengine_pcm_config; config->compat_filter_fn = filter; - return snd_dmaengine_pcm_register(dev, config, + return devm_snd_dmaengine_pcm_register(dev, config, SND_DMAENGINE_PCM_FLAG_NO_DT | SND_DMAENGINE_PCM_FLAG_COMPAT); } -- GitLab From e8de871e19668257972b167aabd56bb5faae784c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 11:07:33 +0800 Subject: [PATCH 5723/7006] ASoC: sh: dma-sh7760: Convert to devm_snd_soc_register_platform Signed-off-by: Axel Lin Acked-by: Manuel Lauss Signed-off-by: Mark Brown --- sound/soc/sh/dma-sh7760.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/sound/soc/sh/dma-sh7760.c b/sound/soc/sh/dma-sh7760.c index fd11404a3bc78..8fad4441c87dc 100644 --- a/sound/soc/sh/dma-sh7760.c +++ b/sound/soc/sh/dma-sh7760.c @@ -327,13 +327,7 @@ static struct snd_soc_platform_driver sh7760_soc_platform = { static int sh7760_soc_platform_probe(struct platform_device *pdev) { - return snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); -} - -static int sh7760_soc_platform_remove(struct platform_device *pdev) -{ - snd_soc_unregister_platform(&pdev->dev); - return 0; + return devm_snd_soc_register_platform(&pdev->dev, &sh7760_soc_platform); } static struct platform_driver sh7760_pcm_driver = { @@ -342,7 +336,6 @@ static struct platform_driver sh7760_pcm_driver = { }, .probe = sh7760_soc_platform_probe, - .remove = sh7760_soc_platform_remove, }; module_platform_driver(sh7760_pcm_driver); -- GitLab From fd63542fc5492b86158dbd53ce5de764f171b1b6 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sun, 30 Aug 2015 11:09:49 +0800 Subject: [PATCH 5724/7006] ASoC: au1x: psc-i2s: Convert to use devm_ioremap_resource Use devm_ioremap_resource() instead of open code. Signed-off-by: Axel Lin Acked-by: Manuel Lauss Signed-off-by: Mark Brown --- sound/soc/au1x/psc-i2s.c | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/sound/soc/au1x/psc-i2s.c b/sound/soc/au1x/psc-i2s.c index e742ef668496f..38e853add96ec 100644 --- a/sound/soc/au1x/psc-i2s.c +++ b/sound/soc/au1x/psc-i2s.c @@ -305,19 +305,9 @@ static int au1xpsc_i2s_drvprobe(struct platform_device *pdev) return -ENOMEM; iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!iores) - return -ENODEV; - - ret = -EBUSY; - if (!devm_request_mem_region(&pdev->dev, iores->start, - resource_size(iores), - pdev->name)) - return -EBUSY; - - wd->mmio = devm_ioremap(&pdev->dev, iores->start, - resource_size(iores)); - if (!wd->mmio) - return -EBUSY; + wd->mmio = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(wd->mmio)) + return PTR_ERR(wd->mmio); dmares = platform_get_resource(pdev, IORESOURCE_DMA, 0); if (!dmares) -- GitLab From 1cfa8de2880e5512f9037c7804ea47a79cc8232c Mon Sep 17 00:00:00 2001 From: "Maciej W. Rozycki" Date: Sun, 3 May 2015 10:36:19 +0100 Subject: [PATCH 5725/7006] MIPS: pgtable-bits.h: Correct _PAGE_GLOBAL_SHIFT build failure Correct a build failure introduced by be0c37c9 [MIPS: Rearrange PTE bits into fixed positions.]: In file included from ./arch/mips/include/asm/io.h:27:0, from ./arch/mips/include/asm/page.h:176, from include/linux/mm_types.h:15, from include/linux/sched.h:27, from include/linux/ptrace.h:5, from arch/mips/kernel/cpu-probe.c:16: ./arch/mips/include/asm/pgtable-bits.h:164:0: error: "_PAGE_GLOBAL_SHIFT" redefined [-Werror] #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) ^ ./arch/mips/include/asm/pgtable-bits.h:141:0: note: this is the location of the previous definition #define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) ^ cc1: all warnings being treated as errors make[2]: *** [arch/mips/kernel/cpu-probe.o] Error 1 for 64BIT/CPU_MIPSR1/MIPS_HUGE_TLB_SUPPORT configurations. Remove the scattered double `_PAGE_NO_EXEC_SHIFT' and `_PAGE_GLOBAL_SHIFT' macro definitions and rearrange them so that the respective macros these definitions are based on are also those used for guarding conditionals. [ralf@linux-mips.org: resolved conflicts and updated commments.] Signed-off-by: Maciej W. Rozycki Cc: Steven J. Hill Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/9960/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable-bits.h | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index c28a8499aec7f..46017419bb6eb 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -133,20 +133,13 @@ #define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT) #define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1) #define _PAGE_SPLITTING (1 << _PAGE_SPLITTING_SHIFT) - -/* Only R2 or newer cores have the XI bit */ -#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) -#define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1) -#else -#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ - #endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */ #if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) /* XI - page cannot be executed */ -#ifndef _PAGE_NO_EXEC_SHIFT +#ifdef _PAGE_SPLITTING_SHIFT +#define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1) +#else #define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1) #endif #define _PAGE_NO_EXEC (cpu_has_rixi ? (1 << _PAGE_NO_EXEC_SHIFT) : 0) @@ -156,14 +149,16 @@ #define _PAGE_READ (cpu_has_rixi ? 0 : (1 << _PAGE_READ_SHIFT)) #define _PAGE_NO_READ_SHIFT _PAGE_READ_SHIFT #define _PAGE_NO_READ (cpu_has_rixi ? (1 << _PAGE_READ_SHIFT) : 0) +#endif /* defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6) */ +#if defined(_PAGE_NO_READ_SHIFT) #define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1) -#define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) - -#else /* !CONFIG_CPU_MIPSR2 && !CONFIG_CPU_MIPSR6 */ +#elif defined(_PAGE_SPLITTING_SHIFT) +#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1) +#else #define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1) +#endif #define _PAGE_GLOBAL (1 << _PAGE_GLOBAL_SHIFT) -#endif /* CONFIG_CPU_MIPSR2 || CONFIG_CPU_MIPSR6 */ #define _PAGE_VALID_SHIFT (_PAGE_GLOBAL_SHIFT + 1) #define _PAGE_VALID (1 << _PAGE_VALID_SHIFT) -- GitLab From e12909107c30efccf570ac67802df5d2eec4cabd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Aug 2015 23:06:32 +0800 Subject: [PATCH 5726/7006] ASoC: sti_uniperif: Ensure component is unregistered when unload module Use devm_snd_soc_register_component to ensure component is unregistered when unload the module. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- sound/soc/sti/sti_uniperif.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c index dffabf3ba9fbc..39bcefe5eea0c 100644 --- a/sound/soc/sti/sti_uniperif.c +++ b/sound/soc/sti/sti_uniperif.c @@ -224,9 +224,9 @@ static int sti_uniperiph_probe(struct platform_device *pdev) dev_set_drvdata(&pdev->dev, priv); - ret = snd_soc_register_component(&pdev->dev, - &sti_uniperiph_dai_component, - priv->dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, + &sti_uniperiph_dai_component, + priv->dai, 1); if (ret < 0) return ret; -- GitLab From 534dcd7ea60cebc41816eff0c290700acb2cc43e Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Sat, 29 Aug 2015 23:09:30 +0800 Subject: [PATCH 5727/7006] ASoC: zx296702-i2s: Fix resource leak when unload module Use devm_* API to fix leaks in current code. 1. Use devm_kzalloc to fix memory leak for zx_i2s when unload the module. 2. Use devm_snd_soc_register_component to ensure component is unregistered when unload the module. Signed-off-by: Axel Lin Reviewed-by: Jun Nie Signed-off-by: Mark Brown --- sound/soc/zte/zx296702-i2s.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sound/soc/zte/zx296702-i2s.c b/sound/soc/zte/zx296702-i2s.c index 98d96e1b17e05..f4b681d7769a7 100644 --- a/sound/soc/zte/zx296702-i2s.c +++ b/sound/soc/zte/zx296702-i2s.c @@ -380,7 +380,7 @@ static int zx_i2s_probe(struct platform_device *pdev) struct zx_i2s_info *zx_i2s; int ret; - zx_i2s = kzalloc(sizeof(*zx_i2s), GFP_KERNEL); + zx_i2s = devm_kzalloc(&pdev->dev, sizeof(*zx_i2s), GFP_KERNEL); if (!zx_i2s) return -ENOMEM; @@ -401,8 +401,8 @@ static int zx_i2s_probe(struct platform_device *pdev) writel_relaxed(0, zx_i2s->reg_base + ZX_I2S_FIFO_CTRL); platform_set_drvdata(pdev, zx_i2s); - ret = snd_soc_register_component(&pdev->dev, &zx_i2s_component, - &zx_i2s_dai, 1); + ret = devm_snd_soc_register_component(&pdev->dev, &zx_i2s_component, + &zx_i2s_dai, 1); if (ret) { dev_err(&pdev->dev, "Register DAI failed: %d\n", ret); return ret; -- GitLab From bb0fa93523b8d7f89b6ee61ab8e9b926ff7a9779 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:10 -0300 Subject: [PATCH 5728/7006] drm/exynos: don't track enabled state at exynos_crtc struct drm_crtc already stores the enabled state of the crtc thus we don't need to replicate enabled in exynos_drm_crtc. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 16 ---------------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - 2 files changed, 17 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index c47899738eb48..94eb8313cfa50 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -25,14 +25,9 @@ static void exynos_drm_crtc_enable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - if (exynos_crtc->enabled) - return; - if (exynos_crtc->ops->enable) exynos_crtc->ops->enable(exynos_crtc); - exynos_crtc->enabled = true; - drm_crtc_vblank_on(crtc); } @@ -40,9 +35,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - if (!exynos_crtc->enabled) - return; - /* wait for the completion of page flip. */ if (!wait_event_timeout(exynos_crtc->pending_flip_queue, (exynos_crtc->event == NULL), HZ/20)) @@ -52,8 +44,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) if (exynos_crtc->ops->disable) exynos_crtc->ops->disable(exynos_crtc); - - exynos_crtc->enabled = false; } static bool @@ -172,9 +162,6 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe) struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(private->crtc[pipe]); - if (!exynos_crtc->enabled) - return -EPERM; - if (exynos_crtc->ops->enable_vblank) return exynos_crtc->ops->enable_vblank(exynos_crtc); @@ -187,9 +174,6 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(private->crtc[pipe]); - if (!exynos_crtc->enabled) - return; - if (exynos_crtc->ops->disable_vblank) exynos_crtc->ops->disable_vblank(exynos_crtc); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6b8a30f23473d..a993aac3a5d06 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -136,7 +136,6 @@ struct exynos_drm_crtc { struct drm_crtc base; enum exynos_drm_output_type type; unsigned int pipe; - bool enabled; wait_queue_head_t pending_flip_queue; struct drm_pending_vblank_event *event; const struct exynos_drm_crtc_ops *ops; -- GitLab From fc75f7107a8de47e135cf3b9fec62f99c184a2c8 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:11 -0300 Subject: [PATCH 5729/7006] drm/exynos: fimd: unify call to exynos_drm_crtc_finish_pageflip() Unify handling of finished plane update to prepare for a following patch that will check for the START and START_S regs to really make sure that the plane was updated. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 5def6bc073ebb..30c1409702bb8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -896,15 +896,15 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) if (ctx->pipe < 0 || !ctx->drm_dev) goto out; - if (ctx->i80_if) { - exynos_drm_crtc_finish_pageflip(ctx->crtc); + if (!ctx->i80_if) + drm_crtc_handle_vblank(&ctx->crtc->base); + + exynos_drm_crtc_finish_pageflip(ctx->crtc); + if (ctx->i80_if) { /* Exits triggering mode */ atomic_set(&ctx->triggering, 0); } else { - drm_crtc_handle_vblank(&ctx->crtc->base); - exynos_drm_crtc_finish_pageflip(ctx->crtc); - /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { atomic_set(&ctx->wait_vsync_event, 0); -- GitLab From d9220d4733d1ea1ae375bd76dd2c961969a6795c Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 24 Aug 2015 20:36:59 +0900 Subject: [PATCH 5730/7006] drm/exynos: add prepare and cleanup phases for planes From: Gustavo Padovan .prepare_plane() and .cleanup_plane() allows to perform extra operations before and after the update of planes. For FIMD for example this will be used to enable disable the shadow protection bit. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 19 +++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 6 ++++++ 2 files changed, 25 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 94eb8313cfa50..54485b76df491 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -73,16 +73,35 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct drm_plane *plane; if (crtc->state->event) { WARN_ON(drm_crtc_vblank_get(crtc) != 0); exynos_crtc->event = crtc->state->event; } + + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + + if (exynos_crtc->ops->atomic_begin) + exynos_crtc->ops->atomic_begin(exynos_crtc, + exynos_plane); + } } static void exynos_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + struct drm_plane *plane; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); + + if (exynos_crtc->ops->atomic_flush) + exynos_crtc->ops->atomic_flush(exynos_crtc, + exynos_plane); + } } static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = { diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index a993aac3a5d06..28afecc3aefa8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -87,6 +87,8 @@ struct exynos_drm_plane { * @disable_vblank: specific driver callback for disabling vblank interrupt. * @wait_for_vblank: wait for vblank interrupt to make sure that * hardware overlay is updated. + * @atomic_begin: prepare a window to receive a update + * @atomic_flush: mark the end of a window update * @update_plane: apply hardware specific overlay data to registers. * @disable_plane: disable hardware specific overlay. * @te_handler: trigger to transfer video image at the tearing effect @@ -107,10 +109,14 @@ struct exynos_drm_crtc_ops { int (*enable_vblank)(struct exynos_drm_crtc *crtc); void (*disable_vblank)(struct exynos_drm_crtc *crtc); void (*wait_for_vblank)(struct exynos_drm_crtc *crtc); + void (*atomic_begin)(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane); void (*update_plane)(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane); void (*disable_plane)(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane); + void (*atomic_flush)(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane); void (*te_handler)(struct exynos_drm_crtc *crtc); void (*clock_enable)(struct exynos_drm_crtc *crtc, bool enable); }; -- GitLab From ce3ff36be91a85d87f138794dbbd704fb99320c2 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:13 -0300 Subject: [PATCH 5731/7006] drm/exynos: fimd: move window protect code to prepare/cleanup_plane Only set/clear the update bit in the CRTC's .atomic_begin()/flush() so all planes are really committed at the same time. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 57 ++++++++++++++---------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 30c1409702bb8..005a9968af5cd 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -591,6 +591,16 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, { u32 reg, bits, val; + /* + * SHADOWCON/PRTCON register is used for enabling timing. + * + * for example, once only width value of a register is set, + * if the dma is started then fimd hardware could malfunction so + * with protect window setting, the register fields with prefix '_F' + * wouldn't be updated at vsync also but updated once unprotect window + * is set. + */ + if (ctx->driver_data->has_shadowcon) { reg = SHADOWCON; bits = SHADOWCON_WINx_PROTECT(win); @@ -607,6 +617,28 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx, writel(val, ctx->regs + reg); } +static void fimd_atomic_begin(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + struct fimd_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + fimd_shadow_protect_win(ctx, plane->zpos, true); +} + +static void fimd_atomic_flush(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + struct fimd_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + fimd_shadow_protect_win(ctx, plane->zpos, false); +} + static void fimd_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { @@ -622,20 +654,6 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, if (ctx->suspended) return; - /* - * SHADOWCON/PRTCON register is used for enabling timing. - * - * for example, once only width value of a register is set, - * if the dma is started then fimd hardware could malfunction so - * with protect window setting, the register fields with prefix '_F' - * wouldn't be updated at vsync also but updated once unprotect window - * is set. - */ - - /* protect windows */ - fimd_shadow_protect_win(ctx, win, true); - - offset = plane->src_x * bpp; offset += plane->src_y * pitch; @@ -707,9 +725,6 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, if (ctx->driver_data->has_shadowcon) fimd_enable_shadow_channel_path(ctx, win, true); - /* Enable DMA channel and unprotect windows */ - fimd_shadow_protect_win(ctx, win, false); - if (ctx->i80_if) atomic_set(&ctx->win_updated, 1); } @@ -723,16 +738,10 @@ static void fimd_disable_plane(struct exynos_drm_crtc *crtc, if (ctx->suspended) return; - /* protect windows */ - fimd_shadow_protect_win(ctx, win, true); - fimd_enable_video_output(ctx, win, false); if (ctx->driver_data->has_shadowcon) fimd_enable_shadow_channel_path(ctx, win, false); - - /* unprotect windows */ - fimd_shadow_protect_win(ctx, win, false); } static void fimd_enable(struct exynos_drm_crtc *crtc) @@ -875,8 +884,10 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { .enable_vblank = fimd_enable_vblank, .disable_vblank = fimd_disable_vblank, .wait_for_vblank = fimd_wait_for_vblank, + .atomic_begin = fimd_atomic_begin, .update_plane = fimd_update_plane, .disable_plane = fimd_disable_plane, + .atomic_flush = fimd_atomic_flush, .te_handler = fimd_te_handler, .clock_enable = fimd_dp_clock_enable, }; -- GitLab From 822f6dfd714c961e3c5648b1d4a5ac10f807d592 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:14 -0300 Subject: [PATCH 5732/7006] drm/exynos: check for pending fb before finish update The current code was ignoring the end of update for all overlay planes, caring only for the primary plane update in case of pageflip. This change adds a change to start to check for pending updates for all planes through exynos_plane->pending_fb. At the start of plane update the pending_fb is set with the fb to be shown on the screen. Then only when to fb is already presented in the screen we set pending_fb to NULL to signal that the update was finished. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae fixup! drm/exynos: check for pending fb before finish update --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 10 +++++++++- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 10 +++++++++- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 7 ++++--- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 3 ++- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 + drivers/gpu/drm/exynos/exynos_drm_fimd.c | 10 +++++++++- drivers/gpu/drm/exynos/exynos_drm_plane.c | 2 ++ drivers/gpu/drm/exynos/exynos_drm_vidi.c | 10 +++++++++- drivers/gpu/drm/exynos/exynos_mixer.c | 10 +++++++++- 9 files changed, 54 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 484e312e0a22d..8d65e45156bd0 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -542,13 +542,21 @@ static irqreturn_t decon_lcd_sys_irq_handler(int irq, void *dev_id) { struct decon_context *ctx = dev_id; u32 val; + int win; if (!test_bit(BIT_CLKS_ENABLED, &ctx->enabled)) goto out; val = readl(ctx->addr + DECON_VIDINTCON1); if (val & VIDINTCON1_INTFRMDONEPEND) { - exynos_drm_crtc_finish_pageflip(ctx->crtc); + for (win = 0 ; win < WINDOWS_NR ; win++) { + struct exynos_drm_plane *plane = &ctx->planes[win]; + + if (!plane->pending_fb) + continue; + + exynos_drm_crtc_finish_update(ctx->crtc, plane); + } /* clear */ writel(VIDINTCON1_INTFRMDONEPEND, diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 07926547c94ff..7651499aa5acf 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -623,6 +623,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) { struct decon_context *ctx = (struct decon_context *)dev_id; u32 val, clear_bit; + int win; val = readl(ctx->regs + VIDINTCON1); @@ -636,7 +637,14 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) if (!ctx->i80_if) { drm_crtc_handle_vblank(&ctx->crtc->base); - exynos_drm_crtc_finish_pageflip(ctx->crtc); + for (win = 0 ; win < WINDOWS_NR ; win++) { + struct exynos_drm_plane *plane = &ctx->planes[win]; + + if (!plane->pending_fb) + continue; + + exynos_drm_crtc_finish_update(ctx->crtc, plane); + } /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 54485b76df491..582e041a9356a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -197,18 +197,19 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) exynos_crtc->ops->disable_vblank(exynos_crtc); } -void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc) +void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, + struct exynos_drm_plane *exynos_plane) { struct drm_crtc *crtc = &exynos_crtc->base; unsigned long flags; + exynos_plane->pending_fb = NULL; + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (exynos_crtc->event) { - drm_crtc_send_vblank_event(crtc, exynos_crtc->event); drm_crtc_vblank_put(crtc); wake_up(&exynos_crtc->pending_flip_queue); - } exynos_crtc->event = NULL; diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 9e7027d6c2f6d..8bedfde2084a9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -25,7 +25,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, void *context); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); -void exynos_drm_crtc_finish_pageflip(struct exynos_drm_crtc *exynos_crtc); +void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, + struct exynos_drm_plane *exynos_plane); void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); /* This function gets pipe value to crtc device matched with out_type. */ diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 28afecc3aefa8..81168034ce878 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -74,6 +74,7 @@ struct exynos_drm_plane { unsigned int v_ratio; dma_addr_t dma_addr[MAX_FB_BUFFER]; unsigned int zpos; + struct drm_framebuffer *pending_fb; }; /* diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 005a9968af5cd..fc26c3ef95bf6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -896,6 +896,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) { struct fimd_context *ctx = (struct fimd_context *)dev_id; u32 val, clear_bit; + int win; val = readl(ctx->regs + VIDINTCON1); @@ -910,7 +911,14 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) if (!ctx->i80_if) drm_crtc_handle_vblank(&ctx->crtc->base); - exynos_drm_crtc_finish_pageflip(ctx->crtc); + for (win = 0 ; win < WINDOWS_NR ; win++) { + struct exynos_drm_plane *plane = &ctx->planes[win]; + + if (!plane->pending_fb) + continue; + + exynos_drm_crtc_finish_update(ctx->crtc, plane); + } if (ctx->i80_if) { /* Exits triggering mode */ diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index d9a68fd83120a..fad7dfc7a7786 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -168,6 +168,8 @@ static void exynos_plane_atomic_update(struct drm_plane *plane, state->src_x >> 16, state->src_y >> 16, state->src_w >> 16, state->src_h >> 16); + exynos_plane->pending_fb = state->fb; + if (exynos_crtc->ops->update_plane) exynos_crtc->ops->update_plane(exynos_crtc, exynos_plane); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 581af35861a6f..b6d00ddb6dd6b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -179,6 +179,7 @@ static void vidi_fake_vblank_handler(struct work_struct *work) { struct vidi_context *ctx = container_of(work, struct vidi_context, work); + int win; if (ctx->pipe < 0) return; @@ -197,7 +198,14 @@ static void vidi_fake_vblank_handler(struct work_struct *work) mutex_unlock(&ctx->lock); - exynos_drm_crtc_finish_pageflip(ctx->crtc); + for (win = 0 ; win < WINDOWS_NR ; win++) { + struct exynos_drm_plane *plane = &ctx->planes[win]; + + if (!plane->pending_fb) + continue; + + exynos_drm_crtc_finish_update(ctx->crtc, plane); + } } static int vidi_show_connection(struct device *dev, diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index e68340c77676f..d7e781153cff3 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -716,6 +716,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) struct mixer_context *ctx = arg; struct mixer_resources *res = &ctx->mixer_res; u32 val, base, shadow; + int win; spin_lock(&res->reg_slock); @@ -742,7 +743,14 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) } drm_crtc_handle_vblank(&ctx->crtc->base); - exynos_drm_crtc_finish_pageflip(ctx->crtc); + for (win = 0 ; win < MIXER_WIN_NR ; win++) { + struct exynos_drm_plane *plane = &ctx->planes[win]; + + if (!plane->pending_fb) + continue; + + exynos_drm_crtc_finish_update(ctx->crtc, plane); + } /* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { -- GitLab From 44205083751cdcfdbd3f8607694ee1a5a9b161c7 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:15 -0300 Subject: [PATCH 5733/7006] drm/exynos: add macro to get the address of START_S reg This macro is need to get the value of the START shadow register, that will tell if an framebuffer is currently displayed on the screen or not. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- include/video/samsung_fimd.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/video/samsung_fimd.h b/include/video/samsung_fimd.h index 0530e5a4c6b1f..d8fc96ed11e9d 100644 --- a/include/video/samsung_fimd.h +++ b/include/video/samsung_fimd.h @@ -296,6 +296,7 @@ /* Video buffer addresses */ #define VIDW_BUF_START(_buff) (0xA0 + ((_buff) * 8)) +#define VIDW_BUF_START_S(_buff) (0x40A0 + ((_buff) * 8)) #define VIDW_BUF_START1(_buff) (0xA4 + ((_buff) * 8)) #define VIDW_BUF_END(_buff) (0xD0 + ((_buff) * 8)) #define VIDW_BUF_END1(_buff) (0xD4 + ((_buff) * 8)) -- GitLab From cb11b3f18957f90f8adeb95adf694f52581416b3 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:16 -0300 Subject: [PATCH 5734/7006] drm/exynos: fimd: only finish update if START == START_S fimd_update_plane() programs BUF_START[win] and during the update BUF_START[win] is copied to BUF_START_S[win] (its shadow register) and starts scanning out, then it raises a irq. The fimd_irq_handler, in the case we have a pending_fb, will check the fb value was copied to START_S register and finish the update in case of success. Based on patch from Daniel Kurtz Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index fc26c3ef95bf6..d96044f4c2287 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -59,6 +59,7 @@ #define VIDWnALPHA1(win) (VIDW_ALPHA + 0x04 + (win) * 8) #define VIDWx_BUF_START(win, buf) (VIDW_BUF_START(buf) + (win) * 8) +#define VIDWx_BUF_START_S(win, buf) (VIDW_BUF_START_S(buf) + (win) * 8) #define VIDWx_BUF_END(win, buf) (VIDW_BUF_END(buf) + (win) * 8) #define VIDWx_BUF_SIZE(win, buf) (VIDW_BUF_SIZE(buf) + (win) * 4) @@ -895,7 +896,7 @@ static const struct exynos_drm_crtc_ops fimd_crtc_ops = { static irqreturn_t fimd_irq_handler(int irq, void *dev_id) { struct fimd_context *ctx = (struct fimd_context *)dev_id; - u32 val, clear_bit; + u32 val, clear_bit, start, start_s; int win; val = readl(ctx->regs + VIDINTCON1); @@ -917,7 +918,10 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) if (!plane->pending_fb) continue; - exynos_drm_crtc_finish_update(ctx->crtc, plane); + start = readl(ctx->regs + VIDWx_BUF_START(win, 0)); + start_s = readl(ctx->regs + VIDWx_BUF_START_S(win, 0)); + if (start == start_s) + exynos_drm_crtc_finish_update(ctx->crtc, plane); } if (ctx->i80_if) { -- GitLab From a379df19356de97afdca37c4e8f5e8729215d6ea Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:17 -0300 Subject: [PATCH 5735/7006] drm/exynos: add atomic asynchronous commit The atomic modesetting interfaces supports async commits that should be implemented by the drivers. If drm core requests an async commit exynos_atomic_commit() will now schedule a work task to run the update later. It also serializes commits that needs to run on the same crtc, putting the following commit to wait until the current one is finished. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 113 ++++++++++++++++++++++++ drivers/gpu/drm/exynos/exynos_drm_drv.h | 11 +++ drivers/gpu/drm/exynos/exynos_drm_fb.c | 35 -------- 3 files changed, 124 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index fa5194caf2590..898591792b12b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -13,6 +13,8 @@ #include #include +#include +#include #include #include @@ -36,6 +38,56 @@ #define DRIVER_MAJOR 1 #define DRIVER_MINOR 0 +struct exynos_atomic_commit { + struct work_struct work; + struct drm_device *dev; + struct drm_atomic_state *state; + u32 crtcs; +}; + +static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) +{ + struct drm_device *dev = commit->dev; + struct exynos_drm_private *priv = dev->dev_private; + struct drm_atomic_state *state = commit->state; + + drm_atomic_helper_commit_modeset_disables(dev, state); + + drm_atomic_helper_commit_modeset_enables(dev, state); + + /* + * Exynos can't update planes with CRTCs and encoders disabled, + * its updates routines, specially for FIMD, requires the clocks + * to be enabled. So it is necessary to handle the modeset operations + * *before* the commit_planes() step, this way it will always + * have the relevant clocks enabled to perform the update. + */ + + drm_atomic_helper_commit_planes(dev, state); + + drm_atomic_helper_wait_for_vblanks(dev, state); + + drm_atomic_helper_cleanup_planes(dev, state); + + drm_atomic_state_free(state); + + spin_lock(&priv->lock); + priv->pending &= ~commit->crtcs; + spin_unlock(&priv->lock); + + wake_up_all(&priv->wait); + + kfree(commit); +} + +static void exynos_drm_atomic_work(struct work_struct *work) +{ + struct exynos_atomic_commit *commit = container_of(work, + struct exynos_atomic_commit, work); + + exynos_atomic_commit_complete(commit); +} + static int exynos_drm_load(struct drm_device *dev, unsigned long flags) { struct exynos_drm_private *private; @@ -47,6 +99,9 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) if (!private) return -ENOMEM; + init_waitqueue_head(&private->wait); + spin_lock_init(&private->lock); + dev_set_drvdata(dev->dev, dev); dev->dev_private = (void *)private; @@ -149,6 +204,64 @@ static int exynos_drm_unload(struct drm_device *dev) return 0; } +static int commit_is_pending(struct exynos_drm_private *priv, u32 crtcs) +{ + bool pending; + + spin_lock(&priv->lock); + pending = priv->pending & crtcs; + spin_unlock(&priv->lock); + + return pending; +} + +int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, + bool async) +{ + struct exynos_drm_private *priv = dev->dev_private; + struct exynos_atomic_commit *commit; + int i, ret; + + commit = kzalloc(sizeof(*commit), GFP_KERNEL); + if (!commit) + return -ENOMEM; + + ret = drm_atomic_helper_prepare_planes(dev, state); + if (ret) { + kfree(commit); + return ret; + } + + /* This is the point of no return */ + + INIT_WORK(&commit->work, exynos_drm_atomic_work); + commit->dev = dev; + commit->state = state; + + /* Wait until all affected CRTCs have completed previous commits and + * mark them as pending. + */ + for (i = 0; i < dev->mode_config.num_crtc; ++i) { + if (state->crtcs[i]) + commit->crtcs |= 1 << drm_crtc_index(state->crtcs[i]); + } + + wait_event(priv->wait, !commit_is_pending(priv, commit->crtcs)); + + spin_lock(&priv->lock); + priv->pending |= commit->crtcs; + spin_unlock(&priv->lock); + + drm_atomic_helper_swap_state(dev, state); + + if (async) + schedule_work(&commit->work); + else + exynos_atomic_commit_complete(commit); + + return 0; +} + static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) { struct drm_connector *connector; diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 81168034ce878..b06fbd43b4752 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -170,6 +170,9 @@ struct drm_exynos_file_private { * @da_space_size: size of device address space. * if 0 then default value is used for it. * @pipe: the pipe number for this crtc/manager. + * @pending: the crtcs that have pending updates to finish + * @lock: protect access to @pending + * @wait: wait an atomic commit to finish */ struct exynos_drm_private { struct drm_fb_helper *fb_helper; @@ -185,6 +188,11 @@ struct exynos_drm_private { unsigned long da_space_size; unsigned int pipe; + + /* for atomic commit */ + u32 pending; + spinlock_t lock; + wait_queue_head_t wait; }; /* @@ -243,6 +251,9 @@ static inline int exynos_dpi_bind(struct drm_device *dev, } #endif +int exynos_atomic_commit(struct drm_device *dev, struct drm_atomic_state *state, + bool async); + extern struct platform_driver fimd_driver; extern struct platform_driver exynos5433_decon_driver; diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 9738f4e0c6eb0..59ebbe5472907 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -267,41 +267,6 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev) exynos_drm_fbdev_init(dev); } -static int exynos_atomic_commit(struct drm_device *dev, - struct drm_atomic_state *state, - bool async) -{ - int ret; - - ret = drm_atomic_helper_prepare_planes(dev, state); - if (ret) - return ret; - - /* This is the point of no return */ - - drm_atomic_helper_swap_state(dev, state); - - drm_atomic_helper_commit_modeset_disables(dev, state); - - drm_atomic_helper_commit_modeset_enables(dev, state); - - /* - * Exynos can't update planes with CRTCs and encoders disabled, - * its updates routines, specially for FIMD, requires the clocks - * to be enabled. So it is necessary to handle the modeset operations - * *before* the commit_planes() step, this way it will always - * have the relevant clocks enabled to perform the update. - */ - - drm_atomic_helper_commit_planes(dev, state); - - drm_atomic_helper_cleanup_planes(dev, state); - - drm_atomic_state_free(state); - - return 0; -} - static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_user_fb_create, .output_poll_changed = exynos_drm_output_poll_changed, -- GitLab From c4533665d819271dad890440b887776ac3d5f265 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:18 -0300 Subject: [PATCH 5736/7006] drm/exynos: wait all planes updates to finish Add infrastructure to wait for all planes updates to finish by using an atomic_t variable to track how many pending updates we are waiting plus a wait_queue for the wait part. It also changes vblank behaviour and keeps it enabled for all types of updates Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 18 +++++++--- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 1 + drivers/gpu/drm/exynos/exynos_drm_drv.c | 44 +++++++++++++++++++++++- drivers/gpu/drm/exynos/exynos_drm_drv.h | 4 +++ 4 files changed, 61 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 582e041a9356a..d6c2c3f8bc6e5 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -75,10 +75,7 @@ static void exynos_crtc_atomic_begin(struct drm_crtc *crtc, struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); struct drm_plane *plane; - if (crtc->state->event) { - WARN_ON(drm_crtc_vblank_get(crtc) != 0); - exynos_crtc->event = crtc->state->event; - } + exynos_crtc->event = crtc->state->event; drm_atomic_crtc_for_each_plane(plane, crtc) { struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); @@ -156,6 +153,8 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, exynos_crtc->ops = ops; exynos_crtc->ctx = ctx; + init_waitqueue_head(&exynos_crtc->wait_update); + crtc = &exynos_crtc->base; private->crtc[pipe] = crtc; @@ -197,6 +196,13 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe) exynos_crtc->ops->disable_vblank(exynos_crtc); } +void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc) +{ + wait_event_timeout(exynos_crtc->wait_update, + (atomic_read(&exynos_crtc->pending_update) == 0), + msecs_to_jiffies(50)); +} + void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, struct exynos_drm_plane *exynos_plane) { @@ -205,10 +211,12 @@ void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, exynos_plane->pending_fb = NULL; + if (atomic_dec_and_test(&exynos_crtc->pending_update)) + wake_up(&exynos_crtc->wait_update); + spin_lock_irqsave(&crtc->dev->event_lock, flags); if (exynos_crtc->event) { drm_crtc_send_vblank_event(crtc, exynos_crtc->event); - drm_crtc_vblank_put(crtc); wake_up(&exynos_crtc->pending_flip_queue); } diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 8bedfde2084a9..f87d4abda6f7b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -25,6 +25,7 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, void *context); int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe); void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe); +void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, struct exynos_drm_plane *exynos_plane); void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 898591792b12b..1350c8e2d5878 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -45,11 +45,37 @@ struct exynos_atomic_commit { u32 crtcs; }; +static void exynos_atomic_wait_for_commit(struct drm_atomic_state *state) +{ + struct drm_crtc_state *crtc_state; + struct drm_crtc *crtc; + int i, ret; + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + if (!crtc->state->enable) + continue; + + ret = drm_crtc_vblank_get(crtc); + if (ret) + continue; + + exynos_drm_crtc_wait_pending_update(exynos_crtc); + drm_crtc_vblank_put(crtc); + } +} + static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) { struct drm_device *dev = commit->dev; struct exynos_drm_private *priv = dev->dev_private; struct drm_atomic_state *state = commit->state; + struct drm_plane *plane; + struct drm_crtc *crtc; + struct drm_plane_state *plane_state; + struct drm_crtc_state *crtc_state; + int i; drm_atomic_helper_commit_modeset_disables(dev, state); @@ -63,9 +89,25 @@ static void exynos_atomic_commit_complete(struct exynos_atomic_commit *commit) * have the relevant clocks enabled to perform the update. */ + for_each_crtc_in_state(state, crtc, crtc_state, i) { + struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); + + atomic_set(&exynos_crtc->pending_update, 0); + } + + for_each_plane_in_state(state, plane, plane_state, i) { + struct exynos_drm_crtc *exynos_crtc = + to_exynos_crtc(plane->crtc); + + if (!plane->crtc) + continue; + + atomic_inc(&exynos_crtc->pending_update); + } + drm_atomic_helper_commit_planes(dev, state); - drm_atomic_helper_wait_for_vblanks(dev, state); + exynos_atomic_wait_for_commit(state); drm_atomic_helper_cleanup_planes(dev, state); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index b06fbd43b4752..7193d94fde3b9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -136,6 +136,8 @@ struct exynos_drm_crtc_ops { * this pipe value. * @enabled: if the crtc is enabled or not * @event: vblank event that is currently queued for flip + * @wait_update: wait all pending planes updates to finish + * @pending_update: number of pending plane updates in this crtc * @ops: pointer to callbacks for exynos drm specific functionality * @ctx: A pointer to the crtc's implementation specific context */ @@ -145,6 +147,8 @@ struct exynos_drm_crtc { unsigned int pipe; wait_queue_head_t pending_flip_queue; struct drm_pending_vblank_event *event; + wait_queue_head_t wait_update; + atomic_t pending_update; const struct exynos_drm_crtc_ops *ops; void *ctx; }; -- GitLab From 7cf23eaf0d8e6f34f3bc89141efc96b2502b290c Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Sat, 15 Aug 2015 13:26:19 -0300 Subject: [PATCH 5737/7006] drm/exynos: remove wait queue for pending page flip Exynos atomic commit procedures already does this job of waiting for pending updates to finish, that means using pending_flip_queue is pointless now because the disable CRTC procedure will never happen during a page_flip. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 11 +---------- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index d6c2c3f8bc6e5..0872aa2f450f2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -35,11 +35,6 @@ static void exynos_drm_crtc_disable(struct drm_crtc *crtc) { struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc); - /* wait for the completion of page flip. */ - if (!wait_event_timeout(exynos_crtc->pending_flip_queue, - (exynos_crtc->event == NULL), HZ/20)) - exynos_crtc->event = NULL; - drm_crtc_vblank_off(crtc); if (exynos_crtc->ops->disable) @@ -146,8 +141,6 @@ struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, if (!exynos_crtc) return ERR_PTR(-ENOMEM); - init_waitqueue_head(&exynos_crtc->pending_flip_queue); - exynos_crtc->pipe = pipe; exynos_crtc->type = type; exynos_crtc->ops = ops; @@ -215,10 +208,8 @@ void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, wake_up(&exynos_crtc->wait_update); spin_lock_irqsave(&crtc->dev->event_lock, flags); - if (exynos_crtc->event) { + if (exynos_crtc->event) drm_crtc_send_vblank_event(crtc, exynos_crtc->event); - wake_up(&exynos_crtc->pending_flip_queue); - } exynos_crtc->event = NULL; spin_unlock_irqrestore(&crtc->dev->event_lock, flags); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 7193d94fde3b9..b7ba21dfb6964 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -145,7 +145,6 @@ struct exynos_drm_crtc { struct drm_crtc base; enum exynos_drm_output_type type; unsigned int pipe; - wait_queue_head_t pending_flip_queue; struct drm_pending_vblank_event *event; wait_queue_head_t wait_update; atomic_t pending_update; -- GitLab From c8c38ccff9308a706b5314ca1cf157713a40f6b5 Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 24 Aug 2015 20:52:19 +0900 Subject: [PATCH 5738/7006] drm/exynos: Enable atomic modesetting feature From: Gustavo Padovan Now that atomic modesetting is implemented for exynos enable the DRIVER_ATOMIC flag on the driver's features. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 1350c8e2d5878..d53e449146010 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -438,7 +438,8 @@ static const struct file_operations exynos_drm_driver_fops = { }; static struct drm_driver exynos_drm_driver = { - .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, + .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME + | DRIVER_ATOMIC, .load = exynos_drm_load, .unload = exynos_drm_unload, .suspend = exynos_drm_suspend, -- GitLab From e7fefb1d5af5d90baec5204d9096e8c4db8c93bd Mon Sep 17 00:00:00 2001 From: Gustavo Padovan Date: Mon, 31 Aug 2015 00:33:57 +0900 Subject: [PATCH 5739/7006] drm/exynos: remove legacy ->suspend()/resume() These legacy helpers should only be used by shadow-attaching drivers. KMS drivers has its own way to handle suspend/resume and don't need to use these two helpers. Signed-off-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index d53e449146010..c882fd30158bc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -442,8 +442,6 @@ static struct drm_driver exynos_drm_driver = { | DRIVER_ATOMIC, .load = exynos_drm_load, .unload = exynos_drm_unload, - .suspend = exynos_drm_suspend, - .resume = exynos_drm_resume, .open = exynos_drm_open, .preclose = exynos_drm_preclose, .lastclose = exynos_drm_lastclose, -- GitLab From cc5a7b35799459ec1d0b0e538f4d810aef704217 Mon Sep 17 00:00:00 2001 From: Hyungwon Hwang Date: Thu, 27 Aug 2015 18:21:14 +0900 Subject: [PATCH 5740/7006] drm/exynos: implement atomic_{begin/flush} of DECON Each CRTC's atomic_{begin/flush} must stop/start the update of shadow registers to active register in the functions. This patch achieves these purpose by moving the setting of protection bits to those functions from decon_update_plane. v2: rebased to the branch exynos-drm-next Signed-off-by: Hyungwon Hwang Reviewed-by: Daniel Stone Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 34 +++++++++++++++---- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 30 ++++++++++++---- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 8d65e45156bd0..f24dc2d2e870a 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -219,6 +219,17 @@ static void decon_shadow_protect_win(struct decon_context *ctx, int win, writel(val, ctx->addr + DECON_SHADOWCON); } +static void decon_atomic_begin(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + struct decon_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + decon_shadow_protect_win(ctx, plane->zpos, true); +} + static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { @@ -232,8 +243,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, if (ctx->suspended) return; - decon_shadow_protect_win(ctx, win, true); - val = COORDINATE_X(plane->crtc_x) | COORDINATE_Y(plane->crtc_y); writel(val, ctx->addr + DECON_VIDOSDxA(win)); @@ -265,15 +274,10 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, val |= WINCONx_ENWIN_F; writel(val, ctx->addr + DECON_WINCONx(win)); - decon_shadow_protect_win(ctx, win, false); - /* standalone update */ val = readl(ctx->addr + DECON_UPDATE); val |= STANDALONE_UPDATE_F; writel(val, ctx->addr + DECON_UPDATE); - - if (ctx->i80_if) - atomic_set(&ctx->win_updated, 1); } static void decon_disable_plane(struct exynos_drm_crtc *crtc, @@ -301,6 +305,20 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, writel(val, ctx->addr + DECON_UPDATE); } +static void decon_atomic_flush(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + struct decon_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + decon_shadow_protect_win(ctx, plane->zpos, false); + + if (ctx->i80_if) + atomic_set(&ctx->win_updated, 1); +} + static void decon_swreset(struct decon_context *ctx) { unsigned int tries; @@ -455,8 +473,10 @@ static struct exynos_drm_crtc_ops decon_crtc_ops = { .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, .commit = decon_commit, + .atomic_begin = decon_atomic_begin, .update_plane = decon_update_plane, .disable_plane = decon_disable_plane, + .atomic_flush = decon_atomic_flush, .te_handler = decon_te_irq_handler, }; diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 7651499aa5acf..c74e30e34c134 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -383,6 +383,17 @@ static void decon_shadow_protect_win(struct decon_context *ctx, writel(val, ctx->regs + SHADOWCON); } +static void decon_atomic_begin(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + struct decon_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + decon_shadow_protect_win(ctx, plane->zpos, true); +} + static void decon_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { @@ -410,9 +421,6 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, * is set. */ - /* protect windows */ - decon_shadow_protect_win(ctx, win, true); - /* buffer start address */ val = (unsigned long)plane->dma_addr[0]; writel(val, ctx->regs + VIDW_BUF_START(win)); @@ -510,14 +518,22 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc, val &= ~WINCONx_ENWIN; writel(val, ctx->regs + WINCON(win)); - /* unprotect windows */ - decon_shadow_protect_win(ctx, win, false); - val = readl(ctx->regs + DECON_UPDATE); val |= DECON_UPDATE_STANDALONE_F; writel(val, ctx->regs + DECON_UPDATE); } +static void decon_atomic_flush(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + struct decon_context *ctx = crtc->ctx; + + if (ctx->suspended) + return; + + decon_shadow_protect_win(ctx, plane->zpos, false); +} + static void decon_init(struct decon_context *ctx) { u32 val; @@ -614,8 +630,10 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, .wait_for_vblank = decon_wait_for_vblank, + .atomic_begin = decon_atomic_begin, .update_plane = decon_update_plane, .disable_plane = decon_disable_plane, + .atomic_flush = decon_atomic_flush, }; -- GitLab From 74f230d2a7e36c27fde38db20ebfb7ddb9c4a116 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Mon, 31 Aug 2015 00:45:56 +0900 Subject: [PATCH 5741/7006] drm/exynos: add render node support This patch allows clients who want to use render node to access rendering relevant ioctls - g2d, post processor and gem allocation. Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_drv.c | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index c882fd30158bc..831d2e4cacf9d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -403,25 +403,25 @@ static const struct vm_operations_struct exynos_drm_gem_vm_ops = { static const struct drm_ioctl_desc exynos_ioctls[] = { DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, exynos_drm_gem_get_ioctl, + DRM_UNLOCKED | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET, - exynos_drm_gem_get_ioctl, DRM_UNLOCKED), - DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION, - vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, - exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, - exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, - exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, - exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, - exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, - exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH), - DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, - exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH), + DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER, exynos_g2d_get_ver_ioctl, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST, exynos_g2d_set_cmdlist_ioctl, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC, exynos_g2d_exec_ioctl, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY, exynos_drm_ipp_get_property, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY, exynos_drm_ipp_set_property, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF, exynos_drm_ipp_queue_buf, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), + DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL, exynos_drm_ipp_cmd_ctrl, + DRM_UNLOCKED | DRM_AUTH | DRM_RENDER_ALLOW), }; static const struct file_operations exynos_drm_driver_fops = { @@ -439,7 +439,7 @@ static const struct file_operations exynos_drm_driver_fops = { static struct drm_driver exynos_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME - | DRIVER_ATOMIC, + | DRIVER_ATOMIC | DRIVER_RENDER, .load = exynos_drm_load, .unload = exynos_drm_unload, .open = exynos_drm_open, -- GitLab From fbbb1e1a7f170cb560224d9694f1afd851bcf47f Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 31 Aug 2015 00:53:57 +0900 Subject: [PATCH 5742/7006] drm/exynos: Properly report supported formats for each device Exynos DRM reported that all planes for all supported sub-devices supports only three pixel formats: XRGB24, ARGB24 and NV12. This patch lets each Exynos DRM sub-drivers to provide the list of supported pixel formats and registers this list to DRM core. Signed-off-by: Marek Szyprowski Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 10 ++++++- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 15 +++++++++- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 11 ++++++- drivers/gpu/drm/exynos/exynos_drm_plane.c | 11 ++----- drivers/gpu/drm/exynos/exynos_drm_plane.h | 1 + drivers/gpu/drm/exynos/exynos_drm_vidi.c | 9 +++++- drivers/gpu/drm/exynos/exynos_mixer.c | 30 +++++++++++++++++-- 7 files changed, 73 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index f24dc2d2e870a..b3c730770b0f0 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -54,6 +54,13 @@ static const char * const decon_clks_name[] = { "sclk_decon_eclk", }; +static const uint32_t decon_formats[] = { + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +}; + static int decon_enable_vblank(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; @@ -497,7 +504,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data) type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], - 1 << ctx->pipe, type, zpos); + 1 << ctx->pipe, type, decon_formats, + ARRAY_SIZE(decon_formats), zpos); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index c74e30e34c134..cbdb78ef3baca 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -70,6 +70,18 @@ static const struct of_device_id decon_driver_dt_match[] = { }; MODULE_DEVICE_TABLE(of, decon_driver_dt_match); +static const uint32_t decon_formats[] = { + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_BGRA8888, +}; + static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = crtc->ctx; @@ -693,7 +705,8 @@ static int decon_bind(struct device *dev, struct device *master, void *data) type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], - 1 << ctx->pipe, type, zpos); + 1 << ctx->pipe, type, decon_formats, + ARRAY_SIZE(decon_formats), zpos); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index d96044f4c2287..750a9e6b9e8d9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -188,6 +188,14 @@ static const struct of_device_id fimd_driver_dt_match[] = { }; MODULE_DEVICE_TABLE(of, fimd_driver_dt_match); +static const uint32_t fimd_formats[] = { + DRM_FORMAT_C8, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +}; + static inline struct fimd_driver_data *drm_fimd_get_driver_data( struct platform_device *pdev) { @@ -956,7 +964,8 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], - 1 << ctx->pipe, type, zpos); + 1 << ctx->pipe, type, fimd_formats, + ARRAY_SIZE(fimd_formats), zpos); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index fad7dfc7a7786..865d6eb0c8458 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -20,12 +20,6 @@ #include "exynos_drm_gem.h" #include "exynos_drm_plane.h" -static const uint32_t formats[] = { - DRM_FORMAT_XRGB8888, - DRM_FORMAT_ARGB8888, - DRM_FORMAT_NV12, -}; - /* * This function is to get X or Y size shown via screen. This needs length and * start position of CRTC. @@ -217,13 +211,14 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned long possible_crtcs, enum drm_plane_type type, + const uint32_t *formats, unsigned int fcount, unsigned int zpos) { int err; err = drm_universal_plane_init(dev, &exynos_plane->base, possible_crtcs, - &exynos_plane_funcs, formats, - ARRAY_SIZE(formats), type); + &exynos_plane_funcs, formats, fcount, + type); if (err) { DRM_ERROR("failed to initialize plane\n"); return err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h index 8c88ae983c38c..476c9340b591c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h @@ -12,4 +12,5 @@ int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *exynos_plane, unsigned long possible_crtcs, enum drm_plane_type type, + const uint32_t *formats, unsigned int fcount, unsigned int zpos); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index b6d00ddb6dd6b..75718e1bc3dd2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -83,6 +83,12 @@ static const char fake_edid_info[] = { 0x00, 0x00, 0x00, 0x06 }; +static const uint32_t formats[] = { + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, + DRM_FORMAT_NV12, +}; + static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = crtc->ctx; @@ -443,7 +449,8 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) type = (zpos == ctx->default_win) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], - 1 << ctx->pipe, type, zpos); + 1 << ctx->pipe, type, formats, + ARRAY_SIZE(formats), zpos); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index d7e781153cff3..7f81cce966d4b 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -43,6 +43,7 @@ #define MIXER_WIN_NR 3 #define MIXER_DEFAULT_WIN 0 +#define VP_DEFAULT_WIN 2 /* The pixelformats that are natively supported by the mixer. */ #define MXR_FORMAT_RGB565 4 @@ -74,6 +75,19 @@ enum mixer_flag_bits { MXR_BIT_VSYNC, }; +static const uint32_t mixer_formats[] = { + DRM_FORMAT_XRGB4444, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_RGB565, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ARGB8888, +}; + +static const uint32_t vp_formats[] = { + DRM_FORMAT_NV12, + DRM_FORMAT_NV21, +}; + struct mixer_context { struct platform_device *pdev; struct device *dev; @@ -1171,7 +1185,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) struct mixer_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct exynos_drm_plane *exynos_plane; - enum drm_plane_type type; unsigned int zpos; int ret; @@ -1180,10 +1193,23 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) return ret; for (zpos = 0; zpos < MIXER_WIN_NR; zpos++) { + enum drm_plane_type type; + const uint32_t *formats; + unsigned int fcount; + type = (zpos == MIXER_DEFAULT_WIN) ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY; + if (zpos < VP_DEFAULT_WIN) { + formats = mixer_formats; + fcount = ARRAY_SIZE(mixer_formats); + } else { + formats = vp_formats; + fcount = ARRAY_SIZE(vp_formats); + } + ret = exynos_plane_init(drm_dev, &ctx->planes[zpos], - 1 << ctx->pipe, type, zpos); + 1 << ctx->pipe, type, formats, fcount, + zpos); if (ret) return ret; } -- GitLab From 50002d4c2176da6b2ed5a2529a2367c05f0fd73b Mon Sep 17 00:00:00 2001 From: Inki Dae Date: Mon, 31 Aug 2015 01:11:53 +0900 Subject: [PATCH 5743/7006] drm/exynos: fix build warning to exynos_drm_gem.c Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_gem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index 67461b77f0401..62b9ea1b07fb0 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -668,7 +668,7 @@ exynos_drm_gem_prime_import_sg_table(struct drm_device *dev, exynos_gem_obj = exynos_drm_gem_init(dev, attach->dmabuf->size); if (IS_ERR(exynos_gem_obj)) { ret = PTR_ERR(exynos_gem_obj); - goto err; + return ERR_PTR(ret); } exynos_gem_obj->dma_addr = sg_dma_address(sgt->sgl); -- GitLab From 5aa44bb90f047662c12c44be1b6de454658632d0 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:13 +0300 Subject: [PATCH 5744/7006] IB/core: Add rwsem to allow reading device list or client list Currently the RDMA subsystem's device list and client list are protected by a single mutex. This prevents adding user-facing APIs that iterate these lists, since using them may cause a deadlock. The patch attempts to solve this problem by adding a read-write semaphore to protect the lists. Readers now don't need the mutex, and are safe just by read-locking the semaphore. The ib_register_device, ib_register_client, ib_unregister_device, and ib_unregister_client functions are modified to lock the semaphore for write during their respective list modification. Also, in order to make sure client callbacks are called only between add() and remove() calls, the code is changed to only add items to the lists after the add() calls and remove from the lists before the remove() calls. This patch attempts to solve a similar need [1] that was seen in the RoCE v2 patch series. [1] http://www.spinics.net/lists/linux-rdma/msg24733.html Reviewed-by: Jason Gunthorpe Cc: Matan Barak Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/device.c | 40 ++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 9567756ca4f9f..0c8fa781538bb 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -55,17 +55,24 @@ struct ib_client_data { struct workqueue_struct *ib_wq; EXPORT_SYMBOL_GPL(ib_wq); +/* The device_list and client_list contain devices and clients after their + * registration has completed, and the devices and clients are removed + * during unregistration. */ static LIST_HEAD(device_list); static LIST_HEAD(client_list); /* - * device_mutex protects access to both device_list and client_list. - * There's no real point to using multiple locks or something fancier - * like an rwsem: we always access both lists, and we're always - * modifying one list or the other list. In any case this is not a - * hot path so there's no point in trying to optimize. + * device_mutex and lists_rwsem protect access to both device_list and + * client_list. device_mutex protects writer access by device and client + * registration / de-registration. lists_rwsem protects reader access to + * these lists. Iterators of these lists must lock it for read, while updates + * to the lists must be done with a write lock. A special case is when the + * device_mutex is locked. In this case locking the lists for read access is + * not necessary as the device_mutex implies it. */ static DEFINE_MUTEX(device_mutex); +static DECLARE_RWSEM(lists_rwsem); + static int ib_device_check_mandatory(struct ib_device *device) { @@ -305,8 +312,6 @@ int ib_register_device(struct ib_device *device, goto out; } - list_add_tail(&device->core_list, &device_list); - device->reg_state = IB_DEV_REGISTERED; { @@ -317,7 +322,10 @@ int ib_register_device(struct ib_device *device, client->add(device); } - out: + down_write(&lists_rwsem); + list_add_tail(&device->core_list, &device_list); + up_write(&lists_rwsem); +out: mutex_unlock(&device_mutex); return ret; } @@ -337,12 +345,14 @@ void ib_unregister_device(struct ib_device *device) mutex_lock(&device_mutex); + down_write(&lists_rwsem); + list_del(&device->core_list); + up_write(&lists_rwsem); + list_for_each_entry_reverse(client, &client_list, list) if (client->remove) client->remove(device); - list_del(&device->core_list); - mutex_unlock(&device_mutex); ib_device_unregister_sysfs(device); @@ -375,11 +385,14 @@ int ib_register_client(struct ib_client *client) mutex_lock(&device_mutex); - list_add_tail(&client->list, &client_list); list_for_each_entry(device, &device_list, core_list) if (client->add && !add_client_context(device, client)) client->add(device); + down_write(&lists_rwsem); + list_add_tail(&client->list, &client_list); + up_write(&lists_rwsem); + mutex_unlock(&device_mutex); return 0; @@ -402,6 +415,10 @@ void ib_unregister_client(struct ib_client *client) mutex_lock(&device_mutex); + down_write(&lists_rwsem); + list_del(&client->list); + up_write(&lists_rwsem); + list_for_each_entry(device, &device_list, core_list) { if (client->remove) client->remove(device); @@ -414,7 +431,6 @@ void ib_unregister_client(struct ib_client *client) } spin_unlock_irqrestore(&device->client_data_lock, flags); } - list_del(&client->list); mutex_unlock(&device_mutex); } -- GitLab From 7c1eb45a22d76bb99236e7485958f87ef7c449cf Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:14 +0300 Subject: [PATCH 5745/7006] IB/core: lock client data with lists_rwsem An ib_client callback that is called with the lists_rwsem locked only for read is protected from changes to the IB client lists, but not from ib_unregister_device() freeing its client data. This is because ib_unregister_device() will remove the device from the device list with lists_rwsem locked for write, but perform the rest of the cleanup, including the call to remove() without that lock. Mark client data that is undergoing de-registration with a new going_down flag in the client data context. Lock the client data list with lists_rwsem for write in addition to using the spinlock, so that functions calling the callback would be able to lock only lists_rwsem for read and let callbacks sleep. Since ib_unregister_client() now marks the client data context, no need for remove() to search the context again, so pass the client data directly to remove() callbacks. Reviewed-by: Jason Gunthorpe Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cache.c | 2 +- drivers/infiniband/core/cm.c | 7 ++- drivers/infiniband/core/cma.c | 7 ++- drivers/infiniband/core/device.c | 53 +++++++++++++++++++---- drivers/infiniband/core/mad.c | 2 +- drivers/infiniband/core/multicast.c | 7 ++- drivers/infiniband/core/sa_query.c | 6 +-- drivers/infiniband/core/ucm.c | 6 +-- drivers/infiniband/core/user_mad.c | 6 +-- drivers/infiniband/core/uverbs_main.c | 6 +-- drivers/infiniband/ulp/ipoib/ipoib_main.c | 7 ++- drivers/infiniband/ulp/srp/ib_srp.c | 6 +-- drivers/infiniband/ulp/srpt/ib_srpt.c | 5 +-- include/rdma/ib_verbs.h | 4 +- net/rds/ib.c | 5 +-- net/rds/iw.c | 5 +-- 16 files changed, 82 insertions(+), 52 deletions(-) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 871da832d016a..c93af66cc091a 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -394,7 +394,7 @@ err: kfree(device->cache.lmc_cache); } -static void ib_cache_cleanup_one(struct ib_device *device) +static void ib_cache_cleanup_one(struct ib_device *device, void *client_data) { int p; diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 3a972ebf3c0d1..82d5c4362aa85 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -58,7 +58,7 @@ MODULE_DESCRIPTION("InfiniBand CM"); MODULE_LICENSE("Dual BSD/GPL"); static void cm_add_one(struct ib_device *device); -static void cm_remove_one(struct ib_device *device); +static void cm_remove_one(struct ib_device *device, void *client_data); static struct ib_client cm_client = { .name = "cm", @@ -3886,9 +3886,9 @@ free: kfree(cm_dev); } -static void cm_remove_one(struct ib_device *ib_device) +static void cm_remove_one(struct ib_device *ib_device, void *client_data) { - struct cm_device *cm_dev; + struct cm_device *cm_dev = client_data; struct cm_port *port; struct ib_port_modify port_modify = { .clr_port_cap_mask = IB_PORT_CM_SUP @@ -3896,7 +3896,6 @@ static void cm_remove_one(struct ib_device *ib_device) unsigned long flags; int i; - cm_dev = ib_get_client_data(ib_device, &cm_client); if (!cm_dev) return; diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 4e72e4c16cfe7..9664131c4eeb6 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -94,7 +94,7 @@ const char *rdma_event_msg(enum rdma_cm_event_type event) EXPORT_SYMBOL(rdma_event_msg); static void cma_add_one(struct ib_device *device); -static void cma_remove_one(struct ib_device *device); +static void cma_remove_one(struct ib_device *device, void *client_data); static struct ib_client cma_client = { .name = "cma", @@ -3554,11 +3554,10 @@ static void cma_process_remove(struct cma_device *cma_dev) wait_for_completion(&cma_dev->comp); } -static void cma_remove_one(struct ib_device *device) +static void cma_remove_one(struct ib_device *device, void *client_data) { - struct cma_device *cma_dev; + struct cma_device *cma_dev = client_data; - cma_dev = ib_get_client_data(device, &cma_client); if (!cma_dev) return; diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 0c8fa781538bb..ce317e6238622 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -50,6 +50,9 @@ struct ib_client_data { struct list_head list; struct ib_client *client; void * data; + /* The device or client is going down. Do not call client or device + * callbacks other than remove(). */ + bool going_down; }; struct workqueue_struct *ib_wq; @@ -69,6 +72,8 @@ static LIST_HEAD(client_list); * to the lists must be done with a write lock. A special case is when the * device_mutex is locked. In this case locking the lists for read access is * not necessary as the device_mutex implies it. + * + * lists_rwsem also protects access to the client data list. */ static DEFINE_MUTEX(device_mutex); static DECLARE_RWSEM(lists_rwsem); @@ -210,10 +215,13 @@ static int add_client_context(struct ib_device *device, struct ib_client *client context->client = client; context->data = NULL; + context->going_down = false; + down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); list_add(&context->list, &device->client_data_list); spin_unlock_irqrestore(&device->client_data_lock, flags); + up_write(&lists_rwsem); return 0; } @@ -339,7 +347,6 @@ EXPORT_SYMBOL(ib_register_device); */ void ib_unregister_device(struct ib_device *device) { - struct ib_client *client; struct ib_client_data *context, *tmp; unsigned long flags; @@ -347,20 +354,29 @@ void ib_unregister_device(struct ib_device *device) down_write(&lists_rwsem); list_del(&device->core_list); - up_write(&lists_rwsem); + spin_lock_irqsave(&device->client_data_lock, flags); + list_for_each_entry_safe(context, tmp, &device->client_data_list, list) + context->going_down = true; + spin_unlock_irqrestore(&device->client_data_lock, flags); + downgrade_write(&lists_rwsem); - list_for_each_entry_reverse(client, &client_list, list) - if (client->remove) - client->remove(device); + list_for_each_entry_safe(context, tmp, &device->client_data_list, + list) { + if (context->client->remove) + context->client->remove(device, context->data); + } + up_read(&lists_rwsem); mutex_unlock(&device_mutex); ib_device_unregister_sysfs(device); + down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); list_for_each_entry_safe(context, tmp, &device->client_data_list, list) kfree(context); spin_unlock_irqrestore(&device->client_data_lock, flags); + up_write(&lists_rwsem); device->reg_state = IB_DEV_UNREGISTERED; } @@ -420,16 +436,35 @@ void ib_unregister_client(struct ib_client *client) up_write(&lists_rwsem); list_for_each_entry(device, &device_list, core_list) { - if (client->remove) - client->remove(device); + struct ib_client_data *found_context = NULL; + down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); list_for_each_entry_safe(context, tmp, &device->client_data_list, list) if (context->client == client) { - list_del(&context->list); - kfree(context); + context->going_down = true; + found_context = context; + break; } spin_unlock_irqrestore(&device->client_data_lock, flags); + up_write(&lists_rwsem); + + if (client->remove) + client->remove(device, found_context ? + found_context->data : NULL); + + if (!found_context) { + pr_warn("No client context found for %s/%s\n", + device->name, client->name); + continue; + } + + down_write(&lists_rwsem); + spin_lock_irqsave(&device->client_data_lock, flags); + list_del(&found_context->list); + kfree(found_context); + spin_unlock_irqrestore(&device->client_data_lock, flags); + up_write(&lists_rwsem); } mutex_unlock(&device_mutex); diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 786fc51bf04b2..66b4b3eb8f67b 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -3335,7 +3335,7 @@ error: } } -static void ib_mad_remove_device(struct ib_device *device) +static void ib_mad_remove_device(struct ib_device *device, void *client_data) { int i; diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 2cb865c7ce7a9..d38d8b2b2979d 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -43,7 +43,7 @@ #include "sa.h" static void mcast_add_one(struct ib_device *device); -static void mcast_remove_one(struct ib_device *device); +static void mcast_remove_one(struct ib_device *device, void *client_data); static struct ib_client mcast_client = { .name = "ib_multicast", @@ -840,13 +840,12 @@ static void mcast_add_one(struct ib_device *device) ib_register_event_handler(&dev->event_handler); } -static void mcast_remove_one(struct ib_device *device) +static void mcast_remove_one(struct ib_device *device, void *client_data) { - struct mcast_device *dev; + struct mcast_device *dev = client_data; struct mcast_port *port; int i; - dev = ib_get_client_data(device, &mcast_client); if (!dev) return; diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index ca919f4296664..d40be3673b79e 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -107,7 +107,7 @@ struct ib_sa_mcmember_query { }; static void ib_sa_add_one(struct ib_device *device); -static void ib_sa_remove_one(struct ib_device *device); +static void ib_sa_remove_one(struct ib_device *device, void *client_data); static struct ib_client sa_client = { .name = "sa", @@ -1221,9 +1221,9 @@ free: return; } -static void ib_sa_remove_one(struct ib_device *device) +static void ib_sa_remove_one(struct ib_device *device, void *client_data) { - struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); + struct ib_sa_device *sa_dev = client_data; int i; if (!sa_dev) diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 0094810736446..8cde48b96f194 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -109,7 +109,7 @@ enum { #define IB_UCM_BASE_DEV MKDEV(IB_UCM_MAJOR, IB_UCM_BASE_MINOR) static void ib_ucm_add_one(struct ib_device *device); -static void ib_ucm_remove_one(struct ib_device *device); +static void ib_ucm_remove_one(struct ib_device *device, void *client_data); static struct ib_client ucm_client = { .name = "ucm", @@ -1310,9 +1310,9 @@ err: return; } -static void ib_ucm_remove_one(struct ib_device *device) +static void ib_ucm_remove_one(struct ib_device *device, void *client_data) { - struct ib_ucm_device *ucm_dev = ib_get_client_data(device, &ucm_client); + struct ib_ucm_device *ucm_dev = client_data; if (!ucm_dev) return; diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 35567fffaa4e3..57f281f8d6862 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -133,7 +133,7 @@ static DEFINE_SPINLOCK(port_lock); static DECLARE_BITMAP(dev_map, IB_UMAD_MAX_PORTS); static void ib_umad_add_one(struct ib_device *device); -static void ib_umad_remove_one(struct ib_device *device); +static void ib_umad_remove_one(struct ib_device *device, void *client_data); static void ib_umad_release_dev(struct kobject *kobj) { @@ -1322,9 +1322,9 @@ free: kobject_put(&umad_dev->kobj); } -static void ib_umad_remove_one(struct ib_device *device) +static void ib_umad_remove_one(struct ib_device *device, void *client_data) { - struct ib_umad_device *umad_dev = ib_get_client_data(device, &umad_client); + struct ib_umad_device *umad_dev = client_data; int i; if (!umad_dev) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index f6eef2da70979..46c92294afa51 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -128,7 +128,7 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, }; static void ib_uverbs_add_one(struct ib_device *device); -static void ib_uverbs_remove_one(struct ib_device *device); +static void ib_uverbs_remove_one(struct ib_device *device, void *client_data); static void ib_uverbs_release_dev(struct kref *ref) { @@ -948,9 +948,9 @@ err: return; } -static void ib_uverbs_remove_one(struct ib_device *device) +static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) { - struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client); + struct ib_uverbs_device *uverbs_dev = client_data; if (!uverbs_dev) return; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index b2943c84a5dda..cca1a0c91ec43 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -89,7 +89,7 @@ struct workqueue_struct *ipoib_workqueue; struct ib_sa_client ipoib_sa_client; static void ipoib_add_one(struct ib_device *device); -static void ipoib_remove_one(struct ib_device *device); +static void ipoib_remove_one(struct ib_device *device, void *client_data); static void ipoib_neigh_reclaim(struct rcu_head *rp); static struct ib_client ipoib_client = { @@ -1715,12 +1715,11 @@ static void ipoib_add_one(struct ib_device *device) ib_set_client_data(device, &ipoib_client, dev_list); } -static void ipoib_remove_one(struct ib_device *device) +static void ipoib_remove_one(struct ib_device *device, void *client_data) { struct ipoib_dev_priv *priv, *tmp; - struct list_head *dev_list; + struct list_head *dev_list = client_data; - dev_list = ib_get_client_data(device, &ipoib_client); if (!dev_list) return; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 31a20b4622666..7755df444cfda 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -131,7 +131,7 @@ MODULE_PARM_DESC(ch_count, "Number of RDMA channels to use for communication with an SRP target. Using more than one channel improves performance if the HCA supports multiple completion vectors. The default value is the minimum of four times the number of online CPU sockets and the number of completion vectors supported by the HCA."); static void srp_add_one(struct ib_device *device); -static void srp_remove_one(struct ib_device *device); +static void srp_remove_one(struct ib_device *device, void *client_data); static void srp_recv_completion(struct ib_cq *cq, void *ch_ptr); static void srp_send_completion(struct ib_cq *cq, void *ch_ptr); static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event); @@ -3460,13 +3460,13 @@ free_attr: kfree(dev_attr); } -static void srp_remove_one(struct ib_device *device) +static void srp_remove_one(struct ib_device *device, void *client_data) { struct srp_device *srp_dev; struct srp_host *host, *tmp_host; struct srp_target_port *target; - srp_dev = ib_get_client_data(device, &srp_client); + srp_dev = client_data; if (!srp_dev) return; diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 60ff0a2390e5f..4c59ceb40fffc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3326,12 +3326,11 @@ err: /** * srpt_remove_one() - InfiniBand device removal callback function. */ -static void srpt_remove_one(struct ib_device *device) +static void srpt_remove_one(struct ib_device *device, void *client_data) { - struct srpt_device *sdev; + struct srpt_device *sdev = client_data; int i; - sdev = ib_get_client_data(device, &srpt_client); if (!sdev) { pr_info("%s(%s): nothing to do.\n", __func__, device->name); return; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 7448a2740287c..449609b709280 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1550,6 +1550,8 @@ struct ib_device { spinlock_t client_data_lock; struct list_head core_list; + /* Access to the client_data_list is protected by the client_data_lock + * spinlock and the lists_rwsem read-write semaphore */ struct list_head client_data_list; struct ib_cache cache; @@ -1761,7 +1763,7 @@ struct ib_device { struct ib_client { char *name; void (*add) (struct ib_device *); - void (*remove)(struct ib_device *); + void (*remove)(struct ib_device *, void *client_data); struct list_head list; }; diff --git a/net/rds/ib.c b/net/rds/ib.c index ba2dffeff6087..348ac37c11616 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -230,11 +230,10 @@ struct rds_ib_device *rds_ib_get_client_data(struct ib_device *device) * * This can be called at any time and can be racing with any other RDS path. */ -static void rds_ib_remove_one(struct ib_device *device) +static void rds_ib_remove_one(struct ib_device *device, void *client_data) { - struct rds_ib_device *rds_ibdev; + struct rds_ib_device *rds_ibdev = client_data; - rds_ibdev = ib_get_client_data(device, &rds_ib_client); if (!rds_ibdev) return; diff --git a/net/rds/iw.c b/net/rds/iw.c index 589935661d667..7cc2f32a0cb38 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -125,12 +125,11 @@ free_attr: kfree(dev_attr); } -static void rds_iw_remove_one(struct ib_device *device) +static void rds_iw_remove_one(struct ib_device *device, void *client_data) { - struct rds_iw_device *rds_iwdev; + struct rds_iw_device *rds_iwdev = client_data; struct rds_iw_cm_id *i_cm_id, *next; - rds_iwdev = ib_get_client_data(device, &rds_iw_client); if (!rds_iwdev) return; -- GitLab From 9268f72dcb24348c8b4cf9bcf8afeb24035157a5 Mon Sep 17 00:00:00 2001 From: Yotam Kenneth Date: Thu, 30 Jul 2015 17:50:15 +0300 Subject: [PATCH 5746/7006] IB/core: Find the network device matching connection parameters In the case of IPoIB, and maybe in other cases, the network device is managed by an upper-layer protocol (ULP). In order to expose this network device to other users of the IB device, let ULPs implement a callback that returns network device according to connection parameters. The IB device and port, together with the P_Key and the GID should be enough to uniquely identify the ULP net device. However, in current kernels there can be multiple IPoIB interfaces created with the same GID. Furthermore, such configuration may be desireable to support ipvlan-like configurations for RDMA CM with IPoIB. To resolve the device in these cases the code will also take the IP address as an additional input. Reviewed-by: Jason Gunthorpe Signed-off-by: Haggai Eran Signed-off-by: Yotam Kenneth Signed-off-by: Shachar Raindel Signed-off-by: Guy Shapiro Signed-off-by: Doug Ledford --- drivers/infiniband/core/device.c | 46 ++++++++++++++++++++++++++++++++ include/rdma/ib_verbs.h | 27 +++++++++++++++++++ 2 files changed, 73 insertions(+) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index ce317e6238622..a9a27816991ab 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include "core_priv.h" @@ -780,6 +781,51 @@ int ib_find_pkey(struct ib_device *device, } EXPORT_SYMBOL(ib_find_pkey); +/** + * ib_get_net_dev_by_params() - Return the appropriate net_dev + * for a received CM request + * @dev: An RDMA device on which the request has been received. + * @port: Port number on the RDMA device. + * @pkey: The Pkey the request came on. + * @gid: A GID that the net_dev uses to communicate. + * @addr: Contains the IP address that the request specified as its + * destination. + */ +struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, + u8 port, + u16 pkey, + const union ib_gid *gid, + const struct sockaddr *addr) +{ + struct net_device *net_dev = NULL; + struct ib_client_data *context; + + if (!rdma_protocol_ib(dev, port)) + return NULL; + + down_read(&lists_rwsem); + + list_for_each_entry(context, &dev->client_data_list, list) { + struct ib_client *client = context->client; + + if (context->going_down) + continue; + + if (client->get_net_dev_by_params) { + net_dev = client->get_net_dev_by_params(dev, port, pkey, + gid, addr, + context->data); + if (net_dev) + break; + } + } + + up_read(&lists_rwsem); + + return net_dev; +} +EXPORT_SYMBOL(ib_get_net_dev_by_params); + static int __init ib_core_init(void) { int ret; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 449609b709280..fd7a6950df75e 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -1765,6 +1766,28 @@ struct ib_client { void (*add) (struct ib_device *); void (*remove)(struct ib_device *, void *client_data); + /* Returns the net_dev belonging to this ib_client and matching the + * given parameters. + * @dev: An RDMA device that the net_dev use for communication. + * @port: A physical port number on the RDMA device. + * @pkey: P_Key that the net_dev uses if applicable. + * @gid: A GID that the net_dev uses to communicate. + * @addr: An IP address the net_dev is configured with. + * @client_data: The device's client data set by ib_set_client_data(). + * + * An ib_client that implements a net_dev on top of RDMA devices + * (such as IP over IB) should implement this callback, allowing the + * rdma_cm module to find the right net_dev for a given request. + * + * The caller is responsible for calling dev_put on the returned + * netdev. */ + struct net_device *(*get_net_dev_by_params)( + struct ib_device *dev, + u8 port, + u16 pkey, + const union ib_gid *gid, + const struct sockaddr *addr, + void *client_data); struct list_head list; }; @@ -3014,4 +3037,8 @@ static inline int ib_check_mr_access(int flags) int ib_check_mr_status(struct ib_mr *mr, u32 check_mask, struct ib_mr_status *mr_status); +struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, u8 port, + u16 pkey, const union ib_gid *gid, + const struct sockaddr *addr); + #endif /* IB_VERBS_H */ -- GitLab From ddde896e561a51ae5023e531d66dc6a140a95ec3 Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Thu, 30 Jul 2015 17:50:16 +0300 Subject: [PATCH 5747/7006] IB/ipoib: Return IPoIB devices matching connection parameters Implement the get_net_device_by_port_pkey_ip callback that returns network device to ib_core according to connection parameters. Check the ipoib device and iterate over all child devices to look for a match. For each IPoIB device we iterate through all upper devices when searching for a matching IP, in order to support bonding. Signed-off-by: Guy Shapiro Signed-off-by: Haggai Eran Signed-off-by: Yotam Kenneth Signed-off-by: Shachar Raindel Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_main.c | 229 +++++++++++++++++++++- 1 file changed, 228 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index cca1a0c91ec43..36536ce5a3e2f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -48,6 +48,9 @@ #include #include +#include +#include +#include #define DRV_VERSION "1.0.0" @@ -91,11 +94,16 @@ struct ib_sa_client ipoib_sa_client; static void ipoib_add_one(struct ib_device *device); static void ipoib_remove_one(struct ib_device *device, void *client_data); static void ipoib_neigh_reclaim(struct rcu_head *rp); +static struct net_device *ipoib_get_net_dev_by_params( + struct ib_device *dev, u8 port, u16 pkey, + const union ib_gid *gid, const struct sockaddr *addr, + void *client_data); static struct ib_client ipoib_client = { .name = "ipoib", .add = ipoib_add_one, - .remove = ipoib_remove_one + .remove = ipoib_remove_one, + .get_net_dev_by_params = ipoib_get_net_dev_by_params, }; int ipoib_open(struct net_device *dev) @@ -222,6 +230,225 @@ static int ipoib_change_mtu(struct net_device *dev, int new_mtu) return 0; } +/* Called with an RCU read lock taken */ +static bool ipoib_is_dev_match_addr_rcu(const struct sockaddr *addr, + struct net_device *dev) +{ + struct net *net = dev_net(dev); + struct in_device *in_dev; + struct sockaddr_in *addr_in = (struct sockaddr_in *)addr; + struct sockaddr_in6 *addr_in6 = (struct sockaddr_in6 *)addr; + __be32 ret_addr; + + switch (addr->sa_family) { + case AF_INET: + in_dev = in_dev_get(dev); + if (!in_dev) + return false; + + ret_addr = inet_confirm_addr(net, in_dev, 0, + addr_in->sin_addr.s_addr, + RT_SCOPE_HOST); + in_dev_put(in_dev); + if (ret_addr) + return true; + + break; + case AF_INET6: + if (IS_ENABLED(CONFIG_IPV6) && + ipv6_chk_addr(net, &addr_in6->sin6_addr, dev, 1)) + return true; + + break; + } + return false; +} + +/** + * Find the master net_device on top of the given net_device. + * @dev: base IPoIB net_device + * + * Returns the master net_device with a reference held, or the same net_device + * if no master exists. + */ +static struct net_device *ipoib_get_master_net_dev(struct net_device *dev) +{ + struct net_device *master; + + rcu_read_lock(); + master = netdev_master_upper_dev_get_rcu(dev); + if (master) + dev_hold(master); + rcu_read_unlock(); + + if (master) + return master; + + dev_hold(dev); + return dev; +} + +/** + * Find a net_device matching the given address, which is an upper device of + * the given net_device. + * @addr: IP address to look for. + * @dev: base IPoIB net_device + * + * If found, returns the net_device with a reference held. Otherwise return + * NULL. + */ +static struct net_device *ipoib_get_net_dev_match_addr( + const struct sockaddr *addr, struct net_device *dev) +{ + struct net_device *upper, + *result = NULL; + struct list_head *iter; + + rcu_read_lock(); + if (ipoib_is_dev_match_addr_rcu(addr, dev)) { + dev_hold(dev); + result = dev; + goto out; + } + + netdev_for_each_all_upper_dev_rcu(dev, upper, iter) { + if (ipoib_is_dev_match_addr_rcu(addr, upper)) { + dev_hold(upper); + result = upper; + break; + } + } +out: + rcu_read_unlock(); + return result; +} + +/* returns the number of IPoIB netdevs on top a given ipoib device matching a + * pkey_index and address, if one exists. + * + * @found_net_dev: contains a matching net_device if the return value >= 1, + * with a reference held. */ +static int ipoib_match_gid_pkey_addr(struct ipoib_dev_priv *priv, + const union ib_gid *gid, + u16 pkey_index, + const struct sockaddr *addr, + int nesting, + struct net_device **found_net_dev) +{ + struct ipoib_dev_priv *child_priv; + struct net_device *net_dev = NULL; + int matches = 0; + + if (priv->pkey_index == pkey_index && + (!gid || !memcmp(gid, &priv->local_gid, sizeof(*gid)))) { + if (!addr) { + net_dev = ipoib_get_master_net_dev(priv->dev); + } else { + /* Verify the net_device matches the IP address, as + * IPoIB child devices currently share a GID. */ + net_dev = ipoib_get_net_dev_match_addr(addr, priv->dev); + } + if (net_dev) { + if (!*found_net_dev) + *found_net_dev = net_dev; + else + dev_put(net_dev); + ++matches; + } + } + + /* Check child interfaces */ + down_read_nested(&priv->vlan_rwsem, nesting); + list_for_each_entry(child_priv, &priv->child_intfs, list) { + matches += ipoib_match_gid_pkey_addr(child_priv, gid, + pkey_index, addr, + nesting + 1, + found_net_dev); + if (matches > 1) + break; + } + up_read(&priv->vlan_rwsem); + + return matches; +} + +/* Returns the number of matching net_devs found (between 0 and 2). Also + * return the matching net_device in the @net_dev parameter, holding a + * reference to the net_device, if the number of matches >= 1 */ +static int __ipoib_get_net_dev_by_params(struct list_head *dev_list, u8 port, + u16 pkey_index, + const union ib_gid *gid, + const struct sockaddr *addr, + struct net_device **net_dev) +{ + struct ipoib_dev_priv *priv; + int matches = 0; + + *net_dev = NULL; + + list_for_each_entry(priv, dev_list, list) { + if (priv->port != port) + continue; + + matches += ipoib_match_gid_pkey_addr(priv, gid, pkey_index, + addr, 0, net_dev); + if (matches > 1) + break; + } + + return matches; +} + +static struct net_device *ipoib_get_net_dev_by_params( + struct ib_device *dev, u8 port, u16 pkey, + const union ib_gid *gid, const struct sockaddr *addr, + void *client_data) +{ + struct net_device *net_dev; + struct list_head *dev_list = client_data; + u16 pkey_index; + int matches; + int ret; + + if (!rdma_protocol_ib(dev, port)) + return NULL; + + ret = ib_find_cached_pkey(dev, port, pkey, &pkey_index); + if (ret) + return NULL; + + if (!dev_list) + return NULL; + + /* See if we can find a unique device matching the L2 parameters */ + matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, + gid, NULL, &net_dev); + + switch (matches) { + case 0: + return NULL; + case 1: + return net_dev; + } + + dev_put(net_dev); + + /* Couldn't find a unique device with L2 parameters only. Use L3 + * address to uniquely match the net device */ + matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index, + gid, addr, &net_dev); + switch (matches) { + case 0: + return NULL; + default: + dev_warn_ratelimited(&dev->dev, + "duplicate IP address detected\n"); + /* Fall through */ + case 1: + return net_dev; + } +} + int ipoib_set_mode(struct net_device *dev, const char *buf) { struct ipoib_dev_priv *priv = netdev_priv(dev); -- GitLab From 15865e7dab62a58407f1b7decdafd89dd0a8b063 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:17 +0300 Subject: [PATCH 5748/7006] IB/cm: Expose service ID in request events Expose the service ID on an incoming CM or SIDR request to the event handler. This will allow the RDMA CM module to de-multiplex connection requests based on the information encoded in the service ID. Acked-by: Sean Hefty Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 3 +++ include/rdma/ib_cm.h | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 82d5c4362aa85..93e9e2f34fc6a 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1268,6 +1268,7 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg, primary_path->packet_life_time = cm_req_get_primary_local_ack_timeout(req_msg); primary_path->packet_life_time -= (primary_path->packet_life_time > 0); + primary_path->service_id = req_msg->service_id; if (req_msg->alt_local_lid) { memset(alt_path, 0, sizeof *alt_path); @@ -1289,6 +1290,7 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg, alt_path->packet_life_time = cm_req_get_alt_local_ack_timeout(req_msg); alt_path->packet_life_time -= (alt_path->packet_life_time > 0); + alt_path->service_id = req_msg->service_id; } } @@ -2992,6 +2994,7 @@ static void cm_format_sidr_req_event(struct cm_work *work, param = &work->cm_event.param.sidr_req_rcvd; param->pkey = __be16_to_cpu(sidr_req_msg->pkey); param->listen_id = listen_id; + param->service_id = sidr_req_msg->service_id; param->port = work->port->port_num; work->cm_event.private_data = &sidr_req_msg->private_data; } diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 39ed2d2fbd514..1b567bbc3ad41 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -223,6 +223,7 @@ struct ib_cm_apr_event_param { struct ib_cm_sidr_req_event_param { struct ib_cm_id *listen_id; + __be64 service_id; u8 port; u16 pkey; }; -- GitLab From 067b171b8679f99e170feae2e1d2eae319736420 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:18 +0300 Subject: [PATCH 5749/7006] IB/cm: Share listening CM IDs Enabling network namespaces for RDMA CM will allow processes on different namespaces to listen on the same port. In order to leave namespace support out of the CM layer, this requires that multiple RDMA CM IDs will be able to share a single CM ID. This patch adds infrastructure to retrieve an existing listening ib_cm_id, based on its device and service ID, or create a new one if one does not already exist. It also adds a reference count for such instances (cm_id_private.listen_sharecount), and prevents cm_destroy_id from destroying a CM if it is still shared. See the relevant discussion [1]. [1] Re: [PATCH v3 for-next 05/13] IB/cm: Reference count ib_cm_ids http://www.spinics.net/lists/netdev/msg328860.html Reviewed-by: Jason Gunthorpe Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 122 +++++++++++++++++++++++++++++++++-- include/rdma/ib_cm.h | 4 ++ 2 files changed, 120 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 93e9e2f34fc6a..fa3d3e7551273 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -213,6 +213,9 @@ struct cm_id_private { spinlock_t lock; /* Do not acquire inside cm.lock */ struct completion comp; atomic_t refcount; + /* Number of clients sharing this ib_cm_id. Only valid for listeners. + * Protected by the cm.lock spinlock. */ + int listen_sharecount; struct ib_mad_send_buf *msg; struct cm_timewait_info *timewait_info; @@ -859,9 +862,15 @@ retest: spin_lock_irq(&cm_id_priv->lock); switch (cm_id->state) { case IB_CM_LISTEN: - cm_id->state = IB_CM_IDLE; spin_unlock_irq(&cm_id_priv->lock); + spin_lock_irq(&cm.lock); + if (--cm_id_priv->listen_sharecount > 0) { + /* The id is still shared. */ + cm_deref_id(cm_id_priv); + spin_unlock_irq(&cm.lock); + return; + } rb_erase(&cm_id_priv->service_node, &cm.listen_service_table); spin_unlock_irq(&cm.lock); break; @@ -941,11 +950,32 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id) } EXPORT_SYMBOL(ib_destroy_cm_id); -int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, - struct ib_cm_compare_data *compare_data) +/** + * __ib_cm_listen - Initiates listening on the specified service ID for + * connection and service ID resolution requests. + * @cm_id: Connection identifier associated with the listen request. + * @service_id: Service identifier matched against incoming connection + * and service ID resolution requests. The service ID should be specified + * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will + * assign a service ID to the caller. + * @service_mask: Mask applied to service ID used to listen across a + * range of service IDs. If set to 0, the service ID is matched + * exactly. This parameter is ignored if %service_id is set to + * IB_CM_ASSIGN_SERVICE_ID. + * @compare_data: This parameter is optional. It specifies data that must + * appear in the private data of a connection request for the specified + * listen request. + * @lock: If set, lock the cm.lock spin-lock when adding the id to the + * listener tree. When false, the caller must already hold the spin-lock, + * and compare_data must be NULL. + */ +static int __ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, + __be64 service_mask, + struct ib_cm_compare_data *compare_data, + bool lock) { struct cm_id_private *cm_id_priv, *cur_cm_id_priv; - unsigned long flags; + unsigned long flags = 0; int ret = 0; service_mask = service_mask ? service_mask : ~cpu_to_be64(0); @@ -970,8 +1000,10 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, } cm_id->state = IB_CM_LISTEN; + if (lock) + spin_lock_irqsave(&cm.lock, flags); - spin_lock_irqsave(&cm.lock, flags); + ++cm_id_priv->listen_sharecount; if (service_id == IB_CM_ASSIGN_SERVICE_ID) { cm_id->service_id = cpu_to_be64(cm.listen_service_id++); cm_id->service_mask = ~cpu_to_be64(0); @@ -980,18 +1012,96 @@ int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, cm_id->service_mask = service_mask; } cur_cm_id_priv = cm_insert_listen(cm_id_priv); - spin_unlock_irqrestore(&cm.lock, flags); if (cur_cm_id_priv) { cm_id->state = IB_CM_IDLE; + --cm_id_priv->listen_sharecount; kfree(cm_id_priv->compare_data); cm_id_priv->compare_data = NULL; ret = -EBUSY; } + + if (lock) + spin_unlock_irqrestore(&cm.lock, flags); + return ret; } + +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, + struct ib_cm_compare_data *compare_data) +{ + return __ib_cm_listen(cm_id, service_id, service_mask, compare_data, + true); +} EXPORT_SYMBOL(ib_cm_listen); +/** + * Create a new listening ib_cm_id and listen on the given service ID. + * + * If there's an existing ID listening on that same device and service ID, + * return it. + * + * @device: Device associated with the cm_id. All related communication will + * be associated with the specified device. + * @cm_handler: Callback invoked to notify the user of CM events. + * @service_id: Service identifier matched against incoming connection + * and service ID resolution requests. The service ID should be specified + * network-byte order. If set to IB_CM_ASSIGN_SERVICE_ID, the CM will + * assign a service ID to the caller. + * + * Callers should call ib_destroy_cm_id when done with the listener ID. + */ +struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, + ib_cm_handler cm_handler, + __be64 service_id) +{ + struct cm_id_private *cm_id_priv; + struct ib_cm_id *cm_id; + unsigned long flags; + int err = 0; + + /* Create an ID in advance, since the creation may sleep */ + cm_id = ib_create_cm_id(device, cm_handler, NULL); + if (IS_ERR(cm_id)) + return cm_id; + + spin_lock_irqsave(&cm.lock, flags); + + if (service_id == IB_CM_ASSIGN_SERVICE_ID) + goto new_id; + + /* Find an existing ID */ + cm_id_priv = cm_find_listen(device, service_id, NULL); + if (cm_id_priv) { + if (cm_id->cm_handler != cm_handler || cm_id->context) { + /* Sharing an ib_cm_id with different handlers is not + * supported */ + spin_unlock_irqrestore(&cm.lock, flags); + return ERR_PTR(-EINVAL); + } + atomic_inc(&cm_id_priv->refcount); + ++cm_id_priv->listen_sharecount; + spin_unlock_irqrestore(&cm.lock, flags); + + ib_destroy_cm_id(cm_id); + cm_id = &cm_id_priv->id; + return cm_id; + } + +new_id: + /* Use newly created ID */ + err = __ib_cm_listen(cm_id, service_id, 0, NULL, false); + + spin_unlock_irqrestore(&cm.lock, flags); + + if (err) { + ib_destroy_cm_id(cm_id); + return ERR_PTR(err); + } + return cm_id; +} +EXPORT_SYMBOL(ib_cm_insert_listen); + static __be64 cm_form_tid(struct cm_id_private *cm_id_priv, enum cm_msg_sequence msg_seq) { diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 1b567bbc3ad41..9cc496e1f2add 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -362,6 +362,10 @@ struct ib_cm_compare_data { int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, struct ib_cm_compare_data *compare_data); +struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, + ib_cm_handler cm_handler, + __be64 service_id); + struct ib_cm_req_param { struct ib_sa_path_rec *primary_path; struct ib_sa_path_rec *alternate_path; -- GitLab From 0c505f70a28d943e15a6702ca75bea4f332a03ed Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:19 +0300 Subject: [PATCH 5750/7006] IB/cma: Refactor RDMA IP CM private-data parsing code When receiving a connection request, rdma_cm needs to associate the request with a network device, in order to disambiguate requests. To do this, it needs to know the request's destination IP. For this the module needs to allow getting this information from the private data in the request packet, instead of relying on the information already being in the listening RDMA CM ID. When creating a new incoming connection ID, the code in cma_save_ip{4,6}_info can no longer rely on the listener's private data to find the port number, so it reads it from the requested service ID. Signed-off-by: Guy Shapiro Signed-off-by: Haggai Eran Signed-off-by: Yotam Kenneth Signed-off-by: Shachar Raindel Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 170 +++++++++++++++++++++------------- 1 file changed, 105 insertions(+), 65 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9664131c4eeb6..249944c2c537e 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -870,107 +870,138 @@ static inline int cma_any_port(struct sockaddr *addr) return !cma_port(addr); } -static void cma_save_ib_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id, +static void cma_save_ib_info(struct sockaddr *src_addr, + struct sockaddr *dst_addr, + struct rdma_cm_id *listen_id, struct ib_sa_path_rec *path) { struct sockaddr_ib *listen_ib, *ib; listen_ib = (struct sockaddr_ib *) &listen_id->route.addr.src_addr; - ib = (struct sockaddr_ib *) &id->route.addr.src_addr; - ib->sib_family = listen_ib->sib_family; - if (path) { - ib->sib_pkey = path->pkey; - ib->sib_flowinfo = path->flow_label; - memcpy(&ib->sib_addr, &path->sgid, 16); - } else { - ib->sib_pkey = listen_ib->sib_pkey; - ib->sib_flowinfo = listen_ib->sib_flowinfo; - ib->sib_addr = listen_ib->sib_addr; - } - ib->sib_sid = listen_ib->sib_sid; - ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); - ib->sib_scope_id = listen_ib->sib_scope_id; - - if (path) { - ib = (struct sockaddr_ib *) &id->route.addr.dst_addr; - ib->sib_family = listen_ib->sib_family; - ib->sib_pkey = path->pkey; - ib->sib_flowinfo = path->flow_label; - memcpy(&ib->sib_addr, &path->dgid, 16); + if (src_addr) { + ib = (struct sockaddr_ib *)src_addr; + ib->sib_family = AF_IB; + if (path) { + ib->sib_pkey = path->pkey; + ib->sib_flowinfo = path->flow_label; + memcpy(&ib->sib_addr, &path->sgid, 16); + ib->sib_sid = path->service_id; + ib->sib_scope_id = 0; + } else { + ib->sib_pkey = listen_ib->sib_pkey; + ib->sib_flowinfo = listen_ib->sib_flowinfo; + ib->sib_addr = listen_ib->sib_addr; + ib->sib_sid = listen_ib->sib_sid; + ib->sib_scope_id = listen_ib->sib_scope_id; + } + ib->sib_sid_mask = cpu_to_be64(0xffffffffffffffffULL); + } + if (dst_addr) { + ib = (struct sockaddr_ib *)dst_addr; + ib->sib_family = AF_IB; + if (path) { + ib->sib_pkey = path->pkey; + ib->sib_flowinfo = path->flow_label; + memcpy(&ib->sib_addr, &path->dgid, 16); + } } } -static __be16 ss_get_port(const struct sockaddr_storage *ss) -{ - if (ss->ss_family == AF_INET) - return ((struct sockaddr_in *)ss)->sin_port; - else if (ss->ss_family == AF_INET6) - return ((struct sockaddr_in6 *)ss)->sin6_port; - BUG(); -} - -static void cma_save_ip4_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id, - struct cma_hdr *hdr) +static void cma_save_ip4_info(struct sockaddr *src_addr, + struct sockaddr *dst_addr, + struct cma_hdr *hdr, + __be16 local_port) { struct sockaddr_in *ip4; - ip4 = (struct sockaddr_in *) &id->route.addr.src_addr; - ip4->sin_family = AF_INET; - ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr; - ip4->sin_port = ss_get_port(&listen_id->route.addr.src_addr); + if (src_addr) { + ip4 = (struct sockaddr_in *)src_addr; + ip4->sin_family = AF_INET; + ip4->sin_addr.s_addr = hdr->dst_addr.ip4.addr; + ip4->sin_port = local_port; + } - ip4 = (struct sockaddr_in *) &id->route.addr.dst_addr; - ip4->sin_family = AF_INET; - ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr; - ip4->sin_port = hdr->port; + if (dst_addr) { + ip4 = (struct sockaddr_in *)dst_addr; + ip4->sin_family = AF_INET; + ip4->sin_addr.s_addr = hdr->src_addr.ip4.addr; + ip4->sin_port = hdr->port; + } } -static void cma_save_ip6_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id, - struct cma_hdr *hdr) +static void cma_save_ip6_info(struct sockaddr *src_addr, + struct sockaddr *dst_addr, + struct cma_hdr *hdr, + __be16 local_port) { struct sockaddr_in6 *ip6; - ip6 = (struct sockaddr_in6 *) &id->route.addr.src_addr; - ip6->sin6_family = AF_INET6; - ip6->sin6_addr = hdr->dst_addr.ip6; - ip6->sin6_port = ss_get_port(&listen_id->route.addr.src_addr); + if (src_addr) { + ip6 = (struct sockaddr_in6 *)src_addr; + ip6->sin6_family = AF_INET6; + ip6->sin6_addr = hdr->dst_addr.ip6; + ip6->sin6_port = local_port; + } - ip6 = (struct sockaddr_in6 *) &id->route.addr.dst_addr; - ip6->sin6_family = AF_INET6; - ip6->sin6_addr = hdr->src_addr.ip6; - ip6->sin6_port = hdr->port; + if (dst_addr) { + ip6 = (struct sockaddr_in6 *)dst_addr; + ip6->sin6_family = AF_INET6; + ip6->sin6_addr = hdr->src_addr.ip6; + ip6->sin6_port = hdr->port; + } } -static int cma_save_net_info(struct rdma_cm_id *id, struct rdma_cm_id *listen_id, - struct ib_cm_event *ib_event) +static u16 cma_port_from_service_id(__be64 service_id) { - struct cma_hdr *hdr; + return (u16)be64_to_cpu(service_id); +} - if (listen_id->route.addr.src_addr.ss_family == AF_IB) { - if (ib_event->event == IB_CM_REQ_RECEIVED) - cma_save_ib_info(id, listen_id, ib_event->param.req_rcvd.primary_path); - else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) - cma_save_ib_info(id, listen_id, NULL); - return 0; - } +static int cma_save_ip_info(struct sockaddr *src_addr, + struct sockaddr *dst_addr, + struct ib_cm_event *ib_event, + __be64 service_id) +{ + struct cma_hdr *hdr; + __be16 port; hdr = ib_event->private_data; if (hdr->cma_version != CMA_VERSION) return -EINVAL; + port = htons(cma_port_from_service_id(service_id)); + switch (cma_get_ip_ver(hdr)) { case 4: - cma_save_ip4_info(id, listen_id, hdr); + cma_save_ip4_info(src_addr, dst_addr, hdr, port); break; case 6: - cma_save_ip6_info(id, listen_id, hdr); + cma_save_ip6_info(src_addr, dst_addr, hdr, port); break; default: return -EINVAL; } + return 0; } +static int cma_save_net_info(struct sockaddr *src_addr, + struct sockaddr *dst_addr, + struct rdma_cm_id *listen_id, + struct ib_cm_event *ib_event, + sa_family_t sa_family, __be64 service_id) +{ + if (sa_family == AF_IB) { + if (ib_event->event == IB_CM_REQ_RECEIVED) + cma_save_ib_info(src_addr, dst_addr, listen_id, + ib_event->param.req_rcvd.primary_path); + else if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) + cma_save_ib_info(src_addr, dst_addr, listen_id, NULL); + return 0; + } + + return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id); +} + static inline int cma_user_data_offset(struct rdma_id_private *id_priv) { return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr); @@ -1221,6 +1252,9 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, struct rdma_id_private *id_priv; struct rdma_cm_id *id; struct rdma_route *rt; + const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; + const __be64 service_id = + ib_event->param.req_rcvd.primary_path->service_id; int ret; id = rdma_create_id(listen_id->event_handler, listen_id->context, @@ -1229,7 +1263,9 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, return NULL; id_priv = container_of(id, struct rdma_id_private, id); - if (cma_save_net_info(id, listen_id, ib_event)) + if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, + (struct sockaddr *)&id->route.addr.dst_addr, + listen_id, ib_event, ss_family, service_id)) goto err; rt = &id->route; @@ -1267,6 +1303,7 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, { struct rdma_id_private *id_priv; struct rdma_cm_id *id; + const sa_family_t ss_family = listen_id->route.addr.src_addr.ss_family; int ret; id = rdma_create_id(listen_id->event_handler, listen_id->context, @@ -1275,7 +1312,10 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, return NULL; id_priv = container_of(id, struct rdma_id_private, id); - if (cma_save_net_info(id, listen_id, ib_event)) + if (cma_save_net_info((struct sockaddr *)&id->route.addr.src_addr, + (struct sockaddr *)&id->route.addr.dst_addr, + listen_id, ib_event, ss_family, + ib_event->param.sidr_req_rcvd.service_id)) goto err; if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { -- GitLab From aac978e15230fccb7a3e9190eb58732925019300 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:20 +0300 Subject: [PATCH 5751/7006] IB/cma: Helper functions to access port space IDRs Add helper functions to access the IDRs by port-space and port number. Pass around the port-space enum in cma.c instead of using pointers to port-space IDRs. Signed-off-by: Haggai Eran Signed-off-by: Yotam Kenneth Signed-off-by: Shachar Raindel Signed-off-by: Guy Shapiro Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 81 ++++++++++++++++++++++++++--------- 1 file changed, 60 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 249944c2c537e..a7886acba0724 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -113,6 +113,22 @@ static DEFINE_IDR(udp_ps); static DEFINE_IDR(ipoib_ps); static DEFINE_IDR(ib_ps); +static struct idr *cma_idr(enum rdma_port_space ps) +{ + switch (ps) { + case RDMA_PS_TCP: + return &tcp_ps; + case RDMA_PS_UDP: + return &udp_ps; + case RDMA_PS_IPOIB: + return &ipoib_ps; + case RDMA_PS_IB: + return &ib_ps; + default: + return NULL; + } +} + struct cma_device { struct list_head list; struct ib_device *device; @@ -122,11 +138,33 @@ struct cma_device { }; struct rdma_bind_list { - struct idr *ps; + enum rdma_port_space ps; struct hlist_head owners; unsigned short port; }; +static int cma_ps_alloc(enum rdma_port_space ps, + struct rdma_bind_list *bind_list, int snum) +{ + struct idr *idr = cma_idr(ps); + + return idr_alloc(idr, bind_list, snum, snum + 1, GFP_KERNEL); +} + +static struct rdma_bind_list *cma_ps_find(enum rdma_port_space ps, int snum) +{ + struct idr *idr = cma_idr(ps); + + return idr_find(idr, snum); +} + +static void cma_ps_remove(enum rdma_port_space ps, int snum) +{ + struct idr *idr = cma_idr(ps); + + idr_remove(idr, snum); +} + enum { CMA_OPTION_AFONLY, }; @@ -1069,7 +1107,7 @@ static void cma_release_port(struct rdma_id_private *id_priv) mutex_lock(&lock); hlist_del(&id_priv->node); if (hlist_empty(&bind_list->owners)) { - idr_remove(bind_list->ps, bind_list->port); + cma_ps_remove(bind_list->ps, bind_list->port); kfree(bind_list); } mutex_unlock(&lock); @@ -2368,8 +2406,8 @@ static void cma_bind_port(struct rdma_bind_list *bind_list, hlist_add_head(&id_priv->node, &bind_list->owners); } -static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, - unsigned short snum) +static int cma_alloc_port(enum rdma_port_space ps, + struct rdma_id_private *id_priv, unsigned short snum) { struct rdma_bind_list *bind_list; int ret; @@ -2378,7 +2416,7 @@ static int cma_alloc_port(struct idr *ps, struct rdma_id_private *id_priv, if (!bind_list) return -ENOMEM; - ret = idr_alloc(ps, bind_list, snum, snum + 1, GFP_KERNEL); + ret = cma_ps_alloc(ps, bind_list, snum); if (ret < 0) goto err; @@ -2391,7 +2429,8 @@ err: return ret == -ENOSPC ? -EADDRNOTAVAIL : ret; } -static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) +static int cma_alloc_any_port(enum rdma_port_space ps, + struct rdma_id_private *id_priv) { static unsigned int last_used_port; int low, high, remaining; @@ -2402,7 +2441,7 @@ static int cma_alloc_any_port(struct idr *ps, struct rdma_id_private *id_priv) rover = prandom_u32() % remaining + low; retry: if (last_used_port != rover && - !idr_find(ps, (unsigned short) rover)) { + !cma_ps_find(ps, (unsigned short)rover)) { int ret = cma_alloc_port(ps, id_priv, rover); /* * Remember previously used port number in order to avoid @@ -2457,7 +2496,8 @@ static int cma_check_port(struct rdma_bind_list *bind_list, return 0; } -static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) +static int cma_use_port(enum rdma_port_space ps, + struct rdma_id_private *id_priv) { struct rdma_bind_list *bind_list; unsigned short snum; @@ -2467,7 +2507,7 @@ static int cma_use_port(struct idr *ps, struct rdma_id_private *id_priv) if (snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) return -EACCES; - bind_list = idr_find(ps, snum); + bind_list = cma_ps_find(ps, snum); if (!bind_list) { ret = cma_alloc_port(ps, id_priv, snum); } else { @@ -2490,25 +2530,24 @@ static int cma_bind_listen(struct rdma_id_private *id_priv) return ret; } -static struct idr *cma_select_inet_ps(struct rdma_id_private *id_priv) +static enum rdma_port_space cma_select_inet_ps( + struct rdma_id_private *id_priv) { switch (id_priv->id.ps) { case RDMA_PS_TCP: - return &tcp_ps; case RDMA_PS_UDP: - return &udp_ps; case RDMA_PS_IPOIB: - return &ipoib_ps; case RDMA_PS_IB: - return &ib_ps; + return id_priv->id.ps; default: - return NULL; + + return 0; } } -static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv) +static enum rdma_port_space cma_select_ib_ps(struct rdma_id_private *id_priv) { - struct idr *ps = NULL; + enum rdma_port_space ps = 0; struct sockaddr_ib *sib; u64 sid_ps, mask, sid; @@ -2518,15 +2557,15 @@ static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv) if ((id_priv->id.ps == RDMA_PS_IB) && (sid == (RDMA_IB_IP_PS_IB & mask))) { sid_ps = RDMA_IB_IP_PS_IB; - ps = &ib_ps; + ps = RDMA_PS_IB; } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_TCP)) && (sid == (RDMA_IB_IP_PS_TCP & mask))) { sid_ps = RDMA_IB_IP_PS_TCP; - ps = &tcp_ps; + ps = RDMA_PS_TCP; } else if (((id_priv->id.ps == RDMA_PS_IB) || (id_priv->id.ps == RDMA_PS_UDP)) && (sid == (RDMA_IB_IP_PS_UDP & mask))) { sid_ps = RDMA_IB_IP_PS_UDP; - ps = &udp_ps; + ps = RDMA_PS_UDP; } if (ps) { @@ -2539,7 +2578,7 @@ static struct idr *cma_select_ib_ps(struct rdma_id_private *id_priv) static int cma_get_port(struct rdma_id_private *id_priv) { - struct idr *ps; + enum rdma_port_space ps; int ret; if (cma_family(id_priv) != AF_IB) -- GitLab From 24cad9a7e8bfd4cf1ace7ac2a2b3f696a0e70420 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:21 +0300 Subject: [PATCH 5752/7006] IB/cm: Expose BTH P_Key in CM and SIDR request events The rdma_cm module will later use the P_Key from the BTH to de-mux requests. See discussion at: http://www.spinics.net/lists/netdev/msg336067.html Cc: Jason Gunthorpe Cc: Liran Liss Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 20 ++++++++++++++++++++ include/rdma/ib_cm.h | 6 ++++++ 2 files changed, 26 insertions(+) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index fa3d3e7551273..d2b2c83f00761 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1404,6 +1404,24 @@ static void cm_format_paths_from_req(struct cm_req_msg *req_msg, } } +static u16 cm_get_bth_pkey(struct cm_work *work) +{ + struct ib_device *ib_dev = work->port->cm_dev->ib_device; + u8 port_num = work->port->port_num; + u16 pkey_index = work->mad_recv_wc->wc->pkey_index; + u16 pkey; + int ret; + + ret = ib_get_cached_pkey(ib_dev, port_num, pkey_index, &pkey); + if (ret) { + dev_warn_ratelimited(&ib_dev->dev, "ib_cm: Couldn't retrieve pkey for incoming request (port %d, pkey index %d). %d\n", + port_num, pkey_index, ret); + return 0; + } + + return pkey; +} + static void cm_format_req_event(struct cm_work *work, struct cm_id_private *cm_id_priv, struct ib_cm_id *listen_id) @@ -1414,6 +1432,7 @@ static void cm_format_req_event(struct cm_work *work, req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; param = &work->cm_event.param.req_rcvd; param->listen_id = listen_id; + param->bth_pkey = cm_get_bth_pkey(work); param->port = cm_id_priv->av.port->port_num; param->primary_path = &work->path[0]; if (req_msg->alt_local_lid) @@ -3105,6 +3124,7 @@ static void cm_format_sidr_req_event(struct cm_work *work, param->pkey = __be16_to_cpu(sidr_req_msg->pkey); param->listen_id = listen_id; param->service_id = sidr_req_msg->service_id; + param->bth_pkey = cm_get_bth_pkey(work); param->port = work->port->port_num; work->cm_event.private_data = &sidr_req_msg->private_data; } diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 9cc496e1f2add..e3f48632e2379 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -113,6 +113,10 @@ struct ib_cm_id; struct ib_cm_req_event_param { struct ib_cm_id *listen_id; + + /* P_Key that was used by the GMP's BTH header */ + u16 bth_pkey; + u8 port; struct ib_sa_path_rec *primary_path; @@ -224,6 +228,8 @@ struct ib_cm_apr_event_param { struct ib_cm_sidr_req_event_param { struct ib_cm_id *listen_id; __be64 service_id; + /* P_Key that was used by the GMP's BTH header */ + u16 bth_pkey; u8 port; u16 pkey; }; -- GitLab From 4c21b5bcef73e6649429c1d9b39f5065e756d857 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:22 +0300 Subject: [PATCH 5753/7006] IB/cma: Add net_dev and private data checks to RDMA CM Instead of relying on a the ib_cm module to check an incoming CM request's private data header, add these checks to the RDMA CM module. This allows a following patch to to clean up the ib_cm interface and remove the code that looks into the private headers. It will also allow supporting namespaces in RDMA CM by making these checks namespace aware later on. Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 188 +++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index a7886acba0724..ed6abdbc93486 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -263,6 +263,15 @@ struct cma_hdr { #define CMA_VERSION 0x00 +struct cma_req_info { + struct ib_device *device; + int port; + union ib_gid local_gid; + __be64 service_id; + u16 pkey; + bool has_gid:1; +}; + static int cma_comp(struct rdma_id_private *id_priv, enum rdma_cm_state comp) { unsigned long flags; @@ -300,7 +309,7 @@ static enum rdma_cm_state cma_exch(struct rdma_id_private *id_priv, return old; } -static inline u8 cma_get_ip_ver(struct cma_hdr *hdr) +static inline u8 cma_get_ip_ver(const struct cma_hdr *hdr) { return hdr->ip_version >> 4; } @@ -1016,7 +1025,7 @@ static int cma_save_ip_info(struct sockaddr *src_addr, cma_save_ip6_info(src_addr, dst_addr, hdr, port); break; default: - return -EINVAL; + return -EAFNOSUPPORT; } return 0; @@ -1040,6 +1049,176 @@ static int cma_save_net_info(struct sockaddr *src_addr, return cma_save_ip_info(src_addr, dst_addr, ib_event, service_id); } +static int cma_save_req_info(const struct ib_cm_event *ib_event, + struct cma_req_info *req) +{ + const struct ib_cm_req_event_param *req_param = + &ib_event->param.req_rcvd; + const struct ib_cm_sidr_req_event_param *sidr_param = + &ib_event->param.sidr_req_rcvd; + + switch (ib_event->event) { + case IB_CM_REQ_RECEIVED: + req->device = req_param->listen_id->device; + req->port = req_param->port; + memcpy(&req->local_gid, &req_param->primary_path->sgid, + sizeof(req->local_gid)); + req->has_gid = true; + req->service_id = req_param->primary_path->service_id; + req->pkey = req_param->bth_pkey; + break; + case IB_CM_SIDR_REQ_RECEIVED: + req->device = sidr_param->listen_id->device; + req->port = sidr_param->port; + req->has_gid = false; + req->service_id = sidr_param->service_id; + req->pkey = sidr_param->bth_pkey; + break; + default: + return -EINVAL; + } + + return 0; +} + +static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, + const struct cma_req_info *req) +{ + struct sockaddr_storage listen_addr_storage; + struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage; + struct net_device *net_dev; + const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; + int err; + + err = cma_save_ip_info(listen_addr, NULL, ib_event, req->service_id); + if (err) + return ERR_PTR(err); + + net_dev = ib_get_net_dev_by_params(req->device, req->port, req->pkey, + gid, listen_addr); + if (!net_dev) + return ERR_PTR(-ENODEV); + + return net_dev; +} + +static enum rdma_port_space rdma_ps_from_service_id(__be64 service_id) +{ + return (be64_to_cpu(service_id) >> 16) & 0xffff; +} + +static bool cma_match_private_data(struct rdma_id_private *id_priv, + const struct cma_hdr *hdr) +{ + struct sockaddr *addr = cma_src_addr(id_priv); + __be32 ip4_addr; + struct in6_addr ip6_addr; + + if (cma_any_addr(addr) && !id_priv->afonly) + return true; + + switch (addr->sa_family) { + case AF_INET: + ip4_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (cma_get_ip_ver(hdr) != 4) + return false; + if (!cma_any_addr(addr) && + hdr->dst_addr.ip4.addr != ip4_addr) + return false; + break; + case AF_INET6: + ip6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr; + if (cma_get_ip_ver(hdr) != 6) + return false; + if (!cma_any_addr(addr) && + memcmp(&hdr->dst_addr.ip6, &ip6_addr, sizeof(ip6_addr))) + return false; + break; + case AF_IB: + return true; + default: + return false; + } + + return true; +} + +static bool cma_match_net_dev(const struct rdma_id_private *id_priv, + const struct net_device *net_dev) +{ + const struct rdma_addr *addr = &id_priv->id.route.addr; + + if (!net_dev) + /* This request is an AF_IB request */ + return addr->src_addr.ss_family == AF_IB; + + return !addr->dev_addr.bound_dev_if || + (net_eq(dev_net(net_dev), &init_net) && + addr->dev_addr.bound_dev_if == net_dev->ifindex); +} + +static struct rdma_id_private *cma_find_listener( + const struct rdma_bind_list *bind_list, + const struct ib_cm_id *cm_id, + const struct ib_cm_event *ib_event, + const struct cma_req_info *req, + const struct net_device *net_dev) +{ + struct rdma_id_private *id_priv, *id_priv_dev; + + if (!bind_list) + return ERR_PTR(-EINVAL); + + hlist_for_each_entry(id_priv, &bind_list->owners, node) { + if (cma_match_private_data(id_priv, ib_event->private_data)) { + if (id_priv->id.device == cm_id->device && + cma_match_net_dev(id_priv, net_dev)) + return id_priv; + list_for_each_entry(id_priv_dev, + &id_priv->listen_list, + listen_list) { + if (id_priv_dev->id.device == cm_id->device && + cma_match_net_dev(id_priv_dev, net_dev)) + return id_priv_dev; + } + } + } + + return ERR_PTR(-EINVAL); +} + +static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id, + struct ib_cm_event *ib_event) +{ + struct cma_req_info req; + struct rdma_bind_list *bind_list; + struct rdma_id_private *id_priv; + struct net_device *net_dev; + int err; + + err = cma_save_req_info(ib_event, &req); + if (err) + return ERR_PTR(err); + + net_dev = cma_get_net_dev(ib_event, &req); + if (IS_ERR(net_dev)) { + if (PTR_ERR(net_dev) == -EAFNOSUPPORT) { + /* Assuming the protocol is AF_IB */ + net_dev = NULL; + } else { + return ERR_CAST(net_dev); + } + } + + bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id), + cma_port_from_service_id(req.service_id)); + id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, net_dev); + + dev_put(net_dev); + + return id_priv; +} + static inline int cma_user_data_offset(struct rdma_id_private *id_priv) { return cma_family(id_priv) == AF_IB ? 0 : sizeof(struct cma_hdr); @@ -1399,7 +1578,10 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) struct rdma_cm_event event; int offset, ret; - listen_id = cm_id->context; + listen_id = cma_id_from_event(cm_id, ib_event); + if (IS_ERR(listen_id)) + return PTR_ERR(listen_id); + if (!cma_check_req_qp_type(&listen_id->id, ib_event)) return -EINVAL; -- GitLab From f887f2ac87c25124a90adf97d76b258eba6295cb Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:23 +0300 Subject: [PATCH 5754/7006] IB/cma: Validate routing of incoming requests Pass incoming request parameters through the relevant IPv4/IPv6 routing tables and make sure the network stack is configured to handle such requests. Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 95 +++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index ed6abdbc93486..951ff96c99e1d 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -46,6 +46,8 @@ #include #include +#include +#include #include #include @@ -1081,16 +1083,98 @@ static int cma_save_req_info(const struct ib_cm_event *ib_event, return 0; } +static bool validate_ipv4_net_dev(struct net_device *net_dev, + const struct sockaddr_in *dst_addr, + const struct sockaddr_in *src_addr) +{ + __be32 daddr = dst_addr->sin_addr.s_addr, + saddr = src_addr->sin_addr.s_addr; + struct fib_result res; + struct flowi4 fl4; + int err; + bool ret; + + if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || + ipv4_is_lbcast(daddr) || ipv4_is_zeronet(saddr) || + ipv4_is_zeronet(daddr) || ipv4_is_loopback(daddr) || + ipv4_is_loopback(saddr)) + return false; + + memset(&fl4, 0, sizeof(fl4)); + fl4.flowi4_iif = net_dev->ifindex; + fl4.daddr = daddr; + fl4.saddr = saddr; + + rcu_read_lock(); + err = fib_lookup(dev_net(net_dev), &fl4, &res, 0); + if (err) + return false; + + ret = FIB_RES_DEV(res) == net_dev; + rcu_read_unlock(); + + return ret; +} + +static bool validate_ipv6_net_dev(struct net_device *net_dev, + const struct sockaddr_in6 *dst_addr, + const struct sockaddr_in6 *src_addr) +{ +#if IS_ENABLED(CONFIG_IPV6) + const int strict = ipv6_addr_type(&dst_addr->sin6_addr) & + IPV6_ADDR_LINKLOCAL; + struct rt6_info *rt = rt6_lookup(dev_net(net_dev), &dst_addr->sin6_addr, + &src_addr->sin6_addr, net_dev->ifindex, + strict); + bool ret; + + if (!rt) + return false; + + ret = rt->rt6i_idev->dev == net_dev; + ip6_rt_put(rt); + + return ret; +#else + return false; +#endif +} + +static bool validate_net_dev(struct net_device *net_dev, + const struct sockaddr *daddr, + const struct sockaddr *saddr) +{ + const struct sockaddr_in *daddr4 = (const struct sockaddr_in *)daddr; + const struct sockaddr_in *saddr4 = (const struct sockaddr_in *)saddr; + const struct sockaddr_in6 *daddr6 = (const struct sockaddr_in6 *)daddr; + const struct sockaddr_in6 *saddr6 = (const struct sockaddr_in6 *)saddr; + + switch (daddr->sa_family) { + case AF_INET: + return saddr->sa_family == AF_INET && + validate_ipv4_net_dev(net_dev, daddr4, saddr4); + + case AF_INET6: + return saddr->sa_family == AF_INET6 && + validate_ipv6_net_dev(net_dev, daddr6, saddr6); + + default: + return false; + } +} + static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, const struct cma_req_info *req) { - struct sockaddr_storage listen_addr_storage; - struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage; + struct sockaddr_storage listen_addr_storage, src_addr_storage; + struct sockaddr *listen_addr = (struct sockaddr *)&listen_addr_storage, + *src_addr = (struct sockaddr *)&src_addr_storage; struct net_device *net_dev; const union ib_gid *gid = req->has_gid ? &req->local_gid : NULL; int err; - err = cma_save_ip_info(listen_addr, NULL, ib_event, req->service_id); + err = cma_save_ip_info(listen_addr, src_addr, ib_event, + req->service_id); if (err) return ERR_PTR(err); @@ -1099,6 +1183,11 @@ static struct net_device *cma_get_net_dev(struct ib_cm_event *ib_event, if (!net_dev) return ERR_PTR(-ENODEV); + if (!validate_net_dev(net_dev, listen_addr, src_addr)) { + dev_put(net_dev); + return ERR_PTR(-EHOSTUNREACH); + } + return net_dev; } -- GitLab From 0b3ca768fcb07338c99df5e3ccec99119435e321 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:24 +0300 Subject: [PATCH 5755/7006] IB/cma: Use found net_dev for passive connections When receiving a new connection in cma_req_handler, we actually already know the net_dev that is used for the connection's creation. Instead of calling cma_translate_addr to resolve the new connection id's source address, just use the net_dev that was found. Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 76 ++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 27 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 951ff96c99e1d..0a7475c921aa3 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1277,33 +1277,31 @@ static struct rdma_id_private *cma_find_listener( } static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id, - struct ib_cm_event *ib_event) + struct ib_cm_event *ib_event, + struct net_device **net_dev) { struct cma_req_info req; struct rdma_bind_list *bind_list; struct rdma_id_private *id_priv; - struct net_device *net_dev; int err; err = cma_save_req_info(ib_event, &req); if (err) return ERR_PTR(err); - net_dev = cma_get_net_dev(ib_event, &req); - if (IS_ERR(net_dev)) { - if (PTR_ERR(net_dev) == -EAFNOSUPPORT) { + *net_dev = cma_get_net_dev(ib_event, &req); + if (IS_ERR(*net_dev)) { + if (PTR_ERR(*net_dev) == -EAFNOSUPPORT) { /* Assuming the protocol is AF_IB */ - net_dev = NULL; + *net_dev = NULL; } else { - return ERR_CAST(net_dev); + return ERR_CAST(*net_dev); } } bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id), cma_port_from_service_id(req.service_id)); - id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, net_dev); - - dev_put(net_dev); + id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev); return id_priv; } @@ -1553,7 +1551,8 @@ out: } static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, - struct ib_cm_event *ib_event) + struct ib_cm_event *ib_event, + struct net_device *net_dev) { struct rdma_id_private *id_priv; struct rdma_cm_id *id; @@ -1585,14 +1584,16 @@ static struct rdma_id_private *cma_new_conn_id(struct rdma_cm_id *listen_id, if (rt->num_paths == 2) rt->path_rec[1] = *ib_event->param.req_rcvd.alternate_path; - if (cma_any_addr(cma_src_addr(id_priv))) { - rt->addr.dev_addr.dev_type = ARPHRD_INFINIBAND; - rdma_addr_set_sgid(&rt->addr.dev_addr, &rt->path_rec[0].sgid); - ib_addr_set_pkey(&rt->addr.dev_addr, be16_to_cpu(rt->path_rec[0].pkey)); - } else { - ret = cma_translate_addr(cma_src_addr(id_priv), &rt->addr.dev_addr); + if (net_dev) { + ret = rdma_copy_addr(&rt->addr.dev_addr, net_dev, NULL); if (ret) goto err; + } else { + /* An AF_IB connection */ + WARN_ON_ONCE(ss_family != AF_IB); + + cma_translate_ib((struct sockaddr_ib *)cma_src_addr(id_priv), + &rt->addr.dev_addr); } rdma_addr_set_dgid(&rt->addr.dev_addr, &rt->path_rec[0].dgid); @@ -1605,7 +1606,8 @@ err: } static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, - struct ib_cm_event *ib_event) + struct ib_cm_event *ib_event, + struct net_device *net_dev) { struct rdma_id_private *id_priv; struct rdma_cm_id *id; @@ -1624,10 +1626,18 @@ static struct rdma_id_private *cma_new_udp_id(struct rdma_cm_id *listen_id, ib_event->param.sidr_req_rcvd.service_id)) goto err; - if (!cma_any_addr((struct sockaddr *) &id->route.addr.src_addr)) { - ret = cma_translate_addr(cma_src_addr(id_priv), &id->route.addr.dev_addr); + if (net_dev) { + ret = rdma_copy_addr(&id->route.addr.dev_addr, net_dev, NULL); if (ret) goto err; + } else { + /* An AF_IB connection */ + WARN_ON_ONCE(ss_family != AF_IB); + + if (!cma_any_addr(cma_src_addr(id_priv))) + cma_translate_ib((struct sockaddr_ib *) + cma_src_addr(id_priv), + &id->route.addr.dev_addr); } id_priv->state = RDMA_CM_CONNECT; @@ -1665,28 +1675,33 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) { struct rdma_id_private *listen_id, *conn_id; struct rdma_cm_event event; + struct net_device *net_dev; int offset, ret; - listen_id = cma_id_from_event(cm_id, ib_event); + listen_id = cma_id_from_event(cm_id, ib_event, &net_dev); if (IS_ERR(listen_id)) return PTR_ERR(listen_id); - if (!cma_check_req_qp_type(&listen_id->id, ib_event)) - return -EINVAL; + if (!cma_check_req_qp_type(&listen_id->id, ib_event)) { + ret = -EINVAL; + goto net_dev_put; + } - if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) - return -ECONNABORTED; + if (cma_disable_callback(listen_id, RDMA_CM_LISTEN)) { + ret = -ECONNABORTED; + goto net_dev_put; + } memset(&event, 0, sizeof event); offset = cma_user_data_offset(listen_id); event.event = RDMA_CM_EVENT_CONNECT_REQUEST; if (ib_event->event == IB_CM_SIDR_REQ_RECEIVED) { - conn_id = cma_new_udp_id(&listen_id->id, ib_event); + conn_id = cma_new_udp_id(&listen_id->id, ib_event, net_dev); event.param.ud.private_data = ib_event->private_data + offset; event.param.ud.private_data_len = IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE - offset; } else { - conn_id = cma_new_conn_id(&listen_id->id, ib_event); + conn_id = cma_new_conn_id(&listen_id->id, ib_event, net_dev); cma_set_req_event_data(&event, &ib_event->param.req_rcvd, ib_event->private_data, offset); } @@ -1724,6 +1739,8 @@ static int cma_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *ib_event) mutex_unlock(&conn_id->handler_mutex); mutex_unlock(&listen_id->handler_mutex); cma_deref_id(conn_id); + if (net_dev) + dev_put(net_dev); return 0; err3: @@ -1737,6 +1754,11 @@ err1: mutex_unlock(&listen_id->handler_mutex); if (conn_id) rdma_destroy_id(&conn_id->id); + +net_dev_put: + if (net_dev) + dev_put(net_dev); + return ret; } -- GitLab From 51efe394bcab3a0c511634f7ae58bb88b1686983 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:25 +0300 Subject: [PATCH 5756/7006] IB/cma: Share ib_cm_ids between rdma_cm_ids Use ib_cm_insert_listen to create listening IB CM IDs or share existing ones if needed. When given a request on a specific CM ID, the code now matches the request to the RDMA CM ID based on the request parameters, so it no longer needs to rely on the ib_cm's private data matching capabilities. Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 59 +++-------------------------------- 1 file changed, 4 insertions(+), 55 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 0a7475c921aa3..9b306d7b5c272 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1771,42 +1771,6 @@ __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr) } EXPORT_SYMBOL(rdma_get_service_id); -static void cma_set_compare_data(enum rdma_port_space ps, struct sockaddr *addr, - struct ib_cm_compare_data *compare) -{ - struct cma_hdr *cma_data, *cma_mask; - __be32 ip4_addr; - struct in6_addr ip6_addr; - - memset(compare, 0, sizeof *compare); - cma_data = (void *) compare->data; - cma_mask = (void *) compare->mask; - - switch (addr->sa_family) { - case AF_INET: - ip4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr; - cma_set_ip_ver(cma_data, 4); - cma_set_ip_ver(cma_mask, 0xF); - if (!cma_any_addr(addr)) { - cma_data->dst_addr.ip4.addr = ip4_addr; - cma_mask->dst_addr.ip4.addr = htonl(~0); - } - break; - case AF_INET6: - ip6_addr = ((struct sockaddr_in6 *) addr)->sin6_addr; - cma_set_ip_ver(cma_data, 6); - cma_set_ip_ver(cma_mask, 0xF); - if (!cma_any_addr(addr)) { - cma_data->dst_addr.ip6 = ip6_addr; - memset(&cma_mask->dst_addr.ip6, 0xFF, - sizeof cma_mask->dst_addr.ip6); - } - break; - default: - break; - } -} - static int cma_iw_handler(struct iw_cm_id *iw_id, struct iw_cm_event *iw_event) { struct rdma_id_private *id_priv = iw_id->context; @@ -1960,33 +1924,18 @@ out: static int cma_ib_listen(struct rdma_id_private *id_priv) { - struct ib_cm_compare_data compare_data; struct sockaddr *addr; struct ib_cm_id *id; __be64 svc_id; - int ret; - id = ib_create_cm_id(id_priv->id.device, cma_req_handler, id_priv); + addr = cma_src_addr(id_priv); + svc_id = rdma_get_service_id(&id_priv->id, addr); + id = ib_cm_insert_listen(id_priv->id.device, cma_req_handler, svc_id); if (IS_ERR(id)) return PTR_ERR(id); - id_priv->cm_id.ib = id; - addr = cma_src_addr(id_priv); - svc_id = rdma_get_service_id(&id_priv->id, addr); - if (cma_any_addr(addr) && !id_priv->afonly) - ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, NULL); - else { - cma_set_compare_data(id_priv->id.ps, addr, &compare_data); - ret = ib_cm_listen(id_priv->cm_id.ib, svc_id, 0, &compare_data); - } - - if (ret) { - ib_destroy_cm_id(id_priv->cm_id.ib); - id_priv->cm_id.ib = NULL; - } - - return ret; + return 0; } static int cma_iw_listen(struct rdma_id_private *id_priv, int backlog) -- GitLab From 73fec7fd04a2ad6c879c93881cba9a40d551b3fd Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 30 Jul 2015 17:50:26 +0300 Subject: [PATCH 5757/7006] IB/cm: Remove compare_data checks Now that there are no ib_cm clients using the compare_data feature for matching IB CM requests' private data, remove the compare_data parameter of ib_cm_listen and remove the code implementing the feature. Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 109 ++++-------------------- drivers/infiniband/core/ucm.c | 3 +- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 2 +- drivers/infiniband/ulp/srpt/ib_srpt.c | 2 +- include/rdma/ib_cm.h | 14 +-- 5 files changed, 23 insertions(+), 107 deletions(-) diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index d2b2c83f00761..ea4db9c1d44fb 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -222,7 +222,6 @@ struct cm_id_private { /* todo: use alternate port on send failure */ struct cm_av av; struct cm_av alt_av; - struct ib_cm_compare_data *compare_data; void *private_data; __be64 tid; @@ -443,40 +442,6 @@ static struct cm_id_private * cm_acquire_id(__be32 local_id, __be32 remote_id) return cm_id_priv; } -static void cm_mask_copy(u32 *dst, const u32 *src, const u32 *mask) -{ - int i; - - for (i = 0; i < IB_CM_COMPARE_SIZE; i++) - dst[i] = src[i] & mask[i]; -} - -static int cm_compare_data(struct ib_cm_compare_data *src_data, - struct ib_cm_compare_data *dst_data) -{ - u32 src[IB_CM_COMPARE_SIZE]; - u32 dst[IB_CM_COMPARE_SIZE]; - - if (!src_data || !dst_data) - return 0; - - cm_mask_copy(src, src_data->data, dst_data->mask); - cm_mask_copy(dst, dst_data->data, src_data->mask); - return memcmp(src, dst, sizeof(src)); -} - -static int cm_compare_private_data(u32 *private_data, - struct ib_cm_compare_data *dst_data) -{ - u32 src[IB_CM_COMPARE_SIZE]; - - if (!dst_data) - return 0; - - cm_mask_copy(src, private_data, dst_data->mask); - return memcmp(src, dst_data->data, sizeof(src)); -} - /* * Trivial helpers to strip endian annotation and compare; the * endianness doesn't actually matter since we just need a stable @@ -509,18 +474,14 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) struct cm_id_private *cur_cm_id_priv; __be64 service_id = cm_id_priv->id.service_id; __be64 service_mask = cm_id_priv->id.service_mask; - int data_cmp; while (*link) { parent = *link; cur_cm_id_priv = rb_entry(parent, struct cm_id_private, service_node); - data_cmp = cm_compare_data(cm_id_priv->compare_data, - cur_cm_id_priv->compare_data); if ((cur_cm_id_priv->id.service_mask & service_id) == (service_mask & cur_cm_id_priv->id.service_id) && - (cm_id_priv->id.device == cur_cm_id_priv->id.device) && - !data_cmp) + (cm_id_priv->id.device == cur_cm_id_priv->id.device)) return cur_cm_id_priv; if (cm_id_priv->id.device < cur_cm_id_priv->id.device) @@ -531,8 +492,6 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) link = &(*link)->rb_left; else if (be64_gt(service_id, cur_cm_id_priv->id.service_id)) link = &(*link)->rb_right; - else if (data_cmp < 0) - link = &(*link)->rb_left; else link = &(*link)->rb_right; } @@ -542,20 +501,16 @@ static struct cm_id_private * cm_insert_listen(struct cm_id_private *cm_id_priv) } static struct cm_id_private * cm_find_listen(struct ib_device *device, - __be64 service_id, - u32 *private_data) + __be64 service_id) { struct rb_node *node = cm.listen_service_table.rb_node; struct cm_id_private *cm_id_priv; - int data_cmp; while (node) { cm_id_priv = rb_entry(node, struct cm_id_private, service_node); - data_cmp = cm_compare_private_data(private_data, - cm_id_priv->compare_data); if ((cm_id_priv->id.service_mask & service_id) == cm_id_priv->id.service_id && - (cm_id_priv->id.device == device) && !data_cmp) + (cm_id_priv->id.device == device)) return cm_id_priv; if (device < cm_id_priv->id.device) @@ -566,8 +521,6 @@ static struct cm_id_private * cm_find_listen(struct ib_device *device, node = node->rb_left; else if (be64_gt(service_id, cm_id_priv->id.service_id)) node = node->rb_right; - else if (data_cmp < 0) - node = node->rb_left; else node = node->rb_right; } @@ -939,7 +892,6 @@ retest: wait_for_completion(&cm_id_priv->comp); while ((work = cm_dequeue_work(cm_id_priv)) != NULL) cm_free_work(work); - kfree(cm_id_priv->compare_data); kfree(cm_id_priv->private_data); kfree(cm_id_priv); } @@ -962,20 +914,11 @@ EXPORT_SYMBOL(ib_destroy_cm_id); * range of service IDs. If set to 0, the service ID is matched * exactly. This parameter is ignored if %service_id is set to * IB_CM_ASSIGN_SERVICE_ID. - * @compare_data: This parameter is optional. It specifies data that must - * appear in the private data of a connection request for the specified - * listen request. - * @lock: If set, lock the cm.lock spin-lock when adding the id to the - * listener tree. When false, the caller must already hold the spin-lock, - * and compare_data must be NULL. */ static int __ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, - __be64 service_mask, - struct ib_cm_compare_data *compare_data, - bool lock) + __be64 service_mask) { struct cm_id_private *cm_id_priv, *cur_cm_id_priv; - unsigned long flags = 0; int ret = 0; service_mask = service_mask ? service_mask : ~cpu_to_be64(0); @@ -988,22 +931,9 @@ static int __ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, if (cm_id->state != IB_CM_IDLE) return -EINVAL; - if (compare_data) { - cm_id_priv->compare_data = kzalloc(sizeof *compare_data, - GFP_KERNEL); - if (!cm_id_priv->compare_data) - return -ENOMEM; - cm_mask_copy(cm_id_priv->compare_data->data, - compare_data->data, compare_data->mask); - memcpy(cm_id_priv->compare_data->mask, compare_data->mask, - sizeof(compare_data->mask)); - } - cm_id->state = IB_CM_LISTEN; - if (lock) - spin_lock_irqsave(&cm.lock, flags); - ++cm_id_priv->listen_sharecount; + if (service_id == IB_CM_ASSIGN_SERVICE_ID) { cm_id->service_id = cpu_to_be64(cm.listen_service_id++); cm_id->service_mask = ~cpu_to_be64(0); @@ -1016,22 +946,21 @@ static int __ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, if (cur_cm_id_priv) { cm_id->state = IB_CM_IDLE; --cm_id_priv->listen_sharecount; - kfree(cm_id_priv->compare_data); - cm_id_priv->compare_data = NULL; ret = -EBUSY; } - - if (lock) - spin_unlock_irqrestore(&cm.lock, flags); - return ret; } -int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, - struct ib_cm_compare_data *compare_data) +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask) { - return __ib_cm_listen(cm_id, service_id, service_mask, compare_data, - true); + unsigned long flags; + int ret; + + spin_lock_irqsave(&cm.lock, flags); + ret = __ib_cm_listen(cm_id, service_id, service_mask); + spin_unlock_irqrestore(&cm.lock, flags); + + return ret; } EXPORT_SYMBOL(ib_cm_listen); @@ -1071,7 +1000,7 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, goto new_id; /* Find an existing ID */ - cm_id_priv = cm_find_listen(device, service_id, NULL); + cm_id_priv = cm_find_listen(device, service_id); if (cm_id_priv) { if (cm_id->cm_handler != cm_handler || cm_id->context) { /* Sharing an ib_cm_id with different handlers is not @@ -1090,7 +1019,7 @@ struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, new_id: /* Use newly created ID */ - err = __ib_cm_listen(cm_id, service_id, 0, NULL, false); + err = __ib_cm_listen(cm_id, service_id, 0); spin_unlock_irqrestore(&cm.lock, flags); @@ -1615,8 +1544,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, /* Find matching listen request. */ listen_cm_id_priv = cm_find_listen(cm_id_priv->id.device, - req_msg->service_id, - req_msg->private_data); + req_msg->service_id); if (!listen_cm_id_priv) { cm_cleanup_timewait(cm_id_priv->timewait_info); spin_unlock_irq(&cm.lock); @@ -3164,8 +3092,7 @@ static int cm_sidr_req_handler(struct cm_work *work) } cm_id_priv->id.state = IB_CM_SIDR_REQ_RCVD; cur_cm_id_priv = cm_find_listen(cm_id->device, - sidr_req_msg->service_id, - sidr_req_msg->private_data); + sidr_req_msg->service_id); if (!cur_cm_id_priv) { spin_unlock_irq(&cm.lock); cm_reject_sidr_req(cm_id_priv, IB_SIDR_UNSUPPORTED); diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 8cde48b96f194..6b4e8a008bc04 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -658,8 +658,7 @@ static ssize_t ib_ucm_listen(struct ib_ucm_file *file, if (result) goto out; - result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask, - NULL); + result = ib_cm_listen(ctx->cm_id, cmd.service_id, cmd.service_mask); out: ib_ucm_ctx_put(ctx); return result; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index ee39be6ccfb0f..9d321575d90e2 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -848,7 +848,7 @@ int ipoib_cm_dev_open(struct net_device *dev) } ret = ib_cm_listen(priv->cm.id, cpu_to_be64(IPOIB_CM_IETF_ID | priv->qp->qp_num), - 0, NULL); + 0); if (ret) { printk(KERN_WARNING "%s: failed to listen on ID 0x%llx\n", priv->ca->name, IPOIB_CM_IETF_ID | priv->qp->qp_num); diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 4c59ceb40fffc..3ab015b0236dc 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -3250,7 +3250,7 @@ static void srpt_add_one(struct ib_device *device) * in the system as service_id; therefore, the target_id will change * if this HCA is gone bad and replaced by different HCA */ - if (ib_cm_listen(sdev->cm_id, cpu_to_be64(srpt_service_guid), 0, NULL)) + if (ib_cm_listen(sdev->cm_id, cpu_to_be64(srpt_service_guid), 0)) goto err_cm; INIT_IB_EVENT_HANDLER(&sdev->event_handler, sdev->device, diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index e3f48632e2379..92a7d85917b4d 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -105,8 +105,6 @@ enum ib_cm_data_size { IB_CM_SIDR_REQ_PRIVATE_DATA_SIZE = 216, IB_CM_SIDR_REP_PRIVATE_DATA_SIZE = 136, IB_CM_SIDR_REP_INFO_LENGTH = 72, - /* compare done u32 at a time */ - IB_CM_COMPARE_SIZE = (64 / sizeof(u32)) }; struct ib_cm_id; @@ -344,11 +342,6 @@ void ib_destroy_cm_id(struct ib_cm_id *cm_id); #define IB_SDP_SERVICE_ID cpu_to_be64(0x0000000000010000ULL) #define IB_SDP_SERVICE_ID_MASK cpu_to_be64(0xFFFFFFFFFFFF0000ULL) -struct ib_cm_compare_data { - u32 data[IB_CM_COMPARE_SIZE]; - u32 mask[IB_CM_COMPARE_SIZE]; -}; - /** * ib_cm_listen - Initiates listening on the specified service ID for * connection and service ID resolution requests. @@ -361,12 +354,9 @@ struct ib_cm_compare_data { * range of service IDs. If set to 0, the service ID is matched * exactly. This parameter is ignored if %service_id is set to * IB_CM_ASSIGN_SERVICE_ID. - * @compare_data: This parameter is optional. It specifies data that must - * appear in the private data of a connection request for the specified - * listen request. */ -int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, __be64 service_mask, - struct ib_cm_compare_data *compare_data); +int ib_cm_listen(struct ib_cm_id *cm_id, __be64 service_id, + __be64 service_mask); struct ib_cm_id *ib_cm_insert_listen(struct ib_device *device, ib_cm_handler cm_handler, -- GitLab From 1ab36387ea4face01aac3560b396b1e2ce07c4ff Mon Sep 17 00:00:00 2001 From: David Dueck Date: Tue, 28 Jul 2015 09:48:16 +0200 Subject: [PATCH 5758/7006] pinctrl: at91: fix null pointer dereference Not all gpio banks are necessarily enabled, in the current code this can lead to null pointer dereferences. [ 51.130000] Unable to handle kernel NULL pointer dereference at virtual address 00000058 [ 51.130000] pgd = dee04000 [ 51.130000] [00000058] *pgd=3f66d831, *pte=00000000, *ppte=00000000 [ 51.140000] Internal error: Oops: 17 [#1] ARM [ 51.140000] Modules linked in: [ 51.140000] CPU: 0 PID: 1664 Comm: cat Not tainted 4.1.1+ #6 [ 51.140000] Hardware name: Atmel SAMA5 [ 51.140000] task: df6dd880 ti: dec60000 task.ti: dec60000 [ 51.140000] PC is at at91_pinconf_get+0xb4/0x200 [ 51.140000] LR is at at91_pinconf_get+0xb4/0x200 [ 51.140000] pc : [] lr : [] psr: 600f0013 sp : dec61e48 ip : 600f0013 fp : df522538 [ 51.140000] r10: df52250c r9 : 00000058 r8 : 00000068 [ 51.140000] r7 : 00000000 r6 : df53c910 r5 : 00000000 r4 : dec61e7c [ 51.140000] r3 : 00000000 r2 : c06746d4 r1 : 00000000 r0 : 00000003 [ 51.140000] Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user [ 51.140000] Control: 10c53c7d Table: 3ee04059 DAC: 00000015 [ 51.140000] Process cat (pid: 1664, stack limit = 0xdec60208) [ 51.140000] Stack: (0xdec61e48 to 0xdec62000) [ 51.140000] 1e40: 00000358 00000000 df522500 ded15f80 c05a9d08 ded15f80 [ 51.140000] 1e60: 0000048c 00000061 df522500 ded15f80 c05a9d08 c01e7304 ded15f80 00000000 [ 51.140000] 1e80: c01e6008 00000060 0000048c c01e6034 c01e5f6c ded15f80 dec61ec0 00000000 [ 51.140000] 1ea0: 00020000 ded6f280 dec61f80 00000001 00000001 c00ae0b8 b6e80000 ded15fb0 [ 51.140000] 1ec0: 00000000 00000000 df4bc974 00000055 00000800 ded6f280 b6e80000 ded6f280 [ 51.140000] 1ee0: ded6f280 00020000 b6e80000 00000000 00020000 c0090dec c0671e1c dec61fb0 [ 51.140000] 1f00: b6f8b510 00000001 00004201 c000924c 00000000 00000003 00000003 00000000 [ 51.140000] 1f20: df4bc940 00022000 00000022 c066e188 b6e7f000 c00836f4 000b6e7f ded6f280 [ 51.140000] 1f40: ded6f280 b6e80000 dec61f80 ded6f280 00020000 c0091508 00000000 00000003 [ 51.140000] 1f60: 00022000 00000000 00000000 ded6f280 ded6f280 00020000 b6e80000 c0091d9c [ 51.140000] 1f80: 00000000 00000000 ffffffff 00020000 00020000 b6e80000 00000003 c000f124 [ 51.140000] 1fa0: dec60000 c000efa0 00020000 00020000 00000003 b6e80000 00020000 000271c4 [ 51.140000] 1fc0: 00020000 00020000 b6e80000 00000003 7fffe000 00000000 00000000 00020000 [ 51.140000] 1fe0: 00000000 bef50b64 00013835 b6f29c76 400f0030 00000003 00000000 00000000 [ 51.140000] [] (at91_pinconf_get) from [] (at91_pinconf_dbg_show+0x18/0x2c0) [ 51.140000] [] (at91_pinconf_dbg_show) from [] (pinconf_pins_show+0xc8/0xf8) [ 51.140000] [] (pinconf_pins_show) from [] (seq_read+0x1a0/0x464) [ 51.140000] [] (seq_read) from [] (__vfs_read+0x20/0xd0) [ 51.140000] [] (__vfs_read) from [] (vfs_read+0x7c/0x108) [ 51.140000] [] (vfs_read) from [] (SyS_read+0x40/0x94) [ 51.140000] [] (SyS_read) from [] (ret_fast_syscall+0x0/0x3c) [ 51.140000] Code: eb010ec2 e30a0d08 e34c005a eb0ae5a7 (e5993000) [ 51.150000] ---[ end trace fb3c370da3ea4794 ]--- Fixes: a0b957f306fa ("pinctrl: at91: allow to have disabled gpio bank") Cc: stable@vger.kernel.org # 3.18 Signed-off-by: David Dueck Acked-by: Ludovic Desroches Acked-by: Alexandre Belloni Acked-by: Nicolas Ferre Cc: Boris Brezillon Cc: Jean-Christophe PLAGNIOL-VILLARD Cc: linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-at91.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c index 72a3e632c4d9b..bae0012ee3560 100644 --- a/drivers/pinctrl/pinctrl-at91.c +++ b/drivers/pinctrl/pinctrl-at91.c @@ -320,6 +320,9 @@ static const struct pinctrl_ops at91_pctrl_ops = { static void __iomem *pin_to_controller(struct at91_pinctrl *info, unsigned int bank) { + if (!gpio_chips[bank]) + return NULL; + return gpio_chips[bank]->regbase; } @@ -729,6 +732,10 @@ static int at91_pmx_set(struct pinctrl_dev *pctldev, unsigned selector, pin = &pins_conf[i]; at91_pin_dbg(info->dev, pin); pio = pin_to_controller(info, pin->bank); + + if (!pio) + continue; + mask = pin_to_mask(pin->pin); at91_mux_disable_interrupt(pio, mask); switch (pin->mux) { @@ -848,6 +855,10 @@ static int at91_pinconf_get(struct pinctrl_dev *pctldev, *config = 0; dev_dbg(info->dev, "%s:%d, pin_id=%d", __func__, __LINE__, pin_id); pio = pin_to_controller(info, pin_to_bank(pin_id)); + + if (!pio) + return -EINVAL; + pin = pin_id % MAX_NB_GPIO_PER_BANK; if (at91_mux_get_multidrive(pio, pin)) @@ -889,6 +900,10 @@ static int at91_pinconf_set(struct pinctrl_dev *pctldev, "%s:%d, pin_id=%d, config=0x%lx", __func__, __LINE__, pin_id, config); pio = pin_to_controller(info, pin_to_bank(pin_id)); + + if (!pio) + return -EINVAL; + pin = pin_id % MAX_NB_GPIO_PER_BANK; mask = pin_to_mask(pin); -- GitLab From 90816d1ddacfb5a8b783f67e2c1a1bc77dc50ff4 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 30 Aug 2015 09:53:06 -0700 Subject: [PATCH 5759/7006] NFSv4.1/flexfiles: Don't mark the entire deviceid as bad for file errors If the file was fenced and/or has been deleted on the DS, then we want to retry pNFS after a layoutreturn with error report. If the server cannot fix the problem, then we rely on it to tell us so in the response to the LAYOUTGET. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 4ec624cfcf8b3..61ccf1122494d 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -1075,18 +1075,26 @@ static int ff_layout_async_handle_error_v3(struct rpc_task *task, if (task->tk_status >= 0) return 0; - if (task->tk_status != -EJUKEBOX) { + switch (task->tk_status) { + /* File access problems. Don't mark the device as unavailable */ + case -EACCES: + case -ESTALE: + case -EISDIR: + case -EBADHANDLE: + case -ELOOP: + case -ENOSPC: + break; + case -EJUKEBOX: + nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY); + goto out_retry; + default: dprintk("%s DS connection error %d\n", __func__, task->tk_status); nfs4_mark_deviceid_unavailable(devid); - if (ff_layout_has_available_ds(lseg)) - return -NFS4ERR_RESET_TO_PNFS; - else - return -NFS4ERR_RESET_TO_MDS; } - - if (task->tk_status == -EJUKEBOX) - nfs_inc_stats(lseg->pls_layout->plh_inode, NFSIOS_DELAY); + /* FIXME: Need to prevent infinite looping here. */ + return -NFS4ERR_RESET_TO_PNFS; +out_retry: task->tk_status = 0; rpc_restart_call(task); rpc_delay(task, NFS_JUKEBOX_RETRY_TIME); -- GitLab From be688195bd08b1c045f89d72c07c7e3ef6516f38 Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Thu, 27 Aug 2015 15:55:15 +0300 Subject: [PATCH 5760/7006] IB/cma: Fix net_dev reference leak with failed requests When no matching listening ID is found for a given request, the net_dev that was used to find the request isn't released. Fixes: 0b3ca768fcb0 ("IB/cma: Use found net_dev for passive connections") Signed-off-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 9b306d7b5c272..b1ab13f3e182b 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -1302,6 +1302,10 @@ static struct rdma_id_private *cma_id_from_event(struct ib_cm_id *cm_id, bind_list = cma_ps_find(rdma_ps_from_service_id(req.service_id), cma_port_from_service_id(req.service_id)); id_priv = cma_find_listener(bind_list, cm_id, ib_event, &req, *net_dev); + if (IS_ERR(id_priv)) { + dev_put(*net_dev); + *net_dev = NULL; + } return id_priv; } -- GitLab From 8b91ffc1cf67d3f0834197c80c5182890c8d508d Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:34 +0300 Subject: [PATCH 5761/7006] IB/core: Get rid of redundant verb ib_destroy_mr This was added in a thought of uniting all mr allocation and deallocation routines but the fact is we have a single deallocation routine already, ib_dereg_mr. And, move mlx5_ib_destroy_mr specific logic into mlx5_ib_dereg_mr (includes only signature stuff for now). And, fixup the only callers (iser/isert) accordingly. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/core/verbs.c | 17 ---------- drivers/infiniband/hw/mlx5/main.c | 1 - drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 - drivers/infiniband/hw/mlx5/mr.c | 43 +++++++----------------- drivers/infiniband/ulp/iser/iser_verbs.c | 2 +- drivers/infiniband/ulp/isert/ib_isert.c | 2 +- include/rdma/ib_verbs.h | 10 ------ 7 files changed, 15 insertions(+), 61 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index bac3fb406a747..8197ce7a64e55 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1257,23 +1257,6 @@ struct ib_mr *ib_create_mr(struct ib_pd *pd, } EXPORT_SYMBOL(ib_create_mr); -int ib_destroy_mr(struct ib_mr *mr) -{ - struct ib_pd *pd; - int ret; - - if (atomic_read(&mr->usecnt)) - return -EBUSY; - - pd = mr->pd; - ret = mr->device->destroy_mr(mr); - if (!ret) - atomic_dec(&pd->usecnt); - - return ret; -} -EXPORT_SYMBOL(ib_destroy_mr); - struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) { struct ib_mr *mr; diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index bac5f98965d0a..48f02da87edc7 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1499,7 +1499,6 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.get_dma_mr = mlx5_ib_get_dma_mr; dev->ib_dev.reg_user_mr = mlx5_ib_reg_user_mr; dev->ib_dev.dereg_mr = mlx5_ib_dereg_mr; - dev->ib_dev.destroy_mr = mlx5_ib_destroy_mr; dev->ib_dev.attach_mcast = mlx5_ib_mcg_attach; dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach; dev->ib_dev.process_mad = mlx5_ib_process_mad; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 7cae098364812..29c74e9ffc00b 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -573,7 +573,6 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int mlx5_ib_update_mtt(struct mlx5_ib_mr *mr, u64 start_page_index, int npages, int zap); int mlx5_ib_dereg_mr(struct ib_mr *ibmr); -int mlx5_ib_destroy_mr(struct ib_mr *ibmr); struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, struct ib_mr_init_attr *mr_init_attr); struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 10d2b213a4d85..9559ee805696d 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1170,6 +1170,19 @@ static int clean_mr(struct mlx5_ib_mr *mr) int umred = mr->umred; int err; + if (mr->sig) { + if (mlx5_core_destroy_psv(dev->mdev, + mr->sig->psv_memory.psv_idx)) + mlx5_ib_warn(dev, "failed to destroy mem psv %d\n", + mr->sig->psv_memory.psv_idx); + if (mlx5_core_destroy_psv(dev->mdev, + mr->sig->psv_wire.psv_idx)) + mlx5_ib_warn(dev, "failed to destroy wire psv %d\n", + mr->sig->psv_wire.psv_idx); + kfree(mr->sig); + mr->sig = NULL; + } + if (!umred) { err = destroy_mkey(dev, mr); if (err) { @@ -1317,36 +1330,6 @@ err_free: return ERR_PTR(err); } -int mlx5_ib_destroy_mr(struct ib_mr *ibmr) -{ - struct mlx5_ib_dev *dev = to_mdev(ibmr->device); - struct mlx5_ib_mr *mr = to_mmr(ibmr); - int err; - - if (mr->sig) { - if (mlx5_core_destroy_psv(dev->mdev, - mr->sig->psv_memory.psv_idx)) - mlx5_ib_warn(dev, "failed to destroy mem psv %d\n", - mr->sig->psv_memory.psv_idx); - if (mlx5_core_destroy_psv(dev->mdev, - mr->sig->psv_wire.psv_idx)) - mlx5_ib_warn(dev, "failed to destroy wire psv %d\n", - mr->sig->psv_wire.psv_idx); - kfree(mr->sig); - } - - err = destroy_mkey(dev, mr); - if (err) { - mlx5_ib_warn(dev, "failed to destroy mkey 0x%x (%d)\n", - mr->mmr.key, err); - return err; - } - - kfree(mr); - - return err; -} - struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) { diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 5c9f565ea0e88..712218675cf1c 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -334,7 +334,7 @@ iser_free_pi_ctx(struct iser_pi_context *pi_ctx) { ib_free_fast_reg_page_list(pi_ctx->prot_frpl); ib_dereg_mr(pi_ctx->prot_mr); - ib_destroy_mr(pi_ctx->sig_mr); + ib_dereg_mr(pi_ctx->sig_mr); kfree(pi_ctx); } diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index d851e1828d6f5..c054af1715537 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -491,7 +491,7 @@ isert_conn_free_fastreg_pool(struct isert_conn *isert_conn) if (fr_desc->pi_ctx) { ib_free_fast_reg_page_list(fr_desc->pi_ctx->prot_frpl); ib_dereg_mr(fr_desc->pi_ctx->prot_mr); - ib_destroy_mr(fr_desc->pi_ctx->sig_mr); + ib_dereg_mr(fr_desc->pi_ctx->sig_mr); kfree(fr_desc->pi_ctx); } kfree(fr_desc); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index fd7a6950df75e..521c2059ede5a 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1671,7 +1671,6 @@ struct ib_device { int (*query_mr)(struct ib_mr *mr, struct ib_mr_attr *mr_attr); int (*dereg_mr)(struct ib_mr *mr); - int (*destroy_mr)(struct ib_mr *mr); struct ib_mr * (*create_mr)(struct ib_pd *pd, struct ib_mr_init_attr *mr_init_attr); struct ib_mr * (*alloc_fast_reg_mr)(struct ib_pd *pd, @@ -2828,15 +2827,6 @@ int ib_dereg_mr(struct ib_mr *mr); struct ib_mr *ib_create_mr(struct ib_pd *pd, struct ib_mr_init_attr *mr_init_attr); -/** - * ib_destroy_mr - Destroys a memory region that was created using - * ib_create_mr and removes it from HW translation tables. - * @mr: The memory region to destroy. - * - * This function can fail, if the memory region has memory windows bound to it. - */ -int ib_destroy_mr(struct ib_mr *mr); - /** * ib_alloc_fast_reg_mr - Allocates memory region usable with the * IB_WR_FAST_REG_MR send work request. -- GitLab From 9bee178b4f6b3e122ed8eda990450a638706e271 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:35 +0300 Subject: [PATCH 5762/7006] IB: Modify ib_create_mr API Use ib_alloc_mr with specific parameters. Change the existing callers. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/core/verbs.c | 31 +++++++++++++++----- drivers/infiniband/hw/mlx5/main.c | 2 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 5 ++-- drivers/infiniband/hw/mlx5/mr.c | 17 +++++++---- drivers/infiniband/ulp/iser/iser_verbs.c | 6 ++-- drivers/infiniband/ulp/isert/ib_isert.c | 6 +--- include/rdma/ib_verbs.h | 37 ++++++++++-------------- 7 files changed, 58 insertions(+), 46 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 8197ce7a64e55..f96dd456db3b1 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1235,15 +1235,32 @@ int ib_dereg_mr(struct ib_mr *mr) } EXPORT_SYMBOL(ib_dereg_mr); -struct ib_mr *ib_create_mr(struct ib_pd *pd, - struct ib_mr_init_attr *mr_init_attr) +/** + * ib_alloc_mr() - Allocates a memory region + * @pd: protection domain associated with the region + * @mr_type: memory region type + * @max_num_sg: maximum sg entries available for registration. + * + * Notes: + * Memory registeration page/sg lists must not exceed max_num_sg. + * For mr_type IB_MR_TYPE_MEM_REG, the total length cannot exceed + * max_num_sg * used_page_size. + * + */ +struct ib_mr *ib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct ib_mr *mr; - if (!pd->device->create_mr) - return ERR_PTR(-ENOSYS); - - mr = pd->device->create_mr(pd, mr_init_attr); + if (pd->device->alloc_mr) { + mr = pd->device->alloc_mr(pd, mr_type, max_num_sg); + } else { + if (mr_type != IB_MR_TYPE_MEM_REG || + !pd->device->alloc_fast_reg_mr) + return ERR_PTR(-ENOSYS); + mr = pd->device->alloc_fast_reg_mr(pd, max_num_sg); + } if (!IS_ERR(mr)) { mr->device = pd->device; @@ -1255,7 +1272,7 @@ struct ib_mr *ib_create_mr(struct ib_pd *pd, return mr; } -EXPORT_SYMBOL(ib_create_mr); +EXPORT_SYMBOL(ib_alloc_mr); struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) { diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 48f02da87edc7..82a371fabe376 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1502,7 +1502,7 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.attach_mcast = mlx5_ib_mcg_attach; dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach; dev->ib_dev.process_mad = mlx5_ib_process_mad; - dev->ib_dev.create_mr = mlx5_ib_create_mr; + dev->ib_dev.alloc_mr = mlx5_ib_alloc_mr; dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr; dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list; dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 29c74e9ffc00b..31b50a4aa5d83 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -573,8 +573,9 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int mlx5_ib_update_mtt(struct mlx5_ib_mr *mr, u64 start_page_index, int npages, int zap); int mlx5_ib_dereg_mr(struct ib_mr *ibmr); -struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, - struct ib_mr_init_attr *mr_init_attr); +struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg); struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 9559ee805696d..26817a28932dc 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1244,14 +1244,15 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr) return 0; } -struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, - struct ib_mr_init_attr *mr_init_attr) +struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct mlx5_ib_dev *dev = to_mdev(pd->device); struct mlx5_create_mkey_mbox_in *in; struct mlx5_ib_mr *mr; int access_mode, err; - int ndescs = roundup(mr_init_attr->max_reg_descriptors, 4); + int ndescs = roundup(max_num_sg, 4); mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (!mr) @@ -1267,9 +1268,11 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, in->seg.xlt_oct_size = cpu_to_be32(ndescs); in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn); - access_mode = MLX5_ACCESS_MODE_MTT; - if (mr_init_attr->flags & IB_MR_SIGNATURE_EN) { + if (mr_type == IB_MR_TYPE_MEM_REG) { + access_mode = MLX5_ACCESS_MODE_MTT; + in->seg.log2_page_size = PAGE_SHIFT; + } else if (mr_type == IB_MR_TYPE_SIGNATURE) { u32 psv_index[2]; in->seg.flags_pd = cpu_to_be32(be32_to_cpu(in->seg.flags_pd) | @@ -1295,6 +1298,10 @@ struct ib_mr *mlx5_ib_create_mr(struct ib_pd *pd, mr->sig->sig_err_exists = false; /* Next UMR, Arm SIGERR */ ++mr->sig->sigerr_count; + } else { + mlx5_ib_warn(dev, "Invalid mr type %d\n", mr_type); + err = -EINVAL; + goto err_free_in; } in->seg.flags = MLX5_PERM_UMR_EN | access_mode; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 712218675cf1c..32d73c1c57cd6 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -284,9 +284,7 @@ iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, struct fast_reg_descriptor *desc) { struct iser_pi_context *pi_ctx = NULL; - struct ib_mr_init_attr mr_init_attr = {.max_reg_descriptors = 2, - .flags = IB_MR_SIGNATURE_EN}; - int ret = 0; + int ret; desc->pi_ctx = kzalloc(sizeof(*desc->pi_ctx), GFP_KERNEL); if (!desc->pi_ctx) @@ -309,7 +307,7 @@ iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, } desc->reg_indicators |= ISER_PROT_KEY_VALID; - pi_ctx->sig_mr = ib_create_mr(pd, &mr_init_attr); + pi_ctx->sig_mr = ib_alloc_mr(pd, IB_MR_TYPE_SIGNATURE, 2); if (IS_ERR(pi_ctx->sig_mr)) { ret = PTR_ERR(pi_ctx->sig_mr); goto sig_mr_failure; diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index c054af1715537..fd0aa93c0bebb 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -508,7 +508,6 @@ isert_create_pi_ctx(struct fast_reg_descriptor *desc, struct ib_device *device, struct ib_pd *pd) { - struct ib_mr_init_attr mr_init_attr; struct pi_context *pi_ctx; int ret; @@ -536,10 +535,7 @@ isert_create_pi_ctx(struct fast_reg_descriptor *desc, } desc->ind |= ISERT_PROT_KEY_VALID; - memset(&mr_init_attr, 0, sizeof(mr_init_attr)); - mr_init_attr.max_reg_descriptors = 2; - mr_init_attr.flags |= IB_MR_SIGNATURE_EN; - pi_ctx->sig_mr = ib_create_mr(pd, &mr_init_attr); + pi_ctx->sig_mr = ib_alloc_mr(pd, IB_MR_TYPE_SIGNATURE, 2); if (IS_ERR(pi_ctx->sig_mr)) { isert_err("Failed to allocate signature enabled mr err=%ld\n", PTR_ERR(pi_ctx->sig_mr)); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 521c2059ede5a..aba51431c9861 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -557,20 +557,18 @@ __attribute_const__ int ib_rate_to_mult(enum ib_rate rate); */ __attribute_const__ int ib_rate_to_mbps(enum ib_rate rate); -enum ib_mr_create_flags { - IB_MR_SIGNATURE_EN = 1, -}; /** - * ib_mr_init_attr - Memory region init attributes passed to routine - * ib_create_mr. - * @max_reg_descriptors: max number of registration descriptors that - * may be used with registration work requests. - * @flags: MR creation flags bit mask. + * enum ib_mr_type - memory region type + * @IB_MR_TYPE_MEM_REG: memory region that is used for + * normal registration + * @IB_MR_TYPE_SIGNATURE: memory region that is used for + * signature operations (data-integrity + * capable regions) */ -struct ib_mr_init_attr { - int max_reg_descriptors; - u32 flags; +enum ib_mr_type { + IB_MR_TYPE_MEM_REG, + IB_MR_TYPE_SIGNATURE, }; /** @@ -1671,8 +1669,9 @@ struct ib_device { int (*query_mr)(struct ib_mr *mr, struct ib_mr_attr *mr_attr); int (*dereg_mr)(struct ib_mr *mr); - struct ib_mr * (*create_mr)(struct ib_pd *pd, - struct ib_mr_init_attr *mr_init_attr); + struct ib_mr * (*alloc_mr)(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg); struct ib_mr * (*alloc_fast_reg_mr)(struct ib_pd *pd, int max_page_list_len); struct ib_fast_reg_page_list * (*alloc_fast_reg_page_list)(struct ib_device *device, @@ -2817,15 +2816,9 @@ int ib_query_mr(struct ib_mr *mr, struct ib_mr_attr *mr_attr); */ int ib_dereg_mr(struct ib_mr *mr); - -/** - * ib_create_mr - Allocates a memory region that may be used for - * signature handover operations. - * @pd: The protection domain associated with the region. - * @mr_init_attr: memory region init attributes. - */ -struct ib_mr *ib_create_mr(struct ib_pd *pd, - struct ib_mr_init_attr *mr_init_attr); +struct ib_mr *ib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg); /** * ib_alloc_fast_reg_mr - Allocates memory region usable with the -- GitLab From 34780f012ceeb41ec6d44b3877396042e750862c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:36 +0300 Subject: [PATCH 5763/7006] IB/iser: Convert to ib_alloc_mr Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_verbs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 32d73c1c57cd6..8f24728f10525 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -299,8 +299,8 @@ iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, goto prot_frpl_failure; } - pi_ctx->prot_mr = ib_alloc_fast_reg_mr(pd, - ISCSI_ISER_SG_TABLESIZE + 1); + pi_ctx->prot_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE + 1); if (IS_ERR(pi_ctx->prot_mr)) { ret = PTR_ERR(pi_ctx->prot_mr); goto prot_mr_failure; @@ -351,7 +351,8 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, return PTR_ERR(desc->data_frpl); } - desc->data_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE + 1); + desc->data_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE + 1); if (IS_ERR(desc->data_mr)) { ret = PTR_ERR(desc->data_mr); iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); -- GitLab From a89be2cc51f6602e803f2f9a9c8c4f59a0bd58b3 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:37 +0300 Subject: [PATCH 5764/7006] iser-target: Convert to ib_alloc_mr Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/isert/ib_isert.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index fd0aa93c0bebb..0ebbaa56de829 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -526,7 +526,8 @@ isert_create_pi_ctx(struct fast_reg_descriptor *desc, goto err_pi_ctx; } - pi_ctx->prot_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE); + pi_ctx->prot_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE); if (IS_ERR(pi_ctx->prot_mr)) { isert_err("Failed to allocate prot frmr err=%ld\n", PTR_ERR(pi_ctx->prot_mr)); @@ -573,7 +574,8 @@ isert_create_fr_desc(struct ib_device *ib_device, struct ib_pd *pd, return PTR_ERR(fr_desc->data_frpl); } - fr_desc->data_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE); + fr_desc->data_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE); if (IS_ERR(fr_desc->data_mr)) { isert_err("Failed to allocate data frmr err=%ld\n", PTR_ERR(fr_desc->data_mr)); -- GitLab From 563b67c5f90abeae1038008e6c9c187fb36ad35c Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:38 +0300 Subject: [PATCH 5765/7006] IB/srp: Convert to ib_alloc_mr Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 7755df444cfda..43265608361e0 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -378,7 +378,8 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, INIT_LIST_HEAD(&pool->free_list); for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) { - mr = ib_alloc_fast_reg_mr(pd, max_page_list_len); + mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + max_page_list_len); if (IS_ERR(mr)) { ret = PTR_ERR(mr); goto destroy_pool; -- GitLab From 0410e38eca85e042f5d5a281dbcc792db701ed44 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:39 +0300 Subject: [PATCH 5766/7006] xprtrdma, svcrdma: Convert to ib_alloc_mr Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- net/sunrpc/xprtrdma/frwr_ops.c | 6 +++--- net/sunrpc/xprtrdma/svc_rdma_transport.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/net/sunrpc/xprtrdma/frwr_ops.c b/net/sunrpc/xprtrdma/frwr_ops.c index 04ea914201b23..5318951b3b531 100644 --- a/net/sunrpc/xprtrdma/frwr_ops.c +++ b/net/sunrpc/xprtrdma/frwr_ops.c @@ -117,7 +117,7 @@ __frwr_recovery_worker(struct work_struct *work) if (ib_dereg_mr(r->r.frmr.fr_mr)) goto out_fail; - r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(pd, depth); + r->r.frmr.fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth); if (IS_ERR(r->r.frmr.fr_mr)) goto out_fail; @@ -148,7 +148,7 @@ __frwr_init(struct rpcrdma_mw *r, struct ib_pd *pd, struct ib_device *device, struct rpcrdma_frmr *f = &r->r.frmr; int rc; - f->fr_mr = ib_alloc_fast_reg_mr(pd, depth); + f->fr_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, depth); if (IS_ERR(f->fr_mr)) goto out_mr_err; f->fr_pgl = ib_alloc_fast_reg_page_list(device, depth); @@ -158,7 +158,7 @@ __frwr_init(struct rpcrdma_mw *r, struct ib_pd *pd, struct ib_device *device, out_mr_err: rc = PTR_ERR(f->fr_mr); - dprintk("RPC: %s: ib_alloc_fast_reg_mr status %i\n", + dprintk("RPC: %s: ib_alloc_mr status %i\n", __func__, rc); return rc; diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index fdc850ffc26c4..8752a2d653b5e 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -738,7 +738,7 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt) if (!frmr) goto err; - mr = ib_alloc_fast_reg_mr(xprt->sc_pd, RPCSVC_MAXPAGES); + mr = ib_alloc_mr(xprt->sc_pd, IB_MR_TYPE_MEM_REG, RPCSVC_MAXPAGES); if (IS_ERR(mr)) goto err_free_frmr; -- GitLab From 9ac07501e1918b8d1140adcc360e8d8c7f5a2f7c Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Fri, 7 Aug 2015 11:11:20 -0500 Subject: [PATCH 5767/7006] svcrdma: limit FRMR page list lengths to device max Svcrdma was incorrectly allocating fastreg MRs and page lists using RPCSVC_MAXPAGES, which can exceed the device capabilities. So limit the depth to the minimum of RPCSVC_MAXPAGES and xprt->sc_frmr_pg_list_len. Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- net/sunrpc/xprtrdma/svc_rdma_transport.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 8752a2d653b5e..11d5133c3f38c 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -733,17 +733,19 @@ static struct svc_rdma_fastreg_mr *rdma_alloc_frmr(struct svcxprt_rdma *xprt) struct ib_mr *mr; struct ib_fast_reg_page_list *pl; struct svc_rdma_fastreg_mr *frmr; + u32 num_sg; frmr = kmalloc(sizeof(*frmr), GFP_KERNEL); if (!frmr) goto err; - mr = ib_alloc_mr(xprt->sc_pd, IB_MR_TYPE_MEM_REG, RPCSVC_MAXPAGES); + num_sg = min_t(u32, RPCSVC_MAXPAGES, xprt->sc_frmr_pg_list_len); + mr = ib_alloc_mr(xprt->sc_pd, IB_MR_TYPE_MEM_REG, num_sg); if (IS_ERR(mr)) goto err_free_frmr; pl = ib_alloc_fast_reg_page_list(xprt->sc_cm_id->device, - RPCSVC_MAXPAGES); + num_sg); if (IS_ERR(pl)) goto err_free_mr; -- GitLab From fc27995942960c894bc4725435dce8750e44cd64 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:40 +0300 Subject: [PATCH 5768/7006] RDS: Convert to ib_alloc_mr Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- net/rds/iw_rdma.c | 5 +++-- net/rds/iw_send.c | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c index dba8d0864f180..6a8fbd6e69e7c 100644 --- a/net/rds/iw_rdma.c +++ b/net/rds/iw_rdma.c @@ -667,11 +667,12 @@ static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool, struct ib_mr *mr; int err; - mr = ib_alloc_fast_reg_mr(rds_iwdev->pd, pool->max_message_size); + mr = ib_alloc_mr(rds_iwdev->pd, IB_MR_TYPE_MEM_REG, + pool->max_message_size); if (IS_ERR(mr)) { err = PTR_ERR(mr); - printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_mr failed (err=%d)\n", err); + printk(KERN_WARNING "RDS/IW: ib_alloc_mr failed (err=%d)\n", err); return err; } diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c index 334fe98c50841..86152ec3b8879 100644 --- a/net/rds/iw_send.c +++ b/net/rds/iw_send.c @@ -153,9 +153,10 @@ void rds_iw_send_init_ring(struct rds_iw_connection *ic) sge->length = sizeof(struct rds_header); sge->lkey = 0; - send->s_mr = ib_alloc_fast_reg_mr(ic->i_pd, fastreg_message_size); + send->s_mr = ib_alloc_mr(ic->i_pd, IB_MR_TYPE_MEM_REG, + fastreg_message_size); if (IS_ERR(send->s_mr)) { - printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_mr failed\n"); + printk(KERN_WARNING "RDS/IW: ib_alloc_mr failed\n"); break; } -- GitLab From b3778ba8ded0aafbd820b68be0686ff0c6026eff Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:41 +0300 Subject: [PATCH 5769/7006] mlx5: Drop mlx5_ib_alloc_fast_reg_mr Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 1 - drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 -- drivers/infiniband/hw/mlx5/mr.c | 44 ---------------------------- 3 files changed, 47 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 82a371fabe376..ce7587538badd 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1503,7 +1503,6 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.detach_mcast = mlx5_ib_mcg_detach; dev->ib_dev.process_mad = mlx5_ib_process_mad; dev->ib_dev.alloc_mr = mlx5_ib_alloc_mr; - dev->ib_dev.alloc_fast_reg_mr = mlx5_ib_alloc_fast_reg_mr; dev->ib_dev.alloc_fast_reg_page_list = mlx5_ib_alloc_fast_reg_page_list; dev->ib_dev.free_fast_reg_page_list = mlx5_ib_free_fast_reg_page_list; dev->ib_dev.check_mr_status = mlx5_ib_check_mr_status; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 31b50a4aa5d83..62b06ae2c87db 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -576,8 +576,6 @@ int mlx5_ib_dereg_mr(struct ib_mr *ibmr); struct ib_mr *mlx5_ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, u32 max_num_sg); -struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, - int max_page_list_len); struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len); void mlx5_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list); diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 26817a28932dc..dad82db892210 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1337,50 +1337,6 @@ err_free: return ERR_PTR(err); } -struct ib_mr *mlx5_ib_alloc_fast_reg_mr(struct ib_pd *pd, - int max_page_list_len) -{ - struct mlx5_ib_dev *dev = to_mdev(pd->device); - struct mlx5_create_mkey_mbox_in *in; - struct mlx5_ib_mr *mr; - int err; - - mr = kzalloc(sizeof(*mr), GFP_KERNEL); - if (!mr) - return ERR_PTR(-ENOMEM); - - in = kzalloc(sizeof(*in), GFP_KERNEL); - if (!in) { - err = -ENOMEM; - goto err_free; - } - - in->seg.status = MLX5_MKEY_STATUS_FREE; - in->seg.xlt_oct_size = cpu_to_be32((max_page_list_len + 1) / 2); - in->seg.qpn_mkey7_0 = cpu_to_be32(0xffffff << 8); - in->seg.flags = MLX5_PERM_UMR_EN | MLX5_ACCESS_MODE_MTT; - in->seg.flags_pd = cpu_to_be32(to_mpd(pd)->pdn); - /* - * TBD not needed - issue 197292 */ - in->seg.log2_page_size = PAGE_SHIFT; - - err = mlx5_core_create_mkey(dev->mdev, &mr->mmr, in, sizeof(*in), NULL, - NULL, NULL); - kfree(in); - if (err) - goto err_free; - - mr->ibmr.lkey = mr->mmr.key; - mr->ibmr.rkey = mr->mmr.key; - mr->umem = NULL; - - return &mr->ibmr; - -err_free: - kfree(mr); - return ERR_PTR(err); -} - struct ib_fast_reg_page_list *mlx5_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len) { -- GitLab From 679e34d1d050fc67f2ab157ebf8553dddc216c55 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:42 +0300 Subject: [PATCH 5770/7006] mlx4: Support ib_alloc_mr verb Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 2 +- drivers/infiniband/hw/mlx4/mlx4_ib.h | 5 +++-- drivers/infiniband/hw/mlx4/mr.c | 11 ++++++++--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 05166b7d8ca70..9ab73a496d527 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2294,7 +2294,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.reg_user_mr = mlx4_ib_reg_user_mr; ibdev->ib_dev.rereg_user_mr = mlx4_ib_rereg_user_mr; ibdev->ib_dev.dereg_mr = mlx4_ib_dereg_mr; - ibdev->ib_dev.alloc_fast_reg_mr = mlx4_ib_alloc_fast_reg_mr; + ibdev->ib_dev.alloc_mr = mlx4_ib_alloc_mr; ibdev->ib_dev.alloc_fast_reg_page_list = mlx4_ib_alloc_fast_reg_page_list; ibdev->ib_dev.free_fast_reg_page_list = mlx4_ib_free_fast_reg_page_list; ibdev->ib_dev.attach_mcast = mlx4_ib_mcg_attach; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 334387f63358a..3b85f0475a254 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -680,8 +680,9 @@ struct ib_mw *mlx4_ib_alloc_mw(struct ib_pd *pd, enum ib_mw_type type); int mlx4_ib_bind_mw(struct ib_qp *qp, struct ib_mw *mw, struct ib_mw_bind *mw_bind); int mlx4_ib_dealloc_mw(struct ib_mw *mw); -struct ib_mr *mlx4_ib_alloc_fast_reg_mr(struct ib_pd *pd, - int max_page_list_len); +struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg); struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len); void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list); diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c index e0d271782d0a0..2542fd3c1a493 100644 --- a/drivers/infiniband/hw/mlx4/mr.c +++ b/drivers/infiniband/hw/mlx4/mr.c @@ -350,19 +350,24 @@ int mlx4_ib_dealloc_mw(struct ib_mw *ibmw) return 0; } -struct ib_mr *mlx4_ib_alloc_fast_reg_mr(struct ib_pd *pd, - int max_page_list_len) +struct ib_mr *mlx4_ib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct mlx4_ib_dev *dev = to_mdev(pd->device); struct mlx4_ib_mr *mr; int err; + if (mr_type != IB_MR_TYPE_MEM_REG || + max_num_sg > MLX4_MAX_FAST_REG_PAGES) + return ERR_PTR(-EINVAL); + mr = kmalloc(sizeof *mr, GFP_KERNEL); if (!mr) return ERR_PTR(-ENOMEM); err = mlx4_mr_alloc(dev->dev, to_mpd(pd)->pdn, 0, 0, 0, - max_page_list_len, 0, &mr->mmr); + max_num_sg, 0, &mr->mmr); if (err) goto err_free; -- GitLab From cacb7d59bed3fd9f65d6ba1a4ea948ce8baa9126 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:43 +0300 Subject: [PATCH 5771/7006] ocrdma: Support ib_alloc_mr verb Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/ocrdma/ocrdma_main.c | 2 +- drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 11 ++++++++--- drivers/infiniband/hw/ocrdma/ocrdma_verbs.h | 4 +++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index b119a3413a155..81ed8a342f4d6 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -309,7 +309,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) dev->ibdev.dereg_mr = ocrdma_dereg_mr; dev->ibdev.reg_user_mr = ocrdma_reg_user_mr; - dev->ibdev.alloc_fast_reg_mr = ocrdma_alloc_frmr; + dev->ibdev.alloc_mr = ocrdma_alloc_mr; dev->ibdev.alloc_fast_reg_page_list = ocrdma_alloc_frmr_page_list; dev->ibdev.free_fast_reg_page_list = ocrdma_free_frmr_page_list; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index bc84cd462ecf3..8e5fb44090f70 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -2998,21 +2998,26 @@ int ocrdma_arm_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags cq_flags) return 0; } -struct ib_mr *ocrdma_alloc_frmr(struct ib_pd *ibpd, int max_page_list_len) +struct ib_mr *ocrdma_alloc_mr(struct ib_pd *ibpd, + enum ib_mr_type mr_type, + u32 max_num_sg) { int status; struct ocrdma_mr *mr; struct ocrdma_pd *pd = get_ocrdma_pd(ibpd); struct ocrdma_dev *dev = get_ocrdma_dev(ibpd->device); - if (max_page_list_len > dev->attr.max_pages_per_frmr) + if (mr_type != IB_MR_TYPE_MEM_REG) + return ERR_PTR(-EINVAL); + + if (max_num_sg > dev->attr.max_pages_per_frmr) return ERR_PTR(-EINVAL); mr = kzalloc(sizeof(*mr), GFP_KERNEL); if (!mr) return ERR_PTR(-ENOMEM); - status = ocrdma_get_pbl_info(dev, mr, max_page_list_len); + status = ocrdma_get_pbl_info(dev, mr, max_num_sg); if (status) goto pbl_err; mr->hwmr.fr_mr = 1; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h index eaccb2d3cb9ff..68e026bb14d00 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h @@ -111,7 +111,9 @@ struct ib_mr *ocrdma_reg_kernel_mr(struct ib_pd *, int num_phys_buf, int acc, u64 *iova_start); struct ib_mr *ocrdma_reg_user_mr(struct ib_pd *, u64 start, u64 length, u64 virt, int acc, struct ib_udata *); -struct ib_mr *ocrdma_alloc_frmr(struct ib_pd *pd, int max_page_list_len); +struct ib_mr *ocrdma_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg); struct ib_fast_reg_page_list *ocrdma_alloc_frmr_page_list(struct ib_device *ibdev, int page_list_len); -- GitLab From a21640347a01ba2f96dfc887b8e33cce462780fd Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:44 +0300 Subject: [PATCH 5772/7006] iw_cxgb4: Support ib_alloc_mr verb Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/iw_cxgb4.h | 4 +++- drivers/infiniband/hw/cxgb4/mem.c | 12 +++++++++--- drivers/infiniband/hw/cxgb4/provider.c | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h index cc77844fada38..c7bb38c931a55 100644 --- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h +++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h @@ -970,7 +970,9 @@ void c4iw_free_fastreg_pbl(struct ib_fast_reg_page_list *page_list); struct ib_fast_reg_page_list *c4iw_alloc_fastreg_pbl( struct ib_device *device, int page_list_len); -struct ib_mr *c4iw_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth); +struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg); int c4iw_dealloc_mw(struct ib_mw *mw); struct ib_mw *c4iw_alloc_mw(struct ib_pd *pd, enum ib_mw_type type); struct ib_mr *c4iw_reg_user_mr(struct ib_pd *pd, u64 start, diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c index cff815b917071..026b91ebd5e2e 100644 --- a/drivers/infiniband/hw/cxgb4/mem.c +++ b/drivers/infiniband/hw/cxgb4/mem.c @@ -853,7 +853,9 @@ int c4iw_dealloc_mw(struct ib_mw *mw) return 0; } -struct ib_mr *c4iw_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) +struct ib_mr *c4iw_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct c4iw_dev *rhp; struct c4iw_pd *php; @@ -862,6 +864,10 @@ struct ib_mr *c4iw_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) u32 stag = 0; int ret = 0; + if (mr_type != IB_MR_TYPE_MEM_REG || + max_num_sg > t4_max_fr_depth(use_dsgl)) + return ERR_PTR(-EINVAL); + php = to_c4iw_pd(pd); rhp = php->rhp; mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); @@ -871,10 +877,10 @@ struct ib_mr *c4iw_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) } mhp->rhp = rhp; - ret = alloc_pbl(mhp, pbl_depth); + ret = alloc_pbl(mhp, max_num_sg); if (ret) goto err1; - mhp->attr.pbl_size = pbl_depth; + mhp->attr.pbl_size = max_num_sg; ret = allocate_stag(&rhp->rdev, &stag, php->pdid, mhp->attr.pbl_size, mhp->attr.pbl_addr); if (ret) diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 6eee3d3855415..7746113552e7b 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -556,7 +556,7 @@ int c4iw_register_device(struct c4iw_dev *dev) dev->ibdev.alloc_mw = c4iw_alloc_mw; dev->ibdev.bind_mw = c4iw_bind_mw; dev->ibdev.dealloc_mw = c4iw_dealloc_mw; - dev->ibdev.alloc_fast_reg_mr = c4iw_alloc_fast_reg_mr; + dev->ibdev.alloc_mr = c4iw_alloc_mr; dev->ibdev.alloc_fast_reg_page_list = c4iw_alloc_fastreg_pbl; dev->ibdev.free_fast_reg_page_list = c4iw_free_fastreg_pbl; dev->ibdev.attach_mcast = c4iw_multicast_attach; -- GitLab From f683d3bdbb37baa49510e32789164e5d33d76ba1 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:45 +0300 Subject: [PATCH 5773/7006] cxgb3: Support ib_alloc_mr verb Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb3/iwch_provider.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index bbbe0184e5922..93308c45f298d 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -800,7 +800,9 @@ static int iwch_dealloc_mw(struct ib_mw *mw) return 0; } -static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) +static struct ib_mr *iwch_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct iwch_dev *rhp; struct iwch_pd *php; @@ -809,6 +811,10 @@ static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) u32 stag = 0; int ret = 0; + if (mr_type != IB_MR_TYPE_MEM_REG || + max_num_sg > T3_MAX_FASTREG_DEPTH) + return ERR_PTR(-EINVAL); + php = to_iwch_pd(pd); rhp = php->rhp; mhp = kzalloc(sizeof(*mhp), GFP_KERNEL); @@ -816,10 +822,10 @@ static struct ib_mr *iwch_alloc_fast_reg_mr(struct ib_pd *pd, int pbl_depth) goto err; mhp->rhp = rhp; - ret = iwch_alloc_pbl(mhp, pbl_depth); + ret = iwch_alloc_pbl(mhp, max_num_sg); if (ret) goto err1; - mhp->attr.pbl_size = pbl_depth; + mhp->attr.pbl_size = max_num_sg; ret = cxio_allocate_stag(&rhp->rdev, &stag, php->pdid, mhp->attr.pbl_size, mhp->attr.pbl_addr); if (ret) @@ -1443,7 +1449,7 @@ int iwch_register_device(struct iwch_dev *dev) dev->ibdev.alloc_mw = iwch_alloc_mw; dev->ibdev.bind_mw = iwch_bind_mw; dev->ibdev.dealloc_mw = iwch_dealloc_mw; - dev->ibdev.alloc_fast_reg_mr = iwch_alloc_fast_reg_mr; + dev->ibdev.alloc_mr = iwch_alloc_mr; dev->ibdev.alloc_fast_reg_page_list = iwch_alloc_fastreg_pbl; dev->ibdev.free_fast_reg_page_list = iwch_free_fastreg_pbl; dev->ibdev.attach_mcast = iwch_multicast_attach; -- GitLab From e02e4d554d2b0c20b1f191c5d98bbf5da500a285 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:46 +0300 Subject: [PATCH 5774/7006] nes: Support ib_alloc_mr verb Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/nes/nes_verbs.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index fbc43e5f717b0..44cb513f9a87c 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -375,9 +375,11 @@ static int alloc_fast_reg_mr(struct nes_device *nesdev, struct nes_pd *nespd, } /* - * nes_alloc_fast_reg_mr + * nes_alloc_mr */ -static struct ib_mr *nes_alloc_fast_reg_mr(struct ib_pd *ibpd, int max_page_list_len) +static struct ib_mr *nes_alloc_mr(struct ib_pd *ibpd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct nes_pd *nespd = to_nespd(ibpd); struct nes_vnic *nesvnic = to_nesvnic(ibpd->device); @@ -393,11 +395,18 @@ static struct ib_mr *nes_alloc_fast_reg_mr(struct ib_pd *ibpd, int max_page_list u32 stag; int ret; struct ib_mr *ibmr; + + if (mr_type != IB_MR_TYPE_MEM_REG) + return ERR_PTR(-EINVAL); + + if (max_num_sg > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) + return ERR_PTR(-E2BIG); + /* * Note: Set to always use a fixed length single page entry PBL. This is to allow * for the fast_reg_mr operation to always know the size of the PBL. */ - if (max_page_list_len > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) + if (max_num_sg > (NES_4K_PBL_CHUNK_SIZE / sizeof(u64))) return ERR_PTR(-E2BIG); get_random_bytes(&next_stag_index, sizeof(next_stag_index)); @@ -424,7 +433,7 @@ static struct ib_mr *nes_alloc_fast_reg_mr(struct ib_pd *ibpd, int max_page_list nes_debug(NES_DBG_MR, "Allocating STag 0x%08X index = 0x%08X\n", stag, stag_index); - ret = alloc_fast_reg_mr(nesdev, nespd, stag, max_page_list_len); + ret = alloc_fast_reg_mr(nesdev, nespd, stag, max_num_sg); if (ret == 0) { nesmr->ibmr.rkey = stag; @@ -3929,7 +3938,7 @@ struct nes_ib_device *nes_init_ofa_device(struct net_device *netdev) nesibdev->ibdev.dealloc_mw = nes_dealloc_mw; nesibdev->ibdev.bind_mw = nes_bind_mw; - nesibdev->ibdev.alloc_fast_reg_mr = nes_alloc_fast_reg_mr; + nesibdev->ibdev.alloc_mr = nes_alloc_mr; nesibdev->ibdev.alloc_fast_reg_page_list = nes_alloc_fast_reg_page_list; nesibdev->ibdev.free_fast_reg_page_list = nes_free_fast_reg_page_list; -- GitLab From 1302f8452bfbede92c5e984afd64d91eb5459ee7 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:47 +0300 Subject: [PATCH 5775/7006] qib: Support ib_alloc_mr verb Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_mr.c | 9 +++++++-- drivers/infiniband/hw/qib/qib_verbs.c | 2 +- drivers/infiniband/hw/qib/qib_verbs.h | 4 +++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c index c4473db46699b..19220dcb9a3b2 100644 --- a/drivers/infiniband/hw/qib/qib_mr.c +++ b/drivers/infiniband/hw/qib/qib_mr.c @@ -327,11 +327,16 @@ out: * * Return the memory region on success, otherwise return an errno. */ -struct ib_mr *qib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) +struct ib_mr *qib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct qib_mr *mr; - mr = alloc_mr(max_page_list_len, pd); + if (mr_type != IB_MR_TYPE_MEM_REG) + return ERR_PTR(-EINVAL); + + mr = alloc_mr(max_num_sg, pd); if (IS_ERR(mr)) return (struct ib_mr *)mr; diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index bc0599ca140a1..3dcc4985b60ff 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -2243,7 +2243,7 @@ int qib_register_ib_device(struct qib_devdata *dd) ibdev->reg_phys_mr = qib_reg_phys_mr; ibdev->reg_user_mr = qib_reg_user_mr; ibdev->dereg_mr = qib_dereg_mr; - ibdev->alloc_fast_reg_mr = qib_alloc_fast_reg_mr; + ibdev->alloc_mr = qib_alloc_mr; ibdev->alloc_fast_reg_page_list = qib_alloc_fast_reg_page_list; ibdev->free_fast_reg_page_list = qib_free_fast_reg_page_list; ibdev->alloc_fmr = qib_alloc_fmr; diff --git a/drivers/infiniband/hw/qib/qib_verbs.h b/drivers/infiniband/hw/qib/qib_verbs.h index bce0fa596b4df..a08df70e85038 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.h +++ b/drivers/infiniband/hw/qib/qib_verbs.h @@ -1034,7 +1034,9 @@ struct ib_mr *qib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int qib_dereg_mr(struct ib_mr *ibmr); -struct ib_mr *qib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); +struct ib_mr *qib_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_entries); struct ib_fast_reg_page_list *qib_alloc_fast_reg_page_list( struct ib_device *ibdev, int page_list_len); -- GitLab From d9fe6dd7afaff529124dd7f49c2da89ef789a56f Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Fri, 7 Aug 2015 10:51:25 -0400 Subject: [PATCH 5776/7006] IB/hfi1: Support ib_alloc_mr verb Ported from upstream qib commit 68c02e232b8a ("qib: Support ib_alloc_mr verb") Tested-by: Jubin John Reviewed-by: Jubin John Signed-off-by: Mike Marciniszyn Signed-off-by: Doug Ledford --- drivers/staging/rdma/hfi1/mr.c | 9 +++++++-- drivers/staging/rdma/hfi1/verbs.c | 1 + drivers/staging/rdma/hfi1/verbs.h | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/staging/rdma/hfi1/mr.c b/drivers/staging/rdma/hfi1/mr.c index 23567f83c8725..bd64e4f986f9c 100644 --- a/drivers/staging/rdma/hfi1/mr.c +++ b/drivers/staging/rdma/hfi1/mr.c @@ -348,11 +348,16 @@ out: * * Return the memory region on success, otherwise return an errno. */ -struct ib_mr *hfi1_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) +struct ib_mr *hfi1_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_num_sg) { struct hfi1_mr *mr; - mr = alloc_mr(max_page_list_len, pd); + if (mr_type != IB_MR_TYPE_MEM_REG) + return ERR_PTR(-EINVAL); + + mr = alloc_mr(max_num_sg, pd); if (IS_ERR(mr)) return (struct ib_mr *)mr; diff --git a/drivers/staging/rdma/hfi1/verbs.c b/drivers/staging/rdma/hfi1/verbs.c index 5f4b6617677a0..53ac214315427 100644 --- a/drivers/staging/rdma/hfi1/verbs.c +++ b/drivers/staging/rdma/hfi1/verbs.c @@ -2045,6 +2045,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) ibdev->reg_phys_mr = hfi1_reg_phys_mr; ibdev->reg_user_mr = hfi1_reg_user_mr; ibdev->dereg_mr = hfi1_dereg_mr; + ibdev->alloc_mr = hfi1_alloc_mr; ibdev->alloc_fast_reg_page_list = hfi1_alloc_fast_reg_page_list; ibdev->free_fast_reg_page_list = hfi1_free_fast_reg_page_list; ibdev->alloc_fmr = hfi1_alloc_fmr; diff --git a/drivers/staging/rdma/hfi1/verbs.h b/drivers/staging/rdma/hfi1/verbs.h index 812536194190e..ed903a93baf70 100644 --- a/drivers/staging/rdma/hfi1/verbs.h +++ b/drivers/staging/rdma/hfi1/verbs.h @@ -1016,7 +1016,9 @@ struct ib_mr *hfi1_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, int hfi1_dereg_mr(struct ib_mr *ibmr); -struct ib_mr *hfi1_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); +struct ib_mr *hfi1_alloc_mr(struct ib_pd *pd, + enum ib_mr_type mr_type, + u32 max_entries); struct ib_fast_reg_page_list *hfi1_alloc_fast_reg_page_list( struct ib_device *ibdev, int page_list_len); -- GitLab From d9f272c523db47a56a64942eb6f25361c400de66 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 30 Jul 2015 10:32:48 +0300 Subject: [PATCH 5777/7006] IB/core: Drop ib_alloc_fast_reg_mr Fully replaced by a more generic and suitable ib_alloc_mr. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/core/verbs.c | 32 +++----------------------------- include/rdma/ib_verbs.h | 11 ----------- 2 files changed, 3 insertions(+), 40 deletions(-) diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index f96dd456db3b1..c80ed17376664 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1253,36 +1253,10 @@ struct ib_mr *ib_alloc_mr(struct ib_pd *pd, { struct ib_mr *mr; - if (pd->device->alloc_mr) { - mr = pd->device->alloc_mr(pd, mr_type, max_num_sg); - } else { - if (mr_type != IB_MR_TYPE_MEM_REG || - !pd->device->alloc_fast_reg_mr) - return ERR_PTR(-ENOSYS); - mr = pd->device->alloc_fast_reg_mr(pd, max_num_sg); - } - - if (!IS_ERR(mr)) { - mr->device = pd->device; - mr->pd = pd; - mr->uobject = NULL; - atomic_inc(&pd->usecnt); - atomic_set(&mr->usecnt, 0); - } - - return mr; -} -EXPORT_SYMBOL(ib_alloc_mr); - -struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) -{ - struct ib_mr *mr; - - if (!pd->device->alloc_fast_reg_mr) + if (!pd->device->alloc_mr) return ERR_PTR(-ENOSYS); - mr = pd->device->alloc_fast_reg_mr(pd, max_page_list_len); - + mr = pd->device->alloc_mr(pd, mr_type, max_num_sg); if (!IS_ERR(mr)) { mr->device = pd->device; mr->pd = pd; @@ -1293,7 +1267,7 @@ struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len) return mr; } -EXPORT_SYMBOL(ib_alloc_fast_reg_mr); +EXPORT_SYMBOL(ib_alloc_mr); struct ib_fast_reg_page_list *ib_alloc_fast_reg_page_list(struct ib_device *device, int max_page_list_len) diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index aba51431c9861..c3540da2731f8 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1672,8 +1672,6 @@ struct ib_device { struct ib_mr * (*alloc_mr)(struct ib_pd *pd, enum ib_mr_type mr_type, u32 max_num_sg); - struct ib_mr * (*alloc_fast_reg_mr)(struct ib_pd *pd, - int max_page_list_len); struct ib_fast_reg_page_list * (*alloc_fast_reg_page_list)(struct ib_device *device, int page_list_len); void (*free_fast_reg_page_list)(struct ib_fast_reg_page_list *page_list); @@ -2820,15 +2818,6 @@ struct ib_mr *ib_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, u32 max_num_sg); -/** - * ib_alloc_fast_reg_mr - Allocates memory region usable with the - * IB_WR_FAST_REG_MR send work request. - * @pd: The protection domain associated with the region. - * @max_page_list_len: requested max physical buffer list length to be - * used with fast register work requests for this MR. - */ -struct ib_mr *ib_alloc_fast_reg_mr(struct ib_pd *pd, int max_page_list_len); - /** * ib_alloc_fast_reg_page_list - Allocates a page list array * @device - ib device pointer. -- GitLab From 399e6f95811bd36fb64b3d30cf8529d633884b4c Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Thu, 30 Jul 2015 18:33:22 +0300 Subject: [PATCH 5778/7006] net/ipv6: Export addrconf_ifid_eui48 For loopback purposes, RoCE devices should have a default GID in the port GID table, even when the interface is down. In order to do so, we use the IPv6 link local address which would have been genenrated for the related Ethernet netdevice when it goes up as a default GID. addrconf_ifid_eui48 is used to gernerate this address, export it. Signed-off-by: Matan Barak Signed-off-by: Doug Ledford --- include/net/addrconf.h | 31 +++++++++++++++++++++++++++++++ net/ipv6/addrconf.c | 31 ------------------------------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/include/net/addrconf.h b/include/net/addrconf.h index def59d3a34d5e..431fdfa3f56d2 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -91,6 +91,37 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2); void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); +static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) +{ + if (dev->addr_len != ETH_ALEN) + return -1; + memcpy(eui, dev->dev_addr, 3); + memcpy(eui + 5, dev->dev_addr + 3, 3); + + /* + * The zSeries OSA network cards can be shared among various + * OS instances, but the OSA cards have only one MAC address. + * This leads to duplicate address conflicts in conjunction + * with IPv6 if more than one instance uses the same card. + * + * The driver for these cards can deliver a unique 16-bit + * identifier for each instance sharing the same card. It is + * placed instead of 0xFFFE in the interface identifier. The + * "u" bit of the interface identifier is not inverted in this + * case. Hence the resulting interface identifier has local + * scope according to RFC2373. + */ + if (dev->dev_id) { + eui[3] = (dev->dev_id >> 8) & 0xFF; + eui[4] = dev->dev_id & 0xFF; + } else { + eui[3] = 0xFF; + eui[4] = 0xFE; + eui[0] ^= 2; + } + return 0; +} + static inline unsigned long addrconf_timeout_fixup(u32 timeout, unsigned int unit) { diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 21c2c818df3b8..5b0c041323d71 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -1845,37 +1845,6 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp) __ipv6_dev_ac_dec(ifp->idev, &addr); } -static int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) -{ - if (dev->addr_len != ETH_ALEN) - return -1; - memcpy(eui, dev->dev_addr, 3); - memcpy(eui + 5, dev->dev_addr + 3, 3); - - /* - * The zSeries OSA network cards can be shared among various - * OS instances, but the OSA cards have only one MAC address. - * This leads to duplicate address conflicts in conjunction - * with IPv6 if more than one instance uses the same card. - * - * The driver for these cards can deliver a unique 16-bit - * identifier for each instance sharing the same card. It is - * placed instead of 0xFFFE in the interface identifier. The - * "u" bit of the interface identifier is not inverted in this - * case. Hence the resulting interface identifier has local - * scope according to RFC2373. - */ - if (dev->dev_id) { - eui[3] = (dev->dev_id >> 8) & 0xFF; - eui[4] = dev->dev_id & 0xFF; - } else { - eui[3] = 0xFF; - eui[4] = 0xFE; - eui[0] ^= 2; - } - return 0; -} - static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) { if (dev->addr_len != IEEE802154_ADDR_LEN) -- GitLab From 816dd19b3d191da88bc034fb85e21ed09a3ed320 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Thu, 30 Jul 2015 18:33:23 +0300 Subject: [PATCH 5779/7006] net: Add info for NETDEV_CHANGEUPPER event Some consumers of NETDEV_CHANGEUPPER event would like to know which upper device was linked/unlinked and what operation was carried. Add information in the notifier info block for that purpose. Signed-off-by: Matan Barak Signed-off-by: Doug Ledford --- include/linux/netdevice.h | 14 ++++++++++++++ net/core/dev.c | 12 ++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e20979dfd6a99..2b7fe4e3146ad 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -3556,6 +3556,20 @@ struct sk_buff *__skb_gso_segment(struct sk_buff *skb, struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, netdev_features_t features); +enum netdev_changeupper_event { + NETDEV_CHANGEUPPER_LINK, + NETDEV_CHANGEUPPER_UNLINK, +}; + +struct netdev_changeupper_info { + struct netdev_notifier_info info; /* must be first */ + enum netdev_changeupper_event event; + struct net_device *upper; +}; + +void netdev_changeupper_info_change(struct net_device *dev, + struct netdev_changeupper_info *info); + struct netdev_bonding_info { ifslave slave; ifbond master; diff --git a/net/core/dev.c b/net/core/dev.c index a8e4dd4302853..6e6f14e5d44fc 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -5302,6 +5302,7 @@ static int __netdev_upper_dev_link(struct net_device *dev, void *private) { struct netdev_adjacent *i, *j, *to_i, *to_j; + struct netdev_changeupper_info changeupper_info; int ret = 0; ASSERT_RTNL(); @@ -5357,7 +5358,10 @@ static int __netdev_upper_dev_link(struct net_device *dev, goto rollback_lower_mesh; } - call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + changeupper_info.event = NETDEV_CHANGEUPPER_LINK; + changeupper_info.upper = upper_dev; + call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, + &changeupper_info.info); return 0; rollback_lower_mesh: @@ -5453,6 +5457,7 @@ void netdev_upper_dev_unlink(struct net_device *dev, struct net_device *upper_dev) { struct netdev_adjacent *i, *j; + struct netdev_changeupper_info changeupper_info; ASSERT_RTNL(); __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); @@ -5474,7 +5479,10 @@ void netdev_upper_dev_unlink(struct net_device *dev, list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) __netdev_adjacent_dev_unlink(dev, i->dev); - call_netdevice_notifiers(NETDEV_CHANGEUPPER, dev); + changeupper_info.event = NETDEV_CHANGEUPPER_UNLINK; + changeupper_info.upper = upper_dev; + call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, + &changeupper_info.info); } EXPORT_SYMBOL(netdev_upper_dev_unlink); -- GitLab From e999869548b9ab97b7dffa053ba2fee81c31d069 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Thu, 30 Jul 2015 18:33:24 +0300 Subject: [PATCH 5780/7006] net/bonding: Export bond_option_active_slave_get_rcu Some consumers of the netdev events API would like to know who is the active slave when a NETDEV_CHANGEUPPER or NETDEV_BONDING_FAILOVER events occur. For example, when managing RoCE GIDs, GIDs based on the bond's ips should only be set on the port which corresponds to active slave netdevice. Signed-off-by: Matan Barak Signed-off-by: Doug Ledford --- drivers/net/bonding/bond_options.c | 13 ------------- include/net/bonding.h | 7 +++++++ 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c index e9c624d54dd4c..28bd005ab9e79 100644 --- a/drivers/net/bonding/bond_options.c +++ b/drivers/net/bonding/bond_options.c @@ -730,19 +730,6 @@ static int bond_option_mode_set(struct bonding *bond, return 0; } -static struct net_device *__bond_option_active_slave_get(struct bonding *bond, - struct slave *slave) -{ - return bond_uses_primary(bond) && slave ? slave->dev : NULL; -} - -struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond) -{ - struct slave *slave = rcu_dereference(bond->curr_active_slave); - - return __bond_option_active_slave_get(bond, slave); -} - static int bond_option_active_slave_set(struct bonding *bond, const struct bond_opt_value *newval) { diff --git a/include/net/bonding.h b/include/net/bonding.h index 20defc0353d13..c1740a2794a37 100644 --- a/include/net/bonding.h +++ b/include/net/bonding.h @@ -310,6 +310,13 @@ static inline bool bond_uses_primary(struct bonding *bond) return bond_mode_uses_primary(BOND_MODE(bond)); } +static inline struct net_device *bond_option_active_slave_get_rcu(struct bonding *bond) +{ + struct slave *slave = rcu_dereference(bond->curr_active_slave); + + return bond_uses_primary(bond) && slave ? slave->dev : NULL; +} + static inline bool bond_slave_is_up(struct slave *slave) { return netif_running(slave->dev) && netif_carrier_ok(slave->dev); -- GitLab From 55aeed06544f675f25aef06a8c47b0b6b8850f4f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 4 Aug 2015 15:23:34 -0600 Subject: [PATCH 5781/7006] IB/core: Make ib_alloc_device init the kobject This gets rid of the weird in-between state where struct ib_device was allocated but the kobject didn't work. Consequently ib_device_release is now guaranteed to be called in all situations and we needn't duplicate its kfrees on error paths. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/core/cache.c | 9 +-- drivers/infiniband/core/core_priv.h | 3 - drivers/infiniband/core/device.c | 92 +++++++++++++++++++---------- drivers/infiniband/core/sysfs.c | 51 ++-------------- 4 files changed, 68 insertions(+), 87 deletions(-) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index c93af66cc091a..a6d50258131e0 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -351,10 +351,10 @@ static void ib_cache_setup_one(struct ib_device *device) rwlock_init(&device->cache.lock); device->cache.pkey_cache = - kmalloc(sizeof *device->cache.pkey_cache * + kzalloc(sizeof *device->cache.pkey_cache * (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL); device->cache.gid_cache = - kmalloc(sizeof *device->cache.gid_cache * + kzalloc(sizeof *device->cache.gid_cache * (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL); device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache * @@ -369,11 +369,8 @@ static void ib_cache_setup_one(struct ib_device *device) goto err; } - for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) { - device->cache.pkey_cache[p] = NULL; - device->cache.gid_cache [p] = NULL; + for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) ib_cache_update(device, p + rdma_start_port(device)); - } INIT_IB_EVENT_HANDLER(&device->cache.event_handler, device, ib_cache_event); diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 87d1936f5c1ca..950583a62e3b7 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -43,9 +43,6 @@ int ib_device_register_sysfs(struct ib_device *device, u8, struct kobject *)); void ib_device_unregister_sysfs(struct ib_device *device); -int ib_sysfs_setup(void); -void ib_sysfs_cleanup(void); - int ib_cache_setup(void); void ib_cache_cleanup(void); diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index a9a27816991ab..a4a914afae1c1 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -165,6 +165,35 @@ static int alloc_name(char *name) return 0; } +static void ib_device_release(struct device *device) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + kfree(dev->port_immutable); + kfree(dev); +} + +static int ib_device_uevent(struct device *device, + struct kobj_uevent_env *env) +{ + struct ib_device *dev = container_of(device, struct ib_device, dev); + + if (add_uevent_var(env, "NAME=%s", dev->name)) + return -ENOMEM; + + /* + * It would be nice to pass the node GUID with the event... + */ + + return 0; +} + +static struct class ib_class = { + .name = "infiniband", + .dev_release = ib_device_release, + .dev_uevent = ib_device_uevent, +}; + /** * ib_alloc_device - allocate an IB device struct * @size:size of structure to allocate @@ -177,9 +206,27 @@ static int alloc_name(char *name) */ struct ib_device *ib_alloc_device(size_t size) { - BUG_ON(size < sizeof (struct ib_device)); + struct ib_device *device; + + if (WARN_ON(size < sizeof(struct ib_device))) + return NULL; + + device = kzalloc(size, GFP_KERNEL); + if (!device) + return NULL; + + device->dev.class = &ib_class; + device_initialize(&device->dev); + + dev_set_drvdata(&device->dev, device); + + INIT_LIST_HEAD(&device->event_handler_list); + spin_lock_init(&device->event_handler_lock); + spin_lock_init(&device->client_data_lock); + INIT_LIST_HEAD(&device->client_data_list); + INIT_LIST_HEAD(&device->port_list); - return kzalloc(size, GFP_KERNEL); + return device; } EXPORT_SYMBOL(ib_alloc_device); @@ -191,13 +238,8 @@ EXPORT_SYMBOL(ib_alloc_device); */ void ib_dealloc_device(struct ib_device *device) { - if (device->reg_state == IB_DEV_UNINITIALIZED) { - kfree(device); - return; - } - - BUG_ON(device->reg_state != IB_DEV_UNREGISTERED); - + WARN_ON(device->reg_state != IB_DEV_UNREGISTERED && + device->reg_state != IB_DEV_UNINITIALIZED); kobject_put(&device->dev.kobj); } EXPORT_SYMBOL(ib_dealloc_device); @@ -235,7 +277,7 @@ static int verify_immutable(const struct ib_device *dev, u8 port) static int read_port_immutable(struct ib_device *device) { - int ret = -ENOMEM; + int ret; u8 start_port = rdma_start_port(device); u8 end_port = rdma_end_port(device); u8 port; @@ -251,26 +293,18 @@ static int read_port_immutable(struct ib_device *device) * (end_port + 1), GFP_KERNEL); if (!device->port_immutable) - goto err; + return -ENOMEM; for (port = start_port; port <= end_port; ++port) { ret = device->get_port_immutable(device, port, &device->port_immutable[port]); if (ret) - goto err; + return ret; - if (verify_immutable(device, port)) { - ret = -EINVAL; - goto err; - } + if (verify_immutable(device, port)) + return -EINVAL; } - - ret = 0; - goto out; -err: - kfree(device->port_immutable); -out: - return ret; + return 0; } /** @@ -301,11 +335,6 @@ int ib_register_device(struct ib_device *device, goto out; } - INIT_LIST_HEAD(&device->event_handler_list); - INIT_LIST_HEAD(&device->client_data_list); - spin_lock_init(&device->event_handler_lock); - spin_lock_init(&device->client_data_lock); - ret = read_port_immutable(device); if (ret) { printk(KERN_WARNING "Couldn't create per port immutable data %s\n", @@ -317,7 +346,6 @@ int ib_register_device(struct ib_device *device, if (ret) { printk(KERN_WARNING "Couldn't register device %s with driver model\n", device->name); - kfree(device->port_immutable); goto out; } @@ -834,7 +862,7 @@ static int __init ib_core_init(void) if (!ib_wq) return -ENOMEM; - ret = ib_sysfs_setup(); + ret = class_register(&ib_class); if (ret) { printk(KERN_WARNING "Couldn't create InfiniBand device class\n"); goto err; @@ -858,7 +886,7 @@ err_nl: ibnl_cleanup(); err_sysfs: - ib_sysfs_cleanup(); + class_unregister(&ib_class); err: destroy_workqueue(ib_wq); @@ -869,7 +897,7 @@ static void __exit ib_core_cleanup(void) { ib_cache_cleanup(); ibnl_cleanup(); - ib_sysfs_cleanup(); + class_unregister(&ib_class); /* Make sure that any pending umem accounting work is done. */ destroy_workqueue(ib_wq); } diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 0b84a9cdfe5b9..34cdd74b0a17e 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -457,29 +457,6 @@ static struct kobj_type port_type = { .default_attrs = port_default_attrs }; -static void ib_device_release(struct device *device) -{ - struct ib_device *dev = container_of(device, struct ib_device, dev); - - kfree(dev->port_immutable); - kfree(dev); -} - -static int ib_device_uevent(struct device *device, - struct kobj_uevent_env *env) -{ - struct ib_device *dev = container_of(device, struct ib_device, dev); - - if (add_uevent_var(env, "NAME=%s", dev->name)) - return -ENOMEM; - - /* - * It would be nice to pass the node GUID with the event... - */ - - return 0; -} - static struct attribute ** alloc_group_attrs(ssize_t (*show)(struct ib_port *, struct port_attribute *, char *buf), @@ -702,12 +679,6 @@ static struct device_attribute *ib_class_attributes[] = { &dev_attr_node_desc }; -static struct class ib_class = { - .name = "infiniband", - .dev_release = ib_device_release, - .dev_uevent = ib_device_uevent, -}; - /* Show a given an attribute in the statistics group */ static ssize_t show_protocol_stat(const struct device *device, struct device_attribute *attr, char *buf, @@ -846,14 +817,12 @@ int ib_device_register_sysfs(struct ib_device *device, int ret; int i; - class_dev->class = &ib_class; - class_dev->parent = device->dma_device; - dev_set_name(class_dev, "%s", device->name); - dev_set_drvdata(class_dev, device); - - INIT_LIST_HEAD(&device->port_list); + device->dev.parent = device->dma_device; + ret = dev_set_name(class_dev, "%s", device->name); + if (ret) + return ret; - ret = device_register(class_dev); + ret = device_add(class_dev); if (ret) goto err; @@ -916,13 +885,3 @@ void ib_device_unregister_sysfs(struct ib_device *device) device_unregister(&device->dev); } - -int ib_sysfs_setup(void) -{ - return class_register(&ib_class); -} - -void ib_sysfs_cleanup(void) -{ - class_unregister(&ib_class); -} -- GitLab From 03db3a2d81e6e84f3ed3cb9e087cae17d762642b Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Thu, 30 Jul 2015 18:33:26 +0300 Subject: [PATCH 5782/7006] IB/core: Add RoCE GID table management RoCE GIDs are based on IP addresses configured on Ethernet net-devices which relate to the RDMA (RoCE) device port. Currently, each of the low-level drivers that support RoCE (ocrdma, mlx4) manages its own RoCE port GID table. As there's nothing which is essentially vendor specific, we generalize that, and enhance the RDMA core GID cache to do this job. In order to populate the GID table, we listen for events: (a) netdev up/down/change_addr events - if a netdev is built onto our RoCE device, we need to add/delete its IPs. This involves adding all GIDs related to this ndev, add default GIDs, etc. (b) inet events - add new GIDs (according to the IP addresses) to the table. For programming the port RoCE GID table, providers must implement the add_gid and del_gid callbacks. RoCE GID management requires us to state the associated net_device alongside the GID. This information is necessary in order to manage the GID table. For example, when a net_device is removed, its associated GIDs need to be removed as well. RoCE mandates generating a default GID for each port, based on the related net-device's IPv6 link local. In contrast to the GID based on the regular IPv6 link-local (as we generate GID per IP address), the default GID is also available when the net device is down (in order to support loopback). Locking is done as follows: The patch modify the GID table code both for new RoCE drivers implementing the add_gid/del_gid callbacks and for current RoCE and IB drivers that do not. The flows for updating the table are different, so the locking requirements are too. While updating RoCE GID table, protection against multiple writers is achieved via mutex_lock(&table->lock). Since writing to a table requires us to find an entry (possible a free entry) in the table and then modify it, this mutex protects both the find_gid and write_gid ensuring the atomicity of the action. Each entry in the GID cache is protected by rwlock. In RoCE, writing (usually results from netdev notifier) involves invoking the vendor's add_gid and del_gid callbacks, which could sleep. Therefore, an invalid flag is added for each entry. Updates for RoCE are done via a workqueue, thus sleeping is permitted. In IB, updates are done in write_lock_irq(&device->cache.lock), thus write_gid isn't allowed to sleep and add_gid/del_gid are not called. When passing net-device into/out-of the GID cache, the device is always passed held (dev_hold). The code uses a single work item for updating all RDMA devices, following a netdev or inet notifier. The patch moves the cache from being a client (which was incorrect, as the cache is part of the IB infrastructure) to being explicitly initialized/freed when a device is registered/removed. Signed-off-by: Matan Barak Signed-off-by: Doug Ledford --- drivers/infiniband/core/Makefile | 3 +- drivers/infiniband/core/cache.c | 765 +++++++++++++++++++++--- drivers/infiniband/core/core_priv.h | 51 +- drivers/infiniband/core/device.c | 96 ++- drivers/infiniband/core/roce_gid_mgmt.c | 465 ++++++++++++++ include/rdma/ib_verbs.h | 66 +- 6 files changed, 1338 insertions(+), 108 deletions(-) create mode 100644 drivers/infiniband/core/roce_gid_mgmt.c diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index acf7367644459..d43a8994ac5c1 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile @@ -9,7 +9,8 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ $(user_access-y) ib_core-y := packer.o ud_header.o verbs.o sysfs.o \ - device.o fmr_pool.o cache.o netlink.o + device.o fmr_pool.o cache.o netlink.o \ + roce_gid_mgmt.o ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index a6d50258131e0..fc39a2fed37b5 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include @@ -47,76 +49,620 @@ struct ib_pkey_cache { u16 table[0]; }; -struct ib_gid_cache { - int table_len; - union ib_gid table[0]; -}; - struct ib_update_work { struct work_struct work; struct ib_device *device; u8 port_num; }; -int ib_get_cached_gid(struct ib_device *device, - u8 port_num, - int index, - union ib_gid *gid) +static union ib_gid zgid; + +static const struct ib_gid_attr zattr; + +enum gid_attr_find_mask { + GID_ATTR_FIND_MASK_GID = 1UL << 0, + GID_ATTR_FIND_MASK_NETDEV = 1UL << 1, + GID_ATTR_FIND_MASK_DEFAULT = 1UL << 2, +}; + +enum gid_table_entry_props { + GID_TABLE_ENTRY_INVALID = 1UL << 0, + GID_TABLE_ENTRY_DEFAULT = 1UL << 1, +}; + +enum gid_table_write_action { + GID_TABLE_WRITE_ACTION_ADD, + GID_TABLE_WRITE_ACTION_DEL, + /* MODIFY only updates the GID table. Currently only used by + * ib_cache_update. + */ + GID_TABLE_WRITE_ACTION_MODIFY +}; + +struct ib_gid_table_entry { + /* This lock protects an entry from being + * read and written simultaneously. + */ + rwlock_t lock; + unsigned long props; + union ib_gid gid; + struct ib_gid_attr attr; + void *context; +}; + +struct ib_gid_table { + int sz; + /* In RoCE, adding a GID to the table requires: + * (a) Find if this GID is already exists. + * (b) Find a free space. + * (c) Write the new GID + * + * Delete requires different set of operations: + * (a) Find the GID + * (b) Delete it. + * + * Add/delete should be carried out atomically. + * This is done by locking this mutex from multiple + * writers. We don't need this lock for IB, as the MAD + * layer replaces all entries. All data_vec entries + * are locked by this lock. + **/ + struct mutex lock; + struct ib_gid_table_entry *data_vec; +}; + +static int write_gid(struct ib_device *ib_dev, u8 port, + struct ib_gid_table *table, int ix, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + enum gid_table_write_action action, + bool default_gid) { - struct ib_gid_cache *cache; + int ret = 0; + struct net_device *old_net_dev; unsigned long flags; + + /* in rdma_cap_roce_gid_table, this funciton should be protected by a + * sleep-able lock. + */ + write_lock_irqsave(&table->data_vec[ix].lock, flags); + + if (rdma_cap_roce_gid_table(ib_dev, port)) { + table->data_vec[ix].props |= GID_TABLE_ENTRY_INVALID; + write_unlock_irqrestore(&table->data_vec[ix].lock, flags); + /* GID_TABLE_WRITE_ACTION_MODIFY currently isn't supported by + * RoCE providers and thus only updates the cache. + */ + if (action == GID_TABLE_WRITE_ACTION_ADD) + ret = ib_dev->add_gid(ib_dev, port, ix, gid, attr, + &table->data_vec[ix].context); + else if (action == GID_TABLE_WRITE_ACTION_DEL) + ret = ib_dev->del_gid(ib_dev, port, ix, + &table->data_vec[ix].context); + write_lock_irqsave(&table->data_vec[ix].lock, flags); + } + + old_net_dev = table->data_vec[ix].attr.ndev; + if (old_net_dev && old_net_dev != attr->ndev) + dev_put(old_net_dev); + /* if modify_gid failed, just delete the old gid */ + if (ret || action == GID_TABLE_WRITE_ACTION_DEL) { + gid = &zgid; + attr = &zattr; + table->data_vec[ix].context = NULL; + } + if (default_gid) + table->data_vec[ix].props |= GID_TABLE_ENTRY_DEFAULT; + memcpy(&table->data_vec[ix].gid, gid, sizeof(*gid)); + memcpy(&table->data_vec[ix].attr, attr, sizeof(*attr)); + if (table->data_vec[ix].attr.ndev && + table->data_vec[ix].attr.ndev != old_net_dev) + dev_hold(table->data_vec[ix].attr.ndev); + + table->data_vec[ix].props &= ~GID_TABLE_ENTRY_INVALID; + + write_unlock_irqrestore(&table->data_vec[ix].lock, flags); + + if (!ret && rdma_cap_roce_gid_table(ib_dev, port)) { + struct ib_event event; + + event.device = ib_dev; + event.element.port_num = port; + event.event = IB_EVENT_GID_CHANGE; + + ib_dispatch_event(&event); + } + return ret; +} + +static int add_gid(struct ib_device *ib_dev, u8 port, + struct ib_gid_table *table, int ix, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + bool default_gid) { + return write_gid(ib_dev, port, table, ix, gid, attr, + GID_TABLE_WRITE_ACTION_ADD, default_gid); +} + +static int modify_gid(struct ib_device *ib_dev, u8 port, + struct ib_gid_table *table, int ix, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + bool default_gid) { + return write_gid(ib_dev, port, table, ix, gid, attr, + GID_TABLE_WRITE_ACTION_MODIFY, default_gid); +} + +static int del_gid(struct ib_device *ib_dev, u8 port, + struct ib_gid_table *table, int ix, + bool default_gid) { + return write_gid(ib_dev, port, table, ix, &zgid, &zattr, + GID_TABLE_WRITE_ACTION_DEL, default_gid); +} + +static int find_gid(struct ib_gid_table *table, const union ib_gid *gid, + const struct ib_gid_attr *val, bool default_gid, + unsigned long mask) +{ + int i; + + for (i = 0; i < table->sz; i++) { + unsigned long flags; + struct ib_gid_attr *attr = &table->data_vec[i].attr; + + read_lock_irqsave(&table->data_vec[i].lock, flags); + + if (table->data_vec[i].props & GID_TABLE_ENTRY_INVALID) + goto next; + + if (mask & GID_ATTR_FIND_MASK_GID && + memcmp(gid, &table->data_vec[i].gid, sizeof(*gid))) + goto next; + + if (mask & GID_ATTR_FIND_MASK_NETDEV && + attr->ndev != val->ndev) + goto next; + + if (mask & GID_ATTR_FIND_MASK_DEFAULT && + !!(table->data_vec[i].props & GID_TABLE_ENTRY_DEFAULT) != + default_gid) + goto next; + + read_unlock_irqrestore(&table->data_vec[i].lock, flags); + return i; +next: + read_unlock_irqrestore(&table->data_vec[i].lock, flags); + } + + return -1; +} + +static void make_default_gid(struct net_device *dev, union ib_gid *gid) +{ + gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); + addrconf_ifid_eui48(&gid->raw[8], dev); +} + +int ib_cache_gid_add(struct ib_device *ib_dev, u8 port, + union ib_gid *gid, struct ib_gid_attr *attr) +{ + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + struct ib_gid_table *table; + int ix; int ret = 0; + struct net_device *idev; - if (port_num < rdma_start_port(device) || port_num > rdma_end_port(device)) + table = ports_table[port - rdma_start_port(ib_dev)]; + + if (!memcmp(gid, &zgid, sizeof(*gid))) return -EINVAL; - read_lock_irqsave(&device->cache.lock, flags); + if (ib_dev->get_netdev) { + idev = ib_dev->get_netdev(ib_dev, port); + if (idev && attr->ndev != idev) { + union ib_gid default_gid; - cache = device->cache.gid_cache[port_num - rdma_start_port(device)]; + /* Adding default GIDs in not permitted */ + make_default_gid(idev, &default_gid); + if (!memcmp(gid, &default_gid, sizeof(*gid))) { + dev_put(idev); + return -EPERM; + } + } + if (idev) + dev_put(idev); + } - if (index < 0 || index >= cache->table_len) - ret = -EINVAL; - else - *gid = cache->table[index]; + mutex_lock(&table->lock); - read_unlock_irqrestore(&device->cache.lock, flags); + ix = find_gid(table, gid, attr, false, GID_ATTR_FIND_MASK_GID | + GID_ATTR_FIND_MASK_NETDEV); + if (ix >= 0) + goto out_unlock; + ix = find_gid(table, &zgid, NULL, false, GID_ATTR_FIND_MASK_GID | + GID_ATTR_FIND_MASK_DEFAULT); + if (ix < 0) { + ret = -ENOSPC; + goto out_unlock; + } + + add_gid(ib_dev, port, table, ix, gid, attr, false); + +out_unlock: + mutex_unlock(&table->lock); return ret; } -EXPORT_SYMBOL(ib_get_cached_gid); -int ib_find_cached_gid(struct ib_device *device, - const union ib_gid *gid, - u8 *port_num, - u16 *index) +int ib_cache_gid_del(struct ib_device *ib_dev, u8 port, + union ib_gid *gid, struct ib_gid_attr *attr) { - struct ib_gid_cache *cache; + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + struct ib_gid_table *table; + int ix; + + table = ports_table[port - rdma_start_port(ib_dev)]; + + mutex_lock(&table->lock); + + ix = find_gid(table, gid, attr, false, + GID_ATTR_FIND_MASK_GID | + GID_ATTR_FIND_MASK_NETDEV | + GID_ATTR_FIND_MASK_DEFAULT); + if (ix < 0) + goto out_unlock; + + del_gid(ib_dev, port, table, ix, false); + +out_unlock: + mutex_unlock(&table->lock); + return 0; +} + +int ib_cache_gid_del_all_netdev_gids(struct ib_device *ib_dev, u8 port, + struct net_device *ndev) +{ + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + struct ib_gid_table *table; + int ix; + + table = ports_table[port - rdma_start_port(ib_dev)]; + + mutex_lock(&table->lock); + + for (ix = 0; ix < table->sz; ix++) + if (table->data_vec[ix].attr.ndev == ndev) + del_gid(ib_dev, port, table, ix, false); + + mutex_unlock(&table->lock); + return 0; +} + +static int __ib_cache_gid_get(struct ib_device *ib_dev, u8 port, int index, + union ib_gid *gid, struct ib_gid_attr *attr) +{ + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + struct ib_gid_table *table; unsigned long flags; - int p, i; - int ret = -ENOENT; - *port_num = -1; - if (index) - *index = -1; + table = ports_table[port - rdma_start_port(ib_dev)]; - read_lock_irqsave(&device->cache.lock, flags); + if (index < 0 || index >= table->sz) + return -EINVAL; - for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) { - cache = device->cache.gid_cache[p]; - for (i = 0; i < cache->table_len; ++i) { - if (!memcmp(gid, &cache->table[i], sizeof *gid)) { - *port_num = p + rdma_start_port(device); - if (index) - *index = i; - ret = 0; - goto found; - } + read_lock_irqsave(&table->data_vec[index].lock, flags); + if (table->data_vec[index].props & GID_TABLE_ENTRY_INVALID) { + read_unlock_irqrestore(&table->data_vec[index].lock, flags); + return -EAGAIN; + } + + memcpy(gid, &table->data_vec[index].gid, sizeof(*gid)); + if (attr) { + memcpy(attr, &table->data_vec[index].attr, sizeof(*attr)); + if (attr->ndev) + dev_hold(attr->ndev); + } + + read_unlock_irqrestore(&table->data_vec[index].lock, flags); + return 0; +} + +static int _ib_cache_gid_table_find(struct ib_device *ib_dev, + const union ib_gid *gid, + const struct ib_gid_attr *val, + unsigned long mask, + u8 *port, u16 *index) +{ + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + struct ib_gid_table *table; + u8 p; + int local_index; + + for (p = 0; p < ib_dev->phys_port_cnt; p++) { + table = ports_table[p]; + local_index = find_gid(table, gid, val, false, mask); + if (local_index >= 0) { + if (index) + *index = local_index; + if (port) + *port = p + rdma_start_port(ib_dev); + return 0; } } -found: - read_unlock_irqrestore(&device->cache.lock, flags); - return ret; + return -ENOENT; +} + +static int ib_cache_gid_find(struct ib_device *ib_dev, + const union ib_gid *gid, + struct net_device *ndev, u8 *port, + u16 *index) +{ + unsigned long mask = GID_ATTR_FIND_MASK_GID; + struct ib_gid_attr gid_attr_val = {.ndev = ndev}; + + if (ndev) + mask |= GID_ATTR_FIND_MASK_NETDEV; + + return _ib_cache_gid_table_find(ib_dev, gid, &gid_attr_val, + mask, port, index); +} + +int ib_cache_gid_find_by_port(struct ib_device *ib_dev, + const union ib_gid *gid, + u8 port, struct net_device *ndev, + u16 *index) +{ + int local_index; + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + struct ib_gid_table *table; + unsigned long mask = GID_ATTR_FIND_MASK_GID; + struct ib_gid_attr val = {.ndev = ndev}; + + if (port < rdma_start_port(ib_dev) || + port > rdma_end_port(ib_dev)) + return -ENOENT; + + table = ports_table[port - rdma_start_port(ib_dev)]; + + if (ndev) + mask |= GID_ATTR_FIND_MASK_NETDEV; + + local_index = find_gid(table, gid, &val, false, mask); + if (local_index >= 0) { + if (index) + *index = local_index; + return 0; + } + + return -ENOENT; +} + +static struct ib_gid_table *alloc_gid_table(int sz) +{ + unsigned int i; + struct ib_gid_table *table = + kzalloc(sizeof(struct ib_gid_table), GFP_KERNEL); + if (!table) + return NULL; + + table->data_vec = kcalloc(sz, sizeof(*table->data_vec), GFP_KERNEL); + if (!table->data_vec) + goto err_free_table; + + mutex_init(&table->lock); + + table->sz = sz; + + for (i = 0; i < sz; i++) + rwlock_init(&table->data_vec[i].lock); + + return table; + +err_free_table: + kfree(table); + return NULL; +} + +static void release_gid_table(struct ib_gid_table *table) +{ + if (table) { + kfree(table->data_vec); + kfree(table); + } +} + +static void cleanup_gid_table_port(struct ib_device *ib_dev, u8 port, + struct ib_gid_table *table) +{ + int i; + + if (!table) + return; + + for (i = 0; i < table->sz; ++i) { + if (memcmp(&table->data_vec[i].gid, &zgid, + sizeof(table->data_vec[i].gid))) + del_gid(ib_dev, port, table, i, + table->data_vec[i].props & + GID_ATTR_FIND_MASK_DEFAULT); + } +} + +void ib_cache_gid_set_default_gid(struct ib_device *ib_dev, u8 port, + struct net_device *ndev, + enum ib_cache_gid_default_mode mode) +{ + struct ib_gid_table **ports_table = ib_dev->cache.gid_cache; + union ib_gid gid; + struct ib_gid_attr gid_attr; + struct ib_gid_table *table; + int ix; + union ib_gid current_gid; + struct ib_gid_attr current_gid_attr = {}; + + table = ports_table[port - rdma_start_port(ib_dev)]; + + make_default_gid(ndev, &gid); + memset(&gid_attr, 0, sizeof(gid_attr)); + gid_attr.ndev = ndev; + + ix = find_gid(table, NULL, NULL, true, GID_ATTR_FIND_MASK_DEFAULT); + + /* Coudn't find default GID location */ + WARN_ON(ix < 0); + + mutex_lock(&table->lock); + if (!__ib_cache_gid_get(ib_dev, port, ix, + ¤t_gid, ¤t_gid_attr) && + mode == IB_CACHE_GID_DEFAULT_MODE_SET && + !memcmp(&gid, ¤t_gid, sizeof(gid)) && + !memcmp(&gid_attr, ¤t_gid_attr, sizeof(gid_attr))) + goto unlock; + + if ((memcmp(¤t_gid, &zgid, sizeof(current_gid)) || + memcmp(¤t_gid_attr, &zattr, + sizeof(current_gid_attr))) && + del_gid(ib_dev, port, table, ix, true)) { + pr_warn("ib_cache_gid: can't delete index %d for default gid %pI6\n", + ix, gid.raw); + goto unlock; + } + + if (mode == IB_CACHE_GID_DEFAULT_MODE_SET) + if (add_gid(ib_dev, port, table, ix, &gid, &gid_attr, true)) + pr_warn("ib_cache_gid: unable to add default gid %pI6\n", + gid.raw); + +unlock: + if (current_gid_attr.ndev) + dev_put(current_gid_attr.ndev); + mutex_unlock(&table->lock); +} + +static int gid_table_reserve_default(struct ib_device *ib_dev, u8 port, + struct ib_gid_table *table) +{ + if (rdma_protocol_roce(ib_dev, port)) { + struct ib_gid_table_entry *entry = &table->data_vec[0]; + + entry->props |= GID_TABLE_ENTRY_DEFAULT; + } + + return 0; +} + +static int _gid_table_setup_one(struct ib_device *ib_dev) +{ + u8 port; + struct ib_gid_table **table; + int err = 0; + + table = kcalloc(ib_dev->phys_port_cnt, sizeof(*table), GFP_KERNEL); + + if (!table) { + pr_warn("failed to allocate ib gid cache for %s\n", + ib_dev->name); + return -ENOMEM; + } + + for (port = 0; port < ib_dev->phys_port_cnt; port++) { + u8 rdma_port = port + rdma_start_port(ib_dev); + + table[port] = + alloc_gid_table( + ib_dev->port_immutable[rdma_port].gid_tbl_len); + if (!table[port]) { + err = -ENOMEM; + goto rollback_table_setup; + } + + err = gid_table_reserve_default(ib_dev, + port + rdma_start_port(ib_dev), + table[port]); + if (err) + goto rollback_table_setup; + } + + ib_dev->cache.gid_cache = table; + return 0; + +rollback_table_setup: + for (port = 0; port < ib_dev->phys_port_cnt; port++) { + cleanup_gid_table_port(ib_dev, port + rdma_start_port(ib_dev), + table[port]); + release_gid_table(table[port]); + } + + kfree(table); + return err; +} + +static void gid_table_release_one(struct ib_device *ib_dev) +{ + struct ib_gid_table **table = ib_dev->cache.gid_cache; + u8 port; + + if (!table) + return; + + for (port = 0; port < ib_dev->phys_port_cnt; port++) + release_gid_table(table[port]); + + kfree(table); + ib_dev->cache.gid_cache = NULL; +} + +static void gid_table_cleanup_one(struct ib_device *ib_dev) +{ + struct ib_gid_table **table = ib_dev->cache.gid_cache; + u8 port; + + if (!table) + return; + + for (port = 0; port < ib_dev->phys_port_cnt; port++) + cleanup_gid_table_port(ib_dev, port + rdma_start_port(ib_dev), + table[port]); +} + +static int gid_table_setup_one(struct ib_device *ib_dev) +{ + int err; + + err = _gid_table_setup_one(ib_dev); + + if (err) + return err; + + err = roce_rescan_device(ib_dev); + + if (err) { + gid_table_cleanup_one(ib_dev); + gid_table_release_one(ib_dev); + } + + return err; +} + +int ib_get_cached_gid(struct ib_device *device, + u8 port_num, + int index, + union ib_gid *gid) +{ + if (port_num < rdma_start_port(device) || port_num > rdma_end_port(device)) + return -EINVAL; + + return __ib_cache_gid_get(device, port_num, index, gid, NULL); +} +EXPORT_SYMBOL(ib_get_cached_gid); + +int ib_find_cached_gid(struct ib_device *device, + const union ib_gid *gid, + u8 *port_num, + u16 *index) +{ + return ib_cache_gid_find(device, gid, NULL, port_num, index); } EXPORT_SYMBOL(ib_find_cached_gid); @@ -243,9 +789,21 @@ static void ib_cache_update(struct ib_device *device, { struct ib_port_attr *tprops = NULL; struct ib_pkey_cache *pkey_cache = NULL, *old_pkey_cache; - struct ib_gid_cache *gid_cache = NULL, *old_gid_cache; + struct ib_gid_cache { + int table_len; + union ib_gid table[0]; + } *gid_cache = NULL; int i; int ret; + struct ib_gid_table *table; + struct ib_gid_table **ports_table = device->cache.gid_cache; + bool use_roce_gid_table = + rdma_cap_roce_gid_table(device, port); + + if (port < rdma_start_port(device) || port > rdma_end_port(device)) + return; + + table = ports_table[port - rdma_start_port(device)]; tprops = kmalloc(sizeof *tprops, GFP_KERNEL); if (!tprops) @@ -265,12 +823,14 @@ static void ib_cache_update(struct ib_device *device, pkey_cache->table_len = tprops->pkey_tbl_len; - gid_cache = kmalloc(sizeof *gid_cache + tprops->gid_tbl_len * - sizeof *gid_cache->table, GFP_KERNEL); - if (!gid_cache) - goto err; + if (!use_roce_gid_table) { + gid_cache = kmalloc(sizeof(*gid_cache) + tprops->gid_tbl_len * + sizeof(*gid_cache->table), GFP_KERNEL); + if (!gid_cache) + goto err; - gid_cache->table_len = tprops->gid_tbl_len; + gid_cache->table_len = tprops->gid_tbl_len; + } for (i = 0; i < pkey_cache->table_len; ++i) { ret = ib_query_pkey(device, port, i, pkey_cache->table + i); @@ -281,29 +841,36 @@ static void ib_cache_update(struct ib_device *device, } } - for (i = 0; i < gid_cache->table_len; ++i) { - ret = ib_query_gid(device, port, i, gid_cache->table + i); - if (ret) { - printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n", - ret, device->name, i); - goto err; + if (!use_roce_gid_table) { + for (i = 0; i < gid_cache->table_len; ++i) { + ret = ib_query_gid(device, port, i, + gid_cache->table + i); + if (ret) { + printk(KERN_WARNING "ib_query_gid failed (%d) for %s (index %d)\n", + ret, device->name, i); + goto err; + } } } write_lock_irq(&device->cache.lock); old_pkey_cache = device->cache.pkey_cache[port - rdma_start_port(device)]; - old_gid_cache = device->cache.gid_cache [port - rdma_start_port(device)]; device->cache.pkey_cache[port - rdma_start_port(device)] = pkey_cache; - device->cache.gid_cache [port - rdma_start_port(device)] = gid_cache; + if (!use_roce_gid_table) { + for (i = 0; i < gid_cache->table_len; i++) { + modify_gid(device, port, table, i, gid_cache->table + i, + &zattr, false); + } + } device->cache.lmc_cache[port - rdma_start_port(device)] = tprops->lmc; write_unlock_irq(&device->cache.lock); + kfree(gid_cache); kfree(old_pkey_cache); - kfree(old_gid_cache); kfree(tprops); return; @@ -344,82 +911,88 @@ static void ib_cache_event(struct ib_event_handler *handler, } } -static void ib_cache_setup_one(struct ib_device *device) +int ib_cache_setup_one(struct ib_device *device) { int p; + int err; rwlock_init(&device->cache.lock); device->cache.pkey_cache = kzalloc(sizeof *device->cache.pkey_cache * (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL); - device->cache.gid_cache = - kzalloc(sizeof *device->cache.gid_cache * - (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL); - device->cache.lmc_cache = kmalloc(sizeof *device->cache.lmc_cache * (rdma_end_port(device) - rdma_start_port(device) + 1), GFP_KERNEL); - - if (!device->cache.pkey_cache || !device->cache.gid_cache || + if (!device->cache.pkey_cache || !device->cache.lmc_cache) { printk(KERN_WARNING "Couldn't allocate cache " "for %s\n", device->name); - goto err; + return -ENOMEM; } + err = gid_table_setup_one(device); + if (err) + /* Allocated memory will be cleaned in the release function */ + return err; + for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) ib_cache_update(device, p + rdma_start_port(device)); INIT_IB_EVENT_HANDLER(&device->cache.event_handler, device, ib_cache_event); - if (ib_register_event_handler(&device->cache.event_handler)) - goto err_cache; - - return; + err = ib_register_event_handler(&device->cache.event_handler); + if (err) + goto err; -err_cache: - for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) { - kfree(device->cache.pkey_cache[p]); - kfree(device->cache.gid_cache[p]); - } + return 0; err: - kfree(device->cache.pkey_cache); - kfree(device->cache.gid_cache); - kfree(device->cache.lmc_cache); + gid_table_cleanup_one(device); + return err; } -static void ib_cache_cleanup_one(struct ib_device *device, void *client_data) +void ib_cache_release_one(struct ib_device *device) { int p; - ib_unregister_event_handler(&device->cache.event_handler); - flush_workqueue(ib_wq); - - for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) { - kfree(device->cache.pkey_cache[p]); - kfree(device->cache.gid_cache[p]); - } - + /* + * The release function frees all the cache elements. + * This function should be called as part of freeing + * all the device's resources when the cache could no + * longer be accessed. + */ + if (device->cache.pkey_cache) + for (p = 0; + p <= rdma_end_port(device) - rdma_start_port(device); ++p) + kfree(device->cache.pkey_cache[p]); + + gid_table_release_one(device); kfree(device->cache.pkey_cache); - kfree(device->cache.gid_cache); kfree(device->cache.lmc_cache); } -static struct ib_client cache_client = { - .name = "cache", - .add = ib_cache_setup_one, - .remove = ib_cache_cleanup_one -}; +void ib_cache_cleanup_one(struct ib_device *device) +{ + /* The cleanup function unregisters the event handler, + * waits for all in-progress workqueue elements and cleans + * up the GID cache. This function should be called after + * the device was removed from the devices list and all + * clients were removed, so the cache exists but is + * non-functional and shouldn't be updated anymore. + */ + ib_unregister_event_handler(&device->cache.event_handler); + flush_workqueue(ib_wq); + gid_table_cleanup_one(device); +} -int __init ib_cache_setup(void) +void __init ib_cache_setup(void) { - return ib_register_client(&cache_client); + roce_gid_mgmt_init(); } void __exit ib_cache_cleanup(void) { - ib_unregister_client(&cache_client); + roce_gid_mgmt_cleanup(); } diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 950583a62e3b7..70bb36ebb03b8 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -43,9 +43,58 @@ int ib_device_register_sysfs(struct ib_device *device, u8, struct kobject *)); void ib_device_unregister_sysfs(struct ib_device *device); -int ib_cache_setup(void); +void ib_cache_setup(void); void ib_cache_cleanup(void); int ib_resolve_eth_l2_attrs(struct ib_qp *qp, struct ib_qp_attr *qp_attr, int *qp_attr_mask); + +typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port, + struct net_device *idev, void *cookie); + +typedef int (*roce_netdev_filter)(struct ib_device *device, u8 port, + struct net_device *idev, void *cookie); + +void ib_enum_roce_netdev(struct ib_device *ib_dev, + roce_netdev_filter filter, + void *filter_cookie, + roce_netdev_callback cb, + void *cookie); +void ib_enum_all_roce_netdevs(roce_netdev_filter filter, + void *filter_cookie, + roce_netdev_callback cb, + void *cookie); + +int ib_cache_gid_find_by_port(struct ib_device *ib_dev, + const union ib_gid *gid, + u8 port, struct net_device *ndev, + u16 *index); + +enum ib_cache_gid_default_mode { + IB_CACHE_GID_DEFAULT_MODE_SET, + IB_CACHE_GID_DEFAULT_MODE_DELETE +}; + +void ib_cache_gid_set_default_gid(struct ib_device *ib_dev, u8 port, + struct net_device *ndev, + enum ib_cache_gid_default_mode mode); + +int ib_cache_gid_add(struct ib_device *ib_dev, u8 port, + union ib_gid *gid, struct ib_gid_attr *attr); + +int ib_cache_gid_del(struct ib_device *ib_dev, u8 port, + union ib_gid *gid, struct ib_gid_attr *attr); + +int ib_cache_gid_del_all_netdev_gids(struct ib_device *ib_dev, u8 port, + struct net_device *ndev); + +int roce_gid_mgmt_init(void); +void roce_gid_mgmt_cleanup(void); + +int roce_rescan_device(struct ib_device *ib_dev); + +int ib_cache_setup_one(struct ib_device *device); +void ib_cache_cleanup_one(struct ib_device *device); +void ib_cache_release_one(struct ib_device *device); + #endif /* _CORE_PRIV_H */ diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index a4a914afae1c1..dfa2c5744741a 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include #include "core_priv.h" @@ -169,6 +171,7 @@ static void ib_device_release(struct device *device) { struct ib_device *dev = container_of(device, struct ib_device, dev); + ib_cache_release_one(dev); kfree(dev->port_immutable); kfree(dev); } @@ -342,10 +345,17 @@ int ib_register_device(struct ib_device *device, goto out; } + ret = ib_cache_setup_one(device); + if (ret) { + printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); + goto out; + } + ret = ib_device_register_sysfs(device, port_callback); if (ret) { printk(KERN_WARNING "Couldn't register device %s with driver model\n", device->name); + ib_cache_cleanup_one(device); goto out; } @@ -399,6 +409,7 @@ void ib_unregister_device(struct ib_device *device) mutex_unlock(&device_mutex); ib_device_unregister_sysfs(device); + ib_cache_cleanup_one(device); down_write(&lists_rwsem); spin_lock_irqsave(&device->client_data_lock, flags); @@ -670,10 +681,79 @@ EXPORT_SYMBOL(ib_query_port); int ib_query_gid(struct ib_device *device, u8 port_num, int index, union ib_gid *gid) { + if (rdma_cap_roce_gid_table(device, port_num)) + return ib_get_cached_gid(device, port_num, index, gid); + return device->query_gid(device, port_num, index, gid); } EXPORT_SYMBOL(ib_query_gid); +/** + * ib_enum_roce_netdev - enumerate all RoCE ports + * @ib_dev : IB device we want to query + * @filter: Should we call the callback? + * @filter_cookie: Cookie passed to filter + * @cb: Callback to call for each found RoCE ports + * @cookie: Cookie passed back to the callback + * + * Enumerates all of the physical RoCE ports of ib_dev + * which are related to netdevice and calls callback() on each + * device for which filter() function returns non zero. + */ +void ib_enum_roce_netdev(struct ib_device *ib_dev, + roce_netdev_filter filter, + void *filter_cookie, + roce_netdev_callback cb, + void *cookie) +{ + u8 port; + + for (port = rdma_start_port(ib_dev); port <= rdma_end_port(ib_dev); + port++) + if (rdma_protocol_roce(ib_dev, port)) { + struct net_device *idev = NULL; + + if (ib_dev->get_netdev) + idev = ib_dev->get_netdev(ib_dev, port); + + if (idev && + idev->reg_state >= NETREG_UNREGISTERED) { + dev_put(idev); + idev = NULL; + } + + if (filter(ib_dev, port, idev, filter_cookie)) + cb(ib_dev, port, idev, cookie); + + if (idev) + dev_put(idev); + } +} + +/** + * ib_enum_all_roce_netdevs - enumerate all RoCE devices + * @filter: Should we call the callback? + * @filter_cookie: Cookie passed to filter + * @cb: Callback to call for each found RoCE ports + * @cookie: Cookie passed back to the callback + * + * Enumerates all RoCE devices' physical ports which are related + * to netdevices and calls callback() on each device for which + * filter() function returns non zero. + */ +void ib_enum_all_roce_netdevs(roce_netdev_filter filter, + void *filter_cookie, + roce_netdev_callback cb, + void *cookie) +{ + struct ib_device *dev; + + down_read(&lists_rwsem); + list_for_each_entry(dev, &device_list, core_list) + ib_enum_roce_netdev(dev, filter, filter_cookie, cb, cookie); + up_read(&lists_rwsem); +} + /** * ib_query_pkey - Get P_Key table entry * @device:Device to query @@ -753,6 +833,13 @@ int ib_find_gid(struct ib_device *device, union ib_gid *gid, int ret, port, i; for (port = rdma_start_port(device); port <= rdma_end_port(device); ++port) { + if (rdma_cap_roce_gid_table(device, port)) { + if (!ib_cache_gid_find_by_port(device, gid, port, + NULL, index)) + *port_num = port; + return 0; + } + for (i = 0; i < device->port_immutable[port].gid_tbl_len; ++i) { ret = ib_query_gid(device, port, i, &tmp_gid); if (ret) @@ -874,17 +961,10 @@ static int __init ib_core_init(void) goto err_sysfs; } - ret = ib_cache_setup(); - if (ret) { - printk(KERN_WARNING "Couldn't set up InfiniBand P_Key/GID cache\n"); - goto err_nl; - } + ib_cache_setup(); return 0; -err_nl: - ibnl_cleanup(); - err_sysfs: class_unregister(&ib_class); diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c new file mode 100644 index 0000000000000..7bf4798ec7e21 --- /dev/null +++ b/drivers/infiniband/core/roce_gid_mgmt.c @@ -0,0 +1,465 @@ +/* + * Copyright (c) 2015, Mellanox Technologies inc. All rights reserved. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 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. + */ + +#include "core_priv.h" + +#include +#include + +/* For in6_dev_get/in6_dev_put */ +#include + +#include +#include + +enum gid_op_type { + GID_DEL = 0, + GID_ADD +}; + +struct update_gid_event_work { + struct work_struct work; + union ib_gid gid; + struct ib_gid_attr gid_attr; + enum gid_op_type gid_op; +}; + +#define ROCE_NETDEV_CALLBACK_SZ 2 +struct netdev_event_work_cmd { + roce_netdev_callback cb; + roce_netdev_filter filter; +}; + +struct netdev_event_work { + struct work_struct work; + struct netdev_event_work_cmd cmds[ROCE_NETDEV_CALLBACK_SZ]; + struct net_device *ndev; +}; + +static void update_gid(enum gid_op_type gid_op, struct ib_device *ib_dev, + u8 port, union ib_gid *gid, + struct ib_gid_attr *gid_attr) +{ + switch (gid_op) { + case GID_ADD: + ib_cache_gid_add(ib_dev, port, gid, gid_attr); + break; + case GID_DEL: + ib_cache_gid_del(ib_dev, port, gid, gid_attr); + break; + } +} + +static int is_eth_port_of_netdev(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + struct net_device *real_dev; + struct net_device *master_dev; + struct net_device *event_ndev = (struct net_device *)cookie; + int res; + + if (!rdma_ndev) + return 0; + + rcu_read_lock(); + master_dev = netdev_master_upper_dev_get_rcu(rdma_ndev); + real_dev = rdma_vlan_dev_real_dev(event_ndev); + res = (real_dev ? real_dev : event_ndev) == + (master_dev ? master_dev : rdma_ndev); + rcu_read_unlock(); + + return res; +} + +static int pass_all_filter(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + return 1; +} + +static void update_gid_ip(enum gid_op_type gid_op, + struct ib_device *ib_dev, + u8 port, struct net_device *ndev, + struct sockaddr *addr) +{ + union ib_gid gid; + struct ib_gid_attr gid_attr; + + rdma_ip2gid(addr, &gid); + memset(&gid_attr, 0, sizeof(gid_attr)); + gid_attr.ndev = ndev; + + update_gid(gid_op, ib_dev, port, &gid, &gid_attr); +} + +static void enum_netdev_default_gids(struct ib_device *ib_dev, + u8 port, struct net_device *event_ndev, + struct net_device *rdma_ndev) +{ + if (rdma_ndev != event_ndev) + return; + + ib_cache_gid_set_default_gid(ib_dev, port, rdma_ndev, + IB_CACHE_GID_DEFAULT_MODE_SET); +} + +static void enum_netdev_ipv4_ips(struct ib_device *ib_dev, + u8 port, struct net_device *ndev) +{ + struct in_device *in_dev; + + if (ndev->reg_state >= NETREG_UNREGISTERING) + return; + + in_dev = in_dev_get(ndev); + if (!in_dev) + return; + + for_ifa(in_dev) { + struct sockaddr_in ip; + + ip.sin_family = AF_INET; + ip.sin_addr.s_addr = ifa->ifa_address; + update_gid_ip(GID_ADD, ib_dev, port, ndev, + (struct sockaddr *)&ip); + } + endfor_ifa(in_dev); + + in_dev_put(in_dev); +} + +static void enum_netdev_ipv6_ips(struct ib_device *ib_dev, + u8 port, struct net_device *ndev) +{ + struct inet6_ifaddr *ifp; + struct inet6_dev *in6_dev; + struct sin6_list { + struct list_head list; + struct sockaddr_in6 sin6; + }; + struct sin6_list *sin6_iter; + struct sin6_list *sin6_temp; + struct ib_gid_attr gid_attr = {.ndev = ndev}; + LIST_HEAD(sin6_list); + + if (ndev->reg_state >= NETREG_UNREGISTERING) + return; + + in6_dev = in6_dev_get(ndev); + if (!in6_dev) + return; + + read_lock_bh(&in6_dev->lock); + list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { + struct sin6_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + + if (!entry) { + pr_warn("roce_gid_mgmt: couldn't allocate entry for IPv6 update\n"); + continue; + } + + entry->sin6.sin6_family = AF_INET6; + entry->sin6.sin6_addr = ifp->addr; + list_add_tail(&entry->list, &sin6_list); + } + read_unlock_bh(&in6_dev->lock); + + in6_dev_put(in6_dev); + + list_for_each_entry_safe(sin6_iter, sin6_temp, &sin6_list, list) { + union ib_gid gid; + + rdma_ip2gid((struct sockaddr *)&sin6_iter->sin6, &gid); + update_gid(GID_ADD, ib_dev, port, &gid, &gid_attr); + list_del(&sin6_iter->list); + kfree(sin6_iter); + } +} + +static void add_netdev_ips(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + struct net_device *event_ndev = (struct net_device *)cookie; + + enum_netdev_default_gids(ib_dev, port, event_ndev, rdma_ndev); + enum_netdev_ipv4_ips(ib_dev, port, event_ndev); + if (IS_ENABLED(CONFIG_IPV6)) + enum_netdev_ipv6_ips(ib_dev, port, event_ndev); +} + +static void del_netdev_ips(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + struct net_device *event_ndev = (struct net_device *)cookie; + + ib_cache_gid_del_all_netdev_gids(ib_dev, port, event_ndev); +} + +static void enum_all_gids_of_dev_cb(struct ib_device *ib_dev, + u8 port, + struct net_device *rdma_ndev, + void *cookie) +{ + struct net *net; + struct net_device *ndev; + + /* Lock the rtnl to make sure the netdevs does not move under + * our feet + */ + rtnl_lock(); + for_each_net(net) + for_each_netdev(net, ndev) + if (is_eth_port_of_netdev(ib_dev, port, rdma_ndev, ndev)) + add_netdev_ips(ib_dev, port, rdma_ndev, ndev); + rtnl_unlock(); +} + +/* This function will rescan all of the network devices in the system + * and add their gids, as needed, to the relevant RoCE devices. */ +int roce_rescan_device(struct ib_device *ib_dev) +{ + ib_enum_roce_netdev(ib_dev, pass_all_filter, NULL, + enum_all_gids_of_dev_cb, NULL); + + return 0; +} + +static void callback_for_addr_gid_device_scan(struct ib_device *device, + u8 port, + struct net_device *rdma_ndev, + void *cookie) +{ + struct update_gid_event_work *parsed = cookie; + + return update_gid(parsed->gid_op, device, + port, &parsed->gid, + &parsed->gid_attr); +} + +/* The following functions operate on all IB devices. netdevice_event and + * addr_event execute ib_enum_all_roce_netdevs through a work. + * ib_enum_all_roce_netdevs iterates through all IB devices. + */ + +static void netdevice_event_work_handler(struct work_struct *_work) +{ + struct netdev_event_work *work = + container_of(_work, struct netdev_event_work, work); + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(work->cmds) && work->cmds[i].cb; i++) + ib_enum_all_roce_netdevs(work->cmds[i].filter, work->ndev, + work->cmds[i].cb, work->ndev); + + dev_put(work->ndev); + kfree(work); +} + +static int netdevice_queue_work(struct netdev_event_work_cmd *cmds, + struct net_device *ndev) +{ + struct netdev_event_work *ndev_work = + kmalloc(sizeof(*ndev_work), GFP_KERNEL); + + if (!ndev_work) { + pr_warn("roce_gid_mgmt: can't allocate work for netdevice_event\n"); + return NOTIFY_DONE; + } + + memcpy(ndev_work->cmds, cmds, sizeof(ndev_work->cmds)); + ndev_work->ndev = ndev; + dev_hold(ndev); + INIT_WORK(&ndev_work->work, netdevice_event_work_handler); + + queue_work(ib_wq, &ndev_work->work); + + return NOTIFY_DONE; +} + +static int netdevice_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + static const struct netdev_event_work_cmd add_cmd = { + .cb = add_netdev_ips, .filter = is_eth_port_of_netdev}; + static const struct netdev_event_work_cmd del_cmd = { + .cb = del_netdev_ips, .filter = pass_all_filter}; + struct net_device *ndev = netdev_notifier_info_to_dev(ptr); + struct netdev_event_work_cmd cmds[ROCE_NETDEV_CALLBACK_SZ] = { {NULL} }; + + if (ndev->type != ARPHRD_ETHER) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_REGISTER: + case NETDEV_UP: + cmds[0] = add_cmd; + break; + + case NETDEV_UNREGISTER: + if (ndev->reg_state < NETREG_UNREGISTERED) + cmds[0] = del_cmd; + else + return NOTIFY_DONE; + break; + + case NETDEV_CHANGEADDR: + cmds[0] = del_cmd; + cmds[1] = add_cmd; + break; + default: + return NOTIFY_DONE; + } + + return netdevice_queue_work(cmds, ndev); +} + +static void update_gid_event_work_handler(struct work_struct *_work) +{ + struct update_gid_event_work *work = + container_of(_work, struct update_gid_event_work, work); + + ib_enum_all_roce_netdevs(is_eth_port_of_netdev, work->gid_attr.ndev, + callback_for_addr_gid_device_scan, work); + + dev_put(work->gid_attr.ndev); + kfree(work); +} + +static int addr_event(struct notifier_block *this, unsigned long event, + struct sockaddr *sa, struct net_device *ndev) +{ + struct update_gid_event_work *work; + enum gid_op_type gid_op; + + if (ndev->type != ARPHRD_ETHER) + return NOTIFY_DONE; + + switch (event) { + case NETDEV_UP: + gid_op = GID_ADD; + break; + + case NETDEV_DOWN: + gid_op = GID_DEL; + break; + + default: + return NOTIFY_DONE; + } + + work = kmalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + pr_warn("roce_gid_mgmt: Couldn't allocate work for addr_event\n"); + return NOTIFY_DONE; + } + + INIT_WORK(&work->work, update_gid_event_work_handler); + + rdma_ip2gid(sa, &work->gid); + work->gid_op = gid_op; + + memset(&work->gid_attr, 0, sizeof(work->gid_attr)); + dev_hold(ndev); + work->gid_attr.ndev = ndev; + + queue_work(ib_wq, &work->work); + + return NOTIFY_DONE; +} + +static int inetaddr_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct sockaddr_in in; + struct net_device *ndev; + struct in_ifaddr *ifa = ptr; + + in.sin_family = AF_INET; + in.sin_addr.s_addr = ifa->ifa_address; + ndev = ifa->ifa_dev->dev; + + return addr_event(this, event, (struct sockaddr *)&in, ndev); +} + +static int inet6addr_event(struct notifier_block *this, unsigned long event, + void *ptr) +{ + struct sockaddr_in6 in6; + struct net_device *ndev; + struct inet6_ifaddr *ifa6 = ptr; + + in6.sin6_family = AF_INET6; + in6.sin6_addr = ifa6->addr; + ndev = ifa6->idev->dev; + + return addr_event(this, event, (struct sockaddr *)&in6, ndev); +} + +static struct notifier_block nb_netdevice = { + .notifier_call = netdevice_event +}; + +static struct notifier_block nb_inetaddr = { + .notifier_call = inetaddr_event +}; + +static struct notifier_block nb_inet6addr = { + .notifier_call = inet6addr_event +}; + +int __init roce_gid_mgmt_init(void) +{ + register_inetaddr_notifier(&nb_inetaddr); + if (IS_ENABLED(CONFIG_IPV6)) + register_inet6addr_notifier(&nb_inet6addr); + /* We relay on the netdevice notifier to enumerate all + * existing devices in the system. Register to this notifier + * last to make sure we will not miss any IP add/del + * callbacks. + */ + register_netdevice_notifier(&nb_netdevice); + + return 0; +} + +void __exit roce_gid_mgmt_cleanup(void) +{ + if (IS_ENABLED(CONFIG_IPV6)) + unregister_inet6addr_notifier(&nb_inet6addr); + unregister_inetaddr_notifier(&nb_inetaddr); + unregister_netdevice_notifier(&nb_netdevice); + /* Ensure all gid deletion tasks complete before we go down, + * to avoid any reference to free'd memory. By the time + * ib-core is removed, all physical devices have been removed, + * so no issue with remaining hardware contexts. + */ +} diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index c3540da2731f8..2de56834a6bef 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -65,6 +65,10 @@ union ib_gid { } global; }; +struct ib_gid_attr { + struct net_device *ndev; +}; + enum rdma_node_type { /* IB values map to NodeInfo:NodeType. */ RDMA_NODE_IB_CA = 1, @@ -285,7 +289,7 @@ enum ib_port_cap_flags { IB_PORT_BOOT_MGMT_SUP = 1 << 23, IB_PORT_LINK_LATENCY_SUP = 1 << 24, IB_PORT_CLIENT_REG_SUP = 1 << 25, - IB_PORT_IP_BASED_GIDS = 1 << 26 + IB_PORT_IP_BASED_GIDS = 1 << 26, }; enum ib_port_width { @@ -1487,7 +1491,7 @@ struct ib_cache { rwlock_t lock; struct ib_event_handler event_handler; struct ib_pkey_cache **pkey_cache; - struct ib_gid_cache **gid_cache; + struct ib_gid_table **gid_cache; u8 *lmc_cache; }; @@ -1573,9 +1577,47 @@ struct ib_device { struct ib_port_attr *port_attr); enum rdma_link_layer (*get_link_layer)(struct ib_device *device, u8 port_num); + /* When calling get_netdev, the HW vendor's driver should return the + * net device of device @device at port @port_num or NULL if such + * a net device doesn't exist. The vendor driver should call dev_hold + * on this net device. The HW vendor's device driver must guarantee + * that this function returns NULL before the net device reaches + * NETDEV_UNREGISTER_FINAL state. + */ + struct net_device *(*get_netdev)(struct ib_device *device, + u8 port_num); int (*query_gid)(struct ib_device *device, u8 port_num, int index, union ib_gid *gid); + /* When calling add_gid, the HW vendor's driver should + * add the gid of device @device at gid index @index of + * port @port_num to be @gid. Meta-info of that gid (for example, + * the network device related to this gid is available + * at @attr. @context allows the HW vendor driver to store extra + * information together with a GID entry. The HW vendor may allocate + * memory to contain this information and store it in @context when a + * new GID entry is written to. Params are consistent until the next + * call of add_gid or delete_gid. The function should return 0 on + * success or error otherwise. The function could be called + * concurrently for different ports. This function is only called + * when roce_gid_table is used. + */ + int (*add_gid)(struct ib_device *device, + u8 port_num, + unsigned int index, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + void **context); + /* When calling del_gid, the HW vendor's driver should delete the + * gid of device @device at gid index @index of port @port_num. + * Upon the deletion of a GID entry, the HW vendor must free any + * allocated memory. The caller will clear @context afterwards. + * This function is only called when roce_gid_table is used. + */ + int (*del_gid)(struct ib_device *device, + u8 port_num, + unsigned int index, + void **context); int (*query_pkey)(struct ib_device *device, u8 port_num, u16 index, u16 *pkey); int (*modify_device)(struct ib_device *device, @@ -2108,6 +2150,26 @@ static inline size_t rdma_max_mad_size(const struct ib_device *device, u8 port_n return device->port_immutable[port_num].max_mad_size; } +/** + * rdma_cap_roce_gid_table - Check if the port of device uses roce_gid_table + * @device: Device to check + * @port_num: Port number to check + * + * RoCE GID table mechanism manages the various GIDs for a device. + * + * NOTE: if allocating the port's GID table has failed, this call will still + * return true, but any RoCE GID table API will fail. + * + * Return: true if the port uses RoCE GID table mechanism in order to manage + * its GIDs. + */ +static inline bool rdma_cap_roce_gid_table(const struct ib_device *device, + u8 port_num) +{ + return rdma_protocol_roce(device, port_num) && + device->add_gid && device->del_gid; +} + int ib_query_gid(struct ib_device *device, u8 port_num, int index, union ib_gid *gid); -- GitLab From 98d25afa970d134024d8652360569e3bd74782b3 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 18 Aug 2015 12:22:10 +0300 Subject: [PATCH 5783/7006] IB/core: missing curly braces in ib_find_gid() Smatch says that, based on the indenting, we should probably add curly braces here. Fixes: 03db3a2d81e6 ('IB/core: Add RoCE GID table management') Signed-off-by: Dan Carpenter Reviewed-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/device.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index dfa2c5744741a..7a4ee795c13e0 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -835,9 +835,10 @@ int ib_find_gid(struct ib_device *device, union ib_gid *gid, for (port = rdma_start_port(device); port <= rdma_end_port(device); ++port) { if (rdma_cap_roce_gid_table(device, port)) { if (!ib_cache_gid_find_by_port(device, gid, port, - NULL, index)) + NULL, index)) { *port_num = port; return 0; + } } for (i = 0; i < device->port_immutable[port].gid_tbl_len; ++i) { -- GitLab From 238fdf48f2b54a01cedb5774c3a1e81c94e1a3a0 Mon Sep 17 00:00:00 2001 From: Matan Barak Date: Thu, 30 Jul 2015 18:33:27 +0300 Subject: [PATCH 5784/7006] IB/core: Add RoCE table bonding support Handling bonding and other devices require us to all all GIDs of the net-devices which are upper-devices of the RoCE port related net-device. Active-backup configurations imposes even more challenges as the default GID should only be set on the active devices (this is necessary as otherwise the same MAC could be used for several slaves and thus several slaves will have identical GIDs). Managing these configurations are done by listening to: (a) NETDEV_CHANGEUPPER event (1) if a related net-device is linked, delete all inactive slaves default GIDs and add the upper device GIDs. (2) if a related net-device is unlinked, delete all upper GIDs and add the default GIDs. (b) NETDEV_BONDING_FAILOVER: (1) delete the bond GIDs from inactive slaves (2) delete the inactive slave's default GIDs (3) Add the bond GIDs to the active slave. Signed-off-by: Matan Barak Signed-off-by: Doug Ledford --- drivers/infiniband/core/roce_gid_mgmt.c | 305 ++++++++++++++++++++++-- 1 file changed, 285 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c index 7bf4798ec7e21..6eecdfbf3aef6 100644 --- a/drivers/infiniband/core/roce_gid_mgmt.c +++ b/drivers/infiniband/core/roce_gid_mgmt.c @@ -37,6 +37,7 @@ /* For in6_dev_get/in6_dev_put */ #include +#include #include #include @@ -53,16 +54,17 @@ struct update_gid_event_work { enum gid_op_type gid_op; }; -#define ROCE_NETDEV_CALLBACK_SZ 2 +#define ROCE_NETDEV_CALLBACK_SZ 3 struct netdev_event_work_cmd { roce_netdev_callback cb; roce_netdev_filter filter; + struct net_device *ndev; + struct net_device *filter_ndev; }; struct netdev_event_work { struct work_struct work; struct netdev_event_work_cmd cmds[ROCE_NETDEV_CALLBACK_SZ]; - struct net_device *ndev; }; static void update_gid(enum gid_op_type gid_op, struct ib_device *ib_dev, @@ -79,12 +81,70 @@ static void update_gid(enum gid_op_type gid_op, struct ib_device *ib_dev, } } +enum bonding_slave_state { + BONDING_SLAVE_STATE_ACTIVE = 1UL << 0, + BONDING_SLAVE_STATE_INACTIVE = 1UL << 1, + /* No primary slave or the device isn't a slave in bonding */ + BONDING_SLAVE_STATE_NA = 1UL << 2, +}; + +static enum bonding_slave_state is_eth_active_slave_of_bonding_rcu(struct net_device *dev, + struct net_device *upper) +{ + if (upper && netif_is_bond_master(upper)) { + struct net_device *pdev = + bond_option_active_slave_get_rcu(netdev_priv(upper)); + + if (pdev) + return dev == pdev ? BONDING_SLAVE_STATE_ACTIVE : + BONDING_SLAVE_STATE_INACTIVE; + } + + return BONDING_SLAVE_STATE_NA; +} + +static bool is_upper_dev_rcu(struct net_device *dev, struct net_device *upper) +{ + struct net_device *_upper = NULL; + struct list_head *iter; + + netdev_for_each_all_upper_dev_rcu(dev, _upper, iter) + if (_upper == upper) + break; + + return _upper == upper; +} + +#define REQUIRED_BOND_STATES (BONDING_SLAVE_STATE_ACTIVE | \ + BONDING_SLAVE_STATE_NA) static int is_eth_port_of_netdev(struct ib_device *ib_dev, u8 port, struct net_device *rdma_ndev, void *cookie) { + struct net_device *event_ndev = (struct net_device *)cookie; struct net_device *real_dev; + int res; + + if (!rdma_ndev) + return 0; + + rcu_read_lock(); + real_dev = rdma_vlan_dev_real_dev(event_ndev); + if (!real_dev) + real_dev = event_ndev; + + res = ((is_upper_dev_rcu(rdma_ndev, event_ndev) && + (is_eth_active_slave_of_bonding_rcu(rdma_ndev, real_dev) & + REQUIRED_BOND_STATES)) || + real_dev == rdma_ndev); + + rcu_read_unlock(); + return res; +} + +static int is_eth_port_inactive_slave(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ struct net_device *master_dev; - struct net_device *event_ndev = (struct net_device *)cookie; int res; if (!rdma_ndev) @@ -92,9 +152,8 @@ static int is_eth_port_of_netdev(struct ib_device *ib_dev, u8 port, rcu_read_lock(); master_dev = netdev_master_upper_dev_get_rcu(rdma_ndev); - real_dev = rdma_vlan_dev_real_dev(event_ndev); - res = (real_dev ? real_dev : event_ndev) == - (master_dev ? master_dev : rdma_ndev); + res = is_eth_active_slave_of_bonding_rcu(rdma_ndev, master_dev) == + BONDING_SLAVE_STATE_INACTIVE; rcu_read_unlock(); return res; @@ -106,6 +165,25 @@ static int pass_all_filter(struct ib_device *ib_dev, u8 port, return 1; } +static int upper_device_filter(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + struct net_device *event_ndev = (struct net_device *)cookie; + int res; + + if (!rdma_ndev) + return 0; + + if (rdma_ndev == event_ndev) + return 1; + + rcu_read_lock(); + res = is_upper_dev_rcu(rdma_ndev, event_ndev); + rcu_read_unlock(); + + return res; +} + static void update_gid_ip(enum gid_op_type gid_op, struct ib_device *ib_dev, u8 port, struct net_device *ndev, @@ -125,13 +203,49 @@ static void enum_netdev_default_gids(struct ib_device *ib_dev, u8 port, struct net_device *event_ndev, struct net_device *rdma_ndev) { - if (rdma_ndev != event_ndev) + rcu_read_lock(); + if (!rdma_ndev || + ((rdma_ndev != event_ndev && + !is_upper_dev_rcu(rdma_ndev, event_ndev)) || + is_eth_active_slave_of_bonding_rcu(rdma_ndev, + netdev_master_upper_dev_get_rcu(rdma_ndev)) == + BONDING_SLAVE_STATE_INACTIVE)) { + rcu_read_unlock(); return; + } + rcu_read_unlock(); ib_cache_gid_set_default_gid(ib_dev, port, rdma_ndev, IB_CACHE_GID_DEFAULT_MODE_SET); } +static void bond_delete_netdev_default_gids(struct ib_device *ib_dev, + u8 port, + struct net_device *event_ndev, + struct net_device *rdma_ndev) +{ + struct net_device *real_dev = rdma_vlan_dev_real_dev(event_ndev); + + if (!rdma_ndev) + return; + + if (!real_dev) + real_dev = event_ndev; + + rcu_read_lock(); + + if (is_upper_dev_rcu(rdma_ndev, event_ndev) && + is_eth_active_slave_of_bonding_rcu(rdma_ndev, real_dev) == + BONDING_SLAVE_STATE_INACTIVE) { + rcu_read_unlock(); + + ib_cache_gid_set_default_gid(ib_dev, port, rdma_ndev, + IB_CACHE_GID_DEFAULT_MODE_DELETE); + } else { + rcu_read_unlock(); + } +} + static void enum_netdev_ipv4_ips(struct ib_device *ib_dev, u8 port, struct net_device *ndev) { @@ -205,15 +319,21 @@ static void enum_netdev_ipv6_ips(struct ib_device *ib_dev, } } +static void _add_netdev_ips(struct ib_device *ib_dev, u8 port, + struct net_device *ndev) +{ + enum_netdev_ipv4_ips(ib_dev, port, ndev); + if (IS_ENABLED(CONFIG_IPV6)) + enum_netdev_ipv6_ips(ib_dev, port, ndev); +} + static void add_netdev_ips(struct ib_device *ib_dev, u8 port, struct net_device *rdma_ndev, void *cookie) { struct net_device *event_ndev = (struct net_device *)cookie; enum_netdev_default_gids(ib_dev, port, event_ndev, rdma_ndev); - enum_netdev_ipv4_ips(ib_dev, port, event_ndev); - if (IS_ENABLED(CONFIG_IPV6)) - enum_netdev_ipv6_ips(ib_dev, port, event_ndev); + _add_netdev_ips(ib_dev, port, event_ndev); } static void del_netdev_ips(struct ib_device *ib_dev, u8 port, @@ -265,6 +385,94 @@ static void callback_for_addr_gid_device_scan(struct ib_device *device, &parsed->gid_attr); } +static void handle_netdev_upper(struct ib_device *ib_dev, u8 port, + void *cookie, + void (*handle_netdev)(struct ib_device *ib_dev, + u8 port, + struct net_device *ndev)) +{ + struct net_device *ndev = (struct net_device *)cookie; + struct upper_list { + struct list_head list; + struct net_device *upper; + }; + struct net_device *upper; + struct list_head *iter; + struct upper_list *upper_iter; + struct upper_list *upper_temp; + LIST_HEAD(upper_list); + + rcu_read_lock(); + netdev_for_each_all_upper_dev_rcu(ndev, upper, iter) { + struct upper_list *entry = kmalloc(sizeof(*entry), + GFP_ATOMIC); + + if (!entry) { + pr_info("roce_gid_mgmt: couldn't allocate entry to delete ndev\n"); + continue; + } + + list_add_tail(&entry->list, &upper_list); + dev_hold(upper); + entry->upper = upper; + } + rcu_read_unlock(); + + handle_netdev(ib_dev, port, ndev); + list_for_each_entry_safe(upper_iter, upper_temp, &upper_list, + list) { + handle_netdev(ib_dev, port, upper_iter->upper); + dev_put(upper_iter->upper); + list_del(&upper_iter->list); + kfree(upper_iter); + } +} + +static void _roce_del_all_netdev_gids(struct ib_device *ib_dev, u8 port, + struct net_device *event_ndev) +{ + ib_cache_gid_del_all_netdev_gids(ib_dev, port, event_ndev); +} + +static void del_netdev_upper_ips(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + handle_netdev_upper(ib_dev, port, cookie, _roce_del_all_netdev_gids); +} + +static void add_netdev_upper_ips(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + handle_netdev_upper(ib_dev, port, cookie, _add_netdev_ips); +} + +static void del_netdev_default_ips_join(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, + void *cookie) +{ + struct net_device *master_ndev; + + rcu_read_lock(); + master_ndev = netdev_master_upper_dev_get_rcu(rdma_ndev); + if (master_ndev) + dev_hold(master_ndev); + rcu_read_unlock(); + + if (master_ndev) { + bond_delete_netdev_default_gids(ib_dev, port, master_ndev, + rdma_ndev); + dev_put(master_ndev); + } +} + +static void del_netdev_default_ips(struct ib_device *ib_dev, u8 port, + struct net_device *rdma_ndev, void *cookie) +{ + struct net_device *event_ndev = (struct net_device *)cookie; + + bond_delete_netdev_default_gids(ib_dev, port, event_ndev, rdma_ndev); +} + /* The following functions operate on all IB devices. netdevice_event and * addr_event execute ib_enum_all_roce_netdevs through a work. * ib_enum_all_roce_netdevs iterates through all IB devices. @@ -276,17 +484,22 @@ static void netdevice_event_work_handler(struct work_struct *_work) container_of(_work, struct netdev_event_work, work); unsigned int i; - for (i = 0; i < ARRAY_SIZE(work->cmds) && work->cmds[i].cb; i++) - ib_enum_all_roce_netdevs(work->cmds[i].filter, work->ndev, - work->cmds[i].cb, work->ndev); + for (i = 0; i < ARRAY_SIZE(work->cmds) && work->cmds[i].cb; i++) { + ib_enum_all_roce_netdevs(work->cmds[i].filter, + work->cmds[i].filter_ndev, + work->cmds[i].cb, + work->cmds[i].ndev); + dev_put(work->cmds[i].ndev); + dev_put(work->cmds[i].filter_ndev); + } - dev_put(work->ndev); kfree(work); } static int netdevice_queue_work(struct netdev_event_work_cmd *cmds, struct net_device *ndev) { + unsigned int i; struct netdev_event_work *ndev_work = kmalloc(sizeof(*ndev_work), GFP_KERNEL); @@ -296,8 +509,14 @@ static int netdevice_queue_work(struct netdev_event_work_cmd *cmds, } memcpy(ndev_work->cmds, cmds, sizeof(ndev_work->cmds)); - ndev_work->ndev = ndev; - dev_hold(ndev); + for (i = 0; i < ARRAY_SIZE(ndev_work->cmds) && ndev_work->cmds[i].cb; i++) { + if (!ndev_work->cmds[i].ndev) + ndev_work->cmds[i].ndev = ndev; + if (!ndev_work->cmds[i].filter_ndev) + ndev_work->cmds[i].filter_ndev = ndev; + dev_hold(ndev_work->cmds[i].ndev); + dev_hold(ndev_work->cmds[i].filter_ndev); + } INIT_WORK(&ndev_work->work, netdevice_event_work_handler); queue_work(ib_wq, &ndev_work->work); @@ -305,13 +524,45 @@ static int netdevice_queue_work(struct netdev_event_work_cmd *cmds, return NOTIFY_DONE; } +static const struct netdev_event_work_cmd add_cmd = { + .cb = add_netdev_ips, .filter = is_eth_port_of_netdev}; +static const struct netdev_event_work_cmd add_cmd_upper_ips = { + .cb = add_netdev_upper_ips, .filter = is_eth_port_of_netdev}; + +static void netdevice_event_changeupper(struct netdev_changeupper_info *changeupper_info, + struct netdev_event_work_cmd *cmds) +{ + static const struct netdev_event_work_cmd upper_ips_del_cmd = { + .cb = del_netdev_upper_ips, .filter = upper_device_filter}; + static const struct netdev_event_work_cmd bonding_default_del_cmd = { + .cb = del_netdev_default_ips, .filter = is_eth_port_inactive_slave}; + + if (changeupper_info->event == + NETDEV_CHANGEUPPER_UNLINK) { + cmds[0] = upper_ips_del_cmd; + cmds[0].ndev = changeupper_info->upper; + cmds[1] = add_cmd; + } else if (changeupper_info->event == + NETDEV_CHANGEUPPER_LINK) { + cmds[0] = bonding_default_del_cmd; + cmds[0].ndev = changeupper_info->upper; + cmds[1] = add_cmd_upper_ips; + cmds[1].ndev = changeupper_info->upper; + cmds[1].filter_ndev = changeupper_info->upper; + } +} + static int netdevice_event(struct notifier_block *this, unsigned long event, void *ptr) { - static const struct netdev_event_work_cmd add_cmd = { - .cb = add_netdev_ips, .filter = is_eth_port_of_netdev}; static const struct netdev_event_work_cmd del_cmd = { .cb = del_netdev_ips, .filter = pass_all_filter}; + static const struct netdev_event_work_cmd bonding_default_del_cmd_join = { + .cb = del_netdev_default_ips_join, .filter = is_eth_port_inactive_slave}; + static const struct netdev_event_work_cmd default_del_cmd = { + .cb = del_netdev_default_ips, .filter = pass_all_filter}; + static const struct netdev_event_work_cmd bonding_event_ips_del_cmd = { + .cb = del_netdev_upper_ips, .filter = upper_device_filter}; struct net_device *ndev = netdev_notifier_info_to_dev(ptr); struct netdev_event_work_cmd cmds[ROCE_NETDEV_CALLBACK_SZ] = { {NULL} }; @@ -321,7 +572,8 @@ static int netdevice_event(struct notifier_block *this, unsigned long event, switch (event) { case NETDEV_REGISTER: case NETDEV_UP: - cmds[0] = add_cmd; + cmds[0] = bonding_default_del_cmd_join; + cmds[1] = add_cmd; break; case NETDEV_UNREGISTER: @@ -332,9 +584,22 @@ static int netdevice_event(struct notifier_block *this, unsigned long event, break; case NETDEV_CHANGEADDR: - cmds[0] = del_cmd; + cmds[0] = default_del_cmd; cmds[1] = add_cmd; break; + + case NETDEV_CHANGEUPPER: + netdevice_event_changeupper( + container_of(ptr, struct netdev_changeupper_info, info), + cmds); + break; + + case NETDEV_BONDING_FAILOVER: + cmds[0] = bonding_event_ips_del_cmd; + cmds[1] = bonding_default_del_cmd_join; + cmds[2] = add_cmd_upper_ips; + break; + default: return NOTIFY_DONE; } -- GitLab From 79857cd31fe70145ff007d4e968557af342c8ccd Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 30 Jul 2015 18:33:28 +0300 Subject: [PATCH 5785/7006] net/mlx4: Postpone the registration of net_device The mlx4 network driver was registered in the context of the 'add' function of the core driver (called when HW should be registered). This makes the netdev event NETDEV_REGISTER to be sent in a context where the answer to get_protocol_dev() callback returns NULL. This may be confusing to listeners of netdev events. This patch is a preparation to the patch that implements the get_netdev() callback in the IB/mlx4 driver. Signed-off-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/net/ethernet/mellanox/mlx4/en_main.c | 36 ++++++++++++-------- drivers/net/ethernet/mellanox/mlx4/intf.c | 3 ++ include/linux/mlx4/driver.h | 1 + 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c index 913b716ed2e14..a946e4bf71d2a 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c @@ -224,6 +224,26 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr) kfree(mdev); } +static void mlx4_en_activate(struct mlx4_dev *dev, void *ctx) +{ + int i; + struct mlx4_en_dev *mdev = ctx; + + /* Create a netdev for each port */ + mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { + mlx4_info(mdev, "Activating port:%d\n", i); + if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) + mdev->pndev[i] = NULL; + } + + /* register notifier */ + mdev->nb.notifier_call = mlx4_en_netdev_event; + if (register_netdevice_notifier(&mdev->nb)) { + mdev->nb.notifier_call = NULL; + mlx4_err(mdev, "Failed to create notifier\n"); + } +} + static void *mlx4_en_add(struct mlx4_dev *dev) { struct mlx4_en_dev *mdev; @@ -297,21 +317,6 @@ static void *mlx4_en_add(struct mlx4_dev *dev) mutex_init(&mdev->state_lock); mdev->device_up = true; - /* Setup ports */ - - /* Create a netdev for each port */ - mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) { - mlx4_info(mdev, "Activating port:%d\n", i); - if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i])) - mdev->pndev[i] = NULL; - } - /* register notifier */ - mdev->nb.notifier_call = mlx4_en_netdev_event; - if (register_netdevice_notifier(&mdev->nb)) { - mdev->nb.notifier_call = NULL; - mlx4_err(mdev, "Failed to create notifier\n"); - } - return mdev; err_mr: @@ -335,6 +340,7 @@ static struct mlx4_interface mlx4_en_interface = { .event = mlx4_en_event, .get_dev = mlx4_en_get_netdev, .protocol = MLX4_PROT_ETH, + .activate = mlx4_en_activate, }; static void mlx4_en_verify_params(void) diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c index 0d80aed590437..0472941af8203 100644 --- a/drivers/net/ethernet/mellanox/mlx4/intf.c +++ b/drivers/net/ethernet/mellanox/mlx4/intf.c @@ -63,8 +63,11 @@ static void mlx4_add_device(struct mlx4_interface *intf, struct mlx4_priv *priv) spin_lock_irq(&priv->ctx_lock); list_add_tail(&dev_ctx->list, &priv->ctx_list); spin_unlock_irq(&priv->ctx_lock); + if (intf->activate) + intf->activate(&priv->dev, dev_ctx->context); } else kfree(dev_ctx); + } static void mlx4_remove_device(struct mlx4_interface *intf, struct mlx4_priv *priv) diff --git a/include/linux/mlx4/driver.h b/include/linux/mlx4/driver.h index 9553a73d2049e..5a06d969338e6 100644 --- a/include/linux/mlx4/driver.h +++ b/include/linux/mlx4/driver.h @@ -59,6 +59,7 @@ struct mlx4_interface { void (*event) (struct mlx4_dev *dev, void *context, enum mlx4_dev_event event, unsigned long param); void * (*get_dev)(struct mlx4_dev *dev, void *context, u8 port); + void (*activate)(struct mlx4_dev *dev, void *context); struct list_head list; enum mlx4_protocol protocol; int flags; -- GitLab From e26be1bfef81a2314a075f54dd8930cf5e8656df Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 30 Jul 2015 18:33:29 +0300 Subject: [PATCH 5786/7006] IB/mlx4: Implement ib_device callbacks get_netdev: get the net_device on the physical port of the IB transport port. In port aggregation mode it is required to return the netdev of the active port. modify_gid: note for a change in the RoCE gid cache. Handle this by writing to the harsware GID table. It is possible that indexes in cahce and hardware tables won't match so a translation is required when modifying a QP or creating an address handle. Signed-off-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/infiniband/core/cache.c | 3 +- drivers/infiniband/hw/mlx4/main.c | 236 ++++++++++++++++++++++++++- drivers/infiniband/hw/mlx4/mlx4_ib.h | 17 ++ include/linux/mlx4/device.h | 3 +- include/rdma/ib_verbs.h | 2 + 5 files changed, 257 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index fc39a2fed37b5..8f66c67ff0df0 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -55,7 +55,8 @@ struct ib_update_work { u8 port_num; }; -static union ib_gid zgid; +union ib_gid zgid; +EXPORT_SYMBOL(zgid); static const struct ib_gid_attr zattr; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 9ab73a496d527..5286ea7bb04af 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -45,6 +45,9 @@ #include #include #include +#include + +#include #include #include @@ -93,8 +96,6 @@ static void init_query_mad(struct ib_smp *mad) mad->method = IB_MGMT_METHOD_GET; } -static union ib_gid zgid; - static int check_flow_steering_support(struct mlx4_dev *dev) { int eth_num_ports = 0; @@ -131,6 +132,237 @@ static int num_ib_ports(struct mlx4_dev *dev) return ib_ports; } +static struct net_device *mlx4_ib_get_netdev(struct ib_device *device, u8 port_num) +{ + struct mlx4_ib_dev *ibdev = to_mdev(device); + struct net_device *dev; + + rcu_read_lock(); + dev = mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port_num); + + if (dev) { + if (mlx4_is_bonded(ibdev->dev)) { + struct net_device *upper = NULL; + + upper = netdev_master_upper_dev_get_rcu(dev); + if (upper) { + struct net_device *active; + + active = bond_option_active_slave_get_rcu(netdev_priv(upper)); + if (active) + dev = active; + } + } + } + if (dev) + dev_hold(dev); + + rcu_read_unlock(); + return dev; +} + +static int mlx4_ib_update_gids(struct gid_entry *gids, + struct mlx4_ib_dev *ibdev, + u8 port_num) +{ + struct mlx4_cmd_mailbox *mailbox; + int err; + struct mlx4_dev *dev = ibdev->dev; + int i; + union ib_gid *gid_tbl; + + mailbox = mlx4_alloc_cmd_mailbox(dev); + if (IS_ERR(mailbox)) + return -ENOMEM; + + gid_tbl = mailbox->buf; + + for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i) + memcpy(&gid_tbl[i], &gids[i].gid, sizeof(union ib_gid)); + + err = mlx4_cmd(dev, mailbox->dma, + MLX4_SET_PORT_GID_TABLE << 8 | port_num, + 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); + if (mlx4_is_bonded(dev)) + err += mlx4_cmd(dev, mailbox->dma, + MLX4_SET_PORT_GID_TABLE << 8 | 2, + 1, MLX4_CMD_SET_PORT, MLX4_CMD_TIME_CLASS_B, + MLX4_CMD_WRAPPED); + + mlx4_free_cmd_mailbox(dev, mailbox); + return err; +} + +static int mlx4_ib_add_gid(struct ib_device *device, + u8 port_num, + unsigned int index, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + void **context) +{ + struct mlx4_ib_dev *ibdev = to_mdev(device); + struct mlx4_ib_iboe *iboe = &ibdev->iboe; + struct mlx4_port_gid_table *port_gid_table; + int free = -1, found = -1; + int ret = 0; + int hw_update = 0; + int i; + struct gid_entry *gids = NULL; + + if (!rdma_cap_roce_gid_table(device, port_num)) + return -EINVAL; + + if (port_num > MLX4_MAX_PORTS) + return -EINVAL; + + if (!context) + return -EINVAL; + + port_gid_table = &iboe->gids[port_num - 1]; + spin_lock_bh(&iboe->lock); + for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i) { + if (!memcmp(&port_gid_table->gids[i].gid, gid, sizeof(*gid))) { + found = i; + break; + } + if (free < 0 && !memcmp(&port_gid_table->gids[i].gid, &zgid, sizeof(*gid))) + free = i; /* HW has space */ + } + + if (found < 0) { + if (free < 0) { + ret = -ENOSPC; + } else { + port_gid_table->gids[free].ctx = kmalloc(sizeof(*port_gid_table->gids[free].ctx), GFP_ATOMIC); + if (!port_gid_table->gids[free].ctx) { + ret = -ENOMEM; + } else { + *context = port_gid_table->gids[free].ctx; + memcpy(&port_gid_table->gids[free].gid, gid, sizeof(*gid)); + port_gid_table->gids[free].ctx->real_index = free; + port_gid_table->gids[free].ctx->refcount = 1; + hw_update = 1; + } + } + } else { + struct gid_cache_context *ctx = port_gid_table->gids[found].ctx; + *context = ctx; + ctx->refcount++; + } + if (!ret && hw_update) { + gids = kmalloc(sizeof(*gids) * MLX4_MAX_PORT_GIDS, GFP_ATOMIC); + if (!gids) { + ret = -ENOMEM; + } else { + for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) + memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); + } + } + spin_unlock_bh(&iboe->lock); + + if (!ret && hw_update) { + ret = mlx4_ib_update_gids(gids, ibdev, port_num); + kfree(gids); + } + + return ret; +} + +static int mlx4_ib_del_gid(struct ib_device *device, + u8 port_num, + unsigned int index, + void **context) +{ + struct gid_cache_context *ctx = *context; + struct mlx4_ib_dev *ibdev = to_mdev(device); + struct mlx4_ib_iboe *iboe = &ibdev->iboe; + struct mlx4_port_gid_table *port_gid_table; + int ret = 0; + int hw_update = 0; + struct gid_entry *gids = NULL; + + if (!rdma_cap_roce_gid_table(device, port_num)) + return -EINVAL; + + if (port_num > MLX4_MAX_PORTS) + return -EINVAL; + + port_gid_table = &iboe->gids[port_num - 1]; + spin_lock_bh(&iboe->lock); + if (ctx) { + ctx->refcount--; + if (!ctx->refcount) { + unsigned int real_index = ctx->real_index; + + memcpy(&port_gid_table->gids[real_index].gid, &zgid, sizeof(zgid)); + kfree(port_gid_table->gids[real_index].ctx); + port_gid_table->gids[real_index].ctx = NULL; + hw_update = 1; + } + } + if (!ret && hw_update) { + int i; + + gids = kmalloc(sizeof(*gids) * MLX4_MAX_PORT_GIDS, GFP_ATOMIC); + if (!gids) { + ret = -ENOMEM; + } else { + for (i = 0; i < MLX4_MAX_PORT_GIDS; i++) + memcpy(&gids[i].gid, &port_gid_table->gids[i].gid, sizeof(union ib_gid)); + } + } + spin_unlock_bh(&iboe->lock); + + if (!ret && hw_update) { + ret = mlx4_ib_update_gids(gids, ibdev, port_num); + kfree(gids); + } + return ret; +} + +int mlx4_ib_gid_index_to_real_index(struct mlx4_ib_dev *ibdev, + u8 port_num, int index) +{ + struct mlx4_ib_iboe *iboe = &ibdev->iboe; + struct gid_cache_context *ctx = NULL; + union ib_gid gid; + struct mlx4_port_gid_table *port_gid_table; + int real_index = -EINVAL; + int i; + int ret; + unsigned long flags; + + if (port_num > MLX4_MAX_PORTS) + return -EINVAL; + + if (mlx4_is_bonded(ibdev->dev)) + port_num = 1; + + if (!rdma_cap_roce_gid_table(&ibdev->ib_dev, port_num)) + return index; + + ret = ib_get_cached_gid(&ibdev->ib_dev, port_num, index, &gid); + if (ret) + return ret; + + if (!memcmp(&gid, &zgid, sizeof(gid))) + return -EINVAL; + + spin_lock_irqsave(&iboe->lock, flags); + port_gid_table = &iboe->gids[port_num - 1]; + + for (i = 0; i < MLX4_MAX_PORT_GIDS; ++i) + if (!memcmp(&port_gid_table->gids[i].gid, &gid, sizeof(gid))) { + ctx = port_gid_table->gids[i].ctx; + break; + } + if (ctx) + real_index = ctx->real_index; + spin_unlock_irqrestore(&iboe->lock, flags); + return real_index; +} + static int mlx4_ib_query_device(struct ib_device *ibdev, struct ib_device_attr *props, struct ib_udata *uhw) diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 3b85f0475a254..87a720f10f50a 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -457,6 +457,20 @@ struct mlx4_ib_sriov { struct idr pv_id_table; }; +struct gid_cache_context { + int real_index; + int refcount; +}; + +struct gid_entry { + union ib_gid gid; + struct gid_cache_context *ctx; +}; + +struct mlx4_port_gid_table { + struct gid_entry gids[MLX4_MAX_PORT_GIDS]; +}; + struct mlx4_ib_iboe { spinlock_t lock; struct net_device *netdevs[MLX4_MAX_PORTS]; @@ -466,6 +480,7 @@ struct mlx4_ib_iboe { struct notifier_block nb_inet; struct notifier_block nb_inet6; union ib_gid gid_table[MLX4_MAX_PORTS][128]; + struct mlx4_port_gid_table gids[MLX4_MAX_PORTS]; }; struct pkey_mgt { @@ -839,5 +854,7 @@ int mlx4_ib_rereg_user_mr(struct ib_mr *mr, int flags, u64 start, u64 length, u64 virt_addr, int mr_access_flags, struct ib_pd *pd, struct ib_udata *udata); +int mlx4_ib_gid_index_to_real_index(struct mlx4_ib_dev *ibdev, + u8 port_num, int index); #endif /* MLX4_IB_H */ diff --git a/include/linux/mlx4/device.h b/include/linux/mlx4/device.h index fd13c1ce3b4ab..5c7687a657173 100644 --- a/include/linux/mlx4/device.h +++ b/include/linux/mlx4/device.h @@ -79,7 +79,8 @@ enum { enum { MLX4_MAX_PORTS = 2, - MLX4_MAX_PORT_PKEYS = 128 + MLX4_MAX_PORT_PKEYS = 128, + MLX4_MAX_PORT_GIDS = 128 }; /* base qkey for use in sriov tunnel-qp/proxy-qp communication. diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 2de56834a6bef..5eff55c8b39df 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -65,6 +65,8 @@ union ib_gid { } global; }; +extern union ib_gid zgid; + struct ib_gid_attr { struct net_device *ndev; }; -- GitLab From 5070cd2239bd4b382c55c212f10b845ec2de31fc Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 30 Jul 2015 18:33:30 +0300 Subject: [PATCH 5787/7006] IB/mlx4: Replace mechanism for RoCE GID management Manage RoCE gid table with logic in IB/core, which is common to all vendors, and remove the mechanism from the mlx4 IB driver. Since management of the GID cache may lead to index mismatch with the hardware GID table, a translation between indexes is required when modifying a QP or creating an address handle. Signed-off-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/ah.c | 2 +- drivers/infiniband/hw/mlx4/main.c | 513 ++------------------------- drivers/infiniband/hw/mlx4/mlx4_ib.h | 4 - drivers/infiniband/hw/mlx4/qp.c | 10 +- 4 files changed, 35 insertions(+), 494 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index f50a546224adf..7ad6f9679c40f 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c @@ -89,7 +89,7 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr if (vlan_tag < 0x1000) vlan_tag |= (ah_attr->sl & 7) << 13; ah->av.eth.port_pd = cpu_to_be32(to_mpd(pd)->pdn | (ah_attr->port_num << 24)); - ah->av.eth.gid_index = ah_attr->grh.sgid_index; + ah->av.eth.gid_index = mlx4_ib_gid_index_to_real_index(ibdev, ah_attr->port_num, ah_attr->grh.sgid_index); ah->av.eth.vlan = cpu_to_be16(vlan_tag); if (ah_attr->static_rate) { ah->av.eth.stat_rate = ah_attr->static_rate + MLX4_STAT_RATE_OFFSET; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 5286ea7bb04af..1437ed5d5a8f8 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -77,13 +77,6 @@ static const char mlx4_ib_version[] = DRV_NAME ": Mellanox ConnectX InfiniBand driver v" DRV_VERSION " (" DRV_RELDATE ")\n"; -struct update_gid_work { - struct work_struct work; - union ib_gid gids[128]; - struct mlx4_ib_dev *dev; - int port; -}; - static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init); static struct workqueue_struct *wq; @@ -647,12 +640,13 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, props->state = IB_PORT_DOWN; props->phys_state = state_to_phys_state(props->state); props->active_mtu = IB_MTU_256; - if (is_bonded) - rtnl_lock(); /* required to get upper dev */ spin_lock_bh(&iboe->lock); ndev = iboe->netdevs[port - 1]; - if (ndev && is_bonded) - ndev = netdev_master_upper_dev_get(ndev); + if (ndev && is_bonded) { + rcu_read_lock(); /* required to get upper dev */ + ndev = netdev_master_upper_dev_get_rcu(ndev); + rcu_read_unlock(); + } if (!ndev) goto out_unlock; @@ -664,8 +658,6 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, props->phys_state = state_to_phys_state(props->state); out_unlock: spin_unlock_bh(&iboe->lock); - if (is_bonded) - rtnl_unlock(); out: mlx4_free_cmd_mailbox(mdev->dev, mailbox); return err; @@ -748,23 +740,27 @@ out: return err; } -static int iboe_query_gid(struct ib_device *ibdev, u8 port, int index, - union ib_gid *gid) -{ - struct mlx4_ib_dev *dev = to_mdev(ibdev); - - *gid = dev->iboe.gid_table[port - 1][index]; - - return 0; -} - static int mlx4_ib_query_gid(struct ib_device *ibdev, u8 port, int index, union ib_gid *gid) { - if (rdma_port_get_link_layer(ibdev, port) == IB_LINK_LAYER_INFINIBAND) + int ret; + + if (rdma_protocol_ib(ibdev, port)) return __mlx4_ib_query_gid(ibdev, port, index, gid, 0); - else - return iboe_query_gid(ibdev, port, index, gid); + + if (!rdma_protocol_roce(ibdev, port)) + return -ENODEV; + + if (!rdma_cap_roce_gid_table(ibdev, port)) + return -ENODEV; + + ret = ib_get_cached_gid(ibdev, port, index, gid); + if (ret == -EAGAIN) { + memcpy(gid, &zgid, sizeof(*gid)); + return 0; + } + + return ret; } int __mlx4_ib_query_pkey(struct ib_device *ibdev, u8 port, u16 index, @@ -1780,272 +1776,6 @@ static struct device_attribute *mlx4_class_attributes[] = { &dev_attr_board_id }; -static void mlx4_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, - struct net_device *dev) -{ - memcpy(eui, dev->dev_addr, 3); - memcpy(eui + 5, dev->dev_addr + 3, 3); - if (vlan_id < 0x1000) { - eui[3] = vlan_id >> 8; - eui[4] = vlan_id & 0xff; - } else { - eui[3] = 0xff; - eui[4] = 0xfe; - } - eui[0] ^= 2; -} - -static void update_gids_task(struct work_struct *work) -{ - struct update_gid_work *gw = container_of(work, struct update_gid_work, work); - struct mlx4_cmd_mailbox *mailbox; - union ib_gid *gids; - int err; - struct mlx4_dev *dev = gw->dev->dev; - int is_bonded = mlx4_is_bonded(dev); - - if (!gw->dev->ib_active) - return; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - pr_warn("update gid table failed %ld\n", PTR_ERR(mailbox)); - return; - } - - gids = mailbox->buf; - memcpy(gids, gw->gids, sizeof gw->gids); - - err = mlx4_cmd(dev, mailbox->dma, MLX4_SET_PORT_GID_TABLE << 8 | gw->port, - MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, MLX4_CMD_WRAPPED); - if (err) - pr_warn("set port command failed\n"); - else - if ((gw->port == 1) || !is_bonded) - mlx4_ib_dispatch_event(gw->dev, - is_bonded ? 1 : gw->port, - IB_EVENT_GID_CHANGE); - - mlx4_free_cmd_mailbox(dev, mailbox); - kfree(gw); -} - -static void reset_gids_task(struct work_struct *work) -{ - struct update_gid_work *gw = - container_of(work, struct update_gid_work, work); - struct mlx4_cmd_mailbox *mailbox; - union ib_gid *gids; - int err; - struct mlx4_dev *dev = gw->dev->dev; - - if (!gw->dev->ib_active) - return; - - mailbox = mlx4_alloc_cmd_mailbox(dev); - if (IS_ERR(mailbox)) { - pr_warn("reset gid table failed\n"); - goto free; - } - - gids = mailbox->buf; - memcpy(gids, gw->gids, sizeof(gw->gids)); - - if (mlx4_ib_port_link_layer(&gw->dev->ib_dev, gw->port) == - IB_LINK_LAYER_ETHERNET) { - err = mlx4_cmd(dev, mailbox->dma, - MLX4_SET_PORT_GID_TABLE << 8 | gw->port, - MLX4_SET_PORT_ETH_OPCODE, MLX4_CMD_SET_PORT, - MLX4_CMD_TIME_CLASS_B, - MLX4_CMD_WRAPPED); - if (err) - pr_warn("set port %d command failed\n", gw->port); - } - - mlx4_free_cmd_mailbox(dev, mailbox); -free: - kfree(gw); -} - -static int update_gid_table(struct mlx4_ib_dev *dev, int port, - union ib_gid *gid, int clear, - int default_gid) -{ - struct update_gid_work *work; - int i; - int need_update = 0; - int free = -1; - int found = -1; - int max_gids; - - if (default_gid) { - free = 0; - } else { - max_gids = dev->dev->caps.gid_table_len[port]; - for (i = 1; i < max_gids; ++i) { - if (!memcmp(&dev->iboe.gid_table[port - 1][i], gid, - sizeof(*gid))) - found = i; - - if (clear) { - if (found >= 0) { - need_update = 1; - dev->iboe.gid_table[port - 1][found] = - zgid; - break; - } - } else { - if (found >= 0) - break; - - if (free < 0 && - !memcmp(&dev->iboe.gid_table[port - 1][i], - &zgid, sizeof(*gid))) - free = i; - } - } - } - - if (found == -1 && !clear && free >= 0) { - dev->iboe.gid_table[port - 1][free] = *gid; - need_update = 1; - } - - if (!need_update) - return 0; - - work = kzalloc(sizeof(*work), GFP_ATOMIC); - if (!work) - return -ENOMEM; - - memcpy(work->gids, dev->iboe.gid_table[port - 1], sizeof(work->gids)); - INIT_WORK(&work->work, update_gids_task); - work->port = port; - work->dev = dev; - queue_work(wq, &work->work); - - return 0; -} - -static void mlx4_make_default_gid(struct net_device *dev, union ib_gid *gid) -{ - gid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); - mlx4_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev); -} - - -static int reset_gid_table(struct mlx4_ib_dev *dev, u8 port) -{ - struct update_gid_work *work; - - work = kzalloc(sizeof(*work), GFP_ATOMIC); - if (!work) - return -ENOMEM; - - memset(dev->iboe.gid_table[port - 1], 0, sizeof(work->gids)); - memset(work->gids, 0, sizeof(work->gids)); - INIT_WORK(&work->work, reset_gids_task); - work->dev = dev; - work->port = port; - queue_work(wq, &work->work); - return 0; -} - -static int mlx4_ib_addr_event(int event, struct net_device *event_netdev, - struct mlx4_ib_dev *ibdev, union ib_gid *gid) -{ - struct mlx4_ib_iboe *iboe; - int port = 0; - struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ? - rdma_vlan_dev_real_dev(event_netdev) : - event_netdev; - union ib_gid default_gid; - - mlx4_make_default_gid(real_dev, &default_gid); - - if (!memcmp(gid, &default_gid, sizeof(*gid))) - return 0; - - if (event != NETDEV_DOWN && event != NETDEV_UP) - return 0; - - if ((real_dev != event_netdev) && - (event == NETDEV_DOWN) && - rdma_link_local_addr((struct in6_addr *)gid)) - return 0; - - iboe = &ibdev->iboe; - spin_lock_bh(&iboe->lock); - - for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) - if ((netif_is_bond_master(real_dev) && - (real_dev == iboe->masters[port - 1])) || - (!netif_is_bond_master(real_dev) && - (real_dev == iboe->netdevs[port - 1]))) - update_gid_table(ibdev, port, gid, - event == NETDEV_DOWN, 0); - - spin_unlock_bh(&iboe->lock); - return 0; - -} - -static u8 mlx4_ib_get_dev_port(struct net_device *dev, - struct mlx4_ib_dev *ibdev) -{ - u8 port = 0; - struct mlx4_ib_iboe *iboe; - struct net_device *real_dev = rdma_vlan_dev_real_dev(dev) ? - rdma_vlan_dev_real_dev(dev) : dev; - - iboe = &ibdev->iboe; - - for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) - if ((netif_is_bond_master(real_dev) && - (real_dev == iboe->masters[port - 1])) || - (!netif_is_bond_master(real_dev) && - (real_dev == iboe->netdevs[port - 1]))) - break; - - if ((port == 0) || (port > ibdev->dev->caps.num_ports)) - return 0; - else - return port; -} - -static int mlx4_ib_inet_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct mlx4_ib_dev *ibdev; - struct in_ifaddr *ifa = ptr; - union ib_gid gid; - struct net_device *event_netdev = ifa->ifa_dev->dev; - - ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid); - - ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb_inet); - - mlx4_ib_addr_event(event, event_netdev, ibdev, &gid); - return NOTIFY_DONE; -} - -#if IS_ENABLED(CONFIG_IPV6) -static int mlx4_ib_inet6_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct mlx4_ib_dev *ibdev; - struct inet6_ifaddr *ifa = ptr; - union ib_gid *gid = (union ib_gid *)&ifa->addr; - struct net_device *event_netdev = ifa->idev->dev; - - ibdev = container_of(this, struct mlx4_ib_dev, iboe.nb_inet6); - - mlx4_ib_addr_event(event, event_netdev, ibdev, gid); - return NOTIFY_DONE; -} -#endif - #define MLX4_IB_INVALID_MAC ((u64)-1) static void mlx4_ib_update_qps(struct mlx4_ib_dev *ibdev, struct net_device *dev, @@ -2104,94 +1834,6 @@ unlock: mutex_unlock(&ibdev->qp1_proxy_lock[port - 1]); } -static void mlx4_ib_get_dev_addr(struct net_device *dev, - struct mlx4_ib_dev *ibdev, u8 port) -{ - struct in_device *in_dev; -#if IS_ENABLED(CONFIG_IPV6) - struct inet6_dev *in6_dev; - union ib_gid *pgid; - struct inet6_ifaddr *ifp; - union ib_gid default_gid; -#endif - union ib_gid gid; - - - if ((port == 0) || (port > ibdev->dev->caps.num_ports)) - return; - - /* IPv4 gids */ - in_dev = in_dev_get(dev); - if (in_dev) { - for_ifa(in_dev) { - /*ifa->ifa_address;*/ - ipv6_addr_set_v4mapped(ifa->ifa_address, - (struct in6_addr *)&gid); - update_gid_table(ibdev, port, &gid, 0, 0); - } - endfor_ifa(in_dev); - in_dev_put(in_dev); - } -#if IS_ENABLED(CONFIG_IPV6) - mlx4_make_default_gid(dev, &default_gid); - /* IPv6 gids */ - in6_dev = in6_dev_get(dev); - if (in6_dev) { - read_lock_bh(&in6_dev->lock); - list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { - pgid = (union ib_gid *)&ifp->addr; - if (!memcmp(pgid, &default_gid, sizeof(*pgid))) - continue; - update_gid_table(ibdev, port, pgid, 0, 0); - } - read_unlock_bh(&in6_dev->lock); - in6_dev_put(in6_dev); - } -#endif -} - -static void mlx4_ib_set_default_gid(struct mlx4_ib_dev *ibdev, - struct net_device *dev, u8 port) -{ - union ib_gid gid; - mlx4_make_default_gid(dev, &gid); - update_gid_table(ibdev, port, &gid, 0, 1); -} - -static int mlx4_ib_init_gid_table(struct mlx4_ib_dev *ibdev) -{ - struct net_device *dev; - struct mlx4_ib_iboe *iboe = &ibdev->iboe; - int i; - int err = 0; - - for (i = 1; i <= ibdev->num_ports; ++i) { - if (rdma_port_get_link_layer(&ibdev->ib_dev, i) == - IB_LINK_LAYER_ETHERNET) { - err = reset_gid_table(ibdev, i); - if (err) - goto out; - } - } - - read_lock(&dev_base_lock); - spin_lock_bh(&iboe->lock); - - for_each_netdev(&init_net, dev) { - u8 port = mlx4_ib_get_dev_port(dev, ibdev); - /* port will be non-zero only for ETH ports */ - if (port) { - mlx4_ib_set_default_gid(ibdev, dev, port); - mlx4_ib_get_dev_addr(dev, ibdev, port); - } - } - - spin_unlock_bh(&iboe->lock); - read_unlock(&dev_base_lock); -out: - return err; -} - static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev, struct net_device *dev, unsigned long event) @@ -2201,81 +1843,22 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev, int update_qps_port = -1; int port; + ASSERT_RTNL(); + iboe = &ibdev->iboe; spin_lock_bh(&iboe->lock); mlx4_foreach_ib_transport_port(port, ibdev->dev) { - enum ib_port_state port_state = IB_PORT_NOP; - struct net_device *old_master = iboe->masters[port - 1]; - struct net_device *curr_netdev; - struct net_device *curr_master; iboe->netdevs[port - 1] = mlx4_get_protocol_dev(ibdev->dev, MLX4_PROT_ETH, port); - if (iboe->netdevs[port - 1]) - mlx4_ib_set_default_gid(ibdev, - iboe->netdevs[port - 1], port); - curr_netdev = iboe->netdevs[port - 1]; - - if (iboe->netdevs[port - 1] && - netif_is_bond_slave(iboe->netdevs[port - 1])) { - iboe->masters[port - 1] = netdev_master_upper_dev_get( - iboe->netdevs[port - 1]); - } else { - iboe->masters[port - 1] = NULL; - } - curr_master = iboe->masters[port - 1]; if (dev == iboe->netdevs[port - 1] && (event == NETDEV_CHANGEADDR || event == NETDEV_REGISTER || event == NETDEV_UP || event == NETDEV_CHANGE)) update_qps_port = port; - if (curr_netdev) { - port_state = (netif_running(curr_netdev) && netif_carrier_ok(curr_netdev)) ? - IB_PORT_ACTIVE : IB_PORT_DOWN; - mlx4_ib_set_default_gid(ibdev, curr_netdev, port); - if (curr_master) { - /* if using bonding/team and a slave port is down, we - * don't want the bond IP based gids in the table since - * flows that select port by gid may get the down port. - */ - if (port_state == IB_PORT_DOWN && - !mlx4_is_bonded(ibdev->dev)) { - reset_gid_table(ibdev, port); - mlx4_ib_set_default_gid(ibdev, - curr_netdev, - port); - } else { - /* gids from the upper dev (bond/team) - * should appear in port's gid table - */ - mlx4_ib_get_dev_addr(curr_master, - ibdev, port); - } - } - /* if bonding is used it is possible that we add it to - * masters only after IP address is assigned to the - * net bonding interface. - */ - if (curr_master && (old_master != curr_master)) { - reset_gid_table(ibdev, port); - mlx4_ib_set_default_gid(ibdev, - curr_netdev, port); - mlx4_ib_get_dev_addr(curr_master, ibdev, port); - } - - if (!curr_master && (old_master != curr_master)) { - reset_gid_table(ibdev, port); - mlx4_ib_set_default_gid(ibdev, - curr_netdev, port); - mlx4_ib_get_dev_addr(curr_netdev, ibdev, port); - } - } else { - reset_gid_table(ibdev, port); - } } - spin_unlock_bh(&iboe->lock); if (update_qps_port > 0) @@ -2458,6 +2041,9 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) 1 : ibdev->num_ports; ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors; ibdev->ib_dev.dma_device = &dev->persist->pdev->dev; + ibdev->ib_dev.get_netdev = mlx4_ib_get_netdev; + ibdev->ib_dev.add_gid = mlx4_ib_add_gid; + ibdev->ib_dev.del_gid = mlx4_ib_del_gid; if (dev->caps.userspace_caps) ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION; @@ -2668,26 +2254,6 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_notif; } } - if (!iboe->nb_inet.notifier_call) { - iboe->nb_inet.notifier_call = mlx4_ib_inet_event; - err = register_inetaddr_notifier(&iboe->nb_inet); - if (err) { - iboe->nb_inet.notifier_call = NULL; - goto err_notif; - } - } -#if IS_ENABLED(CONFIG_IPV6) - if (!iboe->nb_inet6.notifier_call) { - iboe->nb_inet6.notifier_call = mlx4_ib_inet6_event; - err = register_inet6addr_notifier(&iboe->nb_inet6); - if (err) { - iboe->nb_inet6.notifier_call = NULL; - goto err_notif; - } - } -#endif - if (mlx4_ib_init_gid_table(ibdev)) - goto err_notif; } for (j = 0; j < ARRAY_SIZE(mlx4_class_attributes); ++j) { @@ -2718,18 +2284,6 @@ err_notif: pr_warn("failure unregistering notifier\n"); ibdev->iboe.nb.notifier_call = NULL; } - if (ibdev->iboe.nb_inet.notifier_call) { - if (unregister_inetaddr_notifier(&ibdev->iboe.nb_inet)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb_inet.notifier_call = NULL; - } -#if IS_ENABLED(CONFIG_IPV6) - if (ibdev->iboe.nb_inet6.notifier_call) { - if (unregister_inet6addr_notifier(&ibdev->iboe.nb_inet6)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb_inet6.notifier_call = NULL; - } -#endif flush_workqueue(wq); mlx4_ib_close_sriov(ibdev); @@ -2855,19 +2409,6 @@ static void mlx4_ib_remove(struct mlx4_dev *dev, void *ibdev_ptr) kfree(ibdev->ib_uc_qpns_bitmap); } - if (ibdev->iboe.nb_inet.notifier_call) { - if (unregister_inetaddr_notifier(&ibdev->iboe.nb_inet)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb_inet.notifier_call = NULL; - } -#if IS_ENABLED(CONFIG_IPV6) - if (ibdev->iboe.nb_inet6.notifier_call) { - if (unregister_inet6addr_notifier(&ibdev->iboe.nb_inet6)) - pr_warn("failure unregistering notifier\n"); - ibdev->iboe.nb_inet6.notifier_call = NULL; - } -#endif - iounmap(ibdev->uar_map); for (p = 0; p < ibdev->num_ports; ++p) if (ibdev->counters[p].index != -1 && diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 87a720f10f50a..cb47c2cb84ca4 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -474,12 +474,8 @@ struct mlx4_port_gid_table { struct mlx4_ib_iboe { spinlock_t lock; struct net_device *netdevs[MLX4_MAX_PORTS]; - struct net_device *masters[MLX4_MAX_PORTS]; atomic64_t mac[MLX4_MAX_PORTS]; struct notifier_block nb; - struct notifier_block nb_inet; - struct notifier_block nb_inet6; - union ib_gid gid_table[MLX4_MAX_PORTS][128]; struct mlx4_port_gid_table gids[MLX4_MAX_PORTS]; }; diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index c5a3a5f0de41f..4ad9be3ad61c0 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1292,14 +1292,18 @@ static int _mlx4_set_path(struct mlx4_ib_dev *dev, const struct ib_ah_attr *ah, path->static_rate = 0; if (ah->ah_flags & IB_AH_GRH) { - if (ah->grh.sgid_index >= dev->dev->caps.gid_table_len[port]) { + int real_sgid_index = mlx4_ib_gid_index_to_real_index(dev, + port, + ah->grh.sgid_index); + + if (real_sgid_index >= dev->dev->caps.gid_table_len[port]) { pr_err("sgid_index (%u) too large. max is %d\n", - ah->grh.sgid_index, dev->dev->caps.gid_table_len[port] - 1); + real_sgid_index, dev->dev->caps.gid_table_len[port] - 1); return -1; } path->grh_mylmc |= 1 << 7; - path->mgid_index = ah->grh.sgid_index; + path->mgid_index = real_sgid_index; path->hop_limit = ah->grh.hop_limit; path->tclass_flowlabel = cpu_to_be32((ah->grh.traffic_class << 20) | -- GitLab From cc36929e736a30a291ab543b633046eb57d67e68 Mon Sep 17 00:00:00 2001 From: Somnath Kotur Date: Thu, 30 Jul 2015 18:33:31 +0300 Subject: [PATCH 5788/7006] RDMA/ocrdma: Incorporate the moving of GID Table mgmt to IB/Core 1.Change query_gid hook to return value from IB/Core GID management APIs. 2.Get rid of all the netdev notifier chain subscription code as well as maintenance of SGID Table in memory. 3.Implement get_netdev hook in driver. Signed-off-by: Somnath Kotur Signed-off-by: Devesh Sharma Signed-off-by: Doug Ledford --- drivers/infiniband/hw/ocrdma/ocrdma.h | 1 - drivers/infiniband/hw/ocrdma/ocrdma_main.c | 234 +------------------- drivers/infiniband/hw/ocrdma/ocrdma_sli.h | 2 + drivers/infiniband/hw/ocrdma/ocrdma_verbs.c | 45 +++- drivers/infiniband/hw/ocrdma/ocrdma_verbs.h | 11 + 5 files changed, 60 insertions(+), 233 deletions(-) diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h index 6a36338593cd0..b4091ab48db0b 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma.h @@ -246,7 +246,6 @@ struct ocrdma_dev { u16 base_eqid; u16 max_eq; - union ib_gid *sgid_tbl; /* provided synchronization to sgid table for * updating gid entries triggered by notifier. */ diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c index 81ed8a342f4d6..87aa55df7c821 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c @@ -67,8 +67,6 @@ static LIST_HEAD(ocrdma_dev_list); static DEFINE_SPINLOCK(ocrdma_devlist_lock); static DEFINE_IDR(ocrdma_dev_id); -static union ib_gid ocrdma_zero_sgid; - void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid) { u8 mac_addr[6]; @@ -83,135 +81,6 @@ void ocrdma_get_guid(struct ocrdma_dev *dev, u8 *guid) guid[6] = mac_addr[4]; guid[7] = mac_addr[5]; } - -static bool ocrdma_add_sgid(struct ocrdma_dev *dev, union ib_gid *new_sgid) -{ - int i; - unsigned long flags; - - memset(&ocrdma_zero_sgid, 0, sizeof(union ib_gid)); - - - spin_lock_irqsave(&dev->sgid_lock, flags); - for (i = 0; i < OCRDMA_MAX_SGID; i++) { - if (!memcmp(&dev->sgid_tbl[i], &ocrdma_zero_sgid, - sizeof(union ib_gid))) { - /* found free entry */ - memcpy(&dev->sgid_tbl[i], new_sgid, - sizeof(union ib_gid)); - spin_unlock_irqrestore(&dev->sgid_lock, flags); - return true; - } else if (!memcmp(&dev->sgid_tbl[i], new_sgid, - sizeof(union ib_gid))) { - /* entry already present, no addition is required. */ - spin_unlock_irqrestore(&dev->sgid_lock, flags); - return false; - } - } - spin_unlock_irqrestore(&dev->sgid_lock, flags); - return false; -} - -static bool ocrdma_del_sgid(struct ocrdma_dev *dev, union ib_gid *sgid) -{ - int found = false; - int i; - unsigned long flags; - - - spin_lock_irqsave(&dev->sgid_lock, flags); - /* first is default sgid, which cannot be deleted. */ - for (i = 1; i < OCRDMA_MAX_SGID; i++) { - if (!memcmp(&dev->sgid_tbl[i], sgid, sizeof(union ib_gid))) { - /* found matching entry */ - memset(&dev->sgid_tbl[i], 0, sizeof(union ib_gid)); - found = true; - break; - } - } - spin_unlock_irqrestore(&dev->sgid_lock, flags); - return found; -} - -static int ocrdma_addr_event(unsigned long event, struct net_device *netdev, - union ib_gid *gid) -{ - struct ib_event gid_event; - struct ocrdma_dev *dev; - bool found = false; - bool updated = false; - bool is_vlan = false; - - is_vlan = netdev->priv_flags & IFF_802_1Q_VLAN; - if (is_vlan) - netdev = rdma_vlan_dev_real_dev(netdev); - - rcu_read_lock(); - list_for_each_entry_rcu(dev, &ocrdma_dev_list, entry) { - if (dev->nic_info.netdev == netdev) { - found = true; - break; - } - } - rcu_read_unlock(); - - if (!found) - return NOTIFY_DONE; - - mutex_lock(&dev->dev_lock); - switch (event) { - case NETDEV_UP: - updated = ocrdma_add_sgid(dev, gid); - break; - case NETDEV_DOWN: - updated = ocrdma_del_sgid(dev, gid); - break; - default: - break; - } - if (updated) { - /* GID table updated, notify the consumers about it */ - gid_event.device = &dev->ibdev; - gid_event.element.port_num = 1; - gid_event.event = IB_EVENT_GID_CHANGE; - ib_dispatch_event(&gid_event); - } - mutex_unlock(&dev->dev_lock); - return NOTIFY_OK; -} - -static int ocrdma_inetaddr_event(struct notifier_block *notifier, - unsigned long event, void *ptr) -{ - struct in_ifaddr *ifa = ptr; - union ib_gid gid; - struct net_device *netdev = ifa->ifa_dev->dev; - - ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid); - return ocrdma_addr_event(event, netdev, &gid); -} - -static struct notifier_block ocrdma_inetaddr_notifier = { - .notifier_call = ocrdma_inetaddr_event -}; - -#if IS_ENABLED(CONFIG_IPV6) - -static int ocrdma_inet6addr_event(struct notifier_block *notifier, - unsigned long event, void *ptr) -{ - struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr; - union ib_gid *gid = (union ib_gid *)&ifa->addr; - struct net_device *netdev = ifa->idev->dev; - return ocrdma_addr_event(event, netdev, gid); -} - -static struct notifier_block ocrdma_inet6addr_notifier = { - .notifier_call = ocrdma_inet6addr_event -}; - -#endif /* IPV6 and VLAN */ - static enum rdma_link_layer ocrdma_link_layer(struct ib_device *device, u8 port_num) { @@ -280,6 +149,9 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) dev->ibdev.query_port = ocrdma_query_port; dev->ibdev.modify_port = ocrdma_modify_port; dev->ibdev.query_gid = ocrdma_query_gid; + dev->ibdev.get_netdev = ocrdma_get_netdev; + dev->ibdev.add_gid = ocrdma_add_gid; + dev->ibdev.del_gid = ocrdma_del_gid; dev->ibdev.get_link_layer = ocrdma_link_layer; dev->ibdev.alloc_pd = ocrdma_alloc_pd; dev->ibdev.dealloc_pd = ocrdma_dealloc_pd; @@ -342,12 +214,6 @@ static int ocrdma_register_device(struct ocrdma_dev *dev) static int ocrdma_alloc_resources(struct ocrdma_dev *dev) { mutex_init(&dev->dev_lock); - dev->sgid_tbl = kzalloc(sizeof(union ib_gid) * - OCRDMA_MAX_SGID, GFP_KERNEL); - if (!dev->sgid_tbl) - goto alloc_err; - spin_lock_init(&dev->sgid_lock); - dev->cq_tbl = kzalloc(sizeof(struct ocrdma_cq *) * OCRDMA_MAX_CQ, GFP_KERNEL); if (!dev->cq_tbl) @@ -379,7 +245,6 @@ static void ocrdma_free_resources(struct ocrdma_dev *dev) kfree(dev->stag_arr); kfree(dev->qp_tbl); kfree(dev->cq_tbl); - kfree(dev->sgid_tbl); } /* OCRDMA sysfs interface */ @@ -425,68 +290,6 @@ static void ocrdma_remove_sysfiles(struct ocrdma_dev *dev) device_remove_file(&dev->ibdev.dev, ocrdma_attributes[i]); } -static void ocrdma_add_default_sgid(struct ocrdma_dev *dev) -{ - /* GID Index 0 - Invariant manufacturer-assigned EUI-64 */ - union ib_gid *sgid = &dev->sgid_tbl[0]; - - sgid->global.subnet_prefix = cpu_to_be64(0xfe80000000000000LL); - ocrdma_get_guid(dev, &sgid->raw[8]); -} - -static void ocrdma_init_ipv4_gids(struct ocrdma_dev *dev, - struct net_device *net) -{ - struct in_device *in_dev; - union ib_gid gid; - in_dev = in_dev_get(net); - if (in_dev) { - for_ifa(in_dev) { - ipv6_addr_set_v4mapped(ifa->ifa_address, - (struct in6_addr *)&gid); - ocrdma_add_sgid(dev, &gid); - } - endfor_ifa(in_dev); - in_dev_put(in_dev); - } -} - -static void ocrdma_init_ipv6_gids(struct ocrdma_dev *dev, - struct net_device *net) -{ -#if IS_ENABLED(CONFIG_IPV6) - struct inet6_dev *in6_dev; - union ib_gid *pgid; - struct inet6_ifaddr *ifp; - in6_dev = in6_dev_get(net); - if (in6_dev) { - read_lock_bh(&in6_dev->lock); - list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { - pgid = (union ib_gid *)&ifp->addr; - ocrdma_add_sgid(dev, pgid); - } - read_unlock_bh(&in6_dev->lock); - in6_dev_put(in6_dev); - } -#endif -} - -static void ocrdma_init_gid_table(struct ocrdma_dev *dev) -{ - struct net_device *net_dev; - - for_each_netdev(&init_net, net_dev) { - struct net_device *real_dev = rdma_vlan_dev_real_dev(net_dev) ? - rdma_vlan_dev_real_dev(net_dev) : net_dev; - - if (real_dev == dev->nic_info.netdev) { - ocrdma_add_default_sgid(dev); - ocrdma_init_ipv4_gids(dev, net_dev); - ocrdma_init_ipv6_gids(dev, net_dev); - } - } -} - static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) { int status = 0, i; @@ -515,7 +318,6 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info) goto alloc_err; ocrdma_init_service_level(dev); - ocrdma_init_gid_table(dev); status = ocrdma_register_device(dev); if (status) goto alloc_err; @@ -662,34 +464,12 @@ static struct ocrdma_driver ocrdma_drv = { .be_abi_version = OCRDMA_BE_ROCE_ABI_VERSION, }; -static void ocrdma_unregister_inet6addr_notifier(void) -{ -#if IS_ENABLED(CONFIG_IPV6) - unregister_inet6addr_notifier(&ocrdma_inet6addr_notifier); -#endif -} - -static void ocrdma_unregister_inetaddr_notifier(void) -{ - unregister_inetaddr_notifier(&ocrdma_inetaddr_notifier); -} - static int __init ocrdma_init_module(void) { int status; ocrdma_init_debugfs(); - status = register_inetaddr_notifier(&ocrdma_inetaddr_notifier); - if (status) - return status; - -#if IS_ENABLED(CONFIG_IPV6) - status = register_inet6addr_notifier(&ocrdma_inet6addr_notifier); - if (status) - goto err_notifier6; -#endif - status = be_roce_register_driver(&ocrdma_drv); if (status) goto err_be_reg; @@ -697,19 +477,13 @@ static int __init ocrdma_init_module(void) return 0; err_be_reg: -#if IS_ENABLED(CONFIG_IPV6) - ocrdma_unregister_inet6addr_notifier(); -err_notifier6: -#endif - ocrdma_unregister_inetaddr_notifier(); + return status; } static void __exit ocrdma_exit_module(void) { be_roce_unregister_driver(&ocrdma_drv); - ocrdma_unregister_inet6addr_notifier(); - ocrdma_unregister_inetaddr_notifier(); ocrdma_rem_debugfs(); idr_destroy(&ocrdma_dev_id); } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h index 80006b24aa118..6a38268bbe9fb 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h @@ -140,6 +140,8 @@ enum { OCRDMA_DB_RQ_SHIFT = 24 }; +#define OCRDMA_ROUDP_FLAGS_SHIFT 0x03 + #define OCRDMA_DB_CQ_RING_ID_MASK 0x3FF /* bits 0 - 9 */ #define OCRDMA_DB_CQ_RING_ID_EXT_MASK 0x0C00 /* bits 10-11 of qid at 12-11 */ /* qid #2 msbits at 12-11 */ diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c index 8e5fb44090f70..1f3affb6a4771 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "ocrdma.h" #include "ocrdma_hw.h" @@ -64,6 +65,7 @@ int ocrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, u16 *pkey) int ocrdma_query_gid(struct ib_device *ibdev, u8 port, int index, union ib_gid *sgid) { + int ret; struct ocrdma_dev *dev; dev = get_ocrdma_dev(ibdev); @@ -71,8 +73,28 @@ int ocrdma_query_gid(struct ib_device *ibdev, u8 port, if (index >= OCRDMA_MAX_SGID) return -EINVAL; - memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid)); + ret = ib_get_cached_gid(ibdev, port, index, sgid); + if (ret == -EAGAIN) { + memcpy(sgid, &zgid, sizeof(*sgid)); + return 0; + } + + return ret; +} +int ocrdma_add_gid(struct ib_device *device, + u8 port_num, + unsigned int index, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + void **context) { + return 0; +} + +int ocrdma_del_gid(struct ib_device *device, + u8 port_num, + unsigned int index, + void **context) { return 0; } @@ -125,6 +147,24 @@ int ocrdma_query_device(struct ib_device *ibdev, struct ib_device_attr *attr, return 0; } +struct net_device *ocrdma_get_netdev(struct ib_device *ibdev, u8 port_num) +{ + struct ocrdma_dev *dev; + struct net_device *ndev = NULL; + + rcu_read_lock(); + + dev = get_ocrdma_dev(ibdev); + if (dev) + ndev = dev->nic_info.netdev; + if (ndev) + dev_hold(ndev); + + rcu_read_unlock(); + + return ndev; +} + static inline void get_link_speed_and_width(struct ocrdma_dev *dev, u8 *ib_speed, u8 *ib_width) { @@ -194,7 +234,8 @@ int ocrdma_query_port(struct ib_device *ibdev, props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_REINIT_SUP | - IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP | IB_PORT_IP_BASED_GIDS; + IB_PORT_DEVICE_MGMT_SUP | IB_PORT_VENDOR_CLASS_SUP | + IB_PORT_IP_BASED_GIDS; props->gid_tbl_len = OCRDMA_MAX_SGID; props->pkey_tbl_len = 1; props->bad_pkey_cntr = 0; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h index 68e026bb14d00..308c16857a5d0 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.h @@ -63,6 +63,17 @@ ocrdma_query_protocol(struct ib_device *device, u8 port_num); void ocrdma_get_guid(struct ocrdma_dev *, u8 *guid); int ocrdma_query_gid(struct ib_device *, u8 port, int index, union ib_gid *gid); +struct net_device *ocrdma_get_netdev(struct ib_device *device, u8 port_num); +int ocrdma_add_gid(struct ib_device *device, + u8 port_num, + unsigned int index, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + void **context); +int ocrdma_del_gid(struct ib_device *device, + u8 port_num, + unsigned int index, + void **context); int ocrdma_query_pkey(struct ib_device *, u8 port, u16 index, u16 *pkey); struct ib_ucontext *ocrdma_alloc_ucontext(struct ib_device *, -- GitLab From b8071ad893841aba967b7c54e712179864cdf5c3 Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Sat, 15 Aug 2015 10:16:14 -0400 Subject: [PATCH 5789/7006] IB/core: Remove needless bracketization Signed-off-by: Doug Ledford --- drivers/infiniband/core/device.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 7a4ee795c13e0..17639117afc6a 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -324,6 +324,7 @@ int ib_register_device(struct ib_device *device, u8, struct kobject *)) { int ret; + struct ib_client *client; mutex_lock(&device_mutex); @@ -361,13 +362,9 @@ int ib_register_device(struct ib_device *device, device->reg_state = IB_DEV_REGISTERED; - { - struct ib_client *client; - - list_for_each_entry(client, &client_list, list) - if (client->add && !add_client_context(device, client)) - client->add(device); - } + list_for_each_entry(client, &client_list, list) + if (client->add && !add_client_context(device, client)) + client->add(device); down_write(&lists_rwsem); list_add_tail(&device->core_list, &device_list); -- GitLab From 90c1d8b6350cca9d8a234f03c77a317a7613bcee Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 30 Jul 2015 17:34:21 +0300 Subject: [PATCH 5790/7006] IB/mlx4: Fix potential deadlock when sending mad to wire send_mad_to_wire takes the same spinlock that is taken in the interrupt context. Therefore, it needs irqsave/restore. Fixes: b9c5d6a64358 ('IB/mlx4: Add multicast group (MCG) paravirtualization for SR-IOV') Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mcg.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index ed327e6c8fdca..a0559a8af4f4d 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -206,15 +206,16 @@ static int send_mad_to_wire(struct mlx4_ib_demux_ctx *ctx, struct ib_mad *mad) { struct mlx4_ib_dev *dev = ctx->dev; struct ib_ah_attr ah_attr; + unsigned long flags; - spin_lock(&dev->sm_lock); + spin_lock_irqsave(&dev->sm_lock, flags); if (!dev->sm_ah[ctx->port - 1]) { /* port is not yet Active, sm_ah not ready */ - spin_unlock(&dev->sm_lock); + spin_unlock_irqrestore(&dev->sm_lock, flags); return -EAGAIN; } mlx4_ib_query_ah(dev->sm_ah[ctx->port - 1], &ah_attr); - spin_unlock(&dev->sm_lock); + spin_unlock_irqrestore(&dev->sm_lock, flags); return mlx4_ib_send_to_wire(dev, mlx4_master_func_num(dev->dev), ctx->port, IB_QPT_GSI, 0, 1, IB_QP1_QKEY, &ah_attr, NULL, mad); -- GitLab From 2cb8e7f86e8cabd1e8aa608fc2a44e5bfa1d81ca Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 30 Jul 2015 17:34:22 +0300 Subject: [PATCH 5791/7006] IB/mlx4: Demote mcg message from warning to debug The mcg "too many pending requests" warning message fills the log when OpenSM is downed. Demote the message from warning level to debug level. Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mcg.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index a0559a8af4f4d..2d5bccd71fc66 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -51,6 +51,10 @@ pr_warn("%s-%d: %16s (port %d): WARNING: " format, __func__, __LINE__,\ (group)->name, group->demux->port, ## arg) +#define mcg_debug_group(group, format, arg...) \ + pr_debug("%s-%d: %16s (port %d): WARNING: " format, __func__, __LINE__,\ + (group)->name, (group)->demux->port, ## arg) + #define mcg_error_group(group, format, arg...) \ pr_err(" %16s: " format, (group)->name, ## arg) @@ -962,8 +966,8 @@ int mlx4_ib_mcg_multiplex_handler(struct ib_device *ibdev, int port, mutex_lock(&group->lock); if (group->func[slave].num_pend_reqs > MAX_PEND_REQS_PER_FUNC) { mutex_unlock(&group->lock); - mcg_warn_group(group, "Port %d, Func %d has too many pending requests (%d), dropping\n", - port, slave, MAX_PEND_REQS_PER_FUNC); + mcg_debug_group(group, "Port %d, Func %d has too many pending requests (%d), dropping\n", + port, slave, MAX_PEND_REQS_PER_FUNC); release_group(group, 0); kfree(req); return -ENOMEM; -- GitLab From 2b135db3e81301d0452e6aa107349abe67b097d6 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 30 Jul 2015 17:34:23 +0300 Subject: [PATCH 5792/7006] IB/mlx4: Forbid using sysfs to change RoCE pkeys The pkey mapping for RoCE must remain the default mapping: VFs: virtual index 0 = mapped to real index 0 (0xFFFF) All others indices: mapped to a real pkey index containing an invalid pkey. PF: virtual index i = real index i. Don't allow users to change these mappings using files found in sysfs. Fixes: c1e7e466120b ('IB/mlx4: Add iov directory in sysfs under the ib device') Signed-off-by: Jack Morgenstein Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/sysfs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c index 6797108ce8735..69fb5ba94d0f2 100644 --- a/drivers/infiniband/hw/mlx4/sysfs.c +++ b/drivers/infiniband/hw/mlx4/sysfs.c @@ -640,6 +640,8 @@ static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) struct mlx4_port *p; int i; int ret; + int is_eth = rdma_port_get_link_layer(&dev->ib_dev, port_num) == + IB_LINK_LAYER_ETHERNET; p = kzalloc(sizeof *p, GFP_KERNEL); if (!p) @@ -657,7 +659,8 @@ static int add_port(struct mlx4_ib_dev *dev, int port_num, int slave) p->pkey_group.name = "pkey_idx"; p->pkey_group.attrs = - alloc_group_attrs(show_port_pkey, store_port_pkey, + alloc_group_attrs(show_port_pkey, + is_eth ? NULL : store_port_pkey, dev->dev->caps.pkey_table_len[port_num]); if (!p->pkey_group.attrs) { ret = -ENOMEM; -- GitLab From 5e99b139f1b68acd65e36515ca347b03856dfb5a Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Thu, 30 Jul 2015 17:34:24 +0300 Subject: [PATCH 5793/7006] IB/mlx4: Use correct SL on AH query under RoCE The mlx4 IB driver implementation for ib_query_ah used a wrong offset (28 instead of 29) when link type is Ethernet. Fixed to use the correct one. Fixes: fa417f7b520e ('IB/mlx4: Add support for IBoE') Signed-off-by: Shani Michaeli Signed-off-by: Noa Osherovich Signed-off-by: Or Gerlitz Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/ah.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index 7ad6f9679c40f..1688a17de4fe1 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c @@ -148,9 +148,13 @@ int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) enum rdma_link_layer ll; memset(ah_attr, 0, sizeof *ah_attr); - ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; ah_attr->port_num = be32_to_cpu(ah->av.ib.port_pd) >> 24; ll = rdma_port_get_link_layer(ibah->device, ah_attr->port_num); + if (ll == IB_LINK_LAYER_ETHERNET) + ah_attr->sl = be32_to_cpu(ah->av.eth.sl_tclass_flowlabel) >> 29; + else + ah_attr->sl = be32_to_cpu(ah->av.ib.sl_tclass_flowlabel) >> 28; + ah_attr->dlid = ll == IB_LINK_LAYER_INFINIBAND ? be16_to_cpu(ah->av.ib.dlid) : 0; if (ah->av.ib.stat_rate) ah_attr->static_rate = ah->av.ib.stat_rate - MLX4_STAT_RATE_OFFSET; -- GitLab From 799cdaf8a98f13d4fba3162e21e1e63f21045010 Mon Sep 17 00:00:00 2001 From: Ariel Nahum Date: Sun, 9 Aug 2015 11:16:27 +0300 Subject: [PATCH 5794/7006] IB/mlx4: Fix incorrect cq flushing in error state When handling a device internal error, the driver is responsible to drain the completion queue with flush errors. In case a completion queue was assigned to multiple send queues, the driver iterates over the send queues and generates flush errors of inflight wqes. The driver must correctly pass the wc array with an offset as a result of the previous send queue iteration. Not doing so will overwrite previously set completions and return a wrong number of polled completions which includes ones which were not correctly set. Fixes: 35f05dabf95a (IB/mlx4: Reset flow support for IB kernel ULPs) Signed-off-by: Ariel Nahum Signed-off-by: Sagi Grimberg Cc: Yishai Hadas Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/cq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c index 36eb3d012b6d3..2f4259525bb13 100644 --- a/drivers/infiniband/hw/mlx4/cq.c +++ b/drivers/infiniband/hw/mlx4/cq.c @@ -638,7 +638,7 @@ static void mlx4_ib_poll_sw_comp(struct mlx4_ib_cq *cq, int num_entries, * simulated FLUSH_ERR completions */ list_for_each_entry(qp, &cq->send_qp_list, cq_send_list) { - mlx4_ib_qp_sw_comp(qp, num_entries, wc, npolled, 1); + mlx4_ib_qp_sw_comp(qp, num_entries, wc + *npolled, npolled, 1); if (*npolled >= num_entries) goto out; } -- GitLab From e6300cbd9b09e7bf12f5f7b79e77b58d62b9d990 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 31 Jul 2015 14:12:48 -0700 Subject: [PATCH 5795/7006] IB/srp: Constify a function argument This patch does not change any functionality. Signed-off-by: Bart Van Assche Cc: Sagi Grimberg Cc: Sebastian Parschauer Cc: Christoph Hellwig Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 43265608361e0..a0b92a1ee4185 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2172,7 +2172,7 @@ static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask) } static void srp_cm_rep_handler(struct ib_cm_id *cm_id, - struct srp_login_rsp *lrsp, + const struct srp_login_rsp *lrsp, struct srp_rdma_ch *ch) { struct srp_target_port *target = ch->target; -- GitLab From c257ea6f9f9aed0b173e0c2932bb8dac5612cdc6 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 31 Jul 2015 14:13:22 -0700 Subject: [PATCH 5796/7006] IB/srp: Handle partial connection success correctly Avoid that the following kernel warning is reported if the SRP target system accepts fewer channels per connection than what was requested by the initiator system: WARNING: at drivers/infiniband/ulp/srp/ib_srp.c:617 srp_destroy_qp+0xb1/0x120 [ib_srp]() Call Trace: [] warn_slowpath_common+0x7f/0xc0 [] warn_slowpath_null+0x1a/0x20 [] srp_destroy_qp+0xb1/0x120 [ib_srp] [] srp_create_ch_ib+0x19b/0x420 [ib_srp] [] srp_create_target+0x7d7/0xa94 [ib_srp] [] dev_attr_store+0x20/0x30 [] sysfs_write_file+0xef/0x170 [] vfs_write+0xb4/0x130 [] sys_write+0x5f/0xa0 [] system_call_fastpath+0x16/0x1b Signed-off-by: Bart Van Assche Cc: Sagi Grimberg Cc: Sebastian Parschauer Cc: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index a0b92a1ee4185..ae13c96b48d35 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3263,7 +3263,7 @@ static ssize_t srp_create_target(struct device *dev, srp_free_ch_ib(target, ch); srp_free_req_data(target, ch); target->ch_count = ch - target->ch; - break; + goto connected; } } @@ -3273,6 +3273,7 @@ static ssize_t srp_create_target(struct device *dev, node_idx++; } +connected: target->scsi_host->nr_hw_queues = target->ch_count; ret = srp_add_target(host, target); -- GitLab From 713ef24e41757561c7f0bfc9bf4436f7e4a5b527 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 31 Jul 2015 14:13:52 -0700 Subject: [PATCH 5797/7006] IB/srp: Bump driver version and release date Since version 1.0 e.g. scsi-mq has been added. Since this is a significant change, bump the driver version and release date. Signed-off-by: Bart Van Assche Cc: Sagi Grimberg Cc: Sebastian Parschauer Cc: Christoph Hellwig Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ae13c96b48d35..0a18e03fac17a 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -55,8 +55,8 @@ #define DRV_NAME "ib_srp" #define PFX DRV_NAME ": " -#define DRV_VERSION "1.0" -#define DRV_RELDATE "July 1, 2013" +#define DRV_VERSION "2.0" +#define DRV_RELDATE "July 26, 2015" MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator"); -- GitLab From bc44bd1d864664f3658352c6aaaa02557d49165d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 14 Aug 2015 11:01:09 -0700 Subject: [PATCH 5798/7006] IB/srp: Stop the scsi_eh_ and scsi_tmf_ threads if login fails scsi_host_alloc() not only allocates memory for a SCSI host but also creates the scsi_eh_ kernel thread and the scsi_tmf_ workqueue. Stop these threads if login fails by calling scsi_host_put(). Reported-by: Konstantin Krotov Fixes: fb49c8bbaae7 ("Remove an extraneous scsi_host_put() from an error path") Signed-off-by: Bart Van Assche Cc: Sagi Grimberg Cc: Sebastian Parschauer Cc: #v3.19 Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 0a18e03fac17a..c9c4f647b1701 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -2758,6 +2758,13 @@ static int srp_sdev_count(struct Scsi_Host *host) return c; } +/* + * Return values: + * < 0 upon failure. Caller is responsible for SRP target port cleanup. + * 0 and target->state == SRP_TARGET_REMOVED if asynchronous target port + * removal has been scheduled. + * 0 and target->state != SRP_TARGET_REMOVED upon success. + */ static int srp_add_target(struct srp_host *host, struct srp_target_port *target) { struct srp_rport_identifiers ids; @@ -3296,6 +3303,8 @@ out: mutex_unlock(&host->add_target_mutex); scsi_host_put(target->scsi_host); + if (ret < 0) + scsi_host_put(target->scsi_host); return ret; -- GitLab From 6431eb87065ffd24dfc7c0b6954e80a4eb74e177 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Fri, 14 Aug 2015 08:52:06 -0400 Subject: [PATCH 5799/7006] IB/netlink: Add defines for local service requests through netlink This patch adds netlink defines for local service client, local service group, local service operations, and related attributes. Signed-off-by: Kaike Wan Signed-off-by: John Fleck Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- include/uapi/rdma/rdma_netlink.h | 82 ++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index 6e4bb4270ca2e..c19a5dc1531af 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h @@ -7,12 +7,14 @@ enum { RDMA_NL_RDMA_CM = 1, RDMA_NL_NES, RDMA_NL_C4IW, + RDMA_NL_LS, /* RDMA Local Services */ RDMA_NL_NUM_CLIENTS }; enum { RDMA_NL_GROUP_CM = 1, RDMA_NL_GROUP_IWPM, + RDMA_NL_GROUP_LS, RDMA_NL_NUM_GROUPS }; @@ -128,5 +130,85 @@ enum { IWPM_NLA_ERR_MAX }; +/* + * Local service operations: + * RESOLVE - The client requests the local service to resolve a path. + * SET_TIMEOUT - The local service requests the client to set the timeout. + */ +enum { + RDMA_NL_LS_OP_RESOLVE = 0, + RDMA_NL_LS_OP_SET_TIMEOUT, + RDMA_NL_LS_NUM_OPS +}; + +/* Local service netlink message flags */ +#define RDMA_NL_LS_F_ERR 0x0100 /* Failed response */ + +/* + * Local service resolve operation family header. + * The layout for the resolve operation: + * nlmsg header + * family header + * attributes + */ + +/* + * Local service path use: + * Specify how the path(s) will be used. + * ALL - For connected CM operation (6 pathrecords) + * UNIDIRECTIONAL - For unidirectional UD (1 pathrecord) + * GMP - For miscellaneous GMP like operation (at least 1 reversible + * pathrecord) + */ +enum { + LS_RESOLVE_PATH_USE_ALL = 0, + LS_RESOLVE_PATH_USE_UNIDIRECTIONAL, + LS_RESOLVE_PATH_USE_GMP, + LS_RESOLVE_PATH_USE_MAX +}; + +#define LS_DEVICE_NAME_MAX 64 + +struct rdma_ls_resolve_header { + __u8 device_name[LS_DEVICE_NAME_MAX]; + __u8 port_num; + __u8 path_use; +}; + +/* Local service attribute type */ +#define RDMA_NLA_F_MANDATORY (1 << 13) +#define RDMA_NLA_TYPE_MASK (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \ + RDMA_NLA_F_MANDATORY)) + +/* + * Local service attributes: + * Attr Name Size Byte order + * ----------------------------------------------------- + * PATH_RECORD struct ib_path_rec_data + * TIMEOUT u32 cpu + * SERVICE_ID u64 cpu + * DGID u8[16] BE + * SGID u8[16] BE + * TCLASS u8 + * PKEY u16 cpu + * QOS_CLASS u16 cpu + */ +enum { + LS_NLA_TYPE_UNSPEC = 0, + LS_NLA_TYPE_PATH_RECORD, + LS_NLA_TYPE_TIMEOUT, + LS_NLA_TYPE_SERVICE_ID, + LS_NLA_TYPE_DGID, + LS_NLA_TYPE_SGID, + LS_NLA_TYPE_TCLASS, + LS_NLA_TYPE_PKEY, + LS_NLA_TYPE_QOS_CLASS, + LS_NLA_TYPE_MAX +}; + +/* Local service DGID/SGID attribute: big endian */ +struct rdma_nla_ls_gid { + __u8 gid[16]; +}; #endif /* _UAPI_RDMA_NETLINK_H */ -- GitLab From bc10ed7d3d19ff61427007b4d7bf98d3e57bb333 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Fri, 14 Aug 2015 08:52:07 -0400 Subject: [PATCH 5800/7006] IB/core: Add rdma netlink helper functions This patch adds a function to check if listeners for a netlink multicast group are present. It also adds a function to receive netlink response messages. Signed-off-by: Kaike Wan Signed-off-by: John Fleck Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/netlink.c | 55 +++++++++++++++++++++++++++++++ include/rdma/rdma_netlink.h | 7 ++++ 2 files changed, 62 insertions(+) diff --git a/drivers/infiniband/core/netlink.c b/drivers/infiniband/core/netlink.c index 23dd5a5c75971..d47df93567796 100644 --- a/drivers/infiniband/core/netlink.c +++ b/drivers/infiniband/core/netlink.c @@ -49,6 +49,14 @@ static DEFINE_MUTEX(ibnl_mutex); static struct sock *nls; static LIST_HEAD(client_list); +int ibnl_chk_listeners(unsigned int group) +{ + if (netlink_has_listeners(nls, group) == 0) + return -1; + return 0; +} +EXPORT_SYMBOL(ibnl_chk_listeners); + int ibnl_add_client(int index, int nops, const struct ibnl_client_cbs cb_table[]) { @@ -151,6 +159,23 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) !client->cb_table[op].dump) return -EINVAL; + /* + * For response or local service set_timeout request, + * there is no need to use netlink_dump_start. + */ + if (!(nlh->nlmsg_flags & NLM_F_REQUEST) || + (index == RDMA_NL_LS && + op == RDMA_NL_LS_OP_SET_TIMEOUT)) { + struct netlink_callback cb = { + .skb = skb, + .nlh = nlh, + .dump = client->cb_table[op].dump, + .module = client->cb_table[op].module, + }; + + return cb.dump(skb, &cb); + } + { struct netlink_dump_control c = { .dump = client->cb_table[op].dump, @@ -165,9 +190,39 @@ static int ibnl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) return -EINVAL; } +static void ibnl_rcv_reply_skb(struct sk_buff *skb) +{ + struct nlmsghdr *nlh; + int msglen; + + /* + * Process responses until there is no more message or the first + * request. Generally speaking, it is not recommended to mix responses + * with requests. + */ + while (skb->len >= nlmsg_total_size(0)) { + nlh = nlmsg_hdr(skb); + + if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) + return; + + /* Handle response only */ + if (nlh->nlmsg_flags & NLM_F_REQUEST) + return; + + ibnl_rcv_msg(skb, nlh); + + msglen = NLMSG_ALIGN(nlh->nlmsg_len); + if (msglen > skb->len) + msglen = skb->len; + skb_pull(skb, msglen); + } +} + static void ibnl_rcv(struct sk_buff *skb) { mutex_lock(&ibnl_mutex); + ibnl_rcv_reply_skb(skb); netlink_rcv_skb(skb, &ibnl_rcv_msg); mutex_unlock(&ibnl_mutex); } diff --git a/include/rdma/rdma_netlink.h b/include/rdma/rdma_netlink.h index 0790882e0c9b3..5852661443290 100644 --- a/include/rdma/rdma_netlink.h +++ b/include/rdma/rdma_netlink.h @@ -77,4 +77,11 @@ int ibnl_unicast(struct sk_buff *skb, struct nlmsghdr *nlh, int ibnl_multicast(struct sk_buff *skb, struct nlmsghdr *nlh, unsigned int group, gfp_t flags); +/** + * Check if there are any listeners to the netlink group + * @group: the netlink group ID + * Returns 0 on success or a negative for no listeners. + */ +int ibnl_chk_listeners(unsigned int group); + #endif /* _RDMA_NETLINK_H */ -- GitLab From 5d2657708ec25b9fb3dd174443b1f647babcbe62 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Fri, 14 Aug 2015 08:52:08 -0400 Subject: [PATCH 5801/7006] IB/sa: Allocate SA query with kzalloc Replace kmalloc with kzalloc so that all uninitialized fields in SA query will be zero-ed out to avoid unintentional consequence. This prepares the SA query structure to accept new fields in the future. Signed-off-by: Kaike Wan Signed-off-by: John Fleck Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/sa_query.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index d40be3673b79e..968c66f1c5855 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -740,7 +740,7 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, port = &sa_dev->port[port_num - sa_dev->start_port]; agent = port->agent; - query = kmalloc(sizeof *query, gfp_mask); + query = kzalloc(sizeof(*query), gfp_mask); if (!query) return -ENOMEM; @@ -862,7 +862,7 @@ int ib_sa_service_rec_query(struct ib_sa_client *client, method != IB_SA_METHOD_DELETE) return -EINVAL; - query = kmalloc(sizeof *query, gfp_mask); + query = kzalloc(sizeof(*query), gfp_mask); if (!query) return -ENOMEM; @@ -954,7 +954,7 @@ int ib_sa_mcmember_rec_query(struct ib_sa_client *client, port = &sa_dev->port[port_num - sa_dev->start_port]; agent = port->agent; - query = kmalloc(sizeof *query, gfp_mask); + query = kzalloc(sizeof(*query), gfp_mask); if (!query) return -ENOMEM; @@ -1051,7 +1051,7 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client, port = &sa_dev->port[port_num - sa_dev->start_port]; agent = port->agent; - query = kmalloc(sizeof *query, gfp_mask); + query = kzalloc(sizeof(*query), gfp_mask); if (!query) return -ENOMEM; -- GitLab From 2ca546b92a024d07adedd15b4c262b1c2c0786ec Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Fri, 14 Aug 2015 08:52:09 -0400 Subject: [PATCH 5802/7006] IB/sa: Route SA pathrecord query through netlink This patch routes a SA pathrecord query to netlink first and processes the response appropriately. If a failure is returned, the request will be sent through IB. The decision whether to route the request to netlink first is determined by the presence of a listener for the local service netlink multicast group. If the user-space local service netlink multicast group listener is not present, the request will be sent through IB, just like what is currently being done. Signed-off-by: Kaike Wan Signed-off-by: John Fleck Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/sa_query.c | 501 ++++++++++++++++++++++++++++- 1 file changed, 500 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 968c66f1c5855..edcf568dab48a 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -45,12 +45,21 @@ #include #include #include +#include +#include +#include +#include #include "sa.h" MODULE_AUTHOR("Roland Dreier"); MODULE_DESCRIPTION("InfiniBand subnet administration query support"); MODULE_LICENSE("Dual BSD/GPL"); +#define IB_SA_LOCAL_SVC_TIMEOUT_MIN 100 +#define IB_SA_LOCAL_SVC_TIMEOUT_DEFAULT 2000 +#define IB_SA_LOCAL_SVC_TIMEOUT_MAX 200000 +static int sa_local_svc_timeout_ms = IB_SA_LOCAL_SVC_TIMEOUT_DEFAULT; + struct ib_sa_sm_ah { struct ib_ah *ah; struct kref ref; @@ -80,8 +89,16 @@ struct ib_sa_query { struct ib_mad_send_buf *mad_buf; struct ib_sa_sm_ah *sm_ah; int id; + u32 flags; + struct list_head list; /* Local svc request list */ + u32 seq; /* Local svc request sequence number */ + unsigned long timeout; /* Local svc timeout */ + u8 path_use; /* How will the pathrecord be used */ }; +#define IB_SA_ENABLE_LOCAL_SERVICE 0x00000001 +#define IB_SA_CANCEL 0x00000002 + struct ib_sa_service_query { void (*callback)(int, struct ib_sa_service_rec *, void *); void *context; @@ -106,6 +123,26 @@ struct ib_sa_mcmember_query { struct ib_sa_query sa_query; }; +static LIST_HEAD(ib_nl_request_list); +static DEFINE_SPINLOCK(ib_nl_request_lock); +static atomic_t ib_nl_sa_request_seq; +static struct workqueue_struct *ib_nl_wq; +static struct delayed_work ib_nl_timed_work; +static const struct nla_policy ib_nl_policy[LS_NLA_TYPE_MAX] = { + [LS_NLA_TYPE_PATH_RECORD] = {.type = NLA_BINARY, + .len = sizeof(struct ib_path_rec_data)}, + [LS_NLA_TYPE_TIMEOUT] = {.type = NLA_U32}, + [LS_NLA_TYPE_SERVICE_ID] = {.type = NLA_U64}, + [LS_NLA_TYPE_DGID] = {.type = NLA_BINARY, + .len = sizeof(struct rdma_nla_ls_gid)}, + [LS_NLA_TYPE_SGID] = {.type = NLA_BINARY, + .len = sizeof(struct rdma_nla_ls_gid)}, + [LS_NLA_TYPE_TCLASS] = {.type = NLA_U8}, + [LS_NLA_TYPE_PKEY] = {.type = NLA_U16}, + [LS_NLA_TYPE_QOS_CLASS] = {.type = NLA_U16}, +}; + + static void ib_sa_add_one(struct ib_device *device); static void ib_sa_remove_one(struct ib_device *device, void *client_data); @@ -381,6 +418,427 @@ static const struct ib_field guidinfo_rec_table[] = { .size_bits = 512 }, }; +static inline void ib_sa_disable_local_svc(struct ib_sa_query *query) +{ + query->flags &= ~IB_SA_ENABLE_LOCAL_SERVICE; +} + +static inline int ib_sa_query_cancelled(struct ib_sa_query *query) +{ + return (query->flags & IB_SA_CANCEL); +} + +static void ib_nl_set_path_rec_attrs(struct sk_buff *skb, + struct ib_sa_query *query) +{ + struct ib_sa_path_rec *sa_rec = query->mad_buf->context[1]; + struct ib_sa_mad *mad = query->mad_buf->mad; + ib_sa_comp_mask comp_mask = mad->sa_hdr.comp_mask; + u16 val16; + u64 val64; + struct rdma_ls_resolve_header *header; + + query->mad_buf->context[1] = NULL; + + /* Construct the family header first */ + header = (struct rdma_ls_resolve_header *) + skb_put(skb, NLMSG_ALIGN(sizeof(*header))); + memcpy(header->device_name, query->port->agent->device->name, + LS_DEVICE_NAME_MAX); + header->port_num = query->port->port_num; + + if ((comp_mask & IB_SA_PATH_REC_REVERSIBLE) && + sa_rec->reversible != 0) + query->path_use = LS_RESOLVE_PATH_USE_GMP; + else + query->path_use = LS_RESOLVE_PATH_USE_UNIDIRECTIONAL; + header->path_use = query->path_use; + + /* Now build the attributes */ + if (comp_mask & IB_SA_PATH_REC_SERVICE_ID) { + val64 = be64_to_cpu(sa_rec->service_id); + nla_put(skb, RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_SERVICE_ID, + sizeof(val64), &val64); + } + if (comp_mask & IB_SA_PATH_REC_DGID) + nla_put(skb, RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_DGID, + sizeof(sa_rec->dgid), &sa_rec->dgid); + if (comp_mask & IB_SA_PATH_REC_SGID) + nla_put(skb, RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_SGID, + sizeof(sa_rec->sgid), &sa_rec->sgid); + if (comp_mask & IB_SA_PATH_REC_TRAFFIC_CLASS) + nla_put(skb, RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_TCLASS, + sizeof(sa_rec->traffic_class), &sa_rec->traffic_class); + + if (comp_mask & IB_SA_PATH_REC_PKEY) { + val16 = be16_to_cpu(sa_rec->pkey); + nla_put(skb, RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_PKEY, + sizeof(val16), &val16); + } + if (comp_mask & IB_SA_PATH_REC_QOS_CLASS) { + val16 = be16_to_cpu(sa_rec->qos_class); + nla_put(skb, RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_QOS_CLASS, + sizeof(val16), &val16); + } +} + +static int ib_nl_get_path_rec_attrs_len(ib_sa_comp_mask comp_mask) +{ + int len = 0; + + if (comp_mask & IB_SA_PATH_REC_SERVICE_ID) + len += nla_total_size(sizeof(u64)); + if (comp_mask & IB_SA_PATH_REC_DGID) + len += nla_total_size(sizeof(struct rdma_nla_ls_gid)); + if (comp_mask & IB_SA_PATH_REC_SGID) + len += nla_total_size(sizeof(struct rdma_nla_ls_gid)); + if (comp_mask & IB_SA_PATH_REC_TRAFFIC_CLASS) + len += nla_total_size(sizeof(u8)); + if (comp_mask & IB_SA_PATH_REC_PKEY) + len += nla_total_size(sizeof(u16)); + if (comp_mask & IB_SA_PATH_REC_QOS_CLASS) + len += nla_total_size(sizeof(u16)); + + /* + * Make sure that at least some of the required comp_mask bits are + * set. + */ + if (WARN_ON(len == 0)) + return len; + + /* Add the family header */ + len += NLMSG_ALIGN(sizeof(struct rdma_ls_resolve_header)); + + return len; +} + +static int ib_nl_send_msg(struct ib_sa_query *query) +{ + struct sk_buff *skb = NULL; + struct nlmsghdr *nlh; + void *data; + int ret = 0; + struct ib_sa_mad *mad; + int len; + + mad = query->mad_buf->mad; + len = ib_nl_get_path_rec_attrs_len(mad->sa_hdr.comp_mask); + if (len <= 0) + return -EMSGSIZE; + + skb = nlmsg_new(len, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + /* Put nlmsg header only for now */ + data = ibnl_put_msg(skb, &nlh, query->seq, 0, RDMA_NL_LS, + RDMA_NL_LS_OP_RESOLVE, (int) GFP_KERNEL); + if (!data) { + kfree_skb(skb); + return -EMSGSIZE; + } + + /* Add attributes */ + ib_nl_set_path_rec_attrs(skb, query); + + /* Repair the nlmsg header length */ + nlmsg_end(skb, nlh); + + ret = ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, GFP_KERNEL); + if (!ret) + ret = len; + else + ret = 0; + + return ret; +} + +static int ib_nl_make_request(struct ib_sa_query *query) +{ + unsigned long flags; + unsigned long delay; + int ret; + + INIT_LIST_HEAD(&query->list); + query->seq = (u32)atomic_inc_return(&ib_nl_sa_request_seq); + + spin_lock_irqsave(&ib_nl_request_lock, flags); + ret = ib_nl_send_msg(query); + if (ret <= 0) { + ret = -EIO; + goto request_out; + } else { + ret = 0; + } + + delay = msecs_to_jiffies(sa_local_svc_timeout_ms); + query->timeout = delay + jiffies; + list_add_tail(&query->list, &ib_nl_request_list); + /* Start the timeout if this is the only request */ + if (ib_nl_request_list.next == &query->list) + queue_delayed_work(ib_nl_wq, &ib_nl_timed_work, delay); + +request_out: + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + + return ret; +} + +static int ib_nl_cancel_request(struct ib_sa_query *query) +{ + unsigned long flags; + struct ib_sa_query *wait_query; + int found = 0; + + spin_lock_irqsave(&ib_nl_request_lock, flags); + list_for_each_entry(wait_query, &ib_nl_request_list, list) { + /* Let the timeout to take care of the callback */ + if (query == wait_query) { + query->flags |= IB_SA_CANCEL; + query->timeout = jiffies; + list_move(&query->list, &ib_nl_request_list); + found = 1; + mod_delayed_work(ib_nl_wq, &ib_nl_timed_work, 1); + break; + } + } + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + + return found; +} + +static void send_handler(struct ib_mad_agent *agent, + struct ib_mad_send_wc *mad_send_wc); + +static void ib_nl_process_good_resolve_rsp(struct ib_sa_query *query, + const struct nlmsghdr *nlh) +{ + struct ib_mad_send_wc mad_send_wc; + struct ib_sa_mad *mad = NULL; + const struct nlattr *head, *curr; + struct ib_path_rec_data *rec; + int len, rem; + u32 mask = 0; + int status = -EIO; + + if (query->callback) { + head = (const struct nlattr *) nlmsg_data(nlh); + len = nlmsg_len(nlh); + switch (query->path_use) { + case LS_RESOLVE_PATH_USE_UNIDIRECTIONAL: + mask = IB_PATH_PRIMARY | IB_PATH_OUTBOUND; + break; + + case LS_RESOLVE_PATH_USE_ALL: + case LS_RESOLVE_PATH_USE_GMP: + default: + mask = IB_PATH_PRIMARY | IB_PATH_GMP | + IB_PATH_BIDIRECTIONAL; + break; + } + nla_for_each_attr(curr, head, len, rem) { + if (curr->nla_type == LS_NLA_TYPE_PATH_RECORD) { + rec = nla_data(curr); + /* + * Get the first one. In the future, we may + * need to get up to 6 pathrecords. + */ + if ((rec->flags & mask) == mask) { + mad = query->mad_buf->mad; + mad->mad_hdr.method |= + IB_MGMT_METHOD_RESP; + memcpy(mad->data, rec->path_rec, + sizeof(rec->path_rec)); + status = 0; + break; + } + } + } + query->callback(query, status, mad); + } + + mad_send_wc.send_buf = query->mad_buf; + mad_send_wc.status = IB_WC_SUCCESS; + send_handler(query->mad_buf->mad_agent, &mad_send_wc); +} + +static void ib_nl_request_timeout(struct work_struct *work) +{ + unsigned long flags; + struct ib_sa_query *query; + unsigned long delay; + struct ib_mad_send_wc mad_send_wc; + int ret; + + spin_lock_irqsave(&ib_nl_request_lock, flags); + while (!list_empty(&ib_nl_request_list)) { + query = list_entry(ib_nl_request_list.next, + struct ib_sa_query, list); + + if (time_after(query->timeout, jiffies)) { + delay = query->timeout - jiffies; + if ((long)delay <= 0) + delay = 1; + queue_delayed_work(ib_nl_wq, &ib_nl_timed_work, delay); + break; + } + + list_del(&query->list); + ib_sa_disable_local_svc(query); + /* Hold the lock to protect against query cancellation */ + if (ib_sa_query_cancelled(query)) + ret = -1; + else + ret = ib_post_send_mad(query->mad_buf, NULL); + if (ret) { + mad_send_wc.send_buf = query->mad_buf; + mad_send_wc.status = IB_WC_WR_FLUSH_ERR; + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + send_handler(query->port->agent, &mad_send_wc); + spin_lock_irqsave(&ib_nl_request_lock, flags); + } + } + spin_unlock_irqrestore(&ib_nl_request_lock, flags); +} + +static int ib_nl_handle_set_timeout(struct sk_buff *skb, + struct netlink_callback *cb) +{ + const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; + int timeout, delta, abs_delta; + const struct nlattr *attr; + unsigned long flags; + struct ib_sa_query *query; + long delay = 0; + struct nlattr *tb[LS_NLA_TYPE_MAX]; + int ret; + + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), + nlmsg_len(nlh), ib_nl_policy); + attr = (const struct nlattr *)tb[LS_NLA_TYPE_TIMEOUT]; + if (ret || !attr) + goto settimeout_out; + + timeout = *(int *) nla_data(attr); + if (timeout < IB_SA_LOCAL_SVC_TIMEOUT_MIN) + timeout = IB_SA_LOCAL_SVC_TIMEOUT_MIN; + if (timeout > IB_SA_LOCAL_SVC_TIMEOUT_MAX) + timeout = IB_SA_LOCAL_SVC_TIMEOUT_MAX; + + delta = timeout - sa_local_svc_timeout_ms; + if (delta < 0) + abs_delta = -delta; + else + abs_delta = delta; + + if (delta != 0) { + spin_lock_irqsave(&ib_nl_request_lock, flags); + sa_local_svc_timeout_ms = timeout; + list_for_each_entry(query, &ib_nl_request_list, list) { + if (delta < 0 && abs_delta > query->timeout) + query->timeout = 0; + else + query->timeout += delta; + + /* Get the new delay from the first entry */ + if (!delay) { + delay = query->timeout - jiffies; + if (delay <= 0) + delay = 1; + } + } + if (delay) + mod_delayed_work(ib_nl_wq, &ib_nl_timed_work, + (unsigned long)delay); + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + } + +settimeout_out: + return skb->len; +} + +static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh) +{ + struct nlattr *tb[LS_NLA_TYPE_MAX]; + int ret; + + if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR) + return 0; + + ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), + nlmsg_len(nlh), ib_nl_policy); + if (ret) + return 0; + + return 1; +} + +static int ib_nl_handle_resolve_resp(struct sk_buff *skb, + struct netlink_callback *cb) +{ + const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; + unsigned long flags; + struct ib_sa_query *query; + struct ib_mad_send_buf *send_buf; + struct ib_mad_send_wc mad_send_wc; + int found = 0; + int ret; + + if (!netlink_capable(skb, CAP_NET_ADMIN)) + return -EPERM; + + spin_lock_irqsave(&ib_nl_request_lock, flags); + list_for_each_entry(query, &ib_nl_request_list, list) { + /* + * If the query is cancelled, let the timeout routine + * take care of it. + */ + if (nlh->nlmsg_seq == query->seq) { + found = !ib_sa_query_cancelled(query); + if (found) + list_del(&query->list); + break; + } + } + + if (!found) { + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + goto resp_out; + } + + send_buf = query->mad_buf; + + if (!ib_nl_is_good_resolve_resp(nlh)) { + /* if the result is a failure, send out the packet via IB */ + ib_sa_disable_local_svc(query); + ret = ib_post_send_mad(query->mad_buf, NULL); + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + if (ret) { + mad_send_wc.send_buf = send_buf; + mad_send_wc.status = IB_WC_GENERAL_ERR; + send_handler(query->port->agent, &mad_send_wc); + } + } else { + spin_unlock_irqrestore(&ib_nl_request_lock, flags); + ib_nl_process_good_resolve_rsp(query, nlh); + } + +resp_out: + return skb->len; +} + +static struct ibnl_client_cbs ib_sa_cb_table[] = { + [RDMA_NL_LS_OP_RESOLVE] = { + .dump = ib_nl_handle_resolve_resp, + .module = THIS_MODULE }, + [RDMA_NL_LS_OP_SET_TIMEOUT] = { + .dump = ib_nl_handle_set_timeout, + .module = THIS_MODULE }, +}; + static void free_sm_ah(struct kref *kref) { struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref); @@ -502,7 +960,13 @@ void ib_sa_cancel_query(int id, struct ib_sa_query *query) mad_buf = query->mad_buf; spin_unlock_irqrestore(&idr_lock, flags); - ib_cancel_mad(agent, mad_buf); + /* + * If the query is still on the netlink request list, schedule + * it to be cancelled by the timeout routine. Otherwise, it has been + * sent to the MAD layer and has to be cancelled from there. + */ + if (!ib_nl_cancel_request(query)) + ib_cancel_mad(agent, mad_buf); } EXPORT_SYMBOL(ib_sa_cancel_query); @@ -639,6 +1103,14 @@ static int send_mad(struct ib_sa_query *query, int timeout_ms, gfp_t gfp_mask) query->mad_buf->context[0] = query; query->id = id; + if (query->flags & IB_SA_ENABLE_LOCAL_SERVICE) { + if (!ibnl_chk_listeners(RDMA_NL_GROUP_LS)) { + if (!ib_nl_make_request(query)) + return id; + } + ib_sa_disable_local_svc(query); + } + ret = ib_post_send_mad(query->mad_buf, NULL); if (ret) { spin_lock_irqsave(&idr_lock, flags); @@ -767,6 +1239,9 @@ int ib_sa_path_rec_get(struct ib_sa_client *client, *sa_query = &query->sa_query; + query->sa_query.flags |= IB_SA_ENABLE_LOCAL_SERVICE; + query->sa_query.mad_buf->context[1] = rec; + ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); if (ret < 0) goto err2; @@ -1251,6 +1726,8 @@ static int __init ib_sa_init(void) get_random_bytes(&tid, sizeof tid); + atomic_set(&ib_nl_sa_request_seq, 0); + ret = ib_register_client(&sa_client); if (ret) { printk(KERN_ERR "Couldn't register ib_sa client\n"); @@ -1263,7 +1740,25 @@ static int __init ib_sa_init(void) goto err2; } + ib_nl_wq = create_singlethread_workqueue("ib_nl_sa_wq"); + if (!ib_nl_wq) { + ret = -ENOMEM; + goto err3; + } + + if (ibnl_add_client(RDMA_NL_LS, RDMA_NL_LS_NUM_OPS, + ib_sa_cb_table)) { + pr_err("Failed to add netlink callback\n"); + ret = -EINVAL; + goto err4; + } + INIT_DELAYED_WORK(&ib_nl_timed_work, ib_nl_request_timeout); + return 0; +err4: + destroy_workqueue(ib_nl_wq); +err3: + mcast_cleanup(); err2: ib_unregister_client(&sa_client); err1: @@ -1272,6 +1767,10 @@ err1: static void __exit ib_sa_cleanup(void) { + ibnl_remove_client(RDMA_NL_LS); + cancel_delayed_work(&ib_nl_timed_work); + flush_workqueue(ib_nl_wq); + destroy_workqueue(ib_nl_wq); mcast_cleanup(); ib_unregister_client(&sa_client); idr_destroy(&query_idr); -- GitLab From db0a6cbd21d6ece6587c157b3d183521bc8a2781 Mon Sep 17 00:00:00 2001 From: Jenny Falkovich Date: Thu, 6 Aug 2015 18:32:45 +0300 Subject: [PATCH 5803/7006] IB/iser: Change some module parameters to be RO While we're at it, use permission defines instead of octal values and rearrange a little bit. Signed-off-by: Jenny Derzhavetz Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 31 ++++++++++++------------ 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index de8730dd97875..cbe013d22d940 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -74,34 +74,33 @@ #include "iscsi_iser.h" +MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz"); +MODULE_VERSION(DRV_VER); + static struct scsi_host_template iscsi_iser_sht; static struct iscsi_transport iscsi_iser_transport; static struct scsi_transport_template *iscsi_iser_scsi_transport; +static struct workqueue_struct *release_wq; +struct iser_global ig; + +int iser_debug_level = 0; +module_param_named(debug_level, iser_debug_level, int, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)"); static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); +MODULE_PARM_DESC(max_lun, "Max LUNs to allow per session (default:512"); -int iser_debug_level = 0; bool iser_pi_enable = false; -int iser_pi_guard = 1; - -MODULE_DESCRIPTION("iSER (iSCSI Extensions for RDMA) Datamover"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Alex Nezhinsky, Dan Bar Dov, Or Gerlitz"); -MODULE_VERSION(DRV_VER); - -module_param_named(debug_level, iser_debug_level, int, 0644); -MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:disabled)"); - -module_param_named(pi_enable, iser_pi_enable, bool, 0644); +module_param_named(pi_enable, iser_pi_enable, bool, S_IRUGO); MODULE_PARM_DESC(pi_enable, "Enable T10-PI offload support (default:disabled)"); -module_param_named(pi_guard, iser_pi_guard, int, 0644); +int iser_pi_guard; +module_param_named(pi_guard, iser_pi_guard, int, S_IRUGO); MODULE_PARM_DESC(pi_guard, "T10-PI guard_type [deprecated]"); -static struct workqueue_struct *release_wq; -struct iser_global ig; - /* * iscsi_iser_recv() - Process a successfull recv completion * @conn: iscsi connection -- GitLab From 74ce897b7c9be9f5913bbffafcac10f0871c503b Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:46 +0300 Subject: [PATCH 5804/7006] IB/iser: Change minor assignments and logging prints Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index cbe013d22d940..eddf39d42309a 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -847,10 +847,9 @@ failure: static int iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) { - struct iser_conn *iser_conn; + struct iser_conn *iser_conn = ep->dd_data; int rc; - iser_conn = ep->dd_data; rc = wait_for_completion_interruptible_timeout(&iser_conn->up_completion, msecs_to_jiffies(timeout_ms)); /* if conn establishment failed, return error code to iscsi */ @@ -862,7 +861,7 @@ iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) mutex_unlock(&iser_conn->state_mutex); } - iser_info("ib conn %p rc = %d\n", iser_conn, rc); + iser_info("iser conn %p rc = %d\n", iser_conn, rc); if (rc > 0) return 1; /* success, this is the equivalent of POLLOUT */ @@ -884,11 +883,9 @@ iscsi_iser_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) static void iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) { - struct iser_conn *iser_conn; + struct iser_conn *iser_conn = ep->dd_data; - iser_conn = ep->dd_data; - iser_info("ep %p iser conn %p state %d\n", - ep, iser_conn, iser_conn->state); + iser_info("ep %p iser conn %p\n", ep, iser_conn); mutex_lock(&iser_conn->state_mutex); iser_conn_terminate(iser_conn); -- GitLab From 1156cc80f8fc31f8c52740a9c8051afd8d70faf3 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:47 +0300 Subject: [PATCH 5805/7006] IB/iser: Remove '.' from log message Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index eddf39d42309a..e112cbef9bfba 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -905,6 +905,7 @@ iscsi_iser_ep_disconnect(struct iscsi_endpoint *ep) mutex_unlock(&iser_conn->state_mutex); iser_conn_release(iser_conn); } + iscsi_destroy_endpoint(ep); } @@ -1079,7 +1080,7 @@ static void __exit iser_exit(void) if (!connlist_empty) { iser_err("Error cleanup stage completed but we still have iser " - "connections, destroying them anyway.\n"); + "connections, destroying them anyway\n"); list_for_each_entry_safe(iser_conn, n, &ig.connlist, conn_list) { iser_conn_release(iser_conn); -- GitLab From d16739055bd1f562ae4d83e69f7f7f1cefcfbe16 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:48 +0300 Subject: [PATCH 5806/7006] IB/iser: Fix missing return status check in iser_send_data_out Since commit "IB/iser: Fix race between iser connection teardown..." iser_initialize_task_headers() might fail, so we need to check that. Fixes: 7414dde0a6c3a958e (IB/iser: Fix race between iser connection ...) Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_initiator.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 3e2118e8ed879..0a47f42fec24e 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -454,7 +454,7 @@ int iser_send_data_out(struct iscsi_conn *conn, unsigned long buf_offset; unsigned long data_seg_len; uint32_t itt; - int err = 0; + int err; struct ib_sge *tx_dsg; itt = (__force uint32_t)hdr->itt; @@ -475,7 +475,9 @@ int iser_send_data_out(struct iscsi_conn *conn, memcpy(&tx_desc->iscsi_header, hdr, sizeof(struct iscsi_hdr)); /* build the tx desc */ - iser_initialize_task_headers(task, tx_desc); + err = iser_initialize_task_headers(task, tx_desc); + if (err) + goto send_data_out_error; mem_reg = &iser_task->rdma_reg[ISER_DIR_OUT]; tx_dsg = &tx_desc->tx_sg[1]; @@ -502,7 +504,7 @@ int iser_send_data_out(struct iscsi_conn *conn, send_data_out_error: kmem_cache_free(ig.desc_cache, tx_desc); - iser_err("conn %p failed err %d\n",conn, err); + iser_err("conn %p failed err %d\n", conn, err); return err; } -- GitLab From 02816a8b8881f9dea68883c9b72672e87cb91d36 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:49 +0300 Subject: [PATCH 5807/7006] IB/iser: Get rid of un-maintained counters We don't update those anywhere in the code and they seem pretty useless (no one seem to care about those). qp_tx_queue_full: We never should get this fmr_map_not_avail: We can never get to this eh_abort_cnt: We don't monitor aborts Go ahead and remove them. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index e112cbef9bfba..9cc7319887d16 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -750,15 +750,9 @@ iscsi_iser_conn_get_stats(struct iscsi_cls_conn *cls_conn, struct iscsi_stats *s stats->r2t_pdus = conn->r2t_pdus_cnt; /* always 0 */ stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; - stats->custom_length = 4; - strcpy(stats->custom[0].desc, "qp_tx_queue_full"); - stats->custom[0].value = 0; /* TB iser_conn->qp_tx_queue_full; */ - strcpy(stats->custom[1].desc, "fmr_map_not_avail"); - stats->custom[1].value = 0; /* TB iser_conn->fmr_map_not_avail */; - strcpy(stats->custom[2].desc, "eh_abort_cnt"); - stats->custom[2].value = conn->eh_abort_cnt; - strcpy(stats->custom[3].desc, "fmr_unalign_cnt"); - stats->custom[3].value = conn->fmr_unalign_cnt; + stats->custom_length = 1; + strcpy(stats->custom[0].desc, "fmr_unalign_cnt"); + stats->custom[0].value = conn->fmr_unalign_cnt; } static int iscsi_iser_get_ep_param(struct iscsi_endpoint *ep, -- GitLab From 8d5944d80359e645feb2ebd069a6f4caf7825e40 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:50 +0300 Subject: [PATCH 5808/7006] IB/iser: Fix possible bogus DMA unmapping If iser_initialize_task_headers() routine failed before dma mapping, we should not attempt to unmap in cleanup_task(). Fixes: 7414dde0a6c3a958e (IB/iser: Fix race between iser connection ...) Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 12 ++++++++---- drivers/infiniband/ulp/iser/iscsi_iser.h | 2 ++ 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 9cc7319887d16..169cc3e75018d 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -200,6 +200,7 @@ iser_initialize_task_headers(struct iscsi_task *task, goto out; } + tx_desc->mapped = true; tx_desc->dma_addr = dma_addr; tx_desc->tx_sg[0].addr = tx_desc->dma_addr; tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; @@ -359,16 +360,19 @@ iscsi_iser_task_xmit(struct iscsi_task *task) static void iscsi_iser_cleanup_task(struct iscsi_task *task) { struct iscsi_iser_task *iser_task = task->dd_data; - struct iser_tx_desc *tx_desc = &iser_task->desc; - struct iser_conn *iser_conn = task->conn->dd_data; + struct iser_tx_desc *tx_desc = &iser_task->desc; + struct iser_conn *iser_conn = task->conn->dd_data; struct iser_device *device = iser_conn->ib_conn.device; /* DEVICE_REMOVAL event might have already released the device */ if (!device) return; - ib_dma_unmap_single(device->ib_device, - tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); + if (likely(tx_desc->mapped)) { + ib_dma_unmap_single(device->ib_device, tx_desc->dma_addr, + ISER_HEADERS_LEN, DMA_TO_DEVICE); + tx_desc->mapped = false; + } /* mgmt tasks do not need special cleanup */ if (!task->sc) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 262ba1f8ee507..d2b6caf7694d7 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -270,6 +270,7 @@ enum iser_desc_type { * sg[1] optionally points to either of immediate data * unsolicited data-out or control * @num_sge: number sges used on this TX task + * @mapped: Is the task header mapped */ struct iser_tx_desc { struct iser_hdr iser_header; @@ -278,6 +279,7 @@ struct iser_tx_desc { u64 dma_addr; struct ib_sge tx_sg[2]; int num_sge; + bool mapped; }; #define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \ -- GitLab From b9abd8d21d3a04903aefcb7742efe3390f2fac57 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:51 +0300 Subject: [PATCH 5809/7006] IB/iser: Remove a redundant always-false condition We always call iser_initialize_task_headers() and set the header tx_sg.lkey to the device mr lkey, so no point in checking it in iser_create_send_desc(). Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_initiator.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 0a47f42fec24e..9ff6dec6f8be0 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -170,13 +170,7 @@ static void iser_create_send_desc(struct iser_conn *iser_conn, memset(&tx_desc->iser_header, 0, sizeof(struct iser_hdr)); tx_desc->iser_header.flags = ISER_VER; - tx_desc->num_sge = 1; - - if (tx_desc->tx_sg[0].lkey != device->mr->lkey) { - tx_desc->tx_sg[0].lkey = device->mr->lkey; - iser_dbg("sdesc %p lkey mismatch, fixing\n", tx_desc); - } } static void iser_free_login_buf(struct iser_conn *iser_conn) -- GitLab From ea18f5d7777dc4fa9c18c4919281301cf4fd921a Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:52 +0300 Subject: [PATCH 5810/7006] IB/iser: Remove an unneeded print for unaligned memory We can do it in iser_aligned_data_len instead and it will save us an argument that is passed to fall_to_counce_buf just for the print. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_memory.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index f0cdc961eb11b..b6889f66d3213 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -330,8 +330,11 @@ static int iser_data_buf_aligned_len(struct iser_data_buf *data, break; } ret_len = (next_sg) ? i : i+1; - iser_dbg("Found %d aligned entries out of %d in sg:0x%p\n", - ret_len, data->dma_nents, data); + + if (unlikely(ret_len != data->dma_nents)) + iser_warn("rdma alignment violation (%d/%d aligned)\n", + ret_len, data->dma_nents); + return ret_len; } @@ -407,15 +410,12 @@ iser_reg_dma(struct iser_device *device, struct iser_data_buf *mem, static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, struct iser_data_buf *mem, - enum iser_data_dir cmd_dir, - int aligned_len) + enum iser_data_dir cmd_dir) { struct iscsi_conn *iscsi_conn = iser_task->iser_conn->iscsi_conn; struct iser_device *device = iser_task->iser_conn->ib_conn.device; iscsi_conn->fmr_unalign_cnt++; - iser_warn("rdma alignment violation (%d/%d aligned) or FMR not supported\n", - aligned_len, mem->size); if (iser_debug_level > 0) iser_data_buf_dump(mem, device->ib_device); @@ -537,8 +537,7 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, mem, - cmd_dir, aligned_len); + err = fall_to_bounce_buf(iser_task, mem, cmd_dir); if (err) { iser_err("failed to allocate bounce buffer\n"); return err; @@ -800,8 +799,7 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, mem, - cmd_dir, aligned_len); + err = fall_to_bounce_buf(iser_task, mem, cmd_dir); if (err) { iser_err("failed to allocate bounce buffer\n"); return err; @@ -828,7 +826,7 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, aligned_len = iser_data_buf_aligned_len(mem, ibdev); if (aligned_len != mem->dma_nents) { err = fall_to_bounce_buf(iser_task, mem, - cmd_dir, aligned_len); + cmd_dir); if (err) { iser_err("failed to allocate bounce buffer\n"); return err; -- GitLab From d711d81d6463ecf566b93810e16949f2d159aa50 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:53 +0300 Subject: [PATCH 5811/7006] IB/iser: Introduce struct iser_reg_resources Have fast_reg_descriptor hold struct iser_reg_resources (mr, frpl, valid flag). This will be useful when the actual buffer registration routines will be passed with the needed registration resources (i.e. iser_reg_resources) without being aware of their nature (i.e. data or protection). In order to achieve this, we remove reg_indicators flags container and place specific flags (mr_valid) within iser_reg_resources struct. We also place the sig_mr_valid and sig_protcted flags in iser_pi_context. This patch also modifies iser_fast_reg_mr to receive the reg_resources instead of the fast_reg_descriptor and a data/protection indicator. Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 36 ++++---- drivers/infiniband/ulp/iser/iser_memory.c | 35 +++----- drivers/infiniband/ulp/iser/iser_verbs.c | 101 ++++++++++++---------- 3 files changed, 91 insertions(+), 81 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index d2b6caf7694d7..9cdfdbdb027e9 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -367,41 +367,45 @@ struct iser_device { #define ISER_CHECK_REFTAG 0x0f #define ISER_CHECK_APPTAG 0x30 -enum iser_reg_indicator { - ISER_DATA_KEY_VALID = 1 << 0, - ISER_PROT_KEY_VALID = 1 << 1, - ISER_SIG_KEY_VALID = 1 << 2, - ISER_FASTREG_PROTECTED = 1 << 3, +/** + * struct iser_reg_resources - Fast registration recources + * + * @mr: memory region + * @frpl: fast reg page list + * @mr_valid: is mr valid indicator + */ +struct iser_reg_resources { + struct ib_mr *mr; + struct ib_fast_reg_page_list *frpl; + u8 mr_valid:1; }; /** * struct iser_pi_context - Protection information context * - * @prot_mr: protection memory region - * @prot_frpl: protection fastreg page list - * @sig_mr: signature feature enabled memory region + * @rsc: protection buffer registration resources + * @sig_mr: signature enable memory region + * @sig_mr_valid: is sig_mr valid indicator + * @sig_protected: is region protected indicator */ struct iser_pi_context { - struct ib_mr *prot_mr; - struct ib_fast_reg_page_list *prot_frpl; + struct iser_reg_resources rsc; struct ib_mr *sig_mr; + u8 sig_mr_valid:1; + u8 sig_protected:1; }; /** * struct fast_reg_descriptor - Fast registration descriptor * * @list: entry in connection fastreg pool - * @data_mr: data memory region - * @data_frpl: data fastreg page list + * @rsc: data buffer registration resources * @pi_ctx: protection information context - * @reg_indicators: fast registration indicators */ struct fast_reg_descriptor { struct list_head list; - struct ib_mr *data_mr; - struct ib_fast_reg_page_list *data_frpl; + struct iser_reg_resources rsc; struct iser_pi_context *pi_ctx; - u8 reg_indicators; }; /** diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index b6889f66d3213..82a33046bb7c9 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -647,13 +647,12 @@ iser_inv_rkey(struct ib_send_wr *inv_wr, struct ib_mr *mr) static int iser_reg_sig_mr(struct iscsi_iser_task *iser_task, - struct fast_reg_descriptor *desc, + struct iser_pi_context *pi_ctx, struct iser_mem_reg *data_reg, struct iser_mem_reg *prot_reg, struct iser_mem_reg *sig_reg) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; - struct iser_pi_context *pi_ctx = desc->pi_ctx; struct ib_send_wr sig_wr, inv_wr; struct ib_send_wr *bad_wr, *wr = NULL; struct ib_sig_attrs sig_attrs; @@ -666,7 +665,7 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task, iser_set_prot_checks(iser_task->sc, &sig_attrs.check_mask); - if (!(desc->reg_indicators & ISER_SIG_KEY_VALID)) { + if (!pi_ctx->sig_mr_valid) { iser_inv_rkey(&inv_wr, pi_ctx->sig_mr); wr = &inv_wr; } @@ -694,7 +693,7 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task, iser_err("reg_sig_mr failed, ret:%d\n", ret); goto err; } - desc->reg_indicators &= ~ISER_SIG_KEY_VALID; + pi_ctx->sig_mr_valid = 0; sig_reg->sge.lkey = pi_ctx->sig_mr->lkey; sig_reg->rkey = pi_ctx->sig_mr->rkey; @@ -710,8 +709,7 @@ err: static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, struct iser_data_buf *mem, - struct fast_reg_descriptor *desc, - enum iser_reg_indicator ind, + struct iser_reg_resources *rsc, struct iser_mem_reg *reg) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; @@ -726,13 +724,8 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, if (mem->dma_nents == 1) return iser_reg_dma(device, mem, reg); - if (ind == ISER_DATA_KEY_VALID) { - mr = desc->data_mr; - frpl = desc->data_frpl; - } else { - mr = desc->pi_ctx->prot_mr; - frpl = desc->pi_ctx->prot_frpl; - } + mr = rsc->mr; + frpl = rsc->frpl; plen = iser_sg_to_page_vec(mem, device->ib_device, frpl->page_list, &offset, &size); @@ -741,7 +734,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, return -EINVAL; } - if (!(desc->reg_indicators & ind)) { + if (!rsc->mr_valid) { iser_inv_rkey(&inv_wr, mr); wr = &inv_wr; } @@ -770,7 +763,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, iser_err("fast registration failed, ret:%d\n", ret); return ret; } - desc->reg_indicators &= ~ind; + rsc->mr_valid = 0; reg->sge.lkey = mr->lkey; reg->rkey = mr->rkey; @@ -812,8 +805,8 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, mem_reg->mem_h = desc; } - err = iser_fast_reg_mr(iser_task, mem, desc, - ISER_DATA_KEY_VALID, mem_reg); + err = iser_fast_reg_mr(iser_task, mem, + desc ? &desc->rsc : NULL, mem_reg); if (err) goto err_reg; @@ -833,19 +826,19 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, } } - err = iser_fast_reg_mr(iser_task, mem, desc, - ISER_PROT_KEY_VALID, &prot_reg); + err = iser_fast_reg_mr(iser_task, mem, + &desc->pi_ctx->rsc, &prot_reg); if (err) goto err_reg; } - err = iser_reg_sig_mr(iser_task, desc, mem_reg, + err = iser_reg_sig_mr(iser_task, desc->pi_ctx, mem_reg, &prot_reg, mem_reg); if (err) { iser_err("Failed to register signature mr\n"); return err; } - desc->reg_indicators |= ISER_FASTREG_PROTECTED; + desc->pi_ctx->sig_protected = 1; } return 0; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 8f24728f10525..1cadcd954f814 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -279,6 +279,45 @@ void iser_free_fmr_pool(struct ib_conn *ib_conn) ib_conn->fmr.page_vec = NULL; } +static int +iser_alloc_reg_res(struct ib_device *ib_device, struct ib_pd *pd, + struct iser_reg_resources *res) +{ + int ret; + + res->frpl = ib_alloc_fast_reg_page_list(ib_device, + ISCSI_ISER_SG_TABLESIZE + 1); + if (IS_ERR(res->frpl)) { + ret = PTR_ERR(res->frpl); + iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n", + ret); + return PTR_ERR(res->frpl); + } + + res->mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, + ISCSI_ISER_SG_TABLESIZE + 1); + if (IS_ERR(res->mr)) { + ret = PTR_ERR(res->mr); + iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); + goto fast_reg_mr_failure; + } + res->mr_valid = 1; + + return 0; + +fast_reg_mr_failure: + ib_free_fast_reg_page_list(res->frpl); + + return ret; +} + +static void +iser_free_reg_res(struct iser_reg_resources *rsc) +{ + ib_dereg_mr(rsc->mr); + ib_free_fast_reg_page_list(rsc->frpl); +} + static int iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, struct fast_reg_descriptor *desc) @@ -292,36 +331,25 @@ iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, pi_ctx = desc->pi_ctx; - pi_ctx->prot_frpl = ib_alloc_fast_reg_page_list(ib_device, - ISCSI_ISER_SG_TABLESIZE); - if (IS_ERR(pi_ctx->prot_frpl)) { - ret = PTR_ERR(pi_ctx->prot_frpl); - goto prot_frpl_failure; - } - - pi_ctx->prot_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, - ISCSI_ISER_SG_TABLESIZE + 1); - if (IS_ERR(pi_ctx->prot_mr)) { - ret = PTR_ERR(pi_ctx->prot_mr); - goto prot_mr_failure; + ret = iser_alloc_reg_res(ib_device, pd, &pi_ctx->rsc); + if (ret) { + iser_err("failed to allocate reg_resources\n"); + goto alloc_reg_res_err; } - desc->reg_indicators |= ISER_PROT_KEY_VALID; pi_ctx->sig_mr = ib_alloc_mr(pd, IB_MR_TYPE_SIGNATURE, 2); if (IS_ERR(pi_ctx->sig_mr)) { ret = PTR_ERR(pi_ctx->sig_mr); goto sig_mr_failure; } - desc->reg_indicators |= ISER_SIG_KEY_VALID; - desc->reg_indicators &= ~ISER_FASTREG_PROTECTED; + pi_ctx->sig_mr_valid = 1; + desc->pi_ctx->sig_protected = 0; return 0; sig_mr_failure: - ib_dereg_mr(desc->pi_ctx->prot_mr); -prot_mr_failure: - ib_free_fast_reg_page_list(desc->pi_ctx->prot_frpl); -prot_frpl_failure: + iser_free_reg_res(&pi_ctx->rsc); +alloc_reg_res_err: kfree(desc->pi_ctx); return ret; @@ -330,8 +358,7 @@ prot_frpl_failure: static void iser_free_pi_ctx(struct iser_pi_context *pi_ctx) { - ib_free_fast_reg_page_list(pi_ctx->prot_frpl); - ib_dereg_mr(pi_ctx->prot_mr); + iser_free_reg_res(&pi_ctx->rsc); ib_dereg_mr(pi_ctx->sig_mr); kfree(pi_ctx); } @@ -342,23 +369,11 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, { int ret; - desc->data_frpl = ib_alloc_fast_reg_page_list(ib_device, - ISCSI_ISER_SG_TABLESIZE + 1); - if (IS_ERR(desc->data_frpl)) { - ret = PTR_ERR(desc->data_frpl); - iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n", - ret); - return PTR_ERR(desc->data_frpl); - } - - desc->data_mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, - ISCSI_ISER_SG_TABLESIZE + 1); - if (IS_ERR(desc->data_mr)) { - ret = PTR_ERR(desc->data_mr); - iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); - goto fast_reg_mr_failure; + ret = iser_alloc_reg_res(ib_device, pd, &desc->rsc); + if (ret) { + iser_err("failed to allocate reg_resources\n"); + return ret; } - desc->reg_indicators |= ISER_DATA_KEY_VALID; if (pi_enable) { ret = iser_alloc_pi_ctx(ib_device, pd, desc); @@ -367,10 +382,9 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, } return 0; + pi_ctx_alloc_failure: - ib_dereg_mr(desc->data_mr); -fast_reg_mr_failure: - ib_free_fast_reg_page_list(desc->data_frpl); + iser_free_reg_res(&desc->rsc); return ret; } @@ -431,8 +445,7 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn) list_for_each_entry_safe(desc, tmp, &ib_conn->fastreg.pool, list) { list_del(&desc->list); - ib_free_fast_reg_page_list(desc->data_frpl); - ib_dereg_mr(desc->data_mr); + iser_free_reg_res(&desc->rsc); if (desc->pi_ctx) iser_free_pi_ctx(desc->pi_ctx); kfree(desc); @@ -1244,8 +1257,8 @@ u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, struct ib_mr_status mr_status; int ret; - if (desc && desc->reg_indicators & ISER_FASTREG_PROTECTED) { - desc->reg_indicators &= ~ISER_FASTREG_PROTECTED; + if (desc && desc->pi_ctx->sig_protected) { + desc->pi_ctx->sig_protected = 0; ret = ib_check_mr_status(desc->pi_ctx->sig_mr, IB_MR_CHECK_SIG_STATUS, &mr_status); if (ret) { -- GitLab From 5190cc2664972f2c51502e928fcb7a608dddab5f Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:54 +0300 Subject: [PATCH 5812/7006] IB/iser: Rename struct fast_reg_descriptor -> iser_fr_desc Avoid struct names without iser_ prefix. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 8 ++++---- drivers/infiniband/ulp/iser/iser_memory.c | 10 +++++----- drivers/infiniband/ulp/iser/iser_verbs.c | 10 +++++----- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 9cdfdbdb027e9..70bf6e7a711b0 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -396,13 +396,13 @@ struct iser_pi_context { }; /** - * struct fast_reg_descriptor - Fast registration descriptor + * struct iser_fr_desc - Fast registration descriptor * * @list: entry in connection fastreg pool * @rsc: data buffer registration resources * @pi_ctx: protection information context */ -struct fast_reg_descriptor { +struct iser_fr_desc { struct list_head list; struct iser_reg_resources rsc; struct iser_pi_context *pi_ctx; @@ -642,9 +642,9 @@ int iser_create_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max); void iser_free_fastreg_pool(struct ib_conn *ib_conn); u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir, sector_t *sector); -struct fast_reg_descriptor * +struct iser_fr_desc * iser_reg_desc_get(struct ib_conn *ib_conn); void iser_reg_desc_put(struct ib_conn *ib_conn, - struct fast_reg_descriptor *desc); + struct iser_fr_desc *desc); #endif diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 82a33046bb7c9..710ac7d7ecf41 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -146,15 +146,15 @@ iser_copy_to_bounce(struct iser_data_buf *data) iser_copy_bounce(data, true); } -struct fast_reg_descriptor * +struct iser_fr_desc * iser_reg_desc_get(struct ib_conn *ib_conn) { - struct fast_reg_descriptor *desc; + struct iser_fr_desc *desc; unsigned long flags; spin_lock_irqsave(&ib_conn->lock, flags); desc = list_first_entry(&ib_conn->fastreg.pool, - struct fast_reg_descriptor, list); + struct iser_fr_desc, list); list_del(&desc->list); spin_unlock_irqrestore(&ib_conn->lock, flags); @@ -163,7 +163,7 @@ iser_reg_desc_get(struct ib_conn *ib_conn) void iser_reg_desc_put(struct ib_conn *ib_conn, - struct fast_reg_descriptor *desc) + struct iser_fr_desc *desc) { unsigned long flags; @@ -787,7 +787,7 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, struct ib_device *ibdev = device->ib_device; struct iser_data_buf *mem = &iser_task->data[cmd_dir]; struct iser_mem_reg *mem_reg = &iser_task->rdma_reg[cmd_dir]; - struct fast_reg_descriptor *desc = NULL; + struct iser_fr_desc *desc = NULL; int err, aligned_len; aligned_len = iser_data_buf_aligned_len(mem, ibdev); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 1cadcd954f814..e4f89676248c4 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -320,7 +320,7 @@ iser_free_reg_res(struct iser_reg_resources *rsc) static int iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, - struct fast_reg_descriptor *desc) + struct iser_fr_desc *desc) { struct iser_pi_context *pi_ctx = NULL; int ret; @@ -365,7 +365,7 @@ iser_free_pi_ctx(struct iser_pi_context *pi_ctx) static int iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, - bool pi_enable, struct fast_reg_descriptor *desc) + bool pi_enable, struct iser_fr_desc *desc) { int ret; @@ -397,7 +397,7 @@ pi_ctx_alloc_failure: int iser_create_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) { struct iser_device *device = ib_conn->device; - struct fast_reg_descriptor *desc; + struct iser_fr_desc *desc; int i, ret; INIT_LIST_HEAD(&ib_conn->fastreg.pool); @@ -435,7 +435,7 @@ err: */ void iser_free_fastreg_pool(struct ib_conn *ib_conn) { - struct fast_reg_descriptor *desc, *tmp; + struct iser_fr_desc *desc, *tmp; int i = 0; if (list_empty(&ib_conn->fastreg.pool)) @@ -1252,7 +1252,7 @@ u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir, sector_t *sector) { struct iser_mem_reg *reg = &iser_task->rdma_reg[cmd_dir]; - struct fast_reg_descriptor *desc = reg->mem_h; + struct iser_fr_desc *desc = reg->mem_h; unsigned long sector_size = iser_task->sc->device->sector_size; struct ib_mr_status mr_status; int ret; -- GitLab From 8c18ed03a95cb6c3543b0a9e0df5e9366baea5df Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:55 +0300 Subject: [PATCH 5813/7006] IB/iser: Remove dead code in fmr_pool alloc/free In the past the we always tried to allocate an fmr_pool and if it failed on ENOSYS (not supported) then we continued with dma mr. This is not the case anymore and if we tried to allocate an fmr_pool then it is supported and we expect to succeed. Also, the check if fmr_pool is allocated when free is called is redundant as well as we are guaranteed it exists. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_verbs.c | 26 +++++++++--------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index e4f89676248c4..adec4d7438612 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -244,22 +244,18 @@ int iser_create_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) IB_ACCESS_REMOTE_READ); ib_conn->fmr.pool = ib_create_fmr_pool(device->pd, ¶ms); - if (!IS_ERR(ib_conn->fmr.pool)) - return 0; + if (IS_ERR(ib_conn->fmr.pool)) { + ret = PTR_ERR(ib_conn->fmr.pool); + iser_err("FMR allocation failed, err %d\n", ret); + goto err; + } + + return 0; - /* no FMR => no need for page_vec */ +err: kfree(ib_conn->fmr.page_vec); ib_conn->fmr.page_vec = NULL; - - ret = PTR_ERR(ib_conn->fmr.pool); - ib_conn->fmr.pool = NULL; - if (ret != -ENOSYS) { - iser_err("FMR allocation failed, err %d\n", ret); - return ret; - } else { - iser_warn("FMRs are not supported, using unaligned mode\n"); - return 0; - } + return ret; } /** @@ -270,9 +266,7 @@ void iser_free_fmr_pool(struct ib_conn *ib_conn) iser_info("freeing conn %p fmr pool %p\n", ib_conn, ib_conn->fmr.pool); - if (ib_conn->fmr.pool != NULL) - ib_destroy_fmr_pool(ib_conn->fmr.pool); - + ib_destroy_fmr_pool(ib_conn->fmr.pool); ib_conn->fmr.pool = NULL; kfree(ib_conn->fmr.page_vec); -- GitLab From 48afbff673d3d2ff6c52342574392db504dae301 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:56 +0300 Subject: [PATCH 5814/7006] IB/iser: Introduce iser_reg_ops Move all the per-device function pointers to an easy extensible iser_reg_ops structure that contains all the iser registration operations. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 39 +++++++++++++------- drivers/infiniband/ulp/iser/iser_initiator.c | 16 ++++---- drivers/infiniband/ulp/iser/iser_memory.c | 35 ++++++++++++++++++ drivers/infiniband/ulp/iser/iser_verbs.c | 30 ++++----------- 4 files changed, 75 insertions(+), 45 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 70bf6e7a711b0..9ce090c2d5b52 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -325,6 +325,25 @@ struct iser_comp { int active_qps; }; +/** + * struct iser_device - Memory registration operations + * per-device registration schemes + * + * @alloc_reg_res: Allocate registration resources + * @free_reg_res: Free registration resources + * @reg_rdma_mem: Register memory buffers + * @unreg_rdma_mem: Un-register memory buffers + */ +struct iser_reg_ops { + int (*alloc_reg_res)(struct ib_conn *ib_conn, + unsigned cmds_max); + void (*free_reg_res)(struct ib_conn *ib_conn); + int (*reg_rdma_mem)(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir); + void (*unreg_rdma_mem)(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir); +}; + /** * struct iser_device - iSER device handle * @@ -338,11 +357,7 @@ struct iser_comp { * @comps_used: Number of completion contexts used, Min between online * cpus and device max completion vectors * @comps: Dinamically allocated array of completion handlers - * Memory registration pool Function pointers (FMR or Fastreg): - * @iser_alloc_rdma_reg_res: Allocation of memory regions pool - * @iser_free_rdma_reg_res: Free of memory regions pool - * @iser_reg_rdma_mem: Memory registration routine - * @iser_unreg_rdma_mem: Memory deregistration routine + * @reg_ops: Registration ops */ struct iser_device { struct ib_device *ib_device; @@ -354,13 +369,7 @@ struct iser_device { int refcount; int comps_used; struct iser_comp *comps; - int (*iser_alloc_rdma_reg_res)(struct ib_conn *ib_conn, - unsigned cmds_max); - void (*iser_free_rdma_reg_res)(struct ib_conn *ib_conn); - int (*iser_reg_rdma_mem)(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir); - void (*iser_unreg_rdma_mem)(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir); + struct iser_reg_ops *reg_ops; }; #define ISER_CHECK_GUARD 0xc0 @@ -563,6 +572,8 @@ extern int iser_debug_level; extern bool iser_pi_enable; extern int iser_pi_guard; +int iser_assign_reg_ops(struct iser_device *device); + int iser_send_control(struct iscsi_conn *conn, struct iscsi_task *task); @@ -636,9 +647,9 @@ int iser_initialize_task_headers(struct iscsi_task *task, struct iser_tx_desc *tx_desc); int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, struct iscsi_session *session); -int iser_create_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max); +int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max); void iser_free_fmr_pool(struct ib_conn *ib_conn); -int iser_create_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max); +int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max); void iser_free_fastreg_pool(struct ib_conn *ib_conn); u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir, sector_t *sector); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 9ff6dec6f8be0..beacd5f0af1d1 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -73,7 +73,7 @@ static int iser_prepare_read_cmd(struct iscsi_task *task) return err; } - err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_IN); + err = device->reg_ops->reg_rdma_mem(iser_task, ISER_DIR_IN); if (err) { iser_err("Failed to set up Data-IN RDMA\n"); return err; @@ -128,7 +128,7 @@ iser_prepare_write_cmd(struct iscsi_task *task, return err; } - err = device->iser_reg_rdma_mem(iser_task, ISER_DIR_OUT); + err = device->reg_ops->reg_rdma_mem(iser_task, ISER_DIR_OUT); if (err != 0) { iser_err("Failed to register write cmd RDMA mem\n"); return err; @@ -260,7 +260,7 @@ int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, iser_conn->qp_max_recv_dtos_mask = session->cmds_max - 1; /* cmds_max is 2^N */ iser_conn->min_posted_rx = iser_conn->qp_max_recv_dtos >> 2; - if (device->iser_alloc_rdma_reg_res(ib_conn, session->scsi_cmds_max)) + if (device->reg_ops->alloc_reg_res(ib_conn, session->scsi_cmds_max)) goto create_rdma_reg_res_failed; if (iser_alloc_login_buf(iser_conn)) @@ -301,7 +301,7 @@ rx_desc_dma_map_failed: rx_desc_alloc_fail: iser_free_login_buf(iser_conn); alloc_login_buf_fail: - device->iser_free_rdma_reg_res(ib_conn); + device->reg_ops->free_reg_res(ib_conn); create_rdma_reg_res_failed: iser_err("failed allocating rx descriptors / data buffers\n"); return -ENOMEM; @@ -314,8 +314,8 @@ void iser_free_rx_descriptors(struct iser_conn *iser_conn) struct ib_conn *ib_conn = &iser_conn->ib_conn; struct iser_device *device = ib_conn->device; - if (device->iser_free_rdma_reg_res) - device->iser_free_rdma_reg_res(ib_conn); + if (device->reg_ops->free_reg_res) + device->reg_ops->free_reg_res(ib_conn); rx_desc = iser_conn->rx_descs; for (i = 0; i < iser_conn->qp_max_recv_dtos; i++, rx_desc++) @@ -699,7 +699,7 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) } if (iser_task->dir[ISER_DIR_IN]) { - device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN); + device->reg_ops->unreg_rdma_mem(iser_task, ISER_DIR_IN); if (is_rdma_data_aligned) iser_dma_unmap_task_data(iser_task, &iser_task->data[ISER_DIR_IN], @@ -711,7 +711,7 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) } if (iser_task->dir[ISER_DIR_OUT]) { - device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT); + device->reg_ops->unreg_rdma_mem(iser_task, ISER_DIR_OUT); if (is_rdma_data_aligned) iser_dma_unmap_task_data(iser_task, &iser_task->data[ISER_DIR_OUT], diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 710ac7d7ecf41..9febfc1e5e7ce 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -39,6 +39,41 @@ #include "iscsi_iser.h" +static struct iser_reg_ops fastreg_ops = { + .alloc_reg_res = iser_alloc_fastreg_pool, + .free_reg_res = iser_free_fastreg_pool, + .reg_rdma_mem = iser_reg_rdma_mem_fastreg, + .unreg_rdma_mem = iser_unreg_mem_fastreg, +}; + +static struct iser_reg_ops fmr_ops = { + .alloc_reg_res = iser_alloc_fmr_pool, + .free_reg_res = iser_free_fmr_pool, + .reg_rdma_mem = iser_reg_rdma_mem_fmr, + .unreg_rdma_mem = iser_unreg_mem_fmr, +}; + +int iser_assign_reg_ops(struct iser_device *device) +{ + struct ib_device_attr *dev_attr = &device->dev_attr; + + /* Assign function handles - based on FMR support */ + if (device->ib_device->alloc_fmr && device->ib_device->dealloc_fmr && + device->ib_device->map_phys_fmr && device->ib_device->unmap_fmr) { + iser_info("FMR supported, using FMR for registration\n"); + device->reg_ops = &fmr_ops; + } else + if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { + iser_info("FastReg supported, using FastReg for registration\n"); + device->reg_ops = &fastreg_ops; + } else { + iser_err("IB device does not support FMRs nor FastRegs, can't register memory\n"); + return -1; + } + + return 0; +} + static void iser_free_bounce_sg(struct iser_data_buf *data) { diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index adec4d7438612..17f43cf354dad 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -87,25 +87,9 @@ static int iser_create_device_ib_res(struct iser_device *device) return ret; } - /* Assign function handles - based on FMR support */ - if (device->ib_device->alloc_fmr && device->ib_device->dealloc_fmr && - device->ib_device->map_phys_fmr && device->ib_device->unmap_fmr) { - iser_info("FMR supported, using FMR for registration\n"); - device->iser_alloc_rdma_reg_res = iser_create_fmr_pool; - device->iser_free_rdma_reg_res = iser_free_fmr_pool; - device->iser_reg_rdma_mem = iser_reg_rdma_mem_fmr; - device->iser_unreg_rdma_mem = iser_unreg_mem_fmr; - } else - if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) { - iser_info("FastReg supported, using FastReg for registration\n"); - device->iser_alloc_rdma_reg_res = iser_create_fastreg_pool; - device->iser_free_rdma_reg_res = iser_free_fastreg_pool; - device->iser_reg_rdma_mem = iser_reg_rdma_mem_fastreg; - device->iser_unreg_rdma_mem = iser_unreg_mem_fastreg; - } else { - iser_err("IB device does not support FMRs nor FastRegs, can't register memory\n"); - return -1; - } + ret = iser_assign_reg_ops(device); + if (ret) + return ret; device->comps_used = min_t(int, num_online_cpus(), device->ib_device->num_comp_vectors); @@ -211,11 +195,11 @@ static void iser_free_device_ib_res(struct iser_device *device) } /** - * iser_create_fmr_pool - Creates FMR pool and page_vector + * iser_alloc_fmr_pool - Creates FMR pool and page_vector * * returns 0 on success, or errno code on failure */ -int iser_create_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) +int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) { struct iser_device *device = ib_conn->device; struct ib_fmr_pool_param params; @@ -384,11 +368,11 @@ pi_ctx_alloc_failure: } /** - * iser_create_fastreg_pool - Creates pool of fast_reg descriptors + * iser_alloc_fastreg_pool - Creates pool of fast_reg descriptors * for fast registration work requests. * returns 0 on success, or errno code on failure */ -int iser_create_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) +int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) { struct iser_device *device = ib_conn->device; struct iser_fr_desc *desc; -- GitLab From eb6ea8c36c90f022dd9603530286e0707a9c467b Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:57 +0300 Subject: [PATCH 5815/7006] IB/iser: Move fastreg descriptor allocation to iser_create_fastreg_desc Don't have the caller allocate the structure and worry about freeing it in case the routine failed. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_verbs.c | 38 +++++++++++------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 17f43cf354dad..c41bd422ed603 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -341,17 +341,20 @@ iser_free_pi_ctx(struct iser_pi_context *pi_ctx) kfree(pi_ctx); } -static int +static struct iser_fr_desc * iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, - bool pi_enable, struct iser_fr_desc *desc) + bool pi_enable) { + struct iser_fr_desc *desc; int ret; + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return ERR_PTR(-ENOMEM); + ret = iser_alloc_reg_res(ib_device, pd, &desc->rsc); - if (ret) { - iser_err("failed to allocate reg_resources\n"); - return ret; - } + if (ret) + goto reg_res_alloc_failure; if (pi_enable) { ret = iser_alloc_pi_ctx(ib_device, pd, desc); @@ -359,12 +362,14 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, goto pi_ctx_alloc_failure; } - return 0; + return desc; pi_ctx_alloc_failure: iser_free_reg_res(&desc->rsc); +reg_res_alloc_failure: + kfree(desc); - return ret; + return ERR_PTR(ret); } /** @@ -381,19 +386,10 @@ int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) INIT_LIST_HEAD(&ib_conn->fastreg.pool); ib_conn->fastreg.pool_size = 0; for (i = 0; i < cmds_max; i++) { - desc = kzalloc(sizeof(*desc), GFP_KERNEL); - if (!desc) { - iser_err("Failed to allocate a new fast_reg descriptor\n"); - ret = -ENOMEM; - goto err; - } - - ret = iser_create_fastreg_desc(device->ib_device, device->pd, - ib_conn->pi_support, desc); - if (ret) { - iser_err("Failed to create fastreg descriptor err=%d\n", - ret); - kfree(desc); + desc = iser_create_fastreg_desc(device->ib_device, device->pd, + ib_conn->pi_support); + if (IS_ERR(desc)) { + ret = PTR_ERR(desc); goto err; } -- GitLab From 385ad87d4b637c1ebdb54bc93274fc2c267dfc16 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:32:58 +0300 Subject: [PATCH 5816/7006] IB/iser: Introduce iser registration pool struct Instead of having it a part of the connection structure, have it be under a dedicated (embedded) structure in the connection. A logical separation of the registration pool and the connection structure. Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 49 ++++++++++-------- drivers/infiniband/ulp/iser/iser_memory.c | 32 ++++++------ drivers/infiniband/ulp/iser/iser_verbs.c | 60 +++++++++++++---------- 3 files changed, 82 insertions(+), 59 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 9ce090c2d5b52..1fc4c231fb4a7 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -417,6 +417,33 @@ struct iser_fr_desc { struct iser_pi_context *pi_ctx; }; +/** + * struct iser_fr_pool: connection fast registration pool + * + * @lock: protects fmr/fastreg pool + * @union.fmr: + * @pool: FMR pool for fast registrations + * @page_vec: fast reg page list to hold mapped commands pages + * used for registration + * @union.fastreg: + * @pool: Fast registration descriptors pool for fast + * registrations + * @pool_size: Size of pool + */ +struct iser_fr_pool { + spinlock_t lock; + union { + struct { + struct ib_fmr_pool *pool; + struct iser_page_vec *page_vec; + } fmr; + struct { + struct list_head pool; + int pool_size; + } fastreg; + }; +}; + /** * struct ib_conn - Infiniband related objects * @@ -430,15 +457,7 @@ struct iser_fr_desc { * @pi_support: Indicate device T10-PI support * @beacon: beacon send wr to signal all flush errors were drained * @flush_comp: completes when all connection completions consumed - * @lock: protects fmr/fastreg pool - * @union.fmr: - * @pool: FMR pool for fast registrations - * @page_vec: page vector to hold mapped commands pages - * used for registration - * @union.fastreg: - * @pool: Fast registration descriptors pool for fast - * registrations - * @pool_size: Size of pool + * @fr_pool: connection fast registration poool */ struct ib_conn { struct rdma_cm_id *cma_id; @@ -451,17 +470,7 @@ struct ib_conn { bool pi_support; struct ib_send_wr beacon; struct completion flush_comp; - spinlock_t lock; - union { - struct { - struct ib_fmr_pool *pool; - struct iser_page_vec *page_vec; - } fmr; - struct { - struct list_head pool; - int pool_size; - } fastreg; - }; + struct iser_fr_pool fr_pool; }; /** diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 9febfc1e5e7ce..d731ed7616c88 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -184,14 +184,15 @@ iser_copy_to_bounce(struct iser_data_buf *data) struct iser_fr_desc * iser_reg_desc_get(struct ib_conn *ib_conn) { + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_fr_desc *desc; unsigned long flags; - spin_lock_irqsave(&ib_conn->lock, flags); - desc = list_first_entry(&ib_conn->fastreg.pool, + spin_lock_irqsave(&fr_pool->lock, flags); + desc = list_first_entry(&fr_pool->fastreg.pool, struct iser_fr_desc, list); list_del(&desc->list); - spin_unlock_irqrestore(&ib_conn->lock, flags); + spin_unlock_irqrestore(&fr_pool->lock, flags); return desc; } @@ -200,11 +201,12 @@ void iser_reg_desc_put(struct ib_conn *ib_conn, struct iser_fr_desc *desc) { + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; unsigned long flags; - spin_lock_irqsave(&ib_conn->lock, flags); - list_add(&desc->list, &ib_conn->fastreg.pool); - spin_unlock_irqrestore(&ib_conn->lock, flags); + spin_lock_irqsave(&fr_pool->lock, flags); + list_add(&desc->list, &fr_pool->fastreg.pool); + spin_unlock_irqrestore(&fr_pool->lock, flags); } /** @@ -480,6 +482,7 @@ int iser_reg_page_vec(struct iscsi_iser_task *iser_task, struct iser_mem_reg *mem_reg) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_device *device = ib_conn->device; struct ib_pool_fmr *fmr; int ret, plen; @@ -496,7 +499,7 @@ int iser_reg_page_vec(struct iscsi_iser_task *iser_task, return -EINVAL; } - fmr = ib_fmr_pool_map_phys(ib_conn->fmr.pool, + fmr = ib_fmr_pool_map_phys(fr_pool->fmr.pool, page_vec->pages, page_vec->length, page_vec->pages[0]); @@ -560,6 +563,7 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_device *device = ib_conn->device; struct ib_device *ibdev = device->ib_device; struct iser_data_buf *mem = &iser_task->data[cmd_dir]; @@ -583,20 +587,20 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, if (mem->dma_nents == 1) { return iser_reg_dma(device, mem, mem_reg); } else { /* use FMR for multiple dma entries */ - err = iser_reg_page_vec(iser_task, mem, ib_conn->fmr.page_vec, - mem_reg); + err = iser_reg_page_vec(iser_task, mem, + fr_pool->fmr.page_vec, mem_reg); if (err && err != -EAGAIN) { iser_data_buf_dump(mem, ibdev); iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents, ntoh24(iser_task->desc.iscsi_header.dlength)); iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n", - ib_conn->fmr.page_vec->data_size, - ib_conn->fmr.page_vec->length, - ib_conn->fmr.page_vec->offset); - for (i = 0; i < ib_conn->fmr.page_vec->length; i++) + fr_pool->fmr.page_vec->data_size, + fr_pool->fmr.page_vec->length, + fr_pool->fmr.page_vec->offset); + for (i = 0; i < fr_pool->fmr.page_vec->length; i++) iser_err("page_vec[%d] = 0x%llx\n", i, - (unsigned long long)ib_conn->fmr.page_vec->pages[i]); + (unsigned long long)fr_pool->fmr.page_vec->pages[i]); } if (err) return err; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index c41bd422ed603..1b8c9c20fe5b8 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -202,16 +202,21 @@ static void iser_free_device_ib_res(struct iser_device *device) int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) { struct iser_device *device = ib_conn->device; + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; + struct iser_page_vec *page_vec; + struct ib_fmr_pool *fmr_pool; struct ib_fmr_pool_param params; int ret = -ENOMEM; - ib_conn->fmr.page_vec = kmalloc(sizeof(*ib_conn->fmr.page_vec) + - (sizeof(u64)*(ISCSI_ISER_SG_TABLESIZE + 1)), - GFP_KERNEL); - if (!ib_conn->fmr.page_vec) + spin_lock_init(&fr_pool->lock); + + page_vec = kmalloc(sizeof(*page_vec) + + (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE + 1)), + GFP_KERNEL); + if (!page_vec) return ret; - ib_conn->fmr.page_vec->pages = (u64 *)(ib_conn->fmr.page_vec + 1); + page_vec->pages = (u64 *)(page_vec + 1); params.page_shift = SHIFT_4K; /* when the first/last SG element are not start/end * @@ -227,18 +232,20 @@ int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ); - ib_conn->fmr.pool = ib_create_fmr_pool(device->pd, ¶ms); - if (IS_ERR(ib_conn->fmr.pool)) { - ret = PTR_ERR(ib_conn->fmr.pool); + fmr_pool = ib_create_fmr_pool(device->pd, ¶ms); + if (IS_ERR(fmr_pool)) { + ret = PTR_ERR(fmr_pool); iser_err("FMR allocation failed, err %d\n", ret); goto err; } + fr_pool->fmr.page_vec = page_vec; + fr_pool->fmr.pool = fmr_pool; + return 0; err: - kfree(ib_conn->fmr.page_vec); - ib_conn->fmr.page_vec = NULL; + kfree(page_vec); return ret; } @@ -247,14 +254,15 @@ err: */ void iser_free_fmr_pool(struct ib_conn *ib_conn) { - iser_info("freeing conn %p fmr pool %p\n", - ib_conn, ib_conn->fmr.pool); + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; - ib_destroy_fmr_pool(ib_conn->fmr.pool); - ib_conn->fmr.pool = NULL; + iser_info("freeing conn %p fmr pool %p\n", + ib_conn, fr_pool->fmr.pool); - kfree(ib_conn->fmr.page_vec); - ib_conn->fmr.page_vec = NULL; + ib_destroy_fmr_pool(fr_pool->fmr.pool); + fr_pool->fmr.pool = NULL; + kfree(fr_pool->fmr.page_vec); + fr_pool->fmr.page_vec = NULL; } static int @@ -380,11 +388,13 @@ reg_res_alloc_failure: int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) { struct iser_device *device = ib_conn->device; + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_fr_desc *desc; int i, ret; - INIT_LIST_HEAD(&ib_conn->fastreg.pool); - ib_conn->fastreg.pool_size = 0; + INIT_LIST_HEAD(&fr_pool->fastreg.pool); + spin_lock_init(&fr_pool->lock); + fr_pool->fastreg.pool_size = 0; for (i = 0; i < cmds_max; i++) { desc = iser_create_fastreg_desc(device->ib_device, device->pd, ib_conn->pi_support); @@ -393,8 +403,8 @@ int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) goto err; } - list_add_tail(&desc->list, &ib_conn->fastreg.pool); - ib_conn->fastreg.pool_size++; + list_add_tail(&desc->list, &fr_pool->fastreg.pool); + fr_pool->fastreg.pool_size++; } return 0; @@ -409,15 +419,16 @@ err: */ void iser_free_fastreg_pool(struct ib_conn *ib_conn) { + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_fr_desc *desc, *tmp; int i = 0; - if (list_empty(&ib_conn->fastreg.pool)) + if (list_empty(&fr_pool->fastreg.pool)) return; iser_info("freeing conn %p fr pool\n", ib_conn); - list_for_each_entry_safe(desc, tmp, &ib_conn->fastreg.pool, list) { + list_for_each_entry_safe(desc, tmp, &fr_pool->fastreg.pool, list) { list_del(&desc->list); iser_free_reg_res(&desc->rsc); if (desc->pi_ctx) @@ -426,9 +437,9 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn) ++i; } - if (i < ib_conn->fastreg.pool_size) + if (i < fr_pool->fastreg.pool_size) iser_warn("pool still has %d regions registered\n", - ib_conn->fastreg.pool_size - i); + fr_pool->fastreg.pool_size - i); } /** @@ -924,7 +935,6 @@ void iser_conn_init(struct iser_conn *iser_conn) init_completion(&iser_conn->ib_completion); init_completion(&iser_conn->up_completion); INIT_LIST_HEAD(&iser_conn->conn_list); - spin_lock_init(&iser_conn->ib_conn.lock); mutex_init(&iser_conn->state_mutex); } -- GitLab From 2b3bf958103899a96d230c9f2e0d87606f08a7be Mon Sep 17 00:00:00 2001 From: Adir Lev Date: Thu, 6 Aug 2015 18:32:59 +0300 Subject: [PATCH 5817/7006] IB/iser: Maintain connection fmr_pool under a single registration descriptor This will allow us to unify the memory registration code path between the various methods which vary by the device capabilities. This change will make it easier and less intrusive to remove fmr_pools from the code when we'd want to. The reason we use a single descriptor is to avoid taking a redundant spinlock when working with FMRs. We also change the signature of iser_reg_page_vec to make it match iser_fast_reg_mr (and the future indirect registration method). Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 38 +++++++-------- drivers/infiniband/ulp/iser/iser_memory.c | 28 +++++++----- drivers/infiniband/ulp/iser/iser_verbs.c | 56 +++++++++++++++-------- 3 files changed, 68 insertions(+), 54 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 1fc4c231fb4a7..a8c81774ca53f 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -380,12 +380,20 @@ struct iser_device { * struct iser_reg_resources - Fast registration recources * * @mr: memory region - * @frpl: fast reg page list + * @fmr_pool: pool of fmrs + * @frpl: fast reg page list used by frwrs + * @page_vec: fast reg page list used by fmr pool * @mr_valid: is mr valid indicator */ struct iser_reg_resources { - struct ib_mr *mr; - struct ib_fast_reg_page_list *frpl; + union { + struct ib_mr *mr; + struct ib_fmr_pool *fmr_pool; + }; + union { + struct ib_fast_reg_page_list *frpl; + struct iser_page_vec *page_vec; + }; u8 mr_valid:1; }; @@ -420,28 +428,14 @@ struct iser_fr_desc { /** * struct iser_fr_pool: connection fast registration pool * + * @list: list of fastreg descriptors * @lock: protects fmr/fastreg pool - * @union.fmr: - * @pool: FMR pool for fast registrations - * @page_vec: fast reg page list to hold mapped commands pages - * used for registration - * @union.fastreg: - * @pool: Fast registration descriptors pool for fast - * registrations - * @pool_size: Size of pool + * @size: size of the pool */ struct iser_fr_pool { - spinlock_t lock; - union { - struct { - struct ib_fmr_pool *pool; - struct iser_page_vec *page_vec; - } fmr; - struct { - struct list_head pool; - int pool_size; - } fastreg; - }; + struct list_head list; + spinlock_t lock; + int size; }; /** diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index d731ed7616c88..c79292975261f 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -189,7 +189,7 @@ iser_reg_desc_get(struct ib_conn *ib_conn) unsigned long flags; spin_lock_irqsave(&fr_pool->lock, flags); - desc = list_first_entry(&fr_pool->fastreg.pool, + desc = list_first_entry(&fr_pool->list, struct iser_fr_desc, list); list_del(&desc->list); spin_unlock_irqrestore(&fr_pool->lock, flags); @@ -205,7 +205,7 @@ iser_reg_desc_put(struct ib_conn *ib_conn, unsigned long flags; spin_lock_irqsave(&fr_pool->lock, flags); - list_add(&desc->list, &fr_pool->fastreg.pool); + list_add(&desc->list, &fr_pool->list); spin_unlock_irqrestore(&fr_pool->lock, flags); } @@ -478,12 +478,13 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, static int iser_reg_page_vec(struct iscsi_iser_task *iser_task, struct iser_data_buf *mem, - struct iser_page_vec *page_vec, + struct iser_reg_resources *rsc, struct iser_mem_reg *mem_reg) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; - struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_device *device = ib_conn->device; + struct iser_page_vec *page_vec = rsc->page_vec; + struct ib_fmr_pool *fmr_pool = rsc->fmr_pool; struct ib_pool_fmr *fmr; int ret, plen; @@ -499,7 +500,7 @@ int iser_reg_page_vec(struct iscsi_iser_task *iser_task, return -EINVAL; } - fmr = ib_fmr_pool_map_phys(fr_pool->fmr.pool, + fmr = ib_fmr_pool_map_phys(fmr_pool, page_vec->pages, page_vec->length, page_vec->pages[0]); @@ -587,20 +588,23 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, if (mem->dma_nents == 1) { return iser_reg_dma(device, mem, mem_reg); } else { /* use FMR for multiple dma entries */ - err = iser_reg_page_vec(iser_task, mem, - fr_pool->fmr.page_vec, mem_reg); + struct iser_fr_desc *desc; + + desc = list_first_entry(&fr_pool->list, + struct iser_fr_desc, list); + err = iser_reg_page_vec(iser_task, mem, &desc->rsc, mem_reg); if (err && err != -EAGAIN) { iser_data_buf_dump(mem, ibdev); iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", mem->dma_nents, ntoh24(iser_task->desc.iscsi_header.dlength)); iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n", - fr_pool->fmr.page_vec->data_size, - fr_pool->fmr.page_vec->length, - fr_pool->fmr.page_vec->offset); - for (i = 0; i < fr_pool->fmr.page_vec->length; i++) + desc->rsc.page_vec->data_size, + desc->rsc.page_vec->length, + desc->rsc.page_vec->offset); + for (i = 0; i < desc->rsc.page_vec->length; i++) iser_err("page_vec[%d] = 0x%llx\n", i, - (unsigned long long)fr_pool->fmr.page_vec->pages[i]); + (unsigned long long)desc->rsc.page_vec->pages[i]); } if (err) return err; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 1b8c9c20fe5b8..5b5432d95b00f 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -204,17 +204,25 @@ int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) struct iser_device *device = ib_conn->device; struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_page_vec *page_vec; + struct iser_fr_desc *desc; struct ib_fmr_pool *fmr_pool; struct ib_fmr_pool_param params; - int ret = -ENOMEM; + int ret; + INIT_LIST_HEAD(&fr_pool->list); spin_lock_init(&fr_pool->lock); + desc = kzalloc(sizeof(*desc), GFP_KERNEL); + if (!desc) + return -ENOMEM; + page_vec = kmalloc(sizeof(*page_vec) + (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE + 1)), GFP_KERNEL); - if (!page_vec) - return ret; + if (!page_vec) { + ret = -ENOMEM; + goto err_frpl; + } page_vec->pages = (u64 *)(page_vec + 1); @@ -236,16 +244,20 @@ int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) if (IS_ERR(fmr_pool)) { ret = PTR_ERR(fmr_pool); iser_err("FMR allocation failed, err %d\n", ret); - goto err; + goto err_fmr; } - fr_pool->fmr.page_vec = page_vec; - fr_pool->fmr.pool = fmr_pool; + desc->rsc.page_vec = page_vec; + desc->rsc.fmr_pool = fmr_pool; + list_add(&desc->list, &fr_pool->list); return 0; -err: +err_fmr: kfree(page_vec); +err_frpl: + kfree(desc); + return ret; } @@ -255,14 +267,18 @@ err: void iser_free_fmr_pool(struct ib_conn *ib_conn) { struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; + struct iser_fr_desc *desc; + + desc = list_first_entry(&fr_pool->list, + struct iser_fr_desc, list); + list_del(&desc->list); iser_info("freeing conn %p fmr pool %p\n", - ib_conn, fr_pool->fmr.pool); + ib_conn, desc->rsc.fmr_pool); - ib_destroy_fmr_pool(fr_pool->fmr.pool); - fr_pool->fmr.pool = NULL; - kfree(fr_pool->fmr.page_vec); - fr_pool->fmr.page_vec = NULL; + ib_destroy_fmr_pool(desc->rsc.fmr_pool); + kfree(desc->rsc.page_vec); + kfree(desc); } static int @@ -392,9 +408,9 @@ int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) struct iser_fr_desc *desc; int i, ret; - INIT_LIST_HEAD(&fr_pool->fastreg.pool); + INIT_LIST_HEAD(&fr_pool->list); spin_lock_init(&fr_pool->lock); - fr_pool->fastreg.pool_size = 0; + fr_pool->size = 0; for (i = 0; i < cmds_max; i++) { desc = iser_create_fastreg_desc(device->ib_device, device->pd, ib_conn->pi_support); @@ -403,8 +419,8 @@ int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) goto err; } - list_add_tail(&desc->list, &fr_pool->fastreg.pool); - fr_pool->fastreg.pool_size++; + list_add_tail(&desc->list, &fr_pool->list); + fr_pool->size++; } return 0; @@ -423,12 +439,12 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn) struct iser_fr_desc *desc, *tmp; int i = 0; - if (list_empty(&fr_pool->fastreg.pool)) + if (list_empty(&fr_pool->list)) return; iser_info("freeing conn %p fr pool\n", ib_conn); - list_for_each_entry_safe(desc, tmp, &fr_pool->fastreg.pool, list) { + list_for_each_entry_safe(desc, tmp, &fr_pool->list, list) { list_del(&desc->list); iser_free_reg_res(&desc->rsc); if (desc->pi_ctx) @@ -437,9 +453,9 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn) ++i; } - if (i < fr_pool->fastreg.pool_size) + if (i < fr_pool->size) iser_warn("pool still has %d regions registered\n", - fr_pool->fastreg.pool_size - i); + fr_pool->size - i); } /** -- GitLab From 7d0483c927f429c7aece47e730eaa91007577d99 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:00 +0300 Subject: [PATCH 5818/7006] IB/iser: Rename iser_reg_page_vec to iser_fast_reg_fmr Also, change a name of a local variable. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_memory.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index c79292975261f..300e23c1e5064 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -476,10 +476,10 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task, * returns: 0 on success, errno code on failure */ static -int iser_reg_page_vec(struct iscsi_iser_task *iser_task, +int iser_fast_reg_fmr(struct iscsi_iser_task *iser_task, struct iser_data_buf *mem, struct iser_reg_resources *rsc, - struct iser_mem_reg *mem_reg) + struct iser_mem_reg *reg) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; @@ -510,11 +510,11 @@ int iser_reg_page_vec(struct iscsi_iser_task *iser_task, return ret; } - mem_reg->sge.lkey = fmr->fmr->lkey; - mem_reg->rkey = fmr->fmr->rkey; - mem_reg->sge.addr = page_vec->pages[0] + page_vec->offset; - mem_reg->sge.length = page_vec->data_size; - mem_reg->mem_h = fmr; + reg->sge.lkey = fmr->fmr->lkey; + reg->rkey = fmr->fmr->rkey; + reg->sge.addr = page_vec->pages[0] + page_vec->offset; + reg->sge.length = page_vec->data_size; + reg->mem_h = fmr; return 0; } @@ -592,7 +592,7 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, desc = list_first_entry(&fr_pool->list, struct iser_fr_desc, list); - err = iser_reg_page_vec(iser_task, mem, &desc->rsc, mem_reg); + err = iser_fast_reg_fmr(iser_task, mem, &desc->rsc, mem_reg); if (err && err != -EAGAIN) { iser_data_buf_dump(mem, ibdev); iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", -- GitLab From 81722909c8f78ee2db62373a74ec2ecb709c112e Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:01 +0300 Subject: [PATCH 5819/7006] IB/iser: Make reg_desc_get a per device routine As for fmrs we will hold a single registration descriptor as no need for multiple like in the frwr mode (descriptor for each task). This change helps unifying the duplicate registration code paths. Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 16 ++++++++-- drivers/infiniband/ulp/iser/iser_memory.c | 38 +++++++++++++++++------ 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index a8c81774ca53f..611abaa8e7140 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -333,6 +333,8 @@ struct iser_comp { * @free_reg_res: Free registration resources * @reg_rdma_mem: Register memory buffers * @unreg_rdma_mem: Un-register memory buffers + * @reg_desc_get: Get a registration descriptor for pool + * @reg_desc_put: Get a registration descriptor to pool */ struct iser_reg_ops { int (*alloc_reg_res)(struct ib_conn *ib_conn, @@ -342,6 +344,9 @@ struct iser_reg_ops { enum iser_data_dir cmd_dir); void (*unreg_rdma_mem)(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir); + struct iser_fr_desc * (*reg_desc_get)(struct ib_conn *ib_conn); + void (*reg_desc_put)(struct ib_conn *ib_conn, + struct iser_fr_desc *desc); }; /** @@ -657,8 +662,13 @@ void iser_free_fastreg_pool(struct ib_conn *ib_conn); u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir, sector_t *sector); struct iser_fr_desc * -iser_reg_desc_get(struct ib_conn *ib_conn); +iser_reg_desc_get_fr(struct ib_conn *ib_conn); void -iser_reg_desc_put(struct ib_conn *ib_conn, - struct iser_fr_desc *desc); +iser_reg_desc_put_fr(struct ib_conn *ib_conn, + struct iser_fr_desc *desc); +struct iser_fr_desc * +iser_reg_desc_get_fmr(struct ib_conn *ib_conn); +void +iser_reg_desc_put_fmr(struct ib_conn *ib_conn, + struct iser_fr_desc *desc); #endif diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 300e23c1e5064..7ee7f44318ac1 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -44,6 +44,8 @@ static struct iser_reg_ops fastreg_ops = { .free_reg_res = iser_free_fastreg_pool, .reg_rdma_mem = iser_reg_rdma_mem_fastreg, .unreg_rdma_mem = iser_unreg_mem_fastreg, + .reg_desc_get = iser_reg_desc_get_fr, + .reg_desc_put = iser_reg_desc_put_fr, }; static struct iser_reg_ops fmr_ops = { @@ -51,6 +53,8 @@ static struct iser_reg_ops fmr_ops = { .free_reg_res = iser_free_fmr_pool, .reg_rdma_mem = iser_reg_rdma_mem_fmr, .unreg_rdma_mem = iser_unreg_mem_fmr, + .reg_desc_get = iser_reg_desc_get_fmr, + .reg_desc_put = iser_reg_desc_put_fmr, }; int iser_assign_reg_ops(struct iser_device *device) @@ -182,7 +186,7 @@ iser_copy_to_bounce(struct iser_data_buf *data) } struct iser_fr_desc * -iser_reg_desc_get(struct ib_conn *ib_conn) +iser_reg_desc_get_fr(struct ib_conn *ib_conn) { struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_fr_desc *desc; @@ -198,8 +202,8 @@ iser_reg_desc_get(struct ib_conn *ib_conn) } void -iser_reg_desc_put(struct ib_conn *ib_conn, - struct iser_fr_desc *desc) +iser_reg_desc_put_fr(struct ib_conn *ib_conn, + struct iser_fr_desc *desc) { struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; unsigned long flags; @@ -209,6 +213,21 @@ iser_reg_desc_put(struct ib_conn *ib_conn, spin_unlock_irqrestore(&fr_pool->lock, flags); } +struct iser_fr_desc * +iser_reg_desc_get_fmr(struct ib_conn *ib_conn) +{ + struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; + + return list_first_entry(&fr_pool->list, + struct iser_fr_desc, list); +} + +void +iser_reg_desc_put_fmr(struct ib_conn *ib_conn, + struct iser_fr_desc *desc) +{ +} + /** * iser_start_rdma_unaligned_sg */ @@ -544,13 +563,14 @@ void iser_unreg_mem_fmr(struct iscsi_iser_task *iser_task, void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir) { + struct iser_device *device = iser_task->iser_conn->ib_conn.device; struct iser_mem_reg *reg = &iser_task->rdma_reg[cmd_dir]; if (!reg->mem_h) return; - iser_reg_desc_put(&iser_task->iser_conn->ib_conn, - reg->mem_h); + device->reg_ops->reg_desc_put(&iser_task->iser_conn->ib_conn, + reg->mem_h); reg->mem_h = NULL; } @@ -564,7 +584,6 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir) { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; - struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; struct iser_device *device = ib_conn->device; struct ib_device *ibdev = device->ib_device; struct iser_data_buf *mem = &iser_task->data[cmd_dir]; @@ -590,8 +609,7 @@ int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, } else { /* use FMR for multiple dma entries */ struct iser_fr_desc *desc; - desc = list_first_entry(&fr_pool->list, - struct iser_fr_desc, list); + desc = device->reg_ops->reg_desc_get(ib_conn); err = iser_fast_reg_fmr(iser_task, mem, &desc->rsc, mem_reg); if (err && err != -EAGAIN) { iser_data_buf_dump(mem, ibdev); @@ -844,7 +862,7 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, if (mem->dma_nents != 1 || scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) { - desc = iser_reg_desc_get(ib_conn); + desc = device->reg_ops->reg_desc_get(ib_conn); mem_reg->mem_h = desc; } @@ -887,7 +905,7 @@ int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, return 0; err_reg: if (desc) - iser_reg_desc_put(ib_conn, desc); + device->reg_ops->reg_desc_put(ib_conn, desc); return err; } -- GitLab From 32467c420bb68776ebaa53ddf6712e1dba7bb5da Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:02 +0300 Subject: [PATCH 5820/7006] IB/iser: Unify fast memory registration flows iser_reg_rdma_mem_[fastreg|fmr] share a lot of code, and logically do the same thing other than the buffer registration method itself (iser_fast_reg_mr vs. iser_fast_reg_fmr). The DIF logic is not implemented in the FMR flow as there is no existing device that supports FMRs and Signature feature. This patch unifies the flow in a single routine iser_reg_rdma_mem and just split to fmr/frwr for the buffer registration itself. Also, for symmetry reasons, unify iser_unreg_rdma_mem (which will call the relevant device specific unreg routine). Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 23 +- drivers/infiniband/ulp/iser/iser_initiator.c | 11 +- drivers/infiniband/ulp/iser/iser_memory.c | 210 +++++++++---------- 3 files changed, 113 insertions(+), 131 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 611abaa8e7140..e6105d25e6c8f 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -239,6 +239,7 @@ struct iser_data_buf { struct iser_device; struct iscsi_iser_task; struct iscsi_endpoint; +struct iser_reg_resources; /** * struct iser_mem_reg - iSER memory registration info @@ -331,8 +332,8 @@ struct iser_comp { * * @alloc_reg_res: Allocate registration resources * @free_reg_res: Free registration resources - * @reg_rdma_mem: Register memory buffers - * @unreg_rdma_mem: Un-register memory buffers + * @fast_reg_mem: Register memory buffers + * @unreg_mem: Un-register memory buffers * @reg_desc_get: Get a registration descriptor for pool * @reg_desc_put: Get a registration descriptor to pool */ @@ -340,10 +341,12 @@ struct iser_reg_ops { int (*alloc_reg_res)(struct ib_conn *ib_conn, unsigned cmds_max); void (*free_reg_res)(struct ib_conn *ib_conn); - int (*reg_rdma_mem)(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir); - void (*unreg_rdma_mem)(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir); + int (*reg_mem)(struct iscsi_iser_task *iser_task, + struct iser_data_buf *mem, + struct iser_reg_resources *rsc, + struct iser_mem_reg *reg); + void (*unreg_mem)(struct iscsi_iser_task *iser_task, + enum iser_data_dir cmd_dir); struct iser_fr_desc * (*reg_desc_get)(struct ib_conn *ib_conn); void (*reg_desc_put)(struct ib_conn *ib_conn, struct iser_fr_desc *desc); @@ -622,10 +625,10 @@ void iser_finalize_rdma_unaligned_sg(struct iscsi_iser_task *iser_task, struct iser_data_buf *mem, enum iser_data_dir cmd_dir); -int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *task, - enum iser_data_dir cmd_dir); -int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *task, - enum iser_data_dir cmd_dir); +int iser_reg_rdma_mem(struct iscsi_iser_task *task, + enum iser_data_dir dir); +void iser_unreg_rdma_mem(struct iscsi_iser_task *task, + enum iser_data_dir dir); int iser_connect(struct iser_conn *iser_conn, struct sockaddr *src_addr, diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index beacd5f0af1d1..ae19c69e761c5 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -49,7 +49,6 @@ static int iser_prepare_read_cmd(struct iscsi_task *task) { struct iscsi_iser_task *iser_task = task->dd_data; - struct iser_device *device = iser_task->iser_conn->ib_conn.device; struct iser_mem_reg *mem_reg; int err; struct iser_hdr *hdr = &iser_task->desc.iser_header; @@ -73,7 +72,7 @@ static int iser_prepare_read_cmd(struct iscsi_task *task) return err; } - err = device->reg_ops->reg_rdma_mem(iser_task, ISER_DIR_IN); + err = iser_reg_rdma_mem(iser_task, ISER_DIR_IN); if (err) { iser_err("Failed to set up Data-IN RDMA\n"); return err; @@ -103,7 +102,6 @@ iser_prepare_write_cmd(struct iscsi_task *task, unsigned int edtl) { struct iscsi_iser_task *iser_task = task->dd_data; - struct iser_device *device = iser_task->iser_conn->ib_conn.device; struct iser_mem_reg *mem_reg; int err; struct iser_hdr *hdr = &iser_task->desc.iser_header; @@ -128,7 +126,7 @@ iser_prepare_write_cmd(struct iscsi_task *task, return err; } - err = device->reg_ops->reg_rdma_mem(iser_task, ISER_DIR_OUT); + err = iser_reg_rdma_mem(iser_task, ISER_DIR_OUT); if (err != 0) { iser_err("Failed to register write cmd RDMA mem\n"); return err; @@ -662,7 +660,6 @@ void iser_task_rdma_init(struct iscsi_iser_task *iser_task) void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) { - struct iser_device *device = iser_task->iser_conn->ib_conn.device; int is_rdma_data_aligned = 1; int is_rdma_prot_aligned = 1; int prot_count = scsi_prot_sg_count(iser_task->sc); @@ -699,7 +696,7 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) } if (iser_task->dir[ISER_DIR_IN]) { - device->reg_ops->unreg_rdma_mem(iser_task, ISER_DIR_IN); + iser_unreg_rdma_mem(iser_task, ISER_DIR_IN); if (is_rdma_data_aligned) iser_dma_unmap_task_data(iser_task, &iser_task->data[ISER_DIR_IN], @@ -711,7 +708,7 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task) } if (iser_task->dir[ISER_DIR_OUT]) { - device->reg_ops->unreg_rdma_mem(iser_task, ISER_DIR_OUT); + iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT); if (is_rdma_data_aligned) iser_dma_unmap_task_data(iser_task, &iser_task->data[ISER_DIR_OUT], diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 7ee7f44318ac1..b1261d5fbb9b1 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -38,12 +38,22 @@ #include #include "iscsi_iser.h" +static +int iser_fast_reg_fmr(struct iscsi_iser_task *iser_task, + struct iser_data_buf *mem, + struct iser_reg_resources *rsc, + struct iser_mem_reg *mem_reg); +static +int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, + struct iser_data_buf *mem, + struct iser_reg_resources *rsc, + struct iser_mem_reg *mem_reg); static struct iser_reg_ops fastreg_ops = { .alloc_reg_res = iser_alloc_fastreg_pool, .free_reg_res = iser_free_fastreg_pool, - .reg_rdma_mem = iser_reg_rdma_mem_fastreg, - .unreg_rdma_mem = iser_unreg_mem_fastreg, + .reg_mem = iser_fast_reg_mr, + .unreg_mem = iser_unreg_mem_fastreg, .reg_desc_get = iser_reg_desc_get_fr, .reg_desc_put = iser_reg_desc_put_fr, }; @@ -51,8 +61,8 @@ static struct iser_reg_ops fastreg_ops = { static struct iser_reg_ops fmr_ops = { .alloc_reg_res = iser_alloc_fmr_pool, .free_reg_res = iser_free_fmr_pool, - .reg_rdma_mem = iser_reg_rdma_mem_fmr, - .unreg_rdma_mem = iser_unreg_mem_fmr, + .reg_mem = iser_fast_reg_fmr, + .unreg_mem = iser_unreg_mem_fmr, .reg_desc_get = iser_reg_desc_get_fmr, .reg_desc_put = iser_reg_desc_put_fmr, }; @@ -574,62 +584,6 @@ void iser_unreg_mem_fastreg(struct iscsi_iser_task *iser_task, reg->mem_h = NULL; } -/** - * iser_reg_rdma_mem_fmr - Registers memory intended for RDMA, - * using FMR (if possible) obtaining rkey and va - * - * returns 0 on success, errno code on failure - */ -int iser_reg_rdma_mem_fmr(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir) -{ - struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; - struct iser_device *device = ib_conn->device; - struct ib_device *ibdev = device->ib_device; - struct iser_data_buf *mem = &iser_task->data[cmd_dir]; - struct iser_mem_reg *mem_reg; - int aligned_len; - int err; - int i; - - mem_reg = &iser_task->rdma_reg[cmd_dir]; - - aligned_len = iser_data_buf_aligned_len(mem, ibdev); - if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, mem, cmd_dir); - if (err) { - iser_err("failed to allocate bounce buffer\n"); - return err; - } - } - - /* if there a single dma entry, FMR is not needed */ - if (mem->dma_nents == 1) { - return iser_reg_dma(device, mem, mem_reg); - } else { /* use FMR for multiple dma entries */ - struct iser_fr_desc *desc; - - desc = device->reg_ops->reg_desc_get(ib_conn); - err = iser_fast_reg_fmr(iser_task, mem, &desc->rsc, mem_reg); - if (err && err != -EAGAIN) { - iser_data_buf_dump(mem, ibdev); - iser_err("mem->dma_nents = %d (dlength = 0x%x)\n", - mem->dma_nents, - ntoh24(iser_task->desc.iscsi_header.dlength)); - iser_err("page_vec: data_size = 0x%x, length = %d, offset = 0x%x\n", - desc->rsc.page_vec->data_size, - desc->rsc.page_vec->length, - desc->rsc.page_vec->offset); - for (i = 0; i < desc->rsc.page_vec->length; i++) - iser_err("page_vec[%d] = 0x%llx\n", i, - (unsigned long long)desc->rsc.page_vec->pages[i]); - } - if (err) - return err; - } - return 0; -} - static void iser_set_dif_domain(struct scsi_cmnd *sc, struct ib_sig_attrs *sig_attrs, struct ib_sig_domain *domain) @@ -775,19 +729,12 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, { struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; struct iser_device *device = ib_conn->device; - struct ib_mr *mr; - struct ib_fast_reg_page_list *frpl; + struct ib_mr *mr = rsc->mr; + struct ib_fast_reg_page_list *frpl = rsc->frpl; struct ib_send_wr fastreg_wr, inv_wr; struct ib_send_wr *bad_wr, *wr = NULL; int ret, offset, size, plen; - /* if there a single dma entry, dma mr suffices */ - if (mem->dma_nents == 1) - return iser_reg_dma(device, mem, reg); - - mr = rsc->mr; - frpl = rsc->frpl; - plen = iser_sg_to_page_vec(mem, device->ib_device, frpl->page_list, &offset, &size); if (plen * SIZE_4K < size) { @@ -834,78 +781,113 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, return ret; } -/** - * iser_reg_rdma_mem_fastreg - Registers memory intended for RDMA, - * using Fast Registration WR (if possible) obtaining rkey and va - * - * returns 0 on success, errno code on failure - */ -int iser_reg_rdma_mem_fastreg(struct iscsi_iser_task *iser_task, - enum iser_data_dir cmd_dir) +static int +iser_handle_unaligned_buf(struct iscsi_iser_task *task, + struct iser_data_buf *mem, + enum iser_data_dir dir) { - struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; - struct iser_device *device = ib_conn->device; - struct ib_device *ibdev = device->ib_device; - struct iser_data_buf *mem = &iser_task->data[cmd_dir]; - struct iser_mem_reg *mem_reg = &iser_task->rdma_reg[cmd_dir]; - struct iser_fr_desc *desc = NULL; + struct iser_conn *iser_conn = task->iser_conn; + struct iser_device *device = iser_conn->ib_conn.device; int err, aligned_len; - aligned_len = iser_data_buf_aligned_len(mem, ibdev); + aligned_len = iser_data_buf_aligned_len(mem, device->ib_device); if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, mem, cmd_dir); - if (err) { - iser_err("failed to allocate bounce buffer\n"); + err = fall_to_bounce_buf(task, mem, dir); + if (err) return err; - } } + return 0; +} + +static int +iser_reg_prot_sg(struct iscsi_iser_task *task, + struct iser_data_buf *mem, + struct iser_fr_desc *desc, + struct iser_mem_reg *reg) +{ + struct iser_device *device = task->iser_conn->ib_conn.device; + + if (mem->dma_nents == 1) + return iser_reg_dma(device, mem, reg); + + return device->reg_ops->reg_mem(task, mem, &desc->pi_ctx->rsc, reg); +} + +static int +iser_reg_data_sg(struct iscsi_iser_task *task, + struct iser_data_buf *mem, + struct iser_fr_desc *desc, + struct iser_mem_reg *reg) +{ + struct iser_device *device = task->iser_conn->ib_conn.device; + + if (mem->dma_nents == 1) + return iser_reg_dma(device, mem, reg); + + return device->reg_ops->reg_mem(task, mem, &desc->rsc, reg); +} + +int iser_reg_rdma_mem(struct iscsi_iser_task *task, + enum iser_data_dir dir) +{ + struct ib_conn *ib_conn = &task->iser_conn->ib_conn; + struct iser_device *device = ib_conn->device; + struct iser_data_buf *mem = &task->data[dir]; + struct iser_mem_reg *reg = &task->rdma_reg[dir]; + struct iser_fr_desc *desc = NULL; + int err; + + err = iser_handle_unaligned_buf(task, mem, dir); + if (unlikely(err)) + return err; + if (mem->dma_nents != 1 || - scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) { + scsi_get_prot_op(task->sc) != SCSI_PROT_NORMAL) { desc = device->reg_ops->reg_desc_get(ib_conn); - mem_reg->mem_h = desc; + reg->mem_h = desc; } - err = iser_fast_reg_mr(iser_task, mem, - desc ? &desc->rsc : NULL, mem_reg); - if (err) + err = iser_reg_data_sg(task, mem, desc, reg); + if (unlikely(err)) goto err_reg; - if (scsi_get_prot_op(iser_task->sc) != SCSI_PROT_NORMAL) { + if (scsi_get_prot_op(task->sc) != SCSI_PROT_NORMAL) { struct iser_mem_reg prot_reg; memset(&prot_reg, 0, sizeof(prot_reg)); - if (scsi_prot_sg_count(iser_task->sc)) { - mem = &iser_task->prot[cmd_dir]; - aligned_len = iser_data_buf_aligned_len(mem, ibdev); - if (aligned_len != mem->dma_nents) { - err = fall_to_bounce_buf(iser_task, mem, - cmd_dir); - if (err) { - iser_err("failed to allocate bounce buffer\n"); - return err; - } - } + if (scsi_prot_sg_count(task->sc)) { + mem = &task->prot[dir]; + err = iser_handle_unaligned_buf(task, mem, dir); + if (unlikely(err)) + goto err_reg; - err = iser_fast_reg_mr(iser_task, mem, - &desc->pi_ctx->rsc, &prot_reg); - if (err) + err = iser_reg_prot_sg(task, mem, desc, &prot_reg); + if (unlikely(err)) goto err_reg; } - err = iser_reg_sig_mr(iser_task, desc->pi_ctx, mem_reg, - &prot_reg, mem_reg); - if (err) { - iser_err("Failed to register signature mr\n"); - return err; - } + err = iser_reg_sig_mr(task, desc->pi_ctx, reg, + &prot_reg, reg); + if (unlikely(err)) + goto err_reg; + desc->pi_ctx->sig_protected = 1; } return 0; + err_reg: if (desc) device->reg_ops->reg_desc_put(ib_conn, desc); return err; } + +void iser_unreg_rdma_mem(struct iscsi_iser_task *task, + enum iser_data_dir dir) +{ + struct iser_device *device = task->iser_conn->ib_conn.device; + + device->reg_ops->unreg_mem(task, dir); +} -- GitLab From f8db651da29bcad213d43328ebf8ce8459f526a7 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:03 +0300 Subject: [PATCH 5821/7006] IB/iser: Pass registration pool a size parameter Hard coded for now. This will allow to allocate different sized MRs depending on the IO size needed (and device capabilities). This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.h | 11 +++-- drivers/infiniband/ulp/iser/iser_initiator.c | 3 +- drivers/infiniband/ulp/iser/iser_verbs.c | 47 +++++++++++--------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index e6105d25e6c8f..e9ebe0b2263d0 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -339,7 +339,8 @@ struct iser_comp { */ struct iser_reg_ops { int (*alloc_reg_res)(struct ib_conn *ib_conn, - unsigned cmds_max); + unsigned cmds_max, + unsigned int size); void (*free_reg_res)(struct ib_conn *ib_conn); int (*reg_mem)(struct iscsi_iser_task *iser_task, struct iser_data_buf *mem, @@ -658,9 +659,13 @@ int iser_initialize_task_headers(struct iscsi_task *task, struct iser_tx_desc *tx_desc); int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, struct iscsi_session *session); -int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max); +int iser_alloc_fmr_pool(struct ib_conn *ib_conn, + unsigned cmds_max, + unsigned int size); void iser_free_fmr_pool(struct ib_conn *ib_conn); -int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max); +int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, + unsigned cmds_max, + unsigned int size); void iser_free_fastreg_pool(struct ib_conn *ib_conn); u8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, enum iser_data_dir cmd_dir, sector_t *sector); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index ae19c69e761c5..f1200f27b6a70 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -258,7 +258,8 @@ int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, iser_conn->qp_max_recv_dtos_mask = session->cmds_max - 1; /* cmds_max is 2^N */ iser_conn->min_posted_rx = iser_conn->qp_max_recv_dtos >> 2; - if (device->reg_ops->alloc_reg_res(ib_conn, session->scsi_cmds_max)) + if (device->reg_ops->alloc_reg_res(ib_conn, session->scsi_cmds_max, + ISCSI_ISER_SG_TABLESIZE + 1)) goto create_rdma_reg_res_failed; if (iser_alloc_login_buf(iser_conn)) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 5b5432d95b00f..0ade0e876c79f 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -199,7 +199,9 @@ static void iser_free_device_ib_res(struct iser_device *device) * * returns 0 on success, or errno code on failure */ -int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) +int iser_alloc_fmr_pool(struct ib_conn *ib_conn, + unsigned cmds_max, + unsigned int size) { struct iser_device *device = ib_conn->device; struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; @@ -216,8 +218,7 @@ int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) if (!desc) return -ENOMEM; - page_vec = kmalloc(sizeof(*page_vec) + - (sizeof(u64) * (ISCSI_ISER_SG_TABLESIZE + 1)), + page_vec = kmalloc(sizeof(*page_vec) + (sizeof(u64) * size), GFP_KERNEL); if (!page_vec) { ret = -ENOMEM; @@ -227,9 +228,7 @@ int iser_alloc_fmr_pool(struct ib_conn *ib_conn, unsigned cmds_max) page_vec->pages = (u64 *)(page_vec + 1); params.page_shift = SHIFT_4K; - /* when the first/last SG element are not start/end * - * page aligned, the map whould be of N+1 pages */ - params.max_pages_per_fmr = ISCSI_ISER_SG_TABLESIZE + 1; + params.max_pages_per_fmr = size; /* make the pool size twice the max number of SCSI commands * * the ML is expected to queue, watermark for unmap at 50% */ params.pool_size = cmds_max * 2; @@ -282,13 +281,14 @@ void iser_free_fmr_pool(struct ib_conn *ib_conn) } static int -iser_alloc_reg_res(struct ib_device *ib_device, struct ib_pd *pd, - struct iser_reg_resources *res) +iser_alloc_reg_res(struct ib_device *ib_device, + struct ib_pd *pd, + struct iser_reg_resources *res, + unsigned int size) { int ret; - res->frpl = ib_alloc_fast_reg_page_list(ib_device, - ISCSI_ISER_SG_TABLESIZE + 1); + res->frpl = ib_alloc_fast_reg_page_list(ib_device, size); if (IS_ERR(res->frpl)) { ret = PTR_ERR(res->frpl); iser_err("Failed to allocate ib_fast_reg_page_list err=%d\n", @@ -296,8 +296,7 @@ iser_alloc_reg_res(struct ib_device *ib_device, struct ib_pd *pd, return PTR_ERR(res->frpl); } - res->mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, - ISCSI_ISER_SG_TABLESIZE + 1); + res->mr = ib_alloc_mr(pd, IB_MR_TYPE_MEM_REG, size); if (IS_ERR(res->mr)) { ret = PTR_ERR(res->mr); iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); @@ -321,8 +320,10 @@ iser_free_reg_res(struct iser_reg_resources *rsc) } static int -iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, - struct iser_fr_desc *desc) +iser_alloc_pi_ctx(struct ib_device *ib_device, + struct ib_pd *pd, + struct iser_fr_desc *desc, + unsigned int size) { struct iser_pi_context *pi_ctx = NULL; int ret; @@ -333,7 +334,7 @@ iser_alloc_pi_ctx(struct ib_device *ib_device, struct ib_pd *pd, pi_ctx = desc->pi_ctx; - ret = iser_alloc_reg_res(ib_device, pd, &pi_ctx->rsc); + ret = iser_alloc_reg_res(ib_device, pd, &pi_ctx->rsc, size); if (ret) { iser_err("failed to allocate reg_resources\n"); goto alloc_reg_res_err; @@ -366,8 +367,10 @@ iser_free_pi_ctx(struct iser_pi_context *pi_ctx) } static struct iser_fr_desc * -iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, - bool pi_enable) +iser_create_fastreg_desc(struct ib_device *ib_device, + struct ib_pd *pd, + bool pi_enable, + unsigned int size) { struct iser_fr_desc *desc; int ret; @@ -376,12 +379,12 @@ iser_create_fastreg_desc(struct ib_device *ib_device, struct ib_pd *pd, if (!desc) return ERR_PTR(-ENOMEM); - ret = iser_alloc_reg_res(ib_device, pd, &desc->rsc); + ret = iser_alloc_reg_res(ib_device, pd, &desc->rsc, size); if (ret) goto reg_res_alloc_failure; if (pi_enable) { - ret = iser_alloc_pi_ctx(ib_device, pd, desc); + ret = iser_alloc_pi_ctx(ib_device, pd, desc, size); if (ret) goto pi_ctx_alloc_failure; } @@ -401,7 +404,9 @@ reg_res_alloc_failure: * for fast registration work requests. * returns 0 on success, or errno code on failure */ -int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) +int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, + unsigned cmds_max, + unsigned int size) { struct iser_device *device = ib_conn->device; struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; @@ -413,7 +418,7 @@ int iser_alloc_fastreg_pool(struct ib_conn *ib_conn, unsigned cmds_max) fr_pool->size = 0; for (i = 0; i < cmds_max; i++) { desc = iser_create_fastreg_desc(device->ib_device, device->pd, - ib_conn->pi_support); + ib_conn->pi_support, size); if (IS_ERR(desc)) { ret = PTR_ERR(desc); goto err; -- GitLab From df749cdc45d9f97cb0a5e6ceab80e2e00ee9bf85 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:04 +0300 Subject: [PATCH 5822/7006] IB/iser: Support up to 8MB data transfer in a single command iser support up to 512KB data transfer in a single scsi command. This means that larger IOs will split to different request. While iser can easily saturate FDR/EDR wires, some arrays are fine tuned for 1MB (or larger) IO sizes, hence add an option to support larger transfers (up to 8MB) if the device allows it. Given that a few target implementations don't support data transfers of more than 512KB by default and the fact that larger IO sizes require more resources, we introduce a module parameter to determine the maximum number of 512B sectors in a single scsi command. Users that are interested in larger transfers can change this value given that the target supports larger transfers. At the moment, iser works in 4K pages granularity, In a later stage we will get it to work with system page size instead. IO operations that consists of N pages will need a page vector of size N+1 in case the first SG element contains an offset. Given that some devices allocates memory regions in powers of 2, this means that allocating a region with N+1 pages, will result in region resources allocation of the next power of 2. Since we don't want that to happen, in case we are in the limit of IO size supported and the first SG element has an offset, we align the SG list using a bounce buffer (which is OK given that this is not likely to happen a lot). Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 10 ++++++-- drivers/infiniband/ulp/iser/iscsi_iser.h | 14 ++++++++-- drivers/infiniband/ulp/iser/iser_initiator.c | 2 +- drivers/infiniband/ulp/iser/iser_memory.c | 14 ++++++++-- drivers/infiniband/ulp/iser/iser_verbs.c | 27 ++++++++++++++++++++ 5 files changed, 60 insertions(+), 7 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 169cc3e75018d..0720bb46589fe 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -93,6 +93,10 @@ static unsigned int iscsi_max_lun = 512; module_param_named(max_lun, iscsi_max_lun, uint, S_IRUGO); MODULE_PARM_DESC(max_lun, "Max LUNs to allow per session (default:512"); +unsigned int iser_max_sectors = ISER_DEF_MAX_SECTORS; +module_param_named(max_sectors, iser_max_sectors, uint, S_IRUGO | S_IWUSR); +MODULE_PARM_DESC(max_sectors, "Max number of sectors in a single scsi command (default:1024"); + bool iser_pi_enable = false; module_param_named(pi_enable, iser_pi_enable, bool, S_IRUGO); MODULE_PARM_DESC(pi_enable, "Enable T10-PI offload support (default:disabled)"); @@ -625,6 +629,8 @@ iscsi_iser_session_create(struct iscsi_endpoint *ep, if (ep) { iser_conn = ep->dd_data; max_cmds = iser_conn->max_cmds; + shost->sg_tablesize = iser_conn->scsi_sg_tablesize; + shost->max_sectors = iser_conn->scsi_max_sectors; mutex_lock(&iser_conn->state_mutex); if (iser_conn->state != ISER_CONN_UP) { @@ -966,8 +972,8 @@ static struct scsi_host_template iscsi_iser_sht = { .name = "iSCSI Initiator over iSER", .queuecommand = iscsi_queuecommand, .change_queue_depth = scsi_change_queue_depth, - .sg_tablesize = ISCSI_ISER_SG_TABLESIZE, - .max_sectors = 1024, + .sg_tablesize = ISCSI_ISER_DEF_SG_TABLESIZE, + .max_sectors = ISER_DEF_MAX_SECTORS, .cmd_per_lun = ISER_DEF_CMD_PER_LUN, .eh_abort_handler = iscsi_eh_abort, .eh_device_reset_handler= iscsi_eh_device_reset, diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index e9ebe0b2263d0..0bdd7e77e5db2 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -98,8 +98,13 @@ #define SHIFT_4K 12 #define SIZE_4K (1ULL << SHIFT_4K) #define MASK_4K (~(SIZE_4K-1)) - /* support up to 512KB in one RDMA */ -#define ISCSI_ISER_SG_TABLESIZE (0x80000 >> SHIFT_4K) + +/* Default support is 512KB I/O size */ +#define ISER_DEF_MAX_SECTORS 1024 +#define ISCSI_ISER_DEF_SG_TABLESIZE ((ISER_DEF_MAX_SECTORS * 512) >> SHIFT_4K) +/* Maximum support is 8MB I/O size */ +#define ISCSI_ISER_MAX_SG_TABLESIZE ((16384 * 512) >> SHIFT_4K) + #define ISER_DEF_XMIT_CMDS_DEFAULT 512 #if ISCSI_DEF_XMIT_CMDS_MAX > ISER_DEF_XMIT_CMDS_DEFAULT #define ISER_DEF_XMIT_CMDS_MAX ISCSI_DEF_XMIT_CMDS_MAX @@ -504,6 +509,8 @@ struct ib_conn { * @rx_desc_head: head of rx_descs cyclic buffer * @rx_descs: rx buffers array (cyclic buffer) * @num_rx_descs: number of rx descriptors + * @scsi_sg_tablesize: scsi host sg_tablesize + * @scsi_max_sectors: scsi host max sectors */ struct iser_conn { struct ib_conn ib_conn; @@ -528,6 +535,8 @@ struct iser_conn { unsigned int rx_desc_head; struct iser_rx_desc *rx_descs; u32 num_rx_descs; + unsigned short scsi_sg_tablesize; + unsigned int scsi_max_sectors; }; /** @@ -583,6 +592,7 @@ extern struct iser_global ig; extern int iser_debug_level; extern bool iser_pi_enable; extern int iser_pi_guard; +extern unsigned int iser_max_sectors; int iser_assign_reg_ops(struct iser_device *device); diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index f1200f27b6a70..0b1f3b54a0c17 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -259,7 +259,7 @@ int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, iser_conn->min_posted_rx = iser_conn->qp_max_recv_dtos >> 2; if (device->reg_ops->alloc_reg_res(ib_conn, session->scsi_cmds_max, - ISCSI_ISER_SG_TABLESIZE + 1)) + iser_conn->scsi_sg_tablesize)) goto create_rdma_reg_res_failed; if (iser_alloc_login_buf(iser_conn)) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index b1261d5fbb9b1..384fd0a49ccab 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -363,7 +363,8 @@ static int iser_sg_to_page_vec(struct iser_data_buf *data, * consecutive SG elements are actually fragments of the same physcial page. */ static int iser_data_buf_aligned_len(struct iser_data_buf *data, - struct ib_device *ibdev) + struct ib_device *ibdev, + unsigned sg_tablesize) { struct scatterlist *sg, *sgl, *next_sg = NULL; u64 start_addr, end_addr; @@ -375,6 +376,14 @@ static int iser_data_buf_aligned_len(struct iser_data_buf *data, sgl = data->sg; start_addr = ib_sg_dma_address(ibdev, sgl); + if (unlikely(sgl[0].offset && + data->data_len >= sg_tablesize * PAGE_SIZE)) { + iser_dbg("can't register length %lx with offset %x " + "fall to bounce buffer\n", data->data_len, + sgl[0].offset); + return 0; + } + for_each_sg(sgl, sg, data->dma_nents, i) { if (start_check && !IS_4K_ALIGNED(start_addr)) break; @@ -790,7 +799,8 @@ iser_handle_unaligned_buf(struct iscsi_iser_task *task, struct iser_device *device = iser_conn->ib_conn.device; int err, aligned_len; - aligned_len = iser_data_buf_aligned_len(mem, device->ib_device); + aligned_len = iser_data_buf_aligned_len(mem, device->ib_device, + iser_conn->scsi_sg_tablesize); if (aligned_len != mem->dma_nents) { err = fall_to_bounce_buf(task, mem, dir); if (err) diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 0ade0e876c79f..187c7125a4b9e 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -756,6 +756,31 @@ static void iser_connect_error(struct rdma_cm_id *cma_id) iser_conn->state = ISER_CONN_TERMINATING; } +static void +iser_calc_scsi_params(struct iser_conn *iser_conn, + unsigned int max_sectors) +{ + struct iser_device *device = iser_conn->ib_conn.device; + unsigned short sg_tablesize, sup_sg_tablesize; + + sg_tablesize = DIV_ROUND_UP(max_sectors * 512, SIZE_4K); + sup_sg_tablesize = min_t(unsigned, ISCSI_ISER_MAX_SG_TABLESIZE, + device->dev_attr.max_fast_reg_page_list_len); + + if (sg_tablesize > sup_sg_tablesize) { + sg_tablesize = sup_sg_tablesize; + iser_conn->scsi_max_sectors = sg_tablesize * SIZE_4K / 512; + } else { + iser_conn->scsi_max_sectors = max_sectors; + } + + iser_conn->scsi_sg_tablesize = sg_tablesize; + + iser_dbg("iser_conn %p, sg_tablesize %u, max_sectors %u\n", + iser_conn, iser_conn->scsi_sg_tablesize, + iser_conn->scsi_max_sectors); +} + /** * Called with state mutex held **/ @@ -794,6 +819,8 @@ static void iser_addr_handler(struct rdma_cm_id *cma_id) } } + iser_calc_scsi_params(iser_conn, iser_max_sectors); + ret = rdma_resolve_route(cma_id, 1000); if (ret) { iser_err("resolve route failed: %d\n", ret); -- GitLab From 1b16c9894b63c8dfbc578ecf1186be4508b2c49e Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:05 +0300 Subject: [PATCH 5823/7006] IB/iser: Add debug prints to the various memory registration methods Easier to debug when we have the registration details. This patch does not change any functionality. Signed-off-by: Sagi Grimberg Signed-off-by: Adir Lev Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_memory.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 384fd0a49ccab..6eadf51884066 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -554,6 +554,10 @@ int iser_fast_reg_fmr(struct iscsi_iser_task *iser_task, reg->sge.length = page_vec->data_size; reg->mem_h = fmr; + iser_dbg("fmr reg: lkey=0x%x, rkey=0x%x, addr=0x%llx," + " length=0x%x\n", reg->sge.lkey, reg->rkey, + reg->sge.addr, reg->sge.length); + return 0; } @@ -724,7 +728,7 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task, sig_reg->sge.addr = 0; sig_reg->sge.length = scsi_transfer_length(iser_task->sc); - iser_dbg("sig_sge: lkey: 0x%x, rkey: 0x%x, addr: 0x%llx, length: %u\n", + iser_dbg("sig reg: lkey: 0x%x, rkey: 0x%x, addr: 0x%llx, length: %u\n", sig_reg->sge.lkey, sig_reg->rkey, sig_reg->sge.addr, sig_reg->sge.length); err: @@ -787,6 +791,10 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, reg->sge.addr = frpl->page_list[0] + offset; reg->sge.length = size; + iser_dbg("fast reg: lkey=0x%x, rkey=0x%x, addr=0x%llx," + " length=0x%x\n", reg->sge.lkey, reg->rkey, + reg->sge.addr, reg->sge.length); + return ret; } -- GitLab From 7332bed085c68fc76462583a1003c6dca2c31e11 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Thu, 6 Aug 2015 18:33:06 +0300 Subject: [PATCH 5824/7006] IB/iser: Chain all iser transaction send work requests Chaning of send work requests benefits performance by reducing the send queue lock contention (acquired in ib_post_send) and saves us HW doorbells which is posted only once. Currently, in normal IO flows iser does not chain the CDB send work request with the registration work request. Also in PI flows, signature work requests are not chained as well. Lets chain those and post only once. Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 1 + drivers/infiniband/ulp/iser/iscsi_iser.h | 34 ++++++ drivers/infiniband/ulp/iser/iser_memory.c | 120 ++++++++++------------ drivers/infiniband/ulp/iser/iser_verbs.c | 21 ++-- 4 files changed, 99 insertions(+), 77 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 0720bb46589fe..e908a1eb800b9 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -204,6 +204,7 @@ iser_initialize_task_headers(struct iscsi_task *task, goto out; } + tx_desc->wr_idx = 0; tx_desc->mapped = true; tx_desc->dma_addr = dma_addr; tx_desc->tx_sg[0].addr = tx_desc->dma_addr; diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h index 0bdd7e77e5db2..86f6583485ef3 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.h +++ b/drivers/infiniband/ulp/iser/iscsi_iser.h @@ -265,6 +265,14 @@ enum iser_desc_type { ISCSI_TX_DATAOUT }; +/* Maximum number of work requests per task: + * Data memory region local invalidate + fast registration + * Protection memory region local invalidate + fast registration + * Signature memory region local invalidate + fast registration + * PDU send + */ +#define ISER_MAX_WRS 7 + /** * struct iser_tx_desc - iSER TX descriptor (for send wr_id) * @@ -277,6 +285,11 @@ enum iser_desc_type { * unsolicited data-out or control * @num_sge: number sges used on this TX task * @mapped: Is the task header mapped + * @wr_idx: Current WR index + * @wrs: Array of WRs per task + * @data_reg: Data buffer registration details + * @prot_reg: Protection buffer registration details + * @sig_attrs: Signature attributes */ struct iser_tx_desc { struct iser_hdr iser_header; @@ -286,6 +299,11 @@ struct iser_tx_desc { struct ib_sge tx_sg[2]; int num_sge; bool mapped; + u8 wr_idx; + struct ib_send_wr wrs[ISER_MAX_WRS]; + struct iser_mem_reg data_reg; + struct iser_mem_reg prot_reg; + struct ib_sig_attrs sig_attrs; }; #define ISER_RX_PAD_SIZE (256 - (ISER_RX_PAYLOAD_SIZE + \ @@ -689,4 +707,20 @@ iser_reg_desc_get_fmr(struct ib_conn *ib_conn); void iser_reg_desc_put_fmr(struct ib_conn *ib_conn, struct iser_fr_desc *desc); + +static inline struct ib_send_wr * +iser_tx_next_wr(struct iser_tx_desc *tx_desc) +{ + struct ib_send_wr *cur_wr = &tx_desc->wrs[tx_desc->wr_idx]; + struct ib_send_wr *last_wr; + + if (tx_desc->wr_idx) { + last_wr = &tx_desc->wrs[tx_desc->wr_idx - 1]; + last_wr->next = cur_wr; + } + tx_desc->wr_idx++; + + return cur_wr; +} + #endif diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 6eadf51884066..09640c811fdd5 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -664,10 +664,11 @@ iser_inv_rkey(struct ib_send_wr *inv_wr, struct ib_mr *mr) { u32 rkey; - memset(inv_wr, 0, sizeof(*inv_wr)); inv_wr->opcode = IB_WR_LOCAL_INV; inv_wr->wr_id = ISER_FASTREG_LI_WRID; inv_wr->ex.invalidate_rkey = mr->rkey; + inv_wr->send_flags = 0; + inv_wr->num_sge = 0; rkey = ib_inc_rkey(mr->rkey); ib_update_fast_reg_key(mr, rkey); @@ -680,47 +681,38 @@ iser_reg_sig_mr(struct iscsi_iser_task *iser_task, struct iser_mem_reg *prot_reg, struct iser_mem_reg *sig_reg) { - struct ib_conn *ib_conn = &iser_task->iser_conn->ib_conn; - struct ib_send_wr sig_wr, inv_wr; - struct ib_send_wr *bad_wr, *wr = NULL; - struct ib_sig_attrs sig_attrs; + struct iser_tx_desc *tx_desc = &iser_task->desc; + struct ib_sig_attrs *sig_attrs = &tx_desc->sig_attrs; + struct ib_send_wr *wr; int ret; - memset(&sig_attrs, 0, sizeof(sig_attrs)); - ret = iser_set_sig_attrs(iser_task->sc, &sig_attrs); + memset(sig_attrs, 0, sizeof(*sig_attrs)); + ret = iser_set_sig_attrs(iser_task->sc, sig_attrs); if (ret) goto err; - iser_set_prot_checks(iser_task->sc, &sig_attrs.check_mask); + iser_set_prot_checks(iser_task->sc, &sig_attrs->check_mask); if (!pi_ctx->sig_mr_valid) { - iser_inv_rkey(&inv_wr, pi_ctx->sig_mr); - wr = &inv_wr; + wr = iser_tx_next_wr(tx_desc); + iser_inv_rkey(wr, pi_ctx->sig_mr); } - memset(&sig_wr, 0, sizeof(sig_wr)); - sig_wr.opcode = IB_WR_REG_SIG_MR; - sig_wr.wr_id = ISER_FASTREG_LI_WRID; - sig_wr.sg_list = &data_reg->sge; - sig_wr.num_sge = 1; - sig_wr.wr.sig_handover.sig_attrs = &sig_attrs; - sig_wr.wr.sig_handover.sig_mr = pi_ctx->sig_mr; + wr = iser_tx_next_wr(tx_desc); + wr->opcode = IB_WR_REG_SIG_MR; + wr->wr_id = ISER_FASTREG_LI_WRID; + wr->sg_list = &data_reg->sge; + wr->num_sge = 1; + wr->send_flags = 0; + wr->wr.sig_handover.sig_attrs = sig_attrs; + wr->wr.sig_handover.sig_mr = pi_ctx->sig_mr; if (scsi_prot_sg_count(iser_task->sc)) - sig_wr.wr.sig_handover.prot = &prot_reg->sge; - sig_wr.wr.sig_handover.access_flags = IB_ACCESS_LOCAL_WRITE | - IB_ACCESS_REMOTE_READ | - IB_ACCESS_REMOTE_WRITE; - - if (!wr) - wr = &sig_wr; + wr->wr.sig_handover.prot = &prot_reg->sge; else - wr->next = &sig_wr; - - ret = ib_post_send(ib_conn->qp, wr, &bad_wr); - if (ret) { - iser_err("reg_sig_mr failed, ret:%d\n", ret); - goto err; - } + wr->wr.sig_handover.prot = NULL; + wr->wr.sig_handover.access_flags = IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_READ | + IB_ACCESS_REMOTE_WRITE; pi_ctx->sig_mr_valid = 0; sig_reg->sge.lkey = pi_ctx->sig_mr->lkey; @@ -744,9 +736,9 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, struct iser_device *device = ib_conn->device; struct ib_mr *mr = rsc->mr; struct ib_fast_reg_page_list *frpl = rsc->frpl; - struct ib_send_wr fastreg_wr, inv_wr; - struct ib_send_wr *bad_wr, *wr = NULL; - int ret, offset, size, plen; + struct iser_tx_desc *tx_desc = &iser_task->desc; + struct ib_send_wr *wr; + int offset, size, plen; plen = iser_sg_to_page_vec(mem, device->ib_device, frpl->page_list, &offset, &size); @@ -756,34 +748,23 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, } if (!rsc->mr_valid) { - iser_inv_rkey(&inv_wr, mr); - wr = &inv_wr; + wr = iser_tx_next_wr(tx_desc); + iser_inv_rkey(wr, mr); } - /* Prepare FASTREG WR */ - memset(&fastreg_wr, 0, sizeof(fastreg_wr)); - fastreg_wr.wr_id = ISER_FASTREG_LI_WRID; - fastreg_wr.opcode = IB_WR_FAST_REG_MR; - fastreg_wr.wr.fast_reg.iova_start = frpl->page_list[0] + offset; - fastreg_wr.wr.fast_reg.page_list = frpl; - fastreg_wr.wr.fast_reg.page_list_len = plen; - fastreg_wr.wr.fast_reg.page_shift = SHIFT_4K; - fastreg_wr.wr.fast_reg.length = size; - fastreg_wr.wr.fast_reg.rkey = mr->rkey; - fastreg_wr.wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE | - IB_ACCESS_REMOTE_WRITE | - IB_ACCESS_REMOTE_READ); - - if (!wr) - wr = &fastreg_wr; - else - wr->next = &fastreg_wr; - - ret = ib_post_send(ib_conn->qp, wr, &bad_wr); - if (ret) { - iser_err("fast registration failed, ret:%d\n", ret); - return ret; - } + wr = iser_tx_next_wr(tx_desc); + wr->opcode = IB_WR_FAST_REG_MR; + wr->wr_id = ISER_FASTREG_LI_WRID; + wr->send_flags = 0; + wr->wr.fast_reg.iova_start = frpl->page_list[0] + offset; + wr->wr.fast_reg.page_list = frpl; + wr->wr.fast_reg.page_list_len = plen; + wr->wr.fast_reg.page_shift = SHIFT_4K; + wr->wr.fast_reg.length = size; + wr->wr.fast_reg.rkey = mr->rkey; + wr->wr.fast_reg.access_flags = (IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_WRITE | + IB_ACCESS_REMOTE_READ); rsc->mr_valid = 0; reg->sge.lkey = mr->lkey; @@ -795,7 +776,7 @@ static int iser_fast_reg_mr(struct iscsi_iser_task *iser_task, " length=0x%x\n", reg->sge.lkey, reg->rkey, reg->sge.addr, reg->sge.length); - return ret; + return 0; } static int @@ -853,6 +834,7 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *task, struct iser_device *device = ib_conn->device; struct iser_data_buf *mem = &task->data[dir]; struct iser_mem_reg *reg = &task->rdma_reg[dir]; + struct iser_mem_reg *data_reg; struct iser_fr_desc *desc = NULL; int err; @@ -866,27 +848,31 @@ int iser_reg_rdma_mem(struct iscsi_iser_task *task, reg->mem_h = desc; } - err = iser_reg_data_sg(task, mem, desc, reg); + if (scsi_get_prot_op(task->sc) == SCSI_PROT_NORMAL) + data_reg = reg; + else + data_reg = &task->desc.data_reg; + + err = iser_reg_data_sg(task, mem, desc, data_reg); if (unlikely(err)) goto err_reg; if (scsi_get_prot_op(task->sc) != SCSI_PROT_NORMAL) { - struct iser_mem_reg prot_reg; + struct iser_mem_reg *prot_reg = &task->desc.prot_reg; - memset(&prot_reg, 0, sizeof(prot_reg)); if (scsi_prot_sg_count(task->sc)) { mem = &task->prot[dir]; err = iser_handle_unaligned_buf(task, mem, dir); if (unlikely(err)) goto err_reg; - err = iser_reg_prot_sg(task, mem, desc, &prot_reg); + err = iser_reg_prot_sg(task, mem, desc, prot_reg); if (unlikely(err)) goto err_reg; } - err = iser_reg_sig_mr(task, desc->pi_ctx, reg, - &prot_reg, reg); + err = iser_reg_sig_mr(task, desc->pi_ctx, data_reg, + prot_reg, reg); if (unlikely(err)) goto err_reg; diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 187c7125a4b9e..6f5be47a6b90c 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -1116,23 +1116,24 @@ int iser_post_recvm(struct iser_conn *iser_conn, int count) int iser_post_send(struct ib_conn *ib_conn, struct iser_tx_desc *tx_desc, bool signal) { - int ib_ret; - struct ib_send_wr send_wr, *send_wr_failed; + struct ib_send_wr *bad_wr, *wr = iser_tx_next_wr(tx_desc); + int ib_ret; ib_dma_sync_single_for_device(ib_conn->device->ib_device, tx_desc->dma_addr, ISER_HEADERS_LEN, DMA_TO_DEVICE); - send_wr.next = NULL; - send_wr.wr_id = (uintptr_t)tx_desc; - send_wr.sg_list = tx_desc->tx_sg; - send_wr.num_sge = tx_desc->num_sge; - send_wr.opcode = IB_WR_SEND; - send_wr.send_flags = signal ? IB_SEND_SIGNALED : 0; + wr->next = NULL; + wr->wr_id = (uintptr_t)tx_desc; + wr->sg_list = tx_desc->tx_sg; + wr->num_sge = tx_desc->num_sge; + wr->opcode = IB_WR_SEND; + wr->send_flags = signal ? IB_SEND_SIGNALED : 0; - ib_ret = ib_post_send(ib_conn->qp, &send_wr, &send_wr_failed); + ib_ret = ib_post_send(ib_conn->qp, &tx_desc->wrs[0], &bad_wr); if (ib_ret) - iser_err("ib_post_send failed, ret:%d\n", ib_ret); + iser_err("ib_post_send failed, ret:%d opcode:%d\n", + ib_ret, bad_wr->opcode); return ib_ret; } -- GitLab From 96249d70dd70496084c7ec1465ec449cd032955a Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 5 Aug 2015 14:14:45 -0600 Subject: [PATCH 5825/7006] IB/core: Guarantee that a local_dma_lkey is available Every single ULP requires a local_dma_lkey to do anything with a QP, so let us ensure one exists for every PD created. If the driver can supply a global local_dma_lkey then use that, otherwise ask the driver to create a local use all physical memory MR associated with the new PD. Signed-off-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Acked-by: Christoph Hellwig Reviewed-by: Steve Wise Reviewed-by: Ira Weiny Tested-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 1 + drivers/infiniband/core/verbs.c | 47 +++++++++++++++++++++++++--- include/rdma/ib_verbs.h | 9 ++---- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index bbb02ffe87df9..258485ee46b2e 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -562,6 +562,7 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, pd->device = file->device->ib_dev; pd->uobject = uobj; + pd->local_mr = NULL; atomic_set(&pd->usecnt, 0); uobj->object = pd; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index c80ed17376664..2e5fd89a89292 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -213,24 +213,61 @@ EXPORT_SYMBOL(rdma_port_get_link_layer); /* Protection domains */ +/** + * ib_alloc_pd - Allocates an unused protection domain. + * @device: The device on which to allocate the protection domain. + * + * A protection domain object provides an association between QPs, shared + * receive queues, address handles, memory regions, and memory windows. + * + * Every PD has a local_dma_lkey which can be used as the lkey value for local + * memory operations. + */ struct ib_pd *ib_alloc_pd(struct ib_device *device) { struct ib_pd *pd; + struct ib_device_attr devattr; + int rc; + + rc = ib_query_device(device, &devattr); + if (rc) + return ERR_PTR(rc); pd = device->alloc_pd(device, NULL, NULL); + if (IS_ERR(pd)) + return pd; + + pd->device = device; + pd->uobject = NULL; + pd->local_mr = NULL; + atomic_set(&pd->usecnt, 0); + + if (devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY) + pd->local_dma_lkey = device->local_dma_lkey; + else { + struct ib_mr *mr; + + mr = ib_get_dma_mr(pd, IB_ACCESS_LOCAL_WRITE); + if (IS_ERR(mr)) { + ib_dealloc_pd(pd); + return (struct ib_pd *)mr; + } - if (!IS_ERR(pd)) { - pd->device = device; - pd->uobject = NULL; - atomic_set(&pd->usecnt, 0); + pd->local_mr = mr; + pd->local_dma_lkey = pd->local_mr->lkey; } - return pd; } EXPORT_SYMBOL(ib_alloc_pd); int ib_dealloc_pd(struct ib_pd *pd) { + if (pd->local_mr) { + if (ib_dereg_mr(pd->local_mr)) + return -EBUSY; + pd->local_mr = NULL; + } + if (atomic_read(&pd->usecnt)) return -EBUSY; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 5eff55c8b39df..09400512d5798 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1257,9 +1257,11 @@ struct ib_udata { }; struct ib_pd { + u32 local_dma_lkey; struct ib_device *device; struct ib_uobject *uobject; atomic_t usecnt; /* count all resources */ + struct ib_mr *local_mr; }; struct ib_xrcd { @@ -2192,13 +2194,6 @@ int ib_find_gid(struct ib_device *device, union ib_gid *gid, int ib_find_pkey(struct ib_device *device, u8 port_num, u16 pkey, u16 *index); -/** - * ib_alloc_pd - Allocates an unused protection domain. - * @device: The device on which to allocate the protection domain. - * - * A protection domain object provides an association between QPs, shared - * receive queues, address handles, memory regions, and memory windows. - */ struct ib_pd *ib_alloc_pd(struct ib_device *device); /** -- GitLab From 4be90bc60df47f6268b594c4fb6c90f0ff2f519f Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:16 -0600 Subject: [PATCH 5826/7006] IB/mad: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/core/mad.c | 26 +++----------------------- drivers/infiniband/core/mad_priv.h | 1 - include/rdma/ib_mad.h | 1 - 3 files changed, 3 insertions(+), 25 deletions(-) diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 66b4b3eb8f67b..4b5c72311debb 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -338,13 +338,6 @@ struct ib_mad_agent *ib_register_mad_agent(struct ib_device *device, goto error1; } - mad_agent_priv->agent.mr = ib_get_dma_mr(port_priv->qp_info[qpn].qp->pd, - IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(mad_agent_priv->agent.mr)) { - ret = ERR_PTR(-ENOMEM); - goto error2; - } - if (mad_reg_req) { reg_req = kmemdup(mad_reg_req, sizeof *reg_req, GFP_KERNEL); if (!reg_req) { @@ -429,8 +422,6 @@ error4: spin_unlock_irqrestore(&port_priv->reg_lock, flags); kfree(reg_req); error3: - ib_dereg_mr(mad_agent_priv->agent.mr); -error2: kfree(mad_agent_priv); error1: return ret; @@ -590,7 +581,6 @@ static void unregister_mad_agent(struct ib_mad_agent_private *mad_agent_priv) wait_for_completion(&mad_agent_priv->comp); kfree(mad_agent_priv->reg_req); - ib_dereg_mr(mad_agent_priv->agent.mr); kfree(mad_agent_priv); } @@ -1038,7 +1028,7 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, mad_send_wr->mad_agent_priv = mad_agent_priv; mad_send_wr->sg_list[0].length = hdr_len; - mad_send_wr->sg_list[0].lkey = mad_agent->mr->lkey; + mad_send_wr->sg_list[0].lkey = mad_agent->qp->pd->local_dma_lkey; /* OPA MADs don't have to be the full 2048 bytes */ if (opa && base_version == OPA_MGMT_BASE_VERSION && @@ -1047,7 +1037,7 @@ struct ib_mad_send_buf * ib_create_send_mad(struct ib_mad_agent *mad_agent, else mad_send_wr->sg_list[1].length = mad_size - hdr_len; - mad_send_wr->sg_list[1].lkey = mad_agent->mr->lkey; + mad_send_wr->sg_list[1].lkey = mad_agent->qp->pd->local_dma_lkey; mad_send_wr->send_wr.wr_id = (unsigned long) mad_send_wr; mad_send_wr->send_wr.sg_list = mad_send_wr->sg_list; @@ -2885,7 +2875,7 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, struct ib_mad_queue *recv_queue = &qp_info->recv_queue; /* Initialize common scatter list fields */ - sg_list.lkey = (*qp_info->port_priv->mr).lkey; + sg_list.lkey = qp_info->port_priv->pd->local_dma_lkey; /* Initialize common receive WR fields */ recv_wr.next = NULL; @@ -3201,13 +3191,6 @@ static int ib_mad_port_open(struct ib_device *device, goto error4; } - port_priv->mr = ib_get_dma_mr(port_priv->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(port_priv->mr)) { - dev_err(&device->dev, "Couldn't get ib_mad DMA MR\n"); - ret = PTR_ERR(port_priv->mr); - goto error5; - } - if (has_smi) { ret = create_mad_qp(&port_priv->qp_info[0], IB_QPT_SMI); if (ret) @@ -3248,8 +3231,6 @@ error8: error7: destroy_mad_qp(&port_priv->qp_info[0]); error6: - ib_dereg_mr(port_priv->mr); -error5: ib_dealloc_pd(port_priv->pd); error4: ib_destroy_cq(port_priv->cq); @@ -3284,7 +3265,6 @@ static int ib_mad_port_close(struct ib_device *device, int port_num) destroy_workqueue(port_priv->wq); destroy_mad_qp(&port_priv->qp_info[1]); destroy_mad_qp(&port_priv->qp_info[0]); - ib_dereg_mr(port_priv->mr); ib_dealloc_pd(port_priv->pd); ib_destroy_cq(port_priv->cq); cleanup_recv_queue(&port_priv->qp_info[1]); diff --git a/drivers/infiniband/core/mad_priv.h b/drivers/infiniband/core/mad_priv.h index 5be89f98928f2..4a4f7aad09783 100644 --- a/drivers/infiniband/core/mad_priv.h +++ b/drivers/infiniband/core/mad_priv.h @@ -199,7 +199,6 @@ struct ib_mad_port_private { int port_num; struct ib_cq *cq; struct ib_pd *pd; - struct ib_mr *mr; spinlock_t reg_lock; struct ib_mad_mgmt_version_table version[MAX_MGMT_VERSION]; diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index d5ac0229f5e71..c206205bbf986 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -526,7 +526,6 @@ enum { struct ib_mad_agent { struct ib_device *device; struct ib_qp *qp; - struct ib_mr *mr; ib_mad_recv_handler recv_handler; ib_mad_send_handler send_handler; ib_mad_snoop_handler snoop_handler; -- GitLab From 77b1f99660ed60694e1d0e3a63096c1f252debfd Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:17 -0600 Subject: [PATCH 5827/7006] IB/ipoib: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib.h | 1 - drivers/infiniband/ulp/ipoib/ipoib_cm.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 18 +++--------------- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index 79859c4d43c9c..ca2873698d754 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -342,7 +342,6 @@ struct ipoib_dev_priv { u16 pkey; u16 pkey_index; struct ib_pd *pd; - struct ib_mr *mr; struct ib_cq *recv_cq; struct ib_cq *send_cq; struct ib_qp *qp; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 9d321575d90e2..c78dc16380300 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -332,7 +332,7 @@ static void ipoib_cm_init_rx_wr(struct net_device *dev, int i; for (i = 0; i < priv->cm.num_frags; ++i) - sge[i].lkey = priv->mr->lkey; + sge[i].lkey = priv->pd->local_dma_lkey; sge[0].length = IPOIB_CM_HEAD_SIZE; for (i = 1; i < priv->cm.num_frags; ++i) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 851c8219d5010..8c451983d8a5a 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -152,12 +152,6 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) return -ENODEV; } - priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(priv->mr)) { - printk(KERN_WARNING "%s: ib_get_dma_mr failed\n", ca->name); - goto out_free_pd; - } - /* * the various IPoIB tasks assume they will never race against * themselves, so always use a single thread workqueue @@ -165,7 +159,7 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->wq = create_singlethread_workqueue("ipoib_wq"); if (!priv->wq) { printk(KERN_WARNING "ipoib: failed to allocate device WQ\n"); - goto out_free_mr; + goto out_free_pd; } size = ipoib_recvq_size + 1; @@ -225,13 +219,13 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca) priv->dev->dev_addr[3] = (priv->qp->qp_num ) & 0xff; for (i = 0; i < MAX_SKB_FRAGS + 1; ++i) - priv->tx_sge[i].lkey = priv->mr->lkey; + priv->tx_sge[i].lkey = priv->pd->local_dma_lkey; priv->tx_wr.opcode = IB_WR_SEND; priv->tx_wr.sg_list = priv->tx_sge; priv->tx_wr.send_flags = IB_SEND_SIGNALED; - priv->rx_sge[0].lkey = priv->mr->lkey; + priv->rx_sge[0].lkey = priv->pd->local_dma_lkey; priv->rx_sge[0].length = IPOIB_UD_BUF_SIZE(priv->max_ib_mtu); priv->rx_wr.num_sge = 1; @@ -254,9 +248,6 @@ out_free_wq: destroy_workqueue(priv->wq); priv->wq = NULL; -out_free_mr: - ib_dereg_mr(priv->mr); - out_free_pd: ib_dealloc_pd(priv->pd); @@ -289,9 +280,6 @@ void ipoib_transport_dev_cleanup(struct net_device *dev) priv->wq = NULL; } - if (ib_dereg_mr(priv->mr)) - ipoib_warn(priv, "ib_dereg_mr failed\n"); - if (ib_dealloc_pd(priv->pd)) ipoib_warn(priv, "ib_dealloc_pd failed\n"); -- GitLab From 7dd975762825e4c2b95df5e24759a9d6ad915c79 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:18 -0600 Subject: [PATCH 5828/7006] IB/mlx4: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mad.c | 23 ++++------------------- drivers/infiniband/hw/mlx4/mlx4_ib.h | 1 - 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 68b3dfa922bf3..1cd75ff022519 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -580,7 +580,7 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, list.addr = tun_qp->tx_ring[tun_tx_ix].buf.map; list.length = sizeof (struct mlx4_rcv_tunnel_mad); - list.lkey = tun_ctx->mr->lkey; + list.lkey = tun_ctx->pd->local_dma_lkey; wr.wr.ud.ah = ah; wr.wr.ud.port_num = port; @@ -1133,7 +1133,7 @@ static int mlx4_ib_post_pv_qp_buf(struct mlx4_ib_demux_pv_ctx *ctx, sg_list.addr = tun_qp->ring[index].map; sg_list.length = size; - sg_list.lkey = ctx->mr->lkey; + sg_list.lkey = ctx->pd->local_dma_lkey; recv_wr.next = NULL; recv_wr.sg_list = &sg_list; @@ -1244,7 +1244,7 @@ int mlx4_ib_send_to_wire(struct mlx4_ib_dev *dev, int slave, u8 port, list.addr = sqp->tx_ring[wire_tx_ix].buf.map; list.length = sizeof (struct mlx4_mad_snd_buf); - list.lkey = sqp_ctx->mr->lkey; + list.lkey = sqp_ctx->pd->local_dma_lkey; wr.wr.ud.ah = ah; wr.wr.ud.port_num = port; @@ -1827,19 +1827,12 @@ static int create_pv_resources(struct ib_device *ibdev, int slave, int port, goto err_cq; } - ctx->mr = ib_get_dma_mr(ctx->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(ctx->mr)) { - ret = PTR_ERR(ctx->mr); - pr_err("Couldn't get tunnel DMA MR (%d)\n", ret); - goto err_pd; - } - if (ctx->has_smi) { ret = create_pv_sqp(ctx, IB_QPT_SMI, create_tun); if (ret) { pr_err("Couldn't create %s QP0 (%d)\n", create_tun ? "tunnel for" : "", ret); - goto err_mr; + goto err_pd; } } @@ -1876,10 +1869,6 @@ err_qp0: ib_destroy_qp(ctx->qp[0].qp); ctx->qp[0].qp = NULL; -err_mr: - ib_dereg_mr(ctx->mr); - ctx->mr = NULL; - err_pd: ib_dealloc_pd(ctx->pd); ctx->pd = NULL; @@ -1916,8 +1905,6 @@ static void destroy_pv_resources(struct mlx4_ib_dev *dev, int slave, int port, ib_destroy_qp(ctx->qp[1].qp); ctx->qp[1].qp = NULL; mlx4_ib_free_pv_qp_bufs(ctx, IB_QPT_GSI, 1); - ib_dereg_mr(ctx->mr); - ctx->mr = NULL; ib_dealloc_pd(ctx->pd); ctx->pd = NULL; ib_destroy_cq(ctx->cq); @@ -2050,8 +2037,6 @@ static void mlx4_ib_free_sqp_ctx(struct mlx4_ib_demux_pv_ctx *sqp_ctx) ib_destroy_qp(sqp_ctx->qp[1].qp); sqp_ctx->qp[1].qp = NULL; mlx4_ib_free_pv_qp_bufs(sqp_ctx, IB_QPT_GSI, 0); - ib_dereg_mr(sqp_ctx->mr); - sqp_ctx->mr = NULL; ib_dealloc_pd(sqp_ctx->pd); sqp_ctx->pd = NULL; ib_destroy_cq(sqp_ctx->cq); diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index cb47c2cb84ca4..fe52ead0ebda0 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -415,7 +415,6 @@ struct mlx4_ib_demux_pv_ctx { struct ib_device *ib_dev; struct ib_cq *cq; struct ib_pd *pd; - struct ib_mr *mr; struct work_struct work; struct workqueue_struct *wq; struct mlx4_ib_demux_pv_qp qp[2]; -- GitLab From b37c788f595cd578524fb8f50d3bd2fff8b62bc3 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:19 -0600 Subject: [PATCH 5829/7006] IB/mlx5: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 13 ------------- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 - drivers/infiniband/hw/mlx5/mr.c | 5 ++--- 3 files changed, 2 insertions(+), 17 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index ce7587538badd..41d6911e244e1 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1123,7 +1123,6 @@ static void destroy_umrc_res(struct mlx5_ib_dev *dev) mlx5_ib_destroy_qp(dev->umrc.qp); ib_destroy_cq(dev->umrc.cq); - ib_dereg_mr(dev->umrc.mr); ib_dealloc_pd(dev->umrc.pd); } @@ -1138,7 +1137,6 @@ static int create_umr_res(struct mlx5_ib_dev *dev) struct ib_pd *pd; struct ib_cq *cq; struct ib_qp *qp; - struct ib_mr *mr; struct ib_cq_init_attr cq_attr = {}; int ret; @@ -1156,13 +1154,6 @@ static int create_umr_res(struct mlx5_ib_dev *dev) goto error_0; } - mr = ib_get_dma_mr(pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(mr)) { - mlx5_ib_dbg(dev, "Couldn't create DMA MR for sync UMR QP\n"); - ret = PTR_ERR(mr); - goto error_1; - } - cq_attr.cqe = 128; cq = ib_create_cq(&dev->ib_dev, mlx5_umr_cq_handler, NULL, NULL, &cq_attr); @@ -1220,7 +1211,6 @@ static int create_umr_res(struct mlx5_ib_dev *dev) dev->umrc.qp = qp; dev->umrc.cq = cq; - dev->umrc.mr = mr; dev->umrc.pd = pd; sema_init(&dev->umrc.sem, MAX_UMR_WR); @@ -1242,9 +1232,6 @@ error_3: ib_destroy_cq(cq); error_2: - ib_dereg_mr(mr); - -error_1: ib_dealloc_pd(pd); error_0: diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 62b06ae2c87db..a5fa0b9c75802 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -349,7 +349,6 @@ struct umr_common { struct ib_pd *pd; struct ib_cq *cq; struct ib_qp *qp; - struct ib_mr *mr; /* control access to UMR QP */ struct semaphore sem; diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index dad82db892210..0dfd379b9bad5 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -687,12 +687,11 @@ static void prep_umr_reg_wqe(struct ib_pd *pd, struct ib_send_wr *wr, int access_flags) { struct mlx5_ib_dev *dev = to_mdev(pd->device); - struct ib_mr *mr = dev->umrc.mr; struct mlx5_umr_wr *umrwr = (struct mlx5_umr_wr *)&wr->wr.fast_reg; sg->addr = dma; sg->length = ALIGN(sizeof(u64) * n, 64); - sg->lkey = mr->lkey; + sg->lkey = dev->umrc.pd->local_dma_lkey; wr->next = NULL; wr->send_flags = 0; @@ -923,7 +922,7 @@ int mlx5_ib_update_mtt(struct mlx5_ib_mr *mr, u64 start_page_index, int npages, sg.addr = dma; sg.length = ALIGN(npages * sizeof(u64), MLX5_UMR_MTT_ALIGNMENT); - sg.lkey = dev->umrc.mr->lkey; + sg.lkey = dev->umrc.pd->local_dma_lkey; wr.send_flags = MLX5_IB_SEND_UMR_FAIL_IF_FREE | MLX5_IB_SEND_UMR_UPDATE_MTT; -- GitLab From 256b7ad27316525711dfa98b67e7c40cb28b1711 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:20 -0600 Subject: [PATCH 5830/7006] IB/iser: Use pd->local_dma_lkey Replace all leys with pd->local_dma_lkey. This driver does not support iWarp, so this is safe. The insecure use of ib_get_dma_mr is thus isolated to an rkey, and this looks trivially fixed by forcing the use of registration in a future patch. Signed-off-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/infiniband/ulp/iser/iser_initiator.c | 4 ++-- drivers/infiniband/ulp/iser/iser_memory.c | 2 +- drivers/infiniband/ulp/iser/iser_verbs.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index e908a1eb800b9..1ace5d83a4d76 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -209,7 +209,7 @@ iser_initialize_task_headers(struct iscsi_task *task, tx_desc->dma_addr = dma_addr; tx_desc->tx_sg[0].addr = tx_desc->dma_addr; tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; - tx_desc->tx_sg[0].lkey = device->mr->lkey; + tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; iser_task->iser_conn = iser_conn; out: diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c index 0b1f3b54a0c17..d511879d8cdfc 100644 --- a/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/drivers/infiniband/ulp/iser/iser_initiator.c @@ -284,7 +284,7 @@ int iser_alloc_rx_descriptors(struct iser_conn *iser_conn, rx_sg = &rx_desc->rx_sg; rx_sg->addr = rx_desc->dma_addr; rx_sg->length = ISER_RX_PAYLOAD_SIZE; - rx_sg->lkey = device->mr->lkey; + rx_sg->lkey = device->pd->local_dma_lkey; } iser_conn->rx_desc_head = 0; @@ -538,7 +538,7 @@ int iser_send_control(struct iscsi_conn *conn, tx_dsg->addr = iser_conn->login_req_dma; tx_dsg->length = task->data_count; - tx_dsg->lkey = device->mr->lkey; + tx_dsg->lkey = device->pd->local_dma_lkey; mdesc->num_sge = 2; } diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c index 09640c811fdd5..2493cc748db83 100644 --- a/drivers/infiniband/ulp/iser/iser_memory.c +++ b/drivers/infiniband/ulp/iser/iser_memory.c @@ -471,7 +471,7 @@ iser_reg_dma(struct iser_device *device, struct iser_data_buf *mem, { struct scatterlist *sg = mem->sg; - reg->sge.lkey = device->mr->lkey; + reg->sge.lkey = device->pd->local_dma_lkey; reg->rkey = device->mr->rkey; reg->sge.addr = ib_sg_dma_address(device->ib_device, &sg[0]); reg->sge.length = ib_sg_dma_len(device->ib_device, &sg[0]); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 6f5be47a6b90c..ad2d2b50cd7f0 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -1061,7 +1061,7 @@ int iser_post_recvl(struct iser_conn *iser_conn) sge.addr = iser_conn->login_resp_dma; sge.length = ISER_RX_LOGIN_SIZE; - sge.lkey = ib_conn->device->mr->lkey; + sge.lkey = ib_conn->device->pd->local_dma_lkey; rx_wr.wr_id = (uintptr_t)iser_conn->login_resp_buf; rx_wr.sg_list = &sge; -- GitLab From 34efc7dfbd88e4a232b1efa31c5e900606c84fca Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:21 -0600 Subject: [PATCH 5831/7006] iser-target: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/isert/ib_isert.c | 33 +++++++++---------------- drivers/infiniband/ulp/isert/ib_isert.h | 1 - 2 files changed, 11 insertions(+), 23 deletions(-) diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 0ebbaa56de829..dc439a40da3f4 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -235,7 +235,7 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn) rx_sg = &rx_desc->rx_sg; rx_sg->addr = rx_desc->dma_addr; rx_sg->length = ISER_RX_PAYLOAD_SIZE; - rx_sg->lkey = device->mr->lkey; + rx_sg->lkey = device->pd->local_dma_lkey; } isert_conn->rx_desc_head = 0; @@ -385,22 +385,12 @@ isert_create_device_ib_res(struct isert_device *device) goto out_cq; } - device->mr = ib_get_dma_mr(device->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(device->mr)) { - ret = PTR_ERR(device->mr); - isert_err("failed to create dma mr, device %p, ret=%d\n", - device, ret); - goto out_mr; - } - /* Check signature cap */ device->pi_capable = dev_attr->device_cap_flags & IB_DEVICE_SIGNATURE_HANDOVER ? true : false; return 0; -out_mr: - ib_dealloc_pd(device->pd); out_cq: isert_free_comps(device); return ret; @@ -411,7 +401,6 @@ isert_free_device_ib_res(struct isert_device *device) { isert_info("device %p\n", device); - ib_dereg_mr(device->mr); ib_dealloc_pd(device->pd); isert_free_comps(device); } @@ -1090,8 +1079,8 @@ isert_create_send_desc(struct isert_conn *isert_conn, tx_desc->num_sge = 1; tx_desc->isert_cmd = isert_cmd; - if (tx_desc->tx_sg[0].lkey != device->mr->lkey) { - tx_desc->tx_sg[0].lkey = device->mr->lkey; + if (tx_desc->tx_sg[0].lkey != device->pd->local_dma_lkey) { + tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; isert_dbg("tx_desc %p lkey mismatch, fixing\n", tx_desc); } } @@ -1114,7 +1103,7 @@ isert_init_tx_hdrs(struct isert_conn *isert_conn, tx_desc->dma_addr = dma_addr; tx_desc->tx_sg[0].addr = tx_desc->dma_addr; tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; - tx_desc->tx_sg[0].lkey = device->mr->lkey; + tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; isert_dbg("Setup tx_sg[0].addr: 0x%llx length: %u lkey: 0x%x\n", tx_desc->tx_sg[0].addr, tx_desc->tx_sg[0].length, @@ -1147,7 +1136,7 @@ isert_rdma_post_recvl(struct isert_conn *isert_conn) memset(&sge, 0, sizeof(struct ib_sge)); sge.addr = isert_conn->login_req_dma; sge.length = ISER_RX_LOGIN_SIZE; - sge.lkey = isert_conn->device->mr->lkey; + sge.lkey = isert_conn->device->pd->local_dma_lkey; isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n", sge.addr, sge.length, sge.lkey); @@ -1197,7 +1186,7 @@ isert_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, tx_dsg->addr = isert_conn->login_rsp_dma; tx_dsg->length = length; - tx_dsg->lkey = isert_conn->device->mr->lkey; + tx_dsg->lkey = isert_conn->device->pd->local_dma_lkey; tx_desc->num_sge = 2; } if (!login->login_failed) { @@ -2214,7 +2203,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd) isert_cmd->pdu_buf_len = pdu_len; tx_dsg->addr = isert_cmd->pdu_buf_dma; tx_dsg->length = pdu_len; - tx_dsg->lkey = device->mr->lkey; + tx_dsg->lkey = device->pd->local_dma_lkey; isert_cmd->tx_desc.num_sge = 2; } @@ -2342,7 +2331,7 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn) isert_cmd->pdu_buf_len = ISCSI_HDR_LEN; tx_dsg->addr = isert_cmd->pdu_buf_dma; tx_dsg->length = ISCSI_HDR_LEN; - tx_dsg->lkey = device->mr->lkey; + tx_dsg->lkey = device->pd->local_dma_lkey; isert_cmd->tx_desc.num_sge = 2; isert_init_send_wr(isert_conn, isert_cmd, send_wr); @@ -2383,7 +2372,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) isert_cmd->pdu_buf_len = txt_rsp_len; tx_dsg->addr = isert_cmd->pdu_buf_dma; tx_dsg->length = txt_rsp_len; - tx_dsg->lkey = device->mr->lkey; + tx_dsg->lkey = device->pd->local_dma_lkey; isert_cmd->tx_desc.num_sge = 2; } isert_init_send_wr(isert_conn, isert_cmd, send_wr); @@ -2424,7 +2413,7 @@ isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, ib_sge->addr = ib_sg_dma_address(ib_dev, tmp_sg) + page_off; ib_sge->length = min_t(u32, data_left, ib_sg_dma_len(ib_dev, tmp_sg) - page_off); - ib_sge->lkey = device->mr->lkey; + ib_sge->lkey = device->pd->local_dma_lkey; isert_dbg("RDMA ib_sge: addr: 0x%llx length: %u lkey: %x\n", ib_sge->addr, ib_sge->length, ib_sge->lkey); @@ -2598,7 +2587,7 @@ isert_fast_reg_mr(struct isert_conn *isert_conn, u32 page_off; if (mem->dma_nents == 1) { - sge->lkey = device->mr->lkey; + sge->lkey = device->pd->local_dma_lkey; sge->addr = ib_sg_dma_address(ib_dev, &mem->sg[0]); sge->length = ib_sg_dma_len(ib_dev, &mem->sg[0]); isert_dbg("sge: addr: 0x%llx length: %u lkey: %x\n", diff --git a/drivers/infiniband/ulp/isert/ib_isert.h b/drivers/infiniband/ulp/isert/ib_isert.h index 9ec23a786c029..6a04ba3c0f722 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.h +++ b/drivers/infiniband/ulp/isert/ib_isert.h @@ -209,7 +209,6 @@ struct isert_device { int refcount; struct ib_device *ib_device; struct ib_pd *pd; - struct ib_mr *mr; struct isert_comp *comps; int comps_used; struct list_head dev_node; -- GitLab From e6bf5f48d2adc443689c5e627bcd559b00201e5c Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:22 -0600 Subject: [PATCH 5832/7006] IB/srp: Use pd->local_dma_lkey Replace all leys with pd->local_dma_lkey. This driver does not support iWarp, so this is safe. The insecure use of ib_get_dma_mr is thus isolated to an rkey, and will have to be fixed separately. Signed-off-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Reviewed-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index c9c4f647b1701..b890367d26ed2 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3154,7 +3154,7 @@ static ssize_t srp_create_target(struct device *dev, target->io_class = SRP_REV16A_IB_IO_CLASS; target->scsi_host = target_host; target->srp_host = host; - target->lkey = host->srp_dev->mr->lkey; + target->lkey = host->srp_dev->pd->local_dma_lkey; target->rkey = host->srp_dev->mr->rkey; target->cmd_sg_cnt = cmd_sg_entries; target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; -- GitLab From 5a783956c2b90179b852dd58a2ee668f16dfe980 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:24 -0600 Subject: [PATCH 5833/7006] ib_srpt: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 15 ++++----------- drivers/infiniband/ulp/srpt/ib_srpt.h | 1 - 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 3ab015b0236dc..f6fe0414139be 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -783,7 +783,7 @@ static int srpt_post_recv(struct srpt_device *sdev, list.addr = ioctx->ioctx.dma; list.length = srp_max_req_size; - list.lkey = sdev->mr->lkey; + list.lkey = sdev->pd->local_dma_lkey; wr.next = NULL; wr.sg_list = &list; @@ -818,7 +818,7 @@ static int srpt_post_send(struct srpt_rdma_ch *ch, list.addr = ioctx->ioctx.dma; list.length = len; - list.lkey = sdev->mr->lkey; + list.lkey = sdev->pd->local_dma_lkey; wr.next = NULL; wr.wr_id = encode_wr_id(SRPT_SEND, ioctx->ioctx.index); @@ -1206,7 +1206,7 @@ static int srpt_map_sg_to_ib_sge(struct srpt_rdma_ch *ch, while (rsize > 0 && tsize > 0) { sge->addr = dma_addr; - sge->lkey = ch->sport->sdev->mr->lkey; + sge->lkey = ch->sport->sdev->pd->local_dma_lkey; if (rsize >= dma_len) { sge->length = @@ -3211,10 +3211,6 @@ static void srpt_add_one(struct ib_device *device) if (IS_ERR(sdev->pd)) goto free_dev; - sdev->mr = ib_get_dma_mr(sdev->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(sdev->mr)) - goto err_pd; - sdev->srq_size = min(srpt_srq_size, sdev->dev_attr.max_srq_wr); srq_attr.event_handler = srpt_srq_event; @@ -3226,7 +3222,7 @@ static void srpt_add_one(struct ib_device *device) sdev->srq = ib_create_srq(sdev->pd, &srq_attr); if (IS_ERR(sdev->srq)) - goto err_mr; + goto err_pd; pr_debug("%s: create SRQ #wr= %d max_allow=%d dev= %s\n", __func__, sdev->srq_size, sdev->dev_attr.max_srq_wr, @@ -3311,8 +3307,6 @@ err_cm: ib_destroy_cm_id(sdev->cm_id); err_srq: ib_destroy_srq(sdev->srq); -err_mr: - ib_dereg_mr(sdev->mr); err_pd: ib_dealloc_pd(sdev->pd); free_dev: @@ -3357,7 +3351,6 @@ static void srpt_remove_one(struct ib_device *device, void *client_data) srpt_release_sdev(sdev); ib_destroy_srq(sdev->srq); - ib_dereg_mr(sdev->mr); ib_dealloc_pd(sdev->pd); srpt_free_ioctx_ring((struct srpt_ioctx **)sdev->ioctx_ring, sdev, diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.h b/drivers/infiniband/ulp/srpt/ib_srpt.h index 21f8df67522ab..5faad8acd7893 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.h +++ b/drivers/infiniband/ulp/srpt/ib_srpt.h @@ -393,7 +393,6 @@ struct srpt_port { struct srpt_device { struct ib_device *device; struct ib_pd *pd; - struct ib_mr *mr; struct ib_srq *srq; struct ib_cm_id *cm_id; struct ib_device_attr dev_attr; -- GitLab From 2f31fa881fbe70808b945a6d23cae1ca8eadf1b3 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:25 -0600 Subject: [PATCH 5834/7006] net/9p: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Tested-by: Dominique Martinet Signed-off-by: Doug Ledford --- net/9p/trans_rdma.c | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 37a78d20c0f64..ba1210253f5ec 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -94,8 +94,6 @@ struct p9_trans_rdma { struct ib_pd *pd; struct ib_qp *qp; struct ib_cq *cq; - struct ib_mr *dma_mr; - u32 lkey; long timeout; int sq_depth; struct semaphore sq_sem; @@ -382,9 +380,6 @@ static void rdma_destroy_trans(struct p9_trans_rdma *rdma) if (!rdma) return; - if (rdma->dma_mr && !IS_ERR(rdma->dma_mr)) - ib_dereg_mr(rdma->dma_mr); - if (rdma->qp && !IS_ERR(rdma->qp)) ib_destroy_qp(rdma->qp); @@ -415,7 +410,7 @@ post_recv(struct p9_client *client, struct p9_rdma_context *c) sge.addr = c->busa; sge.length = client->msize; - sge.lkey = rdma->lkey; + sge.lkey = rdma->pd->local_dma_lkey; wr.next = NULL; c->wc_op = IB_WC_RECV; @@ -506,7 +501,7 @@ dont_need_post_recv: sge.addr = c->busa; sge.length = c->req->tc->size; - sge.lkey = rdma->lkey; + sge.lkey = rdma->pd->local_dma_lkey; wr.next = NULL; c->wc_op = IB_WC_SEND; @@ -647,7 +642,6 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args) struct p9_trans_rdma *rdma; struct rdma_conn_param conn_param; struct ib_qp_init_attr qp_attr; - struct ib_device_attr devattr; struct ib_cq_init_attr cq_attr = {}; /* Parse the transport specific mount options */ @@ -700,11 +694,6 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args) if (err || (rdma->state != P9_RDMA_ROUTE_RESOLVED)) goto error; - /* Query the device attributes */ - err = ib_query_device(rdma->cm_id->device, &devattr); - if (err) - goto error; - /* Create the Completion Queue */ cq_attr.cqe = opts.sq_depth + opts.rq_depth + 1; rdma->cq = ib_create_cq(rdma->cm_id->device, cq_comp_handler, @@ -719,17 +708,6 @@ rdma_create_trans(struct p9_client *client, const char *addr, char *args) if (IS_ERR(rdma->pd)) goto error; - /* Cache the DMA lkey in the transport */ - rdma->dma_mr = NULL; - if (devattr.device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY) - rdma->lkey = rdma->cm_id->device->local_dma_lkey; - else { - rdma->dma_mr = ib_get_dma_mr(rdma->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(rdma->dma_mr)) - goto error; - rdma->lkey = rdma->dma_mr->lkey; - } - /* Create the Queue Pair */ memset(&qp_attr, 0, sizeof qp_attr); qp_attr.event_handler = qp_event_handler; -- GitLab From e5580242aa8fab292579a1661463f7479275f7ff Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Thu, 30 Jul 2015 17:22:26 -0600 Subject: [PATCH 5835/7006] rds/ib: Remove ib_get_dma_mr calls The pd now has a local_dma_lkey member which completely replaces ib_get_dma_mr, use it instead. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- net/rds/ib.c | 8 -------- net/rds/ib.h | 2 -- net/rds/ib_cm.c | 4 +--- net/rds/ib_recv.c | 6 +++--- net/rds/ib_send.c | 8 ++++---- 5 files changed, 8 insertions(+), 20 deletions(-) diff --git a/net/rds/ib.c b/net/rds/ib.c index 348ac37c11616..c6f95b9494ae1 100644 --- a/net/rds/ib.c +++ b/net/rds/ib.c @@ -99,8 +99,6 @@ static void rds_ib_dev_free(struct work_struct *work) if (rds_ibdev->mr_pool) rds_ib_destroy_mr_pool(rds_ibdev->mr_pool); - if (rds_ibdev->mr) - ib_dereg_mr(rds_ibdev->mr); if (rds_ibdev->pd) ib_dealloc_pd(rds_ibdev->pd); @@ -164,12 +162,6 @@ static void rds_ib_add_one(struct ib_device *device) goto put_dev; } - rds_ibdev->mr = ib_get_dma_mr(rds_ibdev->pd, IB_ACCESS_LOCAL_WRITE); - if (IS_ERR(rds_ibdev->mr)) { - rds_ibdev->mr = NULL; - goto put_dev; - } - rds_ibdev->mr_pool = rds_ib_create_mr_pool(rds_ibdev); if (IS_ERR(rds_ibdev->mr_pool)) { rds_ibdev->mr_pool = NULL; diff --git a/net/rds/ib.h b/net/rds/ib.h index 86d88ec5d5563..36f7d808ffaae 100644 --- a/net/rds/ib.h +++ b/net/rds/ib.h @@ -100,7 +100,6 @@ struct rds_ib_connection { /* alphabet soup, IBTA style */ struct rdma_cm_id *i_cm_id; struct ib_pd *i_pd; - struct ib_mr *i_mr; struct ib_cq *i_send_cq; struct ib_cq *i_recv_cq; @@ -173,7 +172,6 @@ struct rds_ib_device { struct list_head conn_list; struct ib_device *dev; struct ib_pd *pd; - struct ib_mr *mr; struct rds_ib_mr_pool *mr_pool; unsigned int fmr_max_remaps; unsigned int max_fmrs; diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c index 0da2a45b33bd8..a75e8832bc232 100644 --- a/net/rds/ib_cm.c +++ b/net/rds/ib_cm.c @@ -269,7 +269,6 @@ static int rds_ib_setup_qp(struct rds_connection *conn) /* Protection domain and memory range */ ic->i_pd = rds_ibdev->pd; - ic->i_mr = rds_ibdev->mr; cq_attr.cqe = ic->i_send_ring.w_nr + 1; ic->i_send_cq = ib_create_cq(dev, rds_ib_send_cq_comp_handler, @@ -375,7 +374,7 @@ static int rds_ib_setup_qp(struct rds_connection *conn) rds_ib_recv_init_ack(ic); - rdsdebug("conn %p pd %p mr %p cq %p %p\n", conn, ic->i_pd, ic->i_mr, + rdsdebug("conn %p pd %p cq %p %p\n", conn, ic->i_pd, ic->i_send_cq, ic->i_recv_cq); out: @@ -678,7 +677,6 @@ void rds_ib_conn_shutdown(struct rds_connection *conn) ic->i_cm_id = NULL; ic->i_pd = NULL; - ic->i_mr = NULL; ic->i_send_cq = NULL; ic->i_recv_cq = NULL; ic->i_send_hdrs = NULL; diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index cac5b4506ee38..0ceb4c60d2a3a 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c @@ -62,12 +62,12 @@ void rds_ib_recv_init_ring(struct rds_ib_connection *ic) sge = &recv->r_sge[0]; sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header)); sge->length = sizeof(struct rds_header); - sge->lkey = ic->i_mr->lkey; + sge->lkey = ic->i_pd->local_dma_lkey; sge = &recv->r_sge[1]; sge->addr = 0; sge->length = RDS_FRAG_SIZE; - sge->lkey = ic->i_mr->lkey; + sge->lkey = ic->i_pd->local_dma_lkey; } } @@ -520,7 +520,7 @@ void rds_ib_recv_init_ack(struct rds_ib_connection *ic) sge->addr = ic->i_ack_dma; sge->length = sizeof(struct rds_header); - sge->lkey = ic->i_mr->lkey; + sge->lkey = ic->i_pd->local_dma_lkey; wr->sg_list = sge; wr->num_sge = 1; diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c index 5d0a704fa039f..f6c829d43373f 100644 --- a/net/rds/ib_send.c +++ b/net/rds/ib_send.c @@ -202,9 +202,9 @@ void rds_ib_send_init_ring(struct rds_ib_connection *ic) sge = &send->s_sge[0]; sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header)); sge->length = sizeof(struct rds_header); - sge->lkey = ic->i_mr->lkey; + sge->lkey = ic->i_pd->local_dma_lkey; - send->s_sge[1].lkey = ic->i_mr->lkey; + send->s_sge[1].lkey = ic->i_pd->local_dma_lkey; } } @@ -813,7 +813,7 @@ int rds_ib_xmit_atomic(struct rds_connection *conn, struct rm_atomic_op *op) /* Convert our struct scatterlist to struct ib_sge */ send->s_sge[0].addr = ib_sg_dma_address(ic->i_cm_id->device, op->op_sg); send->s_sge[0].length = ib_sg_dma_len(ic->i_cm_id->device, op->op_sg); - send->s_sge[0].lkey = ic->i_mr->lkey; + send->s_sge[0].lkey = ic->i_pd->local_dma_lkey; rdsdebug("rva %Lx rpa %Lx len %u\n", op->op_remote_addr, send->s_sge[0].addr, send->s_sge[0].length); @@ -927,7 +927,7 @@ int rds_ib_xmit_rdma(struct rds_connection *conn, struct rm_rdma_op *op) send->s_sge[j].addr = ib_sg_dma_address(ic->i_cm_id->device, scat); send->s_sge[j].length = len; - send->s_sge[j].lkey = ic->i_mr->lkey; + send->s_sge[j].lkey = ic->i_pd->local_dma_lkey; sent += len; rdsdebug("ic %p sent %d remote_addr %llu\n", ic, sent, remote_addr); -- GitLab From 186fbc6689a368364b7c9eb9d42d6f84b3079f65 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:06:29 -0700 Subject: [PATCH 5836/7006] IB/srp: Re-enable FMR for non-page aligned buffers During a discussion in 2011 nobody recalled why FMR was not used for non-page aligned buffers (see also http://thread.gmane.org/gmane.linux.drivers.rdma/7149). Re-enable FMR for such buffers. For the reason why the srp_map_fmr() function needs to be modified, see also patch "IB/srp: rework mapping engine to use multiple FMR entries" (commit ID 8f26c9ff9cd0; January 2011). Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index b890367d26ed2..6ed976d8aa30d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1272,6 +1272,8 @@ static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, static int srp_map_finish_fmr(struct srp_map_state *state, struct srp_rdma_ch *ch) { + struct srp_target_port *target = ch->target; + struct srp_device *dev = target->srp_host->srp_dev; struct ib_pool_fmr *fmr; u64 io_addr = 0; @@ -1283,7 +1285,8 @@ static int srp_map_finish_fmr(struct srp_map_state *state, *state->next_fmr++ = fmr; state->nmdesc++; - srp_map_desc(state, 0, state->dma_len, fmr->fmr->rkey); + srp_map_desc(state, state->base_dma_addr & ~dev->mr_page_mask, + state->dma_len, fmr->fmr->rkey); return 0; } @@ -1390,14 +1393,7 @@ static int srp_map_sg_entry(struct srp_map_state *state, return 0; } - /* - * Since not all RDMA HW drivers support non-zero page offsets for - * FMR, if we start at an offset into a page, don't merge into the - * current FMR mapping. Finish it out, and use the kernel's MR for - * this sg entry. - */ - if ((!dev->use_fast_reg && dma_addr & ~dev->mr_page_mask) || - dma_len > dev->mr_max_size) { + if (dma_len > dev->mr_max_size) { ret = srp_finish_mapping(state, ch); if (ret) return ret; -- GitLab From 7e85c91970125cb16399c7d1cfedc943266eee49 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:06:57 -0700 Subject: [PATCH 5837/7006] IB/srp: Use multiple registrations for large memory regions Instead of using the global rkey for large memory regions, use multiple registrations. See also the while (dma_len) loop further down in srp_map_sg_entry(). Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 6ed976d8aa30d..03ae72e338c0d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1393,16 +1393,6 @@ static int srp_map_sg_entry(struct srp_map_state *state, return 0; } - if (dma_len > dev->mr_max_size) { - ret = srp_finish_mapping(state, ch); - if (ret) - return ret; - - srp_map_desc(state, dma_addr, dma_len, target->rkey); - srp_map_update_start(state, NULL, 0, 0); - return 0; - } - /* * If this is the first sg that will be mapped via FMR or via FR, save * our position. We need to know the first unmapped entry, its index, -- GitLab From f731ed62934ace0d3f5aa9ec557349171711be05 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:07:27 -0700 Subject: [PATCH 5838/7006] IB/srp: Add memory descriptor array pointer range checking Although most paths through which a request is submitted check block layer parameters like the max_segments limit, these are not checked when an SG_IO or direct I/O request is submitted. Hence add a range check for the memory descriptor array pointer. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 16 ++++++++++++---- drivers/infiniband/ulp/srp/ib_srp.h | 10 ++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 03ae72e338c0d..b7feb7424097d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1277,12 +1277,15 @@ static int srp_map_finish_fmr(struct srp_map_state *state, struct ib_pool_fmr *fmr; u64 io_addr = 0; + if (state->fmr.next >= state->fmr.end) + return -ENOMEM; + fmr = ib_fmr_pool_map_phys(ch->fmr_pool, state->pages, state->npages, io_addr); if (IS_ERR(fmr)) return PTR_ERR(fmr); - *state->next_fmr++ = fmr; + *state->fmr.next++ = fmr; state->nmdesc++; srp_map_desc(state, state->base_dma_addr & ~dev->mr_page_mask, @@ -1301,6 +1304,9 @@ static int srp_map_finish_fr(struct srp_map_state *state, struct srp_fr_desc *desc; u32 rkey; + if (state->fr.next >= state->fr.end) + return -ENOMEM; + desc = srp_fr_pool_get(ch->fr_pool); if (!desc) return -ENOMEM; @@ -1324,7 +1330,7 @@ static int srp_map_finish_fr(struct srp_map_state *state, IB_ACCESS_REMOTE_WRITE); wr.wr.fast_reg.rkey = desc->mr->lkey; - *state->next_fr++ = desc; + *state->fr.next++ = desc; state->nmdesc++; srp_map_desc(state, state->base_dma_addr, state->dma_len, @@ -1450,10 +1456,12 @@ static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch, state->desc = req->indirect_desc; state->pages = req->map_page; if (dev->use_fast_reg) { - state->next_fr = req->fr_list; + state->fr.next = req->fr_list; + state->fr.end = req->fr_list + target->cmd_sg_cnt; use_mr = !!ch->fr_pool; } else { - state->next_fmr = req->fmr_list; + state->fmr.next = req->fmr_list; + state->fmr.end = req->fmr_list + target->cmd_sg_cnt; use_mr = !!ch->fmr_pool; } diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 17ee3f80ba550..2ab73bc76da17 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -282,8 +282,14 @@ struct srp_fr_pool { */ struct srp_map_state { union { - struct ib_pool_fmr **next_fmr; - struct srp_fr_desc **next_fr; + struct { + struct ib_pool_fmr **next; + struct ib_pool_fmr **end; + } fmr; + struct { + struct srp_fr_desc **next; + struct srp_fr_desc **end; + } fr; }; struct srp_direct_buf *desc; u64 *pages; -- GitLab From 0e0d3a480090d03f29e58dfd717960776f3416d9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:07:46 -0700 Subject: [PATCH 5839/7006] IB/srp: Remove the memory registration backtracking code Mapping a discontiguous sg-list requires multiple memory regions and hence can exhaust the memory region pool. The SRP initiator already handles this by temporarily reducing the queue depth. This means that it is safe to remove the memory registration backtracking code. This patch has been tested with direct I/O sizes up to 256 MB. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 62 ++++++----------------------- drivers/infiniband/ulp/srp/ib_srp.h | 6 --- 2 files changed, 13 insertions(+), 55 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index b7feb7424097d..acda65936588d 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1364,15 +1364,6 @@ static int srp_finish_mapping(struct srp_map_state *state, return ret; } -static void srp_map_update_start(struct srp_map_state *state, - struct scatterlist *sg, int sg_index, - dma_addr_t dma_addr) -{ - state->unmapped_sg = sg; - state->unmapped_index = sg_index; - state->unmapped_addr = dma_addr; -} - static int srp_map_sg_entry(struct srp_map_state *state, struct srp_rdma_ch *ch, struct scatterlist *sg, int sg_index, @@ -1399,23 +1390,12 @@ static int srp_map_sg_entry(struct srp_map_state *state, return 0; } - /* - * If this is the first sg that will be mapped via FMR or via FR, save - * our position. We need to know the first unmapped entry, its index, - * and the first unmapped address within that entry to be able to - * restart mapping after an error. - */ - if (!state->unmapped_sg) - srp_map_update_start(state, sg, sg_index, dma_addr); - while (dma_len) { unsigned offset = dma_addr & ~dev->mr_page_mask; if (state->npages == dev->max_pages_per_mr || offset != 0) { ret = srp_finish_mapping(state, ch); if (ret) return ret; - - srp_map_update_start(state, sg, sg_index, dma_addr); } len = min_t(unsigned int, dma_len, dev->mr_page_size - offset); @@ -1434,11 +1414,8 @@ static int srp_map_sg_entry(struct srp_map_state *state, * boundries. */ ret = 0; - if (len != dev->mr_page_size) { + if (len != dev->mr_page_size) ret = srp_finish_mapping(state, ch); - if (!ret) - srp_map_update_start(state, NULL, 0, 0); - } return ret; } @@ -1448,9 +1425,8 @@ static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch, { struct srp_target_port *target = ch->target; struct srp_device *dev = target->srp_host->srp_dev; - struct ib_device *ibdev = dev->dev; struct scatterlist *sg; - int i; + int i, ret; bool use_mr; state->desc = req->indirect_desc; @@ -1466,34 +1442,22 @@ static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch, } for_each_sg(scat, sg, count, i) { - if (srp_map_sg_entry(state, ch, sg, i, use_mr)) { - /* - * Memory registration failed, so backtrack to the - * first unmapped entry and continue on without using - * memory registration. - */ - dma_addr_t dma_addr; - unsigned int dma_len; - -backtrack: - sg = state->unmapped_sg; - i = state->unmapped_index; - - dma_addr = ib_sg_dma_address(ibdev, sg); - dma_len = ib_sg_dma_len(ibdev, sg); - dma_len -= (state->unmapped_addr - dma_addr); - dma_addr = state->unmapped_addr; - use_mr = false; - srp_map_desc(state, dma_addr, dma_len, target->rkey); - } + ret = srp_map_sg_entry(state, ch, sg, i, use_mr); + if (ret) + goto out; } - if (use_mr && srp_finish_mapping(state, ch)) - goto backtrack; + if (use_mr) { + ret = srp_finish_mapping(state, ch); + if (ret) + goto out; + } req->nmdesc = state->nmdesc; + ret = 0; - return 0; +out: + return ret; } static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 2ab73bc76da17..1e424181fdf85 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -276,9 +276,6 @@ struct srp_fr_pool { * @npages: Number of page addresses in the pages[] array. * @nmdesc: Number of FMR or FR memory descriptors used for mapping. * @ndesc: Number of SRP buffer descriptors that have been filled in. - * @unmapped_sg: First element of the sg-list that is mapped via FMR or FR. - * @unmapped_index: Index of the first element mapped via FMR or FR. - * @unmapped_addr: DMA address of the first element mapped via FMR or FR. */ struct srp_map_state { union { @@ -299,9 +296,6 @@ struct srp_map_state { unsigned int npages; unsigned int nmdesc; unsigned int ndesc; - struct scatterlist *unmapped_sg; - int unmapped_index; - dma_addr_t unmapped_addr; }; #endif /* IB_SRP_H */ -- GitLab From 3ae95da8831e7bcf7b6da2b31cb4b50b3058f14e Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:08:18 -0700 Subject: [PATCH 5840/7006] IB/srp: Remove use_mr argument from srp_map_sg_entry() Move the srp_map_desc() call from inside srp_map_sg_entry() to srp_map_sg() such that the use_mr argument can be removed from srp_map_sg_entry(). Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 36 ++++++++++++----------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index acda65936588d..9f57fa0047247 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1260,6 +1260,8 @@ static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr, { struct srp_direct_buf *desc = state->desc; + WARN_ON_ONCE(!dma_len); + desc->va = cpu_to_be64(dma_addr); desc->key = cpu_to_be32(rkey); desc->len = cpu_to_be32(dma_len); @@ -1366,29 +1368,17 @@ static int srp_finish_mapping(struct srp_map_state *state, static int srp_map_sg_entry(struct srp_map_state *state, struct srp_rdma_ch *ch, - struct scatterlist *sg, int sg_index, - bool use_mr) + struct scatterlist *sg, int sg_index) { struct srp_target_port *target = ch->target; struct srp_device *dev = target->srp_host->srp_dev; struct ib_device *ibdev = dev->dev; dma_addr_t dma_addr = ib_sg_dma_address(ibdev, sg); unsigned int dma_len = ib_sg_dma_len(ibdev, sg); - unsigned int len; + unsigned int len = 0; int ret; - if (!dma_len) - return 0; - - if (!use_mr) { - /* - * Once we're in direct map mode for a request, we don't - * go back to FMR or FR mode, so no need to update anything - * other than the descriptor. - */ - srp_map_desc(state, dma_addr, dma_len, target->rkey); - return 0; - } + WARN_ON_ONCE(!dma_len); while (dma_len) { unsigned offset = dma_addr & ~dev->mr_page_mask; @@ -1441,16 +1431,20 @@ static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch, use_mr = !!ch->fmr_pool; } - for_each_sg(scat, sg, count, i) { - ret = srp_map_sg_entry(state, ch, sg, i, use_mr); - if (ret) - goto out; - } - if (use_mr) { + for_each_sg(scat, sg, count, i) { + ret = srp_map_sg_entry(state, ch, sg, i); + if (ret) + goto out; + } ret = srp_finish_mapping(state, ch); if (ret) goto out; + } else { + for_each_sg(scat, sg, count, i) { + srp_map_desc(state, ib_sg_dma_address(dev->dev, sg), + ib_sg_dma_len(dev->dev, sg), target->rkey); + } } req->nmdesc = state->nmdesc; -- GitLab From 002f15674c84fb4c38ed5237c1e7235e09c033f0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:08:44 -0700 Subject: [PATCH 5841/7006] IB/srp: Introduce srp_device.use_fmr Introduce the variable srp_device.use_fmr. Leave out the dev->has_fr / dev->has_fmr and ch->fr_pool / ch->fmr_pool checks since these are redundant. This patch does not change any functionality but makes the source code easier to read. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 22 +++++++++++----------- drivers/infiniband/ulp/srp/ib_srp.h | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 9f57fa0047247..8f385afdba87a 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -546,7 +546,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) if (ret) goto err_qp; - if (dev->use_fast_reg && dev->has_fr) { + if (dev->use_fast_reg) { fr_pool = srp_alloc_fr_pool(target); if (IS_ERR(fr_pool)) { ret = PTR_ERR(fr_pool); @@ -557,7 +557,7 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) if (ch->fr_pool) srp_destroy_fr_pool(ch->fr_pool); ch->fr_pool = fr_pool; - } else if (!dev->use_fast_reg && dev->has_fmr) { + } else if (dev->use_fmr) { fmr_pool = srp_alloc_fmr_pool(target); if (IS_ERR(fmr_pool)) { ret = PTR_ERR(fmr_pool); @@ -623,7 +623,7 @@ static void srp_free_ch_ib(struct srp_target_port *target, if (dev->use_fast_reg) { if (ch->fr_pool) srp_destroy_fr_pool(ch->fr_pool); - } else { + } else if (dev->use_fmr) { if (ch->fmr_pool) ib_destroy_fmr_pool(ch->fmr_pool); } @@ -1085,7 +1085,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd, if (req->nmdesc) srp_fr_pool_put(ch->fr_pool, req->fr_list, req->nmdesc); - } else { + } else if (dev->use_fmr) { struct ib_pool_fmr **pfmr; for (i = req->nmdesc, pfmr = req->fmr_list; i > 0; i--, pfmr++) @@ -1345,8 +1345,11 @@ static int srp_finish_mapping(struct srp_map_state *state, struct srp_rdma_ch *ch) { struct srp_target_port *target = ch->target; + struct srp_device *dev = target->srp_host->srp_dev; int ret = 0; + WARN_ON_ONCE(!dev->use_fast_reg && !dev->use_fmr); + if (state->npages == 0) return 0; @@ -1354,8 +1357,7 @@ static int srp_finish_mapping(struct srp_map_state *state, srp_map_desc(state, state->base_dma_addr, state->dma_len, target->rkey); else - ret = target->srp_host->srp_dev->use_fast_reg ? - srp_map_finish_fr(state, ch) : + ret = dev->use_fast_reg ? srp_map_finish_fr(state, ch) : srp_map_finish_fmr(state, ch); if (ret == 0) { @@ -1417,21 +1419,18 @@ static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch, struct srp_device *dev = target->srp_host->srp_dev; struct scatterlist *sg; int i, ret; - bool use_mr; state->desc = req->indirect_desc; state->pages = req->map_page; if (dev->use_fast_reg) { state->fr.next = req->fr_list; state->fr.end = req->fr_list + target->cmd_sg_cnt; - use_mr = !!ch->fr_pool; - } else { + } else if (dev->use_fmr) { state->fmr.next = req->fmr_list; state->fmr.end = req->fmr_list + target->cmd_sg_cnt; - use_mr = !!ch->fmr_pool; } - if (use_mr) { + if (dev->use_fast_reg || dev->use_fmr) { for_each_sg(scat, sg, count, i) { ret = srp_map_sg_entry(state, ch, sg, i); if (ret) @@ -3364,6 +3363,7 @@ static void srp_add_one(struct ib_device *device) srp_dev->use_fast_reg = (srp_dev->has_fr && (!srp_dev->has_fmr || prefer_fr)); + srp_dev->use_fmr = !srp_dev->use_fast_reg && srp_dev->has_fmr; /* * Use the smallest page size supported by the HCA, down to a diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 1e424181fdf85..60a33c1de3286 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -102,6 +102,7 @@ struct srp_device { int max_pages_per_mr; bool has_fmr; bool has_fr; + bool use_fmr; bool use_fast_reg; }; -- GitLab From 330179f2fa93c1c6c41a90c7deabc98e363018e5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:09:05 -0700 Subject: [PATCH 5842/7006] IB/srp: Register the indirect data buffer descriptor Instead of always using the global rkey for the indirect data buffer descriptor, register that descriptor with the HCA if the kernel module parameter register_always has been set to Y. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 57 +++++++++++++++++++++++++++-- drivers/infiniband/ulp/srp/ib_srp.h | 4 ++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 8f385afdba87a..45b81f1a8d882 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1453,18 +1453,58 @@ out: return ret; } +/* + * Register the indirect data buffer descriptor with the HCA. + * + * Note: since the indirect data buffer descriptor has been allocated with + * kmalloc() it is guaranteed that this buffer is a physically contiguous + * memory buffer. + */ +static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, + void **next_mr, void **end_mr, u32 idb_len, + __be32 *idb_rkey) +{ + struct srp_target_port *target = ch->target; + struct srp_device *dev = target->srp_host->srp_dev; + struct srp_map_state state; + struct srp_direct_buf idb_desc; + u64 idb_pages[1]; + int ret; + + memset(&state, 0, sizeof(state)); + memset(&idb_desc, 0, sizeof(idb_desc)); + state.gen.next = next_mr; + state.gen.end = end_mr; + state.desc = &idb_desc; + state.pages = idb_pages; + state.pages[0] = (req->indirect_dma_addr & + dev->mr_page_mask); + state.npages = 1; + state.base_dma_addr = req->indirect_dma_addr; + state.dma_len = idb_len; + ret = srp_finish_mapping(&state, ch); + if (ret < 0) + goto out; + + *idb_rkey = idb_desc.key; + +out: + return ret; +} + static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, struct srp_request *req) { struct srp_target_port *target = ch->target; struct scatterlist *scat; struct srp_cmd *cmd = req->cmd->buf; - int len, nents, count; + int len, nents, count, ret; struct srp_device *dev; struct ib_device *ibdev; struct srp_map_state state; struct srp_indirect_buf *indirect_hdr; - u32 table_len; + u32 idb_len, table_len; + __be32 idb_rkey; u8 fmt; if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE) @@ -1546,6 +1586,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, count = min(state.ndesc, target->cmd_sg_cnt); table_len = state.ndesc * sizeof (struct srp_direct_buf); + idb_len = sizeof(struct srp_indirect_buf) + table_len; fmt = SRP_DATA_DESC_INDIRECT; len = sizeof(struct srp_cmd) + sizeof (struct srp_indirect_buf); @@ -1554,8 +1595,18 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, memcpy(indirect_hdr->desc_list, req->indirect_desc, count * sizeof (struct srp_direct_buf)); + if (register_always && (dev->use_fast_reg || dev->use_fmr)) { + ret = srp_map_idb(ch, req, state.gen.next, state.gen.end, + idb_len, &idb_rkey); + if (ret < 0) + return ret; + req->nmdesc++; + } else { + idb_rkey = target->rkey; + } + indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); - indirect_hdr->table_desc.key = cpu_to_be32(target->rkey); + indirect_hdr->table_desc.key = idb_rkey; indirect_hdr->table_desc.len = cpu_to_be32(table_len); indirect_hdr->len = cpu_to_be32(state.total_len); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 60a33c1de3286..255b0e591aa47 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -288,6 +288,10 @@ struct srp_map_state { struct srp_fr_desc **next; struct srp_fr_desc **end; } fr; + struct { + void **next; + void **end; + } gen; }; struct srp_direct_buf *desc; u64 *pages; -- GitLab From 03f6fb93fde24f01a940283bdf55024e576ee87d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 10 Aug 2015 17:09:36 -0700 Subject: [PATCH 5843/7006] IB/srp: Create an insecure all physical rkey only if needed The SRP initiator only needs this if the insecure register_always=N performance optimization is enabled, or if FRWR/FMR is not supported in the driver. Do not create an all physical MR unless it is needed to support either of those modes. Default register_always to true so the out of the box configuration does not create an insecure all physical MR. Signed-off-by: Jason Gunthorpe [bvanassche: reworked and rebased this patch] Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 40 +++++++++++++++++------------ drivers/infiniband/ulp/srp/ib_srp.h | 4 +-- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 45b81f1a8d882..ca98d3b472815 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -68,8 +68,8 @@ static unsigned int srp_sg_tablesize; static unsigned int cmd_sg_entries; static unsigned int indirect_sg_entries; static bool allow_ext_sg; -static bool prefer_fr; -static bool register_always; +static bool prefer_fr = true; +static bool register_always = true; static int topspin_workarounds = 1; module_param(srp_sg_tablesize, uint, 0444); @@ -1353,9 +1353,9 @@ static int srp_finish_mapping(struct srp_map_state *state, if (state->npages == 0) return 0; - if (state->npages == 1 && !register_always) + if (state->npages == 1 && target->global_mr) srp_map_desc(state, state->base_dma_addr, state->dma_len, - target->rkey); + target->global_mr->rkey); else ret = dev->use_fast_reg ? srp_map_finish_fr(state, ch) : srp_map_finish_fmr(state, ch); @@ -1442,7 +1442,8 @@ static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch, } else { for_each_sg(scat, sg, count, i) { srp_map_desc(state, ib_sg_dma_address(dev->dev, sg), - ib_sg_dma_len(dev->dev, sg), target->rkey); + ib_sg_dma_len(dev->dev, sg), + target->global_mr->rkey); } } @@ -1531,7 +1532,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, fmt = SRP_DATA_DESC_DIRECT; len = sizeof (struct srp_cmd) + sizeof (struct srp_direct_buf); - if (count == 1 && !register_always) { + if (count == 1 && target->global_mr) { /* * The midlayer only generated a single gather/scatter * entry, or DMA mapping coalesced everything to a @@ -1541,7 +1542,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, struct srp_direct_buf *buf = (void *) cmd->add_data; buf->va = cpu_to_be64(ib_sg_dma_address(ibdev, scat)); - buf->key = cpu_to_be32(target->rkey); + buf->key = cpu_to_be32(target->global_mr->rkey); buf->len = cpu_to_be32(ib_sg_dma_len(ibdev, scat)); req->nmdesc = 0; @@ -1595,14 +1596,14 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, memcpy(indirect_hdr->desc_list, req->indirect_desc, count * sizeof (struct srp_direct_buf)); - if (register_always && (dev->use_fast_reg || dev->use_fmr)) { + if (!target->global_mr) { ret = srp_map_idb(ch, req, state.gen.next, state.gen.end, idb_len, &idb_rkey); if (ret < 0) return ret; req->nmdesc++; } else { - idb_rkey = target->rkey; + idb_rkey = target->global_mr->rkey; } indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr); @@ -3157,7 +3158,7 @@ static ssize_t srp_create_target(struct device *dev, target->scsi_host = target_host; target->srp_host = host; target->lkey = host->srp_dev->pd->local_dma_lkey; - target->rkey = host->srp_dev->mr->rkey; + target->global_mr = host->srp_dev->global_mr; target->cmd_sg_cnt = cmd_sg_entries; target->sg_tablesize = indirect_sg_entries ? : cmd_sg_entries; target->allow_ext_sg = allow_ext_sg; @@ -3447,12 +3448,16 @@ static void srp_add_one(struct ib_device *device) if (IS_ERR(srp_dev->pd)) goto free_dev; - srp_dev->mr = ib_get_dma_mr(srp_dev->pd, - IB_ACCESS_LOCAL_WRITE | - IB_ACCESS_REMOTE_READ | - IB_ACCESS_REMOTE_WRITE); - if (IS_ERR(srp_dev->mr)) - goto err_pd; + if (!register_always || (!srp_dev->has_fmr && !srp_dev->has_fr)) { + srp_dev->global_mr = ib_get_dma_mr(srp_dev->pd, + IB_ACCESS_LOCAL_WRITE | + IB_ACCESS_REMOTE_READ | + IB_ACCESS_REMOTE_WRITE); + if (IS_ERR(srp_dev->global_mr)) + goto err_pd; + } else { + srp_dev->global_mr = NULL; + } for (p = rdma_start_port(device); p <= rdma_end_port(device); ++p) { host = srp_add_port(srp_dev, p); @@ -3509,7 +3514,8 @@ static void srp_remove_one(struct ib_device *device, void *client_data) kfree(host); } - ib_dereg_mr(srp_dev->mr); + if (srp_dev->global_mr) + ib_dereg_mr(srp_dev->global_mr); ib_dealloc_pd(srp_dev->pd); kfree(srp_dev); diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h index 255b0e591aa47..3608f2e4819c4 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.h +++ b/drivers/infiniband/ulp/srp/ib_srp.h @@ -95,7 +95,7 @@ struct srp_device { struct list_head dev_list; struct ib_device *dev; struct ib_pd *pd; - struct ib_mr *mr; + struct ib_mr *global_mr; u64 mr_page_mask; int mr_page_size; int mr_max_size; @@ -183,10 +183,10 @@ struct srp_target_port { spinlock_t lock; /* read only in the hot path */ + struct ib_mr *global_mr; struct srp_rdma_ch *ch; u32 ch_count; u32 lkey; - u32 rkey; enum srp_target_state state; unsigned int max_iu_len; unsigned int cmd_sg_cnt; -- GitLab From 7dd78647a2c2c224e376fc72797d411a3a0bb047 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 5 Aug 2015 14:34:31 -0600 Subject: [PATCH 5844/7006] IB/core: Make ib_dealloc_pd return void The majority of callers never check the return value, and even if they did, they can't do anything about a failure. All possible failure cases represent a bug in the caller, so just WARN_ON inside the function instead. This fixes a few random errors: net/rd/iw.c infinite loops while it fails. (racing with EBUSY?) This also lays the ground work to get rid of error return from the drivers. Most drivers do not error, the few that do are broken since it cannot be handled. Since uverbs can legitimately make use of EBUSY, open code the check. Signed-off-by: Jason Gunthorpe Reviewed-by: Chuck Lever Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 22 +++++++++++++----- drivers/infiniband/core/verbs.c | 26 +++++++++++++++++----- drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 4 +--- drivers/infiniband/ulp/iser/iser_verbs.c | 2 +- include/rdma/ib_verbs.h | 6 +---- net/rds/iw.c | 5 +---- net/sunrpc/xprtrdma/verbs.c | 2 +- 7 files changed, 41 insertions(+), 26 deletions(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 258485ee46b2e..4c98696e3626d 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -606,6 +606,7 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, { struct ib_uverbs_dealloc_pd cmd; struct ib_uobject *uobj; + struct ib_pd *pd; int ret; if (copy_from_user(&cmd, buf, sizeof cmd)) @@ -614,15 +615,20 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, uobj = idr_write_uobj(&ib_uverbs_pd_idr, cmd.pd_handle, file->ucontext); if (!uobj) return -EINVAL; + pd = uobj->object; - ret = ib_dealloc_pd(uobj->object); - if (!ret) - uobj->live = 0; - - put_uobj_write(uobj); + if (atomic_read(&pd->usecnt)) { + ret = -EBUSY; + goto err_put; + } + ret = pd->device->dealloc_pd(uobj->object); + WARN_ONCE(ret, "Infiniband HW driver failed dealloc_pd"); if (ret) - return ret; + goto err_put; + + uobj->live = 0; + put_uobj_write(uobj); idr_remove_uobj(&ib_uverbs_pd_idr, uobj); @@ -633,6 +639,10 @@ ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, put_uobj(uobj); return in_len; + +err_put: + put_uobj_write(uobj); + return ret; } struct xrcd_table_entry { diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 2e5fd89a89292..aad8b3ce66cce 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -260,18 +260,32 @@ struct ib_pd *ib_alloc_pd(struct ib_device *device) } EXPORT_SYMBOL(ib_alloc_pd); -int ib_dealloc_pd(struct ib_pd *pd) +/** + * ib_dealloc_pd - Deallocates a protection domain. + * @pd: The protection domain to deallocate. + * + * It is an error to call this function while any resources in the pd still + * exist. The caller is responsible to synchronously destroy them and + * guarantee no new allocations will happen. + */ +void ib_dealloc_pd(struct ib_pd *pd) { + int ret; + if (pd->local_mr) { - if (ib_dereg_mr(pd->local_mr)) - return -EBUSY; + ret = ib_dereg_mr(pd->local_mr); + WARN_ON(ret); pd->local_mr = NULL; } - if (atomic_read(&pd->usecnt)) - return -EBUSY; + /* uverbs manipulates usecnt with proper locking, while the kabi + requires the caller to guarantee we can't race here. */ + WARN_ON(atomic_read(&pd->usecnt)); - return pd->device->dealloc_pd(pd); + /* Making delalloc_pd a void return is a WIP, no driver should return + an error here. */ + ret = pd->device->dealloc_pd(pd); + WARN_ONCE(ret, "Infiniband HW driver failed dealloc_pd"); } EXPORT_SYMBOL(ib_dealloc_pd); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index 8c451983d8a5a..78845b6e8b812 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c @@ -280,9 +280,7 @@ void ipoib_transport_dev_cleanup(struct net_device *dev) priv->wq = NULL; } - if (ib_dealloc_pd(priv->pd)) - ipoib_warn(priv, "ib_dealloc_pd failed\n"); - + ib_dealloc_pd(priv->pd); } void ipoib_event(struct ib_event_handler *handler, diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index ad2d2b50cd7f0..ae70cc1463ac2 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -185,7 +185,7 @@ static void iser_free_device_ib_res(struct iser_device *device) (void)ib_unregister_event_handler(&device->event_handler); (void)ib_dereg_mr(device->mr); - (void)ib_dealloc_pd(device->pd); + ib_dealloc_pd(device->pd); kfree(device->comps); device->comps = NULL; diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 09400512d5798..128abf2888ab7 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2196,11 +2196,7 @@ int ib_find_pkey(struct ib_device *device, struct ib_pd *ib_alloc_pd(struct ib_device *device); -/** - * ib_dealloc_pd - Deallocates a protection domain. - * @pd: The protection domain to deallocate. - */ -int ib_dealloc_pd(struct ib_pd *pd); +void ib_dealloc_pd(struct ib_pd *pd); /** * ib_create_ah - Creates an address handle for the given address vector. diff --git a/net/rds/iw.c b/net/rds/iw.c index 7cc2f32a0cb38..c7dcddbf17cb5 100644 --- a/net/rds/iw.c +++ b/net/rds/iw.c @@ -148,10 +148,7 @@ static void rds_iw_remove_one(struct ib_device *device, void *client_data) if (rds_iwdev->mr) ib_dereg_mr(rds_iwdev->mr); - while (ib_dealloc_pd(rds_iwdev->pd)) { - rdsdebug("Failed to dealloc pd %p\n", rds_iwdev->pd); - msleep(1); - } + ib_dealloc_pd(rds_iwdev->pd); list_del(&rds_iwdev->list); kfree(rds_iwdev); diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 891c4ede2c20e..afd504375a9a9 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -624,7 +624,7 @@ rpcrdma_ia_close(struct rpcrdma_ia *ia) /* If the pd is still busy, xprtrdma missed freeing a resource */ if (ia->ri_pd && !IS_ERR(ia->ri_pd)) - WARN_ON(ib_dealloc_pd(ia->ri_pd)); + ib_dealloc_pd(ia->ri_pd); } /* -- GitLab From 03c40442a0e66fa52aec6733ea88804fe7d12c77 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 13 Aug 2015 18:32:02 +0300 Subject: [PATCH 5845/7006] IB/uverbs: Fix reference counting usage of event files Fix the reference counting usage to be handled in the event file creation/destruction function, instead of being done by the caller. This is done for both async/non-async event files. Based on Jason Gunthorpe report at https://www.mail-archive.com/ linux-rdma@vger.kernel.org/msg24680.html: "The existing code for this is broken, in ib_uverbs_get_context all the error paths between ib_uverbs_alloc_event_file and the kref_get(file->ref) are wrong - this will result in fput() which will call ib_uverbs_event_close, which will try to do kref_put and ib_unregister_event_handler - which are no longer paired." Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs.h | 1 + drivers/infiniband/core/uverbs_cmd.c | 11 +------ drivers/infiniband/core/uverbs_main.c | 44 +++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index ba365b6d1e8d5..60e6e3d8356ae 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -178,6 +178,7 @@ void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, int is_async); +void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); void ib_uverbs_release_ucq(struct ib_uverbs_file *file, diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 4c98696e3626d..ae2d5972e2022 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -367,16 +367,6 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, goto err_file; } - file->async_file = filp->private_data; - - INIT_IB_EVENT_HANDLER(&file->event_handler, file->device->ib_dev, - ib_uverbs_event_handler); - ret = ib_register_event_handler(&file->event_handler); - if (ret) - goto err_file; - - kref_get(&file->async_file->ref); - kref_get(&file->ref); file->ucontext = ucontext; fd_install(resp.async_fd, filp); @@ -386,6 +376,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, return in_len; err_file: + ib_uverbs_free_async_event_file(file); fput(filp); err_fd: diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 46c92294afa51..7536a4c81d326 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -406,10 +406,9 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp) } spin_unlock_irq(&file->lock); - if (file->is_async) { + if (file->is_async) ib_unregister_event_handler(&file->uverbs_file->event_handler); - kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); - } + kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); kref_put(&file->ref, ib_uverbs_release_event_file); return 0; @@ -541,13 +540,20 @@ void ib_uverbs_event_handler(struct ib_event_handler *handler, NULL, NULL); } +void ib_uverbs_free_async_event_file(struct ib_uverbs_file *file) +{ + kref_put(&file->async_file->ref, ib_uverbs_release_event_file); + file->async_file = NULL; +} + struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, int is_async) { struct ib_uverbs_event_file *ev_file; struct file *filp; + int ret; - ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL); + ev_file = kzalloc(sizeof(*ev_file), GFP_KERNEL); if (!ev_file) return ERR_PTR(-ENOMEM); @@ -556,15 +562,41 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, INIT_LIST_HEAD(&ev_file->event_list); init_waitqueue_head(&ev_file->poll_wait); ev_file->uverbs_file = uverbs_file; + kref_get(&ev_file->uverbs_file->ref); ev_file->async_queue = NULL; - ev_file->is_async = is_async; ev_file->is_closed = 0; filp = anon_inode_getfile("[infinibandevent]", &uverbs_event_fops, ev_file, O_RDONLY); if (IS_ERR(filp)) - kfree(ev_file); + goto err_put_refs; + + if (is_async) { + WARN_ON(uverbs_file->async_file); + uverbs_file->async_file = ev_file; + kref_get(&uverbs_file->async_file->ref); + INIT_IB_EVENT_HANDLER(&uverbs_file->event_handler, + uverbs_file->device->ib_dev, + ib_uverbs_event_handler); + ret = ib_register_event_handler(&uverbs_file->event_handler); + if (ret) + goto err_put_file; + + /* At that point async file stuff was fully set */ + ev_file->is_async = 1; + } + + return filp; + +err_put_file: + fput(filp); + kref_put(&uverbs_file->async_file->ref, ib_uverbs_release_event_file); + uverbs_file->async_file = NULL; + return ERR_PTR(ret); +err_put_refs: + kref_put(&ev_file->uverbs_file->ref, ib_uverbs_release_file); + kref_put(&ev_file->ref, ib_uverbs_release_event_file); return filp; } -- GitLab From 35d4a0b63dc0c6d1177d4f532a9deae958f0662c Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 13 Aug 2015 18:32:03 +0300 Subject: [PATCH 5846/7006] IB/uverbs: Fix race between ib_uverbs_open and remove_one Fixes: 2a72f212263701b927559f6850446421d5906c41 ("IB/uverbs: Remove dev_table") Before this commit there was a device look-up table that was protected by a spin_lock used by ib_uverbs_open and by ib_uverbs_remove_one. When it was dropped and container_of was used instead, it enabled the race with remove_one as dev might be freed just after: dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev) but before the kref_get. In addition, this buggy patch added some dead code as container_of(x,y,z) can never be NULL and so dev can never be NULL. As a result the comment above ib_uverbs_open saying "the open method will either immediately run -ENXIO" is wrong as it can never happen. The solution follows Jason Gunthorpe suggestion from below URL: https://www.mail-archive.com/linux-rdma@vger.kernel.org/msg25692.html cdev will hold a kref on the parent (the containing structure, ib_uverbs_device) and only when that kref is released it is guaranteed that open will never be called again. In addition, fixes the active count scheme to use an atomic not a kref to prevent WARN_ON as pointed by above comment from Jason. Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs.h | 3 +- drivers/infiniband/core/uverbs_main.c | 43 +++++++++++++++++++-------- 2 files changed, 32 insertions(+), 14 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 60e6e3d8356ae..92ec765a45be7 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -85,7 +85,7 @@ */ struct ib_uverbs_device { - struct kref ref; + atomic_t refcount; int num_comp_vectors; struct completion comp; struct device *dev; @@ -94,6 +94,7 @@ struct ib_uverbs_device { struct cdev cdev; struct rb_root xrcd_tree; struct mutex xrcd_tree_mutex; + struct kobject kobj; }; struct ib_uverbs_event_file { diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 7536a4c81d326..e05bbb213d2cd 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -130,14 +130,18 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, static void ib_uverbs_add_one(struct ib_device *device); static void ib_uverbs_remove_one(struct ib_device *device, void *client_data); -static void ib_uverbs_release_dev(struct kref *ref) +static void ib_uverbs_release_dev(struct kobject *kobj) { struct ib_uverbs_device *dev = - container_of(ref, struct ib_uverbs_device, ref); + container_of(kobj, struct ib_uverbs_device, kobj); - complete(&dev->comp); + kfree(dev); } +static struct kobj_type ib_uverbs_dev_ktype = { + .release = ib_uverbs_release_dev, +}; + static void ib_uverbs_release_event_file(struct kref *ref) { struct ib_uverbs_event_file *file = @@ -303,13 +307,19 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, return context->device->dealloc_ucontext(context); } +static void ib_uverbs_comp_dev(struct ib_uverbs_device *dev) +{ + complete(&dev->comp); +} + static void ib_uverbs_release_file(struct kref *ref) { struct ib_uverbs_file *file = container_of(ref, struct ib_uverbs_file, ref); module_put(file->device->ib_dev->owner); - kref_put(&file->device->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&file->device->refcount)) + ib_uverbs_comp_dev(file->device); kfree(file); } @@ -775,9 +785,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) int ret; dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev); - if (dev) - kref_get(&dev->ref); - else + if (!atomic_inc_not_zero(&dev->refcount)) return -ENXIO; if (!try_module_get(dev->ib_dev->owner)) { @@ -798,6 +806,7 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) mutex_init(&file->mutex); filp->private_data = file; + kobject_get(&dev->kobj); return nonseekable_open(inode, filp); @@ -805,13 +814,16 @@ err_module: module_put(dev->ib_dev->owner); err: - kref_put(&dev->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&dev->refcount)) + ib_uverbs_comp_dev(dev); + return ret; } static int ib_uverbs_close(struct inode *inode, struct file *filp) { struct ib_uverbs_file *file = filp->private_data; + struct ib_uverbs_device *dev = file->device; ib_uverbs_cleanup_ucontext(file, file->ucontext); @@ -819,6 +831,7 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp) kref_put(&file->async_file->ref, ib_uverbs_release_event_file); kref_put(&file->ref, ib_uverbs_release_file); + kobject_put(&dev->kobj); return 0; } @@ -914,10 +927,11 @@ static void ib_uverbs_add_one(struct ib_device *device) if (!uverbs_dev) return; - kref_init(&uverbs_dev->ref); + atomic_set(&uverbs_dev->refcount, 1); init_completion(&uverbs_dev->comp); uverbs_dev->xrcd_tree = RB_ROOT; mutex_init(&uverbs_dev->xrcd_tree_mutex); + kobject_init(&uverbs_dev->kobj, &ib_uverbs_dev_ktype); spin_lock(&map_lock); devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); @@ -944,6 +958,7 @@ static void ib_uverbs_add_one(struct ib_device *device) cdev_init(&uverbs_dev->cdev, NULL); uverbs_dev->cdev.owner = THIS_MODULE; uverbs_dev->cdev.ops = device->mmap ? &uverbs_mmap_fops : &uverbs_fops; + uverbs_dev->cdev.kobj.parent = &uverbs_dev->kobj; kobject_set_name(&uverbs_dev->cdev.kobj, "uverbs%d", uverbs_dev->devnum); if (cdev_add(&uverbs_dev->cdev, base, 1)) goto err_cdev; @@ -974,9 +989,10 @@ err_cdev: clear_bit(devnum, overflow_map); err: - kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&uverbs_dev->refcount)) + ib_uverbs_comp_dev(uverbs_dev); wait_for_completion(&uverbs_dev->comp); - kfree(uverbs_dev); + kobject_put(&uverbs_dev->kobj); return; } @@ -996,9 +1012,10 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) else clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map); - kref_put(&uverbs_dev->ref, ib_uverbs_release_dev); + if (atomic_dec_and_test(&uverbs_dev->refcount)) + ib_uverbs_comp_dev(uverbs_dev); wait_for_completion(&uverbs_dev->comp); - kfree(uverbs_dev); + kobject_put(&uverbs_dev->kobj); } static char *uverbs_devnode(struct device *dev, umode_t *mode) -- GitLab From 057aec0d23f750b27f0bb92d2606871f60417e0a Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 13 Aug 2015 18:32:04 +0300 Subject: [PATCH 5847/7006] IB/uverbs: Explicitly pass ib_dev to uverbs commands Done in preparation for deploying RCU for the device removal flow. Allows isolating the RCU handling to the uverb_main layer and keeping the uverbs_cmd code as is. Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs.h | 3 + drivers/infiniband/core/uverbs_cmd.c | 103 +++++++++++++++++--------- drivers/infiniband/core/uverbs_main.c | 21 ++++-- 3 files changed, 88 insertions(+), 39 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index 92ec765a45be7..ea52db1962117 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -178,6 +178,7 @@ extern struct idr ib_uverbs_rule_idr; void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + struct ib_device *ib_dev, int is_async); void ib_uverbs_free_async_event_file(struct ib_uverbs_file *uverbs_file); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); @@ -214,6 +215,7 @@ struct ib_uverbs_flow_spec { #define IB_UVERBS_DECLARE_CMD(name) \ ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \ + struct ib_device *ib_dev, \ const char __user *buf, int in_len, \ int out_len) @@ -255,6 +257,7 @@ IB_UVERBS_DECLARE_CMD(close_xrcd); #define IB_UVERBS_DECLARE_EX_CMD(name) \ int ib_uverbs_ex_##name(struct ib_uverbs_file *file, \ + struct ib_device *ib_dev, \ struct ib_udata *ucore, \ struct ib_udata *uhw) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index ae2d5972e2022..a15318a54b311 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -282,13 +282,13 @@ static void put_xrcd_read(struct ib_uobject *uobj) } ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { struct ib_uverbs_get_context cmd; struct ib_uverbs_get_context_resp resp; struct ib_udata udata; - struct ib_device *ibdev = file->device->ib_dev; #ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING struct ib_device_attr dev_attr; #endif @@ -313,13 +313,13 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - ucontext = ibdev->alloc_ucontext(ibdev, &udata); + ucontext = ib_dev->alloc_ucontext(ib_dev, &udata); if (IS_ERR(ucontext)) { ret = PTR_ERR(ucontext); goto err; } - ucontext->device = ibdev; + ucontext->device = ib_dev; INIT_LIST_HEAD(&ucontext->pd_list); INIT_LIST_HEAD(&ucontext->mr_list); INIT_LIST_HEAD(&ucontext->mw_list); @@ -340,7 +340,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, ucontext->odp_mrs_count = 0; INIT_LIST_HEAD(&ucontext->no_private_counters); - ret = ib_query_device(ibdev, &dev_attr); + ret = ib_query_device(ib_dev, &dev_attr); if (ret) goto err_free; if (!(dev_attr.device_cap_flags & IB_DEVICE_ON_DEMAND_PAGING)) @@ -355,7 +355,7 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file, goto err_free; resp.async_fd = ret; - filp = ib_uverbs_alloc_event_file(file, 1); + filp = ib_uverbs_alloc_event_file(file, ib_dev, 1); if (IS_ERR(filp)) { ret = PTR_ERR(filp); goto err_fd; @@ -384,7 +384,7 @@ err_fd: err_free: put_pid(ucontext->tgid); - ibdev->dealloc_ucontext(ucontext); + ib_dev->dealloc_ucontext(ucontext); err: mutex_unlock(&file->mutex); @@ -392,11 +392,12 @@ err: } static void copy_query_dev_fields(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_uverbs_query_device_resp *resp, struct ib_device_attr *attr) { resp->fw_ver = attr->fw_ver; - resp->node_guid = file->device->ib_dev->node_guid; + resp->node_guid = ib_dev->node_guid; resp->sys_image_guid = attr->sys_image_guid; resp->max_mr_size = attr->max_mr_size; resp->page_size_cap = attr->page_size_cap; @@ -434,10 +435,11 @@ static void copy_query_dev_fields(struct ib_uverbs_file *file, resp->max_srq_sge = attr->max_srq_sge; resp->max_pkeys = attr->max_pkeys; resp->local_ca_ack_delay = attr->local_ca_ack_delay; - resp->phys_port_cnt = file->device->ib_dev->phys_port_cnt; + resp->phys_port_cnt = ib_dev->phys_port_cnt; } ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -452,12 +454,12 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - ret = ib_query_device(file->device->ib_dev, &attr); + ret = ib_query_device(ib_dev, &attr); if (ret) return ret; memset(&resp, 0, sizeof resp); - copy_query_dev_fields(file, &resp, &attr); + copy_query_dev_fields(file, ib_dev, &resp, &attr); if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp)) @@ -467,6 +469,7 @@ ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file, } ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -481,7 +484,7 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; - ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr); + ret = ib_query_port(ib_dev, cmd.port_num, &attr); if (ret) return ret; @@ -506,7 +509,7 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, resp.active_width = attr.active_width; resp.active_speed = attr.active_speed; resp.phys_state = attr.phys_state; - resp.link_layer = rdma_port_get_link_layer(file->device->ib_dev, + resp.link_layer = rdma_port_get_link_layer(ib_dev, cmd.port_num); if (copy_to_user((void __user *) (unsigned long) cmd.response, @@ -517,6 +520,7 @@ ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file, } ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -544,14 +548,13 @@ ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file, init_uobj(uobj, 0, file->ucontext, &pd_lock_class); down_write(&uobj->mutex); - pd = file->device->ib_dev->alloc_pd(file->device->ib_dev, - file->ucontext, &udata); + pd = ib_dev->alloc_pd(ib_dev, file->ucontext, &udata); if (IS_ERR(pd)) { ret = PTR_ERR(pd); goto err; } - pd->device = file->device->ib_dev; + pd->device = ib_dev; pd->uobject = uobj; pd->local_mr = NULL; atomic_set(&pd->usecnt, 0); @@ -592,6 +595,7 @@ err: } ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -722,6 +726,7 @@ static void xrcd_table_delete(struct ib_uverbs_device *dev, } ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -780,15 +785,14 @@ ssize_t ib_uverbs_open_xrcd(struct ib_uverbs_file *file, down_write(&obj->uobject.mutex); if (!xrcd) { - xrcd = file->device->ib_dev->alloc_xrcd(file->device->ib_dev, - file->ucontext, &udata); + xrcd = ib_dev->alloc_xrcd(ib_dev, file->ucontext, &udata); if (IS_ERR(xrcd)) { ret = PTR_ERR(xrcd); goto err; } xrcd->inode = inode; - xrcd->device = file->device->ib_dev; + xrcd->device = ib_dev; atomic_set(&xrcd->usecnt, 0); mutex_init(&xrcd->tgt_qp_mutex); INIT_LIST_HEAD(&xrcd->tgt_qp_list); @@ -859,6 +863,7 @@ err_tree_mutex_unlock: } ssize_t ib_uverbs_close_xrcd(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -936,6 +941,7 @@ void ib_uverbs_dealloc_xrcd(struct ib_uverbs_device *dev, } ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1045,6 +1051,7 @@ err_free: } ssize_t ib_uverbs_rereg_mr(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1138,6 +1145,7 @@ put_uobjs: } ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1176,8 +1184,9 @@ ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file, } ssize_t ib_uverbs_alloc_mw(struct ib_uverbs_file *file, - const char __user *buf, int in_len, - int out_len) + struct ib_device *ib_dev, + const char __user *buf, int in_len, + int out_len) { struct ib_uverbs_alloc_mw cmd; struct ib_uverbs_alloc_mw_resp resp; @@ -1258,8 +1267,9 @@ err_free: } ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file, - const char __user *buf, int in_len, - int out_len) + struct ib_device *ib_dev, + const char __user *buf, int in_len, + int out_len) { struct ib_uverbs_dealloc_mw cmd; struct ib_mw *mw; @@ -1296,6 +1306,7 @@ ssize_t ib_uverbs_dealloc_mw(struct ib_uverbs_file *file, } ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1315,7 +1326,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, return ret; resp.fd = ret; - filp = ib_uverbs_alloc_event_file(file, 0); + filp = ib_uverbs_alloc_event_file(file, ib_dev, 0); if (IS_ERR(filp)) { put_unused_fd(resp.fd); return PTR_ERR(filp); @@ -1333,6 +1344,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file, } static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_udata *ucore, struct ib_udata *uhw, struct ib_uverbs_ex_create_cq *cmd, @@ -1381,14 +1393,14 @@ static struct ib_ucq_object *create_cq(struct ib_uverbs_file *file, if (cmd_sz > offsetof(typeof(*cmd), flags) + sizeof(cmd->flags)) attr.flags = cmd->flags; - cq = file->device->ib_dev->create_cq(file->device->ib_dev, &attr, + cq = ib_dev->create_cq(ib_dev, &attr, file->ucontext, uhw); if (IS_ERR(cq)) { ret = PTR_ERR(cq); goto err_file; } - cq->device = file->device->ib_dev; + cq->device = ib_dev; cq->uobject = &obj->uobject; cq->comp_handler = ib_uverbs_comp_handler; cq->event_handler = ib_uverbs_cq_event_handler; @@ -1449,6 +1461,7 @@ static int ib_uverbs_create_cq_cb(struct ib_uverbs_file *file, } ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1477,7 +1490,7 @@ ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file, cmd_ex.comp_vector = cmd.comp_vector; cmd_ex.comp_channel = cmd.comp_channel; - obj = create_cq(file, &ucore, &uhw, &cmd_ex, + obj = create_cq(file, ib_dev, &ucore, &uhw, &cmd_ex, offsetof(typeof(cmd_ex), comp_channel) + sizeof(cmd.comp_channel), ib_uverbs_create_cq_cb, NULL); @@ -1500,6 +1513,7 @@ static int ib_uverbs_ex_create_cq_cb(struct ib_uverbs_file *file, } int ib_uverbs_ex_create_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_udata *ucore, struct ib_udata *uhw) { @@ -1525,7 +1539,7 @@ int ib_uverbs_ex_create_cq(struct ib_uverbs_file *file, sizeof(resp.response_length))) return -ENOSPC; - obj = create_cq(file, ucore, uhw, &cmd, + obj = create_cq(file, ib_dev, ucore, uhw, &cmd, min(ucore->inlen, sizeof(cmd)), ib_uverbs_ex_create_cq_cb, NULL); @@ -1536,6 +1550,7 @@ int ib_uverbs_ex_create_cq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_resize_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1599,6 +1614,7 @@ static int copy_wc_to_user(void __user *dest, struct ib_wc *wc) } ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1650,6 +1666,7 @@ out_put: } ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1672,6 +1689,7 @@ ssize_t ib_uverbs_req_notify_cq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1724,6 +1742,7 @@ ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -1919,6 +1938,7 @@ err_put: } ssize_t ib_uverbs_open_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { struct ib_uverbs_open_qp cmd; @@ -2013,6 +2033,7 @@ err_put: } ssize_t ib_uverbs_query_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2127,6 +2148,7 @@ static int modify_qp_mask(enum ib_qp_type qp_type, int mask) } ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2223,6 +2245,7 @@ out: } ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2281,6 +2304,7 @@ ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, } ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2525,6 +2549,7 @@ err: } ssize_t ib_uverbs_post_recv(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2574,6 +2599,7 @@ out: } ssize_t ib_uverbs_post_srq_recv(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2623,6 +2649,7 @@ out: } ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2715,6 +2742,7 @@ err: } ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { struct ib_uverbs_destroy_ah cmd; @@ -2751,6 +2779,7 @@ ssize_t ib_uverbs_destroy_ah(struct ib_uverbs_file *file, } ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2798,6 +2827,7 @@ out_put: } ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -2878,6 +2908,7 @@ static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, } int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_udata *ucore, struct ib_udata *uhw) { @@ -3038,6 +3069,7 @@ err_free_attr: } int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_udata *ucore, struct ib_udata *uhw) { @@ -3080,6 +3112,7 @@ int ib_uverbs_ex_destroy_flow(struct ib_uverbs_file *file, } static int __uverbs_create_xsrq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_uverbs_create_xsrq *cmd, struct ib_udata *udata) { @@ -3213,6 +3246,7 @@ err: } ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -3240,7 +3274,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - ret = __uverbs_create_xsrq(file, &xcmd, &udata); + ret = __uverbs_create_xsrq(file, ib_dev, &xcmd, &udata); if (ret) return ret; @@ -3248,6 +3282,7 @@ ssize_t ib_uverbs_create_srq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { struct ib_uverbs_create_xsrq cmd; @@ -3265,7 +3300,7 @@ ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file, (unsigned long) cmd.response + sizeof resp, in_len - sizeof cmd, out_len - sizeof resp); - ret = __uverbs_create_xsrq(file, &cmd, &udata); + ret = __uverbs_create_xsrq(file, ib_dev, &cmd, &udata); if (ret) return ret; @@ -3273,6 +3308,7 @@ ssize_t ib_uverbs_create_xsrq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -3303,6 +3339,7 @@ ssize_t ib_uverbs_modify_srq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -3343,6 +3380,7 @@ ssize_t ib_uverbs_query_srq(struct ib_uverbs_file *file, } ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) { @@ -3400,16 +3438,15 @@ ssize_t ib_uverbs_destroy_srq(struct ib_uverbs_file *file, } int ib_uverbs_ex_query_device(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_udata *ucore, struct ib_udata *uhw) { struct ib_uverbs_ex_query_device_resp resp; struct ib_uverbs_ex_query_device cmd; struct ib_device_attr attr; - struct ib_device *device; int err; - device = file->device->ib_dev; if (ucore->inlen < sizeof(cmd)) return -EINVAL; @@ -3430,11 +3467,11 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file, memset(&attr, 0, sizeof(attr)); - err = device->query_device(device, &attr, uhw); + err = ib_dev->query_device(ib_dev, &attr, uhw); if (err) return err; - copy_query_dev_fields(file, &resp.base, &attr); + copy_query_dev_fields(file, ib_dev, &resp.base, &attr); resp.comp_mask = 0; if (ucore->outlen < resp.response_length + sizeof(resp.odp_caps)) diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index e05bbb213d2cd..082d9c75bf895 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -79,6 +79,7 @@ static DEFINE_SPINLOCK(map_lock); static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES); static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, + struct ib_device *ib_dev, const char __user *buf, int in_len, int out_len) = { [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context, @@ -119,6 +120,7 @@ static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file, }; static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, + struct ib_device *ib_dev, struct ib_udata *ucore, struct ib_udata *uhw) = { [IB_USER_VERBS_EX_CMD_CREATE_FLOW] = ib_uverbs_ex_create_flow, @@ -557,6 +559,7 @@ void ib_uverbs_free_async_event_file(struct ib_uverbs_file *file) } struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, + struct ib_device *ib_dev, int is_async) { struct ib_uverbs_event_file *ev_file; @@ -586,7 +589,7 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, uverbs_file->async_file = ev_file; kref_get(&uverbs_file->async_file->ref); INIT_IB_EVENT_HANDLER(&uverbs_file->event_handler, - uverbs_file->device->ib_dev, + ib_dev, ib_uverbs_event_handler); ret = ib_register_event_handler(&uverbs_file->event_handler); if (ret) @@ -643,9 +646,13 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_file *file = filp->private_data; + struct ib_device *ib_dev = file->device->ib_dev; struct ib_uverbs_cmd_hdr hdr; __u32 flags; + if (!ib_dev) + return -ENODEV; + if (count < sizeof hdr) return -EINVAL; @@ -672,13 +679,13 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, command != IB_USER_VERBS_CMD_GET_CONTEXT) return -EINVAL; - if (!(file->device->ib_dev->uverbs_cmd_mask & (1ull << command))) + if (!(ib_dev->uverbs_cmd_mask & (1ull << command))) return -ENOSYS; if (hdr.in_words * 4 != count) return -EINVAL; - return uverbs_cmd_table[command](file, + return uverbs_cmd_table[command](file, ib_dev, buf + sizeof(hdr), hdr.in_words * 4, hdr.out_words * 4); @@ -705,7 +712,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (!file->ucontext) return -EINVAL; - if (!(file->device->ib_dev->uverbs_ex_cmd_mask & (1ull << command))) + if (!(ib_dev->uverbs_ex_cmd_mask & (1ull << command))) return -ENOSYS; if (count < (sizeof(hdr) + sizeof(ex_hdr))) @@ -746,6 +753,7 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, ex_hdr.provider_out_words * 8); err = uverbs_ex_cmd_table[command](file, + ib_dev, &ucore, &uhw); @@ -761,11 +769,12 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) { struct ib_uverbs_file *file = filp->private_data; + struct ib_device *ib_dev = file->device->ib_dev; - if (!file->ucontext) + if (!ib_dev || !file->ucontext) return -ENODEV; else - return file->device->ib_dev->mmap(file->ucontext, vma); + return ib_dev->mmap(file->ucontext, vma); } /* -- GitLab From 036b10635739ffd030246eedde3d67f724800177 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 13 Aug 2015 18:32:05 +0300 Subject: [PATCH 5848/7006] IB/uverbs: Enable device removal when there are active user space applications Enables the uverbs_remove_one to succeed despite the fact that there are running IB applications working with the given ib device. This functionality enables a HW device to be unbind/reset despite the fact that there are running user space applications using it. It exposes a new IB kernel API named 'disassociate_ucontext' which lets a driver detaching its HW resources from a given user context without crashing/terminating the application. In case a driver implemented the above API and registered with ib_uverb there will be no dependency between its device to its uverbs_device. Upon calling remove_one of ib_uverbs the call should return after disassociating the open HW resources without waiting to clients disconnecting. In case driver didn't implement this API there will be no change to current behaviour and uverbs_remove_one will return only when last client has disconnected and reference count on uverbs device became 0. In case the lower driver device was removed any application will continue working over some zombie HCA, further calls will ended with an immediate error. Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs.h | 9 +- drivers/infiniband/core/uverbs_main.c | 360 +++++++++++++++++++++----- include/rdma/ib_verbs.h | 1 + 3 files changed, 302 insertions(+), 68 deletions(-) diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index ea52db1962117..3863d33c243d8 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -89,12 +89,16 @@ struct ib_uverbs_device { int num_comp_vectors; struct completion comp; struct device *dev; - struct ib_device *ib_dev; + struct ib_device __rcu *ib_dev; int devnum; struct cdev cdev; struct rb_root xrcd_tree; struct mutex xrcd_tree_mutex; struct kobject kobj; + struct srcu_struct disassociate_srcu; + struct mutex lists_mutex; /* protect lists */ + struct list_head uverbs_file_list; + struct list_head uverbs_events_file_list; }; struct ib_uverbs_event_file { @@ -106,6 +110,7 @@ struct ib_uverbs_event_file { wait_queue_head_t poll_wait; struct fasync_struct *async_queue; struct list_head event_list; + struct list_head list; }; struct ib_uverbs_file { @@ -115,6 +120,8 @@ struct ib_uverbs_file { struct ib_ucontext *ucontext; struct ib_event_handler event_handler; struct ib_uverbs_event_file *async_file; + struct list_head list; + int is_closed; }; struct ib_uverbs_event { diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 082d9c75bf895..c29a660c72fe3 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -137,6 +137,7 @@ static void ib_uverbs_release_dev(struct kobject *kobj) struct ib_uverbs_device *dev = container_of(kobj, struct ib_uverbs_device, kobj); + cleanup_srcu_struct(&dev->disassociate_srcu); kfree(dev); } @@ -207,9 +208,6 @@ static int ib_uverbs_cleanup_ucontext(struct ib_uverbs_file *file, { struct ib_uobject *uobj, *tmp; - if (!context) - return 0; - context->closing = 1; list_for_each_entry_safe(uobj, tmp, &context->ah_list, list) { @@ -318,8 +316,16 @@ static void ib_uverbs_release_file(struct kref *ref) { struct ib_uverbs_file *file = container_of(ref, struct ib_uverbs_file, ref); + struct ib_device *ib_dev; + int srcu_key; + + srcu_key = srcu_read_lock(&file->device->disassociate_srcu); + ib_dev = srcu_dereference(file->device->ib_dev, + &file->device->disassociate_srcu); + if (ib_dev && !ib_dev->disassociate_ucontext) + module_put(ib_dev->owner); + srcu_read_unlock(&file->device->disassociate_srcu, srcu_key); - module_put(file->device->ib_dev->owner); if (atomic_dec_and_test(&file->device->refcount)) ib_uverbs_comp_dev(file->device); @@ -343,9 +349,19 @@ static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf, return -EAGAIN; if (wait_event_interruptible(file->poll_wait, - !list_empty(&file->event_list))) + (!list_empty(&file->event_list) || + /* The barriers built into wait_event_interruptible() + * and wake_up() guarentee this will see the null set + * without using RCU + */ + !file->uverbs_file->device->ib_dev))) return -ERESTARTSYS; + /* If device was disassociated and no event exists set an error */ + if (list_empty(&file->event_list) && + !file->uverbs_file->device->ib_dev) + return -EIO; + spin_lock_irq(&file->lock); } @@ -408,8 +424,11 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp) { struct ib_uverbs_event_file *file = filp->private_data; struct ib_uverbs_event *entry, *tmp; + int closed_already = 0; + mutex_lock(&file->uverbs_file->device->lists_mutex); spin_lock_irq(&file->lock); + closed_already = file->is_closed; file->is_closed = 1; list_for_each_entry_safe(entry, tmp, &file->event_list, list) { if (entry->counter) @@ -417,9 +436,14 @@ static int ib_uverbs_event_close(struct inode *inode, struct file *filp) kfree(entry); } spin_unlock_irq(&file->lock); + if (!closed_already) { + list_del(&file->list); + if (file->is_async) + ib_unregister_event_handler(&file->uverbs_file-> + event_handler); + } + mutex_unlock(&file->uverbs_file->device->lists_mutex); - if (file->is_async) - ib_unregister_event_handler(&file->uverbs_file->event_handler); kref_put(&file->uverbs_file->ref, ib_uverbs_release_file); kref_put(&file->ref, ib_uverbs_release_event_file); @@ -584,6 +608,11 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, if (IS_ERR(filp)) goto err_put_refs; + mutex_lock(&uverbs_file->device->lists_mutex); + list_add_tail(&ev_file->list, + &uverbs_file->device->uverbs_events_file_list); + mutex_unlock(&uverbs_file->device->lists_mutex); + if (is_async) { WARN_ON(uverbs_file->async_file); uverbs_file->async_file = ev_file; @@ -646,12 +675,11 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, size_t count, loff_t *pos) { struct ib_uverbs_file *file = filp->private_data; - struct ib_device *ib_dev = file->device->ib_dev; + struct ib_device *ib_dev; struct ib_uverbs_cmd_hdr hdr; __u32 flags; - - if (!ib_dev) - return -ENODEV; + int srcu_key; + ssize_t ret; if (count < sizeof hdr) return -EINVAL; @@ -659,6 +687,14 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, if (copy_from_user(&hdr, buf, sizeof hdr)) return -EFAULT; + srcu_key = srcu_read_lock(&file->device->disassociate_srcu); + ib_dev = srcu_dereference(file->device->ib_dev, + &file->device->disassociate_srcu); + if (!ib_dev) { + ret = -EIO; + goto out; + } + flags = (hdr.command & IB_USER_VERBS_CMD_FLAGS_MASK) >> IB_USER_VERBS_CMD_FLAGS_SHIFT; @@ -666,26 +702,36 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, __u32 command; if (hdr.command & ~(__u32)(IB_USER_VERBS_CMD_FLAGS_MASK | - IB_USER_VERBS_CMD_COMMAND_MASK)) - return -EINVAL; + IB_USER_VERBS_CMD_COMMAND_MASK)) { + ret = -EINVAL; + goto out; + } command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; if (command >= ARRAY_SIZE(uverbs_cmd_table) || - !uverbs_cmd_table[command]) - return -EINVAL; + !uverbs_cmd_table[command]) { + ret = -EINVAL; + goto out; + } if (!file->ucontext && - command != IB_USER_VERBS_CMD_GET_CONTEXT) - return -EINVAL; + command != IB_USER_VERBS_CMD_GET_CONTEXT) { + ret = -EINVAL; + goto out; + } - if (!(ib_dev->uverbs_cmd_mask & (1ull << command))) - return -ENOSYS; + if (!(ib_dev->uverbs_cmd_mask & (1ull << command))) { + ret = -ENOSYS; + goto out; + } - if (hdr.in_words * 4 != count) - return -EINVAL; + if (hdr.in_words * 4 != count) { + ret = -EINVAL; + goto out; + } - return uverbs_cmd_table[command](file, ib_dev, + ret = uverbs_cmd_table[command](file, ib_dev, buf + sizeof(hdr), hdr.in_words * 4, hdr.out_words * 4); @@ -696,51 +742,72 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, struct ib_uverbs_ex_cmd_hdr ex_hdr; struct ib_udata ucore; struct ib_udata uhw; - int err; size_t written_count = count; if (hdr.command & ~(__u32)(IB_USER_VERBS_CMD_FLAGS_MASK | - IB_USER_VERBS_CMD_COMMAND_MASK)) - return -EINVAL; + IB_USER_VERBS_CMD_COMMAND_MASK)) { + ret = -EINVAL; + goto out; + } command = hdr.command & IB_USER_VERBS_CMD_COMMAND_MASK; if (command >= ARRAY_SIZE(uverbs_ex_cmd_table) || - !uverbs_ex_cmd_table[command]) - return -ENOSYS; + !uverbs_ex_cmd_table[command]) { + ret = -ENOSYS; + goto out; + } - if (!file->ucontext) - return -EINVAL; + if (!file->ucontext) { + ret = -EINVAL; + goto out; + } - if (!(ib_dev->uverbs_ex_cmd_mask & (1ull << command))) - return -ENOSYS; + if (!(ib_dev->uverbs_ex_cmd_mask & (1ull << command))) { + ret = -ENOSYS; + goto out; + } - if (count < (sizeof(hdr) + sizeof(ex_hdr))) - return -EINVAL; + if (count < (sizeof(hdr) + sizeof(ex_hdr))) { + ret = -EINVAL; + goto out; + } - if (copy_from_user(&ex_hdr, buf + sizeof(hdr), sizeof(ex_hdr))) - return -EFAULT; + if (copy_from_user(&ex_hdr, buf + sizeof(hdr), sizeof(ex_hdr))) { + ret = -EFAULT; + goto out; + } count -= sizeof(hdr) + sizeof(ex_hdr); buf += sizeof(hdr) + sizeof(ex_hdr); - if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count) - return -EINVAL; + if ((hdr.in_words + ex_hdr.provider_in_words) * 8 != count) { + ret = -EINVAL; + goto out; + } - if (ex_hdr.cmd_hdr_reserved) - return -EINVAL; + if (ex_hdr.cmd_hdr_reserved) { + ret = -EINVAL; + goto out; + } if (ex_hdr.response) { - if (!hdr.out_words && !ex_hdr.provider_out_words) - return -EINVAL; + if (!hdr.out_words && !ex_hdr.provider_out_words) { + ret = -EINVAL; + goto out; + } if (!access_ok(VERIFY_WRITE, (void __user *) (unsigned long) ex_hdr.response, - (hdr.out_words + ex_hdr.provider_out_words) * 8)) - return -EFAULT; + (hdr.out_words + ex_hdr.provider_out_words) * 8)) { + ret = -EFAULT; + goto out; + } } else { - if (hdr.out_words || ex_hdr.provider_out_words) - return -EINVAL; + if (hdr.out_words || ex_hdr.provider_out_words) { + ret = -EINVAL; + goto out; + } } INIT_UDATA_BUF_OR_NULL(&ucore, buf, (unsigned long) ex_hdr.response, @@ -752,29 +819,43 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, ex_hdr.provider_in_words * 8, ex_hdr.provider_out_words * 8); - err = uverbs_ex_cmd_table[command](file, + ret = uverbs_ex_cmd_table[command](file, ib_dev, &ucore, &uhw); - - if (err) - return err; - - return written_count; + if (!ret) + ret = written_count; + } else { + ret = -ENOSYS; } - return -ENOSYS; +out: + srcu_read_unlock(&file->device->disassociate_srcu, srcu_key); + return ret; } static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma) { struct ib_uverbs_file *file = filp->private_data; - struct ib_device *ib_dev = file->device->ib_dev; + struct ib_device *ib_dev; + int ret = 0; + int srcu_key; - if (!ib_dev || !file->ucontext) - return -ENODEV; + srcu_key = srcu_read_lock(&file->device->disassociate_srcu); + ib_dev = srcu_dereference(file->device->ib_dev, + &file->device->disassociate_srcu); + if (!ib_dev) { + ret = -EIO; + goto out; + } + + if (!file->ucontext) + ret = -ENODEV; else - return ib_dev->mmap(file->ucontext, vma); + ret = ib_dev->mmap(file->ucontext, vma); +out: + srcu_read_unlock(&file->device->disassociate_srcu, srcu_key); + return ret; } /* @@ -791,21 +872,43 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) { struct ib_uverbs_device *dev; struct ib_uverbs_file *file; + struct ib_device *ib_dev; int ret; + int module_dependent; + int srcu_key; dev = container_of(inode->i_cdev, struct ib_uverbs_device, cdev); if (!atomic_inc_not_zero(&dev->refcount)) return -ENXIO; - if (!try_module_get(dev->ib_dev->owner)) { - ret = -ENODEV; + srcu_key = srcu_read_lock(&dev->disassociate_srcu); + mutex_lock(&dev->lists_mutex); + ib_dev = srcu_dereference(dev->ib_dev, + &dev->disassociate_srcu); + if (!ib_dev) { + ret = -EIO; goto err; } - file = kmalloc(sizeof *file, GFP_KERNEL); + /* In case IB device supports disassociate ucontext, there is no hard + * dependency between uverbs device and its low level device. + */ + module_dependent = !(ib_dev->disassociate_ucontext); + + if (module_dependent) { + if (!try_module_get(ib_dev->owner)) { + ret = -ENODEV; + goto err; + } + } + + file = kzalloc(sizeof(*file), GFP_KERNEL); if (!file) { ret = -ENOMEM; - goto err_module; + if (module_dependent) + goto err_module; + + goto err; } file->device = dev; @@ -816,13 +919,18 @@ static int ib_uverbs_open(struct inode *inode, struct file *filp) filp->private_data = file; kobject_get(&dev->kobj); + list_add_tail(&file->list, &dev->uverbs_file_list); + mutex_unlock(&dev->lists_mutex); + srcu_read_unlock(&dev->disassociate_srcu, srcu_key); return nonseekable_open(inode, filp); err_module: - module_put(dev->ib_dev->owner); + module_put(ib_dev->owner); err: + mutex_unlock(&dev->lists_mutex); + srcu_read_unlock(&dev->disassociate_srcu, srcu_key); if (atomic_dec_and_test(&dev->refcount)) ib_uverbs_comp_dev(dev); @@ -833,8 +941,18 @@ static int ib_uverbs_close(struct inode *inode, struct file *filp) { struct ib_uverbs_file *file = filp->private_data; struct ib_uverbs_device *dev = file->device; - - ib_uverbs_cleanup_ucontext(file, file->ucontext); + struct ib_ucontext *ucontext = NULL; + + mutex_lock(&file->device->lists_mutex); + ucontext = file->ucontext; + file->ucontext = NULL; + if (!file->is_closed) { + list_del(&file->list); + file->is_closed = 1; + } + mutex_unlock(&file->device->lists_mutex); + if (ucontext) + ib_uverbs_cleanup_ucontext(file, ucontext); if (file->async_file) kref_put(&file->async_file->ref, ib_uverbs_release_event_file); @@ -871,12 +989,21 @@ static struct ib_client uverbs_client = { static ssize_t show_ibdev(struct device *device, struct device_attribute *attr, char *buf) { + int ret = -ENODEV; + int srcu_key; struct ib_uverbs_device *dev = dev_get_drvdata(device); + struct ib_device *ib_dev; if (!dev) return -ENODEV; - return sprintf(buf, "%s\n", dev->ib_dev->name); + srcu_key = srcu_read_lock(&dev->disassociate_srcu); + ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu); + if (ib_dev) + ret = sprintf(buf, "%s\n", ib_dev->name); + srcu_read_unlock(&dev->disassociate_srcu, srcu_key); + + return ret; } static DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL); @@ -884,11 +1011,19 @@ static ssize_t show_dev_abi_version(struct device *device, struct device_attribute *attr, char *buf) { struct ib_uverbs_device *dev = dev_get_drvdata(device); + int ret = -ENODEV; + int srcu_key; + struct ib_device *ib_dev; if (!dev) return -ENODEV; + srcu_key = srcu_read_lock(&dev->disassociate_srcu); + ib_dev = srcu_dereference(dev->ib_dev, &dev->disassociate_srcu); + if (ib_dev) + ret = sprintf(buf, "%d\n", ib_dev->uverbs_abi_ver); + srcu_read_unlock(&dev->disassociate_srcu, srcu_key); - return sprintf(buf, "%d\n", dev->ib_dev->uverbs_abi_ver); + return ret; } static DEVICE_ATTR(abi_version, S_IRUGO, show_dev_abi_version, NULL); @@ -928,6 +1063,7 @@ static void ib_uverbs_add_one(struct ib_device *device) int devnum; dev_t base; struct ib_uverbs_device *uverbs_dev; + int ret; if (!device->alloc_ucontext) return; @@ -936,11 +1072,20 @@ static void ib_uverbs_add_one(struct ib_device *device) if (!uverbs_dev) return; + ret = init_srcu_struct(&uverbs_dev->disassociate_srcu); + if (ret) { + kfree(uverbs_dev); + return; + } + atomic_set(&uverbs_dev->refcount, 1); init_completion(&uverbs_dev->comp); uverbs_dev->xrcd_tree = RB_ROOT; mutex_init(&uverbs_dev->xrcd_tree_mutex); kobject_init(&uverbs_dev->kobj, &ib_uverbs_dev_ktype); + mutex_init(&uverbs_dev->lists_mutex); + INIT_LIST_HEAD(&uverbs_dev->uverbs_file_list); + INIT_LIST_HEAD(&uverbs_dev->uverbs_events_file_list); spin_lock(&map_lock); devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES); @@ -961,7 +1106,7 @@ static void ib_uverbs_add_one(struct ib_device *device) } spin_unlock(&map_lock); - uverbs_dev->ib_dev = device; + rcu_assign_pointer(uverbs_dev->ib_dev, device); uverbs_dev->num_comp_vectors = device->num_comp_vectors; cdev_init(&uverbs_dev->cdev, NULL); @@ -1005,9 +1150,72 @@ err: return; } +static void ib_uverbs_free_hw_resources(struct ib_uverbs_device *uverbs_dev, + struct ib_device *ib_dev) +{ + struct ib_uverbs_file *file; + struct ib_uverbs_event_file *event_file; + struct ib_event event; + + /* Pending running commands to terminate */ + synchronize_srcu(&uverbs_dev->disassociate_srcu); + event.event = IB_EVENT_DEVICE_FATAL; + event.element.port_num = 0; + event.device = ib_dev; + + mutex_lock(&uverbs_dev->lists_mutex); + while (!list_empty(&uverbs_dev->uverbs_file_list)) { + struct ib_ucontext *ucontext; + + file = list_first_entry(&uverbs_dev->uverbs_file_list, + struct ib_uverbs_file, list); + file->is_closed = 1; + ucontext = file->ucontext; + list_del(&file->list); + file->ucontext = NULL; + kref_get(&file->ref); + mutex_unlock(&uverbs_dev->lists_mutex); + /* We must release the mutex before going ahead and calling + * disassociate_ucontext. disassociate_ucontext might end up + * indirectly calling uverbs_close, for example due to freeing + * the resources (e.g mmput). + */ + ib_uverbs_event_handler(&file->event_handler, &event); + if (ucontext) { + ib_dev->disassociate_ucontext(ucontext); + ib_uverbs_cleanup_ucontext(file, ucontext); + } + + mutex_lock(&uverbs_dev->lists_mutex); + kref_put(&file->ref, ib_uverbs_release_file); + } + + while (!list_empty(&uverbs_dev->uverbs_events_file_list)) { + event_file = list_first_entry(&uverbs_dev-> + uverbs_events_file_list, + struct ib_uverbs_event_file, + list); + spin_lock_irq(&event_file->lock); + event_file->is_closed = 1; + spin_unlock_irq(&event_file->lock); + + list_del(&event_file->list); + if (event_file->is_async) { + ib_unregister_event_handler(&event_file->uverbs_file-> + event_handler); + event_file->uverbs_file->event_handler.device = NULL; + } + + wake_up_interruptible(&event_file->poll_wait); + kill_fasync(&event_file->async_queue, SIGIO, POLL_IN); + } + mutex_unlock(&uverbs_dev->lists_mutex); +} + static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) { struct ib_uverbs_device *uverbs_dev = client_data; + int wait_clients = 1; if (!uverbs_dev) return; @@ -1021,9 +1229,27 @@ static void ib_uverbs_remove_one(struct ib_device *device, void *client_data) else clear_bit(uverbs_dev->devnum - IB_UVERBS_MAX_DEVICES, overflow_map); + if (device->disassociate_ucontext) { + /* We disassociate HW resources and immediately return. + * Userspace will see a EIO errno for all future access. + * Upon returning, ib_device may be freed internally and is not + * valid any more. + * uverbs_device is still available until all clients close + * their files, then the uverbs device ref count will be zero + * and its resources will be freed. + * Note: At this point no more files can be opened since the + * cdev was deleted, however active clients can still issue + * commands and close their open files. + */ + rcu_assign_pointer(uverbs_dev->ib_dev, NULL); + ib_uverbs_free_hw_resources(uverbs_dev, device); + wait_clients = 0; + } + if (atomic_dec_and_test(&uverbs_dev->refcount)) ib_uverbs_comp_dev(uverbs_dev); - wait_for_completion(&uverbs_dev->comp); + if (wait_clients) + wait_for_completion(&uverbs_dev->comp); kobject_put(&uverbs_dev->kobj); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 128abf2888ab7..40b83f412d24e 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1769,6 +1769,7 @@ struct ib_device { int (*destroy_flow)(struct ib_flow *flow_id); int (*check_mr_status)(struct ib_mr *mr, u32 check_mask, struct ib_mr_status *mr_status); + void (*disassociate_ucontext)(struct ib_ucontext *ibcontext); struct ib_dma_mapping_ops *dma_ops; -- GitLab From ae184ddeca5db6d60ba9067ba1c9e940fa01d400 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 13 Aug 2015 18:32:06 +0300 Subject: [PATCH 5849/7006] IB/mlx4_ib: Disassociate support Implements the IB core disassociate_ucontext API. The driver detaches the HW resources for a given user context to prevent a dependency between application termination and device disconnecting. This is done by managing the VMAs that were mapped to the HW bars such as door bell and blueflame. When need to detach remap them to an arbitrary kernel page returned by the zap API. Signed-off-by: Yishai Hadas Signed-off-by: Jack Morgenstein Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 139 ++++++++++++++++++++++++++- drivers/infiniband/hw/mlx4/mlx4_ib.h | 13 +++ 2 files changed, 150 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 1437ed5d5a8f8..efecdf0216d85 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -921,7 +921,7 @@ static struct ib_ucontext *mlx4_ib_alloc_ucontext(struct ib_device *ibdev, resp.cqe_size = dev->dev->caps.cqe_size; } - context = kmalloc(sizeof *context, GFP_KERNEL); + context = kzalloc(sizeof(*context), GFP_KERNEL); if (!context) return ERR_PTR(-ENOMEM); @@ -958,21 +958,143 @@ static int mlx4_ib_dealloc_ucontext(struct ib_ucontext *ibcontext) return 0; } +static void mlx4_ib_vma_open(struct vm_area_struct *area) +{ + /* vma_open is called when a new VMA is created on top of our VMA. + * This is done through either mremap flow or split_vma (usually due + * to mlock, madvise, munmap, etc.). We do not support a clone of the + * vma, as this VMA is strongly hardware related. Therefore we set the + * vm_ops of the newly created/cloned VMA to NULL, to prevent it from + * calling us again and trying to do incorrect actions. We assume that + * the original vma size is exactly a single page that there will be no + * "splitting" operations on. + */ + area->vm_ops = NULL; +} + +static void mlx4_ib_vma_close(struct vm_area_struct *area) +{ + struct mlx4_ib_vma_private_data *mlx4_ib_vma_priv_data; + + /* It's guaranteed that all VMAs opened on a FD are closed before the + * file itself is closed, therefore no sync is needed with the regular + * closing flow. (e.g. mlx4_ib_dealloc_ucontext) However need a sync + * with accessing the vma as part of mlx4_ib_disassociate_ucontext. + * The close operation is usually called under mm->mmap_sem except when + * process is exiting. The exiting case is handled explicitly as part + * of mlx4_ib_disassociate_ucontext. + */ + mlx4_ib_vma_priv_data = (struct mlx4_ib_vma_private_data *) + area->vm_private_data; + + /* set the vma context pointer to null in the mlx4_ib driver's private + * data to protect against a race condition in mlx4_ib_dissassociate_ucontext(). + */ + mlx4_ib_vma_priv_data->vma = NULL; +} + +static const struct vm_operations_struct mlx4_ib_vm_ops = { + .open = mlx4_ib_vma_open, + .close = mlx4_ib_vma_close +}; + +static void mlx4_ib_disassociate_ucontext(struct ib_ucontext *ibcontext) +{ + int i; + int ret = 0; + struct vm_area_struct *vma; + struct mlx4_ib_ucontext *context = to_mucontext(ibcontext); + struct task_struct *owning_process = NULL; + struct mm_struct *owning_mm = NULL; + + owning_process = get_pid_task(ibcontext->tgid, PIDTYPE_PID); + if (!owning_process) + return; + + owning_mm = get_task_mm(owning_process); + if (!owning_mm) { + pr_info("no mm, disassociate ucontext is pending task termination\n"); + while (1) { + /* make sure that task is dead before returning, it may + * prevent a rare case of module down in parallel to a + * call to mlx4_ib_vma_close. + */ + put_task_struct(owning_process); + msleep(1); + owning_process = get_pid_task(ibcontext->tgid, + PIDTYPE_PID); + if (!owning_process || + owning_process->state == TASK_DEAD) { + pr_info("disassociate ucontext done, task was terminated\n"); + /* in case task was dead need to release the task struct */ + if (owning_process) + put_task_struct(owning_process); + return; + } + } + } + + /* need to protect from a race on closing the vma as part of + * mlx4_ib_vma_close(). + */ + down_read(&owning_mm->mmap_sem); + for (i = 0; i < HW_BAR_COUNT; i++) { + vma = context->hw_bar_info[i].vma; + if (!vma) + continue; + + ret = zap_vma_ptes(context->hw_bar_info[i].vma, + context->hw_bar_info[i].vma->vm_start, + PAGE_SIZE); + if (ret) { + pr_err("Error: zap_vma_ptes failed for index=%d, ret=%d\n", i, ret); + BUG_ON(1); + } + + /* context going to be destroyed, should not access ops any more */ + context->hw_bar_info[i].vma->vm_ops = NULL; + } + + up_read(&owning_mm->mmap_sem); + mmput(owning_mm); + put_task_struct(owning_process); +} + +static void mlx4_ib_set_vma_data(struct vm_area_struct *vma, + struct mlx4_ib_vma_private_data *vma_private_data) +{ + vma_private_data->vma = vma; + vma->vm_private_data = vma_private_data; + vma->vm_ops = &mlx4_ib_vm_ops; +} + static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { struct mlx4_ib_dev *dev = to_mdev(context->device); + struct mlx4_ib_ucontext *mucontext = to_mucontext(context); if (vma->vm_end - vma->vm_start != PAGE_SIZE) return -EINVAL; if (vma->vm_pgoff == 0) { + /* We prevent double mmaping on same context */ + if (mucontext->hw_bar_info[HW_BAR_DB].vma) + return -EINVAL; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); if (io_remap_pfn_range(vma, vma->vm_start, to_mucontext(context)->uar.pfn, PAGE_SIZE, vma->vm_page_prot)) return -EAGAIN; + + mlx4_ib_set_vma_data(vma, &mucontext->hw_bar_info[HW_BAR_DB]); + } else if (vma->vm_pgoff == 1 && dev->dev->caps.bf_reg_size != 0) { + /* We prevent double mmaping on same context */ + if (mucontext->hw_bar_info[HW_BAR_BF].vma) + return -EINVAL; + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); if (io_remap_pfn_range(vma, vma->vm_start, @@ -980,9 +1102,18 @@ static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) dev->dev->caps.num_uars, PAGE_SIZE, vma->vm_page_prot)) return -EAGAIN; + + mlx4_ib_set_vma_data(vma, &mucontext->hw_bar_info[HW_BAR_BF]); + } else if (vma->vm_pgoff == 3) { struct mlx4_clock_params params; - int ret = mlx4_get_internal_clock_params(dev->dev, ¶ms); + int ret; + + /* We prevent double mmaping on same context */ + if (mucontext->hw_bar_info[HW_BAR_CLOCK].vma) + return -EINVAL; + + ret = mlx4_get_internal_clock_params(dev->dev, ¶ms); if (ret) return ret; @@ -995,6 +1126,9 @@ static int mlx4_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) >> PAGE_SHIFT, PAGE_SIZE, vma->vm_page_prot)) return -EAGAIN; + + mlx4_ib_set_vma_data(vma, + &mucontext->hw_bar_info[HW_BAR_CLOCK]); } else { return -EINVAL; } @@ -2119,6 +2253,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) ibdev->ib_dev.detach_mcast = mlx4_ib_mcg_detach; ibdev->ib_dev.process_mad = mlx4_ib_process_mad; ibdev->ib_dev.get_port_immutable = mlx4_port_immutable; + ibdev->ib_dev.disassociate_ucontext = mlx4_ib_disassociate_ucontext; if (!mlx4_is_slave(ibdev->dev)) { ibdev->ib_dev.alloc_fmr = mlx4_ib_fmr_alloc; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index fe52ead0ebda0..1e7b23bb2eb0b 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -70,11 +70,24 @@ extern int mlx4_ib_sm_guid_assign; #define MLX4_IB_UC_STEER_QPN_ALIGN 1 #define MLX4_IB_UC_MAX_NUM_QPS 256 + +enum hw_bar_type { + HW_BAR_BF, + HW_BAR_DB, + HW_BAR_CLOCK, + HW_BAR_COUNT +}; + +struct mlx4_ib_vma_private_data { + struct vm_area_struct *vma; +}; + struct mlx4_ib_ucontext { struct ib_ucontext ibucontext; struct mlx4_uar uar; struct list_head db_page_list; struct mutex db_page_mutex; + struct mlx4_ib_vma_private_data hw_bar_info[HW_BAR_COUNT]; }; struct mlx4_ib_pd { -- GitLab From e1c30298ccab87151a0c4241fc5985c591598361 Mon Sep 17 00:00:00 2001 From: Yishai Hadas Date: Thu, 13 Aug 2015 18:32:07 +0300 Subject: [PATCH 5850/7006] IB/ucma: HW Device hot-removal support Currently, IB/cma remove_one flow blocks until all user descriptor managed by IB/ucma are released. This prevents hot-removal of IB devices. This patch allows IB/cma to remove devices regardless of user space activity. Upon getting the RDMA_CM_EVENT_DEVICE_REMOVAL event we close all the underlying HW resources for the given ucontext. The ucontext itself is still alive till its explicit destroying by its creator. Running applications at that time will have some zombie device, further operations may fail. Signed-off-by: Yishai Hadas Signed-off-by: Shachar Raindel Reviewed-by: Haggai Eran Signed-off-by: Doug Ledford --- drivers/infiniband/core/ucma.c | 140 ++++++++++++++++++++++++++++++--- 1 file changed, 129 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index acac9eafdbf69..a53fc9b01c699 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -74,6 +74,7 @@ struct ucma_file { struct list_head ctx_list; struct list_head event_list; wait_queue_head_t poll_wait; + struct workqueue_struct *close_wq; }; struct ucma_context { @@ -89,6 +90,13 @@ struct ucma_context { struct list_head list; struct list_head mc_list; + /* mark that device is in process of destroying the internal HW + * resources, protected by the global mut + */ + int closing; + /* sync between removal event and id destroy, protected by file mut */ + int destroying; + struct work_struct close_work; }; struct ucma_multicast { @@ -107,6 +115,7 @@ struct ucma_event { struct list_head list; struct rdma_cm_id *cm_id; struct rdma_ucm_event_resp resp; + struct work_struct close_work; }; static DEFINE_MUTEX(mut); @@ -132,8 +141,12 @@ static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id) mutex_lock(&mut); ctx = _ucma_find_context(id, file); - if (!IS_ERR(ctx)) - atomic_inc(&ctx->ref); + if (!IS_ERR(ctx)) { + if (ctx->closing) + ctx = ERR_PTR(-EIO); + else + atomic_inc(&ctx->ref); + } mutex_unlock(&mut); return ctx; } @@ -144,6 +157,28 @@ static void ucma_put_ctx(struct ucma_context *ctx) complete(&ctx->comp); } +static void ucma_close_event_id(struct work_struct *work) +{ + struct ucma_event *uevent_close = container_of(work, struct ucma_event, close_work); + + rdma_destroy_id(uevent_close->cm_id); + kfree(uevent_close); +} + +static void ucma_close_id(struct work_struct *work) +{ + struct ucma_context *ctx = container_of(work, struct ucma_context, close_work); + + /* once all inflight tasks are finished, we close all underlying + * resources. The context is still alive till its explicit destryoing + * by its creator. + */ + ucma_put_ctx(ctx); + wait_for_completion(&ctx->comp); + /* No new events will be generated after destroying the id. */ + rdma_destroy_id(ctx->cm_id); +} + static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) { struct ucma_context *ctx; @@ -152,6 +187,7 @@ static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) if (!ctx) return NULL; + INIT_WORK(&ctx->close_work, ucma_close_id); atomic_set(&ctx->ref, 1); init_completion(&ctx->comp); INIT_LIST_HEAD(&ctx->mc_list); @@ -242,6 +278,44 @@ static void ucma_set_event_context(struct ucma_context *ctx, } } +/* Called with file->mut locked for the relevant context. */ +static void ucma_removal_event_handler(struct rdma_cm_id *cm_id) +{ + struct ucma_context *ctx = cm_id->context; + struct ucma_event *con_req_eve; + int event_found = 0; + + if (ctx->destroying) + return; + + /* only if context is pointing to cm_id that it owns it and can be + * queued to be closed, otherwise that cm_id is an inflight one that + * is part of that context event list pending to be detached and + * reattached to its new context as part of ucma_get_event, + * handled separately below. + */ + if (ctx->cm_id == cm_id) { + mutex_lock(&mut); + ctx->closing = 1; + mutex_unlock(&mut); + queue_work(ctx->file->close_wq, &ctx->close_work); + return; + } + + list_for_each_entry(con_req_eve, &ctx->file->event_list, list) { + if (con_req_eve->cm_id == cm_id && + con_req_eve->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) { + list_del(&con_req_eve->list); + INIT_WORK(&con_req_eve->close_work, ucma_close_event_id); + queue_work(ctx->file->close_wq, &con_req_eve->close_work); + event_found = 1; + break; + } + } + if (!event_found) + printk(KERN_ERR "ucma_removal_event_handler: warning: connect request event wasn't found\n"); +} + static int ucma_event_handler(struct rdma_cm_id *cm_id, struct rdma_cm_event *event) { @@ -276,14 +350,21 @@ static int ucma_event_handler(struct rdma_cm_id *cm_id, * We ignore events for new connections until userspace has set * their context. This can only happen if an error occurs on a * new connection before the user accepts it. This is okay, - * since the accept will just fail later. + * since the accept will just fail later. However, we do need + * to release the underlying HW resources in case of a device + * removal event. */ + if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) + ucma_removal_event_handler(cm_id); + kfree(uevent); goto out; } list_add_tail(&uevent->list, &ctx->file->event_list); wake_up_interruptible(&ctx->file->poll_wait); + if (event->event == RDMA_CM_EVENT_DEVICE_REMOVAL) + ucma_removal_event_handler(cm_id); out: mutex_unlock(&ctx->file->mut); return ret; @@ -442,9 +523,15 @@ static void ucma_cleanup_mc_events(struct ucma_multicast *mc) } /* - * We cannot hold file->mut when calling rdma_destroy_id() or we can - * deadlock. We also acquire file->mut in ucma_event_handler(), and - * rdma_destroy_id() will wait until all callbacks have completed. + * ucma_free_ctx is called after the underlying rdma CM-ID is destroyed. At + * this point, no new events will be reported from the hardware. However, we + * still need to cleanup the UCMA context for this ID. Specifically, there + * might be events that have not yet been consumed by the user space software. + * These might include pending connect requests which we have not completed + * processing. We cannot call rdma_destroy_id while holding the lock of the + * context (file->mut), as it might cause a deadlock. We therefore extract all + * relevant events from the context pending events list while holding the + * mutex. After that we release them as needed. */ static int ucma_free_ctx(struct ucma_context *ctx) { @@ -452,8 +539,6 @@ static int ucma_free_ctx(struct ucma_context *ctx) struct ucma_event *uevent, *tmp; LIST_HEAD(list); - /* No new events will be generated after destroying the id. */ - rdma_destroy_id(ctx->cm_id); ucma_cleanup_multicast(ctx); @@ -501,10 +586,24 @@ static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf, if (IS_ERR(ctx)) return PTR_ERR(ctx); - ucma_put_ctx(ctx); - wait_for_completion(&ctx->comp); - resp.events_reported = ucma_free_ctx(ctx); + mutex_lock(&ctx->file->mut); + ctx->destroying = 1; + mutex_unlock(&ctx->file->mut); + + flush_workqueue(ctx->file->close_wq); + /* At this point it's guaranteed that there is no inflight + * closing task */ + mutex_lock(&mut); + if (!ctx->closing) { + mutex_unlock(&mut); + ucma_put_ctx(ctx); + wait_for_completion(&ctx->comp); + rdma_destroy_id(ctx->cm_id); + } else { + mutex_unlock(&mut); + } + resp.events_reported = ucma_free_ctx(ctx); if (copy_to_user((void __user *)(unsigned long)cmd.response, &resp, sizeof(resp))) ret = -EFAULT; @@ -1529,6 +1628,7 @@ static int ucma_open(struct inode *inode, struct file *filp) INIT_LIST_HEAD(&file->ctx_list); init_waitqueue_head(&file->poll_wait); mutex_init(&file->mut); + file->close_wq = create_singlethread_workqueue("ucma_close_id"); filp->private_data = file; file->filp = filp; @@ -1543,16 +1643,34 @@ static int ucma_close(struct inode *inode, struct file *filp) mutex_lock(&file->mut); list_for_each_entry_safe(ctx, tmp, &file->ctx_list, list) { + ctx->destroying = 1; mutex_unlock(&file->mut); mutex_lock(&mut); idr_remove(&ctx_idr, ctx->id); mutex_unlock(&mut); + flush_workqueue(file->close_wq); + /* At that step once ctx was marked as destroying and workqueue + * was flushed we are safe from any inflights handlers that + * might put other closing task. + */ + mutex_lock(&mut); + if (!ctx->closing) { + mutex_unlock(&mut); + /* rdma_destroy_id ensures that no event handlers are + * inflight for that id before releasing it. + */ + rdma_destroy_id(ctx->cm_id); + } else { + mutex_unlock(&mut); + } + ucma_free_ctx(ctx); mutex_lock(&file->mut); } mutex_unlock(&file->mut); + destroy_workqueue(file->close_wq); kfree(file); return 0; } -- GitLab From 4a1e2feb9d246775dee0f78ed5b18826bae2b1c5 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sun, 30 Aug 2015 18:37:59 -0700 Subject: [PATCH 5851/7006] NFSv4.1: Fix a protocol issue with CLOSE stateids According to RFC5661 Section 18.2.4, CLOSE is supposed to return the zero stateid. This means that nfs_clear_open_stateid_locked() cannot assume that the result stateid will always match the 'other' field of the existing open stateid when trying to determine a race with a parallel OPEN. Instead, we look at the argument, and check for matches. Cc: stable@vger.kernel.org # v4.0+ Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 2923abf2fc0cd..366b81c185f61 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -1231,6 +1231,7 @@ static void nfs_resync_open_stateid_locked(struct nfs4_state *state) } static void nfs_clear_open_stateid_locked(struct nfs4_state *state, + nfs4_stateid *arg_stateid, nfs4_stateid *stateid, fmode_t fmode) { clear_bit(NFS_O_RDWR_STATE, &state->flags); @@ -1249,8 +1250,9 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state, if (stateid == NULL) return; /* Handle races with OPEN */ - if (!nfs4_stateid_match_other(stateid, &state->open_stateid) || - !nfs4_stateid_is_newer(stateid, &state->open_stateid)) { + if (!nfs4_stateid_match_other(arg_stateid, &state->open_stateid) || + (nfs4_stateid_match_other(stateid, &state->open_stateid) && + !nfs4_stateid_is_newer(stateid, &state->open_stateid))) { nfs_resync_open_stateid_locked(state); return; } @@ -1259,10 +1261,12 @@ static void nfs_clear_open_stateid_locked(struct nfs4_state *state, nfs4_stateid_copy(&state->open_stateid, stateid); } -static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode) +static void nfs_clear_open_stateid(struct nfs4_state *state, + nfs4_stateid *arg_stateid, + nfs4_stateid *stateid, fmode_t fmode) { write_seqlock(&state->seqlock); - nfs_clear_open_stateid_locked(state, stateid, fmode); + nfs_clear_open_stateid_locked(state, arg_stateid, stateid, fmode); write_sequnlock(&state->seqlock); if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) nfs4_schedule_state_manager(state->owner->so_server->nfs_client); @@ -2707,7 +2711,8 @@ static void nfs4_close_done(struct rpc_task *task, void *data) goto out_release; } } - nfs_clear_open_stateid(state, res_stateid, calldata->arg.fmode); + nfs_clear_open_stateid(state, &calldata->arg.stateid, + res_stateid, calldata->arg.fmode); out_release: nfs_release_seqid(calldata->arg.seqid); nfs_refresh_inode(calldata->inode, calldata->res.fattr); -- GitLab From c4c6bc314618f60ba69b0cbf93e506e4c38a11d2 Mon Sep 17 00:00:00 2001 From: Raghavendra K T Date: Sun, 30 Aug 2015 11:29:41 +0530 Subject: [PATCH 5852/7006] net: Introduce helper functions to get the per cpu data Signed-off-by: Raghavendra K T Signed-off-by: David S. Miller --- include/net/ip.h | 10 ++++++++++ net/ipv4/af_inet.c | 41 +++++++++++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 14 deletions(-) diff --git a/include/net/ip.h b/include/net/ip.h index 7b9e1c782aa34..9b9ca28393996 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -202,10 +202,20 @@ void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, #define NET_ADD_STATS_BH(net, field, adnd) SNMP_ADD_STATS_BH((net)->mib.net_statistics, field, adnd) #define NET_ADD_STATS_USER(net, field, adnd) SNMP_ADD_STATS_USER((net)->mib.net_statistics, field, adnd) +u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offct); unsigned long snmp_fold_field(void __percpu *mib, int offt); #if BITS_PER_LONG==32 +u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offct, + size_t syncp_offset); u64 snmp_fold_field64(void __percpu *mib, int offt, size_t sync_off); #else +static inline u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offct, + size_t syncp_offset) +{ + return snmp_get_cpu_field(mib, cpu, offct); + +} + static inline u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_off) { return snmp_fold_field(mib, offt); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 675e88cac2b46..0c69c0bbe1a12 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1452,38 +1452,51 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family, } EXPORT_SYMBOL_GPL(inet_ctl_sock_create); +u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offt) +{ + return *(((unsigned long *)per_cpu_ptr(mib, cpu)) + offt); +} +EXPORT_SYMBOL_GPL(snmp_get_cpu_field); + unsigned long snmp_fold_field(void __percpu *mib, int offt) { unsigned long res = 0; int i; for_each_possible_cpu(i) - res += *(((unsigned long *) per_cpu_ptr(mib, i)) + offt); + res += snmp_get_cpu_field(mib, i, offt); return res; } EXPORT_SYMBOL_GPL(snmp_fold_field); #if BITS_PER_LONG==32 +u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offct, + size_t syncp_offset) +{ + void *bhptr; + struct u64_stats_sync *syncp; + u64 v; + unsigned int start; + + bhptr = per_cpu_ptr(mib, cpu); + syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); + do { + start = u64_stats_fetch_begin_irq(syncp); + v = *(((u64 *)bhptr) + offt); + } while (u64_stats_fetch_retry_irq(syncp, start)); + + return v; +} +EXPORT_SYMBOL_GPL(snmp_get_cpu_field64); + u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_offset) { u64 res = 0; int cpu; for_each_possible_cpu(cpu) { - void *bhptr; - struct u64_stats_sync *syncp; - u64 v; - unsigned int start; - - bhptr = per_cpu_ptr(mib, cpu); - syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); - do { - start = u64_stats_fetch_begin_irq(syncp); - v = *(((u64 *) bhptr) + offt); - } while (u64_stats_fetch_retry_irq(syncp, start)); - - res += v; + res += snmp_get_cpu_field(mib, cpu, offct, syncp_offset); } return res; } -- GitLab From a3a773726c9f9ba2e87fd8ad8e36feff5f6ffd8e Mon Sep 17 00:00:00 2001 From: Raghavendra K T Date: Sun, 30 Aug 2015 11:29:42 +0530 Subject: [PATCH 5853/7006] net: Optimize snmp stat aggregation by walking all the percpu data at once Docker container creation linearly increased from around 1.6 sec to 7.5 sec (at 1000 containers) and perf data showed 50% ovehead in snmp_fold_field. reason: currently __snmp6_fill_stats64 calls snmp_fold_field that walks through per cpu data of an item (iteratively for around 36 items). idea: This patch tries to aggregate the statistics by going through all the items of each cpu sequentially which is reducing cache misses. Docker creation got faster by more than 2x after the patch. Result: Before After Docker creation time 6.836s 3.25s cache miss 2.7% 1.41% perf before: 50.73% docker [kernel.kallsyms] [k] snmp_fold_field 9.07% swapper [kernel.kallsyms] [k] snooze_loop 3.49% docker [kernel.kallsyms] [k] veth_stats_one 2.85% swapper [kernel.kallsyms] [k] _raw_spin_lock perf after: 10.57% docker docker [.] scanblock 8.37% swapper [kernel.kallsyms] [k] snooze_loop 6.91% docker [kernel.kallsyms] [k] snmp_get_cpu_field 6.67% docker [kernel.kallsyms] [k] veth_stats_one changes/ideas suggested: Using buffer in stack (Eric), Usage of memset (David), Using memcpy in place of unaligned_put (Joe). Signed-off-by: Raghavendra K T Acked-by: Eric Dumazet Signed-off-by: David S. Miller --- net/ipv6/addrconf.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 0f08d3b9e2382..99c0f2b843f01 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -4726,18 +4726,24 @@ static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, } static inline void __snmp6_fill_stats64(u64 *stats, void __percpu *mib, - int items, int bytes, size_t syncpoff) + int bytes, size_t syncpoff) { - int i; - int pad = bytes - sizeof(u64) * items; + int i, c; + u64 buff[IPSTATS_MIB_MAX]; + int pad = bytes - sizeof(u64) * IPSTATS_MIB_MAX; + BUG_ON(pad < 0); - /* Use put_unaligned() because stats may not be aligned for u64. */ - put_unaligned(items, &stats[0]); - for (i = 1; i < items; i++) - put_unaligned(snmp_fold_field64(mib, i, syncpoff), &stats[i]); + memset(buff, 0, sizeof(buff)); + buff[0] = IPSTATS_MIB_MAX; - memset(&stats[items], 0, pad); + for_each_possible_cpu(c) { + for (i = 1; i < IPSTATS_MIB_MAX; i++) + buff[i] += snmp_get_cpu_field64(mib, c, i, syncpoff); + } + + memcpy(stats, buff, IPSTATS_MIB_MAX * sizeof(u64)); + memset(&stats[IPSTATS_MIB_MAX], 0, pad); } static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, @@ -4745,8 +4751,8 @@ static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, { switch (attrtype) { case IFLA_INET6_STATS: - __snmp6_fill_stats64(stats, idev->stats.ipv6, - IPSTATS_MIB_MAX, bytes, offsetof(struct ipstats_mib, syncp)); + __snmp6_fill_stats64(stats, idev->stats.ipv6, bytes, + offsetof(struct ipstats_mib, syncp)); break; case IFLA_INET6_ICMP6STATS: __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, ICMP6_MIB_MAX, bytes); -- GitLab From 322e5cc5c6c03584ff9362357fc1448b5e442e9e Mon Sep 17 00:00:00 2001 From: Aleksey Makarov Date: Sun, 30 Aug 2015 12:29:09 +0300 Subject: [PATCH 5854/7006] net: thunderx: fix MAINTAINERS The liquidio and thunder drivers have different maintainers. Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- MAINTAINERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 1e5843ab1139a..c04fa6c3b2ce3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -928,7 +928,7 @@ M: Sunil Goutham M: Robert Richter L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers) S: Supported -F: drivers/net/ethernet/cavium/ +F: drivers/net/ethernet/cavium/thunder/ ARM/CIRRUS LOGIC CLPS711X ARM ARCHITECTURE M: Alexander Shiyan @@ -2543,7 +2543,6 @@ M: Raghu Vatsavayi L: netdev@vger.kernel.org W: http://www.cavium.com S: Supported -F: drivers/net/ethernet/cavium/ F: drivers/net/ethernet/cavium/liquidio/ CC2520 IEEE-802.15.4 RADIO DRIVER -- GitLab From a2dc5dedbbb32d082a9b6edf8793734dbfd59315 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:10 +0300 Subject: [PATCH 5855/7006] net: thunderx: Add receive error stats reporting via ethtool Added ethtool support to dump receive packet error statistics reported in CQE. Also made some small fixes Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nic.h | 36 ++++++-- .../ethernet/cavium/thunder/nicvf_ethtool.c | 34 ++++++-- .../net/ethernet/cavium/thunder/nicvf_main.c | 26 +++--- .../ethernet/cavium/thunder/nicvf_queues.c | 86 ++++++------------- .../ethernet/cavium/thunder/nicvf_queues.h | 41 --------- 5 files changed, 103 insertions(+), 120 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 8aee250904ec8..58adfd64e506a 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -190,10 +190,10 @@ enum tx_stats_reg_offset { }; struct nicvf_hw_stats { - u64 rx_bytes_ok; - u64 rx_ucast_frames_ok; - u64 rx_bcast_frames_ok; - u64 rx_mcast_frames_ok; + u64 rx_bytes; + u64 rx_ucast_frames; + u64 rx_bcast_frames; + u64 rx_mcast_frames; u64 rx_fcs_errors; u64 rx_l2_errors; u64 rx_drop_red; @@ -204,6 +204,31 @@ struct nicvf_hw_stats { u64 rx_drop_mcast; u64 rx_drop_l3_bcast; u64 rx_drop_l3_mcast; + u64 rx_bgx_truncated_pkts; + u64 rx_jabber_errs; + u64 rx_fcs_errs; + u64 rx_bgx_errs; + u64 rx_prel2_errs; + u64 rx_l2_hdr_malformed; + u64 rx_oversize; + u64 rx_undersize; + u64 rx_l2_len_mismatch; + u64 rx_l2_pclp; + u64 rx_ip_ver_errs; + u64 rx_ip_csum_errs; + u64 rx_ip_hdr_malformed; + u64 rx_ip_payload_malformed; + u64 rx_ip_ttl_errs; + u64 rx_l3_pclp; + u64 rx_l4_malformed; + u64 rx_l4_csum_errs; + u64 rx_udp_len_errs; + u64 rx_l4_port_errs; + u64 rx_tcp_flag_errs; + u64 rx_tcp_offset_errs; + u64 rx_l4_pclp; + u64 rx_truncated_pkts; + u64 tx_bytes_ok; u64 tx_ucast_frames_ok; u64 tx_bcast_frames_ok; @@ -222,6 +247,7 @@ struct nicvf_drv_stats { u64 rx_frames_1518; u64 rx_frames_jumbo; u64 rx_drops; + /* Tx */ u64 tx_frames_ok; u64 tx_drops; @@ -257,7 +283,7 @@ struct nicvf { u32 cq_coalesce_usecs; u32 msg_enable; - struct nicvf_hw_stats stats; + struct nicvf_hw_stats hw_stats; struct nicvf_drv_stats drv_stats; struct bgx_stats bgx_stats; struct work_struct reset_task; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c index a4228e6645670..a961aa30f5362 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c @@ -35,10 +35,10 @@ struct nicvf_stat { } static const struct nicvf_stat nicvf_hw_stats[] = { - NICVF_HW_STAT(rx_bytes_ok), - NICVF_HW_STAT(rx_ucast_frames_ok), - NICVF_HW_STAT(rx_bcast_frames_ok), - NICVF_HW_STAT(rx_mcast_frames_ok), + NICVF_HW_STAT(rx_bytes), + NICVF_HW_STAT(rx_ucast_frames), + NICVF_HW_STAT(rx_bcast_frames), + NICVF_HW_STAT(rx_mcast_frames), NICVF_HW_STAT(rx_fcs_errors), NICVF_HW_STAT(rx_l2_errors), NICVF_HW_STAT(rx_drop_red), @@ -49,6 +49,30 @@ static const struct nicvf_stat nicvf_hw_stats[] = { NICVF_HW_STAT(rx_drop_mcast), NICVF_HW_STAT(rx_drop_l3_bcast), NICVF_HW_STAT(rx_drop_l3_mcast), + NICVF_HW_STAT(rx_bgx_truncated_pkts), + NICVF_HW_STAT(rx_jabber_errs), + NICVF_HW_STAT(rx_fcs_errs), + NICVF_HW_STAT(rx_bgx_errs), + NICVF_HW_STAT(rx_prel2_errs), + NICVF_HW_STAT(rx_l2_hdr_malformed), + NICVF_HW_STAT(rx_oversize), + NICVF_HW_STAT(rx_undersize), + NICVF_HW_STAT(rx_l2_len_mismatch), + NICVF_HW_STAT(rx_l2_pclp), + NICVF_HW_STAT(rx_ip_ver_errs), + NICVF_HW_STAT(rx_ip_csum_errs), + NICVF_HW_STAT(rx_ip_hdr_malformed), + NICVF_HW_STAT(rx_ip_payload_malformed), + NICVF_HW_STAT(rx_ip_ttl_errs), + NICVF_HW_STAT(rx_l3_pclp), + NICVF_HW_STAT(rx_l4_malformed), + NICVF_HW_STAT(rx_l4_csum_errs), + NICVF_HW_STAT(rx_udp_len_errs), + NICVF_HW_STAT(rx_l4_port_errs), + NICVF_HW_STAT(rx_tcp_flag_errs), + NICVF_HW_STAT(rx_tcp_offset_errs), + NICVF_HW_STAT(rx_l4_pclp), + NICVF_HW_STAT(rx_truncated_pkts), NICVF_HW_STAT(tx_bytes_ok), NICVF_HW_STAT(tx_ucast_frames_ok), NICVF_HW_STAT(tx_bcast_frames_ok), @@ -195,7 +219,7 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev, nicvf_update_lmac_stats(nic); for (stat = 0; stat < nicvf_n_hw_stats; stat++) - *(data++) = ((u64 *)&nic->stats) + *(data++) = ((u64 *)&nic->hw_stats) [nicvf_hw_stats[stat].index]; for (stat = 0; stat < nicvf_n_drv_stats; stat++) *(data++) = ((u64 *)&nic->drv_stats) diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 3b90afb8c2932..670ff9bf90b04 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -456,6 +456,12 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, skb->data, skb->len, true); } + /* If error packet, drop it here */ + if (err) { + dev_kfree_skb_any(skb); + return; + } + nicvf_set_rx_frame_cnt(nic, skb); skb_record_rx_queue(skb, cqe_rx->rq_idx); @@ -1118,7 +1124,7 @@ void nicvf_update_lmac_stats(struct nicvf *nic) void nicvf_update_stats(struct nicvf *nic) { int qidx; - struct nicvf_hw_stats *stats = &nic->stats; + struct nicvf_hw_stats *stats = &nic->hw_stats; struct nicvf_drv_stats *drv_stats = &nic->drv_stats; struct queue_set *qs = nic->qs; @@ -1127,14 +1133,16 @@ void nicvf_update_stats(struct nicvf *nic) #define GET_TX_STATS(reg) \ nicvf_reg_read(nic, NIC_VNIC_TX_STAT_0_4 | (reg << 3)) - stats->rx_bytes_ok = GET_RX_STATS(RX_OCTS); - stats->rx_ucast_frames_ok = GET_RX_STATS(RX_UCAST); - stats->rx_bcast_frames_ok = GET_RX_STATS(RX_BCAST); - stats->rx_mcast_frames_ok = GET_RX_STATS(RX_MCAST); + stats->rx_bytes = GET_RX_STATS(RX_OCTS); + stats->rx_ucast_frames = GET_RX_STATS(RX_UCAST); + stats->rx_bcast_frames = GET_RX_STATS(RX_BCAST); + stats->rx_mcast_frames = GET_RX_STATS(RX_MCAST); stats->rx_fcs_errors = GET_RX_STATS(RX_FCS); stats->rx_l2_errors = GET_RX_STATS(RX_L2ERR); stats->rx_drop_red = GET_RX_STATS(RX_RED); + stats->rx_drop_red_bytes = GET_RX_STATS(RX_RED_OCTS); stats->rx_drop_overrun = GET_RX_STATS(RX_ORUN); + stats->rx_drop_overrun_bytes = GET_RX_STATS(RX_ORUN_OCTS); stats->rx_drop_bcast = GET_RX_STATS(RX_DRP_BCAST); stats->rx_drop_mcast = GET_RX_STATS(RX_DRP_MCAST); stats->rx_drop_l3_bcast = GET_RX_STATS(RX_DRP_L3BCAST); @@ -1146,9 +1154,6 @@ void nicvf_update_stats(struct nicvf *nic) stats->tx_mcast_frames_ok = GET_TX_STATS(TX_MCAST); stats->tx_drops = GET_TX_STATS(TX_DROP); - drv_stats->rx_frames_ok = stats->rx_ucast_frames_ok + - stats->rx_bcast_frames_ok + - stats->rx_mcast_frames_ok; drv_stats->tx_frames_ok = stats->tx_ucast_frames_ok + stats->tx_bcast_frames_ok + stats->tx_mcast_frames_ok; @@ -1167,14 +1172,15 @@ static struct rtnl_link_stats64 *nicvf_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) { struct nicvf *nic = netdev_priv(netdev); - struct nicvf_hw_stats *hw_stats = &nic->stats; + struct nicvf_hw_stats *hw_stats = &nic->hw_stats; struct nicvf_drv_stats *drv_stats = &nic->drv_stats; nicvf_update_stats(nic); - stats->rx_bytes = hw_stats->rx_bytes_ok; + stats->rx_bytes = hw_stats->rx_bytes; stats->rx_packets = drv_stats->rx_frames_ok; stats->rx_dropped = drv_stats->rx_drops; + stats->multicast = hw_stats->rx_mcast_frames; stats->tx_bytes = hw_stats->tx_bytes_ok; stats->tx_packets = drv_stats->tx_frames_ok; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index ca4240aa6d156..4fc40d8321d37 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -1371,10 +1371,11 @@ void nicvf_update_sq_stats(struct nicvf *nic, int sq_idx) int nicvf_check_cqe_rx_errs(struct nicvf *nic, struct cmp_queue *cq, struct cqe_rx_t *cqe_rx) { - struct cmp_queue_stats *stats = &cq->stats; + struct nicvf_hw_stats *stats = &nic->hw_stats; + struct nicvf_drv_stats *drv_stats = &nic->drv_stats; if (!cqe_rx->err_level && !cqe_rx->err_opcode) { - stats->rx.errop.good++; + drv_stats->rx_frames_ok++; return 0; } @@ -1384,111 +1385,78 @@ int nicvf_check_cqe_rx_errs(struct nicvf *nic, nic->netdev->name, cqe_rx->err_level, cqe_rx->err_opcode); - switch (cqe_rx->err_level) { - case CQ_ERRLVL_MAC: - stats->rx.errlvl.mac_errs++; - break; - case CQ_ERRLVL_L2: - stats->rx.errlvl.l2_errs++; - break; - case CQ_ERRLVL_L3: - stats->rx.errlvl.l3_errs++; - break; - case CQ_ERRLVL_L4: - stats->rx.errlvl.l4_errs++; - break; - } - switch (cqe_rx->err_opcode) { case CQ_RX_ERROP_RE_PARTIAL: - stats->rx.errop.partial_pkts++; + stats->rx_bgx_truncated_pkts++; break; case CQ_RX_ERROP_RE_JABBER: - stats->rx.errop.jabber_errs++; + stats->rx_jabber_errs++; break; case CQ_RX_ERROP_RE_FCS: - stats->rx.errop.fcs_errs++; - break; - case CQ_RX_ERROP_RE_TERMINATE: - stats->rx.errop.terminate_errs++; + stats->rx_fcs_errs++; break; case CQ_RX_ERROP_RE_RX_CTL: - stats->rx.errop.bgx_rx_errs++; + stats->rx_bgx_errs++; break; case CQ_RX_ERROP_PREL2_ERR: - stats->rx.errop.prel2_errs++; - break; - case CQ_RX_ERROP_L2_FRAGMENT: - stats->rx.errop.l2_frags++; - break; - case CQ_RX_ERROP_L2_OVERRUN: - stats->rx.errop.l2_overruns++; - break; - case CQ_RX_ERROP_L2_PFCS: - stats->rx.errop.l2_pfcs++; - break; - case CQ_RX_ERROP_L2_PUNY: - stats->rx.errop.l2_puny++; + stats->rx_prel2_errs++; break; case CQ_RX_ERROP_L2_MAL: - stats->rx.errop.l2_hdr_malformed++; + stats->rx_l2_hdr_malformed++; break; case CQ_RX_ERROP_L2_OVERSIZE: - stats->rx.errop.l2_oversize++; + stats->rx_oversize++; break; case CQ_RX_ERROP_L2_UNDERSIZE: - stats->rx.errop.l2_undersize++; + stats->rx_undersize++; break; case CQ_RX_ERROP_L2_LENMISM: - stats->rx.errop.l2_len_mismatch++; + stats->rx_l2_len_mismatch++; break; case CQ_RX_ERROP_L2_PCLP: - stats->rx.errop.l2_pclp++; + stats->rx_l2_pclp++; break; case CQ_RX_ERROP_IP_NOT: - stats->rx.errop.non_ip++; + stats->rx_ip_ver_errs++; break; case CQ_RX_ERROP_IP_CSUM_ERR: - stats->rx.errop.ip_csum_err++; + stats->rx_ip_csum_errs++; break; case CQ_RX_ERROP_IP_MAL: - stats->rx.errop.ip_hdr_malformed++; + stats->rx_ip_hdr_malformed++; break; case CQ_RX_ERROP_IP_MALD: - stats->rx.errop.ip_payload_malformed++; + stats->rx_ip_payload_malformed++; break; case CQ_RX_ERROP_IP_HOP: - stats->rx.errop.ip_hop_errs++; - break; - case CQ_RX_ERROP_L3_ICRC: - stats->rx.errop.l3_icrc_errs++; + stats->rx_ip_ttl_errs++; break; case CQ_RX_ERROP_L3_PCLP: - stats->rx.errop.l3_pclp++; + stats->rx_l3_pclp++; break; case CQ_RX_ERROP_L4_MAL: - stats->rx.errop.l4_malformed++; + stats->rx_l4_malformed++; break; case CQ_RX_ERROP_L4_CHK: - stats->rx.errop.l4_csum_errs++; + stats->rx_l4_csum_errs++; break; case CQ_RX_ERROP_UDP_LEN: - stats->rx.errop.udp_len_err++; + stats->rx_udp_len_errs++; break; case CQ_RX_ERROP_L4_PORT: - stats->rx.errop.bad_l4_port++; + stats->rx_l4_port_errs++; break; case CQ_RX_ERROP_TCP_FLAG: - stats->rx.errop.bad_tcp_flag++; + stats->rx_tcp_flag_errs++; break; case CQ_RX_ERROP_TCP_OFFSET: - stats->rx.errop.tcp_offset_errs++; + stats->rx_tcp_offset_errs++; break; case CQ_RX_ERROP_L4_PCLP: - stats->rx.errop.l4_pclp++; + stats->rx_l4_pclp++; break; case CQ_RX_ERROP_RBDR_TRUNC: - stats->rx.errop.pkt_truncated++; + stats->rx_truncated_pkts++; break; } diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index f0937b7bfe9f4..dc7387261809c 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -181,47 +181,6 @@ enum CQ_TX_ERROP_E { }; struct cmp_queue_stats { - struct rx_stats { - struct { - u64 mac_errs; - u64 l2_errs; - u64 l3_errs; - u64 l4_errs; - } errlvl; - struct { - u64 good; - u64 partial_pkts; - u64 jabber_errs; - u64 fcs_errs; - u64 terminate_errs; - u64 bgx_rx_errs; - u64 prel2_errs; - u64 l2_frags; - u64 l2_overruns; - u64 l2_pfcs; - u64 l2_puny; - u64 l2_hdr_malformed; - u64 l2_oversize; - u64 l2_undersize; - u64 l2_len_mismatch; - u64 l2_pclp; - u64 non_ip; - u64 ip_csum_err; - u64 ip_hdr_malformed; - u64 ip_payload_malformed; - u64 ip_hop_errs; - u64 l3_icrc_errs; - u64 l3_pclp; - u64 l4_malformed; - u64 l4_csum_errs; - u64 udp_len_err; - u64 bad_l4_port; - u64 bad_tcp_flag; - u64 tcp_offset_errs; - u64 l4_pclp; - u64 pkt_truncated; - } errop; - } rx; struct tx_stats { u64 good; u64 desc_fault; -- GitLab From 6051cba77c1c768d954cf9e423c44bcb85b9adb8 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:11 +0300 Subject: [PATCH 5856/7006] net: thunderx: mailboxes: remove code duplication Use the nicvf_send_msg_to_pf() function in the mailbox code. Signed-off-by: Sunil Goutham Signed-off-by: Robert Richter Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nic.h | 3 +- .../net/ethernet/cavium/thunder/nicvf_main.c | 44 +++++-------------- 2 files changed, 11 insertions(+), 36 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 58adfd64e506a..a83f567a57400 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -295,10 +295,9 @@ struct nicvf { char irq_name[NIC_VF_MSIX_VECTORS][20]; bool irq_allocated[NIC_VF_MSIX_VECTORS]; - bool pf_ready_to_rcv_msg; + /* VF <-> PF mailbox communication */ bool pf_acked; bool pf_nacked; - bool bgx_stats_acked; bool set_mac_pending; } ____cacheline_aligned_in_smp; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 670ff9bf90b04..d4ad36e6bac0b 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -105,7 +105,6 @@ u64 nicvf_queue_reg_read(struct nicvf *nic, u64 offset, u64 qidx) } /* VF -> PF mailbox communication */ - static void nicvf_write_to_mbx(struct nicvf *nic, union nic_mbx *mbx) { u64 *msg = (u64 *)mbx; @@ -147,26 +146,15 @@ int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx) */ static int nicvf_check_pf_ready(struct nicvf *nic) { - int timeout = 5000, sleep = 20; union nic_mbx mbx = {}; mbx.msg.msg = NIC_MBOX_MSG_READY; - - nic->pf_ready_to_rcv_msg = false; - - nicvf_write_to_mbx(nic, &mbx); - - while (!nic->pf_ready_to_rcv_msg) { - msleep(sleep); - if (nic->pf_ready_to_rcv_msg) - break; - timeout -= sleep; - if (!timeout) { - netdev_err(nic->netdev, - "PF didn't respond to READY msg\n"); - return 0; - } + if (nicvf_send_msg_to_pf(nic, &mbx)) { + netdev_err(nic->netdev, + "PF didn't respond to READY msg\n"); + return 0; } + return 1; } @@ -197,7 +185,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) netdev_dbg(nic->netdev, "Mbox message: msg: 0x%x\n", mbx.msg.msg); switch (mbx.msg.msg) { case NIC_MBOX_MSG_READY: - nic->pf_ready_to_rcv_msg = true; + nic->pf_acked = true; nic->vf_id = mbx.nic_cfg.vf_id & 0x7F; nic->tns_mode = mbx.nic_cfg.tns_mode & 0x7F; nic->node = mbx.nic_cfg.node_id; @@ -221,7 +209,6 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) case NIC_MBOX_MSG_BGX_STATS: nicvf_read_bgx_stats(nic, &mbx.bgx_stats); nic->pf_acked = true; - nic->bgx_stats_acked = true; break; case NIC_MBOX_MSG_BGX_LINK_CHANGE: nic->pf_acked = true; @@ -1083,7 +1070,6 @@ void nicvf_update_lmac_stats(struct nicvf *nic) { int stat = 0; union nic_mbx mbx = {}; - int timeout; if (!netif_running(nic->netdev)) return; @@ -1093,14 +1079,9 @@ void nicvf_update_lmac_stats(struct nicvf *nic) /* Rx stats */ mbx.bgx_stats.rx = 1; while (stat < BGX_RX_STATS_COUNT) { - nic->bgx_stats_acked = 0; mbx.bgx_stats.idx = stat; - nicvf_send_msg_to_pf(nic, &mbx); - timeout = 0; - while ((!nic->bgx_stats_acked) && (timeout < 10)) { - msleep(2); - timeout++; - } + if (nicvf_send_msg_to_pf(nic, &mbx)) + return; stat++; } @@ -1109,14 +1090,9 @@ void nicvf_update_lmac_stats(struct nicvf *nic) /* Tx stats */ mbx.bgx_stats.rx = 0; while (stat < BGX_TX_STATS_COUNT) { - nic->bgx_stats_acked = 0; mbx.bgx_stats.idx = stat; - nicvf_send_msg_to_pf(nic, &mbx); - timeout = 0; - while ((!nic->bgx_stats_acked) && (timeout < 10)) { - msleep(2); - timeout++; - } + if (nicvf_send_msg_to_pf(nic, &mbx)) + return; stat++; } } -- GitLab From 38bb5d4f4f988c98035fca003138dd84471432f2 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:12 +0300 Subject: [PATCH 5857/7006] net: thunderx: Receive hashing HW offload support Adding support for receive hashing HW offload by using RSS_ALG and RSS_TAG fields of CQE_RX descriptor. Also removed dependency on minimum receive queue count to configure RSS so that hash is always generated. This hash is used by RPS logic to distribute flows across multiple CPUs. Offload can be disabled via ethtool. Signed-off-by: Robert Richter Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- .../ethernet/cavium/thunder/nicvf_ethtool.c | 14 ++++---- .../net/ethernet/cavium/thunder/nicvf_main.c | 35 +++++++++++++++++-- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c index a961aa30f5362..1eec2cd657ffc 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c @@ -525,17 +525,15 @@ static int nicvf_set_rxfh(struct net_device *dev, const u32 *indir, struct nicvf_rss_info *rss = &nic->rss_info; int idx; - if ((nic->qs->rq_cnt <= 1) || (nic->cpi_alg != CPI_ALG_NONE)) { - rss->enable = false; - rss->hash_bits = 0; - return -EIO; - } - - /* We do not allow change in unsupported parameters */ if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP) return -EOPNOTSUPP; - rss->enable = true; + if (!rss->enable) { + netdev_err(nic->netdev, + "RSS is disabled, cannot change settings\n"); + return -EIO; + } + if (indir) { for (idx = 0; idx < rss->rss_size; idx++) rss->ind_tbl[idx] = indir[idx]; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index d4ad36e6bac0b..afd8ad497140a 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -313,7 +313,7 @@ static int nicvf_rss_init(struct nicvf *nic) nicvf_get_rss_size(nic); - if ((nic->qs->rq_cnt <= 1) || (cpi_alg != CPI_ALG_NONE)) { + if (cpi_alg != CPI_ALG_NONE) { rss->enable = false; rss->hash_bits = 0; return 0; @@ -416,6 +416,34 @@ static void nicvf_snd_pkt_handler(struct net_device *netdev, } } +static inline void nicvf_set_rxhash(struct net_device *netdev, + struct cqe_rx_t *cqe_rx, + struct sk_buff *skb) +{ + u8 hash_type; + u32 hash; + + if (!(netdev->features & NETIF_F_RXHASH)) + return; + + switch (cqe_rx->rss_alg) { + case RSS_ALG_TCP_IP: + case RSS_ALG_UDP_IP: + hash_type = PKT_HASH_TYPE_L4; + hash = cqe_rx->rss_tag; + break; + case RSS_ALG_IP: + hash_type = PKT_HASH_TYPE_L3; + hash = cqe_rx->rss_tag; + break; + default: + hash_type = PKT_HASH_TYPE_NONE; + hash = 0; + } + + skb_set_hash(skb, hash, hash_type); +} + static void nicvf_rcv_pkt_handler(struct net_device *netdev, struct napi_struct *napi, struct cmp_queue *cq, @@ -451,6 +479,8 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, nicvf_set_rx_frame_cnt(nic, skb); + nicvf_set_rxhash(netdev, cqe_rx, skb); + skb_record_rx_queue(skb, cqe_rx->rq_idx); if (netdev->hw_features & NETIF_F_RXCSUM) { /* HW by default verifies TCP/UDP/SCTP checksums */ @@ -1272,7 +1302,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_free_netdev; netdev->features |= (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_TSO | NETIF_F_GRO); + NETIF_F_TSO | NETIF_F_GRO | NETIF_F_RXHASH); + netdev->hw_features = netdev->features; netdev->netdev_ops = &nicvf_netdev_ops; -- GitLab From aa2e259b474a4f52ecc9f6e0d444547de0aac4b2 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:13 +0300 Subject: [PATCH 5858/7006] net: thunderx: Support for HW VLAN stripping This patch configures HW to strip 802.1Q header if found in a receiving packet. The stripped VLAN ID and TCI information is passed on to software via CQE_RX. Also sets netdev's 'vlan_features' so that other HW offload features can be used for tagged packets. This offload feature can be enabled or disabled via ethtool. Network stack normally ignores RPS for 802.1Q packets and hence low throughput. With this offload enabled throughput for tagged packets will be almost same as normal packets. Note: This patch doesn't enable HW VLAN insertion for transmit packets. Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- .../net/ethernet/cavium/thunder/nic_main.c | 4 +++ .../net/ethernet/cavium/thunder/nicvf_main.c | 28 +++++++++++++++++-- .../ethernet/cavium/thunder/nicvf_queues.c | 28 ++++++++++++++++--- .../ethernet/cavium/thunder/nicvf_queues.h | 2 ++ 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index 6e0c03169a55e..7dfec4afe3f99 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -329,6 +329,10 @@ static void nic_init_hw(struct nicpf *nic) /* Timer config */ nic_reg_write(nic, NIC_PF_INTR_TIMER_CFG, NICPF_CLK_PER_INT_TICK); + + /* Enable VLAN ethertype matching and stripping */ + nic_reg_write(nic, NIC_PF_RX_ETYPE_0_7, + (2 << 19) | (ETYPE_ALG_VLAN_STRIP << 16) | ETH_P_8021Q); } /* Channel parse index configuration */ diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index afd8ad497140a..de518288973e7 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -491,6 +492,11 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, skb->protocol = eth_type_trans(skb, netdev); + /* Check for stripped VLAN */ + if (cqe_rx->vlan_found && cqe_rx->vlan_stripped) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + ntohs((__force __be16)cqe_rx->vlan_tci)); + if (napi && (netdev->features & NETIF_F_GRO)) napi_gro_receive(napi, skb); else @@ -1220,6 +1226,18 @@ static void nicvf_reset_task(struct work_struct *work) nic->netdev->trans_start = jiffies; } +static int nicvf_set_features(struct net_device *netdev, + netdev_features_t features) +{ + struct nicvf *nic = netdev_priv(netdev); + netdev_features_t changed = features ^ netdev->features; + + if (changed & NETIF_F_HW_VLAN_CTAG_RX) + nicvf_config_vlan_stripping(nic, features); + + return 0; +} + static const struct net_device_ops nicvf_netdev_ops = { .ndo_open = nicvf_open, .ndo_stop = nicvf_stop, @@ -1228,6 +1246,7 @@ static const struct net_device_ops nicvf_netdev_ops = { .ndo_set_mac_address = nicvf_set_mac_address, .ndo_get_stats64 = nicvf_get_stats64, .ndo_tx_timeout = nicvf_tx_timeout, + .ndo_set_features = nicvf_set_features, }; static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1301,10 +1320,13 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_free_netdev; - netdev->features |= (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | - NETIF_F_TSO | NETIF_F_GRO | NETIF_F_RXHASH); + netdev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_GRO | + NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXHASH); + + netdev->features |= netdev->hw_features; - netdev->hw_features = netdev->features; + netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; netdev->netdev_ops = &nicvf_netdev_ops; netdev->watchdog_timeo = NICVF_TX_TIMEOUT; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index 4fc40d8321d37..b294d67d48e4a 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -475,6 +475,27 @@ static void nicvf_reclaim_rbdr(struct nicvf *nic, return; } +void nicvf_config_vlan_stripping(struct nicvf *nic, netdev_features_t features) +{ + u64 rq_cfg; + int sqs; + + rq_cfg = nicvf_queue_reg_read(nic, NIC_QSET_RQ_GEN_CFG, 0); + + /* Enable first VLAN stripping */ + if (features & NETIF_F_HW_VLAN_CTAG_RX) + rq_cfg |= (1ULL << 25); + else + rq_cfg &= ~(1ULL << 25); + nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, rq_cfg); + + /* Configure Secondary Qsets, if any */ + for (sqs = 0; sqs < nic->sqs_count; sqs++) + if (nic->snicvf[sqs]) + nicvf_queue_reg_write(nic->snicvf[sqs], + NIC_QSET_RQ_GEN_CFG, 0, rq_cfg); +} + /* Configures receive queue */ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs, int qidx, bool enable) @@ -524,7 +545,9 @@ static void nicvf_rcv_queue_config(struct nicvf *nic, struct queue_set *qs, mbx.rq.cfg = (1ULL << 62) | (RQ_CQ_DROP << 8); nicvf_send_msg_to_pf(nic, &mbx); - nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, qidx, 0x00); + nicvf_queue_reg_write(nic, NIC_QSET_RQ_GEN_CFG, 0, 0x00); + if (!nic->sqs_mode) + nicvf_config_vlan_stripping(nic, nic->netdev->features); /* Enable Receive queue */ rq_cfg.ena = 1; @@ -961,9 +984,6 @@ nicvf_sq_add_hdr_subdesc(struct snd_queue *sq, int qentry, /* Offload checksum calculation to HW */ if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb->protocol != htons(ETH_P_IP)) - return; - hdr->csum_l3 = 1; /* Enable IP csum calculation */ hdr->l3_offset = skb_network_offset(skb); hdr->l4_offset = skb_transport_offset(skb); diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index dc7387261809c..8b93dd6721271 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -306,6 +306,8 @@ struct queue_set { #define CQ_ERR_MASK (CQ_WR_FULL | CQ_WR_DISABLE | CQ_WR_FAULT) +void nicvf_config_vlan_stripping(struct nicvf *nic, + netdev_features_t features); int nicvf_set_qset_resources(struct nicvf *nic); int nicvf_config_data_transfer(struct nicvf *nic, bool enable); void nicvf_qset_config(struct nicvf *nic, bool enable); -- GitLab From 39ad6eea6c1a01b69abb1102a767697fb9349830 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:14 +0300 Subject: [PATCH 5859/7006] net: thunderx: Rework interrupt handling Rework interrupt handler to avoid checking IRQ affinity of CQ interrupts. Now separate handlers are registered for each IRQ including RBDR. Register interrupt handlers for only those which are being used. Add nicvf_dump_intr_status() and use it in irq handlers. Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nic.h | 1 + .../net/ethernet/cavium/thunder/nicvf_main.c | 172 ++++++++++-------- .../ethernet/cavium/thunder/nicvf_queues.h | 1 + 3 files changed, 102 insertions(+), 72 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index a83f567a57400..89b997e073138 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -135,6 +135,7 @@ #define NICVF_TX_TIMEOUT (50 * HZ) struct nicvf_cq_poll { + struct nicvf *nicvf; u8 cq_idx; /* Completion queue index */ struct napi_struct napi; }; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index de518288973e7..85213f38ceb0f 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -653,11 +653,20 @@ static void nicvf_handle_qs_err(unsigned long data) nicvf_enable_intr(nic, NICVF_INTR_QS_ERR, 0); } +static void nicvf_dump_intr_status(struct nicvf *nic) +{ + if (netif_msg_intr(nic)) + netdev_info(nic->netdev, "%s: interrupt status 0x%llx\n", + nic->netdev->name, nicvf_reg_read(nic, NIC_VF_INT)); +} + static irqreturn_t nicvf_misc_intr_handler(int irq, void *nicvf_irq) { struct nicvf *nic = (struct nicvf *)nicvf_irq; u64 intr; + nicvf_dump_intr_status(nic); + intr = nicvf_reg_read(nic, NIC_VF_INT); /* Check for spurious interrupt */ if (!(intr & NICVF_INTR_MBOX_MASK)) @@ -668,59 +677,58 @@ static irqreturn_t nicvf_misc_intr_handler(int irq, void *nicvf_irq) return IRQ_HANDLED; } -static irqreturn_t nicvf_intr_handler(int irq, void *nicvf_irq) +static irqreturn_t nicvf_intr_handler(int irq, void *cq_irq) +{ + struct nicvf_cq_poll *cq_poll = (struct nicvf_cq_poll *)cq_irq; + struct nicvf *nic = cq_poll->nicvf; + int qidx = cq_poll->cq_idx; + + nicvf_dump_intr_status(nic); + + /* Disable interrupts */ + nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx); + + /* Schedule NAPI */ + napi_schedule(&cq_poll->napi); + + /* Clear interrupt */ + nicvf_clear_intr(nic, NICVF_INTR_CQ, qidx); + + return IRQ_HANDLED; +} + +static irqreturn_t nicvf_rbdr_intr_handler(int irq, void *nicvf_irq) { - u64 qidx, intr, clear_intr = 0; - u64 cq_intr, rbdr_intr, qs_err_intr; struct nicvf *nic = (struct nicvf *)nicvf_irq; - struct queue_set *qs = nic->qs; - struct nicvf_cq_poll *cq_poll = NULL; + u8 qidx; - intr = nicvf_reg_read(nic, NIC_VF_INT); - if (netif_msg_intr(nic)) - netdev_info(nic->netdev, "%s: interrupt status 0x%llx\n", - nic->netdev->name, intr); - - qs_err_intr = intr & NICVF_INTR_QS_ERR_MASK; - if (qs_err_intr) { - /* Disable Qset err interrupt and schedule softirq */ - nicvf_disable_intr(nic, NICVF_INTR_QS_ERR, 0); - tasklet_hi_schedule(&nic->qs_err_task); - clear_intr |= qs_err_intr; - } - /* Disable interrupts and start polling */ - cq_intr = (intr & NICVF_INTR_CQ_MASK) >> NICVF_INTR_CQ_SHIFT; - for (qidx = 0; qidx < qs->cq_cnt; qidx++) { - if (!(cq_intr & (1 << qidx))) - continue; - if (!nicvf_is_intr_enabled(nic, NICVF_INTR_CQ, qidx)) + nicvf_dump_intr_status(nic); + + /* Disable RBDR interrupt and schedule softirq */ + for (qidx = 0; qidx < nic->qs->rbdr_cnt; qidx++) { + if (!nicvf_is_intr_enabled(nic, NICVF_INTR_RBDR, qidx)) continue; + nicvf_disable_intr(nic, NICVF_INTR_RBDR, qidx); + tasklet_hi_schedule(&nic->rbdr_task); + /* Clear interrupt */ + nicvf_clear_intr(nic, NICVF_INTR_RBDR, qidx); + } - nicvf_disable_intr(nic, NICVF_INTR_CQ, qidx); - clear_intr |= ((1 << qidx) << NICVF_INTR_CQ_SHIFT); + return IRQ_HANDLED; +} - cq_poll = nic->napi[qidx]; - /* Schedule NAPI */ - if (cq_poll) - napi_schedule(&cq_poll->napi); - } +static irqreturn_t nicvf_qs_err_intr_handler(int irq, void *nicvf_irq) +{ + struct nicvf *nic = (struct nicvf *)nicvf_irq; - /* Handle RBDR interrupts */ - rbdr_intr = (intr & NICVF_INTR_RBDR_MASK) >> NICVF_INTR_RBDR_SHIFT; - if (rbdr_intr) { - /* Disable RBDR interrupt and schedule softirq */ - for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) { - if (!nicvf_is_intr_enabled(nic, NICVF_INTR_RBDR, qidx)) - continue; - nicvf_disable_intr(nic, NICVF_INTR_RBDR, qidx); - tasklet_hi_schedule(&nic->rbdr_task); - clear_intr |= ((1 << qidx) << NICVF_INTR_RBDR_SHIFT); - } - } + nicvf_dump_intr_status(nic); + + /* Disable Qset err interrupt and schedule softirq */ + nicvf_disable_intr(nic, NICVF_INTR_QS_ERR, 0); + tasklet_hi_schedule(&nic->qs_err_task); + nicvf_clear_intr(nic, NICVF_INTR_QS_ERR, 0); - /* Clear interrupts */ - nicvf_reg_write(nic, NIC_VF_INT, clear_intr); return IRQ_HANDLED; } @@ -754,7 +762,7 @@ static void nicvf_disable_msix(struct nicvf *nic) static int nicvf_register_interrupts(struct nicvf *nic) { - int irq, free, ret = 0; + int irq, ret = 0; int vector; for_each_cq_irq(irq) @@ -769,44 +777,42 @@ static int nicvf_register_interrupts(struct nicvf *nic) sprintf(nic->irq_name[irq], "NICVF%d RBDR%d", nic->vf_id, irq - NICVF_INTR_ID_RBDR); - /* Register all interrupts except mailbox */ - for (irq = 0; irq < NICVF_INTR_ID_SQ; irq++) { + /* Register CQ interrupts */ + for (irq = 0; irq < nic->qs->cq_cnt; irq++) { vector = nic->msix_entries[irq].vector; ret = request_irq(vector, nicvf_intr_handler, - 0, nic->irq_name[irq], nic); + 0, nic->irq_name[irq], nic->napi[irq]); if (ret) - break; + goto err; nic->irq_allocated[irq] = true; } - for (irq = NICVF_INTR_ID_SQ; irq < NICVF_INTR_ID_MISC; irq++) { + /* Register RBDR interrupt */ + for (irq = NICVF_INTR_ID_RBDR; + irq < (NICVF_INTR_ID_RBDR + nic->qs->rbdr_cnt); irq++) { vector = nic->msix_entries[irq].vector; - ret = request_irq(vector, nicvf_intr_handler, + ret = request_irq(vector, nicvf_rbdr_intr_handler, 0, nic->irq_name[irq], nic); if (ret) - break; + goto err; nic->irq_allocated[irq] = true; } + /* Register QS error interrupt */ sprintf(nic->irq_name[NICVF_INTR_ID_QS_ERR], "NICVF%d Qset error", nic->vf_id); - if (!ret) { - vector = nic->msix_entries[NICVF_INTR_ID_QS_ERR].vector; - irq = NICVF_INTR_ID_QS_ERR; - ret = request_irq(vector, nicvf_intr_handler, - 0, nic->irq_name[irq], nic); - if (!ret) - nic->irq_allocated[irq] = true; - } + irq = NICVF_INTR_ID_QS_ERR; + ret = request_irq(nic->msix_entries[irq].vector, + nicvf_qs_err_intr_handler, + 0, nic->irq_name[irq], nic); + if (!ret) + nic->irq_allocated[irq] = true; - if (ret) { - netdev_err(nic->netdev, "Request irq failed\n"); - for (free = 0; free < irq; free++) - free_irq(nic->msix_entries[free].vector, nic); - return ret; - } +err: + if (ret) + netdev_err(nic->netdev, "request_irq failed, vector %d\n", irq); - return 0; + return ret; } static void nicvf_unregister_interrupts(struct nicvf *nic) @@ -815,8 +821,14 @@ static void nicvf_unregister_interrupts(struct nicvf *nic) /* Free registered interrupts */ for (irq = 0; irq < nic->num_vec; irq++) { - if (nic->irq_allocated[irq]) + if (!nic->irq_allocated[irq]) + continue; + + if (irq < NICVF_INTR_ID_SQ) + free_irq(nic->msix_entries[irq].vector, nic->napi[irq]); + else free_irq(nic->msix_entries[irq].vector, nic); + nic->irq_allocated[irq] = false; } @@ -888,6 +900,20 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } +static inline void nicvf_free_cq_poll(struct nicvf *nic) +{ + struct nicvf_cq_poll *cq_poll; + int qidx; + + for (qidx = 0; qidx < nic->qs->cq_cnt; qidx++) { + cq_poll = nic->napi[qidx]; + if (!cq_poll) + continue; + nic->napi[qidx] = NULL; + kfree(cq_poll); + } +} + int nicvf_stop(struct net_device *netdev) { int irq, qidx; @@ -922,7 +948,6 @@ int nicvf_stop(struct net_device *netdev) cq_poll = nic->napi[qidx]; if (!cq_poll) continue; - nic->napi[qidx] = NULL; napi_synchronize(&cq_poll->napi); /* CQ intr is enabled while napi_complete, * so disable it now @@ -931,7 +956,6 @@ int nicvf_stop(struct net_device *netdev) nicvf_clear_intr(nic, NICVF_INTR_CQ, qidx); napi_disable(&cq_poll->napi); netif_napi_del(&cq_poll->napi); - kfree(cq_poll); } netif_tx_disable(netdev); @@ -947,6 +971,8 @@ int nicvf_stop(struct net_device *netdev) nicvf_unregister_interrupts(nic); + nicvf_free_cq_poll(nic); + return 0; } @@ -973,6 +999,7 @@ int nicvf_open(struct net_device *netdev) goto napi_del; } cq_poll->cq_idx = qidx; + cq_poll->nicvf = nic; netif_napi_add(netdev, &cq_poll->napi, nicvf_poll, NAPI_POLL_WEIGHT); napi_enable(&cq_poll->napi); @@ -1040,6 +1067,8 @@ int nicvf_open(struct net_device *netdev) cleanup: nicvf_disable_intr(nic, NICVF_INTR_MBOX, 0); nicvf_unregister_interrupts(nic); + tasklet_kill(&nic->qs_err_task); + tasklet_kill(&nic->rbdr_task); napi_del: for (qidx = 0; qidx < qs->cq_cnt; qidx++) { cq_poll = nic->napi[qidx]; @@ -1047,9 +1076,8 @@ napi_del: continue; napi_disable(&cq_poll->napi); netif_napi_del(&cq_poll->napi); - kfree(cq_poll); - nic->napi[qidx] = NULL; } + nicvf_free_cq_poll(nic); return err; } diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h index 8b93dd6721271..fb4957d099144 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.h +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.h @@ -251,6 +251,7 @@ struct cmp_queue { void *desc; struct q_desc_mem dmem; struct cmp_queue_stats stats; + int irq; } ____cacheline_aligned_in_smp; struct snd_queue { -- GitLab From 92dc87697e6a71675a9e9eec04ebecd8cf4837a3 Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:15 +0300 Subject: [PATCH 5860/7006] net: thunderx: Support for upto 96 queues for a VF This patch adds support for handling multiple qsets assigned to a single VF. There by increasing no of queues from earlier 8 to max no of CPUs in the system i.e 48 queues on a single node and 96 on dual node system. User doesn't have option to assign which Qsets/VFs to be merged. Upon request from VF, PF assigns next free Qsets as secondary qsets. To maintain current behavior no of queues is kept to 8 by default which can be increased via ethtool. If user wants to unbind NICVF driver from a secondary Qset then it should be done after tearing down primary VF's interface. Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: Robert Richter Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nic.h | 42 +++- .../net/ethernet/cavium/thunder/nic_main.c | 173 +++++++++++++-- .../ethernet/cavium/thunder/nicvf_ethtool.c | 134 ++++++++--- .../net/ethernet/cavium/thunder/nicvf_main.c | 210 ++++++++++++++++-- .../ethernet/cavium/thunder/nicvf_queues.c | 30 ++- 5 files changed, 505 insertions(+), 84 deletions(-) diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 89b997e073138..35b2ee1bc07ed 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -258,13 +258,23 @@ struct nicvf_drv_stats { }; struct nicvf { + struct nicvf *pnicvf; struct net_device *netdev; struct pci_dev *pdev; u8 vf_id; u8 node; - u8 tns_mode; + u8 tns_mode:1; + u8 sqs_mode:1; u16 mtu; struct queue_set *qs; +#define MAX_SQS_PER_VF_SINGLE_NODE 5 +#define MAX_SQS_PER_VF 11 + u8 sqs_id; + u8 sqs_count; /* Secondary Qset count */ + struct nicvf *snicvf[MAX_SQS_PER_VF]; + u8 rx_queues; + u8 tx_queues; + u8 max_queues; void __iomem *reg_base; bool link_up; u8 duplex; @@ -330,14 +340,19 @@ struct nicvf { #define NIC_MBOX_MSG_RQ_SW_SYNC 0x0F /* Flush inflight pkts to RQ */ #define NIC_MBOX_MSG_BGX_STATS 0x10 /* Get stats from BGX */ #define NIC_MBOX_MSG_BGX_LINK_CHANGE 0x11 /* BGX:LMAC link status */ -#define NIC_MBOX_MSG_CFG_DONE 0x12 /* VF configuration done */ -#define NIC_MBOX_MSG_SHUTDOWN 0x13 /* VF is being shutdown */ +#define NIC_MBOX_MSG_ALLOC_SQS 0x12 /* Allocate secondary Qset */ +#define NIC_MBOX_MSG_NICVF_PTR 0x13 /* Send nicvf ptr to PF */ +#define NIC_MBOX_MSG_PNICVF_PTR 0x14 /* Get primary qset nicvf ptr */ +#define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */ +#define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ +#define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ struct nic_cfg_msg { u8 msg; u8 vf_id; - u8 tns_mode; u8 node_id; + u8 tns_mode:1; + u8 sqs_mode:1; u8 mac_addr[ETH_ALEN]; }; @@ -345,6 +360,7 @@ struct nic_cfg_msg { struct qs_cfg_msg { u8 msg; u8 num; + u8 sqs_count; u64 cfg; }; @@ -361,6 +377,7 @@ struct sq_cfg_msg { u8 msg; u8 qs_num; u8 sq_num; + bool sqs_mode; u64 cfg; }; @@ -420,6 +437,21 @@ struct bgx_link_status { u32 speed; }; +/* Get Extra Qset IDs */ +struct sqs_alloc { + u8 msg; + u8 vf_id; + u8 qs_count; +}; + +struct nicvf_ptr { + u8 msg; + u8 vf_id; + bool sqs_mode; + u8 sqs_id; + u64 nicvf; +}; + /* 128 bit shared memory between PF and each VF */ union nic_mbx { struct { u8 msg; } msg; @@ -434,6 +466,8 @@ union nic_mbx { struct rss_cfg_msg rss_cfg; struct bgx_stats_msg bgx_stats; struct bgx_link_status link_status; + struct sqs_alloc sqs_alloc; + struct nicvf_ptr nicvf; }; #define NIC_NODE_ID_MASK 0x03 diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index 7dfec4afe3f99..dac80943a7820 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -28,6 +28,11 @@ struct nicpf { u8 num_vf_en; /* No of VF enabled */ bool vf_enabled[MAX_NUM_VFS_SUPPORTED]; void __iomem *reg_base; /* Register start address */ + u8 num_sqs_en; /* Secondary qsets enabled */ + u64 nicvf[MAX_NUM_VFS_SUPPORTED]; + u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF]; + u8 pqs_vf[MAX_NUM_VFS_SUPPORTED]; + bool sqs_used[MAX_NUM_VFS_SUPPORTED]; struct pkind_cfg pkind; #define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF)) #define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF) @@ -139,13 +144,15 @@ static void nic_mbx_send_ready(struct nicpf *nic, int vf) mbx.nic_cfg.tns_mode = NIC_TNS_BYPASS_MODE; - bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); - lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); - - mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); - if (mac) - ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac); + if (vf < MAX_LMAC) { + bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vf]); + mac = bgx_get_lmac_mac(nic->node, bgx_idx, lmac); + if (mac) + ether_addr_copy((u8 *)&mbx.nic_cfg.mac_addr, mac); + } + mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; mbx.nic_cfg.node_id = nic->node; nic_send_msg_to_vf(nic, vf, &mbx); } @@ -433,6 +440,12 @@ static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg) qset = cfg->vf_id; for (; rssi < (rssi_base + cfg->tbl_len); rssi++) { + u8 svf = cfg->ind_tbl[idx] >> 3; + + if (svf) + qset = nic->vf_sqs[cfg->vf_id][svf - 1]; + else + qset = cfg->vf_id; nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3), (qset << 3) | (cfg->ind_tbl[idx] & 0x7)); idx++; @@ -456,19 +469,31 @@ static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg) * VNIC6-SQ0 -> TL4(528) -> TL3[132] -> TL2[33] -> TL1[1] -> BGX1 * VNIC7-SQ0 -> TL4(536) -> TL3[134] -> TL2[33] -> TL1[1] -> BGX1 */ -static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, u8 sq_idx) +static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, + struct sq_cfg_msg *sq) { u32 bgx, lmac, chan; u32 tl2, tl3, tl4; u32 rr_quantum; + u8 sq_idx = sq->sq_num; + u8 pqs_vnic; + + if (sq->sqs_mode) + pqs_vnic = nic->pqs_vf[vnic]; + else + pqs_vnic = vnic; + + bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); + lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[pqs_vnic]); - bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); - lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[vnic]); /* 24 bytes for FCS, IPG and preamble */ rr_quantum = ((NIC_HW_MAX_FRS + 24) / 4); tl4 = (lmac * NIC_TL4_PER_LMAC) + (bgx * NIC_TL4_PER_BGX); tl4 += sq_idx; + if (sq->sqs_mode) + tl4 += vnic * 8; + tl3 = tl4 / (NIC_MAX_TL4 / NIC_MAX_TL3); nic_reg_write(nic, NIC_PF_QSET_0_127_SQ_0_7_CFG2 | ((u64)vnic << NIC_QS_ID_SHIFT) | @@ -489,6 +514,71 @@ static void nic_tx_channel_cfg(struct nicpf *nic, u8 vnic, u8 sq_idx) nic_reg_write(nic, NIC_PF_TL2_0_63_PRI | (tl2 << 3), 0x00); } +/* Send primary nicvf pointer to secondary QS's VF */ +static void nic_send_pnicvf(struct nicpf *nic, int sqs) +{ + union nic_mbx mbx = {}; + + mbx.nicvf.msg = NIC_MBOX_MSG_PNICVF_PTR; + mbx.nicvf.nicvf = nic->nicvf[nic->pqs_vf[sqs]]; + nic_send_msg_to_vf(nic, sqs, &mbx); +} + +/* Send SQS's nicvf pointer to primary QS's VF */ +static void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf) +{ + union nic_mbx mbx = {}; + int sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id]; + + mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR; + mbx.nicvf.sqs_id = nicvf->sqs_id; + mbx.nicvf.nicvf = nic->nicvf[sqs_id]; + nic_send_msg_to_vf(nic, nicvf->vf_id, &mbx); +} + +/* Find next available Qset that can be assigned as a + * secondary Qset to a VF. + */ +static int nic_nxt_avail_sqs(struct nicpf *nic) +{ + int sqs; + + for (sqs = 0; sqs < nic->num_sqs_en; sqs++) { + if (!nic->sqs_used[sqs]) + nic->sqs_used[sqs] = true; + else + continue; + return sqs + nic->num_vf_en; + } + return -1; +} + +/* Allocate additional Qsets for requested VF */ +static void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs) +{ + union nic_mbx mbx = {}; + int idx, alloc_qs = 0; + int sqs_id; + + if (!nic->num_sqs_en) + goto send_mbox; + + for (idx = 0; idx < sqs->qs_count; idx++) { + sqs_id = nic_nxt_avail_sqs(nic); + if (sqs_id < 0) + break; + nic->vf_sqs[sqs->vf_id][idx] = sqs_id; + nic->pqs_vf[sqs_id] = sqs->vf_id; + alloc_qs++; + } + +send_mbox: + mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS; + mbx.sqs_alloc.vf_id = sqs->vf_id; + mbx.sqs_alloc.qs_count = alloc_qs; + nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); +} + /* Interrupt handler to handle mailbox messages from VFs */ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) { @@ -496,6 +586,7 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) u64 *mbx_data; u64 mbx_addr; u64 reg_addr; + u64 cfg; int bgx, lmac; int i; int ret = 0; @@ -516,15 +607,24 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) switch (mbx.msg.msg) { case NIC_MBOX_MSG_READY: nic_mbx_send_ready(nic, vf); - nic->link[vf] = 0; - nic->duplex[vf] = 0; - nic->speed[vf] = 0; + if (vf < MAX_LMAC) { + nic->link[vf] = 0; + nic->duplex[vf] = 0; + nic->speed[vf] = 0; + } ret = 1; break; case NIC_MBOX_MSG_QS_CFG: reg_addr = NIC_PF_QSET_0_127_CFG | (mbx.qs.num << NIC_QS_ID_SHIFT); - nic_reg_write(nic, reg_addr, mbx.qs.cfg); + cfg = mbx.qs.cfg; + /* Check if its a secondary Qset */ + if (vf >= nic->num_vf_en) { + cfg = cfg & (~0x7FULL); + /* Assign this Qset to primary Qset's VF */ + cfg |= nic->pqs_vf[vf]; + } + nic_reg_write(nic, reg_addr, cfg); break; case NIC_MBOX_MSG_RQ_CFG: reg_addr = NIC_PF_QSET_0_127_RQ_0_7_CFG | @@ -552,9 +652,11 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) (mbx.sq.qs_num << NIC_QS_ID_SHIFT) | (mbx.sq.sq_num << NIC_Q_NUM_SHIFT); nic_reg_write(nic, reg_addr, mbx.sq.cfg); - nic_tx_channel_cfg(nic, mbx.qs.num, mbx.sq.sq_num); + nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq); break; case NIC_MBOX_MSG_SET_MAC: + if (vf >= nic->num_vf_en) + break; lmac = mbx.mac.vf_id; bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]); @@ -581,7 +683,22 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) case NIC_MBOX_MSG_SHUTDOWN: /* First msg in VF teardown sequence */ nic->vf_enabled[vf] = false; + if (vf >= nic->num_vf_en) + nic->sqs_used[vf - nic->num_vf_en] = false; + nic->pqs_vf[vf] = 0; + break; + case NIC_MBOX_MSG_ALLOC_SQS: + nic_alloc_sqs(nic, &mbx.sqs_alloc); + goto unlock; + case NIC_MBOX_MSG_NICVF_PTR: + nic->nicvf[vf] = mbx.nicvf.nicvf; break; + case NIC_MBOX_MSG_PNICVF_PTR: + nic_send_pnicvf(nic, vf); + goto unlock; + case NIC_MBOX_MSG_SNICVF_PTR: + nic_send_snicvf(nic, &mbx.nicvf); + goto unlock; case NIC_MBOX_MSG_BGX_STATS: nic_get_bgx_stats(nic, &mbx.bgx_stats); goto unlock; @@ -610,8 +727,7 @@ static void nic_mbx_intr_handler (struct nicpf *nic, int mbx) if (intr & (1ULL << vf)) { dev_dbg(&nic->pdev->dev, "Intr from VF %d\n", vf + (mbx * vf_per_mbx_reg)); - if ((vf + (mbx * vf_per_mbx_reg)) > nic->num_vf_en) - break; + nic_handle_mbx_intr(nic, vf + (mbx * vf_per_mbx_reg)); nic_clear_mbx_intr(nic, vf, mbx); } @@ -717,9 +833,24 @@ static void nic_unregister_interrupts(struct nicpf *nic) nic_disable_msix(nic); } +static int nic_num_sqs_en(struct nicpf *nic, int vf_en) +{ + int pos, sqs_per_vf = MAX_SQS_PER_VF_SINGLE_NODE; + u16 total_vf; + + /* Check if its a multi-node environment */ + if (nr_node_ids > 1) + sqs_per_vf = MAX_SQS_PER_VF; + + pos = pci_find_ext_capability(nic->pdev, PCI_EXT_CAP_ID_SRIOV); + pci_read_config_word(nic->pdev, (pos + PCI_SRIOV_TOTAL_VF), &total_vf); + return min(total_vf - vf_en, vf_en * sqs_per_vf); +} + static int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic) { int pos = 0; + int vf_en; int err; u16 total_vf_cnt; @@ -736,16 +867,20 @@ static int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic) if (!total_vf_cnt) return 0; - err = pci_enable_sriov(pdev, nic->num_vf_en); + vf_en = nic->num_vf_en; + nic->num_sqs_en = nic_num_sqs_en(nic, nic->num_vf_en); + vf_en += nic->num_sqs_en; + + err = pci_enable_sriov(pdev, vf_en); if (err) { dev_err(&pdev->dev, "SRIOV enable failed, num VF is %d\n", - nic->num_vf_en); + vf_en); nic->num_vf_en = 0; return err; } dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n", - nic->num_vf_en); + vf_en); nic->flags |= NIC_SRIOV_ENABLED; return 0; diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c index 1eec2cd657ffc..af54c10945c25 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_ethtool.c @@ -149,10 +149,33 @@ static void nicvf_set_msglevel(struct net_device *netdev, u32 lvl) nic->msg_enable = lvl; } +static void nicvf_get_qset_strings(struct nicvf *nic, u8 **data, int qset) +{ + int stats, qidx; + int start_qidx = qset * MAX_RCV_QUEUES_PER_QS; + + for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { + for (stats = 0; stats < nicvf_n_queue_stats; stats++) { + sprintf(*data, "rxq%d: %s", qidx + start_qidx, + nicvf_queue_stats[stats].name); + *data += ETH_GSTRING_LEN; + } + } + + for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { + for (stats = 0; stats < nicvf_n_queue_stats; stats++) { + sprintf(*data, "txq%d: %s", qidx + start_qidx, + nicvf_queue_stats[stats].name); + *data += ETH_GSTRING_LEN; + } + } +} + static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data) { struct nicvf *nic = netdev_priv(netdev); - int stats, qidx; + int stats; + int sqs; if (sset != ETH_SS_STATS) return; @@ -167,20 +190,12 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data) data += ETH_GSTRING_LEN; } - for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { - for (stats = 0; stats < nicvf_n_queue_stats; stats++) { - sprintf(data, "rxq%d: %s", qidx, - nicvf_queue_stats[stats].name); - data += ETH_GSTRING_LEN; - } - } + nicvf_get_qset_strings(nic, &data, 0); - for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { - for (stats = 0; stats < nicvf_n_queue_stats; stats++) { - sprintf(data, "txq%d: %s", qidx, - nicvf_queue_stats[stats].name); - data += ETH_GSTRING_LEN; - } + for (sqs = 0; sqs < nic->sqs_count; sqs++) { + if (!nic->snicvf[sqs]) + continue; + nicvf_get_qset_strings(nic->snicvf[sqs], &data, sqs + 1); } for (stats = 0; stats < BGX_RX_STATS_COUNT; stats++) { @@ -197,21 +212,58 @@ static void nicvf_get_strings(struct net_device *netdev, u32 sset, u8 *data) static int nicvf_get_sset_count(struct net_device *netdev, int sset) { struct nicvf *nic = netdev_priv(netdev); + int qstats_count; + int sqs; if (sset != ETH_SS_STATS) return -EINVAL; + qstats_count = nicvf_n_queue_stats * + (nic->qs->rq_cnt + nic->qs->sq_cnt); + for (sqs = 0; sqs < nic->sqs_count; sqs++) { + struct nicvf *snic; + + snic = nic->snicvf[sqs]; + if (!snic) + continue; + qstats_count += nicvf_n_queue_stats * + (snic->qs->rq_cnt + snic->qs->sq_cnt); + } + return nicvf_n_hw_stats + nicvf_n_drv_stats + - (nicvf_n_queue_stats * - (nic->qs->rq_cnt + nic->qs->sq_cnt)) + + qstats_count + BGX_RX_STATS_COUNT + BGX_TX_STATS_COUNT; } +static void nicvf_get_qset_stats(struct nicvf *nic, + struct ethtool_stats *stats, u64 **data) +{ + int stat, qidx; + + if (!nic) + return; + + for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { + nicvf_update_rq_stats(nic, qidx); + for (stat = 0; stat < nicvf_n_queue_stats; stat++) + *((*data)++) = ((u64 *)&nic->qs->rq[qidx].stats) + [nicvf_queue_stats[stat].index]; + } + + for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { + nicvf_update_sq_stats(nic, qidx); + for (stat = 0; stat < nicvf_n_queue_stats; stat++) + *((*data)++) = ((u64 *)&nic->qs->sq[qidx].stats) + [nicvf_queue_stats[stat].index]; + } +} + static void nicvf_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { struct nicvf *nic = netdev_priv(netdev); - int stat, qidx; + int stat; + int sqs; nicvf_update_stats(nic); @@ -225,16 +277,12 @@ static void nicvf_get_ethtool_stats(struct net_device *netdev, *(data++) = ((u64 *)&nic->drv_stats) [nicvf_drv_stats[stat].index]; - for (qidx = 0; qidx < nic->qs->rq_cnt; qidx++) { - for (stat = 0; stat < nicvf_n_queue_stats; stat++) - *(data++) = ((u64 *)&nic->qs->rq[qidx].stats) - [nicvf_queue_stats[stat].index]; - } + nicvf_get_qset_stats(nic, stats, &data); - for (qidx = 0; qidx < nic->qs->sq_cnt; qidx++) { - for (stat = 0; stat < nicvf_n_queue_stats; stat++) - *(data++) = ((u64 *)&nic->qs->sq[qidx].stats) - [nicvf_queue_stats[stat].index]; + for (sqs = 0; sqs < nic->sqs_count; sqs++) { + if (!nic->snicvf[sqs]) + continue; + nicvf_get_qset_stats(nic->snicvf[sqs], stats, &data); } for (stat = 0; stat < BGX_RX_STATS_COUNT; stat++) @@ -393,7 +441,7 @@ static int nicvf_get_rxnfc(struct net_device *dev, switch (info->cmd) { case ETHTOOL_GRXRINGS: - info->data = nic->qs->rq_cnt; + info->data = nic->rx_queues; ret = 0; break; case ETHTOOL_GRXFH: @@ -556,11 +604,11 @@ static void nicvf_get_channels(struct net_device *dev, memset(channel, 0, sizeof(*channel)); - channel->max_rx = MAX_RCV_QUEUES_PER_QS; - channel->max_tx = MAX_SND_QUEUES_PER_QS; + channel->max_rx = nic->max_queues; + channel->max_tx = nic->max_queues; - channel->rx_count = nic->qs->rq_cnt; - channel->tx_count = nic->qs->sq_cnt; + channel->rx_count = nic->rx_queues; + channel->tx_count = nic->tx_queues; } /* Set no of Tx, Rx queues to be used */ @@ -570,22 +618,34 @@ static int nicvf_set_channels(struct net_device *dev, struct nicvf *nic = netdev_priv(dev); int err = 0; bool if_up = netif_running(dev); + int cqcount; if (!channel->rx_count || !channel->tx_count) return -EINVAL; - if (channel->rx_count > MAX_RCV_QUEUES_PER_QS) + if (channel->rx_count > nic->max_queues) return -EINVAL; - if (channel->tx_count > MAX_SND_QUEUES_PER_QS) + if (channel->tx_count > nic->max_queues) return -EINVAL; if (if_up) nicvf_stop(dev); - nic->qs->rq_cnt = channel->rx_count; - nic->qs->sq_cnt = channel->tx_count; + cqcount = max(channel->rx_count, channel->tx_count); + + if (cqcount > MAX_CMP_QUEUES_PER_QS) { + nic->sqs_count = roundup(cqcount, MAX_CMP_QUEUES_PER_QS); + nic->sqs_count = (nic->sqs_count / MAX_CMP_QUEUES_PER_QS) - 1; + } else { + nic->sqs_count = 0; + } + + nic->qs->rq_cnt = min_t(u32, channel->rx_count, MAX_RCV_QUEUES_PER_QS); + nic->qs->sq_cnt = min_t(u32, channel->tx_count, MAX_SND_QUEUES_PER_QS); nic->qs->cq_cnt = max(nic->qs->rq_cnt, nic->qs->sq_cnt); - err = nicvf_set_real_num_queues(dev, nic->qs->sq_cnt, nic->qs->rq_cnt); + nic->rx_queues = channel->rx_count; + nic->tx_queues = channel->tx_count; + err = nicvf_set_real_num_queues(dev, nic->tx_queues, nic->rx_queues); if (err) return err; @@ -593,7 +653,7 @@ static int nicvf_set_channels(struct net_device *dev, nicvf_open(dev); netdev_info(dev, "Setting num Tx rings to %d, Rx rings to %d success\n", - nic->qs->sq_cnt, nic->qs->rq_cnt); + nic->tx_queues, nic->rx_queues); return err; } diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 85213f38ceb0f..68b2dce9229da 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -51,6 +51,14 @@ module_param(cpi_alg, int, S_IRUGO); MODULE_PARM_DESC(cpi_alg, "PFC algorithm (0=none, 1=VLAN, 2=VLAN16, 3=IP Diffserv)"); +static inline u8 nicvf_netdev_qidx(struct nicvf *nic, u8 qidx) +{ + if (nic->sqs_mode) + return qidx + ((nic->sqs_id + 1) * MAX_CMP_QUEUES_PER_QS); + else + return qidx; +} + static inline void nicvf_set_rx_frame_cnt(struct nicvf *nic, struct sk_buff *skb) { @@ -193,6 +201,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) if (!nic->set_mac_pending) ether_addr_copy(nic->netdev->dev_addr, mbx.nic_cfg.mac_addr); + nic->sqs_mode = mbx.nic_cfg.sqs_mode; nic->link_up = false; nic->duplex = 0; nic->speed = 0; @@ -230,6 +239,26 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) netif_tx_stop_all_queues(nic->netdev); } break; + case NIC_MBOX_MSG_ALLOC_SQS: + nic->sqs_count = mbx.sqs_alloc.qs_count; + nic->pf_acked = true; + break; + case NIC_MBOX_MSG_SNICVF_PTR: + /* Primary VF: make note of secondary VF's pointer + * to be used while packet transmission. + */ + nic->snicvf[mbx.nicvf.sqs_id] = + (struct nicvf *)mbx.nicvf.nicvf; + nic->pf_acked = true; + break; + case NIC_MBOX_MSG_PNICVF_PTR: + /* Secondary VF/Qset: make note of primary VF's pointer + * to be used while packet reception, to handover packet + * to primary VF's netdev. + */ + nic->pnicvf = (struct nicvf *)mbx.nicvf.nicvf; + nic->pf_acked = true; + break; default: netdev_err(nic->netdev, "Invalid message from PF, msg 0x%x\n", mbx.msg.msg); @@ -338,11 +367,100 @@ static int nicvf_rss_init(struct nicvf *nic) for (idx = 0; idx < rss->rss_size; idx++) rss->ind_tbl[idx] = ethtool_rxfh_indir_default(idx, - nic->qs->rq_cnt); + nic->rx_queues); nicvf_config_rss(nic); return 1; } +/* Request PF to allocate additional Qsets */ +static void nicvf_request_sqs(struct nicvf *nic) +{ + union nic_mbx mbx = {}; + int sqs; + int sqs_count = nic->sqs_count; + int rx_queues = 0, tx_queues = 0; + + /* Only primary VF should request */ + if (nic->sqs_mode || !nic->sqs_count) + return; + + mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS; + mbx.sqs_alloc.vf_id = nic->vf_id; + mbx.sqs_alloc.qs_count = nic->sqs_count; + if (nicvf_send_msg_to_pf(nic, &mbx)) { + /* No response from PF */ + nic->sqs_count = 0; + return; + } + + /* Return if no Secondary Qsets available */ + if (!nic->sqs_count) + return; + + if (nic->rx_queues > MAX_RCV_QUEUES_PER_QS) + rx_queues = nic->rx_queues - MAX_RCV_QUEUES_PER_QS; + if (nic->tx_queues > MAX_SND_QUEUES_PER_QS) + tx_queues = nic->tx_queues - MAX_SND_QUEUES_PER_QS; + + /* Set no of Rx/Tx queues in each of the SQsets */ + for (sqs = 0; sqs < nic->sqs_count; sqs++) { + mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR; + mbx.nicvf.vf_id = nic->vf_id; + mbx.nicvf.sqs_id = sqs; + nicvf_send_msg_to_pf(nic, &mbx); + + nic->snicvf[sqs]->sqs_id = sqs; + if (rx_queues > MAX_RCV_QUEUES_PER_QS) { + nic->snicvf[sqs]->qs->rq_cnt = MAX_RCV_QUEUES_PER_QS; + rx_queues -= MAX_RCV_QUEUES_PER_QS; + } else { + nic->snicvf[sqs]->qs->rq_cnt = rx_queues; + rx_queues = 0; + } + + if (tx_queues > MAX_SND_QUEUES_PER_QS) { + nic->snicvf[sqs]->qs->sq_cnt = MAX_SND_QUEUES_PER_QS; + tx_queues -= MAX_SND_QUEUES_PER_QS; + } else { + nic->snicvf[sqs]->qs->sq_cnt = tx_queues; + tx_queues = 0; + } + + nic->snicvf[sqs]->qs->cq_cnt = + max(nic->snicvf[sqs]->qs->rq_cnt, nic->snicvf[sqs]->qs->sq_cnt); + + /* Initialize secondary Qset's queues and its interrupts */ + nicvf_open(nic->snicvf[sqs]->netdev); + } + + /* Update stack with actual Rx/Tx queue count allocated */ + if (sqs_count != nic->sqs_count) + nicvf_set_real_num_queues(nic->netdev, + nic->tx_queues, nic->rx_queues); +} + +/* Send this Qset's nicvf pointer to PF. + * PF inturn sends primary VF's nicvf struct to secondary Qsets/VFs + * so that packets received by these Qsets can use primary VF's netdev + */ +static void nicvf_send_vf_struct(struct nicvf *nic) +{ + union nic_mbx mbx = {}; + + mbx.nicvf.msg = NIC_MBOX_MSG_NICVF_PTR; + mbx.nicvf.sqs_mode = nic->sqs_mode; + mbx.nicvf.nicvf = (u64)nic; + nicvf_send_msg_to_pf(nic, &mbx); +} + +static void nicvf_get_primary_vf_struct(struct nicvf *nic) +{ + union nic_mbx mbx = {}; + + mbx.nicvf.msg = NIC_MBOX_MSG_PNICVF_PTR; + nicvf_send_msg_to_pf(nic, &mbx); +} + int nicvf_set_real_num_queues(struct net_device *netdev, int tx_queues, int rx_queues) { @@ -453,6 +571,15 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, struct sk_buff *skb; struct nicvf *nic = netdev_priv(netdev); int err = 0; + int rq_idx; + + rq_idx = nicvf_netdev_qidx(nic, cqe_rx->rq_idx); + + if (nic->sqs_mode) { + /* Use primary VF's 'nicvf' struct */ + nic = nic->pnicvf; + netdev = nic->netdev; + } /* Check for errors */ err = nicvf_check_cqe_rx_errs(nic, cq, cqe_rx); @@ -482,7 +609,7 @@ static void nicvf_rcv_pkt_handler(struct net_device *netdev, nicvf_set_rxhash(netdev, cqe_rx, skb); - skb_record_rx_queue(skb, cqe_rx->rq_idx); + skb_record_rx_queue(skb, rq_idx); if (netdev->hw_features & NETIF_F_RXCSUM) { /* HW by default verifies TCP/UDP/SCTP checksums */ skb->ip_summed = CHECKSUM_UNNECESSARY; @@ -578,8 +705,11 @@ loop: done: /* Wakeup TXQ if its stopped earlier due to SQ full */ if (tx_done) { - txq = netdev_get_tx_queue(netdev, cq_idx); - if (netif_tx_queue_stopped(txq)) { + netdev = nic->pnicvf->netdev; + txq = netdev_get_tx_queue(netdev, + nicvf_netdev_qidx(nic, cq_idx)); + nic = nic->pnicvf; + if (netif_tx_queue_stopped(txq) && netif_carrier_ok(netdev)) { netif_tx_start_queue(txq); nic->drv_stats.txq_wake++; if (netif_msg_tx_err(nic)) @@ -893,7 +1023,6 @@ static netdev_tx_t nicvf_xmit(struct sk_buff *skb, struct net_device *netdev) netdev_warn(netdev, "%s: Transmit ring full, stopping SQ%d\n", netdev->name, qid); - return NETDEV_TX_BUSY; } @@ -926,6 +1055,17 @@ int nicvf_stop(struct net_device *netdev) nicvf_send_msg_to_pf(nic, &mbx); netif_carrier_off(netdev); + netif_tx_stop_all_queues(nic->netdev); + + /* Teardown secondary qsets first */ + if (!nic->sqs_mode) { + for (qidx = 0; qidx < nic->sqs_count; qidx++) { + if (!nic->snicvf[qidx]) + continue; + nicvf_stop(nic->snicvf[qidx]->netdev); + nic->snicvf[qidx] = NULL; + } + } /* Disable RBDR & QS error interrupts */ for (qidx = 0; qidx < qs->rbdr_cnt; qidx++) { @@ -973,6 +1113,10 @@ int nicvf_stop(struct net_device *netdev) nicvf_free_cq_poll(nic); + /* Clear multiqset info */ + nic->pnicvf = nic; + nic->sqs_count = 0; + return 0; } @@ -1028,10 +1172,16 @@ int nicvf_open(struct net_device *netdev) /* Configure CPI alorithm */ nic->cpi_alg = cpi_alg; - nicvf_config_cpi(nic); + if (!nic->sqs_mode) + nicvf_config_cpi(nic); + + nicvf_request_sqs(nic); + if (nic->sqs_mode) + nicvf_get_primary_vf_struct(nic); /* Configure receive side scaling */ - nicvf_rss_init(nic); + if (!nic->sqs_mode) + nicvf_rss_init(nic); err = nicvf_register_interrupts(nic); if (err) @@ -1282,8 +1432,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct device *dev = &pdev->dev; struct net_device *netdev; struct nicvf *nic; - struct queue_set *qs; - int err; + int err, qcount; err = pci_enable_device(pdev); if (err) { @@ -1309,9 +1458,17 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_release_regions; } - netdev = alloc_etherdev_mqs(sizeof(struct nicvf), - MAX_RCV_QUEUES_PER_QS, - MAX_SND_QUEUES_PER_QS); + qcount = MAX_CMP_QUEUES_PER_QS; + + /* Restrict multiqset support only for host bound VFs */ + if (pdev->is_virtfn) { + /* Set max number of queues per VF */ + qcount = roundup(num_online_cpus(), MAX_CMP_QUEUES_PER_QS); + qcount = min(qcount, + (MAX_SQS_PER_VF + 1) * MAX_CMP_QUEUES_PER_QS); + } + + netdev = alloc_etherdev_mqs(sizeof(struct nicvf), qcount, qcount); if (!netdev) { err = -ENOMEM; goto err_release_regions; @@ -1324,6 +1481,8 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) nic = netdev_priv(netdev); nic->netdev = netdev; nic->pdev = pdev; + nic->pnicvf = nic; + nic->max_queues = qcount; /* MAP VF's configuration registers */ nic->reg_base = pcim_iomap(pdev, PCI_CFG_REG_BAR_NUM, 0); @@ -1337,20 +1496,26 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto err_free_netdev; - qs = nic->qs; - - err = nicvf_set_real_num_queues(netdev, qs->sq_cnt, qs->rq_cnt); - if (err) - goto err_free_netdev; - /* Check if PF is alive and get MAC address for this VF */ err = nicvf_register_misc_interrupt(nic); if (err) goto err_free_netdev; + nicvf_send_vf_struct(nic); + + /* Check if this VF is in QS only mode */ + if (nic->sqs_mode) + return 0; + + err = nicvf_set_real_num_queues(netdev, nic->tx_queues, nic->rx_queues); + if (err) + goto err_unregister_interrupts; + netdev->hw_features = (NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_TSO | NETIF_F_GRO | - NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_RXHASH); + NETIF_F_HW_VLAN_CTAG_RX); + + netdev->hw_features |= NETIF_F_RXHASH; netdev->features |= netdev->hw_features; @@ -1389,8 +1554,13 @@ static void nicvf_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct nicvf *nic = netdev_priv(netdev); + struct net_device *pnetdev = nic->pnicvf->netdev; - unregister_netdev(netdev); + /* Check if this Qset is assigned to different VF. + * If yes, clean primary and all secondary Qsets. + */ + if (pnetdev && (pnetdev->reg_state == NETREG_REGISTERED)) + unregister_netdev(pnetdev); nicvf_unregister_interrupts(nic); pci_set_drvdata(pdev, NULL); free_netdev(netdev); diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c index b294d67d48e4a..e404ea837727e 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_queues.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_queues.c @@ -621,6 +621,7 @@ static void nicvf_snd_queue_config(struct nicvf *nic, struct queue_set *qs, mbx.sq.msg = NIC_MBOX_MSG_SQ_CFG; mbx.sq.qs_num = qs->vnic_id; mbx.sq.sq_num = qidx; + mbx.sq.sqs_mode = nic->sqs_mode; mbx.sq.cfg = (sq->cq_qs << 3) | sq->cq_idx; nicvf_send_msg_to_pf(nic, &mbx); @@ -702,6 +703,7 @@ void nicvf_qset_config(struct nicvf *nic, bool enable) /* Send a mailbox msg to PF to config Qset */ mbx.qs.msg = NIC_MBOX_MSG_QS_CFG; mbx.qs.num = qs->vnic_id; + mbx.qs.sqs_count = nic->sqs_count; mbx.qs.cfg = 0; qs_cfg = (struct qs_cfg *)&mbx.qs.cfg; @@ -782,6 +784,10 @@ int nicvf_set_qset_resources(struct nicvf *nic) qs->rbdr_len = RCV_BUF_COUNT; qs->sq_len = SND_QUEUE_LEN; qs->cq_len = CMP_QUEUE_LEN; + + nic->rx_queues = qs->rq_cnt; + nic->tx_queues = qs->sq_cnt; + return 0; } @@ -1025,7 +1031,7 @@ static inline void nicvf_sq_add_gather_subdesc(struct snd_queue *sq, int qentry, * them to SQ for transfer */ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq, - int qentry, struct sk_buff *skb) + int sq_num, int qentry, struct sk_buff *skb) { struct tso_t tso; int seg_subdescs = 0, desc_cnt = 0; @@ -1085,7 +1091,7 @@ static int nicvf_sq_append_tso(struct nicvf *nic, struct snd_queue *sq, /* Inform HW to xmit all TSO segments */ nicvf_queue_reg_write(nic, NIC_QSET_SQ_0_7_DOOR, - skb_get_queue_mapping(skb), desc_cnt); + sq_num, desc_cnt); nic->drv_stats.tx_tso++; return 1; } @@ -1096,10 +1102,24 @@ int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb) int i, size; int subdesc_cnt; int sq_num, qentry; - struct queue_set *qs = nic->qs; + struct queue_set *qs; struct snd_queue *sq; sq_num = skb_get_queue_mapping(skb); + if (sq_num >= MAX_SND_QUEUES_PER_QS) { + /* Get secondary Qset's SQ structure */ + i = sq_num / MAX_SND_QUEUES_PER_QS; + if (!nic->snicvf[i - 1]) { + netdev_warn(nic->netdev, + "Secondary Qset#%d's ptr not initialized\n", + i - 1); + return 1; + } + nic = (struct nicvf *)nic->snicvf[i - 1]; + sq_num = sq_num % MAX_SND_QUEUES_PER_QS; + } + + qs = nic->qs; sq = &qs->sq[sq_num]; subdesc_cnt = nicvf_sq_subdesc_required(nic, skb); @@ -1110,7 +1130,7 @@ int nicvf_sq_append_skb(struct nicvf *nic, struct sk_buff *skb) /* Check if its a TSO packet */ if (skb_shinfo(skb)->gso_size) - return nicvf_sq_append_tso(nic, sq, qentry, skb); + return nicvf_sq_append_tso(nic, sq, sq_num, qentry, skb); /* Add SQ header subdesc */ nicvf_sq_add_hdr_subdesc(sq, qentry, subdesc_cnt - 1, skb, skb->len); @@ -1146,6 +1166,8 @@ doorbell: return 1; append_fail: + /* Use original PCI dev for debug log */ + nic = nic->pnicvf; netdev_dbg(nic->netdev, "Not enough SQ descriptors to xmit pkt\n"); return 0; } -- GitLab From d77a2384988fd397cf4f71417b9d971aa435758d Mon Sep 17 00:00:00 2001 From: Sunil Goutham Date: Sun, 30 Aug 2015 12:29:16 +0300 Subject: [PATCH 5861/7006] net: thunderx: Support for internal loopback mode Support for setting VF's corresponding BGX LMAC in internal loopback mode. This mode can be used for verifying basic HW functionality such as packet I/O, RX checksum validation, CQ/RBDR interrupts, stats e.t.c. Useful when DUT has no external network connectivity. 'loopback' mode can be enabled or disabled via ethtool. Note: This feature is not supported when no of VFs enabled are morethan no of physical interfaces i.e active BGX LMACs Signed-off-by: Sunil Goutham Signed-off-by: Aleksey Makarov Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/thunder/nic.h | 11 +++++++ .../net/ethernet/cavium/thunder/nic_main.c | 21 +++++++++++++ .../net/ethernet/cavium/thunder/nicvf_main.c | 30 ++++++++++++++++++ .../net/ethernet/cavium/thunder/thunder_bgx.c | 31 +++++++++++++++++++ .../net/ethernet/cavium/thunder/thunder_bgx.h | 4 +++ 5 files changed, 97 insertions(+) diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h index 35b2ee1bc07ed..d3950b20feb9e 100644 --- a/drivers/net/ethernet/cavium/thunder/nic.h +++ b/drivers/net/ethernet/cavium/thunder/nic.h @@ -265,6 +265,7 @@ struct nicvf { u8 node; u8 tns_mode:1; u8 sqs_mode:1; + u8 loopback_supported:1; u16 mtu; struct queue_set *qs; #define MAX_SQS_PER_VF_SINGLE_NODE 5 @@ -344,6 +345,7 @@ struct nicvf { #define NIC_MBOX_MSG_NICVF_PTR 0x13 /* Send nicvf ptr to PF */ #define NIC_MBOX_MSG_PNICVF_PTR 0x14 /* Get primary qset nicvf ptr */ #define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */ +#define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */ #define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */ #define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */ @@ -353,6 +355,7 @@ struct nic_cfg_msg { u8 node_id; u8 tns_mode:1; u8 sqs_mode:1; + u8 loopback_supported:1; u8 mac_addr[ETH_ALEN]; }; @@ -452,6 +455,13 @@ struct nicvf_ptr { u64 nicvf; }; +/* Set interface in loopback mode */ +struct set_loopback { + u8 msg; + u8 vf_id; + bool enable; +}; + /* 128 bit shared memory between PF and each VF */ union nic_mbx { struct { u8 msg; } msg; @@ -468,6 +478,7 @@ union nic_mbx { struct bgx_link_status link_status; struct sqs_alloc sqs_alloc; struct nicvf_ptr nicvf; + struct set_loopback lbk; }; #define NIC_NODE_ID_MASK 0x03 diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c index dac80943a7820..b3a5947a2cc03 100644 --- a/drivers/net/ethernet/cavium/thunder/nic_main.c +++ b/drivers/net/ethernet/cavium/thunder/nic_main.c @@ -154,6 +154,9 @@ static void nic_mbx_send_ready(struct nicpf *nic, int vf) } mbx.nic_cfg.sqs_mode = (vf >= nic->num_vf_en) ? true : false; mbx.nic_cfg.node_id = nic->node; + + mbx.nic_cfg.loopback_supported = vf < MAX_LMAC; + nic_send_msg_to_vf(nic, vf, &mbx); } @@ -579,6 +582,21 @@ send_mbox: nic_send_msg_to_vf(nic, sqs->vf_id, &mbx); } +static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk) +{ + int bgx_idx, lmac_idx; + + if (lbk->vf_id > MAX_LMAC) + return -1; + + bgx_idx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); + lmac_idx = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lbk->vf_id]); + + bgx_lmac_internal_loopback(nic->node, bgx_idx, lmac_idx, lbk->enable); + + return 0; +} + /* Interrupt handler to handle mailbox messages from VFs */ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) { @@ -702,6 +720,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf) case NIC_MBOX_MSG_BGX_STATS: nic_get_bgx_stats(nic, &mbx.bgx_stats); goto unlock; + case NIC_MBOX_MSG_LOOPBACK: + ret = nic_config_loopback(nic, &mbx.lbk); + break; default: dev_err(&nic->pdev->dev, "Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg); diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c index 68b2dce9229da..b63e579aeb12d 100644 --- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c +++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c @@ -202,6 +202,7 @@ static void nicvf_handle_mbx_intr(struct nicvf *nic) ether_addr_copy(nic->netdev->dev_addr, mbx.nic_cfg.mac_addr); nic->sqs_mode = mbx.nic_cfg.sqs_mode; + nic->loopback_supported = mbx.nic_cfg.loopback_supported; nic->link_up = false; nic->duplex = 0; nic->speed = 0; @@ -1404,6 +1405,30 @@ static void nicvf_reset_task(struct work_struct *work) nic->netdev->trans_start = jiffies; } +static int nicvf_config_loopback(struct nicvf *nic, + netdev_features_t features) +{ + union nic_mbx mbx = {}; + + mbx.lbk.msg = NIC_MBOX_MSG_LOOPBACK; + mbx.lbk.vf_id = nic->vf_id; + mbx.lbk.enable = (features & NETIF_F_LOOPBACK) != 0; + + return nicvf_send_msg_to_pf(nic, &mbx); +} + +static netdev_features_t nicvf_fix_features(struct net_device *netdev, + netdev_features_t features) +{ + struct nicvf *nic = netdev_priv(netdev); + + if ((features & NETIF_F_LOOPBACK) && + netif_running(netdev) && !nic->loopback_supported) + features &= ~NETIF_F_LOOPBACK; + + return features; +} + static int nicvf_set_features(struct net_device *netdev, netdev_features_t features) { @@ -1413,6 +1438,9 @@ static int nicvf_set_features(struct net_device *netdev, if (changed & NETIF_F_HW_VLAN_CTAG_RX) nicvf_config_vlan_stripping(nic, features); + if ((changed & NETIF_F_LOOPBACK) && netif_running(netdev)) + return nicvf_config_loopback(nic, features); + return 0; } @@ -1424,6 +1452,7 @@ static const struct net_device_ops nicvf_netdev_ops = { .ndo_set_mac_address = nicvf_set_mac_address, .ndo_get_stats64 = nicvf_get_stats64, .ndo_tx_timeout = nicvf_tx_timeout, + .ndo_fix_features = nicvf_fix_features, .ndo_set_features = nicvf_set_features, }; @@ -1518,6 +1547,7 @@ static int nicvf_probe(struct pci_dev *pdev, const struct pci_device_id *ent) netdev->hw_features |= NETIF_F_RXHASH; netdev->features |= netdev->hw_features; + netdev->hw_features |= NETIF_F_LOOPBACK; netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO; diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c index 5e541862f65e5..574c492789009 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.c +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.c @@ -329,6 +329,37 @@ static void bgx_flush_dmac_addrs(struct bgx *bgx, int lmac) } } +/* Configure BGX LMAC in internal loopback mode */ +void bgx_lmac_internal_loopback(int node, int bgx_idx, + int lmac_idx, bool enable) +{ + struct bgx *bgx; + struct lmac *lmac; + u64 cfg; + + bgx = bgx_vnic[(node * MAX_BGX_PER_CN88XX) + bgx_idx]; + if (!bgx) + return; + + lmac = &bgx->lmac[lmac_idx]; + if (lmac->is_sgmii) { + cfg = bgx_reg_read(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL); + if (enable) + cfg |= PCS_MRX_CTL_LOOPBACK1; + else + cfg &= ~PCS_MRX_CTL_LOOPBACK1; + bgx_reg_write(bgx, lmac_idx, BGX_GMP_PCS_MRX_CTL, cfg); + } else { + cfg = bgx_reg_read(bgx, lmac_idx, BGX_SPUX_CONTROL1); + if (enable) + cfg |= SPU_CTL_LOOPBACK; + else + cfg &= ~SPU_CTL_LOOPBACK; + bgx_reg_write(bgx, lmac_idx, BGX_SPUX_CONTROL1, cfg); + } +} +EXPORT_SYMBOL(bgx_lmac_internal_loopback); + static int bgx_lmac_sgmii_init(struct bgx *bgx, int lmacid) { u64 cfg; diff --git a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h index ba4f53b7cc2c1..07b7ec66c60db 100644 --- a/drivers/net/ethernet/cavium/thunder/thunder_bgx.h +++ b/drivers/net/ethernet/cavium/thunder/thunder_bgx.h @@ -72,6 +72,7 @@ #define BGX_SPUX_CONTROL1 0x10000 #define SPU_CTL_LOW_POWER BIT_ULL(11) +#define SPU_CTL_LOOPBACK BIT_ULL(14) #define SPU_CTL_RESET BIT_ULL(15) #define BGX_SPUX_STATUS1 0x10008 #define SPU_STATUS1_RCV_LNK BIT_ULL(2) @@ -126,6 +127,7 @@ #define PCS_MRX_CTL_RST_AN BIT_ULL(9) #define PCS_MRX_CTL_PWR_DN BIT_ULL(11) #define PCS_MRX_CTL_AN_EN BIT_ULL(12) +#define PCS_MRX_CTL_LOOPBACK1 BIT_ULL(14) #define PCS_MRX_CTL_RESET BIT_ULL(15) #define BGX_GMP_PCS_MRX_STATUS 0x30008 #define PCS_MRX_STATUS_AN_CPT BIT_ULL(5) @@ -186,6 +188,8 @@ int bgx_get_lmac_count(int node, int bgx); const u8 *bgx_get_lmac_mac(int node, int bgx_idx, int lmacid); void bgx_set_lmac_mac(int node, int bgx_idx, int lmacid, const u8 *mac); void bgx_get_lmac_link_state(int node, int bgx_idx, int lmacid, void *status); +void bgx_lmac_internal_loopback(int node, int bgx_idx, + int lmac_idx, bool enable); u64 bgx_get_rx_stats(int node, int bgx_idx, int lmac, int idx); u64 bgx_get_tx_stats(int node, int bgx_idx, int lmac, int idx); #define BGX_RX_STATS_COUNT 11 -- GitLab From 0ef707700f1cef2357ce655fc86a4de5e41fa4b5 Mon Sep 17 00:00:00 2001 From: Ken-ichirou MATSUZAWA Date: Mon, 31 Aug 2015 07:54:49 +0900 Subject: [PATCH 5862/7006] netlink: rx mmap: fix POLLIN condition Poll() returns immediately after setting the kernel current frame (ring->head) to SKIP from user space even though there is no new frame. And in a case of all frames is VALID, user space program unintensionally sets (only) kernel current frame to UNUSED, then calls poll(), it will not return immediately even though there are VALID frames. To avoid situations like above, I think we need to scan all frames to find VALID frames at poll() like netlink_alloc_skb(), netlink_forward_ring() finding an UNUSED frame at skb allocation. Signed-off-by: Ken-ichirou MATSUZAWA Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 7965ca7c461d3..50889be1517d0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -594,16 +594,6 @@ netlink_current_frame(const struct netlink_ring *ring, return netlink_lookup_frame(ring, ring->head, status); } -static struct nl_mmap_hdr * -netlink_previous_frame(const struct netlink_ring *ring, - enum nl_mmap_status status) -{ - unsigned int prev; - - prev = ring->head ? ring->head - 1 : ring->frame_max; - return netlink_lookup_frame(ring, prev, status); -} - static void netlink_increment_head(struct netlink_ring *ring) { ring->head = ring->head != ring->frame_max ? ring->head + 1 : 0; @@ -624,6 +614,21 @@ static void netlink_forward_ring(struct netlink_ring *ring) } while (ring->head != head); } +static bool netlink_has_valid_frame(struct netlink_ring *ring) +{ + unsigned int head = ring->head, pos = head; + const struct nl_mmap_hdr *hdr; + + do { + hdr = __netlink_lookup_frame(ring, pos); + if (hdr->nm_status == NL_MMAP_STATUS_VALID) + return true; + pos = pos != 0 ? pos - 1 : ring->frame_max; + } while (pos != head); + + return false; +} + static bool netlink_dump_space(struct netlink_sock *nlk) { struct netlink_ring *ring = &nlk->rx_ring; @@ -671,8 +676,7 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, spin_lock_bh(&sk->sk_receive_queue.lock); if (nlk->rx_ring.pg_vec) { - netlink_forward_ring(&nlk->rx_ring); - if (!netlink_previous_frame(&nlk->rx_ring, NL_MMAP_STATUS_UNUSED)) + if (netlink_has_valid_frame(&nlk->rx_ring)) mask |= POLLIN | POLLRDNORM; } spin_unlock_bh(&sk->sk_receive_queue.lock); -- GitLab From 80ec1927b102480f89436e7d7f961a263e916a44 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Sun, 30 Aug 2015 22:40:44 -0700 Subject: [PATCH 5863/7006] ipv4: Fix 32-bit build. net/ipv4/af_inet.c: In function 'snmp_get_cpu_field64': >> net/ipv4/af_inet.c:1486:26: error: 'offt' undeclared (first use in this function) v = *(((u64 *)bhptr) + offt); ^ net/ipv4/af_inet.c:1486:26: note: each undeclared identifier is reported only once for each function it appears in net/ipv4/af_inet.c: In function 'snmp_fold_field64': >> net/ipv4/af_inet.c:1499:39: error: 'offct' undeclared (first use in this function) res += snmp_get_cpu_field(mib, cpu, offct, syncp_offset); ^ >> net/ipv4/af_inet.c:1499:10: error: too many arguments to function 'snmp_get_cpu_field' res += snmp_get_cpu_field(mib, cpu, offct, syncp_offset); ^ net/ipv4/af_inet.c:1455:5: note: declared here u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offt) ^ Reported-by: kbuild test robot Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 0c69c0bbe1a12..c2d0ebc628d7a 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1471,7 +1471,7 @@ EXPORT_SYMBOL_GPL(snmp_fold_field); #if BITS_PER_LONG==32 -u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offct, +u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offt, size_t syncp_offset) { void *bhptr; @@ -1496,7 +1496,7 @@ u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_offset) int cpu; for_each_possible_cpu(cpu) { - res += snmp_get_cpu_field(mib, cpu, offct, syncp_offset); + res += snmp_get_cpu_field(mib, cpu, offt, syncp_offset); } return res; } -- GitLab From 01e2dae991771adb1257eb5cd3cecfda1aa09ba9 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 31 Aug 2015 08:56:04 +0200 Subject: [PATCH 5864/7006] Revert "gpio: extraxfs: fix returnvar.cocci warnings" This reverts commit 5e22ec019823b0204720e1ad9a5866c638332b3a. --- drivers/gpio/gpio-etraxfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpio/gpio-etraxfs.c b/drivers/gpio/gpio-etraxfs.c index ca33bda8ec555..2ffcd9fdd1f2f 100644 --- a/drivers/gpio/gpio-etraxfs.c +++ b/drivers/gpio/gpio-etraxfs.c @@ -292,6 +292,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d) struct etraxfs_gpio_chip *chip = irq_data_get_irq_chip_data(d); struct etraxfs_gpio_block *block = chip->block; unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq); + int ret = -EBUSY; spin_lock(&block->lock); if (block->group[grpirq]) @@ -313,7 +314,7 @@ static int etraxfs_gpio_irq_request_resources(struct irq_data *d) out: spin_unlock(&block->lock); - return -EBUSY; + return ret; } static void etraxfs_gpio_irq_release_resources(struct irq_data *d) -- GitLab From 71f8a4b81d040b3d094424197ca2f1bf811b1245 Mon Sep 17 00:00:00 2001 From: Jialing Fu Date: Fri, 28 Aug 2015 11:13:09 +0800 Subject: [PATCH 5865/7006] mmc: core: fix race condition in mmc_wait_data_done The following panic is captured in ker3.14, but the issue still exists in latest kernel. --------------------------------------------------------------------- [ 20.738217] c0 3136 (Compiler) Unable to handle kernel NULL pointer dereference at virtual address 00000578 ...... [ 20.738499] c0 3136 (Compiler) PC is at _raw_spin_lock_irqsave+0x24/0x60 [ 20.738527] c0 3136 (Compiler) LR is at _raw_spin_lock_irqsave+0x20/0x60 [ 20.740134] c0 3136 (Compiler) Call trace: [ 20.740165] c0 3136 (Compiler) [] _raw_spin_lock_irqsave+0x24/0x60 [ 20.740200] c0 3136 (Compiler) [] __wake_up+0x1c/0x54 [ 20.740230] c0 3136 (Compiler) [] mmc_wait_data_done+0x28/0x34 [ 20.740262] c0 3136 (Compiler) [] mmc_request_done+0xa4/0x220 [ 20.740314] c0 3136 (Compiler) [] sdhci_tasklet_finish+0xac/0x264 [ 20.740352] c0 3136 (Compiler) [] tasklet_action+0xa0/0x158 [ 20.740382] c0 3136 (Compiler) [] __do_softirq+0x10c/0x2e4 [ 20.740411] c0 3136 (Compiler) [] irq_exit+0x8c/0xc0 [ 20.740439] c0 3136 (Compiler) [] handle_IRQ+0x48/0xac [ 20.740469] c0 3136 (Compiler) [] gic_handle_irq+0x38/0x7c ---------------------------------------------------------------------- Because in SMP, "mrq" has race condition between below two paths: path1: CPU0: static void mmc_wait_data_done(struct mmc_request *mrq) { mrq->host->context_info.is_done_rcv = true; // // If CPU0 has just finished "is_done_rcv = true" in path1, and at // this moment, IRQ or ICache line missing happens in CPU0. // What happens in CPU1 (path2)? // // If the mmcqd thread in CPU1(path2) hasn't entered to sleep mode: // path2 would have chance to break from wait_event_interruptible // in mmc_wait_for_data_req_done and continue to run for next // mmc_request (mmc_blk_rw_rq_prep). // // Within mmc_blk_rq_prep, mrq is cleared to 0. // If below line still gets host from "mrq" as the result of // compiler, the panic happens as we traced. wake_up_interruptible(&mrq->host->context_info.wait); } path2: CPU1: static int mmc_wait_for_data_req_done(... { ... while (1) { wait_event_interruptible(context_info->wait, (context_info->is_done_rcv || context_info->is_new_req)); static void mmc_blk_rw_rq_prep(... { ... memset(brq, 0, sizeof(struct mmc_blk_request)); This issue happens very coincidentally; however adding mdelay(1) in mmc_wait_data_done as below could duplicate it easily. static void mmc_wait_data_done(struct mmc_request *mrq) { mrq->host->context_info.is_done_rcv = true; + mdelay(1); wake_up_interruptible(&mrq->host->context_info.wait); } At runtime, IRQ or ICache line missing may just happen at the same place of the mdelay(1). This patch gets the mmc_context_info at the beginning of function, it can avoid this race condition. Signed-off-by: Jialing Fu Tested-by: Shawn Lin Fixes: 2220eedfd7ae ("mmc: fix async request mechanism ....") Signed-off-by: Shawn Lin Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 664b61729fa96..0520064dc33be 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -358,8 +358,10 @@ EXPORT_SYMBOL(mmc_start_bkops); */ static void mmc_wait_data_done(struct mmc_request *mrq) { - mrq->host->context_info.is_done_rcv = true; - wake_up_interruptible(&mrq->host->context_info.wait); + struct mmc_context_info *context_info = &mrq->host->context_info; + + context_info->is_done_rcv = true; + wake_up_interruptible(&context_info->wait); } static void mmc_wait_done(struct mmc_request *mrq) -- GitLab From 4ae93560b11cb2b57ea5732d442458694ab0c168 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 31 Aug 2015 01:25:11 -0700 Subject: [PATCH 5866/7006] NFSv4.1/pnfs: Don't ask for a read layout for an empty file. Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index 4eec540de9ea0..c4f918eca3d26 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -1494,6 +1494,9 @@ pnfs_update_layout(struct inode *ino, if (!pnfs_enabled_sb(NFS_SERVER(ino))) goto out; + if (iomode == IOMODE_READ && i_size_read(ino) == 0) + goto out; + if (pnfs_within_mdsthreshold(ctx, ino, iomode)) goto out; -- GitLab From 21b874c873b5019db8bb4b4f6aa929c4bac0a398 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 31 Aug 2015 01:19:22 -0700 Subject: [PATCH 5867/7006] NFSv4.1/pnfs: Handle LAYOUTGET return values correctly According to RFC5661 section 18.43.3, if the server cannot satisfy the loga_minlength argument to LAYOUTGET, there are 2 cases: 1) If loga_minlength == 0, it returns NFS4ERR_LAYOUTTRYLATER 2) If loga_minlength != 0, it returns NFS4ERR_BADLAYOUT Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 366b81c185f61..51c7164abd1ac 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -7780,11 +7780,20 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) switch (task->tk_status) { case 0: goto out; + /* + * NFS4ERR_BADLAYOUT means the MDS cannot return a layout of + * length lgp->args.minlength != 0 (see RFC5661 section 18.43.3). + */ + case -NFS4ERR_BADLAYOUT: + goto out_overflow; /* * NFS4ERR_LAYOUTTRYLATER is a conflict with another client - * (or clients) writing to the same RAID stripe + * (or clients) writing to the same RAID stripe except when + * the minlength argument is 0 (see RFC5661 section 18.43.3). */ case -NFS4ERR_LAYOUTTRYLATER: + if (lgp->args.minlength == 0) + goto out_overflow; /* * NFS4ERR_RECALLCONFLICT is when conflict with self (must recall * existing layout before getting a new one). @@ -7840,6 +7849,10 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata) rpc_restart_call_prepare(task); out: dprintk("<-- %s\n", __func__); + return; +out_overflow: + task->tk_status = -EOVERFLOW; + goto out; } static size_t max_response_pages(struct nfs_server *server) -- GitLab From 2d89a1d3c9ff8ceb115f001e66cff9788338ca47 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Mon, 31 Aug 2015 02:05:47 -0700 Subject: [PATCH 5868/7006] NFSv4.1/pNFS: Don't request a minimal read layout beyond the end of file If we have a read layout, then sanity check the minimal layout length so that it does not extend beyond the end of file. Signed-off-by: Trond Myklebust --- fs/nfs/pnfs.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index c4f918eca3d26..ba1246433794f 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -868,6 +868,7 @@ send_layoutget(struct pnfs_layout_hdr *lo, struct nfs_server *server = NFS_SERVER(ino); struct nfs4_layoutget *lgp; struct pnfs_layout_segment *lseg; + loff_t i_size; dprintk("--> %s\n", __func__); @@ -875,9 +876,17 @@ send_layoutget(struct pnfs_layout_hdr *lo, if (lgp == NULL) return NULL; + i_size = i_size_read(ino); + lgp->args.minlength = PAGE_CACHE_SIZE; if (lgp->args.minlength > range->length) lgp->args.minlength = range->length; + if (range->iomode == IOMODE_READ) { + if (range->offset >= i_size) + lgp->args.minlength = 0; + else if (i_size - range->offset < lgp->args.minlength) + lgp->args.minlength = i_size - range->offset; + } lgp->args.maxcount = PNFS_LAYOUT_MAXSIZE; lgp->args.range = *range; lgp->args.type = server->pnfs_curr_ld->id; -- GitLab From d5b98eb12420ce856caaf57dc5256eedc56a3747 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Fri, 28 Aug 2015 20:04:53 +0100 Subject: [PATCH 5869/7006] regmap: Support bulk reads for devices without raw formatting When doing a bulk read from a device which lacks raw I/O support we fall back to doing register at a time reads but we still use the raw formatters in order to render the data into the word size used by the device (since bulk reads still operate on the device word size rather than unsigned ints). This means that devices without raw formatting such as those that provide reg_read() are not supported. Provide handling for them by copying the values read into native endian values of the appropriate size. Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 27456c7978b90..b77f1c6abdad2 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -2338,7 +2338,34 @@ int regmap_bulk_read(struct regmap *map, unsigned int reg, void *val, &ival); if (ret != 0) return ret; - map->format.format_val(val + (i * val_bytes), ival, 0); + + if (map->format.format_val) { + map->format.format_val(val + (i * val_bytes), ival, 0); + } else { + /* Devices providing read and write + * operations can use the bulk I/O + * functions if they define a val_bytes, + * we assume that the values are native + * endian. + */ + u32 *u32 = val; + u16 *u16 = val; + u8 *u8 = val; + + switch (map->format.val_bytes) { + case 4: + u32[i] = ival; + break; + case 2: + u16[i] = ival; + break; + case 1: + u8[i] = ival; + break; + default: + return -EINVAL; + } + } } } -- GitLab From 17649c90ff4c5246bb4babf6260029968a6d119d Mon Sep 17 00:00:00 2001 From: Sergey SENOZHATSKY Date: Mon, 31 Aug 2015 18:54:58 +0900 Subject: [PATCH 5870/7006] regmap: fix a NULL pointer dereference in __regmap_init __regmap_init() may receive a NULL `struct regmap_bus *bus' pointer, for example, from snd_hdac_regmap_init(), and it make sure that it does not NULL deference `bus`, except around ->max_raw_read and ->max_raw_write initialisation. Add missing check. Signed-off-by: Sergey Senozhatsky Signed-off-by: Mark Brown --- drivers/base/regmap/regmap.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index d2efa4b332943..2ffdb62f75f73 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -579,8 +579,10 @@ struct regmap *regmap_init(struct device *dev, map->use_single_read = config->use_single_rw || !bus || !bus->read; map->use_single_write = config->use_single_rw || !bus || !bus->write; map->can_multi_write = config->can_multi_write && bus && bus->write; - map->max_raw_read = bus->max_raw_read; - map->max_raw_write = bus->max_raw_write; + if (bus) { + map->max_raw_read = bus->max_raw_read; + map->max_raw_write = bus->max_raw_write; + } map->dev = dev; map->bus = bus; map->bus_context = bus_context; -- GitLab From f0a515780393dffbb363e6d1567da46af6f3c5f3 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 28 Aug 2015 07:06:58 -0400 Subject: [PATCH 5871/7006] tracing: Don't make assumptions about length of string on task rename While the dest comm string size is assured to be at least TASK_COMM_LEN long, doing a memcpy() also adds the assumption that the source is at least that long as well, which isn't assured, and isn't true in cases such as: set_task_comm(worker->task, "kworker/dying"); This leads to accessing invalid memory. Link: http://lkml.kernel.org/r/1440760018-1557-1-git-send-email-sasha.levin@oracle.com Signed-off-by: Sasha Levin Signed-off-by: Steven Rostedt --- include/trace/events/task.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/trace/events/task.h b/include/trace/events/task.h index dee3bb1d5a6b5..2cca6cd342d89 100644 --- a/include/trace/events/task.h +++ b/include/trace/events/task.h @@ -46,7 +46,7 @@ TRACE_EVENT(task_rename, TP_fast_assign( __entry->pid = task->pid; memcpy(entry->oldcomm, task->comm, TASK_COMM_LEN); - memcpy(entry->newcomm, comm, TASK_COMM_LEN); + strlcpy(entry->newcomm, comm, TASK_COMM_LEN); __entry->oom_score_adj = task->signal->oom_score_adj; ), -- GitLab From d14e7b6d1d8747826cb900db852351c550e00fdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 20 Aug 2015 19:37:29 +0300 Subject: [PATCH 5872/7006] drm/i915: Check DP link status on long hpd too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We are no longer checkling the DP link status on long hpd. We used to do that from the .hot_plug() handler, but it was removed when MST got introduced. If there's no userspace we now fail to retrain the link if the sink power is toggled (or cable yanked and replugged), meaning the user is left staring at a blank screen. With the retraining put back that should be fixed. Also remove the leftover comment that referred to the old retraining from .hot_plug(). Fixes a regression introduced in: commit 0e32b39ceed665bfa4a77a4bc307b6652b991632 Author: Dave Airlie Date: Fri May 2 14:02:48 2014 +1000 drm/i915: add DP 1.2 MST support (v0.7) Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89453 Tested-by: Palmer Dabbelt Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91407 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89461 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=89594 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=85641 Cc: Dave Airlie Cc: stable@vger.kernel.org Signed-off-by: Ville Syrjälä Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 3781cd3e358a7..94686cb7621e4 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4961,9 +4961,12 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) intel_dp_probe_oui(intel_dp); - if (!intel_dp_probe_mst(intel_dp)) + if (!intel_dp_probe_mst(intel_dp)) { + drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); + intel_dp_check_link_status(intel_dp); + drm_modeset_unlock(&dev->mode_config.connection_mutex); goto mst_fail; - + } } else { if (intel_dp->is_mst) { if (intel_dp_check_mst_status(intel_dp) == -EINVAL) @@ -4971,10 +4974,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd) } if (!intel_dp->is_mst) { - /* - * we'll check the link status via the normal hot plug path later - - * but for short hpds we should check it now - */ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); intel_dp_check_link_status(intel_dp); drm_modeset_unlock(&dev->mode_config.connection_mutex); -- GitLab From 54875571bbfde00fc63741715c531cbb5246c3b2 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 30 Jun 2015 17:06:47 +0300 Subject: [PATCH 5873/7006] drm/i915: apply the PCI_D0/D3 hibernation workaround everywhere on pre GEN6 commit da2bc1b9db3351addd293e5b82757efe1f77ed1d Author: Imre Deak Date: Thu Oct 23 19:23:26 2014 +0300 drm/i915: add poweroff_late handler introduced a regression on old platforms during hibernation. A workaround was added in commit ab3be73fa7b43f4c3648ce29b5fd649ea54d3adb Author: Imre Deak Date: Mon Mar 2 13:04:41 2015 +0200 drm/i915: gen4: work around hang during hibernation using an explicit blacklist for the GENs/BIOS vendors where the issue was reported. Later there we had reports of the same failure on platforms not on this list. To my best knowledge the correct thing to do is still to put the device to PCI D3 state during hibernation, see [1] and [2] for the reasons. This also aligns with our future plans to unify more the runtime and system suspend/resume paths. Since an exact blacklist seems to be impractical (multiple GENs and BIOS vendors are affected) apply the workaround on everything pre GEN6. [1] http://lists.freedesktop.org/archives/intel-gfx/2015-February/060710.html [2] https://lkml.org/lkml/2015/6/22/274 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=95061 Reported-by: Ilya Tumaykin Reported-by: Dirk Griesbach Reported-by: Pavel Machek Reported-by: Mikko Rapeli Tested-by: Mikko Rapeli Reported-by: Paul Bolle CC: stable@vger.kernel.org Signed-off-by: Imre Deak Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c index 1d887459e37fd..8edcec8ae5925 100644 --- a/drivers/gpu/drm/i915/i915_drv.c +++ b/drivers/gpu/drm/i915/i915_drv.c @@ -662,15 +662,18 @@ static int i915_drm_suspend_late(struct drm_device *drm_dev, bool hibernation) pci_disable_device(drm_dev->pdev); /* - * During hibernation on some GEN4 platforms the BIOS may try to access + * During hibernation on some platforms the BIOS may try to access * the device even though it's already in D3 and hang the machine. So * leave the device in D0 on those platforms and hope the BIOS will - * power down the device properly. Platforms where this was seen: - * Lenovo Thinkpad X301, X61s + * power down the device properly. The issue was seen on multiple old + * GENs with different BIOS vendors, so having an explicit blacklist + * is inpractical; apply the workaround on everything pre GEN6. The + * platforms where the issue was seen: + * Lenovo Thinkpad X301, X61s, X60, T60, X41 + * Fujitsu FSC S7110 + * Acer Aspire 1830T */ - if (!(hibernation && - drm_dev->pdev->subsystem_vendor == PCI_VENDOR_ID_LENOVO && - INTEL_INFO(dev_priv)->gen == 4)) + if (!(hibernation && INTEL_INFO(dev_priv)->gen < 6)) pci_set_power_state(drm_dev->pdev, PCI_D3hot); return 0; -- GitLab From 11c1b657c42f65c43f866b611956ef0a10bedafc Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Mon, 17 Aug 2015 16:04:04 +0800 Subject: [PATCH 5874/7006] drm/i915: Enable HDMI on DDI-E DDI-E doesn't have the correspondent GMBUS pin. We rely on VBT to tell us which one it being used instead. The DVI/HDMI on shared port couldn't exist. This patch isn't tested without hardware wchich has HDMI on DDI-E. v2: fix trailing whitespace v3: MISSING_CASE take place of BUG() Signed-off-by: Xiong Zhang Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 5 +++++ drivers/gpu/drm/i915/intel_bios.c | 25 +++++++++++++++++++++---- drivers/gpu/drm/i915/intel_hdmi.c | 21 +++++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 089459b397711..9b9bd2e34c132 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1416,6 +1416,10 @@ enum modeset_restore { #define DP_AUX_C 0x20 #define DP_AUX_D 0x30 +#define DDC_PIN_B 0x05 +#define DDC_PIN_C 0x04 +#define DDC_PIN_D 0x06 + struct ddi_vbt_port_info { /* * This is an index in the HDMI/DVI DDI buffer translation table. @@ -1430,6 +1434,7 @@ struct ddi_vbt_port_info { uint8_t supports_dp:1; uint8_t alternate_aux_channel; + uint8_t alternate_ddc_pin; uint8_t dp_boost_level; uint8_t hdmi_boost_level; diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index be83b77aa018b..313b5a73c6b48 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -905,7 +905,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, uint8_t hdmi_level_shift; int i, j; bool is_dvi, is_hdmi, is_dp, is_edp, is_crt; - uint8_t aux_channel; + uint8_t aux_channel, ddc_pin; /* Each DDI port can have more than one value on the "DVO Port" field, * so look for all the possible values for each port and abort if more * than one is found. */ @@ -939,6 +939,7 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, return; aux_channel = child->raw[25]; + ddc_pin = child->common.ddc_pin; is_dvi = child->common.device_type & DEVICE_TYPE_TMDS_DVI_SIGNALING; is_dp = child->common.device_type & DEVICE_TYPE_DISPLAYPORT_OUTPUT; @@ -970,11 +971,27 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, DRM_DEBUG_KMS("Port %c is internal DP\n", port_name(port)); if (is_dvi) { - if (child->common.ddc_pin == 0x05 && port != PORT_B) + if (port == PORT_E) { + info->alternate_ddc_pin = ddc_pin; + /* if DDIE share ddc pin with other port, then + * dvi/hdmi couldn't exist on the shared port. + * Otherwise they share the same ddc bin and system + * couldn't communicate with them seperately. */ + if (ddc_pin == DDC_PIN_B) { + dev_priv->vbt.ddi_port_info[PORT_B].supports_dvi = 0; + dev_priv->vbt.ddi_port_info[PORT_B].supports_hdmi = 0; + } else if (ddc_pin == DDC_PIN_C) { + dev_priv->vbt.ddi_port_info[PORT_C].supports_dvi = 0; + dev_priv->vbt.ddi_port_info[PORT_C].supports_hdmi = 0; + } else if (ddc_pin == DDC_PIN_D) { + dev_priv->vbt.ddi_port_info[PORT_D].supports_dvi = 0; + dev_priv->vbt.ddi_port_info[PORT_D].supports_hdmi = 0; + } + } else if (ddc_pin == DDC_PIN_B && port != PORT_B) DRM_DEBUG_KMS("Unexpected DDC pin for port B\n"); - if (child->common.ddc_pin == 0x04 && port != PORT_C) + else if (ddc_pin == DDC_PIN_C && port != PORT_C) DRM_DEBUG_KMS("Unexpected DDC pin for port C\n"); - if (child->common.ddc_pin == 0x06 && port != PORT_D) + else if (ddc_pin == DDC_PIN_D && port != PORT_D) DRM_DEBUG_KMS("Unexpected DDC pin for port D\n"); } diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 51cbea8247fe9..dcd336bcdfe75 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -1958,6 +1958,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, struct drm_device *dev = intel_encoder->base.dev; struct drm_i915_private *dev_priv = dev->dev_private; enum port port = intel_dig_port->port; + uint8_t alternate_ddc_pin; drm_connector_init(dev, connector, &intel_hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA); @@ -1991,6 +1992,26 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port, intel_hdmi->ddc_bus = GMBUS_PIN_DPD; intel_encoder->hpd_pin = HPD_PORT_D; break; + case PORT_E: + /* On SKL PORT E doesn't have seperate GMBUS pin + * We rely on VBT to set a proper alternate GMBUS pin. */ + alternate_ddc_pin = + dev_priv->vbt.ddi_port_info[PORT_E].alternate_ddc_pin; + switch (alternate_ddc_pin) { + case DDC_PIN_B: + intel_hdmi->ddc_bus = GMBUS_PIN_DPB; + break; + case DDC_PIN_C: + intel_hdmi->ddc_bus = GMBUS_PIN_DPC; + break; + case DDC_PIN_D: + intel_hdmi->ddc_bus = GMBUS_PIN_DPD; + break; + default: + MISSING_CASE(alternate_ddc_pin); + } + intel_encoder->hpd_pin = HPD_PORT_E; + break; case PORT_A: intel_encoder->hpd_pin = HPD_PORT_A; /* Internal port only for eDP. */ -- GitLab From 2800e4c228b8961c4da1a4925cc20c16e623851b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 7 Aug 2015 17:35:21 -0700 Subject: [PATCH 5875/7006] drm/i915/skl: Enable DDI-E There are OEMs using DDI-E out there, so let's enable it. Unfortunately there is no detection bit for DDI-E So we need to rely on VBT for that. I also need to give credits to Xiong since before seing his approach to check info->support_* I was creating an ugly vbt->ddie_sfuse_strap in order to propagate the ddi presence info v2: Rebased as last patch in the series. since all other patches in this series are needed for anything working propperly on DDI-E. Credits-to: "Zhang, Xiong Y" Cc: "Zhang, Xiong Y" Reviewed-by: Xiong Zhang Signed-off-by: Rodrigo Vivi Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_bios.c | 14 +++++++------- drivers/gpu/drm/i915/intel_bios.h | 2 ++ drivers/gpu/drm/i915/intel_display.c | 9 +++++++++ 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index 313b5a73c6b48..b3e437b3bb54f 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c @@ -909,19 +909,19 @@ static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port, /* Each DDI port can have more than one value on the "DVO Port" field, * so look for all the possible values for each port and abort if more * than one is found. */ - int dvo_ports[][2] = { - {DVO_PORT_HDMIA, DVO_PORT_DPA}, - {DVO_PORT_HDMIB, DVO_PORT_DPB}, - {DVO_PORT_HDMIC, DVO_PORT_DPC}, - {DVO_PORT_HDMID, DVO_PORT_DPD}, - {DVO_PORT_CRT, -1 /* Port E can only be DVO_PORT_CRT */ }, + int dvo_ports[][3] = { + {DVO_PORT_HDMIA, DVO_PORT_DPA, -1}, + {DVO_PORT_HDMIB, DVO_PORT_DPB, -1}, + {DVO_PORT_HDMIC, DVO_PORT_DPC, -1}, + {DVO_PORT_HDMID, DVO_PORT_DPD, -1}, + {DVO_PORT_CRT, DVO_PORT_HDMIE, DVO_PORT_DPE}, }; /* Find the child device to use, abort if more than one found. */ for (i = 0; i < dev_priv->vbt.child_dev_num; i++) { it = dev_priv->vbt.child_dev + i; - for (j = 0; j < 2; j++) { + for (j = 0; j < 3; j++) { if (dvo_ports[port][j] == -1) break; diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 06d0dbde2be63..a59122731efde 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -775,6 +775,8 @@ int intel_parse_bios(struct drm_device *dev); #define DVO_PORT_DPC 8 #define DVO_PORT_DPD 9 #define DVO_PORT_DPA 10 +#define DVO_PORT_DPE 11 +#define DVO_PORT_HDMIE 12 #define DVO_PORT_MIPIA 21 #define DVO_PORT_MIPIB 22 #define DVO_PORT_MIPIC 23 diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 8ea9821261abc..9bae13394e5ba 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -13960,6 +13960,15 @@ static void intel_setup_outputs(struct drm_device *dev) intel_ddi_init(dev, PORT_C); if (found & SFUSE_STRAP_DDID_DETECTED) intel_ddi_init(dev, PORT_D); + /* + * On SKL we don't have a way to detect DDI-E so we rely on VBT. + */ + if (IS_SKYLAKE(dev) && + (dev_priv->vbt.ddi_port_info[PORT_E].supports_dp || + dev_priv->vbt.ddi_port_info[PORT_E].supports_dvi || + dev_priv->vbt.ddi_port_info[PORT_E].supports_hdmi)) + intel_ddi_init(dev, PORT_E); + } else if (HAS_PCH_SPLIT(dev)) { int found; dpd_is_edp = intel_dp_is_edp(dev, PORT_D); -- GitLab From 477ec3283c324d16e8da07a8d8a4a367e31b6eab Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 6 Aug 2015 15:51:39 +0800 Subject: [PATCH 5876/7006] drm/i915: eDP can be present on DDI-E Enable eDP on DDI-E. Also let's remove duplicated definitions to avoid later confusion. Signed-off-by: Rodrigo Vivi Reviewed-by: Xiong Zhang Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_bios.h | 5 ----- drivers/gpu/drm/i915/intel_dp.c | 9 +++++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index a59122731efde..46cd5c7ebacd3 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -758,11 +758,6 @@ int intel_parse_bios(struct drm_device *dev); #define DVO_C 2 #define DVO_D 3 -/* define the PORT for DP output type */ -#define PORT_IDPB 7 -#define PORT_IDPC 8 -#define PORT_IDPD 9 - /* Possible values for the "DVO Port" field for versions >= 155: */ #define DVO_PORT_HDMIA 0 #define DVO_PORT_HDMIB 1 diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 94686cb7621e4..32663b1933f19 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5015,16 +5015,17 @@ intel_trans_dp_port_sel(struct drm_crtc *crtc) return -1; } -/* check the VBT to see whether the eDP is on DP-D port */ +/* check the VBT to see whether the eDP is on another port */ bool intel_dp_is_edp(struct drm_device *dev, enum port port) { struct drm_i915_private *dev_priv = dev->dev_private; union child_device_config *p_child; int i; static const short port_mapping[] = { - [PORT_B] = PORT_IDPB, - [PORT_C] = PORT_IDPC, - [PORT_D] = PORT_IDPD, + [PORT_B] = DVO_PORT_DPB, + [PORT_C] = DVO_PORT_DPC, + [PORT_D] = DVO_PORT_DPD, + [PORT_E] = DVO_PORT_DPE, }; if (port == PORT_A) -- GitLab From 3f8340cc72c9a1a4b49bce7802afd7f248400ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Aug 2015 17:23:31 +0300 Subject: [PATCH 5877/7006] drm/radeon/atom: Send out the full AUX address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AUX addresses are 20 bits long. Send out the entire address instead of just the low 16 bits. Cc: Alex Deucher Cc: "Christian König" Signed-off-by: Ville Syrjälä Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/atombios_dp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c index f81e0d7d02329..9cd49c584263c 100644 --- a/drivers/gpu/drm/radeon/atombios_dp.c +++ b/drivers/gpu/drm/radeon/atombios_dp.c @@ -171,8 +171,9 @@ radeon_dp_aux_transfer_atom(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) return -E2BIG; tx_buf[0] = msg->address & 0xff; - tx_buf[1] = msg->address >> 8; - tx_buf[2] = msg->request << 4; + tx_buf[1] = (msg->address >> 8) & 0xff; + tx_buf[2] = (msg->request << 4) | + ((msg->address >> 16) & 0xf); tx_buf[3] = msg->size ? (msg->size - 1) : 0; switch (msg->request & ~DP_AUX_I2C_MOT) { -- GitLab From 7040c399aea2b0213a9aefd73e507369a6d641d6 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 31 Aug 2015 11:15:05 -0400 Subject: [PATCH 5878/7006] drm/radeon/native: Send out the full AUX address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AUX addresses are 20 bits long. Send out the entire address instead of just the low 16 bits. Port of: drm/radeon/atom: Send out the full AUX address to radeon non-atom aux path Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_dp_auxch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/radeon/radeon_dp_auxch.c b/drivers/gpu/drm/radeon/radeon_dp_auxch.c index fcbd60bb03495..3b0c229d7dcd2 100644 --- a/drivers/gpu/drm/radeon/radeon_dp_auxch.c +++ b/drivers/gpu/drm/radeon/radeon_dp_auxch.c @@ -116,8 +116,8 @@ radeon_dp_aux_transfer_native(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg AUX_SW_WR_BYTES(bytes)); /* write the data header into the registers */ - /* request, addres, msg size */ - byte = (msg->request << 4); + /* request, address, msg size */ + byte = (msg->request << 4) | ((msg->address >> 16) & 0xf); WREG32(AUX_SW_DATA + aux_offset[instance], AUX_SW_DATA_MASK(byte) | AUX_SW_AUTOINCREMENT_DISABLE); -- GitLab From d8e19f99d3483adb01c6269dd5775ba8ecf1870a Mon Sep 17 00:00:00 2001 From: Xiong Zhang Date: Thu, 13 Aug 2015 18:00:12 +0800 Subject: [PATCH 5879/7006] drm/i915/skl: Adding DDI_E power well domain From B spec, DDI_E port belong to PowerWell 2, but DDI_E share the powerwell_req/staus register bit with DDI_A which belong to DDI_A_E_POWER_WELL. In order to communicate with the connector on DDI-E, both DDI_A_E_POWER_WELL and POWER_WELL_2 must be enabled. Currently intel_dp_power_get(DDI_E) only enable DDI_A_E_POWER_WELL, this patch will not only enable DDI_a_E_POWER_WELL but also enable POWER_WELL_2. This patch also fix the DDI-E hotplug function. Signed-off-by: Xiong Zhang Reviewed-by: Rodrigo Vivi Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_debugfs.c | 2 ++ drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_display.c | 3 ++- drivers/gpu/drm/i915/intel_runtime_pm.c | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c index 33aabc79813b7..e3ec9049081fd 100644 --- a/drivers/gpu/drm/i915/i915_debugfs.c +++ b/drivers/gpu/drm/i915/i915_debugfs.c @@ -2562,6 +2562,8 @@ static const char *power_domain_str(enum intel_display_power_domain domain) return "PORT_DDI_D_2_LANES"; case POWER_DOMAIN_PORT_DDI_D_4_LANES: return "PORT_DDI_D_4_LANES"; + case POWER_DOMAIN_PORT_DDI_E_2_LANES: + return "PORT_DDI_E_2_LANES"; case POWER_DOMAIN_PORT_DSI: return "PORT_DSI"; case POWER_DOMAIN_PORT_CRT: diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9b9bd2e34c132..e304d4e5ae0c9 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -182,6 +182,7 @@ enum intel_display_power_domain { POWER_DOMAIN_PORT_DDI_C_4_LANES, POWER_DOMAIN_PORT_DDI_D_2_LANES, POWER_DOMAIN_PORT_DDI_D_4_LANES, + POWER_DOMAIN_PORT_DDI_E_2_LANES, POWER_DOMAIN_PORT_DSI, POWER_DOMAIN_PORT_CRT, POWER_DOMAIN_PORT_OTHER, diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 9bae13394e5ba..a5cddcd6d3e07 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5150,7 +5150,6 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) { switch (port) { case PORT_A: - case PORT_E: return POWER_DOMAIN_PORT_DDI_A_4_LANES; case PORT_B: return POWER_DOMAIN_PORT_DDI_B_4_LANES; @@ -5158,6 +5157,8 @@ static enum intel_display_power_domain port_to_power_domain(enum port port) return POWER_DOMAIN_PORT_DDI_C_4_LANES; case PORT_D: return POWER_DOMAIN_PORT_DDI_D_4_LANES; + case PORT_E: + return POWER_DOMAIN_PORT_DDI_E_2_LANES; default: WARN_ON_ONCE(1); return POWER_DOMAIN_PORT_OTHER; diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 821644d1b544e..af7fdb3bd663a 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -297,6 +297,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \ BIT(POWER_DOMAIN_AUX_B) | \ BIT(POWER_DOMAIN_AUX_C) | \ BIT(POWER_DOMAIN_AUX_D) | \ @@ -316,6 +317,7 @@ static void hsw_set_power_well(struct drm_i915_private *dev_priv, #define SKL_DISPLAY_DDI_A_E_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) | \ BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) | \ + BIT(POWER_DOMAIN_PORT_DDI_E_2_LANES) | \ BIT(POWER_DOMAIN_INIT)) #define SKL_DISPLAY_DDI_B_POWER_DOMAINS ( \ BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \ -- GitLab From 0e833e697bcf4c2f3f7fb9fce39d08cd4439e5d7 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Wed, 1 Jul 2015 12:19:56 +1000 Subject: [PATCH 5880/7006] md/raid6: delta syndrome for ARM NEON This implements XOR syndrome calculation using NEON intrinsics. As before, the module can be built for ARM and arm64 from the same source. Relative performance on a Cortex-A57 based system: raid6: int64x1 gen() 905 MB/s raid6: int64x1 xor() 881 MB/s raid6: int64x2 gen() 1343 MB/s raid6: int64x2 xor() 1286 MB/s raid6: int64x4 gen() 1896 MB/s raid6: int64x4 xor() 1321 MB/s raid6: int64x8 gen() 1773 MB/s raid6: int64x8 xor() 1165 MB/s raid6: neonx1 gen() 1834 MB/s raid6: neonx1 xor() 1278 MB/s raid6: neonx2 gen() 2528 MB/s raid6: neonx2 xor() 1942 MB/s raid6: neonx4 gen() 2888 MB/s raid6: neonx4 xor() 2334 MB/s raid6: neonx8 gen() 2957 MB/s raid6: neonx8 xor() 2232 MB/s raid6: using algorithm neonx8 gen() 2957 MB/s raid6: .... xor() 2232 MB/s, rmw enabled Cc: Markus Stockhausen Cc: Neil Brown Signed-off-by: Ard Biesheuvel Signed-off-by: NeilBrown --- lib/raid6/neon.c | 13 ++++++++++++- lib/raid6/neon.uc | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/lib/raid6/neon.c b/lib/raid6/neon.c index d9ad6ee284f4b..7076ef1ba3dd6 100644 --- a/lib/raid6/neon.c +++ b/lib/raid6/neon.c @@ -40,9 +40,20 @@ (unsigned long)bytes, ptrs); \ kernel_neon_end(); \ } \ + static void raid6_neon ## _n ## _xor_syndrome(int disks, \ + int start, int stop, \ + size_t bytes, void **ptrs) \ + { \ + void raid6_neon ## _n ## _xor_syndrome_real(int, \ + int, int, unsigned long, void**); \ + kernel_neon_begin(); \ + raid6_neon ## _n ## _xor_syndrome_real(disks, \ + start, stop, (unsigned long)bytes, ptrs); \ + kernel_neon_end(); \ + } \ struct raid6_calls const raid6_neonx ## _n = { \ raid6_neon ## _n ## _gen_syndrome, \ - NULL, /* XOR not yet implemented */ \ + raid6_neon ## _n ## _xor_syndrome, \ raid6_have_neon, \ "neonx" #_n, \ 0 \ diff --git a/lib/raid6/neon.uc b/lib/raid6/neon.uc index 1b9ed793342d7..4fa51b761dd0c 100644 --- a/lib/raid6/neon.uc +++ b/lib/raid6/neon.uc @@ -3,6 +3,7 @@ * neon.uc - RAID-6 syndrome calculation using ARM NEON instructions * * Copyright (C) 2012 Rob Herring + * Copyright (C) 2015 Linaro Ltd. * * Based on altivec.uc: * Copyright 2002-2004 H. Peter Anvin - All Rights Reserved @@ -78,3 +79,48 @@ void raid6_neon$#_gen_syndrome_real(int disks, unsigned long bytes, void **ptrs) vst1q_u8(&q[d+NSIZE*$$], wq$$); } } + +void raid6_neon$#_xor_syndrome_real(int disks, int start, int stop, + unsigned long bytes, void **ptrs) +{ + uint8_t **dptr = (uint8_t **)ptrs; + uint8_t *p, *q; + int d, z, z0; + + register unative_t wd$$, wq$$, wp$$, w1$$, w2$$; + const unative_t x1d = NBYTES(0x1d); + + z0 = stop; /* P/Q right side optimization */ + p = dptr[disks-2]; /* XOR parity */ + q = dptr[disks-1]; /* RS syndrome */ + + for ( d = 0 ; d < bytes ; d += NSIZE*$# ) { + wq$$ = vld1q_u8(&dptr[z0][d+$$*NSIZE]); + wp$$ = veorq_u8(vld1q_u8(&p[d+$$*NSIZE]), wq$$); + + /* P/Q data pages */ + for ( z = z0-1 ; z >= start ; z-- ) { + wd$$ = vld1q_u8(&dptr[z][d+$$*NSIZE]); + wp$$ = veorq_u8(wp$$, wd$$); + w2$$ = MASK(wq$$); + w1$$ = SHLBYTE(wq$$); + + w2$$ = vandq_u8(w2$$, x1d); + w1$$ = veorq_u8(w1$$, w2$$); + wq$$ = veorq_u8(w1$$, wd$$); + } + /* P/Q left side optimization */ + for ( z = start-1 ; z >= 0 ; z-- ) { + w2$$ = MASK(wq$$); + w1$$ = SHLBYTE(wq$$); + + w2$$ = vandq_u8(w2$$, x1d); + wq$$ = veorq_u8(w1$$, w2$$); + } + w1$$ = vld1q_u8(&q[d+NSIZE*$$]); + wq$$ = veorq_u8(wq$$, w1$$); + + vst1q_u8(&p[d+NSIZE*$$], wp$$); + vst1q_u8(&q[d+NSIZE*$$], wq$$); + } +} -- GitLab From f7851be736d58e7270f05a4ca84b16ce72734a18 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 2 Jul 2015 17:12:58 +1000 Subject: [PATCH 5881/7006] md: Keep /proc/mdstat reporting recovery until fully DONE. Currently when a recovery completes, mdstat shows that it has finished before the new device is marked as a full member. Because of this it can appear to a script that the recovery finished but the array isn't in sync. So while MD_RECOVERY_DONE is still set, keep mdstat reporting "recovery". Once md_reap_sync_thread() completes, the spare will be active and then MD_RECOVERY_DONE will be cleared. To ensure this is race-free, set MD_RECOVERY_DONE before clearning curr_resync. Signed-off-by: NeilBrown --- drivers/md/md.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 4d47a9ab8228f..689be615d7be4 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7093,7 +7093,7 @@ static void status_unused(struct seq_file *seq) seq_printf(seq, "\n"); } -static void status_resync(struct seq_file *seq, struct mddev *mddev) +static int status_resync(struct seq_file *seq, struct mddev *mddev) { sector_t max_sectors, resync, res; unsigned long dt, db; @@ -7101,18 +7101,32 @@ static void status_resync(struct seq_file *seq, struct mddev *mddev) int scale; unsigned int per_milli; - if (mddev->curr_resync <= 3) - resync = 0; - else - resync = mddev->curr_resync - - atomic_read(&mddev->recovery_active); - if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery) || test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) max_sectors = mddev->resync_max_sectors; else max_sectors = mddev->dev_sectors; + resync = mddev->curr_resync; + if (resync <= 3) { + if (test_bit(MD_RECOVERY_DONE, &mddev->recovery)) + /* Still cleaning up */ + resync = max_sectors; + } else + resync -= atomic_read(&mddev->recovery_active); + + if (resync == 0) { + if (mddev->recovery_cp < MaxSector) { + seq_printf(seq, "\tresync=PENDING"); + return 1; + } + return 0; + } + if (resync < 3) { + seq_printf(seq, "\tresync=DELAYED"); + return 1; + } + WARN_ON(max_sectors == 0); /* Pick 'scale' such that (resync>>scale)*1000 will fit * in a sector_t, and (max_sectors>>scale) will fit in a @@ -7177,6 +7191,7 @@ static void status_resync(struct seq_file *seq, struct mddev *mddev) ((unsigned long)rt % 60)/6); seq_printf(seq, " speed=%ldK/sec", db/2/dt); + return 1; } static void *md_seq_start(struct seq_file *seq, loff_t *pos) @@ -7322,13 +7337,8 @@ static int md_seq_show(struct seq_file *seq, void *v) mddev->pers->status(seq, mddev); seq_printf(seq, "\n "); if (mddev->pers->sync_request) { - if (mddev->curr_resync > 2) { - status_resync(seq, mddev); + if (status_resync(seq, mddev)) seq_printf(seq, "\n "); - } else if (mddev->curr_resync >= 1) - seq_printf(seq, "\tresync=DELAYED\n "); - else if (mddev->recovery_cp < MaxSector) - seq_printf(seq, "\tresync=PENDING\n "); } } else seq_printf(seq, "\n "); @@ -7979,11 +7989,11 @@ void md_do_sync(struct md_thread *thread) mddev->resync_max = MaxSector; } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) mddev->resync_min = mddev->curr_resync_completed; + set_bit(MD_RECOVERY_DONE, &mddev->recovery); mddev->curr_resync = 0; spin_unlock(&mddev->lock); wake_up(&resync_wait); - set_bit(MD_RECOVERY_DONE, &mddev->recovery); md_wakeup_thread(mddev->thread); return; } -- GitLab From 985ca973b68cac0adfa83497db231da7f99c6ed9 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 6 Jul 2015 12:26:57 +1000 Subject: [PATCH 5882/7006] md: close some races between setting and checking sync_action. When checking sync_action in a script, we want to be sure it is as accurate as possible. As resync/reshape etc doesn't always start immediately (a separate thread is scheduled to do it), it is best if 'action_show' checks if MD_RECOVER_NEEDED is set (which it does) and in that case reports what is likely to start soon (which it only sometimes does). So: - report 'reshape' if reshape_position suggests one might start. - set MD_RECOVERY_RECOVER in raid1_reshape(), because that is very likely to happen next. Signed-off-by: NeilBrown --- drivers/md/md.c | 2 ++ drivers/md/raid1.c | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 689be615d7be4..324f9df4e429b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -4210,6 +4210,8 @@ action_show(struct mddev *mddev, char *page) type = "repair"; } else if (test_bit(MD_RECOVERY_RECOVER, &recovery)) type = "recover"; + else if (mddev->reshape_position != MaxSector) + type = "reshape"; } return sprintf(page, "%s\n", type); } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 967a4ed73929f..742b50794dfd6 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -3113,6 +3113,7 @@ static int raid1_reshape(struct mddev *mddev) unfreeze_array(conf); + set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); md_wakeup_thread(mddev->thread); -- GitLab From 92140480ed59a006b245efd33a195fde62d1845f Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 6 Jul 2015 12:28:45 +1000 Subject: [PATCH 5883/7006] md/raid5: consider updating reshape_position at start of reshape. md/raid5 only updates ->reshape_position (which is stored in metadata and is authoritative) occasionally, but particularly when getting closed to ->resync_max as it must be correct when ->resync_max is reached. When mdadm tries to stop an array which is reshaping it will: - freeze the reshape, - set resync_max to where the reshape has reached. - unfreeze the reshape. When this happens, the reshape is aborted and then restarted. The restart doesn't check that resync_max is close, and so doesn't update ->reshape_position like it should. This results in the reshape stopping, but ->reshape_position being incorrect. So on that first call to reshape_request, make sure ->reshape_position is updated if needed. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index f757023fc4580..256b05d1117be 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5347,6 +5347,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk sector_t stripe_addr; int reshape_sectors; struct list_head stripes; + sector_t retn; if (sector_nr == 0) { /* If restarting in the middle, skip the initial sectors */ @@ -5362,7 +5363,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk mddev->curr_resync_completed = sector_nr; sysfs_notify(&mddev->kobj, NULL, "sync_completed"); *skipped = 1; - return sector_nr; + retn = sector_nr; + goto finish; } } @@ -5535,6 +5537,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk * then we need to write out the superblock. */ sector_nr += reshape_sectors; + retn = reshape_sectors; +finish: if ((sector_nr - mddev->curr_resync_completed) * 2 >= mddev->resync_max - mddev->curr_resync_completed) { /* Cannot proceed until we've updated the superblock... */ @@ -5560,7 +5564,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk sysfs_notify(&mddev->kobj, NULL, "sync_completed"); } ret: - return reshape_sectors; + return retn; } static inline sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipped) -- GitLab From 02ec50265b16493e4a62228727e9f774068123d2 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Mon, 6 Jul 2015 16:33:47 +1000 Subject: [PATCH 5884/7006] md/raid10: fix a few typos in comments Signed-off-by: NeilBrown --- drivers/md/raid10.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index 38c58e19cfce3..dcc0e9b3ee921 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -4215,7 +4215,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, * at a time, possibly less if that exceeds RESYNC_PAGES, * or we hit a bad block or something. * This might mean we pause for normal IO in the middle of - * a chunk, but that is not a problem was mddev->reshape_position + * a chunk, but that is not a problem as mddev->reshape_position * can record any location. * * If we will want to write to a location that isn't @@ -4239,7 +4239,7 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, * * In all this the minimum difference in data offsets * (conf->offset_diff - always positive) allows a bit of slack, - * so next can be after 'safe', but not by more than offset_disk + * so next can be after 'safe', but not by more than offset_diff * * We need to prepare all the bios here before we start any IO * to ensure the size we choose is acceptable to all devices. -- GitLab From 5cac6bcb9312a18a5091976fc374b4c7b9c4ae2e Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 17 Jul 2015 12:17:50 +1000 Subject: [PATCH 5885/7006] md/raid5: always set conf->prev_chunk_sectors and ->prev_algo These aren't really needed when no reshape is happening, but it is safer to have them always set to a meaningful value. The next patch will use ->prev_chunk_sectors without checking if a reshape is happening (because that makes the code simpler), and this patch makes that safe. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 256b05d1117be..e543bfd7ae66e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6568,6 +6568,9 @@ static struct r5conf *setup_conf(struct mddev *mddev) if (conf->reshape_progress != MaxSector) { conf->prev_chunk_sectors = mddev->chunk_sectors; conf->prev_algo = mddev->layout; + } else { + conf->prev_chunk_sectors = conf->chunk_sectors; + conf->prev_algo = conf->algorithm; } conf->min_nr_stripes = NR_STRIPES; -- GitLab From 3cb5edf45457948347b5ae8cc9650c000cef4391 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 15 Jul 2015 17:24:17 +1000 Subject: [PATCH 5886/7006] md/raid5: switch to use conf->chunk_sectors in place of mddev->chunk_sectors where possible The chunk_sectors and new_chunk_sectors fields of mddev can be changed any time (via sysfs) that the reconfig mutex can be taken. So raid5 keeps internal copies in 'conf' which are stable except for a short locked moment when reshape stops/starts. So any access that does not hold reconfig_mutex should use the 'conf' values, not the 'mddev' values. Several don't. This could result in corruption if new values were written at awkward times. Also use min() or max() rather than open-coding. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e543bfd7ae66e..a98162f5d97fc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -4676,9 +4676,10 @@ static int raid5_mergeable_bvec(struct mddev *mddev, struct bvec_merge_data *bvm, struct bio_vec *biovec) { + struct r5conf *conf = mddev->private; sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev); int max; - unsigned int chunk_sectors = mddev->chunk_sectors; + unsigned int chunk_sectors; unsigned int bio_sectors = bvm->bi_size >> 9; /* @@ -4688,8 +4689,7 @@ static int raid5_mergeable_bvec(struct mddev *mddev, if ((bvm->bi_rw & 1) == WRITE || mddev->degraded) return biovec->bv_len; - if (mddev->new_chunk_sectors < mddev->chunk_sectors) - chunk_sectors = mddev->new_chunk_sectors; + chunk_sectors = min(conf->chunk_sectors, conf->prev_chunk_sectors); max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; if (max < 0) max = 0; if (max <= biovec->bv_len && bio_sectors == 0) @@ -4700,12 +4700,12 @@ static int raid5_mergeable_bvec(struct mddev *mddev, static int in_chunk_boundary(struct mddev *mddev, struct bio *bio) { + struct r5conf *conf = mddev->private; sector_t sector = bio->bi_iter.bi_sector + get_start_sect(bio->bi_bdev); - unsigned int chunk_sectors = mddev->chunk_sectors; + unsigned int chunk_sectors; unsigned int bio_sectors = bio_sectors(bio); - if (mddev->new_chunk_sectors < mddev->chunk_sectors) - chunk_sectors = mddev->new_chunk_sectors; + chunk_sectors = min(conf->chunk_sectors, conf->prev_chunk_sectors); return chunk_sectors >= ((sector & (chunk_sectors - 1)) + bio_sectors); } @@ -5372,10 +5372,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk * If old and new chunk sizes differ, we need to process the * largest of these */ - if (mddev->new_chunk_sectors > mddev->chunk_sectors) - reshape_sectors = mddev->new_chunk_sectors; - else - reshape_sectors = mddev->chunk_sectors; + + reshape_sectors = max(conf->chunk_sectors, conf->prev_chunk_sectors); /* We update the metadata at least every 10 seconds, or when * the data about to be copied would over-write the source of @@ -6260,8 +6258,8 @@ raid5_size(struct mddev *mddev, sector_t sectors, int raid_disks) /* size is defined by the smallest of previous and new size */ raid_disks = min(conf->raid_disks, conf->previous_raid_disks); - sectors &= ~((sector_t)mddev->chunk_sectors - 1); - sectors &= ~((sector_t)mddev->new_chunk_sectors - 1); + sectors &= ~((sector_t)conf->chunk_sectors - 1); + sectors &= ~((sector_t)conf->prev_chunk_sectors - 1); return sectors * (raid_disks - conf->max_degraded); } @@ -6996,7 +6994,7 @@ static void status(struct seq_file *seq, struct mddev *mddev) int i; seq_printf(seq, " level %d, %dk chunk, algorithm %d", mddev->level, - mddev->chunk_sectors / 2, mddev->layout); + conf->chunk_sectors / 2, mddev->layout); seq_printf (seq, " [%d/%d] [", conf->raid_disks, conf->raid_disks - mddev->degraded); for (i = 0; i < conf->raid_disks; i++) seq_printf (seq, "%s", @@ -7202,7 +7200,9 @@ static int raid5_resize(struct mddev *mddev, sector_t sectors) * worth it. */ sector_t newsize; - sectors &= ~((sector_t)mddev->chunk_sectors - 1); + struct r5conf *conf = mddev->private; + + sectors &= ~((sector_t)conf->chunk_sectors - 1); newsize = raid5_size(mddev, sectors, mddev->raid_disks); if (mddev->external_size && mddev->array_sectors > newsize) -- GitLab From 05256d9884d3276f61537d3d7f5605dc21bd3477 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 15 Jul 2015 17:36:21 +1000 Subject: [PATCH 5887/7006] md/raid5: strengthen check on reshape_position at run. When reshaping, we work in units of the largest chunk size. If changing from a larger to a smaller chunk size, that means we reshape more than one stripe at a time. So the required alignment of reshape_position needs to take into account both the old and new chunk size. This means that both 'here_new' and 'here_old' are calculated with respect to the same (maximum) chunk size, so testing if they are the same when delta_disks is zero becomes pointless. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a98162f5d97fc..e95219bf88596 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -6688,6 +6688,8 @@ static int run(struct mddev *mddev) sector_t here_new, here_old; int old_disks; int max_degraded = (mddev->level == 6 ? 2 : 1); + int chunk_sectors; + int new_data_disks; if (mddev->new_level != mddev->level) { printk(KERN_ERR "md/raid:%s: unsupported reshape " @@ -6699,28 +6701,25 @@ static int run(struct mddev *mddev) /* reshape_position must be on a new-stripe boundary, and one * further up in new geometry must map after here in old * geometry. + * If the chunk sizes are different, then as we perform reshape + * in units of the largest of the two, reshape_position needs + * be a multiple of the largest chunk size times new data disks. */ here_new = mddev->reshape_position; - if (sector_div(here_new, mddev->new_chunk_sectors * - (mddev->raid_disks - max_degraded))) { + chunk_sectors = max(mddev->chunk_sectors, mddev->new_chunk_sectors); + new_data_disks = mddev->raid_disks - max_degraded; + if (sector_div(here_new, chunk_sectors * new_data_disks)) { printk(KERN_ERR "md/raid:%s: reshape_position not " "on a stripe boundary\n", mdname(mddev)); return -EINVAL; } - reshape_offset = here_new * mddev->new_chunk_sectors; + reshape_offset = here_new * chunk_sectors; /* here_new is the stripe we will write to */ here_old = mddev->reshape_position; - sector_div(here_old, mddev->chunk_sectors * - (old_disks-max_degraded)); + sector_div(here_old, chunk_sectors * (old_disks-max_degraded)); /* here_old is the first stripe that we might need to read * from */ if (mddev->delta_disks == 0) { - if ((here_new * mddev->new_chunk_sectors != - here_old * mddev->chunk_sectors)) { - printk(KERN_ERR "md/raid:%s: reshape position is" - " confused - aborting\n", mdname(mddev)); - return -EINVAL; - } /* We cannot be sure it is safe to start an in-place * reshape. It is only safe if user-space is monitoring * and taking constant backups. @@ -6739,10 +6738,10 @@ static int run(struct mddev *mddev) return -EINVAL; } } else if (mddev->reshape_backwards - ? (here_new * mddev->new_chunk_sectors + min_offset_diff <= - here_old * mddev->chunk_sectors) - : (here_new * mddev->new_chunk_sectors >= - here_old * mddev->chunk_sectors + (-min_offset_diff))) { + ? (here_new * chunk_sectors + min_offset_diff <= + here_old * chunk_sectors) + : (here_new * chunk_sectors >= + here_old * chunk_sectors + (-min_offset_diff))) { /* Reading from the same stripe as writing to - bad */ printk(KERN_ERR "md/raid:%s: reshape_position too early for " "auto-recovery - aborting.\n", -- GitLab From c74c0d760e30f56f9699dc180036ca37993d1c58 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 15 Jul 2015 17:54:15 +1000 Subject: [PATCH 5888/7006] md/raid5: remove incorrect "min_t()" when calculating writepos. This code is calculating: writepos, which is the furthest along address (device-space) that we *will* be writing to readpos, which is the earliest address that we *could* possible read from, and safepos, which is the earliest address in the 'old' section that we might read from after a crash when the reshape position is recovered from metadata. The first is a precise calculation, so clipping at zero doesn't make sense. As the reshape position is now guaranteed to always be a multiple of reshape_sectors and as we already BUG_ON when reshape_progress is zero, there is no point in this min_t() call. The readpos and safepos are worst case - actual value depends on precise geometry. That worst case could be negative, which is only a problem because we are storing the value in an unsigned. So leave the min_t() for those. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e95219bf88596..19bbdbe1a52f8 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5388,11 +5388,16 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk safepos = conf->reshape_safe; sector_div(safepos, data_disks); if (mddev->reshape_backwards) { - writepos -= min_t(sector_t, reshape_sectors, writepos); + BUG_ON(writepos < reshape_sectors); + writepos -= reshape_sectors; readpos += reshape_sectors; safepos += reshape_sectors; } else { writepos += reshape_sectors; + /* readpos and safepos are worst-case calculations. + * A negative number is overly pessimistic, and causes + * obvious problems for unsigned storage. So clip to 0. + */ readpos -= min_t(sector_t, reshape_sectors, readpos); safepos -= min_t(sector_t, reshape_sectors, safepos); } -- GitLab From a4a3d26d8757a30ae21724d8b0d79e00e113c38d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 17 Jul 2015 11:57:30 +1000 Subject: [PATCH 5889/7006] md: set MD_RECOVERY_RECOVER when starting a degraded array. This ensures that 'sync_action' will show 'recover' immediately the array is started. If there is no spare the status will change to 'idle' once that is detected. Clear MD_RECOVERY_RECOVER for a read-only array to ensure this change happens. This allows scripts which monitor status not to get confused - particularly my test scripts. Signed-off-by: NeilBrown --- drivers/md/md.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index 324f9df4e429b..5b62a3d49e12e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -5218,6 +5218,11 @@ int md_run(struct mddev *mddev) if (sysfs_link_rdev(mddev, rdev)) /* failure here is OK */; + if (mddev->degraded && !mddev->ro) + /* This ensures that recovering status is reported immediately + * via sysfs - until a lack of spares is confirmed. + */ + set_bit(MD_RECOVERY_RECOVER, &mddev->recovery); set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); if (mddev->flags & MD_UPDATE_SB_FLAGS) @@ -8164,6 +8169,7 @@ void md_check_recovery(struct mddev *mddev) */ set_bit(MD_RECOVERY_INTR, &mddev->recovery); md_reap_sync_thread(mddev); + clear_bit(MD_RECOVERY_RECOVER, &mddev->recovery); clear_bit(MD_RECOVERY_NEEDED, &mddev->recovery); goto unlock; } -- GitLab From c5e19d906a658f27fa858b09a95d9551b1a69bd0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 17 Jul 2015 12:06:02 +1000 Subject: [PATCH 5890/7006] md: be careful when testing resync_max against curr_resync_completed. While it generally shouldn't happen, it is not impossible for curr_resync_completed to exceed resync_max. This can particularly happen when reshaping RAID5 - the current status isn't copied to curr_resync_completed promptly, so when it is, it can exceed resync_max. This happens when the reshape is 'frozen', resync_max is set low, and reshape is re-enabled. Taking a difference between two unsigned numbers is always dangerous anyway, so add a test to behave correctly if curr_resync_completed > resync_max Signed-off-by: NeilBrown --- drivers/md/md.c | 3 ++- drivers/md/raid5.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 5b62a3d49e12e..b326cd26b0277 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7834,7 +7834,8 @@ void md_do_sync(struct md_thread *thread) > (max_sectors >> 4)) || time_after_eq(jiffies, update_time + UPDATE_FREQUENCY) || (j - mddev->curr_resync_completed)*2 - >= mddev->resync_max - mddev->curr_resync_completed + >= mddev->resync_max - mddev->curr_resync_completed || + mddev->curr_resync_completed > mddev->resync_max )) { /* time to update curr_resync_completed */ wait_event(mddev->recovery_wait, diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 19bbdbe1a52f8..1c27aa10f89cc 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5542,7 +5542,8 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk sector_nr += reshape_sectors; retn = reshape_sectors; finish: - if ((sector_nr - mddev->curr_resync_completed) * 2 + if (mddev->curr_resync_completed > mddev->resync_max || + (sector_nr - mddev->curr_resync_completed) * 2 >= mddev->resync_max - mddev->curr_resync_completed) { /* Cannot proceed until we've updated the superblock... */ wait_event(conf->wait_for_overlap, -- GitLab From 5ed1df2eacc0ba92c8c7e2499c97594b5ef928a8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 24 Jul 2015 13:27:08 +1000 Subject: [PATCH 5891/7006] md: sync sync_completed has correct value as recovery finishes. There can be a small window between the moment that recovery actually writes the last block and the time when various sysfs and /proc/mdstat attributes report that it has finished. During this time, 'sync_completed' can have the wrong value. This can confuse monitoring software. So: - don't set curr_resync_completed beyond the end of the devices, - set it correctly when resync/recovery has completed. Signed-off-by: NeilBrown --- drivers/md/md.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/md/md.c b/drivers/md/md.c index b326cd26b0277..84dc5d7a445b3 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7880,6 +7880,9 @@ void md_do_sync(struct md_thread *thread) break; j += sectors; + if (j > max_sectors) + /* when skipping, extra large numbers can be returned. */ + j = max_sectors; if (j > 2) mddev->curr_resync = j; if (mddev_is_clustered(mddev)) @@ -7948,6 +7951,12 @@ void md_do_sync(struct md_thread *thread) blk_finish_plug(&plug); wait_event(mddev->recovery_wait, !atomic_read(&mddev->recovery_active)); + if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && + !test_bit(MD_RECOVERY_INTR, &mddev->recovery) && + mddev->curr_resync > 2) { + mddev->curr_resync_completed = mddev->curr_resync; + sysfs_notify(&mddev->kobj, NULL, "sync_completed"); + } /* tell personality that we are finished */ mddev->pers->sync_request(mddev, max_sectors, &skipped); -- GitLab From 6cbd81487f7cfa30e22537bf7cd07f48c4e7164d Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 24 Jul 2015 13:30:32 +1000 Subject: [PATCH 5892/7006] md/raid5: handle possible race as reshape completes. It is possible (though unlikely) for a reshape to be interrupted between the time that end_reshape is called and the time when raid5_finish_reshape is called. This can leave conf->reshape_progress set to MaxSector, but mddev->reshape_position not. This combination confused reshape_request() when ->reshape_backwards. As conf->reshape_progress is so high, it seems the reshape hasn't really begun. But assuming MaxSector is a valid address only leads to sorrow. So ensure reshape_position and reshape_progress both agree, and add an extra check in reshape_request() just in case they don't. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 1c27aa10f89cc..7b0c706f33e74 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5355,6 +5355,10 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr, int *sk conf->reshape_progress < raid5_size(mddev, 0, 0)) { sector_nr = raid5_size(mddev, 0, 0) - conf->reshape_progress; + } else if (mddev->reshape_backwards && + conf->reshape_progress == MaxSector) { + /* shouldn't happen, but just in case, finish up.*/ + sector_nr = MaxSector; } else if (!mddev->reshape_backwards && conf->reshape_progress > 0) sector_nr = conf->reshape_progress; @@ -7446,6 +7450,7 @@ static void end_reshape(struct r5conf *conf) rdev->data_offset = rdev->new_data_offset; smp_wmb(); conf->reshape_progress = MaxSector; + conf->mddev->reshape_position = MaxSector; spin_unlock_irq(&conf->device_lock); wake_up(&conf->wait_for_overlap); -- GitLab From 25b2edfa3b6940b73180d2735cd19fdf58d0cf91 Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Fri, 24 Jul 2015 18:19:58 -0400 Subject: [PATCH 5893/7006] md: setup safemode_timer before it's being used We used to set up the safemode_timer timer in md_run. If md_run would fail before the timer was set up we'd end up trying to modify a timer that doesn't have a callback function when we access safe_delay_store, which would trigger a BUG. neilb: delete init_timer() call as setup_timer() does that. Signed-off-by: Sasha Levin Signed-off-by: NeilBrown --- drivers/md/md.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 84dc5d7a445b3..cdc080bf09d47 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -502,6 +502,8 @@ static void mddev_put(struct mddev *mddev) bioset_free(bs); } +static void md_safemode_timeout(unsigned long data); + void mddev_init(struct mddev *mddev) { mutex_init(&mddev->open_mutex); @@ -509,7 +511,8 @@ void mddev_init(struct mddev *mddev) mutex_init(&mddev->bitmap_info.mutex); INIT_LIST_HEAD(&mddev->disks); INIT_LIST_HEAD(&mddev->all_mddevs); - init_timer(&mddev->safemode_timer); + setup_timer(&mddev->safemode_timer, md_safemode_timeout, + (unsigned long) mddev); atomic_set(&mddev->active, 1); atomic_set(&mddev->openers, 0); atomic_set(&mddev->active_io, 0); @@ -3276,8 +3279,6 @@ int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale) return 0; } -static void md_safemode_timeout(unsigned long data); - static ssize_t safe_delay_show(struct mddev *mddev, char *page) { @@ -5204,8 +5205,6 @@ int md_run(struct mddev *mddev) atomic_set(&mddev->max_corr_read_errors, MD_DEFAULT_MAX_CORRECTED_READ_ERRORS); mddev->safemode = 0; - mddev->safemode_timer.function = md_safemode_timeout; - mddev->safemode_timer.data = (unsigned long) mddev; mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */ mddev->in_sync = 1; smp_wmb(); -- GitLab From b89f704a8ddf7be1a66af9aad350226ae283292f Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 16:54:02 +0800 Subject: [PATCH 5894/7006] md-cluster: use %pU to print UUIDs Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 0072190515e0f..85ef5c5aa350c 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -177,18 +177,6 @@ static void lockres_free(struct dlm_lock_resource *res) kfree(res); } -static char *pretty_uuid(char *dest, char *src) -{ - int i, len = 0; - - for (i = 0; i < 16; i++) { - if (i == 4 || i == 6 || i == 8 || i == 10) - len += sprintf(dest + len, "-"); - len += sprintf(dest + len, "%02x", (__u8)src[i]); - } - return dest; -} - static void add_resync_info(struct mddev *mddev, struct dlm_lock_resource *lockres, sector_t lo, sector_t hi) { @@ -388,7 +376,7 @@ static void process_add_new_disk(struct mddev *mddev, struct cluster_msg *cmsg) int len; len = snprintf(disk_uuid, 64, "DEVICE_UUID="); - pretty_uuid(disk_uuid + len, cmsg->uuid); + sprintf(disk_uuid + len, "%pU", cmsg->uuid); snprintf(raid_slot, 16, "RAID_DISK=%d", cmsg->raid_slot); pr_info("%s:%d Sending kobject change with %s and %s\n", __func__, __LINE__, disk_uuid, raid_slot); init_completion(&cinfo->newdisk_completion); @@ -646,7 +634,7 @@ static int join(struct mddev *mddev, int nodes) mddev->cluster_info = cinfo; memset(str, 0, 64); - pretty_uuid(str, mddev->uuid); + sprintf(str, "%pU", mddev->uuid); ret = dlm_new_lockspace(str, mddev->bitmap_info.cluster_name, DLM_LSFL_FS, LVB_SIZE, &md_ls_ops, mddev, &ops_rv, &cinfo->lockspace); -- GitLab From 05cd0e51769a51f53c68e83976c83653f6ab1595 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 16:54:03 +0800 Subject: [PATCH 5895/7006] md-cluster: split recover_slot for future code reuse Make recover_slot as a wraper to __recover_slot, since the logic of __recover_slot can be reused for the condition when other nodes need to take over the resync job. Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 85ef5c5aa350c..24caabef10cd0 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -269,16 +269,11 @@ static void recover_prep(void *arg) set_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state); } -static void recover_slot(void *arg, struct dlm_slot *slot) +static void __recover_slot(struct mddev *mddev, int slot) { - struct mddev *mddev = arg; struct md_cluster_info *cinfo = mddev->cluster_info; - pr_info("md-cluster: %s Node %d/%d down. My slot: %d. Initiating recovery.\n", - mddev->bitmap_info.cluster_name, - slot->nodeid, slot->slot, - cinfo->slot_number); - set_bit(slot->slot - 1, &cinfo->recovery_map); + set_bit(slot, &cinfo->recovery_map); if (!cinfo->recovery_thread) { cinfo->recovery_thread = md_register_thread(recover_bitmaps, mddev, "recover"); @@ -290,6 +285,20 @@ static void recover_slot(void *arg, struct dlm_slot *slot) md_wakeup_thread(cinfo->recovery_thread); } +static void recover_slot(void *arg, struct dlm_slot *slot) +{ + struct mddev *mddev = arg; + struct md_cluster_info *cinfo = mddev->cluster_info; + + pr_info("md-cluster: %s Node %d/%d down. My slot: %d. Initiating recovery.\n", + mddev->bitmap_info.cluster_name, + slot->nodeid, slot->slot, + cinfo->slot_number); + /* deduct one since dlm slot starts from one while the num of + * cluster-md begins with 0 */ + __recover_slot(mddev, slot->slot - 1); +} + static void recover_done(void *arg, struct dlm_slot *slots, int num_slots, int our_slot, uint32_t generation) -- GitLab From dc737d7c3d62d2cd2b62c7739aaa7604330c3dd8 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 16:54:04 +0800 Subject: [PATCH 5896/7006] md-cluster: transfer the resync ownership to another node When node A stops an array while the array is doing a resync, we need to let another node B take over the resync task. To achieve the goal, we need the A send an explicit BITMAP_NEEDS_SYNC message to the cluster. And the node B which received that message will invoke __recover_slot to do resync. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 15 +++++++++++++++ drivers/md/md.c | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 24caabef10cd0..47199addae042 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -75,6 +75,7 @@ enum msg_type { NEWDISK, REMOVE, RE_ADD, + BITMAP_NEEDS_SYNC, }; struct cluster_msg { @@ -454,6 +455,11 @@ static void process_recvd_msg(struct mddev *mddev, struct cluster_msg *msg) __func__, __LINE__, msg->slot); process_readd_disk(mddev, msg); break; + case BITMAP_NEEDS_SYNC: + pr_info("%s: %d Received BITMAP_NEEDS_SYNC from %d\n", + __func__, __LINE__, msg->slot); + __recover_slot(mddev, msg->slot); + break; default: pr_warn("%s:%d Received unknown message from %d\n", __func__, __LINE__, msg->slot); @@ -814,8 +820,17 @@ static int resync_start(struct mddev *mddev, sector_t lo, sector_t hi) static void resync_finish(struct mddev *mddev) { + struct md_cluster_info *cinfo = mddev->cluster_info; + struct cluster_msg cmsg; + int slot = cinfo->slot_number - 1; + pr_info("%s:%d\n", __func__, __LINE__); resync_send(mddev, RESYNCING, 0, 0); + if (test_bit(MD_RECOVERY_INTR, &mddev->recovery)) { + cmsg.type = cpu_to_le32(BITMAP_NEEDS_SYNC); + cmsg.slot = cpu_to_le32(slot); + sendmsg(cinfo, &cmsg); + } } static int area_resyncing(struct mddev *mddev, int direction, diff --git a/drivers/md/md.c b/drivers/md/md.c index cdc080bf09d47..c0637603a3918 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7959,9 +7959,6 @@ void md_do_sync(struct md_thread *thread) /* tell personality that we are finished */ mddev->pers->sync_request(mddev, max_sectors, &skipped); - if (mddev_is_clustered(mddev)) - md_cluster_ops->resync_finish(mddev); - if (!test_bit(MD_RECOVERY_CHECK, &mddev->recovery) && mddev->curr_resync > 2) { if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) { @@ -7995,6 +7992,9 @@ void md_do_sync(struct md_thread *thread) } } skip: + if (mddev_is_clustered(mddev)) + md_cluster_ops->resync_finish(mddev); + set_bit(MD_CHANGE_DEVS, &mddev->flags); spin_lock(&mddev->lock); -- GitLab From 66099bb0ee6c20f91ace3fa5f82202fbceb67d8e Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:15 +0800 Subject: [PATCH 5897/7006] md-cluster: fix deadlock issue on message lock There is problem with previous communication mechanism, and we got below deadlock scenario with cluster which has 3 nodes. Sender Receiver Receiver token(EX) message(EX) writes message downconverts message(CR) requests ack(EX) get message(CR) gets message(CR) reads message reads message requests EX on message requests EX on message To fix this problem, we do the following changes: 1. the sender downconverts MESSAGE to CW rather than CR. 2. and the receiver request PR lock not EX lock on message. And in case we failed to down-convert EX to CW on message, it is better to unlock message otherthan still hold the lock. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Lidong Zhong Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- Documentation/md-cluster.txt | 4 ++-- drivers/md/md-cluster.c | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Documentation/md-cluster.txt b/Documentation/md-cluster.txt index de1af7db33551..1b794369e03a4 100644 --- a/Documentation/md-cluster.txt +++ b/Documentation/md-cluster.txt @@ -91,7 +91,7 @@ The algorithm is: this message inappropriate or redundant. 3. sender write LVB. - sender down-convert MESSAGE from EX to CR + sender down-convert MESSAGE from EX to CW sender try to get EX of ACK [ wait until all receiver has *processed* the MESSAGE ] @@ -112,7 +112,7 @@ The algorithm is: sender down-convert ACK from EX to CR sender release MESSAGE sender release TOKEN - receiver upconvert to EX of MESSAGE + receiver upconvert to PR of MESSAGE receiver get CR of ACK receiver release MESSAGE diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 47199addae042..85b7836fb4b5f 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -488,8 +488,8 @@ static void recv_daemon(struct md_thread *thread) /*release CR on ack_lockres*/ dlm_unlock_sync(ack_lockres); - /*up-convert to EX on message_lockres*/ - dlm_lock_sync(message_lockres, DLM_LOCK_EX); + /*up-convert to PR on message_lockres*/ + dlm_lock_sync(message_lockres, DLM_LOCK_PR); /*get CR on ack_lockres again*/ dlm_lock_sync(ack_lockres, DLM_LOCK_CR); /*release CR on message_lockres*/ @@ -522,7 +522,7 @@ static void unlock_comm(struct md_cluster_info *cinfo) * The function: * 1. Grabs the message lockresource in EX mode * 2. Copies the message to the message LVB - * 3. Downconverts message lockresource to CR + * 3. Downconverts message lockresource to CW * 4. Upconverts ack lock resource from CR to EX. This forces the BAST on other nodes * and the other nodes read the message. The thread will wait here until all other * nodes have released ack lock resource. @@ -543,12 +543,12 @@ static int __sendmsg(struct md_cluster_info *cinfo, struct cluster_msg *cmsg) memcpy(cinfo->message_lockres->lksb.sb_lvbptr, (void *)cmsg, sizeof(struct cluster_msg)); - /*down-convert EX to CR on Message*/ - error = dlm_lock_sync(cinfo->message_lockres, DLM_LOCK_CR); + /*down-convert EX to CW on Message*/ + error = dlm_lock_sync(cinfo->message_lockres, DLM_LOCK_CW); if (error) { - pr_err("md-cluster: failed to convert EX to CR on MESSAGE(%d)\n", + pr_err("md-cluster: failed to convert EX to CW on MESSAGE(%d)\n", error); - goto failed_message; + goto failed_ack; } /*up-convert CR to EX on Ack*/ -- GitLab From b83d51c0785c34d552111f38fbecbe00cd58b913 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:16 +0800 Subject: [PATCH 5898/7006] md-cluster: init completion within lockres_init We should init completion within lockres_init, otherwise completion could be initialized more than one time during it's life cycle. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 85b7836fb4b5f..2a57f193b103a 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -100,7 +100,6 @@ static int dlm_lock_sync(struct dlm_lock_resource *res, int mode) { int ret = 0; - init_completion(&res->completion); ret = dlm_lock(res->ls, mode, &res->lksb, res->flags, res->name, strlen(res->name), 0, sync_ast, res, res->bast); @@ -125,6 +124,7 @@ static struct dlm_lock_resource *lockres_init(struct mddev *mddev, res = kzalloc(sizeof(struct dlm_lock_resource), GFP_KERNEL); if (!res) return NULL; + init_completion(&res->completion); res->ls = cinfo->lockspace; res->mddev = mddev; namelen = strlen(name); @@ -169,7 +169,6 @@ static void lockres_free(struct dlm_lock_resource *res) if (!res) return; - init_completion(&res->completion); dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res); wait_for_completion(&res->completion); -- GitLab From b5ef56789b808a57fcd07271ff509911662fd877 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:17 +0800 Subject: [PATCH 5899/7006] md-cluster: add the error check if failed to get dlm lock In complicated cluster environment, it is possible that the dlm lock couldn't be get/convert on purpose, the related err info is added for better debug potential issue. For lockres_free, if the lock is blocking by a lock request or conversion request, then dlm_unlock just put it back to grant queue, so need to ensure the lock is free finally. Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 2a57f193b103a..b80a689aad043 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -166,10 +166,24 @@ out_err: static void lockres_free(struct dlm_lock_resource *res) { + int ret; + if (!res) return; - dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res); + /* cancel a lock request or a conversion request that is blocked */ + res->flags |= DLM_LKF_CANCEL; +retry: + ret = dlm_unlock(res->ls, res->lksb.sb_lkid, 0, &res->lksb, res); + if (unlikely(ret != 0)) { + pr_info("%s: failed to unlock %s return %d\n", __func__, res->name, ret); + + /* if a lock conversion is cancelled, then the lock is put + * back to grant queue, need to ensure it is unlocked */ + if (ret == -DLM_ECANCEL) + goto retry; + } + res->flags &= ~DLM_LKF_CANCEL; wait_for_completion(&res->completion); kfree(res->name); @@ -474,6 +488,7 @@ static void recv_daemon(struct md_thread *thread) struct dlm_lock_resource *ack_lockres = cinfo->ack_lockres; struct dlm_lock_resource *message_lockres = cinfo->message_lockres; struct cluster_msg msg; + int ret; /*get CR on Message*/ if (dlm_lock_sync(message_lockres, DLM_LOCK_CR)) { @@ -486,13 +501,21 @@ static void recv_daemon(struct md_thread *thread) process_recvd_msg(thread->mddev, &msg); /*release CR on ack_lockres*/ - dlm_unlock_sync(ack_lockres); + ret = dlm_unlock_sync(ack_lockres); + if (unlikely(ret != 0)) + pr_info("unlock ack failed return %d\n", ret); /*up-convert to PR on message_lockres*/ - dlm_lock_sync(message_lockres, DLM_LOCK_PR); + ret = dlm_lock_sync(message_lockres, DLM_LOCK_PR); + if (unlikely(ret != 0)) + pr_info("lock PR on msg failed return %d\n", ret); /*get CR on ack_lockres again*/ - dlm_lock_sync(ack_lockres, DLM_LOCK_CR); + ret = dlm_lock_sync(ack_lockres, DLM_LOCK_CR); + if (unlikely(ret != 0)) + pr_info("lock CR on ack failed return %d\n", ret); /*release CR on message_lockres*/ - dlm_unlock_sync(message_lockres); + ret = dlm_unlock_sync(message_lockres); + if (unlikely(ret != 0)) + pr_info("unlock msg failed return %d\n", ret); } /* lock_comm() @@ -567,7 +590,13 @@ static int __sendmsg(struct md_cluster_info *cinfo, struct cluster_msg *cmsg) } failed_ack: - dlm_unlock_sync(cinfo->message_lockres); + error = dlm_unlock_sync(cinfo->message_lockres); + if (unlikely(error != 0)) { + pr_err("md-cluster: failed convert to NL on MESSAGE(%d)\n", + error); + /* in case the message can't be released due to some reason */ + goto failed_ack; + } failed_message: return error; } -- GitLab From 9e3072e373320b331512e24f6650efa0a09720af Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:18 +0800 Subject: [PATCH 5900/7006] md-cluster: init suspend_list and suspend_lock early in join If the node just join the cluster, and receive the msg from other nodes before init suspend_list, it will cause kernel crash due to NULL pointer dereference, so move the initializations early to fix the bug. md-cluster: Joined cluster 3578507b-e0cb-6d4f-6322-696cd7b1b10c slot 3 BUG: unable to handle kernel NULL pointer dereference at (null) ... ... ... Call Trace: [] process_recvd_msg+0x2e4/0x330 [md_cluster] [] recv_daemon+0x96/0x170 [md_cluster] [] md_thread+0x11d/0x170 [md_mod] [] kthread+0xb4/0xc0 [] ret_from_fork+0x7c/0xb0 ... ... ... RIP [] __remove_suspend_info+0x11/0xa0 [md_cluster] Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index b80a689aad043..6f1ea3c787f29 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -671,6 +671,8 @@ static int join(struct mddev *mddev, int nodes) if (!cinfo) return -ENOMEM; + INIT_LIST_HEAD(&cinfo->suspend_list); + spin_lock_init(&cinfo->suspend_lock); init_completion(&cinfo->completion); mutex_init(&cinfo->sb_mutex); @@ -736,9 +738,6 @@ static int join(struct mddev *mddev, int nodes) goto err; } - INIT_LIST_HEAD(&cinfo->suspend_list); - spin_lock_init(&cinfo->suspend_lock); - ret = gather_all_resync_info(mddev, nodes); if (ret) goto err; -- GitLab From b2b9bfff0aa721a04a3924ed451c417d2bd9ed15 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:19 +0800 Subject: [PATCH 5901/7006] md-cluster: remove the unused sb_lock The sb_lock is not used anywhere, so let's remove it. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 6f1ea3c787f29..057a9733f7489 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -52,7 +52,6 @@ struct md_cluster_info { dlm_lockspace_t *lockspace; int slot_number; struct completion completion; - struct dlm_lock_resource *sb_lock; struct mutex sb_mutex; struct dlm_lock_resource *bitmap_lockres; struct list_head suspend_list; @@ -692,12 +691,6 @@ static int join(struct mddev *mddev, int nodes) ret = -ERANGE; goto err; } - cinfo->sb_lock = lockres_init(mddev, "cmd-super", - NULL, 0); - if (!cinfo->sb_lock) { - ret = -ENOMEM; - goto err; - } /* Initiate the communication resources */ ret = -ENOMEM; cinfo->recv_thread = md_register_thread(recv_daemon, mddev, "cluster_recv"); @@ -749,7 +742,6 @@ err: lockres_free(cinfo->ack_lockres); lockres_free(cinfo->no_new_dev_lockres); lockres_free(cinfo->bitmap_lockres); - lockres_free(cinfo->sb_lock); if (cinfo->lockspace) dlm_release_lockspace(cinfo->lockspace, 2); mddev->cluster_info = NULL; @@ -770,7 +762,6 @@ static int leave(struct mddev *mddev) lockres_free(cinfo->token_lockres); lockres_free(cinfo->ack_lockres); lockres_free(cinfo->no_new_dev_lockres); - lockres_free(cinfo->sb_lock); lockres_free(cinfo->bitmap_lockres); dlm_release_lockspace(cinfo->lockspace, 2); return 0; -- GitLab From 6e6d9f2cda47745a3abcb6609b1dee0e831161d8 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:20 +0800 Subject: [PATCH 5902/7006] md-cluster: add missed lockres_free We also need to free the lock resource before goto out. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 057a9733f7489..411b4306840ff 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -647,8 +647,10 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots) lockres_free(bm_lockres); continue; } - if (ret) + if (ret) { + lockres_free(bm_lockres); goto out; + } /* TODO: Read the disk bitmap sb and check if it needs recovery */ dlm_unlock_sync(bm_lockres); lockres_free(bm_lockres); -- GitLab From eece075cda38f55fc5829b5f9ec5fb919c561d81 Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:21 +0800 Subject: [PATCH 5903/7006] md-cluster: only call complete(&cinfo->completion) when node join cluster Introduce MD_CLUSTER_BEGIN_JOIN_CLUSTER flag to make sure complete(&cinfo->completion) is only be invoked when node join cluster. Otherwise node failure could also call the complete, and it doesn't make sense to do it. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 411b4306840ff..29f65e2be0253 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -45,6 +45,7 @@ struct resync_info { /* md_cluster_info flags */ #define MD_CLUSTER_WAITING_FOR_NEWDISK 1 #define MD_CLUSTER_SUSPEND_READ_BALANCING 2 +#define MD_CLUSTER_BEGIN_JOIN_CLUSTER 3 struct md_cluster_info { @@ -320,10 +321,17 @@ static void recover_done(void *arg, struct dlm_slot *slots, struct md_cluster_info *cinfo = mddev->cluster_info; cinfo->slot_number = our_slot; - complete(&cinfo->completion); + /* completion is only need to be complete when node join cluster, + * it doesn't need to run during another node's failure */ + if (test_bit(MD_CLUSTER_BEGIN_JOIN_CLUSTER, &cinfo->state)) { + complete(&cinfo->completion); + clear_bit(MD_CLUSTER_BEGIN_JOIN_CLUSTER, &cinfo->state); + } clear_bit(MD_CLUSTER_SUSPEND_READ_BALANCING, &cinfo->state); } +/* the ops is called when node join the cluster, and do lock recovery + * if node failure occurs */ static const struct dlm_lockspace_ops md_ls_ops = { .recover_prep = recover_prep, .recover_slot = recover_slot, @@ -675,6 +683,7 @@ static int join(struct mddev *mddev, int nodes) INIT_LIST_HEAD(&cinfo->suspend_list); spin_lock_init(&cinfo->suspend_lock); init_completion(&cinfo->completion); + set_bit(MD_CLUSTER_BEGIN_JOIN_CLUSTER, &cinfo->state); mutex_init(&cinfo->sb_mutex); mddev->cluster_info = cinfo; -- GitLab From abb9b22ac948000ae156cd2d115c8632ec30a2ce Mon Sep 17 00:00:00 2001 From: Guoqing Jiang Date: Fri, 10 Jul 2015 17:01:22 +0800 Subject: [PATCH 5904/7006] md-cluster: Read the disk bitmap sb and check if it needs recovery In gather_all_resync_info, we need to read the disk bitmap sb and check if it needs recovery. Reviewed-by: Goldwyn Rodrigues Signed-off-by: Guoqing Jiang Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index 29f65e2be0253..c35a03a7eb118 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -625,6 +625,7 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots) struct dlm_lock_resource *bm_lockres; struct suspend_info *s; char str[64]; + sector_t lo, hi; for (i = 0; i < total_slots; i++) { @@ -659,7 +660,20 @@ static int gather_all_resync_info(struct mddev *mddev, int total_slots) lockres_free(bm_lockres); goto out; } - /* TODO: Read the disk bitmap sb and check if it needs recovery */ + + /* Read the disk bitmap sb and check if it needs recovery */ + ret = bitmap_copy_from_slot(mddev, i, &lo, &hi, false); + if (ret) { + pr_warn("md-cluster: Could not gather bitmaps from slot %d", i); + lockres_free(bm_lockres); + continue; + } + if ((hi > 0) && (lo < mddev->recovery_cp)) { + set_bit(MD_RECOVERY_NEEDED, &mddev->recovery); + mddev->recovery_cp = lo; + md_check_recovery(mddev); + } + dlm_unlock_sync(bm_lockres); lockres_free(bm_lockres); } -- GitLab From 6022e75bf0686799a6ecca3c33a669e6c70e9d26 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Thu, 13 Aug 2015 12:32:55 +1000 Subject: [PATCH 5905/7006] md: extend spinlock protection in register_md_cluster_operations This code looks racy. The only possible race is if two modules try to register at the same time and that won't happen. But make the code look safe anyway. Signed-off-by: NeilBrown --- drivers/md/md.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index c0637603a3918..7d5a6cede9b07 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -7427,15 +7427,19 @@ int unregister_md_personality(struct md_personality *p) } EXPORT_SYMBOL(unregister_md_personality); -int register_md_cluster_operations(struct md_cluster_operations *ops, struct module *module) +int register_md_cluster_operations(struct md_cluster_operations *ops, + struct module *module) { - if (md_cluster_ops != NULL) - return -EALREADY; + int ret = 0; spin_lock(&pers_lock); - md_cluster_ops = ops; - md_cluster_mod = module; + if (md_cluster_ops != NULL) + ret = -EALREADY; + else { + md_cluster_ops = ops; + md_cluster_mod = module; + } spin_unlock(&pers_lock); - return 0; + return ret; } EXPORT_SYMBOL(register_md_cluster_operations); -- GitLab From 18b9f67962eb890da0c053e04c3cf0e91871d4fa Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Aug 2015 10:22:00 +1000 Subject: [PATCH 5906/7006] md-cluster: remove inappropriate try_module_get from join() md_setup_cluster already calls try_module_get(), so this try_module_get isn't needed. Also, there is no matching module_put (except in error patch), so this leaves an unbalanced module count. Signed-off-by: NeilBrown --- drivers/md/md-cluster.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c index c35a03a7eb118..11e3bc9d2a4b8 100644 --- a/drivers/md/md-cluster.c +++ b/drivers/md/md-cluster.c @@ -687,9 +687,6 @@ static int join(struct mddev *mddev, int nodes) int ret, ops_rv; char str[64]; - if (!try_module_get(THIS_MODULE)) - return -ENOENT; - cinfo = kzalloc(sizeof(struct md_cluster_info), GFP_KERNEL); if (!cinfo) return -ENOMEM; @@ -771,7 +768,6 @@ err: dlm_release_lockspace(cinfo->lockspace, 2); mddev->cluster_info = NULL; kfree(cinfo); - module_put(THIS_MODULE); return ret; } -- GitLab From 55ce74d4bfe1b9444436264c637f39a152d1e5ac Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Aug 2015 11:11:10 +1000 Subject: [PATCH 5907/7006] md/raid1: ensure device failure recorded before write request returns. When a write to one of the legs of a RAID1 fails, the failure is recorded in the metadata of the other leg(s) so that after a restart the data on the failed drive wont be trusted even if that drive seems to be working again (maybe a cable was unplugged). Similarly when we record a bad-block in response to a write failure, we must not let the write complete until the bad-block update is safe. Currently there is no interlock between the write request completing and the metadata update. So it is possible that the write will complete, the app will confirm success in some way, and then the machine will crash before the metadata update completes. This is an extremely small hole for a racy to fit in, but it is theoretically possible and so should be closed. So: - set MD_CHANGE_PENDING when requesting a metadata update for a failed device, so we can know with certainty when it completes - queue requests that experienced an error on a new queue which is only processed after the metadata update completes - call raid_end_bio_io() on bios in that queue when the time comes. Signed-off-by: NeilBrown --- drivers/md/md.c | 1 + drivers/md/raid1.c | 29 ++++++++++++++++++++++++++++- drivers/md/raid1.h | 5 +++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/md/md.c b/drivers/md/md.c index 7d5a6cede9b07..8644ce76e5f86 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -8629,6 +8629,7 @@ int rdev_set_badblocks(struct md_rdev *rdev, sector_t s, int sectors, /* Make sure they get written out promptly */ sysfs_notify_dirent_safe(rdev->sysfs_state); set_bit(MD_CHANGE_CLEAN, &rdev->mddev->flags); + set_bit(MD_CHANGE_PENDING, &rdev->mddev->flags); md_wakeup_thread(rdev->mddev->thread); } return rv; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 742b50794dfd6..3d9ca836247f6 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1508,6 +1508,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) */ set_bit(MD_RECOVERY_INTR, &mddev->recovery); set_bit(MD_CHANGE_DEVS, &mddev->flags); + set_bit(MD_CHANGE_PENDING, &mddev->flags); printk(KERN_ALERT "md/raid1:%s: Disk failure on %s, disabling device.\n" "md/raid1:%s: Operation continuing on %d devices.\n", @@ -2289,6 +2290,7 @@ static void handle_sync_write_finished(struct r1conf *conf, struct r1bio *r1_bio static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio) { int m; + bool fail = false; for (m = 0; m < conf->raid_disks * 2 ; m++) if (r1_bio->bios[m] == IO_MADE_GOOD) { struct md_rdev *rdev = conf->mirrors[m].rdev; @@ -2301,6 +2303,7 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio) * narrow down and record precise write * errors. */ + fail = true; if (!narrow_write_error(r1_bio, m)) { md_error(conf->mddev, conf->mirrors[m].rdev); @@ -2312,7 +2315,13 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio) } if (test_bit(R1BIO_WriteError, &r1_bio->state)) close_write(r1_bio); - raid_end_bio_io(r1_bio); + if (fail) { + spin_lock_irq(&conf->device_lock); + list_add(&r1_bio->retry_list, &conf->bio_end_io_list); + spin_unlock_irq(&conf->device_lock); + md_wakeup_thread(conf->mddev->thread); + } else + raid_end_bio_io(r1_bio); } static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio) @@ -2418,6 +2427,23 @@ static void raid1d(struct md_thread *thread) md_check_recovery(mddev); + if (!list_empty_careful(&conf->bio_end_io_list) && + !test_bit(MD_CHANGE_PENDING, &mddev->flags)) { + LIST_HEAD(tmp); + spin_lock_irqsave(&conf->device_lock, flags); + if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) { + list_add(&tmp, &conf->bio_end_io_list); + list_del_init(&conf->bio_end_io_list); + } + spin_unlock_irqrestore(&conf->device_lock, flags); + while (!list_empty(&tmp)) { + r1_bio = list_first_entry(&conf->bio_end_io_list, + struct r1bio, retry_list); + list_del(&r1_bio->retry_list); + raid_end_bio_io(r1_bio); + } + } + blk_start_plug(&plug); for (;;) { @@ -2819,6 +2845,7 @@ static struct r1conf *setup_conf(struct mddev *mddev) conf->raid_disks = mddev->raid_disks; conf->mddev = mddev; INIT_LIST_HEAD(&conf->retry_list); + INIT_LIST_HEAD(&conf->bio_end_io_list); spin_lock_init(&conf->resync_lock); init_waitqueue_head(&conf->wait_barrier); diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h index 14ebb288c1ef9..c52d7139c5d76 100644 --- a/drivers/md/raid1.h +++ b/drivers/md/raid1.h @@ -61,6 +61,11 @@ struct r1conf { * block, or anything else. */ struct list_head retry_list; + /* A separate list of r1bio which just need raid_end_bio_io called. + * This mustn't happen for writes which had any errors if the superblock + * needs to be written. + */ + struct list_head bio_end_io_list; /* queue pending writes to be submitted on unplug */ struct bio_list pending_bio_list; -- GitLab From 95af587e95aacb9cfda4a9641069a5244a540dc8 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Aug 2015 11:26:17 +1000 Subject: [PATCH 5908/7006] md/raid10: ensure device failure recorded before write request returns. When a write to one of the legs of a RAID10 fails, the failure is recorded in the metadata of the other legs so that after a restart the data on the failed drive wont be trusted even if that drive seems to be working again (maybe a cable was unplugged). Currently there is no interlock between the write request completing and the metadata update. So it is possible that the write will complete, the app will confirm success in some way, and then the machine will crash before the metadata update completes. This is an extremely small hole for a racy to fit in, but it is theoretically possible and so should be closed. So: - set MD_CHANGE_PENDING when requesting a metadata update for a failed device, so we can know with certainty when it completes - queue requests that experienced an error on a new queue which is only processed after the metadata update completes - call raid_end_bio_io() on bios in that queue when the time comes. Signed-off-by: NeilBrown --- drivers/md/raid10.c | 29 ++++++++++++++++++++++++++++- drivers/md/raid10.h | 6 ++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index dcc0e9b3ee921..a14c304aa751c 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -1681,6 +1681,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) set_bit(Blocked, &rdev->flags); set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); + set_bit(MD_CHANGE_PENDING, &mddev->flags); spin_unlock_irqrestore(&conf->device_lock, flags); printk(KERN_ALERT "md/raid10:%s: Disk failure on %s, disabling device.\n" @@ -2738,6 +2739,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) } put_buf(r10_bio); } else { + bool fail = false; for (m = 0; m < conf->copies; m++) { int dev = r10_bio->devs[m].devnum; struct bio *bio = r10_bio->devs[m].bio; @@ -2750,6 +2752,7 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) rdev_dec_pending(rdev, conf->mddev); } else if (bio != NULL && !test_bit(BIO_UPTODATE, &bio->bi_flags)) { + fail = true; if (!narrow_write_error(r10_bio, m)) { md_error(conf->mddev, rdev); set_bit(R10BIO_Degraded, @@ -2770,7 +2773,13 @@ static void handle_write_completed(struct r10conf *conf, struct r10bio *r10_bio) if (test_bit(R10BIO_WriteError, &r10_bio->state)) close_write(r10_bio); - raid_end_bio_io(r10_bio); + if (fail) { + spin_lock_irq(&conf->device_lock); + list_add(&r10_bio->retry_list, &conf->bio_end_io_list); + spin_unlock_irq(&conf->device_lock); + md_wakeup_thread(conf->mddev->thread); + } else + raid_end_bio_io(r10_bio); } } @@ -2785,6 +2794,23 @@ static void raid10d(struct md_thread *thread) md_check_recovery(mddev); + if (!list_empty_careful(&conf->bio_end_io_list) && + !test_bit(MD_CHANGE_PENDING, &mddev->flags)) { + LIST_HEAD(tmp); + spin_lock_irqsave(&conf->device_lock, flags); + if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) { + list_add(&tmp, &conf->bio_end_io_list); + list_del_init(&conf->bio_end_io_list); + } + spin_unlock_irqrestore(&conf->device_lock, flags); + while (!list_empty(&tmp)) { + r10_bio = list_first_entry(&conf->bio_end_io_list, + struct r10bio, retry_list); + list_del(&r10_bio->retry_list); + raid_end_bio_io(r10_bio); + } + } + blk_start_plug(&plug); for (;;) { @@ -3559,6 +3585,7 @@ static struct r10conf *setup_conf(struct mddev *mddev) conf->reshape_safe = conf->reshape_progress; spin_lock_init(&conf->device_lock); INIT_LIST_HEAD(&conf->retry_list); + INIT_LIST_HEAD(&conf->bio_end_io_list); spin_lock_init(&conf->resync_lock); init_waitqueue_head(&conf->wait_barrier); diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h index 5ee6473ddc2c0..6fc2c75759bf2 100644 --- a/drivers/md/raid10.h +++ b/drivers/md/raid10.h @@ -53,6 +53,12 @@ struct r10conf { sector_t offset_diff; struct list_head retry_list; + /* A separate list of r1bio which just need raid_end_bio_io called. + * This mustn't happen for writes which had any errors if the superblock + * needs to be written. + */ + struct list_head bio_end_io_list; + /* queue pending writes and submit them on unplug */ struct bio_list pending_bio_list; int pending_count; -- GitLab From 34a6f80e1639b124f24b5fadc1d45d69417cbace Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Aug 2015 12:07:57 +1000 Subject: [PATCH 5909/7006] md/raid5: use bio_list for the list of bios to return. This will make it easier to splice two lists together which will be needed in future patch. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 41 +++++++++++++++-------------------------- drivers/md/raid5.h | 2 +- 2 files changed, 16 insertions(+), 27 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 7b0c706f33e74..214dcca0d7f82 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -223,18 +223,14 @@ static int raid6_idx_to_slot(int idx, struct stripe_head *sh, return slot; } -static void return_io(struct bio *return_bi) +static void return_io(struct bio_list *return_bi) { - struct bio *bi = return_bi; - while (bi) { - - return_bi = bi->bi_next; - bi->bi_next = NULL; + struct bio *bi; + while ((bi = bio_list_pop(return_bi)) != NULL) { bi->bi_iter.bi_size = 0; trace_block_bio_complete(bdev_get_queue(bi->bi_bdev), bi, 0); bio_endio(bi, 0); - bi = return_bi; } } @@ -1177,7 +1173,7 @@ async_copy_data(int frombio, struct bio *bio, struct page **page, static void ops_complete_biofill(void *stripe_head_ref) { struct stripe_head *sh = stripe_head_ref; - struct bio *return_bi = NULL; + struct bio_list return_bi = BIO_EMPTY_LIST; int i; pr_debug("%s: stripe %llu\n", __func__, @@ -1201,17 +1197,15 @@ static void ops_complete_biofill(void *stripe_head_ref) while (rbi && rbi->bi_iter.bi_sector < dev->sector + STRIPE_SECTORS) { rbi2 = r5_next_bio(rbi, dev->sector); - if (!raid5_dec_bi_active_stripes(rbi)) { - rbi->bi_next = return_bi; - return_bi = rbi; - } + if (!raid5_dec_bi_active_stripes(rbi)) + bio_list_add(&return_bi, rbi); rbi = rbi2; } } } clear_bit(STRIPE_BIOFILL_RUN, &sh->state); - return_io(return_bi); + return_io(&return_bi); set_bit(STRIPE_HANDLE, &sh->state); release_stripe(sh); @@ -3071,7 +3065,7 @@ static void stripe_set_idx(sector_t stripe, struct r5conf *conf, int previous, static void handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, struct stripe_head_state *s, int disks, - struct bio **return_bi) + struct bio_list *return_bi) { int i; BUG_ON(sh->batch_head); @@ -3115,8 +3109,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, clear_bit(BIO_UPTODATE, &bi->bi_flags); if (!raid5_dec_bi_active_stripes(bi)) { md_write_end(conf->mddev); - bi->bi_next = *return_bi; - *return_bi = bi; + bio_list_add(return_bi, bi); } bi = nextbi; } @@ -3139,8 +3132,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, clear_bit(BIO_UPTODATE, &bi->bi_flags); if (!raid5_dec_bi_active_stripes(bi)) { md_write_end(conf->mddev); - bi->bi_next = *return_bi; - *return_bi = bi; + bio_list_add(return_bi, bi); } bi = bi2; } @@ -3162,10 +3154,8 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh, struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector); clear_bit(BIO_UPTODATE, &bi->bi_flags); - if (!raid5_dec_bi_active_stripes(bi)) { - bi->bi_next = *return_bi; - *return_bi = bi; - } + if (!raid5_dec_bi_active_stripes(bi)) + bio_list_add(return_bi, bi); bi = nextbi; } } @@ -3444,7 +3434,7 @@ static void break_stripe_batch_list(struct stripe_head *head_sh, * never LOCKED, so we don't need to test 'failed' directly. */ static void handle_stripe_clean_event(struct r5conf *conf, - struct stripe_head *sh, int disks, struct bio **return_bi) + struct stripe_head *sh, int disks, struct bio_list *return_bi) { int i; struct r5dev *dev; @@ -3478,8 +3468,7 @@ returnbi: wbi2 = r5_next_bio(wbi, dev->sector); if (!raid5_dec_bi_active_stripes(wbi)) { md_write_end(conf->mddev); - wbi->bi_next = *return_bi; - *return_bi = wbi; + bio_list_add(return_bi, wbi); } wbi = wbi2; } @@ -4612,7 +4601,7 @@ finish: md_wakeup_thread(conf->mddev->thread); } - return_io(s.return_bi); + return_io(&s.return_bi); clear_bit_unlock(STRIPE_ACTIVE, &sh->state); } diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index d05144278690c..1de82a6e4c23c 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -265,7 +265,7 @@ struct stripe_head_state { int dec_preread_active; unsigned long ops_request; - struct bio *return_bi; + struct bio_list return_bi; struct md_rdev *blocked_rdev; int handle_bad_blocks; }; -- GitLab From c3cce6cda162eb2b2960a85d9c8992f4f3be85d0 Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 14 Aug 2015 12:47:33 +1000 Subject: [PATCH 5910/7006] md/raid5: ensure device failure recorded before write request returns. When a write to one of the devices of a RAID5/6 fails, the failure is recorded in the metadata of the other devices so that after a restart the data on the failed drive wont be trusted even if that drive seems to be working again (maybe a cable was unplugged). Similarly when we record a bad-block in response to a write failure, we must not let the write complete until the bad-block update is safe. Currently there is no interlock between the write request completing and the metadata update. So it is possible that the write will complete, the app will confirm success in some way, and then the machine will crash before the metadata update completes. This is an extremely small hole for a racy to fit in, but it is theoretically possible and so should be closed. So: - set MD_CHANGE_PENDING when requesting a metadata update for a failed device, so we can know with certainty when it completes - queue requests that completed when MD_CHANGE_PENDING is set to only be processed after the metadata update completes - call raid_end_bio_io() on bios in that queue when the time comes. Signed-off-by: NeilBrown --- drivers/md/raid5.c | 24 +++++++++++++++++++++++- drivers/md/raid5.h | 3 +++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 214dcca0d7f82..4195064460d0e 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -2513,6 +2513,7 @@ static void error(struct mddev *mddev, struct md_rdev *rdev) set_bit(Blocked, &rdev->flags); set_bit(Faulty, &rdev->flags); set_bit(MD_CHANGE_DEVS, &mddev->flags); + set_bit(MD_CHANGE_PENDING, &mddev->flags); printk(KERN_ALERT "md/raid:%s: Disk failure on %s, disabling device.\n" "md/raid:%s: Operation continuing on %d devices.\n", @@ -4601,7 +4602,15 @@ finish: md_wakeup_thread(conf->mddev->thread); } - return_io(&s.return_bi); + if (!bio_list_empty(&s.return_bi)) { + if (test_bit(MD_CHANGE_PENDING, &conf->mddev->flags)) { + spin_lock_irq(&conf->device_lock); + bio_list_merge(&conf->return_bi, &s.return_bi); + spin_unlock_irq(&conf->device_lock); + md_wakeup_thread(conf->mddev->thread); + } else + return_io(&s.return_bi); + } clear_bit_unlock(STRIPE_ACTIVE, &sh->state); } @@ -5817,6 +5826,18 @@ static void raid5d(struct md_thread *thread) md_check_recovery(mddev); + if (!bio_list_empty(&conf->return_bi) && + !test_bit(MD_CHANGE_PENDING, &mddev->flags)) { + struct bio_list tmp = BIO_EMPTY_LIST; + spin_lock_irq(&conf->device_lock); + if (!test_bit(MD_CHANGE_PENDING, &mddev->flags)) { + bio_list_merge(&tmp, &conf->return_bi); + bio_list_init(&conf->return_bi); + } + spin_unlock_irq(&conf->device_lock); + return_io(&tmp); + } + blk_start_plug(&plug); handled = 0; spin_lock_irq(&conf->device_lock); @@ -6476,6 +6497,7 @@ static struct r5conf *setup_conf(struct mddev *mddev) INIT_LIST_HEAD(&conf->hold_list); INIT_LIST_HEAD(&conf->delayed_list); INIT_LIST_HEAD(&conf->bitmap_list); + bio_list_init(&conf->return_bi); init_llist_head(&conf->released_stripes); atomic_set(&conf->active_stripes, 0); atomic_set(&conf->preread_active_stripes, 0); diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 1de82a6e4c23c..828c2925e68f3 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -476,6 +476,9 @@ struct r5conf { int skip_copy; /* Don't copy data from bio to stripe cache */ struct list_head *last_hold; /* detect hold_list promotions */ + /* bios to have bi_end_io called after metadata is synced */ + struct bio_list return_bi; + atomic_t reshape_stripes; /* stripes with pending writes for reshape */ /* unfortunately we need two cache names as we temporarily have * two caches. -- GitLab From d1bfc62591a0a5144dc380976e737fbbb4f40f4f Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Mon, 31 Aug 2015 15:46:07 +0300 Subject: [PATCH 5911/7006] ipv4: fix 32b build Address remaining issue after 80ec192. Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- net/ipv4/af_inet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index c2d0ebc628d7a..96773a2f95a7e 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -1496,7 +1496,7 @@ u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_offset) int cpu; for_each_possible_cpu(cpu) { - res += snmp_get_cpu_field(mib, cpu, offt, syncp_offset); + res += snmp_get_cpu_field64(mib, cpu, offt, syncp_offset); } return res; } -- GitLab From 7955323bdcab307bd8b1d5ef7a031e4a3d059da3 Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Tue, 18 Aug 2015 17:54:30 +0800 Subject: [PATCH 5912/7006] btrfs: Update out-of-date "skip parity stripe" comment Because btrfs support scrub raid56 parity stripe now. Signed-off-by: Zhao Lei Signed-off-by: Chris Mason --- fs/btrfs/scrub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index c69c75e7b841e..6f913604799d9 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3280,13 +3280,13 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, scrub_blocked_if_needed(fs_info); } - /* for raid56, we skip parity stripe */ if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { ret = get_raid56_logic_offset(physical, num, map, &logical, &stripe_logical); logical += base; if (ret) { + /* it is parity strip */ stripe_logical += base; stripe_end = stripe_logical + increment; ret = scrub_raid56_parity(sctx, map, scrub_dev, -- GitLab From 8c204c9657c32ec5a259ebf852a767afe7efdafa Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Wed, 19 Aug 2015 15:02:40 +0800 Subject: [PATCH 5913/7006] btrfs: Remove noused chunk_tree and chunk_objectid from scrub_enumerate_chunks and scrub_chunk These variables are not used from introduced version, remove them. Signed-off-by: Zhao Lei Signed-off-by: Chris Mason --- fs/btrfs/scrub.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c index 6f913604799d9..d64f557ea91e4 100644 --- a/fs/btrfs/scrub.c +++ b/fs/btrfs/scrub.c @@ -3493,7 +3493,6 @@ out: static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, struct btrfs_device *scrub_dev, - u64 chunk_tree, u64 chunk_objectid, u64 chunk_offset, u64 length, u64 dev_offset, int is_dev_replace) { @@ -3544,8 +3543,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, struct btrfs_root *root = sctx->dev_root; struct btrfs_fs_info *fs_info = root->fs_info; u64 length; - u64 chunk_tree; - u64 chunk_objectid; u64 chunk_offset; int ret = 0; int slot; @@ -3609,8 +3606,6 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, if (found_key.offset + length <= start) goto skip; - chunk_tree = btrfs_dev_extent_chunk_tree(l, dev_extent); - chunk_objectid = btrfs_dev_extent_chunk_objectid(l, dev_extent); chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent); /* @@ -3643,9 +3638,8 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx, dev_replace->cursor_right = found_key.offset + length; dev_replace->cursor_left = found_key.offset; dev_replace->item_needs_writeback = 1; - ret = scrub_chunk(sctx, scrub_dev, chunk_tree, chunk_objectid, - chunk_offset, length, found_key.offset, - is_dev_replace); + ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length, + found_key.offset, is_dev_replace); /* * flush, submit all pending read and write bios, afterwards -- GitLab From 2c4580454fffbf184fdb9292aa19ab1ffc224add Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Thu, 16 Jul 2015 15:00:46 +0800 Subject: [PATCH 5914/7006] btrfs: Cleanup for btrfs_calc_num_tolerated_disk_barrier_failures 1: Use ARRAY_SIZE(types) to replace a static-value variant: int num_types = 4; 2: Use 'continue' on condition to reduce one level tab if (!XXX) { code; ... } -> if (XXX) continue; code; ... 3: Put setting 'num_tolerated_disk_barrier_failures = 2' to (num_tolerated_disk_barrier_failures > 2) condition to make make logic neat. if (num_tolerated_disk_barrier_failures > 0 && XXX) num_tolerated_disk_barrier_failures = 0; else if (num_tolerated_disk_barrier_failures > 1) { if (XXX) num_tolerated_disk_barrier_failures = 1; else if (XXX) num_tolerated_disk_barrier_failures = 2; -> if (num_tolerated_disk_barrier_failures > 0 && XXX) num_tolerated_disk_barrier_failures = 0; if (num_tolerated_disk_barrier_failures > 1 && XXX) num_tolerated_disk_barrier_failures = ; if (num_tolerated_disk_barrier_failures > 2 && XXX) num_tolerated_disk_barrier_failures = 2; 4: Remove comment of: num_mirrors - 1: if RAID1 or RAID10 is configured and more than 2 mirrors are used. which is not fit with code. Signed-off-by: Zhao Lei Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 73 +++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index cc15514b4a767..51192d94c90cd 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3449,13 +3449,12 @@ int btrfs_calc_num_tolerated_disk_barrier_failures( BTRFS_BLOCK_GROUP_SYSTEM, BTRFS_BLOCK_GROUP_METADATA, BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; - int num_types = 4; int i; int c; int num_tolerated_disk_barrier_failures = (int)fs_info->fs_devices->num_devices; - for (i = 0; i < num_types; i++) { + for (i = 0; i < ARRAY_SIZE(types); i++) { struct btrfs_space_info *tmp; sinfo = NULL; @@ -3473,44 +3472,38 @@ int btrfs_calc_num_tolerated_disk_barrier_failures( down_read(&sinfo->groups_sem); for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { - if (!list_empty(&sinfo->block_groups[c])) { - u64 flags; - - btrfs_get_block_group_info( - &sinfo->block_groups[c], &space); - if (space.total_bytes == 0 || - space.used_bytes == 0) - continue; - flags = space.flags; - /* - * return - * 0: if dup, single or RAID0 is configured for - * any of metadata, system or data, else - * 1: if RAID5 is configured, or if RAID1 or - * RAID10 is configured and only two mirrors - * are used, else - * 2: if RAID6 is configured, else - * num_mirrors - 1: if RAID1 or RAID10 is - * configured and more than - * 2 mirrors are used. - */ - if (num_tolerated_disk_barrier_failures > 0 && - ((flags & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID0)) || - ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) - == 0))) - num_tolerated_disk_barrier_failures = 0; - else if (num_tolerated_disk_barrier_failures > 1) { - if (flags & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_RAID10)) { - num_tolerated_disk_barrier_failures = 1; - } else if (flags & - BTRFS_BLOCK_GROUP_RAID6) { - num_tolerated_disk_barrier_failures = 2; - } - } - } + u64 flags; + + if (list_empty(&sinfo->block_groups[c])) + continue; + + btrfs_get_block_group_info(&sinfo->block_groups[c], + &space); + if (space.total_bytes == 0 || space.used_bytes == 0) + continue; + flags = space.flags; + /* + * return + * 0: if dup, single or RAID0 is configured for + * any of metadata, system or data, else + * 1: if RAID5 is configured, or if RAID1 or + * RAID10 is configured and only two mirrors + * are used, else + * 2: if RAID6 is configured + */ + if (num_tolerated_disk_barrier_failures > 0 && + ((flags & (BTRFS_BLOCK_GROUP_DUP | + BTRFS_BLOCK_GROUP_RAID0)) || + ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0))) + num_tolerated_disk_barrier_failures = 0; + else if (num_tolerated_disk_barrier_failures > 1 && + (flags & (BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID5 | + BTRFS_BLOCK_GROUP_RAID10))) + num_tolerated_disk_barrier_failures = 1; + else if (num_tolerated_disk_barrier_failures > 2 && + (flags & BTRFS_BLOCK_GROUP_RAID6)) + num_tolerated_disk_barrier_failures = 2; } up_read(&sinfo->groups_sem); } -- GitLab From 943c6e9925d90dc80207322b5799d95fb90ffec0 Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Wed, 19 Aug 2015 15:54:15 +0800 Subject: [PATCH 5915/7006] btrfs: Add raid56 support for updating num_tolerated_disk_barrier_failures in btrfs_balance Code for updating fs_info->num_tolerated_disk_barrier_failures in btrfs_balance() lacks raid56 support. Reason: Above code was wroten in 2012-08-01, together with btrfs_calc_num_tolerated_disk_barrier_failures()'s first version. Then, btrfs_calc_num_tolerated_disk_barrier_failures() got updated later to support raid56, but code in btrfs_balance() was not updated together. Fix: Merge above similar code to a common function: btrfs_get_num_tolerated_disk_barrier_failures() and make it support both case. It can fix this bug with a bonus of cleanup, and make these code never in above no-sync state from now on. Suggested-by: Anand Jain Signed-off-by: Zhao Lei Signed-off-by: Chris Mason --- fs/btrfs/disk-io.c | 47 ++++++++++++++++++++++++---------------------- fs/btrfs/disk-io.h | 1 + fs/btrfs/volumes.c | 21 ++++----------------- 3 files changed, 30 insertions(+), 39 deletions(-) diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 51192d94c90cd..0b658d0230f02 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c @@ -3440,6 +3440,26 @@ static int barrier_all_devices(struct btrfs_fs_info *info) return 0; } +int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags) +{ + if ((flags & (BTRFS_BLOCK_GROUP_DUP | + BTRFS_BLOCK_GROUP_RAID0 | + BTRFS_AVAIL_ALLOC_BIT_SINGLE)) || + ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0)) + return 0; + + if (flags & (BTRFS_BLOCK_GROUP_RAID1 | + BTRFS_BLOCK_GROUP_RAID5 | + BTRFS_BLOCK_GROUP_RAID10)) + return 1; + + if (flags & BTRFS_BLOCK_GROUP_RAID6) + return 2; + + pr_warn("BTRFS: unknown raid type: %llu\n", flags); + return 0; +} + int btrfs_calc_num_tolerated_disk_barrier_failures( struct btrfs_fs_info *fs_info) { @@ -3482,28 +3502,11 @@ int btrfs_calc_num_tolerated_disk_barrier_failures( if (space.total_bytes == 0 || space.used_bytes == 0) continue; flags = space.flags; - /* - * return - * 0: if dup, single or RAID0 is configured for - * any of metadata, system or data, else - * 1: if RAID5 is configured, or if RAID1 or - * RAID10 is configured and only two mirrors - * are used, else - * 2: if RAID6 is configured - */ - if (num_tolerated_disk_barrier_failures > 0 && - ((flags & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID0)) || - ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0))) - num_tolerated_disk_barrier_failures = 0; - else if (num_tolerated_disk_barrier_failures > 1 && - (flags & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_RAID10))) - num_tolerated_disk_barrier_failures = 1; - else if (num_tolerated_disk_barrier_failures > 2 && - (flags & BTRFS_BLOCK_GROUP_RAID6)) - num_tolerated_disk_barrier_failures = 2; + + num_tolerated_disk_barrier_failures = min( + num_tolerated_disk_barrier_failures, + btrfs_get_num_tolerated_disk_barrier_failures( + flags)); } up_read(&sinfo->groups_sem); } diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h index d4cbfeeeedd42..bdfb479ea8595 100644 --- a/fs/btrfs/disk-io.h +++ b/fs/btrfs/disk-io.h @@ -139,6 +139,7 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, u64 objectid); int btree_lock_page_hook(struct page *page, void *data, void (*flush_fn)(void *)); +int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags); int btrfs_calc_num_tolerated_disk_barrier_failures( struct btrfs_fs_info *fs_info); int __init btrfs_end_io_wq_init(void); diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index 69520dfa8960d..644e070b3bd24 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c @@ -3585,23 +3585,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl, } while (read_seqretry(&fs_info->profiles_lock, seq)); if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { - int num_tolerated_disk_barrier_failures; - u64 target = bctl->sys.target; - - num_tolerated_disk_barrier_failures = - btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); - if (num_tolerated_disk_barrier_failures > 0 && - (target & - (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_AVAIL_ALLOC_BIT_SINGLE))) - num_tolerated_disk_barrier_failures = 0; - else if (num_tolerated_disk_barrier_failures > 1 && - (target & - (BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10))) - num_tolerated_disk_barrier_failures = 1; - - fs_info->num_tolerated_disk_barrier_failures = - num_tolerated_disk_barrier_failures; + fs_info->num_tolerated_disk_barrier_failures = min( + btrfs_calc_num_tolerated_disk_barrier_failures(fs_info), + btrfs_get_num_tolerated_disk_barrier_failures( + bctl->sys.target)); } ret = insert_balance_item(fs_info->tree_root, bctl); -- GitLab From c6dd6ea55758cf403bdc07a51a06c2a1d474f906 Mon Sep 17 00:00:00 2001 From: Qu Wenruo Date: Thu, 20 Aug 2015 09:30:39 +0800 Subject: [PATCH 5916/7006] btrfs: async_thread: Fix workqueue 'max_active' value when initializing At initializing time, for threshold-able workqueue, it's max_active of kernel workqueue should be 1 and grow if it hits threshold. But due to the bad naming, there is both 'max_active' for kernel workqueue and btrfs workqueue. So wrong value is given at workqueue initialization. This patch fixes it, and to avoid further misunderstanding, change the member name of btrfs_workqueue to 'current_active' and 'limit_active'. Also corresponding comment is added for readability. Reported-by: Alex Lyakas Signed-off-by: Qu Wenruo Signed-off-by: Chris Mason --- fs/btrfs/async-thread.c | 57 ++++++++++++++++++++++++----------------- fs/btrfs/async-thread.h | 2 +- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/fs/btrfs/async-thread.c b/fs/btrfs/async-thread.c index 1ce06c849a86d..3e36e4adc4a35 100644 --- a/fs/btrfs/async-thread.c +++ b/fs/btrfs/async-thread.c @@ -42,8 +42,14 @@ struct __btrfs_workqueue { /* Thresholding related variants */ atomic_t pending; - int max_active; - int current_max; + + /* Up limit of concurrency workers */ + int limit_active; + + /* Current number of concurrency workers */ + int current_active; + + /* Threshold to change current_active */ int thresh; unsigned int count; spinlock_t thres_lock; @@ -88,7 +94,7 @@ BTRFS_WORK_HELPER(scrubnc_helper); BTRFS_WORK_HELPER(scrubparity_helper); static struct __btrfs_workqueue * -__btrfs_alloc_workqueue(const char *name, unsigned int flags, int max_active, +__btrfs_alloc_workqueue(const char *name, unsigned int flags, int limit_active, int thresh) { struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS); @@ -96,26 +102,31 @@ __btrfs_alloc_workqueue(const char *name, unsigned int flags, int max_active, if (!ret) return NULL; - ret->max_active = max_active; + ret->limit_active = limit_active; atomic_set(&ret->pending, 0); if (thresh == 0) thresh = DFT_THRESHOLD; /* For low threshold, disabling threshold is a better choice */ if (thresh < DFT_THRESHOLD) { - ret->current_max = max_active; + ret->current_active = limit_active; ret->thresh = NO_THRESHOLD; } else { - ret->current_max = 1; + /* + * For threshold-able wq, let its concurrency grow on demand. + * Use minimal max_active at alloc time to reduce resource + * usage. + */ + ret->current_active = 1; ret->thresh = thresh; } if (flags & WQ_HIGHPRI) ret->normal_wq = alloc_workqueue("%s-%s-high", flags, - ret->max_active, - "btrfs", name); + ret->current_active, "btrfs", + name); else ret->normal_wq = alloc_workqueue("%s-%s", flags, - ret->max_active, "btrfs", + ret->current_active, "btrfs", name); if (!ret->normal_wq) { kfree(ret); @@ -134,7 +145,7 @@ __btrfs_destroy_workqueue(struct __btrfs_workqueue *wq); struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name, unsigned int flags, - int max_active, + int limit_active, int thresh) { struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_NOFS); @@ -143,14 +154,14 @@ struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name, return NULL; ret->normal = __btrfs_alloc_workqueue(name, flags & ~WQ_HIGHPRI, - max_active, thresh); + limit_active, thresh); if (!ret->normal) { kfree(ret); return NULL; } if (flags & WQ_HIGHPRI) { - ret->high = __btrfs_alloc_workqueue(name, flags, max_active, + ret->high = __btrfs_alloc_workqueue(name, flags, limit_active, thresh); if (!ret->high) { __btrfs_destroy_workqueue(ret->normal); @@ -180,7 +191,7 @@ static inline void thresh_queue_hook(struct __btrfs_workqueue *wq) */ static inline void thresh_exec_hook(struct __btrfs_workqueue *wq) { - int new_max_active; + int new_current_active; long pending; int need_change = 0; @@ -197,7 +208,7 @@ static inline void thresh_exec_hook(struct __btrfs_workqueue *wq) wq->count %= (wq->thresh / 4); if (!wq->count) goto out; - new_max_active = wq->current_max; + new_current_active = wq->current_active; /* * pending may be changed later, but it's OK since we really @@ -205,19 +216,19 @@ static inline void thresh_exec_hook(struct __btrfs_workqueue *wq) */ pending = atomic_read(&wq->pending); if (pending > wq->thresh) - new_max_active++; + new_current_active++; if (pending < wq->thresh / 2) - new_max_active--; - new_max_active = clamp_val(new_max_active, 1, wq->max_active); - if (new_max_active != wq->current_max) { + new_current_active--; + new_current_active = clamp_val(new_current_active, 1, wq->limit_active); + if (new_current_active != wq->current_active) { need_change = 1; - wq->current_max = new_max_active; + wq->current_active = new_current_active; } out: spin_unlock(&wq->thres_lock); if (need_change) { - workqueue_set_max_active(wq->normal_wq, wq->current_max); + workqueue_set_max_active(wq->normal_wq, wq->current_active); } } @@ -351,13 +362,13 @@ void btrfs_destroy_workqueue(struct btrfs_workqueue *wq) kfree(wq); } -void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max) +void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int limit_active) { if (!wq) return; - wq->normal->max_active = max; + wq->normal->limit_active = limit_active; if (wq->high) - wq->high->max_active = max; + wq->high->limit_active = limit_active; } void btrfs_set_work_high_priority(struct btrfs_work *work) diff --git a/fs/btrfs/async-thread.h b/fs/btrfs/async-thread.h index b0b093b6afeca..ad4d0647d1a6c 100644 --- a/fs/btrfs/async-thread.h +++ b/fs/btrfs/async-thread.h @@ -69,7 +69,7 @@ BTRFS_WORK_HELPER_PROTO(scrubparity_helper); struct btrfs_workqueue *btrfs_alloc_workqueue(const char *name, unsigned int flags, - int max_active, + int limit_active, int thresh); void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t helper, btrfs_func_t func, -- GitLab From 527afb4493c2892ce89fb74648e72a30b68ba120 Mon Sep 17 00:00:00 2001 From: Tsutomu Itoh Date: Wed, 19 Aug 2015 14:55:00 +0900 Subject: [PATCH 5917/7006] Btrfs: cleanup: remove unnecessary check before btrfs_free_path is called We need not check path before btrfs_free_path() is called because path is checked in btrfs_free_path(). Signed-off-by: Tsutomu Itoh Reviewed-by: Qu Wenruo Signed-off-by: Chris Mason --- fs/btrfs/dev-replace.c | 3 +-- fs/btrfs/inode.c | 3 +-- fs/btrfs/tree-defrag.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c index 564a7de17d998..e54dd5905cee1 100644 --- a/fs/btrfs/dev-replace.c +++ b/fs/btrfs/dev-replace.c @@ -183,8 +183,7 @@ no_valid_dev_replace_entry_found: } out: - if (path) - btrfs_free_path(path); + btrfs_free_path(path); return ret; } diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index bda3c41dc9d5a..37dd8d0f1fb33 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -6905,8 +6905,7 @@ out: trace_btrfs_get_extent(root, em); - if (path) - btrfs_free_path(path); + btrfs_free_path(path); if (trans) { ret = btrfs_end_transaction(trans, root); if (!err) diff --git a/fs/btrfs/tree-defrag.c b/fs/btrfs/tree-defrag.c index a4b9c8b2d35ab..f31db43253399 100644 --- a/fs/btrfs/tree-defrag.c +++ b/fs/btrfs/tree-defrag.c @@ -115,8 +115,7 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, ret = -EAGAIN; } out: - if (path) - btrfs_free_path(path); + btrfs_free_path(path); if (ret == -EAGAIN) { if (root->defrag_max.objectid > root->defrag_progress.objectid) goto done; -- GitLab From 97db62062ac76e314c8bda4dc5b63f0ea906d15f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 31 Aug 2015 21:39:44 +0300 Subject: [PATCH 5918/7006] perf tools: Fix build on powerpc broken by pt/bts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It is theoretically possible to process perf.data files created on x86 and that contain Intel PT or Intel BTS data, on any other architecture, which is why it is possible for there to be build errors on powerpc caused by pt/bts. The errors were: util/intel-pt-decoder/intel-pt-insn-decoder.c: In function ‘intel_pt_insn_decoder’: util/intel-pt-decoder/intel-pt-insn-decoder.c:138:3: error: switch missing default case [-Werror=switch-default] switch (insn->immediate.nbytes) { ^ cc1: all warnings being treated as errors linux-acme.git/tools/perf/perf-obj/libperf.a(libperf-in.o): In function `intel_pt_synth_branch_sample': sources/linux-acme.git/tools/perf/util/intel-pt.c:871: undefined reference to `tsc_to_perf_time' linux-acme.git/tools/perf/perf-obj/libperf.a(libperf-in.o): In function `intel_pt_sample': sources/linux-acme.git/tools/perf/util/intel-pt.c:915: undefined reference to `tsc_to_perf_time' sources/linux-acme.git/tools/perf/util/intel-pt.c:962: undefined reference to `tsc_to_perf_time' linux-acme.git/tools/perf/perf-obj/libperf.a(libperf-in.o): In function `intel_pt_process_event': sources/linux-acme.git/tools/perf/util/intel-pt.c:1454: undefined reference to `perf_time_to_tsc' Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: Sukadev Bhattiprolu Cc: Wang Nan Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441046384-28663-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/Build | 1 + tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/tools/perf/util/Build b/tools/perf/util/Build index e912856cc4e5d..e79e4522368ad 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -75,6 +75,7 @@ libperf-y += record.o libperf-y += srcline.o libperf-y += data.o libperf-$(CONFIG_X86) += tsc.o +libperf-$(CONFIG_AUXTRACE) += tsc.o libperf-y += cloexec.o libperf-y += thread-stack.o libperf-$(CONFIG_AUXTRACE) += auxtrace.o diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c index 9e4eb8fcd5592..d23138c06665a 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c @@ -146,6 +146,9 @@ static void intel_pt_insn_decoder(struct insn *insn, case 4: intel_pt_insn->rel = bswap_32(insn->immediate.value); break; + default: + intel_pt_insn->rel = 0; + break; } #else intel_pt_insn->rel = insn->immediate.value; -- GitLab From f15f4d720088c140cdf1fee6aeab3549dbdddc41 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Tue, 25 Aug 2015 17:15:41 +0200 Subject: [PATCH 5919/7006] dm raid: document RAID 4/5/6 discard support For RAID 4/5/6 data integrity reasons 'discard_zeroes_data' must work properly. Signed-off-by: Heinz Mauelshagen Signed-off-by: Mike Snitzer --- Documentation/device-mapper/dm-raid.txt | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Documentation/device-mapper/dm-raid.txt b/Documentation/device-mapper/dm-raid.txt index cb12af3b51c21..df2d636b60880 100644 --- a/Documentation/device-mapper/dm-raid.txt +++ b/Documentation/device-mapper/dm-raid.txt @@ -209,6 +209,37 @@ include: "repair" - Initiate a repair of the array. "reshape"- Currently unsupported (-EINVAL). + +Discard Support +--------------- +The implementation of discard support among hardware vendors varies. +When a block is discarded, some storage devices will return zeroes when +the block is read. These devices set the 'discard_zeroes_data' +attribute. Other devices will return random data. Confusingly, some +devices that advertise 'discard_zeroes_data' will not reliably return +zeroes when discarded blocks are read! Since RAID 4/5/6 uses blocks +from a number of devices to calculate parity blocks and (for performance +reasons) relies on 'discard_zeroes_data' being reliable, it is important +that the devices be consistent. Blocks may be discarded in the middle +of a RAID 4/5/6 stripe and if subsequent read results are not +consistent, the parity blocks may be calculated differently at any time; +making the parity blocks useless for redundancy. It is important to +understand how your hardware behaves with discards if you are going to +enable discards with RAID 4/5/6. + +Since the behavior of storage devices is unreliable in this respect, +even when reporting 'discard_zeroes_data', by default RAID 4/5/6 +discard support is disabled -- this ensures data integrity at the +expense of losing some performance. + +Storage devices that properly support 'discard_zeroes_data' are +increasingly whitelisted in the kernel and can thus be trusted. + +For trusted devices, the following dm-raid module parameter can be set +to safely enable discard support for RAID 4/5/6: + 'devices_handle_discards_safely' + + Version History --------------- 1.0.0 Initial version. Support for RAID 4/5/6 -- GitLab From 9153df7405ae04c1b0466de720e0a685cfea1a3a Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Mon, 31 Aug 2015 18:20:08 +0100 Subject: [PATCH 5920/7006] dm cache: fix leaking of deferred bio prison cells There were two cases where dm_cell_visit_release() was being called, which removes the cell from the prison's rbtree, but the callers didn't also return the cell to the mempool. Fix this by having them call free_prison_cell(). This leak manifested as the 'kmalloc-96' slab growing until OOM. Fixes: 651f5fa2a3 ("dm cache: defer whole cells") Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer Cc: stable@vger.kernel.org # 4.1+ --- drivers/md/dm-cache-target.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 8cef66b332431..2f60cbf404e52 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -1730,6 +1730,8 @@ static void remap_cell_to_origin_clear_discard(struct cache *cache, remap_to_origin(cache, bio); issue(cache, bio); } + + free_prison_cell(cache, cell); } static void remap_cell_to_cache_dirty(struct cache *cache, struct dm_bio_prison_cell *cell, @@ -1764,6 +1766,8 @@ static void remap_cell_to_cache_dirty(struct cache *cache, struct dm_bio_prison_ remap_to_cache(cache, bio, cblock); issue(cache, bio); } + + free_prison_cell(cache, cell); } /*----------------------------------------------------------------*/ -- GitLab From 0a2050d744037158de773be5c6f1fc468a551bae Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 30 Jul 2015 21:51:54 +0800 Subject: [PATCH 5921/7006] NFSD: Store parent's stat in a separate value After commit ae7095a7c4 (nfsd4: helper function for getting mounted_on ino) we ignore the return value from get_parent_attributes(). Also, the following FATTR4_WORD2_LAYOUT_BLKSIZE uses stat.blksize, so to avoid overwriting that, use an independent value for the parent's attributes. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 75e0563c09d19..1aa0dc38ed584 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2675,6 +2675,9 @@ out_acl: *p++ = cpu_to_be32(stat.mtime.tv_nsec); } if (bmval1 & FATTR4_WORD1_MOUNTED_ON_FILEID) { + struct kstat parent_stat; + u64 ino = stat.ino; + p = xdr_reserve_space(xdr, 8); if (!p) goto out_resource; @@ -2683,9 +2686,13 @@ out_acl: * and this is the root of a cross-mounted filesystem. */ if (ignore_crossmnt == 0 && - dentry == exp->ex_path.mnt->mnt_root) - get_parent_attributes(exp, &stat); - p = xdr_encode_hyper(p, stat.ino); + dentry == exp->ex_path.mnt->mnt_root) { + err = get_parent_attributes(exp, &parent_stat); + if (err) + goto out_nfserr; + ino = parent_stat.ino; + } + p = xdr_encode_hyper(p, ino); } #ifdef CONFIG_NFSD_PNFS if ((bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) || -- GitLab From 4c22279848c531fc7f555d463daf3d0df963bd41 Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Sun, 30 Aug 2015 18:09:38 -0700 Subject: [PATCH 5922/7006] ip-tunnel: Use API to access tunnel metadata options. Currently tun-info options pointer is used in few cases to pass options around. But tunnel options can be accessed using ip_tunnel_info_opts() API without using the pointer. Following patch removes the redundant pointer and consistently make use of API. Signed-off-by: Pravin B Shelar Acked-by: Thomas Graf Reviewed-by: Jesse Gross Signed-off-by: David S. Miller --- drivers/net/geneve.c | 9 ++--- drivers/net/vxlan.c | 4 +- include/net/dst_metadata.h | 31 +++++++--------- include/net/ip_tunnels.h | 67 ++++++++++++++++------------------ net/ipv4/ip_tunnel_core.c | 2 - net/openvswitch/actions.c | 8 ++-- net/openvswitch/datapath.c | 3 +- net/openvswitch/datapath.h | 3 +- net/openvswitch/flow.c | 7 ++-- net/openvswitch/flow_netlink.c | 27 ++++++-------- net/openvswitch/flow_netlink.h | 3 +- net/openvswitch/vport-geneve.c | 5 +-- net/openvswitch/vport-gre.c | 5 +-- net/openvswitch/vport-vxlan.c | 4 +- net/openvswitch/vport.c | 27 +++++++------- net/openvswitch/vport.h | 7 ++-- 16 files changed, 100 insertions(+), 112 deletions(-) diff --git a/drivers/net/geneve.c b/drivers/net/geneve.c index 68b0f0325fc70..da3259ce7c8d0 100644 --- a/drivers/net/geneve.c +++ b/drivers/net/geneve.c @@ -143,7 +143,6 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) if (ip_tunnel_collect_metadata() || gs->collect_md) { __be16 flags; - void *opts; flags = TUNNEL_KEY | TUNNEL_GENEVE_OPT | (gnvh->oam ? TUNNEL_OAM : 0) | @@ -154,11 +153,9 @@ static void geneve_rx(struct geneve_sock *gs, struct sk_buff *skb) gnvh->opt_len * 4); if (!tun_dst) goto drop; - /* Update tunnel dst according to Geneve options. */ - opts = ip_tunnel_info_opts(&tun_dst->u.tun_info, - gnvh->opt_len * 4); - memcpy(opts, gnvh->options, gnvh->opt_len * 4); + ip_tunnel_info_opts_set(&tun_dst->u.tun_info, + gnvh->options, gnvh->opt_len * 4); } else { /* Drop packets w/ critical options, * since we don't support any... @@ -663,7 +660,7 @@ static netdev_tx_t geneve_xmit(struct sk_buff *skb, struct net_device *dev) tunnel_id_to_vni(key->tun_id, vni); if (key->tun_flags & TUNNEL_GENEVE_OPT) - opts = ip_tunnel_info_opts(info, info->options_len); + opts = ip_tunnel_info_opts(info); udp_csum = !!(key->tun_flags & TUNNEL_CSUM); err = geneve_build_skb(rt, skb, key->tun_flags, vni, diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index 6c5269aea5447..ce988fd01b348 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1271,7 +1271,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) goto drop; info = &tun_dst->u.tun_info; - md = ip_tunnel_info_opts(info, sizeof(*md)); + md = ip_tunnel_info_opts(info); } else { memset(md, 0, sizeof(*md)); } @@ -1948,7 +1948,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev, tos = info->key.tos; if (info->options_len) - md = ip_tunnel_info_opts(info, sizeof(*md)); + md = ip_tunnel_info_opts(info); } else { md->gbp = skb->mark; } diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index d32f49cc621d2..547ab82415935 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -48,21 +48,16 @@ static inline bool skb_valid_dst(const struct sk_buff *skb) struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags); struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags); -static inline struct metadata_dst *tun_rx_dst(__be16 flags, - __be64 tunnel_id, int md_size) +static inline struct metadata_dst *tun_rx_dst(int md_size) { struct metadata_dst *tun_dst; - struct ip_tunnel_info *info; tun_dst = metadata_dst_alloc(md_size, GFP_ATOMIC); if (!tun_dst) return NULL; - info = &tun_dst->u.tun_info; - info->key.tun_flags = flags; - info->key.tun_id = tunnel_id; - info->key.tp_src = 0; - info->key.tp_dst = 0; + tun_dst->u.tun_info.options_len = 0; + tun_dst->u.tun_info.mode = 0; return tun_dst; } @@ -73,17 +68,14 @@ static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb, { const struct iphdr *iph = ip_hdr(skb); struct metadata_dst *tun_dst; - struct ip_tunnel_info *info; - tun_dst = tun_rx_dst(flags, tunnel_id, md_size); + tun_dst = tun_rx_dst(md_size); if (!tun_dst) return NULL; - info = &tun_dst->u.tun_info; - info->key.u.ipv4.src = iph->saddr; - info->key.u.ipv4.dst = iph->daddr; - info->key.tos = iph->tos; - info->key.ttl = iph->ttl; + ip_tunnel_key_init(&tun_dst->u.tun_info.key, + iph->saddr, iph->daddr, iph->tos, iph->ttl, + 0, 0, tunnel_id, flags); return tun_dst; } @@ -96,16 +88,21 @@ static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb, struct metadata_dst *tun_dst; struct ip_tunnel_info *info; - tun_dst = tun_rx_dst(flags, tunnel_id, md_size); + tun_dst = tun_rx_dst(md_size); if (!tun_dst) return NULL; info = &tun_dst->u.tun_info; + info->mode = IP_TUNNEL_INFO_IPV6; + info->key.tun_flags = flags; + info->key.tun_id = tunnel_id; + info->key.tp_src = 0; + info->key.tp_dst = 0; + info->key.u.ipv6.src = ip6h->saddr; info->key.u.ipv6.dst = ip6h->daddr; info->key.tos = ipv6_get_dsfield(ip6h); info->key.ttl = ip6h->hop_limit; - info->mode = IP_TUNNEL_INFO_IPV6; return tun_dst; } diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h index 2b4fa06e91bde..9a6a3ba888e8d 100644 --- a/include/net/ip_tunnels.h +++ b/include/net/ip_tunnels.h @@ -57,7 +57,6 @@ struct ip_tunnel_key { struct ip_tunnel_info { struct ip_tunnel_key key; - const void *options; u8 options_len; u8 mode; }; @@ -180,49 +179,32 @@ int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *op, int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *op, unsigned int num); -static inline void __ip_tunnel_info_init(struct ip_tunnel_info *tun_info, - __be32 saddr, __be32 daddr, - u8 tos, u8 ttl, - __be16 tp_src, __be16 tp_dst, - __be64 tun_id, __be16 tun_flags, - const void *opts, u8 opts_len) +static inline void ip_tunnel_key_init(struct ip_tunnel_key *key, + __be32 saddr, __be32 daddr, + u8 tos, u8 ttl, + __be16 tp_src, __be16 tp_dst, + __be64 tun_id, __be16 tun_flags) { - tun_info->key.tun_id = tun_id; - tun_info->key.u.ipv4.src = saddr; - tun_info->key.u.ipv4.dst = daddr; - memset((unsigned char *)&tun_info->key + IP_TUNNEL_KEY_IPV4_PAD, + key->tun_id = tun_id; + key->u.ipv4.src = saddr; + key->u.ipv4.dst = daddr; + memset((unsigned char *)key + IP_TUNNEL_KEY_IPV4_PAD, 0, IP_TUNNEL_KEY_IPV4_PAD_LEN); - tun_info->key.tos = tos; - tun_info->key.ttl = ttl; - tun_info->key.tun_flags = tun_flags; + key->tos = tos; + key->ttl = ttl; + key->tun_flags = tun_flags; /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of * the upper tunnel are used. * E.g: GRE over IPSEC, the tp_src and tp_port are zero. */ - tun_info->key.tp_src = tp_src; - tun_info->key.tp_dst = tp_dst; + key->tp_src = tp_src; + key->tp_dst = tp_dst; /* Clear struct padding. */ - if (sizeof(tun_info->key) != IP_TUNNEL_KEY_SIZE) - memset((unsigned char *)&tun_info->key + IP_TUNNEL_KEY_SIZE, - 0, sizeof(tun_info->key) - IP_TUNNEL_KEY_SIZE); - - tun_info->options = opts; - tun_info->options_len = opts_len; - - tun_info->mode = 0; -} - -static inline void ip_tunnel_info_init(struct ip_tunnel_info *tun_info, - const struct iphdr *iph, - __be16 tp_src, __be16 tp_dst, - __be64 tun_id, __be16 tun_flags, - const void *opts, u8 opts_len) -{ - __ip_tunnel_info_init(tun_info, iph->saddr, iph->daddr, - iph->tos, iph->ttl, tp_src, tp_dst, - tun_id, tun_flags, opts, opts_len); + if (sizeof(*key) != IP_TUNNEL_KEY_SIZE) + memset((unsigned char *)key + IP_TUNNEL_KEY_SIZE, + 0, sizeof(*key) - IP_TUNNEL_KEY_SIZE); } static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info @@ -317,11 +299,24 @@ static inline void iptunnel_xmit_stats(int err, } } -static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info, size_t n) +static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info) { return info + 1; } +static inline void ip_tunnel_info_opts_get(void *to, + const struct ip_tunnel_info *info) +{ + memcpy(to, info + 1, info->options_len); +} + +static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info, + const void *from, int len) +{ + memcpy(ip_tunnel_info_opts(info), from, len); + info->options_len = len; +} + static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) { return (struct ip_tunnel_info *)lwtstate->data; diff --git a/net/ipv4/ip_tunnel_core.c b/net/ipv4/ip_tunnel_core.c index 0c756ade1cf71..29ed6c5a51854 100644 --- a/net/ipv4/ip_tunnel_core.c +++ b/net/ipv4/ip_tunnel_core.c @@ -249,7 +249,6 @@ static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr, tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP_FLAGS]); tun_info->mode = IP_TUNNEL_INFO_TX; - tun_info->options = NULL; tun_info->options_len = 0; *ts = new_state; @@ -357,7 +356,6 @@ static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr, tun_info->key.tun_flags = nla_get_u16(tb[LWTUNNEL_IP6_FLAGS]); tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6; - tun_info->options = NULL; tun_info->options_len = 0; *ts = new_state; diff --git a/net/openvswitch/actions.c b/net/openvswitch/actions.c index 090d9e3a460c2..315f5330b6e54 100644 --- a/net/openvswitch/actions.c +++ b/net/openvswitch/actions.c @@ -793,11 +793,13 @@ static int output_userspace(struct datapath *dp, struct sk_buff *skb, if (vport) { int err; + upcall.egress_tun_info = &info; err = ovs_vport_get_egress_tun_info(vport, skb, - &info); - if (!err) - upcall.egress_tun_info = &info; + &upcall); + if (err) + upcall.egress_tun_info = NULL; } + break; } diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 60c2ab8e6bc30..6fbd2decb19e2 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -491,7 +491,8 @@ static int queue_userspace_packet(struct datapath *dp, struct sk_buff *skb, if (upcall_info->egress_tun_info) { nla = nla_nest_start(user_skb, OVS_PACKET_ATTR_EGRESS_TUN_KEY); err = ovs_nla_put_egress_tunnel_key(user_skb, - upcall_info->egress_tun_info); + upcall_info->egress_tun_info, + upcall_info->egress_tun_opts); BUG_ON(err); nla_nest_end(user_skb, nla); } diff --git a/net/openvswitch/datapath.h b/net/openvswitch/datapath.h index c05b7d9e7bf22..f88038a99f444 100644 --- a/net/openvswitch/datapath.h +++ b/net/openvswitch/datapath.h @@ -116,7 +116,8 @@ struct ovs_skb_cb { * @mru: If not zero, Maximum received IP fragment size. */ struct dp_upcall_info { - const struct ip_tunnel_info *egress_tun_info; + struct ip_tunnel_info *egress_tun_info; + const void *egress_tun_opts; const struct nlattr *userdata; const struct nlattr *actions; int actions_len; diff --git a/net/openvswitch/flow.c b/net/openvswitch/flow.c index bed8d09230cdb..c8db44ab2ee78 100644 --- a/net/openvswitch/flow.c +++ b/net/openvswitch/flow.c @@ -702,12 +702,13 @@ int ovs_flow_key_extract(const struct ip_tunnel_info *tun_info, return -EINVAL; memcpy(&key->tun_key, &tun_info->key, sizeof(key->tun_key)); - if (tun_info->options) { + if (tun_info->options_len) { BUILD_BUG_ON((1 << (sizeof(tun_info->options_len) * 8)) - 1 > sizeof(key->tun_opts)); - memcpy(TUN_METADATA_OPTS(key, tun_info->options_len), - tun_info->options, tun_info->options_len); + + ip_tunnel_info_opts_get(TUN_METADATA_OPTS(key, tun_info->options_len), + tun_info); key->tun_opts_len = tun_info->options_len; } else { key->tun_opts_len = 0; diff --git a/net/openvswitch/flow_netlink.c b/net/openvswitch/flow_netlink.c index e22c5bfe85756..c92d6a262bc51 100644 --- a/net/openvswitch/flow_netlink.c +++ b/net/openvswitch/flow_netlink.c @@ -716,10 +716,11 @@ static int ipv4_tun_to_nlattr(struct sk_buff *skb, } int ovs_nla_put_egress_tunnel_key(struct sk_buff *skb, - const struct ip_tunnel_info *egress_tun_info) + const struct ip_tunnel_info *egress_tun_info, + const void *egress_tun_opts) { return __ipv4_tun_to_nlattr(skb, &egress_tun_info->key, - egress_tun_info->options, + egress_tun_opts, egress_tun_info->options_len); } @@ -1876,20 +1877,14 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, tun_info = &tun_dst->u.tun_info; tun_info->mode = IP_TUNNEL_INFO_TX; tun_info->key = key.tun_key; - tun_info->options_len = key.tun_opts_len; - - if (tun_info->options_len) { - /* We need to store the options in the action itself since - * everything else will go away after flow setup. We can append - * it to tun_info and then point there. - */ - memcpy((tun_info + 1), - TUN_METADATA_OPTS(&key, key.tun_opts_len), key.tun_opts_len); - tun_info->options = (tun_info + 1); - } else { - tun_info->options = NULL; - } + /* We need to store the options in the action itself since + * everything else will go away after flow setup. We can append + * it to tun_info and then point there. + */ + ip_tunnel_info_opts_set(tun_info, + TUN_METADATA_OPTS(&key, key.tun_opts_len), + key.tun_opts_len); add_nested_action_end(*sfa, start); return err; @@ -2345,7 +2340,7 @@ static int set_action_to_attr(const struct nlattr *a, struct sk_buff *skb) err = ipv4_tun_to_nlattr(skb, &tun_info->key, tun_info->options_len ? - tun_info->options : NULL, + ip_tunnel_info_opts(tun_info) : NULL, tun_info->options_len); if (err) return err; diff --git a/net/openvswitch/flow_netlink.h b/net/openvswitch/flow_netlink.h index 07878e22e7830..6ca3f0baf449f 100644 --- a/net/openvswitch/flow_netlink.h +++ b/net/openvswitch/flow_netlink.h @@ -56,7 +56,8 @@ int ovs_nla_get_match(struct net *, struct sw_flow_match *, const struct nlattr *key, const struct nlattr *mask, bool log); int ovs_nla_put_egress_tunnel_key(struct sk_buff *, - const struct ip_tunnel_info *); + const struct ip_tunnel_info *, + const void *egress_tun_opts); bool ovs_nla_get_ufid(struct sw_flow_id *, const struct nlattr *, bool log); int ovs_nla_get_identifier(struct sw_flow_id *sfid, const struct nlattr *ufid, diff --git a/net/openvswitch/vport-geneve.c b/net/openvswitch/vport-geneve.c index 24c56e56feddb..2735e9c4a3b88 100644 --- a/net/openvswitch/vport-geneve.c +++ b/net/openvswitch/vport-geneve.c @@ -53,15 +53,14 @@ static int geneve_get_options(const struct vport *vport, } static int geneve_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *egress_tun_info) + struct dp_upcall_info *upcall) { struct geneve_port *geneve_port = geneve_vport(vport); struct net *net = ovs_dp_get_net(vport->dp); __be16 dport = htons(geneve_port->port_no); __be16 sport = udp_flow_src_port(net, skb, 1, USHRT_MAX, true); - return ovs_tunnel_get_egress_info(egress_tun_info, - ovs_dp_get_net(vport->dp), + return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp), skb, IPPROTO_UDP, sport, dport); } diff --git a/net/openvswitch/vport-gre.c b/net/openvswitch/vport-gre.c index 36c39843607ef..4d24481669c95 100644 --- a/net/openvswitch/vport-gre.c +++ b/net/openvswitch/vport-gre.c @@ -85,10 +85,9 @@ static struct vport *gre_create(const struct vport_parms *parms) } static int gre_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *egress_tun_info) + struct dp_upcall_info *upcall) { - return ovs_tunnel_get_egress_info(egress_tun_info, - ovs_dp_get_net(vport->dp), + return ovs_tunnel_get_egress_info(upcall, ovs_dp_get_net(vport->dp), skb, IPPROTO_GRE, 0, 0); } diff --git a/net/openvswitch/vport-vxlan.c b/net/openvswitch/vport-vxlan.c index ed7b23f443ec9..c11413d5075f8 100644 --- a/net/openvswitch/vport-vxlan.c +++ b/net/openvswitch/vport-vxlan.c @@ -147,7 +147,7 @@ static struct vport *vxlan_create(const struct vport_parms *parms) } static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *egress_tun_info) + struct dp_upcall_info *upcall) { struct vxlan_dev *vxlan = netdev_priv(vport->dev); struct net *net = ovs_dp_get_net(vport->dp); @@ -159,7 +159,7 @@ static int vxlan_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, inet_get_local_port_range(net, &port_min, &port_max); src_port = udp_flow_src_port(net, skb, 0, 0, true); - return ovs_tunnel_get_egress_info(egress_tun_info, net, + return ovs_tunnel_get_egress_info(upcall, net, skb, IPPROTO_UDP, src_port, dst_port); } diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c index 1679dea7c6bca..dc81dc619aa23 100644 --- a/net/openvswitch/vport.c +++ b/net/openvswitch/vport.c @@ -487,13 +487,14 @@ void ovs_vport_deferred_free(struct vport *vport) } EXPORT_SYMBOL_GPL(ovs_vport_deferred_free); -int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, +int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall, struct net *net, struct sk_buff *skb, u8 ipproto, __be16 tp_src, __be16 tp_dst) { + struct ip_tunnel_info *egress_tun_info = upcall->egress_tun_info; const struct ip_tunnel_info *tun_info = skb_tunnel_info(skb); const struct ip_tunnel_key *tun_key; u32 skb_mark = skb->mark; @@ -520,26 +521,26 @@ int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, /* Generate egress_tun_info based on tun_info, * saddr, tp_src and tp_dst */ - __ip_tunnel_info_init(egress_tun_info, - fl.saddr, tun_key->u.ipv4.dst, - tun_key->tos, - tun_key->ttl, - tp_src, tp_dst, - tun_key->tun_id, - tun_key->tun_flags, - tun_info->options, - tun_info->options_len); - + ip_tunnel_key_init(&egress_tun_info->key, + fl.saddr, tun_key->u.ipv4.dst, + tun_key->tos, + tun_key->ttl, + tp_src, tp_dst, + tun_key->tun_id, + tun_key->tun_flags); + egress_tun_info->options_len = tun_info->options_len; + egress_tun_info->mode = tun_info->mode; + upcall->egress_tun_opts = ip_tunnel_info_opts(egress_tun_info); return 0; } EXPORT_SYMBOL_GPL(ovs_tunnel_get_egress_info); int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *info) + struct dp_upcall_info *upcall) { /* get_egress_tun_info() is only implemented on tunnel ports. */ if (unlikely(!vport->ops->get_egress_tun_info)) return -EINVAL; - return vport->ops->get_egress_tun_info(vport, skb, info); + return vport->ops->get_egress_tun_info(vport, skb, upcall); } diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h index 4b6f4a5296c3f..a413f3ae6a7b5 100644 --- a/net/openvswitch/vport.h +++ b/net/openvswitch/vport.h @@ -53,14 +53,15 @@ int ovs_vport_set_upcall_portids(struct vport *, const struct nlattr *pids); int ovs_vport_get_upcall_portids(const struct vport *, struct sk_buff *); u32 ovs_vport_find_upcall_portid(const struct vport *, struct sk_buff *); -int ovs_tunnel_get_egress_info(struct ip_tunnel_info *egress_tun_info, +int ovs_tunnel_get_egress_info(struct dp_upcall_info *upcall, struct net *net, struct sk_buff *, u8 ipproto, __be16 tp_src, __be16 tp_dst); + int ovs_vport_get_egress_tun_info(struct vport *vport, struct sk_buff *skb, - struct ip_tunnel_info *info); + struct dp_upcall_info *upcall); /** * struct vport_portids - array of netlink portids of a vport. @@ -154,7 +155,7 @@ struct vport_ops { void (*send)(struct vport *, struct sk_buff *); int (*get_egress_tun_info)(struct vport *, struct sk_buff *, - struct ip_tunnel_info *); + struct dp_upcall_info *upcall); struct module *owner; struct list_head list; -- GitLab From 87583ebb9f6ea6dc7f8ef167b815656787e429fc Mon Sep 17 00:00:00 2001 From: Philip Downey Date: Mon, 31 Aug 2015 11:30:38 +0100 Subject: [PATCH 5923/7006] IGMP: Document igmp_link_local_mcast_reports Document the addition of a new sysctl variable which controls the generation of IGMP reports for link local multicast groups in the 224.0.0.X range. IGMP reports for local multicast groups can now be optionally inhibited by setting the value to zero e.g.: echo 0 > /proc/sys/net/ipv4/igmp_link_local_mcast_reports To retain backwards compatibility the previous behaviour is retained by default on system boot or reverted by setting the value back to non-zero. Signed-off-by: Philip Downey Signed-off-by: David S. Miller --- Documentation/networking/ip-sysctl.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index ac77a13d2ea2c..ebe94f2cab981 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -1201,6 +1201,11 @@ xfrm4_gc_thresh - INTEGER destination cache entries. At twice this value the system will refuse new allocations. +igmp_link_local_mcast_reports - BOOLEAN + Enable IGMP reports for link local multicast groups in the + 224.0.0.X range. + Default TRUE + Alexey Kuznetsov. kuznet@ms2.inr.ac.ru -- GitLab From 6cf9dfd3bd62edfff69f11c0f111bc261166e4c7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 31 Aug 2015 15:58:44 +0200 Subject: [PATCH 5924/7006] net: fib: move metrics parsing to a helper fib_create_info() is already quite large, so before adding more code to the metrics section move that to a helper, similar to ip6_convert_metrics. Suggested-by: Daniel Borkmann Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- net/ipv4/fib_semantics.c | 71 +++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 1b2d01170a4de..88afbae893f0d 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -876,6 +876,44 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) return true; } +static int +fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) +{ + struct nlattr *nla; + int remaining; + + if (!cfg->fc_mx) + return 0; + + nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { + int type = nla_type(nla); + u32 val; + + if (!type) + continue; + if (type > RTAX_MAX) + return -EINVAL; + + if (type == RTAX_CC_ALGO) { + char tmp[TCP_CA_NAME_MAX]; + + nla_strlcpy(tmp, nla, sizeof(tmp)); + val = tcp_ca_get_key_by_name(tmp); + if (val == TCP_CA_UNSPEC) + return -EINVAL; + } else { + val = nla_get_u32(nla); + } + if (type == RTAX_ADVMSS && val > 65535 - 40) + val = 65535 - 40; + if (type == RTAX_MTU && val > 65535 - 15) + val = 65535 - 15; + fi->fib_metrics[type - 1] = val; + } + + return 0; +} + struct fib_info *fib_create_info(struct fib_config *cfg) { int err; @@ -948,36 +986,9 @@ struct fib_info *fib_create_info(struct fib_config *cfg) goto failure; } endfor_nexthops(fi) - if (cfg->fc_mx) { - struct nlattr *nla; - int remaining; - - nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { - int type = nla_type(nla); - - if (type) { - u32 val; - - if (type > RTAX_MAX) - goto err_inval; - if (type == RTAX_CC_ALGO) { - char tmp[TCP_CA_NAME_MAX]; - - nla_strlcpy(tmp, nla, sizeof(tmp)); - val = tcp_ca_get_key_by_name(tmp); - if (val == TCP_CA_UNSPEC) - goto err_inval; - } else { - val = nla_get_u32(nla); - } - if (type == RTAX_ADVMSS && val > 65535 - 40) - val = 65535 - 40; - if (type == RTAX_MTU && val > 65535 - 15) - val = 65535 - 15; - fi->fib_metrics[type - 1] = val; - } - } - } + err = fib_convert_metrics(fi, cfg); + if (err) + goto failure; if (cfg->fc_mp) { #ifdef CONFIG_IP_ROUTE_MULTIPATH -- GitLab From 1bb14807bc761a88bb9d319e7bf519eebf4c82ec Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 31 Aug 2015 15:58:45 +0200 Subject: [PATCH 5925/7006] net: fib6: reduce identation in ip6_convert_metrics Reduce the identation a bit, there's no need to artificically have it increased. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/ipv6/route.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 308dd5f9158f1..0261b721b34bb 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1711,26 +1711,26 @@ static int ip6_convert_metrics(struct mx6_config *mxc, nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { int type = nla_type(nla); + u32 val; - if (type) { - u32 val; - - if (unlikely(type > RTAX_MAX)) - goto err; - if (type == RTAX_CC_ALGO) { - char tmp[TCP_CA_NAME_MAX]; + if (!type) + continue; + if (unlikely(type > RTAX_MAX)) + goto err; - nla_strlcpy(tmp, nla, sizeof(tmp)); - val = tcp_ca_get_key_by_name(tmp); - if (val == TCP_CA_UNSPEC) - goto err; - } else { - val = nla_get_u32(nla); - } + if (type == RTAX_CC_ALGO) { + char tmp[TCP_CA_NAME_MAX]; - mp[type - 1] = val; - __set_bit(type - 1, mxc->mx_valid); + nla_strlcpy(tmp, nla, sizeof(tmp)); + val = tcp_ca_get_key_by_name(tmp); + if (val == TCP_CA_UNSPEC) + goto err; + } else { + val = nla_get_u32(nla); } + + mp[type - 1] = val; + __set_bit(type - 1, mxc->mx_valid); } mxc->mx = mp; -- GitLab From b8d3e4163a3562d7cba486687904383e78e7dd6a Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 31 Aug 2015 15:58:46 +0200 Subject: [PATCH 5926/7006] fib, fib6: reject invalid feature bits Feature bits that are invalid should not be accepted by the kernel, only the lower 4 bits may be configured, but not the remaining ones. Even from these 4, 2 of them are unused. Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/uapi/linux/rtnetlink.h | 11 +++++++---- net/ipv4/fib_semantics.c | 2 ++ net/ipv6/route.c | 2 ++ 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h index 0d3d3cc43356e..702024769c74b 100644 --- a/include/uapi/linux/rtnetlink.h +++ b/include/uapi/linux/rtnetlink.h @@ -418,10 +418,13 @@ enum { #define RTAX_MAX (__RTAX_MAX - 1) -#define RTAX_FEATURE_ECN 0x00000001 -#define RTAX_FEATURE_SACK 0x00000002 -#define RTAX_FEATURE_TIMESTAMP 0x00000004 -#define RTAX_FEATURE_ALLFRAG 0x00000008 +#define RTAX_FEATURE_ECN (1 << 0) +#define RTAX_FEATURE_SACK (1 << 1) +#define RTAX_FEATURE_TIMESTAMP (1 << 2) +#define RTAX_FEATURE_ALLFRAG (1 << 3) + +#define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \ + RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG) struct rta_session { __u8 proto; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 88afbae893f0d..115a08e70d432 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -908,6 +908,8 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) val = 65535 - 40; if (type == RTAX_MTU && val > 65535 - 15) val = 65535 - 15; + if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) + return -EINVAL; fi->fib_metrics[type - 1] = val; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 0261b721b34bb..8771530df45ea 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1728,6 +1728,8 @@ static int ip6_convert_metrics(struct mx6_config *mxc, } else { val = nla_get_u32(nla); } + if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) + goto err; mp[type - 1] = val; __set_bit(type - 1, mxc->mx_valid); -- GitLab From c3a8d9474684d391b0afc3970d9b249add15ec07 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 31 Aug 2015 15:58:47 +0200 Subject: [PATCH 5927/7006] tcp: use dctcp if enabled on the route to the initiator Currently, the following case doesn't use DCTCP, even if it should: A responder has f.e. Cubic as system wide default, but for a specific route to the initiating host, DCTCP is being set in RTAX_CC_ALGO. The initiating host then uses DCTCP as congestion control, but since the initiator sets ECT(0), tcp_ecn_create_request() doesn't set ecn_ok, and we have to fall back to Reno after 3WHS completes. We were thinking on how to solve this in a minimal, non-intrusive way without bloating tcp_ecn_create_request() needlessly: lets cache the CA ecn option flag in RTAX_FEATURES. In other words, when ECT(0) is set on the SYN packet, set ecn_ok=1 iff route RTAX_FEATURES contains the unexposed (internal-only) DST_FEATURE_ECN_CA. This allows to only do a single metric feature lookup inside tcp_ecn_create_request(). Joint work with Florian Westphal. Signed-off-by: Daniel Borkmann Signed-off-by: Florian Westphal Signed-off-by: David S. Miller --- include/net/dst.h | 6 ++++++ include/net/tcp.h | 2 +- net/core/rtnetlink.c | 6 ++++++ net/ipv4/fib_semantics.c | 6 +++++- net/ipv4/tcp_cong.c | 9 ++++++--- net/ipv4/tcp_input.c | 7 +++++-- net/ipv6/route.c | 9 +++++++-- 7 files changed, 36 insertions(+), 9 deletions(-) diff --git a/include/net/dst.h b/include/net/dst.h index 4c4801645371d..9261d928303d4 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -207,6 +207,12 @@ static inline void dst_metric_set(struct dst_entry *dst, int metric, u32 val) p[metric-1] = val; } +/* Kernel-internal feature bits that are unallocated in user space. */ +#define DST_FEATURE_ECN_CA (1 << 31) + +#define DST_FEATURE_MASK (DST_FEATURE_ECN_CA) +#define DST_FEATURE_ECN_MASK (DST_FEATURE_ECN_CA | RTAX_FEATURE_ECN) + static inline u32 dst_feature(const struct dst_entry *dst, u32 feature) { diff --git a/include/net/tcp.h b/include/net/tcp.h index 4a7b03947a38b..0cab28cd43a90 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -888,7 +888,7 @@ void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked); extern struct tcp_congestion_ops tcp_reno; struct tcp_congestion_ops *tcp_ca_find_key(u32 key); -u32 tcp_ca_get_key_by_name(const char *name); +u32 tcp_ca_get_key_by_name(const char *name, bool *ecn_ca); #ifdef CONFIG_INET char *tcp_ca_get_name_by_key(u32 key, char *buffer); #else diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 788ceed394636..a466821d1441f 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -678,6 +678,12 @@ int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) continue; if (nla_put_string(skb, i + 1, name)) goto nla_put_failure; + } else if (i == RTAX_FEATURES - 1) { + u32 user_features = metrics[i] & RTAX_FEATURE_MASK; + + BUILD_BUG_ON(RTAX_FEATURE_MASK & DST_FEATURE_MASK); + if (nla_put_u32(skb, i + 1, user_features)) + goto nla_put_failure; } else { if (nla_put_u32(skb, i + 1, metrics[i])) goto nla_put_failure; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 115a08e70d432..992a9597daf80 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -879,6 +879,7 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) static int fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) { + bool ecn_ca = false; struct nlattr *nla; int remaining; @@ -898,7 +899,7 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) char tmp[TCP_CA_NAME_MAX]; nla_strlcpy(tmp, nla, sizeof(tmp)); - val = tcp_ca_get_key_by_name(tmp); + val = tcp_ca_get_key_by_name(tmp, &ecn_ca); if (val == TCP_CA_UNSPEC) return -EINVAL; } else { @@ -913,6 +914,9 @@ fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) fi->fib_metrics[type - 1] = val; } + if (ecn_ca) + fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA; + return 0; } diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c index a2ed23c595cf1..93c4dc3ab23fd 100644 --- a/net/ipv4/tcp_cong.c +++ b/net/ipv4/tcp_cong.c @@ -114,16 +114,19 @@ void tcp_unregister_congestion_control(struct tcp_congestion_ops *ca) } EXPORT_SYMBOL_GPL(tcp_unregister_congestion_control); -u32 tcp_ca_get_key_by_name(const char *name) +u32 tcp_ca_get_key_by_name(const char *name, bool *ecn_ca) { const struct tcp_congestion_ops *ca; - u32 key; + u32 key = TCP_CA_UNSPEC; might_sleep(); rcu_read_lock(); ca = __tcp_ca_find_autoload(name); - key = ca ? ca->key : TCP_CA_UNSPEC; + if (ca) { + key = ca->key; + *ecn_ca = ca->flags & TCP_CONG_NEEDS_ECN; + } rcu_read_unlock(); return key; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index dc08e23526652..a8f515bb19c4b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -6003,14 +6003,17 @@ static void tcp_ecn_create_request(struct request_sock *req, const struct net *net = sock_net(listen_sk); bool th_ecn = th->ece && th->cwr; bool ect, ecn_ok; + u32 ecn_ok_dst; if (!th_ecn) return; ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield); - ecn_ok = net->ipv4.sysctl_tcp_ecn || dst_feature(dst, RTAX_FEATURE_ECN); + ecn_ok_dst = dst_feature(dst, DST_FEATURE_ECN_MASK); + ecn_ok = net->ipv4.sysctl_tcp_ecn || ecn_ok_dst; - if ((!ect && ecn_ok) || tcp_ca_needs_ecn(listen_sk)) + if ((!ect && ecn_ok) || tcp_ca_needs_ecn(listen_sk) || + (ecn_ok_dst & DST_FEATURE_ECN_CA)) inet_rsk(req)->ecn_ok = 1; } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 8771530df45ea..f45cac6f83563 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1698,6 +1698,7 @@ out: static int ip6_convert_metrics(struct mx6_config *mxc, const struct fib6_config *cfg) { + bool ecn_ca = false; struct nlattr *nla; int remaining; u32 *mp; @@ -1722,7 +1723,7 @@ static int ip6_convert_metrics(struct mx6_config *mxc, char tmp[TCP_CA_NAME_MAX]; nla_strlcpy(tmp, nla, sizeof(tmp)); - val = tcp_ca_get_key_by_name(tmp); + val = tcp_ca_get_key_by_name(tmp, &ecn_ca); if (val == TCP_CA_UNSPEC) goto err; } else { @@ -1735,8 +1736,12 @@ static int ip6_convert_metrics(struct mx6_config *mxc, __set_bit(type - 1, mxc->mx_valid); } - mxc->mx = mp; + if (ecn_ca) { + __set_bit(RTAX_FEATURES - 1, mxc->mx_valid); + mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA; + } + mxc->mx = mp; return 0; err: kfree(mp); -- GitLab From dbb7ee0e474cc8221de55583f516275693c5b552 Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Mon, 31 Aug 2015 08:57:10 -0700 Subject: [PATCH 5928/7006] lib: move strncpy_from_unsafe() into mm/maccess.c To fix build errors: kernel/built-in.o: In function `bpf_trace_printk': bpf_trace.c:(.text+0x11a254): undefined reference to `strncpy_from_unsafe' kernel/built-in.o: In function `fetch_memory_string': trace_kprobe.c:(.text+0x11acf8): undefined reference to `strncpy_from_unsafe' move strncpy_from_unsafe() next to probe_kernel_read/write() which use the same memory access style. Reported-by: Fengguang Wu Reported-by: Guenter Roeck Fixes: 1a6877b9c0c2 ("lib: introduce strncpy_from_unsafe()") Signed-off-by: Alexei Starovoitov Signed-off-by: David S. Miller --- lib/strncpy_from_user.c | 41 ----------------------------------------- mm/maccess.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c index ead8c4a068d12..e0af6ff73d146 100644 --- a/lib/strncpy_from_user.c +++ b/lib/strncpy_from_user.c @@ -112,44 +112,3 @@ long strncpy_from_user(char *dst, const char __user *src, long count) return -EFAULT; } EXPORT_SYMBOL(strncpy_from_user); - -/** - * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Unsafe address. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from unsafe address to kernel buffer. - * - * On success, returns the length of the string INCLUDING the trailing NUL. - * - * If access fails, returns -EFAULT (some data may have been copied - * and the trailing NUL added). - * - * If @count is smaller than the length of the string, copies @count-1 bytes, - * sets the last byte of @dst buffer to NUL and returns @count. - */ -long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) -{ - mm_segment_t old_fs = get_fs(); - const void *src = unsafe_addr; - long ret; - - if (unlikely(count <= 0)) - return 0; - - set_fs(KERNEL_DS); - pagefault_disable(); - - do { - ret = __copy_from_user_inatomic(dst++, - (const void __user __force *)src++, 1); - } while (dst[-1] && ret == 0 && src - unsafe_addr < count); - - dst[-1] = '\0'; - pagefault_enable(); - set_fs(old_fs); - - return ret < 0 ? ret : src - unsafe_addr; -} diff --git a/mm/maccess.c b/mm/maccess.c index d53adf9ba84bc..34fe24759ed1f 100644 --- a/mm/maccess.c +++ b/mm/maccess.c @@ -60,3 +60,44 @@ long __probe_kernel_write(void *dst, const void *src, size_t size) return ret ? -EFAULT : 0; } EXPORT_SYMBOL_GPL(probe_kernel_write); + +/** + * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address. + * @dst: Destination address, in kernel space. This buffer must be at + * least @count bytes long. + * @src: Unsafe address. + * @count: Maximum number of bytes to copy, including the trailing NUL. + * + * Copies a NUL-terminated string from unsafe address to kernel buffer. + * + * On success, returns the length of the string INCLUDING the trailing NUL. + * + * If access fails, returns -EFAULT (some data may have been copied + * and the trailing NUL added). + * + * If @count is smaller than the length of the string, copies @count-1 bytes, + * sets the last byte of @dst buffer to NUL and returns @count. + */ +long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) +{ + mm_segment_t old_fs = get_fs(); + const void *src = unsafe_addr; + long ret; + + if (unlikely(count <= 0)) + return 0; + + set_fs(KERNEL_DS); + pagefault_disable(); + + do { + ret = __copy_from_user_inatomic(dst++, + (const void __user __force *)src++, 1); + } while (dst[-1] && ret == 0 && src - unsafe_addr < count); + + dst[-1] = '\0'; + pagefault_enable(); + set_fs(old_fs); + + return ret < 0 ? ret : src - unsafe_addr; +} -- GitLab From f0fa6e529efbca3b97ab6286dbeb5910e33f6c53 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Mon, 31 Aug 2015 09:57:12 -0600 Subject: [PATCH 5929/7006] net: Add tos to validate source tracepoint TOS is another key aspect of the lookup passed to fib_validate_source. Add it to the tracepoint. Signed-off-by: David Ahern Signed-off-by: David S. Miller --- include/trace/events/fib.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/trace/events/fib.h b/include/trace/events/fib.h index 4030f75410d72..acd1d22571a2d 100644 --- a/include/trace/events/fib.h +++ b/include/trace/events/fib.h @@ -83,6 +83,7 @@ TRACE_EVENT(fib_validate_source, __string( name, dev->name ) __field( int, oif ) __field( int, iif ) + __field( __u8, tos ) __array( __u8, src, 4 ) __array( __u8, dst, 4 ) ), @@ -93,6 +94,7 @@ TRACE_EVENT(fib_validate_source, __assign_str(name, dev ? dev->name : "not set"); __entry->oif = flp->flowi4_oif; __entry->iif = flp->flowi4_iif; + __entry->tos = flp->flowi4_tos; p32 = (__be32 *) __entry->src; *p32 = flp->saddr; @@ -101,8 +103,8 @@ TRACE_EVENT(fib_validate_source, *p32 = flp->daddr; ), - TP_printk("dev %s oif %d iif %d src %pI4 dst %pI4", - __get_str(name), __entry->oif, __entry->iif, + TP_printk("dev %s oif %d iif %d tos %d src %pI4 dst %pI4", + __get_str(name), __entry->oif, __entry->iif, __entry->tos, __entry->src, __entry->dst) ); #endif /* _TRACE_FIB_H */ -- GitLab From 6ea3c9d5b042edf14eac1e21af21c41f81f3491e Mon Sep 17 00:00:00 2001 From: Nikolay Aleksandrov Date: Mon, 31 Aug 2015 10:44:19 -0700 Subject: [PATCH 5930/7006] mpls: fix mpls_net_init memory leak Fix a memory leak in the mpls netns init function in case of failure. If register_net_sysctl fails then we need to free the ctl_table. Fixes: 7720c01f3f59 ("mpls: Add a sysctl to control the size of the mpls label table") Signed-off-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- net/mpls/af_mpls.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/mpls/af_mpls.c b/net/mpls/af_mpls.c index 8c5707db53c5f..bb185a28de989 100644 --- a/net/mpls/af_mpls.c +++ b/net/mpls/af_mpls.c @@ -1177,8 +1177,10 @@ static int mpls_net_init(struct net *net) table[0].data = net; net->mpls.ctl = register_net_sysctl(net, "net/mpls", table); - if (net->mpls.ctl == NULL) + if (net->mpls.ctl == NULL) { + kfree(table); return -ENOMEM; + } return 0; } -- GitLab From dc9cee5db50afaf38506bc12eb479fb8ea536dba Mon Sep 17 00:00:00 2001 From: Mike Snitzer Date: Mon, 31 Aug 2015 15:41:34 -0400 Subject: [PATCH 5931/7006] dm cache: small cleanups related to deferred prison cell cleanup Eliminate __cell_release() since it only had one caller that always released the cell holder. Switch cell_error_with_code() to using free_prison_cell() for the sake of consistency. Signed-off-by: Mike Snitzer --- drivers/md/dm-cache-target.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index 2f60cbf404e52..e13e5edf22985 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -1063,14 +1063,6 @@ static void dec_io_migrations(struct cache *cache) atomic_dec(&cache->nr_io_migrations); } -static void __cell_release(struct cache *cache, struct dm_bio_prison_cell *cell, - bool holder, struct bio_list *bios) -{ - (holder ? dm_cell_release : dm_cell_release_no_holder) - (cache->prison, cell, bios); - free_prison_cell(cache, cell); -} - static bool discard_or_flush(struct bio *bio) { return bio->bi_rw & (REQ_FLUSH | REQ_FUA | REQ_DISCARD); @@ -1078,14 +1070,13 @@ static bool discard_or_flush(struct bio *bio) static void __cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell) { - if (discard_or_flush(cell->holder)) + if (discard_or_flush(cell->holder)) { /* - * We have to handle these bios - * individually. + * We have to handle these bios individually. */ - __cell_release(cache, cell, true, &cache->deferred_bios); - - else + dm_cell_release(cache->prison, cell, &cache->deferred_bios); + free_prison_cell(cache, cell); + } else list_add_tail(&cell->user_list, &cache->deferred_cells); } @@ -1112,7 +1103,7 @@ static void cell_defer(struct cache *cache, struct dm_bio_prison_cell *cell, boo static void cell_error_with_code(struct cache *cache, struct dm_bio_prison_cell *cell, int err) { dm_cell_error(cache->prison, cell, err); - dm_bio_prison_free_cell(cache->prison, cell); + free_prison_cell(cache, cell); } static void cell_requeue(struct cache *cache, struct dm_bio_prison_cell *cell) -- GitLab From acf860ae7c53cc8b0c5d372c218332aac3eeba4f Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Thu, 27 Aug 2015 02:30:55 +0000 Subject: [PATCH 5932/7006] bpf tools: New API to get name from a BPF object Before this patch there's no way to connect a loaded bpf object to its source file. However, during applying perf's '--filter' to BPF object, without this connection makes things harder, because perf loads all programs together, but '--filter' setting is for each object. The API of bpf_object__open_buffer() is changed to allow passing a name. Fortunately, at this time there's only one user of it (perf test LLVM), so we change it together. Signed-off-by: Wang Nan Cc: Alexei Starovoitov Cc: Brendan Gregg Cc: Daniel Borkmann Cc: David Ahern Cc: He Kuang Cc: Jiri Olsa Cc: Kaixu Xia Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1440742821-44548-2-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/lib/bpf/libbpf.c | 25 ++++++++++++++++++++++--- tools/lib/bpf/libbpf.h | 4 +++- tools/perf/tests/llvm.c | 2 +- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c index 4fa4bc4505f5b..4252fc22f78f4 100644 --- a/tools/lib/bpf/libbpf.c +++ b/tools/lib/bpf/libbpf.c @@ -880,15 +880,26 @@ struct bpf_object *bpf_object__open(const char *path) } struct bpf_object *bpf_object__open_buffer(void *obj_buf, - size_t obj_buf_sz) + size_t obj_buf_sz, + const char *name) { + char tmp_name[64]; + /* param validation */ if (!obj_buf || obj_buf_sz <= 0) return NULL; - pr_debug("loading object from buffer\n"); + if (!name) { + snprintf(tmp_name, sizeof(tmp_name), "%lx-%lx", + (unsigned long)obj_buf, + (unsigned long)obj_buf_sz); + tmp_name[sizeof(tmp_name) - 1] = '\0'; + name = tmp_name; + } + pr_debug("loading object '%s' from buffer\n", + name); - return __bpf_object__open("[buffer]", obj_buf, obj_buf_sz); + return __bpf_object__open(name, obj_buf, obj_buf_sz); } int bpf_object__unload(struct bpf_object *obj) @@ -975,6 +986,14 @@ bpf_object__next(struct bpf_object *prev) return next; } +const char * +bpf_object__get_name(struct bpf_object *obj) +{ + if (!obj) + return NULL; + return obj->path; +} + struct bpf_program * bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) { diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index ea8adc206b624..f16170c95ffdc 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h @@ -28,12 +28,14 @@ struct bpf_object; struct bpf_object *bpf_object__open(const char *path); struct bpf_object *bpf_object__open_buffer(void *obj_buf, - size_t obj_buf_sz); + size_t obj_buf_sz, + const char *name); void bpf_object__close(struct bpf_object *object); /* Load/unload object into/from kernel */ int bpf_object__load(struct bpf_object *obj); int bpf_object__unload(struct bpf_object *obj); +const char *bpf_object__get_name(struct bpf_object *obj); struct bpf_object *bpf_object__next(struct bpf_object *prev); #define bpf_object__for_each_safe(pos, tmp) \ diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c index a337356fd9790..52d55971f66f6 100644 --- a/tools/perf/tests/llvm.c +++ b/tools/perf/tests/llvm.c @@ -26,7 +26,7 @@ static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) { struct bpf_object *obj; - obj = bpf_object__open_buffer(obj_buf, obj_buf_sz); + obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, NULL); if (!obj) return -1; bpf_object__close(obj); -- GitLab From 6896f15aabde505b35888039af93d1d182a0108a Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 30 Jul 2015 21:52:44 +0800 Subject: [PATCH 5933/7006] nfsd: Fix an FS_LAYOUT_TYPES/LAYOUT_TYPES encode bug Currently we'll respond correctly to a request for either FS_LAYOUT_TYPES or LAYOUT_TYPES, but not to a request for both attributes simultaneously. Signed-off-by: Kinglong Mee Reviewed-by: Christoph Hellwig Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 1aa0dc38ed584..ea05dfb132495 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2140,6 +2140,27 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp, return nfsd4_encode_user(xdr, rqstp, ace->who_uid); } +static inline __be32 +nfsd4_encode_layout_type(struct xdr_stream *xdr, enum pnfs_layouttype layout_type) +{ + __be32 *p; + + if (layout_type) { + p = xdr_reserve_space(xdr, 8); + if (!p) + return nfserr_resource; + *p++ = cpu_to_be32(1); + *p++ = cpu_to_be32(layout_type); + } else { + p = xdr_reserve_space(xdr, 4); + if (!p) + return nfserr_resource; + *p++ = cpu_to_be32(0); + } + + return 0; +} + #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \ FATTR4_WORD0_RDATTR_ERROR) #define WORD1_ABSENT_FS_ATTRS FATTR4_WORD1_MOUNTED_ON_FILEID @@ -2695,20 +2716,16 @@ out_acl: p = xdr_encode_hyper(p, ino); } #ifdef CONFIG_NFSD_PNFS - if ((bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) || - (bmval2 & FATTR4_WORD2_LAYOUT_TYPES)) { - if (exp->ex_layout_type) { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); - *p++ = cpu_to_be32(exp->ex_layout_type); - } else { - p = xdr_reserve_space(xdr, 4); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(0); - } + if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) { + status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type); + if (status) + goto out; + } + + if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) { + status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type); + if (status) + goto out; } if (bmval2 & FATTR4_WORD2_LAYOUT_BLKSIZE) { -- GitLab From 7d580722c9f353d19e255f929d341caa821060d6 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 30 Jul 2015 21:54:26 +0800 Subject: [PATCH 5934/7006] nfsd: SUPPATTR_EXCLCREAT must be encoded before SECURITY_LABEL. The encode order should be as the bitmask defined order. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index ea05dfb132495..565b69ca04cd8 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2735,12 +2735,6 @@ out_acl: *p++ = cpu_to_be32(stat.blksize); } #endif /* CONFIG_NFSD_PNFS */ - if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { - status = nfsd4_encode_security_label(xdr, rqstp, context, - contextlen); - if (status) - goto out; - } if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { p = xdr_reserve_space(xdr, 16); if (!p) @@ -2751,6 +2745,13 @@ out_acl: *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD2); } + if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { + status = nfsd4_encode_security_label(xdr, rqstp, context, + contextlen); + if (status) + goto out; + } + attrlen = htonl(xdr->buf->len - attrlen_offset - 4); write_bytes_to_xdr_buf(xdr->buf, attrlen_offset, &attrlen, 4); status = nfs_ok; -- GitLab From ead8fb8c24411722b92198b3dccd102a76cdd050 Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 30 Jul 2015 21:55:02 +0800 Subject: [PATCH 5935/7006] NFSD: Set the attributes used to store the verifier for EXCLUSIVE4_1 According to rfc5661 18.16.4, "If EXCLUSIVE4_1 was used, the client determines the attributes used for the verifier by comparing attrset with cva_attrs.attrmask;" So, EXCLUSIVE4_1 also needs those bitmask used to store the verifier. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4proc.c | 12 ++++++------ fs/nfsd/vfs.c | 6 ------ fs/nfsd/vfs.h | 6 ++++++ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index b9681ee0ed19e..4ce6b97b31ade 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -276,13 +276,13 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval); /* - * Following rfc 3530 14.2.16, use the returned bitmask - * to indicate which attributes we used to store the - * verifier: + * Following rfc 3530 14.2.16, and rfc 5661 18.16.4 + * use the returned bitmask to indicate which attributes + * we used to store the verifier: */ - if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0) - open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS | - FATTR4_WORD1_TIME_MODIFY); + if (nfsd_create_is_exclusive(open->op_createmode) && status == 0) + open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS | + FATTR4_WORD1_TIME_MODIFY); } else /* * Note this may exit with the parent still locked. diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index b5e077a6e7d4d..45c04979e7b3c 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1249,12 +1249,6 @@ out_nfserr: #ifdef CONFIG_NFSD_V3 -static inline int nfsd_create_is_exclusive(int createmode) -{ - return createmode == NFS3_CREATE_EXCLUSIVE - || createmode == NFS4_CREATE_EXCLUSIVE4_1; -} - /* * NFSv3 and NFSv4 version of nfsd_create */ diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h index 5be875e3e638c..fee2451ae2482 100644 --- a/fs/nfsd/vfs.h +++ b/fs/nfsd/vfs.h @@ -131,4 +131,10 @@ static inline __be32 fh_getattr(struct svc_fh *fh, struct kstat *stat) return nfserrno(vfs_getattr(&p, stat)); } +static inline int nfsd_create_is_exclusive(int createmode) +{ + return createmode == NFS3_CREATE_EXCLUSIVE + || createmode == NFS4_CREATE_EXCLUSIVE4_1; +} + #endif /* LINUX_NFSD_VFS_H */ -- GitLab From 75976de6556f593f6c2a18bbbcfb1e594cc7598a Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Thu, 30 Jul 2015 21:55:30 +0800 Subject: [PATCH 5936/7006] NFSD: Return word2 bitmask if setting security label in OPEN/CREATE Security label can be set in OPEN/CREATE request, nfsd should set the bitmask in word2 if setting success. Signed-off-by: Kinglong Mee Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 95 ++++++++++++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 39 deletions(-) diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 565b69ca04cd8..51c9e9ca39a4d 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2226,6 +2226,39 @@ static int get_parent_attributes(struct svc_export *exp, struct kstat *stat) return err; } +static __be32 +nfsd4_encode_bitmap(struct xdr_stream *xdr, u32 bmval0, u32 bmval1, u32 bmval2) +{ + __be32 *p; + + if (bmval2) { + p = xdr_reserve_space(xdr, 16); + if (!p) + goto out_resource; + *p++ = cpu_to_be32(3); + *p++ = cpu_to_be32(bmval0); + *p++ = cpu_to_be32(bmval1); + *p++ = cpu_to_be32(bmval2); + } else if (bmval1) { + p = xdr_reserve_space(xdr, 12); + if (!p) + goto out_resource; + *p++ = cpu_to_be32(2); + *p++ = cpu_to_be32(bmval0); + *p++ = cpu_to_be32(bmval1); + } else { + p = xdr_reserve_space(xdr, 8); + if (!p) + goto out_resource; + *p++ = cpu_to_be32(1); + *p++ = cpu_to_be32(bmval0); + } + + return 0; +out_resource: + return nfserr_resource; +} + /* * Note: @fhp can be NULL; in this case, we might have to compose the filehandle * ourselves. @@ -2322,28 +2355,9 @@ nfsd4_encode_fattr(struct xdr_stream *xdr, struct svc_fh *fhp, } #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */ - if (bmval2) { - p = xdr_reserve_space(xdr, 16); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(3); - *p++ = cpu_to_be32(bmval0); - *p++ = cpu_to_be32(bmval1); - *p++ = cpu_to_be32(bmval2); - } else if (bmval1) { - p = xdr_reserve_space(xdr, 12); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(2); - *p++ = cpu_to_be32(bmval0); - *p++ = cpu_to_be32(bmval1); - } else { - p = xdr_reserve_space(xdr, 8); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(1); - *p++ = cpu_to_be32(bmval0); - } + status = nfsd4_encode_bitmap(xdr, bmval0, bmval1, bmval2); + if (status) + goto out; attrlen_offset = xdr->buf->len; p = xdr_reserve_space(xdr, 4); @@ -2736,13 +2750,11 @@ out_acl: } #endif /* CONFIG_NFSD_PNFS */ if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) { - p = xdr_reserve_space(xdr, 16); - if (!p) - goto out_resource; - *p++ = cpu_to_be32(3); - *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD0); - *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD1); - *p++ = cpu_to_be32(NFSD_SUPPATTR_EXCLCREAT_WORD2); + status = nfsd4_encode_bitmap(xdr, NFSD_SUPPATTR_EXCLCREAT_WORD0, + NFSD_SUPPATTR_EXCLCREAT_WORD1, + NFSD_SUPPATTR_EXCLCREAT_WORD2); + if (status) + goto out; } if (bmval2 & FATTR4_WORD2_SECURITY_LABEL) { @@ -3069,13 +3081,12 @@ nfsd4_encode_create(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_ __be32 *p; if (!nfserr) { - p = xdr_reserve_space(xdr, 32); + p = xdr_reserve_space(xdr, 20); if (!p) return nfserr_resource; - p = encode_cinfo(p, &create->cr_cinfo); - *p++ = cpu_to_be32(2); - *p++ = cpu_to_be32(create->cr_bmval[0]); - *p++ = cpu_to_be32(create->cr_bmval[1]); + encode_cinfo(p, &create->cr_cinfo); + nfserr = nfsd4_encode_bitmap(xdr, create->cr_bmval[0], + create->cr_bmval[1], create->cr_bmval[2]); } return nfserr; } @@ -3215,16 +3226,22 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_op nfserr = nfsd4_encode_stateid(xdr, &open->op_stateid); if (nfserr) goto out; - p = xdr_reserve_space(xdr, 40); + p = xdr_reserve_space(xdr, 24); if (!p) return nfserr_resource; p = encode_cinfo(p, &open->op_cinfo); *p++ = cpu_to_be32(open->op_rflags); - *p++ = cpu_to_be32(2); - *p++ = cpu_to_be32(open->op_bmval[0]); - *p++ = cpu_to_be32(open->op_bmval[1]); - *p++ = cpu_to_be32(open->op_delegate_type); + nfserr = nfsd4_encode_bitmap(xdr, open->op_bmval[0], open->op_bmval[1], + open->op_bmval[2]); + if (nfserr) + goto out; + + p = xdr_reserve_space(xdr, 4); + if (!p) + return nfserr_resource; + + *p++ = cpu_to_be32(open->op_delegate_type); switch (open->op_delegate_type) { case NFS4_OPEN_DELEGATE_NONE: break; -- GitLab From 1f65c17e15992193f1c3f735696872cb75191517 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 18 Aug 2015 15:34:44 -0400 Subject: [PATCH 5937/7006] nfsd: Add Jeff Layton as co-maintainer Jeff has been doing a lot of development (including much of the state-locking rewrite just as one example) plus lots of review and other miscellaneous nfsd work, so let's acknowledge the status quo. I'll continue to be the one to send regular pull requests but Jeff will should be available to cover there occasionally too. Signed-off-by: J. Bruce Fields --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index a2264167791ac..77628d12d3ce0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -5836,6 +5836,7 @@ S: Odd Fixes KERNEL NFSD, SUNRPC, AND LOCKD SERVERS M: "J. Bruce Fields" +M: Jeff Layton L: linux-nfs@vger.kernel.org W: http://nfs.sourceforge.net/ S: Supported -- GitLab From 7fadc59cc89f207ff6ca3d0951e11265fb4f806e Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sun, 9 Aug 2015 18:43:17 -0700 Subject: [PATCH 5938/7006] fs: fix fs/locks.c kernel-doc warning Fix kernel-doc warnings in fs/locks.c: Warning(..//fs/locks.c:1577): No description found for parameter 'flags' Signed-off-by: Randy Dunlap Signed-off-by: Jeff Layton --- fs/locks.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/locks.c b/fs/locks.c index d3d558ba4da79..2a54c800a2239 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1568,6 +1568,7 @@ int fcntl_getlease(struct file *filp) * desired lease. * @dentry: dentry to check * @arg: type of lease that we're trying to acquire + * @flags: current lock flags * * Check to see if there's an existing open fd on this file that would * conflict with the lease we're trying to set. -- GitLab From d988d5ee647861706bc7a391ddbc29429b50f00e Mon Sep 17 00:00:00 2001 From: Kan Liang Date: Fri, 21 Aug 2015 02:23:14 -0400 Subject: [PATCH 5939/7006] perf evlist: Open event on evsel cpus and threads An evsel may have different cpus and threads than the evlist it is in. Use it's own cpus and threads, when opening the evsel in 'perf record'. Signed-off-by: Kan Liang Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1440138194-17001-1-git-send-email-kan.liang@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-record.c | 2 +- tools/perf/util/evlist.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index a660022f2c929..1d14f382f6146 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -279,7 +279,7 @@ static int record__open(struct record *rec) evlist__for_each(evlist, pos) { try_again: - if (perf_evsel__open(pos, evlist->cpus, evlist->threads) < 0) { + if (perf_evsel__open(pos, pos->cpus, pos->threads) < 0) { if (perf_evsel__fallback(pos, errno, msg, sizeof(msg))) { if (verbose) ui__warning("%s\n", msg); diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 8d00039d6a20a..d51a5200c8af7 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c @@ -1181,6 +1181,10 @@ int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **e if (evsel->filter == NULL) continue; + /* + * filters only work for tracepoint event, which doesn't have cpu limit. + * So evlist and evsel should always be same. + */ err = perf_evsel__apply_filter(evsel, ncpus, nthreads, evsel->filter); if (err) { *err_evsel = evsel; -- GitLab From 46cc8ba30445025f0ed3ed9f429aea573b301122 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Tue, 25 Aug 2015 16:59:16 -0400 Subject: [PATCH 5940/7006] nfsd: don't WARN/backtrace for invalid container deployment. These messages, combined with the backtrace they trigger, makes it seem like a serious problem, though a quick search shows distros marking it as a "won't fix" non-issue when the problem is reported by users. The backtrace is overkill, and only really manages to show that if you follow the code path, you can't really avoid it with bootargs or configuration settings in the container. Given that, lets tone it down a bit and get rid of the WARN severity, and the associated backtrace, so people aren't needlessly alarmed. Also, lets drop the split printk line, since they are grep unfriendly. Signed-off-by: Paul Gortmaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4recover.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index 591bfbdf0316d..e3d47091b191d 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -547,8 +547,7 @@ nfsd4_legacy_tracking_init(struct net *net) /* XXX: The legacy code won't work in a container */ if (net != &init_net) { - WARN(1, KERN_ERR "NFSD: attempt to initialize legacy client " - "tracking in a container!\n"); + pr_warn("NFSD: attempt to initialize legacy client tracking in a container ignored.\n"); return -EINVAL; } @@ -1260,8 +1259,7 @@ nfsd4_umh_cltrack_init(struct net *net) /* XXX: The usermode helper s not working in container yet. */ if (net != &init_net) { - WARN(1, KERN_ERR "NFSD: attempt to initialize umh client " - "tracking in a container!\n"); + pr_warn("NFSD: attempt to initialize umh client tracking in a container ignored.\n"); return -EINVAL; } -- GitLab From 51a545685905c934237e640083bc3aa40b36dc14 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Thu, 20 Aug 2015 07:17:01 -0400 Subject: [PATCH 5941/7006] nfsd: allow more than one laundry job to run at a time We can potentially have several nfs4_laundromat jobs running if there are multiple namespaces running nfsd on the box. Those are effectively separated from one another though, so I don't see any reason to serialize them. Also, create_singlethread_workqueue automatically adds the WQ_MEM_RECLAIM flag. Since we run this job on a timer, it's not really involved in any reclaim paths. I see no need for a rescuer thread. Signed-off-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index c0c47a878cc61..af88d1d7ccae5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -6598,7 +6598,7 @@ nfs4_state_start(void) ret = set_callback_cred(); if (ret) return -ENOMEM; - laundry_wq = create_singlethread_workqueue("nfsd4"); + laundry_wq = alloc_workqueue("%s", WQ_UNBOUND, 0, "nfsd4"); if (laundry_wq == NULL) { ret = -ENOMEM; goto out_recovery; -- GitLab From 051ac3848a94f21cfdec899cc9c65ce7f9f116fa Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Thu, 27 Aug 2015 10:01:33 +0530 Subject: [PATCH 5942/7006] net: sunrpc: fix tracepoint Warning: unknown op '->' `perf stat -e sunrpc:svc_xprt_do_enqueue true` results in Warning: unknown op '->' Warning: [sunrpc:svc_xprt_do_enqueue] unknown op '->' Similar warning for svc_handle_xprt as well. Actually TP_printk() should never dereference an address saved in the ring buffer that points somewhere in the kernel. There's no guarantee that that object still exists (with the exception of static strings). Therefore change all the arguments for TP_printk(), so that it references values existing in the ring buffer only. While doing that, also fix another possible bug when argument xprt could be NULL and TP_fast_assign() tries to access it's elements. Signed-off-by: Pratyush Anand Reviewed-by: Jeff Layton Acked-by: Steven Rostedt Cc: stable@vger.kernel.org Fixes: 83a712e0afef "sunrpc: add some tracepoints around ..." Signed-off-by: J. Bruce Fields --- include/trace/events/sunrpc.h | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h index fd1a02cb3c823..003dca9338039 100644 --- a/include/trace/events/sunrpc.h +++ b/include/trace/events/sunrpc.h @@ -529,18 +529,21 @@ TRACE_EVENT(svc_xprt_do_enqueue, TP_STRUCT__entry( __field(struct svc_xprt *, xprt) - __field(struct svc_rqst *, rqst) + __field_struct(struct sockaddr_storage, ss) + __field(int, pid) + __field(unsigned long, flags) ), TP_fast_assign( __entry->xprt = xprt; - __entry->rqst = rqst; + xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss)); + __entry->pid = rqst? rqst->rq_task->pid : 0; + __entry->flags = xprt ? xprt->xpt_flags : 0; ), TP_printk("xprt=0x%p addr=%pIScp pid=%d flags=%s", __entry->xprt, - (struct sockaddr *)&__entry->xprt->xpt_remote, - __entry->rqst ? __entry->rqst->rq_task->pid : 0, - show_svc_xprt_flags(__entry->xprt->xpt_flags)) + (struct sockaddr *)&__entry->ss, + __entry->pid, show_svc_xprt_flags(__entry->flags)) ); TRACE_EVENT(svc_xprt_dequeue, @@ -589,16 +592,20 @@ TRACE_EVENT(svc_handle_xprt, TP_STRUCT__entry( __field(struct svc_xprt *, xprt) __field(int, len) + __field_struct(struct sockaddr_storage, ss) + __field(unsigned long, flags) ), TP_fast_assign( __entry->xprt = xprt; + xprt ? memcpy(&__entry->ss, &xprt->xpt_remote, sizeof(__entry->ss)) : memset(&__entry->ss, 0, sizeof(__entry->ss)); __entry->len = len; + __entry->flags = xprt ? xprt->xpt_flags : 0; ), TP_printk("xprt=0x%p addr=%pIScp len=%d flags=%s", __entry->xprt, - (struct sockaddr *)&__entry->xprt->xpt_remote, __entry->len, - show_svc_xprt_flags(__entry->xprt->xpt_flags)) + (struct sockaddr *)&__entry->ss, + __entry->len, show_svc_xprt_flags(__entry->flags)) ); #endif /* _TRACE_SUNRPC_H */ -- GitLab From e85687393f3ee0a77ccca016f903d1558bb69258 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 24 Aug 2015 12:41:47 -0400 Subject: [PATCH 5943/7006] nfsd: ensure that the ol stateid hash reference is only put once When an open or lock stateid is hashed, we take an extra reference to it. When we unhash it, we drop that reference. The code however does not properly account for the case where we have two callers concurrently trying to unhash the stateid. This can lead to list corruption and the hash reference being put more than once. Fix this by having unhash_ol_stateid use list_del_init on the st_perfile list_head, and then testing to see if that list_head is empty before releasing the hash reference. This means that some of the unhashing wrappers now become bool return functions so we can test to see whether the stateid was unhashed before we put the reference. Reported-by: Andrew W Elble Tested-by: Andrew W Elble Reported-by: Anna Schumaker Tested-by: Anna Schumaker Signed-off-by: Jeff Layton Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 58 ++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index af88d1d7ccae5..f318e706cb358 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1009,16 +1009,20 @@ static void nfs4_put_stateowner(struct nfs4_stateowner *sop) nfs4_free_stateowner(sop); } -static void unhash_ol_stateid(struct nfs4_ol_stateid *stp) +static bool unhash_ol_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_file *fp = stp->st_stid.sc_file; lockdep_assert_held(&stp->st_stateowner->so_client->cl_lock); + if (list_empty(&stp->st_perfile)) + return false; + spin_lock(&fp->fi_lock); - list_del(&stp->st_perfile); + list_del_init(&stp->st_perfile); spin_unlock(&fp->fi_lock); list_del(&stp->st_perstateowner); + return true; } static void nfs4_free_ol_stateid(struct nfs4_stid *stid) @@ -1068,25 +1072,27 @@ static void put_ol_stateid_locked(struct nfs4_ol_stateid *stp, list_add(&stp->st_locks, reaplist); } -static void unhash_lock_stateid(struct nfs4_ol_stateid *stp) +static bool unhash_lock_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); lockdep_assert_held(&oo->oo_owner.so_client->cl_lock); list_del_init(&stp->st_locks); - unhash_ol_stateid(stp); nfs4_unhash_stid(&stp->st_stid); + return unhash_ol_stateid(stp); } static void release_lock_stateid(struct nfs4_ol_stateid *stp) { struct nfs4_openowner *oo = openowner(stp->st_openstp->st_stateowner); + bool unhashed; spin_lock(&oo->oo_owner.so_client->cl_lock); - unhash_lock_stateid(stp); + unhashed = unhash_lock_stateid(stp); spin_unlock(&oo->oo_owner.so_client->cl_lock); - nfs4_put_stid(&stp->st_stid); + if (unhashed) + nfs4_put_stid(&stp->st_stid); } static void unhash_lockowner_locked(struct nfs4_lockowner *lo) @@ -1134,7 +1140,7 @@ static void release_lockowner(struct nfs4_lockowner *lo) while (!list_empty(&lo->lo_owner.so_stateids)) { stp = list_first_entry(&lo->lo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); - unhash_lock_stateid(stp); + WARN_ON(!unhash_lock_stateid(stp)); put_ol_stateid_locked(stp, &reaplist); } spin_unlock(&clp->cl_lock); @@ -1147,21 +1153,26 @@ static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp, { struct nfs4_ol_stateid *stp; + lockdep_assert_held(&open_stp->st_stid.sc_client->cl_lock); + while (!list_empty(&open_stp->st_locks)) { stp = list_entry(open_stp->st_locks.next, struct nfs4_ol_stateid, st_locks); - unhash_lock_stateid(stp); + WARN_ON(!unhash_lock_stateid(stp)); put_ol_stateid_locked(stp, reaplist); } } -static void unhash_open_stateid(struct nfs4_ol_stateid *stp, +static bool unhash_open_stateid(struct nfs4_ol_stateid *stp, struct list_head *reaplist) { + bool unhashed; + lockdep_assert_held(&stp->st_stid.sc_client->cl_lock); - unhash_ol_stateid(stp); + unhashed = unhash_ol_stateid(stp); release_open_stateid_locks(stp, reaplist); + return unhashed; } static void release_open_stateid(struct nfs4_ol_stateid *stp) @@ -1169,8 +1180,8 @@ static void release_open_stateid(struct nfs4_ol_stateid *stp) LIST_HEAD(reaplist); spin_lock(&stp->st_stid.sc_client->cl_lock); - unhash_open_stateid(stp, &reaplist); - put_ol_stateid_locked(stp, &reaplist); + if (unhash_open_stateid(stp, &reaplist)) + put_ol_stateid_locked(stp, &reaplist); spin_unlock(&stp->st_stid.sc_client->cl_lock); free_ol_stateid_reaplist(&reaplist); } @@ -1215,8 +1226,8 @@ static void release_openowner(struct nfs4_openowner *oo) while (!list_empty(&oo->oo_owner.so_stateids)) { stp = list_first_entry(&oo->oo_owner.so_stateids, struct nfs4_ol_stateid, st_perstateowner); - unhash_open_stateid(stp, &reaplist); - put_ol_stateid_locked(stp, &reaplist); + if (unhash_open_stateid(stp, &reaplist)) + put_ol_stateid_locked(stp, &reaplist); } spin_unlock(&clp->cl_lock); free_ol_stateid_reaplist(&reaplist); @@ -4752,7 +4763,7 @@ nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (check_for_locks(stp->st_stid.sc_file, lockowner(stp->st_stateowner))) break; - unhash_lock_stateid(stp); + WARN_ON(!unhash_lock_stateid(stp)); spin_unlock(&cl->cl_lock); nfs4_put_stid(s); ret = nfs_ok; @@ -4968,20 +4979,23 @@ out: static void nfsd4_close_open_stateid(struct nfs4_ol_stateid *s) { struct nfs4_client *clp = s->st_stid.sc_client; + bool unhashed; LIST_HEAD(reaplist); s->st_stid.sc_type = NFS4_CLOSED_STID; spin_lock(&clp->cl_lock); - unhash_open_stateid(s, &reaplist); + unhashed = unhash_open_stateid(s, &reaplist); if (clp->cl_minorversion) { - put_ol_stateid_locked(s, &reaplist); + if (unhashed) + put_ol_stateid_locked(s, &reaplist); spin_unlock(&clp->cl_lock); free_ol_stateid_reaplist(&reaplist); } else { spin_unlock(&clp->cl_lock); free_ol_stateid_reaplist(&reaplist); - move_to_close_lru(s, clp->net); + if (unhashed) + move_to_close_lru(s, clp->net); } } @@ -6014,7 +6028,7 @@ nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst, static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, struct list_head *collect, - void (*func)(struct nfs4_ol_stateid *)) + bool (*func)(struct nfs4_ol_stateid *)) { struct nfs4_openowner *oop; struct nfs4_ol_stateid *stp, *st_next; @@ -6028,9 +6042,9 @@ static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max, list_for_each_entry_safe(lst, lst_next, &stp->st_locks, st_locks) { if (func) { - func(lst); - nfsd_inject_add_lock_to_list(lst, - collect); + if (func(lst)) + nfsd_inject_add_lock_to_list(lst, + collect); } ++count; /* -- GitLab From 3fcbbd244ed1d20dc0eb7d48d729503992fa9b7d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Mon, 24 Aug 2015 12:41:48 -0400 Subject: [PATCH 5944/7006] nfsd: ensure that delegation stateid hash references are only put once It's possible that a DELEGRETURN could race with (e.g.) client expiry, in which case we could end up putting the delegation hash reference more than once. Have unhash_delegation_locked return a bool that indicates whether it was already unhashed. In the case of destroy_delegation we only conditionally put the hash reference if that returns true. The other callers of unhash_delegation_locked call it while walking list_heads that shouldn't yet be detached. If we find that it doesn't return true in those cases, then throw a WARN_ON as that indicates that we have a partially hashed delegation, and that something is likely very wrong. Tested-by: Andrew W Elble Tested-by: Anna Schumaker Signed-off-by: Jeff Layton Cc: stable@vger.kernel.org Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index f318e706cb358..416f32e34a33c 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -777,13 +777,16 @@ hash_delegation_locked(struct nfs4_delegation *dp, struct nfs4_file *fp) list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations); } -static void +static bool unhash_delegation_locked(struct nfs4_delegation *dp) { struct nfs4_file *fp = dp->dl_stid.sc_file; lockdep_assert_held(&state_lock); + if (list_empty(&dp->dl_perfile)) + return false; + dp->dl_stid.sc_type = NFS4_CLOSED_DELEG_STID; /* Ensure that deleg break won't try to requeue it */ ++dp->dl_time; @@ -792,16 +795,21 @@ unhash_delegation_locked(struct nfs4_delegation *dp) list_del_init(&dp->dl_recall_lru); list_del_init(&dp->dl_perfile); spin_unlock(&fp->fi_lock); + return true; } static void destroy_delegation(struct nfs4_delegation *dp) { + bool unhashed; + spin_lock(&state_lock); - unhash_delegation_locked(dp); + unhashed = unhash_delegation_locked(dp); spin_unlock(&state_lock); - put_clnt_odstate(dp->dl_clnt_odstate); - nfs4_put_deleg_lease(dp->dl_stid.sc_file); - nfs4_put_stid(&dp->dl_stid); + if (unhashed) { + put_clnt_odstate(dp->dl_clnt_odstate); + nfs4_put_deleg_lease(dp->dl_stid.sc_file); + nfs4_put_stid(&dp->dl_stid); + } } static void revoke_delegation(struct nfs4_delegation *dp) @@ -1730,7 +1738,7 @@ __destroy_client(struct nfs4_client *clp) spin_lock(&state_lock); while (!list_empty(&clp->cl_delegations)) { dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt); - unhash_delegation_locked(dp); + WARN_ON(!unhash_delegation_locked(dp)); list_add(&dp->dl_recall_lru, &reaplist); } spin_unlock(&state_lock); @@ -4357,7 +4365,7 @@ nfs4_laundromat(struct nfsd_net *nn) new_timeo = min(new_timeo, t); break; } - unhash_delegation_locked(dp); + WARN_ON(!unhash_delegation_locked(dp)); list_add(&dp->dl_recall_lru, &reaplist); } spin_unlock(&state_lock); @@ -6314,7 +6322,7 @@ static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max, continue; atomic_inc(&clp->cl_refcount); - unhash_delegation_locked(dp); + WARN_ON(!unhash_delegation_locked(dp)); list_add(&dp->dl_recall_lru, victims); } ++count; @@ -6645,7 +6653,7 @@ nfs4_state_shutdown_net(struct net *net) spin_lock(&state_lock); list_for_each_safe(pos, next, &nn->del_recall_lru) { dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru); - unhash_delegation_locked(dp); + WARN_ON(!unhash_delegation_locked(dp)); list_add(&dp->dl_recall_lru, &reaplist); } spin_unlock(&state_lock); -- GitLab From bdbf4a29ee5bbe5b6743ba47bc7b10ec2cba8b21 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 26 Aug 2015 23:59:33 +0300 Subject: [PATCH 5945/7006] i2c: muxes: fix leaked i2c adapter device node references Every call of of_parse_phandle() increments user count of found device node, if OF_DYNAMIC is enabled. The change fixes all similar addressed cases in drivers/i2c. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-arb-gpio-challenge.c | 1 + drivers/i2c/muxes/i2c-mux-gpio.c | 1 + drivers/i2c/muxes/i2c-mux-pinctrl.c | 1 + drivers/i2c/muxes/i2c-mux-reg.c | 1 + 4 files changed, 4 insertions(+) diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 71aac0911bf75..402e3a6c671a1 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -197,6 +197,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) return -EINVAL; } arb->parent = of_get_i2c_adapter_by_node(parent_np); + of_node_put(parent_np); if (!arb->parent) { dev_err(dev, "Cannot find parent bus\n"); return -EPROBE_DEFER; diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 70db99264339e..b8e11c16d98c6 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -76,6 +76,7 @@ static int i2c_mux_gpio_probe_dt(struct gpiomux *mux, return -ENODEV; } adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); if (!adapter) return -EPROBE_DEFER; diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index b48378c4b40d6..b5a982ba88986 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -111,6 +111,7 @@ static int i2c_mux_pinctrl_parse_dt(struct i2c_mux_pinctrl *mux, return -ENODEV; } adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); if (!adapter) { dev_err(mux->dev, "Cannot find parent bus\n"); return -EPROBE_DEFER; diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 86d41d36a7834..57ec57e0da529 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -106,6 +106,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, return -ENODEV; } adapter = of_find_i2c_adapter_by_node(adapter_np); + of_node_put(adapter_np); if (!adapter) return -EPROBE_DEFER; -- GitLab From fc36f9485aee3a62b22be1f561543a31bce6d48e Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 31 Aug 2015 18:41:10 +0200 Subject: [PATCH 5946/7006] perf script: Enable printing of interrupted machine state This patch adds the output of the interrupted machine state (iregs) to perf script. It presents them as NAME:VALUE so this is easy to parse during post processing. To capture the interrupted machine state: $ perf record -I .... to display iregs, use the -F option: $ perf script -F ip,iregs 40afc2 AX:0x6c5770 BX:0x1e CX:0x5f4d80a DX:0x101010101010101 SI:0x1 Signed-off-by: Stephane Eranian Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441039273-16260-2-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script.txt | 2 +- tools/perf/builtin-script.c | 31 +++++++++++++++++++++++- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 614b2c7b0293e..dc3ec783b7bd5 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt @@ -116,7 +116,7 @@ OPTIONS --fields:: Comma separated list of fields to print. Options are: comm, tid, pid, time, cpu, event, trace, ip, sym, dso, addr, symoff, - srcline, period, flags. + srcline, period, iregs, flags. Field list can be prepended with the type, trace, sw or hw, to indicate to which event type the field list applies. e.g., -f sw:comm,tid,time,ip,sym and -f trace:time,cpu,trace diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 4430340292c05..eb51325e8ad99 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -6,6 +6,7 @@ #include "util/exec_cmd.h" #include "util/header.h" #include "util/parse-options.h" +#include "util/perf_regs.h" #include "util/session.h" #include "util/tool.h" #include "util/symbol.h" @@ -46,6 +47,7 @@ enum perf_output_field { PERF_OUTPUT_SYMOFFSET = 1U << 11, PERF_OUTPUT_SRCLINE = 1U << 12, PERF_OUTPUT_PERIOD = 1U << 13, + PERF_OUTPUT_IREGS = 1U << 14, }; struct output_option { @@ -66,6 +68,7 @@ struct output_option { {.str = "symoff", .field = PERF_OUTPUT_SYMOFFSET}, {.str = "srcline", .field = PERF_OUTPUT_SRCLINE}, {.str = "period", .field = PERF_OUTPUT_PERIOD}, + {.str = "iregs", .field = PERF_OUTPUT_IREGS}, }; /* default set to maintain compatibility with current format */ @@ -255,6 +258,11 @@ static int perf_evsel__check_attr(struct perf_evsel *evsel, PERF_OUTPUT_PERIOD)) return -EINVAL; + if (PRINT_FIELD(IREGS) && + perf_evsel__check_stype(evsel, PERF_SAMPLE_REGS_INTR, "IREGS", + PERF_OUTPUT_IREGS)) + return -EINVAL; + return 0; } @@ -352,6 +360,24 @@ out: return 0; } +static void print_sample_iregs(union perf_event *event __maybe_unused, + struct perf_sample *sample, + struct thread *thread __maybe_unused, + struct perf_event_attr *attr) +{ + struct regs_dump *regs = &sample->intr_regs; + uint64_t mask = attr->sample_regs_intr; + unsigned i = 0, r; + + if (!regs) + return; + + for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { + u64 val = regs->regs[i++]; + printf("%5s:0x%"PRIx64" ", perf_reg_name(r), val); + } +} + static void print_sample_start(struct perf_sample *sample, struct thread *thread, struct perf_evsel *evsel) @@ -525,6 +551,9 @@ static void process_event(union perf_event *event, struct perf_sample *sample, PERF_MAX_STACK_DEPTH); } + if (PRINT_FIELD(IREGS)) + print_sample_iregs(event, sample, thread, attr); + printf("\n"); } @@ -1643,7 +1672,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) "comma separated output fields prepend with 'type:'. " "Valid types: hw,sw,trace,raw. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," - "addr,symoff,period,flags", parse_output_fields), + "addr,symoff,period,iregs,flags", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", -- GitLab From c5e991ee9dff0f8136168ed2d0d1a8cc3620dac4 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 31 Aug 2015 18:41:11 +0200 Subject: [PATCH 5947/7006] perf/x86: Add list of register names This patch adds a way to locate a register identifier (PERF_X86_REG_*) based on its name, e.g., AX. This will be used by a subsequent patch to improved flexibility of perf record. Signed-off-by: Stephane Eranian Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441039273-16260-3-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/Build | 1 + tools/perf/arch/x86/util/perf_regs.c | 30 ++++++++++++++++++++++++++++ tools/perf/util/perf_regs.h | 7 +++++++ 3 files changed, 38 insertions(+) create mode 100644 tools/perf/arch/x86/util/perf_regs.c diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build index 2c55e1b336c53..ff63649fa9ac6 100644 --- a/tools/perf/arch/x86/util/Build +++ b/tools/perf/arch/x86/util/Build @@ -2,6 +2,7 @@ libperf-y += header.o libperf-y += tsc.o libperf-y += pmu.o libperf-y += kvm-stat.o +libperf-y += perf_regs.o libperf-$(CONFIG_DWARF) += dwarf-regs.o diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c new file mode 100644 index 0000000000000..087c84ef52341 --- /dev/null +++ b/tools/perf/arch/x86/util/perf_regs.c @@ -0,0 +1,30 @@ +#include "../../perf.h" +#include "../../util/perf_regs.h" + +#define REG(n, b) { .name = #n, .mask = 1ULL << (b) } +#define REG_END { .name = NULL } +const struct sample_reg sample_reg_masks[] = { + REG(AX, PERF_REG_X86_AX), + REG(BX, PERF_REG_X86_BX), + REG(CX, PERF_REG_X86_CX), + REG(DX, PERF_REG_X86_DX), + REG(SI, PERF_REG_X86_SI), + REG(DI, PERF_REG_X86_DI), + REG(BP, PERF_REG_X86_BP), + REG(SP, PERF_REG_X86_SP), + REG(IP, PERF_REG_X86_IP), + REG(FLAGS, PERF_REG_X86_FLAGS), + REG(CS, PERF_REG_X86_CS), + REG(SS, PERF_REG_X86_SS), +#ifdef HAVE_ARCH_X86_64_SUPPORT + REG(R8, PERF_REG_X86_R8), + REG(R9, PERF_REG_X86_R9), + REG(R10, PERF_REG_X86_R10), + REG(R11, PERF_REG_X86_R11), + REG(R12, PERF_REG_X86_R12), + REG(R13, PERF_REG_X86_R13), + REG(R14, PERF_REG_X86_R14), + REG(R15, PERF_REG_X86_R15), +#endif + REG_END +}; diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 980dbf76bc984..92c1fff2153eb 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -5,6 +5,13 @@ struct regs_dump; +struct sample_reg { + const char *name; + uint64_t mask; +}; + +extern const struct sample_reg sample_reg_masks[]; + #ifdef HAVE_PERF_REGS_SUPPORT #include -- GitLab From bcc84ec65ad1bd9f777a1fade6f8e5e0c5808fa5 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Mon, 31 Aug 2015 18:41:12 +0200 Subject: [PATCH 5948/7006] perf record: Add ability to name registers to record This patch modifies the -I/--int-regs option to enablepassing the name of the registers to sample on interrupt. Registers can be specified by their symbolic names. For instance on x86, --intr-regs=ax,si. The motivation is to reduce the size of the perf.data file and the overhead of sampling by only collecting the registers useful to a specific analysis. For instance, for value profiling, sampling only the registers used to passed arguements to functions. With no parameter, the --intr-regs still records all possible registers based on the architecture. To name registers, it is necessary to use the long form of the option, i.e., --intr-regs: $ perf record --intr-regs=si,di,r8,r9 ..... To record any possible registers: $ perf record -I ..... $ perf report --intr-regs ... To display the register, one can use perf report -D To list the available registers: $ perf record --intr-regs=\? available registers: AX BX CX DX SI DI BP SP IP FLAGS CS SS R8 R9 R10 R11 R12 R13 R14 R15 Signed-off-by: Stephane Eranian Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Jiri Olsa Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441039273-16260-4-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-record.txt | 6 +- tools/perf/builtin-record.c | 7 ++- tools/perf/perf.h | 2 +- tools/perf/util/Build | 1 + tools/perf/util/evsel.c | 2 +- tools/perf/util/parse-regs-options.c | 71 ++++++++++++++++++++++++ tools/perf/util/parse-regs-options.h | 5 ++ 7 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 tools/perf/util/parse-regs-options.c create mode 100644 tools/perf/util/parse-regs-options.h diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 347a27322ed81..2e9ce77b5e144 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -276,7 +276,11 @@ filter out the startup phase of the program, which is often very different. --intr-regs:: Capture machine state (registers) at interrupt, i.e., on counter overflows for each sample. List of captured registers depends on the architecture. This option -is off by default. +is off by default. It is possible to select the registers to sample using their +symbolic names, e.g. on x86, ax, si. To list the available registers use +--intr-regs=\?. To name registers, pass a comma separated list such as +--intr-regs=ax,bx. The list of register is architecture dependent. + --running-time:: Record running and enabled time for read events (:S) diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 1d14f382f6146..142eeb341b295 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c @@ -27,8 +27,10 @@ #include "util/cpumap.h" #include "util/thread_map.h" #include "util/data.h" +#include "util/perf_regs.h" #include "util/auxtrace.h" #include "util/parse-branch-options.h" +#include "util/parse-regs-options.h" #include #include @@ -1080,8 +1082,9 @@ struct option __record_options[] = { "sample transaction flags (special events only)"), OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread, "use per-thread mmaps"), - OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs, - "Sample machine registers on interrupt"), + OPT_CALLBACK_OPTARG('I', "intr-regs", &record.opts.sample_intr_regs, NULL, "any register", + "sample selected machine registers on interrupt," + " use -I ? to list register names", parse_regs), OPT_BOOLEAN(0, "running-time", &record.opts.running_time, "Record running/enabled time of read (:S) events"), OPT_CALLBACK('k', "clockid", &record.opts, diff --git a/tools/perf/perf.h b/tools/perf/perf.h index cccb4cf575d3a..90129accffbe8 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h @@ -54,7 +54,6 @@ struct record_opts { bool sample_time_set; bool callgraph_set; bool period; - bool sample_intr_regs; bool running_time; bool full_auxtrace; bool auxtrace_snapshot_mode; @@ -64,6 +63,7 @@ struct record_opts { unsigned int auxtrace_mmap_pages; unsigned int user_freq; u64 branch_stack; + u64 sample_intr_regs; u64 default_interval; u64 user_interval; size_t auxtrace_snapshot_size; diff --git a/tools/perf/util/Build b/tools/perf/util/Build index e79e4522368ad..349bc96ca1fed 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -83,6 +83,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ libperf-$(CONFIG_AUXTRACE) += intel-pt.o libperf-$(CONFIG_AUXTRACE) += intel-bts.o libperf-y += parse-branch-options.o +libperf-y += parse-regs-options.o libperf-$(CONFIG_LIBELF) += symbol-elf.o libperf-$(CONFIG_LIBELF) += probe-file.o diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index bac25f41a7518..c53f79123b37f 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -787,7 +787,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) perf_evsel__config_callgraph(evsel, opts, &callchain_param); if (opts->sample_intr_regs) { - attr->sample_regs_intr = PERF_REGS_MASK; + attr->sample_regs_intr = opts->sample_intr_regs; perf_evsel__set_sample_bit(evsel, REGS_INTR); } diff --git a/tools/perf/util/parse-regs-options.c b/tools/perf/util/parse-regs-options.c new file mode 100644 index 0000000000000..4f2c1c255d818 --- /dev/null +++ b/tools/perf/util/parse-regs-options.c @@ -0,0 +1,71 @@ +#include "perf.h" +#include "util/util.h" +#include "util/debug.h" +#include "util/parse-options.h" +#include "util/parse-regs-options.h" + +int +parse_regs(const struct option *opt, const char *str, int unset) +{ + uint64_t *mode = (uint64_t *)opt->value; + const struct sample_reg *r; + char *s, *os = NULL, *p; + int ret = -1; + + if (unset) + return 0; + + /* + * cannot set it twice + */ + if (*mode) + return -1; + + /* str may be NULL in case no arg is passed to -I */ + if (str) { + /* because str is read-only */ + s = os = strdup(str); + if (!s) + return -1; + + for (;;) { + p = strchr(s, ','); + if (p) + *p = '\0'; + + if (!strcmp(s, "?")) { + fprintf(stderr, "available registers: "); + for (r = sample_reg_masks; r->name; r++) { + fprintf(stderr, "%s ", r->name); + } + fputc('\n', stderr); + /* just printing available regs */ + return -1; + } + for (r = sample_reg_masks; r->name; r++) { + if (!strcasecmp(s, r->name)) + break; + } + if (!r->name) { + ui__warning("unknown register %s," + " check man page\n", s); + goto error; + } + + *mode |= r->mask; + + if (!p) + break; + + s = p + 1; + } + } + ret = 0; + + /* default to all possible regs */ + if (*mode == 0) + *mode = PERF_REGS_MASK; +error: + free(os); + return ret; +} diff --git a/tools/perf/util/parse-regs-options.h b/tools/perf/util/parse-regs-options.h new file mode 100644 index 0000000000000..7d762b188007f --- /dev/null +++ b/tools/perf/util/parse-regs-options.h @@ -0,0 +1,5 @@ +#ifndef _PERF_PARSE_REGS_OPTIONS_H +#define _PERF_PARSE_REGS_OPTIONS_H 1 +struct option; +int parse_regs(const struct option *opt, const char *str, int unset); +#endif /* _PERF_PARSE_REGS_OPTIONS_H */ -- GitLab From 5a11dd7d9649149f336ca72069d56ce52b21567f Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 31 Aug 2015 15:56:46 +0200 Subject: [PATCH 5949/7006] net: phy: Allow PHY devices to identify themselves as Ethernet switches, etc. Some Ethernet MAC drivers using the PHY library require the hardcoding of link parameters when interfaced to a switch device, SFP module, switch to switch port, etc. This has typically lead to various ad-hoc implementations looking like this: - using a "fixed PHY" emulated device, which will provide link indication towards the Ethernet MAC driver and hardware - pretend there is no PHY and hardcode link parameters, ala mv643x_eth Based on that, it is desireable to have the PHY drivers advertise the correct link parameters, just like regular Ethernet PHYs towards their CPU Ethernet MAC drivers, however, Ethernet MAC drivers should be able to tell whether this link should be monitored or not. In the context of an Ethernet switch, SFP module, switch to switch link, we do not need to monitor this link since it should be always up. Signed-off-by: Florian Fainelli Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 1 + include/linux/phy.h | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 99d9bc19c94a0..ce46428ff21fa 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -303,6 +303,7 @@ struct phy_device *fixed_phy_register(unsigned int irq, of_node_get(np); phy->dev.of_node = np; + phy->is_pseudo_fixed_link = true; ret = phy_device_register(phy); if (ret) { diff --git a/include/linux/phy.h b/include/linux/phy.h index e5fb1d4159619..962387a192f15 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -330,6 +330,7 @@ struct phy_c45_device_ids { * c45_ids: 802.3-c45 Device Identifers if is_c45. * is_c45: Set to true if this phy uses clause 45 addressing. * is_internal: Set to true if this phy is internal to a MAC. + * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc. * has_fixups: Set to true if this phy has fixups/quirks. * suspended: Set to true if this phy has been suspended successfully. * state: state of the PHY for management purposes @@ -368,6 +369,7 @@ struct phy_device { struct phy_c45_device_ids c45_ids; bool is_c45; bool is_internal; + bool is_pseudo_fixed_link; bool has_fixups; bool suspended; @@ -688,6 +690,16 @@ static inline bool phy_interface_is_rgmii(struct phy_device *phydev) { return phydev->interface >= PHY_INTERFACE_MODE_RGMII && phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID; +}; + +/* + * phy_is_pseudo_fixed_link - Convenience function for testing if this + * PHY is the CPU port facing side of an Ethernet switch, or similar. + * @phydev: the phy_device struct + */ +static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev) +{ + return phydev->is_pseudo_fixed_link; } /** -- GitLab From dea870242a9c4ea74b3ca0f2da3f864c47484cff Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:47 +0200 Subject: [PATCH 5950/7006] dsa: mv88e6xxx: Allow speed/duplex of port to be configured The current code sets user ports to perform auto negotiation using the phy. CPU and DSA ports are configured to full duplex and maximum speed the switch supports. There are however use cases where the CPU has a slower port, and when user ports have SFP modules with fixed speed. In these cases, port settings to be read from a fixed_phy devices. The switch driver then needs to implement the adjust_link op, so the port settings can be set. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6123_61_65.c | 1 + drivers/net/dsa/mv88e6131.c | 1 + drivers/net/dsa/mv88e6171.c | 1 + drivers/net/dsa/mv88e6352.c | 1 + drivers/net/dsa/mv88e6xxx.c | 58 +++++++++++++++++++++++++++++++ drivers/net/dsa/mv88e6xxx.h | 2 ++ 6 files changed, 64 insertions(+) diff --git a/drivers/net/dsa/mv88e6123_61_65.c b/drivers/net/dsa/mv88e6123_61_65.c index 71a29a7ce538d..3de2a6d73fdc4 100644 --- a/drivers/net/dsa/mv88e6123_61_65.c +++ b/drivers/net/dsa/mv88e6123_61_65.c @@ -129,6 +129,7 @@ struct dsa_switch_driver mv88e6123_61_65_switch_driver = { .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_sset_count = mv88e6xxx_get_sset_count, + .adjust_link = mv88e6xxx_adjust_link, #ifdef CONFIG_NET_DSA_HWMON .get_temp = mv88e6xxx_get_temp, #endif diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c index 32f4a08e9bc99..3e83865299650 100644 --- a/drivers/net/dsa/mv88e6131.c +++ b/drivers/net/dsa/mv88e6131.c @@ -182,6 +182,7 @@ struct dsa_switch_driver mv88e6131_switch_driver = { .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_sset_count = mv88e6xxx_get_sset_count, + .adjust_link = mv88e6xxx_adjust_link, }; MODULE_ALIAS("platform:mv88e6085"); diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 735f04cd83eec..d54b7400e8d82 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -108,6 +108,7 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_sset_count = mv88e6xxx_get_sset_count, + .adjust_link = mv88e6xxx_adjust_link, #ifdef CONFIG_NET_DSA_HWMON .get_temp = mv88e6xxx_get_temp, #endif diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index 14b71779df99d..1f5129c105fb3 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -328,6 +328,7 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .get_strings = mv88e6xxx_get_strings, .get_ethtool_stats = mv88e6xxx_get_ethtool_stats, .get_sset_count = mv88e6xxx_get_sset_count, + .adjust_link = mv88e6xxx_adjust_link, .set_eee = mv88e6xxx_set_eee, .get_eee = mv88e6xxx_get_eee, #ifdef CONFIG_NET_DSA_HWMON diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 3774f53d28d78..1a8c45f3e6805 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -560,6 +561,63 @@ static bool mv88e6xxx_6352_family(struct dsa_switch *ds) return false; } +/* We expect the switch to perform auto negotiation if there is a real + * phy. However, in the case of a fixed link phy, we force the port + * settings from the fixed link settings. + */ +void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + u32 ret, reg; + + if (!phy_is_pseudo_fixed_link(phydev)) + return; + + mutex_lock(&ps->smi_mutex); + + ret = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_PCS_CTRL); + if (ret < 0) + goto out; + + reg = ret & ~(PORT_PCS_CTRL_LINK_UP | + PORT_PCS_CTRL_FORCE_LINK | + PORT_PCS_CTRL_DUPLEX_FULL | + PORT_PCS_CTRL_FORCE_DUPLEX | + PORT_PCS_CTRL_UNFORCED); + + reg |= PORT_PCS_CTRL_FORCE_LINK; + if (phydev->link) + reg |= PORT_PCS_CTRL_LINK_UP; + + if (mv88e6xxx_6065_family(ds) && phydev->speed > SPEED_100) + goto out; + + switch (phydev->speed) { + case SPEED_1000: + reg |= PORT_PCS_CTRL_1000; + break; + case SPEED_100: + reg |= PORT_PCS_CTRL_100; + break; + case SPEED_10: + reg |= PORT_PCS_CTRL_10; + break; + default: + pr_info("Unknown speed"); + goto out; + } + + reg |= PORT_PCS_CTRL_FORCE_DUPLEX; + if (phydev->duplex == DUPLEX_FULL) + reg |= PORT_PCS_CTRL_DUPLEX_FULL; + + _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_PCS_CTRL, reg); + +out: + mutex_unlock(&ps->smi_mutex); +} + /* Must be called with SMI mutex held */ static int _mv88e6xxx_stats_wait(struct dsa_switch *ds) { diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 72ca887feb0d5..79003c55fe62c 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -446,6 +446,8 @@ void mv88e6xxx_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data); int mv88e6xxx_get_sset_count(struct dsa_switch *ds); int mv88e6xxx_get_sset_count_basic(struct dsa_switch *ds); +void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, + struct phy_device *phydev); int mv88e6xxx_get_regs_len(struct dsa_switch *ds, int port); void mv88e6xxx_get_regs(struct dsa_switch *ds, int port, struct ethtool_regs *regs, void *_p); -- GitLab From 34b31da486a5e4eda9ff548ebf6dc3adc167bd0c Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:48 +0200 Subject: [PATCH 5951/7006] phy: fixed_phy: Set supported speed in phydev Set the supported field of the phydev to indicate the speed features of the phy. If the phy is never attached to a netdev, but used in an adjust_link() function, the speed will be incorrectly evaluated to 10/half rather than the correct speed/duplex. Signed-off-by: Andrew Lunn Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index ce46428ff21fa..2f9457f05a2e4 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -305,6 +305,18 @@ struct phy_device *fixed_phy_register(unsigned int irq, phy->dev.of_node = np; phy->is_pseudo_fixed_link = true; + switch (status->speed) { + case SPEED_1000: + phy->supported = PHY_1000BT_FEATURES; + break; + case SPEED_100: + phy->supported = PHY_100BT_FEATURES; + break; + case SPEED_10: + default: + phy->supported = PHY_10BT_FEATURES; + } + ret = phy_device_register(phy); if (ret) { phy_device_free(phy); -- GitLab From 39b0c705195e9409dc8a40cc82b11d81405a4a4b Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:49 +0200 Subject: [PATCH 5952/7006] net: dsa: Allow configuration of CPU & DSA port speeds/duplex By default, DSA and CPU ports are configured to the maximum speed the switch supports. However there can be use cases where the peer devices port is slower. Allow a fixed-link property to be used with the DSA and CPU port in the device tree, and use this information to configure the port. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index 053eb2b8e6828..afff17341b738 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -176,6 +176,35 @@ __ATTRIBUTE_GROUPS(dsa_hwmon); #endif /* CONFIG_NET_DSA_HWMON */ /* basic switch operations **************************************************/ +static int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct net_device *master) +{ + struct dsa_chip_data *cd = ds->pd; + struct device_node *port_dn; + struct phy_device *phydev; + int ret, port; + + for (port = 0; port < DSA_MAX_PORTS; port++) { + if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) + continue; + + port_dn = cd->port_dn[port]; + if (of_phy_is_fixed_link(port_dn)) { + ret = of_phy_register_fixed_link(port_dn); + if (ret) { + netdev_err(master, + "failed to register fixed PHY\n"); + return ret; + } + phydev = of_phy_find_device(port_dn); + genphy_config_init(phydev); + genphy_read_status(phydev); + if (ds->drv->adjust_link) + ds->drv->adjust_link(ds, port, phydev); + } + } + return 0; +} + static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) { struct dsa_switch_driver *drv = ds->drv; @@ -297,6 +326,14 @@ static int dsa_switch_setup_one(struct dsa_switch *ds, struct device *parent) } } + /* Perform configuration of the CPU and DSA ports */ + ret = dsa_cpu_dsa_setup(ds, dst->master_netdev); + if (ret < 0) { + netdev_err(dst->master_netdev, "[%d] : can't configure CPU and DSA ports\n", + index); + ret = 0; + } + #ifdef CONFIG_NET_DSA_HWMON /* If the switch provides a temperature sensor, * register with hardware monitoring subsystem. -- GitLab From e44853466844c20d8b5b16de187f63ddc50710dd Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:50 +0200 Subject: [PATCH 5953/7006] net: dsa: Allow DSA and CPU ports to have a phy-mode property It can be useful for DSA and CPU ports to have a phy-mode property, in particular to specify RGMII delays. Parse the property and set it in the fixed-link phydev. Signed-off-by: Andrew Lunn Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- net/dsa/dsa.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index afff17341b738..76e3800765f88 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c @@ -181,7 +181,7 @@ static int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct net_device *master) struct dsa_chip_data *cd = ds->pd; struct device_node *port_dn; struct phy_device *phydev; - int ret, port; + int ret, port, mode; for (port = 0; port < DSA_MAX_PORTS; port++) { if (!(dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))) @@ -196,6 +196,12 @@ static int dsa_cpu_dsa_setup(struct dsa_switch *ds, struct net_device *master) return ret; } phydev = of_phy_find_device(port_dn); + + mode = of_get_phy_mode(port_dn); + if (mode < 0) + mode = PHY_INTERFACE_MODE_NA; + phydev->interface = mode; + genphy_config_init(phydev); genphy_read_status(phydev); if (ds->drv->adjust_link) -- GitLab From e7e72ac05acc357065a9448314dd14fff7c40d39 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:51 +0200 Subject: [PATCH 5954/7006] dsa: mv88e6xxx: Set the RGMII delay based on phy interface Some Marvell switches allow the RGMII Rx and Tx clock to be delayed when the port is using RGMII. Have the adjust_link function look at the phy interface type and enable this delay as requested. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 10 ++++++++++ drivers/net/dsa/mv88e6xxx.h | 2 ++ 2 files changed, 12 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 1a8c45f3e6805..90dee97ae7938 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -612,6 +612,16 @@ void mv88e6xxx_adjust_link(struct dsa_switch *ds, int port, if (phydev->duplex == DUPLEX_FULL) reg |= PORT_PCS_CTRL_DUPLEX_FULL; + if ((mv88e6xxx_6352_family(ds) || mv88e6xxx_6351_family(ds)) && + (port >= ps->num_ports - 2)) { + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) + reg |= PORT_PCS_CTRL_RGMII_DELAY_RXCLK; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) + reg |= PORT_PCS_CTRL_RGMII_DELAY_TXCLK; + if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) + reg |= (PORT_PCS_CTRL_RGMII_DELAY_RXCLK | + PORT_PCS_CTRL_RGMII_DELAY_TXCLK); + } _mv88e6xxx_reg_write(ds, REG_PORT(port), PORT_PCS_CTRL, reg); out: diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index 79003c55fe62c..9b6f3d9d5ae1c 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -46,6 +46,8 @@ #define PORT_STATUS_TX_PAUSED BIT(5) #define PORT_STATUS_FLOW_CTRL BIT(4) #define PORT_PCS_CTRL 0x01 +#define PORT_PCS_CTRL_RGMII_DELAY_RXCLK BIT(15) +#define PORT_PCS_CTRL_RGMII_DELAY_TXCLK BIT(14) #define PORT_PCS_CTRL_FC BIT(7) #define PORT_PCS_CTRL_FORCE_FC BIT(6) #define PORT_PCS_CTRL_LINK_UP BIT(5) -- GitLab From 8b59d19e749b8cb454b7912396c2a6a1b91b9d30 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:52 +0200 Subject: [PATCH 5955/7006] dsa: mv88e6xxx: Don't poll forced interfaces for state changes When polling for link status, don't consider ports which have a forced link. Such ports don't monitor their phy or may not even have a phy. Signed-off-by: Andrew Lunn Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 90dee97ae7938..6f13f72067621 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -395,6 +395,7 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) for (i = 0; i < DSA_MAX_PORTS; i++) { struct net_device *dev; int uninitialized_var(port_status); + int pcs_ctrl; int link; int speed; int duplex; @@ -404,6 +405,10 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) if (dev == NULL) continue; + pcs_ctrl = mv88e6xxx_reg_read(ds, REG_PORT(i), PORT_PCS_CTRL); + if (pcs_ctrl < 0 || pcs_ctrl & PORT_PCS_CTRL_FORCE_LINK) + continue; + link = 0; if (dev->flags & IFF_UP) { port_status = mv88e6xxx_reg_read(ds, REG_PORT(i), -- GitLab From a5597008dbc230876db2d344561d634f4d52ea4a Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:53 +0200 Subject: [PATCH 5956/7006] phy: fixed_phy: Add gpio to determine link up/down. An SFP module may have a link up/down status pin which can be connection to a GPIO line of the host. Add support for reading such an GPIO in the fixed_phy driver. Signed-off-by: Andrew Lunn Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- .../devicetree/bindings/net/fixed-link.txt | 14 +++++++++- Documentation/networking/stmmac.txt | 2 +- arch/m68k/coldfire/m5272.c | 2 +- arch/mips/ar7/platform.c | 5 ++-- arch/mips/bcm47xx/setup.c | 2 +- drivers/net/ethernet/broadcom/genet/bcmmii.c | 2 +- drivers/net/phy/fixed_phy.c | 26 ++++++++++++++++--- drivers/of/of_mdio.c | 13 +++++++--- include/linux/phy_fixed.h | 8 ++++-- 9 files changed, 59 insertions(+), 15 deletions(-) diff --git a/Documentation/devicetree/bindings/net/fixed-link.txt b/Documentation/devicetree/bindings/net/fixed-link.txt index 82bf7e0f47b66..ec5d889fe3d83 100644 --- a/Documentation/devicetree/bindings/net/fixed-link.txt +++ b/Documentation/devicetree/bindings/net/fixed-link.txt @@ -17,6 +17,8 @@ properties: enabled. * 'asym-pause' (boolean, optional), to indicate that asym_pause should be enabled. +* 'link-gpios' ('gpio-list', optional), to indicate if a gpio can be read + to determine if the link is up. Old, deprecated 'fixed-link' binding: @@ -30,7 +32,7 @@ Old, deprecated 'fixed-link' binding: - e: asymmetric pause configuration: 0 for no asymmetric pause, 1 for asymmetric pause -Example: +Examples: ethernet@0 { ... @@ -40,3 +42,13 @@ ethernet@0 { }; ... }; + +ethernet@1 { + ... + fixed-link { + speed = <1000>; + pause; + link-gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>; + }; + ... +}; diff --git a/Documentation/networking/stmmac.txt b/Documentation/networking/stmmac.txt index 2903b1cf4d702..d64a147142364 100644 --- a/Documentation/networking/stmmac.txt +++ b/Documentation/networking/stmmac.txt @@ -254,7 +254,7 @@ static struct fixed_phy_status stmmac0_fixed_phy_status = { During the board's device_init we can configure the first MAC for fixed_link by calling: - fixed_phy_add(PHY_POLL, 1, &stmmac0_fixed_phy_status));) + fixed_phy_add(PHY_POLL, 1, &stmmac0_fixed_phy_status, -1); and the second one, with a real PHY device attached to the bus, by using the stmmac_mdio_bus_data structure (to provide the id, the reset procedure etc). diff --git a/arch/m68k/coldfire/m5272.c b/arch/m68k/coldfire/m5272.c index b15219ed22bf5..c525e4c08f847 100644 --- a/arch/m68k/coldfire/m5272.c +++ b/arch/m68k/coldfire/m5272.c @@ -126,7 +126,7 @@ static struct fixed_phy_status nettel_fixed_phy_status __initdata = { static int __init init_BSP(void) { m5272_uarts_init(); - fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status); + fixed_phy_add(PHY_POLL, 0, &nettel_fixed_phy_status, -1); return 0; } diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index be9ff1673ded7..298b97715d5fe 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -679,7 +679,8 @@ static int __init ar7_register_devices(void) } if (ar7_has_high_cpmac()) { - res = fixed_phy_add(PHY_POLL, cpmac_high.id, &fixed_phy_status); + res = fixed_phy_add(PHY_POLL, cpmac_high.id, + &fixed_phy_status, -1); if (!res) { cpmac_get_mac(1, cpmac_high_data.dev_addr); @@ -692,7 +693,7 @@ static int __init ar7_register_devices(void) } else cpmac_low_data.phy_mask = 0xffffffff; - res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status); + res = fixed_phy_add(PHY_POLL, cpmac_low.id, &fixed_phy_status, -1); if (!res) { cpmac_get_mac(0, cpmac_low_data.dev_addr); res = platform_device_register(&cpmac_low); diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 98c075f817956..17503a05938e6 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -263,7 +263,7 @@ static int __init bcm47xx_register_bus_complete(void) bcm47xx_leds_register(); bcm47xx_workarounds(); - fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status); + fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status, -1); return 0; } device_initcall(bcm47xx_register_bus_complete); diff --git a/drivers/net/ethernet/broadcom/genet/bcmmii.c b/drivers/net/ethernet/broadcom/genet/bcmmii.c index b3679ad1c1c73..c8affad76f368 100644 --- a/drivers/net/ethernet/broadcom/genet/bcmmii.c +++ b/drivers/net/ethernet/broadcom/genet/bcmmii.c @@ -585,7 +585,7 @@ static int bcmgenet_mii_pd_init(struct bcmgenet_priv *priv) .asym_pause = 0, }; - phydev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); + phydev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL); if (!phydev || IS_ERR(phydev)) { dev_err(kdev, "failed to register fixed PHY device\n"); return -ENODEV; diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 2f9457f05a2e4..1bb70e3cc03ea 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -22,6 +22,7 @@ #include #include #include +#include #define MII_REGS_NUM 29 @@ -38,6 +39,7 @@ struct fixed_phy { struct fixed_phy_status status; int (*link_update)(struct net_device *, struct fixed_phy_status *); struct list_head node; + int link_gpio; }; static struct platform_device *pdev; @@ -52,6 +54,9 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) u16 lpagb = 0; u16 lpa = 0; + if (gpio_is_valid(fp->link_gpio)) + fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio); + if (!fp->status.link) goto done; bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; @@ -215,7 +220,8 @@ int fixed_phy_update_state(struct phy_device *phydev, EXPORT_SYMBOL(fixed_phy_update_state); int fixed_phy_add(unsigned int irq, int phy_addr, - struct fixed_phy_status *status) + struct fixed_phy_status *status, + int link_gpio) { int ret; struct fixed_mdio_bus *fmb = &platform_fmb; @@ -231,15 +237,26 @@ int fixed_phy_add(unsigned int irq, int phy_addr, fp->addr = phy_addr; fp->status = *status; + fp->link_gpio = link_gpio; + + if (gpio_is_valid(fp->link_gpio)) { + ret = gpio_request_one(fp->link_gpio, GPIOF_DIR_IN, + "fixed-link-gpio-link"); + if (ret) + goto err_regs; + } ret = fixed_phy_update_regs(fp); if (ret) - goto err_regs; + goto err_gpio; list_add_tail(&fp->node, &fmb->phys); return 0; +err_gpio: + if (gpio_is_valid(fp->link_gpio)) + gpio_free(fp->link_gpio); err_regs: kfree(fp); return ret; @@ -254,6 +271,8 @@ void fixed_phy_del(int phy_addr) list_for_each_entry_safe(fp, tmp, &fmb->phys, node) { if (fp->addr == phy_addr) { list_del(&fp->node); + if (gpio_is_valid(fp->link_gpio)) + gpio_free(fp->link_gpio); kfree(fp); return; } @@ -266,6 +285,7 @@ static DEFINE_SPINLOCK(phy_fixed_addr_lock); struct phy_device *fixed_phy_register(unsigned int irq, struct fixed_phy_status *status, + int link_gpio, struct device_node *np) { struct fixed_mdio_bus *fmb = &platform_fmb; @@ -282,7 +302,7 @@ struct phy_device *fixed_phy_register(unsigned int irq, phy_addr = phy_fixed_addr++; spin_unlock(&phy_fixed_addr_lock); - ret = fixed_phy_add(PHY_POLL, phy_addr, status); + ret = fixed_phy_add(PHY_POLL, phy_addr, status, link_gpio); if (ret < 0) return ERR_PTR(ret); diff --git a/drivers/of/of_mdio.c b/drivers/of/of_mdio.c index 7c8c23cc6896c..1350fa25cdb06 100644 --- a/drivers/of/of_mdio.c +++ b/drivers/of/of_mdio.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -294,6 +295,7 @@ int of_phy_register_fixed_link(struct device_node *np) struct fixed_phy_status status = {}; struct device_node *fixed_link_node; const __be32 *fixed_link_prop; + int link_gpio; int len, err; struct phy_device *phy; const char *managed; @@ -302,7 +304,7 @@ int of_phy_register_fixed_link(struct device_node *np) if (err == 0) { if (strcmp(managed, "in-band-status") == 0) { /* status is zeroed, namely its .link member */ - phy = fixed_phy_register(PHY_POLL, &status, np); + phy = fixed_phy_register(PHY_POLL, &status, -1, np); return IS_ERR(phy) ? PTR_ERR(phy) : 0; } } @@ -318,8 +320,13 @@ int of_phy_register_fixed_link(struct device_node *np) status.pause = of_property_read_bool(fixed_link_node, "pause"); status.asym_pause = of_property_read_bool(fixed_link_node, "asym-pause"); + link_gpio = of_get_named_gpio_flags(fixed_link_node, + "link-gpios", 0, NULL); of_node_put(fixed_link_node); - phy = fixed_phy_register(PHY_POLL, &status, np); + if (link_gpio == -EPROBE_DEFER) + return -EPROBE_DEFER; + + phy = fixed_phy_register(PHY_POLL, &status, link_gpio, np); return IS_ERR(phy) ? PTR_ERR(phy) : 0; } @@ -331,7 +338,7 @@ int of_phy_register_fixed_link(struct device_node *np) status.speed = be32_to_cpu(fixed_link_prop[2]); status.pause = be32_to_cpu(fixed_link_prop[3]); status.asym_pause = be32_to_cpu(fixed_link_prop[4]); - phy = fixed_phy_register(PHY_POLL, &status, np); + phy = fixed_phy_register(PHY_POLL, &status, -1, np); return IS_ERR(phy) ? PTR_ERR(phy) : 0; } diff --git a/include/linux/phy_fixed.h b/include/linux/phy_fixed.h index fe5732d53edac..2400d2ea4f34a 100644 --- a/include/linux/phy_fixed.h +++ b/include/linux/phy_fixed.h @@ -13,9 +13,11 @@ struct device_node; #if IS_ENABLED(CONFIG_FIXED_PHY) extern int fixed_phy_add(unsigned int irq, int phy_id, - struct fixed_phy_status *status); + struct fixed_phy_status *status, + int link_gpio); extern struct phy_device *fixed_phy_register(unsigned int irq, struct fixed_phy_status *status, + int link_gpio, struct device_node *np); extern void fixed_phy_del(int phy_addr); extern int fixed_phy_set_link_update(struct phy_device *phydev, @@ -26,12 +28,14 @@ extern int fixed_phy_update_state(struct phy_device *phydev, const struct fixed_phy_status *changed); #else static inline int fixed_phy_add(unsigned int irq, int phy_id, - struct fixed_phy_status *status) + struct fixed_phy_status *status, + int link_gpio) { return -ENODEV; } static inline struct phy_device *fixed_phy_register(unsigned int irq, struct fixed_phy_status *status, + int gpio_link, struct device_node *np) { return ERR_PTR(-ENODEV); -- GitLab From bc0f4a87fc7e45642455682f281de2131cde9695 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Mon, 31 Aug 2015 15:56:54 +0200 Subject: [PATCH 5957/7006] net: phy: fixed_phy: Set phy capabilities even when link down. What features a phy supports is masked in genphy_config_init() by looking at the PHYs BMSR register. If the link is down, fixed_phy_update_regs() will only set the auto- negotiation capable bit in BMSR. Thus genphy_config_init() comes to the conclusion the PHY can only perform 10/Half, and masks out the higher speed features. If however the link it up, BMSR is set to indicate the speed the PHY is capable of auto-negotiating, and genphy_config_init() does not mask out the high speed features. To fix this, when the link is down, have fixed_phy_update_regs() leave the link status, auto-negotiation complete, and link partner capabilities unset, but set all the local capabilities depending on the fixed phy speed. Signed-off-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 73 ++++++++++++++++++++++++------------- 1 file changed, 48 insertions(+), 25 deletions(-) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 1bb70e3cc03ea..12c7eb2c604e1 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -57,61 +57,84 @@ static int fixed_phy_update_regs(struct fixed_phy *fp) if (gpio_is_valid(fp->link_gpio)) fp->status.link = !!gpio_get_value_cansleep(fp->link_gpio); - if (!fp->status.link) - goto done; - bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; - if (fp->status.duplex) { - bmcr |= BMCR_FULLDPLX; - switch (fp->status.speed) { case 1000: bmsr |= BMSR_ESTATEN; - bmcr |= BMCR_SPEED1000; - lpagb |= LPA_1000FULL; break; case 100: bmsr |= BMSR_100FULL; - bmcr |= BMCR_SPEED100; - lpa |= LPA_100FULL; break; case 10: bmsr |= BMSR_10FULL; - lpa |= LPA_10FULL; break; default: - pr_warn("fixed phy: unknown speed\n"); - return -EINVAL; + break; } } else { switch (fp->status.speed) { case 1000: bmsr |= BMSR_ESTATEN; - bmcr |= BMCR_SPEED1000; - lpagb |= LPA_1000HALF; break; case 100: bmsr |= BMSR_100HALF; - bmcr |= BMCR_SPEED100; - lpa |= LPA_100HALF; break; case 10: bmsr |= BMSR_10HALF; - lpa |= LPA_10HALF; break; default: - pr_warn("fixed phy: unknown speed\n"); - return -EINVAL; + break; } } - if (fp->status.pause) - lpa |= LPA_PAUSE_CAP; + if (fp->status.link) { + bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE; + + if (fp->status.duplex) { + bmcr |= BMCR_FULLDPLX; + + switch (fp->status.speed) { + case 1000: + bmcr |= BMCR_SPEED1000; + lpagb |= LPA_1000FULL; + break; + case 100: + bmcr |= BMCR_SPEED100; + lpa |= LPA_100FULL; + break; + case 10: + lpa |= LPA_10FULL; + break; + default: + pr_warn("fixed phy: unknown speed\n"); + return -EINVAL; + } + } else { + switch (fp->status.speed) { + case 1000: + bmcr |= BMCR_SPEED1000; + lpagb |= LPA_1000HALF; + break; + case 100: + bmcr |= BMCR_SPEED100; + lpa |= LPA_100HALF; + break; + case 10: + lpa |= LPA_10HALF; + break; + default: + pr_warn("fixed phy: unknown speed\n"); + return -EINVAL; + } + } + + if (fp->status.pause) + lpa |= LPA_PAUSE_CAP; - if (fp->status.asym_pause) - lpa |= LPA_PAUSE_ASYM; + if (fp->status.asym_pause) + lpa |= LPA_PAUSE_ASYM; + } -done: fp->regs[MII_PHYSID1] = 0; fp->regs[MII_PHYSID2] = 0; -- GitLab From a394eef562d781f37a50d99cf1dfe596dc1ed96d Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski Date: Mon, 31 Aug 2015 15:59:22 +0200 Subject: [PATCH 5958/7006] ipv6: send NEWLINK on RA managed/otherconf changes The kernel is applying the RA managed/otherconf flags silently and forgets to send ifinfo notify to inform about their change when the router provides a zero reachable_time and retrans_timer as dnsmasq and many routers send it, which just means unspecified by this router and the host should continue using whatever value it is already using. Userspace may monitor the ifinfo notifications to activate dhcpv6. Signed-off-by: Marius Tomaschewski Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 13d3c2beb93ea..12fff091e0439 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1078,6 +1078,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) struct ndisc_options ndopts; int optlen; unsigned int pref = 0; + __u32 old_if_flags; __u8 *opt = (__u8 *)(ra_msg + 1); @@ -1148,6 +1149,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) * Remember the managed/otherconf flags from most recently * received RA message (RFC 2462) -- yoshfuji */ + old_if_flags = in6_dev->if_flags; in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED | IF_RA_OTHERCONF)) | (ra_msg->icmph.icmp6_addrconf_managed ? @@ -1155,6 +1157,9 @@ static void ndisc_router_discovery(struct sk_buff *skb) (ra_msg->icmph.icmp6_addrconf_other ? IF_RA_OTHERCONF : 0); + if (old_if_flags != in6_dev->if_flags) + inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); + if (!in6_dev->cnf.accept_ra_defrtr) { ND_PRINTK(2, info, "RA: %s, defrtr is false for dev: %s\n", -- GitLab From e704059272aae2aaa5e5ce7a76e4c27c492e947e Mon Sep 17 00:00:00 2001 From: David Ward Date: Mon, 31 Aug 2015 14:15:14 -0400 Subject: [PATCH 5959/7006] net: qmi_wwan: Sierra Wireless MC73xx -> Sierra Wireless MC7304/MC7354 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Other Sierra Wireless MC73xx devices exist, with different USB IDs. Cc: Bjørn Mork Signed-off-by: David Ward Signed-off-by: David S. Miller --- drivers/net/usb/qmi_wwan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 6392ae3c4ab82..355842b85ee90 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -752,8 +752,8 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x114f, 0x68a2, 8)}, /* Sierra Wireless MC7750 */ {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ - {QMI_FIXED_INTF(0x1199, 0x68c0, 8)}, /* Sierra Wireless MC73xx */ - {QMI_FIXED_INTF(0x1199, 0x68c0, 10)}, /* Sierra Wireless MC73xx */ + {QMI_FIXED_INTF(0x1199, 0x68c0, 8)}, /* Sierra Wireless MC7304/MC7354 */ + {QMI_FIXED_INTF(0x1199, 0x68c0, 10)}, /* Sierra Wireless MC7304/MC7354 */ {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ {QMI_FIXED_INTF(0x1199, 0x901f, 8)}, /* Sierra Wireless EM7355 */ {QMI_FIXED_INTF(0x1199, 0x9041, 8)}, /* Sierra Wireless MC7305/MC7355 */ -- GitLab From c42858eaf4926eb2f44f3e26731b276ab966ac28 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Mon, 31 Aug 2015 13:57:34 -0700 Subject: [PATCH 5960/7006] gro_cells: remove spinlock protecting receive queues As David pointed out, spinlock are no longer needed to protect the per cpu queues used in gro cells infrastructure. Also use new napi_complete_done() API so that gro_flush_timeout tweaks have an effect. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller --- include/net/gro_cells.h | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/include/net/gro_cells.h b/include/net/gro_cells.h index 0f712c0bc0bf2..cf6c74550baa5 100644 --- a/include/net/gro_cells.h +++ b/include/net/gro_cells.h @@ -32,37 +32,28 @@ static inline void gro_cells_receive(struct gro_cells *gcells, struct sk_buff *s return; } - /* We run in BH context */ - spin_lock(&cell->napi_skbs.lock); - __skb_queue_tail(&cell->napi_skbs, skb); if (skb_queue_len(&cell->napi_skbs) == 1) napi_schedule(&cell->napi); - - spin_unlock(&cell->napi_skbs.lock); } -/* called unser BH context */ +/* called under BH context */ static inline int gro_cell_poll(struct napi_struct *napi, int budget) { struct gro_cell *cell = container_of(napi, struct gro_cell, napi); struct sk_buff *skb; int work_done = 0; - spin_lock(&cell->napi_skbs.lock); while (work_done < budget) { skb = __skb_dequeue(&cell->napi_skbs); if (!skb) break; - spin_unlock(&cell->napi_skbs.lock); napi_gro_receive(napi, skb); work_done++; - spin_lock(&cell->napi_skbs.lock); } if (work_done < budget) - napi_complete(napi); - spin_unlock(&cell->napi_skbs.lock); + napi_complete_done(napi, work_done); return work_done; } @@ -77,7 +68,7 @@ static inline int gro_cells_init(struct gro_cells *gcells, struct net_device *de for_each_possible_cpu(i) { struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); - skb_queue_head_init(&cell->napi_skbs); + __skb_queue_head_init(&cell->napi_skbs); netif_napi_add(dev, &cell->napi, gro_cell_poll, 64); napi_enable(&cell->napi); } @@ -92,8 +83,9 @@ static inline void gro_cells_destroy(struct gro_cells *gcells) return; for_each_possible_cpu(i) { struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); + netif_napi_del(&cell->napi); - skb_queue_purge(&cell->napi_skbs); + __skb_queue_purge(&cell->napi_skbs); } free_percpu(gcells->cells); gcells->cells = NULL; -- GitLab From 07f081fb5057b2ea98baeca3a47bf0eb33e94aa1 Mon Sep 17 00:00:00 2001 From: David Howells Date: Sun, 30 Aug 2015 16:59:57 +0100 Subject: [PATCH 5961/7006] PKCS#7: Add OIDs for sha224, sha284 and sha512 hash algos and use them Add OIDs for sha224, sha284 and sha512 hash algos and use them to select the hashing algorithm. Without this, something like the following error might get written to dmesg: [ 31.829322] PKCS7: Unknown OID: [32] 2.16.840.1.101.3.4.2.3 [ 31.829328] PKCS7: Unknown OID: [180] 2.16.840.1.101.3.4.2.3 [ 31.829330] Unsupported digest algo: 55 Where the 55 on the third line is OID__NR indicating an unknown OID. Reported-by: Valdis Kletnieks Signed-off-by: David Howells Tested-By: Valdis Kletnieks Signed-off-by: James Morris --- crypto/asymmetric_keys/mscode_parser.c | 9 +++++++++ crypto/asymmetric_keys/pkcs7_parser.c | 8 ++++++++ include/linux/oid_registry.h | 3 +++ 3 files changed, 20 insertions(+) diff --git a/crypto/asymmetric_keys/mscode_parser.c b/crypto/asymmetric_keys/mscode_parser.c index 214a992123cdd..adcef59eec0b6 100644 --- a/crypto/asymmetric_keys/mscode_parser.c +++ b/crypto/asymmetric_keys/mscode_parser.c @@ -97,6 +97,15 @@ int mscode_note_digest_algo(void *context, size_t hdrlen, case OID_sha256: ctx->digest_algo = HASH_ALGO_SHA256; break; + case OID_sha384: + ctx->digest_algo = HASH_ALGO_SHA384; + break; + case OID_sha512: + ctx->digest_algo = HASH_ALGO_SHA512; + break; + case OID_sha224: + ctx->digest_algo = HASH_ALGO_SHA224; + break; case OID__NR: sprint_oid(value, vlen, buffer, sizeof(buffer)); diff --git a/crypto/asymmetric_keys/pkcs7_parser.c b/crypto/asymmetric_keys/pkcs7_parser.c index e6298b7a945a9..758acabf2d819 100644 --- a/crypto/asymmetric_keys/pkcs7_parser.c +++ b/crypto/asymmetric_keys/pkcs7_parser.c @@ -229,6 +229,14 @@ int pkcs7_sig_note_digest_algo(void *context, size_t hdrlen, case OID_sha256: ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA256; break; + case OID_sha384: + ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA384; + break; + case OID_sha512: + ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA512; + break; + case OID_sha224: + ctx->sinfo->sig.pkey_hash_algo = HASH_ALGO_SHA224; default: printk("Unsupported digest algo: %u\n", ctx->last_oid); return -ENOPKG; diff --git a/include/linux/oid_registry.h b/include/linux/oid_registry.h index 93e0ff92fb9b6..d2fa9ca42e9a7 100644 --- a/include/linux/oid_registry.h +++ b/include/linux/oid_registry.h @@ -63,6 +63,9 @@ enum OID { OID_certAuthInfoAccess, /* 1.3.6.1.5.5.7.1.1 */ OID_sha1, /* 1.3.14.3.2.26 */ OID_sha256, /* 2.16.840.1.101.3.4.2.1 */ + OID_sha384, /* 2.16.840.1.101.3.4.2.2 */ + OID_sha512, /* 2.16.840.1.101.3.4.2.3 */ + OID_sha224, /* 2.16.840.1.101.3.4.2.4 */ /* Distinguished Name attribute IDs [RFC 2256] */ OID_commonName, /* 2.5.4.3 */ -- GitLab From 2053aeb69a53224717296db31b13d5b45b4f1a0e Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski Date: Tue, 1 Sep 2015 01:57:30 +0200 Subject: [PATCH 5962/7006] ipv6: send only one NEWLINK when RA causes changes Signed-off-by: Marius Tomaschewski Signed-off-by: David S. Miller --- net/ipv6/ndisc.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 12fff091e0439..64a71354b069d 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -1079,6 +1079,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) int optlen; unsigned int pref = 0; __u32 old_if_flags; + bool send_ifinfo_notify = false; __u8 *opt = (__u8 *)(ra_msg + 1); @@ -1158,7 +1159,7 @@ static void ndisc_router_discovery(struct sk_buff *skb) IF_RA_OTHERCONF : 0); if (old_if_flags != in6_dev->if_flags) - inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); + send_ifinfo_notify = true; if (!in6_dev->cnf.accept_ra_defrtr) { ND_PRINTK(2, info, @@ -1261,7 +1262,7 @@ skip_defrtr: rtime = HZ/10; NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime); in6_dev->tstamp = jiffies; - inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); + send_ifinfo_notify = true; } rtime = ntohl(ra_msg->reachable_time); @@ -1278,11 +1279,17 @@ skip_defrtr: GC_STALETIME, 3 * rtime); in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); in6_dev->tstamp = jiffies; - inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); + send_ifinfo_notify = true; } } } + /* + * Send a notify if RA changed managed/otherconf flags or timer settings + */ + if (send_ifinfo_notify) + inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); + skip_linkparms: /* -- GitLab From 63b6c13dbb7d3e36f031629f7e4e86dacfcab8cf Mon Sep 17 00:00:00 2001 From: Pravin B Shelar Date: Mon, 31 Aug 2015 20:05:57 -0700 Subject: [PATCH 5963/7006] tun_dst: Remove opts_size opts_size is only written and never read. Following patch removes this unused variable. Signed-off-by: Pravin B Shelar Signed-off-by: David S. Miller --- include/net/dst_metadata.h | 1 - net/core/dst.c | 1 - 2 files changed, 2 deletions(-) diff --git a/include/net/dst_metadata.h b/include/net/dst_metadata.h index 547ab82415935..af9d5382f6cba 100644 --- a/include/net/dst_metadata.h +++ b/include/net/dst_metadata.h @@ -7,7 +7,6 @@ struct metadata_dst { struct dst_entry dst; - size_t opts_len; union { struct ip_tunnel_info tun_info; } u; diff --git a/net/core/dst.c b/net/core/dst.c index 477035ed7903f..0771c8cb9307c 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -378,7 +378,6 @@ static void __metadata_dst_init(struct metadata_dst *md_dst, u8 optslen) dst->output = dst_md_discard_sk; memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst)); - md_dst->opts_len = optslen; } struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags) -- GitLab From 69f92f67b68ab7028ffe15f0eea76b59f8859383 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Wed, 15 Jul 2015 13:57:35 +0200 Subject: [PATCH 5964/7006] drm/i915: Preserve SSC earlier Commit 92122789b2d6 ("drm/i915: preserve SSC if previously set v3") added code to intel_modeset_gem_init to override the SSC status read from VBT with the SSC status set by BIOS. However, intel_modeset_gem_init is invoked *after* intel_modeset_init, which calls intel_setup_outputs, which *modifies* SSC status by way of intel_init_pch_refclk. So unlike advertised, intel_modeset_gem_init doesn't preserve the SSC status set by BIOS but whatever intel_init_pch_refclk decided on. This is a problem on dual gpu laptops such as the MacBook Pro which require either a handler to switch DDC lines, or the discrete gpu to proxy DDC/AUX communication: Both the handler and the discrete gpu may initialize after the i915 driver, and consequently, an LVDS connector may initially seem disconnected and the SSC therefore is disabled by intel_init_pch_refclk, but on reprobe the connector may turn out to be connected and the SSC must then be enabled. Due to 92122789b2d6 however, the SSC is not enabled on reprobe since it is assumed BIOS disabled it while in fact it was disabled by intel_init_pch_refclk. Also, because the SSC status is preserved so late, the preserved value only ever gets used on resume but not on panel initialization: intel_modeset_init calls intel_init_display which indirectly calls intel_panel_use_ssc via multiple subroutines, *before* the BIOS value overrides the VBT value in intel_modeset_gem_init (intel_panel_use_ssc is the sole user of dev_priv->vbt.lvds_use_ssc). Fix this by moving the code introduced by 92122789b2d6 from intel_modeset_gem_init to intel_modeset_init before the invocation of intel_setup_outputs and intel_init_display. Add a DRM_DEBUG_KMS as suggested way back by Jani: http://lists.freedesktop.org/archives/intel-gfx/2014-June/046666.html Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115 Tested-by: Paul Hordiienko [MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina] Tested-by: William Brown [MBP 8,2 2011 intel SNB + amd turks pre-retina] Tested-by: Lukas Wunner [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina] Tested-by: Bruno Bierbaumer [MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress] Fixes: 92122789b2d6 ("drm/i915: preserve SSC if previously set v3") Signed-off-by: Lukas Wunner Reviewed-by: Jesse Barnes Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 29 +++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index a5cddcd6d3e07..ca9278be49f7d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -14740,6 +14740,24 @@ void intel_modeset_init(struct drm_device *dev) if (INTEL_INFO(dev)->num_pipes == 0) return; + /* + * There may be no VBT; and if the BIOS enabled SSC we can + * just keep using it to avoid unnecessary flicker. Whereas if the + * BIOS isn't using it, don't assume it will work even if the VBT + * indicates as much. + */ + if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) { + bool bios_lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) & + DREF_SSC1_ENABLE); + + if (dev_priv->vbt.lvds_use_ssc != bios_lvds_use_ssc) { + DRM_DEBUG_KMS("SSC %sabled by BIOS, overriding VBT which says %sabled\n", + bios_lvds_use_ssc ? "en" : "dis", + dev_priv->vbt.lvds_use_ssc ? "en" : "dis"); + dev_priv->vbt.lvds_use_ssc = bios_lvds_use_ssc; + } + } + intel_init_display(dev); intel_init_audio(dev); @@ -15299,7 +15317,6 @@ err: void intel_modeset_gem_init(struct drm_device *dev) { - struct drm_i915_private *dev_priv = dev->dev_private; struct drm_crtc *c; struct drm_i915_gem_object *obj; int ret; @@ -15308,16 +15325,6 @@ void intel_modeset_gem_init(struct drm_device *dev) intel_init_gt_powersave(dev); mutex_unlock(&dev->struct_mutex); - /* - * There may be no VBT; and if the BIOS enabled SSC we can - * just keep using it to avoid unnecessary flicker. Whereas if the - * BIOS isn't using it, don't assume it will work even if the VBT - * indicates as much. - */ - if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)) - dev_priv->vbt.lvds_use_ssc = !!(I915_READ(PCH_DREF_CONTROL) & - DREF_SSC1_ENABLE); - intel_modeset_init_hw(dev); intel_setup_overlay(dev); -- GitLab From 5bcd0b7f3c56c616abffd89e11c841834dd1528c Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Sep 2015 07:56:38 +0800 Subject: [PATCH 5965/7006] reset: Add (devm_)reset_control_get stub functions So the drivers can be compiled with CONFIG_RESET_CONTROLLER disabled. Signed-off-by: Axel Lin Signed-off-by: Philipp Zabel --- include/linux/reset.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/include/linux/reset.h b/include/linux/reset.h index da5602bd77d75..7f65f9cff9510 100644 --- a/include/linux/reset.h +++ b/include/linux/reset.h @@ -74,6 +74,20 @@ static inline int device_reset_optional(struct device *dev) return -ENOSYS; } +static inline struct reset_control *__must_check reset_control_get( + struct device *dev, const char *id) +{ + WARN_ON(1); + return ERR_PTR(-EINVAL); +} + +static inline struct reset_control *__must_check devm_reset_control_get( + struct device *dev, const char *id) +{ + WARN_ON(1); + return ERR_PTR(-EINVAL); +} + static inline struct reset_control *reset_control_get_optional( struct device *dev, const char *id) { -- GitLab From c4749c9a4a9ddc16200ce46a19078357727bf4b1 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Mon, 31 Aug 2015 12:25:04 +0200 Subject: [PATCH 5966/7006] drm/atomic: Fix bookkeeping with TEST_ONLY, v3. Commit ec9f932ed41622d120de52a5b525e4d77b9ef17e "drm/atomic: Cleanup on error properly in the atomic ioctl." cleaned up some error paths, but didn't fix the TEST_ONLY path. In the check only case plane->fb shouldn't be updated, and the vblank events should be cleared as on failure. Changes since v1: - Fix -EDEADLK handling of vblank events too. - Free state last with CHECK_ONLY. Changes since v2: - Add comment about freeing crtc_state->event with TEST_ONLY. (Daniel Stone) Signed-off-by: Maarten Lankhorst Reviewed-by: Daniel Stone Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_atomic.c | 39 +++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c index 434915448ea0b..f7d5166f89b24 100644 --- a/drivers/gpu/drm/drm_atomic.c +++ b/drivers/gpu/drm/drm_atomic.c @@ -1515,7 +1515,8 @@ retry: copied_props++; } - if (obj->type == DRM_MODE_OBJECT_PLANE && count_props) { + if (obj->type == DRM_MODE_OBJECT_PLANE && count_props && + !(arg->flags & DRM_MODE_ATOMIC_TEST_ONLY)) { plane = obj_to_plane(obj); plane_mask |= (1 << drm_plane_index(plane)); plane->old_fb = plane->fb; @@ -1537,10 +1538,11 @@ retry: } if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) { + /* + * Unlike commit, check_only does not clean up state. + * Below we call drm_atomic_state_free for it. + */ ret = drm_atomic_check_only(state); - /* _check_only() does not free state, unlike _commit() */ - if (!ret) - drm_atomic_state_free(state); } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) { ret = drm_atomic_async_commit(state); } else { @@ -1567,25 +1569,30 @@ out: plane->old_fb = NULL; } + if (ret && arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { + /* + * TEST_ONLY and PAGE_FLIP_EVENT are mutually exclusive, + * if they weren't, this code should be called on success + * for TEST_ONLY too. + */ + + for_each_crtc_in_state(state, crtc, crtc_state, i) { + if (!crtc_state->event) + continue; + + destroy_vblank_event(dev, file_priv, + crtc_state->event); + } + } + if (ret == -EDEADLK) { drm_atomic_state_clear(state); drm_modeset_backoff(&ctx); goto retry; } - if (ret) { - if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) { - for_each_crtc_in_state(state, crtc, crtc_state, i) { - if (!crtc_state->event) - continue; - - destroy_vblank_event(dev, file_priv, - crtc_state->event); - } - } - + if (ret || arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) drm_atomic_state_free(state); - } drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); -- GitLab From aa3469ce7afd86a670d22375a64f1b5a06707725 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Thu, 27 Aug 2015 10:06:24 -0700 Subject: [PATCH 5967/7006] drm/vmwgfx: Allow dropped masters render-node like access on legacy nodes v2 Applications like gnome-shell may try to render after dropping master privileges. Since the driver should now be safe against this scenario, allow those applications to use their legacy node like a render node. v2: Add missing return statement. Signed-off-by: Thomas Hellstrom Reviewed-by: Sinclair Yeh --- drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 7 ++++++- drivers/gpu/drm/vmwgfx/vmwgfx_surface.c | 6 ++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 03854d606d589..e13b20bd9908d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c @@ -1052,10 +1052,15 @@ static struct vmw_master *vmw_master_check(struct drm_device *dev, } /* - * Check if we were previously master, but now dropped. + * Check if we were previously master, but now dropped. In that + * case, allow at least render node functionality. */ if (vmw_fp->locked_master) { mutex_unlock(&dev->master_mutex); + + if (flags & DRM_RENDER_ALLOW) + return NULL; + DRM_ERROR("Dropped master trying to access ioctl that " "requires authentication.\n"); return ERR_PTR(-EACCES); diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c index 5b8595b784296..3361769842f4d 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_surface.c @@ -911,6 +911,12 @@ vmw_surface_handle_reference(struct vmw_private *dev_priv, "surface reference.\n"); return -EACCES; } + if (ACCESS_ONCE(vmw_fpriv(file_priv)->locked_master)) { + DRM_ERROR("Locked master refused legacy " + "surface reference.\n"); + return -EACCES; + } + handle = u_handle; } -- GitLab From 7e6313a2516dbcd168f4ae36f0abe1a9227106b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 11 Aug 2015 20:21:46 +0300 Subject: [PATCH 5968/7006] drm/i915: Don't use link_bw for PLL setup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use port_clock instead of link_bw when picking the PLL parameters for DP. link_bw may be zero with an eDP 1.4 sink that supports DP_LINK_RATE_SET so we shouldn't use it for anything other than feed it to the sink appropriately. v2: Fix typo in commit message (Sivakumar) Reviewed-by: Sivakumar Thulasimani Signed-off-by: Ville Syrjälä Signed-off-by: Daniel Vetter [Jani: cherry-picked from future.] Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_ddi.c | 11 +++----- drivers/gpu/drm/i915/intel_dp.c | 44 ++++++++++++++++---------------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c index 19004557c868a..61575f67a6263 100644 --- a/drivers/gpu/drm/i915/intel_ddi.c +++ b/drivers/gpu/drm/i915/intel_ddi.c @@ -1554,17 +1554,14 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc, DPLL_CFGCR2_PDIV(wrpll_params.pdiv) | wrpll_params.central_freq; } else if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) { - struct drm_encoder *encoder = &intel_encoder->base; - struct intel_dp *intel_dp = enc_to_intel_dp(encoder); - - switch (intel_dp->link_bw) { - case DP_LINK_BW_1_62: + switch (crtc_state->port_clock / 2) { + case 81000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, 0); break; - case DP_LINK_BW_2_7: + case 135000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_1350, 0); break; - case DP_LINK_BW_5_4: + case 270000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_2700, 0); break; } diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 32663b1933f19..ef345d56f5cd9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -48,28 +48,28 @@ #define INTEL_DP_RESOLUTION_FAILSAFE (3 << INTEL_DP_RESOLUTION_SHIFT_MASK) struct dp_link_dpll { - int link_bw; + int clock; struct dpll dpll; }; static const struct dp_link_dpll gen4_dpll[] = { - { DP_LINK_BW_1_62, + { 162000, { .p1 = 2, .p2 = 10, .n = 2, .m1 = 23, .m2 = 8 } }, - { DP_LINK_BW_2_7, + { 270000, { .p1 = 1, .p2 = 10, .n = 1, .m1 = 14, .m2 = 2 } } }; static const struct dp_link_dpll pch_dpll[] = { - { DP_LINK_BW_1_62, + { 162000, { .p1 = 2, .p2 = 10, .n = 1, .m1 = 12, .m2 = 9 } }, - { DP_LINK_BW_2_7, + { 270000, { .p1 = 1, .p2 = 10, .n = 2, .m1 = 14, .m2 = 8 } } }; static const struct dp_link_dpll vlv_dpll[] = { - { DP_LINK_BW_1_62, + { 162000, { .p1 = 3, .p2 = 2, .n = 5, .m1 = 3, .m2 = 81 } }, - { DP_LINK_BW_2_7, + { 270000, { .p1 = 2, .p2 = 2, .n = 1, .m1 = 2, .m2 = 27 } } }; @@ -83,11 +83,11 @@ static const struct dp_link_dpll chv_dpll[] = { * m2 is stored in fixed point format using formula below * (m2_int << 22) | m2_fraction */ - { DP_LINK_BW_1_62, /* m2_int = 32, m2_fraction = 1677722 */ + { 162000, /* m2_int = 32, m2_fraction = 1677722 */ { .p1 = 4, .p2 = 2, .n = 1, .m1 = 2, .m2 = 0x819999a } }, - { DP_LINK_BW_2_7, /* m2_int = 27, m2_fraction = 0 */ + { 270000, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 4, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } }, - { DP_LINK_BW_5_4, /* m2_int = 27, m2_fraction = 0 */ + { 540000, /* m2_int = 27, m2_fraction = 0 */ { .p1 = 2, .p2 = 1, .n = 1, .m1 = 2, .m2 = 0x6c00000 } } }; @@ -1130,7 +1130,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector) } static void -skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) +skl_edp_set_pll_config(struct intel_crtc_state *pipe_config) { u32 ctrl1; @@ -1142,7 +1142,7 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) pipe_config->dpll_hw_state.cfgcr2 = 0; ctrl1 = DPLL_CTRL1_OVERRIDE(SKL_DPLL0); - switch (link_clock / 2) { + switch (pipe_config->port_clock / 2) { case 81000: ctrl1 |= DPLL_CTRL1_LINK_RATE(DPLL_CTRL1_LINK_RATE_810, SKL_DPLL0); @@ -1176,19 +1176,19 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_clock) } static void -hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw) +hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config) { memset(&pipe_config->dpll_hw_state, 0, sizeof(pipe_config->dpll_hw_state)); - switch (link_bw) { - case DP_LINK_BW_1_62: + switch (pipe_config->port_clock / 2) { + case 81000: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_810; break; - case DP_LINK_BW_2_7: + case 135000: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_1350; break; - case DP_LINK_BW_5_4: + case 270000: pipe_config->ddi_pll_sel = PORT_CLK_SEL_LCPLL_2700; break; } @@ -1245,7 +1245,7 @@ intel_dp_source_rates(struct drm_device *dev, const int **source_rates) static void intel_dp_set_clock(struct intel_encoder *encoder, - struct intel_crtc_state *pipe_config, int link_bw) + struct intel_crtc_state *pipe_config) { struct drm_device *dev = encoder->base.dev; const struct dp_link_dpll *divisor = NULL; @@ -1267,7 +1267,7 @@ intel_dp_set_clock(struct intel_encoder *encoder, if (divisor && count) { for (i = 0; i < count; i++) { - if (link_bw == divisor[i].link_bw) { + if (pipe_config->port_clock == divisor[i].clock) { pipe_config->dpll = divisor[i].dpll; pipe_config->clock_set = true; break; @@ -1544,13 +1544,13 @@ found: } if (IS_SKYLAKE(dev) && is_edp(intel_dp)) - skl_edp_set_pll_config(pipe_config, common_rates[clock]); + skl_edp_set_pll_config(pipe_config); else if (IS_BROXTON(dev)) /* handled in ddi */; else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - hsw_dp_set_ddi_pll_sel(pipe_config, intel_dp->link_bw); + hsw_dp_set_ddi_pll_sel(pipe_config); else - intel_dp_set_clock(encoder, pipe_config, intel_dp->link_bw); + intel_dp_set_clock(encoder, pipe_config); return true; } -- GitLab From 6fa2d197936ba0b8936e813d0adecefac160062b Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Mon, 31 Aug 2015 11:23:28 +0300 Subject: [PATCH 5969/7006] i915: Set ddi_pll_sel in DP MST path MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The DP MST encoder config function never sets ddi_pll_sel, even though its value is programmed in its ->pre_enable() hook. That used to work because a new pipe_config was kzalloc'ed at every modeset, and the value of zero selects the highest clock for the PLL. Starting with the commit below, the value of ddi_pll_sel is preserved through modesets, and since the correct value wasn't properly setup by the MST code, it could lead to warnings and blank screens. commit 8504c74c7ae48b4b8ed1f1c0acf67482a7f45c93 Author: Ander Conselvan de Oliveira Date: Fri May 15 11:51:50 2015 +0300 drm/i915: Preserve ddi_pll_sel when allocating new pipe_config Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91628 Cc: stable@vger.kernel.org # 7e6313a2516d drm/i915: Don't use link_bw for PLL setup Cc: stable@vger.kernel.org Cc: Timo Aaltonen Cc: Luciano Coelho Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_dp_mst.c | 5 +++++ drivers/gpu/drm/i915/intel_drv.h | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index ef345d56f5cd9..0a2e33fbf20dd 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -1175,7 +1175,7 @@ skl_edp_set_pll_config(struct intel_crtc_state *pipe_config) pipe_config->dpll_hw_state.ctrl1 = ctrl1; } -static void +void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config) { memset(&pipe_config->dpll_hw_state, 0, diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 369f8b6b804fe..983553cf8b74e 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -33,6 +33,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { + struct drm_device *dev = encoder->base.dev; struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; @@ -97,6 +98,10 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, &pipe_config->dp_m_n); pipe_config->dp_m_n.tu = slots; + + if (IS_HASWELL(dev) || IS_BROADWELL(dev)) + hsw_dp_set_ddi_pll_sel(pipe_config); + return true; } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 93008fbb815d9..2b9e6f9775c53 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1185,6 +1185,7 @@ void intel_edp_drrs_disable(struct intel_dp *intel_dp); void intel_edp_drrs_invalidate(struct drm_device *dev, unsigned frontbuffer_bits); void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits); +void hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config); /* intel_dp_mst.c */ int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id); -- GitLab From 9cf94eab8b309e8bcc78b41dd1561c75b537dd0b Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Mon, 31 Aug 2015 19:11:02 +0200 Subject: [PATCH 5970/7006] netfilter: conntrack: use nf_ct_tmpl_free in CT/synproxy error paths Commit 0838aa7fcfcd ("netfilter: fix netns dependencies with conntrack templates") migrated templates to the new allocator api, but forgot to update error paths for them in CT and synproxy to use nf_ct_tmpl_free() instead of nf_conntrack_free(). Due to that, memory is being freed into the wrong kmemcache, but also we drop the per net reference count of ct objects causing an imbalance. In Brad's case, this leads to a wrap-around of net->ct.count and thus lets __nf_conntrack_alloc() refuse to create a new ct object: [ 10.340913] xt_addrtype: ipv6 does not support BROADCAST matching [ 10.810168] nf_conntrack: table full, dropping packet [ 11.917416] r8169 0000:07:00.0 eth0: link up [ 11.917438] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready [ 12.815902] nf_conntrack: table full, dropping packet [ 15.688561] nf_conntrack: table full, dropping packet [ 15.689365] nf_conntrack: table full, dropping packet [ 15.690169] nf_conntrack: table full, dropping packet [ 15.690967] nf_conntrack: table full, dropping packet [...] With slab debugging, it also reports the wrong kmemcache (kmalloc-512 vs. nf_conntrack_ffffffff81ce75c0) and reports poison overwrites, etc. Thus, to fix the problem, export and use nf_ct_tmpl_free() instead. Fixes: 0838aa7fcfcd ("netfilter: fix netns dependencies with conntrack templates") Reported-by: Brad Jackson Signed-off-by: Daniel Borkmann Signed-off-by: Pablo Neira Ayuso --- include/net/netfilter/nf_conntrack.h | 1 + net/netfilter/nf_conntrack_core.c | 3 ++- net/netfilter/nf_synproxy_core.c | 2 +- net/netfilter/xt_CT.c | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index 37cd3911d5c59..4023c4ce260f0 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -292,6 +292,7 @@ extern unsigned int nf_conntrack_hash_rnd; void init_nf_conntrack_hash_rnd(void); struct nf_conn *nf_ct_tmpl_alloc(struct net *net, u16 zone, gfp_t flags); +void nf_ct_tmpl_free(struct nf_conn *tmpl); #define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count) #define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count) diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 3c20d02aee738..0625a42df1088 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -320,12 +320,13 @@ out_free: } EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc); -static void nf_ct_tmpl_free(struct nf_conn *tmpl) +void nf_ct_tmpl_free(struct nf_conn *tmpl) { nf_ct_ext_destroy(tmpl); nf_ct_ext_free(tmpl); kfree(tmpl); } +EXPORT_SYMBOL_GPL(nf_ct_tmpl_free); static void destroy_conntrack(struct nf_conntrack *nfct) diff --git a/net/netfilter/nf_synproxy_core.c b/net/netfilter/nf_synproxy_core.c index d7f1685279034..d6ee8f8b19b63 100644 --- a/net/netfilter/nf_synproxy_core.c +++ b/net/netfilter/nf_synproxy_core.c @@ -378,7 +378,7 @@ static int __net_init synproxy_net_init(struct net *net) err3: free_percpu(snet->stats); err2: - nf_conntrack_free(ct); + nf_ct_tmpl_free(ct); err1: return err; } diff --git a/net/netfilter/xt_CT.c b/net/netfilter/xt_CT.c index 43ddeee404e91..f3377ce1ff18e 100644 --- a/net/netfilter/xt_CT.c +++ b/net/netfilter/xt_CT.c @@ -233,7 +233,7 @@ out: return 0; err3: - nf_conntrack_free(ct); + nf_ct_tmpl_free(ct); err2: nf_ct_l3proto_module_put(par->family); err1: -- GitLab From b4df20474ff76b4dbab7d991de271820383995b8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 24 Aug 2015 22:54:21 +0300 Subject: [PATCH 5971/7006] fbdev: fix snprintf() limit in show_bl_curve() The limit should be "PAGE_SIZE - len" instead of PAGE_SIZE. Also let's use scnprintf() because snprintf() returns the number of bytes which would have been printed if there were space and scnprintf() returns the number of bytes actually printed. I don't think we are ever going to actually hit this limit in real life. Signed-off-by: Dan Carpenter Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/core/fbsysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c index 60c3f0a163411..15755ce1d26c8 100644 --- a/drivers/video/fbdev/core/fbsysfs.c +++ b/drivers/video/fbdev/core/fbsysfs.c @@ -485,7 +485,7 @@ static ssize_t show_bl_curve(struct device *device, mutex_lock(&fb_info->bl_curve_mutex); for (i = 0; i < FB_BACKLIGHT_LEVELS; i += 8) - len += snprintf(&buf[len], PAGE_SIZE, "%8ph\n", + len += scnprintf(&buf[len], PAGE_SIZE - len, "%8ph\n", fb_info->bl_curve + i); mutex_unlock(&fb_info->bl_curve_mutex); -- GitLab From c4e6774de19f4638bb887a47a58ee21d6809360b Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 23 Aug 2015 02:11:15 +0200 Subject: [PATCH 5972/7006] fbdev: ssd1307fb: fix error return code Propagate error code on failure. Also changed %ld to %d in dev_err to use ret variable rather than putting two calls to PTR_ERR. A simplified version of the semantic match that finds the first problem is as follows: (http://coccinelle.lip6.fr/) // @@ identifier ret; expression e1,e2; @@ ( if (\(ret < 0\|ret != 0\)) { ... return ret; } | ret = 0 ) ... when != ret = e1 when != &ret *if(...) { ... when != ret = e2 when forall return ret; } // Signed-off-by: Julia Lawall Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/ssd1307fb.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c index b6edd28b267f2..93f4c902d0f9a 100644 --- a/drivers/video/fbdev/ssd1307fb.c +++ b/drivers/video/fbdev/ssd1307fb.c @@ -656,8 +656,9 @@ static int ssd1307fb_probe(struct i2c_client *client, bl = backlight_device_register(bl_name, &client->dev, par, &ssd1307fb_bl_ops, NULL); if (IS_ERR(bl)) { - dev_err(&client->dev, "unable to register backlight device: %ld\n", - PTR_ERR(bl)); + ret = PTR_ERR(bl); + dev_err(&client->dev, "unable to register backlight device: %d\n", + ret); goto bl_init_error; } -- GitLab From 7b554088d56e9df3ee5dff8989b44903965bad95 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 18 Aug 2015 08:58:40 +0530 Subject: [PATCH 5973/7006] video: fbdev: pxa168fb: Use devm_clk_get This patch introduces the use of managed resource function devm_clk_get instead of clk_get and removes corresponding calls to clk_put in the probe and remove functions. To be compatible with the change various gotos are replaced with direct returns, and unneeded label failed_put_clk is dropped. Signed-off-by: Vaishali Thakkar Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/pxa168fb.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/video/fbdev/pxa168fb.c b/drivers/video/fbdev/pxa168fb.c index e209b039f5530..efb57c0599976 100644 --- a/drivers/video/fbdev/pxa168fb.c +++ b/drivers/video/fbdev/pxa168fb.c @@ -615,7 +615,7 @@ static int pxa168fb_probe(struct platform_device *pdev) return -EINVAL; } - clk = clk_get(&pdev->dev, "LCDCLK"); + clk = devm_clk_get(&pdev->dev, "LCDCLK"); if (IS_ERR(clk)) { dev_err(&pdev->dev, "unable to get LCDCLK"); return PTR_ERR(clk); @@ -624,21 +624,18 @@ static int pxa168fb_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (res == NULL) { dev_err(&pdev->dev, "no IO memory defined\n"); - ret = -ENOENT; - goto failed_put_clk; + return -ENOENT; } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no IRQ defined\n"); - ret = -ENOENT; - goto failed_put_clk; + return -ENOENT; } info = framebuffer_alloc(sizeof(struct pxa168fb_info), &pdev->dev); if (info == NULL) { - ret = -ENOMEM; - goto failed_put_clk; + return -ENOMEM; } /* Initialize private data */ @@ -776,8 +773,6 @@ failed_free_fbmem: info->screen_base, fbi->fb_start_dma); failed_free_info: kfree(info); -failed_put_clk: - clk_put(clk); dev_err(&pdev->dev, "frame buffer device init failed with %d\n", ret); return ret; @@ -813,7 +808,6 @@ static int pxa168fb_remove(struct platform_device *pdev) info->screen_base, info->fix.smem_start); clk_disable(fbi->clk); - clk_put(fbi->clk); framebuffer_release(info); -- GitLab From 092b6dbe8a4a24c17f2ebfe86995dc994e61f420 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 17 Aug 2015 10:09:26 +0200 Subject: [PATCH 5974/7006] mmc: android-goldfish: remove incorrect __iomem annotation Make sparse happy: drivers/mmc/host/android-goldfish.c:535:56: sparse: incorrect type in argument 3 (different address spaces) Signed-off-by: Christoph Hellwig Signed-off-by: Ulf Hansson --- drivers/mmc/host/android-goldfish.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index b1eac719a4cca..dca5518b01395 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -118,7 +118,7 @@ struct goldfish_mmc_host { struct mmc_host *mmc; struct device *dev; unsigned char id; /* 16xx chips have 2 MMC blocks */ - void __iomem *virt_base; + void *virt_base; unsigned int phys_base; int irq; unsigned char bus_mode; -- GitLab From f319cb8491e1b4cc44e7baeeb3ae7817dedf57fc Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 1 Sep 2015 20:15:10 +0800 Subject: [PATCH 5975/7006] reset: ath79: Fix missing spin_lock_init Signed-off-by: Axel Lin Acked-by: Alban Bedel Signed-off-by: Philipp Zabel --- drivers/reset/reset-ath79.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/reset/reset-ath79.c b/drivers/reset/reset-ath79.c index d2d290413113b..9aaf646ece55b 100644 --- a/drivers/reset/reset-ath79.c +++ b/drivers/reset/reset-ath79.c @@ -89,6 +89,7 @@ static int ath79_reset_probe(struct platform_device *pdev) if (IS_ERR(ath79_reset->base)) return PTR_ERR(ath79_reset->base); + spin_lock_init(&ath79_reset->lock); ath79_reset->rcdev.ops = &ath79_reset_ops; ath79_reset->rcdev.owner = THIS_MODULE; ath79_reset->rcdev.of_node = pdev->dev.of_node; -- GitLab From cc7da0ba9c96699592d0a69d7d146ac6adcc18e7 Mon Sep 17 00:00:00 2001 From: Joe Thornber Date: Tue, 1 Sep 2015 11:38:19 +0100 Subject: [PATCH 5976/7006] dm cache: fix use after freeing migrations Both free_io_migration() and issue_discard() dereference a migration that was just freed. Fix those by saving off the migrations's cache object before freeing the migration. Also cleanup needless mg->cache dereferences now that the cache object is available directly. Fixes: e44b6a5a3c ("dm cache: move wake_waker() from free_migrations() to where it is needed") Signed-off-by: Joe Thornber Signed-off-by: Mike Snitzer --- drivers/md/dm-cache-target.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c index e13e5edf22985..f9d9cc6a094bd 100644 --- a/drivers/md/dm-cache-target.c +++ b/drivers/md/dm-cache-target.c @@ -1113,9 +1113,11 @@ static void cell_requeue(struct cache *cache, struct dm_bio_prison_cell *cell) static void free_io_migration(struct dm_cache_migration *mg) { - dec_io_migrations(mg->cache); + struct cache *cache = mg->cache; + + dec_io_migrations(cache); free_migration(mg); - wake_worker(mg->cache); + wake_worker(cache); } static void migration_failure(struct dm_cache_migration *mg) @@ -1342,17 +1344,18 @@ static void issue_discard(struct dm_cache_migration *mg) { dm_dblock_t b, e; struct bio *bio = mg->new_ocell->holder; + struct cache *cache = mg->cache; - calc_discard_block_range(mg->cache, bio, &b, &e); + calc_discard_block_range(cache, bio, &b, &e); while (b != e) { - set_discard(mg->cache, b); + set_discard(cache, b); b = to_dblock(from_dblock(b) + 1); } bio_endio(bio, 0); - cell_defer(mg->cache, mg->new_ocell, false); + cell_defer(cache, mg->new_ocell, false); free_migration(mg); - wake_worker(mg->cache); + wake_worker(cache); } static void issue_copy_or_discard(struct dm_cache_migration *mg) -- GitLab From 472204fe37083aa8f31aaf183b4072d432e7c5ea Mon Sep 17 00:00:00 2001 From: Mugunthan V N Date: Mon, 31 Aug 2015 11:51:29 +0530 Subject: [PATCH 5977/7006] Documentation: DT: cpsw: document missing compatible CPSW driver has multiple compatibles for errata implementations but not documented, add necessary documentation. Signed-off-by: Mugunthan V N Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/net/cpsw.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt index 33fe8462edf49..a9df21aaa1548 100644 --- a/Documentation/devicetree/bindings/net/cpsw.txt +++ b/Documentation/devicetree/bindings/net/cpsw.txt @@ -2,7 +2,11 @@ TI SoC Ethernet Switch Controller Device Tree Bindings ------------------------------------------------------ Required properties: -- compatible : Should be "ti,cpsw" +- compatible : Should be one of the below:- + "ti,cpsw" for backward compatible + "ti,am335x-cpsw" for AM335x controllers + "ti,am4372-cpsw" for AM437x controllers + "ti,dra7-cpsw" for DRA7x controllers - reg : physical base address and size of the cpsw registers map - interrupts : property with a value describing the interrupt -- GitLab From 9d6f85d9fe422aa42f3f337872050fb2a30cd430 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Sun, 30 Aug 2015 21:44:12 +0200 Subject: [PATCH 5978/7006] mtd: nand: pxa3xx: add optional dma for pxa architecture The PXA architecture provides a DMA to pump data from the nand controller to memory and the other way around. Add it to the binding description. Signed-off-by: Robert Jarzmik Signed-off-by: Rob Herring --- Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt index 4f833e3c4f516..d9b655f110489 100644 --- a/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt +++ b/Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt @@ -11,6 +11,7 @@ Required properties: Optional properties: + - dmas: dma data channel, see dma.txt binding doc - marvell,nand-enable-arbiter: Set to enable the bus arbiter - marvell,nand-keep-config: Set to keep the NAND controller config as set by the bootloader @@ -32,6 +33,8 @@ Example: compatible = "marvell,pxa3xx-nand"; reg = <0x43100000 90>; interrupts = <45>; + dmas = <&pdma 97 0>; + dma-names = "data"; #address-cells = <1>; marvell,nand-enable-arbiter; -- GitLab From c8fb70a3e8dd60e31c4422bae85783cf1733f038 Mon Sep 17 00:00:00 2001 From: Grant Likely Date: Sun, 23 Aug 2015 13:34:08 -0700 Subject: [PATCH 5979/7006] MAINTAINERS: Add Frank Rowand as DT maintainer Frank has agreed to step up and help with DT core code maintainership. At the same time, Grant is taking a step back from active maintainership responsibilities. Add Frank to the device tree core code entry and shuffle Grant to the end of the list. In a few releases time Grant will be removed entirely. Signed-off-by: Grant Likely Signed-off-by: Rob Herring --- MAINTAINERS | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9289ecb57b68d..3d465be93c3bb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7521,8 +7521,9 @@ F: Documentation/i2c/busses/i2c-ocores F: drivers/i2c/busses/i2c-ocores.c OPEN FIRMWARE AND FLATTENED DEVICE TREE -M: Grant Likely M: Rob Herring +M: Frank Rowand +M: Grant Likely L: devicetree@vger.kernel.org W: http://www.devicetree.org/ T: git git://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux.git -- GitLab From c9c96ae2c57d91ea2b73ef447fdd44c760a96d97 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Mon, 17 Aug 2015 17:24:23 +0800 Subject: [PATCH 5980/7006] dt-bindings: mediatek: Add MT8173 CPU DVFS clock bindings This patch adds the clock and regulator consumer properties part of document for CPU DVFS clocks on Mediatek MT8173 SoC. Signed-off-by: Pi-Cheng Chen Acked-by: Michael Turquette Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- .../bindings/clock/mt8173-cpu-dvfs.txt | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt diff --git a/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt b/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt new file mode 100644 index 0000000000000..52b457c23eede --- /dev/null +++ b/Documentation/devicetree/bindings/clock/mt8173-cpu-dvfs.txt @@ -0,0 +1,83 @@ +Device Tree Clock bindins for CPU DVFS of Mediatek MT8173 SoC + +Required properties: +- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock names. +- clock-names: Should contain the following: + "cpu" - The multiplexer for clock input of CPU cluster. + "intermediate" - A parent of "cpu" clock which is used as "intermediate" clock + source (usually MAINPLL) when the original CPU PLL is under + transition and not stable yet. + Please refer to Documentation/devicetree/bindings/clk/clock-bindings.txt for + generic clock consumer properties. +- proc-supply: Regulator for Vproc of CPU cluster. + +Optional properties: +- sram-supply: Regulator for Vsram of CPU cluster. When present, the cpufreq driver + needs to do "voltage tracking" to step by step scale up/down Vproc and + Vsram to fit SoC specific needs. When absent, the voltage scaling + flow is handled by hardware, hence no software "voltage tracking" is + needed. + +Example: +-------- + cpu0: cpu@0 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x000>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA53SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + cpu1: cpu@1 { + device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x001>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA53SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + cpu2: cpu@100 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x100>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA57SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + cpu3: cpu@101 { + device_type = "cpu"; + compatible = "arm,cortex-a57"; + reg = <0x101>; + enable-method = "psci"; + cpu-idle-states = <&CPU_SLEEP_0>; + clocks = <&infracfg CLK_INFRA_CA57SEL>, + <&apmixedsys CLK_APMIXED_MAINPLL>; + clock-names = "cpu", "intermediate"; + }; + + &cpu0 { + proc-supply = <&mt6397_vpca15_reg>; + }; + + &cpu1 { + proc-supply = <&mt6397_vpca15_reg>; + }; + + &cpu2 { + proc-supply = <&da9211_vcpu_reg>; + sram-supply = <&mt6397_vsramca7_reg>; + }; + + &cpu3 { + proc-supply = <&da9211_vcpu_reg>; + sram-supply = <&mt6397_vsramca7_reg>; + }; -- GitLab From 1453863fb02a18900c9079fa2e4f02710bf46507 Mon Sep 17 00:00:00 2001 From: Pi-Cheng Chen Date: Wed, 19 Aug 2015 10:05:06 +0800 Subject: [PATCH 5981/7006] cpufreq: mediatek: Add MT8173 cpufreq driver Mediatek MT8173 is an ARMv8 based quad-core (2*Cortex-A53 and 2*Cortex-A72) SoC with duall clusters. For each cluster, two voltage inputs, Vproc and Vsram are supplied by two regulators. For the big cluster, two regulators come from different PMICs. In this case, when scaling voltage inputs of the cluster, the voltages of two regulator inputs need to be controlled by software explicitly under the SoC specific limitation: 100mV < Vsram - Vproc < 200mV which is called 'voltage tracking' mechanism. And when scaling the frequency of cluster clock input, the input MUX need to be parented to another "intermediate" stable PLL first and reparented to the original PLL once the original PLL is stable at the target frequency. This patch implements those mechanisms to enable CPU DVFS support for Mediatek MT8173 SoC. Signed-off-by: Pi-Cheng Chen Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig.arm | 7 + drivers/cpufreq/Makefile | 1 + drivers/cpufreq/mt8173-cpufreq.c | 527 +++++++++++++++++++++++++++++++ 3 files changed, 535 insertions(+) create mode 100644 drivers/cpufreq/mt8173-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index cc8a71c267b88..2bacf24a19a92 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -130,6 +130,13 @@ config ARM_KIRKWOOD_CPUFREQ This adds the CPUFreq driver for Marvell Kirkwood SoCs. +config ARM_MT8173_CPUFREQ + bool "Mediatek MT8173 CPUFreq support" + depends on ARCH_MEDIATEK && REGULATOR + select PM_OPP + help + This adds the CPUFreq driver support for Mediatek MT8173 SoC. + config ARM_OMAP2PLUS_CPUFREQ bool "TI OMAP2+" depends on ARCH_OMAP2PLUS diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile index 2169bf792db76..9c75fafd2901c 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_ARM_HISI_ACPU_CPUFREQ) += hisi-acpu-cpufreq.o obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o +obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o diff --git a/drivers/cpufreq/mt8173-cpufreq.c b/drivers/cpufreq/mt8173-cpufreq.c new file mode 100644 index 0000000000000..49caed293a3b8 --- /dev/null +++ b/drivers/cpufreq/mt8173-cpufreq.c @@ -0,0 +1,527 @@ +/* + * Copyright (c) 2015 Linaro Ltd. + * Author: Pi-Cheng Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MIN_VOLT_SHIFT (100000) +#define MAX_VOLT_SHIFT (200000) +#define MAX_VOLT_LIMIT (1150000) +#define VOLT_TOL (10000) + +/* + * The struct mtk_cpu_dvfs_info holds necessary information for doing CPU DVFS + * on each CPU power/clock domain of Mediatek SoCs. Each CPU cluster in + * Mediatek SoCs has two voltage inputs, Vproc and Vsram. In some cases the two + * voltage inputs need to be controlled under a hardware limitation: + * 100mV < Vsram - Vproc < 200mV + * + * When scaling the clock frequency of a CPU clock domain, the clock source + * needs to be switched to another stable PLL clock temporarily until + * the original PLL becomes stable at target frequency. + */ +struct mtk_cpu_dvfs_info { + struct device *cpu_dev; + struct regulator *proc_reg; + struct regulator *sram_reg; + struct clk *cpu_clk; + struct clk *inter_clk; + struct thermal_cooling_device *cdev; + int intermediate_voltage; + bool need_voltage_tracking; +}; + +static int mtk_cpufreq_voltage_tracking(struct mtk_cpu_dvfs_info *info, + int new_vproc) +{ + struct regulator *proc_reg = info->proc_reg; + struct regulator *sram_reg = info->sram_reg; + int old_vproc, old_vsram, new_vsram, vsram, vproc, ret; + + old_vproc = regulator_get_voltage(proc_reg); + old_vsram = regulator_get_voltage(sram_reg); + /* Vsram should not exceed the maximum allowed voltage of SoC. */ + new_vsram = min(new_vproc + MIN_VOLT_SHIFT, MAX_VOLT_LIMIT); + + if (old_vproc < new_vproc) { + /* + * When scaling up voltages, Vsram and Vproc scale up step + * by step. At each step, set Vsram to (Vproc + 200mV) first, + * then set Vproc to (Vsram - 100mV). + * Keep doing it until Vsram and Vproc hit target voltages. + */ + do { + old_vsram = regulator_get_voltage(sram_reg); + old_vproc = regulator_get_voltage(proc_reg); + + vsram = min(new_vsram, old_vproc + MAX_VOLT_SHIFT); + + if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) { + vsram = MAX_VOLT_LIMIT; + + /* + * If the target Vsram hits the maximum voltage, + * try to set the exact voltage value first. + */ + ret = regulator_set_voltage(sram_reg, vsram, + vsram); + if (ret) + ret = regulator_set_voltage(sram_reg, + vsram - VOLT_TOL, + vsram); + + vproc = new_vproc; + } else { + ret = regulator_set_voltage(sram_reg, vsram, + vsram + VOLT_TOL); + + vproc = vsram - MIN_VOLT_SHIFT; + } + if (ret) + return ret; + + ret = regulator_set_voltage(proc_reg, vproc, + vproc + VOLT_TOL); + if (ret) { + regulator_set_voltage(sram_reg, old_vsram, + old_vsram); + return ret; + } + } while (vproc < new_vproc || vsram < new_vsram); + } else if (old_vproc > new_vproc) { + /* + * When scaling down voltages, Vsram and Vproc scale down step + * by step. At each step, set Vproc to (Vsram - 200mV) first, + * then set Vproc to (Vproc + 100mV). + * Keep doing it until Vsram and Vproc hit target voltages. + */ + do { + old_vproc = regulator_get_voltage(proc_reg); + old_vsram = regulator_get_voltage(sram_reg); + + vproc = max(new_vproc, old_vsram - MAX_VOLT_SHIFT); + ret = regulator_set_voltage(proc_reg, vproc, + vproc + VOLT_TOL); + if (ret) + return ret; + + if (vproc == new_vproc) + vsram = new_vsram; + else + vsram = max(new_vsram, vproc + MIN_VOLT_SHIFT); + + if (vsram + VOLT_TOL >= MAX_VOLT_LIMIT) { + vsram = MAX_VOLT_LIMIT; + + /* + * If the target Vsram hits the maximum voltage, + * try to set the exact voltage value first. + */ + ret = regulator_set_voltage(sram_reg, vsram, + vsram); + if (ret) + ret = regulator_set_voltage(sram_reg, + vsram - VOLT_TOL, + vsram); + } else { + ret = regulator_set_voltage(sram_reg, vsram, + vsram + VOLT_TOL); + } + + if (ret) { + regulator_set_voltage(proc_reg, old_vproc, + old_vproc); + return ret; + } + } while (vproc > new_vproc + VOLT_TOL || + vsram > new_vsram + VOLT_TOL); + } + + return 0; +} + +static int mtk_cpufreq_set_voltage(struct mtk_cpu_dvfs_info *info, int vproc) +{ + if (info->need_voltage_tracking) + return mtk_cpufreq_voltage_tracking(info, vproc); + else + return regulator_set_voltage(info->proc_reg, vproc, + vproc + VOLT_TOL); +} + +static int mtk_cpufreq_set_target(struct cpufreq_policy *policy, + unsigned int index) +{ + struct cpufreq_frequency_table *freq_table = policy->freq_table; + struct clk *cpu_clk = policy->clk; + struct clk *armpll = clk_get_parent(cpu_clk); + struct mtk_cpu_dvfs_info *info = policy->driver_data; + struct device *cpu_dev = info->cpu_dev; + struct dev_pm_opp *opp; + long freq_hz, old_freq_hz; + int vproc, old_vproc, inter_vproc, target_vproc, ret; + + inter_vproc = info->intermediate_voltage; + + old_freq_hz = clk_get_rate(cpu_clk); + old_vproc = regulator_get_voltage(info->proc_reg); + + freq_hz = freq_table[index].frequency * 1000; + + rcu_read_lock(); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_hz); + if (IS_ERR(opp)) { + rcu_read_unlock(); + pr_err("cpu%d: failed to find OPP for %ld\n", + policy->cpu, freq_hz); + return PTR_ERR(opp); + } + vproc = dev_pm_opp_get_voltage(opp); + rcu_read_unlock(); + + /* + * If the new voltage or the intermediate voltage is higher than the + * current voltage, scale up voltage first. + */ + target_vproc = (inter_vproc > vproc) ? inter_vproc : vproc; + if (old_vproc < target_vproc) { + ret = mtk_cpufreq_set_voltage(info, target_vproc); + if (ret) { + pr_err("cpu%d: failed to scale up voltage!\n", + policy->cpu); + mtk_cpufreq_set_voltage(info, old_vproc); + return ret; + } + } + + /* Reparent the CPU clock to intermediate clock. */ + ret = clk_set_parent(cpu_clk, info->inter_clk); + if (ret) { + pr_err("cpu%d: failed to re-parent cpu clock!\n", + policy->cpu); + mtk_cpufreq_set_voltage(info, old_vproc); + WARN_ON(1); + return ret; + } + + /* Set the original PLL to target rate. */ + ret = clk_set_rate(armpll, freq_hz); + if (ret) { + pr_err("cpu%d: failed to scale cpu clock rate!\n", + policy->cpu); + clk_set_parent(cpu_clk, armpll); + mtk_cpufreq_set_voltage(info, old_vproc); + return ret; + } + + /* Set parent of CPU clock back to the original PLL. */ + ret = clk_set_parent(cpu_clk, armpll); + if (ret) { + pr_err("cpu%d: failed to re-parent cpu clock!\n", + policy->cpu); + mtk_cpufreq_set_voltage(info, inter_vproc); + WARN_ON(1); + return ret; + } + + /* + * If the new voltage is lower than the intermediate voltage or the + * original voltage, scale down to the new voltage. + */ + if (vproc < inter_vproc || vproc < old_vproc) { + ret = mtk_cpufreq_set_voltage(info, vproc); + if (ret) { + pr_err("cpu%d: failed to scale down voltage!\n", + policy->cpu); + clk_set_parent(cpu_clk, info->inter_clk); + clk_set_rate(armpll, old_freq_hz); + clk_set_parent(cpu_clk, armpll); + return ret; + } + } + + return 0; +} + +static void mtk_cpufreq_ready(struct cpufreq_policy *policy) +{ + struct mtk_cpu_dvfs_info *info = policy->driver_data; + struct device_node *np = of_node_get(info->cpu_dev->of_node); + + if (WARN_ON(!np)) + return; + + if (of_find_property(np, "#cooling-cells", NULL)) { + info->cdev = of_cpufreq_cooling_register(np, + policy->related_cpus); + + if (IS_ERR(info->cdev)) { + dev_err(info->cpu_dev, + "running cpufreq without cooling device: %ld\n", + PTR_ERR(info->cdev)); + + info->cdev = NULL; + } + } + + of_node_put(np); +} + +static int mtk_cpu_dvfs_info_init(struct mtk_cpu_dvfs_info *info, int cpu) +{ + struct device *cpu_dev; + struct regulator *proc_reg = ERR_PTR(-ENODEV); + struct regulator *sram_reg = ERR_PTR(-ENODEV); + struct clk *cpu_clk = ERR_PTR(-ENODEV); + struct clk *inter_clk = ERR_PTR(-ENODEV); + struct dev_pm_opp *opp; + unsigned long rate; + int ret; + + cpu_dev = get_cpu_device(cpu); + if (!cpu_dev) { + pr_err("failed to get cpu%d device\n", cpu); + return -ENODEV; + } + + cpu_clk = clk_get(cpu_dev, "cpu"); + if (IS_ERR(cpu_clk)) { + if (PTR_ERR(cpu_clk) == -EPROBE_DEFER) + pr_warn("cpu clk for cpu%d not ready, retry.\n", cpu); + else + pr_err("failed to get cpu clk for cpu%d\n", cpu); + + ret = PTR_ERR(cpu_clk); + return ret; + } + + inter_clk = clk_get(cpu_dev, "intermediate"); + if (IS_ERR(inter_clk)) { + if (PTR_ERR(inter_clk) == -EPROBE_DEFER) + pr_warn("intermediate clk for cpu%d not ready, retry.\n", + cpu); + else + pr_err("failed to get intermediate clk for cpu%d\n", + cpu); + + ret = PTR_ERR(inter_clk); + goto out_free_resources; + } + + proc_reg = regulator_get_exclusive(cpu_dev, "proc"); + if (IS_ERR(proc_reg)) { + if (PTR_ERR(proc_reg) == -EPROBE_DEFER) + pr_warn("proc regulator for cpu%d not ready, retry.\n", + cpu); + else + pr_err("failed to get proc regulator for cpu%d\n", + cpu); + + ret = PTR_ERR(proc_reg); + goto out_free_resources; + } + + /* Both presence and absence of sram regulator are valid cases. */ + sram_reg = regulator_get_exclusive(cpu_dev, "sram"); + + ret = of_init_opp_table(cpu_dev); + if (ret) { + pr_warn("no OPP table for cpu%d\n", cpu); + goto out_free_resources; + } + + /* Search a safe voltage for intermediate frequency. */ + rate = clk_get_rate(inter_clk); + rcu_read_lock(); + opp = dev_pm_opp_find_freq_ceil(cpu_dev, &rate); + if (IS_ERR(opp)) { + rcu_read_unlock(); + pr_err("failed to get intermediate opp for cpu%d\n", cpu); + ret = PTR_ERR(opp); + goto out_free_opp_table; + } + info->intermediate_voltage = dev_pm_opp_get_voltage(opp); + rcu_read_unlock(); + + info->cpu_dev = cpu_dev; + info->proc_reg = proc_reg; + info->sram_reg = IS_ERR(sram_reg) ? NULL : sram_reg; + info->cpu_clk = cpu_clk; + info->inter_clk = inter_clk; + + /* + * If SRAM regulator is present, software "voltage tracking" is needed + * for this CPU power domain. + */ + info->need_voltage_tracking = !IS_ERR(sram_reg); + + return 0; + +out_free_opp_table: + of_free_opp_table(cpu_dev); + +out_free_resources: + if (!IS_ERR(proc_reg)) + regulator_put(proc_reg); + if (!IS_ERR(sram_reg)) + regulator_put(sram_reg); + if (!IS_ERR(cpu_clk)) + clk_put(cpu_clk); + if (!IS_ERR(inter_clk)) + clk_put(inter_clk); + + return ret; +} + +static void mtk_cpu_dvfs_info_release(struct mtk_cpu_dvfs_info *info) +{ + if (!IS_ERR(info->proc_reg)) + regulator_put(info->proc_reg); + if (!IS_ERR(info->sram_reg)) + regulator_put(info->sram_reg); + if (!IS_ERR(info->cpu_clk)) + clk_put(info->cpu_clk); + if (!IS_ERR(info->inter_clk)) + clk_put(info->inter_clk); + + of_free_opp_table(info->cpu_dev); +} + +static int mtk_cpufreq_init(struct cpufreq_policy *policy) +{ + struct mtk_cpu_dvfs_info *info; + struct cpufreq_frequency_table *freq_table; + int ret; + + info = kzalloc(sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + ret = mtk_cpu_dvfs_info_init(info, policy->cpu); + if (ret) { + pr_err("%s failed to initialize dvfs info for cpu%d\n", + __func__, policy->cpu); + goto out_free_dvfs_info; + } + + ret = dev_pm_opp_init_cpufreq_table(info->cpu_dev, &freq_table); + if (ret) { + pr_err("failed to init cpufreq table for cpu%d: %d\n", + policy->cpu, ret); + goto out_release_dvfs_info; + } + + ret = cpufreq_table_validate_and_show(policy, freq_table); + if (ret) { + pr_err("%s: invalid frequency table: %d\n", __func__, ret); + goto out_free_cpufreq_table; + } + + /* CPUs in the same cluster share a clock and power domain. */ + cpumask_copy(policy->cpus, &cpu_topology[policy->cpu].core_sibling); + policy->driver_data = info; + policy->clk = info->cpu_clk; + + return 0; + +out_free_cpufreq_table: + dev_pm_opp_free_cpufreq_table(info->cpu_dev, &freq_table); + +out_release_dvfs_info: + mtk_cpu_dvfs_info_release(info); + +out_free_dvfs_info: + kfree(info); + + return ret; +} + +static int mtk_cpufreq_exit(struct cpufreq_policy *policy) +{ + struct mtk_cpu_dvfs_info *info = policy->driver_data; + + cpufreq_cooling_unregister(info->cdev); + dev_pm_opp_free_cpufreq_table(info->cpu_dev, &policy->freq_table); + mtk_cpu_dvfs_info_release(info); + kfree(info); + + return 0; +} + +static struct cpufreq_driver mt8173_cpufreq_driver = { + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, + .verify = cpufreq_generic_frequency_table_verify, + .target_index = mtk_cpufreq_set_target, + .get = cpufreq_generic_get, + .init = mtk_cpufreq_init, + .exit = mtk_cpufreq_exit, + .ready = mtk_cpufreq_ready, + .name = "mtk-cpufreq", + .attr = cpufreq_generic_attr, +}; + +static int mt8173_cpufreq_probe(struct platform_device *pdev) +{ + int ret; + + ret = cpufreq_register_driver(&mt8173_cpufreq_driver); + if (ret) + pr_err("failed to register mtk cpufreq driver\n"); + + return ret; +} + +static struct platform_driver mt8173_cpufreq_platdrv = { + .driver = { + .name = "mt8173-cpufreq", + }, + .probe = mt8173_cpufreq_probe, +}; + +static int mt8173_cpufreq_driver_init(void) +{ + struct platform_device *pdev; + int err; + + if (!of_machine_is_compatible("mediatek,mt8173")) + return -ENODEV; + + err = platform_driver_register(&mt8173_cpufreq_platdrv); + if (err) + return err; + + /* + * Since there's no place to hold device registration code and no + * device tree based way to match cpufreq driver yet, both the driver + * and the device registration codes are put here to handle defer + * probing. + */ + pdev = platform_device_register_simple("mt8173-cpufreq", -1, NULL, 0); + if (IS_ERR(pdev)) { + pr_err("failed to register mtk-cpufreq platform device\n"); + return PTR_ERR(pdev); + } + + return 0; +} +device_initcall(mt8173_cpufreq_driver_init); -- GitLab From 6bfb7c7434f75d29241413dc7e784295ba56de98 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:14 +0530 Subject: [PATCH 5982/7006] cpufreq: remove redundant CPUFREQ_INCOMPATIBLE notifier event What's being done from CPUFREQ_INCOMPATIBLE, can also be done with CPUFREQ_ADJUST. There is nothing special with CPUFREQ_INCOMPATIBLE notifier. Kill CPUFREQ_INCOMPATIBLE and fix its usage sites. This also updates the numbering of notifier events to remove holes. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- Documentation/cpu-freq/core.txt | 7 ++----- drivers/acpi/processor_perflib.c | 2 +- drivers/cpufreq/cpufreq.c | 4 ---- drivers/cpufreq/ppc_cbe_cpufreq_pmi.c | 4 ++-- drivers/video/fbdev/pxafb.c | 1 - drivers/video/fbdev/sa1100fb.c | 1 - include/linux/cpufreq.h | 9 ++++----- 7 files changed, 9 insertions(+), 19 deletions(-) diff --git a/Documentation/cpu-freq/core.txt b/Documentation/cpu-freq/core.txt index 70933eadc308d..ba78e7c2a0697 100644 --- a/Documentation/cpu-freq/core.txt +++ b/Documentation/cpu-freq/core.txt @@ -55,16 +55,13 @@ transition notifiers. ---------------------------- These are notified when a new policy is intended to be set. Each -CPUFreq policy notifier is called three times for a policy transition: +CPUFreq policy notifier is called twice for a policy transition: 1.) During CPUFREQ_ADJUST all CPUFreq notifiers may change the limit if they see a need for this - may it be thermal considerations or hardware limitations. -2.) During CPUFREQ_INCOMPATIBLE only changes may be done in order to avoid - hardware failure. - -3.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy +2.) And during CPUFREQ_NOTIFY all notifiers are informed of the new policy - if two hardware drivers failed to agree on a new policy before this stage, the incompatible hardware shall be shut down, and the user informed of this. diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 36b6da2918a68..91941f1cdecb4 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c @@ -87,7 +87,7 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb, if (ignore_ppc) return 0; - if (event != CPUFREQ_INCOMPATIBLE) + if (event != CPUFREQ_ADJUST) return 0; mutex_lock(&performance_mutex); diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 76a26609d96bc..293f47b814bf0 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2206,10 +2206,6 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, blocking_notifier_call_chain(&cpufreq_policy_notifier_list, CPUFREQ_ADJUST, new_policy); - /* adjust if necessary - hardware incompatibility*/ - blocking_notifier_call_chain(&cpufreq_policy_notifier_list, - CPUFREQ_INCOMPATIBLE, new_policy); - /* * verify the cpu speed can be set within this limit, which might be * different to the first one diff --git a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c index d29e8da396a04..7969f7690498b 100644 --- a/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c +++ b/drivers/cpufreq/ppc_cbe_cpufreq_pmi.c @@ -97,8 +97,8 @@ static int pmi_notifier(struct notifier_block *nb, struct cpufreq_frequency_table *cbe_freqs; u8 node; - /* Should this really be called for CPUFREQ_ADJUST, CPUFREQ_INCOMPATIBLE - * and CPUFREQ_NOTIFY policy events?) + /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY + * policy events?) */ if (event == CPUFREQ_START) return 0; diff --git a/drivers/video/fbdev/pxafb.c b/drivers/video/fbdev/pxafb.c index 7245611ec9639..94813af97f09f 100644 --- a/drivers/video/fbdev/pxafb.c +++ b/drivers/video/fbdev/pxafb.c @@ -1668,7 +1668,6 @@ pxafb_freq_policy(struct notifier_block *nb, unsigned long val, void *data) switch (val) { case CPUFREQ_ADJUST: - case CPUFREQ_INCOMPATIBLE: pr_debug("min dma period: %d ps, " "new clock %d kHz\n", pxafb_display_dma_period(var), policy->max); diff --git a/drivers/video/fbdev/sa1100fb.c b/drivers/video/fbdev/sa1100fb.c index 89dd7e02197ff..dcf774c158896 100644 --- a/drivers/video/fbdev/sa1100fb.c +++ b/drivers/video/fbdev/sa1100fb.c @@ -1042,7 +1042,6 @@ sa1100fb_freq_policy(struct notifier_block *nb, unsigned long val, switch (val) { case CPUFREQ_ADJUST: - case CPUFREQ_INCOMPATIBLE: dev_dbg(fbi->dev, "min dma period: %d ps, " "new clock %d kHz\n", sa1100fb_min_dma_period(fbi), policy->max); diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bde1e567b3a93..bedcc90c0757f 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -369,11 +369,10 @@ static inline void cpufreq_resume(void) {} /* Policy Notifiers */ #define CPUFREQ_ADJUST (0) -#define CPUFREQ_INCOMPATIBLE (1) -#define CPUFREQ_NOTIFY (2) -#define CPUFREQ_START (3) -#define CPUFREQ_CREATE_POLICY (4) -#define CPUFREQ_REMOVE_POLICY (5) +#define CPUFREQ_NOTIFY (1) +#define CPUFREQ_START (2) +#define CPUFREQ_CREATE_POLICY (3) +#define CPUFREQ_REMOVE_POLICY (4) #ifdef CONFIG_CPU_FREQ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); -- GitLab From 8fa5b631f32238a16ae3db0db5b354f7b9eb20cb Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:15 +0530 Subject: [PATCH 5983/7006] cpufreq: use memcpy() to copy policy cpufreq_get_policy() is useful if the pointer to policy isn't available in advance. But if it is available, then there is no need to call cpufreq_get_policy(). Directly use memcpy() to copy the policy. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 293f47b814bf0..86d69416821b3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -606,9 +606,7 @@ static ssize_t store_##file_name \ int ret, temp; \ struct cpufreq_policy new_policy; \ \ - ret = cpufreq_get_policy(&new_policy, policy->cpu); \ - if (ret) \ - return -EINVAL; \ + memcpy(&new_policy, policy, sizeof(*policy)); \ \ ret = sscanf(buf, "%u", &new_policy.object); \ if (ret != 1) \ @@ -662,9 +660,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, char str_governor[16]; struct cpufreq_policy new_policy; - ret = cpufreq_get_policy(&new_policy, policy->cpu); - if (ret) - return ret; + memcpy(&new_policy, policy, sizeof(*policy)); ret = sscanf(buf, "%15s", str_governor); if (ret != 1) -- GitLab From 14ca0bdfdd6b422027b9b733abb0bf151811eaa7 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:16 +0530 Subject: [PATCH 5984/7006] cpufreq: update user_policy.* on success 'user_policy' caches properties of a policy that are set by userspace. And these must be updated only if cpufreq core was successful in updating them based on request from user space. In store_scaling_governor(), we are updating user_policy.policy and user_policy.governor even if cpufreq_set_policy() failed. That's incorrect. Fix this by updating user_policy.* only if we were successful in updating the properties. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 86d69416821b3..8e71d8e084397 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -671,14 +671,12 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, return -EINVAL; ret = cpufreq_set_policy(policy, &new_policy); + if (ret) + return ret; policy->user_policy.policy = policy->policy; policy->user_policy.governor = policy->governor; - - if (ret) - return ret; - else - return count; + return count; } /** -- GitLab From e27f8bd248756310a6df8b67f96d41d5a693642c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:17 +0530 Subject: [PATCH 5985/7006] cpufreq: remove redundant 'governor' field from user_policy Its always same as policy->governor, and there is no need to keep another copy of it. Remove it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 7 ++----- include/linux/cpufreq.h | 1 - 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8e71d8e084397..3033952391fe3 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -675,7 +675,6 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, return ret; policy->user_policy.policy = policy->policy; - policy->user_policy.governor = policy->governor; return count; } @@ -1323,10 +1322,9 @@ static int cpufreq_online(unsigned int cpu) goto out_exit_policy; } - if (new_policy) { + if (new_policy) policy->user_policy.policy = policy->policy; - policy->user_policy.governor = policy->governor; - } + up_write(&policy->rwsem); kobject_uevent(&policy->kobj, KOBJ_ADD); @@ -2305,7 +2303,6 @@ int cpufreq_update_policy(unsigned int cpu) new_policy.min = policy->user_policy.min; new_policy.max = policy->user_policy.max; new_policy.policy = policy->user_policy.policy; - new_policy.governor = policy->user_policy.governor; /* * BIOS might change freq behind our back diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index bedcc90c0757f..752bf8a5c3146 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -55,7 +55,6 @@ struct cpufreq_real_policy { unsigned int min; /* in kHz */ unsigned int max; /* in kHz */ unsigned int policy; /* see above */ - struct cpufreq_governor *governor; /* see below */ }; struct cpufreq_policy { -- GitLab From 88dc4384958759510db248bf9158434ac783d407 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:18 +0530 Subject: [PATCH 5986/7006] cpufreq: remove redundant 'policy' field from user_policy Its always same as policy->policy, and there is no need to keep another copy of it. Remove it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 10 +--------- include/linux/cpufreq.h | 1 - 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 3033952391fe3..a80bd68bbd747 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -671,11 +671,7 @@ static ssize_t store_scaling_governor(struct cpufreq_policy *policy, return -EINVAL; ret = cpufreq_set_policy(policy, &new_policy); - if (ret) - return ret; - - policy->user_policy.policy = policy->policy; - return count; + return ret ? ret : count; } /** @@ -1322,9 +1318,6 @@ static int cpufreq_online(unsigned int cpu) goto out_exit_policy; } - if (new_policy) - policy->user_policy.policy = policy->policy; - up_write(&policy->rwsem); kobject_uevent(&policy->kobj, KOBJ_ADD); @@ -2302,7 +2295,6 @@ int cpufreq_update_policy(unsigned int cpu) memcpy(&new_policy, policy, sizeof(*policy)); new_policy.min = policy->user_policy.min; new_policy.max = policy->user_policy.max; - new_policy.policy = policy->user_policy.policy; /* * BIOS might change freq behind our back diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 752bf8a5c3146..54dbbff0a55ee 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -54,7 +54,6 @@ struct cpufreq_cpuinfo { struct cpufreq_real_policy { unsigned int min; /* in kHz */ unsigned int max; /* in kHz */ - unsigned int policy; /* see above */ }; struct cpufreq_policy { -- GitLab From c7a7b418dd1991079dd7ef03fec7d1863ef96154 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:19 +0530 Subject: [PATCH 5987/7006] cpufreq: rename cpufreq_real_policy as cpufreq_user_policy Its all about caching min/max freq requested by userspace, and the name 'cpufreq_real_policy' doesn't fit that well. Rename it to cpufreq_user_policy. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- include/linux/cpufreq.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 54dbbff0a55ee..6ff6a4d95eeaa 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -51,7 +51,7 @@ struct cpufreq_cpuinfo { unsigned int transition_latency; }; -struct cpufreq_real_policy { +struct cpufreq_user_policy { unsigned int min; /* in kHz */ unsigned int max; /* in kHz */ }; @@ -86,7 +86,7 @@ struct cpufreq_policy { struct work_struct update; /* if update_policy() needs to be * called, but you're in IRQ context */ - struct cpufreq_real_policy user_policy; + struct cpufreq_user_policy user_policy; struct cpufreq_frequency_table *freq_table; struct list_head policy_list; -- GitLab From 36dfef23cd26a6d3b71dd86509e34d311f1cd906 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 3 Aug 2015 08:36:20 +0530 Subject: [PATCH 5988/7006] cpufreq: drop !cpufreq_driver check from cpufreq_parse_governor() Driver is guaranteed to be present on a call to cpufreq_parse_governor() and there is no need to check for !cpufreq_driver. Drop it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index a80bd68bbd747..a05cc75cc45d7 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -520,9 +520,6 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, { int err = -EINVAL; - if (!cpufreq_driver) - goto out; - if (cpufreq_driver->setpolicy) { if (!strncasecmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { *policy = CPUFREQ_POLICY_PERFORMANCE; @@ -557,7 +554,6 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy, mutex_unlock(&cpufreq_governor_mutex); } -out: return err; } -- GitLab From a482e5562e48d89ea50f41f9fc6ed3a9768de2ff Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:17 +0200 Subject: [PATCH 5989/7006] cpufreq: sfi: use kmemdup rather than duplicating its implementation The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/sfi-cpufreq.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c index ffa3389e535b8..992ce6f9abecd 100644 --- a/drivers/cpufreq/sfi-cpufreq.c +++ b/drivers/cpufreq/sfi-cpufreq.c @@ -45,12 +45,10 @@ static int sfi_parse_freq(struct sfi_table_header *table) pentry = (struct sfi_freq_table_entry *)sb->pentry; totallen = num_freq_table_entries * sizeof(*pentry); - sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL); + sfi_cpufreq_array = kmemdup(pentry, totallen, GFP_KERNEL); if (!sfi_cpufreq_array) return -ENOMEM; - memcpy(sfi_cpufreq_array, pentry, totallen); - return 0; } -- GitLab From 309d0631cc329ca1051c631c89e0acc9b752cb4d Mon Sep 17 00:00:00 2001 From: Shilpasri G Bhat Date: Thu, 27 Aug 2015 14:41:44 +0530 Subject: [PATCH 5990/7006] cpufreq: powernv: Increase the verbosity of OCC console messages Modify the OCC reset/load/active event message to make it clearer for the user to understand the event and effect of the event. Suggested-by: Stewart Smith Signed-off-by: Shilpasri G Bhat Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/powernv-cpufreq.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/cpufreq/powernv-cpufreq.c b/drivers/cpufreq/powernv-cpufreq.c index 546e056e416d4..64994e10638e4 100644 --- a/drivers/cpufreq/powernv-cpufreq.c +++ b/drivers/cpufreq/powernv-cpufreq.c @@ -465,6 +465,7 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, switch (omsg.type) { case OCC_RESET: occ_reset = true; + pr_info("OCC (On Chip Controller - enforces hard thermal/power limits) Resetting\n"); /* * powernv_cpufreq_throttle_check() is called in * target() callback which can detect the throttle state @@ -474,12 +475,12 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, */ if (!throttled) { throttled = true; - pr_crit("CPU Frequency is throttled\n"); + pr_crit("CPU frequency is throttled for duration\n"); } - pr_info("OCC: Reset\n"); + break; case OCC_LOAD: - pr_info("OCC: Loaded\n"); + pr_info("OCC Loading, CPU frequency is throttled until OCC is started\n"); break; case OCC_THROTTLE: omsg.chip = be64_to_cpu(msg->params[1]); @@ -488,7 +489,7 @@ static int powernv_cpufreq_occ_msg(struct notifier_block *nb, if (occ_reset) { occ_reset = false; throttled = false; - pr_info("OCC: Active\n"); + pr_info("OCC Active, CPU frequency is no longer throttled\n"); for (i = 0; i < nr_chips; i++) { chips[i].restore = true; -- GitLab From 72e624de6e6f0d5a638fbc23842aa76ae048e9e7 Mon Sep 17 00:00:00 2001 From: Abhilash Jindal Date: Tue, 11 Aug 2015 12:01:22 -0400 Subject: [PATCH 5991/7006] cpufreq: speedstep-lib: Use monotonic clock Wall time obtained from do_gettimeofday is susceptible to sudden jumps due to user setting the time or due to NTP. Monotonic time is constantly increasing time better suited for comparing two timestamps. Signed-off-by: Abhilash Jindal Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/speedstep-lib.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c index 4ab7a21566724..15d3214aaa00b 100644 --- a/drivers/cpufreq/speedstep-lib.c +++ b/drivers/cpufreq/speedstep-lib.c @@ -386,7 +386,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, unsigned int prev_speed; unsigned int ret = 0; unsigned long flags; - struct timeval tv1, tv2; + ktime_t tv1, tv2; if ((!processor) || (!low_speed) || (!high_speed) || (!set_state)) return -EINVAL; @@ -415,14 +415,14 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, /* start latency measurement */ if (transition_latency) - do_gettimeofday(&tv1); + tv1 = ktime_get(); /* switch to high state */ set_state(SPEEDSTEP_HIGH); /* end latency measurement */ if (transition_latency) - do_gettimeofday(&tv2); + tv2 = ktime_get(); *high_speed = speedstep_get_frequency(processor); if (!*high_speed) { @@ -442,8 +442,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor, set_state(SPEEDSTEP_LOW); if (transition_latency) { - *transition_latency = (tv2.tv_sec - tv1.tv_sec) * USEC_PER_SEC + - tv2.tv_usec - tv1.tv_usec; + *transition_latency = ktime_to_us(ktime_sub(tv2, tv1)); pr_debug("transition latency is %u uSec\n", *transition_latency); /* convert uSec to nSec and add 20% for safety reasons */ -- GitLab From 3b27d13940c3710a1128527c43719cb0bb05d73b Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 1 Sep 2015 03:29:44 +0000 Subject: [PATCH 5992/7006] perf dwarf: Fix potential array out of bounds access There is a problem in the dwarf-regs.c files for sh, sparc and x86 where it is possible to make an out-of-bounds array access when searching for register names. This patch fixes it by replacing '<=' to '<', so when register (number == XXX_MAX_REGS), get_arch_regstr() will return NULL. Signed-off-by: Wang Nan Reviewed-by: Matt Fleming Acked-by: Jiri Olsa Acked-by: Masami Hiramatsu Cc: David S. Miller Cc: Zefan Li Cc: pi3orama@huawei.com Link: http://lkml.kernel.org/r/1441078184-105038-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/sh/util/dwarf-regs.c | 2 +- tools/perf/arch/sparc/util/dwarf-regs.c | 2 +- tools/perf/arch/x86/util/dwarf-regs.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/perf/arch/sh/util/dwarf-regs.c b/tools/perf/arch/sh/util/dwarf-regs.c index 0d0897f57a102..f8dfa89696f42 100644 --- a/tools/perf/arch/sh/util/dwarf-regs.c +++ b/tools/perf/arch/sh/util/dwarf-regs.c @@ -51,5 +51,5 @@ const char *sh_regs_table[SH_MAX_REGS] = { /* Return architecture dependent register string (for kprobe-tracer) */ const char *get_arch_regstr(unsigned int n) { - return (n <= SH_MAX_REGS) ? sh_regs_table[n] : NULL; + return (n < SH_MAX_REGS) ? sh_regs_table[n] : NULL; } diff --git a/tools/perf/arch/sparc/util/dwarf-regs.c b/tools/perf/arch/sparc/util/dwarf-regs.c index 92eda412fed34..b704fdb9237a9 100644 --- a/tools/perf/arch/sparc/util/dwarf-regs.c +++ b/tools/perf/arch/sparc/util/dwarf-regs.c @@ -39,5 +39,5 @@ const char *sparc_regs_table[SPARC_MAX_REGS] = { */ const char *get_arch_regstr(unsigned int n) { - return (n <= SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL; + return (n < SPARC_MAX_REGS) ? sparc_regs_table[n] : NULL; } diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index be22dd463232e..a08de0a35b838 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c @@ -71,5 +71,5 @@ const char *x86_64_regs_table[X86_64_MAX_REGS] = { /* Return architecture dependent register string (for kprobe-tracer) */ const char *get_arch_regstr(unsigned int n) { - return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL; + return (n < ARCH_MAX_REGS) ? arch_regs_table[n] : NULL; } -- GitLab From 04aa90b529ee45c5ee88997bc214202e07b26979 Mon Sep 17 00:00:00 2001 From: Wang Nan Date: Tue, 1 Sep 2015 05:56:45 +0000 Subject: [PATCH 5993/7006] perf build: Fix Intel PT instruction decoder dependency problem I hit following building error randomly: ... /bin/sh: /path/to/kernel/buildperf/util/intel-pt-decoder/inat-tables.c: No such file or directory ... LINK /path/to/kernel/buildperf/plugin_mac80211.so LINK /path/to/kernel/buildperf/plugin_kmem.so LINK /path/to/kernel/buildperf/plugin_xen.so LINK /path/to/kernel/buildperf/plugin_hrtimer.so In file included from util/intel-pt-decoder/intel-pt-insn-decoder.c:25:0: util/intel-pt-decoder/inat.c:24:25: fatal error: inat-tables.c: No such file or directory #include "inat-tables.c" ^ compilation terminated. make[4]: *** [/path/to/kernel/buildperf/util/intel-pt-decoder/intel-pt-insn-decoder.o] Error 1 make[4]: *** Waiting for unfinished jobs.... LINK /path/to/kernel/buildperf/plugin_function.so This is caused by tools/perf/util/intel-pt-decoder/Build that, it tries to generate $(OUTPUT)util/intel-pt-decoder/inat-tables.c atomatically but forget to ensure the existance of $(OUTPUT)util/intel-pt-decoder directory. This patch fixes it by adding $(call rule_mkdir) like other similar rules. Signed-off-by: Wang Nan Acked-by: Adrian Hunter Acked-by: Jiri Olsa Cc: Zefan Li Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1441087005-107540-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/Build | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/perf/util/intel-pt-decoder/Build b/tools/perf/util/intel-pt-decoder/Build index 240730d682c1b..2386322ece4fc 100644 --- a/tools/perf/util/intel-pt-decoder/Build +++ b/tools/perf/util/intel-pt-decoder/Build @@ -4,6 +4,7 @@ inat_tables_script = util/intel-pt-decoder/gen-insn-attr-x86.awk inat_tables_maps = util/intel-pt-decoder/x86-opcode-map.txt $(OUTPUT)util/intel-pt-decoder/inat-tables.c: $(inat_tables_script) $(inat_tables_maps) + $(call rule_mkdir) @$(call echo-cmd,gen)$(AWK) -f $(inat_tables_script) $(inat_tables_maps) > $@ || rm -f $@ $(OUTPUT)util/intel-pt-decoder/intel-pt-insn-decoder.o: util/intel-pt-decoder/inat.c $(OUTPUT)util/intel-pt-decoder/inat-tables.c -- GitLab From af4aeadd8c04303c0aa2d112145c3627e2ebd026 Mon Sep 17 00:00:00 2001 From: Stephane Eranian Date: Tue, 1 Sep 2015 11:30:14 +0200 Subject: [PATCH 5994/7006] perf tools: Fix link time error with sample_reg_masks on non x86 This patch makes perf compile on non x86 platforms by defining a weak symbol for sample_reg_masks[] in util/perf_regs.c. The patch also moves the REG() and REG_END() macros into the util/per_regs.h header file. The macros are renamed to SMPL_REG/SMPL_REG_END to avoid clashes with other header files. Signed-off-by: Stephane Eranian Acked-by: Jiri Olsa Cc: Adrian Hunter Cc: Andi Kleen Cc: David Ahern Cc: Kan Liang Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1441099814-26783-1-git-send-email-eranian@google.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/util/perf_regs.c | 44 +++++++++++++--------------- tools/perf/util/perf_regs.c | 4 +++ tools/perf/util/perf_regs.h | 2 ++ 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/tools/perf/arch/x86/util/perf_regs.c b/tools/perf/arch/x86/util/perf_regs.c index 087c84ef52341..c5db14f36cc7a 100644 --- a/tools/perf/arch/x86/util/perf_regs.c +++ b/tools/perf/arch/x86/util/perf_regs.c @@ -1,30 +1,28 @@ #include "../../perf.h" #include "../../util/perf_regs.h" -#define REG(n, b) { .name = #n, .mask = 1ULL << (b) } -#define REG_END { .name = NULL } const struct sample_reg sample_reg_masks[] = { - REG(AX, PERF_REG_X86_AX), - REG(BX, PERF_REG_X86_BX), - REG(CX, PERF_REG_X86_CX), - REG(DX, PERF_REG_X86_DX), - REG(SI, PERF_REG_X86_SI), - REG(DI, PERF_REG_X86_DI), - REG(BP, PERF_REG_X86_BP), - REG(SP, PERF_REG_X86_SP), - REG(IP, PERF_REG_X86_IP), - REG(FLAGS, PERF_REG_X86_FLAGS), - REG(CS, PERF_REG_X86_CS), - REG(SS, PERF_REG_X86_SS), + SMPL_REG(AX, PERF_REG_X86_AX), + SMPL_REG(BX, PERF_REG_X86_BX), + SMPL_REG(CX, PERF_REG_X86_CX), + SMPL_REG(DX, PERF_REG_X86_DX), + SMPL_REG(SI, PERF_REG_X86_SI), + SMPL_REG(DI, PERF_REG_X86_DI), + SMPL_REG(BP, PERF_REG_X86_BP), + SMPL_REG(SP, PERF_REG_X86_SP), + SMPL_REG(IP, PERF_REG_X86_IP), + SMPL_REG(FLAGS, PERF_REG_X86_FLAGS), + SMPL_REG(CS, PERF_REG_X86_CS), + SMPL_REG(SS, PERF_REG_X86_SS), #ifdef HAVE_ARCH_X86_64_SUPPORT - REG(R8, PERF_REG_X86_R8), - REG(R9, PERF_REG_X86_R9), - REG(R10, PERF_REG_X86_R10), - REG(R11, PERF_REG_X86_R11), - REG(R12, PERF_REG_X86_R12), - REG(R13, PERF_REG_X86_R13), - REG(R14, PERF_REG_X86_R14), - REG(R15, PERF_REG_X86_R15), + SMPL_REG(R8, PERF_REG_X86_R8), + SMPL_REG(R9, PERF_REG_X86_R9), + SMPL_REG(R10, PERF_REG_X86_R10), + SMPL_REG(R11, PERF_REG_X86_R11), + SMPL_REG(R12, PERF_REG_X86_R12), + SMPL_REG(R13, PERF_REG_X86_R13), + SMPL_REG(R14, PERF_REG_X86_R14), + SMPL_REG(R15, PERF_REG_X86_R15), #endif - REG_END + SMPL_REG_END }; diff --git a/tools/perf/util/perf_regs.c b/tools/perf/util/perf_regs.c index 43168fb0d9a28..885e8ac839979 100644 --- a/tools/perf/util/perf_regs.c +++ b/tools/perf/util/perf_regs.c @@ -2,6 +2,10 @@ #include "perf_regs.h" #include "event.h" +const struct sample_reg __weak sample_reg_masks[] = { + SMPL_REG_END +}; + int perf_reg_value(u64 *valp, struct regs_dump *regs, int id) { int i, idx = 0; diff --git a/tools/perf/util/perf_regs.h b/tools/perf/util/perf_regs.h index 92c1fff2153eb..2984dcc54d67c 100644 --- a/tools/perf/util/perf_regs.h +++ b/tools/perf/util/perf_regs.h @@ -9,6 +9,8 @@ struct sample_reg { const char *name; uint64_t mask; }; +#define SMPL_REG(n, b) { .name = #n, .mask = 1ULL << (b) } +#define SMPL_REG_END { .name = NULL } extern const struct sample_reg sample_reg_masks[]; -- GitLab From 2dfb28e3410d775a687d429f5cadf88e795e7eb6 Mon Sep 17 00:00:00 2001 From: Naresh Kamboju Date: Mon, 31 Aug 2015 17:11:55 +0530 Subject: [PATCH 5995/7006] selftests/zram: must be run as root Adding new functionality check_prereqs() to check test must be run as root Signed-off-by: Naresh Kamboju Signed-off-by: Shuah Khan --- tools/testing/selftests/zram/zram.sh | 12 ++++++++++++ tools/testing/selftests/zram/zram01.sh | 1 + tools/testing/selftests/zram/zram02.sh | 1 + tools/testing/selftests/zram/zram_lib.sh | 10 ++++++++++ 4 files changed, 24 insertions(+) diff --git a/tools/testing/selftests/zram/zram.sh b/tools/testing/selftests/zram/zram.sh index 6ea4b6a5ccab6..20de9a7612692 100755 --- a/tools/testing/selftests/zram/zram.sh +++ b/tools/testing/selftests/zram/zram.sh @@ -1,6 +1,16 @@ #!/bin/bash TCID="zram.sh" +check_prereqs() +{ + local msg="skip all tests:" + + if [ $UID != 0 ]; then + echo $msg must be run as root >&2 + exit 0 + fi +} + run_zram () { echo "--------------------" echo "running zram tests" @@ -10,6 +20,8 @@ echo "" ./zram02.sh } +check_prereqs + # check zram module exists MODULE_PATH=/lib/modules/`uname -r`/kernel/drivers/block/zram/zram.ko if [ -f $MODULE_PATH ]; then diff --git a/tools/testing/selftests/zram/zram01.sh b/tools/testing/selftests/zram/zram01.sh index 2a2475d4b201a..b9566a6478a9c 100755 --- a/tools/testing/selftests/zram/zram01.sh +++ b/tools/testing/selftests/zram/zram01.sh @@ -79,6 +79,7 @@ zram_fill_fs() echo "zram compression ratio: $(echo "scale=2; $v / 100 " | bc):1: OK" } +check_prereqs zram_load zram_max_streams zram_compress_alg diff --git a/tools/testing/selftests/zram/zram02.sh b/tools/testing/selftests/zram/zram02.sh index 96e82dcc195b4..74569b883737f 100755 --- a/tools/testing/selftests/zram/zram02.sh +++ b/tools/testing/selftests/zram/zram02.sh @@ -37,6 +37,7 @@ zram_max_streams="2" zram_sizes="1048576" # 1M zram_mem_limits="1M" +check_prereqs zram_load zram_max_streams zram_set_disksizes diff --git a/tools/testing/selftests/zram/zram_lib.sh b/tools/testing/selftests/zram/zram_lib.sh index 3b6abf1942d72..424e68ed1487d 100755 --- a/tools/testing/selftests/zram/zram_lib.sh +++ b/tools/testing/selftests/zram/zram_lib.sh @@ -20,6 +20,16 @@ dev_mounted=-1 trap INT +check_prereqs() +{ + local msg="skip all tests:" + + if [ $UID != 0 ]; then + echo $msg must be run as root >&2 + exit 0 + fi +} + zram_cleanup() { echo "zram cleanup" -- GitLab From 7eba7d90d48217a97afc171a311b386bde965f39 Mon Sep 17 00:00:00 2001 From: Naresh Kamboju Date: Mon, 31 Aug 2015 17:11:56 +0530 Subject: [PATCH 5996/7006] selftests/zram: Makefile fix Do not override run_tests, The default rule will just run TEST_PROGS Signed-off-by: Naresh Kamboju Acked-by: Michael Ellerman Signed-off-by: Shuah Khan --- tools/testing/selftests/zram/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/tools/testing/selftests/zram/Makefile b/tools/testing/selftests/zram/Makefile index ec45513c73035..29d80346e3eb5 100644 --- a/tools/testing/selftests/zram/Makefile +++ b/tools/testing/selftests/zram/Makefile @@ -5,8 +5,5 @@ TEST_FILES := zram01.sh zram02.sh zram_lib.sh include ../lib.mk -run_tests: - @/bin/bash ./zram.sh - clean: $(RM) err.log -- GitLab From 4a6ac3044f1504fe4521efa7334095c9c9ceecfd Mon Sep 17 00:00:00 2001 From: Marc Zyngier Date: Tue, 1 Sep 2015 10:08:53 +0100 Subject: [PATCH 5997/7006] irqchip/GIC: Fix EOImode setting for non-DT/ACPI systems Non-DT/ACPI systems call directly into the GIC driver at init time. Turns out 0b996fd35957 ("irqchip/GIC: Convert to EOImode == 1") breaks old non firmware-driven platforms, as the driver only works out the capability of the platform on the DT/ACPI paths. Fix this thinko by forcing EOImode==0 on non-DT platforms, which are not capable of supporting a hypervisor anyway. Reported-and-tested-by: Guenter Roeck Signed-off-by: Marc Zyngier Cc: linux-arm-kernel@lists.infradead.org Cc: Jason Cooper Link: http://lkml.kernel.org/r/1441098533-31523-1-git-send-email-marc.zyngier@arm.com Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-gic.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c index 72bf81b8abfcd..e6b7ed5379529 100644 --- a/drivers/irqchip/irq-gic.c +++ b/drivers/irqchip/irq-gic.c @@ -993,7 +993,7 @@ static const struct irq_domain_ops gic_irq_domain_ops = { .xlate = gic_irq_domain_xlate, }; -void __init gic_init_bases(unsigned int gic_nr, int irq_start, +static void __init __gic_init_bases(unsigned int gic_nr, int irq_start, void __iomem *dist_base, void __iomem *cpu_base, u32 percpu_offset, struct device_node *node) { @@ -1103,6 +1103,19 @@ void __init gic_init_bases(unsigned int gic_nr, int irq_start, gic_pm_init(gic); } +void __init gic_init_bases(unsigned int gic_nr, int irq_start, + void __iomem *dist_base, void __iomem *cpu_base, + u32 percpu_offset, struct device_node *node) +{ + /* + * Non-DT/ACPI systems won't run a hypervisor, so let's not + * bother with these... + */ + static_key_slow_dec(&supports_deactivate); + __gic_init_bases(gic_nr, irq_start, dist_base, cpu_base, + percpu_offset, node); +} + #ifdef CONFIG_OF static int gic_cnt __initdata; @@ -1137,7 +1150,7 @@ gic_of_init(struct device_node *node, struct device_node *parent) if (of_property_read_u32(node, "cpu-offset", &percpu_offset)) percpu_offset = 0; - gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); + __gic_init_bases(gic_cnt, -1, dist_base, cpu_base, percpu_offset, node); if (!gic_cnt) gic_init_physaddr(node); @@ -1265,7 +1278,7 @@ gic_v2_acpi_init(struct acpi_table_header *table) * as default IRQ domain to allow for GSI registration and GSI to IRQ * number translation (see acpi_register_gsi() and acpi_gsi_to_irq()). */ - gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); + __gic_init_bases(0, -1, dist_base, cpu_base, 0, NULL); irq_set_default_host(gic_data[0].domain); acpi_irq_model = ACPI_IRQ_MODEL_GIC; -- GitLab From 2ca495ac27d245513c11fed70591b1838250e240 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Tue, 1 Sep 2015 10:46:44 -0600 Subject: [PATCH 5998/7006] blk: Fix bio_io_vec index when checking bvec gaps Corrects a coding error from earlier patch. Reported by: Sagi Grimberg Signed-off-by: Keith Busch Fixes: 03100aada96f ("block: Replace SG_GAPS with new queue limits mask") Signed-off-by: Jens Axboe --- block/blk-merge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block/blk-merge.c b/block/blk-merge.c index 0e0d9fd01c409..b2625271a572b 100644 --- a/block/blk-merge.c +++ b/block/blk-merge.c @@ -488,7 +488,7 @@ static int req_gap_to_prev(struct request *req, struct bio *next) struct bio *prev = req->biotail; return bvec_gap_to_prev(req->q, &prev->bi_io_vec[prev->bi_vcnt - 1], - next->bi_io_vec[1].bv_offset); + next->bi_io_vec[0].bv_offset); } static int ll_merge_requests_fn(struct request_queue *q, struct request *req, -- GitLab From f984a7ce58ea9a12eca7f960bdf68124c8589b60 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 1 Sep 2015 13:40:53 -0400 Subject: [PATCH 5999/7006] nfsd: return CLID_INUSE for unexpected SETCLIENTID_CONFIRM case Somebody with a Solaris client was hitting this case. We haven't figured out why yet, and don't have a reproducer. Meanwhile Frank noticed that RFC 7530 actually recommends CLID_INUSE for this case. Unlikely to help the original reporter, but may as well fix it. Reported-by: Frank Filz Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 416f32e34a33c..08746ec1d44a5 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3111,10 +3111,11 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, /* * We try hard to give out unique clientid's, so if we get an * attempt to confirm the same clientid with a different cred, - * there's a bug somewhere. Let's charitably assume it's our - * bug. + * the client may be buggy; this should never happen. + * + * Nevertheless, RFC 7530 recommends INUSE for this case: */ - status = nfserr_serverfault; + status = nfserr_clid_inuse; if (unconf && !same_creds(&unconf->cl_cred, &rqstp->rq_cred)) goto out; if (conf && !same_creds(&conf->cl_cred, &rqstp->rq_cred)) -- GitLab From 972398fa0a5f47c6ee0bde4d6d24b29f90ec888d Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 1 Sep 2015 12:03:56 -0700 Subject: [PATCH 6000/7006] NFSv4.1/flexfiles: Fix freeing of mirrors Mirrors are now shared objects, so we should not be freeing them directly inside ff_layout_free_lseg(). We should already be doing the right thing in _ff_layout_free_lseg(), so just let it handle things. Also ensure that ff_layout_free_mirror() frees the RPC credential if it is set. Fixes: 28a0d72c6867 ("Add refcounting to struct nfs4_ff_layout_mirror") Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 61ccf1122494d..ee8e7013454f2 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -213,6 +213,8 @@ static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror) { ff_layout_remove_mirror(mirror); kfree(mirror->fh_versions); + if (mirror->cred) + put_rpccred(mirror->cred); nfs4_ff_layout_put_deviceid(mirror->mirror_ds); kfree(mirror); } @@ -525,21 +527,9 @@ static void ff_layout_free_lseg(struct pnfs_layout_segment *lseg) { struct nfs4_ff_layout_segment *fls = FF_LAYOUT_LSEG(lseg); - int i; dprintk("--> %s\n", __func__); - for (i = 0; i < fls->mirror_array_cnt; i++) { - if (fls->mirror_array[i]) { - nfs4_ff_layout_put_deviceid(fls->mirror_array[i]->mirror_ds); - fls->mirror_array[i]->mirror_ds = NULL; - if (fls->mirror_array[i]->cred) { - put_rpccred(fls->mirror_array[i]->cred); - fls->mirror_array[i]->cred = NULL; - } - } - } - if (lseg->pls_range.iomode == IOMODE_RW) { struct nfs4_flexfile_layout *ffl; struct inode *inode; -- GitLab From 9b8ff51822893e743eee09350c1928daa3ef503f Mon Sep 17 00:00:00 2001 From: David Ahern Date: Tue, 1 Sep 2015 14:26:35 -0600 Subject: [PATCH 6001/7006] net: Make table id type u32 A number of VRF patches used 'int' for table id. It should be u32 to be consistent with the rest of the stack. Fixes: 4e3c89920cd3a ("net: Introduce VRF related flags and helpers") 15be405eb2ea9 ("net: Add inet_addr lookup by table") 30bbaa1950055 ("net: Fix up inet_addr_type checks") 021dd3b8a142d ("net: Add routes to the table associated with the device") dc028da54ed35 ("inet: Move VRF table lookup to inlined function") f6d3c19274c74 ("net: FIB tracepoints") Signed-off-by: David Ahern Reviewed-by: Nikolay Aleksandrov Signed-off-by: David S. Miller --- include/net/route.h | 2 +- include/net/vrf.h | 24 ++++++++++++------------ include/trace/events/fib.h | 6 +++--- net/ipv4/af_inet.c | 2 +- net/ipv4/fib_frontend.c | 10 +++++----- net/ipv4/fib_semantics.c | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/include/net/route.h b/include/net/route.h index 395d79bb556cf..cc61cb95f0591 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -188,7 +188,7 @@ void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk); void ip_rt_send_redirect(struct sk_buff *skb); unsigned int inet_addr_type(struct net *net, __be32 addr); -unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id); +unsigned int inet_addr_type_table(struct net *net, __be32 addr, u32 tb_id); unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr); unsigned int inet_addr_type_dev_table(struct net *net, diff --git a/include/net/vrf.h b/include/net/vrf.h index 5bfb16237fd77..593e6094ddd40 100644 --- a/include/net/vrf.h +++ b/include/net/vrf.h @@ -66,9 +66,9 @@ static inline int vrf_master_ifindex(const struct net_device *dev) } /* called with rcu_read_lock */ -static inline int vrf_dev_table_rcu(const struct net_device *dev) +static inline u32 vrf_dev_table_rcu(const struct net_device *dev) { - int tb_id = 0; + u32 tb_id = 0; if (dev) { struct net_vrf_dev *vrf_ptr; @@ -80,9 +80,9 @@ static inline int vrf_dev_table_rcu(const struct net_device *dev) return tb_id; } -static inline int vrf_dev_table(const struct net_device *dev) +static inline u32 vrf_dev_table(const struct net_device *dev) { - int tb_id; + u32 tb_id; rcu_read_lock(); tb_id = vrf_dev_table_rcu(dev); @@ -91,10 +91,10 @@ static inline int vrf_dev_table(const struct net_device *dev) return tb_id; } -static inline int vrf_dev_table_ifindex(struct net *net, int ifindex) +static inline u32 vrf_dev_table_ifindex(struct net *net, int ifindex) { struct net_device *dev; - int tb_id = 0; + u32 tb_id = 0; if (!ifindex) return 0; @@ -111,9 +111,9 @@ static inline int vrf_dev_table_ifindex(struct net *net, int ifindex) } /* called with rtnl */ -static inline int vrf_dev_table_rtnl(const struct net_device *dev) +static inline u32 vrf_dev_table_rtnl(const struct net_device *dev) { - int tb_id = 0; + u32 tb_id = 0; if (dev) { struct net_vrf_dev *vrf_ptr; @@ -149,22 +149,22 @@ static inline int vrf_master_ifindex(const struct net_device *dev) return 0; } -static inline int vrf_dev_table_rcu(const struct net_device *dev) +static inline u32 vrf_dev_table_rcu(const struct net_device *dev) { return 0; } -static inline int vrf_dev_table(const struct net_device *dev) +static inline u32 vrf_dev_table(const struct net_device *dev) { return 0; } -static inline int vrf_dev_table_ifindex(struct net *net, int ifindex) +static inline u32 vrf_dev_table_ifindex(struct net *net, int ifindex) { return 0; } -static inline int vrf_dev_table_rtnl(const struct net_device *dev) +static inline u32 vrf_dev_table_rtnl(const struct net_device *dev) { return 0; } diff --git a/include/trace/events/fib.h b/include/trace/events/fib.h index acd1d22571a2d..833cfcb6750de 100644 --- a/include/trace/events/fib.h +++ b/include/trace/events/fib.h @@ -11,12 +11,12 @@ TRACE_EVENT(fib_table_lookup, - TP_PROTO(int tb_id, const struct flowi4 *flp), + TP_PROTO(u32 tb_id, const struct flowi4 *flp), TP_ARGS(tb_id, flp), TP_STRUCT__entry( - __field( int, tb_id ) + __field( u32, tb_id ) __field( int, oif ) __field( int, iif ) __field( __u8, tos ) @@ -43,7 +43,7 @@ TRACE_EVENT(fib_table_lookup, *p32 = flp->daddr; ), - TP_printk("table %d oif %d iif %d src %pI4 dst %pI4 tos %d scope %d flags %x", + TP_printk("table %u oif %d iif %d src %pI4 dst %pI4 tos %d scope %d flags %x", __entry->tb_id, __entry->oif, __entry->iif, __entry->src, __entry->dst, __entry->tos, __entry->scope, __entry->flags) diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 96773a2f95a7e..1d0c3adb6f349 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -428,7 +428,7 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct net *net = sock_net(sk); unsigned short snum; int chk_addr_ret; - int tb_id = RT_TABLE_LOCAL; + u32 tb_id = RT_TABLE_LOCAL; int err; /* If the socket has its own bind function then use it. (RAW) */ diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 4036c94dfbe14..6fcbd215cdbc5 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -213,7 +213,7 @@ void fib_flush_external(struct net *net) */ static inline unsigned int __inet_dev_addr_type(struct net *net, const struct net_device *dev, - __be32 addr, int tb_id) + __be32 addr, u32 tb_id) { struct flowi4 fl4 = { .daddr = addr }; struct fib_result res; @@ -240,7 +240,7 @@ static inline unsigned int __inet_dev_addr_type(struct net *net, return ret; } -unsigned int inet_addr_type_table(struct net *net, __be32 addr, int tb_id) +unsigned int inet_addr_type_table(struct net *net, __be32 addr, u32 tb_id) { return __inet_dev_addr_type(net, NULL, addr, tb_id); } @@ -255,7 +255,7 @@ EXPORT_SYMBOL(inet_addr_type); unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr) { - int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL; + u32 rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL; return __inet_dev_addr_type(net, dev, addr, rt_table); } @@ -268,7 +268,7 @@ unsigned int inet_addr_type_dev_table(struct net *net, const struct net_device *dev, __be32 addr) { - int rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL; + u32 rt_table = vrf_dev_table(dev) ? : RT_TABLE_LOCAL; return __inet_dev_addr_type(net, NULL, addr, rt_table); } @@ -803,7 +803,7 @@ out: static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) { struct net *net = dev_net(ifa->ifa_dev->dev); - int tb_id = vrf_dev_table_rtnl(ifa->ifa_dev->dev); + u32 tb_id = vrf_dev_table_rtnl(ifa->ifa_dev->dev); struct fib_table *tb; struct fib_config cfg = { .fc_protocol = RTPROT_KERNEL, diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index 992a9597daf80..064bd3caaa4f1 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -863,7 +863,7 @@ static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) { if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || fib_prefsrc != cfg->fc_dst) { - int tb_id = cfg->fc_table; + u32 tb_id = cfg->fc_table; if (tb_id == RT_TABLE_MAIN) tb_id = RT_TABLE_LOCAL; -- GitLab From 01a5ad827a36e36f45e1fdb96903ea115f759865 Mon Sep 17 00:00:00 2001 From: Yunlei He Date: Mon, 31 Aug 2015 17:15:10 +0800 Subject: [PATCH 6002/7006] f2fs: upset segment_info repair upset segment_info like this: 276000|161 0|0 4|70 3|0 3|0 0|0 0|91 4|0 4|232 4|39 276104|0 4|0 4|1 4|0 4|0 4|280 4|0 4|42 4|262 4|38 276204|179 4|89 4|39 4|24 4|0 4|96 4|3 4|428 4|0 4|118 276304|112 4|97 4|0 4|0 4|0 4|68 4|0 4|0 4|86 4|138 276404|0 4|0 0|166 5|39 4|101 0|111 Signed-off-by: Yunlei He Reviewed-by: Chao Yu Signed-off-by: Jaegeuk Kim --- fs/f2fs/super.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index cfe3f9579934f..f79478115d379 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -693,7 +693,7 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset) struct seg_entry *se = get_seg_entry(sbi, i); if ((i % 10) == 0) - seq_printf(seq, "%-5d", i); + seq_printf(seq, "%-10d", i); seq_printf(seq, "%d|%-3u", se->type, get_valid_blocks(sbi, i, 1)); if ((i % 10) == 9 || i == (total_segs - 1)) -- GitLab From b6c6aedcbcbacd7b0cb4b64ed5ac835bc1c60a03 Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 1 Sep 2015 09:36:05 -0400 Subject: [PATCH 6003/7006] phylib: fix device deletion order in mdiobus_unregister() commit 8b63ec1837fa ("phylib: Make PHYs children of their MDIO bus, not the bus' parent.") uncovered a problem in mdiobus_unregister() which leads to this warning when I reboot an APM Mustang (arm64) platform: WARNING: CPU: 7 PID: 4239 at fs/sysfs/group.c:224 sysfs_remove_group+0xa0/0xa4() sysfs group fffffe0000e07a10 not found for kobject 'xgene-mii-eth0:03' ... CPU: 7 PID: 4239 Comm: reboot Tainted: G E 4.2.0-0.18.el7.test15.aarch64 #1 Hardware name: AppliedMicro Mustang/Mustang, BIOS 1.1.0 Aug 26 2015 Call Trace: [] dump_backtrace+0x0/0x170 [] show_stack+0x20/0x2c [] dump_stack+0x78/0x9c [] warn_slowpath_common+0xa0/0xd8 [] warn_slowpath_fmt+0x74/0x88 [] sysfs_remove_group+0x9c/0xa4 [] dpm_sysfs_remove+0x5c/0x70 [] device_del+0x44/0x208 [] device_unregister+0x2c/0x7c [] mdiobus_unregister+0x48/0x94 [] xgene_enet_mdio_remove+0x28/0x44 [] xgene_enet_remove+0xd0/0xd8 [] xgene_enet_shutdown+0x2c/0x3c [] platform_drv_shutdown+0x24/0x40 [] device_shutdown+0xf0/0x1b4 [] kernel_restart_prepare+0x40/0x4c [] kernel_restart+0x1c/0x80 [] SyS_reboot+0x17c/0x250 The problem is that mdiobus_unregister() deletes the bus device before unregistering the phy devices on the bus. This wasn't a problem before because the phys were not children of the bus: /sys/devices/platform/APMC0D05:00/net/eth0/xgene-mii-eth0:03 /sys/devices/platform/APMC0D05:00/net/eth0/xgene-mii-eth0 But now that they are: /sys/devices/platform/APMC0D05:00/net/eth0/xgene-mii-eth0/xgene-mii-eth0:03 when mdiobus_unregister deletes the bus device, the phy subdirs are removed from sysfs also. So when the phys are unregistered afterward, we get the warning. This patch changes the order so that phys are unregistered before the bus device is deleted. Fixes: 8b63ec1837fa ("phylib: Make PHYs children of their MDIO bus, not the bus' parent.") Signed-off-by: Mark Salter Reviewed-by: Florian Fainelli Tested-by: Mark Langsdorf Signed-off-by: David S. Miller --- drivers/net/phy/mdio_bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 46a14cbb02154..02a4615b65f87 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -303,12 +303,12 @@ void mdiobus_unregister(struct mii_bus *bus) BUG_ON(bus->state != MDIOBUS_REGISTERED); bus->state = MDIOBUS_UNREGISTERED; - device_del(&bus->dev); for (i = 0; i < PHY_MAX_ADDR; i++) { if (bus->phy_map[i]) device_unregister(&bus->phy_map[i]->dev); bus->phy_map[i] = NULL; } + device_del(&bus->dev); } EXPORT_SYMBOL(mdiobus_unregister); -- GitLab From d3d11fe08ccc9bff174fc958722b5661f0932486 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Tue, 1 Sep 2015 18:07:41 +0200 Subject: [PATCH 6004/7006] tg3: Fix temperature reporting The temperature registers appear to report values in degrees Celsius while the hwmon API mandates values to be exposed in millidegrees Celsius. Do the conversion so that the values reported by "sensors" are correct. Fixes: aed93e0bf493 ("tg3: Add hwmon support for temperature") Signed-off-by: Jean Delvare Cc: Prashant Sreedharan Cc: Michael Chan Cc: stable@vger.kernel.org [v3.6+] Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/tg3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index 73c934cf6c61c..79789d8e52da3 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c @@ -10757,7 +10757,7 @@ static ssize_t tg3_show_temp(struct device *dev, tg3_ape_scratchpad_read(tp, &temperature, attr->index, sizeof(temperature)); spin_unlock_bh(&tp->lock); - return sprintf(buf, "%u\n", temperature); + return sprintf(buf, "%u\n", temperature * 1000); } -- GitLab From e5276937ae6e654a811345f0716266f12e77bede Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:23 -0700 Subject: [PATCH 6005/7006] flow_dissector: Move skb related functions to skbuff.h Move the flow dissector functions that are specific to skbuffs into skbuff.h out of flow_dissector.h. This makes flow_dissector.h have no dependencies on skbuff.h. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 47 +++++++++++++++++++++++++++++++++ include/net/flow_dissector.h | 50 ------------------------------------ 2 files changed, 47 insertions(+), 50 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 989307f991dbf..8a697c673b581 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -945,6 +945,53 @@ skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) skb->hash = hash; } +void __skb_get_hash(struct sk_buff *skb); +u32 skb_get_poff(const struct sk_buff *skb); +u32 __skb_get_poff(const struct sk_buff *skb, void *data, + const struct flow_keys *keys, int hlen); +__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, + void *data, int hlen_proto); + +static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, + int thoff, u8 ip_proto) +{ + return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0); +} + +void skb_flow_dissector_init(struct flow_dissector *flow_dissector, + const struct flow_dissector_key *key, + unsigned int key_count); + +bool __skb_flow_dissect(const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + void *target_container, + void *data, __be16 proto, int nhoff, int hlen); + +static inline bool skb_flow_dissect(const struct sk_buff *skb, + struct flow_dissector *flow_dissector, + void *target_container) +{ + return __skb_flow_dissect(skb, flow_dissector, target_container, + NULL, 0, 0, 0); +} + +static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, + struct flow_keys *flow) +{ + memset(flow, 0, sizeof(*flow)); + return __skb_flow_dissect(skb, &flow_keys_dissector, flow, + NULL, 0, 0, 0); +} + +static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, + void *data, __be16 proto, + int nhoff, int hlen) +{ + memset(flow, 0, sizeof(*flow)); + return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, + data, proto, nhoff, hlen); +} + static inline __u32 skb_get_hash(struct sk_buff *skb) { if (!skb->l4_hash && !skb->sw_hash) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 1a8c224199360..6777a84c6f94c 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -2,7 +2,6 @@ #define _NET_FLOW_DISSECTOR_H #include -#include #include #include @@ -134,23 +133,6 @@ struct flow_dissector { unsigned short int offset[FLOW_DISSECTOR_KEY_MAX]; }; -void skb_flow_dissector_init(struct flow_dissector *flow_dissector, - const struct flow_dissector_key *key, - unsigned int key_count); - -bool __skb_flow_dissect(const struct sk_buff *skb, - struct flow_dissector *flow_dissector, - void *target_container, - void *data, __be16 proto, int nhoff, int hlen); - -static inline bool skb_flow_dissect(const struct sk_buff *skb, - struct flow_dissector *flow_dissector, - void *target_container) -{ - return __skb_flow_dissect(skb, flow_dissector, target_container, - NULL, 0, 0, 0); -} - struct flow_keys { struct flow_dissector_key_control control; #define FLOW_KEYS_HASH_START_FIELD basic @@ -170,38 +152,6 @@ __be32 flow_get_u32_dst(const struct flow_keys *flow); extern struct flow_dissector flow_keys_dissector; extern struct flow_dissector flow_keys_buf_dissector; -static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, - struct flow_keys *flow) -{ - memset(flow, 0, sizeof(*flow)); - return __skb_flow_dissect(skb, &flow_keys_dissector, flow, - NULL, 0, 0, 0); -} - -static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, - void *data, __be16 proto, - int nhoff, int hlen) -{ - memset(flow, 0, sizeof(*flow)); - return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, - data, proto, nhoff, hlen); -} - -__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, - void *data, int hlen_proto); - -static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, - int thoff, u8 ip_proto) -{ - return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0); -} - -u32 flow_hash_from_keys(struct flow_keys *keys); -void __skb_get_hash(struct sk_buff *skb); -u32 skb_get_poff(const struct sk_buff *skb); -u32 __skb_get_poff(const struct sk_buff *skb, void *data, - const struct flow_keys *keys, int hlen); - /* struct flow_keys_digest: * * This structure is used to hold a digest of the full flow keys. This is a -- GitLab From bcc83839ffdb063dd2b0370cd85c4f825761fc59 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:24 -0700 Subject: [PATCH 6006/7006] skbuff: Make __skb_set_sw_hash a general function Move __skb_set_sw_hash to skbuff.h and add __skb_set_hash which is a common method (between __skb_set_sw_hash and skb_set_hash) to set the hash in an skbuff. Also, move skb_clear_hash to be closer to __skb_set_hash. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 45 +++++++++++++++++++++++------------- include/net/flow_dissector.h | 5 ++++ net/core/flow_dissector.c | 18 +++++---------- 3 files changed, 40 insertions(+), 28 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 8a697c673b581..5d2c812e725b4 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -937,14 +937,40 @@ enum pkt_hash_types { PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */ }; -static inline void -skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) +static inline void skb_clear_hash(struct sk_buff *skb) { - skb->l4_hash = (type == PKT_HASH_TYPE_L4); + skb->hash = 0; skb->sw_hash = 0; + skb->l4_hash = 0; +} + +static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb) +{ + if (!skb->l4_hash) + skb_clear_hash(skb); +} + +static inline void +__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4) +{ + skb->l4_hash = is_l4; + skb->sw_hash = is_sw; skb->hash = hash; } +static inline void +skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) +{ + /* Used by drivers to set hash from HW */ + __skb_set_hash(skb, hash, false, type == PKT_HASH_TYPE_L4); +} + +static inline void +__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4) +{ + __skb_set_hash(skb, hash, true, is_l4); +} + void __skb_get_hash(struct sk_buff *skb); u32 skb_get_poff(const struct sk_buff *skb); u32 __skb_get_poff(const struct sk_buff *skb, void *data, @@ -1027,19 +1053,6 @@ static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) return skb->hash; } -static inline void skb_clear_hash(struct sk_buff *skb) -{ - skb->hash = 0; - skb->sw_hash = 0; - skb->l4_hash = 0; -} - -static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb) -{ - if (!skb->l4_hash) - skb_clear_hash(skb); -} - static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from) { to->hash = from->hash; diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 6777a84c6f94c..af76c496f7db0 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -167,4 +167,9 @@ struct flow_keys_digest { void make_flow_keys_digest(struct flow_keys_digest *digest, const struct flow_keys *flow); +static inline bool flow_keys_have_l4(struct flow_keys *keys) +{ + return (keys->ports.ports || keys->tags.flow_label); +} + #endif diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 11e6540fa3869..151b6e48b81f1 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -590,15 +590,6 @@ void make_flow_keys_digest(struct flow_keys_digest *digest, } EXPORT_SYMBOL(make_flow_keys_digest); -static inline void __skb_set_sw_hash(struct sk_buff *skb, u32 hash, - struct flow_keys *keys) -{ - if (keys->ports.ports) - skb->l4_hash = 1; - skb->sw_hash = 1; - skb->hash = hash; -} - /** * __skb_get_hash: calculate a flow hash * @skb: sk_buff to calculate flow hash from @@ -619,7 +610,8 @@ void __skb_get_hash(struct sk_buff *skb) if (!hash) return; - __skb_set_sw_hash(skb, hash, &keys); + __skb_set_sw_hash(skb, hash, + flow_keys_have_l4(&keys)); } EXPORT_SYMBOL(__skb_get_hash); @@ -648,7 +640,8 @@ __u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) keys.tags.flow_label = (__force u32)fl6->flowlabel; keys.basic.ip_proto = fl6->flowi6_proto; - __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), &keys); + __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), + flow_keys_have_l4(&keys)); return skb->hash; } @@ -668,7 +661,8 @@ __u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) keys.keyid.keyid = fl4->fl4_gre_key; keys.basic.ip_proto = fl4->flowi4_proto; - __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), &keys); + __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), + flow_keys_have_l4(&keys)); return skb->hash; } -- GitLab From c6cc1ca7f4d70cbb3ea3a5ca163c5dabaf155cdb Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:25 -0700 Subject: [PATCH 6007/7006] flowi: Abstract out functions to get flow hash based on flowi Create __get_hash_from_flowi6 and __get_hash_from_flowi4 to get the flow keys and hash based on flowi structures. These are called by __skb_get_hash_flowi6 and __skb_get_hash_flowi4. Also, created get_hash_from_flowi6 and get_hash_from_flowi4 which can be called when just the hash value for a flowi is needed. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 16 ++++++++++++---- include/net/flow.h | 19 +++++++++++++++++++ include/net/flow_dissector.h | 2 ++ net/core/flow.c | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 5d2c812e725b4..bbe41bccfc5f2 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1030,8 +1030,12 @@ __u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6); static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) { - if (!skb->l4_hash && !skb->sw_hash) - __skb_get_hash_flowi6(skb, fl6); + if (!skb->l4_hash && !skb->sw_hash) { + struct flow_keys keys; + + __skb_set_sw_hash(skb, __get_hash_from_flowi6(fl6, &keys), + flow_keys_have_l4(&keys)); + } return skb->hash; } @@ -1040,8 +1044,12 @@ __u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl); static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) { - if (!skb->l4_hash && !skb->sw_hash) - __skb_get_hash_flowi4(skb, fl4); + if (!skb->l4_hash && !skb->sw_hash) { + struct flow_keys keys; + + __skb_set_sw_hash(skb, __get_hash_from_flowi4(fl4, &keys), + flow_keys_have_l4(&keys)); + } return skb->hash; } diff --git a/include/net/flow.h b/include/net/flow.h index 9e0297c4c11da..dafe97c3c048b 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -10,6 +10,7 @@ #include #include #include +#include /* * ifindex generation is per-net namespace, and loopback is @@ -243,4 +244,22 @@ void flow_cache_flush(struct net *net); void flow_cache_flush_deferred(struct net *net); extern atomic_t flow_cache_genid; +__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys); + +static inline __u32 get_hash_from_flowi6(struct flowi6 *fl6) +{ + struct flow_keys keys; + + return __get_hash_from_flowi6(fl6, &keys); +} + +__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys); + +static inline __u32 get_hash_from_flowi4(struct flowi4 *fl4) +{ + struct flow_keys keys; + + return __get_hash_from_flowi4(fl4, &keys); +} + #endif diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index af76c496f7db0..74fe160f0b057 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -172,4 +172,6 @@ static inline bool flow_keys_have_l4(struct flow_keys *keys) return (keys->ports.ports || keys->tags.flow_label); } +u32 flow_hash_from_keys(struct flow_keys *keys); + #endif diff --git a/net/core/flow.c b/net/core/flow.c index 1033725be40bd..61930bb0eb595 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -509,3 +510,38 @@ void flow_cache_fini(struct net *net) fc->percpu = NULL; } EXPORT_SYMBOL(flow_cache_fini); + +__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys) +{ + memset(keys, 0, sizeof(*keys)); + + memcpy(&keys->addrs.v6addrs.src, &fl6->saddr, + sizeof(keys->addrs.v6addrs.src)); + memcpy(&keys->addrs.v6addrs.dst, &fl6->daddr, + sizeof(keys->addrs.v6addrs.dst)); + keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; + keys->ports.src = fl6->fl6_sport; + keys->ports.dst = fl6->fl6_dport; + keys->keyid.keyid = fl6->fl6_gre_key; + keys->tags.flow_label = (__force u32)fl6->flowlabel; + keys->basic.ip_proto = fl6->flowi6_proto; + + return flow_hash_from_keys(keys); +} +EXPORT_SYMBOL(__get_hash_from_flowi6); + +__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys) +{ + memset(keys, 0, sizeof(*keys)); + + keys->addrs.v4addrs.src = fl4->saddr; + keys->addrs.v4addrs.dst = fl4->daddr; + keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + keys->ports.src = fl4->fl4_sport; + keys->ports.dst = fl4->fl4_dport; + keys->keyid.keyid = fl4->fl4_gre_key; + keys->basic.ip_proto = fl4->flowi4_proto; + + return flow_hash_from_keys(keys); +} +EXPORT_SYMBOL(__get_hash_from_flowi4); -- GitLab From a6e544b0a88b53114bfa5a57e21b7be7a8dfc9d0 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:26 -0700 Subject: [PATCH 6008/7006] flow_dissector: Jump to exit code in __skb_flow_dissect Instead of returning immediately (on a parsing failure for instance) we jump to cleanup code. This always sets protocol values in key_control (even on a failure there is still valid information in the key_tags that was set before the problem was hit). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 51 +++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 151b6e48b81f1..22f3d768b4592 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -130,6 +130,7 @@ bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector_key_tags *key_tags; struct flow_dissector_key_keyid *key_keyid; u8 ip_proto = 0; + bool ret = false; if (!data) { data = skb->data; @@ -171,7 +172,7 @@ again: ip: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); if (!iph || iph->ihl < 5) - return false; + goto out_bad; nhoff += iph->ihl * 4; ip_proto = iph->protocol; @@ -197,7 +198,7 @@ ip: ipv6: iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); if (!iph) - return false; + goto out_bad; ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); @@ -234,7 +235,7 @@ ipv6: vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), data, hlen, &_vlan); if (!vlan) - return false; + goto out_bad; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_VLANID)) { @@ -256,7 +257,7 @@ ipv6: } *hdr, _hdr; hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; + goto out_bad; proto = hdr->proto; nhoff += PPPOE_SES_HLEN; switch (proto) { @@ -265,7 +266,7 @@ ipv6: case htons(PPP_IPV6): goto ipv6; default: - return false; + goto out_bad; } } case htons(ETH_P_TIPC): { @@ -275,9 +276,7 @@ ipv6: } *hdr, _hdr; hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; - key_basic->n_proto = proto; - key_control->thoff = (u16)nhoff; + goto out_bad; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_TIPC_ADDRS)) { @@ -287,7 +286,7 @@ ipv6: key_addrs->tipcaddrs.srcnode = hdr->srcnode; key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC_ADDRS; } - return true; + goto out_good; } case htons(ETH_P_MPLS_UC): @@ -297,7 +296,7 @@ mpls: hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; + goto out_bad; if ((ntohl(hdr[0].entry) & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT == MPLS_LABEL_ENTROPY) { @@ -310,21 +309,17 @@ mpls: htonl(MPLS_LS_LABEL_MASK); } - key_basic->n_proto = proto; - key_basic->ip_proto = ip_proto; - key_control->thoff = (u16)nhoff; - - return true; + goto out_good; } - return true; + goto out_good; } case htons(ETH_P_FCOE): key_control->thoff = (u16)(nhoff + FCOE_HEADER_LEN); /* fall through */ default: - return false; + goto out_bad; } ip_proto_again: @@ -337,7 +332,7 @@ ip_proto_again: hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); if (!hdr) - return false; + goto out_bad; /* * Only look inside GRE if version zero and no * routing @@ -357,7 +352,7 @@ ip_proto_again: data, hlen, &_keyid); if (!keyid) - return false; + goto out_bad; if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_GRE_KEYID)) { @@ -378,7 +373,7 @@ ip_proto_again: sizeof(_eth), data, hlen, &_eth); if (!eth) - return false; + goto out_bad; proto = eth->h_proto; nhoff += sizeof(*eth); } @@ -395,7 +390,7 @@ ip_proto_again: opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr), data, hlen, &_opthdr); if (!opthdr) - return false; + goto out_bad; ip_proto = opthdr[0]; nhoff += (opthdr[1] + 1) << 3; @@ -415,10 +410,6 @@ ip_proto_again: break; } - key_basic->n_proto = proto; - key_basic->ip_proto = ip_proto; - key_control->thoff = (u16)nhoff; - if (skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_PORTS)) { key_ports = skb_flow_dissector_target(flow_dissector, @@ -428,7 +419,15 @@ ip_proto_again: data, hlen); } - return true; +out_good: + ret = true; + +out_bad: + key_basic->n_proto = proto; + key_basic->ip_proto = ip_proto; + key_control->thoff = (u16)nhoff; + + return ret; } EXPORT_SYMBOL(__skb_flow_dissect); -- GitLab From cd79a2382aa5dcefa6e21a7c59bb1bb19e53b74d Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:27 -0700 Subject: [PATCH 6009/7006] flow_dissector: Add flags argument to skb_flow_dissector functions The flags argument will allow control of the dissection process (for instance whether to parse beyond L3). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- drivers/net/bonding/bond_main.c | 2 +- drivers/net/ethernet/cisco/enic/enic_clsf.c | 2 +- drivers/net/hyperv/netvsc_drv.c | 2 +- include/linux/skbuff.h | 19 +++++++++++-------- net/core/flow_dissector.c | 7 ++++--- net/ethernet/eth.c | 2 +- net/sched/cls_flow.c | 2 +- net/sched/cls_flower.c | 2 +- net/sched/sch_choke.c | 4 ++-- 9 files changed, 23 insertions(+), 19 deletions(-) diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index 06e2d01f0b4e1..771a449d2f563 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -3095,7 +3095,7 @@ static bool bond_flow_dissect(struct bonding *bond, struct sk_buff *skb, int noff, proto = -1; if (bond->params.xmit_policy > BOND_XMIT_POLICY_LAYER23) - return skb_flow_dissect_flow_keys(skb, fk); + return skb_flow_dissect_flow_keys(skb, fk, 0); fk->ports.ports = 0; noff = skb_network_offset(skb); diff --git a/drivers/net/ethernet/cisco/enic/enic_clsf.c b/drivers/net/ethernet/cisco/enic/enic_clsf.c index d106186f4f4ab..3c677ed3c29e7 100644 --- a/drivers/net/ethernet/cisco/enic/enic_clsf.c +++ b/drivers/net/ethernet/cisco/enic/enic_clsf.c @@ -177,7 +177,7 @@ int enic_rx_flow_steer(struct net_device *dev, const struct sk_buff *skb, int res, i; enic = netdev_priv(dev); - res = skb_flow_dissect_flow_keys(skb, &keys); + res = skb_flow_dissect_flow_keys(skb, &keys, 0); if (!res || keys.basic.n_proto != htons(ETH_P_IP) || (keys.basic.ip_proto != IPPROTO_TCP && keys.basic.ip_proto != IPPROTO_UDP)) diff --git a/drivers/net/hyperv/netvsc_drv.c b/drivers/net/hyperv/netvsc_drv.c index 2990024b90f97..409b48e1e589d 100644 --- a/drivers/net/hyperv/netvsc_drv.c +++ b/drivers/net/hyperv/netvsc_drv.c @@ -239,7 +239,7 @@ static bool netvsc_set_hash(u32 *hash, struct sk_buff *skb) struct flow_keys flow; int data_len; - if (!skb_flow_dissect_flow_keys(skb, &flow) || + if (!skb_flow_dissect_flow_keys(skb, &flow, 0) || !(flow.basic.n_proto == htons(ETH_P_IP) || flow.basic.n_proto == htons(ETH_P_IPV6))) return false; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index bbe41bccfc5f2..9e62687c70f32 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -991,31 +991,34 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, - void *data, __be16 proto, int nhoff, int hlen); + void *data, __be16 proto, int nhoff, int hlen, + unsigned int flags); static inline bool skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, - void *target_container) + void *target_container, unsigned int flags) { return __skb_flow_dissect(skb, flow_dissector, target_container, - NULL, 0, 0, 0); + NULL, 0, 0, 0, flags); } static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, - struct flow_keys *flow) + struct flow_keys *flow, + unsigned int flags) { memset(flow, 0, sizeof(*flow)); return __skb_flow_dissect(skb, &flow_keys_dissector, flow, - NULL, 0, 0, 0); + NULL, 0, 0, 0, flags); } static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, void *data, __be16 proto, - int nhoff, int hlen) + int nhoff, int hlen, + unsigned int flags) { memset(flow, 0, sizeof(*flow)); return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, - data, proto, nhoff, hlen); + data, proto, nhoff, hlen, flags); } static inline __u32 skb_get_hash(struct sk_buff *skb) @@ -2046,7 +2049,7 @@ static inline void skb_probe_transport_header(struct sk_buff *skb, if (skb_transport_header_was_set(skb)) return; - else if (skb_flow_dissect_flow_keys(skb, &keys)) + else if (skb_flow_dissect_flow_keys(skb, &keys, 0)) skb_set_transport_header(skb, keys.control.thoff); else skb_set_transport_header(skb, offset_hint); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 22f3d768b4592..c3d9807cb34ec 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -121,7 +121,8 @@ EXPORT_SYMBOL(__skb_flow_get_ports); bool __skb_flow_dissect(const struct sk_buff *skb, struct flow_dissector *flow_dissector, void *target_container, - void *data, __be16 proto, int nhoff, int hlen) + void *data, __be16 proto, int nhoff, int hlen, + unsigned int flags) { struct flow_dissector_key_control *key_control; struct flow_dissector_key_basic *key_basic; @@ -556,7 +557,7 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect_flow_keys(skb, keys)) + if (!skb_flow_dissect_flow_keys(skb, keys, 0)) return 0; return __flow_hash_from_keys(keys, keyval); @@ -726,7 +727,7 @@ u32 skb_get_poff(const struct sk_buff *skb) { struct flow_keys keys; - if (!skb_flow_dissect_flow_keys(skb, &keys)) + if (!skb_flow_dissect_flow_keys(skb, &keys, 0)) return 0; return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index 217127c3a3ef3..d850fdc828f93 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -132,7 +132,7 @@ u32 eth_get_headlen(void *data, unsigned int len) /* parse any remaining L2/L3 headers, check for L4 */ if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, - sizeof(*eth), len)) + sizeof(*eth), len, 0)) return max_t(u32, keys.control.thoff, sizeof(*eth)); /* parse for any L4 headers */ diff --git a/net/sched/cls_flow.c b/net/sched/cls_flow.c index bb2a0f529c1f5..536838b657bfc 100644 --- a/net/sched/cls_flow.c +++ b/net/sched/cls_flow.c @@ -301,7 +301,7 @@ static int flow_classify(struct sk_buff *skb, const struct tcf_proto *tp, keymask = f->keymask; if (keymask & FLOW_KEYS_NEEDED) - skb_flow_dissect_flow_keys(skb, &flow_keys); + skb_flow_dissect_flow_keys(skb, &flow_keys, 0); for (n = 0; n < f->nkeys; n++) { key = ffs(keymask) - 1; diff --git a/net/sched/cls_flower.c b/net/sched/cls_flower.c index 2f3d03f99487e..57692947ebbe6 100644 --- a/net/sched/cls_flower.c +++ b/net/sched/cls_flower.c @@ -129,7 +129,7 @@ static int fl_classify(struct sk_buff *skb, const struct tcf_proto *tp, * so do it rather here. */ skb_key.basic.n_proto = skb->protocol; - skb_flow_dissect(skb, &head->dissector, &skb_key); + skb_flow_dissect(skb, &head->dissector, &skb_key, 0); fl_set_masked_key(&skb_mkey, &skb_key, &head->mask); diff --git a/net/sched/sch_choke.c b/net/sched/sch_choke.c index 665bde07916b8..02bfd3d1c4f07 100644 --- a/net/sched/sch_choke.c +++ b/net/sched/sch_choke.c @@ -170,13 +170,13 @@ static bool choke_match_flow(struct sk_buff *skb1, if (!choke_skb_cb(skb1)->keys_valid) { choke_skb_cb(skb1)->keys_valid = 1; - skb_flow_dissect_flow_keys(skb1, &temp); + skb_flow_dissect_flow_keys(skb1, &temp, 0); make_flow_keys_digest(&choke_skb_cb(skb1)->keys, &temp); } if (!choke_skb_cb(skb2)->keys_valid) { choke_skb_cb(skb2)->keys_valid = 1; - skb_flow_dissect_flow_keys(skb2, &temp); + skb_flow_dissect_flow_keys(skb2, &temp, 0); make_flow_keys_digest(&choke_skb_cb(skb2)->keys, &temp); } -- GitLab From 807e165dc44fd93f9d378f861f0540a158d7343a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:28 -0700 Subject: [PATCH 6010/7006] flow_dissector: Add control/reporting of fragmentation Add an input flag to flow dissector on rather dissection should be attempted on a first fragment. Also add key_control flags to indicate that a packet is a fragment or first fragment. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 4 ++++ net/core/flow_dissector.c | 15 +++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 74fe160f0b057..34102270b0862 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -12,6 +12,8 @@ struct flow_dissector_key_control { u16 thoff; u16 addr_type; + u32 is_fragment:1; + u32 first_frag:1; }; /** @@ -122,6 +124,8 @@ enum flow_dissector_key_id { FLOW_DISSECTOR_KEY_MAX, }; +#define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) + struct flow_dissector_key { enum flow_dissector_key_id key_id; size_t offset; /* offset of struct flow_dissector_key_* diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index c3d9807cb34ec..7536a4669029f 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -177,8 +177,6 @@ ip: nhoff += iph->ihl * 4; ip_proto = iph->protocol; - if (ip_is_fragment(iph)) - ip_proto = 0; if (!skb_flow_dissector_uses_key(flow_dissector, FLOW_DISSECTOR_KEY_IPV4_ADDRS)) @@ -189,6 +187,19 @@ ip: memcpy(&key_addrs->v4addrs, &iph->saddr, sizeof(key_addrs->v4addrs)); key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + + if (ip_is_fragment(iph)) { + key_control->is_fragment = 1; + + if (iph->frag_off & htons(IP_OFFSET)) { + goto out_good; + } else { + key_control->first_frag = 1; + if (!(flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) + goto out_good; + } + } + break; } case htons(ETH_P_IPV6): { -- GitLab From b840f28b908da0239c8c5d9c8cae362ad21cda97 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:29 -0700 Subject: [PATCH 6011/7006] flow_dissector: Support IPv6 fragment header Parse NEXTHDR_FRAGMENT. When seen account for it in the fragment bits of key_control. Also, check if first fragment should be parsed. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 7536a4669029f..907de2f68b1fc 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -409,6 +409,31 @@ ip_proto_again: goto ip_proto_again; } + case NEXTHDR_FRAGMENT: { + struct frag_hdr _fh, *fh; + + if (proto != htons(ETH_P_IPV6)) + break; + + fh = __skb_header_pointer(skb, nhoff, sizeof(_fh), + data, hlen, &_fh); + + if (!fh) + goto out_bad; + + key_control->is_fragment = 1; + + nhoff += sizeof(_fh); + + if (!(fh->frag_off & htons(IP6_OFFSET))) { + key_control->first_frag = 1; + if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) { + ip_proto = fh->nexthdr; + goto ip_proto_again; + } + } + goto out_good; + } case IPPROTO_IPIP: proto = htons(ETH_P_IP); goto ip; -- GitLab From 8306b688f1a6621b9efe3b0d827e26750528b12a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:30 -0700 Subject: [PATCH 6012/7006] flow_dissector: Add flag to stop parsing at L3 Add an input flag to flow dissector on rather dissection should be stopped when an L3 packet is encountered. This would be useful if a caller just wanted to get IP addresses of the outermost header (e.g. to do an L3 hash). Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 1 + net/core/flow_dissector.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 34102270b0862..bb81e3b576e70 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -125,6 +125,7 @@ enum flow_dissector_key_id { }; #define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) +#define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) struct flow_dissector_key { enum flow_dissector_key_id key_id; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 907de2f68b1fc..94fd841f341f1 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -200,6 +200,9 @@ ip: } } + if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) + goto out_good; + break; } case htons(ETH_P_IPV6): { @@ -238,6 +241,9 @@ ipv6: } } + if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) + goto out_good; + break; } case htons(ETH_P_8021AD): -- GitLab From 872b1abb1ed47a691f465fb3d285f6cf6bcd8663 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:31 -0700 Subject: [PATCH 6013/7006] flow_dissector: Add flag to stop parsing when an IPv6 flow label is seen Add an input flag to flow dissector on rather dissection should be stopped when a flow label is encountered. Presumably, the flow label is derived from a sufficient hash of an inner transport packet so further dissection is not needed (that is ports are not included in the flow hash). Using the flow label instead of ports has the additional benefit that packet fragments should hash to same value as non-fragments for a flow (assuming that the same flow label is used). We set this flag by default in for skb_get_hash. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 1 + net/core/flow_dissector.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index bb81e3b576e70..66dbc3498efb2 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -126,6 +126,7 @@ enum flow_dissector_key_id { #define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) #define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) +#define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(2) struct flow_dissector_key { enum flow_dissector_key_id key_id; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 94fd841f341f1..094e34354627b 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -239,6 +239,8 @@ ipv6: target_container); key_tags->flow_label = ntohl(flow_label); } + if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) + goto out_good; } if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) @@ -599,7 +601,8 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect_flow_keys(skb, keys, 0)) + if (!skb_flow_dissect_flow_keys(skb, keys, + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) return 0; return __flow_hash_from_keys(keys, keyval); -- GitLab From 823b96939578eae67b9d6c0e33a39d6a7b6401e7 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:32 -0700 Subject: [PATCH 6014/7006] flow_dissector: Add control/reporting of encapsulation Add an input flag to flow dissector on rather dissection should stop when encapsulation is detected (IP/IP or GRE). Also, add a key_control flag that indicates encapsulation was encountered during the dissection. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 2 ++ net/core/flow_dissector.c | 15 +++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index 66dbc3498efb2..bddd1089dbce2 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -14,6 +14,7 @@ struct flow_dissector_key_control { u16 addr_type; u32 is_fragment:1; u32 first_frag:1; + u32 encapsulation:1; }; /** @@ -127,6 +128,7 @@ enum flow_dissector_key_id { #define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) #define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) #define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(2) +#define FLOW_DISSECTOR_F_STOP_AT_ENCAP BIT(3) struct flow_dissector_key { enum flow_dissector_key_id key_id; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 094e34354627b..8d890132e2d78 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -397,6 +397,11 @@ ip_proto_again: proto = eth->h_proto; nhoff += sizeof(*eth); } + + key_control->encapsulation = 1; + if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) + goto out_good; + goto again; } case NEXTHDR_HOP: @@ -444,9 +449,19 @@ ip_proto_again: } case IPPROTO_IPIP: proto = htons(ETH_P_IP); + + key_control->encapsulation = 1; + if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) + goto out_good; + goto ip; case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); + + key_control->encapsulation = 1; + if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) + goto out_good; + goto ipv6; case IPPROTO_MPLS: proto = htons(ETH_P_MPLS_UC); -- GitLab From 6db61d79c1e1b2346e2142d6c950a8d2e8380b82 Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 09:24:33 -0700 Subject: [PATCH 6015/7006] flow_dissector: Ignore flow dissector return value from ___skb_get_hash In ___skb_get_hash ignore return value from skb_flow_dissect_flow_keys. A failure in that function likely means that there was a parse error, so we may as well use whatever fields were found before the error was hit. This is also good because it means we won't keep trying to derive the hash on subsequent calls to skb_get_hash for the same packet. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- net/core/flow_dissector.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 8d890132e2d78..b563339436d0c 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -616,9 +616,8 @@ EXPORT_SYMBOL(flow_hash_from_keys); static inline u32 ___skb_get_hash(const struct sk_buff *skb, struct flow_keys *keys, u32 keyval) { - if (!skb_flow_dissect_flow_keys(skb, keys, - FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) - return 0; + skb_flow_dissect_flow_keys(skb, keys, + FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); return __flow_hash_from_keys(keys, keyval); } @@ -662,15 +661,10 @@ EXPORT_SYMBOL(make_flow_keys_digest); void __skb_get_hash(struct sk_buff *skb) { struct flow_keys keys; - u32 hash; __flow_hash_secret_init(); - hash = ___skb_get_hash(skb, &keys, hashrnd); - if (!hash) - return; - - __skb_set_sw_hash(skb, hash, + __skb_set_sw_hash(skb, ___skb_get_hash(skb, &keys, hashrnd), flow_keys_have_l4(&keys)); } EXPORT_SYMBOL(__skb_get_hash); -- GitLab From 388ef16640cefd202daa723fba02e7c0266f8454 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 1 Sep 2015 03:31:33 -0700 Subject: [PATCH 6016/7006] NFSv4.1/flexfiles: Fix incorrect usage of pnfs_generic_mark_devid_invalid() Unlike the files layout, flexfiles does not test for the NFS_DEVICEID_INVALID flag. Instead it relies on NFS_DEVICEID_UNAVAILABLE. Fix is to replace with nfs4_mark_deviceid_unavailable(). Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index b28fa4cbea526..883d35c867788 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -344,7 +344,7 @@ nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx) __func__, mirror_idx); if (mirror && mirror->mirror_ds) { devid = &mirror->mirror_ds->id_node; - pnfs_generic_mark_devid_invalid(devid); + nfs4_mark_deviceid_unavailable(devid); } goto out; } @@ -374,7 +374,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, __func__, ds_idx); if (mirror && mirror->mirror_ds) { devid = &mirror->mirror_ds->id_node; - pnfs_generic_mark_devid_invalid(devid); + nfs4_mark_deviceid_unavailable(devid); } goto out; } -- GitLab From 81d6dc8b3431d298abaef11d8bc64646fc691618 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 1 Sep 2015 02:49:44 -0700 Subject: [PATCH 6017/7006] NFSv4.1/flexfiles: RW layouts are valid only if all mirrors are valid Unlike read layouts, the writeable layout cannot fall back to using only one of the mirrors. It need to write to all of them. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 30 +++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index 883d35c867788..b6c21e9fa0026 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -528,11 +528,11 @@ int ff_layout_encode_ds_ioerr(struct nfs4_flexfile_layout *flo, return 0; } -bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg) +static bool ff_read_layout_has_available_ds(struct pnfs_layout_segment *lseg) { struct nfs4_ff_layout_mirror *mirror; struct nfs4_deviceid_node *devid; - int idx; + u32 idx; for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) { mirror = FF_LAYOUT_COMP(lseg, idx); @@ -546,6 +546,32 @@ bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg) return false; } +static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg) +{ + struct nfs4_ff_layout_mirror *mirror; + struct nfs4_deviceid_node *devid; + u32 idx; + + for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) { + mirror = FF_LAYOUT_COMP(lseg, idx); + if (!mirror || !mirror->mirror_ds) + return false; + devid = &mirror->mirror_ds->id_node; + if (ff_layout_test_devid_unavailable(devid)) + return false; + } + + return FF_LAYOUT_MIRROR_COUNT(lseg) != 0; +} + +bool ff_layout_has_available_ds(struct pnfs_layout_segment *lseg) +{ + if (lseg->pls_range.iomode == IOMODE_READ) + return ff_read_layout_has_available_ds(lseg); + /* Note: RW layout needs all mirrors available */ + return ff_rw_layout_has_available_ds(lseg); +} + module_param(dataserver_retrans, uint, 0644); MODULE_PARM_DESC(dataserver_retrans, "The number of times the NFSv4.1 client " "retries a request before it attempts further " -- GitLab From 889d94d49a3cbcbc8c8d07208549fa614d33da76 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Tue, 1 Sep 2015 00:58:24 -0700 Subject: [PATCH 6018/7006] NFSv4.1/flexfiles: Mark layout for return if the mirrors are invalid If a read-write layout has an invalid mirror, then we should mark it as invalid, and return it. If a read-only layout has an invalid mirror, then mark it as invalid and check if there is still at least one valid mirror before we return it. Note: Also fix incorrect use of pnfs_generic_mark_devid_invalid(). We really want nfs4_mark_deviceid_unavailable(). Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayoutdev.c | 45 +++++++++++++++-------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c index b6c21e9fa0026..e125e55de86da 100644 --- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c +++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c @@ -172,6 +172,32 @@ out_err: return NULL; } +static void ff_layout_mark_devid_invalid(struct pnfs_layout_segment *lseg, + struct nfs4_deviceid_node *devid) +{ + nfs4_mark_deviceid_unavailable(devid); + if (!ff_layout_has_available_ds(lseg)) + pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, + lseg); +} + +static bool ff_layout_mirror_valid(struct pnfs_layout_segment *lseg, + struct nfs4_ff_layout_mirror *mirror) +{ + if (mirror == NULL || mirror->mirror_ds == NULL) { + pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, + lseg); + return false; + } + if (mirror->mirror_ds->ds == NULL) { + struct nfs4_deviceid_node *devid; + devid = &mirror->mirror_ds->id_node; + ff_layout_mark_devid_invalid(lseg, devid); + return false; + } + return true; +} + static u64 end_offset(u64 start, u64 len) { @@ -336,16 +362,10 @@ nfs4_ff_layout_select_ds_fh(struct pnfs_layout_segment *lseg, u32 mirror_idx) { struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, mirror_idx); struct nfs_fh *fh = NULL; - struct nfs4_deviceid_node *devid; - if (mirror == NULL || mirror->mirror_ds == NULL || - mirror->mirror_ds->ds == NULL) { - printk(KERN_ERR "NFS: %s: No data server for mirror offset index %d\n", + if (!ff_layout_mirror_valid(lseg, mirror)) { + pr_err_ratelimited("NFS: %s: No data server for mirror offset index %d\n", __func__, mirror_idx); - if (mirror && mirror->mirror_ds) { - devid = &mirror->mirror_ds->id_node; - nfs4_mark_deviceid_unavailable(devid); - } goto out; } @@ -368,14 +388,9 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx, unsigned int max_payload; rpc_authflavor_t flavor; - if (mirror == NULL || mirror->mirror_ds == NULL || - mirror->mirror_ds->ds == NULL) { - printk(KERN_ERR "NFS: %s: No data server for offset index %d\n", + if (!ff_layout_mirror_valid(lseg, mirror)) { + pr_err_ratelimited("NFS: %s: No data server for offset index %d\n", __func__, ds_idx); - if (mirror && mirror->mirror_ds) { - devid = &mirror->mirror_ds->id_node; - nfs4_mark_deviceid_unavailable(devid); - } goto out; } -- GitLab From 4a70316caef7d158445e672e146eb9f1b8c1aeee Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Mon, 31 Aug 2015 10:53:33 +0800 Subject: [PATCH 6019/7006] nfs: Fix truncated client owner id without proto type The length of "Linux NFSv4.0 " is 14, not 10. Without this patch, I get a truncated client owner id as, "Linux NFSv4.0 ::1/::1" With this patch, "Linux NFSv4.0 ::1/::1 tcp" Fixes: a319268891 ("nfs: make nfs4_init_nonuniform_client_string use a dynamically allocated buffer") Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 51c7164abd1ac..3f73539579e54 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5020,7 +5020,7 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp) return 0; retry: rcu_read_lock(); - len = 10 + strlen(clp->cl_ipaddr) + 1 + + len = 14 + strlen(clp->cl_ipaddr) + 1 + strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)) + 1 + strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO)) + -- GitLab From 4a3e5779cf6c6d557682b499c2190ad04c80c6fd Mon Sep 17 00:00:00 2001 From: Kinglong Mee Date: Mon, 31 Aug 2015 10:53:43 +0800 Subject: [PATCH 6020/7006] nfs: Remove unneeded checking of the return value from scnprintf The return value from scnprintf always less than the buffer length. So, result >= len always false. This patch removes those checking. int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) { int i; i = vsnprintf(buf, size, fmt, args); if (likely(i < size)) return i; if (size != 0) return size - 1; return 0; } Signed-off-by: Kinglong Mee Signed-off-by: Trond Myklebust --- fs/nfs/nfs4proc.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 3f73539579e54..693b903b48bdf 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -5014,11 +5014,10 @@ nfs4_init_nonuniform_client_string(struct nfs_client *clp) int result; size_t len; char *str; - bool retried = false; if (clp->cl_owner_id != NULL) return 0; -retry: + rcu_read_lock(); len = 14 + strlen(clp->cl_ipaddr) + 1 + strlen(rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)) + @@ -5046,14 +5045,6 @@ retry: rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_PROTO)); rcu_read_unlock(); - /* Did something change? */ - if (result >= len) { - kfree(str); - if (retried) - return -EINVAL; - retried = true; - goto retry; - } clp->cl_owner_id = str; return 0; } @@ -5085,10 +5076,6 @@ nfs4_init_uniquifier_client_string(struct nfs_client *clp) clp->rpc_ops->version, clp->cl_minorversion, nfs4_client_id_uniquifier, clp->cl_rpcclient->cl_nodename); - if (result >= len) { - kfree(str); - return -EINVAL; - } clp->cl_owner_id = str; return 0; } @@ -5124,10 +5111,6 @@ nfs4_init_uniform_client_string(struct nfs_client *clp) result = scnprintf(str, len, "Linux NFSv%u.%u %s", clp->rpc_ops->version, clp->cl_minorversion, clp->cl_rpcclient->cl_nodename); - if (result >= len) { - kfree(str); - return -EINVAL; - } clp->cl_owner_id = str; return 0; } -- GitLab From 92faef85613d6d56803ad6130f6daf4a803deddc Mon Sep 17 00:00:00 2001 From: Anjali Singhai Jain Date: Tue, 28 Jul 2015 13:02:00 -0400 Subject: [PATCH 6021/7006] i40e: Set defport behavior for the Main VSI when in promiscuous mode This fixes bugs where the port is not receiving multicast or VLAN tagged packets when in promiscuous mode. This can occur when a SW bridge is created on top of the device. This also fixes issues where the promiscuous behavior setting was not being preserved across a reset caused by features being enabled or disabled. We are using defport instead of doing a true promiscuous mode because we do not need to receive the SRIOV or VMDq VSI directed traffic which would suck up bandwidth and is really not intended for the SW bridge. In addition, with defport we get VLAN promiscuous behavior which is not possible from the VSI level promiscuous setting. Change-ID: Ie21985eac32d5af1c02e9d71c6430a90d5bab40f Signed-off-by: Anjali Singhai Jain Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/i40e/i40e.h | 1 + drivers/net/ethernet/intel/i40e/i40e_main.c | 37 ++++++++++++++++----- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h index 05df21c16c790..e7462793d48d4 100644 --- a/drivers/net/ethernet/intel/i40e/i40e.h +++ b/drivers/net/ethernet/intel/i40e/i40e.h @@ -372,6 +372,7 @@ struct i40e_pf { #ifdef CONFIG_DEBUG_FS struct dentry *i40e_dbg_pf; #endif /* CONFIG_DEBUG_FS */ + bool cur_promisc; u16 instance; /* A unique number per i40e_pf instance in the system */ diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c index a97f193382d79..851c1a159be8a 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_main.c +++ b/drivers/net/ethernet/intel/i40e/i40e_main.c @@ -1937,15 +1937,35 @@ int i40e_sync_vsi_filters(struct i40e_vsi *vsi) cur_promisc = (!!(vsi->current_netdev_flags & IFF_PROMISC) || test_bit(__I40E_FILTER_OVERFLOW_PROMISC, &vsi->state)); - ret = i40e_aq_set_vsi_unicast_promiscuous(&vsi->back->hw, + if (vsi->type == I40E_VSI_MAIN && pf->lan_veb != I40E_NO_VEB) { + /* set defport ON for Main VSI instead of true promisc + * this way we will get all unicast/multicast and VLAN + * promisc behavior but will not get VF or VMDq traffic + * replicated on the Main VSI. + */ + if (pf->cur_promisc != cur_promisc) { + pf->cur_promisc = cur_promisc; + i40e_do_reset_safe(pf, + BIT(__I40E_PF_RESET_REQUESTED)); + } + } else { + ret = i40e_aq_set_vsi_unicast_promiscuous( + &vsi->back->hw, vsi->seid, cur_promisc, NULL); - if (ret) - dev_info(&pf->pdev->dev, - "set uni promisc failed, err %s, aq_err %s\n", - i40e_stat_str(&pf->hw, ret), - i40e_aq_str(&pf->hw, - pf->hw.aq.asq_last_status)); + if (ret) + dev_info(&pf->pdev->dev, + "set unicast promisc failed, err %d, aq_err %d\n", + ret, pf->hw.aq.asq_last_status); + ret = i40e_aq_set_vsi_multicast_promiscuous( + &vsi->back->hw, + vsi->seid, + cur_promisc, NULL); + if (ret) + dev_info(&pf->pdev->dev, + "set multicast promisc failed, err %d, aq_err %d\n", + ret, pf->hw.aq.asq_last_status); + } ret = i40e_aq_set_vsi_broadcast(&vsi->back->hw, vsi->seid, cur_promisc, NULL); @@ -4001,6 +4021,7 @@ static void i40e_vsi_close(struct i40e_vsi *vsi) i40e_vsi_free_irq(vsi); i40e_vsi_free_tx_resources(vsi); i40e_vsi_free_rx_resources(vsi); + vsi->current_netdev_flags = 0; } /** @@ -9312,7 +9333,7 @@ void i40e_veb_release(struct i40e_veb *veb) static int i40e_add_veb(struct i40e_veb *veb, struct i40e_vsi *vsi) { struct i40e_pf *pf = veb->pf; - bool is_default = false; + bool is_default = veb->pf->cur_promisc; bool is_cloud = false; int ret; -- GitLab From bd8069ace513dd2741bc7177eeebc9a392451db1 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 10 Jun 2015 20:05:02 -0400 Subject: [PATCH 6022/7006] ixgbe: add new function to check for management presence This patch adds a support function that will indicate for the existence of management FW. Signed-off-by: Donald C Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c | 8 ++------ drivers/net/ethernet/intel/ixgbe/ixgbe_common.c | 15 +++++++++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_common.h | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index b1e364d26aa73..08fcf57a22ec0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -504,16 +504,12 @@ static enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw) **/ static void ixgbe_stop_mac_link_on_d3_82599(struct ixgbe_hw *hw) { - u32 autoc2_reg, fwsm; + u32 autoc2_reg; u16 ee_ctrl_2 = 0; hw->eeprom.ops.read(hw, IXGBE_EEPROM_CTRL_2, &ee_ctrl_2); - /* Check to see if MNG FW could be enabled */ - fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw)); - - if (((fwsm & IXGBE_FWSM_MODE_MASK) != IXGBE_FWSM_FW_MODE_PT) && - !hw->wol_enabled && + if (!ixgbe_mng_present(hw) && !hw->wol_enabled && ee_ctrl_2 & IXGBE_EEPROM_CCD_BIT) { autoc2_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC2); autoc2_reg |= IXGBE_AUTOC2_LINK_DISABLE_ON_D3_MASK; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 4c1c26732b67a..3f56a8080118e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -3905,3 +3905,18 @@ void ixgbe_enable_rx_generic(struct ixgbe_hw *hw) } } } + +/** ixgbe_mng_present - returns true when management capability is present + * @hw: pointer to hardware structure + **/ +bool ixgbe_mng_present(struct ixgbe_hw *hw) +{ + u32 fwsm; + + if (hw->mac.type < ixgbe_mac_82599EB) + return false; + + fwsm = IXGBE_READ_REG(hw, IXGBE_FWSM(hw)); + fwsm &= IXGBE_FWSM_MODE_MASK; + return fwsm == IXGBE_FWSM_FW_MODE_PT; +} diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h index ec015fed8fa7a..2f779f35dc4f5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.h @@ -113,6 +113,7 @@ s32 ixgbe_set_fw_drv_ver_generic(struct ixgbe_hw *hw, u8 maj, u8 min, s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, u32 length, u32 timeout, bool return_data); void ixgbe_clear_tx_pending(struct ixgbe_hw *hw); +bool ixgbe_mng_present(struct ixgbe_hw *hw); bool ixgbe_mng_enabled(struct ixgbe_hw *hw); void ixgbe_set_rxpba_generic(struct ixgbe_hw *hw, int num_pb, -- GitLab From b5529ef5be1f0a0089988ec51541aa9573e94476 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 10 Jun 2015 20:42:30 -0400 Subject: [PATCH 6023/7006] ixgbe: Assign set_phy_power dynamically where needed There are various reasons why this method may or may not need to be defined and some of these we don't know until runtime. So we will set the value in get_invariants. Signed-off-by: Donald C Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c | 5 +++++ drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 18 ++++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c index 032a5870abd11..4e758435ece87 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c @@ -54,6 +54,11 @@ enum ixgbe_media_type ixgbe_get_media_type_X540(struct ixgbe_hw *hw) s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + + /* set_phy_power was set by default to NULL */ + if (!ixgbe_mng_present(hw)) + phy->ops.set_phy_power = ixgbe_set_copper_phy_power; mac->mcft_size = IXGBE_X540_MC_TBL_SIZE; mac->vft_size = IXGBE_X540_VFT_TBL_SIZE; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 7581da13e92a3..662d2e8962862 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -26,6 +26,20 @@ #include "ixgbe_common.h" #include "ixgbe_phy.h" +static s32 ixgbe_get_invariants_X550_x(struct ixgbe_hw *hw) +{ + struct ixgbe_mac_info *mac = &hw->mac; + struct ixgbe_phy_info *phy = &hw->phy; + + /* Start with X540 invariants, since so simular */ + ixgbe_get_invariants_X540(hw); + + if (mac->ops.get_media_type(hw) != ixgbe_media_type_copper) + phy->ops.set_phy_power = NULL; + + return 0; +} + /** ixgbe_setup_mux_ctl - Setup ESDP register for I2C mux control * @hw: pointer to hardware structure **/ @@ -1855,7 +1869,7 @@ static struct ixgbe_eeprom_operations eeprom_ops_X550EM_x = { .read_reg = &ixgbe_read_phy_reg_generic, \ .write_reg = &ixgbe_write_phy_reg_generic, \ .setup_link = &ixgbe_setup_phy_link_generic, \ - .set_phy_power = &ixgbe_set_copper_phy_power, \ + .set_phy_power = NULL, \ .check_overtemp = &ixgbe_tn_check_overtemp, \ .get_firmware_version = &ixgbe_get_phy_firmware_version_generic, @@ -1893,7 +1907,7 @@ struct ixgbe_info ixgbe_X550_info = { struct ixgbe_info ixgbe_X550EM_x_info = { .mac = ixgbe_mac_X550EM_x, - .get_invariants = &ixgbe_get_invariants_X540, + .get_invariants = &ixgbe_get_invariants_X550_x, .mac_ops = &mac_ops_X550EM_x, .eeprom_ops = &eeprom_ops_X550EM_x, .phy_ops = &phy_ops_X550EM_x, -- GitLab From d490d15877b2e6fc2d800ea232a0eca54cf4592c Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Thu, 11 Jun 2015 11:02:20 -0700 Subject: [PATCH 6024/7006] ixgbe: Check whether FDIRCMD writes actually complete Wait up to about 100 us for FDIRCMD writes to complete and return failure indications. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 63 ++++++++++++------- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 + 2 files changed, 40 insertions(+), 24 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index 08fcf57a22ec0..d91044297062f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2014 Intel Corporation. + Copyright(c) 1999 - 2015 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -1241,6 +1241,25 @@ mac_reset_top: return status; } +/** + * ixgbe_fdir_check_cmd_complete - poll to check whether FDIRCMD is complete + * @hw: pointer to hardware structure + * @fdircmd: current value of FDIRCMD register + */ +static s32 ixgbe_fdir_check_cmd_complete(struct ixgbe_hw *hw, u32 *fdircmd) +{ + int i; + + for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) { + *fdircmd = IXGBE_READ_REG(hw, IXGBE_FDIRCMD); + if (!(*fdircmd & IXGBE_FDIRCMD_CMD_MASK)) + return 0; + udelay(10); + } + + return IXGBE_ERR_FDIR_CMD_INCOMPLETE; +} + /** * ixgbe_reinit_fdir_tables_82599 - Reinitialize Flow Director tables. * @hw: pointer to hardware structure @@ -1249,6 +1268,8 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) { int i; u32 fdirctrl = IXGBE_READ_REG(hw, IXGBE_FDIRCTRL); + u32 fdircmd; + s32 err; fdirctrl &= ~IXGBE_FDIRCTRL_INIT_DONE; @@ -1256,15 +1277,10 @@ s32 ixgbe_reinit_fdir_tables_82599(struct ixgbe_hw *hw) * Before starting reinitialization process, * FDIRCMD.CMD must be zero. */ - for (i = 0; i < IXGBE_FDIRCMD_CMD_POLL; i++) { - if (!(IXGBE_READ_REG(hw, IXGBE_FDIRCMD) & - IXGBE_FDIRCMD_CMD_MASK)) - break; - udelay(10); - } - if (i >= IXGBE_FDIRCMD_CMD_POLL) { - hw_dbg(hw, "Flow Director previous command isn't complete, aborting table re-initialization.\n"); - return IXGBE_ERR_FDIR_REINIT_FAILED; + err = ixgbe_fdir_check_cmd_complete(hw, &fdircmd); + if (err) { + hw_dbg(hw, "Flow Director previous command did not complete, aborting table re-initialization.\n"); + return err; } IXGBE_WRITE_REG(hw, IXGBE_FDIRFREE, 0); @@ -1754,6 +1770,7 @@ s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, u16 soft_id, u8 queue) { u32 fdirport, fdirvlan, fdirhash, fdircmd; + s32 err; /* currently IPv6 is not supported, must be programmed with 0 */ IXGBE_WRITE_REG_BE32(hw, IXGBE_FDIRSIPv6(0), @@ -1802,6 +1819,11 @@ s32 ixgbe_fdir_write_perfect_filter_82599(struct ixgbe_hw *hw, fdircmd |= (u32)input->formatted.vm_pool << IXGBE_FDIRCMD_VT_POOL_SHIFT; IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, fdircmd); + err = ixgbe_fdir_check_cmd_complete(hw, &fdircmd); + if (err) { + hw_dbg(hw, "Flow Director command did not complete!\n"); + return err; + } return 0; } @@ -1811,9 +1833,8 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, u16 soft_id) { u32 fdirhash; - u32 fdircmd = 0; - u32 retry_count; - s32 err = 0; + u32 fdircmd; + s32 err; /* configure FDIRHASH register */ fdirhash = input->formatted.bkt_hash; @@ -1826,18 +1847,12 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, /* Query if filter is present */ IXGBE_WRITE_REG(hw, IXGBE_FDIRCMD, IXGBE_FDIRCMD_CMD_QUERY_REM_FILT); - for (retry_count = 10; retry_count; retry_count--) { - /* allow 10us for query to process */ - udelay(10); - /* verify query completed successfully */ - fdircmd = IXGBE_READ_REG(hw, IXGBE_FDIRCMD); - if (!(fdircmd & IXGBE_FDIRCMD_CMD_MASK)) - break; + err = ixgbe_fdir_check_cmd_complete(hw, &fdircmd); + if (err) { + hw_dbg(hw, "Flow Director command did not complete!\n"); + return err; } - if (!retry_count) - err = IXGBE_ERR_FDIR_REINIT_FAILED; - /* if filter exists in hardware then remove it */ if (fdircmd & IXGBE_FDIRCMD_FILTER_VALID) { IXGBE_WRITE_REG(hw, IXGBE_FDIRHASH, fdirhash); @@ -1846,7 +1861,7 @@ s32 ixgbe_fdir_erase_perfect_filter_82599(struct ixgbe_hw *hw, IXGBE_FDIRCMD_CMD_REMOVE_FLOW); } - return err; + return 0; } /** diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 4615a949381d9..938a4102adf57 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3460,6 +3460,7 @@ struct ixgbe_info { #define IXGBE_ERR_PBA_SECTION -31 #define IXGBE_ERR_INVALID_ARGUMENT -32 #define IXGBE_ERR_HOST_INTERFACE_COMMAND -33 +#define IXGBE_ERR_FDIR_CMD_INCOMPLETE -38 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #define IXGBE_KRM_PORT_CAR_GEN_CTRL(P) ((P) ? 0x8010 : 0x4010) -- GitLab From 4b36993d3df0834eff3b4172962de0343a4d9123 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 1 Sep 2015 16:46:08 -0700 Subject: [PATCH 6025/7006] flow_dissector: Don't use bit fields. Just have a flags member instead. In file included from include/linux/linkage.h:4:0, from include/linux/kernel.h:6, from net/core/flow_dissector.c:1: In function 'flow_keys_hash_start', inlined from 'flow_hash_from_keys' at net/core/flow_dissector.c:553:34: >> include/linux/compiler.h:447:38: error: call to '__compiletime_assert_459' declared with attribute error: BUILD_BUG_ON failed: FLOW_KEYS_HASH_OFFSET % sizeof(u32) Reported-by: kbuild test robot Signed-off-by: David S. Miller --- include/net/flow_dissector.h | 8 +++++--- net/core/flow_dissector.c | 14 +++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/include/net/flow_dissector.h b/include/net/flow_dissector.h index bddd1089dbce2..8c8548cf5888c 100644 --- a/include/net/flow_dissector.h +++ b/include/net/flow_dissector.h @@ -12,11 +12,13 @@ struct flow_dissector_key_control { u16 thoff; u16 addr_type; - u32 is_fragment:1; - u32 first_frag:1; - u32 encapsulation:1; + u32 flags; }; +#define FLOW_DIS_IS_FRAGMENT BIT(0) +#define FLOW_DIS_FIRST_FRAG BIT(1) +#define FLOW_DIS_ENCAPSULATION BIT(2) + /** * struct flow_dissector_key_basic: * @thoff: Transport header offset diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index b563339436d0c..8d32020303c60 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -189,12 +189,12 @@ ip: key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; if (ip_is_fragment(iph)) { - key_control->is_fragment = 1; + key_control->flags |= FLOW_DIS_IS_FRAGMENT; if (iph->frag_off & htons(IP_OFFSET)) { goto out_good; } else { - key_control->first_frag = 1; + key_control->flags |= FLOW_DIS_FIRST_FRAG; if (!(flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) goto out_good; } @@ -398,7 +398,7 @@ ip_proto_again: nhoff += sizeof(*eth); } - key_control->encapsulation = 1; + key_control->flags |= FLOW_DIS_ENCAPSULATION; if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) goto out_good; @@ -434,12 +434,12 @@ ip_proto_again: if (!fh) goto out_bad; - key_control->is_fragment = 1; + key_control->flags |= FLOW_DIS_IS_FRAGMENT; nhoff += sizeof(_fh); if (!(fh->frag_off & htons(IP6_OFFSET))) { - key_control->first_frag = 1; + key_control->flags |= FLOW_DIS_FIRST_FRAG; if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) { ip_proto = fh->nexthdr; goto ip_proto_again; @@ -450,7 +450,7 @@ ip_proto_again: case IPPROTO_IPIP: proto = htons(ETH_P_IP); - key_control->encapsulation = 1; + key_control->flags |= FLOW_DIS_ENCAPSULATION; if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) goto out_good; @@ -458,7 +458,7 @@ ip_proto_again: case IPPROTO_IPV6: proto = htons(ETH_P_IPV6); - key_control->encapsulation = 1; + key_control->flags |= FLOW_DIS_ENCAPSULATION; if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) goto out_good; -- GitLab From f467bc06022d4d37de459f9498ff4fbc7e9b0fca Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Mon, 15 Jun 2015 11:33:20 -0700 Subject: [PATCH 6026/7006] ixgbe: Add support for UDP-encapsulated tx checksum offload By using GSO for UDP-encapsulated packets, all ixgbe devices can be directed to generate checksums for the inner headers because the outer UDP checksum can be zero. So point the machinery at the inner headers and have the hardware generate the checksum. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 66 +++++++++++++++---- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index ab28dc2c37988..900562e023a74 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6912,31 +6912,55 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring, if (!(first->tx_flags & IXGBE_TX_FLAGS_HW_VLAN) && !(first->tx_flags & IXGBE_TX_FLAGS_CC)) return; + vlan_macip_lens = skb_network_offset(skb) << + IXGBE_ADVTXD_MACLEN_SHIFT; } else { u8 l4_hdr = 0; - switch (first->protocol) { - case htons(ETH_P_IP): - vlan_macip_lens |= skb_network_header_len(skb); + union { + struct iphdr *ipv4; + struct ipv6hdr *ipv6; + u8 *raw; + } network_hdr; + union { + struct tcphdr *tcphdr; + u8 *raw; + } transport_hdr; + + if (skb->encapsulation) { + network_hdr.raw = skb_inner_network_header(skb); + transport_hdr.raw = skb_inner_transport_header(skb); + vlan_macip_lens = skb_inner_network_offset(skb) << + IXGBE_ADVTXD_MACLEN_SHIFT; + } else { + network_hdr.raw = skb_network_header(skb); + transport_hdr.raw = skb_transport_header(skb); + vlan_macip_lens = skb_network_offset(skb) << + IXGBE_ADVTXD_MACLEN_SHIFT; + } + + /* use first 4 bits to determine IP version */ + switch (network_hdr.ipv4->version) { + case IPVERSION: + vlan_macip_lens |= transport_hdr.raw - network_hdr.raw; type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4; - l4_hdr = ip_hdr(skb)->protocol; + l4_hdr = network_hdr.ipv4->protocol; break; - case htons(ETH_P_IPV6): - vlan_macip_lens |= skb_network_header_len(skb); - l4_hdr = ipv6_hdr(skb)->nexthdr; + case 6: + vlan_macip_lens |= transport_hdr.raw - network_hdr.raw; + l4_hdr = network_hdr.ipv6->nexthdr; break; default: if (unlikely(net_ratelimit())) { dev_warn(tx_ring->dev, - "partial checksum but proto=%x!\n", - first->protocol); + "partial checksum but version=%d\n", + network_hdr.ipv4->version); } - break; } switch (l4_hdr) { case IPPROTO_TCP: type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_TCP; - mss_l4len_idx = tcp_hdrlen(skb) << + mss_l4len_idx = (transport_hdr.tcphdr->doff * 4) << IXGBE_ADVTXD_L4LEN_SHIFT; break; case IPPROTO_SCTP: @@ -6962,7 +6986,6 @@ static void ixgbe_tx_csum(struct ixgbe_ring *tx_ring, } /* vlan_macip_lens: MACLEN, VLAN tag */ - vlan_macip_lens |= skb_network_offset(skb) << IXGBE_ADVTXD_MACLEN_SHIFT; vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK; ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, 0, @@ -8207,6 +8230,21 @@ static void ixgbe_fwd_del(struct net_device *pdev, void *priv) kfree(fwd_adapter); } +#define IXGBE_MAX_TUNNEL_HDR_LEN 80 +static netdev_features_t +ixgbe_features_check(struct sk_buff *skb, struct net_device *dev, + netdev_features_t features) +{ + if (!skb->encapsulation) + return features; + + if (unlikely(skb_inner_mac_header(skb) - skb_transport_header(skb) > + IXGBE_MAX_TUNNEL_HDR_LEN)) + return features & ~NETIF_F_ALL_CSUM; + + return features; +} + static const struct net_device_ops ixgbe_netdev_ops = { .ndo_open = ixgbe_open, .ndo_stop = ixgbe_close, @@ -8254,6 +8292,7 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_dfwd_del_station = ixgbe_fwd_del, .ndo_add_vxlan_port = ixgbe_add_vxlan_port, .ndo_del_vxlan_port = ixgbe_del_vxlan_port, + .ndo_features_check = ixgbe_features_check, }; /** @@ -8613,6 +8652,9 @@ skip_sriov: netdev->vlan_features |= NETIF_F_IPV6_CSUM; netdev->vlan_features |= NETIF_F_SG; + netdev->hw_enc_features |= NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM; + netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; -- GitLab From 67359c3c9fc8e9fbed991bbe0cfeda55c7e0a64c Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Mon, 15 Jun 2015 11:33:25 -0700 Subject: [PATCH 6027/7006] ixgbe: Add support for VXLAN RX offloads Add support for VXLAN RX offloads for the X55x devices that support them. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 6 + .../net/ethernet/intel/ixgbe/ixgbe_82599.c | 18 ++- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 119 ++++++++++++++---- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 15 ++- 4 files changed, 127 insertions(+), 31 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index ac3ac2a203866..8830c0fb5ffb5 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -630,6 +630,7 @@ struct ixgbe_adapter { #define IXGBE_FLAG_FCOE_ENABLED (u32)(1 << 21) #define IXGBE_FLAG_SRIOV_CAPABLE (u32)(1 << 22) #define IXGBE_FLAG_SRIOV_ENABLED (u32)(1 << 23) +#define IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE BIT(24) u32 flags2; #define IXGBE_FLAG2_RSC_CAPABLE (u32)(1 << 0) @@ -644,6 +645,9 @@ struct ixgbe_adapter { #define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP (u32)(1 << 9) #define IXGBE_FLAG2_PTP_PPS_ENABLED (u32)(1 << 10) #define IXGBE_FLAG2_PHY_INTERRUPT (u32)(1 << 11) +#ifdef CONFIG_IXGBE_VXLAN +#define IXGBE_FLAG2_VXLAN_REREG_NEEDED BIT(12) +#endif /* Tx fast path data */ int num_tx_queues; @@ -757,7 +761,9 @@ struct ixgbe_adapter { u32 timer_event_accumulator; u32 vferr_refcount; struct ixgbe_mac_addr *mac_table; +#ifdef CONFIG_IXGBE_VXLAN u16 vxlan_port; +#endif struct kobject *info_kobj; #ifdef CONFIG_IXGBE_HWMON struct hwmon_buff *ixgbe_hwmon_buff; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c index d91044297062f..dd7062fed61ad 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_82599.c @@ -1519,20 +1519,28 @@ static u32 ixgbe_atr_compute_sig_hash_82599(union ixgbe_atr_hash_dword input, * @input: unique input dword * @common: compressed common input dword * @queue: queue index to direct traffic to + * + * Note that the tunnel bit in input must not be set when the hardware + * tunneling support does not exist. **/ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, union ixgbe_atr_hash_dword input, union ixgbe_atr_hash_dword common, u8 queue) { - u64 fdirhashcmd; - u32 fdircmd; + u64 fdirhashcmd; + u8 flow_type; + bool tunnel; + u32 fdircmd; /* * Get the flow_type in order to program FDIRCMD properly * lowest 2 bits are FDIRCMD.L4TYPE, third lowest bit is FDIRCMD.IPV6 */ - switch (input.formatted.flow_type) { + tunnel = !!(input.formatted.flow_type & IXGBE_ATR_L4TYPE_TUNNEL_MASK); + flow_type = input.formatted.flow_type & + (IXGBE_ATR_L4TYPE_TUNNEL_MASK - 1); + switch (flow_type) { case IXGBE_ATR_FLOW_TYPE_TCPV4: case IXGBE_ATR_FLOW_TYPE_UDPV4: case IXGBE_ATR_FLOW_TYPE_SCTPV4: @@ -1548,8 +1556,10 @@ s32 ixgbe_fdir_add_signature_filter_82599(struct ixgbe_hw *hw, /* configure FDIRCMD register */ fdircmd = IXGBE_FDIRCMD_CMD_ADD_FLOW | IXGBE_FDIRCMD_FILTER_UPDATE | IXGBE_FDIRCMD_LAST | IXGBE_FDIRCMD_QUEUE_EN; - fdircmd |= input.formatted.flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT; + fdircmd |= (u32)flow_type << IXGBE_FDIRCMD_FLOW_TYPE_SHIFT; fdircmd |= (u32)queue << IXGBE_FDIRCMD_RX_QUEUE_SHIFT; + if (tunnel) + fdircmd |= IXGBE_FDIRCMD_TUNNEL_FILTER; /* * The lower 32-bits of fdirhashcmd is for FDIRHASH, the upper 32-bits diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 900562e023a74..dcf849ddb7ce1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -1,7 +1,7 @@ /******************************************************************************* Intel 10 Gigabit PCI Express Linux driver - Copyright(c) 1999 - 2014 Intel Corporation. + Copyright(c) 1999 - 2015 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, @@ -65,6 +65,9 @@ #include "ixgbe_common.h" #include "ixgbe_dcb_82599.h" #include "ixgbe_sriov.h" +#ifdef CONFIG_IXGBE_VXLAN +#include +#endif char ixgbe_driver_name[] = "ixgbe"; static const char ixgbe_driver_string[] = @@ -79,7 +82,7 @@ static char ixgbe_default_device_descr[] = #define DRV_VERSION "4.0.1-k" const char ixgbe_driver_version[] = DRV_VERSION; static const char ixgbe_copyright[] = - "Copyright (c) 1999-2014 Intel Corporation."; + "Copyright (c) 1999-2015 Intel Corporation."; static const char ixgbe_overheat_msg[] = "Network adapter has been stopped because it has over heated. Restart the computer. If the problem persists, power off the system and replace the adapter"; @@ -1430,7 +1433,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring, (hdr_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_TUNNEL >> 16))) { encap_pkt = true; skb->encapsulation = 1; - skb->ip_summed = CHECKSUM_NONE; } /* if IP and error */ @@ -4261,6 +4263,21 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) } } +static void ixgbe_clear_vxlan_port(struct ixgbe_adapter *adapter) +{ + switch (adapter->hw.mac.type) { + case ixgbe_mac_X550: + case ixgbe_mac_X550EM_x: + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VXLANCTRL, 0); +#ifdef CONFIG_IXGBE_VXLAN + adapter->vxlan_port = 0; +#endif + break; + default: + break; + } +} + #ifdef CONFIG_IXGBE_DCB /** * ixgbe_configure_dcb - Configure DCB hardware @@ -5301,6 +5318,9 @@ static int ixgbe_sw_init(struct ixgbe_adapter *adapter) case ixgbe_mac_X550: #ifdef CONFIG_IXGBE_DCA adapter->flags &= ~IXGBE_FLAG_DCA_CAPABLE; +#endif +#ifdef CONFIG_IXGBE_VXLAN + adapter->flags |= IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE; #endif break; default: @@ -5753,10 +5773,11 @@ static int ixgbe_open(struct net_device *netdev) ixgbe_up_complete(adapter); -#if IS_ENABLED(CONFIG_IXGBE_VXLAN) + ixgbe_clear_vxlan_port(adapter); +#ifdef CONFIG_IXGBE_VXLAN vxlan_get_rx_port(netdev); - #endif + return 0; err_set_queues: @@ -6816,6 +6837,12 @@ static void ixgbe_service_task(struct work_struct *work) ixgbe_service_event_complete(adapter); return; } +#ifdef CONFIG_IXGBE_VXLAN + if (adapter->flags2 & IXGBE_FLAG2_VXLAN_REREG_NEEDED) { + adapter->flags2 &= ~IXGBE_FLAG2_VXLAN_REREG_NEEDED; + vxlan_get_rx_port(adapter->netdev); + } +#endif /* CONFIG_IXGBE_VXLAN */ ixgbe_reset_subtask(adapter); ixgbe_phy_interrupt_subtask(adapter); ixgbe_sfp_detection_subtask(adapter); @@ -7240,6 +7267,10 @@ static void ixgbe_atr(struct ixgbe_ring *ring, struct ipv6hdr *ipv6; } hdr; struct tcphdr *th; + struct sk_buff *skb; +#ifdef CONFIG_IXGBE_VXLAN + u8 encap = false; +#endif /* CONFIG_IXGBE_VXLAN */ __be16 vlan_id; /* if ring doesn't have a interrupt vector, cannot perform ATR */ @@ -7253,16 +7284,36 @@ static void ixgbe_atr(struct ixgbe_ring *ring, ring->atr_count++; /* snag network header to get L4 type and address */ - hdr.network = skb_network_header(first->skb); + skb = first->skb; + hdr.network = skb_network_header(skb); + if (skb->encapsulation) { +#ifdef CONFIG_IXGBE_VXLAN + struct ixgbe_adapter *adapter = q_vector->adapter; - /* Currently only IPv4/IPv6 with TCP is supported */ - if ((first->protocol != htons(ETH_P_IPV6) || - hdr.ipv6->nexthdr != IPPROTO_TCP) && - (first->protocol != htons(ETH_P_IP) || - hdr.ipv4->protocol != IPPROTO_TCP)) + if (!adapter->vxlan_port) + return; + if (first->protocol != htons(ETH_P_IP) || + hdr.ipv4->version != IPVERSION || + hdr.ipv4->protocol != IPPROTO_UDP) { + return; + } + if (ntohs(udp_hdr(skb)->dest) != adapter->vxlan_port) + return; + encap = true; + hdr.network = skb_inner_network_header(skb); + th = inner_tcp_hdr(skb); +#else return; - - th = tcp_hdr(first->skb); +#endif /* CONFIG_IXGBE_VXLAN */ + } else { + /* Currently only IPv4/IPv6 with TCP is supported */ + if ((first->protocol != htons(ETH_P_IPV6) || + hdr.ipv6->nexthdr != IPPROTO_TCP) && + (first->protocol != htons(ETH_P_IP) || + hdr.ipv4->protocol != IPPROTO_TCP)) + return; + th = tcp_hdr(skb); + } /* skip this packet since it is invalid or the socket is closing */ if (!th || th->fin) @@ -7311,6 +7362,11 @@ static void ixgbe_atr(struct ixgbe_ring *ring, hdr.ipv6->daddr.s6_addr32[3]; } +#ifdef CONFIG_IXGBE_VXLAN + if (encap) + input.formatted.flow_type |= IXGBE_ATR_L4TYPE_TUNNEL_MASK; +#endif /* CONFIG_IXGBE_VXLAN */ + /* This assumes the Rx queue and Tx queue are bound to the same CPU */ ixgbe_fdir_add_signature_filter_82599(&q_vector->adapter->hw, input, common, ring->queue_index); @@ -7937,12 +7993,23 @@ static int ixgbe_set_features(struct net_device *netdev, need_reset = true; netdev->features = features; + +#ifdef CONFIG_IXGBE_VXLAN + if ((adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE)) { + if (features & NETIF_F_RXCSUM) + adapter->flags2 |= IXGBE_FLAG2_VXLAN_REREG_NEEDED; + else + ixgbe_clear_vxlan_port(adapter); + } +#endif /* CONFIG_IXGBE_VXLAN */ + if (need_reset) ixgbe_do_reset(netdev); return 0; } +#ifdef CONFIG_IXGBE_VXLAN /** * ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up * @dev: The port's netdev @@ -7956,17 +8023,18 @@ static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family, struct ixgbe_hw *hw = &adapter->hw; u16 new_port = ntohs(port); + if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE)) + return; + if (sa_family == AF_INET6) return; - if (adapter->vxlan_port == new_port) { - netdev_info(dev, "Port %d already offloaded\n", new_port); + if (adapter->vxlan_port == new_port) return; - } if (adapter->vxlan_port) { netdev_info(dev, - "Hit Max num of UDP ports, not adding port %d\n", + "Hit Max num of VXLAN ports, not adding port %d\n", new_port); return; } @@ -7985,9 +8053,11 @@ static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family, __be16 port) { struct ixgbe_adapter *adapter = netdev_priv(dev); - struct ixgbe_hw *hw = &adapter->hw; u16 new_port = ntohs(port); + if (!(adapter->flags & IXGBE_FLAG_VXLAN_OFFLOAD_CAPABLE)) + return; + if (sa_family == AF_INET6) return; @@ -7997,9 +8067,10 @@ static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family, return; } - adapter->vxlan_port = 0; - IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0); + ixgbe_clear_vxlan_port(adapter); + adapter->flags2 |= IXGBE_FLAG2_VXLAN_REREG_NEEDED; } +#endif /* CONFIG_IXGBE_VXLAN */ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], struct net_device *dev, @@ -8290,8 +8361,10 @@ static const struct net_device_ops ixgbe_netdev_ops = { .ndo_bridge_getlink = ixgbe_ndo_bridge_getlink, .ndo_dfwd_add_station = ixgbe_fwd_add, .ndo_dfwd_del_station = ixgbe_fwd_del, +#ifdef CONFIG_IXGBE_VXLAN .ndo_add_vxlan_port = ixgbe_add_vxlan_port, .ndo_del_vxlan_port = ixgbe_del_vxlan_port, +#endif /* CONFIG_IXGBE_VXLAN */ .ndo_features_check = ixgbe_features_check, }; @@ -8658,14 +8731,18 @@ skip_sriov: netdev->priv_flags |= IFF_UNICAST_FLT; netdev->priv_flags |= IFF_SUPP_NOFCS; +#ifdef CONFIG_IXGBE_VXLAN switch (adapter->hw.mac.type) { case ixgbe_mac_X550: case ixgbe_mac_X550EM_x: - netdev->hw_enc_features |= NETIF_F_RXCSUM; + netdev->hw_enc_features |= NETIF_F_RXCSUM | + NETIF_F_IP_CSUM | + NETIF_F_IPV6_CSUM; break; default: break; } +#endif /* CONFIG_IXGBE_VXLAN */ #ifdef CONFIG_IXGBE_DCB netdev->dcbnl_ops = &dcbnl_ops; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 938a4102adf57..0e678243abf75 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -2540,9 +2540,11 @@ enum ixgbe_fdir_pballoc_type { #define IXGBE_FDIRCMD_QUEUE_EN 0x00008000 #define IXGBE_FDIRCMD_FLOW_TYPE_SHIFT 5 #define IXGBE_FDIRCMD_RX_QUEUE_SHIFT 16 +#define IXGBE_FDIRCMD_RX_TUNNEL_FILTER_SHIFT 23 #define IXGBE_FDIRCMD_VT_POOL_SHIFT 24 #define IXGBE_FDIR_INIT_DONE_POLL 10 #define IXGBE_FDIRCMD_CMD_POLL 10 +#define IXGBE_FDIRCMD_TUNNEL_FILTER 0x00800000 #define IXGBE_FDIR_DROP_QUEUE 127 @@ -2833,12 +2835,13 @@ typedef u32 ixgbe_link_speed; #define IXGBE_ATR_SIGNATURE_HASH_KEY 0x174D3614 /* Software ATR input stream values and masks */ -#define IXGBE_ATR_HASH_MASK 0x7fff -#define IXGBE_ATR_L4TYPE_MASK 0x3 -#define IXGBE_ATR_L4TYPE_UDP 0x1 -#define IXGBE_ATR_L4TYPE_TCP 0x2 -#define IXGBE_ATR_L4TYPE_SCTP 0x3 -#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4 +#define IXGBE_ATR_HASH_MASK 0x7fff +#define IXGBE_ATR_L4TYPE_MASK 0x3 +#define IXGBE_ATR_L4TYPE_UDP 0x1 +#define IXGBE_ATR_L4TYPE_TCP 0x2 +#define IXGBE_ATR_L4TYPE_SCTP 0x3 +#define IXGBE_ATR_L4TYPE_IPV6_MASK 0x4 +#define IXGBE_ATR_L4TYPE_TUNNEL_MASK 0x10 enum ixgbe_atr_flow_type { IXGBE_ATR_FLOW_TYPE_IPV4 = 0x0, IXGBE_ATR_FLOW_TYPE_UDPV4 = 0x1, -- GitLab From 6ac7439459606a57265800e60b14d58365ab19eb Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 17 Jun 2015 17:34:31 -0400 Subject: [PATCH 6028/7006] ixgbe: Add support for entering low power link up state When the device is closing or suspending, call ixgbe_enter_lplu to enter low power link up state on devices that support it. When this is done, prevent the phy from being reset in the ixgbe_down path so that link is present when calling ixgbe_enter_lplu. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 10 +- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 34 ++++- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 143 ++++++++++++++++++ 3 files changed, 185 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index dcf849ddb7ce1..098c84955a110 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -5798,7 +5798,15 @@ static void ixgbe_close_suspend(struct ixgbe_adapter *adapter) { ixgbe_ptp_suspend(adapter); - ixgbe_down(adapter); + if (adapter->hw.phy.ops.enter_lplu) { + adapter->hw.phy.reset_disable = true; + ixgbe_down(adapter); + adapter->hw.phy.ops.enter_lplu(&adapter->hw); + adapter->hw.phy.reset_disable = false; + } else { + ixgbe_down(adapter); + } + ixgbe_free_irq(adapter); ixgbe_free_all_tx_resources(adapter); diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 0e678243abf75..19271e5d20106 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -848,6 +848,7 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_MDIO_AUTO_NEG_LINK_STATUS 0x4 /* Indicates if link is up */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_MASK 0x7 /* Speed/Duplex Mask */ +#define IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK 0x6 /* Speed Mask */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10M_HALF 0x0 /* 10Mb/s Half Duplex */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10M_FULL 0x1 /* 10Mb/s Full Duplex */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_100M_HALF 0x2 /* 100Mb/s H Duplex */ @@ -856,6 +857,24 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB_FULL 0x5 /* 1Gb/s Full Duplex */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_HALF 0x6 /* 10Gb/s Half Duplex */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB_FULL 0x7 /* 10Gb/s Full Duplex */ +#define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB 0x4 /* 1Gb/s */ +#define IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB 0x6 /* 10Gb/s */ + +#define IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG 0x20 /* 10G Control Reg */ +#define IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG 0xC400 /* 1G Provisioning 1 */ +#define IXGBE_MII_AUTONEG_XNP_TX_REG 0x17 /* 1G XNP Transmit */ +#define IXGBE_MII_AUTONEG_ADVERTISE_REG 0x10 /* 100M Advertisement */ +#define IXGBE_MII_10GBASE_T_ADVERTISE 0x1000 /* full duplex, bit:12*/ +#define IXGBE_MII_1GBASE_T_ADVERTISE_XNP_TX 0x4000 /* full duplex, bit:14*/ +#define IXGBE_MII_1GBASE_T_ADVERTISE 0x8000 /* full duplex, bit:15*/ +#define IXGBE_MII_2_5GBASE_T_ADVERTISE 0x0400 +#define IXGBE_MII_5GBASE_T_ADVERTISE 0x0800 +#define IXGBE_MII_100BASE_T_ADVERTISE 0x0100 /* full duplex, bit:8 */ +#define IXGBE_MII_100BASE_T_ADVERTISE_HALF 0x0080 /* half duplex, bit:7 */ +#define IXGBE_MII_RESTART 0x200 +#define IXGBE_MII_AUTONEG_COMPLETE 0x20 +#define IXGBE_MII_AUTONEG_LINK_UP 0x04 +#define IXGBE_MII_AUTONEG_REG 0x0 /* Management */ #define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */ @@ -1305,6 +1324,7 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_MDIO_AUTO_NEG_CONTROL 0x0 /* AUTO_NEG Control Reg */ #define IXGBE_MDIO_AUTO_NEG_STATUS 0x1 /* AUTO_NEG Status Reg */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_STAT 0xC800 /* AUTO_NEG Vendor Status Reg */ +#define IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM 0xCC00 /* AUTO_NEG Vendor TX Reg */ #define IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM2 0xCC01 /* AUTO_NEG Vendor Tx Reg */ #define IXGBE_MDIO_AUTO_NEG_VEN_LSC 0x1 /* AUTO_NEG Vendor Tx LSC */ #define IXGBE_MDIO_AUTO_NEG_ADVT 0x10 /* AUTO_NEG Advt Reg */ @@ -1312,7 +1332,8 @@ struct ixgbe_thermal_sensor_data { #define IXGBE_MDIO_AUTO_NEG_EEE_ADVT 0x3C /* AUTO_NEG EEE Advt Reg */ #define IXGBE_MDIO_PHY_SET_LOW_POWER_MODE 0x0800 /* Set low power mode */ - +#define IXGBE_AUTO_NEG_LP_STATUS 0xE820 /* AUTO NEG Rx LP Status Reg */ +#define IXGBE_AUTO_NEG_LP_1000BASE_CAP 0x8000 /* AUTO NEG Rx LP 1000BaseT */ #define IXGBE_MDIO_TX_VENDOR_ALARMS_3 0xCC02 /* Vendor Alarms 3 Reg */ #define IXGBE_MDIO_TX_VENDOR_ALARMS_3_RST_MASK 0x3 /* PHY Reset Complete Mask */ #define IXGBE_MDIO_GLOBAL_RES_PR_10 0xC479 /* Global Resv Provisioning 10 Reg */ @@ -2041,6 +2062,11 @@ enum { #define IXGBE_NVM_POLL_WRITE 1 /* Flag for polling for write complete */ #define IXGBE_NVM_POLL_READ 0 /* Flag for polling for read complete */ +#define NVM_INIT_CTRL_3 0x38 +#define NVM_INIT_CTRL_3_LPLU 0x8 +#define NVM_INIT_CTRL_3_D10GMP_PORT0 0x40 +#define NVM_INIT_CTRL_3_D10GMP_PORT1 0x100 + #define IXGBE_EEPROM_PAGE_SIZE_MAX 128 #define IXGBE_EEPROM_RD_BUFFER_MAX_COUNT 512 /* EEPROM words # read in burst */ #define IXGBE_EEPROM_WR_BUFFER_MAX_COUNT 256 /* EEPROM words # wr in burst */ @@ -3301,6 +3327,7 @@ struct ixgbe_phy_operations { s32 (*write_i2c_combined)(struct ixgbe_hw *, u8 addr, u16 reg, u16 val); s32 (*check_overtemp)(struct ixgbe_hw *); s32 (*set_phy_power)(struct ixgbe_hw *, bool on); + s32 (*enter_lplu)(struct ixgbe_hw *); s32 (*handle_lasi)(struct ixgbe_hw *hw); }; @@ -3311,6 +3338,7 @@ struct ixgbe_eeprom_info { u16 word_size; u16 address_bits; u16 word_page_size; + u16 ctrl_word_3; }; #define IXGBE_FLAGS_DOUBLE_RESET_REQUIRED 0x01 @@ -3466,6 +3494,10 @@ struct ixgbe_info { #define IXGBE_ERR_FDIR_CMD_INCOMPLETE -38 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF +#define IXGBE_FUSES0_GROUP(_i) (0x11158 + ((_i) * 4)) +#define IXGBE_FUSES0_300MHZ BIT(5) +#define IXGBE_FUSES0_REV1 BIT(6) + #define IXGBE_KRM_PORT_CAR_GEN_CTRL(P) ((P) ? 0x8010 : 0x4010) #define IXGBE_KRM_LINK_CTRL_1(P) ((P) ? 0x820C : 0x420C) #define IXGBE_KRM_DSP_TXFFE_STATE_4(P) ((P) ? 0x8634 : 0x4634) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 662d2e8962862..bbc5a2da86c4e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1458,6 +1458,144 @@ static s32 ixgbe_reset_phy_t_X550em(struct ixgbe_hw *hw) return ixgbe_enable_lasi_ext_t_x550em(hw); } +/** ixgbe_get_lcd_x550em - Determine lowest common denominator + * @hw: pointer to hardware structure + * @lcd_speed: pointer to lowest common link speed + * + * Determine lowest common link speed with link partner. + **/ +static s32 ixgbe_get_lcd_t_x550em(struct ixgbe_hw *hw, + ixgbe_link_speed *lcd_speed) +{ + u16 an_lp_status; + s32 status; + u16 word = hw->eeprom.ctrl_word_3; + + *lcd_speed = IXGBE_LINK_SPEED_UNKNOWN; + + status = hw->phy.ops.read_reg(hw, IXGBE_AUTO_NEG_LP_STATUS, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &an_lp_status); + if (status) + return status; + + /* If link partner advertised 1G, return 1G */ + if (an_lp_status & IXGBE_AUTO_NEG_LP_1000BASE_CAP) { + *lcd_speed = IXGBE_LINK_SPEED_1GB_FULL; + return status; + } + + /* If 10G disabled for LPLU via NVM D10GMP, then return no valid LCD */ + if ((hw->bus.lan_id && (word & NVM_INIT_CTRL_3_D10GMP_PORT1)) || + (word & NVM_INIT_CTRL_3_D10GMP_PORT0)) + return status; + + /* Link partner not capable of lower speeds, return 10G */ + *lcd_speed = IXGBE_LINK_SPEED_10GB_FULL; + return status; +} + +/** ixgbe_enter_lplu_x550em - Transition to low power states + * @hw: pointer to hardware structure + * + * Configures Low Power Link Up on transition to low power states + * (from D0 to non-D0). Link is required to enter LPLU so avoid resetting + * the X557 PHY immediately prior to entering LPLU. + **/ +static s32 ixgbe_enter_lplu_t_x550em(struct ixgbe_hw *hw) +{ + u16 an_10g_cntl_reg, autoneg_reg, speed; + s32 status; + ixgbe_link_speed lcd_speed; + u32 save_autoneg; + bool link_up; + + /* SW LPLU not required on later HW revisions. */ + if (IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, IXGBE_FUSES0_GROUP(0))) + return 0; + + /* If blocked by MNG FW, then don't restart AN */ + if (ixgbe_check_reset_blocked(hw)) + return 0; + + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); + if (status) + return status; + + status = hw->eeprom.ops.read(hw, NVM_INIT_CTRL_3, + &hw->eeprom.ctrl_word_3); + if (status) + return status; + + /* If link is down, LPLU disabled in NVM, WoL disabled, or + * manageability disabled, then force link down by entering + * low power mode. + */ + if (!link_up || !(hw->eeprom.ctrl_word_3 & NVM_INIT_CTRL_3_LPLU) || + !(hw->wol_enabled || ixgbe_mng_present(hw))) + return ixgbe_set_copper_phy_power(hw, false); + + /* Determine LCD */ + status = ixgbe_get_lcd_t_x550em(hw, &lcd_speed); + if (status) + return status; + + /* If no valid LCD link speed, then force link down and exit. */ + if (lcd_speed == IXGBE_LINK_SPEED_UNKNOWN) + return ixgbe_set_copper_phy_power(hw, false); + + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_STAT, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &speed); + if (status) + return status; + + /* If no link now, speed is invalid so take link down */ + status = ixgbe_ext_phy_t_x550em_get_link(hw, &link_up); + if (status) + return ixgbe_set_copper_phy_power(hw, false); + + /* clear everything but the speed bits */ + speed &= IXGBE_MDIO_AUTO_NEG_VEN_STAT_SPEED_MASK; + + /* If current speed is already LCD, then exit. */ + if (((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_1GB) && + (lcd_speed == IXGBE_LINK_SPEED_1GB_FULL)) || + ((speed == IXGBE_MDIO_AUTO_NEG_VENDOR_STATUS_10GB) && + (lcd_speed == IXGBE_LINK_SPEED_10GB_FULL))) + return status; + + /* Clear AN completed indication */ + status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_AUTO_NEG_VENDOR_TX_ALARM, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + if (status) + return status; + + status = hw->phy.ops.read_reg(hw, IXGBE_MII_10GBASE_T_AUTONEG_CTRL_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &an_10g_cntl_reg); + if (status) + return status; + + status = hw->phy.ops.read_reg(hw, + IXGBE_MII_AUTONEG_VENDOR_PROVISION_1_REG, + IXGBE_MDIO_AUTO_NEG_DEV_TYPE, + &autoneg_reg); + if (status) + return status; + + save_autoneg = hw->phy.autoneg_advertised; + + /* Setup link at least common link speed */ + status = hw->mac.ops.setup_link(hw, lcd_speed, false); + + /* restore autoneg from before setting lplu speed */ + hw->phy.autoneg_advertised = save_autoneg; + + return status; +} + /** ixgbe_init_phy_ops_X550em - PHY/SFP specific init * @hw: pointer to hardware structure * @@ -1528,6 +1666,11 @@ static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw) ret_val = ixgbe_setup_kr_speed_x550em(hw, speed); } + /* setup SW LPLU only for first revision */ + if (!(IXGBE_FUSES0_REV1 & IXGBE_READ_REG(hw, + IXGBE_FUSES0_GROUP(0)))) + phy->ops.enter_lplu = ixgbe_enter_lplu_t_x550em; + phy->ops.handle_lasi = ixgbe_handle_lasi_ext_t_x550em; phy->ops.reset = ixgbe_reset_phy_t_X550em; break; -- GitLab From 454c65dd1a1e7fdaa5bbd3a34e14ab5560fbfad7 Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Wed, 17 Jun 2015 20:59:59 -0400 Subject: [PATCH 6029/7006] ixgbe: add get_bus_info method for X550 Added ixgbe_get_bus_info_X550em to X550 code. ixgbe_get_bus_info_X550em sets bus.width to ixgbe_bus_width_unknown and bus.speed to ixgbe_bus_speed_unknown, because IOSF does not report a PCIe bus width or speed. Signed-off-by: Don Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index bbc5a2da86c4e..dce39be28d5fd 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -611,6 +611,23 @@ static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) return status; } +/** + * ixgbe_get_bus_info_X550em - Set PCI bus info + * @hw: pointer to hardware structure + * + * Sets bus link width and speed to unknown because X550em is + * not a PCI device. + **/ +static s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw) +{ + hw->bus.width = ixgbe_bus_width_unknown; + hw->bus.speed = ixgbe_bus_speed_unknown; + + hw->mac.ops.set_lan_id(hw); + + return 0; +} + /** ixgbe_disable_rx_x550 - Disable RX unit * * Enables the Rx DMA unit for x550 @@ -1966,6 +1983,7 @@ static struct ixgbe_mac_operations mac_ops_X550 = { .get_wwn_prefix = &ixgbe_get_wwn_prefix_generic, .setup_link = &ixgbe_setup_mac_link_X540, .get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic, + .get_bus_info = &ixgbe_get_bus_info_generic, .setup_sfp = NULL, }; @@ -1977,6 +1995,7 @@ static struct ixgbe_mac_operations mac_ops_X550EM_x = { .get_wwn_prefix = NULL, .setup_link = NULL, /* defined later */ .get_link_capabilities = &ixgbe_get_link_capabilities_X550em, + .get_bus_info = &ixgbe_get_bus_info_X550em, .setup_sfp = ixgbe_setup_sfp_modules_X550em, }; -- GitLab From f9328bc6a7edc0fbaea836007b4261ca6233d96f Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 18 Jun 2015 13:24:06 -0400 Subject: [PATCH 6030/7006] ixgbe: add new bus type for intergrated I/O interface (IOSF) With this patch we add support for a new bus type ixgbe_bus_type_internal. X550em devices use IOSF and not PCIe bus so this new type is to accommodate them. Signed-off-by: Donald C Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 11 ++++++++++- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 + drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 1 + 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 098c84955a110..7e331254e9c9b 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -246,11 +246,19 @@ static inline bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw) static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter, int expected_gts) { + struct ixgbe_hw *hw = &adapter->hw; int max_gts = 0; enum pci_bus_speed speed = PCI_SPEED_UNKNOWN; enum pcie_link_width width = PCIE_LNK_WIDTH_UNKNOWN; struct pci_dev *pdev; + /* Some devices are not connected over PCIe and thus do not negotiate + * speed. These devices do not have valid bus info, and thus any report + * we generate may not be correct. + */ + if (hw->bus.type == ixgbe_bus_type_internal) + return; + /* determine whether to use the parent device */ if (ixgbe_pcie_from_parent(&adapter->hw)) pdev = adapter->pdev->bus->parent->self; @@ -8837,9 +8845,10 @@ skip_sriov: hw->eeprom.ops.read(hw, 0x2d, &adapter->eeprom_verl); /* pick up the PCI bus settings for reporting later */ - hw->mac.ops.get_bus_info(hw); if (ixgbe_pcie_from_parent(hw)) ixgbe_get_parent_bus_info(adapter); + else + hw->mac.ops.get_bus_info(hw); /* calculate the expected PCIe bandwidth required for optimal * performance. Note that some older parts will never have enough diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 19271e5d20106..37df15f9ebc81 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3067,6 +3067,7 @@ enum ixgbe_bus_type { ixgbe_bus_type_pci, ixgbe_bus_type_pcix, ixgbe_bus_type_pci_express, + ixgbe_bus_type_internal, ixgbe_bus_type_reserved }; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index dce39be28d5fd..96f603f435eed 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -620,6 +620,7 @@ static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw) **/ static s32 ixgbe_get_bus_info_X550em(struct ixgbe_hw *hw) { + hw->bus.type = ixgbe_bus_type_internal; hw->bus.width = ixgbe_bus_width_unknown; hw->bus.speed = ixgbe_bus_speed_unknown; -- GitLab From fa888b891384ccbf18e70af2e02f5173e55e5e7f Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Thu, 18 Jun 2015 16:31:42 -0400 Subject: [PATCH 6031/7006] ixgbe: Remove unused PCI bus types The ixgbe never has as very doubtfully ever will support either PCI or PCI-X devices. So remove the unused types from the ixgbe_bus_type. Thanks to Alex Duyck for suggesting this. Signed-off-by: Donald C Skidmore Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 37df15f9ebc81..1c5a5b3bbc776 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3064,8 +3064,6 @@ enum ixgbe_smart_speed { /* PCI bus types */ enum ixgbe_bus_type { ixgbe_bus_type_unknown = 0, - ixgbe_bus_type_pci, - ixgbe_bus_type_pcix, ixgbe_bus_type_pci_express, ixgbe_bus_type_internal, ixgbe_bus_type_reserved -- GitLab From a17ace95b0f08ccbcf24946db5673c4b5ee8fcae Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 1 Sep 2015 17:00:24 -0700 Subject: [PATCH 6032/7006] flow: Move __get_hash_from_flowi{4,6} into flow_dissector.c These cannot live in net/core/flow.c which only builds when XFRM is enabled. Reported-by: kbuild test robot Signed-off-by: David S. Miller --- net/core/flow.c | 36 ------------------------------------ net/core/flow_dissector.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 36 deletions(-) diff --git a/net/core/flow.c b/net/core/flow.c index 61930bb0eb595..1033725be40bd 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -510,38 +509,3 @@ void flow_cache_fini(struct net *net) fc->percpu = NULL; } EXPORT_SYMBOL(flow_cache_fini); - -__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys) -{ - memset(keys, 0, sizeof(*keys)); - - memcpy(&keys->addrs.v6addrs.src, &fl6->saddr, - sizeof(keys->addrs.v6addrs.src)); - memcpy(&keys->addrs.v6addrs.dst, &fl6->daddr, - sizeof(keys->addrs.v6addrs.dst)); - keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; - keys->ports.src = fl6->fl6_sport; - keys->ports.dst = fl6->fl6_dport; - keys->keyid.keyid = fl6->fl6_gre_key; - keys->tags.flow_label = (__force u32)fl6->flowlabel; - keys->basic.ip_proto = fl6->flowi6_proto; - - return flow_hash_from_keys(keys); -} -EXPORT_SYMBOL(__get_hash_from_flowi6); - -__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys) -{ - memset(keys, 0, sizeof(*keys)); - - keys->addrs.v4addrs.src = fl4->saddr; - keys->addrs.v4addrs.dst = fl4->daddr; - keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; - keys->ports.src = fl4->fl4_sport; - keys->ports.dst = fl4->fl4_dport; - keys->keyid.keyid = fl4->fl4_gre_key; - keys->basic.ip_proto = fl4->flowi4_proto; - - return flow_hash_from_keys(keys); -} -EXPORT_SYMBOL(__get_hash_from_flowi4); diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 8d32020303c60..345a0408cfe4a 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -787,6 +787,41 @@ u32 skb_get_poff(const struct sk_buff *skb) return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); } +__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys) +{ + memset(keys, 0, sizeof(*keys)); + + memcpy(&keys->addrs.v6addrs.src, &fl6->saddr, + sizeof(keys->addrs.v6addrs.src)); + memcpy(&keys->addrs.v6addrs.dst, &fl6->daddr, + sizeof(keys->addrs.v6addrs.dst)); + keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; + keys->ports.src = fl6->fl6_sport; + keys->ports.dst = fl6->fl6_dport; + keys->keyid.keyid = fl6->fl6_gre_key; + keys->tags.flow_label = (__force u32)fl6->flowlabel; + keys->basic.ip_proto = fl6->flowi6_proto; + + return flow_hash_from_keys(keys); +} +EXPORT_SYMBOL(__get_hash_from_flowi6); + +__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys) +{ + memset(keys, 0, sizeof(*keys)); + + keys->addrs.v4addrs.src = fl4->saddr; + keys->addrs.v4addrs.dst = fl4->daddr; + keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; + keys->ports.src = fl4->fl4_sport; + keys->ports.dst = fl4->fl4_dport; + keys->keyid.keyid = fl4->fl4_gre_key; + keys->basic.ip_proto = fl4->flowi4_proto; + + return flow_hash_from_keys(keys); +} +EXPORT_SYMBOL(__get_hash_from_flowi4); + static const struct flow_dissector_key flow_keys_dissector_keys[] = { { .key_id = FLOW_DISSECTOR_KEY_CONTROL, -- GitLab From bc52f951e344b2ec64388c71890d88c5fc154a41 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 19 Jun 2015 09:37:55 +0530 Subject: [PATCH 6033/7006] ixgbe: use kzalloc for allocating one thing Use kzalloc rather than kcalloc(1.. The semantic patch that makes this change is as follows: // @@ @@ - kcalloc(1, + kzalloc( ...) // and removing checkpatch below CHECK: CHECK: Prefer kzalloc(sizeof(*fwd_adapter)...) over kzalloc(sizeof(struct ixgbe_fwd_adapter)...) Signed-off-by: Maninder Singh Reviewed-by: Vaneet Narang Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 7e331254e9c9b..7389c9692c956 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -8261,7 +8261,7 @@ static void *ixgbe_fwd_add(struct net_device *pdev, struct net_device *vdev) (adapter->num_rx_pools > IXGBE_MAX_MACVLANS)) return ERR_PTR(-EBUSY); - fwd_adapter = kcalloc(1, sizeof(struct ixgbe_fwd_adapter), GFP_KERNEL); + fwd_adapter = kzalloc(sizeof(*fwd_adapter), GFP_KERNEL); if (!fwd_adapter) return ERR_PTR(-ENOMEM); -- GitLab From d5702dea43fc517c389f2d9825213dabbfdaed5e Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Fri, 19 Jun 2015 12:23:36 -0400 Subject: [PATCH 6034/7006] ixgbe: Remove second instance of lan_id variable This patch removes the redundant lan_id in the phy struct and uses the bus version. Both variables exist and intend to represent the STATUS register LAN_ID field. However, phy.lan_id is not bit shifted so the phy.lan_id = 0x0 for LAN Id 0 and phy.lan_id = 0x4 for LAN Id 1. Where bus.lan_id is bit shifted so bus.lan_id = 0x0 for LAN Id 0 and bus.lan_id = 0x1 for LAN Id 1. There seems no need for the additional lan_id variable and this should make the code less confusing. Signed-off-by: Donald C Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 4 +--- drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 - 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 526a20bf74888..740e566cca077 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -243,9 +243,7 @@ s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw) u16 ext_ability = 0; if (!hw->phy.phy_semaphore_mask) { - hw->phy.lan_id = IXGBE_READ_REG(hw, IXGBE_STATUS) & - IXGBE_STATUS_LAN_ID_1; - if (hw->phy.lan_id) + if (hw->bus.lan_id) hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY1_SM; else hw->phy.phy_semaphore_mask = IXGBE_GSSR_PHY0_SM; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index 1c5a5b3bbc776..a3eec19c9fdf8 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3381,7 +3381,6 @@ struct ixgbe_phy_info { bool sfp_setup_needed; u32 revision; enum ixgbe_media_type media_type; - u8 lan_id; u32 phy_semaphore_mask; bool reset_disable; ixgbe_autoneg_advertised autoneg_advertised; -- GitLab From 897b9349f056d1c1cf5141ded4ec26766d845f8b Mon Sep 17 00:00:00 2001 From: Don Skidmore Date: Fri, 19 Jun 2015 19:14:57 -0400 Subject: [PATCH 6035/7006] ixgbe: cleanup to use cached mask value We already cache this FW/SW semaphore mask so might as well use it for consistency. Signed-off-by: Don Skidmore Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 740e566cca077..97275dce2a16d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -606,12 +606,7 @@ s32 ixgbe_write_phy_reg_generic(struct ixgbe_hw *hw, u32 reg_addr, u32 device_type, u16 phy_data) { s32 status; - u32 gssr; - - if (IXGBE_READ_REG(hw, IXGBE_STATUS) & IXGBE_STATUS_LAN_ID_1) - gssr = IXGBE_GSSR_PHY1_SM; - else - gssr = IXGBE_GSSR_PHY0_SM; + u32 gssr = hw->phy.phy_semaphore_mask; if (hw->mac.ops.acquire_swfw_sync(hw, gssr) == 0) { status = ixgbe_write_phy_reg_mdi(hw, reg_addr, device_type, -- GitLab From ae8140aa6bf5c7aafc0d9c2f612c5b59bea1ce9f Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Thu, 25 Jun 2015 17:49:57 -0700 Subject: [PATCH 6036/7006] ixgbe: Avoid needless PHY access on copper phys Avoid a needless PHY access on copper phys to save the 10ms wait time for each PHY access. A helper function is introduced to actually do the register access and process the contents. Signed-off-by: Mark Rustad Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c | 64 +++++++++++++------ drivers/net/ethernet/intel/ixgbe/ixgbe_type.h | 1 + 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c index 97275dce2a16d..597d0b1c23701 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_phy.c @@ -730,39 +730,61 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, } /** - * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities + * ixgbe_get_copper_speeds_supported - Get copper link speed from phy * @hw: pointer to hardware structure - * @speed: pointer to link speed - * @autoneg: boolean auto-negotiation value * - * Determines the link capabilities by reading the AUTOC register. + * Determines the supported link capabilities by reading the PHY auto + * negotiation register. */ -s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg) +static s32 ixgbe_get_copper_speeds_supported(struct ixgbe_hw *hw) { - s32 status; u16 speed_ability; - - *speed = 0; - *autoneg = true; + s32 status; status = hw->phy.ops.read_reg(hw, MDIO_SPEED, MDIO_MMD_PMAPMD, &speed_ability); + if (status) + return status; - if (status == 0) { - if (speed_ability & MDIO_SPEED_10G) - *speed |= IXGBE_LINK_SPEED_10GB_FULL; - if (speed_ability & MDIO_PMA_SPEED_1000) - *speed |= IXGBE_LINK_SPEED_1GB_FULL; - if (speed_ability & MDIO_PMA_SPEED_100) - *speed |= IXGBE_LINK_SPEED_100_FULL; + if (speed_ability & MDIO_SPEED_10G) + hw->phy.speeds_supported |= IXGBE_LINK_SPEED_10GB_FULL; + if (speed_ability & MDIO_PMA_SPEED_1000) + hw->phy.speeds_supported |= IXGBE_LINK_SPEED_1GB_FULL; + if (speed_ability & MDIO_PMA_SPEED_100) + hw->phy.speeds_supported |= IXGBE_LINK_SPEED_100_FULL; + + switch (hw->mac.type) { + case ixgbe_mac_X550: + hw->phy.speeds_supported |= IXGBE_LINK_SPEED_2_5GB_FULL; + hw->phy.speeds_supported |= IXGBE_LINK_SPEED_5GB_FULL; + break; + case ixgbe_mac_X550EM_x: + hw->phy.speeds_supported &= ~IXGBE_LINK_SPEED_100_FULL; + break; + default: + break; } - /* Internal PHY does not support 100 Mbps */ - if (hw->mac.type == ixgbe_mac_X550EM_x) - *speed &= ~IXGBE_LINK_SPEED_100_FULL; + return 0; +} + +/** + * ixgbe_get_copper_link_capabilities_generic - Determines link capabilities + * @hw: pointer to hardware structure + * @speed: pointer to link speed + * @autoneg: boolean auto-negotiation value + */ +s32 ixgbe_get_copper_link_capabilities_generic(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) +{ + s32 status = 0; + + *autoneg = true; + if (!hw->phy.speeds_supported) + status = ixgbe_get_copper_speeds_supported(hw); + *speed = hw->phy.speeds_supported; return status; } diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h index a3eec19c9fdf8..63689192b149a 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h @@ -3384,6 +3384,7 @@ struct ixgbe_phy_info { u32 phy_semaphore_mask; bool reset_disable; ixgbe_autoneg_advertised autoneg_advertised; + ixgbe_link_speed speeds_supported; enum ixgbe_smart_speed smart_speed; bool smart_speed_active; bool multispeed_fiber; -- GitLab From 1c7cf0784e4d448ed8a07c5fc1e3aac1528272f1 Mon Sep 17 00:00:00 2001 From: Tom Barbette Date: Fri, 26 Jun 2015 15:40:18 +0200 Subject: [PATCH 6037/7006] ixgbe: support for ethtool set_rxfh Allows to change the rxfh indirection table and/or key using ethtool interface. Signed-off-by: Tom Barbette Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 + .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 47 +++++++++++++++++++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 2 +- 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h index 8830c0fb5ffb5..edf1fb9132096 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h @@ -973,4 +973,5 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb, struct ixgbe_adapter *adapter, struct ixgbe_ring *tx_ring); u32 ixgbe_rss_indir_tbl_entries(struct ixgbe_adapter *adapter); +void ixgbe_store_reta(struct ixgbe_adapter *adapter); #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index f7aeb560a504a..b0cc439d7b018 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -2868,6 +2868,14 @@ static int ixgbe_set_rxnfc(struct net_device *dev, struct ethtool_rxnfc *cmd) return ret; } +static int ixgbe_rss_indir_tbl_max(struct ixgbe_adapter *adapter) +{ + if (adapter->hw.mac.type < ixgbe_mac_X550) + return 16; + else + return 64; +} + static u32 ixgbe_get_rxfh_key_size(struct net_device *netdev) { struct ixgbe_adapter *adapter = netdev_priv(netdev); @@ -2907,6 +2915,44 @@ static int ixgbe_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key, return 0; } +static int ixgbe_set_rxfh(struct net_device *netdev, const u32 *indir, + const u8 *key, const u8 hfunc) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int i; + u32 reta_entries = ixgbe_rss_indir_tbl_entries(adapter); + + if (hfunc) + return -EINVAL; + + /* Fill out the redirection table */ + if (indir) { + int max_queues = min_t(int, adapter->num_rx_queues, + ixgbe_rss_indir_tbl_max(adapter)); + + /*Allow at least 2 queues w/ SR-IOV.*/ + if ((adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) && + (max_queues < 2)) + max_queues = 2; + + /* Verify user input. */ + for (i = 0; i < reta_entries; i++) + if (indir[i] >= max_queues) + return -EINVAL; + + for (i = 0; i < reta_entries; i++) + adapter->rss_indir_tbl[i] = indir[i]; + } + + /* Fill out the rss hash key */ + if (key) + memcpy(adapter->rss_key, key, ixgbe_get_rxfh_key_size(netdev)); + + ixgbe_store_reta(adapter); + + return 0; +} + static int ixgbe_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) { @@ -3159,6 +3205,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = { .get_rxfh_indir_size = ixgbe_rss_indir_size, .get_rxfh_key_size = ixgbe_get_rxfh_key_size, .get_rxfh = ixgbe_get_rxfh, + .set_rxfh = ixgbe_set_rxfh, .get_channels = ixgbe_get_channels, .set_channels = ixgbe_set_channels, .get_ts_info = ixgbe_get_ts_info, diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 7389c9692c956..afdc7fb39b2c1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3313,7 +3313,7 @@ u32 ixgbe_rss_indir_tbl_entries(struct ixgbe_adapter *adapter) * * Write the RSS redirection table stored in adapter.rss_indir_tbl[] to HW. */ -static void ixgbe_store_reta(struct ixgbe_adapter *adapter) +void ixgbe_store_reta(struct ixgbe_adapter *adapter) { u32 i, reta_entries = ixgbe_rss_indir_tbl_entries(adapter); struct ixgbe_hw *hw = &adapter->hw; -- GitLab From 7e3f5c8881ba45eba1c74344b00558920008e6e6 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Thu, 9 Jul 2015 12:28:59 -0700 Subject: [PATCH 6038/7006] ixgbe: fix bounds checking in ixgbe_setup_tc for 82598 This patch resolves an issue where users were not able to dynamically set number of queues for 82598 via ethtool -L Reported-by: Tal Abudi Signed-off-by: Emil Tantilov Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index afdc7fb39b2c1..0853cf0f5861d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7848,9 +7848,10 @@ int ixgbe_setup_tc(struct net_device *dev, u8 tc) bool pools; /* Hardware supports up to 8 traffic classes */ - if (tc > adapter->dcb_cfg.num_tcs.pg_tcs || - (hw->mac.type == ixgbe_mac_82598EB && - tc < MAX_TRAFFIC_CLASS)) + if (tc > adapter->dcb_cfg.num_tcs.pg_tcs) + return -EINVAL; + + if (hw->mac.type == ixgbe_mac_82598EB && tc && tc < MAX_TRAFFIC_CLASS) return -EINVAL; pools = (find_first_zero_bit(&adapter->fwd_bitmask, 32) > 1); -- GitLab From 454adb008d78e4ecdfec3f2e5e9eb08ee5a60f1a Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Fri, 10 Jul 2015 14:19:22 -0700 Subject: [PATCH 6039/7006] ixgbe: Add support for reporting 2.5G link speed Now that we can do 2.5G link speed, we need to be able to report it. Also change the nested triadic involved in creating the log message to instead use a simpler switch statement to set a string pointer. Signed-off-by: Mark Rustad Signed-off-by: Jeff Kirsher --- .../net/ethernet/intel/ixgbe/ixgbe_ethtool.c | 7 +++++ drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 27 +++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c index b0cc439d7b018..ab2edc8e7703f 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ethtool.c @@ -166,6 +166,8 @@ static int ixgbe_get_settings(struct net_device *netdev, /* set the supported link speeds */ if (supported_link & IXGBE_LINK_SPEED_10GB_FULL) ecmd->supported |= SUPPORTED_10000baseT_Full; + if (supported_link & IXGBE_LINK_SPEED_2_5GB_FULL) + ecmd->supported |= SUPPORTED_2500baseX_Full; if (supported_link & IXGBE_LINK_SPEED_1GB_FULL) ecmd->supported |= SUPPORTED_1000baseT_Full; if (supported_link & IXGBE_LINK_SPEED_100_FULL) @@ -177,6 +179,8 @@ static int ixgbe_get_settings(struct net_device *netdev, ecmd->advertising |= ADVERTISED_100baseT_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_10GB_FULL) ecmd->advertising |= ADVERTISED_10000baseT_Full; + if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_2_5GB_FULL) + ecmd->advertising |= ADVERTISED_2500baseX_Full; if (hw->phy.autoneg_advertised & IXGBE_LINK_SPEED_1GB_FULL) ecmd->advertising |= ADVERTISED_1000baseT_Full; } else { @@ -286,6 +290,9 @@ static int ixgbe_get_settings(struct net_device *netdev, case IXGBE_LINK_SPEED_10GB_FULL: ethtool_cmd_speed_set(ecmd, SPEED_10000); break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + ethtool_cmd_speed_set(ecmd, SPEED_2500); + break; case IXGBE_LINK_SPEED_1GB_FULL: ethtool_cmd_speed_set(ecmd, SPEED_1000); break; diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 0853cf0f5861d..54dfad909001e 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6380,6 +6380,7 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) struct net_device *upper; struct list_head *iter; u32 link_speed = adapter->link_speed; + const char *speed_str; bool flow_rx, flow_tx; /* only continue if link was previously down */ @@ -6417,14 +6418,24 @@ static void ixgbe_watchdog_link_is_up(struct ixgbe_adapter *adapter) if (test_bit(__IXGBE_PTP_RUNNING, &adapter->state)) ixgbe_ptp_start_cyclecounter(adapter); - e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : - (link_speed == IXGBE_LINK_SPEED_100_FULL ? - "100 Mbps" : - "unknown speed"))), + switch (link_speed) { + case IXGBE_LINK_SPEED_10GB_FULL: + speed_str = "10 Gbps"; + break; + case IXGBE_LINK_SPEED_2_5GB_FULL: + speed_str = "2.5 Gbps"; + break; + case IXGBE_LINK_SPEED_1GB_FULL: + speed_str = "1 Gbps"; + break; + case IXGBE_LINK_SPEED_100_FULL: + speed_str = "100 Mbps"; + break; + default: + speed_str = "unknown speed"; + break; + } + e_info(drv, "NIC Link is Up %s, Flow Control: %s\n", speed_str, ((flow_rx && flow_tx) ? "RX/TX" : (flow_rx ? "RX" : (flow_tx ? "TX" : "None")))); -- GitLab From 7837e2867f56ec4435e75af54236732885303694 Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Fri, 10 Jul 2015 15:31:34 -0600 Subject: [PATCH 6040/7006] ixgbe: Remove bimodal SR-IOV disabling When unbinding an SR-IOV device with VFs configured from ixgbe, the driver behaves in one of two ways. If max_vfs was specified, the SR-IOV state is disabled, removing the VFs. The occurs regardless of whether the VF count was later modified through sysfs. If however max_vfs is zero, such as by not specifying the module parameter, the VFs persist after the PF is unbound from ixgbe. If the PF is then bound to vfio-pci to be assigned to a VM, the PF is non-functional. >From the comment, commit da36b64736cf ("ixgbe: Implement PCI SR-IOV sysfs callback operation") clearly intended this alternate behavior, but probably didn't realize the PF doesn't work in this mode. This bimodal behavior is confusing to users and results in a state where the PF is broken for other uses unless the user sets sriov_numvfs to zero prior to unbinding the device. Remove this behavior so that VFs are removed and the PF is functional for other uses after unbind, regardless of the way VFs are enabled. Signed-off-by: Alex Williamson Acked-by: Greg Rose Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 54dfad909001e..63b2cfe9416b2 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -9023,12 +9023,7 @@ static void ixgbe_remove(struct pci_dev *pdev) unregister_netdev(netdev); #ifdef CONFIG_PCI_IOV - /* - * Only disable SR-IOV on unload if the user specified the now - * deprecated max_vfs module parameter. - */ - if (max_vfs) - ixgbe_disable_sriov(adapter); + ixgbe_disable_sriov(adapter); #endif ixgbe_clear_interrupt_scheme(adapter); -- GitLab From 990a2d6ed543bd18b864b8a11f7be3368c67ccea Mon Sep 17 00:00:00 2001 From: Mark Rustad Date: Wed, 29 Jul 2015 16:00:38 -0700 Subject: [PATCH 6041/7006] ixgbe: Resolve "initialized field overwritten" warnings Resolve warnings resulting from redundant initialization of the get_bus_info field in the mac_ops_X550* structures. Signed-off-by: Mark Rustad Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher --- drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c index 96f603f435eed..9fe9445cd73b0 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c @@ -1935,7 +1935,6 @@ static void ixgbe_set_source_address_pruning_X550(struct ixgbe_hw *hw, .get_mac_addr = &ixgbe_get_mac_addr_generic, \ .get_device_caps = &ixgbe_get_device_caps_generic, \ .stop_adapter = &ixgbe_stop_adapter_generic, \ - .get_bus_info = &ixgbe_get_bus_info_generic, \ .set_lan_id = &ixgbe_set_lan_id_multi_port_pcie, \ .read_analog_reg8 = NULL, \ .write_analog_reg8 = NULL, \ -- GitLab From de4c1f8ba302ccf4f2b3b17dc614b0a0b14d351a Mon Sep 17 00:00:00 2001 From: Tom Herbert Date: Tue, 1 Sep 2015 18:11:04 -0700 Subject: [PATCH 6042/7006] flow_dissector: Fix function argument ordering dependency Commit c6cc1ca7f4d70c ("flowi: Abstract out functions to get flow hash based on flowi") introduced a bug in __skb_set_sw_hash where we require a dependency on evaluating arguments in a function in order. There is no such ordering enforced in C, so this incorrect. This patch fixes that by splitting out the arguments. This bug was found via a compiler warning that keys may be uninitialized. Signed-off-by: Tom Herbert Signed-off-by: David S. Miller --- include/linux/skbuff.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 9e62687c70f32..eabfb810bc629 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1035,9 +1035,9 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) { if (!skb->l4_hash && !skb->sw_hash) { struct flow_keys keys; + __u32 hash = __get_hash_from_flowi6(fl6, &keys); - __skb_set_sw_hash(skb, __get_hash_from_flowi6(fl6, &keys), - flow_keys_have_l4(&keys)); + __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); } return skb->hash; @@ -1049,9 +1049,9 @@ static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) { if (!skb->l4_hash && !skb->sw_hash) { struct flow_keys keys; + __u32 hash = __get_hash_from_flowi4(fl4, &keys); - __skb_set_sw_hash(skb, __get_hash_from_flowi4(fl4, &keys), - flow_keys_have_l4(&keys)); + __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); } return skb->hash; -- GitLab From 20a17bf6c04e3eca8824c930ecc55ab832558e3b Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 1 Sep 2015 21:19:17 -0700 Subject: [PATCH 6043/7006] flow_dissector: Use 'const' where possible. Signed-off-by: David S. Miller --- include/linux/skbuff.h | 8 ++-- include/net/flow.h | 8 ++-- net/core/flow_dissector.c | 79 ++++++++++++++++++++------------------- 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index eabfb810bc629..2738d355cdf9a 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1029,9 +1029,9 @@ static inline __u32 skb_get_hash(struct sk_buff *skb) return skb->hash; } -__u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6); +__u32 __skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6); -static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) +static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6) { if (!skb->l4_hash && !skb->sw_hash) { struct flow_keys keys; @@ -1043,9 +1043,9 @@ static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) return skb->hash; } -__u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl); +__u32 __skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl); -static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) +static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl4) { if (!skb->l4_hash && !skb->sw_hash) { struct flow_keys keys; diff --git a/include/net/flow.h b/include/net/flow.h index dafe97c3c048b..acd6a096250e6 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -244,18 +244,18 @@ void flow_cache_flush(struct net *net); void flow_cache_flush_deferred(struct net *net); extern atomic_t flow_cache_genid; -__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys); +__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys); -static inline __u32 get_hash_from_flowi6(struct flowi6 *fl6) +static inline __u32 get_hash_from_flowi6(const struct flowi6 *fl6) { struct flow_keys keys; return __get_hash_from_flowi6(fl6, &keys); } -__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys); +__u32 __get_hash_from_flowi4(const struct flowi4 *fl4, struct flow_keys *keys); -static inline __u32 get_hash_from_flowi4(struct flowi4 *fl4) +static inline __u32 get_hash_from_flowi4(const struct flowi4 *fl4) { struct flow_keys keys; diff --git a/net/core/flow_dissector.c b/net/core/flow_dissector.c index 345a0408cfe4a..d79699c9d1b9e 100644 --- a/net/core/flow_dissector.c +++ b/net/core/flow_dissector.c @@ -19,14 +19,14 @@ #include #include -static bool skb_flow_dissector_uses_key(struct flow_dissector *flow_dissector, - enum flow_dissector_key_id key_id) +static bool dissector_uses_key(const struct flow_dissector *flow_dissector, + enum flow_dissector_key_id key_id) { return flow_dissector->used_keys & (1 << key_id); } -static void skb_flow_dissector_set_key(struct flow_dissector *flow_dissector, - enum flow_dissector_key_id key_id) +static void dissector_set_key(struct flow_dissector *flow_dissector, + enum flow_dissector_key_id key_id) { flow_dissector->used_keys |= (1 << key_id); } @@ -51,20 +51,20 @@ void skb_flow_dissector_init(struct flow_dissector *flow_dissector, * boundaries of unsigned short. */ BUG_ON(key->offset > USHRT_MAX); - BUG_ON(skb_flow_dissector_uses_key(flow_dissector, - key->key_id)); + BUG_ON(dissector_uses_key(flow_dissector, + key->key_id)); - skb_flow_dissector_set_key(flow_dissector, key->key_id); + dissector_set_key(flow_dissector, key->key_id); flow_dissector->offset[key->key_id] = key->offset; } /* Ensure that the dissector always includes control and basic key. * That way we are able to avoid handling lack of these in fast path. */ - BUG_ON(!skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_CONTROL)); - BUG_ON(!skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_BASIC)); + BUG_ON(!dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_CONTROL)); + BUG_ON(!dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_BASIC)); } EXPORT_SYMBOL(skb_flow_dissector_init); @@ -154,8 +154,8 @@ bool __skb_flow_dissect(const struct sk_buff *skb, FLOW_DISSECTOR_KEY_BASIC, target_container); - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_ETH_ADDRS)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_ETH_ADDRS)) { struct ethhdr *eth = eth_hdr(skb); struct flow_dissector_key_eth_addrs *key_eth_addrs; @@ -178,8 +178,8 @@ ip: ip_proto = iph->protocol; - if (!skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV4_ADDRS)) + if (!dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV4_ADDRS)) break; key_addrs = skb_flow_dissector_target(flow_dissector, @@ -218,8 +218,8 @@ ipv6: ip_proto = iph->nexthdr; nhoff += sizeof(struct ipv6hdr); - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { struct flow_dissector_key_ipv6_addrs *key_ipv6_addrs; key_ipv6_addrs = skb_flow_dissector_target(flow_dissector, @@ -232,8 +232,8 @@ ipv6: flow_label = ip6_flowlabel(iph); if (flow_label) { - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_FLOW_LABEL)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_FLOW_LABEL)) { key_tags = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_FLOW_LABEL, target_container); @@ -257,8 +257,8 @@ ipv6: if (!vlan) goto out_bad; - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_VLANID)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_VLANID)) { key_tags = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_VLANID, target_container); @@ -298,8 +298,8 @@ ipv6: if (!hdr) goto out_bad; - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_TIPC_ADDRS)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_TIPC_ADDRS)) { key_addrs = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_TIPC_ADDRS, target_container); @@ -320,8 +320,8 @@ mpls: if ((ntohl(hdr[0].entry) & MPLS_LS_LABEL_MASK) >> MPLS_LS_LABEL_SHIFT == MPLS_LABEL_ENTROPY) { - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) { key_keyid = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_MPLS_ENTROPY, target_container); @@ -374,8 +374,8 @@ ip_proto_again: if (!keyid) goto out_bad; - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_GRE_KEYID)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_GRE_KEYID)) { key_keyid = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_GRE_KEYID, target_container); @@ -470,8 +470,8 @@ ip_proto_again: break; } - if (skb_flow_dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_PORTS)) { + if (dissector_uses_key(flow_dissector, + FLOW_DISSECTOR_KEY_PORTS)) { key_ports = skb_flow_dissector_target(flow_dissector, FLOW_DISSECTOR_KEY_PORTS, target_container); @@ -497,18 +497,21 @@ static __always_inline void __flow_hash_secret_init(void) net_get_random_once(&hashrnd, sizeof(hashrnd)); } -static __always_inline u32 __flow_hash_words(u32 *words, u32 length, u32 keyval) +static __always_inline u32 __flow_hash_words(const u32 *words, u32 length, + u32 keyval) { return jhash2(words, length, keyval); } -static inline void *flow_keys_hash_start(struct flow_keys *flow) +static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow) { + const void *p = flow; + BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32)); - return (void *)flow + FLOW_KEYS_HASH_OFFSET; + return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET); } -static inline size_t flow_keys_hash_length(struct flow_keys *flow) +static inline size_t flow_keys_hash_length(const struct flow_keys *flow) { size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); @@ -598,7 +601,7 @@ static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) __flow_hash_consistentify(keys); - hash = __flow_hash_words((u32 *)flow_keys_hash_start(keys), + hash = __flow_hash_words(flow_keys_hash_start(keys), flow_keys_hash_length(keys), keyval); if (!hash) hash = 1; @@ -677,7 +680,7 @@ __u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) } EXPORT_SYMBOL(skb_get_hash_perturb); -__u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) +__u32 __skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6) { struct flow_keys keys; @@ -701,7 +704,7 @@ __u32 __skb_get_hash_flowi6(struct sk_buff *skb, struct flowi6 *fl6) } EXPORT_SYMBOL(__skb_get_hash_flowi6); -__u32 __skb_get_hash_flowi4(struct sk_buff *skb, struct flowi4 *fl4) +__u32 __skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl4) { struct flow_keys keys; @@ -787,7 +790,7 @@ u32 skb_get_poff(const struct sk_buff *skb) return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); } -__u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys) +__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys) { memset(keys, 0, sizeof(*keys)); @@ -806,7 +809,7 @@ __u32 __get_hash_from_flowi6(struct flowi6 *fl6, struct flow_keys *keys) } EXPORT_SYMBOL(__get_hash_from_flowi6); -__u32 __get_hash_from_flowi4(struct flowi4 *fl4, struct flow_keys *keys) +__u32 __get_hash_from_flowi4(const struct flowi4 *fl4, struct flow_keys *keys) { memset(keys, 0, sizeof(*keys)); -- GitLab From 2a8ceedf787167e6b1670b89d44e8dffca14d19c Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 19 Aug 2015 10:48:55 +0200 Subject: [PATCH 6044/7006] drm/i915: Add audio pin sense / ELD callback This callback will be called by the i915 driver to notify the hda driver that its HDMI information needs to be refreshed, i e, that audio output is now available (or unavailable) - usually as a result of a monitor being plugged in (or unplugged). Signed-off-by: David Henningsson Reviewed-by: Jani Nikula Acked-by: Daniel Vetter Signed-off-by: Takashi Iwai --- include/drm/i915_component.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index c9a8b64aa33b1..ab5bde3736b42 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -34,6 +34,18 @@ struct i915_audio_component { void (*codec_wake_override)(struct device *, bool enable); int (*get_cdclk_freq)(struct device *); } *ops; + + const struct i915_audio_component_audio_ops { + void *audio_ptr; + /** + * Call from i915 driver, notifying the HDA driver that + * pin sense and/or ELD information has changed. + * @audio_ptr: HDA driver object + * @port: Which port has changed (PORTA / PORTB / PORTC etc) + * @port_mst_index: Index within that port, for DisplayPort multistreaming + */ + void (*pin_eld_notify)(void *audio_ptr, int port, int port_mst_index); + } *audio_ops; }; #endif /* _I915_COMPONENT_H_ */ -- GitLab From 51e1d83cab9988716ae68801a721f4df0aaa374b Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 19 Aug 2015 10:48:56 +0200 Subject: [PATCH 6045/7006] drm/i915: Call audio pin/ELD notify function When the audio codec is enabled or disabled, notify the audio driver. This will enable the audio driver to get the notification at all times (even when audio is in different powersave states). Signed-off-by: David Henningsson Reviewed-by: Jani Nikula Acked-by: Daniel Vetter Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_audio.c | 23 ++++++++++++++++++++--- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index fd1de451c8c6b..1fc327d3421e3 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1809,6 +1809,7 @@ struct drm_i915_private { struct drm_property *force_audio_property; /* hda/i915 audio component */ + struct i915_audio_component *audio_component; bool audio_component_registered; uint32_t hw_context_size; diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 3da9b8409f205..969835db8ff70 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -399,6 +399,9 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) struct drm_connector *connector; struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_audio_component *acomp = dev_priv->audio_component; + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + enum port port = intel_dig_port->port; connector = drm_select_eld(encoder, mode); if (!connector) @@ -419,6 +422,9 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) if (dev_priv->display.audio_codec_enable) dev_priv->display.audio_codec_enable(connector, intel_encoder, mode); + + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) + acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, 0); } /** @@ -428,13 +434,20 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) * The disable sequences must be performed before disabling the transcoder or * port. */ -void intel_audio_codec_disable(struct intel_encoder *encoder) +void intel_audio_codec_disable(struct intel_encoder *intel_encoder) { - struct drm_device *dev = encoder->base.dev; + struct drm_encoder *encoder = &intel_encoder->base; + struct drm_device *dev = encoder->dev; struct drm_i915_private *dev_priv = dev->dev_private; + struct i915_audio_component *acomp = dev_priv->audio_component; + struct intel_digital_port *intel_dig_port = enc_to_dig_port(encoder); + enum port port = intel_dig_port->port; if (dev_priv->display.audio_codec_disable) - dev_priv->display.audio_codec_disable(encoder); + dev_priv->display.audio_codec_disable(intel_encoder); + + if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) + acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, 0); } /** @@ -525,12 +538,14 @@ static int i915_audio_component_bind(struct device *i915_dev, struct device *hda_dev, void *data) { struct i915_audio_component *acomp = data; + struct drm_i915_private *dev_priv = dev_to_i915(i915_dev); if (WARN_ON(acomp->ops || acomp->dev)) return -EEXIST; acomp->ops = &i915_audio_component_ops; acomp->dev = i915_dev; + dev_priv->audio_component = acomp; return 0; } @@ -539,9 +554,11 @@ static void i915_audio_component_unbind(struct device *i915_dev, struct device *hda_dev, void *data) { struct i915_audio_component *acomp = data; + struct drm_i915_private *dev_priv = dev_to_i915(i915_dev); acomp->ops = NULL; acomp->dev = NULL; + dev_priv->audio_component = NULL; } static const struct component_ops i915_audio_component_bind_ops = { -- GitLab From 45c053df5bdc4843cf19b920db6ab819ddc27ff7 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 19 Aug 2015 10:48:57 +0200 Subject: [PATCH 6046/7006] ALSA: hda - allow codecs to access the i915 pin/ELD callback This lets the interested codec be notified when an i915 pin/ELD event happens. [tiwai: Fixed a trivial build error for CONFIG_SND_HDA_I915=n] Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- include/sound/hda_i915.h | 7 +++++++ sound/hda/hdac_i915.c | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h index adb5ba5cbd9d0..a5b5cae03e87f 100644 --- a/include/sound/hda_i915.h +++ b/include/sound/hda_i915.h @@ -4,12 +4,15 @@ #ifndef __SOUND_HDA_I915_H #define __SOUND_HDA_I915_H +#include + #ifdef CONFIG_SND_HDA_I915 int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable); int snd_hdac_display_power(struct hdac_bus *bus, bool enable); int snd_hdac_get_display_clk(struct hdac_bus *bus); int snd_hdac_i915_init(struct hdac_bus *bus); int snd_hdac_i915_exit(struct hdac_bus *bus); +int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *); #else static int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { @@ -31,6 +34,10 @@ static inline int snd_hdac_i915_exit(struct hdac_bus *bus) { return 0; } +static inline int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *ops) +{ + return -ENODEV; +} #endif #endif /* __SOUND_HDA_I915_H */ diff --git a/sound/hda/hdac_i915.c b/sound/hda/hdac_i915.c index 5676b849379d4..55c3df4458f79 100644 --- a/sound/hda/hdac_i915.c +++ b/sound/hda/hdac_i915.c @@ -134,6 +134,16 @@ static int hdac_component_master_match(struct device *dev, void *data) return !strcmp(dev->driver->name, "i915"); } +int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *aops) +{ + if (WARN_ON(!hdac_acomp)) + return -ENODEV; + + hdac_acomp->audio_ops = aops; + return 0; +} +EXPORT_SYMBOL_GPL(snd_hdac_i915_register_notifier); + int snd_hdac_i915_init(struct hdac_bus *bus) { struct component_match *match = NULL; -- GitLab From 25adc137c546ce297b4d76820913dda11cad3891 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Wed, 19 Aug 2015 10:48:58 +0200 Subject: [PATCH 6047/7006] ALSA: hda - Wake the codec up on pin/ELD notify events Whenever there is an event from the i915 driver, wake the codec and recheck plug/unplug + ELD status. This fixes the issue with lost unsol events in power save mode, the codec and controller can now sleep in D3 and still know when the HDMI monitor has been connected. Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_hdmi.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index a97db5fc8a151..932292ce5ce75 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -37,6 +37,8 @@ #include #include #include +#include +#include #include "hda_codec.h" #include "hda_local.h" #include "hda_jack.h" @@ -144,6 +146,9 @@ struct hdmi_spec { */ struct hda_multi_out multiout; struct hda_pcm_stream pcm_playback; + + /* i915/powerwell (Haswell+/Valleyview+) specific */ + struct i915_audio_component_audio_ops i915_audio_ops; }; @@ -2191,6 +2196,9 @@ static void generic_hdmi_free(struct hda_codec *codec) struct hdmi_spec *spec = codec->spec; int pin_idx; + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + snd_hdac_i915_register_notifier(NULL); + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); @@ -2316,6 +2324,14 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, snd_hda_codec_set_power_to_all(codec, fg, power_state); } +static void intel_pin_eld_notify(void *audio_ptr, int port, int port_mst_index) +{ + struct hda_codec *codec = audio_ptr; + int pin_nid = port + 0x04; + + check_presence_and_report(codec, pin_nid); +} + static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -2342,8 +2358,12 @@ static int patch_generic_hdmi(struct hda_codec *codec) if (is_valleyview_plus(codec) || is_skylake(codec)) codec->core.link_power_control = 1; - if (is_haswell_plus(codec) || is_valleyview_plus(codec)) + if (is_haswell_plus(codec) || is_valleyview_plus(codec)) { codec->depop_delay = 0; + spec->i915_audio_ops.audio_ptr = codec; + spec->i915_audio_ops.pin_eld_notify = intel_pin_eld_notify; + snd_hdac_i915_register_notifier(&spec->i915_audio_ops); + } if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; -- GitLab From 6869de380e8c11c31b608bb2502dcacd634eda13 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 2 Sep 2015 12:24:55 +0200 Subject: [PATCH 6048/7006] ALSA: hda - Fix missing inline for dummy snd_hdac_set_codec_wakeup() This seems overlooked. Fixes: 98d8fc6c5d36 ('ALSA: hda - Move hda_i915.c from sound/pci/hda to sound/hda') Cc: # v4.2+ Signed-off-by: Takashi Iwai --- include/sound/hda_i915.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/sound/hda_i915.h b/include/sound/hda_i915.h index a5b5cae03e87f..930b41e5acf4c 100644 --- a/include/sound/hda_i915.h +++ b/include/sound/hda_i915.h @@ -14,7 +14,7 @@ int snd_hdac_i915_init(struct hdac_bus *bus); int snd_hdac_i915_exit(struct hdac_bus *bus); int snd_hdac_i915_register_notifier(const struct i915_audio_component_audio_ops *); #else -static int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) +static inline int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable) { return 0; } -- GitLab From 57817e619a215588739f3f644986c78b586b541b Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:31:54 +0200 Subject: [PATCH 6049/7006] video: fbdev: atmel_lcdfb: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni Signed-off-by: Tomi Valkeinen --- drivers/video/fbdev/atmel_lcdfb.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 016cae1425a4e..19eb42b57d874 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include -- GitLab From 79a2b161c12a1b751f53a7698494cb722530bca5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Aug 2015 22:55:05 +0300 Subject: [PATCH 6050/7006] drm/dp: Define AUX_RETRY_INTERVAL as 500 us MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently we react to native and i2c defers by waiting either 400-500 us or 500-600 us, depending on which code path we take. Consolidate them all to one define AUX_RETRY_INTERVAL which defines the minimum interval. Since we've been using two different intervals pick the longer of them and define AUX_RETRY_INTERVAL as 500 us. For the maximum just use AUX_RETRY_INTERVAL+100 us. I want to have a define for this so that I can use it when calculating the estimated duration of i2c-over-aux transfers. Without a define it would be very easy to change the sleep duration and neglect to update the i2c-over-aux estimates. Cc: Simon Farnsworth Cc: moosotc@gmail.com Signed-off-by: Ville Syrjälä Reviewed-by: Simon Farnsworth Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_dp_helper.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 80a02a412607f..7069e54e5b43c 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -159,6 +159,8 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw) } EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate); +#define AUX_RETRY_INTERVAL 500 /* us */ + /** * DOC: dp helpers * @@ -213,7 +215,7 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request, return -EIO; case DP_AUX_NATIVE_REPLY_DEFER: - usleep_range(400, 500); + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); break; } } @@ -476,7 +478,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) * For now just defer for long enough to hopefully be * safe for all use-cases. */ - usleep_range(500, 600); + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); continue; default: @@ -506,7 +508,7 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) aux->i2c_defer_count++; if (defer_i2c < 7) defer_i2c++; - usleep_range(400, 500); + usleep_range(AUX_RETRY_INTERVAL, AUX_RETRY_INTERVAL + 100); continue; default: -- GitLab From 4efa83c8c786ab7ec7982e3dd348cb7e7ecbeb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 1 Sep 2015 20:12:54 +0300 Subject: [PATCH 6051/7006] drm/dp: Adjust i2c-over-aux retry count based on message size and i2c bus speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calculate the number of retries we should do for each i2c-over-aux message based on the time it takes to perform the i2c transfer vs. the aux transfer. We assume the shortest possible length for the aux transfer, and the longest possible (exluding clock stretching) for the i2c transfer. The DP spec has some examples on how to calculate this, but we don't calculate things quite the same way. The spec doesn't account for the retry interval (assumes immediate retry on defer), and doesn't assume the best/worst case behaviour as we do. Note that currently we assume 10 kHz speed for the i2c bus. Some real world devices (eg. some Apple DP->VGA dongle) fails with less than 16 retries. and that would correspond to something close to 15 kHz (with our method of calculating things) But let's just go for 10 kHz to be on the safe side. Ideally we should query/set the i2c bus speed via DPCD but for now this should at leaast remove the regression from the 1->16 byte trasnfer size change. And of course if the sink completes the transfer quicker this shouldn't slow things down since we don't change the interval between retries. I did a few experiments with a DP->DVI dongle I have that allows you to change the i2c bus speed. Here are the results of me changing the actual bus speed and the assumed bus speed and seeing when we start to fail the operation: actual i2c khz assumed i2c khz max retries 1 1 ok -> 2 fail 211 ok -> 106 fail 5 8 ok -> 9 fail 27 ok -> 24 fail 10 17 ok -> 18 fail 13 ok -> 12 fail 100 210 ok -> 211 fail 2 ok -> 1 fail So based on that we have a fairly decent safety margin baked into the formula to calculate the max number of retries. Fixes a regression with some DP dongles from: commit 1d002fa720738bcd0bddb9178e9ea0773288e1dd Author: Simon Farnsworth Date: Tue Feb 10 18:38:08 2015 +0000 drm/dp: Use large transactions for I2C over AUX v2: Use best case for AUX and worst case for i2c (Simon Farnsworth) Add a define our AUX retry interval and account for it v3: Make everything usecs to avoid confusion about units (Daniel) Add a comment reminding people about the AUX bitrate (Daniel) Use DIV_ROUND_UP() since we're after the "worst" case for i2c Cc: Simon Farnsworth Cc: moosotc@gmail.com Tested-by: moosotc@gmail.com Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91451 Reviewed-by: Simon Farnsworth Reviewed-by: Daniel Vetter Signed-off-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_dp_helper.c | 84 ++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 7069e54e5b43c..214a4c649d568 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -424,6 +424,81 @@ static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter) I2C_FUNC_10BIT_ADDR; } +#define AUX_PRECHARGE_LEN 10 /* 10 to 16 */ +#define AUX_SYNC_LEN (16 + 4) /* preamble + AUX_SYNC_END */ +#define AUX_STOP_LEN 4 +#define AUX_CMD_LEN 4 +#define AUX_ADDRESS_LEN 20 +#define AUX_REPLY_PAD_LEN 4 +#define AUX_LENGTH_LEN 8 + +/* + * Calculate the duration of the AUX request/reply in usec. Gives the + * "best" case estimate, ie. successful while as short as possible. + */ +static int drm_dp_aux_req_duration(const struct drm_dp_aux_msg *msg) +{ + int len = AUX_PRECHARGE_LEN + AUX_SYNC_LEN + AUX_STOP_LEN + + AUX_CMD_LEN + AUX_ADDRESS_LEN + AUX_LENGTH_LEN; + + if ((msg->request & DP_AUX_I2C_READ) == 0) + len += msg->size * 8; + + return len; +} + +static int drm_dp_aux_reply_duration(const struct drm_dp_aux_msg *msg) +{ + int len = AUX_PRECHARGE_LEN + AUX_SYNC_LEN + AUX_STOP_LEN + + AUX_CMD_LEN + AUX_REPLY_PAD_LEN; + + /* + * For read we expect what was asked. For writes there will + * be 0 or 1 data bytes. Assume 0 for the "best" case. + */ + if (msg->request & DP_AUX_I2C_READ) + len += msg->size * 8; + + return len; +} + +#define I2C_START_LEN 1 +#define I2C_STOP_LEN 1 +#define I2C_ADDR_LEN 9 /* ADDRESS + R/W + ACK/NACK */ +#define I2C_DATA_LEN 9 /* DATA + ACK/NACK */ + +/* + * Calculate the length of the i2c transfer in usec, assuming + * the i2c bus speed is as specified. Gives the the "worst" + * case estimate, ie. successful while as long as possible. + * Doesn't account the the "MOT" bit, and instead assumes each + * message includes a START, ADDRESS and STOP. Neither does it + * account for additional random variables such as clock stretching. + */ +static int drm_dp_i2c_msg_duration(const struct drm_dp_aux_msg *msg, + int i2c_speed_khz) +{ + /* AUX bitrate is 1MHz, i2c bitrate as specified */ + return DIV_ROUND_UP((I2C_START_LEN + I2C_ADDR_LEN + + msg->size * I2C_DATA_LEN + + I2C_STOP_LEN) * 1000, i2c_speed_khz); +} + +/* + * Deterine how many retries should be attempted to successfully transfer + * the specified message, based on the estimated durations of the + * i2c and AUX transfers. + */ +static int drm_dp_i2c_retry_count(const struct drm_dp_aux_msg *msg, + int i2c_speed_khz) +{ + int aux_time_us = drm_dp_aux_req_duration(msg) + + drm_dp_aux_reply_duration(msg); + int i2c_time_us = drm_dp_i2c_msg_duration(msg, i2c_speed_khz); + + return DIV_ROUND_UP(i2c_time_us, aux_time_us + AUX_RETRY_INTERVAL); +} + /* * Transfer a single I2C-over-AUX message and handle various error conditions, * retrying the transaction as appropriate. It is assumed that the @@ -436,13 +511,18 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) { unsigned int retry, defer_i2c; int ret; - /* * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device * is required to retry at least seven times upon receiving AUX_DEFER * before giving up the AUX transaction. + * + * We also try to account for the i2c bus speed. + * FIXME currently assumes 10 kHz as some real world devices seem + * to require it. We should query/set the speed via DPCD if supported. */ - for (retry = 0, defer_i2c = 0; retry < (7 + defer_i2c); retry++) { + int max_retries = max(7, drm_dp_i2c_retry_count(msg, 10)); + + for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) { mutex_lock(&aux->hw_mutex); ret = aux->transfer(aux, msg); mutex_unlock(&aux->hw_mutex); -- GitLab From f36203be608a38a5b5523a7aa52cc72f757b9679 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Wed, 26 Aug 2015 22:55:07 +0300 Subject: [PATCH 6052/7006] drm/dp: Add dp_aux_i2c_speed_khz module param to set the assume i2c bus speed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To help with debugging i2c-over-aux issues, add a module parameter than can be used to tweak the assumed i2c bus speed, and thus the maximum number of retries we will do for each aux message. Cc: Simon Farnsworth Cc: moosotc@gmail.com Signed-off-by: Ville Syrjälä Reviewed-by: Simon Farnsworth Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/drm_dp_helper.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index 214a4c649d568..291734e87fca7 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -499,6 +499,15 @@ static int drm_dp_i2c_retry_count(const struct drm_dp_aux_msg *msg, return DIV_ROUND_UP(i2c_time_us, aux_time_us + AUX_RETRY_INTERVAL); } +/* + * FIXME currently assumes 10 kHz as some real world devices seem + * to require it. We should query/set the speed via DPCD if supported. + */ +static int dp_aux_i2c_speed_khz __read_mostly = 10; +module_param_unsafe(dp_aux_i2c_speed_khz, int, 0644); +MODULE_PARM_DESC(dp_aux_i2c_speed_khz, + "Assumed speed of the i2c bus in kHz, (1-400, default 10)"); + /* * Transfer a single I2C-over-AUX message and handle various error conditions, * retrying the transaction as appropriate. It is assumed that the @@ -517,10 +526,8 @@ static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg) * before giving up the AUX transaction. * * We also try to account for the i2c bus speed. - * FIXME currently assumes 10 kHz as some real world devices seem - * to require it. We should query/set the speed via DPCD if supported. */ - int max_retries = max(7, drm_dp_i2c_retry_count(msg, 10)); + int max_retries = max(7, drm_dp_i2c_retry_count(msg, dp_aux_i2c_speed_khz)); for (retry = 0, defer_i2c = 0; retry < (max_retries + defer_i2c); retry++) { mutex_lock(&aux->hw_mutex); -- GitLab From 51bc140431e233284660b1d22c47dec9ecdb521e Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 31 Aug 2015 15:10:39 +0100 Subject: [PATCH 6053/7006] drm/i915: Always mark the object as dirty when used by the GPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There have been many hard to track down bugs whereby userspace forgot to flag a write buffer and then cause graphics corruption or a hung GPU when that buffer was later purged under memory pressure (as the buffer appeared clean, its pages would have been evicted rather than preserved and any changes more recent than in the backing storage would be lost). In retrospect this is a rare optimisation against memory pressure, already the slow path. If we always mark the buffer as dirty when accessed by the GPU, anything not used can still be evicted cheaply (ideal behaviour for mark-and-sweep eviction) but we do not run the risk of corruption. For correct read serialisation, userspace still has to notify when the GPU writes to an object. However, there are certain situations under which userspace may wish to tell white lies to the kernel... Signed-off-by: Chris Wilson Cc: Daniel Vetter Cc: Kristian Høgsberg Cc: Jesse Barnes Cc: "Goel, Akash" Cc: Michał Winiarski Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c index 923a3c4bf0b79..a953d4975b8c0 100644 --- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c +++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c @@ -1032,6 +1032,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, u32 old_read = obj->base.read_domains; u32 old_write = obj->base.write_domain; + obj->dirty = 1; /* be paranoid */ obj->base.write_domain = obj->base.pending_write_domain; if (obj->base.write_domain == 0) obj->base.pending_read_domains |= obj->base.read_domains; @@ -1039,7 +1040,6 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas, i915_vma_move_to_active(vma, req); if (obj->base.write_domain) { - obj->dirty = 1; i915_gem_request_assign(&obj->last_write_req, req); intel_fb_obj_invalidate(obj, ORIGIN_CS); -- GitLab From 16f7249ddf831f5ec0e1358222ce5db300446b84 Mon Sep 17 00:00:00 2001 From: Artem Savkov Date: Wed, 2 Sep 2015 13:41:18 +0200 Subject: [PATCH 6054/7006] uapi/drm/i915_drm.h: fix userspace compilation. commit 346add7834557b5b9628b9bf2387106d42e631d4 Author: Daniel Vetter Date: Tue Jul 14 18:07:30 2015 +0200 drm/i915: Use expcitly fixed type in compat32 structs changed the type of param field in drm_i915_getparam from int to s32. This header is exported to userspace and needs to use userspace type __s32 instead. This fixes userspace compilation errors like the following: include/drm/i915_drm.h:361:2: error: unknown type name 's32' s32 param; Signed-off-by: Artem Savkov Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- include/uapi/drm/i915_drm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/drm/i915_drm.h b/include/uapi/drm/i915_drm.h index dbd16a2d37db6..fd5aa47bd6892 100644 --- a/include/uapi/drm/i915_drm.h +++ b/include/uapi/drm/i915_drm.h @@ -358,7 +358,7 @@ typedef struct drm_i915_irq_wait { #define I915_PARAM_HAS_RESOURCE_STREAMER 36 typedef struct drm_i915_getparam { - s32 param; + __s32 param; /* * WARNING: Using pointers instead of fixed-size u64 means we need to write * compat32 code. Don't repeat this mistake. -- GitLab From 4e3d1e26c2b2c40ebff69f2825fa862bfcf082d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Thu, 27 Aug 2015 23:56:12 +0300 Subject: [PATCH 6055/7006] drm/i915: Pass hpd_status_i915[] to intel_get_hpd_pins() in pre-g4x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pass the correct hpd[] array to intel_get_hpd_pins() on pre-g4x platforms. This got broken in the following commit: commit fd63e2a972c670887e5e8a08440111d3812c0996 Author: Imre Deak Date: Tue Jul 21 15:32:44 2015 -0700 drm/i915: combine i9xx_get_hpd_pins and pch_get_hpd_pins Cc: Imre Deak Signed-off-by: Ville Syrjälä Reviewed-by: Paulo Zanoni Reviewed-by: Daniel Vetter Reviewed-by: Egbert Eich Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_irq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c index d94c92d842fb9..a2bceb70a3fdf 100644 --- a/drivers/gpu/drm/i915/i915_irq.c +++ b/drivers/gpu/drm/i915/i915_irq.c @@ -1558,7 +1558,7 @@ static void i9xx_hpd_irq_handler(struct drm_device *dev) u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915; intel_get_hpd_pins(&pin_mask, &long_mask, hotplug_trigger, - hotplug_trigger, hpd_status_g4x, + hotplug_trigger, hpd_status_i915, i9xx_port_hotplug_long_detect); intel_hpd_irq_handler(dev, pin_mask, long_mask); } -- GitLab From a457974f1b9524a6e7d0a0be10df760e7802d32f Mon Sep 17 00:00:00 2001 From: Andrew Elble Date: Mon, 31 Aug 2015 12:06:41 -0400 Subject: [PATCH 6056/7006] nfsd: deal with DELEGRETURN racing with CB_RECALL We have observed the server sending recalls for delegation stateids that have already been successfully returned. Change nfsd4_cb_recall_done() to return success if the client has returned the delegation. While this does not completely eliminate the sending of recalls for delegations that have already been returned, this does prevent unnecessarily declaring the callback path to be down. Reported-by: Eric Meddaugh Signed-off-by: Andrew Elble Acked-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 08746ec1d44a5..0f1d5691b7957 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3510,6 +3510,9 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb, { struct nfs4_delegation *dp = cb_to_delegation(cb); + if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID) + return 1; + switch (task->tk_status) { case 0: return 1; -- GitLab From 179239a7ae805f7695167c62a97eac3efe52d7af Mon Sep 17 00:00:00 2001 From: Tobias Jakobi Date: Tue, 18 Aug 2015 00:51:24 +0200 Subject: [PATCH 6057/7006] drm/exynos: fix size check in g2d_check_buf_desc_is_valid() The size check was incomplete. It only computed the size of area of the drawing rectangle and checked if the size still fit inside the buffer. The correct check is to compute the position of the last byte that the G2D engine is going to access and then check if that position is still contained in the buffer. In particular we need the stride information to determine this. Signed-off-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 51 ++++++++++++++++++++----- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index ba008391a2fcc..85457b33d881b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -48,11 +48,13 @@ /* registers for base address */ #define G2D_SRC_BASE_ADDR 0x0304 +#define G2D_SRC_STRIDE_REG 0x0308 #define G2D_SRC_COLOR_MODE 0x030C #define G2D_SRC_LEFT_TOP 0x0310 #define G2D_SRC_RIGHT_BOTTOM 0x0314 #define G2D_SRC_PLANE2_BASE_ADDR 0x0318 #define G2D_DST_BASE_ADDR 0x0404 +#define G2D_DST_STRIDE_REG 0x0408 #define G2D_DST_COLOR_MODE 0x040C #define G2D_DST_LEFT_TOP 0x0410 #define G2D_DST_RIGHT_BOTTOM 0x0414 @@ -148,6 +150,7 @@ struct g2d_cmdlist { * A structure of buffer description * * @format: color format + * @stride: buffer stride/pitch in bytes * @left_x: the x coordinates of left top corner * @top_y: the y coordinates of left top corner * @right_x: the x coordinates of right bottom corner @@ -156,6 +159,7 @@ struct g2d_cmdlist { */ struct g2d_buf_desc { unsigned int format; + unsigned int stride; unsigned int left_x; unsigned int top_y; unsigned int right_x; @@ -589,6 +593,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset) switch (reg_offset) { case G2D_SRC_BASE_ADDR: + case G2D_SRC_STRIDE_REG: case G2D_SRC_COLOR_MODE: case G2D_SRC_LEFT_TOP: case G2D_SRC_RIGHT_BOTTOM: @@ -598,6 +603,7 @@ static enum g2d_reg_type g2d_get_reg_type(int reg_offset) reg_type = REG_TYPE_SRC_PLANE2; break; case G2D_DST_BASE_ADDR: + case G2D_DST_STRIDE_REG: case G2D_DST_COLOR_MODE: case G2D_DST_LEFT_TOP: case G2D_DST_RIGHT_BOTTOM: @@ -652,8 +658,8 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc, enum g2d_reg_type reg_type, unsigned long size) { - unsigned int width, height; - unsigned long area; + int width, height; + unsigned long bpp, last_pos; /* * check source and destination buffers only. @@ -662,22 +668,37 @@ static bool g2d_check_buf_desc_is_valid(struct g2d_buf_desc *buf_desc, if (reg_type != REG_TYPE_SRC && reg_type != REG_TYPE_DST) return true; - width = buf_desc->right_x - buf_desc->left_x; + /* This check also makes sure that right_x > left_x. */ + width = (int)buf_desc->right_x - (int)buf_desc->left_x; if (width < G2D_LEN_MIN || width > G2D_LEN_MAX) { - DRM_ERROR("width[%u] is out of range!\n", width); + DRM_ERROR("width[%d] is out of range!\n", width); return false; } - height = buf_desc->bottom_y - buf_desc->top_y; + /* This check also makes sure that bottom_y > top_y. */ + height = (int)buf_desc->bottom_y - (int)buf_desc->top_y; if (height < G2D_LEN_MIN || height > G2D_LEN_MAX) { - DRM_ERROR("height[%u] is out of range!\n", height); + DRM_ERROR("height[%d] is out of range!\n", height); return false; } - area = (unsigned long)width * (unsigned long)height * - g2d_get_buf_bpp(buf_desc->format); - if (area > size) { - DRM_ERROR("area[%lu] is out of range[%lu]!\n", area, size); + bpp = g2d_get_buf_bpp(buf_desc->format); + + /* Compute the position of the last byte that the engine accesses. */ + last_pos = ((unsigned long)buf_desc->bottom_y - 1) * + (unsigned long)buf_desc->stride + + (unsigned long)buf_desc->right_x * bpp - 1; + + /* + * Since right_x > left_x and bottom_y > top_y we already know + * that the first_pos < last_pos (first_pos being the position + * of the first byte the engine accesses), it just remains to + * check if last_pos is smaller then the buffer size. + */ + + if (last_pos >= size) { + DRM_ERROR("last engine access position [%lu] " + "is out of range [%lu]!\n", last_pos, size); return false; } @@ -983,6 +1004,16 @@ static int g2d_check_reg_offset(struct device *dev, } else buf_info->types[reg_type] = BUF_TYPE_GEM; break; + case G2D_SRC_STRIDE_REG: + case G2D_DST_STRIDE_REG: + if (for_addr) + goto err; + + reg_type = g2d_get_reg_type(reg_offset); + + buf_desc = &buf_info->descs[reg_type]; + buf_desc->stride = cmdlist->data[index + 1]; + break; case G2D_SRC_COLOR_MODE: case G2D_DST_COLOR_MODE: if (for_addr) -- GitLab From 7de5c36c2aa9fc7ae1443d144f895ffd044c6b36 Mon Sep 17 00:00:00 2001 From: Tobias Jakobi Date: Tue, 18 Aug 2015 00:51:23 +0200 Subject: [PATCH 6058/7006] drm/exynos: remove superfluous checks in g2d_check_reg_offset() The cases of the switch statement ensure that reg_type can never be REG_TYPE_NONE here. Signed-off-by: Tobias Jakobi Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_g2d.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c index 85457b33d881b..535b4ad6c4b14 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c @@ -994,8 +994,6 @@ static int g2d_check_reg_offset(struct device *dev, goto err; reg_type = g2d_get_reg_type(reg_offset); - if (reg_type == REG_TYPE_NONE) - goto err; /* check userptr buffer type. */ if ((cmdlist->data[index] & ~0x7fffffff) >> 31) { @@ -1020,8 +1018,6 @@ static int g2d_check_reg_offset(struct device *dev, goto err; reg_type = g2d_get_reg_type(reg_offset); - if (reg_type == REG_TYPE_NONE) - goto err; buf_desc = &buf_info->descs[reg_type]; value = cmdlist->data[index + 1]; @@ -1034,8 +1030,6 @@ static int g2d_check_reg_offset(struct device *dev, goto err; reg_type = g2d_get_reg_type(reg_offset); - if (reg_type == REG_TYPE_NONE) - goto err; buf_desc = &buf_info->descs[reg_type]; value = cmdlist->data[index + 1]; @@ -1049,8 +1043,6 @@ static int g2d_check_reg_offset(struct device *dev, goto err; reg_type = g2d_get_reg_type(reg_offset); - if (reg_type == REG_TYPE_NONE) - goto err; buf_desc = &buf_info->descs[reg_type]; value = cmdlist->data[index + 1]; -- GitLab From 94e30d93f9360051b76e8e2a4b61753cde5e16c8 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:47 +0900 Subject: [PATCH 6059/7006] drm/exynos: remove exynos_drm_fb_set_buf_cnt() The exynos_drm_fb_set_buf_cnt() is used to set buffer count only in exynos_drm_fbdev_update(). This patch sets directly buffer count in exynos_drm_framebuffer_init() without using exynos_drm_fb_set_buf_cnt(), so there is no any reason to keep exynos_drm_fb_set_buf_cnt(). Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 13 +++---------- drivers/gpu/drm/exynos/exynos_drm_fb.h | 4 ---- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 3 --- 3 files changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 59ebbe5472907..9cf1701e6bba1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -122,16 +122,6 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { .dirty = exynos_drm_fb_dirty, }; -void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, - unsigned int cnt) -{ - struct exynos_drm_fb *exynos_fb; - - exynos_fb = to_exynos_fb(fb); - - exynos_fb->buf_cnt = cnt; -} - unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) { struct exynos_drm_fb *exynos_fb; @@ -163,6 +153,9 @@ exynos_drm_framebuffer_init(struct drm_device *dev, drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); exynos_fb->exynos_gem_obj[0] = exynos_gem_obj; + /* buffer count to framebuffer always is 1 at booting time. */ + exynos_fb->buf_cnt = 1; + ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); if (ret) { kfree(exynos_fb); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 1c9e27c32cd1b..897d2cff6287f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -25,10 +25,6 @@ struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, void exynos_drm_mode_config_init(struct drm_device *dev); -/* set a buffer count to drm framebuffer. */ -void exynos_drm_fb_set_buf_cnt(struct drm_framebuffer *fb, - unsigned int cnt); - /* get a buffer count to drm framebuffer. */ unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb); diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 624595afbce0e..8188b1f32ca0a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -103,9 +103,6 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, return -EIO; } - /* buffer count to framebuffer always is 1 at booting time. */ - exynos_drm_fb_set_buf_cnt(fb, 1); - offset = fbi->var.xoffset * (fb->bits_per_pixel >> 3); offset += fbi->var.yoffset * fb->pitches[0]; -- GitLab From 39a839f2e65185bcde80f99b5ee5ccd649ba07a2 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:48 +0900 Subject: [PATCH 6060/7006] drm/exynos: s/exynos_gem_obj/obj in exynos_drm_fbdev.c The variable name "exynos_gem_obj" is too long, so some lines exceed 80 characters. It's simple to use "obj" instead of "exynos_gem_obj". Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 30 +++++++++++------------ 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 8188b1f32ca0a..25170e22e5970 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -32,7 +32,7 @@ struct exynos_drm_fbdev { struct drm_fb_helper drm_fb_helper; - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem_obj *obj; }; static int exynos_drm_fb_mmap(struct fb_info *info, @@ -40,7 +40,7 @@ static int exynos_drm_fb_mmap(struct fb_info *info, { struct drm_fb_helper *helper = info->par; struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(helper); - struct exynos_drm_gem_obj *obj = exynos_fbd->exynos_gem_obj; + struct exynos_drm_gem_obj *obj = exynos_fbd->obj; unsigned long vm_size; int ret; @@ -117,7 +117,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes) { struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); - struct exynos_drm_gem_obj *exynos_gem_obj; + struct exynos_drm_gem_obj *obj; struct drm_device *dev = helper->dev; struct fb_info *fbi; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; @@ -146,27 +146,25 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, size = mode_cmd.pitches[0] * mode_cmd.height; - exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); + obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); /* * If physically contiguous memory allocation fails and if IOMMU is * supported then try to get buffer from non physically contiguous * memory area. */ - if (IS_ERR(exynos_gem_obj) && is_drm_iommu_supported(dev)) { + if (IS_ERR(obj) && is_drm_iommu_supported(dev)) { dev_warn(&pdev->dev, "contiguous FB allocation failed, falling back to non-contiguous\n"); - exynos_gem_obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, - size); + obj = exynos_drm_gem_create(dev, EXYNOS_BO_NONCONTIG, size); } - if (IS_ERR(exynos_gem_obj)) { - ret = PTR_ERR(exynos_gem_obj); + if (IS_ERR(obj)) { + ret = PTR_ERR(obj); goto err_release_fbi; } - exynos_fbdev->exynos_gem_obj = exynos_gem_obj; + exynos_fbdev->obj = obj; - helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, - &exynos_gem_obj->base); + helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj->base); if (IS_ERR(helper->fb)) { DRM_ERROR("failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); @@ -187,7 +185,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, err_destroy_framebuffer: drm_framebuffer_cleanup(helper->fb); err_destroy_gem: - exynos_drm_gem_destroy(exynos_gem_obj); + exynos_drm_gem_destroy(obj); err_release_fbi: drm_fb_helper_release_fbi(helper); @@ -282,11 +280,11 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev, struct drm_fb_helper *fb_helper) { struct exynos_drm_fbdev *exynos_fbd = to_exynos_fbdev(fb_helper); - struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj; + struct exynos_drm_gem_obj *obj = exynos_fbd->obj; struct drm_framebuffer *fb; - if (exynos_gem_obj->kvaddr) - vunmap(exynos_gem_obj->kvaddr); + if (obj->kvaddr) + vunmap(obj->kvaddr); /* release drm framebuffer and real buffer */ if (fb_helper->fb && fb_helper->fb->funcs) { -- GitLab From d76199609823ef0c5ab20ccdc8785df283241fd1 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:49 +0900 Subject: [PATCH 6061/7006] drm/exynos: cleanup exynos_drm_fbdev_update() It can get exynos_gem object via function argument, so no need to call exynos_drm_fb_gem_obj() in exynos_drm_fbdev_update. It also can get struct drm_framebuffer *fb via helper->fb, so can remove a function argument for it. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 25170e22e5970..4ef87392f82f9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -75,11 +75,11 @@ static struct fb_ops exynos_drm_fb_ops = { }; static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, - struct drm_fb_helper_surface_size *sizes, - struct drm_framebuffer *fb) + struct drm_fb_helper_surface_size *sizes, + struct exynos_drm_gem_obj *obj) { struct fb_info *fbi = helper->fbdev; - struct exynos_drm_gem_obj *obj; + struct drm_framebuffer *fb = helper->fb; unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); unsigned int nr_pages; unsigned long offset; @@ -87,13 +87,6 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); - /* RGB formats use only one buffer */ - obj = exynos_drm_fb_gem_obj(fb, 0); - if (!obj) { - DRM_DEBUG_KMS("gem object is null.\n"); - return -EFAULT; - } - nr_pages = obj->size >> PAGE_SHIFT; obj->kvaddr = (void __iomem *) vmap(obj->pages, nr_pages, VM_MAP, @@ -175,7 +168,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, fbi->flags = FBINFO_FLAG_DEFAULT; fbi->fbops = &exynos_drm_fb_ops; - ret = exynos_drm_fbdev_update(helper, sizes, helper->fb); + ret = exynos_drm_fbdev_update(helper, sizes, obj); if (ret < 0) goto err_destroy_framebuffer; -- GitLab From ee885ca5c0a34d5212eae9293ee8359e65c73715 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:50 +0900 Subject: [PATCH 6062/7006] drm/exynos: update fb_info via only one function This patch moves codes to update fb_info into exynos_drm_fbdev_update(), so fb_info is updated via only one function. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 29 ++++++++++------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 4ef87392f82f9..133cf5f2701fa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -78,12 +78,22 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, struct drm_fb_helper_surface_size *sizes, struct exynos_drm_gem_obj *obj) { - struct fb_info *fbi = helper->fbdev; + struct fb_info *fbi; struct drm_framebuffer *fb = helper->fb; unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3); unsigned int nr_pages; unsigned long offset; + fbi = drm_fb_helper_alloc_fbi(helper); + if (IS_ERR(fbi)) { + DRM_ERROR("failed to allocate fb info.\n"); + return PTR_ERR(fbi); + } + + fbi->par = helper; + fbi->flags = FBINFO_FLAG_DEFAULT; + fbi->fbops = &exynos_drm_fb_ops; + drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth); drm_fb_helper_fill_var(fbi, helper, sizes->fb_width, sizes->fb_height); @@ -93,6 +103,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper, pgprot_writecombine(PAGE_KERNEL)); if (!obj->kvaddr) { DRM_ERROR("failed to map pages to kernel space.\n"); + drm_fb_helper_release_fbi(helper); return -EIO; } @@ -112,7 +123,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, struct exynos_drm_fbdev *exynos_fbdev = to_exynos_fbdev(helper); struct exynos_drm_gem_obj *obj; struct drm_device *dev = helper->dev; - struct fb_info *fbi; struct drm_mode_fb_cmd2 mode_cmd = { 0 }; struct platform_device *pdev = dev->platformdev; unsigned long size; @@ -130,13 +140,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, mutex_lock(&dev->struct_mutex); - fbi = drm_fb_helper_alloc_fbi(helper); - if (IS_ERR(fbi)) { - DRM_ERROR("failed to allocate fb info.\n"); - ret = PTR_ERR(fbi); - goto out; - } - size = mode_cmd.pitches[0] * mode_cmd.height; obj = exynos_drm_gem_create(dev, EXYNOS_BO_CONTIG, size); @@ -152,7 +155,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, if (IS_ERR(obj)) { ret = PTR_ERR(obj); - goto err_release_fbi; + goto out; } exynos_fbdev->obj = obj; @@ -164,10 +167,6 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, goto err_destroy_gem; } - fbi->par = helper; - fbi->flags = FBINFO_FLAG_DEFAULT; - fbi->fbops = &exynos_drm_fb_ops; - ret = exynos_drm_fbdev_update(helper, sizes, obj); if (ret < 0) goto err_destroy_framebuffer; @@ -179,8 +178,6 @@ err_destroy_framebuffer: drm_framebuffer_cleanup(helper->fb); err_destroy_gem: exynos_drm_gem_destroy(obj); -err_release_fbi: - drm_fb_helper_release_fbi(helper); /* * if failed, all resources allocated above would be released by -- GitLab From dcbb85a1641771547d83ee3a43230ea76703ed68 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:51 +0900 Subject: [PATCH 6063/7006] drm/exynos: cleanup to get gem object for fb Current codes get first gem object and then again get remain gem objects. They can be unified to one routine. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 9cf1701e6bba1..33911c10491a9 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -179,27 +179,18 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, if (!exynos_fb) return ERR_PTR(-ENOMEM); - obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[0]); - if (!obj) { - DRM_ERROR("failed to lookup gem object\n"); - ret = -ENOENT; - goto err_free; - } - - drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); - exynos_fb->exynos_gem_obj[0] = to_exynos_gem_obj(obj); exynos_fb->buf_cnt = drm_format_num_planes(mode_cmd->pixel_format); DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); - for (i = 1; i < exynos_fb->buf_cnt; i++) { + for (i = 0; i < exynos_fb->buf_cnt; i++) { obj = drm_gem_object_lookup(dev, file_priv, mode_cmd->handles[i]); if (!obj) { DRM_ERROR("failed to lookup gem object\n"); ret = -ENOENT; exynos_fb->buf_cnt = i; - goto err_unreference; + goto err; } exynos_gem_obj = to_exynos_gem_obj(obj); @@ -207,18 +198,20 @@ exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, ret = check_fb_gem_memory_type(dev, exynos_gem_obj); if (ret < 0) - goto err_unreference; + goto err; } + drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); + ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); if (ret) { DRM_ERROR("failed to init framebuffer.\n"); - goto err_unreference; + goto err; } return &exynos_fb->fb; -err_unreference: +err: for (i = 0; i < exynos_fb->buf_cnt; i++) { struct drm_gem_object *obj; @@ -226,7 +219,7 @@ err_unreference: if (obj) drm_gem_object_unreference_unlocked(obj); } -err_free: + kfree(exynos_fb); return ERR_PTR(ret); } -- GitLab From d56125afcbdfde09bcb05d3e07e1d063989b5f74 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:52 +0900 Subject: [PATCH 6064/7006] drm/exynos: update exynos_drm_framebuffer_init() for multiple buffers This modifies exynos_drm_framebuffer_init() to be possible to support multiple buffers. Then it can be used by exynos_user_fb_create(). Signed-off-by: Joonyoung Shim Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 36 +++++++++++++---------- drivers/gpu/drm/exynos/exynos_drm_fb.h | 5 +++- drivers/gpu/drm/exynos/exynos_drm_fbdev.c | 3 +- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 33911c10491a9..8f94eac93b1d8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -23,7 +23,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_fbdev.h" -#include "exynos_drm_gem.h" #include "exynos_drm_iommu.h" #include "exynos_drm_crtc.h" @@ -134,36 +133,41 @@ unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj) + struct exynos_drm_gem_obj **gem_obj, + int count) { struct exynos_drm_fb *exynos_fb; - struct exynos_drm_gem_obj *exynos_gem_obj; + int i; int ret; - exynos_gem_obj = to_exynos_gem_obj(obj); - - ret = check_fb_gem_memory_type(dev, exynos_gem_obj); - if (ret < 0) - return ERR_PTR(ret); - exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); if (!exynos_fb) return ERR_PTR(-ENOMEM); - drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); - exynos_fb->exynos_gem_obj[0] = exynos_gem_obj; + exynos_fb->buf_cnt = count; + DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); - /* buffer count to framebuffer always is 1 at booting time. */ - exynos_fb->buf_cnt = 1; + for (i = 0; i < count; i++) { + ret = check_fb_gem_memory_type(dev, gem_obj[i]); + if (ret < 0) + goto err; + + exynos_fb->exynos_gem_obj[i] = gem_obj[i]; + } + + drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); - if (ret) { - kfree(exynos_fb); + if (ret < 0) { DRM_ERROR("failed to initialize framebuffer\n"); - return ERR_PTR(ret); + goto err; } return &exynos_fb->fb; + +err: + kfree(exynos_fb); + return ERR_PTR(ret); } static struct drm_framebuffer * diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 897d2cff6287f..8900f6baf3153 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -14,10 +14,13 @@ #ifndef _EXYNOS_DRM_FB_H_ #define _EXYNOS_DRM_FB_H +#include "exynos_drm_gem.h" + struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, - struct drm_gem_object *obj); + struct exynos_drm_gem_obj **gem_obj, + int count); /* get gem object of a drm framebuffer */ struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c index 133cf5f2701fa..a221f753ad9c7 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c @@ -21,7 +21,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_fbdev.h" -#include "exynos_drm_gem.h" #include "exynos_drm_iommu.h" #define MAX_CONNECTOR 4 @@ -160,7 +159,7 @@ static int exynos_drm_fbdev_create(struct drm_fb_helper *helper, exynos_fbdev->obj = obj; - helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj->base); + helper->fb = exynos_drm_framebuffer_init(dev, &mode_cmd, &obj, 1); if (IS_ERR(helper->fb)) { DRM_ERROR("failed to create drm framebuffer.\n"); ret = PTR_ERR(helper->fb); -- GitLab From 8d31758ecfe156fa4775017858613a5087eb57bf Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:53 +0900 Subject: [PATCH 6065/7006] drm/exynos: cleanup exynos_user_fb_create() Using exynos_drm_framebuffer_init(), redundant codes can be removed. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 47 +++++++------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 8f94eac93b1d8..849925ca0cdd6 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -174,57 +174,36 @@ static struct drm_framebuffer * exynos_user_fb_create(struct drm_device *dev, struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd) { + struct exynos_drm_gem_obj *gem_objs[MAX_FB_BUFFER]; struct drm_gem_object *obj; - struct exynos_drm_gem_obj *exynos_gem_obj; - struct exynos_drm_fb *exynos_fb; - int i, ret; - - exynos_fb = kzalloc(sizeof(*exynos_fb), GFP_KERNEL); - if (!exynos_fb) - return ERR_PTR(-ENOMEM); - - exynos_fb->buf_cnt = drm_format_num_planes(mode_cmd->pixel_format); - - DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); + struct drm_framebuffer *fb; + int i; + int ret; - for (i = 0; i < exynos_fb->buf_cnt; i++) { + for (i = 0; i < drm_format_num_planes(mode_cmd->pixel_format); i++) { obj = drm_gem_object_lookup(dev, file_priv, - mode_cmd->handles[i]); + mode_cmd->handles[i]); if (!obj) { DRM_ERROR("failed to lookup gem object\n"); ret = -ENOENT; - exynos_fb->buf_cnt = i; goto err; } - exynos_gem_obj = to_exynos_gem_obj(obj); - exynos_fb->exynos_gem_obj[i] = exynos_gem_obj; - - ret = check_fb_gem_memory_type(dev, exynos_gem_obj); - if (ret < 0) - goto err; + gem_objs[i] = to_exynos_gem_obj(obj); } - drm_helper_mode_fill_fb_struct(&exynos_fb->fb, mode_cmd); - - ret = drm_framebuffer_init(dev, &exynos_fb->fb, &exynos_drm_fb_funcs); - if (ret) { - DRM_ERROR("failed to init framebuffer.\n"); + fb = exynos_drm_framebuffer_init(dev, mode_cmd, gem_objs, i); + if (IS_ERR(fb)) { + ret = PTR_ERR(fb); goto err; } - return &exynos_fb->fb; + return fb; err: - for (i = 0; i < exynos_fb->buf_cnt; i++) { - struct drm_gem_object *obj; + while (i--) + drm_gem_object_unreference_unlocked(&gem_objs[i]->base); - obj = &exynos_fb->exynos_gem_obj[i]->base; - if (obj) - drm_gem_object_unreference_unlocked(obj); - } - - kfree(exynos_fb); return ERR_PTR(ret); } -- GitLab From faec262b14f3d92601c06b5c73b45ea71d0d164b Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:54 +0900 Subject: [PATCH 6066/7006] drm/exynos: remove exynos_drm_fb_get_buf_cnt() We can get buffer count of framebuffer using drm_format_num_planes(), so keeping exynos_drm_fb_get_buf_cnt() is unnecessary. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 9 --------- drivers/gpu/drm/exynos/exynos_drm_fb.h | 3 --- drivers/gpu/drm/exynos/exynos_drm_plane.c | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 849925ca0cdd6..5087f60985f55 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -121,15 +121,6 @@ static struct drm_framebuffer_funcs exynos_drm_fb_funcs = { .dirty = exynos_drm_fb_dirty, }; -unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb) -{ - struct exynos_drm_fb *exynos_fb; - - exynos_fb = to_exynos_fb(fb); - - return exynos_fb->buf_cnt; -} - struct drm_framebuffer * exynos_drm_framebuffer_init(struct drm_device *dev, struct drm_mode_fb_cmd2 *mode_cmd, diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.h b/drivers/gpu/drm/exynos/exynos_drm_fb.h index 8900f6baf3153..85e4445b920e3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.h +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.h @@ -28,7 +28,4 @@ struct exynos_drm_gem_obj *exynos_drm_fb_gem_obj(struct drm_framebuffer *fb, void exynos_drm_mode_config_init(struct drm_device *dev); -/* get a buffer count to drm framebuffer. */ -unsigned int exynos_drm_fb_get_buf_cnt(struct drm_framebuffer *fb); - #endif diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 865d6eb0c8458..7148224414672 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -126,7 +126,7 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, if (!state->fb) return 0; - nr = exynos_drm_fb_get_buf_cnt(state->fb); + nr = drm_format_num_planes(state->fb->pixel_format); for (i = 0; i < nr; i++) { struct exynos_drm_gem_obj *obj = exynos_drm_fb_gem_obj(state->fb, i); -- GitLab From c3058579a2882bb4bb6bf1ab0fe65f5ed070e530 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 1 Sep 2015 16:22:55 +0900 Subject: [PATCH 6067/7006] drm/exynos: remove buf_cnt from struct exynos_drm_fb Looking other drm drivers, there is no the restriction that framebuffer has only one buffer in .create_handle() callback. They use just first buffer. If this limitation is removed, there is no reason keeping buffer count for framebuffer, so we can remove buf_cnt from struct exynos_drm_fb. Signed-off-by: Joonyoung Shim Reviewed-by: Gustavo Padovan Signed-off-by: Inki Dae --- drivers/gpu/drm/exynos/exynos_drm_fb.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 5087f60985f55..0842808595896 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -32,12 +32,10 @@ * exynos specific framebuffer structure. * * @fb: drm framebuffer obejct. - * @buf_cnt: a buffer count to drm framebuffer. * @exynos_gem_obj: array of exynos specific gem object containing a gem object. */ struct exynos_drm_fb { struct drm_framebuffer fb; - unsigned int buf_cnt; struct exynos_drm_gem_obj *exynos_gem_obj[MAX_FB_BUFFER]; }; @@ -97,10 +95,6 @@ static int exynos_drm_fb_create_handle(struct drm_framebuffer *fb, { struct exynos_drm_fb *exynos_fb = to_exynos_fb(fb); - /* This fb should have only one gem object. */ - if (WARN_ON(exynos_fb->buf_cnt != 1)) - return -EINVAL; - return drm_gem_handle_create(file_priv, &exynos_fb->exynos_gem_obj[0]->base, handle); } @@ -135,9 +129,6 @@ exynos_drm_framebuffer_init(struct drm_device *dev, if (!exynos_fb) return ERR_PTR(-ENOMEM); - exynos_fb->buf_cnt = count; - DRM_DEBUG_KMS("buf_cnt = %d\n", exynos_fb->buf_cnt); - for (i = 0; i < count; i++) { ret = check_fb_gem_memory_type(dev, gem_obj[i]); if (ret < 0) -- GitLab From e39daf2c63518a8ce92e3ad5caa04097524b3585 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Mon, 31 Aug 2015 11:08:44 -0400 Subject: [PATCH 6068/7006] drm/amdgpu/atom: Send out the full AUX address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AUX addresses are 20 bits long. Send out the entire address instead of just the low 16 bits. Port of: drm/radeon/atom: Send out the full AUX address to amdgpu Reviewed-by: Jammy Zhou Reviewed-by: Christian König Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/atombios_dp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c index 9ba0a7d5bc8e8..92b6acadfc527 100644 --- a/drivers/gpu/drm/amd/amdgpu/atombios_dp.c +++ b/drivers/gpu/drm/amd/amdgpu/atombios_dp.c @@ -139,7 +139,8 @@ amdgpu_atombios_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *m tx_buf[0] = msg->address & 0xff; tx_buf[1] = msg->address >> 8; - tx_buf[2] = msg->request << 4; + tx_buf[2] = (msg->request << 4) | + ((msg->address >> 16) & 0xf); tx_buf[3] = msg->size ? (msg->size - 1) : 0; switch (msg->request & ~DP_AUX_I2C_MOT) { -- GitLab From 423a9480add9d9afba035d3c2617034d5f766065 Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 24 Aug 2015 16:59:54 +0800 Subject: [PATCH 6069/7006] drm/amdgpu: re-work sync_resv sync_resv is to handle both amdgpu_fence and sched_fence. Signed-off-by: Chunming Zhou Reviewed-by: Jammy Zhou Reviewed-by: Christian K?nig --- drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c index 69b7d4540c6ef..068aeaff7183b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sync.c @@ -142,6 +142,18 @@ int amdgpu_sync_fence(struct amdgpu_device *adev, struct amdgpu_sync *sync, return 0; } +static void *amdgpu_sync_get_owner(struct fence *f) +{ + struct amdgpu_fence *a_fence = to_amdgpu_fence(f); + struct amd_sched_fence *s_fence = to_amd_sched_fence(f); + + if (s_fence) + return s_fence->owner; + else if (a_fence) + return a_fence->owner; + return AMDGPU_FENCE_OWNER_UNDEFINED; +} + /** * amdgpu_sync_resv - use the semaphores to sync to a reservation object * @@ -158,7 +170,7 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, { struct reservation_object_list *flist; struct fence *f; - struct amdgpu_fence *fence; + void *fence_owner; unsigned i; int r = 0; @@ -176,22 +188,22 @@ int amdgpu_sync_resv(struct amdgpu_device *adev, for (i = 0; i < flist->shared_count; ++i) { f = rcu_dereference_protected(flist->shared[i], reservation_object_held(resv)); - fence = f ? to_amdgpu_fence(f) : NULL; - if (fence && fence->ring->adev == adev) { + if (amdgpu_sync_same_dev(adev, f)) { /* VM updates are only interesting * for other VM updates and moves. */ + fence_owner = amdgpu_sync_get_owner(f); if ((owner != AMDGPU_FENCE_OWNER_MOVE) && - (fence->owner != AMDGPU_FENCE_OWNER_MOVE) && + (fence_owner != AMDGPU_FENCE_OWNER_MOVE) && ((owner == AMDGPU_FENCE_OWNER_VM) != - (fence->owner == AMDGPU_FENCE_OWNER_VM))) + (fence_owner == AMDGPU_FENCE_OWNER_VM))) continue; /* Ignore fence from the same owner as * long as it isn't undefined. */ if (owner != AMDGPU_FENCE_OWNER_UNDEFINED && - fence->owner == owner) + fence_owner == owner) continue; } -- GitLab From 09bfda10e6efd7b65bcc29237bee1765ed779657 Mon Sep 17 00:00:00 2001 From: Jeffery Miller Date: Tue, 1 Sep 2015 11:23:02 -0400 Subject: [PATCH 6070/7006] Add radeon suspend/resume quirk for HP Compaq dc5750. With the radeon driver loaded the HP Compaq dc5750 Small Form Factor machine fails to resume from suspend. Adding a quirk similar to other devices avoids the problem and the system resumes properly. Signed-off-by: Jeffery Miller Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/radeon/radeon_combios.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/radeon/radeon_combios.c b/drivers/gpu/drm/radeon/radeon_combios.c index c097d3a82bda7..a9b01bcf7d0a2 100644 --- a/drivers/gpu/drm/radeon/radeon_combios.c +++ b/drivers/gpu/drm/radeon/radeon_combios.c @@ -3387,6 +3387,14 @@ void radeon_combios_asic_init(struct drm_device *dev) rdev->pdev->subsystem_device == 0x30ae) return; + /* quirk for rs4xx HP Compaq dc5750 Small Form Factor to make it resume + * - it hangs on resume inside the dynclk 1 table. + */ + if (rdev->family == CHIP_RS480 && + rdev->pdev->subsystem_vendor == 0x103c && + rdev->pdev->subsystem_device == 0x280a) + return; + /* DYN CLK 1 */ table = combios_get_table_offset(dev, COMBIOS_DYN_CLK_1_TABLE); if (table) -- GitLab From 8221d706f4f39337e28644f333aefbca41ac0d18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 2 Sep 2015 12:14:57 -0400 Subject: [PATCH 6071/7006] drm/amdgpu: partially revert "modify amdgpu_fence_wait_any() to amdgpu_fence_wait_multiple()" v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That isn't used any more. v2: rebase Signed-off-by: Christian König Reviewed-by: Chunming Zhou Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 11 +++--- drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c | 44 +++++------------------ drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c | 4 +-- 3 files changed, 16 insertions(+), 43 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index c6812f2e198ee..b66938dbb5cf2 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -440,12 +440,11 @@ int amdgpu_fence_wait_next(struct amdgpu_ring *ring); int amdgpu_fence_wait_empty(struct amdgpu_ring *ring); unsigned amdgpu_fence_count_emitted(struct amdgpu_ring *ring); -signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, - struct fence **array, - uint32_t count, - bool wait_all, - bool intr, - signed long t); +signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, + struct fence **array, + uint32_t count, + bool intr, + signed long t); struct amdgpu_fence *amdgpu_fence_ref(struct amdgpu_fence *fence); void amdgpu_fence_unref(struct amdgpu_fence **fence); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c index f446bf2fedc99..1be2bd6d07eac 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fence.c @@ -851,22 +851,6 @@ static bool amdgpu_test_signaled_any(struct fence **fences, uint32_t count) return false; } -static bool amdgpu_test_signaled_all(struct fence **fences, uint32_t count) -{ - int idx; - struct fence *fence; - - for (idx = 0; idx < count; ++idx) { - fence = fences[idx]; - if (fence) { - if (!test_bit(FENCE_FLAG_SIGNALED_BIT, &fence->flags)) - return false; - } - } - - return true; -} - struct amdgpu_wait_cb { struct fence_cb base; struct task_struct *task; @@ -885,7 +869,7 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr, struct amdgpu_fence *fence = to_amdgpu_fence(f); struct amdgpu_device *adev = fence->ring->adev; - return amdgpu_fence_wait_multiple(adev, &f, 1, false, intr, t); + return amdgpu_fence_wait_any(adev, &f, 1, intr, t); } /** @@ -894,23 +878,18 @@ static signed long amdgpu_fence_default_wait(struct fence *f, bool intr, * @adev: amdgpu device * @array: the fence array with amdgpu fence pointer * @count: the number of the fence array - * @wait_all: the flag of wait all(true) or wait any(false) * @intr: when sleep, set the current task interruptable or not * @t: timeout to wait * - * If wait_all is true, it will return when all fences are signaled or timeout. - * If wait_all is false, it will return when any fence is signaled or timeout. + * It will return when any fence is signaled or timeout. */ -signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, - struct fence **array, - uint32_t count, - bool wait_all, - bool intr, - signed long t) -{ - long idx = 0; +signed long amdgpu_fence_wait_any(struct amdgpu_device *adev, + struct fence **array, uint32_t count, + bool intr, signed long t) +{ struct amdgpu_wait_cb *cb; struct fence *fence; + unsigned idx; BUG_ON(!array); @@ -927,10 +906,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, if (fence_add_callback(fence, &cb[idx].base, amdgpu_fence_wait_cb)) { /* The fence is already signaled */ - if (wait_all) - continue; - else - goto fence_rm_cb; + goto fence_rm_cb; } } } @@ -945,9 +921,7 @@ signed long amdgpu_fence_wait_multiple(struct amdgpu_device *adev, * amdgpu_test_signaled_any must be called after * set_current_state to prevent a race with wake_up_process */ - if (!wait_all && amdgpu_test_signaled_any(array, count)) - break; - if (wait_all && amdgpu_test_signaled_all(array, count)) + if (amdgpu_test_signaled_any(array, count)) break; if (adev->needs_reset) { diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c index b92525329d6ce..74dad270362ca 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_sa.c @@ -367,8 +367,8 @@ int amdgpu_sa_bo_new(struct amdgpu_device *adev, } while (amdgpu_sa_bo_next_hole(sa_manager, fences, tries)); spin_unlock(&sa_manager->wq.lock); - t = amdgpu_fence_wait_multiple(adev, fences, AMDGPU_MAX_RINGS, false, false, - MAX_SCHEDULE_TIMEOUT); + t = amdgpu_fence_wait_any(adev, fences, AMDGPU_MAX_RINGS, + false, MAX_SCHEDULE_TIMEOUT); r = (t > 0) ? 0 : t; spin_lock(&sa_manager->wq.lock); /* if we have nothing to wait for block */ -- GitLab From 4c28fb0b27ad58d772cb972564369b9ebdad0d6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 28 Aug 2015 17:27:54 +0200 Subject: [PATCH 6072/7006] drm/amdgpu: fix amdgpu_bo_unreserve order in GEM_OP IOCTL v2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit No copy_(to|from)_user while BO is reserved. v2: handle default path as well Signed-off-by: Christian König Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 4afc507820c01..4b36e779622f9 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -615,6 +615,7 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, info.alignment = robj->tbo.mem.page_alignment << PAGE_SHIFT; info.domains = robj->initial_domain; info.domain_flags = robj->flags; + amdgpu_bo_unreserve(robj); if (copy_to_user(out, &info, sizeof(info))) r = -EFAULT; break; @@ -622,17 +623,19 @@ int amdgpu_gem_op_ioctl(struct drm_device *dev, void *data, case AMDGPU_GEM_OP_SET_PLACEMENT: if (amdgpu_ttm_tt_has_userptr(robj->tbo.ttm)) { r = -EPERM; + amdgpu_bo_unreserve(robj); break; } robj->initial_domain = args->value & (AMDGPU_GEM_DOMAIN_VRAM | AMDGPU_GEM_DOMAIN_GTT | AMDGPU_GEM_DOMAIN_CPU); + amdgpu_bo_unreserve(robj); break; default: + amdgpu_bo_unreserve(robj); r = -EINVAL; } - amdgpu_bo_unreserve(robj); out: drm_gem_object_unreference_unlocked(gobj); return r; -- GitLab From c9f0fe5e19ec485476c3b22e9265016b96c813ef Mon Sep 17 00:00:00 2001 From: Chunming Zhou Date: Mon, 31 Aug 2015 15:46:12 +0800 Subject: [PATCH 6073/7006] drm/amdgpu: make wait_event uninterruptible in push_job MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit with interruptible, the push_job maybe return -ERESTARTSYS, then result in push_job error. E.g. bug trace: [ 181.618860] *****amdgpu_copy_buffer:fence->seq:0x0000000048d8758b, contxt:1207959552, ref:683967304, r:-512 [ 181.618929] BUG: unable to handle kernel paging request at ffffffff811aa266 [ 181.625887] IP: [] reservation_object_add_excl_fence+0x3c/0x120 ... [ 181.859767] [] ? unmap_mapping_range+0x66/0x110 [ 181.865928] [] ttm_bo_move_accel_cleanup+0x41/0x3c0 [ttm] [ 181.872971] [] amdgpu_move_blit.isra.18+0x122/0x150 [amdgpu] [ 181.880254] [] ? unmap_mapping_range+0x66/0x110 [ 181.886420] [] amdgpu_bo_move+0xa9/0x200 [amdgpu] [ 181.892753] [] ttm_bo_handle_move_mem+0x26d/0x5c0 [ttm] Signed-off-by: Chunming Zhou Reviewed-by: Christian König --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index 2f5d1f0da8e5f..ab8577f8ed4a4 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -264,7 +264,6 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job) struct amd_sched_entity *entity = sched_job->s_entity; struct amd_sched_fence *fence = amd_sched_fence_create( entity, sched_job->owner); - int r; if (!fence) return -ENOMEM; @@ -272,10 +271,10 @@ int amd_sched_entity_push_job(struct amd_sched_job *sched_job) fence_get(&fence->base); sched_job->s_fence = fence; - r = wait_event_interruptible(entity->scheduler->job_scheduled, - amd_sched_entity_in(sched_job)); + wait_event(entity->scheduler->job_scheduled, + amd_sched_entity_in(sched_job)); - return r; + return 0; } /** -- GitLab From a60c42320b375e80e52e7861acd6b81c61f05166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Tue, 1 Sep 2015 15:33:25 +0200 Subject: [PATCH 6074/7006] drm/amdgpu: use PT for VM sync on unmap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of the array which is used for ID management. Signed-off-by: Christian König Reviewed-by: Jammy Zhou Reviewed-by: Chunming Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 83b7ce6f5f72a..5848564d3d666 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -627,9 +627,14 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev, { uint64_t mask = AMDGPU_VM_PTE_COUNT - 1; uint64_t last_pte = ~0, last_dst = ~0; + void *owner = AMDGPU_FENCE_OWNER_VM; unsigned count = 0; uint64_t addr; + /* sync to everything on unmapping */ + if (!(flags & AMDGPU_PTE_VALID)) + owner = AMDGPU_FENCE_OWNER_UNDEFINED; + /* walk over the address space and update the page tables */ for (addr = start; addr < end; ) { uint64_t pt_idx = addr >> amdgpu_vm_block_size; @@ -638,8 +643,7 @@ static int amdgpu_vm_update_ptes(struct amdgpu_device *adev, uint64_t pte; int r; - amdgpu_sync_resv(adev, &ib->sync, pt->tbo.resv, - AMDGPU_FENCE_OWNER_VM); + amdgpu_sync_resv(adev, &ib->sync, pt->tbo.resv, owner); r = reservation_object_reserve_shared(pt->tbo.resv); if (r) return r; @@ -790,17 +794,6 @@ static int amdgpu_vm_bo_update_mapping(struct amdgpu_device *adev, ib->length_dw = 0; - if (!(flags & AMDGPU_PTE_VALID)) { - unsigned i; - - for (i = 0; i < AMDGPU_MAX_RINGS; ++i) { - struct amdgpu_fence *f = vm->ids[i].last_id_use; - r = amdgpu_sync_fence(adev, &ib->sync, &f->base); - if (r) - return r; - } - } - r = amdgpu_vm_update_ptes(adev, vm, ib, mapping->it.start, mapping->it.last + 1, addr + mapping->offset, flags, gtt_flags); -- GitLab From 4207a734c32cafd8ea603eb440d6a8e100e7d1d2 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Mon, 31 Aug 2015 14:01:05 +0800 Subject: [PATCH 6075/7006] drm/amdgpu: add count field for the SDMA NOP packet v2 This is added to support the burst NOP v2: squash the typo fix Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cikd.h | 1 + drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h | 5 +++++ drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/cikd.h b/drivers/gpu/drm/amd/amdgpu/cikd.h index a3e3dfaa01a43..7f6d457f250a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/cikd.h +++ b/drivers/gpu/drm/amd/amdgpu/cikd.h @@ -487,6 +487,7 @@ (((op) & 0xFF) << 0)) /* sDMA opcodes */ #define SDMA_OPCODE_NOP 0 +# define SDMA_NOP_COUNT(x) (((x) & 0x3FFF) << 16) #define SDMA_OPCODE_COPY 1 # define SDMA_COPY_SUB_OPCODE_LINEAR 0 # define SDMA_COPY_SUB_OPCODE_TILED 1 diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h b/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h index c723602c7b0cc..ee6a041cb288d 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h +++ b/drivers/gpu/drm/amd/amdgpu/iceland_sdma_pkt_open.h @@ -2163,5 +2163,10 @@ #define SDMA_PKT_NOP_HEADER_sub_op_shift 8 #define SDMA_PKT_NOP_HEADER_SUB_OP(x) (((x) & SDMA_PKT_NOP_HEADER_sub_op_mask) << SDMA_PKT_NOP_HEADER_sub_op_shift) +/*define for count field*/ +#define SDMA_PKT_NOP_HEADER_count_offset 0 +#define SDMA_PKT_NOP_HEADER_count_mask 0x00003FFF +#define SDMA_PKT_NOP_HEADER_count_shift 16 +#define SDMA_PKT_NOP_HEADER_COUNT(x) (((x) & SDMA_PKT_NOP_HEADER_count_mask) << SDMA_PKT_NOP_HEADER_count_shift) #endif /* __ICELAND_SDMA_PKT_OPEN_H_ */ diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h b/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h index 099b7b56113c6..e5ebd084288db 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h +++ b/drivers/gpu/drm/amd/amdgpu/tonga_sdma_pkt_open.h @@ -2236,5 +2236,10 @@ #define SDMA_PKT_NOP_HEADER_sub_op_shift 8 #define SDMA_PKT_NOP_HEADER_SUB_OP(x) (((x) & SDMA_PKT_NOP_HEADER_sub_op_mask) << SDMA_PKT_NOP_HEADER_sub_op_shift) +/*define for count field*/ +#define SDMA_PKT_NOP_HEADER_count_offset 0 +#define SDMA_PKT_NOP_HEADER_count_mask 0x00003FFF +#define SDMA_PKT_NOP_HEADER_count_shift 16 +#define SDMA_PKT_NOP_HEADER_COUNT(x) (((x) & SDMA_PKT_NOP_HEADER_count_mask) << SDMA_PKT_NOP_HEADER_count_shift) #endif /* __TONGA_SDMA_PKT_OPEN_H_ */ -- GitLab From 18111de0dfc38c582c4348af3bda5d3331d35012 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Mon, 31 Aug 2015 14:06:39 +0800 Subject: [PATCH 6076/7006] drm/amdgpu: add burst_nop flag for sdma The burst NOP is supported for SDMA when feature_version is >= 20. Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 1 + drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 2 ++ drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 2 ++ drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 2 ++ 4 files changed, 7 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index b66938dbb5cf2..34812eccd7d0f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -1708,6 +1708,7 @@ struct amdgpu_sdma { uint32_t feature_version; struct amdgpu_ring ring; + bool burst_nop; }; /* diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index c1e782952bd7b..cc909c9cee63c 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -501,6 +501,8 @@ static int cik_sdma_load_microcode(struct amdgpu_device *adev) fw_size = le32_to_cpu(hdr->header.ucode_size_bytes) / 4; adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); + if (adev->sdma[i].feature_version >= 20) + adev->sdma[i].burst_nop = true; fw_data = (const __le32 *) (adev->sdma[i].fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); WREG32(mmSDMA0_UCODE_ADDR + sdma_offsets[i], 0); diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 2f3948c090816..2457bf3e3a1e9 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -146,6 +146,8 @@ static int sdma_v2_4_init_microcode(struct amdgpu_device *adev) hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); + if (adev->sdma[i].feature_version >= 20) + adev->sdma[i].burst_nop = true; if (adev->firmware.smu_load) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index a9d9607e8d916..70b2f03c5712e 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -218,6 +218,8 @@ static int sdma_v3_0_init_microcode(struct amdgpu_device *adev) hdr = (const struct sdma_firmware_header_v1_0 *)adev->sdma[i].fw->data; adev->sdma[i].fw_version = le32_to_cpu(hdr->header.ucode_version); adev->sdma[i].feature_version = le32_to_cpu(hdr->ucode_feature_version); + if (adev->sdma[i].feature_version >= 20) + adev->sdma[i].burst_nop = true; if (adev->firmware.smu_load) { info = &adev->firmware.ucode[AMDGPU_UCODE_ID_SDMA0 + i]; -- GitLab From 36f523a7c095192662286057a7eb70d583203fe5 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 1 Sep 2015 12:54:27 +0800 Subject: [PATCH 6077/7006] drm/amdgpu: add AMDGPU_MAX_SDMA_INSTANCES Remove the hardcoded usage Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 34812eccd7d0f..0be51f998ff99 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -98,6 +98,9 @@ extern int amdgpu_sched_hw_submission; #define AMDGPU_MAX_COMPUTE_RINGS 8 #define AMDGPU_MAX_VCE_RINGS 2 +/* max number of IP instances */ +#define AMDGPU_MAX_SDMA_INSTANCES 2 + /* number of hw syncs before falling back on blocking */ #define AMDGPU_NUM_SYNCS 4 @@ -2057,7 +2060,7 @@ struct amdgpu_device { struct amdgpu_gfx gfx; /* sdma */ - struct amdgpu_sdma sdma[2]; + struct amdgpu_sdma sdma[AMDGPU_MAX_SDMA_INSTANCES]; struct amdgpu_irq_src sdma_trap_irq; struct amdgpu_irq_src sdma_illegal_inst_irq; -- GitLab From 4b2f7e2ca94d58ea16e411a1f717392b91f7730a Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 1 Sep 2015 12:56:17 +0800 Subject: [PATCH 6078/7006] drm/amdgpu: add amdgpu_get_sdma_instance helper function This function is added to map the ring to sdma instance Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 0be51f998ff99..057e7ef5c0d0e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -2199,6 +2199,21 @@ static inline void amdgpu_ring_write(struct amdgpu_ring *ring, uint32_t v) ring->ring_free_dw--; } +static inline struct amdgpu_sdma * amdgpu_get_sdma_instance(struct amdgpu_ring *ring) +{ + struct amdgpu_device *adev = ring->adev; + int i; + + for (i = 0; i < AMDGPU_MAX_SDMA_INSTANCES; i++) + if (&adev->sdma[i].ring == ring) + break; + + if (i < AMDGPU_MAX_SDMA_INSTANCES) + return &adev->sdma[i]; + else + return NULL; +} + /* * ASICs macro. */ -- GitLab From edff0e2826412be38f0c7977cbf89262141aad87 Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 1 Sep 2015 13:04:08 +0800 Subject: [PATCH 6079/7006] drm/amdgpu: add insert_nop ring func and default implementation The insert_nop function is added to amdgpu_ring_funcs structure as well as the default implementation Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu.h | 3 +++ drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 24 +++++++++++++++++++++--- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 1 + drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 2 ++ drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 2 ++ drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 1 + drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 1 + drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 1 + drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c | 1 + drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c | 1 + drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 1 + drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 1 + 12 files changed, 36 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu.h b/drivers/gpu/drm/amd/amdgpu/amdgpu.h index 057e7ef5c0d0e..668939a14206b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu.h +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu.h @@ -343,6 +343,8 @@ struct amdgpu_ring_funcs { int (*test_ring)(struct amdgpu_ring *ring); int (*test_ib)(struct amdgpu_ring *ring); bool (*is_lockup)(struct amdgpu_ring *ring); + /* insert NOP packets */ + void (*insert_nop)(struct amdgpu_ring *ring, uint32_t count); }; /* @@ -1217,6 +1219,7 @@ int amdgpu_ib_ring_tests(struct amdgpu_device *adev); void amdgpu_ring_free_size(struct amdgpu_ring *ring); int amdgpu_ring_alloc(struct amdgpu_ring *ring, unsigned ndw); int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw); +void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count); void amdgpu_ring_commit(struct amdgpu_ring *ring); void amdgpu_ring_unlock_commit(struct amdgpu_ring *ring); void amdgpu_ring_undo(struct amdgpu_ring *ring); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 7d442c51063e3..9bec91484c24e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -131,6 +131,21 @@ int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw) return 0; } +/** amdgpu_ring_insert_nop - insert NOP packets + * + * @ring: amdgpu_ring structure holding ring information + * @count: the number of NOP packets to insert + * + * This is the generic insert_nop function for rings except SDMA + */ +void amdgpu_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ + int i; + + for (i = 0; i < count; i++) + amdgpu_ring_write(ring, ring->nop); +} + /** * amdgpu_ring_commit - tell the GPU to execute the new * commands on the ring buffer @@ -143,10 +158,13 @@ int amdgpu_ring_lock(struct amdgpu_ring *ring, unsigned ndw) */ void amdgpu_ring_commit(struct amdgpu_ring *ring) { + uint32_t count; + /* We pad to match fetch size */ - while (ring->wptr & ring->align_mask) { - amdgpu_ring_write(ring, ring->nop); - } + count = ring->align_mask + 1 - (ring->wptr & ring->align_mask); + count %= ring->align_mask + 1; + ring->funcs->insert_nop(ring, count); + mb(); amdgpu_ring_set_wptr(ring); } diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index cc909c9cee63c..f0661b269a63e 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -1305,6 +1305,7 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = { .test_ring = cik_sdma_ring_test_ring, .test_ib = cik_sdma_ring_test_ib, .is_lockup = cik_sdma_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index fab7b236f37fa..517a68f82ec3b 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -5598,6 +5598,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_gfx = { .test_ring = gfx_v7_0_ring_test_ring, .test_ib = gfx_v7_0_ring_test_ib, .is_lockup = gfx_v7_0_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { @@ -5614,6 +5615,7 @@ static const struct amdgpu_ring_funcs gfx_v7_0_ring_funcs_compute = { .test_ring = gfx_v7_0_ring_test_ring, .test_ib = gfx_v7_0_ring_test_ib, .is_lockup = gfx_v7_0_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void gfx_v7_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 818edb37fa9cd..956a35822f860 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -4378,6 +4378,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_gfx = { .test_ring = gfx_v8_0_ring_test_ring, .test_ib = gfx_v8_0_ring_test_ib, .is_lockup = gfx_v8_0_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { @@ -4394,6 +4395,7 @@ static const struct amdgpu_ring_funcs gfx_v8_0_ring_funcs_compute = { .test_ring = gfx_v8_0_ring_test_ring, .test_ib = gfx_v8_0_ring_test_ib, .is_lockup = gfx_v8_0_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void gfx_v8_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 2457bf3e3a1e9..1b913bce2599d 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -1316,6 +1316,7 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = { .test_ring = sdma_v2_4_ring_test_ring, .test_ib = sdma_v2_4_ring_test_ib, .is_lockup = sdma_v2_4_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index 70b2f03c5712e..a7550a8f5d84d 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -1440,6 +1440,7 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { .test_ring = sdma_v3_0_ring_test_ring, .test_ib = sdma_v3_0_ring_test_ib, .is_lockup = sdma_v3_0_ring_is_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c index 9ac383bc6c1fa..5fac5da694f0d 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c @@ -886,6 +886,7 @@ static const struct amdgpu_ring_funcs uvd_v4_2_ring_funcs = { .test_ring = uvd_v4_2_ring_test_ring, .test_ib = uvd_v4_2_ring_test_ib, .is_lockup = amdgpu_ring_test_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void uvd_v4_2_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c index de4b3f57902d2..2d5c59c318afb 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v5_0.c @@ -825,6 +825,7 @@ static const struct amdgpu_ring_funcs uvd_v5_0_ring_funcs = { .test_ring = uvd_v5_0_ring_test_ring, .test_ib = uvd_v5_0_ring_test_ib, .is_lockup = amdgpu_ring_test_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void uvd_v5_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c index 66c975870e974..d9f553fce5310 100644 --- a/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/uvd_v6_0.c @@ -805,6 +805,7 @@ static const struct amdgpu_ring_funcs uvd_v6_0_ring_funcs = { .test_ring = uvd_v6_0_ring_test_ring, .test_ib = uvd_v6_0_ring_test_ib, .is_lockup = amdgpu_ring_test_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void uvd_v6_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c index 303d961d57bd4..cd16df543f64e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v2_0.c @@ -643,6 +643,7 @@ static const struct amdgpu_ring_funcs vce_v2_0_ring_funcs = { .test_ring = amdgpu_vce_ring_test_ring, .test_ib = amdgpu_vce_ring_test_ib, .is_lockup = amdgpu_ring_test_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void vce_v2_0_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 4349658081ff1..5642b8eb92ad7 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -608,6 +608,7 @@ static const struct amdgpu_ring_funcs vce_v3_0_ring_funcs = { .test_ring = amdgpu_vce_ring_test_ring, .test_ib = amdgpu_vce_ring_test_ib, .is_lockup = amdgpu_ring_test_lockup, + .insert_nop = amdgpu_ring_insert_nop, }; static void vce_v3_0_set_ring_funcs(struct amdgpu_device *adev) -- GitLab From ac01db3dd5a0c7916e804a52752b780c5c18b98d Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 1 Sep 2015 13:13:54 +0800 Subject: [PATCH 6080/7006] drm/amdgpu: implement burst NOP for SDMA Customize the insert_nop func for SDMA rings, and use burst NOP for ring/IB submissions in other places as well Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cik_sdma.c | 34 ++++++++++++++++++++++---- drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c | 34 ++++++++++++++++++++++---- drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c | 33 +++++++++++++++++++++---- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c index f0661b269a63e..9ea9de457da37 100644 --- a/drivers/gpu/drm/amd/amdgpu/cik_sdma.c +++ b/drivers/gpu/drm/amd/amdgpu/cik_sdma.c @@ -188,6 +188,19 @@ static void cik_sdma_ring_set_wptr(struct amdgpu_ring *ring) WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], (ring->wptr << 2) & 0x3fffc); } +static void cik_sdma_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ + struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); + int i; + + for (i = 0; i < count; i++) + if (sdma && sdma->burst_nop && (i == 0)) + amdgpu_ring_write(ring, ring->nop | + SDMA_NOP_COUNT(count - 1)); + else + amdgpu_ring_write(ring, ring->nop); +} + /** * cik_sdma_ring_emit_ib - Schedule an IB on the DMA engine * @@ -213,8 +226,8 @@ static void cik_sdma_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, next_rptr); /* IB packet must end on a 8 DW boundary */ - while ((ring->wptr & 7) != 4) - amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0)); + cik_sdma_ring_insert_nop(ring, (12 - (ring->wptr & 7)) % 8); + amdgpu_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_INDIRECT_BUFFER, 0, extra_bits)); amdgpu_ring_write(ring, ib->gpu_addr & 0xffffffe0); /* base must be 32 byte aligned */ amdgpu_ring_write(ring, upper_32_bits(ib->gpu_addr) & 0xffffffff); @@ -817,8 +830,19 @@ static void cik_sdma_vm_set_pte_pde(struct amdgpu_ib *ib, */ static void cik_sdma_vm_pad_ib(struct amdgpu_ib *ib) { - while (ib->length_dw & 0x7) - ib->ptr[ib->length_dw++] = SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0); + struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); + u32 pad_count; + int i; + + pad_count = (8 - (ib->length_dw & 0x7)) % 8; + for (i = 0; i < pad_count; i++) + if (sdma && sdma->burst_nop && (i == 0)) + ib->ptr[ib->length_dw++] = + SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0) | + SDMA_NOP_COUNT(pad_count - 1); + else + ib->ptr[ib->length_dw++] = + SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0); } /** @@ -1305,7 +1329,7 @@ static const struct amdgpu_ring_funcs cik_sdma_ring_funcs = { .test_ring = cik_sdma_ring_test_ring, .test_ib = cik_sdma_ring_test_ib, .is_lockup = cik_sdma_ring_is_lockup, - .insert_nop = amdgpu_ring_insert_nop, + .insert_nop = cik_sdma_ring_insert_nop, }; static void cik_sdma_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c index 1b913bce2599d..14e87234171ae 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v2_4.c @@ -220,6 +220,19 @@ static void sdma_v2_4_ring_set_wptr(struct amdgpu_ring *ring) WREG32(mmSDMA0_GFX_RB_WPTR + sdma_offsets[me], ring->wptr << 2); } +static void sdma_v2_4_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ + struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); + int i; + + for (i = 0; i < count; i++) + if (sdma && sdma->burst_nop && (i == 0)) + amdgpu_ring_write(ring, ring->nop | + SDMA_PKT_NOP_HEADER_COUNT(count - 1)); + else + amdgpu_ring_write(ring, ring->nop); +} + /** * sdma_v2_4_ring_emit_ib - Schedule an IB on the DMA engine * @@ -247,8 +260,8 @@ static void sdma_v2_4_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, next_rptr); /* IB packet must end on a 8 DW boundary */ - while ((ring->wptr & 7) != 2) - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_NOP)); + sdma_v2_4_ring_insert_nop(ring, (10 - (ring->wptr & 7)) % 8); + amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) | SDMA_PKT_INDIRECT_HEADER_VMID(vmid)); /* base must be 32 byte aligned */ @@ -881,8 +894,19 @@ static void sdma_v2_4_vm_set_pte_pde(struct amdgpu_ib *ib, */ static void sdma_v2_4_vm_pad_ib(struct amdgpu_ib *ib) { - while (ib->length_dw & 0x7) - ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_NOP); + struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); + u32 pad_count; + int i; + + pad_count = (8 - (ib->length_dw & 0x7)) % 8; + for (i = 0; i < pad_count; i++) + if (sdma && sdma->burst_nop && (i == 0)) + ib->ptr[ib->length_dw++] = + SDMA_PKT_HEADER_OP(SDMA_OP_NOP) | + SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1); + else + ib->ptr[ib->length_dw++] = + SDMA_PKT_HEADER_OP(SDMA_OP_NOP); } /** @@ -1316,7 +1340,7 @@ static const struct amdgpu_ring_funcs sdma_v2_4_ring_funcs = { .test_ring = sdma_v2_4_ring_test_ring, .test_ib = sdma_v2_4_ring_test_ib, .is_lockup = sdma_v2_4_ring_is_lockup, - .insert_nop = amdgpu_ring_insert_nop, + .insert_nop = sdma_v2_4_ring_insert_nop, }; static void sdma_v2_4_set_ring_funcs(struct amdgpu_device *adev) diff --git a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c index a7550a8f5d84d..9bfe92df15f71 100644 --- a/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/sdma_v3_0.c @@ -306,6 +306,19 @@ static void sdma_v3_0_ring_set_wptr(struct amdgpu_ring *ring) } } +static void sdma_v3_0_ring_insert_nop(struct amdgpu_ring *ring, uint32_t count) +{ + struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ring); + int i; + + for (i = 0; i < count; i++) + if (sdma && sdma->burst_nop && (i == 0)) + amdgpu_ring_write(ring, ring->nop | + SDMA_PKT_NOP_HEADER_COUNT(count - 1)); + else + amdgpu_ring_write(ring, ring->nop); +} + /** * sdma_v3_0_ring_emit_ib - Schedule an IB on the DMA engine * @@ -332,8 +345,7 @@ static void sdma_v3_0_ring_emit_ib(struct amdgpu_ring *ring, amdgpu_ring_write(ring, next_rptr); /* IB packet must end on a 8 DW boundary */ - while ((ring->wptr & 7) != 2) - amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_NOP)); + sdma_v3_0_ring_insert_nop(ring, (10 - (ring->wptr & 7)) % 8); amdgpu_ring_write(ring, SDMA_PKT_HEADER_OP(SDMA_OP_INDIRECT) | SDMA_PKT_INDIRECT_HEADER_VMID(vmid)); @@ -1001,8 +1013,19 @@ static void sdma_v3_0_vm_set_pte_pde(struct amdgpu_ib *ib, */ static void sdma_v3_0_vm_pad_ib(struct amdgpu_ib *ib) { - while (ib->length_dw & 0x7) - ib->ptr[ib->length_dw++] = SDMA_PKT_HEADER_OP(SDMA_OP_NOP); + struct amdgpu_sdma *sdma = amdgpu_get_sdma_instance(ib->ring); + u32 pad_count; + int i; + + pad_count = (8 - (ib->length_dw & 0x7)) % 8; + for (i = 0; i < pad_count; i++) + if (sdma && sdma->burst_nop && (i == 0)) + ib->ptr[ib->length_dw++] = + SDMA_PKT_HEADER_OP(SDMA_OP_NOP) | + SDMA_PKT_NOP_HEADER_COUNT(pad_count - 1); + else + ib->ptr[ib->length_dw++] = + SDMA_PKT_HEADER_OP(SDMA_OP_NOP); } /** @@ -1440,7 +1463,7 @@ static const struct amdgpu_ring_funcs sdma_v3_0_ring_funcs = { .test_ring = sdma_v3_0_ring_test_ring, .test_ib = sdma_v3_0_ring_test_ib, .is_lockup = sdma_v3_0_ring_is_lockup, - .insert_nop = amdgpu_ring_insert_nop, + .insert_nop = sdma_v3_0_ring_insert_nop, }; static void sdma_v3_0_set_ring_funcs(struct amdgpu_device *adev) -- GitLab From bddf8026386927985ef6d0d11c3ba78f70b76bad Mon Sep 17 00:00:00 2001 From: Jammy Zhou Date: Tue, 1 Sep 2015 16:44:11 +0800 Subject: [PATCH 6081/7006] drm/amdgpu: set MEC doorbell range for Fiji Signed-off-by: Jammy Zhou Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 956a35822f860..0af357a1a170e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3240,7 +3240,8 @@ static int gfx_v8_0_cp_compute_resume(struct amdgpu_device *adev) /* enable the doorbell if requested */ if (use_doorbell) { - if (adev->asic_type == CHIP_CARRIZO) { + if ((adev->asic_type == CHIP_CARRIZO) || + (adev->asic_type == CHIP_FIJI)) { WREG32(mmCP_MEC_DOORBELL_RANGE_LOWER, AMDGPU_DOORBELL_KIQ << 2); WREG32(mmCP_MEC_DOORBELL_RANGE_UPPER, -- GitLab From ba13b5f8f86efa78bc0aaea297b0001b6cbf6c21 Mon Sep 17 00:00:00 2001 From: Kaike Wan Date: Thu, 20 Aug 2015 14:20:42 -0400 Subject: [PATCH 6082/7006] IB/sa: Fix rdma netlink message flags The flags to ibnl_put_msg should be NLM_F_REQUEST instead of GFP_KERNEL. Signed-off-by: Kaike Wan Signed-off-by: John Fleck Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/sa_query.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index edcf568dab48a..8c014b33d8e0a 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c @@ -532,7 +532,7 @@ static int ib_nl_send_msg(struct ib_sa_query *query) /* Put nlmsg header only for now */ data = ibnl_put_msg(skb, &nlh, query->seq, 0, RDMA_NL_LS, - RDMA_NL_LS_OP_RESOLVE, (int) GFP_KERNEL); + RDMA_NL_LS_OP_RESOLVE, NLM_F_REQUEST); if (!data) { kfree_skb(skb); return -EMSGSIZE; -- GitLab From b382c08656000c12a146723a153b85b13a855b49 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 2 Sep 2015 14:00:36 +0200 Subject: [PATCH 6083/7006] sock, diag: fix panic in sock_diag_put_filterinfo diag socket's sock_diag_put_filterinfo() dumps classic BPF programs upon request to user space (ss -0 -b). However, native eBPF programs attached to sockets (SO_ATTACH_BPF) cannot be dumped with this method: Their orig_prog is always NULL. However, sock_diag_put_filterinfo() unconditionally tries to access its filter length resp. wants to copy the filter insns from there. Internal cBPF to eBPF transformations attached to sockets don't have this issue, as orig_prog state is kept. It's currently only used by packet sockets. If we would want to add native eBPF support in the future, this needs to be done through a different attribute than PACKET_DIAG_FILTER to not confuse possible user space disassemblers that work on diag data. Fixes: 89aa075832b0 ("net: sock: allow eBPF programs to be attached to sockets") Signed-off-by: Daniel Borkmann Acked-by: Nicolas Dichtel Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- net/core/sock_diag.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/core/sock_diag.c b/net/core/sock_diag.c index d79866c5f8bc5..817622f3dbb79 100644 --- a/net/core/sock_diag.c +++ b/net/core/sock_diag.c @@ -90,6 +90,9 @@ int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, goto out; fprog = filter->prog->orig_prog; + if (!fprog) + goto out; + flen = bpf_classic_proglen(fprog); attr = nla_reserve(skb, attrtype, flen); -- GitLab From 4db78d31deff77f227de56316ee865d65eaa7f01 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 2 Sep 2015 13:25:59 -0300 Subject: [PATCH 6084/7006] bgmac: Update fixed_phy_register() Commit a5597008dbc2 ("phy: fixed_phy: Add gpio to determine link up/down.") added a new argument to fixed_phy_register(), but missed to update bgmac driver, causing the following build failure: drivers/net/ethernet/broadcom/bgmac.c:1450:2: error: too few arguments to function 'fixed_phy_register' Add the missing argument. Reported-by: Mark Brown Signed-off-by: Fabio Estevam Signed-off-by: David S. Miller --- drivers/net/ethernet/broadcom/bgmac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c index d043746e2fc56..28f7610b03feb 100644 --- a/drivers/net/ethernet/broadcom/bgmac.c +++ b/drivers/net/ethernet/broadcom/bgmac.c @@ -1447,7 +1447,7 @@ static int bgmac_fixed_phy_register(struct bgmac *bgmac) struct phy_device *phy_dev; int err; - phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL); + phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, -1, NULL); if (!phy_dev || IS_ERR(phy_dev)) { bgmac_err(bgmac, "Failed to register fixed PHY device\n"); return -ENODEV; -- GitLab From 210c34dcd8d912dcc740f1f17625a7293af5cb56 Mon Sep 17 00:00:00 2001 From: Paul Durrant Date: Wed, 2 Sep 2015 17:58:36 +0100 Subject: [PATCH 6085/7006] xen-netback: add support for multicast control Xen's PV network protocol includes messages to add/remove ethernet multicast addresses to/from a filter list in the backend. This allows the frontend to request the backend only forward multicast packets which are of interest thus preventing unnecessary noise on the shared ring. The canonical netif header in git://xenbits.xen.org/xen.git specifies the message format (two more XEN_NETIF_EXTRA_TYPEs) so the minimal necessary changes have been pulled into include/xen/interface/io/netif.h. To prevent the frontend from extending the multicast filter list arbitrarily a limit (XEN_NETBK_MCAST_MAX) has been set to 64 entries. This limit is not specified by the protocol and so may change in future. If the limit is reached then the next XEN_NETIF_EXTRA_TYPE_MCAST_ADD sent by the frontend will be failed with NETIF_RSP_ERROR. Signed-off-by: Paul Durrant Cc: Ian Campbell Cc: Wei Liu Acked-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 15 +++++ drivers/net/xen-netback/interface.c | 10 +++ drivers/net/xen-netback/netback.c | 99 +++++++++++++++++++++++++++++ drivers/net/xen-netback/xenbus.c | 13 ++++ include/xen/interface/io/netif.h | 8 ++- 5 files changed, 144 insertions(+), 1 deletion(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index c6cb85a85c896..6dc76c1e807b4 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -210,12 +210,22 @@ enum state_bit_shift { VIF_STATUS_CONNECTED, }; +struct xenvif_mcast_addr { + struct list_head entry; + struct rcu_head rcu; + u8 addr[6]; +}; + +#define XEN_NETBK_MCAST_MAX 64 + struct xenvif { /* Unique identifier for this interface. */ domid_t domid; unsigned int handle; u8 fe_dev_addr[6]; + struct list_head fe_mcast_addr; + unsigned int fe_mcast_count; /* Frontend feature information. */ int gso_mask; @@ -224,6 +234,7 @@ struct xenvif { u8 can_sg:1; u8 ip_csum:1; u8 ipv6_csum:1; + u8 multicast_control:1; /* Is this interface disabled? True when backend discovers * frontend is rogue. @@ -341,4 +352,8 @@ void xenvif_skb_zerocopy_prepare(struct xenvif_queue *queue, struct sk_buff *skb); void xenvif_skb_zerocopy_complete(struct xenvif_queue *queue); +/* Multicast control */ +bool xenvif_mcast_match(struct xenvif *vif, const u8 *addr); +void xenvif_mcast_addr_list_free(struct xenvif *vif); + #endif /* __XEN_NETBACK__COMMON_H__ */ diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c index 28577a31549d1..e7bd63eb2876e 100644 --- a/drivers/net/xen-netback/interface.c +++ b/drivers/net/xen-netback/interface.c @@ -171,6 +171,13 @@ static int xenvif_start_xmit(struct sk_buff *skb, struct net_device *dev) !xenvif_schedulable(vif)) goto drop; + if (vif->multicast_control && skb->pkt_type == PACKET_MULTICAST) { + struct ethhdr *eth = (struct ethhdr *)skb->data; + + if (!xenvif_mcast_match(vif, eth->h_dest)) + goto drop; + } + cb = XENVIF_RX_CB(skb); cb->expires = jiffies + vif->drain_timeout; @@ -427,6 +434,7 @@ struct xenvif *xenvif_alloc(struct device *parent, domid_t domid, vif->num_queues = 0; spin_lock_init(&vif->lock); + INIT_LIST_HEAD(&vif->fe_mcast_addr); dev->netdev_ops = &xenvif_netdev_ops; dev->hw_features = NETIF_F_SG | @@ -661,6 +669,8 @@ void xenvif_disconnect(struct xenvif *vif) xenvif_unmap_frontend_rings(queue); } + + xenvif_mcast_addr_list_free(vif); } /* Reverse the relevant parts of xenvif_init_queue(). diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 3f44b522b8311..42569b994ea84 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -1157,6 +1157,80 @@ static bool tx_credit_exceeded(struct xenvif_queue *queue, unsigned size) return false; } +/* No locking is required in xenvif_mcast_add/del() as they are + * only ever invoked from NAPI poll. An RCU list is used because + * xenvif_mcast_match() is called asynchronously, during start_xmit. + */ + +static int xenvif_mcast_add(struct xenvif *vif, const u8 *addr) +{ + struct xenvif_mcast_addr *mcast; + + if (vif->fe_mcast_count == XEN_NETBK_MCAST_MAX) { + if (net_ratelimit()) + netdev_err(vif->dev, + "Too many multicast addresses\n"); + return -ENOSPC; + } + + mcast = kzalloc(sizeof(*mcast), GFP_ATOMIC); + if (!mcast) + return -ENOMEM; + + ether_addr_copy(mcast->addr, addr); + list_add_tail_rcu(&mcast->entry, &vif->fe_mcast_addr); + vif->fe_mcast_count++; + + return 0; +} + +static void xenvif_mcast_del(struct xenvif *vif, const u8 *addr) +{ + struct xenvif_mcast_addr *mcast; + + list_for_each_entry_rcu(mcast, &vif->fe_mcast_addr, entry) { + if (ether_addr_equal(addr, mcast->addr)) { + --vif->fe_mcast_count; + list_del_rcu(&mcast->entry); + kfree_rcu(mcast, rcu); + break; + } + } +} + +bool xenvif_mcast_match(struct xenvif *vif, const u8 *addr) +{ + struct xenvif_mcast_addr *mcast; + + rcu_read_lock(); + list_for_each_entry_rcu(mcast, &vif->fe_mcast_addr, entry) { + if (ether_addr_equal(addr, mcast->addr)) { + rcu_read_unlock(); + return true; + } + } + rcu_read_unlock(); + + return false; +} + +void xenvif_mcast_addr_list_free(struct xenvif *vif) +{ + /* No need for locking or RCU here. NAPI poll and TX queue + * are stopped. + */ + while (!list_empty(&vif->fe_mcast_addr)) { + struct xenvif_mcast_addr *mcast; + + mcast = list_first_entry(&vif->fe_mcast_addr, + struct xenvif_mcast_addr, + entry); + --vif->fe_mcast_count; + list_del(&mcast->entry); + kfree(mcast); + } +} + static void xenvif_tx_build_gops(struct xenvif_queue *queue, int budget, unsigned *copy_ops, @@ -1215,6 +1289,31 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, break; } + if (extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1].type) { + struct xen_netif_extra_info *extra; + + extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_ADD - 1]; + ret = xenvif_mcast_add(queue->vif, extra->u.mcast.addr); + + make_tx_response(queue, &txreq, + (ret == 0) ? + XEN_NETIF_RSP_OKAY : + XEN_NETIF_RSP_ERROR); + push_tx_responses(queue); + continue; + } + + if (extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1].type) { + struct xen_netif_extra_info *extra; + + extra = &extras[XEN_NETIF_EXTRA_TYPE_MCAST_DEL - 1]; + xenvif_mcast_del(queue->vif, extra->u.mcast.addr); + + make_tx_response(queue, &txreq, XEN_NETIF_RSP_OKAY); + push_tx_responses(queue); + continue; + } + ret = xenvif_count_requests(queue, &txreq, txfrags, work_to_do); if (unlikely(ret < 0)) break; diff --git a/drivers/net/xen-netback/xenbus.c b/drivers/net/xen-netback/xenbus.c index ec383b0f54435..929a6e7e5ecfe 100644 --- a/drivers/net/xen-netback/xenbus.c +++ b/drivers/net/xen-netback/xenbus.c @@ -327,6 +327,14 @@ static int netback_probe(struct xenbus_device *dev, goto abort_transaction; } + /* We support multicast-control. */ + err = xenbus_printf(xbt, dev->nodename, + "feature-multicast-control", "%d", 1); + if (err) { + message = "writing feature-multicast-control"; + goto abort_transaction; + } + err = xenbus_transaction_end(xbt, 0); } while (err == -EAGAIN); @@ -1016,6 +1024,11 @@ static int read_xenbus_vif_flags(struct backend_info *be) val = 0; vif->ipv6_csum = !!val; + if (xenbus_scanf(XBT_NIL, dev->otherend, "request-multicast-control", + "%d", &val) < 0) + val = 0; + vif->multicast_control = !!val; + return 0; } diff --git a/include/xen/interface/io/netif.h b/include/xen/interface/io/netif.h index 70054cc0708d0..252ffd4801ef6 100644 --- a/include/xen/interface/io/netif.h +++ b/include/xen/interface/io/netif.h @@ -156,7 +156,9 @@ struct xen_netif_tx_request { /* Types of xen_netif_extra_info descriptors. */ #define XEN_NETIF_EXTRA_TYPE_NONE (0) /* Never used - invalid */ #define XEN_NETIF_EXTRA_TYPE_GSO (1) /* u.gso */ -#define XEN_NETIF_EXTRA_TYPE_MAX (2) +#define XEN_NETIF_EXTRA_TYPE_MCAST_ADD (2) /* u.mcast */ +#define XEN_NETIF_EXTRA_TYPE_MCAST_DEL (3) /* u.mcast */ +#define XEN_NETIF_EXTRA_TYPE_MAX (4) /* xen_netif_extra_info flags. */ #define _XEN_NETIF_EXTRA_FLAG_MORE (0) @@ -201,6 +203,10 @@ struct xen_netif_extra_info { uint16_t features; /* XEN_NETIF_GSO_FEAT_* */ } gso; + struct { + uint8_t addr[6]; /* Address to add/remove. */ + } mcast; + uint16_t pad[3]; } u; }; -- GitLab From 2a06c7b1fd2389aed2a308db8de803603d592444 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 27 Aug 2015 12:52:19 +0300 Subject: [PATCH 6086/7006] mtd: spi-nor: Add support for Micron n25q064a serial flash Add Micron (n25q064a) 8MB flash to the list of supported chips. Signed-off-by: Mika Westerberg Reviewed-by: Jagan Teki [Brian: fixup context] Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index c27d427fead43..2adf35bd5cd2b 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -586,6 +586,7 @@ static const struct flash_info spi_nor_ids[] = { /* Micron */ { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, + { "n25q064a", INFO(0x20bb17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) }, { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) }, -- GitLab From a1d97ef96e3899ad9d4ec0024f9b4927e0490689 Mon Sep 17 00:00:00 2001 From: Alexis Ballier Date: Fri, 14 Aug 2015 19:35:39 +0200 Subject: [PATCH 6087/7006] mtd: spi-nor: Add support for sst25wf020a It is a 256KiB flash with 4 KiB erase sectors and 64KiB overlay blocks. This is the one available on Hardkernel's Odroid U3 shield. Signed-off-by: Alexis Ballier [Brian: seems like this does NOT require the usual SST_WRITE hacks] Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 2adf35bd5cd2b..984f6f404935d 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -634,6 +634,7 @@ static const struct flash_info spi_nor_ids[] = { { "sst25wf512", INFO(0xbf2501, 0, 64 * 1024, 1, SECT_4K | SST_WRITE) }, { "sst25wf010", INFO(0xbf2502, 0, 64 * 1024, 2, SECT_4K | SST_WRITE) }, { "sst25wf020", INFO(0xbf2503, 0, 64 * 1024, 4, SECT_4K | SST_WRITE) }, + { "sst25wf020a", INFO(0x621612, 0, 64 * 1024, 4, SECT_4K) }, { "sst25wf040", INFO(0xbf2504, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, { "sst25wf080", INFO(0xbf2505, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) }, -- GitLab From 092f05c3eccbd616a0cfa21945412a3e82a9fb6c Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 21 Aug 2015 13:45:35 +0300 Subject: [PATCH 6088/7006] mtd: nand: omap2: Rename shippable module to omap2_nand As both omap2 onenand and omap2 nand driver modules are named the same i.e. "omap2.ko", only one of them gets shipped during MODPOST if both are configured as loadable modules. To avoid this ambiguity let's ship the omap2 nand driver as "omap2_nand.ko" Reported by Pierre Neyron via github https://github.com/beagleboard/linux/issues/40 Cc: Robert Nelson Signed-off-by: Roger Quadros Signed-off-by: Brian Norris --- drivers/mtd/nand/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 1f897ec3c242a..075a027632b5c 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -26,7 +26,8 @@ obj-$(CONFIG_MTD_NAND_CS553X) += cs553x_nand.o obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o obj-$(CONFIG_MTD_NAND_ATMEL) += atmel_nand.o obj-$(CONFIG_MTD_NAND_GPIO) += gpio.o -obj-$(CONFIG_MTD_NAND_OMAP2) += omap2.o +omap2_nand-objs := omap2.o +obj-$(CONFIG_MTD_NAND_OMAP2) += omap2_nand.o obj-$(CONFIG_MTD_NAND_OMAP_BCH_BUILD) += omap_elm.o obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o -- GitLab From c1752086796bafaf0c933240642ed1cf21ddab4f Mon Sep 17 00:00:00 2001 From: Jonas Gorski Date: Wed, 26 Aug 2015 14:56:53 +0200 Subject: [PATCH 6089/7006] mtd: spi-nor: allow dual/quad reads on S25FL129P According to the datasheet[1], both S25FL129P0 (256kB sectors) and S25FL129P1 (64kB sectors) support dual read, quad read, dual i/o read and quad i/o read. I have verified dual read to be working for S25FL129P1 on a dual capable spi controller. Quad as well as S25FL129P0 is untested, lacking hardware to verify. [1] http://www.spansion.com/Support/Datasheets/S25FL129P_00.pdf Signed-off-by: Jonas Gorski Reviewed-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 984f6f404935d..295e56e8173a9 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -611,8 +611,8 @@ static const struct flash_info spi_nor_ids[] = { { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, - { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, 0) }, - { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, 0) }, + { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, + { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, { "s25sl008a", INFO(0x010213, 0, 64 * 1024, 16, 0) }, { "s25sl016a", INFO(0x010214, 0, 64 * 1024, 32, 0) }, -- GitLab From 0f12a27b47284e86eaa4a5ad3877ec3018463178 Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Fri, 14 Aug 2015 18:42:32 +0200 Subject: [PATCH 6090/7006] mtd: spi-nor: s25sl064p supports both dual and quad I/O This chip can be found on Hitex LPC4350 Evaluation Board. Signed-off-by: Joachim Eastwood Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 295e56e8173a9..25372f9b534e8 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -603,7 +603,7 @@ static const struct flash_info spi_nor_ids[] = { * for the chips listed here (without boot sectors). */ { "s25sl032p", INFO(0x010215, 0x4d00, 64 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, - { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, 0) }, + { "s25sl064p", INFO(0x010216, 0x4d00, 64 * 1024, 128, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) }, { "s25fl256s1", INFO(0x010219, 0x4d01, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl512s", INFO(0x010220, 0x4d00, 256 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, -- GitLab From f95c03b2d5fb6d56c0d7ec21970329b49b657fed Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 2 Sep 2015 15:15:11 -0700 Subject: [PATCH 6091/7006] NFSv4.1/flexfiles: Mark the layout for return in ff_layout_io_track_ds_error() When I/O cannot complete due to a fatal error on the DS, ensure that we invalidate the corresponding layout segment and return it. Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index ee8e7013454f2..3f073a7de870c 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -1148,6 +1148,7 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, err = ff_layout_track_ds_error(FF_LAYOUT_FROM_HDR(lseg->pls_layout), mirror, offset, length, status, opnum, GFP_NOIO); + pnfs_error_mark_layout_for_return(lseg->pls_layout->plh_inode, lseg); dprintk("%s: err %d op %d status %u\n", __func__, err, opnum, status); } @@ -1156,7 +1157,6 @@ static void ff_layout_io_track_ds_error(struct pnfs_layout_segment *lseg, static int ff_layout_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr) { - struct inode *inode; int err; trace_nfs4_pnfs_read(hdr, task->tk_status); @@ -1176,8 +1176,6 @@ static int ff_layout_read_done_cb(struct rpc_task *task, pnfs_read_resend_pnfs(hdr); return task->tk_status; case -NFS4ERR_RESET_TO_MDS: - inode = hdr->lseg->pls_layout->plh_inode; - pnfs_error_mark_layout_for_return(inode, hdr->lseg); ff_layout_reset_read(hdr); return task->tk_status; case -EAGAIN: @@ -1330,7 +1328,6 @@ static void ff_layout_read_count_stats(struct rpc_task *task, void *data) static int ff_layout_write_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr) { - struct inode *inode; int err; trace_nfs4_pnfs_write(hdr, task->tk_status); @@ -1346,8 +1343,6 @@ static int ff_layout_write_done_cb(struct rpc_task *task, switch (err) { case -NFS4ERR_RESET_TO_PNFS: case -NFS4ERR_RESET_TO_MDS: - inode = hdr->lseg->pls_layout->plh_inode; - pnfs_error_mark_layout_for_return(inode, hdr->lseg); if (err == -NFS4ERR_RESET_TO_PNFS) { pnfs_set_retry_layoutget(hdr->lseg->pls_layout); ff_layout_reset_write(hdr, true); @@ -1376,7 +1371,6 @@ static int ff_layout_write_done_cb(struct rpc_task *task, static int ff_layout_commit_done_cb(struct rpc_task *task, struct nfs_commit_data *data) { - struct inode *inode; int err; trace_nfs4_pnfs_commit_ds(data, task->tk_status); @@ -1391,8 +1385,6 @@ static int ff_layout_commit_done_cb(struct rpc_task *task, switch (err) { case -NFS4ERR_RESET_TO_PNFS: case -NFS4ERR_RESET_TO_MDS: - inode = data->lseg->pls_layout->plh_inode; - pnfs_error_mark_layout_for_return(inode, data->lseg); if (err == -NFS4ERR_RESET_TO_PNFS) pnfs_set_retry_layoutget(data->lseg->pls_layout); else -- GitLab From 7cc8c5cde0a5872f5d013f82978b73c011d8f8f1 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Wed, 2 Sep 2015 15:22:48 -0700 Subject: [PATCH 6092/7006] NFSv4.1/flexfiles: Clean up ff_layout_write_done_cb/ff_layout_commit_done_cb Signed-off-by: Trond Myklebust --- fs/nfs/flexfilelayout/flexfilelayout.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c index 3f073a7de870c..fbc5a56de8759 100644 --- a/fs/nfs/flexfilelayout/flexfilelayout.c +++ b/fs/nfs/flexfilelayout/flexfilelayout.c @@ -1342,14 +1342,12 @@ static int ff_layout_write_done_cb(struct rpc_task *task, switch (err) { case -NFS4ERR_RESET_TO_PNFS: + pnfs_set_retry_layoutget(hdr->lseg->pls_layout); + ff_layout_reset_write(hdr, true); + return task->tk_status; case -NFS4ERR_RESET_TO_MDS: - if (err == -NFS4ERR_RESET_TO_PNFS) { - pnfs_set_retry_layoutget(hdr->lseg->pls_layout); - ff_layout_reset_write(hdr, true); - } else { - pnfs_clear_retry_layoutget(hdr->lseg->pls_layout); - ff_layout_reset_write(hdr, false); - } + pnfs_clear_retry_layoutget(hdr->lseg->pls_layout); + ff_layout_reset_write(hdr, false); return task->tk_status; case -EAGAIN: rpc_restart_call_prepare(task); @@ -1384,11 +1382,11 @@ static int ff_layout_commit_done_cb(struct rpc_task *task, switch (err) { case -NFS4ERR_RESET_TO_PNFS: + pnfs_set_retry_layoutget(data->lseg->pls_layout); + pnfs_generic_prepare_to_resend_writes(data); + return -EAGAIN; case -NFS4ERR_RESET_TO_MDS: - if (err == -NFS4ERR_RESET_TO_PNFS) - pnfs_set_retry_layoutget(data->lseg->pls_layout); - else - pnfs_clear_retry_layoutget(data->lseg->pls_layout); + pnfs_clear_retry_layoutget(data->lseg->pls_layout); pnfs_generic_prepare_to_resend_writes(data); return -EAGAIN; case -EAGAIN: -- GitLab From e41b0bedba0293b9e1e8d1e8ed553104b9693656 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 3 Sep 2015 00:29:07 +0200 Subject: [PATCH 6093/7006] ipv6: fix exthdrs offload registration in out_rt path We previously register IPPROTO_ROUTING offload under inet6_add_offload(), but in error path, we try to unregister it with inet_del_offload(). This doesn't seem correct, it should actually be inet6_del_offload(), also ipv6_exthdrs_offload_exit() from that commit seems rather incorrect (it also uses rthdr_offload twice), but it got removed entirely later on. Fixes: 3336288a9fea ("ipv6: Switch to using new offload infrastructure.") Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/ipv6/exthdrs_offload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/exthdrs_offload.c b/net/ipv6/exthdrs_offload.c index 447a7fbd1bb6f..f5e2ba1c18bf8 100644 --- a/net/ipv6/exthdrs_offload.c +++ b/net/ipv6/exthdrs_offload.c @@ -36,6 +36,6 @@ out: return ret; out_rt: - inet_del_offload(&rthdr_offload, IPPROTO_ROUTING); + inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING); goto out; } -- GitLab From ed63f1dcd5788d36f942fbcce350742385e3e18c Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 2 Sep 2015 17:24:14 +0800 Subject: [PATCH 6094/7006] net: fec: clear receive interrupts before processing a packet The patch just to re-submit the patch "db3421c114cfa6326" because the patch "4d494cdc92b3b9a0" remove the change. Clear any pending receive interrupt before we process a pending packet. This helps to avoid any spurious interrupts being raised after we have fully cleaned the receive ring, while still allowing an interrupt to be raised if we receive another packet. The position of this is critical: we must do this prior to reading the next packet status to avoid potentially dropping an interrupt when a packet is still pending. Acked-by: Fugang Duan Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 4d5c1ba6b64c6..91925e38705eb 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1407,6 +1407,7 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id) if ((status & BD_ENET_RX_LAST) == 0) netdev_err(ndev, "rcv is not +last\n"); + writel(FEC_ENET_RXF, fep->hwp + FEC_IEVENT); /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | -- GitLab From a82b0e63917f597c546cd479acc938e08ac54f2d Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Wed, 2 Sep 2015 20:54:02 +0200 Subject: [PATCH 6095/7006] netfilter: nf_dup{4, 6}: fix build error when nf_conntrack disabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While testing various Kconfig options on another issue, I found that the following one triggers as well on allmodconfig and nf_conntrack disabled: net/ipv4/netfilter/nf_dup_ipv4.c: In function ‘nf_dup_ipv4’: net/ipv4/netfilter/nf_dup_ipv4.c:72:20: error: ‘nf_skb_duplicated’ undeclared (first use in this function) if (this_cpu_read(nf_skb_duplicated)) [...] net/ipv6/netfilter/nf_dup_ipv6.c: In function ‘nf_dup_ipv6’: net/ipv6/netfilter/nf_dup_ipv6.c:66:20: error: ‘nf_skb_duplicated’ undeclared (first use in this function) if (this_cpu_read(nf_skb_duplicated)) Fix it by including directly the header where it is defined. Fixes: bbde9fc1824a ("netfilter: factor out packet duplication for IPv4/IPv6") Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/ipv4/netfilter/nf_dup_ipv4.c | 1 + net/ipv6/netfilter/nf_dup_ipv6.c | 1 + 2 files changed, 2 insertions(+) diff --git a/net/ipv4/netfilter/nf_dup_ipv4.c b/net/ipv4/netfilter/nf_dup_ipv4.c index b5bb37564b0e5..2d79e6e8d934d 100644 --- a/net/ipv4/netfilter/nf_dup_ipv4.c +++ b/net/ipv4/netfilter/nf_dup_ipv4.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/net/ipv6/netfilter/nf_dup_ipv6.c b/net/ipv6/netfilter/nf_dup_ipv6.c index c5c87e921ccde..c8ab626556a02 100644 --- a/net/ipv6/netfilter/nf_dup_ipv6.c +++ b/net/ipv6/netfilter/nf_dup_ipv6.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include -- GitLab From 62da98656b62a5ca57f22263705175af8ded5aa1 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 3 Sep 2015 01:26:07 +0200 Subject: [PATCH 6096/7006] netfilter: nf_conntrack: make nf_ct_zone_dflt built-in Fengguang reported, that some randconfig generated the following linker issue with nf_ct_zone_dflt object involved: [...] CC init/version.o LD init/built-in.o net/built-in.o: In function `ipv4_conntrack_defrag': nf_defrag_ipv4.c:(.text+0x93e95): undefined reference to `nf_ct_zone_dflt' net/built-in.o: In function `ipv6_defrag': nf_defrag_ipv6_hooks.c:(.text+0xe3ffe): undefined reference to `nf_ct_zone_dflt' make: *** [vmlinux] Error 1 Given that configurations exist where we have a built-in part, which is accessing nf_ct_zone_dflt such as the two handlers nf_ct_defrag_user() and nf_ct6_defrag_user(), and a part that configures nf_conntrack as a module, we must move nf_ct_zone_dflt into a fixed, guaranteed built-in area when netfilter is configured in general. Therefore, split the more generic parts into a common header under include/linux/netfilter/ and move nf_ct_zone_dflt into the built-in section that already holds parts related to CONFIG_NF_CONNTRACK in the netfilter core. This fixes the issue on my side. Fixes: 308ac9143ee2 ("netfilter: nf_conntrack: push zone object into functions") Reported-by: Fengguang Wu Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/netfilter.h | 2 ++ .../netfilter/nf_conntrack_zones_common.h | 23 +++++++++++++++++++ include/net/netfilter/nf_conntrack_zones.h | 19 +-------------- net/netfilter/core.c | 6 +++++ net/netfilter/nf_conntrack_core.c | 7 ------ 5 files changed, 32 insertions(+), 25 deletions(-) create mode 100644 include/linux/netfilter/nf_conntrack_zones_common.h diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index d788ce62d8264..36a652531791e 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h @@ -368,6 +368,8 @@ nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) #endif /*CONFIG_NETFILTER*/ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +#include + extern void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *) __rcu; void nf_ct_attach(struct sk_buff *, const struct sk_buff *); extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu; diff --git a/include/linux/netfilter/nf_conntrack_zones_common.h b/include/linux/netfilter/nf_conntrack_zones_common.h new file mode 100644 index 0000000000000..5d7cf36d47665 --- /dev/null +++ b/include/linux/netfilter/nf_conntrack_zones_common.h @@ -0,0 +1,23 @@ +#ifndef _NF_CONNTRACK_ZONES_COMMON_H +#define _NF_CONNTRACK_ZONES_COMMON_H + +#include + +#define NF_CT_DEFAULT_ZONE_ID 0 + +#define NF_CT_ZONE_DIR_ORIG (1 << IP_CT_DIR_ORIGINAL) +#define NF_CT_ZONE_DIR_REPL (1 << IP_CT_DIR_REPLY) + +#define NF_CT_DEFAULT_ZONE_DIR (NF_CT_ZONE_DIR_ORIG | NF_CT_ZONE_DIR_REPL) + +#define NF_CT_FLAG_MARK 1 + +struct nf_conntrack_zone { + u16 id; + u8 flags; + u8 dir; +}; + +extern const struct nf_conntrack_zone nf_ct_zone_dflt; + +#endif /* _NF_CONNTRACK_ZONES_COMMON_H */ diff --git a/include/net/netfilter/nf_conntrack_zones.h b/include/net/netfilter/nf_conntrack_zones.h index 5316c7b3a374d..4e32512cef32a 100644 --- a/include/net/netfilter/nf_conntrack_zones.h +++ b/include/net/netfilter/nf_conntrack_zones.h @@ -1,24 +1,7 @@ #ifndef _NF_CONNTRACK_ZONES_H #define _NF_CONNTRACK_ZONES_H -#include - -#define NF_CT_DEFAULT_ZONE_ID 0 - -#define NF_CT_ZONE_DIR_ORIG (1 << IP_CT_DIR_ORIGINAL) -#define NF_CT_ZONE_DIR_REPL (1 << IP_CT_DIR_REPLY) - -#define NF_CT_DEFAULT_ZONE_DIR (NF_CT_ZONE_DIR_ORIG | NF_CT_ZONE_DIR_REPL) - -#define NF_CT_FLAG_MARK 1 - -struct nf_conntrack_zone { - u16 id; - u8 flags; - u8 dir; -}; - -extern const struct nf_conntrack_zone nf_ct_zone_dflt; +#include #if IS_ENABLED(CONFIG_NF_CONNTRACK) #include diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 0b939b7ad7241..8e47f81134957 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -388,6 +388,12 @@ EXPORT_SYMBOL(nf_conntrack_destroy); struct nfq_ct_hook __rcu *nfq_ct_hook __read_mostly; EXPORT_SYMBOL_GPL(nfq_ct_hook); +/* Built-in default zone used e.g. by modules. */ +const struct nf_conntrack_zone nf_ct_zone_dflt = { + .id = NF_CT_DEFAULT_ZONE_ID, + .dir = NF_CT_DEFAULT_ZONE_DIR, +}; +EXPORT_SYMBOL_GPL(nf_ct_zone_dflt); #endif /* CONFIG_NF_CONNTRACK */ #ifdef CONFIG_NF_NAT_NEEDED diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index ac3be9b0629b7..eedf0495f11f5 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -1286,13 +1286,6 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, } EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); -/* Built-in default zone used e.g. by modules. */ -const struct nf_conntrack_zone nf_ct_zone_dflt = { - .id = NF_CT_DEFAULT_ZONE_ID, - .dir = NF_CT_DEFAULT_ZONE_DIR, -}; -EXPORT_SYMBOL_GPL(nf_ct_zone_dflt); - #ifdef CONFIG_NF_CONNTRACK_ZONES static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = { .len = sizeof(struct nf_conntrack_zone), -- GitLab From 2ff46e6fea6254ac8fa97aeb9c14e51436ab95f6 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 2 Sep 2015 16:34:35 -0700 Subject: [PATCH 6097/7006] mtd: spi-nor: fix NULL dereference when no match found in spi_nor_ids[] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 06bb6f5a69df ("mtd: spi-nor: stop (ab)using struct spi_device_id") converted an array into a pointer, which means that we should be checking if the pointer goes anywhere, not whether the C string is empty. To do the latter means we dereference a NULL pointer when we reach the terminating entry, for which 'name' is now NULL instead of an array { 0, 0, ... }. Sample crash: [ 1.101371] Unable to handle kernel NULL pointer dereference at virtual address 00000000 [ 1.109457] pgd = c0004000 [ 1.112157] [00000000] *pgd=00000000 [ 1.115736] Internal error: Oops: 5 [#1] SMP ARM [ 1.120345] Modules linked in: [ 1.123405] CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.2.0-next-20150902+ #61 [ 1.130611] Hardware name: Rockchip (Device Tree) [ 1.135306] task: ee0b8d40 ti: ee0ba000 task.ti: ee0ba000 [ 1.140697] PC is at spi_nor_scan+0x90/0x8c4 [ 1.144958] LR is at spi_nor_scan+0xa4/0x8c4 ... [ 1.504112] [] (spi_nor_scan) from [] (m25p_probe+0xc8/0x11c) [ 1.511583] [] (m25p_probe) from [] (spi_drv_probe+0x60/0x7c) [ 1.519055] [] (spi_drv_probe) from [] (driver_probe_device+0x1a0/0x444) [ 1.527478] [] (driver_probe_device) from [] (__device_attach_driver+0x94/0xa0) [ 1.536507] [] (__device_attach_driver) from [] (bus_for_each_drv+0x94/0xa4) [ 1.545277] [] (bus_for_each_drv) from [] (__device_attach+0xa4/0x144) [ 1.553526] [] (__device_attach) from [] (device_initial_probe+0x1c/0x20) [ 1.562035] [] (device_initial_probe) from [] (bus_probe_device+0x38/0x94) [ 1.570631] [] (bus_probe_device) from [] (device_add+0x430/0x558) [ 1.578534] [] (device_add) from [] (spi_add_device+0xe4/0x174) [ 1.586178] [] (spi_add_device) from [] (spi_register_master+0x698/0x7d4) [ 1.594688] [] (spi_register_master) from [] (devm_spi_register_master+0x40/0x7c) [ 1.603892] [] (devm_spi_register_master) from [] (rockchip_spi_probe+0x360/0x3f4) [ 1.613182] [] (rockchip_spi_probe) from [] (platform_drv_probe+0x58/0xa8) [ 1.621779] [] (platform_drv_probe) from [] (driver_probe_device+0x1a0/0x444) [ 1.630635] [] (driver_probe_device) from [] (__driver_attach+0x80/0xa4) [ 1.639058] [] (__driver_attach) from [] (bus_for_each_dev+0x98/0xac) [ 1.647221] [] (bus_for_each_dev) from [] (driver_attach+0x28/0x30) [ 1.655210] [] (driver_attach) from [] (bus_add_driver+0x128/0x250) [ 1.663200] [] (bus_add_driver) from [] (driver_register+0xac/0xf0) [ 1.671191] [] (driver_register) from [] (__platform_driver_register+0x58/0x6c) [ 1.680221] [] (__platform_driver_register) from [] (rockchip_spi_driver_init+0x18/0x20) [ 1.690033] [] (rockchip_spi_driver_init) from [] (do_one_initcall+0x124/0x1dc) [ 1.699063] [] (do_one_initcall) from [] (kernel_init_freeable+0x218/0x2ec) [ 1.707748] [] (kernel_init_freeable) from [] (kernel_init+0x1c/0xf4) [ 1.715912] [] (kernel_init) from [] (ret_from_fork+0x14/0x24) [ 1.723460] Code: e3510000 159f67c0 0a00000c e5961000 (e5d13000) [ 1.729564] ---[ end trace 95baa6b3b861ce25 ]--- Fixes: 06bb6f5a69df ("mtd: spi-nor: stop (ab)using struct spi_device_id") Signed-off-by: Brian Norris Cc: Rafał Miłecki --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 25372f9b534e8..f59aedfe1462a 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1218,7 +1218,7 @@ static const struct flash_info *spi_nor_match_id(const char *name) { const struct flash_info *id = spi_nor_ids; - while (id->name[0]) { + while (id->name) { if (!strcmp(name, id->name)) return id; id++; -- GitLab From 21dd33b09c61597df603c654589adffd7955491a Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Wed, 2 Sep 2015 16:18:57 -0600 Subject: [PATCH 6098/7006] kernel/cpu_pm: fix cpu_cluster_pm_exit comment cpu_cluster_pm_exit() must be sent after cpu_cluster_pm_enter() has been sent for the cluster and before any cpu_pm_exit() notifications are sent for any CPU. Cc: Nicolas Pitre Acked-by: Kevin Hilman Signed-off-by: Lina Iyer Signed-off-by: Rafael J. Wysocki --- kernel/cpu_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cpu_pm.c b/kernel/cpu_pm.c index 9656a3c36503d..009cc9a17d95d 100644 --- a/kernel/cpu_pm.c +++ b/kernel/cpu_pm.c @@ -180,7 +180,7 @@ EXPORT_SYMBOL_GPL(cpu_cluster_pm_enter); * low power state that may have caused some blocks in the same power domain * to reset. * - * Must be called after cpu_pm_exit has been called on all cpus in the power + * Must be called after cpu_cluster_pm_enter has been called for the power * domain, and before cpu_pm_exit has been called on any cpu in the power * domain. Notified drivers can include VFP co-processor, interrupt controller * and its PM extensions, local CPU timers context save/restore which -- GitLab From 7d5d0c8ba369cbfb68eec6912f35197d82214668 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 2 Sep 2015 14:36:48 +0530 Subject: [PATCH 6099/7006] cpufreq: dt: Check OPP count before marking them shared We need to explicitly mark OPPs as shared, when they are not defined with OPP-v2 bindings. But this isn't required to be done if we failed to initialize OPP table. Reorder code to verify OPP count before marking them shared. Fixes: 2e02d8723edf ("cpufreq: dt: Add support for operating-points-v2 bindings") Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index c3583cdfadbdf..8c38b5192baaf 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -239,6 +239,17 @@ static int cpufreq_init(struct cpufreq_policy *policy) */ of_cpumask_init_opp_table(policy->cpus); + /* + * But we need OPP table to function so if it is not there let's + * give platform code chance to provide it for us. + */ + ret = dev_pm_opp_get_opp_count(cpu_dev); + if (ret <= 0) { + pr_debug("OPP table is not ready, deferring probe\n"); + ret = -EPROBE_DEFER; + goto out_free_opp; + } + if (need_update) { struct cpufreq_dt_platform_data *pd = cpufreq_get_driver_data(); @@ -256,17 +267,6 @@ static int cpufreq_init(struct cpufreq_policy *policy) transition_latency = dev_pm_opp_get_max_clock_latency(cpu_dev); } - /* - * But we need OPP table to function so if it is not there let's - * give platform code chance to provide it for us. - */ - ret = dev_pm_opp_get_opp_count(cpu_dev); - if (ret <= 0) { - pr_debug("OPP table is not ready, deferring probe\n"); - ret = -EPROBE_DEFER; - goto out_free_opp; - } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) { ret = -ENOMEM; -- GitLab From 8bc862843901e282e58f5ecd66f1df24366ecb6b Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 2 Sep 2015 14:36:49 +0530 Subject: [PATCH 6100/7006] cpufreq: dt: Print error on failing to mark OPPs as shared We need to explicitly mark OPPs as shared, when they are not defined with OPP-v2 bindings. This operation can potentially fail, and in that case we should at least print an error message. Fixes: 2e02d8723edf ("cpufreq: dt: Add support for operating-points-v2 bindings") Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 8c38b5192baaf..b1131cf89757e 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -260,7 +260,10 @@ static int cpufreq_init(struct cpufreq_policy *policy) * OPP tables are initialized only for policy->cpu, do it for * others as well. */ - set_cpus_sharing_opps(cpu_dev, policy->cpus); + ret = set_cpus_sharing_opps(cpu_dev, policy->cpus); + if (ret) + dev_err(cpu_dev, "%s: failed to mark OPPs as shared: %d\n", + __func__, ret); of_property_read_u32(np, "clock-latency", &transition_latency); } else { -- GitLab From a2022001cebd0825b96aa0f3345ea3ad44ae79d4 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 2 Sep 2015 14:36:50 +0530 Subject: [PATCH 6101/7006] cpufreq: dt: Tolerance applies on both sides of target voltage Tolerance applies on both sides of the target voltage, i.e. both min and max sides. But while checking if a voltage is supported by the regulator or not, we haven't taken care of tolerance on the lower side. Fix that. Cc: Lucas Stach Fixes: 045ee45c4ff2 ("cpufreq: cpufreq-dt: disable unsupported OPPs") Signed-off-by: Viresh Kumar Reviewed-by: Lucas Stach Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index b1131cf89757e..3b64c203bf99a 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -303,7 +303,8 @@ static int cpufreq_init(struct cpufreq_policy *policy) rcu_read_unlock(); tol_uV = opp_uV * priv->voltage_tolerance / 100; - if (regulator_is_supported_voltage(cpu_reg, opp_uV, + if (regulator_is_supported_voltage(cpu_reg, + opp_uV - tol_uV, opp_uV + tol_uV)) { if (opp_uV < min_uV) min_uV = opp_uV; -- GitLab From 29e47e2173349ee06bd339f7753821c720d50923 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 2 Sep 2015 10:16:13 +0200 Subject: [PATCH 6102/7006] PM / Domains: Try power off masters in error path of __pm_genpd_poweron() While powering up a genpd, its domain masters are first being powered up. In the error path of __pm_genpd_poweron(), we didn't care to try power off these domain masters. Let's deal with that to avoid leaving unused PM domains powered. Signed-off-by: Ulf Hansson Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 416720159e96c..62f7572502355 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -212,6 +212,18 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool timed) return ret; } +/** + * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff(). + * @genpd: PM domait to power off. + * + * Queue up the execution of pm_genpd_poweroff() unless it's already been done + * before. + */ +static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) +{ + queue_work(pm_wq, &genpd->power_off_work); +} + /** * __pm_genpd_poweron - Restore power to a given PM domain and its masters. * @genpd: PM domain to power up. @@ -259,8 +271,12 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd) return 0; err: - list_for_each_entry_continue_reverse(link, &genpd->slave_links, slave_node) + list_for_each_entry_continue_reverse(link, + &genpd->slave_links, + slave_node) { genpd_sd_counter_dec(link->master); + genpd_queue_power_off_work(link->master); + } return ret; } @@ -348,18 +364,6 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb, return NOTIFY_DONE; } -/** - * genpd_queue_power_off_work - Queue up the execution of pm_genpd_poweroff(). - * @genpd: PM domait to power off. - * - * Queue up the execution of pm_genpd_poweroff() unless it's already been done - * before. - */ -static void genpd_queue_power_off_work(struct generic_pm_domain *genpd) -{ - queue_work(pm_wq, &genpd->power_off_work); -} - /** * pm_genpd_poweroff - Remove power from a given PM domain. * @genpd: PM domain to power down. -- GitLab From abceaa9cded5f059f8c3b3b6f32730084fe5e39f Mon Sep 17 00:00:00 2001 From: Xunlei Pang Date: Mon, 31 Aug 2015 11:34:05 +0800 Subject: [PATCH 6103/7006] cpuidle/coupled: Add sanity check for safe_state_index Since we are using cpuidle_driver::safe_state_index directly as the target state index, it is better to add the sanity check at the point of registering the driver. Signed-off-by: Xunlei Pang Signed-off-by: Rafael J. Wysocki --- drivers/cpuidle/coupled.c | 22 ++++++++++++++++++++++ drivers/cpuidle/cpuidle.h | 6 ++++++ drivers/cpuidle/driver.c | 4 ++++ 3 files changed, 32 insertions(+) diff --git a/drivers/cpuidle/coupled.c b/drivers/cpuidle/coupled.c index 1523e2d745eb5..344058f8501a2 100644 --- a/drivers/cpuidle/coupled.c +++ b/drivers/cpuidle/coupled.c @@ -186,6 +186,28 @@ bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state) return drv->states[state].flags & CPUIDLE_FLAG_COUPLED; } +/** + * cpuidle_coupled_state_verify - check if the coupled states are correctly set. + * @drv: struct cpuidle_driver for the platform + * + * Returns 0 for valid state values, a negative error code otherwise: + * * -EINVAL if any coupled state(safe_state_index) is wrongly set. + */ +int cpuidle_coupled_state_verify(struct cpuidle_driver *drv) +{ + int i; + + for (i = drv->state_count - 1; i >= 0; i--) { + if (cpuidle_state_is_coupled(drv, i) && + (drv->safe_state_index == i || + drv->safe_state_index < 0 || + drv->safe_state_index >= drv->state_count)) + return -EINVAL; + } + + return 0; +} + /** * cpuidle_coupled_set_ready - mark a cpu as ready * @coupled: the struct coupled that contains the current cpu diff --git a/drivers/cpuidle/cpuidle.h b/drivers/cpuidle/cpuidle.h index 178c5ad3d5687..f87f399b0540c 100644 --- a/drivers/cpuidle/cpuidle.h +++ b/drivers/cpuidle/cpuidle.h @@ -35,6 +35,7 @@ extern void cpuidle_remove_sysfs(struct cpuidle_device *dev); #ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state); +int cpuidle_coupled_state_verify(struct cpuidle_driver *drv); int cpuidle_enter_state_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int next_state); int cpuidle_coupled_register_device(struct cpuidle_device *dev); @@ -46,6 +47,11 @@ bool cpuidle_state_is_coupled(struct cpuidle_driver *drv, int state) return false; } +static inline int cpuidle_coupled_state_verify(struct cpuidle_driver *drv) +{ + return 0; +} + static inline int cpuidle_enter_state_coupled(struct cpuidle_device *dev, struct cpuidle_driver *drv, int next_state) { diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c index 5db147859b904..389ade4572beb 100644 --- a/drivers/cpuidle/driver.c +++ b/drivers/cpuidle/driver.c @@ -227,6 +227,10 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv) if (!drv || !drv->state_count) return -EINVAL; + ret = cpuidle_coupled_state_verify(drv); + if (ret) + return ret; + if (cpuidle_disabled()) return -ENODEV; -- GitLab From 7f23532866f931be626e69ff55caf39e54516047 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Wed, 2 Sep 2015 21:48:58 +0530 Subject: [PATCH 6104/7006] KVM: PPC: Book3S HV: Fix race in starting secondary threads The current dynamic micro-threading code has a race due to which a secondary thread naps when it is supposed to be running a vcpu. As a side effect of this, on a guest exit, the primary thread in kvmppc_wait_for_nap() finds that this secondary thread hasn't cleared its vcore pointer. This results in "CPU X seems to be stuck!" warnings. The race is possible since the primary thread on exiting the guests only waits for all the secondaries to clear its vcore pointer. It subsequently expects the secondary threads to enter nap while it unsplits the core. A secondary thread which hasn't yet entered the nap will loop in kvm_no_guest until its vcore pointer and the do_nap flag are unset. Once the core has been unsplit, a new vcpu thread can grab the core and set the do_nap flag *before* setting the vcore pointers of the secondary. As a result, the secondary thread will now enter nap via kvm_unsplit_nap instead of running the guest vcpu. Fix this by setting the do_nap flag after setting the vcore pointer in the PACA of the secondary in kvmppc_run_core. Also, ensure that a secondary thread doesn't nap in kvm_unsplit_nap when the vcore pointer in its PACA struct is set. Fixes: b4deba5c41e9 Signed-off-by: Gautham R. Shenoy Reviewed-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kvm/book3s_hv.c | 10 +++++++++- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index fad52f226c12b..c5edf1719314f 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -2411,7 +2411,6 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) break; cpu_relax(); } - split_info.do_nap = 1; /* ask secondaries to nap when done */ } /* Start all the threads */ @@ -2440,6 +2439,15 @@ static noinline void kvmppc_run_core(struct kvmppc_vcore *vc) thr += pvc->num_threads; } } + + /* + * Ensure that split_info.do_nap is set after setting + * the vcore pointer in the PACA of the secondaries. + */ + smp_mb(); + if (cmd_bit) + split_info.do_nap = 1; /* ask secondaries to nap when done */ + /* * When doing micro-threading, poke the inactive threads as well. * This gets them to the nap instruction after kvm_do_nap, diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index 472680f47d09e..b07f04550969b 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -421,6 +421,14 @@ kvm_no_guest: * whole-core mode, so we need to nap. */ kvm_unsplit_nap: + /* + * Ensure that secondary doesn't nap when it has + * its vcore pointer set. + */ + sync /* matches smp_mb() before setting split_info.do_nap */ + ld r0, HSTATE_KVM_VCORE(r13) + cmpdi r0, 0 + bne kvm_no_guest /* clear any pending message */ BEGIN_FTR_SECTION lis r6, (PPC_DBELL_SERVER << (63-36))@h -- GitLab From 06554d9f6cc8f0b5ec903db19726a15dfc7b09d6 Mon Sep 17 00:00:00 2001 From: "Gautham R. Shenoy" Date: Fri, 7 Aug 2015 17:41:20 +0530 Subject: [PATCH 6105/7006] KVM: PPC: Book3S HV: Exit on H_DOORBELL if HOST_IPI is set The code that handles the case when we receive a H_DOORBELL interrupt has a comment which says "Hypervisor doorbell - exit only if host IPI flag set". However, the current code does not actually check if the host IPI flag is set. This is due to a comparison instruction that got missed. As a result, the current code performs the exit to host only if some sibling thread or a sibling sub-core is exiting to the host. This implies that, an IPI sent to a sibling core in (subcores-per-core != 1) mode will be missed by the host unless the sibling core is on the exit path to the host. This patch adds the missing comparison operation which will ensure that when HOST_IPI flag is set, we unconditionally exit to the host. Fixes: 66feed61cdf6 Cc: stable@vger.kernel.org # v4.1+ Signed-off-by: Gautham R. Shenoy Reviewed-by: David Gibson Signed-off-by: Paul Mackerras --- arch/powerpc/kvm/book3s_hv_rmhandlers.S | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/powerpc/kvm/book3s_hv_rmhandlers.S b/arch/powerpc/kvm/book3s_hv_rmhandlers.S index b07f04550969b..2273dcacef39f 100644 --- a/arch/powerpc/kvm/book3s_hv_rmhandlers.S +++ b/arch/powerpc/kvm/book3s_hv_rmhandlers.S @@ -1213,6 +1213,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_HAS_PPR) cmpwi r12, BOOK3S_INTERRUPT_H_DOORBELL bne 3f lbz r0, HSTATE_HOST_IPI(r13) + cmpwi r0, 0 beq 4f b guest_exit_cont 3: -- GitLab From f35f3a48d6ee810557b58e6b7d933438999401b6 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 2 Sep 2015 11:14:48 +0200 Subject: [PATCH 6106/7006] KVM: PPC: Book3S: Fix size of the PSPB register The size of the Problem State Priority Boost Register is only 32 bits, but the kvm_vcpu_arch->pspb variable is declared as "ulong", ie. 64-bit. However, the assembler code accesses this variable with 32-bit accesses, and the KVM_REG_PPC_PSPB macro is defined with SIZE_U32, too, so that the current code is broken on big endian hosts: kvmppc_get_one_reg_hv() will only return zero for this register since it is using the wrong half of the pspb variable. Let's fix this problem by adjusting the size of the pspb field in the kvm_vcpu_arch structure. Signed-off-by: Thomas Huth Signed-off-by: Paul Mackerras --- arch/powerpc/include/asm/kvm_host.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/include/asm/kvm_host.h b/arch/powerpc/include/asm/kvm_host.h index e187b6a56e7e3..98eebbf663405 100644 --- a/arch/powerpc/include/asm/kvm_host.h +++ b/arch/powerpc/include/asm/kvm_host.h @@ -486,7 +486,7 @@ struct kvm_vcpu_arch { ulong ciabr; ulong cfar; ulong ppr; - ulong pspb; + u32 pspb; ulong fscr; ulong shadow_fscr; ulong ebbhr; -- GitLab From fce388afd633cdf20844e17f47b0d97c7ee06e69 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Thu, 20 Aug 2015 23:40:46 +0200 Subject: [PATCH 6107/7006] i2c: mux: reg: simplify register size checking Checking was done at three different locations, just do it once and properly at probing time. Signed-off-by: Wolfram Sang Tested-by: York Sun --- drivers/i2c/muxes/i2c-mux-reg.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 57ec57e0da529..fb5b55a0cf9d5 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -59,9 +59,6 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id) if (!mux->data.write_only) ioread8(mux->data.reg); break; - default: - pr_err("Invalid register size\n"); - return -EINVAL; } return 0; @@ -155,10 +152,6 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, /* map address from "reg" if exists */ if (of_address_to_resource(np, 0, &res)) { mux->data.reg_size = resource_size(&res); - if (mux->data.reg_size > 4) { - dev_err(&pdev->dev, "Invalid address size\n"); - return -EINVAL; - } mux->data.reg = devm_ioremap_resource(&pdev->dev, &res); if (IS_ERR(mux->data.reg)) return PTR_ERR(mux->data.reg); @@ -211,15 +204,17 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) "Register not set, using platform resource\n"); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); mux->data.reg_size = resource_size(res); - if (mux->data.reg_size > 4) { - dev_err(&pdev->dev, "Invalid resource size\n"); - return -EINVAL; - } mux->data.reg = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(mux->data.reg)) return PTR_ERR(mux->data.reg); } + if (mux->data.reg_size != 4 && mux->data.reg_size != 2 && + mux->data.reg_size != 1) { + dev_err(&pdev->dev, "Invalid register size\n"); + return -EINVAL; + } + mux->adap = devm_kzalloc(&pdev->dev, sizeof(*mux->adap) * mux->data.n_values, GFP_KERNEL); -- GitLab From a05a34e7f6ff4a942186e99932885b10c6bc1d1a Mon Sep 17 00:00:00 2001 From: Mike Rapoport Date: Wed, 2 Sep 2015 11:03:41 +0300 Subject: [PATCH 6108/7006] i2c: mux: reg: fix compilation warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With CONFIG_OF=n, the following warnings occur when compiling drivers/i2c/muxes/i2c-mux-reg.c: CC drivers/i2c/muxes/i2c-mux-reg.o drivers/i2c/muxes/i2c-mux-reg.c:170:13: warning: ‘struct gpiomux’ declared inside parameter list [enabled by default] struct platform_device *pdev) ^ drivers/i2c/muxes/i2c-mux-reg.c:170:13: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default] drivers/i2c/muxes/i2c-mux-reg.c: In function ‘i2c_mux_reg_probe’: drivers/i2c/muxes/i2c-mux-reg.c:201:3: warning: passing argument 1 of ‘i2c_mux_reg_probe_dt’ from incompatible pointer type [enabled by default] ret = i2c_mux_reg_probe_dt(mux, pdev); ^ Signed-off-by: Mike Rapoport Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index fb5b55a0cf9d5..7913d8019bb37 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -160,7 +160,7 @@ static int i2c_mux_reg_probe_dt(struct regmux *mux, return 0; } #else -static int i2c_mux_reg_probe_dt(struct gpiomux *mux, +static int i2c_mux_reg_probe_dt(struct regmux *mux, struct platform_device *pdev) { return 0; -- GitLab From 5a73882fd2c3a86b502d54da532d373a1f2db15e Mon Sep 17 00:00:00 2001 From: York Sun Date: Wed, 2 Sep 2015 11:40:46 -0500 Subject: [PATCH 6109/7006] i2c: mux: reg Change ioread endianness for readback Reading the register (if allowed) after writing is to ensure writing is completed on a posted bus. The endianness of reading doesn't matter. Signed-off-by: York Sun Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-reg.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 7913d8019bb37..5fbd5bd0878f1 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -31,28 +31,28 @@ static int i2c_mux_reg_set(const struct regmux *mux, unsigned int chan_id) if (!mux->data.reg) return -EINVAL; + /* + * Write to the register, followed by a read to ensure the write is + * completed on a "posted" bus, for example PCI or write buffers. + * The endianness of reading doesn't matter and the return data + * is not used. + */ switch (mux->data.reg_size) { case 4: - if (mux->data.little_endian) { + if (mux->data.little_endian) iowrite32(chan_id, mux->data.reg); - if (!mux->data.write_only) - ioread32(mux->data.reg); - } else { + else iowrite32be(chan_id, mux->data.reg); - if (!mux->data.write_only) - ioread32(mux->data.reg); - } + if (!mux->data.write_only) + ioread32(mux->data.reg); break; case 2: - if (mux->data.little_endian) { + if (mux->data.little_endian) iowrite16(chan_id, mux->data.reg); - if (!mux->data.write_only) - ioread16(mux->data.reg); - } else { + else iowrite16be(chan_id, mux->data.reg); - if (!mux->data.write_only) - ioread16be(mux->data.reg); - } + if (!mux->data.write_only) + ioread16(mux->data.reg); break; case 1: iowrite8(chan_id, mux->data.reg); -- GitLab From ec0b9d35d1fbf7e3a3eccc662ad641794d3685a5 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:38 -0500 Subject: [PATCH 6110/7006] MIPS: Remove "weak" from get_c0_compare_int() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). get_c0_compare_int() is defined in several files. Each definition is weak, so I assume Kconfig prevents two or more from being included. The caller contains default code used when get_c0_compare_int() isn't defined at all. Add a weak get_c0_compare_int() definition with the default code and remove the weak annotation from the declaration. Then the platform implementations will be strong and will override the weak default. If multiple platforms are ever configured in, we'll get a link error instead of calling a random platform's implementation. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10686/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/time.h | 2 +- arch/mips/kernel/cevt-r4k.c | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/arch/mips/include/asm/time.h b/arch/mips/include/asm/time.h index 8ab2874225c44..17d4cd20f18c1 100644 --- a/arch/mips/include/asm/time.h +++ b/arch/mips/include/asm/time.h @@ -51,7 +51,7 @@ extern int __weak get_c0_perfcount_int(void); /* * Initialize the calling CPU's compare interrupt as clockevent device */ -extern unsigned int __weak get_c0_compare_int(void); +extern unsigned int get_c0_compare_int(void); extern int r4k_clockevent_init(void); static inline int mips_clockevent_init(void) diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index d70c4d893219e..cc7cc46b58f7a 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -174,6 +174,11 @@ int c0_compare_int_usable(void) return 1; } +unsigned int __weak get_c0_compare_int(void) +{ + return MIPS_CPU_IRQ_BASE + cp0_compare_irq; +} + int r4k_clockevent_init(void) { unsigned int cpu = smp_processor_id(); @@ -189,11 +194,9 @@ int r4k_clockevent_init(void) /* * With vectored interrupts things are getting platform specific. * get_c0_compare_int is a hook to allow a platform to return the - * interrupt number of it's liking. + * interrupt number of its liking. */ - irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; - if (get_c0_compare_int) - irq = get_c0_compare_int(); + irq = get_c0_compare_int(); cd = &per_cpu(mips_clockevent_device, cpu); -- GitLab From 770847bad0200b62af2d93808b4e69d82f14264e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:46 -0500 Subject: [PATCH 6111/7006] MIPS: Remove "weak" from get_c0_fdc_int() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). The most elegant solution is to have a weak default implementation and allow a strong function to override it. Then we don't have to test whether a definition is present, and if there are ever multiple strong definitions, we get a link error instead of calling a random definition. Add a weak get_c0_fdc_int() definition with the default code and remove the weak annotation from the declaration. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10687/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/irq.h | 2 +- drivers/tty/mips_ejtag_fdc.c | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index f0db99f8defe9..15e0fecbc300f 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -49,7 +49,7 @@ extern int cp0_compare_irq_shift; extern int cp0_perfcount_irq; extern int cp0_fdc_irq; -extern int __weak get_c0_fdc_int(void); +extern int get_c0_fdc_int(void); void arch_trigger_all_cpu_backtrace(bool); #define arch_trigger_all_cpu_backtrace arch_trigger_all_cpu_backtrace diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 358323c83b4f3..a8c8cfd52a23b 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -879,6 +879,11 @@ static const struct tty_operations mips_ejtag_fdc_tty_ops = { .chars_in_buffer = mips_ejtag_fdc_tty_chars_in_buffer, }; +int __weak get_c0_fdc_int(void) +{ + return -1; +} + static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) { int ret, nport; @@ -967,9 +972,7 @@ static int mips_ejtag_fdc_tty_probe(struct mips_cdmm_device *dev) wake_up_process(priv->thread); /* Look for an FDC IRQ */ - priv->irq = -1; - if (get_c0_fdc_int) - priv->irq = get_c0_fdc_int(); + priv->irq = get_c0_fdc_int(); /* Try requesting the IRQ */ if (priv->irq >= 0) { -- GitLab From e1d97497309867cdc1064ed6b10953abd1740b05 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:11:54 -0500 Subject: [PATCH 6112/7006] MIPS: Remove "weak" from mips_cdmm_phys_base() declaration Weak header file declarations are error-prone because they make every definition weak, and the linker chooses one based on link order (see 10629d711ed7 ("PCI: Remove __weak annotation from pcibios_get_phb_of_node decl")). mips_cdmm_phys_base() is defined only in arch/mips/mti-malta/malta-memory.c so there's no problem with multiple definitions. But it works better to have a weak default implementation and allow a strong function to override it. Then we don't have to test whether a definition is present, and if there are ever multiple strong definitions, we get a link error instead of calling a random definition. Add a weak mips_cdmm_phys_base() definition and remove the weak annotation from the declaration in arch/mips/include/asm/cdmm.h. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10688/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cdmm.h | 4 ++-- drivers/bus/mips_cdmm.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/cdmm.h b/arch/mips/include/asm/cdmm.h index 16e22ce9719fd..bece2064cc8cb 100644 --- a/arch/mips/include/asm/cdmm.h +++ b/arch/mips/include/asm/cdmm.h @@ -53,7 +53,7 @@ struct mips_cdmm_driver { * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. * * Picking a suitable physical address at which to map the CDMM region is - * platform specific, so this weak function can be defined by platform code to + * platform specific, so this function can be defined by platform code to * pick a suitable value if none is configured by the bootloader. * * This address must be 32kB aligned, and the region occupies a maximum of 32kB @@ -61,7 +61,7 @@ struct mips_cdmm_driver { * * Returns: Physical base address for CDMM region, or 0 on failure. */ -phys_addr_t __weak mips_cdmm_phys_base(void); +phys_addr_t mips_cdmm_phys_base(void); extern struct bus_type mips_cdmm_bustype; void __iomem *mips_cdmm_early_probe(unsigned int dev_type); diff --git a/drivers/bus/mips_cdmm.c b/drivers/bus/mips_cdmm.c index ab3bde16ecb44..1c543effe062f 100644 --- a/drivers/bus/mips_cdmm.c +++ b/drivers/bus/mips_cdmm.c @@ -331,6 +331,18 @@ static phys_addr_t mips_cdmm_cur_base(void) << MIPS_CDMMBASE_ADDR_START; } +/** + * mips_cdmm_phys_base() - Choose a physical base address for CDMM region. + * + * Picking a suitable physical address at which to map the CDMM region is + * platform specific, so this weak function can be overridden by platform + * code to pick a suitable value if none is configured by the bootloader. + */ +phys_addr_t __weak mips_cdmm_phys_base(void) +{ + return 0; +} + /** * mips_cdmm_setup() - Ensure the CDMM bus is initialised and usable. * @bus: Pointer to bus information for current CPU. @@ -368,7 +380,7 @@ static int mips_cdmm_setup(struct mips_cdmm_bus *bus) if (!bus->phys) bus->phys = mips_cdmm_cur_base(); /* Otherwise, ask platform code for suggestions */ - if (!bus->phys && mips_cdmm_phys_base) + if (!bus->phys) bus->phys = mips_cdmm_phys_base(); /* Otherwise, copy what other CPUs have done */ if (!bus->phys) -- GitLab From b620c9720a0e18bc2067c65ad3b9020e813372eb Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Sun, 12 Jul 2015 18:12:03 -0500 Subject: [PATCH 6113/7006] MIPS: Remove "__weak" definition from arch-specific linkage.h "__weak" is defined in include/linux/compiler-gcc.h. We shouldn't need an arch-specific definition. Remove the "__weak" definition from arch/mips/include/asm/linkage.h. Signed-off-by: Bjorn Helgaas Reviewed-by: James Hogan Cc: Andrew Bresticker Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10689/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/linkage.h | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/include/asm/linkage.h b/arch/mips/include/asm/linkage.h index 2767dda9e3091..99651b0ea7c72 100644 --- a/arch/mips/include/asm/linkage.h +++ b/arch/mips/include/asm/linkage.h @@ -5,7 +5,6 @@ #include #endif -#define __weak __attribute__((weak)) #define cond_syscall(x) asm(".weak\t" #x "\n" #x "\t=\tsys_ni_syscall") #define SYSCALL_ALIAS(alias, name) \ asm ( #alias " = " #name "\n\t.globl " #alias) -- GitLab From 6701ca2df4e22fb130330800b6cde687cb761637 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Mon, 22 Jun 2015 12:20:58 +0100 Subject: [PATCH 6114/7006] MIPS: Declare MSA MI10 instruction formats Declare a struct describing the MSA MI10 instruction format used for ld & st instructions, for use by subsequent patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Steven J. Hill Cc: linux-kernel@vger.kernel.org Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10571/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/inst.h | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index fc0cf5ac0cf72..3dce80e679488 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -26,7 +26,7 @@ enum major_op { cop0_op, cop1_op, cop2_op, cop1x_op, beql_op, bnel_op, blezl_op, bgtzl_op, daddi_op, cbcond1_op = daddi_op, daddiu_op, ldl_op, ldr_op, - spec2_op, jalx_op, mdmx_op, spec3_op, + spec2_op, jalx_op, mdmx_op, msa_op = mdmx_op, spec3_op, lb_op, lh_op, lwl_op, lw_op, lbu_op, lhu_op, lwr_op, lwu_op, sb_op, sh_op, swl_op, sw_op, @@ -220,6 +220,24 @@ enum bshfl_func { seh_op = 0x18, }; +/* + * func field for MSA MI10 format. + */ +enum msa_mi10_func { + msa_ld_op = 8, + msa_st_op = 9, +}; + +/* + * MSA 2 bit format fields. + */ +enum msa_2b_fmt { + msa_fmt_b = 0, + msa_fmt_h = 1, + msa_fmt_w = 2, + msa_fmt_d = 3, +}; + /* * (microMIPS) Major opcodes. */ @@ -611,6 +629,16 @@ struct v_format { /* MDMX vector format */ ;))))))) }; +struct msa_mi10_format { /* MSA MI10 */ + __BITFIELD_FIELD(unsigned int opcode : 6, + __BITFIELD_FIELD(signed int s10 : 10, + __BITFIELD_FIELD(unsigned int rs : 5, + __BITFIELD_FIELD(unsigned int wd : 5, + __BITFIELD_FIELD(unsigned int func : 4, + __BITFIELD_FIELD(unsigned int df : 2, + ;)))))) +}; + struct spec3_format { /* SPEC3 */ __BITFIELD_FIELD(unsigned int opcode:6, __BITFIELD_FIELD(unsigned int rs:5, @@ -888,6 +916,7 @@ union mips_instruction { struct p_format p_format; struct f_format f_format; struct ma_format ma_format; + struct msa_mi10_format msa_mi10_format; struct b_format b_format; struct ps_format ps_format; struct v_format v_format; -- GitLab From 6b35e11442db48638c9e9f2ff19f706484a73abe Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 22 Jun 2015 12:20:59 +0100 Subject: [PATCH 6115/7006] MIPS: Introduce accessors for MSA vector registers Introduce accessor functions allowing the kernel to access arbitrary vector registers using an arbitrary data format. The accessors are implemented in assembly, using macros to avoid massive duplication, in order to make use of the existing support for MSA with & without toolchain support. The accessors will be used in a later patch. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Cc: Manuel Lauss Patchwork: https://patchwork.linux-mips.org/patch/10572/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/asmmacro.h | 114 +++++++++++++++++++++++++++++++ arch/mips/include/asm/msa.h | 80 ++++++++++++++++++++++ arch/mips/kernel/r4k_fpu.S | 67 ++++++++++++++++++ 3 files changed, 261 insertions(+) diff --git a/arch/mips/include/asm/asmmacro.h b/arch/mips/include/asm/asmmacro.h index 76317a70200d1..867f924b05c79 100644 --- a/arch/mips/include/asm/asmmacro.h +++ b/arch/mips/include/asm/asmmacro.h @@ -232,6 +232,30 @@ .set pop .endm + .macro ld_b wd, off, base + .set push + .set mips32r2 + .set msa + ld.b $w\wd, \off(\base) + .set pop + .endm + + .macro ld_h wd, off, base + .set push + .set mips32r2 + .set msa + ld.h $w\wd, \off(\base) + .set pop + .endm + + .macro ld_w wd, off, base + .set push + .set mips32r2 + .set msa + ld.w $w\wd, \off(\base) + .set pop + .endm + .macro ld_d wd, off, base .set push .set mips32r2 @@ -241,6 +265,30 @@ .set pop .endm + .macro st_b wd, off, base + .set push + .set mips32r2 + .set msa + st.b $w\wd, \off(\base) + .set pop + .endm + + .macro st_h wd, off, base + .set push + .set mips32r2 + .set msa + st.h $w\wd, \off(\base) + .set pop + .endm + + .macro st_w wd, off, base + .set push + .set mips32r2 + .set msa + st.w $w\wd, \off(\base) + .set pop + .endm + .macro st_d wd, off, base .set push .set mips32r2 @@ -290,7 +338,13 @@ #ifdef CONFIG_CPU_MICROMIPS #define CFC_MSA_INSN 0x587e0056 #define CTC_MSA_INSN 0x583e0816 +#define LDB_MSA_INSN 0x58000807 +#define LDH_MSA_INSN 0x58000817 +#define LDW_MSA_INSN 0x58000827 #define LDD_MSA_INSN 0x58000837 +#define STB_MSA_INSN 0x5800080f +#define STH_MSA_INSN 0x5800081f +#define STW_MSA_INSN 0x5800082f #define STD_MSA_INSN 0x5800083f #define COPY_UW_MSA_INSN 0x58f00056 #define COPY_UD_MSA_INSN 0x58f80056 @@ -299,7 +353,13 @@ #else #define CFC_MSA_INSN 0x787e0059 #define CTC_MSA_INSN 0x783e0819 +#define LDB_MSA_INSN 0x78000820 +#define LDH_MSA_INSN 0x78000821 +#define LDW_MSA_INSN 0x78000822 #define LDD_MSA_INSN 0x78000823 +#define STB_MSA_INSN 0x78000824 +#define STH_MSA_INSN 0x78000825 +#define STW_MSA_INSN 0x78000826 #define STD_MSA_INSN 0x78000827 #define COPY_UW_MSA_INSN 0x78f00059 #define COPY_UD_MSA_INSN 0x78f80059 @@ -329,6 +389,33 @@ .set pop .endm + .macro ld_b wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word LDB_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro ld_h wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word LDH_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro ld_w wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word LDW_MSA_INSN | (\wd << 6) + .set pop + .endm + .macro ld_d wd, off, base .set push .set noat @@ -338,6 +425,33 @@ .set pop .endm + .macro st_b wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word STB_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro st_h wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word STH_MSA_INSN | (\wd << 6) + .set pop + .endm + + .macro st_w wd, off, base + .set push + .set noat + SET_HARDFLOAT + addu $1, \base, \off + .word STW_MSA_INSN | (\wd << 6) + .set pop + .endm + .macro st_d wd, off, base .set push .set noat diff --git a/arch/mips/include/asm/msa.h b/arch/mips/include/asm/msa.h index af5638b12c756..bbb85fe21642f 100644 --- a/arch/mips/include/asm/msa.h +++ b/arch/mips/include/asm/msa.h @@ -14,10 +14,90 @@ #ifndef __ASSEMBLY__ +#include + extern void _save_msa(struct task_struct *); extern void _restore_msa(struct task_struct *); extern void _init_msa_upper(void); +extern void read_msa_wr_b(unsigned idx, union fpureg *to); +extern void read_msa_wr_h(unsigned idx, union fpureg *to); +extern void read_msa_wr_w(unsigned idx, union fpureg *to); +extern void read_msa_wr_d(unsigned idx, union fpureg *to); + +/** + * read_msa_wr() - Read a single MSA vector register + * @idx: The index of the vector register to read + * @to: The FPU register union to store the registers value in + * @fmt: The format of the data in the vector register + * + * Read the value of MSA vector register idx into the FPU register + * union to, using the format fmt. + */ +static inline void read_msa_wr(unsigned idx, union fpureg *to, + enum msa_2b_fmt fmt) +{ + switch (fmt) { + case msa_fmt_b: + read_msa_wr_b(idx, to); + break; + + case msa_fmt_h: + read_msa_wr_h(idx, to); + break; + + case msa_fmt_w: + read_msa_wr_w(idx, to); + break; + + case msa_fmt_d: + read_msa_wr_d(idx, to); + break; + + default: + BUG(); + } +} + +extern void write_msa_wr_b(unsigned idx, union fpureg *from); +extern void write_msa_wr_h(unsigned idx, union fpureg *from); +extern void write_msa_wr_w(unsigned idx, union fpureg *from); +extern void write_msa_wr_d(unsigned idx, union fpureg *from); + +/** + * write_msa_wr() - Write a single MSA vector register + * @idx: The index of the vector register to write + * @from: The FPU register union to take the registers value from + * @fmt: The format of the data in the vector register + * + * Write the value from the FPU register union from into MSA vector + * register idx, using the format fmt. + */ +static inline void write_msa_wr(unsigned idx, union fpureg *from, + enum msa_2b_fmt fmt) +{ + switch (fmt) { + case msa_fmt_b: + write_msa_wr_b(idx, from); + break; + + case msa_fmt_h: + write_msa_wr_h(idx, from); + break; + + case msa_fmt_w: + write_msa_wr_w(idx, from); + break; + + case msa_fmt_d: + write_msa_wr_d(idx, from); + break; + + default: + BUG(); + } +} + static inline void enable_msa(void) { if (cpu_has_msa) { diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 1d88af26ba82a..ca887da1a48a2 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -13,6 +13,7 @@ * Copyright (C) 1999, 2001 Silicon Graphics, Inc. */ #include +#include #include #include #include @@ -274,6 +275,72 @@ LEAF(_restore_fp_context32) END(_restore_fp_context32) #endif +#ifdef CONFIG_CPU_HAS_MSA + + .macro op_one_wr op, idx, base + .align 4 +\idx: \op \idx, 0, \base + jr ra + nop + .endm + + .macro op_msa_wr name, op +LEAF(\name) + .set push + .set noreorder + sll t0, a0, 4 + PTR_LA t1, 0f + PTR_ADDU t0, t0, t1 + jr t0 + nop + op_one_wr \op, 0, a1 + op_one_wr \op, 1, a1 + op_one_wr \op, 2, a1 + op_one_wr \op, 3, a1 + op_one_wr \op, 4, a1 + op_one_wr \op, 5, a1 + op_one_wr \op, 6, a1 + op_one_wr \op, 7, a1 + op_one_wr \op, 8, a1 + op_one_wr \op, 9, a1 + op_one_wr \op, 10, a1 + op_one_wr \op, 11, a1 + op_one_wr \op, 12, a1 + op_one_wr \op, 13, a1 + op_one_wr \op, 14, a1 + op_one_wr \op, 15, a1 + op_one_wr \op, 16, a1 + op_one_wr \op, 17, a1 + op_one_wr \op, 18, a1 + op_one_wr \op, 19, a1 + op_one_wr \op, 20, a1 + op_one_wr \op, 21, a1 + op_one_wr \op, 22, a1 + op_one_wr \op, 23, a1 + op_one_wr \op, 24, a1 + op_one_wr \op, 25, a1 + op_one_wr \op, 26, a1 + op_one_wr \op, 27, a1 + op_one_wr \op, 28, a1 + op_one_wr \op, 29, a1 + op_one_wr \op, 30, a1 + op_one_wr \op, 31, a1 + .set pop + END(\name) + .endm + + op_msa_wr read_msa_wr_b, st_b + op_msa_wr read_msa_wr_h, st_h + op_msa_wr read_msa_wr_w, st_w + op_msa_wr read_msa_wr_d, st_d + + op_msa_wr write_msa_wr_b, ld_b + op_msa_wr write_msa_wr_h, ld_h + op_msa_wr write_msa_wr_w, ld_w + op_msa_wr write_msa_wr_d, ld_d + +#endif /* CONFIG_CPU_HAS_MSA */ + .set reorder .type fault@function -- GitLab From e4aa1f153add29343eeb8b3bf0f64e7c6fc7e697 Mon Sep 17 00:00:00 2001 From: Leonid Yegoshin Date: Mon, 22 Jun 2015 12:21:00 +0100 Subject: [PATCH 6116/7006] MIPS: MSA unaligned memory access support The MSA architecture specification allows for hardware to not implement unaligned vector memory accesses in some or all cases. A typical example of this is the I6400 core which does not implement unaligned vector memory access when the memory crosses a page boundary. The architecture also requires that such memory accesses complete successfully as far as userland is concerned, so the kernel is required to emulate them. This patch implements support for emulating unaligned MSA ld & st instructions by copying between the user memory & the tasks FP context in struct thread_struct, updating hardware registers from there as appropriate in order to avoid saving & restoring the entire vector context for each unaligned memory access. Tested both using an I6400 CPU and with a QEMU build hacked to produce AdEL exceptions for unaligned vector memory accesses. [paul.burton@imgtec.com: - Remove #ifdef's - Move msa_op into enum major_op rather than #define - Replace msa_{to,from}_wd with {read,write}_msa_wr_{b,h,w,l} and the format-agnostic wrappers, removing the custom endian mangling for big endian systems. - Restructure the msa_op case in emulate_load_store_insn to share more code between the load & store cases. - Avoid the need for a temporary union fpureg on the stack by simply reusing the already suitably aligned context in struct thread_struct. - Use sizeof(*fpr) rather than hardcoding 16 as the size for user memory checks & copies. - Stop recalculating the address of the unaligned vector memory access and rely upon the value read from BadVAddr as we do for other unaligned memory access instructions. - Drop the now unused val8 & val16 fields in union fpureg. - Rewrite commit message. - General formatting cleanups.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Huacai Chen Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Jie Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10573/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/unaligned.c | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index eb3efd137fd17..f55869c00ce45 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -891,6 +891,9 @@ static void emulate_load_store_insn(struct pt_regs *regs, #ifdef CONFIG_EVA mm_segment_t seg; #endif + union fpureg *fpr; + enum msa_2b_fmt df; + unsigned int wd; origpc = (unsigned long)pc; orig31 = regs->regs[31]; @@ -1202,6 +1205,75 @@ static void emulate_load_store_insn(struct pt_regs *regs, break; return; + case msa_op: + if (!cpu_has_msa) + goto sigill; + + /* + * If we've reached this point then userland should have taken + * the MSA disabled exception & initialised vector context at + * some point in the past. + */ + BUG_ON(!thread_msa_context_live()); + + df = insn.msa_mi10_format.df; + wd = insn.msa_mi10_format.wd; + fpr = ¤t->thread.fpu.fpr[wd]; + + switch (insn.msa_mi10_format.func) { + case msa_ld_op: + if (!access_ok(VERIFY_READ, addr, sizeof(*fpr))) + goto sigbus; + + /* + * Disable preemption to avoid a race between copying + * state from userland, migrating to another CPU and + * updating the hardware vector register below. + */ + preempt_disable(); + + res = __copy_from_user_inatomic(fpr, addr, + sizeof(*fpr)); + if (res) + goto fault; + + /* + * Update the hardware register if it is in use by the + * task in this quantum, in order to avoid having to + * save & restore the whole vector context. + */ + if (test_thread_flag(TIF_USEDMSA)) + write_msa_wr(wd, fpr, df); + + preempt_enable(); + break; + + case msa_st_op: + if (!access_ok(VERIFY_WRITE, addr, sizeof(*fpr))) + goto sigbus; + + /* + * Update from the hardware register if it is in use by + * the task in this quantum, in order to avoid having to + * save & restore the whole vector context. + */ + preempt_disable(); + if (test_thread_flag(TIF_USEDMSA)) + read_msa_wr(wd, fpr, df); + preempt_enable(); + + res = __copy_to_user_inatomic(addr, fpr, sizeof(*fpr)); + if (res) + goto fault; + break; + + default: + goto sigbus; + } + + compute_return_epc(regs); + break; + #ifndef CONFIG_CPU_MIPSR6 /* * COP2 is available to implementor for application specific use. -- GitLab From cbd95a89996d1b5fadf411e9218c64e713a83099 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 10 Jul 2015 16:52:38 +0100 Subject: [PATCH 6117/7006] MIPS: mm: default platform_maar_init using bootmem data Introduce a default weak implementation of platform_maar_init which makes use of the data that platforms already provide to the bootmem allocator. This should hopefully cover the most common configurations, reduce the duplication of information provided by platforms & leaves platforms with the option of providing a custom implementation if required. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Paolo Bonzini Cc: Steven J. Hill Cc: linux-kernel@vger.kernel.org Cc: Ard Biesheuvel Patchwork: https://patchwork.linux-mips.org/patch/10676/ Signed-off-by: Ralf Baechle --- arch/mips/mm/init.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c index 198a3147dd7d0..66d0f49c5bec4 100644 --- a/arch/mips/mm/init.c +++ b/arch/mips/mm/init.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -333,9 +334,40 @@ static inline void mem_init_free_highmem(void) #endif } -unsigned __weak platform_maar_init(unsigned num_maars) +unsigned __weak platform_maar_init(unsigned num_pairs) { - return 0; + struct maar_config cfg[BOOT_MEM_MAP_MAX]; + unsigned i, num_configured, num_cfg = 0; + phys_addr_t skip; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_INIT_RAM: + break; + default: + continue; + } + + skip = 0x10000 - (boot_mem_map.map[i].addr & 0xffff); + + cfg[num_cfg].lower = boot_mem_map.map[i].addr; + cfg[num_cfg].lower += skip; + + cfg[num_cfg].upper = cfg[num_cfg].lower; + cfg[num_cfg].upper += boot_mem_map.map[i].size - 1; + cfg[num_cfg].upper -= skip; + + cfg[num_cfg].attrs = MIPS_MAAR_S; + num_cfg++; + } + + num_configured = maar_config(cfg, num_cfg, num_pairs); + if (num_configured < num_cfg) + pr_warn("Not enough MAAR pairs (%u) for all bootmem regions (%u)\n", + num_pairs, num_cfg); + + return num_configured; } static void maar_init(void) -- GitLab From 570e5d26ff2e970e018343675bc64302420221d8 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 10 Jul 2015 16:52:39 +0100 Subject: [PATCH 6118/7006] MIPS: malta: Use generic platform_maar_init The default implementation of platform_maar_init is sufficient for Malta boards where we want to allow speculation in the regions of memory corresponding to DDR & disallow it elsewhere. Drop the custom implementation such that the default is used, reducing the duplication of information provided by the Malta platform code. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10677/ Signed-off-by: Ralf Baechle --- arch/mips/mti-malta/malta-memory.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/arch/mips/mti-malta/malta-memory.c b/arch/mips/mti-malta/malta-memory.c index b769657be4d46..dadeb83791828 100644 --- a/arch/mips/mti-malta/malta-memory.c +++ b/arch/mips/mti-malta/malta-memory.c @@ -179,31 +179,6 @@ void __init prom_free_prom_memory(void) } } -unsigned platform_maar_init(unsigned num_pairs) -{ - phys_addr_t mem_end = (physical_memsize & ~0xffffull) - 1; - struct maar_config cfg[] = { - /* DRAM preceding I/O */ - { 0x00000000, 0x0fffffff, MIPS_MAAR_S }, - - /* DRAM following I/O */ - { 0x20000000, mem_end, MIPS_MAAR_S }, - - /* DRAM alias in upper half of physical */ - { 0x80000000, 0x80000000 + mem_end, MIPS_MAAR_S }, - }; - unsigned i, num_cfg = ARRAY_SIZE(cfg); - - /* If DRAM fits before I/O, drop the region following it */ - if (physical_memsize <= 0x10000000) { - num_cfg--; - for (i = 1; i < num_cfg; i++) - cfg[i] = cfg[i + 1]; - } - - return maar_config(cfg, num_cfg, num_pairs); -} - phys_addr_t mips_cdmm_phys_base(void) { /* This address is "typically unused" */ -- GitLab From 82eb8f7342cf722a8bf3d42e9982f56bff166b85 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Wed, 15 Jul 2015 10:44:30 +1200 Subject: [PATCH 6119/7006] MIPS: Use unsigned int when reading CP0 registers Update __read_32bit_c0_register() and __read_32bit_c0_ctrl_register() to use "unsigned int res;" instead of "int res;". There is little reason to treat these register values as signed. They are either counters (which by definition are unsigned) or are made up of various bit fields to be interpreted as per the CPU datasheet. This has come up via u-boot[1] which sync's asm/mipsregs.h with the kernel. In u-boots case the value read from read_c0_count() is assigned to an unsigned long [2] which triggers a sign extension and causes a bug. U-boot should probably be more explicit about the types used for the timer_read_counter() API but that aside is there any reason to treat these values as signed integers? A quick grep around the arch/mips makes me thing that there may be some bugs lurking when read_c0_count() starts to yield a negative value but I haven't really explored any of them. [1] - http://lists.denx.de/pipermail/u-boot/2015-July/219086.html [2] - http://git.denx.de/?p=u-boot.git;a=blob;f=arch/mips/cpu/time.c#l11 Signed-off-by: Chris Packham Cc: linux-mips@linux-mips.org Cc: Daniel Schwierzeck Cc: Chris Packham Cc: Steven J. Hill Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Cc: Paul Burton Patchwork: https://patchwork.linux-mips.org/patch/10718/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 723ee3c7849d2..07bf4e7109acf 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -934,7 +934,7 @@ do { \ */ #define __read_32bit_c0_register(source, sel) \ -({ int __res; \ +({ unsigned int __res; \ if (sel == 0) \ __asm__ __volatile__( \ "mfc0\t%0, " #source "\n\t" \ @@ -1016,7 +1016,7 @@ do { \ * On RM7000/RM9000 these are uses to access cop0 set 1 registers */ #define __read_32bit_c0_ctrl_register(source) \ -({ int __res; \ +({ unsigned int __res; \ __asm__ __volatile__( \ "cfc0\t%0, " #source "\n\t" \ : "=r" (__res)); \ -- GitLab From c46a2f01fb2bea6ae7e4e3f3f2aad65d8eda837d Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 15 Jul 2015 11:48:15 +0200 Subject: [PATCH 6120/7006] MIPS: Treat CP1 control registers as unsigned ints. These are bitfields and treating them as signed values doesn't make any sense. Signed-off-by: Ralf Baechle Reported-by: Chris Packham --- arch/mips/include/asm/mipsregs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index 07bf4e7109acf..b688c924a0258 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -1473,7 +1473,7 @@ do { \ */ #define _read_32bit_cp1_register(source, gas_hardfloat) \ ({ \ - int __res; \ + unsigned int __res; \ \ __asm__ __volatile__( \ " .set push \n" \ -- GitLab From 674d10e26dd4c1a1b9161e9dcce0667d1c5dd318 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 16 Jul 2015 13:24:46 +0100 Subject: [PATCH 6121/7006] MIPS: Kconfig: Drop the EXPERIMENTAL tag from MIPS R6 The MIPS R6 ISA support has been part of mainline since v4.0 and it should be in a good shape nowadays so it is not an experimental feature anymore. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10731/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 60d7ae76dd7e5..52b7918da21a3 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1367,7 +1367,7 @@ config CPU_MIPS32_R2 otherwise CPU_MIPS32_R1 is a safe bet for any MIPS32 system. config CPU_MIPS32_R6 - bool "MIPS32 Release 6 (EXPERIMENTAL)" + bool "MIPS32 Release 6" depends on SYS_HAS_CPU_MIPS32_R6 select CPU_HAS_PREFETCH select CPU_SUPPORTS_32BIT_KERNEL @@ -1418,7 +1418,7 @@ config CPU_MIPS64_R2 otherwise CPU_MIPS64_R1 is a safe bet for any MIPS64 system. config CPU_MIPS64_R6 - bool "MIPS64 Release 6 (EXPERIMENTAL)" + bool "MIPS64 Release 6" depends on SYS_HAS_CPU_MIPS64_R6 select CPU_HAS_PREFETCH select CPU_SUPPORTS_32BIT_KERNEL -- GitLab From bbdd8147b1b9efb7268a7cad31e148d794363abe Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 16 Jul 2015 14:06:45 +0100 Subject: [PATCH 6122/7006] MIPS: cp1emu: Fix closing bracket for the d_fmt case The double format (d_fmt) case uses an opening bracket which then closes at the end of the word format (w_fmt). This can be rather confusing so add the closing bracket at the end of the d_fmt case and use another one for the w_fmt one. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10733/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 712f17a2ecf20..cd858953a7837 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -2021,8 +2021,11 @@ dcopuop: break; } break; + } + + case w_fmt: { + union ieee754dp fs; - case w_fmt: switch (MIPSInst_FUNC(ir)) { case fcvts_op: /* convert word to single precision real */ -- GitLab From 166457436e38175e1d9891f98d9d6edbee100f32 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 16 Jul 2015 16:43:33 +0100 Subject: [PATCH 6123/7006] MIPS: math-emu: Fix indentation Fix indentation for the final 'else' blocks. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10735/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/ieee754int.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/mips/math-emu/ieee754int.h b/arch/mips/math-emu/ieee754int.h index 05389d5e3a933..6383e2c5c1adb 100644 --- a/arch/mips/math-emu/ieee754int.h +++ b/arch/mips/math-emu/ieee754int.h @@ -65,8 +65,8 @@ static inline int ieee754_class_nan(int xc) vc = IEEE754_CLASS_INF; \ else if (vm & SP_MBIT(SP_FBITS-1)) \ vc = IEEE754_CLASS_SNAN; \ - else \ - vc = IEEE754_CLASS_QNAN; \ + else \ + vc = IEEE754_CLASS_QNAN; \ } else if (ve == SP_EMIN-1+SP_EBIAS) { \ if (vm) { \ ve = SP_EMIN; \ @@ -105,8 +105,8 @@ static inline int ieee754_class_nan(int xc) if (vm) { \ ve = DP_EMIN; \ vc = IEEE754_CLASS_DNORM; \ - } else \ - vc = IEEE754_CLASS_ZERO; \ + } else \ + vc = IEEE754_CLASS_ZERO; \ } else { \ ve -= DP_EBIAS; \ vm |= DP_HIDDEN_BIT; \ -- GitLab From e8f80cc1a6d80587136b015e989a12827e1fcfe5 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Fri, 17 Jul 2015 10:36:03 +0100 Subject: [PATCH 6124/7006] MIPS: math-emu: Allow m{f,t}hc emulation on MIPS R6 The mfhc/mthc instructions are supported on MIPS R6 so emulate them if needed. Signed-off-by: Markos Chandras Cc: # 4.0+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10737/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index cd858953a7837..e78b1ae6dcdb7 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1137,7 +1137,7 @@ emul: break; case mfhc_op: - if (!cpu_has_mips_r2) + if (!cpu_has_mips_r2_r6) goto sigill; /* copregister rd -> gpr[rt] */ @@ -1148,7 +1148,7 @@ emul: break; case mthc_op: - if (!cpu_has_mips_r2) + if (!cpu_has_mips_r2_r6) goto sigill; /* copregister rd <- gpr[rt] */ -- GitLab From c909ca718e8f50cf484ef06a8dd935e738e8e53d Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Fri, 17 Jul 2015 10:38:32 +0100 Subject: [PATCH 6125/7006] MIPS: math-emu: Emulate missing BC1{EQ,NE}Z instructions Commit c8a34581ec09 ("MIPS: Emulate the BC1{EQ,NE}Z FPU instructions") added support for emulating the new R6 BC1{EQ,NE}Z branches but it missed the case where the instruction that caused the exception was not on a DS. Signed-off-by: Markos Chandras Fixes: c8a34581ec09 ("MIPS: Emulate the BC1{EQ,NE}Z FPU instructions") Cc: # 4.0+ Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10738/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index e78b1ae6dcdb7..8a5b0eb4ddef4 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1181,6 +1181,24 @@ emul: } break; + case bc1eqz_op: + case bc1nez_op: + if (!cpu_has_mips_r6 || delay_slot(xcp)) + return SIGILL; + + cond = likely = 0; + switch (MIPSInst_RS(ir)) { + case bc1eqz_op: + if (get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1) + cond = 1; + break; + case bc1nez_op: + if (!(get_fpr32(¤t->thread.fpu.fpr[MIPSInst_RT(ir)], 0) & 0x1)) + cond = 1; + break; + } + goto branch_common; + case bc_op: if (delay_slot(xcp)) return SIGILL; @@ -1207,7 +1225,7 @@ emul: case bct_op: break; } - +branch_common: set_delay_slot(xcp); if (cond) { /* -- GitLab From 0f6ce77538c3f0628acdeee30738e4c8fe08d7e2 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:42 +0100 Subject: [PATCH 6126/7006] Documentation/sysrq.txt: Mention MIPS TLB dump (x) Commit d1e9a4f54735 ("MIPS: Add SysRq operation to dump TLBs on all CPUs") added the 'x' sysrq key for dumping MIPS TLB entries, but didn't document it in Documentation/sysrq.txt. Add mention of the MIPS use of the 'x' SysRq key. Reported-by: Maciej W. Rozycki Signed-off-by: James Hogan Acked-by: Jonathan Corbet Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Cc: linux-doc@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10720/ Signed-off-by: Ralf Baechle --- Documentation/sysrq.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index 0e307c94809a0..267f39386f99f 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt @@ -119,6 +119,7 @@ On all - write a character to /proc/sysrq-trigger. e.g.: 'x' - Used by xmon interface on ppc/powerpc platforms. Show global PMU Registers on sparc64. + Dump all TLB entries on MIPS. 'y' - Show global CPU Registers [SPARC-64 specific] -- GitLab From 3c865dd9c1d64046877112451f13db2cb46d4d28 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:43 +0100 Subject: [PATCH 6127/7006] MIPS: Refactor dumping of TLB registers for r3k/r4k The TLB registers are dumped in a couble of places: - sysrq_tlbdump_single() - when dumping TLB state. - do_mcheck() - in response to a machine check error. The main TLB registers also differ between r3k and r4k, but r4k appears to be assumed. Refactor this code into a dump_tlb_regs() function, implemented for both r3k and r4k, and used by both of the above functions. Fixes: d1e9a4f54735 ("MIPS: Add SysRq operation to dump TLBs on all CPUs") Suggested-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10721/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/tlbdebug.h | 1 + arch/mips/kernel/sysrq.c | 14 +------------- arch/mips/kernel/traps.c | 16 ++-------------- arch/mips/lib/dump_tlb.c | 18 ++++++++++++++++++ arch/mips/lib/r3k_dump_tlb.c | 11 +++++++++++ arch/mips/mm/tlb-r3k.c | 2 +- 6 files changed, 34 insertions(+), 28 deletions(-) diff --git a/arch/mips/include/asm/tlbdebug.h b/arch/mips/include/asm/tlbdebug.h index bb8f5c29c3d9f..3a25a8780ac76 100644 --- a/arch/mips/include/asm/tlbdebug.h +++ b/arch/mips/include/asm/tlbdebug.h @@ -11,6 +11,7 @@ /* * TLB debugging functions: */ +extern void dump_tlb_regs(void); extern void dump_tlb_all(void); #endif /* __ASM_TLBDEBUG_H */ diff --git a/arch/mips/kernel/sysrq.c b/arch/mips/kernel/sysrq.c index 5b539f5fc9d9d..5f055393092de 100644 --- a/arch/mips/kernel/sysrq.c +++ b/arch/mips/kernel/sysrq.c @@ -21,24 +21,12 @@ static DEFINE_SPINLOCK(show_lock); static void sysrq_tlbdump_single(void *dummy) { - const int field = 2 * sizeof(unsigned long); unsigned long flags; spin_lock_irqsave(&show_lock, flags); pr_info("CPU%d:\n", smp_processor_id()); - pr_info("Index : %0x\n", read_c0_index()); - pr_info("Pagemask: %0x\n", read_c0_pagemask()); - pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); - pr_info("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); - pr_info("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); - pr_info("Wired : %0x\n", read_c0_wired()); - pr_info("Pagegrain: %0x\n", read_c0_pagegrain()); - if (cpu_has_htw) { - pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); - pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); - pr_info("PWCtl : %0x\n", read_c0_pwctl()); - } + dump_tlb_regs(); pr_info("\n"); dump_tlb_all(); pr_info("\n"); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 01da120d75c44..da0b3189fe883 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -1523,7 +1523,6 @@ asmlinkage void do_watch(struct pt_regs *regs) asmlinkage void do_mcheck(struct pt_regs *regs) { - const int field = 2 * sizeof(unsigned long); int multi_match = regs->cp0_status & ST0_TS; enum ctx_state prev_state; mm_segment_t old_fs = get_fs(); @@ -1532,19 +1531,8 @@ asmlinkage void do_mcheck(struct pt_regs *regs) show_regs(regs); if (multi_match) { - pr_err("Index : %0x\n", read_c0_index()); - pr_err("Pagemask: %0x\n", read_c0_pagemask()); - pr_err("EntryHi : %0*lx\n", field, read_c0_entryhi()); - pr_err("EntryLo0: %0*lx\n", field, read_c0_entrylo0()); - pr_err("EntryLo1: %0*lx\n", field, read_c0_entrylo1()); - pr_err("Wired : %0x\n", read_c0_wired()); - pr_err("Pagegrain: %0x\n", read_c0_pagegrain()); - if (cpu_has_htw) { - pr_err("PWField : %0*lx\n", field, read_c0_pwfield()); - pr_err("PWSize : %0*lx\n", field, read_c0_pwsize()); - pr_err("PWCtl : %0x\n", read_c0_pwctl()); - } - pr_err("\n"); + dump_tlb_regs(); + pr_info("\n"); dump_tlb_all(); } diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 167f35634709b..519ededbf9a4c 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -13,6 +13,24 @@ #include #include +void dump_tlb_regs(void) +{ + const int field = 2 * sizeof(unsigned long); + + pr_info("Index : %0x\n", read_c0_index()); + pr_info("PageMask : %0x\n", read_c0_pagemask()); + pr_info("EntryHi : %0*lx\n", field, read_c0_entryhi()); + pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); + pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); + pr_info("Wired : %0x\n", read_c0_wired()); + pr_info("PageGrain: %0x\n", read_c0_pagegrain()); + if (cpu_has_htw) { + pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); + pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); + pr_info("PWCtl : %0x\n", read_c0_pwctl()); + } +} + static inline const char *msk2str(unsigned int mask) { switch (mask) { diff --git a/arch/mips/lib/r3k_dump_tlb.c b/arch/mips/lib/r3k_dump_tlb.c index 8e0d3cff8ae44..cfcbb5218b595 100644 --- a/arch/mips/lib/r3k_dump_tlb.c +++ b/arch/mips/lib/r3k_dump_tlb.c @@ -14,6 +14,17 @@ #include #include +extern int r3k_have_wired_reg; + +void dump_tlb_regs(void) +{ + pr_info("Index : %0x\n", read_c0_index()); + pr_info("EntryHi : %0lx\n", read_c0_entryhi()); + pr_info("EntryLo : %0lx\n", read_c0_entrylo0()); + if (r3k_have_wired_reg) + pr_info("Wired : %0x\n", read_c0_wired()); +} + static void dump_tlb(int first, int last) { int i; diff --git a/arch/mips/mm/tlb-r3k.c b/arch/mips/mm/tlb-r3k.c index 2b75b8f880ed1..b4f366f7c0f57 100644 --- a/arch/mips/mm/tlb-r3k.c +++ b/arch/mips/mm/tlb-r3k.c @@ -36,7 +36,7 @@ extern void build_tlb_refill_handler(void); "nop\n\t" \ ".set pop\n\t") -static int r3k_have_wired_reg; /* Should be in cpu_data? */ +int r3k_have_wired_reg; /* Should be in cpu_data? */ /* TLB operations. */ static void local_flush_tlb_from(int entry) -- GitLab From aaa7be48fdbf14836ff1bc61c72969960a5923c6 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:44 +0100 Subject: [PATCH 6128/7006] MIPS: Probe for small (1KiB) page support Probe Config3 for small page support. This will be useful to give clues as to whether the PageGrain register exists. Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10722/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cpu-features.h | 4 ++++ arch/mips/include/asm/cpu.h | 1 + arch/mips/kernel/cpu-probe.c | 2 ++ 3 files changed, 7 insertions(+) diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index f25de771f7ed2..9801ac9826554 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -411,4 +411,8 @@ # define cpu_has_cdmm (cpu_data[0].options & MIPS_CPU_CDMM) #endif +#ifndef cpu_has_small_pages +# define cpu_has_small_pages (cpu_data[0].options & MIPS_CPU_SP) +#endif + #endif /* __ASM_CPU_FEATURES_H */ diff --git a/arch/mips/include/asm/cpu.h b/arch/mips/include/asm/cpu.h index 5fa7b8ba48a90..cd89e98557752 100644 --- a/arch/mips/include/asm/cpu.h +++ b/arch/mips/include/asm/cpu.h @@ -384,6 +384,7 @@ enum cpu_type_enum { #define MIPS_CPU_XPA 0x2000000000ull /* CPU supports Extended Physical Addressing */ #define MIPS_CPU_CDMM 0x4000000000ull /* CPU has Common Device Memory Map */ #define MIPS_CPU_BP_GHIST 0x8000000000ull /* R12K+ Branch Prediction Global History */ +#define MIPS_CPU_SP 0x10000000000ull /* Small (1KB) page support */ /* * CPU ASE encodings diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 4e39b340f3b77..987036761fb61 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -538,6 +538,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c) } if (config3 & MIPS_CONF3_CDMM) c->options |= MIPS_CPU_CDMM; + if (config3 & MIPS_CONF3_SP) + c->options |= MIPS_CPU_SP; return config3 & MIPS_CONF_M; } -- GitLab From 5d3c3c7d296d9622560558de96875cf694d96f58 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:45 +0100 Subject: [PATCH 6129/7006] MIPS: dump_tlb: Only dump PageGrain if interesting The PageGrain register may not exist if certain architectural features aren't present, therefore only print out its value when dumping the TLB registers if it is expected to contain fields relevant to the TLB. Fixes: d1e9a4f54735 ("MIPS: Add SysRq operation to dump TLBs on all CPUs") Reported-by: Joshua Kinard Reported-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Joshua Kinard Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10723/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 519ededbf9a4c..2ab83be14ffaa 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -23,7 +23,8 @@ void dump_tlb_regs(void) pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); pr_info("Wired : %0x\n", read_c0_wired()); - pr_info("PageGrain: %0x\n", read_c0_pagegrain()); + if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa) + pr_info("PageGrain: %0x\n", read_c0_pagegrain()); if (cpu_has_htw) { pr_info("PWField : %0*lx\n", field, read_c0_pwfield()); pr_info("PWSize : %0*lx\n", field, read_c0_pwsize()); -- GitLab From 9bd860cae3c46a83371ce899ae0d665b6e253687 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:46 +0100 Subject: [PATCH 6130/7006] MIPS: dump_tlb: Dump FrameMask register if exists The FrameMask register is relevant to the TLB so it should be dumped by dump_tlb_regs(), however it is only present in certain cores (r10000, r12000, r14000, r16000). Add dumping of it, conditional upon current_cpu_type(). Suggested-by: Joshua Kinard Suggested-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Joshua Kinard Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10724/ Signed-off-by: Ralf Baechle --- arch/mips/lib/dump_tlb.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 2ab83be14ffaa..64f90f626681c 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -23,6 +23,14 @@ void dump_tlb_regs(void) pr_info("EntryLo0 : %0*lx\n", field, read_c0_entrylo0()); pr_info("EntryLo1 : %0*lx\n", field, read_c0_entrylo1()); pr_info("Wired : %0x\n", read_c0_wired()); + switch (current_cpu_type()) { + case CPU_R10000: + case CPU_R12000: + case CPU_R14000: + case CPU_R16000: + pr_info("FrameMask: %0x\n", read_c0_framemask()); + break; + } if (cpu_has_small_pages || cpu_has_rixi || cpu_has_xpa) pr_info("PageGrain: %0x\n", read_c0_pagegrain()); if (cpu_has_htw) { -- GitLab From bae637a2148c97882a1bbfdac08d7a5f4441cdb3 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Wed, 15 Jul 2015 16:17:47 +0100 Subject: [PATCH 6131/7006] MIPS: Rearrange ENTRYLO field definitions The generic field definitions (i.e. present before MIPS32/MIPS64) in mipsregs.h are conventionally not prefixed with MIPS_, so rename the recently added MIPS_ENTRYLO_* definitions for the G, V, D, and C fields to ENTRYLO_*. Also rearrange to put the EntryLo and EntryHi definitions in the right place in the file. Fixes: 8ab6abcb6aa4 ("MIPS: mipsregs.h: Add EntryLo bit definitions") Reported-by: Maciej W. Rozycki Signed-off-by: James Hogan Cc: Maciej W. Rozycki Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10725/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/mipsregs.h | 52 +++++++++++++++++--------------- arch/mips/lib/dump_tlb.c | 18 +++++------ 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h index b688c924a0258..d3cd8eac81e3a 100644 --- a/arch/mips/include/asm/mipsregs.h +++ b/arch/mips/include/asm/mipsregs.h @@ -112,6 +112,30 @@ #define CP0_TX39_CACHE $7 +/* Generic EntryLo bit definitions */ +#define ENTRYLO_G (_ULCAST_(1) << 0) +#define ENTRYLO_V (_ULCAST_(1) << 1) +#define ENTRYLO_D (_ULCAST_(1) << 2) +#define ENTRYLO_C_SHIFT 3 +#define ENTRYLO_C (_ULCAST_(7) << ENTRYLO_C_SHIFT) + +/* R3000 EntryLo bit definitions */ +#define R3K_ENTRYLO_G (_ULCAST_(1) << 8) +#define R3K_ENTRYLO_V (_ULCAST_(1) << 9) +#define R3K_ENTRYLO_D (_ULCAST_(1) << 10) +#define R3K_ENTRYLO_N (_ULCAST_(1) << 11) + +/* MIPS32/64 EntryLo bit definitions */ +#ifdef CONFIG_64BIT +/* as read by dmfc0 */ +#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62) +#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63) +#else +/* as read by mfc0 */ +#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30) +#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31) +#endif + /* * Values for PageMask register */ @@ -203,6 +227,9 @@ #define PG_ESP (_ULCAST_(1) << 28) #define PG_IEC (_ULCAST_(1) << 27) +/* MIPS32/64 EntryHI bit definitions */ +#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) + /* * R4x00 interrupt enable / cause bits */ @@ -588,31 +615,6 @@ #define MIPS_MAAR_S (_ULCAST_(1) << 1) #define MIPS_MAAR_V (_ULCAST_(1) << 0) -/* EntryHI bit definition */ -#define MIPS_ENTRYHI_EHINV (_ULCAST_(1) << 10) - -/* R3000 EntryLo bit definitions */ -#define R3K_ENTRYLO_G (_ULCAST_(1) << 8) -#define R3K_ENTRYLO_V (_ULCAST_(1) << 9) -#define R3K_ENTRYLO_D (_ULCAST_(1) << 10) -#define R3K_ENTRYLO_N (_ULCAST_(1) << 11) - -/* R4000 compatible EntryLo bit definitions */ -#define MIPS_ENTRYLO_G (_ULCAST_(1) << 0) -#define MIPS_ENTRYLO_V (_ULCAST_(1) << 1) -#define MIPS_ENTRYLO_D (_ULCAST_(1) << 2) -#define MIPS_ENTRYLO_C_SHIFT 3 -#define MIPS_ENTRYLO_C (_ULCAST_(7) << MIPS_ENTRYLO_C_SHIFT) -#ifdef CONFIG_64BIT -/* as read by dmfc0 */ -#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 62) -#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 63) -#else -/* as read by mfc0 */ -#define MIPS_ENTRYLO_XI (_ULCAST_(1) << 30) -#define MIPS_ENTRYLO_RI (_ULCAST_(1) << 31) -#endif - /* CMGCRBase bit definitions */ #define MIPS_CMGCRB_BASE 11 #define MIPS_CMGCRF_BASE (~_ULCAST_((1 << MIPS_CMGCRB_BASE) - 1)) diff --git a/arch/mips/lib/dump_tlb.c b/arch/mips/lib/dump_tlb.c index 64f90f626681c..92a37319efbe9 100644 --- a/arch/mips/lib/dump_tlb.c +++ b/arch/mips/lib/dump_tlb.c @@ -114,7 +114,7 @@ static void dump_tlb(int first, int last) * leave only a single G bit set after a machine check exception * due to duplicate TLB entry. */ - if (!((entrylo0 | entrylo1) & MIPS_ENTRYLO_G) && + if (!((entrylo0 | entrylo1) & ENTRYLO_G) && (entryhi & 0xff) != asid) continue; @@ -123,8 +123,8 @@ static void dump_tlb(int first, int last) */ printk("Index: %2d pgmask=%s ", i, msk2str(pagemask)); - c0 = (entrylo0 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; - c1 = (entrylo1 & MIPS_ENTRYLO_C) >> MIPS_ENTRYLO_C_SHIFT; + c0 = (entrylo0 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; + c1 = (entrylo1 & ENTRYLO_C) >> ENTRYLO_C_SHIFT; printk("va=%0*lx asid=%02lx\n", vwidth, (entryhi & ~0x1fffUL), @@ -141,9 +141,9 @@ static void dump_tlb(int first, int last) (entrylo0 & MIPS_ENTRYLO_XI) ? 1 : 0); printk("pa=%0*llx c=%d d=%d v=%d g=%d] [", pwidth, pa, c0, - (entrylo0 & MIPS_ENTRYLO_D) ? 1 : 0, - (entrylo0 & MIPS_ENTRYLO_V) ? 1 : 0, - (entrylo0 & MIPS_ENTRYLO_G) ? 1 : 0); + (entrylo0 & ENTRYLO_D) ? 1 : 0, + (entrylo0 & ENTRYLO_V) ? 1 : 0, + (entrylo0 & ENTRYLO_G) ? 1 : 0); /* RI/XI are in awkward places, so mask them off separately */ pa = entrylo1 & ~(MIPS_ENTRYLO_RI | MIPS_ENTRYLO_XI); if (xpa) @@ -155,9 +155,9 @@ static void dump_tlb(int first, int last) (entrylo1 & MIPS_ENTRYLO_XI) ? 1 : 0); printk("pa=%0*llx c=%d d=%d v=%d g=%d]\n", pwidth, pa, c1, - (entrylo1 & MIPS_ENTRYLO_D) ? 1 : 0, - (entrylo1 & MIPS_ENTRYLO_V) ? 1 : 0, - (entrylo1 & MIPS_ENTRYLO_G) ? 1 : 0); + (entrylo1 & ENTRYLO_D) ? 1 : 0, + (entrylo1 & ENTRYLO_V) ? 1 : 0, + (entrylo1 & ENTRYLO_G) ? 1 : 0); } printk("\n"); -- GitLab From 486fcde40d8f903dbd460fb0b5a35423528032e3 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 08:58:20 +0200 Subject: [PATCH 6132/7006] MIPS: Sibyte: Move bus watcher from deprecated __initcall to device_initcall Signed-off-by: Ralf Baechle --- arch/mips/sibyte/common/bus_watcher.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/sibyte/common/bus_watcher.c b/arch/mips/sibyte/common/bus_watcher.c index 41a1d22422112..a4e55999ecb4c 100644 --- a/arch/mips/sibyte/common/bus_watcher.c +++ b/arch/mips/sibyte/common/bus_watcher.c @@ -250,4 +250,4 @@ int __init sibyte_bus_watcher(void) return 0; } -__initcall(sibyte_bus_watcher); +device_initcall(sibyte_bus_watcher); -- GitLab From 8d6b591ce9b2706403b4c79d72c4483a7fbeda54 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 09:04:41 +0200 Subject: [PATCH 6133/7006] MIPS: unaligned: Move from deprecated __initcall to arch_initcall. Signed-off-by: Ralf Baechle --- arch/mips/kernel/unaligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index f55869c00ce45..990354dd6bded 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -2312,5 +2312,5 @@ static int __init debugfs_unaligned(void) return -ENOMEM; return 0; } -__initcall(debugfs_unaligned); +arch_initcall(debugfs_unaligned); #endif -- GitLab From 1bab0b627f6d9cd5af08f6be81288883d3b1aa9c Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 09:09:40 +0200 Subject: [PATCH 6134/7006] MIPS: Lasat: Move from deprecated __initcall to arch_initcall. Signed-off-by: Ralf Baechle --- arch/mips/lasat/sysctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/lasat/sysctl.c b/arch/mips/lasat/sysctl.c index a57959e648a6b..c710d969938d7 100644 --- a/arch/mips/lasat/sysctl.c +++ b/arch/mips/lasat/sysctl.c @@ -270,4 +270,4 @@ static int __init lasat_register_sysctl(void) return 0; } -__initcall(lasat_register_sysctl); +arch_initcall(lasat_register_sysctl); -- GitLab From 1249ed3540809d30d1fe42c94276a9db2845d173 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 20 Jul 2015 09:10:20 +0200 Subject: [PATCH 6135/7006] MIPS: math-emu: Move from deprecated __initcall to arch_initcall. Signed-off-by: Ralf Baechle --- arch/mips/math-emu/me-debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/math-emu/me-debugfs.c b/arch/mips/math-emu/me-debugfs.c index f308e0f05fc58..506a67a98cdf5 100644 --- a/arch/mips/math-emu/me-debugfs.c +++ b/arch/mips/math-emu/me-debugfs.c @@ -65,4 +65,4 @@ do { \ return 0; } -__initcall(debugfs_fpuemu); +arch_initcall(debugfs_fpuemu); -- GitLab From f17c4ca33601f03f4b5f598f085ee356358932b7 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Thu, 23 Jul 2015 12:02:09 +0200 Subject: [PATCH 6136/7006] MIPS: Kconfig: Separate 32BIT and 64BIT config block by blank line. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 52b7918da21a3..efa3706beb549 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1968,6 +1968,7 @@ config 32BIT select TRAD_SIGNALS help Select this option if you want to build a 32-bit kernel. + config 64BIT bool "64-bit kernel" depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL -- GitLab From 3dcd7779ac4dada4a2c97e19a9ac3593891d89a0 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:52 +0530 Subject: [PATCH 6137/7006] MIPS: Alchemy: Migrate to new 'set-state' interface Migrate alchemy driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: Manuel Lauss Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10599/ Signed-off-by: Ralf Baechle --- arch/mips/alchemy/common/time.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/mips/alchemy/common/time.c b/arch/mips/alchemy/common/time.c index 50e17e13c18bb..f99d3ec17a459 100644 --- a/arch/mips/alchemy/common/time.c +++ b/arch/mips/alchemy/common/time.c @@ -69,11 +69,6 @@ static int au1x_rtcmatch2_set_next_event(unsigned long delta, return 0; } -static void au1x_rtcmatch2_set_mode(enum clock_event_mode mode, - struct clock_event_device *cd) -{ -} - static irqreturn_t au1x_rtcmatch2_irq(int irq, void *dev_id) { struct clock_event_device *cd = dev_id; @@ -86,7 +81,6 @@ static struct clock_event_device au1x_rtcmatch2_clockdev = { .features = CLOCK_EVT_FEAT_ONESHOT, .rating = 1500, .set_next_event = au1x_rtcmatch2_set_next_event, - .set_mode = au1x_rtcmatch2_set_mode, .cpumask = cpu_all_mask, }; -- GitLab From 20a7835f8f3666eaaec599f8f9f1628c4e7e88dd Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:53 +0530 Subject: [PATCH 6138/7006] MIPS: Jazz: Migrate to new 'set-state' interface Migrate jazz driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10600/ Signed-off-by: Ralf Baechle --- arch/mips/jazz/irq.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/mips/jazz/irq.c b/arch/mips/jazz/irq.c index e1ea4f625f7a4..5d6828b2a750c 100644 --- a/arch/mips/jazz/irq.c +++ b/arch/mips/jazz/irq.c @@ -110,18 +110,11 @@ asmlinkage void plat_irq_dispatch(void) } } -static void r4030_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - struct clock_event_device r4030_clockevent = { .name = "r4030", .features = CLOCK_EVT_FEAT_PERIODIC, .rating = 300, .irq = JAZZ_TIMER_IRQ, - .set_mode = r4030_set_mode, }; static irqreturn_t r4030_timer_interrupt(int irq, void *dev_id) -- GitLab From c87cbe06916868e1b14a0681e874b96cfab61083 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:54 +0530 Subject: [PATCH 6139/7006] MIPS: jz4740: Migrate to new 'set-state' interface Migrate jz4740 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Paul Burton Cc: Deng-Cheng Zhu Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10601/ Signed-off-by: Ralf Baechle --- arch/mips/jz4740/time.c | 46 ++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/arch/mips/jz4740/time.c b/arch/mips/jz4740/time.c index 7ab47fee1be8f..1f7ca2c9f2625 100644 --- a/arch/mips/jz4740/time.c +++ b/arch/mips/jz4740/time.c @@ -58,7 +58,7 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) jz4740_timer_ack_full(TIMER_CLOCKEVENT); - if (cd->mode != CLOCK_EVT_MODE_PERIODIC) + if (!clockevent_state_periodic(cd)) jz4740_timer_disable(TIMER_CLOCKEVENT); cd->event_handler(cd); @@ -66,24 +66,29 @@ static irqreturn_t jz4740_clockevent_irq(int irq, void *devid) return IRQ_HANDLED; } -static void jz4740_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *cd) +static int jz4740_clockevent_set_periodic(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); - jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); - case CLOCK_EVT_MODE_RESUME: - jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); - jz4740_timer_enable(TIMER_CLOCKEVENT); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_SHUTDOWN: - jz4740_timer_disable(TIMER_CLOCKEVENT); - break; - default: - break; - } + jz4740_timer_set_count(TIMER_CLOCKEVENT, 0); + jz4740_timer_set_period(TIMER_CLOCKEVENT, jz4740_jiffies_per_tick); + jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); + jz4740_timer_enable(TIMER_CLOCKEVENT); + + return 0; +} + +static int jz4740_clockevent_resume(struct clock_event_device *evt) +{ + jz4740_timer_irq_full_enable(TIMER_CLOCKEVENT); + jz4740_timer_enable(TIMER_CLOCKEVENT); + + return 0; +} + +static int jz4740_clockevent_shutdown(struct clock_event_device *evt) +{ + jz4740_timer_disable(TIMER_CLOCKEVENT); + + return 0; } static int jz4740_clockevent_set_next(unsigned long evt, @@ -100,7 +105,10 @@ static struct clock_event_device jz4740_clockevent = { .name = "jz4740-timer", .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, .set_next_event = jz4740_clockevent_set_next, - .set_mode = jz4740_clockevent_set_mode, + .set_state_shutdown = jz4740_clockevent_shutdown, + .set_state_periodic = jz4740_clockevent_set_periodic, + .set_state_oneshot = jz4740_clockevent_shutdown, + .tick_resume = jz4740_clockevent_resume, .rating = 200, #ifdef CONFIG_MACH_JZ4740 .irq = JZ4740_IRQ_TCU0, -- GitLab From 1edf907a09e1cad9032411d84679b637ab696593 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:55 +0530 Subject: [PATCH 6140/7006] MIPS: cevt-bcm1480: Migrate to new 'set-state' interface Migrate cevt-bcm1480 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Read operation on R_SCD_TIMER_CFG and R_SCD_TIMER_INIT registers isn't performed now for many modes as there returned values aren't used. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10602/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-bcm1480.c | 44 ++++++++++++++++----------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/arch/mips/kernel/cevt-bcm1480.c b/arch/mips/kernel/cevt-bcm1480.c index 7976457184b18..940ac00e9129a 100644 --- a/arch/mips/kernel/cevt-bcm1480.c +++ b/arch/mips/kernel/cevt-bcm1480.c @@ -40,8 +40,8 @@ * The general purpose timer ticks at 1MHz independent if * the rest of the system */ -static void sibyte_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) + +static int sibyte_set_periodic(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); void __iomem *cfg, *init; @@ -49,24 +49,22 @@ static void sibyte_set_mode(enum clock_event_mode mode, cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writeq(0, cfg); - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - cfg); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* Stop the timer until we actually program a shot */ - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writeq(0, cfg); - break; - - case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ - case CLOCK_EVT_MODE_RESUME: - ; - } + __raw_writeq(0, cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); + return 0; +} + +static int sibyte_shutdown(struct clock_event_device *evt) +{ + unsigned int cpu = smp_processor_id(); + void __iomem *cfg; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); + + /* Stop the timer until we actually program a shot */ + __raw_writeq(0, cfg); + return 0; } static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) @@ -91,7 +89,7 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) void __iomem *cfg; unsigned long tmode; - if (cd->mode == CLOCK_EVT_MODE_PERIODIC) + if (clockevent_state_periodic(cd)) tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; else tmode = 0; @@ -130,7 +128,9 @@ void sb1480_clockevent_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = sibyte_next_event; - cd->set_mode = sibyte_set_mode; + cd->set_state_shutdown = sibyte_shutdown; + cd->set_state_periodic = sibyte_set_periodic; + cd->set_state_oneshot = sibyte_shutdown; clockevents_register_device(cd); bcm1480_mask_irq(cpu, irq); -- GitLab From 9f95618f9fe5fc902a3d8fecd10c98e482fab6c5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:56 +0530 Subject: [PATCH 6141/7006] MIPS: cevt-ds1287: Migrate to new 'set-state' interface Migrate cevt-ds1287 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10603/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-ds1287.c | 37 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/cevt-ds1287.c b/arch/mips/kernel/cevt-ds1287.c index ff1f01b72270f..77a5ddf53f57e 100644 --- a/arch/mips/kernel/cevt-ds1287.c +++ b/arch/mips/kernel/cevt-ds1287.c @@ -59,27 +59,32 @@ static int ds1287_set_next_event(unsigned long delta, return -EINVAL; } -static void ds1287_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int ds1287_shutdown(struct clock_event_device *evt) { u8 val; spin_lock(&rtc_lock); val = CMOS_READ(RTC_REG_B); + val &= ~RTC_PIE; + CMOS_WRITE(val, RTC_REG_B); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - val |= RTC_PIE; - break; - default: - val &= ~RTC_PIE; - break; - } + spin_unlock(&rtc_lock); + return 0; +} +static int ds1287_set_periodic(struct clock_event_device *evt) +{ + u8 val; + + spin_lock(&rtc_lock); + + val = CMOS_READ(RTC_REG_B); + val |= RTC_PIE; CMOS_WRITE(val, RTC_REG_B); spin_unlock(&rtc_lock); + return 0; } static void ds1287_event_handler(struct clock_event_device *dev) @@ -87,11 +92,13 @@ static void ds1287_event_handler(struct clock_event_device *dev) } static struct clock_event_device ds1287_clockevent = { - .name = "ds1287", - .features = CLOCK_EVT_FEAT_PERIODIC, - .set_next_event = ds1287_set_next_event, - .set_mode = ds1287_set_mode, - .event_handler = ds1287_event_handler, + .name = "ds1287", + .features = CLOCK_EVT_FEAT_PERIODIC, + .set_next_event = ds1287_set_next_event, + .set_state_shutdown = ds1287_shutdown, + .set_state_periodic = ds1287_set_periodic, + .tick_resume = ds1287_shutdown, + .event_handler = ds1287_event_handler, }; static irqreturn_t ds1287_interrupt(int irq, void *dev_id) -- GitLab From c88f2fb4d81df3dbafd79d51b2cacefb356d466c Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:57 +0530 Subject: [PATCH 6142/7006] MIPS: cevt-gt641xx: Migrate to new 'set-state' interface Migrate cevt-gt641xx driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10604/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-gt641xx.c | 57 ++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/arch/mips/kernel/cevt-gt641xx.c b/arch/mips/kernel/cevt-gt641xx.c index f069460751ab9..66040051151d3 100644 --- a/arch/mips/kernel/cevt-gt641xx.c +++ b/arch/mips/kernel/cevt-gt641xx.c @@ -64,8 +64,7 @@ static int gt641xx_timer0_set_next_event(unsigned long delta, return 0; } -static void gt641xx_timer0_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int gt641xx_timer0_shutdown(struct clock_event_device *evt) { u32 ctrl; @@ -73,21 +72,39 @@ static void gt641xx_timer0_set_mode(enum clock_event_mode mode, ctrl = GT_READ(GT_TC_CONTROL_OFS); ctrl &= ~(GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK); + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); + + raw_spin_unlock(>641xx_timer_lock); + return 0; +} + +static int gt641xx_timer0_set_oneshot(struct clock_event_device *evt) +{ + u32 ctrl; + + raw_spin_lock(>641xx_timer_lock); + + ctrl = GT_READ(GT_TC_CONTROL_OFS); + ctrl &= ~GT_TC_CONTROL_SELTC0_MSK; + ctrl |= GT_TC_CONTROL_ENTC0_MSK; + GT_WRITE(GT_TC_CONTROL_OFS, ctrl); + + raw_spin_unlock(>641xx_timer_lock); + return 0; +} - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; - break; - case CLOCK_EVT_MODE_ONESHOT: - ctrl |= GT_TC_CONTROL_ENTC0_MSK; - break; - default: - break; - } +static int gt641xx_timer0_set_periodic(struct clock_event_device *evt) +{ + u32 ctrl; + + raw_spin_lock(>641xx_timer_lock); + ctrl = GT_READ(GT_TC_CONTROL_OFS); + ctrl |= GT_TC_CONTROL_ENTC0_MSK | GT_TC_CONTROL_SELTC0_MSK; GT_WRITE(GT_TC_CONTROL_OFS, ctrl); raw_spin_unlock(>641xx_timer_lock); + return 0; } static void gt641xx_timer0_event_handler(struct clock_event_device *dev) @@ -95,12 +112,16 @@ static void gt641xx_timer0_event_handler(struct clock_event_device *dev) } static struct clock_event_device gt641xx_timer0_clockevent = { - .name = "gt641xx-timer0", - .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, - .irq = GT641XX_TIMER0_IRQ, - .set_next_event = gt641xx_timer0_set_next_event, - .set_mode = gt641xx_timer0_set_mode, - .event_handler = gt641xx_timer0_event_handler, + .name = "gt641xx-timer0", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .irq = GT641XX_TIMER0_IRQ, + .set_next_event = gt641xx_timer0_set_next_event, + .set_state_shutdown = gt641xx_timer0_shutdown, + .set_state_periodic = gt641xx_timer0_set_periodic, + .set_state_oneshot = gt641xx_timer0_set_oneshot, + .tick_resume = gt641xx_timer0_shutdown, + .event_handler = gt641xx_timer0_event_handler, }; static irqreturn_t gt641xx_timer0_interrupt(int irq, void *dev_id) -- GitLab From 877c61dc63c2eaa98515abfd89596f293b543342 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:58 +0530 Subject: [PATCH 6143/7006] MIPS: cevt-r4k: Migrate to new 'set-state' interface Migrate cevt-4k driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: James Hogan Cc: Andrew Bresticker Cc: Qais Yousef Cc: Jason Cooper Cc: Leonid Yegoshin Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10605/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/cevt-r4k.h | 1 - arch/mips/kernel/cevt-r4k.c | 7 ------- 2 files changed, 8 deletions(-) diff --git a/arch/mips/include/asm/cevt-r4k.h b/arch/mips/include/asm/cevt-r4k.h index f0edf6fcd002b..2e13a038d2600 100644 --- a/arch/mips/include/asm/cevt-r4k.h +++ b/arch/mips/include/asm/cevt-r4k.h @@ -21,7 +21,6 @@ DECLARE_PER_CPU(struct clock_event_device, mips_clockevent_device); void mips_event_handler(struct clock_event_device *dev); int c0_compare_int_usable(void); -void mips_set_clock_mode(enum clock_event_mode, struct clock_event_device *); irqreturn_t c0_compare_interrupt(int, void *); extern struct irqaction c0_compare_irqaction; diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c index cc7cc46b58f7a..8dfe6a6e14809 100644 --- a/arch/mips/kernel/cevt-r4k.c +++ b/arch/mips/kernel/cevt-r4k.c @@ -28,12 +28,6 @@ static int mips_next_event(unsigned long delta, return res; } -void mips_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - DEFINE_PER_CPU(struct clock_event_device, mips_clockevent_device); int cp0_timer_irq_installed; @@ -215,7 +209,6 @@ int r4k_clockevent_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = mips_next_event; - cd->set_mode = mips_set_clock_mode; cd->event_handler = mips_event_handler; clockevents_register_device(cd); -- GitLab From 57e148cabbb2f1e6770d6a506088486142b26b97 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:41:59 +0530 Subject: [PATCH 6144/7006] MIPS: cevt-sb1250: Migrate to new 'set-state' interface Migrate cevt-rsb1250 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10606/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-sb1250.c | 45 +++++++++++++++++----------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/arch/mips/kernel/cevt-sb1250.c b/arch/mips/kernel/cevt-sb1250.c index 5ea6d6b1de150..3d860efd63b97 100644 --- a/arch/mips/kernel/cevt-sb1250.c +++ b/arch/mips/kernel/cevt-sb1250.c @@ -38,8 +38,20 @@ * The general purpose timer ticks at 1MHz independent if * the rest of the system */ -static void sibyte_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) + +static int sibyte_shutdown(struct clock_event_device *evt) +{ + void __iomem *cfg; + + cfg = IOADDR(A_SCD_TIMER_REGISTER(smp_processor_id(), R_SCD_TIMER_CFG)); + + /* Stop the timer until we actually program a shot */ + __raw_writeq(0, cfg); + + return 0; +} + +static int sibyte_set_periodic(struct clock_event_device *evt) { unsigned int cpu = smp_processor_id(); void __iomem *cfg, *init; @@ -47,24 +59,11 @@ static void sibyte_set_mode(enum clock_event_mode mode, cfg = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_CFG)); init = IOADDR(A_SCD_TIMER_REGISTER(cpu, R_SCD_TIMER_INIT)); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writeq(0, cfg); - __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); - __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, - cfg); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* Stop the timer until we actually program a shot */ - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writeq(0, cfg); - break; - - case CLOCK_EVT_MODE_UNUSED: /* shuddup gcc */ - case CLOCK_EVT_MODE_RESUME: - ; - } + __raw_writeq(0, cfg); + __raw_writeq((V_SCD_TIMER_FREQ / HZ) - 1, init); + __raw_writeq(M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS, cfg); + + return 0; } static int sibyte_next_event(unsigned long delta, struct clock_event_device *cd) @@ -89,7 +88,7 @@ static irqreturn_t sibyte_counter_handler(int irq, void *dev_id) void __iomem *cfg; unsigned long tmode; - if (cd->mode == CLOCK_EVT_MODE_PERIODIC) + if (clockevent_state_periodic(cd)) tmode = M_SCD_TIMER_ENABLE | M_SCD_TIMER_MODE_CONTINUOUS; else tmode = 0; @@ -129,7 +128,9 @@ void sb1250_clockevent_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = sibyte_next_event; - cd->set_mode = sibyte_set_mode; + cd->set_state_shutdown = sibyte_shutdown; + cd->set_state_periodic = sibyte_set_periodic; + cd->set_state_oneshot = sibyte_shutdown; clockevents_register_device(cd); sb1250_mask_irq(cpu, irq); -- GitLab From d199da550da30e0946a7554f8a93ef75f66f8005 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:00 +0530 Subject: [PATCH 6145/7006] MIPS: cevt-txx9: Migrate to new 'set-state' interface Migrate cevt-txx9 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Deng-Cheng Zhu Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Cc: Viresh Kumar Patchwork: https://patchwork.linux-mips.org/patch/10607/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cevt-txx9.c | 81 +++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 30 deletions(-) diff --git a/arch/mips/kernel/cevt-txx9.c b/arch/mips/kernel/cevt-txx9.c index 723932441ecc7..537eefdf838fe 100644 --- a/arch/mips/kernel/cevt-txx9.c +++ b/arch/mips/kernel/cevt-txx9.c @@ -85,36 +85,54 @@ static void txx9tmr_stop_and_clear(struct txx9_tmr_reg __iomem *tmrptr) __raw_writel(0, &tmrptr->tisr); } -static void txx9tmr_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int txx9tmr_set_state_periodic(struct clock_event_device *evt) { struct txx9_clock_event_device *txx9_cd = container_of(evt, struct txx9_clock_event_device, cd); struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; txx9tmr_stop_and_clear(tmrptr); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, - &tmrptr->itmr); - /* start timer */ - __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> - evt->shift, - &tmrptr->cpra); - __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - __raw_writel(0, &tmrptr->itmr); - break; - case CLOCK_EVT_MODE_ONESHOT: - __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); - break; - case CLOCK_EVT_MODE_RESUME: - __raw_writel(TIMER_CCD, &tmrptr->ccdr); - __raw_writel(0, &tmrptr->itmr); - break; - } + + __raw_writel(TXx9_TMITMR_TIIE | TXx9_TMITMR_TZCE, &tmrptr->itmr); + /* start timer */ + __raw_writel(((u64)(NSEC_PER_SEC / HZ) * evt->mult) >> evt->shift, + &tmrptr->cpra); + __raw_writel(TCR_BASE | TXx9_TMTCR_TCE, &tmrptr->tcr); + return 0; +} + +static int txx9tmr_set_state_oneshot(struct clock_event_device *evt) +{ + struct txx9_clock_event_device *txx9_cd = + container_of(evt, struct txx9_clock_event_device, cd); + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; + + txx9tmr_stop_and_clear(tmrptr); + __raw_writel(TXx9_TMITMR_TIIE, &tmrptr->itmr); + return 0; +} + +static int txx9tmr_set_state_shutdown(struct clock_event_device *evt) +{ + struct txx9_clock_event_device *txx9_cd = + container_of(evt, struct txx9_clock_event_device, cd); + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; + + txx9tmr_stop_and_clear(tmrptr); + __raw_writel(0, &tmrptr->itmr); + return 0; +} + +static int txx9tmr_tick_resume(struct clock_event_device *evt) +{ + struct txx9_clock_event_device *txx9_cd = + container_of(evt, struct txx9_clock_event_device, cd); + struct txx9_tmr_reg __iomem *tmrptr = txx9_cd->tmrptr; + + txx9tmr_stop_and_clear(tmrptr); + __raw_writel(TIMER_CCD, &tmrptr->ccdr); + __raw_writel(0, &tmrptr->itmr); + return 0; } static int txx9tmr_set_next_event(unsigned long delta, @@ -133,12 +151,15 @@ static int txx9tmr_set_next_event(unsigned long delta, static struct txx9_clock_event_device txx9_clock_event_device = { .cd = { - .name = "TXx9", - .features = CLOCK_EVT_FEAT_PERIODIC | - CLOCK_EVT_FEAT_ONESHOT, - .rating = 200, - .set_mode = txx9tmr_set_mode, - .set_next_event = txx9tmr_set_next_event, + .name = "TXx9", + .features = CLOCK_EVT_FEAT_PERIODIC | + CLOCK_EVT_FEAT_ONESHOT, + .rating = 200, + .set_state_shutdown = txx9tmr_set_state_shutdown, + .set_state_periodic = txx9tmr_set_state_periodic, + .set_state_oneshot = txx9tmr_set_state_oneshot, + .tick_resume = txx9tmr_tick_resume, + .set_next_event = txx9tmr_set_next_event, }, }; -- GitLab From e3280b2a54b38406563d6422685a20172382d365 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:01 +0530 Subject: [PATCH 6146/7006] MIPS: loongson64/timer: Migrate to new 'set-state' interface Migrate loongson driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. [ralf@linux-mips.org: Folded in Viresh's followon fix.] Signed-off-by: Viresh Kumar Cc: Huacai Chen Cc: Michael Opdenacker Cc: Hongliang Tao Cc: Valentin Rothberg Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Cc: Viresh Kumar Patchwork: https://patchwork.linux-mips.org/patch/10608/ Patchwork: https://patchwork.linux-mips.org/patch/10883/ Signed-off-by: Ralf Baechle --- .../loongson64/common/cs5536/cs5536_mfgpt.c | 46 ++++--- arch/mips/loongson64/loongson-3/hpet.c | 117 +++++++++++------- 2 files changed, 92 insertions(+), 71 deletions(-) diff --git a/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c b/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c index 875037063a80e..da77d412514c0 100644 --- a/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c +++ b/arch/mips/loongson64/common/cs5536/cs5536_mfgpt.c @@ -51,40 +51,36 @@ void enable_mfgpt0_counter(void) } EXPORT_SYMBOL(enable_mfgpt0_counter); -static void init_mfgpt_timer(enum clock_event_mode mode, - struct clock_event_device *evt) +static int mfgpt_timer_set_periodic(struct clock_event_device *evt) { raw_spin_lock(&mfgpt_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ - outw(0, MFGPT0_CNT); /* set counter to 0 */ - enable_mfgpt0_counter(); - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - if (evt->mode == CLOCK_EVT_MODE_PERIODIC || - evt->mode == CLOCK_EVT_MODE_ONESHOT) - disable_mfgpt0_counter(); - break; - - case CLOCK_EVT_MODE_ONESHOT: - /* The oneshot mode have very high deviation, Not use it! */ - break; - - case CLOCK_EVT_MODE_RESUME: - /* Nothing to do here */ - break; - } + outw(COMPARE, MFGPT0_CMP2); /* set comparator2 */ + outw(0, MFGPT0_CNT); /* set counter to 0 */ + enable_mfgpt0_counter(); + raw_spin_unlock(&mfgpt_lock); + return 0; +} + +static int mfgpt_timer_shutdown(struct clock_event_device *evt) +{ + if (clockevent_state_periodic(evt) || clockevent_state_oneshot(evt)) { + raw_spin_lock(&mfgpt_lock); + disable_mfgpt0_counter(); + raw_spin_unlock(&mfgpt_lock); + } + + return 0; } static struct clock_event_device mfgpt_clockevent = { .name = "mfgpt", .features = CLOCK_EVT_FEAT_PERIODIC, - .set_mode = init_mfgpt_timer, + + /* The oneshot mode have very high deviation, don't use it! */ + .set_state_shutdown = mfgpt_timer_shutdown, + .set_state_periodic = mfgpt_timer_set_periodic, .irq = CS5536_MFGPT_INTR, }; diff --git a/arch/mips/loongson64/loongson-3/hpet.c b/arch/mips/loongson64/loongson-3/hpet.c index 5c21cd3bd339a..bf9f1a77f0e59 100644 --- a/arch/mips/loongson64/loongson-3/hpet.c +++ b/arch/mips/loongson64/loongson-3/hpet.c @@ -78,55 +78,77 @@ static void hpet_enable_legacy_int(void) /* Do nothing on Loongson-3 */ } -static void hpet_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int hpet_set_state_periodic(struct clock_event_device *evt) { - int cfg = 0; + int cfg; spin_lock(&hpet_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - pr_info("set clock event to periodic mode!\n"); - /* stop counter */ - hpet_stop_counter(); - - /* enables the timer0 to generate a periodic interrupt */ - cfg = hpet_read(HPET_T0_CFG); - cfg &= ~HPET_TN_LEVEL; - cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | - HPET_TN_SETVAL | HPET_TN_32BIT; - hpet_write(HPET_T0_CFG, cfg); - - /* set the comparator */ - hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); - udelay(1); - hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); - - /* start counter */ - hpet_start_counter(); - break; - case CLOCK_EVT_MODE_SHUTDOWN: - case CLOCK_EVT_MODE_UNUSED: - cfg = hpet_read(HPET_T0_CFG); - cfg &= ~HPET_TN_ENABLE; - hpet_write(HPET_T0_CFG, cfg); - break; - case CLOCK_EVT_MODE_ONESHOT: - pr_info("set clock event to one shot mode!\n"); - cfg = hpet_read(HPET_T0_CFG); - /* set timer0 type - * 1 : periodic interrupt - * 0 : non-periodic(oneshot) interrupt - */ - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_write(HPET_T0_CFG, cfg); - break; - case CLOCK_EVT_MODE_RESUME: - hpet_enable_legacy_int(); - break; - } + + pr_info("set clock event to periodic mode!\n"); + /* stop counter */ + hpet_stop_counter(); + + /* enables the timer0 to generate a periodic interrupt */ + cfg = hpet_read(HPET_T0_CFG); + cfg &= ~HPET_TN_LEVEL; + cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL | + HPET_TN_32BIT; + hpet_write(HPET_T0_CFG, cfg); + + /* set the comparator */ + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); + udelay(1); + hpet_write(HPET_T0_CMP, HPET_COMPARE_VAL); + + /* start counter */ + hpet_start_counter(); + + spin_unlock(&hpet_lock); + return 0; +} + +static int hpet_set_state_shutdown(struct clock_event_device *evt) +{ + int cfg; + + spin_lock(&hpet_lock); + + cfg = hpet_read(HPET_T0_CFG); + cfg &= ~HPET_TN_ENABLE; + hpet_write(HPET_T0_CFG, cfg); + spin_unlock(&hpet_lock); + return 0; +} + +static int hpet_set_state_oneshot(struct clock_event_device *evt) +{ + int cfg; + + spin_lock(&hpet_lock); + + pr_info("set clock event to one shot mode!\n"); + cfg = hpet_read(HPET_T0_CFG); + /* + * set timer0 type + * 1 : periodic interrupt + * 0 : non-periodic(oneshot) interrupt + */ + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_write(HPET_T0_CFG, cfg); + + spin_unlock(&hpet_lock); + return 0; +} + +static int hpet_tick_resume(struct clock_event_device *evt) +{ + spin_lock(&hpet_lock); + hpet_enable_legacy_int(); + spin_unlock(&hpet_lock); + + return 0; } static int hpet_next_event(unsigned long delta, @@ -206,7 +228,10 @@ void __init setup_hpet_timer(void) cd->name = "hpet"; cd->rating = 320; cd->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; - cd->set_mode = hpet_set_mode; + cd->set_state_shutdown = hpet_set_state_shutdown; + cd->set_state_periodic = hpet_set_state_periodic; + cd->set_state_oneshot = hpet_set_state_oneshot; + cd->tick_resume = hpet_tick_resume; cd->set_next_event = hpet_next_event; cd->irq = HPET_T0_IRQ; cd->cpumask = cpumask_of(cpu); -- GitLab From 1fed884d5f3d615d56d3b3c07d5ef95f7b49b5f5 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:02 +0530 Subject: [PATCH 6147/7006] MIPS: loongsoon32: Migrate to new 'set-state' interface Migrate loongsoon32 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Kelvin Cheung Cc: Huacai Chen Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10609/ Signed-off-by: Ralf Baechle --- arch/mips/loongson32/common/time.c | 57 ++++++++++++++++++------------ 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/arch/mips/loongson32/common/time.c b/arch/mips/loongson32/common/time.c index df0f850d6a5f4..0996b025eeefb 100644 --- a/arch/mips/loongson32/common/time.c +++ b/arch/mips/loongson32/common/time.c @@ -126,26 +126,34 @@ static irqreturn_t ls1x_clockevent_isr(int irq, void *devid) return IRQ_HANDLED; } -static void ls1x_clockevent_set_mode(enum clock_event_mode mode, - struct clock_event_device *cd) +static int ls1x_clockevent_set_state_periodic(struct clock_event_device *cd) { raw_spin_lock(&ls1x_timer_lock); - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); - ls1x_pwmtimer_restart(); - case CLOCK_EVT_MODE_RESUME: - __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_SHUTDOWN: - __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, - timer_base + PWM_CTRL); - break; - default: - break; - } + ls1x_pwmtimer_set_period(ls1x_jiffies_per_tick); + ls1x_pwmtimer_restart(); + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); raw_spin_unlock(&ls1x_timer_lock); + + return 0; +} + +static int ls1x_clockevent_tick_resume(struct clock_event_device *cd) +{ + raw_spin_lock(&ls1x_timer_lock); + __raw_writel(INT_EN | CNT_EN, timer_base + PWM_CTRL); + raw_spin_unlock(&ls1x_timer_lock); + + return 0; +} + +static int ls1x_clockevent_set_state_shutdown(struct clock_event_device *cd) +{ + raw_spin_lock(&ls1x_timer_lock); + __raw_writel(__raw_readl(timer_base + PWM_CTRL) & ~CNT_EN, + timer_base + PWM_CTRL); + raw_spin_unlock(&ls1x_timer_lock); + + return 0; } static int ls1x_clockevent_set_next(unsigned long evt, @@ -160,12 +168,15 @@ static int ls1x_clockevent_set_next(unsigned long evt, } static struct clock_event_device ls1x_clockevent = { - .name = "ls1x-pwmtimer", - .features = CLOCK_EVT_FEAT_PERIODIC, - .rating = 300, - .irq = LS1X_TIMER_IRQ, - .set_next_event = ls1x_clockevent_set_next, - .set_mode = ls1x_clockevent_set_mode, + .name = "ls1x-pwmtimer", + .features = CLOCK_EVT_FEAT_PERIODIC, + .rating = 300, + .irq = LS1X_TIMER_IRQ, + .set_next_event = ls1x_clockevent_set_next, + .set_state_shutdown = ls1x_clockevent_set_state_shutdown, + .set_state_periodic = ls1x_clockevent_set_state_periodic, + .set_state_oneshot = ls1x_clockevent_set_state_shutdown, + .tick_resume = ls1x_clockevent_tick_resume, }; static struct irqaction ls1x_pwmtimer_irqaction = { -- GitLab From 59113d93c2b483485cf62f0b057f896e420048c2 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:03 +0530 Subject: [PATCH 6148/7006] MIPS: rt3352: Migrate to new 'set-state' interface Migrate ralink driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10610/ Signed-off-by: Ralf Baechle --- arch/mips/ralink/cevt-rt3352.c | 59 +++++++++++++++++----------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/arch/mips/ralink/cevt-rt3352.c b/arch/mips/ralink/cevt-rt3352.c index 24bf057a36136..a8e70a9f274bd 100644 --- a/arch/mips/ralink/cevt-rt3352.c +++ b/arch/mips/ralink/cevt-rt3352.c @@ -36,8 +36,8 @@ struct systick_device { int freq_scale; }; -static void systick_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt); +static int systick_set_oneshot(struct clock_event_device *evt); +static int systick_shutdown(struct clock_event_device *evt); static int systick_next_event(unsigned long delta, struct clock_event_device *evt) @@ -73,11 +73,12 @@ static struct systick_device systick = { * cevt-r4k uses 300, make sure systick * gets used if available */ - .rating = 310, - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_next_event = systick_next_event, - .set_mode = systick_set_clock_mode, - .event_handler = systick_event_handler, + .rating = 310, + .features = CLOCK_EVT_FEAT_ONESHOT, + .set_next_event = systick_next_event, + .set_state_shutdown = systick_shutdown, + .set_state_oneshot = systick_set_oneshot, + .event_handler = systick_event_handler, }, }; @@ -87,33 +88,33 @@ static struct irqaction systick_irqaction = { .dev_id = &systick.dev, }; -static void systick_set_clock_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int systick_shutdown(struct clock_event_device *evt) { struct systick_device *sdev; sdev = container_of(evt, struct systick_device, dev); - switch (mode) { - case CLOCK_EVT_MODE_ONESHOT: - if (!sdev->irq_requested) - setup_irq(systick.dev.irq, &systick_irqaction); - sdev->irq_requested = 1; - iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, - systick.membase + SYSTICK_CONFIG); - break; - - case CLOCK_EVT_MODE_SHUTDOWN: - if (sdev->irq_requested) - free_irq(systick.dev.irq, &systick_irqaction); - sdev->irq_requested = 0; - iowrite32(0, systick.membase + SYSTICK_CONFIG); - break; - - default: - pr_err("%s: Unhandeled mips clock_mode\n", systick.dev.name); - break; - } + if (sdev->irq_requested) + free_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 0; + iowrite32(0, systick.membase + SYSTICK_CONFIG); + + return 0; +} + +static int systick_set_oneshot(struct clock_event_device *evt) +{ + struct systick_device *sdev; + + sdev = container_of(evt, struct systick_device, dev); + + if (!sdev->irq_requested) + setup_irq(systick.dev.irq, &systick_irqaction); + sdev->irq_requested = 1; + iowrite32(CFG_EXT_STK_EN | CFG_CNT_EN, + systick.membase + SYSTICK_CONFIG); + + return 0; } static void __init ralink_systick_init(struct device_node *np) -- GitLab From 0c16240ab07ff8a0e611f676f86a92a4b513d15d Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:04 +0530 Subject: [PATCH 6149/7006] MIPS: IP27: Migrate to new 'set-state' interface Migrate sgidriver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Signed-off-by: Viresh Kumar Cc: Deng-Cheng Zhu Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10611/ Signed-off-by: Ralf Baechle --- arch/mips/sgi-ip27/ip27-timer.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index a6d10f607f348..42d6cb9f956e3 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -64,12 +64,6 @@ static int rt_next_event(unsigned long delta, struct clock_event_device *evt) return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; } -static void rt_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - /* Nothing to do ... */ -} - unsigned int rt_timer_irq; static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent); @@ -124,7 +118,6 @@ void hub_rt_clock_event_init(void) cd->irq = irq; cd->cpumask = cpumask_of(cpu); cd->set_next_event = rt_next_event; - cd->set_mode = rt_set_mode; clockevents_register_device(cd); } -- GitLab From 397d08b006fc8bbb087615214400b86b64f8fe50 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 6 Jul 2015 16:42:05 +0530 Subject: [PATCH 6150/7006] MIPS: sni: Migrate to new 'set-state' interface Migrate sni driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Signed-off-by: Viresh Kumar Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linaro-kernel@lists.linaro.org Cc: Thomas Gleixner Patchwork: https://patchwork.linux-mips.org/patch/10612/ Signed-off-by: Ralf Baechle --- arch/mips/sni/time.c | 49 +++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/arch/mips/sni/time.c b/arch/mips/sni/time.c index cf8ec568b9dfa..fb4b3520cdc61 100644 --- a/arch/mips/sni/time.c +++ b/arch/mips/sni/time.c @@ -14,44 +14,33 @@ #define SNI_COUNTER2_DIV 64 #define SNI_COUNTER0_DIV ((SNI_CLOCK_TICK_RATE / SNI_COUNTER2_DIV) / HZ) -static void a20r_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int a20r_set_periodic(struct clock_event_device *evt) { - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; - wmb(); - - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; - wmb(); - *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; - wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0x34; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 0) = SNI_COUNTER0_DIV >> 8; + wmb(); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - break; - case CLOCK_EVT_MODE_RESUME: - break; - } + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 12) = 0xb4; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV; + wmb(); + *(volatile u8 *)(A20R_PT_CLOCK_BASE + 8) = SNI_COUNTER2_DIV >> 8; + wmb(); + return 0; } static struct clock_event_device a20r_clockevent_device = { - .name = "a20r-timer", - .features = CLOCK_EVT_FEAT_PERIODIC, + .name = "a20r-timer", + .features = CLOCK_EVT_FEAT_PERIODIC, /* .mult, .shift, .max_delta_ns and .min_delta_ns left uninitialized */ - .rating = 300, - .irq = SNI_A20R_IRQ_TIMER, - .set_mode = a20r_set_mode, + .rating = 300, + .irq = SNI_A20R_IRQ_TIMER, + .set_state_periodic = a20r_set_periodic, }; static irqreturn_t a20r_interrupt(int irq, void *dev_id) -- GitLab From 689ee8565c5b5af9369f4c34af04196f2d3fea83 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:13 -0700 Subject: [PATCH 6151/7006] MIPS: Simplify EVA FP context handling code The protected_{save,restore}_fp_context functions had effectively different implementations for EVA. Simplify & unify the code somewhat such that EVA configurations simply guarantee the FPU-not-owned path through the standard code path. Signed-off-by: Paul Burton Cc: Markos Chandras Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10787/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 44 +++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 6a28c792d862c..796c7d856d7d9 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -101,7 +101,14 @@ static int copy_fp_from_sigcontext(struct sigcontext __user *sc) static int protected_save_fp_context(struct sigcontext __user *sc) { int err; -#ifndef CONFIG_EVA + + /* + * EVA does not have userland equivalents of ldc1 or sdc1, so + * save to the kernel FP context & copy that to userland below. + */ + if (config_enabled(CONFIG_EVA)) + lose_fpu(1); + while (1) { lock_fpu_owner(); if (is_fpu_owner()) { @@ -120,21 +127,22 @@ static int protected_save_fp_context(struct sigcontext __user *sc) if (err) break; /* really bad sigcontext */ } -#else - /* - * EVA does not have FPU EVA instructions so saving fpu context directly - * does not work. - */ - lose_fpu(1); - err = save_fp_context(sc); /* this might fail */ -#endif + return err; } static int protected_restore_fp_context(struct sigcontext __user *sc) { int err, tmp __maybe_unused; -#ifndef CONFIG_EVA + + /* + * EVA does not have userland equivalents of ldc1 or sdc1, so we + * disable the FPU here such that the code below simply copies to + * the kernel FP context. + */ + if (config_enabled(CONFIG_EVA)) + lose_fpu(0); + while (1) { lock_fpu_owner(); if (is_fpu_owner()) { @@ -153,14 +161,7 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) if (err) break; /* really bad sigcontext */ } -#else - /* - * EVA does not have FPU EVA instructions so restoring fpu context - * directly does not work. - */ - lose_fpu(0); - err = restore_fp_context(sc); /* this might fail */ -#endif + return err; } @@ -629,7 +630,6 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, } #ifdef CONFIG_SMP -#ifndef CONFIG_EVA static int smp_save_fp_context(struct sigcontext __user *sc) { return raw_cpu_has_fpu @@ -643,12 +643,10 @@ static int smp_restore_fp_context(struct sigcontext __user *sc) ? _restore_fp_context(sc) : copy_fp_from_sigcontext(sc); } -#endif /* CONFIG_EVA */ #endif static int signal_setup(void) { -#ifndef CONFIG_EVA #ifdef CONFIG_SMP /* For now just do the cpu_has_fpu check when the functions are invoked */ save_fp_context = smp_save_fp_context; @@ -662,10 +660,6 @@ static int signal_setup(void) restore_fp_context = copy_fp_from_sigcontext; } #endif /* CONFIG_SMP */ -#else - save_fp_context = copy_fp_to_sigcontext; - restore_fp_context = copy_fp_from_sigcontext; -#endif return 0; } -- GitLab From 778561006e5891801ac794ddf7b21148a5555e35 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:14 -0700 Subject: [PATCH 6152/7006] MIPS: Add offsets to sigcontext FP fields to struct mips_abi Add fields to struct mips_abi, which holds information regarding the kernel-userland ABI regarding signals, to specify the offsets to the FP related fields within the appropriate variant of struct sigcontext. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10788/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/abi.h | 4 ++++ arch/mips/kernel/signal.c | 6 +++++- arch/mips/kernel/signal32.c | 6 +++++- arch/mips/kernel/signal_n32.c | 6 +++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/asm/abi.h b/arch/mips/include/asm/abi.h index 7186bb51b89b2..37f84078e78ab 100644 --- a/arch/mips/include/asm/abi.h +++ b/arch/mips/include/asm/abi.h @@ -20,6 +20,10 @@ struct mips_abi { struct pt_regs *regs, sigset_t *set); const unsigned long rt_signal_return_offset; const unsigned long restart; + + unsigned off_sc_fpregs; + unsigned off_sc_fpc_csr; + unsigned off_sc_used_math; }; #endif /* _ASM_ABI_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 796c7d856d7d9..ddf83189fff8e 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -521,7 +521,11 @@ struct mips_abi mips_abi = { .setup_rt_frame = setup_rt_frame, .rt_signal_return_offset = offsetof(struct mips_vdso, rt_signal_trampoline), - .restart = __NR_restart_syscall + .restart = __NR_restart_syscall, + + .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), + .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), + .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), }; static void handle_signal(struct ksignal *ksig, struct pt_regs *regs) diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 5d7f2634996fd..da70ea5cf6ec0 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -585,7 +585,11 @@ struct mips_abi mips_abi_32 = { .setup_rt_frame = setup_rt_frame_32, .rt_signal_return_offset = offsetof(struct mips_vdso, o32_rt_signal_trampoline), - .restart = __NR_O32_restart_syscall + .restart = __NR_O32_restart_syscall, + + .off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs), + .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), + .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), }; static int signal32_init(void) diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index f1d4751eead09..0d017fdcaf07a 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -153,5 +153,9 @@ struct mips_abi mips_abi_n32 = { .setup_rt_frame = setup_rt_frame_n32, .rt_signal_return_offset = offsetof(struct mips_vdso, n32_rt_signal_trampoline), - .restart = __NR_N32_restart_syscall + .restart = __NR_N32_restart_syscall, + + .off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs), + .off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr), + .off_sc_used_math = offsetof(struct sigcontext, sc_used_math), }; -- GitLab From 2db9ca0a355100c40d1bef2aae3b9d9cf199cd04 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:15 -0700 Subject: [PATCH 6153/7006] MIPS: Use struct mips_abi offsets to save FP context When saving FP state to struct sigcontext, make use of the offsets provided by struct mips_abi to obtain appropriate addresses for the sc_fpregs & sc_fpc_csr fields of the sigcontext. This is done only for the native struct sigcontext in this patch (ie. for O32 in CONFIG_32BIT kernels or for N64 in CONFIG_64BIT kernels) but is done in preparation for sharing this code with compat ABIs in further patches. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10789/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/r4k_fpu.S | 151 +++++++++++++++++-------------- arch/mips/kernel/signal-common.h | 6 ++ arch/mips/kernel/signal.c | 85 +++++++++++------ 3 files changed, 145 insertions(+), 97 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index ca887da1a48a2..b8044d612ad39 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -36,6 +36,14 @@ .set noreorder +/** + * _save_fp_context() - save FP context from the FPU + * @a0 - pointer to fpregs field of sigcontext + * @a1 - pointer to fpc_csr field of sigcontext + * + * Save FP context, including the 32 FP data registers and the FP + * control & status register, from the FPU to signal context. + */ LEAF(_save_fp_context) .set push SET_HARDFLOAT @@ -55,45 +63,45 @@ LEAF(_save_fp_context) nop #endif /* Store the 16 odd double precision registers */ - EX sdc1 $f1, SC_FPREGS+8(a0) - EX sdc1 $f3, SC_FPREGS+24(a0) - EX sdc1 $f5, SC_FPREGS+40(a0) - EX sdc1 $f7, SC_FPREGS+56(a0) - EX sdc1 $f9, SC_FPREGS+72(a0) - EX sdc1 $f11, SC_FPREGS+88(a0) - EX sdc1 $f13, SC_FPREGS+104(a0) - EX sdc1 $f15, SC_FPREGS+120(a0) - EX sdc1 $f17, SC_FPREGS+136(a0) - EX sdc1 $f19, SC_FPREGS+152(a0) - EX sdc1 $f21, SC_FPREGS+168(a0) - EX sdc1 $f23, SC_FPREGS+184(a0) - EX sdc1 $f25, SC_FPREGS+200(a0) - EX sdc1 $f27, SC_FPREGS+216(a0) - EX sdc1 $f29, SC_FPREGS+232(a0) - EX sdc1 $f31, SC_FPREGS+248(a0) + EX sdc1 $f1, 8(a0) + EX sdc1 $f3, 24(a0) + EX sdc1 $f5, 40(a0) + EX sdc1 $f7, 56(a0) + EX sdc1 $f9, 72(a0) + EX sdc1 $f11, 88(a0) + EX sdc1 $f13, 104(a0) + EX sdc1 $f15, 120(a0) + EX sdc1 $f17, 136(a0) + EX sdc1 $f19, 152(a0) + EX sdc1 $f21, 168(a0) + EX sdc1 $f23, 184(a0) + EX sdc1 $f25, 200(a0) + EX sdc1 $f27, 216(a0) + EX sdc1 $f29, 232(a0) + EX sdc1 $f31, 248(a0) 1: .set pop #endif .set push SET_HARDFLOAT /* Store the 16 even double precision registers */ - EX sdc1 $f0, SC_FPREGS+0(a0) - EX sdc1 $f2, SC_FPREGS+16(a0) - EX sdc1 $f4, SC_FPREGS+32(a0) - EX sdc1 $f6, SC_FPREGS+48(a0) - EX sdc1 $f8, SC_FPREGS+64(a0) - EX sdc1 $f10, SC_FPREGS+80(a0) - EX sdc1 $f12, SC_FPREGS+96(a0) - EX sdc1 $f14, SC_FPREGS+112(a0) - EX sdc1 $f16, SC_FPREGS+128(a0) - EX sdc1 $f18, SC_FPREGS+144(a0) - EX sdc1 $f20, SC_FPREGS+160(a0) - EX sdc1 $f22, SC_FPREGS+176(a0) - EX sdc1 $f24, SC_FPREGS+192(a0) - EX sdc1 $f26, SC_FPREGS+208(a0) - EX sdc1 $f28, SC_FPREGS+224(a0) - EX sdc1 $f30, SC_FPREGS+240(a0) - EX sw t1, SC_FPC_CSR(a0) + EX sdc1 $f0, 0(a0) + EX sdc1 $f2, 16(a0) + EX sdc1 $f4, 32(a0) + EX sdc1 $f6, 48(a0) + EX sdc1 $f8, 64(a0) + EX sdc1 $f10, 80(a0) + EX sdc1 $f12, 96(a0) + EX sdc1 $f14, 112(a0) + EX sdc1 $f16, 128(a0) + EX sdc1 $f18, 144(a0) + EX sdc1 $f20, 160(a0) + EX sdc1 $f22, 176(a0) + EX sdc1 $f24, 192(a0) + EX sdc1 $f26, 208(a0) + EX sdc1 $f28, 224(a0) + EX sdc1 $f30, 240(a0) + EX sw t1, 0(a1) jr ra li v0, 0 # success .set pop @@ -159,13 +167,16 @@ LEAF(_save_fp_context32) END(_save_fp_context32) #endif -/* - * Restore FPU state: - * - fp gp registers - * - cp1 status/control register +/** + * _restore_fp_context() - restore FP context to the FPU + * @a0 - pointer to fpregs field of sigcontext + * @a1 - pointer to fpc_csr field of sigcontext + * + * Restore FP context, including the 32 FP data registers and the FP + * control & status register, from signal context to the FPU. */ LEAF(_restore_fp_context) - EX lw t1, SC_FPC_CSR(a0) + EX lw t1, 0(a1) #if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2) || \ defined(CONFIG_CPU_MIPS32_R6) @@ -179,42 +190,42 @@ LEAF(_restore_fp_context) bgez t0, 1f # skip loading odd if FR=0 nop #endif - EX ldc1 $f1, SC_FPREGS+8(a0) - EX ldc1 $f3, SC_FPREGS+24(a0) - EX ldc1 $f5, SC_FPREGS+40(a0) - EX ldc1 $f7, SC_FPREGS+56(a0) - EX ldc1 $f9, SC_FPREGS+72(a0) - EX ldc1 $f11, SC_FPREGS+88(a0) - EX ldc1 $f13, SC_FPREGS+104(a0) - EX ldc1 $f15, SC_FPREGS+120(a0) - EX ldc1 $f17, SC_FPREGS+136(a0) - EX ldc1 $f19, SC_FPREGS+152(a0) - EX ldc1 $f21, SC_FPREGS+168(a0) - EX ldc1 $f23, SC_FPREGS+184(a0) - EX ldc1 $f25, SC_FPREGS+200(a0) - EX ldc1 $f27, SC_FPREGS+216(a0) - EX ldc1 $f29, SC_FPREGS+232(a0) - EX ldc1 $f31, SC_FPREGS+248(a0) + EX ldc1 $f1, 8(a0) + EX ldc1 $f3, 24(a0) + EX ldc1 $f5, 40(a0) + EX ldc1 $f7, 56(a0) + EX ldc1 $f9, 72(a0) + EX ldc1 $f11, 88(a0) + EX ldc1 $f13, 104(a0) + EX ldc1 $f15, 120(a0) + EX ldc1 $f17, 136(a0) + EX ldc1 $f19, 152(a0) + EX ldc1 $f21, 168(a0) + EX ldc1 $f23, 184(a0) + EX ldc1 $f25, 200(a0) + EX ldc1 $f27, 216(a0) + EX ldc1 $f29, 232(a0) + EX ldc1 $f31, 248(a0) 1: .set pop #endif .set push SET_HARDFLOAT - EX ldc1 $f0, SC_FPREGS+0(a0) - EX ldc1 $f2, SC_FPREGS+16(a0) - EX ldc1 $f4, SC_FPREGS+32(a0) - EX ldc1 $f6, SC_FPREGS+48(a0) - EX ldc1 $f8, SC_FPREGS+64(a0) - EX ldc1 $f10, SC_FPREGS+80(a0) - EX ldc1 $f12, SC_FPREGS+96(a0) - EX ldc1 $f14, SC_FPREGS+112(a0) - EX ldc1 $f16, SC_FPREGS+128(a0) - EX ldc1 $f18, SC_FPREGS+144(a0) - EX ldc1 $f20, SC_FPREGS+160(a0) - EX ldc1 $f22, SC_FPREGS+176(a0) - EX ldc1 $f24, SC_FPREGS+192(a0) - EX ldc1 $f26, SC_FPREGS+208(a0) - EX ldc1 $f28, SC_FPREGS+224(a0) - EX ldc1 $f30, SC_FPREGS+240(a0) + EX ldc1 $f0, 0(a0) + EX ldc1 $f2, 16(a0) + EX ldc1 $f4, 32(a0) + EX ldc1 $f6, 48(a0) + EX ldc1 $f8, 64(a0) + EX ldc1 $f10, 80(a0) + EX ldc1 $f12, 96(a0) + EX ldc1 $f14, 112(a0) + EX ldc1 $f16, 128(a0) + EX ldc1 $f18, 144(a0) + EX ldc1 $f20, 160(a0) + EX ldc1 $f22, 176(a0) + EX ldc1 $f24, 192(a0) + EX ldc1 $f26, 208(a0) + EX ldc1 $f28, 224(a0) + EX ldc1 $f30, 240(a0) ctc1 t1, fcr31 .set pop jr ra diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 0b85f827cd183..96b0fd82f8b51 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -31,4 +31,10 @@ extern int fpcsr_pending(unsigned int __user *fpcsr); #define lock_fpu_owner() ({ preempt_disable(); pagefault_disable(); }) #define unlock_fpu_owner() ({ pagefault_enable(); preempt_enable(); }) +/* Assembly functions to move context to/from the FPU */ +extern asmlinkage int +_save_fp_context(void __user *fpregs, void __user *csr); +extern asmlinkage int +_restore_fp_context(void __user *fpregs, void __user *csr); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index ddf83189fff8e..10f7dbc989c47 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -41,11 +41,8 @@ #include "signal-common.h" -static int (*save_fp_context)(struct sigcontext __user *sc); -static int (*restore_fp_context)(struct sigcontext __user *sc); - -extern asmlinkage int _save_fp_context(struct sigcontext __user *sc); -extern asmlinkage int _restore_fp_context(struct sigcontext __user *sc); +static int (*save_fp_context)(void __user *sc); +static int (*restore_fp_context)(void __user *sc); struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ @@ -65,41 +62,71 @@ struct rt_sigframe { * Thread saved context copy to/from a signal context presumed to be on the * user stack, and therefore accessed with appropriate macros from uaccess.h. */ -static int copy_fp_to_sigcontext(struct sigcontext __user *sc) +static int copy_fp_to_sigcontext(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; for (i = 0; i < NUM_FPU_REGS; i++) { err |= __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), - &sc->sc_fpregs[i]); + &fpregs[i]); } - err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); + err |= __put_user(current->thread.fpu.fcr31, csr); return err; } -static int copy_fp_from_sigcontext(struct sigcontext __user *sc) +static int copy_fp_from_sigcontext(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; u64 fpr_val; for (i = 0; i < NUM_FPU_REGS; i++) { - err |= __get_user(fpr_val, &sc->sc_fpregs[i]); + err |= __get_user(fpr_val, &fpregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); } - err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); + err |= __get_user(current->thread.fpu.fcr31, csr); return err; } +/* + * Wrappers for the assembly _{save,restore}_fp_context functions. + */ +static int save_hw_fp_context(void __user *sc) +{ + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + + return _save_fp_context(fpregs, csr); +} + +static int restore_hw_fp_context(void __user *sc) +{ + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + + return _restore_fp_context(fpregs, csr); +} + /* * Helper routines */ -static int protected_save_fp_context(struct sigcontext __user *sc) +static int protected_save_fp_context(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int err; /* @@ -121,9 +148,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc) if (likely(!err)) break; /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); + err = __put_user(0, &fpregs[0]) | + __put_user(0, &fpregs[31]) | + __put_user(0, csr); if (err) break; /* really bad sigcontext */ } @@ -131,8 +158,11 @@ static int protected_save_fp_context(struct sigcontext __user *sc) return err; } -static int protected_restore_fp_context(struct sigcontext __user *sc) +static int protected_restore_fp_context(void __user *sc) { + struct mips_abi *abi = current->thread.abi; + uint64_t __user *fpregs = sc + abi->off_sc_fpregs; + uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int err, tmp __maybe_unused; /* @@ -155,9 +185,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc) if (likely(!err)) break; /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); + err = __get_user(tmp, &fpregs[0]) | + __get_user(tmp, &fpregs[31]) | + __get_user(tmp, csr); if (err) break; /* really bad sigcontext */ } @@ -225,11 +255,12 @@ int fpcsr_pending(unsigned int __user *fpcsr) } static int -check_and_restore_fp_context(struct sigcontext __user *sc) +check_and_restore_fp_context(void __user *sc) { + struct mips_abi *abi = current->thread.abi; int err, sig; - err = sig = fpcsr_pending(&sc->sc_fpc_csr); + err = sig = fpcsr_pending(sc + abi->off_sc_fpc_csr); if (err > 0) err = 0; err |= protected_restore_fp_context(sc); @@ -634,17 +665,17 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, } #ifdef CONFIG_SMP -static int smp_save_fp_context(struct sigcontext __user *sc) +static int smp_save_fp_context(void __user *sc) { return raw_cpu_has_fpu - ? _save_fp_context(sc) + ? save_hw_fp_context(sc) : copy_fp_to_sigcontext(sc); } -static int smp_restore_fp_context(struct sigcontext __user *sc) +static int smp_restore_fp_context(void __user *sc) { return raw_cpu_has_fpu - ? _restore_fp_context(sc) + ? restore_hw_fp_context(sc) : copy_fp_from_sigcontext(sc); } #endif @@ -657,8 +688,8 @@ static int signal_setup(void) restore_fp_context = smp_restore_fp_context; #else if (cpu_has_fpu) { - save_fp_context = _save_fp_context; - restore_fp_context = _restore_fp_context; + save_fp_context = save_hw_fp_context; + restore_fp_context = restore_hw_fp_context; } else { save_fp_context = copy_fp_to_sigcontext; restore_fp_context = copy_fp_from_sigcontext; -- GitLab From 64243c2a945640392b59fe1dc66c30ee1ca04170 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:16 -0700 Subject: [PATCH 6154/7006] MIPS: Move FP usage checks into protected_{save, restore}_fp_context In preparation for sharing protected_{save,restore}_fp_context with compat ABIs, move the FP usage checks into said functions. This will both enable that code to be shared, and allow for extensions of it in further patches to also be shared. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10790/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 73 ++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 10f7dbc989c47..9c42c500134e5 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -127,8 +127,15 @@ static int protected_save_fp_context(void __user *sc) struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; + uint32_t __user *used_math = sc + abi->off_sc_used_math; + unsigned int used; int err; + used = !!used_math(); + err = __put_user(used, used_math); + if (err || !used) + return err; + /* * EVA does not have userland equivalents of ldc1 or sdc1, so * save to the kernel FP context & copy that to userland below. @@ -163,7 +170,25 @@ static int protected_restore_fp_context(void __user *sc) struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; - int err, tmp __maybe_unused; + uint32_t __user *used_math = sc + abi->off_sc_used_math; + unsigned int used; + int err, sig, tmp __maybe_unused; + + err = __get_user(used, used_math); + conditional_used_math(used); + + /* + * The signal handler may have used FPU; give it up if the program + * doesn't want it following sigreturn. + */ + if (err || !used) { + lose_fpu(0); + return err; + } + + err = sig = fpcsr_pending(csr); + if (err < 0) + return err; /* * EVA does not have userland equivalents of ldc1 or sdc1, so we @@ -192,14 +217,13 @@ static int protected_restore_fp_context(void __user *sc) break; /* really bad sigcontext */ } - return err; + return err ?: sig; } int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { int err = 0; int i; - unsigned int used_math; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -222,16 +246,13 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) err |= __put_user(rddsp(DSP_MASK), &sc->sc_dsp); } - used_math = !!used_math(); - err |= __put_user(used_math, &sc->sc_used_math); - if (used_math) { - /* - * Save FPU state to signal context. Signal handler - * will "inherit" current FPU state. - */ - err |= protected_save_fp_context(sc); - } + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + err |= protected_save_fp_context(sc); + return err; } @@ -254,22 +275,8 @@ int fpcsr_pending(unsigned int __user *fpcsr) return err ?: sig; } -static int -check_and_restore_fp_context(void __user *sc) -{ - struct mips_abi *abi = current->thread.abi; - int err, sig; - - err = sig = fpcsr_pending(sc + abi->off_sc_fpc_csr); - if (err > 0) - err = 0; - err |= protected_restore_fp_context(sc); - return err ?: sig; -} - int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) { - unsigned int used_math; unsigned long treg; int err = 0; int i; @@ -297,19 +304,7 @@ int restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) for (i = 1; i < 32; i++) err |= __get_user(regs->regs[i], &sc->sc_regs[i]); - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - if (used_math) { - /* restore fpu context if we have used it before */ - if (!err) - err = check_and_restore_fp_context(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(0); - } - - return err; + return err ?: protected_restore_fp_context(sc); } void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, -- GitLab From 6f0aba63bfb3eb33b68cf746c44b6ab302599180 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:17 -0700 Subject: [PATCH 6155/7006] MIPS: Skip odd double FP registers when copying FP32 sigcontext When a task uses 32 bit floating point, the odd indexed 32b register values are stored in bits 63:32 of the preceding even indexed 64b FP register field in saved context. Thus there is no point in preserving the odd indexed 64b register fields since they hold no valid context. This patch will cause them to be skipped, as is already done in arch/mips/kernel/signal32.c. [ralf@linux-mips.org: Fixed reject.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Cc: Andrew Morton Patchwork: https://patchwork.linux-mips.org/patch/10791/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9c42c500134e5..cc3a01f5c5afb 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -69,8 +69,9 @@ static int copy_fp_to_sigcontext(void __user *sc) uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - for (i = 0; i < NUM_FPU_REGS; i++) { + for (i = 0; i < NUM_FPU_REGS; i += inc) { err |= __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), &fpregs[i]); @@ -87,9 +88,10 @@ static int copy_fp_from_sigcontext(void __user *sc) uint32_t __user *csr = sc + abi->off_sc_fpc_csr; int i; int err = 0; + int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; u64 fpr_val; - for (i = 0; i < NUM_FPU_REGS; i++) { + for (i = 0; i < NUM_FPU_REGS; i += inc) { err |= __get_user(fpr_val, &fpregs[i]); set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); } -- GitLab From d02a40aff6e043bae1cd6e6416e9048990928b1d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:18 -0700 Subject: [PATCH 6156/7006] MIPS: Use common FP sigcontext code for O32 compat Make use of the common FP sigcontext code for O32 binaries running on MIPS64 kernels now that it is taking appropriate offsets into struct sigcontext(32) from struct mips_abi. [ralf@linux-mips.org: Fixed reject.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andrew Morton Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10792/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/signal.h | 3 + arch/mips/kernel/asm-offsets.c | 11 --- arch/mips/kernel/r4k_fpu.S | 114 ------------------------- arch/mips/kernel/signal.c | 4 +- arch/mips/kernel/signal32.c | 150 ++------------------------------- 5 files changed, 11 insertions(+), 271 deletions(-) diff --git a/arch/mips/include/asm/signal.h b/arch/mips/include/asm/signal.h index 8efe5a9e2c3e6..003e273eff4ce 100644 --- a/arch/mips/include/asm/signal.h +++ b/arch/mips/include/asm/signal.h @@ -23,4 +23,7 @@ #define __ARCH_HAS_IRIX_SIGACTION +extern int protected_save_fp_context(void __user *sc); +extern int protected_restore_fp_context(void __user *sc); + #endif /* _ASM_SIGNAL_H */ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 072fab13645d5..3706091b6351d 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -245,17 +245,6 @@ void output_sc_defines(void) } #endif -#ifdef CONFIG_MIPS32_COMPAT -void output_sc32_defines(void) -{ - COMMENT("Linux 32-bit sigcontext offsets."); - OFFSET(SC32_FPREGS, sigcontext32, sc_fpregs); - OFFSET(SC32_FPC_CSR, sigcontext32, sc_fpc_csr); - OFFSET(SC32_FPC_EIR, sigcontext32, sc_fpc_eir); - BLANK(); -} -#endif - void output_signal_defined(void) { COMMENT("Linux signal numbers."); diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index b8044d612ad39..0ed139889245a 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -107,66 +107,6 @@ LEAF(_save_fp_context) .set pop END(_save_fp_context) -#ifdef CONFIG_MIPS32_COMPAT - /* Save 32-bit process floating point context */ -LEAF(_save_fp_context32) - .set push - .set MIPS_ISA_ARCH_LEVEL_RAW - SET_HARDFLOAT - cfc1 t1, fcr31 - -#ifndef CONFIG_CPU_MIPS64_R6 - mfc0 t0, CP0_STATUS - sll t0, t0, 5 - bgez t0, 1f # skip storing odd if FR=0 - nop -#endif - - /* Store the 16 odd double precision registers */ - EX sdc1 $f1, SC32_FPREGS+8(a0) - EX sdc1 $f3, SC32_FPREGS+24(a0) - EX sdc1 $f5, SC32_FPREGS+40(a0) - EX sdc1 $f7, SC32_FPREGS+56(a0) - EX sdc1 $f9, SC32_FPREGS+72(a0) - EX sdc1 $f11, SC32_FPREGS+88(a0) - EX sdc1 $f13, SC32_FPREGS+104(a0) - EX sdc1 $f15, SC32_FPREGS+120(a0) - EX sdc1 $f17, SC32_FPREGS+136(a0) - EX sdc1 $f19, SC32_FPREGS+152(a0) - EX sdc1 $f21, SC32_FPREGS+168(a0) - EX sdc1 $f23, SC32_FPREGS+184(a0) - EX sdc1 $f25, SC32_FPREGS+200(a0) - EX sdc1 $f27, SC32_FPREGS+216(a0) - EX sdc1 $f29, SC32_FPREGS+232(a0) - EX sdc1 $f31, SC32_FPREGS+248(a0) - - /* Store the 16 even double precision registers */ -1: EX sdc1 $f0, SC32_FPREGS+0(a0) - EX sdc1 $f2, SC32_FPREGS+16(a0) - EX sdc1 $f4, SC32_FPREGS+32(a0) - EX sdc1 $f6, SC32_FPREGS+48(a0) - EX sdc1 $f8, SC32_FPREGS+64(a0) - EX sdc1 $f10, SC32_FPREGS+80(a0) - EX sdc1 $f12, SC32_FPREGS+96(a0) - EX sdc1 $f14, SC32_FPREGS+112(a0) - EX sdc1 $f16, SC32_FPREGS+128(a0) - EX sdc1 $f18, SC32_FPREGS+144(a0) - EX sdc1 $f20, SC32_FPREGS+160(a0) - EX sdc1 $f22, SC32_FPREGS+176(a0) - EX sdc1 $f24, SC32_FPREGS+192(a0) - EX sdc1 $f26, SC32_FPREGS+208(a0) - EX sdc1 $f28, SC32_FPREGS+224(a0) - EX sdc1 $f30, SC32_FPREGS+240(a0) - EX sw t1, SC32_FPC_CSR(a0) - cfc1 t0, $0 # implementation/version - EX sw t0, SC32_FPC_EIR(a0) - .set pop - - jr ra - li v0, 0 # success - END(_save_fp_context32) -#endif - /** * _restore_fp_context() - restore FP context to the FPU * @a0 - pointer to fpregs field of sigcontext @@ -232,60 +172,6 @@ LEAF(_restore_fp_context) li v0, 0 # success END(_restore_fp_context) -#ifdef CONFIG_MIPS32_COMPAT -LEAF(_restore_fp_context32) - /* Restore an o32 sigcontext. */ - .set push - SET_HARDFLOAT - EX lw t1, SC32_FPC_CSR(a0) - -#ifndef CONFIG_CPU_MIPS64_R6 - mfc0 t0, CP0_STATUS - sll t0, t0, 5 - bgez t0, 1f # skip loading odd if FR=0 - nop -#endif - - EX ldc1 $f1, SC32_FPREGS+8(a0) - EX ldc1 $f3, SC32_FPREGS+24(a0) - EX ldc1 $f5, SC32_FPREGS+40(a0) - EX ldc1 $f7, SC32_FPREGS+56(a0) - EX ldc1 $f9, SC32_FPREGS+72(a0) - EX ldc1 $f11, SC32_FPREGS+88(a0) - EX ldc1 $f13, SC32_FPREGS+104(a0) - EX ldc1 $f15, SC32_FPREGS+120(a0) - EX ldc1 $f17, SC32_FPREGS+136(a0) - EX ldc1 $f19, SC32_FPREGS+152(a0) - EX ldc1 $f21, SC32_FPREGS+168(a0) - EX ldc1 $f23, SC32_FPREGS+184(a0) - EX ldc1 $f25, SC32_FPREGS+200(a0) - EX ldc1 $f27, SC32_FPREGS+216(a0) - EX ldc1 $f29, SC32_FPREGS+232(a0) - EX ldc1 $f31, SC32_FPREGS+248(a0) - -1: EX ldc1 $f0, SC32_FPREGS+0(a0) - EX ldc1 $f2, SC32_FPREGS+16(a0) - EX ldc1 $f4, SC32_FPREGS+32(a0) - EX ldc1 $f6, SC32_FPREGS+48(a0) - EX ldc1 $f8, SC32_FPREGS+64(a0) - EX ldc1 $f10, SC32_FPREGS+80(a0) - EX ldc1 $f12, SC32_FPREGS+96(a0) - EX ldc1 $f14, SC32_FPREGS+112(a0) - EX ldc1 $f16, SC32_FPREGS+128(a0) - EX ldc1 $f18, SC32_FPREGS+144(a0) - EX ldc1 $f20, SC32_FPREGS+160(a0) - EX ldc1 $f22, SC32_FPREGS+176(a0) - EX ldc1 $f24, SC32_FPREGS+192(a0) - EX ldc1 $f26, SC32_FPREGS+208(a0) - EX ldc1 $f28, SC32_FPREGS+224(a0) - EX ldc1 $f30, SC32_FPREGS+240(a0) - ctc1 t1, fcr31 - jr ra - li v0, 0 # success - .set pop - END(_restore_fp_context32) -#endif - #ifdef CONFIG_CPU_HAS_MSA .macro op_one_wr op, idx, base diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index cc3a01f5c5afb..08f521567d64c 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -124,7 +124,7 @@ static int restore_hw_fp_context(void __user *sc) /* * Helper routines */ -static int protected_save_fp_context(void __user *sc) +int protected_save_fp_context(void __user *sc) { struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; @@ -167,7 +167,7 @@ static int protected_save_fp_context(void __user *sc) return err; } -static int protected_restore_fp_context(void __user *sc) +int protected_restore_fp_context(void __user *sc) { struct mips_abi *abi = current->thread.abi; uint64_t __user *fpregs = sc + abi->off_sc_fpregs; diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index da70ea5cf6ec0..7c45cb3e075a1 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -36,12 +36,6 @@ #include "signal-common.h" -static int (*save_fp_context32)(struct sigcontext32 __user *sc); -static int (*restore_fp_context32)(struct sigcontext32 __user *sc); - -extern asmlinkage int _save_fp_context32(struct sigcontext32 __user *sc); -extern asmlinkage int _restore_fp_context32(struct sigcontext32 __user *sc); - /* * Including would give use the 64-bit syscall numbers ... */ @@ -74,99 +68,11 @@ struct rt_sigframe32 { struct ucontext32 rs_uc; }; -/* - * Thread saved context copy to/from a signal context presumed to be on the - * user stack, and therefore accessed with appropriate macros from uaccess.h. - */ -static int copy_fp_to_sigcontext32(struct sigcontext32 __user *sc) -{ - int i; - int err = 0; - int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - - for (i = 0; i < NUM_FPU_REGS; i += inc) { - err |= - __put_user(get_fpr64(¤t->thread.fpu.fpr[i], 0), - &sc->sc_fpregs[i]); - } - err |= __put_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); - - return err; -} - -static int copy_fp_from_sigcontext32(struct sigcontext32 __user *sc) -{ - int i; - int err = 0; - int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1; - u64 fpr_val; - - for (i = 0; i < NUM_FPU_REGS; i += inc) { - err |= __get_user(fpr_val, &sc->sc_fpregs[i]); - set_fpr64(¤t->thread.fpu.fpr[i], 0, fpr_val); - } - err |= __get_user(current->thread.fpu.fcr31, &sc->sc_fpc_csr); - - return err; -} - -/* - * sigcontext handlers - */ -static int protected_save_fp_context32(struct sigcontext32 __user *sc) -{ - int err; - while (1) { - lock_fpu_owner(); - if (is_fpu_owner()) { - err = save_fp_context32(sc); - unlock_fpu_owner(); - } else { - unlock_fpu_owner(); - err = copy_fp_to_sigcontext32(sc); - } - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __put_user(0, &sc->sc_fpregs[0]) | - __put_user(0, &sc->sc_fpregs[31]) | - __put_user(0, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - -static int protected_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, tmp __maybe_unused; - while (1) { - lock_fpu_owner(); - if (is_fpu_owner()) { - err = restore_fp_context32(sc); - unlock_fpu_owner(); - } else { - unlock_fpu_owner(); - err = copy_fp_from_sigcontext32(sc); - } - if (likely(!err)) - break; - /* touch the sigcontext and try again */ - err = __get_user(tmp, &sc->sc_fpregs[0]) | - __get_user(tmp, &sc->sc_fpregs[31]) | - __get_user(tmp, &sc->sc_fpc_csr); - if (err) - break; /* really bad sigcontext */ - } - return err; -} - static int setup_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { int err = 0; int i; - u32 used_math; err |= __put_user(regs->cp0_epc, &sc->sc_pc); @@ -186,35 +92,18 @@ static int setup_sigcontext32(struct pt_regs *regs, err |= __put_user(mflo3(), &sc->sc_lo3); } - used_math = !!used_math(); - err |= __put_user(used_math, &sc->sc_used_math); + /* + * Save FPU state to signal context. Signal handler + * will "inherit" current FPU state. + */ + err |= protected_save_fp_context(sc); - if (used_math) { - /* - * Save FPU state to signal context. Signal handler - * will "inherit" current FPU state. - */ - err |= protected_save_fp_context32(sc); - } return err; } -static int -check_and_restore_fp_context32(struct sigcontext32 __user *sc) -{ - int err, sig; - - err = sig = fpcsr_pending(&sc->sc_fpc_csr); - if (err > 0) - err = 0; - err |= protected_restore_fp_context32(sc); - return err ?: sig; -} - static int restore_sigcontext32(struct pt_regs *regs, struct sigcontext32 __user *sc) { - u32 used_math; int err = 0; s32 treg; int i; @@ -238,19 +127,7 @@ static int restore_sigcontext32(struct pt_regs *regs, for (i = 1; i < 32; i++) err |= __get_user(regs->regs[i], &sc->sc_regs[i]); - err |= __get_user(used_math, &sc->sc_used_math); - conditional_used_math(used_math); - - if (used_math) { - /* restore fpu context if we have used it before */ - if (!err) - err = check_and_restore_fp_context32(sc); - } else { - /* signal handler may have used FPU. Give it up. */ - lose_fpu(0); - } - - return err; + return err ?: protected_restore_fp_context(sc); } /* @@ -591,18 +468,3 @@ struct mips_abi mips_abi_32 = { .off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr), .off_sc_used_math = offsetof(struct sigcontext32, sc_used_math), }; - -static int signal32_init(void) -{ - if (cpu_has_fpu) { - save_fp_context32 = _save_fp_context32; - restore_fp_context32 = _restore_fp_context32; - } else { - save_fp_context32 = copy_fp_to_sigcontext32; - restore_fp_context32 = copy_fp_from_sigcontext32; - } - - return 0; -} - -arch_initcall(signal32_init); -- GitLab From 6a24432cf9cfb6e071fb3566144a3a5ace9d3c0d Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:19 -0700 Subject: [PATCH 6157/7006] MIPS: Remove unused {get,put}_sigset functions These functions are never called & thus dead code. Remove them. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Andrew Morton Patchwork: https://patchwork.linux-mips.org/patch/10793/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/signal32.c | 51 ------------------------------------- 1 file changed, 51 deletions(-) diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 7c45cb3e075a1..f7e89524e3166 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -130,57 +130,6 @@ static int restore_sigcontext32(struct pt_regs *regs, return err ?: protected_restore_fp_context(sc); } -/* - * - */ -extern void __put_sigset_unknown_nsig(void); -extern void __get_sigset_unknown_nsig(void); - -static inline int put_sigset(const sigset_t *kbuf, compat_sigset_t __user *ubuf) -{ - int err = 0; - - if (!access_ok(VERIFY_WRITE, ubuf, sizeof(*ubuf))) - return -EFAULT; - - switch (_NSIG_WORDS) { - default: - __put_sigset_unknown_nsig(); - case 2: - err |= __put_user(kbuf->sig[1] >> 32, &ubuf->sig[3]); - err |= __put_user(kbuf->sig[1] & 0xffffffff, &ubuf->sig[2]); - case 1: - err |= __put_user(kbuf->sig[0] >> 32, &ubuf->sig[1]); - err |= __put_user(kbuf->sig[0] & 0xffffffff, &ubuf->sig[0]); - } - - return err; -} - -static inline int get_sigset(sigset_t *kbuf, const compat_sigset_t __user *ubuf) -{ - int err = 0; - unsigned long sig[4]; - - if (!access_ok(VERIFY_READ, ubuf, sizeof(*ubuf))) - return -EFAULT; - - switch (_NSIG_WORDS) { - default: - __get_sigset_unknown_nsig(); - case 2: - err |= __get_user(sig[3], &ubuf->sig[3]); - err |= __get_user(sig[2], &ubuf->sig[2]); - kbuf->sig[1] = sig[2] | (sig[3] << 32); - case 1: - err |= __get_user(sig[1], &ubuf->sig[1]); - err |= __get_user(sig[0], &ubuf->sig[0]); - kbuf->sig[0] = sig[0] | (sig[1] << 32); - } - - return err; -} - /* * Atomically swap in the new signal mask, and wait for a signal. */ -- GitLab From 0d071fa3772b85fe5d81032fbc011c623570d2fc Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:20 -0700 Subject: [PATCH 6158/7006] MIPS: Indicate FP mode in sigcontext sc_used_math The sc_used_math field of struct sigcontext & its variants has traditionally been used as a boolean value indicating only whether or not floating point context is saved within the sigcontext. With various supported FP modes & the ability to switch between them this information will no longer be enough to decode the meaning of the data stored in the sc_fpregs fields of struct sigcontext. To make that possible 3 bits are defined within sc_used_math: - Bit 0 (USED_FP) represents whether FP was used, essentially providing the boolean flag which sc_used_math as a whole provided previously. - Bit 1 (USED_FR1) provides the value of the Status.FR bit at the time the FP context was saved. - Bit 2 (USED_HYBRID_FPRS) indicates whether the FP context was saved under the hybrid FPR scheme. Essentially, when set the odd singles are located in bits 63:32 of the preceding even indexed sc_fpregs element. Any userland that tests whether the sc_used_math field is zero or non-zero will continue to function as expected. Having said that, I could not find any userland which uses the sc_used_math field at all. [ralf@linux-mips.org: Fixed rejects.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Michael Ellerman Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andy Lutomirski Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10794/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/sigcontext.h | 9 +++++++++ arch/mips/kernel/signal.c | 15 +++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h index 9081d88ae44f3..28f51bb470466 100644 --- a/arch/mips/include/uapi/asm/sigcontext.h +++ b/arch/mips/include/uapi/asm/sigcontext.h @@ -12,6 +12,15 @@ #include #include +/* scalar FP context was used */ +#define USED_FP (1 << 0) + +/* the value of Status.FR when context was saved */ +#define USED_FR1 (1 << 1) + +/* FR=1, but with odd singles in bits 63:32 of preceding even double */ +#define USED_HYBRID_FPRS (1 << 2) + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 08f521567d64c..9cb75e9519c55 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -133,9 +133,16 @@ int protected_save_fp_context(void __user *sc) unsigned int used; int err; - used = !!used_math(); + used = used_math() ? USED_FP : 0; + if (used) { + if (!test_thread_flag(TIF_32BIT_FPREGS)) + used |= USED_FR1; + if (test_thread_flag(TIF_HYBRID_FPREGS)) + used |= USED_HYBRID_FPRS; + } + err = __put_user(used, used_math); - if (err || !used) + if (err || !(used & USED_FP)) return err; /* @@ -177,13 +184,13 @@ int protected_restore_fp_context(void __user *sc) int err, sig, tmp __maybe_unused; err = __get_user(used, used_math); - conditional_used_math(used); + conditional_used_math(used & USED_FP); /* * The signal handler may have used FPU; give it up if the program * doesn't want it following sigreturn. */ - if (err || !used) { + if (err || !(used & USED_FP)) { lose_fpu(0); return err; } -- GitLab From f1fe2d21f4e1aca8644cea888dc618f0183ad671 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:21 -0700 Subject: [PATCH 6159/7006] MIPS: Add definitions for extended context The context introduced by MSA needs to be saved around signals. However, we can't increase the size of struct sigcontext because that will change the offset of the signal mask in struct sigframe or struct ucontext. This patch instead places the new context immediately after the struct sigframe for traditional signals, or similarly after struct ucontext for RT signals. The layout of struct sigframe & struct ucontext is identical from their sigcontext fields onwards, so the offset from the sigcontext to the extended context will always be the same regardless of the type of signal. Userland will be able to search through the extended context by using the magic values to detect which types of context are present. Any unrecognised context can be skipped over using the size field of struct extcontext. Once the magic value END_EXTCONTEXT_MAGIC is seen it is known that there are no further extended context structures to examine. This approach is somewhat similar to that taken by ARM to save VFP & other context at the end of struct ucontext. Userland can determine whether extended context is present by checking for the USED_EXTCONTEXT bit in the sc_used_math field of struct sigcontext. Whilst this could potentially change the historic semantics of sc_used_math if further extended context which does not imply FP context were to be introduced in the future, I have been unable to find any userland code making use of sc_used_math at all. Using one of the fields described as unused in struct sigcontext was considered, but the kernel does not already write to those fields so there would be no guarantee of the field being clear on older kernels. Other alternatives would be to have userland check the kernel version, or to have a HWCAP bit indicating presence of extended context. However there is a desire to have the context & information required to decode it be self contained such that, for example, debuggers could decode the saved context easily. [ralf@linux-mips.org: Fixed conflict.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Peter Zijlstra Cc: Zubair Lutfullah Kakakhel Cc: Alex Smith Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: Andrew Morton Cc: Andy Lutomirski Cc: Michael Ellerman Cc: Markos Chandras Cc: Daniel Borkmann Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10795/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/Kbuild | 1 - arch/mips/include/uapi/asm/sigcontext.h | 3 ++ arch/mips/include/uapi/asm/ucontext.h | 65 +++++++++++++++++++++++++ arch/mips/kernel/signal.c | 13 +++++ 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/uapi/asm/ucontext.h diff --git a/arch/mips/include/asm/Kbuild b/arch/mips/include/asm/Kbuild index 1f8546081d206..40ec4ca3f946a 100644 --- a/arch/mips/include/asm/Kbuild +++ b/arch/mips/include/asm/Kbuild @@ -16,6 +16,5 @@ generic-y += sections.h generic-y += segment.h generic-y += serial.h generic-y += trace_clock.h -generic-y += ucontext.h generic-y += user.h generic-y += xor.h diff --git a/arch/mips/include/uapi/asm/sigcontext.h b/arch/mips/include/uapi/asm/sigcontext.h index 28f51bb470466..5cbd9ae6421fa 100644 --- a/arch/mips/include/uapi/asm/sigcontext.h +++ b/arch/mips/include/uapi/asm/sigcontext.h @@ -21,6 +21,9 @@ /* FR=1, but with odd singles in bits 63:32 of preceding even double */ #define USED_HYBRID_FPRS (1 << 2) +/* extended context was used, see struct extcontext for details */ +#define USED_EXTCONTEXT (1 << 3) + #if _MIPS_SIM == _MIPS_SIM_ABI32 /* diff --git a/arch/mips/include/uapi/asm/ucontext.h b/arch/mips/include/uapi/asm/ucontext.h new file mode 100644 index 0000000000000..2320144ce8580 --- /dev/null +++ b/arch/mips/include/uapi/asm/ucontext.h @@ -0,0 +1,65 @@ +#ifndef __MIPS_UAPI_ASM_UCONTEXT_H +#define __MIPS_UAPI_ASM_UCONTEXT_H + +/** + * struct extcontext - extended context header structure + * @magic: magic value identifying the type of extended context + * @size: the size in bytes of the enclosing structure + * + * Extended context structures provide context which does not fit within struct + * sigcontext. They are placed sequentially in memory at the end of struct + * ucontext and struct sigframe, with each extended context structure beginning + * with a header defined by this struct. The type of context represented is + * indicated by the magic field. Userland may check each extended context + * structure against magic values that it recognises. The size field allows any + * unrecognised context to be skipped, allowing for future expansion. The end + * of the extended context data is indicated by the magic value + * END_EXTCONTEXT_MAGIC. + */ +struct extcontext { + unsigned int magic; + unsigned int size; +}; + +/** + * struct msa_extcontext - MSA extended context structure + * @ext: the extended context header, with magic == MSA_EXTCONTEXT_MAGIC + * @wr: the most significant 64 bits of each MSA vector register + * @csr: the value of the MSA control & status register + * + * If MSA context is live for a task at the time a signal is delivered to it, + * this structure will hold the MSA context of the task as it was prior to the + * signal delivery. + */ +struct msa_extcontext { + struct extcontext ext; +#define MSA_EXTCONTEXT_MAGIC 0x784d5341 /* xMSA */ + + unsigned long long wr[32]; + unsigned int csr; +}; + +#define END_EXTCONTEXT_MAGIC 0x78454e44 /* xEND */ + +/** + * struct ucontext - user context structure + * @uc_flags: + * @uc_link: + * @uc_stack: + * @uc_mcontext: holds basic processor state + * @uc_sigmask: + * @uc_extcontext: holds extended processor state + */ +struct ucontext { + /* Historic fields matching asm-generic */ + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; + + /* Extended context structures may follow ucontext */ + unsigned long long uc_extcontext[0]; +}; + +#endif /* __MIPS_UAPI_ASM_UCONTEXT_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 9cb75e9519c55..3101bafd3a9c7 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -47,8 +47,11 @@ static int (*restore_fp_context)(void __user *sc); struct sigframe { u32 sf_ass[4]; /* argument save space for o32 */ u32 sf_pad[2]; /* Was: signal trampoline */ + + /* Matches struct ucontext from its uc_mcontext field onwards */ struct sigcontext sf_sc; sigset_t sf_mask; + unsigned long long sf_extcontext[0]; }; struct rt_sigframe { @@ -686,6 +689,16 @@ static int smp_restore_fp_context(void __user *sc) static int signal_setup(void) { + /* + * The offset from sigcontext to extended context should be the same + * regardless of the type of signal, such that userland can always know + * where to look if it wishes to find the extended context structures. + */ + BUILD_BUG_ON((offsetof(struct sigframe, sf_extcontext) - + offsetof(struct sigframe, sf_sc)) != + (offsetof(struct rt_sigframe, rs_uc.uc_extcontext) - + offsetof(struct rt_sigframe, rs_uc.uc_mcontext))); + #ifdef CONFIG_SMP /* For now just do the cpu_has_fpu check when the functions are invoked */ save_fp_context = smp_save_fp_context; -- GitLab From bf82cb30c7e58b3a9742f0a45962ebdf51befac7 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:22 -0700 Subject: [PATCH 6160/7006] MIPS: Save MSA extended context around signals It is desirable for signal handlers to be allowed to make use of MSA, particularly if auto vectorisation is used when compiling a program. The MSA context must therefore be saved & restored before & after invoking the signal handler. Make use of the extended context structs defined in the preceding patch to save MSA context after the sigframe when appropriate. [ralf@linux-mips.org: Fixed conflicts.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: linux-kernel@vger.kernel.org Cc: Richard Weinberger Cc: James Hogan Cc: Andrew Morton Cc: Andy Lutomirski Cc: Markos Chandras Cc: Manuel Lauss Cc: Maciej W. Rozycki Patchwork: https://patchwork.linux-mips.org/patch/10796/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/r4k_fpu.S | 118 ++++++++++++++++ arch/mips/kernel/signal-common.h | 3 + arch/mips/kernel/signal.c | 227 +++++++++++++++++++++++++++++-- 3 files changed, 333 insertions(+), 15 deletions(-) diff --git a/arch/mips/kernel/r4k_fpu.S b/arch/mips/kernel/r4k_fpu.S index 0ed139889245a..f09546ee2cdc9 100644 --- a/arch/mips/kernel/r4k_fpu.S +++ b/arch/mips/kernel/r4k_fpu.S @@ -236,6 +236,124 @@ LEAF(\name) op_msa_wr write_msa_wr_w, ld_w op_msa_wr write_msa_wr_d, ld_d +#endif /* CONFIG_CPU_HAS_MSA */ + +#ifdef CONFIG_CPU_HAS_MSA + + .macro save_msa_upper wr, off, base + .set push + .set noat +#ifdef CONFIG_64BIT + copy_u_d \wr, 1 + EX sd $1, \off(\base) +#elif defined(CONFIG_CPU_LITTLE_ENDIAN) + copy_u_w \wr, 2 + EX sw $1, \off(\base) + copy_u_w \wr, 3 + EX sw $1, (\off+4)(\base) +#else /* CONFIG_CPU_BIG_ENDIAN */ + copy_u_w \wr, 2 + EX sw $1, (\off+4)(\base) + copy_u_w \wr, 3 + EX sw $1, \off(\base) +#endif + .set pop + .endm + +LEAF(_save_msa_all_upper) + save_msa_upper 0, 0x00, a0 + save_msa_upper 1, 0x08, a0 + save_msa_upper 2, 0x10, a0 + save_msa_upper 3, 0x18, a0 + save_msa_upper 4, 0x20, a0 + save_msa_upper 5, 0x28, a0 + save_msa_upper 6, 0x30, a0 + save_msa_upper 7, 0x38, a0 + save_msa_upper 8, 0x40, a0 + save_msa_upper 9, 0x48, a0 + save_msa_upper 10, 0x50, a0 + save_msa_upper 11, 0x58, a0 + save_msa_upper 12, 0x60, a0 + save_msa_upper 13, 0x68, a0 + save_msa_upper 14, 0x70, a0 + save_msa_upper 15, 0x78, a0 + save_msa_upper 16, 0x80, a0 + save_msa_upper 17, 0x88, a0 + save_msa_upper 18, 0x90, a0 + save_msa_upper 19, 0x98, a0 + save_msa_upper 20, 0xa0, a0 + save_msa_upper 21, 0xa8, a0 + save_msa_upper 22, 0xb0, a0 + save_msa_upper 23, 0xb8, a0 + save_msa_upper 24, 0xc0, a0 + save_msa_upper 25, 0xc8, a0 + save_msa_upper 26, 0xd0, a0 + save_msa_upper 27, 0xd8, a0 + save_msa_upper 28, 0xe0, a0 + save_msa_upper 29, 0xe8, a0 + save_msa_upper 30, 0xf0, a0 + save_msa_upper 31, 0xf8, a0 + jr ra + li v0, 0 + END(_save_msa_all_upper) + + .macro restore_msa_upper wr, off, base + .set push + .set noat +#ifdef CONFIG_64BIT + EX ld $1, \off(\base) + insert_d \wr, 1 +#elif defined(CONFIG_CPU_LITTLE_ENDIAN) + EX lw $1, \off(\base) + insert_w \wr, 2 + EX lw $1, (\off+4)(\base) + insert_w \wr, 3 +#else /* CONFIG_CPU_BIG_ENDIAN */ + EX lw $1, (\off+4)(\base) + insert_w \wr, 2 + EX lw $1, \off(\base) + insert_w \wr, 3 +#endif + .set pop + .endm + +LEAF(_restore_msa_all_upper) + restore_msa_upper 0, 0x00, a0 + restore_msa_upper 1, 0x08, a0 + restore_msa_upper 2, 0x10, a0 + restore_msa_upper 3, 0x18, a0 + restore_msa_upper 4, 0x20, a0 + restore_msa_upper 5, 0x28, a0 + restore_msa_upper 6, 0x30, a0 + restore_msa_upper 7, 0x38, a0 + restore_msa_upper 8, 0x40, a0 + restore_msa_upper 9, 0x48, a0 + restore_msa_upper 10, 0x50, a0 + restore_msa_upper 11, 0x58, a0 + restore_msa_upper 12, 0x60, a0 + restore_msa_upper 13, 0x68, a0 + restore_msa_upper 14, 0x70, a0 + restore_msa_upper 15, 0x78, a0 + restore_msa_upper 16, 0x80, a0 + restore_msa_upper 17, 0x88, a0 + restore_msa_upper 18, 0x90, a0 + restore_msa_upper 19, 0x98, a0 + restore_msa_upper 20, 0xa0, a0 + restore_msa_upper 21, 0xa8, a0 + restore_msa_upper 22, 0xb0, a0 + restore_msa_upper 23, 0xb8, a0 + restore_msa_upper 24, 0xc0, a0 + restore_msa_upper 25, 0xc8, a0 + restore_msa_upper 26, 0xd0, a0 + restore_msa_upper 27, 0xd8, a0 + restore_msa_upper 28, 0xe0, a0 + restore_msa_upper 29, 0xe8, a0 + restore_msa_upper 30, 0xf0, a0 + restore_msa_upper 31, 0xf8, a0 + jr ra + li v0, 0 + END(_restore_msa_all_upper) + #endif /* CONFIG_CPU_HAS_MSA */ .set reorder diff --git a/arch/mips/kernel/signal-common.h b/arch/mips/kernel/signal-common.h index 96b0fd82f8b51..f50d48435c680 100644 --- a/arch/mips/kernel/signal-common.h +++ b/arch/mips/kernel/signal-common.h @@ -37,4 +37,7 @@ _save_fp_context(void __user *fpregs, void __user *csr); extern asmlinkage int _restore_fp_context(void __user *fpregs, void __user *csr); +extern asmlinkage int _save_msa_all_upper(void __user *buf); +extern asmlinkage int _restore_msa_all_upper(void __user *buf); + #endif /* __SIGNAL_COMMON_H */ diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index 3101bafd3a9c7..fa13a52713dfc 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "signal-common.h" @@ -124,6 +125,168 @@ static int restore_hw_fp_context(void __user *sc) return _restore_fp_context(fpregs, csr); } +/* + * Extended context handling. + */ + +static inline void __user *sc_to_extcontext(void __user *sc) +{ + struct ucontext __user *uc; + + /* + * We can just pretend the sigcontext is always embedded in a struct + * ucontext here, because the offset from sigcontext to extended + * context is the same in the struct sigframe case. + */ + uc = container_of(sc, struct ucontext, uc_mcontext); + return &uc->uc_extcontext; +} + +static int save_msa_extcontext(void __user *buf) +{ + struct msa_extcontext __user *msa = buf; + uint64_t val; + int i, err; + + if (!thread_msa_context_live()) + return 0; + + /* + * Ensure that we can't lose the live MSA context between checking + * for it & writing it to memory. + */ + preempt_disable(); + + if (is_msa_enabled()) { + /* + * There are no EVA versions of the vector register load/store + * instructions, so MSA context has to be saved to kernel memory + * and then copied to user memory. The save to kernel memory + * should already have been done when handling scalar FP + * context. + */ + BUG_ON(config_enabled(CONFIG_EVA)); + + err = __put_user(read_msa_csr(), &msa->csr); + err |= _save_msa_all_upper(&msa->wr); + + preempt_enable(); + } else { + preempt_enable(); + + err = __put_user(current->thread.fpu.msacsr, &msa->csr); + + for (i = 0; i < NUM_FPU_REGS; i++) { + val = get_fpr64(¤t->thread.fpu.fpr[i], 1); + err |= __put_user(val, &msa->wr[i]); + } + } + + err |= __put_user(MSA_EXTCONTEXT_MAGIC, &msa->ext.magic); + err |= __put_user(sizeof(*msa), &msa->ext.size); + + return err ? -EFAULT : sizeof(*msa); +} + +static int restore_msa_extcontext(void __user *buf, unsigned int size) +{ + struct msa_extcontext __user *msa = buf; + unsigned long long val; + unsigned int csr; + int i, err; + + if (size != sizeof(*msa)) + return -EINVAL; + + err = get_user(csr, &msa->csr); + if (err) + return err; + + preempt_disable(); + + if (is_msa_enabled()) { + /* + * There are no EVA versions of the vector register load/store + * instructions, so MSA context has to be copied to kernel + * memory and later loaded to registers. The same is true of + * scalar FP context, so FPU & MSA should have already been + * disabled whilst handling scalar FP context. + */ + BUG_ON(config_enabled(CONFIG_EVA)); + + write_msa_csr(csr); + err |= _restore_msa_all_upper(&msa->wr); + preempt_enable(); + } else { + preempt_enable(); + + current->thread.fpu.msacsr = csr; + + for (i = 0; i < NUM_FPU_REGS; i++) { + err |= __get_user(val, &msa->wr[i]); + set_fpr64(¤t->thread.fpu.fpr[i], 1, val); + } + } + + return err; +} + +static int save_extcontext(void __user *buf) +{ + int sz; + + sz = save_msa_extcontext(buf); + if (sz < 0) + return sz; + buf += sz; + + /* If no context was saved then trivially return */ + if (!sz) + return 0; + + /* Write the end marker */ + if (__put_user(END_EXTCONTEXT_MAGIC, (u32 *)buf)) + return -EFAULT; + + sz += sizeof(((struct extcontext *)NULL)->magic); + return sz; +} + +static int restore_extcontext(void __user *buf) +{ + struct extcontext ext; + int err; + + while (1) { + err = __get_user(ext.magic, (unsigned int *)buf); + if (err) + return err; + + if (ext.magic == END_EXTCONTEXT_MAGIC) + return 0; + + err = __get_user(ext.size, (unsigned int *)(buf + + offsetof(struct extcontext, size))); + if (err) + return err; + + switch (ext.magic) { + case MSA_EXTCONTEXT_MAGIC: + err = restore_msa_extcontext(buf, ext.size); + break; + + default: + err = -EINVAL; + break; + } + + if (err) + return err; + + buf += ext.size; + } +} + /* * Helper routines */ @@ -133,20 +296,17 @@ int protected_save_fp_context(void __user *sc) uint64_t __user *fpregs = sc + abi->off_sc_fpregs; uint32_t __user *csr = sc + abi->off_sc_fpc_csr; uint32_t __user *used_math = sc + abi->off_sc_used_math; - unsigned int used; + unsigned int used, ext_sz; int err; used = used_math() ? USED_FP : 0; - if (used) { - if (!test_thread_flag(TIF_32BIT_FPREGS)) - used |= USED_FR1; - if (test_thread_flag(TIF_HYBRID_FPREGS)) - used |= USED_HYBRID_FPRS; - } + if (!used) + goto fp_done; - err = __put_user(used, used_math); - if (err || !(used & USED_FP)) - return err; + if (!test_thread_flag(TIF_32BIT_FPREGS)) + used |= USED_FR1; + if (test_thread_flag(TIF_HYBRID_FPREGS)) + used |= USED_HYBRID_FPRS; /* * EVA does not have userland equivalents of ldc1 or sdc1, so @@ -171,10 +331,16 @@ int protected_save_fp_context(void __user *sc) __put_user(0, &fpregs[31]) | __put_user(0, csr); if (err) - break; /* really bad sigcontext */ + return err; /* really bad sigcontext */ } - return err; +fp_done: + ext_sz = err = save_extcontext(sc_to_extcontext(sc)); + if (err < 0) + return err; + used |= ext_sz ? USED_EXTCONTEXT : 0; + + return __put_user(used, used_math); } int protected_restore_fp_context(void __user *sc) @@ -184,7 +350,7 @@ int protected_restore_fp_context(void __user *sc) uint32_t __user *csr = sc + abi->off_sc_fpc_csr; uint32_t __user *used_math = sc + abi->off_sc_used_math; unsigned int used; - int err, sig, tmp __maybe_unused; + int err, sig = 0, tmp __maybe_unused; err = __get_user(used, used_math); conditional_used_math(used & USED_FP); @@ -193,10 +359,12 @@ int protected_restore_fp_context(void __user *sc) * The signal handler may have used FPU; give it up if the program * doesn't want it following sigreturn. */ - if (err || !(used & USED_FP)) { + if (err || !(used & USED_FP)) lose_fpu(0); + if (err) return err; - } + if (!(used & USED_FP)) + goto fp_done; err = sig = fpcsr_pending(csr); if (err < 0) @@ -229,6 +397,10 @@ int protected_restore_fp_context(void __user *sc) break; /* really bad sigcontext */ } +fp_done: + if (used & USED_EXTCONTEXT) + err |= restore_extcontext(sc_to_extcontext(sc)); + return err ?: sig; } @@ -268,6 +440,28 @@ int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc) return err; } +static size_t extcontext_max_size(void) +{ + size_t sz = 0; + + /* + * The assumption here is that between this point & the point at which + * the extended context is saved the size of the context should only + * ever be able to shrink (if the task is preempted), but never grow. + * That is, what this function returns is an upper bound on the size of + * the extended context for the current task at the current time. + */ + + if (thread_msa_context_live()) + sz += sizeof(struct msa_extcontext); + + /* If any context is saved then we'll append the end marker */ + if (sz) + sz += sizeof(((struct extcontext *)NULL)->magic); + + return sz; +} + int fpcsr_pending(unsigned int __user *fpcsr) { int err, sig = 0; @@ -324,6 +518,9 @@ void __user *get_sigframe(struct ksignal *ksig, struct pt_regs *regs, { unsigned long sp; + /* Leave space for potential extended context */ + frame_size += extcontext_max_size(); + /* Default to using normal stack */ sp = regs->regs[29]; -- GitLab From e14f1db7a61f016d74393ca9e8fc49a91d27f603 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:23 -0700 Subject: [PATCH 6161/7006] MIPS: AT_HWCAP aux vector infrastructure In order for userland to determine whether various features are safe to use, it will need to know both that the hardware supports those features and that the kernel is recent enough & configured appropriately to support them. For example under the O32 modeless FP proposal the dynamic linker & ifunc resolvers will need this information. The kernel is the only thing in a position to know availability accurately, so the kernel needs to provide the information to userland. This patch introduces the infrastructure to provide the AT_HWCAP aux vector to userland in order to provide that information. It also defines the 2 currently specified flags, which indicate MIPSr6 & MSA support. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Kees Cook Cc: Huacai Chen Cc: Maciej W. Rozycki Cc: Alex Smith Cc: linux-kernel@vger.kernel.org Cc: Leonid Yegoshin Cc: Markos Chandras Cc: Ingo Molnar Patchwork: https://patchwork.linux-mips.org/patch/10797/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/elf.h | 4 +++- arch/mips/include/uapi/asm/hwcap.h | 8 ++++++++ arch/mips/kernel/cpu-probe.c | 3 +++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 arch/mips/include/uapi/asm/hwcap.h diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h index f19e890b99d27..53b26933b12ce 100644 --- a/arch/mips/include/asm/elf.h +++ b/arch/mips/include/asm/elf.h @@ -382,7 +382,9 @@ do { \ instruction set this cpu supports. This could be done in userspace, but it's not easy, and we've already done it here. */ -#define ELF_HWCAP (0) +#define ELF_HWCAP (elf_hwcap) +extern unsigned int elf_hwcap; +#include /* * This yields a string that ld.so will use to load implementation diff --git a/arch/mips/include/uapi/asm/hwcap.h b/arch/mips/include/uapi/asm/hwcap.h new file mode 100644 index 0000000000000..c7484a7ca686d --- /dev/null +++ b/arch/mips/include/uapi/asm/hwcap.h @@ -0,0 +1,8 @@ +#ifndef _UAPI_ASM_HWCAP_H +#define _UAPI_ASM_HWCAP_H + +/* HWCAP flags */ +#define HWCAP_MIPS_R6 (1 << 0) +#define HWCAP_MIPS_MSA (1 << 1) + +#endif /* _UAPI_ASM_HWCAP_H */ diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 987036761fb61..b6c1feed8b7b6 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -32,6 +32,9 @@ #include #include +/* Hardware capabilities */ +unsigned int elf_hwcap __read_mostly; + /* * Get the FPU Implementation/Revision. */ -- GitLab From 4c0630346e2fcfe68eac8fa31d38daf04570e671 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:24 -0700 Subject: [PATCH 6162/7006] MIPS: Advertise MIPSr6 via HWCAP when appropriate When running on a CPU implementing the release 6 of the MIPS32 or MIPS64 ISA, advertise that to userland via the appropriate HWCAP bit. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Huacai Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10798/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index b6c1feed8b7b6..380a14b8772ea 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1524,6 +1524,9 @@ void cpu_probe(void) else c->srsets = 1; + if (cpu_has_mips_r6) + elf_hwcap |= HWCAP_MIPS_R6; + if (cpu_has_msa) { c->msa_id = cpu_get_msa_id(); WARN(c->msa_id & MSA_IR_WRPF, -- GitLab From 3cc9fa7fb3e38e83e59977c8bc5c355687232362 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:25 -0700 Subject: [PATCH 6163/7006] MIPS: Advertise MSA support via HWCAP when present If MSA is supported by both the hardware & the kernel then advertise that support to userland via the AT_HWCAP aux vector. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: Huacai Chen Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10799/ Signed-off-by: Ralf Baechle --- arch/mips/kernel/cpu-probe.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index 380a14b8772ea..571a8e6ea5bd0 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -1531,6 +1531,7 @@ void cpu_probe(void) c->msa_id = cpu_get_msa_id(); WARN(c->msa_id & MSA_IR_WRPF, "Vector register partitioning unimplemented!"); + elf_hwcap |= HWCAP_MIPS_MSA; } cpu_probe_vmbits(c); -- GitLab From 0ce3417e84825155e2d74ac65e133bf7ba995a74 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 27 Jul 2015 12:58:27 -0700 Subject: [PATCH 6164/7006] MIPS: Drop EXPERIMENTAL tag from O32+FP64 & MSA CONFIG_MIPS_O32_FP64_SUPPORT and CONFIG_CPU_HAS_MSA are in pretty good shape these days, and in much wider use than they once were. Stop referring to them as EXPERIMENTAL. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Guenter Roeck Cc: Matthew Fortune Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10801/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index efa3706beb549..3c2e4c87d489e 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2307,7 +2307,7 @@ config CPU_MICROMIPS endchoice config CPU_HAS_MSA - bool "Support for the MIPS SIMD Architecture (EXPERIMENTAL)" + bool "Support for the MIPS SIMD Architecture" depends on CPU_SUPPORTS_MSA depends on 64BIT || MIPS_O32_FP64_SUPPORT help @@ -2647,7 +2647,7 @@ config SECCOMP If unsure, say Y. Only embedded should say N here. config MIPS_O32_FP64_SUPPORT - bool "Support for O32 binaries using 64-bit FP (EXPERIMENTAL)" + bool "Support for O32 binaries using 64-bit FP" depends on 32BIT || MIPS32_O32 help When this is enabled, the kernel will support use of 64-bit floating -- GitLab From c4687b15a8487e8ef028814a301a88958baf72bc Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 24 Jul 2015 16:16:10 +0100 Subject: [PATCH 6165/7006] MIPS: Fix definition of pgprot_writecombine() If pgprot_writecombine is not #defined, asm-generic/pgtable.h will try to provide a default implementation by #defining it to pgprot_noncached. However our implementation is an inline function rather than a #define, so it was never actually used because of the #define in generic code. Add "#define pgprot_writecombine pgprot_writecombine" to prevent generic code from re-defining it. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10767/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/include/asm/pgtable.h b/arch/mips/include/asm/pgtable.h index ae85694752644..8957f15e21ec4 100644 --- a/arch/mips/include/asm/pgtable.h +++ b/arch/mips/include/asm/pgtable.h @@ -393,6 +393,8 @@ static inline pgprot_t pgprot_noncached(pgprot_t _prot) return __pgprot(prot); } +#define pgprot_writecombine pgprot_writecombine + static inline pgprot_t pgprot_writecombine(pgprot_t _prot) { unsigned long prot = pgprot_val(_prot); -- GitLab From 8c172467be36f7c9591e59b647e4cd342ce2ef41 Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Thu, 30 Jul 2015 12:03:42 +0100 Subject: [PATCH 6166/7006] MIPS: Add implementation of dma_map_ops.mmap() The generic implementation of dma_map_ops.mmap(), dma_common_mmap(), is not correct for non-coherent devices. It expects to be passed a virtual address previously returned by dma_alloc_coherent(), which for a non-coherent device will return a KSEG1 address. It then attempts to convert that virtual address to a physical address using virt_to_page() which will yield an incorrect address. Also, dma_common_mmap() does not handle the DMA_ATTR_WRITE_COMBINE attribute, and therefore dma_mmap_writecombine() will not actually set the appropriate pgprot_t flags for write combining. This patch adds an implementation of dma_map_ops.mmap() that correctly handles KSEG1 addresses, and enables write combining when requested. Signed-off-by: Alex Smith Cc: Sadegh Abbasi Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10808/ Signed-off-by: Ralf Baechle --- arch/mips/mm/dma-default.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index eeaf0245c3b16..8f23cf08f4baa 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -194,6 +194,40 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, __free_pages(page, get_order(size)); } +static int mips_dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + struct dma_attrs *attrs) +{ + unsigned long user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; + unsigned long addr = (unsigned long)cpu_addr; + unsigned long off = vma->vm_pgoff; + unsigned long pfn; + int ret = -ENXIO; + + if (!plat_device_is_coherent(dev) && !hw_coherentio) + addr = CAC_ADDR(addr); + + pfn = page_to_pfn(virt_to_page((void *)addr)); + + if (dma_get_attr(DMA_ATTR_WRITE_COMBINE, attrs)) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + else + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) + return ret; + + if (off < count && user_count <= (count - off)) { + ret = remap_pfn_range(vma, vma->vm_start, + pfn + off, + user_count << PAGE_SHIFT, + vma->vm_page_prot); + } + + return ret; +} + static inline void __dma_sync_virtual(void *addr, size_t size, enum dma_data_direction direction) { @@ -380,6 +414,7 @@ EXPORT_SYMBOL(dma_cache_sync); static struct dma_map_ops mips_default_dma_map_ops = { .alloc = mips_dma_alloc_coherent, .free = mips_dma_free_coherent, + .mmap = mips_dma_mmap, .map_page = mips_dma_map_page, .unmap_page = mips_dma_unmap_page, .map_sg = mips_dma_map_sg, -- GitLab From f1f5e414851fdb69a3200e5c15799ea4788d423e Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Fri, 24 Jul 2015 16:16:12 +0100 Subject: [PATCH 6167/7006] MIPS: Use Ingenic-specific write combine attribute on all Ingenic platforms The Ingenic-specific write combining cache attribute was defined based on CONFIG_MACH_JZ4740 and therefore not used on JZ4780. Change this to CONFIG_MACH_INGENIC so that it gets used on all Ingenic platforms. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10769/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/pgtable-bits.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/pgtable-bits.h b/arch/mips/include/asm/pgtable-bits.h index c28a8499aec7f..002eeb224733b 100644 --- a/arch/mips/include/asm/pgtable-bits.h +++ b/arch/mips/include/asm/pgtable-bits.h @@ -249,7 +249,7 @@ static inline uint64_t pte_to_entrylo(unsigned long pte_val) #define _CACHE_CACHABLE_NONCOHERENT (3<<_CACHE_SHIFT) /* LOONGSON */ #define _CACHE_CACHABLE_COHERENT (3<<_CACHE_SHIFT) /* LOONGSON-3 */ -#elif defined(CONFIG_MACH_JZ4740) +#elif defined(CONFIG_MACH_INGENIC) /* Ingenic uses the WA bit to achieve write-combine memory writes */ #define _CACHE_UNCACHED_ACCELERATED (1<<_CACHE_SHIFT) -- GitLab From f51246efee2b6bc72e86bc1d16599fc7c455b986 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 29 Jul 2015 12:14:42 +0200 Subject: [PATCH 6168/7006] MIPS: Get rid of finish_arch_switch(). MIPS was using finish_arch_switch() as a hook to restore and initialize CPU context for all threads, even newly created kernel and user threads. This is however entirely solvable within switch_to() so get rid of finish_arch_switch() which is in the way of scheduler cleanups. Signed-off-by: Ralf Baechle --- arch/mips/include/asm/switch_to.h | 48 +++++++++++++++---------------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index 7163cd7fdd69a..9733cd0266e4b 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -83,45 +83,43 @@ do { if (cpu_has_rw_llb) { \ } \ } while (0) +/* + * For newly created kernel threads switch_to() will return to + * ret_from_kernel_thread, newly created user threads to ret_from_fork. + * That is, everything following resume() will be skipped for new threads. + * So everything that matters to new threads should be placed before resume(). + */ #define switch_to(prev, next, last) \ do { \ - u32 __c0_stat; \ s32 __fpsave = FP_SAVE_NONE; \ __mips_mt_fpaff_switch_to(prev); \ - if (cpu_has_dsp) \ + if (cpu_has_dsp) { \ __save_dsp(prev); \ - if (cop2_present && (KSTK_STATUS(prev) & ST0_CU2)) { \ - if (cop2_lazy_restore) \ - KSTK_STATUS(prev) &= ~ST0_CU2; \ - __c0_stat = read_c0_status(); \ - write_c0_status(__c0_stat | ST0_CU2); \ - cop2_save(prev); \ - write_c0_status(__c0_stat & ~ST0_CU2); \ + __restore_dsp(next); \ + } \ + if (cop2_present) { \ + set_c0_status(ST0_CU2); \ + if ((KSTK_STATUS(prev) & ST0_CU2)) { \ + if (cop2_lazy_restore) \ + KSTK_STATUS(prev) &= ~ST0_CU2; \ + cop2_save(prev); \ + } \ + if (KSTK_STATUS(next) & ST0_CU2 && \ + !cop2_lazy_restore) { \ + cop2_restore(next); \ + } \ + clear_c0_status(ST0_CU2); \ } \ __clear_software_ll_bit(); \ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \ __fpsave = FP_SAVE_SCALAR; \ if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \ __fpsave = FP_SAVE_VECTOR; \ - (last) = resume(prev, next, task_thread_info(next), __fpsave); \ -} while (0) - -#define finish_arch_switch(prev) \ -do { \ - u32 __c0_stat; \ - if (cop2_present && !cop2_lazy_restore && \ - (KSTK_STATUS(current) & ST0_CU2)) { \ - __c0_stat = read_c0_status(); \ - write_c0_status(__c0_stat | ST0_CU2); \ - cop2_restore(current); \ - write_c0_status(__c0_stat & ~ST0_CU2); \ - } \ - if (cpu_has_dsp) \ - __restore_dsp(current); \ if (cpu_has_userlocal) \ - write_c0_userlocal(current_thread_info()->tp_value); \ + write_c0_userlocal(task_thread_info(next)->tp_value); \ __restore_watch(); \ disable_msa(); \ + (last) = resume(prev, next, task_thread_info(next), __fpsave); \ } while (0) #endif /* _ASM_SWITCH_TO_H */ -- GitLab From 5fac4f7ac067b2eee3aaf19eff8bd1d7d8e9a91e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 30 Jul 2015 08:16:10 -0700 Subject: [PATCH 6169/7006] MIPS: Select CONFIG_ARCH_USE_CMPXCHG_LOCKREF for MIPS64 On MIPS64 we have spinlocks that are 32b in size and an efficient cmpxchg64 implementation, so we qualify to make use of cmpxchg backed lockrefs. Select the ARCH_USE_CMPXCHG_LOCKREF Kconfig symbol and provide a trivial implementation of arch_spin_value_unlocked to satisfy the lockref code. Using Linus' simple testcase from http://article.gmane.org/gmane.linux.file-systems/77466 on a dual core system with an in-development MIPS64 CPU running on FPGA I see around an 8% gain: Pre-patch: Total loops: 252698 Total loops: 251482 Total loops: 250806 Total loops: 252885 Total loops: 251666 Post-patch: Total loops: 273728 Total loops: 269932 Total loops: 269341 Total loops: 275004 Total loops: 270208 [ralf@linux-mips.org: Fixed conflict.] Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Steven J. Hill Cc: linux-kernel@vger.kernel.org Cc: Maciej W. Rozycki Cc: Markos Chandras Patchwork: https://patchwork.linux-mips.org/patch/10810/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/include/asm/spinlock.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 3c2e4c87d489e..449f840d5a7f9 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -3,6 +3,7 @@ config MIPS default y select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO + select ARCH_USE_CMPXCHG_LOCKREF if 64BIT select HAVE_CONTEXT_TRACKING select HAVE_GENERIC_DMA_COHERENT select HAVE_IDE diff --git a/arch/mips/include/asm/spinlock.h b/arch/mips/include/asm/spinlock.h index 9de4ba43dcd11..40196bebe849a 100644 --- a/arch/mips/include/asm/spinlock.h +++ b/arch/mips/include/asm/spinlock.h @@ -42,6 +42,11 @@ static inline int arch_spin_is_locked(arch_spinlock_t *lock) return ((counters >> 16) ^ counters) & 0xffff; } +static inline int arch_spin_value_unlocked(arch_spinlock_t lock) +{ + return lock.h.serving_now == lock.h.ticket; +} + #define arch_spin_lock_flags(lock, flags) arch_spin_lock(lock) #define arch_spin_unlock_wait(x) \ while (arch_spin_is_locked(x)) { cpu_relax(); } -- GitLab From f689332b19fa1120de1bd84988a7bd0c08bd9b7b Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Fri, 3 Jul 2015 11:11:48 +0200 Subject: [PATCH 6170/7006] MIPS: Ath79: Remove the unused GPIO function API To prepare moving the GPIO driver to drivers/gpio remove the platform specific pinmux API. As it is not used by any board, and such functionality should better be implemented using the pinmux subsystem just removing it seems to be the best option. Signed-off-by: Alban Bedel Acked-by: Linus Walleij Cc: linux-gpio@vger.kernel.org Cc: Alexandre Courbot Cc: Gabor Juhos Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10596/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/common.h | 3 --- arch/mips/ath79/gpio.c | 43 ---------------------------------------- 2 files changed, 46 deletions(-) diff --git a/arch/mips/ath79/common.h b/arch/mips/ath79/common.h index e5ea71277f0cf..ca7cc19adfea7 100644 --- a/arch/mips/ath79/common.h +++ b/arch/mips/ath79/common.h @@ -25,9 +25,6 @@ unsigned long ath79_get_sys_clk_rate(const char *id); void ath79_ddr_ctrl_init(void); void ath79_ddr_wb_flush(unsigned int reg); -void ath79_gpio_function_enable(u32 mask); -void ath79_gpio_function_disable(u32 mask); -void ath79_gpio_function_setup(u32 set, u32 clear); void ath79_gpio_init(void); #endif /* __ATH79_COMMON_H */ diff --git a/arch/mips/ath79/gpio.c b/arch/mips/ath79/gpio.c index f59ccb26520a9..c3c92eb56e040 100644 --- a/arch/mips/ath79/gpio.c +++ b/arch/mips/ath79/gpio.c @@ -24,8 +24,6 @@ #include #include -#include -#include "common.h" static void __iomem *ath79_gpio_base; static u32 ath79_gpio_count; @@ -139,47 +137,6 @@ static struct gpio_chip ath79_gpio_chip = { .base = 0, }; -static void __iomem *ath79_gpio_get_function_reg(void) -{ - u32 reg = 0; - - if (soc_is_ar71xx() || - soc_is_ar724x() || - soc_is_ar913x() || - soc_is_ar933x()) - reg = AR71XX_GPIO_REG_FUNC; - else if (soc_is_ar934x()) - reg = AR934X_GPIO_REG_FUNC; - else - BUG(); - - return ath79_gpio_base + reg; -} - -void ath79_gpio_function_setup(u32 set, u32 clear) -{ - void __iomem *reg = ath79_gpio_get_function_reg(); - unsigned long flags; - - spin_lock_irqsave(&ath79_gpio_lock, flags); - - __raw_writel((__raw_readl(reg) & ~clear) | set, reg); - /* flush write */ - __raw_readl(reg); - - spin_unlock_irqrestore(&ath79_gpio_lock, flags); -} - -void ath79_gpio_function_enable(u32 mask) -{ - ath79_gpio_function_setup(mask, 0); -} - -void ath79_gpio_function_disable(u32 mask) -{ - ath79_gpio_function_setup(0, mask); -} - static const struct of_device_id ath79_gpio_of_match[] = { { .compatible = "qca,ar7100-gpio" }, { .compatible = "qca,ar9340-gpio" }, -- GitLab From 1d473c2cb9fe25fc6bad30b0eb8d92e384496042 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Fri, 3 Jul 2015 11:11:49 +0200 Subject: [PATCH 6171/7006] MIPS: ath79: Move the GPIO driver to drivers/gpio GPIO drivers should be in drivers/gpio Signed-off-by: Alban Bedel Acked-by: Linus Walleij Cc: linux-gpio@vger.kernel.org Cc: Alexandre Courbot Cc: Gabor Juhos Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10597/ Signed-off-by: Ralf Baechle --- arch/mips/ath79/Makefile | 2 +- drivers/gpio/Makefile | 1 + arch/mips/ath79/gpio.c => drivers/gpio/gpio-ath79.c | 0 3 files changed, 2 insertions(+), 1 deletion(-) rename arch/mips/ath79/gpio.c => drivers/gpio/gpio-ath79.c (100%) diff --git a/arch/mips/ath79/Makefile b/arch/mips/ath79/Makefile index 5c9ff692ff3ca..fcc382cfc7709 100644 --- a/arch/mips/ath79/Makefile +++ b/arch/mips/ath79/Makefile @@ -8,7 +8,7 @@ # under the terms of the GNU General Public License version 2 as published # by the Free Software Foundation. -obj-y := prom.o setup.o irq.o common.o clock.o gpio.o +obj-y := prom.o setup.o irq.o common.o clock.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o obj-$(CONFIG_PCI) += pci.o diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index f82cd678ce086..2b64f6177e33c 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_GPIO_ADP5588) += gpio-adp5588.o obj-$(CONFIG_GPIO_ALTERA) += gpio-altera.o obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o +obj-$(CONFIG_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o diff --git a/arch/mips/ath79/gpio.c b/drivers/gpio/gpio-ath79.c similarity index 100% rename from arch/mips/ath79/gpio.c rename to drivers/gpio/gpio-ath79.c -- GitLab From 832f5dacfa0bb081a3b3b979a36a132b28ffacf3 Mon Sep 17 00:00:00 2001 From: Alban Bedel Date: Sun, 2 Aug 2015 18:30:11 +0200 Subject: [PATCH 6172/7006] MIPS: Remove all the uses of custom gpio.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently CONFIG_ARCH_HAVE_CUSTOM_GPIO_H is defined for all MIPS machines, and each machine type provides its own gpio.h. However only a handful really implement the GPIO API, most just forward everythings to gpiolib. The Alchemy machine is notable as it provides a system to allow implementing the GPIO API at the board level. But it is not used by any board currently supported, so it can also be removed. For most machine types we can just remove the custom gpio.h, as well as the custom wrappers if some exists. Some of the code found in the wrappers must be moved to the respective GPIO driver. A few more fixes are need in some drivers as they rely on linux/gpio.h to provides some machine specific definitions, or used asm/gpio.h instead of linux/gpio.h for the gpio API. Signed-off-by: Alban Bedel Reviewed-by: Linus Walleij Cc: linux-mips@linux-mips.org Cc: Hauke Mehrtens Cc: Rafał Miłecki Cc: Bartlomiej Zolnierkiewicz Cc: Tejun Heo Cc: Alexandre Courbot Cc: Dmitry Torokhov Cc: Florian Fainelli Cc: Manuel Lauss Cc: Joe Perches Cc: Daniel Walter Cc: Sergey Ryazanov Cc: Huacai Chen Cc: James Hartley Cc: Andrew Bresticker Cc: Paul Burton Cc: Jiri Kosina Cc: Bjorn Helgaas Cc: Wolfram Sang Cc: Randy Dunlap Cc: Varka Bhadram Cc: Masanari Iida Cc: Tomi Valkeinen Cc: Michael Buesch Cc: abdoulaye berthe Cc: linux-kernel@vger.kernel.org Cc: linux-ide@vger.kernel.org Cc: linux-gpio@vger.kernel.org Cc: linux-input@vger.kernel.org Cc: netdev@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/10828/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 - arch/mips/alchemy/Kconfig | 7 - arch/mips/alchemy/board-gpr.c | 1 + arch/mips/alchemy/board-mtx1.c | 1 + arch/mips/alchemy/common/Makefile | 7 +- arch/mips/alchemy/devboards/db1000.c | 1 + arch/mips/alchemy/devboards/db1300.c | 1 + arch/mips/alchemy/devboards/db1550.c | 1 + arch/mips/alchemy/devboards/pm.c | 2 +- arch/mips/ar7/gpio.c | 5 +- arch/mips/ar7/platform.c | 1 - arch/mips/ar7/setup.c | 1 - arch/mips/include/asm/gpio.h | 6 - arch/mips/include/asm/mach-ar7/ar7.h | 4 + arch/mips/include/asm/mach-ar7/gpio.h | 41 ----- arch/mips/include/asm/mach-ath25/gpio.h | 16 -- arch/mips/include/asm/mach-ath79/gpio.h | 26 --- .../include/asm/mach-au1x00/gpio-au1000.h | 148 ++---------------- arch/mips/include/asm/mach-au1x00/gpio.h | 86 ---------- arch/mips/include/asm/mach-bcm47xx/gpio.h | 17 -- arch/mips/include/asm/mach-bcm63xx/gpio.h | 15 -- .../include/asm/mach-cavium-octeon/gpio.h | 21 --- arch/mips/include/asm/mach-generic/gpio.h | 21 --- arch/mips/include/asm/mach-jz4740/gpio.h | 2 - arch/mips/include/asm/mach-lantiq/gpio.h | 13 -- arch/mips/include/asm/mach-loongson64/gpio.h | 36 ----- arch/mips/include/asm/mach-pistachio/gpio.h | 21 --- arch/mips/include/asm/mach-rc32434/gpio.h | 12 -- arch/mips/jz4740/gpio.c | 20 +-- arch/mips/pci/pci-lantiq.c | 1 - arch/mips/rb532/devices.c | 1 + arch/mips/rb532/gpio.c | 6 + arch/mips/txx9/generic/setup.c | 16 -- drivers/ata/pata_rb532_cf.c | 3 +- drivers/gpio/gpio-ath79.c | 32 ---- drivers/input/misc/rb532_button.c | 1 + drivers/net/ethernet/ti/cpmac.c | 2 + 37 files changed, 45 insertions(+), 551 deletions(-) delete mode 100644 arch/mips/include/asm/gpio.h delete mode 100644 arch/mips/include/asm/mach-ar7/gpio.h delete mode 100644 arch/mips/include/asm/mach-ath25/gpio.h delete mode 100644 arch/mips/include/asm/mach-ath79/gpio.h delete mode 100644 arch/mips/include/asm/mach-au1x00/gpio.h delete mode 100644 arch/mips/include/asm/mach-bcm47xx/gpio.h delete mode 100644 arch/mips/include/asm/mach-bcm63xx/gpio.h delete mode 100644 arch/mips/include/asm/mach-cavium-octeon/gpio.h delete mode 100644 arch/mips/include/asm/mach-generic/gpio.h delete mode 100644 arch/mips/include/asm/mach-lantiq/gpio.h delete mode 100644 arch/mips/include/asm/mach-loongson64/gpio.h delete mode 100644 arch/mips/include/asm/mach-pistachio/gpio.h diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 449f840d5a7f9..06c5957917d3a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -14,7 +14,6 @@ config MIPS select HAVE_ARCH_SECCOMP_FILTER select HAVE_ARCH_TRACEHOOK select HAVE_BPF_JIT if !CPU_MICROMIPS - select ARCH_HAVE_CUSTOM_GPIO_H select HAVE_FUNCTION_TRACER select HAVE_DYNAMIC_FTRACE select HAVE_FTRACE_MCOUNT_RECORD diff --git a/arch/mips/alchemy/Kconfig b/arch/mips/alchemy/Kconfig index b9628983d6209..7fa24881b708c 100644 --- a/arch/mips/alchemy/Kconfig +++ b/arch/mips/alchemy/Kconfig @@ -6,13 +6,6 @@ config ALCHEMY_GPIOINT_AU1000 config ALCHEMY_GPIOINT_AU1300 bool -# select this in your board config if you don't want to use the gpio -# namespace as documented in the manuals. In this case however you need -# to create the necessary gpio_* functions in your board code/headers! -# see arch/mips/include/asm/mach-au1x00/gpio.h for more information. -config ALCHEMY_GPIO_INDIRECT - def_bool n - choice prompt "Machine type" depends on MIPS_ALCHEMY diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c index acf9a2a37f5a0..79efe4c6e636a 100644 --- a/arch/mips/alchemy/board-gpr.c +++ b/arch/mips/alchemy/board-gpr.c @@ -34,6 +34,7 @@ #include #include #include +#include #include const char *get_system_type(void) diff --git a/arch/mips/alchemy/board-mtx1.c b/arch/mips/alchemy/board-mtx1.c index 1e3b102389ef5..85bb75669b0d5 100644 --- a/arch/mips/alchemy/board-mtx1.c +++ b/arch/mips/alchemy/board-mtx1.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/arch/mips/alchemy/common/Makefile b/arch/mips/alchemy/common/Makefile index f64744f3b59f7..23800b8e67e5e 100644 --- a/arch/mips/alchemy/common/Makefile +++ b/arch/mips/alchemy/common/Makefile @@ -5,10 +5,5 @@ # Makefile for the Alchemy Au1xx0 CPUs, generic files. # -obj-y += prom.o time.o clock.o platform.o power.o \ +obj-y += prom.o time.o clock.o platform.o power.o gpiolib.o \ setup.o sleeper.o dma.o dbdma.o vss.o irq.o usb.o - -# optional gpiolib support -ifeq ($(CONFIG_ALCHEMY_GPIO_INDIRECT),) - obj-$(CONFIG_GPIOLIB) += gpiolib.o -endif diff --git a/arch/mips/alchemy/devboards/db1000.c b/arch/mips/alchemy/devboards/db1000.c index 001102e197f19..bdeed9d13c6fe 100644 --- a/arch/mips/alchemy/devboards/db1000.c +++ b/arch/mips/alchemy/devboards/db1000.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1300.c b/arch/mips/alchemy/devboards/db1300.c index 1c64fdbe4c813..b58077008a538 100644 --- a/arch/mips/alchemy/devboards/db1300.c +++ b/arch/mips/alchemy/devboards/db1300.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/db1550.c b/arch/mips/alchemy/devboards/db1550.c index 0fd5177e35ab2..5740bcfdfc7f6 100644 --- a/arch/mips/alchemy/devboards/db1550.c +++ b/arch/mips/alchemy/devboards/db1550.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/alchemy/devboards/pm.c b/arch/mips/alchemy/devboards/pm.c index bfeb8f3c0be66..93024dc6b314d 100644 --- a/arch/mips/alchemy/devboards/pm.c +++ b/arch/mips/alchemy/devboards/pm.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/mips/ar7/gpio.c b/arch/mips/ar7/gpio.c index d8dbd8f0c1d29..f4930456eb8e8 100644 --- a/arch/mips/ar7/gpio.c +++ b/arch/mips/ar7/gpio.c @@ -21,7 +21,10 @@ #include #include -#include +#include + +#define AR7_GPIO_MAX 32 +#define TITAN_GPIO_MAX 51 struct ar7_gpio_chip { void __iomem *regs; diff --git a/arch/mips/ar7/platform.c b/arch/mips/ar7/platform.c index be9ff1673ded7..462a252ea6e62 100644 --- a/arch/mips/ar7/platform.c +++ b/arch/mips/ar7/platform.c @@ -39,7 +39,6 @@ #include #include -#include #include /***************************************************************************** diff --git a/arch/mips/ar7/setup.c b/arch/mips/ar7/setup.c index 820b7a313d9bf..7bb9a670bb735 100644 --- a/arch/mips/ar7/setup.c +++ b/arch/mips/ar7/setup.c @@ -23,7 +23,6 @@ #include #include #include -#include static void ar7_machine_restart(char *command) { diff --git a/arch/mips/include/asm/gpio.h b/arch/mips/include/asm/gpio.h deleted file mode 100644 index 06e46faf862d5..0000000000000 --- a/arch/mips/include/asm/gpio.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_MIPS_GPIO_H -#define __ASM_MIPS_GPIO_H - -#include - -#endif /* __ASM_MIPS_GPIO_H */ diff --git a/arch/mips/include/asm/mach-ar7/ar7.h b/arch/mips/include/asm/mach-ar7/ar7.h index a47ea0c852483..468cbd61b9067 100644 --- a/arch/mips/include/asm/mach-ar7/ar7.h +++ b/arch/mips/include/asm/mach-ar7/ar7.h @@ -203,4 +203,8 @@ static inline void ar7_device_off(u32 bit) int __init ar7_gpio_init(void); void __init ar7_init_clocks(void); +/* Board specific GPIO functions */ +int ar7_gpio_enable(unsigned gpio); +int ar7_gpio_disable(unsigned gpio); + #endif /* __AR7_H__ */ diff --git a/arch/mips/include/asm/mach-ar7/gpio.h b/arch/mips/include/asm/mach-ar7/gpio.h deleted file mode 100644 index c177cd1eed258..0000000000000 --- a/arch/mips/include/asm/mach-ar7/gpio.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (C) 2007-2009 Florian Fainelli - * - * 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. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __AR7_GPIO_H__ -#define __AR7_GPIO_H__ - -#include - -#define AR7_GPIO_MAX 32 -#define TITAN_GPIO_MAX 51 -#define NR_BUILTIN_GPIO TITAN_GPIO_MAX - -#define gpio_to_irq(gpio) -1 - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -/* Board specific GPIO functions */ -int ar7_gpio_enable(unsigned gpio); -int ar7_gpio_disable(unsigned gpio); - -#include - -#endif diff --git a/arch/mips/include/asm/mach-ath25/gpio.h b/arch/mips/include/asm/mach-ath25/gpio.h deleted file mode 100644 index 713564b8e8ef9..0000000000000 --- a/arch/mips/include/asm/mach-ath25/gpio.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __ASM_MACH_ATH25_GPIO_H -#define __ASM_MACH_ATH25_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -static inline int irq_to_gpio(unsigned irq) -{ - return -EINVAL; -} - -#endif /* __ASM_MACH_ATH25_GPIO_H */ diff --git a/arch/mips/include/asm/mach-ath79/gpio.h b/arch/mips/include/asm/mach-ath79/gpio.h deleted file mode 100644 index 60dcb62785b45..0000000000000 --- a/arch/mips/include/asm/mach-ath79/gpio.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Atheros AR71XX/AR724X/AR913X GPIO API definitions - * - * Copyright (C) 2008-2010 Gabor Juhos - * Copyright (C) 2008 Imre Kaloz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - */ - -#ifndef __ASM_MACH_ATH79_GPIO_H -#define __ASM_MACH_ATH79_GPIO_H - -#define ARCH_NR_GPIOS 64 -#include - -int gpio_to_irq(unsigned gpio); -int irq_to_gpio(unsigned irq); -int gpio_get_value(unsigned gpio); -void gpio_set_value(unsigned gpio, int value); - -#define gpio_cansleep __gpio_cansleep - -#endif /* __ASM_MACH_ATH79_GPIO_H */ diff --git a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h index 9785e4ebb450f..adde1fa5097e6 100644 --- a/arch/mips/include/asm/mach-au1x00/gpio-au1000.h +++ b/arch/mips/include/asm/mach-au1x00/gpio-au1000.h @@ -266,6 +266,17 @@ static inline int alchemy_gpio1_to_irq(int gpio) return -ENXIO; } +/* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before + * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this + * register enables use of GPIOs as wake source. + */ +static inline void alchemy_gpio1_input_enable(void) +{ + void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); + __raw_writel(0, base + 0x110); /* the write op is key */ + wmb(); +} + /* * GPIO2 block macros for common linux GPIO functions. The 'gpio' * parameter must be in range of ALCHEMY_GPIO2_BASE..ALCHEMY_GPIO2_MAX. @@ -518,141 +529,4 @@ static inline int alchemy_irq_to_gpio(int irq) return -ENXIO; } -/**********************************************************************/ - -/* Linux gpio framework integration. - * - * 4 use cases of Au1000-Au1200 GPIOS: - *(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: - * Board must register gpiochips. - *(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: - * 2 (1 for Au1000) gpio_chips are registered. - * - *(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: - * the boards' gpio.h must provide the linux gpio wrapper functions, - * - *(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: - * inlinable gpio functions are provided which enable access to the - * Au1000 gpios only by using the numbers straight out of the data- - * sheets. - - * Cases 1 and 3 are intended for boards which want to provide their own - * GPIO namespace and -operations (i.e. for example you have 8 GPIOs - * which are in part provided by spare Au1000 GPIO pins and in part by - * an external FPGA but you still want them to be accssible in linux - * as gpio0-7. The board can of course use the alchemy_gpioX_* functions - * as required). - */ - -#ifndef CONFIG_GPIOLIB - -#ifdef CONFIG_ALCHEMY_GPIOINT_AU1000 - -#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (4) */ - -static inline int gpio_direction_input(int gpio) -{ - return alchemy_gpio_direction_input(gpio); -} - -static inline int gpio_direction_output(int gpio, int v) -{ - return alchemy_gpio_direction_output(gpio, v); -} - -static inline int gpio_get_value(int gpio) -{ - return alchemy_gpio_get_value(gpio); -} - -static inline void gpio_set_value(int gpio, int v) -{ - alchemy_gpio_set_value(gpio, v); -} - -static inline int gpio_get_value_cansleep(unsigned gpio) -{ - return gpio_get_value(gpio); -} - -static inline void gpio_set_value_cansleep(unsigned gpio, int value) -{ - gpio_set_value(gpio, value); -} - -static inline int gpio_is_valid(int gpio) -{ - return alchemy_gpio_is_valid(gpio); -} - -static inline int gpio_cansleep(int gpio) -{ - return alchemy_gpio_cansleep(gpio); -} - -static inline int gpio_to_irq(int gpio) -{ - return alchemy_gpio_to_irq(gpio); -} - -static inline int irq_to_gpio(int irq) -{ - return alchemy_irq_to_gpio(irq); -} - -static inline int gpio_request(unsigned gpio, const char *label) -{ - return 0; -} - -static inline int gpio_request_one(unsigned gpio, - unsigned long flags, const char *label) -{ - return 0; -} - -static inline int gpio_request_array(struct gpio *array, size_t num) -{ - return 0; -} - -static inline void gpio_free(unsigned gpio) -{ -} - -static inline void gpio_free_array(struct gpio *array, size_t num) -{ -} - -static inline int gpio_set_debounce(unsigned gpio, unsigned debounce) -{ - return -ENOSYS; -} - -static inline int gpio_export(unsigned gpio, bool direction_may_change) -{ - return -ENOSYS; -} - -static inline int gpio_export_link(struct device *dev, const char *name, - unsigned gpio) -{ - return -ENOSYS; -} - -static inline int gpio_sysfs_set_active_low(unsigned gpio, int value) -{ - return -ENOSYS; -} - -static inline void gpio_unexport(unsigned gpio) -{ -} - -#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ - -#endif /* CONFIG_ALCHEMY_GPIOINT_AU1000 */ - -#endif /* !CONFIG_GPIOLIB */ - #endif /* _ALCHEMY_GPIO_AU1000_H_ */ diff --git a/arch/mips/include/asm/mach-au1x00/gpio.h b/arch/mips/include/asm/mach-au1x00/gpio.h deleted file mode 100644 index 22e7ff17fc482..0000000000000 --- a/arch/mips/include/asm/mach-au1x00/gpio.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Alchemy GPIO support. - * - * With CONFIG_GPIOLIB=y different types of on-chip GPIO can be supported within - * the same kernel image. - * With CONFIG_GPIOLIB=n, your board must select ALCHEMY_GPIOINT_AU1XXX for the - * appropriate CPU type (AU1000 currently). - */ - -#ifndef _ALCHEMY_GPIO_H_ -#define _ALCHEMY_GPIO_H_ - -#include -#include -#include - -/* On Au1000, Au1500 and Au1100 GPIOs won't work as inputs before - * SYS_PININPUTEN is written to at least once. On Au1550/Au1200/Au1300 this - * register enables use of GPIOs as wake source. - */ -static inline void alchemy_gpio1_input_enable(void) -{ - void __iomem *base = (void __iomem *)KSEG1ADDR(AU1000_SYS_PHYS_ADDR); - __raw_writel(0, base + 0x110); /* the write op is key */ - wmb(); -} - - -/* Linux gpio framework integration. -* -* 4 use cases of Alchemy GPIOS: -*(1) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=y: -* Board must register gpiochips. -*(2) GPIOLIB=y, ALCHEMY_GPIO_INDIRECT=n: -* A gpiochip for the 75 GPIOs is registered. -* -*(3) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=y: -* the boards' gpio.h must provide the linux gpio wrapper functions, -* -*(4) GPIOLIB=n, ALCHEMY_GPIO_INDIRECT=n: -* inlinable gpio functions are provided which enable access to the -* Au1300 gpios only by using the numbers straight out of the data- -* sheets. - -* Cases 1 and 3 are intended for boards which want to provide their own -* GPIO namespace and -operations (i.e. for example you have 8 GPIOs -* which are in part provided by spare Au1300 GPIO pins and in part by -* an external FPGA but you still want them to be accssible in linux -* as gpio0-7. The board can of course use the alchemy_gpioX_* functions -* as required). -*/ - -#ifdef CONFIG_GPIOLIB - -/* wraps the cpu-dependent irq_to_gpio functions */ -/* FIXME: gpiolib needs an irq_to_gpio hook */ -static inline int __au_irq_to_gpio(unsigned int irq) -{ - switch (alchemy_get_cputype()) { - case ALCHEMY_CPU_AU1000...ALCHEMY_CPU_AU1200: - return alchemy_irq_to_gpio(irq); - case ALCHEMY_CPU_AU1300: - return au1300_irq_to_gpio(irq); - } - return -EINVAL; -} - - -/* using gpiolib to provide up to 2 gpio_chips for on-chip gpios */ -#ifndef CONFIG_ALCHEMY_GPIO_INDIRECT /* case (2) */ - -/* get everything through gpiolib */ -#define gpio_to_irq __gpio_to_irq -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define irq_to_gpio __au_irq_to_gpio - -#include - -#endif /* !CONFIG_ALCHEMY_GPIO_INDIRECT */ - - -#endif /* CONFIG_GPIOLIB */ - -#endif /* _ALCHEMY_GPIO_H_ */ diff --git a/arch/mips/include/asm/mach-bcm47xx/gpio.h b/arch/mips/include/asm/mach-bcm47xx/gpio.h deleted file mode 100644 index 90daefa24a4dc..0000000000000 --- a/arch/mips/include/asm/mach-bcm47xx/gpio.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __ASM_MIPS_MACH_BCM47XX_GPIO_H -#define __ASM_MIPS_MACH_BCM47XX_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -static inline int irq_to_gpio(unsigned int irq) -{ - return -EINVAL; -} - -#endif diff --git a/arch/mips/include/asm/mach-bcm63xx/gpio.h b/arch/mips/include/asm/mach-bcm63xx/gpio.h deleted file mode 100644 index 1eb534de8e3b1..0000000000000 --- a/arch/mips/include/asm/mach-bcm63xx/gpio.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __ASM_MIPS_MACH_BCM63XX_GPIO_H -#define __ASM_MIPS_MACH_BCM63XX_GPIO_H - -#include - -#define gpio_to_irq(gpio) -1 - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -#include - -#endif /* __ASM_MIPS_MACH_BCM63XX_GPIO_H */ diff --git a/arch/mips/include/asm/mach-cavium-octeon/gpio.h b/arch/mips/include/asm/mach-cavium-octeon/gpio.h deleted file mode 100644 index 34e9f7aabab44..0000000000000 --- a/arch/mips/include/asm/mach-cavium-octeon/gpio.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_MACH_CAVIUM_OCTEON_GPIO_H -#define __ASM_MACH_CAVIUM_OCTEON_GPIO_H - -#ifdef CONFIG_GPIOLIB -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#else -int gpio_request(unsigned gpio, const char *label); -void gpio_free(unsigned gpio); -int gpio_direction_input(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -void gpio_set_value(unsigned gpio, int value); -#endif - -#include - -#define gpio_to_irq __gpio_to_irq - -#endif /* __ASM_MACH_GENERIC_GPIO_H */ diff --git a/arch/mips/include/asm/mach-generic/gpio.h b/arch/mips/include/asm/mach-generic/gpio.h deleted file mode 100644 index b4e70208da643..0000000000000 --- a/arch/mips/include/asm/mach-generic/gpio.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_MACH_GENERIC_GPIO_H -#define __ASM_MACH_GENERIC_GPIO_H - -#ifdef CONFIG_GPIOLIB -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#else -int gpio_request(unsigned gpio, const char *label); -void gpio_free(unsigned gpio); -int gpio_direction_input(unsigned gpio); -int gpio_direction_output(unsigned gpio, int value); -int gpio_get_value(unsigned gpio); -void gpio_set_value(unsigned gpio, int value); -#endif -int gpio_to_irq(unsigned gpio); -int irq_to_gpio(unsigned irq); - -#include /* cansleep wrappers */ - -#endif /* __ASM_MACH_GENERIC_GPIO_H */ diff --git a/arch/mips/include/asm/mach-jz4740/gpio.h b/arch/mips/include/asm/mach-jz4740/gpio.h index eaacba79cf18c..bf8c3e1860e71 100644 --- a/arch/mips/include/asm/mach-jz4740/gpio.h +++ b/arch/mips/include/asm/mach-jz4740/gpio.h @@ -73,8 +73,6 @@ int jz_gpio_port_direction_output(int port, uint32_t mask); void jz_gpio_port_set_value(int port, uint32_t value, uint32_t mask); uint32_t jz_gpio_port_get_value(int port, uint32_t mask); -#include - #define JZ_GPIO_PORTA(x) ((x) + 32 * 0) #define JZ_GPIO_PORTB(x) ((x) + 32 * 1) #define JZ_GPIO_PORTC(x) ((x) + 32 * 2) diff --git a/arch/mips/include/asm/mach-lantiq/gpio.h b/arch/mips/include/asm/mach-lantiq/gpio.h deleted file mode 100644 index 9ba1caebca5f5..0000000000000 --- a/arch/mips/include/asm/mach-lantiq/gpio.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ASM_MIPS_MACH_LANTIQ_GPIO_H -#define __ASM_MIPS_MACH_LANTIQ_GPIO_H - -#define gpio_to_irq __gpio_to_irq - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value - -#define gpio_cansleep __gpio_cansleep - -#include - -#endif diff --git a/arch/mips/include/asm/mach-loongson64/gpio.h b/arch/mips/include/asm/mach-loongson64/gpio.h deleted file mode 100644 index b3b216904a9a8..0000000000000 --- a/arch/mips/include/asm/mach-loongson64/gpio.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Loongson GPIO Support - * - * Copyright (c) 2008 Richard Liu, STMicroelectronics - * Copyright (c) 2008-2010 Arnaud Patard - * Copyright (c) 2014 Huacai Chen - * - * 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 __LOONGSON_GPIO_H -#define __LOONGSON_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep - -/* The chip can do interrupt - * but it has not been tested and doc not clear - */ -static inline int gpio_to_irq(int gpio) -{ - return -EINVAL; -} - -static inline int irq_to_gpio(int gpio) -{ - return -EINVAL; -} - -#endif /* __LOONGSON_GPIO_H */ diff --git a/arch/mips/include/asm/mach-pistachio/gpio.h b/arch/mips/include/asm/mach-pistachio/gpio.h deleted file mode 100644 index 6c1649c27b8d2..0000000000000 --- a/arch/mips/include/asm/mach-pistachio/gpio.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Pistachio IRQ setup - * - * Copyright (C) 2014 Google, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ - -#ifndef __ASM_MACH_PISTACHIO_GPIO_H -#define __ASM_MACH_PISTACHIO_GPIO_H - -#include - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep -#define gpio_to_irq __gpio_to_irq - -#endif /* __ASM_MACH_PISTACHIO_GPIO_H */ diff --git a/arch/mips/include/asm/mach-rc32434/gpio.h b/arch/mips/include/asm/mach-rc32434/gpio.h index 4dee0a34250c3..db211212ce79e 100644 --- a/arch/mips/include/asm/mach-rc32434/gpio.h +++ b/arch/mips/include/asm/mach-rc32434/gpio.h @@ -13,18 +13,6 @@ #ifndef _RC32434_GPIO_H_ #define _RC32434_GPIO_H_ -#include -#include - -#define NR_BUILTIN_GPIO 32 - -#define gpio_get_value __gpio_get_value -#define gpio_set_value __gpio_set_value -#define gpio_cansleep __gpio_cansleep - -#define gpio_to_irq(gpio) (8 + 4 * 32 + gpio) -#define irq_to_gpio(irq) (irq - (8 + 4 * 32)) - struct rb532_gpio_reg { u32 gpiofunc; /* GPIO Function Register * gpiofunc[x]==0 bit = gpio diff --git a/arch/mips/jz4740/gpio.c b/arch/mips/jz4740/gpio.c index 77df1602f8189..6cd69fdaa1c5f 100644 --- a/arch/mips/jz4740/gpio.c +++ b/arch/mips/jz4740/gpio.c @@ -231,6 +231,13 @@ static int jz_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) return 0; } +static int jz_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + struct jz_gpio_chip *jz_gpio = gpio_chip_to_jz_gpio_chip(chip); + + return jz_gpio->irq_base + gpio; +} + int jz_gpio_port_direction_input(int port, uint32_t mask) { writel(mask, GPIO_TO_REG(port, JZ_REG_GPIO_DIRECTION_CLEAR)); @@ -262,18 +269,6 @@ uint32_t jz_gpio_port_get_value(int port, uint32_t mask) } EXPORT_SYMBOL(jz_gpio_port_get_value); -int gpio_to_irq(unsigned gpio) -{ - return JZ4740_IRQ_GPIO(0) + gpio; -} -EXPORT_SYMBOL_GPL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - return irq - JZ4740_IRQ_GPIO(0); -} -EXPORT_SYMBOL_GPL(irq_to_gpio); - #define IRQ_TO_BIT(irq) BIT(irq_to_gpio(irq) & 0x1f) static void jz_gpio_check_trigger_both(struct jz_gpio_chip *chip, unsigned int irq) @@ -403,6 +398,7 @@ static int jz_gpio_irq_set_wake(struct irq_data *data, unsigned int on) .get = jz_gpio_get_value, \ .direction_output = jz_gpio_direction_output, \ .direction_input = jz_gpio_direction_input, \ + .to_irq = jz_gpio_to_irq, \ .base = JZ4740_GPIO_BASE_ ## _bank, \ .ngpio = JZ4740_GPIO_NUM_ ## _bank, \ }, \ diff --git a/arch/mips/pci/pci-lantiq.c b/arch/mips/pci/pci-lantiq.c index c5347d99cf3a2..6a15dbd085aa8 100644 --- a/arch/mips/pci/pci-lantiq.c +++ b/arch/mips/pci/pci-lantiq.c @@ -20,7 +20,6 @@ #include #include -#include #include #include diff --git a/arch/mips/rb532/devices.c b/arch/mips/rb532/devices.c index e31e8cdcb296b..9bd7a2de0765f 100644 --- a/arch/mips/rb532/devices.c +++ b/arch/mips/rb532/devices.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c index 5aa3df8530826..650d5d39f34d9 100644 --- a/arch/mips/rb532/gpio.c +++ b/arch/mips/rb532/gpio.c @@ -140,6 +140,11 @@ static int rb532_gpio_direction_output(struct gpio_chip *chip, return 0; } +static int rb532_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) +{ + return 8 + 4 * 32 + gpio; +} + static struct rb532_gpio_chip rb532_gpio_chip[] = { [0] = { .chip = { @@ -148,6 +153,7 @@ static struct rb532_gpio_chip rb532_gpio_chip[] = { .direction_output = rb532_gpio_direction_output, .get = rb532_gpio_get, .set = rb532_gpio_set, + .to_irq = rb532_gpio_to_irq, .base = 0, .ngpio = 32, }, diff --git a/arch/mips/txx9/generic/setup.c b/arch/mips/txx9/generic/setup.c index 2791b8641df64..9d9962ab7d25c 100644 --- a/arch/mips/txx9/generic/setup.c +++ b/arch/mips/txx9/generic/setup.c @@ -117,22 +117,6 @@ void clk_put(struct clk *clk) } EXPORT_SYMBOL(clk_put); -/* GPIO support */ - -#ifdef CONFIG_GPIOLIB -int gpio_to_irq(unsigned gpio) -{ - return -EINVAL; -} -EXPORT_SYMBOL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - return -EINVAL; -} -EXPORT_SYMBOL(irq_to_gpio); -#endif - #define BOARD_VEC(board) extern struct txx9_board_vec board; #include #undef BOARD_VEC diff --git a/drivers/ata/pata_rb532_cf.c b/drivers/ata/pata_rb532_cf.c index 6d08446b877c9..12fe0f3bb7e9b 100644 --- a/drivers/ata/pata_rb532_cf.c +++ b/drivers/ata/pata_rb532_cf.c @@ -27,12 +27,11 @@ #include #include #include +#include #include #include -#include - #define DRV_NAME "pata-rb532-cf" #define DRV_VERSION "0.1.0" #define DRV_DESC "PATA driver for RouterBOARD 532 Compact Flash" diff --git a/drivers/gpio/gpio-ath79.c b/drivers/gpio/gpio-ath79.c index c3c92eb56e040..03b995304ad68 100644 --- a/drivers/gpio/gpio-ath79.c +++ b/drivers/gpio/gpio-ath79.c @@ -202,35 +202,3 @@ static struct platform_driver ath79_gpio_driver = { }; module_platform_driver(ath79_gpio_driver); - -int gpio_get_value(unsigned gpio) -{ - if (gpio < ath79_gpio_count) - return __ath79_gpio_get_value(gpio); - - return __gpio_get_value(gpio); -} -EXPORT_SYMBOL(gpio_get_value); - -void gpio_set_value(unsigned gpio, int value) -{ - if (gpio < ath79_gpio_count) - __ath79_gpio_set_value(gpio, value); - else - __gpio_set_value(gpio, value); -} -EXPORT_SYMBOL(gpio_set_value); - -int gpio_to_irq(unsigned gpio) -{ - /* FIXME */ - return -EINVAL; -} -EXPORT_SYMBOL(gpio_to_irq); - -int irq_to_gpio(unsigned irq) -{ - /* FIXME */ - return -EINVAL; -} -EXPORT_SYMBOL(irq_to_gpio); diff --git a/drivers/input/misc/rb532_button.c b/drivers/input/misc/rb532_button.c index e956e81cd4e6d..62c5814c796bc 100644 --- a/drivers/input/misc/rb532_button.c +++ b/drivers/input/misc/rb532_button.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c index dd94300435365..cba3d9fcb4653 100644 --- a/drivers/net/ethernet/ti/cpmac.c +++ b/drivers/net/ethernet/ti/cpmac.c @@ -41,6 +41,8 @@ #include #include +#include + MODULE_AUTHOR("Eugene Konev "); MODULE_DESCRIPTION("TI AR7 ethernet driver (CPMAC)"); MODULE_LICENSE("GPL"); -- GitLab From 325f0a1833c41d2d399fda161866923b72592cc9 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Sat, 1 Aug 2015 17:44:20 +0530 Subject: [PATCH 6173/7006] MIPS: Netlogic: Use chip_data for irq_chip methods Update mips/netlogic/common/irq.c and mips/pci/msi-xlp.c to use chip_data to store interrupt controller data pointer. It uses handler_data now, and that causes errors when an API (like the GPIO subsystem) tries to use the handler data. Signed-off-by: Kamlakant Patel Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10817/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/common/irq.c | 12 ++++++------ arch/mips/pci/msi-xlp.c | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/arch/mips/netlogic/common/irq.c b/arch/mips/netlogic/common/irq.c index 5f5d18b0e94d8..3660dc67d544f 100644 --- a/arch/mips/netlogic/common/irq.c +++ b/arch/mips/netlogic/common/irq.c @@ -87,7 +87,7 @@ struct nlm_pic_irq { static void xlp_pic_enable(struct irq_data *d) { unsigned long flags; - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); BUG_ON(!pd); spin_lock_irqsave(&pd->node->piclock, flags); @@ -97,7 +97,7 @@ static void xlp_pic_enable(struct irq_data *d) static void xlp_pic_disable(struct irq_data *d) { - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); unsigned long flags; BUG_ON(!pd); @@ -108,7 +108,7 @@ static void xlp_pic_disable(struct irq_data *d) static void xlp_pic_mask_ack(struct irq_data *d) { - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); clear_c0_eimr(pd->picirq); ack_c0_eirr(pd->picirq); @@ -116,7 +116,7 @@ static void xlp_pic_mask_ack(struct irq_data *d) static void xlp_pic_unmask(struct irq_data *d) { - struct nlm_pic_irq *pd = irq_data_get_irq_handler_data(d); + struct nlm_pic_irq *pd = irq_data_get_irq_chip_data(d); BUG_ON(!pd); @@ -193,7 +193,7 @@ void nlm_setup_pic_irq(int node, int picirq, int irq, int irt) pic_data->picirq = picirq; pic_data->node = nlm_get_node(node); irq_set_chip_and_handler(xirq, &xlp_pic, handle_level_irq); - irq_set_handler_data(xirq, pic_data); + irq_set_chip_data(xirq, pic_data); } void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) @@ -202,7 +202,7 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *)) int xirq; xirq = nlm_irq_to_xirq(node, irq); - pic_data = irq_get_handler_data(xirq); + pic_data = irq_get_chip_data(xirq); if (WARN_ON(!pic_data)) return; pic_data->extra_ack = xack; diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c index 3407495fcbe2f..bb14335f804b4 100644 --- a/arch/mips/pci/msi-xlp.c +++ b/arch/mips/pci/msi-xlp.c @@ -131,7 +131,7 @@ struct xlp_msi_data { */ static void xlp_msi_enable(struct irq_data *d) { - struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); unsigned long flags; int vec; @@ -148,7 +148,7 @@ static void xlp_msi_enable(struct irq_data *d) static void xlp_msi_disable(struct irq_data *d) { - struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); unsigned long flags; int vec; @@ -165,7 +165,7 @@ static void xlp_msi_disable(struct irq_data *d) static void xlp_msi_mask_ack(struct irq_data *d) { - struct xlp_msi_data *md = irq_data_get_irq_handler_data(d); + struct xlp_msi_data *md = irq_data_get_irq_chip_data(d); int link, vec; link = nlm_irq_msilink(d->irq); @@ -211,7 +211,7 @@ static void xlp_msix_mask_ack(struct irq_data *d) msixvec = nlm_irq_msixvec(d->irq); link = nlm_irq_msixlink(msixvec); pci_msi_mask_irq(d); - md = irq_data_get_irq_handler_data(d); + md = irq_data_get_irq_chip_data(d); /* Ack MSI on bridge */ if (cpu_is_xlp9xx()) { @@ -302,7 +302,7 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link, /* Get MSI data for the link */ lirq = PIC_PCIE_LINK_MSI_IRQ(link); xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); - md = irq_get_handler_data(xirq); + md = irq_get_chip_data(xirq); msiaddr = MSI_LINK_ADDR(node, link); spin_lock_irqsave(&md->msi_lock, flags); @@ -409,7 +409,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link, /* Get MSI data for the link */ lirq = PIC_PCIE_MSIX_IRQ(link); xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); - md = irq_get_handler_data(xirq); + md = irq_get_chip_data(xirq); msixaddr = MSIX_LINK_ADDR(node, link); spin_lock_irqsave(&md->msi_lock, flags); @@ -485,7 +485,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) { irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq); - irq_set_handler_data(i, md); + irq_set_chip_data(i, md); } for (i = 0; i < XLP_MSIXVEC_PER_LINK ; i++) { @@ -508,7 +508,7 @@ void __init xlp_init_node_msi_irqs(int node, int link) /* Initialize MSI-X extended irq space for the link */ irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i)); irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq); - irq_set_handler_data(irq, md); + irq_set_chip_data(irq, md); } } @@ -520,7 +520,7 @@ void nlm_dispatch_msi(int node, int lirq) link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE; irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0)); - md = irq_get_handler_data(irqbase); + md = irq_get_chip_data(irqbase); if (cpu_is_xlp9xx()) status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSI_STATUS) & md->msi_enabled_mask; @@ -550,7 +550,7 @@ void nlm_dispatch_msix(int node, int lirq) link = lirq - PIC_PCIE_MSIX_IRQ_BASE; irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0)); - md = irq_get_handler_data(irqbase); + md = irq_get_chip_data(irqbase); if (cpu_is_xlp9xx()) status = nlm_read_reg(md->lnkbase, PCIE_9XX_MSIX_STATUSX(link)); else -- GitLab From a8a747764a970fc4c4f39f554c7dc08a4ca67db8 Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Sat, 1 Aug 2015 17:44:21 +0530 Subject: [PATCH 6174/7006] MIPS: Netlogic: add device tree entry for XLP GPIO Add GPIO entries to the Netlogic XLP device tree files. Signed-off-by: Kamlakant Patel Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10819/ Signed-off-by: Ralf Baechle --- arch/mips/boot/dts/netlogic/xlp_evp.dts | 12 ++++++++++++ arch/mips/boot/dts/netlogic/xlp_fvp.dts | 12 ++++++++++++ arch/mips/boot/dts/netlogic/xlp_gvp.dts | 11 +++++++++++ arch/mips/boot/dts/netlogic/xlp_rvp.dts | 11 +++++++++++ arch/mips/boot/dts/netlogic/xlp_svp.dts | 12 ++++++++++++ 5 files changed, 58 insertions(+) diff --git a/arch/mips/boot/dts/netlogic/xlp_evp.dts b/arch/mips/boot/dts/netlogic/xlp_evp.dts index 89ad04808c024..ec16ec2d8d027 100644 --- a/arch/mips/boot/dts/netlogic/xlp_evp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_evp.dts @@ -110,6 +110,18 @@ read-only; }; }; + + gpio: xlp_gpio@34100 { + compatible = "netlogic,xlp832-gpio"; + reg = <0 0x34100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_fvp.dts b/arch/mips/boot/dts/netlogic/xlp_fvp.dts index 63e62b7bd7589..4bcebe641d8e9 100644 --- a/arch/mips/boot/dts/netlogic/xlp_fvp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_fvp.dts @@ -110,6 +110,18 @@ read-only; }; }; + + gpio: xlp_gpio@34100 { + compatible = "netlogic,xlp208-gpio"; + reg = <0 0x34100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_gvp.dts b/arch/mips/boot/dts/netlogic/xlp_gvp.dts index bb4ecd1d47fc2..b3ccb82ad7e4c 100644 --- a/arch/mips/boot/dts/netlogic/xlp_gvp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_gvp.dts @@ -69,6 +69,17 @@ }; }; + gpio: xlp_gpio@114100 { + compatible = "netlogic,xlp980-gpio"; + reg = <0 0x114100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_rvp.dts b/arch/mips/boot/dts/netlogic/xlp_rvp.dts index 7188aed2ea2ed..3783639a318aa 100644 --- a/arch/mips/boot/dts/netlogic/xlp_rvp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_rvp.dts @@ -69,6 +69,17 @@ }; }; + gpio: xlp_gpio@114100 { + compatible = "netlogic,xlp532-gpio"; + reg = <0 0x114100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { diff --git a/arch/mips/boot/dts/netlogic/xlp_svp.dts b/arch/mips/boot/dts/netlogic/xlp_svp.dts index 1ebd00edaacc4..44d6640c14412 100644 --- a/arch/mips/boot/dts/netlogic/xlp_svp.dts +++ b/arch/mips/boot/dts/netlogic/xlp_svp.dts @@ -110,6 +110,18 @@ read-only; }; }; + + gpio: xlp_gpio@34100 { + compatible = "netlogic,xlp316-gpio"; + reg = <0 0x34100 0x1000>; + #gpio-cells = <2>; + gpio-controller; + + #interrupt-cells = <2>; + interrupt-parent = <&pic>; + interrupts = <39>; + interrupt-controller; + }; }; chosen { -- GitLab From 079e31600786b1ef8cab15ac6345605ad9150daf Mon Sep 17 00:00:00 2001 From: Kamlakant Patel Date: Sat, 1 Aug 2015 17:44:22 +0530 Subject: [PATCH 6175/7006] MIPS: Netlogic: set ARCH_REQUIRE_GPIOLIB for XLP platform This is needed to enable GPIO framework support for Netlogic XLP platform. Signed-off-by: Kamlakant Patel Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10818/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 06c5957917d3a..7e182424f1196 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -898,6 +898,7 @@ config NLM_XLP_BOARD select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_64BIT_KERNEL select ARCH_PHYS_ADDR_T_64BIT + select ARCH_REQUIRE_GPIOLIB select SYS_SUPPORTS_BIG_ENDIAN select SYS_SUPPORTS_LITTLE_ENDIAN select SYS_SUPPORTS_HIGHMEM -- GitLab From 8c576912e4708144cbaa28228cc910746f39bafd Mon Sep 17 00:00:00 2001 From: Subhendu Sekhar Behera Date: Sat, 1 Aug 2015 17:44:23 +0530 Subject: [PATCH 6176/7006] MIPS: Netlogic: NAND IRQ mapping Add NAND IRQ mapping for XLP9xx processor. Signed-off-by: Subhendu Sekhar Behera Signed-off-by: Jayachandran C Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10820/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/xlp/nlm_hal.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/netlogic/xlp/nlm_hal.c b/arch/mips/netlogic/xlp/nlm_hal.c index a8f4144a0297f..80ec929747c37 100644 --- a/arch/mips/netlogic/xlp/nlm_hal.c +++ b/arch/mips/netlogic/xlp/nlm_hal.c @@ -91,6 +91,8 @@ static int xlp9xx_irq_to_irt(int irq) return 134; case PIC_SATA_IRQ: return 143; + case PIC_NAND_IRQ: + return 151; case PIC_SPI_IRQ: return 152; case PIC_MMC_IRQ: -- GitLab From e3b28831c18c6c95c51b6bb717fa116d2b658ba9 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Tue, 28 Jul 2015 20:37:43 +0200 Subject: [PATCH 6177/7006] MIPS: Set trap_no field in thread_struct on exception. This reverts commit 7281cd22973008a782860e48ed8d85d00204168c and adds actual functionality to use the field. --- arch/mips/include/asm/processor.h | 2 ++ arch/mips/kernel/asm-offsets.c | 1 + arch/mips/kernel/traps.c | 28 ++++++++++++++-------------- arch/mips/mm/fault.c | 8 ++++---- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/arch/mips/include/asm/processor.h b/arch/mips/include/asm/processor.h index 9b3b48e21c221..59ee6dcf6eed9 100644 --- a/arch/mips/include/asm/processor.h +++ b/arch/mips/include/asm/processor.h @@ -275,6 +275,7 @@ struct thread_struct { unsigned long cp0_badvaddr; /* Last user fault */ unsigned long cp0_baduaddr; /* Last kernel fault accessing USEG */ unsigned long error_code; + unsigned long trap_nr; #ifdef CONFIG_CPU_CAVIUM_OCTEON struct octeon_cop2_state cp2 __attribute__ ((__aligned__(128))); struct octeon_cvmseg_state cvmseg __attribute__ ((__aligned__(128))); @@ -341,6 +342,7 @@ struct thread_struct { .cp0_badvaddr = 0, \ .cp0_baduaddr = 0, \ .error_code = 0, \ + .trap_nr = 0, \ /* \ * Platform specific cop2 registers(null if no COP2) \ */ \ diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index 3706091b6351d..154e2039ea5ef 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -128,6 +128,7 @@ void output_thread_defines(void) thread.cp0_baduaddr); OFFSET(THREAD_ECODE, task_struct, \ thread.error_code); + OFFSET(THREAD_TRAPNO, task_struct, thread.trap_nr); BLANK(); } diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index da0b3189fe883..cea964daf4006 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -370,11 +370,6 @@ void show_registers(struct pt_regs *regs) set_fs(old_fs); } -static int regs_to_trapnr(struct pt_regs *regs) -{ - return (regs->cp0_cause >> 2) & 0x1f; -} - static DEFINE_RAW_SPINLOCK(die_lock); void __noreturn die(const char *str, struct pt_regs *regs) @@ -384,7 +379,7 @@ void __noreturn die(const char *str, struct pt_regs *regs) oops_enter(); - if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) sig = 0; @@ -470,7 +465,7 @@ asmlinkage void do_be(struct pt_regs *regs) printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", data ? "Data" : "Instruction", field, regs->cp0_epc, field, regs->regs[31]); - if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_OOPS, "bus error", regs, 0, current->thread.trap_nr, SIGBUS) == NOTIFY_STOP) goto out; @@ -826,7 +821,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) int sig; prev_state = exception_enter(); - if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_FP, "FP exception", regs, 0, current->thread.trap_nr, SIGFPE) == NOTIFY_STOP) goto out; @@ -882,11 +877,12 @@ void do_trap_or_bp(struct pt_regs *regs, unsigned int code, char b[40]; #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP - if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) + if (kgdb_ll_trap(DIE_TRAP, str, regs, code, current->thread.trap_nr, + SIGTRAP) == NOTIFY_STOP) return; #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ - if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), + if (notify_die(DIE_TRAP, str, regs, code, current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) return; @@ -948,6 +944,7 @@ asmlinkage void do_bp(struct pt_regs *regs) set_fs(KERNEL_DS); prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; if (get_isa16_mode(regs->cp0_epc)) { u16 instr[2]; @@ -989,13 +986,13 @@ asmlinkage void do_bp(struct pt_regs *regs) switch (bcode) { case BRK_KPROBE_BP: if (notify_die(DIE_BREAK, "debug", regs, bcode, - regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) goto out; else break; case BRK_KPROBE_SSTEPBP: if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, - regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) goto out; else break; @@ -1028,6 +1025,7 @@ asmlinkage void do_tr(struct pt_regs *regs) set_fs(get_ds()); prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; if (get_isa16_mode(regs->cp0_epc)) { if (__get_user(instr[0], (u16 __user *)(epc + 0)) || __get_user(instr[1], (u16 __user *)(epc + 2))) @@ -1094,8 +1092,9 @@ asmlinkage void do_ri(struct pt_regs *regs) no_r2_instr: prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; - if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), + if (notify_die(DIE_RI, "RI Fault", regs, 0, current->thread.trap_nr, SIGILL) == NOTIFY_STOP) goto out; @@ -1444,8 +1443,9 @@ asmlinkage void do_msa_fpe(struct pt_regs *regs, unsigned int msacsr) enum ctx_state prev_state; prev_state = exception_enter(); + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; if (notify_die(DIE_MSAFP, "MSA FP exception", regs, 0, - regs_to_trapnr(regs), SIGFPE) == NOTIFY_STOP) + current->thread.trap_nr, SIGFPE) == NOTIFY_STOP) goto out; /* Clear MSACSR.Cause before enabling interrupts */ diff --git a/arch/mips/mm/fault.c b/arch/mips/mm/fault.c index 852a41c6da450..4b88fa031891d 100644 --- a/arch/mips/mm/fault.c +++ b/arch/mips/mm/fault.c @@ -57,12 +57,10 @@ static void __kprobes __do_page_fault(struct pt_regs *regs, unsigned long write, #ifdef CONFIG_KPROBES /* - * This is to notify the fault handler of the kprobes. The - * exception code is redundant as it is also carried in REGS, - * but we pass it anyhow. + * This is to notify the fault handler of the kprobes. */ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, -1, - (regs->cp0_cause >> 2) & 0x1f, SIGSEGV) == NOTIFY_STOP) + current->thread.trap_nr, SIGSEGV) == NOTIFY_STOP) return; #endif @@ -224,6 +222,7 @@ bad_area_nosemaphore: print_vma_addr(" ", regs->regs[31]); pr_info("\n"); } + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; info.si_signo = SIGSEGV; info.si_errno = 0; /* info.si_code has been set above */ @@ -282,6 +281,7 @@ do_sigbus: field, (unsigned long) regs->cp0_epc, field, (unsigned long) regs->regs[31]); #endif + current->thread.trap_nr = (regs->cp0_cause >> 2) & 0x1f; tsk->thread.cp0_badvaddr = address; info.si_signo = SIGBUS; info.si_errno = 0; -- GitLab From 40e084a506eba78310cd5e8ab700fd1226c6130a Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 29 Jul 2015 22:44:53 +0200 Subject: [PATCH 6178/7006] MIPS: Add uprobes support. Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 4 + arch/mips/include/asm/kdebug.h | 4 +- arch/mips/include/asm/ptrace.h | 80 +++++++ arch/mips/include/asm/thread_info.h | 5 +- arch/mips/include/asm/uprobes.h | 58 +++++ arch/mips/include/uapi/asm/break.h | 2 + arch/mips/kernel/Makefile | 1 + arch/mips/kernel/ptrace.c | 88 +++++++ arch/mips/kernel/signal.c | 4 + arch/mips/kernel/traps.c | 12 + arch/mips/kernel/uprobes.c | 341 ++++++++++++++++++++++++++++ 11 files changed, 597 insertions(+), 2 deletions(-) create mode 100644 arch/mips/include/asm/uprobes.h create mode 100644 arch/mips/kernel/uprobes.c diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7e182424f1196..7a9a2554fa002 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -1,6 +1,7 @@ config MIPS bool default y + select ARCH_SUPPORTS_UPROBES select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO select ARCH_USE_CMPXCHG_LOCKREF if 64BIT @@ -1041,6 +1042,9 @@ config FW_CFE config ARCH_DMA_ADDR_T_64BIT def_bool (HIGHMEM && ARCH_PHYS_ADDR_T_64BIT) || 64BIT +config ARCH_SUPPORTS_UPROBES + bool + config DMA_MAYBE_COHERENT select DMA_NONCOHERENT bool diff --git a/arch/mips/include/asm/kdebug.h b/arch/mips/include/asm/kdebug.h index cba22ab7ad4d5..8e3d08e739c18 100644 --- a/arch/mips/include/asm/kdebug.h +++ b/arch/mips/include/asm/kdebug.h @@ -11,7 +11,9 @@ enum die_val { DIE_PAGE_FAULT, DIE_BREAK, DIE_SSTEPBP, - DIE_MSAFP + DIE_MSAFP, + DIE_UPROBE, + DIE_UPROBE_XOL, }; #endif /* _ASM_MIPS_KDEBUG_H */ diff --git a/arch/mips/include/asm/ptrace.h b/arch/mips/include/asm/ptrace.h index ffc320389f40a..f6fc6aac54963 100644 --- a/arch/mips/include/asm/ptrace.h +++ b/arch/mips/include/asm/ptrace.h @@ -14,11 +14,16 @@ #include #include #include +#include +#include #include /* * This struct defines the way the registers are stored on the stack during a * system call/exception. As usual the registers k0/k1 aren't being saved. + * + * If you add a register here, also add it to regoffset_table[] in + * arch/mips/kernel/ptrace.c. */ struct pt_regs { #ifdef CONFIG_32BIT @@ -43,8 +48,83 @@ struct pt_regs { unsigned long long mpl[6]; /* MTM{0-5} */ unsigned long long mtp[6]; /* MTP{0-5} */ #endif + unsigned long __last[0]; } __aligned(8); +static inline unsigned long kernel_stack_pointer(struct pt_regs *regs) +{ + return regs->regs[31]; +} + +/* + * Don't use asm-generic/ptrace.h it defines FP accessors that don't make + * sense on MIPS. We rather want an error if they get invoked. + */ + +static inline void instruction_pointer_set(struct pt_regs *regs, + unsigned long val) +{ + regs->cp0_epc = val; +} + +/* Query offset/name of register from its name/offset */ +extern int regs_query_register_offset(const char *name); +#define MAX_REG_OFFSET (offsetof(struct pt_regs, __last)) + +/** + * regs_get_register() - get register value from its offset + * @regs: pt_regs from which register value is gotten. + * @offset: offset number of the register. + * + * regs_get_register returns the value of a register. The @offset is the + * offset of the register in struct pt_regs address which specified by @regs. + * If @offset is bigger than MAX_REG_OFFSET, this returns 0. + */ +static inline unsigned long regs_get_register(struct pt_regs *regs, + unsigned int offset) +{ + if (unlikely(offset > MAX_REG_OFFSET)) + return 0; + + return *(unsigned long *)((unsigned long)regs + offset); +} + +/** + * regs_within_kernel_stack() - check the address in the stack + * @regs: pt_regs which contains kernel stack pointer. + * @addr: address which is checked. + * + * regs_within_kernel_stack() checks @addr is within the kernel stack page(s). + * If @addr is within the kernel stack, it returns true. If not, returns false. + */ +static inline int regs_within_kernel_stack(struct pt_regs *regs, + unsigned long addr) +{ + return ((addr & ~(THREAD_SIZE - 1)) == + (kernel_stack_pointer(regs) & ~(THREAD_SIZE - 1))); +} + +/** + * regs_get_kernel_stack_nth() - get Nth entry of the stack + * @regs: pt_regs which contains kernel stack pointer. + * @n: stack entry number. + * + * regs_get_kernel_stack_nth() returns @n th entry of the kernel stack which + * is specified by @regs. If the @n th entry is NOT in the kernel stack, + * this returns 0. + */ +static inline unsigned long regs_get_kernel_stack_nth(struct pt_regs *regs, + unsigned int n) +{ + unsigned long *addr = (unsigned long *)kernel_stack_pointer(regs); + + addr += n; + if (regs_within_kernel_stack(regs, (unsigned long)addr)) + return *addr; + else + return 0; +} + struct task_struct; extern int ptrace_getregs(struct task_struct *child, diff --git a/arch/mips/include/asm/thread_info.h b/arch/mips/include/asm/thread_info.h index 9c0014e87c174..e309d8fcb5167 100644 --- a/arch/mips/include/asm/thread_info.h +++ b/arch/mips/include/asm/thread_info.h @@ -99,6 +99,7 @@ static inline struct thread_info *current_thread_info(void) #define TIF_SYSCALL_AUDIT 3 /* syscall auditing active */ #define TIF_SECCOMP 4 /* secure computing */ #define TIF_NOTIFY_RESUME 5 /* callback before returning to user */ +#define TIF_UPROBE 6 /* breakpointed or singlestepping */ #define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */ #define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */ #define TIF_MEMDIE 18 /* is terminating due to OOM killer */ @@ -122,6 +123,7 @@ static inline struct thread_info *current_thread_info(void) #define _TIF_SYSCALL_AUDIT (1< +#include + +#include +#include + +/* + * We want this to be defined as union mips_instruction but that makes the + * generic code blow up. + */ +typedef u32 uprobe_opcode_t; + +/* + * Classic MIPS (note this implementation doesn't consider microMIPS yet) + * instructions are always 4 bytes but in order to deal with branches and + * their delay slots, we treat instructions as having 8 bytes maximum. + */ +#define MAX_UINSN_BYTES 8 +#define UPROBE_XOL_SLOT_BYTES 128 /* Max. cache line size */ + +#define UPROBE_BRK_UPROBE 0x000d000d /* break 13 */ +#define UPROBE_BRK_UPROBE_XOL 0x000e000d /* break 14 */ + +#define UPROBE_SWBP_INSN UPROBE_BRK_UPROBE +#define UPROBE_SWBP_INSN_SIZE 4 + +struct arch_uprobe { + unsigned long resume_epc; + u32 insn[2]; + u32 ixol[2]; + union mips_instruction orig_inst[MAX_UINSN_BYTES / 4]; +}; + +struct arch_uprobe_task { + unsigned long saved_trap_nr; +}; + +extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, + struct mm_struct *mm, unsigned long addr); +extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); +extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); +extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); +extern int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data); +extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, + struct pt_regs *regs); +extern unsigned long arch_uretprobe_hijack_return_addr( + unsigned long trampoline_vaddr, struct pt_regs *regs); + +#endif /* __ASM_UPROBES_H */ diff --git a/arch/mips/include/uapi/asm/break.h b/arch/mips/include/uapi/asm/break.h index 002c39ea20c3e..9c4265cbf1518 100644 --- a/arch/mips/include/uapi/asm/break.h +++ b/arch/mips/include/uapi/asm/break.h @@ -21,6 +21,8 @@ #define BRK_DIVZERO 7 /* Divide by zero check */ #define BRK_RANGE 8 /* Range error check */ #define BRK_BUG 12 /* Used by BUG() */ +#define BRK_UPROBE 13 /* See */ +#define BRK_UPROBE_XOL 14 /* See */ #define BRK_MEMU 514 /* Used by FPU emulator */ #define BRK_KPROBE_BP 515 /* Kprobe break */ #define BRK_KPROBE_SSTEPBP 516 /* Kprobe single step software implementation */ diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 3f5cf8aff6f34..a61435b1ceb12 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_PERF_EVENTS) += perf_event.o obj-$(CONFIG_HW_PERF_EVENTS) += perf_event_mipsxx.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o +obj-$(CONFIG_UPROBES) += uprobes.o obj-$(CONFIG_MIPS_CM) += mips-cm.o obj-$(CONFIG_MIPS_CPC) += mips-cpc.o diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index e933a309f2ea5..4f0ac78d17f19 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -490,6 +491,93 @@ enum mips_regset { REGSET_FPR, }; +struct pt_regs_offset { + const char *name; + int offset; +}; + +#define REG_OFFSET_NAME(reg, r) { \ + .name = #reg, \ + .offset = offsetof(struct pt_regs, r) \ +} + +#define REG_OFFSET_END { \ + .name = NULL, \ + .offset = 0 \ +} + +static const struct pt_regs_offset regoffset_table[] = { + REG_OFFSET_NAME(r0, regs[0]), + REG_OFFSET_NAME(r1, regs[1]), + REG_OFFSET_NAME(r2, regs[2]), + REG_OFFSET_NAME(r3, regs[3]), + REG_OFFSET_NAME(r4, regs[4]), + REG_OFFSET_NAME(r5, regs[5]), + REG_OFFSET_NAME(r6, regs[6]), + REG_OFFSET_NAME(r7, regs[7]), + REG_OFFSET_NAME(r8, regs[8]), + REG_OFFSET_NAME(r9, regs[9]), + REG_OFFSET_NAME(r10, regs[10]), + REG_OFFSET_NAME(r11, regs[11]), + REG_OFFSET_NAME(r12, regs[12]), + REG_OFFSET_NAME(r13, regs[13]), + REG_OFFSET_NAME(r14, regs[14]), + REG_OFFSET_NAME(r15, regs[15]), + REG_OFFSET_NAME(r16, regs[16]), + REG_OFFSET_NAME(r17, regs[17]), + REG_OFFSET_NAME(r18, regs[18]), + REG_OFFSET_NAME(r19, regs[19]), + REG_OFFSET_NAME(r20, regs[20]), + REG_OFFSET_NAME(r21, regs[21]), + REG_OFFSET_NAME(r22, regs[22]), + REG_OFFSET_NAME(r23, regs[23]), + REG_OFFSET_NAME(r24, regs[24]), + REG_OFFSET_NAME(r25, regs[25]), + REG_OFFSET_NAME(r26, regs[26]), + REG_OFFSET_NAME(r27, regs[27]), + REG_OFFSET_NAME(r28, regs[28]), + REG_OFFSET_NAME(r29, regs[29]), + REG_OFFSET_NAME(r30, regs[30]), + REG_OFFSET_NAME(r31, regs[31]), + REG_OFFSET_NAME(c0_status, cp0_status), + REG_OFFSET_NAME(hi, hi), + REG_OFFSET_NAME(lo, lo), +#ifdef CONFIG_CPU_HAS_SMARTMIPS + REG_OFFSET_NAME(acx, acx), +#endif + REG_OFFSET_NAME(c0_badvaddr, cp0_badvaddr), + REG_OFFSET_NAME(c0_cause, cp0_cause), + REG_OFFSET_NAME(c0_epc, cp0_epc), +#ifdef CONFIG_MIPS_MT_SMTC + REG_OFFSET_NAME(c0_tcstatus, cp0_tcstatus), +#endif +#ifdef CONFIG_CPU_CAVIUM_OCTEON + REG_OFFSET_NAME(mpl0, mpl[0]), + REG_OFFSET_NAME(mpl1, mpl[1]), + REG_OFFSET_NAME(mpl2, mpl[2]), + REG_OFFSET_NAME(mtp0, mtp[0]), + REG_OFFSET_NAME(mtp1, mtp[1]), + REG_OFFSET_NAME(mtp2, mtp[2]), +#endif + REG_OFFSET_END, +}; + +/** + * regs_query_register_offset() - query register offset from its name + * @name: the name of a register + * + * regs_query_register_offset() returns the offset of a register in struct + * pt_regs from its name. If the name is invalid, this returns -EINVAL; + */ +int regs_query_register_offset(const char *name) +{ + const struct pt_regs_offset *roff; + for (roff = regoffset_table; roff->name != NULL; roff++) + if (!strcmp(roff->name, name)) + return roff->offset; + return -EINVAL; +} + #if defined(CONFIG_32BIT) || defined(CONFIG_MIPS32_O32) static const struct user_regset mips_regsets[] = { diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index fa13a52713dfc..2fec67bfc457c 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -856,6 +857,9 @@ asmlinkage void do_notify_resume(struct pt_regs *regs, void *unused, user_exit(); + if (thread_info_flags & _TIF_UPROBE) + uprobe_notify_resume(regs); + /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) do_signal(regs); diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index cea964daf4006..fdb392b27e810 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -984,6 +984,18 @@ asmlinkage void do_bp(struct pt_regs *regs) * pertain to them. */ switch (bcode) { + case BRK_UPROBE: + if (notify_die(DIE_UPROBE, "uprobe", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; + case BRK_UPROBE_XOL: + if (notify_die(DIE_UPROBE_XOL, "uprobe_xol", regs, bcode, + current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) + goto out; + else + break; case BRK_KPROBE_BP: if (notify_die(DIE_BREAK, "debug", regs, bcode, current->thread.trap_nr, SIGTRAP) == NOTIFY_STOP) diff --git a/arch/mips/kernel/uprobes.c b/arch/mips/kernel/uprobes.c new file mode 100644 index 0000000000000..8452d933a6453 --- /dev/null +++ b/arch/mips/kernel/uprobes.c @@ -0,0 +1,341 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static inline int insn_has_delay_slot(const union mips_instruction insn) +{ + switch (insn.i_format.opcode) { + /* + * jr and jalr are in r_format format. + */ + case spec_op: + switch (insn.r_format.func) { + case jalr_op: + case jr_op: + return 1; + } + break; + + /* + * This group contains: + * bltz_op, bgez_op, bltzl_op, bgezl_op, + * bltzal_op, bgezal_op, bltzall_op, bgezall_op. + */ + case bcond_op: + switch (insn.i_format.rt) { + case bltz_op: + case bltzl_op: + case bgez_op: + case bgezl_op: + case bltzal_op: + case bltzall_op: + case bgezal_op: + case bgezall_op: + case bposge32_op: + return 1; + } + break; + + /* + * These are unconditional and in j_format. + */ + case jal_op: + case j_op: + case beq_op: + case beql_op: + case bne_op: + case bnel_op: + case blez_op: /* not really i_format */ + case blezl_op: + case bgtz_op: + case bgtzl_op: + return 1; + + /* + * And now the FPA/cp1 branch instructions. + */ + case cop1_op: +#ifdef CONFIG_CPU_CAVIUM_OCTEON + case lwc2_op: /* This is bbit0 on Octeon */ + case ldc2_op: /* This is bbit032 on Octeon */ + case swc2_op: /* This is bbit1 on Octeon */ + case sdc2_op: /* This is bbit132 on Octeon */ +#endif + return 1; + } + + return 0; +} + +/** + * arch_uprobe_analyze_insn - instruction analysis including validity and fixups. + * @mm: the probed address space. + * @arch_uprobe: the probepoint information. + * @addr: virtual address at which to install the probepoint + * Return 0 on success or a -ve number on error. + */ +int arch_uprobe_analyze_insn(struct arch_uprobe *aup, + struct mm_struct *mm, unsigned long addr) +{ + union mips_instruction inst; + + /* + * For the time being this also blocks attempts to use uprobes with + * MIPS16 and microMIPS. + */ + if (addr & 0x03) + return -EINVAL; + + inst.word = aup->insn[0]; + aup->ixol[0] = aup->insn[insn_has_delay_slot(inst)]; + aup->ixol[1] = UPROBE_BRK_UPROBE_XOL; /* NOP */ + + return 0; +} + +/** + * is_trap_insn - check if the instruction is a trap variant + * @insn: instruction to be checked. + * Returns true if @insn is a trap variant. + * + * This definition overrides the weak definition in kernel/events/uprobes.c. + * and is needed for the case where an architecture has multiple trap + * instructions (like PowerPC or MIPS). We treat BREAK just like the more + * modern conditional trap instructions. + */ +bool is_trap_insn(uprobe_opcode_t *insn) +{ + union mips_instruction inst; + + inst.word = *insn; + + switch (inst.i_format.opcode) { + case spec_op: + switch (inst.r_format.func) { + case break_op: + case teq_op: + case tge_op: + case tgeu_op: + case tlt_op: + case tltu_op: + case tne_op: + return 1; + } + break; + + case bcond_op: /* Yes, really ... */ + switch (inst.u_format.rt) { + case teqi_op: + case tgei_op: + case tgeiu_op: + case tlti_op: + case tltiu_op: + case tnei_op: + return 1; + } + break; + } + + return 0; +} + +#define UPROBE_TRAP_NR ULONG_MAX + +/* + * arch_uprobe_pre_xol - prepare to execute out of line. + * @auprobe: the probepoint information. + * @regs: reflects the saved user state of current task. + */ +int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + union mips_instruction insn; + + /* + * Now find the EPC where to resume after the breakpoint has been + * dealt with. This may require emulation of a branch. + */ + aup->resume_epc = regs->cp0_epc + 4; + if (insn_has_delay_slot((union mips_instruction) aup->insn[0])) { + unsigned long epc; + + epc = regs->cp0_epc; + __compute_return_epc_for_insn(regs, insn); + aup->resume_epc = regs->cp0_epc; + } + + utask->autask.saved_trap_nr = current->thread.trap_nr; + current->thread.trap_nr = UPROBE_TRAP_NR; + regs->cp0_epc = current->utask->xol_vaddr; + + return 0; +} + +int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + current->thread.trap_nr = utask->autask.saved_trap_nr; + regs->cp0_epc = aup->resume_epc; + + return 0; +} + +/* + * If xol insn itself traps and generates a signal(Say, + * SIGILL/SIGSEGV/etc), then detect the case where a singlestepped + * instruction jumps back to its own address. It is assumed that anything + * like do_page_fault/do_trap/etc sets thread.trap_nr != -1. + * + * arch_uprobe_pre_xol/arch_uprobe_post_xol save/restore thread.trap_nr, + * arch_uprobe_xol_was_trapped() simply checks that ->trap_nr is not equal to + * UPROBE_TRAP_NR == -1 set by arch_uprobe_pre_xol(). + */ +bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) +{ + if (tsk->thread.trap_nr != UPROBE_TRAP_NR) + return true; + + return false; +} + +int arch_uprobe_exception_notify(struct notifier_block *self, + unsigned long val, void *data) +{ + struct die_args *args = data; + struct pt_regs *regs = args->regs; + + /* regs == NULL is a kernel bug */ + if (WARN_ON(!regs)) + return NOTIFY_DONE; + + /* We are only interested in userspace traps */ + if (!user_mode(regs)) + return NOTIFY_DONE; + + switch (val) { + case DIE_BREAK: + if (uprobe_pre_sstep_notifier(regs)) + return NOTIFY_STOP; + break; + case DIE_UPROBE_XOL: + if (uprobe_post_sstep_notifier(regs)) + return NOTIFY_STOP; + default: + break; + } + + return 0; +} + +/* + * This function gets called when XOL instruction either gets trapped or + * the thread has a fatal signal. Reset the instruction pointer to its + * probed address for the potential restart or for post mortem analysis. + */ +void arch_uprobe_abort_xol(struct arch_uprobe *aup, + struct pt_regs *regs) +{ + struct uprobe_task *utask = current->utask; + + instruction_pointer_set(regs, utask->vaddr); +} + +unsigned long arch_uretprobe_hijack_return_addr( + unsigned long trampoline_vaddr, struct pt_regs *regs) +{ + unsigned long ra; + + ra = regs->regs[31]; + + /* Replace the return address with the trampoline address */ + regs->regs[31] = ra; + + return ra; +} + +/** + * set_swbp - store breakpoint at a given address. + * @auprobe: arch specific probepoint information. + * @mm: the probed process address space. + * @vaddr: the virtual address to insert the opcode. + * + * For mm @mm, store the breakpoint instruction at @vaddr. + * Return 0 (success) or a negative errno. + * + * This version overrides the weak version in kernel/events/uprobes.c. + * It is required to handle MIPS16 and microMIPS. + */ +int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long vaddr) +{ + return uprobe_write_opcode(mm, vaddr, UPROBE_SWBP_INSN); +} + +/** + * set_orig_insn - Restore the original instruction. + * @mm: the probed process address space. + * @auprobe: arch specific probepoint information. + * @vaddr: the virtual address to insert the opcode. + * + * For mm @mm, restore the original opcode (opcode) at @vaddr. + * Return 0 (success) or a negative errno. + * + * This overrides the weak version in kernel/events/uprobes.c. + */ +int set_orig_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, + unsigned long vaddr) +{ + return uprobe_write_opcode(mm, vaddr, + *(uprobe_opcode_t *)&auprobe->orig_inst[0].word); +} + +void __weak arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, + void *src, unsigned long len) +{ + void *kaddr; + + /* Initialize the slot */ + kaddr = kmap_atomic(page); + memcpy(kaddr + (vaddr & ~PAGE_MASK), src, len); + kunmap_atomic(kaddr); + + /* + * The MIPS version of flush_icache_range will operate safely on + * user space addresses and more importantly, it doesn't require a + * VMA argument. + */ + flush_icache_range(vaddr, vaddr + len); +} + +/** + * uprobe_get_swbp_addr - compute address of swbp given post-swbp regs + * @regs: Reflects the saved state of the task after it has hit a breakpoint + * instruction. + * Return the address of the breakpoint instruction. + * + * This overrides the weak version in kernel/events/uprobes.c. + */ +unsigned long uprobe_get_swbp_addr(struct pt_regs *regs) +{ + return instruction_pointer(regs); +} + +/* + * See if the instruction can be emulated. + * Returns true if instruction was emulated, false otherwise. + * + * For now we always emulate so this function just returns 0. + */ +bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) +{ + return 0; +} -- GitLab From b7565cc3321987e46d1f65f5b5eb3fb48268fdc2 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Wed, 29 Jul 2015 23:17:00 +0200 Subject: [PATCH 6179/7006] Documentation: MIPS now supports uprobes. Signed-off-by: Ralf Baechle --- Documentation/features/debug/uprobes/arch-support.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/features/debug/uprobes/arch-support.txt b/Documentation/features/debug/uprobes/arch-support.txt index 4efe36c3ace93..d605c3fc38fd5 100644 --- a/Documentation/features/debug/uprobes/arch-support.txt +++ b/Documentation/features/debug/uprobes/arch-support.txt @@ -22,7 +22,7 @@ | m68k: | TODO | | metag: | TODO | | microblaze: | TODO | - | mips: | TODO | + | mips: | ok | | mn10300: | TODO | | nios2: | TODO | | openrisc: | TODO | -- GitLab From 23eb6f4016758b756b54704b359e3c51d425d6ab Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Tue, 28 Apr 2015 13:11:25 +0200 Subject: [PATCH 6180/7006] MIPS: Netlogic: Fix 0x0x prefixes. Fix the 0x0x prefix in integer constants, in this case the registers interval is actually 0x8065 .. 0x80A4 as confirmed some lines above in the code. Signed-off-by: Antonio Ospite Cc: linux-mips@linux-mips.org Cc: Jiri Kosina Patchwork: https://patchwork.linux-mips.org/patch/9908/ Signed-off-by: Ralf Baechle --- arch/mips/netlogic/xlp/ahci-init-xlp2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/netlogic/xlp/ahci-init-xlp2.c b/arch/mips/netlogic/xlp/ahci-init-xlp2.c index 7b066a44e6798..c11b9c7dc7c8e 100644 --- a/arch/mips/netlogic/xlp/ahci-init-xlp2.c +++ b/arch/mips/netlogic/xlp/ahci-init-xlp2.c @@ -152,7 +152,7 @@ static const u8 sata_phy_config1[] = { 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x01, 0x01, 0x22, 0x00 }; -/* SATA PHY config for register block 2 0x0x8065 .. 0x0x80A4 */ +/* SATA PHY config for register block 2 0x8065 .. 0x80A4 */ static const u8 sata_phy_config2[] = { 0xAA, 0x00, 0x4C, 0xC9, 0xC9, 0x07, 0x07, 0x18, 0x18, 0x05, 0x0C, 0x10, 0x00, 0x10, 0x00, 0xFF, -- GitLab From 1a3d59579b9f436da038f377309cf2270c76318e Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Mon, 3 Aug 2015 08:49:30 -0700 Subject: [PATCH 6181/7006] MIPS: Tidy up FPU context switching Rather than saving the scalar FP or vector context in the assembly resume function, reuse the existing C code we have in fpu.h to do exactly that. This reduces duplication, results in a much easier to read resume function & should allow the compiler to optimise out more MSA code due to is_msa_enabled()/cpu_has_msa being known-zero at compile time for kernels without MSA support. Signed-off-by: Paul Burton Cc: linux-mips@linux-mips.org Cc: Leonid Yegoshin Cc: Maciej W. Rozycki Cc: linux-kernel@vger.kernel.org Cc: James Hogan Cc: Markos Chandras Cc: Manuel Lauss Patchwork: https://patchwork.linux-mips.org/patch/10830/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/fpu.h | 21 ++++++++++------ arch/mips/include/asm/switch_to.h | 21 +++------------- arch/mips/kernel/r4k_switch.S | 41 +------------------------------ 3 files changed, 18 insertions(+), 65 deletions(-) diff --git a/arch/mips/include/asm/fpu.h b/arch/mips/include/asm/fpu.h index 1b06251898352..9cbf383b8834c 100644 --- a/arch/mips/include/asm/fpu.h +++ b/arch/mips/include/asm/fpu.h @@ -164,25 +164,30 @@ static inline int own_fpu(int restore) return ret; } -static inline void lose_fpu(int save) +static inline void lose_fpu_inatomic(int save, struct task_struct *tsk) { - preempt_disable(); if (is_msa_enabled()) { if (save) { - save_msa(current); - current->thread.fpu.fcr31 = + save_msa(tsk); + tsk->thread.fpu.fcr31 = read_32bit_cp1_register(CP1_STATUS); } disable_msa(); - clear_thread_flag(TIF_USEDMSA); + clear_tsk_thread_flag(tsk, TIF_USEDMSA); __disable_fpu(); } else if (is_fpu_owner()) { if (save) - _save_fp(current); + _save_fp(tsk); __disable_fpu(); } - KSTK_STATUS(current) &= ~ST0_CU1; - clear_thread_flag(TIF_USEDFPU); + KSTK_STATUS(tsk) &= ~ST0_CU1; + clear_tsk_thread_flag(tsk, TIF_USEDFPU); +} + +static inline void lose_fpu(int save) +{ + preempt_disable(); + lose_fpu_inatomic(save, current); preempt_enable(); } diff --git a/arch/mips/include/asm/switch_to.h b/arch/mips/include/asm/switch_to.h index 9733cd0266e4b..28b5d84a5022a 100644 --- a/arch/mips/include/asm/switch_to.h +++ b/arch/mips/include/asm/switch_to.h @@ -16,29 +16,21 @@ #include #include #include -#include +#include struct task_struct; -enum { - FP_SAVE_NONE = 0, - FP_SAVE_VECTOR = -1, - FP_SAVE_SCALAR = 1, -}; - /** * resume - resume execution of a task * @prev: The task previously executed. * @next: The task to begin executing. * @next_ti: task_thread_info(next). - * @fp_save: Which, if any, FP context to save for prev. * * This function is used whilst scheduling to save the context of prev & load * the context of next. Returns prev. */ extern asmlinkage struct task_struct *resume(struct task_struct *prev, - struct task_struct *next, struct thread_info *next_ti, - s32 fp_save); + struct task_struct *next, struct thread_info *next_ti); extern unsigned int ll_bit; extern struct task_struct *ll_task; @@ -91,8 +83,8 @@ do { if (cpu_has_rw_llb) { \ */ #define switch_to(prev, next, last) \ do { \ - s32 __fpsave = FP_SAVE_NONE; \ __mips_mt_fpaff_switch_to(prev); \ + lose_fpu_inatomic(1, prev); \ if (cpu_has_dsp) { \ __save_dsp(prev); \ __restore_dsp(next); \ @@ -111,15 +103,10 @@ do { \ clear_c0_status(ST0_CU2); \ } \ __clear_software_ll_bit(); \ - if (test_and_clear_tsk_thread_flag(prev, TIF_USEDFPU)) \ - __fpsave = FP_SAVE_SCALAR; \ - if (test_and_clear_tsk_thread_flag(prev, TIF_USEDMSA)) \ - __fpsave = FP_SAVE_VECTOR; \ if (cpu_has_userlocal) \ write_c0_userlocal(task_thread_info(next)->tp_value); \ __restore_watch(); \ - disable_msa(); \ - (last) = resume(prev, next, task_thread_info(next), __fpsave); \ + (last) = resume(prev, next, task_thread_info(next)); \ } while (0) #endif /* _ASM_SWITCH_TO_H */ diff --git a/arch/mips/kernel/r4k_switch.S b/arch/mips/kernel/r4k_switch.S index 04cbbde3521bc..92cd0516ecf51 100644 --- a/arch/mips/kernel/r4k_switch.S +++ b/arch/mips/kernel/r4k_switch.S @@ -34,7 +34,7 @@ #ifndef USE_ALTERNATE_RESUME_IMPL /* * task_struct *resume(task_struct *prev, task_struct *next, - * struct thread_info *next_ti, s32 fp_save) + * struct thread_info *next_ti) */ .align 5 LEAF(resume) @@ -43,45 +43,6 @@ cpu_save_nonscratch a0 LONG_S ra, THREAD_REG31(a0) - /* - * Check whether we need to save any FP context. FP context is saved - * iff the process has used the context with the scalar FPU or the MSA - * ASE in the current time slice, as indicated by _TIF_USEDFPU and - * _TIF_USEDMSA respectively. switch_to will have set fp_save - * accordingly to an FP_SAVE_ enum value. - */ - beqz a3, 2f - - /* - * We do. Clear the saved CU1 bit for prev, such that next time it is - * scheduled it will start in userland with the FPU disabled. If the - * task uses the FPU then it will be enabled again via the do_cpu trap. - * This allows us to lazily restore the FP context. - */ - PTR_L t3, TASK_THREAD_INFO(a0) - LONG_L t0, ST_OFF(t3) - li t1, ~ST0_CU1 - and t0, t0, t1 - LONG_S t0, ST_OFF(t3) - - /* Check whether we're saving scalar or vector context. */ - bgtz a3, 1f - - /* Save 128b MSA vector context + scalar FP control & status. */ - .set push - SET_HARDFLOAT - cfc1 t1, fcr31 - msa_save_all a0 - .set pop /* SET_HARDFLOAT */ - - sw t1, THREAD_FCR31(a0) - b 2f - -1: /* Save 32b/64b scalar FP context. */ - fpu_save_double a0 t0 t1 # c0_status passed in t0 - # clobbers t1 -2: - #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP) PTR_LA t8, __stack_chk_guard LONG_L t9, TASK_STACK_CANARY(a1) -- GitLab From eb811c73b69f18cefb7a63f22fe07212c6575650 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:12 +0100 Subject: [PATCH 6182/7006] CLOCKSOURCE: mips-gic: Enable the clock before using it For the clock to be used (e.g. get its rate through clk_get_rate) it should be prepared and enabled first. Also, while the clock is enabled the driver must hold a reference to it, so let's remove the call to clk_put. Reviewed-by: Andrew Bresticker Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10779/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index b81ed1a5342d9..913585d93466a 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -158,8 +158,13 @@ static void __init gic_clocksource_of_init(struct device_node *node) clk = of_clk_get(node, 0); if (!IS_ERR(clk)) { + if (clk_prepare_enable(clk) < 0) { + pr_err("GIC failed to enable clock\n"); + clk_put(clk); + return; + } + gic_frequency = clk_get_rate(clk); - clk_put(clk); } else if (of_property_read_u32(node, "clock-frequency", &gic_frequency)) { pr_err("GIC frequency not specified.\n"); -- GitLab From f95ac8558b88a5e9ae2b1d580a5cc55bffa512fa Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:13 +0100 Subject: [PATCH 6183/7006] CLOCKSOURCE: mips-gic: Add missing error returns checks This commit adds the required checks on the functions that return an error. Some of them are not critical, so only a warning is printed. Signed-off-by: Ezequiel Garcia Reviewed-by: Andrew Bresticker Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10780/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 913585d93466a..c4352f0784923 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -100,12 +100,18 @@ static struct notifier_block gic_cpu_nb = { static int gic_clockevent_init(void) { + int ret; + if (!cpu_has_counter || !gic_frequency) return -ENXIO; - setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + ret = setup_percpu_irq(gic_timer_irq, &gic_compare_irqaction); + if (ret < 0) + return ret; - register_cpu_notifier(&gic_cpu_nb); + ret = register_cpu_notifier(&gic_cpu_nb); + if (ret < 0) + pr_warn("GIC: Unable to register CPU notifier\n"); gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device)); @@ -125,13 +131,17 @@ static struct clocksource gic_clocksource = { static void __init __gic_clocksource_init(void) { + int ret; + /* Set clocksource mask. */ gic_clocksource.mask = CLOCKSOURCE_MASK(gic_get_count_width()); /* Calculate a somewhat reasonable rating value. */ gic_clocksource.rating = 200 + gic_frequency / 10000000; - clocksource_register_hz(&gic_clocksource, gic_frequency); + ret = clocksource_register_hz(&gic_clocksource, gic_frequency); + if (ret < 0) + pr_warn("GIC: Unable to register clocksource\n"); gic_clockevent_init(); -- GitLab From 67d4e669c1e504a491e44737f3561eaba919b304 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:14 +0100 Subject: [PATCH 6184/7006] CLOCKSOURCE: mips-gic: Split clocksource and clockevent initialization This is preparation work for the introduction of clockevent frequency update with a clock notifier. This is only possible when the device is passed a clk struct, so let's split the legacy and devicetree initialization. Reviewed-by: Andrew Bresticker Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10781/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index c4352f0784923..22a4daf5f0c8b 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -142,11 +142,6 @@ static void __init __gic_clocksource_init(void) ret = clocksource_register_hz(&gic_clocksource, gic_frequency); if (ret < 0) pr_warn("GIC: Unable to register clocksource\n"); - - gic_clockevent_init(); - - /* And finally start the counter */ - gic_start_count(); } void __init gic_clocksource_init(unsigned int frequency) @@ -156,6 +151,10 @@ void __init gic_clocksource_init(unsigned int frequency) GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE); __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } static void __init gic_clocksource_of_init(struct device_node *node) @@ -187,6 +186,10 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); + gic_clockevent_init(); + + /* And finally start the counter */ + gic_start_count(); } CLOCKSOURCE_OF_DECLARE(mips_gic_timer, "mti,gic-timer", gic_clocksource_of_init); -- GitLab From 42b002ab73e00b24356be4f01954fa961fea4d82 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Sat, 22 Aug 2015 02:40:41 -0700 Subject: [PATCH 6185/7006] MIPS: Kconfig: Enable common clock framework for Malta and SEAD3 Now that we're ready to enable COMMON_CLK for GIC platforms do so for Malta and SEAD3. The only other user of the GIC Pistachio does already do so. [ralf@linux-mips.org: Rewrite the commit message because applied in the right order there is no breakage thus no fix required.] Signed-off-by: Guenter Roeck Cc: Ezequiel Garcia Cc: Daniel Lezcano Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11038/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 7a9a2554fa002..8083ef9c80d49 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -409,6 +409,7 @@ config MIPS_MALTA select CEVT_R4K select CSRC_R4K select CLKSRC_MIPS_GIC + select COMMON_CLK select DMA_MAYBE_COHERENT select GENERIC_ISA_DMA select HAVE_PCSPKR_PLATFORM @@ -459,6 +460,7 @@ config MIPS_SEAD3 select CEVT_R4K select CSRC_R4K select CLKSRC_MIPS_GIC + select COMMON_CLK select CPU_MIPSR2_IRQ_VI select CPU_MIPSR2_IRQ_EI select DMA_NONCOHERENT -- GitLab From fc6a6772f888ee8ab4c5428854f7f1d3abda13df Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:00:15 +0100 Subject: [PATCH 6186/7006] CLOCKSOURCE: mips-gic: Update clockevent frequency on clock rate changes This commit introduces the clockevent frequency update, using a clock notifier. It will be used to support CPUFreq on platforms using MIPS GIC based clockevents. Signed-off-by: Ezequiel Garcia Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10782/ Signed-off-by: Ralf Baechle --- drivers/clocksource/mips-gic-timer.c | 31 +++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/drivers/clocksource/mips-gic-timer.c b/drivers/clocksource/mips-gic-timer.c index 22a4daf5f0c8b..a155bec06d18a 100644 --- a/drivers/clocksource/mips-gic-timer.c +++ b/drivers/clocksource/mips-gic-timer.c @@ -79,6 +79,13 @@ static void gic_clockevent_cpu_exit(struct clock_event_device *cd) disable_percpu_irq(gic_timer_irq); } +static void gic_update_frequency(void *data) +{ + unsigned long rate = (unsigned long)data; + + clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate); +} + static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -94,10 +101,26 @@ static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } +static int gic_clk_notifier(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct clk_notifier_data *cnd = data; + + if (action == POST_RATE_CHANGE) + on_each_cpu(gic_update_frequency, (void *)cnd->new_rate, 1); + + return NOTIFY_OK; +} + + static struct notifier_block gic_cpu_nb = { .notifier_call = gic_cpu_notifier, }; +static struct notifier_block gic_clk_nb = { + .notifier_call = gic_clk_notifier, +}; + static int gic_clockevent_init(void) { int ret; @@ -160,6 +183,7 @@ void __init gic_clocksource_init(unsigned int frequency) static void __init gic_clocksource_of_init(struct device_node *node) { struct clk *clk; + int ret; if (WARN_ON(!gic_present || !node->parent || !of_device_is_compatible(node->parent, "mti,gic"))) @@ -186,7 +210,12 @@ static void __init gic_clocksource_of_init(struct device_node *node) } __gic_clocksource_init(); - gic_clockevent_init(); + + ret = gic_clockevent_init(); + if (!ret && !IS_ERR(clk)) { + if (clk_notifier_register(clk, &gic_clk_nb) < 0) + pr_warn("GIC: Unable to register clock notifier\n"); + } /* And finally start the counter */ gic_start_count(); -- GitLab From d6ed2b9b60cb03091e0c84c270d145a475606297 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Mon, 27 Jul 2015 15:02:33 +0100 Subject: [PATCH 6187/7006] Documentation: dt: Add Pistachio SoC general purpose timer binding document Add a device-tree binding document for the clocksource driver provided by Pistachio SoC general purpose timers. Signed-off-by: Ezequiel Garcia Reviewed-by: Andrew Bresticker Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Daniel Lezcano Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10783/ Signed-off-by: Ralf Baechle --- .../bindings/timer/img,pistachio-gptimer.txt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt diff --git a/Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt b/Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt new file mode 100644 index 0000000000000..7afce80bf6a01 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/img,pistachio-gptimer.txt @@ -0,0 +1,28 @@ +* Pistachio general-purpose timer based clocksource + +Required properties: + - compatible: "img,pistachio-gptimer". + - reg: Address range of the timer registers. + - interrupts: An interrupt for each of the four timers + - clocks: Should contain a clock specifier for each entry in clock-names + - clock-names: Should contain the following entries: + "sys", interface clock + "slow", slow counter clock + "fast", fast counter clock + - img,cr-periph: Must contain a phandle to the peripheral control + syscon node. + +Example: + timer: timer@18102000 { + compatible = "img,pistachio-gptimer"; + reg = <0x18102000 0x100>; + interrupts = , + , + , + ; + clocks = <&clk_periph PERIPH_CLK_COUNTER_FAST>, + <&clk_periph PERIPH_CLK_COUNTER_SLOW>, + <&cr_periph SYS_CLK_TIMER>; + clock-names = "fast", "slow", "sys"; + img,cr-periph = <&cr_periph>; + }; -- GitLab From 84583983c31983068429d82e6f9262009d584549 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Fri, 7 Aug 2015 16:39:31 +0100 Subject: [PATCH 6188/7006] CLOCKSOURCE: Add Pistachio clocksource-only driver The Pistachio SoC provides four general purpose timers, and allow to implement a clocksource driver. This driver can be used as a replacement for the MIPS GIC and MIPS R4K clocksources and sched clocks, which are clocked from the CPU clock. Given the general purpose timers are clocked from an independent clock, this new clocksource driver will be useful to introduce CPUFreq support for Pistachio machines. Signed-off-by: Ezequiel Garcia Signed-off-by: Govindraj Raja Reviewed-by: Thomas Gleixner Acked-by: Daniel Lezcano Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: devicetree@vger.kernel.org Cc: Andrew Bresticker Cc: James Hartley Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Cc: Ezequiel Garcia Patchwork: https://patchwork.linux-mips.org/patch/10899/ Signed-off-by: Ralf Baechle --- drivers/clocksource/Kconfig | 4 + drivers/clocksource/Makefile | 1 + drivers/clocksource/time-pistachio.c | 217 +++++++++++++++++++++++++++ 3 files changed, 222 insertions(+) create mode 100644 drivers/clocksource/time-pistachio.c diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 4e57730e0be4e..74e002e80fd3c 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -111,6 +111,10 @@ config CLKSRC_LPC32XX select CLKSRC_MMIO select CLKSRC_OF +config CLKSRC_PISTACHIO + bool + select CLKSRC_OF + config CLKSRC_STM32 bool "Clocksource for STM32 SoCs" if !ARCH_STM32 depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index f228354961ca6..066337e247379 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o obj-$(CONFIG_MTK_TIMER) += mtk_timer.o +obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o diff --git a/drivers/clocksource/time-pistachio.c b/drivers/clocksource/time-pistachio.c new file mode 100644 index 0000000000000..18d4266c2986c --- /dev/null +++ b/drivers/clocksource/time-pistachio.c @@ -0,0 +1,217 @@ +/* + * Pistachio clocksource based on general-purpose timers + * + * Copyright (C) 2015 Imagination Technologies + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Top level reg */ +#define CR_TIMER_CTRL_CFG 0x00 +#define TIMER_ME_GLOBAL BIT(0) +#define CR_TIMER_REV 0x10 + +/* Timer specific registers */ +#define TIMER_CFG 0x20 +#define TIMER_ME_LOCAL BIT(0) +#define TIMER_RELOAD_VALUE 0x24 +#define TIMER_CURRENT_VALUE 0x28 +#define TIMER_CURRENT_OVERFLOW_VALUE 0x2C +#define TIMER_IRQ_STATUS 0x30 +#define TIMER_IRQ_CLEAR 0x34 +#define TIMER_IRQ_MASK 0x38 + +#define PERIP_TIMER_CONTROL 0x90 + +/* Timer specific configuration Values */ +#define RELOAD_VALUE 0xffffffff + +struct pistachio_clocksource { + void __iomem *base; + raw_spinlock_t lock; + struct clocksource cs; +}; + +static struct pistachio_clocksource pcs_gpt; + +#define to_pistachio_clocksource(cs) \ + container_of(cs, struct pistachio_clocksource, cs) + +static inline u32 gpt_readl(void __iomem *base, u32 offset, u32 gpt_id) +{ + return readl(base + 0x20 * gpt_id + offset); +} + +static inline void gpt_writel(void __iomem *base, u32 value, u32 offset, + u32 gpt_id) +{ + writel(value, base + 0x20 * gpt_id + offset); +} + +static cycle_t pistachio_clocksource_read_cycles(struct clocksource *cs) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 counter, overflw; + unsigned long flags; + + /* + * The counter value is only refreshed after the overflow value is read. + * And they must be read in strict order, hence raw spin lock added. + */ + + raw_spin_lock_irqsave(&pcs->lock, flags); + overflw = gpt_readl(pcs->base, TIMER_CURRENT_OVERFLOW_VALUE, 0); + counter = gpt_readl(pcs->base, TIMER_CURRENT_VALUE, 0); + raw_spin_unlock_irqrestore(&pcs->lock, flags); + + return ~(cycle_t)counter; +} + +static u64 notrace pistachio_read_sched_clock(void) +{ + return pistachio_clocksource_read_cycles(&pcs_gpt.cs); +} + +static void pistachio_clksrc_set_mode(struct clocksource *cs, int timeridx, + int enable) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + u32 val; + + val = gpt_readl(pcs->base, TIMER_CFG, timeridx); + if (enable) + val |= TIMER_ME_LOCAL; + else + val &= ~TIMER_ME_LOCAL; + + gpt_writel(pcs->base, val, TIMER_CFG, timeridx); +} + +static void pistachio_clksrc_enable(struct clocksource *cs, int timeridx) +{ + struct pistachio_clocksource *pcs = to_pistachio_clocksource(cs); + + /* Disable GPT local before loading reload value */ + pistachio_clksrc_set_mode(cs, timeridx, false); + gpt_writel(pcs->base, RELOAD_VALUE, TIMER_RELOAD_VALUE, timeridx); + pistachio_clksrc_set_mode(cs, timeridx, true); +} + +static void pistachio_clksrc_disable(struct clocksource *cs, int timeridx) +{ + /* Disable GPT local */ + pistachio_clksrc_set_mode(cs, timeridx, false); +} + +static int pistachio_clocksource_enable(struct clocksource *cs) +{ + pistachio_clksrc_enable(cs, 0); + return 0; +} + +static void pistachio_clocksource_disable(struct clocksource *cs) +{ + pistachio_clksrc_disable(cs, 0); +} + +/* Desirable clock source for pistachio platform */ +static struct pistachio_clocksource pcs_gpt = { + .cs = { + .name = "gptimer", + .rating = 300, + .enable = pistachio_clocksource_enable, + .disable = pistachio_clocksource_disable, + .read = pistachio_clocksource_read_cycles, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS | + CLOCK_SOURCE_SUSPEND_NONSTOP, + }, +}; + +static void __init pistachio_clksrc_of_init(struct device_node *node) +{ + struct clk *sys_clk, *fast_clk; + struct regmap *periph_regs; + unsigned long rate; + int ret; + + pcs_gpt.base = of_iomap(node, 0); + if (!pcs_gpt.base) { + pr_err("cannot iomap\n"); + return; + } + + periph_regs = syscon_regmap_lookup_by_phandle(node, "img,cr-periph"); + if (IS_ERR(periph_regs)) { + pr_err("cannot get peripheral regmap (%lu)\n", + PTR_ERR(periph_regs)); + return; + } + + /* Switch to using the fast counter clock */ + ret = regmap_update_bits(periph_regs, PERIP_TIMER_CONTROL, + 0xf, 0x0); + if (ret) + return; + + sys_clk = of_clk_get_by_name(node, "sys"); + if (IS_ERR(sys_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(sys_clk)); + return; + } + + fast_clk = of_clk_get_by_name(node, "fast"); + if (IS_ERR(fast_clk)) { + pr_err("clock get failed (%lu)\n", PTR_ERR(fast_clk)); + return; + } + + ret = clk_prepare_enable(sys_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + return; + } + + ret = clk_prepare_enable(fast_clk); + if (ret < 0) { + pr_err("failed to enable clock (%d)\n", ret); + clk_disable_unprepare(sys_clk); + return; + } + + rate = clk_get_rate(fast_clk); + + /* Disable irq's for clocksource usage */ + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 0); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 1); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 2); + gpt_writel(&pcs_gpt.base, 0, TIMER_IRQ_MASK, 3); + + /* Enable timer block */ + writel(TIMER_ME_GLOBAL, pcs_gpt.base); + + raw_spin_lock_init(&pcs_gpt.lock); + sched_clock_register(pistachio_read_sched_clock, 32, rate); + clocksource_register_hz(&pcs_gpt.cs, rate); +} +CLOCKSOURCE_OF_DECLARE(pistachio_gptimer, "img,pistachio-gptimer", + pistachio_clksrc_of_init); -- GitLab From af0cfb2c44ee5cd3c86d1ffd054d318f536cb6dd Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 6 Aug 2015 12:22:43 +0100 Subject: [PATCH 6189/7006] MIPS: pistachio: Allow to enable the external timer based clocksource This commit introduces a new config, so the user can choose to enable the General Purpose Timer based clocksource. This option is required to have CPUFreq support. Signed-off-by: Ezequiel Garcia Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Cc: Daniel Lezcano Cc: devicetree@vger.kernel.org Cc: Thomas Gleixner Cc: Andrew Bresticker Cc: James Hartley Cc: Govindraj Raja Cc: Damien Horsley Cc: James Hogan Cc: Ezequiel Garcia Cc: Ezequiel Garcia Patchwork: http://patchwork.linux-mips.org/patch/10887/ Signed-off-by: Ralf Baechle --- arch/mips/Kconfig | 1 + arch/mips/pistachio/Kconfig | 13 +++++++++++++ 2 files changed, 14 insertions(+) create mode 100644 arch/mips/pistachio/Kconfig diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 8083ef9c80d49..233d338c24b4a 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -951,6 +951,7 @@ source "arch/mips/jazz/Kconfig" source "arch/mips/jz4740/Kconfig" source "arch/mips/lantiq/Kconfig" source "arch/mips/lasat/Kconfig" +source "arch/mips/pistachio/Kconfig" source "arch/mips/pmcs-msp71xx/Kconfig" source "arch/mips/ralink/Kconfig" source "arch/mips/sgi-ip27/Kconfig" diff --git a/arch/mips/pistachio/Kconfig b/arch/mips/pistachio/Kconfig new file mode 100644 index 0000000000000..97731ea94322a --- /dev/null +++ b/arch/mips/pistachio/Kconfig @@ -0,0 +1,13 @@ +config PISTACHIO_GPTIMER_CLKSRC + bool "Enable General Purpose Timer based clocksource" + depends on MACH_PISTACHIO + select CLKSRC_PISTACHIO + select MIPS_EXTERNAL_TIMER + help + This option enables a clocksource driver based on a Pistachio + SoC General Purpose external timer. + + If you want to enable the CPUFreq, you need to enable + this option. + + If you don't want to enable CPUFreq, you can leave this disabled. -- GitLab From c0034c30ed301e28c72dc516156baabf5840ce5f Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:33 +0300 Subject: [PATCH 6190/7006] MIPS: Octeon: Fix CN6880 hang on XAUI init Some CN68XX series Octeon II chips seem to hang if a reset is issued on XAUI initialization. Avoid the hang by disabling the reset on affected models. Tested on Cavium EBB6800 evaluation board and Kontron S1901 board. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: http://patchwork.linux-mips.org/patch/10970/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index 7653b7e92197f..323a784f70711 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -151,7 +151,12 @@ int __cvmx_helper_xaui_enable(int interface) /* (4)c Aply reset sequence */ xauiCtl.u64 = cvmx_read_csr(CVMX_PCSXX_CONTROL1_REG(interface)); xauiCtl.s.lo_pwr = 0; - xauiCtl.s.reset = 1; + + /* Issuing a reset here seems to hang some CN68XX chips. */ + if (!OCTEON_IS_MODEL(OCTEON_CN68XX_PASS1_X) && + !OCTEON_IS_MODEL(OCTEON_CN68XX_PASS2_X)) + xauiCtl.s.reset = 1; + cvmx_write_csr(CVMX_PCSXX_CONTROL1_REG(interface), xauiCtl.u64); /* Wait for PCS to come out of reset */ -- GitLab From 2c8c3f0201333f430b632c6b62a5b81456284884 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:34 +0300 Subject: [PATCH 6191/7006] MIPS: Octeon: Support additional interfaces on CN68XX CN68XX has 9 interfaces. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10968/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index 7e5cf7a5e2f32..ed4816c283f07 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -83,6 +83,8 @@ static cvmx_helper_link_info_t */ int cvmx_helper_get_number_of_interfaces(void) { + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return 9; if (OCTEON_IS_MODEL(OCTEON_CN56XX) || OCTEON_IS_MODEL(OCTEON_CN52XX)) return 4; else -- GitLab From fce0af1dc34e2765357dfbd21dd923c89254bcdb Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:35 +0300 Subject: [PATCH 6192/7006] MIPS: Octeon: Support all PIP input ports on CN68XX CN68XX has 48 PIP input ports. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10969/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/octeon/cvmx-pip.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/include/asm/octeon/cvmx-pip.h b/arch/mips/include/asm/octeon/cvmx-pip.h index df69bfd2b006b..c210154ad941f 100644 --- a/arch/mips/include/asm/octeon/cvmx-pip.h +++ b/arch/mips/include/asm/octeon/cvmx-pip.h @@ -37,7 +37,7 @@ #include #include -#define CVMX_PIP_NUM_INPUT_PORTS 40 +#define CVMX_PIP_NUM_INPUT_PORTS 48 #define CVMX_PIP_NUM_WATCHERS 4 /* -- GitLab From 4397564542c18d2fee904b1e2c09ae15a871d853 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:36 +0300 Subject: [PATCH 6193/7006] MIPS: Octeon: Configure XAUI pkinds Configure the pkinds of XAUI interfaces on Octeon models that have them. This simple configuration uses 1:1 mapping between the PIP input port number and the selected pkind. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10971/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c index 323a784f70711..a56ee590de1f3 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-xaui.c @@ -124,6 +124,13 @@ int __cvmx_helper_xaui_enable(int interface) union cvmx_gmxx_tx_int_en gmx_tx_int_en; union cvmx_pcsxx_int_en_reg pcsx_int_en_reg; + /* Setup PKND */ + if (octeon_has_feature(OCTEON_FEATURE_PKND)) { + gmx_cfg.u64 = cvmx_read_csr(CVMX_GMXX_PRTX_CFG(0, interface)); + gmx_cfg.s.pknd = cvmx_helper_get_ipd_port(interface, 0); + cvmx_write_csr(CVMX_GMXX_PRTX_CFG(0, interface), gmx_cfg.u64); + } + /* (1) Interface has already been enabled. */ /* (2) Disable GMX. */ -- GitLab From b92084ba545b73933ca179d46fe11801f7f9d349 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:37 +0300 Subject: [PATCH 6194/7006] MIPS: Octeon: Configure minimum PKO packet sizes on CN68XX CN68XX has common minimum packet size filters that need to be configured for the traffic to work. Just set them to a default value. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10963/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper.c b/arch/mips/cavium-octeon/executive/cvmx-helper.c index ed4816c283f07..376701f41cc28 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper.c @@ -658,6 +658,21 @@ static int __cvmx_helper_global_setup_pko(void) fau_to.s.tout_val = 0xfff; fau_to.s.tout_enb = 0; cvmx_write_csr(CVMX_IOB_FAU_TIMEOUT, fau_to.u64); + + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + union cvmx_pko_reg_min_pkt min_pkt; + + min_pkt.u64 = 0; + min_pkt.s.size1 = 59; + min_pkt.s.size2 = 59; + min_pkt.s.size3 = 59; + min_pkt.s.size4 = 59; + min_pkt.s.size5 = 59; + min_pkt.s.size6 = 59; + min_pkt.s.size7 = 59; + cvmx_write_csr(CVMX_PKO_REG_MIN_PKT, min_pkt.u64); + } + return 0; } -- GitLab From 70b4e2ed4343f03bd7d64d6a58801ff28d231d34 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:38 +0300 Subject: [PATCH 6195/7006] MIPS: Octeon: Add definitions for setting up SSO Some Octeon II models have SSO instead of POW and use a different register for setting the interrupt thresholds. Add the necessary definitions for configuring the interrupts also on those models. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10972/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/octeon/cvmx-pow-defs.h | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/arch/mips/include/asm/octeon/cvmx-pow-defs.h b/arch/mips/include/asm/octeon/cvmx-pow-defs.h index 9020ef443736d..6a3db4b068ffc 100644 --- a/arch/mips/include/asm/octeon/cvmx-pow-defs.h +++ b/arch/mips/include/asm/octeon/cvmx-pow-defs.h @@ -52,6 +52,12 @@ #define CVMX_POW_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000000080ull) + ((offset) & 15) * 8) #define CVMX_POW_WS_PCX(offset) (CVMX_ADD_IO_SEG(0x0001670000000280ull) + ((offset) & 15) * 8) +#define CVMX_SSO_WQ_INT (CVMX_ADD_IO_SEG(0x0001670000001000ull)) +#define CVMX_SSO_WQ_IQ_DIS (CVMX_ADD_IO_SEG(0x0001670000001010ull)) +#define CVMX_SSO_WQ_INT_PC (CVMX_ADD_IO_SEG(0x0001670000001020ull)) +#define CVMX_SSO_PPX_GRP_MSK(offset) (CVMX_ADD_IO_SEG(0x0001670000006000ull) + ((offset) & 31) * 8) +#define CVMX_SSO_WQ_INT_THRX(offset) (CVMX_ADD_IO_SEG(0x0001670000007000ull) + ((offset) & 63) * 8) + union cvmx_pow_bist_stat { uint64_t u64; struct cvmx_pow_bist_stat_s { @@ -1286,4 +1292,27 @@ union cvmx_pow_ws_pcx { struct cvmx_pow_ws_pcx_s cnf71xx; }; +union cvmx_sso_wq_int_thrx { + uint64_t u64; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t reserved_33_63:31; + uint64_t tc_en:1; + uint64_t tc_thr:4; + uint64_t reserved_26_27:2; + uint64_t ds_thr:12; + uint64_t reserved_12_13:2; + uint64_t iq_thr:12; +#else + uint64_t iq_thr:12; + uint64_t reserved_12_13:2; + uint64_t ds_thr:12; + uint64_t reserved_26_27:2; + uint64_t tc_thr:4; + uint64_t tc_en:1; + uint64_t reserved_33_63:31; +#endif + } s; +}; + #endif -- GitLab From bcbb13964dd4174f3a512d6a4460173c5c252199 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 13 Aug 2015 16:21:39 +0300 Subject: [PATCH 6196/7006] STAGING: Octeon: Properly enable/disable SSO WQE interrupts The Octeon models with SSO instead of POW need to use a different register for configuring the WQE interrupt thresholds. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10964/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet-rx.c | 54 ++++++++++++++++++++-------- drivers/staging/octeon/ethernet.c | 5 ++- 2 files changed, 43 insertions(+), 16 deletions(-) diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 22853d33da052..1636bd9a5bc07 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -195,12 +195,19 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) prefetch(work); did_work_request = 0; if (work == NULL) { - union cvmx_pow_wq_int wq_int; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_write_csr(CVMX_SSO_WQ_IQ_DIS, + 1ull << pow_receive_group); + cvmx_write_csr(CVMX_SSO_WQ_INT, + 1ull << pow_receive_group); + } else { + union cvmx_pow_wq_int wq_int; - wq_int.u64 = 0; - wq_int.s.iq_dis = 1 << pow_receive_group; - wq_int.s.wq_int = 1 << pow_receive_group; - cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); + wq_int.u64 = 0; + wq_int.s.iq_dis = 1 << pow_receive_group; + wq_int.s.wq_int = 1 << pow_receive_group; + cvmx_write_csr(CVMX_POW_WQ_INT, wq_int.u64); + } break; } pskb = (struct sk_buff **)(cvm_oct_get_buffer_ptr(work->packet_ptr) - @@ -422,8 +429,6 @@ void cvm_oct_rx_initialize(void) { int i; struct net_device *dev_for_napi = NULL; - union cvmx_pow_wq_int_thrx int_thr; - union cvmx_pow_wq_int_pc int_pc; for (i = 0; i < TOTAL_NUMBER_OF_PORTS; i++) { if (cvm_oct_device[i]) { @@ -449,15 +454,34 @@ void cvm_oct_rx_initialize(void) disable_irq_nosync(OCTEON_IRQ_WORKQ0 + pow_receive_group); - int_thr.u64 = 0; - int_thr.s.tc_en = 1; - int_thr.s.tc_thr = 1; /* Enable POW interrupt when our port has at least one packet */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), int_thr.u64); - - int_pc.u64 = 0; - int_pc.s.pc_thr = 5; - cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + union cvmx_sso_wq_int_thrx int_thr; + union cvmx_pow_wq_int_pc int_pc; + + int_thr.u64 = 0; + int_thr.s.tc_en = 1; + int_thr.s.tc_thr = 1; + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), + int_thr.u64); + + int_pc.u64 = 0; + int_pc.s.pc_thr = 5; + cvmx_write_csr(CVMX_SSO_WQ_INT_PC, int_pc.u64); + } else { + union cvmx_pow_wq_int_thrx int_thr; + union cvmx_pow_wq_int_pc int_pc; + + int_thr.u64 = 0; + int_thr.s.tc_en = 1; + int_thr.s.tc_thr = 1; + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), + int_thr.u64); + + int_pc.u64 = 0; + int_pc.s.pc_thr = 5; + cvmx_write_csr(CVMX_POW_WQ_INT_PC, int_pc.u64); + } /* Schedule NAPI now. This will indirectly enable the interrupt. */ napi_schedule(&cvm_oct_napi); diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index f9dba23a37591..363742a0f6ee6 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -859,7 +859,10 @@ static int cvm_oct_remove(struct platform_device *pdev) int port; /* Disable POW interrupt */ - cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + cvmx_write_csr(CVMX_SSO_WQ_INT_THRX(pow_receive_group), 0); + else + cvmx_write_csr(CVMX_POW_WQ_INT_THRX(pow_receive_group), 0); cvmx_ipd_disable(); -- GitLab From f5cfc8db28e63d992d293d5b49d7cb8ec5214c56 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 13 Aug 2015 16:21:40 +0300 Subject: [PATCH 6197/7006] STAGING: Octeon: Set SSO group mask properly on CN68XX CN68XX uses SSO instead of POW. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10966/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet-rx.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index 1636bd9a5bc07..abfe9344e1975 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -172,9 +172,16 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } /* Only allow work for our group (and preserve priorities) */ - old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), - (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + old_group_mask = cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); + cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), + 1ull << pow_receive_group); + cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ + } else { + old_group_mask = cvmx_read_csr(CVMX_POW_PP_GRP_MSKX(coreid)); + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), + (old_group_mask & ~0xFFFFull) | 1 << pow_receive_group); + } if (USE_ASYNC_IOBDMA) { cvmx_pow_work_request_async(CVMX_SCR_SCRATCH, CVMX_POW_NO_WAIT); @@ -397,7 +404,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } } /* Restore the original POW group mask */ - cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + cvmx_write_csr(CVMX_SSO_PPX_GRP_MSK(coreid), old_group_mask); + cvmx_read_csr(CVMX_SSO_PPX_GRP_MSK(coreid)); /* Flush */ + } else { + cvmx_write_csr(CVMX_POW_PP_GRP_MSKX(coreid), old_group_mask); + } + if (USE_ASYNC_IOBDMA) { /* Restore the scratch area */ cvmx_scratch_write64(CVMX_SCR_SCRATCH, old_scratch); -- GitLab From d5f9bc7360fc130b6f26e7c0684bc61df29deb6a Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:41 +0300 Subject: [PATCH 6198/7006] STAGING: Octeon: Increase output command buffers The Octeon II models have more interfaces and thus require more output command buffers. Increase the allocation to support these models. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10965/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c index 363742a0f6ee6..fbde4191e717b 100644 --- a/drivers/staging/octeon/ethernet.c +++ b/drivers/staging/octeon/ethernet.c @@ -152,7 +152,7 @@ static void cvm_oct_configure_common_hw(void) num_packet_buffers); if (CVMX_FPA_OUTPUT_BUFFER_POOL != CVMX_FPA_PACKET_POOL) cvm_oct_mem_fill_fpa(CVMX_FPA_OUTPUT_BUFFER_POOL, - CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 128); + CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE, 1024); #ifdef __LITTLE_ENDIAN { -- GitLab From f8023da8ae40c275403568d6f9fc9b585c7f6fab Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:42 +0300 Subject: [PATCH 6199/7006] STAGING: Octeon: Support CN68XX style WQE CN68XX has a bit different WQE structure. This patch provides the new definitions and converts the code to use the proper variant based on the actual model. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10973/ Signed-off-by: Ralf Baechle --- .../executive/cvmx-helper-util.c | 8 +- arch/mips/include/asm/octeon/cvmx-pow.h | 9 +- arch/mips/include/asm/octeon/cvmx-wqe.h | 308 ++++++++++++++---- drivers/staging/octeon/ethernet-rx.c | 58 ++-- drivers/staging/octeon/ethernet-tx.c | 19 +- 5 files changed, 304 insertions(+), 98 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c index 453d7f66459aa..402959605276c 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c @@ -95,9 +95,9 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work) uint8_t *data_address; uint8_t *end_of_data; - cvmx_dprintf("Packet Length: %u\n", work->len); - cvmx_dprintf(" Input Port: %u\n", work->ipprt); - cvmx_dprintf(" QoS: %u\n", work->qos); + cvmx_dprintf("Packet Length: %u\n", work->word1.len); + cvmx_dprintf(" Input Port: %u\n", cvmx_wqe_get_port(work)); + cvmx_dprintf(" QoS: %u\n", cvmx_wqe_get_qos(work)); cvmx_dprintf(" Buffers: %u\n", work->word2.s.bufs); if (work->word2.s.bufs == 0) { @@ -127,7 +127,7 @@ int cvmx_helper_dump_packet(cvmx_wqe_t *work) } } else buffer_ptr = work->packet_ptr; - remaining_bytes = work->len; + remaining_bytes = work->word1.len; while (remaining_bytes) { start_of_buffer = diff --git a/arch/mips/include/asm/octeon/cvmx-pow.h b/arch/mips/include/asm/octeon/cvmx-pow.h index d5565d758dddd..51531563f8dc9 100644 --- a/arch/mips/include/asm/octeon/cvmx-pow.h +++ b/arch/mips/include/asm/octeon/cvmx-pow.h @@ -1810,10 +1810,11 @@ static inline void cvmx_pow_work_submit(cvmx_wqe_t *wqp, uint32_t tag, cvmx_addr_t ptr; cvmx_pow_tag_req_t tag_req; - wqp->qos = qos; - wqp->tag = tag; - wqp->tag_type = tag_type; - wqp->grp = grp; + wqp->word1.tag = tag; + wqp->word1.tag_type = tag_type; + + cvmx_wqe_set_qos(wqp, qos); + cvmx_wqe_set_grp(wqp, grp); tag_req.u64 = 0; tag_req.s.op = CVMX_POW_TAG_OP_ADDWQ; diff --git a/arch/mips/include/asm/octeon/cvmx-wqe.h b/arch/mips/include/asm/octeon/cvmx-wqe.h index 2d6d0c7127a75..0d697aa786d4c 100644 --- a/arch/mips/include/asm/octeon/cvmx-wqe.h +++ b/arch/mips/include/asm/octeon/cvmx-wqe.h @@ -193,6 +193,53 @@ typedef union { uint64_t bufs:8; #endif } s; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t bufs:8; + uint64_t ip_offset:8; + uint64_t vlan_valid:1; + uint64_t vlan_stacked:1; + uint64_t unassigned:1; + uint64_t vlan_cfi:1; + uint64_t vlan_id:12; + uint64_t port:12; /* MAC/PIP port number. */ + uint64_t dec_ipcomp:1; + uint64_t tcp_or_udp:1; + uint64_t dec_ipsec:1; + uint64_t is_v6:1; + uint64_t software:1; + uint64_t L4_error:1; + uint64_t is_frag:1; + uint64_t IP_exc:1; + uint64_t is_bcast:1; + uint64_t is_mcast:1; + uint64_t not_IP:1; + uint64_t rcv_error:1; + uint64_t err_code:8; +#else + uint64_t err_code:8; + uint64_t rcv_error:1; + uint64_t not_IP:1; + uint64_t is_mcast:1; + uint64_t is_bcast:1; + uint64_t IP_exc:1; + uint64_t is_frag:1; + uint64_t L4_error:1; + uint64_t software:1; + uint64_t is_v6:1; + uint64_t dec_ipsec:1; + uint64_t tcp_or_udp:1; + uint64_t dec_ipcomp:1; + uint64_t port:12; + uint64_t vlan_id:12; + uint64_t vlan_cfi:1; + uint64_t unassigned:1; + uint64_t vlan_stacked:1; + uint64_t vlan_valid:1; + uint64_t ip_offset:8; + uint64_t bufs:8; +#endif + } s_cn68xx; /* use this to get at the 16 vlan bits */ struct { @@ -355,6 +402,146 @@ typedef union { } cvmx_pip_wqe_word2; +union cvmx_pip_wqe_word0 { + struct { +#ifdef __BIG_ENDIAN_BITFIELD + /** + * raw chksum result generated by the HW + */ + uint16_t hw_chksum; + /** + * Field unused by hardware - available for software + */ + uint8_t unused; + /** + * Next pointer used by hardware for list maintenance. + * May be written/read by HW before the work queue + * entry is scheduled to a PP (Only 36 bits used in + * Octeon 1) + */ + uint64_t next_ptr:40; +#else + uint64_t next_ptr:40; + uint8_t unused; + uint16_t hw_chksum; +#endif + } cn38xx; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t l4ptr:8; /* 56..63 */ + uint64_t unused0:8; /* 48..55 */ + uint64_t l3ptr:8; /* 40..47 */ + uint64_t l2ptr:8; /* 32..39 */ + uint64_t unused1:18; /* 14..31 */ + uint64_t bpid:6; /* 8..13 */ + uint64_t unused2:2; /* 6..7 */ + uint64_t pknd:6; /* 0..5 */ +#else + uint64_t pknd:6; /* 0..5 */ + uint64_t unused2:2; /* 6..7 */ + uint64_t bpid:6; /* 8..13 */ + uint64_t unused1:18; /* 14..31 */ + uint64_t l2ptr:8; /* 32..39 */ + uint64_t l3ptr:8; /* 40..47 */ + uint64_t unused0:8; /* 48..55 */ + uint64_t l4ptr:8; /* 56..63 */ +#endif + } cn68xx; +}; + +union cvmx_wqe_word0 { + uint64_t u64; + union cvmx_pip_wqe_word0 pip; +}; + +union cvmx_wqe_word1 { + uint64_t u64; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t len:16; + uint64_t varies:14; + /** + * the type of the tag (ORDERED, ATOMIC, NULL) + */ + uint64_t tag_type:2; + uint64_t tag:32; +#else + uint64_t tag:32; + uint64_t tag_type:2; + uint64_t varies:14; + uint64_t len:16; +#endif + }; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + uint64_t len:16; + uint64_t zero_0:1; + /** + * HW sets this to what it thought the priority of + * the input packet was + */ + uint64_t qos:3; + + uint64_t zero_1:1; + /** + * the group that the work queue entry will be scheduled to + */ + uint64_t grp:6; + uint64_t zero_2:3; + uint64_t tag_type:2; + uint64_t tag:32; +#else + uint64_t tag:32; + uint64_t tag_type:2; + uint64_t zero_2:3; + uint64_t grp:6; + uint64_t zero_1:1; + uint64_t qos:3; + uint64_t zero_0:1; + uint64_t len:16; +#endif + } cn68xx; + struct { +#ifdef __BIG_ENDIAN_BITFIELD + /** + * HW sets to the total number of bytes in the packet + */ + uint64_t len:16; + /** + * HW sets this to input physical port + */ + uint64_t ipprt:6; + + /** + * HW sets this to what it thought the priority of + * the input packet was + */ + uint64_t qos:3; + + /** + * the group that the work queue entry will be scheduled to + */ + uint64_t grp:4; + /** + * the type of the tag (ORDERED, ATOMIC, NULL) + */ + uint64_t tag_type:3; + /** + * the synchronization/ordering tag + */ + uint64_t tag:32; +#else + uint64_t tag:32; + uint64_t tag_type:2; + uint64_t zero_2:1; + uint64_t grp:4; + uint64_t qos:3; + uint64_t ipprt:6; + uint64_t len:16; +#endif + } cn38xx; +}; + /** * Work queue entry format * @@ -366,70 +553,13 @@ typedef struct { * WORD 0 * HW WRITE: the following 64 bits are filled by HW when a packet arrives */ - -#ifdef __BIG_ENDIAN_BITFIELD - /** - * raw chksum result generated by the HW - */ - uint16_t hw_chksum; - /** - * Field unused by hardware - available for software - */ - uint8_t unused; - /** - * Next pointer used by hardware for list maintenance. - * May be written/read by HW before the work queue - * entry is scheduled to a PP - * (Only 36 bits used in Octeon 1) - */ - uint64_t next_ptr:40; -#else - uint64_t next_ptr:40; - uint8_t unused; - uint16_t hw_chksum; -#endif + union cvmx_wqe_word0 word0; /***************************************************************** * WORD 1 * HW WRITE: the following 64 bits are filled by HW when a packet arrives */ - -#ifdef __BIG_ENDIAN_BITFIELD - /** - * HW sets to the total number of bytes in the packet - */ - uint64_t len:16; - /** - * HW sets this to input physical port - */ - uint64_t ipprt:6; - - /** - * HW sets this to what it thought the priority of the input packet was - */ - uint64_t qos:3; - - /** - * the group that the work queue entry will be scheduled to - */ - uint64_t grp:4; - /** - * the type of the tag (ORDERED, ATOMIC, NULL) - */ - uint64_t tag_type:3; - /** - * the synchronization/ordering tag - */ - uint64_t tag:32; -#else - uint64_t tag:32; - uint64_t tag_type:2; - uint64_t zero_2:1; - uint64_t grp:4; - uint64_t qos:3; - uint64_t ipprt:6; - uint64_t len:16; -#endif + union cvmx_wqe_word1 word1; /** * WORD 2 HW WRITE: the following 64-bits are filled in by @@ -465,4 +595,64 @@ typedef struct { } CVMX_CACHE_LINE_ALIGNED cvmx_wqe_t; +static inline int cvmx_wqe_get_port(cvmx_wqe_t *work) +{ + int port; + + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + port = work->word2.s_cn68xx.port; + else + port = work->word1.cn38xx.ipprt; + + return port; +} + +static inline void cvmx_wqe_set_port(cvmx_wqe_t *work, int port) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word2.s_cn68xx.port = port; + else + work->word1.cn38xx.ipprt = port; +} + +static inline int cvmx_wqe_get_grp(cvmx_wqe_t *work) +{ + int grp; + + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + grp = work->word1.cn68xx.grp; + else + grp = work->word1.cn38xx.grp; + + return grp; +} + +static inline void cvmx_wqe_set_grp(cvmx_wqe_t *work, int grp) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word1.cn68xx.grp = grp; + else + work->word1.cn38xx.grp = grp; +} + +static inline int cvmx_wqe_get_qos(cvmx_wqe_t *work) +{ + int qos; + + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + qos = work->word1.cn68xx.qos; + else + qos = work->word1.cn38xx.qos; + + return qos; +} + +static inline void cvmx_wqe_set_qos(cvmx_wqe_t *work, int qos) +{ + if (octeon_has_feature(OCTEON_FEATURE_CN68XX_WQE)) + work->word1.cn68xx.qos = qos; + else + work->word1.cn38xx.qos = qos; +} + #endif /* __CVMX_WQE_H__ */ diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c index abfe9344e1975..d1a33a927f6d1 100644 --- a/drivers/staging/octeon/ethernet-rx.c +++ b/drivers/staging/octeon/ethernet-rx.c @@ -70,7 +70,14 @@ static irqreturn_t cvm_oct_do_interrupt(int cpl, void *dev_id) */ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) { - if ((work->word2.snoip.err_code == 10) && (work->len <= 64)) { + int port; + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + port = work->word0.pip.cn68xx.pknd; + else + port = work->word1.cn38xx.ipprt; + + if ((work->word2.snoip.err_code == 10) && (work->word1.len <= 64)) { /* * Ignore length errors on min size packets. Some * equipment incorrectly pads packets to 64+4FCS @@ -87,8 +94,8 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) * packet to determine if we can remove a non spec * preamble and generate a correct packet. */ - int interface = cvmx_helper_get_interface_num(work->ipprt); - int index = cvmx_helper_get_interface_index_num(work->ipprt); + int interface = cvmx_helper_get_interface_num(port); + int index = cvmx_helper_get_interface_index_num(port); union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl; gmxx_rxx_frm_ctl.u64 = @@ -99,7 +106,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) cvmx_phys_to_ptr(work->packet_ptr.s.addr); int i = 0; - while (i < work->len - 1) { + while (i < work->word1.len - 1) { if (*ptr != 0x55) break; ptr++; @@ -109,18 +116,18 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) if (*ptr == 0xd5) { /* printk_ratelimited("Port %d received 0xd5 preamble\n", - work->ipprt); + port); */ work->packet_ptr.s.addr += i + 1; - work->len -= i + 5; + work->word1.len -= i + 5; } else if ((*ptr & 0xf) == 0xd) { /* printk_ratelimited("Port %d received 0x?d preamble\n", - work->ipprt); + port); */ work->packet_ptr.s.addr += i; - work->len -= i + 4; - for (i = 0; i < work->len; i++) { + work->word1.len -= i + 4; + for (i = 0; i < work->word1.len; i++) { *ptr = ((*ptr & 0xf0) >> 4) | ((*(ptr + 1) & 0xf) << 4); @@ -128,7 +135,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) } } else { printk_ratelimited("Port %d unknown preamble, packet dropped\n", - work->ipprt); + port); /* cvmx_helper_dump_packet(work); */ @@ -138,7 +145,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work) } } else { printk_ratelimited("Port %d receive error code %d, packet dropped\n", - work->ipprt, work->word2.snoip.err_code); + port, work->word2.snoip.err_code); cvm_oct_free_work(work); return 1; } @@ -193,6 +200,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) struct sk_buff **pskb = NULL; int skb_in_hw; cvmx_wqe_t *work; + int port; if (USE_ASYNC_IOBDMA && did_work_request) work = cvmx_pow_work_response_async(CVMX_SCR_SCRATCH); @@ -234,7 +242,13 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) prefetch(&skb->head); prefetch(&skb->len); } - prefetch(cvm_oct_device[work->ipprt]); + + if (octeon_has_feature(OCTEON_FEATURE_PKND)) + port = work->word0.pip.cn68xx.pknd; + else + port = work->word1.cn38xx.ipprt; + + prefetch(cvm_oct_device[port]); /* Immediately throw away all packets with receive errors */ if (unlikely(work->word2.snoip.rcv_error)) { @@ -251,7 +265,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) skb->data = skb->head + work->packet_ptr.s.addr - cvmx_ptr_to_phys(skb->head); prefetch(skb->data); - skb->len = work->len; + skb->len = work->word1.len; skb_set_tail_pointer(skb, skb->len); packet_not_copied = 1; } else { @@ -259,7 +273,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) * We have to copy the packet. First allocate * an skbuff for it. */ - skb = dev_alloc_skb(work->len); + skb = dev_alloc_skb(work->word1.len); if (!skb) { cvm_oct_free_work(work); continue; @@ -282,13 +296,14 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) else ptr += 6; } - memcpy(skb_put(skb, work->len), ptr, work->len); + memcpy(skb_put(skb, work->word1.len), ptr, + work->word1.len); /* No packet buffers to free */ } else { int segments = work->word2.s.bufs; union cvmx_buf_ptr segment_ptr = work->packet_ptr; - int len = work->len; + int len = work->word1.len; while (segments--) { union cvmx_buf_ptr next_ptr = @@ -324,10 +339,9 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) } packet_not_copied = 0; } - - if (likely((work->ipprt < TOTAL_NUMBER_OF_PORTS) && - cvm_oct_device[work->ipprt])) { - struct net_device *dev = cvm_oct_device[work->ipprt]; + if (likely((port < TOTAL_NUMBER_OF_PORTS) && + cvm_oct_device[port])) { + struct net_device *dev = cvm_oct_device[port]; struct octeon_ethernet *priv = netdev_priv(dev); /* @@ -347,7 +361,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) skb->ip_summed = CHECKSUM_UNNECESSARY; /* Increment RX stats for virtual ports */ - if (work->ipprt >= CVMX_PIP_NUM_INPUT_PORTS) { + if (port >= CVMX_PIP_NUM_INPUT_PORTS) { #ifdef CONFIG_64BIT atomic64_add(1, (atomic64_t *)&priv->stats.rx_packets); @@ -382,7 +396,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget) * doesn't exist. */ printk_ratelimited("Port %d not controlled by Linux, packet dropped\n", - work->ipprt); + port); dev_kfree_skb_irq(skb); } /* diff --git a/drivers/staging/octeon/ethernet-tx.c b/drivers/staging/octeon/ethernet-tx.c index 7c1c1b052b7d1..588354756c57e 100644 --- a/drivers/staging/octeon/ethernet-tx.c +++ b/drivers/staging/octeon/ethernet-tx.c @@ -589,13 +589,14 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) * Fill in some of the work queue fields. We may need to add * more if the software at the other end needs them. */ - work->hw_chksum = skb->csum; - work->len = skb->len; - work->ipprt = priv->port; - work->qos = priv->port & 0x7; - work->grp = pow_send_group; - work->tag_type = CVMX_HELPER_INPUT_TAG_TYPE; - work->tag = pow_send_group; /* FIXME */ + if (!OCTEON_IS_MODEL(OCTEON_CN68XX)) + work->word0.pip.cn38xx.hw_chksum = skb->csum; + work->word1.len = skb->len; + cvmx_wqe_set_port(work, priv->port); + cvmx_wqe_set_qos(work, priv->port & 0x7); + cvmx_wqe_set_grp(work, pow_send_group); + work->word1.tag_type = CVMX_HELPER_INPUT_TAG_TYPE; + work->word1.tag = pow_send_group; /* FIXME */ /* Default to zero. Sets of zero later are commented out */ work->word2.u64 = 0; work->word2.s.bufs = 1; @@ -675,8 +676,8 @@ int cvm_oct_xmit_pow(struct sk_buff *skb, struct net_device *dev) } /* Submit the packet to the POW */ - cvmx_pow_work_submit(work, work->tag, work->tag_type, work->qos, - work->grp); + cvmx_pow_work_submit(work, work->word1.tag, work->word1.tag_type, + cvmx_wqe_get_qos(work), cvmx_wqe_get_grp(work)); priv->stats.tx_packets++; priv->stats.tx_bytes += skb->len; dev_consume_skb_any(skb); -- GitLab From 153bfe381356226ed4c330bb2dff957a6e6c3986 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:43 +0300 Subject: [PATCH 6200/7006] MIPS: Octeon: Initialize CN68XX PKO CN68XX requires a different PKO configuration. This patch provides just enough setup to get the XAUI interfaces on CN6880 working with default parameters. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10974/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-pko.c | 149 ++++++++++++++++++- 1 file changed, 144 insertions(+), 5 deletions(-) diff --git a/arch/mips/cavium-octeon/executive/cvmx-pko.c b/arch/mips/cavium-octeon/executive/cvmx-pko.c index 008b881cdf647..87be167a7a6ae 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-pko.c +++ b/arch/mips/cavium-octeon/executive/cvmx-pko.c @@ -39,6 +39,143 @@ * Internal state of packet output */ +static int __cvmx_pko_int(int interface, int index) +{ + switch (interface) { + case 0: + return index; + case 1: + return 4; + case 2: + return index + 0x08; + case 3: + return index + 0x0c; + case 4: + return index + 0x10; + case 5: + return 0x1c; + case 6: + return 0x1d; + case 7: + return 0x1e; + case 8: + return 0x1f; + default: + return -1; + } +} + +static void __cvmx_pko_iport_config(int pko_port) +{ + int queue; + const int num_queues = 1; + const int base_queue = pko_port; + const int static_priority_end = 1; + const int static_priority_base = 1; + + for (queue = 0; queue < num_queues; queue++) { + union cvmx_pko_mem_iqueue_ptrs config; + cvmx_cmd_queue_result_t cmd_res; + uint64_t *buf_ptr; + + config.u64 = 0; + config.s.index = queue; + config.s.qid = base_queue + queue; + config.s.ipid = pko_port; + config.s.tail = (queue == (num_queues - 1)); + config.s.s_tail = (queue == static_priority_end); + config.s.static_p = (static_priority_base >= 0); + config.s.static_q = (queue <= static_priority_end); + config.s.qos_mask = 0xff; + + cmd_res = cvmx_cmd_queue_initialize( + CVMX_CMD_QUEUE_PKO(base_queue + queue), + CVMX_PKO_MAX_QUEUE_DEPTH, + CVMX_FPA_OUTPUT_BUFFER_POOL, + (CVMX_FPA_OUTPUT_BUFFER_POOL_SIZE - + CVMX_PKO_COMMAND_BUFFER_SIZE_ADJUST * 8)); + + WARN(cmd_res, + "%s: cmd_res=%d pko_port=%d base_queue=%d num_queues=%d queue=%d\n", + __func__, (int)cmd_res, pko_port, base_queue, + num_queues, queue); + + buf_ptr = (uint64_t *)cvmx_cmd_queue_buffer( + CVMX_CMD_QUEUE_PKO(base_queue + queue)); + config.s.buf_ptr = cvmx_ptr_to_phys(buf_ptr) >> 7; + CVMX_SYNCWS; + cvmx_write_csr(CVMX_PKO_MEM_IQUEUE_PTRS, config.u64); + } +} + +static void __cvmx_pko_queue_alloc_o68(void) +{ + int port; + + for (port = 0; port < 48; port++) + __cvmx_pko_iport_config(port); +} + +static void __cvmx_pko_port_map_o68(void) +{ + int port; + int interface, index; + cvmx_helper_interface_mode_t mode; + union cvmx_pko_mem_iport_ptrs config; + + /* + * Initialize every iport with the invalid eid. + */ + config.u64 = 0; + config.s.eid = 31; /* Invalid */ + for (port = 0; port < 128; port++) { + config.s.ipid = port; + cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); + } + + /* + * Set up PKO_MEM_IPORT_PTRS + */ + for (port = 0; port < 48; port++) { + interface = cvmx_helper_get_interface_num(port); + index = cvmx_helper_get_interface_index_num(port); + mode = cvmx_helper_interface_get_mode(interface); + if (mode == CVMX_HELPER_INTERFACE_MODE_DISABLED) + continue; + + config.s.ipid = port; + config.s.qos_mask = 0xff; + config.s.crc = 1; + config.s.min_pkt = 1; + config.s.intr = __cvmx_pko_int(interface, index); + config.s.eid = config.s.intr; + config.s.pipe = (mode == CVMX_HELPER_INTERFACE_MODE_LOOP) ? + index : port; + cvmx_write_csr(CVMX_PKO_MEM_IPORT_PTRS, config.u64); + } +} + +static void __cvmx_pko_chip_init(void) +{ + int i; + + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) { + __cvmx_pko_port_map_o68(); + __cvmx_pko_queue_alloc_o68(); + return; + } + + /* + * Initialize queues + */ + for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) { + const uint64_t priority = 8; + + cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, + &priority); + } +} + /** * Call before any other calls to initialize the packet * output system. This does chip global config, and should only be @@ -47,8 +184,6 @@ void cvmx_pko_initialize_global(void) { - int i; - uint64_t priority = 8; union cvmx_pko_reg_cmd_buf config; /* @@ -62,9 +197,10 @@ void cvmx_pko_initialize_global(void) cvmx_write_csr(CVMX_PKO_REG_CMD_BUF, config.u64); - for (i = 0; i < CVMX_PKO_MAX_OUTPUT_QUEUES; i++) - cvmx_pko_config_port(CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID, i, 1, - &priority); + /* + * Chip-specific setup. + */ + __cvmx_pko_chip_init(); /* * If we aren't using all of the queues optimize PKO's @@ -212,6 +348,9 @@ cvmx_pko_status_t cvmx_pko_config_port(uint64_t port, uint64_t base_queue, int static_priority_base = -1; int static_priority_end = -1; + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return CVMX_PKO_SUCCESS; + if ((port >= CVMX_PKO_NUM_OUTPUT_PORTS) && (port != CVMX_PKO_MEM_QUEUE_PTRS_ILLEGAL_PID)) { cvmx_dprintf("ERROR: cvmx_pko_config_port: Invalid port %llu\n", -- GitLab From 85847d8033b66c2f36e9a992ff3873fb10d72b80 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:44 +0300 Subject: [PATCH 6201/7006] MIPS: Octeon: Set up 1:1 mapping between CN68XX PKO queues and ports Use the internal port number also as the queue number on CN68XX. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10962/ Signed-off-by: Ralf Baechle --- arch/mips/include/asm/octeon/cvmx-pko.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/mips/include/asm/octeon/cvmx-pko.h b/arch/mips/include/asm/octeon/cvmx-pko.h index 3da59bb8ce24f..5f47f76ed510a 100644 --- a/arch/mips/include/asm/octeon/cvmx-pko.h +++ b/arch/mips/include/asm/octeon/cvmx-pko.h @@ -542,6 +542,9 @@ static inline int cvmx_pko_get_base_queue_per_core(int port, int core) */ static inline int cvmx_pko_get_base_queue(int port) { + if (OCTEON_IS_MODEL(OCTEON_CN68XX)) + return port; + return cvmx_pko_get_base_queue_per_core(port, 0); } -- GitLab From 31705376a2fd71f5c5b596fb2d3b2c6232a6268a Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:45 +0300 Subject: [PATCH 6202/7006] MIPS: Octeon: Support interfaces 4 and 5 Add the support for mapping between interface/port numbers and IPD port numbers also for the additional interfaces some Octeon II models have. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10967/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-util.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c index 402959605276c..b45b2975746db 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-util.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-util.c @@ -382,6 +382,10 @@ int cvmx_helper_get_ipd_port(int interface, int port) return port + 32; case 3: return port + 36; + case 4: + return port + 40; + case 5: + return port + 44; } return -1; } @@ -404,6 +408,10 @@ int cvmx_helper_get_interface_num(int ipd_port) return 2; else if (ipd_port < 40) return 3; + else if (ipd_port < 44) + return 4; + else if (ipd_port < 48) + return 5; else cvmx_dprintf("cvmx_helper_get_interface_num: Illegal IPD " "port number\n"); @@ -428,6 +436,10 @@ int cvmx_helper_get_interface_index_num(int ipd_port) return ipd_port & 3; else if (ipd_port < 40) return ipd_port & 3; + else if (ipd_port < 44) + return ipd_port & 3; + else if (ipd_port < 48) + return ipd_port & 3; else cvmx_dprintf("cvmx_helper_get_interface_index_num: " "Illegal IPD port number\n"); -- GitLab From 1d39a5e4ce09172358a5435a3411a46e76a04bb4 Mon Sep 17 00:00:00 2001 From: Janne Huttunen Date: Thu, 13 Aug 2015 16:21:46 +0300 Subject: [PATCH 6203/7006] STAGING: Octeon: Use common helpers for determining interface and port Currently the Octeon Ethernet driver hardcodes the mapping between interface/port and IPD port number. Since we have generic helpers for the very same purpose, we might as well use them instead. This prevents having the same information in multiple places. Signed-off-by: Janne Huttunen Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: David Daney Cc: linux-mips@linux-mips.org Cc: Janne Huttunen Cc: Aaro Koskinen Cc: Greg Kroah-Hartman Cc: devel@driverdev.osuosl.org Patchwork: https://patchwork.linux-mips.org/patch/10975/ Signed-off-by: Ralf Baechle --- drivers/staging/octeon/ethernet-util.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/staging/octeon/ethernet-util.h b/drivers/staging/octeon/ethernet-util.h index 1ba789a7741bd..45f024bc5e33f 100644 --- a/drivers/staging/octeon/ethernet-util.h +++ b/drivers/staging/octeon/ethernet-util.h @@ -8,6 +8,10 @@ * published by the Free Software Foundation. */ +#include +#include +#include + /** * cvm_oct_get_buffer_ptr - convert packet data address to pointer * @packet_ptr: Packet data hardware address @@ -28,14 +32,12 @@ static inline void *cvm_oct_get_buffer_ptr(union cvmx_buf_ptr packet_ptr) */ static inline int INTERFACE(int ipd_port) { - if (ipd_port < 32) /* Interface 0 or 1 for RGMII,GMII,SPI, etc */ - return ipd_port >> 4; - else if (ipd_port < 36) /* Interface 2 for NPI */ - return 2; - else if (ipd_port < 40) /* Interface 3 for loopback */ - return 3; - else if (ipd_port == 40) /* Non existent interface for POW0 */ - return 4; + int interface = cvmx_helper_get_interface_num(ipd_port); + + if (interface >= 0) + return interface; + else if (ipd_port == CVMX_PIP_NUM_INPUT_PORTS) + return 10; panic("Illegal ipd_port %d passed to INTERFACE\n", ipd_port); } @@ -47,7 +49,5 @@ static inline int INTERFACE(int ipd_port) */ static inline int INDEX(int ipd_port) { - if (ipd_port < 32) - return ipd_port & 15; - return ipd_port & 3; + return cvmx_helper_get_interface_index_num(ipd_port); } -- GitLab From e5dd8f2cf65cb228fad881ecd35093d8409d17c6 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 7 Aug 2015 09:59:10 +0200 Subject: [PATCH 6204/7006] MIPS: BCM47xx: Use kmemdup rather than duplicating its implementation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The patch was generated using fixed coccinelle semantic patch scripts/coccinelle/api/memdup.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2014320 Signed-off-by: Andrzej Hajda Acked-by: Hauke Mehrtens Cc: Hauke Mehrtens Cc: Rafał Miłecki Cc: Andrzej Hajda Cc: Bartlomiej Zolnierkiewicz Cc: Marek Szyprowski Cc: linux-kernel@vger.kernel.org Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10898/ Signed-off-by: Ralf Baechle --- arch/mips/bcm47xx/buttons.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c index 08a4abf09a33e..52caa75bfe4e5 100644 --- a/arch/mips/bcm47xx/buttons.c +++ b/arch/mips/bcm47xx/buttons.c @@ -396,10 +396,9 @@ static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons, { size_t size = nbuttons * sizeof(*buttons); - bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL); + bcm47xx_button_pdata.buttons = kmemdup(buttons, size, GFP_KERNEL); if (!bcm47xx_button_pdata.buttons) return -ENOMEM; - memcpy(bcm47xx_button_pdata.buttons, buttons, size); bcm47xx_button_pdata.nbuttons = nbuttons; return 0; -- GitLab From cef232ec86cdadfa7f58c7db140084db0b6cc9db Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Tue, 11 Aug 2015 10:56:28 +0300 Subject: [PATCH 6205/7006] MIPS: Octeon: Fix management port MII address on Kontron S1901 Management port MII address is incorrect on Kontron S1901 resulting in broken networking. Fix by providing definitions for the in-tree DT pruning code. Signed-off-by: Aaro Koskinen Acked-by: David Daney Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10914/ Signed-off-by: Ralf Baechle --- arch/mips/cavium-octeon/executive/cvmx-helper-board.c | 6 ++++++ arch/mips/include/asm/octeon/cvmx-bootinfo.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c index 9eb0feef44172..36e30d65ba05b 100644 --- a/arch/mips/cavium-octeon/executive/cvmx-helper-board.c +++ b/arch/mips/cavium-octeon/executive/cvmx-helper-board.c @@ -195,6 +195,12 @@ int cvmx_helper_board_get_mii_address(int ipd_port) return 8; else return -1; + case CVMX_BOARD_TYPE_KONTRON_S1901: + if (ipd_port == CVMX_HELPER_BOARD_MGMT_IPD_PORT) + return 1; + else + return -1; + } /* Some unknown board. Somebody forgot to update this function... */ diff --git a/arch/mips/include/asm/octeon/cvmx-bootinfo.h b/arch/mips/include/asm/octeon/cvmx-bootinfo.h index c373d95b5e2cf..d92cf59bdae63 100644 --- a/arch/mips/include/asm/octeon/cvmx-bootinfo.h +++ b/arch/mips/include/asm/octeon/cvmx-bootinfo.h @@ -284,6 +284,7 @@ enum cvmx_board_types_enum { CVMX_BOARD_TYPE_CUST_PRIVATE_MIN = 20001, CVMX_BOARD_TYPE_UBNT_E100 = 20002, CVMX_BOARD_TYPE_CUST_DSR1000N = 20006, + CVMX_BOARD_TYPE_KONTRON_S1901 = 21901, CVMX_BOARD_TYPE_CUST_PRIVATE_MAX = 30000, /* The remaining range is reserved for future use. */ @@ -384,6 +385,7 @@ static inline const char *cvmx_board_type_to_string(enum ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MIN) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_UBNT_E100) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_DSR1000N) + ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_KONTRON_S1901) ENUM_BRD_TYPE_CASE(CVMX_BOARD_TYPE_CUST_PRIVATE_MAX) } return "Unsupported Board"; -- GitLab From 107d34009ef00d1680521be2c4a1cba31f9b69a6 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:27 +0200 Subject: [PATCH 6206/7006] MIPS: inst.h: Add new MIPS R6 FPU opcodes Add opcodes for the new MIPS R6 FPU instructions. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10952/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/inst.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/mips/include/uapi/asm/inst.h b/arch/mips/include/uapi/asm/inst.h index 3dce80e679488..9b44d5a816fa3 100644 --- a/arch/mips/include/uapi/asm/inst.h +++ b/arch/mips/include/uapi/asm/inst.h @@ -167,8 +167,13 @@ enum cop1_sdw_func { fround_op = 0x0c, ftrunc_op = 0x0d, fceil_op = 0x0e, ffloor_op = 0x0f, fmovc_op = 0x11, fmovz_op = 0x12, - fmovn_op = 0x13, frecip_op = 0x15, - frsqrt_op = 0x16, fcvts_op = 0x20, + fmovn_op = 0x13, fseleqz_op = 0x14, + frecip_op = 0x15, frsqrt_op = 0x16, + fselnez_op = 0x17, fmaddf_op = 0x18, + fmsubf_op = 0x19, frint_op = 0x1a, + fclass_op = 0x1b, fmin_op = 0x1c, + fmina_op = 0x1d, fmax_op = 0x1e, + fmaxa_op = 0x1f, fcvts_op = 0x20, fcvtd_op = 0x21, fcvte_op = 0x22, fcvtw_op = 0x24, fcvtl_op = 0x25, fcmp_op = 0x30 -- GitLab From f8c3c6717a7128f9601b20f890d658283d59561a Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:28 +0200 Subject: [PATCH 6207/7006] MIPS: math-emu: Add support for the CMP.condn.fmt R6 instruction Add support for emulating the new CMP.condn.fmt R6 instructions and return SIGILL for the old C.cond.fmt if R2 emulation is not enabled since it's not supported by R6. The functionality of the new CMP.condn.fmt is the following one: If the comparison specified by the condn field of the instruction is true for the operand values, the result is true; otherwise, the result is false. If no exception is taken, the result is written into FPR fd; true is all 1s and false is all 0s repeated the operand width of fmt. All other bits beyond the operand width fmt are UNPREDICTABLE. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10953/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 130 +++++++++++++++++++++++++++++++++--- 1 file changed, 121 insertions(+), 9 deletions(-) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 8a5b0eb4ddef4..ef41fc895e75a 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1394,6 +1394,14 @@ static const unsigned char cmptab[8] = { IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */ }; +static const unsigned char negative_cmptab[8] = { + 0, /* Reserved */ + IEEE754_CLT | IEEE754_CGT | IEEE754_CEQ, + IEEE754_CLT | IEEE754_CGT | IEEE754_CUN, + IEEE754_CLT | IEEE754_CGT, + /* Reserved */ +}; + /* * Additional MIPS4 instructions @@ -1838,7 +1846,7 @@ copcsr: goto copcsr; default: - if (MIPSInst_FUNC(ir) >= fcmp_op) { + if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; union ieee754sp fs, ft; @@ -2015,7 +2023,7 @@ dcopuop: goto copcsr; default: - if (MIPSInst_FUNC(ir) >= fcmp_op) { + if (!NO_R6EMU && MIPSInst_FUNC(ir) >= fcmp_op) { unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op; union ieee754dp fs, ft; @@ -2057,10 +2065,65 @@ dcopuop: rv.d = ieee754dp_fint(fs.bits); rfmt = d_fmt; goto copcsr; - default: - return SIGILL; + default: { + /* Emulating the new CMP.condn.fmt R6 instruction */ +#define CMPOP_MASK 0x7 +#define SIGN_BIT (0x1 << 3) +#define PREDICATE_BIT (0x1 << 4) + + int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; + int sig = MIPSInst_FUNC(ir) & SIGN_BIT; + union ieee754sp fs, ft; + + /* This is an R6 only instruction */ + if (!cpu_has_mips_r6 || + (MIPSInst_FUNC(ir) & 0x20)) + return SIGILL; + + /* fmt is w_fmt for single precision so fix it */ + rfmt = s_fmt; + /* default to false */ + rv.w = 0; + + /* CMP.condn.S */ + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(ft, MIPSInst_FT(ir)); + + /* positive predicates */ + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + if (ieee754sp_cmp(fs, ft, cmptab[cmpop], + sig)) + rv.w = -1; /* true, all 1s */ + if ((sig) && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + } else { + /* negative predicates */ + switch (cmpop) { + case 1: + case 2: + case 3: + if (ieee754sp_cmp(fs, ft, + negative_cmptab[cmpop], + sig)) + rv.w = -1; /* true, all 1s */ + if (sig && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + break; + default: + /* Reserved R6 ops */ + pr_err("Reserved MIPS R6 CMP.condn.S operation\n"); + return SIGILL; + } + } + break; + } } - break; } case l_fmt: @@ -2081,11 +2144,60 @@ dcopuop: rv.d = ieee754dp_flong(bits); rfmt = d_fmt; goto copcsr; - default: - return SIGILL; - } - break; + default: { + /* Emulating the new CMP.condn.fmt R6 instruction */ + int cmpop = MIPSInst_FUNC(ir) & CMPOP_MASK; + int sig = MIPSInst_FUNC(ir) & SIGN_BIT; + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6 || + (MIPSInst_FUNC(ir) & 0x20)) + return SIGILL; + /* fmt is l_fmt for double precision so fix it */ + rfmt = d_fmt; + /* default to false */ + rv.l = 0; + + /* CMP.condn.D */ + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(ft, MIPSInst_FT(ir)); + + /* positive predicates */ + if (!(MIPSInst_FUNC(ir) & PREDICATE_BIT)) { + if (ieee754dp_cmp(fs, ft, + cmptab[cmpop], sig)) + rv.l = -1LL; /* true, all 1s */ + if (sig && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + } else { + /* negative predicates */ + switch (cmpop) { + case 1: + case 2: + case 3: + if (ieee754dp_cmp(fs, ft, + negative_cmptab[cmpop], + sig)) + rv.l = -1LL; /* true, all 1s */ + if (sig && + ieee754_cxtest(IEEE754_INVALID_OPERATION)) + rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S; + else + goto copcsr; + break; + default: + /* Reserved R6 ops */ + pr_err("Reserved MIPS R6 CMP.condn.D operation\n"); + return SIGILL; + } + } + break; + } + } default: return SIGILL; } -- GitLab From 67613f02788d73541c7c9b1c851061b8c223057b Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:29 +0200 Subject: [PATCH 6208/7006] MIPS: math-emu: Add support for the MIPS R6 SELEQZ FPU instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIPS R6 introduced the following instruction: SELEQZ.fmt: FPR[fd]  FPR[ft].bit0 ? 0 : FPR[fs] Add support for emulating the single and double precision formats of the said instruction. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10954/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index ef41fc895e75a..02ba536f15948 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1743,6 +1743,17 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(rv.s, MIPSInst_FS(ir)); break; + case fseleqz_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(rv.s, MIPSInst_FT(ir)); + if (rv.w & 0x1) + rv.w = 0; + else + SPFROMREG(rv.s, MIPSInst_FS(ir)); + break; + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1940,6 +1951,18 @@ copcsr: return 0; DPFROMREG(rv.d, MIPSInst_FS(ir)); break; + + case fseleqz_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(rv.d, MIPSInst_FT(ir)); + if (rv.l & 0x1) + rv.l = 0; + else + DPFROMREG(rv.d, MIPSInst_FS(ir)); + break; + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; -- GitLab From 130fe357ee895421a4aefef7b1285bf52f295afe Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:30 +0200 Subject: [PATCH 6209/7006] MIPS: math-emu: Add support for the MIPS R6 SELNEZ FPU instruction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIPS R6 introduced the following instruction: SELNEZ.fmt: FPR[fd]  FPR[ft].bit0 ? FPR[fs] : 0 Add support for emulating the single and double precision formats of the said instruction. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10955/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 02ba536f15948..8978d52adf0e7 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1754,6 +1754,17 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(rv.s, MIPSInst_FS(ir)); break; + case fselnez_op: + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(rv.s, MIPSInst_FT(ir)); + if (rv.w & 0x1) + SPFROMREG(rv.s, MIPSInst_FS(ir)); + else + rv.w = 0; + break; + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1963,6 +1974,17 @@ copcsr: DPFROMREG(rv.d, MIPSInst_FS(ir)); break; + case fselnez_op: + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(rv.d, MIPSInst_FT(ir)); + if (rv.l & 0x1) + DPFROMREG(rv.d, MIPSInst_FS(ir)); + else + rv.l = 0; + break; + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; -- GitLab From e24c3bec3e8e254a3784b3e4c97bd3a76fbcc807 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:31 +0200 Subject: [PATCH 6210/7006] MIPS: math-emu: Add support for the MIPS R6 MADDF FPU instruction MIPS R6 introduced the following instruction: Floating Point Fused Multiply Add: MADDF.fmt To perform a fused multiply-add of FP values. MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10956/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 26 ++++ arch/mips/math-emu/dp_maddf.c | 265 ++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 5 + arch/mips/math-emu/sp_maddf.c | 255 ++++++++++++++++++++++++++++++++ 5 files changed, 553 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_maddf.c create mode 100644 arch/mips/math-emu/sp_maddf.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 2e5f96275c38a..c40816f86a7a8 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o \ + dp_tint.o dp_fint.o dp_maddf.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o \ + sp_tint.o sp_fint.o sp_maddf.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 8978d52adf0e7..67390ec2c2f8e 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1765,6 +1765,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, rv.w = 0; break; + case fmaddf_op: { + union ieee754sp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(fd, MIPSInst_FD(ir)); + rv.s = ieee754sp_maddf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1985,6 +1998,19 @@ copcsr: rv.l = 0; break; + case fmaddf_op: { + union ieee754dp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(fd, MIPSInst_FD(ir)); + rv.d = ieee754dp_maddf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_maddf.c b/arch/mips/math-emu/dp_maddf.c new file mode 100644 index 0000000000000..119eda9fa1ea8 --- /dev/null +++ b/arch/mips/math-emu/dp_maddf.c @@ -0,0 +1,265 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MADDF.f (Fused Multiply Add) + * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + int re; + int rs; + u64 rm; + unsigned lxm; + unsigned hxm; + unsigned lym; + unsigned hym; + u64 lrm; + u64 hrm; + u64 t; + u64 at; + int s; + + COMPXDP; + COMPYDP; + + u64 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXDP; + EXPLODEYDP; + EXPLODEDP(z, zc, zs, ze, zm) + + FLUSHXDP; + FLUSHYDP; + FLUSHDP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + DPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* fall through to real computations */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 64 - (DP_FBITS + 1); + ym <<= 64 - (DP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x, y) ((u64)(x) * (u64)y) + + lxm = xm; + hxm = xm >> 32; + lym = ym; + hym = ym >> 32; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + t = DPXMULT(lxm, hym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + t = DPXMULT(hxm, lym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((s64) rm < 0) { + rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | + ((rm << (DP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | + ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + + /* And now the addition */ + assert(zm & DP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + rm = XDPSRS(rm, s); + re += s; + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + zm = XDPSRS(zm, s); + ze += s; + } + assert(ze == re); + assert(ze <= DP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in xm, xs and xe. + */ + zm = zm + rm; + + if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ + zm = XDPSRS1(zm); + ze++; + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize to rounding precision. + */ + while ((zm >> (DP_FBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + } + + return ieee754dp_format(zs, ze, zm); +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index a5ca108ce4679..4e025f9e220c4 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -75,6 +75,9 @@ int ieee754sp_cmp(union ieee754sp x, union ieee754sp y, int cop, int sig); union ieee754sp ieee754sp_sqrt(union ieee754sp x); +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y); + /* * double precision (often aka double) */ @@ -99,6 +102,8 @@ int ieee754dp_cmp(union ieee754dp x, union ieee754dp y, int cop, int sig); union ieee754dp ieee754dp_sqrt(union ieee754dp x); +union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, + union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_maddf.c b/arch/mips/math-emu/sp_maddf.c new file mode 100644 index 0000000000000..dd1dd83e34eb0 --- /dev/null +++ b/arch/mips/math-emu/sp_maddf.c @@ -0,0 +1,255 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MADDF.f (Fused Multiply Add) + * MADDF.fmt: FPR[fd] = FPR[fd] + (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + int re; + int rs; + unsigned rm; + unsigned short lxm; + unsigned short hxm; + unsigned short lym; + unsigned short hym; + unsigned lrm; + unsigned hrm; + unsigned t; + unsigned at; + int s; + + COMPXSP; + COMPYSP; + u32 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXSP; + EXPLODEYSP; + EXPLODESP(z, zc, zs, ze, zm) + + FLUSHXSP; + FLUSHYSP; + FLUSHSP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + SPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* fall through to real computations */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + + /* rm = xm * ym, re = xe+ye basically */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 32 - (SP_FBITS + 1); + ym <<= 32 - (SP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + lxm = xm & 0xffff; + hxm = xm >> 16; + lym = ym & 0xffff; + hym = ym >> 16; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + t = lxm * hym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + t = hxm * lym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | + ((rm << (SP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | + ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + /* And now the addition */ + + assert(zm & SP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + SPXSRSYn(s); + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + SPXSRSYn(s); + } + assert(ze == re); + assert(ze <= SP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in zm, zs and ze. + */ + zm = zm + rm; + + if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize in extended single precision + */ + while ((zm >> (SP_MBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + + } + return ieee754sp_format(zs, ze, zm); +} -- GitLab From 83d43305a1df2aa2976e3ccf012e4cf0dc29673d Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:32 +0200 Subject: [PATCH 6211/7006] MIPS: math-emu: Add support for the MIPS R6 MSUBF FPU instruction MIPS R6 introduced the following instruction: Floating Point Fused Multiply Subtract: MSUBF.fmt To perform a fused multiply-subtract of FP values. MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10957/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 26 ++++ arch/mips/math-emu/dp_msubf.c | 269 ++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 4 + arch/mips/math-emu/sp_msubf.c | 258 ++++++++++++++++++++++++++++++++ 5 files changed, 559 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_msubf.c create mode 100644 arch/mips/math-emu/sp_msubf.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index c40816f86a7a8..0037690521eeb 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 67390ec2c2f8e..54964b372992f 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1778,6 +1778,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case fmsubf_op: { + union ieee754sp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + SPFROMREG(fd, MIPSInst_FD(ir)); + rv.s = ieee754sp_msubf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2011,6 +2024,19 @@ copcsr: break; } + case fmsubf_op: { + union ieee754dp ft, fs, fd; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + DPFROMREG(fd, MIPSInst_FD(ir)); + rv.d = ieee754dp_msubf(fd, fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_msubf.c b/arch/mips/math-emu/dp_msubf.c new file mode 100644 index 0000000000000..12241262f8561 --- /dev/null +++ b/arch/mips/math-emu/dp_msubf.c @@ -0,0 +1,269 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MSUB.f (Fused Multiply Subtract) + * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y) +{ + int re; + int rs; + u64 rm; + unsigned lxm; + unsigned hxm; + unsigned lym; + unsigned hym; + u64 lrm; + u64 hrm; + u64 t; + u64 at; + int s; + + COMPXDP; + COMPYDP; + + u64 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXDP; + EXPLODEYDP; + EXPLODEDP(z, zc, zs, ze, zm) + + FLUSHXDP; + FLUSHYDP; + FLUSHDP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + DPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754dp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754dp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + DPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754dp_inf(zs); + /* fall through to real computations */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 64 - (DP_FBITS + 1); + ym <<= 64 - (DP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + + /* 32 * 32 => 64 */ +#define DPXMULT(x, y) ((u64)(x) * (u64)y) + + lxm = xm; + hxm = xm >> 32; + lym = ym; + hym = ym >> 32; + + lrm = DPXMULT(lxm, lym); + hrm = DPXMULT(hxm, hym); + + t = DPXMULT(lxm, hym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + t = DPXMULT(hxm, lym); + + at = lrm + (t << 32); + hrm += at < lrm; + lrm = at; + + hrm = hrm + (t >> 32); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((s64) rm < 0) { + rm = (rm >> (64 - (DP_FBITS + 1 + 3))) | + ((rm << (DP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (64 - (DP_FBITS + 1 + 3 + 1))) | + ((rm << (DP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (DP_HIDDEN_BIT << 3)); + + /* And now the subtraction */ + + /* flip sign of r and handle as add */ + rs ^= 1; + + assert(zm & DP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + rm = XDPSRS(rm, s); + re += s; + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + zm = XDPSRS(zm, s); + ze += s; + } + assert(ze == re); + assert(ze <= DP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in xm, xs and xe. + */ + zm = zm + rm; + + if (zm >> (DP_FBITS + 1 + 3)) { /* carry out */ + zm = XDPSRS1(zm); + ze++; + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754dp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize to rounding precision. + */ + while ((zm >> (DP_FBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + } + + return ieee754dp_format(zs, ze, zm); +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 4e025f9e220c4..8c780190a0592 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -77,6 +77,8 @@ union ieee754sp ieee754sp_sqrt(union ieee754sp x); union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y); /* * double precision (often aka double) @@ -104,6 +106,8 @@ union ieee754dp ieee754dp_sqrt(union ieee754dp x); union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, + union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_msubf.c b/arch/mips/math-emu/sp_msubf.c new file mode 100644 index 0000000000000..81c38b980d69a --- /dev/null +++ b/arch/mips/math-emu/sp_msubf.c @@ -0,0 +1,258 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MSUB.f (Fused Multiply Subtract) + * MSUBF.fmt: FPR[fd] = FPR[fd] - (FPR[fs] x FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, + union ieee754sp y) +{ + int re; + int rs; + unsigned rm; + unsigned short lxm; + unsigned short hxm; + unsigned short lym; + unsigned short hym; + unsigned lrm; + unsigned hrm; + unsigned t; + unsigned at; + int s; + + COMPXSP; + COMPYSP; + u32 zm; int ze; int zs __maybe_unused; int zc; + + EXPLODEXSP; + EXPLODEYSP; + EXPLODESP(z, zc, zs, ze, zm) + + FLUSHXSP; + FLUSHYSP; + FLUSHSP(z, zc, zs, ze, zm); + + ieee754_clearcx(); + + switch (zc) { + case IEEE754_CLASS_SNAN: + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_nanxcpt(z); + case IEEE754_CLASS_DNORM: + SPDNORMx(zm, ze); + /* QNAN is handled separately below */ + } + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return y; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return x; + + /* + * Infinity handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + ieee754_setcx(IEEE754_INVALID_OPERATION); + return ieee754sp_indef(); + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + if (zc == IEEE754_CLASS_QNAN) + return z; + return ieee754sp_inf(xs ^ ys); + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* Multiplication is 0 so just return z */ + return z; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + SPDNORMX; + break; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_NORM): + if (zc == IEEE754_CLASS_QNAN) + return z; + else if (zc == IEEE754_CLASS_INF) + return ieee754sp_inf(zs); + /* fall through to real compuation */ + } + + /* Finally get to do some computation */ + + /* + * Do the multiplication bit first + * + * rm = xm * ym, re = xe + ye basically + * + * At this point xm and ym should have been normalized. + */ + + /* rm = xm * ym, re = xe+ye basically */ + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + re = xe + ye; + rs = xs ^ ys; + + /* shunt to top of word */ + xm <<= 32 - (SP_FBITS + 1); + ym <<= 32 - (SP_FBITS + 1); + + /* + * Multiply 32 bits xm, ym to give high 32 bits rm with stickness. + */ + lxm = xm & 0xffff; + hxm = xm >> 16; + lym = ym & 0xffff; + hym = ym >> 16; + + lrm = lxm * lym; /* 16 * 16 => 32 */ + hrm = hxm * hym; /* 16 * 16 => 32 */ + + t = lxm * hym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + t = hxm * lym; /* 16 * 16 => 32 */ + at = lrm + (t << 16); + hrm += at < lrm; + lrm = at; + hrm = hrm + (t >> 16); + + rm = hrm | (lrm != 0); + + /* + * Sticky shift down to normal rounding precision. + */ + if ((int) rm < 0) { + rm = (rm >> (32 - (SP_FBITS + 1 + 3))) | + ((rm << (SP_FBITS + 1 + 3)) != 0); + re++; + } else { + rm = (rm >> (32 - (SP_FBITS + 1 + 3 + 1))) | + ((rm << (SP_FBITS + 1 + 3 + 1)) != 0); + } + assert(rm & (SP_HIDDEN_BIT << 3)); + + /* And now the subtraction */ + + /* Flip sign of r and handle as add */ + rs ^= 1; + + assert(zm & SP_HIDDEN_BIT); + + /* + * Provide guard,round and stick bit space. + */ + zm <<= 3; + + if (ze > re) { + /* + * Have to shift y fraction right to align. + */ + s = ze - re; + SPXSRSYn(s); + } else if (re > ze) { + /* + * Have to shift x fraction right to align. + */ + s = re - ze; + SPXSRSYn(s); + } + assert(ze == re); + assert(ze <= SP_EMAX); + + if (zs == rs) { + /* + * Generate 28 bit result of adding two 27 bit numbers + * leaving result in zm, zs and ze. + */ + zm = zm + rm; + + if (zm >> (SP_FBITS + 1 + 3)) { /* carry out */ + SPXSRSX1(); /* shift preserving sticky */ + } + } else { + if (zm >= rm) { + zm = zm - rm; + } else { + zm = rm - zm; + zs = rs; + } + if (zm == 0) + return ieee754sp_zero(ieee754_csr.rm == FPU_CSR_RD); + + /* + * Normalize in extended single precision + */ + while ((zm >> (SP_MBITS + 3)) == 0) { + zm <<= 1; + ze--; + } + + } + return ieee754sp_format(zs, ze, zm); +} -- GitLab From 400bd2e41393a783e0532321fdb369d2cc15ea26 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:33 +0200 Subject: [PATCH 6212/7006] MIPS: math-emu: Add support for the MIPS R6 RINT FPU instruction MIPS R6 introduced the following instruction: Floating-Point Round to Integral Scalar floating-point round to integral floating point value. RINT.fmt: FPR[fd] = round_int(FPR[fs]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10958/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/cp1emu.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 54964b372992f..a348cbefe4a8e 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1791,6 +1791,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case frint_op: { + union ieee754sp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754sp_tlong(fs); + rv.s = ieee754sp_flong(rv.l); + goto copcsr; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2037,6 +2049,18 @@ copcsr: break; } + case frint_op: { + union ieee754dp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.l = ieee754dp_tlong(fs); + rv.d = ieee754dp_flong(rv.l); + goto copcsr; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; -- GitLab From 38db37ba069f9d801ef56b820cfc7c247a7ffc02 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:34 +0200 Subject: [PATCH 6213/7006] MIPS: math-emu: Add support for the MIPS R6 CLASS FPU instruction MIPS R6 introduced the following instruction: Stores in fd a bit mask reflecting the floating-point class of the floating point scalar value fs. CLASS.fmt: FPR[fd] = class(FPR[fs]) Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10959/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +-- arch/mips/math-emu/cp1emu.c | 24 ++++++++++++++ arch/mips/math-emu/dp_2008class.c | 55 +++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 2 ++ arch/mips/math-emu/sp_2008class.c | 55 +++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_2008class.c create mode 100644 arch/mips/math-emu/sp_2008class.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index 0037690521eeb..ea8db2607d076 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index a348cbefe4a8e..b65b4ea602328 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1803,6 +1803,18 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto copcsr; } + case fclass_op: { + union ieee754sp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754sp_2008class(fs); + rfmt = w_fmt; + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2061,6 +2073,18 @@ copcsr: goto copcsr; } + case fclass_op: { + union ieee754dp fs; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.w = ieee754dp_2008class(fs); + rfmt = w_fmt; + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_2008class.c b/arch/mips/math-emu/dp_2008class.c new file mode 100644 index 0000000000000..9dc39fc4835e1 --- /dev/null +++ b/arch/mips/math-emu/dp_2008class.c @@ -0,0 +1,55 @@ +/* + * IEEE754 floating point arithmetic + * double precision: CLASS.f + * FPR[fd] = class(FPR[fs]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +int ieee754dp_2008class(union ieee754dp x) +{ + COMPXDP; + + EXPLODEXDP; + + /* + * 10 bit mask as follows: + * + * bit0 = SNAN + * bit1 = QNAN + * bit2 = -INF + * bit3 = -NORM + * bit4 = -DNORM + * bit5 = -ZERO + * bit6 = INF + * bit7 = NORM + * bit8 = DNORM + * bit9 = ZERO + */ + + switch(xc) { + case IEEE754_CLASS_SNAN: + return 0x01; + case IEEE754_CLASS_QNAN: + return 0x02; + case IEEE754_CLASS_INF: + return 0x04 << (xs ? 0 : 4); + case IEEE754_CLASS_NORM: + return 0x08 << (xs ? 0 : 4); + case IEEE754_CLASS_DNORM: + return 0x10 << (xs ? 0 : 4); + case IEEE754_CLASS_ZERO: + return 0x20 << (xs ? 0 : 4); + default: + pr_err("Unknown class: %d\n", xc); + return 0; + } +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 8c780190a0592..3b833eac48f52 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -79,6 +79,7 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp y); union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, union ieee754sp y); +int ieee754sp_2008class(union ieee754sp x); /* * double precision (often aka double) @@ -108,6 +109,7 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp y); union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, union ieee754dp y); +int ieee754dp_2008class(union ieee754dp x); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_2008class.c b/arch/mips/math-emu/sp_2008class.c new file mode 100644 index 0000000000000..ff62606a1465d --- /dev/null +++ b/arch/mips/math-emu/sp_2008class.c @@ -0,0 +1,55 @@ +/* + * IEEE754 floating point arithmetic + * single precision: CLASS.f + * FPR[fd] = class(FPR[fs]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +int ieee754sp_2008class(union ieee754sp x) +{ + COMPXSP; + + EXPLODEXSP; + + /* + * 10 bit mask as follows: + * + * bit0 = SNAN + * bit1 = QNAN + * bit2 = -INF + * bit3 = -NORM + * bit4 = -DNORM + * bit5 = -ZERO + * bit6 = INF + * bit7 = NORM + * bit8 = DNORM + * bit9 = ZERO + */ + + switch(xc) { + case IEEE754_CLASS_SNAN: + return 0x01; + case IEEE754_CLASS_QNAN: + return 0x02; + case IEEE754_CLASS_INF: + return 0x04 << (xs ? 0 : 4); + case IEEE754_CLASS_NORM: + return 0x08 << (xs ? 0 : 4); + case IEEE754_CLASS_DNORM: + return 0x10 << (xs ? 0 : 4); + case IEEE754_CLASS_ZERO: + return 0x20 << (xs ? 0 : 4); + default: + pr_err("Unknown class: %d\n", xc); + return 0; + } +} -- GitLab From 4e9561b20e2f5c1170704a81ec7e1ac961ba5e68 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:35 +0200 Subject: [PATCH 6214/7006] MIPS: math-emu: Add support for the MIPS R6 MIN{, A} FPU instruction MIPS R6 introduced the following instruction: Scalar Floating-Point Minimum and Scalar Floating-Point argument with Minimum Absolute Value MIN.fmt writes the minimum value of the inputs fs and ft to the destination fd. MINA.fmt takes input arguments fs and ft and writes the argument with the minimum absolute value to the destination fd. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10960/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 48 ++++++++ arch/mips/math-emu/dp_fmin.c | 213 +++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 4 + arch/mips/math-emu/sp_fmin.c | 213 +++++++++++++++++++++++++++++++++++ 5 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_fmin.c create mode 100644 arch/mips/math-emu/sp_fmin.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index ea8db2607d076..b9946322804eb 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index b65b4ea602328..f397bdfd93fb1 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1815,6 +1815,30 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case fmin_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmin(fs, ft); + break; + } + + case fmina_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmina(fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2085,6 +2109,30 @@ copcsr: break; } + case fmin_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmin(fs, ft); + break; + } + + case fmina_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmina(fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_fmin.c b/arch/mips/math-emu/dp_fmin.c new file mode 100644 index 0000000000000..c1072b0dfb951 --- /dev/null +++ b/arch/mips/math-emu/dp_fmin.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MIN{,A}.f + * MIN : Scalar Floating-Point Minimum + * MINA: Scalar Floating-Point argument with Minimum Absolute Value + * + * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft]) + * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? x : y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? y : x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return x; + else if (xs < ys) + return y; + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} + +union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 3b833eac48f52..6a16357a1ddd7 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -80,6 +80,8 @@ union ieee754sp ieee754sp_maddf(union ieee754sp z, union ieee754sp x, union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, union ieee754sp y); int ieee754sp_2008class(union ieee754sp x); +union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y); /* * double precision (often aka double) @@ -110,6 +112,8 @@ union ieee754dp ieee754dp_maddf(union ieee754dp z, union ieee754dp x, union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, union ieee754dp y); int ieee754dp_2008class(union ieee754dp x); +union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_fmin.c b/arch/mips/math-emu/sp_fmin.c new file mode 100644 index 0000000000000..4eb1bb9e9dec7 --- /dev/null +++ b/arch/mips/math-emu/sp_fmin.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MIN{,A}.f + * MIN : Scalar Floating-Point Minimum + * MINA: Scalar Floating-Point argument with Minimum Absolute Value + * + * MIN.S : FPR[fd] = minNum(FPR[fs],FPR[ft]) + * MINA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? x : y; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? y : x; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return x; + else if (xs < ys) + return y; + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} + +union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return y; + else if (xe < ye) + return x; + + /* Compare mantissa */ + if (xm <= ym) + return x; + return y; +} -- GitLab From a79f5f9ba5088f157482feaa6ae2bacc9da0f5db Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Thu, 13 Aug 2015 09:56:36 +0200 Subject: [PATCH 6215/7006] MIPS: math-emu: Add support for the MIPS R6 MAX{, A} FPU instruction MIPS R6 introduced the following instruction: Scalar Floating-Point Maximum and Scalar Floating-Point argument with Maximum Absolute Value MAX.fmt writes the maximum value of the inputs fs and ft to the destination fd. MAXA.fmt takes input arguments fs and ft and writes the argument with the maximum absolute value to the destination fd. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10961/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/Makefile | 4 +- arch/mips/math-emu/cp1emu.c | 48 ++++++++ arch/mips/math-emu/dp_fmax.c | 213 +++++++++++++++++++++++++++++++++++ arch/mips/math-emu/ieee754.h | 4 + arch/mips/math-emu/sp_fmax.c | 213 +++++++++++++++++++++++++++++++++++ 5 files changed, 480 insertions(+), 2 deletions(-) create mode 100644 arch/mips/math-emu/dp_fmax.c create mode 100644 arch/mips/math-emu/sp_fmax.c diff --git a/arch/mips/math-emu/Makefile b/arch/mips/math-emu/Makefile index b9946322804eb..a19641d3ac23c 100644 --- a/arch/mips/math-emu/Makefile +++ b/arch/mips/math-emu/Makefile @@ -4,9 +4,9 @@ obj-y += cp1emu.o ieee754dp.o ieee754sp.o ieee754.o \ dp_div.o dp_mul.o dp_sub.o dp_add.o dp_fsp.o dp_cmp.o dp_simple.o \ - dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o \ + dp_tint.o dp_fint.o dp_maddf.o dp_msubf.o dp_2008class.o dp_fmin.o dp_fmax.o \ sp_div.o sp_mul.o sp_sub.o sp_add.o sp_fdp.o sp_cmp.o sp_simple.o \ - sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o \ + sp_tint.o sp_fint.o sp_maddf.o sp_msubf.o sp_2008class.o sp_fmin.o sp_fmax.o \ dsemul.o lib-y += ieee754d.o \ diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index f397bdfd93fb1..32f0e19a0d7f7 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -1839,6 +1839,30 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } + case fmax_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmax(fs, ft); + break; + } + + case fmaxa_op: { + union ieee754sp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + SPFROMREG(ft, MIPSInst_FT(ir)); + SPFROMREG(fs, MIPSInst_FS(ir)); + rv.s = ieee754sp_fmaxa(fs, ft); + break; + } + case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -2133,6 +2157,30 @@ copcsr: break; } + case fmax_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmax(fs, ft); + break; + } + + case fmaxa_op: { + union ieee754dp fs, ft; + + if (!cpu_has_mips_r6) + return SIGILL; + + DPFROMREG(ft, MIPSInst_FT(ir)); + DPFROMREG(fs, MIPSInst_FS(ir)); + rv.d = ieee754dp_fmaxa(fs, ft); + break; + } + case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; diff --git a/arch/mips/math-emu/dp_fmax.c b/arch/mips/math-emu/dp_fmax.c new file mode 100644 index 0000000000000..fd71b8daaaf20 --- /dev/null +++ b/arch/mips/math-emu/dp_fmax.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * double precision: MIN{,A}.f + * MIN : Scalar Floating-Point Minimum + * MINA: Scalar Floating-Point argument with Minimum Absolute Value + * + * MIN.D : FPR[fd] = minNum(FPR[fs],FPR[ft]) + * MINA.D: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754dp.h" + +union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? y : x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? x : y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return y; + else if (xs < ys) + return x; + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} + +union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y) +{ + COMPXDP; + COMPYDP; + + EXPLODEXDP; + EXPLODEYDP; + + FLUSHXDP; + FLUSHYDP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754dp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754dp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754dp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + DPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + DPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + DPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & DP_HIDDEN_BIT); + assert(ym & DP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} diff --git a/arch/mips/math-emu/ieee754.h b/arch/mips/math-emu/ieee754.h index 6a16357a1ddd7..df94720714c73 100644 --- a/arch/mips/math-emu/ieee754.h +++ b/arch/mips/math-emu/ieee754.h @@ -82,6 +82,8 @@ union ieee754sp ieee754sp_msubf(union ieee754sp z, union ieee754sp x, int ieee754sp_2008class(union ieee754sp x); union ieee754sp ieee754sp_fmin(union ieee754sp x, union ieee754sp y); union ieee754sp ieee754sp_fmina(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y); +union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y); /* * double precision (often aka double) @@ -114,6 +116,8 @@ union ieee754dp ieee754dp_msubf(union ieee754dp z, union ieee754dp x, int ieee754dp_2008class(union ieee754dp x); union ieee754dp ieee754dp_fmin(union ieee754dp x, union ieee754dp y); union ieee754dp ieee754dp_fmina(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_fmax(union ieee754dp x, union ieee754dp y); +union ieee754dp ieee754dp_fmaxa(union ieee754dp x, union ieee754dp y); /* 5 types of floating point number diff --git a/arch/mips/math-emu/sp_fmax.c b/arch/mips/math-emu/sp_fmax.c new file mode 100644 index 0000000000000..4d000844e48e3 --- /dev/null +++ b/arch/mips/math-emu/sp_fmax.c @@ -0,0 +1,213 @@ +/* + * IEEE754 floating point arithmetic + * single precision: MAX{,A}.f + * MAX : Scalar Floating-Point Maximum + * MAXA: Scalar Floating-Point argument with Maximum Absolute Value + * + * MAX.S : FPR[fd] = maxNum(FPR[fs],FPR[ft]) + * MAXA.S: FPR[fd] = maxNumMag(FPR[fs],FPR[ft]) + * + * MIPS floating point support + * Copyright (C) 2015 Imagination Technologies, Ltd. + * Author: Markos Chandras + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; version 2 of the License. + */ + +#include "ieee754sp.h" + +union ieee754sp ieee754sp_fmax(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return xs ? y : x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return ys ? x : y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare signs */ + if (xs > ys) + return y; + else if (xs < ys) + return x; + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} + +union ieee754sp ieee754sp_fmaxa(union ieee754sp x, union ieee754sp y) +{ + COMPXSP; + COMPYSP; + + EXPLODEXSP; + EXPLODEYSP; + + FLUSHXSP; + FLUSHYSP; + + ieee754_clearcx(); + + switch (CLPAIR(xc, yc)) { + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_SNAN): + return ieee754sp_nanxcpt(y); + + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_SNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_SNAN, IEEE754_CLASS_INF): + return ieee754sp_nanxcpt(x); + + /* numbers are preferred to NaNs */ + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_QNAN): + return x; + + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_QNAN): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_QNAN, IEEE754_CLASS_INF): + return y; + + /* + * Infinity and zero handling + */ + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_DNORM): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_ZERO): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_ZERO): + return x; + + case CLPAIR(IEEE754_CLASS_INF, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_INF): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_NORM): + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_DNORM): + return y; + + case CLPAIR(IEEE754_CLASS_ZERO, IEEE754_CLASS_ZERO): + if (xs == ys) + return x; + return ieee754sp_zero(1); + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_DNORM): + SPDNORMX; + + case CLPAIR(IEEE754_CLASS_NORM, IEEE754_CLASS_DNORM): + SPDNORMY; + break; + + case CLPAIR(IEEE754_CLASS_DNORM, IEEE754_CLASS_NORM): + SPDNORMX; + } + + /* Finally get to do some computation */ + + assert(xm & SP_HIDDEN_BIT); + assert(ym & SP_HIDDEN_BIT); + + /* Compare exponent */ + if (xe > ye) + return x; + else if (xe < ye) + return y; + + /* Compare mantissa */ + if (xm <= ym) + return y; + return x; +} -- GitLab From 65ab562cabe01d524ec6b50f37694200745c21c1 Mon Sep 17 00:00:00 2001 From: Markos Chandras Date: Wed, 12 Aug 2015 10:14:35 +0100 Subject: [PATCH 6216/7006] MIPS: math-emu: Remove unused handle_dsemul function declaration handle_dsemul does not exist and it's not being used in the code at all so remove its declaration. The deliberate DS emulation exception is handled by the do_dsemulret C code. Signed-off-by: Markos Chandras Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/10950/ Signed-off-by: Ralf Baechle --- arch/mips/math-emu/dsemul.c | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index e0b5cc27d78b0..cbb36c14b155a 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -33,7 +33,6 @@ struct emuframe { int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc) { - extern asmlinkage void handle_dsemulret(void); struct emuframe __user *fr; int err; -- GitLab From fb2646ab032d12ef06225c64768691c7ecc500ec Mon Sep 17 00:00:00 2001 From: Alex Smith Date: Tue, 18 Aug 2015 15:03:10 +0100 Subject: [PATCH 6217/7006] MIPS: Fix alignment of quiet build output for vmlinuz link The "LD vmlinuz" line in the quiet build output is misaligned with the rest of the output. Fix this. Signed-off-by: Alex Smith Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/11019/ Signed-off-by: Ralf Baechle --- arch/mips/boot/compressed/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile index dc91bde10d622..d5bdee115f22f 100644 --- a/arch/mips/boot/compressed/Makefile +++ b/arch/mips/boot/compressed/Makefile @@ -78,7 +78,7 @@ endif vmlinuzobjs-y += $(obj)/piggy.o -quiet_cmd_zld = LD $@ +quiet_cmd_zld = LD $@ cmd_zld = $(LD) $(LDFLAGS) -Ttext $(VMLINUZ_LOAD_ADDRESS) -T $< $(vmlinuzobjs-y) -o $@ quiet_cmd_strip = STRIP $@ cmd_strip = $(STRIP) -s $@ -- GitLab From f0675d4a8ed9d3e863ff611561ee0944969a2784 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 3 Sep 2015 11:51:34 +0200 Subject: [PATCH 6218/7006] drm/i915: Drop port_mst_index parameter from pin/eld callback The port_mst_index parameter was reserved for future use, but maintainers prefer to add it later when it is actually used. [Note: this is an update patch to commit [51e1d83cab99: drm/i915: Call audio pin/ELD notify function] where I mistakenly applied the older version. Jani and Daniel's review tags were to the latest version, so I add them below, too -- tiwai] Signed-off-by: David Henningsson Reviewed-by: Jani Nikula Acked-by: Daniel Vetter Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_audio.c | 4 ++-- include/drm/i915_component.h | 3 +-- sound/pci/hda/patch_hdmi.c | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 969835db8ff70..2d52d96b54938 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -424,7 +424,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder) dev_priv->display.audio_codec_enable(connector, intel_encoder, mode); if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) - acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, 0); + acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port); } /** @@ -447,7 +447,7 @@ void intel_audio_codec_disable(struct intel_encoder *intel_encoder) dev_priv->display.audio_codec_disable(intel_encoder); if (acomp && acomp->audio_ops && acomp->audio_ops->pin_eld_notify) - acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port, 0); + acomp->audio_ops->pin_eld_notify(acomp->audio_ops->audio_ptr, (int) port); } /** diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index ab5bde3736b42..b2d56dd483d9c 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -42,9 +42,8 @@ struct i915_audio_component { * pin sense and/or ELD information has changed. * @audio_ptr: HDA driver object * @port: Which port has changed (PORTA / PORTB / PORTC etc) - * @port_mst_index: Index within that port, for DisplayPort multistreaming */ - void (*pin_eld_notify)(void *audio_ptr, int port, int port_mst_index); + void (*pin_eld_notify)(void *audio_ptr, int port); } *audio_ops; }; diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 932292ce5ce75..acbfbe087ee86 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -2324,7 +2324,7 @@ static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, snd_hda_codec_set_power_to_all(codec, fg, power_state); } -static void intel_pin_eld_notify(void *audio_ptr, int port, int port_mst_index) +static void intel_pin_eld_notify(void *audio_ptr, int port) { struct hda_codec *codec = audio_ptr; int pin_nid = port + 0x04; -- GitLab From e0d8b2ec532852d4b5aabcec3e7611848c32237d Mon Sep 17 00:00:00 2001 From: Yousong Zhou Date: Thu, 3 Sep 2015 17:47:45 +0800 Subject: [PATCH 6219/7006] MIPS: UAPI: Fix unrecognized opcode WSBH/DSBH/DSHD when using MIPS16. The nomips16 has to be added both as function attribute and assembler directive. When only function attribute is specified, the compiler will inline the function with -Os optimization. The generated assembly code cannot be correctly assembled because ISA mode switch has to be done through jump instruction. When only ".set nomips16" directive is used, the generated assembly code will use MIPS32 code for the inline assembly template and MIPS16 for the function return. The compiled binary is invalid: 00403100 <__arch_swab16>: 403100: 7c0410a0 wsbh v0,a0 403104: e820ea31 swc2 $0,-5583(at) while correct code should be: 00402650 <__arch_swab16>: 402650: 7c0410a0 wsbh v0,a0 402654: 03e00008 jr ra 402658: 3042ffff andi v0,v0,0xffff Signed-off-by: Yousong Zhou Cc: Chen Jie Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/11087/ Signed-off-by: Ralf Baechle --- arch/mips/include/uapi/asm/swab.h | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/mips/include/uapi/asm/swab.h b/arch/mips/include/uapi/asm/swab.h index 8f2d184dbe9f7..c4ddc4f0d2dcb 100644 --- a/arch/mips/include/uapi/asm/swab.h +++ b/arch/mips/include/uapi/asm/swab.h @@ -16,11 +16,13 @@ #if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \ defined(_MIPS_ARCH_LOONGSON3A) -static inline __attribute_const__ __u16 __arch_swab16(__u16 x) +static inline __attribute__((nomips16)) __attribute_const__ + __u16 __arch_swab16(__u16 x) { __asm__( " .set push \n" " .set arch=mips32r2 \n" + " .set nomips16 \n" " wsbh %0, %1 \n" " .set pop \n" : "=r" (x) @@ -30,11 +32,13 @@ static inline __attribute_const__ __u16 __arch_swab16(__u16 x) } #define __arch_swab16 __arch_swab16 -static inline __attribute_const__ __u32 __arch_swab32(__u32 x) +static inline __attribute__((nomips16)) __attribute_const__ + __u32 __arch_swab32(__u32 x) { __asm__( " .set push \n" " .set arch=mips32r2 \n" + " .set nomips16 \n" " wsbh %0, %1 \n" " rotr %0, %0, 16 \n" " .set pop \n" @@ -50,11 +54,13 @@ static inline __attribute_const__ __u32 __arch_swab32(__u32 x) * 64-bit kernel on r2 CPUs. */ #ifdef __mips64 -static inline __attribute_const__ __u64 __arch_swab64(__u64 x) +static inline __attribute__((nomips16)) __attribute_const__ + __u64 __arch_swab64(__u64 x) { __asm__( " .set push \n" " .set arch=mips64r2 \n" + " .set nomips16 \n" " dsbh %0, %1 \n" " dshd %0, %0 \n" " .set pop \n" -- GitLab From d5f362a7b977bdfaf8a955f3d604a29267bd5464 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 3 Sep 2015 11:51:35 +0200 Subject: [PATCH 6220/7006] drm/i915: Add locks around audio component bind/unbind This will make sure that audio callbacks do not race with component bind/unbind. [Note: this is an update patch to commit [51e1d83cab99: drm/i915: Call audio pin/ELD notify function] where I mistakenly applied the older version. Jani and Daniel's review tags were to the latest version, so I add them below, too -- tiwai] Signed-off-by: David Henningsson Reviewed-by: Jani Nikula Acked-by: Daniel Vetter Signed-off-by: Takashi Iwai --- drivers/gpu/drm/i915/intel_audio.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c index 2d52d96b54938..678a34f87c1c2 100644 --- a/drivers/gpu/drm/i915/intel_audio.c +++ b/drivers/gpu/drm/i915/intel_audio.c @@ -543,9 +543,11 @@ static int i915_audio_component_bind(struct device *i915_dev, if (WARN_ON(acomp->ops || acomp->dev)) return -EEXIST; + drm_modeset_lock_all(dev_priv->dev); acomp->ops = &i915_audio_component_ops; acomp->dev = i915_dev; dev_priv->audio_component = acomp; + drm_modeset_unlock_all(dev_priv->dev); return 0; } @@ -556,9 +558,11 @@ static void i915_audio_component_unbind(struct device *i915_dev, struct i915_audio_component *acomp = data; struct drm_i915_private *dev_priv = dev_to_i915(i915_dev); + drm_modeset_lock_all(dev_priv->dev); acomp->ops = NULL; acomp->dev = NULL; dev_priv->audio_component = NULL; + drm_modeset_unlock_all(dev_priv->dev); } static const struct component_ops i915_audio_component_bind_ops = { -- GitLab From b7dc42fd79390c074e2bff3b172b585d5c2d80c2 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Thu, 3 Sep 2015 08:57:12 -0400 Subject: [PATCH 6221/7006] ring-buffer: Revert "ring-buffer: Get timestamp after event is allocated" The commit a4543a2fa9ef31 "ring-buffer: Get timestamp after event is allocated" is needed for some future work. But after adding it, there is a race somewhere that causes the saved timestamp to have a slight shift, and get ahead of the actual timestamp and make it look like time goes backwards. I'm still looking into why this happens, but in the mean time, this is holding up other work to get in. I'm reverting the change for now (which makes the problem go away), and will add it back after I know what is wrong and fix it. Signed-off-by: Steven Rostedt --- kernel/trace/ring_buffer.c | 156 ++++++++++++------------------------- 1 file changed, 50 insertions(+), 106 deletions(-) diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 1cce0fbf92cea..fc347f8b1bca2 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c @@ -2141,8 +2141,6 @@ rb_reset_tail(struct ring_buffer_per_cpu *cpu_buffer, local_sub(length, &tail_page->write); } -static inline void rb_end_commit(struct ring_buffer_per_cpu *cpu_buffer); - /* * This is the slow path, force gcc not to inline it. */ @@ -2157,16 +2155,6 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, int ret; u64 ts; - /* - * If the event had a timestamp attached to it, remove it. - * The first event on a page (nested or not) always uses - * the full timestamp of the new page. - */ - if (info->add_timestamp) { - info->add_timestamp = 0; - info->length -= RB_LEN_TIME_EXTEND; - } - next_page = tail_page; rb_inc_page(cpu_buffer, &next_page); @@ -2253,11 +2241,6 @@ rb_move_tail(struct ring_buffer_per_cpu *cpu_buffer, rb_reset_tail(cpu_buffer, tail, info); - /* Commit what we have for now to update timestamps */ - rb_end_commit(cpu_buffer); - /* rb_end_commit() decs committing */ - local_inc(&cpu_buffer->committing); - /* fail and let the caller try again */ return ERR_PTR(-EAGAIN); @@ -2287,6 +2270,9 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) return skip_time_extend(event); } +static inline int rb_event_is_commit(struct ring_buffer_per_cpu *cpu_buffer, + struct ring_buffer_event *event); + /** * rb_update_event - update event type and data * @event: the event to update @@ -2298,7 +2284,7 @@ rb_add_time_stamp(struct ring_buffer_event *event, u64 delta) * and with this, we can determine what to place into the * data field. */ -static void __always_inline +static void rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event, struct rb_event_info *info) @@ -2306,6 +2292,10 @@ rb_update_event(struct ring_buffer_per_cpu *cpu_buffer, unsigned length = info->length; u64 delta = info->delta; + /* Only a commit updates the timestamp */ + if (unlikely(!rb_event_is_commit(cpu_buffer, event))) + delta = 0; + /* * If we need to add a timestamp, then we * add it to the start of the resevered space. @@ -2685,13 +2675,8 @@ EXPORT_SYMBOL_GPL(ring_buffer_unlock_commit); static noinline void rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, - struct ring_buffer_event *event, struct rb_event_info *info) { - struct ring_buffer_event *padding; - int length; - int size; - WARN_ONCE(info->delta > (1ULL << 59), KERN_WARNING "Delta way too big! %llu ts=%llu write stamp = %llu\n%s", (unsigned long long)info->delta, @@ -2701,61 +2686,7 @@ rb_handle_timestamp(struct ring_buffer_per_cpu *cpu_buffer, "If you just came from a suspend/resume,\n" "please switch to the trace global clock:\n" " echo global > /sys/kernel/debug/tracing/trace_clock\n"); - - /* - * Discarding this event to add a timestamp in front, but - * we still need to update the length of it to perform the discard. - */ - rb_update_event(cpu_buffer, event, info); - - if (rb_try_to_discard(cpu_buffer, event)) { - info->add_timestamp = 1; - /* - * The time delta since the last event is too big to - * hold in the time field of the event, then we append a - * TIME EXTEND event ahead of the data event. - */ - info->length += RB_LEN_TIME_EXTEND; - return; - } - - /* - * Humpf! An event came in after this one, and because it is not a - * commit, it will have a delta of zero, thus, it will take on - * the timestamp of the previous commit, which happened a long time - * ago (we need to add a timestamp, remember?). - * We need to add the timestamp here. A timestamp is a fixed size - * of 8 bytes. That means the rest of the event needs to be - * padding. - */ - size = info->length - RB_LEN_TIME_EXTEND; - - /* The padding will have a delta of 1 */ - if (size) - info->delta--; - - padding = rb_add_time_stamp(event, info->delta); - - if (size) { - length = info->length; - info->delta = 0; - info->length = size; - rb_update_event(cpu_buffer, padding, info); - - rb_event_discard(padding); - - /* Still visible, need to update write_stamp */ - rb_update_write_stamp(cpu_buffer, event); - - /* Still need to commit the padding. */ - rb_end_commit(cpu_buffer); - - /* rb_end_commit() decs committing */ - local_inc(&cpu_buffer->committing); - - /* The next iteration still uses the original length */ - info->length = length; - } + info->add_timestamp = 1; } static struct ring_buffer_event * @@ -2765,7 +2696,14 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, struct ring_buffer_event *event; struct buffer_page *tail_page; unsigned long tail, write; - bool is_commit; + + /* + * If the time delta since the last event is too big to + * hold in the time field of the event, then we append a + * TIME EXTEND event ahead of the data event. + */ + if (unlikely(info->add_timestamp)) + info->length += RB_LEN_TIME_EXTEND; tail_page = info->tail_page = cpu_buffer->tail_page; write = local_add_return(info->length, &tail_page->write); @@ -2774,43 +2712,32 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer, write &= RB_WRITE_MASK; tail = write - info->length; - /* See if we shot pass the end of this buffer page */ - if (unlikely(write > BUF_PAGE_SIZE)) - return rb_move_tail(cpu_buffer, tail, info); - - /* We reserved something on the buffer */ - event = __rb_page_index(tail_page, tail); - /* * If this is the first commit on the page, then it has the same - * timestamp as the page itself, otherwise we need to figure out - * the delta. + * timestamp as the page itself. */ - info->ts = rb_time_stamp(cpu_buffer->buffer); - is_commit = rb_event_is_commit(cpu_buffer, event); - - /* Commits are special (non nested events) */ - info->delta = is_commit ? info->ts - cpu_buffer->write_stamp : 0; - - if (!tail) { - /* - * If this is the first commit on the page, set the - * page to its timestamp. - */ - tail_page->page->time_stamp = info->ts; + if (!tail) info->delta = 0; - } else if (unlikely(test_time_stamp(info->delta)) && - !info->add_timestamp) { - rb_handle_timestamp(cpu_buffer, event, info); - return ERR_PTR(-EAGAIN); - } + /* See if we shot pass the end of this buffer page */ + if (unlikely(write > BUF_PAGE_SIZE)) + return rb_move_tail(cpu_buffer, tail, info); + /* We reserved something on the buffer */ + + event = __rb_page_index(tail_page, tail); kmemcheck_annotate_bitfield(event, bitfield); rb_update_event(cpu_buffer, event, info); local_inc(&tail_page->entries); + /* + * If this is the first commit on the page, then update + * its timestamp. + */ + if (!tail) + tail_page->page->time_stamp = info->ts; + /* account for these added bytes */ local_add(info->length, &cpu_buffer->entries_bytes); @@ -2825,6 +2752,7 @@ rb_reserve_next_event(struct ring_buffer *buffer, struct ring_buffer_event *event; struct rb_event_info info; int nr_loops = 0; + u64 diff; rb_start_commit(cpu_buffer); @@ -2842,9 +2770,12 @@ rb_reserve_next_event(struct ring_buffer *buffer, return NULL; } #endif + info.length = rb_calculate_event_length(length); - info.add_timestamp = 0; again: + info.add_timestamp = 0; + info.delta = 0; + /* * We allow for interrupts to reenter here and do a trace. * If one does, it will cause this original code to loop @@ -2857,6 +2788,19 @@ rb_reserve_next_event(struct ring_buffer *buffer, if (RB_WARN_ON(cpu_buffer, ++nr_loops > 1000)) goto out_fail; + info.ts = rb_time_stamp(cpu_buffer->buffer); + diff = info.ts - cpu_buffer->write_stamp; + + /* make sure this diff is calculated here */ + barrier(); + + /* Did the write stamp get updated already? */ + if (likely(info.ts >= cpu_buffer->write_stamp)) { + info.delta = diff; + if (unlikely(test_time_stamp(info.delta))) + rb_handle_timestamp(cpu_buffer, &info); + } + event = __rb_reserve_next(cpu_buffer, &info); if (unlikely(PTR_ERR(event) == -EAGAIN)) -- GitLab From 857d913d057f8e7330e9f17eaa2b0eb7ad492c33 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 27 Aug 2015 00:14:16 -0400 Subject: [PATCH 6222/7006] drm/amdgpu: be explicit about cpu vram access for driver BOs (v2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For kernel driver BOs, be explicit about whether we need vram access up front. This avoids unecessary migrations and avoids using visible vram for buffers were it's not needed. v2: line wrap fixes Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c | 4 ++-- drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 3 ++- drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c | 12 +++++++++--- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 4 +++- drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c | 7 +++++-- drivers/gpu/drm/amd/amdgpu/fiji_smc.c | 8 ++++++-- drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c | 12 +++++++++--- drivers/gpu/drm/amd/amdgpu/iceland_smc.c | 4 +++- drivers/gpu/drm/amd/amdgpu/tonga_smc.c | 8 ++++++-- 12 files changed, 51 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 42d1a22c11994..6ff6ae945794a 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -244,7 +244,8 @@ static int amdgpu_vram_scratch_init(struct amdgpu_device *adev) if (adev->vram_scratch.robj == NULL) { r = amdgpu_bo_create(adev, AMDGPU_GPU_PAGE_SIZE, - PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0, + PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, NULL, &adev->vram_scratch.robj); if (r) { return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c index 81b821247dde5..8a122b1b77861 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_fb.c @@ -126,8 +126,8 @@ static int amdgpufb_create_pinned_object(struct amdgpu_fbdev *rfbdev, aligned_size = ALIGN(size, PAGE_SIZE); ret = amdgpu_gem_object_create(adev, aligned_size, 0, AMDGPU_GEM_DOMAIN_VRAM, - 0, true, - &gobj); + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + true, &gobj); if (ret) { printk(KERN_ERR "failed to allocate framebuffer (%d)\n", aligned_size); diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c index e02db0b2e8393..cbd3a486c5c2c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gart.c @@ -125,7 +125,8 @@ int amdgpu_gart_table_vram_alloc(struct amdgpu_device *adev) if (adev->gart.robj == NULL) { r = amdgpu_bo_create(adev, adev->gart.table_size, - PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, 0, + PAGE_SIZE, true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, NULL, &adev->gart.robj); if (r) { return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c index 4b36e779622f9..5839fab374bf6 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_gem.c @@ -656,7 +656,8 @@ int amdgpu_mode_dumb_create(struct drm_file *file_priv, r = amdgpu_gem_object_create(adev, args->size, 0, AMDGPU_GEM_DOMAIN_VRAM, - 0, ttm_bo_type_device, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + ttm_bo_type_device, &gobj); if (r) return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index 399143541d8a2..b5abd5cde413f 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -859,7 +859,8 @@ int amdgpu_ttm_init(struct amdgpu_device *adev) amdgpu_ttm_set_active_vram_size(adev, adev->mc.visible_vram_size); r = amdgpu_bo_create(adev, 256 * 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, NULL, &adev->stollen_vga_memory); if (r) { return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c index 3ad4a83c418fe..2cf6c6b06e3b1 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_uvd.c @@ -154,7 +154,9 @@ int amdgpu_uvd_sw_init(struct amdgpu_device *adev) bo_size = AMDGPU_GPU_PAGE_ALIGN(le32_to_cpu(hdr->ucode_size_bytes) + 8) + AMDGPU_UVD_STACK_SIZE + AMDGPU_UVD_HEAP_SIZE; r = amdgpu_bo_create(adev, bo_size, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->uvd.vcpu_bo); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &adev->uvd.vcpu_bo); if (r) { dev_err(adev->dev, "(%d) failed to allocate UVD bo\n", r); return r; @@ -901,7 +903,9 @@ int amdgpu_uvd_get_create_msg(struct amdgpu_ring *ring, uint32_t handle, int r, i; r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &bo); if (r) return r; @@ -948,7 +952,9 @@ int amdgpu_uvd_get_destroy_msg(struct amdgpu_ring *ring, uint32_t handle, int r, i; r = amdgpu_bo_create(adev, 1024, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &bo); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &bo); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 1a984c934b1f2..76982438d1c6b 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -141,7 +141,9 @@ int amdgpu_vce_sw_init(struct amdgpu_device *adev, unsigned long size) /* allocate firmware, stack and heap BO */ r = amdgpu_bo_create(adev, size, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->vce.vcpu_bo); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &adev->vce.vcpu_bo); if (r) { dev_err(adev->dev, "(%d) failed to allocate VCE bo\n", r); return r; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c index 5848564d3d666..f68b7cdc370a8 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vm.c @@ -1099,7 +1099,9 @@ int amdgpu_vm_bo_map(struct amdgpu_device *adev, r = amdgpu_bo_create(adev, AMDGPU_VM_PTE_COUNT * 8, AMDGPU_GPU_PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &pt); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_NO_CPU_ACCESS, + NULL, &pt); if (r) goto error_free; @@ -1299,7 +1301,8 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm) vm->page_directory_fence = NULL; r = amdgpu_bo_create(adev, pd_size, align, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_NO_CPU_ACCESS, NULL, &vm->page_directory); if (r) return r; diff --git a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c index 493c8c9c7faa7..322edea658578 100644 --- a/drivers/gpu/drm/amd/amdgpu/fiji_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/fiji_smc.c @@ -762,7 +762,9 @@ int fiji_smu_init(struct amdgpu_device *adev) /* Allocate FW image data structure and header buffer */ ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, - true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); + true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, toc_buf); if (ret) { DRM_ERROR("Failed to allocate memory for TOC buffer\n"); return -ENOMEM; @@ -770,7 +772,9 @@ int fiji_smu_init(struct amdgpu_device *adev) /* Allocate buffer for SMU internal buffer */ ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, - true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, smu_buf); + true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, smu_buf); if (ret) { DRM_ERROR("Failed to allocate memory for SMU internal buffer\n"); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c index 517a68f82ec3b..4bd1e5cf65ca8 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v7_0.c @@ -3786,7 +3786,9 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev) /* save restore block */ if (adev->gfx.rlc.save_restore_obj == NULL) { r = amdgpu_bo_create(adev, dws * 4, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->gfx.rlc.save_restore_obj); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &adev->gfx.rlc.save_restore_obj); if (r) { dev_warn(adev->dev, "(%d) create RLC sr bo failed\n", r); return r; @@ -3827,7 +3829,9 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev) if (adev->gfx.rlc.clear_state_obj == NULL) { r = amdgpu_bo_create(adev, dws * 4, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->gfx.rlc.clear_state_obj); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &adev->gfx.rlc.clear_state_obj); if (r) { dev_warn(adev->dev, "(%d) create RLC c bo failed\n", r); gfx_v7_0_rlc_fini(adev); @@ -3864,7 +3868,9 @@ static int gfx_v7_0_rlc_init(struct amdgpu_device *adev) if (adev->gfx.rlc.cp_table_size) { if (adev->gfx.rlc.cp_table_obj == NULL) { r = amdgpu_bo_create(adev, adev->gfx.rlc.cp_table_size, PAGE_SIZE, true, - AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, &adev->gfx.rlc.cp_table_obj); + AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, &adev->gfx.rlc.cp_table_obj); if (r) { dev_warn(adev->dev, "(%d) create RLC cp table bo failed\n", r); gfx_v7_0_rlc_fini(adev); diff --git a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c index c6f1e2f12b5f7..c900aa942adef 100644 --- a/drivers/gpu/drm/amd/amdgpu/iceland_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/iceland_smc.c @@ -623,7 +623,9 @@ int iceland_smu_init(struct amdgpu_device *adev) /* Allocate FW image data structure and header buffer */ ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, - true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); + true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, toc_buf); if (ret) { DRM_ERROR("Failed to allocate memory for TOC buffer\n"); return -ENOMEM; diff --git a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c index 5fc53a40c7ac1..1f5ac941a6108 100644 --- a/drivers/gpu/drm/amd/amdgpu/tonga_smc.c +++ b/drivers/gpu/drm/amd/amdgpu/tonga_smc.c @@ -761,7 +761,9 @@ int tonga_smu_init(struct amdgpu_device *adev) /* Allocate FW image data structure and header buffer */ ret = amdgpu_bo_create(adev, image_size, PAGE_SIZE, - true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, toc_buf); + true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, toc_buf); if (ret) { DRM_ERROR("Failed to allocate memory for TOC buffer\n"); return -ENOMEM; @@ -769,7 +771,9 @@ int tonga_smu_init(struct amdgpu_device *adev) /* Allocate buffer for SMU internal buffer */ ret = amdgpu_bo_create(adev, smu_internal_buffer_size, PAGE_SIZE, - true, AMDGPU_GEM_DOMAIN_VRAM, 0, NULL, smu_buf); + true, AMDGPU_GEM_DOMAIN_VRAM, + AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED, + NULL, smu_buf); if (ret) { DRM_ERROR("Failed to allocate memory for SMU internal buffer\n"); return -ENOMEM; -- GitLab From cace5dce5581a5a1232b68e1bc7b778ff40c328b Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Wed, 2 Sep 2015 15:06:08 -0400 Subject: [PATCH 6223/7006] drm/amdgpu: use top down allocation for non-CPU accessible vram MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Should help avoid fragmentation of vram due to CPU access requirements. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_object.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c index 57adcad2f7ba1..08b09d55b96fe 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_object.c @@ -127,7 +127,7 @@ static void amdgpu_ttm_placement_init(struct amdgpu_device *adev, placements[c].fpfn = adev->mc.visible_vram_size >> PAGE_SHIFT; placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | - TTM_PL_FLAG_VRAM; + TTM_PL_FLAG_VRAM | TTM_PL_FLAG_TOPDOWN; } placements[c].fpfn = 0; placements[c++].flags = TTM_PL_FLAG_WC | TTM_PL_FLAG_UNCACHED | -- GitLab From ac92f1517379299c03dc501b6a44be49cfcbcfe4 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:27:08 +0000 Subject: [PATCH 6224/7006] pcmcia: pxa2xx: update socket driver to use devm_clk_get() API Update the pxa2xx socket driver to use the devm_clk_get() API so that the cleanup paths are simplified. Reviewed-by: Robert Jarzmik Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_base.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 984a8ff559d88..197c77a64ce0c 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -296,17 +296,15 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) goto err0; } - clk = clk_get(&dev->dev, NULL); + clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(clk)) return -ENODEV; pxa2xx_drv_pcmcia_ops(ops); sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL); - if (!sinfo) { - clk_put(clk); + if (!sinfo) return -ENOMEM; - } sinfo->nskt = ops->nr; sinfo->clk = clk; @@ -332,7 +330,6 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) err1: while (--i >= 0) soc_pcmcia_remove_one(&sinfo->skt[i]); - clk_put(clk); kfree(sinfo); err0: return ret; @@ -348,7 +345,6 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) for (i = 0; i < sinfo->nskt; i++) soc_pcmcia_remove_one(&sinfo->skt[i]); - clk_put(sinfo->clk); kfree(sinfo); return 0; } -- GitLab From 8e2caf0d21a7059d8b56cb19d5d0182a28b1eabc Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:33:16 +0000 Subject: [PATCH 6225/7006] pcmcia: pxa2xx: convert memory allocation to devm_* API Convert the pxa2xx socket driver memory allocation to use devm_kzalloc() to simplify the cleanup path. Reviewed-by: Robert Jarzmik Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_base.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 197c77a64ce0c..0f42d55e7c7fc 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -302,7 +302,8 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) pxa2xx_drv_pcmcia_ops(ops); - sinfo = kzalloc(SKT_DEV_INFO_SIZE(ops->nr), GFP_KERNEL); + sinfo = devm_kzalloc(&dev->dev, SKT_DEV_INFO_SIZE(ops->nr), + GFP_KERNEL); if (!sinfo) return -ENOMEM; @@ -330,7 +331,7 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) err1: while (--i >= 0) soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); + err0: return ret; } @@ -340,12 +341,9 @@ static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev) struct skt_dev_info *sinfo = platform_get_drvdata(dev); int i; - platform_set_drvdata(dev, NULL); - for (i = 0; i < sinfo->nskt; i++) soc_pcmcia_remove_one(&sinfo->skt[i]); - kfree(sinfo); return 0; } -- GitLab From 924e5ea2ce0f6addb8b098760d840b0923573d19 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:27:08 +0000 Subject: [PATCH 6226/7006] pcmcia: sa1111: update socket driver to use devm_clk_get() API Update the pxa2xx socket driver to use the devm_clk_get() API so that the cleanup paths are simplified. Signed-off-by: Russell King --- drivers/pcmcia/sa1111_generic.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index 80b8e9d052752..fb902af8a5b75 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -145,7 +145,7 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, return -ENOMEM; s->soc.nr = ops->first + i; - s->soc.clk = clk_get(&dev->dev, NULL); + s->soc.clk = devm_clk_get(&dev->dev, NULL); if (IS_ERR(s->soc.clk)) { ret = PTR_ERR(s->soc.clk); kfree(s); @@ -226,7 +226,6 @@ static int pcmcia_remove(struct sa1111_dev *dev) for (; s; s = next) { next = s->next; soc_pcmcia_remove_one(&s->soc); - clk_put(s->soc.clk); kfree(s); } -- GitLab From 321ae9646bbfdf27550ecb65617322abc2b92052 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:46:35 +0000 Subject: [PATCH 6227/7006] pcmcia: sa1111: simplify clk handing in sa1111_pcmcia_add() clk_get(dev, NULL) will always refer to the same clock, so it's pointless calling this multiple times for the same device. As we no longer have to worry about the cleanup (via use of devm_clk_get()) we can simplify sa1111_pcmcia_add() too. Signed-off-by: Russell King --- drivers/pcmcia/sa1111_generic.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/pcmcia/sa1111_generic.c b/drivers/pcmcia/sa1111_generic.c index fb902af8a5b75..a1531feb8460c 100644 --- a/drivers/pcmcia/sa1111_generic.c +++ b/drivers/pcmcia/sa1111_generic.c @@ -135,8 +135,13 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, int (*add)(struct soc_pcmcia_socket *)) { struct sa1111_pcmcia_socket *s; + struct clk *clk; int i, ret = 0; + clk = devm_clk_get(&dev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + ops->socket_state = sa1111_pcmcia_socket_state; for (i = 0; i < ops->nr; i++) { @@ -145,12 +150,8 @@ int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops, return -ENOMEM; s->soc.nr = ops->first + i; - s->soc.clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(s->soc.clk)) { - ret = PTR_ERR(s->soc.clk); - kfree(s); - return ret; - } + s->soc.clk = clk; + soc_pcmcia_init_one(&s->soc, ops, &dev->dev); s->dev = dev; if (s->soc.nr) { -- GitLab From c3eb700c5db18be80c1ba37d39995b4c23fbe792 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 10:57:48 +0000 Subject: [PATCH 6228/7006] pcmcia: sa11xx_base.c: remove useless init/exit functions A library module is not required to have module init/exit functions. Get rid of these unnecessary functions. Signed-off-by: Russell King --- drivers/pcmcia/sa11xx_base.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 6e6336d47d4ac..815b6950975c9 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -259,16 +259,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, } EXPORT_SYMBOL(sa11xx_drv_pcmcia_probe); -static int __init sa11xx_pcmcia_init(void) -{ - return 0; -} -fs_initcall(sa11xx_pcmcia_init); - -static void __exit sa11xx_pcmcia_exit(void) {} - -module_exit(sa11xx_pcmcia_exit); - MODULE_AUTHOR("John Dorsey "); MODULE_DESCRIPTION("Linux PCMCIA Card Services: SA-11xx core socket driver"); MODULE_LICENSE("Dual MPL/GPL"); -- GitLab From fca8b807a667c6f34af1cffe57efbd17b257d07b Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 26 Mar 2015 11:01:04 +0000 Subject: [PATCH 6229/7006] pcmcia: soc_common: remove skt_dev_info's clk pointer We no longer need to store the clk pointer in struct skt_dev_info as we no longer need to remember the clk pointer for the cleanup paths. Reviewed-by: Robert Jarzmik Signed-off-by: Russell King --- drivers/pcmcia/pxa2xx_base.c | 1 - drivers/pcmcia/sa11xx_base.c | 1 - drivers/pcmcia/soc_common.h | 1 - 3 files changed, 3 deletions(-) diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 0f42d55e7c7fc..483f919e0d2e2 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c @@ -308,7 +308,6 @@ static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev) return -ENOMEM; sinfo->nskt = ops->nr; - sinfo->clk = clk; /* Initialize processor specific parameters */ for (i = 0; i < ops->nr; i++) { diff --git a/drivers/pcmcia/sa11xx_base.c b/drivers/pcmcia/sa11xx_base.c index 815b6950975c9..9f6ec87b9f9e1 100644 --- a/drivers/pcmcia/sa11xx_base.c +++ b/drivers/pcmcia/sa11xx_base.c @@ -233,7 +233,6 @@ int sa11xx_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops, return -ENOMEM; sinfo->nskt = nr; - sinfo->clk = clk; /* Initialize processor specific parameters */ for (i = 0; i < nr; i++) { diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h index e6fcbea5b682e..94762a54d7319 100644 --- a/drivers/pcmcia/soc_common.h +++ b/drivers/pcmcia/soc_common.h @@ -68,7 +68,6 @@ struct soc_pcmcia_socket { struct skt_dev_info { int nskt; - struct clk *clk; struct soc_pcmcia_socket skt[0]; }; -- GitLab From be9fd2e978939ab3e59ee4164fa0893e70359557 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Sep 2015 10:19:03 -0400 Subject: [PATCH 6230/7006] drm/amdgpu: fix typo in dce10 watermark setup Using the wrong watermwark value for the secondary watermark. Copy paste typo. Noticed by Mykola. Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/dce_v10_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c index 4b255ac3043c9..e4d101b1252a4 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v10_0.c @@ -1353,7 +1353,7 @@ static void dce_v10_0_program_watermarks(struct amdgpu_device *adev, tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 2); WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp); tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset); - tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a); + tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_b); tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time); WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp); /* restore original selection */ -- GitLab From 99a092383794e07d60644b449a01656da112eb1f Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Sep 2015 10:16:23 -0400 Subject: [PATCH 6231/7006] drm/amdgpu: fix typo in dce11 watermark setup Using the wrong watermwark value for the secondary watermark. Copy paste typo. Noticed by Mykola. Reviewed-by: Harry Wentland Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/dce_v11_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c index 70eee807421fd..6411e82446716 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v11_0.c @@ -1329,7 +1329,7 @@ static void dce_v11_0_program_watermarks(struct amdgpu_device *adev, tmp = REG_SET_FIELD(wm_mask, DPG_WATERMARK_MASK_CONTROL, URGENCY_WATERMARK_MASK, 2); WREG32(mmDPG_WATERMARK_MASK_CONTROL + amdgpu_crtc->crtc_offset, tmp); tmp = RREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset); - tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_a); + tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_LOW_WATERMARK, latency_watermark_b); tmp = REG_SET_FIELD(tmp, DPG_PIPE_URGENCY_CONTROL, URGENCY_HIGH_WATERMARK, line_time); WREG32(mmDPG_PIPE_URGENCY_CONTROL + amdgpu_crtc->crtc_offset, tmp); /* restore original selection */ -- GitLab From 362eda04ba0638af1c41dcc1e594dcbff80346c1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Sep 2015 00:53:24 -0400 Subject: [PATCH 6232/7006] drm/amdgpu/cz: fix cz_dpm_update_low_memory_pstate logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The logic was reversed. This feature is not enabled at the moment, but fix it now for the future. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/cz_dpm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c index ace870afc7d45..44fa96ad47099 100644 --- a/drivers/gpu/drm/amd/amdgpu/cz_dpm.c +++ b/drivers/gpu/drm/amd/amdgpu/cz_dpm.c @@ -1596,9 +1596,9 @@ static int cz_dpm_update_low_memory_pstate(struct amdgpu_device *adev) if (pi->sys_info.nb_dpm_enable) { if (ps->force_high) - cz_dpm_nbdpm_lm_pstate_enable(adev, true); - else cz_dpm_nbdpm_lm_pstate_enable(adev, false); + else + cz_dpm_nbdpm_lm_pstate_enable(adev, true); } return ret; -- GitLab From 06d3f2e02024912d46e1fc8387c0284c9dfc36ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Aug 2015 05:31:09 -0300 Subject: [PATCH 6233/7006] [media] tc358743: set direction of reset gpio using devm_gpiod_get MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 256148246852 ("[media] tc358743: support probe from device tree") failed to explicitly set the direction of the reset gpio. Use the optional flag of devm_gpiod_get to make up leeway. This is also necessary because the flag parameter will become mandatory soon. Signed-off-by: Uwe Kleine-König Reviewed-by: Linus Walleij Acked-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index fe42c9a1cb787..a4efb6e2e7a2c 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1681,7 +1681,6 @@ static const struct v4l2_ctrl_config tc358743_ctrl_audio_present = { #ifdef CONFIG_OF static void tc358743_gpio_reset(struct tc358743_state *state) { - gpiod_set_value(state->reset_gpio, 0); usleep_range(5000, 10000); gpiod_set_value(state->reset_gpio, 1); usleep_range(1000, 2000); @@ -1783,7 +1782,7 @@ static int tc358743_probe_of(struct tc358743_state *state) state->pdata.ths_trailcnt = 0x2; state->pdata.hstxvregcnt = 0; - state->reset_gpio = devm_gpiod_get(dev, "reset"); + state->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(state->reset_gpio)) { dev_err(dev, "failed to get reset gpio\n"); ret = PTR_ERR(state->reset_gpio); -- GitLab From 1e137d92c0c6f162d57ede1ba85c298acde26bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Aug 2015 05:31:10 -0300 Subject: [PATCH 6234/7006] [media] tc358743: make reset gpio optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 256148246852 ("[media] tc358743: support probe from device tree") specified in the device tree binding documentation that the reset gpio is optional. Make the implementation match accordingly. Signed-off-by: Uwe Kleine-König Reviewed-by: Linus Walleij Acked-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index a4efb6e2e7a2c..7a6fdecc7215b 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1782,14 +1782,16 @@ static int tc358743_probe_of(struct tc358743_state *state) state->pdata.ths_trailcnt = 0x2; state->pdata.hstxvregcnt = 0; - state->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + state->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_LOW); if (IS_ERR(state->reset_gpio)) { dev_err(dev, "failed to get reset gpio\n"); ret = PTR_ERR(state->reset_gpio); goto disable_clk; } - tc358743_gpio_reset(state); + if (state->reset_gpio) + tc358743_gpio_reset(state); ret = 0; goto free_endpoint; -- GitLab From 062683901ad5c29ac375e6b7c7bca2737d41e11a Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Mon, 17 Aug 2015 08:20:56 -0300 Subject: [PATCH 6235/7006] [media] DocBook media: Fix typo "the the" in xml files This patch fix spelling typo "the the" found in controls.xml and vidioc-g-param.xml. These xml files are'nt generated from any source files, so I have to fix these xml files directly. Signed-off-by: Masanari Iida Signed-off-by: Mauro Carvalho Chehab --- Documentation/DocBook/media/v4l/controls.xml | 2 +- Documentation/DocBook/media/v4l/vidioc-g-parm.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml index 6e1667b5f3ebd..33aece5418800 100644 --- a/Documentation/DocBook/media/v4l/controls.xml +++ b/Documentation/DocBook/media/v4l/controls.xml @@ -3414,7 +3414,7 @@ giving priority to the center of the metered area. V4L2_EXPOSURE_METERING_MATRIX  A multi-zone metering. The light intensity is measured -in several points of the frame and the the results are combined. The +in several points of the frame and the results are combined. The algorithm of the zones selection and their significance in calculating the final value is device dependent. diff --git a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml index f4e28e7d47512..721728745407f 100644 --- a/Documentation/DocBook/media/v4l/vidioc-g-parm.xml +++ b/Documentation/DocBook/media/v4l/vidioc-g-parm.xml @@ -267,7 +267,7 @@ is intended for still imaging applications. The idea is to get the best possible image quality that the hardware can deliver. It is not defined how the driver writer may achieve that; it will depend on the hardware and the ingenuity of the driver writer. High quality mode is -a different mode from the the regular motion video capture modes. In +a different mode from the regular motion video capture modes. In high quality mode: The driver may be able to capture higher -- GitLab From 62e5f051c110a4f8de66f4c33e690892089aaac4 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 18 Aug 2015 10:23:05 -0300 Subject: [PATCH 6236/7006] [media] c8sectpfe: Use %pad to print 'dma_addr_t' Use %pad to print 'dma_addr_t' in order to fix the following build warning: drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c:588:2: warning: format '%x' expects argument of type 'unsigned int', but argument 5 has type 'dma_addr_t' [-Wformat=] Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 1586a1e6836d9..486aef50d99b2 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -585,9 +585,9 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei, writel(tsin->pid_buffer_busaddr, fei->io + PIDF_BASE(tsin->tsin_id)); - dev_info(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=0x%x\n", + dev_info(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n", tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)), - tsin->pid_buffer_busaddr); + &tsin->pid_buffer_busaddr); /* Configure and enable HW PID filtering */ -- GitLab From 22dbe35a3aa2c06cef9faa472c46e8decbcd64e9 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 19 Aug 2015 03:27:27 -0300 Subject: [PATCH 6237/7006] [media] tc358743: add missing Kconfig dependency/select As reported by Randy: > when CONFIG_MEDIA_CONTROLLER is not enabled: > > ../drivers/media/i2c/tc358743.c: In function 'tc358743_probe': > ../drivers/media/i2c/tc358743.c:1890:29: error: 'struct v4l2_subdev' has no member named 'entity' > err = media_entity_init(&sd->entity, 1, &state->pad, 0); > ^ > ../drivers/media/i2c/tc358743.c:1940:26: error: 'struct v4l2_subdev' has no member named 'entity' > media_entity_cleanup(&sd->entity); > ^ > ../drivers/media/i2c/tc358743.c: In function 'tc358743_remove': > ../drivers/media/i2c/tc358743.c:1955:26: error: 'struct v4l2_subdev' has no member named 'entity' > media_entity_cleanup(&sd->entity); > ^ This driver depends on VIDEO_V4L2_SUBDEV_API and needs to select HDMI. Signed-off-by: Hans Verkuil Reported-by: Randy Dunlap Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index d669547604cd1..521bbf1b29bc5 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -289,7 +289,8 @@ config VIDEO_SAA711X config VIDEO_TC358743 tristate "Toshiba TC358743 decoder" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + select HDMI ---help--- Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge. -- GitLab From abeaca0ff5666a1cd7460304e619e4c6a486ea04 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Thu, 20 Aug 2015 04:35:43 -0300 Subject: [PATCH 6238/7006] [media] tc358743: only queue subdev notifications if devnode is set Hardware interrupts are enabled in the probe function, before the subdev is registered to its v4l2_device. Until v4l2_device_register_subdev_node is called, sd->devnode is NULL and v4l2_subdev_notify_event must not be called. Signed-off-by: Philipp Zabel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 7a6fdecc7215b..526d30745a19f 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -870,7 +870,8 @@ static void tc358743_format_change(struct v4l2_subdev *sd) &timings, false); } - v4l2_subdev_notify_event(sd, &tc358743_ev_fmt); + if (sd->devnode) + v4l2_subdev_notify_event(sd, &tc358743_ev_fmt); } static void tc358743_init_interrupts(struct v4l2_subdev *sd) -- GitLab From 543409a2475de00d336468eee5bba8409092db16 Mon Sep 17 00:00:00 2001 From: Steven Rostedt Date: Thu, 20 Aug 2015 18:03:43 -0300 Subject: [PATCH 6239/7006] [media] cx231xx: Use wake_up_interruptible() instead of wake_up_interruptible_nr() While looking at use cases of the wake queues in order to add support for simple wait queues, I noticed that there was only a single user of wake_up_interruptible_nr(), and that use was doing a single task wake up. Have that user use the proper wake_up_interruptible() instead, and perhaps we can even remove the function wake_up_interruptible_nr(). Signed-off-by: Steven Rostedt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index c6ff8968286a6..9798160698a35 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -1875,7 +1875,7 @@ static int cx231xx_close(struct file *filp) v4l2_fh_exit(&fh->fh); kfree(fh); dev->users--; - wake_up_interruptible_nr(&dev->open, 1); + wake_up_interruptible(&dev->open); return 0; } @@ -1908,7 +1908,7 @@ static int cx231xx_close(struct file *filp) } v4l2_fh_exit(&fh->fh); kfree(fh); - wake_up_interruptible_nr(&dev->open, 1); + wake_up_interruptible(&dev->open); return 0; } -- GitLab From cfd34ed8deede7cbb0ba46d61870f075ac9694e3 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Fri, 21 Aug 2015 17:12:20 -0300 Subject: [PATCH 6240/7006] [media] i2c: fix platform_no_drv_owner.cocci warnings drivers/media/i2c/tc358743.c:1960:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Geert Uytterhoeven Signed-off-by: Fengguang Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tc358743.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c index 526d30745a19f..9ef5baaf86465 100644 --- a/drivers/media/i2c/tc358743.c +++ b/drivers/media/i2c/tc358743.c @@ -1969,7 +1969,6 @@ MODULE_DEVICE_TABLE(i2c, tc358743_id); static struct i2c_driver tc358743_driver = { .driver = { - .owner = THIS_MODULE, .name = "tc358743", }, .probe = tc358743_probe, -- GitLab From 58f1eae48e5372200553de07b5ecc7574803ee91 Mon Sep 17 00:00:00 2001 From: Duson Lin Date: Thu, 3 Sep 2015 09:46:45 -0700 Subject: [PATCH 6241/7006] Input: elan_i2c - use iap_version to get firmware information When driver is in IAP mode ic_type query may return 0xff. However iap_version will always be valid, so let's use it to determine parameters of the firmware that the controller is supposed to accept. Signed-off-by: Duson Lin Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d4a38caa1ab13..e2b7420eed97d 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -4,7 +4,7 @@ * Copyright (c) 2013 ELAN Microelectronics Corp. * * Author: 林政維 (Duson Lin) - * Version: 1.5.9 + * Version: 1.6.0 * * Based on cyapa driver: * copyright (c) 2011-2012 Cypress Semiconductor, Inc. @@ -40,7 +40,7 @@ #include "elan_i2c.h" #define DRIVER_NAME "elan_i2c" -#define ELAN_DRIVER_VERSION "1.5.9" +#define ELAN_DRIVER_VERSION "1.6.0" #define ETP_MAX_PRESSURE 255 #define ETP_FWIDTH_REDUCE 90 #define ETP_FINGER_WIDTH 15 @@ -94,10 +94,10 @@ struct elan_tp_data { bool baseline_ready; }; -static int elan_get_fwinfo(u8 ic_type, u16 *validpage_count, +static int elan_get_fwinfo(u8 iap_version, u16 *validpage_count, u16 *signature_address) { - switch(ic_type) { + switch (iap_version) { case 0x08: *validpage_count = 512; break; @@ -264,11 +264,11 @@ static int elan_query_device_info(struct elan_tp_data *data) if (error) return error; - error = elan_get_fwinfo(data->ic_type, &data->fw_validpage_count, + error = elan_get_fwinfo(data->iap_version, &data->fw_validpage_count, &data->fw_signature_address); if (error) { dev_err(&data->client->dev, - "unknown ic type %d\n", data->ic_type); + "unknown iap version %d\n", data->iap_version); return error; } -- GitLab From 50ef28a6ac216fd8b796257a3768fef8f57b917d Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Tue, 1 Sep 2015 07:48:11 -0300 Subject: [PATCH 6242/7006] [media] c8sectpfe: Remove select on undefined LIBELF_32 LIBELF_32 is not defined in Kconfig, and is left over legacy which is not required in the upstream driver, so remove it. Suggested-by: Valentin Rothberg Signed-off-by: Peter Griffin Acked-by: Lee Jones Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/media/platform/sti/c8sectpfe/Kconfig b/drivers/media/platform/sti/c8sectpfe/Kconfig index 1b1110d7374f3..641ad8f34956d 100644 --- a/drivers/media/platform/sti/c8sectpfe/Kconfig +++ b/drivers/media/platform/sti/c8sectpfe/Kconfig @@ -2,7 +2,6 @@ config DVB_C8SECTPFE tristate "STMicroelectronics C8SECTPFE DVB support" depends on PINCTRL && DVB_CORE && I2C depends on ARCH_STI || ARCH_MULTIPLATFORM || COMPILE_TEST - select LIBELF_32 select FW_LOADER select FW_LOADER_USER_HELPER_FALLBACK select DEBUG_FS -- GitLab From 4aeca98c49e9873e18b27540a0ba18b22e1b9424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rechi=20Vita?= Date: Thu, 3 Sep 2015 10:04:49 -0700 Subject: [PATCH 6243/7006] Input: elan_i2c - add ACPI ID "ELAN1000" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This ACPI ID present in the DSDT of the ASUS E202SA laptop. Signed-off-by: João Paulo Rechi Vita Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index e2b7420eed97d..fa945304b9a57 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1170,6 +1170,7 @@ static const struct acpi_device_id elan_acpi_id[] = { { "ELAN0000", 0 }, { "ELAN0100", 0 }, { "ELAN0600", 0 }, + { "ELAN1000", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, elan_acpi_id); -- GitLab From f2bc114b82ecbd32b3581bebdf40f1f2c4e9941b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 3 Sep 2015 10:47:25 -0700 Subject: [PATCH 6244/7006] Input: cyttsp - remove unnecessary MODULE_ALIAS() The drivers have a I2C device ID table that is used to create the module aliases and also "cyttsp" and "cyttsp4" are not supported I2C device IDs so these module aliases are never used. Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/cyttsp4_i2c.c | 1 - drivers/input/touchscreen/cyttsp_i2c.c | 1 - 2 files changed, 2 deletions(-) diff --git a/drivers/input/touchscreen/cyttsp4_i2c.c b/drivers/input/touchscreen/cyttsp4_i2c.c index 9a323dd915dea..a9f95c7d3c006 100644 --- a/drivers/input/touchscreen/cyttsp4_i2c.c +++ b/drivers/input/touchscreen/cyttsp4_i2c.c @@ -86,4 +86,3 @@ module_i2c_driver(cyttsp4_i2c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"); MODULE_AUTHOR("Cypress"); -MODULE_ALIAS("i2c:cyttsp4"); diff --git a/drivers/input/touchscreen/cyttsp_i2c.c b/drivers/input/touchscreen/cyttsp_i2c.c index 519e2de2f8dfc..eee51b3f2e3f3 100644 --- a/drivers/input/touchscreen/cyttsp_i2c.c +++ b/drivers/input/touchscreen/cyttsp_i2c.c @@ -86,4 +86,3 @@ module_i2c_driver(cyttsp_i2c_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cypress TrueTouch(R) Standard Product (TTSP) I2C driver"); MODULE_AUTHOR("Cypress"); -MODULE_ALIAS("i2c:cyttsp"); -- GitLab From e4dbe796285d96976586487fe0555f678c95b60f Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 3 Sep 2015 10:49:17 -0700 Subject: [PATCH 6245/7006] Input: ab8500-ponkey - Fix module autoload for OF platform driver This platform driver has a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Dmitry Torokhov --- drivers/input/misc/ab8500-ponkey.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/ab8500-ponkey.c b/drivers/input/misc/ab8500-ponkey.c index 1f7e15ca5fbe0..4f5ef5bb535b8 100644 --- a/drivers/input/misc/ab8500-ponkey.c +++ b/drivers/input/misc/ab8500-ponkey.c @@ -118,6 +118,7 @@ static const struct of_device_id ab8500_ponkey_match[] = { { .compatible = "stericsson,ab8500-ponkey", }, {} }; +MODULE_DEVICE_TABLE(of, ab8500_ponkey_match); #endif static struct platform_driver ab8500_ponkey_driver = { -- GitLab From 544edf56fdbf3916f4dad4e2dc71de3965a9d964 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 3 Sep 2015 10:49:46 -0700 Subject: [PATCH 6246/7006] Input: pwm-beeper - fix module autoload for OF platform driver This platform driver has a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Dmitry Torokhov --- drivers/input/misc/pwm-beeper.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index e82edf810d1f3..f2261ab547012 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -173,6 +173,7 @@ static const struct of_device_id pwm_beeper_match[] = { { .compatible = "pwm-beeper", }, { }, }; +MODULE_DEVICE_TABLE(of, pwm_beeper_match); #endif static struct platform_driver pwm_beeper_driver = { -- GitLab From 731857715f03035c812c3f6bdcb6b0179150c1aa Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 3 Sep 2015 10:50:21 -0700 Subject: [PATCH 6247/7006] Input: regulator-haptic - fix module autoload for OF platform driver This platform driver has a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Dmitry Torokhov --- drivers/input/misc/regulator-haptic.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c index 6bf3f1082f71e..a804705eb04a2 100644 --- a/drivers/input/misc/regulator-haptic.c +++ b/drivers/input/misc/regulator-haptic.c @@ -249,6 +249,7 @@ static const struct of_device_id regulator_haptic_dt_match[] = { { .compatible = "regulator-haptic" }, { /* sentinel */ }, }; +MODULE_DEVICE_TABLE(of, regulator_haptic_dt_match); static struct platform_driver regulator_haptic_driver = { .probe = regulator_haptic_probe, -- GitLab From 54b9a96f10d9acb7b1ffd40e2e1736443eb7656d Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Wed, 26 Aug 2015 23:00:59 -0400 Subject: [PATCH 6248/7006] IB/cxgb4: Fix if statement in pick_local_ip6adddrs This fixes an if statement checking the return value of the function get_lladdr for success in the function pick_local_ip6addrs to instead of directly checking the return value of this call check the opposite as get_lladdr returns zero for success which would incorrectly make this if statement block not execute with the current if statement check. Signed-off-by: Nicholas Krause Acked-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c index f0c1512c45cdb..debc39d2cbc2a 100644 --- a/drivers/infiniband/hw/cxgb4/cm.c +++ b/drivers/infiniband/hw/cxgb4/cm.c @@ -3031,7 +3031,7 @@ static int pick_local_ip6addrs(struct c4iw_dev *dev, struct iw_cm_id *cm_id) struct sockaddr_in6 *la6 = (struct sockaddr_in6 *)&cm_id->local_addr; struct sockaddr_in6 *ra6 = (struct sockaddr_in6 *)&cm_id->remote_addr; - if (get_lladdr(dev->rdev.lldi.ports[0], &addr, IFA_F_TENTATIVE)) { + if (!get_lladdr(dev->rdev.lldi.ports[0], &addr, IFA_F_TENTATIVE)) { memcpy(la6->sin6_addr.s6_addr, &addr, 16); memcpy(ra6->sin6_addr.s6_addr, &addr, 16); return 0; -- GitLab From b632ffa7cee439ba5dce3b3bc4a5cbe2b3e20133 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 26 Aug 2015 11:00:37 +0200 Subject: [PATCH 6249/7006] IB/uverbs: reject invalid or unknown opcodes We have many WR opcodes that are only supported in kernel space and/or require optional information to be copied into the WR structure. Reject all those not explicitly handled so that we can't pass invalid information to drivers. Cc: stable@vger.kernel.org Signed-off-by: Christoph Hellwig Reviewed-by: Jason Gunthorpe Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index a15318a54b311..be4cb9f04be33 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2372,6 +2372,12 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, next->send_flags = user_wr->send_flags; if (is_ud) { + if (next->opcode != IB_WR_SEND && + next->opcode != IB_WR_SEND_WITH_IMM) { + ret = -EINVAL; + goto out_put; + } + next->wr.ud.ah = idr_read_ah(user_wr->wr.ud.ah, file->ucontext); if (!next->wr.ud.ah) { @@ -2411,9 +2417,11 @@ ssize_t ib_uverbs_post_send(struct ib_uverbs_file *file, user_wr->wr.atomic.compare_add; next->wr.atomic.swap = user_wr->wr.atomic.swap; next->wr.atomic.rkey = user_wr->wr.atomic.rkey; + case IB_WR_SEND: break; default: - break; + ret = -EINVAL; + goto out_put; } } -- GitLab From 270e869d846af143f60b7404e01e785d18420007 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Wed, 2 Sep 2015 20:25:48 +0200 Subject: [PATCH 6250/7006] drm/amdgpu: fix buffer placement under memory pressure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some buffers (UVD/VM page tables) must be placed in VRAM, but the byte restriction for moving buffers didn't took this into account. Port of radeon commit 4b09556660bfe1b43d72ca858524c6baf2c6cb1d. Signed-off-by: Christian König Reviewed-by: Alex Deucher Reviewed-by: Jammy Zhou --- drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c index 6a206f15635fd..3b355aeb62fd3 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c @@ -354,7 +354,7 @@ int amdgpu_cs_list_validate(struct amdgpu_cs_parser *p) * into account. We don't want to disallow buffer moves * completely. */ - if (current_domain != AMDGPU_GEM_DOMAIN_CPU && + if ((lobj->allowed_domains & current_domain) != 0 && (domain & current_domain) == 0 && /* will be moved */ bytes_moved > bytes_moved_threshold) { /* don't move it */ -- GitLab From 81648d043191e5f8f5870c5af6060b56383b139d Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Aug 2015 11:43:00 -0500 Subject: [PATCH 6251/7006] gfs2: Simplify the seq file code for "sbstats" Don't use struct gfs2_glock_iter as the helper data structure for iterating through "sbstats"; we are not iterating through glocks here. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson --- fs/gfs2/glock.c | 31 +++++++++++-------------------- 1 file changed, 11 insertions(+), 20 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a38e38f7b6fc3..a694413a6e32b 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1776,10 +1776,10 @@ static const char *gfs2_stype[] = { static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) { - struct gfs2_glock_iter *gi = seq->private; - struct gfs2_sbd *sdp = gi->sdp; - unsigned index = gi->hash >> 3; - unsigned subindex = gi->hash & 0x07; + struct gfs2_sbd *sdp = seq->private; + loff_t pos = *(loff_t *)iter_ptr; + unsigned index = pos >> 3; + unsigned subindex = pos & 0x07; s64 value; int i; @@ -1930,26 +1930,19 @@ static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) static void *gfs2_sbstats_seq_start(struct seq_file *seq, loff_t *pos) { - struct gfs2_glock_iter *gi = seq->private; - - gi->hash = *pos; + preempt_disable(); if (*pos >= GFS2_NR_SBSTATS) return NULL; - preempt_disable(); - return SEQ_START_TOKEN; + return pos; } static void *gfs2_sbstats_seq_next(struct seq_file *seq, void *iter_ptr, loff_t *pos) { - struct gfs2_glock_iter *gi = seq->private; (*pos)++; - gi->hash++; - if (gi->hash >= GFS2_NR_SBSTATS) { - preempt_enable(); + if (*pos >= GFS2_NR_SBSTATS) return NULL; - } - return SEQ_START_TOKEN; + return pos; } static void gfs2_sbstats_seq_stop(struct seq_file *seq, void *iter_ptr) @@ -2012,12 +2005,10 @@ static int gfs2_glstats_open(struct inode *inode, struct file *file) static int gfs2_sbstats_open(struct inode *inode, struct file *file) { - int ret = seq_open_private(file, &gfs2_sbstats_seq_ops, - sizeof(struct gfs2_glock_iter)); + int ret = seq_open(file, &gfs2_sbstats_seq_ops); if (ret == 0) { struct seq_file *seq = file->private_data; - struct gfs2_glock_iter *gi = seq->private; - gi->sdp = inode->i_private; + seq->private = inode->i_private; /* sdp */ } return ret; } @@ -2043,7 +2034,7 @@ static const struct file_operations gfs2_sbstats_fops = { .open = gfs2_sbstats_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release, }; int gfs2_create_debugfs_file(struct gfs2_sbd *sdp) -- GitLab From 15562c439d0a1850b71aa1c0d92d1f4fb9503c8d Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 16 Mar 2015 11:52:05 -0500 Subject: [PATCH 6252/7006] GFS2: Move glock superblock pointer to field gl_name What uniquely identifies a glock in the glock hash table is not gl_name, but gl_name and its superblock pointer. This patch makes the gl_name field correspond to a unique glock identifier. That will allow us to simplify hashing with a future patch, since the hash algorithm can then take the gl_name and hash its components in one operation. Signed-off-by: Bob Peterson Signed-off-by: Andreas Gruenbacher Acked-by: Steven Whitehouse --- fs/gfs2/glock.c | 32 +++++++++++++++----------------- fs/gfs2/glops.c | 38 ++++++++++++++++++++------------------ fs/gfs2/incore.h | 9 +++++---- fs/gfs2/lock_dlm.c | 10 +++++----- fs/gfs2/lops.c | 6 +++--- fs/gfs2/meta_io.c | 6 +++--- fs/gfs2/meta_io.h | 2 +- fs/gfs2/quota.c | 22 +++++++++++----------- fs/gfs2/rgrp.c | 2 +- fs/gfs2/trace_gfs2.h | 18 +++++++++--------- fs/gfs2/trans.c | 4 ++-- 11 files changed, 75 insertions(+), 74 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index a694413a6e32b..13cba6e3ef6ab 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -119,7 +119,7 @@ static void gfs2_glock_dealloc(struct rcu_head *rcu) void gfs2_glock_free(struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; call_rcu(&gl->gl_rcu, gfs2_glock_dealloc); if (atomic_dec_and_test(&sdp->sd_glock_disposal)) @@ -192,7 +192,7 @@ static void gfs2_glock_remove_from_lru(struct gfs2_glock *gl) void gfs2_glock_put(struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct address_space *mapping = gfs2_glock2aspace(gl); if (lockref_put_or_lock(&gl->gl_lockref)) @@ -220,7 +220,6 @@ void gfs2_glock_put(struct gfs2_glock *gl) */ static struct gfs2_glock *search_bucket(unsigned int hash, - const struct gfs2_sbd *sdp, const struct lm_lockname *name) { struct gfs2_glock *gl; @@ -229,8 +228,6 @@ static struct gfs2_glock *search_bucket(unsigned int hash, hlist_bl_for_each_entry_rcu(gl, h, &gl_hash_table[hash], gl_list) { if (!lm_name_equal(&gl->gl_name, name)) continue; - if (gl->gl_sbd != sdp) - continue; if (lockref_get_not_dead(&gl->gl_lockref)) return gl; } @@ -506,7 +503,7 @@ __releases(&gl->gl_spin) __acquires(&gl->gl_spin) { const struct gfs2_glock_operations *glops = gl->gl_ops; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; unsigned int lck_flags = gh ? gh->gh_flags : 0; int ret; @@ -628,7 +625,7 @@ out_unlock: static void delete_work_func(struct work_struct *work) { struct gfs2_glock *gl = container_of(work, struct gfs2_glock, gl_delete); - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_inode *ip; struct inode *inode; u64 no_addr = gl->gl_name.ln_number; @@ -704,14 +701,16 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, struct gfs2_glock **glp) { struct super_block *s = sdp->sd_vfs; - struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type }; + struct lm_lockname name = { .ln_number = number, + .ln_type = glops->go_type, + .ln_sbd = sdp }; struct gfs2_glock *gl, *tmp; unsigned int hash = gl_hash(sdp, &name); struct address_space *mapping; struct kmem_cache *cachep; rcu_read_lock(); - gl = search_bucket(hash, sdp, &name); + gl = search_bucket(hash, &name); rcu_read_unlock(); *glp = gl; @@ -739,7 +738,6 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, } atomic_inc(&sdp->sd_glock_disposal); - gl->gl_sbd = sdp; gl->gl_flags = 0; gl->gl_name = name; gl->gl_lockref.count = 1; @@ -772,7 +770,7 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, } spin_lock_bucket(hash); - tmp = search_bucket(hash, sdp, &name); + tmp = search_bucket(hash, &name); if (tmp) { spin_unlock_bucket(hash); kfree(gl->gl_lksb.sb_lvbptr); @@ -928,7 +926,7 @@ __releases(&gl->gl_spin) __acquires(&gl->gl_spin) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct list_head *insert_pt = NULL; struct gfs2_holder *gh2; int try_futile = 0; @@ -1006,7 +1004,7 @@ trap_recursive: int gfs2_glock_nq(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; int error = 0; if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) @@ -1313,7 +1311,7 @@ static int gfs2_should_freeze(const struct gfs2_glock *gl) void gfs2_glock_complete(struct gfs2_glock *gl, int ret) { - struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct; spin_lock(&gl->gl_spin); gl->gl_reply = ret; @@ -1471,7 +1469,7 @@ static void examine_bucket(glock_examiner examiner, const struct gfs2_sbd *sdp, rcu_read_lock(); hlist_bl_for_each_entry_rcu(gl, pos, head, gl_list) { - if ((gl->gl_sbd == sdp) && lockref_get_not_dead(&gl->gl_lockref)) + if ((gl->gl_name.ln_sbd == sdp) && lockref_get_not_dead(&gl->gl_lockref)) examiner(gl); } rcu_read_unlock(); @@ -1569,7 +1567,7 @@ void gfs2_glock_finish_truncate(struct gfs2_inode *ip) int ret; ret = gfs2_truncatei_resume(ip); - gfs2_assert_withdraw(gl->gl_sbd, ret == 0); + gfs2_assert_withdraw(gl->gl_name.ln_sbd, ret == 0); spin_lock(&gl->gl_spin); clear_bit(GLF_LOCK, &gl->gl_flags); @@ -1872,7 +1870,7 @@ static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) gi->nhash = 0; } /* Skip entries for other sb and dead entries */ - } while (gi->sdp != gi->gl->gl_sbd || + } while (gi->sdp != gi->gl->gl_name.ln_sbd || __lockref_is_dead(&gi->gl->gl_lockref)); return 0; diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c index fa3fa5e945536..1f6c9c3fe5cbb 100644 --- a/fs/gfs2/glops.c +++ b/fs/gfs2/glops.c @@ -32,13 +32,15 @@ struct workqueue_struct *gfs2_freeze_wq; static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh) { - fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n", + fs_err(gl->gl_name.ln_sbd, + "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page " + "state 0x%lx\n", bh, (unsigned long long)bh->b_blocknr, bh->b_state, bh->b_page->mapping, bh->b_page->flags); - fs_err(gl->gl_sbd, "AIL glock %u:%llu mapping %p\n", + fs_err(gl->gl_name.ln_sbd, "AIL glock %u:%llu mapping %p\n", gl->gl_name.ln_type, gl->gl_name.ln_number, gfs2_glock2aspace(gl)); - gfs2_lm_withdraw(gl->gl_sbd, "AIL error\n"); + gfs2_lm_withdraw(gl->gl_name.ln_sbd, "AIL error\n"); } /** @@ -52,7 +54,7 @@ static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh) static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync, unsigned int nr_revokes) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct list_head *head = &gl->gl_ail_list; struct gfs2_bufdata *bd, *tmp; struct buffer_head *bh; @@ -80,7 +82,7 @@ static void __gfs2_ail_flush(struct gfs2_glock *gl, bool fsync, static void gfs2_ail_empty_gl(struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_trans tr; memset(&tr, 0, sizeof(tr)); @@ -109,7 +111,7 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl) void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; unsigned int revokes = atomic_read(&gl->gl_ail_count); unsigned int max_revokes = (sdp->sd_sb.sb_bsize - sizeof(struct gfs2_log_descriptor)) / sizeof(u64); int ret; @@ -139,7 +141,7 @@ void gfs2_ail_flush(struct gfs2_glock *gl, bool fsync) static void rgrp_go_sync(struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct address_space *mapping = &sdp->sd_aspace; struct gfs2_rgrpd *rgd; int error; @@ -179,7 +181,7 @@ static void rgrp_go_sync(struct gfs2_glock *gl) static void rgrp_go_inval(struct gfs2_glock *gl, int flags) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct address_space *mapping = &sdp->sd_aspace; struct gfs2_rgrpd *rgd = gl->gl_object; @@ -218,7 +220,7 @@ static void inode_go_sync(struct gfs2_glock *gl) GLOCK_BUG_ON(gl, gl->gl_state != LM_ST_EXCLUSIVE); - gfs2_log_flush(gl->gl_sbd, gl, NORMAL_FLUSH); + gfs2_log_flush(gl->gl_name.ln_sbd, gl, NORMAL_FLUSH); filemap_fdatawrite(metamapping); if (ip) { struct address_space *mapping = ip->i_inode.i_mapping; @@ -252,7 +254,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) { struct gfs2_inode *ip = gl->gl_object; - gfs2_assert_withdraw(gl->gl_sbd, !atomic_read(&gl->gl_ail_count)); + gfs2_assert_withdraw(gl->gl_name.ln_sbd, !atomic_read(&gl->gl_ail_count)); if (flags & DIO_METADATA) { struct address_space *mapping = gfs2_glock2aspace(gl); @@ -264,9 +266,9 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) } } - if (ip == GFS2_I(gl->gl_sbd->sd_rindex)) { - gfs2_log_flush(gl->gl_sbd, NULL, NORMAL_FLUSH); - gl->gl_sbd->sd_rindex_uptodate = 0; + if (ip == GFS2_I(gl->gl_name.ln_sbd->sd_rindex)) { + gfs2_log_flush(gl->gl_name.ln_sbd, NULL, NORMAL_FLUSH); + gl->gl_name.ln_sbd->sd_rindex_uptodate = 0; } if (ip && S_ISREG(ip->i_inode.i_mode)) truncate_inode_pages(ip->i_inode.i_mapping, 0); @@ -281,7 +283,7 @@ static void inode_go_inval(struct gfs2_glock *gl, int flags) static int inode_go_demote_ok(const struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_holder *gh; if (sdp->sd_jindex == gl->gl_object || sdp->sd_rindex == gl->gl_object) @@ -416,7 +418,7 @@ int gfs2_inode_refresh(struct gfs2_inode *ip) static int inode_go_lock(struct gfs2_holder *gh) { struct gfs2_glock *gl = gh->gh_gl; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_inode *ip = gl->gl_object; int error = 0; @@ -477,7 +479,7 @@ static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl) static void freeze_go_sync(struct gfs2_glock *gl) { int error = 0; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; if (gl->gl_state == LM_ST_SHARED && test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) { @@ -500,7 +502,7 @@ static void freeze_go_sync(struct gfs2_glock *gl) static int freeze_go_xmote_bh(struct gfs2_glock *gl, struct gfs2_holder *gh) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode); struct gfs2_glock *j_gl = ip->i_gl; struct gfs2_log_header_host head; @@ -545,7 +547,7 @@ static int freeze_go_demote_ok(const struct gfs2_glock *gl) static void iopen_go_callback(struct gfs2_glock *gl, bool remote) { struct gfs2_inode *ip = (struct gfs2_inode *)gl->gl_object; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; if (!remote || (sdp->sd_vfs->s_flags & MS_RDONLY)) return; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index a1ec7c20e4982..35a55f3d6d3be 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -203,13 +203,15 @@ enum { }; struct lm_lockname { + struct gfs2_sbd *ln_sbd; u64 ln_number; unsigned int ln_type; }; #define lm_name_equal(name1, name2) \ - (((name1)->ln_number == (name2)->ln_number) && \ - ((name1)->ln_type == (name2)->ln_type)) + (((name1)->ln_number == (name2)->ln_number) && \ + ((name1)->ln_type == (name2)->ln_type) && \ + ((name1)->ln_sbd == (name2)->ln_sbd)) struct gfs2_glock_operations { @@ -327,7 +329,6 @@ enum { struct gfs2_glock { struct hlist_bl_node gl_list; - struct gfs2_sbd *gl_sbd; unsigned long gl_flags; /* GLF_... */ struct lm_lockname gl_name; @@ -835,7 +836,7 @@ static inline void gfs2_glstats_inc(struct gfs2_glock *gl, int which) static inline void gfs2_sbstats_inc(const struct gfs2_glock *gl, int which) { - const struct gfs2_sbd *sdp = gl->gl_sbd; + const struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; preempt_disable(); this_cpu_ptr(sdp->sd_lkstats)->lkstats[gl->gl_name.ln_type].stats[which]++; preempt_enable(); diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index 641383a9c1bbf..c962cfcf19b05 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -80,7 +80,7 @@ static inline void gfs2_update_reply_times(struct gfs2_glock *gl) preempt_disable(); rtt = ktime_to_ns(ktime_sub(ktime_get_real(), gl->gl_dstamp)); - lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats); + lks = this_cpu_ptr(gl->gl_name.ln_sbd->sd_lkstats); gfs2_update_stats(&gl->gl_stats, index, rtt); /* Local */ gfs2_update_stats(&lks->lkstats[gltype], index, rtt); /* Global */ preempt_enable(); @@ -108,7 +108,7 @@ static inline void gfs2_update_request_times(struct gfs2_glock *gl) dstamp = gl->gl_dstamp; gl->gl_dstamp = ktime_get_real(); irt = ktime_to_ns(ktime_sub(gl->gl_dstamp, dstamp)); - lks = this_cpu_ptr(gl->gl_sbd->sd_lkstats); + lks = this_cpu_ptr(gl->gl_name.ln_sbd->sd_lkstats); gfs2_update_stats(&gl->gl_stats, GFS2_LKS_SIRT, irt); /* Local */ gfs2_update_stats(&lks->lkstats[gltype], GFS2_LKS_SIRT, irt); /* Global */ preempt_enable(); @@ -253,7 +253,7 @@ static void gfs2_reverse_hex(char *c, u64 value) static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, unsigned int flags) { - struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct; int req; u32 lkf; char strname[GDLM_STRNAME_BYTES] = ""; @@ -281,7 +281,7 @@ static int gdlm_lock(struct gfs2_glock *gl, unsigned int req_state, static void gdlm_put_lock(struct gfs2_glock *gl) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct lm_lockstruct *ls = &sdp->sd_lockstruct; int lvb_needs_unlock = 0; int error; @@ -319,7 +319,7 @@ static void gdlm_put_lock(struct gfs2_glock *gl) static void gdlm_cancel(struct gfs2_glock *gl) { - struct lm_lockstruct *ls = &gl->gl_sbd->sd_lockstruct; + struct lm_lockstruct *ls = &gl->gl_name.ln_sbd->sd_lockstruct; dlm_unlock(ls->ls_dlm, gl->gl_lksb.sb_lkid, DLM_LKF_CANCEL, NULL, gl); } diff --git a/fs/gfs2/lops.c b/fs/gfs2/lops.c index 2c1ae861dc944..7833394a9a202 100644 --- a/fs/gfs2/lops.c +++ b/fs/gfs2/lops.c @@ -70,7 +70,7 @@ static bool buffer_is_rgrp(const struct gfs2_bufdata *bd) static void maybe_release_space(struct gfs2_bufdata *bd) { struct gfs2_glock *gl = bd->bd_gl; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_rgrpd *rgd = gl->gl_object; unsigned int index = bd->bd_bh->b_blocknr - gl->gl_name.ln_number; struct gfs2_bitmap *bi = rgd->rd_bits + index; @@ -585,7 +585,7 @@ static int buf_lo_scan_elements(struct gfs2_jdesc *jd, unsigned int start, static void gfs2_meta_sync(struct gfs2_glock *gl) { struct address_space *mapping = gfs2_glock2aspace(gl); - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; int error; if (mapping == NULL) @@ -595,7 +595,7 @@ static void gfs2_meta_sync(struct gfs2_glock *gl) error = filemap_fdatawait(mapping); if (error) - gfs2_io_error(gl->gl_sbd); + gfs2_io_error(gl->gl_name.ln_sbd); } static void buf_lo_after_scan(struct gfs2_jdesc *jd, int error, int pass) diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index b984a6e190bc2..0e1d4be5865a5 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -114,7 +114,7 @@ const struct address_space_operations gfs2_rgrp_aops = { struct buffer_head *gfs2_getbuf(struct gfs2_glock *gl, u64 blkno, int create) { struct address_space *mapping = gfs2_glock2aspace(gl); - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct page *page; struct buffer_head *bh; unsigned int shift; @@ -200,7 +200,7 @@ struct buffer_head *gfs2_meta_new(struct gfs2_glock *gl, u64 blkno) int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, struct buffer_head **bhp) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct buffer_head *bh; if (unlikely(test_bit(SDF_SHUTDOWN, &sdp->sd_flags))) { @@ -362,7 +362,7 @@ int gfs2_meta_indirect_buffer(struct gfs2_inode *ip, int height, u64 num, struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct buffer_head *first_bh, *bh; u32 max_ra = gfs2_tune_get(sdp, gt_max_readahead) >> sdp->sd_sb.sb_bsize_shift; diff --git a/fs/gfs2/meta_io.h b/fs/gfs2/meta_io.h index ac5d8027d3356..8ca161567a93c 100644 --- a/fs/gfs2/meta_io.h +++ b/fs/gfs2/meta_io.h @@ -44,7 +44,7 @@ static inline struct gfs2_sbd *gfs2_mapping2sbd(struct address_space *mapping) { struct inode *inode = mapping->host; if (mapping->a_ops == &gfs2_meta_aops) - return (((struct gfs2_glock *)mapping) - 1)->gl_sbd; + return (((struct gfs2_glock *)mapping) - 1)->gl_name.ln_sbd; else if (mapping->a_ops == &gfs2_rgrp_aops) return container_of(mapping, struct gfs2_sbd, sd_aspace); else diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c index 9b61f92fcfdf0..3a31226531ea8 100644 --- a/fs/gfs2/quota.c +++ b/fs/gfs2/quota.c @@ -119,7 +119,7 @@ static void gfs2_qd_dispose(struct list_head *list) while (!list_empty(list)) { qd = list_entry(list->next, struct gfs2_quota_data, qd_lru); - sdp = qd->qd_gl->gl_sbd; + sdp = qd->qd_gl->gl_name.ln_sbd; list_del(&qd->qd_lru); @@ -302,7 +302,7 @@ static int qd_get(struct gfs2_sbd *sdp, struct kqid qid, static void qd_hold(struct gfs2_quota_data *qd) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; gfs2_assert(sdp, !__lockref_is_dead(&qd->qd_lockref)); lockref_get(&qd->qd_lockref); } @@ -367,7 +367,7 @@ static void slot_put(struct gfs2_quota_data *qd) static int bh_get(struct gfs2_quota_data *qd) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); unsigned int block, offset; struct buffer_head *bh; @@ -414,7 +414,7 @@ fail: static void bh_put(struct gfs2_quota_data *qd) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; mutex_lock(&sdp->sd_quota_mutex); gfs2_assert(sdp, qd->qd_bh_count); @@ -486,7 +486,7 @@ static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) static void qd_unlock(struct gfs2_quota_data *qd) { - gfs2_assert_warn(qd->qd_gl->gl_sbd, + gfs2_assert_warn(qd->qd_gl->gl_name.ln_sbd, test_bit(QDF_LOCKED, &qd->qd_flags)); clear_bit(QDF_LOCKED, &qd->qd_flags); bh_put(qd); @@ -614,7 +614,7 @@ static int sort_qd(const void *a, const void *b) static void do_qc(struct gfs2_quota_data *qd, s64 change) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); struct gfs2_quota_change *qc = qd->qd_bh_qc; s64 x; @@ -831,7 +831,7 @@ static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) { - struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_name.ln_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_alloc_parms ap = { .aflags = 0, }; unsigned int data_blocks, ind_blocks; @@ -922,7 +922,7 @@ out: gfs2_glock_dq_uninit(&ghs[qx]); mutex_unlock(&ip->i_inode.i_mutex); kfree(ghs); - gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl, NORMAL_FLUSH); + gfs2_log_flush(ip->i_gl->gl_name.ln_sbd, ip->i_gl, NORMAL_FLUSH); return error; } @@ -954,7 +954,7 @@ static int update_qd(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd) static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder *q_gh) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_holder i_gh; int error; @@ -1037,7 +1037,7 @@ int gfs2_quota_lock(struct gfs2_inode *ip, kuid_t uid, kgid_t gid) static int need_sync(struct gfs2_quota_data *qd) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; struct gfs2_tune *gt = &sdp->sd_tune; s64 value; unsigned int num, den; @@ -1125,7 +1125,7 @@ out: static int print_message(struct gfs2_quota_data *qd, char *type) { - struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; + struct gfs2_sbd *sdp = qd->qd_gl->gl_name.ln_sbd; fs_info(sdp, "quota %s for %s %u\n", type, diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index c6c62321dfd6f..c92ae7fd36f38 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1860,7 +1860,7 @@ static void try_rgrp_unlink(struct gfs2_rgrpd *rgd, u64 *last_unlinked, u64 skip static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops) { const struct gfs2_glock *gl = rgd->rd_gl; - const struct gfs2_sbd *sdp = gl->gl_sbd; + const struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_lkstats *st; s64 r_dcount, l_dcount; s64 l_srttb, a_srttb = 0; diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index 20c007d747ab2..fff47d0e0ef55 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -104,7 +104,7 @@ TRACE_EVENT(gfs2_glock_state_change, ), TP_fast_assign( - __entry->dev = gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->glnum = gl->gl_name.ln_number; __entry->gltype = gl->gl_name.ln_type; __entry->cur_state = glock_trace_state(gl->gl_state); @@ -140,7 +140,7 @@ TRACE_EVENT(gfs2_glock_put, ), TP_fast_assign( - __entry->dev = gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->gltype = gl->gl_name.ln_type; __entry->glnum = gl->gl_name.ln_number; __entry->cur_state = glock_trace_state(gl->gl_state); @@ -174,7 +174,7 @@ TRACE_EVENT(gfs2_demote_rq, ), TP_fast_assign( - __entry->dev = gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->gltype = gl->gl_name.ln_type; __entry->glnum = gl->gl_name.ln_number; __entry->cur_state = glock_trace_state(gl->gl_state); @@ -209,7 +209,7 @@ TRACE_EVENT(gfs2_promote, ), TP_fast_assign( - __entry->dev = gh->gh_gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = gh->gh_gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->glnum = gh->gh_gl->gl_name.ln_number; __entry->gltype = gh->gh_gl->gl_name.ln_type; __entry->first = first; @@ -239,7 +239,7 @@ TRACE_EVENT(gfs2_glock_queue, ), TP_fast_assign( - __entry->dev = gh->gh_gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = gh->gh_gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->glnum = gh->gh_gl->gl_name.ln_number; __entry->gltype = gh->gh_gl->gl_name.ln_type; __entry->queue = queue; @@ -278,7 +278,7 @@ TRACE_EVENT(gfs2_glock_lock_time, ), TP_fast_assign( - __entry->dev = gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->glnum = gl->gl_name.ln_number; __entry->gltype = gl->gl_name.ln_type; __entry->status = gl->gl_lksb.sb_status; @@ -333,7 +333,7 @@ TRACE_EVENT(gfs2_pin, ), TP_fast_assign( - __entry->dev = bd->bd_gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = bd->bd_gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->pin = pin; __entry->len = bd->bd_bh->b_size; __entry->block = bd->bd_bh->b_blocknr; @@ -449,7 +449,7 @@ TRACE_EVENT(gfs2_bmap, ), TP_fast_assign( - __entry->dev = ip->i_gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = ip->i_gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->lblock = lblock; __entry->pblock = buffer_mapped(bh) ? bh->b_blocknr : 0; __entry->inum = ip->i_no_addr; @@ -489,7 +489,7 @@ TRACE_EVENT(gfs2_block_alloc, ), TP_fast_assign( - __entry->dev = rgd->rd_gl->gl_sbd->sd_vfs->s_dev; + __entry->dev = rgd->rd_gl->gl_name.ln_sbd->sd_vfs->s_dev; __entry->start = block; __entry->inum = ip->i_no_addr; __entry->len = len; diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c index 88bff24306691..b95d0d625f32b 100644 --- a/fs/gfs2/trans.c +++ b/fs/gfs2/trans.c @@ -158,7 +158,7 @@ static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl, void gfs2_trans_add_data(struct gfs2_glock *gl, struct buffer_head *bh) { struct gfs2_trans *tr = current->journal_info; - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct address_space *mapping = bh->b_page->mapping; struct gfs2_inode *ip = GFS2_I(mapping->host); struct gfs2_bufdata *bd; @@ -224,7 +224,7 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd) void gfs2_trans_add_meta(struct gfs2_glock *gl, struct buffer_head *bh) { - struct gfs2_sbd *sdp = gl->gl_sbd; + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_bufdata *bd; lock_buffer(bh); -- GitLab From 88ffbf3e037e67b52c46d528aca1618489c21f68 Mon Sep 17 00:00:00 2001 From: Bob Peterson Date: Mon, 16 Mar 2015 11:02:46 -0500 Subject: [PATCH 6253/7006] GFS2: Use resizable hash table for glocks This patch changes the glock hash table from a normal hash table to a resizable hash table, which scales better. This also simplifies a lot of code. Signed-off-by: Bob Peterson Signed-off-by: Andreas Gruenbacher Acked-by: Steven Whitehouse --- fs/gfs2/glock.c | 264 ++++++++++++++++++----------------------------- fs/gfs2/incore.h | 4 +- 2 files changed, 102 insertions(+), 166 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 13cba6e3ef6ab..edb15eeb0ad55 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "gfs2.h" #include "incore.h" @@ -50,9 +51,8 @@ #include "trace_gfs2.h" struct gfs2_glock_iter { - int hash; /* hash bucket index */ - unsigned nhash; /* Index within current bucket */ struct gfs2_sbd *sdp; /* incore superblock */ + struct rhashtable_iter hti; /* rhashtable iterator */ struct gfs2_glock *gl; /* current glock struct */ loff_t last_pos; /* last position */ }; @@ -70,44 +70,19 @@ static DEFINE_SPINLOCK(lru_lock); #define GFS2_GL_HASH_SHIFT 15 #define GFS2_GL_HASH_SIZE (1 << GFS2_GL_HASH_SHIFT) -#define GFS2_GL_HASH_MASK (GFS2_GL_HASH_SIZE - 1) -static struct hlist_bl_head gl_hash_table[GFS2_GL_HASH_SIZE]; -static struct dentry *gfs2_root; - -/** - * gl_hash() - Turn glock number into hash bucket number - * @lock: The glock number - * - * Returns: The number of the corresponding hash bucket - */ - -static unsigned int gl_hash(const struct gfs2_sbd *sdp, - const struct lm_lockname *name) -{ - unsigned int h; - - h = jhash(&name->ln_number, sizeof(u64), 0); - h = jhash(&name->ln_type, sizeof(unsigned int), h); - h = jhash(&sdp, sizeof(struct gfs2_sbd *), h); - h &= GFS2_GL_HASH_MASK; - - return h; -} - -static inline void spin_lock_bucket(unsigned int hash) -{ - hlist_bl_lock(&gl_hash_table[hash]); -} +static struct rhashtable_params ht_parms = { + .nelem_hint = GFS2_GL_HASH_SIZE * 3 / 4, + .key_len = sizeof(struct lm_lockname), + .key_offset = offsetof(struct gfs2_glock, gl_name), + .head_offset = offsetof(struct gfs2_glock, gl_node), +}; -static inline void spin_unlock_bucket(unsigned int hash) -{ - hlist_bl_unlock(&gl_hash_table[hash]); -} +static struct rhashtable gl_hash_table; -static void gfs2_glock_dealloc(struct rcu_head *rcu) +void gfs2_glock_free(struct gfs2_glock *gl) { - struct gfs2_glock *gl = container_of(rcu, struct gfs2_glock, gl_rcu); + struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; if (gl->gl_ops->go_flags & GLOF_ASPACE) { kmem_cache_free(gfs2_glock_aspace_cachep, gl); @@ -115,13 +90,6 @@ static void gfs2_glock_dealloc(struct rcu_head *rcu) kfree(gl->gl_lksb.sb_lvbptr); kmem_cache_free(gfs2_glock_cachep, gl); } -} - -void gfs2_glock_free(struct gfs2_glock *gl) -{ - struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; - - call_rcu(&gl->gl_rcu, gfs2_glock_dealloc); if (atomic_dec_and_test(&sdp->sd_glock_disposal)) wake_up(&sdp->sd_glock_wait); } @@ -202,39 +170,13 @@ void gfs2_glock_put(struct gfs2_glock *gl) gfs2_glock_remove_from_lru(gl); spin_unlock(&gl->gl_lockref.lock); - spin_lock_bucket(gl->gl_hash); - hlist_bl_del_rcu(&gl->gl_list); - spin_unlock_bucket(gl->gl_hash); + rhashtable_remove_fast(&gl_hash_table, &gl->gl_node, ht_parms); GLOCK_BUG_ON(gl, !list_empty(&gl->gl_holders)); GLOCK_BUG_ON(gl, mapping && mapping->nrpages); trace_gfs2_glock_put(gl); sdp->sd_lockstruct.ls_ops->lm_put_lock(gl); } -/** - * search_bucket() - Find struct gfs2_glock by lock number - * @bucket: the bucket to search - * @name: The lock name - * - * Returns: NULL, or the struct gfs2_glock with the requested number - */ - -static struct gfs2_glock *search_bucket(unsigned int hash, - const struct lm_lockname *name) -{ - struct gfs2_glock *gl; - struct hlist_bl_node *h; - - hlist_bl_for_each_entry_rcu(gl, h, &gl_hash_table[hash], gl_list) { - if (!lm_name_equal(&gl->gl_name, name)) - continue; - if (lockref_get_not_dead(&gl->gl_lockref)) - return gl; - } - - return NULL; -} - /** * may_grant - check if its ok to grant a new lock * @gl: The glock @@ -704,14 +646,14 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, struct lm_lockname name = { .ln_number = number, .ln_type = glops->go_type, .ln_sbd = sdp }; - struct gfs2_glock *gl, *tmp; - unsigned int hash = gl_hash(sdp, &name); + struct gfs2_glock *gl, *tmp = NULL; struct address_space *mapping; struct kmem_cache *cachep; + int ret, tries = 0; - rcu_read_lock(); - gl = search_bucket(hash, &name); - rcu_read_unlock(); + gl = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms); + if (gl && !lockref_get_not_dead(&gl->gl_lockref)) + gl = NULL; *glp = gl; if (gl) @@ -738,13 +680,13 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, } atomic_inc(&sdp->sd_glock_disposal); + gl->gl_node.next = NULL; gl->gl_flags = 0; gl->gl_name = name; gl->gl_lockref.count = 1; gl->gl_state = LM_ST_UNLOCKED; gl->gl_target = LM_ST_UNLOCKED; gl->gl_demote_state = LM_ST_EXCLUSIVE; - gl->gl_hash = hash; gl->gl_ops = glops; gl->gl_dstamp = ktime_set(0, 0); preempt_disable(); @@ -769,22 +711,34 @@ int gfs2_glock_get(struct gfs2_sbd *sdp, u64 number, mapping->writeback_index = 0; } - spin_lock_bucket(hash); - tmp = search_bucket(hash, &name); - if (tmp) { - spin_unlock_bucket(hash); - kfree(gl->gl_lksb.sb_lvbptr); - kmem_cache_free(cachep, gl); - atomic_dec(&sdp->sd_glock_disposal); - gl = tmp; - } else { - hlist_bl_add_head_rcu(&gl->gl_list, &gl_hash_table[hash]); - spin_unlock_bucket(hash); +again: + ret = rhashtable_lookup_insert_fast(&gl_hash_table, &gl->gl_node, + ht_parms); + if (ret == 0) { + *glp = gl; + return 0; } - *glp = gl; + if (ret == -EEXIST) { + ret = 0; + tmp = rhashtable_lookup_fast(&gl_hash_table, &name, ht_parms); + if (tmp == NULL || !lockref_get_not_dead(&tmp->gl_lockref)) { + if (++tries < 100) { + cond_resched(); + goto again; + } + tmp = NULL; + ret = -ENOMEM; + } + } else { + WARN_ON_ONCE(ret); + } + kfree(gl->gl_lksb.sb_lvbptr); + kmem_cache_free(cachep, gl); + atomic_dec(&sdp->sd_glock_disposal); + *glp = tmp; - return 0; + return ret; } /** @@ -1460,31 +1414,26 @@ static struct shrinker glock_shrinker = { * */ -static void examine_bucket(glock_examiner examiner, const struct gfs2_sbd *sdp, - unsigned int hash) +static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp) { struct gfs2_glock *gl; - struct hlist_bl_head *head = &gl_hash_table[hash]; - struct hlist_bl_node *pos; + struct rhash_head *pos, *next; + const struct bucket_table *tbl; + int i; rcu_read_lock(); - hlist_bl_for_each_entry_rcu(gl, pos, head, gl_list) { - if ((gl->gl_name.ln_sbd == sdp) && lockref_get_not_dead(&gl->gl_lockref)) - examiner(gl); + tbl = rht_dereference_rcu(gl_hash_table.tbl, &gl_hash_table); + for (i = 0; i < tbl->size; i++) { + rht_for_each_entry_safe(gl, pos, next, tbl, i, gl_node) { + if ((gl->gl_name.ln_sbd == sdp) && + lockref_get_not_dead(&gl->gl_lockref)) + examiner(gl); + } } rcu_read_unlock(); cond_resched(); } -static void glock_hash_walk(glock_examiner examiner, const struct gfs2_sbd *sdp) -{ - unsigned x; - - for (x = 0; x < GFS2_GL_HASH_SIZE; x++) - examine_bucket(examiner, sdp, x); -} - - /** * thaw_glock - thaw out a glock which has an unprocessed reply waiting * @gl: The glock to thaw @@ -1802,20 +1751,24 @@ static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) int __init gfs2_glock_init(void) { - unsigned i; - for(i = 0; i < GFS2_GL_HASH_SIZE; i++) { - INIT_HLIST_BL_HEAD(&gl_hash_table[i]); - } + int ret; + + ret = rhashtable_init(&gl_hash_table, &ht_parms); + if (ret < 0) + return ret; glock_workqueue = alloc_workqueue("glock_workqueue", WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_FREEZABLE, 0); - if (!glock_workqueue) + if (!glock_workqueue) { + rhashtable_destroy(&gl_hash_table); return -ENOMEM; + } gfs2_delete_workqueue = alloc_workqueue("delete_workqueue", WQ_MEM_RECLAIM | WQ_FREEZABLE, 0); if (!gfs2_delete_workqueue) { destroy_workqueue(glock_workqueue); + rhashtable_destroy(&gl_hash_table); return -ENOMEM; } @@ -1827,72 +1780,41 @@ int __init gfs2_glock_init(void) void gfs2_glock_exit(void) { unregister_shrinker(&glock_shrinker); + rhashtable_destroy(&gl_hash_table); destroy_workqueue(glock_workqueue); destroy_workqueue(gfs2_delete_workqueue); } -static inline struct gfs2_glock *glock_hash_chain(unsigned hash) +static void gfs2_glock_iter_next(struct gfs2_glock_iter *gi) { - return hlist_bl_entry(hlist_bl_first_rcu(&gl_hash_table[hash]), - struct gfs2_glock, gl_list); -} - -static inline struct gfs2_glock *glock_hash_next(struct gfs2_glock *gl) -{ - return hlist_bl_entry(rcu_dereference(gl->gl_list.next), - struct gfs2_glock, gl_list); -} - -static int gfs2_glock_iter_next(struct gfs2_glock_iter *gi) -{ - struct gfs2_glock *gl; - do { - gl = gi->gl; - if (gl) { - gi->gl = glock_hash_next(gl); - gi->nhash++; - } else { - if (gi->hash >= GFS2_GL_HASH_SIZE) { - rcu_read_unlock(); - return 1; - } - gi->gl = glock_hash_chain(gi->hash); - gi->nhash = 0; - } - while (gi->gl == NULL) { - gi->hash++; - if (gi->hash >= GFS2_GL_HASH_SIZE) { - rcu_read_unlock(); - return 1; - } - gi->gl = glock_hash_chain(gi->hash); - gi->nhash = 0; + gi->gl = rhashtable_walk_next(&gi->hti); + if (IS_ERR(gi->gl)) { + if (PTR_ERR(gi->gl) == -EAGAIN) + continue; + gi->gl = NULL; } /* Skip entries for other sb and dead entries */ - } while (gi->sdp != gi->gl->gl_name.ln_sbd || - __lockref_is_dead(&gi->gl->gl_lockref)); - - return 0; + } while ((gi->gl) && ((gi->sdp != gi->gl->gl_name.ln_sbd) || + __lockref_is_dead(&gi->gl->gl_lockref))); } static void *gfs2_glock_seq_start(struct seq_file *seq, loff_t *pos) { struct gfs2_glock_iter *gi = seq->private; loff_t n = *pos; + int ret; if (gi->last_pos <= *pos) - n = gi->nhash + (*pos - gi->last_pos); - else - gi->hash = 0; + n = (*pos - gi->last_pos); - gi->nhash = 0; - rcu_read_lock(); + ret = rhashtable_walk_start(&gi->hti); + if (ret) + return NULL; do { - if (gfs2_glock_iter_next(gi)) - return NULL; - } while (n--); + gfs2_glock_iter_next(gi); + } while (gi->gl && n--); gi->last_pos = *pos; return gi->gl; @@ -1905,9 +1827,7 @@ static void *gfs2_glock_seq_next(struct seq_file *seq, void *iter_ptr, (*pos)++; gi->last_pos = *pos; - if (gfs2_glock_iter_next(gi)) - return NULL; - + gfs2_glock_iter_next(gi); return gi->gl; } @@ -1915,9 +1835,8 @@ static void gfs2_glock_seq_stop(struct seq_file *seq, void *iter_ptr) { struct gfs2_glock_iter *gi = seq->private; - if (gi->gl) - rcu_read_unlock(); gi->gl = NULL; + rhashtable_walk_stop(&gi->hti); } static int gfs2_glock_seq_show(struct seq_file *seq, void *iter_ptr) @@ -1978,14 +1897,28 @@ static int gfs2_glocks_open(struct inode *inode, struct file *file) if (ret == 0) { struct seq_file *seq = file->private_data; struct gfs2_glock_iter *gi = seq->private; + gi->sdp = inode->i_private; + gi->last_pos = 0; seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN); if (seq->buf) seq->size = GFS2_SEQ_GOODSIZE; + gi->gl = NULL; + ret = rhashtable_walk_init(&gl_hash_table, &gi->hti); } return ret; } +static int gfs2_glocks_release(struct inode *inode, struct file *file) +{ + struct seq_file *seq = file->private_data; + struct gfs2_glock_iter *gi = seq->private; + + gi->gl = NULL; + rhashtable_walk_exit(&gi->hti); + return seq_release_private(inode, file); +} + static int gfs2_glstats_open(struct inode *inode, struct file *file) { int ret = seq_open_private(file, &gfs2_glstats_seq_ops, @@ -1994,9 +1927,12 @@ static int gfs2_glstats_open(struct inode *inode, struct file *file) struct seq_file *seq = file->private_data; struct gfs2_glock_iter *gi = seq->private; gi->sdp = inode->i_private; + gi->last_pos = 0; seq->buf = kmalloc(GFS2_SEQ_GOODSIZE, GFP_KERNEL | __GFP_NOWARN); if (seq->buf) seq->size = GFS2_SEQ_GOODSIZE; + gi->gl = NULL; + ret = rhashtable_walk_init(&gl_hash_table, &gi->hti); } return ret; } @@ -2016,7 +1952,7 @@ static const struct file_operations gfs2_glocks_fops = { .open = gfs2_glocks_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = gfs2_glocks_release, }; static const struct file_operations gfs2_glstats_fops = { @@ -2024,7 +1960,7 @@ static const struct file_operations gfs2_glstats_fops = { .open = gfs2_glstats_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = gfs2_glocks_release, }; static const struct file_operations gfs2_sbstats_fops = { diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index 35a55f3d6d3be..e300f74190906 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -22,6 +22,7 @@ #include #include #include +#include #define DIO_WAIT 0x00000010 #define DIO_METADATA 0x00000020 @@ -342,7 +343,6 @@ struct gfs2_glock { gl_req:2, /* State in last dlm request */ gl_reply:8; /* Last reply from the dlm */ - unsigned int gl_hash; unsigned long gl_demote_time; /* time of first demote request */ long gl_hold_time; struct list_head gl_holders; @@ -368,7 +368,7 @@ struct gfs2_glock { loff_t end; } gl_vm; }; - struct rcu_head gl_rcu; + struct rhash_head gl_node; }; #define GFS2_MIN_LVB_SIZE 32 /* Min size of LVB that gfs2 supports */ -- GitLab From 4d207133e9c362bc05a3bb6701d63eeb75cc4b77 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Thu, 27 Aug 2015 12:51:45 -0500 Subject: [PATCH 6254/7006] gfs2: Make statistics unsigned, suitable for use with do_div() None of these statistics can meaningfully be negative, and the numerator for do_div() must have the type u64. The generic implementation of do_div() used on some 32-bit architectures asserts that, resulting in a compiler error in gfs2_rgrp_congested(). Fixes: 0166b197c2ed ("GFS2: Average in only non-zero round-trip times ...") Signed-off-by: Ben Hutchings Signed-off-by: Bob Peterson Acked-by: Andreas Gruenbacher --- fs/gfs2/glock.c | 22 +++++++++++----------- fs/gfs2/incore.h | 2 +- fs/gfs2/rgrp.c | 8 ++++---- fs/gfs2/trace_gfs2.h | 16 ++++++++-------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index edb15eeb0ad55..37d4db1ac0b27 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1680,17 +1680,17 @@ static int gfs2_glstats_seq_show(struct seq_file *seq, void *iter_ptr) { struct gfs2_glock *gl = iter_ptr; - seq_printf(seq, "G: n:%u/%llx rtt:%lld/%lld rttb:%lld/%lld irt:%lld/%lld dcnt: %lld qcnt: %lld\n", + seq_printf(seq, "G: n:%u/%llx rtt:%llu/%llu rttb:%llu/%llu irt:%llu/%llu dcnt: %llu qcnt: %llu\n", gl->gl_name.ln_type, (unsigned long long)gl->gl_name.ln_number, - (long long)gl->gl_stats.stats[GFS2_LKS_SRTT], - (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR], - (long long)gl->gl_stats.stats[GFS2_LKS_SRTTB], - (long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB], - (long long)gl->gl_stats.stats[GFS2_LKS_SIRT], - (long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR], - (long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT], - (long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]); + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_SRTT], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_SRTTVAR], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_SRTTB], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_SRTTVARB], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_SIRT], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_SIRTVAR], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_DCOUNT], + (unsigned long long)gl->gl_stats.stats[GFS2_LKS_QCOUNT]); return 0; } @@ -1727,7 +1727,7 @@ static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) loff_t pos = *(loff_t *)iter_ptr; unsigned index = pos >> 3; unsigned subindex = pos & 0x07; - s64 value; + u64 value; int i; if (index == 0 && subindex != 0) @@ -1743,7 +1743,7 @@ static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) } else { value = lkstats->lkstats[index - 1].stats[subindex]; } - seq_printf(seq, " %15lld", (long long)value); + seq_printf(seq, " %15llu", (long long)value); } seq_putc(seq, '\n'); return 0; diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h index e300f74190906..121ed08d9d9f9 100644 --- a/fs/gfs2/incore.h +++ b/fs/gfs2/incore.h @@ -244,7 +244,7 @@ enum { }; struct gfs2_lkstats { - s64 stats[GFS2_NR_LKSTATS]; + u64 stats[GFS2_NR_LKSTATS]; }; enum { diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c index c92ae7fd36f38..475985d14758c 100644 --- a/fs/gfs2/rgrp.c +++ b/fs/gfs2/rgrp.c @@ -1862,11 +1862,11 @@ static bool gfs2_rgrp_congested(const struct gfs2_rgrpd *rgd, int loops) const struct gfs2_glock *gl = rgd->rd_gl; const struct gfs2_sbd *sdp = gl->gl_name.ln_sbd; struct gfs2_lkstats *st; - s64 r_dcount, l_dcount; - s64 l_srttb, a_srttb = 0; + u64 r_dcount, l_dcount; + u64 l_srttb, a_srttb = 0; s64 srttb_diff; - s64 sqr_diff; - s64 var; + u64 sqr_diff; + u64 var; int cpu, nonzero = 0; preempt_disable(); diff --git a/fs/gfs2/trace_gfs2.h b/fs/gfs2/trace_gfs2.h index fff47d0e0ef55..49ac55da4e334 100644 --- a/fs/gfs2/trace_gfs2.h +++ b/fs/gfs2/trace_gfs2.h @@ -267,14 +267,14 @@ TRACE_EVENT(gfs2_glock_lock_time, __field( int, status ) __field( char, flags ) __field( s64, tdiff ) - __field( s64, srtt ) - __field( s64, srttvar ) - __field( s64, srttb ) - __field( s64, srttvarb ) - __field( s64, sirt ) - __field( s64, sirtvar ) - __field( s64, dcount ) - __field( s64, qcount ) + __field( u64, srtt ) + __field( u64, srttvar ) + __field( u64, srttb ) + __field( u64, srttvarb ) + __field( u64, sirt ) + __field( u64, sirtvar ) + __field( u64, dcount ) + __field( u64, qcount ) ), TP_fast_assign( -- GitLab From c9ea8c8b74b5fb2584879e4338770ed252d8a489 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Aug 2015 13:05:08 -0500 Subject: [PATCH 6255/7006] gfs2: Fix a typo in a comment Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson --- fs/gfs2/lock_dlm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/gfs2/lock_dlm.c b/fs/gfs2/lock_dlm.c index c962cfcf19b05..284c1542783eb 100644 --- a/fs/gfs2/lock_dlm.c +++ b/fs/gfs2/lock_dlm.c @@ -31,7 +31,7 @@ extern struct workqueue_struct *gfs2_control_wq; * * @delta is the difference between the current rtt sample and the * running average srtt. We add 1/8 of that to the srtt in order to - * update the current srtt estimate. The varience estimate is a bit + * update the current srtt estimate. The variance estimate is a bit * more complicated. We subtract the abs value of the @delta from * the current variance estimate and add 1/4 of that to the running * total. -- GitLab From 8f7e0a806db0a3ba33234af3c39d68ed8c144071 Mon Sep 17 00:00:00 2001 From: Andreas Gruenbacher Date: Thu, 27 Aug 2015 13:02:54 -0500 Subject: [PATCH 6256/7006] gfs2: A minor "sbstats" cleanup It seems cleaner to avoid the temporary value here. Signed-off-by: Andreas Gruenbacher Signed-off-by: Bob Peterson --- fs/gfs2/glock.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c index 37d4db1ac0b27..9bd1244caf38d 100644 --- a/fs/gfs2/glock.c +++ b/fs/gfs2/glock.c @@ -1727,7 +1727,6 @@ static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) loff_t pos = *(loff_t *)iter_ptr; unsigned index = pos >> 3; unsigned subindex = pos & 0x07; - u64 value; int i; if (index == 0 && subindex != 0) @@ -1738,12 +1737,12 @@ static int gfs2_sbstats_seq_show(struct seq_file *seq, void *iter_ptr) for_each_possible_cpu(i) { const struct gfs2_pcpu_lkstats *lkstats = per_cpu_ptr(sdp->sd_lkstats, i); - if (index == 0) { - value = i; - } else { - value = lkstats->lkstats[index - 1].stats[subindex]; - } - seq_printf(seq, " %15llu", (long long)value); + + if (index == 0) + seq_printf(seq, " %15u", i); + else + seq_printf(seq, " %15llu", (unsigned long long)lkstats-> + lkstats[index - 1].stats[subindex]); } seq_putc(seq, '\n'); return 0; -- GitLab From 11d748045c6dadb279d1acdb6d2ea8f3f2ede85b Mon Sep 17 00:00:00 2001 From: Haggai Eran Date: Tue, 1 Sep 2015 09:56:56 +0300 Subject: [PATCH 6257/7006] IB/mlx5: avoid destroying a NULL mr in reg_user_mr error flow The mlx5_ib_reg_user_mr() function will attempt to call clean_mr() in its error flow even though there is never a case where the error flow occurs with a valid MR pointer to destroy. Remove the clean_mr() call and the incorrect comment above it. Fixes: b4cfe447d47b ("IB/mlx5: Implement on demand paging by adding support for MMU notifiers") Cc: Eli Cohen Signed-off-by: Haggai Eran Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mr.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 0dfd379b9bad5..54a15b5d336d0 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -1114,19 +1114,7 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, return &mr->ibmr; error: - /* - * Destroy the umem *before* destroying the MR, to ensure we - * will not have any in-flight notifiers when destroying the - * MR. - * - * As the MR is completely invalid to begin with, and this - * error path is only taken if we can't push the mr entry into - * the pagefault tree, this is safe. - */ - ib_umem_release(umem); - /* Kill the MR, and return an error code. */ - clean_mr(mr); return ERR_PTR(err); } -- GitLab From b636401f0ec9bbf7931774e00f3adf7ee9214cce Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Wed, 2 Sep 2015 22:23:04 +0300 Subject: [PATCH 6258/7006] mlx5: Fix incorrect wc pkey_index assignment for GSI messages Since patch series "Demux IB CM requests in the rdma_cm module" the P_Key index is taken from the work completion rather than the message itself. The HCA provides us with the message P_Key. In order to provide the P_Key index, we need to look it up. Given that this is relevant only for GSI messages (session establishments) which is less performance critical, micro-optimize against the GSI (is_qp1) branch. Fixes: 4c21b5bcef73 ("IB/cma: Add net_dev and private data checks to RDMA CM") Signed-off-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/cq.c | 10 +++++++++- drivers/infiniband/hw/mlx5/mlx5_ib.h | 5 +++++ drivers/infiniband/hw/mlx5/qp.c | 5 ----- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 5c9eeea628054..2d0dbbf38ceb9 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -33,6 +33,7 @@ #include #include #include +#include #include "mlx5_ib.h" #include "user.h" @@ -227,7 +228,14 @@ static void handle_responder(struct ib_wc *wc, struct mlx5_cqe64 *cqe, wc->dlid_path_bits = cqe->ml_path; g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3; wc->wc_flags |= g ? IB_WC_GRH : 0; - wc->pkey_index = be32_to_cpu(cqe->imm_inval_pkey) & 0xffff; + if (unlikely(is_qp1(qp->ibqp.qp_type))) { + u16 pkey = be32_to_cpu(cqe->imm_inval_pkey) & 0xffff; + + ib_find_cached_pkey(&dev->ib_dev, qp->port, pkey, + &wc->pkey_index); + } else { + wc->pkey_index = 0; + } } static void dump_cqe(struct mlx5_ib_dev *dev, struct mlx5_err_cqe *cqe) diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index a5fa0b9c75802..bb8cda79e8812 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -680,6 +680,11 @@ static inline u8 convert_access(int acc) MLX5_PERM_LOCAL_READ; } +static inline int is_qp1(enum ib_qp_type qp_type) +{ + return qp_type == IB_QPT_GSI; +} + #define MLX5_MAX_UMR_SHIFT 16 #define MLX5_MAX_UMR_PAGES (1 << MLX5_MAX_UMR_SHIFT) diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 203c8a45e0955..c745c6c5e10da 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -76,11 +76,6 @@ static int is_qp0(enum ib_qp_type qp_type) return qp_type == IB_QPT_SMI; } -static int is_qp1(enum ib_qp_type qp_type) -{ - return qp_type == IB_QPT_GSI; -} - static int is_sqp(enum ib_qp_type qp_type) { return is_qp0(qp_type) || is_qp1(qp_type); -- GitLab From a64eefaac1c5cc8dbc6995228fe08a61b8e1d26b Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 2 Sep 2015 22:50:12 +0200 Subject: [PATCH 6259/7006] hpfs: support hotfixes When the OS/2 driver hits a disk write error, it writes the sector to another location and adds the sector mapping to the hotfix map. This patch makes the hpfs driver understand the hotfix map and remap accesses accoring to it. Signed-off-by: Mikulas Patocka Signed-off-by: Linus Torvalds --- fs/hpfs/buffer.c | 39 +++++++++++++++++++++++++++++++++------ fs/hpfs/file.c | 9 +++++++-- fs/hpfs/hpfs_fn.h | 7 +++++++ fs/hpfs/map.c | 26 ++++++++++++++++++++++++++ fs/hpfs/super.c | 15 +++------------ 5 files changed, 76 insertions(+), 20 deletions(-) diff --git a/fs/hpfs/buffer.c b/fs/hpfs/buffer.c index 8057fe4e65749..f626114449e4a 100644 --- a/fs/hpfs/buffer.c +++ b/fs/hpfs/buffer.c @@ -10,6 +10,30 @@ #include #include "hpfs_fn.h" +secno hpfs_search_hotfix_map(struct super_block *s, secno sec) +{ + unsigned i; + struct hpfs_sb_info *sbi = hpfs_sb(s); + for (i = 0; unlikely(i < sbi->n_hotfixes); i++) { + if (sbi->hotfix_from[i] == sec) { + return sbi->hotfix_to[i]; + } + } + return sec; +} + +unsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n) +{ + unsigned i; + struct hpfs_sb_info *sbi = hpfs_sb(s); + for (i = 0; unlikely(i < sbi->n_hotfixes); i++) { + if (sbi->hotfix_from[i] >= sec && sbi->hotfix_from[i] < sec + n) { + n = sbi->hotfix_from[i] - sec; + } + } + return n; +} + void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n) { struct buffer_head *bh; @@ -18,6 +42,9 @@ void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n) if (n <= 0 || unlikely(secno >= hpfs_sb(s)->sb_fs_size)) return; + if (unlikely(hpfs_search_hotfix_map_for_range(s, secno, n) != n)) + return; + bh = sb_find_get_block(s, secno); if (bh) { if (buffer_uptodate(bh)) { @@ -51,7 +78,7 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head cond_resched(); - *bhp = bh = sb_bread(s, secno); + *bhp = bh = sb_bread(s, hpfs_search_hotfix_map(s, secno)); if (bh != NULL) return bh->b_data; else { @@ -71,7 +98,7 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head cond_resched(); - if ((*bhp = bh = sb_getblk(s, secno)) != NULL) { + if ((*bhp = bh = sb_getblk(s, hpfs_search_hotfix_map(s, secno))) != NULL) { if (!buffer_uptodate(bh)) wait_on_buffer(bh); set_buffer_uptodate(bh); return bh->b_data; @@ -99,10 +126,10 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe hpfs_prefetch_sectors(s, secno, 4 + ahead); - if (!(qbh->bh[0] = sb_bread(s, secno + 0))) goto bail0; - if (!(qbh->bh[1] = sb_bread(s, secno + 1))) goto bail1; - if (!(qbh->bh[2] = sb_bread(s, secno + 2))) goto bail2; - if (!(qbh->bh[3] = sb_bread(s, secno + 3))) goto bail3; + if (!hpfs_map_sector(s, secno + 0, &qbh->bh[0], 0)) goto bail0; + if (!hpfs_map_sector(s, secno + 1, &qbh->bh[1], 0)) goto bail1; + if (!hpfs_map_sector(s, secno + 2, &qbh->bh[2], 0)) goto bail2; + if (!hpfs_map_sector(s, secno + 3, &qbh->bh[3], 0)) goto bail3; if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index 7ca28d604bf76..d3bcdd9757005 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -83,6 +83,11 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he if (s) { if (bh_result->b_size >> 9 < n_secs) n_secs = bh_result->b_size >> 9; + n_secs = hpfs_search_hotfix_map_for_range(inode->i_sb, s, n_secs); + if (unlikely(!n_secs)) { + s = hpfs_search_hotfix_map(inode->i_sb, s); + n_secs = 1; + } map_bh(bh_result, inode->i_sb, s); bh_result->b_size = n_secs << 9; goto ret_0; @@ -101,7 +106,7 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he inode->i_blocks++; hpfs_i(inode)->mmu_private += 512; set_buffer_new(bh_result); - map_bh(bh_result, inode->i_sb, s); + map_bh(bh_result, inode->i_sb, hpfs_search_hotfix_map(inode->i_sb, s)); ret_0: r = 0; ret_r: @@ -181,7 +186,7 @@ static int hpfs_write_end(struct file *file, struct address_space *mapping, static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) { - return generic_block_bmap(mapping,block,hpfs_get_block); + return generic_block_bmap(mapping, block, hpfs_get_block); } const struct address_space_operations hpfs_aops = { diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index c4867b5116ddf..975654a63c13d 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -88,6 +88,10 @@ struct hpfs_sb_info { unsigned sb_max_fwd_alloc; /* max forwad allocation */ int sb_timeshift; struct rcu_head rcu; + + unsigned n_hotfixes; + secno hotfix_from[256]; + secno hotfix_to[256]; }; /* Four 512-byte buffers and the 2k block obtained by concatenating them */ @@ -217,6 +221,8 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno); /* buffer.c */ +secno hpfs_search_hotfix_map(struct super_block *s, secno sec); +unsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n); void hpfs_prefetch_sectors(struct super_block *, unsigned, int); void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int); void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **); @@ -285,6 +291,7 @@ __le32 *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head void hpfs_prefetch_bitmap(struct super_block *, unsigned); unsigned char *hpfs_load_code_page(struct super_block *, secno); __le32 *hpfs_load_bitmap_directory(struct super_block *, secno bmp); +void hpfs_load_hotfix_map(struct super_block *s, struct hpfs_spare_block *spareblock); struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **); struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **); struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *); diff --git a/fs/hpfs/map.c b/fs/hpfs/map.c index 442770edcdc70..a69bbc1e87f86 100644 --- a/fs/hpfs/map.c +++ b/fs/hpfs/map.c @@ -130,6 +130,32 @@ __le32 *hpfs_load_bitmap_directory(struct super_block *s, secno bmp) return b; } +void hpfs_load_hotfix_map(struct super_block *s, struct hpfs_spare_block *spareblock) +{ + struct quad_buffer_head qbh; + u32 *directory; + u32 n_hotfixes, n_used_hotfixes; + unsigned i; + + n_hotfixes = le32_to_cpu(spareblock->n_spares); + n_used_hotfixes = le32_to_cpu(spareblock->n_spares_used); + + if (n_hotfixes > 256 || n_used_hotfixes > n_hotfixes) { + hpfs_error(s, "invalid number of hotfixes: %u, used: %u", n_hotfixes, n_used_hotfixes); + return; + } + if (!(directory = hpfs_map_4sectors(s, le32_to_cpu(spareblock->hotfix_map), &qbh, 0))) { + hpfs_error(s, "can't load hotfix map"); + return; + } + for (i = 0; i < n_used_hotfixes; i++) { + hpfs_sb(s)->hotfix_from[i] = le32_to_cpu(directory[i]); + hpfs_sb(s)->hotfix_to[i] = le32_to_cpu(directory[n_hotfixes + i]); + } + hpfs_sb(s)->n_hotfixes = n_used_hotfixes; + hpfs_brelse4(&qbh); +} + /* * Load fnode to memory */ diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 68a9bed056284..a561591896bd3 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -628,6 +628,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) goto bail4; } + if (spareblock->n_spares_used) + hpfs_load_hotfix_map(s, spareblock); + /* Load bitmap directory */ if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps)))) goto bail4; @@ -647,18 +650,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) mark_buffer_dirty(bh2); } - if (spareblock->hotfixes_used || spareblock->n_spares_used) { - if (errs >= 2) { - pr_err("Hotfixes not supported here, try chkdsk\n"); - mark_dirty(s, 0); - goto bail4; - } - hpfs_error(s, "hotfixes not supported here, try chkdsk"); - if (errs == 0) - pr_err("Proceeding, but your filesystem will be probably corrupted by this driver...\n"); - else - pr_err("This driver may read bad files or crash when operating on disk with hotfixes.\n"); - } if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) { if (errs >= 2) { pr_err("Spare dnodes used, try chkdsk\n"); -- GitLab From f49a26e7718dd30b49e3541e3e25aecf5e7294e2 Mon Sep 17 00:00:00 2001 From: Mikulas Patocka Date: Wed, 2 Sep 2015 22:51:53 +0200 Subject: [PATCH 6260/7006] hpfs: update ctime and mtime on directory modification Update ctime and mtime when a directory is modified. (though OS/2 doesn't update them anyway) Signed-off-by: Mikulas Patocka Cc: stable@kernel.org # v3.3+ Signed-off-by: Linus Torvalds --- fs/hpfs/namei.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index a0872f239f04f..9e92c9c2d3195 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -8,6 +8,17 @@ #include #include "hpfs_fn.h" +static void hpfs_update_directory_times(struct inode *dir) +{ + time_t t = get_seconds(); + if (t == dir->i_mtime.tv_sec && + t == dir->i_ctime.tv_sec) + return; + dir->i_mtime.tv_sec = dir->i_ctime.tv_sec = t; + dir->i_mtime.tv_nsec = dir->i_ctime.tv_nsec = 0; + hpfs_write_inode_nolock(dir); +} + static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) { const unsigned char *name = dentry->d_name.name; @@ -99,6 +110,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) result->i_mode = mode | S_IFDIR; hpfs_write_inode_nolock(result); } + hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; @@ -187,6 +199,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, b result->i_mode = mode | S_IFREG; hpfs_write_inode_nolock(result); } + hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; @@ -262,6 +275,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, de insert_inode_hash(result); hpfs_write_inode_nolock(result); + hpfs_update_directory_times(dir); d_instantiate(dentry, result); brelse(bh); hpfs_unlock(dir->i_sb); @@ -340,6 +354,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy insert_inode_hash(result); hpfs_write_inode_nolock(result); + hpfs_update_directory_times(dir); d_instantiate(dentry, result); hpfs_unlock(dir->i_sb); return 0; @@ -423,6 +438,8 @@ again: out1: hpfs_brelse4(&qbh); out: + if (!err) + hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); return err; } @@ -477,6 +494,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) out1: hpfs_brelse4(&qbh); out: + if (!err) + hpfs_update_directory_times(dir); hpfs_unlock(dir->i_sb); return err; } @@ -595,7 +614,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, goto end1; } - end: +end: hpfs_i(i)->i_parent_dir = new_dir->i_ino; if (S_ISDIR(i->i_mode)) { inc_nlink(new_dir); @@ -610,6 +629,10 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, brelse(bh); } end1: + if (!err) { + hpfs_update_directory_times(old_dir); + hpfs_update_directory_times(new_dir); + } hpfs_unlock(i->i_sb); return err; } -- GitLab From 6fd8edabc2b03203e6bc44e77d1dfff415e706cc Mon Sep 17 00:00:00 2001 From: Jubin John Date: Wed, 2 Sep 2015 10:43:24 -0400 Subject: [PATCH 6261/7006] IB/hfi1: Add CSRs for CONFIG_SDMA_VERBOSITY 3 CSRs needed by the CONFIG_SDMA_VERBOSITY code were removed during the CSR clean up. Adding these CSRs back to resolve 0-day build failure: https://lists.01.org/pipermail/kbuild-all/2015-August/011919.html Reviewed-by: Mike Marciniszyn Signed-off-by: Jubin John Signed-off-by: Doug Ledford --- drivers/staging/rdma/hfi1/chip_registers.h | 3 +++ drivers/staging/rdma/hfi1/sdma.c | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/rdma/hfi1/chip_registers.h b/drivers/staging/rdma/hfi1/chip_registers.h index 6521030018d85..bf45de29d8bd7 100644 --- a/drivers/staging/rdma/hfi1/chip_registers.h +++ b/drivers/staging/rdma/hfi1/chip_registers.h @@ -1285,5 +1285,8 @@ #define PCIE_CFG_REG_PL106_GEN3_EQ_PSET_REQ_VEC_SHIFT 8 #define PCIE_CFG_REG_PL106_GEN3_EQ_EVAL2MS_DISABLE_SMASK 0x20ull #define PCIE_CFG_REG_PL106_GEN3_EQ_PHASE23_EXIT_MODE_SMASK 0x10ull +#define CCE_INT_BLOCKED (CCE + 0x000000110C00) +#define SEND_DMA_IDLE_CNT (TXE + 0x000000200040) +#define SEND_DMA_DESC_FETCHED_CNT (TXE + 0x000000200058) #endif /* DEF_CHIP_REG */ diff --git a/drivers/staging/rdma/hfi1/sdma.c b/drivers/staging/rdma/hfi1/sdma.c index 37bd767d6bc01..a8c903caecce0 100644 --- a/drivers/staging/rdma/hfi1/sdma.c +++ b/drivers/staging/rdma/hfi1/sdma.c @@ -1769,7 +1769,7 @@ void sdma_dumpstate(struct sdma_engine *sde) sdma_dumpstate_helper(SD(ENG_ERR_MASK)); for (i = 0; i < CCE_NUM_INT_CSRS; ++i) { - sdma_dumpstate_helper2(CCE_INT_STATUS)); + sdma_dumpstate_helper2(CCE_INT_STATUS); sdma_dumpstate_helper2(CCE_INT_MASK); sdma_dumpstate_helper2(CCE_INT_BLOCKED); } @@ -1777,7 +1777,7 @@ void sdma_dumpstate(struct sdma_engine *sde) sdma_dumpstate_helper(SD(TAIL)); sdma_dumpstate_helper(SD(HEAD)); sdma_dumpstate_helper(SD(PRIORITY_THLD)); - sdma_dumpstate_helper(SD(IDLE_CNT); + sdma_dumpstate_helper(SD(IDLE_CNT)); sdma_dumpstate_helper(SD(RELOAD_CNT)); sdma_dumpstate_helper(SD(DESC_CNT)); sdma_dumpstate_helper(SD(DESC_FETCHED_CNT)); -- GitLab From 6f876ce4b53f7c748e07cedab661aa4bcc8a09d2 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Wed, 2 Sep 2015 18:46:21 -0400 Subject: [PATCH 6262/7006] IB/hfi1: Add PSM2 user space header to header_install When the hfi1 driver was added a user space header file (hfi1_user.h) was added to be shared between PSM2 and the driver. However, the file was not added to the header install. Add it now. Fixes: d4ab347005fb ("IB/core: Add core header changes needed for OPA") Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- include/uapi/rdma/Kbuild | 1 + include/uapi/rdma/hfi/Kbuild | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 include/uapi/rdma/hfi/Kbuild diff --git a/include/uapi/rdma/Kbuild b/include/uapi/rdma/Kbuild index 687ae332200f9..231901b08f6ce 100644 --- a/include/uapi/rdma/Kbuild +++ b/include/uapi/rdma/Kbuild @@ -5,3 +5,4 @@ header-y += ib_user_sa.h header-y += ib_user_verbs.h header-y += rdma_netlink.h header-y += rdma_user_cm.h +header-y += hfi/ diff --git a/include/uapi/rdma/hfi/Kbuild b/include/uapi/rdma/hfi/Kbuild new file mode 100644 index 0000000000000..ef23c294fc71f --- /dev/null +++ b/include/uapi/rdma/hfi/Kbuild @@ -0,0 +1,2 @@ +# UAPI Header export list +header-y += hfi1_user.h -- GitLab From ce755c9b01e09ee4907cf79bd0f57fa5cf65c4c3 Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Wed, 2 Sep 2015 18:45:54 -0400 Subject: [PATCH 6263/7006] IB/core: Remove unnecessary defines from ib_mad.h Remove the unused IB_NOTICE_REPRESS_* defines. When the hfi1 driver was added these definitions were moved from the qib driver to ib_mad.h. They should have been removed instead. Fixes: d4ab347005fb ("IB/core: Add core header changes needed for OPA") Signed-off-by: Ira Weiny Reviewed-by: Hal Rosenstock Signed-off-by: Doug Ledford --- include/rdma/ib_mad.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index c206205bbf986..7f2cf855a0b68 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -156,18 +156,6 @@ #define IB_NOTICE_TRAP_BAD_PKEY cpu_to_be16(257) #define IB_NOTICE_TRAP_BAD_QKEY cpu_to_be16(258) -/* - * Repress trap/notice flags - */ -#define IB_NOTICE_REPRESS_LLI_THRESH (1 << 0) -#define IB_NOTICE_REPRESS_EBO_THRESH (1 << 1) -#define IB_NOTICE_REPRESS_FLOW_UPDATE (1 << 2) -#define IB_NOTICE_REPRESS_CAP_MASK_CHG (1 << 3) -#define IB_NOTICE_REPRESS_SYS_GUID_CHG (1 << 4) -#define IB_NOTICE_REPRESS_BAD_MKEY (1 << 5) -#define IB_NOTICE_REPRESS_BAD_PKEY (1 << 6) -#define IB_NOTICE_REPRESS_BAD_QKEY (1 << 7) - /* * Generic trap/notice other local changes flags (trap 144). */ -- GitLab From 0629cb06cdf8f1a403ce71bce5b83380ae898e1a Mon Sep 17 00:00:00 2001 From: Ira Weiny Date: Thu, 3 Sep 2015 14:16:30 -0400 Subject: [PATCH 6264/7006] IB/core: Move SM class defines from ib_mad.h to ib_smi.h When the hfi1 driver was added these definitions were moved from the qib driver to ib_mad.h to be used by both qib and hfi1. They should have been moved to ib_smi.h instead. Fixes: d4ab347005fb ("IB/core: Add core header changes needed for OPA") Reviewed-by: Hal Rosenstock Signed-off-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_ruc.c | 1 + include/rdma/ib_mad.h | 45 --------------------------- include/rdma/ib_smi.h | 47 +++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index f42bd0f47577a..22e356ca8058a 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -32,6 +32,7 @@ */ #include +#include #include "qib.h" #include "qib_mad.h" diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index 7f2cf855a0b68..188df91d58514 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -144,31 +144,6 @@ #define IB_NOTICE_PROD_ROUTER cpu_to_be16(3) #define IB_NOTICE_PROD_CLASS_MGR cpu_to_be16(4) -/* - * Generic trap/notice numbers - */ -#define IB_NOTICE_TRAP_LLI_THRESH cpu_to_be16(129) -#define IB_NOTICE_TRAP_EBO_THRESH cpu_to_be16(130) -#define IB_NOTICE_TRAP_FLOW_UPDATE cpu_to_be16(131) -#define IB_NOTICE_TRAP_CAP_MASK_CHG cpu_to_be16(144) -#define IB_NOTICE_TRAP_SYS_GUID_CHG cpu_to_be16(145) -#define IB_NOTICE_TRAP_BAD_MKEY cpu_to_be16(256) -#define IB_NOTICE_TRAP_BAD_PKEY cpu_to_be16(257) -#define IB_NOTICE_TRAP_BAD_QKEY cpu_to_be16(258) - -/* - * Generic trap/notice other local changes flags (trap 144). - */ -#define IB_NOTICE_TRAP_LSE_CHG 0x04 /* Link Speed Enable changed */ -#define IB_NOTICE_TRAP_LWE_CHG 0x02 /* Link Width Enable changed */ -#define IB_NOTICE_TRAP_NODE_DESC_CHG 0x01 - -/* - * Generic trap/notice M_Key volation flags in dr_trunc_hop (trap 256). - */ -#define IB_NOTICE_TRAP_DR_NOTICE 0x80 -#define IB_NOTICE_TRAP_DR_TRUNC 0x40 - enum { IB_MGMT_MAD_HDR = 24, IB_MGMT_MAD_DATA = 232, @@ -282,21 +257,6 @@ struct ib_class_port_info { __be32 trap_qkey; }; -struct ib_node_info { - u8 base_version; - u8 class_version; - u8 node_type; - u8 num_ports; - __be64 sys_guid; - __be64 node_guid; - __be64 port_guid; - __be16 partition_cap; - __be16 device_id; - __be32 revision; - u8 local_port_num; - u8 vendor_id[3]; -} __packed; - struct ib_mad_notice_attr { u8 generic_type; u8 prod_type_msb; @@ -361,11 +321,6 @@ struct ib_mad_notice_attr { } details; }; -struct ib_vl_weight_elem { - u8 vl; /* VL is low 5 bits, upper 3 bits reserved */ - u8 weight; -}; - /** * ib_mad_send_buf - MAD data buffer and work request for sends. * @next: A pointer used to chain together MADs for posting. diff --git a/include/rdma/ib_smi.h b/include/rdma/ib_smi.h index 98b9086d769af..b439e988408e6 100644 --- a/include/rdma/ib_smi.h +++ b/include/rdma/ib_smi.h @@ -119,10 +119,57 @@ struct ib_port_info { u8 link_roundtrip_latency[3]; }; +struct ib_node_info { + u8 base_version; + u8 class_version; + u8 node_type; + u8 num_ports; + __be64 sys_guid; + __be64 node_guid; + __be64 port_guid; + __be16 partition_cap; + __be16 device_id; + __be32 revision; + u8 local_port_num; + u8 vendor_id[3]; +} __packed; + +struct ib_vl_weight_elem { + u8 vl; /* IB: VL is low 4 bits, upper 4 bits reserved */ + /* OPA: VL is low 5 bits, upper 3 bits reserved */ + u8 weight; +}; + static inline u8 ib_get_smp_direction(struct ib_smp *smp) { return ((smp->status & IB_SMP_DIRECTION) == IB_SMP_DIRECTION); } +/* + * SM Trap/Notice numbers + */ +#define IB_NOTICE_TRAP_LLI_THRESH cpu_to_be16(129) +#define IB_NOTICE_TRAP_EBO_THRESH cpu_to_be16(130) +#define IB_NOTICE_TRAP_FLOW_UPDATE cpu_to_be16(131) +#define IB_NOTICE_TRAP_CAP_MASK_CHG cpu_to_be16(144) +#define IB_NOTICE_TRAP_SYS_GUID_CHG cpu_to_be16(145) +#define IB_NOTICE_TRAP_BAD_MKEY cpu_to_be16(256) +#define IB_NOTICE_TRAP_BAD_PKEY cpu_to_be16(257) +#define IB_NOTICE_TRAP_BAD_QKEY cpu_to_be16(258) + +/* + * Other local changes flags (trap 144). + */ +#define IB_NOTICE_TRAP_LSE_CHG 0x04 /* Link Speed Enable changed */ +#define IB_NOTICE_TRAP_LWE_CHG 0x02 /* Link Width Enable changed */ +#define IB_NOTICE_TRAP_NODE_DESC_CHG 0x01 + +/* + * M_Key volation flags in dr_trunc_hop (trap 256). + */ +#define IB_NOTICE_TRAP_DR_NOTICE 0x80 +#define IB_NOTICE_TRAP_DR_TRUNC 0x40 + + #endif /* IB_SMI_H */ -- GitLab From 7fbc67df2cd6d0b72fd5d6d3acaa79ab6f5b0224 Mon Sep 17 00:00:00 2001 From: Sagi Grimberg Date: Mon, 24 Aug 2015 19:04:51 +0300 Subject: [PATCH 6265/7006] IB/srp: Fix possible protection fault srp_destroy_qp is designed to indicate we are safe to continue with freeing the channel resources by modifying the qp error state, posting a dummy wr on the queue-pair and waiting for it to flush. This also holds for the channel registration pool as we are unmapping the memory region when handling a scsi response. Destroying the channel registration pool before we make sure we processed all the inflight IO might introduce a use-after-free of the registration pool. This use-after-free is demonstrated in the stack trace below where srp is trying to unmap a used FMR after the fmr_pool was already destroyed. general protection fault: 0000 [#1] SMP RIP: 0010:[] [] _raw_spin_lock_irqsave+0x1b/0x50 Call Trace: [] ib_fmr_pool_unmap+0x1a/0xb0 [ib_core] [] srp_unmap_data.isra.28+0x17d/0x250 [ib_srp] [] srp_free_req+0x2b/0x60 [ib_srp] [] srp_recv_completion+0x174/0x580 [ib_srp] [] mlx4_eq_int+0x4de/0xe50 [mlx4_core] [] mlx4_msi_x_interrupt+0x10/0x20 [mlx4_core] [] handle_irq_event_percpu+0x35/0x1b0 [] handle_irq_event+0x32/0x50 [] handle_edge_irq+0x6f/0x120 [] handle_irq+0x1a/0x30 [] do_IRQ+0x45/0xb0 [] common_interrupt+0x6d/0x6d [] cpuidle_enter_state+0x4f/0xc0 [] cpuidle_idle_call+0xcc/0x210 [] arch_cpu_idle+0xa/0x30 [] cpu_startup_entry+0xe1/0x270 [] start_secondary+0x21a/0x2c0 Reported-by: Eliott Kespi Signed-off-by: Sagi Grimberg Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index ca98d3b472815..b481490ad2575 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -554,9 +554,6 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) "FR pool allocation failed (%d)\n", ret); goto err_qp; } - if (ch->fr_pool) - srp_destroy_fr_pool(ch->fr_pool); - ch->fr_pool = fr_pool; } else if (dev->use_fmr) { fmr_pool = srp_alloc_fmr_pool(target); if (IS_ERR(fmr_pool)) { @@ -565,9 +562,6 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) "FMR pool allocation failed (%d)\n", ret); goto err_qp; } - if (ch->fmr_pool) - ib_destroy_fmr_pool(ch->fmr_pool); - ch->fmr_pool = fmr_pool; } if (ch->qp) @@ -581,6 +575,16 @@ static int srp_create_ch_ib(struct srp_rdma_ch *ch) ch->recv_cq = recv_cq; ch->send_cq = send_cq; + if (dev->use_fast_reg) { + if (ch->fr_pool) + srp_destroy_fr_pool(ch->fr_pool); + ch->fr_pool = fr_pool; + } else if (dev->use_fmr) { + if (ch->fmr_pool) + ib_destroy_fmr_pool(ch->fmr_pool); + ch->fmr_pool = fmr_pool; + } + kfree(init_attr); return 0; -- GitLab From 92e847212676bb3c5f9f7e317907367dbb8c504b Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 3 Sep 2015 14:58:55 -0500 Subject: [PATCH 6266/7006] ipmi: Add device tree bindings information Signed-off-by: Corey Minyard --- Documentation/devicetree/bindings/ipmi.txt | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/ipmi.txt diff --git a/Documentation/devicetree/bindings/ipmi.txt b/Documentation/devicetree/bindings/ipmi.txt new file mode 100644 index 0000000000000..d5f1a877ed3ec --- /dev/null +++ b/Documentation/devicetree/bindings/ipmi.txt @@ -0,0 +1,25 @@ +IPMI device + +Required properties: +- compatible: should be one of ipmi-kcs, ipmi-smic, or ipmi-bt +- device_type: should be ipmi +- reg: Address and length of the register set for the device + +Optional properties: +- interrupts: The interrupt for the device. Without this the interface + is polled. +- reg-size - The size of the register. Defaults to 1 +- reg-spacing - The number of bytes between register starts. Defaults to 1 +- reg-shift - The amount to shift the registers to the right to get the data + into bit zero. + +Example: + +smic@fff3a000 { + compatible = "ipmi-smic"; + device_type = "ipmi"; + reg = <0xfff3a000 0x1000>; + interrupts = <0 24 4>; + reg-size = <4>; + reg-spacing = <4>; +}; -- GitLab From 0fbcf4af7c8362d4691f9388efa57d0b14b34225 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 9 Jun 2015 16:51:46 -0500 Subject: [PATCH 6267/7006] ipmi: Convert the IPMI SI ACPI handling to a platform device The IPMI SI driver was using direct PNP, but that was not really ideal because the IPMI device is a platform device. There was some special handling in the acpi_pnp.c code for making this work, but that was breaking ACPI handling for the IPMI SSIF driver. So without this patch there were significant issues getting the SSIF driver to work with ACPI. So use a platform device for ACPI detection and remove the entry from acpi_pnp.c. Signed-off-by: Corey Minyard --- drivers/acpi/acpi_pnp.c | 2 - drivers/char/ipmi/ipmi_si_intf.c | 320 +++++++++++++++---------------- 2 files changed, 157 insertions(+), 165 deletions(-) diff --git a/drivers/acpi/acpi_pnp.c b/drivers/acpi/acpi_pnp.c index fb765524cc3d5..c58940b231d69 100644 --- a/drivers/acpi/acpi_pnp.c +++ b/drivers/acpi/acpi_pnp.c @@ -19,8 +19,6 @@ static const struct acpi_device_id acpi_pnp_device_ids[] = { {"PNP0600"}, /* Generic ESDI/IDE/ATA compatible hard disk controller */ /* floppy */ {"PNP0700"}, - /* ipmi_si */ - {"IPI0001"}, /* tpm_inf_pnp */ {"IFX0101"}, /* Infineon TPMs */ {"IFX0102"}, /* Infineon TPMs */ diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 8a45e92ff60c7..6443e762b4265 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -64,7 +64,6 @@ #include #include #include -#include #include #include #include @@ -309,9 +308,6 @@ static int num_force_kipmid; #ifdef CONFIG_PCI static bool pci_registered; #endif -#ifdef CONFIG_ACPI -static bool pnp_registered; -#endif #ifdef CONFIG_PARISC static bool parisc_registered; #endif @@ -2233,134 +2229,6 @@ static void spmi_find_bmc(void) try_init_spmi(spmi); } } - -static int ipmi_pnp_probe(struct pnp_dev *dev, - const struct pnp_device_id *dev_id) -{ - struct acpi_device *acpi_dev; - struct smi_info *info; - struct resource *res, *res_second; - acpi_handle handle; - acpi_status status; - unsigned long long tmp; - int rv = -EINVAL; - - acpi_dev = pnp_acpi_device(dev); - if (!acpi_dev) - return -ENODEV; - - info = smi_info_alloc(); - if (!info) - return -ENOMEM; - - info->addr_source = SI_ACPI; - printk(KERN_INFO PFX "probing via ACPI\n"); - - handle = acpi_dev->handle; - info->addr_info.acpi_info.acpi_handle = handle; - - /* _IFT tells us the interface type: KCS, BT, etc */ - status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); - goto err_free; - } - - switch (tmp) { - case 1: - info->si_type = SI_KCS; - break; - case 2: - info->si_type = SI_SMIC; - break; - case 3: - info->si_type = SI_BT; - break; - case 4: /* SSIF, just ignore */ - rv = -ENODEV; - goto err_free; - default: - dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); - goto err_free; - } - - res = pnp_get_resource(dev, IORESOURCE_IO, 0); - if (res) { - info->io_setup = port_setup; - info->io.addr_type = IPMI_IO_ADDR_SPACE; - } else { - res = pnp_get_resource(dev, IORESOURCE_MEM, 0); - if (res) { - info->io_setup = mem_setup; - info->io.addr_type = IPMI_MEM_ADDR_SPACE; - } - } - if (!res) { - dev_err(&dev->dev, "no I/O or memory address\n"); - goto err_free; - } - info->io.addr_data = res->start; - - info->io.regspacing = DEFAULT_REGSPACING; - res_second = pnp_get_resource(dev, - (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? - IORESOURCE_IO : IORESOURCE_MEM, - 1); - if (res_second) { - if (res_second->start > info->io.addr_data) - info->io.regspacing = res_second->start - info->io.addr_data; - } - info->io.regsize = DEFAULT_REGSPACING; - info->io.regshift = 0; - - /* If _GPE exists, use it; otherwise use standard interrupts */ - status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); - if (ACPI_SUCCESS(status)) { - info->irq = tmp; - info->irq_setup = acpi_gpe_irq_setup; - } else if (pnp_irq_valid(dev, 0)) { - info->irq = pnp_irq(dev, 0); - info->irq_setup = std_irq_setup; - } - - info->dev = &dev->dev; - pnp_set_drvdata(dev, info); - - dev_info(info->dev, "%pR regsize %d spacing %d irq %d\n", - res, info->io.regsize, info->io.regspacing, - info->irq); - - rv = add_smi(info); - if (rv) - kfree(info); - - return rv; - -err_free: - kfree(info); - return rv; -} - -static void ipmi_pnp_remove(struct pnp_dev *dev) -{ - struct smi_info *info = pnp_get_drvdata(dev); - - cleanup_one_si(info); -} - -static const struct pnp_device_id pnp_dev_table[] = { - {"IPI0001", 0}, - {"", 0}, -}; - -static struct pnp_driver ipmi_pnp_driver = { - .name = DEVICE_NAME, - .probe = ipmi_pnp_probe, - .remove = ipmi_pnp_remove, - .id_table = pnp_dev_table, -}; - -MODULE_DEVICE_TABLE(pnp, pnp_dev_table); #endif #ifdef CONFIG_DMI @@ -2669,10 +2537,19 @@ static struct pci_driver ipmi_pci_driver = { }; #endif /* CONFIG_PCI */ -static const struct of_device_id ipmi_match[]; -static int ipmi_probe(struct platform_device *dev) -{ #ifdef CONFIG_OF +static const struct of_device_id of_ipmi_match[] = { + { .type = "ipmi", .compatible = "ipmi-kcs", + .data = (void *)(unsigned long) SI_KCS }, + { .type = "ipmi", .compatible = "ipmi-smic", + .data = (void *)(unsigned long) SI_SMIC }, + { .type = "ipmi", .compatible = "ipmi-bt", + .data = (void *)(unsigned long) SI_BT }, + {}, +}; + +static int of_ipmi_probe(struct platform_device *dev) +{ const struct of_device_id *match; struct smi_info *info; struct resource resource; @@ -2683,9 +2560,9 @@ static int ipmi_probe(struct platform_device *dev) dev_info(&dev->dev, "probing via device tree\n"); - match = of_match_device(ipmi_match, &dev->dev); + match = of_match_device(of_ipmi_match, &dev->dev); if (!match) - return -EINVAL; + return -ENODEV; if (!of_device_is_available(np)) return -EINVAL; @@ -2754,33 +2631,161 @@ static int ipmi_probe(struct platform_device *dev) kfree(info); return ret; } -#endif return 0; } +#else +#define of_ipmi_match NULL +static int of_ipmi_probe(struct platform_device *dev) +{ + return -ENODEV; +} +#endif -static int ipmi_remove(struct platform_device *dev) +#ifdef CONFIG_ACPI +static int acpi_ipmi_probe(struct platform_device *dev) { -#ifdef CONFIG_OF - cleanup_one_si(dev_get_drvdata(&dev->dev)); + struct smi_info *info; + struct resource *res, *res_second; + acpi_handle handle; + acpi_status status; + unsigned long long tmp; + int rv = -EINVAL; + + handle = ACPI_HANDLE(&dev->dev); + if (!handle) + return -ENODEV; + + info = smi_info_alloc(); + if (!info) + return -ENOMEM; + + info->addr_source = SI_ACPI; + dev_info(&dev->dev, PFX "probing via ACPI\n"); + + info->addr_info.acpi_info.acpi_handle = handle; + + /* _IFT tells us the interface type: KCS, BT, etc */ + status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dev_err(&dev->dev, "Could not find ACPI IPMI interface type\n"); + goto err_free; + } + + switch (tmp) { + case 1: + info->si_type = SI_KCS; + break; + case 2: + info->si_type = SI_SMIC; + break; + case 3: + info->si_type = SI_BT; + break; + case 4: /* SSIF, just ignore */ + rv = -ENODEV; + goto err_free; + default: + dev_info(&dev->dev, "unknown IPMI type %lld\n", tmp); + goto err_free; + } + + res = platform_get_resource(dev, IORESOURCE_IO, 0); + if (res) { + info->io_setup = port_setup; + info->io.addr_type = IPMI_IO_ADDR_SPACE; + } else { + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (res) { + info->io_setup = mem_setup; + info->io.addr_type = IPMI_MEM_ADDR_SPACE; + } + } + if (!res) { + dev_err(&dev->dev, "no I/O or memory address\n"); + goto err_free; + } + info->io.addr_data = res->start; + + info->io.regspacing = DEFAULT_REGSPACING; + res_second = platform_get_resource(dev, + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? + IORESOURCE_IO : IORESOURCE_MEM, + 1); + if (res_second) { + if (res_second->start > info->io.addr_data) + info->io.regspacing = + res_second->start - info->io.addr_data; + } + info->io.regsize = DEFAULT_REGSPACING; + info->io.regshift = 0; + + /* If _GPE exists, use it; otherwise use standard interrupts */ + status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); + if (ACPI_SUCCESS(status)) { + info->irq = tmp; + info->irq_setup = acpi_gpe_irq_setup; + } else { + int irq = platform_get_irq(dev, 0); + + if (irq > 0) { + info->irq = irq; + info->irq_setup = std_irq_setup; + } + } + + info->dev = &dev->dev; + platform_set_drvdata(dev, info); + + dev_info(info->dev, "%pR regsize %d spacing %d irq %d\n", + res, info->io.regsize, info->io.regspacing, + info->irq); + + rv = add_smi(info); + if (rv) + kfree(info); + + return rv; + +err_free: + kfree(info); + return rv; +} + +static struct acpi_device_id acpi_ipmi_match[] = { + { "IPI0001", 0 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, acpi_ipmi_match); +#else +static int acpi_ipmi_probe(struct platform_device *dev) +{ + return -ENODEV; +} #endif - return 0; + +static int ipmi_probe(struct platform_device *dev) +{ + if (of_ipmi_probe(dev) == 0) + return 0; + + return acpi_ipmi_probe(dev); } -static const struct of_device_id ipmi_match[] = +static int ipmi_remove(struct platform_device *dev) { - { .type = "ipmi", .compatible = "ipmi-kcs", - .data = (void *)(unsigned long) SI_KCS }, - { .type = "ipmi", .compatible = "ipmi-smic", - .data = (void *)(unsigned long) SI_SMIC }, - { .type = "ipmi", .compatible = "ipmi-bt", - .data = (void *)(unsigned long) SI_BT }, - {}, -}; + struct smi_info *info = dev_get_drvdata(&dev->dev); + + if (info) + cleanup_one_si(info); + + return 0; +} static struct platform_driver ipmi_driver = { .driver = { .name = DEVICE_NAME, - .of_match_table = ipmi_match, + .of_match_table = of_ipmi_match, + .acpi_match_table = ACPI_PTR(acpi_ipmi_match), }, .probe = ipmi_probe, .remove = ipmi_remove, @@ -3692,13 +3697,6 @@ static int init_ipmi_si(void) } #endif -#ifdef CONFIG_ACPI - if (si_tryacpi) { - pnp_register_driver(&ipmi_pnp_driver); - pnp_registered = true; - } -#endif - #ifdef CONFIG_DMI if (si_trydmi) dmi_find_bmc(); @@ -3850,10 +3848,6 @@ static void cleanup_ipmi_si(void) if (pci_registered) pci_unregister_driver(&ipmi_pci_driver); #endif -#ifdef CONFIG_ACPI - if (pnp_registered) - pnp_unregister_driver(&ipmi_pnp_driver); -#endif #ifdef CONFIG_PARISC if (parisc_registered) unregister_parisc_driver(&ipmi_parisc_driver); -- GitLab From cca85f19c260df495a487495479c67803b25fa8a Mon Sep 17 00:00:00 2001 From: Neelesh Gupta Date: Thu, 16 Jul 2015 16:46:54 +0530 Subject: [PATCH 6268/7006] ipmi/powernv: Fix potential invalid pointer dereference If the OPAL call to receive the ipmi message fails, then we free up the smi message and return. But, the driver still holds the reference to old smi message in the 'cur_msg' which can potentially be accessed later and freed again leading to kernel oops. To fix it up, The kernel driver should reset the 'cur_msg' and send reply to the user in addition to freeing the message. Signed-off-by: Neelesh Gupta Fixed a checkpatch warning dealing with an else after a return. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_powernv.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index 9b409c0f14f7c..62c0c634280f2 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -143,8 +143,15 @@ static int ipmi_powernv_recv(struct ipmi_smi_powernv *smi) pr_devel("%s: -> %d (size %lld)\n", __func__, rc, rc == 0 ? size : 0); if (rc) { + /* If came via the poll, and response was not yet ready */ + if (rc == OPAL_EMPTY) { + spin_unlock_irqrestore(&smi->msg_lock, flags); + return 0; + } + + smi->cur_msg = NULL; spin_unlock_irqrestore(&smi->msg_lock, flags); - ipmi_free_smi_msg(msg); + send_error_reply(smi, msg, IPMI_ERR_UNSPECIFIED); return 0; } -- GitLab From b2234ee9fc059c17e811a365383e3412a2f50bed Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 19 Feb 2015 11:29:24 -0600 Subject: [PATCH 6269/7006] ipmi: Add a comment in how messages are delivered from the lower layer To avoid confusion in the future. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index bf75f63617731..ef4a418f630ae 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -3959,6 +3959,10 @@ free_msg: if (!run_to_completion) spin_lock_irqsave(&intf->xmit_msgs_lock, flags); + /* + * We can get an asynchronous event or receive message in addition + * to commands we send. + */ if (msg == intf->curr_msg) intf->curr_msg = NULL; if (!run_to_completion) -- GitLab From 881c585ef79addb2440a7f8d59bda5640d0ff623 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Sat, 9 May 2015 15:32:28 -0400 Subject: [PATCH 6270/7006] impi:Remove unneeded setting of module owner to THIS_MODULE in the platform structure, powernv_ipmi_driver This removes the no longer required setting of the module owner for the plaform structure,powernv_ipmi_driver to THIS_MODULE as the driver core for ipmi drivers will directly find and set the module owner for this driver. Signed-off-by: Nicholas Krause Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_powernv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_powernv.c b/drivers/char/ipmi/ipmi_powernv.c index 62c0c634280f2..6e658aa114f19 100644 --- a/drivers/char/ipmi/ipmi_powernv.c +++ b/drivers/char/ipmi/ipmi_powernv.c @@ -307,7 +307,6 @@ static const struct of_device_id ipmi_powernv_match[] = { static struct platform_driver powernv_ipmi_driver = { .driver = { .name = "ipmi-powernv", - .owner = THIS_MODULE, .of_match_table = ipmi_powernv_match, }, .probe = ipmi_powernv_probe, -- GitLab From fedb25ea903d3520b6cff00c41740a892cf6bc0e Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Tue, 26 May 2015 00:54:57 +0530 Subject: [PATCH 6271/7006] char:ipmi - Change 1 to true for bool type variables during initialization. Signed-off-by: Shailendra Verma Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 8 ++++---- drivers/char/ipmi/ipmi_ssif.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 6443e762b4265..b1fdbf78da9bc 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1279,14 +1279,14 @@ static int smi_num; /* Used to sequence the SMIs */ #define DEFAULT_REGSIZE 1 #ifdef CONFIG_ACPI -static bool si_tryacpi = 1; +static bool si_tryacpi = true; #endif #ifdef CONFIG_DMI -static bool si_trydmi = 1; +static bool si_trydmi = true; #endif -static bool si_tryplatform = 1; +static bool si_tryplatform = true; #ifdef CONFIG_PCI -static bool si_trypci = 1; +static bool si_trypci = true; #endif static bool si_trydefaults = IS_ENABLED(CONFIG_IPMI_SI_PROBE_DEFAULTS); static char *si_type[SI_MAX_PARMS]; diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 207689c444a81..428a5faef74d3 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1154,11 +1154,11 @@ static int use_thread; module_param(use_thread, int, 0); MODULE_PARM_DESC(use_thread, "Use the thread interface."); -static bool ssif_tryacpi = 1; +static bool ssif_tryacpi = true; module_param_named(tryacpi, ssif_tryacpi, bool, 0); MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the default scan of the interfaces identified via ACPI"); -static bool ssif_trydmi = 1; +static bool ssif_trydmi = true; module_param_named(trydmi, ssif_trydmi, bool, 0); MODULE_PARM_DESC(trydmi, "Setting this to zero will disable the default scan of the interfaces identified via DMI (SMBIOS)"); -- GitLab From a7930899ca0082a33350b253c6ed34f67255f98e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 27 Jun 2015 18:12:14 +0200 Subject: [PATCH 6272/7006] ipmi: Delete an unnecessary check before the function call "cleanup_one_si" The cleanup_one_si() function tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index b1fdbf78da9bc..4387bd6de2cae 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2775,9 +2775,7 @@ static int ipmi_remove(struct platform_device *dev) { struct smi_info *info = dev_get_drvdata(&dev->dev); - if (info) - cleanup_one_si(info); - + cleanup_one_si(info); return 0; } -- GitLab From 5186cf9c74034a4a7856de9c8048493be34c457d Mon Sep 17 00:00:00 2001 From: Mathias Krause Date: Sat, 13 Jun 2015 14:19:33 +0200 Subject: [PATCH 6273/7006] ipmi: constify SSIF ACPI device ids Constify the ACPI device ID array, it doesn't need to be writable at runtime. Signed-off-by: Mathias Krause Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_ssif.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 428a5faef74d3..b043d8d458235 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1787,7 +1787,7 @@ skip_addr: } #ifdef CONFIG_ACPI -static struct acpi_device_id ssif_acpi_match[] = { +static const struct acpi_device_id ssif_acpi_match[] = { { "IPI0001", 0 }, { }, }; -- GitLab From 81d02b7f8c507f06299476a0e5b2aa677c5eaecb Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Sat, 13 Jun 2015 10:34:25 -0500 Subject: [PATCH 6274/7006] ipmi: Make some data const that was only read Several data structures were only used for reading, so make them const. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_bt_sm.c | 2 +- drivers/char/ipmi/ipmi_kcs_sm.c | 2 +- drivers/char/ipmi/ipmi_msghandler.c | 12 ++++---- drivers/char/ipmi/ipmi_si_intf.c | 47 +++++++++++++++-------------- drivers/char/ipmi/ipmi_si_sm.h | 10 +++--- drivers/char/ipmi/ipmi_smic_sm.c | 2 +- include/linux/ipmi_smi.h | 2 +- 7 files changed, 40 insertions(+), 37 deletions(-) diff --git a/drivers/char/ipmi/ipmi_bt_sm.c b/drivers/char/ipmi/ipmi_bt_sm.c index 61e71616689b7..feafdab734ae2 100644 --- a/drivers/char/ipmi/ipmi_bt_sm.c +++ b/drivers/char/ipmi/ipmi_bt_sm.c @@ -694,7 +694,7 @@ static int bt_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers bt_smi_handlers = { +const struct si_sm_handlers bt_smi_handlers = { .init_data = bt_init_data, .start_transaction = bt_start_transaction, .get_result = bt_get_result, diff --git a/drivers/char/ipmi/ipmi_kcs_sm.c b/drivers/char/ipmi/ipmi_kcs_sm.c index 8c25f596808a9..1da61af7f5767 100644 --- a/drivers/char/ipmi/ipmi_kcs_sm.c +++ b/drivers/char/ipmi/ipmi_kcs_sm.c @@ -540,7 +540,7 @@ static void kcs_cleanup(struct si_sm_data *kcs) { } -struct si_sm_handlers kcs_smi_handlers = { +const struct si_sm_handlers kcs_smi_handlers = { .init_data = init_kcs_data, .start_transaction = start_kcs_transaction, .get_result = get_kcs_result, diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index ef4a418f630ae..e9ea29c4ec604 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -342,7 +342,7 @@ struct ipmi_smi { * an umpreemptible region to use this. You must fetch the * value into a local variable and make sure it is not NULL. */ - struct ipmi_smi_handlers *handlers; + const struct ipmi_smi_handlers *handlers; void *send_info; #ifdef CONFIG_PROC_FS @@ -1015,7 +1015,7 @@ int ipmi_get_smi_info(int if_num, struct ipmi_smi_info *data) { int rv = 0; ipmi_smi_t intf; - struct ipmi_smi_handlers *handlers; + const struct ipmi_smi_handlers *handlers; mutex_lock(&ipmi_interfaces_mutex); list_for_each_entry_rcu(intf, &ipmi_interfaces, link) { @@ -1501,7 +1501,7 @@ static struct ipmi_smi_msg *smi_add_send_msg(ipmi_smi_t intf, } -static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers, +static void smi_send(ipmi_smi_t intf, const struct ipmi_smi_handlers *handlers, struct ipmi_smi_msg *smi_msg, int priority) { int run_to_completion = intf->run_to_completion; @@ -2747,7 +2747,7 @@ void ipmi_poll_interface(ipmi_user_t user) } EXPORT_SYMBOL(ipmi_poll_interface); -int ipmi_register_smi(struct ipmi_smi_handlers *handlers, +int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *si_dev, @@ -4019,7 +4019,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, unsigned int *waiting_msgs) { struct ipmi_recv_msg *msg; - struct ipmi_smi_handlers *handlers; + const struct ipmi_smi_handlers *handlers; if (intf->in_shutdown) return; @@ -4086,7 +4086,7 @@ static void check_msg_timeout(ipmi_smi_t intf, struct seq_table *ent, ipmi_inc_stat(intf, retransmitted_ipmb_commands); - smi_send(intf, intf->handlers, smi_msg, 0); + smi_send(intf, handlers, smi_msg, 0); } else ipmi_free_smi_msg(smi_msg); diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4387bd6de2cae..4a4a13dc98b3a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -163,7 +163,7 @@ struct smi_info { int intf_num; ipmi_smi_t intf; struct si_sm_data *si_sm; - struct si_sm_handlers *handlers; + const struct si_sm_handlers *handlers; enum si_type si_type; spinlock_t si_lock; struct ipmi_smi_msg *waiting_msg; @@ -1254,7 +1254,7 @@ static void set_maintenance_mode(void *send_info, bool enable) atomic_set(&smi_info->req_events, 0); } -static struct ipmi_smi_handlers handlers = { +static const struct ipmi_smi_handlers handlers = { .owner = THIS_MODULE, .start_processing = smi_start_processing, .get_smi_info = get_smi_info, @@ -1442,14 +1442,14 @@ static int std_irq_setup(struct smi_info *info) return rv; } -static unsigned char port_inb(struct si_sm_io *io, unsigned int offset) +static unsigned char port_inb(const struct si_sm_io *io, unsigned int offset) { unsigned int addr = io->addr_data; return inb(addr + (offset * io->regspacing)); } -static void port_outb(struct si_sm_io *io, unsigned int offset, +static void port_outb(const struct si_sm_io *io, unsigned int offset, unsigned char b) { unsigned int addr = io->addr_data; @@ -1457,14 +1457,14 @@ static void port_outb(struct si_sm_io *io, unsigned int offset, outb(b, addr + (offset * io->regspacing)); } -static unsigned char port_inw(struct si_sm_io *io, unsigned int offset) +static unsigned char port_inw(const struct si_sm_io *io, unsigned int offset) { unsigned int addr = io->addr_data; return (inw(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; } -static void port_outw(struct si_sm_io *io, unsigned int offset, +static void port_outw(const struct si_sm_io *io, unsigned int offset, unsigned char b) { unsigned int addr = io->addr_data; @@ -1472,14 +1472,14 @@ static void port_outw(struct si_sm_io *io, unsigned int offset, outw(b << io->regshift, addr + (offset * io->regspacing)); } -static unsigned char port_inl(struct si_sm_io *io, unsigned int offset) +static unsigned char port_inl(const struct si_sm_io *io, unsigned int offset) { unsigned int addr = io->addr_data; return (inl(addr + (offset * io->regspacing)) >> io->regshift) & 0xff; } -static void port_outl(struct si_sm_io *io, unsigned int offset, +static void port_outl(const struct si_sm_io *io, unsigned int offset, unsigned char b) { unsigned int addr = io->addr_data; @@ -1552,49 +1552,52 @@ static int port_setup(struct smi_info *info) return 0; } -static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inb(const struct si_sm_io *io, + unsigned int offset) { return readb((io->addr)+(offset * io->regspacing)); } -static void intf_mem_outb(struct si_sm_io *io, unsigned int offset, - unsigned char b) +static void intf_mem_outb(const struct si_sm_io *io, unsigned int offset, + unsigned char b) { writeb(b, (io->addr)+(offset * io->regspacing)); } -static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inw(const struct si_sm_io *io, + unsigned int offset) { return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; } -static void intf_mem_outw(struct si_sm_io *io, unsigned int offset, - unsigned char b) +static void intf_mem_outw(const struct si_sm_io *io, unsigned int offset, + unsigned char b) { writeb(b << io->regshift, (io->addr)+(offset * io->regspacing)); } -static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset) +static unsigned char intf_mem_inl(const struct si_sm_io *io, + unsigned int offset) { return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; } -static void intf_mem_outl(struct si_sm_io *io, unsigned int offset, - unsigned char b) +static void intf_mem_outl(const struct si_sm_io *io, unsigned int offset, + unsigned char b) { writel(b << io->regshift, (io->addr)+(offset * io->regspacing)); } #ifdef readq -static unsigned char mem_inq(struct si_sm_io *io, unsigned int offset) +static unsigned char mem_inq(const struct si_sm_io *io, unsigned int offset) { return (readq((io->addr)+(offset * io->regspacing)) >> io->regshift) & 0xff; } -static void mem_outq(struct si_sm_io *io, unsigned int offset, +static void mem_outq(const struct si_sm_io *io, unsigned int offset, unsigned char b) { writeq(b << io->regshift, (io->addr)+(offset * io->regspacing)); @@ -2522,7 +2525,7 @@ static void ipmi_pci_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -static struct pci_device_id ipmi_pci_devices[] = { +static const struct pci_device_id ipmi_pci_devices[] = { { PCI_DEVICE(PCI_HP_VENDOR_ID, PCI_MMC_DEVICE_ID) }, { PCI_DEVICE_CLASS(PCI_ERMC_CLASSCODE, PCI_ERMC_CLASSCODE_MASK) }, { 0, } @@ -2751,7 +2754,7 @@ err_free: return rv; } -static struct acpi_device_id acpi_ipmi_match[] = { +static const struct acpi_device_id acpi_ipmi_match[] = { { "IPI0001", 0 }, { }, }; @@ -3324,7 +3327,7 @@ static inline void wait_for_timer_and_thread(struct smi_info *smi_info) del_timer_sync(&smi_info->si_timer); } -static struct ipmi_default_vals +static const struct ipmi_default_vals { int type; int port; diff --git a/drivers/char/ipmi/ipmi_si_sm.h b/drivers/char/ipmi/ipmi_si_sm.h index df89f73475fb9..a705027c0493f 100644 --- a/drivers/char/ipmi/ipmi_si_sm.h +++ b/drivers/char/ipmi/ipmi_si_sm.h @@ -46,8 +46,8 @@ struct si_sm_data; * this interface. */ struct si_sm_io { - unsigned char (*inputb)(struct si_sm_io *io, unsigned int offset); - void (*outputb)(struct si_sm_io *io, + unsigned char (*inputb)(const struct si_sm_io *io, unsigned int offset); + void (*outputb)(const struct si_sm_io *io, unsigned int offset, unsigned char b); @@ -135,7 +135,7 @@ struct si_sm_handlers { }; /* Current state machines that we can use. */ -extern struct si_sm_handlers kcs_smi_handlers; -extern struct si_sm_handlers smic_smi_handlers; -extern struct si_sm_handlers bt_smi_handlers; +extern const struct si_sm_handlers kcs_smi_handlers; +extern const struct si_sm_handlers smic_smi_handlers; +extern const struct si_sm_handlers bt_smi_handlers; diff --git a/drivers/char/ipmi/ipmi_smic_sm.c b/drivers/char/ipmi/ipmi_smic_sm.c index c8e77afa8b961..8f7c73ff58f23 100644 --- a/drivers/char/ipmi/ipmi_smic_sm.c +++ b/drivers/char/ipmi/ipmi_smic_sm.c @@ -589,7 +589,7 @@ static int smic_size(void) return sizeof(struct si_sm_data); } -struct si_sm_handlers smic_smi_handlers = { +const struct si_sm_handlers smic_smi_handlers = { .init_data = init_smic_data, .start_transaction = start_smic_transaction, .get_result = smic_get_result, diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 0b1e569f5ff5e..41de0cf34c495 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -207,7 +207,7 @@ static inline int ipmi_demangle_device_id(const unsigned char *data, upper layer until the start_processing() function in the handlers is called, and the lower layer must get the interface from that call. */ -int ipmi_register_smi(struct ipmi_smi_handlers *handlers, +int ipmi_register_smi(const struct ipmi_smi_handlers *handlers, void *send_info, struct ipmi_device_id *device_id, struct device *dev, -- GitLab From b0868dd5c17c0d9cc8919e786db2e428aa225621 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Jul 2015 14:55:16 +0900 Subject: [PATCH 6275/7006] ipmi: Remove unneeded set_run_to_completion call send_panic_events() calls intf->handlers->set_run_to_completion(), but it has already been done in the caller function panic_event(). Remove it from send_panic_events(). Signed-off-by: Hidehiro Kawai Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index e9ea29c4ec604..5e31c339062ee 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4368,9 +4368,7 @@ static void send_panic_events(char *str) /* Interface is not ready. */ continue; - intf->run_to_completion = 1; /* Send the event announcing the panic. */ - intf->handlers->set_run_to_completion(intf->send_info, 1); ipmi_panic_request_and_wait(intf, &addr, &msg); } -- GitLab From e45361d733d0a1432b0f6307375045e66ac02489 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Jul 2015 14:55:16 +0900 Subject: [PATCH 6276/7006] ipmi: Factor out message flushing procedure Factor out message flushing procedure which is used in run-to-completion mode. This patch doesn't change the logic. Signed-off-by: Hidehiro Kawai Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 39 +++++++++++++++----------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 4a4a13dc98b3a..5bd6d5b974cd7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -924,11 +924,25 @@ static void check_start_timer_thread(struct smi_info *smi_info) } } +static void flush_messages(struct smi_info *smi_info) +{ + enum si_sm_result result; + + /* + * Currently, this function is called only in run-to-completion + * mode. This means we are single-threaded, no need for locks. + */ + result = smi_event_handler(smi_info, 0); + while (result != SI_SM_IDLE) { + udelay(SI_SHORT_TIMEOUT_USEC); + result = smi_event_handler(smi_info, SI_SHORT_TIMEOUT_USEC); + } +} + static void sender(void *send_info, struct ipmi_smi_msg *msg) { struct smi_info *smi_info = send_info; - enum si_sm_result result; unsigned long flags; debug_timestamp("Enqueue"); @@ -940,17 +954,7 @@ static void sender(void *send_info, */ smi_info->waiting_msg = msg; - /* - * Run to completion means we are single-threaded, no - * need for locks. - */ - - result = smi_event_handler(smi_info, 0); - while (result != SI_SM_IDLE) { - udelay(SI_SHORT_TIMEOUT_USEC); - result = smi_event_handler(smi_info, - SI_SHORT_TIMEOUT_USEC); - } + flush_messages(smi_info); return; } @@ -971,17 +975,10 @@ static void sender(void *send_info, static void set_run_to_completion(void *send_info, bool i_run_to_completion) { struct smi_info *smi_info = send_info; - enum si_sm_result result; smi_info->run_to_completion = i_run_to_completion; - if (i_run_to_completion) { - result = smi_event_handler(smi_info, 0); - while (result != SI_SM_IDLE) { - udelay(SI_SHORT_TIMEOUT_USEC); - result = smi_event_handler(smi_info, - SI_SHORT_TIMEOUT_USEC); - } - } + if (i_run_to_completion) + flush_messages(smi_info); } /* -- GitLab From 82802f968bd3118af04eaeb3814c21d9813be527 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Jul 2015 14:55:16 +0900 Subject: [PATCH 6277/7006] ipmi: Don't flush messages in sender() in run-to-completion mode When flushing queued messages in run-to-completion mode, smi_event_handler() is recursively called. flush_messages() smi_event_handler() handle_transaction_done() deliver_recv_msg() ipmi_smi_msg_received() smi_recv_tasklet() sender() flush_messages() smi_event_handler() ... The depth of the recursive call depends on the number of queued messages, so it can cause a stack overflow if many messages have been queued. To solve this problem, this patch removes flush_messages() from sender()@ipmi_si_intf.c. Instead, add flush_messages() to caller side of sender() if needed. Additionally, to implement this, add new handler flush_messages to struct ipmi_smi_handlers. Signed-off-by: Hidehiro Kawai Fixed up a comment and some spacing issues. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 3 +++ drivers/char/ipmi/ipmi_si_intf.c | 10 +++++----- include/linux/ipmi_smi.h | 5 +++++ 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 5e31c339062ee..6e191ff910e62 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4295,6 +4295,9 @@ static void ipmi_panic_request_and_wait(ipmi_smi_t intf, 0, 1); /* Don't retry, and don't wait. */ if (rv) atomic_sub(2, &panic_done_count); + else if (intf->handlers->flush_messages) + intf->handlers->flush_messages(intf->send_info); + while (atomic_read(&panic_done_count) != 0) ipmi_poll(intf); } diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 5bd6d5b974cd7..2f4cf6e78f72e 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -924,8 +924,9 @@ static void check_start_timer_thread(struct smi_info *smi_info) } } -static void flush_messages(struct smi_info *smi_info) +static void flush_messages(void *send_info) { + struct smi_info *smi_info = send_info; enum si_sm_result result; /* @@ -949,12 +950,10 @@ static void sender(void *send_info, if (smi_info->run_to_completion) { /* - * If we are running to completion, start it and run - * transactions until everything is clear. + * If we are running to completion, start it. Upper + * layer will call flush_messages to clear it out. */ smi_info->waiting_msg = msg; - - flush_messages(smi_info); return; } @@ -1260,6 +1259,7 @@ static const struct ipmi_smi_handlers handlers = { .set_need_watch = set_need_watch, .set_maintenance_mode = set_maintenance_mode, .set_run_to_completion = set_run_to_completion, + .flush_messages = flush_messages, .poll = poll, }; diff --git a/include/linux/ipmi_smi.h b/include/linux/ipmi_smi.h index 41de0cf34c495..f8cea14485ddd 100644 --- a/include/linux/ipmi_smi.h +++ b/include/linux/ipmi_smi.h @@ -115,6 +115,11 @@ struct ipmi_smi_handlers { implement it. */ void (*set_need_watch)(void *send_info, bool enable); + /* + * Called when flushing all pending messages. + */ + void (*flush_messages)(void *send_info); + /* Called when the interface should go into "run to completion" mode. If this call sets the value to true, the interface should make sure that all messages are flushed -- GitLab From 06e5e345fea8df24b1d935f98741343df4cab664 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Jul 2015 14:55:16 +0900 Subject: [PATCH 6278/7006] ipmi: Avoid touching possible corrupted lists in the panic context When processing queued messages in the panic context, IPMI driver tries to do it without any locking to avoid deadlocks. However, this means we can touch a corrupted list if the kernel panicked while manipulating the list. Fortunately, current `add-tail and del-from-head' style implementation won't touch the corrupted part, but it is inherently risky. To get rid of the risk, this patch re-initializes the message lists on panic if the related spinlock has already been acquired. As the result, we may lose queued messages, but it's not so painful. Dropping messages on the received message list is also less problematic because no one can respond the received messages. Signed-off-by: Hidehiro Kawai Fixed a comment typo. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index 6e191ff910e62..cdac5f7037e5c 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4511,6 +4511,23 @@ static int panic_event(struct notifier_block *this, /* Interface is not ready. */ continue; + /* + * If we were interrupted while locking xmit_msgs_lock or + * waiting_rcv_msgs_lock, the corresponding list may be + * corrupted. In this case, drop items on the list for + * the safety. + */ + if (!spin_trylock(&intf->xmit_msgs_lock)) { + INIT_LIST_HEAD(&intf->xmit_msgs); + INIT_LIST_HEAD(&intf->hp_xmit_msgs); + } else + spin_unlock(&intf->xmit_msgs_lock); + + if (!spin_trylock(&intf->waiting_rcv_msgs_lock)) + INIT_LIST_HEAD(&intf->waiting_rcv_msgs); + else + spin_unlock(&intf->waiting_rcv_msgs_lock); + intf->run_to_completion = 1; intf->handlers->set_run_to_completion(intf->send_info, 1); } -- GitLab From c49c097610fe1aabf86111297280a718abb5dcc2 Mon Sep 17 00:00:00 2001 From: Hidehiro Kawai Date: Mon, 27 Jul 2015 14:55:16 +0900 Subject: [PATCH 6279/7006] ipmi: Don't call receive handler in the panic context Received handlers defined as ipmi_recv_hndl member of struct ipmi_user_hndl can take a spinlock. This means that if the kernel panics while holding the lock, a deadlock may happen on the lock while flushing queued messages in the panic context. Calling the receive handler doesn't make much meanings in the panic context, simply skip it to avoid possible deadlocks. Signed-off-by: Hidehiro Kawai Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index cdac5f7037e5c..e3536da05c88a 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -744,7 +744,13 @@ static void deliver_response(struct ipmi_recv_msg *msg) ipmi_inc_stat(intf, unhandled_local_responses); } ipmi_free_recv_msg(msg); - } else { + } else if (!oops_in_progress) { + /* + * If we are running in the panic context, calling the + * receive handler doesn't much meaning and has a deadlock + * risk. At this moment, simply skip it in that case. + */ + ipmi_user_t user = msg->user; user->handler->ipmi_recv_hndl(msg, user->handler_data); } -- GitLab From d08828973d96eb26e48fb7ca8fb8a8d49adbe53a Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 18 Aug 2015 14:29:10 -0500 Subject: [PATCH 6280/7006] ipmi: Compensate for BMCs that wont set the irq enable bit It appears that some BMCs support interrupts but don't support setting the irq enable bits. The interrupts are just always on. Sigh. Add code to compensate. The new code was very similar to another functions, so this also factors out the common code into other functions. Signed-off-by: Corey Minyard Tested-by: Henrik Korkuc --- drivers/char/ipmi/ipmi_si_intf.c | 180 +++++++++++++++++++++++-------- 1 file changed, 137 insertions(+), 43 deletions(-) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 2f4cf6e78f72e..21bddc10e321a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -262,9 +262,21 @@ struct smi_info { bool supports_event_msg_buff; /* - * Can we clear the global enables receive irq bit? + * Can we disable interrupts the global enables receive irq + * bit? There are currently two forms of brokenness, some + * systems cannot disable the bit (which is technically within + * the spec but a bad idea) and some systems have the bit + * forced to zero even though interrupts work (which is + * clearly outside the spec). The next bool tells which form + * of brokenness is present. */ - bool cannot_clear_recv_irq_bit; + bool cannot_disable_irq; + + /* + * Some systems are broken and cannot set the irq enable + * bit, even if they support interrupts. + */ + bool irq_enable_broken; /* * Did we get an attention that we did not handle? @@ -554,13 +566,14 @@ static u8 current_global_enables(struct smi_info *smi_info, u8 base, if (smi_info->supports_event_msg_buff) enables |= IPMI_BMC_EVT_MSG_BUFF; - if ((smi_info->irq && !smi_info->interrupt_disabled) || - smi_info->cannot_clear_recv_irq_bit) + if (((smi_info->irq && !smi_info->interrupt_disabled) || + smi_info->cannot_disable_irq) && + !smi_info->irq_enable_broken) enables |= IPMI_BMC_RCV_MSG_INTR; if (smi_info->supports_event_msg_buff && - smi_info->irq && !smi_info->interrupt_disabled) - + smi_info->irq && !smi_info->interrupt_disabled && + !smi_info->irq_enable_broken) enables |= IPMI_BMC_EVT_MSG_INTR; *irq_on = enables & (IPMI_BMC_EVT_MSG_INTR | IPMI_BMC_RCV_MSG_INTR); @@ -2908,12 +2921,7 @@ static int try_get_dev_id(struct smi_info *smi_info) return rv; } -/* - * Some BMCs do not support clearing the receive irq bit in the global - * enables (even if they don't support interrupts on the BMC). Check - * for this and handle it properly. - */ -static void check_clr_rcv_irq(struct smi_info *smi_info) +static int get_global_enables(struct smi_info *smi_info, u8 *enables) { unsigned char msg[3]; unsigned char *resp; @@ -2921,12 +2929,8 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) int rv; resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); - if (!resp) { - printk(KERN_WARNING PFX "Out of memory allocating response for" - " global enables command, cannot check recv irq bit" - " handling.\n"); - return; - } + if (!resp) + return -ENOMEM; msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD; @@ -2934,9 +2938,9 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) rv = wait_for_msg_done(smi_info); if (rv) { - printk(KERN_WARNING PFX "Error getting response from get" - " global enables command, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Error getting response from get global enables command: %d\n", + rv); goto out; } @@ -2947,27 +2951,44 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || resp[2] != 0) { - printk(KERN_WARNING PFX "Invalid return from get global" - " enables command, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Invalid return from get global enables command: %ld %x %x %x\n", + resp_len, resp[0], resp[1], resp[2]); rv = -EINVAL; goto out; + } else { + *enables = resp[3]; } - if ((resp[3] & IPMI_BMC_RCV_MSG_INTR) == 0) - /* Already clear, should work ok. */ - goto out; +out: + kfree(resp); + return rv; +} + +/* + * Returns 1 if it gets an error from the command. + */ +static int set_global_enables(struct smi_info *smi_info, u8 enables) +{ + unsigned char msg[3]; + unsigned char *resp; + unsigned long resp_len; + int rv; + + resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL); + if (!resp) + return -ENOMEM; msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; - msg[2] = resp[3] & ~IPMI_BMC_RCV_MSG_INTR; + msg[2] = enables; smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3); rv = wait_for_msg_done(smi_info); if (rv) { - printk(KERN_WARNING PFX "Error getting response from set" - " global enables command, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Error getting response from set global enables command: %d\n", + rv); goto out; } @@ -2977,25 +2998,93 @@ static void check_clr_rcv_irq(struct smi_info *smi_info) if (resp_len < 3 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { - printk(KERN_WARNING PFX "Invalid return from get global" - " enables command, cannot check recv irq bit" - " handling.\n"); + dev_warn(smi_info->dev, + "Invalid return from set global enables command: %ld %x %x\n", + resp_len, resp[0], resp[1]); rv = -EINVAL; goto out; } - if (resp[2] != 0) { + if (resp[2] != 0) + rv = 1; + +out: + kfree(resp); + return rv; +} + +/* + * Some BMCs do not support clearing the receive irq bit in the global + * enables (even if they don't support interrupts on the BMC). Check + * for this and handle it properly. + */ +static void check_clr_rcv_irq(struct smi_info *smi_info) +{ + u8 enables = 0; + int rv; + + rv = get_global_enables(smi_info, &enables); + if (!rv) { + if ((enables & IPMI_BMC_RCV_MSG_INTR) == 0) + /* Already clear, should work ok. */ + return; + + enables &= ~IPMI_BMC_RCV_MSG_INTR; + rv = set_global_enables(smi_info, enables); + } + + if (rv < 0) { + dev_err(smi_info->dev, + "Cannot check clearing the rcv irq: %d\n", rv); + return; + } + + if (rv) { /* * An error when setting the event buffer bit means * clearing the bit is not supported. */ - printk(KERN_WARNING PFX "The BMC does not support clearing" - " the recv irq bit, compensating, but the BMC needs to" - " be fixed.\n"); - smi_info->cannot_clear_recv_irq_bit = true; + dev_warn(smi_info->dev, + "The BMC does not support clearing the recv irq bit, compensating, but the BMC needs to be fixed.\n"); + smi_info->cannot_disable_irq = true; + } +} + +/* + * Some BMCs do not support setting the interrupt bits in the global + * enables even if they support interrupts. Clearly bad, but we can + * compensate. + */ +static void check_set_rcv_irq(struct smi_info *smi_info) +{ + u8 enables = 0; + int rv; + + if (!smi_info->irq) + return; + + rv = get_global_enables(smi_info, &enables); + if (!rv) { + enables |= IPMI_BMC_RCV_MSG_INTR; + rv = set_global_enables(smi_info, enables); + } + + if (rv < 0) { + dev_err(smi_info->dev, + "Cannot check setting the rcv irq: %d\n", rv); + return; + } + + if (rv) { + /* + * An error when setting the event buffer bit means + * setting the bit is not supported. + */ + dev_warn(smi_info->dev, + "The BMC does not support setting the recv irq bit, compensating, but the BMC needs to be fixed.\n"); + smi_info->cannot_disable_irq = true; + smi_info->irq_enable_broken = true; } - out: - kfree(resp); } static int try_enable_event_buffer(struct smi_info *smi_info) @@ -3316,6 +3405,12 @@ static void setup_xaction_handlers(struct smi_info *smi_info) setup_dell_poweredge_bt_xaction_handler(smi_info); } +static void check_for_broken_irqs(struct smi_info *smi_info) +{ + check_clr_rcv_irq(smi_info); + check_set_rcv_irq(smi_info); +} + static inline void wait_for_timer_and_thread(struct smi_info *smi_info) { if (smi_info->thread != NULL) @@ -3493,10 +3588,9 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } - check_clr_rcv_irq(new_smi); - setup_oem_data_handler(new_smi); setup_xaction_handlers(new_smi); + check_for_broken_irqs(new_smi); new_smi->waiting_msg = NULL; new_smi->curr_msg = NULL; -- GitLab From acbd9ae70a94bdc626508f444879e19ebe1c421f Mon Sep 17 00:00:00 2001 From: Brijesh Singh Date: Mon, 24 Aug 2015 09:15:25 -0500 Subject: [PATCH 6281/7006] ipmi: add of_device_id in MODULE_DEVICE_TABLE Fix autoloading ipmi modules when using device tree. Signed-off-by: Brijesh Singh Moved this change up into the CONFIG_OF section to account for changes to the probing code. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 21bddc10e321a..654f6f36a071c 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2646,6 +2646,7 @@ static int of_ipmi_probe(struct platform_device *dev) } return 0; } +MODULE_DEVICE_TABLE(of, of_ipmi_match); #else #define of_ipmi_match NULL static int of_ipmi_probe(struct platform_device *dev) -- GitLab From bf2d087749d91e1fa2826edde1e2fd650d3053ca Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 27 Aug 2015 15:49:18 -0500 Subject: [PATCH 6282/7006] ipmi:ssif: Add a module parm to specify that SMBus alerts don't work They are broken on some platforms, this gives people a chance to work around it until the firmware is fixed. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_ssif.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index b043d8d458235..877205d220468 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1136,6 +1136,10 @@ module_param_array(slave_addrs, int, &num_slave_addrs, 0); MODULE_PARM_DESC(slave_addrs, "The default IPMB slave address for the controller."); +static bool alerts_broken; +module_param(alerts_broken, bool, 0); +MODULE_PARM_DESC(alerts_broken, "Don't enable alerts for the controller."); + /* * Bit 0 enables message debugging, bit 1 enables state debugging, and * bit 2 enables timing debugging. This is an array indexed by @@ -1582,6 +1586,10 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) ssif_info->global_enables |= IPMI_BMC_EVT_MSG_BUFF; } + /* Some systems don't behave well if you enable alerts. */ + if (alerts_broken) + goto found; + msg[0] = IPMI_NETFN_APP_REQUEST << 2; msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD; msg[2] = ssif_info->global_enables | IPMI_BMC_RCV_MSG_INTR; -- GitLab From c3acdc06a95ff20d920220ecb931186b0bb22c42 Mon Sep 17 00:00:00 2001 From: Doug Ledford Date: Thu, 3 Sep 2015 17:05:58 -0400 Subject: [PATCH 6283/7006] IB/ipoib: Clean up send-only multicast joins Even though we don't expect the group to be created by the SM we sill need to provide all the parameters to force the SM to validate they are correct. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- .../infiniband/ulp/ipoib/ipoib_multicast.c | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 0d23e0568deb6..5e2db3b7c8bb1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -448,8 +448,7 @@ out_locked: return status; } -static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, - int create) +static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) { struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_sa_multicast *multicast; @@ -471,7 +470,14 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, IB_SA_MCMEMBER_REC_PKEY | IB_SA_MCMEMBER_REC_JOIN_STATE; - if (create) { + if (mcast != priv->broadcast) { + /* + * RFC 4391: + * The MGID MUST use the same P_Key, Q_Key, SL, MTU, + * and HopLimit as those used in the broadcast-GID. The rest + * of attributes SHOULD follow the values used in the + * broadcast-GID as well. + */ comp_mask |= IB_SA_MCMEMBER_REC_QKEY | IB_SA_MCMEMBER_REC_MTU_SELECTOR | @@ -492,6 +498,22 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, rec.sl = priv->broadcast->mcmember.sl; rec.flow_label = priv->broadcast->mcmember.flow_label; rec.hop_limit = priv->broadcast->mcmember.hop_limit; + + /* + * Historically Linux IPoIB has never properly supported SEND + * ONLY join. It emulated it by not providing all the required + * attributes, which is enough to prevent group creation and + * detect if there are full members or not. A major problem + * with supporting SEND ONLY is detecting when the group is + * auto-destroyed as IPoIB will cache the MLID.. + */ +#if 1 + if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) + comp_mask &= ~IB_SA_MCMEMBER_REC_TRAFFIC_CLASS; +#else + if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) + rec.join_state = 4; +#endif } multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, @@ -517,7 +539,6 @@ void ipoib_mcast_join_task(struct work_struct *work) struct ib_port_attr port_attr; unsigned long delay_until = 0; struct ipoib_mcast *mcast = NULL; - int create = 1; if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) return; @@ -566,7 +587,6 @@ void ipoib_mcast_join_task(struct work_struct *work) if (IS_ERR_OR_NULL(priv->broadcast->mc) && !test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) { mcast = priv->broadcast; - create = 0; if (mcast->backoff > 1 && time_before(jiffies, mcast->delay_until)) { delay_until = mcast->delay_until; @@ -590,12 +610,8 @@ void ipoib_mcast_join_task(struct work_struct *work) /* Found the next unjoined group */ init_completion(&mcast->done); set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); - if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) - create = 0; - else - create = 1; spin_unlock_irq(&priv->lock); - ipoib_mcast_join(dev, mcast, create); + ipoib_mcast_join(dev, mcast); spin_lock_irq(&priv->lock); } else if (!delay_until || time_before(mcast->delay_until, delay_until)) @@ -618,7 +634,7 @@ out: } spin_unlock_irq(&priv->lock); if (mcast) - ipoib_mcast_join(dev, mcast, create); + ipoib_mcast_join(dev, mcast); } int ipoib_mcast_start_thread(struct net_device *dev) -- GitLab From d1178cbcdcf91900ccf10a177350d7945703c151 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Fri, 21 Aug 2015 17:34:13 -0600 Subject: [PATCH 6284/7006] IB/ipoib: Suppress warning for send only join failures We expect send only joins to fail, it just means there are no listeners for the group. The correct thing to do is silently drop the packet at source. Eg avahi will full join 224.0.0.251 which causes a send only IGMP packet to 224.0.0.22, and then a warning level kmessage like this: ib0: sendonly multicast join failed for ff12:401b:ffff:0000:0000:0000:0000:0016, status -22 If there is no IP router listening to IGMP. Signed-off-by: Jason Gunthorpe Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 5e2db3b7c8bb1..09a1748f9d131 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -393,8 +393,13 @@ static int ipoib_mcast_join_complete(int status, goto out_locked; } } else { - if (mcast->logcount++ < 20) { - if (status == -ETIMEDOUT || status == -EAGAIN) { + bool silent_fail = + test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) && + status == -EINVAL; + + if (mcast->logcount < 20) { + if (status == -ETIMEDOUT || status == -EAGAIN || + silent_fail) { ipoib_dbg_mcast(priv, "%smulticast join failed for %pI6, status %d\n", test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) ? "sendonly " : "", mcast->mcmember.mgid.raw, status); @@ -403,6 +408,9 @@ static int ipoib_mcast_join_complete(int status, test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) ? "sendonly " : "", mcast->mcmember.mgid.raw, status); } + + if (!silent_fail) + mcast->logcount++; } if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) && -- GitLab From 4e33d1f0a145d48e8cf287954bbf791af8387cfb Mon Sep 17 00:00:00 2001 From: Greg Kurz Date: Thu, 3 Sep 2015 11:12:59 +0200 Subject: [PATCH 6285/7006] KVM: PPC: Book3S: Fix typo in top comment about locking Signed-off-by: Greg Kurz Signed-off-by: Paul Mackerras --- arch/powerpc/kvm/book3s_xics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index c6ca7db646735..905e94a1370f4 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -41,7 +41,7 @@ * ======= * * Each ICS has a spin lock protecting the information about the IRQ - * sources and avoiding simultaneous deliveries if the same interrupt. + * sources and avoiding simultaneous deliveries of the same interrupt. * * ICP operations are done via a single compare & swap transaction * (most ICP state fits in the union kvmppc_icp_state) -- GitLab From 4548a697e4969d695047cebd6d9af5e2f6cc728e Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Wed, 2 Sep 2015 17:49:29 +0900 Subject: [PATCH 6286/7006] net: eth: altera: fix napi poll_list corruption tse_poll() calls __napi_complete() with irq enabled. This leads napi poll_list corruption and may stop all napi drivers working. Use napi_complete() instead of __napi_complete(). Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index da48e66377b5f..8207877d62376 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -511,8 +511,7 @@ static int tse_poll(struct napi_struct *napi, int budget) if (rxcomplete < budget) { - napi_gro_flush(napi, false); - __napi_complete(napi); + napi_complete(napi); netdev_dbg(priv->dev, "NAPI Complete, did %d packets with budget %d\n", -- GitLab From d82f0f1fc8a4f214a50c9dfc64e3896f9894afb7 Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Wed, 2 Sep 2015 16:20:21 -0300 Subject: [PATCH 6287/7006] sctp: fix dst leak Commit 0ca50d12fe46 failed to release the reference to dst entries that it decided to skip. Fixes: 0ca50d12fe46 ("sctp: fix src address selection if using secondary addresses") Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/protocol.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4345790ad3266..4abf94d4cce76 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -511,8 +511,10 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, */ odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, false); - if (!odev || odev->ifindex != fl4->flowi4_oif) + if (!odev || odev->ifindex != fl4->flowi4_oif) { + dst_release(&rt->dst); continue; + } dst = &rt->dst; break; -- GitLab From 410f03831c0768f2b1850d28ba697b167ddcb89b Mon Sep 17 00:00:00 2001 From: Marcelo Ricardo Leitner Date: Wed, 2 Sep 2015 16:20:22 -0300 Subject: [PATCH 6288/7006] sctp: add routing output fallback Commit 0ca50d12fe46 added a restriction that the address must belong to the output interface, so that sctp will use the right interface even when using secondary addresses. But it breaks IPVS setups, on which people is used to attach VIP addresses to loopback interface on real servers. It's preferred to attach to the interface actually in use, but it's a very common setup and that used to work. This patch then saves the first routing good result, even if it would be going out through an interface that doesn't have that address. If no better hit found, it's then used. This effectively restores the original behavior if no better interface could be found. Fixes: 0ca50d12fe46 ("sctp: fix src address selection if using secondary addresses") Signed-off-by: Marcelo Ricardo Leitner Signed-off-by: David S. Miller --- net/sctp/protocol.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 4abf94d4cce76..b7143337e4fa0 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -506,16 +506,22 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, if (IS_ERR(rt)) continue; + if (!dst) + dst = &rt->dst; + /* Ensure the src address belongs to the output * interface. */ odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, false); if (!odev || odev->ifindex != fl4->flowi4_oif) { - dst_release(&rt->dst); + if (&rt->dst != dst) + dst_release(&rt->dst); continue; } + if (dst != &rt->dst) + dst_release(dst); dst = &rt->dst; break; } -- GitLab From 26492f195eed08b95ad5acdfbe625062ad7d86c6 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 3 Sep 2015 10:50:57 -0700 Subject: [PATCH 6289/7006] Input: sparcspkr - fix module autoload for OF platform drivers These platform drivers have a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Dmitry Torokhov --- drivers/input/misc/sparcspkr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/input/misc/sparcspkr.c b/drivers/input/misc/sparcspkr.c index 54116e544c96e..6f997aa49183a 100644 --- a/drivers/input/misc/sparcspkr.c +++ b/drivers/input/misc/sparcspkr.c @@ -253,6 +253,7 @@ static const struct of_device_id bbc_beep_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, bbc_beep_match); static struct platform_driver bbc_beep_driver = { .driver = { @@ -332,6 +333,7 @@ static const struct of_device_id grover_beep_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, grover_beep_match); static struct platform_driver grover_beep_driver = { .driver = { -- GitLab From 22c15e5e008297c90daa8657fea1a3f0e0675454 Mon Sep 17 00:00:00 2001 From: James Chen Date: Thu, 3 Sep 2015 22:12:38 -0700 Subject: [PATCH 6290/7006] Input: elants_i2c - extend the calibration timeout to 12 seconds The 23 inch device found in Chrome project buddy requires 9.2~10.5 seconds to complete calibration. Let's increase calibration timeout to 12 seconds to give the device enough time. Signed-off-by: James Chen Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/elants_i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c index ddac134b25b10..17cc20ef4923b 100644 --- a/drivers/input/touchscreen/elants_i2c.c +++ b/drivers/input/touchscreen/elants_i2c.c @@ -102,7 +102,7 @@ #define ELAN_FW_PAGESIZE 132 /* calibration timeout definition */ -#define ELAN_CALI_TIMEOUT_MSEC 10000 +#define ELAN_CALI_TIMEOUT_MSEC 12000 #define ELAN_POWERON_DELAY_USEC 500 #define ELAN_RESET_DELAY_MSEC 20 -- GitLab From eb38f3a4f6e86f8bb10a3217ebd85ecc5d763aae Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Sep 2015 22:20:00 -0700 Subject: [PATCH 6291/7006] Input: evdev - do not report errors form flush() We've got bug reports showing the old systemd-logind (at least system-210) aborting unexpectedly, and this turned out to be because of an invalid error code from close() call to evdev devices. close() is supposed to return only either EINTR or EBADFD, while the device returned ENODEV. logind was overreacting to it and decided to kill itself when an unexpected error code was received. What a tragedy. The bad error code comes from flush fops, and actually evdev_flush() returns ENODEV when device is disconnected or client's access to it is revoked. But in these cases the fact that flush did not actually happen is not an error, but rather normal behavior. For non-disconnected devices result of flush is also not that interesting as there is no potential of data loss and even if it fails application has no way of handling the error. Because of that we are better off always returning success from evdev_flush(). Also returning EINTR from flush()/close() is discouraged (as it is not clear how application should handle this error), so let's stop taking evdev->mutex interruptibly. Bugzilla: http://bugzilla.suse.com/show_bug.cgi?id=939834 Cc: Signed-off-by: Takashi Iwai Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index 9d35499faca46..08d496411f757 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -290,19 +290,14 @@ static int evdev_flush(struct file *file, fl_owner_t id) { struct evdev_client *client = file->private_data; struct evdev *evdev = client->evdev; - int retval; - retval = mutex_lock_interruptible(&evdev->mutex); - if (retval) - return retval; + mutex_lock(&evdev->mutex); - if (!evdev->exist || client->revoked) - retval = -ENODEV; - else - retval = input_flush_device(&evdev->handle, file); + if (evdev->exist && !client->revoked) + input_flush_device(&evdev->handle, file); mutex_unlock(&evdev->mutex); - return retval; + return 0; } static void evdev_free(struct device *dev) -- GitLab From 1adecc6755e1e4193b5618ddb2e107f6d6e88f4b Mon Sep 17 00:00:00 2001 From: Woodrow Shen Date: Fri, 4 Sep 2015 15:08:12 +0800 Subject: [PATCH 6292/7006] ALSA: hda - Add some FIXUP quirks for white noise on Dell laptop. Dell laptop has a series model to use the same codec but different subsystem ID. At the same time they happens the white noise by login screen and headphone; for fixing them together, I only can add these IDs to FIXUP function ALC292_FIXUP_DISABLE_AAMIX, then try to solve such the similar issues. Codec: Realtek ALC3235 Vendor Id: 0x10ec0293 Subsystem Id: 0x102806dd Subsystem Id: 0x102806df Subsystem Id: 0x102806e0 Cc: BugLink: https://bugs.launchpad.net/bugs/1492132 Signed-off-by: Woodrow Shen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 4e6b0907f908c..764dd5bba9eea 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -5189,8 +5189,11 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x06c7, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), - SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX), SND_PCI_QUIRK(0x1028, 0x06db, "Dell", ALC292_FIXUP_DISABLE_AAMIX), + SND_PCI_QUIRK(0x1028, 0x06dd, "Dell", ALC292_FIXUP_DISABLE_AAMIX), + SND_PCI_QUIRK(0x1028, 0x06de, "Dell", ALC292_FIXUP_DISABLE_AAMIX), + SND_PCI_QUIRK(0x1028, 0x06df, "Dell", ALC292_FIXUP_DISABLE_AAMIX), + SND_PCI_QUIRK(0x1028, 0x06e0, "Dell", ALC292_FIXUP_DISABLE_AAMIX), SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), -- GitLab From 26803821463c4e76322559b3dfb0c6b0fcc8aee8 Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 2 Sep 2015 12:57:08 +0300 Subject: [PATCH 6293/7006] package/Makefile: move source tar creation to a function Split source tarball creation from rpm-pkg target so it can be used from deb-pkg target as well. As added bonus, we can now pretty print TAR the name of tarball created in quiet mode This patch prepares the groundwork for deb-pkg source package adding bit. Signed-off-by: Riku Voipio Signed-off-by: Michal Marek --- scripts/package/Makefile | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/scripts/package/Makefile b/scripts/package/Makefile index 8b11d5adec7f5..297e75684738c 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -24,27 +24,30 @@ # Remove hyphens since they have special meaning in RPM filenames KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE)) # Include only those top-level files that are needed by make, plus the GPL copy -TAR_CONTENT := $(KBUILD_ALLDIRS) kernel.spec .config .scmversion Makefile \ +TAR_CONTENT := $(KBUILD_ALLDIRS) .config .scmversion Makefile \ Kbuild Kconfig COPYING $(wildcard localversion*) -TAR_CONTENT := $(addprefix $(KERNELPATH)/,$(TAR_CONTENT)) MKSPEC := $(srctree)/scripts/package/mkspec +quiet_cmd_src_tar = TAR $(2).tar.gz + cmd_src_tar = \ +if test "$(objtree)" != "$(srctree)"; then \ + echo "Building source tarball is not possible outside the"; \ + echo "kernel source tree. Don't set KBUILD_OUTPUT, or use the"; \ + echo "binrpm-pkg or bindeb-pkg target instead."; \ + false; \ +fi ; \ +$(srctree)/scripts/setlocalversion --save-scmversion; \ +ln -sf $(srctree) $(2); \ +tar -cz $(RCS_TAR_IGNORE) -f $(2).tar.gz \ + $(addprefix $(2)/,$(TAR_CONTENT) $(3)); \ +rm -f $(2) $(objtree)/.scmversion + # rpm-pkg # --------------------------------------------------------------------------- rpm-pkg rpm: FORCE - @if test "$(objtree)" != "$(srctree)"; then \ - echo "Building source + binary RPM is not possible outside the"; \ - echo "kernel source tree. Don't set KBUILD_OUTPUT, or use the"; \ - echo "binrpm-pkg target instead."; \ - false; \ - fi $(MAKE) clean - ln -sf $(srctree) $(KERNELPATH) $(CONFIG_SHELL) $(MKSPEC) >$(objtree)/kernel.spec - $(CONFIG_SHELL) $(srctree)/scripts/setlocalversion --save-scmversion - tar -cz $(RCS_TAR_IGNORE) -f $(KERNELPATH).tar.gz $(TAR_CONTENT) - rm $(KERNELPATH) - rm -f $(objtree)/.scmversion + $(call cmd,src_tar,$(KERNELPATH),kernel.spec) $(CONFIG_SHELL) $(srctree)/scripts/mkversion > $(objtree)/.tmp_version mv -f $(objtree)/.tmp_version $(objtree)/.version rpmbuild --target $(UTS_MACHINE) -ta $(KERNELPATH).tar.gz -- GitLab From 3716001bcb7f5822382ac1f2f54226b87312cc6b Mon Sep 17 00:00:00 2001 From: Riku Voipio Date: Wed, 2 Sep 2015 12:57:24 +0300 Subject: [PATCH 6294/7006] deb-pkg: add source package Make deb-pkg build both source and binary package like make rpm-pkg does. For people who only need binary kernel package, there is now bindeb-pkg target, same target also used to build the .deb files if built from the source package using dpkg-buildpackage. Generated source package will build the same kernel .config than what was available for make deb-pkg. The name of the source package can be set with KDEB_SOURCENAME enviroment variable. The source package is useful for GPL compliance, or for feeding to a automated debian package builder. Cc: Chris J Arges Reviewed-by: maximilian attems Reviewed-by: Ben Hutchings Signed-off-by: Riku Voipio Signed-off-by: Michal Marek --- scripts/package/Makefile | 17 +++++++++++++---- scripts/package/builddeb | 38 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/scripts/package/Makefile b/scripts/package/Makefile index 297e75684738c..1aca224e8597c 100644 --- a/scripts/package/Makefile +++ b/scripts/package/Makefile @@ -23,6 +23,8 @@ # Remove hyphens since they have special meaning in RPM filenames KERNELPATH := kernel-$(subst -,_,$(KERNELRELEASE)) +KDEB_SOURCENAME ?= linux-$(KERNELRELEASE) +export KDEB_SOURCENAME # Include only those top-level files that are needed by make, plus the GPL copy TAR_CONTENT := $(KBUILD_ALLDIRS) .config .scmversion Makefile \ Kbuild Kconfig COPYING $(wildcard localversion*) @@ -83,11 +85,17 @@ quiet_cmd_builddeb = BUILDDEB } && \ \ $$KBUILD_PKG_ROOTCMD $(CONFIG_SHELL) \ - $(srctree)/scripts/package/builddeb + $(srctree)/scripts/package/builddeb $@ deb-pkg: FORCE + $(MAKE) clean + $(call cmd,src_tar,$(KDEB_SOURCENAME)) + $(MAKE) KBUILD_SRC= + +$(call cmd,builddeb) + +bindeb-pkg: FORCE $(MAKE) KBUILD_SRC= - $(call cmd,builddeb) + +$(call cmd,builddeb) clean-dirs += $(objtree)/debian/ @@ -132,8 +140,9 @@ perf-%pkg: FORCE # --------------------------------------------------------------------------- help: FORCE @echo ' rpm-pkg - Build both source and binary RPM kernel packages' - @echo ' binrpm-pkg - Build only the binary kernel package' - @echo ' deb-pkg - Build the kernel as a deb package' + @echo ' binrpm-pkg - Build only the binary kernel RPM package' + @echo ' deb-pkg - Build both source and binary deb kernel packages' + @echo ' bindeb-pkg - Build only the binary kernel deb package' @echo ' tar-pkg - Build the kernel as an uncompressed tarball' @echo ' targz-pkg - Build the kernel as a gzip compressed tarball' @echo ' tarbz2-pkg - Build the kernel as a bzip2 compressed tarball' diff --git a/scripts/package/builddeb b/scripts/package/builddeb index 0c18cfd932876..0cd46e129920e 100755 --- a/scripts/package/builddeb +++ b/scripts/package/builddeb @@ -79,6 +79,7 @@ if [ -n "$KDEB_PKGVERSION" ]; then else packageversion=$version-$revision fi +sourcename=$KDEB_SOURCENAME tmpdir="$objtree/debian/tmp" fwdir="$objtree/debian/fwtmp" kernel_headers_dir="$objtree/debian/hdrtmp" @@ -238,7 +239,7 @@ fi # Generate a simple changelog template cat < debian/changelog -linux-upstream ($packageversion) $distribution; urgency=low +$sourcename ($packageversion) $distribution; urgency=low * Custom built Linux kernel. @@ -265,12 +266,16 @@ On Debian GNU/Linux systems, the complete text of the GNU General Public License version 2 can be found in \`/usr/share/common-licenses/GPL-2'. EOF + +build_depends="bc, kmod, cpio " + # Generate a control file cat < debian/control -Source: linux-upstream +Source: $sourcename Section: kernel Priority: optional Maintainer: $maintainer +Build-Depends: $build_depends Standards-Version: 3.8.4 Homepage: http://www.kernel.org/ EOF @@ -391,4 +396,33 @@ EOF create_package "$dbg_packagename" "$dbg_dir" fi +if [ "x$1" = "xdeb-pkg" ] +then + cat < debian/rules +#!/usr/bin/make -f + +build: + \$(MAKE) + +binary-arch: + \$(MAKE) KDEB_SOURCENAME=${sourcename} KDEB_PKGVERSION=${packageversion} bindeb-pkg + +clean: + rm -rf debian/*tmp + mv debian/ debian.backup # debian/ might be cleaned away + \$(MAKE) clean + mv debian.backup debian + +binary: binary-arch +EOF + mv ${sourcename}.tar.gz ../${sourcename}_${version}.orig.tar.gz + tar caf ../${sourcename}_${packageversion}.debian.tar.gz debian/{copyright,rules,changelog,control} + dpkg-source -cdebian/control -ldebian/changelog --format="3.0 (custom)" --target-format="3.0 (quilt)" \ + -b / ../${sourcename}_${version}.orig.tar.gz ../${sourcename}_${packageversion}.debian.tar.gz + mv ${sourcename}_${packageversion}*dsc .. + dpkg-genchanges > ../${sourcename}_${packageversion}_${debarch}.changes +else + dpkg-genchanges -b > ../${sourcename}_${packageversion}_${debarch}.changes +fi + exit 0 -- GitLab From 86bfbc15660a61bb7b3df73db11939eec3393008 Mon Sep 17 00:00:00 2001 From: Luis de Bethencourt Date: Thu, 3 Sep 2015 13:03:04 +0200 Subject: [PATCH 6295/7006] ALSA: sparc: amd7930: Fix module autoload for OF platform driver This platform driver has a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Luis de Bethencourt Signed-off-by: Takashi Iwai --- sound/sparc/amd7930.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c index 784ceb85b2d9f..35c1f6ae773f0 100644 --- a/sound/sparc/amd7930.c +++ b/sound/sparc/amd7930.c @@ -1064,6 +1064,7 @@ static const struct of_device_id amd7930_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, amd7930_match); static struct platform_driver amd7930_sbus_driver = { .driver = { -- GitLab From 5631d9c429857194bd55d7bcd8fa5bdd1a9899a3 Mon Sep 17 00:00:00 2001 From: Michal Marek Date: Wed, 19 Aug 2015 17:36:41 +0200 Subject: [PATCH 6296/7006] kbuild: Fix clang detection We cannot detect clang before including the arch Makefile, because that can set the default cross compiler. We also cannot detect clang after including the arch Makefile, because powerpc wants to know about clang. Solve this by using an deferred variable. This costs us a few shell invocations, but this is only a constant number. Reported-by: Behan Webster Reported-by: Anton Blanchard Signed-off-by: Michal Marek --- Makefile | 9 +-------- arch/powerpc/Makefile | 8 ++++---- scripts/Kbuild.include | 4 ++++ scripts/Makefile.extrawarn | 2 +- 4 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 13270c0a93363..5ccbb58553aba 100644 --- a/Makefile +++ b/Makefile @@ -661,14 +661,7 @@ endif endif KBUILD_CFLAGS += $(stackp-flag) -ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) -COMPILER := clang -else -COMPILER := gcc -endif -export COMPILER - -ifeq ($(COMPILER),clang) +ifeq ($(cc-name),clang) KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,) KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable) diff --git a/arch/powerpc/Makefile b/arch/powerpc/Makefile index 05f464eb69527..dfe88896b06c0 100644 --- a/arch/powerpc/Makefile +++ b/arch/powerpc/Makefile @@ -67,7 +67,7 @@ UTS_MACHINE := $(OLDARCH) ifeq ($(CONFIG_CPU_LITTLE_ENDIAN),y) override CC += -mlittle-endian -ifneq ($(COMPILER),clang) +ifneq ($(cc-name),clang) override CC += -mno-strict-align endif override AS += -mlittle-endian @@ -333,7 +333,7 @@ TOUT := .tmp_gas_check # - Require gcc 4.0 or above on 64-bit # - gcc-4.2.0 has issues compiling modules on 64-bit checkbin: - @if test "${COMPILER}" != "clang" \ + @if test "$(cc-name)" != "clang" \ && test "$(cc-version)" = "0304" ; then \ if ! /bin/echo mftb 5 | $(AS) -v -mppc -many -o $(TOUT) >/dev/null 2>&1 ; then \ echo -n '*** ${VERSION}.${PATCHLEVEL} kernels no longer build '; \ @@ -342,14 +342,14 @@ checkbin: false; \ fi ; \ fi - @if test "${COMPILER}" != "clang" \ + @if test "$(cc-name)" != "clang" \ && test "$(cc-version)" -lt "0400" \ && test "x${CONFIG_PPC64}" = "xy" ; then \ echo -n "Sorry, GCC v4.0 or above is required to build " ; \ echo "the 64-bit powerpc kernel." ; \ false ; \ fi - @if test "${COMPILER}" != "clang" \ + @if test "$(cc-name)" != "clang" \ && test "$(cc-fullversion)" = "040200" \ && test "x${CONFIG_MODULES}${CONFIG_PPC64}" = "xyy" ; then \ echo -n '*** GCC-4.2.0 cannot compile the 64-bit powerpc ' ; \ diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include index d3437b82ac256..3523df6133910 100644 --- a/scripts/Kbuild.include +++ b/scripts/Kbuild.include @@ -128,6 +128,10 @@ cc-option-align = $(subst -functions=0,,\ cc-disable-warning = $(call try-run,\ $(CC) $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) +# cc-name +# Expands to either gcc or clang +cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) + # cc-version cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) diff --git a/scripts/Makefile.extrawarn b/scripts/Makefile.extrawarn index f734033af219d..4efedcbe4165f 100644 --- a/scripts/Makefile.extrawarn +++ b/scripts/Makefile.extrawarn @@ -56,7 +56,7 @@ endif KBUILD_CFLAGS += $(warning) else -ifeq ($(COMPILER),clang) +ifeq ($(cc-name),clang) KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides) KBUILD_CFLAGS += $(call cc-disable-warning, unused-value) KBUILD_CFLAGS += $(call cc-disable-warning, format) -- GitLab From 98a1f8282b8c37378c1b947d661a58942331ca90 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Wed, 26 Aug 2015 12:22:14 +0200 Subject: [PATCH 6297/7006] mac80211: Do not use sizeof() on pointer type The rate_control_cap_mask() function takes a parameter mcs_mask, which GCC will take to be u8 * even though it was declared with a fixed size. This causes the following warning: net/mac80211/rate.c: In function 'rate_control_cap_mask': net/mac80211/rate.c:719:25: warning: 'sizeof' on array function parameter 'mcs_mask' will return size of 'u8 * {aka unsigned char *}' [-Wsizeof-array-argument] for (i = 0; i < sizeof(mcs_mask); i++) ^ net/mac80211/rate.c:684:10: note: declared here u8 mcs_mask[IEEE80211_HT_MCS_MASK_LEN], ^ This can be easily fixed by using the IEEE80211_HT_MCS_MASK_LEN directly within the loop condition. Signed-off-by: Thierry Reding Signed-off-by: Johannes Berg --- net/mac80211/rate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 9857693b91ec7..9ce8883d5f449 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -716,7 +716,7 @@ static bool rate_control_cap_mask(struct ieee80211_sub_if_data *sdata, /* Filter out rates that the STA does not support */ *mask &= sta->supp_rates[sband->band]; - for (i = 0; i < sizeof(mcs_mask); i++) + for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) mcs_mask[i] &= sta->ht_cap.mcs.rx_mask[i]; sta_vht_cap = sta->vht_cap.vht_mcs.rx_mcs_map; -- GitLab From 22f66895e60cfc55b92f6fa93f05bb3fbdbd0bed Mon Sep 17 00:00:00 2001 From: Avri Altman Date: Tue, 18 Aug 2015 16:52:07 +0300 Subject: [PATCH 6298/7006] mac80211: protect non-HT BSS when HT TDLS traffic exists HT TDLS traffic should be protected in a non-HT BSS to avoid collisions. Therefore, when TDLS peers join/leave, check if protection is (now) needed and set the ht_operation_mode of the virtual interface according to the HT capabilities of the TDLS peer(s). This works because a non-HT BSS connection never sets (or otherwise uses) the ht_operation_mode; it just means that drivers must be aware that this field applies to all HT traffic for this virtual interface, not just the traffic within the BSS. Document that. Signed-off-by: Avri Altman Signed-off-by: Johannes Berg --- include/net/mac80211.h | 4 ++- net/mac80211/tdls.c | 70 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e3314e516681e..bfc569498bfa7 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -477,7 +477,9 @@ struct ieee80211_event { * @chandef: Channel definition for this BSS -- the hardware might be * configured a higher bandwidth than this BSS uses, for example. * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation. - * This field is only valid when the channel type is one of the HT types. + * This field is only valid when the channel is a wide HT/VHT channel. + * Note that with TDLS this can be the case (channel is HT, protection must + * be used from this field) even when the BSS association isn't using HT. * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value * implies disabled * @cqm_rssi_hyst: Connection quality monitor RSSI hysteresis diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c index aee701a5649e5..4e202d0679b26 100644 --- a/net/mac80211/tdls.c +++ b/net/mac80211/tdls.c @@ -1249,6 +1249,58 @@ static void iee80211_tdls_recalc_chanctx(struct ieee80211_sub_if_data *sdata) mutex_unlock(&local->chanctx_mtx); } +static int iee80211_tdls_have_ht_peers(struct ieee80211_sub_if_data *sdata) +{ + struct sta_info *sta; + bool result = false; + + rcu_read_lock(); + list_for_each_entry_rcu(sta, &sdata->local->sta_list, list) { + if (!sta->sta.tdls || sta->sdata != sdata || !sta->uploaded || + !test_sta_flag(sta, WLAN_STA_AUTHORIZED) || + !test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH) || + !sta->sta.ht_cap.ht_supported) + continue; + result = true; + break; + } + rcu_read_unlock(); + + return result; +} + +static void +iee80211_tdls_recalc_ht_protection(struct ieee80211_sub_if_data *sdata, + struct sta_info *sta) +{ + struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + bool tdls_ht; + u16 protection = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED | + IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT | + IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT; + u16 opmode; + + /* Nothing to do if the BSS connection uses HT */ + if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT)) + return; + + tdls_ht = (sta && sta->sta.ht_cap.ht_supported) || + iee80211_tdls_have_ht_peers(sdata); + + opmode = sdata->vif.bss_conf.ht_operation_mode; + + if (tdls_ht) + opmode |= protection; + else + opmode &= ~protection; + + if (opmode == sdata->vif.bss_conf.ht_operation_mode) + return; + + sdata->vif.bss_conf.ht_operation_mode = opmode; + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); +} + int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, const u8 *peer, enum nl80211_tdls_operation oper) { @@ -1274,6 +1326,10 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, return -ENOTSUPP; } + /* protect possible bss_conf changes and avoid concurrency in + * ieee80211_bss_info_change_notify() + */ + sdata_lock(sdata); mutex_lock(&local->mtx); tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); @@ -1287,16 +1343,18 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, iee80211_tdls_recalc_chanctx(sdata); - rcu_read_lock(); + mutex_lock(&local->sta_mtx); sta = sta_info_get(sdata, peer); if (!sta) { - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); ret = -ENOLINK; break; } + iee80211_tdls_recalc_ht_protection(sdata, sta); + set_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH); - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); WARN_ON_ONCE(is_zero_ether_addr(sdata->u.mgd.tdls_peer) || !ether_addr_equal(sdata->u.mgd.tdls_peer, peer)); @@ -1318,6 +1376,11 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, ieee80211_flush_queues(local, sdata, false); ret = sta_info_destroy_addr(sdata, peer); + + mutex_lock(&local->sta_mtx); + iee80211_tdls_recalc_ht_protection(sdata, NULL); + mutex_unlock(&local->sta_mtx); + iee80211_tdls_recalc_chanctx(sdata); break; default: @@ -1335,6 +1398,7 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, &sdata->u.mgd.request_smps_work); mutex_unlock(&local->mtx); + sdata_unlock(sdata); return ret; } -- GitLab From 4c0778933a3d7c35a94e8c35847acd9bb59a257d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Paulo=20Rechi=20Vita?= Date: Tue, 25 Aug 2015 08:56:43 -0400 Subject: [PATCH 6299/7006] rfkill: Copy "all" global state to other types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When switching the state of all RFKill switches of type all we need to replicate the RFKILL_TYPE_ALL global state to all the other types global state, so it is used to initialize persistent RFKill switches on register. Signed-off-by: João Paulo Rechi Vita Acked-by: Marcel Holtmann Signed-off-by: Johannes Berg --- net/rfkill/core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/net/rfkill/core.c b/net/rfkill/core.c index f12149a29cb19..b41e9ea2ffff4 100644 --- a/net/rfkill/core.c +++ b/net/rfkill/core.c @@ -341,7 +341,15 @@ static void __rfkill_switch_all(const enum rfkill_type type, bool blocked) { struct rfkill *rfkill; - rfkill_global_states[type].cur = blocked; + if (type == RFKILL_TYPE_ALL) { + int i; + + for (i = 0; i < NUM_RFKILL_TYPES; i++) + rfkill_global_states[i].cur = blocked; + } else { + rfkill_global_states[type].cur = blocked; + } + list_for_each_entry(rfkill, &rfkill_list, node) { if (rfkill->type != type && type != RFKILL_TYPE_ALL) continue; -- GitLab From 549cc1c560128d583698ba9a73af283fe87dbab8 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Wed, 2 Sep 2015 19:00:31 +0200 Subject: [PATCH 6300/7006] cfg80211: regulatory: restore proper user alpha2 restore_regulatory_settings() should restore alpha2 as computed in restore_alpha2(), not raw user_alpha2 to behave as described in the comment just above that code. This fixes endless loop of calling CRDA for "00" and "97" countries after resume from suspend on my laptop. Looks like others had the same problem, too: http://ath9k-devel.ath9k.narkive.com/knY5W6St/ath9k-and-crda-messages-in-logs https://bugs.launchpad.net/ubuntu/+source/linux/+bug/899335 https://forum.porteus.org/viewtopic.php?t=4975&p=36436 https://forums.opensuse.org/showthread.php/483356-Authentication-Regulatory-Domain-issues-ath5k-12-2 Signed-off-by: Maciej Szmigiero Signed-off-by: Johannes Berg --- net/wireless/reg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b144485946f2e..2510b231451ec 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -2625,7 +2625,7 @@ static void restore_regulatory_settings(bool reset_user) * settings, user regulatory settings takes precedence. */ if (is_an_alpha2(alpha2)) - regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER); + regulatory_hint_user(alpha2, NL80211_USER_REG_HINT_USER); spin_lock(®_requests_lock); list_splice_tail_init(&tmp_reg_req_list, ®_requests_list); -- GitLab From 52a45f38ca5998db0394e782d137595a82a08b43 Mon Sep 17 00:00:00 2001 From: Arik Nemtsov Date: Sat, 15 Aug 2015 22:39:53 +0300 Subject: [PATCH 6301/7006] mac80211: avoid VHT usage with no 80MHz chans allowed Currently if 80MHz channels are not allowed for use, the VHT IE is not included in the probe request for an AP. This is not good enough if the AP is configured with the wrong regulatory and supports VHT even where prohibited or in TDLS scenarios. Mark the ifmgd with the DISABLE_VHT flag for the misbehaving-AP case, and unset VHT support from the peer-station entry for the TDLS case. Signed-off-by: Arik Nemtsov Signed-off-by: Emmanuel Grumbach Signed-off-by: Johannes Berg --- net/mac80211/mlme.c | 16 ++++++++++++++++ net/mac80211/vht.c | 15 +++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 705ef1d040edf..cd7e55e08a238 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -4267,6 +4267,8 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband; struct cfg80211_chan_def chandef; int ret; + u32 i; + bool have_80mhz; sband = local->hw.wiphy->bands[cbss->channel->band]; @@ -4317,6 +4319,20 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata, } } + /* Allow VHT if at least one channel on the sband supports 80 MHz */ + have_80mhz = false; + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_80MHZ)) + continue; + + have_80mhz = true; + break; + } + + if (!have_80mhz) + ifmgd->flags |= IEEE80211_STA_DISABLE_VHT; + ifmgd->flags |= ieee80211_determine_chantype(sdata, sband, cbss->channel, ht_cap, ht_oper, vht_oper, diff --git a/net/mac80211/vht.c b/net/mac80211/vht.c index 834ccdbc74be1..ff1c798921a6a 100644 --- a/net/mac80211/vht.c +++ b/net/mac80211/vht.c @@ -120,6 +120,7 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, struct ieee80211_sta_vht_cap *vht_cap = &sta->sta.vht_cap; struct ieee80211_sta_vht_cap own_cap; u32 cap_info, i; + bool have_80mhz; memset(vht_cap, 0, sizeof(*vht_cap)); @@ -129,6 +130,20 @@ ieee80211_vht_cap_ie_to_sta_vht_cap(struct ieee80211_sub_if_data *sdata, if (!vht_cap_ie || !sband->vht_cap.vht_supported) return; + /* Allow VHT if at least one channel on the sband supports 80 MHz */ + have_80mhz = false; + for (i = 0; i < sband->n_channels; i++) { + if (sband->channels[i].flags & (IEEE80211_CHAN_DISABLED | + IEEE80211_CHAN_NO_80MHZ)) + continue; + + have_80mhz = true; + break; + } + + if (!have_80mhz) + return; + /* * A VHT STA must support 40 MHz, but if we verify that here * then we break a few things - some APs (e.g. Netgear R6300v2 -- GitLab From ef9be10c8c999e00b239eec24cf01952a308f8e7 Mon Sep 17 00:00:00 2001 From: Johannes Berg Date: Fri, 28 Aug 2015 10:44:20 +0200 Subject: [PATCH 6302/7006] mac80211: reject software RSSI CQM with beacon filtering When beacon filtering is enabled the mac80211 software implementation for RSSI CQM cannot work as beacons will not be available. Rather than accepting such a configuration without proper effect, reject it. Signed-off-by: Johannes Berg --- net/mac80211/cfg.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 685ec13ed7c2b..17b1fe961c5d6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2468,6 +2468,10 @@ static int ieee80211_set_cqm_rssi_config(struct wiphy *wiphy, rssi_hyst == bss_conf->cqm_rssi_hyst) return 0; + if (sdata->vif.driver_flags & IEEE80211_VIF_BEACON_FILTER && + !(sdata->vif.driver_flags & IEEE80211_VIF_SUPPORTS_CQM_RSSI)) + return -EOPNOTSUPP; + bss_conf->cqm_rssi_thold = rssi_thold; bss_conf->cqm_rssi_hyst = rssi_hyst; -- GitLab From 5134e999cb72c621f48305d5c201ab30156505c1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Fri, 4 Sep 2015 00:11:54 -0400 Subject: [PATCH 6303/7006] drm/amdgpu: fix warning in scheduler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should never happen so warn when the count does not equal the expected size. Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/scheduler/gpu_scheduler.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c index ab8577f8ed4a4..9259f1b6664c6 100644 --- a/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c +++ b/drivers/gpu/drm/amd/scheduler/gpu_scheduler.c @@ -332,7 +332,7 @@ static int amd_sched_main(void *param) { struct sched_param sparam = {.sched_priority = 1}; struct amd_gpu_scheduler *sched = (struct amd_gpu_scheduler *)param; - int r; + int r, count; sched_setscheduler(current, SCHED_FIFO, &sparam); @@ -361,7 +361,8 @@ static int amd_sched_main(void *param) fence_put(fence); } - kfifo_out(&entity->job_queue, &job, sizeof(job)); + count = kfifo_out(&entity->job_queue, &job, sizeof(job)); + WARN_ON(count != sizeof(job)); wake_up(&sched->job_scheduled); } return 0; -- GitLab From 71c6da846be478a61556717ef1ee1cea91f5d6a8 Mon Sep 17 00:00:00 2001 From: Andrey Ryabinin Date: Thu, 3 Sep 2015 14:32:01 +0300 Subject: [PATCH 6304/7006] crypto: ghash-clmulni: specify context size for ghash async algorithm Currently context size (cra_ctxsize) doesn't specified for ghash_async_alg. Which means it's zero. Thus crypto_create_tfm() doesn't allocate needed space for ghash_async_ctx, so any read/write to ctx (e.g. in ghash_async_init_tfm()) is not valid. Cc: stable@vger.kernel.org Signed-off-by: Andrey Ryabinin Signed-off-by: Herbert Xu --- arch/x86/crypto/ghash-clmulni-intel_glue.c | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/crypto/ghash-clmulni-intel_glue.c b/arch/x86/crypto/ghash-clmulni-intel_glue.c index 64d7cf1b50e11..440df0c7a2eef 100644 --- a/arch/x86/crypto/ghash-clmulni-intel_glue.c +++ b/arch/x86/crypto/ghash-clmulni-intel_glue.c @@ -294,6 +294,7 @@ static struct ahash_alg ghash_async_alg = { .cra_name = "ghash", .cra_driver_name = "ghash-clmulni", .cra_priority = 400, + .cra_ctxsize = sizeof(struct ghash_async_ctx), .cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC, .cra_blocksize = GHASH_BLOCK_SIZE, .cra_type = &crypto_ahash_type, -- GitLab From 062a68a5e0aaa9577d75391ffafa11e3c2a5f892 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 4 Sep 2015 09:11:24 -0700 Subject: [PATCH 6305/7006] Revert "uart: pl011: Add support to ZTE ZX296702 uart" This reverts commit 8cd90e50d1408c65c355084b1c7f8f9085f49c6b as with this patch the serial console is broken on lots of platforms. Reported-by: Marc Zyngier Cc: Jun Nie Acked-by: Will Deacon Tested-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 4 +- drivers/tty/serial/amba-pl011.c | 195 +++----------------------------- include/linux/amba/serial.h | 14 --- 3 files changed, 16 insertions(+), 197 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index ed299b9e63752..687b1ea294b79 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -47,12 +47,12 @@ config SERIAL_AMBA_PL010_CONSOLE config SERIAL_AMBA_PL011 tristate "ARM AMBA PL011 serial port support" - depends on ARM_AMBA || SOC_ZX296702 + depends on ARM_AMBA select SERIAL_CORE help This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M - here. Say Y or M if you have SOC_ZX296702. + here. If unsure, say N. diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 2af09ab153b6d..017443d092c15 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -74,10 +74,6 @@ /* There is by now at least one vendor with differing details, so handle it */ struct vendor_data { unsigned int ifls; - unsigned int fr_busy; - unsigned int fr_dsr; - unsigned int fr_cts; - unsigned int fr_ri; unsigned int lcrh_tx; unsigned int lcrh_rx; u16 *reg_lut; @@ -131,7 +127,6 @@ static u16 arm_reg[] = { [REG_DMACR] = UART011_DMACR, }; -#ifdef CONFIG_ARM_AMBA static unsigned int get_fifosize_arm(struct amba_device *dev) { return amba_rev(dev) < 3 ? 16 : 32; @@ -139,10 +134,6 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .fr_busy = UART01x_FR_BUSY, - .fr_dsr = UART01x_FR_DSR, - .fr_cts = UART01x_FR_CTS, - .fr_ri = UART011_FR_RI, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_LCRH, .reg_lut = arm_reg, @@ -153,13 +144,8 @@ static struct vendor_data vendor_arm = { .fixed_options = false, .get_fifosize = get_fifosize_arm, }; -#endif static struct vendor_data vendor_sbsa = { - .fr_busy = UART01x_FR_BUSY, - .fr_dsr = UART01x_FR_DSR, - .fr_cts = UART01x_FR_CTS, - .fr_ri = UART011_FR_RI, .reg_lut = arm_reg, .oversampling = false, .dma_threshold = false, @@ -168,7 +154,6 @@ static struct vendor_data vendor_sbsa = { .fixed_options = true, }; -#ifdef CONFIG_ARM_AMBA static u16 st_reg[] = { [REG_DR] = UART01x_DR, [REG_RSR] = UART01x_RSR, @@ -195,10 +180,6 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, - .fr_busy = UART01x_FR_BUSY, - .fr_dsr = UART01x_FR_DSR, - .fr_cts = UART01x_FR_CTS, - .fr_ri = UART011_FR_RI, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_ST_LCRH_RX, .reg_lut = st_reg, @@ -209,43 +190,6 @@ static struct vendor_data vendor_st = { .fixed_options = false, .get_fifosize = get_fifosize_st, }; -#endif - -#ifdef CONFIG_SOC_ZX296702 -static u16 zte_reg[] = { - [REG_DR] = ZX_UART01x_DR, - [REG_RSR] = UART01x_RSR, - [REG_ST_DMAWM] = ST_UART011_DMAWM, - [REG_FR] = ZX_UART01x_FR, - [REG_ST_LCRH_RX] = ST_UART011_LCRH_RX, - [REG_ILPR] = UART01x_ILPR, - [REG_IBRD] = UART011_IBRD, - [REG_FBRD] = UART011_FBRD, - [REG_LCRH] = ZX_UART011_LCRH_TX, - [REG_CR] = ZX_UART011_CR, - [REG_IFLS] = ZX_UART011_IFLS, - [REG_IMSC] = ZX_UART011_IMSC, - [REG_RIS] = ZX_UART011_RIS, - [REG_MIS] = ZX_UART011_MIS, - [REG_ICR] = ZX_UART011_ICR, - [REG_DMACR] = ZX_UART011_DMACR, -}; - -static struct vendor_data vendor_zte = { - .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .fr_busy = ZX_UART01x_FR_BUSY, - .fr_dsr = ZX_UART01x_FR_DSR, - .fr_cts = ZX_UART01x_FR_CTS, - .fr_ri = ZX_UART011_FR_RI, - .lcrh_tx = REG_LCRH, - .lcrh_rx = REG_ST_LCRH_RX, - .reg_lut = zte_reg, - .oversampling = false, - .dma_threshold = false, - .cts_event_workaround = false, - .fixed_options = false, -}; -#endif /* Deals with DMA transactions */ @@ -289,10 +233,6 @@ struct uart_amba_port { unsigned int im; /* interrupt mask */ unsigned int old_status; unsigned int fifosize; /* vendor-specific */ - unsigned int fr_busy; /* vendor-specific */ - unsigned int fr_dsr; /* vendor-specific */ - unsigned int fr_cts; /* vendor-specific */ - unsigned int fr_ri; /* vendor-specific */ unsigned int lcrh_tx; /* vendor-specific */ unsigned int lcrh_rx; /* vendor-specific */ unsigned int old_cr; /* state during shutdown */ @@ -1223,7 +1163,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (pl011_readw(uap, REG_FR) & uap->fr_busy) + while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) barrier(); spin_lock_irq(&uap->port.lock); @@ -1472,11 +1412,11 @@ static void pl011_modem_status(struct uart_amba_port *uap) if (delta & UART01x_FR_DCD) uart_handle_dcd_change(&uap->port, status & UART01x_FR_DCD); - if (delta & uap->fr_dsr) + if (delta & UART01x_FR_DSR) uap->port.icount.dsr++; - if (delta & uap->fr_cts) - uart_handle_cts_change(&uap->port, status & uap->fr_cts); + if (delta & UART01x_FR_CTS) + uart_handle_cts_change(&uap->port, status & UART01x_FR_CTS); wake_up_interruptible(&uap->port.state->port.delta_msr_wait); } @@ -1547,7 +1487,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int status = pl011_readw(uap, REG_FR); - return status & (uap->fr_busy|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; + return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } static unsigned int pl011_get_mctrl(struct uart_port *port) @@ -1562,9 +1502,9 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) result |= tiocmbit TIOCMBIT(UART01x_FR_DCD, TIOCM_CAR); - TIOCMBIT(uap->fr_dsr, TIOCM_DSR); - TIOCMBIT(uap->fr_cts, TIOCM_CTS); - TIOCMBIT(uap->fr_ri, TIOCM_RNG); + TIOCMBIT(UART01x_FR_DSR, TIOCM_DSR); + TIOCMBIT(UART01x_FR_CTS, TIOCM_CTS); + TIOCMBIT(UART011_FR_RI, TIOCM_RNG); #undef TIOCMBIT return result; } @@ -1780,7 +1720,8 @@ static int pl011_startup(struct uart_port *port) /* * initialise the old status of the modem signals */ - uap->old_status = pl011_readw(uap, REG_FR) & UART01x_FR_MODEM_ANY; + uap->old_status = pl011_readw(uap, REG_FR) & + UART01x_FR_MODEM_ANY; /* Startup DMA */ pl011_dma_startup(uap); @@ -1859,7 +1800,7 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap) /* mask all interrupts and clear all pending ones */ uap->im = 0; pl011_writew(uap, uap->im, REG_IMSC); - pl011_writew(uap, 0xffff, REG_ICR); + pl011_writew(0xffff, REG_ICR); spin_unlock_irq(&uap->port.lock); } @@ -2237,7 +2178,7 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) */ do { status = pl011_readw(uap, REG_FR); - } while (status & uap->fr_busy); + } while (status & UART01x_FR_BUSY); if (!uap->vendor->always_enabled) pl011_writew(uap, old_cr, REG_CR); @@ -2354,7 +2295,7 @@ static void pl011_putc(struct uart_port *port, int c) while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) ; pl011_writeb(uap, c, REG_DR); - while (pl011_readw(uap, REG_FR) & uap->fr_busy) + while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) ; } @@ -2500,7 +2441,6 @@ static int pl011_register_port(struct uart_amba_port *uap) return ret; } -#ifdef CONFIG_ARM_AMBA static int pl011_probe(struct amba_device *dev, const struct amba_id *id) { struct uart_amba_port *uap; @@ -2524,10 +2464,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) uap->reg_lut = vendor->reg_lut; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; - uap->fr_busy = vendor->fr_busy; - uap->fr_dsr = vendor->fr_dsr; - uap->fr_cts = vendor->fr_cts; - uap->fr_ri = vendor->fr_ri; uap->fifosize = vendor->get_fifosize(dev); uap->port.irq = dev->irq[0]; uap->port.ops = &amba_pl011_pops; @@ -2551,67 +2487,6 @@ static int pl011_remove(struct amba_device *dev) pl011_unregister_port(uap); return 0; } -#endif - -#ifdef CONFIG_SOC_ZX296702 -static int zx_uart_probe(struct platform_device *pdev) -{ - struct uart_amba_port *uap; - struct vendor_data *vendor = &vendor_zte; - struct resource *res; - int portnr, ret; - - portnr = pl011_find_free_port(); - if (portnr < 0) - return portnr; - - uap = devm_kzalloc(&pdev->dev, sizeof(struct uart_amba_port), - GFP_KERNEL); - if (!uap) { - ret = -ENOMEM; - goto out; - } - - uap->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(uap->clk)) { - ret = PTR_ERR(uap->clk); - goto out; - } - - uap->vendor = vendor; - uap->reg_lut = vendor->reg_lut; - uap->lcrh_rx = vendor->lcrh_rx; - uap->lcrh_tx = vendor->lcrh_tx; - uap->fr_busy = vendor->fr_busy; - uap->fr_dsr = vendor->fr_dsr; - uap->fr_cts = vendor->fr_cts; - uap->fr_ri = vendor->fr_ri; - uap->fifosize = 16; - uap->port.irq = platform_get_irq(pdev, 0); - uap->port.ops = &amba_pl011_pops; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - - ret = pl011_setup_port(&pdev->dev, uap, res, portnr); - if (ret) - return ret; - - platform_set_drvdata(pdev, uap); - - return pl011_register_port(uap); -out: - return ret; -} - -static int zx_uart_remove(struct platform_device *pdev) -{ - struct uart_amba_port *uap = platform_get_drvdata(pdev); - - uart_remove_one_port(&amba_reg, &uap->port); - pl011_unregister_port(uap); - return 0; -} -#endif #ifdef CONFIG_PM_SLEEP static int pl011_suspend(struct device *dev) @@ -2669,10 +2544,6 @@ static int sbsa_uart_probe(struct platform_device *pdev) uap->vendor = &vendor_sbsa; uap->reg_lut = vendor_sbsa.reg_lut; - uap->fr_busy = vendor_sbsa.fr_busy; - uap->fr_dsr = vendor_sbsa.fr_dsr; - uap->fr_cts = vendor_sbsa.fr_cts; - uap->fr_ri = vendor_sbsa.fr_ri; uap->fifosize = 32; uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; @@ -2722,7 +2593,6 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { }, }; -#ifdef CONFIG_ARM_AMBA static struct amba_id pl011_ids[] = { { .id = 0x00041011, @@ -2748,57 +2618,20 @@ static struct amba_driver pl011_driver = { .probe = pl011_probe, .remove = pl011_remove, }; -#endif - -#ifdef CONFIG_SOC_ZX296702 -static const struct of_device_id zx_uart_dt_ids[] = { - { .compatible = "zte,zx296702-uart", }, - { /* sentinel */ } -}; -MODULE_DEVICE_TABLE(of, zx_uart_dt_ids); - -static struct platform_driver zx_uart_driver = { - .driver = { - .name = "zx-uart", - .owner = THIS_MODULE, - .pm = &pl011_dev_pm_ops, - .of_match_table = zx_uart_dt_ids, - }, - .probe = zx_uart_probe, - .remove = zx_uart_remove, -}; -#endif - static int __init pl011_init(void) { - int ret; printk(KERN_INFO "Serial: AMBA PL011 UART driver\n"); if (platform_driver_register(&arm_sbsa_uart_platform_driver)) pr_warn("could not register SBSA UART platform driver\n"); - -#ifdef CONFIG_SOC_ZX296702 - ret = platform_driver_register(&zx_uart_driver); - if (ret) - pr_warn("could not register ZX UART platform driver\n"); -#endif - -#ifdef CONFIG_ARM_AMBA - ret = amba_driver_register(&pl011_driver); -#endif - return ret; + return amba_driver_register(&pl011_driver); } static void __exit pl011_exit(void) { platform_driver_unregister(&arm_sbsa_uart_platform_driver); -#ifdef CONFIG_SOC_ZX296702 - platform_driver_unregister(&zx_uart_driver); -#endif -#ifdef CONFIG_ARM_AMBA amba_driver_unregister(&pl011_driver); -#endif } /* diff --git a/include/linux/amba/serial.h b/include/linux/amba/serial.h index 6a0a89ed7f81c..0ddb5c02ad8b6 100644 --- a/include/linux/amba/serial.h +++ b/include/linux/amba/serial.h @@ -33,14 +33,12 @@ #define UART01x_DR 0x00 /* Data read or written from the interface. */ #define UART01x_RSR 0x04 /* Receive status register (Read). */ #define UART01x_ECR 0x04 /* Error clear register (Write). */ -#define ZX_UART01x_DR 0x04 /* Data read or written from the interface. */ #define UART010_LCRH 0x08 /* Line control register, high byte. */ #define ST_UART011_DMAWM 0x08 /* DMA watermark configure register. */ #define UART010_LCRM 0x0C /* Line control register, middle byte. */ #define ST_UART011_TIMEOUT 0x0C /* Timeout period register. */ #define UART010_LCRL 0x10 /* Line control register, low byte. */ #define UART010_CR 0x14 /* Control register. */ -#define ZX_UART01x_FR 0x14 /* Flag register (Read only). */ #define UART01x_FR 0x18 /* Flag register (Read only). */ #define UART010_IIR 0x1C /* Interrupt identification register (Read). */ #define UART010_ICR 0x1C /* Interrupt clear register (Write). */ @@ -51,21 +49,13 @@ #define UART011_LCRH 0x2c /* Line control register. */ #define ST_UART011_LCRH_TX 0x2c /* Tx Line control register. */ #define UART011_CR 0x30 /* Control register. */ -#define ZX_UART011_LCRH_TX 0x30 /* Tx Line control register. */ #define UART011_IFLS 0x34 /* Interrupt fifo level select. */ -#define ZX_UART011_CR 0x34 /* Control register. */ -#define ZX_UART011_IFLS 0x38 /* Interrupt fifo level select. */ #define UART011_IMSC 0x38 /* Interrupt mask. */ #define UART011_RIS 0x3c /* Raw interrupt status. */ #define UART011_MIS 0x40 /* Masked interrupt status. */ -#define ZX_UART011_IMSC 0x40 /* Interrupt mask. */ #define UART011_ICR 0x44 /* Interrupt clear register. */ -#define ZX_UART011_RIS 0x44 /* Raw interrupt status. */ #define UART011_DMACR 0x48 /* DMA control register. */ -#define ZX_UART011_MIS 0x48 /* Masked interrupt status. */ -#define ZX_UART011_ICR 0x4c /* Interrupt clear register. */ #define ST_UART011_XFCR 0x50 /* XON/XOFF control register. */ -#define ZX_UART011_DMACR 0x50 /* DMA control register. */ #define ST_UART011_XON1 0x54 /* XON1 register. */ #define ST_UART011_XON2 0x58 /* XON2 register. */ #define ST_UART011_XOFF1 0x5C /* XON1 register. */ @@ -85,19 +75,15 @@ #define UART01x_RSR_PE 0x02 #define UART01x_RSR_FE 0x01 -#define ZX_UART01x_FR_BUSY 0x300 #define UART011_FR_RI 0x100 #define UART011_FR_TXFE 0x080 #define UART011_FR_RXFF 0x040 #define UART01x_FR_TXFF 0x020 #define UART01x_FR_RXFE 0x010 #define UART01x_FR_BUSY 0x008 -#define ZX_UART01x_FR_DSR 0x008 #define UART01x_FR_DCD 0x004 #define UART01x_FR_DSR 0x002 -#define ZX_UART01x_FR_CTS 0x002 #define UART01x_FR_CTS 0x001 -#define ZX_UART011_FR_RI 0x001 #define UART01x_FR_TMSK (UART01x_FR_TXFF + UART01x_FR_BUSY) #define UART011_CR_CTSEN 0x8000 /* CTS hardware flow control */ -- GitLab From 8e50254a6ab2abb6ae08699adffe3d89e4c75912 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 4 Sep 2015 09:12:03 -0700 Subject: [PATCH 6306/7006] Revert "uart: pl011: Improve LCRH register access decision" This reverts commit 09dcc7dfc05b31bf0bbcd1511cd1a2644908d5c8 as with this patch the serial console is broken on lots of platforms. Reported-by: Marc Zyngier Cc: Jun Nie Acked-by: Will Deacon Tested-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 017443d092c15..e1f3bd5afad6d 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -249,11 +249,6 @@ struct uart_amba_port { #endif }; -static bool is_implemented(struct uart_amba_port *uap, unsigned int reg) -{ - return uap->reg_lut[reg] != (u16)~0; -} - static unsigned int pl011_readw(struct uart_amba_port *uap, int index) { WARN_ON(index > REG_NR); @@ -1654,7 +1649,7 @@ static int pl011_hwinit(struct uart_port *port) static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) { pl011_writew(uap, lcr_h, uap->lcrh_rx); - if (is_implemented(uap, REG_ST_LCRH_RX)) { + if (uap->lcrh_rx != uap->lcrh_tx) { int i; /* * Wait 10 PCLKs before writing LCRH_TX register, @@ -1789,7 +1784,7 @@ static void pl011_disable_uart(struct uart_amba_port *uap) * disable break condition and fifos */ pl011_shutdown_channel(uap, uap->lcrh_rx); - if (is_implemented(uap, REG_ST_LCRH_RX)) + if (uap->lcrh_rx != uap->lcrh_tx) pl011_shutdown_channel(uap, uap->lcrh_tx); } -- GitLab From ab66ca27c801605c6bb19baed2933544dd7d39e6 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 4 Sep 2015 09:13:30 -0700 Subject: [PATCH 6307/7006] Revert "uart: pl011: Introduce register look up table" This reverts commit 2c096a9eedc6841d3610545f4e6c3d72bd0962be as with this patch the serial console is broken on lots of platforms. Reported-by: Marc Zyngier Cc: Jun Nie Acked-by: Will Deacon Tested-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 55 +++------------------------------ 1 file changed, 5 insertions(+), 50 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index e1f3bd5afad6d..29a291d3bf24b 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -76,7 +76,6 @@ struct vendor_data { unsigned int ifls; unsigned int lcrh_tx; unsigned int lcrh_rx; - u16 *reg_lut; bool oversampling; bool dma_threshold; bool cts_event_workaround; @@ -108,25 +107,6 @@ enum reg_idx { REG_DMACR = IDX(UART011_DMACR), }; -static u16 arm_reg[] = { - [REG_DR] = UART01x_DR, - [REG_RSR] = UART01x_RSR, - [REG_ST_DMAWM] = ~0, - [REG_FR] = UART01x_FR, - [REG_ST_LCRH_RX] = ~0, - [REG_ILPR] = UART01x_ILPR, - [REG_IBRD] = UART011_IBRD, - [REG_FBRD] = UART011_FBRD, - [REG_LCRH] = UART011_LCRH, - [REG_CR] = UART011_CR, - [REG_IFLS] = UART011_IFLS, - [REG_IMSC] = UART011_IMSC, - [REG_RIS] = UART011_RIS, - [REG_MIS] = UART011_MIS, - [REG_ICR] = UART011_ICR, - [REG_DMACR] = UART011_DMACR, -}; - static unsigned int get_fifosize_arm(struct amba_device *dev) { return amba_rev(dev) < 3 ? 16 : 32; @@ -136,7 +116,6 @@ static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_LCRH, - .reg_lut = arm_reg, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -146,7 +125,6 @@ static struct vendor_data vendor_arm = { }; static struct vendor_data vendor_sbsa = { - .reg_lut = arm_reg, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -154,25 +132,6 @@ static struct vendor_data vendor_sbsa = { .fixed_options = true, }; -static u16 st_reg[] = { - [REG_DR] = UART01x_DR, - [REG_RSR] = UART01x_RSR, - [REG_ST_DMAWM] = ST_UART011_DMAWM, - [REG_FR] = UART01x_FR, - [REG_ST_LCRH_RX] = ST_UART011_LCRH_RX, - [REG_ILPR] = UART01x_ILPR, - [REG_IBRD] = UART011_IBRD, - [REG_FBRD] = UART011_FBRD, - [REG_LCRH] = UART011_LCRH, - [REG_CR] = UART011_CR, - [REG_IFLS] = UART011_IFLS, - [REG_IMSC] = UART011_IMSC, - [REG_RIS] = UART011_RIS, - [REG_MIS] = UART011_MIS, - [REG_ICR] = UART011_ICR, - [REG_DMACR] = UART011_DMACR, -}; - static unsigned int get_fifosize_st(struct amba_device *dev) { return 64; @@ -182,7 +141,6 @@ static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, .lcrh_tx = REG_LCRH, .lcrh_rx = REG_ST_LCRH_RX, - .reg_lut = st_reg, .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, @@ -228,7 +186,6 @@ struct uart_amba_port { struct uart_port port; struct clk *clk; const struct vendor_data *vendor; - u16 *reg_lut; unsigned int dmacr; /* dma control reg */ unsigned int im; /* interrupt mask */ unsigned int old_status; @@ -252,19 +209,19 @@ struct uart_amba_port { static unsigned int pl011_readw(struct uart_amba_port *uap, int index) { WARN_ON(index > REG_NR); - return readw_relaxed(uap->port.membase + uap->reg_lut[index]); + return readw_relaxed(uap->port.membase + (index << 2)); } static void pl011_writew(struct uart_amba_port *uap, int val, int index) { WARN_ON(index > REG_NR); - writew_relaxed(val, uap->port.membase + uap->reg_lut[index]); + writew_relaxed(val, uap->port.membase + (index << 2)); } static void pl011_writeb(struct uart_amba_port *uap, u8 val, int index) { WARN_ON(index > REG_NR); - writeb_relaxed(val, uap->port.membase + uap->reg_lut[index]); + writeb_relaxed(val, uap->port.membase + (index << 2)); } /* @@ -367,7 +324,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { - .dst_addr = uap->port.mapbase + uap->reg_lut[REG_DR], + .dst_addr = uap->port.mapbase + REG_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_MEM_TO_DEV, .dst_maxburst = uap->fifosize >> 1, @@ -422,7 +379,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) if (chan) { struct dma_slave_config rx_conf = { - .src_addr = uap->port.mapbase + uap->reg_lut[REG_DR], + .src_addr = uap->port.mapbase + REG_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, .src_maxburst = uap->fifosize >> 2, @@ -2456,7 +2413,6 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) return PTR_ERR(uap->clk); uap->vendor = vendor; - uap->reg_lut = vendor->reg_lut; uap->lcrh_rx = vendor->lcrh_rx; uap->lcrh_tx = vendor->lcrh_tx; uap->fifosize = vendor->get_fifosize(dev); @@ -2538,7 +2494,6 @@ static int sbsa_uart_probe(struct platform_device *pdev) return -ENOMEM; uap->vendor = &vendor_sbsa; - uap->reg_lut = vendor_sbsa.reg_lut; uap->fifosize = 32; uap->port.irq = platform_get_irq(pdev, 0); uap->port.ops = &sbsa_uart_pops; -- GitLab From f11c98417c65ddd730c483c1c9290ae0f7b121a7 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 4 Sep 2015 09:13:39 -0700 Subject: [PATCH 6308/7006] Revert "uart: pl011: Introduce register accessor" This reverts commit 7b753f318d1456c8e7740f3bd96d1dbb362d5449 as with this patch the serial console is broken on lots of platforms. Reported-by: Marc Zyngier Cc: Jun Nie Acked-by: Will Deacon Tested-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 263 +++++++++++++++----------------- 1 file changed, 122 insertions(+), 141 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 29a291d3bf24b..ee57e2bee9a1b 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -85,26 +85,23 @@ struct vendor_data { unsigned int (*get_fifosize)(struct amba_device *dev); }; -/* Max address offset of register in use is 0x48 */ -#define REG_NR (0x48 >> 2) -#define IDX(x) (x >> 2) enum reg_idx { - REG_DR = IDX(UART01x_DR), - REG_RSR = IDX(UART01x_RSR), - REG_ST_DMAWM = IDX(ST_UART011_DMAWM), - REG_FR = IDX(UART01x_FR), - REG_ST_LCRH_RX = IDX(ST_UART011_LCRH_RX), - REG_ILPR = IDX(UART01x_ILPR), - REG_IBRD = IDX(UART011_IBRD), - REG_FBRD = IDX(UART011_FBRD), - REG_LCRH = IDX(UART011_LCRH), - REG_CR = IDX(UART011_CR), - REG_IFLS = IDX(UART011_IFLS), - REG_IMSC = IDX(UART011_IMSC), - REG_RIS = IDX(UART011_RIS), - REG_MIS = IDX(UART011_MIS), - REG_ICR = IDX(UART011_ICR), - REG_DMACR = IDX(UART011_DMACR), + REG_DR = UART01x_DR, + REG_RSR = UART01x_RSR, + REG_ST_DMAWM = ST_UART011_DMAWM, + REG_FR = UART01x_FR, + REG_ST_LCRH_RX = ST_UART011_LCRH_RX, + REG_ILPR = UART01x_ILPR, + REG_IBRD = UART011_IBRD, + REG_FBRD = UART011_FBRD, + REG_LCRH = UART011_LCRH, + REG_CR = UART011_CR, + REG_IFLS = UART011_IFLS, + REG_IMSC = UART011_IMSC, + REG_RIS = UART011_RIS, + REG_MIS = UART011_MIS, + REG_ICR = UART011_ICR, + REG_DMACR = UART011_DMACR, }; static unsigned int get_fifosize_arm(struct amba_device *dev) @@ -206,24 +203,6 @@ struct uart_amba_port { #endif }; -static unsigned int pl011_readw(struct uart_amba_port *uap, int index) -{ - WARN_ON(index > REG_NR); - return readw_relaxed(uap->port.membase + (index << 2)); -} - -static void pl011_writew(struct uart_amba_port *uap, int val, int index) -{ - WARN_ON(index > REG_NR); - writew_relaxed(val, uap->port.membase + (index << 2)); -} - -static void pl011_writeb(struct uart_amba_port *uap, u8 val, int index) -{ - WARN_ON(index > REG_NR); - writeb_relaxed(val, uap->port.membase + (index << 2)); -} - /* * Reads up to 256 characters from the FIFO or until it's empty and * inserts them into the TTY layer. Returns the number of characters @@ -236,12 +215,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) int fifotaken = 0; while (max_count--) { - status = pl011_readw(uap, REG_FR); + status = readw(uap->port.membase + REG_FR); if (status & UART01x_FR_RXFE) break; /* Take chars from the FIFO and update status */ - ch = pl011_readw(uap, REG_DR) | + ch = readw(uap->port.membase + REG_DR) | UART_DUMMY_DR_RX; flag = TTY_NORMAL; uap->port.icount.rx++; @@ -478,7 +457,7 @@ static void pl011_dma_tx_callback(void *data) dmacr = uap->dmacr; uap->dmacr = dmacr & ~UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); /* * If TX DMA was disabled, it means that we've stopped the DMA for @@ -592,7 +571,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) dma_dev->device_issue_pending(chan); uap->dmacr |= UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->dmatx.queued = true; /* @@ -628,9 +607,9 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (uap->dmatx.queued) { uap->dmacr |= UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->im &= ~UART011_TXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return true; } @@ -640,7 +619,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return true; } return false; @@ -654,7 +633,7 @@ static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) { if (uap->dmatx.queued) { uap->dmacr &= ~UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); } } @@ -680,12 +659,14 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (!uap->dmatx.queued) { if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + + REG_IMSC); } else ret = false; } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, + uap->port.membase + REG_DMACR); } return ret; } @@ -696,9 +677,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) */ dmacr = uap->dmacr; uap->dmacr &= ~UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); - if (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) { + if (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) { /* * No space in the FIFO, so enable the transmit interrupt * so we know when there is space. Note that once we've @@ -707,13 +688,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) return false; } - pl011_writew(uap, uap->port.x_char, REG_DR); + writew(uap->port.x_char, uap->port.membase + REG_DR); uap->port.icount.tx++; uap->port.x_char = 0; /* Success - restore the DMA state */ uap->dmacr = dmacr; - pl011_writew(uap, dmacr, REG_DMACR); + writew(dmacr, uap->port.membase + REG_DMACR); return true; } @@ -741,7 +722,7 @@ __acquires(&uap->port.lock) DMA_TO_DEVICE); uap->dmatx.queued = false; uap->dmacr &= ~UART011_TXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); } } @@ -781,11 +762,11 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) dma_async_issue_pending(rxchan); uap->dmacr |= UART011_RXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->dmarx.running = true; uap->im &= ~UART011_RXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return 0; } @@ -843,9 +824,8 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, */ if (dma_count == pending && readfifo) { /* Clear any error flags */ - pl011_writew(uap, - UART011_OEIS | UART011_BEIS | UART011_PEIS - | UART011_FEIS, REG_ICR); + writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, + uap->port.membase + REG_ICR); /* * If we read all the DMA'd characters, and we had an @@ -893,7 +873,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) /* Disable RX DMA - incoming data will wait in the FIFO */ uap->dmacr &= ~UART011_RXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); uap->dmarx.running = false; pending = sgbuf->sg.length - state.residue; @@ -913,7 +893,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } } @@ -961,7 +941,7 @@ static void pl011_dma_rx_callback(void *data) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } } @@ -974,7 +954,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) { /* FIXME. Just disable the DMA enable */ uap->dmacr &= ~UART011_RXDMAE; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); } /* @@ -1018,7 +998,7 @@ static void pl011_dma_rx_poll(unsigned long args) spin_lock_irqsave(&uap->port.lock, flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); spin_unlock_irqrestore(&uap->port.lock, flags); uap->dmarx.running = false; @@ -1080,7 +1060,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap) skip_rx: /* Turn on DMA error (RX/TX will be enabled on demand) */ uap->dmacr |= UART011_DMAONERR; - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); /* * ST Micro variants has some specific dma burst threshold @@ -1088,9 +1068,9 @@ skip_rx: * be issued above/below 16 bytes. */ if (uap->vendor->dma_threshold) - pl011_writew(uap, - ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, - REG_ST_DMAWM); + writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, + uap->port.membase + REG_ST_DMAWM); + if (uap->using_rx_dma) { if (pl011_dma_rx_trigger_dma(uap)) @@ -1115,12 +1095,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) + while (readw(uap->port.membase + REG_FR) & UART01x_FR_BUSY) barrier(); spin_lock_irq(&uap->port.lock); uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); - pl011_writew(uap, uap->dmacr, REG_DMACR); + writew(uap->dmacr, uap->port.membase + REG_DMACR); spin_unlock_irq(&uap->port.lock); if (uap->using_tx_dma) { @@ -1221,7 +1201,7 @@ static void pl011_stop_tx(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im &= ~UART011_TXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); pl011_dma_tx_stop(uap); } @@ -1231,7 +1211,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); static void pl011_start_tx_pio(struct uart_amba_port *uap) { uap->im |= UART011_TXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); pl011_tx_chars(uap, false); } @@ -1251,7 +1231,7 @@ static void pl011_stop_rx(struct uart_port *port) uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| UART011_PEIM|UART011_BEIM|UART011_OEIM); - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); pl011_dma_rx_stop(uap); } @@ -1262,7 +1242,7 @@ static void pl011_enable_ms(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } static void pl011_rx_chars(struct uart_amba_port *uap) @@ -1282,7 +1262,7 @@ __acquires(&uap->port.lock) dev_dbg(uap->port.dev, "could not trigger RX DMA job " "fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); } else { #ifdef CONFIG_DMA_ENGINE /* Start Rx DMA poll */ @@ -1303,10 +1283,10 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, bool from_irq) { if (unlikely(!from_irq) && - pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) + readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) return false; /* unable to transmit character */ - pl011_writew(uap, c, REG_DR); + writew(c, uap->port.membase + REG_DR); uap->port.icount.tx++; return true; @@ -1353,7 +1333,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) { unsigned int status, delta; - status = pl011_readw(uap, REG_FR) & UART01x_FR_MODEM_ANY; + status = readw(uap->port.membase + REG_FR) & UART01x_FR_MODEM_ANY; delta = status ^ uap->old_status; uap->old_status = status; @@ -1381,15 +1361,15 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap) return; /* workaround to make sure that all bits are unlocked.. */ - pl011_writew(uap, 0x00, REG_ICR); + writew(0x00, uap->port.membase + REG_ICR); /* * WA: introduce 26ns(1 uart clk) delay before W1C; * single apb access will incur 2 pclk(133.12Mhz) delay, * so add 2 dummy reads */ - dummy_read = pl011_readw(uap, REG_ICR); - dummy_read = pl011_readw(uap, REG_ICR); + dummy_read = readw(uap->port.membase + REG_ICR); + dummy_read = readw(uap->port.membase + REG_ICR); } static irqreturn_t pl011_int(int irq, void *dev_id) @@ -1401,13 +1381,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id) int handled = 0; spin_lock_irqsave(&uap->port.lock, flags); - imsc = pl011_readw(uap, REG_IMSC); - status = pl011_readw(uap, REG_RIS) & imsc; + imsc = readw(uap->port.membase + REG_IMSC); + status = readw(uap->port.membase + REG_RIS) & imsc; if (status) { do { check_apply_cts_event_workaround(uap); - pl011_writew(uap, status & ~(UART011_TXIS|UART011_RTIS| - UART011_RXIS), REG_ICR); + + writew(status & ~(UART011_TXIS|UART011_RTIS| + UART011_RXIS), + uap->port.membase + REG_ICR); if (status & (UART011_RTIS|UART011_RXIS)) { if (pl011_dma_rx_running(uap)) @@ -1424,7 +1406,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (pass_counter-- == 0) break; - status = pl011_readw(uap, REG_RIS) & imsc; + status = readw(uap->port.membase + REG_RIS) & imsc; } while (status != 0); handled = 1; } @@ -1438,7 +1420,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned int status = pl011_readw(uap, REG_FR); + unsigned int status = readw(uap->port.membase + REG_FR); return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } @@ -1447,7 +1429,7 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int result = 0; - unsigned int status = pl011_readw(uap, REG_FR); + unsigned int status = readw(uap->port.membase + REG_FR); #define TIOCMBIT(uartbit, tiocmbit) \ if (status & uartbit) \ @@ -1467,7 +1449,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) container_of(port, struct uart_amba_port, port); unsigned int cr; - cr = pl011_readw(uap, REG_CR); + cr = readw(uap->port.membase + REG_CR); #define TIOCMBIT(tiocmbit, uartbit) \ if (mctrl & tiocmbit) \ @@ -1487,7 +1469,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) } #undef TIOCMBIT - pl011_writew(uap, cr, REG_CR); + writew(cr, uap->port.membase + REG_CR); } static void pl011_break_ctl(struct uart_port *port, int break_state) @@ -1498,12 +1480,12 @@ static void pl011_break_ctl(struct uart_port *port, int break_state) unsigned int lcr_h; spin_lock_irqsave(&uap->port.lock, flags); - lcr_h = pl011_readw(uap, uap->lcrh_tx); + lcr_h = readw(uap->port.membase + uap->lcrh_tx); if (break_state == -1) lcr_h |= UART01x_LCRH_BRK; else lcr_h &= ~UART01x_LCRH_BRK; - pl011_writew(uap, lcr_h, uap->lcrh_tx); + writew(lcr_h, uap->port.membase + uap->lcrh_tx); spin_unlock_irqrestore(&uap->port.lock, flags); } @@ -1513,8 +1495,9 @@ static void pl011_quiesce_irqs(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); + unsigned char __iomem *regs = uap->port.membase; - pl011_writew(uap, pl011_readw(uap, REG_MIS), REG_ICR); + writew(readw(regs + REG_MIS), regs + REG_ICR); /* * There is no way to clear TXIM as this is "ready to transmit IRQ", so * we simply mask it. start_tx() will unmask it. @@ -1528,7 +1511,7 @@ static void pl011_quiesce_irqs(struct uart_port *port) * (including tx queue), so we're also fine with start_tx()'s caller * side. */ - pl011_writew(uap, pl011_readw(uap, REG_IMSC) & ~UART011_TXIM, REG_IMSC); + writew(readw(regs + REG_IMSC) & ~UART011_TXIM, regs + REG_IMSC); } static int pl011_get_poll_char(struct uart_port *port) @@ -1543,11 +1526,11 @@ static int pl011_get_poll_char(struct uart_port *port) */ pl011_quiesce_irqs(port); - status = pl011_readw(uap, REG_FR); + status = readw(uap->port.membase + REG_FR); if (status & UART01x_FR_RXFE) return NO_POLL_CHAR; - return pl011_readw(uap, REG_DR); + return readw(uap->port.membase + REG_DR); } static void pl011_put_poll_char(struct uart_port *port, @@ -1556,10 +1539,10 @@ static void pl011_put_poll_char(struct uart_port *port, struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) + while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) barrier(); - pl011_writew(uap, ch, REG_DR); + writew(ch, uap->port.membase + REG_DR); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1583,15 +1566,15 @@ static int pl011_hwinit(struct uart_port *port) uap->port.uartclk = clk_get_rate(uap->clk); /* Clear pending error and receive interrupts */ - pl011_writew(uap, UART011_OEIS | UART011_BEIS | UART011_PEIS | - UART011_FEIS | UART011_RTIS | UART011_RXIS, REG_ICR); + writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS | + UART011_RTIS | UART011_RXIS, uap->port.membase + REG_ICR); /* * Save interrupts enable mask, and enable RX interrupts in case if * the interrupt is used for NMI entry. */ - uap->im = pl011_readw(uap, REG_IMSC); - pl011_writew(uap, UART011_RTIM | UART011_RXIM, REG_IMSC); + uap->im = readw(uap->port.membase + REG_IMSC); + writew(UART011_RTIM | UART011_RXIM, uap->port.membase + REG_IMSC); if (dev_get_platdata(uap->port.dev)) { struct amba_pl011_data *plat; @@ -1605,7 +1588,7 @@ static int pl011_hwinit(struct uart_port *port) static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) { - pl011_writew(uap, lcr_h, uap->lcrh_rx); + writew(lcr_h, uap->port.membase + uap->lcrh_rx); if (uap->lcrh_rx != uap->lcrh_tx) { int i; /* @@ -1613,14 +1596,14 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) * to get this delay write read only register 10 times */ for (i = 0; i < 10; ++i) - pl011_writew(uap, 0xff, REG_MIS); - pl011_writew(uap, lcr_h, uap->lcrh_tx); + writew(0xff, uap->port.membase + REG_MIS); + writew(lcr_h, uap->port.membase + uap->lcrh_tx); } } static int pl011_allocate_irq(struct uart_amba_port *uap) { - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); } @@ -1635,11 +1618,12 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) spin_lock_irq(&uap->port.lock); /* Clear out any spuriously appearing RX interrupts */ - pl011_writew(uap, UART011_RTIS | UART011_RXIS, REG_ICR); + writew(UART011_RTIS | UART011_RXIS, + uap->port.membase + REG_ICR); uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; - pl011_writew(uap, uap->im, REG_IMSC); + writew(uap->im, uap->port.membase + REG_IMSC); spin_unlock_irq(&uap->port.lock); } @@ -1658,21 +1642,21 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - pl011_writew(uap, uap->vendor->ifls, REG_IFLS); + writew(uap->vendor->ifls, uap->port.membase + REG_IFLS); spin_lock_irq(&uap->port.lock); /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - pl011_writew(uap, cr, REG_CR); + writew(cr, uap->port.membase + REG_CR); spin_unlock_irq(&uap->port.lock); /* * initialise the old status of the modem signals */ - uap->old_status = pl011_readw(uap, REG_FR) & + uap->old_status = readw(uap->port.membase + REG_FR) & UART01x_FR_MODEM_ANY; /* Startup DMA */ @@ -1712,11 +1696,11 @@ static int sbsa_uart_startup(struct uart_port *port) static void pl011_shutdown_channel(struct uart_amba_port *uap, unsigned int lcrh) { - unsigned long val; + unsigned long val; - val = pl011_readw(uap, lcrh); - val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); - pl011_writew(uap, val, lcrh); + val = readw(uap->port.membase + lcrh); + val &= ~(UART01x_LCRH_BRK | UART01x_LCRH_FEN); + writew(val, uap->port.membase + lcrh); } /* @@ -1730,11 +1714,11 @@ static void pl011_disable_uart(struct uart_amba_port *uap) uap->autorts = false; spin_lock_irq(&uap->port.lock); - cr = pl011_readw(uap, REG_CR); + cr = readw(uap->port.membase + REG_CR); uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - pl011_writew(uap, cr, REG_CR); + writew(cr, uap->port.membase + REG_CR); spin_unlock_irq(&uap->port.lock); /* @@ -1751,8 +1735,8 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap) /* mask all interrupts and clear all pending ones */ uap->im = 0; - pl011_writew(uap, uap->im, REG_IMSC); - pl011_writew(0xffff, REG_ICR); + writew(uap->im, uap->port.membase + REG_IMSC); + writew(0xffff, uap->port.membase + REG_ICR); spin_unlock_irq(&uap->port.lock); } @@ -1904,8 +1888,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, pl011_enable_ms(port); /* first, disable everything */ - old_cr = pl011_readw(uap, REG_CR); - pl011_writew(uap, 0, REG_CR); + old_cr = readw(port->membase + REG_CR); + writew(0, port->membase + REG_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) @@ -1938,8 +1922,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, quot -= 2; } /* Set baud rate */ - pl011_writew(uap, quot & 0x3f, REG_FBRD); - pl011_writew(uap, quot >> 6, REG_IBRD); + writew(quot & 0x3f, port->membase + REG_FBRD); + writew(quot >> 6, port->membase + REG_IBRD); /* * ----------v----------v----------v----------v----- @@ -1948,7 +1932,7 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, * ----------^----------^----------^----------^----- */ pl011_write_lcr_h(uap, lcr_h); - pl011_writew(uap, old_cr, REG_CR); + writew(old_cr, port->membase + REG_CR); spin_unlock_irqrestore(&port->lock, flags); } @@ -2089,9 +2073,9 @@ static void pl011_console_putchar(struct uart_port *port, int ch) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) + while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) barrier(); - pl011_writew(uap, ch, REG_DR); + writew(ch, uap->port.membase + REG_DR); } static void @@ -2116,10 +2100,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * First save the CR then disable the interrupts */ if (!uap->vendor->always_enabled) { - old_cr = pl011_readw(uap, REG_CR); + old_cr = readw(uap->port.membase + REG_CR); new_cr = old_cr & ~UART011_CR_CTSEN; new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - pl011_writew(uap, new_cr, REG_CR); + writew(new_cr, uap->port.membase + REG_CR); } uart_console_write(&uap->port, s, count, pl011_console_putchar); @@ -2129,10 +2113,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * and restore the TCR */ do { - status = pl011_readw(uap, REG_FR); + status = readw(uap->port.membase + REG_FR); } while (status & UART01x_FR_BUSY); if (!uap->vendor->always_enabled) - pl011_writew(uap, old_cr, REG_CR); + writew(old_cr, uap->port.membase + REG_CR); if (locked) spin_unlock(&uap->port.lock); @@ -2145,10 +2129,10 @@ static void __init pl011_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits) { - if (pl011_readw(uap, REG_CR) & UART01x_CR_UARTEN) { + if (readw(uap->port.membase + REG_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, ibrd, fbrd; - lcr_h = pl011_readw(uap, uap->lcrh_tx); + lcr_h = readw(uap->port.membase + uap->lcrh_tx); *parity = 'n'; if (lcr_h & UART01x_LCRH_PEN) { @@ -2163,13 +2147,13 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, else *bits = 8; - ibrd = pl011_readw(uap, REG_IBRD); - fbrd = pl011_readw(uap, REG_FBRD); + ibrd = readw(uap->port.membase + REG_IBRD); + fbrd = readw(uap->port.membase + REG_FBRD); *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); if (uap->vendor->oversampling) { - if (pl011_readw(uap, REG_CR) + if (readw(uap->port.membase + REG_CR) & ST_UART011_CR_OVSFACT) *baud *= 2; } @@ -2241,13 +2225,10 @@ static struct console amba_console = { static void pl011_putc(struct uart_port *port, int c) { - struct uart_amba_port *uap = - container_of(port, struct uart_amba_port, port); - - while (pl011_readw(uap, REG_FR) & UART01x_FR_TXFF) + while (readl(port->membase + REG_FR) & UART01x_FR_TXFF) ; - pl011_writeb(uap, c, REG_DR); - while (pl011_readw(uap, REG_FR) & UART01x_FR_BUSY) + writeb(c, port->membase + REG_DR); + while (readl(port->membase + REG_FR) & UART01x_FR_BUSY) ; } @@ -2374,8 +2355,8 @@ static int pl011_register_port(struct uart_amba_port *uap) int ret; /* Ensure interrupts from this UART are masked and cleared */ - pl011_writew(uap, 0, REG_IMSC); - pl011_writew(uap, 0xffff, REG_ICR); + writew(0, uap->port.membase + REG_IMSC); + writew(0xffff, uap->port.membase + REG_ICR); if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); -- GitLab From 0de6cfb9f314db230c47b2158e7725208b3b4728 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 4 Sep 2015 09:13:56 -0700 Subject: [PATCH 6309/7006] Revert "uart: pl011: Rename regs with enumeration" This reverts commit 534e14e2293d8cd714b94513686228453b21fae2 as with this patch the serial console is broken on lots of platforms. Reported-by: Marc Zyngier Cc: Jun Nie Acked-by: Will Deacon Tested-by: Will Deacon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 207 ++++++++++++++------------------ 1 file changed, 93 insertions(+), 114 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ee57e2bee9a1b..fd27e986b1dd3 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -85,25 +85,6 @@ struct vendor_data { unsigned int (*get_fifosize)(struct amba_device *dev); }; -enum reg_idx { - REG_DR = UART01x_DR, - REG_RSR = UART01x_RSR, - REG_ST_DMAWM = ST_UART011_DMAWM, - REG_FR = UART01x_FR, - REG_ST_LCRH_RX = ST_UART011_LCRH_RX, - REG_ILPR = UART01x_ILPR, - REG_IBRD = UART011_IBRD, - REG_FBRD = UART011_FBRD, - REG_LCRH = UART011_LCRH, - REG_CR = UART011_CR, - REG_IFLS = UART011_IFLS, - REG_IMSC = UART011_IMSC, - REG_RIS = UART011_RIS, - REG_MIS = UART011_MIS, - REG_ICR = UART011_ICR, - REG_DMACR = UART011_DMACR, -}; - static unsigned int get_fifosize_arm(struct amba_device *dev) { return amba_rev(dev) < 3 ? 16 : 32; @@ -111,8 +92,8 @@ static unsigned int get_fifosize_arm(struct amba_device *dev) static struct vendor_data vendor_arm = { .ifls = UART011_IFLS_RX4_8|UART011_IFLS_TX4_8, - .lcrh_tx = REG_LCRH, - .lcrh_rx = REG_LCRH, + .lcrh_tx = UART011_LCRH, + .lcrh_rx = UART011_LCRH, .oversampling = false, .dma_threshold = false, .cts_event_workaround = false, @@ -136,8 +117,8 @@ static unsigned int get_fifosize_st(struct amba_device *dev) static struct vendor_data vendor_st = { .ifls = UART011_IFLS_RX_HALF|UART011_IFLS_TX_HALF, - .lcrh_tx = REG_LCRH, - .lcrh_rx = REG_ST_LCRH_RX, + .lcrh_tx = ST_UART011_LCRH_TX, + .lcrh_rx = ST_UART011_LCRH_RX, .oversampling = true, .dma_threshold = true, .cts_event_workaround = true, @@ -215,12 +196,12 @@ static int pl011_fifo_to_tty(struct uart_amba_port *uap) int fifotaken = 0; while (max_count--) { - status = readw(uap->port.membase + REG_FR); + status = readw(uap->port.membase + UART01x_FR); if (status & UART01x_FR_RXFE) break; /* Take chars from the FIFO and update status */ - ch = readw(uap->port.membase + REG_DR) | + ch = readw(uap->port.membase + UART01x_DR) | UART_DUMMY_DR_RX; flag = TTY_NORMAL; uap->port.icount.rx++; @@ -303,7 +284,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) struct amba_pl011_data *plat = dev_get_platdata(uap->port.dev); struct device *dev = uap->port.dev; struct dma_slave_config tx_conf = { - .dst_addr = uap->port.mapbase + REG_DR, + .dst_addr = uap->port.mapbase + UART01x_DR, .dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_MEM_TO_DEV, .dst_maxburst = uap->fifosize >> 1, @@ -358,7 +339,7 @@ static void pl011_dma_probe(struct uart_amba_port *uap) if (chan) { struct dma_slave_config rx_conf = { - .src_addr = uap->port.mapbase + REG_DR, + .src_addr = uap->port.mapbase + UART01x_DR, .src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE, .direction = DMA_DEV_TO_MEM, .src_maxburst = uap->fifosize >> 2, @@ -457,7 +438,7 @@ static void pl011_dma_tx_callback(void *data) dmacr = uap->dmacr; uap->dmacr = dmacr & ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); /* * If TX DMA was disabled, it means that we've stopped the DMA for @@ -571,7 +552,7 @@ static int pl011_dma_tx_refill(struct uart_amba_port *uap) dma_dev->device_issue_pending(chan); uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); uap->dmatx.queued = true; /* @@ -607,9 +588,9 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (uap->dmatx.queued) { uap->dmacr |= UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); return true; } @@ -619,7 +600,7 @@ static bool pl011_dma_tx_irq(struct uart_amba_port *uap) */ if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); return true; } return false; @@ -633,7 +614,7 @@ static inline void pl011_dma_tx_stop(struct uart_amba_port *uap) { if (uap->dmatx.queued) { uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); } } @@ -660,13 +641,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) if (pl011_dma_tx_refill(uap) > 0) { uap->im &= ~UART011_TXIM; writew(uap->im, uap->port.membase + - REG_IMSC); + UART011_IMSC); } else ret = false; } else if (!(uap->dmacr & UART011_TXDMAE)) { uap->dmacr |= UART011_TXDMAE; writew(uap->dmacr, - uap->port.membase + REG_DMACR); + uap->port.membase + UART011_DMACR); } return ret; } @@ -677,9 +658,9 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) */ dmacr = uap->dmacr; uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); - if (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) { + if (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) { /* * No space in the FIFO, so enable the transmit interrupt * so we know when there is space. Note that once we've @@ -688,13 +669,13 @@ static inline bool pl011_dma_tx_start(struct uart_amba_port *uap) return false; } - writew(uap->port.x_char, uap->port.membase + REG_DR); + writew(uap->port.x_char, uap->port.membase + UART01x_DR); uap->port.icount.tx++; uap->port.x_char = 0; /* Success - restore the DMA state */ uap->dmacr = dmacr; - writew(dmacr, uap->port.membase + REG_DMACR); + writew(dmacr, uap->port.membase + UART011_DMACR); return true; } @@ -722,7 +703,7 @@ __acquires(&uap->port.lock) DMA_TO_DEVICE); uap->dmatx.queued = false; uap->dmacr &= ~UART011_TXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); } } @@ -762,11 +743,11 @@ static int pl011_dma_rx_trigger_dma(struct uart_amba_port *uap) dma_async_issue_pending(rxchan); uap->dmacr |= UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); uap->dmarx.running = true; uap->im &= ~UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); return 0; } @@ -825,7 +806,7 @@ static void pl011_dma_rx_chars(struct uart_amba_port *uap, if (dma_count == pending && readfifo) { /* Clear any error flags */ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS, - uap->port.membase + REG_ICR); + uap->port.membase + UART011_ICR); /* * If we read all the DMA'd characters, and we had an @@ -873,7 +854,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) /* Disable RX DMA - incoming data will wait in the FIFO */ uap->dmacr &= ~UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); uap->dmarx.running = false; pending = sgbuf->sg.length - state.residue; @@ -893,7 +874,7 @@ static void pl011_dma_rx_irq(struct uart_amba_port *uap) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); } } @@ -941,7 +922,7 @@ static void pl011_dma_rx_callback(void *data) dev_dbg(uap->port.dev, "could not retrigger RX DMA job " "fall back to interrupt mode\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); } } @@ -954,7 +935,7 @@ static inline void pl011_dma_rx_stop(struct uart_amba_port *uap) { /* FIXME. Just disable the DMA enable */ uap->dmacr &= ~UART011_RXDMAE; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); } /* @@ -998,7 +979,7 @@ static void pl011_dma_rx_poll(unsigned long args) spin_lock_irqsave(&uap->port.lock, flags); pl011_dma_rx_stop(uap); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); spin_unlock_irqrestore(&uap->port.lock, flags); uap->dmarx.running = false; @@ -1060,7 +1041,7 @@ static void pl011_dma_startup(struct uart_amba_port *uap) skip_rx: /* Turn on DMA error (RX/TX will be enabled on demand) */ uap->dmacr |= UART011_DMAONERR; - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); /* * ST Micro variants has some specific dma burst threshold @@ -1069,8 +1050,7 @@ skip_rx: */ if (uap->vendor->dma_threshold) writew(ST_UART011_DMAWM_RX_16 | ST_UART011_DMAWM_TX_16, - uap->port.membase + REG_ST_DMAWM); - + uap->port.membase + ST_UART011_DMAWM); if (uap->using_rx_dma) { if (pl011_dma_rx_trigger_dma(uap)) @@ -1095,12 +1075,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap) return; /* Disable RX and TX DMA */ - while (readw(uap->port.membase + REG_FR) & UART01x_FR_BUSY) + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_BUSY) barrier(); spin_lock_irq(&uap->port.lock); uap->dmacr &= ~(UART011_DMAONERR | UART011_RXDMAE | UART011_TXDMAE); - writew(uap->dmacr, uap->port.membase + REG_DMACR); + writew(uap->dmacr, uap->port.membase + UART011_DMACR); spin_unlock_irq(&uap->port.lock); if (uap->using_tx_dma) { @@ -1201,7 +1181,7 @@ static void pl011_stop_tx(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im &= ~UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); pl011_dma_tx_stop(uap); } @@ -1211,7 +1191,7 @@ static void pl011_tx_chars(struct uart_amba_port *uap, bool from_irq); static void pl011_start_tx_pio(struct uart_amba_port *uap) { uap->im |= UART011_TXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); pl011_tx_chars(uap, false); } @@ -1231,7 +1211,7 @@ static void pl011_stop_rx(struct uart_port *port) uap->im &= ~(UART011_RXIM|UART011_RTIM|UART011_FEIM| UART011_PEIM|UART011_BEIM|UART011_OEIM); - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); pl011_dma_rx_stop(uap); } @@ -1242,7 +1222,7 @@ static void pl011_enable_ms(struct uart_port *port) container_of(port, struct uart_amba_port, port); uap->im |= UART011_RIMIM|UART011_CTSMIM|UART011_DCDMIM|UART011_DSRMIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); } static void pl011_rx_chars(struct uart_amba_port *uap) @@ -1262,7 +1242,7 @@ __acquires(&uap->port.lock) dev_dbg(uap->port.dev, "could not trigger RX DMA job " "fall back to interrupt mode again\n"); uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); } else { #ifdef CONFIG_DMA_ENGINE /* Start Rx DMA poll */ @@ -1283,10 +1263,10 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, bool from_irq) { if (unlikely(!from_irq) && - readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) + readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) return false; /* unable to transmit character */ - writew(c, uap->port.membase + REG_DR); + writew(c, uap->port.membase + UART01x_DR); uap->port.icount.tx++; return true; @@ -1333,7 +1313,7 @@ static void pl011_modem_status(struct uart_amba_port *uap) { unsigned int status, delta; - status = readw(uap->port.membase + REG_FR) & UART01x_FR_MODEM_ANY; + status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; delta = status ^ uap->old_status; uap->old_status = status; @@ -1361,15 +1341,15 @@ static void check_apply_cts_event_workaround(struct uart_amba_port *uap) return; /* workaround to make sure that all bits are unlocked.. */ - writew(0x00, uap->port.membase + REG_ICR); + writew(0x00, uap->port.membase + UART011_ICR); /* * WA: introduce 26ns(1 uart clk) delay before W1C; * single apb access will incur 2 pclk(133.12Mhz) delay, * so add 2 dummy reads */ - dummy_read = readw(uap->port.membase + REG_ICR); - dummy_read = readw(uap->port.membase + REG_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); + dummy_read = readw(uap->port.membase + UART011_ICR); } static irqreturn_t pl011_int(int irq, void *dev_id) @@ -1381,15 +1361,15 @@ static irqreturn_t pl011_int(int irq, void *dev_id) int handled = 0; spin_lock_irqsave(&uap->port.lock, flags); - imsc = readw(uap->port.membase + REG_IMSC); - status = readw(uap->port.membase + REG_RIS) & imsc; + imsc = readw(uap->port.membase + UART011_IMSC); + status = readw(uap->port.membase + UART011_RIS) & imsc; if (status) { do { check_apply_cts_event_workaround(uap); writew(status & ~(UART011_TXIS|UART011_RTIS| UART011_RXIS), - uap->port.membase + REG_ICR); + uap->port.membase + UART011_ICR); if (status & (UART011_RTIS|UART011_RXIS)) { if (pl011_dma_rx_running(uap)) @@ -1406,7 +1386,7 @@ static irqreturn_t pl011_int(int irq, void *dev_id) if (pass_counter-- == 0) break; - status = readw(uap->port.membase + REG_RIS) & imsc; + status = readw(uap->port.membase + UART011_RIS) & imsc; } while (status != 0); handled = 1; } @@ -1420,7 +1400,7 @@ static unsigned int pl011_tx_empty(struct uart_port *port) { struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - unsigned int status = readw(uap->port.membase + REG_FR); + unsigned int status = readw(uap->port.membase + UART01x_FR); return status & (UART01x_FR_BUSY|UART01x_FR_TXFF) ? 0 : TIOCSER_TEMT; } @@ -1429,7 +1409,7 @@ static unsigned int pl011_get_mctrl(struct uart_port *port) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); unsigned int result = 0; - unsigned int status = readw(uap->port.membase + REG_FR); + unsigned int status = readw(uap->port.membase + UART01x_FR); #define TIOCMBIT(uartbit, tiocmbit) \ if (status & uartbit) \ @@ -1449,7 +1429,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) container_of(port, struct uart_amba_port, port); unsigned int cr; - cr = readw(uap->port.membase + REG_CR); + cr = readw(uap->port.membase + UART011_CR); #define TIOCMBIT(tiocmbit, uartbit) \ if (mctrl & tiocmbit) \ @@ -1469,7 +1449,7 @@ static void pl011_set_mctrl(struct uart_port *port, unsigned int mctrl) } #undef TIOCMBIT - writew(cr, uap->port.membase + REG_CR); + writew(cr, uap->port.membase + UART011_CR); } static void pl011_break_ctl(struct uart_port *port, int break_state) @@ -1497,7 +1477,7 @@ static void pl011_quiesce_irqs(struct uart_port *port) container_of(port, struct uart_amba_port, port); unsigned char __iomem *regs = uap->port.membase; - writew(readw(regs + REG_MIS), regs + REG_ICR); + writew(readw(regs + UART011_MIS), regs + UART011_ICR); /* * There is no way to clear TXIM as this is "ready to transmit IRQ", so * we simply mask it. start_tx() will unmask it. @@ -1511,7 +1491,7 @@ static void pl011_quiesce_irqs(struct uart_port *port) * (including tx queue), so we're also fine with start_tx()'s caller * side. */ - writew(readw(regs + REG_IMSC) & ~UART011_TXIM, regs + REG_IMSC); + writew(readw(regs + UART011_IMSC) & ~UART011_TXIM, regs + UART011_IMSC); } static int pl011_get_poll_char(struct uart_port *port) @@ -1526,11 +1506,11 @@ static int pl011_get_poll_char(struct uart_port *port) */ pl011_quiesce_irqs(port); - status = readw(uap->port.membase + REG_FR); + status = readw(uap->port.membase + UART01x_FR); if (status & UART01x_FR_RXFE) return NO_POLL_CHAR; - return readw(uap->port.membase + REG_DR); + return readw(uap->port.membase + UART01x_DR); } static void pl011_put_poll_char(struct uart_port *port, @@ -1539,10 +1519,10 @@ static void pl011_put_poll_char(struct uart_port *port, struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) barrier(); - writew(ch, uap->port.membase + REG_DR); + writew(ch, uap->port.membase + UART01x_DR); } #endif /* CONFIG_CONSOLE_POLL */ @@ -1567,14 +1547,14 @@ static int pl011_hwinit(struct uart_port *port) /* Clear pending error and receive interrupts */ writew(UART011_OEIS | UART011_BEIS | UART011_PEIS | UART011_FEIS | - UART011_RTIS | UART011_RXIS, uap->port.membase + REG_ICR); + UART011_RTIS | UART011_RXIS, uap->port.membase + UART011_ICR); /* * Save interrupts enable mask, and enable RX interrupts in case if * the interrupt is used for NMI entry. */ - uap->im = readw(uap->port.membase + REG_IMSC); - writew(UART011_RTIM | UART011_RXIM, uap->port.membase + REG_IMSC); + uap->im = readw(uap->port.membase + UART011_IMSC); + writew(UART011_RTIM | UART011_RXIM, uap->port.membase + UART011_IMSC); if (dev_get_platdata(uap->port.dev)) { struct amba_pl011_data *plat; @@ -1596,14 +1576,14 @@ static void pl011_write_lcr_h(struct uart_amba_port *uap, unsigned int lcr_h) * to get this delay write read only register 10 times */ for (i = 0; i < 10; ++i) - writew(0xff, uap->port.membase + REG_MIS); + writew(0xff, uap->port.membase + UART011_MIS); writew(lcr_h, uap->port.membase + uap->lcrh_tx); } } static int pl011_allocate_irq(struct uart_amba_port *uap) { - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); return request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap); } @@ -1619,11 +1599,11 @@ static void pl011_enable_interrupts(struct uart_amba_port *uap) /* Clear out any spuriously appearing RX interrupts */ writew(UART011_RTIS | UART011_RXIS, - uap->port.membase + REG_ICR); + uap->port.membase + UART011_ICR); uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; - writew(uap->im, uap->port.membase + REG_IMSC); + writew(uap->im, uap->port.membase + UART011_IMSC); spin_unlock_irq(&uap->port.lock); } @@ -1642,22 +1622,21 @@ static int pl011_startup(struct uart_port *port) if (retval) goto clk_dis; - writew(uap->vendor->ifls, uap->port.membase + REG_IFLS); + writew(uap->vendor->ifls, uap->port.membase + UART011_IFLS); spin_lock_irq(&uap->port.lock); /* restore RTS and DTR */ cr = uap->old_cr & (UART011_CR_RTS | UART011_CR_DTR); cr |= UART01x_CR_UARTEN | UART011_CR_RXE | UART011_CR_TXE; - writew(cr, uap->port.membase + REG_CR); + writew(cr, uap->port.membase + UART011_CR); spin_unlock_irq(&uap->port.lock); /* * initialise the old status of the modem signals */ - uap->old_status = readw(uap->port.membase + REG_FR) & - UART01x_FR_MODEM_ANY; + uap->old_status = readw(uap->port.membase + UART01x_FR) & UART01x_FR_MODEM_ANY; /* Startup DMA */ pl011_dma_startup(uap); @@ -1714,11 +1693,11 @@ static void pl011_disable_uart(struct uart_amba_port *uap) uap->autorts = false; spin_lock_irq(&uap->port.lock); - cr = readw(uap->port.membase + REG_CR); + cr = readw(uap->port.membase + UART011_CR); uap->old_cr = cr; cr &= UART011_CR_RTS | UART011_CR_DTR; cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(cr, uap->port.membase + REG_CR); + writew(cr, uap->port.membase + UART011_CR); spin_unlock_irq(&uap->port.lock); /* @@ -1735,8 +1714,8 @@ static void pl011_disable_interrupts(struct uart_amba_port *uap) /* mask all interrupts and clear all pending ones */ uap->im = 0; - writew(uap->im, uap->port.membase + REG_IMSC); - writew(0xffff, uap->port.membase + REG_ICR); + writew(uap->im, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); spin_unlock_irq(&uap->port.lock); } @@ -1888,8 +1867,8 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, pl011_enable_ms(port); /* first, disable everything */ - old_cr = readw(port->membase + REG_CR); - writew(0, port->membase + REG_CR); + old_cr = readw(port->membase + UART011_CR); + writew(0, port->membase + UART011_CR); if (termios->c_cflag & CRTSCTS) { if (old_cr & UART011_CR_RTS) @@ -1922,17 +1901,17 @@ pl011_set_termios(struct uart_port *port, struct ktermios *termios, quot -= 2; } /* Set baud rate */ - writew(quot & 0x3f, port->membase + REG_FBRD); - writew(quot >> 6, port->membase + REG_IBRD); + writew(quot & 0x3f, port->membase + UART011_FBRD); + writew(quot >> 6, port->membase + UART011_IBRD); /* * ----------v----------v----------v----------v----- * NOTE: lcrh_tx and lcrh_rx MUST BE WRITTEN AFTER - * REG_FBRD & REG_IBRD. + * UART011_FBRD & UART011_IBRD. * ----------^----------^----------^----------^----- */ pl011_write_lcr_h(uap, lcr_h); - writew(old_cr, port->membase + REG_CR); + writew(old_cr, port->membase + UART011_CR); spin_unlock_irqrestore(&port->lock, flags); } @@ -2073,9 +2052,9 @@ static void pl011_console_putchar(struct uart_port *port, int ch) struct uart_amba_port *uap = container_of(port, struct uart_amba_port, port); - while (readw(uap->port.membase + REG_FR) & UART01x_FR_TXFF) + while (readw(uap->port.membase + UART01x_FR) & UART01x_FR_TXFF) barrier(); - writew(ch, uap->port.membase + REG_DR); + writew(ch, uap->port.membase + UART01x_DR); } static void @@ -2100,10 +2079,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * First save the CR then disable the interrupts */ if (!uap->vendor->always_enabled) { - old_cr = readw(uap->port.membase + REG_CR); + old_cr = readw(uap->port.membase + UART011_CR); new_cr = old_cr & ~UART011_CR_CTSEN; new_cr |= UART01x_CR_UARTEN | UART011_CR_TXE; - writew(new_cr, uap->port.membase + REG_CR); + writew(new_cr, uap->port.membase + UART011_CR); } uart_console_write(&uap->port, s, count, pl011_console_putchar); @@ -2113,10 +2092,10 @@ pl011_console_write(struct console *co, const char *s, unsigned int count) * and restore the TCR */ do { - status = readw(uap->port.membase + REG_FR); + status = readw(uap->port.membase + UART01x_FR); } while (status & UART01x_FR_BUSY); if (!uap->vendor->always_enabled) - writew(old_cr, uap->port.membase + REG_CR); + writew(old_cr, uap->port.membase + UART011_CR); if (locked) spin_unlock(&uap->port.lock); @@ -2129,7 +2108,7 @@ static void __init pl011_console_get_options(struct uart_amba_port *uap, int *baud, int *parity, int *bits) { - if (readw(uap->port.membase + REG_CR) & UART01x_CR_UARTEN) { + if (readw(uap->port.membase + UART011_CR) & UART01x_CR_UARTEN) { unsigned int lcr_h, ibrd, fbrd; lcr_h = readw(uap->port.membase + uap->lcrh_tx); @@ -2147,13 +2126,13 @@ pl011_console_get_options(struct uart_amba_port *uap, int *baud, else *bits = 8; - ibrd = readw(uap->port.membase + REG_IBRD); - fbrd = readw(uap->port.membase + REG_FBRD); + ibrd = readw(uap->port.membase + UART011_IBRD); + fbrd = readw(uap->port.membase + UART011_FBRD); *baud = uap->port.uartclk * 4 / (64 * ibrd + fbrd); if (uap->vendor->oversampling) { - if (readw(uap->port.membase + REG_CR) + if (readw(uap->port.membase + UART011_CR) & ST_UART011_CR_OVSFACT) *baud *= 2; } @@ -2225,10 +2204,10 @@ static struct console amba_console = { static void pl011_putc(struct uart_port *port, int c) { - while (readl(port->membase + REG_FR) & UART01x_FR_TXFF) + while (readl(port->membase + UART01x_FR) & UART01x_FR_TXFF) ; - writeb(c, port->membase + REG_DR); - while (readl(port->membase + REG_FR) & UART01x_FR_BUSY) + writeb(c, port->membase + UART01x_DR); + while (readl(port->membase + UART01x_FR) & UART01x_FR_BUSY) ; } @@ -2355,8 +2334,8 @@ static int pl011_register_port(struct uart_amba_port *uap) int ret; /* Ensure interrupts from this UART are masked and cleared */ - writew(0, uap->port.membase + REG_IMSC); - writew(0xffff, uap->port.membase + REG_ICR); + writew(0, uap->port.membase + UART011_IMSC); + writew(0xffff, uap->port.membase + UART011_ICR); if (!amba_reg.state) { ret = uart_register_driver(&amba_reg); -- GitLab From 140b519f7a117c86c085b3800a2fea3015cd877f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20K=C3=B6nig?= Date: Fri, 4 Sep 2015 18:48:29 +0200 Subject: [PATCH 6310/7006] drm/amdgpu: properly enable VM fault interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes not printing VM faults. Signed-off-by: Christian König Reviewed-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c | 16 +++++++++------- drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c | 17 +++++++++-------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c index 10218828face1..774528ab87043 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v7_0.c @@ -523,17 +523,11 @@ static int gmc_v7_0_gart_enable(struct amdgpu_device *adev) tmp = RREG32(mmVM_CONTEXT1_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_DEPTH, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_BLOCK_SIZE, amdgpu_vm_block_size - 9); @@ -852,6 +846,13 @@ static int gmc_v7_0_early_init(void *handle) return 0; } +static int gmc_v7_0_late_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); +} + static int gmc_v7_0_sw_init(void *handle) { int r; @@ -976,6 +977,7 @@ static int gmc_v7_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + amdgpu_irq_put(adev, &adev->mc.vm_fault, 0); gmc_v7_0_gart_disable(adev); return 0; @@ -1301,7 +1303,7 @@ static int gmc_v7_0_set_powergating_state(void *handle, const struct amd_ip_funcs gmc_v7_0_ip_funcs = { .early_init = gmc_v7_0_early_init, - .late_init = NULL, + .late_init = gmc_v7_0_late_init, .sw_init = gmc_v7_0_sw_init, .sw_fini = gmc_v7_0_sw_fini, .hw_init = gmc_v7_0_hw_init, diff --git a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c index 78109b750d297..9a07742620d03 100644 --- a/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gmc_v8_0.c @@ -653,19 +653,12 @@ static int gmc_v8_0_gart_enable(struct amdgpu_device *adev) tmp = RREG32(mmVM_CONTEXT1_CNTL); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, ENABLE_CONTEXT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_DEPTH, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, RANGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, DUMMY_PAGE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PDE0_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, VALID_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, READ_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, WRITE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); - tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, EXECUTE_PROTECTION_FAULT_ENABLE_INTERRUPT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, EXECUTE_PROTECTION_FAULT_ENABLE_DEFAULT, 1); tmp = REG_SET_FIELD(tmp, VM_CONTEXT1_CNTL, PAGE_TABLE_BLOCK_SIZE, amdgpu_vm_block_size - 9); @@ -852,6 +845,13 @@ static int gmc_v8_0_early_init(void *handle) return 0; } +static int gmc_v8_0_late_init(void *handle) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + + return amdgpu_irq_get(adev, &adev->mc.vm_fault, 0); +} + static int gmc_v8_0_sw_init(void *handle) { int r; @@ -978,6 +978,7 @@ static int gmc_v8_0_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + amdgpu_irq_put(adev, &adev->mc.vm_fault, 0); gmc_v8_0_gart_disable(adev); return 0; @@ -1288,7 +1289,7 @@ static int gmc_v8_0_set_powergating_state(void *handle, const struct amd_ip_funcs gmc_v8_0_ip_funcs = { .early_init = gmc_v8_0_early_init, - .late_init = NULL, + .late_init = gmc_v8_0_late_init, .sw_init = gmc_v8_0_sw_init, .sw_fini = gmc_v8_0_sw_fini, .hw_init = gmc_v8_0_hw_init, -- GitLab From 898e50d444e12f735e45d07cd3f306ac5d4abca8 Mon Sep 17 00:00:00 2001 From: Leo Liu Date: Fri, 4 Sep 2015 15:08:55 -0400 Subject: [PATCH 6311/7006] drm/amdgpu: remove ib test for the second VCE Ring MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit it seems the VCE ring 1 ib test not reliable, remove it for now. Signed-off-by: Leo Liu Reviewed-by: Alex Deucher Reviewed-by: Christian König Tested-and-Reviewed-by: Sonny Jiang --- drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c index 76982438d1c6b..3cab96c42aa88 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_vce.c @@ -838,6 +838,10 @@ int amdgpu_vce_ring_test_ib(struct amdgpu_ring *ring) struct fence *fence = NULL; int r; + /* skip vce ring1 ib test for now, since it's not reliable */ + if (ring == &ring->adev->vce.ring[1]) + return 0; + r = amdgpu_vce_get_create_msg(ring, 1, NULL); if (r) { DRM_ERROR("amdgpu: failed to get create msg (%d).\n", r); -- GitLab From be4f38e28ca2bbd6d06db8064277d71389746e26 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Sep 2015 19:03:11 -0400 Subject: [PATCH 6312/7006] drm/amdgpu: fix vce3 instance handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Need to properly handle the instances for the idle checks and soft reset. Acked-by: Leo Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vce_v3_0.c | 48 +++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c index 5642b8eb92ad7..f0656dfb53f3a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c +++ b/drivers/gpu/drm/amd/amdgpu/vce_v3_0.c @@ -32,8 +32,8 @@ #include "vid.h" #include "vce/vce_3_0_d.h" #include "vce/vce_3_0_sh_mask.h" -#include "oss/oss_2_0_d.h" -#include "oss/oss_2_0_sh_mask.h" +#include "oss/oss_3_0_d.h" +#include "oss/oss_3_0_sh_mask.h" #include "gca/gfx_8_0_d.h" #include "smu/smu_7_1_2_d.h" #include "smu/smu_7_1_2_sh_mask.h" @@ -426,17 +426,41 @@ static void vce_v3_0_mc_resume(struct amdgpu_device *adev, int idx) static bool vce_v3_0_is_idle(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + u32 mask = 0; + int idx; - return !(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK); + for (idx = 0; idx < 2; ++idx) { + if (adev->vce.harvest_config & (1 << idx)) + continue; + + if (idx == 0) + mask |= SRBM_STATUS2__VCE0_BUSY_MASK; + else + mask |= SRBM_STATUS2__VCE1_BUSY_MASK; + } + + return !(RREG32(mmSRBM_STATUS2) & mask); } static int vce_v3_0_wait_for_idle(void *handle) { unsigned i; struct amdgpu_device *adev = (struct amdgpu_device *)handle; + u32 mask = 0; + int idx; + + for (idx = 0; idx < 2; ++idx) { + if (adev->vce.harvest_config & (1 << idx)) + continue; + + if (idx == 0) + mask |= SRBM_STATUS2__VCE0_BUSY_MASK; + else + mask |= SRBM_STATUS2__VCE1_BUSY_MASK; + } for (i = 0; i < adev->usec_timeout; i++) { - if (!(RREG32(mmSRBM_STATUS2) & SRBM_STATUS2__VCE_BUSY_MASK)) + if (!(RREG32(mmSRBM_STATUS2) & mask)) return 0; } return -ETIMEDOUT; @@ -445,9 +469,21 @@ static int vce_v3_0_wait_for_idle(void *handle) static int vce_v3_0_soft_reset(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; + u32 mask = 0; + int idx; + + for (idx = 0; idx < 2; ++idx) { + if (adev->vce.harvest_config & (1 << idx)) + continue; - WREG32_P(mmSRBM_SOFT_RESET, SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK, - ~SRBM_SOFT_RESET__SOFT_RESET_VCE_MASK); + if (idx == 0) + mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK; + else + mask |= SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK; + } + WREG32_P(mmSRBM_SOFT_RESET, mask, + ~(SRBM_SOFT_RESET__SOFT_RESET_VCE0_MASK | + SRBM_SOFT_RESET__SOFT_RESET_VCE1_MASK)); mdelay(5); return vce_v3_0_start(adev); -- GitLab From 35c7a9526af75040fac744babd0fafe18b8fe0a1 Mon Sep 17 00:00:00 2001 From: Alex Deucher Date: Thu, 3 Sep 2015 18:01:00 -0400 Subject: [PATCH 6313/7006] drm/amdgpu: rename gmc_v8_0_init_compute_vmid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It should be gfx_v8_0_init_compute_vmid since it's part of the gfx block. Acked-by: Leo Liu Reviewed-by: Christian König Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 0af357a1a170e..53f07439a5128 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -2005,7 +2005,7 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev, } /** - * gmc_v8_0_init_compute_vmid - gart enable + * gfx_v8_0_init_compute_vmid - gart enable * * @rdev: amdgpu_device pointer * @@ -2015,7 +2015,7 @@ static void gfx_v8_0_setup_rb(struct amdgpu_device *adev, #define DEFAULT_SH_MEM_BASES (0x6000) #define FIRST_COMPUTE_VMID (8) #define LAST_COMPUTE_VMID (16) -static void gmc_v8_0_init_compute_vmid(struct amdgpu_device *adev) +static void gfx_v8_0_init_compute_vmid(struct amdgpu_device *adev) { int i; uint32_t sh_mem_config; @@ -2282,7 +2282,7 @@ static void gfx_v8_0_gpu_init(struct amdgpu_device *adev) vi_srbm_select(adev, 0, 0, 0, 0); mutex_unlock(&adev->srbm_mutex); - gmc_v8_0_init_compute_vmid(adev); + gfx_v8_0_init_compute_vmid(adev); mutex_lock(&adev->grbm_idx_mutex); /* -- GitLab From 5cf9d70659594e1a75b34d18619d0bb6e0cbbafa Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 4 Sep 2015 15:07:37 -0400 Subject: [PATCH 6314/7006] NFS: Optimise away the close-to-open getattr if there is no cached data If there is no cached data, then there is no need to track the file change attribute on close. Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 99a68bd9c1782..6307d8de103d0 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -761,11 +761,13 @@ EXPORT_SYMBOL_GPL(nfs_put_lock_context); * @ctx: pointer to context * @is_sync: is this a synchronous close * - * always ensure that the attributes are up to date if we're mounted - * with close-to-open semantics + * Ensure that the attributes are up to date if we're mounted + * with close-to-open semantics and we have cached data that will + * need to be revalidated on open. */ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) { + struct nfs_inode *nfsi; struct inode *inode; struct nfs_server *server; @@ -774,7 +776,12 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync) if (!is_sync) return; inode = d_inode(ctx->dentry); - if (!list_empty(&NFS_I(inode)->open_files)) + nfsi = NFS_I(inode); + if (inode->i_mapping->nrpages == 0) + return; + if (nfsi->cache_validity & NFS_INO_INVALID_DATA) + return; + if (!list_empty(&nfsi->open_files)) return; server = NFS_SERVER(inode); if (server->flags & NFS_MOUNT_NOCTO) -- GitLab From 4eae50143bcbfda819c650b7ed6739f3b6338ffc Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 4 Sep 2015 15:17:53 -0400 Subject: [PATCH 6315/7006] Revert "NFS: Make close(2) asynchronous when closing NFS O_DIRECT files" This reverts commit f895c53f8ace3c3e49ebf9def90e63fc6d46d2bf. This commit causes a NFSv4 regression in that close()+unlink() can end up failing. The reason is that we no longer have a guarantee that the CLOSE has completed on the server, meaning that the subsequent call to REMOVE may fail with NFS4ERR_FILE_OPEN if the server implements Windows unlink() semantics. Reported-by: Cc: Chuck Lever Signed-off-by: Trond Myklebust --- fs/nfs/inode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 6307d8de103d0..326d9e10d8337 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -853,6 +853,11 @@ void put_nfs_open_context(struct nfs_open_context *ctx) } EXPORT_SYMBOL_GPL(put_nfs_open_context); +static void put_nfs_open_context_sync(struct nfs_open_context *ctx) +{ + __put_nfs_open_context(ctx, 1); +} + /* * Ensure that mmap has a recent RPC credential for use when writing out * shared pages @@ -908,7 +913,7 @@ void nfs_file_clear_open_context(struct file *filp) spin_lock(&inode->i_lock); list_move_tail(&ctx->list, &NFS_I(inode)->open_files); spin_unlock(&inode->i_lock); - __put_nfs_open_context(ctx, filp->f_flags & O_DIRECT ? 0 : 1); + put_nfs_open_context_sync(ctx); } } -- GitLab From 6a4756f6951f97a9a601ba24632c5906750ef00d Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Fri, 1 May 2015 15:58:19 +0200 Subject: [PATCH 6316/7006] cris: arch-v32: gpio: Use kzalloc instead of kmalloc/memset Turn a kmalloc/memset into an equivalent kzalloc. Doing so also move the zero'ing of the memory outside of a mutex. Signed-off-by: Christophe Jaillet Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/mach-fs/gpio.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/arch/cris/arch-v32/drivers/mach-fs/gpio.c b/arch/cris/arch-v32/drivers/mach-fs/gpio.c index 009f4ee1bd095..72968fbf814b8 100644 --- a/arch/cris/arch-v32/drivers/mach-fs/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-fs/gpio.c @@ -425,12 +425,11 @@ gpio_open(struct inode *inode, struct file *filp) if (p > GPIO_MINOR_LAST) return -EINVAL; - priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL); + priv = kzalloc(sizeof(struct gpio_private), GFP_KERNEL); if (!priv) return -ENOMEM; mutex_lock(&gpio_mutex); - memset(priv, 0, sizeof(*priv)); priv->minor = p; -- GitLab From 98a725a57a8e92bfbe962a8c69975ce0f9ff11fe Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 14 May 2015 14:36:55 +0200 Subject: [PATCH 6317/7006] CRISv32: add unreachable() to BUG() Add an unreachable() in the BUG() implementations, to get rid of several warnings similar to the one below: kernel/sched/core.c: In function 'pick_next_task': kernel/sched/core.c:2690:1: warning: control reaches end of non-void function [-Wreturn-type] Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/arch-v32/arch/bug.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/cris/include/arch-v32/arch/bug.h b/arch/cris/include/arch-v32/arch/bug.h index 0f211e1352484..fb59faaaae0af 100644 --- a/arch/cris/include/arch-v32/arch/bug.h +++ b/arch/cris/include/arch-v32/arch/bug.h @@ -10,6 +10,7 @@ * All other stuff is done out-of-band with exception handlers. */ #define BUG() \ +do { \ __asm__ __volatile__ ("0: break 14\n\t" \ ".section .fixup,\"ax\"\n" \ "1:\n\t" \ @@ -21,9 +22,15 @@ ".section __ex_table,\"a\"\n\t" \ ".dword 0b, 1b\n\t" \ ".previous\n\t" \ - : : "ri" (__FILE__), "i" (__LINE__)) + : : "ri" (__FILE__), "i" (__LINE__)); \ + unreachable(); \ +} while (0) #else -#define BUG() __asm__ __volatile__ ("break 14\n\t") +#define BUG() \ +do { \ + __asm__ __volatile__ ("break 14\n\t"); \ + unreachable(); \ +} while (0) #endif #define HAVE_ARCH_BUG -- GitLab From f59625a8f770741d590da09be4f0fcfc75b31e46 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 14 May 2015 14:36:56 +0200 Subject: [PATCH 6318/7006] CRISv32: allow CONFIG_DEBUG_BUGVERBOSE Support for verbose BUG reporting already exists, but the HAVE flag that allows the option to be enabled is missing. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 0314e325a6693..b202b8277a266 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -58,6 +58,7 @@ config CRIS select CLKSRC_MMIO if ETRAX_ARCH_V32 select GENERIC_CLOCKEVENTS if ETRAX_ARCH_V32 select GENERIC_SCHED_CLOCK if ETRAX_ARCH_V32 + select HAVE_DEBUG_BUGVERBOSE if ETRAX_ARCH_V32 config HZ int -- GitLab From ee59843cd2b4331db49671c7f045ee2ff9d535b6 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Wed, 6 May 2015 21:48:12 +0800 Subject: [PATCH 6319/7006] CRIS: Wire up missing syscalls The related warnings: CALL scripts/checksyscalls.sh :1229:2: warning: #warning syscall sched_setattr not implemented [-Wcpp] :1232:2: warning: #warning syscall sched_getattr not implemented [-Wcpp] :1235:2: warning: #warning syscall renameat2 not implemented [-Wcpp] :1238:2: warning: #warning syscall seccomp not implemented [-Wcpp] :1241:2: warning: #warning syscall getrandom not implemented [-Wcpp] :1244:2: warning: #warning syscall memfd_create not implemented [-Wcpp] :1247:2: warning: #warning syscall bpf not implemented [-Wcpp] :1250:2: warning: #warning syscall execveat not implemented [-Wcpp] Signed-off-by: Chen Gang Signed-off-by: Jesper Nilsson --- arch/cris/arch-v10/kernel/entry.S | 8 ++++++++ arch/cris/arch-v32/kernel/entry.S | 8 ++++++++ arch/cris/include/asm/unistd.h | 2 +- arch/cris/include/uapi/asm/unistd.h | 8 ++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/arch/cris/arch-v10/kernel/entry.S b/arch/cris/arch-v10/kernel/entry.S index 81570fcd04128..b5622521dad50 100644 --- a/arch/cris/arch-v10/kernel/entry.S +++ b/arch/cris/arch-v10/kernel/entry.S @@ -955,6 +955,14 @@ sys_call_table: .long sys_process_vm_writev .long sys_kcmp /* 350 */ .long sys_finit_module + .long sys_sched_setattr + .long sys_sched_getattr + .long sys_renameat2 + .long sys_seccomp /* 355 */ + .long sys_getrandom + .long sys_memfd_create + .long sys_bpf + .long sys_execveat /* * NOTE!! This doesn't have to be exact - we just have diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index 026a0b21b8f0f..1c5595a6ceb51 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -875,6 +875,14 @@ sys_call_table: .long sys_process_vm_writev .long sys_kcmp /* 350 */ .long sys_finit_module + .long sys_sched_setattr + .long sys_sched_getattr + .long sys_renameat2 + .long sys_seccomp /* 355 */ + .long sys_getrandom + .long sys_memfd_create + .long sys_bpf + .long sys_execveat /* * NOTE!! This doesn't have to be exact - we just have diff --git a/arch/cris/include/asm/unistd.h b/arch/cris/include/asm/unistd.h index 0f40fed1ba258..9c23535821c01 100644 --- a/arch/cris/include/asm/unistd.h +++ b/arch/cris/include/asm/unistd.h @@ -4,7 +4,7 @@ #include -#define NR_syscalls 360 +#define NR_syscalls 365 #include diff --git a/arch/cris/include/uapi/asm/unistd.h b/arch/cris/include/uapi/asm/unistd.h index f3287face443b..062b648b27e1b 100644 --- a/arch/cris/include/uapi/asm/unistd.h +++ b/arch/cris/include/uapi/asm/unistd.h @@ -356,5 +356,13 @@ #define __NR_process_vm_writev 349 #define __NR_kcmp 350 #define __NR_finit_module 351 +#define __NR_sched_setattr 352 +#define __NR_sched_getattr 353 +#define __NR_renameat2 354 +#define __NR_seccomp 355 +#define __NR_getrandom 356 +#define __NR_memfd_create 357 +#define __NR_bpf 358 +#define __NR_execveat 359 #endif /* _UAPI_ASM_CRIS_UNISTD_H_ */ -- GitLab From 94230178678cb7e0f82ff2c161ac84742f79a2e7 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 3 Jun 2015 12:25:51 +0200 Subject: [PATCH 6320/7006] CRISv32: ETRAX FS: Squash warnings in pinmux driver Squash the followng warnings arch/cris/arch-v32/mach-fs/pinmux.c: In function 'crisv32_pinmux_alloc_fixed': arch/cris/arch-v32/mach-fs/pinmux.c:104:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] arch/cris/arch-v32/mach-fs/pinmux.c: In function 'crisv32_pinmux_dealloc_fixed': arch/cris/arch-v32/mach-fs/pinmux.c:238:2: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] arch/cris/arch-v32/mach-fs/pinmux.c: In function '__crisv32_pinmux_alloc': arch/cris/arch-v32/mach-fs/pinmux.c:49:1: warning: control reaches end of non-void function [-Wreturn-type] Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/mach-fs/pinmux.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c index 05a04708b8eb4..d8a3a3c439dd0 100644 --- a/arch/cris/arch-v32/mach-fs/pinmux.c +++ b/arch/cris/arch-v32/mach-fs/pinmux.c @@ -46,6 +46,8 @@ static int __crisv32_pinmux_alloc(int port, int first_pin, int last_pin, pins[port][i] = mode; crisv32_pinmux_set(port); + + return 0; } static int crisv32_pinmux_init(void) @@ -93,6 +95,7 @@ int crisv32_pinmux_alloc_fixed(enum fixed_function function) int ret = -EINVAL; char saved[sizeof pins]; unsigned long flags; + reg_pinmux_rw_hwprot hwprot; spin_lock_irqsave(&pinmux_lock, flags); @@ -101,7 +104,7 @@ int crisv32_pinmux_alloc_fixed(enum fixed_function function) crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ - reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); + hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); switch (function) { case pinmux_ser1: @@ -227,6 +230,7 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function) int ret = -EINVAL; char saved[sizeof pins]; unsigned long flags; + reg_pinmux_rw_hwprot hwprot; spin_lock_irqsave(&pinmux_lock, flags); @@ -235,7 +239,7 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function) crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */ - reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); + hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); switch (function) { case pinmux_ser1: -- GitLab From 939b83fb03f275016cd72a0f81f49bf8e63c2a14 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 3 Jun 2015 12:42:01 +0200 Subject: [PATCH 6321/7006] CRISv32: Add GPIO driver to the default configs Fix a number of small issues visible when GPIO is enabled: - Correct missing default for !ETRAXFS in Kconfig - Remove information on number of bits for some Kconfigs related to the GPIO, they are different in ETRAX FS and ARTPEC-3 - Fix compile warning in ARTPEC-3 GPIO driver Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/Kconfig | 16 ++++++++-------- arch/cris/arch-v32/drivers/mach-a3/gpio.c | 4 ++-- arch/cris/configs/artpec_3_defconfig | 5 +---- arch/cris/configs/etraxfs_defconfig | 1 + 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index 4fc16b44fff26..e6c523cc40bc8 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -202,7 +202,7 @@ config ETRAX_PA_CHANGEABLE_DIR default "0x00" if ETRAXFS default "0x00000000" if !ETRAXFS help - This is a bitmask (8 bits) with information of what bits in PA that a + This is a bitmask with information of what bits in PA that a user can change direction on using ioctl's. Bit set = changeable. You probably want 0 here, but it depends on your hardware. @@ -213,7 +213,7 @@ config ETRAX_PA_CHANGEABLE_BITS default "0x00" if ETRAXFS default "0x00000000" if !ETRAXFS help - This is a bitmask (8 bits) with information of what bits in PA + This is a bitmask with information of what bits in PA that a user can change the value on using ioctl's. Bit set = changeable. @@ -223,7 +223,7 @@ config ETRAX_PB_CHANGEABLE_DIR default "0x00000" if ETRAXFS default "0x00000000" if !ETRAXFS help - This is a bitmask (18 bits) with information of what bits in PB + This is a bitmask with information of what bits in PB that a user can change direction on using ioctl's. Bit set = changeable. You probably want 0 here, but it depends on your hardware. @@ -234,7 +234,7 @@ config ETRAX_PB_CHANGEABLE_BITS default "0x00000" if ETRAXFS default "0x00000000" if !ETRAXFS help - This is a bitmask (18 bits) with information of what bits in PB + This is a bitmask with information of what bits in PB that a user can change the value on using ioctl's. Bit set = changeable. @@ -244,7 +244,7 @@ config ETRAX_PC_CHANGEABLE_DIR default "0x00000" if ETRAXFS default "0x00000000" if !ETRAXFS help - This is a bitmask (18 bits) with information of what bits in PC + This is a bitmask with information of what bits in PC that a user can change direction on using ioctl's. Bit set = changeable. You probably want 0 here, but it depends on your hardware. @@ -253,9 +253,9 @@ config ETRAX_PC_CHANGEABLE_BITS hex "PC user changeable bits mask" depends on ETRAX_GPIO default "0x00000" if ETRAXFS - default "0x00000000" if ETRAXFS + default "0x00000000" if !ETRAXFS help - This is a bitmask (18 bits) with information of what bits in PC + This is a bitmask with information of what bits in PC that a user can change the value on using ioctl's. Bit set = changeable. @@ -264,7 +264,7 @@ config ETRAX_PD_CHANGEABLE_DIR depends on ETRAX_GPIO && ETRAXFS default "0x00000" help - This is a bitmask (18 bits) with information of what bits in PD + This is a bitmask with information of what bits in PD that a user can change direction on using ioctl's. Bit set = changeable. You probably want 0x00000 here, but it depends on your hardware. diff --git a/arch/cris/arch-v32/drivers/mach-a3/gpio.c b/arch/cris/arch-v32/drivers/mach-a3/gpio.c index 74f9fe80940c7..c92e1da3684db 100644 --- a/arch/cris/arch-v32/drivers/mach-a3/gpio.c +++ b/arch/cris/arch-v32/drivers/mach-a3/gpio.c @@ -957,7 +957,7 @@ static void __init virtual_gpio_init(void) static int __init gpio_init(void) { - int res; + int res, res2; printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 " "Axis Communications AB\n"); @@ -977,7 +977,7 @@ static int __init gpio_init(void) CRIS_LED_DISK_READ(0); CRIS_LED_DISK_WRITE(0); - int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, + res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, IRQF_SHARED, "gpio", &alarmlist); if (res2) { printk(KERN_ERR "err: irq for gpio\n"); diff --git a/arch/cris/configs/artpec_3_defconfig b/arch/cris/configs/artpec_3_defconfig index 71854d41c5a02..70e497e0b03ee 100644 --- a/arch/cris/configs/artpec_3_defconfig +++ b/arch/cris/configs/artpec_3_defconfig @@ -12,10 +12,6 @@ CONFIG_ETRAX_FAST_TIMER=y CONFIG_CRIS_MACH_ARTPEC3=y CONFIG_ETRAX_DRAM_SIZE=32 CONFIG_ETRAX_FLASH1_SIZE=4 -CONFIG_ETRAX_DEF_GIO_PA_OE=1c -CONFIG_ETRAX_DEF_GIO_PA_OUT=00 -CONFIG_ETRAX_DEF_GIO_PB_OE=00000 -CONFIG_ETRAX_DEF_GIO_PB_OUT=00000 CONFIG_NET=y CONFIG_PACKET=y CONFIG_UNIX=y @@ -42,3 +38,4 @@ CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y +CONFIG_ETRAX_GPIO=y diff --git a/arch/cris/configs/etraxfs_defconfig b/arch/cris/configs/etraxfs_defconfig index 87c7227fecb2d..91232680d6c86 100644 --- a/arch/cris/configs/etraxfs_defconfig +++ b/arch/cris/configs/etraxfs_defconfig @@ -38,3 +38,4 @@ CONFIG_JFFS2_FS=y CONFIG_CRAMFS=y CONFIG_NFS_FS=y CONFIG_NFS_V3=y +CONFIG_ETRAX_GPIO=y -- GitLab From 4b86715748da506b176b5ec50c041b335c9d1769 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 3 Jun 2015 13:04:23 +0200 Subject: [PATCH 6322/7006] CRISv32: Squash compile warnings for axisflashmap Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/axisflashmap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/arch/cris/arch-v32/drivers/axisflashmap.c b/arch/cris/arch-v32/drivers/axisflashmap.c index 28dd77144e8fe..5387424683ccc 100644 --- a/arch/cris/arch-v32/drivers/axisflashmap.c +++ b/arch/cris/arch-v32/drivers/axisflashmap.c @@ -313,6 +313,7 @@ static int __init init_axis_flash(void) size_t len; int ram_rootfs_partition = -1; /* -1 => no RAM rootfs partition */ int part; + struct mtd_partition *partition; /* We need a root fs. If it resides in RAM, we need to use an * MTDRAM device, so it must be enabled in the kernel config, @@ -329,7 +330,7 @@ static int __init init_axis_flash(void) main_mtd = flash_probe(); if (main_mtd) - printk(KERN_INFO "%s: 0x%08x bytes of NOR flash memory.\n", + printk(KERN_INFO "%s: 0x%08llx bytes of NOR flash memory.\n", main_mtd->name, main_mtd->size); #ifdef CONFIG_ETRAX_NANDFLASH @@ -388,10 +389,10 @@ static int __init init_axis_flash(void) #endif if (main_mtd) { + loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR; main_mtd->owner = THIS_MODULE; axisflash_mtd = main_mtd; - loff_t ptable_sector = CONFIG_ETRAX_PTABLE_SECTOR; /* First partition (rescue) is always set to the default. */ pidx++; @@ -517,7 +518,7 @@ static int __init init_axis_flash(void) /* Decide whether to use default partition table. */ /* Only use default table if we actually have a device (main_mtd) */ - struct mtd_partition *partition = &axis_partitions[0]; + partition = &axis_partitions[0]; if (main_mtd && !ptable_ok) { memcpy(axis_partitions, axis_default_partitions, sizeof(axis_default_partitions)); @@ -580,7 +581,7 @@ static int __init init_axis_flash(void) printk(KERN_INFO "axisflashmap: Adding RAM partition " "for rootfs image.\n"); err = mtdram_init_device(mtd_ram, - (void *)partition[part].offset, + (void *)(u_int32_t)partition[part].offset, partition[part].size, partition[part].name); if (err) -- GitLab From 835e4177284e1574033dea47d4bb8e55c21b6345 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 27 Mar 2015 22:32:27 +0100 Subject: [PATCH 6323/7006] CRIS: UAPI: fix ptrace.h The exported ptrace.h header on CRIS references an "arch" directory which does not exist. Fix this by having the variants in the same directory and including them conditionally, similar to other architectures. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/signal.c | 1 - arch/cris/include/arch-v32/arch/irqflags.h | 2 +- arch/cris/include/uapi/asm/Kbuild | 2 ++ arch/cris/include/uapi/asm/ptrace.h | 6 +++++- .../{arch-v10/arch/ptrace.h => uapi/asm/ptrace_v10.h} | 0 .../{arch-v32/arch/ptrace.h => uapi/asm/ptrace_v32.h} | 0 6 files changed, 8 insertions(+), 3 deletions(-) rename arch/cris/include/{arch-v10/arch/ptrace.h => uapi/asm/ptrace_v10.h} (100%) rename arch/cris/include/{arch-v32/arch/ptrace.h => uapi/asm/ptrace_v32.h} (100%) diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 3a36ae6b79d5a..150d1d76c29d2 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -19,7 +19,6 @@ #include #include #include -#include #include extern unsigned long cris_signal_return_page; diff --git a/arch/cris/include/arch-v32/arch/irqflags.h b/arch/cris/include/arch-v32/arch/irqflags.h index 041851f8ec6f9..5f6fddf995099 100644 --- a/arch/cris/include/arch-v32/arch/irqflags.h +++ b/arch/cris/include/arch-v32/arch/irqflags.h @@ -2,7 +2,7 @@ #define __ASM_CRIS_ARCH_IRQFLAGS_H #include -#include +#include static inline unsigned long arch_local_save_flags(void) { diff --git a/arch/cris/include/uapi/asm/Kbuild b/arch/cris/include/uapi/asm/Kbuild index 01f66b8f15e50..8443dc81f19b2 100644 --- a/arch/cris/include/uapi/asm/Kbuild +++ b/arch/cris/include/uapi/asm/Kbuild @@ -19,6 +19,8 @@ header-y += param.h header-y += poll.h header-y += posix_types.h header-y += ptrace.h +header-y += ptrace_v10.h +header-y += ptrace_v32.h header-y += resource.h header-y += rs485.h header-y += sembuf.h diff --git a/arch/cris/include/uapi/asm/ptrace.h b/arch/cris/include/uapi/asm/ptrace.h index c689c9bbbe503..bd8946f83ed3a 100644 --- a/arch/cris/include/uapi/asm/ptrace.h +++ b/arch/cris/include/uapi/asm/ptrace.h @@ -1 +1,5 @@ -#include +#ifdef __arch_v32 +#include +#else +#include +#endif diff --git a/arch/cris/include/arch-v10/arch/ptrace.h b/arch/cris/include/uapi/asm/ptrace_v10.h similarity index 100% rename from arch/cris/include/arch-v10/arch/ptrace.h rename to arch/cris/include/uapi/asm/ptrace_v10.h diff --git a/arch/cris/include/arch-v32/arch/ptrace.h b/arch/cris/include/uapi/asm/ptrace_v32.h similarity index 100% rename from arch/cris/include/arch-v32/arch/ptrace.h rename to arch/cris/include/uapi/asm/ptrace_v32.h -- GitLab From 3a79a075375cebb672ddaea7896378afa0203e87 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 14 May 2015 17:00:58 +0200 Subject: [PATCH 6324/7006] CRIS: don't make asm/elf.h depend on asm/user.h We're going to export asm/elf.h; remove its dependencies on the non-exported asm/user.h and the unused asm/system.h include. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/arch-v10/arch/elf.h | 5 +++-- arch/cris/include/arch-v32/arch/elf.h | 5 +++-- arch/cris/include/asm/elf.h | 5 +---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/arch/cris/include/arch-v10/arch/elf.h b/arch/cris/include/arch-v10/arch/elf.h index 1eb638aeddb44..3ea65cef529db 100644 --- a/arch/cris/include/arch-v10/arch/elf.h +++ b/arch/cris/include/arch-v10/arch/elf.h @@ -1,10 +1,11 @@ #ifndef __ASMCRIS_ARCH_ELF_H #define __ASMCRIS_ARCH_ELF_H -#include - #define ELF_MACH EF_CRIS_VARIANT_ANY_V0_V10 +/* Matches struct user_regs_struct */ +#define ELF_NGREG 35 + /* * This is used to ensure we don't load something for the wrong architecture. */ diff --git a/arch/cris/include/arch-v32/arch/elf.h b/arch/cris/include/arch-v32/arch/elf.h index c46d582911668..f09fe49005c01 100644 --- a/arch/cris/include/arch-v32/arch/elf.h +++ b/arch/cris/include/arch-v32/arch/elf.h @@ -1,10 +1,11 @@ #ifndef _ASM_CRIS_ELF_H #define _ASM_CRIS_ELF_H -#include - #define ELF_CORE_EFLAGS EF_CRIS_VARIANT_V32 +/* Matches struct user_regs_struct */ +#define ELF_NGREG 32 + /* * This is used to ensure we don't load something for the wrong architecture. */ diff --git a/arch/cris/include/asm/elf.h b/arch/cris/include/asm/elf.h index c2a394ff55ff3..986adbabb581e 100644 --- a/arch/cris/include/asm/elf.h +++ b/arch/cris/include/asm/elf.h @@ -5,7 +5,7 @@ * ELF register definitions.. */ -#include +#include #define R_CRIS_NONE 0 #define R_CRIS_8 1 @@ -32,7 +32,6 @@ typedef unsigned long elf_greg_t; /* Note that NGREG is defined to ELF_NGREG in include/linux/elfcore.h, and is thus exposed to user-space. */ -#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) typedef elf_greg_t elf_gregset_t[ELF_NGREG]; /* A placeholder; CRIS does not have any fp regs. */ @@ -45,8 +44,6 @@ typedef unsigned long elf_fpregset_t; #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_CRIS -#include - /* The master for these definitions is {binutils}/include/elf/cris.h: */ /* User symbols in this file have a leading underscore. */ #define EF_CRIS_UNDERSCORE 0x00000001 -- GitLab From 2493d3e28a22087116158249d79410fd355d1e83 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 27 Mar 2015 22:35:11 +0100 Subject: [PATCH 6325/7006] CRIS: UAPI: fix elf.h export CRIS userspace (uClibc for one) expects asm/elf.h to be exported but this header appears to have gone missing at some point. Move it to uapi/ and export it. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/uapi/asm/Kbuild | 3 +++ arch/cris/include/{ => uapi}/asm/elf.h | 6 +++++- .../include/{arch-v10/arch/elf.h => uapi/asm/elf_v10.h} | 0 .../include/{arch-v32/arch/elf.h => uapi/asm/elf_v32.h} | 0 4 files changed, 8 insertions(+), 1 deletion(-) rename arch/cris/include/{ => uapi}/asm/elf.h (97%) rename arch/cris/include/{arch-v10/arch/elf.h => uapi/asm/elf_v10.h} (100%) rename arch/cris/include/{arch-v32/arch/elf.h => uapi/asm/elf_v32.h} (100%) diff --git a/arch/cris/include/uapi/asm/Kbuild b/arch/cris/include/uapi/asm/Kbuild index 8443dc81f19b2..d5564a0ae66ad 100644 --- a/arch/cris/include/uapi/asm/Kbuild +++ b/arch/cris/include/uapi/asm/Kbuild @@ -6,6 +6,9 @@ header-y += ../arch-v32/arch/ header-y += auxvec.h header-y += bitsperlong.h header-y += byteorder.h +header-y += elf.h +header-y += elf_v10.h +header-y += elf_v32.h header-y += errno.h header-y += ethernet.h header-y += etraxgpio.h diff --git a/arch/cris/include/asm/elf.h b/arch/cris/include/uapi/asm/elf.h similarity index 97% rename from arch/cris/include/asm/elf.h rename to arch/cris/include/uapi/asm/elf.h index 986adbabb581e..a5df05bfee66c 100644 --- a/arch/cris/include/asm/elf.h +++ b/arch/cris/include/uapi/asm/elf.h @@ -5,7 +5,11 @@ * ELF register definitions.. */ -#include +#ifdef __arch_v32 +#include +#else +#include +#endif #define R_CRIS_NONE 0 #define R_CRIS_8 1 diff --git a/arch/cris/include/arch-v10/arch/elf.h b/arch/cris/include/uapi/asm/elf_v10.h similarity index 100% rename from arch/cris/include/arch-v10/arch/elf.h rename to arch/cris/include/uapi/asm/elf_v10.h diff --git a/arch/cris/include/arch-v32/arch/elf.h b/arch/cris/include/uapi/asm/elf_v32.h similarity index 100% rename from arch/cris/include/arch-v32/arch/elf.h rename to arch/cris/include/uapi/asm/elf_v32.h -- GitLab From 0c02fa2f4ef47334387aeb3aef21ccdab6513459 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:31:10 +0100 Subject: [PATCH 6326/7006] CRIS: UAPI: use generic headers via Kbuild Use Kbuild magic to include the generic headers. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 10 ++++++++++ arch/cris/include/uapi/asm/bitsperlong.h | 1 - arch/cris/include/uapi/asm/errno.h | 6 ------ arch/cris/include/uapi/asm/fcntl.h | 1 - arch/cris/include/uapi/asm/ioctl.h | 1 - arch/cris/include/uapi/asm/ipcbuf.h | 1 - arch/cris/include/uapi/asm/kvm_para.h | 1 - arch/cris/include/uapi/asm/mman.h | 1 - arch/cris/include/uapi/asm/poll.h | 1 - arch/cris/include/uapi/asm/resource.h | 6 ------ arch/cris/include/uapi/asm/siginfo.h | 6 ------ arch/cris/include/uapi/asm/statfs.h | 6 ------ 12 files changed, 10 insertions(+), 31 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/bitsperlong.h delete mode 100644 arch/cris/include/uapi/asm/errno.h delete mode 100644 arch/cris/include/uapi/asm/fcntl.h delete mode 100644 arch/cris/include/uapi/asm/ioctl.h delete mode 100644 arch/cris/include/uapi/asm/ipcbuf.h delete mode 100644 arch/cris/include/uapi/asm/kvm_para.h delete mode 100644 arch/cris/include/uapi/asm/mman.h delete mode 100644 arch/cris/include/uapi/asm/poll.h delete mode 100644 arch/cris/include/uapi/asm/resource.h delete mode 100644 arch/cris/include/uapi/asm/siginfo.h delete mode 100644 arch/cris/include/uapi/asm/statfs.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index ad2244f35bca0..1e19a4f06565a 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -1,14 +1,19 @@ generic-y += atomic.h generic-y += barrier.h +generic-y += bitsperlong.h generic-y += clkdev.h generic-y += cmpxchg.h generic-y += cputime.h generic-y += device.h generic-y += div64.h +generic-y += errno.h generic-y += exec.h generic-y += emergency-restart.h +generic-y += fcntl.h generic-y += futex.h generic-y += hardirq.h +generic-y += ioctl.h +generic-y += ipcbuf.h generic-y += irq_regs.h generic-y += irq_work.h generic-y += kdebug.h @@ -19,10 +24,15 @@ generic-y += local.h generic-y += local64.h generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h +generic-y += mman.h generic-y += module.h generic-y += percpu.h +generic-y += poll.h generic-y += preempt.h +generic-y += resource.h generic-y += sections.h +generic-y += siginfo.h +generic-y += statfs.h generic-y += topology.h generic-y += trace_clock.h generic-y += vga.h diff --git a/arch/cris/include/uapi/asm/bitsperlong.h b/arch/cris/include/uapi/asm/bitsperlong.h deleted file mode 100644 index 6dc0bb0c13b29..0000000000000 --- a/arch/cris/include/uapi/asm/bitsperlong.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/errno.h b/arch/cris/include/uapi/asm/errno.h deleted file mode 100644 index 2bf5eb5fa773c..0000000000000 --- a/arch/cris/include/uapi/asm/errno.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_ERRNO_H -#define _CRIS_ERRNO_H - -#include - -#endif diff --git a/arch/cris/include/uapi/asm/fcntl.h b/arch/cris/include/uapi/asm/fcntl.h deleted file mode 100644 index 46ab12db57397..0000000000000 --- a/arch/cris/include/uapi/asm/fcntl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/ioctl.h b/arch/cris/include/uapi/asm/ioctl.h deleted file mode 100644 index b279fe06dfe5b..0000000000000 --- a/arch/cris/include/uapi/asm/ioctl.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/ipcbuf.h b/arch/cris/include/uapi/asm/ipcbuf.h deleted file mode 100644 index 84c7e51cb6d0b..0000000000000 --- a/arch/cris/include/uapi/asm/ipcbuf.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/kvm_para.h b/arch/cris/include/uapi/asm/kvm_para.h deleted file mode 100644 index 14fab8f0b9576..0000000000000 --- a/arch/cris/include/uapi/asm/kvm_para.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/mman.h b/arch/cris/include/uapi/asm/mman.h deleted file mode 100644 index 8eebf89f5ab17..0000000000000 --- a/arch/cris/include/uapi/asm/mman.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/poll.h b/arch/cris/include/uapi/asm/poll.h deleted file mode 100644 index c98509d3149e6..0000000000000 --- a/arch/cris/include/uapi/asm/poll.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/arch/cris/include/uapi/asm/resource.h b/arch/cris/include/uapi/asm/resource.h deleted file mode 100644 index b5d29448de4eb..0000000000000 --- a/arch/cris/include/uapi/asm/resource.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_RESOURCE_H -#define _CRIS_RESOURCE_H - -#include - -#endif diff --git a/arch/cris/include/uapi/asm/siginfo.h b/arch/cris/include/uapi/asm/siginfo.h deleted file mode 100644 index c1cd6d16928b4..0000000000000 --- a/arch/cris/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_SIGINFO_H -#define _CRIS_SIGINFO_H - -#include - -#endif diff --git a/arch/cris/include/uapi/asm/statfs.h b/arch/cris/include/uapi/asm/statfs.h deleted file mode 100644 index fdaf921844bc2..0000000000000 --- a/arch/cris/include/uapi/asm/statfs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _CRIS_STATFS_H -#define _CRIS_STATFS_H - -#include - -#endif -- GitLab From 889d74a4d40f60427d0482bc271bfc5660a1157b Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 22:59:42 +0100 Subject: [PATCH 6327/7006] CRIS: UAPI: use generic auxvec.h CRIS's auxvec.h is empty just like the asm-generic version. Effective diff: -#ifndef __ASMCRIS_AUXVEC_H -#define __ASMCRIS_AUXVEC_H +#ifndef __ASM_GENERIC_AUXVEC_H +#define __ASM_GENERIC_AUXVEC_H + Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/uapi/asm/auxvec.h | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/auxvec.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 1e19a4f06565a..1ee91be2c915d 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -1,4 +1,5 @@ generic-y += atomic.h +generic-y += auxvec.h generic-y += barrier.h generic-y += bitsperlong.h generic-y += clkdev.h diff --git a/arch/cris/include/uapi/asm/auxvec.h b/arch/cris/include/uapi/asm/auxvec.h deleted file mode 100644 index cb30b01bf19f2..0000000000000 --- a/arch/cris/include/uapi/asm/auxvec.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef __ASMCRIS_AUXVEC_H -#define __ASMCRIS_AUXVEC_H - -#endif -- GitLab From c823b970b632a86e4f01f3eae9c0860350b70c3c Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:21:25 +0100 Subject: [PATCH 6328/7006] CRIS: UAPI: use generic sockios.h CRIS' sockios.h is equivalent to the asm-generic version. Effective diff: -#ifndef __ARCH_CRIS_SOCKIOS__ -#define __ARCH_CRIS_SOCKIOS__ +#ifndef __ASM_GENERIC_SOCKIOS_H +#define __ASM_GENERIC_SOCKIOS_H Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/uapi/asm/sockios.h | 13 ------------- 2 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/sockios.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 1ee91be2c915d..14095b9531b8e 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -33,6 +33,7 @@ generic-y += preempt.h generic-y += resource.h generic-y += sections.h generic-y += siginfo.h +generic-y += sockios.h generic-y += statfs.h generic-y += topology.h generic-y += trace_clock.h diff --git a/arch/cris/include/uapi/asm/sockios.h b/arch/cris/include/uapi/asm/sockios.h deleted file mode 100644 index cfe7bfecf5999..0000000000000 --- a/arch/cris/include/uapi/asm/sockios.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ARCH_CRIS_SOCKIOS__ -#define __ARCH_CRIS_SOCKIOS__ - -/* Socket-level I/O control calls. */ -#define FIOSETOWN 0x8901 -#define SIOCSPGRP 0x8902 -#define FIOGETOWN 0x8903 -#define SIOCGPGRP 0x8904 -#define SIOCATMARK 0x8905 -#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ -#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ - -#endif -- GitLab From 53789d25a0603e5c836e460c758867d2071eb135 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:43:31 +0100 Subject: [PATCH 6329/7006] CRIS: UAPI: use generic sembuf.h CRIS's sembuf.h is equivalent to the asm-generic version. Effective diff: -#ifndef _CRIS_SEMBUF_H -#define _CRIS_SEMBUF_H +#ifndef __ASM_GENERIC_SEMBUF_H +#define __ASM_GENERIC_SEMBUF_H +#include struct semid64_ds { struct ipc64_perm sem_perm; __kernel_time_t sem_otime; +#if __BITS_PER_LONG != 64 unsigned long __unused1; +#endif __kernel_time_t sem_ctime; +#if __BITS_PER_LONG != 64 unsigned long __unused2; +#endif unsigned long sem_nsems; unsigned long __unused3; unsigned long __unused4; Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/uapi/asm/sembuf.h | 25 ------------------------- 2 files changed, 1 insertion(+), 25 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/sembuf.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 14095b9531b8e..2dcd67023f27b 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -32,6 +32,7 @@ generic-y += poll.h generic-y += preempt.h generic-y += resource.h generic-y += sections.h +generic-y += sembuf.h generic-y += siginfo.h generic-y += sockios.h generic-y += statfs.h diff --git a/arch/cris/include/uapi/asm/sembuf.h b/arch/cris/include/uapi/asm/sembuf.h deleted file mode 100644 index 7fed9843796dd..0000000000000 --- a/arch/cris/include/uapi/asm/sembuf.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _CRIS_SEMBUF_H -#define _CRIS_SEMBUF_H - -/* - * The semid64_ds structure for CRIS architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct semid64_ds { - struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ - __kernel_time_t sem_otime; /* last semop time */ - unsigned long __unused1; - __kernel_time_t sem_ctime; /* last change time */ - unsigned long __unused2; - unsigned long sem_nsems; /* no. of semaphores in array */ - unsigned long __unused3; - unsigned long __unused4; -}; - -#endif /* _CRIS_SEMBUF_H */ -- GitLab From 45266922510fcd1e55df483f41be8debd5df9de8 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:47:37 +0100 Subject: [PATCH 6330/7006] CRIS: UAPI: use generic socket.h CRIS' socket.h is equivalent to the asm-generic version. Effective diff: -#ifndef _ASM_SOCKET_H -#define _ASM_SOCKET_H - - +#ifndef __ASM_GENERIC_SOCKET_H +#define __ASM_GENERIC_SOCKET_H #include #define SO_LINGER 13 #define SO_BSDCOMPAT 14 #define SO_REUSEPORT 15 +#ifndef SO_PASSCRED #define SO_PASSCRED 16 #define SO_PEERCRED 17 #define SO_RCVLOWAT 18 #define SO_SNDLOWAT 19 #define SO_RCVTIMEO 20 #define SO_SNDTIMEO 21 +#endif #define SO_SECURITY_AUTHENTICATION 22 Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/uapi/asm/socket.h | 92 ----------------------------- 2 files changed, 1 insertion(+), 92 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/socket.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 2dcd67023f27b..30ed4e26ad81c 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -34,6 +34,7 @@ generic-y += resource.h generic-y += sections.h generic-y += sembuf.h generic-y += siginfo.h +generic-y += socket.h generic-y += sockios.h generic-y += statfs.h generic-y += topology.h diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h deleted file mode 100644 index e2503d9f1869b..0000000000000 --- a/arch/cris/include/uapi/asm/socket.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _ASM_SOCKET_H -#define _ASM_SOCKET_H - -/* almost the same as asm-i386/socket.h */ - -#include - -/* For setsockoptions(2) */ -#define SOL_SOCKET 1 - -#define SO_DEBUG 1 -#define SO_REUSEADDR 2 -#define SO_TYPE 3 -#define SO_ERROR 4 -#define SO_DONTROUTE 5 -#define SO_BROADCAST 6 -#define SO_SNDBUF 7 -#define SO_RCVBUF 8 -#define SO_SNDBUFFORCE 32 -#define SO_RCVBUFFORCE 33 -#define SO_KEEPALIVE 9 -#define SO_OOBINLINE 10 -#define SO_NO_CHECK 11 -#define SO_PRIORITY 12 -#define SO_LINGER 13 -#define SO_BSDCOMPAT 14 -#define SO_REUSEPORT 15 -#define SO_PASSCRED 16 -#define SO_PEERCRED 17 -#define SO_RCVLOWAT 18 -#define SO_SNDLOWAT 19 -#define SO_RCVTIMEO 20 -#define SO_SNDTIMEO 21 - -/* Security levels - as per NRL IPv6 - don't actually do anything */ -#define SO_SECURITY_AUTHENTICATION 22 -#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 -#define SO_SECURITY_ENCRYPTION_NETWORK 24 - -#define SO_BINDTODEVICE 25 - -/* Socket filtering */ -#define SO_ATTACH_FILTER 26 -#define SO_DETACH_FILTER 27 -#define SO_GET_FILTER SO_ATTACH_FILTER - -#define SO_PEERNAME 28 -#define SO_TIMESTAMP 29 -#define SCM_TIMESTAMP SO_TIMESTAMP - -#define SO_ACCEPTCONN 30 - -#define SO_PEERSEC 31 -#define SO_PASSSEC 34 -#define SO_TIMESTAMPNS 35 -#define SCM_TIMESTAMPNS SO_TIMESTAMPNS - -#define SO_MARK 36 - -#define SO_TIMESTAMPING 37 -#define SCM_TIMESTAMPING SO_TIMESTAMPING - -#define SO_PROTOCOL 38 -#define SO_DOMAIN 39 - -#define SO_RXQ_OVFL 40 - -#define SO_WIFI_STATUS 41 -#define SCM_WIFI_STATUS SO_WIFI_STATUS -#define SO_PEEK_OFF 42 - -/* Instruct lower device to use last 4-bytes of skb data as FCS */ -#define SO_NOFCS 43 - -#define SO_LOCK_FILTER 44 - -#define SO_SELECT_ERR_QUEUE 45 - -#define SO_BUSY_POLL 46 - -#define SO_MAX_PACING_RATE 47 - -#define SO_BPF_EXTENSIONS 48 - -#define SO_INCOMING_CPU 49 - -#define SO_ATTACH_BPF 50 -#define SO_DETACH_BPF SO_DETACH_FILTER - -#endif /* _ASM_SOCKET_H */ - - -- GitLab From 74d94adb351161cc4027f94e878ac4e80adcfdc9 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:53:37 +0100 Subject: [PATCH 6331/7006] CRIS: UAPI: use generic msgbuf.h CRIS' msgbuf.h is equivalent to the asm-generic version. Effective diff: -#ifndef _CRIS_MSGBUF_H -#define _CRIS_MSGBUF_H - - +#ifndef __ASM_GENERIC_MSGBUF_H +#define __ASM_GENERIC_MSGBUF_H +#include struct msqid64_ds { struct ipc64_perm msg_perm; __kernel_time_t msg_stime; +#if __BITS_PER_LONG != 64 unsigned long __unused1; +#endif __kernel_time_t msg_rtime; +#if __BITS_PER_LONG != 64 unsigned long __unused2; +#endif __kernel_time_t msg_ctime; +#if __BITS_PER_LONG != 64 unsigned long __unused3; - unsigned long msg_cbytes; - unsigned long msg_qnum; - unsigned long msg_qbytes; +#endif + __kernel_ulong_t msg_cbytes; + __kernel_ulong_t msg_qnum; + __kernel_ulong_t msg_qbytes; __kernel_pid_t msg_lspid; __kernel_pid_t msg_lrpid; - unsigned long __unused4; - unsigned long __unused5; + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; }; #endif Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/uapi/asm/msgbuf.h | 33 ----------------------------- 2 files changed, 1 insertion(+), 33 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/msgbuf.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 30ed4e26ad81c..ccc0182ab52e6 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -27,6 +27,7 @@ generic-y += mcs_spinlock.h generic-y += mm-arch-hooks.h generic-y += mman.h generic-y += module.h +generic-y += msgbuf.h generic-y += percpu.h generic-y += poll.h generic-y += preempt.h diff --git a/arch/cris/include/uapi/asm/msgbuf.h b/arch/cris/include/uapi/asm/msgbuf.h deleted file mode 100644 index ada63df1d574e..0000000000000 --- a/arch/cris/include/uapi/asm/msgbuf.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _CRIS_MSGBUF_H -#define _CRIS_MSGBUF_H - -/* verbatim copy of asm-i386 version */ - -/* - * The msqid64_ds structure for CRIS architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct msqid64_ds { - struct ipc64_perm msg_perm; - __kernel_time_t msg_stime; /* last msgsnd time */ - unsigned long __unused1; - __kernel_time_t msg_rtime; /* last msgrcv time */ - unsigned long __unused2; - __kernel_time_t msg_ctime; /* last change time */ - unsigned long __unused3; - unsigned long msg_cbytes; /* current number of bytes on queue */ - unsigned long msg_qnum; /* number of messages in queue */ - unsigned long msg_qbytes; /* max number of bytes on queue */ - __kernel_pid_t msg_lspid; /* pid of last msgsnd */ - __kernel_pid_t msg_lrpid; /* last receive pid */ - unsigned long __unused4; - unsigned long __unused5; -}; - -#endif /* _CRIS_MSGBUF_H */ -- GitLab From 258a9ff66c30c830f6e2f06856878be4d4cc81af Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:55:46 +0100 Subject: [PATCH 6332/7006] CRIS: UAPI: use generic shmbuf.h CRIS' shmbuf.h is equivalent to the asm-generic verison. Effective diff: -#ifndef _CRIS_SHMBUF_H -#define _CRIS_SHMBUF_H +#ifndef __ASM_GENERIC_SHMBUF_H +#define __ASM_GENERIC_SHMBUF_H + +#include struct ipc64_perm shm_perm; size_t shm_segsz; __kernel_time_t shm_atime; +#if __BITS_PER_LONG != 64 unsigned long __unused1; +#endif __kernel_time_t shm_dtime; +#if __BITS_PER_LONG != 64 unsigned long __unused2; +#endif __kernel_time_t shm_ctime; +#if __BITS_PER_LONG != 64 unsigned long __unused3; +#endif __kernel_pid_t shm_cpid; __kernel_pid_t shm_lpid; - unsigned long shm_nattch; - unsigned long __unused4; - unsigned long __unused5; + __kernel_ulong_t shm_nattch; + __kernel_ulong_t __unused4; + __kernel_ulong_t __unused5; }; struct shminfo64 { - unsigned long shmmax; - unsigned long shmmin; - unsigned long shmmni; - unsigned long shmseg; - unsigned long shmall; - unsigned long __unused1; - unsigned long __unused2; - unsigned long __unused3; - unsigned long __unused4; + __kernel_ulong_t shmmax; + __kernel_ulong_t shmmin; + __kernel_ulong_t shmmni; + __kernel_ulong_t shmseg; + __kernel_ulong_t shmall; + __kernel_ulong_t __unused1; + __kernel_ulong_t __unused2; + __kernel_ulong_t __unused3; + __kernel_ulong_t __unused4; }; #endif Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/uapi/asm/shmbuf.h | 42 ----------------------------- 2 files changed, 1 insertion(+), 42 deletions(-) delete mode 100644 arch/cris/include/uapi/asm/shmbuf.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index ccc0182ab52e6..17b5237aaf0ae 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -34,6 +34,7 @@ generic-y += preempt.h generic-y += resource.h generic-y += sections.h generic-y += sembuf.h +generic-y += shmbuf.h generic-y += siginfo.h generic-y += socket.h generic-y += sockios.h diff --git a/arch/cris/include/uapi/asm/shmbuf.h b/arch/cris/include/uapi/asm/shmbuf.h deleted file mode 100644 index 3239e3f000e8d..0000000000000 --- a/arch/cris/include/uapi/asm/shmbuf.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef _CRIS_SHMBUF_H -#define _CRIS_SHMBUF_H - -/* - * The shmid64_ds structure for CRIS architecture (same as for i386) - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct shmid64_ds { - struct ipc64_perm shm_perm; /* operation perms */ - size_t shm_segsz; /* size of segment (bytes) */ - __kernel_time_t shm_atime; /* last attach time */ - unsigned long __unused1; - __kernel_time_t shm_dtime; /* last detach time */ - unsigned long __unused2; - __kernel_time_t shm_ctime; /* last change time */ - unsigned long __unused3; - __kernel_pid_t shm_cpid; /* pid of creator */ - __kernel_pid_t shm_lpid; /* pid of last operator */ - unsigned long shm_nattch; /* no. of current attaches */ - unsigned long __unused4; - unsigned long __unused5; -}; - -struct shminfo64 { - unsigned long shmmax; - unsigned long shmmin; - unsigned long shmmni; - unsigned long shmseg; - unsigned long shmall; - unsigned long __unused1; - unsigned long __unused2; - unsigned long __unused3; - unsigned long __unused4; -}; - -#endif /* _CRIS_SHMBUF_H */ -- GitLab From 20ae24739968ae7f94d0e73215d444042f91df78 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Sat, 28 Feb 2015 23:59:50 +0100 Subject: [PATCH 6333/7006] CRIS: UAPI: use generic types.h CRIS' types.h is functionally identical to the asm-generic version. Effective diff: +#ifndef _ASM_GENERIC_TYPES_H +#define _ASM_GENERIC_TYPES_H + #include + +#endif Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 1 + arch/cris/include/asm/types.h | 12 ------------ arch/cris/include/uapi/asm/types.h | 1 - 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 arch/cris/include/asm/types.h delete mode 100644 arch/cris/include/uapi/asm/types.h diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index 17b5237aaf0ae..b7f68192d15b5 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -41,5 +41,6 @@ generic-y += sockios.h generic-y += statfs.h generic-y += topology.h generic-y += trace_clock.h +generic-y += types.h generic-y += vga.h generic-y += xor.h diff --git a/arch/cris/include/asm/types.h b/arch/cris/include/asm/types.h deleted file mode 100644 index a3cac7757c7ff..0000000000000 --- a/arch/cris/include/asm/types.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _ETRAX_TYPES_H -#define _ETRAX_TYPES_H - -#include - -/* - * These aren't exported outside the kernel to avoid name space clashes - */ - -#define BITS_PER_LONG 32 - -#endif diff --git a/arch/cris/include/uapi/asm/types.h b/arch/cris/include/uapi/asm/types.h deleted file mode 100644 index 9ec9d4c5ac4d0..0000000000000 --- a/arch/cris/include/uapi/asm/types.h +++ /dev/null @@ -1 +0,0 @@ -#include -- GitLab From 444e0c2881bcc70db6833d9c653c6ced36813d3b Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 19 Feb 2015 21:36:55 +0100 Subject: [PATCH 6334/7006] CRISv32: add support for irqflags tracing Add support irqflags tracing, which is required for things like lockdep and ftrace. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/Kconfig | 4 ++++ arch/cris/arch-v32/kernel/entry.S | 11 +++++++++++ arch/cris/kernel/irq.c | 6 +++++- 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index b202b8277a266..e7ba2d4bdd4f3 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -36,6 +36,10 @@ config FORCE_MAX_ZONEORDER int default 6 +config TRACE_IRQFLAGS_SUPPORT + depends on ETRAX_ARCH_V32 + def_bool y + config CRIS bool default y diff --git a/arch/cris/arch-v32/kernel/entry.S b/arch/cris/arch-v32/kernel/entry.S index 1c5595a6ceb51..b17a20999f87b 100644 --- a/arch/cris/arch-v32/kernel/entry.S +++ b/arch/cris/arch-v32/kernel/entry.S @@ -240,6 +240,17 @@ ret_from_sys_call: .type _Rexit,@function _Rexit: +#if defined(CONFIG_TRACE_IRQFLAGS) + addoq +PT_ccs, $sp, $acr + move.d [$acr], $r0 + btstq 15, $r0 ; I1 + bpl 1f + nop + jsr trace_hardirqs_on + nop +1: +#endif + ;; This epilogue MUST match the prologues in multiple_interrupt, irq.h ;; and ptregs.h. addq 4, $sp ; Skip orig_r10. diff --git a/arch/cris/kernel/irq.c b/arch/cris/kernel/irq.c index dd0be5de55d5b..694850e8f077a 100644 --- a/arch/cris/kernel/irq.c +++ b/arch/cris/kernel/irq.c @@ -45,7 +45,11 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { unsigned long sp; - struct pt_regs *old_regs = set_irq_regs(regs); + struct pt_regs *old_regs; + + trace_hardirqs_off(); + + old_regs = set_irq_regs(regs); irq_enter(); sp = rdsp(); if (unlikely((sp & (PAGE_SIZE - 1)) < (PAGE_SIZE/8))) { -- GitLab From 3fffa23ee0a348aef1b597b67626d4724667143b Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 20 Feb 2015 18:57:37 +0100 Subject: [PATCH 6335/7006] CRISv32: annotate irq enable in idle loop Use a call to local_irq_enable() instead of incline asm so that the irqsoff latency tracer knows that interrupts are enabled here. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/cris/arch-v32/kernel/process.c b/arch/cris/arch-v32/kernel/process.c index cebd32e2a8fb9..c7ce784a393cc 100644 --- a/arch/cris/arch-v32/kernel/process.c +++ b/arch/cris/arch-v32/kernel/process.c @@ -23,9 +23,9 @@ extern void stop_watchdog(void); /* We use this if we don't have any better idle routine. */ void default_idle(void) { + local_irq_enable(); /* Halt until exception. */ - __asm__ volatile("ei \n\t" - "halt "); + __asm__ volatile("halt"); } /* -- GitLab From aa6f4d2b6547a9949d87c9b09a872a7015366588 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 14 May 2015 18:19:03 +0200 Subject: [PATCH 6336/7006] CRIS: add STACKTRACE_SUPPORT Add stacktrace support, which is required for lockdep and tracing. The stack tracing simply looks at all kernel text symbols found on the stack, similar to the trap stack dumping code, which can also be converted to use this. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/Kconfig | 3 ++ arch/cris/include/asm/stacktrace.h | 8 ++++ arch/cris/kernel/Makefile | 1 + arch/cris/kernel/stacktrace.c | 76 ++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+) create mode 100644 arch/cris/include/asm/stacktrace.h create mode 100644 arch/cris/kernel/stacktrace.c diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index e7ba2d4bdd4f3..61f4acceb9d43 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -40,6 +40,9 @@ config TRACE_IRQFLAGS_SUPPORT depends on ETRAX_ARCH_V32 def_bool y +config STACKTRACE_SUPPORT + def_bool y + config CRIS bool default y diff --git a/arch/cris/include/asm/stacktrace.h b/arch/cris/include/asm/stacktrace.h new file mode 100644 index 0000000000000..2d90856943ad0 --- /dev/null +++ b/arch/cris/include/asm/stacktrace.h @@ -0,0 +1,8 @@ +#ifndef __CRIS_STACKTRACE_H +#define __CRIS_STACKTRACE_H + +void walk_stackframe(unsigned long sp, + int (*fn)(unsigned long addr, void *data), + void *data); + +#endif diff --git a/arch/cris/kernel/Makefile b/arch/cris/kernel/Makefile index edef71f12bb88..5fae398ca9152 100644 --- a/arch/cris/kernel/Makefile +++ b/arch/cris/kernel/Makefile @@ -8,6 +8,7 @@ extra-y := vmlinux.lds obj-y := process.o traps.o irq.o ptrace.o setup.o time.o sys_cris.o obj-y += devicetree.o +obj-y += stacktrace.o obj-$(CONFIG_MODULES) += crisksyms.o obj-$(CONFIG_MODULES) += module.o diff --git a/arch/cris/kernel/stacktrace.c b/arch/cris/kernel/stacktrace.c new file mode 100644 index 0000000000000..99838c74456dd --- /dev/null +++ b/arch/cris/kernel/stacktrace.c @@ -0,0 +1,76 @@ +#include +#include +#include +#include + +void walk_stackframe(unsigned long sp, + int (*fn)(unsigned long addr, void *data), + void *data) +{ + unsigned long high = ALIGN(sp, THREAD_SIZE); + + for (; sp <= high - 4; sp += 4) { + unsigned long addr = *(unsigned long *) sp; + + if (!kernel_text_address(addr)) + continue; + + if (fn(addr, data)) + break; + } +} + +struct stack_trace_data { + struct stack_trace *trace; + unsigned int no_sched_functions; + unsigned int skip; +}; + +#ifdef CONFIG_STACKTRACE + +static int save_trace(unsigned long addr, void *d) +{ + struct stack_trace_data *data = d; + struct stack_trace *trace = data->trace; + + if (data->no_sched_functions && in_sched_functions(addr)) + return 0; + + if (data->skip) { + data->skip--; + return 0; + } + + trace->entries[trace->nr_entries++] = addr; + + return trace->nr_entries >= trace->max_entries; +} + +void save_stack_trace_tsk(struct task_struct *tsk, struct stack_trace *trace) +{ + struct stack_trace_data data; + unsigned long sp; + + data.trace = trace; + data.skip = trace->skip; + + if (tsk != current) { + data.no_sched_functions = 1; + sp = tsk->thread.ksp; + } else { + data.no_sched_functions = 0; + sp = rdsp(); + } + + walk_stackframe(sp, save_trace, &data); + if (trace->nr_entries < trace->max_entries) + trace->entries[trace->nr_entries++] = ULONG_MAX; +} + +void save_stack_trace(struct stack_trace *trace) +{ + save_stack_trace_tsk(current, trace); +} +EXPORT_SYMBOL_GPL(save_stack_trace); + +#endif /* CONFIG_STACKTRACE */ -- GitLab From 94c5c115c1f7d347d5ec7f32a090f8643dd42525 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Thu, 14 May 2015 18:19:37 +0200 Subject: [PATCH 6337/7006] CRISv32: enable LOCKDEP_SUPPORT Now that we have stack tracing and irq flags tracing support, we can also enable lockdep support Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/Kconfig | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig index 61f4acceb9d43..8da5653bd8958 100644 --- a/arch/cris/Kconfig +++ b/arch/cris/Kconfig @@ -43,6 +43,10 @@ config TRACE_IRQFLAGS_SUPPORT config STACKTRACE_SUPPORT def_bool y +config LOCKDEP_SUPPORT + depends on ETRAX_ARCH_V32 + def_bool y + config CRIS bool default y -- GitLab From 7f0144e7779a8c62e3177301d4b2179432ce5460 Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 20 Feb 2015 19:35:16 +0100 Subject: [PATCH 6338/7006] CRIS: fix switch_mm() lockdep splat With lockdep support implemented on CRISv32, we get the following splat. switch_mm() can be called both from the scheduler() (with interrupts disabled) and from flush_old_exec (via activate_mm()), with interrupts enabled. Fix it by disabling interrupts in activate_mm(), similar to powerpc and hexagon. t====================================================== [ INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected ] 3.19.0-08802-g20bc9f1-dirty #323 Not tainted ------------------------------------------------------ init/1 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: (mmu_context_lock){+.+...}, at: [] switch_mm+0x22/0xc6 and this task is already holding: (&rq->lock){-.-.-.}, at: [] __schedule+0x5e/0x648 which would create a new lock dependency: (&rq->lock){-.-.-.} -> (mmu_context_lock){+.+...} but this new dependency connects a HARDIRQ-irq-safe lock: (&rq->lock){-.-.-.} ... which became HARDIRQ-irq-safe at: [] scheduler_tick+0x28/0x5e [] timer_interrupt+0x4e/0x6a [] handle_irq_event_percpu+0x54/0x13c [] generic_handle_irq+0x2a/0x36 to a HARDIRQ-irq-unsafe lock: (mmu_context_lock){+.+...} ... which became HARDIRQ-irq-unsafe at: ... [] __lock_acquire+0x8f8/0x1d9c [] switch_mm+0x22/0xc6 [] flush_old_exec+0x500/0x5d4 [] load_elf_phdrs+0x7a/0x84 [] load_elf_binary+0x21c/0x13b4 [] do_execve+0x22/0x2c [] ____call_usermodehelper+0x0/0x154 [] ret_from_kernel_thread+0xe/0x14 other info that might help us debug this: Possible interrupt unsafe locking scenario: CPU0 CPU1 ---- ---- lock(mmu_context_lock); local_irq_disable(); lock(&rq->lock); lock(mmu_context_lock); lock(&rq->lock); *** DEADLOCK *** 1 lock held by init/1: #0: (&rq->lock){-.-.-.}, at: [] __schedule+0x5e/0x648 Call Trace: [] printk+0x0/0x4e [] print_shortest_lock_dependencies+0x0/0x15c [] print_stack_trace+0x0/0x88 [] __lock_is_held+0x3e/0x5e [] lock_acquire+0x8a/0xcc [] _raw_spin_lock+0x44/0x7a [] switch_mm+0x22/0xc6 [] __schedule+0x0/0x648 [] schedule+0x36/0x7c [] trace_hardirqs_on+0x0/0x1e [] do_work_pending+0x30/0xd4 [] _work_pending+0xe/0x12 Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/mmu_context.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/arch/cris/include/asm/mmu_context.h b/arch/cris/include/asm/mmu_context.h index 1d45fd6365b72..349acfd25d2f6 100644 --- a/arch/cris/include/asm/mmu_context.h +++ b/arch/cris/include/asm/mmu_context.h @@ -11,7 +11,14 @@ extern void switch_mm(struct mm_struct *prev, struct mm_struct *next, #define deactivate_mm(tsk,mm) do { } while (0) -#define activate_mm(prev,next) switch_mm((prev),(next),NULL) +static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) +{ + unsigned long flags; + + local_irq_save(flags); + switch_mm(prev, next, NULL); + local_irq_restore(flags); +} /* current active pgd - this is similar to other processors pgd * registers like cr3 on the i386 -- GitLab From c2ffc68afc0fce16923a54b2dad4d544463b9e0b Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 22 May 2015 20:58:48 +0200 Subject: [PATCH 6339/7006] CRISv10: delete unused lib/old_checksum.c This file is never built. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/arch-v10/lib/old_checksum.c | 86 --------------------------- 1 file changed, 86 deletions(-) delete mode 100644 arch/cris/arch-v10/lib/old_checksum.c diff --git a/arch/cris/arch-v10/lib/old_checksum.c b/arch/cris/arch-v10/lib/old_checksum.c deleted file mode 100644 index 8f79163f13941..0000000000000 --- a/arch/cris/arch-v10/lib/old_checksum.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IP/TCP/UDP checksumming routines - * - * Authors: Jorge Cwik, - * Arnt Gulbrandsen, - * Tom May, - * Lots of code moved from tcp.c and ip.c; see those files - * for more names. - * - * 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 -#include - -#undef PROFILE_CHECKSUM - -#ifdef PROFILE_CHECKSUM -/* these are just for profiling the checksum code with an oscillioscope.. uh */ -#if 0 -#define BITOFF *((unsigned char *)0xb0000030) = 0xff -#define BITON *((unsigned char *)0xb0000030) = 0x0 -#endif -#include -#define CBITON LED_ACTIVE_SET(1) -#define CBITOFF LED_ACTIVE_SET(0) -#define BITOFF -#define BITON -#else -#define BITOFF -#define BITON -#define CBITOFF -#define CBITON -#endif - -/* - * computes a partial checksum, e.g. for TCP/UDP fragments - */ - -#include - -__wsum csum_partial(const void *p, int len, __wsum __sum) -{ - u32 sum = (__force u32)__sum; - const u16 *buff = p; - /* - * Experiments with ethernet and slip connections show that buff - * is aligned on either a 2-byte or 4-byte boundary. - */ - const void *endMarker = p + len; - const void *marker = endMarker - (len % 16); -#if 0 - if((int)buff & 0x3) - printk("unaligned buff %p\n", buff); - __delay(900); /* extra delay of 90 us to test performance hit */ -#endif - BITON; - while (buff < marker) { - sum += *buff++; - sum += *buff++; - sum += *buff++; - sum += *buff++; - sum += *buff++; - sum += *buff++; - sum += *buff++; - sum += *buff++; - } - marker = endMarker - (len % 2); - while (buff < marker) - sum += *buff++; - - if (endMarker > buff) - sum += *(const u8 *)buff; /* add extra byte separately */ - - BITOFF; - return (__force __wsum)sum; -} - -EXPORT_SYMBOL(csum_partial); -- GitLab From 254a0f4135482dc02701562a38e10675a48c8ddf Mon Sep 17 00:00:00 2001 From: Rabin Vincent Date: Fri, 22 May 2015 20:58:49 +0200 Subject: [PATCH 6340/7006] CRISv10: delete unused lib/dmacopy.c This file is never built. Signed-off-by: Rabin Vincent Signed-off-by: Jesper Nilsson --- arch/cris/arch-v10/lib/dmacopy.c | 42 -------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 arch/cris/arch-v10/lib/dmacopy.c diff --git a/arch/cris/arch-v10/lib/dmacopy.c b/arch/cris/arch-v10/lib/dmacopy.c deleted file mode 100644 index 49f5b8ca5b47b..0000000000000 --- a/arch/cris/arch-v10/lib/dmacopy.c +++ /dev/null @@ -1,42 +0,0 @@ -/* - * memcpy for large blocks, using memory-memory DMA channels 6 and 7 in Etrax - */ - -#include -#include - -#define D(x) - -void *dma_memcpy(void *pdst, - const void *psrc, - unsigned int pn) -{ - static etrax_dma_descr indma, outdma; - - D(printk(KERN_DEBUG "dma_memcpy %d bytes... ", pn)); - -#if 0 - *R_GEN_CONFIG = genconfig_shadow = - (genconfig_shadow & ~0x3c0000) | - IO_STATE(R_GEN_CONFIG, dma6, intdma7) | - IO_STATE(R_GEN_CONFIG, dma7, intdma6); -#endif - indma.sw_len = outdma.sw_len = pn; - indma.ctrl = d_eol | d_eop; - outdma.ctrl = d_eol; - indma.buf = psrc; - outdma.buf = pdst; - - *R_DMA_CH6_FIRST = &indma; - *R_DMA_CH7_FIRST = &outdma; - *R_DMA_CH6_CMD = IO_STATE(R_DMA_CH6_CMD, cmd, start); - *R_DMA_CH7_CMD = IO_STATE(R_DMA_CH7_CMD, cmd, start); - - while (*R_DMA_CH7_CMD == 1) - /* wait for completion */; - - D(printk(KERN_DEBUG "done\n")); -} - - - -- GitLab From 7f36e3e56db1ae75d1e157011b3cb2e0957f0a7e Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Fri, 4 Sep 2015 15:42:32 -0700 Subject: [PATCH 6341/7006] memory-hotplug: add hot-added memory ranges to memblock before allocate node_data for a node. Commit f9126ab9241f ("memory-hotplug: fix wrong edge when hot add a new node") hot-added memory range to memblock, after creating pgdat for new node. But there is a problem: add_memory() |--> hotadd_new_pgdat() |--> free_area_init_node() |--> get_pfn_range_for_nid() |--> find start_pfn and end_pfn in memblock |--> ...... |--> memblock_add_node(start, size, nid) -------- Here, just too late. get_pfn_range_for_nid() will find that start_pfn and end_pfn are both 0. As a result, when adding memory, dmesg will give the following wrong message. Initmem setup node 5 [mem 0x0000000000000000-0xffffffffffffffff] On node 5 totalpages: 0 Built 5 zonelists in Node order, mobility grouping on. Total pages: 32588823 Policy zone: Normal init_memory_mapping: [mem 0x60000000000-0x607ffffffff] The solution is simple, just add the memory range to memblock a little earlier, before hotadd_new_pgdat(). [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Tang Chen Cc: Xishi Qiu Cc: Yasuaki Ishimatsu Cc: Kamezawa Hiroyuki Cc: Taku Izumi Cc: Gu Zheng Cc: Naoya Horiguchi Cc: Vlastimil Babka Cc: Mel Gorman Cc: David Rientjes Cc: [4.2.x] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory_hotplug.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c index 6da82bcb0a8b6..8fd97dac538a4 100644 --- a/mm/memory_hotplug.c +++ b/mm/memory_hotplug.c @@ -1248,6 +1248,14 @@ int __ref add_memory(int nid, u64 start, u64 size) mem_hotplug_begin(); + /* + * Add new range to memblock so that when hotadd_new_pgdat() is called + * to allocate new pgdat, get_pfn_range_for_nid() will be able to find + * this new range and calculate total pages correctly. The range will + * be removed at hot-remove time. + */ + memblock_add_node(start, size, nid); + new_node = !node_online(nid); if (new_node) { pgdat = hotadd_new_pgdat(nid, start); @@ -1277,7 +1285,6 @@ int __ref add_memory(int nid, u64 start, u64 size) /* create new memmap entry */ firmware_map_add_hotplug(start, start + size, "System RAM"); - memblock_add_node(start, size, nid); goto out; @@ -1286,6 +1293,7 @@ error: if (new_pgdat) rollback_node_hotadd(nid, pgdat); release_memory_resource(res); + memblock_remove(start, size); out: mem_hotplug_done(); -- GitLab From aa1057b3dec478b20c77bad07442318ae36d893c Mon Sep 17 00:00:00 2001 From: Ryan Ding Date: Fri, 4 Sep 2015 15:42:36 -0700 Subject: [PATCH 6342/7006] ocfs2: direct write will call ocfs2_rw_unlock() twice when doing aio+dio ocfs2_file_write_iter() is usng the wrong return value ('written'). This will cause ocfs2_rw_unlock() be called both in write_iter & end_io, triggering a BUG_ON. This issue was introduced by commit 7da839c47589 ("ocfs2: use __generic_file_write_iter()"). Orabug: 21612107 Fixes: 7da839c47589 ("ocfs2: use __generic_file_write_iter()") Signed-off-by: Ryan Ding Reviewed-by: Junxiao Bi Cc: Al Viro Cc: Mark Fasheh Cc: Joel Becker Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/file.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 7210583b472f5..2eb11363b1f78 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2378,6 +2378,20 @@ relock: /* buffered aio wouldn't have proper lock coverage today */ BUG_ON(written == -EIOCBQUEUED && !(iocb->ki_flags & IOCB_DIRECT)); + /* + * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io + * function pointer which is called when o_direct io completes so that + * it can unlock our rw lock. + * Unfortunately there are error cases which call end_io and others + * that don't. so we don't have to unlock the rw_lock if either an + * async dio is going to do it in the future or an end_io after an + * error has already done it. + */ + if ((written == -EIOCBQUEUED) || (!ocfs2_iocb_is_rw_locked(iocb))) { + rw_level = -1; + unaligned_dio = 0; + } + if (unlikely(written <= 0)) goto no_sync; @@ -2402,20 +2416,6 @@ relock: } no_sync: - /* - * deep in g_f_a_w_n()->ocfs2_direct_IO we pass in a ocfs2_dio_end_io - * function pointer which is called when o_direct io completes so that - * it can unlock our rw lock. - * Unfortunately there are error cases which call end_io and others - * that don't. so we don't have to unlock the rw_lock if either an - * async dio is going to do it in the future or an end_io after an - * error has already done it. - */ - if ((ret == -EIOCBQUEUED) || (!ocfs2_iocb_is_rw_locked(iocb))) { - rw_level = -1; - unaligned_dio = 0; - } - if (unaligned_dio) { ocfs2_iocb_clear_unaligned_aio(iocb); mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio); -- GitLab From 04697858d89e4bf2650364f8d6956e2554e8ef88 Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Fri, 4 Sep 2015 15:42:39 -0700 Subject: [PATCH 6343/7006] mm: check if section present during memory block registering Tony Luck found on his setup, if memory block size 512M will cause crash during booting. BUG: unable to handle kernel paging request at ffffea0074000020 IP: get_nid_for_pfn+0x17/0x40 PGD 128ffcb067 PUD 128ffc9067 PMD 0 Oops: 0000 [#1] SMP Modules linked in: CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.2.0-rc8 #1 ... Call Trace: ? register_mem_sect_under_node+0x66/0xe0 register_one_node+0x17b/0x240 ? pci_iommu_alloc+0x6e/0x6e topology_init+0x3c/0x95 do_one_initcall+0xcd/0x1f0 The system has non continuous RAM address: BIOS-e820: [mem 0x0000001300000000-0x0000001cffffffff] usable BIOS-e820: [mem 0x0000001d70000000-0x0000001ec7ffefff] usable BIOS-e820: [mem 0x0000001f00000000-0x0000002bffffffff] usable BIOS-e820: [mem 0x0000002c18000000-0x0000002d6fffefff] usable BIOS-e820: [mem 0x0000002e00000000-0x00000039ffffffff] usable So there are start sections in memory block not present. For example: memory block : [0x2c18000000, 0x2c20000000) 512M first three sections are not present. The current register_mem_sect_under_node() assume first section is present, but memory block section number range [start_section_nr, end_section_nr] would include not present section. For arch that support vmemmap, we don't setup memmap for struct page area within not present sections area. So skip the pfn range that belong to absent section. [akpm@linux-foundation.org: simplification] [rientjes@google.com: more simplification] Fixes: bdee237c0343 ("x86: mm: Use 2GB memory block size on large memory x86-64 systems") Fixes: 982792c782ef ("x86, mm: probe memory block size for generic x86 64bit") Signed-off-by: Yinghai Lu Signed-off-by: David Rientjes Reported-by: Tony Luck Tested-by: Tony Luck Cc: Greg KH Cc: Ingo Molnar Tested-by: David Rientjes Cc: [3.15+] Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/base/node.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/base/node.c b/drivers/base/node.c index 31df474d72f4a..560751bad2947 100644 --- a/drivers/base/node.c +++ b/drivers/base/node.c @@ -392,6 +392,16 @@ int register_mem_sect_under_node(struct memory_block *mem_blk, int nid) for (pfn = sect_start_pfn; pfn <= sect_end_pfn; pfn++) { int page_nid; + /* + * memory block could have several absent sections from start. + * skip pfn range from absent section + */ + if (!pfn_present(pfn)) { + pfn = round_down(pfn + PAGES_PER_SECTION, + PAGES_PER_SECTION) - 1; + continue; + } + page_nid = get_nid_for_pfn(pfn); if (page_nid < 0) continue; -- GitLab From e9f069868d60550c4b46f084ac9276a57c1b4711 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 4 Sep 2015 15:42:42 -0700 Subject: [PATCH 6344/7006] kernel/kthread.c:kthread_create_on_node(): clarify documentation - Make it clear that the `node' arg refers to memory allocations only: kthread_create_on_node() does not pin the new thread to that node's CPUs. - Encourage the use of NUMA_NO_NODE. [nzimmer@sgi.com: use NUMA_NO_NODE in kthread_create() also] Cc: Nathan Zimmer Cc: Tejun Heo Cc: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kthread.h | 2 +- kernel/kthread.c | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/linux/kthread.h b/include/linux/kthread.h index 869b21dcf503a..e691b6a23f722 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h @@ -11,7 +11,7 @@ struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), const char namefmt[], ...); #define kthread_create(threadfn, data, namefmt, arg...) \ - kthread_create_on_node(threadfn, data, -1, namefmt, ##arg) + kthread_create_on_node(threadfn, data, NUMA_NO_NODE, namefmt, ##arg) struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data), diff --git a/kernel/kthread.c b/kernel/kthread.c index 490924cc9e7c8..9ff173dca1aef 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -248,15 +248,16 @@ static void create_kthread(struct kthread_create_info *create) * kthread_create_on_node - create a kthread. * @threadfn: the function to run until signal_pending(current). * @data: data ptr for @threadfn. - * @node: memory node number. + * @node: task and thread structures for the thread are allocated on this node * @namefmt: printf-style name for the thread. * * Description: This helper function creates and names a kernel * thread. The thread will be stopped: use wake_up_process() to start - * it. See also kthread_run(). + * it. See also kthread_run(). The new thread has SCHED_NORMAL policy and + * is affine to all CPUs. * * If thread is going to be bound on a particular cpu, give its node - * in @node, to get NUMA affinity for kthread stack, or else give -1. + * in @node, to get NUMA affinity for kthread stack, or else give NUMA_NO_NODE. * When woken, the thread will run @threadfn() with @data as its * argument. @threadfn() can either call do_exit() directly if it is a * standalone thread for which no one will call kthread_stop(), or -- GitLab From 58319057b7847667f0c9585b9de0e8932b0fdb08 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 4 Sep 2015 15:42:45 -0700 Subject: [PATCH 6345/7006] capabilities: ambient capabilities Credit where credit is due: this idea comes from Christoph Lameter with a lot of valuable input from Serge Hallyn. This patch is heavily based on Christoph's patch. ===== The status quo ===== On Linux, there are a number of capabilities defined by the kernel. To perform various privileged tasks, processes can wield capabilities that they hold. Each task has four capability masks: effective (pE), permitted (pP), inheritable (pI), and a bounding set (X). When the kernel checks for a capability, it checks pE. The other capability masks serve to modify what capabilities can be in pE. Any task can remove capabilities from pE, pP, or pI at any time. If a task has a capability in pP, it can add that capability to pE and/or pI. If a task has CAP_SETPCAP, then it can add any capability to pI, and it can remove capabilities from X. Tasks are not the only things that can have capabilities; files can also have capabilities. A file can have no capabilty information at all [1]. If a file has capability information, then it has a permitted mask (fP) and an inheritable mask (fI) as well as a single effective bit (fE) [2]. File capabilities modify the capabilities of tasks that execve(2) them. A task that successfully calls execve has its capabilities modified for the file ultimately being excecuted (i.e. the binary itself if that binary is ELF or for the interpreter if the binary is a script.) [3] In the capability evolution rules, for each mask Z, pZ represents the old value and pZ' represents the new value. The rules are: pP' = (X & fP) | (pI & fI) pI' = pI pE' = (fE ? pP' : 0) X is unchanged For setuid binaries, fP, fI, and fE are modified by a moderately complicated set of rules that emulate POSIX behavior. Similarly, if euid == 0 or ruid == 0, then fP, fI, and fE are modified differently (primary, fP and fI usually end up being the full set). For nonroot users executing binaries with neither setuid nor file caps, fI and fP are empty and fE is false. As an extra complication, if you execute a process as nonroot and fE is set, then the "secure exec" rules are in effect: AT_SECURE gets set, LD_PRELOAD doesn't work, etc. This is rather messy. We've learned that making any changes is dangerous, though: if a new kernel version allows an unprivileged program to change its security state in a way that persists cross execution of a setuid program or a program with file caps, this persistent state is surprisingly likely to allow setuid or file-capped programs to be exploited for privilege escalation. ===== The problem ===== Capability inheritance is basically useless. If you aren't root and you execute an ordinary binary, fI is zero, so your capabilities have no effect whatsoever on pP'. This means that you can't usefully execute a helper process or a shell command with elevated capabilities if you aren't root. On current kernels, you can sort of work around this by setting fI to the full set for most or all non-setuid executable files. This causes pP' = pI for nonroot, and inheritance works. No one does this because it's a PITA and it isn't even supported on most filesystems. If you try this, you'll discover that every nonroot program ends up with secure exec rules, breaking many things. This is a problem that has bitten many people who have tried to use capabilities for anything useful. ===== The proposed change ===== This patch adds a fifth capability mask called the ambient mask (pA). pA does what most people expect pI to do. pA obeys the invariant that no bit can ever be set in pA if it is not set in both pP and pI. Dropping a bit from pP or pI drops that bit from pA. This ensures that existing programs that try to drop capabilities still do so, with a complication. Because capability inheritance is so broken, setting KEEPCAPS, using setresuid to switch to nonroot uids, and then calling execve effectively drops capabilities. Therefore, setresuid from root to nonroot conditionally clears pA unless SECBIT_NO_SETUID_FIXUP is set. Processes that don't like this can re-add bits to pA afterwards. The capability evolution rules are changed: pA' = (file caps or setuid or setgid ? 0 : pA) pP' = (X & fP) | (pI & fI) | pA' pI' = pI pE' = (fE ? pP' : pA') X is unchanged If you are nonroot but you have a capability, you can add it to pA. If you do so, your children get that capability in pA, pP, and pE. For example, you can set pA = CAP_NET_BIND_SERVICE, and your children can automatically bind low-numbered ports. Hallelujah! Unprivileged users can create user namespaces, map themselves to a nonzero uid, and create both privileged (relative to their namespace) and unprivileged process trees. This is currently more or less impossible. Hallelujah! You cannot use pA to try to subvert a setuid, setgid, or file-capped program: if you execute any such program, pA gets cleared and the resulting evolution rules are unchanged by this patch. Users with nonzero pA are unlikely to unintentionally leak that capability. If they run programs that try to drop privileges, dropping privileges will still work. It's worth noting that the degree of paranoia in this patch could possibly be reduced without causing serious problems. Specifically, if we allowed pA to persist across executing non-pA-aware setuid binaries and across setresuid, then, naively, the only capabilities that could leak as a result would be the capabilities in pA, and any attacker *already* has those capabilities. This would make me nervous, though -- setuid binaries that tried to privilege-separate might fail to do so, and putting CAP_DAC_READ_SEARCH or CAP_DAC_OVERRIDE into pA could have unexpected side effects. (Whether these unexpected side effects would be exploitable is an open question.) I've therefore taken the more paranoid route. We can revisit this later. An alternative would be to require PR_SET_NO_NEW_PRIVS before setting ambient capabilities. I think that this would be annoying and would make granting otherwise unprivileged users minor ambient capabilities (CAP_NET_BIND_SERVICE or CAP_NET_RAW for example) much less useful than it is with this patch. ===== Footnotes ===== [1] Files that are missing the "security.capability" xattr or that have unrecognized values for that xattr end up with has_cap set to false. The code that does that appears to be complicated for no good reason. [2] The libcap capability mask parsers and formatters are dangerously misleading and the documentation is flat-out wrong. fE is *not* a mask; it's a single bit. This has probably confused every single person who has tried to use file capabilities. [3] Linux very confusingly processes both the script and the interpreter if applicable, for reasons that elude me. The results from thinking about a script's file capabilities and/or setuid bits are mostly discarded. Preliminary userspace code is here, but it needs updating: https://git.kernel.org/cgit/linux/kernel/git/luto/util-linux-playground.git/commit/?h=cap_ambient&id=7f5afbd175d2 Here is a test program that can be used to verify the functionality (from Christoph): /* * Test program for the ambient capabilities. This program spawns a shell * that allows running processes with a defined set of capabilities. * * (C) 2015 Christoph Lameter * Released under: GPL v3 or later. * * * Compile using: * * gcc -o ambient_test ambient_test.o -lcap-ng * * This program must have the following capabilities to run properly: * Permissions for CAP_NET_RAW, CAP_NET_ADMIN, CAP_SYS_NICE * * A command to equip the binary with the right caps is: * * setcap cap_net_raw,cap_net_admin,cap_sys_nice+p ambient_test * * * To get a shell with additional caps that can be inherited by other processes: * * ./ambient_test /bin/bash * * * Verifying that it works: * * From the bash spawed by ambient_test run * * cat /proc/$$/status * * and have a look at the capabilities. */ #include #include #include #include #include #include /* * Definitions from the kernel header files. These are going to be removed * when the /usr/include files have these defined. */ #define PR_CAP_AMBIENT 47 #define PR_CAP_AMBIENT_IS_SET 1 #define PR_CAP_AMBIENT_RAISE 2 #define PR_CAP_AMBIENT_LOWER 3 #define PR_CAP_AMBIENT_CLEAR_ALL 4 static void set_ambient_cap(int cap) { int rc; capng_get_caps_process(); rc = capng_update(CAPNG_ADD, CAPNG_INHERITABLE, cap); if (rc) { printf("Cannot add inheritable cap\n"); exit(2); } capng_apply(CAPNG_SELECT_CAPS); /* Note the two 0s at the end. Kernel checks for these */ if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)) { perror("Cannot set cap"); exit(1); } } int main(int argc, char **argv) { int rc; set_ambient_cap(CAP_NET_RAW); set_ambient_cap(CAP_NET_ADMIN); set_ambient_cap(CAP_SYS_NICE); printf("Ambient_test forking shell\n"); if (execv(argv[1], argv + 1)) perror("Cannot exec"); return 0; } Signed-off-by: Christoph Lameter # Original author Signed-off-by: Andy Lutomirski Acked-by: Serge E. Hallyn Acked-by: Kees Cook Cc: Jonathan Corbet Cc: Aaron Jones Cc: Ted Ts'o Cc: Andrew G. Morgan Cc: Mimi Zohar Cc: Austin S Hemmelgarn Cc: Markku Savela Cc: Jarkko Sakkinen Cc: Michael Kerrisk Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/array.c | 5 +- include/linux/cred.h | 8 +++ include/uapi/linux/prctl.h | 7 +++ kernel/user_namespace.c | 1 + security/commoncap.c | 102 +++++++++++++++++++++++++++++++---- security/keys/process_keys.c | 1 + 6 files changed, 113 insertions(+), 11 deletions(-) diff --git a/fs/proc/array.c b/fs/proc/array.c index ce065cf3104fb..f60f0121e3319 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -308,7 +308,8 @@ static void render_cap_t(struct seq_file *m, const char *header, static inline void task_cap(struct seq_file *m, struct task_struct *p) { const struct cred *cred; - kernel_cap_t cap_inheritable, cap_permitted, cap_effective, cap_bset; + kernel_cap_t cap_inheritable, cap_permitted, cap_effective, + cap_bset, cap_ambient; rcu_read_lock(); cred = __task_cred(p); @@ -316,12 +317,14 @@ static inline void task_cap(struct seq_file *m, struct task_struct *p) cap_permitted = cred->cap_permitted; cap_effective = cred->cap_effective; cap_bset = cred->cap_bset; + cap_ambient = cred->cap_ambient; rcu_read_unlock(); render_cap_t(m, "CapInh:\t", &cap_inheritable); render_cap_t(m, "CapPrm:\t", &cap_permitted); render_cap_t(m, "CapEff:\t", &cap_effective); render_cap_t(m, "CapBnd:\t", &cap_bset); + render_cap_t(m, "CapAmb:\t", &cap_ambient); } static inline void task_seccomp(struct seq_file *m, struct task_struct *p) diff --git a/include/linux/cred.h b/include/linux/cred.h index 8b6c083e68a73..8d70e1361ecd0 100644 --- a/include/linux/cred.h +++ b/include/linux/cred.h @@ -137,6 +137,7 @@ struct cred { kernel_cap_t cap_permitted; /* caps we're permitted */ kernel_cap_t cap_effective; /* caps we can actually use */ kernel_cap_t cap_bset; /* capability bounding set */ + kernel_cap_t cap_ambient; /* Ambient capability set */ #ifdef CONFIG_KEYS unsigned char jit_keyring; /* default keyring to attach requested * keys to */ @@ -212,6 +213,13 @@ static inline void validate_process_creds(void) } #endif +static inline bool cap_ambient_invariant_ok(const struct cred *cred) +{ + return cap_issubset(cred->cap_ambient, + cap_intersect(cred->cap_permitted, + cred->cap_inheritable)); +} + /** * get_new_cred - Get a reference on a new set of credentials * @cred: The new credentials to reference diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 31891d9535e2a..a8d0759a9e400 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -190,4 +190,11 @@ struct prctl_mm_map { # define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */ # define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */ +/* Control the ambient capability set */ +#define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index f65a0a06a8c06..88fefa68c5164 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -39,6 +39,7 @@ static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns) cred->cap_inheritable = CAP_EMPTY_SET; cred->cap_permitted = CAP_FULL_SET; cred->cap_effective = CAP_FULL_SET; + cred->cap_ambient = CAP_EMPTY_SET; cred->cap_bset = CAP_FULL_SET; #ifdef CONFIG_KEYS key_put(cred->request_key_auth); diff --git a/security/commoncap.c b/security/commoncap.c index d103f5a4043d3..1f74dde1063e5 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -267,6 +267,16 @@ int cap_capset(struct cred *new, new->cap_effective = *effective; new->cap_inheritable = *inheritable; new->cap_permitted = *permitted; + + /* + * Mask off ambient bits that are no longer both permitted and + * inheritable. + */ + new->cap_ambient = cap_intersect(new->cap_ambient, + cap_intersect(*permitted, + *inheritable)); + if (WARN_ON(!cap_ambient_invariant_ok(new))) + return -EINVAL; return 0; } @@ -347,6 +357,7 @@ static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, /* * pP' = (X & fP) | (pI & fI) + * The addition of pA' is handled later. */ new->cap_permitted.cap[i] = (new->cap_bset.cap[i] & permitted) | @@ -474,10 +485,13 @@ int cap_bprm_set_creds(struct linux_binprm *bprm) { const struct cred *old = current_cred(); struct cred *new = bprm->cred; - bool effective, has_cap = false; + bool effective, has_cap = false, is_setid; int ret; kuid_t root_uid; + if (WARN_ON(!cap_ambient_invariant_ok(old))) + return -EPERM; + effective = false; ret = get_file_caps(bprm, &effective, &has_cap); if (ret < 0) @@ -522,8 +536,9 @@ skip: * * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. */ - if ((!uid_eq(new->euid, old->uid) || - !gid_eq(new->egid, old->gid) || + is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid); + + if ((is_setid || !cap_issubset(new->cap_permitted, old->cap_permitted)) && bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { /* downgrade; they get no more than they had, and maybe less */ @@ -539,10 +554,28 @@ skip: new->suid = new->fsuid = new->euid; new->sgid = new->fsgid = new->egid; + /* File caps or setid cancels ambient. */ + if (has_cap || is_setid) + cap_clear(new->cap_ambient); + + /* + * Now that we've computed pA', update pP' to give: + * pP' = (X & fP) | (pI & fI) | pA' + */ + new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient); + + /* + * Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set, + * this is the same as pE' = (fE ? pP' : 0) | pA'. + */ if (effective) new->cap_effective = new->cap_permitted; else - cap_clear(new->cap_effective); + new->cap_effective = new->cap_ambient; + + if (WARN_ON(!cap_ambient_invariant_ok(new))) + return -EPERM; + bprm->cap_effective = effective; /* @@ -557,7 +590,7 @@ skip: * Number 1 above might fail if you don't have a full bset, but I think * that is interesting information to audit. */ - if (!cap_isclear(new->cap_effective)) { + if (!cap_issubset(new->cap_effective, new->cap_ambient)) { if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || issecure(SECURE_NOROOT)) { @@ -568,6 +601,10 @@ skip: } new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); + + if (WARN_ON(!cap_ambient_invariant_ok(new))) + return -EPERM; + return 0; } @@ -589,7 +626,7 @@ int cap_bprm_secureexec(struct linux_binprm *bprm) if (!uid_eq(cred->uid, root_uid)) { if (bprm->cap_effective) return 1; - if (!cap_isclear(cred->cap_permitted)) + if (!cap_issubset(cred->cap_permitted, cred->cap_ambient)) return 1; } @@ -691,10 +728,18 @@ static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) uid_eq(old->suid, root_uid)) && (!uid_eq(new->uid, root_uid) && !uid_eq(new->euid, root_uid) && - !uid_eq(new->suid, root_uid)) && - !issecure(SECURE_KEEP_CAPS)) { - cap_clear(new->cap_permitted); - cap_clear(new->cap_effective); + !uid_eq(new->suid, root_uid))) { + if (!issecure(SECURE_KEEP_CAPS)) { + cap_clear(new->cap_permitted); + cap_clear(new->cap_effective); + } + + /* + * Pre-ambient programs expect setresuid to nonroot followed + * by exec to drop capabilities. We should make sure that + * this remains the case. + */ + cap_clear(new->cap_ambient); } if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) cap_clear(new->cap_effective); @@ -924,6 +969,43 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); return commit_creds(new); + case PR_CAP_AMBIENT: + if (arg2 == PR_CAP_AMBIENT_CLEAR_ALL) { + if (arg3 | arg4 | arg5) + return -EINVAL; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + cap_clear(new->cap_ambient); + return commit_creds(new); + } + + if (((!cap_valid(arg3)) | arg4 | arg5)) + return -EINVAL; + + if (arg2 == PR_CAP_AMBIENT_IS_SET) { + return !!cap_raised(current_cred()->cap_ambient, arg3); + } else if (arg2 != PR_CAP_AMBIENT_RAISE && + arg2 != PR_CAP_AMBIENT_LOWER) { + return -EINVAL; + } else { + if (arg2 == PR_CAP_AMBIENT_RAISE && + (!cap_raised(current_cred()->cap_permitted, arg3) || + !cap_raised(current_cred()->cap_inheritable, + arg3))) + return -EPERM; + + new = prepare_creds(); + if (!new) + return -ENOMEM; + if (arg2 == PR_CAP_AMBIENT_RAISE) + cap_raise(new->cap_ambient, arg3); + else + cap_lower(new->cap_ambient, arg3); + return commit_creds(new); + } + default: /* No functionality available - continue with default */ return -ENOSYS; diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c index bd536cb221e23..43b4cddbf2b39 100644 --- a/security/keys/process_keys.c +++ b/security/keys/process_keys.c @@ -848,6 +848,7 @@ void key_change_session_keyring(struct callback_head *twork) new->cap_inheritable = old->cap_inheritable; new->cap_permitted = old->cap_permitted; new->cap_effective = old->cap_effective; + new->cap_ambient = old->cap_ambient; new->cap_bset = old->cap_bset; new->jit_keyring = old->jit_keyring; -- GitLab From 32ae976ed3b5ba39c9208ace41bcdf4157d21db3 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 4 Sep 2015 15:42:48 -0700 Subject: [PATCH 6346/7006] selftests/capabilities: Add tests for capability evolution This test focuses on ambient capabilities. It requires either root or the ability to create user namespaces. Some of the test cases will be skipped for nonroot users. Signed-off-by: Andy Lutomirski Acked-by: Kees Cook Cc: Christoph Lameter # Original author Cc: Serge E. Hallyn Cc: James Morris Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../testing/selftests/capabilities/.gitignore | 2 + tools/testing/selftests/capabilities/Makefile | 18 + .../selftests/capabilities/test_execve.c | 427 ++++++++++++++++++ .../selftests/capabilities/validate_cap.c | 73 +++ 4 files changed, 520 insertions(+) create mode 100644 tools/testing/selftests/capabilities/.gitignore create mode 100644 tools/testing/selftests/capabilities/Makefile create mode 100644 tools/testing/selftests/capabilities/test_execve.c create mode 100644 tools/testing/selftests/capabilities/validate_cap.c diff --git a/tools/testing/selftests/capabilities/.gitignore b/tools/testing/selftests/capabilities/.gitignore new file mode 100644 index 0000000000000..b732dd0d47384 --- /dev/null +++ b/tools/testing/selftests/capabilities/.gitignore @@ -0,0 +1,2 @@ +test_execve +validate_cap diff --git a/tools/testing/selftests/capabilities/Makefile b/tools/testing/selftests/capabilities/Makefile new file mode 100644 index 0000000000000..8c8f0c1f08894 --- /dev/null +++ b/tools/testing/selftests/capabilities/Makefile @@ -0,0 +1,18 @@ +all: + +include ../lib.mk + +.PHONY: all clean + +TARGETS := validate_cap test_execve +TEST_PROGS := test_execve + +CFLAGS := -O2 -g -std=gnu99 -Wall -lcap-ng + +all: $(TARGETS) + +clean: + $(RM) $(TARGETS) + +$(TARGETS): %: %.c + $(CC) -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl diff --git a/tools/testing/selftests/capabilities/test_execve.c b/tools/testing/selftests/capabilities/test_execve.c new file mode 100644 index 0000000000000..10a21a958aaf7 --- /dev/null +++ b/tools/testing/selftests/capabilities/test_execve.c @@ -0,0 +1,427 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PR_CAP_AMBIENT +#define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 +#endif + +static int nerrs; + +static void vmaybe_write_file(bool enoent_ok, char *filename, char *fmt, va_list ap) +{ + char buf[4096]; + int fd; + ssize_t written; + int buf_len; + + buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); + if (buf_len < 0) { + err(1, "vsnprintf failed"); + } + if (buf_len >= sizeof(buf)) { + errx(1, "vsnprintf output truncated"); + } + + fd = open(filename, O_WRONLY); + if (fd < 0) { + if ((errno == ENOENT) && enoent_ok) + return; + err(1, "open of %s failed", filename); + } + written = write(fd, buf, buf_len); + if (written != buf_len) { + if (written >= 0) { + errx(1, "short write to %s", filename); + } else { + err(1, "write to %s failed", filename); + } + } + if (close(fd) != 0) { + err(1, "close of %s failed", filename); + } +} + +static void maybe_write_file(char *filename, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmaybe_write_file(true, filename, fmt, ap); + va_end(ap); +} + +static void write_file(char *filename, char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vmaybe_write_file(false, filename, fmt, ap); + va_end(ap); +} + +static bool create_and_enter_ns(uid_t inner_uid) +{ + uid_t outer_uid; + gid_t outer_gid; + int i; + bool have_outer_privilege; + + outer_uid = getuid(); + outer_gid = getgid(); + + /* + * TODO: If we're already root, we could skip creating the userns. + */ + + if (unshare(CLONE_NEWNS) == 0) { + printf("[NOTE]\tUsing global UIDs for tests\n"); + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) != 0) + err(1, "PR_SET_KEEPCAPS"); + if (setresuid(inner_uid, inner_uid, -1) != 0) + err(1, "setresuid"); + + // Re-enable effective caps + capng_get_caps_process(); + for (i = 0; i < CAP_LAST_CAP; i++) + if (capng_have_capability(CAPNG_PERMITTED, i)) + capng_update(CAPNG_ADD, CAPNG_EFFECTIVE, i); + if (capng_apply(CAPNG_SELECT_CAPS) != 0) + err(1, "capng_apply"); + + have_outer_privilege = true; + } else if (unshare(CLONE_NEWUSER | CLONE_NEWNS) == 0) { + printf("[NOTE]\tUsing a user namespace for tests\n"); + maybe_write_file("/proc/self/setgroups", "deny"); + write_file("/proc/self/uid_map", "%d %d 1", inner_uid, outer_uid); + write_file("/proc/self/gid_map", "0 %d 1", outer_gid); + + have_outer_privilege = false; + } else { + errx(1, "must be root or be able to create a userns"); + } + + if (mount("none", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0) + err(1, "remount everything private"); + + return have_outer_privilege; +} + +static void chdir_to_tmpfs(void) +{ + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd)) != cwd) + err(1, "getcwd"); + + if (mount("private_tmp", ".", "tmpfs", 0, "mode=0777") != 0) + err(1, "mount private tmpfs"); + + if (chdir(cwd) != 0) + err(1, "chdir to private tmpfs"); + + if (umount2(".", MNT_DETACH) != 0) + err(1, "detach private tmpfs"); +} + +static void copy_fromat_to(int fromfd, const char *fromname, const char *toname) +{ + int from = openat(fromfd, fromname, O_RDONLY); + if (from == -1) + err(1, "open copy source"); + + int to = open(toname, O_CREAT | O_WRONLY | O_EXCL, 0700); + + while (true) { + char buf[4096]; + ssize_t sz = read(from, buf, sizeof(buf)); + if (sz == 0) + break; + if (sz < 0) + err(1, "read"); + + if (write(to, buf, sz) != sz) + err(1, "write"); /* no short writes on tmpfs */ + } + + close(from); + close(to); +} + +static bool fork_wait(void) +{ + pid_t child = fork(); + if (child == 0) { + nerrs = 0; + return true; + } else if (child > 0) { + int status; + if (waitpid(child, &status, 0) != child || + !WIFEXITED(status)) { + printf("[FAIL]\tChild died\n"); + nerrs++; + } else if (WEXITSTATUS(status) != 0) { + printf("[FAIL]\tChild failed\n"); + nerrs++; + } else { + printf("[OK]\tChild succeeded\n"); + } + + return false; + } else { + err(1, "fork"); + } +} + +static void exec_other_validate_cap(const char *name, + bool eff, bool perm, bool inh, bool ambient) +{ + execl(name, name, (eff ? "1" : "0"), + (perm ? "1" : "0"), (inh ? "1" : "0"), (ambient ? "1" : "0"), + NULL); + err(1, "execl"); +} + +static void exec_validate_cap(bool eff, bool perm, bool inh, bool ambient) +{ + exec_other_validate_cap("./validate_cap", eff, perm, inh, ambient); +} + +static int do_tests(int uid, const char *our_path) +{ + bool have_outer_privilege = create_and_enter_ns(uid); + + int ourpath_fd = open(our_path, O_RDONLY | O_DIRECTORY); + if (ourpath_fd == -1) + err(1, "open '%s'", our_path); + + chdir_to_tmpfs(); + + copy_fromat_to(ourpath_fd, "validate_cap", "validate_cap"); + + if (have_outer_privilege) { + uid_t gid = getegid(); + + copy_fromat_to(ourpath_fd, "validate_cap", + "validate_cap_suidroot"); + if (chown("validate_cap_suidroot", 0, -1) != 0) + err(1, "chown"); + if (chmod("validate_cap_suidroot", S_ISUID | 0700) != 0) + err(1, "chmod"); + + copy_fromat_to(ourpath_fd, "validate_cap", + "validate_cap_suidnonroot"); + if (chown("validate_cap_suidnonroot", uid + 1, -1) != 0) + err(1, "chown"); + if (chmod("validate_cap_suidnonroot", S_ISUID | 0700) != 0) + err(1, "chmod"); + + copy_fromat_to(ourpath_fd, "validate_cap", + "validate_cap_sgidroot"); + if (chown("validate_cap_sgidroot", -1, 0) != 0) + err(1, "chown"); + if (chmod("validate_cap_sgidroot", S_ISGID | 0710) != 0) + err(1, "chmod"); + + copy_fromat_to(ourpath_fd, "validate_cap", + "validate_cap_sgidnonroot"); + if (chown("validate_cap_sgidnonroot", -1, gid + 1) != 0) + err(1, "chown"); + if (chmod("validate_cap_sgidnonroot", S_ISGID | 0710) != 0) + err(1, "chmod"); +} + + capng_get_caps_process(); + + /* Make sure that i starts out clear */ + capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); + if (capng_apply(CAPNG_SELECT_CAPS) != 0) + err(1, "capng_apply"); + + if (uid == 0) { + printf("[RUN]\tRoot => ep\n"); + if (fork_wait()) + exec_validate_cap(true, true, false, false); + } else { + printf("[RUN]\tNon-root => no caps\n"); + if (fork_wait()) + exec_validate_cap(false, false, false, false); + } + + printf("[OK]\tCheck cap_ambient manipulation rules\n"); + + /* We should not be able to add ambient caps yet. */ + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != -1 || errno != EPERM) { + if (errno == EINVAL) + printf("[FAIL]\tPR_CAP_AMBIENT_RAISE isn't supported\n"); + else + printf("[FAIL]\tPR_CAP_AMBIENT_RAISE should have failed eith EPERM on a non-inheritable cap\n"); + return 1; + } + printf("[OK]\tPR_CAP_AMBIENT_RAISE failed on non-inheritable cap\n"); + + capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_RAW); + capng_update(CAPNG_DROP, CAPNG_PERMITTED, CAP_NET_RAW); + capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, CAP_NET_RAW); + if (capng_apply(CAPNG_SELECT_CAPS) != 0) + err(1, "capng_apply"); + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_RAW, 0, 0, 0) != -1 || errno != EPERM) { + printf("[FAIL]\tPR_CAP_AMBIENT_RAISE should have failed on a non-permitted cap\n"); + return 1; + } + printf("[OK]\tPR_CAP_AMBIENT_RAISE failed on non-permitted cap\n"); + + capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); + if (capng_apply(CAPNG_SELECT_CAPS) != 0) + err(1, "capng_apply"); + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { + printf("[FAIL]\tPR_CAP_AMBIENT_RAISE should have succeeded\n"); + return 1; + } + printf("[OK]\tPR_CAP_AMBIENT_RAISE worked\n"); + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 1) { + printf("[FAIL]\tPR_CAP_AMBIENT_IS_SET is broken\n"); + return 1; + } + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0) != 0) + err(1, "PR_CAP_AMBIENT_CLEAR_ALL"); + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { + printf("[FAIL]\tPR_CAP_AMBIENT_CLEAR_ALL didn't work\n"); + return 1; + } + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) + err(1, "PR_CAP_AMBIENT_RAISE"); + + capng_update(CAPNG_DROP, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); + if (capng_apply(CAPNG_SELECT_CAPS) != 0) + err(1, "capng_apply"); + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) { + printf("[FAIL]\tDropping I should have dropped A\n"); + return 1; + } + + printf("[OK]\tBasic manipulation appears to work\n"); + + capng_update(CAPNG_ADD, CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE); + if (capng_apply(CAPNG_SELECT_CAPS) != 0) + err(1, "capng_apply"); + if (uid == 0) { + printf("[RUN]\tRoot +i => eip\n"); + if (fork_wait()) + exec_validate_cap(true, true, true, false); + } else { + printf("[RUN]\tNon-root +i => i\n"); + if (fork_wait()) + exec_validate_cap(false, false, true, false); + } + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0) != 0) + err(1, "PR_CAP_AMBIENT_RAISE"); + + printf("[RUN]\tUID %d +ia => eipa\n", uid); + if (fork_wait()) + exec_validate_cap(true, true, true, true); + + /* The remaining tests need real privilege */ + + if (!have_outer_privilege) { + printf("[SKIP]\tSUID/SGID tests (needs privilege)\n"); + goto done; + } + + if (uid == 0) { + printf("[RUN]\tRoot +ia, suidroot => eipa\n"); + if (fork_wait()) + exec_other_validate_cap("./validate_cap_suidroot", + true, true, true, true); + + printf("[RUN]\tRoot +ia, suidnonroot => ip\n"); + if (fork_wait()) + exec_other_validate_cap("./validate_cap_suidnonroot", + false, true, true, false); + + printf("[RUN]\tRoot +ia, sgidroot => eipa\n"); + if (fork_wait()) + exec_other_validate_cap("./validate_cap_sgidroot", + true, true, true, true); + + if (fork_wait()) { + printf("[RUN]\tRoot, gid != 0, +ia, sgidroot => eip\n"); + if (setresgid(1, 1, 1) != 0) + err(1, "setresgid"); + exec_other_validate_cap("./validate_cap_sgidroot", + true, true, true, false); + } + + printf("[RUN]\tRoot +ia, sgidnonroot => eip\n"); + if (fork_wait()) + exec_other_validate_cap("./validate_cap_sgidnonroot", + true, true, true, false); + } else { + printf("[RUN]\tNon-root +ia, sgidnonroot => i\n"); + exec_other_validate_cap("./validate_cap_sgidnonroot", + false, false, true, false); + + if (fork_wait()) { + printf("[RUN]\tNon-root +ia, sgidroot => i\n"); + if (setresgid(1, 1, 1) != 0) + err(1, "setresgid"); + exec_other_validate_cap("./validate_cap_sgidroot", + false, false, true, false); + } + } + +done: + return nerrs ? 1 : 0; +} + +int main(int argc, char **argv) +{ + char *tmp1, *tmp2, *our_path; + + /* Find our path */ + tmp1 = strdup(argv[0]); + if (!tmp1) + err(1, "strdup"); + tmp2 = dirname(tmp1); + our_path = strdup(tmp2); + if (!our_path) + err(1, "strdup"); + free(tmp1); + + if (fork_wait()) { + printf("[RUN]\t+++ Tests with uid == 0 +++\n"); + return do_tests(0, our_path); + } + + if (fork_wait()) { + printf("[RUN]\t+++ Tests with uid != 0 +++\n"); + return do_tests(1, our_path); + } + + return nerrs ? 1 : 0; +} diff --git a/tools/testing/selftests/capabilities/validate_cap.c b/tools/testing/selftests/capabilities/validate_cap.c new file mode 100644 index 0000000000000..dd3c45f7b23cc --- /dev/null +++ b/tools/testing/selftests/capabilities/validate_cap.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef PR_CAP_AMBIENT +#define PR_CAP_AMBIENT 47 +# define PR_CAP_AMBIENT_IS_SET 1 +# define PR_CAP_AMBIENT_RAISE 2 +# define PR_CAP_AMBIENT_LOWER 3 +# define PR_CAP_AMBIENT_CLEAR_ALL 4 +#endif + +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 19) +# define HAVE_GETAUXVAL +#endif + +static bool bool_arg(char **argv, int i) +{ + if (!strcmp(argv[i], "0")) + return false; + else if (!strcmp(argv[i], "1")) + return true; + else + errx(1, "wrong argv[%d]", i); +} + +int main(int argc, char **argv) +{ + const char *atsec = ""; + + /* + * Be careful just in case a setgid or setcapped copy of this + * helper gets out. + */ + + if (argc != 5) + errx(1, "wrong argc"); + +#ifdef HAVE_GETAUXVAL + if (getauxval(AT_SECURE)) + atsec = " (AT_SECURE is set)"; + else + atsec = " (AT_SECURE is not set)"; +#endif + + capng_get_caps_process(); + + if (capng_have_capability(CAPNG_EFFECTIVE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 1)) { + printf("[FAIL]\tWrong effective state%s\n", atsec); + return 1; + } + if (capng_have_capability(CAPNG_PERMITTED, CAP_NET_BIND_SERVICE) != bool_arg(argv, 2)) { + printf("[FAIL]\tWrong permitted state%s\n", atsec); + return 1; + } + if (capng_have_capability(CAPNG_INHERITABLE, CAP_NET_BIND_SERVICE) != bool_arg(argv, 3)) { + printf("[FAIL]\tWrong inheritable state%s\n", atsec); + return 1; + } + + if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, CAP_NET_BIND_SERVICE, 0, 0, 0) != bool_arg(argv, 4)) { + printf("[FAIL]\tWrong ambient state%s\n", atsec); + return 1; + } + + printf("[OK]\tCapabilities after execve were correct\n"); + return 0; +} -- GitLab From 746bf6d64275be0c65b0631d8a72b16f1454cfa1 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 4 Sep 2015 15:42:51 -0700 Subject: [PATCH 6347/7006] capabilities: add a securebit to disable PR_CAP_AMBIENT_RAISE Per Andrew Morgan's request, add a securebit to allow admins to disable PR_CAP_AMBIENT_RAISE. This securebit will prevent processes from adding capabilities to their ambient set. For simplicity, this disables PR_CAP_AMBIENT_RAISE entirely rather than just disabling setting previously cleared bits. Signed-off-by: Andy Lutomirski Acked-by: Andrew G. Morgan Acked-by: Serge Hallyn Cc: Kees Cook Cc: Christoph Lameter Cc: Serge Hallyn Cc: Jonathan Corbet Cc: Aaron Jones Cc: Ted Ts'o Cc: Andrew G. Morgan Cc: Mimi Zohar Cc: Austin S Hemmelgarn Cc: Markku Savela Cc: Jarkko Sakkinen Cc: Michael Kerrisk Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/uapi/linux/securebits.h | 11 ++++++++++- security/commoncap.c | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/include/uapi/linux/securebits.h b/include/uapi/linux/securebits.h index 985aac9e6bf88..35ac35cef2170 100644 --- a/include/uapi/linux/securebits.h +++ b/include/uapi/linux/securebits.h @@ -43,9 +43,18 @@ #define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS)) #define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED)) +/* When set, a process cannot add new capabilities to its ambient set. */ +#define SECURE_NO_CAP_AMBIENT_RAISE 6 +#define SECURE_NO_CAP_AMBIENT_RAISE_LOCKED 7 /* make bit-6 immutable */ + +#define SECBIT_NO_CAP_AMBIENT_RAISE (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE)) +#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED \ + (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED)) + #define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ issecure_mask(SECURE_NO_SETUID_FIXUP) | \ - issecure_mask(SECURE_KEEP_CAPS)) + issecure_mask(SECURE_KEEP_CAPS) | \ + issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE)) #define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1) #endif /* _UAPI_LINUX_SECUREBITS_H */ diff --git a/security/commoncap.c b/security/commoncap.c index 1f74dde1063e5..1832cf701c3d6 100644 --- a/security/commoncap.c +++ b/security/commoncap.c @@ -993,7 +993,8 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, if (arg2 == PR_CAP_AMBIENT_RAISE && (!cap_raised(current_cred()->cap_permitted, arg3) || !cap_raised(current_cred()->cap_inheritable, - arg3))) + arg3) || + issecure(SECURE_NO_CAP_AMBIENT_RAISE))) return -EPERM; new = prepare_creds(); -- GitLab From 031e29b5877f31676739dc2f847d04c2c0732034 Mon Sep 17 00:00:00 2001 From: Yuriy Kolerov Date: Fri, 4 Sep 2015 15:42:58 -0700 Subject: [PATCH 6348/7006] drivers/video/concole: add negative dependency for VGA_CONSOLE on ARC Architectures which support VGA console must define screen_info structurture from "uapi/linux/screen_info.h". Otherwise undefined symbol error occurs. Usually it's defined in "setup.c" for each architecture. If an architecture does not support VGA console (ARC's case) there are 2 ways: define a dummy instance of screen_info or add a negative dependency for VGA_CONSOLE in to prevent selecting this option. I've implemented the second way. However the best solution is to add HAVE_VGA_CONSOLE option for targets which support VGA console. Then turn off VGA_CONSOLE by default and add dependency to HAVE_VGA_CONSOLE. But right now it's better to just add a negative dependency for ARC and then consider how to collaborate about this issue with maintainers of other architectures. Signed-off-by: Yuriy Kolerov Acked-by: Geert Uytterhoeven Cc: Jean-Christophe Plagniol-Villard Cc: Tomi Valkeinen Cc: Jaya Kumar Cc: Vineet Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig index ba97efc3bf707..071280643db75 100644 --- a/drivers/video/console/Kconfig +++ b/drivers/video/console/Kconfig @@ -9,7 +9,7 @@ config VGA_CONSOLE depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \ !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \ (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ - !ARM64 + !ARM64 && !ARC default y help Saying Y here will allow you to use Linux in text mode through a -- GitLab From 7c49b8616460ebb12ee56d80d1abfbc20b6f3cbb Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Fri, 4 Sep 2015 15:43:01 -0700 Subject: [PATCH 6349/7006] fs/notify: optimize inotify/fsnotify code for unwatched files I have a _tiny_ microbenchmark that sits in a loop and writes single bytes to a file. Writing one byte to a tmpfs file is around 2x slower than reading one byte from a file, which is a _bit_ more than I expecte. This is a dumb benchmark, but I think it's hard to deny that write() is a hot path and we should avoid unnecessary overhead there. I did a 'perf record' of 30-second samples of read and write. The top item in a diffprofile is srcu_read_lock() from fsnotify(). There are active inotify fd's from systemd, but nothing is actually listening to the file or its part of the filesystem. I *think* we can avoid taking the srcu_read_lock() for the common case where there are no actual marks on the file. This means that there will both be nothing to notify for *and* implies that there is no need for clearing the ignore mask. This patch gave a 13.1% speedup in writes/second on my test, which is an improvement from the 10.8% that I saw with the last version. Signed-off-by: Dave Hansen Reviewed-by: Jan Kara Cc: Al Viro Cc: Eric Paris Cc: John McCutchan Cc: Robert Love Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/notify/fsnotify.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index dd3fb0b17be7c..d675e76251d36 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -204,6 +204,16 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, else mnt = NULL; + /* + * Optimization: srcu_read_lock() has a memory barrier which can + * be expensive. It protects walking the *_fsnotify_marks lists. + * However, if we do not walk the lists, we do not have to do + * SRCU because we have no references to any objects and do not + * need SRCU to keep them "alive". + */ + if (hlist_empty(&to_tell->i_fsnotify_marks) && + (!mnt || hlist_empty(&mnt->mnt_fsnotify_marks))) + return 0; /* * if this is a modify event we may need to clear the ignored masks * otherwise return if neither the inode nor the vfsmount care about -- GitLab From 3c53e514212455db9923c203694a72007558b48f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 4 Sep 2015 15:43:03 -0700 Subject: [PATCH 6350/7006] fsnotify: fix check in inotify fdinfo printing A check in inotify_fdinfo() checking whether mark is valid was always true due to a bug. Luckily we can never get to invalidated marks since we hold mark_mutex and invalidated marks get removed from the group list when they are invalidated under that mutex. Anyway fix the check to make code more future proof. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/notify/fdinfo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c index 58b7cdb63da9f..6b6f0d472ae81 100644 --- a/fs/notify/fdinfo.c +++ b/fs/notify/fdinfo.c @@ -76,7 +76,8 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark) struct inotify_inode_mark *inode_mark; struct inode *inode; - if (!(mark->flags & (FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_INODE))) + if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE) || + !(mark->flags & FSNOTIFY_MARK_FLAG_INODE)) return; inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark); -- GitLab From 1e39fc01836d02a11515aaabd97a0a938326bfe2 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 4 Sep 2015 15:43:06 -0700 Subject: [PATCH 6351/7006] fsnotify: document mark locking Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/fsnotify_backend.h | 50 +++++++++++++++++++------------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index 65a517dd32f7a..dd6ddb0287eda 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -195,40 +195,50 @@ struct fsnotify_group { #define FSNOTIFY_EVENT_INODE 2 /* - * a mark is simply an object attached to an in core inode which allows an + * A mark is simply an object attached to an in core inode which allows an * fsnotify listener to indicate they are either no longer interested in events * of a type matching mask or only interested in those events. * - * these are flushed when an inode is evicted from core and may be flushed - * when the inode is modified (as seen by fsnotify_access). Some fsnotify users - * (such as dnotify) will flush these when the open fd is closed and not at - * inode eviction or modification. + * These are flushed when an inode is evicted from core and may be flushed + * when the inode is modified (as seen by fsnotify_access). Some fsnotify + * users (such as dnotify) will flush these when the open fd is closed and not + * at inode eviction or modification. + * + * Text in brackets is showing the lock(s) protecting modifications of a + * particular entry. obj_lock means either inode->i_lock or + * mnt->mnt_root->d_lock depending on the mark type. */ struct fsnotify_mark { - __u32 mask; /* mask this mark is for */ - /* we hold ref for each i_list and g_list. also one ref for each 'thing' + /* Mask this mark is for [mark->lock, group->mark_mutex] */ + __u32 mask; + /* We hold one for presence in g_list. Also one ref for each 'thing' * in kernel that found and may be using this mark. */ - atomic_t refcnt; /* active things looking at this mark */ - struct fsnotify_group *group; /* group this mark is for */ - struct list_head g_list; /* list of marks by group->i_fsnotify_marks - * Also reused for queueing mark into - * destroy_list when it's waiting for - * the end of SRCU period before it can - * be freed */ - spinlock_t lock; /* protect group and inode */ - struct hlist_node obj_list; /* list of marks for inode / vfsmount */ - struct list_head free_list; /* tmp list used when freeing this mark */ - union { + atomic_t refcnt; + /* Group this mark is for. Set on mark creation, stable until last ref + * is dropped */ + struct fsnotify_group *group; + /* List of marks by group->i_fsnotify_marks. Also reused for queueing + * mark into destroy_list when it's waiting for the end of SRCU period + * before it can be freed. [group->mark_mutex] */ + struct list_head g_list; + /* Protects inode / mnt pointers, flags, masks */ + spinlock_t lock; + /* List of marks for inode / vfsmount [obj_lock] */ + struct hlist_node obj_list; + /* tmp list used when freeing this mark */ + struct list_head free_list; + union { /* Object pointer [mark->lock, group->mark_mutex] */ struct inode *inode; /* inode this mark is associated with */ struct vfsmount *mnt; /* vfsmount this mark is associated with */ }; - __u32 ignored_mask; /* events types to ignore */ + /* Events types to ignore [mark->lock, group->mark_mutex] */ + __u32 ignored_mask; #define FSNOTIFY_MARK_FLAG_INODE 0x01 #define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 #define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04 #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08 #define FSNOTIFY_MARK_FLAG_ALIVE 0x10 - unsigned int flags; /* vfsmount or inode mark? */ + unsigned int flags; /* flags [mark->lock] */ void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */ }; -- GitLab From 925d1132a03e33cb8f29a0057300d023b4f1be23 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 4 Sep 2015 15:43:09 -0700 Subject: [PATCH 6352/7006] fsnotify: remove mark->free_list Free list is used when all marks on given inode / mount should be destroyed when inode / mount is going away. However we can free all of the marks without using a special list with some care. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/notify/fsnotify.c | 1 - fs/notify/fsnotify.h | 21 ++++++++++++----- fs/notify/inode_mark.c | 20 ---------------- fs/notify/mark.c | 40 ++++++++++++++++++++------------ fs/notify/vfsmount_mark.c | 19 --------------- include/linux/fsnotify_backend.h | 2 -- 6 files changed, 40 insertions(+), 63 deletions(-) diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index d675e76251d36..db39de2dd4cbc 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c @@ -26,7 +26,6 @@ #include #include "fsnotify.h" -#include "../mount.h" /* * Clear all of the marks on an inode when it is being evicted from core diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 13a00be516d25..b44c68a857e77 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h @@ -6,6 +6,8 @@ #include #include +#include "../mount.h" + /* destroy all events sitting in this groups notification queue */ extern void fsnotify_flush_notify(struct fsnotify_group *group); @@ -38,15 +40,22 @@ extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark); /* inode specific destruction of a mark */ extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark); -/* Destroy all marks in the given list */ -extern void fsnotify_destroy_marks(struct list_head *to_free); /* Find mark belonging to given group in the list of marks */ extern struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head, struct fsnotify_group *group); -/* run the list of all marks associated with inode and flag them to be freed */ -extern void fsnotify_clear_marks_by_inode(struct inode *inode); -/* run the list of all marks associated with vfsmount and flag them to be freed */ -extern void fsnotify_clear_marks_by_mount(struct vfsmount *mnt); +/* Destroy all marks in the given list protected by 'lock' */ +extern void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock); +/* run the list of all marks associated with inode and destroy them */ +static inline void fsnotify_clear_marks_by_inode(struct inode *inode) +{ + fsnotify_destroy_marks(&inode->i_fsnotify_marks, &inode->i_lock); +} +/* run the list of all marks associated with vfsmount and destroy them */ +static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) +{ + fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks, + &mnt->mnt_root->d_lock); +} /* * update the dentry->d_flags of all of inode's children to indicate if inode cares * about events that happen to its children. diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 3daf513ee99e6..474a3ce1b5e10 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c @@ -64,26 +64,6 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) spin_unlock(&inode->i_lock); } -/* - * Given an inode, destroy all of the marks associated with that inode. - */ -void fsnotify_clear_marks_by_inode(struct inode *inode) -{ - struct fsnotify_mark *mark; - struct hlist_node *n; - LIST_HEAD(free_list); - - spin_lock(&inode->i_lock); - hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, obj_list) { - list_add(&mark->free_list, &free_list); - hlist_del_init_rcu(&mark->obj_list); - fsnotify_get_mark(mark); - } - spin_unlock(&inode->i_lock); - - fsnotify_destroy_marks(&free_list); -} - /* * Given a group clear all of the inode marks associated with that group. */ diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 39ddcaf0918f1..3b2d1ba41e7bc 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -203,24 +203,34 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark, mutex_unlock(&group->mark_mutex); } -/* - * Destroy all marks in the given list. The marks must be already detached from - * the original inode / vfsmount. - */ -void fsnotify_destroy_marks(struct list_head *to_free) +void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock) { - struct fsnotify_mark *mark, *lmark; - struct fsnotify_group *group; - - list_for_each_entry_safe(mark, lmark, to_free, free_list) { - spin_lock(&mark->lock); - fsnotify_get_group(mark->group); - group = mark->group; - spin_unlock(&mark->lock); + struct fsnotify_mark *mark; - fsnotify_destroy_mark(mark, group); + while (1) { + /* + * We have to be careful since we can race with e.g. + * fsnotify_clear_marks_by_group() and once we drop 'lock', + * mark can get removed from the obj_list and destroyed. But + * we are holding mark reference so mark cannot be freed and + * calling fsnotify_destroy_mark() more than once is fine. + */ + spin_lock(lock); + if (hlist_empty(head)) { + spin_unlock(lock); + break; + } + mark = hlist_entry(head->first, struct fsnotify_mark, obj_list); + /* + * We don't update i_fsnotify_mask / mnt_fsnotify_mask here + * since inode / mount is going away anyway. So just remove + * mark from the list. + */ + hlist_del_init_rcu(&mark->obj_list); + fsnotify_get_mark(mark); + spin_unlock(lock); + fsnotify_destroy_mark(mark, mark->group); fsnotify_put_mark(mark); - fsnotify_put_group(group); } } diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c index 326b148e623cd..a8fcab68faef1 100644 --- a/fs/notify/vfsmount_mark.c +++ b/fs/notify/vfsmount_mark.c @@ -28,25 +28,6 @@ #include #include "fsnotify.h" -#include "../mount.h" - -void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) -{ - struct fsnotify_mark *mark; - struct hlist_node *n; - struct mount *m = real_mount(mnt); - LIST_HEAD(free_list); - - spin_lock(&mnt->mnt_root->d_lock); - hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, obj_list) { - list_add(&mark->free_list, &free_list); - hlist_del_init_rcu(&mark->obj_list); - fsnotify_get_mark(mark); - } - spin_unlock(&mnt->mnt_root->d_lock); - - fsnotify_destroy_marks(&free_list); -} void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) { diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index dd6ddb0287eda..f044fe30e8c35 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -225,8 +225,6 @@ struct fsnotify_mark { spinlock_t lock; /* List of marks for inode / vfsmount [obj_lock] */ struct hlist_node obj_list; - /* tmp list used when freeing this mark */ - struct list_head free_list; union { /* Object pointer [mark->lock, group->mark_mutex] */ struct inode *inode; /* inode this mark is associated with */ struct vfsmount *mnt; /* vfsmount this mark is associated with */ -- GitLab From 4712e722f91457e60723b9cef6265a74290efba9 Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Fri, 4 Sep 2015 15:43:12 -0700 Subject: [PATCH 6353/7006] fsnotify: get rid of fsnotify_destroy_mark_locked() fsnotify_destroy_mark_locked() is subtle to use because it temporarily releases group->mark_mutex. To avoid future problems with this function, split it into two. fsnotify_detach_mark() is the part that needs group->mark_mutex and fsnotify_free_mark() is the part that must be called outside of group->mark_mutex. This way it's much clearer what's going on and we also avoid some pointless acquisitions of group->mark_mutex. Signed-off-by: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/notify/dnotify/dnotify.c | 14 ++++-- fs/notify/fanotify/fanotify_user.c | 8 +++- fs/notify/mark.c | 73 ++++++++++++++++-------------- include/linux/fsnotify_backend.h | 7 ++- 4 files changed, 61 insertions(+), 41 deletions(-) diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 44523f4a60841..6faaf710e563e 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c @@ -154,6 +154,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id) struct dnotify_struct *dn; struct dnotify_struct **prev; struct inode *inode; + bool free = false; inode = file_inode(filp); if (!S_ISDIR(inode->i_mode)) @@ -182,11 +183,15 @@ void dnotify_flush(struct file *filp, fl_owner_t id) /* nothing else could have found us thanks to the dnotify_groups mark_mutex */ - if (dn_mark->dn == NULL) - fsnotify_destroy_mark_locked(fsn_mark, dnotify_group); + if (dn_mark->dn == NULL) { + fsnotify_detach_mark(fsn_mark); + free = true; + } mutex_unlock(&dnotify_group->mark_mutex); + if (free) + fsnotify_free_mark(fsn_mark); fsnotify_put_mark(fsn_mark); } @@ -362,9 +367,10 @@ out: spin_unlock(&fsn_mark->lock); if (destroy) - fsnotify_destroy_mark_locked(fsn_mark, dnotify_group); - + fsnotify_detach_mark(fsn_mark); mutex_unlock(&dnotify_group->mark_mutex); + if (destroy) + fsnotify_free_mark(fsn_mark); fsnotify_put_mark(fsn_mark); out_err: if (new_fsn_mark) diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c index cf275500a6658..8e8e6bcd1d43d 100644 --- a/fs/notify/fanotify/fanotify_user.c +++ b/fs/notify/fanotify/fanotify_user.c @@ -529,8 +529,10 @@ static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, &destroy_mark); if (destroy_mark) - fsnotify_destroy_mark_locked(fsn_mark, group); + fsnotify_detach_mark(fsn_mark); mutex_unlock(&group->mark_mutex); + if (destroy_mark) + fsnotify_free_mark(fsn_mark); fsnotify_put_mark(fsn_mark); if (removed & real_mount(mnt)->mnt_fsnotify_mask) @@ -557,8 +559,10 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group, removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags, &destroy_mark); if (destroy_mark) - fsnotify_destroy_mark_locked(fsn_mark, group); + fsnotify_detach_mark(fsn_mark); mutex_unlock(&group->mark_mutex); + if (destroy_mark) + fsnotify_free_mark(fsn_mark); /* matches the fsnotify_find_inode_mark() */ fsnotify_put_mark(fsn_mark); diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 3b2d1ba41e7bc..fc0df4442f7b4 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -122,26 +122,27 @@ u32 fsnotify_recalc_mask(struct hlist_head *head) } /* - * Any time a mark is getting freed we end up here. - * The caller had better be holding a reference to this mark so we don't actually - * do the final put under the mark->lock + * Remove mark from inode / vfsmount list, group list, drop inode reference + * if we got one. + * + * Must be called with group->mark_mutex held. */ -void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, - struct fsnotify_group *group) +void fsnotify_detach_mark(struct fsnotify_mark *mark) { struct inode *inode = NULL; + struct fsnotify_group *group = mark->group; BUG_ON(!mutex_is_locked(&group->mark_mutex)); spin_lock(&mark->lock); /* something else already called this function on this mark */ - if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { + if (!(mark->flags & FSNOTIFY_MARK_FLAG_ATTACHED)) { spin_unlock(&mark->lock); return; } - mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; + mark->flags &= ~FSNOTIFY_MARK_FLAG_ATTACHED; if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { inode = mark->inode; @@ -150,6 +151,12 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, fsnotify_destroy_vfsmount_mark(mark); else BUG(); + /* + * Note that we didn't update flags telling whether inode cares about + * what's happening with children. We update these flags from + * __fsnotify_parent() lazily when next event happens on one of our + * children. + */ list_del_init(&mark->g_list); @@ -157,18 +164,32 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) iput(inode); - /* release lock temporarily */ - mutex_unlock(&group->mark_mutex); + + atomic_dec(&group->num_marks); +} + +/* + * Free fsnotify mark. The freeing is actually happening from a kthread which + * first waits for srcu period end. Caller must have a reference to the mark + * or be protected by fsnotify_mark_srcu. + */ +void fsnotify_free_mark(struct fsnotify_mark *mark) +{ + struct fsnotify_group *group = mark->group; + + spin_lock(&mark->lock); + /* something else already called this function on this mark */ + if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { + spin_unlock(&mark->lock); + return; + } + mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; + spin_unlock(&mark->lock); spin_lock(&destroy_lock); list_add(&mark->g_list, &destroy_list); spin_unlock(&destroy_lock); wake_up(&destroy_waitq); - /* - * We don't necessarily have a ref on mark from caller so the above destroy - * may have actually freed it, unless this group provides a 'freeing_mark' - * function which must be holding a reference. - */ /* * Some groups like to know that marks are being freed. This is a @@ -177,30 +198,15 @@ void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, */ if (group->ops->freeing_mark) group->ops->freeing_mark(mark, group); - - /* - * __fsnotify_update_child_dentry_flags(inode); - * - * I really want to call that, but we can't, we have no idea if the inode - * still exists the second we drop the mark->lock. - * - * The next time an event arrive to this inode from one of it's children - * __fsnotify_parent will see that the inode doesn't care about it's - * children and will update all of these flags then. So really this - * is just a lazy update (and could be a perf win...) - */ - - atomic_dec(&group->num_marks); - - mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); } void fsnotify_destroy_mark(struct fsnotify_mark *mark, struct fsnotify_group *group) { mutex_lock_nested(&group->mark_mutex, SINGLE_DEPTH_NESTING); - fsnotify_destroy_mark_locked(mark, group); + fsnotify_detach_mark(mark); mutex_unlock(&group->mark_mutex); + fsnotify_free_mark(mark); } void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock) @@ -342,7 +348,7 @@ int fsnotify_add_mark_locked(struct fsnotify_mark *mark, * inode->i_lock */ spin_lock(&mark->lock); - mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; + mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_ATTACHED; fsnotify_get_group(group); mark->group = group; @@ -448,8 +454,9 @@ void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, } mark = list_first_entry(&to_free, struct fsnotify_mark, g_list); fsnotify_get_mark(mark); - fsnotify_destroy_mark_locked(mark, group); + fsnotify_detach_mark(mark); mutex_unlock(&group->mark_mutex); + fsnotify_free_mark(mark); fsnotify_put_mark(mark); } } diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h index f044fe30e8c35..e0727d77feafb 100644 --- a/include/linux/fsnotify_backend.h +++ b/include/linux/fsnotify_backend.h @@ -236,6 +236,7 @@ struct fsnotify_mark { #define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04 #define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08 #define FSNOTIFY_MARK_FLAG_ALIVE 0x10 +#define FSNOTIFY_MARK_FLAG_ATTACHED 0x20 unsigned int flags; /* flags [mark->lock] */ void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */ }; @@ -353,8 +354,10 @@ extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_ /* given a group and a mark, flag mark to be freed when all references are dropped */ extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, struct fsnotify_group *group); -extern void fsnotify_destroy_mark_locked(struct fsnotify_mark *mark, - struct fsnotify_group *group); +/* detach mark from inode / mount list, group list, drop inode reference */ +extern void fsnotify_detach_mark(struct fsnotify_mark *mark); +/* free mark */ +extern void fsnotify_free_mark(struct fsnotify_mark *mark); /* run all the marks in a group, and clear all of the vfsmount marks */ extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); /* run all the marks in a group, and clear all of the inode marks */ -- GitLab From 779a6ce877bf711323f998b3a7382cdbe7350d87 Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 4 Sep 2015 15:43:15 -0700 Subject: [PATCH 6354/7006] scripts/spelling.txt: add misspelled words for check misspelled words for check:- chcek chck cehck I myself did these spell mistakes in changelog for patches, Thus suggesting to add in spelling.txt, so that checkpatch.pl warns it earlier. References:- ./arch/powerpc/kernel/exceptions-64e.S:456: . . . make sure you chcek https://lkml.org/lkml/2015/6/25/289 ./arch/x86/mm/pageattr.c:1368: * No need to cehck in that case [akpm@linux-foundation.org: add whcih->which, whcih I always get wrong] Signed-off-by: Maninder Singh Acked-by: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/spelling.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index bb8e4d0a19119..4bd8d1a3415f3 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -187,6 +187,7 @@ capatibilities||capabilities carefuly||carefully cariage||carriage catagory||category +cehck||check challange||challenge challanges||challenges chanell||channel @@ -199,6 +200,8 @@ charactor||character charater||character charaters||characters charcter||character +chcek||check +chck||check checksuming||checksumming childern||children childs||children @@ -1028,6 +1031,7 @@ visiters||visitors vitual||virtual wating||waiting whataver||whatever +whcih||which whenver||whenever wheter||whether whe||when -- GitLab From c22b6ae69ee93c1ecc6821847a8542163fbf3e1a Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Fri, 4 Sep 2015 15:43:18 -0700 Subject: [PATCH 6355/7006] scripts/spelling.txt: spelling of uninitialized I just did a spelling mistake of uninitialized and wrote that as unintialized. Fortunately I noticed it in my final review. Signed-off-by: Sudip Mukherjee Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/spelling.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index 4bd8d1a3415f3..bf30d2c0ec274 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -990,6 +990,7 @@ unexpectd||unexpected unexpeted||unexpected unfortunatelly||unfortunately unifiy||unify +unintialized||uninitialized unknonw||unknown unknow||unknown unkown||unknown -- GitLab From d40e1e6532efbb40f8fc1f5af093063a3d186754 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 4 Sep 2015 15:43:21 -0700 Subject: [PATCH 6356/7006] kerneldoc: Convert error messages to GNU error message format Editors like emacs and vi recognize a number of error message formats. The format used by the kerneldoc tool is not recognized by emacs. Change the kerneldoc error message format to the GNU style such that the emacs prev-error and next-error commands can be used to navigate through kerneldoc error messages. For more information about the GNU error message format, see also https://www.gnu.org/prep/standards/html_node/Errors.html. This patch has been generated via the following sed command: sed -i.orig 's/Error(\${file}:\$.):/\${file}:\$.: error:/g;s/Warning(\${file}:\$.):/\${file}:\$.: warning:/g;s/Warning(\${file}):/\${file}:1: warning:/g;s/Info(\${file}:\$.):/\${file}:\$.: info:/g' scripts/kernel-doc Signed-off-by: Bart Van Assche Cc: Johannes Berg Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/kernel-doc | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/scripts/kernel-doc b/scripts/kernel-doc index a7bf5f68aacb2..9a08fb5c1af64 100755 --- a/scripts/kernel-doc +++ b/scripts/kernel-doc @@ -469,7 +469,7 @@ sub dump_section { } else { # print STDERR "other section '$name' = '$contents'\n"; if (defined($sections{$name}) && ($sections{$name} ne "")) { - print STDERR "Error(${file}:$.): duplicate section name '$name'\n"; + print STDERR "${file}:$.: error: duplicate section name '$name'\n"; ++$errors; } $sections{$name} = $contents; @@ -1820,7 +1820,7 @@ sub dump_struct($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse struct or union!\n"; + print STDERR "${file}:$.: error: Cannot parse struct or union!\n"; ++$errors; } } @@ -1841,7 +1841,7 @@ sub dump_enum($$) { push @parameterlist, $arg; if (!$parameterdescs{$arg}) { $parameterdescs{$arg} = $undescribed; - print STDERR "Warning(${file}:$.): Enum value '$arg' ". + print STDERR "${file}:$.: warning: Enum value '$arg' ". "not described in enum '$declaration_name'\n"; } @@ -1859,7 +1859,7 @@ sub dump_enum($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse enum!\n"; + print STDERR "${file}:$.: error: Cannot parse enum!\n"; ++$errors; } } @@ -1887,7 +1887,7 @@ sub dump_typedef($$) { }); } else { - print STDERR "Error(${file}:$.): Cannot parse typedef!\n"; + print STDERR "${file}:$.: error: Cannot parse typedef!\n"; ++$errors; } } @@ -2019,11 +2019,11 @@ sub push_parameter($$$) { $parameterdescs{$param_name} = $undescribed; if (($type eq 'function') || ($type eq 'enum')) { - print STDERR "Warning(${file}:$.): Function parameter ". + print STDERR "${file}:$.: warning: Function parameter ". "or member '$param' not " . "described in '$declaration_name'\n"; } - print STDERR "Warning(${file}:$.):" . + print STDERR "${file}:$.: warning:" . " No description found for parameter '$param'\n"; ++$warnings; } @@ -2074,14 +2074,14 @@ sub check_sections($$$$$$) { } if ($err) { if ($decl_type eq "function") { - print STDERR "Warning(${file}:$.): " . + print STDERR "${file}:$.: warning: " . "Excess function parameter " . "'$sects[$sx]' " . "description in '$decl_name'\n"; ++$warnings; } else { if ($nested !~ m/\Q$sects[$sx]\E/) { - print STDERR "Warning(${file}:$.): " . + print STDERR "${file}:$.: warning: " . "Excess struct/union/enum/typedef member " . "'$sects[$sx]' " . "description in '$decl_name'\n"; @@ -2107,7 +2107,7 @@ sub check_return_section { if (!defined($sections{$section_return}) || $sections{$section_return} eq "") { - print STDERR "Warning(${file}:$.): " . + print STDERR "${file}:$.: warning: " . "No description found for return value of " . "'$declaration_name'\n"; ++$warnings; @@ -2186,7 +2186,7 @@ sub dump_function($$) { create_parameterlist($args, ',', $file); } else { - print STDERR "Warning(${file}:$.): cannot understand function prototype: '$prototype'\n"; + print STDERR "${file}:$.: warning: cannot understand function prototype: '$prototype'\n"; return; } @@ -2251,7 +2251,7 @@ sub tracepoint_munge($) { $tracepointargs = $1; } if (($tracepointname eq 0) || ($tracepointargs eq 0)) { - print STDERR "Warning(${file}:$.): Unrecognized tracepoint format: \n". + print STDERR "${file}:$.: warning: Unrecognized tracepoint format: \n". "$prototype\n"; } else { $prototype = "static inline void trace_$tracepointname($tracepointargs)"; @@ -2450,7 +2450,7 @@ sub process_file($) { } if (($declaration_purpose eq "") && $verbose) { - print STDERR "Warning(${file}:$.): missing initial short description on line:\n"; + print STDERR "${file}:$.: warning: missing initial short description on line:\n"; print STDERR $_; ++$warnings; } @@ -2468,10 +2468,10 @@ sub process_file($) { } if ($verbose) { - print STDERR "Info(${file}:$.): Scanning doc for $identifier\n"; + print STDERR "${file}:$.: info: Scanning doc for $identifier\n"; } } else { - print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.", + print STDERR "${file}:$.: warning: Cannot understand $_ on line $.", " - I thought it was a doc line\n"; ++$warnings; $state = 0; @@ -2483,7 +2483,7 @@ sub process_file($) { if (($contents ne "") && ($contents ne "\n")) { if (!$in_doc_sect && $verbose) { - print STDERR "Warning(${file}:$.): contents before sections\n"; + print STDERR "${file}:$.: warning: contents before sections\n"; ++$warnings; } dump_section($file, $section, xml_escape($contents)); @@ -2509,7 +2509,7 @@ sub process_file($) { } # look for doc_com + + doc_end: if ($_ =~ m'\s*\*\s*[a-zA-Z_0-9:\.]+\*/') { - print STDERR "Warning(${file}:$.): suspicious ending line: $_"; + print STDERR "${file}:$.: warning: suspicious ending line: $_"; ++$warnings; } @@ -2539,7 +2539,7 @@ sub process_file($) { } } else { # i dont know - bad line? ignore. - print STDERR "Warning(${file}:$.): bad line: $_"; + print STDERR "${file}:$.: warning: bad line: $_"; ++$warnings; } } elsif ($state == 5) { # scanning for split parameters @@ -2631,7 +2631,7 @@ sub process_file($) { } } if ($initial_section_counter == $section_counter) { - print STDERR "Warning(${file}): no structured comments found\n"; + print STDERR "${file}:1: warning: no structured comments found\n"; if (($function_only == 1) && ($show_not_found == 1)) { print STDERR " Was looking for '$_'.\n" for keys %function_table; } -- GitLab From fa70900e0984792cc45a9e51c28684c3287058c2 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 4 Sep 2015 15:43:24 -0700 Subject: [PATCH 6357/7006] scripts/Lindent: handle missing indent gracefully If indent is not found, bail out immediately instead of spitting random shell script error messages. Signed-off-by: Jean Delvare Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/Lindent | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/Lindent b/scripts/Lindent index 9c4b3e2b7098a..6d889de4e70b6 100755 --- a/scripts/Lindent +++ b/scripts/Lindent @@ -1,6 +1,9 @@ #!/bin/sh PARAM="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1" RES=`indent --version` +if [ "$RES" = "" ]; then + exit 1 +fi V1=`echo $RES | cut -d' ' -f3 | cut -d'.' -f1` V2=`echo $RES | cut -d' ' -f3 | cut -d'.' -f2` V3=`echo $RES | cut -d' ' -f3 | cut -d'.' -f3` -- GitLab From e260fe01fa39eddb05bd8b70fad5bc9a129648f2 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 4 Sep 2015 15:43:26 -0700 Subject: [PATCH 6358/7006] scripts: decode_stacktrace: fix ARM architecture decoding Fix the stack decoder for the ARM architecture. An ARM stack is designed as : [ 81.547704] [] (bucket_find_contain) from [] (check_sync+0x40/0x4f8) [ 81.559668] [] (check_sync) from [] (debug_dma_sync_sg_for_cpu+0x128/0x194) [ 81.571583] [] (debug_dma_sync_sg_for_cpu) from [] (__videobuf_s The current script doesn't expect the symbols to be bound by parenthesis, and triggers the following errors : awk: cmd. line:1: error: Unmatched ( or \(: / (check_sync$/ [ 81.547704] (bucket_find_contain) from (check_sync+0x40/0x4f8) Fix it by chopping starting and ending parenthesis from the each symbol name. As a side note, this probably comes from the function dump_backtrace_entry(), which is implemented differently for each architecture. That makes a single decoding script a bit a challenge. Signed-off-by: Robert Jarzmik Cc: Sasha Levin Cc: Russell King Cc: Michal Marek Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/decode_stacktrace.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/decode_stacktrace.sh b/scripts/decode_stacktrace.sh index 515c4c00e957c..00d6d53c2681d 100755 --- a/scripts/decode_stacktrace.sh +++ b/scripts/decode_stacktrace.sh @@ -14,11 +14,14 @@ declare -A cache parse_symbol() { # The structure of symbol at this point is: - # [name]+[offset]/[total length] + # ([name]+[offset]/[total length]) # # For example: # do_basic_setup+0x9c/0xbf + # Remove the englobing parenthesis + symbol=${symbol#\(} + symbol=${symbol%\)} # Strip the symbol name so that we could look it up local name=${symbol%+*} -- GitLab From 35108d71383c5f4abc286430c0b5da79d22553f9 Mon Sep 17 00:00:00 2001 From: Zhao Lei Date: Fri, 4 Sep 2015 15:43:29 -0700 Subject: [PATCH 6359/7006] scripts/spelling.txt: add some typo-words I wrote a small script to show word-pair from all linux spelling-typo commits, and get following result by sort | uniq -c: 181 occured -> occurred 78 transfered -> transferred 67 recieved -> received 65 dependant -> dependent 58 wether -> whether 56 accomodate -> accommodate 54 occured -> occurred 51 recieve -> receive 47 cant -> can't 40 sucessfully -> successfully ... Some of them are not in spelling.txt, this patch adds the most common word-pairs into spelling.txt. Signed-off-by: Zhao Lei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/spelling.txt | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/scripts/spelling.txt b/scripts/spelling.txt index bf30d2c0ec274..946caf3bd694e 100644 --- a/scripts/spelling.txt +++ b/scripts/spelling.txt @@ -32,6 +32,7 @@ accoring||according accout||account accquire||acquire accquired||acquired +accross||across acessable||accessible acess||access achitecture||architecture @@ -100,8 +101,10 @@ appropiate||appropriate appropriatly||appropriately approriate||appropriate approriately||appropriately +apropriate||appropriate aquainted||acquainted aquired||acquired +aquisition||acquisition arbitary||arbitrary architechture||architecture arguement||argument @@ -111,6 +114,8 @@ arne't||aren't arraival||arrival artifical||artificial artillary||artillery +asign||assign +assertation||assertion assiged||assigned assigment||assignment assigments||assignments @@ -136,6 +141,7 @@ automatize||automate automatized||automated automatizes||automates autonymous||autonomous +auxillary||auxiliary auxilliary||auxiliary avaiable||available avaible||available @@ -234,6 +240,8 @@ compatability||compatibility compatable||compatible compatibiliy||compatibility compatibilty||compatibility +compatiblity||compatibility +competion||completion compilant||compliant compleatly||completely completly||completely @@ -294,6 +302,7 @@ defferred||deferred definate||definite definately||definitely defintion||definition +defintions||definitions defualt||default defult||default deivce||device @@ -309,6 +318,7 @@ depreacted||deprecated depreacte||deprecate desactivate||deactivate desciptors||descriptors +descripton||description descrition||description descritptor||descriptor desctiptor||descriptor @@ -330,6 +340,7 @@ devided||divided deviece||device diable||disable dictionnary||dictionary +didnt||didn't diferent||different differrence||difference difinition||definition @@ -347,6 +358,7 @@ docuentation||documentation documantation||documentation documentaion||documentation documment||document +doesnt||doesn't dorp||drop dosen||doesn downlad||download @@ -453,11 +465,13 @@ grahical||graphical grahpical||graphical grapic||graphic guage||gauge +guarenteed||guaranteed guarentee||guarantee halfs||halves hander||handler handfull||handful hanled||handled +happend||happened harware||hardware heirarchically||hierarchically helpfull||helpful @@ -515,6 +529,7 @@ initialzed||initialized initilization||initialization initilize||initialize inofficial||unofficial +insititute||institute instal||install inteface||interface integreated||integrated @@ -549,6 +564,7 @@ invididual||individual invokation||invocation invokations||invocations irrelevent||irrelevant +isnt||isn't isssue||issue itslef||itself jave||java @@ -561,6 +577,7 @@ langauage||language langauge||language langugage||language lauch||launch +layed||laid leightweight||lightweight lengh||length lenght||length @@ -717,6 +734,7 @@ preceeding||preceding preceed||precede precendence||precedence precission||precision +preemptable||preemptible prefered||preferred prefferably||preferably premption||preemption @@ -747,6 +765,7 @@ programers||programmers programm||program programms||programs progresss||progress +promiscous||promiscuous promps||prompts pronnounced||pronounced prononciation||pronunciation @@ -820,6 +839,7 @@ reseting||resetting resizeable||resizable resouces||resources resoures||resources +responce||response ressizes||resizes ressource||resource ressources||resources @@ -872,6 +892,7 @@ setts||sets settting||setting shotdown||shutdown shoud||should +shouldnt||shouldn't shoule||should shrinked||shrunk siginificantly||significantly @@ -916,9 +937,11 @@ straming||streaming struc||struct structres||structures stuct||struct +stucture||structure sturcture||structure subdirectoires||subdirectories suble||subtle +substract||subtract succesfully||successfully succesful||successful successfull||successful @@ -1031,6 +1054,7 @@ virtiual||virtual visiters||visitors vitual||virtual wating||waiting +wether||whether whataver||whatever whcih||which whenver||whenever -- GitLab From 917520e100e1db5e8dd546dd94fef070a31652a5 Mon Sep 17 00:00:00 2001 From: SF Markus Elfring Date: Fri, 4 Sep 2015 15:43:32 -0700 Subject: [PATCH 6360/7006] ntfs: delete unnecessary checks before calling iput() iput() tests whether its argument is NULL and then returns immediately. Thus the test around the call is not needed. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Cc: Julia Lawall Reviewed-by: Anton Altaparmakov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ntfs/super.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index c1128bcbeb5ed..d1a853585b539 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2204,17 +2204,12 @@ get_ctx_vol_failed: return true; #ifdef NTFS_RW iput_usnjrnl_err_out: - if (vol->usnjrnl_j_ino) - iput(vol->usnjrnl_j_ino); - if (vol->usnjrnl_max_ino) - iput(vol->usnjrnl_max_ino); - if (vol->usnjrnl_ino) - iput(vol->usnjrnl_ino); + iput(vol->usnjrnl_j_ino); + iput(vol->usnjrnl_max_ino); + iput(vol->usnjrnl_ino); iput_quota_err_out: - if (vol->quota_q_ino) - iput(vol->quota_q_ino); - if (vol->quota_ino) - iput(vol->quota_ino); + iput(vol->quota_q_ino); + iput(vol->quota_ino); iput(vol->extend_ino); #endif /* NTFS_RW */ iput_sec_err_out: @@ -2223,8 +2218,7 @@ iput_root_err_out: iput(vol->root_ino); iput_logfile_err_out: #ifdef NTFS_RW - if (vol->logfile_ino) - iput(vol->logfile_ino); + iput(vol->logfile_ino); iput_vol_err_out: #endif /* NTFS_RW */ iput(vol->vol_ino); @@ -2254,8 +2248,7 @@ iput_mftbmp_err_out: iput(vol->mftbmp_ino); iput_mirr_err_out: #ifdef NTFS_RW - if (vol->mftmirr_ino) - iput(vol->mftmirr_ino); + iput(vol->mftmirr_ino); #endif /* NTFS_RW */ return false; } -- GitLab From 81cf09edc793688cbf53c3082802571e2018f3ac Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Fri, 4 Sep 2015 15:43:35 -0700 Subject: [PATCH 6361/7006] sh: use PFN_DOWN macro Replace ((x) >> PAGE_SHIFT) with the predefined PFN_DOWN macro. Signed-off-by: Alexander Kuleshov Acked-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sh/mm/init.c | 4 ++-- arch/sh/mm/numa.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/sh/mm/init.c b/arch/sh/mm/init.c index 2790b6a64157f..17f486233db03 100644 --- a/arch/sh/mm/init.c +++ b/arch/sh/mm/init.c @@ -488,7 +488,7 @@ void free_initrd_mem(unsigned long start, unsigned long end) int arch_add_memory(int nid, u64 start, u64 size) { pg_data_t *pgdat; - unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long start_pfn = PFN_DOWN(start); unsigned long nr_pages = size >> PAGE_SHIFT; int ret; @@ -517,7 +517,7 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to_nid); #ifdef CONFIG_MEMORY_HOTREMOVE int arch_remove_memory(u64 start, u64 size) { - unsigned long start_pfn = start >> PAGE_SHIFT; + unsigned long start_pfn = PFN_DOWN(start); unsigned long nr_pages = size >> PAGE_SHIFT; struct zone *zone; int ret; diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c index bce52ba66206f..05713d190247c 100644 --- a/arch/sh/mm/numa.c +++ b/arch/sh/mm/numa.c @@ -33,8 +33,8 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end) /* Don't allow bogus node assignment */ BUG_ON(nid >= MAX_NUMNODES || nid <= 0); - start_pfn = start >> PAGE_SHIFT; - end_pfn = end >> PAGE_SHIFT; + start_pfn = PFN_DOWN(start); + end_pfn = PFN_DOWN(end); pmb_bolt_mapping((unsigned long)__va(start), start, end - start, PAGE_KERNEL); -- GitLab From 512f62acbdf1ee81ce4882c85835f5420a1c304c Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:37 -0700 Subject: [PATCH 6362/7006] ocfs2: fix race between dio and recover orphan During direct io the inode will be added to orphan first and then deleted from orphan. There is a race window that the orphan entry will be deleted twice and thus trigger the BUG when validating OCFS2_DIO_ORPHANED_FL in ocfs2_del_inode_from_orphan. ocfs2_direct_IO_write ... ocfs2_add_inode_to_orphan >>>>>>>> race window. 1) another node may rm the file and then down, this node take care of orphan recovery and clear flag OCFS2_DIO_ORPHANED_FL. 2) since rw lock is unlocked, it may race with another orphan recovery and append dio. ocfs2_del_inode_from_orphan So take inode mutex lock when recovering orphans and make rw unlock at the end of aio write in case of append dio. Signed-off-by: Joseph Qi Reported-by: Yiwen Jiang Cc: Weiwei Wang Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/aops.c | 9 ++++++--- fs/ocfs2/file.c | 2 +- fs/ocfs2/inode.h | 2 -- fs/ocfs2/journal.c | 8 ++++---- fs/ocfs2/namei.c | 42 +++++++++++++----------------------------- fs/ocfs2/super.c | 2 -- 6 files changed, 24 insertions(+), 41 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 0f5fd9db8194e..1e88ff4837020 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -627,10 +627,13 @@ static void ocfs2_dio_end_io(struct kiocb *iocb, mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio); } - ocfs2_iocb_clear_rw_locked(iocb); + /* Let rw unlock to be done later to protect append direct io write */ + if (offset + bytes <= i_size_read(inode)) { + ocfs2_iocb_clear_rw_locked(iocb); - level = ocfs2_iocb_rw_locked_level(iocb); - ocfs2_rw_unlock(inode, level); + level = ocfs2_iocb_rw_locked_level(iocb); + ocfs2_rw_unlock(inode, level); + } } static int ocfs2_releasepage(struct page *page, gfp_t wait) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 2eb11363b1f78..5d384a6cd696e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2416,7 +2416,7 @@ relock: } no_sync: - if (unaligned_dio) { + if (unaligned_dio && ocfs2_iocb_is_unaligned_aio(iocb)) { ocfs2_iocb_clear_unaligned_aio(iocb); mutex_unlock(&OCFS2_I(inode)->ip_unaligned_aio); } diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index 5e86b247c821c..ca3431ee7f249 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h @@ -81,8 +81,6 @@ struct ocfs2_inode_info tid_t i_sync_tid; tid_t i_datasync_tid; - wait_queue_head_t append_dio_wq; - struct dquot *i_dquot[MAXQUOTAS]; }; diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 7c099f7032fdb..5e5626884433b 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -2170,6 +2170,7 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, iter = oi->ip_next_orphan; oi->ip_next_orphan = NULL; + mutex_lock(&inode->i_mutex); ret = ocfs2_rw_lock(inode, 1); if (ret < 0) { mlog_errno(ret); @@ -2206,17 +2207,16 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, ret = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0); if (ret) mlog_errno(ret); - - wake_up(&OCFS2_I(inode)->append_dio_wq); } /* else if ORPHAN_NO_NEED_TRUNCATE, do nothing */ unlock_inode: ocfs2_inode_unlock(inode, 1); + brelse(di_bh); + di_bh = NULL; unlock_rw: ocfs2_rw_unlock(inode, 1); next: + mutex_unlock(&inode->i_mutex); iput(inode); - brelse(di_bh); - di_bh = NULL; inode = iter; } diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 948681e37cfdb..e9ea7f23da125 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -2601,27 +2601,6 @@ leave: return status; } -static int ocfs2_dio_orphan_recovered(struct inode *inode) -{ - int ret; - struct buffer_head *di_bh = NULL; - struct ocfs2_dinode *di = NULL; - - ret = ocfs2_inode_lock(inode, &di_bh, 1); - if (ret < 0) { - mlog_errno(ret); - return 0; - } - - di = (struct ocfs2_dinode *) di_bh->b_data; - ret = !(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL)); - ocfs2_inode_unlock(inode, 1); - brelse(di_bh); - - return ret; -} - -#define OCFS2_DIO_ORPHANED_FL_CHECK_INTERVAL 10000 int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, struct inode *inode) { @@ -2633,7 +2612,6 @@ int ocfs2_add_inode_to_orphan(struct ocfs2_super *osb, handle_t *handle = NULL; struct ocfs2_dinode *di = NULL; -restart: status = ocfs2_inode_lock(inode, &di_bh, 1); if (status < 0) { mlog_errno(status); @@ -2643,15 +2621,21 @@ restart: di = (struct ocfs2_dinode *) di_bh->b_data; /* * Another append dio crashed? - * If so, wait for recovery first. + * If so, manually recover it first. */ if (unlikely(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL))) { - ocfs2_inode_unlock(inode, 1); - brelse(di_bh); - wait_event_interruptible_timeout(OCFS2_I(inode)->append_dio_wq, - ocfs2_dio_orphan_recovered(inode), - msecs_to_jiffies(OCFS2_DIO_ORPHANED_FL_CHECK_INTERVAL)); - goto restart; + status = ocfs2_truncate_file(inode, di_bh, i_size_read(inode)); + if (status < 0) { + if (status != -ENOSPC) + mlog_errno(status); + goto bail_unlock_inode; + } + + status = ocfs2_del_inode_from_orphan(osb, inode, di_bh, 0, 0); + if (status < 0) { + mlog_errno(status); + goto bail_unlock_inode; + } } status = ocfs2_prepare_orphan_dir(osb, &orphan_dir_inode, diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 403c5660b3064..4474ef2bbc960 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1746,8 +1746,6 @@ static void ocfs2_inode_init_once(void *data) ocfs2_lock_res_init_once(&oi->ip_inode_lockres); ocfs2_lock_res_init_once(&oi->ip_open_lockres); - init_waitqueue_head(&oi->append_dio_wq); - ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode), &ocfs2_inode_caching_ops); -- GitLab From faaebf18f831c1546bdc65ff8f49d2a73e675ded Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:40 -0700 Subject: [PATCH 6363/7006] ocfs2: fix several issues of append dio 1) Take rw EX lock in case of append dio. 2) Explicitly treat the error code -EIOCBQUEUED as normal. 3) Set di_bh to NULL after brelse if it may be used again later. Signed-off-by: Joseph Qi Cc: Yiwen Jiang Cc: Weiwei Wang Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/aops.c | 7 ++++++- fs/ocfs2/file.c | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 1e88ff4837020..b36dcad3a1405 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -860,7 +860,8 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, written = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, offset, ocfs2_direct_IO_get_blocks, ocfs2_dio_end_io, NULL, 0); - if (unlikely(written < 0)) { + /* overwrite aio may return -EIOCBQUEUED, and it is not an error */ + if ((written < 0) && (written != -EIOCBQUEUED)) { loff_t i_size = i_size_read(inode); if (offset + count > i_size) { @@ -879,12 +880,14 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, ocfs2_inode_unlock(inode, 1); brelse(di_bh); + di_bh = NULL; goto clean_orphan; } } ocfs2_inode_unlock(inode, 1); brelse(di_bh); + di_bh = NULL; ret = jbd2_journal_force_commit(journal); if (ret < 0) @@ -939,10 +942,12 @@ clean_orphan: if (tmp_ret < 0) { ret = tmp_ret; mlog_errno(ret); + brelse(di_bh); goto out; } ocfs2_inode_unlock(inode, 1); + brelse(di_bh); tmp_ret = jbd2_journal_force_commit(journal); if (tmp_ret < 0) { diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 5d384a6cd696e..38fc339228327 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2271,6 +2271,8 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb, OCFS2_MOUNT_COHERENCY_BUFFERED); int unaligned_dio = 0; int dropped_dio = 0; + int append_write = ((iocb->ki_pos + count) >= + i_size_read(inode) ? 1 : 0); trace_ocfs2_file_aio_write(inode, file, file->f_path.dentry, (unsigned long long)OCFS2_I(inode)->ip_blkno, @@ -2290,8 +2292,9 @@ relock: /* * Concurrent O_DIRECT writes are allowed with * mount_option "coherency=buffered". + * For append write, we must take rw EX. */ - rw_level = (!direct_io || full_coherency); + rw_level = (!direct_io || full_coherency || append_write); ret = ocfs2_rw_lock(inode, rw_level); if (ret < 0) { -- GitLab From acf8fdbe6afb084666df347602fe4258f1cf5fd5 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:43 -0700 Subject: [PATCH 6364/7006] ocfs2: do not BUG if buffer not uptodate in __ocfs2_journal_access When storage network is unstable, it may trigger the BUG in __ocfs2_journal_access because of buffer not uptodate. We can retry the write in this case or return error instead of BUG. Signed-off-by: Joseph Qi Reported-by: Zhangguanghui Tested-by: Zhangguanghui Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/journal.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 5e5626884433b..3bfd36a23e401 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -668,7 +668,23 @@ static int __ocfs2_journal_access(handle_t *handle, mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n"); mlog(ML_ERROR, "b_blocknr=%llu\n", (unsigned long long)bh->b_blocknr); - BUG(); + + lock_buffer(bh); + /* + * A previous attempt to write this buffer head failed. + * Nothing we can do but to retry the write and hope for + * the best. + */ + if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) { + clear_buffer_write_io_error(bh); + set_buffer_uptodate(bh); + } + + if (!buffer_uptodate(bh)) { + unlock_buffer(bh); + return -EIO; + } + unlock_buffer(bh); } /* Set the current transaction information on the ci so -- GitLab From 372a447c4bb8271d128def5f93e3365d5d06b4d8 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 4 Sep 2015 15:43:46 -0700 Subject: [PATCH 6365/7006] ocfs2: do not log twice error messages 'o2hb_map_slot_data' and 'o2hb_populate_slot_data' are called from only one place, in 'o2hb_region_dev_write'. Return value is checked and 'mlog_errno' is called to log a message if it is not 0. So there is no need to call 'mlog_errno' directly within these functions. This would result on logging the message twice. Signed-off-by: Christophe JAILLET Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/cluster/heartbeat.c | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index 140de3c93d2e3..f97306453a0b3 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -1619,17 +1619,13 @@ static int o2hb_map_slot_data(struct o2hb_region *reg) struct o2hb_disk_slot *slot; reg->hr_tmp_block = kmalloc(reg->hr_block_bytes, GFP_KERNEL); - if (reg->hr_tmp_block == NULL) { - mlog_errno(-ENOMEM); + if (reg->hr_tmp_block == NULL) return -ENOMEM; - } reg->hr_slots = kcalloc(reg->hr_blocks, sizeof(struct o2hb_disk_slot), GFP_KERNEL); - if (reg->hr_slots == NULL) { - mlog_errno(-ENOMEM); + if (reg->hr_slots == NULL) return -ENOMEM; - } for(i = 0; i < reg->hr_blocks; i++) { slot = ®->hr_slots[i]; @@ -1645,17 +1641,13 @@ static int o2hb_map_slot_data(struct o2hb_region *reg) reg->hr_slot_data = kcalloc(reg->hr_num_pages, sizeof(struct page *), GFP_KERNEL); - if (!reg->hr_slot_data) { - mlog_errno(-ENOMEM); + if (!reg->hr_slot_data) return -ENOMEM; - } for(i = 0; i < reg->hr_num_pages; i++) { page = alloc_page(GFP_KERNEL); - if (!page) { - mlog_errno(-ENOMEM); + if (!page) return -ENOMEM; - } reg->hr_slot_data[i] = page; @@ -1687,10 +1679,8 @@ static int o2hb_populate_slot_data(struct o2hb_region *reg) struct o2hb_disk_heartbeat_block *hb_block; ret = o2hb_read_slots(reg, reg->hr_blocks); - if (ret) { - mlog_errno(ret); + if (ret) goto out; - } /* We only want to get an idea of the values initially in each * slot, so we do no verification - o2hb_check_slot will -- GitLab From bf59e6623a3a92a2bf428f2d6592c81aae6317e1 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:49 -0700 Subject: [PATCH 6366/7006] ocfs2: clean up unused local variables in ocfs2_file_write_iter Since commit 86b9c6f3f891 ("ocfs2: remove filesize checks for sync I/O journal commit") removes filesize checks for sync I/O journal commit, variables old_size and old_clusters are not actually used any more. So clean them up. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/file.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 38fc339228327..c4a99fb61c3e4 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -2262,8 +2262,6 @@ static ssize_t ocfs2_file_write_iter(struct kiocb *iocb, ssize_t written = 0; ssize_t ret; size_t count = iov_iter_count(from), orig_count; - loff_t old_size; - u32 old_clusters; struct file *file = iocb->ki_filp; struct inode *inode = file_inode(file); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); @@ -2367,13 +2365,6 @@ relock: ocfs2_iocb_set_unaligned_aio(iocb); } - /* - * To later detect whether a journal commit for sync writes is - * necessary, we sample i_size, and cluster count here. - */ - old_size = i_size_read(inode); - old_clusters = OCFS2_I(inode)->ip_clusters; - /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb, rw_level); -- GitLab From 3cb2ec43f63c42412a18620f1226eb4aa434a7a8 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:52 -0700 Subject: [PATCH 6367/7006] ocfs2: adjust code to match locking/unlocking order Unlocking order in ocfs2_unlink and ocfs2_rename mismatches the corresponding locking order, although it won't cause issues, adjust the code so that it looks more reasonable. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/namei.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index e9ea7f23da125..97c47d71efa72 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1035,11 +1035,6 @@ leave: if (handle) ocfs2_commit_trans(osb, handle); - if (child_locked) - ocfs2_inode_unlock(inode, 1); - - ocfs2_inode_unlock(dir, 1); - if (orphan_dir) { /* This was locked for us in ocfs2_prepare_orphan_dir() */ ocfs2_inode_unlock(orphan_dir, 1); @@ -1047,6 +1042,11 @@ leave: iput(orphan_dir); } + if (child_locked) + ocfs2_inode_unlock(inode, 1); + + ocfs2_inode_unlock(dir, 1); + brelse(fe_bh); brelse(parent_node_bh); @@ -1633,21 +1633,9 @@ static int ocfs2_rename(struct inode *old_dir, ocfs2_dentry_move(old_dentry, new_dentry, old_dir, new_dir); status = 0; bail: - if (rename_lock) - ocfs2_rename_unlock(osb); - if (handle) ocfs2_commit_trans(osb, handle); - if (parents_locked) - ocfs2_double_unlock(old_dir, new_dir); - - if (old_child_locked) - ocfs2_inode_unlock(old_inode, 1); - - if (new_child_locked) - ocfs2_inode_unlock(new_inode, 1); - if (orphan_dir) { /* This was locked for us in ocfs2_prepare_orphan_dir() */ ocfs2_inode_unlock(orphan_dir, 1); @@ -1655,6 +1643,18 @@ bail: iput(orphan_dir); } + if (new_child_locked) + ocfs2_inode_unlock(new_inode, 1); + + if (old_child_locked) + ocfs2_inode_unlock(old_inode, 1); + + if (parents_locked) + ocfs2_double_unlock(old_dir, new_dir); + + if (rename_lock) + ocfs2_rename_unlock(osb); + if (new_inode) sync_mapping_buffers(old_inode->i_mapping); -- GitLab From 914a9b74295774b92409fbc3e0abcfa9185d9469 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:54 -0700 Subject: [PATCH 6368/7006] ocfs2: remove unneeded code in ocfs2_dlm_init status is already initialized and it will only be 0 or negatives in the code flow. So remove the unneeded assignment after the lable 'local'. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlmglue.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 23157e40dd740..1c91103c13339 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -3035,8 +3035,6 @@ local: ocfs2_orphan_scan_lock_res_init(&osb->osb_orphan_scan.os_lockres, osb); osb->cconn = conn; - - status = 0; bail: if (status < 0) { ocfs2_dlm_shutdown_debug(osb); -- GitLab From cdd09f49cb271d95cbe69ef886459e0490040e98 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:43:57 -0700 Subject: [PATCH 6369/7006] ocfs2: fix BUG when o2hb_register_callback fails In dlm_register_domain_handlers, if o2hb_register_callback fails, it will call dlm_unregister_domain_handlers to unregister. This will trigger the BUG_ON in o2hb_unregister_callback because hc_magic is 0. So we should call o2hb_setup_callback to initialize hc first. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlm/dlmdomain.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 7df88a6dd6260..4f750701bd9a4 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -1725,12 +1725,13 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm) o2hb_setup_callback(&dlm->dlm_hb_down, O2HB_NODE_DOWN_CB, dlm_hb_node_down_cb, dlm, DLM_HB_NODE_DOWN_PRI); + o2hb_setup_callback(&dlm->dlm_hb_up, O2HB_NODE_UP_CB, + dlm_hb_node_up_cb, dlm, DLM_HB_NODE_UP_PRI); + status = o2hb_register_callback(dlm->name, &dlm->dlm_hb_down); if (status) goto bail; - o2hb_setup_callback(&dlm->dlm_hb_up, O2HB_NODE_UP_CB, - dlm_hb_node_up_cb, dlm, DLM_HB_NODE_UP_PRI); status = o2hb_register_callback(dlm->name, &dlm->dlm_hb_up); if (status) goto bail; -- GitLab From 0e3d9eafb86183a33efc42f0beff5afceebbafba Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:44:00 -0700 Subject: [PATCH 6370/7006] ocfs2: remove unneeded code in dlm_register_domain_handlers The last goto statement is unneeded, so remove it. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlm/dlmdomain.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 4f750701bd9a4..019459b20aeb8 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -1846,8 +1846,6 @@ static int dlm_register_domain_handlers(struct dlm_ctxt *dlm) sizeof(struct dlm_exit_domain), dlm_begin_exit_domain_handler, dlm, NULL, &dlm->dlm_domain_handlers); - if (status) - goto bail; bail: if (status) -- GitLab From f83c7b5e9fd633fe91128af116e6472a8c4d29a5 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:44:03 -0700 Subject: [PATCH 6371/7006] ocfs2/dlm: use list_for_each_entry instead of list_for_each Use list_for_each_entry instead of list_for_each to simplify code. Signed-off-by: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlm/dlmrecovery.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index ce12e0b1a31f1..d0e436dc64371 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -1776,7 +1776,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, struct dlm_migratable_lockres *mres) { struct dlm_migratable_lock *ml; - struct list_head *queue, *iter; + struct list_head *queue; struct list_head *tmpq = NULL; struct dlm_lock *newlock = NULL; struct dlm_lockstatus *lksb = NULL; @@ -1821,9 +1821,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, spin_lock(&res->spinlock); for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) { tmpq = dlm_list_idx_to_ptr(res, j); - list_for_each(iter, tmpq) { - lock = list_entry(iter, - struct dlm_lock, list); + list_for_each_entry(lock, tmpq, list) { if (lock->ml.cookie == ml->cookie) break; lock = NULL; -- GitLab From 807a7907114c7c703017ed7a96477a2eeb0d08e0 Mon Sep 17 00:00:00 2001 From: jiangyiwen Date: Fri, 4 Sep 2015 15:44:06 -0700 Subject: [PATCH 6372/7006] ocfs2: set filesytem read-only when ocfs2_delete_entry failed. In ocfs2_rename, it will lead to an inode with two entried(old and new) if ocfs2_delete_entry(old) failed. Thus, filesystem will be inconsistent. The case is described below: ocfs2_rename -> ocfs2_start_trans -> ocfs2_add_entry(new) -> ocfs2_delete_entry(old) -> __ocfs2_journal_access *failed* because of -ENOMEM -> ocfs2_commit_trans So filesystem should be set to read-only at the moment. Signed-off-by: Yiwen Jiang Cc: Joseph Qi Cc: Joel Becker Reviewed-by: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/namei.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 97c47d71efa72..1c43993e81b05 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1569,12 +1569,25 @@ static int ocfs2_rename(struct inode *old_dir, status = ocfs2_find_entry(old_dentry->d_name.name, old_dentry->d_name.len, old_dir, &old_entry_lookup); - if (status) + if (status) { + if (!is_journal_aborted(osb->journal->j_journal)) { + ocfs2_error(osb->sb, "new entry %.*s is added, but old entry %.*s " + "is not deleted.", + new_dentry->d_name.len, new_dentry->d_name.name, + old_dentry->d_name.len, old_dentry->d_name.name); + } goto bail; + } status = ocfs2_delete_entry(handle, old_dir, &old_entry_lookup); if (status < 0) { mlog_errno(status); + if (!is_journal_aborted(osb->journal->j_journal)) { + ocfs2_error(osb->sb, "new entry %.*s is added, but old entry %.*s " + "is not deleted.", + new_dentry->d_name.len, new_dentry->d_name.name, + old_dentry->d_name.len, old_dentry->d_name.name); + } goto bail; } -- GitLab From 0f5e7b41f91814447defc34e915fc5d6e52266d9 Mon Sep 17 00:00:00 2001 From: Sanidhya Kashyap Date: Fri, 4 Sep 2015 15:44:08 -0700 Subject: [PATCH 6373/7006] ocfs2: trusted xattr missing CAP_SYS_ADMIN check The trusted extended attributes are only visible to the process which hvae CAP_SYS_ADMIN capability but the check is missing in ocfs2 xattr_handler trusted list. The check is important because this will be used for implementing mechanisms in the userspace for which other ordinary processes should not have access to. Signed-off-by: Sanidhya Kashyap Reviewed-by: Mark Fasheh Cc: Joel Becker Cc: Taesoo kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/xattr.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 889f3796a0d73..a24f264b2fc44 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -7334,6 +7334,9 @@ static size_t ocfs2_xattr_trusted_list(struct dentry *dentry, char *list, const size_t prefix_len = XATTR_TRUSTED_PREFIX_LEN; const size_t total_len = prefix_len + name_len + 1; + if (!capable(CAP_SYS_ADMIN)) + return 0; + if (list && total_len <= list_size) { memcpy(list, XATTR_TRUSTED_PREFIX, prefix_len); memcpy(list + prefix_len, name, name_len); -- GitLab From 513e2dae9422223072ed3887e91efebec2fc0a01 Mon Sep 17 00:00:00 2001 From: Xue jiufei Date: Fri, 4 Sep 2015 15:44:11 -0700 Subject: [PATCH 6374/7006] ocfs2: flush inode data to disk and free inode when i_count becomes zero Disk inode deletion may be heavily delayed when one node unlink a file after the same dentry is freed on another node(say N1) because of memory shrink but inode is left in memory. This inode can only be freed while N1 doing the orphan scan work. However, N1 may skip orphan scan for several times because other nodes may do the work earlier. In our tests, it may take 1 hour on 4 nodes cluster and it hurts the user experience. So we think the inode should be freed after the data flushed to disk when i_count becomes zero to avoid such circumstances. Signed-off-by: Joyce.xue Cc: Joel Becker Reviewed-by: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/inode.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index b254416dc8d92..4e69f3cbc5f18 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1191,17 +1191,19 @@ void ocfs2_evict_inode(struct inode *inode) int ocfs2_drop_inode(struct inode *inode) { struct ocfs2_inode_info *oi = OCFS2_I(inode); - int res; trace_ocfs2_drop_inode((unsigned long long)oi->ip_blkno, inode->i_nlink, oi->ip_flags); - if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED) - res = 1; - else - res = generic_drop_inode(inode); + assert_spin_locked(&inode->i_lock); + inode->i_state |= I_WILL_FREE; + spin_unlock(&inode->i_lock); + write_inode_now(inode, 1); + spin_lock(&inode->i_lock); + WARN_ON(inode->i_state & I_NEW); + inode->i_state &= ~I_WILL_FREE; - return res; + return 1; } /* -- GitLab From 7d0fb9148ab6f52006de7cce18860227594ba872 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Fri, 4 Sep 2015 15:44:11 -0700 Subject: [PATCH 6375/7006] ocfs2: add errors=continue OCFS2 is often used in high-availaibility systems. However, ocfs2 converts the filesystem to read-only at the drop of the hat. This may not be necessary, since turning the filesystem read-only would affect other running processes as well, decreasing availability. This attempt is to add errors=continue, which would return the EIO to the calling process and terminate furhter processing so that the filesystem is not corrupted further. However, the filesystem is not converted to read-only. As a future plan, I intend to create a small utility or extend fsck.ocfs2 to fix small errors such as in the inode. The input to the utility such as the inode can come from the kernel logs so we don't have to schedule a downtime for fixing small-enough errors. The patch changes the ocfs2_error to return an error. The error returned depends on the mount option set. If none is set, the default is to turn the filesystem read-only. Perhaps errors=continue is not the best option name. Historically it is used for making an attempt to progress in the current process itself. Should we call it errors=eio? or errors=killproc? Suggestions/Comments welcome. Sources are available at: https://github.com/goldwynr/linux/tree/error-cont Signed-off-by: Goldwyn Rodrigues Signed-off-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/ocfs2.h | 2 ++ fs/ocfs2/super.c | 63 +++++++++++++++++++++++++++++++++--------------- fs/ocfs2/super.h | 2 +- 3 files changed, 47 insertions(+), 20 deletions(-) diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 690ddc60189b5..7a01262678476 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -286,6 +286,8 @@ enum ocfs2_mount_options OCFS2_MOUNT_HB_GLOBAL = 1 << 14, /* Global heartbeat */ OCFS2_MOUNT_JOURNAL_ASYNC_COMMIT = 1 << 15, /* Journal Async Commit */ + OCFS2_MOUNT_ERRORS_CONT = 1 << 16, /* Return EIO to the calling process on error */ + OCFS2_MOUNT_ERRORS_ROFS = 1 << 17, /* Change filesystem to read-only on error */ }; #define OCFS2_OSB_SOFT_RO 0x0001 diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 4474ef2bbc960..e79058ecfb4be 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -192,6 +192,7 @@ enum { Opt_resv_level, Opt_dir_resv_level, Opt_journal_async_commit, + Opt_err_cont, Opt_err, }; @@ -224,6 +225,7 @@ static const match_table_t tokens = { {Opt_resv_level, "resv_level=%u"}, {Opt_dir_resv_level, "dir_resv_level=%u"}, {Opt_journal_async_commit, "journal_async_commit"}, + {Opt_err_cont, "errors=continue"}, {Opt_err, NULL} }; @@ -1330,10 +1332,19 @@ static int ocfs2_parse_options(struct super_block *sb, mopt->mount_opt |= OCFS2_MOUNT_NOINTR; break; case Opt_err_panic: + mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT; + mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS; mopt->mount_opt |= OCFS2_MOUNT_ERRORS_PANIC; break; case Opt_err_ro: + mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_CONT; mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC; + mopt->mount_opt |= OCFS2_MOUNT_ERRORS_ROFS; + break; + case Opt_err_cont: + mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_ROFS; + mopt->mount_opt &= ~OCFS2_MOUNT_ERRORS_PANIC; + mopt->mount_opt |= OCFS2_MOUNT_ERRORS_CONT; break; case Opt_data_ordered: mopt->mount_opt &= ~OCFS2_MOUNT_DATA_WRITEBACK; @@ -1530,6 +1541,8 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root) if (opts & OCFS2_MOUNT_ERRORS_PANIC) seq_printf(s, ",errors=panic"); + else if (opts & OCFS2_MOUNT_ERRORS_CONT) + seq_printf(s, ",errors=continue"); else seq_printf(s, ",errors=remount-ro"); @@ -2539,31 +2552,43 @@ static void ocfs2_delete_osb(struct ocfs2_super *osb) memset(osb, 0, sizeof(struct ocfs2_super)); } -/* Put OCFS2 into a readonly state, or (if the user specifies it), - * panic(). We do not support continue-on-error operation. */ -static void ocfs2_handle_error(struct super_block *sb) +/* Depending on the mount option passed, perform one of the following: + * Put OCFS2 into a readonly state (default) + * Return EIO so that only the process errs + * Fix the error as if fsck.ocfs2 -y + * panic + */ +static int ocfs2_handle_error(struct super_block *sb) { struct ocfs2_super *osb = OCFS2_SB(sb); - - if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_PANIC) - panic("OCFS2: (device %s): panic forced after error\n", - sb->s_id); + int rv = 0; ocfs2_set_osb_flag(osb, OCFS2_OSB_ERROR_FS); + pr_crit("On-disk corruption discovered. " + "Please run fsck.ocfs2 once the filesystem is unmounted.\n"); - if (sb->s_flags & MS_RDONLY && - (ocfs2_is_soft_readonly(osb) || - ocfs2_is_hard_readonly(osb))) - return; - - printk(KERN_CRIT "File system is now read-only due to the potential " - "of on-disk corruption. Please run fsck.ocfs2 once the file " - "system is unmounted.\n"); - sb->s_flags |= MS_RDONLY; - ocfs2_set_ro_flag(osb, 0); + if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_PANIC) { + panic("OCFS2: (device %s): panic forced after error\n", + sb->s_id); + } else if (osb->s_mount_opt & OCFS2_MOUNT_ERRORS_CONT) { + pr_crit("OCFS2: Returning error to the calling process.\n"); + rv = -EIO; + } else { /* default option */ + rv = -EROFS; + if (sb->s_flags & MS_RDONLY && + (ocfs2_is_soft_readonly(osb) || + ocfs2_is_hard_readonly(osb))) + return rv; + + pr_crit("OCFS2: File system is now read-only.\n"); + sb->s_flags |= MS_RDONLY; + ocfs2_set_ro_flag(osb, 0); + } + + return rv; } -void __ocfs2_error(struct super_block *sb, const char *function, +int __ocfs2_error(struct super_block *sb, const char *function, const char *fmt, ...) { struct va_format vaf; @@ -2580,7 +2605,7 @@ void __ocfs2_error(struct super_block *sb, const char *function, va_end(args); - ocfs2_handle_error(sb); + return ocfs2_handle_error(sb); } /* Handle critical errors. This is intentionally more drastic than diff --git a/fs/ocfs2/super.h b/fs/ocfs2/super.h index 74ff74cf78fe9..c1c87d90542c8 100644 --- a/fs/ocfs2/super.h +++ b/fs/ocfs2/super.h @@ -32,7 +32,7 @@ int ocfs2_publish_get_mount_state(struct ocfs2_super *osb, int node_num); __printf(3, 4) -void __ocfs2_error(struct super_block *sb, const char *function, +int __ocfs2_error(struct super_block *sb, const char *function, const char *fmt, ...); #define ocfs2_error(sb, fmt, args...) __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##args) -- GitLab From 17a5b9ab32fe0464e7f556e28a2b49d2023fb533 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Fri, 4 Sep 2015 15:44:17 -0700 Subject: [PATCH 6376/7006] ocfs2: acknowledge return value of ocfs2_error() Caveat: This may return -EROFS for a read case, which seems wrong. This is happening even without this patch series though. Should we convert EROFS to EIO? Signed-off-by: Goldwyn Rodrigues Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/alloc.c | 16 ++++++++-------- fs/ocfs2/dir.c | 25 +++++++++--------------- fs/ocfs2/inode.c | 8 ++++---- fs/ocfs2/move_extents.c | 3 +-- fs/ocfs2/refcounttree.c | 42 ++++++++++++++++++----------------------- fs/ocfs2/suballoc.c | 25 ++++++------------------ fs/ocfs2/xattr.c | 15 +++++---------- 7 files changed, 51 insertions(+), 83 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 5997c00a1515a..9a0fd494fe748 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -908,32 +908,32 @@ static int ocfs2_validate_extent_block(struct super_block *sb, */ if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Extent block #%llu has bad signature %.*s", (unsigned long long)bh->b_blocknr, 7, eb->h_signature); - return -EINVAL; + goto bail; } if (le64_to_cpu(eb->h_blkno) != bh->b_blocknr) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Extent block #%llu has an invalid h_blkno " "of %llu", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(eb->h_blkno)); - return -EINVAL; + goto bail; } if (le32_to_cpu(eb->h_fs_generation) != OCFS2_SB(sb)->fs_generation) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Extent block #%llu has an invalid " "h_fs_generation of #%u", (unsigned long long)bh->b_blocknr, le32_to_cpu(eb->h_fs_generation)); - return -EINVAL; + goto bail; } - - return 0; +bail: + return rc; } int ocfs2_read_extent_block(struct ocfs2_caching_info *ci, u64 eb_blkno, diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 02878a83f0b4e..25f03af09237a 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -480,8 +480,7 @@ static int ocfs2_check_dir_trailer(struct inode *dir, struct buffer_head *bh) trailer = ocfs2_trailer_from_bh(bh, dir->i_sb); if (!OCFS2_IS_VALID_DIR_TRAILER(trailer)) { - rc = -EINVAL; - ocfs2_error(dir->i_sb, + rc = ocfs2_error(dir->i_sb, "Invalid dirblock #%llu: " "signature = %.*s\n", (unsigned long long)bh->b_blocknr, 7, @@ -489,8 +488,7 @@ static int ocfs2_check_dir_trailer(struct inode *dir, struct buffer_head *bh) goto out; } if (le64_to_cpu(trailer->db_blkno) != bh->b_blocknr) { - rc = -EINVAL; - ocfs2_error(dir->i_sb, + rc = ocfs2_error(dir->i_sb, "Directory block #%llu has an invalid " "db_blkno of %llu", (unsigned long long)bh->b_blocknr, @@ -499,8 +497,7 @@ static int ocfs2_check_dir_trailer(struct inode *dir, struct buffer_head *bh) } if (le64_to_cpu(trailer->db_parent_dinode) != OCFS2_I(dir)->ip_blkno) { - rc = -EINVAL; - ocfs2_error(dir->i_sb, + rc = ocfs2_error(dir->i_sb, "Directory block #%llu on dinode " "#%llu has an invalid parent_dinode " "of %llu", @@ -604,14 +601,13 @@ static int ocfs2_validate_dx_root(struct super_block *sb, } if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) { - ocfs2_error(sb, + ret = ocfs2_error(sb, "Dir Index Root # %llu has bad signature %.*s", (unsigned long long)le64_to_cpu(dx_root->dr_blkno), 7, dx_root->dr_signature); - return -EINVAL; } - return 0; + return ret; } static int ocfs2_read_dx_root(struct inode *dir, struct ocfs2_dinode *di, @@ -648,12 +644,11 @@ static int ocfs2_validate_dx_leaf(struct super_block *sb, } if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf)) { - ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s", + ret = ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s", 7, dx_leaf->dl_signature); - return -EROFS; } - return 0; + return ret; } static int ocfs2_read_dx_leaf(struct inode *dir, u64 blkno, @@ -812,11 +807,10 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode, el = &eb->h_list; if (el->l_tree_depth) { - ocfs2_error(inode->i_sb, + ret = ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in " "btree tree block %llu\n", inode->i_ino, (unsigned long long)eb_bh->b_blocknr); - ret = -EROFS; goto out; } } @@ -832,11 +826,10 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode, } if (!found) { - ocfs2_error(inode->i_sb, "Inode %lu has bad extent " + ret = ocfs2_error(inode->i_sb, "Inode %lu has bad extent " "record (%u, %u, 0) in btree", inode->i_ino, le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); - ret = -EROFS; goto out; } diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 4e69f3cbc5f18..7868f7e7c455b 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1352,21 +1352,21 @@ int ocfs2_validate_inode_block(struct super_block *sb, rc = -EINVAL; if (!OCFS2_IS_VALID_DINODE(di)) { - ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n", + rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n", (unsigned long long)bh->b_blocknr, 7, di->i_signature); goto bail; } if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { - ocfs2_error(sb, "Invalid dinode #%llu: i_blkno is %llu\n", + rc = ocfs2_error(sb, "Invalid dinode #%llu: i_blkno is %llu\n", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(di->i_blkno)); goto bail; } if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Invalid dinode #%llu: OCFS2_VALID_FL not set\n", (unsigned long long)bh->b_blocknr); goto bail; @@ -1374,7 +1374,7 @@ int ocfs2_validate_inode_block(struct super_block *sb, if (le32_to_cpu(di->i_fs_generation) != OCFS2_SB(sb)->fs_generation) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Invalid dinode #%llu: fs_generation is %u\n", (unsigned long long)bh->b_blocknr, le32_to_cpu(di->i_fs_generation)); diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 56a768d06aa6f..70dd0ec7b7e9b 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -99,11 +99,10 @@ static int __ocfs2_move_extent(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { - ocfs2_error(inode->i_sb, + ret = ocfs2_error(inode->i_sb, "Inode %llu has an extent at cpos %u which can no " "longer be found.\n", (unsigned long long)ino, cpos); - ret = -EROFS; goto out; } diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 7dc818b87cd82..b404dbde3fe4f 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -102,32 +102,32 @@ static int ocfs2_validate_refcount_block(struct super_block *sb, if (!OCFS2_IS_VALID_REFCOUNT_BLOCK(rb)) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Refcount block #%llu has bad signature %.*s", (unsigned long long)bh->b_blocknr, 7, rb->rf_signature); - return -EINVAL; + goto out; } if (le64_to_cpu(rb->rf_blkno) != bh->b_blocknr) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Refcount block #%llu has an invalid rf_blkno " "of %llu", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(rb->rf_blkno)); - return -EINVAL; + goto out; } if (le32_to_cpu(rb->rf_fs_generation) != OCFS2_SB(sb)->fs_generation) { - ocfs2_error(sb, + rc = ocfs2_error(sb, "Refcount block #%llu has an invalid " "rf_fs_generation of #%u", (unsigned long long)bh->b_blocknr, le32_to_cpu(rb->rf_fs_generation)); - return -EINVAL; + goto out; } - - return 0; +out: + return rc; } static int ocfs2_read_refcount_block(struct ocfs2_caching_info *ci, @@ -1102,12 +1102,11 @@ static int ocfs2_get_refcount_rec(struct ocfs2_caching_info *ci, el = &eb->h_list; if (el->l_tree_depth) { - ocfs2_error(sb, - "refcount tree %llu has non zero tree " - "depth in leaf btree tree block %llu\n", - (unsigned long long)ocfs2_metadata_cache_owner(ci), - (unsigned long long)eb_bh->b_blocknr); - ret = -EROFS; + ret = ocfs2_error(sb, + "refcount tree %llu has non zero tree " + "depth in leaf btree tree block %llu\n", + (unsigned long long)ocfs2_metadata_cache_owner(ci), + (unsigned long long)eb_bh->b_blocknr); goto out; } } @@ -2359,10 +2358,9 @@ static int ocfs2_mark_extent_refcounted(struct inode *inode, cpos, len, phys); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { - ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " + ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " "tree, but the feature bit is not set in the " "super block.", inode->i_ino); - ret = -EROFS; goto out; } @@ -2545,10 +2543,9 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, u64 start_cpos = ocfs2_blocks_to_clusters(inode->i_sb, phys_blkno); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { - ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " + ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " "tree, but the feature bit is not set in the " "super block.", inode->i_ino); - ret = -EROFS; goto out; } @@ -2672,11 +2669,10 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, el = &eb->h_list; if (el->l_tree_depth) { - ocfs2_error(inode->i_sb, + ret = ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in " "leaf block %llu\n", inode->i_ino, (unsigned long long)eb_bh->b_blocknr); - ret = -EROFS; goto out; } } @@ -3106,11 +3102,10 @@ static int ocfs2_clear_ext_refcount(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { - ocfs2_error(sb, + ret = ocfs2_error(sb, "Inode %llu has an extent at cpos %u which can no " "longer be found.\n", (unsigned long long)ino, cpos); - ret = -EROFS; goto out; } @@ -3376,10 +3371,9 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context) struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { - ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " + return ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " "tree, but the feature bit is not set in the " "super block.", inode->i_ino); - return -EROFS; } ocfs2_init_dealloc_ctxt(&context->dealloc); diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 4479029630bb3..e4bb00110e915 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -171,7 +171,7 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) if (resize) \ mlog(ML_ERROR, fmt "\n", ##__VA_ARGS__); \ else \ - ocfs2_error(sb, fmt, ##__VA_ARGS__); \ + return ocfs2_error(sb, fmt, ##__VA_ARGS__); \ } while (0) static int ocfs2_validate_gd_self(struct super_block *sb, @@ -184,7 +184,6 @@ static int ocfs2_validate_gd_self(struct super_block *sb, do_error("Group descriptor #%llu has bad signature %.*s", (unsigned long long)bh->b_blocknr, 7, gd->bg_signature); - return -EINVAL; } if (le64_to_cpu(gd->bg_blkno) != bh->b_blocknr) { @@ -192,7 +191,6 @@ static int ocfs2_validate_gd_self(struct super_block *sb, "of %llu", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(gd->bg_blkno)); - return -EINVAL; } if (le32_to_cpu(gd->bg_generation) != OCFS2_SB(sb)->fs_generation) { @@ -200,7 +198,6 @@ static int ocfs2_validate_gd_self(struct super_block *sb, "fs_generation of #%u", (unsigned long long)bh->b_blocknr, le32_to_cpu(gd->bg_generation)); - return -EINVAL; } if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) { @@ -209,7 +206,6 @@ static int ocfs2_validate_gd_self(struct super_block *sb, (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits), le16_to_cpu(gd->bg_free_bits_count)); - return -EINVAL; } if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) { @@ -218,7 +214,6 @@ static int ocfs2_validate_gd_self(struct super_block *sb, (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits), 8 * le16_to_cpu(gd->bg_size)); - return -EINVAL; } return 0; @@ -238,7 +233,6 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(gd->bg_parent_dinode), (unsigned long long)le64_to_cpu(di->i_blkno)); - return -EINVAL; } max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * le16_to_cpu(di->id2.i_chain.cl_bpc); @@ -246,7 +240,6 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, do_error("Group descriptor #%llu has bit count of %u", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits)); - return -EINVAL; } /* In resize, we may meet the case bg_chain == cl_next_free_rec. */ @@ -257,7 +250,6 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, do_error("Group descriptor #%llu has bad chain %u", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_chain)); - return -EINVAL; } return 0; @@ -384,11 +376,10 @@ static int ocfs2_block_group_fill(handle_t *handle, struct super_block * sb = alloc_inode->i_sb; if (((unsigned long long) bg_bh->b_blocknr) != group_blkno) { - ocfs2_error(alloc_inode->i_sb, "group block (%llu) != " + status = ocfs2_error(alloc_inode->i_sb, "group block (%llu) != " "b_blocknr (%llu)", (unsigned long long)group_blkno, (unsigned long long) bg_bh->b_blocknr); - status = -EIO; goto bail; } @@ -834,9 +825,8 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb, BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) { - ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator %llu", + status = ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator %llu", (unsigned long long)le64_to_cpu(fe->i_blkno)); - status = -EIO; goto bail; } @@ -1370,12 +1360,11 @@ int ocfs2_block_group_set_bits(handle_t *handle, le16_add_cpu(&bg->bg_free_bits_count, -num_bits); if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) { - ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit" + return ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit" " count %u but claims %u are freed. num_bits %d", (unsigned long long)le64_to_cpu(bg->bg_blkno), le16_to_cpu(bg->bg_bits), le16_to_cpu(bg->bg_free_bits_count), num_bits); - return -EROFS; } while(num_bits--) ocfs2_set_bit(bit_off++, bitmap); @@ -1905,13 +1894,12 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, if (le32_to_cpu(fe->id1.bitmap1.i_used) >= le32_to_cpu(fe->id1.bitmap1.i_total)) { - ocfs2_error(ac->ac_inode->i_sb, + status = ocfs2_error(ac->ac_inode->i_sb, "Chain allocator dinode %llu has %u used " "bits but only %u total.", (unsigned long long)le64_to_cpu(fe->i_blkno), le32_to_cpu(fe->id1.bitmap1.i_used), le32_to_cpu(fe->id1.bitmap1.i_total)); - status = -EIO; goto bail; } @@ -2429,12 +2417,11 @@ static int ocfs2_block_group_clear_bits(handle_t *handle, } le16_add_cpu(&bg->bg_free_bits_count, num_bits); if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) { - ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit" + return ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit" " count %u but claims %u are freed. num_bits %d", (unsigned long long)le64_to_cpu(bg->bg_blkno), le16_to_cpu(bg->bg_bits), le16_to_cpu(bg->bg_free_bits_count), num_bits); - return -EROFS; } if (undo_fn) diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index a24f264b2fc44..5944a311bb947 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -499,30 +499,27 @@ static int ocfs2_validate_xattr_block(struct super_block *sb, */ if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { - ocfs2_error(sb, + return ocfs2_error(sb, "Extended attribute block #%llu has bad " "signature %.*s", (unsigned long long)bh->b_blocknr, 7, xb->xb_signature); - return -EINVAL; } if (le64_to_cpu(xb->xb_blkno) != bh->b_blocknr) { - ocfs2_error(sb, + return ocfs2_error(sb, "Extended attribute block #%llu has an " "invalid xb_blkno of %llu", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(xb->xb_blkno)); - return -EINVAL; } if (le32_to_cpu(xb->xb_fs_generation) != OCFS2_SB(sb)->fs_generation) { - ocfs2_error(sb, + return ocfs2_error(sb, "Extended attribute block #%llu has an invalid " "xb_fs_generation of #%u", (unsigned long long)bh->b_blocknr, le32_to_cpu(xb->xb_fs_generation)); - return -EINVAL; } return 0; @@ -3694,11 +3691,10 @@ static int ocfs2_xattr_get_rec(struct inode *inode, el = &eb->h_list; if (el->l_tree_depth) { - ocfs2_error(inode->i_sb, + ret = ocfs2_error(inode->i_sb, "Inode %lu has non zero tree depth in " "xattr tree block %llu\n", inode->i_ino, (unsigned long long)eb_bh->b_blocknr); - ret = -EROFS; goto out; } } @@ -3713,11 +3709,10 @@ static int ocfs2_xattr_get_rec(struct inode *inode, } if (!e_blkno) { - ocfs2_error(inode->i_sb, "Inode %lu has bad extent " + ret = ocfs2_error(inode->i_sb, "Inode %lu has bad extent " "record (%u, %u, 0) in xattr", inode->i_ino, le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); - ret = -EROFS; goto out; } -- GitLab From 34237681e02ad1617138926f437d0a147249ec13 Mon Sep 17 00:00:00 2001 From: Goldwyn Rodrigues Date: Fri, 4 Sep 2015 15:44:20 -0700 Subject: [PATCH 6377/7006] ocfs2: clear the rest of the buffers on error In case a validation fails, clear the rest of the buffers and return the error to the calling function. This also facilitates bubbling up the error originating from ocfs2_error to calling functions. Signed-off-by: Goldwyn Rodrigues Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/buffer_head_io.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c index 1edcb141f6393..fe50ded1b4ce7 100644 --- a/fs/ocfs2/buffer_head_io.c +++ b/fs/ocfs2/buffer_head_io.c @@ -316,6 +316,12 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr, bh = bhs[i]; if (!(flags & OCFS2_BH_READAHEAD)) { + if (status) { + /* Clear the rest of the buffers on error */ + put_bh(bh); + bhs[i] = NULL; + continue; + } /* We know this can't have changed as we hold the * owner sem. Avoid doing any work on the bh if the * journal has it. */ -- GitLab From 6ab855a99b735c227ad1e0deda636833f41c5b87 Mon Sep 17 00:00:00 2001 From: WeiWei Wang Date: Fri, 4 Sep 2015 15:44:23 -0700 Subject: [PATCH 6378/7006] ocfs2: add ip_alloc_sem in direct IO to protect allocation changes In ocfs2, ip_alloc_sem is used to protect allocation changes on the node. In direct IO, we add ip_alloc_sem to protect date consistent between direct-io and ocfs2_truncate_file race (buffer io use ip_alloc_sem already). Although inode->i_mutex lock is used to avoid concurrency of above situation, i think ip_alloc_sem is still needed because protect allocation changes is significant. Other filesystem like ext4 also uses rw_semaphore to protect data consistent between get_block-vs-truncate race by other means, So ip_alloc_sem in ocfs2 direct io is needed. Signed-off-by: Weiwei Wang Signed-off-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/aops.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index b36dcad3a1405..a7ab145e29014 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -533,10 +533,14 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, inode_blocks = ocfs2_blocks_for_bytes(inode->i_sb, i_size_read(inode)); + down_read(&OCFS2_I(inode)->ip_alloc_sem); + /* This figures out the size of the next contiguous block, and * our logical offset */ ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &contig_blocks, &ext_flags); + up_read(&OCFS2_I(inode)->ip_alloc_sem); + if (ret) { mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n", (unsigned long long)iblock); @@ -557,6 +561,8 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, alloc_locked = 1; + down_write(&OCFS2_I(inode)->ip_alloc_sem); + /* fill hole, allocate blocks can't be larger than the size * of the hole */ clusters_to_alloc = ocfs2_clusters_for_bytes(inode->i_sb, len); @@ -569,6 +575,7 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ret = ocfs2_extend_allocation(inode, cpos, clusters_to_alloc, 0); if (ret < 0) { + up_write(&OCFS2_I(inode)->ip_alloc_sem); mlog_errno(ret); goto bail; } @@ -576,11 +583,13 @@ static int ocfs2_direct_IO_get_blocks(struct inode *inode, sector_t iblock, ret = ocfs2_extent_map_get_blocks(inode, iblock, &p_blkno, &contig_blocks, &ext_flags); if (ret < 0) { + up_write(&OCFS2_I(inode)->ip_alloc_sem); mlog(ML_ERROR, "get_blocks() failed iblock=%llu\n", (unsigned long long)iblock); ret = -EIO; goto bail; } + up_write(&OCFS2_I(inode)->ip_alloc_sem); } /* @@ -835,12 +844,17 @@ static ssize_t ocfs2_direct_IO_write(struct kiocb *iocb, /* zeroing out the previously allocated cluster tail * that but not zeroed */ - if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) + if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) { + down_read(&OCFS2_I(inode)->ip_alloc_sem); ret = ocfs2_direct_IO_zero_extend(osb, inode, offset, zero_len_tail, cluster_align_tail); - else + up_read(&OCFS2_I(inode)->ip_alloc_sem); + } else { + down_write(&OCFS2_I(inode)->ip_alloc_sem); ret = ocfs2_direct_IO_extend_no_holes(osb, inode, offset); + up_write(&OCFS2_I(inode)->ip_alloc_sem); + } if (ret < 0) { mlog_errno(ret); ocfs2_inode_unlock(inode, 1); -- GitLab From 928dda1f9433f024ac48c3d97ae683bf83dd0e42 Mon Sep 17 00:00:00 2001 From: Yiwen Jiang Date: Fri, 4 Sep 2015 15:44:25 -0700 Subject: [PATCH 6379/7006] ocfs2: fix a tiny case that inode can not removed When running dirop_fileop_racer we found a case that inode can not removed. Two nodes, say Node A and Node B, mount the same ocfs2 volume. Create two dirs /race/1/ and /race/2/ in the filesystem. Node A Node B rm -r /race/2/ mv /race/1/ /race/2/ call ocfs2_unlink(), get the EX mode of /race/2/ wait for B unlock /race/2/ decrease i_nlink of /race/2/ to 0, and add inode of /race/2/ into orphan dir, unlock /race/2/ got EX mode of /race/2/. because /race/1/ is dir, so inc i_nlink of /race/2/ and update into disk, unlock /race/2/ because i_nlink of /race/2/ is not zero, this inode will always remain in orphan dir This patch fixes this case by test whether i_nlink of new dir is zero. Signed-off-by: Yiwen Jiang Reviewed-by: Mark Fasheh Cc: Joel Becker Cc: Joseph Qi Cc: Xue jiufei Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/namei.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 1c43993e81b05..b7dfac226b1e2 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -1309,6 +1309,11 @@ static int ocfs2_rename(struct inode *old_dir, } parents_locked = 1; + if (!new_dir->i_nlink) { + status = -EACCES; + goto bail; + } + /* make sure both dirs have bhs * get an extra ref on old_dir_bh if old==new */ if (!new_dir_bh) { -- GitLab From 72f6fe1fe5a386225cdc30f025681830a63a117e Mon Sep 17 00:00:00 2001 From: "Norton.Zhu" Date: Fri, 4 Sep 2015 15:44:28 -0700 Subject: [PATCH 6380/7006] ocfs2: optimize error handling in dlm_request_join Currently error handling in dlm_request_join is a little obscure, so optimize it to promote readability. If packet.code is invalid, reset it to JOIN_DISALLOW to keep it meaningful. It only influences the log printing. Signed-off-by: Norton.Zhu Cc: Srinivas Eeda Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlm/dlmdomain.c | 71 ++++++++++++++++++++++------------------ 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 019459b20aeb8..6918f30d02cd7 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -1465,39 +1465,46 @@ static int dlm_request_join(struct dlm_ctxt *dlm, if (status == -ENOPROTOOPT) { status = 0; *response = JOIN_OK_NO_MAP; - } else if (packet.code == JOIN_DISALLOW || - packet.code == JOIN_OK_NO_MAP) { - *response = packet.code; - } else if (packet.code == JOIN_PROTOCOL_MISMATCH) { - mlog(ML_NOTICE, - "This node requested DLM locking protocol %u.%u and " - "filesystem locking protocol %u.%u. At least one of " - "the protocol versions on node %d is not compatible, " - "disconnecting\n", - dlm->dlm_locking_proto.pv_major, - dlm->dlm_locking_proto.pv_minor, - dlm->fs_locking_proto.pv_major, - dlm->fs_locking_proto.pv_minor, - node); - status = -EPROTO; - *response = packet.code; - } else if (packet.code == JOIN_OK) { - *response = packet.code; - /* Use the same locking protocol as the remote node */ - dlm->dlm_locking_proto.pv_minor = packet.dlm_minor; - dlm->fs_locking_proto.pv_minor = packet.fs_minor; - mlog(0, - "Node %d responds JOIN_OK with DLM locking protocol " - "%u.%u and fs locking protocol %u.%u\n", - node, - dlm->dlm_locking_proto.pv_major, - dlm->dlm_locking_proto.pv_minor, - dlm->fs_locking_proto.pv_major, - dlm->fs_locking_proto.pv_minor); } else { - status = -EINVAL; - mlog(ML_ERROR, "invalid response %d from node %u\n", - packet.code, node); + *response = packet.code; + switch (packet.code) { + case JOIN_DISALLOW: + case JOIN_OK_NO_MAP: + break; + case JOIN_PROTOCOL_MISMATCH: + mlog(ML_NOTICE, + "This node requested DLM locking protocol %u.%u and " + "filesystem locking protocol %u.%u. At least one of " + "the protocol versions on node %d is not compatible, " + "disconnecting\n", + dlm->dlm_locking_proto.pv_major, + dlm->dlm_locking_proto.pv_minor, + dlm->fs_locking_proto.pv_major, + dlm->fs_locking_proto.pv_minor, + node); + status = -EPROTO; + break; + case JOIN_OK: + /* Use the same locking protocol as the remote node */ + dlm->dlm_locking_proto.pv_minor = packet.dlm_minor; + dlm->fs_locking_proto.pv_minor = packet.fs_minor; + mlog(0, + "Node %d responds JOIN_OK with DLM locking protocol " + "%u.%u and fs locking protocol %u.%u\n", + node, + dlm->dlm_locking_proto.pv_major, + dlm->dlm_locking_proto.pv_minor, + dlm->fs_locking_proto.pv_major, + dlm->fs_locking_proto.pv_minor); + break; + default: + status = -EINVAL; + mlog(ML_ERROR, "invalid response %d from node %u\n", + packet.code, node); + /* Reset response to JOIN_DISALLOW */ + *response = JOIN_DISALLOW; + break; + } } mlog(0, "status %d, node %d response is %d\n", status, node, -- GitLab From 3d46a44a0c01b15d385ccaae24b56f619613c256 Mon Sep 17 00:00:00 2001 From: Tariq Saeed Date: Fri, 4 Sep 2015 15:44:31 -0700 Subject: [PATCH 6381/7006] ocfs2: fix BUG_ON() in ocfs2_ci_checkpointed() PID: 614 TASK: ffff882a739da580 CPU: 3 COMMAND: "ocfs2dc" #0 [ffff882ecc3759b0] machine_kexec at ffffffff8103b35d #1 [ffff882ecc375a20] crash_kexec at ffffffff810b95b5 #2 [ffff882ecc375af0] oops_end at ffffffff815091d8 #3 [ffff882ecc375b20] die at ffffffff8101868b #4 [ffff882ecc375b50] do_trap at ffffffff81508bb0 #5 [ffff882ecc375ba0] do_invalid_op at ffffffff810165e5 #6 [ffff882ecc375c40] invalid_op at ffffffff815116fb [exception RIP: ocfs2_ci_checkpointed+208] RIP: ffffffffa0a7e940 RSP: ffff882ecc375cf0 RFLAGS: 00010002 RAX: 0000000000000001 RBX: 000000000000654b RCX: ffff8812dc83f1f8 RDX: 00000000000017d9 RSI: ffff8812dc83f1f8 RDI: ffffffffa0b2c318 RBP: ffff882ecc375d20 R8: ffff882ef6ecfa60 R9: ffff88301f272200 R10: 0000000000000000 R11: 0000000000000000 R12: ffffffffffffffff R13: ffff8812dc83f4f0 R14: 0000000000000000 R15: ffff8812dc83f1f8 ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff882ecc375d28] ocfs2_check_meta_downconvert at ffffffffa0a7edbd [ocfs2] #8 [ffff882ecc375d38] ocfs2_unblock_lock at ffffffffa0a84af8 [ocfs2] #9 [ffff882ecc375dc8] ocfs2_process_blocked_lock at ffffffffa0a85285 [ocfs2] #10 [ffff882ecc375e18] ocfs2_downconvert_thread_do_work at ffffffffa0a85445 [ocfs2] #11 [ffff882ecc375e68] ocfs2_downconvert_thread at ffffffffa0a854de [ocfs2] #12 [ffff882ecc375ee8] kthread at ffffffff81090da7 #13 [ffff882ecc375f48] kernel_thread_helper at ffffffff81511884 assert is tripped because the tran is not checkpointed and the lock level is PR. Some time ago, chmod command had been executed. As result, the following call chain left the inode cluster lock in PR state, latter on causing the assert. system_call_fastpath -> my_chmod -> sys_chmod -> sys_fchmodat -> notify_change -> ocfs2_setattr -> posix_acl_chmod -> ocfs2_iop_set_acl -> ocfs2_set_acl -> ocfs2_acl_set_mode Here is how. 1119 int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) 1120 { 1247 ocfs2_inode_unlock(inode, 1); <<< WRONG thing to do. .. 1258 if (!status && attr->ia_valid & ATTR_MODE) { 1259 status = posix_acl_chmod(inode, inode->i_mode); 519 posix_acl_chmod(struct inode *inode, umode_t mode) 520 { .. 539 ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS); 287 int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, ... 288 { 289 return ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); 224 int ocfs2_set_acl(handle_t *handle, 225 struct inode *inode, ... 231 { .. 252 ret = ocfs2_acl_set_mode(inode, di_bh, 253 handle, mode); 168 static int ocfs2_acl_set_mode(struct inode *inode, struct buffer_head ... 170 { 183 if (handle == NULL) { >>> BUG: inode lock not held in ex at this point <<< 184 handle = ocfs2_start_trans(OCFS2_SB(inode->i_sb), 185 OCFS2_INODE_UPDATE_CREDITS); ocfs2_setattr.#1247 we unlock and at #1259 call posix_acl_chmod. When we reach ocfs2_acl_set_mode.#181 and do trans, the inode cluster lock is not held in EX mode (it should be). How this could have happended? We are the lock master, were holding lock EX and have released it in ocfs2_setattr.#1247. Note that there are no holders of this lock at this point. Another node needs the lock in PR, and we downconvert from EX to PR. So the inode lock is PR when do the trans in ocfs2_acl_set_mode.#184. The trans stays in core (not flushed to disc). Now another node want the lock in EX, downconvert thread gets kicked (the one that tripped assert abovt), finds an unflushed trans but the lock is not EX (it is PR). If the lock was at EX, it would have flushed the trans ocfs2_ci_checkpointed -> ocfs2_start_checkpoint before downconverting (to NULL) for the request. ocfs2_setattr must not drop inode lock ex in this code path. If it does, takes it again before the trans, say in ocfs2_set_acl, another cluster node can get in between, execute another setattr, overwriting the one in progress on this node, resulting in a mode acl size combo that is a mix of the two. Orabug: 20189959 Signed-off-by: Tariq Saeed Reviewed-by: Mark Fasheh Cc: Joel Becker Cc: Joseph Qi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/file.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index c4a99fb61c3e4..0e5b4515f92e7 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1130,6 +1130,7 @@ out: int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) { int status = 0, size_change; + int inode_locked = 0; struct inode *inode = d_inode(dentry); struct super_block *sb = inode->i_sb; struct ocfs2_super *osb = OCFS2_SB(sb); @@ -1178,6 +1179,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) mlog_errno(status); goto bail_unlock_rw; } + inode_locked = 1; if (size_change) { status = inode_newsize_ok(inode, attr->ia_size); @@ -1258,7 +1260,10 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) bail_commit: ocfs2_commit_trans(osb, handle); bail_unlock: - ocfs2_inode_unlock(inode, 1); + if (status) { + ocfs2_inode_unlock(inode, 1); + inode_locked = 0; + } bail_unlock_rw: if (size_change) ocfs2_rw_unlock(inode, 1); @@ -1274,6 +1279,8 @@ bail: if (status < 0) mlog_errno(status); } + if (inode_locked) + ocfs2_inode_unlock(inode, 1); return status; } -- GitLab From 743b5f1434f57a147226c747fe228cadeb7b05ed Mon Sep 17 00:00:00 2001 From: Tariq Saeed Date: Fri, 4 Sep 2015 15:44:34 -0700 Subject: [PATCH 6382/7006] ocfs2: take inode lock in ocfs2_iop_set/get_acl() This bug in mainline code is pointed out by Mark Fasheh. When ocfs2_iop_set_acl() and ocfs2_iop_get_acl() are entered from VFS layer, inode lock is not held. This seems to be regression from older kernels. The patch is to fix that. Orabug: 20189959 Signed-off-by: Tariq Saeed Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/acl.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index c58a1bcfda0fd..0cdf497c91efb 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c @@ -284,7 +284,19 @@ int ocfs2_set_acl(handle_t *handle, int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type) { - return ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL); + struct buffer_head *bh = NULL; + int status = 0; + + status = ocfs2_inode_lock(inode, &bh, 1); + if (status < 0) { + if (status != -ENOENT) + mlog_errno(status); + return status; + } + status = ocfs2_set_acl(NULL, inode, bh, type, acl, NULL, NULL); + ocfs2_inode_unlock(inode, 1); + brelse(bh); + return status; } struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) @@ -292,19 +304,21 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type) struct ocfs2_super *osb; struct buffer_head *di_bh = NULL; struct posix_acl *acl; - int ret = -EAGAIN; + int ret; osb = OCFS2_SB(inode->i_sb); if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) return NULL; - - ret = ocfs2_read_inode_block(inode, &di_bh); - if (ret < 0) + ret = ocfs2_inode_lock(inode, &di_bh, 0); + if (ret < 0) { + if (ret != -ENOENT) + mlog_errno(ret); return ERR_PTR(ret); + } acl = ocfs2_get_acl_nolock(inode, type, di_bh); + ocfs2_inode_unlock(inode, 0); brelse(di_bh); - return acl; } -- GitLab From f57a22ddecd6f26040a67e2c12880f98f88b6e00 Mon Sep 17 00:00:00 2001 From: Yiwen Jiang Date: Fri, 4 Sep 2015 15:44:37 -0700 Subject: [PATCH 6383/7006] ocfs2: avoid access invalid address when read o2dlm debug messages The following case will lead to a lockres is freed but is still in use. cat /sys/kernel/debug/o2dlm/locking_state dlm_thread lockres_seq_start -> lock dlm->track_lock -> get resA resA->refs decrease to 0, call dlm_lockres_release, and wait for "cat" unlock. Although resA->refs is already set to 0, increase resA->refs, and then unlock lock dlm->track_lock -> list_del_init() -> unlock -> free resA In such a race case, invalid address access may occurs. So we should delete list res->tracking before resA->refs decrease to 0. Signed-off-by: Yiwen Jiang Reviewed-by: Joseph Qi Cc: Joel Becker Signed-off-by: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlm/dlmmaster.c | 22 +++++++++++----------- fs/ocfs2/dlm/dlmthread.c | 10 ++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index fdf4b41d0609a..46b8b2bbc95ae 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c @@ -498,16 +498,6 @@ static void dlm_lockres_release(struct kref *kref) mlog(0, "destroying lockres %.*s\n", res->lockname.len, res->lockname.name); - spin_lock(&dlm->track_lock); - if (!list_empty(&res->tracking)) - list_del_init(&res->tracking); - else { - mlog(ML_ERROR, "Resource %.*s not on the Tracking list\n", - res->lockname.len, res->lockname.name); - dlm_print_one_lock_resource(res); - } - spin_unlock(&dlm->track_lock); - atomic_dec(&dlm->res_cur_count); if (!hlist_unhashed(&res->hash_node) || @@ -795,8 +785,18 @@ lookup: dlm_lockres_grab_inflight_ref(dlm, tmpres); spin_unlock(&tmpres->spinlock); - if (res) + if (res) { + spin_lock(&dlm->track_lock); + if (!list_empty(&res->tracking)) + list_del_init(&res->tracking); + else + mlog(ML_ERROR, "Resource %.*s not " + "on the Tracking list\n", + res->lockname.len, + res->lockname.name); + spin_unlock(&dlm->track_lock); dlm_lockres_put(res); + } res = tmpres; goto leave; } diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c index 69aac6f088ada..2e5e6d5fffe8d 100644 --- a/fs/ocfs2/dlm/dlmthread.c +++ b/fs/ocfs2/dlm/dlmthread.c @@ -211,6 +211,16 @@ static void dlm_purge_lockres(struct dlm_ctxt *dlm, __dlm_unhash_lockres(dlm, res); + spin_lock(&dlm->track_lock); + if (!list_empty(&res->tracking)) + list_del_init(&res->tracking); + else { + mlog(ML_ERROR, "Resource %.*s not on the Tracking list\n", + res->lockname.len, res->lockname.name); + __dlm_print_one_lock_resource(res); + } + spin_unlock(&dlm->track_lock); + /* lockres is not in the hash now. drop the flag and wake up * any processes waiting in dlm_get_lock_resource. */ if (!master) { -- GitLab From ad694821224634d46b6571f0161e85ac2e397396 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:44:40 -0700 Subject: [PATCH 6384/7006] ocfs2: fix race between crashed dio and rm There is a race case between crashed dio and rm, which will lead to OCFS2_VALID_FL not set read-only. N1 N2 ------------------------------------------------------------------------ dd with direct flag rm file crashed with an dio entry left in orphan dir clear OCFS2_VALID_FL in ocfs2_remove_inode recover N1 and read the corrupted inode, and set filesystem read-only So we skip the inode deletion this time and wait for dio entry recovered first. Signed-off-by: Joseph Qi Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/inode.c | 9 +++++++++ fs/ocfs2/journal.c | 4 +++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 7868f7e7c455b..fe4b3f7db2455 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -971,6 +971,7 @@ static void ocfs2_delete_inode(struct inode *inode) int wipe, status; sigset_t oldset; struct buffer_head *di_bh = NULL; + struct ocfs2_dinode *di = NULL; trace_ocfs2_delete_inode(inode->i_ino, (unsigned long long)OCFS2_I(inode)->ip_blkno, @@ -1025,6 +1026,14 @@ static void ocfs2_delete_inode(struct inode *inode) goto bail_unlock_nfs_sync; } + di = (struct ocfs2_dinode *)di_bh->b_data; + /* Skip inode deletion and wait for dio orphan entry recovered + * first */ + if (unlikely(di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL))) { + ocfs2_cleanup_delete_inode(inode, 0); + goto bail_unlock_inode; + } + /* Query the cluster. This will be the final decision made * before we go ahead and wipe the inode. */ status = ocfs2_query_inode_wipe(inode, di_bh, &wipe); diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 3bfd36a23e401..52948af646b63 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -2210,7 +2210,9 @@ static int ocfs2_recover_orphans(struct ocfs2_super *osb, * ocfs2_delete_inode. */ oi->ip_flags |= OCFS2_INODE_MAYBE_ORPHANED; spin_unlock(&oi->ip_lock); - } else if ((orphan_reco_type == ORPHAN_NEED_TRUNCATE) && + } + + if ((orphan_reco_type == ORPHAN_NEED_TRUNCATE) && (di->i_flags & cpu_to_le32(OCFS2_DIO_ORPHANED_FL))) { ret = ocfs2_truncate_file(inode, di_bh, i_size_read(inode)); -- GitLab From 40476b8294466d40e7db57b4cbf69a831a4486b8 Mon Sep 17 00:00:00 2001 From: Tina Ruchandani Date: Fri, 4 Sep 2015 15:44:43 -0700 Subject: [PATCH 6385/7006] ocfs2: use 64bit variables to track heartbeat time o2hb_elapsed_msecs computes the time taken for a disk heartbeat. 'struct timeval' variables are used to store start and end times. On 32-bit systems, the 'tv_sec' component of 'struct timeval' will overflow in year 2038 and beyond. This patch solves the overflow with the following: 1. Replace o2hb_elapsed_msecs using 'ktime_t' values to measure start and end time, and built-in function 'ktime_ms_delta' to compute the elapsed time. ktime_get_real() is used since the code prints out the wallclock time. 2. Changes format string to print time as a single 64-bit nanoseconds value ("%lld") instead of seconds and microseconds. This simplifies the code since converting ktime_t to that format would need expensive computation. However, the debug log string is less readable than the previous format. Signed-off-by: Tina Ruchandani Suggested by: Arnd Bergmann Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/cluster/heartbeat.c | 49 +++++++----------------------------- 1 file changed, 9 insertions(+), 40 deletions(-) diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c index f97306453a0b3..fa15debcc02be 100644 --- a/fs/ocfs2/cluster/heartbeat.c +++ b/fs/ocfs2/cluster/heartbeat.c @@ -36,7 +36,7 @@ #include #include #include - +#include #include "heartbeat.h" #include "tcp.h" #include "nodemanager.h" @@ -1060,37 +1060,6 @@ bail: return ret; } -/* Subtract b from a, storing the result in a. a *must* have a larger - * value than b. */ -static void o2hb_tv_subtract(struct timeval *a, - struct timeval *b) -{ - /* just return 0 when a is after b */ - if (a->tv_sec < b->tv_sec || - (a->tv_sec == b->tv_sec && a->tv_usec < b->tv_usec)) { - a->tv_sec = 0; - a->tv_usec = 0; - return; - } - - a->tv_sec -= b->tv_sec; - a->tv_usec -= b->tv_usec; - while ( a->tv_usec < 0 ) { - a->tv_sec--; - a->tv_usec += 1000000; - } -} - -static unsigned int o2hb_elapsed_msecs(struct timeval *start, - struct timeval *end) -{ - struct timeval res = *end; - - o2hb_tv_subtract(&res, start); - - return res.tv_sec * 1000 + res.tv_usec / 1000; -} - /* * we ride the region ref that the region dir holds. before the region * dir is removed and drops it ref it will wait to tear down this @@ -1101,7 +1070,7 @@ static int o2hb_thread(void *data) int i, ret; struct o2hb_region *reg = data; struct o2hb_bio_wait_ctxt write_wc; - struct timeval before_hb, after_hb; + ktime_t before_hb, after_hb; unsigned int elapsed_msec; mlog(ML_HEARTBEAT|ML_KTHREAD, "hb thread running\n"); @@ -1118,18 +1087,18 @@ static int o2hb_thread(void *data) * hr_timeout_ms between disk writes. On busy systems * this should result in a heartbeat which is less * likely to time itself out. */ - do_gettimeofday(&before_hb); + before_hb = ktime_get_real(); ret = o2hb_do_disk_heartbeat(reg); - do_gettimeofday(&after_hb); - elapsed_msec = o2hb_elapsed_msecs(&before_hb, &after_hb); + after_hb = ktime_get_real(); + + elapsed_msec = (unsigned int) + ktime_ms_delta(after_hb, before_hb); mlog(ML_HEARTBEAT, - "start = %lu.%lu, end = %lu.%lu, msec = %u, ret = %d\n", - before_hb.tv_sec, (unsigned long) before_hb.tv_usec, - after_hb.tv_sec, (unsigned long) after_hb.tv_usec, - elapsed_msec, ret); + "start = %lld, end = %lld, msec = %u, ret = %d\n", + before_hb.tv64, after_hb.tv64, elapsed_msec, ret); if (!kthread_should_stop() && elapsed_msec < reg->hr_timeout_ms) { -- GitLab From 7f27ec978b0ef37391262bbf15c587fd8526e268 Mon Sep 17 00:00:00 2001 From: yangwenfang Date: Fri, 4 Sep 2015 15:44:45 -0700 Subject: [PATCH 6386/7006] ocfs2: call ocfs2_journal_access_di() before ocfs2_journal_dirty() in ocfs2_write_end_nolock() 1: After we call ocfs2_journal_access_di() in ocfs2_write_begin(), jbd2_journal_restart() may also be called, in this function transaction A's t_updates-- and obtains a new transaction B. If jbd2_journal_commit_transaction() is happened to commit transaction A, when t_updates==0, it will continue to complete commit and unfile buffer. So when jbd2_journal_dirty_metadata(), the handle is pointed a new transaction B, and the buffer head's journal head is already freed, jh->b_transaction == NULL, jh->b_next_transaction == NULL, it returns EINVAL, So it triggers the BUG_ON(status). thread 1 jbd2 ocfs2_write_begin jbd2_journal_commit_transaction ocfs2_write_begin_nolock ocfs2_start_trans jbd2__journal_start(t_updates+1, transaction A) ocfs2_journal_access_di ocfs2_write_cluster_by_desc ocfs2_mark_extent_written ocfs2_change_extent_flag ocfs2_split_extent ocfs2_extend_rotate_transaction jbd2_journal_restart (t_updates-1,transaction B) t_updates==0 __jbd2_journal_refile_buffer (jh->b_transaction = NULL) ocfs2_write_end ocfs2_write_end_nolock ocfs2_journal_dirty jbd2_journal_dirty_metadata(bug) ocfs2_commit_trans 2. In ext4, I found that: jbd2_journal_get_write_access() called by ext4_write_end. ext4_write_begin ext4_journal_start __ext4_journal_start_sb ext4_journal_check_start jbd2__journal_start ext4_write_end ext4_mark_inode_dirty ext4_reserve_inode_write ext4_journal_get_write_access jbd2_journal_get_write_access ext4_mark_iloc_dirty ext4_do_update_inode ext4_handle_dirty_metadata jbd2_journal_dirty_metadata 3. So I think we should put ocfs2_journal_access_di before ocfs2_journal_dirty in the ocfs2_write_end. and it works well after my modification. Signed-off-by: vicky Reviewed-by: Mark Fasheh Cc: Joel Becker Cc: Zhangguanghui Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/aops.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index a7ab145e29014..faf36a96cd19d 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -2207,10 +2207,7 @@ try_again: if (ret) goto out_commit; } - /* - * We don't want this to fail in ocfs2_write_end(), so do it - * here. - */ + ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), wc->w_di_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (ret) { @@ -2367,7 +2364,7 @@ int ocfs2_write_end_nolock(struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) { - int i; + int i, ret; unsigned from, to, start = pos & (PAGE_CACHE_SIZE - 1); struct inode *inode = mapping->host; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); @@ -2376,6 +2373,14 @@ int ocfs2_write_end_nolock(struct address_space *mapping, handle_t *handle = wc->w_handle; struct page *tmppage; + ret = ocfs2_journal_access_di(handle, INODE_CACHE(inode), wc->w_di_bh, + OCFS2_JOURNAL_ACCESS_WRITE); + if (ret) { + copied = ret; + mlog_errno(ret); + goto out; + } + if (OCFS2_I(inode)->ip_dyn_features & OCFS2_INLINE_DATA_FL) { ocfs2_write_end_inline(inode, pos, len, &copied, di, wc); goto out_write_size; @@ -2431,6 +2436,7 @@ out_write_size: ocfs2_update_inode_fsync_trans(handle, inode, 1); ocfs2_journal_dirty(handle, wc->w_di_bh); +out: /* unlock pages before dealloc since it needs acquiring j_trans_barrier * lock, or it will cause a deadlock since journal commit threads holds * this lock and will ask for the page lock when flushing the data. -- GitLab From d0c97d52f5e1de125394d748be7bd5763fd9ed9e Mon Sep 17 00:00:00 2001 From: Xue jiufei Date: Fri, 4 Sep 2015 15:44:48 -0700 Subject: [PATCH 6387/7006] ocfs2: do not set fs read-only if rec[0] is empty while committing truncate While appending an extent to a file, it will call these functions: ocfs2_insert_extent -> call ocfs2_grow_tree() if there's no free rec -> ocfs2_add_branch add a new branch to extent tree, now rec[0] in the leaf of rightmost path is empty -> ocfs2_do_insert_extent -> ocfs2_rotate_tree_right -> ocfs2_extend_rotate_transaction -> jbd2_journal_restart if jbd2_journal_extend fail -> ocfs2_insert_path -> ocfs2_extend_trans -> jbd2_journal_restart if jbd2_journal_extend fail -> ocfs2_insert_at_leaf -> ocfs2_et_update_clusters Function jbd2_journal_restart() may be called and it may happened that buffers dirtied in ocfs2_add_branch() are committed while buffers dirtied in ocfs2_insert_at_leaf() and ocfs2_et_update_clusters() are not. So an empty rec[0] is left in rightmost path which will cause read-only filesystem when call ocfs2_commit_truncate() with the error message: "Inode %lu has an empty extent record". This is not a serious problem, so remove the rightmost path when call ocfs2_commit_truncate(). Signed-off-by: joyce.xue Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/alloc.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 9a0fd494fe748..77cbd1e3c950f 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -3131,6 +3131,30 @@ out: return ret; } +static int ocfs2_remove_rightmost_empty_extent(struct ocfs2_super *osb, + struct ocfs2_extent_tree *et, + struct ocfs2_path *path, + struct ocfs2_cached_dealloc_ctxt *dealloc) +{ + handle_t *handle; + int ret; + int credits = path->p_tree_depth * 2 + 1; + + handle = ocfs2_start_trans(osb, credits); + if (IS_ERR(handle)) { + ret = PTR_ERR(handle); + mlog_errno(ret); + return ret; + } + + ret = ocfs2_remove_rightmost_path(handle, et, path, dealloc); + if (ret) + mlog_errno(ret); + + ocfs2_commit_trans(osb, handle); + return ret; +} + /* * Left rotation of btree records. * @@ -7108,15 +7132,23 @@ start: * to check it up here before changing the tree. */ if (root_el->l_tree_depth && rec->e_int_clusters == 0) { - ocfs2_error(inode->i_sb, "Inode %lu has an empty " + mlog(ML_ERROR, "Inode %lu has an empty " "extent record, depth %u\n", inode->i_ino, le16_to_cpu(root_el->l_tree_depth)); - status = -EROFS; - goto bail; + status = ocfs2_remove_rightmost_empty_extent(osb, + &et, path, &dealloc); + if (status) { + mlog_errno(status); + goto bail; + } + + ocfs2_reinit_path(path, 1); + goto start; + } else { + trunc_cpos = le32_to_cpu(rec->e_cpos); + trunc_len = 0; + blkno = 0; } - trunc_cpos = le32_to_cpu(rec->e_cpos); - trunc_len = 0; - blkno = 0; } else if (le32_to_cpu(rec->e_cpos) >= new_highest_cpos) { /* * Truncate entire record. -- GitLab From 7ecef14ab1db961545354fa443749aeda2ea1b75 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 4 Sep 2015 15:44:51 -0700 Subject: [PATCH 6388/7006] ocfs2: neaten do_error, ocfs2_error and ocfs2_abort These uses sometimes do and sometimes don't have '\n' terminations. Make the uses consistently use '\n' terminations and remove the newline from the functions. Miscellanea: o Coalesce formats o Realign arguments Signed-off-by: Joe Perches Reviewed-by: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/alloc.c | 86 +++++++++++++++-------------------------- fs/ocfs2/aops.c | 4 +- fs/ocfs2/dir.c | 49 +++++++++++------------ fs/ocfs2/extent_map.c | 22 ++++++----- fs/ocfs2/inode.c | 18 ++++----- fs/ocfs2/journal.c | 2 +- fs/ocfs2/localalloc.c | 3 +- fs/ocfs2/move_extents.c | 5 +-- fs/ocfs2/quota_local.c | 3 +- fs/ocfs2/refcounttree.c | 53 +++++++++++-------------- fs/ocfs2/suballoc.c | 75 +++++++++++++++++------------------ fs/ocfs2/super.c | 4 +- fs/ocfs2/super.h | 6 ++- fs/ocfs2/xattr.c | 35 ++++++++--------- 14 files changed, 163 insertions(+), 202 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index 77cbd1e3c950f..b20706e8a4d1c 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -909,27 +909,25 @@ static int ocfs2_validate_extent_block(struct super_block *sb, if (!OCFS2_IS_VALID_EXTENT_BLOCK(eb)) { rc = ocfs2_error(sb, - "Extent block #%llu has bad signature %.*s", - (unsigned long long)bh->b_blocknr, 7, - eb->h_signature); + "Extent block #%llu has bad signature %.*s\n", + (unsigned long long)bh->b_blocknr, 7, + eb->h_signature); goto bail; } if (le64_to_cpu(eb->h_blkno) != bh->b_blocknr) { rc = ocfs2_error(sb, - "Extent block #%llu has an invalid h_blkno " - "of %llu", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(eb->h_blkno)); + "Extent block #%llu has an invalid h_blkno of %llu\n", + (unsigned long long)bh->b_blocknr, + (unsigned long long)le64_to_cpu(eb->h_blkno)); goto bail; } if (le32_to_cpu(eb->h_fs_generation) != OCFS2_SB(sb)->fs_generation) { rc = ocfs2_error(sb, - "Extent block #%llu has an invalid " - "h_fs_generation of #%u", - (unsigned long long)bh->b_blocknr, - le32_to_cpu(eb->h_fs_generation)); + "Extent block #%llu has an invalid h_fs_generation of #%u\n", + (unsigned long long)bh->b_blocknr, + le32_to_cpu(eb->h_fs_generation)); goto bail; } bail: @@ -1446,8 +1444,7 @@ static int ocfs2_find_branch_target(struct ocfs2_extent_tree *et, while(le16_to_cpu(el->l_tree_depth) > 1) { if (le16_to_cpu(el->l_next_free_rec) == 0) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu has empty " - "extent list (next_free_rec == 0)", + "Owner %llu has empty extent list (next_free_rec == 0)\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci)); status = -EIO; goto bail; @@ -1456,9 +1453,7 @@ static int ocfs2_find_branch_target(struct ocfs2_extent_tree *et, blkno = le64_to_cpu(el->l_recs[i].e_blkno); if (!blkno) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu has extent " - "list where extent # %d has no physical " - "block start", + "Owner %llu has extent list where extent # %d has no physical block start\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), i); status = -EIO; goto bail; @@ -1788,8 +1783,7 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci, while (el->l_tree_depth) { if (le16_to_cpu(el->l_next_free_rec) == 0) { ocfs2_error(ocfs2_metadata_cache_get_super(ci), - "Owner %llu has empty extent list at " - "depth %u\n", + "Owner %llu has empty extent list at depth %u\n", (unsigned long long)ocfs2_metadata_cache_owner(ci), le16_to_cpu(el->l_tree_depth)); ret = -EROFS; @@ -1814,8 +1808,7 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci, blkno = le64_to_cpu(el->l_recs[i].e_blkno); if (blkno == 0) { ocfs2_error(ocfs2_metadata_cache_get_super(ci), - "Owner %llu has bad blkno in extent list " - "at depth %u (index %d)\n", + "Owner %llu has bad blkno in extent list at depth %u (index %d)\n", (unsigned long long)ocfs2_metadata_cache_owner(ci), le16_to_cpu(el->l_tree_depth), i); ret = -EROFS; @@ -1836,8 +1829,7 @@ static int __ocfs2_find_path(struct ocfs2_caching_info *ci, if (le16_to_cpu(el->l_next_free_rec) > le16_to_cpu(el->l_count)) { ocfs2_error(ocfs2_metadata_cache_get_super(ci), - "Owner %llu has bad count in extent list " - "at block %llu (next free=%u, count=%u)\n", + "Owner %llu has bad count in extent list at block %llu (next free=%u, count=%u)\n", (unsigned long long)ocfs2_metadata_cache_owner(ci), (unsigned long long)bh->b_blocknr, le16_to_cpu(el->l_next_free_rec), @@ -2116,8 +2108,7 @@ static int ocfs2_rotate_subtree_right(handle_t *handle, if (left_el->l_next_free_rec != left_el->l_count) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Inode %llu has non-full interior leaf node %llu" - "(next free = %u)", + "Inode %llu has non-full interior leaf node %llu (next free = %u)\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), (unsigned long long)left_leaf_bh->b_blocknr, le16_to_cpu(left_el->l_next_free_rec)); @@ -2256,8 +2247,7 @@ int ocfs2_find_cpos_for_left_leaf(struct super_block *sb, * If we got here, we never found a valid node where * the tree indicated one should be. */ - ocfs2_error(sb, - "Invalid extent tree at extent block %llu\n", + ocfs2_error(sb, "Invalid extent tree at extent block %llu\n", (unsigned long long)blkno); ret = -EROFS; goto out; @@ -2872,8 +2862,7 @@ int ocfs2_find_cpos_for_right_leaf(struct super_block *sb, * If we got here, we never found a valid node where * the tree indicated one should be. */ - ocfs2_error(sb, - "Invalid extent tree at extent block %llu\n", + ocfs2_error(sb, "Invalid extent tree at extent block %llu\n", (unsigned long long)blkno); ret = -EROFS; goto out; @@ -3224,7 +3213,7 @@ rightmost_no_delete: if (le16_to_cpu(el->l_next_free_rec) == 0) { ret = -EIO; ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu has empty extent block at %llu", + "Owner %llu has empty extent block at %llu\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), (unsigned long long)le64_to_cpu(eb->h_blkno)); goto out; @@ -3954,7 +3943,7 @@ static void ocfs2_adjust_rightmost_records(handle_t *handle, next_free = le16_to_cpu(el->l_next_free_rec); if (next_free == 0) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu has a bad extent list", + "Owner %llu has a bad extent list\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci)); ret = -EIO; return; @@ -4379,10 +4368,7 @@ static int ocfs2_figure_merge_contig_type(struct ocfs2_extent_tree *et, bh = path_leaf_bh(left_path); eb = (struct ocfs2_extent_block *)bh->b_data; ocfs2_error(sb, - "Extent block #%llu has an " - "invalid l_next_free_rec of " - "%d. It should have " - "matched the l_count of %d", + "Extent block #%llu has an invalid l_next_free_rec of %d. It should have matched the l_count of %d\n", (unsigned long long)le64_to_cpu(eb->h_blkno), le16_to_cpu(new_el->l_next_free_rec), le16_to_cpu(new_el->l_count)); @@ -4437,8 +4423,7 @@ static int ocfs2_figure_merge_contig_type(struct ocfs2_extent_tree *et, bh = path_leaf_bh(right_path); eb = (struct ocfs2_extent_block *)bh->b_data; ocfs2_error(sb, - "Extent block #%llu has an " - "invalid l_next_free_rec of %d", + "Extent block #%llu has an invalid l_next_free_rec of %d\n", (unsigned long long)le64_to_cpu(eb->h_blkno), le16_to_cpu(new_el->l_next_free_rec)); status = -EINVAL; @@ -4994,10 +4979,9 @@ leftright: split_index = ocfs2_search_extent_list(el, cpos); if (split_index == -1) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu has an extent at cpos %u " - "which can no longer be found.\n", - (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), - cpos); + "Owner %llu has an extent at cpos %u which can no longer be found\n", + (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), + cpos); ret = -EROFS; goto out; } @@ -5182,10 +5166,9 @@ int ocfs2_change_extent_flag(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { ocfs2_error(sb, - "Owner %llu has an extent at cpos %u which can no " - "longer be found.\n", - (unsigned long long) - ocfs2_metadata_cache_owner(et->et_ci), cpos); + "Owner %llu has an extent at cpos %u which can no longer be found\n", + (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), + cpos); ret = -EROFS; goto out; } @@ -5252,9 +5235,7 @@ int ocfs2_mark_extent_written(struct inode *inode, cpos, len, phys); if (!ocfs2_writes_unwritten_extents(OCFS2_SB(inode->i_sb))) { - ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents " - "that are being written to, but the feature bit " - "is not set in the super block.", + ocfs2_error(inode->i_sb, "Inode %llu has unwritten extents that are being written to, but the feature bit is not set in the super block\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); ret = -EROFS; goto out; @@ -5538,8 +5519,7 @@ int ocfs2_remove_extent(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu has an extent at cpos %u which can no " - "longer be found.\n", + "Owner %llu has an extent at cpos %u which can no longer be found\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), cpos); ret = -EROFS; @@ -5604,7 +5584,7 @@ int ocfs2_remove_extent(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu: split at cpos %u lost record.", + "Owner %llu: split at cpos %u lost record\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), cpos); ret = -EROFS; @@ -5620,8 +5600,7 @@ int ocfs2_remove_extent(handle_t *handle, ocfs2_rec_clusters(el, rec); if (rec_range != trunc_range) { ocfs2_error(ocfs2_metadata_cache_get_super(et->et_ci), - "Owner %llu: error after split at cpos %u" - "trunc len %u, existing record is (%u,%u)", + "Owner %llu: error after split at cpos %u trunc len %u, existing record is (%u,%u)\n", (unsigned long long)ocfs2_metadata_cache_owner(et->et_ci), cpos, len, le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); @@ -7236,8 +7215,7 @@ int ocfs2_truncate_inline(struct inode *inode, struct buffer_head *di_bh, !(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL) || !ocfs2_supports_inline_data(osb)) { ocfs2_error(inode->i_sb, - "Inline data flags for inode %llu don't agree! " - "Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n", + "Inline data flags for inode %llu don't agree! Disk: 0x%x, Memory: 0x%x, Superblock: 0x%x\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, le16_to_cpu(di->i_dyn_features), OCFS2_I(inode)->ip_dyn_features, diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index faf36a96cd19d..64b11d90eca68 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -227,7 +227,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data; if (!(le16_to_cpu(di->i_dyn_features) & OCFS2_INLINE_DATA_FL)) { - ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag", + ocfs2_error(inode->i_sb, "Inode %llu lost inline data flag\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); return -EROFS; } @@ -237,7 +237,7 @@ int ocfs2_read_inline_data(struct inode *inode, struct page *page, if (size > PAGE_CACHE_SIZE || size > ocfs2_max_inline_data_with_xattr(inode->i_sb, di)) { ocfs2_error(inode->i_sb, - "Inode %llu has with inline data has bad size: %Lu", + "Inode %llu has with inline data has bad size: %Lu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)size); return -EROFS; diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 25f03af09237a..ffecf89c8c1cd 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -481,29 +481,25 @@ static int ocfs2_check_dir_trailer(struct inode *dir, struct buffer_head *bh) trailer = ocfs2_trailer_from_bh(bh, dir->i_sb); if (!OCFS2_IS_VALID_DIR_TRAILER(trailer)) { rc = ocfs2_error(dir->i_sb, - "Invalid dirblock #%llu: " - "signature = %.*s\n", - (unsigned long long)bh->b_blocknr, 7, - trailer->db_signature); + "Invalid dirblock #%llu: signature = %.*s\n", + (unsigned long long)bh->b_blocknr, 7, + trailer->db_signature); goto out; } if (le64_to_cpu(trailer->db_blkno) != bh->b_blocknr) { rc = ocfs2_error(dir->i_sb, - "Directory block #%llu has an invalid " - "db_blkno of %llu", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(trailer->db_blkno)); + "Directory block #%llu has an invalid db_blkno of %llu\n", + (unsigned long long)bh->b_blocknr, + (unsigned long long)le64_to_cpu(trailer->db_blkno)); goto out; } if (le64_to_cpu(trailer->db_parent_dinode) != OCFS2_I(dir)->ip_blkno) { rc = ocfs2_error(dir->i_sb, - "Directory block #%llu on dinode " - "#%llu has an invalid parent_dinode " - "of %llu", - (unsigned long long)bh->b_blocknr, - (unsigned long long)OCFS2_I(dir)->ip_blkno, - (unsigned long long)le64_to_cpu(trailer->db_blkno)); + "Directory block #%llu on dinode #%llu has an invalid parent_dinode of %llu\n", + (unsigned long long)bh->b_blocknr, + (unsigned long long)OCFS2_I(dir)->ip_blkno, + (unsigned long long)le64_to_cpu(trailer->db_blkno)); goto out; } out: @@ -602,9 +598,9 @@ static int ocfs2_validate_dx_root(struct super_block *sb, if (!OCFS2_IS_VALID_DX_ROOT(dx_root)) { ret = ocfs2_error(sb, - "Dir Index Root # %llu has bad signature %.*s", - (unsigned long long)le64_to_cpu(dx_root->dr_blkno), - 7, dx_root->dr_signature); + "Dir Index Root # %llu has bad signature %.*s\n", + (unsigned long long)le64_to_cpu(dx_root->dr_blkno), + 7, dx_root->dr_signature); } return ret; @@ -644,8 +640,8 @@ static int ocfs2_validate_dx_leaf(struct super_block *sb, } if (!OCFS2_IS_VALID_DX_LEAF(dx_leaf)) { - ret = ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s", - 7, dx_leaf->dl_signature); + ret = ocfs2_error(sb, "Dir Index Leaf has bad signature %.*s\n", + 7, dx_leaf->dl_signature); } return ret; @@ -808,9 +804,9 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode, if (el->l_tree_depth) { ret = ocfs2_error(inode->i_sb, - "Inode %lu has non zero tree depth in " - "btree tree block %llu\n", inode->i_ino, - (unsigned long long)eb_bh->b_blocknr); + "Inode %lu has non zero tree depth in btree tree block %llu\n", + inode->i_ino, + (unsigned long long)eb_bh->b_blocknr); goto out; } } @@ -826,10 +822,11 @@ static int ocfs2_dx_dir_lookup_rec(struct inode *inode, } if (!found) { - ret = ocfs2_error(inode->i_sb, "Inode %lu has bad extent " - "record (%u, %u, 0) in btree", inode->i_ino, - le32_to_cpu(rec->e_cpos), - ocfs2_rec_clusters(el, rec)); + ret = ocfs2_error(inode->i_sb, + "Inode %lu has bad extent record (%u, %u, 0) in btree\n", + inode->i_ino, + le32_to_cpu(rec->e_cpos), + ocfs2_rec_clusters(el, rec)); goto out; } diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c index 767370b656ca6..e4719e0a3f999 100644 --- a/fs/ocfs2/extent_map.c +++ b/fs/ocfs2/extent_map.c @@ -305,8 +305,8 @@ static int ocfs2_last_eb_is_empty(struct inode *inode, if (el->l_tree_depth) { ocfs2_error(inode->i_sb, - "Inode %lu has non zero tree depth in " - "leaf block %llu\n", inode->i_ino, + "Inode %lu has non zero tree depth in leaf block %llu\n", + inode->i_ino, (unsigned long long)eb_bh->b_blocknr); ret = -EROFS; goto out; @@ -441,8 +441,8 @@ static int ocfs2_get_clusters_nocache(struct inode *inode, if (el->l_tree_depth) { ocfs2_error(inode->i_sb, - "Inode %lu has non zero tree depth in " - "leaf block %llu\n", inode->i_ino, + "Inode %lu has non zero tree depth in leaf block %llu\n", + inode->i_ino, (unsigned long long)eb_bh->b_blocknr); ret = -EROFS; goto out; @@ -475,8 +475,9 @@ static int ocfs2_get_clusters_nocache(struct inode *inode, BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); if (!rec->e_blkno) { - ocfs2_error(inode->i_sb, "Inode %lu has bad extent " - "record (%u, %u, 0)", inode->i_ino, + ocfs2_error(inode->i_sb, + "Inode %lu has bad extent record (%u, %u, 0)\n", + inode->i_ino, le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); ret = -EROFS; @@ -564,8 +565,8 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, if (el->l_tree_depth) { ocfs2_error(inode->i_sb, - "Inode %lu has non zero tree depth in " - "xattr leaf block %llu\n", inode->i_ino, + "Inode %lu has non zero tree depth in xattr leaf block %llu\n", + inode->i_ino, (unsigned long long)eb_bh->b_blocknr); ret = -EROFS; goto out; @@ -582,8 +583,9 @@ int ocfs2_xattr_get_clusters(struct inode *inode, u32 v_cluster, BUG_ON(v_cluster < le32_to_cpu(rec->e_cpos)); if (!rec->e_blkno) { - ocfs2_error(inode->i_sb, "Inode %lu has bad extent " - "record (%u, %u, 0) in xattr", inode->i_ino, + ocfs2_error(inode->i_sb, + "Inode %lu has bad extent record (%u, %u, 0) in xattr\n", + inode->i_ino, le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec)); ret = -EROFS; diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index fe4b3f7db2455..8f87e05ee25d3 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -1362,31 +1362,31 @@ int ocfs2_validate_inode_block(struct super_block *sb, if (!OCFS2_IS_VALID_DINODE(di)) { rc = ocfs2_error(sb, "Invalid dinode #%llu: signature = %.*s\n", - (unsigned long long)bh->b_blocknr, 7, - di->i_signature); + (unsigned long long)bh->b_blocknr, 7, + di->i_signature); goto bail; } if (le64_to_cpu(di->i_blkno) != bh->b_blocknr) { rc = ocfs2_error(sb, "Invalid dinode #%llu: i_blkno is %llu\n", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(di->i_blkno)); + (unsigned long long)bh->b_blocknr, + (unsigned long long)le64_to_cpu(di->i_blkno)); goto bail; } if (!(di->i_flags & cpu_to_le32(OCFS2_VALID_FL))) { rc = ocfs2_error(sb, - "Invalid dinode #%llu: OCFS2_VALID_FL not set\n", - (unsigned long long)bh->b_blocknr); + "Invalid dinode #%llu: OCFS2_VALID_FL not set\n", + (unsigned long long)bh->b_blocknr); goto bail; } if (le32_to_cpu(di->i_fs_generation) != OCFS2_SB(sb)->fs_generation) { rc = ocfs2_error(sb, - "Invalid dinode #%llu: fs_generation is %u\n", - (unsigned long long)bh->b_blocknr, - le32_to_cpu(di->i_fs_generation)); + "Invalid dinode #%llu: fs_generation is %u\n", + (unsigned long long)bh->b_blocknr, + le32_to_cpu(di->i_fs_generation)); goto bail; } diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index 52948af646b63..ff82b28462a65 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -374,7 +374,7 @@ handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs) mlog_errno(PTR_ERR(handle)); if (is_journal_aborted(journal)) { - ocfs2_abort(osb->sb, "Detected aborted journal"); + ocfs2_abort(osb->sb, "Detected aborted journal\n"); handle = ERR_PTR(-EROFS); } } else { diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 857bbbcd39f3b..0a4457fb0711b 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -665,8 +665,7 @@ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, #ifdef CONFIG_OCFS2_DEBUG_FS if (le32_to_cpu(alloc->id1.bitmap1.i_used) != ocfs2_local_alloc_count_bits(alloc)) { - ocfs2_error(osb->sb, "local alloc inode %llu says it has " - "%u used bits, but a count shows %u", + ocfs2_error(osb->sb, "local alloc inode %llu says it has %u used bits, but a count shows %u\n", (unsigned long long)le64_to_cpu(alloc->i_blkno), le32_to_cpu(alloc->id1.bitmap1.i_used), ocfs2_local_alloc_count_bits(alloc)); diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c index 70dd0ec7b7e9b..124471d26a73f 100644 --- a/fs/ocfs2/move_extents.c +++ b/fs/ocfs2/move_extents.c @@ -100,9 +100,8 @@ static int __ocfs2_move_extent(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { ret = ocfs2_error(inode->i_sb, - "Inode %llu has an extent at cpos %u which can no " - "longer be found.\n", - (unsigned long long)ino, cpos); + "Inode %llu has an extent at cpos %u which can no longer be found\n", + (unsigned long long)ino, cpos); goto out; } diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index bb07004df72a3..8a54fd8a4fa57 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -138,8 +138,7 @@ static int ocfs2_read_quota_block(struct inode *inode, u64 v_block, if (i_size_read(inode) >> inode->i_sb->s_blocksize_bits <= v_block) { ocfs2_error(inode->i_sb, - "Quota file %llu is probably corrupted! Requested " - "to read block %Lu but file has size only %Lu\n", + "Quota file %llu is probably corrupted! Requested to read block %Lu but file has size only %Lu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno, (unsigned long long)v_block, (unsigned long long)i_size_read(inode)); diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index b404dbde3fe4f..e5d57cd325052 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c @@ -103,27 +103,25 @@ static int ocfs2_validate_refcount_block(struct super_block *sb, if (!OCFS2_IS_VALID_REFCOUNT_BLOCK(rb)) { rc = ocfs2_error(sb, - "Refcount block #%llu has bad signature %.*s", - (unsigned long long)bh->b_blocknr, 7, - rb->rf_signature); + "Refcount block #%llu has bad signature %.*s\n", + (unsigned long long)bh->b_blocknr, 7, + rb->rf_signature); goto out; } if (le64_to_cpu(rb->rf_blkno) != bh->b_blocknr) { rc = ocfs2_error(sb, - "Refcount block #%llu has an invalid rf_blkno " - "of %llu", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(rb->rf_blkno)); + "Refcount block #%llu has an invalid rf_blkno of %llu\n", + (unsigned long long)bh->b_blocknr, + (unsigned long long)le64_to_cpu(rb->rf_blkno)); goto out; } if (le32_to_cpu(rb->rf_fs_generation) != OCFS2_SB(sb)->fs_generation) { rc = ocfs2_error(sb, - "Refcount block #%llu has an invalid " - "rf_fs_generation of #%u", - (unsigned long long)bh->b_blocknr, - le32_to_cpu(rb->rf_fs_generation)); + "Refcount block #%llu has an invalid rf_fs_generation of #%u\n", + (unsigned long long)bh->b_blocknr, + le32_to_cpu(rb->rf_fs_generation)); goto out; } out: @@ -1103,10 +1101,9 @@ static int ocfs2_get_refcount_rec(struct ocfs2_caching_info *ci, if (el->l_tree_depth) { ret = ocfs2_error(sb, - "refcount tree %llu has non zero tree " - "depth in leaf btree tree block %llu\n", - (unsigned long long)ocfs2_metadata_cache_owner(ci), - (unsigned long long)eb_bh->b_blocknr); + "refcount tree %llu has non zero tree depth in leaf btree tree block %llu\n", + (unsigned long long)ocfs2_metadata_cache_owner(ci), + (unsigned long long)eb_bh->b_blocknr); goto out; } } @@ -2358,9 +2355,8 @@ static int ocfs2_mark_extent_refcounted(struct inode *inode, cpos, len, phys); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { - ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " - "tree, but the feature bit is not set in the " - "super block.", inode->i_ino); + ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount tree, but the feature bit is not set in the super block\n", + inode->i_ino); goto out; } @@ -2543,9 +2539,8 @@ int ocfs2_prepare_refcount_change_for_del(struct inode *inode, u64 start_cpos = ocfs2_blocks_to_clusters(inode->i_sb, phys_blkno); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { - ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " - "tree, but the feature bit is not set in the " - "super block.", inode->i_ino); + ret = ocfs2_error(inode->i_sb, "Inode %lu want to use refcount tree, but the feature bit is not set in the super block\n", + inode->i_ino); goto out; } @@ -2670,9 +2665,9 @@ static int ocfs2_refcount_cal_cow_clusters(struct inode *inode, if (el->l_tree_depth) { ret = ocfs2_error(inode->i_sb, - "Inode %lu has non zero tree depth in " - "leaf block %llu\n", inode->i_ino, - (unsigned long long)eb_bh->b_blocknr); + "Inode %lu has non zero tree depth in leaf block %llu\n", + inode->i_ino, + (unsigned long long)eb_bh->b_blocknr); goto out; } } @@ -3103,9 +3098,8 @@ static int ocfs2_clear_ext_refcount(handle_t *handle, index = ocfs2_search_extent_list(el, cpos); if (index == -1) { ret = ocfs2_error(sb, - "Inode %llu has an extent at cpos %u which can no " - "longer be found.\n", - (unsigned long long)ino, cpos); + "Inode %llu has an extent at cpos %u which can no longer be found\n", + (unsigned long long)ino, cpos); goto out; } @@ -3371,9 +3365,8 @@ static int ocfs2_replace_cow(struct ocfs2_cow_context *context) struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb))) { - return ocfs2_error(inode->i_sb, "Inode %lu want to use refcount " - "tree, but the feature bit is not set in the " - "super block.", inode->i_ino); + return ocfs2_error(inode->i_sb, "Inode %lu want to use refcount tree, but the feature bit is not set in the super block\n", + inode->i_ino); } ocfs2_init_dealloc_ctxt(&context->dealloc); diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index e4bb00110e915..0456ae399bf71 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -167,12 +167,12 @@ static u32 ocfs2_bits_per_group(struct ocfs2_chain_list *cl) } #define do_error(fmt, ...) \ - do{ \ - if (resize) \ - mlog(ML_ERROR, fmt "\n", ##__VA_ARGS__); \ - else \ - return ocfs2_error(sb, fmt, ##__VA_ARGS__); \ - } while (0) +do { \ + if (resize) \ + mlog(ML_ERROR, fmt, ##__VA_ARGS__); \ + else \ + return ocfs2_error(sb, fmt, ##__VA_ARGS__); \ +} while (0) static int ocfs2_validate_gd_self(struct super_block *sb, struct buffer_head *bh, @@ -181,36 +181,32 @@ static int ocfs2_validate_gd_self(struct super_block *sb, struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; if (!OCFS2_IS_VALID_GROUP_DESC(gd)) { - do_error("Group descriptor #%llu has bad signature %.*s", + do_error("Group descriptor #%llu has bad signature %.*s\n", (unsigned long long)bh->b_blocknr, 7, gd->bg_signature); } if (le64_to_cpu(gd->bg_blkno) != bh->b_blocknr) { - do_error("Group descriptor #%llu has an invalid bg_blkno " - "of %llu", + do_error("Group descriptor #%llu has an invalid bg_blkno of %llu\n", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(gd->bg_blkno)); } if (le32_to_cpu(gd->bg_generation) != OCFS2_SB(sb)->fs_generation) { - do_error("Group descriptor #%llu has an invalid " - "fs_generation of #%u", + do_error("Group descriptor #%llu has an invalid fs_generation of #%u\n", (unsigned long long)bh->b_blocknr, le32_to_cpu(gd->bg_generation)); } if (le16_to_cpu(gd->bg_free_bits_count) > le16_to_cpu(gd->bg_bits)) { - do_error("Group descriptor #%llu has bit count %u but " - "claims that %u are free", + do_error("Group descriptor #%llu has bit count %u but claims that %u are free\n", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits), le16_to_cpu(gd->bg_free_bits_count)); } if (le16_to_cpu(gd->bg_bits) > (8 * le16_to_cpu(gd->bg_size))) { - do_error("Group descriptor #%llu has bit count %u but " - "max bitmap bits of %u", + do_error("Group descriptor #%llu has bit count %u but max bitmap bits of %u\n", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits), 8 * le16_to_cpu(gd->bg_size)); @@ -228,8 +224,7 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, struct ocfs2_group_desc *gd = (struct ocfs2_group_desc *)bh->b_data; if (di->i_blkno != gd->bg_parent_dinode) { - do_error("Group descriptor #%llu has bad parent " - "pointer (%llu, expected %llu)", + do_error("Group descriptor #%llu has bad parent pointer (%llu, expected %llu)\n", (unsigned long long)bh->b_blocknr, (unsigned long long)le64_to_cpu(gd->bg_parent_dinode), (unsigned long long)le64_to_cpu(di->i_blkno)); @@ -237,7 +232,7 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, max_bits = le16_to_cpu(di->id2.i_chain.cl_cpg) * le16_to_cpu(di->id2.i_chain.cl_bpc); if (le16_to_cpu(gd->bg_bits) > max_bits) { - do_error("Group descriptor #%llu has bit count of %u", + do_error("Group descriptor #%llu has bit count of %u\n", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_bits)); } @@ -247,7 +242,7 @@ static int ocfs2_validate_gd_parent(struct super_block *sb, le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) || ((le16_to_cpu(gd->bg_chain) == le16_to_cpu(di->id2.i_chain.cl_next_free_rec)) && !resize)) { - do_error("Group descriptor #%llu has bad chain %u", + do_error("Group descriptor #%llu has bad chain %u\n", (unsigned long long)bh->b_blocknr, le16_to_cpu(gd->bg_chain)); } @@ -376,10 +371,10 @@ static int ocfs2_block_group_fill(handle_t *handle, struct super_block * sb = alloc_inode->i_sb; if (((unsigned long long) bg_bh->b_blocknr) != group_blkno) { - status = ocfs2_error(alloc_inode->i_sb, "group block (%llu) != " - "b_blocknr (%llu)", - (unsigned long long)group_blkno, - (unsigned long long) bg_bh->b_blocknr); + status = ocfs2_error(alloc_inode->i_sb, + "group block (%llu) != b_blocknr (%llu)\n", + (unsigned long long)group_blkno, + (unsigned long long) bg_bh->b_blocknr); goto bail; } @@ -825,8 +820,9 @@ static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb, BUG_ON(!OCFS2_IS_VALID_DINODE(fe)); if (!(fe->i_flags & cpu_to_le32(OCFS2_CHAIN_FL))) { - status = ocfs2_error(alloc_inode->i_sb, "Invalid chain allocator %llu", - (unsigned long long)le64_to_cpu(fe->i_blkno)); + status = ocfs2_error(alloc_inode->i_sb, + "Invalid chain allocator %llu\n", + (unsigned long long)le64_to_cpu(fe->i_blkno)); goto bail; } @@ -1360,11 +1356,11 @@ int ocfs2_block_group_set_bits(handle_t *handle, le16_add_cpu(&bg->bg_free_bits_count, -num_bits); if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) { - return ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit" - " count %u but claims %u are freed. num_bits %d", - (unsigned long long)le64_to_cpu(bg->bg_blkno), - le16_to_cpu(bg->bg_bits), - le16_to_cpu(bg->bg_free_bits_count), num_bits); + return ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit count %u but claims %u are freed. num_bits %d\n", + (unsigned long long)le64_to_cpu(bg->bg_blkno), + le16_to_cpu(bg->bg_bits), + le16_to_cpu(bg->bg_free_bits_count), + num_bits); } while(num_bits--) ocfs2_set_bit(bit_off++, bitmap); @@ -1895,11 +1891,10 @@ static int ocfs2_claim_suballoc_bits(struct ocfs2_alloc_context *ac, if (le32_to_cpu(fe->id1.bitmap1.i_used) >= le32_to_cpu(fe->id1.bitmap1.i_total)) { status = ocfs2_error(ac->ac_inode->i_sb, - "Chain allocator dinode %llu has %u used " - "bits but only %u total.", - (unsigned long long)le64_to_cpu(fe->i_blkno), - le32_to_cpu(fe->id1.bitmap1.i_used), - le32_to_cpu(fe->id1.bitmap1.i_total)); + "Chain allocator dinode %llu has %u used bits but only %u total\n", + (unsigned long long)le64_to_cpu(fe->i_blkno), + le32_to_cpu(fe->id1.bitmap1.i_used), + le32_to_cpu(fe->id1.bitmap1.i_total)); goto bail; } @@ -2417,11 +2412,11 @@ static int ocfs2_block_group_clear_bits(handle_t *handle, } le16_add_cpu(&bg->bg_free_bits_count, num_bits); if (le16_to_cpu(bg->bg_free_bits_count) > le16_to_cpu(bg->bg_bits)) { - return ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit" - " count %u but claims %u are freed. num_bits %d", - (unsigned long long)le64_to_cpu(bg->bg_blkno), - le16_to_cpu(bg->bg_bits), - le16_to_cpu(bg->bg_free_bits_count), num_bits); + return ocfs2_error(alloc_inode->i_sb, "Group descriptor # %llu has bit count %u but claims %u are freed. num_bits %d\n", + (unsigned long long)le64_to_cpu(bg->bg_blkno), + le16_to_cpu(bg->bg_bits), + le16_to_cpu(bg->bg_free_bits_count), + num_bits); } if (undo_fn) diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index e79058ecfb4be..3a9a1af39ad7a 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -2600,7 +2600,7 @@ int __ocfs2_error(struct super_block *sb, const char *function, /* Not using mlog here because we want to show the actual * function the error came from. */ - printk(KERN_CRIT "OCFS2: ERROR (device %s): %s: %pV\n", + printk(KERN_CRIT "OCFS2: ERROR (device %s): %s: %pV", sb->s_id, function, &vaf); va_end(args); @@ -2622,7 +2622,7 @@ void __ocfs2_abort(struct super_block *sb, const char *function, vaf.fmt = fmt; vaf.va = &args; - printk(KERN_CRIT "OCFS2: abort (device %s): %s: %pV\n", + printk(KERN_CRIT "OCFS2: abort (device %s): %s: %pV", sb->s_id, function, &vaf); va_end(args); diff --git a/fs/ocfs2/super.h b/fs/ocfs2/super.h index c1c87d90542c8..b477d0b1c7b6c 100644 --- a/fs/ocfs2/super.h +++ b/fs/ocfs2/super.h @@ -35,13 +35,15 @@ __printf(3, 4) int __ocfs2_error(struct super_block *sb, const char *function, const char *fmt, ...); -#define ocfs2_error(sb, fmt, args...) __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##args) +#define ocfs2_error(sb, fmt, ...) \ + __ocfs2_error(sb, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) __printf(3, 4) void __ocfs2_abort(struct super_block *sb, const char *function, const char *fmt, ...); -#define ocfs2_abort(sb, fmt, args...) __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##args) +#define ocfs2_abort(sb, fmt, ...) \ + __ocfs2_abort(sb, __PRETTY_FUNCTION__, fmt, ##__VA_ARGS__) /* * Void signal blockers, because in-kernel sigprocmask() only fails diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c index 5944a311bb947..ebfdea78659b1 100644 --- a/fs/ocfs2/xattr.c +++ b/fs/ocfs2/xattr.c @@ -500,26 +500,23 @@ static int ocfs2_validate_xattr_block(struct super_block *sb, if (!OCFS2_IS_VALID_XATTR_BLOCK(xb)) { return ocfs2_error(sb, - "Extended attribute block #%llu has bad " - "signature %.*s", - (unsigned long long)bh->b_blocknr, 7, - xb->xb_signature); + "Extended attribute block #%llu has bad signature %.*s\n", + (unsigned long long)bh->b_blocknr, 7, + xb->xb_signature); } if (le64_to_cpu(xb->xb_blkno) != bh->b_blocknr) { return ocfs2_error(sb, - "Extended attribute block #%llu has an " - "invalid xb_blkno of %llu", - (unsigned long long)bh->b_blocknr, - (unsigned long long)le64_to_cpu(xb->xb_blkno)); + "Extended attribute block #%llu has an invalid xb_blkno of %llu\n", + (unsigned long long)bh->b_blocknr, + (unsigned long long)le64_to_cpu(xb->xb_blkno)); } if (le32_to_cpu(xb->xb_fs_generation) != OCFS2_SB(sb)->fs_generation) { return ocfs2_error(sb, - "Extended attribute block #%llu has an invalid " - "xb_fs_generation of #%u", - (unsigned long long)bh->b_blocknr, - le32_to_cpu(xb->xb_fs_generation)); + "Extended attribute block #%llu has an invalid xb_fs_generation of #%u\n", + (unsigned long long)bh->b_blocknr, + le32_to_cpu(xb->xb_fs_generation)); } return 0; @@ -3692,9 +3689,9 @@ static int ocfs2_xattr_get_rec(struct inode *inode, if (el->l_tree_depth) { ret = ocfs2_error(inode->i_sb, - "Inode %lu has non zero tree depth in " - "xattr tree block %llu\n", inode->i_ino, - (unsigned long long)eb_bh->b_blocknr); + "Inode %lu has non zero tree depth in xattr tree block %llu\n", + inode->i_ino, + (unsigned long long)eb_bh->b_blocknr); goto out; } } @@ -3709,10 +3706,10 @@ static int ocfs2_xattr_get_rec(struct inode *inode, } if (!e_blkno) { - ret = ocfs2_error(inode->i_sb, "Inode %lu has bad extent " - "record (%u, %u, 0) in xattr", inode->i_ino, - le32_to_cpu(rec->e_cpos), - ocfs2_rec_clusters(el, rec)); + ret = ocfs2_error(inode->i_sb, "Inode %lu has bad extent record (%u, %u, 0) in xattr\n", + inode->i_ino, + le32_to_cpu(rec->e_cpos), + ocfs2_rec_clusters(el, rec)); goto out; } -- GitLab From 46359295a352e01a5a017297c70b7ee0c5da6de6 Mon Sep 17 00:00:00 2001 From: Joseph Qi Date: Fri, 4 Sep 2015 15:44:54 -0700 Subject: [PATCH 6389/7006] ocfs2: clean up redundant NULL checks before kfree NULL check before kfree is redundant and so clean them up. Signed-off-by: Joseph Qi Reviewed-by: Mark Fasheh Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/alloc.c | 2 +- fs/ocfs2/suballoc.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index b20706e8a4d1c..86181d6526dc5 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -6178,7 +6178,7 @@ bail: iput(tl_inode); brelse(tl_bh); - if (status < 0 && (*tl_copy)) { + if (status < 0) { kfree(*tl_copy); *tl_copy = NULL; mlog_errno(status); diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 0456ae399bf71..d83d2602cf2b0 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -149,10 +149,8 @@ void ocfs2_free_ac_resource(struct ocfs2_alloc_context *ac) brelse(ac->ac_bh); ac->ac_bh = NULL; ac->ac_resv = NULL; - if (ac->ac_find_loc_priv) { - kfree(ac->ac_find_loc_priv); - ac->ac_find_loc_priv = NULL; - } + kfree(ac->ac_find_loc_priv); + ac->ac_find_loc_priv = NULL; } void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) -- GitLab From a068acf2ee77693e0bf39d6e07139ba704f461c3 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 4 Sep 2015 15:44:57 -0700 Subject: [PATCH 6390/7006] fs: create and use seq_show_option for escaping Many file systems that implement the show_options hook fail to correctly escape their output which could lead to unescaped characters (e.g. new lines) leaking into /proc/mounts and /proc/[pid]/mountinfo files. This could lead to confusion, spoofed entries (resulting in things like systemd issuing false d-bus "mount" notifications), and who knows what else. This looks like it would only be the root user stepping on themselves, but it's possible weird things could happen in containers or in other situations with delegated mount privileges. Here's an example using overlay with setuid fusermount trusting the contents of /proc/mounts (via the /etc/mtab symlink). Imagine the use of "sudo" is something more sneaky: $ BASE="ovl" $ MNT="$BASE/mnt" $ LOW="$BASE/lower" $ UP="$BASE/upper" $ WORK="$BASE/work/ 0 0 none /proc fuse.pwn user_id=1000" $ mkdir -p "$LOW" "$UP" "$WORK" $ sudo mount -t overlay -o "lowerdir=$LOW,upperdir=$UP,workdir=$WORK" none /mnt $ cat /proc/mounts none /root/ovl/mnt overlay rw,relatime,lowerdir=ovl/lower,upperdir=ovl/upper,workdir=ovl/work/ 0 0 none /proc fuse.pwn user_id=1000 0 0 $ fusermount -u /proc $ cat /proc/mounts cat: /proc/mounts: No such file or directory This fixes the problem by adding new seq_show_option and seq_show_option_n helpers, and updating the vulnerable show_option handlers to use them as needed. Some, like SELinux, need to be open coded due to unusual existing escape mechanisms. [akpm@linux-foundation.org: add lost chunk, per Kees] [keescook@chromium.org: seq_show_option should be using const parameters] Signed-off-by: Kees Cook Acked-by: Serge Hallyn Acked-by: Jan Kara Acked-by: Paul Moore Cc: J. R. Okajima Signed-off-by: Kees Cook Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ceph/super.c | 2 +- fs/cifs/cifsfs.c | 6 +++--- fs/ext4/super.c | 4 ++-- fs/gfs2/super.c | 6 +++--- fs/hfs/super.c | 4 ++-- fs/hfsplus/options.c | 4 ++-- fs/hostfs/hostfs_kern.c | 2 +- fs/ocfs2/super.c | 4 ++-- fs/overlayfs/super.c | 6 +++--- fs/reiserfs/super.c | 8 +++++--- fs/xfs/xfs_super.c | 4 ++-- include/linux/seq_file.h | 35 +++++++++++++++++++++++++++++++++++ kernel/cgroup.c | 7 ++++--- net/ceph/ceph_common.c | 7 +++++-- security/selinux/hooks.c | 2 +- 15 files changed, 71 insertions(+), 30 deletions(-) diff --git a/fs/ceph/super.c b/fs/ceph/super.c index d1c833c321b92..7b6bfcbf801ca 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -479,7 +479,7 @@ static int ceph_show_options(struct seq_file *m, struct dentry *root) if (fsopt->max_readdir_bytes != CEPH_MAX_READDIR_BYTES_DEFAULT) seq_printf(m, ",readdir_max_bytes=%d", fsopt->max_readdir_bytes); if (strcmp(fsopt->snapdir_name, CEPH_SNAPDIRNAME_DEFAULT)) - seq_printf(m, ",snapdirname=%s", fsopt->snapdir_name); + seq_show_option(m, "snapdirname", fsopt->snapdir_name); return 0; } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 0a9fb6b53126a..6a1119e87fbb6 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -394,17 +394,17 @@ cifs_show_options(struct seq_file *s, struct dentry *root) struct sockaddr *srcaddr; srcaddr = (struct sockaddr *)&tcon->ses->server->srcaddr; - seq_printf(s, ",vers=%s", tcon->ses->server->vals->version_string); + seq_show_option(s, "vers", tcon->ses->server->vals->version_string); cifs_show_security(s, tcon->ses); cifs_show_cache_flavor(s, cifs_sb); if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER) seq_puts(s, ",multiuser"); else if (tcon->ses->user_name) - seq_printf(s, ",username=%s", tcon->ses->user_name); + seq_show_option(s, "username", tcon->ses->user_name); if (tcon->ses->domainName) - seq_printf(s, ",domain=%s", tcon->ses->domainName); + seq_show_option(s, "domain", tcon->ses->domainName); if (srcaddr->sa_family != AF_UNSPEC) { struct sockaddr_in *saddr4; diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ee3878262a495..a63c7b0a10cfc 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1776,10 +1776,10 @@ static inline void ext4_show_quota_options(struct seq_file *seq, } if (sbi->s_qf_names[USRQUOTA]) - seq_printf(seq, ",usrjquota=%s", sbi->s_qf_names[USRQUOTA]); + seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]); if (sbi->s_qf_names[GRPQUOTA]) - seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]); + seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]); #endif } diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 2982445947e17..894fb01a91dab 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c @@ -1334,11 +1334,11 @@ static int gfs2_show_options(struct seq_file *s, struct dentry *root) if (is_ancestor(root, sdp->sd_master_dir)) seq_puts(s, ",meta"); if (args->ar_lockproto[0]) - seq_printf(s, ",lockproto=%s", args->ar_lockproto); + seq_show_option(s, "lockproto", args->ar_lockproto); if (args->ar_locktable[0]) - seq_printf(s, ",locktable=%s", args->ar_locktable); + seq_show_option(s, "locktable", args->ar_locktable); if (args->ar_hostdata[0]) - seq_printf(s, ",hostdata=%s", args->ar_hostdata); + seq_show_option(s, "hostdata", args->ar_hostdata); if (args->ar_spectator) seq_puts(s, ",spectator"); if (args->ar_localflocks) diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 55c03b9e90708..4574fdd3d4219 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -136,9 +136,9 @@ static int hfs_show_options(struct seq_file *seq, struct dentry *root) struct hfs_sb_info *sbi = HFS_SB(root->d_sb); if (sbi->s_creator != cpu_to_be32(0x3f3f3f3f)) - seq_printf(seq, ",creator=%.4s", (char *)&sbi->s_creator); + seq_show_option_n(seq, "creator", (char *)&sbi->s_creator, 4); if (sbi->s_type != cpu_to_be32(0x3f3f3f3f)) - seq_printf(seq, ",type=%.4s", (char *)&sbi->s_type); + seq_show_option_n(seq, "type", (char *)&sbi->s_type, 4); seq_printf(seq, ",uid=%u,gid=%u", from_kuid_munged(&init_user_ns, sbi->s_uid), from_kgid_munged(&init_user_ns, sbi->s_gid)); diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c index c90b72ee676d8..bb806e58c9770 100644 --- a/fs/hfsplus/options.c +++ b/fs/hfsplus/options.c @@ -218,9 +218,9 @@ int hfsplus_show_options(struct seq_file *seq, struct dentry *root) struct hfsplus_sb_info *sbi = HFSPLUS_SB(root->d_sb); if (sbi->creator != HFSPLUS_DEF_CR_TYPE) - seq_printf(seq, ",creator=%.4s", (char *)&sbi->creator); + seq_show_option_n(seq, "creator", (char *)&sbi->creator, 4); if (sbi->type != HFSPLUS_DEF_CR_TYPE) - seq_printf(seq, ",type=%.4s", (char *)&sbi->type); + seq_show_option_n(seq, "type", (char *)&sbi->type, 4); seq_printf(seq, ",umask=%o,uid=%u,gid=%u", sbi->umask, from_kuid_munged(&init_user_ns, sbi->uid), from_kgid_munged(&init_user_ns, sbi->gid)); diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 059597b23f677..2ac99db3750ef 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -260,7 +260,7 @@ static int hostfs_show_options(struct seq_file *seq, struct dentry *root) size_t offset = strlen(root_ino) + 1; if (strlen(root_path) > offset) - seq_printf(seq, ",%s", root_path + offset); + seq_show_option(seq, root_path + offset, NULL); if (append) seq_puts(seq, ",append"); diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 3a9a1af39ad7a..2de4c8a9340c2 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -1563,8 +1563,8 @@ static int ocfs2_show_options(struct seq_file *s, struct dentry *root) seq_printf(s, ",localflocks,"); if (osb->osb_cluster_stack[0]) - seq_printf(s, ",cluster_stack=%.*s", OCFS2_STACK_LABEL_LEN, - osb->osb_cluster_stack); + seq_show_option_n(s, "cluster_stack", osb->osb_cluster_stack, + OCFS2_STACK_LABEL_LEN); if (opts & OCFS2_MOUNT_USRQUOTA) seq_printf(s, ",usrquota"); if (opts & OCFS2_MOUNT_GRPQUOTA) diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 7466ff339c667..79073d68b475d 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -588,10 +588,10 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) struct super_block *sb = dentry->d_sb; struct ovl_fs *ufs = sb->s_fs_info; - seq_printf(m, ",lowerdir=%s", ufs->config.lowerdir); + seq_show_option(m, "lowerdir", ufs->config.lowerdir); if (ufs->config.upperdir) { - seq_printf(m, ",upperdir=%s", ufs->config.upperdir); - seq_printf(m, ",workdir=%s", ufs->config.workdir); + seq_show_option(m, "upperdir", ufs->config.upperdir); + seq_show_option(m, "workdir", ufs->config.workdir); } return 0; } diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 0e4cf728126f2..4a62fe8cc3bff 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -714,18 +714,20 @@ static int reiserfs_show_options(struct seq_file *seq, struct dentry *root) seq_puts(seq, ",acl"); if (REISERFS_SB(s)->s_jdev) - seq_printf(seq, ",jdev=%s", REISERFS_SB(s)->s_jdev); + seq_show_option(seq, "jdev", REISERFS_SB(s)->s_jdev); if (journal->j_max_commit_age != journal->j_default_max_commit_age) seq_printf(seq, ",commit=%d", journal->j_max_commit_age); #ifdef CONFIG_QUOTA if (REISERFS_SB(s)->s_qf_names[USRQUOTA]) - seq_printf(seq, ",usrjquota=%s", REISERFS_SB(s)->s_qf_names[USRQUOTA]); + seq_show_option(seq, "usrjquota", + REISERFS_SB(s)->s_qf_names[USRQUOTA]); else if (opts & (1 << REISERFS_USRQUOTA)) seq_puts(seq, ",usrquota"); if (REISERFS_SB(s)->s_qf_names[GRPQUOTA]) - seq_printf(seq, ",grpjquota=%s", REISERFS_SB(s)->s_qf_names[GRPQUOTA]); + seq_show_option(seq, "grpjquota", + REISERFS_SB(s)->s_qf_names[GRPQUOTA]); else if (opts & (1 << REISERFS_GRPQUOTA)) seq_puts(seq, ",grpquota"); if (REISERFS_SB(s)->s_jquota_fmt) { diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index 1fb16562c1599..bbd9b1f10ffb2 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -511,9 +511,9 @@ xfs_showargs( seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10); if (mp->m_logname) - seq_printf(m, "," MNTOPT_LOGDEV "=%s", mp->m_logname); + seq_show_option(m, MNTOPT_LOGDEV, mp->m_logname); if (mp->m_rtname) - seq_printf(m, "," MNTOPT_RTDEV "=%s", mp->m_rtname); + seq_show_option(m, MNTOPT_RTDEV, mp->m_rtname); if (mp->m_dalign > 0) seq_printf(m, "," MNTOPT_SUNIT "=%d", diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index 912a7c482649e..d4c7271382cb3 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -149,6 +149,41 @@ static inline struct user_namespace *seq_user_ns(struct seq_file *seq) #endif } +/** + * seq_show_options - display mount options with appropriate escapes. + * @m: the seq_file handle + * @name: the mount option name + * @value: the mount option name's value, can be NULL + */ +static inline void seq_show_option(struct seq_file *m, const char *name, + const char *value) +{ + seq_putc(m, ','); + seq_escape(m, name, ",= \t\n\\"); + if (value) { + seq_putc(m, '='); + seq_escape(m, value, ", \t\n\\"); + } +} + +/** + * seq_show_option_n - display mount options with appropriate escapes + * where @value must be a specific length. + * @m: the seq_file handle + * @name: the mount option name + * @value: the mount option name's value, cannot be NULL + * @length: the length of @value to display + * + * This is a macro since this uses "length" to define the size of the + * stack buffer. + */ +#define seq_show_option_n(m, name, value, length) { \ + char val_buf[length + 1]; \ + strncpy(val_buf, value, length); \ + val_buf[length] = '\0'; \ + seq_show_option(m, name, val_buf); \ +} + #define SEQ_START_TOKEN ((void *)1) /* * Helpers for iteration over list_head-s in seq_files diff --git a/kernel/cgroup.c b/kernel/cgroup.c index f3f5cd5e2c0d9..a8538e4437842 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1342,7 +1342,7 @@ static int cgroup_show_options(struct seq_file *seq, if (root != &cgrp_dfl_root) for_each_subsys(ss, ssid) if (root->subsys_mask & (1 << ssid)) - seq_printf(seq, ",%s", ss->legacy_name); + seq_show_option(seq, ss->name, NULL); if (root->flags & CGRP_ROOT_NOPREFIX) seq_puts(seq, ",noprefix"); if (root->flags & CGRP_ROOT_XATTR) @@ -1350,13 +1350,14 @@ static int cgroup_show_options(struct seq_file *seq, spin_lock(&release_agent_path_lock); if (strlen(root->release_agent_path)) - seq_printf(seq, ",release_agent=%s", root->release_agent_path); + seq_show_option(seq, "release_agent", + root->release_agent_path); spin_unlock(&release_agent_path_lock); if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags)) seq_puts(seq, ",clone_children"); if (strlen(root->name)) - seq_printf(seq, ",name=%s", root->name); + seq_show_option(seq, "name", root->name); return 0; } diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index f30329f726418..69a4d30a9ccf4 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -517,8 +517,11 @@ int ceph_print_client_options(struct seq_file *m, struct ceph_client *client) struct ceph_options *opt = client->options; size_t pos = m->count; - if (opt->name) - seq_printf(m, "name=%s,", opt->name); + if (opt->name) { + seq_puts(m, "name="); + seq_escape(m, opt->name, ", \t\n\\"); + seq_putc(m, ','); + } if (opt->key) seq_puts(m, "secret=,"); diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 564079c5c49dc..cdf4c589a3914 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -1100,7 +1100,7 @@ static void selinux_write_opts(struct seq_file *m, seq_puts(m, prefix); if (has_comma) seq_putc(m, '\"'); - seq_puts(m, opts->mnt_opts[i]); + seq_escape(m, opts->mnt_opts[i], "\"\n\\"); if (has_comma) seq_putc(m, '\"'); } -- GitLab From 5869b5064b0950afc447610c0f5d4134b71d9e94 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 4 Sep 2015 15:45:00 -0700 Subject: [PATCH 6391/7006] smpboot: fix memory leak on error handling The cpumask is allocated before threads get created. If the latter step fails, we need to free the cpumask. Signed-off-by: Frederic Weisbecker Reviewed-by: Chris Metcalf Reviewed-by: Thomas Gleixner Cc: Chris Metcalf Cc: Don Zickus Cc: Peter Zijlstra Cc: Ulrich Obergfell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/smpboot.c | 1 + 1 file changed, 1 insertion(+) diff --git a/kernel/smpboot.c b/kernel/smpboot.c index 7c434c39f02a2..71aa90b69f8fb 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -301,6 +301,7 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) ret = __smpboot_create_thread(plug_thread, cpu); if (ret) { smpboot_destroy_threads(plug_thread); + free_cpumask_var(plug_thread->cpumask); goto out; } smpboot_unpark_thread(plug_thread, cpu); -- GitLab From 3dd08c0c918f9bf058572ddbf26e7d6fb5674a5c Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 4 Sep 2015 15:45:03 -0700 Subject: [PATCH 6392/7006] smpboot: make cleanup to mirror setup The per-cpu kthread cleanup() callback is the mirror of the setup() callback. When the per-cpu kthread is started, it first calls setup() to initialize the resources which are then released by cleanup() when the kthread exits. Now since the introduction of a per-cpu kthread cpumask, the kthreads excluded by the cpumask on boot may happen to be parked immediately after their creation without taking the setup() stage, waiting to be asked to unpark to do so. Then when smpboot_unregister_percpu_thread() is later called, the kthread is stopped without having ever called setup(). But this triggers a bug as the kthread unconditionally calls cleanup() on exit but this doesn't mirror any setup(). Thus the kernel crashes because we try to free resources that haven't been initialized, as in the watchdog case: WATCHDOG disable 0 WATCHDOG disable 1 WATCHDOG disable 2 BUG: unable to handle kernel NULL pointer dereference at (null) IP: hrtimer_active+0x26/0x60 [...] Call Trace: hrtimer_try_to_cancel+0x1c/0x280 hrtimer_cancel+0x1d/0x30 watchdog_disable+0x56/0x70 watchdog_cleanup+0xe/0x10 smpboot_thread_fn+0x23c/0x2c0 kthread+0xf8/0x110 ret_from_fork+0x3f/0x70 This bug is currently masked with explicit kthread unparking before kthread_stop() on smpboot_destroy_threads(). This forces a call to setup() and then unpark(). We could fix this by unconditionally calling setup() on kthread entry. But setup() isn't always cheap. In the case of watchdog it launches hrtimer, perf events, etc... So we may as well like to skip it if there are chances the kthread will never be used, as in a reduced cpumask value. So let's simply do a state machine check before calling cleanup() that makes sure setup() has been called before mirroring it. And remove the nasty hack workaround. Signed-off-by: Frederic Weisbecker Reviewed-by: Chris Metcalf Reviewed-by: Thomas Gleixner Cc: Chris Metcalf Cc: Don Zickus Cc: Peter Zijlstra Cc: Ulrich Obergfell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/smpboot.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/kernel/smpboot.c b/kernel/smpboot.c index 71aa90b69f8fb..60aa858a6a078 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -113,7 +113,8 @@ static int smpboot_thread_fn(void *data) if (kthread_should_stop()) { __set_current_state(TASK_RUNNING); preempt_enable(); - if (ht->cleanup) + /* cleanup must mirror setup */ + if (ht->cleanup && td->status != HP_THREAD_NONE) ht->cleanup(td->cpu, cpu_online(td->cpu)); kfree(td); return 0; @@ -259,15 +260,6 @@ static void smpboot_destroy_threads(struct smp_hotplug_thread *ht) { unsigned int cpu; - /* Unpark any threads that were voluntarily parked. */ - for_each_cpu_not(cpu, ht->cpumask) { - if (cpu_online(cpu)) { - struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); - if (tsk) - kthread_unpark(tsk); - } - } - /* We need to destroy also the parked threads of offline cpus */ for_each_possible_cpu(cpu) { struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); -- GitLab From 230ec93909f00678401cb2d63b8b95f1dea68e40 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 4 Sep 2015 15:45:06 -0700 Subject: [PATCH 6393/7006] smpboot: allow passing the cpumask on per-cpu thread registration It makes the registration cheaper and simpler for the smpboot per-cpu kthread users that don't need to always update the cpumask after threads creation. [sfr@canb.auug.org.au: fix for allow passing the cpumask on per-cpu thread registration] Signed-off-by: Frederic Weisbecker Reviewed-by: Chris Metcalf Reviewed-by: Thomas Gleixner Cc: Chris Metcalf Cc: Don Zickus Cc: Peter Zijlstra Cc: Ulrich Obergfell Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/smpboot.h | 11 ++++++++++- kernel/smpboot.c | 14 +++++++++----- kernel/watchdog.c | 9 +++------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/include/linux/smpboot.h b/include/linux/smpboot.h index da3c593f9845b..e6109a6cd8f65 100644 --- a/include/linux/smpboot.h +++ b/include/linux/smpboot.h @@ -48,7 +48,16 @@ struct smp_hotplug_thread { const char *thread_comm; }; -int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread); +int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread, + const struct cpumask *cpumask); + +static inline int +smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) +{ + return smpboot_register_percpu_thread_cpumask(plug_thread, + cpu_possible_mask); +} + void smpboot_unregister_percpu_thread(struct smp_hotplug_thread *plug_thread); int smpboot_update_cpumask_percpu_thread(struct smp_hotplug_thread *plug_thread, const struct cpumask *); diff --git a/kernel/smpboot.c b/kernel/smpboot.c index 60aa858a6a078..a818cbc73e147 100644 --- a/kernel/smpboot.c +++ b/kernel/smpboot.c @@ -273,19 +273,22 @@ static void smpboot_destroy_threads(struct smp_hotplug_thread *ht) } /** - * smpboot_register_percpu_thread - Register a per_cpu thread related to hotplug + * smpboot_register_percpu_thread_cpumask - Register a per_cpu thread related + * to hotplug * @plug_thread: Hotplug thread descriptor + * @cpumask: The cpumask where threads run * * Creates and starts the threads on all online cpus. */ -int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) +int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread, + const struct cpumask *cpumask) { unsigned int cpu; int ret = 0; if (!alloc_cpumask_var(&plug_thread->cpumask, GFP_KERNEL)) return -ENOMEM; - cpumask_copy(plug_thread->cpumask, cpu_possible_mask); + cpumask_copy(plug_thread->cpumask, cpumask); get_online_cpus(); mutex_lock(&smpboot_threads_lock); @@ -296,7 +299,8 @@ int smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) free_cpumask_var(plug_thread->cpumask); goto out; } - smpboot_unpark_thread(plug_thread, cpu); + if (cpumask_test_cpu(cpu, cpumask)) + smpboot_unpark_thread(plug_thread, cpu); } list_add(&plug_thread->list, &hotplug_threads); out: @@ -304,7 +308,7 @@ out: put_online_cpus(); return ret; } -EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread); +EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread_cpumask); /** * smpboot_unregister_percpu_thread - Unregister a per_cpu thread related to hotplug diff --git a/kernel/watchdog.c b/kernel/watchdog.c index a6ffa43f29930..e5bb86fb0ea5f 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -713,15 +713,12 @@ static int watchdog_enable_all_cpus(void) int err = 0; if (!watchdog_running) { - err = smpboot_register_percpu_thread(&watchdog_threads); + err = smpboot_register_percpu_thread_cpumask(&watchdog_threads, + &watchdog_cpumask); if (err) pr_err("Failed to create watchdog threads, disabled\n"); - else { - if (smpboot_update_cpumask_percpu_thread( - &watchdog_threads, &watchdog_cpumask)) - pr_err("Failed to set cpumask for watchdog threads\n"); + else watchdog_running = 1; - } } else { /* * Enable/disable the lockup detectors or -- GitLab From 314b08ff5205420d956d14657e16d92c460a6f21 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Fri, 4 Sep 2015 15:45:09 -0700 Subject: [PATCH 6394/7006] watchdog: simplify housekeeping affinity with the appropriate mask housekeeping_mask gathers all the CPUs that aren't part of the nohz_full set. This is exactly what we want the watchdog to be affine to without the need to use complicated cpumask operations. Signed-off-by: Frederic Weisbecker Reviewed-by: Chris Metcalf Cc: Thomas Gleixner Cc: Chris Metcalf Cc: Don Zickus Cc: Peter Zijlstra Cc: Ulrich Obergfell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/watchdog.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index e5bb86fb0ea5f..d18330fa47769 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -929,10 +929,8 @@ void __init lockup_detector_init(void) #ifdef CONFIG_NO_HZ_FULL if (tick_nohz_full_enabled()) { - if (!cpumask_empty(tick_nohz_full_mask)) - pr_info("Disabling watchdog on nohz_full cores by default\n"); - cpumask_andnot(&watchdog_cpumask, cpu_possible_mask, - tick_nohz_full_mask); + pr_info("Disabling watchdog on nohz_full cores by default\n"); + cpumask_copy(&watchdog_cpumask, housekeeping_mask); } else cpumask_copy(&watchdog_cpumask, cpu_possible_mask); #else -- GitLab From aacfbe6a9724bb6d66a656a5abcc681d5649ed92 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 4 Sep 2015 15:45:12 -0700 Subject: [PATCH 6395/7006] kernel/watchdog: move NMI function header declarations from watchdog.h to nmi.h The kernel's NMI watchdog has nothing to do with the watchdog subsystem. Its header declarations should be in linux/nmi.h, not linux/watchdog.h. The code provided two sets of dummy functions if HARDLOCKUP_DETECTOR is not configured, one in the include file and one in kernel/watchdog.c. Remove the dummy functions from kernel/watchdog.c and use those from the include file. Signed-off-by: Guenter Roeck Cc: Stephane Eranian Cc: Peter Zijlstra (Intel) Cc: Ingo Molnar Cc: Don Zickus Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/kernel/cpu/perf_event_intel.c | 2 +- include/linux/nmi.h | 8 +++++--- include/linux/watchdog.h | 8 -------- kernel/watchdog.c | 2 -- 4 files changed, 6 insertions(+), 14 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 3f124d553c5aa..36bd8250934b0 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/include/linux/nmi.h b/include/linux/nmi.h index f94da0e65dea9..088714537d103 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -26,10 +26,12 @@ static inline void touch_nmi_watchdog(void) #if defined(CONFIG_HARDLOCKUP_DETECTOR) extern void hardlockup_detector_disable(void); +void watchdog_nmi_disable_all(void); +void watchdog_nmi_enable_all(void); #else -static inline void hardlockup_detector_disable(void) -{ -} +static inline void hardlockup_detector_disable(void) {} +static inline void watchdog_nmi_disable_all(void) {} +static inline void watchdog_nmi_enable_all(void) {} #endif /* diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index f47feada5b42c..d74a0e907b9e7 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -140,12 +140,4 @@ extern int watchdog_init_timeout(struct watchdog_device *wdd, extern int watchdog_register_device(struct watchdog_device *); extern void watchdog_unregister_device(struct watchdog_device *); -#ifdef CONFIG_HARDLOCKUP_DETECTOR -void watchdog_nmi_disable_all(void); -void watchdog_nmi_enable_all(void); -#else -static inline void watchdog_nmi_disable_all(void) {} -static inline void watchdog_nmi_enable_all(void) {} -#endif - #endif /* ifndef _LINUX_WATCHDOG_H */ diff --git a/kernel/watchdog.c b/kernel/watchdog.c index d18330fa47769..e74d48bc3e61f 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -651,8 +651,6 @@ unlock: #else static int watchdog_nmi_enable(unsigned int cpu) { return 0; } static void watchdog_nmi_disable(unsigned int cpu) { return; } -void watchdog_nmi_enable_all(void) {} -void watchdog_nmi_disable_all(void) {} #endif /* CONFIG_HARDLOCKUP_DETECTOR */ static struct smp_hotplug_thread watchdog_threads = { -- GitLab From 81a4beef91ba4a9e8ad6054ca9933dff7e25ff28 Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Fri, 4 Sep 2015 15:45:15 -0700 Subject: [PATCH 6396/7006] watchdog: introduce watchdog_park_threads() and watchdog_unpark_threads() Originally watchdog_nmi_enable(cpu) and watchdog_nmi_disable(cpu) were only called in watchdog thread context. However, the following commits utilize these functions outside of watchdog thread context too. commit 9809b18fcf6b8d8ec4d3643677345907e6b50eca Author: Michal Hocko Date: Tue Sep 24 15:27:30 2013 -0700 watchdog: update watchdog_thresh properly commit b3738d29323344da3017a91010530cf3a58590fc Author: Stephane Eranian Date: Mon Nov 17 20:07:03 2014 +0100 watchdog: Add watchdog enable/disable all functions Hence, it is now possible that these functions execute concurrently with the same 'cpu' argument. This concurrency is problematic because per-cpu 'watchdog_ev' can be accessed/modified without adequate synchronization. The patch series aims to address the above problem. However, instead of introducing locks to protect per-cpu 'watchdog_ev' a different approach is taken: Invoke these functions by parking and unparking the watchdog threads (to ensure they are always called in watchdog thread context). static struct smp_hotplug_thread watchdog_threads = { ... .park = watchdog_disable, // calls watchdog_nmi_disable() .unpark = watchdog_enable, // calls watchdog_nmi_enable() }; Both previously mentioned commits call these functions in a similar way and thus in principle contain some duplicate code. The patch series also avoids this duplication by providing a commonly usable mechanism. - Patch 1/4 introduces the watchdog_{park|unpark}_threads functions that park/unpark all watchdog threads specified in 'watchdog_cpumask'. They are intended to be called inside of kernel/watchdog.c only. - Patch 2/4 introduces the watchdog_{suspend|resume} functions which can be utilized by external callers to deactivate the hard and soft lockup detector temporarily. - Patch 3/4 utilizes watchdog_{park|unpark}_threads to replace some code that was introduced by commit 9809b18fcf6b8d8ec4d3643677345907e6b50eca. - Patch 4/4 utilizes watchdog_{suspend|resume} to replace some code that was introduced by commit b3738d29323344da3017a91010530cf3a58590fc. A few corner cases should be mentioned here for completeness. - kthread_park() of watchdog/N could hang if cpu N is already locked up. However, if watchdog is enabled the lockup will be detected anyway. - kthread_unpark() of watchdog/N could hang if cpu N got locked up after kthread_park(). The occurrence of this scenario should be _very_ rare in practice, in particular because it is not expected that temporary deactivation will happen frequently, and if it happens at all it is expected that the duration of deactivation will be short. This patch (of 4): introduce watchdog_park_threads() and watchdog_unpark_threads() These functions are intended to be used only from inside kernel/watchdog.c to park/unpark all watchdog threads that are specified in watchdog_cpumask. Signed-off-by: Ulrich Obergfell Reviewed-by: Aaron Tomlin Cc: Guenter Roeck Cc: Don Zickus Cc: Ulrich Obergfell Cc: Jiri Olsa Cc: Michal Hocko Cc: Stephane Eranian Cc: Chris Metcalf Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/watchdog.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index e74d48bc3e61f..6c489e49c6102 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -24,6 +24,7 @@ #include #include #include +#include /* * The run state of the lockup detectors is controlled by the content of the @@ -664,6 +665,41 @@ static struct smp_hotplug_thread watchdog_threads = { .unpark = watchdog_enable, }; +/* + * park all watchdog threads that are specified in 'watchdog_cpumask' + */ +static int watchdog_park_threads(void) +{ + int cpu, ret = 0; + + get_online_cpus(); + for_each_watchdog_cpu(cpu) { + ret = kthread_park(per_cpu(softlockup_watchdog, cpu)); + if (ret) + break; + } + if (ret) { + for_each_watchdog_cpu(cpu) + kthread_unpark(per_cpu(softlockup_watchdog, cpu)); + } + put_online_cpus(); + + return ret; +} + +/* + * unpark all watchdog threads that are specified in 'watchdog_cpumask' + */ +static void watchdog_unpark_threads(void) +{ + int cpu; + + get_online_cpus(); + for_each_watchdog_cpu(cpu) + kthread_unpark(per_cpu(softlockup_watchdog, cpu)); + put_online_cpus(); +} + static void restart_watchdog_hrtimer(void *info) { struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); -- GitLab From 8c073d27d7ad293bf734cc8475689413afadab81 Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Fri, 4 Sep 2015 15:45:18 -0700 Subject: [PATCH 6397/7006] watchdog: introduce watchdog_suspend() and watchdog_resume() This interface can be utilized to deactivate the hard and soft lockup detector temporarily. Callers are expected to minimize the duration of deactivation. Multiple deactivations are allowed to occur in parallel but should be rare in practice. [akpm@linux-foundation.org: remove unneeded static initialization] Signed-off-by: Ulrich Obergfell Reviewed-by: Aaron Tomlin Cc: Guenter Roeck Cc: Don Zickus Cc: Ulrich Obergfell Cc: Jiri Olsa Cc: Michal Hocko Cc: Stephane Eranian Cc: Chris Metcalf Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/nmi.h | 2 ++ kernel/watchdog.c | 65 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/include/linux/nmi.h b/include/linux/nmi.h index 088714537d103..e9f213c337bb3 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -82,6 +82,8 @@ extern int proc_watchdog_thresh(struct ctl_table *, int , void __user *, size_t *, loff_t *); extern int proc_watchdog_cpumask(struct ctl_table *, int, void __user *, size_t *, loff_t *); +extern int watchdog_suspend(void); +extern void watchdog_resume(void); #endif #ifdef CONFIG_HAVE_ACPI_APEI_NMI diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 6c489e49c6102..e6eb5b6972128 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -67,6 +67,7 @@ unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask); #define for_each_watchdog_cpu(cpu) \ for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask) +static int __read_mostly watchdog_suspended; static int __read_mostly watchdog_running; static u64 __read_mostly sample_period; @@ -700,6 +701,50 @@ static void watchdog_unpark_threads(void) put_online_cpus(); } +/* + * Suspend the hard and soft lockup detector by parking the watchdog threads. + */ +int watchdog_suspend(void) +{ + int ret = 0; + + mutex_lock(&watchdog_proc_mutex); + /* + * Multiple suspend requests can be active in parallel (counted by + * the 'watchdog_suspended' variable). If the watchdog threads are + * running, the first caller takes care that they will be parked. + * The state of 'watchdog_running' cannot change while a suspend + * request is active (see related changes in 'proc' handlers). + */ + if (watchdog_running && !watchdog_suspended) + ret = watchdog_park_threads(); + + if (ret == 0) + watchdog_suspended++; + + mutex_unlock(&watchdog_proc_mutex); + + return ret; +} + +/* + * Resume the hard and soft lockup detector by unparking the watchdog threads. + */ +void watchdog_resume(void) +{ + mutex_lock(&watchdog_proc_mutex); + + watchdog_suspended--; + /* + * The watchdog threads are unparked if they were previously running + * and if there is no more active suspend request. + */ + if (watchdog_running && !watchdog_suspended) + watchdog_unpark_threads(); + + mutex_unlock(&watchdog_proc_mutex); +} + static void restart_watchdog_hrtimer(void *info) { struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); @@ -818,6 +863,12 @@ static int proc_watchdog_common(int which, struct ctl_table *table, int write, mutex_lock(&watchdog_proc_mutex); + if (watchdog_suspended) { + /* no parameter changes allowed while watchdog is suspended */ + err = -EAGAIN; + goto out; + } + /* * If the parameter is being read return the state of the corresponding * bit(s) in 'watchdog_enabled', else update 'watchdog_enabled' and the @@ -903,6 +954,12 @@ int proc_watchdog_thresh(struct ctl_table *table, int write, mutex_lock(&watchdog_proc_mutex); + if (watchdog_suspended) { + /* no parameter changes allowed while watchdog is suspended */ + err = -EAGAIN; + goto out; + } + old = ACCESS_ONCE(watchdog_thresh); err = proc_dointvec_minmax(table, write, buffer, lenp, ppos); @@ -934,6 +991,13 @@ int proc_watchdog_cpumask(struct ctl_table *table, int write, int err; mutex_lock(&watchdog_proc_mutex); + + if (watchdog_suspended) { + /* no parameter changes allowed while watchdog is suspended */ + err = -EAGAIN; + goto out; + } + err = proc_do_large_bitmap(table, write, buffer, lenp, ppos); if (!err && write) { /* Remove impossible cpus to keep sysctl output cleaner. */ @@ -951,6 +1015,7 @@ int proc_watchdog_cpumask(struct ctl_table *table, int write, pr_err("cpumask update failed\n"); } } +out: mutex_unlock(&watchdog_proc_mutex); return err; } -- GitLab From d4bdd0b21c7652a8271f873cc755486b255c1bbd Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Fri, 4 Sep 2015 15:45:21 -0700 Subject: [PATCH 6398/7006] watchdog: use park/unpark functions in update_watchdog_all_cpus() Remove update_watchdog() and restart_watchdog_hrtimer() since these functions are no longer needed. Changes of parameters such as the sample period are honored at the time when the watchdog threads are being unparked. Signed-off-by: Ulrich Obergfell Reviewed-by: Aaron Tomlin Cc: Guenter Roeck Cc: Don Zickus Cc: Ulrich Obergfell Cc: Jiri Olsa Cc: Michal Hocko Cc: Stephane Eranian Cc: Chris Metcalf Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/watchdog.c | 40 ++-------------------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/kernel/watchdog.c b/kernel/watchdog.c index e6eb5b6972128..eb8f94b501014 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -745,46 +745,10 @@ void watchdog_resume(void) mutex_unlock(&watchdog_proc_mutex); } -static void restart_watchdog_hrtimer(void *info) -{ - struct hrtimer *hrtimer = raw_cpu_ptr(&watchdog_hrtimer); - int ret; - - /* - * No need to cancel and restart hrtimer if it is currently executing - * because it will reprogram itself with the new period now. - * We should never see it unqueued here because we are running per-cpu - * with interrupts disabled. - */ - ret = hrtimer_try_to_cancel(hrtimer); - if (ret == 1) - hrtimer_start(hrtimer, ns_to_ktime(sample_period), - HRTIMER_MODE_REL_PINNED); -} - -static void update_watchdog(int cpu) -{ - /* - * Make sure that perf event counter will adopt to a new - * sampling period. Updating the sampling period directly would - * be much nicer but we do not have an API for that now so - * let's use a big hammer. - * Hrtimer will adopt the new period on the next tick but this - * might be late already so we have to restart the timer as well. - */ - watchdog_nmi_disable(cpu); - smp_call_function_single(cpu, restart_watchdog_hrtimer, NULL, 1); - watchdog_nmi_enable(cpu); -} - static void update_watchdog_all_cpus(void) { - int cpu; - - get_online_cpus(); - for_each_watchdog_cpu(cpu) - update_watchdog(cpu); - put_online_cpus(); + watchdog_park_threads(); + watchdog_unpark_threads(); } static int watchdog_enable_all_cpus(void) -- GitLab From 999bbe49ea0118b70ddf3f5d679f51dc7a97ae55 Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Fri, 4 Sep 2015 15:45:25 -0700 Subject: [PATCH 6399/7006] watchdog: use suspend/resume interface in fixup_ht_bug() Remove watchdog_nmi_disable_all() and watchdog_nmi_enable_all() since these functions are no longer needed. If a subsystem has a need to deactivate the watchdog temporarily, it should utilize the watchdog_suspend() and watchdog_resume() functions. [akpm@linux-foundation.org: fix build with CONFIG_LOCKUP_DETECTOR=m] Signed-off-by: Ulrich Obergfell Reviewed-by: Aaron Tomlin Cc: Guenter Roeck Cc: Don Zickus Cc: Ulrich Obergfell Cc: Jiri Olsa Cc: Michal Hocko Cc: Stephane Eranian Cc: Chris Metcalf Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/kernel/cpu/perf_event_intel.c | 7 ++++-- include/linux/nmi.h | 13 +++++++--- kernel/watchdog.c | 35 -------------------------- 3 files changed, 14 insertions(+), 41 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 36bd8250934b0..144ab91951a7c 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -3627,7 +3627,10 @@ static __init int fixup_ht_bug(void) return 0; } - watchdog_nmi_disable_all(); + if (watchdog_suspend() != 0) { + pr_debug("failed to disable PMU erratum BJ122, BV98, HSD29 workaround\n"); + return 0; + } x86_pmu.flags &= ~(PMU_FL_EXCL_CNTRS | PMU_FL_EXCL_ENABLED); @@ -3635,7 +3638,7 @@ static __init int fixup_ht_bug(void) x86_pmu.commit_scheduling = NULL; x86_pmu.stop_scheduling = NULL; - watchdog_nmi_enable_all(); + watchdog_resume(); get_online_cpus(); diff --git a/include/linux/nmi.h b/include/linux/nmi.h index e9f213c337bb3..e5afe8bae2028 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -26,12 +26,8 @@ static inline void touch_nmi_watchdog(void) #if defined(CONFIG_HARDLOCKUP_DETECTOR) extern void hardlockup_detector_disable(void); -void watchdog_nmi_disable_all(void); -void watchdog_nmi_enable_all(void); #else static inline void hardlockup_detector_disable(void) {} -static inline void watchdog_nmi_disable_all(void) {} -static inline void watchdog_nmi_enable_all(void) {} #endif /* @@ -84,6 +80,15 @@ extern int proc_watchdog_cpumask(struct ctl_table *, int, void __user *, size_t *, loff_t *); extern int watchdog_suspend(void); extern void watchdog_resume(void); +#else +static inline int watchdog_suspend(void) +{ + return 0; +} + +static inline void watchdog_resume(void) +{ +} #endif #ifdef CONFIG_HAVE_ACPI_APEI_NMI diff --git a/kernel/watchdog.c b/kernel/watchdog.c index eb8f94b501014..69666f4b8e8f7 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -615,41 +615,6 @@ static void watchdog_nmi_disable(unsigned int cpu) } } -void watchdog_nmi_enable_all(void) -{ - int cpu; - - mutex_lock(&watchdog_proc_mutex); - - if (!(watchdog_enabled & NMI_WATCHDOG_ENABLED)) - goto unlock; - - get_online_cpus(); - for_each_watchdog_cpu(cpu) - watchdog_nmi_enable(cpu); - put_online_cpus(); - -unlock: - mutex_unlock(&watchdog_proc_mutex); -} - -void watchdog_nmi_disable_all(void) -{ - int cpu; - - mutex_lock(&watchdog_proc_mutex); - - if (!watchdog_running) - goto unlock; - - get_online_cpus(); - for_each_watchdog_cpu(cpu) - watchdog_nmi_disable(cpu); - put_online_cpus(); - -unlock: - mutex_unlock(&watchdog_proc_mutex); -} #else static int watchdog_nmi_enable(unsigned int cpu) { return 0; } static void watchdog_nmi_disable(unsigned int cpu) { return; } -- GitLab From ec6a90661a0d6ce1461d05c7a58a0a151154e14a Mon Sep 17 00:00:00 2001 From: Ulrich Obergfell Date: Fri, 4 Sep 2015 15:45:28 -0700 Subject: [PATCH 6400/7006] watchdog: rename watchdog_suspend() and watchdog_resume() Rename watchdog_suspend() to lockup_detector_suspend() and watchdog_resume() to lockup_detector_resume() to avoid confusion with the watchdog subsystem and to be consistent with the existing name lockup_detector_init(). Also provide comment blocks to explain the watchdog_running and watchdog_suspended variables and their relationship. Signed-off-by: Ulrich Obergfell Reviewed-by: Aaron Tomlin Cc: Guenter Roeck Cc: Don Zickus Cc: Ulrich Obergfell Cc: Jiri Olsa Cc: Michal Hocko Cc: Stephane Eranian Cc: Chris Metcalf Cc: Frederic Weisbecker Cc: Peter Zijlstra Cc: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/kernel/cpu/perf_event_intel.c | 4 ++-- include/linux/nmi.h | 8 ++++---- kernel/watchdog.c | 26 ++++++++++++++++++++++---- 3 files changed, 28 insertions(+), 10 deletions(-) diff --git a/arch/x86/kernel/cpu/perf_event_intel.c b/arch/x86/kernel/cpu/perf_event_intel.c index 144ab91951a7c..cd9b6d0b10bf4 100644 --- a/arch/x86/kernel/cpu/perf_event_intel.c +++ b/arch/x86/kernel/cpu/perf_event_intel.c @@ -3627,7 +3627,7 @@ static __init int fixup_ht_bug(void) return 0; } - if (watchdog_suspend() != 0) { + if (lockup_detector_suspend() != 0) { pr_debug("failed to disable PMU erratum BJ122, BV98, HSD29 workaround\n"); return 0; } @@ -3638,7 +3638,7 @@ static __init int fixup_ht_bug(void) x86_pmu.commit_scheduling = NULL; x86_pmu.stop_scheduling = NULL; - watchdog_resume(); + lockup_detector_resume(); get_online_cpus(); diff --git a/include/linux/nmi.h b/include/linux/nmi.h index e5afe8bae2028..a91adf6e02f2a 100644 --- a/include/linux/nmi.h +++ b/include/linux/nmi.h @@ -78,15 +78,15 @@ extern int proc_watchdog_thresh(struct ctl_table *, int , void __user *, size_t *, loff_t *); extern int proc_watchdog_cpumask(struct ctl_table *, int, void __user *, size_t *, loff_t *); -extern int watchdog_suspend(void); -extern void watchdog_resume(void); +extern int lockup_detector_suspend(void); +extern void lockup_detector_resume(void); #else -static inline int watchdog_suspend(void) +static inline int lockup_detector_suspend(void) { return 0; } -static inline void watchdog_resume(void) +static inline void lockup_detector_resume(void) { } #endif diff --git a/kernel/watchdog.c b/kernel/watchdog.c index 69666f4b8e8f7..64ed1c37bd1fd 100644 --- a/kernel/watchdog.c +++ b/kernel/watchdog.c @@ -67,8 +67,26 @@ unsigned long *watchdog_cpumask_bits = cpumask_bits(&watchdog_cpumask); #define for_each_watchdog_cpu(cpu) \ for_each_cpu_and((cpu), cpu_online_mask, &watchdog_cpumask) -static int __read_mostly watchdog_suspended; +/* + * The 'watchdog_running' variable is set to 1 when the watchdog threads + * are registered/started and is set to 0 when the watchdog threads are + * unregistered/stopped, so it is an indicator whether the threads exist. + */ static int __read_mostly watchdog_running; +/* + * If a subsystem has a need to deactivate the watchdog temporarily, it + * can use the suspend/resume interface to achieve this. The content of + * the 'watchdog_suspended' variable reflects this state. Existing threads + * are parked/unparked by the lockup_detector_{suspend|resume} functions + * (see comment blocks pertaining to those functions for further details). + * + * 'watchdog_suspended' also prevents threads from being registered/started + * or unregistered/stopped via parameters in /proc/sys/kernel, so the state + * of 'watchdog_running' cannot change while the watchdog is deactivated + * temporarily (see related code in 'proc' handlers). + */ +static int __read_mostly watchdog_suspended; + static u64 __read_mostly sample_period; static DEFINE_PER_CPU(unsigned long, watchdog_touch_ts); @@ -669,7 +687,7 @@ static void watchdog_unpark_threads(void) /* * Suspend the hard and soft lockup detector by parking the watchdog threads. */ -int watchdog_suspend(void) +int lockup_detector_suspend(void) { int ret = 0; @@ -679,7 +697,7 @@ int watchdog_suspend(void) * the 'watchdog_suspended' variable). If the watchdog threads are * running, the first caller takes care that they will be parked. * The state of 'watchdog_running' cannot change while a suspend - * request is active (see related changes in 'proc' handlers). + * request is active (see related code in 'proc' handlers). */ if (watchdog_running && !watchdog_suspended) ret = watchdog_park_threads(); @@ -695,7 +713,7 @@ int watchdog_suspend(void) /* * Resume the hard and soft lockup detector by unparking the watchdog threads. */ -void watchdog_resume(void) +void lockup_detector_resume(void) { mutex_lock(&watchdog_proc_mutex); -- GitLab From 2ae44005b678431a5c7a55dafcd09421ba3fadf0 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Fri, 4 Sep 2015 15:45:31 -0700 Subject: [PATCH 6401/7006] slub: fix spelling succedd to succeed With this patchset the SLUB allocator now has both bulk alloc and free implemented. This patchset mostly optimizes the "fastpath" where objects are available on the per CPU fastpath page. This mostly amortize the less-heavy none-locked cmpxchg_double used on fastpath. The "fallback" bulking (e.g __kmem_cache_free_bulk) provides a good basis for comparison. Measurements[1] of the fallback functions __kmem_cache_{free,alloc}_bulk have been copied from slab_common.c and forced "noinline" to force a function call like slab_common.c. Measurements on CPU CPU i7-4790K @ 4.00GHz Baseline normal fastpath (alloc+free cost): 42 cycles(tsc) 10.601 ns Measurements last-patch with disabled debugging: Bulk- fallback - this-patch 1 - 57 cycles(tsc) 14.448 ns - 44 cycles(tsc) 11.236 ns improved 22.8% 2 - 51 cycles(tsc) 12.768 ns - 28 cycles(tsc) 7.019 ns improved 45.1% 3 - 48 cycles(tsc) 12.232 ns - 22 cycles(tsc) 5.526 ns improved 54.2% 4 - 48 cycles(tsc) 12.025 ns - 19 cycles(tsc) 4.786 ns improved 60.4% 8 - 46 cycles(tsc) 11.558 ns - 18 cycles(tsc) 4.572 ns improved 60.9% 16 - 45 cycles(tsc) 11.458 ns - 18 cycles(tsc) 4.658 ns improved 60.0% 30 - 45 cycles(tsc) 11.499 ns - 18 cycles(tsc) 4.568 ns improved 60.0% 32 - 79 cycles(tsc) 19.917 ns - 65 cycles(tsc) 16.454 ns improved 17.7% 34 - 78 cycles(tsc) 19.655 ns - 63 cycles(tsc) 15.932 ns improved 19.2% 48 - 68 cycles(tsc) 17.049 ns - 50 cycles(tsc) 12.506 ns improved 26.5% 64 - 80 cycles(tsc) 20.009 ns - 63 cycles(tsc) 15.929 ns improved 21.3% 128 - 94 cycles(tsc) 23.749 ns - 86 cycles(tsc) 21.583 ns improved 8.5% 158 - 97 cycles(tsc) 24.299 ns - 90 cycles(tsc) 22.552 ns improved 7.2% 250 - 102 cycles(tsc) 25.681 ns - 98 cycles(tsc) 24.589 ns improved 3.9% Benchmarking shows impressive improvements in the "fastpath" with a small number of objects in the working set. Once the working set increases, resulting in activating the "slowpath" (that contains the heavier locked cmpxchg_double) the improvement decreases. I'm currently working on also optimizing the "slowpath" (as network stack use-case hits this), but this patchset should provide a good foundation for further improvements. Rest of my patch queue in this area needs some more work, but preliminary results are good. I'm attending Netfilter Workshop[2] next week, and I'll hopefully return working on further improvements in this area. This patch (of 6): s/succedd/succeed/ Signed-off-by: Jesper Dangaard Brouer Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index f68c0e50f3c08..defd76f986482 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2712,7 +2712,7 @@ redo: * Determine the currently cpus per cpu slab. * The cpu may change afterward. However that does not matter since * data is retrieved via this pointer. If we are on the same cpu - * during the cmpxchg then the free will succedd. + * during the cmpxchg then the free will succeed. */ do { tid = this_cpu_read(s->cpu_slab->tid); -- GitLab From 484748f0b65a1950b2b93f444a2287e8dd2cedd6 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Fri, 4 Sep 2015 15:45:34 -0700 Subject: [PATCH 6402/7006] slab: infrastructure for bulk object allocation and freeing Add the basic infrastructure for alloc/free operations on pointer arrays. It includes a generic function in the common slab code that is used in this infrastructure patch to create the unoptimized functionality for slab bulk operations. Allocators can then provide optimized allocation functions for situations in which large numbers of objects are needed. These optimization may avoid taking locks repeatedly and bypass metadata creation if all objects in slab pages can be used to provide the objects required. Allocators can extend the skeletons provided and add their own code to the bulk alloc and free functions. They can keep the generic allocation and freeing and just fall back to those if optimizations would not work (like for example when debugging is on). Signed-off-by: Christoph Lameter Signed-off-by: Jesper Dangaard Brouer Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 10 ++++++++++ mm/slab.c | 13 +++++++++++++ mm/slab.h | 9 +++++++++ mm/slab_common.c | 23 +++++++++++++++++++++++ mm/slob.c | 13 +++++++++++++ mm/slub.c | 14 ++++++++++++++ 6 files changed, 82 insertions(+) diff --git a/include/linux/slab.h b/include/linux/slab.h index a99f0e5243e1e..7e37d448ed910 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -290,6 +290,16 @@ void *__kmalloc(size_t size, gfp_t flags); void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags); void kmem_cache_free(struct kmem_cache *, void *); +/* + * Bulk allocation and freeing operations. These are accellerated in an + * allocator specific way to avoid taking locks repeatedly or building + * metadata structures unnecessarily. + * + * Note that interrupts must be enabled when calling these functions. + */ +void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); +bool kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); + #ifdef CONFIG_NUMA void *__kmalloc_node(size_t size, gfp_t flags, int node); void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node); diff --git a/mm/slab.c b/mm/slab.c index bbd0b47dc6a97..60c936938b848 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -3416,6 +3416,19 @@ void *kmem_cache_alloc(struct kmem_cache *cachep, gfp_t flags) } EXPORT_SYMBOL(kmem_cache_alloc); +void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) +{ + __kmem_cache_free_bulk(s, size, p); +} +EXPORT_SYMBOL(kmem_cache_free_bulk); + +bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, + void **p) +{ + return __kmem_cache_alloc_bulk(s, flags, size, p); +} +EXPORT_SYMBOL(kmem_cache_alloc_bulk); + #ifdef CONFIG_TRACING void * kmem_cache_alloc_trace(struct kmem_cache *cachep, gfp_t flags, size_t size) diff --git a/mm/slab.h b/mm/slab.h index 8da63e4e470f2..88b55497738cb 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -163,6 +163,15 @@ void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s); ssize_t slabinfo_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos); +/* + * Generic implementation of bulk operations + * These are useful for situations in which the allocator cannot + * perform optimizations. In that case segments of the objecct listed + * may be allocated or freed using these operations. + */ +void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); +bool __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); + #ifdef CONFIG_MEMCG_KMEM /* * Iterate over all memcg caches of the given root cache. The caller must hold diff --git a/mm/slab_common.c b/mm/slab_common.c index 86831105a09f4..c26829fe4e37e 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -104,6 +104,29 @@ static inline int kmem_cache_sanity_check(const char *name, size_t size) } #endif +void __kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p) +{ + size_t i; + + for (i = 0; i < nr; i++) + kmem_cache_free(s, p[i]); +} + +bool __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr, + void **p) +{ + size_t i; + + for (i = 0; i < nr; i++) { + void *x = p[i] = kmem_cache_alloc(s, flags); + if (!x) { + __kmem_cache_free_bulk(s, i, p); + return false; + } + } + return true; +} + #ifdef CONFIG_MEMCG_KMEM void slab_init_memcg_params(struct kmem_cache *s) { diff --git a/mm/slob.c b/mm/slob.c index 4765f65019c73..165bbd3cd6062 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -611,6 +611,19 @@ void kmem_cache_free(struct kmem_cache *c, void *b) } EXPORT_SYMBOL(kmem_cache_free); +void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) +{ + __kmem_cache_free_bulk(s, size, p); +} +EXPORT_SYMBOL(kmem_cache_free_bulk); + +bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, + void **p) +{ + return __kmem_cache_alloc_bulk(s, flags, size, p); +} +EXPORT_SYMBOL(kmem_cache_alloc_bulk); + int __kmem_cache_shutdown(struct kmem_cache *c) { /* No way to check for remaining objects */ diff --git a/mm/slub.c b/mm/slub.c index defd76f986482..3ca89ef9b7b09 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2750,6 +2750,20 @@ void kmem_cache_free(struct kmem_cache *s, void *x) } EXPORT_SYMBOL(kmem_cache_free); +void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) +{ + __kmem_cache_free_bulk(s, size, p); +} +EXPORT_SYMBOL(kmem_cache_free_bulk); + +bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, + void **p) +{ + return __kmem_cache_alloc_bulk(s, flags, size, p); +} +EXPORT_SYMBOL(kmem_cache_alloc_bulk); + + /* * Object placement in a slab is made very easy because we always start at * offset 0. If we tune the size of the object to the alignment then we can -- GitLab From 994eb764ec5ad57c9b7c5e72b892205039a84b69 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Fri, 4 Sep 2015 15:45:37 -0700 Subject: [PATCH 6403/7006] slub bulk alloc: extract objects from the per cpu slab First piece: acceleration of retrieval of per cpu objects If we are allocating lots of objects then it is advantageous to disable interrupts and avoid the this_cpu_cmpxchg() operation to get these objects faster. Note that we cannot do the fast operation if debugging is enabled, because we would have to add extra code to do all the debugging checks. And it would not be fast anyway. Note also that the requirement of having interrupts disabled avoids having to do processor flag operations. Allocate as many objects as possible in the fast way and then fall back to the generic implementation for the rest of the objects. Measurements on CPU CPU i7-4790K @ 4.00GHz Baseline normal fastpath (alloc+free cost): 42 cycles(tsc) 10.554 ns Bulk- fallback - this-patch 1 - 57 cycles(tsc) 14.432 ns - 48 cycles(tsc) 12.155 ns improved 15.8% 2 - 50 cycles(tsc) 12.746 ns - 37 cycles(tsc) 9.390 ns improved 26.0% 3 - 48 cycles(tsc) 12.180 ns - 33 cycles(tsc) 8.417 ns improved 31.2% 4 - 48 cycles(tsc) 12.015 ns - 32 cycles(tsc) 8.045 ns improved 33.3% 8 - 46 cycles(tsc) 11.526 ns - 30 cycles(tsc) 7.699 ns improved 34.8% 16 - 45 cycles(tsc) 11.418 ns - 32 cycles(tsc) 8.205 ns improved 28.9% 30 - 80 cycles(tsc) 20.246 ns - 73 cycles(tsc) 18.328 ns improved 8.8% 32 - 79 cycles(tsc) 19.946 ns - 72 cycles(tsc) 18.208 ns improved 8.9% 34 - 78 cycles(tsc) 19.659 ns - 71 cycles(tsc) 17.987 ns improved 9.0% 48 - 86 cycles(tsc) 21.516 ns - 82 cycles(tsc) 20.566 ns improved 4.7% 64 - 93 cycles(tsc) 23.423 ns - 89 cycles(tsc) 22.480 ns improved 4.3% 128 - 100 cycles(tsc) 25.170 ns - 99 cycles(tsc) 24.871 ns improved 1.0% 158 - 102 cycles(tsc) 25.549 ns - 101 cycles(tsc) 25.375 ns improved 1.0% 250 - 101 cycles(tsc) 25.344 ns - 100 cycles(tsc) 25.182 ns improved 1.0% Signed-off-by: Christoph Lameter Signed-off-by: Jesper Dangaard Brouer Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 3ca89ef9b7b09..30e7dedec664f 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2750,16 +2750,61 @@ void kmem_cache_free(struct kmem_cache *s, void *x) } EXPORT_SYMBOL(kmem_cache_free); +/* Note that interrupts must be enabled when calling this function. */ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) { __kmem_cache_free_bulk(s, size, p); } EXPORT_SYMBOL(kmem_cache_free_bulk); +/* Note that interrupts must be enabled when calling this function. */ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - void **p) + void **p) { - return __kmem_cache_alloc_bulk(s, flags, size, p); + struct kmem_cache_cpu *c; + int i; + + /* Debugging fallback to generic bulk */ + if (kmem_cache_debug(s)) + return __kmem_cache_alloc_bulk(s, flags, size, p); + + /* + * Drain objects in the per cpu slab, while disabling local + * IRQs, which protects against PREEMPT and interrupts + * handlers invoking normal fastpath. + */ + local_irq_disable(); + c = this_cpu_ptr(s->cpu_slab); + + for (i = 0; i < size; i++) { + void *object = c->freelist; + + if (!object) + break; + + c->freelist = get_freepointer(s, object); + p[i] = object; + } + c->tid = next_tid(c->tid); + local_irq_enable(); + + /* Clear memory outside IRQ disabled fastpath loop */ + if (unlikely(flags & __GFP_ZERO)) { + int j; + + for (j = 0; j < i; j++) + memset(p[j], 0, s->object_size); + } + + /* Fallback to single elem alloc */ + for (; i < size; i++) { + void *x = p[i] = kmem_cache_alloc(s, flags); + if (unlikely(!x)) { + __kmem_cache_free_bulk(s, i, p); + return false; + } + } + return true; } EXPORT_SYMBOL(kmem_cache_alloc_bulk); -- GitLab From ebe909e0fdb34b980c5cf636c495e4f0bb0dfda8 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Fri, 4 Sep 2015 15:45:40 -0700 Subject: [PATCH 6404/7006] slub: improve bulk alloc strategy Call slowpath __slab_alloc() from within the bulk loop, as the side-effect of this call likely repopulates c->freelist. Choose to reenable local IRQs while calling slowpath. Saving some optimizations for later. E.g. it is possible to extract parts of __slab_alloc() and avoid the unnecessary and expensive (37 cycles) local_irq_{save,restore}. For now, be happy calling __slab_alloc() this lower icache impact of this func and I don't have to worry about correctness. Measurements on CPU CPU i7-4790K @ 4.00GHz Baseline normal fastpath (alloc+free cost): 42 cycles(tsc) 10.601 ns Bulk- fallback - this-patch 1 - 58 cycles(tsc) 14.516 ns - 49 cycles(tsc) 12.459 ns improved 15.5% 2 - 51 cycles(tsc) 12.930 ns - 38 cycles(tsc) 9.605 ns improved 25.5% 3 - 49 cycles(tsc) 12.274 ns - 34 cycles(tsc) 8.525 ns improved 30.6% 4 - 48 cycles(tsc) 12.058 ns - 32 cycles(tsc) 8.036 ns improved 33.3% 8 - 46 cycles(tsc) 11.609 ns - 31 cycles(tsc) 7.756 ns improved 32.6% 16 - 45 cycles(tsc) 11.451 ns - 32 cycles(tsc) 8.148 ns improved 28.9% 30 - 79 cycles(tsc) 19.865 ns - 68 cycles(tsc) 17.164 ns improved 13.9% 32 - 76 cycles(tsc) 19.212 ns - 66 cycles(tsc) 16.584 ns improved 13.2% 34 - 74 cycles(tsc) 18.600 ns - 63 cycles(tsc) 15.954 ns improved 14.9% 48 - 88 cycles(tsc) 22.092 ns - 77 cycles(tsc) 19.373 ns improved 12.5% 64 - 80 cycles(tsc) 20.043 ns - 68 cycles(tsc) 17.188 ns improved 15.0% 128 - 99 cycles(tsc) 24.818 ns - 89 cycles(tsc) 22.404 ns improved 10.1% 158 - 99 cycles(tsc) 24.977 ns - 92 cycles(tsc) 23.089 ns improved 7.1% 250 - 106 cycles(tsc) 26.552 ns - 99 cycles(tsc) 24.785 ns improved 6.6% Signed-off-by: Jesper Dangaard Brouer Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 30e7dedec664f..f98b1b9e7080c 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2779,8 +2779,22 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, for (i = 0; i < size; i++) { void *object = c->freelist; - if (!object) - break; + if (unlikely(!object)) { + local_irq_enable(); + /* + * Invoking slow path likely have side-effect + * of re-populating per CPU c->freelist + */ + p[i] = __slab_alloc(s, flags, NUMA_NO_NODE, + _RET_IP_, c); + if (unlikely(!p[i])) { + __kmem_cache_free_bulk(s, i, p); + return false; + } + local_irq_disable(); + c = this_cpu_ptr(s->cpu_slab); + continue; /* goto for-loop */ + } c->freelist = get_freepointer(s, object); p[i] = object; @@ -2796,14 +2810,6 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, memset(p[j], 0, s->object_size); } - /* Fallback to single elem alloc */ - for (; i < size; i++) { - void *x = p[i] = kmem_cache_alloc(s, flags); - if (unlikely(!x)) { - __kmem_cache_free_bulk(s, i, p); - return false; - } - } return true; } EXPORT_SYMBOL(kmem_cache_alloc_bulk); -- GitLab From fbd02630c6e3c60feecc4688f5f98b015d264516 Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Fri, 4 Sep 2015 15:45:43 -0700 Subject: [PATCH 6405/7006] slub: initial bulk free implementation This implements SLUB specific kmem_cache_free_bulk(). SLUB allocator now both have bulk alloc and free implemented. Choose to reenable local IRQs while calling slowpath __slab_free(). In worst case, where all objects hit slowpath call, the performance should still be faster than fallback function __kmem_cache_free_bulk(), because local_irq_{disable+enable} is very fast (7-cycles), while the fallback invokes this_cpu_cmpxchg() which is slightly slower (9-cycles). Nitpicking, this should be faster for N>=4, due to the entry cost of local_irq_{disable+enable}. Do notice that the save+restore variant is very expensive, this is key to why this optimization works. CPU: i7-4790K CPU @ 4.00GHz * local_irq_{disable,enable}: 7 cycles(tsc) - 1.821 ns * local_irq_{save,restore} : 37 cycles(tsc) - 9.443 ns Measurements on CPU CPU i7-4790K @ 4.00GHz Baseline normal fastpath (alloc+free cost): 43 cycles(tsc) 10.834 ns Bulk- fallback - this-patch 1 - 58 cycles(tsc) 14.542 ns - 43 cycles(tsc) 10.811 ns improved 25.9% 2 - 50 cycles(tsc) 12.659 ns - 27 cycles(tsc) 6.867 ns improved 46.0% 3 - 48 cycles(tsc) 12.168 ns - 21 cycles(tsc) 5.496 ns improved 56.2% 4 - 47 cycles(tsc) 11.987 ns - 24 cycles(tsc) 6.038 ns improved 48.9% 8 - 46 cycles(tsc) 11.518 ns - 17 cycles(tsc) 4.280 ns improved 63.0% 16 - 45 cycles(tsc) 11.366 ns - 17 cycles(tsc) 4.483 ns improved 62.2% 30 - 45 cycles(tsc) 11.433 ns - 18 cycles(tsc) 4.531 ns improved 60.0% 32 - 75 cycles(tsc) 18.983 ns - 58 cycles(tsc) 14.586 ns improved 22.7% 34 - 71 cycles(tsc) 17.940 ns - 53 cycles(tsc) 13.391 ns improved 25.4% 48 - 80 cycles(tsc) 20.077 ns - 65 cycles(tsc) 16.268 ns improved 18.8% 64 - 71 cycles(tsc) 17.799 ns - 53 cycles(tsc) 13.440 ns improved 25.4% 128 - 91 cycles(tsc) 22.980 ns - 79 cycles(tsc) 19.899 ns improved 13.2% 158 - 100 cycles(tsc) 25.241 ns - 90 cycles(tsc) 22.732 ns improved 10.0% 250 - 102 cycles(tsc) 25.583 ns - 95 cycles(tsc) 23.916 ns improved 6.9% Signed-off-by: Jesper Dangaard Brouer Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/mm/slub.c b/mm/slub.c index f98b1b9e7080c..2bd3d12ae106c 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2753,7 +2753,39 @@ EXPORT_SYMBOL(kmem_cache_free); /* Note that interrupts must be enabled when calling this function. */ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) { - __kmem_cache_free_bulk(s, size, p); + struct kmem_cache_cpu *c; + struct page *page; + int i; + + /* Debugging fallback to generic bulk */ + if (kmem_cache_debug(s)) + return __kmem_cache_free_bulk(s, size, p); + + local_irq_disable(); + c = this_cpu_ptr(s->cpu_slab); + + for (i = 0; i < size; i++) { + void *object = p[i]; + + BUG_ON(!object); + page = virt_to_head_page(object); + BUG_ON(s != page->slab_cache); /* Check if valid slab page */ + + if (c->page == page) { + /* Fastpath: local CPU free */ + set_freepointer(s, object, c->freelist); + c->freelist = object; + } else { + c->tid = next_tid(c->tid); + local_irq_enable(); + /* Slowpath: overhead locked cmpxchg_double_slab */ + __slab_free(s, page, object, _RET_IP_); + local_irq_disable(); + c = this_cpu_ptr(s->cpu_slab); + } + } + c->tid = next_tid(c->tid); + local_irq_enable(); } EXPORT_SYMBOL(kmem_cache_free_bulk); -- GitLab From 3eed034d045ce93a40e232a6bd5f86127342053a Mon Sep 17 00:00:00 2001 From: Jesper Dangaard Brouer Date: Fri, 4 Sep 2015 15:45:45 -0700 Subject: [PATCH 6406/7006] slub: add support for kmem_cache_debug in bulk calls Per request of Joonsoo Kim adding kmem debug support. I've tested that when debugging is disabled, then there is almost no performance impact as this code basically gets removed by the compiler. Need some guidance in enabling and testing this. bulk- PREVIOUS - THIS-PATCH 1 - 43 cycles(tsc) 10.811 ns - 44 cycles(tsc) 11.236 ns improved -2.3% 2 - 27 cycles(tsc) 6.867 ns - 28 cycles(tsc) 7.019 ns improved -3.7% 3 - 21 cycles(tsc) 5.496 ns - 22 cycles(tsc) 5.526 ns improved -4.8% 4 - 24 cycles(tsc) 6.038 ns - 19 cycles(tsc) 4.786 ns improved 20.8% 8 - 17 cycles(tsc) 4.280 ns - 18 cycles(tsc) 4.572 ns improved -5.9% 16 - 17 cycles(tsc) 4.483 ns - 18 cycles(tsc) 4.658 ns improved -5.9% 30 - 18 cycles(tsc) 4.531 ns - 18 cycles(tsc) 4.568 ns improved 0.0% 32 - 58 cycles(tsc) 14.586 ns - 65 cycles(tsc) 16.454 ns improved -12.1% 34 - 53 cycles(tsc) 13.391 ns - 63 cycles(tsc) 15.932 ns improved -18.9% 48 - 65 cycles(tsc) 16.268 ns - 50 cycles(tsc) 12.506 ns improved 23.1% 64 - 53 cycles(tsc) 13.440 ns - 63 cycles(tsc) 15.929 ns improved -18.9% 128 - 79 cycles(tsc) 19.899 ns - 86 cycles(tsc) 21.583 ns improved -8.9% 158 - 90 cycles(tsc) 22.732 ns - 90 cycles(tsc) 22.552 ns improved 0.0% 250 - 95 cycles(tsc) 23.916 ns - 98 cycles(tsc) 24.589 ns improved -3.2% Signed-off-by: Jesper Dangaard Brouer Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 2bd3d12ae106c..48bdb4e5a9858 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -2757,10 +2757,6 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) struct page *page; int i; - /* Debugging fallback to generic bulk */ - if (kmem_cache_debug(s)) - return __kmem_cache_free_bulk(s, size, p); - local_irq_disable(); c = this_cpu_ptr(s->cpu_slab); @@ -2768,8 +2764,13 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) void *object = p[i]; BUG_ON(!object); + /* kmem cache debug support */ + s = cache_from_obj(s, object); + if (unlikely(!s)) + goto exit; + slab_free_hook(s, object); + page = virt_to_head_page(object); - BUG_ON(s != page->slab_cache); /* Check if valid slab page */ if (c->page == page) { /* Fastpath: local CPU free */ @@ -2784,6 +2785,7 @@ void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) c = this_cpu_ptr(s->cpu_slab); } } +exit: c->tid = next_tid(c->tid); local_irq_enable(); } @@ -2796,10 +2798,6 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, struct kmem_cache_cpu *c; int i; - /* Debugging fallback to generic bulk */ - if (kmem_cache_debug(s)) - return __kmem_cache_alloc_bulk(s, flags, size, p); - /* * Drain objects in the per cpu slab, while disabling local * IRQs, which protects against PREEMPT and interrupts @@ -2828,8 +2826,20 @@ bool kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, continue; /* goto for-loop */ } + /* kmem_cache debug support */ + s = slab_pre_alloc_hook(s, flags); + if (unlikely(!s)) { + __kmem_cache_free_bulk(s, i, p); + c->tid = next_tid(c->tid); + local_irq_enable(); + return false; + } + c->freelist = get_freepointer(s, object); p[i] = object; + + /* kmem_cache debug support */ + slab_post_alloc_hook(s, flags, object); } c->tid = next_tid(c->tid); local_irq_enable(); -- GitLab From 588f8ba913d35a667407afa29444bf2f94e03d19 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 4 Sep 2015 15:45:48 -0700 Subject: [PATCH 6407/7006] mm/slub: move slab initialization into irq enabled region Initializing a new slab can introduce rather large latencies because most of the initialization runs always with interrupts disabled. There is no point in doing so. The newly allocated slab is not visible yet, so there is no reason to protect it against concurrent alloc/free. Move the expensive parts of the initialization into allocate_slab(), so for all allocations with GFP_WAIT set, interrupts are enabled. Signed-off-by: Thomas Gleixner Acked-by: Christoph Lameter Cc: Pekka Enberg Acked-by: David Rientjes Cc: Joonsoo Kim Cc: Sebastian Andrzej Siewior Cc: Steven Rostedt Cc: Peter Zijlstra Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 89 ++++++++++++++++++++++++++----------------------------- 1 file changed, 42 insertions(+), 47 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 48bdb4e5a9858..3efcdc02082c6 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1306,6 +1306,17 @@ static inline void slab_free_hook(struct kmem_cache *s, void *x) kasan_slab_free(s, x); } +static void setup_object(struct kmem_cache *s, struct page *page, + void *object) +{ + setup_object_debug(s, page, object); + if (unlikely(s->ctor)) { + kasan_unpoison_object_data(s, object); + s->ctor(object); + kasan_poison_object_data(s, object); + } +} + /* * Slab allocation and freeing */ @@ -1336,6 +1347,8 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) struct page *page; struct kmem_cache_order_objects oo = s->oo; gfp_t alloc_gfp; + void *start, *p; + int idx, order; flags &= gfp_allowed_mask; @@ -1359,13 +1372,13 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) * Try a lower order alloc if possible */ page = alloc_slab_page(s, alloc_gfp, node, oo); - - if (page) - stat(s, ORDER_FALLBACK); + if (unlikely(!page)) + goto out; + stat(s, ORDER_FALLBACK); } - if (kmemcheck_enabled && page - && !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) { + if (kmemcheck_enabled && + !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) { int pages = 1 << oo_order(oo); kmemcheck_alloc_shadow(page, oo_order(oo), alloc_gfp, node); @@ -1380,51 +1393,9 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) kmemcheck_mark_unallocated_pages(page, pages); } - if (flags & __GFP_WAIT) - local_irq_disable(); - if (!page) - return NULL; - page->objects = oo_objects(oo); - mod_zone_page_state(page_zone(page), - (s->flags & SLAB_RECLAIM_ACCOUNT) ? - NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, - 1 << oo_order(oo)); - - return page; -} - -static void setup_object(struct kmem_cache *s, struct page *page, - void *object) -{ - setup_object_debug(s, page, object); - if (unlikely(s->ctor)) { - kasan_unpoison_object_data(s, object); - s->ctor(object); - kasan_poison_object_data(s, object); - } -} - -static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) -{ - struct page *page; - void *start; - void *p; - int order; - int idx; - - if (unlikely(flags & GFP_SLAB_BUG_MASK)) { - pr_emerg("gfp: %u\n", flags & GFP_SLAB_BUG_MASK); - BUG(); - } - - page = allocate_slab(s, - flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node); - if (!page) - goto out; order = compound_order(page); - inc_slabs_node(s, page_to_nid(page), page->objects); page->slab_cache = s; __SetPageSlab(page); if (page_is_pfmemalloc(page)) @@ -1448,10 +1419,34 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) page->freelist = start; page->inuse = page->objects; page->frozen = 1; + out: + if (flags & __GFP_WAIT) + local_irq_disable(); + if (!page) + return NULL; + + mod_zone_page_state(page_zone(page), + (s->flags & SLAB_RECLAIM_ACCOUNT) ? + NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, + 1 << oo_order(oo)); + + inc_slabs_node(s, page_to_nid(page), page->objects); + return page; } +static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) +{ + if (unlikely(flags & GFP_SLAB_BUG_MASK)) { + pr_emerg("gfp: %u\n", flags & GFP_SLAB_BUG_MASK); + BUG(); + } + + return allocate_slab(s, + flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node); +} + static void __free_slab(struct kmem_cache *s, struct page *page) { int order = compound_order(page); -- GitLab From 80da026a8e5da83b6ab029807844587960490e2b Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Fri, 4 Sep 2015 15:45:51 -0700 Subject: [PATCH 6408/7006] mm/slub: fix slab double-free in case of duplicate sysfs filename sysfs_slab_add() shouldn't call kobject_put at error path: this puts last reference of kmem-cache kobject and frees it. Kmem cache will be freed second time at error path in kmem_cache_create(). For example this happens when slub debug was enabled in runtime and somebody creates new kmem cache: # echo 1 | tee /sys/kernel/slab/*/sanity_checks # modprobe configfs "configfs_dir_cache" cannot be merged because existing slab have debug and cannot create new slab because unique name ":t-0000096" already taken. Signed-off-by: Konstantin Khlebnikov Acked-by: Christoph Lameter Cc: Pekka Enberg Acked-by: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/mm/slub.c b/mm/slub.c index 3efcdc02082c6..7e9e508263fb2 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -5283,7 +5283,7 @@ static int sysfs_slab_add(struct kmem_cache *s) s->kobj.kset = cache_kset(s); err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, "%s", name); if (err) - goto out_put_kobj; + goto out; err = sysfs_create_group(&s->kobj, &slab_attr_group); if (err) @@ -5310,8 +5310,6 @@ out: return err; out_del_kobj: kobject_del(&s->kobj); -out_put_kobj: - kobject_put(&s->kobj); goto out; } -- GitLab From 45eb00cd3a034b8448f52fd9074e9b2b11d857c1 Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Fri, 4 Sep 2015 15:45:54 -0700 Subject: [PATCH 6409/7006] mm/slub: don't wait for high-order page allocation Description is almost copied from commit fb05e7a89f50 ("net: don't wait for order-3 page allocation"). I saw excessive direct memory reclaim/compaction triggered by slub. This causes performance issues and add latency. Slub uses high-order allocation to reduce internal fragmentation and management overhead. But, direct memory reclaim/compaction has high overhead and the benefit of high-order allocation can't compensate the overhead of both work. This patch makes auxiliary high-order allocation atomic. If there is no memory pressure and memory isn't fragmented, the alloction will still success, so we don't sacrifice high-order allocation's benefit here. If the atomic allocation fails, direct memory reclaim/compaction will not be triggered, allocation fallback to low-order immediately, hence the direct memory reclaim/compaction overhead is avoided. In the allocation failure case, kswapd is waken up and trying to make high-order freepages, so allocation could success next time. Following is the test to measure effect of this patch. System: QEMU, CPU 8, 512 MB Mem: 25% memory is allocated at random position to make fragmentation. Memory-hogger occupies 150 MB memory. Workload: hackbench -g 20 -l 1000 Average result by 10 runs (Base va Patched) elapsed_time(s): 4.3468 vs 2.9838 compact_stall: 461.7 vs 73.6 pgmigrate_success: 28315.9 vs 7256.1 Signed-off-by: Joonsoo Kim Cc: Christoph Lameter Cc: Pekka Enberg Acked-by: David Rientjes Cc: Shaohua Li Cc: Vlastimil Babka Cc: Michal Hocko Cc: Eric Dumazet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slub.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/slub.c b/mm/slub.c index 7e9e508263fb2..084184e706c63 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1362,6 +1362,8 @@ static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) * so we fall-back to the minimum order allocation. */ alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL; + if ((alloc_gfp & __GFP_WAIT) && oo_order(oo) > oo_order(s->min)) + alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~__GFP_WAIT; page = alloc_slab_page(s, alloc_gfp, node, oo); if (unlikely(!page)) { -- GitLab From 2d16e0fd3265b42648d267b7adb837db9798edaf Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Fri, 4 Sep 2015 15:45:57 -0700 Subject: [PATCH 6410/7006] mm/slab.h: fix argument order in cache_from_obj's error message While debugging a networking issue, I hit a condition that triggered an object to be freed into the wrong kmem cache, and thus triggered the warning in cache_from_obj(). The arguments in the error message are in wrong order: the location of the object's kmem cache is in cachep, not s. Signed-off-by: Daniel Borkmann Cc: Christoph Lameter Cc: Pekka Enberg Cc: David Rientjes Cc: Joonsoo Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/slab.h b/mm/slab.h index 88b55497738cb..a3a967d7d7c27 100644 --- a/mm/slab.h +++ b/mm/slab.h @@ -330,7 +330,7 @@ static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) return cachep; pr_err("%s: Wrong slab cache. %s but object is from %s\n", - __func__, cachep->name, s->name); + __func__, s->name, cachep->name); WARN_ON_ONCE(1); return s; } -- GitLab From 25edd8bffd0f7563f0c04c1d219eb89061ce9886 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:00 -0700 Subject: [PATCH 6411/7006] userfaultfd: linux/Documentation/vm/userfaultfd.txt This is the latest userfaultfd patchset. The postcopy live migration feature on the qemu side is mostly ready to be merged and it entirely depends on the userfaultfd syscall to be merged as well. So it'd be great if this patchset could be reviewed for merging in -mm. Userfaults allow to implement on demand paging from userland and more generally they allow userland to more efficiently take control of the behavior of page faults than what was available before (PROT_NONE + SIGSEGV trap). The use cases are: 1) KVM postcopy live migration (one form of cloud memory externalization). KVM postcopy live migration is the primary driver of this work: http://blog.zhaw.ch/icclab/setting-up-post-copy-live-migration-in-openstack/ http://lists.gnu.org/archive/html/qemu-devel/2015-02/msg04873.html 2) postcopy live migration of binaries inside linux containers: http://thread.gmane.org/gmane.linux.kernel.mm/132662 3) KVM postcopy live snapshotting (allowing to limit/throttle the memory usage, unlike fork would, plus the avoidance of fork overhead in the first place). While the wrprotect tracking is not implemented yet, the syscall API is already contemplating the wrprotect fault tracking and it's generic enough to allow its later implementation in a backwards compatible fashion. 4) KVM userfaults on shared memory. The UFFDIO_COPY lowlevel method should be extended to work also on tmpfs and then the uffdio_register.ioctls will notify userland that UFFDIO_COPY is available even when the registered virtual memory range is tmpfs backed. 5) alternate mechanism to notify web browsers or apps on embedded devices that volatile pages have been reclaimed. This basically avoids the need to run a syscall before the app can access with the CPU the virtual regions marked volatile. This depends on point 4) to be fulfilled first, as volatile pages happily apply to tmpfs. Even though there wasn't a real use case requesting it yet, it also allows to implement distributed shared memory in a way that readonly shared mappings can exist simultaneously in different hosts and they can be become exclusive at the first wrprotect fault. This patch (of 22): Add documentation. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/userfaultfd.txt | 142 +++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 Documentation/vm/userfaultfd.txt diff --git a/Documentation/vm/userfaultfd.txt b/Documentation/vm/userfaultfd.txt new file mode 100644 index 0000000000000..90912925425e4 --- /dev/null +++ b/Documentation/vm/userfaultfd.txt @@ -0,0 +1,142 @@ += Userfaultfd = + +== Objective == + +Userfaults allow the implementation of on-demand paging from userland +and more generally they allow userland to take control of various +memory page faults, something otherwise only the kernel code could do. + +For example userfaults allows a proper and more optimal implementation +of the PROT_NONE+SIGSEGV trick. + +== Design == + +Userfaults are delivered and resolved through the userfaultfd syscall. + +The userfaultfd (aside from registering and unregistering virtual +memory ranges) provides two primary functionalities: + +1) read/POLLIN protocol to notify a userland thread of the faults + happening + +2) various UFFDIO_* ioctls that can manage the virtual memory regions + registered in the userfaultfd that allows userland to efficiently + resolve the userfaults it receives via 1) or to manage the virtual + memory in the background + +The real advantage of userfaults if compared to regular virtual memory +management of mremap/mprotect is that the userfaults in all their +operations never involve heavyweight structures like vmas (in fact the +userfaultfd runtime load never takes the mmap_sem for writing). + +Vmas are not suitable for page- (or hugepage) granular fault tracking +when dealing with virtual address spaces that could span +Terabytes. Too many vmas would be needed for that. + +The userfaultfd once opened by invoking the syscall, can also be +passed using unix domain sockets to a manager process, so the same +manager process could handle the userfaults of a multitude of +different processes without them being aware about what is going on +(well of course unless they later try to use the userfaultfd +themselves on the same region the manager is already tracking, which +is a corner case that would currently return -EBUSY). + +== API == + +When first opened the userfaultfd must be enabled invoking the +UFFDIO_API ioctl specifying a uffdio_api.api value set to UFFD_API (or +a later API version) which will specify the read/POLLIN protocol +userland intends to speak on the UFFD. The UFFDIO_API ioctl if +successful (i.e. if the requested uffdio_api.api is spoken also by the +running kernel), will return into uffdio_api.features and +uffdio_api.ioctls two 64bit bitmasks of respectively the activated +feature of the read(2) protocol and the generic ioctl available. + +Once the userfaultfd has been enabled the UFFDIO_REGISTER ioctl should +be invoked (if present in the returned uffdio_api.ioctls bitmask) to +register a memory range in the userfaultfd by setting the +uffdio_register structure accordingly. The uffdio_register.mode +bitmask will specify to the kernel which kind of faults to track for +the range (UFFDIO_REGISTER_MODE_MISSING would track missing +pages). The UFFDIO_REGISTER ioctl will return the +uffdio_register.ioctls bitmask of ioctls that are suitable to resolve +userfaults on the range registered. Not all ioctls will necessarily be +supported for all memory types depending on the underlying virtual +memory backend (anonymous memory vs tmpfs vs real filebacked +mappings). + +Userland can use the uffdio_register.ioctls to manage the virtual +address space in the background (to add or potentially also remove +memory from the userfaultfd registered range). This means a userfault +could be triggering just before userland maps in the background the +user-faulted page. + +The primary ioctl to resolve userfaults is UFFDIO_COPY. That +atomically copies a page into the userfault registered range and wakes +up the blocked userfaults (unless uffdio_copy.mode & +UFFDIO_COPY_MODE_DONTWAKE is set). Other ioctl works similarly to +UFFDIO_COPY. They're atomic as in guaranteeing that nothing can see an +half copied page since it'll keep userfaulting until the copy has +finished. + +== QEMU/KVM == + +QEMU/KVM is using the userfaultfd syscall to implement postcopy live +migration. Postcopy live migration is one form of memory +externalization consisting of a virtual machine running with part or +all of its memory residing on a different node in the cloud. The +userfaultfd abstraction is generic enough that not a single line of +KVM kernel code had to be modified in order to add postcopy live +migration to QEMU. + +Guest async page faults, FOLL_NOWAIT and all other GUP features work +just fine in combination with userfaults. Userfaults trigger async +page faults in the guest scheduler so those guest processes that +aren't waiting for userfaults (i.e. network bound) can keep running in +the guest vcpus. + +It is generally beneficial to run one pass of precopy live migration +just before starting postcopy live migration, in order to avoid +generating userfaults for readonly guest regions. + +The implementation of postcopy live migration currently uses one +single bidirectional socket but in the future two different sockets +will be used (to reduce the latency of the userfaults to the minimum +possible without having to decrease /proc/sys/net/ipv4/tcp_wmem). + +The QEMU in the source node writes all pages that it knows are missing +in the destination node, into the socket, and the migration thread of +the QEMU running in the destination node runs UFFDIO_COPY|ZEROPAGE +ioctls on the userfaultfd in order to map the received pages into the +guest (UFFDIO_ZEROCOPY is used if the source page was a zero page). + +A different postcopy thread in the destination node listens with +poll() to the userfaultfd in parallel. When a POLLIN event is +generated after a userfault triggers, the postcopy thread read() from +the userfaultfd and receives the fault address (or -EAGAIN in case the +userfault was already resolved and waken by a UFFDIO_COPY|ZEROPAGE run +by the parallel QEMU migration thread). + +After the QEMU postcopy thread (running in the destination node) gets +the userfault address it writes the information about the missing page +into the socket. The QEMU source node receives the information and +roughly "seeks" to that page address and continues sending all +remaining missing pages from that new page offset. Soon after that +(just the time to flush the tcp_wmem queue through the network) the +migration thread in the QEMU running in the destination node will +receive the page that triggered the userfault and it'll map it as +usual with the UFFDIO_COPY|ZEROPAGE (without actually knowing if it +was spontaneously sent by the source or if it was an urgent page +requested through an userfault). + +By the time the userfaults start, the QEMU in the destination node +doesn't need to keep any per-page state bitmap relative to the live +migration around and a single per-page bitmap has to be maintained in +the QEMU running in the source node to know which pages are still +missing in the destination node. The bitmap in the source node is +checked to find which missing pages to send in round robin and we seek +over it when receiving incoming userfaults. After sending each page of +course the bitmap is updated accordingly. It's also useful to avoid +sending the same page twice (in case the userfault is read by the +postcopy thread just before UFFDIO_COPY|ZEROPAGE runs in the migration +thread). -- GitLab From 51360155eccb907ff8635bd10fc7de876408c2e0 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:04 -0700 Subject: [PATCH 6412/7006] userfaultfd: waitqueue: add nr wake parameter to __wake_up_locked_key userfaultfd needs to wake all waitqueues (pass 0 as nr parameter), instead of the current hardcoded 1 (that would wake just the first waitqueue in the head list). Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/wait.h | 5 +++-- kernel/sched/wait.c | 7 ++++--- net/sunrpc/sched.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/linux/wait.h b/include/linux/wait.h index 1e1bf9f963a94..d3d077228d4c1 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -147,7 +147,8 @@ __remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) typedef int wait_bit_action_f(struct wait_bit_key *); void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key); -void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key); +void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, int nr, + void *key); void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr, void *key); void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr); void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr); @@ -179,7 +180,7 @@ wait_queue_head_t *bit_waitqueue(void *, int); #define wake_up_poll(x, m) \ __wake_up(x, TASK_NORMAL, 1, (void *) (m)) #define wake_up_locked_poll(x, m) \ - __wake_up_locked_key((x), TASK_NORMAL, (void *) (m)) + __wake_up_locked_key((x), TASK_NORMAL, 1, (void *) (m)) #define wake_up_interruptible_poll(x, m) \ __wake_up(x, TASK_INTERRUPTIBLE, 1, (void *) (m)) #define wake_up_interruptible_sync_poll(x, m) \ diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c index 052e02672d124..272d9322bc5df 100644 --- a/kernel/sched/wait.c +++ b/kernel/sched/wait.c @@ -106,9 +106,10 @@ void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr) } EXPORT_SYMBOL_GPL(__wake_up_locked); -void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key) +void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, int nr, + void *key) { - __wake_up_common(q, mode, 1, 0, key); + __wake_up_common(q, mode, nr, 0, key); } EXPORT_SYMBOL_GPL(__wake_up_locked_key); @@ -283,7 +284,7 @@ void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, if (!list_empty(&wait->task_list)) list_del_init(&wait->task_list); else if (waitqueue_active(q)) - __wake_up_locked_key(q, mode, key); + __wake_up_locked_key(q, mode, 1, key); spin_unlock_irqrestore(&q->lock, flags); } EXPORT_SYMBOL(abort_exclusive_wait); diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 337ca851a350c..b140c092d226e 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c @@ -297,7 +297,7 @@ static int rpc_complete_task(struct rpc_task *task) clear_bit(RPC_TASK_ACTIVE, &task->tk_runstate); ret = atomic_dec_and_test(&task->tk_count); if (waitqueue_active(wq)) - __wake_up_locked_key(wq, TASK_NORMAL, &k); + __wake_up_locked_key(wq, TASK_NORMAL, 1, &k); spin_unlock_irqrestore(&wq->lock, flags); return ret; } -- GitLab From 1038628d80e96e3a086189172d9be8eb85ecfabf Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:04 -0700 Subject: [PATCH 6413/7006] userfaultfd: uAPI Defines the uAPI of the userfaultfd, notably the ioctl numbers and protocol. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/ioctl/ioctl-number.txt | 1 + include/uapi/linux/Kbuild | 1 + include/uapi/linux/userfaultfd.h | 83 ++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+) create mode 100644 include/uapi/linux/userfaultfd.h diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt index 64df08db46577..39ac6546d4a42 100644 --- a/Documentation/ioctl/ioctl-number.txt +++ b/Documentation/ioctl/ioctl-number.txt @@ -303,6 +303,7 @@ Code Seq#(hex) Include File Comments 0xA3 80-8F Port ACL in development: 0xA3 90-9F linux/dtlk.h +0xAA 00-3F linux/uapi/linux/userfaultfd.h 0xAB 00-1F linux/nbd.h 0xAC 00-1F linux/raw.h 0xAD 00 Netfilter device in development: diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index aafb9937b162b..70ff1d9abf0dd 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -456,3 +456,4 @@ header-y += xfrm.h header-y += xilinx-v4l2-controls.h header-y += zorro.h header-y += zorro_ids.h +header-y += userfaultfd.h diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h new file mode 100644 index 0000000000000..09c2e2a8c9d65 --- /dev/null +++ b/include/uapi/linux/userfaultfd.h @@ -0,0 +1,83 @@ +/* + * include/linux/userfaultfd.h + * + * Copyright (C) 2007 Davide Libenzi + * Copyright (C) 2015 Red Hat, Inc. + * + */ + +#ifndef _LINUX_USERFAULTFD_H +#define _LINUX_USERFAULTFD_H + +#include + +#define UFFD_API ((__u64)0xAA) +/* FIXME: add "|UFFD_BIT_WP" to UFFD_API_BITS after implementing it */ +#define UFFD_API_BITS (UFFD_BIT_WRITE) +#define UFFD_API_IOCTLS \ + ((__u64)1 << _UFFDIO_REGISTER | \ + (__u64)1 << _UFFDIO_UNREGISTER | \ + (__u64)1 << _UFFDIO_API) +#define UFFD_API_RANGE_IOCTLS \ + ((__u64)1 << _UFFDIO_WAKE) + +/* + * Valid ioctl command number range with this API is from 0x00 to + * 0x3F. UFFDIO_API is the fixed number, everything else can be + * changed by implementing a different UFFD_API. If sticking to the + * same UFFD_API more ioctl can be added and userland will be aware of + * which ioctl the running kernel implements through the ioctl command + * bitmask written by the UFFDIO_API. + */ +#define _UFFDIO_REGISTER (0x00) +#define _UFFDIO_UNREGISTER (0x01) +#define _UFFDIO_WAKE (0x02) +#define _UFFDIO_API (0x3F) + +/* userfaultfd ioctl ids */ +#define UFFDIO 0xAA +#define UFFDIO_API _IOWR(UFFDIO, _UFFDIO_API, \ + struct uffdio_api) +#define UFFDIO_REGISTER _IOWR(UFFDIO, _UFFDIO_REGISTER, \ + struct uffdio_register) +#define UFFDIO_UNREGISTER _IOR(UFFDIO, _UFFDIO_UNREGISTER, \ + struct uffdio_range) +#define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ + struct uffdio_range) + +/* + * Valid bits below PAGE_SHIFT in the userfault address read through + * the read() syscall. + */ +#define UFFD_BIT_WRITE (1<<0) /* this was a write fault, MISSING or WP */ +#define UFFD_BIT_WP (1<<1) /* handle_userfault() reason VM_UFFD_WP */ +#define UFFD_BITS 2 /* two above bits used for UFFD_BIT_* mask */ + +struct uffdio_api { + /* userland asks for an API number */ + __u64 api; + + /* kernel answers below with the available features for the API */ + __u64 bits; + __u64 ioctls; +}; + +struct uffdio_range { + __u64 start; + __u64 len; +}; + +struct uffdio_register { + struct uffdio_range range; +#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0) +#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1) + __u64 mode; + + /* + * kernel answers which ioctl commands are available for the + * range, keep at the end as the last 8 bytes aren't read. + */ + __u64 ioctls; +}; + +#endif /* _LINUX_USERFAULTFD_H */ -- GitLab From 932b18e0aec65acb089f4bd8761ee85e70f8eb6a Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:10 -0700 Subject: [PATCH 6414/7006] userfaultfd: linux/userfaultfd_k.h Kernel header defining the methods needed by the VM common code to interact with the userfaultfd. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/userfaultfd_k.h | 79 +++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 include/linux/userfaultfd_k.h diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h new file mode 100644 index 0000000000000..e1e43609a179a --- /dev/null +++ b/include/linux/userfaultfd_k.h @@ -0,0 +1,79 @@ +/* + * include/linux/userfaultfd_k.h + * + * Copyright (C) 2015 Red Hat, Inc. + * + */ + +#ifndef _LINUX_USERFAULTFD_K_H +#define _LINUX_USERFAULTFD_K_H + +#ifdef CONFIG_USERFAULTFD + +#include /* linux/include/uapi/linux/userfaultfd.h */ + +#include + +/* + * CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining + * new flags, since they might collide with O_* ones. We want + * to re-use O_* flags that couldn't possibly have a meaning + * from userfaultfd, in order to leave a free define-space for + * shared O_* flags. + */ +#define UFFD_CLOEXEC O_CLOEXEC +#define UFFD_NONBLOCK O_NONBLOCK + +#define UFFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK) +#define UFFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS) + +extern int handle_userfault(struct vm_area_struct *vma, unsigned long address, + unsigned int flags, unsigned long reason); + +/* mm helpers */ +static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma, + struct vm_userfaultfd_ctx vm_ctx) +{ + return vma->vm_userfaultfd_ctx.ctx == vm_ctx.ctx; +} + +static inline bool userfaultfd_missing(struct vm_area_struct *vma) +{ + return vma->vm_flags & VM_UFFD_MISSING; +} + +static inline bool userfaultfd_armed(struct vm_area_struct *vma) +{ + return vma->vm_flags & (VM_UFFD_MISSING | VM_UFFD_WP); +} + +#else /* CONFIG_USERFAULTFD */ + +/* mm helpers */ +static inline int handle_userfault(struct vm_area_struct *vma, + unsigned long address, + unsigned int flags, + unsigned long reason) +{ + return VM_FAULT_SIGBUS; +} + +static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma, + struct vm_userfaultfd_ctx vm_ctx) +{ + return true; +} + +static inline bool userfaultfd_missing(struct vm_area_struct *vma) +{ + return false; +} + +static inline bool userfaultfd_armed(struct vm_area_struct *vma) +{ + return false; +} + +#endif /* CONFIG_USERFAULTFD */ + +#endif /* _LINUX_USERFAULTFD_K_H */ -- GitLab From 745f234be12b6191b15eae8dd415cc81a9137f47 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:14 -0700 Subject: [PATCH 6415/7006] userfaultfd: add vm_userfaultfd_ctx to the vm_area_struct This adds the vm_userfaultfd_ctx to the vm_area_struct. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm_types.h | 11 +++++++++++ kernel/fork.c | 1 + 2 files changed, 12 insertions(+) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 15549578d5599..26a30c3566f0c 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -256,6 +256,16 @@ struct vm_region { * this region */ }; +#ifdef CONFIG_USERFAULTFD +#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) { NULL, }) +struct vm_userfaultfd_ctx { + struct userfaultfd_ctx *ctx; +}; +#else /* CONFIG_USERFAULTFD */ +#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) {}) +struct vm_userfaultfd_ctx {}; +#endif /* CONFIG_USERFAULTFD */ + /* * This struct defines a memory VMM memory area. There is one of these * per VM-area/task. A VM area is any part of the process virtual memory @@ -322,6 +332,7 @@ struct vm_area_struct { #ifdef CONFIG_NUMA struct mempolicy *vm_policy; /* NUMA policy for the VMA */ #endif + struct vm_userfaultfd_ctx vm_userfaultfd_ctx; }; struct core_thread { diff --git a/kernel/fork.c b/kernel/fork.c index 03aa2e6de7a4e..ceb4eb4abb9df 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -456,6 +456,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) goto fail_nomem_anon_vma_fork; tmp->vm_flags &= ~VM_LOCKED; tmp->vm_next = tmp->vm_prev = NULL; + tmp->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; file = tmp->vm_file; if (file) { struct inode *inode = file_inode(file); -- GitLab From 16ba6f811dfe44bc14f7946a4b257b85476fc16e Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:17 -0700 Subject: [PATCH 6416/7006] userfaultfd: add VM_UFFD_MISSING and VM_UFFD_WP These two flags gets set in vma->vm_flags to tell the VM common code if the userfaultfd is armed and in which mode (only tracking missing faults, only tracking wrprotect faults or both). If neither flags is set it means the userfaultfd is not armed on the vma. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 2 ++ include/linux/mm.h | 2 ++ kernel/fork.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index ca1e091881d44..3b4d8255e8068 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -597,6 +597,8 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma) [ilog2(VM_HUGEPAGE)] = "hg", [ilog2(VM_NOHUGEPAGE)] = "nh", [ilog2(VM_MERGEABLE)] = "mg", + [ilog2(VM_UFFD_MISSING)]= "um", + [ilog2(VM_UFFD_WP)] = "uw", }; size_t i; diff --git a/include/linux/mm.h b/include/linux/mm.h index bf6f117fcf4d8..0f7cd30039ead 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -124,8 +124,10 @@ extern unsigned int kobjsize(const void *objp); #define VM_MAYSHARE 0x00000080 #define VM_GROWSDOWN 0x00000100 /* general info on the segment */ +#define VM_UFFD_MISSING 0x00000200 /* missing pages tracking */ #define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ #define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ +#define VM_UFFD_WP 0x00001000 /* wrprotect pages tracking */ #define VM_LOCKED 0x00002000 #define VM_IO 0x00004000 /* Memory mapped I/O or similar */ diff --git a/kernel/fork.c b/kernel/fork.c index ceb4eb4abb9df..7d5f0f118a634 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -454,7 +454,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) tmp->vm_mm = mm; if (anon_vma_fork(tmp, mpnt)) goto fail_nomem_anon_vma_fork; - tmp->vm_flags &= ~VM_LOCKED; + tmp->vm_flags &= ~(VM_LOCKED|VM_UFFD_MISSING|VM_UFFD_WP); tmp->vm_next = tmp->vm_prev = NULL; tmp->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; file = tmp->vm_file; -- GitLab From 6b251fc96cf2cdf1ce4b5db055547e2a5679bc77 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:20 -0700 Subject: [PATCH 6417/7006] userfaultfd: call handle_userfault() for userfaultfd_missing() faults This is where the page faults must be modified to call handle_userfault() if userfaultfd_missing() is true (so if the vma->vm_flags had VM_UFFD_MISSING set). handle_userfault() then takes care of blocking the page fault and delivering it to userland. The fault flags must also be passed as parameter so the "read|write" kind of fault can be passed to userland. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 69 +++++++++++++++++++++++++++++++++--------------- mm/memory.c | 16 +++++++++++ 2 files changed, 63 insertions(+), 22 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 097c7a4bfbd9f..7735f99931fa1 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -717,7 +718,8 @@ static inline pmd_t mk_huge_pmd(struct page *page, pgprot_t prot) static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd, - struct page *page, gfp_t gfp) + struct page *page, gfp_t gfp, + unsigned int flags) { struct mem_cgroup *memcg; pgtable_t pgtable; @@ -725,12 +727,16 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, VM_BUG_ON_PAGE(!PageCompound(page), page); - if (mem_cgroup_try_charge(page, mm, gfp, &memcg)) - return VM_FAULT_OOM; + if (mem_cgroup_try_charge(page, mm, gfp, &memcg)) { + put_page(page); + count_vm_event(THP_FAULT_FALLBACK); + return VM_FAULT_FALLBACK; + } pgtable = pte_alloc_one(mm, haddr); if (unlikely(!pgtable)) { mem_cgroup_cancel_charge(page, memcg); + put_page(page); return VM_FAULT_OOM; } @@ -750,6 +756,21 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, pte_free(mm, pgtable); } else { pmd_t entry; + + /* Deliver the page fault to userland */ + if (userfaultfd_missing(vma)) { + int ret; + + spin_unlock(ptl); + mem_cgroup_cancel_charge(page, memcg); + put_page(page); + pte_free(mm, pgtable); + ret = handle_userfault(vma, haddr, flags, + VM_UFFD_MISSING); + VM_BUG_ON(ret & VM_FAULT_FALLBACK); + return ret; + } + entry = mk_huge_pmd(page, vma->vm_page_prot); entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma); page_add_new_anon_rmap(page, vma, haddr); @@ -760,6 +781,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, add_mm_counter(mm, MM_ANONPAGES, HPAGE_PMD_NR); atomic_long_inc(&mm->nr_ptes); spin_unlock(ptl); + count_vm_event(THP_FAULT_ALLOC); } return 0; @@ -771,19 +793,16 @@ static inline gfp_t alloc_hugepage_gfpmask(int defrag, gfp_t extra_gfp) } /* Caller must hold page table lock. */ -static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, +static void set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd, struct page *zero_page) { pmd_t entry; - if (!pmd_none(*pmd)) - return false; entry = mk_pmd(zero_page, vma->vm_page_prot); entry = pmd_mkhuge(entry); pgtable_trans_huge_deposit(mm, pmd, pgtable); set_pmd_at(mm, haddr, pmd, entry); atomic_long_inc(&mm->nr_ptes); - return true; } int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, @@ -806,6 +825,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, pgtable_t pgtable; struct page *zero_page; bool set; + int ret; pgtable = pte_alloc_one(mm, haddr); if (unlikely(!pgtable)) return VM_FAULT_OOM; @@ -816,14 +836,28 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, return VM_FAULT_FALLBACK; } ptl = pmd_lock(mm, pmd); - set = set_huge_zero_page(pgtable, mm, vma, haddr, pmd, - zero_page); - spin_unlock(ptl); + ret = 0; + set = false; + if (pmd_none(*pmd)) { + if (userfaultfd_missing(vma)) { + spin_unlock(ptl); + ret = handle_userfault(vma, haddr, flags, + VM_UFFD_MISSING); + VM_BUG_ON(ret & VM_FAULT_FALLBACK); + } else { + set_huge_zero_page(pgtable, mm, vma, + haddr, pmd, + zero_page); + spin_unlock(ptl); + set = true; + } + } else + spin_unlock(ptl); if (!set) { pte_free(mm, pgtable); put_huge_zero_page(); } - return 0; + return ret; } gfp = alloc_hugepage_gfpmask(transparent_hugepage_defrag(vma), 0); page = alloc_hugepage_vma(gfp, vma, haddr, HPAGE_PMD_ORDER); @@ -831,14 +865,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, count_vm_event(THP_FAULT_FALLBACK); return VM_FAULT_FALLBACK; } - if (unlikely(__do_huge_pmd_anonymous_page(mm, vma, haddr, pmd, page, gfp))) { - put_page(page); - count_vm_event(THP_FAULT_FALLBACK); - return VM_FAULT_FALLBACK; - } - - count_vm_event(THP_FAULT_ALLOC); - return 0; + return __do_huge_pmd_anonymous_page(mm, vma, haddr, pmd, page, gfp, flags); } int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, @@ -873,16 +900,14 @@ int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, */ if (is_huge_zero_pmd(pmd)) { struct page *zero_page; - bool set; /* * get_huge_zero_page() will never allocate a new page here, * since we already have a zero page to copy. It just takes a * reference. */ zero_page = get_huge_zero_page(); - set = set_huge_zero_page(pgtable, dst_mm, vma, addr, dst_pmd, + set_huge_zero_page(pgtable, dst_mm, vma, addr, dst_pmd, zero_page); - BUG_ON(!set); /* unexpected !pmd_none(dst_pmd) */ ret = 0; goto out_unlock; } diff --git a/mm/memory.c b/mm/memory.c index 388dcf9aa283c..2961fb654369e 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -2685,6 +2686,12 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, page_table = pte_offset_map_lock(mm, pmd, address, &ptl); if (!pte_none(*page_table)) goto unlock; + /* Deliver the page fault to userland, check inside PT lock */ + if (userfaultfd_missing(vma)) { + pte_unmap_unlock(page_table, ptl); + return handle_userfault(vma, address, flags, + VM_UFFD_MISSING); + } goto setpte; } @@ -2713,6 +2720,15 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, if (!pte_none(*page_table)) goto release; + /* Deliver the page fault to userland, check inside PT lock */ + if (userfaultfd_missing(vma)) { + pte_unmap_unlock(page_table, ptl); + mem_cgroup_cancel_charge(page, memcg); + page_cache_release(page); + return handle_userfault(vma, address, flags, + VM_UFFD_MISSING); + } + inc_mm_counter_fast(mm, MM_ANONPAGES); page_add_new_anon_rmap(page, vma, address); mem_cgroup_commit_charge(page, memcg, false); -- GitLab From 19a809afe2fe089317226bbe5c5a1ce7f53dcdca Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:24 -0700 Subject: [PATCH 6418/7006] userfaultfd: teach vma_merge to merge across vma->vm_userfaultfd_ctx vma->vm_userfaultfd_ctx is yet another vma parameter that vma_merge must be aware about so that we can merge vmas back like they were originally before arming the userfaultfd on some memory range. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 +- mm/madvise.c | 3 ++- mm/mempolicy.c | 4 ++-- mm/mlock.c | 3 ++- mm/mmap.c | 40 +++++++++++++++++++++++++++------------- mm/mprotect.c | 3 ++- 6 files changed, 36 insertions(+), 19 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 0f7cd30039ead..77a9d609523e8 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1835,7 +1835,7 @@ extern int vma_adjust(struct vm_area_struct *vma, unsigned long start, extern struct vm_area_struct *vma_merge(struct mm_struct *, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t, - struct mempolicy *); + struct mempolicy *, struct vm_userfaultfd_ctx); extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *); extern int split_vma(struct mm_struct *, struct vm_area_struct *, unsigned long addr, int new_below); diff --git a/mm/madvise.c b/mm/madvise.c index 64bb8a22110c2..9113579739059 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -103,7 +103,8 @@ static long madvise_behavior(struct vm_area_struct *vma, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, new_flags, vma->anon_vma, - vma->vm_file, pgoff, vma_policy(vma)); + vma->vm_file, pgoff, vma_policy(vma), + vma->vm_userfaultfd_ctx); if (*prev) { vma = *prev; goto success; diff --git a/mm/mempolicy.c b/mm/mempolicy.c index 99d4c1d0b8583..a7f1e0d1d6b8f 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -722,8 +722,8 @@ static int mbind_range(struct mm_struct *mm, unsigned long start, pgoff = vma->vm_pgoff + ((vmstart - vma->vm_start) >> PAGE_SHIFT); prev = vma_merge(mm, prev, vmstart, vmend, vma->vm_flags, - vma->anon_vma, vma->vm_file, pgoff, - new_pol); + vma->anon_vma, vma->vm_file, pgoff, + new_pol, vma->vm_userfaultfd_ctx); if (prev) { vma = prev; next = vma->vm_next; diff --git a/mm/mlock.c b/mm/mlock.c index 6fd2cf15e8687..25936680064fd 100644 --- a/mm/mlock.c +++ b/mm/mlock.c @@ -510,7 +510,8 @@ static int mlock_fixup(struct vm_area_struct *vma, struct vm_area_struct **prev, pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *prev = vma_merge(mm, *prev, start, end, newflags, vma->anon_vma, - vma->vm_file, pgoff, vma_policy(vma)); + vma->vm_file, pgoff, vma_policy(vma), + vma->vm_userfaultfd_ctx); if (*prev) { vma = *prev; goto success; diff --git a/mm/mmap.c b/mm/mmap.c index f126923ce683c..82db4fc0a9d34 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -41,6 +41,7 @@ #include #include #include +#include #include #include @@ -919,7 +920,8 @@ again: remove_next = 1 + (end > next->vm_end); * per-vma resources, so we don't attempt to merge those. */ static inline int is_mergeable_vma(struct vm_area_struct *vma, - struct file *file, unsigned long vm_flags) + struct file *file, unsigned long vm_flags, + struct vm_userfaultfd_ctx vm_userfaultfd_ctx) { /* * VM_SOFTDIRTY should not prevent from VMA merging, if we @@ -935,6 +937,8 @@ static inline int is_mergeable_vma(struct vm_area_struct *vma, return 0; if (vma->vm_ops && vma->vm_ops->close) return 0; + if (!is_mergeable_vm_userfaultfd_ctx(vma, vm_userfaultfd_ctx)) + return 0; return 1; } @@ -965,9 +969,11 @@ static inline int is_mergeable_anon_vma(struct anon_vma *anon_vma1, */ static int can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, - struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) + struct anon_vma *anon_vma, struct file *file, + pgoff_t vm_pgoff, + struct vm_userfaultfd_ctx vm_userfaultfd_ctx) { - if (is_mergeable_vma(vma, file, vm_flags) && + if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { if (vma->vm_pgoff == vm_pgoff) return 1; @@ -984,9 +990,11 @@ can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, */ static int can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, - struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) + struct anon_vma *anon_vma, struct file *file, + pgoff_t vm_pgoff, + struct vm_userfaultfd_ctx vm_userfaultfd_ctx) { - if (is_mergeable_vma(vma, file, vm_flags) && + if (is_mergeable_vma(vma, file, vm_flags, vm_userfaultfd_ctx) && is_mergeable_anon_vma(anon_vma, vma->anon_vma, vma)) { pgoff_t vm_pglen; vm_pglen = vma_pages(vma); @@ -1029,7 +1037,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, - pgoff_t pgoff, struct mempolicy *policy) + pgoff_t pgoff, struct mempolicy *policy, + struct vm_userfaultfd_ctx vm_userfaultfd_ctx) { pgoff_t pglen = (end - addr) >> PAGE_SHIFT; struct vm_area_struct *area, *next; @@ -1056,14 +1065,17 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, if (prev && prev->vm_end == addr && mpol_equal(vma_policy(prev), policy) && can_vma_merge_after(prev, vm_flags, - anon_vma, file, pgoff)) { + anon_vma, file, pgoff, + vm_userfaultfd_ctx)) { /* * OK, it can. Can we now merge in the successor as well? */ if (next && end == next->vm_start && mpol_equal(policy, vma_policy(next)) && can_vma_merge_before(next, vm_flags, - anon_vma, file, pgoff+pglen) && + anon_vma, file, + pgoff+pglen, + vm_userfaultfd_ctx) && is_mergeable_anon_vma(prev->anon_vma, next->anon_vma, NULL)) { /* cases 1, 6 */ @@ -1084,7 +1096,8 @@ struct vm_area_struct *vma_merge(struct mm_struct *mm, if (next && end == next->vm_start && mpol_equal(policy, vma_policy(next)) && can_vma_merge_before(next, vm_flags, - anon_vma, file, pgoff+pglen)) { + anon_vma, file, pgoff+pglen, + vm_userfaultfd_ctx)) { if (prev && addr < prev->vm_end) /* case 4 */ err = vma_adjust(prev, prev->vm_start, addr, prev->vm_pgoff, NULL); @@ -1570,8 +1583,8 @@ unsigned long mmap_region(struct file *file, unsigned long addr, /* * Can we just expand an old mapping? */ - vma = vma_merge(mm, prev, addr, addr + len, vm_flags, NULL, file, pgoff, - NULL); + vma = vma_merge(mm, prev, addr, addr + len, vm_flags, + NULL, file, pgoff, NULL, NULL_VM_UFFD_CTX); if (vma) goto out; @@ -2757,7 +2770,7 @@ static unsigned long do_brk(unsigned long addr, unsigned long len) /* Can we just expand an old private anonymous mapping? */ vma = vma_merge(mm, prev, addr, addr + len, flags, - NULL, NULL, pgoff, NULL); + NULL, NULL, pgoff, NULL, NULL_VM_UFFD_CTX); if (vma) goto out; @@ -2913,7 +2926,8 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, if (find_vma_links(mm, addr, addr + len, &prev, &rb_link, &rb_parent)) return NULL; /* should never get here */ new_vma = vma_merge(mm, prev, addr, addr + len, vma->vm_flags, - vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma)); + vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), + vma->vm_userfaultfd_ctx); if (new_vma) { /* * Source vma may have been merged into new_vma diff --git a/mm/mprotect.c b/mm/mprotect.c index e7d6f1171ecb6..ef5be8eaab001 100644 --- a/mm/mprotect.c +++ b/mm/mprotect.c @@ -292,7 +292,8 @@ mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, */ pgoff = vma->vm_pgoff + ((start - vma->vm_start) >> PAGE_SHIFT); *pprev = vma_merge(mm, *pprev, start, end, newflags, - vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma)); + vma->anon_vma, vma->vm_file, pgoff, vma_policy(vma), + vma->vm_userfaultfd_ctx); if (*pprev) { vma = *pprev; goto success; -- GitLab From c1294d05de5df1ab8c93aa13c531782ede907e14 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:27 -0700 Subject: [PATCH 6419/7006] userfaultfd: prevent khugepaged to merge if userfaultfd is armed If userfaultfd is armed on a certain vma we can't "fill" the holes with zeroes or we'll break the userland on demand paging. The holes if the userfault is armed, are really missing information (not zeroes) that the userland has to load from network or elsewhere. The same issue happens for wrprotected ptes that we can't just convert into a single writable pmd_trans_huge. We could however in theory still merge across zeropages if only VM_UFFD_MISSING is set (so if VM_UFFD_WP is not set)... that could be slightly improved but it'd be much more complex code for a tiny corner case. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 7735f99931fa1..d38aaf9dcba60 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2158,7 +2158,8 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma, _pte++, address += PAGE_SIZE) { pte_t pteval = *_pte; if (pte_none(pteval) || is_zero_pfn(pte_pfn(pteval))) { - if (++none_or_zero <= khugepaged_max_ptes_none) + if (!userfaultfd_armed(vma) && + ++none_or_zero <= khugepaged_max_ptes_none) continue; else goto out; @@ -2611,7 +2612,8 @@ static int khugepaged_scan_pmd(struct mm_struct *mm, _pte++, _address += PAGE_SIZE) { pte_t pteval = *_pte; if (pte_none(pteval) || is_zero_pfn(pte_pfn(pteval))) { - if (++none_or_zero <= khugepaged_max_ptes_none) + if (!userfaultfd_armed(vma) && + ++none_or_zero <= khugepaged_max_ptes_none) continue; else goto out_unmap; -- GitLab From 86039bd3b4e6a1129318cbfed4e0a6e001656635 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:31 -0700 Subject: [PATCH 6420/7006] userfaultfd: add new syscall to provide memory externalization Once an userfaultfd has been created and certain region of the process virtual address space have been registered into it, the thread responsible for doing the memory externalization can manage the page faults in userland by talking to the kernel using the userfaultfd protocol. poll() can be used to know when there are new pending userfaults to be read (POLLIN). Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Cc: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 1036 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1036 insertions(+) create mode 100644 fs/userfaultfd.c diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c new file mode 100644 index 0000000000000..9bc256d1a143b --- /dev/null +++ b/fs/userfaultfd.c @@ -0,0 +1,1036 @@ +/* + * fs/userfaultfd.c + * + * Copyright (C) 2007 Davide Libenzi + * Copyright (C) 2008-2009 Red Hat, Inc. + * Copyright (C) 2015 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * Some part derived from fs/eventfd.c (anon inode setup) and + * mm/ksm.c (mm hashing). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum userfaultfd_state { + UFFD_STATE_WAIT_API, + UFFD_STATE_RUNNING, +}; + +struct userfaultfd_ctx { + /* pseudo fd refcounting */ + atomic_t refcount; + /* waitqueue head for the userfaultfd page faults */ + wait_queue_head_t fault_wqh; + /* waitqueue head for the pseudo fd to wakeup poll/read */ + wait_queue_head_t fd_wqh; + /* userfaultfd syscall flags */ + unsigned int flags; + /* state machine */ + enum userfaultfd_state state; + /* released */ + bool released; + /* mm with one ore more vmas attached to this userfaultfd_ctx */ + struct mm_struct *mm; +}; + +struct userfaultfd_wait_queue { + unsigned long address; + wait_queue_t wq; + bool pending; + struct userfaultfd_ctx *ctx; +}; + +struct userfaultfd_wake_range { + unsigned long start; + unsigned long len; +}; + +static int userfaultfd_wake_function(wait_queue_t *wq, unsigned mode, + int wake_flags, void *key) +{ + struct userfaultfd_wake_range *range = key; + int ret; + struct userfaultfd_wait_queue *uwq; + unsigned long start, len; + + uwq = container_of(wq, struct userfaultfd_wait_queue, wq); + ret = 0; + /* don't wake the pending ones to avoid reads to block */ + if (uwq->pending && !ACCESS_ONCE(uwq->ctx->released)) + goto out; + /* len == 0 means wake all */ + start = range->start; + len = range->len; + if (len && (start > uwq->address || start + len <= uwq->address)) + goto out; + ret = wake_up_state(wq->private, mode); + if (ret) + /* + * Wake only once, autoremove behavior. + * + * After the effect of list_del_init is visible to the + * other CPUs, the waitqueue may disappear from under + * us, see the !list_empty_careful() in + * handle_userfault(). try_to_wake_up() has an + * implicit smp_mb__before_spinlock, and the + * wq->private is read before calling the extern + * function "wake_up_state" (which in turns calls + * try_to_wake_up). While the spin_lock;spin_unlock; + * wouldn't be enough, the smp_mb__before_spinlock is + * enough to avoid an explicit smp_mb() here. + */ + list_del_init(&wq->task_list); +out: + return ret; +} + +/** + * userfaultfd_ctx_get - Acquires a reference to the internal userfaultfd + * context. + * @ctx: [in] Pointer to the userfaultfd context. + * + * Returns: In case of success, returns not zero. + */ +static void userfaultfd_ctx_get(struct userfaultfd_ctx *ctx) +{ + if (!atomic_inc_not_zero(&ctx->refcount)) + BUG(); +} + +/** + * userfaultfd_ctx_put - Releases a reference to the internal userfaultfd + * context. + * @ctx: [in] Pointer to userfaultfd context. + * + * The userfaultfd context reference must have been previously acquired either + * with userfaultfd_ctx_get() or userfaultfd_ctx_fdget(). + */ +static void userfaultfd_ctx_put(struct userfaultfd_ctx *ctx) +{ + if (atomic_dec_and_test(&ctx->refcount)) { + VM_BUG_ON(spin_is_locked(&ctx->fault_pending_wqh.lock)); + VM_BUG_ON(waitqueue_active(&ctx->fault_pending_wqh)); + VM_BUG_ON(spin_is_locked(&ctx->fault_wqh.lock)); + VM_BUG_ON(waitqueue_active(&ctx->fault_wqh)); + VM_BUG_ON(spin_is_locked(&ctx->fd_wqh.lock)); + VM_BUG_ON(waitqueue_active(&ctx->fd_wqh)); + mmput(ctx->mm); + kfree(ctx); + } +} + +static inline unsigned long userfault_address(unsigned long address, + unsigned int flags, + unsigned long reason) +{ + BUILD_BUG_ON(PAGE_SHIFT < UFFD_BITS); + address &= PAGE_MASK; + if (flags & FAULT_FLAG_WRITE) + /* + * Encode "write" fault information in the LSB of the + * address read by userland, without depending on + * FAULT_FLAG_WRITE kernel internal value. + */ + address |= UFFD_BIT_WRITE; + if (reason & VM_UFFD_WP) + /* + * Encode "reason" fault information as bit number 1 + * in the address read by userland. If bit number 1 is + * clear it means the reason is a VM_FAULT_MISSING + * fault. + */ + address |= UFFD_BIT_WP; + return address; +} + +/* + * The locking rules involved in returning VM_FAULT_RETRY depending on + * FAULT_FLAG_ALLOW_RETRY, FAULT_FLAG_RETRY_NOWAIT and + * FAULT_FLAG_KILLABLE are not straightforward. The "Caution" + * recommendation in __lock_page_or_retry is not an understatement. + * + * If FAULT_FLAG_ALLOW_RETRY is set, the mmap_sem must be released + * before returning VM_FAULT_RETRY only if FAULT_FLAG_RETRY_NOWAIT is + * not set. + * + * If FAULT_FLAG_ALLOW_RETRY is set but FAULT_FLAG_KILLABLE is not + * set, VM_FAULT_RETRY can still be returned if and only if there are + * fatal_signal_pending()s, and the mmap_sem must be released before + * returning it. + */ +int handle_userfault(struct vm_area_struct *vma, unsigned long address, + unsigned int flags, unsigned long reason) +{ + struct mm_struct *mm = vma->vm_mm; + struct userfaultfd_ctx *ctx; + struct userfaultfd_wait_queue uwq; + + BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); + + ctx = vma->vm_userfaultfd_ctx.ctx; + if (!ctx) + return VM_FAULT_SIGBUS; + + BUG_ON(ctx->mm != mm); + + VM_BUG_ON(reason & ~(VM_UFFD_MISSING|VM_UFFD_WP)); + VM_BUG_ON(!(reason & VM_UFFD_MISSING) ^ !!(reason & VM_UFFD_WP)); + + /* + * If it's already released don't get it. This avoids to loop + * in __get_user_pages if userfaultfd_release waits on the + * caller of handle_userfault to release the mmap_sem. + */ + if (unlikely(ACCESS_ONCE(ctx->released))) + return VM_FAULT_SIGBUS; + + /* + * Check that we can return VM_FAULT_RETRY. + * + * NOTE: it should become possible to return VM_FAULT_RETRY + * even if FAULT_FLAG_TRIED is set without leading to gup() + * -EBUSY failures, if the userfaultfd is to be extended for + * VM_UFFD_WP tracking and we intend to arm the userfault + * without first stopping userland access to the memory. For + * VM_UFFD_MISSING userfaults this is enough for now. + */ + if (unlikely(!(flags & FAULT_FLAG_ALLOW_RETRY))) { + /* + * Validate the invariant that nowait must allow retry + * to be sure not to return SIGBUS erroneously on + * nowait invocations. + */ + BUG_ON(flags & FAULT_FLAG_RETRY_NOWAIT); +#ifdef CONFIG_DEBUG_VM + if (printk_ratelimit()) { + printk(KERN_WARNING + "FAULT_FLAG_ALLOW_RETRY missing %x\n", flags); + dump_stack(); + } +#endif + return VM_FAULT_SIGBUS; + } + + /* + * Handle nowait, not much to do other than tell it to retry + * and wait. + */ + if (flags & FAULT_FLAG_RETRY_NOWAIT) + return VM_FAULT_RETRY; + + /* take the reference before dropping the mmap_sem */ + userfaultfd_ctx_get(ctx); + + /* be gentle and immediately relinquish the mmap_sem */ + up_read(&mm->mmap_sem); + + init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function); + uwq.wq.private = current; + uwq.address = userfault_address(address, flags, reason); + uwq.pending = true; + uwq.ctx = ctx; + + spin_lock(&ctx->fault_wqh.lock); + /* + * After the __add_wait_queue the uwq is visible to userland + * through poll/read(). + */ + __add_wait_queue(&ctx->fault_wqh, &uwq.wq); + for (;;) { + set_current_state(TASK_KILLABLE); + if (!uwq.pending || ACCESS_ONCE(ctx->released) || + fatal_signal_pending(current)) + break; + spin_unlock(&ctx->fault_wqh.lock); + + wake_up_poll(&ctx->fd_wqh, POLLIN); + schedule(); + + spin_lock(&ctx->fault_wqh.lock); + } + __remove_wait_queue(&ctx->fault_wqh, &uwq.wq); + __set_current_state(TASK_RUNNING); + spin_unlock(&ctx->fault_wqh.lock); + + /* + * ctx may go away after this if the userfault pseudo fd is + * already released. + */ + userfaultfd_ctx_put(ctx); + + return VM_FAULT_RETRY; +} + +static int userfaultfd_release(struct inode *inode, struct file *file) +{ + struct userfaultfd_ctx *ctx = file->private_data; + struct mm_struct *mm = ctx->mm; + struct vm_area_struct *vma, *prev; + /* len == 0 means wake all */ + struct userfaultfd_wake_range range = { .len = 0, }; + unsigned long new_flags; + + ACCESS_ONCE(ctx->released) = true; + + /* + * Flush page faults out of all CPUs. NOTE: all page faults + * must be retried without returning VM_FAULT_SIGBUS if + * userfaultfd_ctx_get() succeeds but vma->vma_userfault_ctx + * changes while handle_userfault released the mmap_sem. So + * it's critical that released is set to true (above), before + * taking the mmap_sem for writing. + */ + down_write(&mm->mmap_sem); + prev = NULL; + for (vma = mm->mmap; vma; vma = vma->vm_next) { + cond_resched(); + BUG_ON(!!vma->vm_userfaultfd_ctx.ctx ^ + !!(vma->vm_flags & (VM_UFFD_MISSING | VM_UFFD_WP))); + if (vma->vm_userfaultfd_ctx.ctx != ctx) { + prev = vma; + continue; + } + new_flags = vma->vm_flags & ~(VM_UFFD_MISSING | VM_UFFD_WP); + prev = vma_merge(mm, prev, vma->vm_start, vma->vm_end, + new_flags, vma->anon_vma, + vma->vm_file, vma->vm_pgoff, + vma_policy(vma), + NULL_VM_UFFD_CTX); + if (prev) + vma = prev; + else + prev = vma; + vma->vm_flags = new_flags; + vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; + } + up_write(&mm->mmap_sem); + + /* + * After no new page faults can wait on this fault_wqh, flush + * the last page faults that may have been already waiting on + * the fault_wqh. + */ + spin_lock(&ctx->fault_wqh.lock); + __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, 0, &range); + spin_unlock(&ctx->fault_wqh.lock); + + wake_up_poll(&ctx->fd_wqh, POLLHUP); + userfaultfd_ctx_put(ctx); + return 0; +} + +/* fault_wqh.lock must be hold by the caller */ +static inline unsigned int find_userfault(struct userfaultfd_ctx *ctx, + struct userfaultfd_wait_queue **uwq) +{ + wait_queue_t *wq; + struct userfaultfd_wait_queue *_uwq; + unsigned int ret = 0; + + VM_BUG_ON(!spin_is_locked(&ctx->fault_wqh.lock)); + + list_for_each_entry(wq, &ctx->fault_wqh.task_list, task_list) { + _uwq = container_of(wq, struct userfaultfd_wait_queue, wq); + if (_uwq->pending) { + ret = POLLIN; + if (!uwq) + /* + * If there's at least a pending and + * we don't care which one it is, + * break immediately and leverage the + * efficiency of the LIFO walk. + */ + break; + /* + * If we need to find which one was pending we + * keep walking until we find the first not + * pending one, so we read() them in FIFO order. + */ + *uwq = _uwq; + } else + /* + * break the loop at the first not pending + * one, there cannot be pending userfaults + * after the first not pending one, because + * all new pending ones are inserted at the + * head and we walk it in LIFO. + */ + break; + } + + return ret; +} + +static unsigned int userfaultfd_poll(struct file *file, poll_table *wait) +{ + struct userfaultfd_ctx *ctx = file->private_data; + unsigned int ret; + + poll_wait(file, &ctx->fd_wqh, wait); + + switch (ctx->state) { + case UFFD_STATE_WAIT_API: + return POLLERR; + case UFFD_STATE_RUNNING: + spin_lock(&ctx->fault_wqh.lock); + ret = find_userfault(ctx, NULL); + spin_unlock(&ctx->fault_wqh.lock); + return ret; + default: + BUG(); + } +} + +static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, + __u64 *addr) +{ + ssize_t ret; + DECLARE_WAITQUEUE(wait, current); + struct userfaultfd_wait_queue *uwq = NULL; + + /* always take the fd_wqh lock before the fault_wqh lock */ + spin_lock(&ctx->fd_wqh.lock); + __add_wait_queue(&ctx->fd_wqh, &wait); + for (;;) { + set_current_state(TASK_INTERRUPTIBLE); + spin_lock(&ctx->fault_wqh.lock); + if (find_userfault(ctx, &uwq)) { + /* + * The fault_wqh.lock prevents the uwq to + * disappear from under us. + */ + uwq->pending = false; + /* careful to always initialize addr if ret == 0 */ + *addr = uwq->address; + spin_unlock(&ctx->fault_wqh.lock); + ret = 0; + break; + } + spin_unlock(&ctx->fault_wqh.lock); + if (signal_pending(current)) { + ret = -ERESTARTSYS; + break; + } + if (no_wait) { + ret = -EAGAIN; + break; + } + spin_unlock(&ctx->fd_wqh.lock); + schedule(); + spin_lock(&ctx->fd_wqh.lock); + } + __remove_wait_queue(&ctx->fd_wqh, &wait); + __set_current_state(TASK_RUNNING); + spin_unlock(&ctx->fd_wqh.lock); + + return ret; +} + +static ssize_t userfaultfd_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct userfaultfd_ctx *ctx = file->private_data; + ssize_t _ret, ret = 0; + /* careful to always initialize addr if ret == 0 */ + __u64 uninitialized_var(addr); + int no_wait = file->f_flags & O_NONBLOCK; + + if (ctx->state == UFFD_STATE_WAIT_API) + return -EINVAL; + BUG_ON(ctx->state != UFFD_STATE_RUNNING); + + for (;;) { + if (count < sizeof(addr)) + return ret ? ret : -EINVAL; + _ret = userfaultfd_ctx_read(ctx, no_wait, &addr); + if (_ret < 0) + return ret ? ret : _ret; + if (put_user(addr, (__u64 __user *) buf)) + return ret ? ret : -EFAULT; + ret += sizeof(addr); + buf += sizeof(addr); + count -= sizeof(addr); + /* + * Allow to read more than one fault at time but only + * block if waiting for the very first one. + */ + no_wait = O_NONBLOCK; + } +} + +static void __wake_userfault(struct userfaultfd_ctx *ctx, + struct userfaultfd_wake_range *range) +{ + unsigned long start, end; + + start = range->start; + end = range->start + range->len; + + spin_lock(&ctx->fault_wqh.lock); + /* wake all in the range and autoremove */ + __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, 0, range); + spin_unlock(&ctx->fault_wqh.lock); +} + +static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx, + struct userfaultfd_wake_range *range) +{ + /* + * To be sure waitqueue_active() is not reordered by the CPU + * before the pagetable update, use an explicit SMP memory + * barrier here. PT lock release or up_read(mmap_sem) still + * have release semantics that can allow the + * waitqueue_active() to be reordered before the pte update. + */ + smp_mb(); + + /* + * Use waitqueue_active because it's very frequent to + * change the address space atomically even if there are no + * userfaults yet. So we take the spinlock only when we're + * sure we've userfaults to wake. + */ + if (waitqueue_active(&ctx->fault_wqh)) + __wake_userfault(ctx, range); +} + +static __always_inline int validate_range(struct mm_struct *mm, + __u64 start, __u64 len) +{ + __u64 task_size = mm->task_size; + + if (start & ~PAGE_MASK) + return -EINVAL; + if (len & ~PAGE_MASK) + return -EINVAL; + if (!len) + return -EINVAL; + if (start < mmap_min_addr) + return -EINVAL; + if (start >= task_size) + return -EINVAL; + if (len > task_size - start) + return -EINVAL; + return 0; +} + +static int userfaultfd_register(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + struct mm_struct *mm = ctx->mm; + struct vm_area_struct *vma, *prev, *cur; + int ret; + struct uffdio_register uffdio_register; + struct uffdio_register __user *user_uffdio_register; + unsigned long vm_flags, new_flags; + bool found; + unsigned long start, end, vma_end; + + user_uffdio_register = (struct uffdio_register __user *) arg; + + ret = -EFAULT; + if (copy_from_user(&uffdio_register, user_uffdio_register, + sizeof(uffdio_register)-sizeof(__u64))) + goto out; + + ret = -EINVAL; + if (!uffdio_register.mode) + goto out; + if (uffdio_register.mode & ~(UFFDIO_REGISTER_MODE_MISSING| + UFFDIO_REGISTER_MODE_WP)) + goto out; + vm_flags = 0; + if (uffdio_register.mode & UFFDIO_REGISTER_MODE_MISSING) + vm_flags |= VM_UFFD_MISSING; + if (uffdio_register.mode & UFFDIO_REGISTER_MODE_WP) { + vm_flags |= VM_UFFD_WP; + /* + * FIXME: remove the below error constraint by + * implementing the wprotect tracking mode. + */ + ret = -EINVAL; + goto out; + } + + ret = validate_range(mm, uffdio_register.range.start, + uffdio_register.range.len); + if (ret) + goto out; + + start = uffdio_register.range.start; + end = start + uffdio_register.range.len; + + down_write(&mm->mmap_sem); + vma = find_vma_prev(mm, start, &prev); + + ret = -ENOMEM; + if (!vma) + goto out_unlock; + + /* check that there's at least one vma in the range */ + ret = -EINVAL; + if (vma->vm_start >= end) + goto out_unlock; + + /* + * Search for not compatible vmas. + * + * FIXME: this shall be relaxed later so that it doesn't fail + * on tmpfs backed vmas (in addition to the current allowance + * on anonymous vmas). + */ + found = false; + for (cur = vma; cur && cur->vm_start < end; cur = cur->vm_next) { + cond_resched(); + + BUG_ON(!!cur->vm_userfaultfd_ctx.ctx ^ + !!(cur->vm_flags & (VM_UFFD_MISSING | VM_UFFD_WP))); + + /* check not compatible vmas */ + ret = -EINVAL; + if (cur->vm_ops) + goto out_unlock; + + /* + * Check that this vma isn't already owned by a + * different userfaultfd. We can't allow more than one + * userfaultfd to own a single vma simultaneously or we + * wouldn't know which one to deliver the userfaults to. + */ + ret = -EBUSY; + if (cur->vm_userfaultfd_ctx.ctx && + cur->vm_userfaultfd_ctx.ctx != ctx) + goto out_unlock; + + found = true; + } + BUG_ON(!found); + + if (vma->vm_start < start) + prev = vma; + + ret = 0; + do { + cond_resched(); + + BUG_ON(vma->vm_ops); + BUG_ON(vma->vm_userfaultfd_ctx.ctx && + vma->vm_userfaultfd_ctx.ctx != ctx); + + /* + * Nothing to do: this vma is already registered into this + * userfaultfd and with the right tracking mode too. + */ + if (vma->vm_userfaultfd_ctx.ctx == ctx && + (vma->vm_flags & vm_flags) == vm_flags) + goto skip; + + if (vma->vm_start > start) + start = vma->vm_start; + vma_end = min(end, vma->vm_end); + + new_flags = (vma->vm_flags & ~vm_flags) | vm_flags; + prev = vma_merge(mm, prev, start, vma_end, new_flags, + vma->anon_vma, vma->vm_file, vma->vm_pgoff, + vma_policy(vma), + ((struct vm_userfaultfd_ctx){ ctx })); + if (prev) { + vma = prev; + goto next; + } + if (vma->vm_start < start) { + ret = split_vma(mm, vma, start, 1); + if (ret) + break; + } + if (vma->vm_end > end) { + ret = split_vma(mm, vma, end, 0); + if (ret) + break; + } + next: + /* + * In the vma_merge() successful mprotect-like case 8: + * the next vma was merged into the current one and + * the current one has not been updated yet. + */ + vma->vm_flags = new_flags; + vma->vm_userfaultfd_ctx.ctx = ctx; + + skip: + prev = vma; + start = vma->vm_end; + vma = vma->vm_next; + } while (vma && vma->vm_start < end); +out_unlock: + up_write(&mm->mmap_sem); + if (!ret) { + /* + * Now that we scanned all vmas we can already tell + * userland which ioctls methods are guaranteed to + * succeed on this range. + */ + if (put_user(UFFD_API_RANGE_IOCTLS, + &user_uffdio_register->ioctls)) + ret = -EFAULT; + } +out: + return ret; +} + +static int userfaultfd_unregister(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + struct mm_struct *mm = ctx->mm; + struct vm_area_struct *vma, *prev, *cur; + int ret; + struct uffdio_range uffdio_unregister; + unsigned long new_flags; + bool found; + unsigned long start, end, vma_end; + const void __user *buf = (void __user *)arg; + + ret = -EFAULT; + if (copy_from_user(&uffdio_unregister, buf, sizeof(uffdio_unregister))) + goto out; + + ret = validate_range(mm, uffdio_unregister.start, + uffdio_unregister.len); + if (ret) + goto out; + + start = uffdio_unregister.start; + end = start + uffdio_unregister.len; + + down_write(&mm->mmap_sem); + vma = find_vma_prev(mm, start, &prev); + + ret = -ENOMEM; + if (!vma) + goto out_unlock; + + /* check that there's at least one vma in the range */ + ret = -EINVAL; + if (vma->vm_start >= end) + goto out_unlock; + + /* + * Search for not compatible vmas. + * + * FIXME: this shall be relaxed later so that it doesn't fail + * on tmpfs backed vmas (in addition to the current allowance + * on anonymous vmas). + */ + found = false; + ret = -EINVAL; + for (cur = vma; cur && cur->vm_start < end; cur = cur->vm_next) { + cond_resched(); + + BUG_ON(!!cur->vm_userfaultfd_ctx.ctx ^ + !!(cur->vm_flags & (VM_UFFD_MISSING | VM_UFFD_WP))); + + /* + * Check not compatible vmas, not strictly required + * here as not compatible vmas cannot have an + * userfaultfd_ctx registered on them, but this + * provides for more strict behavior to notice + * unregistration errors. + */ + if (cur->vm_ops) + goto out_unlock; + + found = true; + } + BUG_ON(!found); + + if (vma->vm_start < start) + prev = vma; + + ret = 0; + do { + cond_resched(); + + BUG_ON(vma->vm_ops); + + /* + * Nothing to do: this vma is already registered into this + * userfaultfd and with the right tracking mode too. + */ + if (!vma->vm_userfaultfd_ctx.ctx) + goto skip; + + if (vma->vm_start > start) + start = vma->vm_start; + vma_end = min(end, vma->vm_end); + + new_flags = vma->vm_flags & ~(VM_UFFD_MISSING | VM_UFFD_WP); + prev = vma_merge(mm, prev, start, vma_end, new_flags, + vma->anon_vma, vma->vm_file, vma->vm_pgoff, + vma_policy(vma), + NULL_VM_UFFD_CTX); + if (prev) { + vma = prev; + goto next; + } + if (vma->vm_start < start) { + ret = split_vma(mm, vma, start, 1); + if (ret) + break; + } + if (vma->vm_end > end) { + ret = split_vma(mm, vma, end, 0); + if (ret) + break; + } + next: + /* + * In the vma_merge() successful mprotect-like case 8: + * the next vma was merged into the current one and + * the current one has not been updated yet. + */ + vma->vm_flags = new_flags; + vma->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; + + skip: + prev = vma; + start = vma->vm_end; + vma = vma->vm_next; + } while (vma && vma->vm_start < end); +out_unlock: + up_write(&mm->mmap_sem); +out: + return ret; +} + +/* + * This is mostly needed to re-wakeup those userfaults that were still + * pending when userland wake them up the first time. We don't wake + * the pending one to avoid blocking reads to block, or non blocking + * read to return -EAGAIN, if used with POLLIN, to avoid userland + * doubts on why POLLIN wasn't reliable. + */ +static int userfaultfd_wake(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + int ret; + struct uffdio_range uffdio_wake; + struct userfaultfd_wake_range range; + const void __user *buf = (void __user *)arg; + + ret = -EFAULT; + if (copy_from_user(&uffdio_wake, buf, sizeof(uffdio_wake))) + goto out; + + ret = validate_range(ctx->mm, uffdio_wake.start, uffdio_wake.len); + if (ret) + goto out; + + range.start = uffdio_wake.start; + range.len = uffdio_wake.len; + + /* + * len == 0 means wake all and we don't want to wake all here, + * so check it again to be sure. + */ + VM_BUG_ON(!range.len); + + wake_userfault(ctx, &range); + ret = 0; + +out: + return ret; +} + +/* + * userland asks for a certain API version and we return which bits + * and ioctl commands are implemented in this kernel for such API + * version or -EINVAL if unknown. + */ +static int userfaultfd_api(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + struct uffdio_api uffdio_api; + void __user *buf = (void __user *)arg; + int ret; + + ret = -EINVAL; + if (ctx->state != UFFD_STATE_WAIT_API) + goto out; + ret = -EFAULT; + if (copy_from_user(&uffdio_api, buf, sizeof(__u64))) + goto out; + if (uffdio_api.api != UFFD_API) { + /* careful not to leak info, we only read the first 8 bytes */ + memset(&uffdio_api, 0, sizeof(uffdio_api)); + if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api))) + goto out; + ret = -EINVAL; + goto out; + } + /* careful not to leak info, we only read the first 8 bytes */ + uffdio_api.bits = UFFD_API_BITS; + uffdio_api.ioctls = UFFD_API_IOCTLS; + ret = -EFAULT; + if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api))) + goto out; + ctx->state = UFFD_STATE_RUNNING; + ret = 0; +out: + return ret; +} + +static long userfaultfd_ioctl(struct file *file, unsigned cmd, + unsigned long arg) +{ + int ret = -EINVAL; + struct userfaultfd_ctx *ctx = file->private_data; + + switch(cmd) { + case UFFDIO_API: + ret = userfaultfd_api(ctx, arg); + break; + case UFFDIO_REGISTER: + ret = userfaultfd_register(ctx, arg); + break; + case UFFDIO_UNREGISTER: + ret = userfaultfd_unregister(ctx, arg); + break; + case UFFDIO_WAKE: + ret = userfaultfd_wake(ctx, arg); + break; + } + return ret; +} + +#ifdef CONFIG_PROC_FS +static void userfaultfd_show_fdinfo(struct seq_file *m, struct file *f) +{ + struct userfaultfd_ctx *ctx = f->private_data; + wait_queue_t *wq; + struct userfaultfd_wait_queue *uwq; + unsigned long pending = 0, total = 0; + + spin_lock(&ctx->fault_wqh.lock); + list_for_each_entry(wq, &ctx->fault_wqh.task_list, task_list) { + uwq = container_of(wq, struct userfaultfd_wait_queue, wq); + if (uwq->pending) + pending++; + total++; + } + spin_unlock(&ctx->fault_wqh.lock); + + /* + * If more protocols will be added, there will be all shown + * separated by a space. Like this: + * protocols: aa:... bb:... + */ + seq_printf(m, "pending:\t%lu\ntotal:\t%lu\nAPI:\t%Lx:%x:%Lx\n", + pending, total, UFFD_API, UFFD_API_BITS, + UFFD_API_IOCTLS|UFFD_API_RANGE_IOCTLS); +} +#endif + +static const struct file_operations userfaultfd_fops = { +#ifdef CONFIG_PROC_FS + .show_fdinfo = userfaultfd_show_fdinfo, +#endif + .release = userfaultfd_release, + .poll = userfaultfd_poll, + .read = userfaultfd_read, + .unlocked_ioctl = userfaultfd_ioctl, + .compat_ioctl = userfaultfd_ioctl, + .llseek = noop_llseek, +}; + +/** + * userfaultfd_file_create - Creates an userfaultfd file pointer. + * @flags: Flags for the userfaultfd file. + * + * This function creates an userfaultfd file pointer, w/out installing + * it into the fd table. This is useful when the userfaultfd file is + * used during the initialization of data structures that require + * extra setup after the userfaultfd creation. So the userfaultfd + * creation is split into the file pointer creation phase, and the + * file descriptor installation phase. In this way races with + * userspace closing the newly installed file descriptor can be + * avoided. Returns an userfaultfd file pointer, or a proper error + * pointer. + */ +static struct file *userfaultfd_file_create(int flags) +{ + struct file *file; + struct userfaultfd_ctx *ctx; + + BUG_ON(!current->mm); + + /* Check the UFFD_* constants for consistency. */ + BUILD_BUG_ON(UFFD_CLOEXEC != O_CLOEXEC); + BUILD_BUG_ON(UFFD_NONBLOCK != O_NONBLOCK); + + file = ERR_PTR(-EINVAL); + if (flags & ~UFFD_SHARED_FCNTL_FLAGS) + goto out; + + file = ERR_PTR(-ENOMEM); + ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + goto out; + + atomic_set(&ctx->refcount, 1); + init_waitqueue_head(&ctx->fault_wqh); + init_waitqueue_head(&ctx->fd_wqh); + ctx->flags = flags; + ctx->state = UFFD_STATE_WAIT_API; + ctx->released = false; + ctx->mm = current->mm; + /* prevent the mm struct to be freed */ + atomic_inc(&ctx->mm->mm_users); + + file = anon_inode_getfile("[userfaultfd]", &userfaultfd_fops, ctx, + O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS)); + if (IS_ERR(file)) + kfree(ctx); +out: + return file; +} + +SYSCALL_DEFINE1(userfaultfd, int, flags) +{ + int fd, error; + struct file *file; + + error = get_unused_fd_flags(flags & UFFD_SHARED_FCNTL_FLAGS); + if (error < 0) + return error; + fd = error; + + file = userfaultfd_file_create(flags); + if (IS_ERR(file)) { + error = PTR_ERR(file); + goto err_put_unused_fd; + } + fd_install(fd, file); + + return fd; + +err_put_unused_fd: + put_unused_fd(fd); + + return error; +} -- GitLab From 3f602d2724b1f7d2d27ddcd7963a040a5890fd16 Mon Sep 17 00:00:00 2001 From: Pavel Emelyanov Date: Fri, 4 Sep 2015 15:46:34 -0700 Subject: [PATCH 6421/7006] userfaultfd: Rename uffd_api.bits into .features This is (seems to be) the minimal thing that is required to unblock standard uffd usage from the non-cooperative one. Now more bits can be added to the features field indicating e.g. UFFD_FEATURE_FORK and others needed for the latter use-case. Signed-off-by: Pavel Emelyanov Signed-off-by: Andrea Arcangeli Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 4 ++-- include/uapi/linux/userfaultfd.h | 12 +++++++++--- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 9bc256d1a143b..0756d97b06669 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -884,7 +884,7 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx, goto out; } /* careful not to leak info, we only read the first 8 bytes */ - uffdio_api.bits = UFFD_API_BITS; + uffdio_api.features = UFFD_API_FEATURES; uffdio_api.ioctls = UFFD_API_IOCTLS; ret = -EFAULT; if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api))) @@ -941,7 +941,7 @@ static void userfaultfd_show_fdinfo(struct seq_file *m, struct file *f) * protocols: aa:... bb:... */ seq_printf(m, "pending:\t%lu\ntotal:\t%lu\nAPI:\t%Lx:%x:%Lx\n", - pending, total, UFFD_API, UFFD_API_BITS, + pending, total, UFFD_API, UFFD_API_FEATURES, UFFD_API_IOCTLS|UFFD_API_RANGE_IOCTLS); } #endif diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h index 09c2e2a8c9d65..330206016249c 100644 --- a/include/uapi/linux/userfaultfd.h +++ b/include/uapi/linux/userfaultfd.h @@ -12,8 +12,8 @@ #include #define UFFD_API ((__u64)0xAA) -/* FIXME: add "|UFFD_BIT_WP" to UFFD_API_BITS after implementing it */ -#define UFFD_API_BITS (UFFD_BIT_WRITE) +/* FIXME: add "|UFFD_FEATURE_WP" to UFFD_API_FEATURES after implementing it */ +#define UFFD_API_FEATURES (UFFD_FEATURE_WRITE_BIT) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -53,12 +53,18 @@ #define UFFD_BIT_WP (1<<1) /* handle_userfault() reason VM_UFFD_WP */ #define UFFD_BITS 2 /* two above bits used for UFFD_BIT_* mask */ +/* + * Features reported in uffdio_api.features field + */ +#define UFFD_FEATURE_WRITE_BIT (1<<0) /* Corresponds to UFFD_BIT_WRITE */ +#define UFFD_FEATURE_WP_BIT (1<<1) /* Corresponds to UFFD_BIT_WP */ + struct uffdio_api { /* userland asks for an API number */ __u64 api; /* kernel answers below with the available features for the API */ - __u64 bits; + __u64 features; __u64 ioctls; }; -- GitLab From a9b85f9415fd9e529d03299e5335433f614ec1fb Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:37 -0700 Subject: [PATCH 6422/7006] userfaultfd: change the read API to return a uffd_msg I had requests to return the full address (not the page aligned one) to userland. It's not entirely clear how the page offset could be relevant because userfaults aren't like SIGBUS that can sigjump to a different place and it actually skip resolving the fault depending on a page offset. There's currently no real way to skip the fault especially because after a UFFDIO_COPY|ZEROPAGE, the fault is optimized to be retried within the kernel without having to return to userland first (not even self modifying code replacing the .text that touched the faulting address would prevent the fault to be repeated). Userland cannot skip repeating the fault even more so if the fault was triggered by a KVM secondary page fault or any get_user_pages or any copy-user inside some syscall which will return to kernel code. The second time FAULT_FLAG_RETRY_NOWAIT won't be set leading to a SIGBUS being raised because the userfault can't wait if it cannot release the mmap_map first (and FAULT_FLAG_RETRY_NOWAIT is required for that). Still returning userland a proper structure during the read() on the uffd, can allow to use the current UFFD_API for the future non-cooperative extensions too and it looks cleaner as well. Once we get additional fields there's no point to return the fault address page aligned anymore to reuse the bits below PAGE_SHIFT. The only downside is that the read() syscall will read 32bytes instead of 8bytes but that's not going to be measurable overhead. The total number of new events that can be extended or of new future bits for already shipped events, is limited to 64 by the features field of the uffdio_api structure. If more will be needed a bump of UFFD_API will be required. [akpm@linux-foundation.org: use __packed] Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/userfaultfd.txt | 12 +++-- fs/userfaultfd.c | 79 +++++++++++++++++++------------- include/uapi/linux/userfaultfd.h | 70 ++++++++++++++++++++++------ 3 files changed, 108 insertions(+), 53 deletions(-) diff --git a/Documentation/vm/userfaultfd.txt b/Documentation/vm/userfaultfd.txt index 90912925425e4..70a3c94d19413 100644 --- a/Documentation/vm/userfaultfd.txt +++ b/Documentation/vm/userfaultfd.txt @@ -46,11 +46,13 @@ is a corner case that would currently return -EBUSY). When first opened the userfaultfd must be enabled invoking the UFFDIO_API ioctl specifying a uffdio_api.api value set to UFFD_API (or a later API version) which will specify the read/POLLIN protocol -userland intends to speak on the UFFD. The UFFDIO_API ioctl if -successful (i.e. if the requested uffdio_api.api is spoken also by the -running kernel), will return into uffdio_api.features and -uffdio_api.ioctls two 64bit bitmasks of respectively the activated -feature of the read(2) protocol and the generic ioctl available. +userland intends to speak on the UFFD and the uffdio_api.features +userland requires. The UFFDIO_API ioctl if successful (i.e. if the +requested uffdio_api.api is spoken also by the running kernel and the +requested features are going to be enabled) will return into +uffdio_api.features and uffdio_api.ioctls two 64bit bitmasks of +respectively all the available features of the read(2) protocol and +the generic ioctl available. Once the userfaultfd has been enabled the UFFDIO_REGISTER ioctl should be invoked (if present in the returned uffdio_api.ioctls bitmask) to diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 0756d97b06669..1f2ddaaf3c03b 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -50,7 +50,7 @@ struct userfaultfd_ctx { }; struct userfaultfd_wait_queue { - unsigned long address; + struct uffd_msg msg; wait_queue_t wq; bool pending; struct userfaultfd_ctx *ctx; @@ -77,7 +77,8 @@ static int userfaultfd_wake_function(wait_queue_t *wq, unsigned mode, /* len == 0 means wake all */ start = range->start; len = range->len; - if (len && (start > uwq->address || start + len <= uwq->address)) + if (len && (start > uwq->msg.arg.pagefault.address || + start + len <= uwq->msg.arg.pagefault.address)) goto out; ret = wake_up_state(wq->private, mode); if (ret) @@ -135,28 +136,43 @@ static void userfaultfd_ctx_put(struct userfaultfd_ctx *ctx) } } -static inline unsigned long userfault_address(unsigned long address, - unsigned int flags, - unsigned long reason) +static inline void msg_init(struct uffd_msg *msg) { - BUILD_BUG_ON(PAGE_SHIFT < UFFD_BITS); - address &= PAGE_MASK; + BUILD_BUG_ON(sizeof(struct uffd_msg) != 32); + /* + * Must use memset to zero out the paddings or kernel data is + * leaked to userland. + */ + memset(msg, 0, sizeof(struct uffd_msg)); +} + +static inline struct uffd_msg userfault_msg(unsigned long address, + unsigned int flags, + unsigned long reason) +{ + struct uffd_msg msg; + msg_init(&msg); + msg.event = UFFD_EVENT_PAGEFAULT; + msg.arg.pagefault.address = address; if (flags & FAULT_FLAG_WRITE) /* - * Encode "write" fault information in the LSB of the - * address read by userland, without depending on - * FAULT_FLAG_WRITE kernel internal value. + * If UFFD_FEATURE_PAGEFAULT_FLAG_WRITE was set in the + * uffdio_api.features and UFFD_PAGEFAULT_FLAG_WRITE + * was not set in a UFFD_EVENT_PAGEFAULT, it means it + * was a read fault, otherwise if set it means it's + * a write fault. */ - address |= UFFD_BIT_WRITE; + msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WRITE; if (reason & VM_UFFD_WP) /* - * Encode "reason" fault information as bit number 1 - * in the address read by userland. If bit number 1 is - * clear it means the reason is a VM_FAULT_MISSING - * fault. + * If UFFD_FEATURE_PAGEFAULT_FLAG_WP was set in the + * uffdio_api.features and UFFD_PAGEFAULT_FLAG_WP was + * not set in a UFFD_EVENT_PAGEFAULT, it means it was + * a missing fault, otherwise if set it means it's a + * write protect fault. */ - address |= UFFD_BIT_WP; - return address; + msg.arg.pagefault.flags |= UFFD_PAGEFAULT_FLAG_WP; + return msg; } /* @@ -242,7 +258,7 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function); uwq.wq.private = current; - uwq.address = userfault_address(address, flags, reason); + uwq.msg = userfault_msg(address, flags, reason); uwq.pending = true; uwq.ctx = ctx; @@ -398,7 +414,7 @@ static unsigned int userfaultfd_poll(struct file *file, poll_table *wait) } static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, - __u64 *addr) + struct uffd_msg *msg) { ssize_t ret; DECLARE_WAITQUEUE(wait, current); @@ -416,8 +432,8 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, * disappear from under us. */ uwq->pending = false; - /* careful to always initialize addr if ret == 0 */ - *addr = uwq->address; + /* careful to always initialize msg if ret == 0 */ + *msg = uwq->msg; spin_unlock(&ctx->fault_wqh.lock); ret = 0; break; @@ -447,8 +463,7 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf, { struct userfaultfd_ctx *ctx = file->private_data; ssize_t _ret, ret = 0; - /* careful to always initialize addr if ret == 0 */ - __u64 uninitialized_var(addr); + struct uffd_msg msg; int no_wait = file->f_flags & O_NONBLOCK; if (ctx->state == UFFD_STATE_WAIT_API) @@ -456,16 +471,16 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf, BUG_ON(ctx->state != UFFD_STATE_RUNNING); for (;;) { - if (count < sizeof(addr)) + if (count < sizeof(msg)) return ret ? ret : -EINVAL; - _ret = userfaultfd_ctx_read(ctx, no_wait, &addr); + _ret = userfaultfd_ctx_read(ctx, no_wait, &msg); if (_ret < 0) return ret ? ret : _ret; - if (put_user(addr, (__u64 __user *) buf)) + if (copy_to_user((__u64 __user *) buf, &msg, sizeof(msg))) return ret ? ret : -EFAULT; - ret += sizeof(addr); - buf += sizeof(addr); - count -= sizeof(addr); + ret += sizeof(msg); + buf += sizeof(msg); + count -= sizeof(msg); /* * Allow to read more than one fault at time but only * block if waiting for the very first one. @@ -873,17 +888,15 @@ static int userfaultfd_api(struct userfaultfd_ctx *ctx, if (ctx->state != UFFD_STATE_WAIT_API) goto out; ret = -EFAULT; - if (copy_from_user(&uffdio_api, buf, sizeof(__u64))) + if (copy_from_user(&uffdio_api, buf, sizeof(uffdio_api))) goto out; - if (uffdio_api.api != UFFD_API) { - /* careful not to leak info, we only read the first 8 bytes */ + if (uffdio_api.api != UFFD_API || uffdio_api.features) { memset(&uffdio_api, 0, sizeof(uffdio_api)); if (copy_to_user(buf, &uffdio_api, sizeof(uffdio_api))) goto out; ret = -EINVAL; goto out; } - /* careful not to leak info, we only read the first 8 bytes */ uffdio_api.features = UFFD_API_FEATURES; uffdio_api.ioctls = UFFD_API_IOCTLS; ret = -EFAULT; diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h index 330206016249c..a5f8825381ef0 100644 --- a/include/uapi/linux/userfaultfd.h +++ b/include/uapi/linux/userfaultfd.h @@ -11,9 +11,15 @@ #include +#include + #define UFFD_API ((__u64)0xAA) -/* FIXME: add "|UFFD_FEATURE_WP" to UFFD_API_FEATURES after implementing it */ -#define UFFD_API_FEATURES (UFFD_FEATURE_WRITE_BIT) +/* + * After implementing the respective features it will become: + * #define UFFD_API_FEATURES (UFFD_FEATURE_PAGEFAULT_FLAG_WP | \ + * UFFD_FEATURE_EVENT_FORK) + */ +#define UFFD_API_FEATURES (0) #define UFFD_API_IOCTLS \ ((__u64)1 << _UFFDIO_REGISTER | \ (__u64)1 << _UFFDIO_UNREGISTER | \ @@ -45,26 +51,60 @@ #define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ struct uffdio_range) -/* - * Valid bits below PAGE_SHIFT in the userfault address read through - * the read() syscall. - */ -#define UFFD_BIT_WRITE (1<<0) /* this was a write fault, MISSING or WP */ -#define UFFD_BIT_WP (1<<1) /* handle_userfault() reason VM_UFFD_WP */ -#define UFFD_BITS 2 /* two above bits used for UFFD_BIT_* mask */ +/* read() structure */ +struct uffd_msg { + __u8 event; + + __u8 reserved1; + __u16 reserved2; + __u32 reserved3; + + union { + struct { + __u64 flags; + __u64 address; + } pagefault; + + struct { + /* unused reserved fields */ + __u64 reserved1; + __u64 reserved2; + __u64 reserved3; + } reserved; + } arg; +} __packed; /* - * Features reported in uffdio_api.features field + * Start at 0x12 and not at 0 to be more strict against bugs. */ -#define UFFD_FEATURE_WRITE_BIT (1<<0) /* Corresponds to UFFD_BIT_WRITE */ -#define UFFD_FEATURE_WP_BIT (1<<1) /* Corresponds to UFFD_BIT_WP */ +#define UFFD_EVENT_PAGEFAULT 0x12 +#if 0 /* not available yet */ +#define UFFD_EVENT_FORK 0x13 +#endif + +/* flags for UFFD_EVENT_PAGEFAULT */ +#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */ struct uffdio_api { - /* userland asks for an API number */ + /* userland asks for an API number and the features to enable */ __u64 api; - - /* kernel answers below with the available features for the API */ + /* + * Kernel answers below with the all available features for + * the API, this notifies userland of which events and/or + * which flags for each event are enabled in the current + * kernel. + * + * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE + * are to be considered implicitly always enabled in all kernels as + * long as the uffdio_api.api requested matches UFFD_API. + */ +#if 0 /* not available yet */ +#define UFFD_FEATURE_PAGEFAULT_FLAG_WP (1<<0) +#define UFFD_FEATURE_EVENT_FORK (1<<1) +#endif __u64 features; + __u64 ioctls; }; -- GitLab From ba85c702e4b247393ffe9e3fbc13d8aee7b02059 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:41 -0700 Subject: [PATCH 6423/7006] userfaultfd: wake pending userfaults This is an optimization but it's a userland visible one and it affects the API. The downside of this optimization is that if you call poll() and you get POLLIN, read(ufd) may still return -EAGAIN. The blocked userfault may be waken by a different thread, before read(ufd) comes around. This in short means that poll() isn't really usable if the userfaultfd is opened in blocking mode. userfaults won't wait in "pending" state to be read anymore and any UFFDIO_WAKE or similar operations that has the objective of waking userfaults after their resolution, will wake all blocked userfaults for the resolved range, including those that haven't been read() by userland yet. The behavior of poll() becomes not standard, but this obviates the need of "spurious" UFFDIO_WAKE and it lets the userland threads to restart immediately without requiring an UFFDIO_WAKE. This is even more significant in case of repeated faults on the same address from multiple threads. This optimization is justified by the measurement that the number of spurious UFFDIO_WAKE accounts for 5% and 10% of the total userfaults for heavy workloads, so it's worth optimizing those away. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 65 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 1f2ddaaf3c03b..0877222dfa475 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -52,6 +52,10 @@ struct userfaultfd_ctx { struct userfaultfd_wait_queue { struct uffd_msg msg; wait_queue_t wq; + /* + * Only relevant when queued in fault_wqh and only used by the + * read operation to avoid reading the same userfault twice. + */ bool pending; struct userfaultfd_ctx *ctx; }; @@ -71,9 +75,6 @@ static int userfaultfd_wake_function(wait_queue_t *wq, unsigned mode, uwq = container_of(wq, struct userfaultfd_wait_queue, wq); ret = 0; - /* don't wake the pending ones to avoid reads to block */ - if (uwq->pending && !ACCESS_ONCE(uwq->ctx->released)) - goto out; /* len == 0 means wake all */ start = range->start; len = range->len; @@ -196,12 +197,14 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, struct mm_struct *mm = vma->vm_mm; struct userfaultfd_ctx *ctx; struct userfaultfd_wait_queue uwq; + int ret; BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); + ret = VM_FAULT_SIGBUS; ctx = vma->vm_userfaultfd_ctx.ctx; if (!ctx) - return VM_FAULT_SIGBUS; + goto out; BUG_ON(ctx->mm != mm); @@ -214,7 +217,7 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, * caller of handle_userfault to release the mmap_sem. */ if (unlikely(ACCESS_ONCE(ctx->released))) - return VM_FAULT_SIGBUS; + goto out; /* * Check that we can return VM_FAULT_RETRY. @@ -240,15 +243,16 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, dump_stack(); } #endif - return VM_FAULT_SIGBUS; + goto out; } /* * Handle nowait, not much to do other than tell it to retry * and wait. */ + ret = VM_FAULT_RETRY; if (flags & FAULT_FLAG_RETRY_NOWAIT) - return VM_FAULT_RETRY; + goto out; /* take the reference before dropping the mmap_sem */ userfaultfd_ctx_get(ctx); @@ -268,21 +272,23 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, * through poll/read(). */ __add_wait_queue(&ctx->fault_wqh, &uwq.wq); - for (;;) { - set_current_state(TASK_KILLABLE); - if (!uwq.pending || ACCESS_ONCE(ctx->released) || - fatal_signal_pending(current)) - break; - spin_unlock(&ctx->fault_wqh.lock); + set_current_state(TASK_KILLABLE); + spin_unlock(&ctx->fault_wqh.lock); + if (likely(!ACCESS_ONCE(ctx->released) && + !fatal_signal_pending(current))) { wake_up_poll(&ctx->fd_wqh, POLLIN); schedule(); + ret |= VM_FAULT_MAJOR; + } + __set_current_state(TASK_RUNNING); + /* see finish_wait() comment for why list_empty_careful() */ + if (!list_empty_careful(&uwq.wq.task_list)) { spin_lock(&ctx->fault_wqh.lock); + list_del_init(&uwq.wq.task_list); + spin_unlock(&ctx->fault_wqh.lock); } - __remove_wait_queue(&ctx->fault_wqh, &uwq.wq); - __set_current_state(TASK_RUNNING); - spin_unlock(&ctx->fault_wqh.lock); /* * ctx may go away after this if the userfault pseudo fd is @@ -290,7 +296,8 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, */ userfaultfd_ctx_put(ctx); - return VM_FAULT_RETRY; +out: + return ret; } static int userfaultfd_release(struct inode *inode, struct file *file) @@ -404,6 +411,12 @@ static unsigned int userfaultfd_poll(struct file *file, poll_table *wait) case UFFD_STATE_WAIT_API: return POLLERR; case UFFD_STATE_RUNNING: + /* + * poll() never guarantees that read won't block. + * userfaults can be waken before they're read(). + */ + if (unlikely(!(file->f_flags & O_NONBLOCK))) + return POLLERR; spin_lock(&ctx->fault_wqh.lock); ret = find_userfault(ctx, NULL); spin_unlock(&ctx->fault_wqh.lock); @@ -834,11 +847,19 @@ out: } /* - * This is mostly needed to re-wakeup those userfaults that were still - * pending when userland wake them up the first time. We don't wake - * the pending one to avoid blocking reads to block, or non blocking - * read to return -EAGAIN, if used with POLLIN, to avoid userland - * doubts on why POLLIN wasn't reliable. + * userfaultfd_wake is needed in case an userfault is in flight by the + * time a UFFDIO_COPY (or other ioctl variants) completes. The page + * may be well get mapped and the page fault if repeated wouldn't lead + * to a userfault anymore, but before scheduling in TASK_KILLABLE mode + * handle_userfault() doesn't recheck the pagetables and it doesn't + * serialize against UFFDO_COPY (or other ioctl variants). Ultimately + * the knowledge of which pages are mapped is left to userland who is + * responsible for handling the race between read() userfaults and + * background UFFDIO_COPY (or other ioctl variants), if done by + * separate concurrent threads. + * + * userfaultfd_wake may be used in combination with the + * UFFDIO_*_MODE_DONTWAKE to wakeup userfaults in batches. */ static int userfaultfd_wake(struct userfaultfd_ctx *ctx, unsigned long arg) -- GitLab From 15b726ef048b31a24b3fefb6863083a25fe34800 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:44 -0700 Subject: [PATCH 6424/7006] userfaultfd: optimize read() and poll() to be O(1) This makes read O(1) and poll that was already O(1) becomes lockless. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 185 ++++++++++++++++++++++++++++------------------- 1 file changed, 111 insertions(+), 74 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 0877222dfa475..232cbf37c59f8 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -35,7 +35,9 @@ enum userfaultfd_state { struct userfaultfd_ctx { /* pseudo fd refcounting */ atomic_t refcount; - /* waitqueue head for the userfaultfd page faults */ + /* waitqueue head for the pending (i.e. not read) userfaults */ + wait_queue_head_t fault_pending_wqh; + /* waitqueue head for the userfaults */ wait_queue_head_t fault_wqh; /* waitqueue head for the pseudo fd to wakeup poll/read */ wait_queue_head_t fd_wqh; @@ -52,11 +54,6 @@ struct userfaultfd_ctx { struct userfaultfd_wait_queue { struct uffd_msg msg; wait_queue_t wq; - /* - * Only relevant when queued in fault_wqh and only used by the - * read operation to avoid reading the same userfault twice. - */ - bool pending; struct userfaultfd_ctx *ctx; }; @@ -263,17 +260,21 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function); uwq.wq.private = current; uwq.msg = userfault_msg(address, flags, reason); - uwq.pending = true; uwq.ctx = ctx; - spin_lock(&ctx->fault_wqh.lock); + spin_lock(&ctx->fault_pending_wqh.lock); /* * After the __add_wait_queue the uwq is visible to userland * through poll/read(). */ - __add_wait_queue(&ctx->fault_wqh, &uwq.wq); + __add_wait_queue(&ctx->fault_pending_wqh, &uwq.wq); + /* + * The smp_mb() after __set_current_state prevents the reads + * following the spin_unlock to happen before the list_add in + * __add_wait_queue. + */ set_current_state(TASK_KILLABLE); - spin_unlock(&ctx->fault_wqh.lock); + spin_unlock(&ctx->fault_pending_wqh.lock); if (likely(!ACCESS_ONCE(ctx->released) && !fatal_signal_pending(current))) { @@ -283,11 +284,28 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, } __set_current_state(TASK_RUNNING); - /* see finish_wait() comment for why list_empty_careful() */ + + /* + * Here we race with the list_del; list_add in + * userfaultfd_ctx_read(), however because we don't ever run + * list_del_init() to refile across the two lists, the prev + * and next pointers will never point to self. list_add also + * would never let any of the two pointers to point to + * self. So list_empty_careful won't risk to see both pointers + * pointing to self at any time during the list refile. The + * only case where list_del_init() is called is the full + * removal in the wake function and there we don't re-list_add + * and it's fine not to block on the spinlock. The uwq on this + * kernel stack can be released after the list_del_init. + */ if (!list_empty_careful(&uwq.wq.task_list)) { - spin_lock(&ctx->fault_wqh.lock); - list_del_init(&uwq.wq.task_list); - spin_unlock(&ctx->fault_wqh.lock); + spin_lock(&ctx->fault_pending_wqh.lock); + /* + * No need of list_del_init(), the uwq on the stack + * will be freed shortly anyway. + */ + list_del(&uwq.wq.task_list); + spin_unlock(&ctx->fault_pending_wqh.lock); } /* @@ -345,59 +363,38 @@ static int userfaultfd_release(struct inode *inode, struct file *file) up_write(&mm->mmap_sem); /* - * After no new page faults can wait on this fault_wqh, flush + * After no new page faults can wait on this fault_*wqh, flush * the last page faults that may have been already waiting on - * the fault_wqh. + * the fault_*wqh. */ - spin_lock(&ctx->fault_wqh.lock); + spin_lock(&ctx->fault_pending_wqh.lock); + __wake_up_locked_key(&ctx->fault_pending_wqh, TASK_NORMAL, 0, &range); __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, 0, &range); - spin_unlock(&ctx->fault_wqh.lock); + spin_unlock(&ctx->fault_pending_wqh.lock); wake_up_poll(&ctx->fd_wqh, POLLHUP); userfaultfd_ctx_put(ctx); return 0; } -/* fault_wqh.lock must be hold by the caller */ -static inline unsigned int find_userfault(struct userfaultfd_ctx *ctx, - struct userfaultfd_wait_queue **uwq) +/* fault_pending_wqh.lock must be hold by the caller */ +static inline struct userfaultfd_wait_queue *find_userfault( + struct userfaultfd_ctx *ctx) { wait_queue_t *wq; - struct userfaultfd_wait_queue *_uwq; - unsigned int ret = 0; - - VM_BUG_ON(!spin_is_locked(&ctx->fault_wqh.lock)); + struct userfaultfd_wait_queue *uwq; - list_for_each_entry(wq, &ctx->fault_wqh.task_list, task_list) { - _uwq = container_of(wq, struct userfaultfd_wait_queue, wq); - if (_uwq->pending) { - ret = POLLIN; - if (!uwq) - /* - * If there's at least a pending and - * we don't care which one it is, - * break immediately and leverage the - * efficiency of the LIFO walk. - */ - break; - /* - * If we need to find which one was pending we - * keep walking until we find the first not - * pending one, so we read() them in FIFO order. - */ - *uwq = _uwq; - } else - /* - * break the loop at the first not pending - * one, there cannot be pending userfaults - * after the first not pending one, because - * all new pending ones are inserted at the - * head and we walk it in LIFO. - */ - break; - } + VM_BUG_ON(!spin_is_locked(&ctx->fault_pending_wqh.lock)); - return ret; + uwq = NULL; + if (!waitqueue_active(&ctx->fault_pending_wqh)) + goto out; + /* walk in reverse to provide FIFO behavior to read userfaults */ + wq = list_last_entry(&ctx->fault_pending_wqh.task_list, + typeof(*wq), task_list); + uwq = container_of(wq, struct userfaultfd_wait_queue, wq); +out: + return uwq; } static unsigned int userfaultfd_poll(struct file *file, poll_table *wait) @@ -417,9 +414,20 @@ static unsigned int userfaultfd_poll(struct file *file, poll_table *wait) */ if (unlikely(!(file->f_flags & O_NONBLOCK))) return POLLERR; - spin_lock(&ctx->fault_wqh.lock); - ret = find_userfault(ctx, NULL); - spin_unlock(&ctx->fault_wqh.lock); + /* + * lockless access to see if there are pending faults + * __pollwait last action is the add_wait_queue but + * the spin_unlock would allow the waitqueue_active to + * pass above the actual list_add inside + * add_wait_queue critical section. So use a full + * memory barrier to serialize the list_add write of + * add_wait_queue() with the waitqueue_active read + * below. + */ + ret = 0; + smp_mb(); + if (waitqueue_active(&ctx->fault_pending_wqh)) + ret = POLLIN; return ret; default: BUG(); @@ -431,27 +439,47 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, { ssize_t ret; DECLARE_WAITQUEUE(wait, current); - struct userfaultfd_wait_queue *uwq = NULL; + struct userfaultfd_wait_queue *uwq; - /* always take the fd_wqh lock before the fault_wqh lock */ + /* always take the fd_wqh lock before the fault_pending_wqh lock */ spin_lock(&ctx->fd_wqh.lock); __add_wait_queue(&ctx->fd_wqh, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - spin_lock(&ctx->fault_wqh.lock); - if (find_userfault(ctx, &uwq)) { + spin_lock(&ctx->fault_pending_wqh.lock); + uwq = find_userfault(ctx); + if (uwq) { /* - * The fault_wqh.lock prevents the uwq to - * disappear from under us. + * The fault_pending_wqh.lock prevents the uwq + * to disappear from under us. + * + * Refile this userfault from + * fault_pending_wqh to fault_wqh, it's not + * pending anymore after we read it. + * + * Use list_del() by hand (as + * userfaultfd_wake_function also uses + * list_del_init() by hand) to be sure nobody + * changes __remove_wait_queue() to use + * list_del_init() in turn breaking the + * !list_empty_careful() check in + * handle_userfault(). The uwq->wq.task_list + * must never be empty at any time during the + * refile, or the waitqueue could disappear + * from under us. The "wait_queue_head_t" + * parameter of __remove_wait_queue() is unused + * anyway. */ - uwq->pending = false; + list_del(&uwq->wq.task_list); + __add_wait_queue(&ctx->fault_wqh, &uwq->wq); + /* careful to always initialize msg if ret == 0 */ *msg = uwq->msg; - spin_unlock(&ctx->fault_wqh.lock); + spin_unlock(&ctx->fault_pending_wqh.lock); ret = 0; break; } - spin_unlock(&ctx->fault_wqh.lock); + spin_unlock(&ctx->fault_pending_wqh.lock); if (signal_pending(current)) { ret = -ERESTARTSYS; break; @@ -510,10 +538,14 @@ static void __wake_userfault(struct userfaultfd_ctx *ctx, start = range->start; end = range->start + range->len; - spin_lock(&ctx->fault_wqh.lock); + spin_lock(&ctx->fault_pending_wqh.lock); /* wake all in the range and autoremove */ - __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, 0, range); - spin_unlock(&ctx->fault_wqh.lock); + if (waitqueue_active(&ctx->fault_pending_wqh)) + __wake_up_locked_key(&ctx->fault_pending_wqh, TASK_NORMAL, 0, + range); + if (waitqueue_active(&ctx->fault_wqh)) + __wake_up_locked_key(&ctx->fault_wqh, TASK_NORMAL, 0, range); + spin_unlock(&ctx->fault_pending_wqh.lock); } static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx, @@ -534,7 +566,8 @@ static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx, * userfaults yet. So we take the spinlock only when we're * sure we've userfaults to wake. */ - if (waitqueue_active(&ctx->fault_wqh)) + if (waitqueue_active(&ctx->fault_pending_wqh) || + waitqueue_active(&ctx->fault_wqh)) __wake_userfault(ctx, range); } @@ -960,14 +993,17 @@ static void userfaultfd_show_fdinfo(struct seq_file *m, struct file *f) struct userfaultfd_wait_queue *uwq; unsigned long pending = 0, total = 0; - spin_lock(&ctx->fault_wqh.lock); + spin_lock(&ctx->fault_pending_wqh.lock); + list_for_each_entry(wq, &ctx->fault_pending_wqh.task_list, task_list) { + uwq = container_of(wq, struct userfaultfd_wait_queue, wq); + pending++; + total++; + } list_for_each_entry(wq, &ctx->fault_wqh.task_list, task_list) { uwq = container_of(wq, struct userfaultfd_wait_queue, wq); - if (uwq->pending) - pending++; total++; } - spin_unlock(&ctx->fault_wqh.lock); + spin_unlock(&ctx->fault_pending_wqh.lock); /* * If more protocols will be added, there will be all shown @@ -1027,6 +1063,7 @@ static struct file *userfaultfd_file_create(int flags) goto out; atomic_set(&ctx->refcount, 1); + init_waitqueue_head(&ctx->fault_pending_wqh); init_waitqueue_head(&ctx->fault_wqh); init_waitqueue_head(&ctx->fd_wqh); ctx->flags = flags; -- GitLab From 3004ec9cabf49f43fae2b2bd1855a4720f1def7a Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:48 -0700 Subject: [PATCH 6425/7006] userfaultfd: allocate the userfaultfd_ctx cacheline aligned Use proper slab to guarantee alignment. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 39 +++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 232cbf37c59f8..8977a4e8a7f8c 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -27,20 +27,26 @@ #include #include +static struct kmem_cache *userfaultfd_ctx_cachep __read_mostly; + enum userfaultfd_state { UFFD_STATE_WAIT_API, UFFD_STATE_RUNNING, }; +/* + * Start with fault_pending_wqh and fault_wqh so they're more likely + * to be in the same cacheline. + */ struct userfaultfd_ctx { - /* pseudo fd refcounting */ - atomic_t refcount; /* waitqueue head for the pending (i.e. not read) userfaults */ wait_queue_head_t fault_pending_wqh; /* waitqueue head for the userfaults */ wait_queue_head_t fault_wqh; /* waitqueue head for the pseudo fd to wakeup poll/read */ wait_queue_head_t fd_wqh; + /* pseudo fd refcounting */ + atomic_t refcount; /* userfaultfd syscall flags */ unsigned int flags; /* state machine */ @@ -130,7 +136,7 @@ static void userfaultfd_ctx_put(struct userfaultfd_ctx *ctx) VM_BUG_ON(spin_is_locked(&ctx->fd_wqh.lock)); VM_BUG_ON(waitqueue_active(&ctx->fd_wqh)); mmput(ctx->mm); - kfree(ctx); + kmem_cache_free(userfaultfd_ctx_cachep, ctx); } } @@ -1028,6 +1034,15 @@ static const struct file_operations userfaultfd_fops = { .llseek = noop_llseek, }; +static void init_once_userfaultfd_ctx(void *mem) +{ + struct userfaultfd_ctx *ctx = (struct userfaultfd_ctx *) mem; + + init_waitqueue_head(&ctx->fault_pending_wqh); + init_waitqueue_head(&ctx->fault_wqh); + init_waitqueue_head(&ctx->fd_wqh); +} + /** * userfaultfd_file_create - Creates an userfaultfd file pointer. * @flags: Flags for the userfaultfd file. @@ -1058,14 +1073,11 @@ static struct file *userfaultfd_file_create(int flags) goto out; file = ERR_PTR(-ENOMEM); - ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); + ctx = kmem_cache_alloc(userfaultfd_ctx_cachep, GFP_KERNEL); if (!ctx) goto out; atomic_set(&ctx->refcount, 1); - init_waitqueue_head(&ctx->fault_pending_wqh); - init_waitqueue_head(&ctx->fault_wqh); - init_waitqueue_head(&ctx->fd_wqh); ctx->flags = flags; ctx->state = UFFD_STATE_WAIT_API; ctx->released = false; @@ -1076,7 +1088,7 @@ static struct file *userfaultfd_file_create(int flags) file = anon_inode_getfile("[userfaultfd]", &userfaultfd_fops, ctx, O_RDWR | (flags & UFFD_SHARED_FCNTL_FLAGS)); if (IS_ERR(file)) - kfree(ctx); + kmem_cache_free(userfaultfd_ctx_cachep, ctx); out: return file; } @@ -1105,3 +1117,14 @@ err_put_unused_fd: return error; } + +static int __init userfaultfd_init(void) +{ + userfaultfd_ctx_cachep = kmem_cache_create("userfaultfd_ctx_cache", + sizeof(struct userfaultfd_ctx), + 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, + init_once_userfaultfd_ctx); + return 0; +} +__initcall(userfaultfd_init); -- GitLab From 8d2afd96c20316d112e04d935d9e09150e988397 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:51 -0700 Subject: [PATCH 6426/7006] userfaultfd: solve the race between UFFDIO_COPY|ZEROPAGE and read Solve in-kernel the race between UFFDIO_COPY|ZEROPAGE and userfaultfd_read if they are run on different threads simultaneously. Until now qemu solved the race in userland: the race was explicitly and intentionally left for userland to solve. However we can also solve it in kernel. Requiring all users to solve this race if they use two threads (one for the background transfer and one for the userfault reads) isn't very attractive from an API prospective, furthermore this allows to remove a whole bunch of mutex and bitmap code from qemu, making it faster. The cost of __get_user_pages_fast should be insignificant considering it scales perfectly and the pagetables are already hot in the CPU cache, compared to the overhead in userland to maintain those structures. Applying this patch is backwards compatible with respect to the userfaultfd userland API, however reverting this change wouldn't be backwards compatible anymore. Without this patch qemu in the background transfer thread, has to read the old state, and do UFFDIO_WAKE if old_state is missing but it become REQUESTED by the time it tries to set it to RECEIVED (signaling the other side received an userfault). vcpu background_thr userfault_thr ----- ----- ----- vcpu0 handle_mm_fault() postcopy_place_page read old_state -> MISSING UFFDIO_COPY 0x7fb76a139000 (no wakeup, still pending) vcpu0 fault at 0x7fb76a139000 enters handle_userfault poll() is kicked poll() -> POLLIN read() -> 0x7fb76a139000 postcopy_pmi_change_state(MISSING, REQUESTED) -> REQUESTED tmp_state = postcopy_pmi_change_state(old_state, RECEIVED) -> REQUESTED /* check that no userfault raced with UFFDIO_COPY */ if (old_state == MISSING && tmp_state == REQUESTED) UFFDIO_WAKE from background thread And a second case where a UFFDIO_WAKE would be needed is in the userfault thread: vcpu background_thr userfault_thr ----- ----- ----- vcpu0 handle_mm_fault() postcopy_place_page read old_state -> MISSING UFFDIO_COPY 0x7fb76a139000 (no wakeup, still pending) tmp_state = postcopy_pmi_change_state(old_state, RECEIVED) -> RECEIVED vcpu0 fault at 0x7fb76a139000 enters handle_userfault poll() is kicked poll() -> POLLIN read() -> 0x7fb76a139000 if (postcopy_pmi_change_state(MISSING, REQUESTED) == RECEIVED) UFFDIO_WAKE from userfault thread This patch removes the need of both UFFDIO_WAKE and of the associated per-page tristate as well. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 81 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 66 insertions(+), 15 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 8977a4e8a7f8c..febbd2b165dfc 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -179,6 +179,67 @@ static inline struct uffd_msg userfault_msg(unsigned long address, return msg; } +/* + * Verify the pagetables are still not ok after having reigstered into + * the fault_pending_wqh to avoid userland having to UFFDIO_WAKE any + * userfault that has already been resolved, if userfaultfd_read and + * UFFDIO_COPY|ZEROPAGE are being run simultaneously on two different + * threads. + */ +static inline bool userfaultfd_must_wait(struct userfaultfd_ctx *ctx, + unsigned long address, + unsigned long flags, + unsigned long reason) +{ + struct mm_struct *mm = ctx->mm; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd, _pmd; + pte_t *pte; + bool ret = true; + + VM_BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); + + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + goto out; + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + goto out; + pmd = pmd_offset(pud, address); + /* + * READ_ONCE must function as a barrier with narrower scope + * and it must be equivalent to: + * _pmd = *pmd; barrier(); + * + * This is to deal with the instability (as in + * pmd_trans_unstable) of the pmd. + */ + _pmd = READ_ONCE(*pmd); + if (!pmd_present(_pmd)) + goto out; + + ret = false; + if (pmd_trans_huge(_pmd)) + goto out; + + /* + * the pmd is stable (as in !pmd_trans_unstable) so we can re-read it + * and use the standard pte_offset_map() instead of parsing _pmd. + */ + pte = pte_offset_map(pmd, address); + /* + * Lockless access: we're in a wait_event so it's ok if it + * changes under us. + */ + if (pte_none(*pte)) + ret = true; + pte_unmap(pte); + +out: + return ret; +} + /* * The locking rules involved in returning VM_FAULT_RETRY depending on * FAULT_FLAG_ALLOW_RETRY, FAULT_FLAG_RETRY_NOWAIT and @@ -201,6 +262,7 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, struct userfaultfd_ctx *ctx; struct userfaultfd_wait_queue uwq; int ret; + bool must_wait; BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); @@ -260,9 +322,6 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, /* take the reference before dropping the mmap_sem */ userfaultfd_ctx_get(ctx); - /* be gentle and immediately relinquish the mmap_sem */ - up_read(&mm->mmap_sem); - init_waitqueue_func_entry(&uwq.wq, userfaultfd_wake_function); uwq.wq.private = current; uwq.msg = userfault_msg(address, flags, reason); @@ -282,7 +341,10 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, set_current_state(TASK_KILLABLE); spin_unlock(&ctx->fault_pending_wqh.lock); - if (likely(!ACCESS_ONCE(ctx->released) && + must_wait = userfaultfd_must_wait(ctx, address, flags, reason); + up_read(&mm->mmap_sem); + + if (likely(must_wait && !ACCESS_ONCE(ctx->released) && !fatal_signal_pending(current))) { wake_up_poll(&ctx->fd_wqh, POLLIN); schedule(); @@ -886,17 +948,6 @@ out: } /* - * userfaultfd_wake is needed in case an userfault is in flight by the - * time a UFFDIO_COPY (or other ioctl variants) completes. The page - * may be well get mapped and the page fault if repeated wouldn't lead - * to a userfault anymore, but before scheduling in TASK_KILLABLE mode - * handle_userfault() doesn't recheck the pagetables and it doesn't - * serialize against UFFDO_COPY (or other ioctl variants). Ultimately - * the knowledge of which pages are mapped is left to userland who is - * responsible for handling the race between read() userfaults and - * background UFFDIO_COPY (or other ioctl variants), if done by - * separate concurrent threads. - * * userfaultfd_wake may be used in combination with the * UFFDIO_*_MODE_DONTWAKE to wakeup userfaults in batches. */ -- GitLab From a14c151e567cb2c3e62611da808a8bdab86fdee5 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:54 -0700 Subject: [PATCH 6427/7006] userfaultfd: buildsystem activation This allows to select the userfaultfd during configuration to build it. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/Makefile | 1 + init/Kconfig | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/fs/Makefile b/fs/Makefile index 09e051fefc5b4..f79cf4043e60d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_ANON_INODES) += anon_inodes.o obj-$(CONFIG_SIGNALFD) += signalfd.o obj-$(CONFIG_TIMERFD) += timerfd.o obj-$(CONFIG_EVENTFD) += eventfd.o +obj-$(CONFIG_USERFAULTFD) += userfaultfd.o obj-$(CONFIG_AIO) += aio.o obj-$(CONFIG_FS_DAX) += dax.o obj-$(CONFIG_FILE_LOCKING) += locks.o diff --git a/init/Kconfig b/init/Kconfig index bb9b4dd55889f..161acd8bc56fc 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1576,6 +1576,17 @@ config ADVISE_SYSCALLS applications use these syscalls, you can disable this option to save space. +config USERFAULTFD + bool "Enable userfaultfd() system call" + select ANON_INODES + default y + depends on MMU + help + Enable the userfaultfd() system call that allows to intercept and + handle page faults in userland. + + If unsure, say Y. + config PCI_QUIRKS default y bool "Enable PCI quirk workarounds" if EXPERT -- GitLab From 1380fca084743fef8d17e59b273473393944ce58 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:46:58 -0700 Subject: [PATCH 6428/7006] userfaultfd: activate syscall This activates the userfaultfd syscall. [sfr@canb.auug.org.au: activate syscall fix] [akpm@linux-foundation.org: don't enable userfaultfd on powerpc] Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/entry/syscalls/syscall_64.tbl | 1 + include/linux/syscalls.h | 1 + kernel/sys_ni.c | 1 + 4 files changed, 4 insertions(+) diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 25e3cf1cd8fde..477bfa6db3707 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -380,3 +380,4 @@ 371 i386 recvfrom sys_recvfrom compat_sys_recvfrom 372 i386 recvmsg sys_recvmsg compat_sys_recvmsg 373 i386 shutdown sys_shutdown +374 i386 userfaultfd sys_userfaultfd diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 9ef32d5f1b19e..81c490634db99 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -329,6 +329,7 @@ 320 common kexec_file_load sys_kexec_file_load 321 common bpf sys_bpf 322 64 execveat stub_execveat +323 common userfaultfd sys_userfaultfd # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index b45c45b8c829f..08001317aee73 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -810,6 +810,7 @@ asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr); asmlinkage long sys_eventfd(unsigned int count); asmlinkage long sys_eventfd2(unsigned int count, int flags); asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags); +asmlinkage long sys_userfaultfd(int flags); asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int); asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *, diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index ca7d84f438f1e..03c3875d99589 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -219,6 +219,7 @@ cond_syscall(compat_sys_timerfd_gettime); cond_syscall(sys_eventfd); cond_syscall(sys_eventfd2); cond_syscall(sys_memfd_create); +cond_syscall(sys_userfaultfd); /* performance counters: */ cond_syscall(sys_perf_event_open); -- GitLab From 1f1c6f075904c241f9e44eb37efa8777141fc938 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:01 -0700 Subject: [PATCH 6429/7006] userfaultfd: UFFDIO_COPY|UFFDIO_ZEROPAGE uAPI This implements the uABI of UFFDIO_COPY and UFFDIO_ZEROPAGE. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/uapi/linux/userfaultfd.h | 42 +++++++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/userfaultfd.h b/include/uapi/linux/userfaultfd.h index a5f8825381ef0..df0e09bb7dd5a 100644 --- a/include/uapi/linux/userfaultfd.h +++ b/include/uapi/linux/userfaultfd.h @@ -25,7 +25,9 @@ (__u64)1 << _UFFDIO_UNREGISTER | \ (__u64)1 << _UFFDIO_API) #define UFFD_API_RANGE_IOCTLS \ - ((__u64)1 << _UFFDIO_WAKE) + ((__u64)1 << _UFFDIO_WAKE | \ + (__u64)1 << _UFFDIO_COPY | \ + (__u64)1 << _UFFDIO_ZEROPAGE) /* * Valid ioctl command number range with this API is from 0x00 to @@ -38,6 +40,8 @@ #define _UFFDIO_REGISTER (0x00) #define _UFFDIO_UNREGISTER (0x01) #define _UFFDIO_WAKE (0x02) +#define _UFFDIO_COPY (0x03) +#define _UFFDIO_ZEROPAGE (0x04) #define _UFFDIO_API (0x3F) /* userfaultfd ioctl ids */ @@ -50,6 +54,10 @@ struct uffdio_range) #define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ struct uffdio_range) +#define UFFDIO_COPY _IOWR(UFFDIO, _UFFDIO_COPY, \ + struct uffdio_copy) +#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ + struct uffdio_zeropage) /* read() structure */ struct uffd_msg { @@ -126,4 +134,36 @@ struct uffdio_register { __u64 ioctls; }; +struct uffdio_copy { + __u64 dst; + __u64 src; + __u64 len; + /* + * There will be a wrprotection flag later that allows to map + * pages wrprotected on the fly. And such a flag will be + * available if the wrprotection ioctl are implemented for the + * range according to the uffdio_register.ioctls. + */ +#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "copy" is written by the ioctl and must be at the end: the + * copy_from_user will not read the last 8 bytes. + */ + __s64 copy; +}; + +struct uffdio_zeropage { + struct uffdio_range range; +#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "zeropage" is written by the ioctl and must be at the end: + * the copy_from_user will not read the last 8 bytes. + */ + __s64 zeropage; +}; + #endif /* _LINUX_USERFAULTFD_H */ -- GitLab From c1a4de99fada21e2e9251e52cbb51eff5aadc757 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:04 -0700 Subject: [PATCH 6430/7006] userfaultfd: mcopy_atomic|mfill_zeropage: UFFDIO_COPY|UFFDIO_ZEROPAGE preparation This implements mcopy_atomic and mfill_zeropage that are the lowlevel VM methods that are invoked respectively by the UFFDIO_COPY and UFFDIO_ZEROPAGE userfaultfd commands. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/userfaultfd_k.h | 6 + mm/Makefile | 1 + mm/userfaultfd.c | 269 ++++++++++++++++++++++++++++++++++ 3 files changed, 276 insertions(+) create mode 100644 mm/userfaultfd.c diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h index e1e43609a179a..587480ad41b7b 100644 --- a/include/linux/userfaultfd_k.h +++ b/include/linux/userfaultfd_k.h @@ -30,6 +30,12 @@ extern int handle_userfault(struct vm_area_struct *vma, unsigned long address, unsigned int flags, unsigned long reason); +extern ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start, + unsigned long src_start, unsigned long len); +extern ssize_t mfill_zeropage(struct mm_struct *dst_mm, + unsigned long dst_start, + unsigned long len); + /* mm helpers */ static inline bool is_mergeable_vm_userfaultfd_ctx(struct vm_area_struct *vma, struct vm_userfaultfd_ctx vm_ctx) diff --git a/mm/Makefile b/mm/Makefile index 98c4eaeabdcb4..b424d5e5b6ff5 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -78,3 +78,4 @@ obj-$(CONFIG_CMA) += cma.o obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o +obj-$(CONFIG_USERFAULTFD) += userfaultfd.o diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c new file mode 100644 index 0000000000000..c54c761609fc9 --- /dev/null +++ b/mm/userfaultfd.c @@ -0,0 +1,269 @@ +/* + * mm/userfaultfd.c + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "internal.h" + +static int mcopy_atomic_pte(struct mm_struct *dst_mm, + pmd_t *dst_pmd, + struct vm_area_struct *dst_vma, + unsigned long dst_addr, + unsigned long src_addr) +{ + struct mem_cgroup *memcg; + pte_t _dst_pte, *dst_pte; + spinlock_t *ptl; + struct page *page; + void *page_kaddr; + int ret; + + ret = -ENOMEM; + page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, dst_vma, dst_addr); + if (!page) + goto out; + + page_kaddr = kmap(page); + ret = -EFAULT; + if (copy_from_user(page_kaddr, (const void __user *) src_addr, + PAGE_SIZE)) + goto out_kunmap_release; + kunmap(page); + + /* + * The memory barrier inside __SetPageUptodate makes sure that + * preceeding stores to the page contents become visible before + * the set_pte_at() write. + */ + __SetPageUptodate(page); + + ret = -ENOMEM; + if (mem_cgroup_try_charge(page, dst_mm, GFP_KERNEL, &memcg)) + goto out_release; + + _dst_pte = mk_pte(page, dst_vma->vm_page_prot); + if (dst_vma->vm_flags & VM_WRITE) + _dst_pte = pte_mkwrite(pte_mkdirty(_dst_pte)); + + ret = -EEXIST; + dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl); + if (!pte_none(*dst_pte)) + goto out_release_uncharge_unlock; + + inc_mm_counter(dst_mm, MM_ANONPAGES); + page_add_new_anon_rmap(page, dst_vma, dst_addr); + mem_cgroup_commit_charge(page, memcg, false); + lru_cache_add_active_or_unevictable(page, dst_vma); + + set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); + + /* No need to invalidate - it was non-present before */ + update_mmu_cache(dst_vma, dst_addr, dst_pte); + + pte_unmap_unlock(dst_pte, ptl); + ret = 0; +out: + return ret; +out_release_uncharge_unlock: + pte_unmap_unlock(dst_pte, ptl); + mem_cgroup_cancel_charge(page, memcg); +out_release: + page_cache_release(page); + goto out; +out_kunmap_release: + kunmap(page); + goto out_release; +} + +static int mfill_zeropage_pte(struct mm_struct *dst_mm, + pmd_t *dst_pmd, + struct vm_area_struct *dst_vma, + unsigned long dst_addr) +{ + pte_t _dst_pte, *dst_pte; + spinlock_t *ptl; + int ret; + + _dst_pte = pte_mkspecial(pfn_pte(my_zero_pfn(dst_addr), + dst_vma->vm_page_prot)); + ret = -EEXIST; + dst_pte = pte_offset_map_lock(dst_mm, dst_pmd, dst_addr, &ptl); + if (!pte_none(*dst_pte)) + goto out_unlock; + set_pte_at(dst_mm, dst_addr, dst_pte, _dst_pte); + /* No need to invalidate - it was non-present before */ + update_mmu_cache(dst_vma, dst_addr, dst_pte); + ret = 0; +out_unlock: + pte_unmap_unlock(dst_pte, ptl); + return ret; +} + +static pmd_t *mm_alloc_pmd(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd = NULL; + + pgd = pgd_offset(mm, address); + pud = pud_alloc(mm, pgd, address); + if (pud) + /* + * Note that we didn't run this because the pmd was + * missing, the *pmd may be already established and in + * turn it may also be a trans_huge_pmd. + */ + pmd = pmd_alloc(mm, pud, address); + return pmd; +} + +static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, + unsigned long dst_start, + unsigned long src_start, + unsigned long len, + bool zeropage) +{ + struct vm_area_struct *dst_vma; + ssize_t err; + pmd_t *dst_pmd; + unsigned long src_addr, dst_addr; + long copied = 0; + + /* + * Sanitize the command parameters: + */ + BUG_ON(dst_start & ~PAGE_MASK); + BUG_ON(len & ~PAGE_MASK); + + /* Does the address range wrap, or is the span zero-sized? */ + BUG_ON(src_start + len <= src_start); + BUG_ON(dst_start + len <= dst_start); + + down_read(&dst_mm->mmap_sem); + + /* + * Make sure the vma is not shared, that the dst range is + * both valid and fully within a single existing vma. + */ + err = -EINVAL; + dst_vma = find_vma(dst_mm, dst_start); + if (!dst_vma || (dst_vma->vm_flags & VM_SHARED)) + goto out; + if (dst_start < dst_vma->vm_start || + dst_start + len > dst_vma->vm_end) + goto out; + + /* + * Be strict and only allow __mcopy_atomic on userfaultfd + * registered ranges to prevent userland errors going + * unnoticed. As far as the VM consistency is concerned, it + * would be perfectly safe to remove this check, but there's + * no useful usage for __mcopy_atomic ouside of userfaultfd + * registered ranges. This is after all why these are ioctls + * belonging to the userfaultfd and not syscalls. + */ + if (!dst_vma->vm_userfaultfd_ctx.ctx) + goto out; + + /* + * FIXME: only allow copying on anonymous vmas, tmpfs should + * be added. + */ + if (dst_vma->vm_ops) + goto out; + + /* + * Ensure the dst_vma has a anon_vma or this page + * would get a NULL anon_vma when moved in the + * dst_vma. + */ + err = -ENOMEM; + if (unlikely(anon_vma_prepare(dst_vma))) + goto out; + + for (src_addr = src_start, dst_addr = dst_start; + src_addr < src_start + len; ) { + pmd_t dst_pmdval; + BUG_ON(dst_addr >= dst_start + len); + dst_pmd = mm_alloc_pmd(dst_mm, dst_addr); + if (unlikely(!dst_pmd)) { + err = -ENOMEM; + break; + } + + dst_pmdval = pmd_read_atomic(dst_pmd); + /* + * If the dst_pmd is mapped as THP don't + * override it and just be strict. + */ + if (unlikely(pmd_trans_huge(dst_pmdval))) { + err = -EEXIST; + break; + } + if (unlikely(pmd_none(dst_pmdval)) && + unlikely(__pte_alloc(dst_mm, dst_vma, dst_pmd, + dst_addr))) { + err = -ENOMEM; + break; + } + /* If an huge pmd materialized from under us fail */ + if (unlikely(pmd_trans_huge(*dst_pmd))) { + err = -EFAULT; + break; + } + + BUG_ON(pmd_none(*dst_pmd)); + BUG_ON(pmd_trans_huge(*dst_pmd)); + + if (!zeropage) + err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma, + dst_addr, src_addr); + else + err = mfill_zeropage_pte(dst_mm, dst_pmd, dst_vma, + dst_addr); + + cond_resched(); + + if (!err) { + dst_addr += PAGE_SIZE; + src_addr += PAGE_SIZE; + copied += PAGE_SIZE; + + if (fatal_signal_pending(current)) + err = -EINTR; + } + if (err) + break; + } + +out: + up_read(&dst_mm->mmap_sem); + BUG_ON(copied < 0); + BUG_ON(err > 0); + BUG_ON(!copied && !err); + return copied ? copied : err; +} + +ssize_t mcopy_atomic(struct mm_struct *dst_mm, unsigned long dst_start, + unsigned long src_start, unsigned long len) +{ + return __mcopy_atomic(dst_mm, dst_start, src_start, len, false); +} + +ssize_t mfill_zeropage(struct mm_struct *dst_mm, unsigned long start, + unsigned long len) +{ + return __mcopy_atomic(dst_mm, start, 0, len, true); +} -- GitLab From b6ebaedb4cb1a18220ae626c3a9e184ee39dd248 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:08 -0700 Subject: [PATCH 6431/7006] userfaultfd: avoid mmap_sem read recursion in mcopy_atomic If the rwsem starves writers it wasn't strictly a bug but lockdep doesn't like it and this avoids depending on lowlevel implementation details of the lock. [akpm@linux-foundation.org: delete weird BUILD_BUG_ON()] Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/userfaultfd.c | 91 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 26 deletions(-) diff --git a/mm/userfaultfd.c b/mm/userfaultfd.c index c54c761609fc9..77fee9325a572 100644 --- a/mm/userfaultfd.c +++ b/mm/userfaultfd.c @@ -21,26 +21,39 @@ static int mcopy_atomic_pte(struct mm_struct *dst_mm, pmd_t *dst_pmd, struct vm_area_struct *dst_vma, unsigned long dst_addr, - unsigned long src_addr) + unsigned long src_addr, + struct page **pagep) { struct mem_cgroup *memcg; pte_t _dst_pte, *dst_pte; spinlock_t *ptl; - struct page *page; void *page_kaddr; int ret; + struct page *page; - ret = -ENOMEM; - page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, dst_vma, dst_addr); - if (!page) - goto out; - - page_kaddr = kmap(page); - ret = -EFAULT; - if (copy_from_user(page_kaddr, (const void __user *) src_addr, - PAGE_SIZE)) - goto out_kunmap_release; - kunmap(page); + if (!*pagep) { + ret = -ENOMEM; + page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, dst_vma, dst_addr); + if (!page) + goto out; + + page_kaddr = kmap_atomic(page); + ret = copy_from_user(page_kaddr, + (const void __user *) src_addr, + PAGE_SIZE); + kunmap_atomic(page_kaddr); + + /* fallback to copy_from_user outside mmap_sem */ + if (unlikely(ret)) { + ret = -EFAULT; + *pagep = page; + /* don't free the page */ + goto out; + } + } else { + page = *pagep; + *pagep = NULL; + } /* * The memory barrier inside __SetPageUptodate makes sure that @@ -82,9 +95,6 @@ out_release_uncharge_unlock: out_release: page_cache_release(page); goto out; -out_kunmap_release: - kunmap(page); - goto out_release; } static int mfill_zeropage_pte(struct mm_struct *dst_mm, @@ -139,7 +149,8 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, ssize_t err; pmd_t *dst_pmd; unsigned long src_addr, dst_addr; - long copied = 0; + long copied; + struct page *page; /* * Sanitize the command parameters: @@ -151,6 +162,11 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, BUG_ON(src_start + len <= src_start); BUG_ON(dst_start + len <= dst_start); + src_addr = src_start; + dst_addr = dst_start; + copied = 0; + page = NULL; +retry: down_read(&dst_mm->mmap_sem); /* @@ -160,10 +176,10 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, err = -EINVAL; dst_vma = find_vma(dst_mm, dst_start); if (!dst_vma || (dst_vma->vm_flags & VM_SHARED)) - goto out; + goto out_unlock; if (dst_start < dst_vma->vm_start || dst_start + len > dst_vma->vm_end) - goto out; + goto out_unlock; /* * Be strict and only allow __mcopy_atomic on userfaultfd @@ -175,14 +191,14 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, * belonging to the userfaultfd and not syscalls. */ if (!dst_vma->vm_userfaultfd_ctx.ctx) - goto out; + goto out_unlock; /* * FIXME: only allow copying on anonymous vmas, tmpfs should * be added. */ if (dst_vma->vm_ops) - goto out; + goto out_unlock; /* * Ensure the dst_vma has a anon_vma or this page @@ -191,12 +207,13 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, */ err = -ENOMEM; if (unlikely(anon_vma_prepare(dst_vma))) - goto out; + goto out_unlock; - for (src_addr = src_start, dst_addr = dst_start; - src_addr < src_start + len; ) { + while (src_addr < src_start + len) { pmd_t dst_pmdval; + BUG_ON(dst_addr >= dst_start + len); + dst_pmd = mm_alloc_pmd(dst_mm, dst_addr); if (unlikely(!dst_pmd)) { err = -ENOMEM; @@ -229,13 +246,32 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, if (!zeropage) err = mcopy_atomic_pte(dst_mm, dst_pmd, dst_vma, - dst_addr, src_addr); + dst_addr, src_addr, &page); else err = mfill_zeropage_pte(dst_mm, dst_pmd, dst_vma, dst_addr); cond_resched(); + if (unlikely(err == -EFAULT)) { + void *page_kaddr; + + up_read(&dst_mm->mmap_sem); + BUG_ON(!page); + + page_kaddr = kmap(page); + err = copy_from_user(page_kaddr, + (const void __user *) src_addr, + PAGE_SIZE); + kunmap(page); + if (unlikely(err)) { + err = -EFAULT; + goto out; + } + goto retry; + } else + BUG_ON(page); + if (!err) { dst_addr += PAGE_SIZE; src_addr += PAGE_SIZE; @@ -248,8 +284,11 @@ static __always_inline ssize_t __mcopy_atomic(struct mm_struct *dst_mm, break; } -out: +out_unlock: up_read(&dst_mm->mmap_sem); +out: + if (page) + page_cache_release(page); BUG_ON(copied < 0); BUG_ON(err > 0); BUG_ON(!copied && !err); -- GitLab From ad465cae96b456b48d26c96f27a0577ba443472a Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:11 -0700 Subject: [PATCH 6432/7006] userfaultfd: UFFDIO_COPY and UFFDIO_ZEROPAGE These two ioctl allows to either atomically copy or to map zeropages into the virtual address space. This is used by the thread that opened the userfaultfd to resolve the userfaults. Signed-off-by: Andrea Arcangeli Acked-by: Pavel Emelyanov Cc: Sanidhya Kashyap Cc: zhang.zhanghailiang@huawei.com Cc: "Kirill A. Shutemov" Cc: Andres Lagar-Cavilla Cc: Dave Hansen Cc: Paolo Bonzini Cc: Rik van Riel Cc: Mel Gorman Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Peter Feiner Cc: "Dr. David Alan Gilbert" Cc: Johannes Weiner Cc: "Huangpeng (Peter)" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 96 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index febbd2b165dfc..5f11678907d5d 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -983,6 +983,96 @@ out: return ret; } +static int userfaultfd_copy(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + __s64 ret; + struct uffdio_copy uffdio_copy; + struct uffdio_copy __user *user_uffdio_copy; + struct userfaultfd_wake_range range; + + user_uffdio_copy = (struct uffdio_copy __user *) arg; + + ret = -EFAULT; + if (copy_from_user(&uffdio_copy, user_uffdio_copy, + /* don't copy "copy" last field */ + sizeof(uffdio_copy)-sizeof(__s64))) + goto out; + + ret = validate_range(ctx->mm, uffdio_copy.dst, uffdio_copy.len); + if (ret) + goto out; + /* + * double check for wraparound just in case. copy_from_user() + * will later check uffdio_copy.src + uffdio_copy.len to fit + * in the userland range. + */ + ret = -EINVAL; + if (uffdio_copy.src + uffdio_copy.len <= uffdio_copy.src) + goto out; + if (uffdio_copy.mode & ~UFFDIO_COPY_MODE_DONTWAKE) + goto out; + + ret = mcopy_atomic(ctx->mm, uffdio_copy.dst, uffdio_copy.src, + uffdio_copy.len); + if (unlikely(put_user(ret, &user_uffdio_copy->copy))) + return -EFAULT; + if (ret < 0) + goto out; + BUG_ON(!ret); + /* len == 0 would wake all */ + range.len = ret; + if (!(uffdio_copy.mode & UFFDIO_COPY_MODE_DONTWAKE)) { + range.start = uffdio_copy.dst; + wake_userfault(ctx, &range); + } + ret = range.len == uffdio_copy.len ? 0 : -EAGAIN; +out: + return ret; +} + +static int userfaultfd_zeropage(struct userfaultfd_ctx *ctx, + unsigned long arg) +{ + __s64 ret; + struct uffdio_zeropage uffdio_zeropage; + struct uffdio_zeropage __user *user_uffdio_zeropage; + struct userfaultfd_wake_range range; + + user_uffdio_zeropage = (struct uffdio_zeropage __user *) arg; + + ret = -EFAULT; + if (copy_from_user(&uffdio_zeropage, user_uffdio_zeropage, + /* don't copy "zeropage" last field */ + sizeof(uffdio_zeropage)-sizeof(__s64))) + goto out; + + ret = validate_range(ctx->mm, uffdio_zeropage.range.start, + uffdio_zeropage.range.len); + if (ret) + goto out; + ret = -EINVAL; + if (uffdio_zeropage.mode & ~UFFDIO_ZEROPAGE_MODE_DONTWAKE) + goto out; + + ret = mfill_zeropage(ctx->mm, uffdio_zeropage.range.start, + uffdio_zeropage.range.len); + if (unlikely(put_user(ret, &user_uffdio_zeropage->zeropage))) + return -EFAULT; + if (ret < 0) + goto out; + /* len == 0 would wake all */ + BUG_ON(!ret); + range.len = ret; + if (!(uffdio_zeropage.mode & UFFDIO_ZEROPAGE_MODE_DONTWAKE)) { + range.start = uffdio_zeropage.range.start; + wake_userfault(ctx, &range); + } + ret = range.len == uffdio_zeropage.range.len ? 0 : -EAGAIN; +out: + return ret; +} + /* * userland asks for a certain API version and we return which bits * and ioctl commands are implemented in this kernel for such API @@ -1038,6 +1128,12 @@ static long userfaultfd_ioctl(struct file *file, unsigned cmd, case UFFDIO_WAKE: ret = userfaultfd_wake(ctx, arg); break; + case UFFDIO_COPY: + ret = userfaultfd_copy(ctx, arg); + break; + case UFFDIO_ZEROPAGE: + ret = userfaultfd_zeropage(ctx, arg); + break; } return ret; } -- GitLab From e6485a47b758cae04a496764a1095961ee3249e4 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:15 -0700 Subject: [PATCH 6433/7006] userfaultfd: require UFFDIO_API before other ioctls UFFDIO_API was already forced before read/poll could work. This makes the code more strict to force it also for all other ioctls. All users would already have been required to call UFFDIO_API before invoking other ioctls but this makes it more explicit. This will ensure we can change all ioctls (all but UFFDIO_API/struct uffdio_api) with a bump of uffdio_api.api. There's no actual plan or need to change the API or the ioctl, the current API already should cover fine even the non cooperative usage, but this is just for the longer term future just in case. Signed-off-by: Andrea Arcangeli Cc: Pavel Emelyanov Cc: Dave Hansen Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index 5f11678907d5d..af88ef6fffff7 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -577,7 +577,6 @@ static ssize_t userfaultfd_read(struct file *file, char __user *buf, if (ctx->state == UFFD_STATE_WAIT_API) return -EINVAL; - BUG_ON(ctx->state != UFFD_STATE_RUNNING); for (;;) { if (count < sizeof(msg)) @@ -1115,6 +1114,9 @@ static long userfaultfd_ioctl(struct file *file, unsigned cmd, int ret = -EINVAL; struct userfaultfd_ctx *ctx = file->private_data; + if (cmd != UFFDIO_API && ctx->state == UFFD_STATE_WAIT_API) + return -EINVAL; + switch(cmd) { case UFFDIO_API: ret = userfaultfd_api(ctx, arg); -- GitLab From dfa37dc3fc1f6f81a6900d0e561c02362f4817f6 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:18 -0700 Subject: [PATCH 6434/7006] userfaultfd: allow signals to interrupt a userfault This is only simple to achieve if the userfault is going to return to userland (not to the kernel) because we can avoid returning VM_FAULT_RETRY despite we temporarily released the mmap_sem. The fault would just be retried by userland then. This is safe at least on x86 and powerpc (the two archs with the syscall implemented so far). Hint to verify for which archs this is safe: after handle_mm_fault returns, no access to data structures protected by the mmap_sem must be done by the fault code in arch/*/mm/fault.c until up_read(&mm->mmap_sem) is called. This has two main benefits: signals can run with lower latency in production (signals aren't blocked by userfaults and userfaults are immediately repeated after signal processing) and gdb can then trivially debug the threads blocked in this kind of userfaults coming directly from userland. On a side note: while gdb has a need to get signal processed, coredumps always worked perfectly with userfaults, no matter if the userfault is triggered by GUP a kernel copy_user or directly from userland. Signed-off-by: Andrea Arcangeli Cc: Pavel Emelyanov Cc: Dave Hansen Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index af88ef6fffff7..a14d63e945f47 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -262,7 +262,7 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, struct userfaultfd_ctx *ctx; struct userfaultfd_wait_queue uwq; int ret; - bool must_wait; + bool must_wait, return_to_userland; BUG_ON(!rwsem_is_locked(&mm->mmap_sem)); @@ -327,6 +327,9 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, uwq.msg = userfault_msg(address, flags, reason); uwq.ctx = ctx; + return_to_userland = (flags & (FAULT_FLAG_USER|FAULT_FLAG_KILLABLE)) == + (FAULT_FLAG_USER|FAULT_FLAG_KILLABLE); + spin_lock(&ctx->fault_pending_wqh.lock); /* * After the __add_wait_queue the uwq is visible to userland @@ -338,14 +341,16 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, * following the spin_unlock to happen before the list_add in * __add_wait_queue. */ - set_current_state(TASK_KILLABLE); + set_current_state(return_to_userland ? TASK_INTERRUPTIBLE : + TASK_KILLABLE); spin_unlock(&ctx->fault_pending_wqh.lock); must_wait = userfaultfd_must_wait(ctx, address, flags, reason); up_read(&mm->mmap_sem); if (likely(must_wait && !ACCESS_ONCE(ctx->released) && - !fatal_signal_pending(current))) { + (return_to_userland ? !signal_pending(current) : + !fatal_signal_pending(current)))) { wake_up_poll(&ctx->fd_wqh, POLLIN); schedule(); ret |= VM_FAULT_MAJOR; @@ -353,6 +358,30 @@ int handle_userfault(struct vm_area_struct *vma, unsigned long address, __set_current_state(TASK_RUNNING); + if (return_to_userland) { + if (signal_pending(current) && + !fatal_signal_pending(current)) { + /* + * If we got a SIGSTOP or SIGCONT and this is + * a normal userland page fault, just let + * userland return so the signal will be + * handled and gdb debugging works. The page + * fault code immediately after we return from + * this function is going to release the + * mmap_sem and it's not depending on it + * (unlike gup would if we were not to return + * VM_FAULT_RETRY). + * + * If a fatal signal is pending we still take + * the streamlined VM_FAULT_RETRY failure path + * and there's no need to retake the mmap_sem + * in such case. + */ + down_read(&mm->mmap_sem); + ret = 0; + } + } + /* * Here we race with the list_del; list_add in * userfaultfd_ctx_read(), however because we don't ever run -- GitLab From 230c92a8797e0e717c6732de0fffdd5726c0f48f Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:20 -0700 Subject: [PATCH 6435/7006] userfaultfd: propagate the full address in THP faults The THP faults were not propagating the original fault address. The latest version of the API with uffd.arg.pagefault.address is supposed to propagate the full address through THP faults. This was not a kernel crashing bug and it wouldn't risk to corrupt user memory, but it would cause a SIGBUS failure because the wrong page was being copied. For various reasons this wasn't easily reproducible in the qemu workload, but the strestest exposed the problem immediately. Signed-off-by: Andrea Arcangeli Cc: Pavel Emelyanov Cc: Dave Hansen Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index d38aaf9dcba60..279a818a39b13 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -717,13 +717,14 @@ static inline pmd_t mk_huge_pmd(struct page *page, pgprot_t prot) static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long haddr, pmd_t *pmd, + unsigned long address, pmd_t *pmd, struct page *page, gfp_t gfp, unsigned int flags) { struct mem_cgroup *memcg; pgtable_t pgtable; spinlock_t *ptl; + unsigned long haddr = address & HPAGE_PMD_MASK; VM_BUG_ON_PAGE(!PageCompound(page), page); @@ -765,7 +766,7 @@ static int __do_huge_pmd_anonymous_page(struct mm_struct *mm, mem_cgroup_cancel_charge(page, memcg); put_page(page); pte_free(mm, pgtable); - ret = handle_userfault(vma, haddr, flags, + ret = handle_userfault(vma, address, flags, VM_UFFD_MISSING); VM_BUG_ON(ret & VM_FAULT_FALLBACK); return ret; @@ -841,7 +842,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, if (pmd_none(*pmd)) { if (userfaultfd_missing(vma)) { spin_unlock(ptl); - ret = handle_userfault(vma, haddr, flags, + ret = handle_userfault(vma, address, flags, VM_UFFD_MISSING); VM_BUG_ON(ret & VM_FAULT_FALLBACK); } else { @@ -865,7 +866,8 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, count_vm_event(THP_FAULT_FALLBACK); return VM_FAULT_FALLBACK; } - return __do_huge_pmd_anonymous_page(mm, vma, haddr, pmd, page, gfp, flags); + return __do_huge_pmd_anonymous_page(mm, vma, address, pmd, page, gfp, + flags); } int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, -- GitLab From 2c5b7e1be74ff0175dedbbd325abe9f0dbbb09ae Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:23 -0700 Subject: [PATCH 6436/7006] userfaultfd: avoid missing wakeups during refile in userfaultfd_read During the refile in userfaultfd_read both waitqueues could look empty to the lockless wake_userfault(). Use a seqcount to prevent this false negative that could leave an userfault blocked. Signed-off-by: Andrea Arcangeli Cc: Pavel Emelyanov Cc: Dave Hansen Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/userfaultfd.c | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/fs/userfaultfd.c b/fs/userfaultfd.c index a14d63e945f47..634e676072cb7 100644 --- a/fs/userfaultfd.c +++ b/fs/userfaultfd.c @@ -45,6 +45,8 @@ struct userfaultfd_ctx { wait_queue_head_t fault_wqh; /* waitqueue head for the pseudo fd to wakeup poll/read */ wait_queue_head_t fd_wqh; + /* a refile sequence protected by fault_pending_wqh lock */ + struct seqcount refile_seq; /* pseudo fd refcounting */ atomic_t refcount; /* userfaultfd syscall flags */ @@ -546,6 +548,15 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, spin_lock(&ctx->fault_pending_wqh.lock); uwq = find_userfault(ctx); if (uwq) { + /* + * Use a seqcount to repeat the lockless check + * in wake_userfault() to avoid missing + * wakeups because during the refile both + * waitqueue could become empty if this is the + * only userfault. + */ + write_seqcount_begin(&ctx->refile_seq); + /* * The fault_pending_wqh.lock prevents the uwq * to disappear from under us. @@ -570,6 +581,8 @@ static ssize_t userfaultfd_ctx_read(struct userfaultfd_ctx *ctx, int no_wait, list_del(&uwq->wq.task_list); __add_wait_queue(&ctx->fault_wqh, &uwq->wq); + write_seqcount_end(&ctx->refile_seq); + /* careful to always initialize msg if ret == 0 */ *msg = uwq->msg; spin_unlock(&ctx->fault_pending_wqh.lock); @@ -647,6 +660,9 @@ static void __wake_userfault(struct userfaultfd_ctx *ctx, static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx, struct userfaultfd_wake_range *range) { + unsigned seq; + bool need_wakeup; + /* * To be sure waitqueue_active() is not reordered by the CPU * before the pagetable update, use an explicit SMP memory @@ -662,8 +678,13 @@ static __always_inline void wake_userfault(struct userfaultfd_ctx *ctx, * userfaults yet. So we take the spinlock only when we're * sure we've userfaults to wake. */ - if (waitqueue_active(&ctx->fault_pending_wqh) || - waitqueue_active(&ctx->fault_wqh)) + do { + seq = read_seqcount_begin(&ctx->refile_seq); + need_wakeup = waitqueue_active(&ctx->fault_pending_wqh) || + waitqueue_active(&ctx->fault_wqh); + cond_resched(); + } while (read_seqcount_retry(&ctx->refile_seq, seq)); + if (need_wakeup) __wake_userfault(ctx, range); } @@ -1219,6 +1240,7 @@ static void init_once_userfaultfd_ctx(void *mem) init_waitqueue_head(&ctx->fault_pending_wqh); init_waitqueue_head(&ctx->fault_wqh); init_waitqueue_head(&ctx->fd_wqh); + seqcount_init(&ctx->refile_seq); } /** -- GitLab From c47174fc362a089b1125174258e53ef4a69ce6b8 Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Fri, 4 Sep 2015 15:47:23 -0700 Subject: [PATCH 6437/7006] userfaultfd: selftest This test allocates two virtual areas and bounces the physical memory across the two virtual areas using only userfaultfd. Signed-off-by: Andrea Arcangeli Cc: Pavel Emelyanov Cc: Dave Hansen Cc: Linus Torvalds Cc: Shuah Khan Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/vm/Makefile | 3 + tools/testing/selftests/vm/run_vmtests | 11 + tools/testing/selftests/vm/userfaultfd.c | 636 +++++++++++++++++++++++ 3 files changed, 650 insertions(+) create mode 100644 tools/testing/selftests/vm/userfaultfd.c diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 231b9a031f6ad..0d6854744b373 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -8,10 +8,13 @@ BINARIES += hugetlbfstest BINARIES += map_hugetlb BINARIES += thuge-gen BINARIES += transhuge-stress +BINARIES += userfaultfd all: $(BINARIES) %: %.c $(CC) $(CFLAGS) -o $@ $^ -lrt +userfaultfd: userfaultfd.c + $(CC) $(CFLAGS) -O2 -o $@ $^ -lpthread TEST_PROGS := run_vmtests TEST_FILES := $(BINARIES) diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index 49ece11ff7fdc..831adeb5fc552 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -86,6 +86,17 @@ else echo "[PASS]" fi +echo "--------------------" +echo "running userfaultfd" +echo "--------------------" +./userfaultfd 128 32 +if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 +else + echo "[PASS]" +fi + #cleanup umount $mnt rm -rf $mnt diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c new file mode 100644 index 0000000000000..0c0b839533526 --- /dev/null +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -0,0 +1,636 @@ +/* + * Stress userfaultfd syscall. + * + * Copyright (C) 2015 Red Hat, Inc. + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + * This test allocates two virtual areas and bounces the physical + * memory across the two virtual areas (from area_src to area_dst) + * using userfaultfd. + * + * There are three threads running per CPU: + * + * 1) one per-CPU thread takes a per-page pthread_mutex in a random + * page of the area_dst (while the physical page may still be in + * area_src), and increments a per-page counter in the same page, + * and checks its value against a verification region. + * + * 2) another per-CPU thread handles the userfaults generated by + * thread 1 above. userfaultfd blocking reads or poll() modes are + * exercised interleaved. + * + * 3) one last per-CPU thread transfers the memory in the background + * at maximum bandwidth (if not already transferred by thread + * 2). Each cpu thread takes cares of transferring a portion of the + * area. + * + * When all threads of type 3 completed the transfer, one bounce is + * complete. area_src and area_dst are then swapped. All threads are + * respawned and so the bounce is immediately restarted in the + * opposite direction. + * + * per-CPU threads 1 by triggering userfaults inside + * pthread_mutex_lock will also verify the atomicity of the memory + * transfer (UFFDIO_COPY). + * + * The program takes two parameters: the amounts of physical memory in + * megabytes (MiB) of the area and the number of bounces to execute. + * + * # 100MiB 99999 bounces + * ./userfaultfd 100 99999 + * + * # 1GiB 99 bounces + * ./userfaultfd 1000 99 + * + * # 10MiB-~6GiB 999 bounces, continue forever unless an error triggers + * while ./userfaultfd $[RANDOM % 6000 + 10] 999; do true; done + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../../../include/uapi/linux/userfaultfd.h" + +#ifdef __x86_64__ +#define __NR_userfaultfd 323 +#elif defined(__i386__) +#define __NR_userfaultfd 359 +#elif defined(__powewrpc__) +#define __NR_userfaultfd 364 +#else +#error "missing __NR_userfaultfd definition" +#endif + +static unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size; + +#define BOUNCE_RANDOM (1<<0) +#define BOUNCE_RACINGFAULTS (1<<1) +#define BOUNCE_VERIFY (1<<2) +#define BOUNCE_POLL (1<<3) +static int bounces; + +static unsigned long long *count_verify; +static int uffd, finished, *pipefd; +static char *area_src, *area_dst; +static char *zeropage; +pthread_attr_t attr; + +/* pthread_mutex_t starts at page offset 0 */ +#define area_mutex(___area, ___nr) \ + ((pthread_mutex_t *) ((___area) + (___nr)*page_size)) +/* + * count is placed in the page after pthread_mutex_t naturally aligned + * to avoid non alignment faults on non-x86 archs. + */ +#define area_count(___area, ___nr) \ + ((volatile unsigned long long *) ((unsigned long) \ + ((___area) + (___nr)*page_size + \ + sizeof(pthread_mutex_t) + \ + sizeof(unsigned long long) - 1) & \ + ~(unsigned long)(sizeof(unsigned long long) \ + - 1))) + +static int my_bcmp(char *str1, char *str2, size_t n) +{ + unsigned long i; + for (i = 0; i < n; i++) + if (str1[i] != str2[i]) + return 1; + return 0; +} + +static void *locking_thread(void *arg) +{ + unsigned long cpu = (unsigned long) arg; + struct random_data rand; + unsigned long page_nr = *(&(page_nr)); /* uninitialized warning */ + int32_t rand_nr; + unsigned long long count; + char randstate[64]; + unsigned int seed; + time_t start; + + if (bounces & BOUNCE_RANDOM) { + seed = (unsigned int) time(NULL) - bounces; + if (!(bounces & BOUNCE_RACINGFAULTS)) + seed += cpu; + bzero(&rand, sizeof(rand)); + bzero(&randstate, sizeof(randstate)); + if (initstate_r(seed, randstate, sizeof(randstate), &rand)) + fprintf(stderr, "srandom_r error\n"), exit(1); + } else { + page_nr = -bounces; + if (!(bounces & BOUNCE_RACINGFAULTS)) + page_nr += cpu * nr_pages_per_cpu; + } + + while (!finished) { + if (bounces & BOUNCE_RANDOM) { + if (random_r(&rand, &rand_nr)) + fprintf(stderr, "random_r 1 error\n"), exit(1); + page_nr = rand_nr; + if (sizeof(page_nr) > sizeof(rand_nr)) { + if (random_r(&rand, &rand_nr)) + fprintf(stderr, "random_r 2 error\n"), exit(1); + page_nr |= ((unsigned long) rand_nr) << 32; + } + } else + page_nr += 1; + page_nr %= nr_pages; + + start = time(NULL); + if (bounces & BOUNCE_VERIFY) { + count = *area_count(area_dst, page_nr); + if (!count) + fprintf(stderr, + "page_nr %lu wrong count %Lu %Lu\n", + page_nr, count, + count_verify[page_nr]), exit(1); + + + /* + * We can't use bcmp (or memcmp) because that + * returns 0 erroneously if the memory is + * changing under it (even if the end of the + * page is never changing and always + * different). + */ +#if 1 + if (!my_bcmp(area_dst + page_nr * page_size, zeropage, + page_size)) + fprintf(stderr, + "my_bcmp page_nr %lu wrong count %Lu %Lu\n", + page_nr, count, + count_verify[page_nr]), exit(1); +#else + unsigned long loops; + + loops = 0; + /* uncomment the below line to test with mutex */ + /* pthread_mutex_lock(area_mutex(area_dst, page_nr)); */ + while (!bcmp(area_dst + page_nr * page_size, zeropage, + page_size)) { + loops += 1; + if (loops > 10) + break; + } + /* uncomment below line to test with mutex */ + /* pthread_mutex_unlock(area_mutex(area_dst, page_nr)); */ + if (loops) { + fprintf(stderr, + "page_nr %lu all zero thread %lu %p %lu\n", + page_nr, cpu, area_dst + page_nr * page_size, + loops); + if (loops > 10) + exit(1); + } +#endif + } + + pthread_mutex_lock(area_mutex(area_dst, page_nr)); + count = *area_count(area_dst, page_nr); + if (count != count_verify[page_nr]) { + fprintf(stderr, + "page_nr %lu memory corruption %Lu %Lu\n", + page_nr, count, + count_verify[page_nr]), exit(1); + } + count++; + *area_count(area_dst, page_nr) = count_verify[page_nr] = count; + pthread_mutex_unlock(area_mutex(area_dst, page_nr)); + + if (time(NULL) - start > 1) + fprintf(stderr, + "userfault too slow %ld " + "possible false positive with overcommit\n", + time(NULL) - start); + } + + return NULL; +} + +static int copy_page(unsigned long offset) +{ + struct uffdio_copy uffdio_copy; + + if (offset >= nr_pages * page_size) + fprintf(stderr, "unexpected offset %lu\n", + offset), exit(1); + uffdio_copy.dst = (unsigned long) area_dst + offset; + uffdio_copy.src = (unsigned long) area_src + offset; + uffdio_copy.len = page_size; + uffdio_copy.mode = 0; + uffdio_copy.copy = 0; + if (ioctl(uffd, UFFDIO_COPY, &uffdio_copy)) { + /* real retval in ufdio_copy.copy */ + if (uffdio_copy.copy != -EEXIST) + fprintf(stderr, "UFFDIO_COPY error %Ld\n", + uffdio_copy.copy), exit(1); + } else if (uffdio_copy.copy != page_size) { + fprintf(stderr, "UFFDIO_COPY unexpected copy %Ld\n", + uffdio_copy.copy), exit(1); + } else + return 1; + return 0; +} + +static void *uffd_poll_thread(void *arg) +{ + unsigned long cpu = (unsigned long) arg; + struct pollfd pollfd[2]; + struct uffd_msg msg; + int ret; + unsigned long offset; + char tmp_chr; + unsigned long userfaults = 0; + + pollfd[0].fd = uffd; + pollfd[0].events = POLLIN; + pollfd[1].fd = pipefd[cpu*2]; + pollfd[1].events = POLLIN; + + for (;;) { + ret = poll(pollfd, 2, -1); + if (!ret) + fprintf(stderr, "poll error %d\n", ret), exit(1); + if (ret < 0) + perror("poll"), exit(1); + if (pollfd[1].revents & POLLIN) { + if (read(pollfd[1].fd, &tmp_chr, 1) != 1) + fprintf(stderr, "read pipefd error\n"), + exit(1); + break; + } + if (!(pollfd[0].revents & POLLIN)) + fprintf(stderr, "pollfd[0].revents %d\n", + pollfd[0].revents), exit(1); + ret = read(uffd, &msg, sizeof(msg)); + if (ret < 0) { + if (errno == EAGAIN) + continue; + perror("nonblocking read error"), exit(1); + } + if (msg.event != UFFD_EVENT_PAGEFAULT) + fprintf(stderr, "unexpected msg event %u\n", + msg.event), exit(1); + if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) + fprintf(stderr, "unexpected write fault\n"), exit(1); + offset = (char *)msg.arg.pagefault.address - area_dst; + offset &= ~(page_size-1); + if (copy_page(offset)) + userfaults++; + } + return (void *)userfaults; +} + +pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER; + +static void *uffd_read_thread(void *arg) +{ + unsigned long *this_cpu_userfaults; + struct uffd_msg msg; + unsigned long offset; + int ret; + + this_cpu_userfaults = (unsigned long *) arg; + *this_cpu_userfaults = 0; + + pthread_mutex_unlock(&uffd_read_mutex); + /* from here cancellation is ok */ + + for (;;) { + ret = read(uffd, &msg, sizeof(msg)); + if (ret != sizeof(msg)) { + if (ret < 0) + perror("blocking read error"), exit(1); + else + fprintf(stderr, "short read\n"), exit(1); + } + if (msg.event != UFFD_EVENT_PAGEFAULT) + fprintf(stderr, "unexpected msg event %u\n", + msg.event), exit(1); + if (bounces & BOUNCE_VERIFY && + msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) + fprintf(stderr, "unexpected write fault\n"), exit(1); + offset = (char *)msg.arg.pagefault.address - area_dst; + offset &= ~(page_size-1); + if (copy_page(offset)) + (*this_cpu_userfaults)++; + } + return (void *)NULL; +} + +static void *background_thread(void *arg) +{ + unsigned long cpu = (unsigned long) arg; + unsigned long page_nr; + + for (page_nr = cpu * nr_pages_per_cpu; + page_nr < (cpu+1) * nr_pages_per_cpu; + page_nr++) + copy_page(page_nr * page_size); + + return NULL; +} + +static int stress(unsigned long *userfaults) +{ + unsigned long cpu; + pthread_t locking_threads[nr_cpus]; + pthread_t uffd_threads[nr_cpus]; + pthread_t background_threads[nr_cpus]; + void **_userfaults = (void **) userfaults; + + finished = 0; + for (cpu = 0; cpu < nr_cpus; cpu++) { + if (pthread_create(&locking_threads[cpu], &attr, + locking_thread, (void *)cpu)) + return 1; + if (bounces & BOUNCE_POLL) { + if (pthread_create(&uffd_threads[cpu], &attr, + uffd_poll_thread, (void *)cpu)) + return 1; + } else { + if (pthread_create(&uffd_threads[cpu], &attr, + uffd_read_thread, + &_userfaults[cpu])) + return 1; + pthread_mutex_lock(&uffd_read_mutex); + } + if (pthread_create(&background_threads[cpu], &attr, + background_thread, (void *)cpu)) + return 1; + } + for (cpu = 0; cpu < nr_cpus; cpu++) + if (pthread_join(background_threads[cpu], NULL)) + return 1; + + /* + * Be strict and immediately zap area_src, the whole area has + * been transferred already by the background treads. The + * area_src could then be faulted in in a racy way by still + * running uffdio_threads reading zeropages after we zapped + * area_src (but they're guaranteed to get -EEXIST from + * UFFDIO_COPY without writing zero pages into area_dst + * because the background threads already completed). + */ + if (madvise(area_src, nr_pages * page_size, MADV_DONTNEED)) { + perror("madvise"); + return 1; + } + + for (cpu = 0; cpu < nr_cpus; cpu++) { + char c; + if (bounces & BOUNCE_POLL) { + if (write(pipefd[cpu*2+1], &c, 1) != 1) { + fprintf(stderr, "pipefd write error\n"); + return 1; + } + if (pthread_join(uffd_threads[cpu], &_userfaults[cpu])) + return 1; + } else { + if (pthread_cancel(uffd_threads[cpu])) + return 1; + if (pthread_join(uffd_threads[cpu], NULL)) + return 1; + } + } + + finished = 1; + for (cpu = 0; cpu < nr_cpus; cpu++) + if (pthread_join(locking_threads[cpu], NULL)) + return 1; + + return 0; +} + +static int userfaultfd_stress(void) +{ + void *area; + char *tmp_area; + unsigned long nr; + struct uffdio_register uffdio_register; + struct uffdio_api uffdio_api; + unsigned long cpu; + int uffd_flags; + unsigned long userfaults[nr_cpus]; + + if (posix_memalign(&area, page_size, nr_pages * page_size)) { + fprintf(stderr, "out of memory\n"); + return 1; + } + area_src = area; + if (posix_memalign(&area, page_size, nr_pages * page_size)) { + fprintf(stderr, "out of memory\n"); + return 1; + } + area_dst = area; + + uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); + if (uffd < 0) { + fprintf(stderr, + "userfaultfd syscall not available in this kernel\n"); + return 1; + } + uffd_flags = fcntl(uffd, F_GETFD, NULL); + + uffdio_api.api = UFFD_API; + uffdio_api.features = 0; + if (ioctl(uffd, UFFDIO_API, &uffdio_api)) { + fprintf(stderr, "UFFDIO_API\n"); + return 1; + } + if (uffdio_api.api != UFFD_API) { + fprintf(stderr, "UFFDIO_API error %Lu\n", uffdio_api.api); + return 1; + } + + count_verify = malloc(nr_pages * sizeof(unsigned long long)); + if (!count_verify) { + perror("count_verify"); + return 1; + } + + for (nr = 0; nr < nr_pages; nr++) { + *area_mutex(area_src, nr) = (pthread_mutex_t) + PTHREAD_MUTEX_INITIALIZER; + count_verify[nr] = *area_count(area_src, nr) = 1; + } + + pipefd = malloc(sizeof(int) * nr_cpus * 2); + if (!pipefd) { + perror("pipefd"); + return 1; + } + for (cpu = 0; cpu < nr_cpus; cpu++) { + if (pipe2(&pipefd[cpu*2], O_CLOEXEC | O_NONBLOCK)) { + perror("pipe"); + return 1; + } + } + + if (posix_memalign(&area, page_size, page_size)) { + fprintf(stderr, "out of memory\n"); + return 1; + } + zeropage = area; + bzero(zeropage, page_size); + + pthread_mutex_lock(&uffd_read_mutex); + + pthread_attr_init(&attr); + pthread_attr_setstacksize(&attr, 16*1024*1024); + + while (bounces--) { + unsigned long expected_ioctls; + + printf("bounces: %d, mode:", bounces); + if (bounces & BOUNCE_RANDOM) + printf(" rnd"); + if (bounces & BOUNCE_RACINGFAULTS) + printf(" racing"); + if (bounces & BOUNCE_VERIFY) + printf(" ver"); + if (bounces & BOUNCE_POLL) + printf(" poll"); + printf(", "); + fflush(stdout); + + if (bounces & BOUNCE_POLL) + fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK); + else + fcntl(uffd, F_SETFL, uffd_flags & ~O_NONBLOCK); + + /* register */ + uffdio_register.range.start = (unsigned long) area_dst; + uffdio_register.range.len = nr_pages * page_size; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) { + fprintf(stderr, "register failure\n"); + return 1; + } + expected_ioctls = (1 << _UFFDIO_WAKE) | + (1 << _UFFDIO_COPY) | + (1 << _UFFDIO_ZEROPAGE); + if ((uffdio_register.ioctls & expected_ioctls) != + expected_ioctls) { + fprintf(stderr, + "unexpected missing ioctl for anon memory\n"); + return 1; + } + + /* + * The madvise done previously isn't enough: some + * uffd_thread could have read userfaults (one of + * those already resolved by the background thread) + * and it may be in the process of calling + * UFFDIO_COPY. UFFDIO_COPY will read the zapped + * area_src and it would map a zero page in it (of + * course such a UFFDIO_COPY is perfectly safe as it'd + * return -EEXIST). The problem comes at the next + * bounce though: that racing UFFDIO_COPY would + * generate zeropages in the area_src, so invalidating + * the previous MADV_DONTNEED. Without this additional + * MADV_DONTNEED those zeropages leftovers in the + * area_src would lead to -EEXIST failure during the + * next bounce, effectively leaving a zeropage in the + * area_dst. + * + * Try to comment this out madvise to see the memory + * corruption being caught pretty quick. + * + * khugepaged is also inhibited to collapse THP after + * MADV_DONTNEED only after the UFFDIO_REGISTER, so it's + * required to MADV_DONTNEED here. + */ + if (madvise(area_dst, nr_pages * page_size, MADV_DONTNEED)) { + perror("madvise 2"); + return 1; + } + + /* bounce pass */ + if (stress(userfaults)) + return 1; + + /* unregister */ + if (ioctl(uffd, UFFDIO_UNREGISTER, &uffdio_register.range)) { + fprintf(stderr, "register failure\n"); + return 1; + } + + /* verification */ + if (bounces & BOUNCE_VERIFY) { + for (nr = 0; nr < nr_pages; nr++) { + if (my_bcmp(area_dst, + area_dst + nr * page_size, + sizeof(pthread_mutex_t))) { + fprintf(stderr, + "error mutex 2 %lu\n", + nr); + bounces = 0; + } + if (*area_count(area_dst, nr) != count_verify[nr]) { + fprintf(stderr, + "error area_count %Lu %Lu %lu\n", + *area_count(area_src, nr), + count_verify[nr], + nr); + bounces = 0; + } + } + } + + /* prepare next bounce */ + tmp_area = area_src; + area_src = area_dst; + area_dst = tmp_area; + + printf("userfaults:"); + for (cpu = 0; cpu < nr_cpus; cpu++) + printf(" %lu", userfaults[cpu]); + printf("\n"); + } + + return 0; +} + +int main(int argc, char **argv) +{ + if (argc < 3) + fprintf(stderr, "Usage: \n"), exit(1); + nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); + page_size = sysconf(_SC_PAGE_SIZE); + if ((unsigned long) area_count(NULL, 0) + sizeof(unsigned long long) > + page_size) + fprintf(stderr, "Impossible to run this test\n"), exit(2); + nr_pages_per_cpu = atol(argv[1]) * 1024*1024 / page_size / + nr_cpus; + if (!nr_pages_per_cpu) { + fprintf(stderr, "invalid MiB\n"); + fprintf(stderr, "Usage: \n"), exit(1); + } + bounces = atoi(argv[2]); + if (bounces <= 0) { + fprintf(stderr, "invalid bounces\n"); + fprintf(stderr, "Usage: \n"), exit(1); + } + nr_pages = nr_pages_per_cpu * nr_cpus; + printf("nr_pages: %lu, nr_pages_per_cpu: %lu\n", + nr_pages, nr_pages_per_cpu); + return userfaultfd_stress(); +} -- GitLab From 5b74283ab251b9db55cbbe31d19ca72482103290 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Fri, 4 Sep 2015 15:47:29 -0700 Subject: [PATCH 6438/7006] x86, mm: trace when an IPI is about to be sent When unmapping pages it is necessary to flush the TLB. If that page was accessed by another CPU then an IPI is used to flush the remote CPU. That is a lot of IPIs if kswapd is scanning and unmapping >100K pages per second. There already is a window between when a page is unmapped and when it is TLB flushed. This series increases the window so multiple pages can be flushed using a single IPI. This should be safe or the kernel is hosed already. Patch 1 simply made the rest of the series easier to write as ftrace could identify all the senders of TLB flush IPIS. Patch 2 tracks what CPUs potentially map a PFN and then sends an IPI to flush the entire TLB. Patch 3 tracks when there potentially are writable TLB entries that need to be batched differently Patch 4 increases SWAP_CLUSTER_MAX to further batch flushes The performance impact is documented in the changelogs but in the optimistic case on a 4-socket machine the full series reduces interrupts from 900K interrupts/second to 60K interrupts/second. This patch (of 4): It is easy to trace when an IPI is received to flush a TLB but harder to detect what event sent it. This patch makes it easy to identify the source of IPIs being transmitted for TLB flushes on x86. Signed-off-by: Mel Gorman Reviewed-by: Rik van Riel Reviewed-by: Dave Hansen Acked-by: Ingo Molnar Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/mm/tlb.c | 1 + include/linux/mm_types.h | 1 + include/trace/events/tlb.h | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/arch/x86/mm/tlb.c b/arch/x86/mm/tlb.c index 90b924acd9822..8ddb5d0d66fb6 100644 --- a/arch/x86/mm/tlb.c +++ b/arch/x86/mm/tlb.c @@ -140,6 +140,7 @@ void native_flush_tlb_others(const struct cpumask *cpumask, info.flush_end = end; count_vm_tlb_event(NR_TLB_REMOTE_FLUSH); + trace_tlb_flush(TLB_REMOTE_SEND_IPI, end - start); if (is_uv_system()) { unsigned int cpu; diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index 26a30c3566f0c..c8d0a73d64c45 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -554,6 +554,7 @@ enum tlb_flush_reason { TLB_REMOTE_SHOOTDOWN, TLB_LOCAL_SHOOTDOWN, TLB_LOCAL_MM_SHOOTDOWN, + TLB_REMOTE_SEND_IPI, NR_TLB_FLUSH_REASONS, }; diff --git a/include/trace/events/tlb.h b/include/trace/events/tlb.h index 4250f364a6caa..bc8815f45f3b3 100644 --- a/include/trace/events/tlb.h +++ b/include/trace/events/tlb.h @@ -11,7 +11,8 @@ EM( TLB_FLUSH_ON_TASK_SWITCH, "flush on task switch" ) \ EM( TLB_REMOTE_SHOOTDOWN, "remote shootdown" ) \ EM( TLB_LOCAL_SHOOTDOWN, "local shootdown" ) \ - EMe( TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" ) + EM( TLB_LOCAL_MM_SHOOTDOWN, "local mm shootdown" ) \ + EMe( TLB_REMOTE_SEND_IPI, "remote ipi send" ) /* * First define the enums in TLB_FLUSH_REASON to be exported to userspace -- GitLab From 72b252aed506b8f1a03f7abd29caef4cdf6a043b Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Fri, 4 Sep 2015 15:47:32 -0700 Subject: [PATCH 6439/7006] mm: send one IPI per CPU to TLB flush all entries after unmapping pages An IPI is sent to flush remote TLBs when a page is unmapped that was potentially accesssed by other CPUs. There are many circumstances where this happens but the obvious one is kswapd reclaiming pages belonging to a running process as kswapd and the task are likely running on separate CPUs. On small machines, this is not a significant problem but as machine gets larger with more cores and more memory, the cost of these IPIs can be high. This patch uses a simple structure that tracks CPUs that potentially have TLB entries for pages being unmapped. When the unmapping is complete, the full TLB is flushed on the assumption that a refill cost is lower than flushing individual entries. Architectures wishing to do this must give the following guarantee. If a clean page is unmapped and not immediately flushed, the architecture must guarantee that a write to that linear address from a CPU with a cached TLB entry will trap a page fault. This is essentially what the kernel already depends on but the window is much larger with this patch applied and is worth highlighting. The architecture should consider whether the cost of the full TLB flush is higher than sending an IPI to flush each individual entry. An additional architecture helper called flush_tlb_local is required. It's a trivial wrapper with some accounting in the x86 case. The impact of this patch depends on the workload as measuring any benefit requires both mapped pages co-located on the LRU and memory pressure. The case with the biggest impact is multiple processes reading mapped pages taken from the vm-scalability test suite. The test case uses NR_CPU readers of mapped files that consume 10*RAM. Linear mapped reader on a 4-node machine with 64G RAM and 48 CPUs 4.2.0-rc1 4.2.0-rc1 vanilla flushfull-v7 Ops lru-file-mmap-read-elapsed 159.62 ( 0.00%) 120.68 ( 24.40%) Ops lru-file-mmap-read-time_range 30.59 ( 0.00%) 2.80 ( 90.85%) Ops lru-file-mmap-read-time_stddv 6.70 ( 0.00%) 0.64 ( 90.38%) 4.2.0-rc1 4.2.0-rc1 vanilla flushfull-v7 User 581.00 611.43 System 5804.93 4111.76 Elapsed 161.03 122.12 This is showing that the readers completed 24.40% faster with 29% less system CPU time. From vmstats, it is known that the vanilla kernel was interrupted roughly 900K times per second during the steady phase of the test and the patched kernel was interrupts 180K times per second. The impact is lower on a single socket machine. 4.2.0-rc1 4.2.0-rc1 vanilla flushfull-v7 Ops lru-file-mmap-read-elapsed 25.33 ( 0.00%) 20.38 ( 19.54%) Ops lru-file-mmap-read-time_range 0.91 ( 0.00%) 1.44 (-58.24%) Ops lru-file-mmap-read-time_stddv 0.28 ( 0.00%) 0.47 (-65.34%) 4.2.0-rc1 4.2.0-rc1 vanilla flushfull-v7 User 58.09 57.64 System 111.82 76.56 Elapsed 27.29 22.55 It's still a noticeable improvement with vmstat showing interrupts went from roughly 500K per second to 45K per second. The patch will have no impact on workloads with no memory pressure or have relatively few mapped pages. It will have an unpredictable impact on the workload running on the CPU being flushed as it'll depend on how many TLB entries need to be refilled and how long that takes. Worst case, the TLB will be completely cleared of active entries when the target PFNs were not resident at all. [sasha.levin@oracle.com: trace tlb flush after disabling preemption in try_to_unmap_flush] Signed-off-by: Mel Gorman Reviewed-by: Rik van Riel Cc: Dave Hansen Acked-by: Ingo Molnar Cc: Linus Torvalds Signed-off-by: Sasha Levin Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/Kconfig | 1 + arch/x86/include/asm/tlbflush.h | 6 ++ include/linux/rmap.h | 3 + include/linux/sched.h | 16 +++++ init/Kconfig | 10 +++ mm/internal.h | 11 ++++ mm/rmap.c | 104 +++++++++++++++++++++++++++++++- mm/vmscan.c | 23 ++++++- 8 files changed, 172 insertions(+), 2 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 48f7433dac6f5..117e2f373e50d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -41,6 +41,7 @@ config X86 select ARCH_USE_CMPXCHG_LOCKREF if X86_64 select ARCH_USE_QUEUED_RWLOCKS select ARCH_USE_QUEUED_SPINLOCKS + select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH if SMP select ARCH_WANTS_DYNAMIC_TASK_STRUCT select ARCH_WANT_FRAME_POINTERS select ARCH_WANT_IPC_PARSE_VERSION if X86_32 diff --git a/arch/x86/include/asm/tlbflush.h b/arch/x86/include/asm/tlbflush.h index cd791948b286a..6df2029405a3a 100644 --- a/arch/x86/include/asm/tlbflush.h +++ b/arch/x86/include/asm/tlbflush.h @@ -261,6 +261,12 @@ static inline void reset_lazy_tlbstate(void) #endif /* SMP */ +/* Not inlined due to inc_irq_stat not being defined yet */ +#define flush_tlb_local() { \ + inc_irq_stat(irq_tlb_count); \ + local_flush_tlb(); \ +} + #ifndef CONFIG_PARAVIRT #define flush_tlb_others(mask, mm, start, end) \ native_flush_tlb_others(mask, mm, start, end) diff --git a/include/linux/rmap.h b/include/linux/rmap.h index c89c53a113a8d..29446aeef36e5 100644 --- a/include/linux/rmap.h +++ b/include/linux/rmap.h @@ -89,6 +89,9 @@ enum ttu_flags { TTU_IGNORE_MLOCK = (1 << 8), /* ignore mlock */ TTU_IGNORE_ACCESS = (1 << 9), /* don't age */ TTU_IGNORE_HWPOISON = (1 << 10),/* corrupted page is recoverable */ + TTU_BATCH_FLUSH = (1 << 11), /* Batch TLB flushes where possible + * and caller guarantees they will + * do a final flush if necessary */ }; #ifdef CONFIG_MMU diff --git a/include/linux/sched.h b/include/linux/sched.h index 119823decc463..3c602c20c717c 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1344,6 +1344,18 @@ enum perf_event_task_context { perf_nr_task_contexts, }; +/* Track pages that require TLB flushes */ +struct tlbflush_unmap_batch { + /* + * Each bit set is a CPU that potentially has a TLB entry for one of + * the PFNs being flushed. See set_tlb_ubc_flush_pending(). + */ + struct cpumask cpumask; + + /* True if any bit in cpumask is set */ + bool flush_required; +}; + struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ void *stack; @@ -1700,6 +1712,10 @@ struct task_struct { unsigned long numa_pages_migrated; #endif /* CONFIG_NUMA_BALANCING */ +#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH + struct tlbflush_unmap_batch tlb_ubc; +#endif + struct rcu_head rcu; /* diff --git a/init/Kconfig b/init/Kconfig index 161acd8bc56fc..cf7e4824c8d0d 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -882,6 +882,16 @@ config GENERIC_SCHED_CLOCK config ARCH_SUPPORTS_NUMA_BALANCING bool +# +# For architectures that prefer to flush all TLBs after a number of pages +# are unmapped instead of sending one IPI per page to flush. The architecture +# must provide guarantees on what happens if a clean TLB cache entry is +# written after the unmap. Details are in mm/rmap.c near the check for +# should_defer_flush. The architecture should also consider if the full flush +# and the refill costs are offset by the savings of sending fewer IPIs. +config ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH + bool + # # For architectures that know their GCC __int128 support is sound # diff --git a/mm/internal.h b/mm/internal.h index 36b23f1e2ca62..bd6372ac5f7f7 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -426,4 +426,15 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone, #define ALLOC_CMA 0x80 /* allow allocations from CMA areas */ #define ALLOC_FAIR 0x100 /* fair zone allocation */ +enum ttu_flags; +struct tlbflush_unmap_batch; + +#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH +void try_to_unmap_flush(void); +#else +static inline void try_to_unmap_flush(void) +{ +} + +#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ #endif /* __MM_INTERNAL_H */ diff --git a/mm/rmap.c b/mm/rmap.c index 171b68768df14..326d5d89e45cd 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -62,6 +62,8 @@ #include +#include + #include "internal.h" static struct kmem_cache *anon_vma_cachep; @@ -583,6 +585,89 @@ vma_address(struct page *page, struct vm_area_struct *vma) return address; } +#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH +static void percpu_flush_tlb_batch_pages(void *data) +{ + /* + * All TLB entries are flushed on the assumption that it is + * cheaper to flush all TLBs and let them be refilled than + * flushing individual PFNs. Note that we do not track mm's + * to flush as that might simply be multiple full TLB flushes + * for no gain. + */ + count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED); + flush_tlb_local(); +} + +/* + * Flush TLB entries for recently unmapped pages from remote CPUs. It is + * important if a PTE was dirty when it was unmapped that it's flushed + * before any IO is initiated on the page to prevent lost writes. Similarly, + * it must be flushed before freeing to prevent data leakage. + */ +void try_to_unmap_flush(void) +{ + struct tlbflush_unmap_batch *tlb_ubc = ¤t->tlb_ubc; + int cpu; + + if (!tlb_ubc->flush_required) + return; + + cpu = get_cpu(); + + trace_tlb_flush(TLB_REMOTE_SHOOTDOWN, -1UL); + + if (cpumask_test_cpu(cpu, &tlb_ubc->cpumask)) + percpu_flush_tlb_batch_pages(&tlb_ubc->cpumask); + + if (cpumask_any_but(&tlb_ubc->cpumask, cpu) < nr_cpu_ids) { + smp_call_function_many(&tlb_ubc->cpumask, + percpu_flush_tlb_batch_pages, (void *)tlb_ubc, true); + } + cpumask_clear(&tlb_ubc->cpumask); + tlb_ubc->flush_required = false; + put_cpu(); +} + +static void set_tlb_ubc_flush_pending(struct mm_struct *mm, + struct page *page) +{ + struct tlbflush_unmap_batch *tlb_ubc = ¤t->tlb_ubc; + + cpumask_or(&tlb_ubc->cpumask, &tlb_ubc->cpumask, mm_cpumask(mm)); + tlb_ubc->flush_required = true; +} + +/* + * Returns true if the TLB flush should be deferred to the end of a batch of + * unmap operations to reduce IPIs. + */ +static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags) +{ + bool should_defer = false; + + if (!(flags & TTU_BATCH_FLUSH)) + return false; + + /* If remote CPUs need to be flushed then defer batch the flush */ + if (cpumask_any_but(mm_cpumask(mm), get_cpu()) < nr_cpu_ids) + should_defer = true; + put_cpu(); + + return should_defer; +} +#else +static void set_tlb_ubc_flush_pending(struct mm_struct *mm, + struct page *page) +{ +} + +static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags) +{ + return false; +} +#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ + /* * At what user virtual address is page expected in vma? * Caller should check the page is actually part of the vma. @@ -1220,7 +1305,24 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, /* Nuke the page table entry. */ flush_cache_page(vma, address, page_to_pfn(page)); - pteval = ptep_clear_flush(vma, address, pte); + if (should_defer_flush(mm, flags)) { + /* + * We clear the PTE but do not flush so potentially a remote + * CPU could still be writing to the page. If the entry was + * previously clean then the architecture must guarantee that + * a clear->dirty transition on a cached TLB entry is written + * through and traps if the PTE is unmapped. + */ + pteval = ptep_get_and_clear(mm, address, pte); + + /* Potentially writable TLBs must be flushed before IO */ + if (pte_dirty(pteval)) + flush_tlb_page(vma, address); + else + set_tlb_ubc_flush_pending(mm, page); + } else { + pteval = ptep_clear_flush(vma, address, pte); + } /* Move the dirty bit to the physical page now the pte is gone. */ if (pte_dirty(pteval)) diff --git a/mm/vmscan.c b/mm/vmscan.c index 8286938c70ded..99ec00d6a5dd6 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1057,7 +1057,8 @@ static unsigned long shrink_page_list(struct list_head *page_list, * processes. Try to unmap it here. */ if (page_mapped(page) && mapping) { - switch (try_to_unmap(page, ttu_flags)) { + switch (try_to_unmap(page, + ttu_flags|TTU_BATCH_FLUSH)) { case SWAP_FAIL: goto activate_locked; case SWAP_AGAIN: @@ -1208,6 +1209,7 @@ keep: } mem_cgroup_uncharge_list(&free_pages); + try_to_unmap_flush(); free_hot_cold_page_list(&free_pages, true); list_splice(&ret_pages, page_list); @@ -2151,6 +2153,23 @@ out: } } +#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH +static void init_tlb_ubc(void) +{ + /* + * This deliberately does not clear the cpumask as it's expensive + * and unnecessary. If there happens to be data in there then the + * first SWAP_CLUSTER_MAX pages will send an unnecessary IPI and + * then will be cleared. + */ + current->tlb_ubc.flush_required = false; +} +#else +static inline void init_tlb_ubc(void) +{ +} +#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ + /* * This is a basic per-zone page freer. Used by both kswapd and direct reclaim. */ @@ -2185,6 +2204,8 @@ static void shrink_lruvec(struct lruvec *lruvec, int swappiness, scan_adjusted = (global_reclaim(sc) && !current_is_kswapd() && sc->priority == DEF_PRIORITY); + init_tlb_ubc(); + blk_start_plug(&plug); while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || nr[LRU_INACTIVE_FILE]) { -- GitLab From d950c9477d51f0cefc2ed3cf76e695d46af0d9c1 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Fri, 4 Sep 2015 15:47:35 -0700 Subject: [PATCH 6440/7006] mm: defer flush of writable TLB entries If a PTE is unmapped and it's dirty then it was writable recently. Due to deferred TLB flushing, it's best to assume a writable TLB cache entry exists. With that assumption, the TLB must be flushed before any IO can start or the page is freed to avoid lost writes or data corruption. This patch defers flushing of potentially writable TLBs as long as possible. Signed-off-by: Mel Gorman Reviewed-by: Rik van Riel Cc: Dave Hansen Acked-by: Ingo Molnar Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/sched.h | 7 +++++++ mm/internal.h | 4 ++++ mm/rmap.c | 28 +++++++++++++++++++++------- mm/vmscan.c | 7 ++++++- 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 3c602c20c717c..a4ab9daa387c0 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1354,6 +1354,13 @@ struct tlbflush_unmap_batch { /* True if any bit in cpumask is set */ bool flush_required; + + /* + * If true then the PTE was dirty when unmapped. The entry must be + * flushed before IO is initiated or a stale TLB entry potentially + * allows an update without redirtying the page. + */ + bool writable; }; struct task_struct { diff --git a/mm/internal.h b/mm/internal.h index bd6372ac5f7f7..1195dd2d6a2b9 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -431,10 +431,14 @@ struct tlbflush_unmap_batch; #ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH void try_to_unmap_flush(void); +void try_to_unmap_flush_dirty(void); #else static inline void try_to_unmap_flush(void) { } +static inline void try_to_unmap_flush_dirty(void) +{ +} #endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ #endif /* __MM_INTERNAL_H */ diff --git a/mm/rmap.c b/mm/rmap.c index 326d5d89e45cd..0db38e7d0a72b 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -626,16 +626,34 @@ void try_to_unmap_flush(void) } cpumask_clear(&tlb_ubc->cpumask); tlb_ubc->flush_required = false; + tlb_ubc->writable = false; put_cpu(); } +/* Flush iff there are potentially writable TLB entries that can race with IO */ +void try_to_unmap_flush_dirty(void) +{ + struct tlbflush_unmap_batch *tlb_ubc = ¤t->tlb_ubc; + + if (tlb_ubc->writable) + try_to_unmap_flush(); +} + static void set_tlb_ubc_flush_pending(struct mm_struct *mm, - struct page *page) + struct page *page, bool writable) { struct tlbflush_unmap_batch *tlb_ubc = ¤t->tlb_ubc; cpumask_or(&tlb_ubc->cpumask, &tlb_ubc->cpumask, mm_cpumask(mm)); tlb_ubc->flush_required = true; + + /* + * If the PTE was dirty then it's best to assume it's writable. The + * caller must use try_to_unmap_flush_dirty() or try_to_unmap_flush() + * before the page is queued for IO. + */ + if (writable) + tlb_ubc->writable = true; } /* @@ -658,7 +676,7 @@ static bool should_defer_flush(struct mm_struct *mm, enum ttu_flags flags) } #else static void set_tlb_ubc_flush_pending(struct mm_struct *mm, - struct page *page) + struct page *page, bool writable) { } @@ -1315,11 +1333,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, */ pteval = ptep_get_and_clear(mm, address, pte); - /* Potentially writable TLBs must be flushed before IO */ - if (pte_dirty(pteval)) - flush_tlb_page(vma, address); - else - set_tlb_ubc_flush_pending(mm, page); + set_tlb_ubc_flush_pending(mm, page, pte_dirty(pteval)); } else { pteval = ptep_clear_flush(vma, address, pte); } diff --git a/mm/vmscan.c b/mm/vmscan.c index 99ec00d6a5dd6..b1139039122a0 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1098,7 +1098,12 @@ static unsigned long shrink_page_list(struct list_head *page_list, if (!sc->may_writepage) goto keep_locked; - /* Page is dirty, try to write it out here */ + /* + * Page is dirty. Flush the TLB if a writable entry + * potentially exists to avoid CPU writes after IO + * starts and then write it out here. + */ + try_to_unmap_flush_dirty(); switch (pageout(page, mapping, sc)) { case PAGE_KEEP: goto keep_locked; -- GitLab From c7e1e3ccfbd153c890240a391f258efaedfa94d0 Mon Sep 17 00:00:00 2001 From: Mel Gorman Date: Fri, 4 Sep 2015 15:47:38 -0700 Subject: [PATCH 6441/7006] Documentation/features/vm: add feature description and arch support status for batched TLB flush after unmap Signed-off-by: Mel Gorman Acked-by: Ingo Molnar Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../features/vm/TLB/arch-support.txt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 Documentation/features/vm/TLB/arch-support.txt diff --git a/Documentation/features/vm/TLB/arch-support.txt b/Documentation/features/vm/TLB/arch-support.txt new file mode 100644 index 0000000000000..261b92e2fb1ae --- /dev/null +++ b/Documentation/features/vm/TLB/arch-support.txt @@ -0,0 +1,40 @@ +# +# Feature name: batch-unmap-tlb-flush +# Kconfig: ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH +# description: arch supports deferral of TLB flush until multiple pages are unmapped +# + ----------------------- + | arch |status| + ----------------------- + | alpha: | TODO | + | arc: | TODO | + | arm: | TODO | + | arm64: | TODO | + | avr32: | .. | + | blackfin: | TODO | + | c6x: | .. | + | cris: | .. | + | frv: | .. | + | h8300: | .. | + | hexagon: | TODO | + | ia64: | TODO | + | m32r: | TODO | + | m68k: | .. | + | metag: | TODO | + | microblaze: | .. | + | mips: | TODO | + | mn10300: | TODO | + | nios2: | .. | + | openrisc: | .. | + | parisc: | TODO | + | powerpc: | TODO | + | s390: | TODO | + | score: | .. | + | sh: | TODO | + | sparc: | TODO | + | tile: | TODO | + | um: | .. | + | unicore32: | .. | + | x86: | ok | + | xtensa: | TODO | + ----------------------- -- GitLab From c0a294988322a804901fe24222027fe8a34defcb Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Fri, 4 Sep 2015 15:47:38 -0700 Subject: [PATCH 6442/7006] mm/memblock: WARN_ON when nid differs from overlap region Each memblock_region has nid to indicates the Node ID of this range. For the overlap case, memblock_add_range() inserts the lower part and leave the upper part as indicated in the overlapped region. If the nid of the new range differs from the overlapped region, the information recorded is not correct. This patch adds a WARN_ON when the nid of the new range differs from the overlapped region. Signed-off-by: Wei Yang Acked-by: David Rientjes Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memblock.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/memblock.c b/mm/memblock.c index 87108e77e476a..95ce68c6da8ad 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -566,6 +566,9 @@ repeat: * area, insert that portion. */ if (rbase > base) { +#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP + WARN_ON(nid != memblock_get_region_node(rgn)); +#endif nr_new++; if (insert) memblock_insert_region(type, i++, base, -- GitLab From 73858173593c31cb94bce63fe1c24eb803bb04e6 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 4 Sep 2015 15:47:43 -0700 Subject: [PATCH 6443/7006] genalloc: add name arg to gen_pool_get() and devm_gen_pool_create() This change modifies gen_pool_get() and devm_gen_pool_create() client interfaces adding one more argument "name" of a gen_pool object. Due to implementation gen_pool_get() is capable to retrieve only one gen_pool associated with a device even if multiple gen_pools are created, fortunately right at the moment it is sufficient for the clients, hence provide NULL as a valid argument on both producer devm_gen_pool_create() and consumer gen_pool_get() sides. Because only one created gen_pool per device is addressable, explicitly add a restriction to devm_gen_pool_create() to create only one gen_pool per device, this implies two possible error codes returned by the function, account it on client side (only misc/sram). This completes client side changes related to genalloc updates. [akpm@linux-foundation.org: gen_pool_get() cleanup] Signed-off-by: Vladimir Zapolskiy Cc: Philipp Zabel Cc: Greg Kroah-Hartman Cc: Russell King Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Jean-Christophe Plagniol-Villard Cc: Shawn Guo Cc: Sascha Hauer Cc: Mauro Carvalho Chehab Cc: Arnd Bergmann Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/mach-at91/pm.c | 2 +- arch/arm/mach-imx/pm-imx5.c | 2 +- arch/arm/mach-imx/pm-imx6.c | 2 +- arch/arm/mach-socfpga/pm.c | 2 +- drivers/media/platform/coda/coda-common.c | 2 +- drivers/misc/sram.c | 8 ++-- include/linux/genalloc.h | 4 +- lib/genalloc.c | 49 +++++++++++++---------- 8 files changed, 39 insertions(+), 32 deletions(-) diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c index 265ffeb2037ec..80e277cfcc8b6 100644 --- a/arch/arm/mach-at91/pm.c +++ b/arch/arm/mach-at91/pm.c @@ -369,7 +369,7 @@ static void __init at91_pm_sram_init(void) return; } - sram_pool = gen_pool_get(&pdev->dev); + sram_pool = gen_pool_get(&pdev->dev, NULL); if (!sram_pool) { pr_warn("%s: sram pool unavailable!\n", __func__); return; diff --git a/arch/arm/mach-imx/pm-imx5.c b/arch/arm/mach-imx/pm-imx5.c index 1885676c23c08..532d4b08276dc 100644 --- a/arch/arm/mach-imx/pm-imx5.c +++ b/arch/arm/mach-imx/pm-imx5.c @@ -297,7 +297,7 @@ static int __init imx_suspend_alloc_ocram( goto put_node; } - ocram_pool = gen_pool_get(&pdev->dev); + ocram_pool = gen_pool_get(&pdev->dev, NULL); if (!ocram_pool) { pr_warn("%s: ocram pool unavailable!\n", __func__); ret = -ENODEV; diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c index 93ecf559d06d6..8ff8fc0b261cc 100644 --- a/arch/arm/mach-imx/pm-imx6.c +++ b/arch/arm/mach-imx/pm-imx6.c @@ -451,7 +451,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata) goto put_node; } - ocram_pool = gen_pool_get(&pdev->dev); + ocram_pool = gen_pool_get(&pdev->dev, NULL); if (!ocram_pool) { pr_warn("%s: ocram pool unavailable!\n", __func__); ret = -ENODEV; diff --git a/arch/arm/mach-socfpga/pm.c b/arch/arm/mach-socfpga/pm.c index 6a4199f2bffb8..c378ab0c24317 100644 --- a/arch/arm/mach-socfpga/pm.c +++ b/arch/arm/mach-socfpga/pm.c @@ -56,7 +56,7 @@ static int socfpga_setup_ocram_self_refresh(void) goto put_node; } - ocram_pool = gen_pool_get(&pdev->dev); + ocram_pool = gen_pool_get(&pdev->dev, NULL); if (!ocram_pool) { pr_warn("%s: ocram pool unavailable!\n", __func__); ret = -ENODEV; diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index 58f65486de332..284ac4c934ba9 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2157,7 +2157,7 @@ static int coda_probe(struct platform_device *pdev) /* Get IRAM pool from device tree or platform data */ pool = of_gen_pool_get(np, "iram", 0); if (!pool && pdata) - pool = gen_pool_get(pdata->iram_dev); + pool = gen_pool_get(pdata->iram_dev, NULL); if (!pool) { dev_err(&pdev->dev, "iram pool not available\n"); return -ENOMEM; diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index 15c33cc34a802..431e1dd528bcb 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -186,10 +186,10 @@ static int sram_probe(struct platform_device *pdev) if (IS_ERR(sram->virt_base)) return PTR_ERR(sram->virt_base); - sram->pool = devm_gen_pool_create(sram->dev, - ilog2(SRAM_GRANULARITY), -1); - if (!sram->pool) - return -ENOMEM; + sram->pool = devm_gen_pool_create(sram->dev, ilog2(SRAM_GRANULARITY), + NUMA_NO_NODE, NULL); + if (IS_ERR(sram->pool)) + return PTR_ERR(sram->pool); ret = sram_reserve_regions(sram, res); if (ret) diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 5383bb1394a1a..6afa65e6cdb7e 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -118,8 +118,8 @@ extern unsigned long gen_pool_best_fit(unsigned long *map, unsigned long size, unsigned long start, unsigned int nr, void *data); extern struct gen_pool *devm_gen_pool_create(struct device *dev, - int min_alloc_order, int nid); -extern struct gen_pool *gen_pool_get(struct device *dev); + int min_alloc_order, int nid, const char *name); +extern struct gen_pool *gen_pool_get(struct device *dev, const char *name); bool addr_in_gen_pool(struct gen_pool *pool, unsigned long start, size_t size); diff --git a/lib/genalloc.c b/lib/genalloc.c index daf0afb6d979e..b13cfd1a366ef 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -570,24 +570,47 @@ static void devm_gen_pool_release(struct device *dev, void *res) gen_pool_destroy(*(struct gen_pool **)res); } +/** + * gen_pool_get - Obtain the gen_pool (if any) for a device + * @dev: device to retrieve the gen_pool from + * @name: name of a gen_pool or NULL, identifies a particular gen_pool on device + * + * Returns the gen_pool for the device if one is present, or NULL. + */ +struct gen_pool *gen_pool_get(struct device *dev, const char *name) +{ + struct gen_pool **p; + + p = devres_find(dev, devm_gen_pool_release, NULL, NULL); + if (!p) + return NULL; + return *p; +} +EXPORT_SYMBOL_GPL(gen_pool_get); + /** * devm_gen_pool_create - managed gen_pool_create * @dev: device that provides the gen_pool * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents - * @nid: node id of the node the pool structure should be allocated on, or -1 + * @nid: node selector for allocated gen_pool, %NUMA_NO_NODE for all nodes + * @name: name of a gen_pool or NULL, identifies a particular gen_pool on device * * Create a new special memory pool that can be used to manage special purpose * memory not managed by the regular kmalloc/kfree interface. The pool will be * automatically destroyed by the device management code. */ struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order, - int nid) + int nid, const char *name) { struct gen_pool **ptr, *pool; + /* Check that genpool to be created is uniquely addressed on device */ + if (gen_pool_get(dev, name)) + return ERR_PTR(-EINVAL); + ptr = devres_alloc(devm_gen_pool_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) - return NULL; + return ERR_PTR(-ENOMEM); pool = gen_pool_create(min_alloc_order, nid); if (pool) { @@ -595,29 +618,13 @@ struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order, devres_add(dev, ptr); } else { devres_free(ptr); + return ERR_PTR(-ENOMEM); } return pool; } EXPORT_SYMBOL(devm_gen_pool_create); -/** - * gen_pool_get - Obtain the gen_pool (if any) for a device - * @dev: device to retrieve the gen_pool from - * - * Returns the gen_pool for the device if one is present, or NULL. - */ -struct gen_pool *gen_pool_get(struct device *dev) -{ - struct gen_pool **p = devres_find(dev, devm_gen_pool_release, NULL, - NULL); - - if (!p) - return NULL; - return *p; -} -EXPORT_SYMBOL_GPL(gen_pool_get); - #ifdef CONFIG_OF /** * of_gen_pool_get - find a pool by phandle property @@ -642,7 +649,7 @@ struct gen_pool *of_gen_pool_get(struct device_node *np, of_node_put(np_pool); if (!pdev) return NULL; - return gen_pool_get(&pdev->dev); + return gen_pool_get(&pdev->dev, NULL); } EXPORT_SYMBOL_GPL(of_gen_pool_get); #endif /* CONFIG_OF */ -- GitLab From c98c36355dd6d5c4433c8d17e8eb839ca9b97606 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Fri, 4 Sep 2015 15:47:47 -0700 Subject: [PATCH 6444/7006] genalloc: add support of multiple gen_pools per device This change fills devm_gen_pool_create()/gen_pool_get() "name" argument stub with contents and extends of_gen_pool_get() functionality on this basis. If there is no associated platform device with a device node passed to of_gen_pool_get(), the function attempts to get a label property or device node name (= repeats MTD OF partition standard) and seeks for a named gen_pool registered by device of the parent device node. The main idea of the change is to allow registration of independent gen_pools under the same umbrella device, say "partitions" on "storage device", the original functionality of one "partition" per "storage device" is untouched. [akpm@linux-foundation.org: fix constness in devres_find()] [dan.carpenter@oracle.com: freeing const data pointers] Signed-off-by: Vladimir Zapolskiy Cc: Philipp Zabel Cc: Greg Kroah-Hartman Cc: Russell King Cc: Nicolas Ferre Cc: Alexandre Belloni Cc: Jean-Christophe Plagniol-Villard Cc: Shawn Guo Cc: Sascha Hauer Cc: Mauro Carvalho Chehab Cc: Arnd Bergmann Signed-off-by: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/genalloc.h | 2 ++ lib/genalloc.c | 71 ++++++++++++++++++++++++++++++++-------- 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/include/linux/genalloc.h b/include/linux/genalloc.h index 6afa65e6cdb7e..7ff168d06967c 100644 --- a/include/linux/genalloc.h +++ b/include/linux/genalloc.h @@ -59,6 +59,8 @@ struct gen_pool { genpool_algo_t algo; /* allocation function */ void *data; + + const char *name; }; /* diff --git a/lib/genalloc.c b/lib/genalloc.c index b13cfd1a366ef..116a166b096f0 100644 --- a/lib/genalloc.c +++ b/lib/genalloc.c @@ -160,6 +160,7 @@ struct gen_pool *gen_pool_create(int min_alloc_order, int nid) pool->min_alloc_order = min_alloc_order; pool->algo = gen_pool_first_fit; pool->data = NULL; + pool->name = NULL; } return pool; } @@ -252,8 +253,8 @@ void gen_pool_destroy(struct gen_pool *pool) kfree(chunk); } + kfree_const(pool->name); kfree(pool); - return; } EXPORT_SYMBOL(gen_pool_destroy); @@ -570,6 +571,20 @@ static void devm_gen_pool_release(struct device *dev, void *res) gen_pool_destroy(*(struct gen_pool **)res); } +static int devm_gen_pool_match(struct device *dev, void *res, void *data) +{ + struct gen_pool **p = res; + + /* NULL data matches only a pool without an assigned name */ + if (!data && !(*p)->name) + return 1; + + if (!data || !(*p)->name) + return 0; + + return !strcmp((*p)->name, data); +} + /** * gen_pool_get - Obtain the gen_pool (if any) for a device * @dev: device to retrieve the gen_pool from @@ -581,7 +596,8 @@ struct gen_pool *gen_pool_get(struct device *dev, const char *name) { struct gen_pool **p; - p = devres_find(dev, devm_gen_pool_release, NULL, NULL); + p = devres_find(dev, devm_gen_pool_release, devm_gen_pool_match, + (void *)name); if (!p) return NULL; return *p; @@ -603,25 +619,38 @@ struct gen_pool *devm_gen_pool_create(struct device *dev, int min_alloc_order, int nid, const char *name) { struct gen_pool **ptr, *pool; + const char *pool_name = NULL; /* Check that genpool to be created is uniquely addressed on device */ if (gen_pool_get(dev, name)) return ERR_PTR(-EINVAL); + if (name) { + pool_name = kstrdup_const(name, GFP_KERNEL); + if (!pool_name) + return ERR_PTR(-ENOMEM); + } + ptr = devres_alloc(devm_gen_pool_release, sizeof(*ptr), GFP_KERNEL); if (!ptr) - return ERR_PTR(-ENOMEM); + goto free_pool_name; pool = gen_pool_create(min_alloc_order, nid); - if (pool) { - *ptr = pool; - devres_add(dev, ptr); - } else { - devres_free(ptr); - return ERR_PTR(-ENOMEM); - } + if (!pool) + goto free_devres; + + *ptr = pool; + pool->name = pool_name; + devres_add(dev, ptr); return pool; + +free_devres: + devres_free(ptr); +free_pool_name: + kfree_const(pool_name); + + return ERR_PTR(-ENOMEM); } EXPORT_SYMBOL(devm_gen_pool_create); @@ -640,16 +669,30 @@ struct gen_pool *of_gen_pool_get(struct device_node *np, const char *propname, int index) { struct platform_device *pdev; - struct device_node *np_pool; + struct device_node *np_pool, *parent; + const char *name = NULL; + struct gen_pool *pool = NULL; np_pool = of_parse_phandle(np, propname, index); if (!np_pool) return NULL; + pdev = of_find_device_by_node(np_pool); + if (!pdev) { + /* Check if named gen_pool is created by parent node device */ + parent = of_get_parent(np_pool); + pdev = of_find_device_by_node(parent); + of_node_put(parent); + + of_property_read_string(np_pool, "label", &name); + if (!name) + name = np_pool->name; + } + if (pdev) + pool = gen_pool_get(&pdev->dev, name); of_node_put(np_pool); - if (!pdev) - return NULL; - return gen_pool_get(&pdev->dev, NULL); + + return pool; } EXPORT_SYMBOL_GPL(of_gen_pool_get); #endif /* CONFIG_OF */ -- GitLab From ce9ce6659a5775047ad529ed77ab119da5fb8b0c Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 4 Sep 2015 15:47:50 -0700 Subject: [PATCH 6445/7006] mm: memcontrol: bring back the VM_BUG_ON() in mem_cgroup_swapout() Clark stumbled over a VM_BUG_ON() in -RT which was then was removed by Johannes in commit f371763a79d ("mm: memcontrol: fix false-positive VM_BUG_ON() on -rt"). The comment before that patch was a tiny bit better than it is now. While the patch claimed to fix a false-postive on -RT this was not the case. None of the -RT folks ACKed it and it was not a false positive report. That was a *real* problem. This patch updates the comment that is improper because it refers to "disabled preemption" as a consequence of that lock being taken. A spin_lock() disables preemption, true, but in this case the code relies on the fact that the lock _also_ disables interrupts once it is acquired. And this is the important detail (which was checked the VM_BUG_ON()) which needs to be pointed out. This is the hint one needs while looking at the code. It was explained by Johannes on the list that the per-CPU variables are protected by local_irq_save(). The BUG_ON() was helpful. This code has been workarounded in -RT in the meantime. I wouldn't mind running into more of those if the code in question uses *special* kind of locking since now there is no verification (in terms of lockdep or BUG_ON()) and therefore I bring the VM_BUG_ON() check back in. The two functions after the comment could also have a "local_irq_save()" dance around them in order to serialize access to the per-CPU variables. This has been avoided because the interrupts should be off. Signed-off-by: Sebastian Andrzej Siewior Acked-by: Johannes Weiner Cc: Thomas Gleixner Cc: Steven Rostedt Cc: Clark Williams Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index acb93c554f6e8..1af057575ce9e 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -5965,7 +5965,13 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry) if (!mem_cgroup_is_root(memcg)) page_counter_uncharge(&memcg->memory, 1); - /* Caller disabled preemption with mapping->tree_lock */ + /* + * Interrupts should be disabled here because the caller holds the + * mapping->tree_lock lock which is taken with interrupts-off. It is + * important here to have the interrupts disabled because it is the + * only synchronisation we have for udpating the per-CPU variables. + */ + VM_BUG_ON(!irqs_disabled()); mem_cgroup_charge_statistics(memcg, page, -1); memcg_check_events(memcg, page); } -- GitLab From d899844e9c98c9c74b4d9926fd3bd66a225f6978 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 4 Sep 2015 15:47:53 -0700 Subject: [PATCH 6446/7006] mm: fix status code which move_pages() returns for zero page The manpage for move_pages(2) specifies that status code for zero page is supposed to be -EFAULT. Currently kernel return -ENOENT in this case. follow_page() can do it for us, if we would ask for FOLL_DUMP. The use of FOLL_DUMP also means that the upper layer page tables pages are no longer allocated. Signed-off-by: Kirill A. Shutemov Reviewed-by: Christoph Lameter Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/migrate.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/mm/migrate.c b/mm/migrate.c index eb4267107d1fe..5c08cab5419e7 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1226,7 +1226,9 @@ static int do_move_page_to_node_array(struct mm_struct *mm, if (!vma || pp->addr < vma->vm_start || !vma_migratable(vma)) goto set_status; - page = follow_page(vma, pp->addr, FOLL_GET|FOLL_SPLIT); + /* FOLL_DUMP to ignore special (like zero) pages */ + page = follow_page(vma, pp->addr, + FOLL_GET | FOLL_SPLIT | FOLL_DUMP); err = PTR_ERR(page); if (IS_ERR(page)) @@ -1236,10 +1238,6 @@ static int do_move_page_to_node_array(struct mm_struct *mm, if (!page) goto set_status; - /* Use PageReserved to check for zero page */ - if (PageReserved(page)) - goto put_and_set; - pp->page = page; err = page_to_nid(page); @@ -1396,18 +1394,14 @@ static void do_pages_stat_array(struct mm_struct *mm, unsigned long nr_pages, if (!vma || addr < vma->vm_start) goto set_status; - page = follow_page(vma, addr, 0); + /* FOLL_DUMP to ignore special (like zero) pages */ + page = follow_page(vma, addr, FOLL_DUMP); err = PTR_ERR(page); if (IS_ERR(page)) goto set_status; - err = -ENOENT; - /* Use PageReserved to check for zero page */ - if (!page || PageReserved(page)) - goto set_status; - - err = page_to_nid(page); + err = page ? page_to_nid(page) : -ENOENT; set_status: *status = err; -- GitLab From 1027e4436b6a5c413c95d95e50d0f26348a602ac Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Fri, 4 Sep 2015 15:47:55 -0700 Subject: [PATCH 6447/7006] mm: make GUP handle pfn mapping unless FOLL_GET is requested With DAX, pfn mapping becoming more common. The patch adjusts GUP code to cover pfn mapping for cases when we don't need struct page to proceed. To make it possible, let's change follow_page() code to return -EEXIST error code if proper page table entry exists, but no corresponding struct page. __get_user_page() would ignore the error code and move to the next page frame. The immediate effect of the change is working MAP_POPULATE and mlock() on DAX mappings. [akpm@linux-foundation.org: fix arm64 build] Signed-off-by: Kirill A. Shutemov Reviewed-by: Toshi Kani Acked-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/gup.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/mm/gup.c b/mm/gup.c index 6297f6bccfb1e..a798293fc6486 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -12,7 +12,9 @@ #include #include #include + #include +#include #include "internal.h" @@ -32,6 +34,30 @@ static struct page *no_page_table(struct vm_area_struct *vma, return NULL; } +static int follow_pfn_pte(struct vm_area_struct *vma, unsigned long address, + pte_t *pte, unsigned int flags) +{ + /* No page to get reference */ + if (flags & FOLL_GET) + return -EFAULT; + + if (flags & FOLL_TOUCH) { + pte_t entry = *pte; + + if (flags & FOLL_WRITE) + entry = pte_mkdirty(entry); + entry = pte_mkyoung(entry); + + if (!pte_same(*pte, entry)) { + set_pte_at(vma->vm_mm, address, pte, entry); + update_mmu_cache(vma, address, pte); + } + } + + /* Proper page table entry exists, but no corresponding struct page */ + return -EEXIST; +} + static struct page *follow_page_pte(struct vm_area_struct *vma, unsigned long address, pmd_t *pmd, unsigned int flags) { @@ -73,10 +99,21 @@ retry: page = vm_normal_page(vma, address, pte); if (unlikely(!page)) { - if ((flags & FOLL_DUMP) || - !is_zero_pfn(pte_pfn(pte))) - goto bad_page; - page = pte_page(pte); + if (flags & FOLL_DUMP) { + /* Avoid special (like zero) pages in core dumps */ + page = ERR_PTR(-EFAULT); + goto out; + } + + if (is_zero_pfn(pte_pfn(pte))) { + page = pte_page(pte); + } else { + int ret; + + ret = follow_pfn_pte(vma, address, ptep, flags); + page = ERR_PTR(ret); + goto out; + } } if (flags & FOLL_GET) @@ -114,12 +151,9 @@ retry: unlock_page(page); } } +out: pte_unmap_unlock(ptep, ptl); return page; -bad_page: - pte_unmap_unlock(ptep, ptl); - return ERR_PTR(-EFAULT); - no_page: pte_unmap_unlock(ptep, ptl); if (!pte_none(pte)) @@ -489,9 +523,15 @@ retry: goto next_page; } BUG(); - } - if (IS_ERR(page)) + } else if (PTR_ERR(page) == -EEXIST) { + /* + * Proper page table entry exists, but no corresponding + * struct page. + */ + goto next_page; + } else if (IS_ERR(page)) { return i ? i : PTR_ERR(page); + } if (pages) { pages[i] = page; flush_anon_page(vma, page, start); -- GitLab From 31aafb45f4e1c34e4aba37c150ae4e74880b46ed Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Fri, 4 Sep 2015 15:47:58 -0700 Subject: [PATCH 6448/7006] mm/hugetlb.c: make vma_shareable() return bool This makes vma_shareable() return bool now due to this particular function only ever returning either one or zero as its return value. Signed-off-by: Nicholas Krause Acked-by: Mike Kravetz Acked-by: Naoya Horiguchi Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index a8c3087089d8a..5d1d84ca96749 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3779,7 +3779,7 @@ static unsigned long page_table_shareable(struct vm_area_struct *svma, return saddr; } -static int vma_shareable(struct vm_area_struct *vma, unsigned long addr) +static bool vma_shareable(struct vm_area_struct *vma, unsigned long addr) { unsigned long base = addr & PUD_MASK; unsigned long end = base + PUD_SIZE; @@ -3789,8 +3789,8 @@ static int vma_shareable(struct vm_area_struct *vma, unsigned long addr) */ if (vma->vm_flags & VM_MAYSHARE && vma->vm_start <= base && end <= vma->vm_end) - return 1; - return 0; + return true; + return false; } /* -- GitLab From df1eab303c836c98a79de427aa1c7d6812acaaa9 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Sep 2015 15:48:01 -0700 Subject: [PATCH 6449/7006] mremap: don't leak new_vma if f_op->mremap() fails move_vma() can't just return if f_op->mremap() fails, we should unmap the new vma like we do if move_page_tables() fails. To avoid the code duplication this patch moves the "move entries back" under the new "if (err)" branch. Signed-off-by: Oleg Nesterov Acked-by: David Rientjes Cc: Benjamin LaHaise Cc: Hugh Dickins Cc: Jeff Moyer Cc: Kirill Shutemov Cc: Pavel Emelyanov Cc: Laurent Dufour Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mremap.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index a7c93eceb1c8d..f54a43fa4b798 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -276,6 +276,12 @@ static unsigned long move_vma(struct vm_area_struct *vma, moved_len = move_page_tables(vma, old_addr, new_vma, new_addr, old_len, need_rmap_locks); if (moved_len < old_len) { + err = -ENOMEM; + } else if (vma->vm_file && vma->vm_file->f_op->mremap) { + err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma); + } + + if (unlikely(err)) { /* * On error, move entries back from new area to old, * which will succeed since page tables still there, @@ -286,16 +292,8 @@ static unsigned long move_vma(struct vm_area_struct *vma, vma = new_vma; old_len = new_len; old_addr = new_addr; - new_addr = -ENOMEM; + new_addr = err; } else { - if (vma->vm_file && vma->vm_file->f_op->mremap) { - err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma); - if (err < 0) { - move_page_tables(new_vma, new_addr, vma, - old_addr, moved_len, true); - return err; - } - } arch_remap(mm, old_addr, old_addr + old_len, new_addr, new_addr + new_len); } -- GitLab From 5477e70a6420a6b7ca96c8e21413ee1c96a84260 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Sep 2015 15:48:04 -0700 Subject: [PATCH 6450/7006] mm: move ->mremap() from file_operations to vm_operations_struct vma->vm_ops->mremap() looks more natural and clean in move_vma(), and this way ->mremap() can have more users. Say, vdso. While at it, s/aio_ring_remap/aio_ring_mremap/. Note: this is the minimal change before ->mremap() finds another user in file_operations; this method should have more arguments, and it can be used to kill arch_remap(). Signed-off-by: Oleg Nesterov Acked-by: Pavel Emelyanov Acked-by: Kirill A. Shutemov Cc: David Rientjes Cc: Benjamin LaHaise Cc: Hugh Dickins Cc: Jeff Moyer Cc: Laurent Dufour Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/aio.c | 27 ++++++++++++++++++--------- include/linux/fs.h | 1 - include/linux/mm.h | 1 + mm/mremap.c | 4 ++-- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/fs/aio.c b/fs/aio.c index 480440f4701fb..155f84253f331 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -308,15 +308,9 @@ static void aio_free_ring(struct kioctx *ctx) } } -static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma) -{ - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_ops = &generic_file_vm_ops; - return 0; -} - -static int aio_ring_remap(struct file *file, struct vm_area_struct *vma) +static int aio_ring_mremap(struct vm_area_struct *vma) { + struct file *file = vma->vm_file; struct mm_struct *mm = vma->vm_mm; struct kioctx_table *table; int i, res = -EINVAL; @@ -342,9 +336,24 @@ static int aio_ring_remap(struct file *file, struct vm_area_struct *vma) return res; } +static const struct vm_operations_struct aio_ring_vm_ops = { + .mremap = aio_ring_mremap, +#if IS_ENABLED(CONFIG_MMU) + .fault = filemap_fault, + .map_pages = filemap_map_pages, + .page_mkwrite = filemap_page_mkwrite, +#endif +}; + +static int aio_ring_mmap(struct file *file, struct vm_area_struct *vma) +{ + vma->vm_flags |= VM_DONTEXPAND; + vma->vm_ops = &aio_ring_vm_ops; + return 0; +} + static const struct file_operations aio_ring_fops = { .mmap = aio_ring_mmap, - .mremap = aio_ring_remap, }; #if IS_ENABLED(CONFIG_MIGRATION) diff --git a/include/linux/fs.h b/include/linux/fs.h index fbd780c33c5fb..864203c10dbcb 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1612,7 +1612,6 @@ struct file_operations { long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); - int (*mremap)(struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); int (*flush) (struct file *, fl_owner_t id); int (*release) (struct inode *, struct file *); diff --git a/include/linux/mm.h b/include/linux/mm.h index 77a9d609523e8..8b257c43855bb 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -247,6 +247,7 @@ struct vm_fault { struct vm_operations_struct { void (*open)(struct vm_area_struct * area); void (*close)(struct vm_area_struct * area); + int (*mremap)(struct vm_area_struct * area); int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf); diff --git a/mm/mremap.c b/mm/mremap.c index f54a43fa4b798..3310378bb60f7 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -277,8 +277,8 @@ static unsigned long move_vma(struct vm_area_struct *vma, need_rmap_locks); if (moved_len < old_len) { err = -ENOMEM; - } else if (vma->vm_file && vma->vm_file->f_op->mremap) { - err = vma->vm_file->f_op->mremap(vma->vm_file, new_vma); + } else if (vma->vm_ops && vma->vm_ops->mremap) { + err = vma->vm_ops->mremap(new_vma); } if (unlikely(err)) { -- GitLab From d456fb9e5254df433d4806769d7ff75d80d66aa4 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Sep 2015 15:48:07 -0700 Subject: [PATCH 6451/7006] mremap: don't do mm_populate(new_addr) on failure move_vma() sets *locked even if move_page_tables() or ->mremap() fails, change sys_mremap() to check "ret & ~PAGE_MASK". I think we should simply remove the VM_LOCKED code in move_vma(), that is why this patch doesn't change move_vma(). But this needs more cleanups. Signed-off-by: Oleg Nesterov Acked-by: David Rientjes Cc: Benjamin LaHaise Cc: Hugh Dickins Cc: Jeff Moyer Cc: Kirill A. Shutemov Cc: Laurent Dufour Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mremap.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/mremap.c b/mm/mremap.c index 3310378bb60f7..7dcf7b42068e6 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -578,8 +578,10 @@ SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, ret = move_vma(vma, addr, old_len, new_len, new_addr, &locked); } out: - if (ret & ~PAGE_MASK) + if (ret & ~PAGE_MASK) { vm_unacct_memory(charged); + locked = 0; + } up_write(¤t->mm->mmap_sem); if (locked && new_len > old_len) mm_populate(new_addr + old_len, new_len - old_len); -- GitLab From 1d3916869798755968b3cd764ab21f2bb86ffff7 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Sep 2015 15:48:10 -0700 Subject: [PATCH 6452/7006] mremap: don't do uneccesary checks if new_len == old_len The "new_len > old_len" branch in vma_to_resize() looks very confusing. It only covers the VM_DONTEXPAND/pgoff checks but everything below is equally unneeded if new_len == old_len. Change this code to return if "new_len == old_len", new_len < old_len is not possible, otherwise the code below is wrong anyway. Signed-off-by: Oleg Nesterov Acked-by: David Rientjes Cc: Benjamin LaHaise Cc: Hugh Dickins Cc: Jeff Moyer Cc: Kirill A. Shutemov Cc: Laurent Dufour Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mremap.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index 7dcf7b42068e6..d3f42bece5643 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -346,6 +346,7 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, { struct mm_struct *mm = current->mm; struct vm_area_struct *vma = find_vma(mm, addr); + unsigned long pgoff; if (!vma || vma->vm_start > addr) return ERR_PTR(-EFAULT); @@ -357,17 +358,17 @@ static struct vm_area_struct *vma_to_resize(unsigned long addr, if (old_len > vma->vm_end - addr) return ERR_PTR(-EFAULT); + if (new_len == old_len) + return vma; + /* Need to be careful about a growing mapping */ - if (new_len > old_len) { - unsigned long pgoff; - - if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) - return ERR_PTR(-EFAULT); - pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; - pgoff += vma->vm_pgoff; - if (pgoff + (new_len >> PAGE_SHIFT) < pgoff) - return ERR_PTR(-EINVAL); - } + pgoff = (addr - vma->vm_start) >> PAGE_SHIFT; + pgoff += vma->vm_pgoff; + if (pgoff + (new_len >> PAGE_SHIFT) < pgoff) + return ERR_PTR(-EINVAL); + + if (vma->vm_flags & (VM_DONTEXPAND | VM_PFNMAP)) + return ERR_PTR(-EFAULT); if (vma->vm_flags & VM_LOCKED) { unsigned long locked, lock_limit; -- GitLab From 9943242ca468149c4ce30d4633524c0866d4a87b Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Fri, 4 Sep 2015 15:48:13 -0700 Subject: [PATCH 6453/7006] mremap: simplify the "overlap" check in mremap_to() Minor, but this check is overcomplicated. Two half-intervals do NOT overlap if END1 <= START2 || END2 <= START1, mremap_to() just needs to negate this check. Signed-off-by: Oleg Nesterov Acked-by: David Rientjes Cc: Benjamin LaHaise Cc: Hugh Dickins Cc: Jeff Moyer Cc: Kirill A. Shutemov Cc: Laurent Dufour Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mremap.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/mm/mremap.c b/mm/mremap.c index d3f42bece5643..5a71cce8c6ea8 100644 --- a/mm/mremap.c +++ b/mm/mremap.c @@ -407,13 +407,8 @@ static unsigned long mremap_to(unsigned long addr, unsigned long old_len, if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) goto out; - /* Check if the location we're moving into overlaps the - * old location at all, and fail if it does. - */ - if ((new_addr <= addr) && (new_addr+new_len) > addr) - goto out; - - if ((addr <= new_addr) && (addr+old_len) > new_addr) + /* Ensure the old/new locations do not overlap */ + if (addr + old_len > new_addr && new_addr + new_len > addr) goto out; ret = do_munmap(mm, new_addr, new_len); -- GitLab From 4e6dab4233f667c0ae465e5cb46603b49b4f6d74 Mon Sep 17 00:00:00 2001 From: "minkyung88.kim" Date: Fri, 4 Sep 2015 15:48:16 -0700 Subject: [PATCH 6454/7006] mm: remove struct node_active_region struct node_active_region is not used anymore. Remove it. Signed-off-by: minkyung88.kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmzone.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 754c25966a0a7..ac00e2050943b 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -690,14 +690,6 @@ struct zonelist { #endif }; -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -struct node_active_region { - unsigned long start_pfn; - unsigned long end_pfn; - int nid; -}; -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - #ifndef CONFIG_DISCONTIGMEM /* The array of struct pages - for discontigmem use pgdat->lmem_map */ extern struct page *mem_map; -- GitLab From d9e7e37b4d83371d08650612e0bb0b80a1240289 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Fri, 4 Sep 2015 15:48:19 -0700 Subject: [PATCH 6455/7006] mm/dmapool.c: change is_page_busy() return from int to bool This makes the function is_page_busy() return bool rather then an int now due to this particular function's single return statement only ever evaulating to either one or zero. Signed-off-by: Nicholas Krause Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/dmapool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/dmapool.c b/mm/dmapool.c index fd5fe4342e932..59d10d16f0a5d 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -242,7 +242,7 @@ static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) return page; } -static inline int is_page_busy(struct dma_page *page) +static inline bool is_page_busy(struct dma_page *page) { return page->in_use != 0; } -- GitLab From ca1d6c7d9d461effa2c4e8b9b227a14e9fdcf1cc Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Fri, 4 Sep 2015 15:48:22 -0700 Subject: [PATCH 6456/7006] mm/memory.c: make tlb_next_batch() return bool This makes the tlb_next_batch() bool due to this particular function only ever returning either one or zero as its return value. Signed-off-by: Nicholas Krause Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 2961fb654369e..bb04d8f2f86c4 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -181,22 +181,22 @@ static void check_sync_rss_stat(struct task_struct *task) #ifdef HAVE_GENERIC_MMU_GATHER -static int tlb_next_batch(struct mmu_gather *tlb) +static bool tlb_next_batch(struct mmu_gather *tlb) { struct mmu_gather_batch *batch; batch = tlb->active; if (batch->next) { tlb->active = batch->next; - return 1; + return true; } if (tlb->batch_count == MAX_GATHER_BATCH_COUNT) - return 0; + return false; batch = (void *)__get_free_pages(GFP_NOWAIT | __GFP_NOWARN, 0); if (!batch) - return 0; + return false; tlb->batch_count++; batch->next = NULL; @@ -206,7 +206,7 @@ static int tlb_next_batch(struct mmu_gather *tlb) tlb->active->next = batch; tlb->active = batch; - return 1; + return true; } /* tlb_gather_mmu -- GitLab From 1ecef9ed0f63bfff58895a4f3aec751e907c7f3d Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Fri, 4 Sep 2015 15:48:24 -0700 Subject: [PATCH 6457/7006] mm/madvise.c: make madvise_behaviour_valid() return bool This makes the madvise_bahaviour_valid() function return bool due to this particular function always returning the value of either one or zero as its return value. Signed-off-by: Nicholas Krause Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/madvise.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/madvise.c b/mm/madvise.c index 9113579739059..ce3a4222c7e7a 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -386,7 +386,7 @@ madvise_vma(struct vm_area_struct *vma, struct vm_area_struct **prev, } } -static int +static bool madvise_behavior_valid(int behavior) { switch (behavior) { @@ -408,10 +408,10 @@ madvise_behavior_valid(int behavior) #endif case MADV_DONTDUMP: case MADV_DODUMP: - return 1; + return true; default: - return 0; + return false; } } -- GitLab From 559ec2f8fd50981821621f52db5e1a8ffcf8d792 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Fri, 4 Sep 2015 15:48:27 -0700 Subject: [PATCH 6458/7006] mm/hugetlb.c: make vma_has_reserves() return bool This makes vma_has_reserves() return bool due to this particular function only returning either one or zero as its return value. Signed-off-by: Nicholas Krause Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 5d1d84ca96749..51ae41d0fbc0d 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -616,7 +616,7 @@ void reset_vma_resv_huge_pages(struct vm_area_struct *vma) } /* Returns true if the VMA has associated reserve pages */ -static int vma_has_reserves(struct vm_area_struct *vma, long chg) +static bool vma_has_reserves(struct vm_area_struct *vma, long chg) { if (vma->vm_flags & VM_NORESERVE) { /* @@ -629,23 +629,23 @@ static int vma_has_reserves(struct vm_area_struct *vma, long chg) * properly, so add work-around here. */ if (vma->vm_flags & VM_MAYSHARE && chg == 0) - return 1; + return true; else - return 0; + return false; } /* Shared mappings always use reserves */ if (vma->vm_flags & VM_MAYSHARE) - return 1; + return true; /* * Only the process that called mmap() has reserves for * private mappings. */ if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) - return 1; + return true; - return 0; + return false; } static void enqueue_huge_page(struct hstate *h, struct page *page) -- GitLab From 5269e7067cd66f4797760f160be21ff50f2d1582 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Thu, 3 Sep 2015 08:20:58 -0700 Subject: [PATCH 6459/7006] cpufreq: Add ARM_MT8173_CPUFREQ dependency on THERMAL If ARM_MT8173_CPUFREQ is configured, and THERMAL is configured as module, the following build error is seen for arm:allmodconfig and arm64:allmodconfig. drivers/built-in.o: In function `mtk_cpufreq_ready': :(.text+0x32a20c): undefined reference to `of_cpufreq_cooling_register' drivers/built-in.o: In function `mtk_cpufreq_exit': :(.text+0x32a420): undefined reference to `cpufreq_cooling_unregister' The fix is similar to CPUFREQ_DT, but more restrictive since ARM_MT8173_CPUFREQ can not be built as module. Fixes: 1453863fb02a ("cpufreq: mediatek: Add MT8173 cpufreq driver") Signed-off-by: Guenter Roeck Acked-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/Kconfig.arm | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm index 2bacf24a19a92..360c5df552076 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -133,6 +133,7 @@ config ARM_KIRKWOOD_CPUFREQ config ARM_MT8173_CPUFREQ bool "Mediatek MT8173 CPUFreq support" depends on ARCH_MEDIATEK && REGULATOR + depends on !CPU_THERMAL || THERMAL=y select PM_OPP help This adds the CPUFreq driver support for Mediatek MT8173 SoC. -- GitLab From 30e7a65b3fdb53cc49f85c965095e40aceea3961 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Thu, 3 Sep 2015 09:10:37 +0100 Subject: [PATCH 6460/7006] PM / Domains: Ensure subdomain is not in use before removing The function pm_genpd_remove_subdomain() removes a subdomain from a generic PM domain, however, it does not check if the subdomain has any slave domains or device attached before doing so. Therefore, add a test to verify that the subdomain does not have any slave domains associated or any device attached before removing. Signed-off-by: Jon Hunter Acked-by: Kevin Hilman Signed-off-by: Rafael J. Wysocki --- drivers/base/power/domain.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c index 62f7572502355..16550c63d611a 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1473,6 +1473,13 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, mutex_lock(&genpd->lock); + if (!list_empty(&subdomain->slave_links) || subdomain->device_count) { + pr_warn("%s: unable to remove subdomain %s\n", genpd->name, + subdomain->name); + ret = -EBUSY; + goto out; + } + list_for_each_entry(link, &genpd->master_links, master_node) { if (link->slave != subdomain) continue; @@ -1491,6 +1498,7 @@ int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, break; } +out: mutex_unlock(&genpd->lock); return ret; -- GitLab From 2fb07a10e0aa699ddb12aba1459208579bdc9802 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 23 Jun 2015 11:15:10 -0500 Subject: [PATCH 6461/7006] rtc: ds1307: Convert to threaded IRQ The driver currently emulates the concept of threaded IRQ using a workqueue, which it really does not need to. Instead, switch over to threaded_irq handlers which is meant precisely for the same purpose. Signed-off-by: Felipe Balbi Signed-off-by: Nishanth Menon Reviewed-by: Grygorii Strashko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 59 +++++++++++++--------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 6e76de1856fc1..8ea496e54a2e8 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -114,7 +114,6 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; - struct work_struct work; s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, @@ -311,27 +310,17 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client, /*----------------------------------------------------------------------*/ /* - * The IRQ logic includes a "real" handler running in IRQ context just - * long enough to schedule this workqueue entry. We need a task context - * to talk to the RTC, since I2C I/O calls require that; and disable the - * IRQ until we clear its status on the chip, so that this handler can - * work with any type of triggering (not just falling edge). - * * The ds1337 and ds1339 both have two alarms, but we only use the first * one (with a "seconds" field). For ds1337 we expect nINTA is our alarm * signal; ds1339 chips have only one alarm signal. */ -static void ds1307_work(struct work_struct *work) +static irqreturn_t ds1307_irq(int irq, void *dev_id) { - struct ds1307 *ds1307; - struct i2c_client *client; - struct mutex *lock; + struct i2c_client *client = dev_id; + struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct mutex *lock = &ds1307->rtc->ops_lock; int stat, control; - ds1307 = container_of(work, struct ds1307, work); - client = ds1307->client; - lock = &ds1307->rtc->ops_lock; - mutex_lock(lock); stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); if (stat < 0) @@ -352,18 +341,8 @@ static void ds1307_work(struct work_struct *work) } out: - if (test_bit(HAS_ALARM, &ds1307->flags)) - enable_irq(client->irq); mutex_unlock(lock); -} - -static irqreturn_t ds1307_irq(int irq, void *dev_id) -{ - struct i2c_client *client = dev_id; - struct ds1307 *ds1307 = i2c_get_clientdata(client); - disable_irq_nosync(irq); - schedule_work(&ds1307->work); return IRQ_HANDLED; } @@ -634,13 +613,14 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { MCP794XX_BIT_ALMX_C1 | \ MCP794XX_BIT_ALMX_C2) -static void mcp794xx_work(struct work_struct *work) +static irqreturn_t mcp794xx_irq(int irq, void *dev_id) { - struct ds1307 *ds1307 = container_of(work, struct ds1307, work); - struct i2c_client *client = ds1307->client; + struct i2c_client *client = dev_id; + struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct mutex *lock = &ds1307->rtc->ops_lock; int reg, ret; - mutex_lock(&ds1307->rtc->ops_lock); + mutex_lock(lock); /* Check and clear alarm 0 interrupt flag. */ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL); @@ -665,9 +645,9 @@ static void mcp794xx_work(struct work_struct *work) rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); out: - if (test_bit(HAS_ALARM, &ds1307->flags)) - enable_irq(client->irq); - mutex_unlock(&ds1307->rtc->ops_lock); + mutex_unlock(lock); + + return IRQ_HANDLED; } static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) @@ -896,6 +876,8 @@ static int ds1307_probe(struct i2c_client *client, bool want_irq = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); + irq_handler_t irq_handler = ds1307_irq; + static const int bbsqi_bitpos[] = { [ds_1337] = 0, [ds_1339] = DS1339_BIT_BBSQI, @@ -962,8 +944,6 @@ static int ds1307_probe(struct i2c_client *client, * running on Vbackup (BBSQI/BBSQW) */ if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, ds1307_work); - ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1053,7 +1033,7 @@ static int ds1307_probe(struct i2c_client *client, case mcp794xx: rtc_ops = &mcp794xx_rtc_ops; if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, mcp794xx_work); + irq_handler = mcp794xx_irq; want_irq = true; } break; @@ -1176,8 +1156,9 @@ read_rtc: } if (want_irq) { - err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, - ds1307->rtc->name, client); + err = request_threaded_irq(client->irq, NULL, irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + ds1307->rtc->name, client); if (err) { client->irq = 0; dev_err(&client->dev, "unable to request IRQ!\n"); @@ -1231,10 +1212,8 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); - if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) { + if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) free_irq(client->irq, client); - cancel_work_sync(&ds1307->work); - } if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); -- GitLab From c5983191362af5ef7a627d8811a45f0fd01a3582 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 23 Jun 2015 11:15:11 -0500 Subject: [PATCH 6462/7006] rtc: ds1307: Switch to managed irq allocation Since we are not doing anything fancy in remove function that requires us to sequence IRQ free operation, we might as well switch over to devm_ equivalent of managed IRQ allocation and remove the explicit free_irq since it'd be done automatically at remove. Signed-off-by: Nishanth Menon Acked-by: Felipe Balbi Reviewed-by: Grygorii Strashko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 8ea496e54a2e8..0a98d8a527915 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1156,9 +1156,10 @@ read_rtc: } if (want_irq) { - err = request_threaded_irq(client->irq, NULL, irq_handler, - IRQF_SHARED | IRQF_ONESHOT, - ds1307->rtc->name, client); + err = devm_request_threaded_irq(&client->dev, + client->irq, NULL, irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + ds1307->rtc->name, client); if (err) { client->irq = 0; dev_err(&client->dev, "unable to request IRQ!\n"); @@ -1212,9 +1213,6 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); - if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) - free_irq(client->irq, client); - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); -- GitLab From eac7237fd8432e232af3c407e667dbdc17ebf1d8 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 23 Jun 2015 11:15:12 -0500 Subject: [PATCH 6463/7006] rtc: ds1307: Sort the headers It is always a good practice to keep the #includes sorted Signed-off-by: Nishanth Menon Acked-by: Felipe Balbi Reviewed-by: Grygorii Strashko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 0a98d8a527915..b03880fc32b56 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -11,14 +11,14 @@ * published by the Free Software Foundation. */ -#include +#include +#include #include +#include +#include +#include #include -#include #include -#include -#include -#include /* * We can't determine type by probing, but if we expect pre-Linux code -- GitLab From 7abea617a4bae178da0f42983998c779ec2f732d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Jun 2015 11:26:54 -0500 Subject: [PATCH 6464/7006] rtc: ds1307: Support optional wakeup interrupt source With the recent pinctrl-single changes, SoCs such as Texas Instrument's OMAP processors can treat wake-up events from deeper idle states as interrupts. Let's add support for the optional second interrupt for wake-up using the generic wakeirq support added in commit 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") Finally, to pass the wake-up interrupt in the dts file, interrupts-extended property needs to be passed. This is similar in approach to commit 2a0b965cfb6e ("serial: omap: Add support for optional wake-up") + ee83bd3b6483 ("serial: omap: Switch wake-up interrupt to generic wakeirq") Signed-off-by: Nishanth Menon Reviewed-by: Grygorii Strashko Acked-by: Tony Lindgren Acked-by: Felipe Balbi Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index b03880fc32b56..e16989c48a90f 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -114,6 +117,7 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; + int wakeirq; s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, @@ -1156,6 +1160,8 @@ read_rtc: } if (want_irq) { + struct device_node *node = client->dev.of_node; + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler, IRQF_SHARED | IRQF_ONESHOT, @@ -1163,13 +1169,34 @@ read_rtc: if (err) { client->irq = 0; dev_err(&client->dev, "unable to request IRQ!\n"); - } else { + goto no_irq; + } - set_bit(HAS_ALARM, &ds1307->flags); - dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + set_bit(HAS_ALARM, &ds1307->flags); + dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + + /* Currently supported by OF code only! */ + if (!node) + goto no_irq; + + err = of_irq_get(node, 1); + if (err <= 0) { + if (err == -EPROBE_DEFER) + goto exit; + goto no_irq; + } + ds1307->wakeirq = err; + + err = dev_pm_set_dedicated_wake_irq(&client->dev, + ds1307->wakeirq); + if (err) { + dev_err(&client->dev, "unable to setup wakeIRQ %d!\n", + err); + goto exit; } } +no_irq: if (chip->nvram_size) { ds1307->nvram = devm_kzalloc(&client->dev, @@ -1213,6 +1240,9 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); + if (ds1307->wakeirq) + dev_pm_clear_wake_irq(&client->dev); + if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); -- GitLab From 508db592e2f54d731bf2f5eabd9642a1a566f276 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 7 Jul 2015 11:16:14 +0530 Subject: [PATCH 6465/7006] rtc: ds1685: Use module_platform_driver Use module_platform_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return platform_driver_register(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { platform_driver_unregister(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_platform_driver; @@ -module_exit(e); +module_platform_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1685.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 818a3635a8c86..05a51ef527032 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -2145,27 +2145,7 @@ static struct platform_driver ds1685_rtc_driver = { .probe = ds1685_rtc_probe, .remove = ds1685_rtc_remove, }; - -/** - * ds1685_rtc_init - rtc module init. - */ -static int __init -ds1685_rtc_init(void) -{ - return platform_driver_register(&ds1685_rtc_driver); -} - -/** - * ds1685_rtc_exit - rtc module exit. - */ -static void __exit -ds1685_rtc_exit(void) -{ - platform_driver_unregister(&ds1685_rtc_driver); -} - -module_init(ds1685_rtc_init); -module_exit(ds1685_rtc_exit); +module_platform_driver(ds1685_rtc_driver); /* ----------------------------------------------------------------------- */ -- GitLab From 617f6f7ef5bfe8c0ac580243c3da9a836c6e39bf Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Wed, 8 Jul 2015 12:26:47 +0530 Subject: [PATCH 6466/7006] rtc: bq32k: remove redundant check removing below static analysis error: (error) Possible null pointer dereference: client if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ^^^^^^^ Error comes because client is dereferenced before NULL check. So probably NULL this check is not required. Signed-off-by: Maninder Singh Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-bq32k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 92679df6d6e22..409de9f1b604c 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -212,7 +212,7 @@ static int bq32k_probe(struct i2c_client *client, if (error) return error; - if (client && client->dev.of_node) + if (client->dev.of_node) trickle_charger_of_init(dev, client->dev.of_node); rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name, -- GitLab From 4ab82103131777b9aabb6ba31aead6e5b0293b32 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 9 Jul 2015 12:25:51 +0530 Subject: [PATCH 6467/7006] rtc: 88pm80x: add device tree support Along with DT support, this patch also cleans up the unnecessary code around 'rtc_wakeup' initialization. Signed-off-by: Chao Xie Signed-off-by: Vaibhav Hiremath Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm80x.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 7df0579d9852c..466bf7f9a285a 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -251,17 +251,26 @@ static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); static int pm80x_rtc_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm80x_platform_data *pm80x_pdata = - dev_get_platdata(pdev->dev.parent); - struct pm80x_rtc_pdata *pdata = NULL; + struct pm80x_rtc_pdata *pdata = dev_get_platdata(&pdev->dev); struct pm80x_rtc_info *info; + struct device_node *node = pdev->dev.of_node; struct rtc_time tm; unsigned long ticks = 0; int ret; - pdata = dev_get_platdata(&pdev->dev); - if (pdata == NULL) - dev_warn(&pdev->dev, "No platform data!\n"); + if (!pdata && !node) { + dev_err(&pdev->dev, + "pm80x-rtc requires platform data or of_node\n"); + return -EINVAL; + } + + if (!pdata) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + } info = devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL); @@ -327,11 +336,8 @@ static int pm80x_rtc_probe(struct platform_device *pdev) regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO, PM800_RTC1_USE_XO); - if (pm80x_pdata) { - pdata = pm80x_pdata->rtc; - if (pdata) - info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; - } + /* remember whether this power up is caused by PMIC RTC or not */ + info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; device_init_wakeup(&pdev->dev, 1); -- GitLab From 821f51c4da869706356ddecfeeac286bf4df9b98 Mon Sep 17 00:00:00 2001 From: Andrea Scian Date: Tue, 16 Jun 2015 11:35:19 +0200 Subject: [PATCH 6468/7006] rtc: use rtc_valid_tm() error code when reading date/time There's a wrong comment in some RTC drivers that say it's better to ignore rtc_valid_tm() when reading RTC timestamp. However this is wrong and is better to return to the userspace the error if timestamp is not valid. Signed-off-by: Andrea Scian Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 7 +------ drivers/rtc/rtc-pcf2123.c | 8 +------- drivers/rtc/rtc-pcf2127.c | 8 +------- 3 files changed, 3 insertions(+), 20 deletions(-) diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index f9b082784b906..3726271367863 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -151,12 +151,7 @@ static int isl12022_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* The clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. */ - if (rtc_valid_tm(tm) < 0) - dev_err(&client->dev, "retrieved date and time is invalid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 8a7556cbcb7f0..1c47650fe624f 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -165,13 +165,7 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* the clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. - */ - if (rtc_valid_tm(tm) < 0) - dev_err(dev, "retrieved date/time is not valid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 9bd842e977492..350c5c7cb6780 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -88,13 +88,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* the clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. - */ - if (rtc_valid_tm(tm) < 0) - dev_err(&client->dev, "retrieved date/time is not valid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) -- GitLab From 653ebd75e9e469e99a40ab14128d915386dc78c6 Mon Sep 17 00:00:00 2001 From: Andrea Scian Date: Tue, 16 Jun 2015 11:39:47 +0200 Subject: [PATCH 6469/7006] rtc: pcf2127: use OFS flag to detect unreliable date and warn the user The PCF2127 datasheet states that it's wrong to say that the date in unreliable if BLF (battery low flag) is set but instead, OSF (seconds register) should be used to check if oscillator, for any reason, stopped. Battery may be low (usually below 2V5 threshold) but the date may be anyway correct (typically date is unreliable when input voltage is below 1V2). Signed-off-by: Andrea Scian Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 350c5c7cb6780..baf45c9ca65ee 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -33,11 +33,14 @@ #define PCF2127_REG_MO (0x08) #define PCF2127_REG_YR (0x09) +#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ + static struct i2c_driver pcf2127_driver; struct pcf2127 { struct rtc_device *rtc; int voltage_low; /* indicates if a low_voltage was detected */ + int oscillator_failed; /* OSF was detected and date is unreliable */ }; /* @@ -59,7 +62,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) if (buf[PCF2127_REG_CTRL3] & 0x04) { pcf2127->voltage_low = 1; dev_info(&client->dev, - "low voltage detected, date/time is not reliable.\n"); + "low voltage detected, check/replace RTC battery.\n"); + } + + if (buf[PCF2127_REG_SC] & PCF2127_OSF) { + /* + * no need clear the flag here, + * it will be cleared once the new date is saved + */ + pcf2127->oscillator_failed = 1; + dev_warn(&client->dev, + "oscillator stop detected, date/time is not reliable\n"); + return -EINVAL; } dev_dbg(&client->dev, @@ -93,6 +107,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct pcf2127 *pcf2127 = i2c_get_clientdata(client); unsigned char buf[8]; int i = 0, err; @@ -106,7 +121,7 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[i++] = PCF2127_REG_SC; /* hours, minutes and seconds */ - buf[i++] = bin2bcd(tm->tm_sec); + buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */ buf[i++] = bin2bcd(tm->tm_min); buf[i++] = bin2bcd(tm->tm_hour); buf[i++] = bin2bcd(tm->tm_mday); @@ -126,6 +141,9 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } + /* clear OSF flag in client data */ + pcf2127->oscillator_failed = 0; + return 0; } @@ -138,7 +156,9 @@ static int pcf2127_rtc_ioctl(struct device *dev, switch (cmd) { case RTC_VL_READ: if (pcf2127->voltage_low) - dev_info(dev, "low voltage detected, date/time is not reliable.\n"); + dev_info(dev, "low voltage detected, check/replace battery\n"); + if (pcf2127->oscillator_failed) + dev_info(dev, "oscillator stop detected, date/time is not reliable\n"); if (copy_to_user((void __user *)arg, &pcf2127->voltage_low, sizeof(int))) -- GitLab From b28845433eb9c205c381ed69b09167d6ae5aac1c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:50 +0900 Subject: [PATCH 6470/7006] rtc: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab-b5ze-s3.c | 1 - drivers/rtc/rtc-bq32k.c | 1 - drivers/rtc/rtc-ds1307.c | 1 - drivers/rtc/rtc-ds1374.c | 1 - drivers/rtc/rtc-ds3232.c | 1 - drivers/rtc/rtc-fm3130.c | 1 - drivers/rtc/rtc-hym8563.c | 1 - drivers/rtc/rtc-isl12057.c | 1 - drivers/rtc/rtc-pcf2127.c | 1 - drivers/rtc/rtc-pcf85063.c | 1 - drivers/rtc/rtc-pcf8523.c | 1 - drivers/rtc/rtc-pcf8563.c | 1 - drivers/rtc/rtc-pcf8583.c | 1 - drivers/rtc/rtc-rx8025.c | 1 - drivers/rtc/rtc-rx8581.c | 1 - 15 files changed, 15 deletions(-) diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index b5cbc1bf5a3e5..0fb1d767afa9e 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -1020,7 +1020,6 @@ MODULE_DEVICE_TABLE(i2c, abb5zes3_id); static struct i2c_driver abb5zes3_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &abb5zes3_rtc_pm_ops, .of_match_table = of_match_ptr(abb5zes3_dt_match), }, diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 409de9f1b604c..0299988b4f136 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -234,7 +234,6 @@ MODULE_DEVICE_TABLE(i2c, bq32k_id); static struct i2c_driver bq32k_driver = { .driver = { .name = "bq32k", - .owner = THIS_MODULE, }, .probe = bq32k_probe, .id_table = bq32k_id, diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index e16989c48a90f..c51bc0a65afce 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1252,7 +1252,6 @@ static int ds1307_remove(struct i2c_client *client) static struct i2c_driver ds1307_driver = { .driver = { .name = "rtc-ds1307", - .owner = THIS_MODULE, }, .probe = ds1307_probe, .remove = ds1307_remove, diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 72c9333752339..6d8665647eee2 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -708,7 +708,6 @@ static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume); static struct i2c_driver ds1374_driver = { .driver = { .name = "rtc-ds1374", - .owner = THIS_MODULE, .pm = &ds1374_pm, }, .probe = ds1374_probe, diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7e48e532214fe..18f062f2a6343 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -500,7 +500,6 @@ MODULE_DEVICE_TABLE(i2c, ds3232_id); static struct i2c_driver ds3232_driver = { .driver = { .name = "rtc-ds3232", - .owner = THIS_MODULE, .pm = &ds3232_pm_ops, }, .probe = ds3232_probe, diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index 83c3b3029fa77..576eadbba2967 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -523,7 +523,6 @@ exit_free: static struct i2c_driver fm3130_driver = { .driver = { .name = "rtc-fm3130", - .owner = THIS_MODULE, }, .probe = fm3130_probe, .id_table = fm3130_id, diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index e9da7959d3fe1..097325d96db56 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -599,7 +599,6 @@ MODULE_DEVICE_TABLE(of, hym8563_dt_idtable); static struct i2c_driver hym8563_driver = { .driver = { .name = "rtc-hym8563", - .owner = THIS_MODULE, .pm = &hym8563_pm_ops, .of_match_table = hym8563_dt_idtable, }, diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index da818d3337cec..ee3e8dbcacafe 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -659,7 +659,6 @@ MODULE_DEVICE_TABLE(i2c, isl12057_id); static struct i2c_driver isl12057_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &isl12057_rtc_pm_ops, .of_match_table = of_match_ptr(isl12057_dt_match), }, diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index baf45c9ca65ee..4b11d31f71740 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -231,7 +231,6 @@ MODULE_DEVICE_TABLE(of, pcf2127_of_match); static struct i2c_driver pcf2127_driver = { .driver = { .name = "rtc-pcf2127", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf2127_of_match), }, .probe = pcf2127_probe, diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 6a12bf62c504b..b6d73dd881f24 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -189,7 +189,6 @@ MODULE_DEVICE_TABLE(of, pcf85063_of_match); static struct i2c_driver pcf85063_driver = { .driver = { .name = "rtc-pcf85063", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf85063_of_match), }, .probe = pcf85063_probe, diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 4cdb64be061bd..e7ebcc0b7e59b 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -334,7 +334,6 @@ MODULE_DEVICE_TABLE(of, pcf8523_of_match); static struct i2c_driver pcf8523_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf8523_of_match), }, .probe = pcf8523_probe, diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 8bba022be946e..e569243db57ef 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -483,7 +483,6 @@ MODULE_DEVICE_TABLE(of, pcf8563_of_match); static struct i2c_driver pcf8563_driver = { .driver = { .name = "rtc-pcf8563", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf8563_of_match), }, .probe = pcf8563_probe, diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 5911a6dca2919..7ca9e8871d77d 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -309,7 +309,6 @@ MODULE_DEVICE_TABLE(i2c, pcf8583_id); static struct i2c_driver pcf8583_driver = { .driver = { .name = "pcf8583", - .owner = THIS_MODULE, }, .probe = pcf8583_probe, .id_table = pcf8583_id, diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index e6298e02b400e..a297542e2f8a3 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -628,7 +628,6 @@ static int rx8025_remove(struct i2c_client *client) static struct i2c_driver rx8025_driver = { .driver = { .name = "rtc-rx8025", - .owner = THIS_MODULE, }, .probe = rx8025_probe, .remove = rx8025_remove, diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index de8d9c4277826..161e25d016c39 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -315,7 +315,6 @@ MODULE_DEVICE_TABLE(i2c, rx8581_id); static struct i2c_driver rx8581_driver = { .driver = { .name = "rtc-rx8581", - .owner = THIS_MODULE, }, .probe = rx8581_probe, .id_table = rx8581_id, -- GitLab From 045c6fdd37a01d950c0f5ca64733b53b184fe91b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:51 +0900 Subject: [PATCH 6471/7006] rtc: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-opal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 7061dcae2b09d..417d7b4a5cd85 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -236,7 +236,6 @@ static struct platform_driver opal_rtc_driver = { .id_table = opal_rtc_driver_ids, .driver = { .name = DRVNAME, - .owner = THIS_MODULE, .of_match_table = opal_rtc_match, }, }; -- GitLab From dcb9372b34c9de90672e4cf811d7c3a8519320aa Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sat, 11 Jul 2015 19:28:50 +0200 Subject: [PATCH 6472/7006] doc: dt: add documentation for nxp,lpc1788-rtc Document NXP LPC178x/18xx/408x/43xx bindings Signed-off-by: Joachim Eastwood Signed-off-by: Alexandre Belloni --- .../bindings/rtc/nxp,lpc1788-rtc.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt new file mode 100644 index 0000000000000..3c97bd180592a --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt @@ -0,0 +1,21 @@ +NXP LPC1788 real-time clock + +The LPC1788 RTC provides calendar and clock functionality +together with periodic tick and alarm interrupt support. + +Required properties: +- compatible : must contain "nxp,lpc1788-rtc" +- reg : Specifies base physical address and size of the registers. +- interrupts : A single interrupt specifier. +- clocks : Must contain clock specifiers for rtc and register clock +- clock-names : Must contain "rtc" and "reg" + See ../clocks/clock-bindings.txt for details. + +Example: +rtc: rtc@40046000 { + compatible = "nxp,lpc1788-rtc"; + reg = <0x40046000 0x1000>; + interrupts = <47>; + clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>; + clock-names = "rtc", "reg"; +}; -- GitLab From c28b42e3aee03fe869a3f73039cf92686ccbc8fb Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sat, 11 Jul 2015 19:28:49 +0200 Subject: [PATCH 6473/7006] rtc: add rtc-lpc24xx driver Add driver for the RTC found on NXP LPC178x/18xx/408x/43xx devices. The RTC provides calendar and clock functionality together with alarm interrupt support. Signed-off-by: Joachim Eastwood Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 12 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-lpc24xx.c | 310 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+) create mode 100644 drivers/rtc/rtc-lpc24xx.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 533bfa3b60397..e132ccbec5158 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1456,6 +1456,18 @@ config RTC_DRV_JZ4740 This driver can also be buillt as a module. If so, the module will be called rtc-jz4740. +config RTC_DRV_LPC24XX + tristate "NXP RTC for LPC178x/18xx/408x/43xx" + depends on ARCH_LPC18XX || COMPILE_TEST + depends on OF && HAS_IOMEM + help + This enables support for the NXP RTC found which can be found on + NXP LPC178x/18xx/408x/43xx devices. + + If you have one of the devices above enable this driver to use + the hardware RTC. This driver can also be buillt as a module. If + so, the module will be called rtc-lpc24xx. + config RTC_DRV_LPC32XX depends on ARCH_LPC32XX tristate "NXP LPC32XX RTC" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1b09a62fcf4b8..279738449a8d1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o +obj-$(CONFIG_RTC_DRV_LPC24XX) += rtc-lpc24xx.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c new file mode 100644 index 0000000000000..59d99596fdebc --- /dev/null +++ b/drivers/rtc/rtc-lpc24xx.c @@ -0,0 +1,310 @@ +/* + * RTC driver for NXP LPC178x/18xx/43xx Real-Time Clock (RTC) + * + * Copyright (C) 2011 NXP Semiconductors + * Copyright (C) 2015 Joachim Eastwood + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* LPC24xx RTC register offsets and bits */ +#define LPC24XX_ILR 0x00 +#define LPC24XX_RTCCIF BIT(0) +#define LPC24XX_RTCALF BIT(1) +#define LPC24XX_CTC 0x04 +#define LPC24XX_CCR 0x08 +#define LPC24XX_CLKEN BIT(0) +#define LPC178X_CCALEN BIT(4) +#define LPC24XX_CIIR 0x0c +#define LPC24XX_AMR 0x10 +#define LPC24XX_ALARM_DISABLE 0xff +#define LPC24XX_CTIME0 0x14 +#define LPC24XX_CTIME1 0x18 +#define LPC24XX_CTIME2 0x1c +#define LPC24XX_SEC 0x20 +#define LPC24XX_MIN 0x24 +#define LPC24XX_HOUR 0x28 +#define LPC24XX_DOM 0x2c +#define LPC24XX_DOW 0x30 +#define LPC24XX_DOY 0x34 +#define LPC24XX_MONTH 0x38 +#define LPC24XX_YEAR 0x3c +#define LPC24XX_ALSEC 0x60 +#define LPC24XX_ALMIN 0x64 +#define LPC24XX_ALHOUR 0x68 +#define LPC24XX_ALDOM 0x6c +#define LPC24XX_ALDOW 0x70 +#define LPC24XX_ALDOY 0x74 +#define LPC24XX_ALMON 0x78 +#define LPC24XX_ALYEAR 0x7c + +/* Macros to read fields in consolidated time (CT) registers */ +#define CT0_SECS(x) (((x) >> 0) & 0x3f) +#define CT0_MINS(x) (((x) >> 8) & 0x3f) +#define CT0_HOURS(x) (((x) >> 16) & 0x1f) +#define CT0_DOW(x) (((x) >> 24) & 0x07) +#define CT1_DOM(x) (((x) >> 0) & 0x1f) +#define CT1_MONTH(x) (((x) >> 8) & 0x0f) +#define CT1_YEAR(x) (((x) >> 16) & 0xfff) +#define CT2_DOY(x) (((x) >> 0) & 0xfff) + +#define rtc_readl(dev, reg) readl((dev)->rtc_base + (reg)) +#define rtc_writel(dev, reg, val) writel((val), (dev)->rtc_base + (reg)) + +struct lpc24xx_rtc { + void __iomem *rtc_base; + struct rtc_device *rtc; + struct clk *clk_rtc; + struct clk *clk_reg; +}; + +static int lpc24xx_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + + /* Disable RTC during update */ + rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN); + + rtc_writel(rtc, LPC24XX_SEC, tm->tm_sec); + rtc_writel(rtc, LPC24XX_MIN, tm->tm_min); + rtc_writel(rtc, LPC24XX_HOUR, tm->tm_hour); + rtc_writel(rtc, LPC24XX_DOW, tm->tm_wday); + rtc_writel(rtc, LPC24XX_DOM, tm->tm_mday); + rtc_writel(rtc, LPC24XX_DOY, tm->tm_yday); + rtc_writel(rtc, LPC24XX_MONTH, tm->tm_mon); + rtc_writel(rtc, LPC24XX_YEAR, tm->tm_year); + + rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN); + + return 0; +} + +static int lpc24xx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + u32 ct0, ct1, ct2; + + ct0 = rtc_readl(rtc, LPC24XX_CTIME0); + ct1 = rtc_readl(rtc, LPC24XX_CTIME1); + ct2 = rtc_readl(rtc, LPC24XX_CTIME2); + + tm->tm_sec = CT0_SECS(ct0); + tm->tm_min = CT0_MINS(ct0); + tm->tm_hour = CT0_HOURS(ct0); + tm->tm_wday = CT0_DOW(ct0); + tm->tm_mon = CT1_MONTH(ct1); + tm->tm_mday = CT1_DOM(ct1); + tm->tm_year = CT1_YEAR(ct1); + tm->tm_yday = CT2_DOY(ct2); + + return rtc_valid_tm(tm); +} + +static int lpc24xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + + tm->tm_sec = rtc_readl(rtc, LPC24XX_ALSEC); + tm->tm_min = rtc_readl(rtc, LPC24XX_ALMIN); + tm->tm_hour = rtc_readl(rtc, LPC24XX_ALHOUR); + tm->tm_mday = rtc_readl(rtc, LPC24XX_ALDOM); + tm->tm_wday = rtc_readl(rtc, LPC24XX_ALDOW); + tm->tm_yday = rtc_readl(rtc, LPC24XX_ALDOY); + tm->tm_mon = rtc_readl(rtc, LPC24XX_ALMON); + tm->tm_year = rtc_readl(rtc, LPC24XX_ALYEAR); + + wkalrm->enabled = rtc_readl(rtc, LPC24XX_AMR) == 0; + wkalrm->pending = !!(rtc_readl(rtc, LPC24XX_ILR) & LPC24XX_RTCCIF); + + return rtc_valid_tm(&wkalrm->time); +} + +static int lpc24xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + + /* Disable alarm irq during update */ + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + + rtc_writel(rtc, LPC24XX_ALSEC, tm->tm_sec); + rtc_writel(rtc, LPC24XX_ALMIN, tm->tm_min); + rtc_writel(rtc, LPC24XX_ALHOUR, tm->tm_hour); + rtc_writel(rtc, LPC24XX_ALDOM, tm->tm_mday); + rtc_writel(rtc, LPC24XX_ALDOW, tm->tm_wday); + rtc_writel(rtc, LPC24XX_ALDOY, tm->tm_yday); + rtc_writel(rtc, LPC24XX_ALMON, tm->tm_mon); + rtc_writel(rtc, LPC24XX_ALYEAR, tm->tm_year); + + if (wkalrm->enabled) + rtc_writel(rtc, LPC24XX_AMR, 0); + + return 0; +} + +static int lpc24xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + + if (enable) + rtc_writel(rtc, LPC24XX_AMR, 0); + else + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + + return 0; +} + +static irqreturn_t lpc24xx_rtc_interrupt(int irq, void *data) +{ + unsigned long events = RTC_IRQF; + struct lpc24xx_rtc *rtc = data; + u32 rtc_iir; + + /* Check interrupt cause */ + rtc_iir = rtc_readl(rtc, LPC24XX_ILR); + if (rtc_iir & LPC24XX_RTCALF) { + events |= RTC_AF; + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + } + + /* Clear interrupt status and report event */ + rtc_writel(rtc, LPC24XX_ILR, rtc_iir); + rtc_update_irq(rtc->rtc, 1, events); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops lpc24xx_rtc_ops = { + .read_time = lpc24xx_rtc_read_time, + .set_time = lpc24xx_rtc_set_time, + .read_alarm = lpc24xx_rtc_read_alarm, + .set_alarm = lpc24xx_rtc_set_alarm, + .alarm_irq_enable = lpc24xx_rtc_alarm_irq_enable, +}; + +static int lpc24xx_rtc_probe(struct platform_device *pdev) +{ + struct lpc24xx_rtc *rtc; + struct resource *res; + int irq, ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtc->rtc_base)) + return PTR_ERR(rtc->rtc_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_warn(&pdev->dev, "can't get interrupt resource\n"); + return irq; + } + + rtc->clk_rtc = devm_clk_get(&pdev->dev, "rtc"); + if (IS_ERR(rtc->clk_rtc)) { + dev_err(&pdev->dev, "error getting rtc clock\n"); + return PTR_ERR(rtc->clk_rtc); + } + + rtc->clk_reg = devm_clk_get(&pdev->dev, "reg"); + if (IS_ERR(rtc->clk_reg)) { + dev_err(&pdev->dev, "error getting reg clock\n"); + return PTR_ERR(rtc->clk_reg); + } + + ret = clk_prepare_enable(rtc->clk_rtc); + if (ret) { + dev_err(&pdev->dev, "unable to enable rtc clock\n"); + return ret; + } + + ret = clk_prepare_enable(rtc->clk_reg); + if (ret) { + dev_err(&pdev->dev, "unable to enable reg clock\n"); + goto disable_rtc_clk; + } + + platform_set_drvdata(pdev, rtc); + + /* Clear any pending interrupts */ + rtc_writel(rtc, LPC24XX_ILR, LPC24XX_RTCCIF | LPC24XX_RTCALF); + + /* Enable RTC count */ + rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN); + + ret = devm_request_irq(&pdev->dev, irq, lpc24xx_rtc_interrupt, 0, + pdev->name, rtc); + if (ret < 0) { + dev_warn(&pdev->dev, "can't request interrupt\n"); + goto disable_clks; + } + + rtc->rtc = devm_rtc_device_register(&pdev->dev, "lpc24xx-rtc", + &lpc24xx_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + dev_err(&pdev->dev, "can't register rtc device\n"); + ret = PTR_ERR(rtc->rtc); + goto disable_clks; + } + + return 0; + +disable_clks: + clk_disable_unprepare(rtc->clk_reg); +disable_rtc_clk: + clk_disable_unprepare(rtc->clk_rtc); + return ret; +} + +static int lpc24xx_rtc_remove(struct platform_device *pdev) +{ + struct lpc24xx_rtc *rtc = platform_get_drvdata(pdev); + + /* Ensure all interrupt sources are masked */ + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + rtc_writel(rtc, LPC24XX_CIIR, 0); + + rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN); + + clk_disable_unprepare(rtc->clk_rtc); + clk_disable_unprepare(rtc->clk_reg); + + return 0; +} + +static const struct of_device_id lpc24xx_rtc_match[] = { + { .compatible = "nxp,lpc1788-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match); + +static struct platform_driver lpc24xx_rtc_driver = { + .probe = lpc24xx_rtc_probe, + .remove = lpc24xx_rtc_remove, + .driver = { + .name = "lpc24xx-rtc", + .of_match_table = lpc24xx_rtc_match, + }, +}; +module_platform_driver(lpc24xx_rtc_driver); + +MODULE_AUTHOR("Kevin Wells "); +MODULE_DESCRIPTION("RTC driver for the LPC178x/18xx/408x/43xx SoCs"); +MODULE_LICENSE("GPL"); -- GitLab From f4a2eecb3ff9f51b179b213e7cc3766f920f2dc5 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Tue, 14 Jul 2015 13:28:28 +0530 Subject: [PATCH 6474/7006] rtc: opal: Enable alarms only when opal supports tpo rtc-opal driver provides support for rtc alarms via timed-power-on(tpo). However some Power platforms like BML use a fake rtc clock and don't support tpo. Such platforms are indicated by the missing 'has-tpo' property in the device tree. Current implementation however enables callback for rtc_class_ops.read/set alarm irrespective of the tpo support from the platform. This results in a failed opal call when kernel tries to read an existing alarms via opal_get_tpo_time during rtc device registration. This patch fixes this issue by setting opal_rtc_ops.read/set_alarm callback pointers only when tpo is supported. Acked-by: Michael Neuling Acked-by: Neelesh Gupta Signed-off-by: Vaibhav Jain Acked-by: Stewart Smith Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-opal.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 417d7b4a5cd85..6fbf9e617151d 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -190,11 +190,9 @@ exit: return rc; } -static const struct rtc_class_ops opal_rtc_ops = { +static struct rtc_class_ops opal_rtc_ops = { .read_time = opal_get_rtc_time, .set_time = opal_set_rtc_time, - .read_alarm = opal_get_tpo_time, - .set_alarm = opal_set_tpo_time, }; static int opal_rtc_probe(struct platform_device *pdev) @@ -202,8 +200,11 @@ static int opal_rtc_probe(struct platform_device *pdev) struct rtc_device *rtc; if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "has-tpo", - NULL)) + NULL)) { device_set_wakeup_capable(&pdev->dev, true); + opal_rtc_ops.read_alarm = opal_get_tpo_time; + opal_rtc_ops.set_alarm = opal_set_tpo_time; + } rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops, THIS_MODULE); -- GitLab From dfe6c04aa289de06df95d888719af63d1d4c982d Mon Sep 17 00:00:00 2001 From: Guo Zeng Date: Tue, 14 Jul 2015 01:31:38 +0000 Subject: [PATCH 6475/7006] rtc: sirfsoc: move to regmap APIs from platform-specific APIs The current codes use CSR platform specific API exported by machine codes to read/write RTC registers. they are: sirfsoc_rtc_iobrg_readl() sirfsoc_rtc_iobrg_writel() commit b1999477ed91 ("ARM: prima2: move to use REGMAP APIs for rtciobrg") moves to regmap support, now we can move to use regmap APIs in RTC driver. Signed-off-by: Guo Zeng Signed-off-by: Barry Song Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sirfsoc.c | 107 +++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 43 deletions(-) diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index edc3b43282d40..7367f617145cd 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -13,6 +13,7 @@ #include #include #include +#include #include @@ -48,12 +49,27 @@ struct sirfsoc_rtc_drv { /* Overflow for every 8 years extra time */ u32 overflow_rtc; spinlock_t lock; + struct regmap *regmap; #ifdef CONFIG_PM u32 saved_counter; u32 saved_overflow_rtc; #endif }; +static u32 sirfsoc_rtc_readl(struct sirfsoc_rtc_drv *rtcdrv, u32 offset) +{ + u32 val; + + regmap_read(rtcdrv->regmap, rtcdrv->rtc_base + offset, &val); + return val; +} + +static void sirfsoc_rtc_writel(struct sirfsoc_rtc_drv *rtcdrv, + u32 offset, u32 val) +{ + regmap_write(rtcdrv->regmap, rtcdrv->rtc_base + offset, val); +} + static int sirfsoc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { @@ -64,9 +80,9 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, spin_lock_irq(&rtcdrv->lock); - rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + rtc_count = sirfsoc_rtc_readl(rtcdrv, RTC_CN); - rtc_alarm = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_ALARM0); + rtc_alarm = sirfsoc_rtc_readl(rtcdrv, RTC_ALARM0); memset(alrm, 0, sizeof(struct rtc_wkalrm)); /* @@ -82,8 +98,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | rtc_alarm >> RTC_SHIFT, &(alrm->time)); - if (sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E) + if (sirfsoc_rtc_readl(rtcdrv, RTC_STATUS) & SIRFSOC_RTC_AL0E) alrm->enabled = 1; spin_unlock_irq(&rtcdrv->lock); @@ -103,8 +118,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, spin_lock_irq(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); if (rtc_status_reg & SIRFSOC_RTC_AL0E) { /* * An ongoing alarm in progress - ingore it and not @@ -113,8 +127,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, dev_info(dev, "An old alarm was set, will be replaced by a new one\n"); } - sirfsoc_rtc_iobrg_writel( - rtc_alarm << RTC_SHIFT, rtcdrv->rtc_base + RTC_ALARM0); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, rtc_alarm << RTC_SHIFT); rtc_status_reg &= ~0x07; /* mask out the lower status bits */ /* * This bit RTC_AL sets it as a wake-up source for Sleep Mode @@ -123,8 +136,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, rtc_status_reg |= SIRFSOC_RTC_AL0; /* enable the RTC alarm interrupt */ rtc_status_reg |= SIRFSOC_RTC_AL0E; - sirfsoc_rtc_iobrg_writel( - rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); spin_unlock_irq(&rtcdrv->lock); } else { @@ -135,8 +147,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, */ spin_lock_irq(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); if (rtc_status_reg & SIRFSOC_RTC_AL0E) { /* clear the RTC status register's alarm bit */ rtc_status_reg &= ~0x07; @@ -145,8 +156,8 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, /* Clear the Alarm enable bit */ rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); - sirfsoc_rtc_iobrg_writel(rtc_status_reg, - rtcdrv->rtc_base + RTC_STATUS); + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, + rtc_status_reg); } spin_unlock_irq(&rtcdrv->lock); @@ -167,9 +178,9 @@ static int sirfsoc_rtc_read_time(struct device *dev, * fail, read several times to make sure get stable value. */ do { - tmp_rtc = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + tmp_rtc = sirfsoc_rtc_readl(rtcdrv, RTC_CN); cpu_relax(); - } while (tmp_rtc != sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN)); + } while (tmp_rtc != sirfsoc_rtc_readl(rtcdrv, RTC_CN)); rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | tmp_rtc >> RTC_SHIFT, tm); @@ -187,10 +198,8 @@ static int sirfsoc_rtc_set_time(struct device *dev, rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT); - sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, - rtcdrv->rtc_base + RTC_SW_VALUE); - sirfsoc_rtc_iobrg_writel( - rtc_time << RTC_SHIFT, rtcdrv->rtc_base + RTC_CN); + sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); + sirfsoc_rtc_writel(rtcdrv, RTC_CN, rtc_time << RTC_SHIFT); return 0; } @@ -222,14 +231,13 @@ static int sirfsoc_rtc_alarm_irq_enable(struct device *dev, spin_lock_irq(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); if (enabled) rtc_status_reg |= SIRFSOC_RTC_AL0E; else rtc_status_reg &= ~SIRFSOC_RTC_AL0E; - sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); spin_unlock_irq(&rtcdrv->lock); @@ -254,7 +262,7 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) spin_lock(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); /* this bit will be set ONLY if an alarm was active * and it expired NOW * So this is being used as an ASSERT @@ -270,7 +278,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) /* Clear the Alarm enable bit */ rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); } - sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); spin_unlock(&rtcdrv->lock); @@ -287,6 +296,13 @@ static const struct of_device_id sirfsoc_rtc_of_match[] = { { .compatible = "sirf,prima2-sysrtc"}, {}, }; + +const struct regmap_config sysrtc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .fast_io = true, +}; + MODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match); static int sirfsoc_rtc_probe(struct platform_device *pdev) @@ -314,27 +330,35 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) /* Register rtc alarm as a wakeup source */ device_init_wakeup(&pdev->dev, 1); + rtcdrv->regmap = devm_regmap_init_iobg(&pdev->dev, + &sysrtc_regmap_config); + if (IS_ERR(rtcdrv->regmap)) { + err = PTR_ERR(rtcdrv->regmap); + dev_err(&pdev->dev, "Failed to allocate register map: %d\n", + err); + return err; + } + /* * Set SYS_RTC counter in RTC_HZ HZ Units * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 * If 16HZ, therefore RTC_DIV = 1023; */ rtc_div = ((32768 / RTC_HZ) / 2) - 1; - sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); + sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); /* 0x3 -> RTC_CLK */ - sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, - rtcdrv->rtc_base + RTC_CLOCK_SWITCH); + sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); /* reset SYS RTC ALARM0 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); /* reset SYS RTC ALARM1 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); /* Restore RTC Overflow From Register After Command Reboot */ rtcdrv->overflow_rtc = - sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sirfsoc_rtc_ops, THIS_MODULE); @@ -372,10 +396,10 @@ static int sirfsoc_rtc_suspend(struct device *dev) { struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); rtcdrv->overflow_rtc = - sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); rtcdrv->saved_counter = - sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + sirfsoc_rtc_readl(rtcdrv, RTC_CN); rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq)) rtcdrv->irq_wake = 1; @@ -392,12 +416,10 @@ static int sirfsoc_rtc_resume(struct device *dev) * if resume from snapshot and the rtc power is lost, * restroe the rtc settings */ - if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_CLOCK_SWITCH)) { + if (SIRFSOC_RTC_CLK != sirfsoc_rtc_readl(rtcdrv, RTC_CLOCK_SWITCH)) { u32 rtc_div; /* 0x3 -> RTC_CLK */ - sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, - rtcdrv->rtc_base + RTC_CLOCK_SWITCH); + sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); /* * Set SYS_RTC counter in RTC_HZ HZ Units * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 @@ -405,13 +427,13 @@ static int sirfsoc_rtc_resume(struct device *dev) */ rtc_div = ((32768 / RTC_HZ) / 2) - 1; - sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); + sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); /* reset SYS RTC ALARM0 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); /* reset SYS RTC ALARM1 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); } rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc; @@ -419,15 +441,14 @@ static int sirfsoc_rtc_resume(struct device *dev) * if current counter is small than previous, * it means overflow in sleep */ - tmp = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + tmp = sirfsoc_rtc_readl(rtcdrv, RTC_CN); if (tmp <= rtcdrv->saved_counter) rtcdrv->overflow_rtc++; /* *PWRC Value Be Changed When Suspend, Restore Overflow * In Memory To Register */ - sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, - rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); if (device_may_wakeup(dev) && rtcdrv->irq_wake) { disable_irq_wake(rtcdrv->irq); -- GitLab From 6706664d92ea841913d5fcfd06c290fbe6d33bd2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:49 -0700 Subject: [PATCH 6476/7006] rtc: class: fix double free in rtc_register_device() error path Commit 59cca865f21e ("drivers/rtc/class.c: fix device_register() error handling") correctly noted that naked kfree() should not be used after failed device_register() call, however, while it added the needed put_device() it forgot to remove the original kfree() causing double-free. Cc: Vasiliy Kulikov Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index ea2a315df6b7b..eb82ec2a21bd8 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -234,8 +234,9 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, err = device_register(&rtc->dev); if (err) { + /* This will free both memory and the ID */ put_device(&rtc->dev); - goto exit_kfree; + goto exit; } rtc_dev_add_device(rtc); @@ -247,9 +248,6 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, return rtc; -exit_kfree: - kfree(rtc); - exit_ida: ida_simple_remove(&rtc_ida, id); -- GitLab From c3b399a4b6703a04ef6eb3efe35ff12163e409e0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:50 -0700 Subject: [PATCH 6477/7006] rtc: class: remove unnecessary device_get() in rtc_device_unregister Technically the address of rtc->dev can never be NULL, so get_device() can never fail. Also caller of rtc_device_unregister() supposed to be the owner of the device and thus have a valid reference. Therefore call to get_device() is not needed here. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index eb82ec2a21bd8..de7707f7e7666 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -266,19 +266,18 @@ EXPORT_SYMBOL_GPL(rtc_device_register); */ void rtc_device_unregister(struct rtc_device *rtc) { - if (get_device(&rtc->dev) != NULL) { - mutex_lock(&rtc->ops_lock); - /* remove innards of this RTC, then disable it, before - * letting any rtc_class_open() users access it again - */ - rtc_sysfs_del_device(rtc); - rtc_dev_del_device(rtc); - rtc_proc_del_device(rtc); - device_unregister(&rtc->dev); - rtc->ops = NULL; - mutex_unlock(&rtc->ops_lock); - put_device(&rtc->dev); - } + mutex_lock(&rtc->ops_lock); + /* + * Remove innards of this RTC, then disable it, before + * letting any rtc_class_open() users access it again + */ + rtc_sysfs_del_device(rtc); + rtc_dev_del_device(rtc); + rtc_proc_del_device(rtc); + device_del(&rtc->dev); + rtc->ops = NULL; + mutex_unlock(&rtc->ops_lock); + put_device(&rtc->dev); } EXPORT_SYMBOL_GPL(rtc_device_unregister); -- GitLab From 1e4cd62558c293bc51cc179d676b708683a29c12 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:51 -0700 Subject: [PATCH 6478/7006] rtc: dev: properly manage lifetime of dev and cdev in rtc device struct rtc embeds both struct dev and struct cdev. Unfortunately character device structure may outlive the parent rtc structure unless we set it up as parent of character device so that it will stay pinned until character device is freed. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-dev.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 799c34bcb26f3..a6d9434addf6f 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -477,6 +477,7 @@ void rtc_dev_prepare(struct rtc_device *rtc) cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; + rtc->char_dev.kobj.parent = &rtc->dev.kobj; } void rtc_dev_add_device(struct rtc_device *rtc) -- GitLab From 0d9030a2c3214cf8f9bfff84204e0f5ba5e790d7 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 5 Jun 2015 16:59:43 +0300 Subject: [PATCH 6479/7006] rtc: fix drivers that consider 0 as a valid IRQ in client->irq Since dab472eb931b ("i2c / ACPI: Use 0 to indicate that device does not have interrupt assigned"), 0 is not a valid i2c client irq anymore, so change all driver's checks accordingly. The same issue occurs when the device is instantiated via device tree with no IRQ, or from the i2c sysfs interface, even before the patch above. Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 4 ++-- drivers/rtc/rtc-ds3232.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 6d8665647eee2..7067232ba5071 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -688,7 +688,7 @@ static int ds1374_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - if (client->irq >= 0 && device_may_wakeup(&client->dev)) + if (client->irq > 0 && device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); return 0; } @@ -697,7 +697,7 @@ static int ds1374_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - if (client->irq >= 0 && device_may_wakeup(&client->dev)) + if (client->irq > 0 && device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); return 0; } diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 18f062f2a6343..a8702dda0f262 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -443,7 +443,7 @@ static int ds3232_remove(struct i2c_client *client) { struct ds3232 *ds3232 = i2c_get_clientdata(client); - if (client->irq >= 0) { + if (client->irq > 0) { mutex_lock(&ds3232->mutex); ds3232->exiting = 1; mutex_unlock(&ds3232->mutex); -- GitLab From f2284f9c900a47961883b88064933a89b5dd5f46 Mon Sep 17 00:00:00 2001 From: Henri Roosen Date: Fri, 24 Jul 2015 10:16:06 +0200 Subject: [PATCH 6480/7006] rtc: rx8025: remove obsolete local_irq_disable() and local_irq_enable() for rtc_update_irq() Since commit e6229bec25be ("rtc: make rtc_update_irq callable with irqs enabled") rtc_update_irq() is callable with irqs enabled. Signed-off-by: Henri Roosen Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index a297542e2f8a3..6fe87702fcff3 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -161,9 +161,7 @@ static void rx8025_work(struct work_struct *work) if (status & RX8025_BIT_CTRL2_CTFG) { /* periodic */ status &= ~RX8025_BIT_CTRL2_CTFG; - local_irq_disable(); rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF); - local_irq_enable(); } if (status & RX8025_BIT_CTRL2_DAFG) { @@ -172,9 +170,7 @@ static void rx8025_work(struct work_struct *work) if (rx8025_write_reg(client, RX8025_REG_CTRL1, rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE)) goto out; - local_irq_disable(); rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); - local_irq_enable(); } /* acknowledge IRQ */ -- GitLab From df100c017ea9f1a6a517c3fba84f8507973c004e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:06 -0700 Subject: [PATCH 6481/7006] rtc: make rtc_does_wakealarm() return boolean Users of rtc_does_wakealarm() return value treat it as boolean so let's change the signature accordingly. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index babd43bf3ddc3..2fbc11bb4352f 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -230,10 +230,11 @@ static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, * suspend-to-disk. So: no attribute unless that side effect is possible. * (Userspace may disable that mechanism later.) */ -static inline int rtc_does_wakealarm(struct rtc_device *rtc) +static bool rtc_does_wakealarm(struct rtc_device *rtc) { if (!device_can_wakeup(rtc->dev.parent)) - return 0; + return false; + return rtc->ops->set_alarm != NULL; } -- GitLab From a17ccd1c6a327e5b468358e8352a6af004261473 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:07 -0700 Subject: [PATCH 6482/7006] rtc: switch wakealarm attribute to DEVICE_ATTR_RW Instead of using older style DEVICE_ATTR for wakealarm attribute let's switch to using DEVICE_ATTR_RW that ensures consistent across the kernel permissions on the attribute. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sysfs.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 2fbc11bb4352f..e3ce1dc92b654 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -134,8 +134,7 @@ static struct attribute *rtc_attrs[] = { ATTRIBUTE_GROUPS(rtc); static ssize_t -rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, - char *buf) +wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; unsigned long alarm; @@ -159,7 +158,7 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, } static ssize_t -rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, +wakealarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { ssize_t retval; @@ -221,8 +220,7 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, retval = rtc_set_alarm(rtc, &alm); return (retval < 0) ? retval : n; } -static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, - rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); +static DEVICE_ATTR_RW(wakealarm); /* The reason to trigger an alarm with no process watching it (via sysfs) -- GitLab From 3ee2c40b7ac2bf121aaa1176d8ac25b6a26e3a94 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:08 -0700 Subject: [PATCH 6483/7006] rtc: switch to using is_visible() to control sysfs attributes Instead of creating wakealarm attribute manually, after the device has been registered, let's rely on facilities provided by the attribute groups to control which attributes are visible and which are not. This allows to create all needed attributes at once, at the same time that we register RTC class device. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 4 +-- drivers/rtc/rtc-core.h | 19 +++---------- drivers/rtc/rtc-sysfs.c | 59 +++++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 48 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index de7707f7e7666..de86578bcd6d7 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -202,6 +202,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->max_user_freq = 64; rtc->dev.parent = dev; rtc->dev.class = rtc_class; + rtc->dev.groups = rtc_get_dev_attribute_groups(); rtc->dev.release = rtc_device_release; mutex_init(&rtc->ops_lock); @@ -240,7 +241,6 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, } rtc_dev_add_device(rtc); - rtc_sysfs_add_device(rtc); rtc_proc_add_device(rtc); dev_info(dev, "rtc core: registered %s as %s\n", @@ -271,7 +271,6 @@ void rtc_device_unregister(struct rtc_device *rtc) * Remove innards of this RTC, then disable it, before * letting any rtc_class_open() users access it again */ - rtc_sysfs_del_device(rtc); rtc_dev_del_device(rtc); rtc_proc_del_device(rtc); device_del(&rtc->dev); @@ -360,7 +359,6 @@ static int __init rtc_init(void) } rtc_class->pm = RTC_CLASS_DEV_PM_OPS; rtc_dev_init(); - rtc_sysfs_init(rtc_class); return 0; } diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h index 5f9df7430a227..a098aea197fc7 100644 --- a/drivers/rtc/rtc-core.h +++ b/drivers/rtc/rtc-core.h @@ -48,23 +48,10 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc) #endif #ifdef CONFIG_RTC_INTF_SYSFS - -extern void __init rtc_sysfs_init(struct class *); -extern void rtc_sysfs_add_device(struct rtc_device *rtc); -extern void rtc_sysfs_del_device(struct rtc_device *rtc); - +const struct attribute_group **rtc_get_dev_attribute_groups(void); #else - -static inline void rtc_sysfs_init(struct class *rtc) -{ -} - -static inline void rtc_sysfs_add_device(struct rtc_device *rtc) +static inline const struct attribute_group **rtc_get_dev_attribute_groups(void) { + return NULL; } - -static inline void rtc_sysfs_del_device(struct rtc_device *rtc) -{ -} - #endif diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index e3ce1dc92b654..7273855ed02ef 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -122,17 +122,6 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(hctosys); -static struct attribute *rtc_attrs[] = { - &dev_attr_name.attr, - &dev_attr_date.attr, - &dev_attr_time.attr, - &dev_attr_since_epoch.attr, - &dev_attr_max_user_freq.attr, - &dev_attr_hctosys.attr, - NULL, -}; -ATTRIBUTE_GROUPS(rtc); - static ssize_t wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -222,6 +211,16 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(wakealarm); +static struct attribute *rtc_attrs[] = { + &dev_attr_name.attr, + &dev_attr_date.attr, + &dev_attr_time.attr, + &dev_attr_since_epoch.attr, + &dev_attr_max_user_freq.attr, + &dev_attr_hctosys.attr, + &dev_attr_wakealarm.attr, + NULL, +}; /* The reason to trigger an alarm with no process watching it (via sysfs) * is its side effect: waking from a system state like suspend-to-RAM or @@ -236,29 +235,31 @@ static bool rtc_does_wakealarm(struct rtc_device *rtc) return rtc->ops->set_alarm != NULL; } - -void rtc_sysfs_add_device(struct rtc_device *rtc) +static umode_t rtc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) { - int err; + struct device *dev = container_of(kobj, struct device, kobj); + struct rtc_device *rtc = to_rtc_device(dev); + umode_t mode = attr->mode; - /* not all RTCs support both alarms and wakeup */ - if (!rtc_does_wakealarm(rtc)) - return; + if (attr == &dev_attr_wakealarm.attr) + if (!rtc_does_wakealarm(rtc)) + mode = 0; - err = device_create_file(&rtc->dev, &dev_attr_wakealarm); - if (err) - dev_err(rtc->dev.parent, - "failed to create alarm attribute, %d\n", err); + return mode; } -void rtc_sysfs_del_device(struct rtc_device *rtc) -{ - /* REVISIT did we add it successfully? */ - if (rtc_does_wakealarm(rtc)) - device_remove_file(&rtc->dev, &dev_attr_wakealarm); -} +static struct attribute_group rtc_attr_group = { + .is_visible = rtc_attr_is_visible, + .attrs = rtc_attrs, +}; + +static const struct attribute_group *rtc_attr_groups[] = { + &rtc_attr_group, + NULL +}; -void __init rtc_sysfs_init(struct class *rtc_class) +const struct attribute_group **rtc_get_dev_attribute_groups(void) { - rtc_class->dev_groups = rtc_groups; + return rtc_attr_groups; } -- GitLab From d7f9777de884daf5721211bddfd21e7c8c156b17 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Thu, 30 Jul 2015 22:53:14 +0800 Subject: [PATCH 6484/7006] rtc: mt6397: implement suspend/resume function in rtc-mt6397 driver Implement the suspend/resume function in order to control rtc's irq_wake flag and handle as wakeup source. Signed-off-by: Henry Chen Acked-by: Eddie Huang Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mt6397.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index eab230be5a54f..30c926b363615 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -373,6 +373,31 @@ static int mtk_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int mt6397_rtc_suspend(struct device *dev) +{ + struct mt6397_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + + return 0; +} + +static int mt6397_rtc_resume(struct device *dev) +{ + struct mt6397_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend, + mt6397_rtc_resume); + static const struct of_device_id mt6397_rtc_of_match[] = { { .compatible = "mediatek,mt6397-rtc", }, { } @@ -382,6 +407,7 @@ static struct platform_driver mtk_rtc_driver = { .driver = { .name = "mt6397-rtc", .of_match_table = mt6397_rtc_of_match, + .pm = &mt6397_pm_ops, }, .probe = mtk_rtc_probe, .remove = mtk_rtc_remove, -- GitLab From 80ca3277bc7f398e3315af996443464dac5d4b88 Mon Sep 17 00:00:00 2001 From: S Twiss Date: Tue, 21 Jul 2015 11:29:07 +0100 Subject: [PATCH 6485/7006] rtc: da9063: Add DA9062 RTC capability to DA9063 RTC driver Add DA9062 RTC support into the existing DA9063 RTC driver component by using generic access tables for common register and bit mask definitions. The following change will add generic register and bit mask support to the DA9063 RTC. The changes are slightly complicated by requiring support for three register sets: DA9063-AD, DA9063-BB and DA9062-AA. The following alterations have been made to the DA9063 RTC: - Addition of a da9063_compatible_rtc_regmap structure to hold all generic registers and bitmasks for this type of RTC component. - A re-write of struct da9063 to use pointers for regmap and compatible registers/masks definitions - Addition of a of_device_id table for DA9063 and DA9062 defaults - Refactoring functions to use struct da9063_compatible_rtc accesses to generic registers/masks instead of using defines from registers.h - Re-work of da9063_rtc_probe() to use of_match_node() and dev_get_regmap() to provide initialisation of generic registers and masks and access to regmap Signed-off-by: Steve Twiss Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 6 +- drivers/rtc/rtc-da9063.c | 391 ++++++++++++++++++++++++++++----------- 2 files changed, 282 insertions(+), 115 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e132ccbec5158..35ea04c50a5ca 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -945,11 +945,11 @@ config RTC_DRV_DA9055 will be called rtc-da9055 config RTC_DRV_DA9063 - tristate "Dialog Semiconductor DA9063 RTC" - depends on MFD_DA9063 + tristate "Dialog Semiconductor DA9063/DA9062 RTC" + depends on MFD_DA9063 || MFD_DA9062 help If you say yes here you will get support for the RTC subsystem - of the Dialog Semiconductor DA9063. + for the Dialog Semiconductor PMIC chips DA9063 and DA9062. This driver can also be built as a module. If so, the module will be called "rtc-da9063". diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 7ffc5707f8b9d..5f38a5c84b562 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -12,15 +12,18 @@ * Library General Public License for more details. */ +#include +#include +#include #include #include -#include +#include #include -#include +#include #include #include -#include -#include + +#include #include #include @@ -29,99 +32,230 @@ #define YEARS_FROM_DA9063(year) ((year) + 100) #define MONTHS_FROM_DA9063(month) ((month) - 1) -#define RTC_ALARM_DATA_LEN (DA9063_AD_REG_ALARM_Y - DA9063_AD_REG_ALARM_MI + 1) - -#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1) -#define RTC_SEC 0 -#define RTC_MIN 1 -#define RTC_HOUR 2 -#define RTC_DAY 3 -#define RTC_MONTH 4 -#define RTC_YEAR 5 - -struct da9063_rtc { - struct rtc_device *rtc_dev; - struct da9063 *hw; - struct rtc_time alarm_time; - bool rtc_sync; - int alarm_year; - int alarm_start; - int alarm_len; - int data_start; +enum { + RTC_SEC = 0, + RTC_MIN = 1, + RTC_HOUR = 2, + RTC_DAY = 3, + RTC_MONTH = 4, + RTC_YEAR = 5, + RTC_DATA_LEN +}; + +struct da9063_compatible_rtc_regmap { + /* REGS */ + int rtc_enable_reg; + int rtc_enable_32k_crystal_reg; + int rtc_alarm_secs_reg; + int rtc_alarm_year_reg; + int rtc_count_secs_reg; + int rtc_count_year_reg; + int rtc_event_reg; + /* MASKS */ + int rtc_enable_mask; + int rtc_crystal_mask; + int rtc_event_alarm_mask; + int rtc_alarm_on_mask; + int rtc_alarm_status_mask; + int rtc_tick_on_mask; + int rtc_ready_to_read_mask; + int rtc_count_sec_mask; + int rtc_count_min_mask; + int rtc_count_hour_mask; + int rtc_count_day_mask; + int rtc_count_month_mask; + int rtc_count_year_mask; + /* ALARM CONFIG */ + int rtc_data_start; + int rtc_alarm_len; +}; + +struct da9063_compatible_rtc { + struct rtc_device *rtc_dev; + struct rtc_time alarm_time; + struct regmap *regmap; + const struct da9063_compatible_rtc_regmap *config; + bool rtc_sync; +}; + +static const struct da9063_compatible_rtc_regmap da9063_ad_regs = { + /* REGS */ + .rtc_enable_reg = DA9063_REG_CONTROL_E, + .rtc_alarm_secs_reg = DA9063_AD_REG_ALARM_MI, + .rtc_alarm_year_reg = DA9063_AD_REG_ALARM_Y, + .rtc_count_secs_reg = DA9063_REG_COUNT_S, + .rtc_count_year_reg = DA9063_REG_COUNT_Y, + .rtc_event_reg = DA9063_REG_EVENT_A, + /* MASKS */ + .rtc_enable_mask = DA9063_RTC_EN, + .rtc_crystal_mask = DA9063_CRYSTAL, + .rtc_enable_32k_crystal_reg = DA9063_REG_EN_32K, + .rtc_event_alarm_mask = DA9063_E_ALARM, + .rtc_alarm_on_mask = DA9063_ALARM_ON, + .rtc_alarm_status_mask = DA9063_ALARM_STATUS_ALARM | + DA9063_ALARM_STATUS_TICK, + .rtc_tick_on_mask = DA9063_TICK_ON, + .rtc_ready_to_read_mask = DA9063_RTC_READ, + .rtc_count_sec_mask = DA9063_COUNT_SEC_MASK, + .rtc_count_min_mask = DA9063_COUNT_MIN_MASK, + .rtc_count_hour_mask = DA9063_COUNT_HOUR_MASK, + .rtc_count_day_mask = DA9063_COUNT_DAY_MASK, + .rtc_count_month_mask = DA9063_COUNT_MONTH_MASK, + .rtc_count_year_mask = DA9063_COUNT_YEAR_MASK, + /* ALARM CONFIG */ + .rtc_data_start = RTC_MIN, + .rtc_alarm_len = RTC_DATA_LEN - 1, +}; + +static const struct da9063_compatible_rtc_regmap da9063_bb_regs = { + /* REGS */ + .rtc_enable_reg = DA9063_REG_CONTROL_E, + .rtc_alarm_secs_reg = DA9063_BB_REG_ALARM_S, + .rtc_alarm_year_reg = DA9063_BB_REG_ALARM_Y, + .rtc_count_secs_reg = DA9063_REG_COUNT_S, + .rtc_count_year_reg = DA9063_REG_COUNT_Y, + .rtc_event_reg = DA9063_REG_EVENT_A, + /* MASKS */ + .rtc_enable_mask = DA9063_RTC_EN, + .rtc_crystal_mask = DA9063_CRYSTAL, + .rtc_enable_32k_crystal_reg = DA9063_REG_EN_32K, + .rtc_event_alarm_mask = DA9063_E_ALARM, + .rtc_alarm_on_mask = DA9063_ALARM_ON, + .rtc_alarm_status_mask = DA9063_ALARM_STATUS_ALARM | + DA9063_ALARM_STATUS_TICK, + .rtc_tick_on_mask = DA9063_TICK_ON, + .rtc_ready_to_read_mask = DA9063_RTC_READ, + .rtc_count_sec_mask = DA9063_COUNT_SEC_MASK, + .rtc_count_min_mask = DA9063_COUNT_MIN_MASK, + .rtc_count_hour_mask = DA9063_COUNT_HOUR_MASK, + .rtc_count_day_mask = DA9063_COUNT_DAY_MASK, + .rtc_count_month_mask = DA9063_COUNT_MONTH_MASK, + .rtc_count_year_mask = DA9063_COUNT_YEAR_MASK, + /* ALARM CONFIG */ + .rtc_data_start = RTC_SEC, + .rtc_alarm_len = RTC_DATA_LEN, +}; + +static const struct da9063_compatible_rtc_regmap da9062_aa_regs = { + /* REGS */ + .rtc_enable_reg = DA9062AA_CONTROL_E, + .rtc_alarm_secs_reg = DA9062AA_ALARM_S, + .rtc_alarm_year_reg = DA9062AA_ALARM_Y, + .rtc_count_secs_reg = DA9062AA_COUNT_S, + .rtc_count_year_reg = DA9062AA_COUNT_Y, + .rtc_event_reg = DA9062AA_EVENT_A, + /* MASKS */ + .rtc_enable_mask = DA9062AA_RTC_EN_MASK, + .rtc_crystal_mask = DA9062AA_CRYSTAL_MASK, + .rtc_enable_32k_crystal_reg = DA9062AA_EN_32K, + .rtc_event_alarm_mask = DA9062AA_M_ALARM_MASK, + .rtc_alarm_on_mask = DA9062AA_ALARM_ON_MASK, + .rtc_alarm_status_mask = (0x02 << 6), + .rtc_tick_on_mask = DA9062AA_TICK_ON_MASK, + .rtc_ready_to_read_mask = DA9062AA_RTC_READ_MASK, + .rtc_count_sec_mask = DA9062AA_COUNT_SEC_MASK, + .rtc_count_min_mask = DA9062AA_COUNT_MIN_MASK, + .rtc_count_hour_mask = DA9062AA_COUNT_HOUR_MASK, + .rtc_count_day_mask = DA9062AA_COUNT_DAY_MASK, + .rtc_count_month_mask = DA9062AA_COUNT_MONTH_MASK, + .rtc_count_year_mask = DA9062AA_COUNT_YEAR_MASK, + /* ALARM CONFIG */ + .rtc_data_start = RTC_SEC, + .rtc_alarm_len = RTC_DATA_LEN, +}; + +static const struct of_device_id da9063_compatible_reg_id_table[] = { + { .compatible = "dlg,da9063-rtc", .data = &da9063_bb_regs }, + { .compatible = "dlg,da9062-rtc", .data = &da9062_aa_regs }, + { }, }; -static void da9063_data_to_tm(u8 *data, struct rtc_time *tm) +static void da9063_data_to_tm(u8 *data, struct rtc_time *tm, + struct da9063_compatible_rtc *rtc) { - tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK; - tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK; - tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK; - tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK; + const struct da9063_compatible_rtc_regmap *config = rtc->config; + + tm->tm_sec = data[RTC_SEC] & config->rtc_count_sec_mask; + tm->tm_min = data[RTC_MIN] & config->rtc_count_min_mask; + tm->tm_hour = data[RTC_HOUR] & config->rtc_count_hour_mask; + tm->tm_mday = data[RTC_DAY] & config->rtc_count_day_mask; tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] & - DA9063_COUNT_MONTH_MASK); + config->rtc_count_month_mask); tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] & - DA9063_COUNT_YEAR_MASK); + config->rtc_count_year_mask); } -static void da9063_tm_to_data(struct rtc_time *tm, u8 *data) +static void da9063_tm_to_data(struct rtc_time *tm, u8 *data, + struct da9063_compatible_rtc *rtc) { - data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK; - data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK; + const struct da9063_compatible_rtc_regmap *config = rtc->config; + + data[RTC_SEC] &= ~config->rtc_count_sec_mask; + data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask; - data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK; - data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK; + data[RTC_MIN] &= ~config->rtc_count_min_mask; + data[RTC_MIN] |= tm->tm_min & config->rtc_count_min_mask; - data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK; - data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK; + data[RTC_HOUR] &= ~config->rtc_count_hour_mask; + data[RTC_HOUR] |= tm->tm_hour & config->rtc_count_hour_mask; - data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK; - data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK; + data[RTC_DAY] &= ~config->rtc_count_day_mask; + data[RTC_DAY] |= tm->tm_mday & config->rtc_count_day_mask; - data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK; + data[RTC_MONTH] &= ~config->rtc_count_month_mask; data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) & - DA9063_COUNT_MONTH_MASK; + config->rtc_count_month_mask; - data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK; + data[RTC_YEAR] &= ~config->rtc_count_year_mask; data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) & - DA9063_COUNT_YEAR_MASK; + config->rtc_count_year_mask; } static int da9063_rtc_stop_alarm(struct device *dev) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; - return regmap_update_bits(rtc->hw->regmap, rtc->alarm_year, - DA9063_ALARM_ON, 0); + return regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_alarm_on_mask, + 0); } static int da9063_rtc_start_alarm(struct device *dev) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; - return regmap_update_bits(rtc->hw->regmap, rtc->alarm_year, - DA9063_ALARM_ON, DA9063_ALARM_ON); + return regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_alarm_on_mask, + config->rtc_alarm_on_mask); } static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; unsigned long tm_secs; unsigned long al_secs; u8 data[RTC_DATA_LEN]; int ret; - ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S, + ret = regmap_bulk_read(rtc->regmap, + config->rtc_count_secs_reg, data, RTC_DATA_LEN); if (ret < 0) { dev_err(dev, "Failed to read RTC time data: %d\n", ret); return ret; } - if (!(data[RTC_SEC] & DA9063_RTC_READ)) { + if (!(data[RTC_SEC] & config->rtc_ready_to_read_mask)) { dev_dbg(dev, "RTC not yet ready to be read by the host\n"); return -EINVAL; } - da9063_data_to_tm(data, tm); + da9063_data_to_tm(data, tm, rtc); rtc_tm_to_time(tm, &tm_secs); rtc_tm_to_time(&rtc->alarm_time, &al_secs); @@ -137,12 +271,14 @@ static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; u8 data[RTC_DATA_LEN]; int ret; - da9063_tm_to_data(tm, data); - ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S, + da9063_tm_to_data(tm, data, rtc); + ret = regmap_bulk_write(rtc->regmap, + config->rtc_count_secs_reg, data, RTC_DATA_LEN); if (ret < 0) dev_err(dev, "Failed to set RTC time data: %d\n", ret); @@ -152,26 +288,31 @@ static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; u8 data[RTC_DATA_LEN]; int ret; unsigned int val; data[RTC_SEC] = 0; - ret = regmap_bulk_read(rtc->hw->regmap, rtc->alarm_start, - &data[rtc->data_start], rtc->alarm_len); + ret = regmap_bulk_read(rtc->regmap, + config->rtc_alarm_secs_reg, + &data[config->rtc_data_start], + config->rtc_alarm_len); if (ret < 0) return ret; - da9063_data_to_tm(data, &alrm->time); + da9063_data_to_tm(data, &alrm->time, rtc); - alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON); + alrm->enabled = !!(data[RTC_YEAR] & config->rtc_alarm_on_mask); - ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val); + ret = regmap_read(rtc->regmap, + config->rtc_event_reg, + &val); if (ret < 0) return ret; - if (val & (DA9063_E_ALARM)) + if (val & config->rtc_event_alarm_mask) alrm->pending = 1; else alrm->pending = 0; @@ -181,11 +322,12 @@ static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; u8 data[RTC_DATA_LEN]; int ret; - da9063_tm_to_data(&alrm->time, data); + da9063_tm_to_data(&alrm->time, data, rtc); ret = da9063_rtc_stop_alarm(dev); if (ret < 0) { @@ -193,14 +335,16 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } - ret = regmap_bulk_write(rtc->hw->regmap, rtc->alarm_start, - &data[rtc->data_start], rtc->alarm_len); + ret = regmap_bulk_write(rtc->regmap, + config->rtc_alarm_secs_reg, + &data[config->rtc_data_start], + config->rtc_alarm_len); if (ret < 0) { dev_err(dev, "Failed to write alarm: %d\n", ret); return ret; } - da9063_data_to_tm(data, &rtc->alarm_time); + da9063_data_to_tm(data, &rtc->alarm_time, rtc); if (alrm->enabled) { ret = da9063_rtc_start_alarm(dev); @@ -213,7 +357,8 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +static int da9063_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) { if (enabled) return da9063_rtc_start_alarm(dev); @@ -223,10 +368,13 @@ static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static irqreturn_t da9063_alarm_event(int irq, void *data) { - struct da9063_rtc *rtc = data; + struct da9063_compatible_rtc *rtc = data; + const struct da9063_compatible_rtc_regmap *config = rtc->config; - regmap_update_bits(rtc->hw->regmap, rtc->alarm_year, - DA9063_ALARM_ON, 0); + regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_alarm_on_mask, + 0); rtc->rtc_sync = true; rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -244,72 +392,92 @@ static const struct rtc_class_ops da9063_rtc_ops = { static int da9063_rtc_probe(struct platform_device *pdev) { - struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_rtc *rtc; + struct da9063_compatible_rtc *rtc; + const struct da9063_compatible_rtc_regmap *config; + const struct of_device_id *match; int irq_alarm; u8 data[RTC_DATA_LEN]; int ret; - ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E, - DA9063_RTC_EN, DA9063_RTC_EN); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to enable RTC\n"); - goto err; - } + if (!pdev->dev.of_node) + return -ENXIO; - ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K, - DA9063_CRYSTAL, DA9063_CRYSTAL); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); - goto err; - } + match = of_match_node(da9063_compatible_reg_id_table, + pdev->dev.of_node); rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; - if (da9063->variant_code == PMIC_DA9063_AD) { - rtc->alarm_year = DA9063_AD_REG_ALARM_Y; - rtc->alarm_start = DA9063_AD_REG_ALARM_MI; - rtc->alarm_len = RTC_ALARM_DATA_LEN; - rtc->data_start = RTC_MIN; - } else { - rtc->alarm_year = DA9063_BB_REG_ALARM_Y; - rtc->alarm_start = DA9063_BB_REG_ALARM_S; - rtc->alarm_len = RTC_DATA_LEN; - rtc->data_start = RTC_SEC; + rtc->config = match->data; + if (of_device_is_compatible(pdev->dev.of_node, "dlg,da9063-rtc")) { + struct da9063 *chip = dev_get_drvdata(pdev->dev.parent); + + if (chip->variant_code == PMIC_DA9063_AD) + rtc->config = &da9063_ad_regs; } - ret = regmap_update_bits(da9063->regmap, rtc->alarm_start, - DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM, - 0); + rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!rtc->regmap) { + dev_warn(&pdev->dev, "Parent regmap unavailable.\n"); + return -ENXIO; + } + + config = rtc->config; + ret = regmap_update_bits(rtc->regmap, + config->rtc_enable_reg, + config->rtc_enable_mask, + config->rtc_enable_mask); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable RTC\n"); + return ret; + } + + ret = regmap_update_bits(rtc->regmap, + config->rtc_enable_32k_crystal_reg, + config->rtc_crystal_mask, + config->rtc_crystal_mask); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); + return ret; + } + + ret = regmap_update_bits(rtc->regmap, + config->rtc_alarm_secs_reg, + config->rtc_alarm_status_mask, + 0); if (ret < 0) { dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); - goto err; + return ret; } - ret = regmap_update_bits(da9063->regmap, rtc->alarm_start, + ret = regmap_update_bits(rtc->regmap, + config->rtc_alarm_secs_reg, DA9063_ALARM_STATUS_ALARM, DA9063_ALARM_STATUS_ALARM); if (ret < 0) { dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); - goto err; + return ret; } - ret = regmap_update_bits(da9063->regmap, rtc->alarm_year, - DA9063_TICK_ON, 0); + ret = regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_tick_on_mask, + 0); if (ret < 0) { dev_err(&pdev->dev, "Failed to disable TICKs\n"); - goto err; + return ret; } data[RTC_SEC] = 0; - ret = regmap_bulk_read(da9063->regmap, rtc->alarm_start, - &data[rtc->data_start], rtc->alarm_len); + ret = regmap_bulk_read(rtc->regmap, + config->rtc_alarm_secs_reg, + &data[config->rtc_data_start], + config->rtc_alarm_len); if (ret < 0) { dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n", ret); - goto err; + return ret; } platform_set_drvdata(pdev, rtc); @@ -322,18 +490,16 @@ static int da9063_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", irq_alarm, ret); - goto err; + return ret; } - rtc->hw = da9063; rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, &da9063_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); - da9063_data_to_tm(data, &rtc->alarm_time); + da9063_data_to_tm(data, &rtc->alarm_time, rtc); rtc->rtc_sync = false; -err: return ret; } @@ -341,6 +507,7 @@ static struct platform_driver da9063_rtc_driver = { .probe = da9063_rtc_probe, .driver = { .name = DA9063_DRVNAME_RTC, + .of_match_table = da9063_compatible_reg_id_table, }, }; -- GitLab From 88b8d33b1c6aadba553c998db91c4b36be0fac52 Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Mon, 6 Jul 2015 12:19:12 +0800 Subject: [PATCH 6486/7006] rtc: cmos: Cancel alarm timer if alarm time is equal to now+1 seconds Steps to reproduce the problem: 1) Enable RTC wake-up option in BIOS Setup 2) Issue one of these commands in the OS: "poweroff" or "shutdown -h now" 3) System will shut down and then reboot automatically Root-cause of the issue: 1) During the shutdown process, the hwclock utility is used to save the system clock to hardware clock (RTC). 2) The hwclock utility invokes ioctl() with RTC_UIE_ON. The kernel configures the RTC alarm for the periodic interrupt (every 1 second). 3) The hwclock uitlity closes the /dev/rtc0 device, and the kernel disables the RTC alarm irq (AIE bit of Register B) via ioctl() with RTC_UIE_OFF. But, the configured alarm time is the current_time + 1. 4) After the next 1 second is elapsed, the AF (alarm interrupt flag) of Register C is set. 5) The S5 handler in BIOS is invoked to configure alarm registers (enable AIE bit and configure alarm date/time). But, BIOS does not clear the previous interrupt status during alarm configuration. Therefore, "AF=AIE=1" causes the rtc device to trigger an interrupt. 6) So, the machine reboots automatically right after shutdown. This patch cancels the alarm timer if the following condictions are met (suggested by Alexandre): 1) The configured alarm time is equal to current_time + 1 seconds. 2) The AIE timer is not in use. The member 'alarm_expires' is introduced in struct cmos_rtc because of the following reasons: 1) The configured alarm time can be retrieved from cmos_read_alarm(), but we need to take the 'wrapped timestamp' and 'time rollover' into consideration. The function __rtc_read_alarm() eliminates the concerns. To avoid the duplicated code in the lower level RTC driver, invoking __rtc_read_alarm from the lower level RTC driver is not encouraged. Moreover, the compilation error 'the undefined __rtc_read_alarm" is observed if the lower level RTC driver is compiled as a kernel module. 2) The uie_rtctimer.node.expires and aie_timer.node.expires can be retrieved for the configured alarm time. But, the problem is that either of them might configure the CMOS alarm time. We cannot make sure UIE timer or AIE tiemr configured the CMOS alarm time before. (uie_rtctimer or aie_timer is enabled and then is disabled). 3) The patch introduces the member 'alarm_expires' to keep the newly configured alarm time, so the above-mentioned concerns can be eliminated. The issue goes away after 20-time shutdown tests. Signed-off-by: Adrian Huang Tested-by: Egbert Eich Tested-by: Diego Ercolani Cc: Borislav Petkov Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 64 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index a82556a0757a2..5ac9a5da85228 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -51,6 +51,7 @@ struct cmos_rtc { struct device *dev; int irq; struct resource *iomem; + time64_t alarm_expires; void (*wake_on)(struct device *); void (*wake_off)(struct device *); @@ -377,6 +378,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) spin_unlock_irq(&rtc_lock); + cmos->alarm_expires = rtc_tm_to_time64(&t->time); + return 0; } @@ -860,6 +863,51 @@ static void __exit cmos_do_remove(struct device *dev) cmos->dev = NULL; } +static int cmos_aie_poweroff(struct device *dev) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + struct rtc_time now; + time64_t t_now; + int retval = 0; + unsigned char rtc_control; + + if (!cmos->alarm_expires) + return -EINVAL; + + spin_lock_irq(&rtc_lock); + rtc_control = CMOS_READ(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + /* We only care about the situation where AIE is disabled. */ + if (rtc_control & RTC_AIE) + return -EBUSY; + + cmos_read_time(dev, &now); + t_now = rtc_tm_to_time64(&now); + + /* + * When enabling "RTC wake-up" in BIOS setup, the machine reboots + * automatically right after shutdown on some buggy boxes. + * This automatic rebooting issue won't happen when the alarm + * time is larger than now+1 seconds. + * + * If the alarm time is equal to now+1 seconds, the issue can be + * prevented by cancelling the alarm. + */ + if (cmos->alarm_expires == t_now + 1) { + struct rtc_wkalrm alarm; + + /* Cancel the AIE timer by configuring the past time. */ + rtc_time64_to_tm(t_now - 1, &alarm.time); + alarm.enabled = 0; + retval = cmos_set_alarm(dev, &alarm); + } else if (cmos->alarm_expires > t_now + 1) { + retval = -EBUSY; + } + + return retval; +} + #ifdef CONFIG_PM static int cmos_suspend(struct device *dev) @@ -1094,8 +1142,12 @@ static void cmos_pnp_shutdown(struct pnp_dev *pnp) struct device *dev = &pnp->dev; struct cmos_rtc *cmos = dev_get_drvdata(dev); - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) - return; + if (system_state == SYSTEM_POWER_OFF) { + int retval = cmos_poweroff(dev); + + if (cmos_aie_poweroff(dev) < 0 && !retval) + return; + } cmos_do_shutdown(cmos->irq); } @@ -1200,8 +1252,12 @@ static void cmos_platform_shutdown(struct platform_device *pdev) struct device *dev = &pdev->dev; struct cmos_rtc *cmos = dev_get_drvdata(dev); - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) - return; + if (system_state == SYSTEM_POWER_OFF) { + int retval = cmos_poweroff(dev); + + if (cmos_aie_poweroff(dev) < 0 && !retval) + return; + } cmos_do_shutdown(cmos->irq); } -- GitLab From 8109d44f7604cd5ab833ea09da98703f6eb16460 Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Mon, 6 Jul 2015 12:19:13 +0800 Subject: [PATCH 6487/7006] rtc: cmos: Revert "rtc-cmos: Add an alarm disable quirk" Commit d5a1c7e3fc38 ("rtc-cmos: Add an alarm disable quirk") that added a special quirk is not needed because [PATCH 1/2] of this patchset makes the kernel more robust: rtc-cmos: Cancel alarm timer if alarm time is equal to now+1 seconds Signed-off-by: Adrian Huang Tested-by: Egbert Eich Tested-by: Diego Ercolani Cc: Borislav Petkov Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 50 ------------------------------------------ 1 file changed, 50 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 5ac9a5da85228..c2e90c62a59ca 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -41,7 +41,6 @@ #include #include #include -#include /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include @@ -383,50 +382,6 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -/* - * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. - */ -static bool alarm_disable_quirk; - -static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) -{ - alarm_disable_quirk = true; - pr_info("BIOS has alarm-disable quirk - RTC alarms disabled\n"); - return 0; -} - -static const struct dmi_system_id rtc_quirks[] __initconst = { - /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ - { - .callback = set_alarm_disable_quirk, - .ident = "IBM Truman", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), - }, - }, - /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ - { - .callback = set_alarm_disable_quirk, - .ident = "Gigabyte GA-990XA-UD3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "Gigabyte Technology Co., Ltd."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), - }, - }, - /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ - { - .callback = set_alarm_disable_quirk, - .ident = "Toshiba Satellite L300", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), - }, - }, - {} -}; - static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -435,9 +390,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) if (!is_valid_irq(cmos->irq)) return -EINVAL; - if (alarm_disable_quirk) - return 0; - spin_lock_irqsave(&rtc_lock, flags); if (enabled) @@ -1299,8 +1251,6 @@ static int __init cmos_init(void) platform_driver_registered = true; } - dmi_check_system(rtc_quirks); - if (retval == 0) return 0; -- GitLab From 1c4fc2955ad37afb0d75ed5a67bad94c1529b0cf Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:46 +0200 Subject: [PATCH 6488/7006] rtc: Export OF module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab-b5ze-s3.c | 1 + drivers/rtc/rtc-isl12022.c | 1 + drivers/rtc/rtc-isl12057.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index 0fb1d767afa9e..a319bf1e49dea 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -1009,6 +1009,7 @@ static const struct of_device_id abb5zes3_dt_match[] = { { .compatible = "abracon,abb5zes3" }, { }, }; +MODULE_DEVICE_TABLE(of, abb5zes3_dt_match); #endif static const struct i2c_device_id abb5zes3_id[] = { diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 3726271367863..839d1fd63cd78 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -274,6 +274,7 @@ static const struct of_device_id isl12022_dt_match[] = { { .compatible = "isil,isl12022" }, { }, }; +MODULE_DEVICE_TABLE(of, isl12022_dt_match); #endif static const struct i2c_device_id isl12022_id[] = { diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index ee3e8dbcacafe..a0462e5430c79 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -648,6 +648,7 @@ static const struct of_device_id isl12057_dt_match[] = { { .compatible = "isil,isl12057" }, { }, }; +MODULE_DEVICE_TABLE(of, isl12057_dt_match); #endif static const struct i2c_device_id isl12057_id[] = { -- GitLab From 27675ef03c0535158b77af76591920fe041ebf14 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Wed, 29 Jul 2015 14:13:40 +0800 Subject: [PATCH 6489/7006] rtc: pl031: fix typo for author email The email address missed character ">", so add it. Signed-off-by: Leo Yan Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl031.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 99181fff88fd6..41dcb7ddb9060 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -476,6 +476,6 @@ static struct amba_driver pl031_driver = { module_amba_driver(pl031_driver); -MODULE_AUTHOR("Deepak Saxena "); MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver"); MODULE_LICENSE("GPL"); -- GitLab From ffe60fcfda98a3e4f51bc1e02ff5412a7e1c9c79 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:46:15 +0200 Subject: [PATCH 6490/7006] rtc: at91sam9: properly handle error case In case of a probe error, it is possible to abort after issuing clk_prepare_enable(). Ensure the clock is disabled and unprepared in that case. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 5ccaee32df722..152cd816cc433 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -451,8 +451,10 @@ static int at91_rtc_probe(struct platform_device *pdev) rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtcdev)) - return PTR_ERR(rtc->rtcdev); + if (IS_ERR(rtc->rtcdev)) { + ret = PTR_ERR(rtc->rtcdev); + goto err_clk; + } /* register irq handler after we know what name we'll use */ ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, @@ -460,7 +462,7 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_name(&rtc->rtcdev->dev), rtc); if (ret) { dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); - return ret; + goto err_clk; } /* NOTE: sam9260 rev A silicon has a ROM bug which resets the @@ -474,6 +476,11 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_name(&rtc->rtcdev->dev)); return 0; + +err_clk: + clk_disable_unprepare(rtc->sclk); + + return ret; } /* -- GitLab From 73ab31ce1bbc64c590b2a2d58364942adfa11a3f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:47:57 +0200 Subject: [PATCH 6491/7006] rtc: at91sam9: remove useless check rtc->sclk necessarily points to a valid clocks at this point. Else the probe would have aborted. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 152cd816cc433..0a8485ac3864d 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -494,8 +494,7 @@ static int at91_rtc_remove(struct platform_device *pdev) /* disable all interrupts */ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); - if (!IS_ERR(rtc->sclk)) - clk_disable_unprepare(rtc->sclk); + clk_disable_unprepare(rtc->sclk); return 0; } -- GitLab From 6932ff5395e3a2541fba696b38dc71393cf7ce57 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:49:24 +0200 Subject: [PATCH 6492/7006] rtc: at91sam9: sort headers alphabetically Sort included headers alphabetically. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 0a8485ac3864d..23f721d049b26 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -11,20 +11,20 @@ * 2 of the License, or (at your option) any later version. */ -#include -#include -#include -#include -#include +#include #include #include -#include -#include #include +#include #include +#include +#include +#include #include +#include +#include #include -#include +#include /* * This driver uses two configurable hardware resources that live in the -- GitLab From 8918bd8a5f6c37963ba04ae79ad6488108894ab9 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:51:10 +0200 Subject: [PATCH 6493/7006] rtc: at91sam9: get sclk rate after enabling it See help for clk_get_rate(): "obtain the current clock rate (in Hz) for a clock source. This is only valid once the clock source has been enabled." It currently returns the correct value but that may not stay that way. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 23f721d049b26..f9e85ace5e71d 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -425,18 +425,19 @@ static int at91_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->sclk)) return PTR_ERR(rtc->sclk); - sclk_rate = clk_get_rate(rtc->sclk); - if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { - dev_err(&pdev->dev, "Invalid slow clock rate\n"); - return -EINVAL; - } - ret = clk_prepare_enable(rtc->sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; } + sclk_rate = clk_get_rate(rtc->sclk); + if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { + dev_err(&pdev->dev, "Invalid slow clock rate\n"); + ret = -EINVAL; + goto err_clk; + } + mr = rtt_readl(rtc, MR); /* unless RTT is counting at 1 Hz, re-initialize it */ -- GitLab From 74000eb14a173f427240b90363580c686a675ddf Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 02:01:33 +0200 Subject: [PATCH 6494/7006] rtc: at91rm9200: sort headers alphabetically Sort included headers alphabetically. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91rm9200.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 35efd3f75b180..c4062d9f1bdd2 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -18,20 +18,20 @@ * */ -#include -#include -#include -#include -#include #include +#include #include -#include #include -#include #include -#include +#include +#include #include +#include +#include +#include +#include #include +#include #include #include "rtc-at91rm9200.h" -- GitLab From e7cba884af366f49ab7b7f5157e690357addebba Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Fri, 31 Jul 2015 16:23:43 +0530 Subject: [PATCH 6495/7006] rtc: Drop (un)likely before IS_ERR(_OR_NULL) IS_ERR(_OR_NULL) already contain an 'unlikely' compiler flag and there is no need to do that again from its callers. Drop it. gemini driver was using likely() for a failure case while the rtc driver is getting registered. That looks wrong and it should really be unlikely. But because we are killing all the unlikely() flags, lets kill that too. Signed-off-by: Viresh Kumar Acked-by: Hans Ulli Kroll Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 2 +- drivers/rtc/rtc-bfin.c | 2 +- drivers/rtc/rtc-gemini.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 11b639067312f..5836751b8203e 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -564,7 +564,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { - if (unlikely(IS_ERR_OR_NULL(rtc))) + if (IS_ERR_OR_NULL(rtc)) return; pm_stay_awake(rtc->dev.parent); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 3d44b11721ea0..535a5f9338d02 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -361,7 +361,7 @@ static int bfin_rtc_probe(struct platform_device *pdev) /* Register our RTC with the RTC framework */ rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc->rtc_dev))) + if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); /* Grab the IRQ and init the hardware */ diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index 35f4486738fce..2fed93e1114a6 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-gemini.c @@ -148,7 +148,7 @@ static int gemini_rtc_probe(struct platform_device *pdev) rtc->rtc_dev = rtc_device_register(pdev->name, dev, &gemini_rtc_ops, THIS_MODULE); - if (likely(IS_ERR(rtc->rtc_dev))) + if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); return 0; -- GitLab From 202cc98acf96de1c3897194e1ed5ae1c80c8b0f3 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 31 Jul 2015 15:01:04 +0530 Subject: [PATCH 6496/7006] rtc: gemini: fix ptr_ret.cocci warnings drivers/rtc/rtc-gemini.c:151:1-3: WARNING: PTR_ERR_OR_ZERO can be used Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: scripts/coccinelle/api/ptr_ret.cocci Signed-off-by: Fengguang Wu Signed-off-by: Viresh Kumar Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-gemini.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index 2fed93e1114a6..e84184647d152 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-gemini.c @@ -148,10 +148,7 @@ static int gemini_rtc_probe(struct platform_device *pdev) rtc->rtc_dev = rtc_device_register(pdev->name, dev, &gemini_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc_dev)) - return PTR_ERR(rtc->rtc_dev); - - return 0; + return PTR_ERR_OR_ZERO(rtc->rtc_dev); } static int gemini_rtc_remove(struct platform_device *pdev) -- GitLab From 11f67a8bbf65872c3e9edc70242420a8c314a860 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Jul 2015 11:39:51 +0200 Subject: [PATCH 6497/7006] rtc: at91rm9200: get and use slow clock Commit dca1a4b5ff6e ("clk: at91: keep slow clk enabled to prevent system hang") added a workaround for the slow clock as it is not properly handled by its users. Get and use the slow clock as it is necessary for the at91rm9200 rtc. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91rm9200.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index c4062d9f1bdd2..cb62e214b52a0 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -59,6 +60,7 @@ static bool suspended; static DEFINE_SPINLOCK(suspended_lock); static unsigned long cached_events; static u32 at91_rtc_imr; +static struct clk *sclk; static void at91_rtc_write_ier(u32 mask) { @@ -407,6 +409,16 @@ static int __init at91_rtc_probe(struct platform_device *pdev) return -ENOMEM; } + sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sclk)) + return PTR_ERR(sclk); + + ret = clk_prepare_enable(sclk); + if (ret) { + dev_err(&pdev->dev, "Could not enable slow clock\n"); + return ret; + } + at91_rtc_write(AT91_RTC_CR, 0); at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */ @@ -420,7 +432,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) "at91_rtc", pdev); if (ret) { dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); - return ret; + goto err_clk; } /* cpu init code should really have flagged this device as @@ -431,8 +443,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev) rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto err_clk; + } platform_set_drvdata(pdev, rtc); /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy @@ -442,6 +456,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); return 0; + +err_clk: + clk_disable_unprepare(sclk); + + return ret; } /* @@ -454,6 +473,8 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); + clk_disable_unprepare(sclk); + return 0; } -- GitLab From 3c217e51d8a272b9301058fe845d6c69cc0651cb Mon Sep 17 00:00:00 2001 From: Sylvain Chouleur Date: Mon, 8 Jun 2015 11:45:19 +0200 Subject: [PATCH 6498/7006] rtc: cmos: century support If century field is supported by the RTC CMOS device, then we should use it and then do not consider years greater that 169 as an error. For information, the year field of the rtc_time structure contains the value to add to 1970 to obtain the current year. This was a hack to be able to support years for 1970 to 2069. This patch remains compatible with this implementation. Signed-off-by: Sylvain Chouleur Signed-off-by: Alexandre Belloni --- include/asm-generic/rtc.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h index fa86f240c8743..4e3b6558331ea 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h @@ -16,6 +16,9 @@ #include #include #include +#ifdef CONFIG_ACPI +#include +#endif #define RTC_PIE 0x40 /* periodic interrupt enable */ #define RTC_AIE 0x20 /* alarm interrupt enable */ @@ -46,6 +49,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time) { unsigned char ctrl; unsigned long flags; + unsigned char century = 0; #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; @@ -78,6 +82,11 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time) time->tm_year = CMOS_READ(RTC_YEAR); #ifdef CONFIG_MACH_DECSTATION real_year = CMOS_READ(RTC_DEC_YEAR); +#endif +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century = CMOS_READ(acpi_gbl_FADT.century); #endif ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irqrestore(&rtc_lock, flags); @@ -90,12 +99,16 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time) time->tm_mday = bcd2bin(time->tm_mday); time->tm_mon = bcd2bin(time->tm_mon); time->tm_year = bcd2bin(time->tm_year); + century = bcd2bin(century); } #ifdef CONFIG_MACH_DECSTATION time->tm_year += real_year - 72; #endif + if (century) + time->tm_year += (century - 19) * 100; + /* * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; @@ -122,6 +135,7 @@ static inline int __set_rtc_time(struct rtc_time *time) #ifdef CONFIG_MACH_DECSTATION unsigned int real_yrs, leap_yr; #endif + unsigned char century = 0; yrs = time->tm_year; mon = time->tm_mon + 1; /* tm_mon starts at zero */ @@ -150,6 +164,15 @@ static inline int __set_rtc_time(struct rtc_time *time) yrs = 73; } #endif + +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) { + century = (yrs + 1900) / 100; + yrs %= 100; + } +#endif + /* These limits and adjustments are independent of * whether the chip is in binary mode or not. */ @@ -169,6 +192,7 @@ static inline int __set_rtc_time(struct rtc_time *time) day = bin2bcd(day); mon = bin2bcd(mon); yrs = bin2bcd(yrs); + century = bin2bcd(century); } save_control = CMOS_READ(RTC_CONTROL); @@ -185,6 +209,11 @@ static inline int __set_rtc_time(struct rtc_time *time) CMOS_WRITE(hrs, RTC_HOURS); CMOS_WRITE(min, RTC_MINUTES); CMOS_WRITE(sec, RTC_SECONDS); +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + CMOS_WRITE(century, acpi_gbl_FADT.century); +#endif CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); -- GitLab From a3781639e148497d7381d8786aaefe9f8b7e3028 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:26 +0300 Subject: [PATCH 6499/7006] rtc: cmos: clean up cmos_nvram_read()/cmos_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index c2e90c62a59ca..8f7034ba7d9e3 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -467,13 +467,6 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj, { int retval; - if (unlikely(off >= attr->size)) - return 0; - if (unlikely(off < 0)) - return -EINVAL; - if ((off + count) > attr->size) - count = attr->size - off; - off += NVRAM_OFFSET; spin_lock_irq(&rtc_lock); for (retval = 0; count; count--, off++, retval++) { @@ -498,12 +491,6 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj, int retval; cmos = dev_get_drvdata(container_of(kobj, struct device, kobj)); - if (unlikely(off >= attr->size)) - return -EFBIG; - if (unlikely(off < 0)) - return -EINVAL; - if ((off + count) > attr->size) - count = attr->size - off; /* NOTE: on at least PCs and Ataris, the boot firmware uses a * checksum on part of the NVRAM data. That's currently ignored -- GitLab From 273e03041e6d48024a57682cbf7b61510f74ec64 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:27 +0300 Subject: [PATCH 6500/7006] rtc: ds1305: clean up ds1305_nvram_read()/ds1305_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller size in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1305.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 12b07158a3664..baa5d047f9c82 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -538,15 +538,6 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj, spi = container_of(kobj, struct spi_device, dev.kobj); - if (unlikely(off >= DS1305_NVRAM_LEN)) - return 0; - if (count >= DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN; - if ((off + count) > DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN - off; - if (unlikely(!count)) - return count; - addr = DS1305_NVRAM + off; msg_init(&m, x, &addr, count, NULL, buf); @@ -569,15 +560,6 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj, spi = container_of(kobj, struct spi_device, dev.kobj); - if (unlikely(off >= DS1305_NVRAM_LEN)) - return -EFBIG; - if (count >= DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN; - if ((off + count) > DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN - off; - if (unlikely(!count)) - return count; - addr = (DS1305_WRITE | DS1305_NVRAM) + off; msg_init(&m, x, &addr, count, buf, NULL); -- GitLab From ca7c14d3a1ab1932732c506e32ab5b189b9c0a16 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:28 +0300 Subject: [PATCH 6501/7006] rtc: ds1307: clean up ds1307_nvram_read()/ds1307_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index c51bc0a65afce..a705e6490808f 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -782,13 +782,6 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= ds1307->nvram->size)) - return 0; - if ((off + count) > ds1307->nvram->size) - count = ds1307->nvram->size - off; - if (unlikely(!count)) - return count; - result = ds1307->read_block_data(client, ds1307->nvram_offset + off, count, buf); if (result < 0) @@ -808,13 +801,6 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= ds1307->nvram->size)) - return -EFBIG; - if ((off + count) > ds1307->nvram->size) - count = ds1307->nvram->size - off; - if (unlikely(!count)) - return count; - result = ds1307->write_block_data(client, ds1307->nvram_offset + off, count, buf); if (result < 0) { -- GitLab From f4843b19d2c7b5effd25e2a65b487d02bf55e96f Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:29 +0300 Subject: [PATCH 6502/7006] rtc: ds1343: clean up ds1343_nvram_read()/ds1343_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1343.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index ae9f997223b1f..79a06dd3c1856 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -162,12 +162,6 @@ static ssize_t ds1343_nvram_write(struct file *filp, struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct ds1343_priv *priv = dev_get_drvdata(dev); - if (unlikely(!count)) - return count; - - if ((count + off) > DS1343_NVRAM_LEN) - count = DS1343_NVRAM_LEN - off; - address = DS1343_NVRAM + off; ret = regmap_bulk_write(priv->map, address, buf, count); @@ -187,12 +181,6 @@ static ssize_t ds1343_nvram_read(struct file *filp, struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct ds1343_priv *priv = dev_get_drvdata(dev); - if (unlikely(!count)) - return count; - - if ((count + off) > DS1343_NVRAM_LEN) - count = DS1343_NVRAM_LEN - off; - address = DS1343_NVRAM + off; ret = regmap_bulk_read(priv->map, address, buf, count); -- GitLab From 8ccba14233000f48639aad4cab55ed7b61260db5 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 5 Aug 2015 21:12:58 +0300 Subject: [PATCH 6503/7006] rtc: ds1511: clean up ds1511_nvram_read()/ds1511_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c The change enables burst mode of access to SRAM for any read()/write() operations, it is worth to mention that this may influence on userspace, for instance prior to the change read(fd, buf, 1); read(fd, buf + 1, 1); and read(fd, buf, 2); sequences of syscalls over DS1511's sysfs "nvram" fd led to different DS1511 state changes and/or buf content, if some userspace applications are written specifically for DS1511 and exploit this strange "feature", they may be impacted. Also the change corrects NVRAM size accessible to userspace from 255 bytes to 256 bytes. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1511.c | 42 +++++----------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 7415c2b4d6e8e..da3d04ce83bd8 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -64,7 +64,7 @@ enum ds1511reg { #define DS1511_KIE 0x04 #define DS1511_WDE 0x02 #define DS1511_WDS 0x01 -#define DS1511_RAM_MAX 0xff +#define DS1511_RAM_MAX 0x100 #define RTC_CMD DS1511_CONTROL_B #define RTC_CMD1 DS1511_CONTROL_A @@ -159,7 +159,7 @@ ds1511_wdog_set(unsigned long deciseconds) /* * set wdog enable and wdog 'steering' bit to issue a reset */ - rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD); + rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD); } void @@ -407,26 +407,10 @@ ds1511_nvram_read(struct file *filp, struct kobject *kobj, { ssize_t count; - /* - * if count is more than one, turn on "burst" mode - * turn it off when you're done - */ - if (size > 1) - rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); - - if (pos > DS1511_RAM_MAX) - pos = DS1511_RAM_MAX; - - if (size + pos > DS1511_RAM_MAX + 1) - size = DS1511_RAM_MAX - pos + 1; - rtc_write(pos, DS1511_RAMADDR_LSB); - for (count = 0; size > 0; count++, size--) + for (count = 0; count < size; count++) *buf++ = rtc_read(DS1511_RAMDATA); - if (count > 1) - rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); - return count; } @@ -437,26 +421,10 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj, { ssize_t count; - /* - * if count is more than one, turn on "burst" mode - * turn it off when you're done - */ - if (size > 1) - rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); - - if (pos > DS1511_RAM_MAX) - pos = DS1511_RAM_MAX; - - if (size + pos > DS1511_RAM_MAX + 1) - size = DS1511_RAM_MAX - pos + 1; - rtc_write(pos, DS1511_RAMADDR_LSB); - for (count = 0; size > 0; count++, size--) + for (count = 0; count < size; count++) rtc_write(*buf++, DS1511_RAMDATA); - if (count > 1) - rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); - return count; } @@ -490,7 +458,7 @@ static int ds1511_rtc_probe(struct platform_device *pdev) /* * turn on the clock and the crystal, etc. */ - rtc_write(0, RTC_CMD); + rtc_write(DS1511_BME, RTC_CMD); rtc_write(0, RTC_CMD1); /* * clear the wdog counter -- GitLab From a9118d77b3be366c4843446d671a52ccfddcc15c Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:31 +0300 Subject: [PATCH 6504/7006] rtc: ds1553: clean up ds1553_nvram_read()/ds1553_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1553.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index a24e091bcb41d..38422ab4ec5a1 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -245,7 +245,7 @@ static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) *buf++ = readb(ioaddr + pos++); return count; } @@ -260,7 +260,7 @@ static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) writeb(*buf++, ioaddr + pos++); return count; } -- GitLab From c472d7ded2dfbe7da29531a9c9e6b951e5658605 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:32 +0300 Subject: [PATCH 6505/7006] rtc: ds1742: clean up ds1742_nvram_read()/ds1742_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1742.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 0f8d8ace15156..c5168b3bcf1a6 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -134,7 +134,7 @@ static ssize_t ds1742_nvram_read(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr_nvram; ssize_t count; - for (count = 0; size > 0 && pos < pdata->size_nvram; count++, size--) + for (count = 0; count < size; count++) *buf++ = readb(ioaddr + pos++); return count; } @@ -149,7 +149,7 @@ static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr_nvram; ssize_t count; - for (count = 0; size > 0 && pos < pdata->size_nvram; count++, size--) + for (count = 0; count < size; count++) writeb(*buf++, ioaddr + pos++); return count; } -- GitLab From 99be3e371b2ac03b936044139be10cf0c7b9cc58 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 5 Aug 2015 21:13:02 +0300 Subject: [PATCH 6506/7006] rtc: m48t59: clean up m48t59_nvram_read()/m48t59_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Spinlock acquisition/release is moved out of the loop body to get atomic states of NVRAM reading and writing operations. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t59.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 90abb5bd589c8..d99a705bec07a 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -345,11 +345,12 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < pdata->offset; cnt++, size--) { - spin_lock_irqsave(&m48t59->lock, flags); + spin_lock_irqsave(&m48t59->lock, flags); + + for (; cnt < size; cnt++) *buf++ = M48T59_READ(cnt); - spin_unlock_irqrestore(&m48t59->lock, flags); - } + + spin_unlock_irqrestore(&m48t59->lock, flags); return cnt; } @@ -365,11 +366,12 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < pdata->offset; cnt++, size--) { - spin_lock_irqsave(&m48t59->lock, flags); + spin_lock_irqsave(&m48t59->lock, flags); + + for (; cnt < size; cnt++) M48T59_WRITE(*buf++, cnt); - spin_unlock_irqrestore(&m48t59->lock, flags); - } + + spin_unlock_irqrestore(&m48t59->lock, flags); return cnt; } -- GitLab From d1cf4bdee8e574c0d2b7ce9fa8d9cd89c0ac761a Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:34 +0300 Subject: [PATCH 6507/7006] rtc: rp5c01: clean up rp5c01_nvram_read()/rp5c01_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rp5c01.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index b548551f385cc..026035373ae65 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -170,7 +170,7 @@ static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj, spin_lock_irq(&priv->lock); - for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { + for (count = 0; count < size; count++) { u8 data; rp5c01_write(priv, @@ -200,7 +200,7 @@ static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj, spin_lock_irq(&priv->lock); - for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { + for (count = 0; count < size; count++) { u8 data = *buf++; rp5c01_write(priv, -- GitLab From ecc663c3d0dc181fd15e4d60753024d180fd7e8f Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:35 +0300 Subject: [PATCH 6508/7006] rtc: stk17ta8: clean up stk17ta8_nvram_read()/stk17ta8_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stk17ta8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 0e93b714ee414..ba6a83b5b5c9a 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -254,7 +254,7 @@ static ssize_t stk17ta8_nvram_read(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) *buf++ = readb(ioaddr + pos++); return count; } @@ -269,7 +269,7 @@ static ssize_t stk17ta8_nvram_write(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) writeb(*buf++, ioaddr + pos++); return count; } -- GitLab From 824625d3926f0caf4753426d2b24a8fc08a406c8 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:36 +0300 Subject: [PATCH 6509/7006] rtc: tx4939: clean up tx4939_rtc_nvram_read()/tx4939_rtc_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-tx4939.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index cb7f94ede5165..560d9a5e02253 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -199,8 +199,7 @@ static ssize_t tx4939_rtc_nvram_read(struct file *filp, struct kobject *kobj, ssize_t count; spin_lock_irq(&pdata->lock); - for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; - count++, size--) { + for (count = 0; count < size; count++) { __raw_writel(pos++, &rtcreg->adr); *buf++ = __raw_readl(&rtcreg->dat); } @@ -218,8 +217,7 @@ static ssize_t tx4939_rtc_nvram_write(struct file *filp, struct kobject *kobj, ssize_t count; spin_lock_irq(&pdata->lock); - for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; - count++, size--) { + for (count = 0; count < size; count++) { __raw_writel(pos++, &rtcreg->adr); __raw_writel(*buf++, &rtcreg->dat); } -- GitLab From 15d3bdc23eb54c50b2a5f143325fe83c3ab0dd27 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 15:50:23 +0200 Subject: [PATCH 6510/7006] rtc: rx8025: remove useless headers and reorder them Remove the useless includes and order the remaining ones alphabetically. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 6fe87702fcff3..a943e1c082637 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -18,13 +18,10 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ -#include -#include -#include -#include #include #include -#include +#include +#include #include /* Register definitions */ -- GitLab From b6a57c955c362cb9d6ace991cdd77376849abb44 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 15:59:43 +0200 Subject: [PATCH 6511/7006] rtc: rx8025: Convert to threaded IRQ The driver currently emulates the concept of threaded IRQ using a workqueue, switch to threaded IRQ instead. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index a943e1c082637..d8737713135d8 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -71,9 +71,7 @@ MODULE_DEVICE_TABLE(i2c, rx8025_id); struct rx8025_data { struct i2c_client *client; struct rtc_device *rtc; - struct work_struct work; u8 ctrl1; - unsigned exiting:1; }; static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) @@ -128,26 +126,12 @@ static int rx8025_write_regs(struct i2c_client *client, return ret; } -static irqreturn_t rx8025_irq(int irq, void *dev_id) +static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); - - disable_irq_nosync(irq); - schedule_work(&rx8025->work); - return IRQ_HANDLED; -} - -static void rx8025_work(struct work_struct *work) -{ - struct rx8025_data *rx8025 = container_of(work, struct rx8025_data, - work); - struct i2c_client *client = rx8025->client; - struct mutex *lock = &rx8025->rtc->ops_lock; u8 status; - mutex_lock(lock); - if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) goto out; @@ -175,10 +159,7 @@ static void rx8025_work(struct work_struct *work) status | RX8025_BIT_CTRL2_XST); out: - if (!rx8025->exiting) - enable_irq(client->irq); - - mutex_unlock(lock); + return IRQ_HANDLED; } static int rx8025_get_time(struct device *dev, struct rtc_time *dt) @@ -550,7 +531,6 @@ static int rx8025_probe(struct i2c_client *client, rx8025->client = client; i2c_set_clientdata(client, rx8025); - INIT_WORK(&rx8025->work, rx8025_work); err = rx8025_init_client(client, &need_reset); if (err) @@ -574,7 +554,7 @@ static int rx8025_probe(struct i2c_client *client, if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); - err = request_irq(client->irq, rx8025_irq, + err = request_threaded_irq(client->irq, NULL, rx8025_handle_irq, 0, "rx8025", client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); @@ -602,17 +582,8 @@ errout: static int rx8025_remove(struct i2c_client *client) { - struct rx8025_data *rx8025 = i2c_get_clientdata(client); - struct mutex *lock = &rx8025->rtc->ops_lock; - - if (client->irq > 0) { - mutex_lock(lock); - rx8025->exiting = 1; - mutex_unlock(lock); - + if (client->irq > 0) free_irq(client->irq, client); - cancel_work_sync(&rx8025->work); - } rx8025_sysfs_unregister(&client->dev); return 0; -- GitLab From f0b63a1d5a4a4d9d60fe728ede0fa78ec5aab8be Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 16:07:30 +0200 Subject: [PATCH 6512/7006] rtc: rx8025: switch to managed irq allocation Use devm_request_threaded_irq() so it is not necessary to call free_irq() explicitly. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index d8737713135d8..be91e922a139d 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -554,8 +554,9 @@ static int rx8025_probe(struct i2c_client *client, if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); - err = request_threaded_irq(client->irq, NULL, rx8025_handle_irq, - 0, "rx8025", client); + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + rx8025_handle_irq, 0, "rx8025", + client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); goto errout; @@ -567,14 +568,10 @@ static int rx8025_probe(struct i2c_client *client, err = rx8025_sysfs_register(&client->dev); if (err) - goto errout_irq; + goto errout; return 0; -errout_irq: - if (client->irq > 0) - free_irq(client->irq, client); - errout: dev_err(&adapter->dev, "probing for rx8025 failed\n"); return err; @@ -582,9 +579,6 @@ errout: static int rx8025_remove(struct i2c_client *client) { - if (client->irq > 0) - free_irq(client->irq, client); - rx8025_sysfs_unregister(&client->dev); return 0; } -- GitLab From dbcce7cf1eb95c704faa3fff1acc974010c8e5a4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 16:12:10 +0200 Subject: [PATCH 6513/7006] rtc: rx8025: remove useless probe error message It is useless to print a message when probe fails as the user is already aware that it failed. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index be91e922a139d..612b6876cbd5c 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -513,20 +513,18 @@ static int rx8025_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8025_data *rx8025; - int err, need_reset = 0; + int err = 0, need_reset = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { dev_err(&adapter->dev, "doesn't support required functionality\n"); - err = -EIO; - goto errout; + return -EIO; } rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL); if (!rx8025) { - err = -ENOMEM; - goto errout; + return -ENOMEM; } rx8025->client = client; @@ -534,7 +532,7 @@ static int rx8025_probe(struct i2c_client *client, err = rx8025_init_client(client, &need_reset); if (err) - goto errout; + return err; if (need_reset) { struct rtc_time tm; @@ -547,9 +545,8 @@ static int rx8025_probe(struct i2c_client *client, rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, &rx8025_rtc_ops, THIS_MODULE); if (IS_ERR(rx8025->rtc)) { - err = PTR_ERR(rx8025->rtc); dev_err(&client->dev, "unable to register the class device\n"); - goto errout; + return PTR_ERR(rx8025->rtc); } if (client->irq > 0) { @@ -559,7 +556,7 @@ static int rx8025_probe(struct i2c_client *client, client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); - goto errout; + return err; } } @@ -567,13 +564,6 @@ static int rx8025_probe(struct i2c_client *client, rx8025->rtc->max_user_freq = 1; err = rx8025_sysfs_register(&client->dev); - if (err) - goto errout; - - return 0; - -errout: - dev_err(&adapter->dev, "probing for rx8025 failed\n"); return err; } -- GitLab From 2ddd18693cb93126077bd072884dffca423c1e27 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 25 Jul 2015 11:50:22 +0200 Subject: [PATCH 6514/7006] rtc: rx8025: use BIT() Use BIT() instead of hand coding. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 612b6876cbd5c..52683eda1da28 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -19,6 +19,7 @@ * version 2 as published by the Free Software Foundation. */ #include +#include #include #include #include @@ -45,17 +46,17 @@ #define RX8025_BIT_CTRL1_CT (7 << 0) /* 1 Hz periodic level irq */ #define RX8025_BIT_CTRL1_CT_1HZ 4 -#define RX8025_BIT_CTRL1_TEST (1 << 3) -#define RX8025_BIT_CTRL1_1224 (1 << 5) -#define RX8025_BIT_CTRL1_DALE (1 << 6) -#define RX8025_BIT_CTRL1_WALE (1 << 7) - -#define RX8025_BIT_CTRL2_DAFG (1 << 0) -#define RX8025_BIT_CTRL2_WAFG (1 << 1) -#define RX8025_BIT_CTRL2_CTFG (1 << 2) -#define RX8025_BIT_CTRL2_PON (1 << 4) -#define RX8025_BIT_CTRL2_XST (1 << 5) -#define RX8025_BIT_CTRL2_VDET (1 << 6) +#define RX8025_BIT_CTRL1_TEST BIT(3) +#define RX8025_BIT_CTRL1_1224 BIT(5) +#define RX8025_BIT_CTRL1_DALE BIT(6) +#define RX8025_BIT_CTRL1_WALE BIT(7) + +#define RX8025_BIT_CTRL2_DAFG BIT(0) +#define RX8025_BIT_CTRL2_WAFG BIT(1) +#define RX8025_BIT_CTRL2_CTFG BIT(2) +#define RX8025_BIT_CTRL2_PON BIT(4) +#define RX8025_BIT_CTRL2_XST BIT(5) +#define RX8025_BIT_CTRL2_VDET BIT(6) /* Clock precision adjustment */ #define RX8025_ADJ_RESOLUTION 3050 /* in ppb */ -- GitLab From 32672c55951b2633bb93ec6f12734cf17e9d3a14 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 25 Jul 2015 12:07:37 +0200 Subject: [PATCH 6515/7006] rtc: rx8025: only handle dates between 2000 and 2099 The hardware is only capable of handling dates between 2000 and 2099, enforce that. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 52683eda1da28..3612362b65ac4 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -188,10 +188,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f); dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; - dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]); - - if (dt->tm_year < 70) - dt->tm_year += 100; + dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100; dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, dt->tm_sec, dt->tm_min, dt->tm_hour, @@ -205,11 +202,8 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; - /* - * BUG: The HW assumes every year that is a multiple of 4 to be a leap - * year. Next time this is wrong is 2100, which will not be a leap - * year. - */ + if ((dt->tm_year < 100) || (dt->tm_year > 199)) + return -EINVAL; /* * Here the read-only bits are written as "0". I'm not sure if that @@ -226,7 +220,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday); date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday); date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); - date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year % 100); + date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100); dev_dbg(dev, "%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", -- GitLab From 2e10e74df72ff0f8ea65eb1ee6e39ed8278a91bf Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 25 Jul 2015 15:54:59 +0200 Subject: [PATCH 6516/7006] rtc: rx8025: fix transfer mode The datasheet specifies that transfer mode must be 0 for write and either 0x4 (simplified read) or 0 (standard read). 0x8 is not specified, use standard mode. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 3612362b65ac4..771558602409e 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -77,7 +77,7 @@ struct rx8025_data { static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) { - int ret = i2c_smbus_read_byte_data(client, (number << 4) | 0x08); + int ret = i2c_smbus_read_byte_data(client, number << 4); if (ret < 0) { dev_err(&client->dev, "Unable to read register #%d\n", number); @@ -91,7 +91,7 @@ static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) static int rx8025_read_regs(struct i2c_client *client, int number, u8 length, u8 *values) { - int ret = i2c_smbus_read_i2c_block_data(client, (number << 4) | 0x08, + int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length, values); if (ret != length) { @@ -117,7 +117,7 @@ static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) static int rx8025_write_regs(struct i2c_client *client, int number, u8 length, u8 *values) { - int ret = i2c_smbus_write_i2c_block_data(client, (number << 4) | 0x08, + int ret = i2c_smbus_write_i2c_block_data(client, number << 4, length, values); if (ret) -- GitLab From 6f0a8cfebb898b88fb0d934d7a44a6d4c98d5285 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 26 Jul 2015 10:13:31 +0200 Subject: [PATCH 6517/7006] rtc: rx8025: don't reset the time Stop setting the time to epoch when it is invalid. The proper way to handle that is to return an error when it is invalid instead of returning an incorrect value. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 771558602409e..d158a640299e8 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -166,9 +166,23 @@ out: static int rx8025_get_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); - u8 date[7]; + u8 date[7], ctrl; int err; + err = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2, &ctrl); + if (err) + return err; + + if (ctrl & RX8025_BIT_CTRL2_PON) { + dev_warn(dev, "power-on reset detected, date is invalid\n"); + return -EINVAL; + } + + if (!(ctrl & RX8025_BIT_CTRL2_XST)) { + dev_warn(dev, "crystal stopped, date is invalid\n"); + return -EINVAL; + } + err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (err) return err; @@ -230,7 +244,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); } -static int rx8025_init_client(struct i2c_client *client, int *need_reset) +static int rx8025_init_client(struct i2c_client *client) { struct rx8025_data *rx8025 = i2c_get_clientdata(client); u8 ctrl[2], ctrl2; @@ -247,19 +261,19 @@ static int rx8025_init_client(struct i2c_client *client, int *need_reset) if (ctrl[1] & RX8025_BIT_CTRL2_PON) { dev_warn(&client->dev, "power-on reset was detected, " "you may have to readjust the clock\n"); - *need_reset = 1; + need_clear = 1; } if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { dev_warn(&client->dev, "a power voltage drop was detected, " "you may have to readjust the clock\n"); - *need_reset = 1; + need_clear = 1; } if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { dev_warn(&client->dev, "Oscillation stop was detected," "you may have to readjust the clock\n"); - *need_reset = 1; + need_clear = 1; } if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { @@ -270,7 +284,7 @@ static int rx8025_init_client(struct i2c_client *client, int *need_reset) if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) need_clear = 1; - if (*need_reset || need_clear) { + if (need_clear) { ctrl2 = ctrl[0]; ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | @@ -508,7 +522,7 @@ static int rx8025_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8025_data *rx8025; - int err = 0, need_reset = 0; + int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { @@ -525,18 +539,10 @@ static int rx8025_probe(struct i2c_client *client, rx8025->client = client; i2c_set_clientdata(client, rx8025); - err = rx8025_init_client(client, &need_reset); + err = rx8025_init_client(client); if (err) return err; - if (need_reset) { - struct rtc_time tm; - dev_info(&client->dev, - "bad conditions detected, resetting date\n"); - rtc_time_to_tm(0, &tm); /* 1970/1/1 */ - rx8025_set_time(&client->dev, &tm); - } - rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, &rx8025_rtc_ops, THIS_MODULE); if (IS_ERR(rx8025->rtc)) { -- GitLab From fd9061fb497926c0e62bf1c7ff727801499fd2ea Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 00:40:25 +0200 Subject: [PATCH 6518/7006] rtc: rx8025: cleanup accessors Remove useless error messages, at that point, the user already knows something went wrong but will not be able to do anything about it anyway. It is also highly unlikely that some registers are readable/writable but not some other ones. Also, transform rx8025_read_reg to be more resemblant to i2c_smbus_read_byte_data() Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 85 +++++++++++++++------------------------- 1 file changed, 31 insertions(+), 54 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index d158a640299e8..bf96f40fd200f 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -75,65 +75,43 @@ struct rx8025_data { u8 ctrl1; }; -static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) +static s32 rx8025_read_reg(const struct i2c_client *client, u8 number) { - int ret = i2c_smbus_read_byte_data(client, number << 4); - - if (ret < 0) { - dev_err(&client->dev, "Unable to read register #%d\n", number); - return ret; - } - - *value = ret; - return 0; + return i2c_smbus_read_byte_data(client, number << 4); } -static int rx8025_read_regs(struct i2c_client *client, - int number, u8 length, u8 *values) +static int rx8025_read_regs(const struct i2c_client *client, + u8 number, u8 length, u8 *values) { - int ret = i2c_smbus_read_i2c_block_data(client, number << 4, - length, values); - - if (ret != length) { - dev_err(&client->dev, "Unable to read registers #%d..#%d\n", - number, number + length - 1); + int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length, + values); + if (ret != length) return ret < 0 ? ret : -EIO; - } return 0; } -static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) +static s32 rx8025_write_reg(const struct i2c_client *client, u8 number, + u8 value) { - int ret = i2c_smbus_write_byte_data(client, number << 4, value); - - if (ret) - dev_err(&client->dev, "Unable to write register #%d\n", - number); - - return ret; + return i2c_smbus_write_byte_data(client, number << 4, value); } -static int rx8025_write_regs(struct i2c_client *client, - int number, u8 length, u8 *values) +static s32 rx8025_write_regs(const struct i2c_client *client, + u8 number, u8 length, const u8 *values) { - int ret = i2c_smbus_write_i2c_block_data(client, number << 4, - length, values); - - if (ret) - dev_err(&client->dev, "Unable to write registers #%d..#%d\n", - number, number + length - 1); - - return ret; + return i2c_smbus_write_i2c_block_data(client, number << 4, + length, values); } static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); - u8 status; + int status; - if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) + status = rx8025_read_reg(client, RX8025_REG_CTRL2); + if (status < 0) goto out; if (!(status & RX8025_BIT_CTRL2_XST)) @@ -166,12 +144,12 @@ out: static int rx8025_get_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); - u8 date[7], ctrl; - int err; + u8 date[7]; + int ctrl, err; - err = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2, &ctrl); - if (err) - return err; + ctrl = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); + if (ctrl < 0) + return ctrl; if (ctrl & RX8025_BIT_CTRL2_PON) { dev_warn(dev, "power-on reset detected, date is invalid\n"); @@ -302,8 +280,8 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); struct i2c_client *client = rx8025->client; - u8 ctrl2, ald[2]; - int err; + u8 ald[2]; + int ctrl2, err; if (client->irq <= 0) return -EINVAL; @@ -312,9 +290,9 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) if (err) return err; - err = rx8025_read_reg(client, RX8025_REG_CTRL2, &ctrl2); - if (err) - return err; + ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); + if (ctrl2 < 0) + return ctrl2; dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n", __func__, ald[0], ald[1], ctrl2); @@ -435,12 +413,11 @@ static struct rtc_class_ops rx8025_rtc_ops = { static int rx8025_get_clock_adjust(struct device *dev, int *adj) { struct i2c_client *client = to_i2c_client(dev); - u8 digoff; - int err; + int digoff; - err = rx8025_read_reg(client, RX8025_REG_DIGOFF, &digoff); - if (err) - return err; + digoff = rx8025_read_reg(client, RX8025_REG_DIGOFF); + if (digoff < 0) + return digoff; *adj = digoff >= 64 ? digoff - 128 : digoff; if (*adj > 0) -- GitLab From 8a06513df55ef10baf80f55d13786eb29efa4fa6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 00:45:37 +0200 Subject: [PATCH 6519/7006] rtc: rx8025: continue without alarm when irq request fails Instead of bailing out, disable alarms and continue when devm_request_threaded_irq() fails. This allows to still provide some functionality. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index bf96f40fd200f..ab5fb4fe2a835 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -533,8 +533,8 @@ static int rx8025_probe(struct i2c_client *client, rx8025_handle_irq, 0, "rx8025", client); if (err) { - dev_err(&client->dev, "unable to request IRQ\n"); - return err; + dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); + client->irq = 0; } } -- GitLab From a27c7bf657cb4ab893328359b66a584251be6cac Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 10:46:22 +0200 Subject: [PATCH 6520/7006] rtc: rx8025: fix rx8025_init_client() rx8025_init_client is modifying ctrl[0] and writing it to RX8025_REG_CTRL2 but ctrl[0] is actually RX8025_REG_CTRL1. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index ab5fb4fe2a835..22ce08d6e8077 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -263,7 +263,7 @@ static int rx8025_init_client(struct i2c_client *client) need_clear = 1; if (need_clear) { - ctrl2 = ctrl[0]; + ctrl2 = ctrl[1]; ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | RX8025_BIT_CTRL2_DAFG); -- GitLab From 8c4a4467cda299491eff64640c891a0b2926cb76 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 10:48:20 +0200 Subject: [PATCH 6521/7006] rtc: rx8025: reset validity when setting time Wait for the user to set the time to reset the validity bits. Until then, the time may be invalid. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 22ce08d6e8077..340133a5d9077 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -104,6 +104,19 @@ static s32 rx8025_write_regs(const struct i2c_client *client, length, values); } +static int rx8025_reset_validity(struct i2c_client *client) +{ + int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); + + if (ctrl2 < 0) + return ctrl2; + + ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET); + + return rx8025_write_reg(client, RX8025_REG_CTRL2, + ctrl2 | RX8025_BIT_CTRL2_XST); +} + static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; @@ -133,10 +146,6 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); } - /* acknowledge IRQ */ - rx8025_write_reg(client, RX8025_REG_CTRL2, - status | RX8025_BIT_CTRL2_XST); - out: return IRQ_HANDLED; } @@ -193,6 +202,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; + int ret; if ((dt->tm_year < 100) || (dt->tm_year > 199)) return -EINVAL; @@ -219,7 +229,11 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) __func__, date[0], date[1], date[2], date[3], date[4], date[5], date[6]); - return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); + ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); + if (ret < 0) + return ret; + + return rx8025_reset_validity(rx8025->client); } static int rx8025_init_client(struct i2c_client *client) @@ -239,19 +253,16 @@ static int rx8025_init_client(struct i2c_client *client) if (ctrl[1] & RX8025_BIT_CTRL2_PON) { dev_warn(&client->dev, "power-on reset was detected, " "you may have to readjust the clock\n"); - need_clear = 1; } if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { dev_warn(&client->dev, "a power voltage drop was detected, " "you may have to readjust the clock\n"); - need_clear = 1; } if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { dev_warn(&client->dev, "Oscillation stop was detected," "you may have to readjust the clock\n"); - need_clear = 1; } if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { @@ -264,10 +275,8 @@ static int rx8025_init_client(struct i2c_client *client) if (need_clear) { ctrl2 = ctrl[1]; - ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | - RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | + ctrl2 &= ~(RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | RX8025_BIT_CTRL2_DAFG); - ctrl2 |= RX8025_BIT_CTRL2_XST; err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2); } -- GitLab From 4b33d36b670e7166e8a082e050bfb241ba65271f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 10:56:50 +0200 Subject: [PATCH 6522/7006] rtc: rx8025: remove useless initialization irq_freq is already initialized to 1 in rtc_device_register() Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 340133a5d9077..f9b86b92943ff 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -547,7 +547,6 @@ static int rx8025_probe(struct i2c_client *client, } } - rx8025->rtc->irq_freq = 1; rx8025->rtc->max_user_freq = 1; err = rx8025_sysfs_register(&client->dev); -- GitLab From 5c66e1e0b79bd63dcdfbc03b80823522643a1f14 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 11:24:33 +0200 Subject: [PATCH 6523/7006] rtc: rx8025: fix RX8025_BIT_CTRL2_CTFG initialization RX8025_BIT_CTRL2_CTFG was set to 0 only when it was already 0. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index f9b86b92943ff..f3f1de26c2283 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -270,7 +270,7 @@ static int rx8025_init_client(struct i2c_client *client) need_clear = 1; } - if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) + if (ctrl[1] & RX8025_BIT_CTRL2_CTFG) need_clear = 1; if (need_clear) { -- GitLab From efbbb4fd6b6fe0d3d2cfb3c5bbcdf00f1995cb60 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 11:33:59 +0200 Subject: [PATCH 6524/7006] rtc: rx8025: check time validity when necessary Check time validity when reading time as this is when we need to know. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 58 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index f3f1de26c2283..24c3d69ce1b97 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -104,6 +104,31 @@ static s32 rx8025_write_regs(const struct i2c_client *client, length, values); } +static int rx8025_check_validity(struct device *dev) +{ + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + int ctrl2; + + ctrl2 = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); + if (ctrl2 < 0) + return ctrl2; + + if (ctrl2 & RX8025_BIT_CTRL2_VDET) + dev_warn(dev, "power voltage drop detected\n"); + + if (ctrl2 & RX8025_BIT_CTRL2_PON) { + dev_warn(dev, "power-on reset detected, date is invalid\n"); + return -EINVAL; + } + + if (!(ctrl2 & RX8025_BIT_CTRL2_XST)) { + dev_warn(dev, "crystal stopped, date is invalid\n"); + return -EINVAL; + } + + return 0; +} + static int rx8025_reset_validity(struct i2c_client *client) { int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); @@ -154,21 +179,11 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; - int ctrl, err; - - ctrl = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); - if (ctrl < 0) - return ctrl; - - if (ctrl & RX8025_BIT_CTRL2_PON) { - dev_warn(dev, "power-on reset detected, date is invalid\n"); - return -EINVAL; - } + int err; - if (!(ctrl & RX8025_BIT_CTRL2_XST)) { - dev_warn(dev, "crystal stopped, date is invalid\n"); - return -EINVAL; - } + err = rx8025_check_validity(dev); + if (err) + return err; err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (err) @@ -250,21 +265,6 @@ static int rx8025_init_client(struct i2c_client *client) /* Keep test bit zero ! */ rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST; - if (ctrl[1] & RX8025_BIT_CTRL2_PON) { - dev_warn(&client->dev, "power-on reset was detected, " - "you may have to readjust the clock\n"); - } - - if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { - dev_warn(&client->dev, "a power voltage drop was detected, " - "you may have to readjust the clock\n"); - } - - if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { - dev_warn(&client->dev, "Oscillation stop was detected," - "you may have to readjust the clock\n"); - } - if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { dev_warn(&client->dev, "Alarm was detected\n"); need_clear = 1; -- GitLab From 0c6e718389305cbc4cd9b8e3fd4b4173bd1127e6 Mon Sep 17 00:00:00 2001 From: Nadav Haklai Date: Thu, 6 Aug 2015 17:18:48 +0200 Subject: [PATCH 6525/7006] rtc: armada38x: Align RTC set time procedure with the official errata According to the Armada38x functional errata FE-3124064, writing to the RTC TIME register may fail. As a workaround, after writing to RTC TIME register, issue a dummy write of 0x0 twice to the RTC Status register. This is the updated implementation of the Errata that eliminates the need of the long 100ms delay during the RTC set time procedure. [gregory.clement@free-electrons.com]: removed the mutex and use the spinlock again Signed-off-by: Nadav Haklai Reviewed-by: Neta Zur Hershkovits Signed-off-by: Gregory CLEMENT Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 2b08cac62f07a..06c6bd5eab411 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -40,13 +40,6 @@ struct armada38x_rtc { void __iomem *regs; void __iomem *regs_soc; spinlock_t lock; - /* - * While setting the time, the RTC TIME register should not be - * accessed. Setting the RTC time involves sleeping during - * 100ms, so a mutex instead of a spinlock is used to protect - * it - */ - struct mutex mutex_time; int irq; }; @@ -64,9 +57,9 @@ static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset) static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); - unsigned long time, time_check; + unsigned long time, time_check, flags; - mutex_lock(&rtc->mutex_time); + spin_lock_irqsave(&rtc->lock, flags); time = readl(rtc->regs + RTC_TIME); /* * WA for failing time set attempts. As stated in HW ERRATA if @@ -77,7 +70,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) if ((time_check - time) > 1) time_check = readl(rtc->regs + RTC_TIME); - mutex_unlock(&rtc->mutex_time); + spin_unlock_irqrestore(&rtc->lock, flags); rtc_time_to_tm(time_check, tm); @@ -88,23 +81,23 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); int ret = 0; - unsigned long time; + unsigned long time, flags; ret = rtc_tm_to_time(tm, &time); if (ret) goto out; /* - * Setting the RTC time not always succeeds. According to the - * errata we need to first write on the status register and - * then wait for 100ms before writing to the time register to be - * sure that the data will be taken into account. + * According to errata FE-3124064, Write to RTC TIME register + * may fail. As a workaround, after writing to RTC TIME + * register, issue a dummy write of 0x0 twice to RTC Status + * register. */ - mutex_lock(&rtc->mutex_time); - rtc_delayed_write(0, rtc, RTC_STATUS); - msleep(100); + spin_lock_irqsave(&rtc->lock, flags); rtc_delayed_write(time, rtc, RTC_TIME); - mutex_unlock(&rtc->mutex_time); + rtc_delayed_write(0, rtc, RTC_STATUS); + rtc_delayed_write(0, rtc, RTC_STATUS); + spin_unlock_irqrestore(&rtc->lock, flags); out: return ret; @@ -229,7 +222,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&rtc->lock); - mutex_init(&rtc->mutex_time); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); rtc->regs = devm_ioremap_resource(&pdev->dev, res); -- GitLab From 1955f213a68323f7348fc06461017c7675efe6c1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:33:39 +0200 Subject: [PATCH 6526/7006] rtc: at91sam9: include linux/of.h This driver is using device tree but is not including of.h Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91sam9.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index f9e85ace5e71d..16492e2baf5e1 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include -- GitLab From 80e274e96e5bc4ddf9ee4b31ab6f4a2a9fa08040 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:33:40 +0200 Subject: [PATCH 6527/7006] rtc: at91sam9: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91sam9.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 16492e2baf5e1..7206e2fa43837 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include -- GitLab From 1fb1c35f56bb6ab4a65920c648154b0f78f634a5 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 12 Aug 2015 19:21:46 +0900 Subject: [PATCH 6528/7006] rtc: s3c: fix disabled clocks for alarm The clock enable/disable codes for alarm have been removed from commit 24e1455493da ("drivers/rtc/rtc-s3c.c: delete duplicate clock control") and the clocks are disabled even if alarm is set, so alarm interrupt can't happen. The s3c_rtc_setaie function can be called several times with 'enabled' argument having same value, so it needs to check whether clocks are enabled or not. Signed-off-by: Joonyoung Shim Cc: # v4.1 Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index a0f8323621990..2e709e239dbcc 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -39,6 +39,7 @@ struct s3c_rtc { void __iomem *base; struct clk *rtc_clk; struct clk *rtc_src_clk; + bool clk_disabled; struct s3c_rtc_data *data; @@ -71,9 +72,12 @@ static void s3c_rtc_enable_clk(struct s3c_rtc *info) unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + if (info->clk_disabled) { + clk_enable(info->rtc_clk); + if (info->data->needs_src_clk) + clk_enable(info->rtc_src_clk); + info->clk_disabled = false; + } spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); } @@ -82,9 +86,12 @@ static void s3c_rtc_disable_clk(struct s3c_rtc *info) unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); + if (!info->clk_disabled) { + if (info->data->needs_src_clk) + clk_disable(info->rtc_src_clk); + clk_disable(info->rtc_clk); + info->clk_disabled = true; + } spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); } @@ -128,6 +135,11 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) s3c_rtc_disable_clk(info); + if (enabled) + s3c_rtc_enable_clk(info); + else + s3c_rtc_disable_clk(info); + return 0; } -- GitLab From 7f23a93661eb5caa373f75a145cec14331a8caaa Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 11 Aug 2015 20:28:19 +0900 Subject: [PATCH 6529/7006] rtc: s3c: add missing clk control It's missed to call clk_unprepare() about info->rtc_src_clk in s3c_rtc_remove and to call clk_disable_unprepare about info->rtc_clk in error routine of s3c_rtc_probe. Signed-off-by: Joonyoung Shim Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 2e709e239dbcc..3ee961529b5b4 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -422,6 +422,8 @@ static int s3c_rtc_remove(struct platform_device *pdev) s3c_rtc_setaie(info->dev, 0); + if (info->data->needs_src_clk) + clk_unprepare(info->rtc_src_clk); clk_unprepare(info->rtc_clk); info->rtc_clk = NULL; @@ -494,6 +496,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) if (IS_ERR(info->rtc_src_clk)) { dev_err(&pdev->dev, "failed to find rtc source clock\n"); + clk_disable_unprepare(info->rtc_clk); return PTR_ERR(info->rtc_src_clk); } clk_prepare_enable(info->rtc_src_clk); -- GitLab From 27b15e31dbc5f4d7fc93e6acaa898cbfd1cf74ea Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 11 Aug 2015 20:28:20 +0900 Subject: [PATCH 6530/7006] rtc: s3c: remove unnecessary NULL assignment It's unnecessary the code that assigns info->rtc_clk to NULL in s3c_rtc_remove. Signed-off-by: Joonyoung Shim Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 3ee961529b5b4..7cc8f73a3fe8f 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -425,7 +425,6 @@ static int s3c_rtc_remove(struct platform_device *pdev) if (info->data->needs_src_clk) clk_unprepare(info->rtc_src_clk); clk_unprepare(info->rtc_clk); - info->rtc_clk = NULL; return 0; } -- GitLab From bb148bdeb0ab16fc0ae8009799471e4d7180073b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Aug 2015 18:02:39 +0200 Subject: [PATCH 6531/7006] ALSA: hda - Enable headphone jack detect on old Fujitsu laptops According to the bug report, FSC Amilo laptops with ALC880 can detect the headphone jack but currently the driver disables it. It's partly intentionally, as non-working jack detect was reported in the past. Let's enable now. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102501 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 764dd5bba9eea..9b43cb95c0478 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1135,7 +1135,7 @@ static const struct hda_fixup alc880_fixups[] = { /* override all pins as BIOS on old Amilo is broken */ .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121411f }, /* HP */ + { 0x14, 0x0121401f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x99030130 }, /* bass speaker */ { 0x17, 0x411111f0 }, /* N/A */ @@ -1155,7 +1155,7 @@ static const struct hda_fixup alc880_fixups[] = { /* almost compatible with FUJITSU, but no bass and SPDIF */ .type = HDA_FIXUP_PINS, .v.pins = (const struct hda_pintbl[]) { - { 0x14, 0x0121411f }, /* HP */ + { 0x14, 0x0121401f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x411111f0 }, /* N/A */ { 0x17, 0x411111f0 }, /* N/A */ -- GitLab From a161574e200ae63a5042120e0d8c36830e81bde3 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 13 Aug 2015 18:05:06 +0200 Subject: [PATCH 6532/7006] ALSA: hda - Use ALC880_FIXUP_FUJITSU for FSC Amilo M1437 It turned out that the machine has a bass speaker, so take a correct fixup entry. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=102501 Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9b43cb95c0478..f71ee28bf0f3f 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1364,7 +1364,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), - SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), + SND_PCI_QUIRK(0x1734, 0x107c, "FSC Amilo M1437", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x10b0, "FSC Amilo Pi1556", ALC880_FIXUP_FUJITSU), -- GitLab From 467e1436ba85f78b8c4610c4549eb255a8211c42 Mon Sep 17 00:00:00 2001 From: Niranjan Sivakumar Date: Sat, 5 Sep 2015 18:20:35 +0200 Subject: [PATCH 6533/7006] ALSA: hda - Fix white noise on Dell M3800 The M3800 is very minor workstation variant of the XPS 15 which has already been patched for this issue. I figured it's probably more important for this version of the laptop to be patched than the regular XPS as Dell sells is pre-configured with Ubuntu to be used as a Linux workstation. I have tested the patch on my the hardware on Linux 4.2.0. Signed-off-by: Niranjan Sivakumar Cc: # v4.1+ Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index f71ee28bf0f3f..a75b5611d1e40 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6384,6 +6384,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x05fe, "Dell XPS 15", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), + SND_PCI_QUIRK(0x1028, 0x060d, "Dell M3800", ALC668_FIXUP_DELL_XPS13), SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), -- GitLab From dc2280ebf45bfa4fbc4b1588a6642aa33454a9b8 Mon Sep 17 00:00:00 2001 From: Wang Dongsheng Date: Wed, 12 Aug 2015 17:14:13 +0800 Subject: [PATCH 6534/7006] rtc: ds3232: fix WARNING trace in resume function If ds3232 work on some platform that is not implementing irq_set_wake, ds3232 will get a WARNING trace in resume. So fix ds3232->suspended state to false when irq_set_irq_wake return error. WARNING: CPU: 0 PID: 729 at kernel/irq/manage.c:604 irq_set_irq_wake+0x4b/0x8c() Unbalanced IRQ 201 wake disable Modules linked in: CPU: 0 PID: 729 Comm: sh Not tainted 3.12.19-rt30+ #25 [<800107d9>] (unwind_backtrace+0x1/0x88) from [<8000e4ef>] (show_stack+0xb/0xc) [<8000e4ef>] (show_stack+0xb/0xc) from [<802b5fa9>] (dump_stack+0x4d/0x60) [<802b5fa9>] (dump_stack+0x4d/0x60) from [<800186dd>] (warn_slowpath_common+0x45/0x64) [<800186dd>] (warn_slowpath_common+0x45/0x64) from [<80018717>] (warn_slowpath_fmt+0x1b/0x24) [<80018717>] (warn_slowpath_fmt+0x1b/0x24) from [<8003a8d3>] (irq_set_irq_wake+0x4b/0x8c) [<8003a8d3>] (irq_set_irq_wake+0x4b/0x8c) from [<80204fcb>] (ds3232_resume+0x2d/0x36) [<80204fcb>] (ds3232_resume+0x2d/0x36) from [<801954c7>] (dpm_run_callback.isra.13+0xb/0x28) [<801954c7>] (dpm_run_callback.isra.13+0xb/0x28) from [<80195b1b>] (device_resume+0x7b/0xa2) [<80195b1b>] (device_resume+0x7b/0xa2) from [<80195f0f>] (dpm_resume+0xbb/0x19c) [<80195f0f>] (dpm_resume+0xbb/0x19c) from [<801960d9>] (dpm_resume_end+0x9/0x12) [<801960d9>] (dpm_resume_end+0x9/0x12) from [<80037e1d>] (suspend_devices_and_enter+0x17d/0x1d0) [<80037e1d>] (suspend_devices_and_enter+0x17d/0x1d0) from [<80037ee1>] (pm_suspend+0x71/0x128) [<80037ee1>] (pm_suspend+0x71/0x128) from [<80037449>] (state_store+0x6d/0x80) [<80037449>] (state_store+0x6d/0x80) from [<800af4d5>] (sysfs_write_file+0x9f/0xde) [<800af4d5>] (sysfs_write_file+0x9f/0xde) from [<8007a437>] (vfs_write+0x7b/0x104) [<8007a437>] (vfs_write+0x7b/0x104) from [<8007a7f7>] (SyS_write+0x27/0x48) [<8007a7f7>] (SyS_write+0x27/0x48) from [<8000c121>] (ret_fast_syscall+0x1/0x44) Signed-off-by: Wang Dongsheng Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index a8702dda0f262..4e99ace66f74d 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -463,7 +463,10 @@ static int ds3232_suspend(struct device *dev) if (device_can_wakeup(dev)) { ds3232->suspended = true; - irq_set_irq_wake(client->irq, 1); + if (irq_set_irq_wake(client->irq, 1)) { + dev_warn_once(dev, "Cannot set wakeup source\n"); + ds3232->suspended = false; + } } return 0; -- GitLab From 8c0961ba7c9356186a0606a391f08e2ecb491a57 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 12 May 2015 16:23:23 -0500 Subject: [PATCH 6535/7006] rtc: sa1100: prepare to share sa1100_rtc_ops Factor out the RTC initialization from the platform device specific parts in order to share the RTC device ops with other drivers. Specifically, it will be shared with rtc-pxa driver. Signed-off-by: Rob Herring Cc: Robert Jarzmik Cc: Russell King Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sa1100.c | 59 ++++++++++++++++++++-------------------- drivers/rtc/rtc-sa1100.h | 19 +++++++++++++ 2 files changed, 49 insertions(+), 29 deletions(-) create mode 100644 drivers/rtc/rtc-sa1100.h diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b6e1ca08c2c0e..abc19abd5f2d2 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -42,17 +42,12 @@ #include #endif +#include "rtc-sa1100.h" + #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 #define RTC_FREQ 1024 -struct sa1100_rtc { - spinlock_t lock; - int irq_1hz; - int irq_alarm; - struct rtc_device *rtc; - struct clk *clk; -}; static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { @@ -223,29 +218,18 @@ static const struct rtc_class_ops sa1100_rtc_ops = { .alarm_irq_enable = sa1100_rtc_alarm_irq_enable, }; -static int sa1100_rtc_probe(struct platform_device *pdev) +int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) { struct rtc_device *rtc; - struct sa1100_rtc *info; - int irq_1hz, irq_alarm, ret = 0; + int ret; - irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); - irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); - if (irq_1hz < 0 || irq_alarm < 0) - return -ENODEV; + spin_lock_init(&info->lock); - info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); - if (!info) - return -ENOMEM; info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed to find rtc clock source\n"); return PTR_ERR(info->clk); } - info->irq_1hz = irq_1hz; - info->irq_alarm = irq_alarm; - spin_lock_init(&info->lock); - platform_set_drvdata(pdev, info); ret = clk_prepare_enable(info->clk); if (ret) @@ -265,14 +249,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RCNR = 0; } - device_init_wakeup(&pdev->dev, 1); - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto err_dev; + clk_disable_unprepare(info->clk); + return PTR_ERR(rtc); } info->rtc = rtc; @@ -301,9 +282,29 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RTSR = RTSR_AL | RTSR_HZ; return 0; -err_dev: - clk_disable_unprepare(info->clk); - return ret; +} +EXPORT_SYMBOL_GPL(sa1100_rtc_init); + +static int sa1100_rtc_probe(struct platform_device *pdev) +{ + struct sa1100_rtc *info; + int irq_1hz, irq_alarm; + + irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); + irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); + if (irq_1hz < 0 || irq_alarm < 0) + return -ENODEV; + + info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->irq_1hz = irq_1hz; + info->irq_alarm = irq_alarm; + + platform_set_drvdata(pdev, info); + device_init_wakeup(&pdev->dev, 1); + + return sa1100_rtc_init(pdev, info); } static int sa1100_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-sa1100.h b/drivers/rtc/rtc-sa1100.h new file mode 100644 index 0000000000000..665d054740a17 --- /dev/null +++ b/drivers/rtc/rtc-sa1100.h @@ -0,0 +1,19 @@ +#ifndef __RTC_SA1100_H__ +#define __RTC_SA1100_H__ + +#include + +struct clk; +struct platform_device; + +struct sa1100_rtc { + spinlock_t lock; + int irq_1hz; + int irq_alarm; + struct rtc_device *rtc; + struct clk *clk; +}; + +int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info); + +#endif -- GitLab From 3cdf4ad9633e3ca616617e76b46915c02cba426b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 May 2015 09:20:04 -0500 Subject: [PATCH 6536/7006] rtc: pxa: convert to use shared sa1100 functions Currently, the rtc-sa1100 and rtc-pxa drivers co-exist as rtc-pxa has a superset of functionality. Having 2 drivers sharing the same memory resource is not allowed by the driver model if resources are properly declared. This problem was avoided by not adding memory resources to the SA1100 RTC driver, but that prevents clean-up of the SA1100 driver. This commit converts the PXA RTC to use the exported SA1100 RTC functions. Now the sa1100-rtc and pxa-rtc devices are mutually exclusive, so we must remove the sa1100-rtc from pxa27x and pxa3xx. Signed-off-by: Rob Herring Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Russell King Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: linux-arm-kernel@lists.infradead.org Cc: rtc-linux@googlegroups.com Signed-off-by: Alexandre Belloni --- arch/arm/mach-pxa/pxa27x.c | 1 - arch/arm/mach-pxa/pxa3xx.c | 1 - drivers/rtc/Kconfig | 12 +++++---- drivers/rtc/rtc-pxa.c | 51 ++++++++++++++++++-------------------- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index e6aae9e8adfbd..221260d5d1092 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -282,7 +282,6 @@ static struct platform_device *devices[] __initdata = { &pxa_device_asoc_ssp2, &pxa_device_asoc_ssp3, &pxa_device_asoc_platform, - &sa1100_device_rtc, &pxa_device_rtc, &pxa27x_device_ssp1, &pxa27x_device_ssp2, diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 165638462a2f2..ce0f8d6242e2a 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -394,7 +394,6 @@ static struct platform_device *devices[] __initdata = { &pxa_device_asoc_ssp3, &pxa_device_asoc_ssp4, &pxa_device_asoc_platform, - &sa1100_device_rtc, &pxa_device_rtc, &pxa3xx_device_ssp1, &pxa3xx_device_ssp2, diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 35ea04c50a5ca..0f65a222a48a4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1306,11 +1306,13 @@ config RTC_DRV_GENERIC just say Y. config RTC_DRV_PXA - tristate "PXA27x/PXA3xx" - depends on ARCH_PXA - help - If you say Y here you will get access to the real time clock - built into your PXA27x or PXA3xx CPU. + tristate "PXA27x/PXA3xx" + depends on ARCH_PXA + select RTC_DRV_SA1100 + help + If you say Y here you will get access to the real time clock + built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs + consisting of an SA1100 compatible RTC and the extended PXA RTC. This RTC driver uses PXA RTC registers available since pxa27x series (RDxR, RYxR) instead of legacy RCNR, RTAR. diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 4561f375327db..fb9b3a7d22667 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -32,6 +32,8 @@ #include +#include "rtc-sa1100.h" + #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 #define MAXFREQ_PERIODIC 1000 @@ -86,10 +88,9 @@ __raw_writel((value), (pxa_rtc)->base + (reg)) struct pxa_rtc { + struct sa1100_rtc sa1100_rtc; struct resource *ress; void __iomem *base; - int irq_1Hz; - int irq_Alrm; struct rtc_device *rtc; spinlock_t lock; /* Protects this structure */ }; @@ -184,25 +185,25 @@ static int pxa_rtc_open(struct device *dev) struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); int ret; - ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, 0, + ret = request_irq(pxa_rtc->sa1100_rtc.irq_1hz, pxa_rtc_irq, 0, "rtc 1Hz", dev); if (ret < 0) { - dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz, - ret); + dev_err(dev, "can't get irq %i, err %d\n", + pxa_rtc->sa1100_rtc.irq_1hz, ret); goto err_irq_1Hz; } - ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, 0, + ret = request_irq(pxa_rtc->sa1100_rtc.irq_alarm, pxa_rtc_irq, 0, "rtc Alrm", dev); if (ret < 0) { - dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm, - ret); + dev_err(dev, "can't get irq %i, err %d\n", + pxa_rtc->sa1100_rtc.irq_alarm, ret); goto err_irq_Alrm; } return 0; err_irq_Alrm: - free_irq(pxa_rtc->irq_1Hz, dev); + free_irq(pxa_rtc->sa1100_rtc.irq_1hz, dev); err_irq_1Hz: return ret; } @@ -215,8 +216,8 @@ static void pxa_rtc_release(struct device *dev) rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); spin_unlock_irq(&pxa_rtc->lock); - free_irq(pxa_rtc->irq_Alrm, dev); - free_irq(pxa_rtc->irq_1Hz, dev); + free_irq(pxa_rtc->sa1100_rtc.irq_1hz, dev); + free_irq(pxa_rtc->sa1100_rtc.irq_alarm, dev); } static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -320,12 +321,13 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct pxa_rtc *pxa_rtc; + struct sa1100_rtc *sa1100_rtc; int ret; - u32 rttr; pxa_rtc = devm_kzalloc(dev, sizeof(*pxa_rtc), GFP_KERNEL); if (!pxa_rtc) return -ENOMEM; + sa1100_rtc = &pxa_rtc->sa1100_rtc; spin_lock_init(&pxa_rtc->lock); platform_set_drvdata(pdev, pxa_rtc); @@ -336,13 +338,13 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return -ENXIO; } - pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0); - if (pxa_rtc->irq_1Hz < 0) { + sa1100_rtc->irq_1hz = platform_get_irq(pdev, 0); + if (sa1100_rtc->irq_1hz < 0) { dev_err(dev, "No 1Hz IRQ resource defined\n"); return -ENXIO; } - pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1); - if (pxa_rtc->irq_Alrm < 0) { + sa1100_rtc->irq_alarm = platform_get_irq(pdev, 1); + if (sa1100_rtc->irq_alarm < 0) { dev_err(dev, "No alarm IRQ resource defined\n"); return -ENXIO; } @@ -354,15 +356,10 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return -ENOMEM; } - /* - * If the clock divider is uninitialized then reset it to the - * default value to get the 1Hz clock. - */ - if (rtc_readl(pxa_rtc, RTTR) == 0) { - rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - rtc_writel(pxa_rtc, RTTR, rttr); - dev_warn(dev, "warning: initializing default clock" - " divider/trim value\n"); + ret = sa1100_rtc_init(pdev, sa1100_rtc); + if (!ret) { + dev_err(dev, "Unable to init SA1100 RTC sub-device\n"); + return ret; } rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); @@ -402,7 +399,7 @@ static int pxa_rtc_suspend(struct device *dev) struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - enable_irq_wake(pxa_rtc->irq_Alrm); + enable_irq_wake(pxa_rtc->sa1100_rtc.irq_alarm); return 0; } @@ -411,7 +408,7 @@ static int pxa_rtc_resume(struct device *dev) struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - disable_irq_wake(pxa_rtc->irq_Alrm); + disable_irq_wake(pxa_rtc->sa1100_rtc.irq_alarm); return 0; } #endif -- GitLab From 2c4fabec8790384b91473aa3d0d28d4407168ef9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 2 Feb 2015 17:50:32 -0600 Subject: [PATCH 6537/7006] ARM: pxa: add memory resource to SA1100 RTC device The drivers for the SA1100 and PXA RTCs are now mutually exclusive, so add the memory resource for the sa1100-rtc device. Since the memory resource is already present in the pxa_rtc_resources, that makes sa1100_rtc_resources and pxa_rtc_resources equivalent, so use pxa_rtc_resources for both devices and remove the duplicate sa1100_rtc_resources. Signed-off-by: Rob Herring Cc: Daniel Mack Cc: Haojian Zhuang Acked-by: Robert Jarzmik Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Alexandre Belloni --- arch/arm/mach-pxa/devices.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index e6ce669b54af4..c62473235a133 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -440,25 +440,11 @@ struct platform_device pxa_device_rtc = { .resource = pxa_rtc_resources, }; -static struct resource sa1100_rtc_resources[] = { - { - .start = IRQ_RTC1Hz, - .end = IRQ_RTC1Hz, - .name = "rtc 1Hz", - .flags = IORESOURCE_IRQ, - }, { - .start = IRQ_RTCAlrm, - .end = IRQ_RTCAlrm, - .name = "rtc alarm", - .flags = IORESOURCE_IRQ, - }, -}; - struct platform_device sa1100_device_rtc = { .name = "sa1100-rtc", .id = -1, - .num_resources = ARRAY_SIZE(sa1100_rtc_resources), - .resource = sa1100_rtc_resources, + .num_resources = ARRAY_SIZE(pxa_rtc_resources), + .resource = pxa_rtc_resources, }; static struct resource pxa_ac97_resources[] = { -- GitLab From 90d0ae8e9583355725583e9d1ff0ebdc97936f39 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Feb 2015 14:44:51 -0600 Subject: [PATCH 6538/7006] rtc: sa1100/pxa: convert to run-time register mapping SA1100 and PXA differ only in register offsets which are currently hardcoded in a machine specific header. Some arm64 platforms (PXA1928) have this RTC block as well (and not the PXA270 variant). Convert the driver to use ioremap and set the register offsets dynamically. Since we are touching all the register accesses, convert them all to readl_relaxed/writel_relaxed. Signed-off-by: Rob Herring Acked-by: Robert Jarzmik Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pxa.c | 4 ++ drivers/rtc/rtc-sa1100.c | 82 +++++++++++++++++++++++++++------------- drivers/rtc/rtc-sa1100.h | 4 ++ 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index fb9b3a7d22667..fe4985b546088 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -356,6 +356,10 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return -ENOMEM; } + sa1100_rtc->rcnr = pxa_rtc->base + 0x0; + sa1100_rtc->rtsr = pxa_rtc->base + 0x8; + sa1100_rtc->rtar = pxa_rtc->base + 0x4; + sa1100_rtc->rttr = pxa_rtc->base + 0xc; ret = sa1100_rtc_init(pdev, sa1100_rtc); if (!ret) { dev_err(dev, "Unable to init SA1100 RTC sub-device\n"); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index abc19abd5f2d2..c2187bf6c7e41 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -35,12 +35,10 @@ #include #include -#include -#include - -#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) -#include -#endif +#define RTSR_HZE BIT(3) /* HZ interrupt enable */ +#define RTSR_ALE BIT(2) /* RTC alarm interrupt enable */ +#define RTSR_HZ BIT(1) /* HZ rising-edge detected */ +#define RTSR_AL BIT(0) /* RTC alarm detected */ #include "rtc-sa1100.h" @@ -58,16 +56,16 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) spin_lock(&info->lock); - rtsr = RTSR; + rtsr = readl_relaxed(info->rtsr); /* clear interrupt sources */ - RTSR = 0; + writel_relaxed(0, info->rtsr); /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_probe(). */ if (rtsr & (RTSR_ALE | RTSR_HZE)) { /* This is the original code, before there was the if test * above. This code does not clear interrupts that were not * enabled. */ - RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + writel_relaxed((RTSR_AL | RTSR_HZ) & (rtsr >> 2), info->rtsr); } else { /* For some reason, it is possible to enter this routine * without interruptions enabled, it has been tested with @@ -76,13 +74,13 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) * This situation leads to an infinite "loop" of interrupt * routine calling and as a result the processor seems to * lock on its first call to open(). */ - RTSR = RTSR_AL | RTSR_HZ; + writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr); } /* clear alarm interrupt if it has occurred */ if (rtsr & RTSR_AL) rtsr &= ~RTSR_ALE; - RTSR = rtsr & (RTSR_ALE | RTSR_HZE); + writel_relaxed(rtsr & (RTSR_ALE | RTSR_HZE), info->rtsr); /* update irq data & counter */ if (rtsr & RTSR_AL) @@ -130,7 +128,7 @@ static void sa1100_rtc_release(struct device *dev) struct sa1100_rtc *info = dev_get_drvdata(dev); spin_lock_irq(&info->lock); - RTSR = 0; + writel_relaxed(0, info->rtsr); spin_unlock_irq(&info->lock); free_irq(info->irq_alarm, dev); @@ -139,39 +137,46 @@ static void sa1100_rtc_release(struct device *dev) static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { + u32 rtsr; struct sa1100_rtc *info = dev_get_drvdata(dev); spin_lock_irq(&info->lock); + rtsr = readl_relaxed(info->rtsr); if (enabled) - RTSR |= RTSR_ALE; + rtsr |= RTSR_ALE; else - RTSR &= ~RTSR_ALE; + rtsr &= ~RTSR_ALE; + writel_relaxed(rtsr, info->rtsr); spin_unlock_irq(&info->lock); return 0; } static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) { - rtc_time_to_tm(RCNR, tm); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + rtc_time_to_tm(readl_relaxed(info->rcnr), tm); return 0; } static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) { + struct sa1100_rtc *info = dev_get_drvdata(dev); unsigned long time; int ret; ret = rtc_tm_to_time(tm, &time); if (ret == 0) - RCNR = time; + writel_relaxed(time, info->rcnr); return ret; } static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { u32 rtsr; + struct sa1100_rtc *info = dev_get_drvdata(dev); - rtsr = RTSR; + rtsr = readl_relaxed(info->rtsr); alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; return 0; @@ -187,12 +192,13 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = rtc_tm_to_time(&alrm->time, &time); if (ret != 0) goto out; - RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); - RTAR = time; + writel_relaxed(readl_relaxed(info->rtsr) & + (RTSR_HZE | RTSR_ALE | RTSR_AL), info->rtsr); + writel_relaxed(time, info->rtar); if (alrm->enabled) - RTSR |= RTSR_ALE; + writel_relaxed(readl_relaxed(info->rtsr) | RTSR_ALE, info->rtsr); else - RTSR &= ~RTSR_ALE; + writel_relaxed(readl_relaxed(info->rtsr) & ~RTSR_ALE, info->rtsr); out: spin_unlock_irq(&info->lock); @@ -201,8 +207,10 @@ out: static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR); - seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + seq_printf(seq, "trim/divider\t\t: 0x%08x\n", readl_relaxed(info->rttr)); + seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", readl_relaxed(info->rtsr)); return 0; } @@ -241,12 +249,12 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) * If the clock divider is uninitialized then reset it to the * default value to get the 1Hz clock. */ - if (RTTR == 0) { - RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + if (readl_relaxed(info->rttr) == 0) { + writel_relaxed(RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16), info->rttr); dev_warn(&pdev->dev, "warning: " "initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ - RCNR = 0; + writel_relaxed(0, info->rcnr); } rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops, @@ -279,7 +287,7 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) * * Notice that clearing bit 1 and 0 is accomplished by writting ONES to * the corresponding bits in RTSR. */ - RTSR = RTSR_AL | RTSR_HZ; + writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr); return 0; } @@ -288,6 +296,8 @@ EXPORT_SYMBOL_GPL(sa1100_rtc_init); static int sa1100_rtc_probe(struct platform_device *pdev) { struct sa1100_rtc *info; + struct resource *iores; + void __iomem *base; int irq_1hz, irq_alarm; irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); @@ -301,6 +311,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) info->irq_1hz = irq_1hz; info->irq_alarm = irq_alarm; + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(base)) + return PTR_ERR(base); + + if (IS_ENABLED(CONFIG_ARCH_SA1100) || + of_device_is_compatible(pdev->dev.of_node, "mrvl,sa1100-rtc")) { + info->rcnr = base + 0x04; + info->rtsr = base + 0x10; + info->rtar = base + 0x00; + info->rttr = base + 0x08; + } else { + info->rcnr = base + 0x0; + info->rtsr = base + 0x8; + info->rtar = base + 0x4; + info->rttr = base + 0xc; + } + platform_set_drvdata(pdev, info); device_init_wakeup(&pdev->dev, 1); diff --git a/drivers/rtc/rtc-sa1100.h b/drivers/rtc/rtc-sa1100.h index 665d054740a17..2c79c0c578228 100644 --- a/drivers/rtc/rtc-sa1100.h +++ b/drivers/rtc/rtc-sa1100.h @@ -8,6 +8,10 @@ struct platform_device; struct sa1100_rtc { spinlock_t lock; + void __iomem *rcnr; + void __iomem *rtar; + void __iomem *rtsr; + void __iomem *rttr; int irq_1hz; int irq_alarm; struct rtc_device *rtc; -- GitLab From d6679c48c13ce896a428d392ffe8a62ad6a75b77 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Feb 2015 14:46:29 -0600 Subject: [PATCH 6539/7006] ARM: sa1100: remove unused RTC register definitions Now that register definitions have been moved to the driver, we can remove them from machine specific code. Signed-off-by: Rob Herring Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Alexandre Belloni --- arch/arm/mach-sa1100/include/mach/SA-1100.h | 34 --------------------- 1 file changed, 34 deletions(-) diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h index 0ac6cc08a19c6..7972617cca647 100644 --- a/arch/arm/mach-sa1100/include/mach/SA-1100.h +++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h @@ -857,40 +857,6 @@ #define OIER_E3 OIER_E (3) /* match interrupt Enable 3 */ -/* - * Real-Time Clock (RTC) control registers - * - * Registers - * RTAR Real-Time Clock (RTC) Alarm Register (read/write). - * RCNR Real-Time Clock (RTC) CouNt Register (read/write). - * RTTR Real-Time Clock (RTC) Trim Register (read/write). - * RTSR Real-Time Clock (RTC) Status Register (read/write). - * - * Clocks - * frtx, Trtx Frequency, period of the real-time clock crystal - * (32.768 kHz nominal). - * frtc, Trtc Frequency, period of the real-time clock counter - * (1 Hz nominal). - */ - -#define RTAR __REG(0x90010000) /* RTC Alarm Reg. */ -#define RCNR __REG(0x90010004) /* RTC CouNt Reg. */ -#define RTTR __REG(0x90010008) /* RTC Trim Reg. */ -#define RTSR __REG(0x90010010) /* RTC Status Reg. */ - -#define RTTR_C Fld (16, 0) /* clock divider Count - 1 */ -#define RTTR_D Fld (10, 16) /* trim Delete count */ - /* frtc = (1023*(C + 1) - D)*frtx/ */ - /* (1023*(C + 1)^2) */ - /* Trtc = (1023*(C + 1)^2)*Trtx/ */ - /* (1023*(C + 1) - D) */ - -#define RTSR_AL 0x00000001 /* ALarm detected */ -#define RTSR_HZ 0x00000002 /* 1 Hz clock detected */ -#define RTSR_ALE 0x00000004 /* ALarm interrupt Enable */ -#define RTSR_HZE 0x00000008 /* 1 Hz clock interrupt Enable */ - - /* * Power Manager (PM) control registers * -- GitLab From 7b758ef4440cd581e8207d762af635c644c85f81 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Feb 2015 14:54:01 -0600 Subject: [PATCH 6540/7006] ARM: mmp: remove unused RTC register definitions Now that register definitions have been moved to the driver, regs-rtc.h is no longer used and can be removed. Signed-off-by: Rob Herring Cc: Eric Miao Cc: Haojian Zhuang Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Alexandre Belloni --- arch/arm/mach-mmp/include/mach/regs-rtc.h | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 arch/arm/mach-mmp/include/mach/regs-rtc.h diff --git a/arch/arm/mach-mmp/include/mach/regs-rtc.h b/arch/arm/mach-mmp/include/mach/regs-rtc.h deleted file mode 100644 index 5bff886a39412..0000000000000 --- a/arch/arm/mach-mmp/include/mach/regs-rtc.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __ASM_MACH_REGS_RTC_H -#define __ASM_MACH_REGS_RTC_H - -#include - -#define RTC_VIRT_BASE (APB_VIRT_BASE + 0x10000) -#define RTC_REG(x) (*((volatile u32 __iomem *)(RTC_VIRT_BASE + (x)))) - -/* - * Real Time Clock - */ - -#define RCNR RTC_REG(0x00) /* RTC Count Register */ -#define RTAR RTC_REG(0x04) /* RTC Alarm Register */ -#define RTSR RTC_REG(0x08) /* RTC Status Register */ -#define RTTR RTC_REG(0x0C) /* RTC Timer Trim Register */ - -#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ -#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ -#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ -#define RTSR_AL (1 << 0) /* RTC alarm detected */ - -#endif /* __ASM_MACH_REGS_RTC_H */ -- GitLab From e66ce07a9692f492580820640b446971dff97a74 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Jun 2015 07:53:01 -0500 Subject: [PATCH 6541/7006] ARM: config: Switch PXA27x platforms to use PXA RTC driver With the SA1100 and PXA RTC drivers be mutually exclusive and no longer sharing hardware, PXA27x/PXA3xx platforms must use the PXA RTC driver as the SA1100 platform device is no longer registered. This change should be almost transparent to userspace. Former users of pxa-rtc should be aware that 2 RTCs will be available on their kernels, rtc0 being sa1100-rtc and rtc1 being pxa-rtc. Any userspace relying on the fact that rtc0 was pxa-rtc should be fixed. As a consequence: - the first reboot after the switch will have the wrong time, - on dual boot platform where the other OS programs some logic into the sa1100 rtc IP, a lack of fix in userspace, ie. a kernel changing sa1100-rtc thinking it is pxa-rtc could have dire consequence, such as wiping the other OS data partition. (Thanks to Robert Jarmik for help on the above commit text.) Signed-off-by: Rob Herring Acked-by: Robert Jarzmik Cc: Daniel Mack Cc: Haojian Zhuang Cc: Sergey Lapin Cc: Russell King Cc: Mike Rapoport Cc: Philipp Zabel Signed-off-by: Alexandre Belloni --- arch/arm/configs/cm_x2xx_defconfig | 2 +- arch/arm/configs/em_x270_defconfig | 2 +- arch/arm/configs/magician_defconfig | 2 +- arch/arm/configs/palmz72_defconfig | 2 +- arch/arm/configs/pcm027_defconfig | 2 +- arch/arm/configs/trizeps4_defconfig | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig index dc01c049a5206..3b32d5fd93266 100644 --- a/arch/arm/configs/cm_x2xx_defconfig +++ b/arch/arm/configs/cm_x2xx_defconfig @@ -157,7 +157,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_V3020=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_INOTIFY=y diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig index 4560c9ca6636a..8e10df7ba1b40 100644 --- a/arch/arm/configs/em_x270_defconfig +++ b/arch/arm/configs/em_x270_defconfig @@ -157,7 +157,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_V3020=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_INOTIFY=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index 557dd291288b2..a5b4920cd6d44 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -150,7 +150,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_BACKLIGHT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DEBUG=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_INOTIFY=y CONFIG_MSDOS_FS=m diff --git a/arch/arm/configs/palmz72_defconfig b/arch/arm/configs/palmz72_defconfig index 4baa83c1c5775..83c135e19aba0 100644 --- a/arch/arm/configs/palmz72_defconfig +++ b/arch/arm/configs/palmz72_defconfig @@ -67,7 +67,7 @@ CONFIG_MMC=y CONFIG_MMC_DEBUG=y CONFIG_MMC_PXA=y CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_DNOTIFY is not set diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig index 0a847d04ddc19..b5624e325817f 100644 --- a/arch/arm/configs/pcm027_defconfig +++ b/arch/arm/configs/pcm027_defconfig @@ -82,7 +82,7 @@ CONFIG_MMC=y CONFIG_MMC_PXA=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_PCF8563=m -CONFIG_RTC_DRV_SA1100=m +CONFIG_RTC_DRV_PXA=m CONFIG_EXT2_FS=m CONFIG_EXT3_FS=m # CONFIG_DNOTIFY is not set diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index 932ee4e4a13ae..4bc870028035d 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -177,7 +177,7 @@ CONFIG_NEW_LEDS=y CONFIG_RTC_CLASS=y # CONFIG_RTC_HCTOSYS is not set CONFIG_RTC_DRV_PCF8583=m -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y -- GitLab From a038c3aa9f3afe9ab97a75827789859fb4af5767 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Fri, 14 Aug 2015 20:44:02 +0200 Subject: [PATCH 6542/7006] rtc: as3722: correct month value The RTC month value is 1-indexed, but the kernel assumes it is 0-indexed. This may result in the RTC not rolling over correctly. Signed-off-by: Bibek Basu Signed-off-by: Felix Janda Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-as3722.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c index 9f38eda69154d..56cc5821118bf 100644 --- a/drivers/rtc/rtc-as3722.c +++ b/drivers/rtc/rtc-as3722.c @@ -45,7 +45,7 @@ static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm) rbuff[1] = bin2bcd(tm->tm_min); rbuff[2] = bin2bcd(tm->tm_hour); rbuff[3] = bin2bcd(tm->tm_mday); - rbuff[4] = bin2bcd(tm->tm_mon); + rbuff[4] = bin2bcd(tm->tm_mon + 1); rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900)); } @@ -55,7 +55,7 @@ static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm) tm->tm_min = bcd2bin(rbuff[1] & 0x7F); tm->tm_hour = bcd2bin(rbuff[2] & 0x3F); tm->tm_mday = bcd2bin(rbuff[3] & 0x3F); - tm->tm_mon = bcd2bin(rbuff[4] & 0x1F); + tm->tm_mon = bcd2bin(rbuff[4] & 0x1F) - 1; tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F); return; } -- GitLab From 12ece40d9196e01961192fc25cfdaf22392520de Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Wed, 19 Aug 2015 15:23:21 +0530 Subject: [PATCH 6543/7006] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc adds file for description on device node bindings for RTC found on Xilinx Zynq Ultrascale+ MPSoC. Signed-off-by: Suneel Garapati Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/xlnx-rtc.txt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/xlnx-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt new file mode 100644 index 0000000000000..0df6f016b1b77 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt @@ -0,0 +1,25 @@ +* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock + +RTC controller for the Xilinx Zynq MPSoC Real Time Clock +Separate IRQ lines for seconds and alarm + +Required properties: +- compatible: Should be "xlnx,zynqmp-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ lines for the RTC. +- interrupt-names: interrupt line names eg. "sec" "alarm" + +Optional: +- calibration: calibration value for 1 sec period which will + be programmed directly to calibration register + +Example: +rtc: rtc@ffa60000 { + compatible = "xlnx,zynqmp-rtc"; + reg = <0x0 0xffa60000 0x100>; + interrupt-parent = <&gic>; + interrupts = <0 26 4>, <0 27 4>; + interrupt-names = "alarm", "sec"; + calibration = <0x198233>; +}; -- GitLab From 11143c19eb57a8aee4335e57b21f2897b9fff294 Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Wed, 19 Aug 2015 15:23:22 +0530 Subject: [PATCH 6544/7006] rtc: add xilinx zynqmp rtc driver Add support for RTC controller found on Xilinx Zynq Ultrascale+ MPSoC platform. Signed-off-by: Suneel Garapati Acked-by: Moritz Fischer Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-zynqmp.c | 279 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/rtc/rtc-zynqmp.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 0f65a222a48a4..9d4290617cee5 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1116,6 +1116,13 @@ config RTC_DRV_OPAL This driver can also be built as a module. If so, the module will be called rtc-opal. +config RTC_DRV_ZYNQMP + tristate "Xilinx Zynq Ultrascale+ MPSoC RTC" + depends on OF + help + If you say yes here you get support for the RTC controller found on + Xilinx Zynq Ultrascale+ MPSoC. + comment "on-CPU RTC drivers" config RTC_DRV_DAVINCI diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 279738449a8d1..e491eb5244342 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -159,3 +159,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o +obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c new file mode 100644 index 0000000000000..8b28762f06dff --- /dev/null +++ b/drivers/rtc/rtc-zynqmp.c @@ -0,0 +1,279 @@ +/* + * Xilinx Zynq Ultrascale+ MPSoC Real Time Clock Driver + * + * Copyright (C) 2015 Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* RTC Registers */ +#define RTC_SET_TM_WR 0x00 +#define RTC_SET_TM_RD 0x04 +#define RTC_CALIB_WR 0x08 +#define RTC_CALIB_RD 0x0C +#define RTC_CUR_TM 0x10 +#define RTC_CUR_TICK 0x14 +#define RTC_ALRM 0x18 +#define RTC_INT_STS 0x20 +#define RTC_INT_MASK 0x24 +#define RTC_INT_EN 0x28 +#define RTC_INT_DIS 0x2C +#define RTC_CTRL 0x40 + +#define RTC_FR_EN BIT(20) +#define RTC_FR_DATSHIFT 16 +#define RTC_TICK_MASK 0xFFFF +#define RTC_INT_SEC BIT(0) +#define RTC_INT_ALRM BIT(1) +#define RTC_OSC_EN BIT(24) + +#define RTC_CALIB_DEF 0x198233 +#define RTC_CALIB_MASK 0x1FFFFF +#define RTC_SEC_MAX_VAL 0xFFFFFFFF + +struct xlnx_rtc_dev { + struct rtc_device *rtc; + void __iomem *reg_base; + int alarm_irq; + int sec_irq; +}; + +static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned long new_time; + + new_time = rtc_tm_to_time64(tm); + + if (new_time > RTC_SEC_MAX_VAL) + return -EINVAL; + + writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR); + + return 0; +} + +static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm); + + return rtc_valid_tm(tm); +} + +static int xlnx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_ALRM), &alrm->time); + alrm->enabled = readl(xrtcdev->reg_base + RTC_INT_MASK) & RTC_INT_ALRM; + + return 0; +} + +static int xlnx_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + if (enabled) + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN); + else + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); + + return 0; +} + +static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned long alarm_time; + + alarm_time = rtc_tm_to_time64(&alrm->time); + + if (alarm_time > RTC_SEC_MAX_VAL) + return -EINVAL; + + writel((u32)alarm_time, (xrtcdev->reg_base + RTC_ALRM)); + + xlnx_rtc_alarm_irq_enable(dev, alrm->enabled); + + return 0; +} + +static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval) +{ + /* + * Based on crystal freq of 33.330 KHz + * set the seconds counter and enable, set fractions counter + * to default value suggested as per design spec + * to correct RTC delay in frequency over period of time. + */ + calibval &= RTC_CALIB_MASK; + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR)); +} + +static const struct rtc_class_ops xlnx_rtc_ops = { + .set_time = xlnx_rtc_set_time, + .read_time = xlnx_rtc_read_time, + .read_alarm = xlnx_rtc_read_alarm, + .set_alarm = xlnx_rtc_set_alarm, + .alarm_irq_enable = xlnx_rtc_alarm_irq_enable, +}; + +static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) +{ + struct xlnx_rtc_dev *xrtcdev = (struct xlnx_rtc_dev *)id; + unsigned int status; + + status = readl(xrtcdev->reg_base + RTC_INT_STS); + /* Check if interrupt asserted */ + if (!(status & (RTC_INT_SEC | RTC_INT_ALRM))) + return IRQ_NONE; + + /* Clear interrupt */ + writel(status, xrtcdev->reg_base + RTC_INT_STS); + + if (status & RTC_INT_SEC) + rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF); + if (status & RTC_INT_ALRM) + rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int xlnx_rtc_probe(struct platform_device *pdev) +{ + struct xlnx_rtc_dev *xrtcdev; + struct resource *res; + int ret; + unsigned int calibvalue; + + xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL); + if (!xrtcdev) + return -ENOMEM; + + platform_set_drvdata(pdev, xrtcdev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xrtcdev->reg_base)) + return PTR_ERR(xrtcdev->reg_base); + + xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm"); + if (xrtcdev->alarm_irq < 0) { + dev_err(&pdev->dev, "no irq resource\n"); + return xrtcdev->alarm_irq; + } + ret = devm_request_irq(&pdev->dev, xrtcdev->alarm_irq, + xlnx_rtc_interrupt, 0, + dev_name(&pdev->dev), xrtcdev); + if (ret) { + dev_err(&pdev->dev, "request irq failed\n"); + return ret; + } + + xrtcdev->sec_irq = platform_get_irq_byname(pdev, "sec"); + if (xrtcdev->sec_irq < 0) { + dev_err(&pdev->dev, "no irq resource\n"); + return xrtcdev->sec_irq; + } + ret = devm_request_irq(&pdev->dev, xrtcdev->sec_irq, + xlnx_rtc_interrupt, 0, + dev_name(&pdev->dev), xrtcdev); + if (ret) { + dev_err(&pdev->dev, "request irq failed\n"); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, "calibration", + &calibvalue); + if (ret) + calibvalue = RTC_CALIB_DEF; + + xlnx_init_rtc(xrtcdev, calibvalue); + + device_init_wakeup(&pdev->dev, 1); + + xrtcdev->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &xlnx_rtc_ops, THIS_MODULE); + return PTR_ERR_OR_ZERO(xrtcdev->rtc); +} + +static int xlnx_rtc_remove(struct platform_device *pdev) +{ + xlnx_rtc_alarm_irq_enable(&pdev->dev, 0); + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +static int __maybe_unused xlnx_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(xrtcdev->alarm_irq); + else + xlnx_rtc_alarm_irq_enable(dev, 0); + + return 0; +} + +static int __maybe_unused xlnx_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(xrtcdev->alarm_irq); + else + xlnx_rtc_alarm_irq_enable(dev, 1); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xlnx_rtc_pm_ops, xlnx_rtc_suspend, xlnx_rtc_resume); + +static const struct of_device_id xlnx_rtc_of_match[] = { + {.compatible = "xlnx,zynqmp-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match); + +static struct platform_driver xlnx_rtc_driver = { + .probe = xlnx_rtc_probe, + .remove = xlnx_rtc_remove, + .driver = { + .name = KBUILD_MODNAME, + .pm = &xlnx_rtc_pm_ops, + .of_match_table = xlnx_rtc_of_match, + }, +}; + +module_platform_driver(xlnx_rtc_driver); + +MODULE_DESCRIPTION("Xilinx Zynq MPSoC RTC driver"); +MODULE_AUTHOR("Xilinx Inc."); +MODULE_LICENSE("GPL v2"); -- GitLab From ff02c0444b83201ff76cc49deccac8cf2bffc7bc Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 21 Aug 2015 18:43:41 +0900 Subject: [PATCH 6545/7006] rtc: s5m: fix to update ctrl register According to datasheet, the S2MPS13X and S2MPS14X should update write buffer via setting WUDR bit to high after ctrl register is written. If not, ALARM interrupt of rtc-s5m doesn't happen first time when i use tools/testing/selftests/timers/rtctest.c test program and hour format is used to 12 hour mode in Odroid-XU3 board. One more issue is the RTC doesn't keep time on Odroid-XU3 board when i turn on board after power off even if RTC battery is connected. It can be solved as setting WUDR & RUDR bits to high at the same time after RTC_CTRL register is written. It's same with condition of only writing ALARM registers, so this is for only S2MPS14 and we should set WUDR & A_UDR bits to high on S2MPS13. I can't find any reasonable description about this like fix from datasheet, but can find similar codes from rtc driver source of hardkernel kernel and vendor kernel. Signed-off-by: Joonyoung Shim Cc: # v3.16 Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 8c70d785ba739..ab60287ee72d6 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -635,6 +635,16 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) case S2MPS13X: data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); + if (ret < 0) + break; + + /* + * Should set WUDR & (RUDR or AUDR) bits to high after writing + * RTC_CTRL register like writing Alarm registers. We can't find + * the description from datasheet but vendor code does that + * really. + */ + ret = s5m8767_rtc_set_alarm_reg(info); break; default: -- GitLab From fff51e771eafc3b4fa6daf1372fd4a4023bb402b Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 18 Aug 2015 15:11:14 +0530 Subject: [PATCH 6546/7006] ARM: dts: AM437x: Add the internal and external clock nodes for rtc rtc can either be supplied from internal 32k clock or external crystal generated 32k clock. Internal clock is SOC specific and the external clock is board dependent. Adding the corresponding nodes. Signed-off-by: Keerthy Acked-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/rtc-omap.txt | 4 ++++ arch/arm/boot/dts/am4372.dtsi | 2 ++ arch/arm/boot/dts/am437x-gp-evm.dts | 13 +++++++++++++ arch/arm/boot/dts/am437x-idk-evm.dts | 9 +++++++++ arch/arm/boot/dts/am437x-sk-evm.dts | 9 +++++++++ 5 files changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index 43a83668673aa..bf7d11ae9bea6 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -16,6 +16,8 @@ Required properties: Optional properties: - system-power-controller: whether the rtc is controlling the system power through pmic_power_en +- clocks: Any internal or external clocks feeding in to rtc +- clock-names: Corresponding names of the clocks Example: @@ -26,4 +28,6 @@ rtc@1c23000 { 19>; interrupt-parent = <&intc>; system-power-controller; + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; }; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 564900b9fcceb..0447c04a40cc4 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -358,6 +358,8 @@ interrupts = ; ti,hwmods = "rtc"; + clocks = <&clk_32768_ck>; + clock-names = "int-clk"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 215775dc69483..22038f21f2283 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -112,6 +112,13 @@ clock-frequency = <12000000>; }; + /* fixed 32k external oscillator clock */ + clk_32k_rtc: clk_32k_rtc { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + sound0: sound@0 { compatible = "simple-audio-card"; simple-audio-card,name = "AM437x-GP-EVM"; @@ -941,3 +948,9 @@ tx-num-evt = <32>; rx-num-evt = <32>; }; + +&rtc { + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts index 378344271746f..af25801418b49 100644 --- a/arch/arm/boot/dts/am437x-idk-evm.dts +++ b/arch/arm/boot/dts/am437x-idk-evm.dts @@ -110,6 +110,13 @@ gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; }; }; + + /* fixed 32k external oscillator clock */ + clk_32k_rtc: clk_32k_rtc { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; }; &am43xx_pinmux { @@ -394,6 +401,8 @@ }; &rtc { + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; status = "okay"; }; diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 22af44894c66f..7da7c2da4af13 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -24,6 +24,13 @@ display0 = &lcd0; }; + /* fixed 32k external oscillator clock */ + clk_32k_rtc: clk_32k_rtc { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + backlight { compatible = "pwm-backlight"; pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>; @@ -697,6 +704,8 @@ }; &rtc { + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; status = "okay"; }; -- GitLab From 532409aa1ba8b69d5a3dea159d4b1bd9adbd7a46 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 18 Aug 2015 15:11:15 +0530 Subject: [PATCH 6547/7006] rtc: omap: Add internal clock enabling support The rtc can be clocked by an internal 32K clock. Adding the support to enable the same. Signed-off-by: Keerthy Acked-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8b6355ffaff99..f31c0127dae01 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -25,6 +25,7 @@ #include #include #include +#include /* * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock @@ -132,6 +133,7 @@ struct omap_rtc_device_type { struct omap_rtc { struct rtc_device *rtc; void __iomem *base; + struct clk *clk; int irq_alarm; int irq_timer; u8 interrupts_reg; @@ -553,6 +555,11 @@ static int omap_rtc_probe(struct platform_device *pdev) if (rtc->irq_alarm <= 0) return -ENOENT; + rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); + + if (!IS_ERR(rtc->clk)) + clk_prepare_enable(rtc->clk); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rtc->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(rtc->base)) @@ -681,6 +688,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); + if (!IS_ERR(rtc->clk)) + clk_disable_unprepare(rtc->clk); + rtc->type->unlock(rtc); /* leave rtc running, but disable irqs */ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); -- GitLab From 399cf0f63f6f24d7a837fbfbc801010cb6e77579 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 18 Aug 2015 15:11:16 +0530 Subject: [PATCH 6548/7006] rtc: omap: Add external clock enabling support Configure the clock source to external clock if available. External clock is preferred as it can be ticking during suspend. Signed-off-by: Keerthy Acked-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index f31c0127dae01..ec2e9c5fb993c 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -108,6 +108,7 @@ /* OMAP_RTC_OSC_REG bit fields: */ #define OMAP_RTC_OSC_32KCLK_EN BIT(6) +#define OMAP_RTC_OSC_SEL_32KCLK_SRC BIT(3) /* OMAP_RTC_IRQWAKEEN bit fields: */ #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) @@ -138,6 +139,7 @@ struct omap_rtc { int irq_timer; u8 interrupts_reg; bool is_pmic_controller; + bool has_ext_clk; const struct omap_rtc_device_type *type; }; @@ -555,7 +557,11 @@ static int omap_rtc_probe(struct platform_device *pdev) if (rtc->irq_alarm <= 0) return -ENOENT; - rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); + rtc->clk = devm_clk_get(&pdev->dev, "ext-clk"); + if (!IS_ERR(rtc->clk)) + rtc->has_ext_clk = true; + else + rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); if (!IS_ERR(rtc->clk)) clk_prepare_enable(rtc->clk); @@ -634,6 +640,16 @@ static int omap_rtc_probe(struct platform_device *pdev) if (reg != new_ctrl) rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); + /* + * If we have the external clock then switch to it so we can keep + * ticking across suspend. + */ + if (rtc->has_ext_clk) { + reg = rtc_read(rtc, OMAP_RTC_OSC_REG); + rtc_write(rtc, OMAP_RTC_OSC_REG, + reg | OMAP_RTC_OSC_SEL_32KCLK_SRC); + } + rtc->type->lock(rtc); device_init_wakeup(&pdev->dev, true); @@ -679,6 +695,7 @@ err: static int __exit omap_rtc_remove(struct platform_device *pdev) { struct omap_rtc *rtc = platform_get_drvdata(pdev); + u8 reg; if (pm_power_off == omap_rtc_power_off && omap_rtc_power_off_rtc == rtc) { @@ -695,6 +712,12 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) /* leave rtc running, but disable irqs */ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); + if (rtc->has_ext_clk) { + reg = rtc_read(rtc, OMAP_RTC_OSC_REG); + reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC; + rtc_write(rtc, OMAP_RTC_OSC_REG, reg); + } + rtc->type->lock(rtc); /* Disable the clock/module */ -- GitLab From 63074cc3d4b8367aa6d9dc5520b88ca6557d32fa Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 27 Aug 2015 12:34:32 +0200 Subject: [PATCH 6549/7006] rtc: Fix module autoload for rtc-{ab8500,max8997,s5m} drivers These platform drivers have a platform device ID table but the module alias information is not created so module autoloading will not work. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab8500.c | 1 + drivers/rtc/rtc-max8997.c | 1 + drivers/rtc/rtc-s5m.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 133d2e2e1a259..8537d1e3a9958 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -446,6 +446,7 @@ static const struct platform_device_id ab85xx_rtc_ids[] = { { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, }; +MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids); static int ab8500_rtc_probe(struct platform_device *pdev) { diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index 9e02bcda0c091..db984d4bf9526 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -521,6 +521,7 @@ static const struct platform_device_id rtc_id[] = { { "max8997-rtc", 0 }, {}, }; +MODULE_DEVICE_TABLE(platform, rtc_id); static struct platform_driver max8997_rtc_driver = { .driver = { diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index ab60287ee72d6..f2504b4eef345 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -807,6 +807,7 @@ static const struct platform_device_id s5m_rtc_id[] = { { "s2mps14-rtc", S2MPS14X }, { }, }; +MODULE_DEVICE_TABLE(platform, s5m_rtc_id); static struct platform_driver s5m_rtc_driver = { .driver = { -- GitLab From 73798d5c41fdb434ccbeeec76afc8106869a98c3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 27 Aug 2015 13:52:02 +0200 Subject: [PATCH 6550/7006] rtc: Fix module autoload for OF platform drivers These platform drivers have a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Javier Martinez Canillas Acked-by: Andrew Lunn Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 1 + drivers/rtc/rtc-coh901331.c | 1 + drivers/rtc/rtc-da9063.c | 1 + drivers/rtc/rtc-moxart.c | 1 + drivers/rtc/rtc-mpc5121.c | 1 + drivers/rtc/rtc-mt6397.c | 1 + drivers/rtc/rtc-mv.c | 1 + drivers/rtc/rtc-vt8500.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 06c6bd5eab411..9a3f2a6f512e0 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -295,6 +295,7 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = { { .compatible = "marvell,armada-380-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); #endif static struct platform_driver armada38x_rtc_driver = { diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 56343b2fbc685..101b7a240e0fa 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -263,6 +263,7 @@ static const struct of_device_id coh901331_dt_match[] = { { .compatible = "stericsson,coh901331" }, {}, }; +MODULE_DEVICE_TABLE(of, coh901331_dt_match); static struct platform_driver coh901331_driver = { .driver = { diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 5f38a5c84b562..00a8f7f4f87cb 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -169,6 +169,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = { { .compatible = "dlg,da9062-rtc", .data = &da9062_aa_regs }, { }, }; +MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table); static void da9063_data_to_tm(u8 *data, struct rtc_time *tm, struct da9063_compatible_rtc *rtc) diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c index 73759c9a4527a..07b30a373a929 100644 --- a/drivers/rtc/rtc-moxart.c +++ b/drivers/rtc/rtc-moxart.c @@ -312,6 +312,7 @@ static const struct of_device_id moxart_rtc_match[] = { { .compatible = "moxa,moxart-rtc" }, { }, }; +MODULE_DEVICE_TABLE(of, moxart_rtc_match); static struct platform_driver moxart_rtc_driver = { .probe = moxart_rtc_probe, diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 1767e18d5bd48..4ca4daa0b8f32 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -406,6 +406,7 @@ static const struct of_device_id mpc5121_rtc_match[] = { { .compatible = "fsl,mpc5200-rtc", }, {}, }; +MODULE_DEVICE_TABLE(of, mpc5121_rtc_match); #endif static struct platform_driver mpc5121_rtc_driver = { diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 30c926b363615..06a5c52b292f2 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -402,6 +402,7 @@ static const struct of_device_id mt6397_rtc_of_match[] = { { .compatible = "mediatek,mt6397-rtc", }, { } }; +MODULE_DEVICE_TABLE(of, mt6397_rtc_of_match); static struct platform_driver mtk_rtc_driver = { .driver = { diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 7f50d2ef7f6ef..79bb28617d458 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -324,6 +324,7 @@ static const struct of_device_id rtc_mv_of_match_table[] = { { .compatible = "marvell,orion-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table); #endif static struct platform_driver mv_rtc_driver = { diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index a58b6d17e6f07..27e896995e9b3 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -271,6 +271,7 @@ static const struct of_device_id wmt_dt_ids[] = { { .compatible = "via,vt8500-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, wmt_dt_ids); static struct platform_driver vt8500_rtc_driver = { .probe = vt8500_rtc_probe, -- GitLab From d78908d9717b627a261b1bfe6feb67181e12752e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 10 Aug 2015 09:47:45 -0300 Subject: [PATCH 6551/7006] rtc: ds1374: Remove unused variable Remove unused variable 'res' and fix the following build warning: drivers/rtc/rtc-ds1374.c:667:6: warning: unused variable 'res' [-Wunused-variable] Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 7067232ba5071..3b3049c8c9e04 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -664,8 +664,6 @@ static int ds1374_remove(struct i2c_client *client) { struct ds1374 *ds1374 = i2c_get_clientdata(client); #ifdef CONFIG_RTC_DRV_DS1374_WDT - int res; - misc_deregister(&ds1374_miscdev); ds1374_miscdev.parent = NULL; unregister_reboot_notifier(&ds1374_wdt_notifier); -- GitLab From 8a67e93153f03a8d205727c0aeacb5524a414f77 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 4 Sep 2015 08:58:05 -0300 Subject: [PATCH 6552/7006] rtc: ab8500: Add a sentinel to ab85xx_rtc_ids[] Add a sentinel to ab85xx_rtc_ids[] in order to fix the following error: drivers/rtc/rtc-ab8500: struct platform_device_id is 24 bytes. The last of 2 is: 0x61 0x62 0x38 0x35 0x34 0x30 0x2d 0x72 0x74 0x63 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x8c FATAL: drivers/rtc/rtc-ab8500: struct platform_device_id is not terminated with a NULL entry! Reported-by: Andrey Ryabinin Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab8500.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 8537d1e3a9958..51407c4c7bd2b 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -445,6 +445,7 @@ static const struct rtc_class_ops ab8540_rtc_ops = { static const struct platform_device_id ab85xx_rtc_ids[] = { { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids); -- GitLab From 5f1b2f77646fc0ef2f36fc554f5722a1381d0892 Mon Sep 17 00:00:00 2001 From: Mitja Spes Date: Wed, 2 Sep 2015 10:02:29 +0200 Subject: [PATCH 6553/7006] rtc: abx80x: fix RTC write bit Fix RTC write bit as per application manual Cc: stable@vger.kernel.org # 4.1+ Signed-off-by: Mitja Spes Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 4337c3bc6acef..afea84c7a155c 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -28,7 +28,7 @@ #define ABX8XX_REG_WD 0x07 #define ABX8XX_REG_CTRL1 0x10 -#define ABX8XX_CTRL_WRITE BIT(1) +#define ABX8XX_CTRL_WRITE BIT(0) #define ABX8XX_CTRL_12_24 BIT(6) #define ABX8XX_REG_CFG_KEY 0x1f -- GitLab From f5d75341fac6033f6afac900da110cc78e06d40d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 5 Sep 2015 10:29:09 -0700 Subject: [PATCH 6554/7006] Input: i8042 - lower log level for "no controller" message Nowadays the machines without i8042 controller is popular, and no need to print "No controller found" message in the error log level, which annoys at booting in quiet mode. Let's lower it info level. Signed-off-by: Takashi Iwai Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index c9c98f0ab284f..db91de539ee30 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -877,7 +877,7 @@ static int __init i8042_check_aux(void) static int i8042_controller_check(void) { if (i8042_flush()) { - pr_err("No controller found\n"); + pr_info("No controller found\n"); return -ENODEV; } -- GitLab From 48ead50c1dd8e5cdb7ead067558a834c1e895e6e Mon Sep 17 00:00:00 2001 From: Sanchayan Maity Date: Sat, 5 Sep 2015 10:32:09 -0700 Subject: [PATCH 6555/7006] Input: Add touchscreen support for Colibri VF50 The Colibri Vybrid VF50 module supports 4-wire touchscreens using FETs and ADC inputs. This driver uses the IIO consumer interface and relies on the vf610_adc driver based on the IIO framework. Signed-off-by: Sanchayan Maity Signed-off-by: Dmitry Torokhov --- .../input/touchscreen/colibri-vf50-ts.txt | 36 ++ drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/colibri-vf50-ts.c | 386 ++++++++++++++++++ 4 files changed, 435 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt create mode 100644 drivers/input/touchscreen/colibri-vf50-ts.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt b/Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt new file mode 100644 index 0000000000000..9d9e930f32512 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/colibri-vf50-ts.txt @@ -0,0 +1,36 @@ +* Toradex Colibri VF50 Touchscreen driver + +Required Properties: +- compatible must be toradex,vf50-touchscreen +- io-channels: adc channels being used by the Colibri VF50 module +- xp-gpios: FET gate driver for input of X+ +- xm-gpios: FET gate driver for input of X- +- yp-gpios: FET gate driver for input of Y+ +- ym-gpios: FET gate driver for input of Y- +- interrupt-parent: phandle for the interrupt controller +- interrupts: pen irq interrupt for touch detection +- pinctrl-names: "idle", "default", "gpios" +- pinctrl-0: pinctrl node for pen/touch detection state pinmux +- pinctrl-1: pinctrl node for X/Y and pressure measurement (ADC) state pinmux +- pinctrl-2: pinctrl node for gpios functioning as FET gate drivers +- vf50-ts-min-pressure: pressure level at which to stop measuring X/Y values + +Example: + + touchctrl: vf50_touchctrl { + compatible = "toradex,vf50-touchscreen"; + io-channels = <&adc1 0>,<&adc0 0>, + <&adc0 1>,<&adc1 2>; + xp-gpios = <&gpio0 13 GPIO_ACTIVE_LOW>; + xm-gpios = <&gpio2 29 GPIO_ACTIVE_HIGH>; + yp-gpios = <&gpio0 12 GPIO_ACTIVE_LOW>; + ym-gpios = <&gpio0 4 GPIO_ACTIVE_HIGH>; + interrupt-parent = <&gpio0>; + interrupts = <8 IRQ_TYPE_LEVEL_LOW>; + pinctrl-names = "idle","default","gpios"; + pinctrl-0 = <&pinctrl_touchctrl_idle>; + pinctrl-1 = <&pinctrl_touchctrl_default>; + pinctrl-2 = <&pinctrl_touchctrl_gpios>; + vf50-ts-min-pressure = <200>; + status = "disabled"; + }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 059edeb7f04a0..a6d7a4d8dbb77 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -1040,4 +1040,16 @@ config TOUCHSCREEN_ZFORCE To compile this driver as a module, choose M here: the module will be called zforce_ts. +config TOUCHSCREEN_COLIBRI_VF50 + tristate "Toradex Colibri on board touchscreen driver" + depends on GPIOLIB && IIO && VF610_ADC + help + Say Y here if you have a Colibri VF50 and plan to use + the on-board provided 4-wire touchscreen driver. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called colibri_vf50_ts. + endif diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index c85aae23e7f84..fb27f7e36070a 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -85,3 +85,4 @@ obj-$(CONFIG_TOUCHSCREEN_W90X900) += w90p910_ts.o obj-$(CONFIG_TOUCHSCREEN_SX8654) += sx8654.o obj-$(CONFIG_TOUCHSCREEN_TPS6507X) += tps6507x-ts.o obj-$(CONFIG_TOUCHSCREEN_ZFORCE) += zforce_ts.o +obj-$(CONFIG_TOUCHSCREEN_COLIBRI_VF50) += colibri-vf50-ts.o diff --git a/drivers/input/touchscreen/colibri-vf50-ts.c b/drivers/input/touchscreen/colibri-vf50-ts.c new file mode 100644 index 0000000000000..5d4903a402cc6 --- /dev/null +++ b/drivers/input/touchscreen/colibri-vf50-ts.c @@ -0,0 +1,386 @@ +/* + * Toradex Colibri VF50 Touchscreen driver + * + * Copyright 2015 Toradex AG + * + * Originally authored by Stefan Agner for 3.0 kernel + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "colibri-vf50-ts" +#define DRV_VERSION "1.0" + +#define VF_ADC_MAX ((1 << 12) - 1) + +#define COLI_TOUCH_MIN_DELAY_US 1000 +#define COLI_TOUCH_MAX_DELAY_US 2000 +#define COLI_PULLUP_MIN_DELAY_US 10000 +#define COLI_PULLUP_MAX_DELAY_US 11000 +#define COLI_TOUCH_NO_OF_AVGS 5 +#define COLI_TOUCH_REQ_ADC_CHAN 4 + +struct vf50_touch_device { + struct platform_device *pdev; + struct input_dev *ts_input; + struct iio_channel *channels; + struct gpio_desc *gpio_xp; + struct gpio_desc *gpio_xm; + struct gpio_desc *gpio_yp; + struct gpio_desc *gpio_ym; + int pen_irq; + int min_pressure; + bool stop_touchscreen; +}; + +/* + * Enables given plates and measures touch parameters using ADC + */ +static int adc_ts_measure(struct iio_channel *channel, + struct gpio_desc *plate_p, struct gpio_desc *plate_m) +{ + int i, value = 0, val = 0; + int error; + + gpiod_set_value(plate_p, 1); + gpiod_set_value(plate_m, 1); + + usleep_range(COLI_TOUCH_MIN_DELAY_US, COLI_TOUCH_MAX_DELAY_US); + + for (i = 0; i < COLI_TOUCH_NO_OF_AVGS; i++) { + error = iio_read_channel_raw(channel, &val); + if (error < 0) { + value = error; + goto error_iio_read; + } + + value += val; + } + + value /= COLI_TOUCH_NO_OF_AVGS; + +error_iio_read: + gpiod_set_value(plate_p, 0); + gpiod_set_value(plate_m, 0); + + return value; +} + +/* + * Enable touch detection using falling edge detection on XM + */ +static void vf50_ts_enable_touch_detection(struct vf50_touch_device *vf50_ts) +{ + /* Enable plate YM (needs to be strong GND, high active) */ + gpiod_set_value(vf50_ts->gpio_ym, 1); + + /* + * Let the platform mux to idle state in order to enable + * Pull-Up on GPIO + */ + pinctrl_pm_select_idle_state(&vf50_ts->pdev->dev); + + /* Wait for the pull-up to be stable on high */ + usleep_range(COLI_PULLUP_MIN_DELAY_US, COLI_PULLUP_MAX_DELAY_US); +} + +/* + * ADC touch screen sampling bottom half irq handler + */ +static irqreturn_t vf50_ts_irq_bh(int irq, void *private) +{ + struct vf50_touch_device *vf50_ts = private; + struct device *dev = &vf50_ts->pdev->dev; + int val_x, val_y, val_z1, val_z2, val_p = 0; + bool discard_val_on_start = true; + + /* Disable the touch detection plates */ + gpiod_set_value(vf50_ts->gpio_ym, 0); + + /* Let the platform mux to default state in order to mux as ADC */ + pinctrl_pm_select_default_state(dev); + + while (!vf50_ts->stop_touchscreen) { + /* X-Direction */ + val_x = adc_ts_measure(&vf50_ts->channels[0], + vf50_ts->gpio_xp, vf50_ts->gpio_xm); + if (val_x < 0) + break; + + /* Y-Direction */ + val_y = adc_ts_measure(&vf50_ts->channels[1], + vf50_ts->gpio_yp, vf50_ts->gpio_ym); + if (val_y < 0) + break; + + /* + * Touch pressure + * Measure on XP/YM + */ + val_z1 = adc_ts_measure(&vf50_ts->channels[2], + vf50_ts->gpio_yp, vf50_ts->gpio_xm); + if (val_z1 < 0) + break; + val_z2 = adc_ts_measure(&vf50_ts->channels[3], + vf50_ts->gpio_yp, vf50_ts->gpio_xm); + if (val_z2 < 0) + break; + + /* Validate signal (avoid calculation using noise) */ + if (val_z1 > 64 && val_x > 64) { + /* + * Calculate resistance between the plates + * lower resistance means higher pressure + */ + int r_x = (1000 * val_x) / VF_ADC_MAX; + + val_p = (r_x * val_z2) / val_z1 - r_x; + + } else { + val_p = 2000; + } + + val_p = 2000 - val_p; + dev_dbg(dev, + "Measured values: x: %d, y: %d, z1: %d, z2: %d, p: %d\n", + val_x, val_y, val_z1, val_z2, val_p); + + /* + * If touch pressure is too low, stop measuring and reenable + * touch detection + */ + if (val_p < vf50_ts->min_pressure || val_p > 2000) + break; + + /* + * The pressure may not be enough for the first x and the + * second y measurement, but, the pressure is ok when the + * driver is doing the third and fourth measurement. To + * take care of this, we drop the first measurement always. + */ + if (discard_val_on_start) { + discard_val_on_start = false; + } else { + /* + * Report touch position and sleep for + * the next measurement. + */ + input_report_abs(vf50_ts->ts_input, + ABS_X, VF_ADC_MAX - val_x); + input_report_abs(vf50_ts->ts_input, + ABS_Y, VF_ADC_MAX - val_y); + input_report_abs(vf50_ts->ts_input, + ABS_PRESSURE, val_p); + input_report_key(vf50_ts->ts_input, BTN_TOUCH, 1); + input_sync(vf50_ts->ts_input); + } + + usleep_range(COLI_PULLUP_MIN_DELAY_US, + COLI_PULLUP_MAX_DELAY_US); + } + + /* Report no more touch, re-enable touch detection */ + input_report_abs(vf50_ts->ts_input, ABS_PRESSURE, 0); + input_report_key(vf50_ts->ts_input, BTN_TOUCH, 0); + input_sync(vf50_ts->ts_input); + + vf50_ts_enable_touch_detection(vf50_ts); + + return IRQ_HANDLED; +} + +static int vf50_ts_open(struct input_dev *dev_input) +{ + struct vf50_touch_device *touchdev = input_get_drvdata(dev_input); + struct device *dev = &touchdev->pdev->dev; + + dev_dbg(dev, "Input device %s opened, starting touch detection\n", + dev_input->name); + + touchdev->stop_touchscreen = false; + + /* Mux detection before request IRQ, wait for pull-up to settle */ + vf50_ts_enable_touch_detection(touchdev); + + return 0; +} + +static void vf50_ts_close(struct input_dev *dev_input) +{ + struct vf50_touch_device *touchdev = input_get_drvdata(dev_input); + struct device *dev = &touchdev->pdev->dev; + + touchdev->stop_touchscreen = true; + + /* Make sure IRQ is not running past close */ + mb(); + synchronize_irq(touchdev->pen_irq); + + gpiod_set_value(touchdev->gpio_ym, 0); + pinctrl_pm_select_default_state(dev); + + dev_dbg(dev, "Input device %s closed, disable touch detection\n", + dev_input->name); +} + +static int vf50_ts_get_gpiod(struct device *dev, struct gpio_desc **gpio_d, + const char *con_id, enum gpiod_flags flags) +{ + int error; + + *gpio_d = devm_gpiod_get(dev, con_id, flags); + if (IS_ERR(*gpio_d)) { + error = PTR_ERR(*gpio_d); + dev_err(dev, "Could not get gpio_%s %d\n", con_id, error); + return error; + } + + return 0; +} + +static void vf50_ts_channel_release(void *data) +{ + struct iio_channel *channels = data; + + iio_channel_release_all(channels); +} + +static int vf50_ts_probe(struct platform_device *pdev) +{ + struct input_dev *input; + struct iio_channel *channels; + struct device *dev = &pdev->dev; + struct vf50_touch_device *touchdev; + int num_adc_channels; + int error; + + channels = iio_channel_get_all(dev); + if (IS_ERR(channels)) + return PTR_ERR(channels); + + error = devm_add_action(dev, vf50_ts_channel_release, channels); + if (error) { + iio_channel_release_all(channels); + dev_err(dev, "Failed to register iio channel release action"); + return error; + } + + num_adc_channels = 0; + while (channels[num_adc_channels].indio_dev) + num_adc_channels++; + + if (num_adc_channels != COLI_TOUCH_REQ_ADC_CHAN) { + dev_err(dev, "Inadequate ADC channels specified\n"); + return -EINVAL; + } + + touchdev = devm_kzalloc(dev, sizeof(*touchdev), GFP_KERNEL); + if (!touchdev) + return -ENOMEM; + + touchdev->pdev = pdev; + touchdev->channels = channels; + + error = of_property_read_u32(dev->of_node, "vf50-ts-min-pressure", + &touchdev->min_pressure); + if (error) + return error; + + input = devm_input_allocate_device(dev); + if (!input) { + dev_err(dev, "Failed to allocate TS input device\n"); + return -ENOMEM; + } + + platform_set_drvdata(pdev, touchdev); + + input->name = DRIVER_NAME; + input->id.bustype = BUS_HOST; + input->dev.parent = dev; + input->open = vf50_ts_open; + input->close = vf50_ts_close; + + input_set_capability(input, EV_KEY, BTN_TOUCH); + input_set_abs_params(input, ABS_X, 0, VF_ADC_MAX, 0, 0); + input_set_abs_params(input, ABS_Y, 0, VF_ADC_MAX, 0, 0); + input_set_abs_params(input, ABS_PRESSURE, 0, VF_ADC_MAX, 0, 0); + + touchdev->ts_input = input; + input_set_drvdata(input, touchdev); + + error = input_register_device(input); + if (error) { + dev_err(dev, "Failed to register input device\n"); + return error; + } + + error = vf50_ts_get_gpiod(dev, &touchdev->gpio_xp, "xp", GPIOD_OUT_LOW); + if (error) + return error; + + error = vf50_ts_get_gpiod(dev, &touchdev->gpio_xm, + "xm", GPIOD_OUT_LOW); + if (error) + return error; + + error = vf50_ts_get_gpiod(dev, &touchdev->gpio_yp, "yp", GPIOD_OUT_LOW); + if (error) + return error; + + error = vf50_ts_get_gpiod(dev, &touchdev->gpio_ym, "ym", GPIOD_OUT_LOW); + if (error) + return error; + + touchdev->pen_irq = platform_get_irq(pdev, 0); + if (touchdev->pen_irq < 0) + return touchdev->pen_irq; + + error = devm_request_threaded_irq(dev, touchdev->pen_irq, + NULL, vf50_ts_irq_bh, IRQF_ONESHOT, + "vf50 touch", touchdev); + if (error) { + dev_err(dev, "Failed to request IRQ %d: %d\n", + touchdev->pen_irq, error); + return error; + } + + return 0; +} + +static const struct of_device_id vf50_touch_of_match[] = { + { .compatible = "toradex,vf50-touchscreen", }, + { } +}; +MODULE_DEVICE_TABLE(of, vf50_touch_of_match); + +static struct platform_driver vf50_touch_driver = { + .driver = { + .name = "toradex,vf50_touchctrl", + .of_match_table = vf50_touch_of_match, + }, + .probe = vf50_ts_probe, +}; +module_platform_driver(vf50_touch_driver); + +MODULE_AUTHOR("Sanchayan Maity"); +MODULE_DESCRIPTION("Colibri VF50 Touchscreen driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); -- GitLab From 9a436d524d3533cd15ed5a189d2237ff1e4e5343 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Sat, 5 Sep 2015 11:31:21 -0700 Subject: [PATCH 6556/7006] Input: touchscreen - add imx6ul_tsc driver support Freescale i.MX6UL contains a internal touchscreen controller, this patch add a driver to support this controller. Signed-off-by: Haibo Chen Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/imx6ul_tsc.txt | 36 ++ drivers/input/touchscreen/Kconfig | 12 + drivers/input/touchscreen/Makefile | 1 + drivers/input/touchscreen/imx6ul_tsc.c | 523 ++++++++++++++++++ 4 files changed, 572 insertions(+) create mode 100644 Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt create mode 100644 drivers/input/touchscreen/imx6ul_tsc.c diff --git a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt new file mode 100644 index 0000000000000..853dff96dd9f7 --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt @@ -0,0 +1,36 @@ +* Freescale i.MX6UL Touch Controller + +Required properties: +- compatible: must be "fsl,imx6ul-tsc". +- reg: this touch controller address and the ADC2 address. +- interrupts: the interrupt of this touch controller and ADC2. +- clocks: the root clock of touch controller and ADC2. +- clock-names; must be "tsc" and "adc". +- xnur-gpio: the X- gpio this controller connect to. + This xnur-gpio returns to low once the finger leave the touch screen (The + last touch event the touch controller capture). + +Optional properties: +- measure-delay-time: the value of measure delay time. + Before X-axis or Y-axis measurement, the screen need some time before + even potential distribution ready. + This value depends on the touch screen. +- pre-charge-time: the touch screen need some time to precharge. + This value depends on the touch screen. + +Example: + tsc: tsc@02040000 { + compatible = "fsl,imx6ul-tsc"; + reg = <0x02040000 0x4000>, <0x0219c000 0x4000>; + interrupts = , + ; + clocks = <&clks IMX6UL_CLK_IPG>, + <&clks IMX6UL_CLK_ADC2>; + clock-names = "tsc", "adc"; + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_tsc>; + xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; + measure-delay-time = <0xfff>; + pre-charge-time = <0xffff>; + status = "okay"; + }; diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a6d7a4d8dbb77..600dcceff5426 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -479,6 +479,18 @@ config TOUCHSCREEN_MTOUCH To compile this driver as a module, choose M here: the module will be called mtouch. +config TOUCHSCREEN_IMX6UL_TSC + tristate "Freescale i.MX6UL touchscreen controller" + depends on (OF && GPIOLIB) || COMPILE_TEST + help + Say Y here if you have a Freescale i.MX6UL, and want to + use the internal touchscreen controller. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + module will be called imx6ul_tsc. + config TOUCHSCREEN_INEXIO tristate "iNexio serial touchscreens" select SERIO diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index fb27f7e36070a..1b79cc09744af 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_TOUCHSCREEN_EGALAX) += egalax_ts.o obj-$(CONFIG_TOUCHSCREEN_FUJITSU) += fujitsu_ts.o obj-$(CONFIG_TOUCHSCREEN_GOODIX) += goodix.o obj-$(CONFIG_TOUCHSCREEN_ILI210X) += ili210x.o +obj-$(CONFIG_TOUCHSCREEN_IMX6UL_TSC) += imx6ul_tsc.o obj-$(CONFIG_TOUCHSCREEN_INEXIO) += inexio.o obj-$(CONFIG_TOUCHSCREEN_INTEL_MID) += intel-mid-touch.o obj-$(CONFIG_TOUCHSCREEN_IPROC) += bcm_iproc_tsc.o diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c new file mode 100644 index 0000000000000..ff0b75813daa2 --- /dev/null +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -0,0 +1,523 @@ +/* + * Freescale i.MX6UL touchscreen controller driver + * + * Copyright (C) 2015 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* ADC configuration registers field define */ +#define ADC_AIEN (0x1 << 7) +#define ADC_CONV_DISABLE 0x1F +#define ADC_CAL (0x1 << 7) +#define ADC_CALF 0x2 +#define ADC_12BIT_MODE (0x2 << 2) +#define ADC_IPG_CLK 0x00 +#define ADC_CLK_DIV_8 (0x03 << 5) +#define ADC_SHORT_SAMPLE_MODE (0x0 << 4) +#define ADC_HARDWARE_TRIGGER (0x1 << 13) +#define SELECT_CHANNEL_4 0x04 +#define SELECT_CHANNEL_1 0x01 +#define DISABLE_CONVERSION_INT (0x0 << 7) + +/* ADC registers */ +#define REG_ADC_HC0 0x00 +#define REG_ADC_HC1 0x04 +#define REG_ADC_HC2 0x08 +#define REG_ADC_HC3 0x0C +#define REG_ADC_HC4 0x10 +#define REG_ADC_HS 0x14 +#define REG_ADC_R0 0x18 +#define REG_ADC_CFG 0x2C +#define REG_ADC_GC 0x30 +#define REG_ADC_GS 0x34 + +#define ADC_TIMEOUT msecs_to_jiffies(100) + +/* TSC registers */ +#define REG_TSC_BASIC_SETING 0x00 +#define REG_TSC_PRE_CHARGE_TIME 0x10 +#define REG_TSC_FLOW_CONTROL 0x20 +#define REG_TSC_MEASURE_VALUE 0x30 +#define REG_TSC_INT_EN 0x40 +#define REG_TSC_INT_SIG_EN 0x50 +#define REG_TSC_INT_STATUS 0x60 +#define REG_TSC_DEBUG_MODE 0x70 +#define REG_TSC_DEBUG_MODE2 0x80 + +/* TSC configuration registers field define */ +#define DETECT_4_WIRE_MODE (0x0 << 4) +#define AUTO_MEASURE 0x1 +#define MEASURE_SIGNAL 0x1 +#define DETECT_SIGNAL (0x1 << 4) +#define VALID_SIGNAL (0x1 << 8) +#define MEASURE_INT_EN 0x1 +#define MEASURE_SIG_EN 0x1 +#define VALID_SIG_EN (0x1 << 8) +#define DE_GLITCH_2 (0x2 << 29) +#define START_SENSE (0x1 << 12) +#define TSC_DISABLE (0x1 << 16) +#define DETECT_MODE 0x2 + +struct imx6ul_tsc { + struct device *dev; + struct input_dev *input; + void __iomem *tsc_regs; + void __iomem *adc_regs; + struct clk *tsc_clk; + struct clk *adc_clk; + struct gpio_desc *xnur_gpio; + + int measure_delay_time; + int pre_charge_time; + + struct completion completion; +}; + +/* + * TSC module need ADC to get the measure value. So + * before config TSC, we should initialize ADC module. + */ +static void imx6ul_adc_init(struct imx6ul_tsc *tsc) +{ + int adc_hc = 0; + int adc_gc; + int adc_gs; + int adc_cfg; + int timeout; + + reinit_completion(&tsc->completion); + + adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); + adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; + adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; + adc_cfg &= ~ADC_HARDWARE_TRIGGER; + writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); + + /* enable calibration interrupt */ + adc_hc |= ADC_AIEN; + adc_hc |= ADC_CONV_DISABLE; + writel(adc_hc, tsc->adc_regs + REG_ADC_HC0); + + /* start ADC calibration */ + adc_gc = readl(tsc->adc_regs + REG_ADC_GC); + adc_gc |= ADC_CAL; + writel(adc_gc, tsc->adc_regs + REG_ADC_GC); + + timeout = wait_for_completion_timeout + (&tsc->completion, ADC_TIMEOUT); + if (timeout == 0) + dev_err(tsc->dev, "Timeout for adc calibration\n"); + + adc_gs = readl(tsc->adc_regs + REG_ADC_GS); + if (adc_gs & ADC_CALF) + dev_err(tsc->dev, "ADC calibration failed\n"); + + /* TSC need the ADC work in hardware trigger */ + adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); + adc_cfg |= ADC_HARDWARE_TRIGGER; + writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); +} + +/* + * This is a TSC workaround. Currently TSC misconnect two + * ADC channels, this function remap channel configure for + * hardware trigger. + */ +static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) +{ + int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; + + adc_hc0 = DISABLE_CONVERSION_INT; + writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0); + + adc_hc1 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_4; + writel(adc_hc1, tsc->adc_regs + REG_ADC_HC1); + + adc_hc2 = DISABLE_CONVERSION_INT; + writel(adc_hc2, tsc->adc_regs + REG_ADC_HC2); + + adc_hc3 = DISABLE_CONVERSION_INT | SELECT_CHANNEL_1; + writel(adc_hc3, tsc->adc_regs + REG_ADC_HC3); + + adc_hc4 = DISABLE_CONVERSION_INT; + writel(adc_hc4, tsc->adc_regs + REG_ADC_HC4); +} + +/* + * TSC setting, confige the pre-charge time and measure delay time. + * different touch screen may need different pre-charge time and + * measure delay time. + */ +static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) +{ + int basic_setting = 0; + int start; + + basic_setting |= tsc->measure_delay_time << 8; + basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; + writel(basic_setting, tsc->tsc_regs + REG_TSC_BASIC_SETING); + + writel(DE_GLITCH_2, tsc->tsc_regs + REG_TSC_DEBUG_MODE2); + + writel(tsc->pre_charge_time, tsc->tsc_regs + REG_TSC_PRE_CHARGE_TIME); + writel(MEASURE_INT_EN, tsc->tsc_regs + REG_TSC_INT_EN); + writel(MEASURE_SIG_EN | VALID_SIG_EN, + tsc->tsc_regs + REG_TSC_INT_SIG_EN); + + /* start sense detection */ + start = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL); + start |= START_SENSE; + start &= ~TSC_DISABLE; + writel(start, tsc->tsc_regs + REG_TSC_FLOW_CONTROL); +} + +static void imx6ul_tsc_init(struct imx6ul_tsc *tsc) +{ + imx6ul_adc_init(tsc); + imx6ul_tsc_channel_config(tsc); + imx6ul_tsc_set(tsc); +} + +static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) +{ + int tsc_flow; + int adc_cfg; + + /* TSC controller enters to idle status */ + tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL); + tsc_flow |= TSC_DISABLE; + writel(tsc_flow, tsc->tsc_regs + REG_TSC_FLOW_CONTROL); + + /* ADC controller enters to stop mode */ + adc_cfg = readl(tsc->adc_regs + REG_ADC_HC0); + adc_cfg |= ADC_CONV_DISABLE; + writel(adc_cfg, tsc->adc_regs + REG_ADC_HC0); +} + +/* Delay some time (max 2ms), wait the pre-charge done. */ +static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(2); + int state_machine; + int debug_mode2; + + do { + if (time_after(jiffies, timeout)) + return false; + + usleep_range(200, 400); + debug_mode2 = readl(tsc->tsc_regs + REG_TSC_DEBUG_MODE2); + state_machine = (debug_mode2 >> 20) & 0x7; + } while (state_machine != DETECT_MODE); + + usleep_range(200, 400); + return true; +} + +static irqreturn_t tsc_irq_fn(int irq, void *dev_id) +{ + struct imx6ul_tsc *tsc = dev_id; + int status; + int value; + int x, y; + int start; + + status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS); + + /* write 1 to clear the bit measure-signal */ + writel(MEASURE_SIGNAL | DETECT_SIGNAL, + tsc->tsc_regs + REG_TSC_INT_STATUS); + + /* It's a HW self-clean bit. Set this bit and start sense detection */ + start = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL); + start |= START_SENSE; + writel(start, tsc->tsc_regs + REG_TSC_FLOW_CONTROL); + + if (status & MEASURE_SIGNAL) { + value = readl(tsc->tsc_regs + REG_TSC_MEASURE_VALUE); + x = (value >> 16) & 0x0fff; + y = value & 0x0fff; + + /* + * In detect mode, we can get the xnur gpio value, + * otherwise assume contact is stiull active. + */ + if (!tsc_wait_detect_mode(tsc) || + gpiod_get_value_cansleep(tsc->xnur_gpio)) { + input_report_key(tsc->input, BTN_TOUCH, 1); + input_report_abs(tsc->input, ABS_X, x); + input_report_abs(tsc->input, ABS_Y, y); + } else { + input_report_key(tsc->input, BTN_TOUCH, 0); + } + + input_sync(tsc->input); + } + + return IRQ_HANDLED; +} + +static irqreturn_t adc_irq_fn(int irq, void *dev_id) +{ + struct imx6ul_tsc *tsc = dev_id; + int coco; + int value; + + coco = readl(tsc->adc_regs + REG_ADC_HS); + if (coco & 0x01) { + value = readl(tsc->adc_regs + REG_ADC_R0); + complete(&tsc->completion); + } + + return IRQ_HANDLED; +} + +static int imx6ul_tsc_open(struct input_dev *input_dev) +{ + struct imx6ul_tsc *tsc = input_get_drvdata(input_dev); + int err; + + err = clk_prepare_enable(tsc->adc_clk); + if (err) { + dev_err(tsc->dev, + "Could not prepare or enable the adc clock: %d\n", + err); + return err; + } + + err = clk_prepare_enable(tsc->tsc_clk); + if (err) { + dev_err(tsc->dev, + "Could not prepare or enable the tsc clock: %d\n", + err); + clk_disable_unprepare(tsc->adc_clk); + return err; + } + + imx6ul_tsc_init(tsc); + + return 0; +} + +static void imx6ul_tsc_close(struct input_dev *input_dev) +{ + struct imx6ul_tsc *tsc = input_get_drvdata(input_dev); + + imx6ul_tsc_disable(tsc); + + clk_disable_unprepare(tsc->tsc_clk); + clk_disable_unprepare(tsc->adc_clk); +} + +static int imx6ul_tsc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct imx6ul_tsc *tsc; + struct input_dev *input_dev; + struct resource *tsc_mem; + struct resource *adc_mem; + int err; + int tsc_irq; + int adc_irq; + + tsc = devm_kzalloc(&pdev->dev, sizeof(struct imx6ul_tsc), GFP_KERNEL); + if (!tsc) + return -ENOMEM; + + input_dev = devm_input_allocate_device(&pdev->dev); + if (!input_dev) + return -ENOMEM; + + input_dev->name = "iMX6UL TouchScreen Controller"; + input_dev->id.bustype = BUS_HOST; + + input_dev->open = imx6ul_tsc_open; + input_dev->close = imx6ul_tsc_close; + + input_set_capability(input_dev, EV_KEY, BTN_TOUCH); + input_set_abs_params(input_dev, ABS_X, 0, 0xFFF, 0, 0); + input_set_abs_params(input_dev, ABS_Y, 0, 0xFFF, 0, 0); + + input_set_drvdata(input_dev, tsc); + + tsc->dev = &pdev->dev; + tsc->input = input_dev; + init_completion(&tsc->completion); + + tsc->xnur_gpio = devm_gpiod_get(&pdev->dev, "xnur", GPIOD_IN); + if (IS_ERR(tsc->xnur_gpio)) { + err = PTR_ERR(tsc->xnur_gpio); + dev_err(&pdev->dev, + "failed to request GPIO tsc_X- (xnur): %d\n", err); + return err; + } + + tsc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + tsc->tsc_regs = devm_ioremap_resource(&pdev->dev, tsc_mem); + if (IS_ERR(tsc->tsc_regs)) { + err = PTR_ERR(tsc->tsc_regs); + dev_err(&pdev->dev, "failed to remap tsc memory: %d\n", err); + return err; + } + + adc_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + tsc->adc_regs = devm_ioremap_resource(&pdev->dev, adc_mem); + if (IS_ERR(tsc->adc_regs)) { + err = PTR_ERR(tsc->adc_regs); + dev_err(&pdev->dev, "failed to remap adc memory: %d\n", err); + return err; + } + + tsc->tsc_clk = devm_clk_get(&pdev->dev, "tsc"); + if (IS_ERR(tsc->tsc_clk)) { + err = PTR_ERR(tsc->tsc_clk); + dev_err(&pdev->dev, "failed getting tsc clock: %d\n", err); + return err; + } + + tsc->adc_clk = devm_clk_get(&pdev->dev, "adc"); + if (IS_ERR(tsc->adc_clk)) { + err = PTR_ERR(tsc->adc_clk); + dev_err(&pdev->dev, "failed getting adc clock: %d\n", err); + return err; + } + + tsc_irq = platform_get_irq(pdev, 0); + if (tsc_irq < 0) { + dev_err(&pdev->dev, "no tsc irq resource?\n"); + return tsc_irq; + } + + adc_irq = platform_get_irq(pdev, 1); + if (adc_irq <= 0) { + dev_err(&pdev->dev, "no adc irq resource?\n"); + return adc_irq; + } + + err = devm_request_threaded_irq(tsc->dev, tsc_irq, + NULL, tsc_irq_fn, IRQF_ONESHOT, + dev_name(&pdev->dev), tsc); + if (err) { + dev_err(&pdev->dev, + "failed requesting tsc irq %d: %d\n", + tsc_irq, err); + return err; + } + + err = devm_request_irq(tsc->dev, adc_irq, adc_irq_fn, 0, + dev_name(&pdev->dev), tsc); + if (err) { + dev_err(&pdev->dev, + "failed requesting adc irq %d: %d\n", + adc_irq, err); + return err; + } + + err = of_property_read_u32(np, "measure-delay-time", + &tsc->measure_delay_time); + if (err) + tsc->measure_delay_time = 0xffff; + + err = of_property_read_u32(np, "pre-charge-time", + &tsc->pre_charge_time); + if (err) + tsc->pre_charge_time = 0xfff; + + err = input_register_device(tsc->input); + if (err) { + dev_err(&pdev->dev, + "failed to register input device: %d\n", err); + return err; + } + + platform_set_drvdata(pdev, tsc); + return 0; +} + +static int __maybe_unused imx6ul_tsc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx6ul_tsc *tsc = platform_get_drvdata(pdev); + struct input_dev *input_dev = tsc->input; + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + imx6ul_tsc_disable(tsc); + + clk_disable_unprepare(tsc->tsc_clk); + clk_disable_unprepare(tsc->adc_clk); + } + + mutex_unlock(&input_dev->mutex); + + return 0; +} + +static int __maybe_unused imx6ul_tsc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx6ul_tsc *tsc = platform_get_drvdata(pdev); + struct input_dev *input_dev = tsc->input; + int retval = 0; + + mutex_lock(&input_dev->mutex); + + if (input_dev->users) { + retval = clk_prepare_enable(tsc->adc_clk); + if (retval) + goto out; + + retval = clk_prepare_enable(tsc->tsc_clk); + if (retval) { + clk_disable_unprepare(tsc->adc_clk); + goto out; + } + + imx6ul_tsc_init(tsc); + } + +out: + mutex_unlock(&input_dev->mutex); + return retval; +} + +static SIMPLE_DEV_PM_OPS(imx6ul_tsc_pm_ops, + imx6ul_tsc_suspend, imx6ul_tsc_resume); + +static const struct of_device_id imx6ul_tsc_match[] = { + { .compatible = "fsl,imx6ul-tsc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx6ul_tsc_match); + +static struct platform_driver imx6ul_tsc_driver = { + .driver = { + .name = "imx6ul-tsc", + .of_match_table = imx6ul_tsc_match, + .pm = &imx6ul_tsc_pm_ops, + }, + .probe = imx6ul_tsc_probe, +}; +module_platform_driver(imx6ul_tsc_driver); + +MODULE_AUTHOR("Haibo Chen "); +MODULE_DESCRIPTION("Freescale i.MX6UL Touchscreen controller driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From ade9c1a47c811a7ae1c874882ad9178af1ed1098 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 19 Feb 2014 13:38:13 -0800 Subject: [PATCH 6557/7006] Input: imx_keypad - remove obsolete comment Since commit 81e8f2bc (Input: imx_keypad - add pm suspend and resume support) the imx_keypad driver supports power management, so let's remove the obsolete comment. Signed-off-by: Fabio Estevam Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/imx_keypad.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c index d2ea863d6a45f..2165f3dd328ba 100644 --- a/drivers/input/keyboard/imx_keypad.c +++ b/drivers/input/keyboard/imx_keypad.c @@ -5,8 +5,6 @@ * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. - * - * <>. */ #include -- GitLab From c82199061009d1561e31e17fca5e47a87cb7ff4c Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Fri, 28 Aug 2015 19:42:30 -0700 Subject: [PATCH 6558/7006] task_work: remove fifo ordering guarantee MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit f341861fb0b ("task_work: add a scheduling point in task_work_run()") I fixed a latency problem adding a cond_resched() call. Later, commit ac3d0da8f329 added yet another loop to reverse a list, bringing back the latency spike : I've seen in some cases this loop taking 275 ms, if for example a process with 2,000,000 files is killed. We could add yet another cond_resched() in the reverse loop, or we can simply remove the reversal, as I do not think anything would depend on order of task_work_add() submitted works. Fixes: ac3d0da8f329 ("task_work: Make task_work_add() lockless") Signed-off-by: Eric Dumazet Reported-by: Maciej Żenczykowski Acked-by: Al Viro Signed-off-by: Linus Torvalds --- kernel/task_work.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/kernel/task_work.c b/kernel/task_work.c index 8727032e3a6fb..53fa971d000d0 100644 --- a/kernel/task_work.c +++ b/kernel/task_work.c @@ -18,6 +18,8 @@ static struct callback_head work_exited; /* all we need is ->next == NULL */ * This is like the signal handler which runs in kernel mode, but it doesn't * try to wake up the @task. * + * Note: there is no ordering guarantee on works queued here. + * * RETURNS: * 0 if succeeds or -ESRCH. */ @@ -108,16 +110,6 @@ void task_work_run(void) raw_spin_unlock_wait(&task->pi_lock); smp_mb(); - /* Reverse the list to run the works in fifo order */ - head = NULL; - do { - next = work->next; - work->next = head; - head = work; - work = next; - } while (work); - - work = head; do { next = work->next; work->func(work); -- GitLab From 25b4a44c19c83d98e8c0807a7ede07c1f28eab8b Mon Sep 17 00:00:00 2001 From: Richard Laing Date: Thu, 3 Sep 2015 13:52:31 +1200 Subject: [PATCH 6559/7006] net/ipv6: Correct PIM6 mrt_lock handling In the IPv6 multicast routing code the mrt_lock was not being released correctly in the MFC iterator, as a result adding or deleting a MIF would cause a hang because the mrt_lock could not be acquired. This fix is a copy of the code for the IPv4 case and ensures that the lock is released correctly. Signed-off-by: Richard Laing Acked-by: Cong Wang Signed-off-by: David S. Miller --- net/ipv6/ip6mr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 74ceb73c1c9a0..5f36266b1f5ef 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -550,7 +550,7 @@ static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) if (it->cache == &mrt->mfc6_unres_queue) spin_unlock_bh(&mfc_unres_lock); - else if (it->cache == mrt->mfc6_cache_array) + else if (it->cache == &mrt->mfc6_cache_array[it->ct]) read_unlock(&mrt_lock); } -- GitLab From bd516bd1feeb3890502178a74228ec05271f2b6d Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Thu, 3 Sep 2015 11:30:30 +0530 Subject: [PATCH 6560/7006] net: wan: sbni: fix device usage count dev_get_by_name() will increment the usage count if the matching device is found. But we were not decrementing the count if we have got the device and the device is non-active. Signed-off-by: Sudip Mukherjee Signed-off-by: David S. Miller --- drivers/net/wan/sbni.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 758c4ba1e97c9..8fef8d83436dd 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -1358,6 +1358,8 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) if( !slave_dev || !(slave_dev->flags & IFF_UP) ) { netdev_err(dev, "trying to enslave non-active device %s\n", slave_name); + if (slave_dev) + dev_put(slave_dev); return -EPERM; } -- GitLab From b65888796b72b677928527b17eeb8e935b767146 Mon Sep 17 00:00:00 2001 From: Sathya Perla Date: Thu, 3 Sep 2015 07:41:53 -0400 Subject: [PATCH 6561/7006] be2net: Revert "make the RX_FILTER command asynchronous" commit The be_cmd_rx_filter() routine sends a non-embedded cmd to the FW and used a pre-allocated dma memory to hold the cmd payload. This worked fine when this cmd was synchronous. This cmd was changed to asynchronous mode by the commit 8af65c2f4("make the RX_FILTER command asynchronous"). So now when there are two quick invocations of this cmd, the 2nd request may end up overwriting the first request, causing FW cmd corruption. This patch reverts the offending commit and hence fixes the regression. Fixes: 8af65c2f4("be2net: make the RX_FILTER command asynchronous") Signed-off-by: Sathya Perla Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be_cmds.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 3be1fbdcdd021..eb323913cd39f 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1968,7 +1968,7 @@ static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); } - status = be_mcc_notify(adapter); + status = be_mcc_notify_wait(adapter); err: spin_unlock_bh(&adapter->mcc_lock); return status; -- GitLab From 0890cf6cb6ab1af650025670b1a839671a9a3fcb Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 3 Sep 2015 14:04:17 +0200 Subject: [PATCH 6562/7006] switchdev: fix return value of switchdev_port_fdb_dump in case of error switchdev_port_fdb_dump is used as .ndo_fdb_dump. Its return value is idx, so we cannot return errval. Fixes: 45d4122ca7cd ("switchdev: add support for fdb add/del/dump via switchdev_port_obj ops.") Signed-off-by: Jiri Pirko Acked-by: Sridhar Samudrala Acked-by: Scott Feldman Signed-off-by: David S. Miller --- net/switchdev/switchdev.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 16c1c43980a12..fda38f830a108 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c @@ -853,12 +853,8 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, .cb = cb, .idx = idx, }; - int err; - - err = switchdev_port_obj_dump(dev, &dump.obj); - if (err) - return err; + switchdev_port_obj_dump(dev, &dump.obj); return dump.idx; } EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); -- GitLab From 42ea4457aea7aaeddf0c0b06724f297608f5e9d2 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Thu, 3 Sep 2015 21:38:30 +0200 Subject: [PATCH 6563/7006] net: fec: normalize return value of pm_runtime_get_sync() in MDIO write If fec MDIO write method succeeds its return value comes from call to pm_runtime_get_sync(). But pm_runtime_get_sync() can also return 1. In case of Micrel KSZ9031 PHY this value will then be returned along the call chain of phy_write() -> ksz9031_extended_write() -> ksz9031_center_flp_timing() -> ksz9031_config_init() -> phy_init_hw() -> phy_attach_direct() -> phy_connect_direct(). Then phy_connect() will cast it into a pointer using ERR_PTR(), which then fec_enet_mii_probe() will try to dereference resulting in an oops. Fix it by normalizing return value of pm_runtime_get_sync() to be zero if positive in MDIO write method. Fixes: 8fff755e9f8d ("net: fec: Ensure clocks are enabled while using mdio bus") Signed-off-by: Maciej Szmigiero Acked-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 91925e38705eb..6cc334035e073 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -1816,11 +1816,13 @@ static int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, struct fec_enet_private *fep = bus->priv; struct device *dev = &fep->pdev->dev; unsigned long time_left; - int ret = 0; + int ret; ret = pm_runtime_get_sync(dev); if (ret < 0) return ret; + else + ret = 0; fep->mii_timeout = 0; reinit_completion(&fep->mdio_done); -- GitLab From 8f384c0177a03640312b9cb3638c998b32243b63 Mon Sep 17 00:00:00 2001 From: Sowmini Varadhan Date: Thu, 3 Sep 2015 16:24:52 -0400 Subject: [PATCH 6564/7006] RDS: rds_conn_lookup() should factor in the struct net for a match Only return a conn if the rds_conn_net(conn) matches the struct net passed to rds_conn_lookup(). Fixes: 467fa15356ac ("RDS-TCP: Support multiple RDS-TCP listen endpoints, one per netns.") Signed-off-by: Sowmini Varadhan Acked-by: Santosh Shilimkar Signed-off-by: David S. Miller --- net/rds/connection.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/net/rds/connection.c b/net/rds/connection.c index a50e652eb269d..9b2de5e67d795 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -70,7 +70,8 @@ static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr) } while (0) /* rcu read lock must be held or the connection spinlock */ -static struct rds_connection *rds_conn_lookup(struct hlist_head *head, +static struct rds_connection *rds_conn_lookup(struct net *net, + struct hlist_head *head, __be32 laddr, __be32 faddr, struct rds_transport *trans) { @@ -78,7 +79,7 @@ static struct rds_connection *rds_conn_lookup(struct hlist_head *head, hlist_for_each_entry_rcu(conn, head, c_hash_node) { if (conn->c_faddr == faddr && conn->c_laddr == laddr && - conn->c_trans == trans) { + conn->c_trans == trans && net == rds_conn_net(conn)) { ret = conn; break; } @@ -132,7 +133,7 @@ static struct rds_connection *__rds_conn_create(struct net *net, if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP) goto new_conn; rcu_read_lock(); - conn = rds_conn_lookup(head, laddr, faddr, trans); + conn = rds_conn_lookup(net, head, laddr, faddr, trans); if (conn && conn->c_loopback && conn->c_trans != &rds_loop_transport && laddr == faddr && !is_outgoing) { /* This is a looped back IB connection, and we're @@ -239,7 +240,7 @@ new_conn: if (!is_outgoing && otrans->t_type == RDS_TRANS_TCP) found = NULL; else - found = rds_conn_lookup(head, laddr, faddr, trans); + found = rds_conn_lookup(net, head, laddr, faddr, trans); if (found) { trans->conn_free(conn->c_transport_data); kmem_cache_free(rds_conn_slab, conn); -- GitLab From 29ecd66019047768080e8eeab4cd6582b28383a2 Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Sun, 6 Sep 2015 16:24:50 +0200 Subject: [PATCH 6565/7006] KVM: x86: avoid uninitialized variable warning This does not show up on all compiler versions, so it sneaked into the first 4.3 pull request. The fix is to mimic the logic of the "print sptes" loop in the "fill array" loop. Then leaf and root can be both initialized unconditionally. Note that "leaf" now points to the first unused element of the array, not the last filled element. Reported-by: Linus Torvalds Signed-off-by: Paolo Bonzini --- arch/x86/kvm/mmu.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index fb16a8ea3dee0..69088a1ba5090 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c @@ -3309,13 +3309,14 @@ walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep) walk_shadow_page_lockless_begin(vcpu); - for (shadow_walk_init(&iterator, vcpu, addr), root = iterator.level; + for (shadow_walk_init(&iterator, vcpu, addr), + leaf = root = iterator.level; shadow_walk_okay(&iterator); __shadow_walk_next(&iterator, spte)) { - leaf = iterator.level; spte = mmu_spte_get_lockless(iterator.sptep); sptes[leaf - 1] = spte; + leaf--; if (!is_shadow_present_pte(spte)) break; @@ -3329,7 +3330,7 @@ walk_shadow_page_get_mmio_spte(struct kvm_vcpu *vcpu, u64 addr, u64 *sptep) if (reserved) { pr_err("%s: detect reserved bits on spte, addr 0x%llx, dump hierarchy:\n", __func__, addr); - while (root >= leaf) { + while (root > leaf) { pr_err("------ spte 0x%llx level %d.\n", sptes[root - 1], root); root--; -- GitLab From efbb288afc2f3079fa5e9308f4d9d06a390babdc Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Sun, 6 Sep 2015 19:35:41 +0600 Subject: [PATCH 6566/7006] kvm: compile process_smi_save_seg_64() only for x86_64 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The process_smi_save_seg_64() function called only in the process_smi_save_state_64() if the CONFIG_X86_64 is set. This patch adds #ifdef CONFIG_X86_64 around process_smi_save_seg_64() to prevent following warning message: arch/x86/kvm/x86.c:5946:13: warning: ‘process_smi_save_seg_64’ defined but not used [-Wunused-function] static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n) ^ Signed-off-by: Alexander Kuleshov Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index c7b6aed998e9d..13728dbdbb560 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -5955,6 +5955,7 @@ static void process_smi_save_seg_32(struct kvm_vcpu *vcpu, char *buf, int n) put_smstate(u32, buf, offset, process_smi_get_segment_flags(&seg)); } +#ifdef CONFIG_X86_64 static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n) { struct kvm_segment seg; @@ -5970,6 +5971,7 @@ static void process_smi_save_seg_64(struct kvm_vcpu *vcpu, char *buf, int n) put_smstate(u32, buf, offset + 4, seg.limit); put_smstate(u64, buf, offset + 8, seg.base); } +#endif static void process_smi_save_state_32(struct kvm_vcpu *vcpu, char *buf) { -- GitLab From e8dd2d2d641cb2724ee10e76c0ad02e04289c017 Mon Sep 17 00:00:00 2001 From: Valdis Kletnieks Date: Sat, 29 Aug 2015 17:49:16 -0400 Subject: [PATCH 6567/7006] Silence compiler warning in arch/x86/kvm/emulate.c Compiler warning: CC [M] arch/x86/kvm/emulate.o arch/x86/kvm/emulate.c: In function "__do_insn_fetch_bytes": arch/x86/kvm/emulate.c:814:9: warning: "linear" may be used uninitialized in this function [-Wmaybe-uninitialized] GCC is smart enough to realize that the inlined __linearize may return before setting the value of linear, but not smart enough to realize the same X86EMU_CONTINUE blocks actual use of the value. However, the value of 'linear' can only be set to one value, so hoisting the one line of code upwards makes GCC happy with the code. Reported-by: Aruna Hewapathirane Tested-by: Aruna Hewapathirane Signed-off-by: Valdis Kletnieks Signed-off-by: Paolo Bonzini --- arch/x86/kvm/emulate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c index e7a4fde5d6310..b372a7557c16c 100644 --- a/arch/x86/kvm/emulate.c +++ b/arch/x86/kvm/emulate.c @@ -650,6 +650,7 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, u16 sel; la = seg_base(ctxt, addr.seg) + addr.ea; + *linear = la; *max_size = 0; switch (mode) { case X86EMUL_MODE_PROT64: @@ -693,7 +694,6 @@ static __always_inline int __linearize(struct x86_emulate_ctxt *ctxt, } if (insn_aligned(ctxt, size) && ((la & (size - 1)) != 0)) return emulate_gp(ctxt, 0); - *linear = la; return X86EMUL_CONTINUE; bad: if (addr.seg == VCPU_SREG_SS) -- GitLab From 19020f8ab83de9dc5a9c8af1f321a526f38bbc40 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Thu, 3 Sep 2015 22:07:37 +0800 Subject: [PATCH 6568/7006] KVM: make halt_poll_ns per-vCPU Change halt_poll_ns into per-VCPU variable, seeded from module parameter, to allow greater flexibility. Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini --- include/linux/kvm_host.h | 1 + virt/kvm/kvm_main.c | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index 81089cf1f0c11..1bef9e21e7259 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -242,6 +242,7 @@ struct kvm_vcpu { int sigset_active; sigset_t sigset; struct kvm_vcpu_stat stat; + unsigned int halt_poll_ns; #ifdef CONFIG_HAS_IOMEM int mmio_needed; diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d8db2f8fce9c7..c06e57cd12696 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -217,6 +217,7 @@ int kvm_vcpu_init(struct kvm_vcpu *vcpu, struct kvm *kvm, unsigned id) vcpu->kvm = kvm; vcpu->vcpu_id = id; vcpu->pid = NULL; + vcpu->halt_poll_ns = 0; init_waitqueue_head(&vcpu->wq); kvm_async_pf_vcpu_init(vcpu); @@ -1930,8 +1931,8 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) bool waited = false; start = cur = ktime_get(); - if (halt_poll_ns) { - ktime_t stop = ktime_add_ns(ktime_get(), halt_poll_ns); + if (vcpu->halt_poll_ns) { + ktime_t stop = ktime_add_ns(ktime_get(), vcpu->halt_poll_ns); do { /* -- GitLab From aca6ff29c4063a8d467cdee241e6b3bf7dc4a171 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Thu, 3 Sep 2015 22:07:38 +0800 Subject: [PATCH 6569/7006] KVM: dynamic halt-polling There is a downside of always-poll since poll is still happened for idle vCPUs which can waste cpu usage. This patchset add the ability to adjust halt_poll_ns dynamically, to grow halt_poll_ns when shot halt is detected, and to shrink halt_poll_ns when long halt is detected. There are two new kernel parameters for changing the halt_poll_ns: halt_poll_ns_grow and halt_poll_ns_shrink. no-poll always-poll dynamic-poll ----------------------------------------------------------------------- Idle (nohz) vCPU %c0 0.15% 0.3% 0.2% Idle (250HZ) vCPU %c0 1.1% 4.6%~14% 1.2% TCP_RR latency 34us 27us 26.7us "Idle (X) vCPU %c0" is the percent of time the physical cpu spent in c0 over 60 seconds (each vCPU is pinned to a pCPU). (nohz) means the guest was tickless. (250HZ) means the guest was ticking at 250HZ. The big win is with ticking operating systems. Running the linux guest with nohz=off (and HZ=250), we save 3.4%~12.8% CPUs/second and get close to no-polling overhead levels by using the dynamic-poll. The savings should be even higher for higher frequency ticks. Suggested-by: David Matlack Signed-off-by: Wanpeng Li [Simplify the patch. - Paolo] Signed-off-by: Paolo Bonzini --- virt/kvm/kvm_main.c | 53 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index c06e57cd12696..8ab49cfc024ea 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -66,9 +66,18 @@ MODULE_AUTHOR("Qumranet"); MODULE_LICENSE("GPL"); -static unsigned int halt_poll_ns; +/* halt polling only reduces halt latency by 5-7 us, 500us is enough */ +static unsigned int halt_poll_ns = 500000; module_param(halt_poll_ns, uint, S_IRUGO | S_IWUSR); +/* Default doubles per-vcpu halt_poll_ns. */ +static unsigned int halt_poll_ns_grow = 2; +module_param(halt_poll_ns_grow, int, S_IRUGO); + +/* Default resets per-vcpu halt_poll_ns . */ +static unsigned int halt_poll_ns_shrink; +module_param(halt_poll_ns_shrink, int, S_IRUGO); + /* * Ordering of locks: * @@ -1907,6 +1916,31 @@ void kvm_vcpu_mark_page_dirty(struct kvm_vcpu *vcpu, gfn_t gfn) } EXPORT_SYMBOL_GPL(kvm_vcpu_mark_page_dirty); +static void grow_halt_poll_ns(struct kvm_vcpu *vcpu) +{ + int val = vcpu->halt_poll_ns; + + /* 10us base */ + if (val == 0 && halt_poll_ns_grow) + val = 10000; + else + val *= halt_poll_ns_grow; + + vcpu->halt_poll_ns = val; +} + +static void shrink_halt_poll_ns(struct kvm_vcpu *vcpu) +{ + int val = vcpu->halt_poll_ns; + + if (halt_poll_ns_shrink == 0) + val = 0; + else + val /= halt_poll_ns_shrink; + + vcpu->halt_poll_ns = val; +} + static int kvm_vcpu_check_block(struct kvm_vcpu *vcpu) { if (kvm_arch_vcpu_runnable(vcpu)) { @@ -1929,6 +1963,7 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) ktime_t start, cur; DEFINE_WAIT(wait); bool waited = false; + u64 block_ns; start = cur = ktime_get(); if (vcpu->halt_poll_ns) { @@ -1961,7 +1996,21 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) cur = ktime_get(); out: - trace_kvm_vcpu_wakeup(ktime_to_ns(cur) - ktime_to_ns(start), waited); + block_ns = ktime_to_ns(cur) - ktime_to_ns(start); + + if (halt_poll_ns) { + if (block_ns <= vcpu->halt_poll_ns) + ; + /* we had a long block, shrink polling */ + else if (vcpu->halt_poll_ns && block_ns > halt_poll_ns) + shrink_halt_poll_ns(vcpu); + /* we had a short halt and our poll time is too small */ + else if (vcpu->halt_poll_ns < halt_poll_ns && + block_ns < halt_poll_ns) + grow_halt_poll_ns(vcpu); + } + + trace_kvm_vcpu_wakeup(block_ns, waited); } EXPORT_SYMBOL_GPL(kvm_vcpu_block); -- GitLab From 2cbd78244fb26a06f2b8fb006b32f133451df413 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Thu, 3 Sep 2015 22:07:39 +0800 Subject: [PATCH 6570/7006] KVM: trace kvm_halt_poll_ns grow/shrink Tracepoint for dynamic halt_pool_ns, fired on every potential change. Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini --- include/trace/events/kvm.h | 30 ++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 8 ++++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index a44062da684b5..0d1bc478833b9 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h @@ -356,6 +356,36 @@ TRACE_EVENT( __entry->address) ); +TRACE_EVENT(kvm_halt_poll_ns, + TP_PROTO(bool grow, unsigned int vcpu_id, int new, int old), + TP_ARGS(grow, vcpu_id, new, old), + + TP_STRUCT__entry( + __field(bool, grow) + __field(unsigned int, vcpu_id) + __field(int, new) + __field(int, old) + ), + + TP_fast_assign( + __entry->grow = grow; + __entry->vcpu_id = vcpu_id; + __entry->new = new; + __entry->old = old; + ), + + TP_printk("vcpu %u: halt_poll_ns %d (%s %d)", + __entry->vcpu_id, + __entry->new, + __entry->grow ? "grow" : "shrink", + __entry->old) +); + +#define trace_kvm_halt_poll_ns_grow(vcpu_id, new, old) \ + trace_kvm_halt_poll_ns(true, vcpu_id, new, old) +#define trace_kvm_halt_poll_ns_shrink(vcpu_id, new, old) \ + trace_kvm_halt_poll_ns(false, vcpu_id, new, old) + #endif #endif /* _TRACE_KVM_MAIN_H */ diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index 8ab49cfc024ea..4662a8877f6c7 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -1918,8 +1918,9 @@ EXPORT_SYMBOL_GPL(kvm_vcpu_mark_page_dirty); static void grow_halt_poll_ns(struct kvm_vcpu *vcpu) { - int val = vcpu->halt_poll_ns; + int old, val; + old = val = vcpu->halt_poll_ns; /* 10us base */ if (val == 0 && halt_poll_ns_grow) val = 10000; @@ -1927,18 +1928,21 @@ static void grow_halt_poll_ns(struct kvm_vcpu *vcpu) val *= halt_poll_ns_grow; vcpu->halt_poll_ns = val; + trace_kvm_halt_poll_ns_grow(vcpu->vcpu_id, val, old); } static void shrink_halt_poll_ns(struct kvm_vcpu *vcpu) { - int val = vcpu->halt_poll_ns; + int old, val; + old = val = vcpu->halt_poll_ns; if (halt_poll_ns_shrink == 0) val = 0; else val /= halt_poll_ns_shrink; vcpu->halt_poll_ns = val; + trace_kvm_halt_poll_ns_shrink(vcpu->vcpu_id, val, old); } static int kvm_vcpu_check_block(struct kvm_vcpu *vcpu) -- GitLab From d224fe0d609734888af63656ddaf3a8352f0a7b5 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Thu, 13 Aug 2015 18:48:09 -0700 Subject: [PATCH 6571/7006] mpt2sas: Refcount sas_device objects and fix unsafe list usage These objects can be referenced concurrently throughout the driver, we need a way to make sure threads can't delete them out from under each other. This patch adds the refcount, and refactors the code to use it. Additionally, we cannot iterate over the sas_device_list without holding the lock, or we risk corrupting random memory if items are added or deleted as we iterate. This patch refactors _scsih_probe_sas() to use the sas_device_list in a safe way. Signed-off-by: Calvin Owens Reviewed-by: Christoph Hellwig Reviewed-by: Nicholas Bellinger Tested-by: Chaitra Basappa Acked-by: Sreekanth Reddy Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.h | 22 +- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 480 ++++++++++++++++------- drivers/scsi/mpt2sas/mpt2sas_transport.c | 12 +- 3 files changed, 360 insertions(+), 154 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index caff8d10cca42..78f41aca9598c 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -238,6 +238,7 @@ * @flags: MPT_TARGET_FLAGS_XXX flags * @deleted: target flaged for deletion * @tm_busy: target is busy with TM request. + * @sdev: The sas_device associated with this target */ struct MPT2SAS_TARGET { struct scsi_target *starget; @@ -248,6 +249,7 @@ struct MPT2SAS_TARGET { u32 flags; u8 deleted; u8 tm_busy; + struct _sas_device *sdev; }; @@ -376,8 +378,24 @@ struct _sas_device { u8 phy; u8 responding; u8 pfa_led_on; + struct kref refcount; }; +static inline void sas_device_get(struct _sas_device *s) +{ + kref_get(&s->refcount); +} + +static inline void sas_device_free(struct kref *r) +{ + kfree(container_of(r, struct _sas_device, refcount)); +} + +static inline void sas_device_put(struct _sas_device *s) +{ + kref_put(&s->refcount, sas_device_free); +} + /** * struct _raid_device - raid volume link list * @list: sas device list @@ -1095,7 +1113,9 @@ struct _sas_node *mpt2sas_scsih_expander_find_by_handle(struct MPT2SAS_ADAPTER * u16 handle); struct _sas_node *mpt2sas_scsih_expander_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, u64 sas_address); -struct _sas_device *mpt2sas_scsih_sas_device_find_by_sas_address( +struct _sas_device *mpt2sas_get_sdev_by_addr( + struct MPT2SAS_ADAPTER *ioc, u64 sas_address); +struct _sas_device *__mpt2sas_get_sdev_by_addr( struct MPT2SAS_ADAPTER *ioc, u64 sas_address); void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 3f26147bbc646..5eca3a4a9a7a5 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -526,8 +526,61 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, } } +static struct _sas_device * +__mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc, + struct MPT2SAS_TARGET *tgt_priv) +{ + struct _sas_device *ret; + + assert_spin_locked(&ioc->sas_device_lock); + + ret = tgt_priv->sdev; + if (ret) + sas_device_get(ret); + + return ret; +} + +static struct _sas_device * +mpt2sas_get_sdev_from_target(struct MPT2SAS_ADAPTER *ioc, + struct MPT2SAS_TARGET *tgt_priv) +{ + struct _sas_device *ret; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + ret = __mpt2sas_get_sdev_from_target(ioc, tgt_priv); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return ret; +} + + +struct _sas_device * +__mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc, + u64 sas_address) +{ + struct _sas_device *sas_device; + + assert_spin_locked(&ioc->sas_device_lock); + + list_for_each_entry(sas_device, &ioc->sas_device_list, list) + if (sas_device->sas_address == sas_address) + goto found_device; + + list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) + if (sas_device->sas_address == sas_address) + goto found_device; + + return NULL; + +found_device: + sas_device_get(sas_device); + return sas_device; +} + /** - * mpt2sas_scsih_sas_device_find_by_sas_address - sas device search + * mpt2sas_get_sdev_by_addr - sas device search * @ioc: per adapter object * @sas_address: sas address * Context: Calling function should acquire ioc->sas_device_lock @@ -536,24 +589,44 @@ _scsih_determine_boot_device(struct MPT2SAS_ADAPTER *ioc, * object. */ struct _sas_device * -mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, +mpt2sas_get_sdev_by_addr(struct MPT2SAS_ADAPTER *ioc, u64 sas_address) +{ + struct _sas_device *sas_device; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt2sas_get_sdev_by_addr(ioc, + sas_address); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return sas_device; +} + +static struct _sas_device * +__mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) { struct _sas_device *sas_device; + assert_spin_locked(&ioc->sas_device_lock); + list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; + if (sas_device->handle == handle) + goto found_device; list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->sas_address == sas_address) - return sas_device; + if (sas_device->handle == handle) + goto found_device; return NULL; + +found_device: + sas_device_get(sas_device); + return sas_device; } /** - * _scsih_sas_device_find_by_handle - sas device search + * mpt2sas_get_sdev_by_handle - sas device search * @ioc: per adapter object * @handle: sas device handle (assigned by firmware) * Context: Calling function should acquire ioc->sas_device_lock @@ -562,19 +635,16 @@ mpt2sas_scsih_sas_device_find_by_sas_address(struct MPT2SAS_ADAPTER *ioc, * object. */ static struct _sas_device * -_scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) +mpt2sas_get_sdev_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) { struct _sas_device *sas_device; + unsigned long flags; - list_for_each_entry(sas_device, &ioc->sas_device_list, list) - if (sas_device->handle == handle) - return sas_device; - - list_for_each_entry(sas_device, &ioc->sas_device_init_list, list) - if (sas_device->handle == handle) - return sas_device; + spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return NULL; + return sas_device; } /** @@ -583,7 +653,7 @@ _scsih_sas_device_find_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) * @sas_device: the sas_device object * Context: This function will acquire ioc->sas_device_lock. * - * Removing object and freeing associated memory from the ioc->sas_device_list. + * If sas_device is on the list, remove it and decrement its reference count. */ static void _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, @@ -594,9 +664,15 @@ _scsih_sas_device_remove(struct MPT2SAS_ADAPTER *ioc, if (!sas_device) return; + /* + * The lock serializes access to the list, but we still need to verify + * that nobody removed the entry while we were waiting on the lock. + */ spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_del(&sas_device->list); - kfree(sas_device); + if (!list_empty(&sas_device->list)) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -620,6 +696,7 @@ _scsih_sas_device_add(struct MPT2SAS_ADAPTER *ioc, sas_device->handle, (unsigned long long)sas_device->sas_address)); spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device_get(sas_device); list_add_tail(&sas_device->list, &ioc->sas_device_list); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -659,6 +736,7 @@ _scsih_sas_device_init_add(struct MPT2SAS_ADAPTER *ioc, sas_device->handle, (unsigned long long)sas_device->sas_address)); spin_lock_irqsave(&ioc->sas_device_lock, flags); + sas_device_get(sas_device); list_add_tail(&sas_device->list, &ioc->sas_device_init_list); _scsih_determine_boot_device(ioc, sas_device, 0); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -1208,12 +1286,15 @@ _scsih_change_queue_depth(struct scsi_device *sdev, int qdepth) goto not_sata; if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) goto not_sata; + spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_device_priv_data->sas_target->sas_address); - if (sas_device && sas_device->device_info & - MPI2_SAS_DEVICE_INFO_SATA_DEVICE) - max_depth = MPT2SAS_SATA_QUEUE_DEPTH; + sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); + if (sas_device) { + if (sas_device->device_info & MPI2_SAS_DEVICE_INFO_SATA_DEVICE) + max_depth = MPT2SAS_SATA_QUEUE_DEPTH; + + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); not_sata: @@ -1271,18 +1352,20 @@ _scsih_target_alloc(struct scsi_target *starget) /* sas/sata devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); if (sas_device) { sas_target_priv_data->handle = sas_device->handle; sas_target_priv_data->sas_address = sas_device->sas_address; + sas_target_priv_data->sdev = sas_device; sas_device->starget = starget; sas_device->id = starget->id; sas_device->channel = starget->channel; if (test_bit(sas_device->handle, ioc->pd_handles)) sas_target_priv_data->flags |= MPT_TARGET_FLAGS_RAID_COMPONENT; + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -1324,13 +1407,21 @@ _scsih_target_destroy(struct scsi_target *starget) spin_lock_irqsave(&ioc->sas_device_lock, flags); rphy = dev_to_rphy(starget->dev.parent); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - rphy->identify.sas_address); + sas_device = __mpt2sas_get_sdev_from_target(ioc, sas_target_priv_data); if (sas_device && (sas_device->starget == starget) && (sas_device->id == starget->id) && (sas_device->channel == starget->channel)) sas_device->starget = NULL; + if (sas_device) { + /* + * Corresponding get() is in _scsih_target_alloc() + */ + sas_target_priv_data->sdev = NULL; + sas_device_put(sas_device); + + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); out: @@ -1386,7 +1477,7 @@ _scsih_slave_alloc(struct scsi_device *sdev) if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_target_priv_data->sas_address); if (sas_device && (sas_device->starget == NULL)) { sdev_printk(KERN_INFO, sdev, @@ -1394,6 +1485,10 @@ _scsih_slave_alloc(struct scsi_device *sdev) __func__, __LINE__); sas_device->starget = starget; } + + if (sas_device) + sas_device_put(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -1428,10 +1523,13 @@ _scsih_slave_destroy(struct scsi_device *sdev) if (!(sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME)) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_target_priv_data->sas_address); + sas_device = __mpt2sas_get_sdev_from_target(ioc, + sas_target_priv_data); if (sas_device && !sas_target_priv_data->num_luns) sas_device->starget = NULL; + + if (sas_device) + sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -2078,7 +2176,7 @@ _scsih_slave_configure(struct scsi_device *sdev) } spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_device_priv_data->sas_target->sas_address); if (!sas_device) { spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -2112,17 +2210,18 @@ _scsih_slave_configure(struct scsi_device *sdev) (unsigned long long) sas_device->enclosure_logical_id, sas_device->slot); + sas_device_put(sas_device); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); if (!ssp_target) _scsih_display_sata_capabilities(ioc, handle, sdev); - _scsih_change_queue_depth(sdev, qdepth); if (ssp_target) { sas_read_port_mode_page(sdev); _scsih_enable_tlr(ioc, sdev); } + return 0; } @@ -2509,8 +2608,7 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) device_str, (unsigned long long)priv_target->sas_address); } else { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); + sas_device = __mpt2sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { if (priv_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { @@ -2529,6 +2627,8 @@ _scsih_tm_display_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd) "enclosure_logical_id(0x%016llx), slot(%d)\n", (unsigned long long)sas_device->enclosure_logical_id, sas_device->slot); + + sas_device_put(sas_device); } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } @@ -2604,12 +2704,12 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; + struct _sas_device *sas_device = NULL; u16 handle; int r; struct scsi_target *starget = scmd->device->sdev_target; + struct MPT2SAS_TARGET *target_priv_data = starget->hostdata; starget_printk(KERN_INFO, starget, "attempting device reset! " "scmd(%p)\n", scmd); @@ -2629,12 +2729,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) handle = 0; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - sas_device_priv_data->sas_target->handle); + sas_device = mpt2sas_get_sdev_from_target(ioc, + target_priv_data); if (sas_device) handle = sas_device->volume_handle; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } else handle = sas_device_priv_data->sas_target->handle; @@ -2651,6 +2749,10 @@ _scsih_dev_reset(struct scsi_cmnd *scmd) out: sdev_printk(KERN_INFO, scmd->device, "device reset: %s scmd(%p)\n", ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + if (sas_device) + sas_device_put(sas_device); + return r; } @@ -2665,11 +2767,11 @@ _scsih_target_reset(struct scsi_cmnd *scmd) { struct MPT2SAS_ADAPTER *ioc = shost_priv(scmd->device->host); struct MPT2SAS_DEVICE *sas_device_priv_data; - struct _sas_device *sas_device; - unsigned long flags; + struct _sas_device *sas_device = NULL; u16 handle; int r; struct scsi_target *starget = scmd->device->sdev_target; + struct MPT2SAS_TARGET *target_priv_data = starget->hostdata; starget_printk(KERN_INFO, starget, "attempting target reset! " "scmd(%p)\n", scmd); @@ -2689,12 +2791,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd) handle = 0; if (sas_device_priv_data->sas_target->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, - sas_device_priv_data->sas_target->handle); + sas_device = mpt2sas_get_sdev_from_target(ioc, + target_priv_data); if (sas_device) handle = sas_device->volume_handle; - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } else handle = sas_device_priv_data->sas_target->handle; @@ -2711,6 +2811,10 @@ _scsih_target_reset(struct scsi_cmnd *scmd) out: starget_printk(KERN_INFO, starget, "target reset: %s scmd(%p)\n", ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd); + + if (sas_device) + sas_device_put(sas_device); + return r; } @@ -3002,15 +3106,15 @@ _scsih_block_io_to_children_attached_to_ex(struct MPT2SAS_ADAPTER *ioc, list_for_each_entry(mpt2sas_port, &sas_expander->sas_port_list, port_list) { - if (mpt2sas_port->remote_identify.device_type == - SAS_END_DEVICE) { + if (mpt2sas_port->remote_identify.device_type == SAS_END_DEVICE) { spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = - mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - mpt2sas_port->remote_identify.sas_address); - if (sas_device) + sas_device = __mpt2sas_get_sdev_by_addr(ioc, + mpt2sas_port->remote_identify.sas_address); + if (sas_device) { set_bit(sas_device->handle, - ioc->blocking_handles); + ioc->blocking_handles); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } } @@ -3080,7 +3184,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) { Mpi2SCSITaskManagementRequest_t *mpi_request; u16 smid; - struct _sas_device *sas_device; + struct _sas_device *sas_device = NULL; struct MPT2SAS_TARGET *sas_target_priv_data = NULL; u64 sas_address = 0; unsigned long flags; @@ -3110,7 +3214,7 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); if (sas_device && sas_device->starget && sas_device->starget->hostdata) { sas_target_priv_data = sas_device->starget->hostdata; @@ -3131,14 +3235,14 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) if (!smid) { delayed_tr = kzalloc(sizeof(*delayed_tr), GFP_ATOMIC); if (!delayed_tr) - return; + goto out; INIT_LIST_HEAD(&delayed_tr->list); delayed_tr->handle = handle; list_add_tail(&delayed_tr->list, &ioc->delayed_tr_list); dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "DELAYED:tr:handle(0x%04x), (open)\n", ioc->name, handle)); - return; + goto out; } dewtprintk(ioc, printk(MPT2SAS_INFO_FMT "tr_send:handle(0x%04x), " @@ -3150,6 +3254,9 @@ _scsih_tm_tr_send(struct MPT2SAS_ADAPTER *ioc, u16 handle) mpi_request->DevHandle = cpu_to_le16(handle); mpi_request->TaskType = MPI2_SCSITASKMGMT_TASKTYPE_TARGET_RESET; mpt2sas_base_put_smid_hi_priority(ioc, smid); +out: + if (sas_device) + sas_device_put(sas_device); } @@ -4068,7 +4175,6 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, char *desc_scsi_state = ioc->tmp_string; u32 log_info = le32_to_cpu(mpi_reply->IOCLogInfo); struct _sas_device *sas_device = NULL; - unsigned long flags; struct scsi_target *starget = scmd->device->sdev_target; struct MPT2SAS_TARGET *priv_target = starget->hostdata; char *device_str = NULL; @@ -4200,9 +4306,7 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, printk(MPT2SAS_WARN_FMT "\t%s wwid(0x%016llx)\n", ioc->name, device_str, (unsigned long long)priv_target->sas_address); } else { - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - priv_target->sas_address); + sas_device = mpt2sas_get_sdev_from_target(ioc, priv_target); if (sas_device) { printk(MPT2SAS_WARN_FMT "\tsas_address(0x%016llx), " "phy(%d)\n", ioc->name, sas_device->sas_address, @@ -4211,8 +4315,9 @@ _scsih_scsi_ioc_info(struct MPT2SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, "\tenclosure_logical_id(0x%016llx), slot(%d)\n", ioc->name, sas_device->enclosure_logical_id, sas_device->slot); + + sas_device_put(sas_device); } - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); } printk(MPT2SAS_WARN_FMT "\thandle(0x%04x), ioc_status(%s)(0x%04x), " @@ -4259,7 +4364,7 @@ _scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) Mpi2SepRequest_t mpi_request; struct _sas_device *sas_device; - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); if (!sas_device) return; @@ -4274,7 +4379,7 @@ _scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) &mpi_request)) != 0) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + goto out; } sas_device->pfa_led_on = 1; @@ -4284,8 +4389,10 @@ _scsih_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) "enclosure_processor: ioc_status (0x%04x), loginfo(0x%08x)\n", ioc->name, le16_to_cpu(mpi_reply.IOCStatus), le32_to_cpu(mpi_reply.IOCLogInfo))); - return; + goto out; } +out: + sas_device_put(sas_device); } /** @@ -4370,19 +4477,17 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) /* only handle non-raid devices */ spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); if (!sas_device) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; + goto out_unlock; } starget = sas_device->starget; sas_target_priv_data = starget->hostdata; if ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_RAID_COMPONENT) || - ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + ((sas_target_priv_data->flags & MPT_TARGET_FLAGS_VOLUME))) + goto out_unlock; + starget_printk(KERN_WARNING, starget, "predicted fault\n"); spin_unlock_irqrestore(&ioc->sas_device_lock, flags); @@ -4396,7 +4501,7 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) if (!event_reply) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); - return; + goto out; } event_reply->Function = MPI2_FUNCTION_EVENT_NOTIFICATION; @@ -4413,6 +4518,14 @@ _scsih_smart_predicted_fault(struct MPT2SAS_ADAPTER *ioc, u16 handle) event_data->SASAddress = cpu_to_le64(sas_target_priv_data->sas_address); mpt2sas_ctl_add_to_event_log(ioc, event_reply); kfree(event_reply); +out: + if (sas_device) + sas_device_put(sas_device); + return; + +out_unlock: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + goto out; } /** @@ -5148,14 +5261,13 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(sas_device_pg0.SASAddress); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); if (!sas_device) { printk(MPT2SAS_ERR_FMT "device is not present " "handle(0x%04x), no sas_device!!!\n", ioc->name, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; + goto out_unlock; } if (unlikely(sas_device->handle != handle)) { @@ -5172,19 +5284,24 @@ _scsih_check_device(struct MPT2SAS_ADAPTER *ioc, u16 handle) MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)) { printk(MPT2SAS_ERR_FMT "device is not present " "handle(0x%04x), flags!!!\n", ioc->name, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; + goto out_unlock; } /* check if there were any issues with discovery */ if (_scsih_check_access_status(ioc, sas_address, handle, - sas_device_pg0.AccessStatus)) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + sas_device_pg0.AccessStatus)) + goto out_unlock; + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); _scsih_ublock_io_device(ioc, sas_address); + if (sas_device) + sas_device_put(sas_device); + return; +out_unlock: + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + if (sas_device) + sas_device_put(sas_device); } /** @@ -5208,7 +5325,6 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) u32 ioc_status; __le64 sas_address; u32 device_info; - unsigned long flags; if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -5250,14 +5366,13 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) return -1; } - - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = mpt2sas_get_sdev_by_addr(ioc, sas_address); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { + sas_device_put(sas_device); return 0; + } sas_device = kzalloc(sizeof(struct _sas_device), GFP_KERNEL); @@ -5267,6 +5382,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) return -1; } + kref_init(&sas_device->refcount); sas_device->handle = handle; if (_scsih_get_sas_address(ioc, le16_to_cpu (sas_device_pg0.ParentDevHandle), @@ -5296,6 +5412,7 @@ _scsih_add_device(struct MPT2SAS_ADAPTER *ioc, u16 handle, u8 phy_num, u8 is_pd) else _scsih_sas_device_add(ioc, sas_device); + sas_device_put(sas_device); return 0; } @@ -5344,7 +5461,6 @@ _scsih_remove_device(struct MPT2SAS_ADAPTER *ioc, "handle(0x%04x), sas_addr(0x%016llx)\n", ioc->name, __func__, sas_device->handle, (unsigned long long) sas_device->sas_address)); - kfree(sas_device); } /** * _scsih_device_remove_by_handle - removing device object by handle @@ -5363,12 +5479,17 @@ _scsih_device_remove_by_handle(struct MPT2SAS_ADAPTER *ioc, u16 handle) return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - if (sas_device) - list_del(&sas_device->list); + sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + + if (sas_device) { _scsih_remove_device(ioc, sas_device); + sas_device_put(sas_device); + } } /** @@ -5389,13 +5510,17 @@ mpt2sas_device_remove_by_sas_address(struct MPT2SAS_ADAPTER *ioc, return; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, - sas_address); - if (sas_device) - list_del(&sas_device->list); + sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); + if (sas_device) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + + if (sas_device) { _scsih_remove_device(ioc, sas_device); + sas_device_put(sas_device); + } } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING /** @@ -5716,26 +5841,28 @@ _scsih_sas_device_status_change_event(struct MPT2SAS_ADAPTER *ioc, spin_lock_irqsave(&ioc->sas_device_lock, flags); sas_address = le64_to_cpu(event_data->SASAddress); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, sas_address); - if (!sas_device || !sas_device->starget) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!sas_device || !sas_device->starget) + goto out; target_priv_data = sas_device->starget->hostdata; - if (!target_priv_data) { - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - return; - } + if (!target_priv_data) + goto out; if (event_data->ReasonCode == MPI2_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET) target_priv_data->tm_busy = 1; else target_priv_data->tm_busy = 0; + +out: + if (sas_device) + sas_device_put(sas_device); + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + } #ifdef CONFIG_SCSI_MPT2SAS_LOGGING @@ -6123,7 +6250,7 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, u16 handle = le16_to_cpu(element->PhysDiskDevHandle); spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); if (sas_device) { sas_device->volume_handle = 0; sas_device->volume_wwid = 0; @@ -6142,6 +6269,8 @@ _scsih_sas_pd_expose(struct MPT2SAS_ADAPTER *ioc, /* exposing raid component */ if (starget) starget_for_each_device(starget, NULL, _scsih_reprobe_lun); + + sas_device_put(sas_device); } /** @@ -6170,7 +6299,7 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, &volume_wwid); spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); + sas_device = __mpt2sas_get_sdev_by_handle(ioc, handle); if (sas_device) { set_bit(handle, ioc->pd_handles); if (sas_device->starget && sas_device->starget->hostdata) { @@ -6189,6 +6318,8 @@ _scsih_sas_pd_hide(struct MPT2SAS_ADAPTER *ioc, /* hiding raid component */ if (starget) starget_for_each_device(starget, (void *)1, _scsih_reprobe_lun); + + sas_device_put(sas_device); } /** @@ -6221,7 +6352,6 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, Mpi2EventIrConfigElement_t *element) { struct _sas_device *sas_device; - unsigned long flags; u16 handle = le16_to_cpu(element->PhysDiskDevHandle); Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; @@ -6231,11 +6361,11 @@ _scsih_sas_pd_add(struct MPT2SAS_ADAPTER *ioc, set_bit(handle, ioc->pd_handles); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); return; + } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle))) { @@ -6509,7 +6639,6 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, u16 handle, parent_handle; u32 state; struct _sas_device *sas_device; - unsigned long flags; Mpi2ConfigReply_t mpi_reply; Mpi2SasDevicePage0_t sas_device_pg0; u32 ioc_status; @@ -6542,12 +6671,11 @@ _scsih_sas_ir_physical_disk_event(struct MPT2SAS_ADAPTER *ioc, if (!ioc->is_warpdrive) set_bit(handle, ioc->pd_handles); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - - if (sas_device) + sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); return; + } if ((mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, @@ -7015,6 +7143,7 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) struct _raid_device *raid_device, *raid_device_next; struct list_head tmp_list; unsigned long flags; + LIST_HEAD(head); printk(MPT2SAS_INFO_FMT "removing unresponding devices: start\n", ioc->name); @@ -7022,14 +7151,29 @@ _scsih_remove_unresponding_sas_devices(struct MPT2SAS_ADAPTER *ioc) /* removing unresponding end devices */ printk(MPT2SAS_INFO_FMT "removing unresponding devices: end-devices\n", ioc->name); + + /* + * Iterate, pulling off devices marked as non-responding. We become the + * owner for the reference the list had on any object we prune. + */ + spin_lock_irqsave(&ioc->sas_device_lock, flags); list_for_each_entry_safe(sas_device, sas_device_next, - &ioc->sas_device_list, list) { + &ioc->sas_device_list, list) { if (!sas_device->responding) - mpt2sas_device_remove_by_sas_address(ioc, - sas_device->sas_address); + list_move_tail(&sas_device->list, &head); else sas_device->responding = 0; } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + /* + * Now, uninitialize and remove the unresponding devices we pruned. + */ + list_for_each_entry_safe(sas_device, sas_device_next, &head, list) { + _scsih_remove_device(ioc, sas_device); + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } /* removing unresponding volumes */ if (ioc->ir_firmware) { @@ -7179,11 +7323,11 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) } phys_disk_num = pd_pg0.PhysDiskNum; handle = le16_to_cpu(pd_pg0.DevHandle); - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = _scsih_sas_device_find_by_handle(ioc, handle); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + sas_device = mpt2sas_get_sdev_by_handle(ioc, handle); + if (sas_device) { + sas_device_put(sas_device); continue; + } if (mpt2sas_config_get_sas_device_pg0(ioc, &mpi_reply, &sas_device_pg0, MPI2_SAS_DEVICE_PGAD_FORM_HANDLE, handle) != 0) @@ -7302,12 +7446,12 @@ _scsih_scan_for_devices_after_reset(struct MPT2SAS_ADAPTER *ioc) if (!(_scsih_is_end_device( le32_to_cpu(sas_device_pg0.DeviceInfo)))) continue; - spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = mpt2sas_get_sdev_by_addr(ioc, le64_to_cpu(sas_device_pg0.SASAddress)); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); - if (sas_device) + if (sas_device) { + sas_device_put(sas_device); continue; + } parent_handle = le16_to_cpu(sas_device_pg0.ParentDevHandle); if (!_scsih_get_sas_address(ioc, parent_handle, &sas_address)) { printk(MPT2SAS_INFO_FMT "\tBEFORE adding end device: " @@ -7966,6 +8110,48 @@ _scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc) } } +static struct _sas_device *get_next_sas_device(struct MPT2SAS_ADAPTER *ioc) +{ + struct _sas_device *sas_device = NULL; + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + if (!list_empty(&ioc->sas_device_init_list)) { + sas_device = list_first_entry(&ioc->sas_device_init_list, + struct _sas_device, list); + sas_device_get(sas_device); + } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + return sas_device; +} + +static void sas_device_make_active(struct MPT2SAS_ADAPTER *ioc, + struct _sas_device *sas_device) +{ + unsigned long flags; + + spin_lock_irqsave(&ioc->sas_device_lock, flags); + + /* + * Since we dropped the lock during the call to port_add(), we need to + * be careful here that somebody else didn't move or delete this item + * while we were busy with other things. + * + * If it was on the list, we need a put() for the reference the list + * had. Either way, we need a get() for the destination list. + */ + if (!list_empty(&sas_device->list)) { + list_del_init(&sas_device->list); + sas_device_put(sas_device); + } + + sas_device_get(sas_device); + list_add_tail(&sas_device->list, &ioc->sas_device_list); + + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); +} + /** * _scsih_probe_sas - reporting sas devices to sas transport * @ioc: per adapter object @@ -7975,34 +8161,30 @@ _scsih_probe_raid(struct MPT2SAS_ADAPTER *ioc) static void _scsih_probe_sas(struct MPT2SAS_ADAPTER *ioc) { - struct _sas_device *sas_device, *next; - unsigned long flags; - - /* SAS Device List */ - list_for_each_entry_safe(sas_device, next, &ioc->sas_device_init_list, - list) { + struct _sas_device *sas_device; - if (ioc->hide_drives) - continue; + if (ioc->hide_drives) + return; + while ((sas_device = get_next_sas_device(ioc))) { if (!mpt2sas_transport_port_add(ioc, sas_device->handle, - sas_device->sas_address_parent)) { - list_del(&sas_device->list); - kfree(sas_device); + sas_device->sas_address_parent)) { + _scsih_sas_device_remove(ioc, sas_device); + sas_device_put(sas_device); continue; } else if (!sas_device->starget) { if (!ioc->is_driver_loading) { mpt2sas_transport_port_remove(ioc, - sas_device->sas_address, - sas_device->sas_address_parent); - list_del(&sas_device->list); - kfree(sas_device); + sas_device->sas_address, + sas_device->sas_address_parent); + _scsih_sas_device_remove(ioc, sas_device); + sas_device_put(sas_device); continue; } } - spin_lock_irqsave(&ioc->sas_device_lock, flags); - list_move_tail(&sas_device->list, &ioc->sas_device_list); - spin_unlock_irqrestore(&ioc->sas_device_lock, flags); + + sas_device_make_active(ioc, sas_device); + sas_device_put(sas_device); } } diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c index ff2500ab9ba47..af868009395d2 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_transport.c +++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c @@ -1323,15 +1323,17 @@ _transport_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); if (sas_device) { *identifier = sas_device->enclosure_logical_id; rc = 0; + sas_device_put(sas_device); } else { *identifier = 0; rc = -ENXIO; } + spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return rc; } @@ -1351,12 +1353,14 @@ _transport_get_bay_identifier(struct sas_rphy *rphy) int rc; spin_lock_irqsave(&ioc->sas_device_lock, flags); - sas_device = mpt2sas_scsih_sas_device_find_by_sas_address(ioc, + sas_device = __mpt2sas_get_sdev_by_addr(ioc, rphy->identify.sas_address); - if (sas_device) + if (sas_device) { rc = sas_device->slot; - else + sas_device_put(sas_device); + } else { rc = -ENXIO; + } spin_unlock_irqrestore(&ioc->sas_device_lock, flags); return rc; } -- GitLab From 008549f6e8a1dc4aeea4a8d64184909786b27713 Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Thu, 13 Aug 2015 18:48:10 -0700 Subject: [PATCH 6572/7006] mpt2sas: Refcount fw_events and fix unsafe list usage The fw_event_work struct is concurrently referenced at shutdown, so add a refcount to protect it, and refactor the code to use it. Additionally, refactor _scsih_fw_event_cleanup_queue() such that it no longer iterates over the list without holding the lock, since _firmware_event_work() concurrently deletes items from the list. Signed-off-by: Calvin Owens Reviewed-by: Christoph Hellwig Reviewed-by: Nicholas Bellinger Tested-by: Chaitra Basappa Acked-by: Sreekanth Reddy Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 112 ++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index 5eca3a4a9a7a5..c0ff55b0d3ccc 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -176,9 +176,37 @@ struct fw_event_work { u8 VP_ID; u8 ignore; u16 event; + struct kref refcount; char event_data[0] __aligned(4); }; +static void fw_event_work_free(struct kref *r) +{ + kfree(container_of(r, struct fw_event_work, refcount)); +} + +static void fw_event_work_get(struct fw_event_work *fw_work) +{ + kref_get(&fw_work->refcount); +} + +static void fw_event_work_put(struct fw_event_work *fw_work) +{ + kref_put(&fw_work->refcount, fw_event_work_free); +} + +static struct fw_event_work *alloc_fw_event_work(int len) +{ + struct fw_event_work *fw_event; + + fw_event = kzalloc(sizeof(*fw_event) + len, GFP_ATOMIC); + if (!fw_event) + return NULL; + + kref_init(&fw_event->refcount); + return fw_event; +} + /* raid transport support */ static struct raid_template *mpt2sas_raid_template; @@ -2872,36 +2900,39 @@ _scsih_fw_event_add(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) return; spin_lock_irqsave(&ioc->fw_event_lock, flags); + fw_event_work_get(fw_event); list_add_tail(&fw_event->list, &ioc->fw_event_list); INIT_DELAYED_WORK(&fw_event->delayed_work, _firmware_event_work); + fw_event_work_get(fw_event); queue_delayed_work(ioc->firmware_event_thread, &fw_event->delayed_work, 0); spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } /** - * _scsih_fw_event_free - delete fw_event + * _scsih_fw_event_del_from_list - delete fw_event from the list * @ioc: per adapter object * @fw_event: object describing the event * Context: This function will acquire ioc->fw_event_lock. * - * This removes firmware event object from link list, frees associated memory. + * If the fw_event is on the fw_event_list, remove it and do a put. * * Return nothing. */ static void -_scsih_fw_event_free(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work +_scsih_fw_event_del_from_list(struct MPT2SAS_ADAPTER *ioc, struct fw_event_work *fw_event) { unsigned long flags; spin_lock_irqsave(&ioc->fw_event_lock, flags); - list_del(&fw_event->list); - kfree(fw_event); + if (!list_empty(&fw_event->list)) { + list_del_init(&fw_event->list); + fw_event_work_put(fw_event); + } spin_unlock_irqrestore(&ioc->fw_event_lock, flags); } - /** * _scsih_error_recovery_delete_devices - remove devices not responding * @ioc: per adapter object @@ -2916,13 +2947,14 @@ _scsih_error_recovery_delete_devices(struct MPT2SAS_ADAPTER *ioc) if (ioc->is_driver_loading) return; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT2SAS_REMOVE_UNRESPONDING_DEVICES; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -2936,12 +2968,29 @@ mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) { struct fw_event_work *fw_event; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT2SAS_PORT_ENABLE_COMPLETE; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); +} + +static struct fw_event_work *dequeue_next_fw_event(struct MPT2SAS_ADAPTER *ioc) +{ + unsigned long flags; + struct fw_event_work *fw_event = NULL; + + spin_lock_irqsave(&ioc->fw_event_lock, flags); + if (!list_empty(&ioc->fw_event_list)) { + fw_event = list_first_entry(&ioc->fw_event_list, + struct fw_event_work, list); + list_del_init(&fw_event->list); + } + spin_unlock_irqrestore(&ioc->fw_event_lock, flags); + + return fw_event; } /** @@ -2956,17 +3005,25 @@ mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc) static void _scsih_fw_event_cleanup_queue(struct MPT2SAS_ADAPTER *ioc) { - struct fw_event_work *fw_event, *next; + struct fw_event_work *fw_event; if (list_empty(&ioc->fw_event_list) || !ioc->firmware_event_thread || in_interrupt()) return; - list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) { - if (cancel_delayed_work_sync(&fw_event->delayed_work)) { - _scsih_fw_event_free(ioc, fw_event); - continue; - } + while ((fw_event = dequeue_next_fw_event(ioc))) { + /* + * Wait on the fw_event to complete. If this returns 1, then + * the event was never executed, and we need a put for the + * reference the delayed_work had on the fw_event. + * + * If it did execute, we wait for it to finish, and the put will + * happen from _firmware_event_work() + */ + if (cancel_delayed_work_sync(&fw_event->delayed_work)) + fw_event_work_put(fw_event); + + fw_event_work_put(fw_event); } } @@ -4447,13 +4504,14 @@ _scsih_send_event_to_turn_on_pfa_led(struct MPT2SAS_ADAPTER *ioc, u16 handle) { struct fw_event_work *fw_event; - fw_event = kzalloc(sizeof(struct fw_event_work), GFP_ATOMIC); + fw_event = alloc_fw_event_work(0); if (!fw_event) return; fw_event->event = MPT2SAS_TURN_ON_PFA_LED; fw_event->device_handle = handle; fw_event->ioc = ioc; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); } /** @@ -7554,17 +7612,27 @@ _firmware_event_work(struct work_struct *work) struct fw_event_work, delayed_work.work); struct MPT2SAS_ADAPTER *ioc = fw_event->ioc; + _scsih_fw_event_del_from_list(ioc, fw_event); + /* the queue is being flushed so ignore this event */ - if (ioc->remove_host || - ioc->pci_error_recovery) { - _scsih_fw_event_free(ioc, fw_event); + if (ioc->remove_host || ioc->pci_error_recovery) { + fw_event_work_put(fw_event); return; } switch (fw_event->event) { case MPT2SAS_REMOVE_UNRESPONDING_DEVICES: - while (scsi_host_in_recovery(ioc->shost) || ioc->shost_recovery) + while (scsi_host_in_recovery(ioc->shost) || + ioc->shost_recovery) { + /* + * If we're unloading, bail. Otherwise, this can become + * an infinite loop. + */ + if (ioc->remove_host) + goto out; + ssleep(1); + } _scsih_remove_unresponding_sas_devices(ioc); _scsih_scan_for_devices_after_reset(ioc); break; @@ -7613,7 +7681,8 @@ _firmware_event_work(struct work_struct *work) _scsih_sas_ir_operation_status_event(ioc, fw_event); break; } - _scsih_fw_event_free(ioc, fw_event); +out: + fw_event_work_put(fw_event); } /** @@ -7751,7 +7820,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, } sz = le16_to_cpu(mpi_reply->EventDataLength) * 4; - fw_event = kzalloc(sizeof(*fw_event) + sz, GFP_ATOMIC); + fw_event = alloc_fw_event_work(sz); if (!fw_event) { printk(MPT2SAS_ERR_FMT "failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); @@ -7764,6 +7833,7 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index, fw_event->VP_ID = mpi_reply->VP_ID; fw_event->event = event; _scsih_fw_event_add(ioc, fw_event); + fw_event_work_put(fw_event); return; } -- GitLab From c1287970f4847a973830daf4076bc25929f3b2d9 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:20 +0300 Subject: [PATCH 6573/7006] scsi_debug: define pr_fmt() for consistent logging Use pr_fmt with both module name and __func__ Also drop few bare printk leftovers The log format should stay pretty much intact Signed-off-by: Tomas Winkler Acked-by: Douglas Gilbert Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 118 +++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 65 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 30268bb2ddb6a..6e6bf0f03cf7a 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -25,6 +25,9 @@ * module options to "modprobe scsi_debug num_tgts=2" [20021221] */ + +#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ + #include #include @@ -2446,8 +2449,7 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data, __be16 csum = dif_compute_csum(data, scsi_debug_sector_size); if (sdt->guard_tag != csum) { - pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", - __func__, + pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", (unsigned long)sector, be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum)); @@ -2455,14 +2457,14 @@ static int dif_verify(struct sd_dif_tuple *sdt, const void *data, } if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { - pr_err("%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); + pr_err("REF check failed on sector %lu\n", + (unsigned long)sector); return 0x03; } if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && be32_to_cpu(sdt->ref_tag) != ei_lba) { - pr_err("%s: REF check failed on sector %lu\n", - __func__, (unsigned long)sector); + pr_err("REF check failed on sector %lu\n", + (unsigned long)sector); return 0x03; } return 0; @@ -3449,7 +3451,7 @@ static void sdebug_q_cmd_complete(unsigned long indx) atomic_inc(&sdebug_completions); qa_indx = indx; if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) { - pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx); + pr_err("wild qa_indx=%d\n", qa_indx); return; } spin_lock_irqsave(&queued_arr_lock, iflags); @@ -3457,21 +3459,21 @@ static void sdebug_q_cmd_complete(unsigned long indx) scp = sqcp->a_cmnd; if (NULL == scp) { spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("%s: scp is NULL\n", __func__); + pr_err("scp is NULL\n"); return; } devip = (struct sdebug_dev_info *)scp->device->hostdata; if (devip) atomic_dec(&devip->num_in_q); else - pr_err("%s: devip=NULL\n", __func__); + pr_err("devip=NULL\n"); if (atomic_read(&retired_max_queue) > 0) retiring = 1; sqcp->a_cmnd = NULL; if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) { spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("%s: Unexpected completion\n", __func__); + pr_err("Unexpected completion\n"); return; } @@ -3481,7 +3483,7 @@ static void sdebug_q_cmd_complete(unsigned long indx) retval = atomic_read(&retired_max_queue); if (qa_indx >= retval) { spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("%s: index %d too large\n", __func__, retval); + pr_err("index %d too large\n", retval); return; } k = find_last_bit(queued_in_use_bm, retval); @@ -3509,7 +3511,7 @@ sdebug_q_cmd_hrt_complete(struct hrtimer *timer) atomic_inc(&sdebug_completions); qa_indx = sd_hrtp->qa_indx; if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) { - pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx); + pr_err("wild qa_indx=%d\n", qa_indx); goto the_end; } spin_lock_irqsave(&queued_arr_lock, iflags); @@ -3517,21 +3519,21 @@ sdebug_q_cmd_hrt_complete(struct hrtimer *timer) scp = sqcp->a_cmnd; if (NULL == scp) { spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("%s: scp is NULL\n", __func__); + pr_err("scp is NULL\n"); goto the_end; } devip = (struct sdebug_dev_info *)scp->device->hostdata; if (devip) atomic_dec(&devip->num_in_q); else - pr_err("%s: devip=NULL\n", __func__); + pr_err("devip=NULL\n"); if (atomic_read(&retired_max_queue) > 0) retiring = 1; sqcp->a_cmnd = NULL; if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) { spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("%s: Unexpected completion\n", __func__); + pr_err("Unexpected completion\n"); goto the_end; } @@ -3541,7 +3543,7 @@ sdebug_q_cmd_hrt_complete(struct hrtimer *timer) retval = atomic_read(&retired_max_queue); if (qa_indx >= retval) { spin_unlock_irqrestore(&queued_arr_lock, iflags); - pr_err("%s: index %d too large\n", __func__, retval); + pr_err("index %d too large\n", retval); goto the_end; } k = find_last_bit(queued_in_use_bm, retval); @@ -3580,7 +3582,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) return devip; sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); if (!sdbg_host) { - pr_err("%s: Host info NULL\n", __func__); + pr_err("Host info NULL\n"); return NULL; } list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { @@ -3596,8 +3598,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) if (!open_devip) { /* try and make a new one */ open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); if (!open_devip) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __func__, __LINE__); + pr_err("out of memory at line %d\n", __LINE__); return NULL; } } @@ -3615,7 +3616,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) static int scsi_debug_slave_alloc(struct scsi_device *sdp) { if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n", + pr_info("slave_alloc <%u %u %u %llu>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); return 0; @@ -3626,7 +3627,7 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp) struct sdebug_dev_info *devip; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n", + pr_info("slave_configure <%u %u %u %llu>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; @@ -3646,7 +3647,7 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp) (struct sdebug_dev_info *)sdp->hostdata; if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) - printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n", + pr_info("slave_destroy <%u %u %u %llu>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); if (devip) { /* make this slot available for re-use */ @@ -3897,8 +3898,7 @@ static void __init sdebug_build_parts(unsigned char *ramp, return; if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { scsi_debug_num_parts = SDEBUG_MAX_PARTS; - pr_warn("%s: reducing partitions to %d\n", __func__, - SDEBUG_MAX_PARTS); + pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); } num_sectors = (int)sdebug_store_sectors; sectors_per_part = (num_sectors - sdebug_sectors_per) @@ -3945,8 +3945,7 @@ schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, struct scsi_device *sdp = cmnd->device; if (NULL == cmnd || NULL == devip) { - pr_warn("%s: called with NULL cmnd or devip pointer\n", - __func__); + pr_warn("called with NULL cmnd or devip pointer\n"); /* no particularly good error to report back */ return SCSI_MLQUEUE_HOST_BUSY; } @@ -4383,8 +4382,7 @@ static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, fake_storep = vmalloc(sz); if (NULL == fake_storep) { - pr_err("%s: out of memory, 9\n", - __func__); + pr_err("out of memory, 9\n"); return -ENOMEM; } memset(fake_storep, 0, sz); @@ -4784,8 +4782,7 @@ static int __init scsi_debug_init(void) atomic_set(&retired_max_queue, 0); if (scsi_debug_ndelay >= 1000000000) { - pr_warn("%s: ndelay must be less than 1 second, ignored\n", - __func__); + pr_warn("ndelay must be less than 1 second, ignored\n"); scsi_debug_ndelay = 0; } else if (scsi_debug_ndelay > 0) scsi_debug_delay = DELAY_OVERRIDDEN; @@ -4797,8 +4794,7 @@ static int __init scsi_debug_init(void) case 4096: break; default: - pr_err("%s: invalid sector_size %d\n", __func__, - scsi_debug_sector_size); + pr_err("invalid sector_size %d\n", scsi_debug_sector_size); return -EINVAL; } @@ -4811,29 +4807,28 @@ static int __init scsi_debug_init(void) break; default: - pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__); + pr_err("dif must be 0, 1, 2 or 3\n"); return -EINVAL; } if (scsi_debug_guard > 1) { - pr_err("%s: guard must be 0 or 1\n", __func__); + pr_err("guard must be 0 or 1\n"); return -EINVAL; } if (scsi_debug_ato > 1) { - pr_err("%s: ato must be 0 or 1\n", __func__); + pr_err("ato must be 0 or 1\n"); return -EINVAL; } if (scsi_debug_physblk_exp > 15) { - pr_err("%s: invalid physblk_exp %u\n", __func__, - scsi_debug_physblk_exp); + pr_err("invalid physblk_exp %u\n", scsi_debug_physblk_exp); return -EINVAL; } if (scsi_debug_lowest_aligned > 0x3fff) { - pr_err("%s: lowest_aligned too big: %u\n", __func__, - scsi_debug_lowest_aligned); + pr_err("lowest_aligned too big: %u\n", + scsi_debug_lowest_aligned); return -EINVAL; } @@ -4863,7 +4858,7 @@ static int __init scsi_debug_init(void) if (0 == scsi_debug_fake_rw) { fake_storep = vmalloc(sz); if (NULL == fake_storep) { - pr_err("%s: out of memory, 1\n", __func__); + pr_err("out of memory, 1\n"); return -ENOMEM; } memset(fake_storep, 0, sz); @@ -4877,11 +4872,10 @@ static int __init scsi_debug_init(void) dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); dif_storep = vmalloc(dif_size); - pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size, - dif_storep); + pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); if (dif_storep == NULL) { - pr_err("%s: out of mem. (DIX)\n", __func__); + pr_err("out of mem. (DIX)\n"); ret = -ENOMEM; goto free_vm; } @@ -4903,18 +4897,17 @@ static int __init scsi_debug_init(void) if (scsi_debug_unmap_alignment && scsi_debug_unmap_granularity <= scsi_debug_unmap_alignment) { - pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n", - __func__); + pr_err("ERR: unmap_granularity <= unmap_alignment\n"); return -EINVAL; } map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); - pr_info("%s: %lu provisioning blocks\n", __func__, map_size); + pr_info("%lu provisioning blocks\n", map_size); if (map_storep == NULL) { - pr_err("%s: out of mem. (MAP)\n", __func__); + pr_err("out of mem. (MAP)\n"); ret = -ENOMEM; goto free_vm; } @@ -4928,18 +4921,18 @@ static int __init scsi_debug_init(void) pseudo_primary = root_device_register("pseudo_0"); if (IS_ERR(pseudo_primary)) { - pr_warn("%s: root_device_register() error\n", __func__); + pr_warn("root_device_register() error\n"); ret = PTR_ERR(pseudo_primary); goto free_vm; } ret = bus_register(&pseudo_lld_bus); if (ret < 0) { - pr_warn("%s: bus_register error: %d\n", __func__, ret); + pr_warn("bus_register error: %d\n", ret); goto dev_unreg; } ret = driver_register(&sdebug_driverfs_driver); if (ret < 0) { - pr_warn("%s: driver_register error: %d\n", __func__, ret); + pr_warn("driver_register error: %d\n", ret); goto bus_unreg; } @@ -4948,16 +4941,14 @@ static int __init scsi_debug_init(void) for (k = 0; k < host_to_add; k++) { if (sdebug_add_adapter()) { - pr_err("%s: sdebug_add_adapter failed k=%d\n", - __func__, k); + pr_err("sdebug_add_adapter failed k=%d\n", k); break; } } - if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { - pr_info("%s: built %d host(s)\n", __func__, - scsi_debug_add_host); - } + if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) + pr_info("built %d host(s)\n", scsi_debug_add_host); + return 0; bus_unreg: @@ -5012,8 +5003,7 @@ static int sdebug_add_adapter(void) sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); if (NULL == sdbg_host) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __func__, __LINE__); + pr_err("out of memory at line %d\n", __LINE__); return -ENOMEM; } @@ -5023,8 +5013,7 @@ static int sdebug_add_adapter(void) for (k = 0; k < devs_per_host; k++) { sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); if (!sdbg_devinfo) { - printk(KERN_ERR "%s: out of memory at line %d\n", - __func__, __LINE__); + pr_err("out of memory at line %d\n", __LINE__); error = -ENOMEM; goto clean; } @@ -5338,7 +5327,7 @@ static int sdebug_driver_probe(struct device * dev) sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); if (NULL == hpnt) { - pr_err("%s: scsi_host_alloc failed\n", __func__); + pr_err("scsi_host_alloc failed\n"); error = -ENODEV; return error; } @@ -5381,7 +5370,7 @@ static int sdebug_driver_probe(struct device * dev) scsi_host_set_prot(hpnt, host_prot); - printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", + pr_info("host protection%s%s%s%s%s%s%s\n", (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", @@ -5409,7 +5398,7 @@ static int sdebug_driver_probe(struct device * dev) error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { - printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); + pr_err("scsi_add_host failed\n"); error = -ENODEV; scsi_host_put(hpnt); } else @@ -5426,8 +5415,7 @@ static int sdebug_driver_remove(struct device * dev) sdbg_host = to_sdebug_host(dev); if (!sdbg_host) { - printk(KERN_ERR "%s: Unable to locate host info\n", - __func__); + pr_err("Unable to locate host info\n"); return -ENODEV; } -- GitLab From 34d55434ba1f39093ea30cb770d70508fdb1edaa Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:21 +0300 Subject: [PATCH 6574/7006] scsi_debug: use SCSI_W_LUN_REPORT_LUNS instead of SAM2_WLUN_REPORT_LUNS; use SCSI_W_LUN_REPORT_LUNS from scsi.h instead of localy defined SAM2_WLUN_REPORT_LUNS Signed-off-by: Tomas Winkler Acked-by: Douglas Gilbert Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 6e6bf0f03cf7a..bbe04dae040c4 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -204,7 +204,6 @@ static const char *scsi_debug_version_date = "20141022"; /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) * or "peripheral device" addressing (value 0) */ #define SAM2_LUN_ADDRESS_METHOD 0 -#define SAM2_WLUN_REPORT_LUNS 0xc101 /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued * (for response) at one time. Can be reduced by max_queue option. Command @@ -701,7 +700,7 @@ static void sdebug_max_tgts_luns(void) else hpnt->max_id = scsi_debug_num_tgts; /* scsi_debug_max_luns; */ - hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; + hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS; } spin_unlock(&sdebug_host_list_lock); } @@ -1291,7 +1290,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); if (! arr) return DID_REQUEUE << 16; - have_wlun = (scp->device->lun == SAM2_WLUN_REPORT_LUNS); + have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS); if (have_wlun) pq_pdt = 0x1e; /* present, wlun */ else if (scsi_debug_no_lun_0 && (0 == devip->lun)) @@ -3367,8 +3366,8 @@ static int resp_report_luns(struct scsi_cmnd * scp, one_lun[i].scsi_lun[1] = lun & 0xff; } if (want_wlun) { - one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; - one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; + one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff; + one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff; i++; } alloc_len = (unsigned char *)(one_lun + i) - arr; @@ -5167,7 +5166,7 @@ scsi_debug_queuecommand(struct scsi_cmnd *scp) } sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b); } - has_wlun_rl = (sdp->lun == SAM2_WLUN_REPORT_LUNS); + has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl) return schedule_resp(scp, NULL, errsts_no_connect, 0); @@ -5338,7 +5337,7 @@ static int sdebug_driver_probe(struct device * dev) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ + hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ host_prot = 0; -- GitLab From de232af6703ff8e283559016c14a3273ea932878 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:22 +0300 Subject: [PATCH 6575/7006] scsi_debug: vfree is null safe so drop the check Signed-off-by: Tomas Winkler Acked-by: Douglas Gilbert Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index bbe04dae040c4..e2c509e39765e 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -4955,10 +4955,8 @@ bus_unreg: dev_unreg: root_device_unregister(pseudo_primary); free_vm: - if (map_storep) - vfree(map_storep); - if (dif_storep) - vfree(dif_storep); + vfree(map_storep); + vfree(dif_storep); vfree(fake_storep); return ret; @@ -4976,9 +4974,7 @@ static void __exit scsi_debug_exit(void) bus_unregister(&pseudo_lld_bus); root_device_unregister(pseudo_primary); - if (dif_storep) - vfree(dif_storep); - + vfree(dif_storep); vfree(fake_storep); } -- GitLab From 58a8635d5a1b49c4b87fb48969319e1ce77d3f03 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:23 +0300 Subject: [PATCH 6576/7006] scsi_debug: make dump_sector static MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fixes warning: warning: no previous prototype for ‘dump_sector’ Signed-off-by: Tomas Winkler Acked-by: Douglas Gilbert Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index e2c509e39765e..3a70683cf9f90 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -2681,7 +2681,7 @@ resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) return 0; } -void dump_sector(unsigned char *buf, int len) +static void dump_sector(unsigned char *buf, int len) { int i, j, n; -- GitLab From 299b6c07ea134d4f9d7cb743194bf9c1941585b2 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:24 +0300 Subject: [PATCH 6577/7006] scsi_debug: schedule_resp fix input variable check The function should never be called with cmnd NULL so put a fat WARN there. Fix also smatch wraning: schedule_resp() warn: variable dereferenced before check 'cmnd' Signed-off-by: Tomas Winkler Acked-by: Douglas Gilbert Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 3a70683cf9f90..faa4ddd8decfb 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -3941,13 +3941,20 @@ schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, unsigned long iflags; int k, num_in_q, qdepth, inject; struct sdebug_queued_cmd *sqcp = NULL; - struct scsi_device *sdp = cmnd->device; + struct scsi_device *sdp; + + /* this should never happen */ + if (WARN_ON(!cmnd)) + return SCSI_MLQUEUE_HOST_BUSY; - if (NULL == cmnd || NULL == devip) { - pr_warn("called with NULL cmnd or devip pointer\n"); + if (NULL == devip) { + pr_warn("called devip == NULL\n"); /* no particularly good error to report back */ return SCSI_MLQUEUE_HOST_BUSY; } + + sdp = cmnd->device; + if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", __func__, scsi_result); -- GitLab From f2d3fd29ba6226218533ad3fbba2312ae122663f Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:25 +0300 Subject: [PATCH 6578/7006] scsi_debug: fix REPORT LUNS Well Known LU The use case to report 'REPORT LUNS WLUN' described in scsi_debug documentation didn't work because: scsi_scan_host_selected() checks for: lun < shost->max_lun To fix this we set: max_lun = SCSI_W_LUN_REPORT_LUNS + 1; Signed-off-by: Tomas Winkler Acked-by: Douglas Gilbert Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index faa4ddd8decfb..2e0b3d7dc40f2 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -700,7 +700,7 @@ static void sdebug_max_tgts_luns(void) else hpnt->max_id = scsi_debug_num_tgts; /* scsi_debug_max_luns; */ - hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS; + hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; } spin_unlock(&sdebug_host_list_lock); } @@ -5340,7 +5340,8 @@ static int sdebug_driver_probe(struct device * dev) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; - hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ + /* = scsi_debug_max_luns; */ + hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; host_prot = 0; -- GitLab From 2492fc09f0b90cd69cd9788d12c5c79d673adef3 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Tue, 28 Jul 2015 16:54:26 +0300 Subject: [PATCH 6579/7006] scsi_debug: resp_request: remove unused variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes the following warning In function ‘resp_requests’: drivers/scsi//scsi_debug.c:1432:15: warning: variable ‘want_dsense’ set but not used [-Wunused-but-set-variable] bool dsense, want_dsense; Signed-off-by: Tomas Winkler Reviewed-by: Martin K. Petersen Signed-off-by: James Bottomley --- drivers/scsi/scsi_debug.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 2e0b3d7dc40f2..dfcc45bb03b1f 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1429,12 +1429,11 @@ static int resp_requests(struct scsi_cmnd * scp, unsigned char * sbuff; unsigned char *cmd = scp->cmnd; unsigned char arr[SCSI_SENSE_BUFFERSIZE]; - bool dsense, want_dsense; + bool dsense; int len = 18; memset(arr, 0, sizeof(arr)); dsense = !!(cmd[1] & 1); - want_dsense = dsense || scsi_debug_dsense; sbuff = scp->sense_buffer; if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { if (dsense) { -- GitLab From 0c416b54f29151a31999868d59c64ace11589d1b Mon Sep 17 00:00:00 2001 From: Jordan Hargrave Date: Mon, 13 Jul 2015 09:27:33 -0500 Subject: [PATCH 6580/7006] scsi_transport_sas: Remove check for SAS expander when querying bay/enclosure IDs. Dell Server backplanes can report bay/enclosure IDs without an expander present. This patch allows the bay/enclosure IDs to be propagaged to sysfs.we Signed-off-by: Jordan Hargrave Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_sas.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 9a058194b9bdb..30d26e345dcc7 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c @@ -1222,13 +1222,6 @@ show_sas_rphy_enclosure_identifier(struct device *dev, u64 identifier; int error; - /* - * Only devices behind an expander are supported, because the - * enclosure identifier is a SMP feature. - */ - if (scsi_is_sas_phy_local(phy)) - return -EINVAL; - error = i->f->get_enclosure_identifier(rphy, &identifier); if (error) return error; @@ -1248,9 +1241,6 @@ show_sas_rphy_bay_identifier(struct device *dev, struct sas_internal *i = to_sas_internal(shost->transportt); int val; - if (scsi_is_sas_phy_local(phy)) - return -EINVAL; - val = i->f->get_bay_identifier(rphy); if (val < 0) return val; -- GitLab From b7f4d6343820af5c2dc3979e91d85e71e638cd3d Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Thu, 13 Aug 2015 06:41:51 -0400 Subject: [PATCH 6581/7006] bfa: Fix indentation Signed-off-by: Anil Gurumurthy Tested-by : Sudarasana Kalluru Reviewed-by: Ewan D. Milne Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_ioc.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 315d6d6dcfc86..4e7104461f09e 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -3665,19 +3665,19 @@ bfa_cb_sfp_state_query(struct bfa_sfp_s *sfp) if (sfp->state_query_cbfn) sfp->state_query_cbfn(sfp->state_query_cbarg, sfp->status); - sfp->media = NULL; - } + sfp->media = NULL; + } - if (sfp->portspeed) { - sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed); - if (sfp->state_query_cbfn) - sfp->state_query_cbfn(sfp->state_query_cbarg, - sfp->status); - sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; - } + if (sfp->portspeed) { + sfp->status = bfa_sfp_speed_valid(sfp, sfp->portspeed); + if (sfp->state_query_cbfn) + sfp->state_query_cbfn(sfp->state_query_cbarg, + sfp->status); + sfp->portspeed = BFA_PORT_SPEED_UNKNOWN; + } - sfp->state_query_lock = 0; - sfp->state_query_cbfn = NULL; + sfp->state_query_lock = 0; + sfp->state_query_cbfn = NULL; } /* -- GitLab From 6f3d828f5bd72174c24789aba5d4ed036b60f44b Mon Sep 17 00:00:00 2001 From: Anil Gurumurthy Date: Thu, 13 Aug 2015 06:41:52 -0400 Subject: [PATCH 6582/7006] bfa: Fix incorrect de-reference of pointer Signed-off-by: Anil Gurumurthy Tested-by: Sudarsana Kalluru Reviewed-by: Ewan D. Milne Signed-off-by: James Bottomley --- drivers/scsi/bfa/bfa_ioc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfa_ioc.c b/drivers/scsi/bfa/bfa_ioc.c index 4e7104461f09e..98f7e8cca52df 100644 --- a/drivers/scsi/bfa/bfa_ioc.c +++ b/drivers/scsi/bfa/bfa_ioc.c @@ -3878,7 +3878,7 @@ bfa_sfp_show_comp(struct bfa_sfp_s *sfp, struct bfi_mbmsg_s *msg) bfa_trc(sfp, sfp->data_valid); if (sfp->data_valid) { u32 size = sizeof(struct sfp_mem_s); - u8 *des = (u8 *) &(sfp->sfpmem); + u8 *des = (u8 *)(sfp->sfpmem); memcpy(des, sfp->dbuf_kva, size); } /* -- GitLab From 612872cabf5be6f95d43d9a88eef38201ae8005d Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 17 Aug 2015 13:03:02 +0200 Subject: [PATCH 6583/7006] lpfc: Fix possible use-after-free and double free in lpfc_mbx_cmpl_rdp_page_a2() If the bf_get() call in lpfc_mbx_cmpl_rdp_page_a2() does succeeds, execution continues normally and mp gets kfree()d. If the subsequent call to lpfc_sli_issue_mbox() fails execution jumps to the error label where lpfc_mbuf_free() is called with mp->virt and mp->phys as function arguments. This is the use after free. Following the use after free mp gets kfree()d again which is a double free. Signed-off-by: Johannes Thumshirn Acked-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_mbox.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index eb627724417e1..4abb93a83e0ff 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -2284,7 +2284,7 @@ lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) (struct lpfc_rdp_context *)(mbox->context2); if (bf_get(lpfc_mqe_status, &mbox->u.mqe)) - goto error; + goto error_mbuf_free; lpfc_sli_bemem_bcopy(mp->virt, &rdp_context->page_a2, DMP_SFF_PAGE_A2_SIZE); @@ -2299,13 +2299,14 @@ lpfc_mbx_cmpl_rdp_page_a2(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) mbox->mbox_cmpl = lpfc_mbx_cmpl_rdp_link_stat; mbox->context2 = (struct lpfc_rdp_context *) rdp_context; if (lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT) == MBX_NOT_FINISHED) - goto error; + goto error_cmd_free; return; -error: +error_mbuf_free: lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); +error_cmd_free: lpfc_sli4_mbox_cmd_free(phba, mbox); rdp_context->cmpl(phba, rdp_context, FAILURE); } -- GitLab From 50acde8ed35620fdfad88f4e20a39a1eb0d8d4c9 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 17 Aug 2015 15:52:32 +0200 Subject: [PATCH 6584/7006] pm80xx: Don't override ts->stat on IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY In case psataPayload->status has a status of IO_OPEN_CNX_ERROR_HW_RESOURCE_BUSY ts->stat gets set to SAS_OPEN_REJECT but a missing 'break' statement causes a fallthrough to the default handler of the switch statement overriding ts->stat to SAS_DEV_NO_RESPONSE. Signed-off-by: Johannes Thumshirn Acked-by: Jack Wang Signed-off-by: James Bottomley --- drivers/scsi/pm8001/pm8001_hwi.c | 1 + drivers/scsi/pm8001/pm80xx_hwi.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 39306b1e704c5..04e67a190652e 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -2642,6 +2642,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + break; default: PM8001_IO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 0e1628f2018e5..9a389f1508de8 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2337,6 +2337,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_OPEN_REJECT; ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; + break; default: PM8001_IO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); -- GitLab From 6229b414b3adb3aac0b54e67d72d6462fc230c0d Mon Sep 17 00:00:00 2001 From: Nagarajkumar Narayanan Date: Tue, 18 Aug 2015 13:27:10 +0530 Subject: [PATCH 6585/7006] mpt2sas: setpci reset kernel oops fix mpt2sas: setpci reset on nytro warpdrive card along with sysfs access and cli ioctl access resulted in kernel oops 1. pci_access_mutex lock added to provide synchronization between IOCTL, sysfs, PCI resource handling path 2. gioc_lock spinlock to protect list operations over multiple controllers >From c53a1cff4c07528b8b9ec7f6716e94950283e8f9 Mon Sep 17 00:00:00 2001 From: Nagarajkumar Narayanan Date: Tue, 18 Aug 2015 11:58:13 +0530 Subject: [PATCH] mpt2sas setpci reset oops fix In mpt2sas driver due to lack of synchronization between ioctl, BRM status access through sysfs, pci resource removal kernel oops happen as ioctl path and BRM status sysfs access path still tries to access the removed resources Two locks added to provide syncrhonization 1. pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and pci resource handling. PCI resource freeing will lead to free vital hardware/memory resource, which might be in use by cli/sysfs path functions resulting in Null pointer reference followed by kernel crash. To avoid the above race condition we use mutex syncrhonization which ensures the syncrhonization between cli/sysfs_show path Note: pci_access_mutex is used only if nytro warpdrive cards (ioc->is_warpdrive based on device id) are used as we could not test this case with other SAS2 HBA cards We can remove this check if this behaviour confirmed from other cards. 2. spinlock on list operations over IOCs Case: when multiple warpdrive cards(IOCs) are in use Each IOC will added to the ioc list stucture on initialization. Watchdog threads run at regular intervals to check IOC for any fault conditions which will trigger the dead_ioc thread to deallocate pci resource, resulting deleting the IOC netry from list, this deletion need to protected by spinlock to enusre that ioc removal is syncrhonized, if not synchronized it might lead to list_del corruption as the ioc list is traversed in cli path Signed-off-by: Nagarajkumar Narayanan Reviewed-by: Johannes Thumshirn Acked-by: Sreekanth Reddy Signed-off-by: James Bottomley --- drivers/scsi/mpt2sas/mpt2sas_base.c | 6 +++++ drivers/scsi/mpt2sas/mpt2sas_base.h | 19 +++++++++++++- drivers/scsi/mpt2sas/mpt2sas_ctl.c | 38 +++++++++++++++++++++++----- drivers/scsi/mpt2sas/mpt2sas_scsih.c | 13 +++++++++- 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c index 6dec7cff316f4..c167911221e96 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.c +++ b/drivers/scsi/mpt2sas/mpt2sas_base.c @@ -112,9 +112,12 @@ _scsih_set_fwfault_debug(const char *val, struct kernel_param *kp) if (ret) return ret; + /* global ioc spinlock to protect controller list on list operations */ printk(KERN_INFO "setting fwfault_debug(%d)\n", mpt2sas_fwfault_debug); + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt2sas_ioc_list, list) ioc->fwfault_debug = mpt2sas_fwfault_debug; + spin_unlock(&gioc_lock); return 0; } @@ -4437,6 +4440,8 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) dexitprintk(ioc, printk(MPT2SAS_INFO_FMT "%s\n", ioc->name, __func__)); + /* synchronizing freeing resource with pci_access_mutex lock */ + mutex_lock(&ioc->pci_access_mutex); if (ioc->chip_phys && ioc->chip) { _base_mask_interrupts(ioc); ioc->shost_recovery = 1; @@ -4456,6 +4461,7 @@ mpt2sas_base_free_resources(struct MPT2SAS_ADAPTER *ioc) pci_disable_pcie_error_reporting(pdev); pci_disable_device(pdev); } + mutex_unlock(&ioc->pci_access_mutex); return; } diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index 78f41aca9598c..97ea360c6920e 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h @@ -817,6 +817,12 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc); * @delayed_tr_list: target reset link list * @delayed_tr_volume_list: volume target reset link list * @@temp_sensors_count: flag to carry the number of temperature sensors + * @pci_access_mutex: Mutex to synchronize ioctl,sysfs show path and + * pci resource handling. PCI resource freeing will lead to free + * vital hardware/memory resource, which might be in use by cli/sysfs + * path functions resulting in Null pointer reference followed by kernel + * crash. To avoid the above race condition we use mutex syncrhonization + * which ensures the syncrhonization between cli/sysfs_show path */ struct MPT2SAS_ADAPTER { struct list_head list; @@ -1033,6 +1039,7 @@ struct MPT2SAS_ADAPTER { u8 mfg_pg10_hide_flag; u8 hide_drives; + struct mutex pci_access_mutex; }; typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, @@ -1041,6 +1048,17 @@ typedef u8 (*MPT_CALLBACK)(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, /* base shared API */ extern struct list_head mpt2sas_ioc_list; +/* spinlock on list operations over IOCs + * Case: when multiple warpdrive cards(IOCs) are in use + * Each IOC will added to the ioc list stucture on initialization. + * Watchdog threads run at regular intervals to check IOC for any + * fault conditions which will trigger the dead_ioc thread to + * deallocate pci resource, resulting deleting the IOC netry from list, + * this deletion need to protected by spinlock to enusre that + * ioc removal is syncrhonized, if not synchronized it might lead to + * list_del corruption as the ioc list is traversed in cli path + */ +extern spinlock_t gioc_lock; void mpt2sas_base_start_watchdog(struct MPT2SAS_ADAPTER *ioc); void mpt2sas_base_stop_watchdog(struct MPT2SAS_ADAPTER *ioc); @@ -1119,7 +1137,6 @@ struct _sas_device *__mpt2sas_get_sdev_by_addr( struct MPT2SAS_ADAPTER *ioc, u64 sas_address); void mpt2sas_port_enable_complete(struct MPT2SAS_ADAPTER *ioc); - void mpt2sas_scsih_reset_handler(struct MPT2SAS_ADAPTER *ioc, int reset_phase); /* config shared API */ diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c index 4e509604b5716..3694b63bd9931 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c +++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c @@ -427,13 +427,16 @@ static int _ctl_verify_adapter(int ioc_number, struct MPT2SAS_ADAPTER **iocpp) { struct MPT2SAS_ADAPTER *ioc; - + /* global ioc lock to protect controller on list operations */ + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { if (ioc->id != ioc_number) continue; + spin_unlock(&gioc_lock); *iocpp = ioc; return ioc_number; } + spin_unlock(&gioc_lock); *iocpp = NULL; return -1; } @@ -522,10 +525,15 @@ _ctl_poll(struct file *filep, poll_table *wait) poll_wait(filep, &ctl_poll_wait, wait); + /* global ioc lock to protect controller on list operations */ + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt2sas_ioc_list, list) { - if (ioc->aen_event_read_flag) + if (ioc->aen_event_read_flag) { + spin_unlock(&gioc_lock); return POLLIN | POLLRDNORM; + } } + spin_unlock(&gioc_lock); return 0; } @@ -2168,16 +2176,23 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, if (_ctl_verify_adapter(ioctl_header.ioc_number, &ioc) == -1 || !ioc) return -ENODEV; + /* pci_access_mutex lock acquired by ioctl path */ + mutex_lock(&ioc->pci_access_mutex); if (ioc->shost_recovery || ioc->pci_error_recovery || - ioc->is_driver_loading) - return -EAGAIN; + ioc->is_driver_loading || ioc->remove_host) { + ret = -EAGAIN; + goto out_unlock_pciaccess; + } state = (file->f_flags & O_NONBLOCK) ? NON_BLOCKING : BLOCKING; if (state == NON_BLOCKING) { - if (!mutex_trylock(&ioc->ctl_cmds.mutex)) - return -EAGAIN; + if (!mutex_trylock(&ioc->ctl_cmds.mutex)) { + ret = -EAGAIN; + goto out_unlock_pciaccess; + } } else if (mutex_lock_interruptible(&ioc->ctl_cmds.mutex)) { - return -ERESTARTSYS; + ret = -ERESTARTSYS; + goto out_unlock_pciaccess; } switch (cmd) { @@ -2258,6 +2273,8 @@ _ctl_ioctl_main(struct file *file, unsigned int cmd, void __user *arg, } mutex_unlock(&ioc->ctl_cmds.mutex); +out_unlock_pciaccess: + mutex_unlock(&ioc->pci_access_mutex); return ret; } @@ -2711,6 +2728,12 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, "warpdrive\n", ioc->name, __func__); goto out; } + /* pci_access_mutex lock acquired by sysfs show path */ + mutex_lock(&ioc->pci_access_mutex); + if (ioc->pci_error_recovery || ioc->remove_host) { + mutex_unlock(&ioc->pci_access_mutex); + return 0; + } /* allocate upto GPIOVal 36 entries */ sz = offsetof(Mpi2IOUnitPage3_t, GPIOVal) + (sizeof(u16) * 36); @@ -2749,6 +2772,7 @@ _ctl_BRM_status_show(struct device *cdev, struct device_attribute *attr, out: kfree(io_unit_pg3); + mutex_unlock(&ioc->pci_access_mutex); return rc; } static DEVICE_ATTR(BRM_status, S_IRUGO, _ctl_BRM_status_show, NULL); diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c index c0ff55b0d3ccc..0ad09b2bff9c6 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c +++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c @@ -79,7 +79,8 @@ static int _scsih_scan_finished(struct Scsi_Host *shost, unsigned long time); /* global parameters */ LIST_HEAD(mpt2sas_ioc_list); - +/* global ioc lock for list operations */ +DEFINE_SPINLOCK(gioc_lock); /* local parameters */ static u8 scsi_io_cb_idx = -1; static u8 tm_cb_idx = -1; @@ -321,8 +322,10 @@ _scsih_set_debug_level(const char *val, struct kernel_param *kp) return ret; printk(KERN_INFO "setting logging_level(0x%08x)\n", logging_level); + spin_lock(&gioc_lock); list_for_each_entry(ioc, &mpt2sas_ioc_list, list) ioc->logging_level = logging_level; + spin_unlock(&gioc_lock); return 0; } module_param_call(logging_level, _scsih_set_debug_level, param_get_int, @@ -8081,7 +8084,9 @@ _scsih_remove(struct pci_dev *pdev) sas_remove_host(shost); scsi_remove_host(shost); mpt2sas_base_detach(ioc); + spin_lock(&gioc_lock); list_del(&ioc->list); + spin_unlock(&gioc_lock); scsi_host_put(shost); } @@ -8394,7 +8399,9 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc = shost_priv(shost); memset(ioc, 0, sizeof(struct MPT2SAS_ADAPTER)); INIT_LIST_HEAD(&ioc->list); + spin_lock(&gioc_lock); list_add_tail(&ioc->list, &mpt2sas_ioc_list); + spin_unlock(&gioc_lock); ioc->shost = shost; ioc->id = mpt_ids++; sprintf(ioc->name, "%s%d", MPT2SAS_DRIVER_NAME, ioc->id); @@ -8419,6 +8426,8 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) ioc->schedule_dead_ioc_flush_running_cmds = &_scsih_flush_running_cmds; /* misc semaphores and spin locks */ mutex_init(&ioc->reset_in_progress_mutex); + /* initializing pci_access_mutex lock */ + mutex_init(&ioc->pci_access_mutex); spin_lock_init(&ioc->ioc_reset_in_progress_lock); spin_lock_init(&ioc->scsi_lookup_lock); spin_lock_init(&ioc->sas_device_lock); @@ -8521,7 +8530,9 @@ _scsih_probe(struct pci_dev *pdev, const struct pci_device_id *id) out_attach_fail: destroy_workqueue(ioc->firmware_event_thread); out_thread_fail: + spin_lock(&gioc_lock); list_del(&ioc->list); + spin_unlock(&gioc_lock); scsi_host_put(shost); return rv; } -- GitLab From 420fa2118c020a005e9f0311c1e0b27414306618 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Wed, 19 Aug 2015 11:18:44 +0530 Subject: [PATCH 6586/7006] fcoe: Convert use of __constant_htons to htons In little endian cases, the macro htons unfolds to __swab16 which provides special case for constants. In big endian cases, __constant_htons and htons expand directly to the same expression. So, replace __constant_htons with htons with the goal of getting rid of the definition of __constant_htons completely. The semantic patch that performs this transformation is as follows: @@expression x;@@ - __constant_htons(x) + htons(x) Signed-off-by: Vaishali Thakkar Acked-by: Vasu Dev Signed-off-by: James Bottomley --- drivers/scsi/fcoe/fcoe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index ec193a8357d70..d3eb80c46bbe2 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -364,7 +364,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe, * on the ethertype for the given device */ fcoe->fcoe_packet_type.func = fcoe_rcv; - fcoe->fcoe_packet_type.type = __constant_htons(ETH_P_FCOE); + fcoe->fcoe_packet_type.type = htons(ETH_P_FCOE); fcoe->fcoe_packet_type.dev = netdev; dev_add_pack(&fcoe->fcoe_packet_type); -- GitLab From 537b604c8b3aa8b96fe35f87dd085816552e294c Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Thu, 27 Aug 2015 20:16:37 +0200 Subject: [PATCH 6587/7006] scsi: fix scsi_error_handler vs. scsi_host_dev_release race b9d5c6b7ef57 ("[SCSI] cleanup setting task state in scsi_error_handler()") has introduced a race between scsi_error_handler and scsi_host_dev_release resulting in the hang when the device goes away because scsi_error_handler might miss a wake up: CPU0 CPU1 scsi_error_handler scsi_host_dev_release kthread_stop() kthread_should_stop() test_bit(KTHREAD_SHOULD_STOP) set_bit(KTHREAD_SHOULD_STOP) wake_up_process() wait_for_completion() set_current_state(TASK_INTERRUPTIBLE) schedule() The most straightforward solution seems to be to invert the ordering of the set_current_state and kthread_should_stop. The issue has been noticed during reboot test on a 3.0 based kernel but the current code seems to be affected in the same way. [jejb: additional comment added] Cc: # 3.6+ Reported-and-debugged-by: Mike Mayer Signed-off-by: Michal Hocko Reviewed-by: Dan Williams Reviewed-by: Hannes Reinecke Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 410911c31c67f..b5bbc122c414c 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -2179,8 +2179,17 @@ int scsi_error_handler(void *data) * We never actually get interrupted because kthread_run * disables signal delivery for the created thread. */ - while (!kthread_should_stop()) { + while (true) { + /* + * The sequence in kthread_stop() sets the stop flag first + * then wakes the process. To avoid missed wakeups, the task + * should always be in a non running state before the stop + * flag is checked + */ set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop()) + break; + if ((shost->host_failed == 0 && shost->host_eh_scheduled == 0) || shost->host_failed != atomic_read(&shost->host_busy)) { SCSI_LOG_ERROR_RECOVERY(1, -- GitLab From 99c79eceb152e2ac7f8a81ff55d4a810f730ec7b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 4 Sep 2015 12:47:28 +0200 Subject: [PATCH 6588/7006] lan78xx: Fix ladv/radv error handling in lan78xx_link_reset() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/usb/lan78xx.c: In function ‘lan78xx_link_reset’: net/usb/lan78xx.c:1107: warning: comparison is always false due to limited range of data type net/usb/lan78xx.c:1111: warning: comparison is always false due to limited range of data type Assigning return values that can be negative error codes to "u16" variables makes them positive, ignoring the errors. Hence use "int" instead. Drop the "unlikely"s (unlikely considered harmful) and propagate the actual error values instead of overriding them to -EIO while we're at it. Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller --- drivers/net/usb/lan78xx.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 39364a45af404..a39518fc93aad 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -1049,8 +1049,7 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) { struct mii_if_info *mii = &dev->mii; struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; - u16 ladv, radv; - int ret; + int ladv, radv, ret; u32 buf; /* clear PHY interrupt status */ @@ -1104,12 +1103,12 @@ static int lan78xx_link_reset(struct lan78xx_net *dev) } ladv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_ADVERTISE); - if (unlikely(ladv < 0)) - return -EIO; + if (ladv < 0) + return ladv; radv = lan78xx_mdio_read(dev->net, mii->phy_id, MII_LPA); - if (unlikely(radv < 0)) - return -EIO; + if (radv < 0) + return radv; netif_dbg(dev, link, dev->net, "speed: %u duplex: %d anadv: 0x%04x anlpa: 0x%04x", -- GitLab From 0f1b7354e0d65ad528b820a8a46c15d70954f699 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 4 Sep 2015 12:49:32 +0200 Subject: [PATCH 6589/7006] vxlan: Refactor vxlan_udp_encap_recv() to kill compiler warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/vxlan.c: In function ‘vxlan_udp_encap_recv’: drivers/net/vxlan.c:1226: warning: ‘info’ may be used uninitialized in this function While this warning is a false positive, it can be killed easily by getting rid of the pointer intermediary and referring directly to the ip_tunnel_info structure. Signed-off-by: Geert Uytterhoeven Reviewed-by: Jiri Benc Acked-by: Thomas Graf Signed-off-by: David S. Miller --- drivers/net/vxlan.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c index ce988fd01b348..cf8b7f0473b39 100644 --- a/drivers/net/vxlan.c +++ b/drivers/net/vxlan.c @@ -1223,7 +1223,6 @@ drop: static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { struct metadata_dst *tun_dst = NULL; - struct ip_tunnel_info *info; struct vxlan_sock *vs; struct vxlanhdr *vxh; u32 flags, vni; @@ -1270,8 +1269,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (!tun_dst) goto drop; - info = &tun_dst->u.tun_info; - md = ip_tunnel_info_opts(info); + md = ip_tunnel_info_opts(&tun_dst->u.tun_info); } else { memset(md, 0, sizeof(*md)); } @@ -1286,7 +1284,7 @@ static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb) md->gbp = ntohs(gbp->policy_id); if (tun_dst) - info->key.tun_flags |= TUNNEL_VXLAN_OPT; + tun_dst->u.tun_info.key.tun_flags |= TUNNEL_VXLAN_OPT; if (gbp->dont_learn) md->gbp |= VXLAN_GBP_DONT_LEARN; -- GitLab From e5a5837da756b4826d40636239718eb8f76775fd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 4 Sep 2015 14:44:12 +0200 Subject: [PATCH 6590/7006] ethernet: synopsys: SYNOPSYS_DWC_ETH_QOS should depend on HAS_DMA If NO_DMA=y: ERROR: "dma_alloc_coherent" [drivers/net/ethernet/synopsys/dwc_eth_qos.ko] undefined! ERROR: "dma_free_coherent" [drivers/net/ethernet/synopsys/dwc_eth_qos.ko] undefined! ERROR: "dma_unmap_single" [drivers/net/ethernet/synopsys/dwc_eth_qos.ko] undefined! ERROR: "dma_map_page" [drivers/net/ethernet/synopsys/dwc_eth_qos.ko] undefined! ERROR: "dma_mapping_error" [drivers/net/ethernet/synopsys/dwc_eth_qos.ko] undefined! ERROR: "dma_map_single" [drivers/net/ethernet/synopsys/dwc_eth_qos.ko] undefined! Signed-off-by: Geert Uytterhoeven Acked-by: Lars Persson Signed-off-by: David S. Miller --- drivers/net/ethernet/synopsys/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/synopsys/Kconfig b/drivers/net/ethernet/synopsys/Kconfig index a8f315106742d..8276ee5a7d541 100644 --- a/drivers/net/ethernet/synopsys/Kconfig +++ b/drivers/net/ethernet/synopsys/Kconfig @@ -20,7 +20,7 @@ config SYNOPSYS_DWC_ETH_QOS select PHYLIB select CRC32 select MII - depends on OF + depends on OF && HAS_DMA ---help--- This driver supports the DWC Ethernet QoS from Synopsys -- GitLab From 585e7e1a544c5b13b2a0014c23f3cb6622e8c995 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Fri, 4 Sep 2015 11:22:24 -0400 Subject: [PATCH 6591/7006] net: dsa: mv88e6171: add hardware 802.1Q support The Marvell 88E6171 switch is in the 88E6351 family, which supports 802.1Q, thus add support from the generic mv88e6xxx functions. Signed-off-by: Vivien Didelot Reviewed-by: Andrew Lunn Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6171.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index d54b7400e8d82..c2daaf087761c 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -117,6 +117,11 @@ struct dsa_switch_driver mv88e6171_switch_driver = { .port_join_bridge = mv88e6xxx_join_bridge, .port_leave_bridge = mv88e6xxx_leave_bridge, .port_stp_update = mv88e6xxx_port_stp_update, + .port_pvid_get = mv88e6xxx_port_pvid_get, + .port_pvid_set = mv88e6xxx_port_pvid_set, + .port_vlan_add = mv88e6xxx_port_vlan_add, + .port_vlan_del = mv88e6xxx_port_vlan_del, + .vlan_getnext = mv88e6xxx_vlan_getnext, .port_fdb_add = mv88e6xxx_port_fdb_add, .port_fdb_del = mv88e6xxx_port_fdb_del, .port_fdb_getnext = mv88e6xxx_port_fdb_getnext, -- GitLab From f88f69dd17f150e2abcc7e2d95f895f2546fa381 Mon Sep 17 00:00:00 2001 From: Joe Stringer Date: Fri, 4 Sep 2015 13:07:40 -0700 Subject: [PATCH 6592/7006] openvswitch: Remove conntrack Kconfig option. There's no particular desire to have conntrack action support in Open vSwitch as an independently configurable bit, rather just to ensure there is not a hard dependency. This exposed option doesn't accurately reflect the conntrack dependency when enabled, so simplify this by removing the option. Compile the support if NF_CONNTRACK is enabled. Fixes: 7f8a436eaa2c ("openvswitch: Add conntrack action") Signed-off-by: Joe Stringer Acked-by: Pravin B Shelar Signed-off-by: David S. Miller --- net/openvswitch/Kconfig | 12 +----------- net/openvswitch/Makefile | 4 +++- net/openvswitch/conntrack.h | 4 ++-- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/net/openvswitch/Kconfig b/net/openvswitch/Kconfig index af7cdef42066b..2a071f470d578 100644 --- a/net/openvswitch/Kconfig +++ b/net/openvswitch/Kconfig @@ -5,6 +5,7 @@ config OPENVSWITCH tristate "Open vSwitch" depends on INET + depends on (!NF_CONNTRACK || NF_CONNTRACK) select LIBCRC32C select MPLS select NET_MPLS_GSO @@ -31,17 +32,6 @@ config OPENVSWITCH If unsure, say N. -config OPENVSWITCH_CONNTRACK - bool "Open vSwitch conntrack action support" - depends on OPENVSWITCH - depends on NF_CONNTRACK - default OPENVSWITCH - ---help--- - If you say Y here, then Open vSwitch module will be able to pass - packets through conntrack. - - Say N to exclude this support and reduce the binary size. - config OPENVSWITCH_GRE tristate "Open vSwitch GRE tunneling support" depends on OPENVSWITCH diff --git a/net/openvswitch/Makefile b/net/openvswitch/Makefile index 5b5913b06f540..60f809085b920 100644 --- a/net/openvswitch/Makefile +++ b/net/openvswitch/Makefile @@ -15,7 +15,9 @@ openvswitch-y := \ vport-internal_dev.o \ vport-netdev.o -openvswitch-$(CONFIG_OPENVSWITCH_CONNTRACK) += conntrack.o +ifneq ($(CONFIG_NF_CONNTRACK),) +openvswitch-y += conntrack.o +endif obj-$(CONFIG_OPENVSWITCH_VXLAN)+= vport-vxlan.o obj-$(CONFIG_OPENVSWITCH_GENEVE)+= vport-geneve.o diff --git a/net/openvswitch/conntrack.h b/net/openvswitch/conntrack.h index 3cb30667a7dcb..43f5dd7a55774 100644 --- a/net/openvswitch/conntrack.h +++ b/net/openvswitch/conntrack.h @@ -19,7 +19,7 @@ struct ovs_conntrack_info; enum ovs_key_attr; -#if defined(CONFIG_OPENVSWITCH_CONNTRACK) +#if IS_ENABLED(CONFIG_NF_CONNTRACK) void ovs_ct_init(struct net *); void ovs_ct_exit(struct net *); bool ovs_ct_verify(struct net *, enum ovs_key_attr attr); @@ -82,5 +82,5 @@ static inline int ovs_ct_put_key(const struct sw_flow_key *key, } static inline void ovs_ct_free_action(const struct nlattr *a) { } -#endif +#endif /* CONFIG_NF_CONNTRACK */ #endif /* ovs_conntrack.h */ -- GitLab From bd1a05ee98b06c9a20138c45f96ccfddf3163f93 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Thu, 3 Sep 2015 23:22:16 +0300 Subject: [PATCH 6593/7006] fixed_phy: pass 'irq' to fixed_phy_add() I've noticed that fixed_phy_register() ignores its 'irq' parameter instead of passing it to fixed_phy_add(). Luckily, fixed_phy_register() seems to always be called with PHY_POLL for 'irq'... :-) Fixes: a75951217472 ("net: phy: extend fixed driver with fixed_phy_register()") Signed-off-by: Sergei Shtylyov Acked-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/phy/fixed_phy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c index 12c7eb2c604e1..fb1299c6326ec 100644 --- a/drivers/net/phy/fixed_phy.c +++ b/drivers/net/phy/fixed_phy.c @@ -325,7 +325,7 @@ struct phy_device *fixed_phy_register(unsigned int irq, phy_addr = phy_fixed_addr++; spin_unlock(&phy_fixed_addr_lock); - ret = fixed_phy_add(PHY_POLL, phy_addr, status, link_gpio); + ret = fixed_phy_add(irq, phy_addr, status, link_gpio); if (ret < 0) return ERR_PTR(ret); -- GitLab From 46cdc9be0841b30ba612aec1878cb746faf280a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fran=C3=A7ois=20romieu?= Date: Fri, 4 Sep 2015 23:05:42 +0200 Subject: [PATCH 6594/7006] cxgb4: fix usage of uninitialized variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c: In function ‘init_one’: drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c:4579:8: warning: ‘chip’ may be used uninitialized in this function [-Wmaybe-uninitialized] chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); ^ drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c:4571:11: note: ‘chip’ was declared here int ver, chip; ^ Fixes: d86bd29e0b31 ("cxgb4/cxgb4vf: read the correct bits of PL Who Am I register") Signed-off-by: Francois Romieu Cc: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index eb22d58743e22..592a4d66169c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4568,28 +4568,23 @@ static void free_some_resources(struct adapter *adapter) static int get_chip_type(struct pci_dev *pdev, u32 pl_rev) { - int ver, chip; u16 device_id; /* Retrieve adapter's device ID */ pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); - ver = device_id >> 12; - switch (ver) { + + switch (device_id >> 12) { case CHELSIO_T4: - chip |= CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); - break; + return CHELSIO_CHIP_CODE(CHELSIO_T4, pl_rev); case CHELSIO_T5: - chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev); - break; + return CHELSIO_CHIP_CODE(CHELSIO_T5, pl_rev); case CHELSIO_T6: - chip |= CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); - break; + return CHELSIO_CHIP_CODE(CHELSIO_T6, pl_rev); default: dev_err(&pdev->dev, "Device %d is not supported\n", device_id); - return -EINVAL; } - return chip; + return -EINVAL; } static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) -- GitLab From e7e98d76777ffba334bbf7a61939c5de48acc5a0 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Thu, 30 Jul 2015 13:31:42 +0100 Subject: [PATCH 6595/7006] Documentation/features/vm: Meta2 is capable of THP Change metag Transparent Huge Pages (THP) support from .. to TODO. Meta2 has variable sized pages, between 4KB and 4MB, specified at the 1st level page table level, and already supports hugetlbfs, so supporting THP is theoretically possible too. Signed-off-by: James Hogan Acked-by: Ingo Molnar Cc: Jonathan Corbet Cc: linux-metag@vger.kernel.org Cc: linux-doc@vger.kernel.org --- Documentation/features/vm/THP/arch-support.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/features/vm/THP/arch-support.txt b/Documentation/features/vm/THP/arch-support.txt index 972d02c2a74cc..df384e3e845f7 100644 --- a/Documentation/features/vm/THP/arch-support.txt +++ b/Documentation/features/vm/THP/arch-support.txt @@ -20,7 +20,7 @@ | ia64: | TODO | | m32r: | .. | | m68k: | .. | - | metag: | .. | + | metag: | TODO | | microblaze: | .. | | mips: | ok | | mn10300: | .. | -- GitLab From 5ee20bc792467d7d612157e0a9962765aa943b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Rast=C3=A9n?= Date: Sun, 6 Sep 2015 18:16:13 +0200 Subject: [PATCH 6596/7006] ALSA: usb-audio: Change internal PCM order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New PCMs will now be added to the end of the chip's PCM list instead of to the front. This changes the way streams are combined so that the first capture stream will now be merged with the first playback stream instead of the last. This fixes a problem with ASUS U7. Cards with one playback stream and cards without capture streams should be unaffected by this change. Exception added for M-Audio Audiophile USB (tm) since it seems to have a fix to swap capture stream numbering in alsa-lib conf/cards/USB-audio.conf Signed-off-by: Johan Rastén Signed-off-by: Takashi Iwai --- sound/usb/stream.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 310a3822d2b72..970086015cded 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -377,7 +377,15 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, snd_usb_init_substream(as, stream, fp); - list_add(&as->list, &chip->pcm_list); + /* + * Keep using head insertion for M-Audio Audiophile USB (tm) which has a + * fix to swap capture stream order in conf/cards/USB-audio.conf + */ + if (chip->usb_id == USB_ID(0x0763, 0x2003)) + list_add(&as->list, &chip->pcm_list); + else + list_add_tail(&as->list, &chip->pcm_list); + chip->pcm_devs++; snd_usb_proc_pcm_format_add(as); -- GitLab From 7d160a6c462c2c690e074c173b43aad7204049ad Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 5 Sep 2015 19:06:57 -0400 Subject: [PATCH 6597/7006] NFSv4: Express delegation limit in units of pages Since we're tracking modifications to the page cache on a per-page basis, it makes sense to express the limit to how much we may cache in units of pages. Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 4 ++-- fs/nfs/delegation.h | 2 +- fs/nfs/nfs4xdr.c | 16 ++++++++++------ include/linux/nfs_xdr.h | 2 +- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 029d688a969f4..cd503cc2251cf 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -175,7 +175,7 @@ void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, if (delegation->inode != NULL) { nfs4_stateid_copy(&delegation->stateid, &res->delegation); delegation->type = res->delegation_type; - delegation->maxsize = res->maxsize; + delegation->pagemod_limit = res->pagemod_limit; oldcred = delegation->cred; delegation->cred = get_rpccred(cred); clear_bit(NFS_DELEGATION_NEED_RECLAIM, @@ -337,7 +337,7 @@ int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct return -ENOMEM; nfs4_stateid_copy(&delegation->stateid, &res->delegation); delegation->type = res->delegation_type; - delegation->maxsize = res->maxsize; + delegation->pagemod_limit = res->pagemod_limit; delegation->change_attr = inode->i_version; delegation->cred = get_rpccred(cred); delegation->inode = inode; diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index e3c20a3ccc937..554178a173766 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -18,7 +18,7 @@ struct nfs_delegation { struct inode *inode; nfs4_stateid stateid; fmode_t type; - loff_t maxsize; + unsigned long pagemod_limit; __u64 change_attr; unsigned long flags; spinlock_t lock; diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index ff4784c54e04f..788adf3897c74 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c @@ -4932,24 +4932,28 @@ static int decode_lookup(struct xdr_stream *xdr) } /* This is too sick! */ -static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize) +static int decode_space_limit(struct xdr_stream *xdr, + unsigned long *pagemod_limit) { __be32 *p; uint32_t limit_type, nblocks, blocksize; + u64 maxsize = 0; p = xdr_inline_decode(xdr, 12); if (unlikely(!p)) goto out_overflow; limit_type = be32_to_cpup(p++); switch (limit_type) { - case 1: - xdr_decode_hyper(p, maxsize); + case NFS4_LIMIT_SIZE: + xdr_decode_hyper(p, &maxsize); break; - case 2: + case NFS4_LIMIT_BLOCKS: nblocks = be32_to_cpup(p++); blocksize = be32_to_cpup(p); - *maxsize = (uint64_t)nblocks * (uint64_t)blocksize; + maxsize = (uint64_t)nblocks * (uint64_t)blocksize; } + maxsize >>= PAGE_CACHE_SHIFT; + *pagemod_limit = min_t(u64, maxsize, ULONG_MAX); return 0; out_overflow: print_overflow_msg(__func__, xdr); @@ -4977,7 +4981,7 @@ static int decode_rw_delegation(struct xdr_stream *xdr, break; case NFS4_OPEN_DELEGATE_WRITE: res->delegation_type = FMODE_WRITE|FMODE_READ; - if (decode_space_limit(xdr, &res->maxsize) < 0) + if (decode_space_limit(xdr, &res->pagemod_limit) < 0) return -EIO; } return decode_ace(xdr, NULL, res->server->nfs_client); diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index b4392d86d157a..52faf7e96c65d 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h @@ -406,8 +406,8 @@ struct nfs_openres { const struct nfs_server *server; fmode_t delegation_type; nfs4_stateid delegation; + unsigned long pagemod_limit; __u32 do_recall; - __u64 maxsize; __u32 attrset[NFS4_BITMAP_SIZE]; struct nfs4_string *owner; struct nfs4_string *group_owner; -- GitLab From 5445b1fbd123420bffed5e629a420aa2a16bf849 Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Sat, 5 Sep 2015 19:06:58 -0400 Subject: [PATCH 6598/7006] NFSv4: Respect the server imposed limit on how many changes we may cache The NFSv4 delegation spec allows the server to tell a client to limit how much data it cache after the file is closed. In return, the server guarantees enough free space to avoid ENOSPC situations, etc. Prior to this patch, we assumed we could always cache aggressively after close. Unfortunately, this causes problems with servers that set the limit to 0 and therefore do not offer any ENOSPC guarantees. Signed-off-by: Trond Myklebust --- fs/nfs/delegation.c | 25 +++++++++++++++++++++++++ fs/nfs/delegation.h | 1 + fs/nfs/file.c | 10 +--------- fs/nfs/internal.h | 1 - fs/nfs/nfs4file.c | 29 ++++++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index cd503cc2251cf..2714ef835bdd4 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c @@ -900,3 +900,28 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, rcu_read_unlock(); return ret; } + +/** + * nfs4_delegation_flush_on_close - Check if we must flush file on close + * @inode: inode to check + * + * This function checks the number of outstanding writes to the file + * against the delegation 'space_limit' field to see if + * the spec requires us to flush the file on close. + */ +bool nfs4_delegation_flush_on_close(const struct inode *inode) +{ + struct nfs_inode *nfsi = NFS_I(inode); + struct nfs_delegation *delegation; + bool ret = true; + + rcu_read_lock(); + delegation = rcu_dereference(nfsi->delegation); + if (delegation == NULL || !(delegation->type & FMODE_WRITE)) + goto out; + if (nfsi->nrequests < delegation->pagemod_limit) + ret = false; +out: + rcu_read_unlock(); + return ret; +} diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 554178a173766..a44829173e573 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h @@ -61,6 +61,7 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); int nfs4_have_delegation(struct inode *inode, fmode_t flags); int nfs4_check_delegation(struct inode *inode, fmode_t flags); +bool nfs4_delegation_flush_on_close(const struct inode *inode); #endif diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 526a2681d9750..c0f9b1ed12b9e 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -142,7 +142,7 @@ EXPORT_SYMBOL_GPL(nfs_file_llseek); /* * Flush all dirty pages, and check for write errors. */ -int +static int nfs_file_flush(struct file *file, fl_owner_t id) { struct inode *inode = file_inode(file); @@ -153,17 +153,9 @@ nfs_file_flush(struct file *file, fl_owner_t id) if ((file->f_mode & FMODE_WRITE) == 0) return 0; - /* - * If we're holding a write delegation, then just start the i/o - * but don't wait for completion (or send a commit). - */ - if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE)) - return filemap_fdatawrite(file->f_mapping); - /* Flush writes to the server and return any errors */ return vfs_fsync(file, 0); } -EXPORT_SYMBOL_GPL(nfs_file_flush); ssize_t nfs_file_read(struct kiocb *iocb, struct iov_iter *to) diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 9ab3b1c21bb41..56cfde26fb9ce 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h @@ -360,7 +360,6 @@ int nfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *) /* file.c */ int nfs_file_fsync_commit(struct file *, loff_t, loff_t, int); loff_t nfs_file_llseek(struct file *, loff_t, int); -int nfs_file_flush(struct file *, fl_owner_t); ssize_t nfs_file_read(struct kiocb *, struct iov_iter *); ssize_t nfs_file_splice_read(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c index 43f1590b9240d..b0dbe0abed536 100644 --- a/fs/nfs/nfs4file.c +++ b/fs/nfs/nfs4file.c @@ -6,7 +6,9 @@ #include #include #include +#include "delegation.h" #include "internal.h" +#include "iostat.h" #include "fscache.h" #include "pnfs.h" @@ -99,6 +101,31 @@ out_drop: goto out_put_ctx; } +/* + * Flush all dirty pages, and check for write errors. + */ +static int +nfs4_file_flush(struct file *file, fl_owner_t id) +{ + struct inode *inode = file_inode(file); + + dprintk("NFS: flush(%pD2)\n", file); + + nfs_inc_stats(inode, NFSIOS_VFSFLUSH); + if ((file->f_mode & FMODE_WRITE) == 0) + return 0; + + /* + * If we're holding a write delegation, then check if we're required + * to flush the i/o on close. If not, then just start the i/o now. + */ + if (!nfs4_delegation_flush_on_close(inode)) + return filemap_fdatawrite(file->f_mapping); + + /* Flush writes to the server and return any errors */ + return vfs_fsync(file, 0); +} + static int nfs4_file_fsync(struct file *file, loff_t start, loff_t end, int datasync) { @@ -177,7 +204,7 @@ const struct file_operations nfs4_file_operations = { .write_iter = nfs_file_write, .mmap = nfs_file_mmap, .open = nfs4_file_open, - .flush = nfs_file_flush, + .flush = nfs4_file_flush, .release = nfs_file_release, .fsync = nfs4_file_fsync, .lock = nfs_lock, -- GitLab From 549a14c14b2f1868b81e5417a33b6d79e6da1d00 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Tue, 18 Aug 2015 13:59:28 +0800 Subject: [PATCH 6599/7006] nios2/time: Migrate to new 'set-state' interface Migrate nios2 driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. Cc: Ley Foon Tan Cc: Tobias Klauser Cc: Herbert Xu Cc: Dmitry Torokhov Cc: nios2-dev@lists.rocketboards.org Signed-off-by: Viresh Kumar Acked-by: Ley Foon Tan --- arch/nios2/kernel/time.c | 49 ++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c index 9e3cc8a40ee9f..bbc3f9157f9c4 100644 --- a/arch/nios2/kernel/time.c +++ b/arch/nios2/kernel/time.c @@ -130,7 +130,7 @@ static void nios2_timer_stop(struct nios2_timer *timer) } static void nios2_timer_config(struct nios2_timer *timer, unsigned long period, - enum clock_event_mode mode) + bool periodic) { u16 ctrl; @@ -148,7 +148,7 @@ static void nios2_timer_config(struct nios2_timer *timer, unsigned long period, timer_writew(timer, period >> 16, ALTERA_TIMER_PERIODH_REG); ctrl |= ALTERA_TIMER_CONTROL_START_MSK | ALTERA_TIMER_CONTROL_ITO_MSK; - if (mode == CLOCK_EVT_MODE_PERIODIC) + if (periodic) ctrl |= ALTERA_TIMER_CONTROL_CONT_MSK; else ctrl &= ~ALTERA_TIMER_CONTROL_CONT_MSK; @@ -160,32 +160,38 @@ static int nios2_timer_set_next_event(unsigned long delta, { struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); - nios2_timer_config(&nios2_ced->timer, delta, evt->mode); + nios2_timer_config(&nios2_ced->timer, delta, false); return 0; } -static void nios2_timer_set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) +static int nios2_timer_shutdown(struct clock_event_device *evt) +{ + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + struct nios2_timer *timer = &nios2_ced->timer; + + nios2_timer_stop(timer); + return 0; +} + +static int nios2_timer_set_periodic(struct clock_event_device *evt) { unsigned long period; struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); struct nios2_timer *timer = &nios2_ced->timer; - switch (mode) { - case CLOCK_EVT_MODE_PERIODIC: - period = DIV_ROUND_UP(timer->freq, HZ); - nios2_timer_config(timer, period, CLOCK_EVT_MODE_PERIODIC); - break; - case CLOCK_EVT_MODE_ONESHOT: - case CLOCK_EVT_MODE_UNUSED: - case CLOCK_EVT_MODE_SHUTDOWN: - nios2_timer_stop(timer); - break; - case CLOCK_EVT_MODE_RESUME: - nios2_timer_start(timer); - break; - } + period = DIV_ROUND_UP(timer->freq, HZ); + nios2_timer_config(timer, period, true); + return 0; +} + +static int nios2_timer_resume(struct clock_event_device *evt) +{ + struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt); + struct nios2_timer *timer = &nios2_ced->timer; + + nios2_timer_start(timer); + return 0; } irqreturn_t timer_interrupt(int irq, void *dev_id) @@ -218,7 +224,10 @@ static struct nios2_clockevent_dev nios2_ce = { .rating = 250, .shift = 32, .set_next_event = nios2_timer_set_next_event, - .set_mode = nios2_timer_set_mode, + .set_state_shutdown = nios2_timer_shutdown, + .set_state_periodic = nios2_timer_set_periodic, + .set_state_oneshot = nios2_timer_shutdown, + .tick_resume = nios2_timer_resume, }, }; -- GitLab From db5a7e55468147f28d1a408880564b61c542e4f8 Mon Sep 17 00:00:00 2001 From: Bernd Weiberg Date: Fri, 4 Sep 2015 17:03:03 +0800 Subject: [PATCH 6600/7006] nios2: fixed variable imm16 to s16 Fxid variable imm16 to s16 instead of u16, offset might be negative. Signed-off-by: Bernd Weiberg Signed-off-by: Ley Foon Tan --- arch/nios2/kernel/misaligned.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/nios2/kernel/misaligned.c b/arch/nios2/kernel/misaligned.c index 4e5907a0cabe8..89fe0b6ee339c 100644 --- a/arch/nios2/kernel/misaligned.c +++ b/arch/nios2/kernel/misaligned.c @@ -71,7 +71,7 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) u32 isn, addr, val; int in_kernel; u8 a, b, d0, d1, d2, d3; - u16 imm16; + s16 imm16; unsigned int fault; /* back up one instruction */ -- GitLab From 3fb39c482c39760ab3b5e59f30868c988c25578d Mon Sep 17 00:00:00 2001 From: Bernd Weiberg Date: Fri, 4 Sep 2015 16:59:45 +0800 Subject: [PATCH 6601/7006] nios2: remove unused statistic counters Removed some statistic counters to improve the performance of the handler. Signed-off-by: Bernd Weiberg Signed-off-by: Ley Foon Tan --- arch/nios2/kernel/misaligned.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/arch/nios2/kernel/misaligned.c b/arch/nios2/kernel/misaligned.c index 89fe0b6ee339c..23e0544e117ce 100644 --- a/arch/nios2/kernel/misaligned.c +++ b/arch/nios2/kernel/misaligned.c @@ -32,8 +32,6 @@ #define INST_STW 0x15 #define INST_LDW 0x17 -static unsigned long ma_user, ma_kern, ma_skipped, ma_half, ma_word; - static unsigned int ma_usermode; #define UM_WARN 0x01 #define UM_FIXUP 0x02 @@ -53,7 +51,6 @@ static int reg_offsets[32]; static inline u32 get_reg_val(struct pt_regs *fp, int reg) { u8 *p = ((u8 *)fp) + reg_offsets[reg]; - return *(u32 *)p; } @@ -78,7 +75,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) fp->ea -= 4; if (fixup_exception(fp)) { - ma_skipped++; return; } @@ -103,18 +99,11 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) fault |= __get_user(d1, (u8 *)(addr+1)); val = (d1 << 8) | d0; put_reg_val(fp, b, val); - ma_half++; break; case INST_STH: val = get_reg_val(fp, b); d1 = val >> 8; d0 = val >> 0; - - pr_debug("sth: ra=%d (%08x) rb=%d (%08x), imm16 %04x addr %08x val %08x\n", - a, get_reg_val(fp, a), - b, get_reg_val(fp, b), - imm16, addr, val); - if (in_kernel) { *(u8 *)(addr+0) = d0; *(u8 *)(addr+1) = d1; @@ -122,14 +111,12 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) fault |= __put_user(d0, (u8 *)(addr+0)); fault |= __put_user(d1, (u8 *)(addr+1)); } - ma_half++; break; case INST_LDH: fault |= __get_user(d0, (u8 *)(addr+0)); fault |= __get_user(d1, (u8 *)(addr+1)); val = (short)((d1 << 8) | d0); put_reg_val(fp, b, val); - ma_half++; break; case INST_STW: val = get_reg_val(fp, b); @@ -148,7 +135,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) fault |= __put_user(d2, (u8 *)(addr+2)); fault |= __put_user(d3, (u8 *)(addr+3)); } - ma_word++; break; case INST_LDW: fault |= __get_user(d0, (u8 *)(addr+0)); @@ -157,7 +143,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) fault |= __get_user(d3, (u8 *)(addr+3)); val = (d3 << 24) | (d2 << 16) | (d1 << 8) | d0; put_reg_val(fp, b, val); - ma_word++; break; } } @@ -186,7 +171,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) * note exception and skip bad instruction (return) */ if (in_kernel) { - ma_kern++; fp->ea += 4; if (ma_usermode & KM_WARN) { @@ -200,8 +184,6 @@ asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause) return; } - ma_user++; - /* * user mode - * possibly warn, -- GitLab From 0094dc40a97260b64313b169989952d3aa2013f6 Mon Sep 17 00:00:00 2001 From: Ley Foon Tan Date: Tue, 8 Sep 2015 01:50:05 +0800 Subject: [PATCH 6602/7006] MAINTAINERS: update nios2 git repo Signed-off-by: Ley Foon Tan --- MAINTAINERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS b/MAINTAINERS index b60e2b2369d25..7077bf99a2f83 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7239,7 +7239,7 @@ F: drivers/scsi/nsp32* NIOS2 ARCHITECTURE M: Ley Foon Tan L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers) -T: git git://git.rocketboards.org/linux-socfpga-next.git +T: git git://git.kernel.org/pub/scm/linux/kernel/git/lftan/nios2.git S: Maintained F: arch/nios2/ -- GitLab From 5e9fd733fa34b491e7ac41c91aa42ba0a9d8ea10 Mon Sep 17 00:00:00 2001 From: Jon Mason Date: Sat, 4 Jul 2015 14:48:33 -0400 Subject: [PATCH 6603/7006] NTB: Add list to MAINTAINERS Add the new NTB mailing list to MAINTAINERS Signed-off-by: Jon Mason --- MAINTAINERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index b60e2b2369d25..754bc7332bcfa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7258,6 +7258,7 @@ NTB DRIVER CORE M: Jon Mason M: Dave Jiang M: Allen Hubbe +L: linux-ntb@googlegroups.com S: Supported W: https://github.com/jonmason/ntb/wiki T: git git://github.com/jonmason/ntb.git @@ -7269,6 +7270,7 @@ F: include/linux/ntb_transport.h NTB INTEL DRIVER M: Jon Mason M: Dave Jiang +L: linux-ntb@googlegroups.com S: Supported W: https://github.com/jonmason/ntb/wiki T: git git://github.com/jonmason/ntb.git -- GitLab From e74bfeedad08180b968d8613dcde141ffb0720c3 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:17 -0400 Subject: [PATCH 6604/7006] NTB: Add flow control to the ntb_netdev Right now if we push the NTB really hard, we start dropping packets due to not able to process the packets fast enough. We need to st:qop the upper layer from flooding us when that happens. A timer is necessary in order to restart the queue once the resource has been processed on the receive side. Due to the way NTB is setup, the resources on the tx side are tied to the processing of the rx side and there's no async way to know when the rx side has released those resources. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/net/ntb_netdev.c | 77 +++++++++++++++++++++++++++++++++++ drivers/ntb/ntb_transport.c | 18 +++++++- include/linux/ntb_transport.h | 1 + 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/drivers/net/ntb_netdev.c b/drivers/net/ntb_netdev.c index d8757bf9ad755..a9acf71568555 100644 --- a/drivers/net/ntb_netdev.c +++ b/drivers/net/ntb_netdev.c @@ -61,11 +61,21 @@ MODULE_VERSION(NTB_NETDEV_VER); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("Intel Corporation"); +/* Time in usecs for tx resource reaper */ +static unsigned int tx_time = 1; + +/* Number of descriptors to free before resuming tx */ +static unsigned int tx_start = 10; + +/* Number of descriptors still available before stop upper layer tx */ +static unsigned int tx_stop = 5; + struct ntb_netdev { struct list_head list; struct pci_dev *pdev; struct net_device *ndev; struct ntb_transport_qp *qp; + struct timer_list tx_timer; }; #define NTB_TX_TIMEOUT_MS 1000 @@ -136,11 +146,42 @@ enqueue_again: } } +static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev, + struct ntb_transport_qp *qp, int size) +{ + struct ntb_netdev *dev = netdev_priv(netdev); + + netif_stop_queue(netdev); + /* Make sure to see the latest value of ntb_transport_tx_free_entry() + * since the queue was last started. + */ + smp_mb(); + + if (likely(ntb_transport_tx_free_entry(qp) < size)) { + mod_timer(&dev->tx_timer, jiffies + usecs_to_jiffies(tx_time)); + return -EBUSY; + } + + netif_start_queue(netdev); + return 0; +} + +static int ntb_netdev_maybe_stop_tx(struct net_device *ndev, + struct ntb_transport_qp *qp, int size) +{ + if (netif_queue_stopped(ndev) || + (ntb_transport_tx_free_entry(qp) >= size)) + return 0; + + return __ntb_netdev_maybe_stop_tx(ndev, qp, size); +} + static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data, void *data, int len) { struct net_device *ndev = qp_data; struct sk_buff *skb; + struct ntb_netdev *dev = netdev_priv(ndev); skb = data; if (!skb || !ndev) @@ -155,6 +196,15 @@ static void ntb_netdev_tx_handler(struct ntb_transport_qp *qp, void *qp_data, } dev_kfree_skb(skb); + + if (ntb_transport_tx_free_entry(dev->qp) >= tx_start) { + /* Make sure anybody stopping the queue after this sees the new + * value of ntb_transport_tx_free_entry() + */ + smp_mb(); + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } } static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb, @@ -163,10 +213,15 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb, struct ntb_netdev *dev = netdev_priv(ndev); int rc; + ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop); + rc = ntb_transport_tx_enqueue(dev->qp, skb, skb->data, skb->len); if (rc) goto err; + /* check for next submit */ + ntb_netdev_maybe_stop_tx(ndev, dev->qp, tx_stop); + return NETDEV_TX_OK; err: @@ -175,6 +230,23 @@ err: return NETDEV_TX_BUSY; } +static void ntb_netdev_tx_timer(unsigned long data) +{ + struct net_device *ndev = (struct net_device *)data; + struct ntb_netdev *dev = netdev_priv(ndev); + + if (ntb_transport_tx_free_entry(dev->qp) < tx_stop) { + mod_timer(&dev->tx_timer, jiffies + msecs_to_jiffies(tx_time)); + } else { + /* Make sure anybody stopping the queue after this sees the new + * value of ntb_transport_tx_free_entry() + */ + smp_mb(); + if (netif_queue_stopped(ndev)) + netif_wake_queue(ndev); + } +} + static int ntb_netdev_open(struct net_device *ndev) { struct ntb_netdev *dev = netdev_priv(ndev); @@ -197,8 +269,11 @@ static int ntb_netdev_open(struct net_device *ndev) } } + setup_timer(&dev->tx_timer, ntb_netdev_tx_timer, (unsigned long)ndev); + netif_carrier_off(ndev); ntb_transport_link_up(dev->qp); + netif_start_queue(ndev); return 0; @@ -219,6 +294,8 @@ static int ntb_netdev_close(struct net_device *ndev) while ((skb = ntb_transport_rx_remove(dev->qp, &len))) dev_kfree_skb(skb); + del_timer_sync(&dev->tx_timer); + return 0; } diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 1c6386d5f79c7..0d851d6845237 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -494,6 +494,12 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, "tx_index - \t%u\n", qp->tx_index); out_offset += snprintf(buf + out_offset, out_count - out_offset, "tx_max_entry - \t%u\n", qp->tx_max_entry); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "qp->remote_rx_info->entry - \t%u\n", + qp->remote_rx_info->entry); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "free tx - \t%u\n", + ntb_transport_tx_free_entry(qp)); out_offset += snprintf(buf + out_offset, out_count - out_offset, "\nQP Link %s\n", @@ -535,6 +541,7 @@ static struct ntb_queue_entry *ntb_list_rm(spinlock_t *lock, } entry = list_first_entry(list, struct ntb_queue_entry, entry); list_del(&entry->entry); + out: spin_unlock_irqrestore(lock, flags); @@ -1843,7 +1850,7 @@ int ntb_transport_tx_enqueue(struct ntb_transport_qp *qp, void *cb, void *data, entry = ntb_list_rm(&qp->ntb_tx_free_q_lock, &qp->tx_free_q); if (!entry) { qp->tx_err_no_buf++; - return -ENOMEM; + return -EBUSY; } entry->cb_data = cb; @@ -1969,6 +1976,15 @@ unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp) } EXPORT_SYMBOL_GPL(ntb_transport_max_size); +unsigned int ntb_transport_tx_free_entry(struct ntb_transport_qp *qp) +{ + unsigned int head = qp->tx_index; + unsigned int tail = qp->remote_rx_info->entry; + + return tail > head ? tail - head : qp->tx_max_entry + tail - head; +} +EXPORT_SYMBOL_GPL(ntb_transport_tx_free_entry); + static void ntb_transport_doorbell_callback(void *data, int vector) { struct ntb_transport_ctx *nt = data; diff --git a/include/linux/ntb_transport.h b/include/linux/ntb_transport.h index 2862861366a5e..7243eb98a722e 100644 --- a/include/linux/ntb_transport.h +++ b/include/linux/ntb_transport.h @@ -83,3 +83,4 @@ void *ntb_transport_rx_remove(struct ntb_transport_qp *qp, unsigned int *len); void ntb_transport_link_up(struct ntb_transport_qp *qp); void ntb_transport_link_down(struct ntb_transport_qp *qp); bool ntb_transport_link_query(struct ntb_transport_qp *qp); +unsigned int ntb_transport_tx_free_entry(struct ntb_transport_qp *qp); -- GitLab From 0a5d19d9f046d770776508fdde959d2a42bce9f7 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:18 -0400 Subject: [PATCH 6605/7006] NTB: Add PCI Device IDs for Broadwell Xeon Adding PCI Device IDs for B2B (back to back), RP (root port, primary), and TB (transparent bridge, secondary) devices. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 15 +++++++++++++++ drivers/ntb/hw/intel/ntb_hw_intel.h | 3 +++ 2 files changed, 18 insertions(+) diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 87751cfd6f4fa..c2bc56b67e63d 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -190,14 +190,17 @@ static inline int pdev_is_xeon(struct pci_dev *pdev) case PCI_DEVICE_ID_INTEL_NTB_SS_SNB: case PCI_DEVICE_ID_INTEL_NTB_SS_IVT: case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: case PCI_DEVICE_ID_INTEL_NTB_PS_JSF: case PCI_DEVICE_ID_INTEL_NTB_PS_SNB: case PCI_DEVICE_ID_INTEL_NTB_PS_IVT: case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: + case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: case PCI_DEVICE_ID_INTEL_NTB_B2B_JSF: case PCI_DEVICE_ID_INTEL_NTB_B2B_SNB: case PCI_DEVICE_ID_INTEL_NTB_B2B_IVT: case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: return 1; } return 0; @@ -1843,6 +1846,9 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev) case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: ndev->hwerr_flags |= NTB_HWERR_SDOORBELL_LOCKUP; break; } @@ -1857,6 +1863,9 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev) case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: ndev->hwerr_flags |= NTB_HWERR_SB01BASE_LOCKUP; break; } @@ -1878,6 +1887,9 @@ static int xeon_init_dev(struct intel_ntb_dev *ndev) case PCI_DEVICE_ID_INTEL_NTB_SS_HSX: case PCI_DEVICE_ID_INTEL_NTB_PS_HSX: case PCI_DEVICE_ID_INTEL_NTB_B2B_HSX: + case PCI_DEVICE_ID_INTEL_NTB_SS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_PS_BDX: + case PCI_DEVICE_ID_INTEL_NTB_B2B_BDX: ndev->hwerr_flags |= NTB_HWERR_B2BDOORBELL_BIT14; break; } @@ -2234,14 +2246,17 @@ static const struct pci_device_id intel_ntb_pci_tbl[] = { {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SNB)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_IVT)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_BDX)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_JSF)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_SNB)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_IVT)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_PS_BDX)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_JSF)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_SNB)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_BDX)}, {0} }; MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl); diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 7ddaf387b679c..ea0612f797df6 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -67,6 +67,9 @@ #define PCI_DEVICE_ID_INTEL_NTB_PS_HSX 0x2F0E #define PCI_DEVICE_ID_INTEL_NTB_SS_HSX 0x2F0F #define PCI_DEVICE_ID_INTEL_NTB_B2B_BWD 0x0C4E +#define PCI_DEVICE_ID_INTEL_NTB_B2B_BDX 0x6F0D +#define PCI_DEVICE_ID_INTEL_NTB_PS_BDX 0x6F0E +#define PCI_DEVICE_ID_INTEL_NTB_SS_BDX 0x6F0F /* Intel Xeon hardware */ -- GitLab From 315100004fd6d9189b033f3bf9c5eba9eb906705 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:19 -0400 Subject: [PATCH 6606/7006] NTB: Make the transport list in order of discovery The list should be added from the bottom and not the top in order to ensure the transport is provided in the same order to clients as ntb devices are discovered. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 0d851d6845237..29553fb7fb8e7 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -297,7 +297,7 @@ static LIST_HEAD(ntb_transport_list); static int ntb_bus_init(struct ntb_transport_ctx *nt) { - list_add(&nt->entry, &ntb_transport_list); + list_add_tail(&nt->entry, &ntb_transport_list); return 0; } -- GitLab From d98ef99e378b0d5c42be928d6f2abe08a5f9ce53 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:20 -0400 Subject: [PATCH 6607/7006] NTB: Clean up QP stats info Make QP stats info more readable for debugging purposes. Also add an entry to indicate whether DMA is being used. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 29553fb7fb8e7..777436c47679d 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -452,7 +452,7 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, out_offset = 0; out_offset += snprintf(buf + out_offset, out_count - out_offset, - "NTB QP stats\n"); + "\nNTB QP stats:\n\n"); out_offset += snprintf(buf + out_offset, out_count - out_offset, "rx_bytes - \t%llu\n", qp->rx_bytes); out_offset += snprintf(buf + out_offset, out_count - out_offset, @@ -470,11 +470,11 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, out_offset += snprintf(buf + out_offset, out_count - out_offset, "rx_err_ver - \t%llu\n", qp->rx_err_ver); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "rx_buff - \t%p\n", qp->rx_buff); + "rx_buff - \t0x%p\n", qp->rx_buff); out_offset += snprintf(buf + out_offset, out_count - out_offset, "rx_index - \t%u\n", qp->rx_index); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "rx_max_entry - \t%u\n", qp->rx_max_entry); + "rx_max_entry - \t%u\n\n", qp->rx_max_entry); out_offset += snprintf(buf + out_offset, out_count - out_offset, "tx_bytes - \t%llu\n", qp->tx_bytes); @@ -489,21 +489,28 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, out_offset += snprintf(buf + out_offset, out_count - out_offset, "tx_err_no_buf - %llu\n", qp->tx_err_no_buf); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "tx_mw - \t%p\n", qp->tx_mw); + "tx_mw - \t0x%p\n", qp->tx_mw); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "tx_index - \t%u\n", qp->tx_index); + "tx_index (H) - \t%u\n", qp->tx_index); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "tx_max_entry - \t%u\n", qp->tx_max_entry); - out_offset += snprintf(buf + out_offset, out_count - out_offset, - "qp->remote_rx_info->entry - \t%u\n", + "RRI (T) - \t%u\n", qp->remote_rx_info->entry); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "tx_max_entry - \t%u\n", qp->tx_max_entry); out_offset += snprintf(buf + out_offset, out_count - out_offset, "free tx - \t%u\n", ntb_transport_tx_free_entry(qp)); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "\nQP Link %s\n", + "\n"); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Using DMA - \t%s\n", use_dma ? "Yes" : "No"); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "QP Link - \t%s\n", qp->link_is_up ? "Up" : "Down"); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "\n"); + if (out_offset > out_count) out_offset = out_count; -- GitLab From 905921e74864e80228e7f8cfe75315cd0a8cada8 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 13 Jul 2015 08:07:21 -0400 Subject: [PATCH 6608/7006] NTB: Remove dma_sync_wait from ntb_async_rx The dma_sync_wait can hurt the performance of workloads mixed with both large and small frames. Large frames will be copied using the dma engine. Small frames will be copied by the cpu. The dma_sync_wait prevents the cpu and dma engine copying in parallel. In the period where the cpu is copying, the dma engine is stopped. The dma engine is not doing any useful work to copy large frames during that time, and the additional time to restart the dma engine for the next large frame. This will decrease the throughput for the portion of a workload with large frames. In the period where the dma engine is copying, the cpu is held up waiting for dma to complete. The small frames processing will be delayed until the dma is complete. The RX frames are completed in-order, and the processing of small frames takes very little time, so dma_sync_wait may have an insignificant impact on the respose time of frames. The more significant impact is to the system, because the delay in dma_sync_wait is implemented as busy non-blocking wait. This can prevent the delayed core from doing any useful work, even if it could be processing work for other drivers, unrelated to transport RX processing. After applying the earlier patch to fix out-of-order RX acknoledgement, the dma_sync_wait is no longer necessary. Remove it, so that cpu memcpy will proceed immediately for small frames, in parallel with ongoing dma for large frames. Do not hold up the cpu from doing work while dma is in progress. The prior fix will continue to ensure in-order completion of the RX frames to the upper layer, and in-order delivery of the RX acknoledgement. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 777436c47679d..f6aae0fbde48d 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -1233,18 +1233,18 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset) goto err; if (len < copy_bytes) - goto err_wait; + goto err; device = chan->device; pay_off = (size_t)offset & ~PAGE_MASK; buff_off = (size_t)buf & ~PAGE_MASK; if (!is_dma_copy_aligned(device, pay_off, buff_off, len)) - goto err_wait; + goto err; unmap = dmaengine_get_unmap_data(device->dev, 2, GFP_NOWAIT); if (!unmap) - goto err_wait; + goto err; unmap->len = len; unmap->addr[0] = dma_map_page(device->dev, virt_to_page(offset), @@ -1287,12 +1287,6 @@ err_set_unmap: dmaengine_unmap_put(unmap); err_get_unmap: dmaengine_unmap_put(unmap); -err_wait: - /* If the callbacks come out of order, the writing of the index to the - * last completed will be out of order. This may result in the - * receive stalling forever. - */ - dma_sync_wait(chan, qp->last_cookie); err: ntb_memcpy_rx(entry, offset); qp->rx_memcpy++; -- GitLab From 569410ca756cd3ebb15609cb6828a8393fb6384d Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Mon, 13 Jul 2015 08:07:22 -0400 Subject: [PATCH 6609/7006] NTB: Use unique DMA channels for TX and RX Allocate two DMA channels, one for TX operation and one for RX operation, instead of having one DMA channel for everything. This provides slightly better performance, and also will make error handling cleaner later on. Signed-off-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 77 ++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index f6aae0fbde48d..6e3ee907d1861 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -119,7 +119,8 @@ struct ntb_transport_qp { struct ntb_transport_ctx *transport; struct ntb_dev *ndev; void *cb_data; - struct dma_chan *dma_chan; + struct dma_chan *tx_dma_chan; + struct dma_chan *rx_dma_chan; bool client_ready; bool link_is_up; @@ -504,7 +505,11 @@ static ssize_t debugfs_read(struct file *filp, char __user *ubuf, size_t count, out_offset += snprintf(buf + out_offset, out_count - out_offset, "\n"); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Using DMA - \t%s\n", use_dma ? "Yes" : "No"); + "Using TX DMA - \t%s\n", + qp->tx_dma_chan ? "Yes" : "No"); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Using RX DMA - \t%s\n", + qp->rx_dma_chan ? "Yes" : "No"); out_offset += snprintf(buf + out_offset, out_count - out_offset, "QP Link - \t%s\n", qp->link_is_up ? "Up" : "Down"); @@ -1220,7 +1225,7 @@ static void ntb_async_rx(struct ntb_queue_entry *entry, void *offset) { struct dma_async_tx_descriptor *txd; struct ntb_transport_qp *qp = entry->qp; - struct dma_chan *chan = qp->dma_chan; + struct dma_chan *chan = qp->rx_dma_chan; struct dma_device *device; size_t pay_off, buff_off, len; struct dmaengine_unmap_data *unmap; @@ -1381,8 +1386,8 @@ static void ntb_transport_rxc_db(unsigned long data) break; } - if (i && qp->dma_chan) - dma_async_issue_pending(qp->dma_chan); + if (i && qp->rx_dma_chan) + dma_async_issue_pending(qp->rx_dma_chan); if (i == qp->rx_max_entry) { /* there is more work to do */ @@ -1449,7 +1454,7 @@ static void ntb_async_tx(struct ntb_transport_qp *qp, { struct ntb_payload_header __iomem *hdr; struct dma_async_tx_descriptor *txd; - struct dma_chan *chan = qp->dma_chan; + struct dma_chan *chan = qp->tx_dma_chan; struct dma_device *device; size_t dest_off, buff_off; struct dmaengine_unmap_data *unmap; @@ -1642,14 +1647,27 @@ ntb_transport_create_queue(void *data, struct device *client_dev, dma_cap_set(DMA_MEMCPY, dma_mask); if (use_dma) { - qp->dma_chan = dma_request_channel(dma_mask, ntb_dma_filter_fn, - (void *)(unsigned long)node); - if (!qp->dma_chan) - dev_info(&pdev->dev, "Unable to allocate DMA channel\n"); + qp->tx_dma_chan = + dma_request_channel(dma_mask, ntb_dma_filter_fn, + (void *)(unsigned long)node); + if (!qp->tx_dma_chan) + dev_info(&pdev->dev, "Unable to allocate TX DMA channel\n"); + + qp->rx_dma_chan = + dma_request_channel(dma_mask, ntb_dma_filter_fn, + (void *)(unsigned long)node); + if (!qp->rx_dma_chan) + dev_info(&pdev->dev, "Unable to allocate RX DMA channel\n"); } else { - qp->dma_chan = NULL; + qp->tx_dma_chan = NULL; + qp->rx_dma_chan = NULL; } - dev_dbg(&pdev->dev, "Using %s memcpy\n", qp->dma_chan ? "DMA" : "CPU"); + + dev_dbg(&pdev->dev, "Using %s memcpy for TX\n", + qp->tx_dma_chan ? "DMA" : "CPU"); + + dev_dbg(&pdev->dev, "Using %s memcpy for RX\n", + qp->rx_dma_chan ? "DMA" : "CPU"); for (i = 0; i < NTB_QP_DEF_NUM_ENTRIES; i++) { entry = kzalloc_node(sizeof(*entry), GFP_ATOMIC, node); @@ -1684,8 +1702,10 @@ err2: err1: while ((entry = ntb_list_rm(&qp->ntb_rx_q_lock, &qp->rx_free_q))) kfree(entry); - if (qp->dma_chan) - dma_release_channel(qp->dma_chan); + if (qp->tx_dma_chan) + dma_release_channel(qp->tx_dma_chan); + if (qp->rx_dma_chan) + dma_release_channel(qp->rx_dma_chan); nt->qp_bitmap_free |= qp_bit; err: return NULL; @@ -1709,12 +1729,27 @@ void ntb_transport_free_queue(struct ntb_transport_qp *qp) pdev = qp->ndev->pdev; - if (qp->dma_chan) { - struct dma_chan *chan = qp->dma_chan; + if (qp->tx_dma_chan) { + struct dma_chan *chan = qp->tx_dma_chan; + /* Putting the dma_chan to NULL will force any new traffic to be + * processed by the CPU instead of the DAM engine + */ + qp->tx_dma_chan = NULL; + + /* Try to be nice and wait for any queued DMA engine + * transactions to process before smashing it with a rock + */ + dma_sync_wait(chan, qp->last_cookie); + dmaengine_terminate_all(chan); + dma_release_channel(chan); + } + + if (qp->rx_dma_chan) { + struct dma_chan *chan = qp->rx_dma_chan; /* Putting the dma_chan to NULL will force any new traffic to be * processed by the CPU instead of the DAM engine */ - qp->dma_chan = NULL; + qp->rx_dma_chan = NULL; /* Try to be nice and wait for any queued DMA engine * transactions to process before smashing it with a rock @@ -1962,16 +1997,20 @@ EXPORT_SYMBOL_GPL(ntb_transport_qp_num); unsigned int ntb_transport_max_size(struct ntb_transport_qp *qp) { unsigned int max; + unsigned int copy_align; if (!qp) return 0; - if (!qp->dma_chan) + if (!qp->tx_dma_chan && !qp->rx_dma_chan) return qp->tx_max_frame - sizeof(struct ntb_payload_header); + copy_align = max(qp->tx_dma_chan->device->copy_align, + qp->rx_dma_chan->device->copy_align); + /* If DMA engine usage is possible, try to find the max size for that */ max = qp->tx_max_frame - sizeof(struct ntb_payload_header); - max -= max % (1 << qp->dma_chan->device->copy_align); + max -= max % (1 << copy_align); return max; } -- GitLab From a7c23237481782fbea3c2230e362b72863e144b0 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Wed, 15 Jul 2015 04:15:28 -0400 Subject: [PATCH 6610/7006] NTB: Fix documentation for ntb_link_is_up There was a copy and paste error in the documentation for ntb_link_is_up. The long description was mistakenly copied from ntb_link_set_trans. This adds the appropriate long description for ntb_link_is_up. Reported-by: Dave Jiang Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- include/linux/ntb.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/linux/ntb.h b/include/linux/ntb.h index b02f72bb8e325..e3d3299c60520 100644 --- a/include/linux/ntb.h +++ b/include/linux/ntb.h @@ -522,10 +522,9 @@ static inline int ntb_mw_clear_trans(struct ntb_dev *ntb, int idx) * @speed: OUT - The link speed expressed as PCIe generation number. * @width: OUT - The link width expressed as the number of PCIe lanes. * - * Set the translation of a memory window. The peer may access local memory - * through the window starting at the address, up to the size. The address - * must be aligned to the alignment specified by ntb_mw_get_range(). The size - * must be aligned to the size alignment specified by ntb_mw_get_range(). + * Get the current state of the ntb link. It is recommended to query the link + * state once after every link event. It is safe to query the link state in + * the context of the link event callback. * * Return: One if the link is up, zero if the link is down, otherwise a * negative value indicating the error number. -- GitLab From 86663c91866ae85c219f1a80ef2c9460b7ca5cd8 Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Wed, 15 Jul 2015 12:43:21 -0400 Subject: [PATCH 6611/7006] NTB: Fix documentation for ntb_peer_db_clear. The documentation should say "peer" not "local" when referring to the peer doorbell register. Reported-by: Dave Jiang Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- include/linux/ntb.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/ntb.h b/include/linux/ntb.h index e3d3299c60520..f798e2afba88d 100644 --- a/include/linux/ntb.h +++ b/include/linux/ntb.h @@ -794,7 +794,7 @@ static inline int ntb_peer_db_set(struct ntb_dev *ntb, u64 db_bits) } /** - * ntb_peer_db_clear() - clear bits in the local doorbell register + * ntb_peer_db_clear() - clear bits in the peer doorbell register * @ntb: NTB device context. * @db_bits: Doorbell bits to clear. * -- GitLab From 2aa2a77a489deda473c99a4c15074d092718912c Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 31 Aug 2015 09:30:59 -0400 Subject: [PATCH 6612/7006] NTB: Improve index handling in B2B MW workaround Check that b2b_mw_idx is in range of the number of memory windows when initializing the device. The workaround is considered to be in effect only if the device b2b_idx is exactly UINT_MAX, instead of any index past the last memory window. Only print B2B MW workaround information in debugfs if the workaround is in effect. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index c2bc56b67e63d..fc6af2da8df05 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -575,10 +575,13 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, "Connection Topology -\t%s\n", ntb_topo_string(ndev->ntb.topo)); - off += scnprintf(buf + off, buf_size - off, - "B2B Offset -\t\t%#lx\n", ndev->b2b_off); - off += scnprintf(buf + off, buf_size - off, - "B2B MW Idx -\t\t%d\n", ndev->b2b_idx); + if (ndev->b2b_idx != UINT_MAX) { + off += scnprintf(buf + off, buf_size - off, + "B2B MW Idx -\t\t%u\n", ndev->b2b_idx); + off += scnprintf(buf + off, buf_size - off, + "B2B Offset -\t\t%#lx\n", ndev->b2b_off); + } + off += scnprintf(buf + off, buf_size - off, "BAR4 Split -\t\t%s\n", ndev->bar4_split ? "yes" : "no"); @@ -1487,7 +1490,7 @@ static int xeon_setup_b2b_mw(struct intel_ntb_dev *ndev, pdev = ndev_pdev(ndev); mmio = ndev->self_mmio; - if (ndev->b2b_idx >= ndev->mw_count) { + if (ndev->b2b_idx == UINT_MAX) { dev_dbg(ndev_dev(ndev), "not using b2b mw\n"); b2b_bar = 0; ndev->b2b_off = 0; @@ -1779,6 +1782,13 @@ static int xeon_init_ntb(struct intel_ntb_dev *ndev) else ndev->b2b_idx = b2b_mw_idx; + if (ndev->b2b_idx >= ndev->mw_count) { + dev_dbg(ndev_dev(ndev), + "b2b_mw_idx %d invalid for mw_count %u\n", + b2b_mw_idx, ndev->mw_count); + return -EINVAL; + } + dev_dbg(ndev_dev(ndev), "setting up b2b mw idx %d means %d\n", b2b_mw_idx, ndev->b2b_idx); @@ -2008,7 +2018,7 @@ static inline void ndev_init_struct(struct intel_ntb_dev *ndev, ndev->ntb.ops = &intel_ntb_ops; ndev->b2b_off = 0; - ndev->b2b_idx = INT_MAX; + ndev->b2b_idx = UINT_MAX; ndev->bar4_split = 0; -- GitLab From 9a07826f99034202dad589285a47132685d9538b Mon Sep 17 00:00:00 2001 From: Allen Hubbe Date: Mon, 31 Aug 2015 09:31:00 -0400 Subject: [PATCH 6613/7006] NTB: Fix range check on memory window index The range check must exclude the upper bound. Signed-off-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index fc6af2da8df05..865a3e3cc5816 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -240,7 +240,7 @@ static inline int ndev_ignore_unsafe(struct intel_ntb_dev *ndev, static int ndev_mw_to_bar(struct intel_ntb_dev *ndev, int idx) { - if (idx < 0 || idx > ndev->mw_count) + if (idx < 0 || idx >= ndev->mw_count) return -EINVAL; return ndev->reg->mw_bar[idx]; } -- GitLab From d075a88e515278b3e2d5ec39e80e6fd3c6e48841 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 3 Sep 2015 12:15:21 +0530 Subject: [PATCH 6614/7006] cpufreq: staticize cpufreq_cpu_get_raw() cpufreq_cpu_get_raw() isn't used by any external users, staticize it. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index abb776827bb1f..feb6dc51efa7e 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -239,7 +239,7 @@ int cpufreq_generic_init(struct cpufreq_policy *policy, EXPORT_SYMBOL_GPL(cpufreq_generic_init); /* Only for cpufreq core internal use */ -struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu) +static struct cpufreq_policy *cpufreq_cpu_get_raw(unsigned int cpu) { struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu); -- GitLab From 63431f789c957cebcffeb51953dfaeb7f1ddd827 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 27 Jul 2015 17:58:06 +0530 Subject: [PATCH 6615/7006] cpufreq: Use __func__ to print function's name Its better to use __func__ to print functions name instead of writing the name in the print statement. This also has the advantage that a change in function's name doesn't force us to change the print message as well. Reviewed-by: Preeti U Murthy Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index feb6dc51efa7e..8b6bf38b2497b 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -2033,8 +2033,7 @@ static int __cpufreq_governor(struct cpufreq_policy *policy, if (!try_module_get(policy->governor->owner)) return -EINVAL; - pr_debug("__cpufreq_governor for CPU %u, event %u\n", - policy->cpu, event); + pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event); mutex_lock(&cpufreq_governor_lock); if ((policy->governor_enabled && event == CPUFREQ_GOV_START) -- GitLab From 3dfe6a507353f3253c8136734d94bfdb459fa04d Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 11:14:13 +0200 Subject: [PATCH 6616/7006] kvm: move new trace event outside #ifdef CONFIG_KVM_ASYNC_PF Fixes compilation with ppc64_defconfig. Reported-by: Stephen Rothwell Signed-off-by: Wanpeng Li Signed-off-by: Paolo Bonzini --- include/trace/events/kvm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/trace/events/kvm.h b/include/trace/events/kvm.h index 0d1bc478833b9..d6f83222a6a16 100644 --- a/include/trace/events/kvm.h +++ b/include/trace/events/kvm.h @@ -356,6 +356,8 @@ TRACE_EVENT( __entry->address) ); +#endif + TRACE_EVENT(kvm_halt_poll_ns, TP_PROTO(bool grow, unsigned int vcpu_id, int new, int old), TP_ARGS(grow, vcpu_id, new, old), @@ -386,8 +388,6 @@ TRACE_EVENT(kvm_halt_poll_ns, #define trace_kvm_halt_poll_ns_shrink(vcpu_id, new, old) \ trace_kvm_halt_poll_ns(false, vcpu_id, new, old) -#endif - #endif /* _TRACE_KVM_MAIN_H */ /* This part must be outside protection */ -- GitLab From ba60c41ae392b473a1897faa0b8739fcb8759d69 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 2 Sep 2015 12:33:53 +0530 Subject: [PATCH 6617/7006] kvm: irqchip: fix memory leak We were taking the exit path after checking ue->flags and return value of setup_routing_entry(), but 'e' was not freed incase of a failure. Signed-off-by: Sudip Mukherjee Signed-off-by: Paolo Bonzini --- virt/kvm/irqchip.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/virt/kvm/irqchip.c b/virt/kvm/irqchip.c index 21c14244f4c4f..d7ea8e20dae4e 100644 --- a/virt/kvm/irqchip.c +++ b/virt/kvm/irqchip.c @@ -213,11 +213,15 @@ int kvm_set_irq_routing(struct kvm *kvm, goto out; r = -EINVAL; - if (ue->flags) + if (ue->flags) { + kfree(e); goto out; + } r = setup_routing_entry(new, e, ue); - if (r) + if (r) { + kfree(e); goto out; + } ++ue; } -- GitLab From 61c610ec61bb334ba97cddaf352c95b9371d2a23 Mon Sep 17 00:00:00 2001 From: Chee Nouk Phoon Date: Tue, 8 Sep 2015 18:07:44 +0800 Subject: [PATCH 6618/7006] nios2: Add Max10 device tree Max10 is a FPGA device. This patch adds Nios2 support for Max10. This device tree is based on Max10 hardware reference design. Signed-off-by: Chee Nouk Phoon Signed-off-by: Ley Foon Tan --- arch/nios2/boot/dts/10m50_devboard.dts | 248 +++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100755 arch/nios2/boot/dts/10m50_devboard.dts diff --git a/arch/nios2/boot/dts/10m50_devboard.dts b/arch/nios2/boot/dts/10m50_devboard.dts new file mode 100755 index 0000000000000..3e411c644824b --- /dev/null +++ b/arch/nios2/boot/dts/10m50_devboard.dts @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2015 Altera Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +/dts-v1/; + +/ { + model = "Altera NiosII Max10"; + compatible = "altr,niosii-max10"; + #address-cells = <1>; + #size-cells = <1>; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu: cpu@0 { + device_type = "cpu"; + compatible = "altr,nios2-1.1"; + reg = <0x00000000>; + interrupt-controller; + #interrupt-cells = <1>; + altr,exception-addr = <0xc8000120>; + altr,fast-tlb-miss-addr = <0xc0000100>; + altr,has-div = <1>; + altr,has-initda = <1>; + altr,has-mmu = <1>; + altr,has-mul = <1>; + altr,implementation = "fast"; + altr,pid-num-bits = <8>; + altr,reset-addr = <0xd4000000>; + altr,tlb-num-entries = <256>; + altr,tlb-num-ways = <16>; + altr,tlb-ptr-sz = <8>; + clock-frequency = <75000000>; + dcache-line-size = <32>; + dcache-size = <32768>; + icache-line-size = <32>; + icache-size = <32768>; + }; + }; + + memory { + device_type = "memory"; + reg = <0x08000000 0x08000000>, + <0x00000000 0x00000400>; + }; + + sopc0: sopc@0 { + device_type = "soc"; + ranges; + #address-cells = <1>; + #size-cells = <1>; + compatible = "altr,avalon", "simple-bus"; + bus-frequency = <75000000>; + + jtag_uart: serial@18001530 { + compatible = "altr,juart-1.0"; + reg = <0x18001530 0x00000008>; + interrupt-parent = <&cpu>; + interrupts = <7>; + }; + + a_16550_uart_0: serial@18001600 { + compatible = "altr,16550-FIFO32", "ns16550a"; + reg = <0x18001600 0x00000200>; + interrupt-parent = <&cpu>; + interrupts = <1>; + auto-flow-control = <1>; + clock-frequency = <50000000>; + fifo-size = <32>; + reg-io-width = <4>; + reg-shift = <2>; + }; + + sysid: sysid@18001528 { + compatible = "altr,sysid-1.0"; + reg = <0x18001528 0x00000008>; + id = <4207856382>; + timestamp = <1431309290>; + }; + + rgmii_0_eth_tse_0: ethernet@400 { + compatible = "altr,tse-msgdma-1.0", "altr,tse-1.0"; + reg = <0x00000400 0x00000400>, + <0x00000820 0x00000020>, + <0x00000800 0x00000020>, + <0x000008c0 0x00000008>, + <0x00000840 0x00000020>, + <0x00000860 0x00000020>; + reg-names = "control_port", "rx_csr", "rx_desc", "rx_resp", "tx_csr", "tx_desc"; + interrupt-parent = <&cpu>; + interrupts = <2 3>; + interrupt-names = "rx_irq", "tx_irq"; + rx-fifo-depth = <8192>; + tx-fifo-depth = <8192>; + address-bits = <48>; + max-frame-size = <1518>; + local-mac-address = [00 00 00 00 00 00]; + altr,has-supplementary-unicast; + altr,enable-sup-addr = <1>; + altr,has-hash-multicast-filter; + altr,enable-hash = <1>; + phy-mode = "rgmii-id"; + phy-handle = <&phy0>; + rgmii_0_eth_tse_0_mdio: mdio { + compatible = "altr,tse-mdio"; + #address-cells = <1>; + #size-cells = <0>; + phy0: ethernet-phy@0 { + reg = <0>; + device_type = "ethernet-phy"; + }; + }; + }; + + enet_pll: clock@0 { + compatible = "altr,pll-1.0"; + #clock-cells = <1>; + + enet_pll_c0: enet_pll_c0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <125000000>; + clock-output-names = "enet_pll-c0"; + }; + + enet_pll_c1: enet_pll_c1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <25000000>; + clock-output-names = "enet_pll-c1"; + }; + + enet_pll_c2: enet_pll_c2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <2500000>; + clock-output-names = "enet_pll-c2"; + }; + }; + + sys_pll: clock@1 { + compatible = "altr,pll-1.0"; + #clock-cells = <1>; + + sys_pll_c0: sys_pll_c0 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <100000000>; + clock-output-names = "sys_pll-c0"; + }; + + sys_pll_c1: sys_pll_c1 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <50000000>; + clock-output-names = "sys_pll-c1"; + }; + + sys_pll_c2: sys_pll_c2 { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <75000000>; + clock-output-names = "sys_pll-c2"; + }; + }; + + sys_clk_timer: timer@18001440 { + compatible = "altr,timer-1.0"; + reg = <0x18001440 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <0>; + clock-frequency = <75000000>; + }; + + led_pio: gpio@180014d0 { + compatible = "altr,pio-1.0"; + reg = <0x180014d0 0x00000010>; + altr,gpio-bank-width = <4>; + resetvalue = <15>; + #gpio-cells = <2>; + gpio-controller; + }; + + button_pio: gpio@180014c0 { + compatible = "altr,pio-1.0"; + reg = <0x180014c0 0x00000010>; + interrupt-parent = <&cpu>; + interrupts = <6>; + altr,gpio-bank-width = <3>; + altr,interrupt-type = <2>; + edge_type = <1>; + level_trigger = <0>; + resetvalue = <0>; + #gpio-cells = <2>; + gpio-controller; + }; + + sys_clk_timer_1: timer@880 { + compatible = "altr,timer-1.0"; + reg = <0x00000880 0x00000020>; + interrupt-parent = <&cpu>; + interrupts = <5>; + clock-frequency = <75000000>; + }; + + fpga_leds: leds { + compatible = "gpio-leds"; + + led_fpga0: fpga0 { + label = "fpga_led0"; + gpios = <&led_pio 0 1>; + }; + + led_fpga1: fpga1 { + label = "fpga_led1"; + gpios = <&led_pio 1 1>; + }; + + led_fpga2: fpga2 { + label = "fpga_led2"; + gpios = <&led_pio 2 1>; + }; + + led_fpga3: fpga3 { + label = "fpga_led3"; + gpios = <&led_pio 3 1>; + }; + }; + }; + + chosen { + bootargs = "debug console=ttyS0,115200"; + }; +}; -- GitLab From 08441d462ebdc64df79b392f877e26522616bad5 Mon Sep 17 00:00:00 2001 From: Chee Nouk Phoon Date: Tue, 8 Sep 2015 18:08:56 +0800 Subject: [PATCH 6619/7006] nios2: add Max10 defconfig Max10 is a FPGA device. This patch adds defconfig based on Max10 hardware reference design. Design is intended to run on Max10 development kit. Signed-off-by: Chee Nouk Phoon Signed-off-by: Ley Foon Tan --- arch/nios2/configs/10m50_defconfig | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100755 arch/nios2/configs/10m50_defconfig diff --git a/arch/nios2/configs/10m50_defconfig b/arch/nios2/configs/10m50_defconfig new file mode 100755 index 0000000000000..8b2a30b3b34fe --- /dev/null +++ b/arch/nios2/configs/10m50_defconfig @@ -0,0 +1,81 @@ +CONFIG_SYSVIPC=y +CONFIG_NO_HZ_IDLE=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_SYSCTL_SYSCALL=y +# CONFIG_ELF_CORE is not set +# CONFIG_EPOLL is not set +# CONFIG_SIGNALFD is not set +# CONFIG_TIMERFD is not set +# CONFIG_EVENTFD is not set +# CONFIG_SHMEM is not set +# CONFIG_AIO is not set +CONFIG_EMBEDDED=y +CONFIG_SLAB=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_NIOS2_MEM_BASE=0x8000000 +CONFIG_NIOS2_HW_MUL_SUPPORT=y +CONFIG_NIOS2_HW_DIV_SUPPORT=y +CONFIG_CUSTOM_CACHE_SETTINGS=y +CONFIG_NIOS2_DCACHE_SIZE=0x8000 +CONFIG_NIOS2_ICACHE_SIZE=0x8000 +# CONFIG_NIOS2_CMDLINE_IGNORE_DTB is not set +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +# CONFIG_INET_XFRM_MODE_TRANSPORT is not set +# CONFIG_INET_XFRM_MODE_TUNNEL is not set +# CONFIG_INET_XFRM_MODE_BEET is not set +# CONFIG_INET_LRO is not set +# CONFIG_IPV6 is not set +# CONFIG_WIRELESS is not set +CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +# CONFIG_FW_LOADER is not set +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_INTELEXT=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_NETDEVICES=y +CONFIG_ALTERA_TSE=y +CONFIG_MARVELL_PHY=y +# CONFIG_WLAN is not set +# CONFIG_INPUT_MOUSE is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_ALTERA_JTAGUART=y +# CONFIG_HW_RANDOM is not set +CONFIG_GPIOLIB=y +CONFIG_GPIO_SYSFS=y +CONFIG_GPIO_ALTERA=y +# CONFIG_HWMON is not set +# CONFIG_USB_SUPPORT is not set +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +# CONFIG_DNOTIFY is not set +# CONFIG_INOTIFY_USER is not set +CONFIG_JFFS2_FS=y +CONFIG_NFS_FS=y +CONFIG_NFS_V3_ACL=y +CONFIG_ROOT_NFS=y +CONFIG_SUNRPC_DEBUG=y +CONFIG_DEBUG_INFO=y +# CONFIG_ENABLE_WARN_DEPRECATED is not set -- GitLab From 53eab6fd2777dc7cb338519827e23f8bf892903e Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Fri, 21 Aug 2015 15:53:55 -0700 Subject: [PATCH 6620/7006] virtio-blk: use VIRTIO_BLK_F_WCE and VIRTIO_BLK_F_CONFIG_WCE in virtio1 VIRTIO_BLK_F_CONFIG_WCE is important in order to achieve good performance (up to 2x, though more realistically +30-40%) in latency-bound workloads. However, it was removed by mistake together with VIRTIO_BLK_F_FLUSH. It will be restored in the next revision of the virtio 1.0 standard, so do the same in Linux. Signed-off-by: Paolo Bonzini Signed-off-by: Michael S. Tsirkin --- drivers/block/virtio_blk.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index d4d05f064d390..ea2c17c66dfb6 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -478,8 +478,7 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev) struct virtio_blk_config, wce, &writeback); if (err) - writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE) || - virtio_has_feature(vdev, VIRTIO_F_VERSION_1); + writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE); return writeback; } @@ -840,7 +839,7 @@ static unsigned int features_legacy[] = { static unsigned int features[] = { VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, - VIRTIO_BLK_F_TOPOLOGY, + VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, VIRTIO_BLK_F_MQ, }; -- GitLab From 38c4ab8e48ab153dee461e10e81256720b70a0b3 Mon Sep 17 00:00:00 2001 From: Graeme Gregory Date: Tue, 28 Jul 2015 10:44:02 +0100 Subject: [PATCH 6621/7006] virtio_mmio: add ACPI probing Added the match table and pointers for ACPI probing to the driver. This uses the same identifier for virt devices as being used for qemu ARM64 ACPI support. http://git.linaro.org/people/shannon.zhao/qemu.git/commit/d0bf1955a3ecbab4b51d46f8c5dda02b7e14a17e Signed-off-by: Graeme Gregory Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_mmio.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 10189b5b627f9..f499d9da72373 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -58,6 +58,7 @@ #define pr_fmt(fmt) "virtio-mmio: " fmt +#include #include #include #include @@ -732,12 +733,21 @@ static struct of_device_id virtio_mmio_match[] = { }; MODULE_DEVICE_TABLE(of, virtio_mmio_match); +#ifdef CONFIG_ACPI +static const struct acpi_device_id virtio_mmio_acpi_match[] = { + { "LNRO0005", }, + { } +}; +MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match); +#endif + static struct platform_driver virtio_mmio_driver = { .probe = virtio_mmio_probe, .remove = virtio_mmio_remove, .driver = { .name = "virtio-mmio", .of_match_table = virtio_mmio_match, + .acpi_match_table = ACPI_PTR(virtio_mmio_acpi_match), }, }; -- GitLab From 5fa3142da14b162f30e4781ff17e1926c47f28fb Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sun, 6 Sep 2015 17:05:42 +0800 Subject: [PATCH 6622/7006] virtio-blk: Allow extended partitions This will allow up to DISK_MAX_PARTS (256) partitions, with for example GPT in the guest. Otherwise, the partition scan code will only discover the first 15 partitions. Signed-off-by: Fam Zheng Signed-off-by: Michael S. Tsirkin --- drivers/block/virtio_blk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c index ea2c17c66dfb6..e93899cc6f60b 100644 --- a/drivers/block/virtio_blk.c +++ b/drivers/block/virtio_blk.c @@ -656,6 +656,7 @@ static int virtblk_probe(struct virtio_device *vdev) vblk->disk->private_data = vblk; vblk->disk->fops = &virtblk_fops; vblk->disk->driverfs_dev = &vdev->dev; + vblk->disk->flags |= GENHD_FL_EXT_DEVT; vblk->index = index; /* configure queue flush support */ -- GitLab From b4d34037329f46ed818d3b0a6e1e23b9c8721f79 Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 20 Aug 2015 00:49:48 +0300 Subject: [PATCH 6623/7006] virtio_ballon: change stub of release_pages_by_pfn and rename it to release_pages_balloon. The function originally takes arrays of pfns and now it takes pointer to struct virtio_ballon. This change is necessary to conditionally call adjust_managed_page_count in the next patch. Signed-off-by: Denis V. Lunev CC: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_balloon.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 82e80e034f250..8543c9a97307a 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -166,13 +166,13 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num) mutex_unlock(&vb->balloon_lock); } -static void release_pages_by_pfn(const u32 pfns[], unsigned int num) +static void release_pages_balloon(struct virtio_balloon *vb) { unsigned int i; /* Find pfns pointing at start of each page, get pages and free them. */ - for (i = 0; i < num; i += VIRTIO_BALLOON_PAGES_PER_PAGE) { - struct page *page = balloon_pfn_to_page(pfns[i]); + for (i = 0; i < vb->num_pfns; i += VIRTIO_BALLOON_PAGES_PER_PAGE) { + struct page *page = balloon_pfn_to_page(vb->pfns[i]); adjust_managed_page_count(page, 1); put_page(page); /* balloon reference */ } @@ -206,7 +206,7 @@ static unsigned leak_balloon(struct virtio_balloon *vb, size_t num) if (vb->num_pfns != 0) tell_host(vb, vb->deflate_vq); mutex_unlock(&vb->balloon_lock); - release_pages_by_pfn(vb->pfns, vb->num_pfns); + release_pages_balloon(vb); return num_freed_pages; } -- GitLab From 997e120843e82609c8d99a9d5714e6cf91e14cbe Mon Sep 17 00:00:00 2001 From: "Denis V. Lunev" Date: Thu, 20 Aug 2015 00:49:49 +0300 Subject: [PATCH 6624/7006] virtio_balloon: do not change memory amount visible via /proc/meminfo Balloon device is frequently used as a mean of cooperative memory control in between guest and host to manage memory overcommitment. This is the typical case for any hosting workload when KVM guest is provided for end-user. Though there is a problem in this setup. The end-user and hosting provider have signed SLA agreement in which some amount of memory is guaranted for the guest. The good thing is that this memory will be given to the guest when the guest will really need it (f.e. with OOM in guest and with VIRTIO_BALLOON_F_DEFLATE_ON_OOM configuration flag set). The bad thing is that end-user does not know this. Balloon by default reduce the amount of memory exposed to the end-user each time when the page is stolen from guest or returned back by using adjust_managed_page_count and thus /proc/meminfo shows reduced amount of memory. Fortunately the solution is simple, we should just avoid to call adjust_managed_page_count with VIRTIO_BALLOON_F_DEFLATE_ON_OOM set. Signed-off-by: Denis V. Lunev CC: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_balloon.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 8543c9a97307a..7efc32945810e 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -157,7 +157,9 @@ static void fill_balloon(struct virtio_balloon *vb, size_t num) } set_page_pfns(vb->pfns + vb->num_pfns, page); vb->num_pages += VIRTIO_BALLOON_PAGES_PER_PAGE; - adjust_managed_page_count(page, -1); + if (!virtio_has_feature(vb->vdev, + VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) + adjust_managed_page_count(page, -1); } /* Did we get any? */ @@ -173,7 +175,9 @@ static void release_pages_balloon(struct virtio_balloon *vb) /* Find pfns pointing at start of each page, get pages and free them. */ for (i = 0; i < vb->num_pfns; i += VIRTIO_BALLOON_PAGES_PER_PAGE) { struct page *page = balloon_pfn_to_page(vb->pfns[i]); - adjust_managed_page_count(page, 1); + if (!virtio_has_feature(vb->vdev, + VIRTIO_BALLOON_F_DEFLATE_ON_OOM)) + adjust_managed_page_count(page, 1); put_page(page); /* balloon reference */ } } -- GitLab From e85376cbd23299e4d40bace0cb5ab867b270fdbd Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Thu, 27 Aug 2015 13:13:31 +0200 Subject: [PATCH 6625/7006] drm/i915: Fix broken mst get_hw_state. connector->encoder is initialized as NULL. Fix this by setting it in during pre enable. MST connectors are not read out during initial hw readout, and have no fixed encoder mappings. So it's harmless to return false when the connector has never been assigned to an encoder. Signed-off-by: Maarten Lankhorst Reviewed-by: Ander Conselvan de Oliveira Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 8 ++++---- drivers/gpu/drm/i915/intel_dp_mst.c | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index ca9278be49f7d..8cc9264f78094 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6305,7 +6305,7 @@ static void intel_connector_check_state(struct intel_connector *connector) connector->base.name); if (connector->get_hw_state(connector)) { - struct drm_encoder *encoder = &connector->encoder->base; + struct intel_encoder *encoder = connector->encoder; struct drm_connector_state *conn_state = connector->base.state; I915_STATE_WARN(!crtc, @@ -6317,13 +6317,13 @@ static void intel_connector_check_state(struct intel_connector *connector) I915_STATE_WARN(!crtc->state->active, "connector is active, but attached crtc isn't\n"); - if (!encoder) + if (!encoder || encoder->type == INTEL_OUTPUT_DP_MST) return; - I915_STATE_WARN(conn_state->best_encoder != encoder, + I915_STATE_WARN(conn_state->best_encoder != &encoder->base, "atomic encoder doesn't match attached encoder\n"); - I915_STATE_WARN(conn_state->crtc != encoder->crtc, + I915_STATE_WARN(conn_state->crtc != encoder->base.crtc, "attached encoder crtc differs from connector crtc\n"); } else { I915_STATE_WARN(crtc && crtc->state->active, diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 983553cf8b74e..3e4be5a3becdd 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -173,6 +173,11 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) return; } + /* MST encoders are bound to a crtc, not to a connector, + * force the mapping here for get_hw_state. + */ + found->encoder = encoder; + DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); intel_mst->port = found->port; @@ -400,7 +405,7 @@ static const struct drm_encoder_funcs intel_dp_mst_enc_funcs = { static bool intel_dp_mst_get_hw_state(struct intel_connector *connector) { - if (connector->encoder) { + if (connector->encoder && connector->base.state->crtc) { enum pipe pipe; if (!connector->encoder->get_hw_state(connector->encoder, &pipe)) return false; -- GitLab From 38d9029a652cb2925a97a8484f6e8f2c85fd55bb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Fri, 31 Jul 2015 19:34:46 -0700 Subject: [PATCH 6626/7006] parisc: Define ioremap_uc and ioremap_wc Commit 3cc2dac5be3f ("drivers/video/fbdev/atyfb: Replace MTRR UC hole with strong UC") introduces calls to ioremap_wc and ioremap_uc. This causes build failures with parisc:allmodconfig. Map the missing functions to ioremap_nocache. Fixes: 3cc2dac5be3f ("drivers/video/fbdev/atyfb: Replace MTRR UC hole with strong UC") Cc: Luis R. Rodriguez Cc: Paul Gortmaker Signed-off-by: Guenter Roeck Signed-off-by: Helge Deller --- arch/parisc/include/asm/io.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h index 8cd0abf28ffbb..1a16f1d1075fc 100644 --- a/arch/parisc/include/asm/io.h +++ b/arch/parisc/include/asm/io.h @@ -137,6 +137,8 @@ static inline void __iomem * ioremap(unsigned long offset, unsigned long size) return __ioremap(offset, size, _PAGE_NO_CACHE); } #define ioremap_nocache(off, sz) ioremap((off), (sz)) +#define ioremap_wc ioremap_nocache +#define ioremap_uc ioremap_nocache extern void iounmap(const volatile void __iomem *addr); -- GitLab From e02a653e15d8d32e9e768fd99a3271aafe5c5d77 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 2 Sep 2015 18:17:29 +0200 Subject: [PATCH 6627/7006] PCI,parisc: Enable 64-bit bus addresses on PA-RISC Commit 3a9ad0b ("PCI: Add pci_bus_addr_t") unconditionally introduced usage of 64-bit PCI bus addresses on all 64-bit platforms which broke PA-RISC. It turned out that due to enabling the 64-bit addresses, the PCI logic decided to use the GMMIO instead of the LMMIO region. This commit simply disables registering the GMMIO and thus we fall back to use the LMMIO region as before. Reverts commit 45ea2a5fed6dacb9bb0558d8b21eacc1c45d5bb4 ("PCI: Don't use 64-bit bus addresses on PA-RISC") To: linux-parisc@vger.kernel.org Cc: linux-pci@vger.kernel.org Cc: Bjorn Helgaas Cc: Meelis Roos Cc: stable@vger.kernel.org # v3.19+ Signed-off-by: Helge Deller --- drivers/parisc/lba_pci.c | 7 +++++-- drivers/pci/Kconfig | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c index 901e1a3fa4e26..7b9e89ba0465f 100644 --- a/drivers/parisc/lba_pci.c +++ b/drivers/parisc/lba_pci.c @@ -1555,8 +1555,11 @@ lba_driver_probe(struct parisc_device *dev) if (lba_dev->hba.lmmio_space.flags) pci_add_resource_offset(&resources, &lba_dev->hba.lmmio_space, lba_dev->hba.lmmio_space_offset); - if (lba_dev->hba.gmmio_space.flags) - pci_add_resource(&resources, &lba_dev->hba.gmmio_space); + if (lba_dev->hba.gmmio_space.flags) { + /* pci_add_resource(&resources, &lba_dev->hba.gmmio_space); */ + pr_warn("LBA: Not registering GMMIO space %pR\n", + &lba_dev->hba.gmmio_space); + } pci_add_resource(&resources, &lba_dev->hba.bus_num); diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig index 944f50015ed07..73de4efcbe6ed 100644 --- a/drivers/pci/Kconfig +++ b/drivers/pci/Kconfig @@ -2,7 +2,7 @@ # PCI configuration # config PCI_BUS_ADDR_T_64BIT - def_bool y if (ARCH_DMA_ADDR_T_64BIT || (64BIT && !PARISC)) + def_bool y if (ARCH_DMA_ADDR_T_64BIT || 64BIT) depends on PCI config PCI_MSI -- GitLab From 699817c3df46eb209044d8c9eb20c6ff6c67c81d Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Wed, 2 Sep 2015 18:18:48 +0200 Subject: [PATCH 6628/7006] parisc: Additionally check for in_atomic() in page fault handler Craig Estey noticed that we didn't checked for in_atomic() in our page fault handler like other architectures. This commit adds this check by using faulthandler_disabled() which includes a check for pagefault_disabled() and in_atomic(). Reported-by: Craig Estey Signed-off-by: Helge Deller --- arch/parisc/mm/fault.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 15503adddf4f5..a762864ec92e9 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c @@ -207,7 +207,7 @@ void do_page_fault(struct pt_regs *regs, unsigned long code, int fault; unsigned int flags; - if (pagefault_disabled()) + if (faulthandler_disabled()) goto no_context; tsk = current; -- GitLab From b1b4e435e4ef7de77f07bf2a42c8380b960c2d44 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Thu, 3 Sep 2015 22:45:21 +0200 Subject: [PATCH 6629/7006] parisc: Filter out spurious interrupts in PA-RISC irq handler When detecting a serial port on newer PA-RISC machines (with iosapic) we have a long way to go to find the right IRQ line, registering it, then registering the serial port and the irq handler for the serial port. During this phase spurious interrupts for the serial port may happen which then crashes the kernel because the action handler might not have been set up yet. So, basically it's a race condition between the serial port hardware and the CPU which sets up the necessary fields in the irq sructs. The main reason for this race is, that we unmask the serial port irqs too early without having set up everything properly before (which isn't easily possible because we need the IRQ number to register the serial ports). This patch is a work-around for this problem. It adds checks to the CPU irq handler to verify if the IRQ action field has been initialized already. If not, we just skip this interrupt (which isn't critical for a serial port at bootup). The real fix would probably involve rewriting all PA-RISC specific IRQ code (for CPU, IOSAPIC, GSC and EISA) to use IRQ domains with proper parenting of the irq chips and proper irq enabling along this line. This bug has been in the PA-RISC port since the beginning, but the crashes happened very rarely with currently used hardware. But on the latest machine which I bought (a C8000 workstation), which uses the fastest CPUs (4 x PA8900, 1GHz) and which has the largest possible L1 cache size (64MB each), the kernel crashed at every boot because of this race. So, without this patch the machine would currently be unuseable. For the record, here is the flow logic: 1. serial_init_chip() in 8250_gsc.c calls iosapic_serial_irq(). 2. iosapic_serial_irq() calls txn_alloc_irq() to find the irq. 3. iosapic_serial_irq() calls cpu_claim_irq() to register the CPU irq 4. cpu_claim_irq() unmasks the CPU irq (which it shouldn't!) 5. serial_init_chip() then registers the 8250 port. Problems: - In step 4 the CPU irq shouldn't have been registered yet, but after step 5 - If serial irq happens between 4 and 5 have finished, the kernel will crash Signed-off-by: Helge Deller --- arch/parisc/kernel/irq.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c index 413ec3c3f9cc5..ba5e1c7b1f177 100644 --- a/arch/parisc/kernel/irq.c +++ b/arch/parisc/kernel/irq.c @@ -507,8 +507,8 @@ void do_cpu_irq_mask(struct pt_regs *regs) struct pt_regs *old_regs; unsigned long eirr_val; int irq, cpu = smp_processor_id(); -#ifdef CONFIG_SMP struct irq_data *irq_data; +#ifdef CONFIG_SMP cpumask_t dest; #endif @@ -521,8 +521,13 @@ void do_cpu_irq_mask(struct pt_regs *regs) goto set_out; irq = eirr_to_irq(eirr_val); -#ifdef CONFIG_SMP irq_data = irq_get_irq_data(irq); + + /* Filter out spurious interrupts, mostly from serial port at bootup */ + if (unlikely(!irq_desc_has_action(irq_data_to_desc(irq_data)))) + goto set_out; + +#ifdef CONFIG_SMP cpumask_copy(&dest, irq_data_get_affinity_mask(irq_data)); if (irqd_is_per_cpu(irq_data) && !cpumask_test_cpu(smp_processor_id(), &dest)) { -- GitLab From 1b59ddfcf1678de38a1f8ca9fb8ea5eebeff1843 Mon Sep 17 00:00:00 2001 From: John David Anglin Date: Mon, 7 Sep 2015 20:13:28 -0400 Subject: [PATCH 6630/7006] parisc: Use double word condition in 64bit CAS operation The attached change fixes the condition used in the "sub" instruction. A double word comparison is needed. This fixes the 64-bit LWS CAS operation on 64-bit kernels. I can now enable 64-bit atomic support in GCC. Cc: Signed-off-by: John David Anglin Signed-off-by: Helge Deller --- arch/parisc/kernel/syscall.S | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S index 7ef22e3387e09..0b8d26d3ba43b 100644 --- a/arch/parisc/kernel/syscall.S +++ b/arch/parisc/kernel/syscall.S @@ -821,7 +821,7 @@ cas2_action: /* 64bit CAS */ #ifdef CONFIG_64BIT 19: ldd,ma 0(%sr3,%r26), %r29 - sub,= %r29, %r25, %r0 + sub,*= %r29, %r25, %r0 b,n cas2_end 20: std,ma %r24, 0(%sr3,%r26) copy %r0, %r28 -- GitLab From eafd72e016c69df511b14a98b61e439c58ad9c51 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 19 Aug 2015 18:52:34 +0200 Subject: [PATCH 6631/7006] xen: avoid early crash of memory limited dom0 Commit b1c9f169047b ("xen: split counting of extra memory pages...") introduced an error when dom0 was started with limited memory. The problem arises in case dom0 is started with initial memory and maximum memory being the same and exactly a multiple of 1 GB. The kernel must be configured without CONFIG_XEN_BALLOON_MEMORY_HOTPLUG for the problem to happen. In this case it will crash very early during boot due to the virtual mapped p2m list not being large enough to be able to remap any memory: (XEN) Freed 304kB init memory. mapping kernel into physical memory about to get started... (XEN) traps.c:459:d0v0 Unhandled invalid opcode fault/trap [#6] on VCPU 0 [ec=0000] (XEN) domain_crash_sync called from entry.S: fault at ffff82d080229a93 create_bounce_frame+0x12b/0x13a (XEN) Domain 0 (vcpu#0) crashed on cpu#0: (XEN) ----[ Xen-4.5.2-pre x86_64 debug=n Not tainted ]---- (XEN) CPU: 0 (XEN) RIP: e033:[] (XEN) RFLAGS: 0000000000000206 EM: 1 CONTEXT: pv guest (d0v0) (XEN) rax: ffffffff81db2000 rbx: 000000004d000000 rcx: 0000000000000000 (XEN) rdx: 000000004d000000 rsi: 0000000000063000 rdi: 000000004d063000 (XEN) rbp: ffffffff81c03d78 rsp: ffffffff81c03d28 r8: 0000000000023000 (XEN) r9: 00000001040ff000 r10: 0000000000007ff0 r11: 0000000000000000 (XEN) r12: 0000000000063000 r13: 000000000004d000 r14: 0000000000000063 (XEN) r15: 0000000000000063 cr0: 0000000080050033 cr4: 00000000000006f0 (XEN) cr3: 0000000105c0f000 cr2: ffffc90000268000 (XEN) ds: 0000 es: 0000 fs: 0000 gs: 0000 ss: e02b cs: e033 (XEN) Guest stack trace from rsp=ffffffff81c03d28: (XEN) 0000000000000000 0000000000000000 ffffffff81d120cb 000000010000e030 (XEN) 0000000000010006 ffffffff81c03d68 000000000000e02b ffffffffffffffff (XEN) 0000000000000063 000000000004d063 ffffffff81c03de8 ffffffff81d130a7 (XEN) ffffffff81c03de8 000000000004d000 00000001040ff000 0000000000105db1 (XEN) 00000001040ff001 000000000004d062 ffff8800092d6ff8 0000000002027000 (XEN) ffff8800094d8340 ffff8800092d6ff8 00003ffffffff000 ffff8800092d7ff8 (XEN) ffffffff81c03e48 ffffffff81d13c43 ffff8800094d8000 ffff8800094d9000 (XEN) 0000000000000000 ffff8800092d6000 00000000092d6000 000000004cfbf000 (XEN) 00000000092d6000 00000000052d5442 0000000000000000 0000000000000000 (XEN) ffffffff81c03ed8 ffffffff81d185c1 0000000000000000 0000000000000000 (XEN) ffffffff81c03e78 ffffffff810f8ca4 ffffffff81c03ed8 ffffffff8171a15d (XEN) 0000000000000010 ffffffff81c03ee8 0000000000000000 0000000000000000 (XEN) ffffffff81f0e402 ffffffffffffffff ffffffff81dae900 0000000000000000 (XEN) 0000000000000000 0000000000000000 ffffffff81c03f28 ffffffff81d0cf0f (XEN) 0000000000000000 0000000000000000 0000000000000000 ffffffff81db82e0 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) ffffffff81c03f38 ffffffff81d0c603 ffffffff81c03ff8 ffffffff81d11c86 (XEN) 0300000100000032 0000000000000005 0000000000000020 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) 0000000000000000 0000000000000000 0000000000000000 0000000000000000 (XEN) Domain 0 crashed: rebooting machine in 5 seconds. This can be avoided by allocating aneough space for the p2m to cover the maximum memory of dom0 plus the identity mapped holes required for PCI space, BIOS etc. Reported-by: Boris Ostrovsky Signed-off-by: Juergen Gross Signed-off-by: David Vrabel --- arch/x86/xen/setup.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index a1a77eabe8588..ead0d363bfba8 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -789,11 +789,12 @@ char * __init xen_memory_setup(void) &xen_e820_map_entries); max_pages = xen_get_max_pages(); - if (max_pages > max_pfn) - extra_pages += max_pages - max_pfn; /* How many extra pages do we need due to remapping? */ - extra_pages += xen_count_remap_pages(max_pfn); + max_pages += xen_count_remap_pages(max_pfn); + + if (max_pages > max_pfn) + extra_pages += max_pages - max_pfn; /* * Clamp the amount of extra memory to a EXTRA_MEM_RATIO -- GitLab From ab24507cfae8d916814bb6c16f66e453184a29a5 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Wed, 19 Aug 2015 18:53:11 +0200 Subject: [PATCH 6632/7006] xen: avoid another early crash of memory limited dom0 Commit b1c9f169047b ("xen: split counting of extra memory pages...") introduced an error when dom0 was started with limited memory occurring only on some hardware. The problem arises in case dom0 is started with initial memory and maximum memory being the same. The kernel must be configured without CONFIG_XEN_BALLOON_MEMORY_HOTPLUG for the problem to happen. If all of this is true and the E820 map of the machine is sparse (some areas are not covered) then the machine might crash early in the boot process. An example E820 map triggering the problem looks like this: [ 0.000000] e820: BIOS-provided physical RAM map: [ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009d7ff] usable [ 0.000000] BIOS-e820: [mem 0x000000000009d800-0x000000000009ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000000e0000-0x00000000000fffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x00000000cf7fafff] usable [ 0.000000] BIOS-e820: [mem 0x00000000cf7fb000-0x00000000cf95ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000cf960000-0x00000000cfb62fff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfb63000-0x00000000cfd14fff] usable [ 0.000000] BIOS-e820: [mem 0x00000000cfd15000-0x00000000cfd61fff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfd62000-0x00000000cfd6cfff] ACPI data [ 0.000000] BIOS-e820: [mem 0x00000000cfd6d000-0x00000000cfd6ffff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfd70000-0x00000000cfd70fff] usable [ 0.000000] BIOS-e820: [mem 0x00000000cfd71000-0x00000000cfea8fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000cfea9000-0x00000000cfeb9fff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfeba000-0x00000000cfecafff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000cfecb000-0x00000000cfecbfff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfecc000-0x00000000cfedbfff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000cfedc000-0x00000000cfedcfff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfedd000-0x00000000cfeddfff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000cfede000-0x00000000cfee3fff] ACPI NVS [ 0.000000] BIOS-e820: [mem 0x00000000cfee4000-0x00000000cfef6fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000cfef7000-0x00000000cfefffff] usable [ 0.000000] BIOS-e820: [mem 0x00000000e0000000-0x00000000efffffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fec00000-0x00000000fec00fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fec10000-0x00000000fec10fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fed00000-0x00000000fed00fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fed40000-0x00000000fed44fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fed61000-0x00000000fed70fff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000fed80000-0x00000000fed8ffff] reserved [ 0.000000] BIOS-e820: [mem 0x00000000ff000000-0x00000000ffffffff] reserved [ 0.000000] BIOS-e820: [mem 0x0000000100001000-0x000000020effffff] usable In this case the area a0000-dffff isn't present in the map. This will confuse the memory setup of the domain when remapping the memory from such holes to populated areas. To avoid the problem the accounting of to be remapped memory has to count such holes in the E820 map as well. Reported-by: Boris Ostrovsky Signed-off-by: Juergen Gross Signed-off-by: David Vrabel --- arch/x86/xen/setup.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index ead0d363bfba8..7a5d5666677f0 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -593,20 +593,27 @@ static void __init xen_ignore_unusable(void) static unsigned long __init xen_count_remap_pages(unsigned long max_pfn) { unsigned long extra = 0; + unsigned long start_pfn, end_pfn; const struct e820entry *entry = xen_e820_map; int i; + end_pfn = 0; for (i = 0; i < xen_e820_map_entries; i++, entry++) { - unsigned long start_pfn = PFN_DOWN(entry->addr); - unsigned long end_pfn = PFN_UP(entry->addr + entry->size); + start_pfn = PFN_DOWN(entry->addr); + /* Adjacent regions on non-page boundaries handling! */ + end_pfn = min(end_pfn, start_pfn); if (start_pfn >= max_pfn) - break; - if (entry->type == E820_RAM) - continue; - if (end_pfn >= max_pfn) - end_pfn = max_pfn; - extra += end_pfn - start_pfn; + return extra + max_pfn - end_pfn; + + /* Add any holes in map to result. */ + extra += start_pfn - end_pfn; + + end_pfn = PFN_UP(entry->addr + entry->size); + end_pfn = min(end_pfn, max_pfn); + + if (entry->type != E820_RAM) + extra += end_pfn - start_pfn; } return extra; -- GitLab From cb9e444b5aaa900bb4310da411315b6947c53e37 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 4 Sep 2015 14:18:08 +0200 Subject: [PATCH 6633/7006] xen: limit memory to architectural maximum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a pv-domain (including dom0) is started it tries to size it's p2m list according to the maximum possible memory amount it ever can achieve. Limit the initial maximum memory size to the architectural limit of the hardware in order to avoid overflows during remapping of memory. This problem will occur when dom0 is started with an initial memory size being a multiple of 1GB, but without specifying it's maximum memory size. The kernel must be configured without CONFIG_XEN_BALLOON_MEMORY_HOTPLUG for the problem to happen. Reported-by: Roger Pau Monné Tested-by: Roger Pau Monné Signed-off-by: Juergen Gross Signed-off-by: David Vrabel --- arch/x86/xen/setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 7a5d5666677f0..70de4c8b8f271 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -531,7 +531,7 @@ static unsigned long __init xen_get_pages_limit(void) #ifdef CONFIG_X86_32 limit = GB(64) / PAGE_SIZE; #else - limit = ~0ul; + limit = MAXMEM / PAGE_SIZE; if (!xen_initial_domain() && xen_512gb_limit) limit = GB(512) / PAGE_SIZE; #endif -- GitLab From 626d7508664c4bc8e67f496da4387ecd0c410b8c Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Fri, 4 Sep 2015 14:05:51 +0200 Subject: [PATCH 6634/7006] xen: switch extra memory accounting to use pfns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of using physical addresses for accounting of extra memory areas available for ballooning switch to pfns as this is much less error prone regarding partial pages. Reported-by: Roger Pau Monné Tested-by: Roger Pau Monné Signed-off-by: Juergen Gross Signed-off-by: David Vrabel --- arch/x86/xen/setup.c | 80 ++++++++++++++++++++++++------------------- drivers/xen/balloon.c | 6 ++-- include/xen/page.h | 4 +-- 3 files changed, 49 insertions(+), 41 deletions(-) diff --git a/arch/x86/xen/setup.c b/arch/x86/xen/setup.c index 70de4c8b8f271..f5ef6746d47a0 100644 --- a/arch/x86/xen/setup.c +++ b/arch/x86/xen/setup.c @@ -90,62 +90,69 @@ static void __init xen_parse_512gb(void) xen_512gb_limit = val; } -static void __init xen_add_extra_mem(phys_addr_t start, phys_addr_t size) +static void __init xen_add_extra_mem(unsigned long start_pfn, + unsigned long n_pfns) { int i; + /* + * No need to check for zero size, should happen rarely and will only + * write a new entry regarded to be unused due to zero size. + */ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { /* Add new region. */ - if (xen_extra_mem[i].size == 0) { - xen_extra_mem[i].start = start; - xen_extra_mem[i].size = size; + if (xen_extra_mem[i].n_pfns == 0) { + xen_extra_mem[i].start_pfn = start_pfn; + xen_extra_mem[i].n_pfns = n_pfns; break; } /* Append to existing region. */ - if (xen_extra_mem[i].start + xen_extra_mem[i].size == start) { - xen_extra_mem[i].size += size; + if (xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns == + start_pfn) { + xen_extra_mem[i].n_pfns += n_pfns; break; } } if (i == XEN_EXTRA_MEM_MAX_REGIONS) printk(KERN_WARNING "Warning: not enough extra memory regions\n"); - memblock_reserve(start, size); + memblock_reserve(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns)); } -static void __init xen_del_extra_mem(phys_addr_t start, phys_addr_t size) +static void __init xen_del_extra_mem(unsigned long start_pfn, + unsigned long n_pfns) { int i; - phys_addr_t start_r, size_r; + unsigned long start_r, size_r; for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { - start_r = xen_extra_mem[i].start; - size_r = xen_extra_mem[i].size; + start_r = xen_extra_mem[i].start_pfn; + size_r = xen_extra_mem[i].n_pfns; /* Start of region. */ - if (start_r == start) { - BUG_ON(size > size_r); - xen_extra_mem[i].start += size; - xen_extra_mem[i].size -= size; + if (start_r == start_pfn) { + BUG_ON(n_pfns > size_r); + xen_extra_mem[i].start_pfn += n_pfns; + xen_extra_mem[i].n_pfns -= n_pfns; break; } /* End of region. */ - if (start_r + size_r == start + size) { - BUG_ON(size > size_r); - xen_extra_mem[i].size -= size; + if (start_r + size_r == start_pfn + n_pfns) { + BUG_ON(n_pfns > size_r); + xen_extra_mem[i].n_pfns -= n_pfns; break; } /* Mid of region. */ - if (start > start_r && start < start_r + size_r) { - BUG_ON(start + size > start_r + size_r); - xen_extra_mem[i].size = start - start_r; + if (start_pfn > start_r && start_pfn < start_r + size_r) { + BUG_ON(start_pfn + n_pfns > start_r + size_r); + xen_extra_mem[i].n_pfns = start_pfn - start_r; /* Calling memblock_reserve() again is okay. */ - xen_add_extra_mem(start + size, start_r + size_r - - (start + size)); + xen_add_extra_mem(start_pfn + n_pfns, start_r + size_r - + (start_pfn + n_pfns)); break; } } - memblock_free(start, size); + memblock_free(PFN_PHYS(start_pfn), PFN_PHYS(n_pfns)); } /* @@ -156,11 +163,10 @@ static void __init xen_del_extra_mem(phys_addr_t start, phys_addr_t size) unsigned long __ref xen_chk_extra_mem(unsigned long pfn) { int i; - phys_addr_t addr = PFN_PHYS(pfn); for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { - if (addr >= xen_extra_mem[i].start && - addr < xen_extra_mem[i].start + xen_extra_mem[i].size) + if (pfn >= xen_extra_mem[i].start_pfn && + pfn < xen_extra_mem[i].start_pfn + xen_extra_mem[i].n_pfns) return INVALID_P2M_ENTRY; } @@ -176,10 +182,10 @@ void __init xen_inv_extra_mem(void) int i; for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) { - if (!xen_extra_mem[i].size) + if (!xen_extra_mem[i].n_pfns) continue; - pfn_s = PFN_DOWN(xen_extra_mem[i].start); - pfn_e = PFN_UP(xen_extra_mem[i].start + xen_extra_mem[i].size); + pfn_s = xen_extra_mem[i].start_pfn; + pfn_e = pfn_s + xen_extra_mem[i].n_pfns; for (pfn = pfn_s; pfn < pfn_e; pfn++) set_phys_to_machine(pfn, INVALID_P2M_ENTRY); } @@ -507,7 +513,7 @@ void __init xen_remap_memory(void) } else if (pfn_s + len == xen_remap_buf.target_pfn) { len += xen_remap_buf.size; } else { - xen_del_extra_mem(PFN_PHYS(pfn_s), PFN_PHYS(len)); + xen_del_extra_mem(pfn_s, len); pfn_s = xen_remap_buf.target_pfn; len = xen_remap_buf.size; } @@ -517,7 +523,7 @@ void __init xen_remap_memory(void) } if (pfn_s != ~0UL && len) - xen_del_extra_mem(PFN_PHYS(pfn_s), PFN_PHYS(len)); + xen_del_extra_mem(pfn_s, len); set_pte_mfn(buf, mfn_save, PAGE_KERNEL); @@ -744,7 +750,7 @@ static void __init xen_reserve_xen_mfnlist(void) **/ char * __init xen_memory_setup(void) { - unsigned long max_pfn; + unsigned long max_pfn, pfn_s, n_pfns; phys_addr_t mem_end, addr, size, chunk_size; u32 type; int rc; @@ -831,9 +837,11 @@ char * __init xen_memory_setup(void) chunk_size = min(size, mem_end - addr); } else if (extra_pages) { chunk_size = min(size, PFN_PHYS(extra_pages)); - extra_pages -= PFN_DOWN(chunk_size); - xen_add_extra_mem(addr, chunk_size); - xen_max_p2m_pfn = PFN_DOWN(addr + chunk_size); + pfn_s = PFN_UP(addr); + n_pfns = PFN_DOWN(addr + chunk_size) - pfn_s; + extra_pages -= n_pfns; + xen_add_extra_mem(pfn_s, n_pfns); + xen_max_p2m_pfn = pfn_s + n_pfns; } else type = E820_UNUSABLE; } diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index bf4a23c7c5918..1fa633b2d556e 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -638,9 +638,9 @@ static int __init balloon_init(void) * regions (see arch/x86/xen/setup.c). */ for (i = 0; i < XEN_EXTRA_MEM_MAX_REGIONS; i++) - if (xen_extra_mem[i].size) - balloon_add_region(PFN_UP(xen_extra_mem[i].start), - PFN_DOWN(xen_extra_mem[i].size)); + if (xen_extra_mem[i].n_pfns) + balloon_add_region(xen_extra_mem[i].start_pfn, + xen_extra_mem[i].n_pfns); return 0; } diff --git a/include/xen/page.h b/include/xen/page.h index c5ed20bb3fe96..a5983da2f5cd9 100644 --- a/include/xen/page.h +++ b/include/xen/page.h @@ -9,8 +9,8 @@ static inline unsigned long page_to_mfn(struct page *page) } struct xen_memory_region { - phys_addr_t start; - phys_addr_t size; + unsigned long start_pfn; + unsigned long n_pfns; }; #define XEN_EXTRA_MEM_MAX_REGIONS 128 /* == E820MAX */ -- GitLab From 72581cecee411be2b2c00226c98e0c20aab337a2 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 8 Sep 2015 17:49:31 +0200 Subject: [PATCH 6635/7006] parisc: Drop CONFIG_SMP around update_cr16_clocksource() No need to use CONFIG_SMP around update_cr16_clocksource(). It checks for num_online_cpus() beeing greater than 1, which is always 1 in UP builds. Signed-off-by: Helge Deller --- arch/parisc/kernel/time.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 70e105d62423f..cc68a4fbce6a9 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -202,7 +202,6 @@ static struct clocksource clocksource_cr16 = { .flags = CLOCK_SOURCE_IS_CONTINUOUS, }; -#ifdef CONFIG_SMP int update_cr16_clocksource(void) { /* since the cr16 cycle counters are not synchronized across CPUs, @@ -214,12 +213,6 @@ int update_cr16_clocksource(void) return 0; } -#else -int update_cr16_clocksource(void) -{ - return 0; /* no change */ -} -#endif /*CONFIG_SMP*/ void __init start_cpu_itimer(void) { -- GitLab From 6dc0dcde406bb0e40ad6a6f45f44534d3a094205 Mon Sep 17 00:00:00 2001 From: Helge Deller Date: Tue, 8 Sep 2015 17:50:03 +0200 Subject: [PATCH 6636/7006] parisc: Use platform_device_register_simple("rtc-generic") Signed-off-by: Helge Deller --- arch/parisc/kernel/time.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index cc68a4fbce6a9..400acac0a304d 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -224,20 +224,14 @@ void __init start_cpu_itimer(void) per_cpu(cpu_data, cpu).it_value = next_tick; } -static struct platform_device rtc_generic_dev = { - .name = "rtc-generic", - .id = -1, -}; - static int __init rtc_init(void) { - if (platform_device_register(&rtc_generic_dev) < 0) - printk(KERN_ERR "unable to register rtc device...\n"); + struct platform_device *pdev; - /* not necessarily an error */ - return 0; + pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0); + return PTR_ERR_OR_ZERO(pdev); } -module_init(rtc_init); +device_initcall(rtc_init); void read_persistent_clock(struct timespec *ts) { -- GitLab From 32e09870eedfb501a6cb5729d8c23f44f8a7cbdd Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:35 +0100 Subject: [PATCH 6637/7006] xen: Make clear that swiotlb and biomerge are dealing with DMA address The swiotlb is required when programming a DMA address on ARM when a device is not protected by an IOMMU. In this case, the DMA address should always be equal to the machine address. For DOM0 memory, Xen ensure it by have an identity mapping between the guest address and host address. However, when mapping a foreign grant reference, the 1:1 model doesn't work. For ARM guest, most of the callers of pfn_to_mfn expects to get a GFN (Guest Frame Number), i.e a PFN (Page Frame Number) from the Linux point of view given that all ARM guest are auto-translated. Even though the name pfn_to_mfn is misleading, we need to ensure that those caller get a GFN and not by mistake a MFN. In pratical, I haven't seen error related to this but we should fix it for the sake of correctness. In order to fix the implementation of pfn_to_mfn on ARM in a follow-up patch, we have to introduce new helpers to return the DMA from a PFN and the invert. On x86, the new helpers will be an alias of pfn_to_mfn and mfn_to_pfn. The helpers will be used in swiotlb and xen_biovec_phys_mergeable. This is necessary in the latter because we have to ensure that the biovec code will not try to merge a biovec using foreign page and another using Linux memory. Lastly, the helper mfn_to_local_pfn has been renamed to bfn_to_local_pfn given that the only usage was in swiotlb. Signed-off-by: Julien Grall Reviewed-by: Stefano Stabellini Signed-off-by: David Vrabel --- arch/arm/include/asm/xen/page.h | 23 +++++++++++++++++++++-- arch/arm/xen/mm.c | 4 ++-- arch/x86/include/asm/xen/page.h | 8 ++++++-- drivers/xen/biomerge.c | 6 +++--- drivers/xen/swiotlb-xen.c | 16 ++++++++-------- 5 files changed, 40 insertions(+), 17 deletions(-) diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index 98b1084f8282e..5f76a9e7ef1b7 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -52,7 +52,26 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) return mfn; } -#define mfn_to_local_pfn(mfn) mfn_to_pfn(mfn) +/* Pseudo-physical <-> BUS conversion */ +static inline unsigned long pfn_to_bfn(unsigned long pfn) +{ + unsigned long mfn; + + if (phys_to_mach.rb_node != NULL) { + mfn = __pfn_to_mfn(pfn); + if (mfn != INVALID_P2M_ENTRY) + return mfn; + } + + return pfn; +} + +static inline unsigned long bfn_to_pfn(unsigned long bfn) +{ + return bfn; +} + +#define bfn_to_local_pfn(bfn) bfn_to_pfn(bfn) /* VIRT <-> MACHINE conversion */ #define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v))) @@ -96,7 +115,7 @@ static inline bool set_phys_to_machine(unsigned long pfn, unsigned long mfn) bool xen_arch_need_swiotlb(struct device *dev, unsigned long pfn, - unsigned long mfn); + unsigned long bfn); unsigned long xen_get_swiotlb_free_pages(unsigned int order); #endif /* _ASM_ARM_XEN_PAGE_H */ diff --git a/arch/arm/xen/mm.c b/arch/arm/xen/mm.c index 03e75fef15b82..6dd911d1f0ac6 100644 --- a/arch/arm/xen/mm.c +++ b/arch/arm/xen/mm.c @@ -139,9 +139,9 @@ void __xen_dma_sync_single_for_device(struct device *hwdev, bool xen_arch_need_swiotlb(struct device *dev, unsigned long pfn, - unsigned long mfn) + unsigned long bfn) { - return (!hypercall_cflush && (pfn != mfn) && !is_device_dma_coherent(dev)); + return (!hypercall_cflush && (pfn != bfn) && !is_device_dma_coherent(dev)); } int xen_create_contiguous_region(phys_addr_t pstart, unsigned int order, diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index a3804fbe1f36d..724bffbde54d5 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -176,6 +176,10 @@ static inline xpaddr_t machine_to_phys(xmaddr_t machine) return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset); } +/* Pseudo-physical <-> Bus conversion */ +#define pfn_to_bfn(pfn) pfn_to_mfn(pfn) +#define bfn_to_pfn(bfn) mfn_to_pfn(bfn) + /* * We detect special mappings in one of two ways: * 1. If the MFN is an I/O page then Xen will set the m2p entry @@ -196,7 +200,7 @@ static inline xpaddr_t machine_to_phys(xmaddr_t machine) * require. In all the cases we care about, the FOREIGN_FRAME bit is * masked (e.g., pfn_to_mfn()) so behaviour there is correct. */ -static inline unsigned long mfn_to_local_pfn(unsigned long mfn) +static inline unsigned long bfn_to_local_pfn(unsigned long mfn) { unsigned long pfn; @@ -262,7 +266,7 @@ void make_lowmem_page_readwrite(void *vaddr); static inline bool xen_arch_need_swiotlb(struct device *dev, unsigned long pfn, - unsigned long mfn) + unsigned long bfn) { return false; } diff --git a/drivers/xen/biomerge.c b/drivers/xen/biomerge.c index 0edb91c0de6bf..8ae2fc90e1ea8 100644 --- a/drivers/xen/biomerge.c +++ b/drivers/xen/biomerge.c @@ -6,10 +6,10 @@ bool xen_biovec_phys_mergeable(const struct bio_vec *vec1, const struct bio_vec *vec2) { - unsigned long mfn1 = pfn_to_mfn(page_to_pfn(vec1->bv_page)); - unsigned long mfn2 = pfn_to_mfn(page_to_pfn(vec2->bv_page)); + unsigned long bfn1 = pfn_to_bfn(page_to_pfn(vec1->bv_page)); + unsigned long bfn2 = pfn_to_bfn(page_to_pfn(vec2->bv_page)); return __BIOVEC_PHYS_MERGEABLE(vec1, vec2) && - ((mfn1 == mfn2) || ((mfn1+1) == mfn2)); + ((bfn1 == bfn2) || ((bfn1+1) == bfn2)); } EXPORT_SYMBOL(xen_biovec_phys_mergeable); diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 4c549323c605d..d757a3e610c6c 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -82,8 +82,8 @@ static u64 start_dma_addr; */ static inline dma_addr_t xen_phys_to_bus(phys_addr_t paddr) { - unsigned long mfn = pfn_to_mfn(PFN_DOWN(paddr)); - dma_addr_t dma = (dma_addr_t)mfn << PAGE_SHIFT; + unsigned long bfn = pfn_to_bfn(PFN_DOWN(paddr)); + dma_addr_t dma = (dma_addr_t)bfn << PAGE_SHIFT; dma |= paddr & ~PAGE_MASK; @@ -92,7 +92,7 @@ static inline dma_addr_t xen_phys_to_bus(phys_addr_t paddr) static inline phys_addr_t xen_bus_to_phys(dma_addr_t baddr) { - unsigned long pfn = mfn_to_pfn(PFN_DOWN(baddr)); + unsigned long pfn = bfn_to_pfn(PFN_DOWN(baddr)); dma_addr_t dma = (dma_addr_t)pfn << PAGE_SHIFT; phys_addr_t paddr = dma; @@ -110,15 +110,15 @@ static int check_pages_physically_contiguous(unsigned long pfn, unsigned int offset, size_t length) { - unsigned long next_mfn; + unsigned long next_bfn; int i; int nr_pages; - next_mfn = pfn_to_mfn(pfn); + next_bfn = pfn_to_bfn(pfn); nr_pages = (offset + length + PAGE_SIZE-1) >> PAGE_SHIFT; for (i = 1; i < nr_pages; i++) { - if (pfn_to_mfn(++pfn) != ++next_mfn) + if (pfn_to_bfn(++pfn) != ++next_bfn) return 0; } return 1; @@ -138,8 +138,8 @@ static inline int range_straddles_page_boundary(phys_addr_t p, size_t size) static int is_xen_swiotlb_buffer(dma_addr_t dma_addr) { - unsigned long mfn = PFN_DOWN(dma_addr); - unsigned long pfn = mfn_to_local_pfn(mfn); + unsigned long bfn = PFN_DOWN(dma_addr); + unsigned long pfn = bfn_to_local_pfn(bfn); phys_addr_t paddr; /* If the address is outside our domain, it CAN -- GitLab From 5192b35de47e47a0f736fe30da199f32030680e7 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:36 +0100 Subject: [PATCH 6638/7006] arm/xen: implement correctly pfn_to_mfn After the commit introducing convertion between DMA and guest addresses, all the callers of pfn_to_mfn are expecting to get a GFN (Guest Frame Number). On ARM, all the guests are auto-translated so the GFN is equal to the Linux PFN (Pseudo-physical Frame Number). The current implementation may return an MFN if the caller is passing a PFN associated to a mapped foreign grant. In pratice, I haven't seen the problem on running guest but we should fix it for the sake of correctness. Correct the implementation by always returning the pfn passed in parameter. A follow-up patch will take care to rename pfn_to_mfn to a suitable name. Signed-off-by: Julien Grall Reviewed-by: Stefano Stabellini Signed-off-by: David Vrabel --- arch/arm/include/asm/xen/page.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index 5f76a9e7ef1b7..911d62b4df26e 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -36,14 +36,6 @@ extern struct rb_root phys_to_mach; static inline unsigned long pfn_to_mfn(unsigned long pfn) { - unsigned long mfn; - - if (phys_to_mach.rb_node != NULL) { - mfn = __pfn_to_mfn(pfn); - if (mfn != INVALID_P2M_ENTRY) - return mfn; - } - return pfn; } -- GitLab From 0df4f266b3af90442bbeb5e685a84a80745beba0 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:37 +0100 Subject: [PATCH 6639/7006] xen: Use correctly the Xen memory terminologies Based on include/xen/mm.h [1], Linux is mistakenly using MFN when GFN is meant, I suspect this is because the first support for Xen was for PV. This resulted in some misimplementation of helpers on ARM and confused developers about the expected behavior. For instance, with pfn_to_mfn, we expect to get an MFN based on the name. Although, if we look at the implementation on x86, it's returning a GFN. For clarity and avoid new confusion, replace any reference to mfn with gfn in any helpers used by PV drivers. The x86 code will still keep some reference of pfn_to_mfn which may be used by all kind of guests No changes as been made in the hypercall field, even though they may be invalid, in order to keep the same as the defintion in xen repo. Note that page_to_mfn has been renamed to xen_page_to_gfn to avoid a name to close to the KVM function gfn_to_page. Take also the opportunity to simplify simple construction such as pfn_to_mfn(page_to_pfn(page)) into xen_page_to_gfn. More complex clean up will come in follow-up patches. [1] http://xenbits.xen.org/gitweb/?p=xen.git;a=commitdiff;h=e758ed14f390342513405dd766e874934573e6cb Signed-off-by: Julien Grall Reviewed-by: Stefano Stabellini Acked-by: Dmitry Torokhov Acked-by: Wei Liu Signed-off-by: David Vrabel --- arch/arm/include/asm/xen/page.h | 13 ++++----- arch/x86/include/asm/xen/page.h | 35 +++++++++++++++++++++++-- arch/x86/xen/smp.c | 2 +- drivers/block/xen-blkfront.c | 6 ++--- drivers/input/misc/xen-kbdfront.c | 4 +-- drivers/net/xen-netback/netback.c | 4 +-- drivers/net/xen-netfront.c | 12 +++++---- drivers/scsi/xen-scsifront.c | 10 +++---- drivers/tty/hvc/hvc_xen.c | 5 ++-- drivers/video/fbdev/xen-fbfront.c | 4 +-- drivers/xen/balloon.c | 2 +- drivers/xen/events/events_base.c | 2 +- drivers/xen/events/events_fifo.c | 4 +-- drivers/xen/gntalloc.c | 3 ++- drivers/xen/manage.c | 2 +- drivers/xen/tmem.c | 4 +-- drivers/xen/xenbus/xenbus_client.c | 2 +- drivers/xen/xenbus/xenbus_dev_backend.c | 2 +- drivers/xen/xenbus/xenbus_probe.c | 8 +++--- include/xen/page.h | 4 +-- 20 files changed, 81 insertions(+), 47 deletions(-) diff --git a/arch/arm/include/asm/xen/page.h b/arch/arm/include/asm/xen/page.h index 911d62b4df26e..127956353b006 100644 --- a/arch/arm/include/asm/xen/page.h +++ b/arch/arm/include/asm/xen/page.h @@ -34,14 +34,15 @@ typedef struct xpaddr { unsigned long __pfn_to_mfn(unsigned long pfn); extern struct rb_root phys_to_mach; -static inline unsigned long pfn_to_mfn(unsigned long pfn) +/* Pseudo-physical <-> Guest conversion */ +static inline unsigned long pfn_to_gfn(unsigned long pfn) { return pfn; } -static inline unsigned long mfn_to_pfn(unsigned long mfn) +static inline unsigned long gfn_to_pfn(unsigned long gfn) { - return mfn; + return gfn; } /* Pseudo-physical <-> BUS conversion */ @@ -65,9 +66,9 @@ static inline unsigned long bfn_to_pfn(unsigned long bfn) #define bfn_to_local_pfn(bfn) bfn_to_pfn(bfn) -/* VIRT <-> MACHINE conversion */ -#define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v))) -#define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) +/* VIRT <-> GUEST conversion */ +#define virt_to_gfn(v) (pfn_to_gfn(virt_to_pfn(v))) +#define gfn_to_virt(m) (__va(gfn_to_pfn(m) << PAGE_SHIFT)) /* Only used in PV code. But ARM guests are always HVM. */ static inline xmaddr_t arbitrary_virt_to_machine(void *vaddr) diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index 724bffbde54d5..0679e11d2cf7d 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -101,6 +101,11 @@ static inline unsigned long pfn_to_mfn(unsigned long pfn) { unsigned long mfn; + /* + * Some x86 code are still using pfn_to_mfn instead of + * pfn_to_mfn. This will have to be removed when we figured + * out which call. + */ if (xen_feature(XENFEAT_auto_translated_physmap)) return pfn; @@ -147,6 +152,11 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn) { unsigned long pfn; + /* + * Some x86 code are still using mfn_to_pfn instead of + * gfn_to_pfn. This will have to be removed when we figure + * out which call. + */ if (xen_feature(XENFEAT_auto_translated_physmap)) return mfn; @@ -176,9 +186,26 @@ static inline xpaddr_t machine_to_phys(xmaddr_t machine) return XPADDR(PFN_PHYS(mfn_to_pfn(PFN_DOWN(machine.maddr))) | offset); } +/* Pseudo-physical <-> Guest conversion */ +static inline unsigned long pfn_to_gfn(unsigned long pfn) +{ + if (xen_feature(XENFEAT_auto_translated_physmap)) + return pfn; + else + return pfn_to_mfn(pfn); +} + +static inline unsigned long gfn_to_pfn(unsigned long gfn) +{ + if (xen_feature(XENFEAT_auto_translated_physmap)) + return gfn; + else + return mfn_to_pfn(gfn); +} + /* Pseudo-physical <-> Bus conversion */ -#define pfn_to_bfn(pfn) pfn_to_mfn(pfn) -#define bfn_to_pfn(bfn) mfn_to_pfn(bfn) +#define pfn_to_bfn(pfn) pfn_to_gfn(pfn) +#define bfn_to_pfn(bfn) gfn_to_pfn(bfn) /* * We detect special mappings in one of two ways: @@ -219,6 +246,10 @@ static inline unsigned long bfn_to_local_pfn(unsigned long mfn) #define virt_to_mfn(v) (pfn_to_mfn(virt_to_pfn(v))) #define mfn_to_virt(m) (__va(mfn_to_pfn(m) << PAGE_SHIFT)) +/* VIRT <-> GUEST conversion */ +#define virt_to_gfn(v) (pfn_to_gfn(virt_to_pfn(v))) +#define gfn_to_virt(g) (__va(gfn_to_pfn(g) << PAGE_SHIFT)) + static inline unsigned long pte_mfn(pte_t pte) { return (pte.pte & PTE_PFN_MASK) >> PAGE_SHIFT; diff --git a/arch/x86/xen/smp.c b/arch/x86/xen/smp.c index 2a9ff73427916..3f4ebf0261f28 100644 --- a/arch/x86/xen/smp.c +++ b/arch/x86/xen/smp.c @@ -453,7 +453,7 @@ cpu_initialize_context(unsigned int cpu, struct task_struct *idle) } #endif ctxt->user_regs.esp = idle->thread.sp0 - sizeof(struct pt_regs); - ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir)); + ctxt->ctrlreg[3] = xen_pfn_to_cr3(virt_to_gfn(swapper_pg_dir)); if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, ctxt)) BUG(); diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index 5dd591d6c8596..432e1058721fd 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -250,7 +250,7 @@ static struct grant *get_grant(grant_ref_t *gref_head, struct blkfront_info *info) { struct grant *gnt_list_entry; - unsigned long buffer_mfn; + unsigned long buffer_gfn; BUG_ON(list_empty(&info->grants)); gnt_list_entry = list_first_entry(&info->grants, struct grant, @@ -269,10 +269,10 @@ static struct grant *get_grant(grant_ref_t *gref_head, BUG_ON(!pfn); gnt_list_entry->pfn = pfn; } - buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); + buffer_gfn = pfn_to_gfn(gnt_list_entry->pfn); gnttab_grant_foreign_access_ref(gnt_list_entry->gref, info->xbdev->otherend_id, - buffer_mfn, 0); + buffer_gfn, 0); return gnt_list_entry; } diff --git a/drivers/input/misc/xen-kbdfront.c b/drivers/input/misc/xen-kbdfront.c index 95599e478e19c..23d0549539d43 100644 --- a/drivers/input/misc/xen-kbdfront.c +++ b/drivers/input/misc/xen-kbdfront.c @@ -232,7 +232,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, struct xenbus_transaction xbt; ret = gnttab_grant_foreign_access(dev->otherend_id, - virt_to_mfn(info->page), 0); + virt_to_gfn(info->page), 0); if (ret < 0) return ret; info->gref = ret; @@ -255,7 +255,7 @@ static int xenkbd_connect_backend(struct xenbus_device *dev, goto error_irqh; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", - virt_to_mfn(info->page)); + virt_to_gfn(info->page)); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 3f44b522b8311..7c64c74711e8d 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -314,7 +314,7 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb } else { copy_gop->source.domid = DOMID_SELF; copy_gop->source.u.gmfn = - virt_to_mfn(page_address(page)); + virt_to_gfn(page_address(page)); } copy_gop->source.offset = offset; @@ -1296,7 +1296,7 @@ static void xenvif_tx_build_gops(struct xenvif_queue *queue, queue->tx_copy_ops[*copy_ops].source.offset = txreq.offset; queue->tx_copy_ops[*copy_ops].dest.u.gmfn = - virt_to_mfn(skb->data); + virt_to_gfn(skb->data); queue->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF; queue->tx_copy_ops[*copy_ops].dest.offset = offset_in_page(skb->data); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index f948c46d51329..47f791e608519 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -291,7 +291,7 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) struct sk_buff *skb; unsigned short id; grant_ref_t ref; - unsigned long pfn; + unsigned long gfn; struct xen_netif_rx_request *req; skb = xennet_alloc_one_rx_buffer(queue); @@ -307,12 +307,12 @@ static void xennet_alloc_rx_buffers(struct netfront_queue *queue) BUG_ON((signed short)ref < 0); queue->grant_rx_ref[id] = ref; - pfn = page_to_pfn(skb_frag_page(&skb_shinfo(skb)->frags[0])); + gfn = xen_page_to_gfn(skb_frag_page(&skb_shinfo(skb)->frags[0])); req = RING_GET_REQUEST(&queue->rx, req_prod); gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, - pfn_to_mfn(pfn), + gfn, 0); req->id = id; @@ -430,8 +430,10 @@ static struct xen_netif_tx_request *xennet_make_one_txreq( ref = gnttab_claim_grant_reference(&queue->gref_tx_head); BUG_ON((signed short)ref < 0); - gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id, - page_to_mfn(page), GNTMAP_readonly); + gnttab_grant_foreign_access_ref(ref, + queue->info->xbdev->otherend_id, + xen_page_to_gfn(page), + GNTMAP_readonly); queue->tx_skbs[id].skb = skb; queue->grant_tx_page[id] = page; diff --git a/drivers/scsi/xen-scsifront.c b/drivers/scsi/xen-scsifront.c index fad22caf0efff..9dc8687bf0480 100644 --- a/drivers/scsi/xen-scsifront.c +++ b/drivers/scsi/xen-scsifront.c @@ -377,7 +377,6 @@ static int map_data_for_request(struct vscsifrnt_info *info, unsigned int data_len = scsi_bufflen(sc); unsigned int data_grants = 0, seg_grants = 0; struct scatterlist *sg; - unsigned long mfn; struct scsiif_request_segment *seg; ring_req->nr_segments = 0; @@ -420,9 +419,9 @@ static int map_data_for_request(struct vscsifrnt_info *info, ref = gnttab_claim_grant_reference(&gref_head); BUG_ON(ref == -ENOSPC); - mfn = pfn_to_mfn(page_to_pfn(page)); gnttab_grant_foreign_access_ref(ref, - info->dev->otherend_id, mfn, 1); + info->dev->otherend_id, + xen_page_to_gfn(page), 1); shadow->gref[ref_cnt] = ref; ring_req->seg[ref_cnt].gref = ref; ring_req->seg[ref_cnt].offset = (uint16_t)off; @@ -454,9 +453,10 @@ static int map_data_for_request(struct vscsifrnt_info *info, ref = gnttab_claim_grant_reference(&gref_head); BUG_ON(ref == -ENOSPC); - mfn = pfn_to_mfn(page_to_pfn(page)); gnttab_grant_foreign_access_ref(ref, - info->dev->otherend_id, mfn, grant_ro); + info->dev->otherend_id, + xen_page_to_gfn(page), + grant_ro); shadow->gref[ref_cnt] = ref; seg->gref = ref; diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index a9d837f83ce83..efe5124a368de 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -265,7 +265,8 @@ static int xen_pv_console_init(void) return 0; } info->evtchn = xen_start_info->console.domU.evtchn; - info->intf = mfn_to_virt(xen_start_info->console.domU.mfn); + /* GFN == MFN for PV guest */ + info->intf = gfn_to_virt(xen_start_info->console.domU.mfn); info->vtermno = HVC_COOKIE; spin_lock(&xencons_lock); @@ -390,7 +391,7 @@ static int xencons_connect_backend(struct xenbus_device *dev, if (IS_ERR(info->hvc)) return PTR_ERR(info->hvc); if (xen_pv_domain()) - mfn = virt_to_mfn(info->intf); + mfn = virt_to_gfn(info->intf); else mfn = __pa(info->intf) >> PAGE_SHIFT; ret = gnttab_alloc_grant_references(1, &gref_head); diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 09dc44736c1ac..25e3cce0c35fc 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -539,7 +539,7 @@ static int xenfb_remove(struct xenbus_device *dev) static unsigned long vmalloc_to_mfn(void *address) { - return pfn_to_mfn(vmalloc_to_pfn(address)); + return pfn_to_gfn(vmalloc_to_pfn(address)); } static void xenfb_init_shared_page(struct xenfb_info *info, @@ -586,7 +586,7 @@ static int xenfb_connect_backend(struct xenbus_device *dev, goto unbind_irq; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", - virt_to_mfn(info->page)); + virt_to_gfn(info->page)); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c index 1fa633b2d556e..c79329fcfa78c 100644 --- a/drivers/xen/balloon.c +++ b/drivers/xen/balloon.c @@ -441,7 +441,7 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp) /* Update direct mapping, invalidate P2M, and add to balloon. */ for (i = 0; i < nr_pages; i++) { pfn = frame_list[i]; - frame_list[i] = pfn_to_mfn(pfn); + frame_list[i] = pfn_to_gfn(pfn); page = pfn_to_page(pfn); #ifdef CONFIG_XEN_HAVE_PVMMU diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index ed620e5857a1e..c49bb7a5be8f1 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c @@ -1688,7 +1688,7 @@ void __init xen_init_IRQ(void) struct physdev_pirq_eoi_gmfn eoi_gmfn; pirq_eoi_map = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); - eoi_gmfn.gmfn = virt_to_mfn(pirq_eoi_map); + eoi_gmfn.gmfn = virt_to_gfn(pirq_eoi_map); rc = HYPERVISOR_physdev_op(PHYSDEVOP_pirq_eoi_gmfn_v2, &eoi_gmfn); /* TODO: No PVH support for PIRQ EOI */ if (rc != 0) { diff --git a/drivers/xen/events/events_fifo.c b/drivers/xen/events/events_fifo.c index ed673e1acd615..1d4baf56c36bf 100644 --- a/drivers/xen/events/events_fifo.c +++ b/drivers/xen/events/events_fifo.c @@ -111,7 +111,7 @@ static int init_control_block(int cpu, for (i = 0; i < EVTCHN_FIFO_MAX_QUEUES; i++) q->head[i] = 0; - init_control.control_gfn = virt_to_mfn(control_block); + init_control.control_gfn = virt_to_gfn(control_block); init_control.offset = 0; init_control.vcpu = cpu; @@ -167,7 +167,7 @@ static int evtchn_fifo_setup(struct irq_info *info) /* Mask all events in this page before adding it. */ init_array_page(array_page); - expand_array.array_gfn = virt_to_mfn(array_page); + expand_array.array_gfn = virt_to_gfn(array_page); ret = HYPERVISOR_event_channel_op(EVTCHNOP_expand_array, &expand_array); if (ret < 0) diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index e53fe191738cf..14370df9ac1cc 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -142,7 +142,8 @@ static int add_grefs(struct ioctl_gntalloc_alloc_gref *op, /* Grant foreign access to the page. */ rc = gnttab_grant_foreign_access(op->domid, - pfn_to_mfn(page_to_pfn(gref->page)), readonly); + xen_page_to_gfn(gref->page), + readonly); if (rc < 0) goto undo; gref_ids[i] = gref->gref_id = rc; diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index d10effee9b9eb..e12bd3635f832 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c @@ -80,7 +80,7 @@ static int xen_suspend(void *data) * is resuming in a new domain. */ si->cancelled = HYPERVISOR_suspend(xen_pv_domain() - ? virt_to_mfn(xen_start_info) + ? virt_to_gfn(xen_start_info) : 0); xen_arch_post_suspend(si->cancelled); diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c index 239738f944bad..28c97ff606f41 100644 --- a/drivers/xen/tmem.c +++ b/drivers/xen/tmem.c @@ -131,7 +131,7 @@ static int xen_tmem_new_pool(struct tmem_pool_uuid uuid, static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid, u32 index, unsigned long pfn) { - unsigned long gmfn = xen_pv_domain() ? pfn_to_mfn(pfn) : pfn; + unsigned long gmfn = pfn_to_gfn(pfn); return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index, gmfn, 0, 0, 0); @@ -140,7 +140,7 @@ static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid, static int xen_tmem_get_page(u32 pool_id, struct tmem_oid oid, u32 index, unsigned long pfn) { - unsigned long gmfn = xen_pv_domain() ? pfn_to_mfn(pfn) : pfn; + unsigned long gmfn = pfn_to_gfn(pfn); return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index, gmfn, 0, 0, 0); diff --git a/drivers/xen/xenbus/xenbus_client.c b/drivers/xen/xenbus/xenbus_client.c index e30353575d5da..2ba09c1195c87 100644 --- a/drivers/xen/xenbus/xenbus_client.c +++ b/drivers/xen/xenbus/xenbus_client.c @@ -380,7 +380,7 @@ int xenbus_grant_ring(struct xenbus_device *dev, void *vaddr, for (i = 0; i < nr_pages; i++) { err = gnttab_grant_foreign_access(dev->otherend_id, - virt_to_mfn(vaddr), 0); + virt_to_gfn(vaddr), 0); if (err < 0) { xenbus_dev_fatal(dev, err, "granting access to ring page"); diff --git a/drivers/xen/xenbus/xenbus_dev_backend.c b/drivers/xen/xenbus/xenbus_dev_backend.c index b17707ee07d4f..ee6d9efd7b768 100644 --- a/drivers/xen/xenbus/xenbus_dev_backend.c +++ b/drivers/xen/xenbus/xenbus_dev_backend.c @@ -49,7 +49,7 @@ static long xenbus_alloc(domid_t domid) goto out_err; gnttab_grant_foreign_access_ref(GNTTAB_RESERVED_XENSTORE, domid, - virt_to_mfn(xen_store_interface), 0 /* writable */); + virt_to_gfn(xen_store_interface), 0 /* writable */); arg.dom = DOMID_SELF; arg.remote_dom = domid; diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index 4308fb3cf7c2f..b3870f4ca1d08 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -711,9 +711,7 @@ static int __init xenstored_local_init(void) if (!page) goto out_err; - xen_store_mfn = xen_start_info->store_mfn = - pfn_to_mfn(virt_to_phys((void *)page) >> - PAGE_SHIFT); + xen_store_mfn = xen_start_info->store_mfn = virt_to_gfn((void *)page); /* Next allocate a local port which xenstored can bind to */ alloc_unbound.dom = DOMID_SELF; @@ -787,12 +785,12 @@ static int __init xenbus_init(void) err = xenstored_local_init(); if (err) goto out_error; - xen_store_interface = mfn_to_virt(xen_store_mfn); + xen_store_interface = gfn_to_virt(xen_store_mfn); break; case XS_PV: xen_store_evtchn = xen_start_info->store_evtchn; xen_store_mfn = xen_start_info->store_mfn; - xen_store_interface = mfn_to_virt(xen_store_mfn); + xen_store_interface = gfn_to_virt(xen_store_mfn); break; case XS_HVM: err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); diff --git a/include/xen/page.h b/include/xen/page.h index a5983da2f5cd9..1daae485e3360 100644 --- a/include/xen/page.h +++ b/include/xen/page.h @@ -3,9 +3,9 @@ #include -static inline unsigned long page_to_mfn(struct page *page) +static inline unsigned long xen_page_to_gfn(struct page *page) { - return pfn_to_mfn(page_to_pfn(page)); + return pfn_to_gfn(page_to_pfn(page)); } struct xen_memory_region { -- GitLab From a76e3cc32d872acd5104278d21d2084da07c16a8 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:38 +0100 Subject: [PATCH 6640/7006] xen/tmem: Use xen_page_to_gfn rather than pfn_to_gfn All the caller of xen_tmem_{get,put}_page have a struct page * in hand and call pfn_to_gfn for the only benefits of these 2 functions. Rather than passing the pfn in parameter, pass directly the page and use directly xen_page_to_gfn. Signed-off-by: Julien Grall Reviewed-by: Stefano Stabellini Signed-off-by: David Vrabel --- drivers/xen/tmem.c | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c index 28c97ff606f41..945fc43272017 100644 --- a/drivers/xen/tmem.c +++ b/drivers/xen/tmem.c @@ -129,21 +129,17 @@ static int xen_tmem_new_pool(struct tmem_pool_uuid uuid, /* xen generic tmem ops */ static int xen_tmem_put_page(u32 pool_id, struct tmem_oid oid, - u32 index, unsigned long pfn) + u32 index, struct page *page) { - unsigned long gmfn = pfn_to_gfn(pfn); - return xen_tmem_op(TMEM_PUT_PAGE, pool_id, oid, index, - gmfn, 0, 0, 0); + xen_page_to_gfn(page), 0, 0, 0); } static int xen_tmem_get_page(u32 pool_id, struct tmem_oid oid, - u32 index, unsigned long pfn) + u32 index, struct page *page) { - unsigned long gmfn = pfn_to_gfn(pfn); - return xen_tmem_op(TMEM_GET_PAGE, pool_id, oid, index, - gmfn, 0, 0, 0); + xen_page_to_gfn(page), 0, 0, 0); } static int xen_tmem_flush_page(u32 pool_id, struct tmem_oid oid, u32 index) @@ -173,14 +169,13 @@ static void tmem_cleancache_put_page(int pool, struct cleancache_filekey key, { u32 ind = (u32) index; struct tmem_oid oid = *(struct tmem_oid *)&key; - unsigned long pfn = page_to_pfn(page); if (pool < 0) return; if (ind != index) return; mb(); /* ensure page is quiescent; tmem may address it with an alias */ - (void)xen_tmem_put_page((u32)pool, oid, ind, pfn); + (void)xen_tmem_put_page((u32)pool, oid, ind, page); } static int tmem_cleancache_get_page(int pool, struct cleancache_filekey key, @@ -188,7 +183,6 @@ static int tmem_cleancache_get_page(int pool, struct cleancache_filekey key, { u32 ind = (u32) index; struct tmem_oid oid = *(struct tmem_oid *)&key; - unsigned long pfn = page_to_pfn(page); int ret; /* translate return values to linux semantics */ @@ -196,7 +190,7 @@ static int tmem_cleancache_get_page(int pool, struct cleancache_filekey key, return -1; if (ind != index) return -1; - ret = xen_tmem_get_page((u32)pool, oid, ind, pfn); + ret = xen_tmem_get_page((u32)pool, oid, ind, page); if (ret == 1) return 0; else @@ -287,7 +281,6 @@ static int tmem_frontswap_store(unsigned type, pgoff_t offset, { u64 ind64 = (u64)offset; u32 ind = (u32)offset; - unsigned long pfn = page_to_pfn(page); int pool = tmem_frontswap_poolid; int ret; @@ -296,7 +289,7 @@ static int tmem_frontswap_store(unsigned type, pgoff_t offset, if (ind64 != ind) return -1; mb(); /* ensure page is quiescent; tmem may address it with an alias */ - ret = xen_tmem_put_page(pool, oswiz(type, ind), iswiz(ind), pfn); + ret = xen_tmem_put_page(pool, oswiz(type, ind), iswiz(ind), page); /* translate Xen tmem return values to linux semantics */ if (ret == 1) return 0; @@ -313,7 +306,6 @@ static int tmem_frontswap_load(unsigned type, pgoff_t offset, { u64 ind64 = (u64)offset; u32 ind = (u32)offset; - unsigned long pfn = page_to_pfn(page); int pool = tmem_frontswap_poolid; int ret; @@ -321,7 +313,7 @@ static int tmem_frontswap_load(unsigned type, pgoff_t offset, return -1; if (ind64 != ind) return -1; - ret = xen_tmem_get_page(pool, oswiz(type, ind), iswiz(ind), pfn); + ret = xen_tmem_get_page(pool, oswiz(type, ind), iswiz(ind), page); /* translate Xen tmem return values to linux semantics */ if (ret == 1) return 0; -- GitLab From 0467533a7a5da08a881a31120d95cd159e54640b Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:39 +0100 Subject: [PATCH 6641/7006] video/xen-fbfront: Further s/MFN/GFN clean-up The PV driver xen-fbfront is only dealing with GFN and not MFN. Rename all the occurence of MFN to GFN. Also take the opportunity to replace to usage of pfn_to_gfn by xen_page_to_gfn. Signed-off-by: Julien Grall Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- drivers/video/fbdev/xen-fbfront.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/video/fbdev/xen-fbfront.c b/drivers/video/fbdev/xen-fbfront.c index 25e3cce0c35fc..0567d517eed34 100644 --- a/drivers/video/fbdev/xen-fbfront.c +++ b/drivers/video/fbdev/xen-fbfront.c @@ -46,7 +46,7 @@ struct xenfb_info { int nr_pages; int irq; struct xenfb_page *page; - unsigned long *mfns; + unsigned long *gfns; int update_wanted; /* XENFB_TYPE_UPDATE wanted */ int feature_resize; /* XENFB_TYPE_RESIZE ok */ struct xenfb_resize resize; /* protected by resize_lock */ @@ -402,8 +402,8 @@ static int xenfb_probe(struct xenbus_device *dev, info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; - info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); - if (!info->mfns) + info->gfns = vmalloc(sizeof(unsigned long) * info->nr_pages); + if (!info->gfns) goto error_nomem; /* set up shared page */ @@ -530,29 +530,29 @@ static int xenfb_remove(struct xenbus_device *dev) framebuffer_release(info->fb_info); } free_page((unsigned long)info->page); - vfree(info->mfns); + vfree(info->gfns); vfree(info->fb); kfree(info); return 0; } -static unsigned long vmalloc_to_mfn(void *address) +static unsigned long vmalloc_to_gfn(void *address) { - return pfn_to_gfn(vmalloc_to_pfn(address)); + return xen_page_to_gfn(vmalloc_to_page(address)); } static void xenfb_init_shared_page(struct xenfb_info *info, struct fb_info *fb_info) { int i; - int epd = PAGE_SIZE / sizeof(info->mfns[0]); + int epd = PAGE_SIZE / sizeof(info->gfns[0]); for (i = 0; i < info->nr_pages; i++) - info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); + info->gfns[i] = vmalloc_to_gfn(info->fb + i * PAGE_SIZE); for (i = 0; i * epd < info->nr_pages; i++) - info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); + info->page->pd[i] = vmalloc_to_gfn(&info->gfns[i * epd]); info->page->width = fb_info->var.xres; info->page->height = fb_info->var.yres; -- GitLab From 859e3267c515d0cc7cc11528e80a2b7f3edc3bd9 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:40 +0100 Subject: [PATCH 6642/7006] hvc/xen: Further s/MFN/GFN clean-up HVM_PARAM_CONSOLE_PFN is used to retrieved the console PFN for HVM guest. It returns a PFN (aka GFN) and not a MFN. Furthermore, use directly virt_to_gfn for both PV and HVM domain rather than doing a special case for each of the them. Signed-off-by: Julien Grall Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- drivers/tty/hvc/hvc_xen.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/drivers/tty/hvc/hvc_xen.c b/drivers/tty/hvc/hvc_xen.c index efe5124a368de..10beb1589d834 100644 --- a/drivers/tty/hvc/hvc_xen.c +++ b/drivers/tty/hvc/hvc_xen.c @@ -200,7 +200,7 @@ static int xen_hvm_console_init(void) { int r; uint64_t v = 0; - unsigned long mfn; + unsigned long gfn; struct xencons_info *info; if (!xen_hvm_domain()) @@ -217,7 +217,7 @@ static int xen_hvm_console_init(void) } /* * If the toolstack (or the hypervisor) hasn't set these values, the - * default value is 0. Even though mfn = 0 and evtchn = 0 are + * default value is 0. Even though gfn = 0 and evtchn = 0 are * theoretically correct values, in practice they never are and they * mean that a legacy toolstack hasn't initialized the pv console correctly. */ @@ -229,8 +229,8 @@ static int xen_hvm_console_init(void) r = hvm_get_parameter(HVM_PARAM_CONSOLE_PFN, &v); if (r < 0 || v == 0) goto err; - mfn = v; - info->intf = xen_remap(mfn << PAGE_SHIFT, PAGE_SIZE); + gfn = v; + info->intf = xen_remap(gfn << PAGE_SHIFT, PAGE_SIZE); if (info->intf == NULL) goto err; info->vtermno = HVC_COOKIE; @@ -375,7 +375,6 @@ static int xencons_connect_backend(struct xenbus_device *dev, int ret, evtchn, devid, ref, irq; struct xenbus_transaction xbt; grant_ref_t gref_head; - unsigned long mfn; ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) @@ -390,10 +389,6 @@ static int xencons_connect_backend(struct xenbus_device *dev, irq, &domU_hvc_ops, 256); if (IS_ERR(info->hvc)) return PTR_ERR(info->hvc); - if (xen_pv_domain()) - mfn = virt_to_gfn(info->intf); - else - mfn = __pa(info->intf) >> PAGE_SHIFT; ret = gnttab_alloc_grant_references(1, &gref_head); if (ret < 0) return ret; @@ -402,7 +397,7 @@ static int xencons_connect_backend(struct xenbus_device *dev, if (ref < 0) return ref; gnttab_grant_foreign_access_ref(ref, info->xbdev->otherend_id, - mfn, 0); + virt_to_gfn(info->intf), 0); again: ret = xenbus_transaction_start(&xbt); -- GitLab From a13d7201d7deedcbb6ac6efa94a1a7d34d3d79ec Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:41 +0100 Subject: [PATCH 6643/7006] xen/privcmd: Further s/MFN/GFN/ clean-up The privcmd code is mixing the usage of GFN and MFN within the same functions which make the code difficult to understand when you only work with auto-translated guests. The privcmd driver is only dealing with GFN so replace all the mention of MFN into GFN. The ioctl structure used to map foreign change has been left unchanged given that the userspace is using it. Nonetheless, add a comment to explain the expected value within the "mfn" field. Signed-off-by: Julien Grall Reviewed-by: David Vrabel Signed-off-by: David Vrabel --- arch/arm/xen/enlighten.c | 18 ++++++++-------- arch/x86/xen/mmu.c | 32 +++++++++++++-------------- drivers/xen/privcmd.c | 44 +++++++++++++++++++------------------- drivers/xen/xlate_mmu.c | 18 ++++++++-------- include/uapi/xen/privcmd.h | 4 ++++ include/xen/xen-ops.h | 10 ++++----- 6 files changed, 65 insertions(+), 61 deletions(-) diff --git a/arch/arm/xen/enlighten.c b/arch/arm/xen/enlighten.c index c50c8d33f8740..eeeab074e1542 100644 --- a/arch/arm/xen/enlighten.c +++ b/arch/arm/xen/enlighten.c @@ -49,35 +49,35 @@ static __read_mostly unsigned int xen_events_irq; static __initdata struct device_node *xen_node; -int xen_remap_domain_mfn_array(struct vm_area_struct *vma, +int xen_remap_domain_gfn_array(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t *mfn, int nr, + xen_pfn_t *gfn, int nr, int *err_ptr, pgprot_t prot, unsigned domid, struct page **pages) { - return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr, + return xen_xlate_remap_gfn_array(vma, addr, gfn, nr, err_ptr, prot, domid, pages); } -EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array); +EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_array); /* Not used by XENFEAT_auto_translated guests. */ -int xen_remap_domain_mfn_range(struct vm_area_struct *vma, +int xen_remap_domain_gfn_range(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t mfn, int nr, + xen_pfn_t gfn, int nr, pgprot_t prot, unsigned domid, struct page **pages) { return -ENOSYS; } -EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); +EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_range); -int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, +int xen_unmap_domain_gfn_range(struct vm_area_struct *vma, int nr, struct page **pages) { return xen_xlate_unmap_gfn_range(vma, nr, pages); } -EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); +EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); static void xen_percpu_init(void) { diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c index 2c50b445884e8..9c479fe404591 100644 --- a/arch/x86/xen/mmu.c +++ b/arch/x86/xen/mmu.c @@ -2812,9 +2812,9 @@ static int remap_area_mfn_pte_fn(pte_t *ptep, pgtable_t token, return 0; } -static int do_remap_mfn(struct vm_area_struct *vma, +static int do_remap_gfn(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t *mfn, int nr, + xen_pfn_t *gfn, int nr, int *err_ptr, pgprot_t prot, unsigned domid, struct page **pages) @@ -2830,14 +2830,14 @@ static int do_remap_mfn(struct vm_area_struct *vma, if (xen_feature(XENFEAT_auto_translated_physmap)) { #ifdef CONFIG_XEN_PVH /* We need to update the local page tables and the xen HAP */ - return xen_xlate_remap_gfn_array(vma, addr, mfn, nr, err_ptr, + return xen_xlate_remap_gfn_array(vma, addr, gfn, nr, err_ptr, prot, domid, pages); #else return -EINVAL; #endif } - rmd.mfn = mfn; + rmd.mfn = gfn; rmd.prot = prot; /* We use the err_ptr to indicate if there we are doing a contigious * mapping or a discontigious mapping. */ @@ -2865,8 +2865,8 @@ static int do_remap_mfn(struct vm_area_struct *vma, batch_left, &done, domid); /* - * @err_ptr may be the same buffer as @mfn, so - * only clear it after each chunk of @mfn is + * @err_ptr may be the same buffer as @gfn, so + * only clear it after each chunk of @gfn is * used. */ if (err_ptr) { @@ -2896,19 +2896,19 @@ out: return err < 0 ? err : mapped; } -int xen_remap_domain_mfn_range(struct vm_area_struct *vma, +int xen_remap_domain_gfn_range(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t mfn, int nr, + xen_pfn_t gfn, int nr, pgprot_t prot, unsigned domid, struct page **pages) { - return do_remap_mfn(vma, addr, &mfn, nr, NULL, prot, domid, pages); + return do_remap_gfn(vma, addr, &gfn, nr, NULL, prot, domid, pages); } -EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_range); +EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_range); -int xen_remap_domain_mfn_array(struct vm_area_struct *vma, +int xen_remap_domain_gfn_array(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t *mfn, int nr, + xen_pfn_t *gfn, int nr, int *err_ptr, pgprot_t prot, unsigned domid, struct page **pages) { @@ -2917,13 +2917,13 @@ int xen_remap_domain_mfn_array(struct vm_area_struct *vma, * cause of "wrong memory was mapped in". */ BUG_ON(err_ptr == NULL); - return do_remap_mfn(vma, addr, mfn, nr, err_ptr, prot, domid, pages); + return do_remap_gfn(vma, addr, gfn, nr, err_ptr, prot, domid, pages); } -EXPORT_SYMBOL_GPL(xen_remap_domain_mfn_array); +EXPORT_SYMBOL_GPL(xen_remap_domain_gfn_array); /* Returns: 0 success */ -int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, +int xen_unmap_domain_gfn_range(struct vm_area_struct *vma, int numpgs, struct page **pages) { if (!pages || !xen_feature(XENFEAT_auto_translated_physmap)) @@ -2935,4 +2935,4 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, return -EINVAL; #endif } -EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range); +EXPORT_SYMBOL_GPL(xen_unmap_domain_gfn_range); diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 5a296161d843b..c6deb87c5c697 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -193,16 +193,16 @@ static int traverse_pages_block(unsigned nelem, size_t size, return ret; } -struct mmap_mfn_state { +struct mmap_gfn_state { unsigned long va; struct vm_area_struct *vma; domid_t domain; }; -static int mmap_mfn_range(void *data, void *state) +static int mmap_gfn_range(void *data, void *state) { struct privcmd_mmap_entry *msg = data; - struct mmap_mfn_state *st = state; + struct mmap_gfn_state *st = state; struct vm_area_struct *vma = st->vma; int rc; @@ -216,7 +216,7 @@ static int mmap_mfn_range(void *data, void *state) ((msg->va+(msg->npages< vma->vm_end)) return -EINVAL; - rc = xen_remap_domain_mfn_range(vma, + rc = xen_remap_domain_gfn_range(vma, msg->va & PAGE_MASK, msg->mfn, msg->npages, vma->vm_page_prot, @@ -236,7 +236,7 @@ static long privcmd_ioctl_mmap(void __user *udata) struct vm_area_struct *vma; int rc; LIST_HEAD(pagelist); - struct mmap_mfn_state state; + struct mmap_gfn_state state; /* We only support privcmd_ioctl_mmap_batch for auto translated. */ if (xen_feature(XENFEAT_auto_translated_physmap)) @@ -273,7 +273,7 @@ static long privcmd_ioctl_mmap(void __user *udata) rc = traverse_pages(mmapcmd.num, sizeof(struct privcmd_mmap_entry), &pagelist, - mmap_mfn_range, &state); + mmap_gfn_range, &state); out_up: @@ -299,18 +299,18 @@ struct mmap_batch_state { int global_error; int version; - /* User-space mfn array to store errors in the second pass for V1. */ - xen_pfn_t __user *user_mfn; + /* User-space gfn array to store errors in the second pass for V1. */ + xen_pfn_t __user *user_gfn; /* User-space int array to store errors in the second pass for V2. */ int __user *user_err; }; -/* auto translated dom0 note: if domU being created is PV, then mfn is - * mfn(addr on bus). If it's auto xlated, then mfn is pfn (input to HAP). +/* auto translated dom0 note: if domU being created is PV, then gfn is + * mfn(addr on bus). If it's auto xlated, then gfn is pfn (input to HAP). */ static int mmap_batch_fn(void *data, int nr, void *state) { - xen_pfn_t *mfnp = data; + xen_pfn_t *gfnp = data; struct mmap_batch_state *st = state; struct vm_area_struct *vma = st->vma; struct page **pages = vma->vm_private_data; @@ -321,8 +321,8 @@ static int mmap_batch_fn(void *data, int nr, void *state) cur_pages = &pages[st->index]; BUG_ON(nr < 0); - ret = xen_remap_domain_mfn_array(st->vma, st->va & PAGE_MASK, mfnp, nr, - (int *)mfnp, st->vma->vm_page_prot, + ret = xen_remap_domain_gfn_array(st->vma, st->va & PAGE_MASK, gfnp, nr, + (int *)gfnp, st->vma->vm_page_prot, st->domain, cur_pages); /* Adjust the global_error? */ @@ -347,22 +347,22 @@ static int mmap_return_error(int err, struct mmap_batch_state *st) if (st->version == 1) { if (err) { - xen_pfn_t mfn; + xen_pfn_t gfn; - ret = get_user(mfn, st->user_mfn); + ret = get_user(gfn, st->user_gfn); if (ret < 0) return ret; /* * V1 encodes the error codes in the 32bit top - * nibble of the mfn (with its known + * nibble of the gfn (with its known * limitations vis-a-vis 64 bit callers). */ - mfn |= (err == -ENOENT) ? + gfn |= (err == -ENOENT) ? PRIVCMD_MMAPBATCH_PAGED_ERROR : PRIVCMD_MMAPBATCH_MFN_ERROR; - return __put_user(mfn, st->user_mfn++); + return __put_user(gfn, st->user_gfn++); } else - st->user_mfn++; + st->user_gfn++; } else { /* st->version == 2 */ if (err) return __put_user(err, st->user_err++); @@ -388,7 +388,7 @@ static int mmap_return_errors(void *data, int nr, void *state) return 0; } -/* Allocate pfns that are then mapped with gmfns from foreign domid. Update +/* Allocate pfns that are then mapped with gfns from foreign domid. Update * the vma with the page info to use later. * Returns: 0 if success, otherwise -errno */ @@ -526,7 +526,7 @@ static long privcmd_ioctl_mmap_batch(void __user *udata, int version) if (state.global_error) { /* Write back errors in second pass. */ - state.user_mfn = (xen_pfn_t *)m.arr; + state.user_gfn = (xen_pfn_t *)m.arr; state.user_err = m.err; ret = traverse_pages_block(m.num, sizeof(xen_pfn_t), &pagelist, mmap_return_errors, &state); @@ -587,7 +587,7 @@ static void privcmd_close(struct vm_area_struct *vma) if (!xen_feature(XENFEAT_auto_translated_physmap) || !numpgs || !pages) return; - rc = xen_unmap_domain_mfn_range(vma, numpgs, pages); + rc = xen_unmap_domain_gfn_range(vma, numpgs, pages); if (rc == 0) free_xenballooned_pages(numpgs, pages); else diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c index 58a5389aec891..cff23872c5a96 100644 --- a/drivers/xen/xlate_mmu.c +++ b/drivers/xen/xlate_mmu.c @@ -38,8 +38,8 @@ #include #include -/* map fgmfn of domid to lpfn in the current domain */ -static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, +/* map fgfn of domid to lpfn in the current domain */ +static int map_foreign_page(unsigned long lpfn, unsigned long fgfn, unsigned int domid) { int rc; @@ -49,7 +49,7 @@ static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, .size = 1, .space = XENMAPSPACE_gmfn_foreign, }; - xen_ulong_t idx = fgmfn; + xen_ulong_t idx = fgfn; xen_pfn_t gpfn = lpfn; int err = 0; @@ -62,13 +62,13 @@ static int map_foreign_page(unsigned long lpfn, unsigned long fgmfn, } struct remap_data { - xen_pfn_t *fgmfn; /* foreign domain's gmfn */ + xen_pfn_t *fgfn; /* foreign domain's gfn */ pgprot_t prot; domid_t domid; struct vm_area_struct *vma; int index; struct page **pages; - struct xen_remap_mfn_info *info; + struct xen_remap_gfn_info *info; int *err_ptr; int mapped; }; @@ -82,20 +82,20 @@ static int remap_pte_fn(pte_t *ptep, pgtable_t token, unsigned long addr, pte_t pte = pte_mkspecial(pfn_pte(pfn, info->prot)); int rc; - rc = map_foreign_page(pfn, *info->fgmfn, info->domid); + rc = map_foreign_page(pfn, *info->fgfn, info->domid); *info->err_ptr++ = rc; if (!rc) { set_pte_at(info->vma->vm_mm, addr, ptep, pte); info->mapped++; } - info->fgmfn++; + info->fgfn++; return 0; } int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, unsigned long addr, - xen_pfn_t *mfn, int nr, + xen_pfn_t *gfn, int nr, int *err_ptr, pgprot_t prot, unsigned domid, struct page **pages) @@ -108,7 +108,7 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, x86 PVOPS */ BUG_ON(!((vma->vm_flags & (VM_PFNMAP | VM_IO)) == (VM_PFNMAP | VM_IO))); - data.fgmfn = mfn; + data.fgfn = gfn; data.prot = prot; data.domid = domid; data.vma = vma; diff --git a/include/uapi/xen/privcmd.h b/include/uapi/xen/privcmd.h index a85316811d79a..7ddeeda938097 100644 --- a/include/uapi/xen/privcmd.h +++ b/include/uapi/xen/privcmd.h @@ -44,6 +44,10 @@ struct privcmd_hypercall { struct privcmd_mmap_entry { __u64 va; + /* + * This should be a GFN. It's not possible to change the name because + * it's exposed to the user-space. + */ __u64 mfn; __u64 npages; }; diff --git a/include/xen/xen-ops.h b/include/xen/xen-ops.h index 0ce4f32017ea9..e4e214a5abd53 100644 --- a/include/xen/xen-ops.h +++ b/include/xen/xen-ops.h @@ -30,7 +30,7 @@ void xen_destroy_contiguous_region(phys_addr_t pstart, unsigned int order); struct vm_area_struct; /* - * xen_remap_domain_mfn_array() - map an array of foreign frames + * xen_remap_domain_gfn_array() - map an array of foreign frames * @vma: VMA to map the pages into * @addr: Address at which to map the pages * @gfn: Array of GFNs to map @@ -46,14 +46,14 @@ struct vm_area_struct; * Returns the number of successfully mapped frames, or a -ve error * code. */ -int xen_remap_domain_mfn_array(struct vm_area_struct *vma, +int xen_remap_domain_gfn_array(struct vm_area_struct *vma, unsigned long addr, xen_pfn_t *gfn, int nr, int *err_ptr, pgprot_t prot, unsigned domid, struct page **pages); -/* xen_remap_domain_mfn_range() - map a range of foreign frames +/* xen_remap_domain_gfn_range() - map a range of foreign frames * @vma: VMA to map the pages into * @addr: Address at which to map the pages * @gfn: First GFN to map. @@ -65,12 +65,12 @@ int xen_remap_domain_mfn_array(struct vm_area_struct *vma, * Returns the number of successfully mapped frames, or a -ve error * code. */ -int xen_remap_domain_mfn_range(struct vm_area_struct *vma, +int xen_remap_domain_gfn_range(struct vm_area_struct *vma, unsigned long addr, xen_pfn_t gfn, int nr, pgprot_t prot, unsigned domid, struct page **pages); -int xen_unmap_domain_mfn_range(struct vm_area_struct *vma, +int xen_unmap_domain_gfn_range(struct vm_area_struct *vma, int numpgs, struct page **pages); int xen_xlate_remap_gfn_array(struct vm_area_struct *vma, unsigned long addr, -- GitLab From 5f51042f876b88a3b81a135cc4ca0adb3d246112 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Fri, 7 Aug 2015 17:34:42 +0100 Subject: [PATCH 6644/7006] xen/xenbus: Rename the variable xen_store_mfn to xen_store_gfn The variable xen_store_mfn is effectively storing a GFN and not an MFN. Signed-off-by: Julien Grall Signed-off-by: David Vrabel --- drivers/xen/xenbus/xenbus_probe.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/xen/xenbus/xenbus_probe.c b/drivers/xen/xenbus/xenbus_probe.c index b3870f4ca1d08..3cbe0556de266 100644 --- a/drivers/xen/xenbus/xenbus_probe.c +++ b/drivers/xen/xenbus/xenbus_probe.c @@ -75,7 +75,7 @@ EXPORT_SYMBOL_GPL(xen_store_interface); enum xenstore_init xen_store_domain_type; EXPORT_SYMBOL_GPL(xen_store_domain_type); -static unsigned long xen_store_mfn; +static unsigned long xen_store_gfn; static BLOCKING_NOTIFIER_HEAD(xenstore_chain); @@ -711,7 +711,7 @@ static int __init xenstored_local_init(void) if (!page) goto out_err; - xen_store_mfn = xen_start_info->store_mfn = virt_to_gfn((void *)page); + xen_store_gfn = xen_start_info->store_mfn = virt_to_gfn((void *)page); /* Next allocate a local port which xenstored can bind to */ alloc_unbound.dom = DOMID_SELF; @@ -785,12 +785,12 @@ static int __init xenbus_init(void) err = xenstored_local_init(); if (err) goto out_error; - xen_store_interface = gfn_to_virt(xen_store_mfn); + xen_store_interface = gfn_to_virt(xen_store_gfn); break; case XS_PV: xen_store_evtchn = xen_start_info->store_evtchn; - xen_store_mfn = xen_start_info->store_mfn; - xen_store_interface = gfn_to_virt(xen_store_mfn); + xen_store_gfn = xen_start_info->store_mfn; + xen_store_interface = gfn_to_virt(xen_store_gfn); break; case XS_HVM: err = hvm_get_parameter(HVM_PARAM_STORE_EVTCHN, &v); @@ -800,9 +800,9 @@ static int __init xenbus_init(void) err = hvm_get_parameter(HVM_PARAM_STORE_PFN, &v); if (err) goto out_error; - xen_store_mfn = (unsigned long)v; + xen_store_gfn = (unsigned long)v; xen_store_interface = - xen_remap(xen_store_mfn << PAGE_SHIFT, PAGE_SIZE); + xen_remap(xen_store_gfn << PAGE_SHIFT, PAGE_SIZE); break; default: pr_warn("Xenstore state unknown\n"); -- GitLab From 49df2e3e902e1c3caf998f97a92512424936199d Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Wed, 29 Jul 2015 18:53:17 +0200 Subject: [PATCH 6645/7006] userfaultfd: selftest: update userfaultfd x86 32bit syscall number It changed as result of other syscalls, and while the system call list itself was correctly updated, the selftest program was not. Signed-off-by: Andrea Arcangeli Cc: Andrew Morton Cc: Stephen Rothwell Cc: Thomas Gleixner Cc: Andy Lutomirski Signed-off-by: Linus Torvalds --- tools/testing/selftests/vm/userfaultfd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index 0c0b839533526..76071b14cb938 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -69,7 +69,7 @@ #ifdef __x86_64__ #define __NR_userfaultfd 323 #elif defined(__i386__) -#define __NR_userfaultfd 359 +#define __NR_userfaultfd 374 #elif defined(__powewrpc__) #define __NR_userfaultfd 364 #else -- GitLab From 48fec5d0a504dfbb302cb1dd24ebb0b82a46cce9 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 1 Jul 2015 16:27:46 +0800 Subject: [PATCH 6646/7006] ceph: EIO all operations after forced umount This patch makes try_get_cap_refs() and __do_request() check if the file system was forced umount, and return -EIO if it was. This patch also adds a helper function to drops dirty caps and wakes up blocking operation. Signed-off-by: Yan, Zheng --- fs/ceph/addr.c | 2 +- fs/ceph/caps.c | 8 +++++++ fs/ceph/mds_client.c | 54 +++++++++++++++++++++++++++++++++++--------- fs/ceph/mds_client.h | 1 + fs/ceph/super.c | 1 + 5 files changed, 54 insertions(+), 12 deletions(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 890c50971a690..1594f2c590bd2 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -717,7 +717,7 @@ static int ceph_writepages_start(struct address_space *mapping, wbc->sync_mode == WB_SYNC_NONE ? "NONE" : (wbc->sync_mode == WB_SYNC_ALL ? "ALL" : "HOLD")); - if (fsc->mount_state == CEPH_MOUNT_SHUTDOWN) { + if (ACCESS_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { pr_warn("writepage_start %p on forced umount\n", inode); return -EIO; /* we're in a forced umount, don't write! */ } diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index ddd5e94712904..27b566874bc1d 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c @@ -2413,6 +2413,14 @@ again: goto out_unlock; } + if (!__ceph_is_any_caps(ci) && + ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + dout("get_cap_refs %p forced umount\n", inode); + *err = -EIO; + ret = 1; + goto out_unlock; + } + dout("get_cap_refs %p have %s needed %s\n", inode, ceph_cap_string(have), ceph_cap_string(need)); } diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index 6aa07af67603a..ddc471c322300 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2107,7 +2107,6 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, msg = create_request_message(mdsc, req, mds, drop_cap_releases); if (IS_ERR(msg)) { req->r_err = PTR_ERR(msg); - complete_request(mdsc, req); return PTR_ERR(msg); } req->r_request = msg; @@ -2135,7 +2134,7 @@ static int __do_request(struct ceph_mds_client *mdsc, { struct ceph_mds_session *session = NULL; int mds = -1; - int err = -EAGAIN; + int err = 0; if (req->r_err || req->r_got_result) { if (req->r_aborted) @@ -2149,6 +2148,11 @@ static int __do_request(struct ceph_mds_client *mdsc, err = -EIO; goto finish; } + if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { + dout("do_request forced umount\n"); + err = -EIO; + goto finish; + } put_request_session(req); @@ -2196,13 +2200,15 @@ static int __do_request(struct ceph_mds_client *mdsc, out_session: ceph_put_mds_session(session); +finish: + if (err) { + dout("__do_request early error %d\n", err); + req->r_err = err; + complete_request(mdsc, req); + __unregister_request(mdsc, req); + } out: return err; - -finish: - req->r_err = err; - complete_request(mdsc, req); - goto out; } /* @@ -2289,8 +2295,6 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc, if (req->r_err) { err = req->r_err; - __unregister_request(mdsc, req); - dout("do_request early error %d\n", err); goto out; } @@ -3555,7 +3559,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) { u64 want_tid, want_flush, want_snap; - if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN) + if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) return; dout("sync\n"); @@ -3584,7 +3588,7 @@ void ceph_mdsc_sync(struct ceph_mds_client *mdsc) */ static bool done_closing_sessions(struct ceph_mds_client *mdsc) { - if (mdsc->fsc->mount_state == CEPH_MOUNT_SHUTDOWN) + if (ACCESS_ONCE(mdsc->fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) return true; return atomic_read(&mdsc->num_sessions) == 0; } @@ -3643,6 +3647,34 @@ void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc) dout("stopped\n"); } +void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc) +{ + struct ceph_mds_session *session; + int mds; + + dout("force umount\n"); + + mutex_lock(&mdsc->mutex); + for (mds = 0; mds < mdsc->max_sessions; mds++) { + session = __ceph_lookup_mds_session(mdsc, mds); + if (!session) + continue; + mutex_unlock(&mdsc->mutex); + mutex_lock(&session->s_mutex); + __close_session(mdsc, session); + if (session->s_state == CEPH_MDS_SESSION_CLOSING) { + cleanup_session_requests(mdsc, session); + remove_session_caps(session); + } + mutex_unlock(&session->s_mutex); + ceph_put_mds_session(session); + mutex_lock(&mdsc->mutex); + kick_requests(mdsc, mds); + } + __wake_requests(mdsc, &mdsc->waiting_for_map); + mutex_unlock(&mdsc->mutex); +} + static void ceph_mdsc_stop(struct ceph_mds_client *mdsc) { dout("stop\n"); diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 762757e6cebf9..f575eafe2261c 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h @@ -366,6 +366,7 @@ extern int ceph_send_msg_mds(struct ceph_mds_client *mdsc, extern int ceph_mdsc_init(struct ceph_fs_client *fsc); extern void ceph_mdsc_close_sessions(struct ceph_mds_client *mdsc); +extern void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc); extern void ceph_mdsc_destroy(struct ceph_fs_client *fsc); extern void ceph_mdsc_sync(struct ceph_mds_client *mdsc); diff --git a/fs/ceph/super.c b/fs/ceph/super.c index d1c833c321b92..69e6e19bcfc17 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c @@ -708,6 +708,7 @@ static void ceph_umount_begin(struct super_block *sb) if (!fsc) return; fsc->mount_state = CEPH_MOUNT_SHUTDOWN; + ceph_mdsc_force_umount(fsc->mdsc); return; } -- GitLab From a341d4df87487ae68189e0be869c39a2b0cb9aaa Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Wed, 1 Jul 2015 17:03:23 +0800 Subject: [PATCH 6647/7006] ceph: invalidate dirty pages after forced umount After forced umount, ceph_writepages_start() skips flushing dirty pages. To make sure inode's reference count get dropped to zero, we need to invalidate dirty pages. Signed-off-by: Yan, Zheng --- fs/ceph/addr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 1594f2c590bd2..98933350331c4 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -719,6 +719,8 @@ static int ceph_writepages_start(struct address_space *mapping, if (ACCESS_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) { pr_warn("writepage_start %p on forced umount\n", inode); + truncate_pagecache(inode, 0); + mapping_set_error(mapping, -EIO); return -EIO; /* we're in a forced umount, don't write! */ } if (fsc->mount_options->wsize && fsc->mount_options->wsize < wsize) -- GitLab From b79b23682a1649f30960fb5bd920ba46c89a1b14 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Sun, 5 Jul 2015 06:34:05 +0000 Subject: [PATCH 6648/7006] libceph: remove the unused macro AES_KEY_SIZE This removes the no longer used macro AES_KEY_SIZE as no functions use this macro anymore and thus this macro can be removed due it no longer being required. Signed-off-by: Nicholas Krause Signed-off-by: Ilya Dryomov --- net/ceph/crypto.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/net/ceph/crypto.c b/net/ceph/crypto.c index 790fe89d90c0a..4440edcce0d6c 100644 --- a/net/ceph/crypto.c +++ b/net/ceph/crypto.c @@ -79,10 +79,6 @@ int ceph_crypto_key_unarmor(struct ceph_crypto_key *key, const char *inkey) return 0; } - - -#define AES_KEY_SIZE 16 - static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void) { return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); -- GitLab From d920ff6fc7c1ec3d7bd80432bff5575c0ebe426c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Canet?= Date: Thu, 25 Jun 2015 21:02:57 +0200 Subject: [PATCH 6649/7006] libceph: Avoid holding the zero page on ceph_msgr_slab_init errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ceph_msgr_slab_init may fail due to a temporary ENOMEM. Delay a bit the initialization of zero_page in ceph_msgr_init and reorder its cleanup in _ceph_msgr_exit so it's done in reverse order of setup. BUG_ON() will not suffer to be postponed in case it is triggered. Signed-off-by: Benoît Canet Reviewed-by: Alex Elder Signed-off-by: Ilya Dryomov --- net/ceph/messenger.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index e3be1d22a2477..0f9ea60a89712 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -276,22 +276,22 @@ static void _ceph_msgr_exit(void) ceph_msgr_wq = NULL; } - ceph_msgr_slab_exit(); - BUG_ON(zero_page == NULL); page_cache_release(zero_page); zero_page = NULL; + + ceph_msgr_slab_exit(); } int ceph_msgr_init(void) { + if (ceph_msgr_slab_init()) + return -ENOMEM; + BUG_ON(zero_page != NULL); zero_page = ZERO_PAGE(0); page_cache_get(zero_page); - if (ceph_msgr_slab_init()) - return -ENOMEM; - /* * The number of active work items is limited by the number of * connections, so leave @max_active at default. -- GitLab From 6893162215d7bf08a4273247ec1fc7dedee5135c Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Fri, 3 Jul 2015 15:44:41 +0300 Subject: [PATCH 6650/7006] libceph: rename con_work() to ceph_con_workfn() Even though it's static, con_work(), being a work func, shows up in various stacktraces a lot. Prefix it with ceph_. Signed-off-by: Ilya Dryomov --- net/ceph/messenger.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 0f9ea60a89712..101ab6285fbae 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -176,7 +176,7 @@ static struct lock_class_key socket_class; static void queue_con(struct ceph_connection *con); static void cancel_con(struct ceph_connection *con); -static void con_work(struct work_struct *); +static void ceph_con_workfn(struct work_struct *); static void con_fault(struct ceph_connection *con); /* @@ -749,7 +749,7 @@ void ceph_con_init(struct ceph_connection *con, void *private, mutex_init(&con->mutex); INIT_LIST_HEAD(&con->out_queue); INIT_LIST_HEAD(&con->out_sent); - INIT_DELAYED_WORK(&con->work, con_work); + INIT_DELAYED_WORK(&con->work, ceph_con_workfn); con->state = CON_STATE_CLOSED; } @@ -2799,7 +2799,7 @@ static void con_fault_finish(struct ceph_connection *con) /* * Do some work on a connection. Drop a connection ref when we're done. */ -static void con_work(struct work_struct *work) +static void ceph_con_workfn(struct work_struct *work) { struct ceph_connection *con = container_of(work, struct ceph_connection, work.work); -- GitLab From 23078637e05460428f803be7d0f46908df8a970a Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 20 Jul 2015 10:14:06 +0800 Subject: [PATCH 6651/7006] ceph: fix queuing inode to mdsdir's snaprealm During MDS failovers, MClientSnap message may cause kclient to move some inodes from root directory's snaprealm to mdsdir's snaprealm and queue snapshots for these inodes. For a FS has never created any snapshot, both root directory's snaprealm and mdsdir's snaprealm share the same snapshot contexts (both are ceph_empty_snapc). This confuses ceph_put_wrbuffer_cap_refs(), make it unable to distinguish snapshot buffers from head buffers. The fix is do not use ceph_empty_snapc as snaprealm's cached context. Signed-off-by: Yan, Zheng --- fs/ceph/snap.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/fs/ceph/snap.c b/fs/ceph/snap.c index 233d906aec02b..4aa7122a8d38c 100644 --- a/fs/ceph/snap.c +++ b/fs/ceph/snap.c @@ -338,12 +338,6 @@ static int build_snap_context(struct ceph_snap_realm *realm) return 0; } - if (num == 0 && realm->seq == ceph_empty_snapc->seq) { - ceph_get_snap_context(ceph_empty_snapc); - snapc = ceph_empty_snapc; - goto done; - } - /* alloc new snap context */ err = -ENOMEM; if (num > (SIZE_MAX - sizeof(*snapc)) / sizeof(u64)) @@ -381,7 +375,6 @@ static int build_snap_context(struct ceph_snap_realm *realm) realm->ino, realm, snapc, snapc->seq, (unsigned int) snapc->num_snaps); -done: ceph_put_snap_context(realm->cached_context); realm->cached_context = snapc; return 0; -- GitLab From 1550d34e5626a20a2e12c73bdc1e6e217a0ba897 Mon Sep 17 00:00:00 2001 From: Brad Hubbard Date: Tue, 18 Aug 2015 10:18:53 +0800 Subject: [PATCH 6652/7006] ceph: remove redundant test of head->safe and silence static analysis warnings Signed-off-by: Brad Hubbard Signed-off-by: Yan, Zheng --- fs/ceph/mds_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index ddc471c322300..d4eaa849a820e 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2415,7 +2415,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) mutex_unlock(&mdsc->mutex); goto out; } - if (req->r_got_safe && !head->safe) { + if (req->r_got_safe) { pr_warn("got unsafe after safe on %llu from mds%d\n", tid, mds); mutex_unlock(&mdsc->mutex); -- GitLab From a43137f7b0f1467cf3005b6ff6574d978642d247 Mon Sep 17 00:00:00 2001 From: Jianpeng Ma Date: Tue, 18 Aug 2015 10:23:50 +0800 Subject: [PATCH 6653/7006] ceph: remove the useless judgement err != 0 is already handled. So skip this. Signed-off-by: Jianpeng Ma Signed-off-by: Yan, Zheng --- fs/ceph/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 8b79d87eaf467..2ebcbd4c163b8 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -279,7 +279,7 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry, if (err) goto out_req; - if (err == 0 && (flags & O_CREAT) && !req->r_reply_info.head->is_dentry) + if ((flags & O_CREAT) && !req->r_reply_info.head->is_dentry) err = ceph_handle_notrace_create(dir, dentry); if (d_unhashed(dentry)) { -- GitLab From e36d571d70c7f46b20c28d81025fd5fc044a8e22 Mon Sep 17 00:00:00 2001 From: Jianpeng Ma Date: Tue, 18 Aug 2015 10:25:35 +0800 Subject: [PATCH 6654/7006] ceph: no need to get parent inode in ceph_open parent inode is needed in creating new inode case. For ceph_open, the target inode already exists. Signed-off-by: Jianpeng Ma Signed-off-by: Yan, Zheng --- fs/ceph/file.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 2ebcbd4c163b8..90ec110b8400c 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -136,7 +136,6 @@ int ceph_open(struct inode *inode, struct file *file) struct ceph_mds_client *mdsc = fsc->mdsc; struct ceph_mds_request *req; struct ceph_file_info *cf = file->private_data; - struct inode *parent_inode = NULL; int err; int flags, fmode, wanted; @@ -210,10 +209,7 @@ int ceph_open(struct inode *inode, struct file *file) ihold(inode); req->r_num_caps = 1; - if (flags & O_CREAT) - parent_inode = ceph_get_dentry_parent_inode(file->f_path.dentry); - err = ceph_mdsc_do_request(mdsc, parent_inode, req); - iput(parent_inode); + err = ceph_mdsc_do_request(mdsc, NULL, req); if (!err) err = ceph_init_file(inode, file, req->r_fmode); ceph_mdsc_put_request(req); -- GitLab From 5fdb1389e1399d6801a8c5d10952ef4153039fb2 Mon Sep 17 00:00:00 2001 From: Jianpeng Ma Date: Tue, 18 Aug 2015 10:30:38 +0800 Subject: [PATCH 6655/7006] ceph: cleanup use of ceph_msg_get Signed-off-by: Jianpeng Ma Signed-off-by: Yan, Zheng --- fs/ceph/mds_client.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index d4eaa849a820e..51cb02da75d98 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c @@ -2524,8 +2524,7 @@ out_err: if (err) { req->r_err = err; } else { - req->r_reply = msg; - ceph_msg_get(msg); + req->r_reply = ceph_msg_get(msg); req->r_got_result = true; } } else { -- GitLab From 6dd74e44dc1df85f125982a8d6591bc4a76c9f5d Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Fri, 28 Aug 2015 17:59:35 +0800 Subject: [PATCH 6656/7006] libceph: set 'exists' flag for newly up osd Signed-off-by: Yan, Zheng Reviewed-by: Sage Weil Signed-off-by: Ilya Dryomov --- net/ceph/osdmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c index 4a3125836b64a..7d8f581d9f1f7 100644 --- a/net/ceph/osdmap.c +++ b/net/ceph/osdmap.c @@ -1300,7 +1300,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, ceph_decode_addr(&addr); pr_info("osd%d up\n", osd); BUG_ON(osd >= map->max_osd); - map->osd_state[osd] |= CEPH_OSD_UP; + map->osd_state[osd] |= CEPH_OSD_UP | CEPH_OSD_EXISTS; map->osd_addr[osd] = addr; } -- GitLab From 3ebe138ac642a195c7f2efdb918f464734421fd6 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 31 Aug 2015 15:21:39 +0300 Subject: [PATCH 6657/7006] rbd: fix double free on rbd_dev->header_name If rbd_dev_image_probe() in rbd_dev_probe_parent() fails, header_name is freed twice: once in rbd_dev_probe_parent() and then in its caller rbd_dev_image_probe() (rbd_dev_image_probe() is called recursively to handle parent images). rbd_dev_probe_parent() is responsible for probing the parent, so it shouldn't muck with clone's fields. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index bc67a93aa4f47..324bf35ec4dd6 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -5201,7 +5201,6 @@ static int rbd_dev_probe_parent(struct rbd_device *rbd_dev) out_err: if (parent) { rbd_dev_unparent(rbd_dev); - kfree(rbd_dev->header_name); rbd_dev_destroy(parent); } else { rbd_put_client(rbdc); -- GitLab From d194cd1dd1be61249b08e5461ae8a9c05d1072c9 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Mon, 31 Aug 2015 18:22:10 +0300 Subject: [PATCH 6658/7006] rbd: plug rbd_dev->header.object_prefix memory leak Need to free object_prefix when rbd_dev_v2_snap_context() fails, but only if this is the first time we are reading in the header. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- drivers/block/rbd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 324bf35ec4dd6..69d03aa46d0db 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -4720,7 +4720,10 @@ static int rbd_dev_v2_header_info(struct rbd_device *rbd_dev) } ret = rbd_dev_v2_snap_context(rbd_dev); - dout("rbd_dev_v2_snap_context returned %d\n", ret); + if (ret && first_time) { + kfree(rbd_dev->header.object_prefix); + rbd_dev->header.object_prefix = NULL; + } return ret; } -- GitLab From 8b9558aab853e98ba6e3fee0dd8545544966958c Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Tue, 1 Sep 2015 17:19:38 +0800 Subject: [PATCH 6659/7006] libceph: use keepalive2 to verify the mon session is alive Signed-off-by: Yan, Zheng Signed-off-by: Ilya Dryomov --- include/linux/ceph/libceph.h | 2 ++ include/linux/ceph/messenger.h | 4 +++ include/linux/ceph/msgr.h | 4 ++- net/ceph/ceph_common.c | 1 + net/ceph/messenger.c | 59 +++++++++++++++++++++++++++++++--- net/ceph/mon_client.c | 37 ++++++++++++++++----- 6 files changed, 93 insertions(+), 14 deletions(-) diff --git a/include/linux/ceph/libceph.h b/include/linux/ceph/libceph.h index 9ebee53d3bf58..397c5cd097948 100644 --- a/include/linux/ceph/libceph.h +++ b/include/linux/ceph/libceph.h @@ -46,6 +46,7 @@ struct ceph_options { unsigned long mount_timeout; /* jiffies */ unsigned long osd_idle_ttl; /* jiffies */ unsigned long osd_keepalive_timeout; /* jiffies */ + unsigned long monc_ping_timeout; /* jiffies */ /* * any type that can't be simply compared or doesn't need need @@ -66,6 +67,7 @@ struct ceph_options { #define CEPH_MOUNT_TIMEOUT_DEFAULT msecs_to_jiffies(60 * 1000) #define CEPH_OSD_KEEPALIVE_DEFAULT msecs_to_jiffies(5 * 1000) #define CEPH_OSD_IDLE_TTL_DEFAULT msecs_to_jiffies(60 * 1000) +#define CEPH_MONC_PING_TIMEOUT_DEFAULT msecs_to_jiffies(30 * 1000) #define CEPH_MSG_MAX_FRONT_LEN (16*1024*1024) #define CEPH_MSG_MAX_MIDDLE_LEN (16*1024*1024) diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h index 37753278987ac..7e1252e97a30b 100644 --- a/include/linux/ceph/messenger.h +++ b/include/linux/ceph/messenger.h @@ -248,6 +248,8 @@ struct ceph_connection { int in_base_pos; /* bytes read */ __le64 in_temp_ack; /* for reading an ack */ + struct timespec last_keepalive_ack; + struct delayed_work work; /* send|recv work */ unsigned long delay; /* current delay interval */ }; @@ -285,6 +287,8 @@ extern void ceph_msg_revoke(struct ceph_msg *msg); extern void ceph_msg_revoke_incoming(struct ceph_msg *msg); extern void ceph_con_keepalive(struct ceph_connection *con); +extern bool ceph_con_keepalive_expired(struct ceph_connection *con, + unsigned long interval); extern void ceph_msg_data_add_pages(struct ceph_msg *msg, struct page **pages, size_t length, size_t alignment); diff --git a/include/linux/ceph/msgr.h b/include/linux/ceph/msgr.h index 1c1887206ffa9..0fe2656ac4157 100644 --- a/include/linux/ceph/msgr.h +++ b/include/linux/ceph/msgr.h @@ -84,10 +84,12 @@ struct ceph_entity_inst { #define CEPH_MSGR_TAG_MSG 7 /* message */ #define CEPH_MSGR_TAG_ACK 8 /* message ack */ #define CEPH_MSGR_TAG_KEEPALIVE 9 /* just a keepalive byte! */ -#define CEPH_MSGR_TAG_BADPROTOVER 10 /* bad protocol version */ +#define CEPH_MSGR_TAG_BADPROTOVER 10 /* bad protocol version */ #define CEPH_MSGR_TAG_BADAUTHORIZER 11 /* bad authorizer */ #define CEPH_MSGR_TAG_FEATURES 12 /* insufficient features */ #define CEPH_MSGR_TAG_SEQ 13 /* 64-bit int follows with seen seq number */ +#define CEPH_MSGR_TAG_KEEPALIVE2 14 /* keepalive2 byte + ceph_timespec */ +#define CEPH_MSGR_TAG_KEEPALIVE2_ACK 15 /* keepalive2 reply */ /* diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c index f30329f726418..3f56eefc2a073 100644 --- a/net/ceph/ceph_common.c +++ b/net/ceph/ceph_common.c @@ -357,6 +357,7 @@ ceph_parse_options(char *options, const char *dev_name, opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT; opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; + opt->monc_ping_timeout = CEPH_MONC_PING_TIMEOUT_DEFAULT; /* get mon ip(s) */ /* ip1[:port1][,ip2[:port2]...] */ diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 101ab6285fbae..36757d46ac406 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -163,6 +163,7 @@ static struct kmem_cache *ceph_msg_data_cache; static char tag_msg = CEPH_MSGR_TAG_MSG; static char tag_ack = CEPH_MSGR_TAG_ACK; static char tag_keepalive = CEPH_MSGR_TAG_KEEPALIVE; +static char tag_keepalive2 = CEPH_MSGR_TAG_KEEPALIVE2; #ifdef CONFIG_LOCKDEP static struct lock_class_key socket_class; @@ -1351,7 +1352,15 @@ static void prepare_write_keepalive(struct ceph_connection *con) { dout("prepare_write_keepalive %p\n", con); con_out_kvec_reset(con); - con_out_kvec_add(con, sizeof (tag_keepalive), &tag_keepalive); + if (con->peer_features & CEPH_FEATURE_MSGR_KEEPALIVE2) { + struct timespec ts = CURRENT_TIME; + struct ceph_timespec ceph_ts; + ceph_encode_timespec(&ceph_ts, &ts); + con_out_kvec_add(con, sizeof(tag_keepalive2), &tag_keepalive2); + con_out_kvec_add(con, sizeof(ceph_ts), &ceph_ts); + } else { + con_out_kvec_add(con, sizeof(tag_keepalive), &tag_keepalive); + } con_flag_set(con, CON_FLAG_WRITE_PENDING); } @@ -1625,6 +1634,12 @@ static void prepare_read_tag(struct ceph_connection *con) con->in_tag = CEPH_MSGR_TAG_READY; } +static void prepare_read_keepalive_ack(struct ceph_connection *con) +{ + dout("prepare_read_keepalive_ack %p\n", con); + con->in_base_pos = 0; +} + /* * Prepare to read a message. */ @@ -2457,6 +2472,17 @@ static void process_message(struct ceph_connection *con) mutex_lock(&con->mutex); } +static int read_keepalive_ack(struct ceph_connection *con) +{ + struct ceph_timespec ceph_ts; + size_t size = sizeof(ceph_ts); + int ret = read_partial(con, size, size, &ceph_ts); + if (ret <= 0) + return ret; + ceph_decode_timespec(&con->last_keepalive_ack, &ceph_ts); + prepare_read_tag(con); + return 1; +} /* * Write something to the socket. Called in a worker thread when the @@ -2526,6 +2552,10 @@ more_kvec: do_next: if (con->state == CON_STATE_OPEN) { + if (con_flag_test_and_clear(con, CON_FLAG_KEEPALIVE_PENDING)) { + prepare_write_keepalive(con); + goto more; + } /* is anything else pending? */ if (!list_empty(&con->out_queue)) { prepare_write_message(con); @@ -2535,10 +2565,6 @@ do_next: prepare_write_ack(con); goto more; } - if (con_flag_test_and_clear(con, CON_FLAG_KEEPALIVE_PENDING)) { - prepare_write_keepalive(con); - goto more; - } } /* Nothing to do! */ @@ -2641,6 +2667,9 @@ more: case CEPH_MSGR_TAG_ACK: prepare_read_ack(con); break; + case CEPH_MSGR_TAG_KEEPALIVE2_ACK: + prepare_read_keepalive_ack(con); + break; case CEPH_MSGR_TAG_CLOSE: con_close_socket(con); con->state = CON_STATE_CLOSED; @@ -2684,6 +2713,12 @@ more: process_ack(con); goto more; } + if (con->in_tag == CEPH_MSGR_TAG_KEEPALIVE2_ACK) { + ret = read_keepalive_ack(con); + if (ret <= 0) + goto out; + goto more; + } out: dout("try_read done on %p ret %d\n", con, ret); @@ -3101,6 +3136,20 @@ void ceph_con_keepalive(struct ceph_connection *con) } EXPORT_SYMBOL(ceph_con_keepalive); +bool ceph_con_keepalive_expired(struct ceph_connection *con, + unsigned long interval) +{ + if (interval > 0 && + (con->peer_features & CEPH_FEATURE_MSGR_KEEPALIVE2)) { + struct timespec now = CURRENT_TIME; + struct timespec ts; + jiffies_to_timespec(interval, &ts); + ts = timespec_add(con->last_keepalive_ack, ts); + return timespec_compare(&now, &ts) >= 0; + } + return false; +} + static struct ceph_msg_data *ceph_msg_data_create(enum ceph_msg_data_type type) { struct ceph_msg_data *data; diff --git a/net/ceph/mon_client.c b/net/ceph/mon_client.c index 9d6ff1215928c..edda01626a459 100644 --- a/net/ceph/mon_client.c +++ b/net/ceph/mon_client.c @@ -149,6 +149,10 @@ static int __open_session(struct ceph_mon_client *monc) CEPH_ENTITY_TYPE_MON, monc->cur_mon, &monc->monmap->mon_inst[monc->cur_mon].addr); + /* send an initial keepalive to ensure our timestamp is + * valid by the time we are in an OPENED state */ + ceph_con_keepalive(&monc->con); + /* initiatiate authentication handshake */ ret = ceph_auth_build_hello(monc->auth, monc->m_auth->front.iov_base, @@ -170,14 +174,19 @@ static bool __sub_expired(struct ceph_mon_client *monc) */ static void __schedule_delayed(struct ceph_mon_client *monc) { - unsigned int delay; + struct ceph_options *opt = monc->client->options; + unsigned long delay; - if (monc->cur_mon < 0 || __sub_expired(monc)) + if (monc->cur_mon < 0 || __sub_expired(monc)) { delay = 10 * HZ; - else + } else { delay = 20 * HZ; - dout("__schedule_delayed after %u\n", delay); - schedule_delayed_work(&monc->delayed_work, delay); + if (opt->monc_ping_timeout > 0) + delay = min(delay, opt->monc_ping_timeout / 3); + } + dout("__schedule_delayed after %lu\n", delay); + schedule_delayed_work(&monc->delayed_work, + round_jiffies_relative(delay)); } /* @@ -743,11 +752,23 @@ static void delayed_work(struct work_struct *work) __close_session(monc); __open_session(monc); /* continue hunting */ } else { - ceph_con_keepalive(&monc->con); + struct ceph_options *opt = monc->client->options; + int is_auth = ceph_auth_is_authenticated(monc->auth); + if (ceph_con_keepalive_expired(&monc->con, + opt->monc_ping_timeout)) { + dout("monc keepalive timeout\n"); + is_auth = 0; + __close_session(monc); + monc->hunting = true; + __open_session(monc); + } - __validate_auth(monc); + if (!monc->hunting) { + ceph_con_keepalive(&monc->con); + __validate_auth(monc); + } - if (ceph_auth_is_authenticated(monc->auth)) + if (is_auth) __send_subscribe(monc); } __schedule_delayed(monc); -- GitLab From fcb0bb6aab256288a4e0a8650d26e4096ec30319 Mon Sep 17 00:00:00 2001 From: Eugene Shatokhin Date: Tue, 1 Sep 2015 17:05:33 +0300 Subject: [PATCH 6660/7006] usbnet: Fix a race between usbnet_stop() and the BH MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The race may happen when a device (e.g. YOTA 4G LTE Modem) is unplugged while the system is downloading a large file from the Net. Hardware breakpoints and Kprobes with delays were used to confirm that the race does actually happen. The race is on skb_queue ('next' pointer) between usbnet_stop() and rx_complete(), which, in turn, calls usbnet_bh(). Here is a part of the call stack with the code where the changes to the queue happen. The line numbers are for the kernel 4.1.0: *0 __skb_unlink (skbuff.h:1517) prev->next = next; *1 defer_bh (usbnet.c:430) spin_lock_irqsave(&list->lock, flags); old_state = entry->state; entry->state = state; __skb_unlink(skb, list); spin_unlock(&list->lock); spin_lock(&dev->done.lock); __skb_queue_tail(&dev->done, skb); if (dev->done.qlen == 1) tasklet_schedule(&dev->bh); spin_unlock_irqrestore(&dev->done.lock, flags); *2 rx_complete (usbnet.c:640) state = defer_bh(dev, skb, &dev->rxq, state); At the same time, the following code repeatedly checks if the queue is empty and reads these values concurrently with the above changes: *0 usbnet_terminate_urbs (usbnet.c:765) /* maybe wait for deletions to finish. */ while (!skb_queue_empty(&dev->rxq) && !skb_queue_empty(&dev->txq) && !skb_queue_empty(&dev->done)) { schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); set_current_state(TASK_UNINTERRUPTIBLE); netif_dbg(dev, ifdown, dev->net, "waited for %d urb completions\n", temp); } *1 usbnet_stop (usbnet.c:806) if (!(info->flags & FLAG_AVOID_UNLINK_URBS)) usbnet_terminate_urbs(dev); As a result, it is possible, for example, that the skb is removed from dev->rxq by __skb_unlink() before the check "!skb_queue_empty(&dev->rxq)" in usbnet_terminate_urbs() is made. It is also possible in this case that the skb is added to dev->done queue after "!skb_queue_empty(&dev->done)" is checked. So usbnet_terminate_urbs() may stop waiting and return while dev->done queue still has an item. Locking in defer_bh() and usbnet_terminate_urbs() was revisited to avoid this race. Signed-off-by: Eugene Shatokhin Reviewed-by: Bjørn Mork Acked-by: Oliver Neukum Signed-off-by: David S. Miller --- drivers/net/usb/usbnet.c | 39 ++++++++++++++++++++++++++++----------- 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index e0498571ae267..b4cf10781348e 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -428,12 +428,18 @@ static enum skb_state defer_bh(struct usbnet *dev, struct sk_buff *skb, old_state = entry->state; entry->state = state; __skb_unlink(skb, list); - spin_unlock(&list->lock); - spin_lock(&dev->done.lock); + + /* defer_bh() is never called with list == &dev->done. + * spin_lock_nested() tells lockdep that it is OK to take + * dev->done.lock here with list->lock held. + */ + spin_lock_nested(&dev->done.lock, SINGLE_DEPTH_NESTING); + __skb_queue_tail(&dev->done, skb); if (dev->done.qlen == 1) tasklet_schedule(&dev->bh); - spin_unlock_irqrestore(&dev->done.lock, flags); + spin_unlock(&dev->done.lock); + spin_unlock_irqrestore(&list->lock, flags); return old_state; } @@ -749,6 +755,20 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs); /*-------------------------------------------------------------------------*/ +static void wait_skb_queue_empty(struct sk_buff_head *q) +{ + unsigned long flags; + + spin_lock_irqsave(&q->lock, flags); + while (!skb_queue_empty(q)) { + spin_unlock_irqrestore(&q->lock, flags); + schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); + set_current_state(TASK_UNINTERRUPTIBLE); + spin_lock_irqsave(&q->lock, flags); + } + spin_unlock_irqrestore(&q->lock, flags); +} + // precondition: never called in_interrupt static void usbnet_terminate_urbs(struct usbnet *dev) { @@ -762,14 +782,11 @@ static void usbnet_terminate_urbs(struct usbnet *dev) unlink_urbs(dev, &dev->rxq); /* maybe wait for deletions to finish. */ - while (!skb_queue_empty(&dev->rxq) - && !skb_queue_empty(&dev->txq) - && !skb_queue_empty(&dev->done)) { - schedule_timeout(msecs_to_jiffies(UNLINK_TIMEOUT_MS)); - set_current_state(TASK_UNINTERRUPTIBLE); - netif_dbg(dev, ifdown, dev->net, - "waited for %d urb completions\n", temp); - } + wait_skb_queue_empty(&dev->rxq); + wait_skb_queue_empty(&dev->txq); + wait_skb_queue_empty(&dev->done); + netif_dbg(dev, ifdown, dev->net, + "waited for %d urb completions\n", temp); set_current_state(TASK_RUNNING); remove_wait_queue(&dev->wait, &wait); } -- GitLab From 5b902d6f97f573fde911338e5d943e6b07fac7f9 Mon Sep 17 00:00:00 2001 From: Julien Grall Date: Thu, 3 Sep 2015 23:59:50 +0100 Subject: [PATCH 6661/7006] device property: Don't overwrite addr when failing in device_get_mac_address The function device_get_mac_address is trying different property names in order to get the mac address. To check the return value, the variable addr (which contain the buffer pass by the caller) will be re-used. This means that if the previous property is not found, the next property will be read using a NULL buffer. Therefore it's only possible to retrieve the mac if node contains a property "mac-address". Fix it by using a temporary buffer for the return value. This has been introduced by commit 4c96b7dc0d393f12c17e0d81db15aa4a820a6ab3 "Add a matching set of device_ functions for determining mac/phy" Signed-off-by: Julien Grall Cc: Jeremy Linton Cc: David S. Miller Reviewed-by: Jeremy Linton Signed-off-by: David S. Miller --- drivers/base/property.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/drivers/base/property.c b/drivers/base/property.c index ff03f2348f77e..2d75366c61e03 100644 --- a/drivers/base/property.c +++ b/drivers/base/property.c @@ -611,13 +611,15 @@ static void *device_get_mac_addr(struct device *dev, */ void *device_get_mac_address(struct device *dev, char *addr, int alen) { - addr = device_get_mac_addr(dev, "mac-address", addr, alen); - if (addr) - return addr; + char *res; - addr = device_get_mac_addr(dev, "local-mac-address", addr, alen); - if (addr) - return addr; + res = device_get_mac_addr(dev, "mac-address", addr, alen); + if (res) + return res; + + res = device_get_mac_addr(dev, "local-mac-address", addr, alen); + if (res) + return res; return device_get_mac_addr(dev, "address", addr, alen); } -- GitLab From 61e57c0c3a37539e13af03ce68598034d37c7256 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Tue, 8 Sep 2015 14:58:22 -0700 Subject: [PATCH 6662/7006] cgroup: fix seq_show_option merge with legacy_name When seq_show_option (commit a068acf2ee77: "fs: create and use seq_show_option for escaping") was merged, it did not correctly collide with cgroup's addition of legacy_name (commit 3e1d2eed39d8: "cgroup: introduce cgroup_subsys->legacy_name") changes. This fixes the reported name. Signed-off-by: Kees Cook Acked-by: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cgroup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index a8538e4437842..2cf0f79f1fc90 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -1342,7 +1342,7 @@ static int cgroup_show_options(struct seq_file *seq, if (root != &cgrp_dfl_root) for_each_subsys(ss, ssid) if (root->subsys_mask & (1 << ssid)) - seq_show_option(seq, ss->name, NULL); + seq_show_option(seq, ss->legacy_name, NULL); if (root->flags & CGRP_ROOT_NOPREFIX) seq_puts(seq, ",noprefix"); if (root->flags & CGRP_ROOT_XATTR) -- GitLab From af8713b701a74c3784ce6683f64f474a94b1b643 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 8 Sep 2015 14:58:25 -0700 Subject: [PATCH 6663/7006] selftests/userfaultfd: fix compiler warnings on 32-bit On 32-bit: userfaultfd.c: In function 'locking_thread': userfaultfd.c:152: warning: left shift count >= width of type userfaultfd.c: In function 'uffd_poll_thread': userfaultfd.c:295: warning: cast to pointer from integer of different size userfaultfd.c: In function 'uffd_read_thread': userfaultfd.c:332: warning: cast to pointer from integer of different size Fix the shift warning by splitting the shift in two parts, and the integer/pointer warnigns by adding intermediate casts to "unsigned long". Signed-off-by: Geert Uytterhoeven Cc: Andrea Arcangeli Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/vm/userfaultfd.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index 0c0b839533526..b619f672131ea 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -147,7 +147,8 @@ static void *locking_thread(void *arg) if (sizeof(page_nr) > sizeof(rand_nr)) { if (random_r(&rand, &rand_nr)) fprintf(stderr, "random_r 2 error\n"), exit(1); - page_nr |= ((unsigned long) rand_nr) << 32; + page_nr |= (((unsigned long) rand_nr) << 16) << + 16; } } else page_nr += 1; @@ -290,7 +291,8 @@ static void *uffd_poll_thread(void *arg) msg.event), exit(1); if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) fprintf(stderr, "unexpected write fault\n"), exit(1); - offset = (char *)msg.arg.pagefault.address - area_dst; + offset = (char *)(unsigned long)msg.arg.pagefault.address - + area_dst; offset &= ~(page_size-1); if (copy_page(offset)) userfaults++; @@ -327,7 +329,8 @@ static void *uffd_read_thread(void *arg) if (bounces & BOUNCE_VERIFY && msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) fprintf(stderr, "unexpected write fault\n"), exit(1); - offset = (char *)msg.arg.pagefault.address - area_dst; + offset = (char *)(unsigned long)msg.arg.pagefault.address - + area_dst; offset &= ~(page_size-1); if (copy_page(offset)) (*this_cpu_userfaults)++; -- GitLab From b5330628546616af14ff23075fbf8d4ad91f6e25 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 8 Sep 2015 14:58:28 -0700 Subject: [PATCH 6664/7006] mm: introduce vma_is_anonymous(vma) helper special_mapping_fault() is absolutely broken. It seems it was always wrong, but this didn't matter until vdso/vvar started to use more than one page. And after this change vma_is_anonymous() becomes really trivial, it simply checks vm_ops == NULL. However, I do think the helper makes sense. There are a lot of ->vm_ops != NULL checks, the helper makes the caller's code more understandable (self-documented) and this is more grep-friendly. This patch (of 3): Preparation. Add the new simple helper, vma_is_anonymous(vma), and change handle_pte_fault() to use it. It will have more users. The name is not accurate, say a hpet_mmap()'ed vma is not anonymous. Perhaps it should be named vma_has_fault() instead. But it matches the logic in mmap.c/memory.c (see next changes). "True" just means that a page fault will use do_anonymous_page(). Signed-off-by: Oleg Nesterov Acked-by: Kirill A. Shutemov Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 5 +++++ mm/memory.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 8b257c43855bb..dfb7ce05f1e33 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1260,6 +1260,11 @@ static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); } +static inline bool vma_is_anonymous(struct vm_area_struct *vma) +{ + return !vma->vm_ops; +} + static inline int stack_guard_page_start(struct vm_area_struct *vma, unsigned long addr) { diff --git a/mm/memory.c b/mm/memory.c index bb04d8f2f86c4..882c9d7ae2f5f 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3267,12 +3267,12 @@ static int handle_pte_fault(struct mm_struct *mm, barrier(); if (!pte_present(entry)) { if (pte_none(entry)) { - if (vma->vm_ops) + if (vma_is_anonymous(vma)) + return do_anonymous_page(mm, vma, address, + pte, pmd, flags); + else return do_fault(mm, vma, address, pte, pmd, flags, entry); - - return do_anonymous_page(mm, vma, address, pte, pmd, - flags); } return do_swap_page(mm, vma, address, pte, pmd, flags, entry); -- GitLab From 8a9cc3b55e9d20289cc18a65257e62c2dd4932fb Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 8 Sep 2015 14:58:31 -0700 Subject: [PATCH 6665/7006] mmap: fix the usage of ->vm_pgoff in special_mapping paths Test-case: #include #include #include #include #include #include void *find_vdso_vaddr(void) { FILE *perl; char buf[32] = {}; perl = popen("perl -e 'open STDIN,qq|/proc/@{[getppid]}/maps|;" "/^(.*?)-.*vdso/ && print hex $1 while <>'", "r"); fread(buf, sizeof(buf), 1, perl); fclose(perl); return (void *)atol(buf); } #define PAGE_SIZE 4096 int main(void) { void *vdso = find_vdso_vaddr(); assert(vdso); // of course they should differ, and they do so far printf("vdso pages differ: %d\n", !!memcmp(vdso, vdso + PAGE_SIZE, PAGE_SIZE)); // split into 2 vma's assert(mprotect(vdso, PAGE_SIZE, PROT_READ) == 0); // force another fault on the next check assert(madvise(vdso, 2 * PAGE_SIZE, MADV_DONTNEED) == 0); // now they no longer differ, the 2nd vm_pgoff is wrong printf("vdso pages differ: %d\n", !!memcmp(vdso, vdso + PAGE_SIZE, PAGE_SIZE)); return 0; } Output: vdso pages differ: 1 vdso pages differ: 0 This is because split_vma() correctly updates ->vm_pgoff, but the logic in insert_vm_struct() and special_mapping_fault() is absolutely broken, so the fault at vdso + PAGE_SIZE return the 1st page. The same happens if you simply unmap the 1st page. special_mapping_fault() does: pgoff = vmf->pgoff - vma->vm_pgoff; and this is _only_ correct if vma->vm_start mmaps the first page from ->vm_private_data array. vdso or any other user of install_special_mapping() is not anonymous, it has the "backing storage" even if it is just the array of pages. So we actually need to make vm_pgoff work as an offset in this array. Note: this also allows to fix another problem: currently gdb can't access "[vvar]" memory because in this case special_mapping_fault() doesn't work. Now that we can use ->vm_pgoff we can implement ->access() and fix this. Signed-off-by: Oleg Nesterov Acked-by: Kirill A. Shutemov Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 82db4fc0a9d34..52b2f6e16f6f1 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2884,7 +2884,7 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma) * using the existing file pgoff checks and manipulations. * Similarly in do_mmap_pgoff and in do_brk. */ - if (!vma->vm_file) { + if (vma_is_anonymous(vma)) { BUG_ON(vma->anon_vma); vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT; } @@ -3027,21 +3027,13 @@ static int special_mapping_fault(struct vm_area_struct *vma, pgoff_t pgoff; struct page **pages; - /* - * special mappings have no vm_file, and in that case, the mm - * uses vm_pgoff internally. So we have to subtract it from here. - * We are allowed to do this because we are the mm; do not copy - * this code into drivers! - */ - pgoff = vmf->pgoff - vma->vm_pgoff; - if (vma->vm_ops == &legacy_special_mapping_vmops) pages = vma->vm_private_data; else pages = ((struct vm_special_mapping *)vma->vm_private_data)-> pages; - for (; pgoff && *pages; ++pages) + for (pgoff = vmf->pgoff; pgoff && *pages; ++pages) pgoff--; if (*pages) { -- GitLab From ce75799b83aaf3fd592e21531a9532bed157c6b5 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Tue, 8 Sep 2015 14:58:34 -0700 Subject: [PATCH 6666/7006] mremap: fix the wrong !vma->vm_file check in copy_vma() Test-case: #define _GNU_SOURCE #include #include #include #include #include #include void *find_vdso_vaddr(void) { FILE *perl; char buf[32] = {}; perl = popen("perl -e 'open STDIN,qq|/proc/@{[getppid]}/maps|;" "/^(.*?)-.*vdso/ && print hex $1 while <>'", "r"); fread(buf, sizeof(buf), 1, perl); fclose(perl); return (void *)atol(buf); } #define PAGE_SIZE 4096 void *get_unmapped_area(void) { void *p = mmap(0, PAGE_SIZE, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1,0); assert(p != MAP_FAILED); munmap(p, PAGE_SIZE); return p; } char save[2][PAGE_SIZE]; int main(void) { void *vdso = find_vdso_vaddr(); void *page[2]; assert(vdso); memcpy(save, vdso, sizeof (save)); // force another fault on the next check assert(madvise(vdso, 2 * PAGE_SIZE, MADV_DONTNEED) == 0); page[0] = mremap(vdso, PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE, get_unmapped_area()); page[1] = mremap(vdso + PAGE_SIZE, PAGE_SIZE, PAGE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE, get_unmapped_area()); assert(page[0] != MAP_FAILED && page[1] != MAP_FAILED); printf("match: %d %d\n", !memcmp(save[0], page[0], PAGE_SIZE), !memcmp(save[1], page[1], PAGE_SIZE)); return 0; } fails without this patch. Before the previous commit it gets the wrong page, now it segfaults (which is imho better). This is because copy_vma() wrongly assumes that if vma->vm_file == NULL is irrelevant until the first fault which will use do_anonymous_page(). This is obviously wrong for the special mapping. Signed-off-by: Oleg Nesterov Acked-by: Kirill A. Shutemov Cc: Andy Lutomirski Cc: Hugh Dickins Cc: Pavel Emelyanov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/mmap.c b/mm/mmap.c index 52b2f6e16f6f1..52a2373d0ed42 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2918,7 +2918,7 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, * If anonymous vma has not yet been faulted, update new pgoff * to match new location, to increase its chance of merging. */ - if (unlikely(!vma->vm_file && !vma->anon_vma)) { + if (unlikely(vma_is_anonymous(vma) && !vma->anon_vma)) { pgoff = addr >> PAGE_SHIFT; faulted_in_anon_vma = false; } -- GitLab From e1b9996b85ba3ff143ded04523cd015762d20f03 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 14:58:37 -0700 Subject: [PATCH 6667/7006] thp: vma_adjust_trans_huge(): adjust file-backed VMA too This series of patches adds support for using PMD page table entries to map DAX files. We expect NV-DIMMs to start showing up that are many gigabytes in size and the memory consumption of 4kB PTEs will be astronomical. The patch series leverages much of the Transparant Huge Pages infrastructure, going so far as to borrow one of Kirill's patches from his THP page cache series. This patch (of 10): Since we're going to have huge pages in page cache, we need to call adjust file-backed VMA, which potentially can contain huge pages. For now we call it for all VMAs. Probably later we will need to introduce a flag to indicate that the VMA has huge pages. Signed-off-by: Kirill A. Shutemov Signed-off-by: Matthew Wilcox Acked-by: Hillf Danton Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/huge_mm.h | 11 +---------- mm/huge_memory.c | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index f10b20f051599..1c53c7d7ef7e6 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -122,7 +122,7 @@ extern void split_huge_page_pmd_mm(struct mm_struct *mm, unsigned long address, #endif extern int hugepage_madvise(struct vm_area_struct *vma, unsigned long *vm_flags, int advice); -extern void __vma_adjust_trans_huge(struct vm_area_struct *vma, +extern void vma_adjust_trans_huge(struct vm_area_struct *vma, unsigned long start, unsigned long end, long adjust_next); @@ -138,15 +138,6 @@ static inline int pmd_trans_huge_lock(pmd_t *pmd, struct vm_area_struct *vma, else return 0; } -static inline void vma_adjust_trans_huge(struct vm_area_struct *vma, - unsigned long start, - unsigned long end, - long adjust_next) -{ - if (!vma->anon_vma || vma->vm_ops) - return; - __vma_adjust_trans_huge(vma, start, end, adjust_next); -} static inline int hpage_nr_pages(struct page *page) { if (unlikely(PageTransHuge(page))) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 279a818a39b13..4d5fcb630d321 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2991,7 +2991,7 @@ static void split_huge_page_address(struct mm_struct *mm, split_huge_page_pmd_mm(mm, address, pmd); } -void __vma_adjust_trans_huge(struct vm_area_struct *vma, +void vma_adjust_trans_huge(struct vm_area_struct *vma, unsigned long start, unsigned long end, long adjust_next) -- GitLab From c94c2acf84dc16cf4b989bb0bc849785b7ff52f5 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:58:40 -0700 Subject: [PATCH 6668/7006] dax: move DAX-related functions to a new header In order to handle the !CONFIG_TRANSPARENT_HUGEPAGES case, we need to return VM_FAULT_FALLBACK from the inlined dax_pmd_fault(), which is defined in linux/mm.h. Given that we don't want to include in , the easiest solution is to move the DAX-related functions to a new header, . We could also have moved VM_FAULT_* definitions to a new header, or a different header that isn't quite such a boil-the-ocean header as , but this felt like the best option. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/block_dev.c | 1 + fs/ext2/file.c | 1 + fs/ext2/inode.c | 1 + fs/ext4/file.c | 1 + fs/ext4/indirect.c | 1 + fs/ext4/inode.c | 1 + fs/xfs/xfs_buf.h | 1 + include/linux/dax.h | 21 +++++++++++++++++++++ include/linux/fs.h | 14 -------------- 9 files changed, 28 insertions(+), 14 deletions(-) create mode 100644 include/linux/dax.h diff --git a/fs/block_dev.c b/fs/block_dev.c index 33b813e04f792..28cc525b8d59a 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "internal.h" diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 3b57c9f83c9b9..db4c299b7cf67 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "ext2.h" #include "xattr.h" diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index a3a404c5df2ed..c60a248c640cb 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/ext4/file.c b/fs/ext4/file.c index bc313ac5d3fa0..f8a631047379b 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/ext4/indirect.c b/fs/ext4/indirect.c index 4f6ac499f09e7..2468261748b2c 100644 --- a/fs/ext4/indirect.c +++ b/fs/ext4/indirect.c @@ -22,6 +22,7 @@ #include "ext4_jbd2.h" #include "truncate.h" +#include #include #include diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 29f1af7c2cab9..5ebcc7683a5c1 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h index 331c1ccf82647..c79b717d9b882 100644 --- a/fs/xfs/xfs_buf.h +++ b/fs/xfs/xfs_buf.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include diff --git a/include/linux/dax.h b/include/linux/dax.h new file mode 100644 index 0000000000000..4f27d3dbf6e80 --- /dev/null +++ b/include/linux/dax.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_DAX_H +#define _LINUX_DAX_H + +#include +#include +#include + +ssize_t dax_do_io(struct kiocb *, struct inode *, struct iov_iter *, loff_t, + get_block_t, dio_iodone_t, int flags); +int dax_clear_blocks(struct inode *, sector_t block, long size); +int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t); +int dax_truncate_page(struct inode *, loff_t from, get_block_t); +int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, + dax_iodone_t); +int __dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, + dax_iodone_t); +int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); +#define dax_mkwrite(vma, vmf, gb, iod) dax_fault(vma, vmf, gb, iod) +#define __dax_mkwrite(vma, vmf, gb, iod) __dax_fault(vma, vmf, gb, iod) + +#endif diff --git a/include/linux/fs.h b/include/linux/fs.h index b2f9b9c25e419..72d8a844c692b 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -52,7 +52,6 @@ struct swap_info_struct; struct seq_file; struct workqueue_struct; struct iov_iter; -struct vm_fault; extern void __init inode_init(void); extern void __init inode_init_early(void); @@ -2678,19 +2677,6 @@ extern loff_t fixed_size_llseek(struct file *file, loff_t offset, extern int generic_file_open(struct inode * inode, struct file * filp); extern int nonseekable_open(struct inode * inode, struct file * filp); -ssize_t dax_do_io(struct kiocb *, struct inode *, struct iov_iter *, loff_t, - get_block_t, dio_iodone_t, int flags); -int dax_clear_blocks(struct inode *, sector_t block, long size); -int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t); -int dax_truncate_page(struct inode *, loff_t from, get_block_t); -int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, - dax_iodone_t); -int __dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, - dax_iodone_t); -int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); -#define dax_mkwrite(vma, vmf, gb, iod) dax_fault(vma, vmf, gb, iod) -#define __dax_mkwrite(vma, vmf, gb, iod) __dax_fault(vma, vmf, gb, iod) - #ifdef CONFIG_BLOCK typedef void (dio_submit_t)(int rw, struct bio *bio, struct inode *inode, loff_t file_offset); -- GitLab From 7c414164593514f76b422faae0824bdd3754209b Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 8 Sep 2015 14:58:43 -0700 Subject: [PATCH 6669/7006] dax: revert userfaultfd change Undo the change which "userfaultfd: call handle_userfault() for userfaultfd_missing() faults" made to set_huge_zero_page(). DAX will need that return value. Cc: Andrea Arcangeli Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 4d5fcb630d321..ca475dfdb28fe 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -794,16 +794,19 @@ static inline gfp_t alloc_hugepage_gfpmask(int defrag, gfp_t extra_gfp) } /* Caller must hold page table lock. */ -static void set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, +static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd, struct page *zero_page) { pmd_t entry; + if (!pmd_none(*pmd)) + return false; entry = mk_pmd(zero_page, vma->vm_page_prot); entry = pmd_mkhuge(entry); pgtable_trans_huge_deposit(mm, pmd, pgtable); set_pmd_at(mm, haddr, pmd, entry); atomic_long_inc(&mm->nr_ptes); + return true; } int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, -- GitLab From 4897c7655d9419ba7e62bac145ec6a1847134d93 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:58:45 -0700 Subject: [PATCH 6670/7006] thp: prepare for DAX huge pages Add a vma_is_dax() helper macro to test whether the VMA is DAX, and use it in zap_huge_pmd() and __split_huge_page_pmd(). [akpm@linux-foundation.org: fix build] Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/dax.h | 4 ++++ mm/huge_memory.c | 48 +++++++++++++++++++++++++++------------------ 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/include/linux/dax.h b/include/linux/dax.h index 4f27d3dbf6e80..9b51f9d40ad96 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -18,4 +18,8 @@ int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); #define dax_mkwrite(vma, vmf, gb, iod) dax_fault(vma, vmf, gb, iod) #define __dax_mkwrite(vma, vmf, gb, iod) __dax_fault(vma, vmf, gb, iod) +static inline bool vma_is_dax(struct vm_area_struct *vma) +{ + return vma->vm_file && IS_DAX(vma->vm_file->f_mapping->host); +} #endif diff --git a/mm/huge_memory.c b/mm/huge_memory.c index ca475dfdb28fe..9057241d57224 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -794,7 +795,7 @@ static inline gfp_t alloc_hugepage_gfpmask(int defrag, gfp_t extra_gfp) } /* Caller must hold page table lock. */ -static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, +bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd, struct page *zero_page) { @@ -1421,7 +1422,6 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, int ret = 0; if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { - struct page *page; pgtable_t pgtable; pmd_t orig_pmd; /* @@ -1433,13 +1433,22 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, orig_pmd = pmdp_huge_get_and_clear_full(tlb->mm, addr, pmd, tlb->fullmm); tlb_remove_pmd_tlb_entry(tlb, pmd, addr); - pgtable = pgtable_trans_huge_withdraw(tlb->mm, pmd); + if (vma_is_dax(vma)) { + if (is_huge_zero_pmd(orig_pmd)) { + pgtable = NULL; + } else { + spin_unlock(ptl); + return 1; + } + } else { + pgtable = pgtable_trans_huge_withdraw(tlb->mm, pmd); + } if (is_huge_zero_pmd(orig_pmd)) { atomic_long_dec(&tlb->mm->nr_ptes); spin_unlock(ptl); put_huge_zero_page(); } else { - page = pmd_page(orig_pmd); + struct page *page = pmd_page(orig_pmd); page_remove_rmap(page); VM_BUG_ON_PAGE(page_mapcount(page) < 0, page); add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR); @@ -1448,7 +1457,8 @@ int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, spin_unlock(ptl); tlb_remove_page(tlb, page); } - pte_free(tlb->mm, pgtable); + if (pgtable) + pte_free(tlb->mm, pgtable); ret = 1; } return ret; @@ -2914,7 +2924,7 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address, pmd_t *pmd) { spinlock_t *ptl; - struct page *page; + struct page *page = NULL; struct mm_struct *mm = vma->vm_mm; unsigned long haddr = address & HPAGE_PMD_MASK; unsigned long mmun_start; /* For mmu_notifiers */ @@ -2927,25 +2937,25 @@ void __split_huge_page_pmd(struct vm_area_struct *vma, unsigned long address, again: mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end); ptl = pmd_lock(mm, pmd); - if (unlikely(!pmd_trans_huge(*pmd))) { - spin_unlock(ptl); - mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); - return; - } - if (is_huge_zero_pmd(*pmd)) { + if (unlikely(!pmd_trans_huge(*pmd))) + goto unlock; + if (vma_is_dax(vma)) { + pmdp_huge_clear_flush(vma, haddr, pmd); + } else if (is_huge_zero_pmd(*pmd)) { __split_huge_zero_page_pmd(vma, haddr, pmd); - spin_unlock(ptl); - mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); - return; + } else { + page = pmd_page(*pmd); + VM_BUG_ON_PAGE(!page_count(page), page); + get_page(page); } - page = pmd_page(*pmd); - VM_BUG_ON_PAGE(!page_count(page), page); - get_page(page); + unlock: spin_unlock(ptl); mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); - split_huge_page(page); + if (!page) + return; + split_huge_page(page); put_page(page); /* -- GitLab From b96375f74a6d4f39fc6cbdc0bce5175115c7f96f Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:58:48 -0700 Subject: [PATCH 6671/7006] mm: add a pmd_fault handler Allow non-anonymous VMAs to provide huge pages in response to a page fault. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 2 ++ mm/memory.c | 30 ++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index dfb7ce05f1e33..e1fbd18b8c4bb 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -249,6 +249,8 @@ struct vm_operations_struct { void (*close)(struct vm_area_struct * area); int (*mremap)(struct vm_area_struct * area); int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); + int (*pmd_fault)(struct vm_area_struct *, unsigned long address, + pmd_t *, unsigned int flags); void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf); /* notification that a previously read-only page is about to become diff --git a/mm/memory.c b/mm/memory.c index 882c9d7ae2f5f..a3f9a8ccec0f9 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3232,6 +3232,27 @@ out: return 0; } +static int create_huge_pmd(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, pmd_t *pmd, unsigned int flags) +{ + if (!vma->vm_ops) + return do_huge_pmd_anonymous_page(mm, vma, address, pmd, flags); + if (vma->vm_ops->pmd_fault) + return vma->vm_ops->pmd_fault(vma, address, pmd, flags); + return VM_FAULT_FALLBACK; +} + +static int wp_huge_pmd(struct mm_struct *mm, struct vm_area_struct *vma, + unsigned long address, pmd_t *pmd, pmd_t orig_pmd, + unsigned int flags) +{ + if (!vma->vm_ops) + return do_huge_pmd_wp_page(mm, vma, address, pmd, orig_pmd); + if (vma->vm_ops->pmd_fault) + return vma->vm_ops->pmd_fault(vma, address, pmd, flags); + return VM_FAULT_FALLBACK; +} + /* * These routines also need to handle stuff like marking pages dirty * and/or accessed for architectures that don't do it in hardware (most @@ -3334,10 +3355,7 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, if (!pmd) return VM_FAULT_OOM; if (pmd_none(*pmd) && transparent_hugepage_enabled(vma)) { - int ret = VM_FAULT_FALLBACK; - if (!vma->vm_ops) - ret = do_huge_pmd_anonymous_page(mm, vma, address, - pmd, flags); + int ret = create_huge_pmd(mm, vma, address, pmd, flags); if (!(ret & VM_FAULT_FALLBACK)) return ret; } else { @@ -3361,8 +3379,8 @@ static int __handle_mm_fault(struct mm_struct *mm, struct vm_area_struct *vma, orig_pmd, pmd); if (dirty && !pmd_write(orig_pmd)) { - ret = do_huge_pmd_wp_page(mm, vma, address, pmd, - orig_pmd); + ret = wp_huge_pmd(mm, vma, address, pmd, + orig_pmd, flags); if (!(ret & VM_FAULT_FALLBACK)) return ret; } else { -- GitLab From fc43704437ebe40f642ac53f7ee73661fe74e6b8 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:58:51 -0700 Subject: [PATCH 6672/7006] mm: export various functions for the benefit of DAX To use the huge zero page in DAX, we need these functions exported. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/huge_mm.h | 10 ++++++++++ mm/huge_memory.c | 7 +------ 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 1c53c7d7ef7e6..70587ea079c3a 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -155,6 +155,16 @@ static inline bool is_huge_zero_page(struct page *page) return ACCESS_ONCE(huge_zero_page) == page; } +static inline bool is_huge_zero_pmd(pmd_t pmd) +{ + return is_huge_zero_page(pmd_page(pmd)); +} + +struct page *get_huge_zero_page(void); +bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, + struct vm_area_struct *vma, unsigned long haddr, + pmd_t *pmd, struct page *zero_page); + #else /* CONFIG_TRANSPARENT_HUGEPAGE */ #define HPAGE_PMD_SHIFT ({ BUILD_BUG(); 0; }) #define HPAGE_PMD_MASK ({ BUILD_BUG(); 0; }) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 9057241d57224..c426a89e025c7 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -173,12 +173,7 @@ fail: static atomic_t huge_zero_refcount; struct page *huge_zero_page __read_mostly; -static inline bool is_huge_zero_pmd(pmd_t pmd) -{ - return is_huge_zero_page(pmd_page(pmd)); -} - -static struct page *get_huge_zero_page(void) +struct page *get_huge_zero_page(void) { struct page *zero_page; retry: -- GitLab From 5cad465d7fa646bad3d677df276bfc8e2ad709e3 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:58:54 -0700 Subject: [PATCH 6673/7006] mm: add vmf_insert_pfn_pmd() Similar to vm_insert_pfn(), but for PMDs rather than PTEs. The 'vmf_' prefix instead of 'vm_' prefix is intended to indicate that it returns a VMF_ value rather than an errno (which would only have to be converted into a VMF_ value anyway). Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/huge_mm.h | 2 ++ mm/huge_memory.c | 43 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index 70587ea079c3a..f9b612fec4dd8 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -33,6 +33,8 @@ extern int move_huge_pmd(struct vm_area_struct *vma, extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr, pgprot_t newprot, int prot_numa); +int vmf_insert_pfn_pmd(struct vm_area_struct *, unsigned long addr, pmd_t *, + unsigned long pfn, bool write); enum transparent_hugepage_flag { TRANSPARENT_HUGEPAGE_FLAG, diff --git a/mm/huge_memory.c b/mm/huge_memory.c index c426a89e025c7..3ea6f908a5e01 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -869,6 +869,49 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, flags); } +static int insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd, unsigned long pfn, pgprot_t prot, bool write) +{ + struct mm_struct *mm = vma->vm_mm; + pmd_t entry; + spinlock_t *ptl; + + ptl = pmd_lock(mm, pmd); + if (pmd_none(*pmd)) { + entry = pmd_mkhuge(pfn_pmd(pfn, prot)); + if (write) { + entry = pmd_mkyoung(pmd_mkdirty(entry)); + entry = maybe_pmd_mkwrite(entry, vma); + } + set_pmd_at(mm, addr, pmd, entry); + update_mmu_cache_pmd(vma, addr, pmd); + } + spin_unlock(ptl); + return VM_FAULT_NOPAGE; +} + +int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd, unsigned long pfn, bool write) +{ + pgprot_t pgprot = vma->vm_page_prot; + /* + * If we had pmd_special, we could avoid all these restrictions, + * but we need to be consistent with PTEs and architectures that + * can't support a 'special' bit. + */ + BUG_ON(!(vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP))); + BUG_ON((vma->vm_flags & (VM_PFNMAP|VM_MIXEDMAP)) == + (VM_PFNMAP|VM_MIXEDMAP)); + BUG_ON((vma->vm_flags & VM_PFNMAP) && is_cow_mapping(vma->vm_flags)); + BUG_ON((vma->vm_flags & VM_MIXEDMAP) && pfn_valid(pfn)); + + if (addr < vma->vm_start || addr >= vma->vm_end) + return VM_FAULT_SIGBUS; + if (track_pfn_insert(vma, &pgprot, pfn)) + return VM_FAULT_SIGBUS; + return insert_pfn_pmd(vma, addr, pmd, pfn, pgprot, write); +} + int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long addr, struct vm_area_struct *vma) -- GitLab From 844f35db1088dd1a9de37b53d4d823626232bd19 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:58:57 -0700 Subject: [PATCH 6674/7006] dax: add huge page fault support This is the support code for DAX-enabled filesystems to allow them to provide huge pages in response to faults. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/dax.txt | 7 +- fs/dax.c | 152 ++++++++++++++++++++++++++++++ include/linux/dax.h | 14 +++ 3 files changed, 170 insertions(+), 3 deletions(-) diff --git a/Documentation/filesystems/dax.txt b/Documentation/filesystems/dax.txt index 7af2851d667c7..7bde64014a897 100644 --- a/Documentation/filesystems/dax.txt +++ b/Documentation/filesystems/dax.txt @@ -60,9 +60,10 @@ Filesystem support consists of - implementing the direct_IO address space operation, and calling dax_do_io() instead of blockdev_direct_IO() if S_DAX is set - implementing an mmap file operation for DAX files which sets the - VM_MIXEDMAP flag on the VMA, and setting the vm_ops to include handlers - for fault and page_mkwrite (which should probably call dax_fault() and - dax_mkwrite(), passing the appropriate get_block() callback) + VM_MIXEDMAP and VM_HUGEPAGE flags on the VMA, and setting the vm_ops to + include handlers for fault, pmd_fault and page_mkwrite (which should + probably call dax_fault(), dax_pmd_fault() and dax_mkwrite(), passing the + appropriate get_block() callback) - calling dax_truncate_page() instead of block_truncate_page() for DAX files - calling dax_zero_page_range() instead of zero_user() for DAX files - ensuring that there is sufficient locking between reads, writes, diff --git a/fs/dax.c b/fs/dax.c index a7f77e1fa18c2..15f8ffc13fa6e 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -494,6 +494,158 @@ int dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, } EXPORT_SYMBOL_GPL(dax_fault); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +/* + * The 'colour' (ie low bits) within a PMD of a page offset. This comes up + * more often than one might expect in the below function. + */ +#define PG_PMD_COLOUR ((PMD_SIZE >> PAGE_SHIFT) - 1) + +int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmd, unsigned int flags, get_block_t get_block, + dax_iodone_t complete_unwritten) +{ + struct file *file = vma->vm_file; + struct address_space *mapping = file->f_mapping; + struct inode *inode = mapping->host; + struct buffer_head bh; + unsigned blkbits = inode->i_blkbits; + unsigned long pmd_addr = address & PMD_MASK; + bool write = flags & FAULT_FLAG_WRITE; + long length; + void *kaddr; + pgoff_t size, pgoff; + sector_t block, sector; + unsigned long pfn; + int result = 0; + + /* Fall back to PTEs if we're going to COW */ + if (write && !(vma->vm_flags & VM_SHARED)) + return VM_FAULT_FALLBACK; + /* If the PMD would extend outside the VMA */ + if (pmd_addr < vma->vm_start) + return VM_FAULT_FALLBACK; + if ((pmd_addr + PMD_SIZE) > vma->vm_end) + return VM_FAULT_FALLBACK; + + pgoff = ((pmd_addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (pgoff >= size) + return VM_FAULT_SIGBUS; + /* If the PMD would cover blocks out of the file */ + if ((pgoff | PG_PMD_COLOUR) >= size) + return VM_FAULT_FALLBACK; + + memset(&bh, 0, sizeof(bh)); + block = (sector_t)pgoff << (PAGE_SHIFT - blkbits); + + bh.b_size = PMD_SIZE; + length = get_block(inode, block, &bh, write); + if (length) + return VM_FAULT_SIGBUS; + i_mmap_lock_read(mapping); + + /* + * If the filesystem isn't willing to tell us the length of a hole, + * just fall back to PTEs. Calling get_block 512 times in a loop + * would be silly. + */ + if (!buffer_size_valid(&bh) || bh.b_size < PMD_SIZE) + goto fallback; + + /* Guard against a race with truncate */ + size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (pgoff >= size) { + result = VM_FAULT_SIGBUS; + goto out; + } + if ((pgoff | PG_PMD_COLOUR) >= size) + goto fallback; + + if (is_huge_zero_pmd(*pmd)) + unmap_mapping_range(mapping, pgoff << PAGE_SHIFT, PMD_SIZE, 0); + + if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) { + bool set; + spinlock_t *ptl; + struct mm_struct *mm = vma->vm_mm; + struct page *zero_page = get_huge_zero_page(); + if (unlikely(!zero_page)) + goto fallback; + + ptl = pmd_lock(mm, pmd); + set = set_huge_zero_page(NULL, mm, vma, pmd_addr, pmd, + zero_page); + spin_unlock(ptl); + result = VM_FAULT_NOPAGE; + } else { + sector = bh.b_blocknr << (blkbits - 9); + length = bdev_direct_access(bh.b_bdev, sector, &kaddr, &pfn, + bh.b_size); + if (length < 0) { + result = VM_FAULT_SIGBUS; + goto out; + } + if ((length < PMD_SIZE) || (pfn & PG_PMD_COLOUR)) + goto fallback; + + if (buffer_unwritten(&bh) || buffer_new(&bh)) { + int i; + for (i = 0; i < PTRS_PER_PMD; i++) + clear_page(kaddr + i * PAGE_SIZE); + count_vm_event(PGMAJFAULT); + mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); + result |= VM_FAULT_MAJOR; + } + + result |= vmf_insert_pfn_pmd(vma, address, pmd, pfn, write); + } + + out: + i_mmap_unlock_read(mapping); + + if (buffer_unwritten(&bh)) + complete_unwritten(&bh, !(result & VM_FAULT_ERROR)); + + return result; + + fallback: + count_vm_event(THP_FAULT_FALLBACK); + result = VM_FAULT_FALLBACK; + goto out; +} +EXPORT_SYMBOL_GPL(__dax_pmd_fault); + +/** + * dax_pmd_fault - handle a PMD fault on a DAX file + * @vma: The virtual memory area where the fault occurred + * @vmf: The description of the fault + * @get_block: The filesystem method used to translate file offsets to blocks + * + * When a page fault occurs, filesystems may call this helper in their + * pmd_fault handler for DAX files. + */ +int dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, + pmd_t *pmd, unsigned int flags, get_block_t get_block, + dax_iodone_t complete_unwritten) +{ + int result; + struct super_block *sb = file_inode(vma->vm_file)->i_sb; + + if (flags & FAULT_FLAG_WRITE) { + sb_start_pagefault(sb); + file_update_time(vma->vm_file); + } + result = __dax_pmd_fault(vma, address, pmd, flags, get_block, + complete_unwritten); + if (flags & FAULT_FLAG_WRITE) + sb_end_pagefault(sb); + + return result; +} +EXPORT_SYMBOL_GPL(dax_pmd_fault); +#endif /* CONFIG_TRANSPARENT_HUGEPAGES */ + /** * dax_pfn_mkwrite - handle first write to DAX page * @vma: The virtual memory area where the fault occurred diff --git a/include/linux/dax.h b/include/linux/dax.h index 9b51f9d40ad96..b415e521528de 100644 --- a/include/linux/dax.h +++ b/include/linux/dax.h @@ -14,6 +14,20 @@ int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, dax_iodone_t); int __dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t, dax_iodone_t); +#ifdef CONFIG_TRANSPARENT_HUGEPAGE +int dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *, + unsigned int flags, get_block_t, dax_iodone_t); +int __dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *, + unsigned int flags, get_block_t, dax_iodone_t); +#else +static inline int dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd, unsigned int flags, get_block_t gb, + dax_iodone_t di) +{ + return VM_FAULT_FALLBACK; +} +#define __dax_pmd_fault dax_pmd_fault +#endif int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); #define dax_mkwrite(vma, vmf, gb, iod) dax_fault(vma, vmf, gb, iod) #define __dax_mkwrite(vma, vmf, gb, iod) __dax_fault(vma, vmf, gb, iod) -- GitLab From e7b1ea2ad6581b83f63246db48aa2c2c9bf2ec8d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:00 -0700 Subject: [PATCH 6675/7006] ext2: huge page fault support Use DAX to provide support for huge pages. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext2/file.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/ext2/file.c b/fs/ext2/file.c index db4c299b7cf67..1982c3f11aec4 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -32,6 +32,12 @@ static int ext2_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return dax_fault(vma, vmf, ext2_get_block, NULL); } +static int ext2_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd, unsigned int flags) +{ + return dax_pmd_fault(vma, addr, pmd, flags, ext2_get_block, NULL); +} + static int ext2_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { return dax_mkwrite(vma, vmf, ext2_get_block, NULL); @@ -39,6 +45,7 @@ static int ext2_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) static const struct vm_operations_struct ext2_dax_vm_ops = { .fault = ext2_dax_fault, + .pmd_fault = ext2_dax_pmd_fault, .page_mkwrite = ext2_dax_mkwrite, .pfn_mkwrite = dax_pfn_mkwrite, }; @@ -50,7 +57,7 @@ static int ext2_file_mmap(struct file *file, struct vm_area_struct *vma) file_accessed(file); vma->vm_ops = &ext2_dax_vm_ops; - vma->vm_flags |= VM_MIXEDMAP; + vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; return 0; } #else -- GitLab From 11bd1a9ecdd687b8a4b9b360b7e4b74a1a5e2bd5 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:03 -0700 Subject: [PATCH 6676/7006] ext4: huge page fault support Use DAX to provide support for huge pages. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/file.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index f8a631047379b..953d519e799c0 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -211,6 +211,13 @@ static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Is this the right get_block? */ } +static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, + pmd_t *pmd, unsigned int flags) +{ + return dax_pmd_fault(vma, addr, pmd, flags, ext4_get_block_write, + ext4_end_io_unwritten); +} + static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { return dax_mkwrite(vma, vmf, ext4_get_block, ext4_end_io_unwritten); @@ -218,6 +225,7 @@ static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) static const struct vm_operations_struct ext4_dax_vm_ops = { .fault = ext4_dax_fault, + .pmd_fault = ext4_dax_pmd_fault, .page_mkwrite = ext4_dax_mkwrite, .pfn_mkwrite = dax_pfn_mkwrite, }; @@ -245,7 +253,7 @@ static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) file_accessed(file); if (IS_DAX(file_inode(file))) { vma->vm_ops = &ext4_dax_vm_ops; - vma->vm_flags |= VM_MIXEDMAP; + vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; } else { vma->vm_ops = &ext4_file_vm_ops; } -- GitLab From acd76e74d80f961553861d9cf49a62cbcf496d28 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:06 -0700 Subject: [PATCH 6677/7006] xfs: huge page fault support Use DAX to provide support for huge pages. Signed-off-by: Matthew Wilcox Cc: Hillf Danton Cc: "Kirill A. Shutemov" Cc: Theodore Ts'o Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/xfs/xfs_file.c | 30 +++++++++++++++++++++++++++++- fs/xfs/xfs_trace.h | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index de2c2376242bc..e78feb400e22b 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -1546,8 +1546,36 @@ xfs_filemap_fault( return ret; } +STATIC int +xfs_filemap_pmd_fault( + struct vm_area_struct *vma, + unsigned long addr, + pmd_t *pmd, + unsigned int flags) +{ + struct inode *inode = file_inode(vma->vm_file); + struct xfs_inode *ip = XFS_I(inode); + int ret; + + if (!IS_DAX(inode)) + return VM_FAULT_FALLBACK; + + trace_xfs_filemap_pmd_fault(ip); + + sb_start_pagefault(inode->i_sb); + file_update_time(vma->vm_file); + xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED); + ret = __dax_pmd_fault(vma, addr, pmd, flags, xfs_get_blocks_direct, + xfs_end_io_dax_write); + xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED); + sb_end_pagefault(inode->i_sb); + + return ret; +} + static const struct vm_operations_struct xfs_file_vm_ops = { .fault = xfs_filemap_fault, + .pmd_fault = xfs_filemap_pmd_fault, .map_pages = filemap_map_pages, .page_mkwrite = xfs_filemap_page_mkwrite, }; @@ -1560,7 +1588,7 @@ xfs_file_mmap( file_accessed(filp); vma->vm_ops = &xfs_file_vm_ops; if (IS_DAX(file_inode(filp))) - vma->vm_flags |= VM_MIXEDMAP; + vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; return 0; } diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h index 9aeeb21bc3d01..5ed36b1e04c1a 100644 --- a/fs/xfs/xfs_trace.h +++ b/fs/xfs/xfs_trace.h @@ -687,6 +687,7 @@ DEFINE_INODE_EVENT(xfs_inode_clear_eofblocks_tag); DEFINE_INODE_EVENT(xfs_inode_free_eofblocks_invalid); DEFINE_INODE_EVENT(xfs_filemap_fault); +DEFINE_INODE_EVENT(xfs_filemap_pmd_fault); DEFINE_INODE_EVENT(xfs_filemap_page_mkwrite); DECLARE_EVENT_CLASS(xfs_iref_class, -- GitLab From dd8a2b6c29a3221c19ab475c8408fc2b914ccfab Mon Sep 17 00:00:00 2001 From: Valentin Rothberg Date: Tue, 8 Sep 2015 14:59:09 -0700 Subject: [PATCH 6678/7006] fs/dax.c: fix typo in #endif comment Fix typo s/CONFIG_TRANSPARENT_HUGEPAGES/CONFIG_TRANSPARENT_HUGEPAGE/ in #endif comment introduced by commit 2b26a9206d6a ("dax: add huge page fault support"). Signed-off-by: Valentin Rothberg Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dax.c b/fs/dax.c index 15f8ffc13fa6e..2deed64b7eea7 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -644,7 +644,7 @@ int dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, return result; } EXPORT_SYMBOL_GPL(dax_pmd_fault); -#endif /* CONFIG_TRANSPARENT_HUGEPAGES */ +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ /** * dax_pfn_mkwrite - handle first write to DAX page -- GitLab From e676a4c191653787c3fe851fe3b9f1f33d49dac2 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:11 -0700 Subject: [PATCH 6679/7006] ext4: use ext4_get_block_write() for DAX DAX relies on the get_block function either zeroing newly allocated blocks before they're findable by subsequent calls to get_block, or marking newly allocated blocks as unwritten. ext4_get_block() cannot create unwritten extents, but ext4_get_block_write() can. Signed-off-by: Matthew Wilcox Reported-by: Andy Rudoff Cc: Theodore Ts'o Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 953d519e799c0..ca5302a256ead 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -196,7 +196,7 @@ out: static void ext4_end_io_unwritten(struct buffer_head *bh, int uptodate) { struct inode *inode = bh->b_assoc_map->host; - /* XXX: breaks on 32-bit > 16GB. Is that even supported? */ + /* XXX: breaks on 32-bit > 16TB. Is that even supported? */ loff_t offset = (loff_t)(uintptr_t)bh->b_private << inode->i_blkbits; int err; if (!uptodate) @@ -207,8 +207,7 @@ static void ext4_end_io_unwritten(struct buffer_head *bh, int uptodate) static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - return dax_fault(vma, vmf, ext4_get_block, ext4_end_io_unwritten); - /* Is this the right get_block? */ + return dax_fault(vma, vmf, ext4_get_block_write, ext4_end_io_unwritten); } static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, @@ -220,7 +219,8 @@ static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { - return dax_mkwrite(vma, vmf, ext4_get_block, ext4_end_io_unwritten); + return dax_mkwrite(vma, vmf, ext4_get_block_write, + ext4_end_io_unwritten); } static const struct vm_operations_struct ext4_dax_vm_ops = { -- GitLab From ae18d6dcf57b56b984ff27fd55b4e2caf5bfbd44 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:14 -0700 Subject: [PATCH 6680/7006] thp: change insert_pfn's return type to void It would make more sense to have all the return values from vmf_insert_pfn_pmd() encoded in one place instead of having to follow the convention into insert_pfn(). Suggested by Jeff Moyer. Signed-off-by: Matthew Wilcox Cc: Jeff Moyer Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 3ea6f908a5e01..5df0d1597c15e 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -869,7 +869,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma, flags); } -static int insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, +static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd, unsigned long pfn, pgprot_t prot, bool write) { struct mm_struct *mm = vma->vm_mm; @@ -887,7 +887,6 @@ static int insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, update_mmu_cache_pmd(vma, addr, pmd); } spin_unlock(ptl); - return VM_FAULT_NOPAGE; } int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, @@ -909,7 +908,8 @@ int vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr, return VM_FAULT_SIGBUS; if (track_pfn_insert(vma, &pgprot, pfn)) return VM_FAULT_SIGBUS; - return insert_pfn_pmd(vma, addr, pmd, pfn, pgprot, write); + insert_pfn_pmd(vma, addr, pmd, pfn, pgprot, write); + return VM_FAULT_NOPAGE; } int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, -- GitLab From 84c4e5e675408b6fb7d74eec7da9a4a5698b50af Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:17 -0700 Subject: [PATCH 6681/7006] dax: improve comment about truncate race Jan Kara pointed out I should be more explicit here about the perils of racing against truncate. The comment is mostly the same as for the PTE case. Signed-off-by: Matthew Wilcox Cc: Jan Kara Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs/dax.c b/fs/dax.c index 2deed64b7eea7..c694117a70620 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -553,7 +553,12 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if (!buffer_size_valid(&bh) || bh.b_size < PMD_SIZE) goto fallback; - /* Guard against a race with truncate */ + /* + * If a truncate happened while we were allocating blocks, we may + * leave blocks allocated to the file that are beyond EOF. We can't + * take i_mutex here, so just leave them hanging; they'll be freed + * when the file is deleted. + */ size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; if (pgoff >= size) { result = VM_FAULT_SIGBUS; -- GitLab From ed923b5776a2d2e949bd5b20f3956d68f3c826b7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:20 -0700 Subject: [PATCH 6682/7006] ext4: add ext4_get_block_dax() DAX wants different semantics from any currently-existing ext4 get_block callback. Unlike ext4_get_block_write(), it needs to honour the 'create' flag, and unlike ext4_get_block(), it needs to be able to return unwritten extents. So introduce a new ext4_get_block_dax() which has those semantics. We could also change ext4_get_block_write() to honour the 'create' flag, but that might have consequences on other users that I do not currently understand. Signed-off-by: Matthew Wilcox Cc: Theodore Ts'o Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/ext4.h | 2 ++ fs/ext4/file.c | 6 +++--- fs/ext4/inode.c | 11 +++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 32071f5c1c262..fd1f28be52969 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -2272,6 +2272,8 @@ struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int); struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int); int ext4_get_block_write(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); +int ext4_get_block_dax(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create); int ext4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create); int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, diff --git a/fs/ext4/file.c b/fs/ext4/file.c index ca5302a256ead..d5219e4cd91de 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -207,19 +207,19 @@ static void ext4_end_io_unwritten(struct buffer_head *bh, int uptodate) static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - return dax_fault(vma, vmf, ext4_get_block_write, ext4_end_io_unwritten); + return dax_fault(vma, vmf, ext4_get_block_dax, ext4_end_io_unwritten); } static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd, unsigned int flags) { - return dax_pmd_fault(vma, addr, pmd, flags, ext4_get_block_write, + return dax_pmd_fault(vma, addr, pmd, flags, ext4_get_block_dax, ext4_end_io_unwritten); } static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) { - return dax_mkwrite(vma, vmf, ext4_get_block_write, + return dax_mkwrite(vma, vmf, ext4_get_block_dax, ext4_end_io_unwritten); } diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 5ebcc7683a5c1..612fbcf76b5c4 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3021,6 +3021,17 @@ static int ext4_get_block_write_nolock(struct inode *inode, sector_t iblock, EXT4_GET_BLOCKS_NO_LOCK); } +int ext4_get_block_dax(struct inode *inode, sector_t iblock, + struct buffer_head *bh_result, int create) +{ + int flags = EXT4_GET_BLOCKS_PRE_IO | EXT4_GET_BLOCKS_UNWRIT_EXT; + if (create) + flags |= EXT4_GET_BLOCKS_CREATE; + ext4_debug("ext4_get_block_dax: inode %lu, create flag %d\n", + inode->i_ino, create); + return _ext4_get_block(inode, iblock, bh_result, flags); +} + static void ext4_end_io_dio(struct kiocb *iocb, loff_t offset, ssize_t size, void *private) { -- GitLab From 01a33b4ace68bc35679a347f21d5ed6e222e30dc Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:22 -0700 Subject: [PATCH 6683/7006] ext4: start transaction before calling into DAX Jan Kara pointed out that in the case where we are writing to a hole, we can end up with a lock inversion between the page lock and the journal lock. We can avoid this by starting the transaction in ext4 before calling into DAX. The journal lock nests inside the superblock pagefault lock, so we have to duplicate that code from dax_fault, like XFS does. Signed-off-by: Matthew Wilcox Cc: Jan Kara Cc: Theodore Ts'o Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ext4/file.c | 55 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/fs/ext4/file.c b/fs/ext4/file.c index d5219e4cd91de..113837e7ba98d 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -207,14 +207,63 @@ static void ext4_end_io_unwritten(struct buffer_head *bh, int uptodate) static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { - return dax_fault(vma, vmf, ext4_get_block_dax, ext4_end_io_unwritten); + int result; + handle_t *handle = NULL; + struct super_block *sb = file_inode(vma->vm_file)->i_sb; + bool write = vmf->flags & FAULT_FLAG_WRITE; + + if (write) { + sb_start_pagefault(sb); + file_update_time(vma->vm_file); + handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, + EXT4_DATA_TRANS_BLOCKS(sb)); + } + + if (IS_ERR(handle)) + result = VM_FAULT_SIGBUS; + else + result = __dax_fault(vma, vmf, ext4_get_block_dax, + ext4_end_io_unwritten); + + if (write) { + if (!IS_ERR(handle)) + ext4_journal_stop(handle); + sb_end_pagefault(sb); + } + + return result; } static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, pmd_t *pmd, unsigned int flags) { - return dax_pmd_fault(vma, addr, pmd, flags, ext4_get_block_dax, - ext4_end_io_unwritten); + int result; + handle_t *handle = NULL; + struct inode *inode = file_inode(vma->vm_file); + struct super_block *sb = inode->i_sb; + bool write = flags & FAULT_FLAG_WRITE; + + if (write) { + sb_start_pagefault(sb); + file_update_time(vma->vm_file); + handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, + ext4_chunk_trans_blocks(inode, + PMD_SIZE / PAGE_SIZE)); + } + + if (IS_ERR(handle)) + result = VM_FAULT_SIGBUS; + else + result = __dax_pmd_fault(vma, addr, pmd, flags, + ext4_get_block_dax, ext4_end_io_unwritten); + + if (write) { + if (!IS_ERR(handle)) + ext4_journal_stop(handle); + sb_end_pagefault(sb); + } + + return result; } static int ext4_dax_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) -- GitLab From 843172978bb92997310d2f7fbc172ece423cfc02 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:25 -0700 Subject: [PATCH 6684/7006] dax: fix race between simultaneous faults If two threads write-fault on the same hole at the same time, the winner of the race will return to userspace and complete their store, only to have the loser overwrite their store with zeroes. Fix this for now by taking the i_mmap_sem for write instead of read, and do so outside the call to get_block(). Now the loser of the race will see the block has already been zeroed, and will not zero it again. This severely limits our scalability. I have ideas for improving it, but those can wait for a later patch. Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 33 +++++++++++++++++---------------- mm/memory.c | 11 ++++++++--- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index c694117a70620..9593f4bee3277 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -272,7 +272,6 @@ static int copy_user_bh(struct page *to, struct buffer_head *bh, static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh, struct vm_area_struct *vma, struct vm_fault *vmf) { - struct address_space *mapping = inode->i_mapping; sector_t sector = bh->b_blocknr << (inode->i_blkbits - 9); unsigned long vaddr = (unsigned long)vmf->virtual_address; void *addr; @@ -280,8 +279,6 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh, pgoff_t size; int error; - i_mmap_lock_read(mapping); - /* * Check truncate didn't happen while we were allocating a block. * If it did, this block may or may not be still allocated to the @@ -309,8 +306,6 @@ static int dax_insert_mapping(struct inode *inode, struct buffer_head *bh, error = vm_insert_mixed(vma, vaddr, pfn); out: - i_mmap_unlock_read(mapping); - return error; } @@ -372,15 +367,17 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, * from a read fault and we've raced with a truncate */ error = -EIO; - goto unlock_page; + goto unlock; } + } else { + i_mmap_lock_write(mapping); } error = get_block(inode, block, &bh, 0); if (!error && (bh.b_size < PAGE_SIZE)) error = -EIO; /* fs corruption? */ if (error) - goto unlock_page; + goto unlock; if (!buffer_mapped(&bh) && !buffer_unwritten(&bh) && !vmf->cow_page) { if (vmf->flags & FAULT_FLAG_WRITE) { @@ -391,8 +388,9 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, if (!error && (bh.b_size < PAGE_SIZE)) error = -EIO; if (error) - goto unlock_page; + goto unlock; } else { + i_mmap_unlock_write(mapping); return dax_load_hole(mapping, page, vmf); } } @@ -404,17 +402,15 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, else clear_user_highpage(new_page, vaddr); if (error) - goto unlock_page; + goto unlock; vmf->page = page; if (!page) { - i_mmap_lock_read(mapping); /* Check we didn't race with truncate */ size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; if (vmf->pgoff >= size) { - i_mmap_unlock_read(mapping); error = -EIO; - goto out; + goto unlock; } } return VM_FAULT_LOCKED; @@ -450,6 +446,8 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, WARN_ON_ONCE(!(vmf->flags & FAULT_FLAG_WRITE)); } + if (!page) + i_mmap_unlock_write(mapping); out: if (error == -ENOMEM) return VM_FAULT_OOM | major; @@ -458,11 +456,14 @@ int __dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, return VM_FAULT_SIGBUS | major; return VM_FAULT_NOPAGE | major; - unlock_page: + unlock: if (page) { unlock_page(page); page_cache_release(page); + } else { + i_mmap_unlock_write(mapping); } + goto out; } EXPORT_SYMBOL(__dax_fault); @@ -540,10 +541,10 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, block = (sector_t)pgoff << (PAGE_SHIFT - blkbits); bh.b_size = PMD_SIZE; + i_mmap_lock_write(mapping); length = get_block(inode, block, &bh, write); if (length) return VM_FAULT_SIGBUS; - i_mmap_lock_read(mapping); /* * If the filesystem isn't willing to tell us the length of a hole, @@ -607,11 +608,11 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, } out: - i_mmap_unlock_read(mapping); - if (buffer_unwritten(&bh)) complete_unwritten(&bh, !(result & VM_FAULT_ERROR)); + i_mmap_unlock_write(mapping); + return result; fallback: diff --git a/mm/memory.c b/mm/memory.c index a3f9a8ccec0f9..320c42e95e695 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2427,11 +2427,16 @@ void unmap_mapping_range(struct address_space *mapping, details.last_index = ULONG_MAX; - /* DAX uses i_mmap_lock to serialise file truncate vs page fault */ - i_mmap_lock_write(mapping); + /* + * DAX already holds i_mmap_lock to serialise file truncate vs + * page fault and page fault vs page fault. + */ + if (!IS_DAX(mapping->host)) + i_mmap_lock_write(mapping); if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) unmap_mapping_range_tree(&mapping->i_mmap, &details); - i_mmap_unlock_write(mapping); + if (!IS_DAX(mapping->host)) + i_mmap_unlock_write(mapping); } EXPORT_SYMBOL(unmap_mapping_range); -- GitLab From 5b701b846aad7909d20693bcced2522d0ce8d1bc Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 14:59:28 -0700 Subject: [PATCH 6685/7006] thp: decrement refcount on huge zero page if it is split The DAX code neglected to put the refcount on the huge zero page. Also we must notify on splits. Signed-off-by: Kirill A. Shutemov Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 5df0d1597c15e..7510b6f683e97 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2978,7 +2978,9 @@ again: if (unlikely(!pmd_trans_huge(*pmd))) goto unlock; if (vma_is_dax(vma)) { - pmdp_huge_clear_flush(vma, haddr, pmd); + pmd_t _pmd = pmdp_huge_clear_flush_notify(vma, haddr, pmd); + if (is_huge_zero_pmd(_pmd)) + put_huge_zero_page(); } else if (is_huge_zero_pmd(*pmd)) { __split_huge_zero_page_pmd(vma, haddr, pmd); } else { -- GitLab From da146769004e1dd5ed06853e6d009be8ca675d5f Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 14:59:31 -0700 Subject: [PATCH 6686/7006] thp: fix zap_huge_pmd() for DAX The original DAX code assumed that pgtable_t was a pointer, which isn't true on all architectures. Restructure the code to not rely on that assumption. [willy@linux.intel.com: further fixes integrated into this patch] Signed-off-by: Kirill A. Shutemov Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 71 +++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 7510b6f683e97..96dfd9d81fcb2 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -1456,50 +1456,41 @@ out: int zap_huge_pmd(struct mmu_gather *tlb, struct vm_area_struct *vma, pmd_t *pmd, unsigned long addr) { + pmd_t orig_pmd; spinlock_t *ptl; - int ret = 0; - if (__pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { - pgtable_t pgtable; - pmd_t orig_pmd; - /* - * For architectures like ppc64 we look at deposited pgtable - * when calling pmdp_huge_get_and_clear. So do the - * pgtable_trans_huge_withdraw after finishing pmdp related - * operations. - */ - orig_pmd = pmdp_huge_get_and_clear_full(tlb->mm, addr, pmd, - tlb->fullmm); - tlb_remove_pmd_tlb_entry(tlb, pmd, addr); - if (vma_is_dax(vma)) { - if (is_huge_zero_pmd(orig_pmd)) { - pgtable = NULL; - } else { - spin_unlock(ptl); - return 1; - } - } else { - pgtable = pgtable_trans_huge_withdraw(tlb->mm, pmd); - } - if (is_huge_zero_pmd(orig_pmd)) { - atomic_long_dec(&tlb->mm->nr_ptes); - spin_unlock(ptl); + if (__pmd_trans_huge_lock(pmd, vma, &ptl) != 1) + return 0; + /* + * For architectures like ppc64 we look at deposited pgtable + * when calling pmdp_huge_get_and_clear. So do the + * pgtable_trans_huge_withdraw after finishing pmdp related + * operations. + */ + orig_pmd = pmdp_huge_get_and_clear_full(tlb->mm, addr, pmd, + tlb->fullmm); + tlb_remove_pmd_tlb_entry(tlb, pmd, addr); + if (vma_is_dax(vma)) { + spin_unlock(ptl); + if (is_huge_zero_pmd(orig_pmd)) put_huge_zero_page(); - } else { - struct page *page = pmd_page(orig_pmd); - page_remove_rmap(page); - VM_BUG_ON_PAGE(page_mapcount(page) < 0, page); - add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR); - VM_BUG_ON_PAGE(!PageHead(page), page); - atomic_long_dec(&tlb->mm->nr_ptes); - spin_unlock(ptl); - tlb_remove_page(tlb, page); - } - if (pgtable) - pte_free(tlb->mm, pgtable); - ret = 1; + } else if (is_huge_zero_pmd(orig_pmd)) { + pte_free(tlb->mm, pgtable_trans_huge_withdraw(tlb->mm, pmd)); + atomic_long_dec(&tlb->mm->nr_ptes); + spin_unlock(ptl); + put_huge_zero_page(); + } else { + struct page *page = pmd_page(orig_pmd); + page_remove_rmap(page); + VM_BUG_ON_PAGE(page_mapcount(page) < 0, page); + add_mm_counter(tlb->mm, MM_ANONPAGES, -HPAGE_PMD_NR); + VM_BUG_ON_PAGE(!PageHead(page), page); + pte_free(tlb->mm, pgtable_trans_huge_withdraw(tlb->mm, pmd)); + atomic_long_dec(&tlb->mm->nr_ptes); + spin_unlock(ptl); + tlb_remove_page(tlb, page); } - return ret; + return 1; } int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma, -- GitLab From d295e3415a88ae63a37a22652808b20c7fcb970e Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 14:59:34 -0700 Subject: [PATCH 6687/7006] dax: don't use set_huge_zero_page() This is another place where DAX assumed that pgtable_t was a pointer. Open code the important parts of set_huge_zero_page() in DAX and make set_huge_zero_page() static again. Signed-off-by: Kirill A. Shutemov Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 18 ++++++++++++------ include/linux/huge_mm.h | 3 --- mm/huge_memory.c | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index 9593f4bee3277..d778e5f1a01cf 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -572,18 +572,24 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, unmap_mapping_range(mapping, pgoff << PAGE_SHIFT, PMD_SIZE, 0); if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) { - bool set; spinlock_t *ptl; - struct mm_struct *mm = vma->vm_mm; + pmd_t entry; struct page *zero_page = get_huge_zero_page(); + if (unlikely(!zero_page)) goto fallback; - ptl = pmd_lock(mm, pmd); - set = set_huge_zero_page(NULL, mm, vma, pmd_addr, pmd, - zero_page); - spin_unlock(ptl); + ptl = pmd_lock(vma->vm_mm, pmd); + if (!pmd_none(*pmd)) { + spin_unlock(ptl); + goto fallback; + } + + entry = mk_pmd(zero_page, vma->vm_page_prot); + entry = pmd_mkhuge(entry); + set_pmd_at(vma->vm_mm, pmd_addr, pmd, entry); result = VM_FAULT_NOPAGE; + spin_unlock(ptl); } else { sector = bh.b_blocknr << (blkbits - 9); length = bdev_direct_access(bh.b_bdev, sector, &kaddr, &pfn, diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h index f9b612fec4dd8..ecb080d6ff420 100644 --- a/include/linux/huge_mm.h +++ b/include/linux/huge_mm.h @@ -163,9 +163,6 @@ static inline bool is_huge_zero_pmd(pmd_t pmd) } struct page *get_huge_zero_page(void); -bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, - struct vm_area_struct *vma, unsigned long haddr, - pmd_t *pmd, struct page *zero_page); #else /* CONFIG_TRANSPARENT_HUGEPAGE */ #define HPAGE_PMD_SHIFT ({ BUILD_BUG(); 0; }) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 96dfd9d81fcb2..3e574efad8f85 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -790,7 +790,7 @@ static inline gfp_t alloc_hugepage_gfpmask(int defrag, gfp_t extra_gfp) } /* Caller must hold page table lock. */ -bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, +static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm, struct vm_area_struct *vma, unsigned long haddr, pmd_t *pmd, struct page *zero_page) { -- GitLab From 73a6ec47f68787df1b41869def52915da2f4a6b7 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:37 -0700 Subject: [PATCH 6688/7006] dax: ensure that zero pages are removed from other processes If the first access to a huge page was a store, there would be no existing zero pmd in this process's page tables. There could be a zero pmd in another process's page tables, if it had done a load. We can detect this case by noticing that the buffer_head returned from the filesystem is New, and ensure that other processes mapping this huge page have their page tables flushed. Signed-off-by: Matthew Wilcox Reported-by: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs/dax.c b/fs/dax.c index d778e5f1a01cf..74838c43be910 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -568,7 +568,11 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if ((pgoff | PG_PMD_COLOUR) >= size) goto fallback; - if (is_huge_zero_pmd(*pmd)) + /* + * If we allocated new storage, make sure no process has any + * zero pages covering this hole + */ + if (buffer_new(&bh)) unmap_mapping_range(mapping, pgoff << PAGE_SHIFT, PMD_SIZE, 0); if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) { -- GitLab From 3fdd1b479dbc03347e98f904f54133a9cef5521f Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 8 Sep 2015 14:59:39 -0700 Subject: [PATCH 6689/7006] dax: use linear_page_index() I was basically open-coding it (thanks to copying code from do_fault() which probably also needs to be fixed). Signed-off-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dax.c b/fs/dax.c index 74838c43be910..9ef9b80cc1323 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -529,7 +529,7 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if ((pmd_addr + PMD_SIZE) > vma->vm_end) return VM_FAULT_FALLBACK; - pgoff = ((pmd_addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; + pgoff = linear_page_index(vma, pmd_addr); size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; if (pgoff >= size) return VM_FAULT_SIGBUS; -- GitLab From 46c043ede4711e8d598b9d63c5616c1fedb0605e Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 14:59:42 -0700 Subject: [PATCH 6690/7006] mm: take i_mmap_lock in unmap_mapping_range() for DAX DAX is not so special: we need i_mmap_lock to protect mapping->i_mmap. __dax_pmd_fault() uses unmap_mapping_range() shoot out zero page from all mappings. We need to drop i_mmap_lock there to avoid lock deadlock. Re-aquiring the lock should be fine since we check i_size after the point. Signed-off-by: Kirill A. Shutemov Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/dax.c | 35 +++++++++++++++++++---------------- mm/memory.c | 11 ++--------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index 9ef9b80cc1323..ed54efedade62 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -554,6 +554,25 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if (!buffer_size_valid(&bh) || bh.b_size < PMD_SIZE) goto fallback; + if (buffer_unwritten(&bh) || buffer_new(&bh)) { + int i; + for (i = 0; i < PTRS_PER_PMD; i++) + clear_page(kaddr + i * PAGE_SIZE); + count_vm_event(PGMAJFAULT); + mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); + result |= VM_FAULT_MAJOR; + } + + /* + * If we allocated new storage, make sure no process has any + * zero pages covering this hole + */ + if (buffer_new(&bh)) { + i_mmap_unlock_write(mapping); + unmap_mapping_range(mapping, pgoff << PAGE_SHIFT, PMD_SIZE, 0); + i_mmap_lock_write(mapping); + } + /* * If a truncate happened while we were allocating blocks, we may * leave blocks allocated to the file that are beyond EOF. We can't @@ -568,13 +587,6 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if ((pgoff | PG_PMD_COLOUR) >= size) goto fallback; - /* - * If we allocated new storage, make sure no process has any - * zero pages covering this hole - */ - if (buffer_new(&bh)) - unmap_mapping_range(mapping, pgoff << PAGE_SHIFT, PMD_SIZE, 0); - if (!write && !buffer_mapped(&bh) && buffer_uptodate(&bh)) { spinlock_t *ptl; pmd_t entry; @@ -605,15 +617,6 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if ((length < PMD_SIZE) || (pfn & PG_PMD_COLOUR)) goto fallback; - if (buffer_unwritten(&bh) || buffer_new(&bh)) { - int i; - for (i = 0; i < PTRS_PER_PMD; i++) - clear_page(kaddr + i * PAGE_SIZE); - count_vm_event(PGMAJFAULT); - mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); - result |= VM_FAULT_MAJOR; - } - result |= vmf_insert_pfn_pmd(vma, address, pmd, pfn, write); } diff --git a/mm/memory.c b/mm/memory.c index 320c42e95e695..ce8e983f3c4db 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2426,17 +2426,10 @@ void unmap_mapping_range(struct address_space *mapping, if (details.last_index < details.first_index) details.last_index = ULONG_MAX; - - /* - * DAX already holds i_mmap_lock to serialise file truncate vs - * page fault and page fault vs page fault. - */ - if (!IS_DAX(mapping->host)) - i_mmap_lock_write(mapping); + i_mmap_lock_write(mapping); if (unlikely(!RB_EMPTY_ROOT(&mapping->i_mmap))) unmap_mapping_range_tree(&mapping->i_mmap, &details); - if (!IS_DAX(mapping->host)) - i_mmap_unlock_write(mapping); + i_mmap_unlock_write(mapping); } EXPORT_SYMBOL(unmap_mapping_range); -- GitLab From 52a2b53ffde6d6018dfc454fbde34383351fb896 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 14:59:45 -0700 Subject: [PATCH 6691/7006] mm, dax: use i_mmap_unlock_write() in do_cow_fault() __dax_fault() takes i_mmap_lock for write. Let's pair it with write unlock on do_cow_fault() side. Signed-off-by: Kirill A. Shutemov Acked-by: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index ce8e983f3c4db..6cd0b21604019 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3013,9 +3013,9 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma, } else { /* * The fault handler has no page to lock, so it holds - * i_mmap_lock for read to protect against truncate. + * i_mmap_lock for write to protect against truncate. */ - i_mmap_unlock_read(vma->vm_file->f_mapping); + i_mmap_unlock_write(vma->vm_file->f_mapping); } goto uncharge_out; } @@ -3029,9 +3029,9 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma, } else { /* * The fault handler has no page to lock, so it holds - * i_mmap_lock for read to protect against truncate. + * i_mmap_lock for write to protect against truncate. */ - i_mmap_unlock_read(vma->vm_file->f_mapping); + i_mmap_unlock_write(vma->vm_file->f_mapping); } return ret; uncharge_out: -- GitLab From 904a9553d4fcdc0c7d5621f6178f0e07598701dc Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 8 Sep 2015 14:59:48 -0700 Subject: [PATCH 6692/7006] mm/page_alloc.c: refine the calculation of highest possible node id nr_node_ids records the highest possible node id, which is calculated by scanning the bitmap node_states[N_POSSIBLE]. Current implementation scan the bitmap from the beginning, which will scan the whole bitmap. This patch reverses the order by scanning from the end with find_last_bit(). Signed-off-by: Wei Yang Cc: Tejun Heo Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5b5240b7f642d..809e27e77b3a3 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5478,11 +5478,9 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, */ void __init setup_nr_node_ids(void) { - unsigned int node; - unsigned int highest = 0; + unsigned int highest; - for_each_node_mask(node, node_possible_map) - highest = node; + highest = find_last_bit(node_possible_map.bits, MAX_NUMNODES); nr_node_ids = highest + 1; } #endif -- GitLab From 7f3eb55bfad8a6dfd880559210f5b21737d69815 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 8 Sep 2015 14:59:50 -0700 Subject: [PATCH 6693/7006] mm/page_alloc.c: remove unused variable in free_area_init_core() Commit febd5949e134 ("mm/memory hotplug: init the zone's size when calculating node totalpages") refines the function free_area_init_core(). After doing so, these two parameters are not used anymore. This patch removes these two parameters. Signed-off-by: Wei Yang Cc: Gu Zheng Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 809e27e77b3a3..badc7d3bde433 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5303,8 +5303,7 @@ static unsigned long __paginginit calc_memmap_size(unsigned long spanned_pages, * * NOTE: pgdat should get zeroed by caller. */ -static void __paginginit free_area_init_core(struct pglist_data *pgdat, - unsigned long node_start_pfn, unsigned long node_end_pfn) +static void __paginginit free_area_init_core(struct pglist_data *pgdat) { enum zone_type j; int nid = pgdat->node_id; @@ -5467,7 +5466,7 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, (unsigned long)pgdat->node_mem_map); #endif - free_area_init_core(pgdat, start_pfn, end_pfn); + free_area_init_core(pgdat); } #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -- GitLab From 4fcab5f437c481e51c270a2d12ef56a3f2367371 Mon Sep 17 00:00:00 2001 From: Wei Yang Date: Tue, 8 Sep 2015 14:59:53 -0700 Subject: [PATCH 6694/7006] mm/memblock.c: WARN_ON when flags differs from overlap region Each memblock_region has flags to indicates the type of this range. For the overlap case, memblock_add_range() inserts the lower part and leave the upper part as indicated in the overlapped region. If the flags of the new range differs from the overlapped region, the information recorded is not correct. This patch adds a WARN_ON when the flags of the new range differs from the overlapped region. Signed-off-by: Wei Yang Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memblock.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/memblock.c b/mm/memblock.c index 95ce68c6da8ad..bde61e8c28c55 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -569,6 +569,7 @@ repeat: #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP WARN_ON(nid != memblock_get_region_node(rgn)); #endif + WARN_ON(flags != rgn->flags); nr_new++; if (insert) memblock_insert_region(type, i++, base, -- GitLab From b5e3aa0a4d5e35329203fd09acb0dbc7f7fd64de Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Tue, 8 Sep 2015 14:59:56 -0700 Subject: [PATCH 6695/7006] mm: remove put_page_unless_one() It has no callers. Signed-off-by: Vineet Gupta Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index e1fbd18b8c4bb..4ec72ef1f04a9 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -361,18 +361,6 @@ static inline int get_page_unless_zero(struct page *page) return atomic_inc_not_zero(&page->_count); } -/* - * Try to drop a ref unless the page has a refcount of one, return false if - * that is the case. - * This is to make sure that the refcount won't become zero after this drop. - * This can be called when MMU is off so it must not access - * any of the virtual mappings. - */ -static inline int put_page_unless_one(struct page *page) -{ - return atomic_add_unless(&page->_count, -1, 1); -} - extern int page_is_ram(unsigned long pfn); extern int region_is_ram(resource_size_t phys_addr, unsigned long size); -- GitLab From a06db751c321546e5563041956a57613259c6720 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Sep 2015 14:59:59 -0700 Subject: [PATCH 6696/7006] pagemap: check permissions and capabilities at open time This patchset makes pagemap useable again in the safe way (after row hammer bug it was made CAP_SYS_ADMIN-only). This patchset restores access for non-privileged users but hides PFNs from them. Also it adds bit 'map-exclusive' which is set if page is mapped only here: it helps in estimation of working set without exposing pfns and allows to distinguish CoWed and non-CoWed private anonymous pages. Second patch removes page-shift bits and completes migration to the new pagemap format: flags soft-dirty and mmap-exclusive are available only in the new format. This patch (of 5): This patch moves permission checks from pagemap_read() into pagemap_open(). Pointer to mm is saved in file->private_data. This reference pins only mm_struct itself. /proc/*/mem, maps, smaps already work in the same way. See http://lkml.kernel.org/r/CA+55aFyKpWrt_Ajzh1rzp_GcwZ4=6Y=kOv8hBz172CFJp6L8Tg@mail.gmail.com Signed-off-by: Konstantin Khlebnikov Reviewed-by: Naoya Horiguchi Reviewed-by: Mark Williamson Tested-by: Mark Williamson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 48 +++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 3b4d8255e8068..07c86f51d225f 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1229,40 +1229,33 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, static ssize_t pagemap_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - struct task_struct *task = get_proc_task(file_inode(file)); - struct mm_struct *mm; + struct mm_struct *mm = file->private_data; struct pagemapread pm; - int ret = -ESRCH; struct mm_walk pagemap_walk = {}; unsigned long src; unsigned long svpfn; unsigned long start_vaddr; unsigned long end_vaddr; - int copied = 0; + int ret = 0, copied = 0; - if (!task) + if (!mm || !atomic_inc_not_zero(&mm->mm_users)) goto out; ret = -EINVAL; /* file position must be aligned */ if ((*ppos % PM_ENTRY_BYTES) || (count % PM_ENTRY_BYTES)) - goto out_task; + goto out_mm; ret = 0; if (!count) - goto out_task; + goto out_mm; pm.v2 = soft_dirty_cleared; pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY); ret = -ENOMEM; if (!pm.buffer) - goto out_task; - - mm = mm_access(task, PTRACE_MODE_READ); - ret = PTR_ERR(mm); - if (!mm || IS_ERR(mm)) - goto out_free; + goto out_mm; pagemap_walk.pmd_entry = pagemap_pte_range; pagemap_walk.pte_hole = pagemap_pte_hole; @@ -1275,10 +1268,10 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, src = *ppos; svpfn = src / PM_ENTRY_BYTES; start_vaddr = svpfn << PAGE_SHIFT; - end_vaddr = TASK_SIZE_OF(task); + end_vaddr = mm->task_size; /* watch out for wraparound */ - if (svpfn > TASK_SIZE_OF(task) >> PAGE_SHIFT) + if (svpfn > mm->task_size >> PAGE_SHIFT) start_vaddr = end_vaddr; /* @@ -1305,7 +1298,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, len = min(count, PM_ENTRY_BYTES * pm.pos); if (copy_to_user(buf, pm.buffer, len)) { ret = -EFAULT; - goto out_mm; + goto out_free; } copied += len; buf += len; @@ -1315,24 +1308,38 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (!ret || ret == PM_END_OF_BUFFER) ret = copied; -out_mm: - mmput(mm); out_free: kfree(pm.buffer); -out_task: - put_task_struct(task); +out_mm: + mmput(mm); out: return ret; } static int pagemap_open(struct inode *inode, struct file *file) { + struct mm_struct *mm; + /* do not disclose physical addresses: attack vector */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about " "to stop being page-shift some time soon. See the " "linux/Documentation/vm/pagemap.txt for details.\n"); + + mm = proc_mem_open(inode, PTRACE_MODE_READ); + if (IS_ERR(mm)) + return PTR_ERR(mm); + file->private_data = mm; + return 0; +} + +static int pagemap_release(struct inode *inode, struct file *file) +{ + struct mm_struct *mm = file->private_data; + + if (mm) + mmdrop(mm); return 0; } @@ -1340,6 +1347,7 @@ const struct file_operations proc_pagemap_operations = { .llseek = mem_lseek, /* borrow this */ .read = pagemap_read, .open = pagemap_open, + .release = pagemap_release, }; #endif /* CONFIG_PROC_PAGE_MONITOR */ -- GitLab From deb945441b9408d6cd15751f5232eeca9f50a5a1 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Sep 2015 15:00:02 -0700 Subject: [PATCH 6697/7006] pagemap: switch to the new format and do some cleanup This patch removes page-shift bits (scheduled to remove since 3.11) and completes migration to the new bit layout. Also it cleans messy macro. Signed-off-by: Konstantin Khlebnikov Reviewed-by: Naoya Horiguchi Cc: Mark Williamson Tested-by: Mark Williamson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 150 +++++++++++++++--------------------------- tools/vm/page-types.c | 25 +++---- 2 files changed, 61 insertions(+), 114 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 07c86f51d225f..41c0a0a500f70 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -712,23 +712,6 @@ const struct file_operations proc_tid_smaps_operations = { .release = proc_map_release, }; -/* - * We do not want to have constant page-shift bits sitting in - * pagemap entries and are about to reuse them some time soon. - * - * Here's the "migration strategy": - * 1. when the system boots these bits remain what they are, - * but a warning about future change is printed in log; - * 2. once anyone clears soft-dirty bits via clear_refs file, - * these flag is set to denote, that user is aware of the - * new API and those page-shift bits change their meaning. - * The respective warning is printed in dmesg; - * 3. In a couple of releases we will remove all the mentions - * of page-shift in pagemap entries. - */ - -static bool soft_dirty_cleared __read_mostly; - enum clear_refs_types { CLEAR_REFS_ALL = 1, CLEAR_REFS_ANON, @@ -889,13 +872,6 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf, if (type < CLEAR_REFS_ALL || type >= CLEAR_REFS_LAST) return -EINVAL; - if (type == CLEAR_REFS_SOFT_DIRTY) { - soft_dirty_cleared = true; - pr_warn_once("The pagemap bits 55-60 has changed their meaning!" - " See the linux/Documentation/vm/pagemap.txt for " - "details.\n"); - } - task = get_proc_task(file_inode(file)); if (!task) return -ESRCH; @@ -963,36 +939,24 @@ typedef struct { struct pagemapread { int pos, len; /* units: PM_ENTRY_BYTES, not bytes */ pagemap_entry_t *buffer; - bool v2; }; #define PAGEMAP_WALK_SIZE (PMD_SIZE) #define PAGEMAP_WALK_MASK (PMD_MASK) -#define PM_ENTRY_BYTES sizeof(pagemap_entry_t) -#define PM_STATUS_BITS 3 -#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) -#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET) -#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK) -#define PM_PSHIFT_BITS 6 -#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) -#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) -#define __PM_PSHIFT(x) (((u64) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) -#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) -#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) -/* in "new" pagemap pshift bits are occupied with more status bits */ -#define PM_STATUS2(v2, x) (__PM_PSHIFT(v2 ? x : PAGE_SHIFT)) - -#define __PM_SOFT_DIRTY (1LL) -#define PM_PRESENT PM_STATUS(4LL) -#define PM_SWAP PM_STATUS(2LL) -#define PM_FILE PM_STATUS(1LL) -#define PM_NOT_PRESENT(v2) PM_STATUS2(v2, 0) +#define PM_ENTRY_BYTES sizeof(pagemap_entry_t) +#define PM_PFRAME_BITS 55 +#define PM_PFRAME_MASK GENMASK_ULL(PM_PFRAME_BITS - 1, 0) +#define PM_SOFT_DIRTY BIT_ULL(55) +#define PM_FILE BIT_ULL(61) +#define PM_SWAP BIT_ULL(62) +#define PM_PRESENT BIT_ULL(63) + #define PM_END_OF_BUFFER 1 -static inline pagemap_entry_t make_pme(u64 val) +static inline pagemap_entry_t make_pme(u64 frame, u64 flags) { - return (pagemap_entry_t) { .pme = val }; + return (pagemap_entry_t) { .pme = (frame & PM_PFRAME_MASK) | flags }; } static int add_to_pagemap(unsigned long addr, pagemap_entry_t *pme, @@ -1013,7 +977,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, while (addr < end) { struct vm_area_struct *vma = find_vma(walk->mm, addr); - pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); + pagemap_entry_t pme = make_pme(0, 0); /* End of address space hole, which we mark as non-present. */ unsigned long hole_end; @@ -1033,7 +997,7 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, /* Addresses in the VMA. */ if (vma->vm_flags & VM_SOFTDIRTY) - pme.pme |= PM_STATUS2(pm->v2, __PM_SOFT_DIRTY); + pme = make_pme(0, PM_SOFT_DIRTY); for (; addr < min(end, vma->vm_end); addr += PAGE_SIZE) { err = add_to_pagemap(addr, &pme, pm); if (err) @@ -1044,63 +1008,61 @@ out: return err; } -static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, +static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, struct vm_area_struct *vma, unsigned long addr, pte_t pte) { - u64 frame, flags; + u64 frame = 0, flags = 0; struct page *page = NULL; - int flags2 = 0; if (pte_present(pte)) { frame = pte_pfn(pte); - flags = PM_PRESENT; + flags |= PM_PRESENT; page = vm_normal_page(vma, addr, pte); if (pte_soft_dirty(pte)) - flags2 |= __PM_SOFT_DIRTY; + flags |= PM_SOFT_DIRTY; } else if (is_swap_pte(pte)) { swp_entry_t entry; if (pte_swp_soft_dirty(pte)) - flags2 |= __PM_SOFT_DIRTY; + flags |= PM_SOFT_DIRTY; entry = pte_to_swp_entry(pte); frame = swp_type(entry) | (swp_offset(entry) << MAX_SWAPFILES_SHIFT); - flags = PM_SWAP; + flags |= PM_SWAP; if (is_migration_entry(entry)) page = migration_entry_to_page(entry); - } else { - if (vma->vm_flags & VM_SOFTDIRTY) - flags2 |= __PM_SOFT_DIRTY; - *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2)); - return; } if (page && !PageAnon(page)) flags |= PM_FILE; - if ((vma->vm_flags & VM_SOFTDIRTY)) - flags2 |= __PM_SOFT_DIRTY; + if (vma->vm_flags & VM_SOFTDIRTY) + flags |= PM_SOFT_DIRTY; - *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags); + return make_pme(frame, flags); } #ifdef CONFIG_TRANSPARENT_HUGEPAGE -static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, - pmd_t pmd, int offset, int pmd_flags2) +static pagemap_entry_t thp_pmd_to_pagemap_entry(struct pagemapread *pm, + pmd_t pmd, int offset, u64 flags) { + u64 frame = 0; + /* * Currently pmd for thp is always present because thp can not be * swapped-out, migrated, or HWPOISONed (split in such cases instead.) * This if-check is just to prepare for future implementation. */ - if (pmd_present(pmd)) - *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) - | PM_STATUS2(pm->v2, pmd_flags2) | PM_PRESENT); - else - *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, pmd_flags2)); + if (pmd_present(pmd)) { + frame = pmd_pfn(pmd) + offset; + flags |= PM_PRESENT; + } + + return make_pme(frame, flags); } #else -static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, - pmd_t pmd, int offset, int pmd_flags2) +static pagemap_entry_t thp_pmd_to_pagemap_entry(struct pagemapread *pm, + pmd_t pmd, int offset, u64 flags) { + return make_pme(0, 0); } #endif @@ -1114,12 +1076,10 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, int err = 0; if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { - int pmd_flags2; + u64 flags = 0; if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(*pmd)) - pmd_flags2 = __PM_SOFT_DIRTY; - else - pmd_flags2 = 0; + flags |= PM_SOFT_DIRTY; for (; addr != end; addr += PAGE_SIZE) { unsigned long offset; @@ -1127,7 +1087,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, offset = (addr & ~PAGEMAP_WALK_MASK) >> PAGE_SHIFT; - thp_pmd_to_pagemap_entry(&pme, pm, *pmd, offset, pmd_flags2); + pme = thp_pmd_to_pagemap_entry(pm, *pmd, offset, flags); err = add_to_pagemap(addr, &pme, pm); if (err) break; @@ -1147,7 +1107,7 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, for (; addr < end; pte++, addr += PAGE_SIZE) { pagemap_entry_t pme; - pte_to_pagemap_entry(&pme, pm, vma, addr, *pte); + pme = pte_to_pagemap_entry(pm, vma, addr, *pte); err = add_to_pagemap(addr, &pme, pm); if (err) break; @@ -1160,16 +1120,17 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, } #ifdef CONFIG_HUGETLB_PAGE -static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, - pte_t pte, int offset, int flags2) +static pagemap_entry_t huge_pte_to_pagemap_entry(struct pagemapread *pm, + pte_t pte, int offset, u64 flags) { - if (pte_present(pte)) - *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) | - PM_STATUS2(pm->v2, flags2) | - PM_PRESENT); - else - *pme = make_pme(PM_NOT_PRESENT(pm->v2) | - PM_STATUS2(pm->v2, flags2)); + u64 frame = 0; + + if (pte_present(pte)) { + frame = pte_pfn(pte) + offset; + flags |= PM_PRESENT; + } + + return make_pme(frame, flags); } /* This function walks within one hugetlb entry in the single call */ @@ -1180,17 +1141,15 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, struct pagemapread *pm = walk->private; struct vm_area_struct *vma = walk->vma; int err = 0; - int flags2; + u64 flags = 0; pagemap_entry_t pme; if (vma->vm_flags & VM_SOFTDIRTY) - flags2 = __PM_SOFT_DIRTY; - else - flags2 = 0; + flags |= PM_SOFT_DIRTY; for (; addr != end; addr += PAGE_SIZE) { int offset = (addr & ~hmask) >> PAGE_SHIFT; - huge_pte_to_pagemap_entry(&pme, pm, *pte, offset, flags2); + pme = huge_pte_to_pagemap_entry(pm, *pte, offset, flags); err = add_to_pagemap(addr, &pme, pm); if (err) return err; @@ -1211,7 +1170,8 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, * Bits 0-54 page frame number (PFN) if present * Bits 0-4 swap type if swapped * Bits 5-54 swap offset if swapped - * Bits 55-60 page shift (page size = 1<> PAGE_SHIFT); pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY); ret = -ENOMEM; @@ -1323,9 +1282,6 @@ static int pagemap_open(struct inode *inode, struct file *file) /* do not disclose physical addresses: attack vector */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; - pr_warn_once("Bits 55-60 of /proc/PID/pagemap entries are about " - "to stop being page-shift some time soon. See the " - "linux/Documentation/vm/pagemap.txt for details.\n"); mm = proc_mem_open(inode, PTRACE_MODE_READ); if (IS_ERR(mm)) diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 8bdf16b8ba604..603ec916716b3 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -57,23 +57,14 @@ * pagemap kernel ABI bits */ -#define PM_ENTRY_BYTES sizeof(uint64_t) -#define PM_STATUS_BITS 3 -#define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) -#define PM_STATUS_MASK (((1LL << PM_STATUS_BITS) - 1) << PM_STATUS_OFFSET) -#define PM_STATUS(nr) (((nr) << PM_STATUS_OFFSET) & PM_STATUS_MASK) -#define PM_PSHIFT_BITS 6 -#define PM_PSHIFT_OFFSET (PM_STATUS_OFFSET - PM_PSHIFT_BITS) -#define PM_PSHIFT_MASK (((1LL << PM_PSHIFT_BITS) - 1) << PM_PSHIFT_OFFSET) -#define __PM_PSHIFT(x) (((uint64_t) (x) << PM_PSHIFT_OFFSET) & PM_PSHIFT_MASK) -#define PM_PFRAME_MASK ((1LL << PM_PSHIFT_OFFSET) - 1) -#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) - -#define __PM_SOFT_DIRTY (1LL) -#define PM_PRESENT PM_STATUS(4LL) -#define PM_SWAP PM_STATUS(2LL) -#define PM_SOFT_DIRTY __PM_PSHIFT(__PM_SOFT_DIRTY) - +#define PM_ENTRY_BYTES 8 +#define PM_PFRAME_BITS 55 +#define PM_PFRAME_MASK ((1LL << PM_PFRAME_BITS) - 1) +#define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) +#define PM_SOFT_DIRTY (1ULL << 55) +#define PM_FILE (1ULL << 61) +#define PM_SWAP (1ULL << 62) +#define PM_PRESENT (1ULL << 63) /* * kernel page flags -- GitLab From 356515e7b64c2629f686109d426baaf868cdf7e8 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Sep 2015 15:00:04 -0700 Subject: [PATCH 6698/7006] pagemap: rework hugetlb and thp report This patch moves pmd dissection out of reporting loop: huge pages are reported as bunch of normal pages with contiguous PFNs. Add missing "FILE" bit in hugetlb vmas. Signed-off-by: Konstantin Khlebnikov Reviewed-by: Naoya Horiguchi Reviewed-by: Mark Williamson Tested-by: Mark Williamson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 100 ++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 56 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 41c0a0a500f70..98ba9ea96b199 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -1040,33 +1040,7 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, return make_pme(frame, flags); } -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static pagemap_entry_t thp_pmd_to_pagemap_entry(struct pagemapread *pm, - pmd_t pmd, int offset, u64 flags) -{ - u64 frame = 0; - - /* - * Currently pmd for thp is always present because thp can not be - * swapped-out, migrated, or HWPOISONed (split in such cases instead.) - * This if-check is just to prepare for future implementation. - */ - if (pmd_present(pmd)) { - frame = pmd_pfn(pmd) + offset; - flags |= PM_PRESENT; - } - - return make_pme(frame, flags); -} -#else -static pagemap_entry_t thp_pmd_to_pagemap_entry(struct pagemapread *pm, - pmd_t pmd, int offset, u64 flags) -{ - return make_pme(0, 0); -} -#endif - -static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, +static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, struct mm_walk *walk) { struct vm_area_struct *vma = walk->vma; @@ -1075,35 +1049,48 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, pte_t *pte, *orig_pte; int err = 0; - if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { - u64 flags = 0; +#ifdef CONFIG_TRANSPARENT_HUGEPAGE + if (pmd_trans_huge_lock(pmdp, vma, &ptl) == 1) { + u64 flags = 0, frame = 0; + pmd_t pmd = *pmdp; - if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(*pmd)) + if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(pmd)) flags |= PM_SOFT_DIRTY; + /* + * Currently pmd for thp is always present because thp + * can not be swapped-out, migrated, or HWPOISONed + * (split in such cases instead.) + * This if-check is just to prepare for future implementation. + */ + if (pmd_present(pmd)) { + flags |= PM_PRESENT; + frame = pmd_pfn(pmd) + + ((addr & ~PMD_MASK) >> PAGE_SHIFT); + } + for (; addr != end; addr += PAGE_SIZE) { - unsigned long offset; - pagemap_entry_t pme; + pagemap_entry_t pme = make_pme(frame, flags); - offset = (addr & ~PAGEMAP_WALK_MASK) >> - PAGE_SHIFT; - pme = thp_pmd_to_pagemap_entry(pm, *pmd, offset, flags); err = add_to_pagemap(addr, &pme, pm); if (err) break; + if (flags & PM_PRESENT) + frame++; } spin_unlock(ptl); return err; } - if (pmd_trans_unstable(pmd)) + if (pmd_trans_unstable(pmdp)) return 0; +#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ /* * We can assume that @vma always points to a valid one and @end never * goes beyond vma->vm_end. */ - orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); + orig_pte = pte = pte_offset_map_lock(walk->mm, pmdp, addr, &ptl); for (; addr < end; pte++, addr += PAGE_SIZE) { pagemap_entry_t pme; @@ -1120,39 +1107,40 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, } #ifdef CONFIG_HUGETLB_PAGE -static pagemap_entry_t huge_pte_to_pagemap_entry(struct pagemapread *pm, - pte_t pte, int offset, u64 flags) -{ - u64 frame = 0; - - if (pte_present(pte)) { - frame = pte_pfn(pte) + offset; - flags |= PM_PRESENT; - } - - return make_pme(frame, flags); -} - /* This function walks within one hugetlb entry in the single call */ -static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, +static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask, unsigned long addr, unsigned long end, struct mm_walk *walk) { struct pagemapread *pm = walk->private; struct vm_area_struct *vma = walk->vma; + u64 flags = 0, frame = 0; int err = 0; - u64 flags = 0; - pagemap_entry_t pme; + pte_t pte; if (vma->vm_flags & VM_SOFTDIRTY) flags |= PM_SOFT_DIRTY; + pte = huge_ptep_get(ptep); + if (pte_present(pte)) { + struct page *page = pte_page(pte); + + if (!PageAnon(page)) + flags |= PM_FILE; + + flags |= PM_PRESENT; + frame = pte_pfn(pte) + + ((addr & ~hmask) >> PAGE_SHIFT); + } + for (; addr != end; addr += PAGE_SIZE) { - int offset = (addr & ~hmask) >> PAGE_SHIFT; - pme = huge_pte_to_pagemap_entry(pm, *pte, offset, flags); + pagemap_entry_t pme = make_pme(frame, flags); + err = add_to_pagemap(addr, &pme, pm); if (err) return err; + if (flags & PM_PRESENT) + frame++; } cond_resched(); @@ -1216,7 +1204,7 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (!pm.buffer) goto out_mm; - pagemap_walk.pmd_entry = pagemap_pte_range; + pagemap_walk.pmd_entry = pagemap_pmd_range; pagemap_walk.pte_hole = pagemap_pte_hole; #ifdef CONFIG_HUGETLB_PAGE pagemap_walk.hugetlb_entry = pagemap_hugetlb_range; -- GitLab From 1c90308e7a77af6742a97d1021cca923b23b7f0d Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Sep 2015 15:00:07 -0700 Subject: [PATCH 6699/7006] pagemap: hide physical addresses from non-privileged users This patch makes pagemap readable for normal users and hides physical addresses from them. For some use-cases PFN isn't required at all. See http://lkml.kernel.org/r/1425935472-17949-1-git-send-email-kirill@shutemov.name Fixes: ab676b7d6fbf ("pagemap: do not leak physical addresses to non-privileged userspace") Signed-off-by: Konstantin Khlebnikov Cc: Naoya Horiguchi Reviewed-by: Mark Williamson Tested-by: Mark Williamson Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/task_mmu.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 98ba9ea96b199..bc651644b1b24 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -939,6 +939,7 @@ typedef struct { struct pagemapread { int pos, len; /* units: PM_ENTRY_BYTES, not bytes */ pagemap_entry_t *buffer; + bool show_pfn; }; #define PAGEMAP_WALK_SIZE (PMD_SIZE) @@ -1015,7 +1016,8 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, struct page *page = NULL; if (pte_present(pte)) { - frame = pte_pfn(pte); + if (pm->show_pfn) + frame = pte_pfn(pte); flags |= PM_PRESENT; page = vm_normal_page(vma, addr, pte); if (pte_soft_dirty(pte)) @@ -1065,8 +1067,9 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, */ if (pmd_present(pmd)) { flags |= PM_PRESENT; - frame = pmd_pfn(pmd) + - ((addr & ~PMD_MASK) >> PAGE_SHIFT); + if (pm->show_pfn) + frame = pmd_pfn(pmd) + + ((addr & ~PMD_MASK) >> PAGE_SHIFT); } for (; addr != end; addr += PAGE_SIZE) { @@ -1075,7 +1078,7 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, err = add_to_pagemap(addr, &pme, pm); if (err) break; - if (flags & PM_PRESENT) + if (pm->show_pfn && (flags & PM_PRESENT)) frame++; } spin_unlock(ptl); @@ -1129,8 +1132,9 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask, flags |= PM_FILE; flags |= PM_PRESENT; - frame = pte_pfn(pte) + - ((addr & ~hmask) >> PAGE_SHIFT); + if (pm->show_pfn) + frame = pte_pfn(pte) + + ((addr & ~hmask) >> PAGE_SHIFT); } for (; addr != end; addr += PAGE_SIZE) { @@ -1139,7 +1143,7 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask, err = add_to_pagemap(addr, &pme, pm); if (err) return err; - if (flags & PM_PRESENT) + if (pm->show_pfn && (flags & PM_PRESENT)) frame++; } @@ -1198,6 +1202,9 @@ static ssize_t pagemap_read(struct file *file, char __user *buf, if (!count) goto out_mm; + /* do not disclose physical addresses: attack vector */ + pm.show_pfn = file_ns_capable(file, &init_user_ns, CAP_SYS_ADMIN); + pm.len = (PAGEMAP_WALK_SIZE >> PAGE_SHIFT); pm.buffer = kmalloc(pm.len * PM_ENTRY_BYTES, GFP_TEMPORARY); ret = -ENOMEM; @@ -1267,10 +1274,6 @@ static int pagemap_open(struct inode *inode, struct file *file) { struct mm_struct *mm; - /* do not disclose physical addresses: attack vector */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - mm = proc_mem_open(inode, PTRACE_MODE_READ); if (IS_ERR(mm)) return PTR_ERR(mm); -- GitLab From 77bb499bb60f4b79cca7d139c8041662860fcf87 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Sep 2015 15:00:10 -0700 Subject: [PATCH 6700/7006] pagemap: add mmap-exclusive bit for marking pages mapped only here This patch sets bit 56 in pagemap if this page is mapped only once. It allows to detect exclusively used pages without exposing PFN: present file exclusive state 0 0 0 non-present 1 1 0 file page mapped somewhere else 1 1 1 file page mapped only here 1 0 0 anon non-CoWed page (shared with parent/child) 1 0 1 anon CoWed page (or never forked) CoWed pages in (MAP_FILE | MAP_PRIVATE) areas are anon in this context. MMap-exclusive bit doesn't reflect potential page-sharing via swapcache: page could be mapped once but has several swap-ptes which point to it. Application could detect that by swap bit in pagemap entry and touch that pte via /proc/pid/mem to get real information. See http://lkml.kernel.org/r/CAEVpBa+_RyACkhODZrRvQLs80iy0sqpdrd0AaP_-tgnX3Y9yNQ@mail.gmail.com Requested by Mark Williamson. [akpm@linux-foundation.org: fix spello] Signed-off-by: Konstantin Khlebnikov Reviewed-by: Mark Williamson Tested-by: Mark Williamson Reviewed-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/pagemap.txt | 3 ++- fs/proc/task_mmu.c | 14 +++++++++++++- tools/vm/page-types.c | 10 ++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index 6bfbc172cdb96..56faec0f73f73 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -16,7 +16,8 @@ There are three components to pagemap: * Bits 0-4 swap type if swapped * Bits 5-54 swap offset if swapped * Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt) - * Bits 56-60 zero + * Bit 56 page exclusively mapped + * Bits 57-60 zero * Bit 61 page is file-page or shared-anon * Bit 62 page swapped * Bit 63 page present diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index bc651644b1b24..67c76468a7be4 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -949,6 +949,7 @@ struct pagemapread { #define PM_PFRAME_BITS 55 #define PM_PFRAME_MASK GENMASK_ULL(PM_PFRAME_BITS - 1, 0) #define PM_SOFT_DIRTY BIT_ULL(55) +#define PM_MMAP_EXCLUSIVE BIT_ULL(56) #define PM_FILE BIT_ULL(61) #define PM_SWAP BIT_ULL(62) #define PM_PRESENT BIT_ULL(63) @@ -1036,6 +1037,8 @@ static pagemap_entry_t pte_to_pagemap_entry(struct pagemapread *pm, if (page && !PageAnon(page)) flags |= PM_FILE; + if (page && page_mapcount(page) == 1) + flags |= PM_MMAP_EXCLUSIVE; if (vma->vm_flags & VM_SOFTDIRTY) flags |= PM_SOFT_DIRTY; @@ -1066,6 +1069,11 @@ static int pagemap_pmd_range(pmd_t *pmdp, unsigned long addr, unsigned long end, * This if-check is just to prepare for future implementation. */ if (pmd_present(pmd)) { + struct page *page = pmd_page(pmd); + + if (page_mapcount(page) == 1) + flags |= PM_MMAP_EXCLUSIVE; + flags |= PM_PRESENT; if (pm->show_pfn) frame = pmd_pfn(pmd) + @@ -1131,6 +1139,9 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask, if (!PageAnon(page)) flags |= PM_FILE; + if (page_mapcount(page) == 1) + flags |= PM_MMAP_EXCLUSIVE; + flags |= PM_PRESENT; if (pm->show_pfn) frame = pte_pfn(pte) + @@ -1163,7 +1174,8 @@ static int pagemap_hugetlb_range(pte_t *ptep, unsigned long hmask, * Bits 0-4 swap type if swapped * Bits 5-54 swap offset if swapped * Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt) - * Bits 56-60 zero + * Bit 56 page exclusively mapped + * Bits 57-60 zero * Bit 61 page is file-page or shared-anon * Bit 62 page swapped * Bit 63 page present diff --git a/tools/vm/page-types.c b/tools/vm/page-types.c index 603ec916716b3..7f73fa32a590b 100644 --- a/tools/vm/page-types.c +++ b/tools/vm/page-types.c @@ -62,6 +62,7 @@ #define PM_PFRAME_MASK ((1LL << PM_PFRAME_BITS) - 1) #define PM_PFRAME(x) ((x) & PM_PFRAME_MASK) #define PM_SOFT_DIRTY (1ULL << 55) +#define PM_MMAP_EXCLUSIVE (1ULL << 56) #define PM_FILE (1ULL << 61) #define PM_SWAP (1ULL << 62) #define PM_PRESENT (1ULL << 63) @@ -91,6 +92,8 @@ #define KPF_SLOB_FREE 49 #define KPF_SLUB_FROZEN 50 #define KPF_SLUB_DEBUG 51 +#define KPF_FILE 62 +#define KPF_MMAP_EXCLUSIVE 63 #define KPF_ALL_BITS ((uint64_t)~0ULL) #define KPF_HACKERS_BITS (0xffffULL << 32) @@ -140,6 +143,9 @@ static const char * const page_flag_names[] = { [KPF_SLOB_FREE] = "P:slob_free", [KPF_SLUB_FROZEN] = "A:slub_frozen", [KPF_SLUB_DEBUG] = "E:slub_debug", + + [KPF_FILE] = "F:file", + [KPF_MMAP_EXCLUSIVE] = "1:mmap_exclusive", }; @@ -443,6 +449,10 @@ static uint64_t expand_overloaded_flags(uint64_t flags, uint64_t pme) if (pme & PM_SOFT_DIRTY) flags |= BIT(SOFTDIRTY); + if (pme & PM_FILE) + flags |= BIT(FILE); + if (pme & PM_MMAP_EXCLUSIVE) + flags |= BIT(MMAP_EXCLUSIVE); return flags; } -- GitLab From 83b4b0bb635eee2b8e075062e4e008d1bc110ed7 Mon Sep 17 00:00:00 2001 From: Konstantin Khlebnikov Date: Tue, 8 Sep 2015 15:00:13 -0700 Subject: [PATCH 6701/7006] pagemap: update documentation Notes about recent changes. [akpm@linux-foundation.org: various tweaks] Signed-off-by: Konstantin Khlebnikov Cc: Mark Williamson Cc: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/pagemap.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index 56faec0f73f73..3cd38438242ae 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -16,12 +16,17 @@ There are three components to pagemap: * Bits 0-4 swap type if swapped * Bits 5-54 swap offset if swapped * Bit 55 pte is soft-dirty (see Documentation/vm/soft-dirty.txt) - * Bit 56 page exclusively mapped + * Bit 56 page exclusively mapped (since 4.2) * Bits 57-60 zero - * Bit 61 page is file-page or shared-anon + * Bit 61 page is file-page or shared-anon (since 3.5) * Bit 62 page swapped * Bit 63 page present + Since Linux 4.0 only users with the CAP_SYS_ADMIN capability can get PFNs. + In 4.0 and 4.1 opens by unprivileged fail with -EPERM. Starting from + 4.2 the PFN field is zeroed if the user does not have CAP_SYS_ADMIN. + Reason: information about PFNs helps in exploiting Rowhammer vulnerability. + If the page is not present but in swap, then the PFN contains an encoding of the swap file number and the page's offset into the swap. Unmapped pages return a null PFN. This allows determining @@ -160,3 +165,8 @@ Other notes: Reading from any of the files will return -EINVAL if you are not starting the read on an 8-byte boundary (e.g., if you sought an odd number of bytes into the file), or if the size of the read is not a multiple of 8 bytes. + +Before Linux 3.11 pagemap bits 55-60 were used for "page-shift" (which is +always 12 at most architectures). Since Linux 3.11 their meaning changes +after first clear of soft-dirty bits. Since Linux 4.2 they are used for +flags unconditionally. -- GitLab From 06f805965fc205e27681eee99fd2376fafd8da65 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Tue, 8 Sep 2015 15:00:16 -0700 Subject: [PATCH 6702/7006] memtest: use kstrtouint instead of simple_strtoul Since simple_strtoul is obsolete and memtest_pattern is type of int, use kstrtouint instead. Signed-off-by: Vladimir Murzin Cc: Leon Romanovsky Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memtest.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mm/memtest.c b/mm/memtest.c index 0a1cc133f6d72..20e836138e003 100644 --- a/mm/memtest.c +++ b/mm/memtest.c @@ -89,16 +89,18 @@ static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end) } /* default is disabled */ -static int memtest_pattern __initdata; +static unsigned int memtest_pattern __initdata; static int __init parse_memtest(char *arg) { + int ret = 0; + if (arg) - memtest_pattern = simple_strtoul(arg, NULL, 0); + ret = kstrtouint(arg, 0, &memtest_pattern); else memtest_pattern = ARRAY_SIZE(patterns); - return 0; + return ret; } early_param("memtest", parse_memtest); -- GitLab From f373bafcad68834761b40da9cecda842f43d4797 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Tue, 8 Sep 2015 15:00:19 -0700 Subject: [PATCH 6703/7006] memtest: cleanup log messages - prefer pr_info(... to printk(KERN_INFO ... - use %pa for phys_addr_t - use cpu_to_be64 while printing pattern in reserve_bad_mem() Signed-off-by: Vladimir Murzin Cc: Leon Romanovsky Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memtest.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/mm/memtest.c b/mm/memtest.c index 20e836138e003..6bcf7d89adfc8 100644 --- a/mm/memtest.c +++ b/mm/memtest.c @@ -31,10 +31,8 @@ static u64 patterns[] __initdata = { static void __init reserve_bad_mem(u64 pattern, phys_addr_t start_bad, phys_addr_t end_bad) { - printk(KERN_INFO " %016llx bad mem addr %010llx - %010llx reserved\n", - (unsigned long long) pattern, - (unsigned long long) start_bad, - (unsigned long long) end_bad); + pr_info(" %016llx bad mem addr %pa - %pa reserved\n", + cpu_to_be64(pattern), &start_bad, &end_bad); memblock_reserve(start_bad, end_bad - start_bad); } @@ -79,10 +77,8 @@ static void __init do_one_pass(u64 pattern, phys_addr_t start, phys_addr_t end) this_start = clamp(this_start, start, end); this_end = clamp(this_end, start, end); if (this_start < this_end) { - printk(KERN_INFO " %010llx - %010llx pattern %016llx\n", - (unsigned long long)this_start, - (unsigned long long)this_end, - (unsigned long long)cpu_to_be64(pattern)); + pr_info(" %pa - %pa pattern %016llx\n", + &this_start, &this_end, cpu_to_be64(pattern)); memtest(pattern, this_start, this_end - this_start); } } @@ -113,7 +109,7 @@ void __init early_memtest(phys_addr_t start, phys_addr_t end) if (!memtest_pattern) return; - printk(KERN_INFO "early_memtest: # of tests: %d\n", memtest_pattern); + pr_info("early_memtest: # of tests: %u\n", memtest_pattern); for (i = memtest_pattern-1; i < UINT_MAX; --i) { idx = i % ARRAY_SIZE(patterns); do_one_pass(patterns[idx], start, end); -- GitLab From 3115aec4513e5bcb399235cac98a5637fe641c13 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Tue, 8 Sep 2015 15:00:22 -0700 Subject: [PATCH 6704/7006] memtest: remove unused header files memtest does not require these headers to be included. Signed-off-by: Vladimir Murzin Cc: Leon Romanovsky Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memtest.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/mm/memtest.c b/mm/memtest.c index 6bcf7d89adfc8..8eaa4c3a5f65a 100644 --- a/mm/memtest.c +++ b/mm/memtest.c @@ -1,11 +1,6 @@ #include -#include -#include #include -#include -#include #include -#include #include static u64 patterns[] __initdata = { -- GitLab From 8334b96221ff0dcbde4873d31eb4d84774ed8ed4 Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Tue, 8 Sep 2015 15:00:24 -0700 Subject: [PATCH 6705/7006] mm: /proc/pid/smaps:: show proportional swap share of the mapping We want to know per-process workingset size for smart memory management on userland and we use swap(ex, zram) heavily to maximize memory efficiency so workingset includes swap as well as RSS. On such system, if there are lots of shared anonymous pages, it's really hard to figure out exactly how many each process consumes memory(ie, rss + wap) if the system has lots of shared anonymous memory(e.g, android). This patch introduces SwapPss field on /proc//smaps so we can get more exact workingset size per process. Bongkyu tested it. Result is below. 1. 50M used swap SwapTotal: 461976 kB SwapFree: 411192 kB $ adb shell cat /proc/*/smaps | grep "SwapPss:" | awk '{sum += $2} END {print sum}'; 48236 $ adb shell cat /proc/*/smaps | grep "Swap:" | awk '{sum += $2} END {print sum}'; 141184 2. 240M used swap SwapTotal: 461976 kB SwapFree: 216808 kB $ adb shell cat /proc/*/smaps | grep "SwapPss:" | awk '{sum += $2} END {print sum}'; 230315 $ adb shell cat /proc/*/smaps | grep "Swap:" | awk '{sum += $2} END {print sum}'; 1387744 [akpm@linux-foundation.org: simplify kunmap_atomic() call] Signed-off-by: Minchan Kim Reported-by: Bongkyu Kim Tested-by: Bongkyu Kim Cc: Hugh Dickins Cc: Sergey Senozhatsky Cc: Jonathan Corbet Cc: Jerome Marchand Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/filesystems/proc.txt | 18 +++++++++---- fs/proc/task_mmu.c | 18 +++++++++++-- include/linux/swap.h | 6 +++++ mm/swapfile.c | 42 ++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 7 deletions(-) diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 6f7fafde0884e..d411ca63c8b6c 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -424,6 +424,7 @@ Private_Dirty: 0 kB Referenced: 892 kB Anonymous: 0 kB Swap: 0 kB +SwapPss: 0 kB KernelPageSize: 4 kB MMUPageSize: 4 kB Locked: 374 kB @@ -433,16 +434,23 @@ the first of these lines shows the same information as is displayed for the mapping in /proc/PID/maps. The remaining lines show the size of the mapping (size), the amount of the mapping that is currently resident in RAM (RSS), the process' proportional share of this mapping (PSS), the number of clean and -dirty private pages in the mapping. Note that even a page which is part of a -MAP_SHARED mapping, but has only a single pte mapped, i.e. is currently used -by only one process, is accounted as private and not as shared. "Referenced" -indicates the amount of memory currently marked as referenced or accessed. +dirty private pages in the mapping. + +The "proportional set size" (PSS) of a process is the count of pages it has +in memory, where each page is divided by the number of processes sharing it. +So if a process has 1000 pages all to itself, and 1000 shared with one other +process, its PSS will be 1500. +Note that even a page which is part of a MAP_SHARED mapping, but has only +a single pte mapped, i.e. is currently used by only one process, is accounted +as private and not as shared. +"Referenced" indicates the amount of memory currently marked as referenced or +accessed. "Anonymous" shows the amount of memory that does not belong to any file. Even a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE and a page is modified, the file page is replaced by a private anonymous copy. "Swap" shows how much would-be-anonymous memory is also used, but out on swap. - +"SwapPss" shows proportional swap share of this mapping. "VmFlags" field deserves a separate description. This member represents the kernel flags associated with the particular virtual memory area in two letter encoded manner. The codes are the following: diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 67c76468a7be4..41f1a50c10c9e 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -446,6 +446,7 @@ struct mem_size_stats { unsigned long anonymous_thp; unsigned long swap; u64 pss; + u64 swap_pss; }; static void smaps_account(struct mem_size_stats *mss, struct page *page, @@ -492,9 +493,20 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr, } else if (is_swap_pte(*pte)) { swp_entry_t swpent = pte_to_swp_entry(*pte); - if (!non_swap_entry(swpent)) + if (!non_swap_entry(swpent)) { + int mapcount; + mss->swap += PAGE_SIZE; - else if (is_migration_entry(swpent)) + mapcount = swp_swapcount(swpent); + if (mapcount >= 2) { + u64 pss_delta = (u64)PAGE_SIZE << PSS_SHIFT; + + do_div(pss_delta, mapcount); + mss->swap_pss += pss_delta; + } else { + mss->swap_pss += (u64)PAGE_SIZE << PSS_SHIFT; + } + } else if (is_migration_entry(swpent)) page = migration_entry_to_page(swpent); } @@ -640,6 +652,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) "Anonymous: %8lu kB\n" "AnonHugePages: %8lu kB\n" "Swap: %8lu kB\n" + "SwapPss: %8lu kB\n" "KernelPageSize: %8lu kB\n" "MMUPageSize: %8lu kB\n" "Locked: %8lu kB\n", @@ -654,6 +667,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) mss.anonymous >> 10, mss.anonymous_thp >> 10, mss.swap >> 10, + (unsigned long)(mss.swap_pss >> (10 + PSS_SHIFT)), vma_kernel_pagesize(vma) >> 10, vma_mmu_pagesize(vma) >> 10, (vma->vm_flags & VM_LOCKED) ? diff --git a/include/linux/swap.h b/include/linux/swap.h index 31496d201fdc0..6282f1eb3d6a3 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -431,6 +431,7 @@ extern unsigned int count_swap_pages(int, int); extern sector_t map_swap_page(struct page *, struct block_device **); extern sector_t swapdev_block(int, pgoff_t); extern int page_swapcount(struct page *); +extern int swp_swapcount(swp_entry_t entry); extern struct swap_info_struct *page_swap_info(struct page *); extern int reuse_swap_page(struct page *); extern int try_to_free_swap(struct page *); @@ -522,6 +523,11 @@ static inline int page_swapcount(struct page *page) return 0; } +static inline int swp_swapcount(swp_entry_t entry) +{ + return 0; +} + #define reuse_swap_page(page) (page_mapcount(page) == 1) static inline int try_to_free_swap(struct page *page) diff --git a/mm/swapfile.c b/mm/swapfile.c index aebc2dd6e6497..58877312cf6b9 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c @@ -874,6 +874,48 @@ int page_swapcount(struct page *page) return count; } +/* + * How many references to @entry are currently swapped out? + * This considers COUNT_CONTINUED so it returns exact answer. + */ +int swp_swapcount(swp_entry_t entry) +{ + int count, tmp_count, n; + struct swap_info_struct *p; + struct page *page; + pgoff_t offset; + unsigned char *map; + + p = swap_info_get(entry); + if (!p) + return 0; + + count = swap_count(p->swap_map[swp_offset(entry)]); + if (!(count & COUNT_CONTINUED)) + goto out; + + count &= ~COUNT_CONTINUED; + n = SWAP_MAP_MAX + 1; + + offset = swp_offset(entry); + page = vmalloc_to_page(p->swap_map + offset); + offset &= ~PAGE_MASK; + VM_BUG_ON(page_private(page) != SWP_CONTINUED); + + do { + page = list_entry(page->lru.next, struct page, lru); + map = kmap_atomic(page); + tmp_count = map[offset]; + kunmap_atomic(map); + + count += (tmp_count & ~COUNT_CONTINUED) * n; + n *= (SWAP_CONT_MAX + 1); + } while (tmp_count & COUNT_CONTINUED); +out: + spin_unlock(&p->lock); + return count; +} + /* * We can write to an anon page without COW if there are no other references * to it. And as a side-effect, free up its swap: because the old content -- GitLab From 998ef75ddb5709bbea0bf1506cd2717348a3c647 Mon Sep 17 00:00:00 2001 From: Dave Hansen Date: Tue, 8 Sep 2015 15:00:28 -0700 Subject: [PATCH 6706/7006] fs: do not prefault sys_write() user buffer pages === Short summary ==== iov_iter_fault_in_readable() works around a really rare case and we can avoid the deadlock it addresses in another way: disable page faults and work around copy failures by faulting after the copy in a slow path instead of before in a hot one. I have a little microbenchmark that does repeated, small writes to tmpfs. This patch speeds that micro up by 6.2%. === Long version === When doing a sys_write() we have a source buffer in userspace and then a target file page. If both of those are the same physical page, there is a potential deadlock that we avoid. It would happen something like this: 1. We start the write to the file 2. Allocate page cache page and set it !Uptodate 3. Touch the userspace buffer to copy in the user data 4. Page fault (since source of the write not yet mapped) 5. Page fault code tries to lock the page and deadlocks (more details on this below) To avoid this, we prefault the page to guarantee that this fault does not occur. But, this prefault comes at a cost. It is one of the most expensive things that we do in a hot write() path (especially if we compare it to the read path). It is working around a pretty rare case. To fix this, it's pretty simple. We move the "prefault" code to run after we attempt the copy. We explicitly disable page faults _during_ the copy, detect the copy failure, then execute the "prefault" ouside of where the page lock needs to be held. iov_iter_copy_from_user_atomic() actually already has an implicit pagefault_disable() inside of it (at least on x86), but we add an explicit one. I don't think we can depend on every kmap_atomic() implementation to pagefault_disable() for eternity. =================================================== The stack trace when this happens looks like this: wait_on_page_bit_killable+0xc0/0xd0 __lock_page_or_retry+0x84/0xa0 filemap_fault+0x1ed/0x3d0 __do_fault+0x41/0xc0 handle_mm_fault+0x9bb/0x1210 __do_page_fault+0x17f/0x3d0 do_page_fault+0xc/0x10 page_fault+0x22/0x30 generic_perform_write+0xca/0x1a0 __generic_file_write_iter+0x190/0x1f0 ext4_file_write_iter+0xe9/0x460 __vfs_write+0xaa/0xe0 vfs_write+0xa6/0x1a0 SyS_write+0x46/0xa0 entry_SYSCALL_64_fastpath+0x12/0x6a 0xffffffffffffffff (Note, this does *NOT* happen in practice today because the kmap_atomic() does a pagefault_disable(). The trace above was obtained by taking out the pagefault_disable().) You can trigger the deadlock with this little code snippet: fd = open("foo", O_RDWR); fdmap = mmap(NULL, len, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0); write(fd, &fdmap[0], 1); Signed-off-by: Dave Hansen Cc: Al Viro Cc: Michal Hocko Cc: Jens Axboe Cc: Tejun Heo Cc: NeilBrown Cc: Matthew Wilcox Cc: Paul Cassella Cc: Greg Thelen Cc: Andi Kleen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/filemap.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/mm/filemap.c b/mm/filemap.c index 1283fc8254586..30d69c0c5a386 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2473,21 +2473,6 @@ ssize_t generic_perform_write(struct file *file, iov_iter_count(i)); again: - /* - * Bring in the user page that we will copy from _first_. - * Otherwise there's a nasty deadlock on copying from the - * same page as we're writing to, without it being marked - * up-to-date. - * - * Not only is this an optimisation, but it is also required - * to check that the address is actually valid, when atomic - * usercopies are used, below. - */ - if (unlikely(iov_iter_fault_in_readable(i, bytes))) { - status = -EFAULT; - break; - } - status = a_ops->write_begin(file, mapping, pos, bytes, flags, &page, &fsdata); if (unlikely(status < 0)) @@ -2495,8 +2480,17 @@ again: if (mapping_writably_mapped(mapping)) flush_dcache_page(page); - + /* + * 'page' is now locked. If we are trying to copy from a + * mapping of 'page' in userspace, the copy might fault and + * would need PageUptodate() to complete. But, page can not be + * made Uptodate without acquiring the page lock, which we hold. + * Deadlock. Avoid with pagefault_disable(). Fix up below with + * iov_iter_fault_in_readable(). + */ + pagefault_disable(); copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes); + pagefault_enable(); flush_dcache_page(page); status = a_ops->write_end(file, mapping, pos, bytes, copied, @@ -2519,6 +2513,14 @@ again: */ bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset, iov_iter_single_seg_count(i)); + /* + * This is the fallback to recover if the copy from + * userspace above faults. + */ + if (unlikely(iov_iter_fault_in_readable(i, bytes))) { + status = -EFAULT; + break; + } goto again; } pos += copied; -- GitLab From 28c015d07507e164d93b33498b4e482ff81c0e9b Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 8 Sep 2015 15:00:31 -0700 Subject: [PATCH 6707/7006] mm: improve __GFP_NORETRY comment based on implementation Explicitly state that __GFP_NORETRY will attempt direct reclaim and memory compaction before returning NULL and that the oom killer is not called in the current implementation of the page allocator. [akpm@linux-foundation.org: s/has/have/] Signed-off-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index ad35f300b9a46..3bd64b115999f 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -63,7 +63,10 @@ struct vm_area_struct; * but it is definitely preferable to use the flag rather than opencode endless * loop around allocator. * - * __GFP_NORETRY: The VM implementation must not retry indefinitely. + * __GFP_NORETRY: The VM implementation must not retry indefinitely and will + * return NULL when direct reclaim and memory compaction have failed to allow + * the allocation to succeed. The OOM killer is not called with the current + * implementation. * * __GFP_MOVABLE: Flag that this page will be movable by the page migration * mechanism or reclaimed -- GitLab From 2c0b80d463c6ade539d51ad03bc7c41849fb37e8 Mon Sep 17 00:00:00 2001 From: Nicholas Krause Date: Tue, 8 Sep 2015 15:00:33 -0700 Subject: [PATCH 6708/7006] mm: make set_recommended_min_free_kbytes() return void This makes set_recommended_min_free_kbytes() have a return type of void as it cannot fail. Signed-off-by: Nicholas Krause Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 3e574efad8f85..71a4822c832b9 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -106,7 +106,7 @@ static struct khugepaged_scan khugepaged_scan = { }; -static int set_recommended_min_free_kbytes(void) +static void set_recommended_min_free_kbytes(void) { struct zone *zone; int nr_zones = 0; @@ -141,7 +141,6 @@ static int set_recommended_min_free_kbytes(void) min_free_kbytes = recommended_min; } setup_per_zone_wmarks(); - return 0; } static int start_stop_khugepaged(void) -- GitLab From 6e0fc46dc2152d3e2d25a5d5b640ae3586c247c6 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 8 Sep 2015 15:00:36 -0700 Subject: [PATCH 6709/7006] mm, oom: organize oom context into struct There are essential elements to an oom context that are passed around to multiple functions. Organize these elements into a new struct, struct oom_control, that specifies the context for an oom condition. This patch introduces no functional change. Signed-off-by: David Rientjes Acked-by: Michal Hocko Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/tty/sysrq.c | 12 ++++- include/linux/oom.h | 25 ++++++---- mm/memcontrol.c | 16 ++++-- mm/oom_kill.c | 115 +++++++++++++++++++++----------------------- mm/page_alloc.c | 10 +++- 5 files changed, 98 insertions(+), 80 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index b5b427888b245..ed3e258f4ee9f 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -353,9 +353,17 @@ static struct sysrq_key_op sysrq_term_op = { static void moom_callback(struct work_struct *ignored) { + const gfp_t gfp_mask = GFP_KERNEL; + struct oom_control oc = { + .zonelist = node_zonelist(first_memory_node, gfp_mask), + .nodemask = NULL, + .gfp_mask = gfp_mask, + .order = 0, + .force_kill = true, + }; + mutex_lock(&oom_lock); - if (!out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), - GFP_KERNEL, 0, NULL, true)) + if (!out_of_memory(&oc)) pr_info("OOM request ignored because killer is disabled\n"); mutex_unlock(&oom_lock); } diff --git a/include/linux/oom.h b/include/linux/oom.h index 7deecb7bca5e3..cb29085ded371 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -12,6 +12,14 @@ struct notifier_block; struct mem_cgroup; struct task_struct; +struct oom_control { + struct zonelist *zonelist; + nodemask_t *nodemask; + gfp_t gfp_mask; + int order; + bool force_kill; +}; + /* * Types of limitations to the nodes from which allocations may occur */ @@ -57,21 +65,18 @@ extern unsigned long oom_badness(struct task_struct *p, extern int oom_kills_count(void); extern void note_oom_kill(void); -extern void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, +extern void oom_kill_process(struct oom_control *oc, struct task_struct *p, unsigned int points, unsigned long totalpages, - struct mem_cgroup *memcg, nodemask_t *nodemask, - const char *message); + struct mem_cgroup *memcg, const char *message); -extern void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask, - int order, const nodemask_t *nodemask, +extern void check_panic_on_oom(struct oom_control *oc, + enum oom_constraint constraint, struct mem_cgroup *memcg); -extern enum oom_scan_t oom_scan_process_thread(struct task_struct *task, - unsigned long totalpages, const nodemask_t *nodemask, - bool force_kill); +extern enum oom_scan_t oom_scan_process_thread(struct oom_control *oc, + struct task_struct *task, unsigned long totalpages); -extern bool out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, - int order, nodemask_t *mask, bool force_kill); +extern bool out_of_memory(struct oom_control *oc); extern void exit_oom_victim(void); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 1af057575ce9e..573d90347aa2d 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1545,6 +1545,13 @@ static unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg) static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, int order) { + struct oom_control oc = { + .zonelist = NULL, + .nodemask = NULL, + .gfp_mask = gfp_mask, + .order = order, + .force_kill = false, + }; struct mem_cgroup *iter; unsigned long chosen_points = 0; unsigned long totalpages; @@ -1563,7 +1570,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, goto unlock; } - check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, order, NULL, memcg); + check_panic_on_oom(&oc, CONSTRAINT_MEMCG, memcg); totalpages = mem_cgroup_get_limit(memcg) ? : 1; for_each_mem_cgroup_tree(iter, memcg) { struct css_task_iter it; @@ -1571,8 +1578,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, css_task_iter_start(&iter->css, &it); while ((task = css_task_iter_next(&it))) { - switch (oom_scan_process_thread(task, totalpages, NULL, - false)) { + switch (oom_scan_process_thread(&oc, task, totalpages)) { case OOM_SCAN_SELECT: if (chosen) put_task_struct(chosen); @@ -1610,8 +1616,8 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, if (chosen) { points = chosen_points * 1000 / totalpages; - oom_kill_process(chosen, gfp_mask, order, points, totalpages, - memcg, NULL, "Memory cgroup out of memory"); + oom_kill_process(&oc, chosen, points, totalpages, memcg, + "Memory cgroup out of memory"); } unlock: mutex_unlock(&oom_lock); diff --git a/mm/oom_kill.c b/mm/oom_kill.c index dff991e0681e8..80a7cbd89d664 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -196,27 +196,26 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg, * Determine the type of allocation constraint. */ #ifdef CONFIG_NUMA -static enum oom_constraint constrained_alloc(struct zonelist *zonelist, - gfp_t gfp_mask, nodemask_t *nodemask, - unsigned long *totalpages) +static enum oom_constraint constrained_alloc(struct oom_control *oc, + unsigned long *totalpages) { struct zone *zone; struct zoneref *z; - enum zone_type high_zoneidx = gfp_zone(gfp_mask); + enum zone_type high_zoneidx = gfp_zone(oc->gfp_mask); bool cpuset_limited = false; int nid; /* Default to all available memory */ *totalpages = totalram_pages + total_swap_pages; - if (!zonelist) + if (!oc->zonelist) return CONSTRAINT_NONE; /* * Reach here only when __GFP_NOFAIL is used. So, we should avoid * to kill current.We have to random task kill in this case. * Hopefully, CONSTRAINT_THISNODE...but no way to handle it, now. */ - if (gfp_mask & __GFP_THISNODE) + if (oc->gfp_mask & __GFP_THISNODE) return CONSTRAINT_NONE; /* @@ -224,17 +223,18 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist, * the page allocator means a mempolicy is in effect. Cpuset policy * is enforced in get_page_from_freelist(). */ - if (nodemask && !nodes_subset(node_states[N_MEMORY], *nodemask)) { + if (oc->nodemask && + !nodes_subset(node_states[N_MEMORY], *oc->nodemask)) { *totalpages = total_swap_pages; - for_each_node_mask(nid, *nodemask) + for_each_node_mask(nid, *oc->nodemask) *totalpages += node_spanned_pages(nid); return CONSTRAINT_MEMORY_POLICY; } /* Check this allocation failure is caused by cpuset's wall function */ - for_each_zone_zonelist_nodemask(zone, z, zonelist, - high_zoneidx, nodemask) - if (!cpuset_zone_allowed(zone, gfp_mask)) + for_each_zone_zonelist_nodemask(zone, z, oc->zonelist, + high_zoneidx, oc->nodemask) + if (!cpuset_zone_allowed(zone, oc->gfp_mask)) cpuset_limited = true; if (cpuset_limited) { @@ -246,20 +246,18 @@ static enum oom_constraint constrained_alloc(struct zonelist *zonelist, return CONSTRAINT_NONE; } #else -static enum oom_constraint constrained_alloc(struct zonelist *zonelist, - gfp_t gfp_mask, nodemask_t *nodemask, - unsigned long *totalpages) +static enum oom_constraint constrained_alloc(struct oom_control *oc, + unsigned long *totalpages) { *totalpages = totalram_pages + total_swap_pages; return CONSTRAINT_NONE; } #endif -enum oom_scan_t oom_scan_process_thread(struct task_struct *task, - unsigned long totalpages, const nodemask_t *nodemask, - bool force_kill) +enum oom_scan_t oom_scan_process_thread(struct oom_control *oc, + struct task_struct *task, unsigned long totalpages) { - if (oom_unkillable_task(task, NULL, nodemask)) + if (oom_unkillable_task(task, NULL, oc->nodemask)) return OOM_SCAN_CONTINUE; /* @@ -267,7 +265,7 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, * Don't allow any other task to have access to the reserves. */ if (test_tsk_thread_flag(task, TIF_MEMDIE)) { - if (!force_kill) + if (!oc->force_kill) return OOM_SCAN_ABORT; } if (!task->mm) @@ -280,7 +278,7 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, if (oom_task_origin(task)) return OOM_SCAN_SELECT; - if (task_will_free_mem(task) && !force_kill) + if (task_will_free_mem(task) && !oc->force_kill) return OOM_SCAN_ABORT; return OOM_SCAN_OK; @@ -289,12 +287,9 @@ enum oom_scan_t oom_scan_process_thread(struct task_struct *task, /* * Simple selection loop. We chose the process with the highest * number of 'points'. Returns -1 on scan abort. - * - * (not docbooked, we don't want this one cluttering up the manual) */ -static struct task_struct *select_bad_process(unsigned int *ppoints, - unsigned long totalpages, const nodemask_t *nodemask, - bool force_kill) +static struct task_struct *select_bad_process(struct oom_control *oc, + unsigned int *ppoints, unsigned long totalpages) { struct task_struct *g, *p; struct task_struct *chosen = NULL; @@ -304,8 +299,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, for_each_process_thread(g, p) { unsigned int points; - switch (oom_scan_process_thread(p, totalpages, nodemask, - force_kill)) { + switch (oom_scan_process_thread(oc, p, totalpages)) { case OOM_SCAN_SELECT: chosen = p; chosen_points = ULONG_MAX; @@ -318,7 +312,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints, case OOM_SCAN_OK: break; }; - points = oom_badness(p, NULL, nodemask, totalpages); + points = oom_badness(p, NULL, oc->nodemask, totalpages); if (!points || points < chosen_points) continue; /* Prefer thread group leaders for display purposes */ @@ -380,13 +374,13 @@ static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask) rcu_read_unlock(); } -static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, - struct mem_cgroup *memcg, const nodemask_t *nodemask) +static void dump_header(struct oom_control *oc, struct task_struct *p, + struct mem_cgroup *memcg) { task_lock(current); pr_warning("%s invoked oom-killer: gfp_mask=0x%x, order=%d, " "oom_score_adj=%hd\n", - current->comm, gfp_mask, order, + current->comm, oc->gfp_mask, oc->order, current->signal->oom_score_adj); cpuset_print_task_mems_allowed(current); task_unlock(current); @@ -396,7 +390,7 @@ static void dump_header(struct task_struct *p, gfp_t gfp_mask, int order, else show_mem(SHOW_MEM_FILTER_NODES); if (sysctl_oom_dump_tasks) - dump_tasks(memcg, nodemask); + dump_tasks(memcg, oc->nodemask); } /* @@ -487,10 +481,9 @@ void oom_killer_enable(void) * Must be called while holding a reference to p, which will be released upon * returning. */ -void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, +void oom_kill_process(struct oom_control *oc, struct task_struct *p, unsigned int points, unsigned long totalpages, - struct mem_cgroup *memcg, nodemask_t *nodemask, - const char *message) + struct mem_cgroup *memcg, const char *message) { struct task_struct *victim = p; struct task_struct *child; @@ -514,7 +507,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, task_unlock(p); if (__ratelimit(&oom_rs)) - dump_header(p, gfp_mask, order, memcg, nodemask); + dump_header(oc, p, memcg); task_lock(p); pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n", @@ -537,7 +530,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, /* * oom_badness() returns 0 if the thread is unkillable */ - child_points = oom_badness(child, memcg, nodemask, + child_points = oom_badness(child, memcg, oc->nodemask, totalpages); if (child_points > victim_points) { put_task_struct(victim); @@ -600,8 +593,7 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order, /* * Determines whether the kernel must panic because of the panic_on_oom sysctl. */ -void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask, - int order, const nodemask_t *nodemask, +void check_panic_on_oom(struct oom_control *oc, enum oom_constraint constraint, struct mem_cgroup *memcg) { if (likely(!sysctl_panic_on_oom)) @@ -615,7 +607,7 @@ void check_panic_on_oom(enum oom_constraint constraint, gfp_t gfp_mask, if (constraint != CONSTRAINT_NONE) return; } - dump_header(NULL, gfp_mask, order, memcg, nodemask); + dump_header(oc, NULL, memcg); panic("Out of memory: %s panic_on_oom is enabled\n", sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide"); } @@ -635,22 +627,16 @@ int unregister_oom_notifier(struct notifier_block *nb) EXPORT_SYMBOL_GPL(unregister_oom_notifier); /** - * __out_of_memory - kill the "best" process when we run out of memory - * @zonelist: zonelist pointer - * @gfp_mask: memory allocation flags - * @order: amount of memory being requested as a power of 2 - * @nodemask: nodemask passed to page allocator - * @force_kill: true if a task must be killed, even if others are exiting + * out_of_memory - kill the "best" process when we run out of memory + * @oc: pointer to struct oom_control * * If we run out of memory, we have the choice between either * killing a random task (bad), letting the system crash (worse) * OR try to be smart about which process to kill. Note that we * don't have to be perfect here, we just have to be good. */ -bool out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, - int order, nodemask_t *nodemask, bool force_kill) +bool out_of_memory(struct oom_control *oc) { - const nodemask_t *mpol_mask; struct task_struct *p; unsigned long totalpages; unsigned long freed = 0; @@ -684,30 +670,29 @@ bool out_of_memory(struct zonelist *zonelist, gfp_t gfp_mask, * Check if there were limitations on the allocation (only relevant for * NUMA) that may require different handling. */ - constraint = constrained_alloc(zonelist, gfp_mask, nodemask, - &totalpages); - mpol_mask = (constraint == CONSTRAINT_MEMORY_POLICY) ? nodemask : NULL; - check_panic_on_oom(constraint, gfp_mask, order, mpol_mask, NULL); + constraint = constrained_alloc(oc, &totalpages); + if (constraint != CONSTRAINT_MEMORY_POLICY) + oc->nodemask = NULL; + check_panic_on_oom(oc, constraint, NULL); if (sysctl_oom_kill_allocating_task && current->mm && - !oom_unkillable_task(current, NULL, nodemask) && + !oom_unkillable_task(current, NULL, oc->nodemask) && current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) { get_task_struct(current); - oom_kill_process(current, gfp_mask, order, 0, totalpages, NULL, - nodemask, + oom_kill_process(oc, current, 0, totalpages, NULL, "Out of memory (oom_kill_allocating_task)"); goto out; } - p = select_bad_process(&points, totalpages, mpol_mask, force_kill); + p = select_bad_process(oc, &points, totalpages); /* Found nothing?!?! Either we hang forever, or we panic. */ if (!p) { - dump_header(NULL, gfp_mask, order, NULL, mpol_mask); + dump_header(oc, NULL, NULL); panic("Out of memory and no killable processes...\n"); } if (p != (void *)-1UL) { - oom_kill_process(p, gfp_mask, order, points, totalpages, NULL, - nodemask, "Out of memory"); + oom_kill_process(oc, p, points, totalpages, NULL, + "Out of memory"); killed = 1; } out: @@ -728,13 +713,21 @@ out: */ void pagefault_out_of_memory(void) { + struct oom_control oc = { + .zonelist = NULL, + .nodemask = NULL, + .gfp_mask = 0, + .order = 0, + .force_kill = false, + }; + if (mem_cgroup_oom_synchronize(true)) return; if (!mutex_trylock(&oom_lock)) return; - if (!out_of_memory(NULL, 0, 0, NULL, false)) { + if (!out_of_memory(&oc)) { /* * There shouldn't be any user tasks runnable while the * OOM killer is disabled, so the current task has to diff --git a/mm/page_alloc.c b/mm/page_alloc.c index badc7d3bde433..96536144185c6 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2693,6 +2693,13 @@ static inline struct page * __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, const struct alloc_context *ac, unsigned long *did_some_progress) { + struct oom_control oc = { + .zonelist = ac->zonelist, + .nodemask = ac->nodemask, + .gfp_mask = gfp_mask, + .order = order, + .force_kill = false, + }; struct page *page; *did_some_progress = 0; @@ -2744,8 +2751,7 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, goto out; } /* Exhausted what can be done so it's blamo time */ - if (out_of_memory(ac->zonelist, gfp_mask, order, ac->nodemask, false) - || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) + if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) *did_some_progress = 1; out: mutex_unlock(&oom_lock); -- GitLab From 54e9e29132d7caefcad470281cae06ac34a982c8 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 8 Sep 2015 15:00:39 -0700 Subject: [PATCH 6710/7006] mm, oom: pass an oom order of -1 when triggered by sysrq The force_kill member of struct oom_control isn't needed if an order of -1 is used instead. This is the same as order == -1 in struct compact_control which requires full memory compaction. This patch introduces no functional change. Signed-off-by: David Rientjes Cc: Sergey Senozhatsky Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/tty/sysrq.c | 3 +-- include/linux/oom.h | 1 - mm/memcontrol.c | 1 - mm/oom_kill.c | 5 ++--- mm/page_alloc.c | 1 - 5 files changed, 3 insertions(+), 8 deletions(-) diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c index ed3e258f4ee9f..95b330a9ea983 100644 --- a/drivers/tty/sysrq.c +++ b/drivers/tty/sysrq.c @@ -358,8 +358,7 @@ static void moom_callback(struct work_struct *ignored) .zonelist = node_zonelist(first_memory_node, gfp_mask), .nodemask = NULL, .gfp_mask = gfp_mask, - .order = 0, - .force_kill = true, + .order = -1, }; mutex_lock(&oom_lock); diff --git a/include/linux/oom.h b/include/linux/oom.h index cb29085ded371..8fb67b9e61100 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -17,7 +17,6 @@ struct oom_control { nodemask_t *nodemask; gfp_t gfp_mask; int order; - bool force_kill; }; /* diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 573d90347aa2d..9871f13fc35bd 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -1550,7 +1550,6 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask, .nodemask = NULL, .gfp_mask = gfp_mask, .order = order, - .force_kill = false, }; struct mem_cgroup *iter; unsigned long chosen_points = 0; diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 80a7cbd89d664..77adc8e876aa2 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -265,7 +265,7 @@ enum oom_scan_t oom_scan_process_thread(struct oom_control *oc, * Don't allow any other task to have access to the reserves. */ if (test_tsk_thread_flag(task, TIF_MEMDIE)) { - if (!oc->force_kill) + if (oc->order != -1) return OOM_SCAN_ABORT; } if (!task->mm) @@ -278,7 +278,7 @@ enum oom_scan_t oom_scan_process_thread(struct oom_control *oc, if (oom_task_origin(task)) return OOM_SCAN_SELECT; - if (task_will_free_mem(task) && !oc->force_kill) + if (task_will_free_mem(task) && oc->order != -1) return OOM_SCAN_ABORT; return OOM_SCAN_OK; @@ -718,7 +718,6 @@ void pagefault_out_of_memory(void) .nodemask = NULL, .gfp_mask = 0, .order = 0, - .force_kill = false, }; if (mem_cgroup_oom_synchronize(true)) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 96536144185c6..5f9394df19bf4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -2698,7 +2698,6 @@ __alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, .nodemask = ac->nodemask, .gfp_mask = gfp_mask, .order = order, - .force_kill = false, }; struct page *page; -- GitLab From 071a4befebb655d6b31bf5c6bacd5a6df035224d Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 8 Sep 2015 15:00:42 -0700 Subject: [PATCH 6711/7006] mm, oom: do not panic for oom kills triggered from sysrq Sysrq+f is used to kill a process either for debug or when the VM is otherwise unresponsive. It is not intended to trigger a panic when no process may be killed. Avoid panicking the system for sysrq+f when no processes are killed. Signed-off-by: David Rientjes Suggested-by: Michal Hocko Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysrq.txt | 3 ++- mm/oom_kill.c | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt index 267f39386f99f..13f5619b2203e 100644 --- a/Documentation/sysrq.txt +++ b/Documentation/sysrq.txt @@ -75,7 +75,8 @@ On all - write a character to /proc/sysrq-trigger. e.g.: 'e' - Send a SIGTERM to all processes, except for init. -'f' - Will call oom_kill to kill a memory hog process. +'f' - Will call the oom killer to kill a memory hog process, but do not + panic if nothing can be killed. 'g' - Used by kgdb (kernel debugger) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 77adc8e876aa2..91dd59f63910e 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -607,6 +607,9 @@ void check_panic_on_oom(struct oom_control *oc, enum oom_constraint constraint, if (constraint != CONSTRAINT_NONE) return; } + /* Do not panic for oom kills triggered by sysrq */ + if (oc->order == -1) + return; dump_header(oc, NULL, memcg); panic("Out of memory: %s panic_on_oom is enabled\n", sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide"); @@ -686,11 +689,11 @@ bool out_of_memory(struct oom_control *oc) p = select_bad_process(oc, &points, totalpages); /* Found nothing?!?! Either we hang forever, or we panic. */ - if (!p) { + if (!p && oc->order != -1) { dump_header(oc, NULL, NULL); panic("Out of memory and no killable processes...\n"); } - if (p != (void *)-1UL) { + if (p && p != (void *)-1UL) { oom_kill_process(oc, p, points, totalpages, NULL, "Out of memory"); killed = 1; -- GitLab From 8989e4c7d4e3c30b55c998a1138cd06c92df7295 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 8 Sep 2015 15:00:44 -0700 Subject: [PATCH 6712/7006] mm, oom: add description of struct oom_control Describe the purpose of struct oom_control and what each member does. Also make gfp_mask and order const since they are never manipulated or passed to functions that discard the qualifier. Signed-off-by: David Rientjes Cc: Michal Hocko Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/oom.h | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/include/linux/oom.h b/include/linux/oom.h index 8fb67b9e61100..03e6257321f03 100644 --- a/include/linux/oom.h +++ b/include/linux/oom.h @@ -12,11 +12,25 @@ struct notifier_block; struct mem_cgroup; struct task_struct; +/* + * Details of the page allocation that triggered the oom killer that are used to + * determine what should be killed. + */ struct oom_control { + /* Used to determine cpuset */ struct zonelist *zonelist; - nodemask_t *nodemask; - gfp_t gfp_mask; - int order; + + /* Used to determine mempolicy */ + nodemask_t *nodemask; + + /* Used to determine cpuset and node locality requirement */ + const gfp_t gfp_mask; + + /* + * order == -1 means the oom kill is required by sysrq, otherwise only + * for display purposes. + */ + const int order; }; /* -- GitLab From 75e8f8b24cb0dc4951267d31f0a49e5ce2f345c4 Mon Sep 17 00:00:00 2001 From: David Rientjes Date: Tue, 8 Sep 2015 15:00:47 -0700 Subject: [PATCH 6713/7006] mm, oom: remove unnecessary variable The "killed" variable in out_of_memory() can be removed since the call to oom_kill_process() where we should block to allow the process time to exit is obvious. Signed-off-by: David Rientjes Acked-by: Michal Hocko Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/oom_kill.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/mm/oom_kill.c b/mm/oom_kill.c index 91dd59f63910e..1ecc0bcaecc51 100644 --- a/mm/oom_kill.c +++ b/mm/oom_kill.c @@ -645,7 +645,6 @@ bool out_of_memory(struct oom_control *oc) unsigned long freed = 0; unsigned int uninitialized_var(points); enum oom_constraint constraint = CONSTRAINT_NONE; - int killed = 0; if (oom_killer_disabled) return false; @@ -653,7 +652,7 @@ bool out_of_memory(struct oom_control *oc) blocking_notifier_call_chain(&oom_notify_list, 0, &freed); if (freed > 0) /* Got some memory back in the last second. */ - goto out; + return true; /* * If current has a pending SIGKILL or is exiting, then automatically @@ -666,7 +665,7 @@ bool out_of_memory(struct oom_control *oc) if (current->mm && (fatal_signal_pending(current) || task_will_free_mem(current))) { mark_oom_victim(current); - goto out; + return true; } /* @@ -684,7 +683,7 @@ bool out_of_memory(struct oom_control *oc) get_task_struct(current); oom_kill_process(oc, current, 0, totalpages, NULL, "Out of memory (oom_kill_allocating_task)"); - goto out; + return true; } p = select_bad_process(oc, &points, totalpages); @@ -696,16 +695,12 @@ bool out_of_memory(struct oom_control *oc) if (p && p != (void *)-1UL) { oom_kill_process(oc, p, points, totalpages, NULL, "Out of memory"); - killed = 1; - } -out: - /* - * Give the killed threads a good chance of exiting before trying to - * allocate memory again. - */ - if (killed) + /* + * Give the killed process a good chance to exit before trying + * to allocate memory again. + */ schedule_timeout_killable(1); - + } return true; } -- GitLab From 3942d29918522ba6a393c19388301ec04df429cd Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:00:50 -0700 Subject: [PATCH 6714/7006] mm/slab_common: allow NULL cache pointer in kmem_cache_destroy() kmem_cache_destroy() does not tolerate a NULL kmem_cache pointer argument and performs a NULL-pointer dereference. This requires additional attention and effort from developers/reviewers and forces all kmem_cache_destroy() callers (200+ as of 4.1) to do a NULL check if (cache) kmem_cache_destroy(cache); Or, otherwise, be invalid kmem_cache_destroy() users. Tweak kmem_cache_destroy() and NULL-check the pointer there. Proposed by Andrew Morton. Link: https://lkml.org/lkml/2015/6/8/583 Signed-off-by: Sergey Senozhatsky Acked-by: David Rientjes Cc: Julia Lawall Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/slab_common.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/slab_common.c b/mm/slab_common.c index c26829fe4e37e..bde04a699ab63 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -640,6 +640,9 @@ void kmem_cache_destroy(struct kmem_cache *s) bool need_rcu_barrier = false; bool busy = false; + if (unlikely(!s)) + return; + BUG_ON(!is_root_cache(s)); get_online_cpus(); -- GitLab From 4e3ca3e033d1eea62fa16c3fdbef4f20427bd0de Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:00:53 -0700 Subject: [PATCH 6715/7006] mm/mempool: allow NULL `pool' pointer in mempool_destroy() mempool_destroy() does not tolerate a NULL mempool_t pointer argument and performs a NULL-pointer dereference. This requires additional attention and effort from developers/reviewers and forces all mempool_destroy() callers to do a NULL check if (pool) mempool_destroy(pool); Or, otherwise, be invalid mempool_destroy() users. Tweak mempool_destroy() and NULL-check the pointer there. Proposed by Andrew Morton. Link: https://lkml.org/lkml/2015/6/8/583 Signed-off-by: Sergey Senozhatsky Acked-by: David Rientjes Cc: Julia Lawall Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempool.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/mempool.c b/mm/mempool.c index 2cc08de8b1db2..4c533bc51d733 100644 --- a/mm/mempool.c +++ b/mm/mempool.c @@ -150,6 +150,9 @@ static void *remove_element(mempool_t *pool) */ void mempool_destroy(mempool_t *pool) { + if (unlikely(!pool)) + return; + while (pool->curr_nr) { void *element = remove_element(pool); pool->free(element, pool->pool_data); -- GitLab From 44d7175da6ea10e353e69b586bb68bbfef89e403 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:00:56 -0700 Subject: [PATCH 6716/7006] mm/dmapool: allow NULL `pool' pointer in dma_pool_destroy() dma_pool_destroy() does not tolerate a NULL dma_pool pointer argument and performs a NULL-pointer dereference. This requires additional attention and effort from developers/reviewers and forces all dma_pool_destroy() callers to do a NULL check if (pool) dma_pool_destroy(pool); Or, otherwise, be invalid dma_pool_destroy() users. Tweak dma_pool_destroy() and NULL-check the pointer there. Proposed by Andrew Morton. Link: https://lkml.org/lkml/2015/6/8/583 Signed-off-by: Sergey Senozhatsky Acked-by: David Rientjes Cc: Julia Lawall Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/dmapool.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mm/dmapool.c b/mm/dmapool.c index 59d10d16f0a5d..4b657099111f8 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -271,6 +271,9 @@ void dma_pool_destroy(struct dma_pool *pool) { bool empty = false; + if (unlikely(!pool)) + return; + mutex_lock(&pools_reg_lock); mutex_lock(&pools_lock); list_del(&pool->pools); -- GitLab From b3d9ed3fd872fc074286674ae8595ee880938bbf Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Sep 2015 15:00:59 -0700 Subject: [PATCH 6717/7006] sparc32: do not include swap.h from pgtable_32.h "memcg: export struct mem_cgroup" will add includes into linux/memcontrol.h which lead to further header dependency issues as reported by Guenter Roeck: In file included from include/linux/highmem.h:7:0, from include/linux/bio.h:23, from include/linux/writeback.h:192, from include/linux/memcontrol.h:30, from include/linux/swap.h:8, from ./arch/sparc/include/asm/pgtable_32.h:17, from ./arch/sparc/include/asm/pgtable.h:6, from arch/sparc/kernel/traps_32.c:23: include/linux/mm.h: In function 'is_vmalloc_addr': include/linux/mm.h:371:17: error: 'VMALLOC_START' undeclared (first use in this function) include/linux/mm.h:371:17: note: each undeclared identifier is reported only once for each function it appears in include/linux/mm.h:371:41: error: 'VMALLOC_END' undeclared (first use in this function) include/linux/mm.h: In function 'maybe_mkwrite': include/linux/mm.h:556:3: error: implicit declaration of function 'pte_mkwrite' The issue is that pgtable_32.h depends on swap.h to get swap_entry_t but that goes all the way down to linux/mm.h which wants to have VMALLOC_* which is defined later in pgtable_32.h, though. swap_entry_t is defined in include/mm_types.h so it should be sufficient to include this header without more dependencies. Signed-off-by: Michal Hocko Reported-by: Guenter Roeck Tested-by: Guenter Roeck Cc: David Miller Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/sparc/include/asm/pgtable_32.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/sparc/include/asm/pgtable_32.h b/arch/sparc/include/asm/pgtable_32.h index f06b36a00a3b1..91b963a887b78 100644 --- a/arch/sparc/include/asm/pgtable_32.h +++ b/arch/sparc/include/asm/pgtable_32.h @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include -- GitLab From 33398cf2f360c5ce24c8a22436d52a06ad4e5eb5 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Sep 2015 15:01:02 -0700 Subject: [PATCH 6718/7006] memcg: export struct mem_cgroup mem_cgroup structure is defined in mm/memcontrol.c currently which means that the code outside of this file has to use external API even for trivial access stuff. This patch exports mm_struct with its dependencies and makes some of the exported functions inlines. This even helps to reduce the code size a bit (make defconfig + CONFIG_MEMCG=y) text data bss dec hex filename 12355346 1823792 1089536 15268674 e8fb42 vmlinux.before 12354970 1823792 1089536 15268298 e8f9ca vmlinux.after This is not much (370B) but better than nothing. We also save a function call in some hot paths like callers of mem_cgroup_count_vm_event which is used for accounting. The patch doesn't introduce any functional changes. [vdavykov@parallels.com: inline memcg_kmem_is_active] [vdavykov@parallels.com: do not expose type outside of CONFIG_MEMCG] [akpm@linux-foundation.org: memcontrol.h needs eventfd.h for eventfd_ctx] [akpm@linux-foundation.org: export mem_cgroup_from_task() to modules] Signed-off-by: Michal Hocko Reviewed-by: Vladimir Davydov Suggested-by: Johannes Weiner Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memcontrol.h | 370 +++++++++++++++++++++++++++++++++---- include/linux/swap.h | 10 +- include/net/sock.h | 28 --- mm/memcontrol.c | 315 +------------------------------ mm/memory-failure.c | 2 +- mm/slab_common.c | 2 +- mm/vmscan.c | 2 +- 7 files changed, 351 insertions(+), 378 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 73b02b0a8f609..ab2f6880e27b2 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -23,6 +23,11 @@ #include #include #include +#include +#include +#include +#include +#include struct mem_cgroup; struct page; @@ -67,12 +72,221 @@ enum mem_cgroup_events_index { MEMCG_NR_EVENTS, }; +/* + * Per memcg event counter is incremented at every pagein/pageout. With THP, + * it will be incremated by the number of pages. This counter is used for + * for trigger some periodic events. This is straightforward and better + * than using jiffies etc. to handle periodic memcg event. + */ +enum mem_cgroup_events_target { + MEM_CGROUP_TARGET_THRESH, + MEM_CGROUP_TARGET_SOFTLIMIT, + MEM_CGROUP_TARGET_NUMAINFO, + MEM_CGROUP_NTARGETS, +}; + +/* + * Bits in struct cg_proto.flags + */ +enum cg_proto_flags { + /* Currently active and new sockets should be assigned to cgroups */ + MEMCG_SOCK_ACTIVE, + /* It was ever activated; we must disarm static keys on destruction */ + MEMCG_SOCK_ACTIVATED, +}; + +struct cg_proto { + struct page_counter memory_allocated; /* Current allocated memory. */ + struct percpu_counter sockets_allocated; /* Current number of sockets. */ + int memory_pressure; + long sysctl_mem[3]; + unsigned long flags; + /* + * memcg field is used to find which memcg we belong directly + * Each memcg struct can hold more than one cg_proto, so container_of + * won't really cut. + * + * The elegant solution would be having an inverse function to + * proto_cgroup in struct proto, but that means polluting the structure + * for everybody, instead of just for memcg users. + */ + struct mem_cgroup *memcg; +}; + #ifdef CONFIG_MEMCG +struct mem_cgroup_stat_cpu { + long count[MEM_CGROUP_STAT_NSTATS]; + unsigned long events[MEMCG_NR_EVENTS]; + unsigned long nr_page_events; + unsigned long targets[MEM_CGROUP_NTARGETS]; +}; + +struct mem_cgroup_reclaim_iter { + struct mem_cgroup *position; + /* scan generation, increased every round-trip */ + unsigned int generation; +}; + +/* + * per-zone information in memory controller. + */ +struct mem_cgroup_per_zone { + struct lruvec lruvec; + unsigned long lru_size[NR_LRU_LISTS]; + + struct mem_cgroup_reclaim_iter iter[DEF_PRIORITY + 1]; + + struct rb_node tree_node; /* RB tree node */ + unsigned long usage_in_excess;/* Set to the value by which */ + /* the soft limit is exceeded*/ + bool on_tree; + struct mem_cgroup *memcg; /* Back pointer, we cannot */ + /* use container_of */ +}; + +struct mem_cgroup_per_node { + struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES]; +}; + +struct mem_cgroup_threshold { + struct eventfd_ctx *eventfd; + unsigned long threshold; +}; + +/* For threshold */ +struct mem_cgroup_threshold_ary { + /* An array index points to threshold just below or equal to usage. */ + int current_threshold; + /* Size of entries[] */ + unsigned int size; + /* Array of thresholds */ + struct mem_cgroup_threshold entries[0]; +}; + +struct mem_cgroup_thresholds { + /* Primary thresholds array */ + struct mem_cgroup_threshold_ary *primary; + /* + * Spare threshold array. + * This is needed to make mem_cgroup_unregister_event() "never fail". + * It must be able to store at least primary->size - 1 entries. + */ + struct mem_cgroup_threshold_ary *spare; +}; + +/* + * The memory controller data structure. The memory controller controls both + * page cache and RSS per cgroup. We would eventually like to provide + * statistics based on the statistics developed by Rik Van Riel for clock-pro, + * to help the administrator determine what knobs to tune. + */ +struct mem_cgroup { + struct cgroup_subsys_state css; + + /* Accounted resources */ + struct page_counter memory; + struct page_counter memsw; + struct page_counter kmem; + + /* Normal memory consumption range */ + unsigned long low; + unsigned long high; + + unsigned long soft_limit; + + /* vmpressure notifications */ + struct vmpressure vmpressure; + + /* css_online() has been completed */ + int initialized; + + /* + * Should the accounting and control be hierarchical, per subtree? + */ + bool use_hierarchy; + + /* protected by memcg_oom_lock */ + bool oom_lock; + int under_oom; + + int swappiness; + /* OOM-Killer disable */ + int oom_kill_disable; + + /* protect arrays of thresholds */ + struct mutex thresholds_lock; + + /* thresholds for memory usage. RCU-protected */ + struct mem_cgroup_thresholds thresholds; + + /* thresholds for mem+swap usage. RCU-protected */ + struct mem_cgroup_thresholds memsw_thresholds; + + /* For oom notifier event fd */ + struct list_head oom_notify; + + /* + * Should we move charges of a task when a task is moved into this + * mem_cgroup ? And what type of charges should we move ? + */ + unsigned long move_charge_at_immigrate; + /* + * set > 0 if pages under this cgroup are moving to other cgroup. + */ + atomic_t moving_account; + /* taken only while moving_account > 0 */ + spinlock_t move_lock; + struct task_struct *move_lock_task; + unsigned long move_lock_flags; + /* + * percpu counter. + */ + struct mem_cgroup_stat_cpu __percpu *stat; + spinlock_t pcp_counter_lock; + +#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET) + struct cg_proto tcp_mem; +#endif +#if defined(CONFIG_MEMCG_KMEM) + /* Index in the kmem_cache->memcg_params.memcg_caches array */ + int kmemcg_id; + bool kmem_acct_activated; + bool kmem_acct_active; +#endif + + int last_scanned_node; +#if MAX_NUMNODES > 1 + nodemask_t scan_nodes; + atomic_t numainfo_events; + atomic_t numainfo_updating; +#endif + +#ifdef CONFIG_CGROUP_WRITEBACK + struct list_head cgwb_list; + struct wb_domain cgwb_domain; +#endif + + /* List of events which userspace want to receive */ + struct list_head event_list; + spinlock_t event_list_lock; + + struct mem_cgroup_per_node *nodeinfo[0]; + /* WARNING: nodeinfo must be the last member here */ +}; extern struct cgroup_subsys_state *mem_cgroup_root_css; -void mem_cgroup_events(struct mem_cgroup *memcg, +/** + * mem_cgroup_events - count memory events against a cgroup + * @memcg: the memory cgroup + * @idx: the event index + * @nr: the number of events to account for + */ +static inline void mem_cgroup_events(struct mem_cgroup *memcg, enum mem_cgroup_events_index idx, - unsigned int nr); + unsigned int nr) +{ + this_cpu_add(memcg->stat->events[idx], nr); +} bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg); @@ -90,15 +304,31 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage, struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *); struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *); -bool mem_cgroup_is_descendant(struct mem_cgroup *memcg, - struct mem_cgroup *root); bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg); extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); -extern struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css); +static inline +struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){ + return css ? container_of(css, struct mem_cgroup, css) : NULL; +} + +struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *, + struct mem_cgroup *, + struct mem_cgroup_reclaim_cookie *); +void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *); + +static inline bool mem_cgroup_is_descendant(struct mem_cgroup *memcg, + struct mem_cgroup *root) +{ + if (root == memcg) + return true; + if (!root->use_hierarchy) + return false; + return cgroup_is_descendant(memcg->css.cgroup, root->css.cgroup); +} static inline bool mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *memcg) @@ -114,22 +344,65 @@ static inline bool mm_match_cgroup(struct mm_struct *mm, return match; } -extern struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg); extern struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page); -struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *, - struct mem_cgroup *, - struct mem_cgroup_reclaim_cookie *); -void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *); +static inline bool mem_cgroup_disabled(void) +{ + if (memory_cgrp_subsys.disabled) + return true; + return false; +} /* * For memory reclaim. */ -int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec); -bool mem_cgroup_lruvec_online(struct lruvec *lruvec); int mem_cgroup_select_victim_node(struct mem_cgroup *memcg); -unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list); -void mem_cgroup_update_lru_size(struct lruvec *, enum lru_list, int); + +void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, + int nr_pages); + +static inline bool mem_cgroup_lruvec_online(struct lruvec *lruvec) +{ + struct mem_cgroup_per_zone *mz; + struct mem_cgroup *memcg; + + if (mem_cgroup_disabled()) + return true; + + mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); + memcg = mz->memcg; + + return !!(memcg->css.flags & CSS_ONLINE); +} + +static inline +unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) +{ + struct mem_cgroup_per_zone *mz; + + mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); + return mz->lru_size[lru]; +} + +static inline int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec) +{ + unsigned long inactive_ratio; + unsigned long inactive; + unsigned long active; + unsigned long gb; + + inactive = mem_cgroup_get_lru_size(lruvec, LRU_INACTIVE_ANON); + active = mem_cgroup_get_lru_size(lruvec, LRU_ACTIVE_ANON); + + gb = (inactive + active) >> (30 - PAGE_SHIFT); + if (gb) + inactive_ratio = int_sqrt(10 * gb); + else + inactive_ratio = 1; + + return inactive * inactive_ratio < active; +} + extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p); @@ -156,18 +429,26 @@ bool mem_cgroup_oom_synchronize(bool wait); extern int do_swap_account; #endif -static inline bool mem_cgroup_disabled(void) -{ - if (memory_cgrp_subsys.disabled) - return true; - return false; -} - struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page); -void mem_cgroup_update_page_stat(struct mem_cgroup *memcg, - enum mem_cgroup_stat_index idx, int val); void mem_cgroup_end_page_stat(struct mem_cgroup *memcg); +/** + * mem_cgroup_update_page_stat - update page state statistics + * @memcg: memcg to account against + * @idx: page state item to account + * @val: number of pages (positive or negative) + * + * See mem_cgroup_begin_page_stat() for locking requirements. + */ +static inline void mem_cgroup_update_page_stat(struct mem_cgroup *memcg, + enum mem_cgroup_stat_index idx, int val) +{ + VM_BUG_ON(!rcu_read_lock_held()); + + if (memcg) + this_cpu_add(memcg->stat->count[idx], val); +} + static inline void mem_cgroup_inc_page_stat(struct mem_cgroup *memcg, enum mem_cgroup_stat_index idx) { @@ -184,13 +465,31 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order, gfp_t gfp_mask, unsigned long *total_scanned); -void __mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx); static inline void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx) { + struct mem_cgroup *memcg; + if (mem_cgroup_disabled()) return; - __mem_cgroup_count_vm_event(mm, idx); + + rcu_read_lock(); + memcg = mem_cgroup_from_task(rcu_dereference(mm->owner)); + if (unlikely(!memcg)) + goto out; + + switch (idx) { + case PGFAULT: + this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT]); + break; + case PGMAJFAULT: + this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT]); + break; + default: + BUG(); + } +out: + rcu_read_unlock(); } #ifdef CONFIG_TRANSPARENT_HUGEPAGE void mem_cgroup_split_huge_fixup(struct page *head); @@ -275,12 +574,6 @@ static inline bool task_in_mem_cgroup(struct task_struct *task, return true; } -static inline struct cgroup_subsys_state - *mem_cgroup_css(struct mem_cgroup *memcg) -{ - return NULL; -} - static inline struct mem_cgroup * mem_cgroup_iter(struct mem_cgroup *root, struct mem_cgroup *prev, @@ -444,7 +737,10 @@ static inline bool memcg_kmem_enabled(void) return static_key_false(&memcg_kmem_enabled_key); } -bool memcg_kmem_is_active(struct mem_cgroup *memcg); +static inline bool memcg_kmem_is_active(struct mem_cgroup *memcg) +{ + return memcg->kmem_acct_active; +} /* * In general, we'll do everything in our power to not incur in any overhead @@ -463,7 +759,15 @@ void __memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, int order); void __memcg_kmem_uncharge_pages(struct page *page, int order); -int memcg_cache_id(struct mem_cgroup *memcg); +/* + * helper for acessing a memcg's index. It will be used as an index in the + * child cache array in kmem_cache, and also to derive its name. This function + * will return -1 when this is not a kmem-limited memcg. + */ +static inline int memcg_cache_id(struct mem_cgroup *memcg) +{ + return memcg ? memcg->kmemcg_id : -1; +} struct kmem_cache *__memcg_kmem_get_cache(struct kmem_cache *cachep); void __memcg_kmem_put_cache(struct kmem_cache *cachep); diff --git a/include/linux/swap.h b/include/linux/swap.h index 6282f1eb3d6a3..2ce190709280f 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -351,7 +351,15 @@ extern void check_move_unevictable_pages(struct page **, int nr_pages); extern int kswapd_run(int nid); extern void kswapd_stop(int nid); #ifdef CONFIG_MEMCG -extern int mem_cgroup_swappiness(struct mem_cgroup *mem); +static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg) +{ + /* root ? */ + if (mem_cgroup_disabled() || !memcg->css.parent) + return vm_swappiness; + + return memcg->swappiness; +} + #else static inline int mem_cgroup_swappiness(struct mem_cgroup *mem) { diff --git a/include/net/sock.h b/include/net/sock.h index 43c6abcf06abc..a98c71ea40c5b 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1042,34 +1042,6 @@ struct proto { #endif }; -/* - * Bits in struct cg_proto.flags - */ -enum cg_proto_flags { - /* Currently active and new sockets should be assigned to cgroups */ - MEMCG_SOCK_ACTIVE, - /* It was ever activated; we must disarm static keys on destruction */ - MEMCG_SOCK_ACTIVATED, -}; - -struct cg_proto { - struct page_counter memory_allocated; /* Current allocated memory. */ - struct percpu_counter sockets_allocated; /* Current number of sockets. */ - int memory_pressure; - long sysctl_mem[3]; - unsigned long flags; - /* - * memcg field is used to find which memcg we belong directly - * Each memcg struct can hold more than one cg_proto, so container_of - * won't really cut. - * - * The elegant solution would be having an inverse function to - * proto_cgroup in struct proto, but that means polluting the structure - * for everybody, instead of just for memcg users. - */ - struct mem_cgroup *memcg; -}; - int proto_register(struct proto *prot, int alloc_slab); void proto_unregister(struct proto *prot); diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 9871f13fc35bd..6935f77589e70 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -111,56 +111,10 @@ static const char * const mem_cgroup_lru_names[] = { "unevictable", }; -/* - * Per memcg event counter is incremented at every pagein/pageout. With THP, - * it will be incremated by the number of pages. This counter is used for - * for trigger some periodic events. This is straightforward and better - * than using jiffies etc. to handle periodic memcg event. - */ -enum mem_cgroup_events_target { - MEM_CGROUP_TARGET_THRESH, - MEM_CGROUP_TARGET_SOFTLIMIT, - MEM_CGROUP_TARGET_NUMAINFO, - MEM_CGROUP_NTARGETS, -}; #define THRESHOLDS_EVENTS_TARGET 128 #define SOFTLIMIT_EVENTS_TARGET 1024 #define NUMAINFO_EVENTS_TARGET 1024 -struct mem_cgroup_stat_cpu { - long count[MEM_CGROUP_STAT_NSTATS]; - unsigned long events[MEMCG_NR_EVENTS]; - unsigned long nr_page_events; - unsigned long targets[MEM_CGROUP_NTARGETS]; -}; - -struct reclaim_iter { - struct mem_cgroup *position; - /* scan generation, increased every round-trip */ - unsigned int generation; -}; - -/* - * per-zone information in memory controller. - */ -struct mem_cgroup_per_zone { - struct lruvec lruvec; - unsigned long lru_size[NR_LRU_LISTS]; - - struct reclaim_iter iter[DEF_PRIORITY + 1]; - - struct rb_node tree_node; /* RB tree node */ - unsigned long usage_in_excess;/* Set to the value by which */ - /* the soft limit is exceeded*/ - bool on_tree; - struct mem_cgroup *memcg; /* Back pointer, we cannot */ - /* use container_of */ -}; - -struct mem_cgroup_per_node { - struct mem_cgroup_per_zone zoneinfo[MAX_NR_ZONES]; -}; - /* * Cgroups above their limits are maintained in a RB-Tree, independent of * their hierarchy representation @@ -181,32 +135,6 @@ struct mem_cgroup_tree { static struct mem_cgroup_tree soft_limit_tree __read_mostly; -struct mem_cgroup_threshold { - struct eventfd_ctx *eventfd; - unsigned long threshold; -}; - -/* For threshold */ -struct mem_cgroup_threshold_ary { - /* An array index points to threshold just below or equal to usage. */ - int current_threshold; - /* Size of entries[] */ - unsigned int size; - /* Array of thresholds */ - struct mem_cgroup_threshold entries[0]; -}; - -struct mem_cgroup_thresholds { - /* Primary thresholds array */ - struct mem_cgroup_threshold_ary *primary; - /* - * Spare threshold array. - * This is needed to make mem_cgroup_unregister_event() "never fail". - * It must be able to store at least primary->size - 1 entries. - */ - struct mem_cgroup_threshold_ary *spare; -}; - /* for OOM */ struct mem_cgroup_eventfd_list { struct list_head list; @@ -256,113 +184,6 @@ struct mem_cgroup_event { static void mem_cgroup_threshold(struct mem_cgroup *memcg); static void mem_cgroup_oom_notify(struct mem_cgroup *memcg); -/* - * The memory controller data structure. The memory controller controls both - * page cache and RSS per cgroup. We would eventually like to provide - * statistics based on the statistics developed by Rik Van Riel for clock-pro, - * to help the administrator determine what knobs to tune. - */ -struct mem_cgroup { - struct cgroup_subsys_state css; - - /* Accounted resources */ - struct page_counter memory; - struct page_counter memsw; - struct page_counter kmem; - - /* Normal memory consumption range */ - unsigned long low; - unsigned long high; - - unsigned long soft_limit; - - /* vmpressure notifications */ - struct vmpressure vmpressure; - - /* css_online() has been completed */ - int initialized; - - /* - * Should the accounting and control be hierarchical, per subtree? - */ - bool use_hierarchy; - - /* protected by memcg_oom_lock */ - bool oom_lock; - int under_oom; - - int swappiness; - /* OOM-Killer disable */ - int oom_kill_disable; - - /* protect arrays of thresholds */ - struct mutex thresholds_lock; - - /* thresholds for memory usage. RCU-protected */ - struct mem_cgroup_thresholds thresholds; - - /* thresholds for mem+swap usage. RCU-protected */ - struct mem_cgroup_thresholds memsw_thresholds; - - /* For oom notifier event fd */ - struct list_head oom_notify; - - /* - * Should we move charges of a task when a task is moved into this - * mem_cgroup ? And what type of charges should we move ? - */ - unsigned long move_charge_at_immigrate; - /* - * set > 0 if pages under this cgroup are moving to other cgroup. - */ - atomic_t moving_account; - /* taken only while moving_account > 0 */ - spinlock_t move_lock; - struct task_struct *move_lock_task; - unsigned long move_lock_flags; - /* - * percpu counter. - */ - struct mem_cgroup_stat_cpu __percpu *stat; - spinlock_t pcp_counter_lock; - -#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET) - struct cg_proto tcp_mem; -#endif -#if defined(CONFIG_MEMCG_KMEM) - /* Index in the kmem_cache->memcg_params.memcg_caches array */ - int kmemcg_id; - bool kmem_acct_activated; - bool kmem_acct_active; -#endif - - int last_scanned_node; -#if MAX_NUMNODES > 1 - nodemask_t scan_nodes; - atomic_t numainfo_events; - atomic_t numainfo_updating; -#endif - -#ifdef CONFIG_CGROUP_WRITEBACK - struct list_head cgwb_list; - struct wb_domain cgwb_domain; -#endif - - /* List of events which userspace want to receive */ - struct list_head event_list; - spinlock_t event_list_lock; - - struct mem_cgroup_per_node *nodeinfo[0]; - /* WARNING: nodeinfo must be the last member here */ -}; - -#ifdef CONFIG_MEMCG_KMEM -bool memcg_kmem_is_active(struct mem_cgroup *memcg) -{ - return memcg->kmem_acct_active; -} -#endif - /* Stuffs for move charges at task migration. */ /* * Types of charges to be moved. @@ -423,11 +244,6 @@ enum res_type { */ static DEFINE_MUTEX(memcg_create_mutex); -struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *s) -{ - return s ? container_of(s, struct mem_cgroup, css) : NULL; -} - /* Some nice accessors for the vmpressure. */ struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg) { @@ -593,11 +409,6 @@ mem_cgroup_zone_zoneinfo(struct mem_cgroup *memcg, struct zone *zone) return &memcg->nodeinfo[nid]->zoneinfo[zid]; } -struct cgroup_subsys_state *mem_cgroup_css(struct mem_cgroup *memcg) -{ - return &memcg->css; -} - /** * mem_cgroup_css_from_page - css of the memcg associated with a page * @page: page of interest @@ -876,14 +687,6 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg, __this_cpu_add(memcg->stat->nr_page_events, nr_pages); } -unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) -{ - struct mem_cgroup_per_zone *mz; - - mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); - return mz->lru_size[lru]; -} - static unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, int nid, unsigned int lru_mask) @@ -986,6 +789,7 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p) return mem_cgroup_from_css(task_css(p, memory_cgrp_id)); } +EXPORT_SYMBOL(mem_cgroup_from_task); static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm) { @@ -1031,7 +835,7 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root, struct mem_cgroup *prev, struct mem_cgroup_reclaim_cookie *reclaim) { - struct reclaim_iter *uninitialized_var(iter); + struct mem_cgroup_reclaim_iter *uninitialized_var(iter); struct cgroup_subsys_state *css = NULL; struct mem_cgroup *memcg = NULL; struct mem_cgroup *pos = NULL; @@ -1173,30 +977,6 @@ void mem_cgroup_iter_break(struct mem_cgroup *root, iter != NULL; \ iter = mem_cgroup_iter(NULL, iter, NULL)) -void __mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx) -{ - struct mem_cgroup *memcg; - - rcu_read_lock(); - memcg = mem_cgroup_from_task(rcu_dereference(mm->owner)); - if (unlikely(!memcg)) - goto out; - - switch (idx) { - case PGFAULT: - this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT]); - break; - case PGMAJFAULT: - this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT]); - break; - default: - BUG(); - } -out: - rcu_read_unlock(); -} -EXPORT_SYMBOL(__mem_cgroup_count_vm_event); - /** * mem_cgroup_zone_lruvec - get the lru list vector for a zone and memcg * @zone: zone of the wanted lruvec @@ -1295,15 +1075,6 @@ void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, VM_BUG_ON((long)(*lru_size) < 0); } -bool mem_cgroup_is_descendant(struct mem_cgroup *memcg, struct mem_cgroup *root) -{ - if (root == memcg) - return true; - if (!root->use_hierarchy) - return false; - return cgroup_is_descendant(memcg->css.cgroup, root->css.cgroup); -} - bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg) { struct mem_cgroup *task_memcg; @@ -1330,39 +1101,6 @@ bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg) return ret; } -int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec) -{ - unsigned long inactive_ratio; - unsigned long inactive; - unsigned long active; - unsigned long gb; - - inactive = mem_cgroup_get_lru_size(lruvec, LRU_INACTIVE_ANON); - active = mem_cgroup_get_lru_size(lruvec, LRU_ACTIVE_ANON); - - gb = (inactive + active) >> (30 - PAGE_SHIFT); - if (gb) - inactive_ratio = int_sqrt(10 * gb); - else - inactive_ratio = 1; - - return inactive * inactive_ratio < active; -} - -bool mem_cgroup_lruvec_online(struct lruvec *lruvec) -{ - struct mem_cgroup_per_zone *mz; - struct mem_cgroup *memcg; - - if (mem_cgroup_disabled()) - return true; - - mz = container_of(lruvec, struct mem_cgroup_per_zone, lruvec); - memcg = mz->memcg; - - return !!(memcg->css.flags & CSS_ONLINE); -} - #define mem_cgroup_from_counter(counter, member) \ container_of(counter, struct mem_cgroup, member) @@ -1394,15 +1132,6 @@ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg) return margin; } -int mem_cgroup_swappiness(struct mem_cgroup *memcg) -{ - /* root ? */ - if (mem_cgroup_disabled() || !memcg->css.parent) - return vm_swappiness; - - return memcg->swappiness; -} - /* * A routine for checking "mem" is under move_account() or not. * @@ -2067,23 +1796,6 @@ void mem_cgroup_end_page_stat(struct mem_cgroup *memcg) } EXPORT_SYMBOL(mem_cgroup_end_page_stat); -/** - * mem_cgroup_update_page_stat - update page state statistics - * @memcg: memcg to account against - * @idx: page state item to account - * @val: number of pages (positive or negative) - * - * See mem_cgroup_begin_page_stat() for locking requirements. - */ -void mem_cgroup_update_page_stat(struct mem_cgroup *memcg, - enum mem_cgroup_stat_index idx, int val) -{ - VM_BUG_ON(!rcu_read_lock_held()); - - if (memcg) - this_cpu_add(memcg->stat->count[idx], val); -} - /* * size of first charge trial. "32" comes from vmscan.c's magic value. * TODO: maybe necessary to use big numbers in big irons. @@ -2509,16 +2221,6 @@ void memcg_uncharge_kmem(struct mem_cgroup *memcg, unsigned long nr_pages) css_put_many(&memcg->css, nr_pages); } -/* - * helper for acessing a memcg's index. It will be used as an index in the - * child cache array in kmem_cache, and also to derive its name. This function - * will return -1 when this is not a kmem-limited memcg. - */ -int memcg_cache_id(struct mem_cgroup *memcg) -{ - return memcg ? memcg->kmemcg_id : -1; -} - static int memcg_alloc_cache_id(void) { int id, size; @@ -5525,19 +5227,6 @@ struct cgroup_subsys memory_cgrp_subsys = { .early_init = 0, }; -/** - * mem_cgroup_events - count memory events against a cgroup - * @memcg: the memory cgroup - * @idx: the event index - * @nr: the number of events to account for - */ -void mem_cgroup_events(struct mem_cgroup *memcg, - enum mem_cgroup_events_index idx, - unsigned int nr) -{ - this_cpu_add(memcg->stat->events[idx], nr); -} - /** * mem_cgroup_low - check if memory consumption is below the normal range * @root: the highest ancestor to consider diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 1f4446a90cef0..016c814101edb 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -146,7 +146,7 @@ static int hwpoison_filter_task(struct page *p) if (!mem) return -EINVAL; - css = mem_cgroup_css(mem); + css = &mem->css; ino = cgroup_ino(css->cgroup); css_put(css); diff --git a/mm/slab_common.c b/mm/slab_common.c index bde04a699ab63..5ce4faeb16fbb 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -500,7 +500,7 @@ void memcg_create_kmem_cache(struct mem_cgroup *memcg, struct kmem_cache *root_cache) { static char memcg_name_buf[NAME_MAX + 1]; /* protected by slab_mutex */ - struct cgroup_subsys_state *css = mem_cgroup_css(memcg); + struct cgroup_subsys_state *css = &memcg->css; struct memcg_cache_array *arr; struct kmem_cache *s = NULL; char *cache_name; diff --git a/mm/vmscan.c b/mm/vmscan.c index b1139039122a0..bf23c88621ce6 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -175,7 +175,7 @@ static bool sane_reclaim(struct scan_control *sc) if (!memcg) return true; #ifdef CONFIG_CGROUP_WRITEBACK - if (cgroup_on_dfl(mem_cgroup_css(memcg)->cgroup)) + if (memcg->css.cgroup) return true; #endif return false; -- GitLab From fabc3fdde00b54825ba23230aedbf88a735b4e49 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Sep 2015 15:01:04 -0700 Subject: [PATCH 6719/7006] memcg: get rid of mem_cgroup_root_css for !CONFIG_MEMCG The only user is cgwb_bdi_init and that one depends on CONFIG_CGROUP_WRITEBACK which in turn depends on CONFIG_MEMCG so it doesn't make much sense to definte an empty stub for !CONFIG_MEMCG. Moreover ERR_PTR(-EINVAL) is ugly and would lead to runtime crashes if used in unguarded code paths. Better fail during compilation. Signed-off-by: Michal Hocko Reviewed-by: Vladimir Davydov Cc: Johannes Weiner Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memcontrol.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index ab2f6880e27b2..91bbe4ba62336 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -498,8 +498,6 @@ void mem_cgroup_split_huge_fixup(struct page *head); #else /* CONFIG_MEMCG */ struct mem_cgroup; -#define mem_cgroup_root_css ((struct cgroup_subsys_state *)ERR_PTR(-EINVAL)) - static inline void mem_cgroup_events(struct mem_cgroup *memcg, enum mem_cgroup_events_index idx, unsigned int nr) -- GitLab From 64219994898c8689c3d57668996f476f8c2d398c Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Sep 2015 15:01:07 -0700 Subject: [PATCH 6720/7006] memcg: get rid of extern for functions in memcontrol.h Most of the exported functions in this header are not marked extern so change the rest to follow the same style. Signed-off-by: Michal Hocko Reviewed-by: Vladimir Davydov Cc: Johannes Weiner Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memcontrol.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index 91bbe4ba62336..d92b80b63c5ca 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -306,10 +306,10 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *); bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg); -extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); -extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); +struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); +struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); -extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); +struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); static inline struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){ return css ? container_of(css, struct mem_cgroup, css) : NULL; @@ -344,7 +344,7 @@ static inline bool mm_match_cgroup(struct mm_struct *mm, return match; } -extern struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page); +struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page); static inline bool mem_cgroup_disabled(void) { @@ -403,8 +403,8 @@ static inline int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec) return inactive * inactive_ratio < active; } -extern void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, - struct task_struct *p); +void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, + struct task_struct *p); static inline void mem_cgroup_oom_enable(void) { @@ -719,8 +719,8 @@ static inline void sock_release_memcg(struct sock *sk) extern struct static_key memcg_kmem_enabled_key; extern int memcg_nr_cache_ids; -extern void memcg_get_cache_ids(void); -extern void memcg_put_cache_ids(void); +void memcg_get_cache_ids(void); +void memcg_put_cache_ids(void); /* * Helper macro to loop through all memcg-specific caches. Callers must still -- GitLab From 9f2115f93b88e5e8d48b87b153e36a537afb58cb Mon Sep 17 00:00:00 2001 From: Tejun Heo Date: Tue, 8 Sep 2015 15:01:10 -0700 Subject: [PATCH 6721/7006] memcg: restructure mem_cgroup_can_attach() Restructure it to lower nesting level and help the planned threadgroup leader iteration changes. This is pure reorganization. Signed-off-by: Tejun Heo Signed-off-by: Michal Hocko Reviewed-by: Vladimir Davydov Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 61 ++++++++++++++++++++++++++----------------------- 1 file changed, 32 insertions(+), 29 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 6935f77589e70..191d8aa5da713 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -4834,10 +4834,12 @@ static void mem_cgroup_clear_mc(void) static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, struct cgroup_taskset *tset) { - struct task_struct *p = cgroup_taskset_first(tset); - int ret = 0; struct mem_cgroup *memcg = mem_cgroup_from_css(css); + struct mem_cgroup *from; + struct task_struct *p; + struct mm_struct *mm; unsigned long move_flags; + int ret = 0; /* * We are now commited to this value whatever it is. Changes in this @@ -4845,36 +4847,37 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css, * So we need to save it, and keep it going. */ move_flags = READ_ONCE(memcg->move_charge_at_immigrate); - if (move_flags) { - struct mm_struct *mm; - struct mem_cgroup *from = mem_cgroup_from_task(p); + if (!move_flags) + return 0; - VM_BUG_ON(from == memcg); + p = cgroup_taskset_first(tset); + from = mem_cgroup_from_task(p); - mm = get_task_mm(p); - if (!mm) - return 0; - /* We move charges only when we move a owner of the mm */ - if (mm->owner == p) { - VM_BUG_ON(mc.from); - VM_BUG_ON(mc.to); - VM_BUG_ON(mc.precharge); - VM_BUG_ON(mc.moved_charge); - VM_BUG_ON(mc.moved_swap); - - spin_lock(&mc.lock); - mc.from = from; - mc.to = memcg; - mc.flags = move_flags; - spin_unlock(&mc.lock); - /* We set mc.moving_task later */ - - ret = mem_cgroup_precharge_mc(mm); - if (ret) - mem_cgroup_clear_mc(); - } - mmput(mm); + VM_BUG_ON(from == memcg); + + mm = get_task_mm(p); + if (!mm) + return 0; + /* We move charges only when we move a owner of the mm */ + if (mm->owner == p) { + VM_BUG_ON(mc.from); + VM_BUG_ON(mc.to); + VM_BUG_ON(mc.precharge); + VM_BUG_ON(mc.moved_charge); + VM_BUG_ON(mc.moved_swap); + + spin_lock(&mc.lock); + mc.from = from; + mc.to = memcg; + mc.flags = move_flags; + spin_unlock(&mc.lock); + /* We set mc.moving_task later */ + + ret = mem_cgroup_precharge_mc(mm); + if (ret) + mem_cgroup_clear_mc(); } + mmput(mm); return ret; } -- GitLab From a03f1f058969ec350fb7451a6fbca23096ee5727 Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Sep 2015 15:01:13 -0700 Subject: [PATCH 6722/7006] memcg, tcp_kmem: check for cg_proto in sock_update_memcg sk_prot->proto_cgroup is allowed to return NULL but sock_update_memcg doesn't check for NULL. The function relies on the mem_cgroup_is_root check because we shouldn't get NULL otherwise because mem_cgroup_from_task will always return !NULL. All other callers are checking for NULL and we can safely replace mem_cgroup_is_root() check by cg_proto != NULL which will be more straightforward (proto_cgroup returns NULL for the root memcg already). Signed-off-by: Michal Hocko Reviewed-by: Vladimir Davydov Cc: Johannes Weiner Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memcontrol.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 191d8aa5da713..3033e6c422295 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -315,8 +315,7 @@ void sock_update_memcg(struct sock *sk) rcu_read_lock(); memcg = mem_cgroup_from_task(current); cg_proto = sk->sk_prot->proto_cgroup(memcg); - if (!mem_cgroup_is_root(memcg) && - memcg_proto_active(cg_proto) && + if (cg_proto && memcg_proto_active(cg_proto) && css_tryget_online(&memcg->css)) { sk->sk_cgrp = cg_proto; } -- GitLab From e752eb68811aeece2220e183e23369a34122fb5e Mon Sep 17 00:00:00 2001 From: Michal Hocko Date: Tue, 8 Sep 2015 15:01:16 -0700 Subject: [PATCH 6723/7006] memcg: move memcg_proto_active from sock.h The only user is sock_update_memcg which is living in memcontrol.c so it doesn't make much sense to pollute sock.h by this inline helper. Move it to memcontrol.c and open code it into its only caller. Signed-off-by: Michal Hocko Cc: Vladimir Davydov Cc: Johannes Weiner Cc: Tejun Heo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/net/sock.h | 5 ----- mm/memcontrol.c | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/include/net/sock.h b/include/net/sock.h index a98c71ea40c5b..7aa78440559a4 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -1045,11 +1045,6 @@ struct proto { int proto_register(struct proto *prot, int alloc_slab); void proto_unregister(struct proto *prot); -static inline bool memcg_proto_active(struct cg_proto *cg_proto) -{ - return test_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags); -} - #ifdef SOCK_REFCNT_DEBUG static inline void sk_refcnt_debug_inc(struct sock *sk) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 3033e6c422295..1742a2db89c7b 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -315,7 +315,7 @@ void sock_update_memcg(struct sock *sk) rcu_read_lock(); memcg = mem_cgroup_from_task(current); cg_proto = sk->sk_prot->proto_cgroup(memcg); - if (cg_proto && memcg_proto_active(cg_proto) && + if (cg_proto && test_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags) && css_tryget_online(&memcg->css)) { sk->sk_cgrp = cg_proto; } -- GitLab From 156408c0edaacbea1137f58b28fd6ec341064310 Mon Sep 17 00:00:00 2001 From: Vishnu Pratap Singh Date: Tue, 8 Sep 2015 15:01:19 -0700 Subject: [PATCH 6724/7006] lib/show_mem.c: correct reserved memory calculation CMA reserved memory is not part of total reserved memory. Currently when we print the total reserve memory it considers cma as part of reserve memory and do minus of totalcma_pages from reserved, which is wrong. In cases where total reserved is less than cma reserved we will get negative values & while printing we print as unsigned and we will get a very large value. Below is the show mem output on X86 ubuntu based system where CMA reserved is 100MB (25600 pages) & total reserved is ~40MB(10316 pages). And reserve memory shows a large value because of this bug. Before: [ 127.066430] 898908 pages RAM [ 127.066432] 671682 pages HighMem/MovableOnly [ 127.066434] 4294952012 pages reserved [ 127.066436] 25600 pages cma reserved After: [ 44.663129] 898908 pages RAM [ 44.663130] 671682 pages HighMem/MovableOnly [ 44.663130] 10316 pages reserved [ 44.663131] 25600 pages cma reserved Signed-off-by: Vishnu Pratap Singh Cc: Michal Nazarewicz Cc: Marek Szyprowski Cc: Joonsoo Kim Cc: Laurent Pinchart Cc: Sasha Levin Cc: Danesh Petigara Cc: Laura Abbott Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/show_mem.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/show_mem.c b/lib/show_mem.c index adc98e1825ba0..1feed6a2b12ae 100644 --- a/lib/show_mem.c +++ b/lib/show_mem.c @@ -38,11 +38,9 @@ void show_mem(unsigned int filter) printk("%lu pages RAM\n", total); printk("%lu pages HighMem/MovableOnly\n", highmem); + printk("%lu pages reserved\n", reserved); #ifdef CONFIG_CMA - printk("%lu pages reserved\n", (reserved - totalcma_pages)); printk("%lu pages cma reserved\n", totalcma_pages); -#else - printk("%lu pages reserved\n", reserved); #endif #ifdef CONFIG_QUICKLIST printk("%lu pages in pagetable cache\n", -- GitLab From aa016d145d4c3b8a7273429528f19d5b423ddbc7 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:01:22 -0700 Subject: [PATCH 6725/7006] mm, page_isolation: remove bogus tests for isolated pages The __test_page_isolated_in_pageblock() is used to verify whether all pages in pageblock were either successfully isolated, or are hwpoisoned. Two of the possible state of pages, that are tested, are however bogus and misleading. Both tests rely on get_freepage_migratetype(page), which however has no guarantees about pages on freelists. Specifically, it doesn't guarantee that the migratetype returned by the function actually matches the migratetype of the freelist that the page is on. Such guarantee is not its purpose and would have negative impact on allocator performance. The first test checks whether the freepage_migratetype equals MIGRATE_ISOLATE, supposedly to catch races between page isolation and allocator activity. These races should be fixed nowadays with 51bb1a4093 ("mm/page_alloc: add freepage on isolate pageblock to correct buddy list") and related patches. As explained above, the check wouldn't be able to catch them reliably anyway. For the same reason false positives can happen, although they are harmless, as the move_freepages() call would just move the page to the same freelist it's already on. So removing the test is not a bug fix, just cleanup. After this patch, we assume that all PageBuddy pages are on the correct freelist and that the races were really fixed. A truly reliable verification in the form of e.g. VM_BUG_ON() would be complicated and is arguably not needed. The second test (page_count(page) == 0 && get_freepage_migratetype(page) == MIGRATE_ISOLATE) is probably supposed (the code comes from a big memory isolation patch from 2007) to catch pages on MIGRATE_ISOLATE pcplists. However, pcplists don't contain MIGRATE_ISOLATE freepages nowadays, those are freed directly to free lists, so the check is obsolete. Remove it as well. Signed-off-by: Vlastimil Babka Acked-by: Joonsoo Kim Cc: Minchan Kim Acked-by: Michal Nazarewicz Cc: Laura Abbott Reviewed-by: Naoya Horiguchi Cc: Seungho Park Cc: Johannes Weiner Cc: "Kirill A. Shutemov" Acked-by: Mel Gorman Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 4 ++++ mm/page_isolation.c | 30 ++++++------------------------ 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5f9394df19bf4..a329cfaf634d5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -788,7 +788,11 @@ static void free_pcppages_bulk(struct zone *zone, int count, page = list_entry(list->prev, struct page, lru); /* must delete as __free_one_page list manipulates */ list_del(&page->lru); + mt = get_freepage_migratetype(page); + /* MIGRATE_ISOLATE page should not go to pcplists */ + VM_BUG_ON_PAGE(is_migrate_isolate(mt), page); + /* Pageblock could have been isolated meanwhile */ if (unlikely(has_isolate_pageblock(zone))) mt = get_pageblock_migratetype(page); diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 303c908790efc..32fdc1df05e5f 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -223,34 +223,16 @@ __test_page_isolated_in_pageblock(unsigned long pfn, unsigned long end_pfn, continue; } page = pfn_to_page(pfn); - if (PageBuddy(page)) { + if (PageBuddy(page)) /* - * If race between isolatation and allocation happens, - * some free pages could be in MIGRATE_MOVABLE list - * although pageblock's migratation type of the page - * is MIGRATE_ISOLATE. Catch it and move the page into - * MIGRATE_ISOLATE list. + * If the page is on a free list, it has to be on + * the correct MIGRATE_ISOLATE freelist. There is no + * simple way to verify that as VM_BUG_ON(), though. */ - if (get_freepage_migratetype(page) != MIGRATE_ISOLATE) { - struct page *end_page; - - end_page = page + (1 << page_order(page)) - 1; - move_freepages(page_zone(page), page, end_page, - MIGRATE_ISOLATE); - } pfn += 1 << page_order(page); - } - else if (page_count(page) == 0 && - get_freepage_migratetype(page) == MIGRATE_ISOLATE) - pfn += 1; - else if (skip_hwpoisoned_pages && PageHWPoison(page)) { - /* - * The HWPoisoned page may be not in buddy - * system, and page_count() is not 0. - */ + else if (skip_hwpoisoned_pages && PageHWPoison(page)) + /* A HWPoisoned page cannot be also PageBuddy */ pfn++; - continue; - } else break; } -- GitLab From bb14c2c75db972a1bf65fd63c8d5a0b41a8f263a Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:01:25 -0700 Subject: [PATCH 6726/7006] mm: rename and move get/set_freepage_migratetype The pair of get/set_freepage_migratetype() functions are used to cache pageblock migratetype for a page put on a pcplist, so that it does not have to be retrieved again when the page is put on a free list (e.g. when pcplists become full). Historically it was also assumed that the value is accurate for pages on freelists (as the functions' names unfortunately suggest), but that cannot be guaranteed without affecting various allocator fast paths. It is in fact not needed and all such uses have been removed. The last remaining (but pointless) usage related to pages of freelists is in move_freepages(), which this patch removes. To prevent further confusion, rename the functions to get/set_pcppage_migratetype() and expand their description. Since all the users are now in mm/page_alloc.c, move the functions there from the shared header. Signed-off-by: Vlastimil Babka Acked-by: David Rientjes Acked-by: Joonsoo Kim Cc: Minchan Kim Acked-by: Michal Nazarewicz Cc: Laura Abbott Reviewed-by: Naoya Horiguchi Cc: Seungho Park Cc: Johannes Weiner Cc: "Kirill A. Shutemov" Acked-by: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 12 ------------ mm/page_alloc.c | 41 ++++++++++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/include/linux/mm.h b/include/linux/mm.h index 4ec72ef1f04a9..bab8ff89da508 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -309,18 +309,6 @@ struct inode; #define page_private(page) ((page)->private) #define set_page_private(page, v) ((page)->private = (v)) -/* It's valid only if the page is free path or free_list */ -static inline void set_freepage_migratetype(struct page *page, int migratetype) -{ - page->index = migratetype; -} - -/* It's valid only if the page is free path or free_list */ -static inline int get_freepage_migratetype(struct page *page) -{ - return page->index; -} - /* * FIXME: take this include out, include page-flags.h in * files which need it (119 of them) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index a329cfaf634d5..252665d553b48 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -125,6 +125,24 @@ unsigned long dirty_balance_reserve __read_mostly; int percpu_pagelist_fraction; gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; +/* + * A cached value of the page's pageblock's migratetype, used when the page is + * put on a pcplist. Used to avoid the pageblock migratetype lookup when + * freeing from pcplists in most cases, at the cost of possibly becoming stale. + * Also the migratetype set in the page does not necessarily match the pcplist + * index, e.g. page might have MIGRATE_CMA set but be on a pcplist with any + * other index - this ensures that it will be put on the correct CMA freelist. + */ +static inline int get_pcppage_migratetype(struct page *page) +{ + return page->index; +} + +static inline void set_pcppage_migratetype(struct page *page, int migratetype) +{ + page->index = migratetype; +} + #ifdef CONFIG_PM_SLEEP /* * The following functions are used by the suspend/hibernate code to temporarily @@ -789,7 +807,7 @@ static void free_pcppages_bulk(struct zone *zone, int count, /* must delete as __free_one_page list manipulates */ list_del(&page->lru); - mt = get_freepage_migratetype(page); + mt = get_pcppage_migratetype(page); /* MIGRATE_ISOLATE page should not go to pcplists */ VM_BUG_ON_PAGE(is_migrate_isolate(mt), page); /* Pageblock could have been isolated meanwhile */ @@ -956,7 +974,6 @@ static void __free_pages_ok(struct page *page, unsigned int order) migratetype = get_pfnblock_migratetype(page, pfn); local_irq_save(flags); __count_vm_events(PGFREE, 1 << order); - set_freepage_migratetype(page, migratetype); free_one_page(page_zone(page), page, pfn, order, migratetype); local_irq_restore(flags); } @@ -1384,7 +1401,7 @@ struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, rmv_page_order(page); area->nr_free--; expand(zone, page, order, current_order, area, migratetype); - set_freepage_migratetype(page, migratetype); + set_pcppage_migratetype(page, migratetype); return page; } @@ -1461,7 +1478,6 @@ int move_freepages(struct zone *zone, order = page_order(page); list_move(&page->lru, &zone->free_area[order].free_list[migratetype]); - set_freepage_migratetype(page, migratetype); page += 1 << order; pages_moved += 1 << order; } @@ -1631,14 +1647,13 @@ __rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype) expand(zone, page, order, current_order, area, start_migratetype); /* - * The freepage_migratetype may differ from pageblock's + * The pcppage_migratetype may differ from pageblock's * migratetype depending on the decisions in - * try_to_steal_freepages(). This is OK as long as it - * does not differ for MIGRATE_CMA pageblocks. For CMA - * we need to make sure unallocated pages flushed from - * pcp lists are returned to the correct freelist. + * find_suitable_fallback(). This is OK as long as it does not + * differ for MIGRATE_CMA pageblocks. Those can be used as + * fallback only via special __rmqueue_cma_fallback() function */ - set_freepage_migratetype(page, start_migratetype); + set_pcppage_migratetype(page, start_migratetype); trace_mm_page_alloc_extfrag(page, order, current_order, start_migratetype, fallback_mt); @@ -1714,7 +1729,7 @@ static int rmqueue_bulk(struct zone *zone, unsigned int order, else list_add_tail(&page->lru, list); list = &page->lru; - if (is_migrate_cma(get_freepage_migratetype(page))) + if (is_migrate_cma(get_pcppage_migratetype(page))) __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, -(1 << order)); } @@ -1911,7 +1926,7 @@ void free_hot_cold_page(struct page *page, bool cold) return; migratetype = get_pfnblock_migratetype(page, pfn); - set_freepage_migratetype(page, migratetype); + set_pcppage_migratetype(page, migratetype); local_irq_save(flags); __count_vm_event(PGFREE); @@ -2116,7 +2131,7 @@ struct page *buffered_rmqueue(struct zone *preferred_zone, if (!page) goto failed; __mod_zone_freepage_state(zone, -(1 << order), - get_freepage_migratetype(page)); + get_pcppage_migratetype(page)); } __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order)); -- GitLab From 5e9113731a3ce616e8b5aa128ffc1aeaa4942571 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:28 -0700 Subject: [PATCH 6727/7006] mm/hugetlb: add cache of descriptors to resv_map for region_add hugetlbfs is used today by applications that want a high degree of control over huge page usage. Often, large hugetlbfs files are used to map a large number huge pages into the application processes. The applications know when page ranges within these large files will no longer be used, and ideally would like to release them back to the subpool or global pools for other uses. The fallocate() system call provides an interface for preallocation and hole punching within files. This patch set adds fallocate functionality to hugetlbfs. fallocate hole punch will want to remove a specific range of pages. When pages are removed, their associated entries in the region/reserve map will also be removed. This will break an assumption in the region_chg/region_add calling sequence. If a new region descriptor must be allocated, it is done as part of the region_chg processing. In this way, region_add can not fail because it does not need to attempt an allocation. To prepare for fallocate hole punch, create a "cache" of descriptors that can be used by region_add if necessary. region_chg will ensure there are sufficient entries in the cache. It will be necessary to track the number of in progress add operations to know a sufficient number of descriptors reside in the cache. A new routine region_abort is added to adjust this in progress count when add operations are aborted. vma_abort_reservation is also added for callers creating reservations with vma_needs_reservation/vma_commit_reservation. [akpm@linux-foundation.org: fix typo in comment, use more cols] Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/hugetlb.h | 3 + mm/hugetlb.c | 174 +++++++++++++++++++++++++++++++++++----- 2 files changed, 155 insertions(+), 22 deletions(-) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index d891f949466ae..e2d94960b38bc 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -35,6 +35,9 @@ struct resv_map { struct kref refs; spinlock_t lock; struct list_head regions; + long adds_in_progress; + struct list_head region_cache; + long region_cache_count; }; extern struct resv_map *resv_map_alloc(void); void resv_map_release(struct kref *ref); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 51ae41d0fbc0d..4e5815ed7a8e4 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -240,11 +240,14 @@ struct file_region { /* * Add the huge page range represented by [f, t) to the reserve - * map. Existing regions will be expanded to accommodate the - * specified range. We know only existing regions need to be - * expanded, because region_add is only called after region_chg - * with the same range. If a new file_region structure must - * be allocated, it is done in region_chg. + * map. In the normal case, existing regions will be expanded + * to accommodate the specified range. Sufficient regions should + * exist for expansion due to the previous call to region_chg + * with the same range. However, it is possible that region_del + * could have been called after region_chg and modifed the map + * in such a way that no region exists to be expanded. In this + * case, pull a region descriptor from the cache associated with + * the map and use that for the new range. * * Return the number of new huge pages added to the map. This * number is greater than or equal to zero. @@ -261,6 +264,28 @@ static long region_add(struct resv_map *resv, long f, long t) if (f <= rg->to) break; + /* + * If no region exists which can be expanded to include the + * specified range, the list must have been modified by an + * interleving call to region_del(). Pull a region descriptor + * from the cache and use it for this range. + */ + if (&rg->link == head || t < rg->from) { + VM_BUG_ON(resv->region_cache_count <= 0); + + resv->region_cache_count--; + nrg = list_first_entry(&resv->region_cache, struct file_region, + link); + list_del(&nrg->link); + + nrg->from = f; + nrg->to = t; + list_add(&nrg->link, rg->link.prev); + + add += t - f; + goto out_locked; + } + /* Round our left edge to the current segment if it encloses us. */ if (f > rg->from) f = rg->from; @@ -294,6 +319,8 @@ static long region_add(struct resv_map *resv, long f, long t) add += t - nrg->to; /* Added to end of region */ nrg->to = t; +out_locked: + resv->adds_in_progress--; spin_unlock(&resv->lock); VM_BUG_ON(add < 0); return add; @@ -312,11 +339,14 @@ static long region_add(struct resv_map *resv, long f, long t) * so that the subsequent region_add call will have all the * regions it needs and will not fail. * - * Returns the number of huge pages that need to be added - * to the existing reservation map for the range [f, t). - * This number is greater or equal to zero. -ENOMEM is - * returned if a new file_region structure is needed and can - * not be allocated. + * Upon entry, region_chg will also examine the cache of region descriptors + * associated with the map. If there are not enough descriptors cached, one + * will be allocated for the in progress add operation. + * + * Returns the number of huge pages that need to be added to the existing + * reservation map for the range [f, t). This number is greater or equal to + * zero. -ENOMEM is returned if a new file_region structure or cache entry + * is needed and can not be allocated. */ static long region_chg(struct resv_map *resv, long f, long t) { @@ -326,6 +356,31 @@ static long region_chg(struct resv_map *resv, long f, long t) retry: spin_lock(&resv->lock); +retry_locked: + resv->adds_in_progress++; + + /* + * Check for sufficient descriptors in the cache to accommodate + * the number of in progress add operations. + */ + if (resv->adds_in_progress > resv->region_cache_count) { + struct file_region *trg; + + VM_BUG_ON(resv->adds_in_progress - resv->region_cache_count > 1); + /* Must drop lock to allocate a new descriptor. */ + resv->adds_in_progress--; + spin_unlock(&resv->lock); + + trg = kmalloc(sizeof(*trg), GFP_KERNEL); + if (!trg) + return -ENOMEM; + + spin_lock(&resv->lock); + list_add(&trg->link, &resv->region_cache); + resv->region_cache_count++; + goto retry_locked; + } + /* Locate the region we are before or in. */ list_for_each_entry(rg, head, link) if (f <= rg->to) @@ -336,6 +391,7 @@ retry: * size such that we can guarantee to record the reservation. */ if (&rg->link == head || t < rg->from) { if (!nrg) { + resv->adds_in_progress--; spin_unlock(&resv->lock); nrg = kmalloc(sizeof(*nrg), GFP_KERNEL); if (!nrg) @@ -384,6 +440,25 @@ out_nrg: return chg; } +/* + * Abort the in progress add operation. The adds_in_progress field + * of the resv_map keeps track of the operations in progress between + * calls to region_chg and region_add. Operations are sometimes + * aborted after the call to region_chg. In such cases, region_abort + * is called to decrement the adds_in_progress counter. + * + * NOTE: The range arguments [f, t) are not needed or used in this + * routine. They are kept to make reading the calling code easier as + * arguments will match the associated region_chg call. + */ +static void region_abort(struct resv_map *resv, long f, long t) +{ + spin_lock(&resv->lock); + VM_BUG_ON(!resv->region_cache_count); + resv->adds_in_progress--; + spin_unlock(&resv->lock); +} + /* * Truncate the reserve map at index 'end'. Modify/truncate any * region which contains end. Delete any regions past end. @@ -544,22 +619,44 @@ static void set_vma_private_data(struct vm_area_struct *vma, struct resv_map *resv_map_alloc(void) { struct resv_map *resv_map = kmalloc(sizeof(*resv_map), GFP_KERNEL); - if (!resv_map) + struct file_region *rg = kmalloc(sizeof(*rg), GFP_KERNEL); + + if (!resv_map || !rg) { + kfree(resv_map); + kfree(rg); return NULL; + } kref_init(&resv_map->refs); spin_lock_init(&resv_map->lock); INIT_LIST_HEAD(&resv_map->regions); + resv_map->adds_in_progress = 0; + + INIT_LIST_HEAD(&resv_map->region_cache); + list_add(&rg->link, &resv_map->region_cache); + resv_map->region_cache_count = 1; + return resv_map; } void resv_map_release(struct kref *ref) { struct resv_map *resv_map = container_of(ref, struct resv_map, refs); + struct list_head *head = &resv_map->region_cache; + struct file_region *rg, *trg; /* Clear out any active regions before we release the map. */ region_truncate(resv_map, 0); + + /* ... and any entries left in the cache */ + list_for_each_entry_safe(rg, trg, head, link) { + list_del(&rg->link); + kfree(rg); + } + + VM_BUG_ON(resv_map->adds_in_progress); + kfree(resv_map); } @@ -1473,16 +1570,18 @@ static void return_unused_surplus_pages(struct hstate *h, } } + /* - * vma_needs_reservation and vma_commit_reservation are used by the huge - * page allocation routines to manage reservations. + * vma_needs_reservation, vma_commit_reservation and vma_abort_reservation + * are used by the huge page allocation routines to manage reservations. * * vma_needs_reservation is called to determine if the huge page at addr * within the vma has an associated reservation. If a reservation is * needed, the value 1 is returned. The caller is then responsible for * managing the global reservation and subpool usage counts. After * the huge page has been allocated, vma_commit_reservation is called - * to add the page to the reservation map. + * to add the page to the reservation map. If the reservation must be + * aborted instead of committed, vma_abort_reservation is called. * * In the normal case, vma_commit_reservation returns the same value * as the preceding vma_needs_reservation call. The only time this @@ -1490,9 +1589,14 @@ static void return_unused_surplus_pages(struct hstate *h, * is the responsibility of the caller to notice the difference and * take appropriate action. */ +enum vma_resv_mode { + VMA_NEEDS_RESV, + VMA_COMMIT_RESV, + VMA_ABORT_RESV, +}; static long __vma_reservation_common(struct hstate *h, struct vm_area_struct *vma, unsigned long addr, - bool commit) + enum vma_resv_mode mode) { struct resv_map *resv; pgoff_t idx; @@ -1503,10 +1607,20 @@ static long __vma_reservation_common(struct hstate *h, return 1; idx = vma_hugecache_offset(h, vma, addr); - if (commit) - ret = region_add(resv, idx, idx + 1); - else + switch (mode) { + case VMA_NEEDS_RESV: ret = region_chg(resv, idx, idx + 1); + break; + case VMA_COMMIT_RESV: + ret = region_add(resv, idx, idx + 1); + break; + case VMA_ABORT_RESV: + region_abort(resv, idx, idx + 1); + ret = 0; + break; + default: + BUG(); + } if (vma->vm_flags & VM_MAYSHARE) return ret; @@ -1517,13 +1631,19 @@ static long __vma_reservation_common(struct hstate *h, static long vma_needs_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) { - return __vma_reservation_common(h, vma, addr, false); + return __vma_reservation_common(h, vma, addr, VMA_NEEDS_RESV); } static long vma_commit_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) { - return __vma_reservation_common(h, vma, addr, true); + return __vma_reservation_common(h, vma, addr, VMA_COMMIT_RESV); +} + +static void vma_abort_reservation(struct hstate *h, + struct vm_area_struct *vma, unsigned long addr) +{ + (void)__vma_reservation_common(h, vma, addr, VMA_ABORT_RESV); } static struct page *alloc_huge_page(struct vm_area_struct *vma, @@ -1549,8 +1669,10 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, if (chg < 0) return ERR_PTR(-ENOMEM); if (chg || avoid_reserve) - if (hugepage_subpool_get_pages(spool, 1) < 0) + if (hugepage_subpool_get_pages(spool, 1) < 0) { + vma_abort_reservation(h, vma, addr); return ERR_PTR(-ENOSPC); + } ret = hugetlb_cgroup_charge_cgroup(idx, pages_per_huge_page(h), &h_cg); if (ret) @@ -1596,6 +1718,7 @@ out_uncharge_cgroup: out_subpool_put: if (chg || avoid_reserve) hugepage_subpool_put_pages(spool, 1); + vma_abort_reservation(h, vma, addr); return ERR_PTR(-ENOSPC); } @@ -3236,11 +3359,14 @@ retry: * any allocations necessary to record that reservation occur outside * the spinlock. */ - if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) + if ((flags & FAULT_FLAG_WRITE) && !(vma->vm_flags & VM_SHARED)) { if (vma_needs_reservation(h, vma, address) < 0) { ret = VM_FAULT_OOM; goto backout_unlocked; } + /* Just decrements count, does not deallocate */ + vma_abort_reservation(h, vma, address); + } ptl = huge_pte_lockptr(h, mm, ptep); spin_lock(ptl); @@ -3387,6 +3513,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, ret = VM_FAULT_OOM; goto out_mutex; } + /* Just decrements count, does not deallocate */ + vma_abort_reservation(h, vma, address); if (!(vma->vm_flags & VM_MAYSHARE)) pagecache_page = hugetlbfs_pagecache_page(h, @@ -3726,6 +3854,8 @@ int hugetlb_reserve_pages(struct inode *inode, } return 0; out_err: + if (!vma || vma->vm_flags & VM_MAYSHARE) + region_abort(resv_map, from, to); if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER)) kref_put(&resv_map->refs, resv_map_release); return ret; -- GitLab From feba16e25a578080af5aad5eb9e469b4e6c23eef Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:31 -0700 Subject: [PATCH 6728/7006] mm/hugetlb: add region_del() to delete a specific range of entries fallocate hole punch will want to remove a specific range of pages. The existing region_truncate() routine deletes all region/reserve map entries after a specified offset. region_del() will provide this same functionality if the end of region is specified as LONG_MAX. Hence, region_del() can replace region_truncate(). Unlike region_truncate(), region_del() can return an error in the rare case where it can not allocate memory for a region descriptor. This ONLY happens in the case where an existing region must be split. Current callers passing LONG_MAX as end of range will never experience this error and do not need to deal with error handling. Future callers of region_del() (such as fallocate hole punch) will need to handle this error. Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 122 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 85 insertions(+), 37 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 4e5815ed7a8e4..78e7eded4063c 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -460,43 +460,90 @@ static void region_abort(struct resv_map *resv, long f, long t) } /* - * Truncate the reserve map at index 'end'. Modify/truncate any - * region which contains end. Delete any regions past end. - * Return the number of huge pages removed from the map. + * Delete the specified range [f, t) from the reserve map. If the + * t parameter is LONG_MAX, this indicates that ALL regions after f + * should be deleted. Locate the regions which intersect [f, t) + * and either trim, delete or split the existing regions. + * + * Returns the number of huge pages deleted from the reserve map. + * In the normal case, the return value is zero or more. In the + * case where a region must be split, a new region descriptor must + * be allocated. If the allocation fails, -ENOMEM will be returned. + * NOTE: If the parameter t == LONG_MAX, then we will never split + * a region and possibly return -ENOMEM. Callers specifying + * t == LONG_MAX do not need to check for -ENOMEM error. */ -static long region_truncate(struct resv_map *resv, long end) +static long region_del(struct resv_map *resv, long f, long t) { struct list_head *head = &resv->regions; struct file_region *rg, *trg; - long chg = 0; + struct file_region *nrg = NULL; + long del = 0; +retry: spin_lock(&resv->lock); - /* Locate the region we are either in or before. */ - list_for_each_entry(rg, head, link) - if (end <= rg->to) + list_for_each_entry_safe(rg, trg, head, link) { + if (rg->to <= f) + continue; + if (rg->from >= t) break; - if (&rg->link == head) - goto out; - /* If we are in the middle of a region then adjust it. */ - if (end > rg->from) { - chg = rg->to - end; - rg->to = end; - rg = list_entry(rg->link.next, typeof(*rg), link); - } + if (f > rg->from && t < rg->to) { /* Must split region */ + /* + * Check for an entry in the cache before dropping + * lock and attempting allocation. + */ + if (!nrg && + resv->region_cache_count > resv->adds_in_progress) { + nrg = list_first_entry(&resv->region_cache, + struct file_region, + link); + list_del(&nrg->link); + resv->region_cache_count--; + } - /* Drop any remaining regions. */ - list_for_each_entry_safe(rg, trg, rg->link.prev, link) { - if (&rg->link == head) + if (!nrg) { + spin_unlock(&resv->lock); + nrg = kmalloc(sizeof(*nrg), GFP_KERNEL); + if (!nrg) + return -ENOMEM; + goto retry; + } + + del += t - f; + + /* New entry for end of split region */ + nrg->from = t; + nrg->to = rg->to; + INIT_LIST_HEAD(&nrg->link); + + /* Original entry is trimmed */ + rg->to = f; + + list_add(&nrg->link, &rg->link); + nrg = NULL; break; - chg += rg->to - rg->from; - list_del(&rg->link); - kfree(rg); + } + + if (f <= rg->from && t >= rg->to) { /* Remove entire region */ + del += rg->to - rg->from; + list_del(&rg->link); + kfree(rg); + continue; + } + + if (f <= rg->from) { /* Trim beginning of region */ + del += t - rg->from; + rg->from = t; + } else { /* Trim end of region */ + del += rg->to - f; + rg->to = f; + } } -out: spin_unlock(&resv->lock); - return chg; + kfree(nrg); + return del; } /* @@ -647,7 +694,7 @@ void resv_map_release(struct kref *ref) struct file_region *rg, *trg; /* Clear out any active regions before we release the map. */ - region_truncate(resv_map, 0); + region_del(resv_map, 0, LONG_MAX); /* ... and any entries left in the cache */ list_for_each_entry_safe(rg, trg, head, link) { @@ -1572,7 +1619,7 @@ static void return_unused_surplus_pages(struct hstate *h, /* - * vma_needs_reservation, vma_commit_reservation and vma_abort_reservation + * vma_needs_reservation, vma_commit_reservation and vma_end_reservation * are used by the huge page allocation routines to manage reservations. * * vma_needs_reservation is called to determine if the huge page at addr @@ -1580,8 +1627,9 @@ static void return_unused_surplus_pages(struct hstate *h, * needed, the value 1 is returned. The caller is then responsible for * managing the global reservation and subpool usage counts. After * the huge page has been allocated, vma_commit_reservation is called - * to add the page to the reservation map. If the reservation must be - * aborted instead of committed, vma_abort_reservation is called. + * to add the page to the reservation map. If the page allocation fails, + * the reservation must be ended instead of committed. vma_end_reservation + * is called in such cases. * * In the normal case, vma_commit_reservation returns the same value * as the preceding vma_needs_reservation call. The only time this @@ -1592,7 +1640,7 @@ static void return_unused_surplus_pages(struct hstate *h, enum vma_resv_mode { VMA_NEEDS_RESV, VMA_COMMIT_RESV, - VMA_ABORT_RESV, + VMA_END_RESV, }; static long __vma_reservation_common(struct hstate *h, struct vm_area_struct *vma, unsigned long addr, @@ -1614,7 +1662,7 @@ static long __vma_reservation_common(struct hstate *h, case VMA_COMMIT_RESV: ret = region_add(resv, idx, idx + 1); break; - case VMA_ABORT_RESV: + case VMA_END_RESV: region_abort(resv, idx, idx + 1); ret = 0; break; @@ -1640,10 +1688,10 @@ static long vma_commit_reservation(struct hstate *h, return __vma_reservation_common(h, vma, addr, VMA_COMMIT_RESV); } -static void vma_abort_reservation(struct hstate *h, +static void vma_end_reservation(struct hstate *h, struct vm_area_struct *vma, unsigned long addr) { - (void)__vma_reservation_common(h, vma, addr, VMA_ABORT_RESV); + (void)__vma_reservation_common(h, vma, addr, VMA_END_RESV); } static struct page *alloc_huge_page(struct vm_area_struct *vma, @@ -1670,7 +1718,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, return ERR_PTR(-ENOMEM); if (chg || avoid_reserve) if (hugepage_subpool_get_pages(spool, 1) < 0) { - vma_abort_reservation(h, vma, addr); + vma_end_reservation(h, vma, addr); return ERR_PTR(-ENOSPC); } @@ -1718,7 +1766,7 @@ out_uncharge_cgroup: out_subpool_put: if (chg || avoid_reserve) hugepage_subpool_put_pages(spool, 1); - vma_abort_reservation(h, vma, addr); + vma_end_reservation(h, vma, addr); return ERR_PTR(-ENOSPC); } @@ -3365,7 +3413,7 @@ retry: goto backout_unlocked; } /* Just decrements count, does not deallocate */ - vma_abort_reservation(h, vma, address); + vma_end_reservation(h, vma, address); } ptl = huge_pte_lockptr(h, mm, ptep); @@ -3514,7 +3562,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, goto out_mutex; } /* Just decrements count, does not deallocate */ - vma_abort_reservation(h, vma, address); + vma_end_reservation(h, vma, address); if (!(vma->vm_flags & VM_MAYSHARE)) pagecache_page = hugetlbfs_pagecache_page(h, @@ -3870,7 +3918,7 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) long gbl_reserve; if (resv_map) - chg = region_truncate(resv_map, offset); + chg = region_del(resv_map, offset, LONG_MAX); spin_lock(&inode->i_lock); inode->i_blocks -= (blocks_per_huge_page(h) * freed); spin_unlock(&inode->i_lock); -- GitLab From c672c7f29f2fdb73e1f72911bf499675c81fcdbb Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:35 -0700 Subject: [PATCH 6729/7006] mm/hugetlb: expose hugetlb fault mutex for use by fallocate hugetlb page faults are currently synchronized by the table of mutexes (htlb_fault_mutex_table). fallocate code will need to synchronize with the page fault code when it allocates or deletes pages. Expose interfaces so that fallocate operations can be synchronized with page faults. Minor name changes to be more consistent with other global hugetlb symbols. Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/hugetlb.h | 5 +++++ mm/hugetlb.c | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index e2d94960b38bc..530cf6fc24c7e 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -88,6 +88,11 @@ int dequeue_hwpoisoned_huge_page(struct page *page); bool isolate_huge_page(struct page *page, struct list_head *list); void putback_active_hugepage(struct page *page); void free_huge_page(struct page *page); +extern struct mutex *hugetlb_fault_mutex_table; +u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm, + struct vm_area_struct *vma, + struct address_space *mapping, + pgoff_t idx, unsigned long address); #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 78e7eded4063c..070880fe1ff71 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -64,7 +64,7 @@ DEFINE_SPINLOCK(hugetlb_lock); * prevent spurious OOMs when the hugepage pool is fully utilized. */ static int num_fault_mutexes; -static struct mutex *htlb_fault_mutex_table ____cacheline_aligned_in_smp; +struct mutex *hugetlb_fault_mutex_table ____cacheline_aligned_in_smp; /* Forward declaration */ static int hugetlb_acct_memory(struct hstate *h, long delta); @@ -2482,7 +2482,7 @@ static void __exit hugetlb_exit(void) } kobject_put(hugepages_kobj); - kfree(htlb_fault_mutex_table); + kfree(hugetlb_fault_mutex_table); } module_exit(hugetlb_exit); @@ -2515,12 +2515,12 @@ static int __init hugetlb_init(void) #else num_fault_mutexes = 1; #endif - htlb_fault_mutex_table = + hugetlb_fault_mutex_table = kmalloc(sizeof(struct mutex) * num_fault_mutexes, GFP_KERNEL); - BUG_ON(!htlb_fault_mutex_table); + BUG_ON(!hugetlb_fault_mutex_table); for (i = 0; i < num_fault_mutexes; i++) - mutex_init(&htlb_fault_mutex_table[i]); + mutex_init(&hugetlb_fault_mutex_table[i]); return 0; } module_init(hugetlb_init); @@ -3454,7 +3454,7 @@ backout_unlocked: } #ifdef CONFIG_SMP -static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm, +u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm, struct vm_area_struct *vma, struct address_space *mapping, pgoff_t idx, unsigned long address) @@ -3479,7 +3479,7 @@ static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm, * For uniprocesor systems we always use a single mutex, so just * return 0 and avoid the hashing overhead. */ -static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm, +u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm, struct vm_area_struct *vma, struct address_space *mapping, pgoff_t idx, unsigned long address) @@ -3527,8 +3527,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, * get spurious allocation failures if two CPUs race to instantiate * the same page in the page cache. */ - hash = fault_mutex_hash(h, mm, vma, mapping, idx, address); - mutex_lock(&htlb_fault_mutex_table[hash]); + hash = hugetlb_fault_mutex_hash(h, mm, vma, mapping, idx, address); + mutex_lock(&hugetlb_fault_mutex_table[hash]); entry = huge_ptep_get(ptep); if (huge_pte_none(entry)) { @@ -3613,7 +3613,7 @@ out_ptl: put_page(pagecache_page); } out_mutex: - mutex_unlock(&htlb_fault_mutex_table[hash]); + mutex_unlock(&hugetlb_fault_mutex_table[hash]); /* * Generally it's safe to hold refcount during waiting page lock. But * here we just wait to defer the next page fault to avoid busy loop and -- GitLab From 1bfad99ab42569807d0ca1698449cae5e8c0334a Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:38 -0700 Subject: [PATCH 6730/7006] hugetlbfs: hugetlb_vmtruncate_list() needs to take a range to delete fallocate hole punch will want to unmap a specific range of pages. Modify the existing hugetlb_vmtruncate_list() routine to take a start/end range. If end is 0, this indicates all pages after start should be unmapped. This is the same as the existing truncate functionality. Modify existing callers to add 0 as end of range. Since the routine will be used in hole punch as well as truncate operations, it is more appropriately renamed to hugetlb_vmdelete_list(). Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 973c24ce59ad3..b1e197d38abb2 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -349,11 +349,15 @@ static void hugetlbfs_evict_inode(struct inode *inode) } static inline void -hugetlb_vmtruncate_list(struct rb_root *root, pgoff_t pgoff) +hugetlb_vmdelete_list(struct rb_root *root, pgoff_t start, pgoff_t end) { struct vm_area_struct *vma; - vma_interval_tree_foreach(vma, root, pgoff, ULONG_MAX) { + /* + * end == 0 indicates that the entire range after + * start should be unmapped. + */ + vma_interval_tree_foreach(vma, root, start, end ? end : ULONG_MAX) { unsigned long v_offset; /* @@ -362,13 +366,20 @@ hugetlb_vmtruncate_list(struct rb_root *root, pgoff_t pgoff) * which overlap the truncated area starting at pgoff, * and no vma on a 32-bit arch can span beyond the 4GB. */ - if (vma->vm_pgoff < pgoff) - v_offset = (pgoff - vma->vm_pgoff) << PAGE_SHIFT; + if (vma->vm_pgoff < start) + v_offset = (start - vma->vm_pgoff) << PAGE_SHIFT; else v_offset = 0; - unmap_hugepage_range(vma, vma->vm_start + v_offset, - vma->vm_end, NULL); + if (end) { + end = ((end - start) << PAGE_SHIFT) + + vma->vm_start + v_offset; + if (end > vma->vm_end) + end = vma->vm_end; + } else + end = vma->vm_end; + + unmap_hugepage_range(vma, vma->vm_start + v_offset, end, NULL); } } @@ -384,7 +395,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) i_size_write(inode, offset); i_mmap_lock_write(mapping); if (!RB_EMPTY_ROOT(&mapping->i_mmap)) - hugetlb_vmtruncate_list(&mapping->i_mmap, pgoff); + hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); i_mmap_unlock_write(mapping); truncate_hugepages(inode, offset); return 0; -- GitLab From b5cec28d36f5ee6b4e6f68a0a40aa1e4045d6d99 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:41 -0700 Subject: [PATCH 6731/7006] hugetlbfs: truncate_hugepages() takes a range of pages Modify truncate_hugepages() to take a range of pages (start, end) instead of simply start. If an end value of LLONG_MAX is passed, the current "truncate" functionality is maintained. Existing callers are modified to pass LLONG_MAX as end of range. By keying off end == LLONG_MAX, the routine behaves differently for truncate and hole punch. Page removal is now synchronized with page allocation via faults by using the fault mutex table. The hole punch case can experience the rare region_del error and must handle accordingly. Add the routine hugetlb_fix_reserve_counts to fix up reserve counts in the case where region_del returns an error. Since the routine handles more than just the truncate case, it is renamed to remove_inode_hugepages(). To be consistent, the routine truncate_huge_page() is renamed remove_huge_page(). Downstream of remove_inode_hugepages(), the routine hugetlb_unreserve_pages() is also modified to take a range of pages. hugetlb_unreserve_pages is modified to detect an error from region_del and pass it back to the caller. Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 98 ++++++++++++++++++++++++++++++++++++----- include/linux/hugetlb.h | 4 +- mm/hugetlb.c | 40 +++++++++++++++-- 3 files changed, 128 insertions(+), 14 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index b1e197d38abb2..1ef630f81c991 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -293,26 +293,61 @@ static int hugetlbfs_write_end(struct file *file, struct address_space *mapping, return -EINVAL; } -static void truncate_huge_page(struct page *page) +static void remove_huge_page(struct page *page) { ClearPageDirty(page); ClearPageUptodate(page); delete_from_page_cache(page); } -static void truncate_hugepages(struct inode *inode, loff_t lstart) + +/* + * remove_inode_hugepages handles two distinct cases: truncation and hole + * punch. There are subtle differences in operation for each case. + + * truncation is indicated by end of range being LLONG_MAX + * In this case, we first scan the range and release found pages. + * After releasing pages, hugetlb_unreserve_pages cleans up region/reserv + * maps and global counts. + * hole punch is indicated if end is not LLONG_MAX + * In the hole punch case we scan the range and release found pages. + * Only when releasing a page is the associated region/reserv map + * deleted. The region/reserv map for ranges without associated + * pages are not modified. + * Note: If the passed end of range value is beyond the end of file, but + * not LLONG_MAX this routine still performs a hole punch operation. + */ +static void remove_inode_hugepages(struct inode *inode, loff_t lstart, + loff_t lend) { struct hstate *h = hstate_inode(inode); struct address_space *mapping = &inode->i_data; const pgoff_t start = lstart >> huge_page_shift(h); + const pgoff_t end = lend >> huge_page_shift(h); + struct vm_area_struct pseudo_vma; struct pagevec pvec; pgoff_t next; int i, freed = 0; + long lookup_nr = PAGEVEC_SIZE; + bool truncate_op = (lend == LLONG_MAX); + memset(&pseudo_vma, 0, sizeof(struct vm_area_struct)); + pseudo_vma.vm_flags = (VM_HUGETLB | VM_MAYSHARE | VM_SHARED); pagevec_init(&pvec, 0); next = start; - while (1) { - if (!pagevec_lookup(&pvec, mapping, next, PAGEVEC_SIZE)) { + while (next < end) { + /* + * Make sure to never grab more pages that we + * might possibly need. + */ + if (end - next < lookup_nr) + lookup_nr = end - next; + + /* + * This pagevec_lookup() may return pages past 'end', + * so we must check for page->index > end. + */ + if (!pagevec_lookup(&pvec, mapping, next, lookup_nr)) { if (next == start) break; next = start; @@ -321,26 +356,69 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart) for (i = 0; i < pagevec_count(&pvec); ++i) { struct page *page = pvec.pages[i]; + u32 hash; + + hash = hugetlb_fault_mutex_hash(h, current->mm, + &pseudo_vma, + mapping, next, 0); + mutex_lock(&hugetlb_fault_mutex_table[hash]); lock_page(page); + if (page->index >= end) { + unlock_page(page); + mutex_unlock(&hugetlb_fault_mutex_table[hash]); + next = end; /* we are done */ + break; + } + + /* + * If page is mapped, it was faulted in after being + * unmapped. Do nothing in this race case. In the + * normal case page is not mapped. + */ + if (!page_mapped(page)) { + bool rsv_on_error = !PagePrivate(page); + /* + * We must free the huge page and remove + * from page cache (remove_huge_page) BEFORE + * removing the region/reserve map + * (hugetlb_unreserve_pages). In rare out + * of memory conditions, removal of the + * region/reserve map could fail. Before + * free'ing the page, note PagePrivate which + * is used in case of error. + */ + remove_huge_page(page); + freed++; + if (!truncate_op) { + if (unlikely(hugetlb_unreserve_pages( + inode, next, + next + 1, 1))) + hugetlb_fix_reserve_counts( + inode, rsv_on_error); + } + } + if (page->index > next) next = page->index; + ++next; - truncate_huge_page(page); unlock_page(page); - freed++; + + mutex_unlock(&hugetlb_fault_mutex_table[hash]); } huge_pagevec_release(&pvec); } - BUG_ON(!lstart && mapping->nrpages); - hugetlb_unreserve_pages(inode, start, freed); + + if (truncate_op) + (void)hugetlb_unreserve_pages(inode, start, LONG_MAX, freed); } static void hugetlbfs_evict_inode(struct inode *inode) { struct resv_map *resv_map; - truncate_hugepages(inode, 0); + remove_inode_hugepages(inode, 0, LLONG_MAX); resv_map = (struct resv_map *)inode->i_mapping->private_data; /* root inode doesn't have the resv_map, so we should check it */ if (resv_map) @@ -397,7 +475,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) if (!RB_EMPTY_ROOT(&mapping->i_mmap)) hugetlb_vmdelete_list(&mapping->i_mmap, pgoff, 0); i_mmap_unlock_write(mapping); - truncate_hugepages(inode, offset); + remove_inode_hugepages(inode, offset, LLONG_MAX); return 0; } diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 530cf6fc24c7e..35afca1692fb9 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -83,11 +83,13 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, int hugetlb_reserve_pages(struct inode *inode, long from, long to, struct vm_area_struct *vma, vm_flags_t vm_flags); -void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed); +long hugetlb_unreserve_pages(struct inode *inode, long start, long end, + long freed); int dequeue_hwpoisoned_huge_page(struct page *page); bool isolate_huge_page(struct page *page, struct list_head *list); void putback_active_hugepage(struct page *page); void free_huge_page(struct page *page); +void hugetlb_fix_reserve_counts(struct inode *inode, bool restore_reserve); extern struct mutex *hugetlb_fault_mutex_table; u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm, struct vm_area_struct *vma, diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 070880fe1ff71..61c52cd5f77b7 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -546,6 +546,28 @@ retry: return del; } +/* + * A rare out of memory error was encountered which prevented removal of + * the reserve map region for a page. The huge page itself was free'ed + * and removed from the page cache. This routine will adjust the subpool + * usage count, and the global reserve count if needed. By incrementing + * these counts, the reserve map entry which could not be deleted will + * appear as a "reserved" entry instead of simply dangling with incorrect + * counts. + */ +void hugetlb_fix_reserve_counts(struct inode *inode, bool restore_reserve) +{ + struct hugepage_subpool *spool = subpool_inode(inode); + long rsv_adjust; + + rsv_adjust = hugepage_subpool_get_pages(spool, 1); + if (restore_reserve && rsv_adjust) { + struct hstate *h = hstate_inode(inode); + + hugetlb_acct_memory(h, 1); + } +} + /* * Count and return the number of huge pages in the reserve map * that intersect with the range [f, t). @@ -3909,7 +3931,8 @@ out_err: return ret; } -void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) +long hugetlb_unreserve_pages(struct inode *inode, long start, long end, + long freed) { struct hstate *h = hstate_inode(inode); struct resv_map *resv_map = inode_resv_map(inode); @@ -3917,8 +3940,17 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) struct hugepage_subpool *spool = subpool_inode(inode); long gbl_reserve; - if (resv_map) - chg = region_del(resv_map, offset, LONG_MAX); + if (resv_map) { + chg = region_del(resv_map, start, end); + /* + * region_del() can fail in the rare case where a region + * must be split and another region descriptor can not be + * allocated. If end == LONG_MAX, it will not fail. + */ + if (chg < 0) + return chg; + } + spin_lock(&inode->i_lock); inode->i_blocks -= (blocks_per_huge_page(h) * freed); spin_unlock(&inode->i_lock); @@ -3929,6 +3961,8 @@ void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed) */ gbl_reserve = hugepage_subpool_put_pages(spool, (chg - freed)); hugetlb_acct_memory(h, -gbl_reserve); + + return 0; } #ifdef CONFIG_ARCH_WANT_HUGE_PMD_SHARE -- GitLab From 1fb1b0e9ef2d661488f8053986c3b7641cae529d Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:44 -0700 Subject: [PATCH 6732/7006] mm/hugetlb: vma_has_reserves() needs to handle fallocate hole punch In vma_has_reserves(), the current assumption is that reserves are always present for shared mappings. However, this will not be the case with fallocate hole punch. When punching a hole, the present page will be deleted as well as the region/reserve map entry (and hence any reservation). vma_has_reserves is passed "chg" which indicates whether or not a region/reserve map is present. Use this to determine if reserves are actually present or were removed via hole punch. Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 61c52cd5f77b7..bd12e8c8bc7b4 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -801,8 +801,19 @@ static bool vma_has_reserves(struct vm_area_struct *vma, long chg) } /* Shared mappings always use reserves */ - if (vma->vm_flags & VM_MAYSHARE) - return true; + if (vma->vm_flags & VM_MAYSHARE) { + /* + * We know VM_NORESERVE is not set. Therefore, there SHOULD + * be a region map for all pages. The only situation where + * there is no region map is if a hole was punched via + * fallocate. In this case, there really are no reverves to + * use. This situation is indicated if chg != 0. + */ + if (chg) + return false; + else + return true; + } /* * Only the process that called mmap() has reserves for -- GitLab From d85f69b0b533ec6d7ac8c21db958c44c6d957c90 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:47 -0700 Subject: [PATCH 6733/7006] mm/hugetlb: alloc_huge_page handle areas hole punched by fallocate Areas hole punched by fallocate will not have entries in the region/reserve map. However, shared mappings with min_size subpool reservations may still have reserved pages. alloc_huge_page needs to handle this special case and do the proper accounting. Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hugetlb.c | 54 +++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/mm/hugetlb.c b/mm/hugetlb.c index bd12e8c8bc7b4..114ad6ce7030a 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1733,34 +1733,58 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, struct hugepage_subpool *spool = subpool_vma(vma); struct hstate *h = hstate_vma(vma); struct page *page; - long chg, commit; + long map_chg, map_commit; + long gbl_chg; int ret, idx; struct hugetlb_cgroup *h_cg; idx = hstate_index(h); /* - * Processes that did not create the mapping will have no - * reserves and will not have accounted against subpool - * limit. Check that the subpool limit can be made before - * satisfying the allocation MAP_NORESERVE mappings may also - * need pages and subpool limit allocated allocated if no reserve - * mapping overlaps. + * Examine the region/reserve map to determine if the process + * has a reservation for the page to be allocated. A return + * code of zero indicates a reservation exists (no change). */ - chg = vma_needs_reservation(h, vma, addr); - if (chg < 0) + map_chg = gbl_chg = vma_needs_reservation(h, vma, addr); + if (map_chg < 0) return ERR_PTR(-ENOMEM); - if (chg || avoid_reserve) - if (hugepage_subpool_get_pages(spool, 1) < 0) { + + /* + * Processes that did not create the mapping will have no + * reserves as indicated by the region/reserve map. Check + * that the allocation will not exceed the subpool limit. + * Allocations for MAP_NORESERVE mappings also need to be + * checked against any subpool limit. + */ + if (map_chg || avoid_reserve) { + gbl_chg = hugepage_subpool_get_pages(spool, 1); + if (gbl_chg < 0) { vma_end_reservation(h, vma, addr); return ERR_PTR(-ENOSPC); } + /* + * Even though there was no reservation in the region/reserve + * map, there could be reservations associated with the + * subpool that can be used. This would be indicated if the + * return value of hugepage_subpool_get_pages() is zero. + * However, if avoid_reserve is specified we still avoid even + * the subpool reservations. + */ + if (avoid_reserve) + gbl_chg = 1; + } + ret = hugetlb_cgroup_charge_cgroup(idx, pages_per_huge_page(h), &h_cg); if (ret) goto out_subpool_put; spin_lock(&hugetlb_lock); - page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve, chg); + /* + * glb_chg is passed to indicate whether or not a page must be taken + * from the global free pool (global change). gbl_chg == 0 indicates + * a reservation exists for the allocation. + */ + page = dequeue_huge_page_vma(h, vma, addr, avoid_reserve, gbl_chg); if (!page) { spin_unlock(&hugetlb_lock); page = alloc_buddy_huge_page(h, NUMA_NO_NODE); @@ -1776,8 +1800,8 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, set_page_private(page, (unsigned long)spool); - commit = vma_commit_reservation(h, vma, addr); - if (unlikely(chg > commit)) { + map_commit = vma_commit_reservation(h, vma, addr); + if (unlikely(map_chg > map_commit)) { /* * The page was added to the reservation map between * vma_needs_reservation and vma_commit_reservation. @@ -1797,7 +1821,7 @@ static struct page *alloc_huge_page(struct vm_area_struct *vma, out_uncharge_cgroup: hugetlb_cgroup_uncharge_cgroup(idx, pages_per_huge_page(h), h_cg); out_subpool_put: - if (chg || avoid_reserve) + if (map_chg || avoid_reserve) hugepage_subpool_put_pages(spool, 1); vma_end_reservation(h, vma, addr); return ERR_PTR(-ENOSPC); -- GitLab From ab76ad540a50191308e5bb6b5e2d9e26c78616d3 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:50 -0700 Subject: [PATCH 6734/7006] hugetlbfs: New huge_add_to_page_cache helper routine Currently, there is only a single place where hugetlbfs pages are added to the page cache. The new fallocate code be adding a second one, so break the functionality out into its own helper. Signed-off-by: Dave Hansen Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/hugetlb.h | 2 ++ mm/hugetlb.c | 27 ++++++++++++++++++--------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 35afca1692fb9..1222fb07a7465 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -333,6 +333,8 @@ struct huge_bootmem_page { struct page *alloc_huge_page_node(struct hstate *h, int nid); struct page *alloc_huge_page_noerr(struct vm_area_struct *vma, unsigned long addr, int avoid_reserve); +int huge_add_to_page_cache(struct page *page, struct address_space *mapping, + pgoff_t idx); /* arch callback */ int __init alloc_bootmem_huge_page(struct hstate *h); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 114ad6ce7030a..d45eacc5653ed 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -3375,6 +3375,23 @@ static bool hugetlbfs_pagecache_present(struct hstate *h, return page != NULL; } +int huge_add_to_page_cache(struct page *page, struct address_space *mapping, + pgoff_t idx) +{ + struct inode *inode = mapping->host; + struct hstate *h = hstate_inode(inode); + int err = add_to_page_cache(page, mapping, idx, GFP_KERNEL); + + if (err) + return err; + ClearPagePrivate(page); + + spin_lock(&inode->i_lock); + inode->i_blocks += blocks_per_huge_page(h); + spin_unlock(&inode->i_lock); + return 0; +} + static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma, struct address_space *mapping, pgoff_t idx, unsigned long address, pte_t *ptep, unsigned int flags) @@ -3422,21 +3439,13 @@ retry: set_page_huge_active(page); if (vma->vm_flags & VM_MAYSHARE) { - int err; - struct inode *inode = mapping->host; - - err = add_to_page_cache(page, mapping, idx, GFP_KERNEL); + int err = huge_add_to_page_cache(page, mapping, idx); if (err) { put_page(page); if (err == -EEXIST) goto retry; goto out; } - ClearPagePrivate(page); - - spin_lock(&inode->i_lock); - inode->i_blocks += blocks_per_huge_page(h); - spin_unlock(&inode->i_lock); } else { lock_page(page); if (unlikely(anon_vma_prepare(vma))) { -- GitLab From 70c3547e36f5c9fbc4caecfeca98f0effa6932c5 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:54 -0700 Subject: [PATCH 6735/7006] hugetlbfs: add hugetlbfs_fallocate() This is based on the shmem version, but it has diverged quite a bit. We have no swap to worry about, nor the new file sealing. Add synchronication via the fault mutex table to coordinate page faults, fallocate allocation and fallocate hole punch. What this allows us to do is move physical memory in and out of a hugetlbfs file without having it mapped. This also gives us the ability to support MADV_REMOVE since it is currently implemented using fallocate(). MADV_REMOVE lets madvise() remove pages from the middle of a hugetlbfs file, which wasn't possible before. hugetlbfs fallocate only operates on whole huge pages. Based on code by Dave Hansen. Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: Dave Hansen Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hugetlbfs/inode.c | 179 +++++++++++++++++++++++++++++++++++++++- include/linux/hugetlb.h | 3 + mm/hugetlb.c | 2 +- 3 files changed, 182 insertions(+), 2 deletions(-) diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 1ef630f81c991..316adb968b658 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -12,6 +12,7 @@ #include #include #include /* remove ASAP */ +#include #include #include #include @@ -84,6 +85,29 @@ static const match_table_t tokens = { {Opt_err, NULL}, }; +#ifdef CONFIG_NUMA +static inline void hugetlb_set_vma_policy(struct vm_area_struct *vma, + struct inode *inode, pgoff_t index) +{ + vma->vm_policy = mpol_shared_policy_lookup(&HUGETLBFS_I(inode)->policy, + index); +} + +static inline void hugetlb_drop_vma_policy(struct vm_area_struct *vma) +{ + mpol_cond_put(vma->vm_policy); +} +#else +static inline void hugetlb_set_vma_policy(struct vm_area_struct *vma, + struct inode *inode, pgoff_t index) +{ +} + +static inline void hugetlb_drop_vma_policy(struct vm_area_struct *vma) +{ +} +#endif + static void huge_pagevec_release(struct pagevec *pvec) { int i; @@ -479,6 +503,158 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset) return 0; } +static long hugetlbfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) +{ + struct hstate *h = hstate_inode(inode); + loff_t hpage_size = huge_page_size(h); + loff_t hole_start, hole_end; + + /* + * For hole punch round up the beginning offset of the hole and + * round down the end. + */ + hole_start = round_up(offset, hpage_size); + hole_end = round_down(offset + len, hpage_size); + + if (hole_end > hole_start) { + struct address_space *mapping = inode->i_mapping; + + mutex_lock(&inode->i_mutex); + i_mmap_lock_write(mapping); + if (!RB_EMPTY_ROOT(&mapping->i_mmap)) + hugetlb_vmdelete_list(&mapping->i_mmap, + hole_start >> PAGE_SHIFT, + hole_end >> PAGE_SHIFT); + i_mmap_unlock_write(mapping); + remove_inode_hugepages(inode, hole_start, hole_end); + mutex_unlock(&inode->i_mutex); + } + + return 0; +} + +static long hugetlbfs_fallocate(struct file *file, int mode, loff_t offset, + loff_t len) +{ + struct inode *inode = file_inode(file); + struct address_space *mapping = inode->i_mapping; + struct hstate *h = hstate_inode(inode); + struct vm_area_struct pseudo_vma; + struct mm_struct *mm = current->mm; + loff_t hpage_size = huge_page_size(h); + unsigned long hpage_shift = huge_page_shift(h); + pgoff_t start, index, end; + int error; + u32 hash; + + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) + return -EOPNOTSUPP; + + if (mode & FALLOC_FL_PUNCH_HOLE) + return hugetlbfs_punch_hole(inode, offset, len); + + /* + * Default preallocate case. + * For this range, start is rounded down and end is rounded up + * as well as being converted to page offsets. + */ + start = offset >> hpage_shift; + end = (offset + len + hpage_size - 1) >> hpage_shift; + + mutex_lock(&inode->i_mutex); + + /* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */ + error = inode_newsize_ok(inode, offset + len); + if (error) + goto out; + + /* + * Initialize a pseudo vma as this is required by the huge page + * allocation routines. If NUMA is configured, use page index + * as input to create an allocation policy. + */ + memset(&pseudo_vma, 0, sizeof(struct vm_area_struct)); + pseudo_vma.vm_flags = (VM_HUGETLB | VM_MAYSHARE | VM_SHARED); + pseudo_vma.vm_file = file; + + for (index = start; index < end; index++) { + /* + * This is supposed to be the vaddr where the page is being + * faulted in, but we have no vaddr here. + */ + struct page *page; + unsigned long addr; + int avoid_reserve = 0; + + cond_resched(); + + /* + * fallocate(2) manpage permits EINTR; we may have been + * interrupted because we are using up too much memory. + */ + if (signal_pending(current)) { + error = -EINTR; + break; + } + + /* Set numa allocation policy based on index */ + hugetlb_set_vma_policy(&pseudo_vma, inode, index); + + /* addr is the offset within the file (zero based) */ + addr = index * hpage_size; + + /* mutex taken here, fault path and hole punch */ + hash = hugetlb_fault_mutex_hash(h, mm, &pseudo_vma, mapping, + index, addr); + mutex_lock(&hugetlb_fault_mutex_table[hash]); + + /* See if already present in mapping to avoid alloc/free */ + page = find_get_page(mapping, index); + if (page) { + put_page(page); + mutex_unlock(&hugetlb_fault_mutex_table[hash]); + hugetlb_drop_vma_policy(&pseudo_vma); + continue; + } + + /* Allocate page and add to page cache */ + page = alloc_huge_page(&pseudo_vma, addr, avoid_reserve); + hugetlb_drop_vma_policy(&pseudo_vma); + if (IS_ERR(page)) { + mutex_unlock(&hugetlb_fault_mutex_table[hash]); + error = PTR_ERR(page); + goto out; + } + clear_huge_page(page, addr, pages_per_huge_page(h)); + __SetPageUptodate(page); + error = huge_add_to_page_cache(page, mapping, index); + if (unlikely(error)) { + put_page(page); + mutex_unlock(&hugetlb_fault_mutex_table[hash]); + goto out; + } + + mutex_unlock(&hugetlb_fault_mutex_table[hash]); + + /* + * page_put due to reference from alloc_huge_page() + * unlock_page because locked by add_to_page_cache() + */ + put_page(page); + unlock_page(page); + } + + if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) + i_size_write(inode, offset + len); + inode->i_ctime = CURRENT_TIME; + spin_lock(&inode->i_lock); + inode->i_private = NULL; + spin_unlock(&inode->i_lock); +out: + mutex_unlock(&inode->i_mutex); + return error; +} + static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = d_inode(dentry); @@ -790,7 +966,8 @@ const struct file_operations hugetlbfs_file_operations = { .mmap = hugetlbfs_file_mmap, .fsync = noop_fsync, .get_unmapped_area = hugetlb_get_unmapped_area, - .llseek = default_llseek, + .llseek = default_llseek, + .fallocate = hugetlbfs_fallocate, }; static const struct inode_operations hugetlbfs_dir_inode_operations = { diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index 1222fb07a7465..5e35379f58a53 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h @@ -330,6 +330,8 @@ struct huge_bootmem_page { #endif }; +struct page *alloc_huge_page(struct vm_area_struct *vma, + unsigned long addr, int avoid_reserve); struct page *alloc_huge_page_node(struct hstate *h, int nid); struct page *alloc_huge_page_noerr(struct vm_area_struct *vma, unsigned long addr, int avoid_reserve); @@ -483,6 +485,7 @@ static inline spinlock_t *huge_pte_lockptr(struct hstate *h, #else /* CONFIG_HUGETLB_PAGE */ struct hstate {}; +#define alloc_huge_page(v, a, r) NULL #define alloc_huge_page_node(h, nid) NULL #define alloc_huge_page_noerr(v, a, r) NULL #define alloc_bootmem_huge_page(h) NULL diff --git a/mm/hugetlb.c b/mm/hugetlb.c index d45eacc5653ed..cd1280c487ff9 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1727,7 +1727,7 @@ static void vma_end_reservation(struct hstate *h, (void)__vma_reservation_common(h, vma, addr, VMA_END_RESV); } -static struct page *alloc_huge_page(struct vm_area_struct *vma, +struct page *alloc_huge_page(struct vm_area_struct *vma, unsigned long addr, int avoid_reserve) { struct hugepage_subpool *spool = subpool_vma(vma); -- GitLab From 72079ba0dfefc1444b4ef98a2fa3d040838a775f Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:01:57 -0700 Subject: [PATCH 6736/7006] mm: madvise allow remove operation for hugetlbfs Now that we have hole punching support for hugetlbfs, we can also support the MADV_REMOVE interface to it. Signed-off-by: Dave Hansen Signed-off-by: Mike Kravetz Reviewed-by: Naoya Horiguchi Acked-by: Hillf Danton Cc: David Rientjes Cc: Hugh Dickins Cc: Davidlohr Bueso Cc: Aneesh Kumar Cc: Christoph Hellwig Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/madvise.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/madvise.c b/mm/madvise.c index ce3a4222c7e7a..c889fcbb530e9 100644 --- a/mm/madvise.c +++ b/mm/madvise.c @@ -301,7 +301,7 @@ static long madvise_remove(struct vm_area_struct *vma, *prev = NULL; /* tell sys_madvise we drop mmap_sem */ - if (vma->vm_flags & (VM_LOCKED | VM_HUGETLB)) + if (vma->vm_flags & VM_LOCKED) return -EINVAL; f = vma->vm_file; -- GitLab From c5c5c9d1008fb15945d0173b3ca75931ef53ae1f Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 8 Sep 2015 15:02:00 -0700 Subject: [PATCH 6737/7006] mm/memblock.c: make memblock_overlaps_region() return bool. memblock_overlaps_region() checks if the given memblock region intersects a region in memblock. If so, it returns the index of the intersected region. But its only caller is memblock_is_region_reserved(), and it returns 0 if false, non-zero if true. Both of these should return bool. Signed-off-by: Tang Chen Cc: Thomas Gleixner Cc: Tejun Heo Cc: Yasuaki Ishimatsu Cc: Luiz Capitulino Cc: Xishi Qiu Cc: Will Deacon Cc: Vladimir Murzin Cc: Fabian Frederick Cc: Alexander Kuleshov Cc: Baoquan He Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memblock.h | 2 +- mm/memblock.c | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/linux/memblock.h b/include/linux/memblock.h index cc4b019720600..d312ae3b51fc6 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -323,7 +323,7 @@ void memblock_enforce_memory_limit(phys_addr_t memory_limit); int memblock_is_memory(phys_addr_t addr); int memblock_is_region_memory(phys_addr_t base, phys_addr_t size); int memblock_is_reserved(phys_addr_t addr); -int memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); +bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); extern void __memblock_dump_all(void); diff --git a/mm/memblock.c b/mm/memblock.c index bde61e8c28c55..08a5126338dbf 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -91,7 +91,7 @@ static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, p return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); } -static long __init_memblock memblock_overlaps_region(struct memblock_type *type, +static bool __init_memblock memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size) { unsigned long i; @@ -103,7 +103,7 @@ static long __init_memblock memblock_overlaps_region(struct memblock_type *type, break; } - return (i < type->cnt) ? i : -1; + return i < type->cnt; } /* @@ -1566,12 +1566,12 @@ int __init_memblock memblock_is_region_memory(phys_addr_t base, phys_addr_t size * Check if the region [@base, @base+@size) intersects a reserved memory block. * * RETURNS: - * 0 if false, non-zero if true + * True if they intersect, false if not. */ -int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) +bool __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t size) { memblock_cap_size(base, &size); - return memblock_overlaps_region(&memblock.reserved, base, size) >= 0; + return memblock_overlaps_region(&memblock.reserved, base, size); } void __init_memblock memblock_trim_memory(phys_addr_t align) -- GitLab From 95cf82ecc1fcb44df1768162343cc8eb88083b86 Mon Sep 17 00:00:00 2001 From: Tang Chen Date: Tue, 8 Sep 2015 15:02:03 -0700 Subject: [PATCH 6738/7006] mem-hotplug: handle node hole when initializing numa_meminfo. When parsing SRAT, all memory ranges are added into numa_meminfo. In numa_init(), before entering numa_cleanup_meminfo(), all possible memory ranges are in numa_meminfo. And numa_cleanup_meminfo() removes all ranges over max_pfn or empty. But, this only works if the nodes are continuous. Let's have a look at the following example: We have an SRAT like this: SRAT: Node 0 PXM 0 [mem 0x00000000-0x5fffffff] SRAT: Node 0 PXM 0 [mem 0x100000000-0x1ffffffffff] SRAT: Node 1 PXM 1 [mem 0x20000000000-0x3ffffffffff] SRAT: Node 4 PXM 2 [mem 0x40000000000-0x5ffffffffff] hotplug SRAT: Node 5 PXM 3 [mem 0x60000000000-0x7ffffffffff] hotplug SRAT: Node 2 PXM 4 [mem 0x80000000000-0x9ffffffffff] hotplug SRAT: Node 3 PXM 5 [mem 0xa0000000000-0xbffffffffff] hotplug SRAT: Node 6 PXM 6 [mem 0xc0000000000-0xdffffffffff] hotplug SRAT: Node 7 PXM 7 [mem 0xe0000000000-0xfffffffffff] hotplug On boot, only node 0,1,2,3 exist. And the numa_meminfo will look like this: numa_meminfo.nr_blks = 9 1. on node 0: [0, 60000000] 2. on node 0: [100000000, 20000000000] 3. on node 1: [20000000000, 40000000000] 4. on node 4: [40000000000, 60000000000] 5. on node 5: [60000000000, 80000000000] 6. on node 2: [80000000000, a0000000000] 7. on node 3: [a0000000000, a0800000000] 8. on node 6: [c0000000000, a0800000000] 9. on node 7: [e0000000000, a0800000000] And numa_cleanup_meminfo() will merge 1 and 2, and remove 8,9 because the end address is over max_pfn, which is a0800000000. But 4 and 5 are not removed because their end addresses are less then max_pfn. But in fact, node 4 and 5 don't exist. In a word, numa_cleanup_meminfo() is not able to handle holes between nodes. Since memory ranges in node 4 and 5 are in numa_meminfo, in numa_register_memblks(), node 4 and 5 will be mistakenly set to online. If you run lscpu, it will show: NUMA node0 CPU(s): 0-14,128-142 NUMA node1 CPU(s): 15-29,143-157 NUMA node2 CPU(s): NUMA node3 CPU(s): NUMA node4 CPU(s): 62-76,190-204 NUMA node5 CPU(s): 78-92,206-220 In this patch, we use memblock_overlaps_region() to check if ranges in numa_meminfo overlap with ranges in memory_block. Since memory_block contains all available memory at boot time, if they overlap, it means the ranges exist. If not, then remove them from numa_meminfo. After this patch, lscpu will show: NUMA node0 CPU(s): 0-14,128-142 NUMA node1 CPU(s): 15-29,143-157 NUMA node4 CPU(s): 62-76,190-204 NUMA node5 CPU(s): 78-92,206-220 Signed-off-by: Tang Chen Reviewed-by: Yasuaki Ishimatsu Cc: Thomas Gleixner Cc: Tejun Heo Cc: Luiz Capitulino Cc: Xishi Qiu Cc: Will Deacon Cc: Vladimir Murzin Cc: Fabian Frederick Cc: Alexander Kuleshov Cc: Baoquan He Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/mm/numa.c | 6 ++++-- include/linux/memblock.h | 2 ++ mm/memblock.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 4053bb58bf92e..c3b3f653ed0c6 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -246,8 +246,10 @@ int __init numa_cleanup_meminfo(struct numa_meminfo *mi) bi->start = max(bi->start, low); bi->end = min(bi->end, high); - /* and there's no empty block */ - if (bi->start >= bi->end) + /* and there's no empty or non-exist block */ + if (bi->start >= bi->end || + !memblock_overlaps_region(&memblock.memory, + bi->start, bi->end - bi->start)) numa_remove_memblk_from(i--, mi); } diff --git a/include/linux/memblock.h b/include/linux/memblock.h index d312ae3b51fc6..c518eb5892603 100644 --- a/include/linux/memblock.h +++ b/include/linux/memblock.h @@ -77,6 +77,8 @@ int memblock_remove(phys_addr_t base, phys_addr_t size); int memblock_free(phys_addr_t base, phys_addr_t size); int memblock_reserve(phys_addr_t base, phys_addr_t size); void memblock_trim_memory(phys_addr_t align); +bool memblock_overlaps_region(struct memblock_type *type, + phys_addr_t base, phys_addr_t size); int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); diff --git a/mm/memblock.c b/mm/memblock.c index 08a5126338dbf..509255223688e 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -91,7 +91,7 @@ static unsigned long __init_memblock memblock_addrs_overlap(phys_addr_t base1, p return ((base1 < (base2 + size2)) && (base2 < (base1 + size1))); } -static bool __init_memblock memblock_overlaps_region(struct memblock_type *type, +bool __init_memblock memblock_overlaps_region(struct memblock_type *type, phys_addr_t base, phys_addr_t size) { unsigned long i; -- GitLab From acda0c3340282bc7c36f4e9a5e2ccb7bb7e64676 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Tue, 8 Sep 2015 15:02:06 -0700 Subject: [PATCH 6739/7006] mm/mempolicy.c: get rid of duplicated check for vma(VM_PFNMAP) in queue_pages_range() This check was introduced as part of 6f4576e3687 ("mempolicy: apply page table walker on queue_pages_range()") which got duplicated by 48684a65b4e ("mm: pagewalk: fix misbehavior of walk_page_range for vma(VM_PFNMAP)") by reintroducing it earlier on queue_page_test_walk() Signed-off-by: Aristeu Rozanski Acked-by: Naoya Horiguchi Acked-by: Kirill A. Shutemov Cc: Andrea Arcangeli Acked-by: Cyrill Gorcunov Cc: Dave Hansen Cc: Kirill A. Shutemov Cc: Pavel Emelyanov Cc: Benjamin Herrenschmidt Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mempolicy.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/mm/mempolicy.c b/mm/mempolicy.c index a7f1e0d1d6b8f..d6f2caee28c04 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -608,9 +608,6 @@ static int queue_pages_test_walk(unsigned long start, unsigned long end, qp->prev = vma; - if (vma->vm_flags & VM_PFNMAP) - return 1; - if (flags & MPOL_MF_LAZY) { /* Similar to task_numa_work, skip inaccessible VMAs */ if (vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE)) -- GitLab From c5b4e1b02f2a0c2309ecd58a235a2f5ee4eb0074 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 8 Sep 2015 15:02:09 -0700 Subject: [PATCH 6740/7006] mm, page_isolation: make set/unset_migratetype_isolate() file-local Nowaday, set/unset_migratetype_isolate() is defined and used only in mm/page_isolation, so let's limit the scope within the file. Signed-off-by: Naoya Horiguchi Acked-by: David Rientjes Acked-by: Vlastimil Babka Cc: Joonsoo Kim Cc: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/page-isolation.h | 5 ----- mm/page_isolation.c | 5 +++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/include/linux/page-isolation.h b/include/linux/page-isolation.h index 2dc1e1697b451..047d64706f2a2 100644 --- a/include/linux/page-isolation.h +++ b/include/linux/page-isolation.h @@ -65,11 +65,6 @@ undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn, bool skip_hwpoisoned_pages); -/* - * Internal functions. Changes pageblock's migrate type. - */ -int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages); -void unset_migratetype_isolate(struct page *page, unsigned migratetype); struct page *alloc_migrate_target(struct page *page, unsigned long private, int **resultp); diff --git a/mm/page_isolation.c b/mm/page_isolation.c index 32fdc1df05e5f..4568fd58f70a0 100644 --- a/mm/page_isolation.c +++ b/mm/page_isolation.c @@ -9,7 +9,8 @@ #include #include "internal.h" -int set_migratetype_isolate(struct page *page, bool skip_hwpoisoned_pages) +static int set_migratetype_isolate(struct page *page, + bool skip_hwpoisoned_pages) { struct zone *zone; unsigned long flags, pfn; @@ -72,7 +73,7 @@ out: return ret; } -void unset_migratetype_isolate(struct page *page, unsigned migratetype) +static void unset_migratetype_isolate(struct page *page, unsigned migratetype) { struct zone *zone; unsigned long flags, nr_pages; -- GitLab From 1b4ace4141db1ddc46f6c9915086dd5e18d7154d Mon Sep 17 00:00:00 2001 From: Chris Metcalf Date: Tue, 8 Sep 2015 15:02:12 -0700 Subject: [PATCH 6741/7006] bootmem: avoid freeing to bootmem after bootmem is done Bootmem isn't popular any more, but some architectures still use it, and freeing to bootmem after calling free_all_bootmem_core() can end up scribbling over random memory. Instead, make sure the kernel generates a warning in this case by ensuring the node_bootmem_map field is non-NULL when are freeing or marking bootmem. An instance of this bug was just fixed in the tile architecture ("tile: use free_bootmem_late() for initrd") and catching this case more widely seems like a good thing. Signed-off-by: Chris Metcalf Acked-by: Mel Gorman Cc: Yasuaki Ishimatsu Cc: Pekka Enberg Cc: Paul McQuade Cc: Tang Chen Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/bootmem.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mm/bootmem.c b/mm/bootmem.c index a23dd19346548..3b6380784c285 100644 --- a/mm/bootmem.c +++ b/mm/bootmem.c @@ -236,6 +236,7 @@ static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) count += pages; while (pages--) __free_pages_bootmem(page++, cur++, 0); + bdata->node_bootmem_map = NULL; bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count); @@ -294,6 +295,9 @@ static void __init __free(bootmem_data_t *bdata, sidx + bdata->node_min_pfn, eidx + bdata->node_min_pfn); + if (WARN_ON(bdata->node_bootmem_map == NULL)) + return; + if (bdata->hint_idx > sidx) bdata->hint_idx = sidx; @@ -314,6 +318,9 @@ static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx, eidx + bdata->node_min_pfn, flags); + if (WARN_ON(bdata->node_bootmem_map == NULL)) + return 0; + for (idx = sidx; idx < eidx; idx++) if (test_and_set_bit(idx, bdata->node_bootmem_map)) { if (exclusive) { -- GitLab From 64b990d2957cb535fe1c17b9694d5d4f7de69962 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Tue, 8 Sep 2015 15:02:15 -0700 Subject: [PATCH 6742/7006] mm: drop __nocast from vm_flags_t definition __nocast does no good for vm_flags_t. It only produces useless sparse warnings. Let's drop it. Signed-off-by: Kirill A. Shutemov Cc: Oleg Nesterov Acked-by: David Rientjes Cc: Johannes Weiner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h index c8d0a73d64c45..3d6baa7d4534c 100644 --- a/include/linux/mm_types.h +++ b/include/linux/mm_types.h @@ -235,7 +235,7 @@ struct page_frag_cache { bool pfmemalloc; }; -typedef unsigned long __nocast vm_flags_t; +typedef unsigned long vm_flags_t; /* * A region containing a mapping of a non-memory backed file under NOMMU -- GitLab From 0b802f101d0c6caeeee89066dc2c8665082a83df Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Tue, 8 Sep 2015 15:02:18 -0700 Subject: [PATCH 6743/7006] mm: vmscan: never isolate more pages than necessary If transparent huge pages are enabled, we can isolate many more pages than we actually need to scan, because we count both single and huge pages equally in isolate_lru_pages(). Since commit 5bc7b8aca942d ("mm: thp: add split tail pages to shrink page list in page reclaim"), we scan all the tail pages immediately after a huge page split (see shrink_page_list()). As a result, we can reclaim up to SWAP_CLUSTER_MAX * HPAGE_PMD_NR (512 MB) in one run! This is easy to catch on memcg reclaim with zswap enabled. The latter makes swapout instant so that if we happen to scan an unreferenced huge page we will evict both its head and tail pages immediately, which is likely to result in excessive reclaim. Signed-off-by: Vladimir Davydov Cc: Johannes Weiner Reviewed-by: Michal Hocko Cc: Vlastimil Babka Cc: Minchan Kim Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index bf23c88621ce6..0b1aab411cb08 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1359,7 +1359,8 @@ static unsigned long isolate_lru_pages(unsigned long nr_to_scan, unsigned long nr_taken = 0; unsigned long scan; - for (scan = 0; scan < nr_to_scan && !list_empty(src); scan++) { + for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan && + !list_empty(src); scan++) { struct page *page; int nr_pages; -- GitLab From c54839a722a02818677bcabe57e957f0ce4f841d Mon Sep 17 00:00:00 2001 From: Jaewon Kim Date: Tue, 8 Sep 2015 15:02:21 -0700 Subject: [PATCH 6744/7006] vmscan: fix increasing nr_isolated incurred by putback unevictable pages reclaim_clean_pages_from_list() assumes that shrink_page_list() returns number of pages removed from the candidate list. But shrink_page_list() puts back mlocked pages without passing it to caller and without counting as nr_reclaimed. This increases nr_isolated. To fix this, this patch changes shrink_page_list() to pass unevictable pages back to caller. Caller will take care those pages. Minchan said: It fixes two issues. 1. With unevictable page, cma_alloc will be successful. Exactly speaking, cma_alloc of current kernel will fail due to unevictable pages. 2. fix leaking of NR_ISOLATED counter of vmstat With it, too_many_isolated works. Otherwise, it could make hang until the process get SIGKILL. Signed-off-by: Jaewon Kim Acked-by: Minchan Kim Cc: Mel Gorman Acked-by: Vlastimil Babka Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 0b1aab411cb08..8276a3a615ca0 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -1196,7 +1196,7 @@ cull_mlocked: if (PageSwapCache(page)) try_to_free_swap(page); unlock_page(page); - putback_lru_page(page); + list_add(&page->lru, &ret_pages); continue; activate_locked: -- GitLab From fa23f56d90ed7bd760ae2aea6dfb2f501a099e90 Mon Sep 17 00:00:00 2001 From: "Sean O. Stalley" Date: Tue, 8 Sep 2015 15:02:24 -0700 Subject: [PATCH 6745/7006] mm: add support for __GFP_ZERO flag to dma_pool_alloc() Currently a call to dma_pool_alloc() with a ___GFP_ZERO flag returns a non-zeroed memory region. This patchset adds support for the __GFP_ZERO flag to dma_pool_alloc(), adds 2 wrapper functions for allocing zeroed memory from a pool, and provides a coccinelle script for finding & replacing instances of dma_pool_alloc() followed by memset(0) with a single dma_pool_zalloc() call. There was some concern that this always calls memset() to zero, instead of passing __GFP_ZERO into the page allocator. [https://lkml.org/lkml/2015/7/15/881] I ran a test on my system to get an idea of how often dma_pool_alloc() calls into pool_alloc_page(). After Boot: [ 30.119863] alloc_calls:541, page_allocs:7 After an hour: [ 3600.951031] alloc_calls:9566, page_allocs:12 After copying 1GB file onto a USB drive: [ 4260.657148] alloc_calls:17225, page_allocs:12 It doesn't look like dma_pool_alloc() calls down to the page allocator very often (at least on my system). This patch (of 4): Currently the __GFP_ZERO flag is ignored by dma_pool_alloc(). Make dma_pool_alloc() zero the memory if this flag is set. Signed-off-by: Sean O. Stalley Acked-by: David Rientjes Cc: Vinod Koul Cc: Bjorn Helgaas Cc: Gilles Muller Cc: Nicolas Palix Cc: Michal Marek Cc: Sebastian Andrzej Siewior Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/dmapool.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mm/dmapool.c b/mm/dmapool.c index 4b657099111f8..71a8998cd03a6 100644 --- a/mm/dmapool.c +++ b/mm/dmapool.c @@ -337,7 +337,7 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, /* pool_alloc_page() might sleep, so temporarily drop &pool->lock */ spin_unlock_irqrestore(&pool->lock, flags); - page = pool_alloc_page(pool, mem_flags); + page = pool_alloc_page(pool, mem_flags & (~__GFP_ZERO)); if (!page) return NULL; @@ -375,9 +375,14 @@ void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, break; } } - memset(retval, POOL_POISON_ALLOCATED, pool->size); + if (!(mem_flags & __GFP_ZERO)) + memset(retval, POOL_POISON_ALLOCATED, pool->size); #endif spin_unlock_irqrestore(&pool->lock, flags); + + if (mem_flags & __GFP_ZERO) + memset(retval, 0, pool->size); + return retval; } EXPORT_SYMBOL(dma_pool_alloc); -- GitLab From ad82362b2defd4adad87d8538617b2f51a4bf9c3 Mon Sep 17 00:00:00 2001 From: "Sean O. Stalley" Date: Tue, 8 Sep 2015 15:02:27 -0700 Subject: [PATCH 6746/7006] mm: add dma_pool_zalloc() call to DMA API Add a wrapper function for dma_pool_alloc() to get zeroed memory. Signed-off-by: Sean O. Stalley Cc: Vinod Koul Cc: Bjorn Helgaas Cc: Gilles Muller Cc: Nicolas Palix Cc: Michal Marek Cc: Sebastian Andrzej Siewior Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/DMA-API.txt | 7 +++++++ include/linux/dmapool.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/Documentation/DMA-API.txt b/Documentation/DMA-API.txt index 7eba542eff7c8..edccacd4f048a 100644 --- a/Documentation/DMA-API.txt +++ b/Documentation/DMA-API.txt @@ -104,6 +104,13 @@ crossing restrictions, pass 0 for alloc; passing 4096 says memory allocated from this pool must not cross 4KByte boundaries. + void *dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags, + dma_addr_t *handle) + +Wraps dma_pool_alloc() and also zeroes the returned memory if the +allocation attempt succeeded. + + void *dma_pool_alloc(struct dma_pool *pool, gfp_t gfp_flags, dma_addr_t *dma_handle); diff --git a/include/linux/dmapool.h b/include/linux/dmapool.h index e1043f79122f8..53ba737505df3 100644 --- a/include/linux/dmapool.h +++ b/include/linux/dmapool.h @@ -24,6 +24,12 @@ void dma_pool_destroy(struct dma_pool *pool); void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle); +static inline void *dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags, + dma_addr_t *handle) +{ + return dma_pool_alloc(pool, mem_flags | __GFP_ZERO, handle); +} + void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr); /* -- GitLab From 01a7fd337b2c2af97e9c55bb9406a222a2e209d3 Mon Sep 17 00:00:00 2001 From: "Sean O. Stalley" Date: Tue, 8 Sep 2015 15:02:30 -0700 Subject: [PATCH 6747/7006] pci: mm: add pci_pool_zalloc() call Add a wrapper function for pci_pool_alloc() to get zeroed memory. Signed-off-by: Sean O. Stalley Cc: Vinod Koul Cc: Bjorn Helgaas Cc: Gilles Muller Cc: Nicolas Palix Cc: Michal Marek Cc: Sebastian Andrzej Siewior Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/pci.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/pci.h b/include/linux/pci.h index 1a64733c48c74..e90eb22de6286 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1227,6 +1227,8 @@ int pci_set_vga_state(struct pci_dev *pdev, bool decode, dma_pool_create(name, &pdev->dev, size, align, allocation) #define pci_pool_destroy(pool) dma_pool_destroy(pool) #define pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle) +#define pci_pool_zalloc(pool, flags, handle) \ + dma_pool_zalloc(pool, flags, handle) #define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr) struct msix_entry { -- GitLab From 1fc524d74cf40072a2de3f74a920818398dbff30 Mon Sep 17 00:00:00 2001 From: "Sean O. Stalley" Date: Tue, 8 Sep 2015 15:02:33 -0700 Subject: [PATCH 6748/7006] coccinelle: mm: scripts/coccinelle/api/alloc/pool_zalloc-simple.cocci add [pci|dma]_pool_zalloc coccinelle check. replaces instances of [pci|dma]_pool_alloc() followed by memset(0) with [pci|dma]_pool_zalloc(). Signed-off-by: Sean O. Stalley Acked-by: Julia Lawall Cc: Vinod Koul Cc: Bjorn Helgaas Cc: Gilles Muller Cc: Nicolas Palix Cc: Michal Marek Cc: Sebastian Andrzej Siewior Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../api/alloc/pool_zalloc-simple.cocci | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 scripts/coccinelle/api/alloc/pool_zalloc-simple.cocci diff --git a/scripts/coccinelle/api/alloc/pool_zalloc-simple.cocci b/scripts/coccinelle/api/alloc/pool_zalloc-simple.cocci new file mode 100644 index 0000000000000..9b7eb321a0256 --- /dev/null +++ b/scripts/coccinelle/api/alloc/pool_zalloc-simple.cocci @@ -0,0 +1,84 @@ +/// +/// Use *_pool_zalloc rather than *_pool_alloc followed by memset with 0 +/// +// Copyright: (C) 2015 Intel Corp. GPLv2. +// Options: --no-includes --include-headers +// +// Keywords: dma_pool_zalloc, pci_pool_zalloc +// + +virtual context +virtual patch +virtual org +virtual report + +//---------------------------------------------------------- +// For context mode +//---------------------------------------------------------- + +@depends on context@ +expression x; +statement S; +@@ + +* x = \(dma_pool_alloc\|pci_pool_alloc\)(...); + if ((x==NULL) || ...) S +* memset(x,0, ...); + +//---------------------------------------------------------- +// For patch mode +//---------------------------------------------------------- + +@depends on patch@ +expression x; +expression a,b,c; +statement S; +@@ + +- x = dma_pool_alloc(a,b,c); ++ x = dma_pool_zalloc(a,b,c); + if ((x==NULL) || ...) S +- memset(x,0,...); + +@depends on patch@ +expression x; +expression a,b,c; +statement S; +@@ + +- x = pci_pool_alloc(a,b,c); ++ x = pci_pool_zalloc(a,b,c); + if ((x==NULL) || ...) S +- memset(x,0,...); + +//---------------------------------------------------------- +// For org and report mode +//---------------------------------------------------------- + +@r depends on org || report@ +expression x; +expression a,b,c; +statement S; +position p; +@@ + + x = @p\(dma_pool_alloc\|pci_pool_alloc\)(a,b,c); + if ((x==NULL) || ...) S + memset(x,0, ...); + +@script:python depends on org@ +p << r.p; +x << r.x; +@@ + +msg="%s" % (x) +msg_safe=msg.replace("[","@(").replace("]",")") +coccilib.org.print_todo(p[0], msg_safe) + +@script:python depends on report@ +p << r.p; +x << r.x; +@@ + +msg="WARNING: *_pool_zalloc should be used for %s, instead of *_pool_alloc/memset" % (x) +coccilib.report.print_report(p[0], msg) -- GitLab From f2849aa09d4fbc4145ebb5dc96187c9ab967f5cf Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:02:36 -0700 Subject: [PATCH 6749/7006] mm, compaction: more robust check for scanners meeting Assorted compaction cleanups and optimizations. The interesting patches are 4 and 5. In 4, skipping of compound pages in single iteration is improved for migration scanner, so it works also for !PageLRU compound pages such as hugetlbfs, slab etc. Patch 5 introduces this kind of skipping in the free scanner. The trick is that we can read compound_order() without any protection, if we are careful to filter out values larger than MAX_ORDER. The only danger is that we skip too much. The same trick was already used for reading the freepage order in the migrate scanner. To demonstrate improvements of Patches 4 and 5 I've run stress-highalloc from mmtests, set to simulate THP allocations (including __GFP_COMP) on a 4GB system where 1GB was occupied by hugetlbfs pages. I'll include just the relevant stats: Patch 3 Patch 4 Patch 5 Compaction stalls 7523 7529 7515 Compaction success 323 304 322 Compaction failures 7200 7224 7192 Page migrate success 247778 264395 240737 Page migrate failure 15358 33184 21621 Compaction pages isolated 906928 980192 909983 Compaction migrate scanned 2005277 1692805 1498800 Compaction free scanned 13255284 11539986 9011276 Compaction cost 288 305 277 With 5 iterations per patch, the results are still noisy, but we can see that Patch 4 does reduce migrate_scanned by 15% thanks to skipping the hugetlbfs pages at once. Interestingly, free_scanned is also reduced and I have no idea why. Patch 5 further reduces free_scanned as expected, by 15%. Other stats are unaffected modulo noise. [1] https://lkml.org/lkml/2015/1/19/158 This patch (of 5): Compaction should finish when the migration and free scanner meet, i.e. they reach the same pageblock. Currently however, the test in compact_finished() simply just compares the exact pfns, which may yield a false negative when the free scanner position is in the middle of a pageblock and the migration scanner reaches the begining of the same pageblock. This hasn't been a problem until commit e14c720efdd7 ("mm, compaction: remember position within pageblock in free pages scanner") allowed the free scanner position to be in the middle of a pageblock between invocations. The hot-fix 1d5bfe1ffb5b ("mm, compaction: prevent infinite loop in compact_zone") prevented the issue by adding a special check in the migration scanner to satisfy the current detection of scanners meeting. However, the proper fix is to make the detection more robust. This patch introduces the compact_scanners_met() function that returns true when the free scanner position is in the same or lower pageblock than the migration scanner. The special case in isolate_migratepages() introduced by 1d5bfe1ffb5b is removed. Suggested-by: Joonsoo Kim Signed-off-by: Vlastimil Babka Cc: Minchan Kim Acked-by: Mel Gorman Acked-by: Joonsoo Kim Acked-by: Michal Nazarewicz Cc: Naoya Horiguchi Cc: Christoph Lameter Acked-by: Rik van Riel Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 018f08da99a2e..7077b81a48937 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -897,6 +897,16 @@ static bool suitable_migration_target(struct page *page) return false; } +/* + * Test whether the free scanner has reached the same or lower pageblock than + * the migration scanner, and compaction should thus terminate. + */ +static inline bool compact_scanners_met(struct compact_control *cc) +{ + return (cc->free_pfn >> pageblock_order) + <= (cc->migrate_pfn >> pageblock_order); +} + /* * Based on information in the current compact_control, find blocks * suitable for isolating free pages from and then isolate them. @@ -1127,12 +1137,8 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, } acct_isolated(zone, cc); - /* - * Record where migration scanner will be restarted. If we end up in - * the same pageblock as the free scanner, make the scanners fully - * meet so that compact_finished() terminates compaction. - */ - cc->migrate_pfn = (end_pfn <= cc->free_pfn) ? low_pfn : cc->free_pfn; + /* Record where migration scanner will be restarted. */ + cc->migrate_pfn = low_pfn; return cc->nr_migratepages ? ISOLATE_SUCCESS : ISOLATE_NONE; } @@ -1147,7 +1153,7 @@ static int __compact_finished(struct zone *zone, struct compact_control *cc, return COMPACT_PARTIAL; /* Compaction run completes if the migrate and free scanner meet */ - if (cc->free_pfn <= cc->migrate_pfn) { + if (compact_scanners_met(cc)) { /* Let the next compaction start anew. */ zone->compact_cached_migrate_pfn[0] = zone->zone_start_pfn; zone->compact_cached_migrate_pfn[1] = zone->zone_start_pfn; @@ -1376,7 +1382,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) * migrate_pages() may return -ENOMEM when scanners meet * and we want compact_finished() to detect it */ - if (err == -ENOMEM && cc->free_pfn > cc->migrate_pfn) { + if (err == -ENOMEM && !compact_scanners_met(cc)) { ret = COMPACT_PARTIAL; goto out; } -- GitLab From f5f61a320bf6275f37fcabf6645b4ac8e683c007 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:02:39 -0700 Subject: [PATCH 6750/7006] mm, compaction: simplify handling restart position in free pages scanner Handling the position where compaction free scanner should restart (stored in cc->free_pfn) got more complex with commit e14c720efdd7 ("mm, compaction: remember position within pageblock in free pages scanner"). Currently the position is updated in each loop iteration of isolate_freepages(), although it should be enough to update it only when breaking from the loop. There's also an extra check outside the loop updates the position in case we have met the migration scanner. This can be simplified if we move the test for having isolated enough from the for-loop header next to the test for contention, and determining the restart position only in these cases. We can reuse the isolate_start_pfn variable for this instead of setting cc->free_pfn directly. Outside the loop, we can simply set cc->free_pfn to current value of isolate_start_pfn without any extra check. Also add a VM_BUG_ON to catch possible mistake in the future, in case we later add a new condition that terminates isolate_freepages_block() prematurely without also considering the condition in isolate_freepages(). Signed-off-by: Vlastimil Babka Cc: Minchan Kim Acked-by: Mel Gorman Acked-by: Joonsoo Kim Cc: Michal Nazarewicz Cc: Naoya Horiguchi Cc: Christoph Lameter Cc: Rik van Riel Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 7077b81a48937..2c1e1ff321bff 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -943,8 +943,7 @@ static void isolate_freepages(struct compact_control *cc) * pages on cc->migratepages. We stop searching if the migrate * and free page scanners meet or enough free pages are isolated. */ - for (; block_start_pfn >= low_pfn && - cc->nr_migratepages > cc->nr_freepages; + for (; block_start_pfn >= low_pfn; block_end_pfn = block_start_pfn, block_start_pfn -= pageblock_nr_pages, isolate_start_pfn = block_start_pfn) { @@ -976,6 +975,8 @@ static void isolate_freepages(struct compact_control *cc) block_end_pfn, freelist, false); /* + * If we isolated enough freepages, or aborted due to async + * compaction being contended, terminate the loop. * Remember where the free scanner should restart next time, * which is where isolate_freepages_block() left off. * But if it scanned the whole pageblock, isolate_start_pfn @@ -984,27 +985,31 @@ static void isolate_freepages(struct compact_control *cc) * In that case we will however want to restart at the start * of the previous pageblock. */ - cc->free_pfn = (isolate_start_pfn < block_end_pfn) ? - isolate_start_pfn : - block_start_pfn - pageblock_nr_pages; - - /* - * isolate_freepages_block() might have aborted due to async - * compaction being contended - */ - if (cc->contended) + if ((cc->nr_freepages >= cc->nr_migratepages) + || cc->contended) { + if (isolate_start_pfn >= block_end_pfn) + isolate_start_pfn = + block_start_pfn - pageblock_nr_pages; break; + } else { + /* + * isolate_freepages_block() should not terminate + * prematurely unless contended, or isolated enough + */ + VM_BUG_ON(isolate_start_pfn < block_end_pfn); + } } /* split_free_page does not map the pages */ map_pages(freelist); /* - * If we crossed the migrate scanner, we want to keep it that way - * so that compact_finished() may detect this + * Record where the free scanner will restart next time. Either we + * broke from the loop and set isolate_start_pfn based on the last + * call to isolate_freepages_block(), or we met the migration scanner + * and the loop terminated due to isolate_start_pfn < low_pfn */ - if (block_start_pfn < low_pfn) - cc->free_pfn = cc->migrate_pfn; + cc->free_pfn = isolate_start_pfn; } /* -- GitLab From 02333641e2cf4ac9f23eeeb01183ed8318d346ca Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:02:42 -0700 Subject: [PATCH 6751/7006] mm, compaction: encapsulate resetting cached scanner positions Reseting the cached compaction scanner positions is now open-coded in __reset_isolation_suitable() and compact_finished(). Encapsulate the functionality in a new function reset_cached_positions(). Signed-off-by: Vlastimil Babka Cc: Minchan Kim Cc: Mel Gorman Cc: Joonsoo Kim Acked-by: Michal Nazarewicz Cc: Naoya Horiguchi Cc: Christoph Lameter Cc: Rik van Riel Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 2c1e1ff321bff..0dce7e87d771b 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -207,6 +207,13 @@ static inline bool isolation_suitable(struct compact_control *cc, return !get_pageblock_skip(page); } +static void reset_cached_positions(struct zone *zone) +{ + zone->compact_cached_migrate_pfn[0] = zone->zone_start_pfn; + zone->compact_cached_migrate_pfn[1] = zone->zone_start_pfn; + zone->compact_cached_free_pfn = zone_end_pfn(zone); +} + /* * This function is called to clear all cached information on pageblocks that * should be skipped for page isolation when the migrate and free page scanner @@ -218,9 +225,6 @@ static void __reset_isolation_suitable(struct zone *zone) unsigned long end_pfn = zone_end_pfn(zone); unsigned long pfn; - zone->compact_cached_migrate_pfn[0] = start_pfn; - zone->compact_cached_migrate_pfn[1] = start_pfn; - zone->compact_cached_free_pfn = end_pfn; zone->compact_blockskip_flush = false; /* Walk the zone and mark every pageblock as suitable for isolation */ @@ -238,6 +242,8 @@ static void __reset_isolation_suitable(struct zone *zone) clear_pageblock_skip(page); } + + reset_cached_positions(zone); } void reset_isolation_suitable(pg_data_t *pgdat) @@ -1160,9 +1166,7 @@ static int __compact_finished(struct zone *zone, struct compact_control *cc, /* Compaction run completes if the migrate and free scanner meet */ if (compact_scanners_met(cc)) { /* Let the next compaction start anew. */ - zone->compact_cached_migrate_pfn[0] = zone->zone_start_pfn; - zone->compact_cached_migrate_pfn[1] = zone->zone_start_pfn; - zone->compact_cached_free_pfn = zone_end_pfn(zone); + reset_cached_positions(zone); /* * Mark that the PG_migrate_skip information should be cleared -- GitLab From 29c0dde830f8c08ceacf2d3edf6dc8ddd9a9c3c4 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:02:46 -0700 Subject: [PATCH 6752/7006] mm, compaction: always skip all compound pages by order in migrate scanner The compaction migrate scanner tries to skip THP pages by their order, to reduce number of iterations for pages it cannot isolate. The check is only done if PageLRU() is true, which means it applies to THP pages, but not e.g. hugetlbfs pages or any other non-LRU compound pages, which we have to iterate by base pages. This limitation comes from the assumption that it's only safe to read compound_order() when we have the zone's lru_lock and THP cannot be split under us. But the only danger (after filtering out order values that are not below MAX_ORDER, to prevent overflows) is that we skip too much or too little after reading a bogus compound_order() due to a rare race. This is the same reasoning as patch 99c0fd5e51c4 ("mm, compaction: skip buddy pages by their order in the migrate scanner") introduced for unsafely reading PageBuddy() order. After this patch, all pages are tested for PageCompound() and we skip them by compound_order(). The test is done after the test for balloon_page_movable() as we don't want to assume if balloon pages (or other pages with own isolation and migration implementation if a generic API gets implemented) are compound or not. When tested with stress-highalloc from mmtests on 4GB system with 1GB hugetlbfs pages, the vmstat compact_migrate_scanned count decreased by 15%. [kirill.shutemov@linux.intel.com: change PageTransHuge checks to PageCompound for different series was squashed here] Signed-off-by: Vlastimil Babka Cc: Minchan Kim Acked-by: Mel Gorman Acked-by: Joonsoo Kim Acked-by: Michal Nazarewicz Cc: Naoya Horiguchi Cc: Christoph Lameter Cc: Rik van Riel Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 47 +++++++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 0dce7e87d771b..1ccb015ab1eba 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -680,6 +680,8 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, /* Time to isolate some pages for migration */ for (; low_pfn < end_pfn; low_pfn++) { + bool is_lru; + /* * Periodically drop the lock (if held) regardless of its * contention, to give chance to IRQs. Abort async compaction @@ -723,36 +725,35 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, * It's possible to migrate LRU pages and balloon pages * Skip any other type of page */ - if (!PageLRU(page)) { + is_lru = PageLRU(page); + if (!is_lru) { if (unlikely(balloon_page_movable(page))) { if (balloon_page_isolate(page)) { /* Successfully isolated */ goto isolate_success; } } - continue; } /* - * PageLRU is set. lru_lock normally excludes isolation - * splitting and collapsing (collapsing has already happened - * if PageLRU is set) but the lock is not necessarily taken - * here and it is wasteful to take it just to check transhuge. - * Check TransHuge without lock and skip the whole pageblock if - * it's either a transhuge or hugetlbfs page, as calling - * compound_order() without preventing THP from splitting the - * page underneath us may return surprising results. + * Regardless of being on LRU, compound pages such as THP and + * hugetlbfs are not to be compacted. We can potentially save + * a lot of iterations if we skip them at once. The check is + * racy, but we can consider only valid values and the only + * danger is skipping too much. */ - if (PageTransHuge(page)) { - if (!locked) - low_pfn = ALIGN(low_pfn + 1, - pageblock_nr_pages) - 1; - else - low_pfn += (1 << compound_order(page)) - 1; + if (PageCompound(page)) { + unsigned int comp_order = compound_order(page); + + if (likely(comp_order < MAX_ORDER)) + low_pfn += (1UL << comp_order) - 1; continue; } + if (!is_lru) + continue; + /* * Migration will fail if an anonymous page is pinned in memory, * so avoid taking lru_lock and isolating it unnecessarily in an @@ -769,11 +770,17 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, if (!locked) break; - /* Recheck PageLRU and PageTransHuge under lock */ + /* Recheck PageLRU and PageCompound under lock */ if (!PageLRU(page)) continue; - if (PageTransHuge(page)) { - low_pfn += (1 << compound_order(page)) - 1; + + /* + * Page become compound since the non-locked check, + * and it's on LRU. It can only be a THP so the order + * is safe to read and it's 0 for tail pages. + */ + if (unlikely(PageCompound(page))) { + low_pfn += (1UL << compound_order(page)) - 1; continue; } } @@ -784,7 +791,7 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, if (__isolate_lru_page(page, isolate_mode) != 0) continue; - VM_BUG_ON_PAGE(PageTransCompound(page), page); + VM_BUG_ON_PAGE(PageCompound(page), page); /* Successfully isolated */ del_page_from_lru_list(page, lruvec, page_lru(page)); -- GitLab From 9fcd6d2e052eef525e94a9ae58dbe7ed4df4f5a7 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:02:49 -0700 Subject: [PATCH 6753/7006] mm, compaction: skip compound pages by order in free scanner The compaction free scanner is looking for PageBuddy() pages and skipping all others. For large compound pages such as THP or hugetlbfs, we can save a lot of iterations if we skip them at once using their compound_order(). This is generally unsafe and we can read a bogus value of order due to a race, but if we are careful, the only danger is skipping too much. When tested with stress-highalloc from mmtests on 4GB system with 1GB hugetlbfs pages, the vmstat compact_free_scanned count decreased by at least 15%. Signed-off-by: Vlastimil Babka Cc: Minchan Kim Cc: Mel Gorman Acked-by: Joonsoo Kim Acked-by: Michal Nazarewicz Cc: Naoya Horiguchi Cc: Christoph Lameter Cc: Rik van Riel Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/mm/compaction.c b/mm/compaction.c index 1ccb015ab1eba..8f64d35339900 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -437,6 +437,24 @@ static unsigned long isolate_freepages_block(struct compact_control *cc, if (!valid_page) valid_page = page; + + /* + * For compound pages such as THP and hugetlbfs, we can save + * potentially a lot of iterations if we skip them at once. + * The check is racy, but we can consider only valid values + * and the only danger is skipping too much. + */ + if (PageCompound(page)) { + unsigned int comp_order = compound_order(page); + + if (likely(comp_order < MAX_ORDER)) { + blockpfn += (1UL << comp_order) - 1; + cursor += (1UL << comp_order) - 1; + } + + goto isolate_fail; + } + if (!PageBuddy(page)) goto isolate_fail; @@ -496,6 +514,13 @@ isolate_fail: } + /* + * There is a tiny chance that we have read bogus compound_order(), + * so be careful to not go outside of the pageblock. + */ + if (unlikely(blockpfn > end_pfn)) + blockpfn = end_pfn; + trace_mm_compaction_isolate_freepages(*start_pfn, blockpfn, nr_scanned, total_isolated); -- GitLab From 243db5351aae5e6756fb610d41431a30d44b56a6 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:02:52 -0700 Subject: [PATCH 6754/7006] Revert "selftests: add hugetlbfstest" This manually reverts 7e50533d4b842 ("selftests: add hugetlbfstest"). The hugetlbfstest test depends on hugetlb pages being counted in a task's rss. This functionality is not in the kernel, so the test will always fail. Remove test to avoid confusion. Signed-off-by: Mike Kravetz Acked-by: Naoya Horiguchi Cc: Joern Engel Cc: Davidlohr Bueso Cc: David Rientjes Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/vm/Makefile | 1 - tools/testing/selftests/vm/hugetlbfstest.c | 86 ---------------------- tools/testing/selftests/vm/run_vmtests | 11 --- 3 files changed, 98 deletions(-) delete mode 100644 tools/testing/selftests/vm/hugetlbfstest.c diff --git a/tools/testing/selftests/vm/Makefile b/tools/testing/selftests/vm/Makefile index 0d6854744b373..d36fab7d8ebd9 100644 --- a/tools/testing/selftests/vm/Makefile +++ b/tools/testing/selftests/vm/Makefile @@ -4,7 +4,6 @@ CFLAGS = -Wall BINARIES = compaction_test BINARIES += hugepage-mmap BINARIES += hugepage-shm -BINARIES += hugetlbfstest BINARIES += map_hugetlb BINARIES += thuge-gen BINARIES += transhuge-stress diff --git a/tools/testing/selftests/vm/hugetlbfstest.c b/tools/testing/selftests/vm/hugetlbfstest.c deleted file mode 100644 index 02e1072ec1874..0000000000000 --- a/tools/testing/selftests/vm/hugetlbfstest.c +++ /dev/null @@ -1,86 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef unsigned long long u64; - -static size_t length = 1 << 24; - -static u64 read_rss(void) -{ - char buf[4096], *s = buf; - int i, fd; - u64 rss; - - fd = open("/proc/self/statm", O_RDONLY); - assert(fd > 2); - memset(buf, 0, sizeof(buf)); - read(fd, buf, sizeof(buf) - 1); - for (i = 0; i < 1; i++) - s = strchr(s, ' ') + 1; - rss = strtoull(s, NULL, 10); - return rss << 12; /* assumes 4k pagesize */ -} - -static void do_mmap(int fd, int extra_flags, int unmap) -{ - int *p; - int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags; - u64 before, after; - int ret; - - before = read_rss(); - p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0); - assert(p != MAP_FAILED || - !"mmap returned an unexpected error"); - after = read_rss(); - assert(llabs(after - before - length) < 0x40000 || - !"rss didn't grow as expected"); - if (!unmap) - return; - ret = munmap(p, length); - assert(!ret || !"munmap returned an unexpected error"); - after = read_rss(); - assert(llabs(after - before) < 0x40000 || - !"rss didn't shrink as expected"); -} - -static int open_file(const char *path) -{ - int fd, err; - - unlink(path); - fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL - | O_LARGEFILE | O_CLOEXEC, 0600); - assert(fd > 2); - unlink(path); - err = ftruncate(fd, length); - assert(!err); - return fd; -} - -int main(void) -{ - int hugefd, fd; - - fd = open_file("/dev/shm/hugetlbhog"); - hugefd = open_file("/hugepages/hugetlbhog"); - - system("echo 100 > /proc/sys/vm/nr_hugepages"); - do_mmap(-1, MAP_ANONYMOUS, 1); - do_mmap(fd, 0, 1); - do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 1); - do_mmap(hugefd, 0, 1); - do_mmap(hugefd, MAP_HUGETLB, 1); - /* Leak the last one to test do_exit() */ - do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 0); - printf("oll korrekt.\n"); - return 0; -} diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index 831adeb5fc552..d891d6e326f49 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -75,17 +75,6 @@ else echo "[PASS]" fi -echo "--------------------" -echo "running hugetlbfstest" -echo "--------------------" -./hugetlbfstest -if [ $? -ne 0 ]; then - echo "[FAIL]" - exitcode=1 -else - echo "[PASS]" -fi - echo "--------------------" echo "running userfaultfd" echo "--------------------" -- GitLab From fd5a9ecd6880619bea74c6b12ec86819eacfb012 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:02:55 -0700 Subject: [PATCH 6755/7006] selftests:vm: point to libhugetlbfs for regression testing The hugetlb selftests provide minimal coverage. Have run script point people at libhugetlbfs for better regression testing. Signed-off-by: Mike Kravetz Acked-by: Naoya Horiguchi Cc: Joern Engel Cc: Davidlohr Bueso Cc: David Rientjes Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/vm/run_vmtests | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index d891d6e326f49..9179ce8df485d 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -75,6 +75,10 @@ else echo "[PASS]" fi +echo "NOTE: The above hugetlb tests provide minimal coverage. Use" +echo " https://github.com/libhugetlbfs/libhugetlbfs.git for" +echo " hugetlb regression testing." + echo "--------------------" echo "running userfaultfd" echo "--------------------" -- GitLab From e6590740ceb83fd014fae7d571fe5a5d5886b7c8 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Tue, 8 Sep 2015 15:02:58 -0700 Subject: [PATCH 6756/7006] Documentation: update libhugetlbfs location and use for testing The URL for libhugetlbfs has changed. Also, put a stronger emphasis on using libgugetlbfs for hugetlb regression testing. Signed-off-by: Mike Kravetz Acked-by: Naoya Horiguchi Cc: Joern Engel Cc: Davidlohr Bueso Cc: David Rientjes Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/hugetlbpage.txt | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt index 030977fb8d2dc..54dd9b9c6c31a 100644 --- a/Documentation/vm/hugetlbpage.txt +++ b/Documentation/vm/hugetlbpage.txt @@ -329,7 +329,14 @@ Examples 3) hugepage-mmap: see tools/testing/selftests/vm/hugepage-mmap.c -4) The libhugetlbfs (http://libhugetlbfs.sourceforge.net) library provides a - wide range of userspace tools to help with huge page usability, environment - setup, and control. Furthermore it provides useful test cases that should be - used when modifying code to ensure no regressions are introduced. +4) The libhugetlbfs (https://github.com/libhugetlbfs/libhugetlbfs) library + provides a wide range of userspace tools to help with huge page usability, + environment setup, and control. + +Kernel development regression testing +===================================== + +The most complete set of hugetlb tests are in the libhugetlbfs repository. +If you modify any hugetlb related code, use the libhugetlbfs test suite +to check for regressions. In addition, if you add any new hugetlb +functionality, please add appropriate tests to libhugetlbfs. -- GitLab From 6b0f68e32ea8749ff7d4a66cd5761e915e48e59d Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 8 Sep 2015 15:03:01 -0700 Subject: [PATCH 6757/7006] mm: add utility for early copy from unmapped ram When booting an arm64 kernel w/initrd using UEFI/grub, use of mem= will likely cut off part or all of the initrd. This leaves it outside the kernel linear map which leads to failure when unpacking. The x86 code has a similar need to relocate an initrd outside of mapped memory in some cases. The current x86 code uses early_memremap() to copy the original initrd from unmapped to mapped RAM. This patchset creates a generic copy_from_early_mem() utility based on that x86 code and has arm64 and x86 share it in their respective initrd relocation code. This patch (of 3): In some early boot circumstances, it may be necessary to copy from RAM outside the kernel linear mapping to mapped RAM. The need to relocate an initrd is one example in the x86 code. This patch creates a helper function based on current x86 code. Signed-off-by: Mark Salter Cc: Catalin Marinas Cc: Will Deacon Cc: Arnd Bergmann Cc: Ard Biesheuvel Cc: Mark Rutland Cc: Russell King Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Yinghai Lu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/asm-generic/early_ioremap.h | 6 ++++++ mm/early_ioremap.c | 22 ++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/asm-generic/early_ioremap.h b/include/asm-generic/early_ioremap.h index a5de55c04fb2e..e539f27ec51ba 100644 --- a/include/asm-generic/early_ioremap.h +++ b/include/asm-generic/early_ioremap.h @@ -33,6 +33,12 @@ extern void early_ioremap_setup(void); */ extern void early_ioremap_reset(void); +/* + * Early copy from unmapped memory to kernel mapped memory. + */ +extern void copy_from_early_mem(void *dest, phys_addr_t src, + unsigned long size); + #else static inline void early_ioremap_init(void) { } static inline void early_ioremap_setup(void) { } diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c index e10ccd299d666..a0baeb4be934b 100644 --- a/mm/early_ioremap.c +++ b/mm/early_ioremap.c @@ -217,6 +217,28 @@ early_memremap(resource_size_t phys_addr, unsigned long size) return (__force void *)__early_ioremap(phys_addr, size, FIXMAP_PAGE_NORMAL); } + +#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) + +void __init copy_from_early_mem(void *dest, phys_addr_t src, unsigned long size) +{ + unsigned long slop, clen; + char *p; + + while (size) { + slop = src & ~PAGE_MASK; + clen = size; + if (clen > MAX_MAP_CHUNK - slop) + clen = MAX_MAP_CHUNK - slop; + p = early_memremap(src & PAGE_MASK, clen + slop); + memcpy(dest, p + slop, clen); + early_memunmap(p, clen + slop); + dest += clen; + src += clen; + size -= clen; + } +} + #else /* CONFIG_MMU */ void __init __iomem * -- GitLab From 1570f0d7ab425c1e0905715bf9cc98b2a82e723f Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 8 Sep 2015 15:03:04 -0700 Subject: [PATCH 6758/7006] arm64: support initrd outside kernel linear map The use of mem= could leave part or all of the initrd outside of the kernel linear map. This will lead to an error when unpacking the initrd and a probable failure to boot. This patch catches that situation and relocates the initrd to be fully within the linear map. Signed-off-by: Mark Salter Acked-by: Will Deacon Cc: Catalin Marinas Cc: Arnd Bergmann Cc: Ard Biesheuvel Cc: Mark Rutland Cc: Russell King Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Yinghai Lu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm64/kernel/setup.c | 62 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c index 8884788812433..6bab21f84a9ff 100644 --- a/arch/arm64/kernel/setup.c +++ b/arch/arm64/kernel/setup.c @@ -339,6 +339,67 @@ static void __init request_standard_resources(void) } } +#ifdef CONFIG_BLK_DEV_INITRD +/* + * Relocate initrd if it is not completely within the linear mapping. + * This would be the case if mem= cuts out all or part of it. + */ +static void __init relocate_initrd(void) +{ + phys_addr_t orig_start = __virt_to_phys(initrd_start); + phys_addr_t orig_end = __virt_to_phys(initrd_end); + phys_addr_t ram_end = memblock_end_of_DRAM(); + phys_addr_t new_start; + unsigned long size, to_free = 0; + void *dest; + + if (orig_end <= ram_end) + return; + + /* + * Any of the original initrd which overlaps the linear map should + * be freed after relocating. + */ + if (orig_start < ram_end) + to_free = ram_end - orig_start; + + size = orig_end - orig_start; + + /* initrd needs to be relocated completely inside linear mapping */ + new_start = memblock_find_in_range(0, PFN_PHYS(max_pfn), + size, PAGE_SIZE); + if (!new_start) + panic("Cannot relocate initrd of size %ld\n", size); + memblock_reserve(new_start, size); + + initrd_start = __phys_to_virt(new_start); + initrd_end = initrd_start + size; + + pr_info("Moving initrd from [%llx-%llx] to [%llx-%llx]\n", + orig_start, orig_start + size - 1, + new_start, new_start + size - 1); + + dest = (void *)initrd_start; + + if (to_free) { + memcpy(dest, (void *)__phys_to_virt(orig_start), to_free); + dest += to_free; + } + + copy_from_early_mem(dest, orig_start + to_free, size - to_free); + + if (to_free) { + pr_info("Freeing original RAMDISK from [%llx-%llx]\n", + orig_start, orig_start + to_free - 1); + memblock_free(orig_start, to_free); + } +} +#else +static inline void __init relocate_initrd(void) +{ +} +#endif + u64 __cpu_logical_map[NR_CPUS] = { [0 ... NR_CPUS-1] = INVALID_HWID }; void __init setup_arch(char **cmdline_p) @@ -372,6 +433,7 @@ void __init setup_arch(char **cmdline_p) acpi_boot_table_init(); paging_init(); + relocate_initrd(); request_standard_resources(); early_ioremap_reset(); -- GitLab From 5dd2c4bded8776ee93c8f38b739fea531095067f Mon Sep 17 00:00:00 2001 From: Mark Salter Date: Tue, 8 Sep 2015 15:03:07 -0700 Subject: [PATCH 6759/7006] x86: use generic early mem copy The early_ioremap library now has a generic copy_from_early_mem() function. Use the generic copy function for x86 relocate_initrd(). [akpm@linux-foundation.org: remove MAX_MAP_CHUNK define, per Yinghai Lu] Signed-off-by: Mark Salter Cc: Catalin Marinas Cc: Will Deacon Cc: Arnd Bergmann Cc: Ard Biesheuvel Cc: Mark Rutland Cc: Russell King Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Yinghai Lu Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/kernel/setup.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index b143c2d04420c..baadbf90a7c59 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -317,15 +317,12 @@ static u64 __init get_ramdisk_size(void) return ramdisk_size; } -#define MAX_MAP_CHUNK (NR_FIX_BTMAPS << PAGE_SHIFT) static void __init relocate_initrd(void) { /* Assume only end is not page aligned */ u64 ramdisk_image = get_ramdisk_image(); u64 ramdisk_size = get_ramdisk_size(); u64 area_size = PAGE_ALIGN(ramdisk_size); - unsigned long slop, clen, mapaddr; - char *p, *q; /* We need to move the initrd down into directly mapped mem */ relocated_ramdisk = memblock_find_in_range(0, PFN_PHYS(max_pfn_mapped), @@ -343,25 +340,8 @@ static void __init relocate_initrd(void) printk(KERN_INFO "Allocated new RAMDISK: [mem %#010llx-%#010llx]\n", relocated_ramdisk, relocated_ramdisk + ramdisk_size - 1); - q = (char *)initrd_start; - - /* Copy the initrd */ - while (ramdisk_size) { - slop = ramdisk_image & ~PAGE_MASK; - clen = ramdisk_size; - if (clen > MAX_MAP_CHUNK-slop) - clen = MAX_MAP_CHUNK-slop; - mapaddr = ramdisk_image & PAGE_MASK; - p = early_memremap(mapaddr, clen+slop); - memcpy(q, p+slop, clen); - early_memunmap(p, clen+slop); - q += clen; - ramdisk_image += clen; - ramdisk_size -= clen; - } + copy_from_early_mem((void *)initrd_start, ramdisk_image, ramdisk_size); - ramdisk_image = get_ramdisk_image(); - ramdisk_size = get_ramdisk_size(); printk(KERN_INFO "Move RAMDISK from [mem %#010llx-%#010llx] to" " [mem %#010llx-%#010llx]\n", ramdisk_image, ramdisk_image + ramdisk_size - 1, -- GitLab From 7d1900c744b2e4687b3e467edf58373c02bcf22d Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 15:03:10 -0700 Subject: [PATCH 6760/7006] mm/hwpoison: fix failure to split thp w/ refcount held THP pages will get a refcount in madvise_hwpoison() w/ MF_COUNT_INCREASED flag, however, the refcount is still held when fail to split THP pages. Fix it by reducing the refcount of THP pages when fail to split THP. Signed-off-by: Wanpeng Li Cc: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory-failure.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 016c814101edb..8ad923a93539b 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1725,6 +1725,8 @@ int soft_offline_page(struct page *page, int flags) if (PageAnon(hpage) && unlikely(split_huge_page(hpage))) { pr_info("soft offline: %#lx: failed to split THP\n", pfn); + if (flags & MF_COUNT_INCREASED) + put_page(page); return -EBUSY; } } -- GitLab From 1e0e635be82132167a134b5a9c884e70e61f8373 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 15:03:13 -0700 Subject: [PATCH 6761/7006] mm/hwpoison: fix PageHWPoison test/set race There is a race between madvise_hwpoison path and memory_failure: CPU0 CPU1 madvise_hwpoison get_user_pages_fast PageHWPoison check (false) memory_failure TestSetPageHWPoison soft_offline_page PageHWPoison check (true) return -EBUSY (without put_page) Signed-off-by: Wanpeng Li Suggested-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory-failure.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 8ad923a93539b..863544d84a099 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1719,6 +1719,8 @@ int soft_offline_page(struct page *page, int flags) if (PageHWPoison(page)) { pr_info("soft offline: %#lx page already poisoned\n", pfn); + if (flags & MF_COUNT_INCREASED) + put_page(page); return -EBUSY; } if (!PageHuge(page) && PageTransHuge(hpage)) { -- GitLab From 94bf4ec84a84d3ab2513b4e681fd3d083328d76d Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 15:03:15 -0700 Subject: [PATCH 6762/7006] mm/hwpoison: introduce put_hwpoison_page to put refcount for memory error handling Introduce put_hwpoison_page to put refcount for memory error handling. Signed-off-by: Wanpeng Li Suggested-by: Naoya Horiguchi Acked-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mm.h | 1 + mm/memory-failure.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/include/linux/mm.h b/include/linux/mm.h index bab8ff89da508..11df1a8ea38bd 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -2169,6 +2169,7 @@ extern int memory_failure(unsigned long pfn, int trapno, int flags); extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); extern int unpoison_memory(unsigned long pfn); extern int get_hwpoison_page(struct page *page); +extern void put_hwpoison_page(struct page *page); extern int sysctl_memory_failure_early_kill; extern int sysctl_memory_failure_recovery; extern void shake_page(struct page *p, int access); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 863544d84a099..5ceb8253e33b0 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -934,6 +934,27 @@ int get_hwpoison_page(struct page *page) } EXPORT_SYMBOL_GPL(get_hwpoison_page); +/** + * put_hwpoison_page() - Put refcount for memory error handling: + * @page: raw error page (hit by memory error) + */ +void put_hwpoison_page(struct page *page) +{ + struct page *head = compound_head(page); + + if (PageHuge(head)) { + put_page(head); + return; + } + + if (PageTransHuge(head)) + if (page != head) + put_page(head); + + put_page(page); +} +EXPORT_SYMBOL_GPL(put_hwpoison_page); + /* * Do all that is necessary to remove user space mappings. Unmap * the pages and send SIGBUS to the processes if the data was dirty. -- GitLab From be91748fa6ca6909853c3dc630d65e45084962d7 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 15:03:18 -0700 Subject: [PATCH 6763/7006] mm/hwpoison: fix refcount of THP head page in no-injection case Hwpoison injection takes a refcount of target page and another refcount of head page of THP if the target page is the tail page of a THP. However, current code doesn't release the refcount of head page if the THP is not supported to be injected wrt hwpoison filter. Fix it by reducing the refcount of head page if the target page is the tail page of a THP and it is not supported to be injected. Signed-off-by: Wanpeng Li Acked-by: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hwpoison-inject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c index bf73ac17dad42..aeba0edd6e447 100644 --- a/mm/hwpoison-inject.c +++ b/mm/hwpoison-inject.c @@ -58,7 +58,7 @@ inject: pr_info("Injecting memory failure at pfn %#lx\n", pfn); return memory_failure(pfn, 18, MF_COUNT_INCREASED); put_out: - put_page(p); + put_hwpoison_page(p); return 0; } -- GitLab From 665d9da7f0a9bd80b64d0024630806e45c7ff7d7 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 15:03:21 -0700 Subject: [PATCH 6764/7006] mm/hwpoison: replace most of put_page in memory error handling by put_hwpoison_page Replace most instances of put_page() in memory error handling with put_hwpoison_page(). Signed-off-by: Wanpeng Li Cc: Naoya Horiguchi Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory-failure.c | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 5ceb8253e33b0..5420d3819adf9 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1174,9 +1174,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) pr_err("MCE: %#lx: thp split failed\n", pfn); if (TestClearPageHWPoison(p)) atomic_long_sub(nr_pages, &num_poisoned_pages); - put_page(p); - if (p != hpage) - put_page(hpage); + put_hwpoison_page(p); return -EBUSY; } VM_BUG_ON_PAGE(!page_count(p), p); @@ -1237,14 +1235,14 @@ int memory_failure(unsigned long pfn, int trapno, int flags) printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn); atomic_long_sub(nr_pages, &num_poisoned_pages); unlock_page(hpage); - put_page(hpage); + put_hwpoison_page(hpage); return 0; } if (hwpoison_filter(p)) { if (TestClearPageHWPoison(p)) atomic_long_sub(nr_pages, &num_poisoned_pages); unlock_page(hpage); - put_page(hpage); + put_hwpoison_page(hpage); return 0; } @@ -1258,7 +1256,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) if (PageHuge(p) && PageTail(p) && TestSetPageHWPoison(hpage)) { action_result(pfn, MF_MSG_POISONED_HUGE, MF_IGNORED); unlock_page(hpage); - put_page(hpage); + put_hwpoison_page(hpage); return 0; } /* @@ -1492,9 +1490,9 @@ int unpoison_memory(unsigned long pfn) } unlock_page(page); - put_page(page); + put_hwpoison_page(page); if (freeit && !(pfn == my_zero_pfn(0) && page_count(p) == 1)) - put_page(page); + put_hwpoison_page(page); return 0; } @@ -1554,7 +1552,7 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) /* * Try to free it. */ - put_page(page); + put_hwpoison_page(page); shake_page(page, 1); /* @@ -1563,7 +1561,7 @@ static int get_any_page(struct page *page, unsigned long pfn, int flags) ret = __get_any_page(page, pfn, 0); if (!PageLRU(page)) { /* Drop page reference which is from __get_any_page() */ - put_page(page); + put_hwpoison_page(page); pr_info("soft_offline: %#lx: unknown non LRU page type %lx\n", pfn, page->flags); return -EIO; @@ -1586,7 +1584,7 @@ static int soft_offline_huge_page(struct page *page, int flags) lock_page(hpage); if (PageHWPoison(hpage)) { unlock_page(hpage); - put_page(hpage); + put_hwpoison_page(hpage); pr_info("soft offline: %#lx hugepage already poisoned\n", pfn); return -EBUSY; } @@ -1597,7 +1595,7 @@ static int soft_offline_huge_page(struct page *page, int flags) * get_any_page() and isolate_huge_page() takes a refcount each, * so need to drop one here. */ - put_page(hpage); + put_hwpoison_page(hpage); if (!ret) { pr_info("soft offline: %#lx hugepage failed to isolate\n", pfn); return -EBUSY; @@ -1646,7 +1644,7 @@ static int __soft_offline_page(struct page *page, int flags) wait_on_page_writeback(page); if (PageHWPoison(page)) { unlock_page(page); - put_page(page); + put_hwpoison_page(page); pr_info("soft offline: %#lx page already poisoned\n", pfn); return -EBUSY; } @@ -1661,7 +1659,7 @@ static int __soft_offline_page(struct page *page, int flags) * would need to fix isolation locking first. */ if (ret == 1) { - put_page(page); + put_hwpoison_page(page); pr_info("soft_offline: %#lx: invalidated\n", pfn); SetPageHWPoison(page); atomic_long_inc(&num_poisoned_pages); @@ -1678,7 +1676,7 @@ static int __soft_offline_page(struct page *page, int flags) * Drop page reference which is came from get_any_page() * successful isolate_lru_page() already took another one. */ - put_page(page); + put_hwpoison_page(page); if (!ret) { LIST_HEAD(pagelist); inc_zone_page_state(page, NR_ISOLATED_ANON + @@ -1741,7 +1739,7 @@ int soft_offline_page(struct page *page, int flags) if (PageHWPoison(page)) { pr_info("soft offline: %#lx page already poisoned\n", pfn); if (flags & MF_COUNT_INCREASED) - put_page(page); + put_hwpoison_page(page); return -EBUSY; } if (!PageHuge(page) && PageTransHuge(hpage)) { @@ -1749,7 +1747,7 @@ int soft_offline_page(struct page *page, int flags) pr_info("soft offline: %#lx: failed to split THP\n", pfn); if (flags & MF_COUNT_INCREASED) - put_page(page); + put_hwpoison_page(page); return -EBUSY; } } -- GitLab From 8e30456b6c56029ecbb43b777519175e478adfbf Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 8 Sep 2015 15:03:24 -0700 Subject: [PATCH 6765/7006] mm/hwpoison: introduce num_poisoned_pages wrappers num_poisoned_pages counter will be changed outside mm/memory-failure.c by a subsequent patch, so this patch prepares wrappers to manipulate it. Signed-off-by: Naoya Horiguchi Tested-by: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swapops.h | 23 +++++++++++++++++++++++ mm/memory-failure.c | 30 ++++++++++++++---------------- 2 files changed, 37 insertions(+), 16 deletions(-) diff --git a/include/linux/swapops.h b/include/linux/swapops.h index cedf3d3c373f1..ec04669f2a3bf 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -164,6 +164,9 @@ static inline int is_write_migration_entry(swp_entry_t entry) #endif #ifdef CONFIG_MEMORY_FAILURE + +extern atomic_long_t num_poisoned_pages __read_mostly; + /* * Support for hardware poisoned pages */ @@ -177,6 +180,26 @@ static inline int is_hwpoison_entry(swp_entry_t entry) { return swp_type(entry) == SWP_HWPOISON; } + +static inline void num_poisoned_pages_inc(void) +{ + atomic_long_inc(&num_poisoned_pages); +} + +static inline void num_poisoned_pages_dec(void) +{ + atomic_long_dec(&num_poisoned_pages); +} + +static inline void num_poisoned_pages_add(long num) +{ + atomic_long_add(num, &num_poisoned_pages); +} + +static inline void num_poisoned_pages_sub(long num) +{ + atomic_long_sub(num, &num_poisoned_pages); +} #else static inline swp_entry_t make_hwpoison_entry(struct page *page) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 5420d3819adf9..393ea13b07546 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1121,7 +1121,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) nr_pages = 1 << compound_order(hpage); else /* normal page or thp */ nr_pages = 1; - atomic_long_add(nr_pages, &num_poisoned_pages); + num_poisoned_pages_add(nr_pages); /* * We need/can do nothing about count=0 pages. @@ -1149,7 +1149,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) if (PageHWPoison(hpage)) { if ((hwpoison_filter(p) && TestClearPageHWPoison(p)) || (p != hpage && TestSetPageHWPoison(hpage))) { - atomic_long_sub(nr_pages, &num_poisoned_pages); + num_poisoned_pages_sub(nr_pages); unlock_page(hpage); return 0; } @@ -1173,7 +1173,7 @@ int memory_failure(unsigned long pfn, int trapno, int flags) else pr_err("MCE: %#lx: thp split failed\n", pfn); if (TestClearPageHWPoison(p)) - atomic_long_sub(nr_pages, &num_poisoned_pages); + num_poisoned_pages_sub(nr_pages); put_hwpoison_page(p); return -EBUSY; } @@ -1233,14 +1233,14 @@ int memory_failure(unsigned long pfn, int trapno, int flags) */ if (!PageHWPoison(p)) { printk(KERN_ERR "MCE %#lx: just unpoisoned\n", pfn); - atomic_long_sub(nr_pages, &num_poisoned_pages); + num_poisoned_pages_sub(nr_pages); unlock_page(hpage); put_hwpoison_page(hpage); return 0; } if (hwpoison_filter(p)) { if (TestClearPageHWPoison(p)) - atomic_long_sub(nr_pages, &num_poisoned_pages); + num_poisoned_pages_sub(nr_pages); unlock_page(hpage); put_hwpoison_page(hpage); return 0; @@ -1469,7 +1469,7 @@ int unpoison_memory(unsigned long pfn) return 0; } if (TestClearPageHWPoison(p)) - atomic_long_dec(&num_poisoned_pages); + num_poisoned_pages_dec(); pr_info("MCE: Software-unpoisoned free page %#lx\n", pfn); return 0; } @@ -1483,7 +1483,7 @@ int unpoison_memory(unsigned long pfn) */ if (TestClearPageHWPoison(page)) { pr_info("MCE: Software-unpoisoned page %#lx\n", pfn); - atomic_long_sub(nr_pages, &num_poisoned_pages); + num_poisoned_pages_sub(nr_pages); freeit = 1; if (PageHuge(page)) clear_page_hwpoison_huge_page(page); @@ -1619,11 +1619,10 @@ static int soft_offline_huge_page(struct page *page, int flags) if (PageHuge(page)) { set_page_hwpoison_huge_page(hpage); dequeue_hwpoisoned_huge_page(hpage); - atomic_long_add(1 << compound_order(hpage), - &num_poisoned_pages); + num_poisoned_pages_add(1 << compound_order(hpage)); } else { SetPageHWPoison(page); - atomic_long_inc(&num_poisoned_pages); + num_poisoned_pages_inc(); } } return ret; @@ -1662,7 +1661,7 @@ static int __soft_offline_page(struct page *page, int flags) put_hwpoison_page(page); pr_info("soft_offline: %#lx: invalidated\n", pfn); SetPageHWPoison(page); - atomic_long_inc(&num_poisoned_pages); + num_poisoned_pages_inc(); return 0; } @@ -1683,7 +1682,7 @@ static int __soft_offline_page(struct page *page, int flags) page_is_file_cache(page)); list_add(&page->lru, &pagelist); if (!TestSetPageHWPoison(page)) - atomic_long_inc(&num_poisoned_pages); + num_poisoned_pages_dec(); ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL, MIGRATE_SYNC, MR_MEMORY_FAILURE); if (ret) { @@ -1699,7 +1698,7 @@ static int __soft_offline_page(struct page *page, int flags) if (ret > 0) ret = -EIO; if (TestClearPageHWPoison(page)) - atomic_long_dec(&num_poisoned_pages); + num_poisoned_pages_dec(); } } else { pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n", @@ -1765,11 +1764,10 @@ int soft_offline_page(struct page *page, int flags) if (PageHuge(page)) { set_page_hwpoison_huge_page(hpage); if (!dequeue_hwpoisoned_huge_page(hpage)) - atomic_long_add(1 << compound_order(hpage), - &num_poisoned_pages); + num_poisoned_pages_add(1 << compound_order(hpage)); } else { if (!TestSetPageHWPoison(page)) - atomic_long_inc(&num_poisoned_pages); + num_poisoned_pages_inc(); } } return ret; -- GitLab From da1b13ccfbebe0b9d69b5d61eff0a675e19e69a5 Mon Sep 17 00:00:00 2001 From: Wanpeng Li Date: Tue, 8 Sep 2015 15:03:27 -0700 Subject: [PATCH 6766/7006] mm/hwpoison: fix race between soft_offline_page and unpoison_memory Wanpeng Li reported a race between soft_offline_page() and unpoison_memory(), which causes the following kernel panic: BUG: Bad page state in process bash pfn:97000 page:ffffea00025c0000 count:0 mapcount:1 mapping: (null) index:0x7f4fdbe00 flags: 0x1fffff80080048(uptodate|active|swapbacked) page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set bad because of flags: flags: 0x40(active) Modules linked in: snd_hda_codec_hdmi i915 rpcsec_gss_krb5 nfsv4 dns_resolver bnep rfcomm nfsd bluetooth auth_rpcgss nfs_acl nfs rfkill lockd grace sunrpc i2c_algo_bit drm_kms_helper snd_hda_codec_realtek snd_hda_codec_generic drm snd_hda_intel fscache snd_hda_codec x86_pkg_temp_thermal coretemp kvm_intel snd_hda_core snd_hwdep kvm snd_pcm snd_seq_dummy snd_seq_oss crct10dif_pclmul snd_seq_midi crc32_pclmul snd_seq_midi_event ghash_clmulni_intel snd_rawmidi aesni_intel lrw gf128mul snd_seq glue_helper ablk_helper snd_seq_device cryptd fuse snd_timer dcdbas serio_raw mei_me parport_pc snd mei ppdev i2c_core video lp soundcore parport lpc_ich shpchp mfd_core ext4 mbcache jbd2 sd_mod e1000e ahci ptp libahci crc32c_intel libata pps_core CPU: 3 PID: 2211 Comm: bash Not tainted 4.2.0-rc5-mm1+ #45 Hardware name: Dell Inc. OptiPlex 7020/0F5C5X, BIOS A03 01/08/2015 Call Trace: dump_stack+0x48/0x5c bad_page+0xe6/0x140 free_pages_prepare+0x2f9/0x320 ? uncharge_list+0xdd/0x100 free_hot_cold_page+0x40/0x170 __put_single_page+0x20/0x30 put_page+0x25/0x40 unmap_and_move+0x1a6/0x1f0 migrate_pages+0x100/0x1d0 ? kill_procs+0x100/0x100 ? unlock_page+0x6f/0x90 __soft_offline_page+0x127/0x2a0 soft_offline_page+0xa6/0x200 This race is explained like below: CPU0 CPU1 soft_offline_page __soft_offline_page TestSetPageHWPoison unpoison_memory PageHWPoison check (true) TestClearPageHWPoison put_page -> release refcount held by get_hwpoison_page in unpoison_memory put_page -> release refcount held by isolate_lru_page in __soft_offline_page migrate_pages The second put_page() releases refcount held by isolate_lru_page() which will lead to unmap_and_move() releases the last refcount of page and w/ mapcount still 1 since try_to_unmap() is not called if there is only one user map the page. Anyway, the page refcount and mapcount will still mess if the page is mapped by multiple users. This race was introduced by commit 4491f71260 ("mm/memory-failure: set PageHWPoison before migrate_pages()"), which focuses on preventing the reuse of successfully migrated page. Before this commit we prevent the reuse by changing the migratetype to MIGRATE_ISOLATE during soft offlining, which has the following problems, so simply reverting the commit is not a best option: 1) it doesn't eliminate the reuse completely, because set_migratetype_isolate() can fail to set MIGRATE_ISOLATE to the target page if the pageblock of the page contains one or more unmovable pages (i.e. has_unmovable_pages() returns true). 2) the original code changes migratetype to MIGRATE_ISOLATE forcibly, and sets it to MIGRATE_MOVABLE forcibly after soft offline, regardless of the original migratetype state, which could impact other subsystems like memory hotplug or compaction. This patch moves PageSetHWPoison just after put_page() in unmap_and_move(), which closes up the reported race window and minimizes another race window b/w SetPageHWPoison and reallocation (which causes the reuse of soft-offlined page.) The latter race window still exists but it's acceptable, because it's rare and effectively the same as ordinary "containment failure" case even if it happens, so keep the window open is acceptable. Fixes: 4491f71260 ("mm/memory-failure: set PageHWPoison before migrate_pages()") Signed-off-by: Wanpeng Li Signed-off-by: Naoya Horiguchi Reported-by: Wanpeng Li Tested-by: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swapops.h | 14 ++++++++++++++ mm/memory-failure.c | 4 ---- mm/migrate.c | 9 +++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/include/linux/swapops.h b/include/linux/swapops.h index ec04669f2a3bf..5c3a5f3e7eec6 100644 --- a/include/linux/swapops.h +++ b/include/linux/swapops.h @@ -181,6 +181,11 @@ static inline int is_hwpoison_entry(swp_entry_t entry) return swp_type(entry) == SWP_HWPOISON; } +static inline bool test_set_page_hwpoison(struct page *page) +{ + return TestSetPageHWPoison(page); +} + static inline void num_poisoned_pages_inc(void) { atomic_long_inc(&num_poisoned_pages); @@ -211,6 +216,15 @@ static inline int is_hwpoison_entry(swp_entry_t swp) { return 0; } + +static inline bool test_set_page_hwpoison(struct page *page) +{ + return false; +} + +static inline void num_poisoned_pages_inc(void) +{ +} #endif #if defined(CONFIG_MEMORY_FAILURE) || defined(CONFIG_MIGRATION) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index 393ea13b07546..b0664c23838b8 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1681,8 +1681,6 @@ static int __soft_offline_page(struct page *page, int flags) inc_zone_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); list_add(&page->lru, &pagelist); - if (!TestSetPageHWPoison(page)) - num_poisoned_pages_dec(); ret = migrate_pages(&pagelist, new_page, NULL, MPOL_MF_MOVE_ALL, MIGRATE_SYNC, MR_MEMORY_FAILURE); if (ret) { @@ -1697,8 +1695,6 @@ static int __soft_offline_page(struct page *page, int flags) pfn, ret, page->flags); if (ret > 0) ret = -EIO; - if (TestClearPageHWPoison(page)) - num_poisoned_pages_dec(); } } else { pr_info("soft offline: %#lx: isolation failed: %d, page count %d, type %lx\n", diff --git a/mm/migrate.c b/mm/migrate.c index 5c08cab5419e7..918defbdda0e5 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -880,8 +880,7 @@ static int __unmap_and_move(struct page *page, struct page *newpage, /* Establish migration ptes or remove ptes */ if (page_mapped(page)) { try_to_unmap(page, - TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS| - TTU_IGNORE_HWPOISON); + TTU_MIGRATION|TTU_IGNORE_MLOCK|TTU_IGNORE_ACCESS); page_was_mapped = 1; } @@ -952,9 +951,11 @@ out: dec_zone_page_state(page, NR_ISOLATED_ANON + page_is_file_cache(page)); /* Soft-offlined page shouldn't go through lru cache list */ - if (reason == MR_MEMORY_FAILURE) + if (reason == MR_MEMORY_FAILURE) { put_page(page); - else + if (!test_set_page_hwpoison(page)) + num_poisoned_pages_inc(); + } else putback_lru_page(page); } -- GitLab From 230ac719c500e58e71342be381ad2042a8cffc42 Mon Sep 17 00:00:00 2001 From: Naoya Horiguchi Date: Tue, 8 Sep 2015 15:03:29 -0700 Subject: [PATCH 6767/7006] mm/hwpoison: don't try to unpoison containment-failed pages memory_failure() can be called at any page at any time, which means that we can't eliminate the possibility of containment failure. In such case the best option is to leak the page intentionally (and never touch it later.) We have an unpoison function for testing, and it cannot handle such containment-failed pages, which results in kernel panic (visible with various calltraces.) So this patch suggests that we limit the unpoisonable pages to properly contained pages and ignore any other ones. Testers are recommended to keep in mind that there're un-unpoisonable pages when writing test programs. Signed-off-by: Naoya Horiguchi Tested-by: Wanpeng Li Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory-failure.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index b0664c23838b8..bba2d7c2c9ce4 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1445,6 +1445,22 @@ int unpoison_memory(unsigned long pfn) return 0; } + if (page_count(page) > 1) { + pr_info("MCE: Someone grabs the hwpoison page %#lx\n", pfn); + return 0; + } + + if (page_mapped(page)) { + pr_info("MCE: Someone maps the hwpoison page %#lx\n", pfn); + return 0; + } + + if (page_mapping(page)) { + pr_info("MCE: the hwpoison page has non-NULL mapping %#lx\n", + pfn); + return 0; + } + /* * unpoison_memory() can encounter thp only when the thp is being * worked by memory_failure() and the page lock is not held yet. -- GitLab From 567d117b8b2ab1c3437acc4799505a59bfa5722b Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 8 Sep 2015 15:03:33 -0700 Subject: [PATCH 6768/7006] mm/memblock.c: rename local variable of memblock_type to 'type' Since commit e3239ff92a17 ("memblock: Rename memblock_region to memblock_type and memblock_property to memblock_region"), all local variables of the membock_type type were renamed to 'type'. This commit renames all remaining local variables with the memblock_type type to the same view. Signed-off-by: Alexander Kuleshov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memblock.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index 509255223688e..69babe22eef79 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -615,14 +615,14 @@ static int __init_memblock memblock_add_region(phys_addr_t base, int nid, unsigned long flags) { - struct memblock_type *_rgn = &memblock.memory; + struct memblock_type *type = &memblock.memory; memblock_dbg("memblock_add: [%#016llx-%#016llx] flags %#02lx %pF\n", (unsigned long long)base, (unsigned long long)base + size - 1, flags, (void *)_RET_IP_); - return memblock_add_range(_rgn, base, size, nid, flags); + return memblock_add_range(type, base, size, nid, flags); } int __init_memblock memblock_add(phys_addr_t base, phys_addr_t size) @@ -835,10 +835,10 @@ void __init_memblock __next_reserved_mem_region(u64 *idx, phys_addr_t *out_start, phys_addr_t *out_end) { - struct memblock_type *rsv = &memblock.reserved; + struct memblock_type *type = &memblock.reserved; - if (*idx >= 0 && *idx < rsv->cnt) { - struct memblock_region *r = &rsv->regions[*idx]; + if (*idx >= 0 && *idx < type->cnt) { + struct memblock_region *r = &type->regions[*idx]; phys_addr_t base = r->base; phys_addr_t size = r->size; -- GitLab From 44a30220bc0a171c010e8df63d144655abdafe61 Mon Sep 17 00:00:00 2001 From: Yu Zhao Date: Tue, 8 Sep 2015 15:03:33 -0700 Subject: [PATCH 6769/7006] shmem: recalculate file inode when fstat Shmem uses shmem_recalc_inode to update i_blocks when it allocates page, undoes range or swaps. But mm can drop clean page without notifying shmem. This makes fstat sometimes return out-of-date block size. The problem can be partially solved when we add inode_operations->getattr which calls shmem_recalc_inode to update i_blocks for fstat. shmem_recalc_inode also updates counter used by statfs and vm_committed_as. For them the situation is not changed. They still suffer from the discrepancy after dropping clean page and before the function is called by aforementioned triggers. Signed-off-by: Yu Zhao Signed-off-by: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/shmem.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/mm/shmem.c b/mm/shmem.c index dbe0c1e8349c7..48ce82926d931 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -542,6 +542,21 @@ void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) } EXPORT_SYMBOL_GPL(shmem_truncate_range); +static int shmem_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + struct shmem_inode_info *info = SHMEM_I(inode); + + spin_lock(&info->lock); + shmem_recalc_inode(inode); + spin_unlock(&info->lock); + + generic_fillattr(inode, stat); + + return 0; +} + static int shmem_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = d_inode(dentry); @@ -3122,6 +3137,7 @@ static const struct file_operations shmem_file_operations = { }; static const struct inode_operations shmem_inode_operations = { + .getattr = shmem_getattr, .setattr = shmem_setattr, #ifdef CONFIG_TMPFS_XATTR .setxattr = shmem_setxattr, -- GitLab From e3975891254e08d220ddcafca93a0e05d9560bfb Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 8 Sep 2015 15:03:38 -0700 Subject: [PATCH 6770/7006] mm/mmap.c: simplify the failure return working flow __split_vma() doesn't need out_err label, neither need initializing err. copy_vma() can return NULL directly when kmem_cache_alloc() fails. Signed-off-by: Chen Gang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 52a2373d0ed42..7a3b12399f063 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2455,7 +2455,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long addr, int new_below) { struct vm_area_struct *new; - int err = -ENOMEM; + int err; if (is_vm_hugetlb_page(vma) && (addr & ~(huge_page_mask(hstate_vma(vma))))) @@ -2463,7 +2463,7 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); if (!new) - goto out_err; + return -ENOMEM; /* most fields are the same, copy all, and then fixup */ *new = *vma; @@ -2511,7 +2511,6 @@ static int __split_vma(struct mm_struct *mm, struct vm_area_struct *vma, mpol_put(vma_policy(new)); out_free_vma: kmem_cache_free(vm_area_cachep, new); - out_err: return err; } @@ -2952,30 +2951,31 @@ struct vm_area_struct *copy_vma(struct vm_area_struct **vmap, *need_rmap_locks = (new_vma->vm_pgoff <= vma->vm_pgoff); } else { new_vma = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); - if (new_vma) { - *new_vma = *vma; - new_vma->vm_start = addr; - new_vma->vm_end = addr + len; - new_vma->vm_pgoff = pgoff; - if (vma_dup_policy(vma, new_vma)) - goto out_free_vma; - INIT_LIST_HEAD(&new_vma->anon_vma_chain); - if (anon_vma_clone(new_vma, vma)) - goto out_free_mempol; - if (new_vma->vm_file) - get_file(new_vma->vm_file); - if (new_vma->vm_ops && new_vma->vm_ops->open) - new_vma->vm_ops->open(new_vma); - vma_link(mm, new_vma, prev, rb_link, rb_parent); - *need_rmap_locks = false; - } + if (!new_vma) + goto out; + *new_vma = *vma; + new_vma->vm_start = addr; + new_vma->vm_end = addr + len; + new_vma->vm_pgoff = pgoff; + if (vma_dup_policy(vma, new_vma)) + goto out_free_vma; + INIT_LIST_HEAD(&new_vma->anon_vma_chain); + if (anon_vma_clone(new_vma, vma)) + goto out_free_mempol; + if (new_vma->vm_file) + get_file(new_vma->vm_file); + if (new_vma->vm_ops && new_vma->vm_ops->open) + new_vma->vm_ops->open(new_vma); + vma_link(mm, new_vma, prev, rb_link, rb_parent); + *need_rmap_locks = false; } return new_vma; - out_free_mempol: +out_free_mempol: mpol_put(vma_policy(new_vma)); - out_free_vma: +out_free_vma: kmem_cache_free(vm_area_cachep, new_vma); +out: return NULL; } -- GitLab From 21cd3a604797c2774676926a95a3d17d4cd5cbb3 Mon Sep 17 00:00:00 2001 From: Wang Kai Date: Tue, 8 Sep 2015 15:03:41 -0700 Subject: [PATCH 6771/7006] kmemleak: record accurate early log buffer count and report when exceeded In log_early function, crt_early_log should also count once when 'crt_early_log >= ARRAY_SIZE(early_log)'. Otherwise the reported count from kmemleak_init is one less than 'actual number'. Then, in kmemleak_init, if early_log buffer size equal actual number, kmemleak will init sucessful, so change warning condition to 'crt_early_log > ARRAY_SIZE(early_log)'. Signed-off-by: Wang Kai Acked-by: Catalin Marinas Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/kmemleak.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index cf79f110157c9..f532f6a37b553 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -838,6 +838,7 @@ static void __init log_early(int op_type, const void *ptr, size_t size, } if (crt_early_log >= ARRAY_SIZE(early_log)) { + crt_early_log++; kmemleak_disable(); return; } @@ -1882,7 +1883,7 @@ void __init kmemleak_init(void) object_cache = KMEM_CACHE(kmemleak_object, SLAB_NOLEAKTRACE); scan_area_cache = KMEM_CACHE(kmemleak_scan_area, SLAB_NOLEAKTRACE); - if (crt_early_log >= ARRAY_SIZE(early_log)) + if (crt_early_log > ARRAY_SIZE(early_log)) pr_warning("Early log buffer exceeded (%d), please increase " "DEBUG_KMEMLEAK_EARLY_LOG_SIZE\n", crt_early_log); -- GitLab From 26f5d7609f03ad8d6dc552458e4e371a62416b37 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 8 Sep 2015 15:03:44 -0700 Subject: [PATCH 6772/7006] list_lru: don't call list_lru_from_kmem if the list_head is empty If the list_head is empty then we'll have called list_lru_from_kmem for nothing. Move that call inside of the list_empty if block. Signed-off-by: Jeff Layton Reviewed-by: Vladimir Davydov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/list_lru.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/list_lru.c b/mm/list_lru.c index 909eca2c820e4..e1da19fac1b36 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -99,8 +99,8 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item) struct list_lru_one *l; spin_lock(&nlru->lock); - l = list_lru_from_kmem(nlru, item); if (list_empty(item)) { + l = list_lru_from_kmem(nlru, item); list_add_tail(item, &l->list); l->nr_items++; spin_unlock(&nlru->lock); @@ -118,8 +118,8 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item) struct list_lru_one *l; spin_lock(&nlru->lock); - l = list_lru_from_kmem(nlru, item); if (!list_empty(item)) { + l = list_lru_from_kmem(nlru, item); list_del_init(item); l->nr_items--; spin_unlock(&nlru->lock); -- GitLab From 7fadc820222497eac234d1d51a66517c00a6ca4c Mon Sep 17 00:00:00 2001 From: Hugh Dickins Date: Tue, 8 Sep 2015 15:03:46 -0700 Subject: [PATCH 6773/7006] mm, vmscan: unlock page while waiting on writeback This is merely a politeness: I've not found that shrink_page_list() leads to deadlock with the page it holds locked across wait_on_page_writeback(); but nevertheless, why hold others off by keeping the page locked there? And while we're at it: remove the mistaken "not " from the commentary on this Case 3 (and a distracting blank line from Case 2, if I may). Signed-off-by: Hugh Dickins Acked-by: Michal Hocko Acked-by: Johannes Weiner Cc: Mel Gorman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/vmscan.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mm/vmscan.c b/mm/vmscan.c index 8276a3a615ca0..2d978b28a410b 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -985,7 +985,7 @@ static unsigned long shrink_page_list(struct list_head *page_list, * __GFP_IO|__GFP_FS for this reason); but more thought * would probably show more reasons. * - * 3) Legacy memcg encounters a page that is not already marked + * 3) Legacy memcg encounters a page that is already marked * PageReclaim. memcg does not have any dirty pages * throttling so we could easily OOM just because too many * pages are in writeback and there is nothing else to @@ -1015,12 +1015,15 @@ static unsigned long shrink_page_list(struct list_head *page_list, */ SetPageReclaim(page); nr_writeback++; - goto keep_locked; /* Case 3 above */ } else { + unlock_page(page); wait_on_page_writeback(page); + /* then go back and try same page again */ + list_add_tail(&page->lru, page_list); + continue; } } -- GitLab From 96db800f5d73cd5c49461253d45766e094f0f8c2 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:03:50 -0700 Subject: [PATCH 6774/7006] mm: rename alloc_pages_exact_node() to __alloc_pages_node() alloc_pages_exact_node() was introduced in commit 6484eb3e2a81 ("page allocator: do not check NUMA node ID when the caller knows the node is valid") as an optimized variant of alloc_pages_node(), that doesn't fallback to current node for nid == NUMA_NO_NODE. Unfortunately the name of the function can easily suggest that the allocation is restricted to the given node and fails otherwise. In truth, the node is only preferred, unless __GFP_THISNODE is passed among the gfp flags. The misleading name has lead to mistakes in the past, see for example commits 5265047ac301 ("mm, thp: really limit transparent hugepage allocation to local node") and b360edb43f8e ("mm, mempolicy: migrate_to_node should only migrate to node"). Another issue with the name is that there's a family of alloc_pages_exact*() functions where 'exact' means exact size (instead of page order), which leads to more confusion. To prevent further mistakes, this patch effectively renames alloc_pages_exact_node() to __alloc_pages_node() to better convey that it's an optimized variant of alloc_pages_node() not intended for general usage. Both functions get described in comments. It has been also considered to really provide a convenience function for allocations restricted to a node, but the major opinion seems to be that __GFP_THISNODE already provides that functionality and we shouldn't duplicate the API needlessly. The number of users would be small anyway. Existing callers of alloc_pages_exact_node() are simply converted to call __alloc_pages_node(), with the exception of sba_alloc_coherent() which open-codes the check for NUMA_NO_NODE, so it is converted to use alloc_pages_node() instead. This means it no longer performs some VM_BUG_ON checks, and since the current check for nid in alloc_pages_node() uses a 'nid < 0' comparison (which includes NUMA_NO_NODE), it may hide wrong values which would be previously exposed. Both differences will be rectified by the next patch. To sum up, this patch makes no functional changes, except temporarily hiding potentially buggy callers. Restricting the checks in alloc_pages_node() is left for the next patch which can in turn expose more existing buggy callers. Signed-off-by: Vlastimil Babka Acked-by: Johannes Weiner Acked-by: Robin Holt Acked-by: Michal Hocko Acked-by: Christoph Lameter Acked-by: Michael Ellerman Cc: Mel Gorman Cc: David Rientjes Cc: Greg Thelen Cc: Aneesh Kumar K.V Cc: Pekka Enberg Cc: Joonsoo Kim Cc: Naoya Horiguchi Cc: Tony Luck Cc: Fenghua Yu Cc: Arnd Bergmann Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Gleb Natapov Cc: Paolo Bonzini Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Cliff Whickman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/ia64/hp/common/sba_iommu.c | 6 +----- arch/ia64/kernel/uncached.c | 2 +- arch/ia64/sn/pci/pci_dma.c | 2 +- arch/powerpc/platforms/cell/ras.c | 2 +- arch/x86/kvm/vmx.c | 2 +- drivers/misc/sgi-xp/xpc_uv.c | 2 +- include/linux/gfp.h | 23 +++++++++++++++-------- kernel/profile.c | 8 ++++---- mm/filemap.c | 2 +- mm/huge_memory.c | 2 +- mm/hugetlb.c | 4 ++-- mm/memory-failure.c | 2 +- mm/mempolicy.c | 4 ++-- mm/migrate.c | 4 ++-- mm/page_alloc.c | 2 -- mm/slab.c | 2 +- mm/slob.c | 4 ++-- mm/slub.c | 2 +- 18 files changed, 38 insertions(+), 37 deletions(-) diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c index 344387a554066..a6d6190c9d24c 100644 --- a/arch/ia64/hp/common/sba_iommu.c +++ b/arch/ia64/hp/common/sba_iommu.c @@ -1140,13 +1140,9 @@ sba_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, #ifdef CONFIG_NUMA { - int node = ioc->node; struct page *page; - if (node == NUMA_NO_NODE) - node = numa_node_id(); - - page = alloc_pages_exact_node(node, flags, get_order(size)); + page = alloc_pages_node(ioc->node, flags, get_order(size)); if (unlikely(!page)) return NULL; diff --git a/arch/ia64/kernel/uncached.c b/arch/ia64/kernel/uncached.c index 20e8a9b21d751..f3976da36721a 100644 --- a/arch/ia64/kernel/uncached.c +++ b/arch/ia64/kernel/uncached.c @@ -97,7 +97,7 @@ static int uncached_add_chunk(struct uncached_pool *uc_pool, int nid) /* attempt to allocate a granule's worth of cached memory pages */ - page = alloc_pages_exact_node(nid, + page = __alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE, IA64_GRANULE_SHIFT-PAGE_SHIFT); if (!page) { diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c index d0853e8e8623e..8f59907007cbe 100644 --- a/arch/ia64/sn/pci/pci_dma.c +++ b/arch/ia64/sn/pci/pci_dma.c @@ -92,7 +92,7 @@ static void *sn_dma_alloc_coherent(struct device *dev, size_t size, */ node = pcibus_to_node(pdev->bus); if (likely(node >=0)) { - struct page *p = alloc_pages_exact_node(node, + struct page *p = __alloc_pages_node(node, flags, get_order(size)); if (likely(p)) diff --git a/arch/powerpc/platforms/cell/ras.c b/arch/powerpc/platforms/cell/ras.c index e865d748179b2..2d4f60c0119aa 100644 --- a/arch/powerpc/platforms/cell/ras.c +++ b/arch/powerpc/platforms/cell/ras.c @@ -123,7 +123,7 @@ static int __init cbe_ptcal_enable_on_node(int nid, int order) area->nid = nid; area->order = order; - area->pages = alloc_pages_exact_node(area->nid, + area->pages = __alloc_pages_node(area->nid, GFP_KERNEL|__GFP_THISNODE, area->order); diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 4a4eec30cc08c..148ea20160222 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -3150,7 +3150,7 @@ static struct vmcs *alloc_vmcs_cpu(int cpu) struct page *pages; struct vmcs *vmcs; - pages = alloc_pages_exact_node(node, GFP_KERNEL, vmcs_config.order); + pages = __alloc_pages_node(node, GFP_KERNEL, vmcs_config.order); if (!pages) return NULL; vmcs = page_address(pages); diff --git a/drivers/misc/sgi-xp/xpc_uv.c b/drivers/misc/sgi-xp/xpc_uv.c index 95c894482fddf..340b44d9e8cf7 100644 --- a/drivers/misc/sgi-xp/xpc_uv.c +++ b/drivers/misc/sgi-xp/xpc_uv.c @@ -239,7 +239,7 @@ xpc_create_gru_mq_uv(unsigned int mq_size, int cpu, char *irq_name, mq->mmr_blade = uv_cpu_to_blade_id(cpu); nid = cpu_to_node(cpu); - page = alloc_pages_exact_node(nid, + page = __alloc_pages_node(nid, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE, pg_order); if (page == NULL) { diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 3bd64b115999f..d2c142bc872e5 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -303,20 +303,28 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order, return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL); } -static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, - unsigned int order) +/* + * Allocate pages, preferring the node given as nid. The node must be valid and + * online. For more general interface, see alloc_pages_node(). + */ +static inline struct page * +__alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) { - /* Unknown node is current node */ - if (nid < 0) - nid = numa_node_id(); + VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES || !node_online(nid)); return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask)); } -static inline struct page *alloc_pages_exact_node(int nid, gfp_t gfp_mask, +/* + * Allocate pages, preferring the node given as nid. When nid == NUMA_NO_NODE, + * prefer the current CPU's node. + */ +static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) { - VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES || !node_online(nid)); + /* Unknown node is current node */ + if (nid < 0) + nid = numa_node_id(); return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask)); } @@ -357,7 +365,6 @@ extern unsigned long get_zeroed_page(gfp_t gfp_mask); void *alloc_pages_exact(size_t size, gfp_t gfp_mask); void free_pages_exact(void *virt, size_t size); -/* This is different from alloc_pages_exact_node !!! */ void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask); #define __get_free_page(gfp_mask) \ diff --git a/kernel/profile.c b/kernel/profile.c index a7bcd28d6e9f5..99513e1160e51 100644 --- a/kernel/profile.c +++ b/kernel/profile.c @@ -339,7 +339,7 @@ static int profile_cpu_callback(struct notifier_block *info, node = cpu_to_mem(cpu); per_cpu(cpu_profile_flip, cpu) = 0; if (!per_cpu(cpu_profile_hits, cpu)[1]) { - page = alloc_pages_exact_node(node, + page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); if (!page) @@ -347,7 +347,7 @@ static int profile_cpu_callback(struct notifier_block *info, per_cpu(cpu_profile_hits, cpu)[1] = page_address(page); } if (!per_cpu(cpu_profile_hits, cpu)[0]) { - page = alloc_pages_exact_node(node, + page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0); if (!page) @@ -543,14 +543,14 @@ static int create_hash_tables(void) int node = cpu_to_mem(cpu); struct page *page; - page = alloc_pages_exact_node(node, + page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE, 0); if (!page) goto out_cleanup; per_cpu(cpu_profile_hits, cpu)[1] = (struct profile_hit *)page_address(page); - page = alloc_pages_exact_node(node, + page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE, 0); if (!page) diff --git a/mm/filemap.c b/mm/filemap.c index 30d69c0c5a386..72940fb386668 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -674,7 +674,7 @@ struct page *__page_cache_alloc(gfp_t gfp) do { cpuset_mems_cookie = read_mems_allowed_begin(); n = cpuset_mem_spread_node(); - page = alloc_pages_exact_node(n, gfp, 0); + page = __alloc_pages_node(n, gfp, 0); } while (!page && read_mems_allowed_retry(cpuset_mems_cookie)); return page; diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 71a4822c832b9..883f613ada7e2 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2414,7 +2414,7 @@ khugepaged_alloc_page(struct page **hpage, gfp_t gfp, struct mm_struct *mm, */ up_read(&mm->mmap_sem); - *hpage = alloc_pages_exact_node(node, gfp, HPAGE_PMD_ORDER); + *hpage = __alloc_pages_node(node, gfp, HPAGE_PMD_ORDER); if (unlikely(!*hpage)) { count_vm_event(THP_COLLAPSE_ALLOC_FAILED); *hpage = ERR_PTR(-ENOMEM); diff --git a/mm/hugetlb.c b/mm/hugetlb.c index cd1280c487ff9..999fb0aef8f16 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -1331,7 +1331,7 @@ static struct page *alloc_fresh_huge_page_node(struct hstate *h, int nid) { struct page *page; - page = alloc_pages_exact_node(nid, + page = __alloc_pages_node(nid, htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); @@ -1483,7 +1483,7 @@ static struct page *alloc_buddy_huge_page(struct hstate *h, int nid) __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); else - page = alloc_pages_exact_node(nid, + page = __alloc_pages_node(nid, htlb_alloc_mask(h)|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN, huge_page_order(h)); diff --git a/mm/memory-failure.c b/mm/memory-failure.c index bba2d7c2c9ce4..eeda6485e76c2 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -1521,7 +1521,7 @@ static struct page *new_page(struct page *p, unsigned long private, int **x) return alloc_huge_page_node(page_hstate(compound_head(p)), nid); else - return alloc_pages_exact_node(nid, GFP_HIGHUSER_MOVABLE, 0); + return __alloc_pages_node(nid, GFP_HIGHUSER_MOVABLE, 0); } /* diff --git a/mm/mempolicy.c b/mm/mempolicy.c index d6f2caee28c04..87a177917cb2e 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -942,7 +942,7 @@ static struct page *new_node_page(struct page *page, unsigned long node, int **x return alloc_huge_page_node(page_hstate(compound_head(page)), node); else - return alloc_pages_exact_node(node, GFP_HIGHUSER_MOVABLE | + return __alloc_pages_node(node, GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0); } @@ -1998,7 +1998,7 @@ retry_cpuset: nmask = policy_nodemask(gfp, pol); if (!nmask || node_isset(hpage_node, *nmask)) { mpol_cond_put(pol); - page = alloc_pages_exact_node(hpage_node, + page = __alloc_pages_node(hpage_node, gfp | __GFP_THISNODE, order); goto out; } diff --git a/mm/migrate.c b/mm/migrate.c index 918defbdda0e5..02ce25df16c26 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -1195,7 +1195,7 @@ static struct page *new_page_node(struct page *p, unsigned long private, return alloc_huge_page_node(page_hstate(compound_head(p)), pm->node); else - return alloc_pages_exact_node(pm->node, + return __alloc_pages_node(pm->node, GFP_HIGHUSER_MOVABLE | __GFP_THISNODE, 0); } @@ -1555,7 +1555,7 @@ static struct page *alloc_misplaced_dst_page(struct page *page, int nid = (int) data; struct page *newpage; - newpage = alloc_pages_exact_node(nid, + newpage = __alloc_pages_node(nid, (GFP_HIGHUSER_MOVABLE | __GFP_THISNODE | __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN) & diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 252665d553b48..bdaa0cf8fd412 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -3511,8 +3511,6 @@ EXPORT_SYMBOL(alloc_pages_exact); * * Like alloc_pages_exact(), but try to allocate on node nid first before falling * back. - * Note this is not alloc_pages_exact_node() which allocates on a specific node, - * but is not exact. */ void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) { diff --git a/mm/slab.c b/mm/slab.c index 60c936938b848..c77ebe6cc87cd 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1595,7 +1595,7 @@ static struct page *kmem_getpages(struct kmem_cache *cachep, gfp_t flags, if (memcg_charge_slab(cachep, flags, cachep->gfporder)) return NULL; - page = alloc_pages_exact_node(nodeid, flags | __GFP_NOTRACK, cachep->gfporder); + page = __alloc_pages_node(nodeid, flags | __GFP_NOTRACK, cachep->gfporder); if (!page) { memcg_uncharge_slab(cachep, cachep->gfporder); slab_out_of_memory(cachep, flags, nodeid); diff --git a/mm/slob.c b/mm/slob.c index 165bbd3cd6062..0d7e5df74d1f0 100644 --- a/mm/slob.c +++ b/mm/slob.c @@ -45,7 +45,7 @@ * NUMA support in SLOB is fairly simplistic, pushing most of the real * logic down to the page allocator, and simply doing the node accounting * on the upper levels. In the event that a node id is explicitly - * provided, alloc_pages_exact_node() with the specified node id is used + * provided, __alloc_pages_node() with the specified node id is used * instead. The common case (or when the node id isn't explicitly provided) * will default to the current node, as per numa_node_id(). * @@ -193,7 +193,7 @@ static void *slob_new_pages(gfp_t gfp, int order, int node) #ifdef CONFIG_NUMA if (node != NUMA_NO_NODE) - page = alloc_pages_exact_node(node, gfp, order); + page = __alloc_pages_node(node, gfp, order); else #endif page = alloc_pages(gfp, order); diff --git a/mm/slub.c b/mm/slub.c index 084184e706c63..f614b5dc396bc 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1334,7 +1334,7 @@ static inline struct page *alloc_slab_page(struct kmem_cache *s, if (node == NUMA_NO_NODE) page = alloc_pages(flags, order); else - page = alloc_pages_exact_node(node, flags, order); + page = __alloc_pages_node(node, flags, order); if (!page) memcg_uncharge_slab(s, order); -- GitLab From 0bc35a970c01c50e3bcc4b5a612787346024e5db Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:03:53 -0700 Subject: [PATCH 6775/7006] mm: unify checks in alloc_pages_node() and __alloc_pages_node() Perform the same debug checks in alloc_pages_node() as are done in __alloc_pages_node(), by making the former function a wrapper of the latter one. In addition to better diagnostics in DEBUG_VM builds for situations which have been already fatal (e.g. out-of-bounds node id), there are two visible changes for potential existing buggy callers of alloc_pages_node(): - calling alloc_pages_node() with any negative nid (e.g. due to arithmetic overflow) was treated as passing NUMA_NO_NODE and fallback to local node was applied. This will now be fatal. - calling alloc_pages_node() with an offline node will now be checked for DEBUG_VM builds. Since it's not fatal if the node has been previously online, and this patch may expose some existing buggy callers, change the VM_BUG_ON in __alloc_pages_node() to VM_WARN_ON. Signed-off-by: Vlastimil Babka Acked-by: David Rientjes Acked-by: Johannes Weiner Acked-by: Christoph Lameter Acked-by: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index d2c142bc872e5..4a12cae2fb0c7 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -310,23 +310,23 @@ __alloc_pages(gfp_t gfp_mask, unsigned int order, static inline struct page * __alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) { - VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES || !node_online(nid)); + VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES); + VM_WARN_ON(!node_online(nid)); return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask)); } /* * Allocate pages, preferring the node given as nid. When nid == NUMA_NO_NODE, - * prefer the current CPU's node. + * prefer the current CPU's node. Otherwise node must be valid and online. */ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) { - /* Unknown node is current node */ - if (nid < 0) + if (nid == NUMA_NO_NODE) nid = numa_node_id(); - return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask)); + return __alloc_pages_node(nid, gfp_mask, order); } #ifdef CONFIG_NUMA -- GitLab From 82c1fc714763b823169958a98196d9be56c63b30 Mon Sep 17 00:00:00 2001 From: Vlastimil Babka Date: Tue, 8 Sep 2015 15:03:56 -0700 Subject: [PATCH 6776/7006] mm: use numa_mem_id() in alloc_pages_node() alloc_pages_node() might fail when called with NUMA_NO_NODE and __GFP_THISNODE on a CPU belonging to a memoryless node. To make the local-node fallback more robust and prevent such situations, use numa_mem_id(), which was introduced for similar scenarios in the slab context. Suggested-by: Christoph Lameter Signed-off-by: Vlastimil Babka Acked-by: David Rientjes Acked-by: Mel Gorman Acked-by: Christoph Lameter Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/gfp.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/gfp.h b/include/linux/gfp.h index 4a12cae2fb0c7..f92cbd2f44507 100644 --- a/include/linux/gfp.h +++ b/include/linux/gfp.h @@ -318,13 +318,14 @@ __alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) /* * Allocate pages, preferring the node given as nid. When nid == NUMA_NO_NODE, - * prefer the current CPU's node. Otherwise node must be valid and online. + * prefer the current CPU's closest node. Otherwise node must be valid and + * online. */ static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) { if (nid == NUMA_NO_NODE) - nid = numa_node_id(); + nid = numa_mem_id(); return __alloc_pages_node(nid, gfp_mask, order); } -- GitLab From 1a16718cf7f4f48ee2aa2cfd9a961c6b433a7b5b Mon Sep 17 00:00:00 2001 From: Joonsoo Kim Date: Tue, 8 Sep 2015 15:03:59 -0700 Subject: [PATCH 6777/7006] mm/compaction: correct to flush migrated pages if pageblock skip happens We cache isolate_start_pfn before entering isolate_migratepages(). If pageblock is skipped in isolate_migratepages() due to whatever reason, cc->migrate_pfn can be far from isolate_start_pfn hence we flush pages that were freed. For example, the following scenario can be possible: - assume order-9 compaction, pageblock order is 9 - start_isolate_pfn is 0x200 - isolate_migratepages() - skip a number of pageblocks - start to isolate from pfn 0x600 - cc->migrate_pfn = 0x620 - return - last_migrated_pfn is set to 0x200 - check flushing condition - current_block_start is set to 0x600 - last_migrated_pfn < current_block_start then do useless flush This wrong flush would not help the performance and success rate so this patch tries to fix it. One simple way to know the exact position where we start to isolate migratable pages is that we cache it in isolate_migratepages() before entering actual isolation. This patch implements that and fixes the problem. Signed-off-by: Joonsoo Kim Acked-by: Vlastimil Babka Cc: Mel Gorman Cc: Rik van Riel Cc: David Rientjes Cc: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/compaction.c | 30 +++++++++++++++--------------- mm/internal.h | 1 + 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/mm/compaction.c b/mm/compaction.c index 8f64d35339900..c5c627aae9962 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -1115,6 +1115,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, struct compact_control *cc) { unsigned long low_pfn, end_pfn; + unsigned long isolate_start_pfn; struct page *page; const isolate_mode_t isolate_mode = (sysctl_compact_unevictable_allowed ? ISOLATE_UNEVICTABLE : 0) | @@ -1163,6 +1164,7 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, continue; /* Perform the isolation */ + isolate_start_pfn = low_pfn; low_pfn = isolate_migratepages_block(cc, low_pfn, end_pfn, isolate_mode); @@ -1171,6 +1173,15 @@ static isolate_migrate_t isolate_migratepages(struct zone *zone, return ISOLATE_ABORT; } + /* + * Record where we could have freed pages by migration and not + * yet flushed them to buddy allocator. + * - this is the lowest page that could have been isolated and + * then freed by migration. + */ + if (cc->nr_migratepages && !cc->last_migrated_pfn) + cc->last_migrated_pfn = isolate_start_pfn; + /* * Either we isolated something and proceed with migration. Or * we failed and compact_zone should decide if we should @@ -1342,7 +1353,6 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) unsigned long end_pfn = zone_end_pfn(zone); const int migratetype = gfpflags_to_migratetype(cc->gfp_mask); const bool sync = cc->mode != MIGRATE_ASYNC; - unsigned long last_migrated_pfn = 0; ret = compaction_suitable(zone, cc->order, cc->alloc_flags, cc->classzone_idx); @@ -1380,6 +1390,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn; zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn; } + cc->last_migrated_pfn = 0; trace_mm_compaction_begin(start_pfn, cc->migrate_pfn, cc->free_pfn, end_pfn, sync); @@ -1389,7 +1400,6 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) while ((ret = compact_finished(zone, cc, migratetype)) == COMPACT_CONTINUE) { int err; - unsigned long isolate_start_pfn = cc->migrate_pfn; switch (isolate_migratepages(zone, cc)) { case ISOLATE_ABORT: @@ -1429,16 +1439,6 @@ static int compact_zone(struct zone *zone, struct compact_control *cc) } } - /* - * Record where we could have freed pages by migration and not - * yet flushed them to buddy allocator. We use the pfn that - * isolate_migratepages() started from in this loop iteration - * - this is the lowest page that could have been isolated and - * then freed by migration. - */ - if (!last_migrated_pfn) - last_migrated_pfn = isolate_start_pfn; - check_drain: /* * Has the migration scanner moved away from the previous @@ -1447,18 +1447,18 @@ check_drain: * compact_finished() can detect immediately if allocation * would succeed. */ - if (cc->order > 0 && last_migrated_pfn) { + if (cc->order > 0 && cc->last_migrated_pfn) { int cpu; unsigned long current_block_start = cc->migrate_pfn & ~((1UL << cc->order) - 1); - if (last_migrated_pfn < current_block_start) { + if (cc->last_migrated_pfn < current_block_start) { cpu = get_cpu(); lru_add_drain_cpu(cpu); drain_local_pages(zone); put_cpu(); /* No more flushing until we migrate again */ - last_migrated_pfn = 0; + cc->last_migrated_pfn = 0; } } diff --git a/mm/internal.h b/mm/internal.h index 1195dd2d6a2b9..bc0fa9a69e463 100644 --- a/mm/internal.h +++ b/mm/internal.h @@ -182,6 +182,7 @@ struct compact_control { unsigned long nr_migratepages; /* Number of pages to migrate */ unsigned long free_pfn; /* isolate_freepages search base */ unsigned long migrate_pfn; /* isolate_migratepages search base */ + unsigned long last_migrated_pfn;/* Not yet flushed page being freed */ enum migrate_mode mode; /* Async or sync migration mode */ bool ignore_skip_hint; /* Scan blocks even if marked skip */ int order; /* order a direct compactor needs */ -- GitLab From c11539315129b599aae6d9bc0f941dee5559ec58 Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 8 Sep 2015 15:04:02 -0700 Subject: [PATCH 6778/7006] mm/memblock.c: fiy typos in comments s/succees/success/ Signed-off-by: Alexander Kuleshov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memblock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mm/memblock.c b/mm/memblock.c index 69babe22eef79..31b06c67b1b16 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -762,7 +762,7 @@ int __init_memblock memblock_reserve(phys_addr_t base, phys_addr_t size) * * This function isolates region [@base, @base + @size), and sets/clears flag * - * Return 0 on succees, -errno on failure. + * Return 0 on success, -errno on failure. */ static int __init_memblock memblock_setclr_flag(phys_addr_t base, phys_addr_t size, int set, int flag) @@ -789,7 +789,7 @@ static int __init_memblock memblock_setclr_flag(phys_addr_t base, * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on succees, -errno on failure. + * Return 0 on success, -errno on failure. */ int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size) { @@ -801,7 +801,7 @@ int __init_memblock memblock_mark_hotplug(phys_addr_t base, phys_addr_t size) * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on succees, -errno on failure. + * Return 0 on success, -errno on failure. */ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) { @@ -813,7 +813,7 @@ int __init_memblock memblock_clear_hotplug(phys_addr_t base, phys_addr_t size) * @base: the base phys addr of the region * @size: the size of the region * - * Return 0 on succees, -errno on failure. + * Return 0 on success, -errno on failure. */ int __init_memblock memblock_mark_mirror(phys_addr_t base, phys_addr_t size) { -- GitLab From bde43c6c9f4f360ae549a0ed9f10a3e62e363aca Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Tue, 8 Sep 2015 15:04:05 -0700 Subject: [PATCH 6779/7006] mm/khugepaged: allow interruption of allocation sleep again Commit 1dfb059b9438 ("thp: reduce khugepaged freezing latency") fixed khugepaged to do not block a system suspend. But the result is that it could not get interrupted before the given timeout because the condition for the wait event is "false". This patch puts back the original approach but it uses freezable_schedule_timeout_interruptible() instead of schedule_timeout_interruptible(). It does the right thing. I am pretty sure that the freezable variant was not used in the original fix only because it was not available at that time. The regression has been there for ages. It was not critical. It just did the allocation throttling a little bit more aggressively. I found this problem when converting the kthread to kthread worker API and trying to understand the code. This bug is thought to have minimal userspace-visible impact. Somebody could set a high alloc_sleep value by mistake, and then try to fix it back, but khugepaged would keep sleeping until the high value expires. Signed-off-by: Petr Mladek Cc: Andrea Arcangeli Acked-by: Vlastimil Babka Cc: "Aneesh Kumar K.V" Cc: "Kirill A. Shutemov" Cc: David Rientjes Cc: Ebru Akagunduz Cc: Mel Gorman Cc: Jiri Kosina Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/huge_memory.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mm/huge_memory.c b/mm/huge_memory.c index 883f613ada7e2..b16279cbd91df 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -2326,8 +2326,12 @@ static void __collapse_huge_page_copy(pte_t *pte, struct page *page, static void khugepaged_alloc_sleep(void) { - wait_event_freezable_timeout(khugepaged_wait, false, - msecs_to_jiffies(khugepaged_alloc_sleep_millisecs)); + DEFINE_WAIT(wait); + + add_wait_queue(&khugepaged_wait, &wait); + freezable_schedule_timeout_interruptible( + msecs_to_jiffies(khugepaged_alloc_sleep_millisecs)); + remove_wait_queue(&khugepaged_wait, &wait); } static int khugepaged_node_load[MAX_NUMNODES]; -- GitLab From c9d13f5fc748a02cb5917a798f065681007342b9 Mon Sep 17 00:00:00 2001 From: Chen Gang Date: Tue, 8 Sep 2015 15:04:08 -0700 Subject: [PATCH 6780/7006] mm/mmap.c:insert_vm_struct(): check for failure before setting values There's no point in initializing vma->vm_pgoff if the insertion attempt will be failing anyway. Run the checks before performing the initialization. Signed-off-by: Chen Gang Cc: Michal Hocko Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/mm/mmap.c b/mm/mmap.c index 7a3b12399f063..b6be3249f0a92 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -2871,6 +2871,13 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma) struct vm_area_struct *prev; struct rb_node **rb_link, *rb_parent; + if (find_vma_links(mm, vma->vm_start, vma->vm_end, + &prev, &rb_link, &rb_parent)) + return -ENOMEM; + if ((vma->vm_flags & VM_ACCOUNT) && + security_vm_enough_memory_mm(mm, vma_pages(vma))) + return -ENOMEM; + /* * The vm_pgoff of a purely anonymous vma should be irrelevant * until its first write fault, when page's anon_vma and index @@ -2887,12 +2894,6 @@ int insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vma) BUG_ON(vma->anon_vma); vma->vm_pgoff = vma->vm_start >> PAGE_SHIFT; } - if (find_vma_links(mm, vma->vm_start, vma->vm_end, - &prev, &rb_link, &rb_parent)) - return -ENOMEM; - if ((vma->vm_flags & VM_ACCOUNT) && - security_vm_enough_memory_mm(mm, vma_pages(vma))) - return -ENOMEM; vma_link(mm, vma, prev, rb_link, rb_parent); return 0; -- GitLab From 013110a73dcf970cb28c5b0a79f9eee577ea6aa2 Mon Sep 17 00:00:00 2001 From: Yaowei Bai Date: Tue, 8 Sep 2015 15:04:10 -0700 Subject: [PATCH 6781/7006] mm/page_alloc.c: fix a misleading comment The comment says that the per-cpu batchsize and zone watermarks are determined by present_pages which is definitely wrong, they are both calculated from managed_pages. Fix it. Signed-off-by: Yaowei Bai Acked-by: Michal Hocko Cc: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/sysctl/vm.txt | 4 ++-- mm/page_alloc.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt index 9c3f2f8054b5f..a4482fceacecc 100644 --- a/Documentation/sysctl/vm.txt +++ b/Documentation/sysctl/vm.txt @@ -349,7 +349,7 @@ zone[i]'s protection[j] is calculated by following expression. (i < j): zone[i]->protection[j] - = (total sums of present_pages from zone[i+1] to zone[j] on the node) + = (total sums of managed_pages from zone[i+1] to zone[j] on the node) / lowmem_reserve_ratio[i]; (i = j): (should not be protected. = 0; @@ -360,7 +360,7 @@ The default values of lowmem_reserve_ratio[i] are 256 (if zone[i] means DMA or DMA32 zone) 32 (others). As above expression, they are reciprocal number of ratio. -256 means 1/256. # of protection pages becomes about "0.39%" of total present +256 means 1/256. # of protection pages becomes about "0.39%" of total managed pages of higher zones on the node. If you would like to protect more pages, smaller values are effective. diff --git a/mm/page_alloc.c b/mm/page_alloc.c index bdaa0cf8fd412..59abb47b70ee4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6022,7 +6022,7 @@ void __init mem_init_print_info(const char *str) * set_dma_reserve - set the specified number of pages reserved in the first zone * @new_dma_reserve: The number of pages to mark reserved * - * The per-cpu batchsize and zone watermarks are determined by present_pages. + * The per-cpu batchsize and zone watermarks are determined by managed_pages. * In the DMA zone, a significant percentage may be consumed by kernel image * and other unfreeable allocations which can skew the watermarks badly. This * function may optionally be used to account for unfreeable pages in the -- GitLab From 34b100605cb7e201d5c4e39f54d0e11caa950733 Mon Sep 17 00:00:00 2001 From: Yaowei Bai Date: Tue, 8 Sep 2015 15:04:13 -0700 Subject: [PATCH 6782/7006] mm/page_alloc.c: change sysctl_lower_zone_reserve_ratio to sysctl_lowmem_reserve_ratio in comments We use sysctl_lowmem_reserve_ratio rather than sysctl_lower_zone_reserve_ratio to determine how aggressive the kernel is in defending lowmem from the possibility of being captured into pinned user memory. To avoid misleading, correct it in some comments. Signed-off-by: Yaowei Bai Acked-by: Michal Hocko Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 59abb47b70ee4..5e8e99dd595a5 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -6075,7 +6075,7 @@ void __init page_alloc_init(void) } /* - * calculate_totalreserve_pages - called when sysctl_lower_zone_reserve_ratio + * calculate_totalreserve_pages - called when sysctl_lowmem_reserve_ratio * or min_free_kbytes changes. */ static void calculate_totalreserve_pages(void) @@ -6119,7 +6119,7 @@ static void calculate_totalreserve_pages(void) /* * setup_per_zone_lowmem_reserve - called whenever - * sysctl_lower_zone_reserve_ratio changes. Ensures that each zone + * sysctl_lowmem_reserve_ratio changes. Ensures that each zone * has a correct pages reserved value, so an adequate number of * pages are left in the zone after a successful __alloc_pages(). */ -- GitLab From b5685e9263a6f3a8da546b8a46382f18a63745c9 Mon Sep 17 00:00:00 2001 From: Xishi Qiu Date: Tue, 8 Sep 2015 15:04:16 -0700 Subject: [PATCH 6783/7006] memory-hotplug: fix comments in zone_spanned_pages_in_node() and zone_spanned_pages_in_node() When hot adding a node from add_memory(), we will add memblock first, so the node is not empty. But when called from cpu_up(), the node should be empty. Signed-off-by: Xishi Qiu Cc: Tang Chen Cc: Yasuaki Ishimatsu Cc: Naoya Horiguchi Cc: Vlastimil Babka Cc: Taku Izumi \ Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 5e8e99dd595a5..b0fda2b9ca76b 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5085,7 +5085,7 @@ static unsigned long __meminit zone_spanned_pages_in_node(int nid, { unsigned long zone_start_pfn, zone_end_pfn; - /* When hotadd a new node, the node should be empty */ + /* When hotadd a new node from cpu_up(), the node should be empty */ if (!node_start_pfn && !node_end_pfn) return 0; @@ -5152,7 +5152,7 @@ static unsigned long __meminit zone_absent_pages_in_node(int nid, unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type]; unsigned long zone_start_pfn, zone_end_pfn; - /* When hotadd a new node, the node should be empty */ + /* When hotadd a new node from cpu_up(), the node should be empty */ if (!node_start_pfn && !node_end_pfn) return 0; -- GitLab From 4ada0c5a2daf11816180ec30bdbdbed1f6ff3224 Mon Sep 17 00:00:00 2001 From: Zhen Lei Date: Tue, 8 Sep 2015 15:04:19 -0700 Subject: [PATCH 6784/7006] mm/page_alloc.c: fix type information of memoryless node For a memoryless node, the output of get_pfn_range_for_nid are all zero. It will display mem from 0 to -1. Signed-off-by: Zhen Lei Acked-by: David Rientjes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/page_alloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index b0fda2b9ca76b..4a4c399bacebe 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5476,7 +5476,8 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size, #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); pr_info("Initmem setup node %d [mem %#018Lx-%#018Lx]\n", nid, - (u64)start_pfn << PAGE_SHIFT, ((u64)end_pfn << PAGE_SHIFT) - 1); + (u64)start_pfn << PAGE_SHIFT, + end_pfn ? ((u64)end_pfn << PAGE_SHIFT) - 1 : 0); #endif calculate_node_totalpages(pgdat, start_pfn, end_pfn, zones_size, zholes_size); -- GitLab From ad5ea8cd5b934cc082f2cda900b490def149908e Mon Sep 17 00:00:00 2001 From: Alexander Kuleshov Date: Tue, 8 Sep 2015 15:04:22 -0700 Subject: [PATCH 6785/7006] mm/memblock.c: fix comment in __next_mem_range() Signed-off-by: Alexander Kuleshov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memblock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/memblock.c b/mm/memblock.c index 31b06c67b1b16..1c7b647e58971 100644 --- a/mm/memblock.c +++ b/mm/memblock.c @@ -976,7 +976,7 @@ void __init_memblock __next_mem_range(u64 *idx, int nid, ulong flags, * in type_b. * * @idx: pointer to u64 loop variable - * @nid: nid: node selector, %NUMA_NO_NODE for all nodes + * @nid: node selector, %NUMA_NO_NODE for all nodes * @flags: pick from blocks based on memory attributes * @type_a: pointer to memblock_type from where the range is taken * @type_b: pointer to memblock_type which excludes memory from being taken -- GitLab From b430d1fd6c7d22cc07e7c22a2ee1078667605313 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:24 -0700 Subject: [PATCH 6786/7006] zsmalloc: drop unused variable `nr_to_migrate' This patchset tweaks compaction and makes it possible to trigger pool compaction automatically when system is getting low on memory. zsmalloc in some cases can suffer from a notable fragmentation and compaction can release some considerable amount of memory. The problem here is that currently we fully rely on user space to perform compaction when needed. However, performing zsmalloc compaction is not always an obvious thing to do. For example, suppose we have a `idle' fragmented (compaction was never performed) zram device and system is getting low on memory due to some 3rd party user processes (gcc LTO, or firefox, etc.). It's quite unlikely that user space will issue zpool compaction in this case. Besides, user space cannot tell for sure how badly pool is fragmented; however, this info is known to zsmalloc and, hence, to a shrinker. This patch (of 7): __zs_compact() does not use `nr_to_migrate', drop it. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 0a7f81aa2249c..7d816c2d74f9d 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1703,7 +1703,6 @@ static struct page *isolate_source_page(struct size_class *class) static unsigned long __zs_compact(struct zs_pool *pool, struct size_class *class) { - int nr_to_migrate; struct zs_compact_control cc; struct page *src_page; struct page *dst_page = NULL; @@ -1714,8 +1713,6 @@ static unsigned long __zs_compact(struct zs_pool *pool, BUG_ON(!is_first_page(src_page)); - /* The goal is to migrate all live objects in source page */ - nr_to_migrate = src_page->inuse; cc.index = 0; cc.s_page = src_page; @@ -1730,7 +1727,6 @@ static unsigned long __zs_compact(struct zs_pool *pool, putback_zspage(pool, class, dst_page); nr_total_migrated += cc.nr_migrated; - nr_to_migrate -= cc.nr_migrated; } /* Stop if we couldn't find slot */ -- GitLab From 57244594195fe697f9261c7970ca25db35280967 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:27 -0700 Subject: [PATCH 6787/7006] zsmalloc: always keep per-class stats Always account per-class `zs_size_stat' stats. This data will help us make better decisions during compaction. We are especially interested in OBJ_ALLOCATED and OBJ_USED, which can tell us if class compaction will result in any memory gain. For instance, we know the number of allocated objects in the class, the number of objects being used (so we also know how many objects are not used) and the number of objects per-page. So we can ensure if we have enough unused objects to form at least one ZS_EMPTY zspage during compaction. We calculate this value on per-class basis so we can calculate a total number of zspages that can be released. Which is exactly what a shrinker wants to know. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 40 ++++++++-------------------------------- 1 file changed, 8 insertions(+), 32 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 7d816c2d74f9d..1227f8323e93c 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -169,14 +169,12 @@ enum zs_stat_type { NR_ZS_STAT_TYPE, }; -#ifdef CONFIG_ZSMALLOC_STAT - -static struct dentry *zs_stat_root; - struct zs_size_stat { unsigned long objs[NR_ZS_STAT_TYPE]; }; +#ifdef CONFIG_ZSMALLOC_STAT +static struct dentry *zs_stat_root; #endif /* @@ -201,6 +199,8 @@ static int zs_size_classes; static const int fullness_threshold_frac = 4; struct size_class { + spinlock_t lock; + struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS]; /* * Size of objects stored in this class. Must be multiple * of ZS_ALIGN. @@ -210,16 +210,10 @@ struct size_class { /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */ int pages_per_zspage; - /* huge object: pages_per_zspage == 1 && maxobj_per_zspage == 1 */ - bool huge; - -#ifdef CONFIG_ZSMALLOC_STAT struct zs_size_stat stats; -#endif - - spinlock_t lock; - struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS]; + /* huge object: pages_per_zspage == 1 && maxobj_per_zspage == 1 */ + bool huge; }; /* @@ -441,8 +435,6 @@ static int get_size_class_index(int size) return min(zs_size_classes - 1, idx); } -#ifdef CONFIG_ZSMALLOC_STAT - static inline void zs_stat_inc(struct size_class *class, enum zs_stat_type type, unsigned long cnt) { @@ -461,6 +453,8 @@ static inline unsigned long zs_stat_get(struct size_class *class, return class->stats.objs[type]; } +#ifdef CONFIG_ZSMALLOC_STAT + static int __init zs_stat_init(void) { if (!debugfs_initialized()) @@ -576,23 +570,6 @@ static void zs_pool_stat_destroy(struct zs_pool *pool) } #else /* CONFIG_ZSMALLOC_STAT */ - -static inline void zs_stat_inc(struct size_class *class, - enum zs_stat_type type, unsigned long cnt) -{ -} - -static inline void zs_stat_dec(struct size_class *class, - enum zs_stat_type type, unsigned long cnt) -{ -} - -static inline unsigned long zs_stat_get(struct size_class *class, - enum zs_stat_type type) -{ - return 0; -} - static int __init zs_stat_init(void) { return 0; @@ -610,7 +587,6 @@ static inline int zs_pool_stat_create(char *name, struct zs_pool *pool) static inline void zs_pool_stat_destroy(struct zs_pool *pool) { } - #endif -- GitLab From 04f05909e0fde36ba481ad4c850b666ebef1ac55 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:30 -0700 Subject: [PATCH 6788/7006] zsmalloc: introduce zs_can_compact() function This function checks if class compaction will free any pages. Rephrasing -- do we have enough unused objects to form at least one ZS_EMPTY page and free it. It aborts compaction if class compaction will not result in any (further) savings. EXAMPLE (this debug output is not part of this patch set): - class size - number of allocated objects - number of used objects - max objects per zspage - pages per zspage - estimated number of pages that will be freed [..] class-512 objs:544 inuse:540 maxobj-per-zspage:8 pages-per-zspage:1 zspages-to-free:0 ... class-512 compaction is useless. break class-496 objs:660 inuse:570 maxobj-per-zspage:33 pages-per-zspage:4 zspages-to-free:2 class-496 objs:627 inuse:570 maxobj-per-zspage:33 pages-per-zspage:4 zspages-to-free:1 class-496 objs:594 inuse:570 maxobj-per-zspage:33 pages-per-zspage:4 zspages-to-free:0 ... class-496 compaction is useless. break class-448 objs:657 inuse:617 maxobj-per-zspage:9 pages-per-zspage:1 zspages-to-free:4 class-448 objs:648 inuse:617 maxobj-per-zspage:9 pages-per-zspage:1 zspages-to-free:3 class-448 objs:639 inuse:617 maxobj-per-zspage:9 pages-per-zspage:1 zspages-to-free:2 class-448 objs:630 inuse:617 maxobj-per-zspage:9 pages-per-zspage:1 zspages-to-free:1 class-448 objs:621 inuse:617 maxobj-per-zspage:9 pages-per-zspage:1 zspages-to-free:0 ... class-448 compaction is useless. break class-432 objs:728 inuse:685 maxobj-per-zspage:28 pages-per-zspage:3 zspages-to-free:1 class-432 objs:700 inuse:685 maxobj-per-zspage:28 pages-per-zspage:3 zspages-to-free:0 ... class-432 compaction is useless. break class-416 objs:819 inuse:705 maxobj-per-zspage:39 pages-per-zspage:4 zspages-to-free:2 class-416 objs:780 inuse:705 maxobj-per-zspage:39 pages-per-zspage:4 zspages-to-free:1 class-416 objs:741 inuse:705 maxobj-per-zspage:39 pages-per-zspage:4 zspages-to-free:0 ... class-416 compaction is useless. break class-400 objs:690 inuse:674 maxobj-per-zspage:10 pages-per-zspage:1 zspages-to-free:1 class-400 objs:680 inuse:674 maxobj-per-zspage:10 pages-per-zspage:1 zspages-to-free:0 ... class-400 compaction is useless. break class-384 objs:736 inuse:709 maxobj-per-zspage:32 pages-per-zspage:3 zspages-to-free:0 ... class-384 compaction is useless. break [..] Every "compaction is useless" indicates that we saved CPU cycles. class-512 has 544 object allocated 540 objects used 8 objects per-page Even if we have a ALMOST_EMPTY zspage, we still don't have enough room to migrate all of its objects and free this zspage; so compaction will not make a lot of sense, it's better to just leave it as is. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 1227f8323e93c..4b39e5eaf34f0 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1676,6 +1676,29 @@ static struct page *isolate_source_page(struct size_class *class) return page; } +/* + * + * Based on the number of unused allocated objects calculate + * and return the number of pages that we can free. + * + * Should be called under class->lock. + */ +static unsigned long zs_can_compact(struct size_class *class) +{ + unsigned long obj_wasted; + + if (!zs_stat_get(class, CLASS_ALMOST_EMPTY)) + return 0; + + obj_wasted = zs_stat_get(class, OBJ_ALLOCATED) - + zs_stat_get(class, OBJ_USED); + + obj_wasted /= get_maxobj_per_zspage(class->size, + class->pages_per_zspage); + + return obj_wasted * get_pages_per_zspage(class->size); +} + static unsigned long __zs_compact(struct zs_pool *pool, struct size_class *class) { @@ -1689,6 +1712,9 @@ static unsigned long __zs_compact(struct zs_pool *pool, BUG_ON(!is_first_page(src_page)); + if (!zs_can_compact(class)) + break; + cc.index = 0; cc.s_page = src_page; -- GitLab From 0dc63d488a2a433a4a85d3908b3f195c4e6450d2 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:33 -0700 Subject: [PATCH 6789/7006] zsmalloc: cosmetic compaction code adjustments Change zs_object_copy() argument order to be (DST, SRC) rather than (SRC, DST). copy/move functions usually have (to, from) arguments order. Rename alloc_target_page() to isolate_target_page(). This function doesn't allocate anything, it isolates target page, pretty much like isolate_source_page(). Tweak __zs_compact() comment. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 4b39e5eaf34f0..2a1f95249f129 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1471,7 +1471,7 @@ void zs_free(struct zs_pool *pool, unsigned long handle) } EXPORT_SYMBOL_GPL(zs_free); -static void zs_object_copy(unsigned long src, unsigned long dst, +static void zs_object_copy(unsigned long dst, unsigned long src, struct size_class *class) { struct page *s_page, *d_page; @@ -1612,7 +1612,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, used_obj = handle_to_obj(handle); free_obj = obj_malloc(d_page, class, handle); - zs_object_copy(used_obj, free_obj, class); + zs_object_copy(free_obj, used_obj, class); index++; record_obj(handle, free_obj); unpin_tag(handle); @@ -1628,7 +1628,7 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, return ret; } -static struct page *alloc_target_page(struct size_class *class) +static struct page *isolate_target_page(struct size_class *class) { int i; struct page *page; @@ -1718,11 +1718,11 @@ static unsigned long __zs_compact(struct zs_pool *pool, cc.index = 0; cc.s_page = src_page; - while ((dst_page = alloc_target_page(class))) { + while ((dst_page = isolate_target_page(class))) { cc.d_page = dst_page; /* - * If there is no more space in dst_page, try to - * allocate another zspage. + * If there is no more space in dst_page, resched + * and see if anyone had allocated another zspage. */ if (!migrate_zspage(pool, class, &cc)) break; -- GitLab From 7d3f3938236b4bb878214e6791e76fd8409bdeee Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:35 -0700 Subject: [PATCH 6790/7006] zsmalloc/zram: introduce zs_pool_stats api `zs_compact_control' accounts the number of migrated objects but it has a limited lifespan -- we lose it as soon as zs_compaction() returns back to zram. It worked fine, because (a) zram had it's own counter of migrated objects and (b) only zram could trigger compaction. However, this does not work for automatic pool compaction (not issued by zram). To account objects migrated during auto-compaction (issued by the shrinker) we need to store this number in zs_pool. Define a new `struct zs_pool_stats' structure to keep zs_pool's stats there. It provides only `num_migrated', as of this writing, but it surely can be extended. A new zsmalloc zs_pool_stats() symbol exports zs_pool's stats back to caller. Use zs_pool_stats() in zram and remove `num_migrated' from zram_stats. Signed-off-by: Sergey Senozhatsky Suggested-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/zram/zram_drv.c | 15 +++++++++------ drivers/block/zram/zram_drv.h | 1 - include/linux/zsmalloc.h | 6 ++++++ mm/zsmalloc.c | 29 +++++++++++++++-------------- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index 9c01f5bfa33fc..bcde5c321090c 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -388,7 +388,6 @@ static ssize_t comp_algorithm_store(struct device *dev, static ssize_t compact_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { - unsigned long nr_migrated; struct zram *zram = dev_to_zram(dev); struct zram_meta *meta; @@ -399,8 +398,7 @@ static ssize_t compact_store(struct device *dev, } meta = zram->meta; - nr_migrated = zs_compact(meta->mem_pool); - atomic64_add(nr_migrated, &zram->stats.num_migrated); + zs_compact(meta->mem_pool); up_read(&zram->init_lock); return len; @@ -428,26 +426,31 @@ static ssize_t mm_stat_show(struct device *dev, struct device_attribute *attr, char *buf) { struct zram *zram = dev_to_zram(dev); + struct zs_pool_stats pool_stats; u64 orig_size, mem_used = 0; long max_used; ssize_t ret; + memset(&pool_stats, 0x00, sizeof(struct zs_pool_stats)); + down_read(&zram->init_lock); - if (init_done(zram)) + if (init_done(zram)) { mem_used = zs_get_total_pages(zram->meta->mem_pool); + zs_pool_stats(zram->meta->mem_pool, &pool_stats); + } orig_size = atomic64_read(&zram->stats.pages_stored); max_used = atomic_long_read(&zram->stats.max_used_pages); ret = scnprintf(buf, PAGE_SIZE, - "%8llu %8llu %8llu %8lu %8ld %8llu %8llu\n", + "%8llu %8llu %8llu %8lu %8ld %8llu %8lu\n", orig_size << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.compr_data_size), mem_used << PAGE_SHIFT, zram->limit_pages << PAGE_SHIFT, max_used << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.zero_pages), - (u64)atomic64_read(&zram->stats.num_migrated)); + pool_stats.num_migrated); up_read(&zram->init_lock); return ret; diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h index 6dbe2df506bf0..8e92339686d74 100644 --- a/drivers/block/zram/zram_drv.h +++ b/drivers/block/zram/zram_drv.h @@ -78,7 +78,6 @@ struct zram_stats { atomic64_t compr_data_size; /* compressed size of pages stored */ atomic64_t num_reads; /* failed + successful */ atomic64_t num_writes; /* --do-- */ - atomic64_t num_migrated; /* no. of migrated object */ atomic64_t failed_reads; /* can happen when memory is too low */ atomic64_t failed_writes; /* can happen when memory is too low */ atomic64_t invalid_io; /* non-page-aligned I/O requests */ diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h index 1338190b54783..ad3d23239043c 100644 --- a/include/linux/zsmalloc.h +++ b/include/linux/zsmalloc.h @@ -34,6 +34,11 @@ enum zs_mapmode { */ }; +struct zs_pool_stats { + /* How many objects were migrated */ + unsigned long num_migrated; +}; + struct zs_pool; struct zs_pool *zs_create_pool(char *name, gfp_t flags); @@ -49,4 +54,5 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle); unsigned long zs_get_total_pages(struct zs_pool *pool); unsigned long zs_compact(struct zs_pool *pool); +void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats); #endif diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 2a1f95249f129..8f76d8875acab 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -245,6 +245,7 @@ struct zs_pool { gfp_t flags; /* allocation flags used when growing pool */ atomic_long_t pages_allocated; + struct zs_pool_stats stats; #ifdef CONFIG_ZSMALLOC_STAT struct dentry *stat_dentry; #endif @@ -1578,7 +1579,7 @@ struct zs_compact_control { /* Starting object index within @s_page which used for live object * in the subpage. */ int index; - /* how many of objects are migrated */ + /* How many of objects were migrated */ int nr_migrated; }; @@ -1590,7 +1591,6 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, struct page *s_page = cc->s_page; struct page *d_page = cc->d_page; unsigned long index = cc->index; - int nr_migrated = 0; int ret = 0; while (1) { @@ -1617,13 +1617,12 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, record_obj(handle, free_obj); unpin_tag(handle); obj_free(pool, class, used_obj); - nr_migrated++; + cc->nr_migrated++; } /* Remember last position in this iteration */ cc->s_page = s_page; cc->index = index; - cc->nr_migrated = nr_migrated; return ret; } @@ -1699,14 +1698,13 @@ static unsigned long zs_can_compact(struct size_class *class) return obj_wasted * get_pages_per_zspage(class->size); } -static unsigned long __zs_compact(struct zs_pool *pool, - struct size_class *class) +static void __zs_compact(struct zs_pool *pool, struct size_class *class) { struct zs_compact_control cc; struct page *src_page; struct page *dst_page = NULL; - unsigned long nr_total_migrated = 0; + cc.nr_migrated = 0; spin_lock(&class->lock); while ((src_page = isolate_source_page(class))) { @@ -1728,7 +1726,6 @@ static unsigned long __zs_compact(struct zs_pool *pool, break; putback_zspage(pool, class, dst_page); - nr_total_migrated += cc.nr_migrated; } /* Stop if we couldn't find slot */ @@ -1738,7 +1735,6 @@ static unsigned long __zs_compact(struct zs_pool *pool, putback_zspage(pool, class, dst_page); putback_zspage(pool, class, src_page); spin_unlock(&class->lock); - nr_total_migrated += cc.nr_migrated; cond_resched(); spin_lock(&class->lock); } @@ -1746,15 +1742,14 @@ static unsigned long __zs_compact(struct zs_pool *pool, if (src_page) putback_zspage(pool, class, src_page); - spin_unlock(&class->lock); + pool->stats.num_migrated += cc.nr_migrated; - return nr_total_migrated; + spin_unlock(&class->lock); } unsigned long zs_compact(struct zs_pool *pool) { int i; - unsigned long nr_migrated = 0; struct size_class *class; for (i = zs_size_classes - 1; i >= 0; i--) { @@ -1763,13 +1758,19 @@ unsigned long zs_compact(struct zs_pool *pool) continue; if (class->index != i) continue; - nr_migrated += __zs_compact(pool, class); + __zs_compact(pool, class); } - return nr_migrated; + return pool->stats.num_migrated; } EXPORT_SYMBOL_GPL(zs_compact); +void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats) +{ + memcpy(stats, &pool->stats, sizeof(struct zs_pool_stats)); +} +EXPORT_SYMBOL_GPL(zs_pool_stats); + /** * zs_create_pool - Creates an allocation pool to work from. * @flags: allocation flags used to allocate pool metadata -- GitLab From 860c707dca155a56dfa115ddd6c00959296144a6 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:38 -0700 Subject: [PATCH 6791/7006] zsmalloc: account the number of compacted pages Compaction returns back to zram the number of migrated objects, which is quite uninformative -- we have objects of different sizes so user space cannot obtain any valuable data from that number. Change compaction to operate in terms of pages and return back to compaction issuer the number of pages that were freed during compaction. So from now on we will export more meaningful value in zram/mm_stat -- the number of freed (compacted) pages. This requires: (a) a rename of `num_migrated' to 'pages_compacted' (b) a internal API change -- return first_page's fullness_group from putback_zspage(), so we know when putback_zspage() did free_zspage(). It helps us to account compaction stats correctly. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/blockdev/zram.txt | 3 ++- drivers/block/zram/zram_drv.c | 2 +- include/linux/zsmalloc.h | 4 ++-- mm/zsmalloc.c | 27 +++++++++++++++++---------- 4 files changed, 22 insertions(+), 14 deletions(-) diff --git a/Documentation/blockdev/zram.txt b/Documentation/blockdev/zram.txt index c4de576093aff..62435bb252660 100644 --- a/Documentation/blockdev/zram.txt +++ b/Documentation/blockdev/zram.txt @@ -144,7 +144,8 @@ mem_used_max RW the maximum amount memory zram have consumed to store compressed data mem_limit RW the maximum amount of memory ZRAM can use to store the compressed data -num_migrated RO the number of objects migrated migrated by compaction +pages_compacted RO the number of pages freed during compaction + (available only via zram/mm_stat node) compact WO trigger memory compaction WARNING diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index bcde5c321090c..f1c4bb34e007e 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -450,7 +450,7 @@ static ssize_t mm_stat_show(struct device *dev, zram->limit_pages << PAGE_SHIFT, max_used << PAGE_SHIFT, (u64)atomic64_read(&zram->stats.zero_pages), - pool_stats.num_migrated); + pool_stats.pages_compacted); up_read(&zram->init_lock); return ret; diff --git a/include/linux/zsmalloc.h b/include/linux/zsmalloc.h index ad3d23239043c..6398dfae53f10 100644 --- a/include/linux/zsmalloc.h +++ b/include/linux/zsmalloc.h @@ -35,8 +35,8 @@ enum zs_mapmode { }; struct zs_pool_stats { - /* How many objects were migrated */ - unsigned long num_migrated; + /* How many pages were migrated (freed) */ + unsigned long pages_compacted; }; struct zs_pool; diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 8f76d8875acab..b7b4a5612ec7a 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1579,8 +1579,6 @@ struct zs_compact_control { /* Starting object index within @s_page which used for live object * in the subpage. */ int index; - /* How many of objects were migrated */ - int nr_migrated; }; static int migrate_zspage(struct zs_pool *pool, struct size_class *class, @@ -1617,7 +1615,6 @@ static int migrate_zspage(struct zs_pool *pool, struct size_class *class, record_obj(handle, free_obj); unpin_tag(handle); obj_free(pool, class, used_obj); - cc->nr_migrated++; } /* Remember last position in this iteration */ @@ -1643,8 +1640,17 @@ static struct page *isolate_target_page(struct size_class *class) return page; } -static void putback_zspage(struct zs_pool *pool, struct size_class *class, - struct page *first_page) +/* + * putback_zspage - add @first_page into right class's fullness list + * @pool: target pool + * @class: destination class + * @first_page: target page + * + * Return @fist_page's fullness_group + */ +static enum fullness_group putback_zspage(struct zs_pool *pool, + struct size_class *class, + struct page *first_page) { enum fullness_group fullness; @@ -1662,6 +1668,8 @@ static void putback_zspage(struct zs_pool *pool, struct size_class *class, free_zspage(first_page); } + + return fullness; } static struct page *isolate_source_page(struct size_class *class) @@ -1704,7 +1712,6 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class) struct page *src_page; struct page *dst_page = NULL; - cc.nr_migrated = 0; spin_lock(&class->lock); while ((src_page = isolate_source_page(class))) { @@ -1733,7 +1740,9 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class) break; putback_zspage(pool, class, dst_page); - putback_zspage(pool, class, src_page); + if (putback_zspage(pool, class, src_page) == ZS_EMPTY) + pool->stats.pages_compacted += + get_pages_per_zspage(class->size); spin_unlock(&class->lock); cond_resched(); spin_lock(&class->lock); @@ -1742,8 +1751,6 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class) if (src_page) putback_zspage(pool, class, src_page); - pool->stats.num_migrated += cc.nr_migrated; - spin_unlock(&class->lock); } @@ -1761,7 +1768,7 @@ unsigned long zs_compact(struct zs_pool *pool) __zs_compact(pool, class); } - return pool->stats.num_migrated; + return pool->stats.pages_compacted; } EXPORT_SYMBOL_GPL(zs_compact); -- GitLab From ab9d306d9c3bf64b1dbad127aa13252cc550f839 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:41 -0700 Subject: [PATCH 6792/7006] zsmalloc: use shrinker to trigger auto-compaction Perform automatic pool compaction by a shrinker when system is getting tight on memory. User-space has a very little knowledge regarding zsmalloc fragmentation and basically has no mechanism to tell whether compaction will result in any memory gain. Another issue is that user space is not always aware of the fact that system is getting tight on memory. Which leads to very uncomfortable scenarios when user space may start issuing compaction 'randomly' or from crontab (for example). Fragmentation is not always necessarily bad, allocated and unused objects, after all, may be filled with the data later, w/o the need of allocating a new zspage. On the other hand, we obviously don't want to waste memory when the system needs it. Compaction now has a relatively quick pool scan so we are able to estimate the number of pages that will be freed easily, which makes it possible to call this function from a shrinker->count_objects() callback. We also abort compaction as soon as we detect that we can't free any pages any more, preventing wasteful objects migrations. Signed-off-by: Sergey Senozhatsky Suggested-by: Minchan Kim Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index b7b4a5612ec7a..27b9661c8fa67 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -246,6 +246,14 @@ struct zs_pool { atomic_long_t pages_allocated; struct zs_pool_stats stats; + + /* Compact classes */ + struct shrinker shrinker; + /* + * To signify that register_shrinker() was successful + * and unregister_shrinker() will not Oops. + */ + bool shrinker_enabled; #ifdef CONFIG_ZSMALLOC_STAT struct dentry *stat_dentry; #endif @@ -1778,6 +1786,69 @@ void zs_pool_stats(struct zs_pool *pool, struct zs_pool_stats *stats) } EXPORT_SYMBOL_GPL(zs_pool_stats); +static unsigned long zs_shrinker_scan(struct shrinker *shrinker, + struct shrink_control *sc) +{ + unsigned long pages_freed; + struct zs_pool *pool = container_of(shrinker, struct zs_pool, + shrinker); + + pages_freed = pool->stats.pages_compacted; + /* + * Compact classes and calculate compaction delta. + * Can run concurrently with a manually triggered + * (by user) compaction. + */ + pages_freed = zs_compact(pool) - pages_freed; + + return pages_freed ? pages_freed : SHRINK_STOP; +} + +static unsigned long zs_shrinker_count(struct shrinker *shrinker, + struct shrink_control *sc) +{ + int i; + struct size_class *class; + unsigned long pages_to_free = 0; + struct zs_pool *pool = container_of(shrinker, struct zs_pool, + shrinker); + + if (!pool->shrinker_enabled) + return 0; + + for (i = zs_size_classes - 1; i >= 0; i--) { + class = pool->size_class[i]; + if (!class) + continue; + if (class->index != i) + continue; + + spin_lock(&class->lock); + pages_to_free += zs_can_compact(class); + spin_unlock(&class->lock); + } + + return pages_to_free; +} + +static void zs_unregister_shrinker(struct zs_pool *pool) +{ + if (pool->shrinker_enabled) { + unregister_shrinker(&pool->shrinker); + pool->shrinker_enabled = false; + } +} + +static int zs_register_shrinker(struct zs_pool *pool) +{ + pool->shrinker.scan_objects = zs_shrinker_scan; + pool->shrinker.count_objects = zs_shrinker_count; + pool->shrinker.batch = 0; + pool->shrinker.seeks = DEFAULT_SEEKS; + + return register_shrinker(&pool->shrinker); +} + /** * zs_create_pool - Creates an allocation pool to work from. * @flags: allocation flags used to allocate pool metadata @@ -1863,6 +1934,12 @@ struct zs_pool *zs_create_pool(char *name, gfp_t flags) if (zs_pool_stat_create(name, pool)) goto err; + /* + * Not critical, we still can use the pool + * and user can trigger compaction manually. + */ + if (zs_register_shrinker(pool) == 0) + pool->shrinker_enabled = true; return pool; err: @@ -1875,6 +1952,7 @@ void zs_destroy_pool(struct zs_pool *pool) { int i; + zs_unregister_shrinker(pool); zs_pool_stat_destroy(pool); for (i = 0; i < zs_size_classes; i++) { -- GitLab From 58f171174625150f3aaad0cddd3e365270b8e1b8 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:44 -0700 Subject: [PATCH 6793/7006] zsmalloc: partial page ordering within a fullness_list We want to see more ZS_FULL pages and less ZS_ALMOST_{FULL, EMPTY} pages. Put a page with higher ->inuse count first within its ->fullness_list, which will give us better chances to fill up this page with new objects (find_get_zspage() return ->fullness_list head for new object allocation), so some zspages will become ZS_ALMOST_FULL/ZS_FULL quicker. It performs a trivial and cheap ->inuse compare which does not slow down zsmalloc and in the worst case keeps the list pages in no particular order. A more expensive solution could sort fullness_list by ->inuse count. [minchan@kernel.org: code adjustments] Signed-off-by: Sergey Senozhatsky Cc: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 27b9661c8fa67..615b9b9b45ebf 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -643,13 +643,22 @@ static void insert_zspage(struct page *page, struct size_class *class, if (fullness >= _ZS_NR_FULLNESS_GROUPS) return; - head = &class->fullness_list[fullness]; - if (*head) - list_add_tail(&page->lru, &(*head)->lru); - - *head = page; zs_stat_inc(class, fullness == ZS_ALMOST_EMPTY ? CLASS_ALMOST_EMPTY : CLASS_ALMOST_FULL, 1); + + head = &class->fullness_list[fullness]; + if (!*head) { + *head = page; + return; + } + + /* + * We want to see more ZS_FULL pages and less almost + * empty/full. Put pages with higher ->inuse first. + */ + list_add_tail(&page->lru, &(*head)->lru); + if (page->inuse >= (*head)->inuse) + *head = page; } /* -- GitLab From ad9d5e175a77a253f52a7259a7c918b8351d99f1 Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Tue, 8 Sep 2015 15:04:47 -0700 Subject: [PATCH 6794/7006] zsmalloc: consider ZS_ALMOST_FULL as migrate source There is no reason to prevent select ZS_ALMOST_FULL as migration source if we cannot find source from ZS_ALMOST_EMPTY. With this patch, zs_can_compact will return more exact result. Signed-off-by: Minchan Kim Acked-by: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 615b9b9b45ebf..c10885ca87a49 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1691,11 +1691,17 @@ static enum fullness_group putback_zspage(struct zs_pool *pool, static struct page *isolate_source_page(struct size_class *class) { - struct page *page; + int i; + struct page *page = NULL; + + for (i = ZS_ALMOST_EMPTY; i >= ZS_ALMOST_FULL; i--) { + page = class->fullness_list[i]; + if (!page) + continue; - page = class->fullness_list[ZS_ALMOST_EMPTY]; - if (page) - remove_zspage(page, class, ZS_ALMOST_EMPTY); + remove_zspage(page, class, i); + break; + } return page; } @@ -1711,9 +1717,6 @@ static unsigned long zs_can_compact(struct size_class *class) { unsigned long obj_wasted; - if (!zs_stat_get(class, CLASS_ALMOST_EMPTY)) - return 0; - obj_wasted = zs_stat_get(class, OBJ_ALLOCATED) - zs_stat_get(class, OBJ_USED); -- GitLab From 6cbf16b3b66a61b9c6df8f2ed4ac346cb427f28a Mon Sep 17 00:00:00 2001 From: Minchan Kim Date: Tue, 8 Sep 2015 15:04:49 -0700 Subject: [PATCH 6795/7006] zsmalloc: use class->pages_per_zspage There is no need to recalcurate pages_per_zspage in runtime. Just use class->pages_per_zspage to avoid unnecessary runtime overhead. Signed-off-by: Minchan Kim Acked-by: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index c10885ca87a49..ce08d043becd2 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1723,7 +1723,7 @@ static unsigned long zs_can_compact(struct size_class *class) obj_wasted /= get_maxobj_per_zspage(class->size, class->pages_per_zspage); - return obj_wasted * get_pages_per_zspage(class->size); + return obj_wasted * class->pages_per_zspage; } static void __zs_compact(struct zs_pool *pool, struct size_class *class) @@ -1761,8 +1761,7 @@ static void __zs_compact(struct zs_pool *pool, struct size_class *class) putback_zspage(pool, class, dst_page); if (putback_zspage(pool, class, src_page) == ZS_EMPTY) - pool->stats.pages_compacted += - get_pages_per_zspage(class->size); + pool->stats.pages_compacted += class->pages_per_zspage; spin_unlock(&class->lock); cond_resched(); spin_lock(&class->lock); -- GitLab From b3e237f1f5a86030c875e186ff19640f4f4f3c63 Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:52 -0700 Subject: [PATCH 6796/7006] zsmalloc: do not take class lock in zs_shrinker_count() We can avoid taking class ->lock around zs_can_compact() in zs_shrinker_count(), because the number that we return back is outdated in general case, by design. We have different sources that are able to change class's state right after we return from zs_can_compact() -- ongoing I/O operations, manually triggered compaction, or two of them happening simultaneously. We re-do this calculations during compaction on a per class basis anyway. zs_unregister_shrinker() will not return until we have an active shrinker, so classes won't unexpectedly disappear while zs_shrinker_count() iterates them. Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index ce08d043becd2..c19b99c8a4572 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -1710,8 +1710,6 @@ static struct page *isolate_source_page(struct size_class *class) * * Based on the number of unused allocated objects calculate * and return the number of pages that we can free. - * - * Should be called under class->lock. */ static unsigned long zs_can_compact(struct size_class *class) { @@ -1834,9 +1832,7 @@ static unsigned long zs_shrinker_count(struct shrinker *shrinker, if (class->index != i) continue; - spin_lock(&class->lock); pages_to_free += zs_can_compact(class); - spin_unlock(&class->lock); } return pages_to_free; -- GitLab From cd10add00c1b31cd664a31108a9b395025def50a Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:55 -0700 Subject: [PATCH 6797/7006] zsmalloc: remove null check from destroy_handle_cache() We can pass a NULL cache pointer to kmem_cache_destroy(), because it NULL-checks its argument now. Remove redundant test from destroy_handle_cache(). Signed-off-by: Sergey Senozhatsky Acked-by: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zsmalloc.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index c19b99c8a4572..089120429c183 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -288,8 +288,7 @@ static int create_handle_cache(struct zs_pool *pool) static void destroy_handle_cache(struct zs_pool *pool) { - if (pool->handle_cachep) - kmem_cache_destroy(pool->handle_cachep); + kmem_cache_destroy(pool->handle_cachep); } static unsigned long alloc_handle(struct zs_pool *pool) -- GitLab From 708649694a8699ff91d395c4aef5ecea3ade14bc Mon Sep 17 00:00:00 2001 From: Sergey Senozhatsky Date: Tue, 8 Sep 2015 15:04:58 -0700 Subject: [PATCH 6798/7006] zram: unify error reporting Make zram syslog error reporting more consistent. We have random error levels in some places. For example, critical errors like "Error allocating memory for compressed page" and "Unable to allocate temp memory" are reported as KERN_INFO messages. a) Reassign error levels Error messages that directly affect zram functionality -- pr_err(): Error allocating zram address table Error creating memory pool Decompression failed! err=%d, page=%u Unable to allocate temp memory Compression failed! err=%d Error allocating memory for compressed page: %u, size=%zu Cannot initialise %s compressing backend Error allocating disk queue for device %d Error allocating disk structure for device %d Error creating sysfs group for device %d Unable to register zram-control class Unable to get major number Messages that do not affect functionality, but user must be warned (because sysfs attrs will be removed in this particular case) -- pr_warn(): %d (%s) Attribute %s (and others) will be removed. %s Messages that do not affect functionality and mostly are informative -- pr_info(): Cannot change max compression streams Can't change algorithm for initialized device Cannot change disksize for initialized device Added device: %s Removed device: %s b) Update sysfs_create_group() error message First, it lacks a trailing new line; add it. Second, every error message in zram_add() has a "for device %d" part, which makes errors more informative. Add missing part to "Error creating sysfs group" message. Signed-off-by: Sergey Senozhatsky Cc: Minchan Kim Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/block/zram/zram_drv.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c index f1c4bb34e007e..9fa15bb9d118e 100644 --- a/drivers/block/zram/zram_drv.c +++ b/drivers/block/zram/zram_drv.c @@ -622,7 +622,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec, uncmem = user_mem; if (!uncmem) { - pr_info("Unable to allocate temp memory\n"); + pr_err("Unable to allocate temp memory\n"); ret = -ENOMEM; goto out_cleanup; } @@ -719,7 +719,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index, handle = zs_malloc(meta->mem_pool, clen); if (!handle) { - pr_info("Error allocating memory for compressed page: %u, size=%zu\n", + pr_err("Error allocating memory for compressed page: %u, size=%zu\n", index, clen); ret = -ENOMEM; goto out; @@ -1039,7 +1039,7 @@ static ssize_t disksize_store(struct device *dev, comp = zcomp_create(zram->compressor, zram->max_comp_streams); if (IS_ERR(comp)) { - pr_info("Cannot initialise %s compressing backend\n", + pr_err("Cannot initialise %s compressing backend\n", zram->compressor); err = PTR_ERR(comp); goto out_free_meta; @@ -1217,7 +1217,7 @@ static int zram_add(void) /* gendisk structure */ zram->disk = alloc_disk(1); if (!zram->disk) { - pr_warn("Error allocating disk structure for device %d\n", + pr_err("Error allocating disk structure for device %d\n", device_id); ret = -ENOMEM; goto out_free_queue; @@ -1266,7 +1266,8 @@ static int zram_add(void) ret = sysfs_create_group(&disk_to_dev(zram->disk)->kobj, &zram_disk_attr_group); if (ret < 0) { - pr_warn("Error creating sysfs group"); + pr_err("Error creating sysfs group for device %d\n", + device_id); goto out_free_disk; } strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor)); @@ -1406,13 +1407,13 @@ static int __init zram_init(void) ret = class_register(&zram_control_class); if (ret) { - pr_warn("Unable to register zram-control class\n"); + pr_err("Unable to register zram-control class\n"); return ret; } zram_major = register_blkdev(0, "zram"); if (zram_major <= 0) { - pr_warn("Unable to get major number\n"); + pr_err("Unable to get major number\n"); class_unregister(&zram_control_class); return -EBUSY; } -- GitLab From 5b999aadbae65696a148f55250d94b6f3d74071e Mon Sep 17 00:00:00 2001 From: Dmitry Safonov <0x7f454c46@gmail.com> Date: Tue, 8 Sep 2015 15:05:00 -0700 Subject: [PATCH 6799/7006] mm: swap: zswap: maybe_preload & refactoring zswap_get_swap_cache_page and read_swap_cache_async have pretty much the same code with only significant difference in return value and usage of swap_readpage. I a helper __read_swap_cache_async() with the common code. Behavior change: now zswap_get_swap_cache_page will use radix_tree_maybe_preload instead radix_tree_preload. Looks like, this wasn't changed only by the reason of code duplication. Signed-off-by: Dmitry Safonov <0x7f454c46@gmail.com> Cc: Johannes Weiner Cc: Vladimir Davydov Cc: Michal Hocko Cc: Hugh Dickins Cc: Minchan Kim Cc: Tejun Heo Cc: Jens Axboe Cc: Christoph Hellwig Cc: David Herrmann Cc: Seth Jennings Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 3 ++ mm/swap_state.c | 37 +++++++++++++++------- mm/zswap.c | 73 ++++---------------------------------------- 3 files changed, 35 insertions(+), 78 deletions(-) diff --git a/include/linux/swap.h b/include/linux/swap.h index 2ce190709280f..7ba7dccaf0e7e 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -406,6 +406,9 @@ extern void free_pages_and_swap_cache(struct page **, int); extern struct page *lookup_swap_cache(swp_entry_t); extern struct page *read_swap_cache_async(swp_entry_t, gfp_t, struct vm_area_struct *vma, unsigned long addr); +extern struct page *__read_swap_cache_async(swp_entry_t, gfp_t, + struct vm_area_struct *vma, unsigned long addr, + bool *new_page_allocated); extern struct page *swapin_readahead(swp_entry_t, gfp_t, struct vm_area_struct *vma, unsigned long addr); diff --git a/mm/swap_state.c b/mm/swap_state.c index 8bc8e66138da1..d504adb7fa5f0 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -288,17 +288,14 @@ struct page * lookup_swap_cache(swp_entry_t entry) return page; } -/* - * Locate a page of swap in physical memory, reserving swap cache space - * and reading the disk if it is not already cached. - * A failure return means that either the page allocation failed or that - * the swap entry is no longer in use. - */ -struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, - struct vm_area_struct *vma, unsigned long addr) +struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, + struct vm_area_struct *vma, unsigned long addr, + bool *new_page_allocated) { struct page *found_page, *new_page = NULL; + struct address_space *swapper_space = swap_address_space(entry); int err; + *new_page_allocated = false; do { /* @@ -306,8 +303,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * called after lookup_swap_cache() failed, re-calling * that would confuse statistics. */ - found_page = find_get_page(swap_address_space(entry), - entry.val); + found_page = find_get_page(swapper_space, entry.val); if (found_page) break; @@ -366,7 +362,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, * Initiate read into locked page and return. */ lru_cache_add_anon(new_page); - swap_readpage(new_page); + *new_page_allocated = true; return new_page; } radix_tree_preload_end(); @@ -384,6 +380,25 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, return found_page; } +/* + * Locate a page of swap in physical memory, reserving swap cache space + * and reading the disk if it is not already cached. + * A failure return means that either the page allocation failed or that + * the swap entry is no longer in use. + */ +struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, + struct vm_area_struct *vma, unsigned long addr) +{ + bool page_was_allocated; + struct page *retpage = __read_swap_cache_async(entry, gfp_mask, + vma, addr, &page_was_allocated); + + if (page_was_allocated) + swap_readpage(retpage); + + return retpage; +} + static unsigned long swapin_nr_pages(unsigned long offset) { static unsigned long prev_offset; diff --git a/mm/zswap.c b/mm/zswap.c index 2d5727baed598..09208c7c86f3e 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -446,75 +446,14 @@ enum zswap_get_swap_ret { static int zswap_get_swap_cache_page(swp_entry_t entry, struct page **retpage) { - struct page *found_page, *new_page = NULL; - struct address_space *swapper_space = swap_address_space(entry); - int err; + bool page_was_allocated; - *retpage = NULL; - do { - /* - * First check the swap cache. Since this is normally - * called after lookup_swap_cache() failed, re-calling - * that would confuse statistics. - */ - found_page = find_get_page(swapper_space, entry.val); - if (found_page) - break; - - /* - * Get a new page to read into from swap. - */ - if (!new_page) { - new_page = alloc_page(GFP_KERNEL); - if (!new_page) - break; /* Out of memory */ - } - - /* - * call radix_tree_preload() while we can wait. - */ - err = radix_tree_preload(GFP_KERNEL); - if (err) - break; - - /* - * Swap entry may have been freed since our caller observed it. - */ - err = swapcache_prepare(entry); - if (err == -EEXIST) { /* seems racy */ - radix_tree_preload_end(); - continue; - } - if (err) { /* swp entry is obsolete ? */ - radix_tree_preload_end(); - break; - } - - /* May fail (-ENOMEM) if radix-tree node allocation failed. */ - __set_page_locked(new_page); - SetPageSwapBacked(new_page); - err = __add_to_swap_cache(new_page, entry); - if (likely(!err)) { - radix_tree_preload_end(); - lru_cache_add_anon(new_page); - *retpage = new_page; - return ZSWAP_SWAPCACHE_NEW; - } - radix_tree_preload_end(); - ClearPageSwapBacked(new_page); - __clear_page_locked(new_page); - /* - * add_to_swap_cache() doesn't return -EEXIST, so we can safely - * clear SWAP_HAS_CACHE flag. - */ - swapcache_free(entry); - } while (err != -ENOMEM); - - if (new_page) - page_cache_release(new_page); - if (!found_page) + *retpage = __read_swap_cache_async(entry, GFP_KERNEL, + NULL, 0, &page_was_allocated); + if (page_was_allocated) + return ZSWAP_SWAPCACHE_NEW; + if (!*retpage) return ZSWAP_SWAPCACHE_FAIL; - *retpage = found_page; return ZSWAP_SWAPCACHE_EXIST; } -- GitLab From 786727799a85aeabc20cab5ecfb72771bcbd6b85 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Sep 2015 15:05:03 -0700 Subject: [PATCH 6800/7006] mm: zpool: constify the zpool_ops The structure zpool_ops is not modified so make the pointer to it a pointer to const. Signed-off-by: Krzysztof Kozlowski Acked-by: Dan Streetman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/zpool.h | 4 ++-- mm/zbud.c | 4 ++-- mm/zpool.c | 4 ++-- mm/zsmalloc.c | 3 ++- mm/zswap.c | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/linux/zpool.h b/include/linux/zpool.h index d30eff3d84d54..c924a28d98050 100644 --- a/include/linux/zpool.h +++ b/include/linux/zpool.h @@ -37,7 +37,7 @@ enum zpool_mapmode { }; struct zpool *zpool_create_pool(char *type, char *name, - gfp_t gfp, struct zpool_ops *ops); + gfp_t gfp, const struct zpool_ops *ops); char *zpool_get_type(struct zpool *pool); @@ -81,7 +81,7 @@ struct zpool_driver { atomic_t refcount; struct list_head list; - void *(*create)(char *name, gfp_t gfp, struct zpool_ops *ops, + void *(*create)(char *name, gfp_t gfp, const struct zpool_ops *ops, struct zpool *zpool); void (*destroy)(void *pool); diff --git a/mm/zbud.c b/mm/zbud.c index f3bf6f7627d8d..6f8158d648648 100644 --- a/mm/zbud.c +++ b/mm/zbud.c @@ -99,7 +99,7 @@ struct zbud_pool { struct zbud_ops *ops; #ifdef CONFIG_ZPOOL struct zpool *zpool; - struct zpool_ops *zpool_ops; + const struct zpool_ops *zpool_ops; #endif }; @@ -138,7 +138,7 @@ static struct zbud_ops zbud_zpool_ops = { }; static void *zbud_zpool_create(char *name, gfp_t gfp, - struct zpool_ops *zpool_ops, + const struct zpool_ops *zpool_ops, struct zpool *zpool) { struct zbud_pool *pool; diff --git a/mm/zpool.c b/mm/zpool.c index 722a4f60e90b2..951db32b833f3 100644 --- a/mm/zpool.c +++ b/mm/zpool.c @@ -22,7 +22,7 @@ struct zpool { struct zpool_driver *driver; void *pool; - struct zpool_ops *ops; + const struct zpool_ops *ops; struct list_head list; }; @@ -115,7 +115,7 @@ static void zpool_put_driver(struct zpool_driver *driver) * Returns: New zpool on success, NULL on failure. */ struct zpool *zpool_create_pool(char *type, char *name, gfp_t gfp, - struct zpool_ops *ops) + const struct zpool_ops *ops) { struct zpool_driver *driver; struct zpool *zpool; diff --git a/mm/zsmalloc.c b/mm/zsmalloc.c index 089120429c183..f135b1b6fcdca 100644 --- a/mm/zsmalloc.c +++ b/mm/zsmalloc.c @@ -311,7 +311,8 @@ static void record_obj(unsigned long handle, unsigned long obj) #ifdef CONFIG_ZPOOL -static void *zs_zpool_create(char *name, gfp_t gfp, struct zpool_ops *zpool_ops, +static void *zs_zpool_create(char *name, gfp_t gfp, + const struct zpool_ops *zpool_ops, struct zpool *zpool) { return zs_create_pool(name, gfp); diff --git a/mm/zswap.c b/mm/zswap.c index 09208c7c86f3e..48a1d081e2a5f 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -755,7 +755,7 @@ static void zswap_frontswap_invalidate_area(unsigned type) zswap_trees[type] = NULL; } -static struct zpool_ops zswap_zpool_ops = { +static const struct zpool_ops zswap_zpool_ops = { .evict = zswap_writeback_entry }; -- GitLab From c83db4f419e7105af38cdcca80cc51213214a2c8 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Tue, 8 Sep 2015 15:05:06 -0700 Subject: [PATCH 6801/7006] mm: zbud: constify the zbud_ops The structure zbud_ops is not modified so make the pointer to it a pointer to const. Signed-off-by: Krzysztof Kozlowski Acked-by: Dan Streetman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/zbud.h | 2 +- mm/zbud.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/linux/zbud.h b/include/linux/zbud.h index f9d41a6e361f4..e183a0a65ac1c 100644 --- a/include/linux/zbud.h +++ b/include/linux/zbud.h @@ -9,7 +9,7 @@ struct zbud_ops { int (*evict)(struct zbud_pool *pool, unsigned long handle); }; -struct zbud_pool *zbud_create_pool(gfp_t gfp, struct zbud_ops *ops); +struct zbud_pool *zbud_create_pool(gfp_t gfp, const struct zbud_ops *ops); void zbud_destroy_pool(struct zbud_pool *pool); int zbud_alloc(struct zbud_pool *pool, size_t size, gfp_t gfp, unsigned long *handle); diff --git a/mm/zbud.c b/mm/zbud.c index 6f8158d648648..fa48bcdff9d5b 100644 --- a/mm/zbud.c +++ b/mm/zbud.c @@ -96,7 +96,7 @@ struct zbud_pool { struct list_head buddied; struct list_head lru; u64 pages_nr; - struct zbud_ops *ops; + const struct zbud_ops *ops; #ifdef CONFIG_ZPOOL struct zpool *zpool; const struct zpool_ops *zpool_ops; @@ -133,7 +133,7 @@ static int zbud_zpool_evict(struct zbud_pool *pool, unsigned long handle) return -ENOENT; } -static struct zbud_ops zbud_zpool_ops = { +static const struct zbud_ops zbud_zpool_ops = { .evict = zbud_zpool_evict }; @@ -302,7 +302,7 @@ static int num_free_chunks(struct zbud_header *zhdr) * Return: pointer to the new zbud pool or NULL if the metadata allocation * failed. */ -struct zbud_pool *zbud_create_pool(gfp_t gfp, struct zbud_ops *ops) +struct zbud_pool *zbud_create_pool(gfp_t gfp, const struct zbud_ops *ops) { struct zbud_pool *pool; int i; -- GitLab From df69f52d990bd85159727bd26e819d3a6e49c666 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Tue, 8 Sep 2015 15:05:09 -0700 Subject: [PATCH 6802/7006] zpool: remove no-op module init/exit Remove zpool_init() and zpool_exit(); they do nothing other than print "loaded" and "unloaded". Signed-off-by: Dan Streetman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zpool.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/mm/zpool.c b/mm/zpool.c index 951db32b833f3..68d2dd8ed2d8c 100644 --- a/mm/zpool.c +++ b/mm/zpool.c @@ -320,20 +320,6 @@ u64 zpool_get_total_size(struct zpool *zpool) return zpool->driver->total_size(zpool->pool); } -static int __init init_zpool(void) -{ - pr_info("loaded\n"); - return 0; -} - -static void __exit exit_zpool(void) -{ - pr_info("unloaded\n"); -} - -module_init(init_zpool); -module_exit(exit_zpool); - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Dan Streetman "); MODULE_DESCRIPTION("Common API for compressed memory storage"); -- GitLab From 7179385afef252cd3f52c0a06cc0c405ae6d66bc Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Fri, 12 Jun 2015 09:44:52 -0400 Subject: [PATCH 6803/7006] sb_edac: look harder for DDRIO on Haswell systems In case the memory banks are populated so the first channel isn't used, the DDRIO PCI device won't be visible and it won't be possible to determine the memory type. Acked-by: Tony Luck Signed-off-by: Aristeu Rozanski Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/sb_edac.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index ca7831168298a..84b740d64b501 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -471,6 +471,9 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = { #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD2 0x2f6c #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TAD3 0x2f6d #define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0 0x2fbd +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1 0x2fbf +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2 0x2fb9 +#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3 0x2fbb static const struct pci_id_descr pci_dev_descr_haswell[] = { /* first item must be the HA */ { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0, 0) }, @@ -488,6 +491,9 @@ static const struct pci_id_descr pci_dev_descr_haswell[] = { { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TAD3, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0, 1) }, + { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1, 1) }, + { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2, 1) }, + { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_TA, 1) }, { PCI_DESCR(PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1_THERMAL, 1) }, @@ -1869,7 +1875,11 @@ static int haswell_mci_bind_devs(struct mem_ctl_info *mci, } break; case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO0: - pvt->pci_ddrio = pdev; + case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO1: + case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO2: + case PCI_DEVICE_ID_INTEL_HASWELL_IMC_DDRIO3: + if (!pvt->pci_ddrio) + pvt->pci_ddrio = pdev; break; case PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA1: pvt->pci_ha1 = pdev; -- GitLab From 12f0721c5a70408e86257c5c99605cf743cd44c6 Mon Sep 17 00:00:00 2001 From: Aristeu Rozanski Date: Fri, 12 Jun 2015 15:08:17 -0400 Subject: [PATCH 6804/7006] sb_edac: correctly fetch DIMM width on Ivy Bridge and Haswell dimm_dev_type has been incorrectly determined in sb_edac. This patch fixes it for Ivy Bridge and Haswell only since nothing like exists for Sandy Bridge. We tested this patch in multiple systems matching the results with the installed memory modules. Acked-by: Tony Luck Signed-off-by: Aristeu Rozanski Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/sb_edac.c | 60 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 49 insertions(+), 11 deletions(-) diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 84b740d64b501..cf1268ddef0c0 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -280,6 +280,7 @@ struct sbridge_info { u8 max_interleave; u8 (*get_node_id)(struct sbridge_pvt *pvt); enum mem_type (*get_memory_type)(struct sbridge_pvt *pvt); + enum dev_type (*get_width)(struct sbridge_pvt *pvt, u32 mtr); struct pci_dev *pci_vtd; }; @@ -768,6 +769,49 @@ out: return mtype; } +static enum dev_type sbridge_get_width(struct sbridge_pvt *pvt, u32 mtr) +{ + /* there's no way to figure out */ + return DEV_UNKNOWN; +} + +static enum dev_type __ibridge_get_width(u32 mtr) +{ + enum dev_type type; + + switch (mtr) { + case 3: + type = DEV_UNKNOWN; + break; + case 2: + type = DEV_X16; + break; + case 1: + type = DEV_X8; + break; + case 0: + type = DEV_X4; + break; + } + + return type; +} + +static enum dev_type ibridge_get_width(struct sbridge_pvt *pvt, u32 mtr) +{ + /* + * ddr3_width on the documentation but also valid for DDR4 on + * Haswell + */ + return __ibridge_get_width(GET_BITFIELD(mtr, 7, 8)); +} + +static enum dev_type broadwell_get_width(struct sbridge_pvt *pvt, u32 mtr) +{ + /* ddr3_width on the documentation but also valid for DDR4 */ + return __ibridge_get_width(GET_BITFIELD(mtr, 8, 9)); +} + static u8 get_node_id(struct sbridge_pvt *pvt) { u32 reg; @@ -972,17 +1016,7 @@ static int get_dimm_config(struct mem_ctl_info *mci) dimm->nr_pages = npages; dimm->grain = 32; - switch (banks) { - case 16: - dimm->dtype = DEV_X16; - break; - case 8: - dimm->dtype = DEV_X8; - break; - case 4: - dimm->dtype = DEV_X4; - break; - } + dimm->dtype = pvt->info.get_width(pvt, mtr); dimm->mtype = mtype; dimm->edac_mode = mode; snprintf(dimm->label, sizeof(dimm->label), @@ -2371,6 +2405,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.interleave_list = ibridge_interleave_list; pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); pvt->info.interleave_pkg = ibridge_interleave_pkg; + pvt->info.get_width = ibridge_get_width; mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx); /* Store pci devices at mci for faster access */ @@ -2390,6 +2425,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.interleave_list = sbridge_interleave_list; pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); pvt->info.interleave_pkg = sbridge_interleave_pkg; + pvt->info.get_width = sbridge_get_width; mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); /* Store pci devices at mci for faster access */ @@ -2409,6 +2445,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.interleave_list = ibridge_interleave_list; pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); pvt->info.interleave_pkg = ibridge_interleave_pkg; + pvt->info.get_width = ibridge_get_width; mci->ctl_name = kasprintf(GFP_KERNEL, "Haswell Socket#%d", mci->mc_idx); /* Store pci devices at mci for faster access */ @@ -2428,6 +2465,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) pvt->info.interleave_list = ibridge_interleave_list; pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); pvt->info.interleave_pkg = ibridge_interleave_pkg; + pvt->info.get_width = broadwell_get_width; mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx); /* Store pci devices at mci for faster access */ -- GitLab From d70e22d5bcf700a53881acad71a6c669be6eec93 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 16 Jul 2015 16:56:19 +0530 Subject: [PATCH 6805/7006] hexagon/time: Migrate to new 'set-state' interface Migrate hexagon driver to the new 'set-state' interface provided by clockevents core, the earlier 'set-mode' interface is marked obsolete now. This also enables us to implement callbacks for new states of clockevent devices, for example: ONESHOT_STOPPED. We weren't doing anything in the ->set_mode() callback. So, this patch doesn't provide any set-state callbacks. Cc: linux-hexagon@vger.kernel.org Signed-off-by: Viresh Kumar Signed-off-by: Richard Kuo --- arch/hexagon/kernel/time.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/arch/hexagon/kernel/time.c b/arch/hexagon/kernel/time.c index 17fbf45bf1502..a6a1d1f8309a4 100644 --- a/arch/hexagon/kernel/time.c +++ b/arch/hexagon/kernel/time.c @@ -97,20 +97,6 @@ static int set_next_event(unsigned long delta, struct clock_event_device *evt) return 0; } -/* - * Sets the mode (periodic, shutdown, oneshot, etc) of a timer. - */ -static void set_mode(enum clock_event_mode mode, - struct clock_event_device *evt) -{ - switch (mode) { - case CLOCK_EVT_MODE_SHUTDOWN: - /* XXX implement me */ - default: - break; - } -} - #ifdef CONFIG_SMP /* Broadcast mechanism */ static void broadcast(const struct cpumask *mask) @@ -119,13 +105,13 @@ static void broadcast(const struct cpumask *mask) } #endif +/* XXX Implement set_state_shutdown() */ static struct clock_event_device hexagon_clockevent_dev = { .name = "clockevent", .features = CLOCK_EVT_FEAT_ONESHOT, .rating = 400, .irq = RTOS_TIMER_INT, .set_next_event = set_next_event, - .set_mode = set_mode, #ifdef CONFIG_SMP .broadcast = broadcast, #endif @@ -146,7 +132,6 @@ void setup_percpu_clockdev(void) dummy_clock_dev->features = CLOCK_EVT_FEAT_DUMMY; dummy_clock_dev->cpumask = cpumask_of(cpu); - dummy_clock_dev->mode = CLOCK_EVT_MODE_UNUSED; clockevents_register_device(dummy_clock_dev); } -- GitLab From f33b77408a91d4427374010897b90af678dc47be Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 8 Sep 2015 19:06:03 +0200 Subject: [PATCH 6806/7006] staging: board: Migrate away from __pm_genpd_name_add_device() The named genpd APIs are deprecated. Hence convert the board staging code from using genpd names to DT node paths. For now this supports PM domains with "#power-domain-cells = <0>" only. Signed-off-by: Geert Uytterhoeven Reviewed-by: Ulf Hansson Acked-by: Greg Kroah-Hartman Signed-off-by: Rafael J. Wysocki --- drivers/staging/board/armadillo800eva.c | 2 +- drivers/staging/board/board.c | 36 ++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/drivers/staging/board/armadillo800eva.c b/drivers/staging/board/armadillo800eva.c index 81df77bd55cc9..9c41652ee908b 100644 --- a/drivers/staging/board/armadillo800eva.c +++ b/drivers/staging/board/armadillo800eva.c @@ -91,7 +91,7 @@ static const struct board_staging_dev armadillo800eva_devices[] __initconst = { .pdev = &lcdc0_device, .clocks = lcdc0_clocks, .nclocks = ARRAY_SIZE(lcdc0_clocks), - .domain = "a4lc", + .domain = "/system-controller@e6180000/pm-domains/c5/a4lc@1" }, }; diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c index 29d456e29f38f..3eb5eb8f069c2 100644 --- a/drivers/staging/board/board.c +++ b/drivers/staging/board/board.c @@ -135,6 +135,40 @@ int __init board_staging_register_clock(const struct board_staging_clk *bsc) return error; } +#ifdef CONFIG_PM_GENERIC_DOMAINS_OF +static int board_staging_add_dev_domain(struct platform_device *pdev, + const char *domain) +{ + struct of_phandle_args pd_args; + struct generic_pm_domain *pd; + struct device_node *np; + + np = of_find_node_by_path(domain); + if (!np) { + pr_err("Cannot find domain node %s\n", domain); + return -ENOENT; + } + + pd_args.np = np; + pd_args.args_count = 0; + pd = of_genpd_get_from_provider(&pd_args); + if (IS_ERR(pd)) { + pr_err("Cannot find genpd %s (%ld)\n", domain, PTR_ERR(pd)); + return PTR_ERR(pd); + + } + pr_debug("Found genpd %s for device %s\n", pd->name, pdev->name); + + return pm_genpd_add_device(pd, &pdev->dev); +} +#else +static inline int board_staging_add_dev_domain(struct platform_device *pdev, + const char *domain) +{ + return 0; +} +#endif + int __init board_staging_register_device(const struct board_staging_dev *dev) { struct platform_device *pdev = dev->pdev; @@ -161,7 +195,7 @@ int __init board_staging_register_device(const struct board_staging_dev *dev) } if (dev->domain) - __pm_genpd_name_add_device(dev->domain, &pdev->dev, NULL); + board_staging_add_dev_domain(pdev, dev->domain); return error; } -- GitLab From 4eafbd15b6c84cd3f6c76022c8a6c27f7cc076e1 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 8 Sep 2015 18:41:01 +0200 Subject: [PATCH 6807/7006] PM / OPP: add dev_pm_opp_get_suspend_opp() helper Add dev_pm_opp_get_suspend_opp() helper to obtain suspend opp. Acked-by: Viresh Kumar Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 30 ++++++++++++++++++++++++++++++ include/linux/pm_opp.h | 6 ++++++ 2 files changed, 36 insertions(+) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index bb703b5ebaff9..3df62dbcec3ad 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -340,6 +340,36 @@ unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) } EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); +/** + * dev_pm_opp_get_suspend_opp() - Get suspend opp + * @dev: device for which we do this operation + * + * Return: This function returns pointer to the suspend opp if it is + * defined, otherwise it returns NULL. + * + * Locking: This function must be called under rcu_read_lock(). opp is a rcu + * protected pointer. The reason for the same is that the opp pointer which is + * returned will remain valid for use with opp_get_{voltage, freq} only while + * under the locked area. The pointer returned must be used prior to unlocking + * with rcu_read_unlock() to maintain the integrity of the pointer. + */ +struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev) +{ + struct device_opp *dev_opp; + struct dev_pm_opp *opp; + + opp_rcu_lockdep_assert(); + + dev_opp = _find_device_opp(dev); + if (IS_ERR(dev_opp)) + opp = NULL; + else + opp = dev_opp->suspend_opp; + + return opp; +} +EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp); + /** * dev_pm_opp_get_opp_count() - Get number of opps available in the opp list * @dev: device for which we do this operation diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h index cab7ba55bedb8..e817722ee3f01 100644 --- a/include/linux/pm_opp.h +++ b/include/linux/pm_opp.h @@ -34,6 +34,7 @@ bool dev_pm_opp_is_turbo(struct dev_pm_opp *opp); int dev_pm_opp_get_opp_count(struct device *dev); unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev); +struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev); struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, @@ -80,6 +81,11 @@ static inline unsigned long dev_pm_opp_get_max_clock_latency(struct device *dev) return 0; } +static inline struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev) +{ + return NULL; +} + static inline struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev, unsigned long freq, bool available) { -- GitLab From 201f3716575781b83259ed026845a213c2355035 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 8 Sep 2015 18:41:02 +0200 Subject: [PATCH 6808/7006] cpufreq: allow cpufreq_generic_suspend() to work without suspend frequency Some cpufreq drivers may set suspend frequency only for selected setups but still would like to use the generic suspend handler. Thus don't treat !policy->suspend_freq condition as an incorrect one. Acked-by: Viresh Kumar Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 8b6bf38b2497b..ca963336c262f 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1628,8 +1628,8 @@ int cpufreq_generic_suspend(struct cpufreq_policy *policy) int ret; if (!policy->suspend_freq) { - pr_err("%s: suspend_freq can't be zero\n", __func__); - return -EINVAL; + pr_debug("%s: suspend_freq not defined\n", __func__); + return 0; } pr_debug("%s: Setting suspend-freq: %u\n", __func__, -- GitLab From 953ba9ff77f3d08635712eaeffb218d46889b58a Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 8 Sep 2015 18:41:03 +0200 Subject: [PATCH 6809/7006] cpufreq-dt: add suspend frequency support Add suspend frequency support and if needed set it to the frequency obtained from the suspend opp (can be defined using opp-v2 bindings and is optional). Acked-by: Viresh Kumar Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/cpufreq-dt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c index 3b64c203bf99a..7c0d70e2a8616 100644 --- a/drivers/cpufreq/cpufreq-dt.c +++ b/drivers/cpufreq/cpufreq-dt.c @@ -196,6 +196,7 @@ static int cpufreq_init(struct cpufreq_policy *policy) struct device *cpu_dev; struct regulator *cpu_reg; struct clk *cpu_clk; + struct dev_pm_opp *suspend_opp; unsigned long min_uV = ~0, max_uV = 0; unsigned int transition_latency; bool need_update = false; @@ -333,6 +334,13 @@ static int cpufreq_init(struct cpufreq_policy *policy) policy->driver_data = priv; policy->clk = cpu_clk; + + rcu_read_lock(); + suspend_opp = dev_pm_opp_get_suspend_opp(cpu_dev); + if (suspend_opp) + policy->suspend_freq = dev_pm_opp_get_freq(suspend_opp) / 1000; + rcu_read_unlock(); + ret = cpufreq_table_validate_and_show(policy, freq_table); if (ret) { dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__, @@ -423,6 +431,7 @@ static struct cpufreq_driver dt_cpufreq_driver = { .ready = cpufreq_ready, .name = "cpufreq-dt", .attr = cpufreq_dt_attr, + .suspend = cpufreq_generic_suspend, }; static int dt_cpufreq_probe(struct platform_device *pdev) -- GitLab From 39797a279d62972cd914ef580fdfacb13e508bf8 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Sat, 5 Sep 2015 13:07:27 -0700 Subject: [PATCH 6810/7006] net: dsa: bcm_sf2: Fix ageing conditions and operation The comparison check between cur_hw_state and hw_state is currently invalid because cur_hw_state is right shifted by G_MISTP_SHIFT, while hw_state is not, so we end-up comparing bits 2:0 with bits 7:5, which is going to cause an additional aging to occur. Fix this by not shifting cur_hw_state while reading it, but instead, mask the value with the appropriately shitfted bitmask. The other problem with the fast-ageing process is that we did not set the EN_AGE_DYNAMIC bit to request the ageing to occur for dynamically learned MAC addresses. Finally, write back 0 to the FAST_AGE_CTRL register to avoid leaving spurious bits sets from one operation to the other. Fixes: 12f460f23423 ("net: dsa: bcm_sf2: add HW bridging support") Signed-off-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 289e20443d83a..9d56515f4c4da 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -418,7 +418,7 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) core_writel(priv, port, CORE_FAST_AGE_PORT); reg = core_readl(priv, CORE_FAST_AGE_CTRL); - reg |= EN_AGE_PORT | FAST_AGE_STR_DONE; + reg |= EN_AGE_PORT | EN_AGE_DYNAMIC | FAST_AGE_STR_DONE; core_writel(priv, reg, CORE_FAST_AGE_CTRL); do { @@ -432,6 +432,8 @@ static int bcm_sf2_sw_fast_age_port(struct dsa_switch *ds, int port) if (!timeout) return -ETIMEDOUT; + core_writel(priv, 0, CORE_FAST_AGE_CTRL); + return 0; } @@ -507,7 +509,7 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, u32 reg; reg = core_readl(priv, CORE_G_PCTL_PORT(port)); - cur_hw_state = reg >> G_MISTP_STATE_SHIFT; + cur_hw_state = reg & (G_MISTP_STATE_MASK << G_MISTP_STATE_SHIFT); switch (state) { case BR_STATE_DISABLED: @@ -531,10 +533,12 @@ static int bcm_sf2_sw_br_set_stp_state(struct dsa_switch *ds, int port, } /* Fast-age ARL entries if we are moving a port from Learning or - * Forwarding state to Disabled, Blocking or Listening state + * Forwarding (cur_hw_state) state to Disabled, Blocking or Listening + * state (hw_state) */ if (cur_hw_state != hw_state) { - if (cur_hw_state & 4 && !(hw_state & 4)) { + if (cur_hw_state >= G_MISTP_LEARN_STATE && + hw_state <= G_MISTP_LISTEN_STATE) { ret = bcm_sf2_sw_fast_age_port(ds, port); if (ret) { pr_err("%s: fast-ageing failed\n", __func__); -- GitLab From bf361ad38165939049a2649b1a0078f3268d4bd1 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Sat, 5 Sep 2015 21:27:57 -0400 Subject: [PATCH 6811/7006] net: bridge: check __vlan_vid_del for error Since __vlan_del can return an error code, change its inner function __vlan_vid_del to return an eventual error from switchdev_port_obj_del. Signed-off-by: Vivien Didelot Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/bridge/br_vlan.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 3cd8cc9e804b3..5f5a02b49a996 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c @@ -117,10 +117,11 @@ out_filt: return err; } -static void __vlan_vid_del(struct net_device *dev, struct net_bridge *br, - u16 vid) +static int __vlan_vid_del(struct net_device *dev, struct net_bridge *br, + u16 vid) { const struct net_device_ops *ops = dev->netdev_ops; + int err = 0; /* If driver uses VLAN ndo ops, use 8021q to delete vid * on device, otherwise try switchdev ops to delete vid. @@ -137,8 +138,12 @@ static void __vlan_vid_del(struct net_device *dev, struct net_bridge *br, }, }; - switchdev_port_obj_del(dev, &vlan_obj); + err = switchdev_port_obj_del(dev, &vlan_obj); + if (err == -EOPNOTSUPP) + err = 0; } + + return err; } static int __vlan_del(struct net_port_vlans *v, u16 vid) @@ -151,7 +156,11 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid) if (v->port_idx) { struct net_bridge_port *p = v->parent.port; - __vlan_vid_del(p->dev, p->br, vid); + int err; + + err = __vlan_vid_del(p->dev, p->br, vid); + if (err) + return err; } clear_bit(vid, v->vlan_bitmap); -- GitLab From 7a577f013d6745c800a11a2911ddc9a3214e7f09 Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Sat, 5 Sep 2015 21:49:41 -0400 Subject: [PATCH 6812/7006] net: bridge: remove unnecessary switchdev include Remove the unnecessary switchdev.h include from br_netlink.c. Signed-off-by: Vivien Didelot Acked-by: Jiri Pirko Signed-off-by: David S. Miller --- net/bridge/br_netlink.c | 1 - 1 file changed, 1 deletion(-) diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index af5e187553fd6..ea748c93a07f1 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include "br_private.h" -- GitLab From 7b9018738e43c7c7693632174c69fde83b8edc07 Mon Sep 17 00:00:00 2001 From: Barry Song Date: Mon, 7 Sep 2015 03:15:20 +0000 Subject: [PATCH 6813/7006] dm9000: fix a typo Signed-off-by: Barry Song Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index c0a7813603c3d..cf94b72dbacd9 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -1226,7 +1226,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id) if (int_status & ISR_PRS) dm9000_rx(dev); - /* Trnasmit Interrupt check */ + /* Transmit Interrupt check */ if (int_status & ISR_PTS) dm9000_tx_done(dev, db); -- GitLab From 7845989cb4b3da1db903918c844fccb9817d34a0 Mon Sep 17 00:00:00 2001 From: Kolmakov Dmitriy Date: Mon, 7 Sep 2015 09:05:48 +0000 Subject: [PATCH 6814/7006] net: tipc: fix stall during bclink wakeup procedure If an attempt to wake up users of broadcast link is made when there is no enough place in send queue than it may hang up inside the tipc_sk_rcv() function since the loop breaks only after the wake up queue becomes empty. This can lead to complete CPU stall with the following message generated by RCU: INFO: rcu_sched self-detected stall on CPU { 0} (t=2101 jiffies g=54225 c=54224 q=11465) Task dump for CPU 0: tpch R running task 0 39949 39948 0x0000000a ffffffff818536c0 ffff88181fa037a0 ffffffff8106a4be 0000000000000000 ffffffff818536c0 ffff88181fa037c0 ffffffff8106d8a8 ffff88181fa03800 0000000000000001 ffff88181fa037f0 ffffffff81094a50 ffff88181fa15680 Call Trace: [] sched_show_task+0xae/0x120 [] dump_cpu_task+0x38/0x40 [] rcu_dump_cpu_stacks+0x90/0xd0 [] rcu_check_callbacks+0x3eb/0x6e0 [] ? account_system_time+0x7f/0x170 [] update_process_times+0x34/0x60 [] tick_sched_handle.isra.18+0x31/0x40 [] tick_sched_timer+0x3c/0x70 [] __run_hrtimer.isra.34+0x3d/0xc0 [] hrtimer_interrupt+0xc5/0x1e0 [] ? native_smp_send_reschedule+0x42/0x60 [] local_apic_timer_interrupt+0x34/0x60 [] smp_apic_timer_interrupt+0x3c/0x60 [] apic_timer_interrupt+0x6b/0x70 [] ? _raw_spin_unlock_irqrestore+0x9/0x10 [] __wake_up_sync_key+0x4f/0x60 [] tipc_write_space+0x31/0x40 [tipc] [] filter_rcv+0x31f/0x520 [tipc] [] ? tipc_sk_lookup+0xc9/0x110 [tipc] [] ? _raw_spin_lock_bh+0x19/0x30 [] tipc_sk_rcv+0x2dc/0x3e0 [tipc] [] tipc_bclink_wakeup_users+0x2f/0x40 [tipc] [] tipc_node_unlock+0x186/0x190 [tipc] [] ? kfree_skb+0x2c/0x40 [] tipc_rcv+0x2ac/0x8c0 [tipc] [] tipc_l2_rcv_msg+0x38/0x50 [tipc] [] __netif_receive_skb_core+0x5a3/0x950 [] __netif_receive_skb+0x13/0x60 [] netif_receive_skb_internal+0x1e/0x90 [] napi_gro_receive+0x78/0xa0 [] tg3_poll_work+0xc54/0xf40 [tg3] [] ? consume_skb+0x2c/0x40 [] tg3_poll_msix+0x41/0x160 [tg3] [] net_rx_action+0xe2/0x290 [] __do_softirq+0xda/0x1f0 [] irq_exit+0x76/0xa0 [] do_IRQ+0x55/0xf0 [] common_interrupt+0x6b/0x6b The issue occurs only when tipc_sk_rcv() is used to wake up postponed senders: tipc_bclink_wakeup_users() // wakeupq - is a queue which consists of special // messages with SOCK_WAKEUP type. tipc_sk_rcv(wakeupq) ... while (skb_queue_len(inputq)) { filter_rcv(skb) // Here the type of message is checked // and if it is SOCK_WAKEUP then // it tries to wake up a sender. tipc_write_space(sk) wake_up_interruptible_sync_poll() } After the sender thread is woke up it can gather control and perform an attempt to send a message. But if there is no enough place in send queue it will call link_schedule_user() function which puts a message of type SOCK_WAKEUP to the wakeup queue and put the sender to sleep. Thus the size of the queue actually is not changed and the while() loop never exits. The approach I proposed is to wake up only senders for which there is enough place in send queue so the described issue can't occur. Moreover the same approach is already used to wake up senders on unicast links. I have got into the issue on our product code but to reproduce the issue I changed a benchmark test application (from tipcutils/demos/benchmark) to perform the following scenario: 1. Run 64 instances of test application (nodes). It can be done on the one physical machine. 2. Each application connects to all other using TIPC sockets in RDM mode. 3. When setup is done all nodes start simultaneously send broadcast messages. 4. Everything hangs up. The issue is reproducible only when a congestion on broadcast link occurs. For example, when there are only 8 nodes it works fine since congestion doesn't occur. Send queue limit is 40 in my case (I use a critical importance level) and when 64 nodes send a message at the same moment a congestion occurs every time. Signed-off-by: Dmitry S Kolmakov Reviewed-by: Jon Maloy Acked-by: Ying Xue Signed-off-by: David S. Miller --- net/tipc/bcast.c | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index 8b010c976b2f7..41042de3ae9bc 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c @@ -169,6 +169,30 @@ static void bclink_retransmit_pkt(struct tipc_net *tn, u32 after, u32 to) } } +/** + * bclink_prepare_wakeup - prepare users for wakeup after congestion + * @bcl: broadcast link + * @resultq: queue for users which can be woken up + * Move a number of waiting users, as permitted by available space in + * the send queue, from link wait queue to specified queue for wakeup + */ +static void bclink_prepare_wakeup(struct tipc_link *bcl, struct sk_buff_head *resultq) +{ + int pnd[TIPC_SYSTEM_IMPORTANCE + 1] = {0,}; + int imp, lim; + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&bcl->wakeupq, skb, tmp) { + imp = TIPC_SKB_CB(skb)->chain_imp; + lim = bcl->window + bcl->backlog[imp].limit; + pnd[imp] += TIPC_SKB_CB(skb)->chain_sz; + if ((pnd[imp] + bcl->backlog[imp].len) >= lim) + continue; + skb_unlink(skb, &bcl->wakeupq); + skb_queue_tail(resultq, skb); + } +} + /** * tipc_bclink_wakeup_users - wake up pending users * @@ -177,8 +201,12 @@ static void bclink_retransmit_pkt(struct tipc_net *tn, u32 after, u32 to) void tipc_bclink_wakeup_users(struct net *net) { struct tipc_net *tn = net_generic(net, tipc_net_id); + struct tipc_link *bcl = tn->bcl; + struct sk_buff_head resultq; - tipc_sk_rcv(net, &tn->bclink->link.wakeupq); + skb_queue_head_init(&resultq); + bclink_prepare_wakeup(bcl, &resultq); + tipc_sk_rcv(net, &resultq); } /** -- GitLab From d15f9d694b77fe5e4ea12b3031ecaa13b5aa2b10 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Wed, 2 Sep 2015 11:37:09 +0300 Subject: [PATCH 6815/7006] libceph: check data_len in ->alloc_msg() Only ->alloc_msg() should check data_len of the incoming message against the preallocated ceph_msg, doing it in the messenger is not right. The contract is that either ->alloc_msg() returns a ceph_msg which will fit all of the portions of the incoming message, or it returns NULL and possibly sets skip, signaling whether NULL is due to an -ENOMEM. ->alloc_msg() should be the only place where we make the skip/no-skip decision. I stumbled upon this while looking at con/osd ref counting. Right now, if we get a non-extent message with a larger data portion than we are prepared for, ->alloc_msg() returns a ceph_msg, and then, when we skip it in the messenger, we don't put the con/osd ref acquired in ceph_con_in_msg_alloc() (which is normally put in process_message()), so this also fixes a memory leak. An existing BUG_ON in ceph_msg_data_cursor_init() ensures we don't corrupt random memory should a buggy ->alloc_msg() return an unfit ceph_msg. While at it, I changed the "unknown tid" dout() to a pr_warn() to make sure all skips are seen and unified format strings. Signed-off-by: Ilya Dryomov Reviewed-by: Alex Elder --- net/ceph/messenger.c | 7 ------ net/ceph/osd_client.c | 51 +++++++++++++++---------------------------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c index 36757d46ac406..525f454f75318 100644 --- a/net/ceph/messenger.c +++ b/net/ceph/messenger.c @@ -2337,13 +2337,6 @@ static int read_partial_message(struct ceph_connection *con) return ret; BUG_ON(!con->in_msg ^ skip); - if (con->in_msg && data_len > con->in_msg->data_length) { - pr_warn("%s skipping long message (%u > %zd)\n", - __func__, data_len, con->in_msg->data_length); - ceph_msg_put(con->in_msg); - con->in_msg = NULL; - skip = 1; - } if (skip) { /* skip this message */ dout("alloc_msg said skip message\n"); diff --git a/net/ceph/osd_client.c b/net/ceph/osd_client.c index 50033677c0fa5..80b94e37c94aa 100644 --- a/net/ceph/osd_client.c +++ b/net/ceph/osd_client.c @@ -2817,8 +2817,9 @@ out: } /* - * lookup and return message for incoming reply. set up reply message - * pages. + * Lookup and return message for incoming reply. Don't try to do + * anything about a larger than preallocated data portion of the + * message at the moment - for now, just skip the message. */ static struct ceph_msg *get_reply(struct ceph_connection *con, struct ceph_msg_header *hdr, @@ -2836,10 +2837,10 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, mutex_lock(&osdc->request_mutex); req = __lookup_request(osdc, tid); if (!req) { - *skip = 1; + pr_warn("%s osd%d tid %llu unknown, skipping\n", + __func__, osd->o_osd, tid); m = NULL; - dout("get_reply unknown tid %llu from osd%d\n", tid, - osd->o_osd); + *skip = 1; goto out; } @@ -2849,10 +2850,9 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, ceph_msg_revoke_incoming(req->r_reply); if (front_len > req->r_reply->front_alloc_len) { - pr_warn("get_reply front %d > preallocated %d (%u#%llu)\n", - front_len, req->r_reply->front_alloc_len, - (unsigned int)con->peer_name.type, - le64_to_cpu(con->peer_name.num)); + pr_warn("%s osd%d tid %llu front %d > preallocated %d\n", + __func__, osd->o_osd, req->r_tid, front_len, + req->r_reply->front_alloc_len); m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front_len, GFP_NOFS, false); if (!m) @@ -2860,37 +2860,22 @@ static struct ceph_msg *get_reply(struct ceph_connection *con, ceph_msg_put(req->r_reply); req->r_reply = m; } - m = ceph_msg_get(req->r_reply); - - if (data_len > 0) { - struct ceph_osd_data *osd_data; - /* - * XXX This is assuming there is only one op containing - * XXX page data. Probably OK for reads, but this - * XXX ought to be done more generally. - */ - osd_data = osd_req_op_extent_osd_data(req, 0); - if (osd_data->type == CEPH_OSD_DATA_TYPE_PAGES) { - if (osd_data->pages && - unlikely(osd_data->length < data_len)) { - - pr_warn("tid %lld reply has %d bytes we had only %llu bytes ready\n", - tid, data_len, osd_data->length); - *skip = 1; - ceph_msg_put(m); - m = NULL; - goto out; - } - } + if (data_len > req->r_reply->data_length) { + pr_warn("%s osd%d tid %llu data %d > preallocated %zu, skipping\n", + __func__, osd->o_osd, req->r_tid, data_len, + req->r_reply->data_length); + m = NULL; + *skip = 1; + goto out; } - *skip = 0; + + m = ceph_msg_get(req->r_reply); dout("get_reply tid %lld %p\n", tid, m); out: mutex_unlock(&osdc->request_mutex); return m; - } static struct ceph_msg *alloc_msg(struct ceph_connection *con, -- GitLab From 55b0b31cbc09f80db384671e22cdc94b2aa26b29 Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 7 Sep 2015 11:35:01 +0800 Subject: [PATCH 6816/7006] ceph: get inode size for each append write Signed-off-by: Yan, Zheng --- fs/ceph/file.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 90ec110b8400c..0c62868b5c561 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c @@ -952,6 +952,12 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) /* We can write back this queue in page reclaim */ current->backing_dev_info = inode_to_bdi(inode); + if (iocb->ki_flags & IOCB_APPEND) { + err = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE, false); + if (err < 0) + goto out; + } + err = generic_write_checks(iocb, from); if (err <= 0) goto out; -- GitLab From 438386853d4c0c48fe73bf05a7d61c70ca5a3bfb Mon Sep 17 00:00:00 2001 From: "Yan, Zheng" Date: Mon, 7 Sep 2015 15:46:24 +0800 Subject: [PATCH 6817/7006] ceph: improve readahead for file holes When readahead encounters file holes, osd reply returns error -ENOENT, finish_read() skips adding pages to the the page cache. So readahead does not work for file holes. The fix is adding zero pages to the page cache when -ENOENT is returned. Signed-off-by: Yan, Zheng --- fs/ceph/addr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 98933350331c4..6471e28e0586b 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -276,7 +276,7 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) for (i = 0; i < num_pages; i++) { struct page *page = osd_data->pages[i]; - if (rc < 0) + if (rc < 0 && rc != ENOENT) goto unlock; if (bytes < (int)PAGE_CACHE_SIZE) { /* zero (remainder of) page */ -- GitLab From acd29f7b22262d9e848393b9b6ae13eb42d22514 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Tue, 8 Sep 2015 14:17:13 +0100 Subject: [PATCH 6818/7006] drm/i915: Limit the number of loops for reading a split 64bit register MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In I915_READ64_2x32 we attempt to read a 64bit register using 2 32bit reads. Due to the nature of the registers we try to read in this manner, they may increment between the two instruction (e.g. a timestamp counter). To keep the result accurate, we repeat the read if we detect an overflow (i.e. the upper value varies). However, some hardware is just plain flaky and may endless loop as the the upper 32bits are not stable. Just give up after a couple of tries and report whatever we read last. v2: Use the most recent values when erring out on an unstable register. Reported-by: russianneuromancer@ya.ru Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91906 Signed-off-by: Chris Wilson Cc: Michał Winiarski Cc: Daniel Vetter Cc: Jani Nikula Cc: stable@vger.kernel.org Reviewed-by: Daniel Vetter Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index e304d4e5ae0c9..522da7b12a882 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3383,13 +3383,13 @@ int intel_freq_opcode(struct drm_i915_private *dev_priv, int val); #define I915_READ64(reg) dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true) #define I915_READ64_2x32(lower_reg, upper_reg) ({ \ - u32 upper, lower, tmp; \ - tmp = I915_READ(upper_reg); \ + u32 upper, lower, old_upper, loop = 0; \ + upper = I915_READ(upper_reg); \ do { \ - upper = tmp; \ + old_upper = upper; \ lower = I915_READ(lower_reg); \ - tmp = I915_READ(upper_reg); \ - } while (upper != tmp); \ + upper = I915_READ(upper_reg); \ + } while (upper != old_upper && loop++ < 2); \ (u64)upper << 32 | lower; }) #define POSTING_READ(reg) (void)I915_READ_NOTRACE(reg) -- GitLab From 841e6f90bb789a1372087b22c39f3a9ef2e02758 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Wed, 5 Aug 2015 23:31:46 -0300 Subject: [PATCH 6819/7006] pwm: NXP LPC18xx PWM/SCT driver This commit adds support for NXP LPC18xx PWM/SCT. NXP LPC SoCs family, which includes LPC18xx/LPC43xx, provides a State Configurable Timer (SCT) which can be configured as a Pulse Width Modulator. Other SoCs in that family may share the same hardware. The PWM supports a total of 16 channels, but only 15 can be simultaneously requested. There's only one period, global to all the channels, thus PWM driver will refuse setting different values to it, unless there's only one channel requested. Signed-off-by: Ariel D'Alessandro [thierry.reding@gmail.com: remove excessive padding of fields] Signed-off-by: Thierry Reding --- drivers/pwm/Kconfig | 12 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-lpc18xx-sct.c | 465 ++++++++++++++++++++++++++++++++++ 3 files changed, 478 insertions(+) create mode 100644 drivers/pwm/pwm-lpc18xx-sct.c diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index b1541f40fd8d1..ac8b0e968b6b6 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -173,6 +173,18 @@ config PWM_LP3943 To compile this driver as a module, choose M here: the module will be called pwm-lp3943. +config PWM_LPC18XX_SCT + tristate "LPC18xx/43xx PWM/SCT support" + depends on ARCH_LPC18XX + help + Generic PWM framework driver for NXP LPC18xx PWM/SCT which + supports 16 channels. + A maximum of 15 channels can be requested simultaneously and + must have the same period. + + To compile this driver as a module, choose M here: the module + will be called pwm-lpc18xx-sct. + config PWM_LPC32XX tristate "LPC32XX PWM support" depends on ARCH_LPC32XX diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index ec50eb5b5a8fd..cd9abef2d5b12 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_PWM_IMG) += pwm-img.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o +obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o diff --git a/drivers/pwm/pwm-lpc18xx-sct.c b/drivers/pwm/pwm-lpc18xx-sct.c new file mode 100644 index 0000000000000..9163085101bc9 --- /dev/null +++ b/drivers/pwm/pwm-lpc18xx-sct.c @@ -0,0 +1,465 @@ +/* + * NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver + * + * Copyright (c) 2015 Ariel D'Alessandro + * + * 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. + * + * Notes + * ===== + * NXP LPC18xx provides a State Configurable Timer (SCT) which can be configured + * as a Pulse Width Modulator. + * + * SCT supports 16 outputs, 16 events and 16 registers. Each event will be + * triggered when its related register matches the SCT counter value, and it + * will set or clear a selected output. + * + * One of the events is preselected to generate the period, thus the maximum + * number of simultaneous channels is limited to 15. Notice that period is + * global to all the channels, thus PWM driver will refuse setting different + * values to it, unless there's only one channel requested. + */ + +#include +#include +#include +#include +#include +#include + +/* LPC18xx SCT registers */ +#define LPC18XX_PWM_CONFIG 0x000 +#define LPC18XX_PWM_CONFIG_UNIFY BIT(0) +#define LPC18XX_PWM_CONFIG_NORELOAD BIT(7) + +#define LPC18XX_PWM_CTRL 0x004 +#define LPC18XX_PWM_CTRL_HALT BIT(2) +#define LPC18XX_PWM_BIDIR BIT(4) +#define LPC18XX_PWM_PRE_SHIFT 5 +#define LPC18XX_PWM_PRE_MASK (0xff << LPC18XX_PWM_PRE_SHIFT) +#define LPC18XX_PWM_PRE(x) (x << LPC18XX_PWM_PRE_SHIFT) + +#define LPC18XX_PWM_LIMIT 0x008 + +#define LPC18XX_PWM_RES_BASE 0x058 +#define LPC18XX_PWM_RES_SHIFT(_ch) (_ch * 2) +#define LPC18XX_PWM_RES(_ch, _action) (_action << LPC18XX_PWM_RES_SHIFT(_ch)) +#define LPC18XX_PWM_RES_MASK(_ch) (0x3 << LPC18XX_PWM_RES_SHIFT(_ch)) + +#define LPC18XX_PWM_MATCH_BASE 0x100 +#define LPC18XX_PWM_MATCH(_ch) (LPC18XX_PWM_MATCH_BASE + _ch * 4) + +#define LPC18XX_PWM_MATCHREL_BASE 0x200 +#define LPC18XX_PWM_MATCHREL(_ch) (LPC18XX_PWM_MATCHREL_BASE + _ch * 4) + +#define LPC18XX_PWM_EVSTATEMSK_BASE 0x300 +#define LPC18XX_PWM_EVSTATEMSK(_ch) (LPC18XX_PWM_EVSTATEMSK_BASE + _ch * 8) +#define LPC18XX_PWM_EVSTATEMSK_ALL 0xffffffff + +#define LPC18XX_PWM_EVCTRL_BASE 0x304 +#define LPC18XX_PWM_EVCTRL(_ev) (LPC18XX_PWM_EVCTRL_BASE + _ev * 8) + +#define LPC18XX_PWM_EVCTRL_MATCH(_ch) _ch + +#define LPC18XX_PWM_EVCTRL_COMB_SHIFT 12 +#define LPC18XX_PWM_EVCTRL_COMB_MATCH (0x1 << LPC18XX_PWM_EVCTRL_COMB_SHIFT) + +#define LPC18XX_PWM_OUTPUTSET_BASE 0x500 +#define LPC18XX_PWM_OUTPUTSET(_ch) (LPC18XX_PWM_OUTPUTSET_BASE + _ch * 8) + +#define LPC18XX_PWM_OUTPUTCL_BASE 0x504 +#define LPC18XX_PWM_OUTPUTCL(_ch) (LPC18XX_PWM_OUTPUTCL_BASE + _ch * 8) + +/* LPC18xx SCT unified counter */ +#define LPC18XX_PWM_TIMER_MAX 0xffffffff + +/* LPC18xx SCT events */ +#define LPC18XX_PWM_EVENT_PERIOD 0 +#define LPC18XX_PWM_EVENT_MAX 16 + +/* SCT conflict resolution */ +enum lpc18xx_pwm_res_action { + LPC18XX_PWM_RES_NONE, + LPC18XX_PWM_RES_SET, + LPC18XX_PWM_RES_CLEAR, + LPC18XX_PWM_RES_TOGGLE, +}; + +struct lpc18xx_pwm_data { + unsigned int duty_event; +}; + +struct lpc18xx_pwm_chip { + struct device *dev; + struct pwm_chip chip; + void __iomem *base; + struct clk *pwm_clk; + unsigned long clk_rate; + unsigned int period_ns; + unsigned int min_period_ns; + unsigned int max_period_ns; + unsigned int period_event; + unsigned long event_map; + struct mutex res_lock; + struct mutex period_lock; +}; + +static inline struct lpc18xx_pwm_chip * +to_lpc18xx_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct lpc18xx_pwm_chip, chip); +} + +static inline void lpc18xx_pwm_writel(struct lpc18xx_pwm_chip *lpc18xx_pwm, + u32 reg, u32 val) +{ + writel(val, lpc18xx_pwm->base + reg); +} + +static inline u32 lpc18xx_pwm_readl(struct lpc18xx_pwm_chip *lpc18xx_pwm, + u32 reg) +{ + return readl(lpc18xx_pwm->base + reg); +} + +static void lpc18xx_pwm_set_conflict_res(struct lpc18xx_pwm_chip *lpc18xx_pwm, + struct pwm_device *pwm, + enum lpc18xx_pwm_res_action action) +{ + u32 val; + + mutex_lock(&lpc18xx_pwm->res_lock); + + /* + * Simultaneous set and clear may happen on an output, that is the case + * when duty_ns == period_ns. LPC18xx SCT allows to set a conflict + * resolution action to be taken in such a case. + */ + val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_RES_BASE); + val &= ~LPC18XX_PWM_RES_MASK(pwm->hwpwm); + val |= LPC18XX_PWM_RES(pwm->hwpwm, action); + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_RES_BASE, val); + + mutex_unlock(&lpc18xx_pwm->res_lock); +} + +static void lpc18xx_pwm_config_period(struct pwm_chip *chip, int period_ns) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + u64 val; + + val = (u64)period_ns * lpc18xx_pwm->clk_rate; + do_div(val, NSEC_PER_SEC); + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_MATCH(lpc18xx_pwm->period_event), + (u32)val - 1); + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_MATCHREL(lpc18xx_pwm->period_event), + (u32)val - 1); +} + +static void lpc18xx_pwm_config_duty(struct pwm_chip *chip, + struct pwm_device *pwm, int duty_ns) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + u64 val; + + val = (u64)duty_ns * lpc18xx_pwm->clk_rate; + do_div(val, NSEC_PER_SEC); + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_MATCH(lpc18xx_data->duty_event), + (u32)val); + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_MATCHREL(lpc18xx_data->duty_event), + (u32)val); +} + +static int lpc18xx_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + int requested_events, i; + + if (period_ns < lpc18xx_pwm->min_period_ns || + period_ns > lpc18xx_pwm->max_period_ns) { + dev_err(chip->dev, "period %d not in range\n", period_ns); + return -ERANGE; + } + + mutex_lock(&lpc18xx_pwm->period_lock); + + requested_events = bitmap_weight(&lpc18xx_pwm->event_map, + LPC18XX_PWM_EVENT_MAX); + + /* + * The PWM supports only a single period for all PWM channels. + * Once the period is set, it can only be changed if no more than one + * channel is requested at that moment. + */ + if (requested_events > 2 && lpc18xx_pwm->period_ns != period_ns && + lpc18xx_pwm->period_ns) { + dev_err(chip->dev, "conflicting period requested for PWM %u\n", + pwm->hwpwm); + mutex_unlock(&lpc18xx_pwm->period_lock); + return -EBUSY; + } + + if ((requested_events <= 2 && lpc18xx_pwm->period_ns != period_ns) || + !lpc18xx_pwm->period_ns) { + lpc18xx_pwm->period_ns = period_ns; + for (i = 0; i < chip->npwm; i++) + pwm_set_period(&chip->pwms[i], period_ns); + lpc18xx_pwm_config_period(chip, period_ns); + } + + mutex_unlock(&lpc18xx_pwm->period_lock); + + lpc18xx_pwm_config_duty(chip, pwm, duty_ns); + + return 0; +} + +static int lpc18xx_pwm_set_polarity(struct pwm_chip *chip, + struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + return 0; +} + +static int lpc18xx_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + enum lpc18xx_pwm_res_action res_action; + unsigned int set_event, clear_event; + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), + LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_data->duty_event) | + LPC18XX_PWM_EVCTRL_COMB_MATCH); + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_EVSTATEMSK(lpc18xx_data->duty_event), + LPC18XX_PWM_EVSTATEMSK_ALL); + + if (pwm->polarity == PWM_POLARITY_NORMAL) { + set_event = lpc18xx_pwm->period_event; + clear_event = lpc18xx_data->duty_event; + res_action = LPC18XX_PWM_RES_SET; + } else { + set_event = lpc18xx_data->duty_event; + clear_event = lpc18xx_pwm->period_event; + res_action = LPC18XX_PWM_RES_CLEAR; + } + + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), + BIT(set_event)); + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), + BIT(clear_event)); + lpc18xx_pwm_set_conflict_res(lpc18xx_pwm, pwm, res_action); + + return 0; +} + +static void lpc18xx_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_EVCTRL(lpc18xx_data->duty_event), 0); + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTSET(pwm->hwpwm), 0); + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_OUTPUTCL(pwm->hwpwm), 0); +} + +static int lpc18xx_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + unsigned long event; + + event = find_first_zero_bit(&lpc18xx_pwm->event_map, + LPC18XX_PWM_EVENT_MAX); + + if (event >= LPC18XX_PWM_EVENT_MAX) { + dev_err(lpc18xx_pwm->dev, + "maximum number of simultaneous channels reached\n"); + return -EBUSY; + }; + + set_bit(event, &lpc18xx_pwm->event_map); + lpc18xx_data->duty_event = event; + lpc18xx_pwm_config_duty(chip, pwm, pwm_get_duty_cycle(pwm)); + + return 0; +} + +static void lpc18xx_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = to_lpc18xx_pwm_chip(chip); + struct lpc18xx_pwm_data *lpc18xx_data = pwm_get_chip_data(pwm); + + pwm_disable(pwm); + pwm_set_duty_cycle(pwm, 0); + clear_bit(lpc18xx_data->duty_event, &lpc18xx_pwm->event_map); +} + +static const struct pwm_ops lpc18xx_pwm_ops = { + .config = lpc18xx_pwm_config, + .set_polarity = lpc18xx_pwm_set_polarity, + .enable = lpc18xx_pwm_enable, + .disable = lpc18xx_pwm_disable, + .request = lpc18xx_pwm_request, + .free = lpc18xx_pwm_free, + .owner = THIS_MODULE, +}; + +static const struct of_device_id lpc18xx_pwm_of_match[] = { + { .compatible = "nxp,lpc1850-sct-pwm" }, + {} +}; +MODULE_DEVICE_TABLE(of, lpc18xx_pwm_of_match); + +static int lpc18xx_pwm_probe(struct platform_device *pdev) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm; + struct pwm_device *pwm; + struct resource *res; + int ret, i; + u64 val; + + lpc18xx_pwm = devm_kzalloc(&pdev->dev, sizeof(*lpc18xx_pwm), + GFP_KERNEL); + if (!lpc18xx_pwm) + return -ENOMEM; + + lpc18xx_pwm->dev = &pdev->dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lpc18xx_pwm->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(lpc18xx_pwm->base)) + return PTR_ERR(lpc18xx_pwm->base); + + lpc18xx_pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm"); + if (IS_ERR(lpc18xx_pwm->pwm_clk)) { + dev_err(&pdev->dev, "failed to get pwm clock\n"); + return PTR_ERR(lpc18xx_pwm->pwm_clk); + } + + ret = clk_prepare_enable(lpc18xx_pwm->pwm_clk); + if (ret < 0) { + dev_err(&pdev->dev, "could not prepare or enable pwm clock\n"); + return ret; + } + + lpc18xx_pwm->clk_rate = clk_get_rate(lpc18xx_pwm->pwm_clk); + + mutex_init(&lpc18xx_pwm->res_lock); + mutex_init(&lpc18xx_pwm->period_lock); + + val = (u64)NSEC_PER_SEC * LPC18XX_PWM_TIMER_MAX; + do_div(val, lpc18xx_pwm->clk_rate); + lpc18xx_pwm->max_period_ns = val; + + lpc18xx_pwm->min_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, + lpc18xx_pwm->clk_rate); + + lpc18xx_pwm->chip.dev = &pdev->dev; + lpc18xx_pwm->chip.ops = &lpc18xx_pwm_ops; + lpc18xx_pwm->chip.base = -1; + lpc18xx_pwm->chip.npwm = 16; + lpc18xx_pwm->chip.of_xlate = of_pwm_xlate_with_flags; + lpc18xx_pwm->chip.of_pwm_n_cells = 3; + + /* SCT counter must be in unify (32 bit) mode */ + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CONFIG, + LPC18XX_PWM_CONFIG_UNIFY); + + /* + * Everytime the timer counter reaches the period value, the related + * event will be triggered and the counter reset to 0. + */ + set_bit(LPC18XX_PWM_EVENT_PERIOD, &lpc18xx_pwm->event_map); + lpc18xx_pwm->period_event = LPC18XX_PWM_EVENT_PERIOD; + + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_EVSTATEMSK(lpc18xx_pwm->period_event), + LPC18XX_PWM_EVSTATEMSK_ALL); + + val = LPC18XX_PWM_EVCTRL_MATCH(lpc18xx_pwm->period_event) | + LPC18XX_PWM_EVCTRL_COMB_MATCH; + lpc18xx_pwm_writel(lpc18xx_pwm, + LPC18XX_PWM_EVCTRL(lpc18xx_pwm->period_event), val); + + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_LIMIT, + BIT(lpc18xx_pwm->period_event)); + + ret = pwmchip_add(&lpc18xx_pwm->chip); + if (ret < 0) { + dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret); + goto disable_pwmclk; + } + + for (i = 0; i < lpc18xx_pwm->chip.npwm; i++) { + pwm = &lpc18xx_pwm->chip.pwms[i]; + pwm->chip_data = devm_kzalloc(lpc18xx_pwm->dev, + sizeof(struct lpc18xx_pwm_data), + GFP_KERNEL); + if (!pwm->chip_data) { + ret = -ENOMEM; + goto remove_pwmchip; + } + } + + platform_set_drvdata(pdev, lpc18xx_pwm); + + val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); + val &= ~LPC18XX_PWM_BIDIR; + val &= ~LPC18XX_PWM_CTRL_HALT; + val &= ~LPC18XX_PWM_PRE_MASK; + val |= LPC18XX_PWM_PRE(0); + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, val); + + return 0; + +remove_pwmchip: + pwmchip_remove(&lpc18xx_pwm->chip); +disable_pwmclk: + clk_disable_unprepare(lpc18xx_pwm->pwm_clk); + return ret; +} + +static int lpc18xx_pwm_remove(struct platform_device *pdev) +{ + struct lpc18xx_pwm_chip *lpc18xx_pwm = platform_get_drvdata(pdev); + u32 val; + + val = lpc18xx_pwm_readl(lpc18xx_pwm, LPC18XX_PWM_CTRL); + lpc18xx_pwm_writel(lpc18xx_pwm, LPC18XX_PWM_CTRL, + val | LPC18XX_PWM_CTRL_HALT); + + clk_disable_unprepare(lpc18xx_pwm->pwm_clk); + + return pwmchip_remove(&lpc18xx_pwm->chip); +} + +static struct platform_driver lpc18xx_pwm_driver = { + .driver = { + .name = "lpc18xx-sct-pwm", + .of_match_table = lpc18xx_pwm_of_match, + }, + .probe = lpc18xx_pwm_probe, + .remove = lpc18xx_pwm_remove, +}; +module_platform_driver(lpc18xx_pwm_driver); + +MODULE_AUTHOR("Ariel D'Alessandro "); +MODULE_DESCRIPTION("NXP LPC18xx PWM driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From b0dabcc6f8b7cb08d5c81ecbc642105d67a4c1d2 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Wed, 5 Aug 2015 23:31:47 -0300 Subject: [PATCH 6820/7006] pwm: Add NXP LPC18xx PWM/SCT DT binding documentation Add the devicetree binding document for NXP LPC18xx PWM/SCT. Signed-off-by: Ariel D'Alessandro Signed-off-by: Thierry Reding --- .../bindings/pwm/lpc1850-sct-pwm.txt | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt diff --git a/Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt b/Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt new file mode 100644 index 0000000000000..36e49d4325cdb --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/lpc1850-sct-pwm.txt @@ -0,0 +1,20 @@ +* NXP LPC18xx State Configurable Timer - Pulse Width Modulator driver + +Required properties: + - compatible: Should be "nxp,lpc1850-sct-pwm" + - reg: Should contain physical base address and length of pwm registers. + - clocks: Must contain an entry for each entry in clock-names. + See ../clock/clock-bindings.txt for details. + - clock-names: Must include the following entries. + - pwm: PWM operating clock. + - #pwm-cells: Should be 3. See pwm.txt in this directory for the description + of the cells format. + +Example: + pwm: pwm@40000000 { + compatible = "nxp,lpc1850-sct-pwm"; + reg = <0x40000000 0x1000>; + clocks =<&ccu1 CLK_CPU_SCT>; + clock-names = "pwm"; + #pwm-cells = <3>; + }; -- GitLab From 7a5938201834a9c25155176d0f5942d48336b244 Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Fri, 31 Jul 2015 18:51:20 +0200 Subject: [PATCH 6821/7006] ARM: at91: pwm: atmel-hlcdc: Add at91sam9n12 errata The errata for HLCDC PWM of at91sam9n12 are the same as for at91sam9x5. Signed-off-by: Josh Wu Acked-by: Alexandre Belloni Signed-off-by: Thierry Reding --- drivers/pwm/pwm-atmel-hlcdc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c index fa5feaba25a5d..5df1db40fc075 100644 --- a/drivers/pwm/pwm-atmel-hlcdc.c +++ b/drivers/pwm/pwm-atmel-hlcdc.c @@ -217,6 +217,11 @@ static const struct atmel_hlcdc_pwm_errata atmel_hlcdc_pwm_sama5d3_errata = { }; static const struct of_device_id atmel_hlcdc_dt_ids[] = { + { + .compatible = "atmel,at91sam9n12-hlcdc", + /* 9n12 has same errata as 9x5 HLCDC PWM */ + .data = &atmel_hlcdc_pwm_at91sam9x5_errata, + }, { .compatible = "atmel,at91sam9x5-hlcdc", .data = &atmel_hlcdc_pwm_at91sam9x5_errata, -- GitLab From 02cc2ccfe771677db3cd40a71837e1467ebc839a Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 22 Apr 2015 21:28:04 -0400 Subject: [PATCH 6822/7006] Revert "Hexagon: fix signal.c compile error" This reverts commit f3f601c1d2728f02544cfd143eaa82e5398b3e9b. UAPI headers cannot use "uapi/" in their paths by design -- when they're installed, they do not have the uapi/ prefix. Otherwise doing so breaks userland badly. Signed-off-by: Mike Frysinger Signed-off-by: Richard Kuo --- arch/hexagon/include/uapi/asm/signal.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/arch/hexagon/include/uapi/asm/signal.h b/arch/hexagon/include/uapi/asm/signal.h index 98106e55ad4ff..24b998888916a 100644 --- a/arch/hexagon/include/uapi/asm/signal.h +++ b/arch/hexagon/include/uapi/asm/signal.h @@ -19,8 +19,6 @@ #ifndef _ASM_SIGNAL_H #define _ASM_SIGNAL_H -#include - extern unsigned long __rt_sigtramp_template[2]; void do_signal(struct pt_regs *regs); -- GitLab From d77e92e270edd79a2218ce0ba5b6179ad0c93175 Mon Sep 17 00:00:00 2001 From: Ross Zwisler Date: Wed, 9 Sep 2015 10:29:40 -0600 Subject: [PATCH 6823/7006] dax: update PMD fault handler with PMEM API As part of the v4.3 merge window the DAX code was updated by Matthew and Kirill to handle PMD pages. Also as part of the v4.3 merge window we updated the DAX code to do proper PMEM flushing (commit 2765cfbb342c: "dax: update I/O path to do proper PMEM flushing"). The additional code added by the DAX PMD patches also needs to be updated to properly use the PMEM API. This ensures that after a PMD fault is handled the zeros written to the newly allocated pages are durable on the DIMMs. linux/dax.h is included to get rid of a bunch of sparse warnings. Signed-off-by: Ross Zwisler Cc: Matthew Wilcox , Cc: Dan Williams Cc: Kirill Shutemov Signed-off-by: Linus Torvalds --- fs/dax.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/dax.c b/fs/dax.c index e43389c74bbce..93bf2f990ace4 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -527,7 +528,7 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, unsigned long pmd_addr = address & PMD_MASK; bool write = flags & FAULT_FLAG_WRITE; long length; - void *kaddr; + void __pmem *kaddr; pgoff_t size, pgoff; sector_t block, sector; unsigned long pfn; @@ -570,7 +571,8 @@ int __dax_pmd_fault(struct vm_area_struct *vma, unsigned long address, if (buffer_unwritten(&bh) || buffer_new(&bh)) { int i; for (i = 0; i < PTRS_PER_PMD; i++) - clear_page(kaddr + i * PAGE_SIZE); + clear_pmem(kaddr + i * PAGE_SIZE, PAGE_SIZE); + wmb_pmem(); count_vm_event(PGMAJFAULT); mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); result |= VM_FAULT_MAJOR; -- GitLab From bd2843fe1f29f6145c623ae9390f144cefaa611d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 9 Sep 2015 10:16:39 +0100 Subject: [PATCH 6824/7006] fix ufs write vs readpage race when writing into a hole Followup to the UFS series - with the way we clear the new blocks (via buffer cache, possibly on more than a page worth of file) we really should not insert a reference to new block into inode block tree until after we'd cleared it. Signed-off-by: Al Viro Signed-off-by: Linus Torvalds --- fs/ufs/balloc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index fb8b54eb77c5d..dc5fae601c24b 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -417,14 +417,14 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, if (oldcount == 0) { result = ufs_alloc_fragments (inode, cgno, goal, count, err); if (result) { + ufs_clear_frags(inode, result + oldcount, + newcount - oldcount, locked_page != NULL); write_seqlock(&UFS_I(inode)->meta_lock); ufs_cpu_to_data_ptr(sb, p, result); write_sequnlock(&UFS_I(inode)->meta_lock); *err = 0; UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag, fragment + count); - ufs_clear_frags(inode, result + oldcount, - newcount - oldcount, locked_page != NULL); } mutex_unlock(&UFS_SB(sb)->s_lock); UFSD("EXIT, result %llu\n", (unsigned long long)result); -- GitLab From d43cefcd68bbc9a67b2c0efe38eb9cf6b5170fe8 Mon Sep 17 00:00:00 2001 From: Atsushi Nemoto Date: Tue, 8 Sep 2015 18:15:41 +0900 Subject: [PATCH 6825/7006] net: eth: altera: Fix the initial device operstate Call netif_carrier_off() prior to register_netdev(), otherwise userspace can see incorrect link state. Signed-off-by: Atsushi Nemoto Signed-off-by: David S. Miller --- drivers/net/ethernet/altera/altera_tse_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/ethernet/altera/altera_tse_main.c b/drivers/net/ethernet/altera/altera_tse_main.c index 8207877d62376..fe644823ceaf9 100644 --- a/drivers/net/ethernet/altera/altera_tse_main.c +++ b/drivers/net/ethernet/altera/altera_tse_main.c @@ -1517,6 +1517,7 @@ static int altera_tse_probe(struct platform_device *pdev) spin_lock_init(&priv->tx_lock); spin_lock_init(&priv->rxdma_irq_lock); + netif_carrier_off(ndev); ret = register_netdev(ndev); if (ret) { dev_err(&pdev->dev, "failed to register TSE net device\n"); -- GitLab From fd1754fb8afbd9cf4ea279d533414aa6577b7e60 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 8 Sep 2015 16:25:39 +0530 Subject: [PATCH 6826/7006] cxgb4: Fix tx flit calculation In commit 0aac3f56d4a63f04 ("cxgb4: Add comment for calculate tx flits and sge length code") introduced a regression where tx flit calculation is going wrong, which can lead to data corruption, hang, stall and write-combining failure. Fixing it. Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/sge.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c index 78f446c58422e..9162746d77295 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/sge.c +++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c @@ -807,7 +807,7 @@ static inline unsigned int calc_tx_flits(const struct sk_buff *skb) * message or, if we're doing a Large Send Offload, an LSO CPL message * with an embedded TX Packet Write CPL message. */ - flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 4; + flits = sgl_len(skb_shinfo(skb)->nr_frags + 1); if (skb_shinfo(skb)->gso_size) flits += (sizeof(struct fw_eth_tx_pkt_wr) + sizeof(struct cpl_tx_pkt_lso_core) + -- GitLab From 2a485cf7db2815ca0d1510143d9126c4475aab39 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Tue, 8 Sep 2015 16:25:40 +0530 Subject: [PATCH 6827/7006] cxgb4: Fix for write-combining stats configuration The write-combining configuration register SGE_STAT_CFG_A needs to be configured after FW initializes the adapter, else FW will reset the configuration Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 592a4d66169c7..f5dcde27e4028 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -4719,8 +4719,6 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto out_free_adapter; } - t4_write_reg(adapter, SGE_STAT_CFG_A, - STATSOURCE_T5_V(7) | STATMODE_V(0)); } setup_memwin(adapter); @@ -4732,6 +4730,11 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) goto out_unmap_bar; + /* configure SGE_STAT_CFG_A to read WC stats */ + if (!is_t4(adapter->params.chip)) + t4_write_reg(adapter, SGE_STAT_CFG_A, + STATSOURCE_T5_V(7) | STATMODE_V(0)); + for_each_port(adapter, i) { struct net_device *netdev; -- GitLab From f15d7114bbdd594f1d8b644a44f647d2b6e9772e Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Mon, 29 Jun 2015 11:46:17 -0500 Subject: [PATCH 6828/7006] Documentation/watchdog: add timeout and ping rate control to watchdog-test.c The watchdog test program is much more useful if it can configure the timeout value and ping rate. This will allow you to test actual timeouts. Adds the -t parameter to set the timeout value (in seconds), and -p to set the ping rate (number of seconds between pings). Signed-off-by: Timur Tabi Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/watchdog/src/watchdog-test.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Documentation/watchdog/src/watchdog-test.c b/Documentation/watchdog/src/watchdog-test.c index 3da822967ee0e..fcdde8fc98be3 100644 --- a/Documentation/watchdog/src/watchdog-test.c +++ b/Documentation/watchdog/src/watchdog-test.c @@ -41,6 +41,7 @@ static void term(int sig) int main(int argc, char *argv[]) { int flags; + unsigned int ping_rate = 1; fd = open("/dev/watchdog", O_WRONLY); @@ -63,22 +64,33 @@ int main(int argc, char *argv[]) fprintf(stderr, "Watchdog card enabled.\n"); fflush(stderr); goto end; + } else if (!strncasecmp(argv[1], "-t", 2) && argv[2]) { + flags = atoi(argv[2]); + ioctl(fd, WDIOC_SETTIMEOUT, &flags); + fprintf(stderr, "Watchdog timeout set to %u seconds.\n", flags); + fflush(stderr); + goto end; + } else if (!strncasecmp(argv[1], "-p", 2) && argv[2]) { + ping_rate = strtoul(argv[2], NULL, 0); + fprintf(stderr, "Watchdog ping rate set to %u seconds.\n", ping_rate); + fflush(stderr); } else { - fprintf(stderr, "-d to disable, -e to enable.\n"); + fprintf(stderr, "-d to disable, -e to enable, -t to set " \ + "the timeout,\n-p to set the ping rate, and \n"); fprintf(stderr, "run by itself to tick the card.\n"); fflush(stderr); goto end; } - } else { - fprintf(stderr, "Watchdog Ticking Away!\n"); - fflush(stderr); } + fprintf(stderr, "Watchdog Ticking Away!\n"); + fflush(stderr); + signal(SIGINT, term); while(1) { keep_alive(); - sleep(1); + sleep(ping_rate); } end: close(fd); -- GitLab From 8a340dbbc4b10fe07a924e91979bfc93e966dd65 Mon Sep 17 00:00:00 2001 From: Ezequiel Garcia Date: Thu, 23 Jul 2015 17:21:16 -0300 Subject: [PATCH 6829/7006] watchdog: imgpdc: Unregister restart handler on remove Commit c631f20068 ("watchdog: imgpdc: Add reboot support") introduced a restart handler but forgot to unregister it on driver removal. Fix it. Fixes: c631f20068 ("watchdog: imgpdc: Add reboot support") Reported-by: Ariel D'Alessandro Signed-off-by: Ezequiel Garcia Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/imgpdc_wdt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c index 0f73621827abf..15ab07230960f 100644 --- a/drivers/watchdog/imgpdc_wdt.c +++ b/drivers/watchdog/imgpdc_wdt.c @@ -316,6 +316,7 @@ static int pdc_wdt_remove(struct platform_device *pdev) { struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev); + unregister_restart_handler(&pdc_wdt->restart_handler); pdc_wdt_stop(&pdc_wdt->wdt_dev); watchdog_unregister_device(&pdc_wdt->wdt_dev); clk_disable_unprepare(pdc_wdt->wdt_clk); -- GitLab From 9fab06920c9207aca8ff4e2416bb10cabc19294a Mon Sep 17 00:00:00 2001 From: Greta Zhang Date: Fri, 24 Jul 2015 15:28:45 +0800 Subject: [PATCH 6830/7006] watchdog: mtk_wdt: add suspend/resume support add mediatek watchdog driver suspend/resume support Signed-off-by: Greta Zhang Signed-off-by: Roger Lu Signed-off-by: Eddie Huang Acked-by: Matthias Brugger Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mtk_wdt.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 938b987de551b..056412ca836d3 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -221,17 +221,47 @@ static int mtk_wdt_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int mtk_wdt_suspend(struct device *dev) +{ + struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev); + + if (watchdog_active(&mtk_wdt->wdt_dev)) + mtk_wdt_stop(&mtk_wdt->wdt_dev); + + return 0; +} + +static int mtk_wdt_resume(struct device *dev) +{ + struct mtk_wdt_dev *mtk_wdt = dev_get_drvdata(dev); + + if (watchdog_active(&mtk_wdt->wdt_dev)) { + mtk_wdt_start(&mtk_wdt->wdt_dev); + mtk_wdt_ping(&mtk_wdt->wdt_dev); + } + + return 0; +} +#endif + static const struct of_device_id mtk_wdt_dt_ids[] = { { .compatible = "mediatek,mt6589-wdt" }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids); +static const struct dev_pm_ops mtk_wdt_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mtk_wdt_suspend, + mtk_wdt_resume) +}; + static struct platform_driver mtk_wdt_driver = { .probe = mtk_wdt_probe, .remove = mtk_wdt_remove, .driver = { .name = DRV_NAME, + .pm = &mtk_wdt_pm_ops, .of_match_table = mtk_wdt_dt_ids, }, }; -- GitLab From 5724485b185a4ac4bb96149718ff736c5ef5c169 Mon Sep 17 00:00:00 2001 From: Greta Zhang Date: Fri, 24 Jul 2015 15:28:46 +0800 Subject: [PATCH 6831/7006] watchdog: mtk_wdt: add wdt shutdown callback to disable wdt if enabled Without .shutdown(), watchdog might reset the system during power off. For example, if watchdog's timeout is set to 30s, then it is reset to zero by mtk_wdt_ping(). During power off, no app will ping watchdog, but watchdog is still running and may trigger reset. Signed-off-by: Greta Zhang Signed-off-by: Eddie Huang Acked-by: Matthias Brugger Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mtk_wdt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c index 056412ca836d3..6ad9df9487110 100644 --- a/drivers/watchdog/mtk_wdt.c +++ b/drivers/watchdog/mtk_wdt.c @@ -210,6 +210,14 @@ static int mtk_wdt_probe(struct platform_device *pdev) return 0; } +static void mtk_wdt_shutdown(struct platform_device *pdev) +{ + struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); + + if (watchdog_active(&mtk_wdt->wdt_dev)) + mtk_wdt_stop(&mtk_wdt->wdt_dev); +} + static int mtk_wdt_remove(struct platform_device *pdev) { struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev); @@ -259,6 +267,7 @@ static const struct dev_pm_ops mtk_wdt_pm_ops = { static struct platform_driver mtk_wdt_driver = { .probe = mtk_wdt_probe, .remove = mtk_wdt_remove, + .shutdown = mtk_wdt_shutdown, .driver = { .name = DRV_NAME, .pm = &mtk_wdt_pm_ops, -- GitLab From 0919e4445190da18496d31aac08b90828a47d45f Mon Sep 17 00:00:00 2001 From: Francesco Lavra Date: Sat, 25 Jul 2015 08:25:18 +0200 Subject: [PATCH 6832/7006] watchdog: sunxi: fix activation of system reset Commit f2147de33470 ("watchdog: sunxi: support parameterized compatible strings") introduced a regression in sunxi_wdt_start(), by which the system reset function of the watchdog is not enabled upon starting the watchdog. As a result, the system is not reset when the watchdog expires. Fix it. Fixes: f2147de33470 ("watchdog: sunxi: support parameterized compatible strings") Signed-off-by: Francesco Lavra Acked-by: Maxime Ripard Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck Cc: stable@vger.kernel.org --- drivers/watchdog/sunxi_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/sunxi_wdt.c b/drivers/watchdog/sunxi_wdt.c index a29afb37c48ca..47bd8a14d01f5 100644 --- a/drivers/watchdog/sunxi_wdt.c +++ b/drivers/watchdog/sunxi_wdt.c @@ -184,7 +184,7 @@ static int sunxi_wdt_start(struct watchdog_device *wdt_dev) /* Set system reset function */ reg = readl(wdt_base + regs->wdt_cfg); reg &= ~(regs->wdt_reset_mask); - reg |= ~(regs->wdt_reset_val); + reg |= regs->wdt_reset_val; writel(reg, wdt_base + regs->wdt_cfg); /* Enable watchdog */ -- GitLab From 64307b48f79f35d28ed6b44e20b773bc00a0152e Mon Sep 17 00:00:00 2001 From: Vivien Didelot Date: Mon, 27 Jul 2015 12:03:30 -0400 Subject: [PATCH 6833/7006] watchdog: (nv_tco) add support for MCP79 Tested on the Nvidia chipset with an SMBus controller PCI ID 0x0AA2 (as shown in the PCI listing during the boot sequence). Signed-off-by: Vivien Didelot Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/nv_tco.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/watchdog/nv_tco.c b/drivers/watchdog/nv_tco.c index c028454be66ce..bd917bb757b82 100644 --- a/drivers/watchdog/nv_tco.c +++ b/drivers/watchdog/nv_tco.c @@ -294,6 +294,8 @@ static const struct pci_device_id tco_pci_tbl[] = { PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS, PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS, + PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* End of list */ }; MODULE_DEVICE_TABLE(pci, tco_pci_tbl); -- GitLab From fa928ee8d4af1f70eee77a5ac77c084a0715eb9e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 29 Jul 2015 09:45:36 -0700 Subject: [PATCH 6834/7006] watchdog: booke_wdt: Use infrastructure to check timeout limits The watchdog infrastructure checks the maximum timeout for us. Use it. Signed-off-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/booke_wdt.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/watchdog/booke_wdt.c b/drivers/watchdog/booke_wdt.c index e96b09b135c8f..04da4b66c75e3 100644 --- a/drivers/watchdog/booke_wdt.c +++ b/drivers/watchdog/booke_wdt.c @@ -186,8 +186,6 @@ static int booke_wdt_stop(struct watchdog_device *wdog) static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, unsigned int timeout) { - if (timeout > MAX_WDT_TIMEOUT) - return -EINVAL; wdt_dev->timeout = timeout; booke_wdt_set(wdt_dev); @@ -211,7 +209,6 @@ static struct watchdog_device booke_wdt_dev = { .info = &booke_wdt_info, .ops = &booke_wdt_ops, .min_timeout = 1, - .max_timeout = 0xFFFF }; static void __exit booke_wdt_exit(void) @@ -229,6 +226,7 @@ static int __init booke_wdt_init(void) booke_wdt_set_timeout(&booke_wdt_dev, period_to_sec(booke_wdt_period)); watchdog_set_nowayout(&booke_wdt_dev, nowayout); + booke_wdt_dev.max_timeout = MAX_WDT_TIMEOUT; if (booke_wdt_enabled) booke_wdt_start(&booke_wdt_dev); -- GitLab From 1d5d48523900a4b0f25d6b52f1a93c84bd671186 Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Tue, 8 Sep 2015 14:25:14 +0100 Subject: [PATCH 6835/7006] xen-netback: require fewer guest Rx slots when not using GSO Commit f48da8b14d04ca87ffcffe68829afd45f926ec6a (xen-netback: fix unlimited guest Rx internal queue and carrier flapping) introduced a regression. The PV frontend in IPXE only places 4 requests on the guest Rx ring. Since netback required at least (MAX_SKB_FRAGS + 1) slots, IPXE could not receive any packets. a) If GSO is not enabled on the VIF, fewer guest Rx slots are required for the largest possible packet. Calculate the required slots based on the maximum GSO size or the MTU. This calculation of the number of required slots relies on 1650d5455bd2 (xen-netback: always fully coalesce guest Rx packets) which present in 4.0-rc1 and later. b) Reduce the Rx stall detection to checking for at least one available Rx request. This is fine since we're predominately concerned with detecting interfaces which are down and thus have zero available Rx requests. Signed-off-by: David Vrabel Reviewed-by: Wei Liu Signed-off-by: David S. Miller --- drivers/net/xen-netback/common.h | 10 ---------- drivers/net/xen-netback/netback.c | 23 ++++++++++++++++------- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h index 6dc76c1e807b4..a7bf747271162 100644 --- a/drivers/net/xen-netback/common.h +++ b/drivers/net/xen-netback/common.h @@ -200,11 +200,6 @@ struct xenvif_queue { /* Per-queue data for xenvif */ struct xenvif_stats stats; }; -/* Maximum number of Rx slots a to-guest packet may use, including the - * slot needed for GSO meta-data. - */ -#define XEN_NETBK_RX_SLOTS_MAX (MAX_SKB_FRAGS + 1) - enum state_bit_shift { /* This bit marks that the vif is connected */ VIF_STATUS_CONNECTED, @@ -317,11 +312,6 @@ int xenvif_dealloc_kthread(void *data); void xenvif_rx_queue_tail(struct xenvif_queue *queue, struct sk_buff *skb); -/* Determine whether the needed number of slots (req) are available, - * and set req_event if not. - */ -bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue, int needed); - void xenvif_carrier_on(struct xenvif *vif); /* Callback from stack when TX packet can be released */ diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index 42569b994ea84..b588b1a08cd4b 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -149,9 +149,20 @@ static inline pending_ring_idx_t pending_index(unsigned i) return i & (MAX_PENDING_REQS-1); } -bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue, int needed) +static int xenvif_rx_ring_slots_needed(struct xenvif *vif) +{ + if (vif->gso_mask) + return DIV_ROUND_UP(vif->dev->gso_max_size, PAGE_SIZE) + 1; + else + return DIV_ROUND_UP(vif->dev->mtu, PAGE_SIZE); +} + +static bool xenvif_rx_ring_slots_available(struct xenvif_queue *queue) { RING_IDX prod, cons; + int needed; + + needed = xenvif_rx_ring_slots_needed(queue->vif); do { prod = queue->rx.sring->req_prod; @@ -513,7 +524,7 @@ static void xenvif_rx_action(struct xenvif_queue *queue) skb_queue_head_init(&rxq); - while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX) + while (xenvif_rx_ring_slots_available(queue) && (skb = xenvif_rx_dequeue(queue)) != NULL) { queue->last_rx_time = jiffies; @@ -1938,8 +1949,7 @@ static bool xenvif_rx_queue_stalled(struct xenvif_queue *queue) prod = queue->rx.sring->req_prod; cons = queue->rx.req_cons; - return !queue->stalled - && prod - cons < XEN_NETBK_RX_SLOTS_MAX + return !queue->stalled && prod - cons < 1 && time_after(jiffies, queue->last_rx_time + queue->vif->stall_timeout); } @@ -1951,14 +1961,13 @@ static bool xenvif_rx_queue_ready(struct xenvif_queue *queue) prod = queue->rx.sring->req_prod; cons = queue->rx.req_cons; - return queue->stalled - && prod - cons >= XEN_NETBK_RX_SLOTS_MAX; + return queue->stalled && prod - cons >= 1; } static bool xenvif_have_rx_work(struct xenvif_queue *queue) { return (!skb_queue_empty(&queue->rx_queue) - && xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX)) + && xenvif_rx_ring_slots_available(queue)) || (queue->vif->stall_timeout && (xenvif_rx_queue_stalled(queue) || xenvif_rx_queue_ready(queue))) -- GitLab From ab54d7f017772e89964d4040937a83cd4468562a Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Jul 2015 11:39:39 +0200 Subject: [PATCH 6836/7006] Documentation: watchdog: at91sam9_wdt: add clocks property The watchdog has an input clock, the slow clock. It is required as it will not function without it. Signed-off-by: Alexandre Belloni Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- Documentation/devicetree/bindings/watchdog/atmel-wdt.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt index a4d869744f595..86fa6de1019bd 100644 --- a/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt +++ b/Documentation/devicetree/bindings/watchdog/atmel-wdt.txt @@ -6,6 +6,7 @@ Required properties: - compatible: must be "atmel,at91sam9260-wdt". - reg: physical base address of the controller and length of memory mapped region. +- clocks: phandle to input clock. Optional properties: - timeout-sec: contains the watchdog timeout in seconds. @@ -39,6 +40,7 @@ Example: compatible = "atmel,at91sam9260-wdt"; reg = <0xfffffd40 0x10>; interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>; + clocks = <&clk32k>; timeout-sec = <15>; atmel,watchdog-type = "hardware"; atmel,reset-type = "all"; -- GitLab From 0a0a542f6bbb2ebe956f0117c842302442ef52da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Thu, 30 Jul 2015 11:32:23 +0200 Subject: [PATCH 6837/7006] watchdog: gpio-wdt: be more strict about hw_algo matching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit strncmp(algo, "toggle", 6) doesn't compare the trailing '\0' byte, so using hw_algo = "toggleboggle" is recognized the same way as hw_algo = "toggle" . While this doesn't introduce any problems for a device tree that sticks to the documented settings it's still ugly. Fix this by using strcmp to only match on "toggle" and "level". Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/gpio_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 1687cc2d71223..57d30f1f55ab4 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c @@ -182,10 +182,10 @@ static int gpio_wdt_probe(struct platform_device *pdev) ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo); if (ret) return ret; - if (!strncmp(algo, "toggle", 6)) { + if (!strcmp(algo, "toggle")) { priv->hw_algo = HW_ALGO_TOGGLE; f = GPIOF_IN; - } else if (!strncmp(algo, "level", 5)) { + } else if (!strcmp(algo, "level")) { priv->hw_algo = HW_ALGO_LEVEL; f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; } else { -- GitLab From 4f2d0b2d1b31cbe704c8f94e74e46cb64187ab0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 31 Jul 2015 09:21:36 +0200 Subject: [PATCH 6838/7006] watchdog: gpio-wdt: ping already at startup for always running devices MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During probe for an always-running watchdog a timer is setup to constantly ping the watchdog while the device is not open. The gpio to ping the watchdog is setup to inactive. For a watchdog with hw_algo = "toggle" this results in a ping depending on the initial state of the gpio, for hw_algo = "level" no ping is generated. Make sure that the first automatic ping is sent immediately and not only when the timer expires the first time. This makes the machine survive in case more than half of the watchdog timeout is already elapsed. (Which is very probable for the chip I'm faced with that has a timeout of one second.) Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/gpio_wdt.c | 60 ++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 57d30f1f55ab4..5e16b0983e2ad 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c @@ -50,12 +50,41 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv) gpio_direction_input(priv->gpio); } +static void gpio_wdt_hwping(unsigned long data) +{ + struct watchdog_device *wdd = (struct watchdog_device *)data; + struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); + + if (priv->armed && time_after(jiffies, priv->last_jiffies + + msecs_to_jiffies(wdd->timeout * 1000))) { + dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); + return; + } + + /* Restart timer */ + mod_timer(&priv->timer, jiffies + priv->hw_margin); + + switch (priv->hw_algo) { + case HW_ALGO_TOGGLE: + /* Toggle output pin */ + priv->state = !priv->state; + gpio_set_value_cansleep(priv->gpio, priv->state); + break; + case HW_ALGO_LEVEL: + /* Pulse */ + gpio_set_value_cansleep(priv->gpio, !priv->active_low); + udelay(1); + gpio_set_value_cansleep(priv->gpio, priv->active_low); + break; + } +} + static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv) { priv->state = priv->active_low; gpio_direction_output(priv->gpio, priv->state); priv->last_jiffies = jiffies; - mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin); + gpio_wdt_hwping((unsigned long)&priv->wdd); } static int gpio_wdt_start(struct watchdog_device *wdd) @@ -97,35 +126,6 @@ static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t) return gpio_wdt_ping(wdd); } -static void gpio_wdt_hwping(unsigned long data) -{ - struct watchdog_device *wdd = (struct watchdog_device *)data; - struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd); - - if (priv->armed && time_after(jiffies, priv->last_jiffies + - msecs_to_jiffies(wdd->timeout * 1000))) { - dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n"); - return; - } - - /* Restart timer */ - mod_timer(&priv->timer, jiffies + priv->hw_margin); - - switch (priv->hw_algo) { - case HW_ALGO_TOGGLE: - /* Toggle output pin */ - priv->state = !priv->state; - gpio_set_value_cansleep(priv->gpio, priv->state); - break; - case HW_ALGO_LEVEL: - /* Pulse */ - gpio_set_value_cansleep(priv->gpio, !priv->active_low); - udelay(1); - gpio_set_value_cansleep(priv->gpio, priv->active_low); - break; - } -} - static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code, void *unused) { -- GitLab From 7c25f8c9f67708e6464d2221bc311cbd99e950dc Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Sat, 1 Aug 2015 15:37:16 -0300 Subject: [PATCH 6839/7006] watchdog: NXP LPC18xx Watchdog Timer Driver This commit adds support for the watchdog timer found in NXP LPC SoCs family, which includes LPC18xx/LPC43xx. Other SoCs in that family may share the same watchdog hardware. Watchdog driver registers a restart handler that will restart the system by performing an incorrect feed after ensuring the watchdog is enabled in reset mode. As watchdog cannot be disabled in hardware, driver's stop routine will regularly send a keepalive ping using a timer. Signed-off-by: Ariel D'Alessandro Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 11 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/lpc18xx_wdt.c | 340 +++++++++++++++++++++++++++++++++ 3 files changed, 352 insertions(+) create mode 100644 drivers/watchdog/lpc18xx_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 241fafde42cb5..b69bd67eea96d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -558,6 +558,17 @@ config DIGICOLOR_WATCHDOG To compile this driver as a module, choose M here: the module will be called digicolor_wdt. +config LPC18XX_WATCHDOG + tristate "LPC18xx/43xx Watchdog" + depends on ARCH_LPC18XX || COMPILE_TEST + select WATCHDOG_CORE + help + Say Y here if to include support for the watchdog timer + in NXP LPC SoCs family, which includes LPC18xx/LPC43xx + processors. + To compile this driver as a module, choose M here: the + module will be called lpc18xx_wdt. + # AVR32 Architecture config AT32AP700X_WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 59ea9a1b8e766..1b0ef48bf19ab 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -66,6 +66,7 @@ obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o obj-$(CONFIG_DIGICOLOR_WATCHDOG) += digicolor_wdt.o +obj-$(CONFIG_LPC18XX_WATCHDOG) += lpc18xx_wdt.o # AVR32 Architecture obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c new file mode 100644 index 0000000000000..00ff5bdd2db05 --- /dev/null +++ b/drivers/watchdog/lpc18xx_wdt.c @@ -0,0 +1,340 @@ +/* + * NXP LPC18xx Watchdog Timer (WDT) + * + * Copyright (c) 2015 Ariel D'Alessandro + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * Notes + * ----- + * The Watchdog consists of a fixed divide-by-4 clock pre-scaler and a 24-bit + * counter which decrements on every clock cycle. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Registers */ +#define LPC18XX_WDT_MOD 0x00 +#define LPC18XX_WDT_MOD_WDEN BIT(0) +#define LPC18XX_WDT_MOD_WDRESET BIT(1) + +#define LPC18XX_WDT_TC 0x04 +#define LPC18XX_WDT_TC_MIN 0xff +#define LPC18XX_WDT_TC_MAX 0xffffff + +#define LPC18XX_WDT_FEED 0x08 +#define LPC18XX_WDT_FEED_MAGIC1 0xaa +#define LPC18XX_WDT_FEED_MAGIC2 0x55 + +#define LPC18XX_WDT_TV 0x0c + +/* Clock pre-scaler */ +#define LPC18XX_WDT_CLK_DIV 4 + +/* Timeout values in seconds */ +#define LPC18XX_WDT_DEF_TIMEOUT 30U + +static int heartbeat; +module_param(heartbeat, int, 0); +MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds (default=" + __MODULE_STRING(LPC18XX_WDT_DEF_TIMEOUT) ")"); + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +struct lpc18xx_wdt_dev { + struct watchdog_device wdt_dev; + struct clk *reg_clk; + struct clk *wdt_clk; + unsigned long clk_rate; + void __iomem *base; + struct timer_list timer; + struct notifier_block restart_handler; + spinlock_t lock; +}; + +static int lpc18xx_wdt_feed(struct watchdog_device *wdt_dev) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); + unsigned long flags; + + /* + * An abort condition will occur if an interrupt happens during the feed + * sequence. + */ + spin_lock_irqsave(&lpc18xx_wdt->lock, flags); + writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); + writel(LPC18XX_WDT_FEED_MAGIC2, lpc18xx_wdt->base + LPC18XX_WDT_FEED); + spin_unlock_irqrestore(&lpc18xx_wdt->lock, flags); + + return 0; +} + +static void lpc18xx_wdt_timer_feed(unsigned long data) +{ + struct watchdog_device *wdt_dev = (struct watchdog_device *)data; + struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); + + lpc18xx_wdt_feed(wdt_dev); + + /* Use safe value (1/2 of real timeout) */ + mod_timer(&lpc18xx_wdt->timer, jiffies + + msecs_to_jiffies((wdt_dev->timeout * MSEC_PER_SEC) / 2)); +} + +/* + * Since LPC18xx Watchdog cannot be disabled in hardware, we must keep feeding + * it with a timer until userspace watchdog software takes over. + */ +static int lpc18xx_wdt_stop(struct watchdog_device *wdt_dev) +{ + lpc18xx_wdt_timer_feed((unsigned long)wdt_dev); + + return 0; +} + +static void __lpc18xx_wdt_set_timeout(struct lpc18xx_wdt_dev *lpc18xx_wdt) +{ + unsigned int val; + + val = DIV_ROUND_UP(lpc18xx_wdt->wdt_dev.timeout * lpc18xx_wdt->clk_rate, + LPC18XX_WDT_CLK_DIV); + writel(val, lpc18xx_wdt->base + LPC18XX_WDT_TC); +} + +static int lpc18xx_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int new_timeout) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); + + lpc18xx_wdt->wdt_dev.timeout = new_timeout; + __lpc18xx_wdt_set_timeout(lpc18xx_wdt); + + return 0; +} + +unsigned int lpc18xx_wdt_get_timeleft(struct watchdog_device *wdt_dev) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); + unsigned int val; + + val = readl(lpc18xx_wdt->base + LPC18XX_WDT_TV); + return (val * LPC18XX_WDT_CLK_DIV) / lpc18xx_wdt->clk_rate; +} + +static int lpc18xx_wdt_start(struct watchdog_device *wdt_dev) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); + unsigned int val; + + if (timer_pending(&lpc18xx_wdt->timer)) + del_timer(&lpc18xx_wdt->timer); + + val = readl(lpc18xx_wdt->base + LPC18XX_WDT_MOD); + val |= LPC18XX_WDT_MOD_WDEN; + val |= LPC18XX_WDT_MOD_WDRESET; + writel(val, lpc18xx_wdt->base + LPC18XX_WDT_MOD); + + /* + * Setting the WDEN bit in the WDMOD register is not sufficient to + * enable the Watchdog. A valid feed sequence must be completed after + * setting WDEN before the Watchdog is capable of generating a reset. + */ + lpc18xx_wdt_feed(wdt_dev); + + return 0; +} + +static struct watchdog_info lpc18xx_wdt_info = { + .identity = "NXP LPC18xx Watchdog", + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, +}; + +static const struct watchdog_ops lpc18xx_wdt_ops = { + .owner = THIS_MODULE, + .start = lpc18xx_wdt_start, + .stop = lpc18xx_wdt_stop, + .ping = lpc18xx_wdt_feed, + .set_timeout = lpc18xx_wdt_set_timeout, + .get_timeleft = lpc18xx_wdt_get_timeleft, +}; + +static int lpc18xx_wdt_restart(struct notifier_block *this, unsigned long mode, + void *cmd) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = container_of(this, + struct lpc18xx_wdt_dev, restart_handler); + unsigned long flags; + int val; + + /* + * Incorrect feed sequence causes immediate watchdog reset if enabled. + */ + spin_lock_irqsave(&lpc18xx_wdt->lock, flags); + + val = readl(lpc18xx_wdt->base + LPC18XX_WDT_MOD); + val |= LPC18XX_WDT_MOD_WDEN; + val |= LPC18XX_WDT_MOD_WDRESET; + writel(val, lpc18xx_wdt->base + LPC18XX_WDT_MOD); + + writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); + writel(LPC18XX_WDT_FEED_MAGIC2, lpc18xx_wdt->base + LPC18XX_WDT_FEED); + + writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); + writel(LPC18XX_WDT_FEED_MAGIC1, lpc18xx_wdt->base + LPC18XX_WDT_FEED); + + spin_unlock_irqrestore(&lpc18xx_wdt->lock, flags); + + return NOTIFY_OK; +} + +static int lpc18xx_wdt_probe(struct platform_device *pdev) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt; + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + + lpc18xx_wdt = devm_kzalloc(dev, sizeof(*lpc18xx_wdt), GFP_KERNEL); + if (!lpc18xx_wdt) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lpc18xx_wdt->base = devm_ioremap_resource(dev, res); + if (IS_ERR(lpc18xx_wdt->base)) + return PTR_ERR(lpc18xx_wdt->base); + + lpc18xx_wdt->reg_clk = devm_clk_get(dev, "reg"); + if (IS_ERR(lpc18xx_wdt->reg_clk)) { + dev_err(dev, "failed to get the reg clock\n"); + return PTR_ERR(lpc18xx_wdt->reg_clk); + } + + lpc18xx_wdt->wdt_clk = devm_clk_get(dev, "wdtclk"); + if (IS_ERR(lpc18xx_wdt->wdt_clk)) { + dev_err(dev, "failed to get the wdt clock\n"); + return PTR_ERR(lpc18xx_wdt->wdt_clk); + } + + ret = clk_prepare_enable(lpc18xx_wdt->reg_clk); + if (ret) { + dev_err(dev, "could not prepare or enable sys clock\n"); + return ret; + } + + ret = clk_prepare_enable(lpc18xx_wdt->wdt_clk); + if (ret) { + dev_err(dev, "could not prepare or enable wdt clock\n"); + goto disable_reg_clk; + } + + /* We use the clock rate to calculate timeouts */ + lpc18xx_wdt->clk_rate = clk_get_rate(lpc18xx_wdt->wdt_clk); + if (lpc18xx_wdt->clk_rate == 0) { + dev_err(dev, "failed to get clock rate\n"); + ret = -EINVAL; + goto disable_wdt_clk; + } + + lpc18xx_wdt->wdt_dev.info = &lpc18xx_wdt_info; + lpc18xx_wdt->wdt_dev.ops = &lpc18xx_wdt_ops; + + lpc18xx_wdt->wdt_dev.min_timeout = DIV_ROUND_UP(LPC18XX_WDT_TC_MIN * + LPC18XX_WDT_CLK_DIV, lpc18xx_wdt->clk_rate); + + lpc18xx_wdt->wdt_dev.max_timeout = (LPC18XX_WDT_TC_MAX * + LPC18XX_WDT_CLK_DIV) / lpc18xx_wdt->clk_rate; + + lpc18xx_wdt->wdt_dev.timeout = min(lpc18xx_wdt->wdt_dev.max_timeout, + LPC18XX_WDT_DEF_TIMEOUT); + + spin_lock_init(&lpc18xx_wdt->lock); + + lpc18xx_wdt->wdt_dev.parent = dev; + watchdog_set_drvdata(&lpc18xx_wdt->wdt_dev, lpc18xx_wdt); + + ret = watchdog_init_timeout(&lpc18xx_wdt->wdt_dev, heartbeat, dev); + + __lpc18xx_wdt_set_timeout(lpc18xx_wdt); + + setup_timer(&lpc18xx_wdt->timer, lpc18xx_wdt_timer_feed, + (unsigned long)&lpc18xx_wdt->wdt_dev); + + watchdog_set_nowayout(&lpc18xx_wdt->wdt_dev, nowayout); + + platform_set_drvdata(pdev, lpc18xx_wdt); + + ret = watchdog_register_device(&lpc18xx_wdt->wdt_dev); + if (ret) + goto disable_wdt_clk; + + lpc18xx_wdt->restart_handler.notifier_call = lpc18xx_wdt_restart; + lpc18xx_wdt->restart_handler.priority = 128; + ret = register_restart_handler(&lpc18xx_wdt->restart_handler); + if (ret) + dev_warn(dev, "failed to register restart handler: %d\n", ret); + + return 0; + +disable_wdt_clk: + clk_disable_unprepare(lpc18xx_wdt->wdt_clk); +disable_reg_clk: + clk_disable_unprepare(lpc18xx_wdt->reg_clk); + return ret; +} + +static void lpc18xx_wdt_shutdown(struct platform_device *pdev) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev); + + lpc18xx_wdt_stop(&lpc18xx_wdt->wdt_dev); +} + +static int lpc18xx_wdt_remove(struct platform_device *pdev) +{ + struct lpc18xx_wdt_dev *lpc18xx_wdt = platform_get_drvdata(pdev); + + unregister_restart_handler(&lpc18xx_wdt->restart_handler); + + dev_warn(&pdev->dev, "I quit now, hardware will probably reboot!\n"); + del_timer(&lpc18xx_wdt->timer); + + watchdog_unregister_device(&lpc18xx_wdt->wdt_dev); + clk_disable_unprepare(lpc18xx_wdt->wdt_clk); + clk_disable_unprepare(lpc18xx_wdt->reg_clk); + + return 0; +} + +static const struct of_device_id lpc18xx_wdt_match[] = { + { .compatible = "nxp,lpc1850-wwdt" }, + {} +}; +MODULE_DEVICE_TABLE(of, lpc18xx_wdt_match); + +static struct platform_driver lpc18xx_wdt_driver = { + .driver = { + .name = "lpc18xx-wdt", + .of_match_table = lpc18xx_wdt_match, + }, + .probe = lpc18xx_wdt_probe, + .remove = lpc18xx_wdt_remove, + .shutdown = lpc18xx_wdt_shutdown, +}; +module_platform_driver(lpc18xx_wdt_driver); + +MODULE_AUTHOR("Ariel D'Alessandro "); +MODULE_DESCRIPTION("NXP LPC18xx Watchdog Timer Driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From cfde37e1ec18dc68a52a1b882390c0f9c52b5f10 Mon Sep 17 00:00:00 2001 From: Ariel D'Alessandro Date: Sat, 1 Aug 2015 15:37:17 -0300 Subject: [PATCH 6840/7006] DT: watchdog: Add NXP LPC18xx Watchdog Timer binding documentation Add the devicetree binding document for NXP LPC18xx Watchdog Timer. Signed-off-by: Ariel D'Alessandro Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/lpc18xx-wdt.txt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt diff --git a/Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt b/Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt new file mode 100644 index 0000000000000..09f6b24969e0f --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/lpc18xx-wdt.txt @@ -0,0 +1,19 @@ +* NXP LPC18xx Watchdog Timer (WDT) + +Required properties: +- compatible: Should be "nxp,lpc1850-wwdt" +- reg: Should contain WDT registers location and length +- clocks: Must contain an entry for each entry in clock-names. +- clock-names: Should contain "wdtclk" and "reg"; the watchdog counter + clock and register interface clock respectively. +- interrupts: Should contain WDT interrupt + +Examples: + +watchdog@40080000 { + compatible = "nxp,lpc1850-wwdt"; + reg = <0x40080000 0x24>; + clocks = <&cgu BASE_SAFE_CLK>, <&ccu1 CLK_CPU_WWDT>; + clock-names = "wdtclk", "reg"; + interrupts = <49>; +}; -- GitLab From 6cd8a1b9f71290d58099101e65e7e2279bcdb212 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Fri, 7 Aug 2015 10:28:40 -0700 Subject: [PATCH 6841/7006] watchdog: lpc18xx_wdt_get_timeleft() can be static Signed-off-by: Fengguang Wu Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/lpc18xx_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/lpc18xx_wdt.c b/drivers/watchdog/lpc18xx_wdt.c index 00ff5bdd2db05..ab7b8b185d992 100644 --- a/drivers/watchdog/lpc18xx_wdt.c +++ b/drivers/watchdog/lpc18xx_wdt.c @@ -123,7 +123,7 @@ static int lpc18xx_wdt_set_timeout(struct watchdog_device *wdt_dev, return 0; } -unsigned int lpc18xx_wdt_get_timeleft(struct watchdog_device *wdt_dev) +static unsigned int lpc18xx_wdt_get_timeleft(struct watchdog_device *wdt_dev) { struct lpc18xx_wdt_dev *lpc18xx_wdt = watchdog_get_drvdata(wdt_dev); unsigned int val; -- GitLab From a57e06f7c6365f7d6e13f35933d3ef329205c1af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:52 +0200 Subject: [PATCH 6842/7006] watchdog: mpc8xxx: remove dead code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 689381a248871..8ad42b83f995d 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -68,12 +68,6 @@ module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -/* - * We always prescale, but if someone really doesn't want to they can set this - * to 0 - */ -static int prescale = 1; - static DEFINE_SPINLOCK(wdt_spinlock); static void mpc8xxx_wdt_keepalive(void) @@ -101,11 +95,9 @@ static void mpc8xxx_wdt_timer_ping(unsigned long arg) static int mpc8xxx_wdt_start(struct watchdog_device *w) { - u32 tmp = SWCRR_SWEN; + u32 tmp = SWCRR_SWEN | SWCRR_SWPR; /* Good, fire up the show */ - if (prescale) - tmp |= SWCRR_SWPR; if (reset) tmp |= SWCRR_SWRI; @@ -179,10 +171,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) } /* Calculate the timeout in seconds */ - if (prescale) - timeout_sec = (timeout * wdt_type->prescaler) / freq; - else - timeout_sec = timeout / freq; + timeout_sec = (timeout * wdt_type->prescaler) / freq; mpc8xxx_wdt_dev.timeout = timeout_sec; #ifdef MODULE -- GitLab From 50ffb53ef2311e4631086d27783b00db6859c60e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:53 +0200 Subject: [PATCH 6843/7006] watchdog: mpc8xxx: simplify registration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit ef90174f8210 ("watchdog: watchdog_core: Add watchdog registration deferral mechanism") there is no need to delay the call to watchdog_register_device any more. So simplify the registration code accordingly. Resetting wd_base to NULL can the also be dropped because nothing depends on it being NULL to signal probe failure any more. (The matching wd_base = NULL in .remove was missing, too.) Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 38 +++++++--------------------------- 1 file changed, 7 insertions(+), 31 deletions(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 8ad42b83f995d..e0acda3282d9f 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -51,7 +51,6 @@ struct mpc8xxx_wdt_type { }; static struct mpc8xxx_wdt __iomem *wd_base; -static int mpc8xxx_wdt_init_late(void); static u16 timeout = 0xffff; module_param(timeout, ushort, 0); @@ -174,11 +173,14 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) timeout_sec = (timeout * wdt_type->prescaler) / freq; mpc8xxx_wdt_dev.timeout = timeout_sec; -#ifdef MODULE - ret = mpc8xxx_wdt_init_late(); - if (ret) + + watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout); + + ret = watchdog_register_device(&mpc8xxx_wdt_dev); + if (ret) { + pr_err("cannot register watchdog device (err=%d)\n", ret); goto err_unmap; -#endif + } pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", reset ? "reset" : "interrupt", timeout, timeout_sec); @@ -193,7 +195,6 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) return 0; err_unmap: iounmap(wd_base); - wd_base = NULL; return ret; } @@ -242,31 +243,6 @@ static struct platform_driver mpc8xxx_wdt_driver = { }, }; -/* - * We do wdt initialization in two steps: arch_initcall probes the wdt - * very early to start pinging the watchdog (misc devices are not yet - * available), and later module_init() just registers the misc device. - */ -static int mpc8xxx_wdt_init_late(void) -{ - int ret; - - if (!wd_base) - return -ENODEV; - - watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout); - - ret = watchdog_register_device(&mpc8xxx_wdt_dev); - if (ret) { - pr_err("cannot register watchdog device (err=%d)\n", ret); - return ret; - } - return 0; -} -#ifndef MODULE -module_init(mpc8xxx_wdt_init_late); -#endif - static int __init mpc8xxx_wdt_init(void) { return platform_driver_register(&mpc8xxx_wdt_driver); -- GitLab From f0ded83b96d27b27db0015e701cfd916330e3c50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:54 +0200 Subject: [PATCH 6844/7006] watchdog: mpc8xxx: make use of of_device_get_match_data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This function is new in v4.2-rc1 and makes a forward declaration of the match table superfluous which can so be removed. Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index e0acda3282d9f..fb1fe967cf57f 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -139,7 +139,6 @@ static struct watchdog_device mpc8xxx_wdt_dev = { .ops = &mpc8xxx_wdt_ops, }; -static const struct of_device_id mpc8xxx_wdt_match[]; static int mpc8xxx_wdt_probe(struct platform_device *ofdev) { int ret; @@ -150,10 +149,9 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) bool enabled; unsigned int timeout_sec; - match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev); - if (!match) + wdt_type = of_device_get_match_data(&ofdev->dev); + if (!wdt_type) return -EINVAL; - wdt_type = match->data; if (!freq || freq == -1) return -EINVAL; -- GitLab From de5f71222bd544558d81701454eb457b295de96e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:55 +0200 Subject: [PATCH 6845/7006] watchdog: mpc8xxx: use devm_ioremap_resource to map memory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This simplifies the error paths and device unbinding. Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index fb1fe967cf57f..a6790fcfa69b9 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -142,8 +142,7 @@ static struct watchdog_device mpc8xxx_wdt_dev = { static int mpc8xxx_wdt_probe(struct platform_device *ofdev) { int ret; - const struct of_device_id *match; - struct device_node *np = ofdev->dev.of_node; + struct resource *res; const struct mpc8xxx_wdt_type *wdt_type; u32 freq = fsl_get_sys_freq(); bool enabled; @@ -156,15 +155,15 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) if (!freq || freq == -1) return -EINVAL; - wd_base = of_iomap(np, 0); - if (!wd_base) - return -ENOMEM; + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); + wd_base = devm_ioremap_resource(&ofdev->dev, res); + if (IS_ERR(wd_base)) + return PTR_ERR(wd_base); enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN; if (!enabled && wdt_type->hw_enabled) { pr_info("could not be enabled in software\n"); - ret = -ENOSYS; - goto err_unmap; + return -ENOSYS; } /* Calculate the timeout in seconds */ @@ -177,7 +176,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) ret = watchdog_register_device(&mpc8xxx_wdt_dev); if (ret) { pr_err("cannot register watchdog device (err=%d)\n", ret); - goto err_unmap; + return ret; } pr_info("WDT driver for MPC8xxx initialized. mode:%s timeout=%d (%d seconds)\n", @@ -191,9 +190,6 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) if (enabled) mod_timer(&wdt_timer, jiffies); return 0; -err_unmap: - iounmap(wd_base); - return ret; } static int mpc8xxx_wdt_remove(struct platform_device *ofdev) @@ -202,7 +198,6 @@ static int mpc8xxx_wdt_remove(struct platform_device *ofdev) reset ? "reset" : "machine check exception"); del_timer_sync(&wdt_timer); watchdog_unregister_device(&mpc8xxx_wdt_dev); - iounmap(wd_base); return 0; } -- GitLab From 7997ebad4d747ff5561cb5ec0c7423e0d4e628d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:56 +0200 Subject: [PATCH 6846/7006] watchdog: mpc8xxx: use dynamic memory for device specific data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of relying on global static memory dynamically allocate the needed data. This has the benefit of some saved bytes if the driver is not in use and making it possible to bind more than one device (even though this has no known use case). Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 88 ++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 35 deletions(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index a6790fcfa69b9..0b69797d34172 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -50,7 +50,12 @@ struct mpc8xxx_wdt_type { bool hw_enabled; }; -static struct mpc8xxx_wdt __iomem *wd_base; +struct mpc8xxx_wdt_ddata { + struct mpc8xxx_wdt __iomem *base; + struct watchdog_device wdd; + struct timer_list timer; + spinlock_t lock; +}; static u16 timeout = 0xffff; module_param(timeout, ushort, 0); @@ -67,33 +72,29 @@ module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started " "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); -static DEFINE_SPINLOCK(wdt_spinlock); - -static void mpc8xxx_wdt_keepalive(void) +static void mpc8xxx_wdt_keepalive(struct mpc8xxx_wdt_ddata *ddata) { /* Ping the WDT */ - spin_lock(&wdt_spinlock); - out_be16(&wd_base->swsrr, 0x556c); - out_be16(&wd_base->swsrr, 0xaa39); - spin_unlock(&wdt_spinlock); + spin_lock(&ddata->lock); + out_be16(&ddata->base->swsrr, 0x556c); + out_be16(&ddata->base->swsrr, 0xaa39); + spin_unlock(&ddata->lock); } -static struct watchdog_device mpc8xxx_wdt_dev; -static void mpc8xxx_wdt_timer_ping(unsigned long arg); -static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, - (unsigned long)&mpc8xxx_wdt_dev); - static void mpc8xxx_wdt_timer_ping(unsigned long arg) { - struct watchdog_device *w = (struct watchdog_device *)arg; + struct mpc8xxx_wdt_ddata *ddata = (void *)arg; - mpc8xxx_wdt_keepalive(); + mpc8xxx_wdt_keepalive(ddata); /* We're pinging it twice faster than needed, just to be sure. */ - mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2); + mod_timer(&ddata->timer, jiffies + HZ * ddata->wdd.timeout / 2); } static int mpc8xxx_wdt_start(struct watchdog_device *w) { + struct mpc8xxx_wdt_ddata *ddata = + container_of(w, struct mpc8xxx_wdt_ddata, wdd); + u32 tmp = SWCRR_SWEN | SWCRR_SWPR; /* Good, fire up the show */ @@ -102,22 +103,28 @@ static int mpc8xxx_wdt_start(struct watchdog_device *w) tmp |= timeout << 16; - out_be32(&wd_base->swcrr, tmp); + out_be32(&ddata->base->swcrr, tmp); - del_timer_sync(&wdt_timer); + del_timer_sync(&ddata->timer); return 0; } static int mpc8xxx_wdt_ping(struct watchdog_device *w) { - mpc8xxx_wdt_keepalive(); + struct mpc8xxx_wdt_ddata *ddata = + container_of(w, struct mpc8xxx_wdt_ddata, wdd); + + mpc8xxx_wdt_keepalive(ddata); return 0; } static int mpc8xxx_wdt_stop(struct watchdog_device *w) { - mod_timer(&wdt_timer, jiffies); + struct mpc8xxx_wdt_ddata *ddata = + container_of(w, struct mpc8xxx_wdt_ddata, wdd); + + mod_timer(&ddata->timer, jiffies); return 0; } @@ -134,16 +141,12 @@ static struct watchdog_ops mpc8xxx_wdt_ops = { .stop = mpc8xxx_wdt_stop, }; -static struct watchdog_device mpc8xxx_wdt_dev = { - .info = &mpc8xxx_wdt_info, - .ops = &mpc8xxx_wdt_ops, -}; - static int mpc8xxx_wdt_probe(struct platform_device *ofdev) { int ret; struct resource *res; const struct mpc8xxx_wdt_type *wdt_type; + struct mpc8xxx_wdt_ddata *ddata; u32 freq = fsl_get_sys_freq(); bool enabled; unsigned int timeout_sec; @@ -155,25 +158,36 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) if (!freq || freq == -1) return -EINVAL; + ddata = devm_kzalloc(&ofdev->dev, sizeof(*ddata), GFP_KERNEL); + if (!ddata) + return -ENOMEM; + res = platform_get_resource(ofdev, IORESOURCE_MEM, 0); - wd_base = devm_ioremap_resource(&ofdev->dev, res); - if (IS_ERR(wd_base)) - return PTR_ERR(wd_base); + ddata->base = devm_ioremap_resource(&ofdev->dev, res); + if (IS_ERR(ddata->base)) + return PTR_ERR(ddata->base); - enabled = in_be32(&wd_base->swcrr) & SWCRR_SWEN; + enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN; if (!enabled && wdt_type->hw_enabled) { pr_info("could not be enabled in software\n"); return -ENOSYS; } + spin_lock_init(&ddata->lock); + setup_timer(&ddata->timer, mpc8xxx_wdt_timer_ping, + (unsigned long)ddata); + + ddata->wdd.info = &mpc8xxx_wdt_info, + ddata->wdd.ops = &mpc8xxx_wdt_ops, + /* Calculate the timeout in seconds */ timeout_sec = (timeout * wdt_type->prescaler) / freq; - mpc8xxx_wdt_dev.timeout = timeout_sec; + ddata->wdd.timeout = timeout_sec; - watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout); + watchdog_set_nowayout(&ddata->wdd, nowayout); - ret = watchdog_register_device(&mpc8xxx_wdt_dev); + ret = watchdog_register_device(&ddata->wdd); if (ret) { pr_err("cannot register watchdog device (err=%d)\n", ret); return ret; @@ -188,16 +202,20 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) * userspace handles it. */ if (enabled) - mod_timer(&wdt_timer, jiffies); + mod_timer(&ddata->timer, jiffies); + + platform_set_drvdata(ofdev, ddata); return 0; } static int mpc8xxx_wdt_remove(struct platform_device *ofdev) { + struct mpc8xxx_wdt_ddata *ddata = platform_get_drvdata(ofdev); + pr_crit("Watchdog removed, expect the %s soon!\n", reset ? "reset" : "machine check exception"); - del_timer_sync(&wdt_timer); - watchdog_unregister_device(&mpc8xxx_wdt_dev); + del_timer_sync(&ddata->timer); + watchdog_unregister_device(&ddata->wdd); return 0; } -- GitLab From 72cd501e6a9b578cf99ae062477d9c7a938a3238 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:57 +0200 Subject: [PATCH 6847/7006] watchdog: mpc8xxx: use better error code when watchdog cannot be enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit checkpatch warns about ENOSYS, telling "ENOSYS means 'invalid syscall nr' and nothing else". So use ENODEV instead. Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/mpc8xxx_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 0b69797d34172..5f2273aac37d5 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -170,7 +170,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev) enabled = in_be32(&ddata->base->swcrr) & SWCRR_SWEN; if (!enabled && wdt_type->hw_enabled) { pr_info("could not be enabled in software\n"); - return -ENOSYS; + return -ENODEV; } spin_lock_init(&ddata->lock); -- GitLab From f8c33e9717150f7b8063d6d77a8ea90adad434e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 12 Aug 2015 10:15:58 +0200 Subject: [PATCH 6848/7006] watchdog: mpc8xxx: allow to compile for MPC512x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MPC5125 processor features a watchdog device that is identical to the MPC8610 one. So allow to enable the driver for MPC512x kernel configurations. Signed-off-by: Uwe Kleine-König Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b69bd67eea96d..cd99fcce3bab6 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1344,7 +1344,7 @@ config MPC5200_WDT config 8xxx_WDT tristate "MPC8xxx Platform Watchdog Timer" - depends on PPC_8xx || PPC_83xx || PPC_86xx + depends on PPC_8xx || PPC_83xx || PPC_86xx || PPC_MPC512x select WATCHDOG_CORE help This driver is for a SoC level watchdog that exists on some -- GitLab From 76534860f108b812926a4fbfbdadbfa9cdec89d0 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 6 Aug 2015 18:16:46 +0800 Subject: [PATCH 6849/7006] watchdog: add a driver to support SAMA5D4 watchdog timer From SAMA5D4, the watchdog timer is upgrated with a new feature, which is describled as in the datasheet, "WDT_MR can be written until a LOCKMR command is issued in WDT_CR". That is to say, as long as the bootstrap and u-boot don't issue a LOCKMR command, WDT_MR can be written more than once in the driver. So the SAMA5D4 watchdog driver's implementation is different from the at91sam9260 watchdog driver implemented in file at91sam9_wdt.c. The user application open the device file to enable the watchdog timer hardware, and close to disable it, and set the watchdog timer timeout by seting WDV and WDD fields of WDT_MR register, and ping the watchdog by issuing WDRSTT command to WDT_CR register with hard-coded key. Signed-off-by: Wenyou Yang Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 9 + drivers/watchdog/Makefile | 1 + drivers/watchdog/at91sam9_wdt.h | 2 + drivers/watchdog/sama5d4_wdt.c | 280 ++++++++++++++++++++++++++++++++ 4 files changed, 292 insertions(+) create mode 100644 drivers/watchdog/sama5d4_wdt.c diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index cd99fcce3bab6..ce0658c92fe85 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -188,6 +188,15 @@ config AT91SAM9X_WATCHDOG Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will reboot your system when the timeout is reached. +config SAMA5D4_WATCHDOG + tristate "Atmel SAMA5D4 Watchdog Timer" + depends on ARCH_AT91 + select WATCHDOG_CORE + help + Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. + Its Watchdog Timer Mode Register can be written more than once. + This will reboot your system when the timeout is reached. + config CADENCE_WATCHDOG tristate "Cadence Watchdog Timer" depends on HAS_IOMEM diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 1b0ef48bf19ab..0c616e3f67bb5 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -41,6 +41,7 @@ obj-$(CONFIG_IXP4XX_WATCHDOG) += ixp4xx_wdt.o obj-$(CONFIG_KS8695_WATCHDOG) += ks8695_wdt.o obj-$(CONFIG_S3C2410_WATCHDOG) += s3c2410_wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o +obj-$(CONFIG_SAMA5D4_WATCHDOG) += sama5d4_wdt.o obj-$(CONFIG_DW_WATCHDOG) += dw_wdt.o obj-$(CONFIG_EP93XX_WATCHDOG) += ep93xx_wdt.o obj-$(CONFIG_PNX4008_WATCHDOG) += pnx4008_wdt.o diff --git a/drivers/watchdog/at91sam9_wdt.h b/drivers/watchdog/at91sam9_wdt.h index c6fbb2e6c41ba..b79a83b467cec 100644 --- a/drivers/watchdog/at91sam9_wdt.h +++ b/drivers/watchdog/at91sam9_wdt.h @@ -22,11 +22,13 @@ #define AT91_WDT_MR 0x04 /* Watchdog Mode Register */ #define AT91_WDT_WDV (0xfff << 0) /* Counter Value */ +#define AT91_WDT_SET_WDV(x) ((x) & AT91_WDT_WDV) #define AT91_WDT_WDFIEN (1 << 12) /* Fault Interrupt Enable */ #define AT91_WDT_WDRSTEN (1 << 13) /* Reset Processor */ #define AT91_WDT_WDRPROC (1 << 14) /* Timer Restart */ #define AT91_WDT_WDDIS (1 << 15) /* Watchdog Disable */ #define AT91_WDT_WDD (0xfff << 16) /* Delta Value */ +#define AT91_WDT_SET_WDD(x) (((x) << 16) & AT91_WDT_WDD) #define AT91_WDT_WDDBGHLT (1 << 28) /* Debug Halt */ #define AT91_WDT_WDIDLEHLT (1 << 29) /* Idle Halt */ diff --git a/drivers/watchdog/sama5d4_wdt.c b/drivers/watchdog/sama5d4_wdt.c new file mode 100644 index 0000000000000..a49634cdc1ccb --- /dev/null +++ b/drivers/watchdog/sama5d4_wdt.c @@ -0,0 +1,280 @@ +/* + * Driver for Atmel SAMA5D4 Watchdog Timer + * + * Copyright (C) 2015 Atmel Corporation + * + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "at91sam9_wdt.h" + +/* minimum and maximum watchdog timeout, in seconds */ +#define MIN_WDT_TIMEOUT 1 +#define MAX_WDT_TIMEOUT 16 +#define WDT_DEFAULT_TIMEOUT MAX_WDT_TIMEOUT + +#define WDT_SEC2TICKS(s) ((s) ? (((s) << 8) - 1) : 0) + +struct sama5d4_wdt { + struct watchdog_device wdd; + void __iomem *reg_base; + u32 config; +}; + +static int wdt_timeout = WDT_DEFAULT_TIMEOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; + +module_param(wdt_timeout, int, 0); +MODULE_PARM_DESC(wdt_timeout, + "Watchdog timeout in seconds. (default = " + __MODULE_STRING(WDT_DEFAULT_TIMEOUT) ")"); + +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +#define wdt_read(wdt, field) \ + readl_relaxed((wdt)->reg_base + (field)) + +#define wdt_write(wtd, field, val) \ + writel_relaxed((val), (wdt)->reg_base + (field)) + +static int sama5d4_wdt_start(struct watchdog_device *wdd) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + u32 reg; + + reg = wdt_read(wdt, AT91_WDT_MR); + reg &= ~AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, reg); + + return 0; +} + +static int sama5d4_wdt_stop(struct watchdog_device *wdd) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + u32 reg; + + reg = wdt_read(wdt, AT91_WDT_MR); + reg |= AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, reg); + + return 0; +} + +static int sama5d4_wdt_ping(struct watchdog_device *wdd) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + + wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT); + + return 0; +} + +static int sama5d4_wdt_set_timeout(struct watchdog_device *wdd, + unsigned int timeout) +{ + struct sama5d4_wdt *wdt = watchdog_get_drvdata(wdd); + u32 value = WDT_SEC2TICKS(timeout); + u32 reg; + + reg = wdt_read(wdt, AT91_WDT_MR); + reg &= ~AT91_WDT_WDV; + reg &= ~AT91_WDT_WDD; + reg |= AT91_WDT_SET_WDV(value); + reg |= AT91_WDT_SET_WDD(value); + wdt_write(wdt, AT91_WDT_MR, reg); + + wdd->timeout = timeout; + + return 0; +} + +static const struct watchdog_info sama5d4_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING, + .identity = "Atmel SAMA5D4 Watchdog", +}; + +static struct watchdog_ops sama5d4_wdt_ops = { + .owner = THIS_MODULE, + .start = sama5d4_wdt_start, + .stop = sama5d4_wdt_stop, + .ping = sama5d4_wdt_ping, + .set_timeout = sama5d4_wdt_set_timeout, +}; + +static irqreturn_t sama5d4_wdt_irq_handler(int irq, void *dev_id) +{ + struct sama5d4_wdt *wdt = platform_get_drvdata(dev_id); + + if (wdt_read(wdt, AT91_WDT_SR)) { + pr_crit("Atmel Watchdog Software Reset\n"); + emergency_restart(); + pr_crit("Reboot didn't succeed\n"); + } + + return IRQ_HANDLED; +} + +static int of_sama5d4_wdt_init(struct device_node *np, struct sama5d4_wdt *wdt) +{ + const char *tmp; + + wdt->config = AT91_WDT_WDDIS; + + if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) && + !strcmp(tmp, "software")) + wdt->config |= AT91_WDT_WDFIEN; + else + wdt->config |= AT91_WDT_WDRSTEN; + + if (of_property_read_bool(np, "atmel,idle-halt")) + wdt->config |= AT91_WDT_WDIDLEHLT; + + if (of_property_read_bool(np, "atmel,dbg-halt")) + wdt->config |= AT91_WDT_WDDBGHLT; + + return 0; +} + +static int sama5d4_wdt_init(struct sama5d4_wdt *wdt) +{ + struct watchdog_device *wdd = &wdt->wdd; + u32 value = WDT_SEC2TICKS(wdd->timeout); + u32 reg; + + /* + * Because the fields WDV and WDD must not be modified when the WDDIS + * bit is set, so clear the WDDIS bit before writing the WDT_MR. + */ + reg = wdt_read(wdt, AT91_WDT_MR); + reg &= ~AT91_WDT_WDDIS; + wdt_write(wdt, AT91_WDT_MR, reg); + + reg = wdt->config; + reg |= AT91_WDT_SET_WDD(value); + reg |= AT91_WDT_SET_WDV(value); + + wdt_write(wdt, AT91_WDT_MR, reg); + + return 0; +} + +static int sama5d4_wdt_probe(struct platform_device *pdev) +{ + struct watchdog_device *wdd; + struct sama5d4_wdt *wdt; + struct resource *res; + void __iomem *regs; + u32 irq = 0; + int ret; + + wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL); + if (!wdt) + return -ENOMEM; + + wdd = &wdt->wdd; + wdd->timeout = wdt_timeout; + wdd->info = &sama5d4_wdt_info; + wdd->ops = &sama5d4_wdt_ops; + wdd->min_timeout = MIN_WDT_TIMEOUT; + wdd->max_timeout = MAX_WDT_TIMEOUT; + + watchdog_set_drvdata(wdd, wdt); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + wdt->reg_base = regs; + + if (pdev->dev.of_node) { + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + dev_warn(&pdev->dev, "failed to get IRQ from DT\n"); + + ret = of_sama5d4_wdt_init(pdev->dev.of_node, wdt); + if (ret) + return ret; + } + + if ((wdt->config & AT91_WDT_WDFIEN) && irq) { + ret = devm_request_irq(&pdev->dev, irq, sama5d4_wdt_irq_handler, + IRQF_SHARED | IRQF_IRQPOLL | + IRQF_NO_SUSPEND, pdev->name, pdev); + if (ret) { + dev_err(&pdev->dev, + "cannot register interrupt handler\n"); + return ret; + } + } + + ret = watchdog_init_timeout(wdd, wdt_timeout, &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "unable to set timeout value\n"); + return ret; + } + + ret = sama5d4_wdt_init(wdt); + if (ret) + return ret; + + watchdog_set_nowayout(wdd, nowayout); + + ret = watchdog_register_device(wdd); + if (ret) { + dev_err(&pdev->dev, "failed to register watchdog device\n"); + return ret; + } + + platform_set_drvdata(pdev, wdt); + + dev_info(&pdev->dev, "initialized (timeout = %d sec, nowayout = %d)\n", + wdt_timeout, nowayout); + + return 0; +} + +static int sama5d4_wdt_remove(struct platform_device *pdev) +{ + struct sama5d4_wdt *wdt = platform_get_drvdata(pdev); + + sama5d4_wdt_stop(&wdt->wdd); + + watchdog_unregister_device(&wdt->wdd); + + return 0; +} + +static const struct of_device_id sama5d4_wdt_of_match[] = { + { .compatible = "atmel,sama5d4-wdt", }, + { } +}; +MODULE_DEVICE_TABLE(of, sama5d4_wdt_of_match); + +static struct platform_driver sama5d4_wdt_driver = { + .probe = sama5d4_wdt_probe, + .remove = sama5d4_wdt_remove, + .driver = { + .name = "sama5d4_wdt", + .of_match_table = sama5d4_wdt_of_match, + } +}; +module_platform_driver(sama5d4_wdt_driver); + +MODULE_AUTHOR("Atmel Corporation"); +MODULE_DESCRIPTION("Atmel SAMA5D4 Watchdog Timer driver"); +MODULE_LICENSE("GPL v2"); -- GitLab From 74e98eb085889b0d2d4908f59f6e00026063014f Mon Sep 17 00:00:00 2001 From: Sasha Levin Date: Tue, 8 Sep 2015 10:53:40 -0400 Subject: [PATCH 6850/7006] RDS: verify the underlying transport exists before creating a connection There was no verification that an underlying transport exists when creating a connection, this would cause dereferencing a NULL ptr. It might happen on sockets that weren't properly bound before attempting to send a message, which will cause a NULL ptr deref: [135546.047719] kasan: GPF could be caused by NULL-ptr deref or user memory accessgeneral protection fault: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC KASAN [135546.051270] Modules linked in: [135546.051781] CPU: 4 PID: 15650 Comm: trinity-c4 Not tainted 4.2.0-next-20150902-sasha-00041-gbaa1222-dirty #2527 [135546.053217] task: ffff8800835bc000 ti: ffff8800bc708000 task.ti: ffff8800bc708000 [135546.054291] RIP: __rds_conn_create (net/rds/connection.c:194) [135546.055666] RSP: 0018:ffff8800bc70fab0 EFLAGS: 00010202 [135546.056457] RAX: dffffc0000000000 RBX: 0000000000000f2c RCX: ffff8800835bc000 [135546.057494] RDX: 0000000000000007 RSI: ffff8800835bccd8 RDI: 0000000000000038 [135546.058530] RBP: ffff8800bc70fb18 R08: 0000000000000001 R09: 0000000000000000 [135546.059556] R10: ffffed014d7a3a23 R11: ffffed014d7a3a21 R12: 0000000000000000 [135546.060614] R13: 0000000000000001 R14: ffff8801ec3d0000 R15: 0000000000000000 [135546.061668] FS: 00007faad4ffb700(0000) GS:ffff880252000000(0000) knlGS:0000000000000000 [135546.062836] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b [135546.063682] CR2: 000000000000846a CR3: 000000009d137000 CR4: 00000000000006a0 [135546.064723] Stack: [135546.065048] ffffffffafe2055c ffffffffafe23fc1 ffffed00493097bf ffff8801ec3d0008 [135546.066247] 0000000000000000 00000000000000d0 0000000000000000 ac194a24c0586342 [135546.067438] 1ffff100178e1f78 ffff880320581b00 ffff8800bc70fdd0 ffff880320581b00 [135546.068629] Call Trace: [135546.069028] ? __rds_conn_create (include/linux/rcupdate.h:856 net/rds/connection.c:134) [135546.069989] ? rds_message_copy_from_user (net/rds/message.c:298) [135546.071021] rds_conn_create_outgoing (net/rds/connection.c:278) [135546.071981] rds_sendmsg (net/rds/send.c:1058) [135546.072858] ? perf_trace_lock (include/trace/events/lock.h:38) [135546.073744] ? lockdep_init (kernel/locking/lockdep.c:3298) [135546.074577] ? rds_send_drop_to (net/rds/send.c:976) [135546.075508] ? __might_fault (./arch/x86/include/asm/current.h:14 mm/memory.c:3795) [135546.076349] ? __might_fault (mm/memory.c:3795) [135546.077179] ? rds_send_drop_to (net/rds/send.c:976) [135546.078114] sock_sendmsg (net/socket.c:611 net/socket.c:620) [135546.078856] SYSC_sendto (net/socket.c:1657) [135546.079596] ? SYSC_connect (net/socket.c:1628) [135546.080510] ? trace_dump_stack (kernel/trace/trace.c:1926) [135546.081397] ? ring_buffer_unlock_commit (kernel/trace/ring_buffer.c:2479 kernel/trace/ring_buffer.c:2558 kernel/trace/ring_buffer.c:2674) [135546.082390] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) [135546.083410] ? trace_event_raw_event_sys_enter (include/trace/events/syscalls.h:16) [135546.084481] ? do_audit_syscall_entry (include/trace/events/syscalls.h:16) [135546.085438] ? trace_buffer_unlock_commit (kernel/trace/trace.c:1749) [135546.085515] rds_ib_laddr_check(): addr 36.74.25.172 ret -99 node type -1 Acked-by: Santosh Shilimkar Signed-off-by: Sasha Levin Signed-off-by: David S. Miller --- net/rds/connection.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/net/rds/connection.c b/net/rds/connection.c index 9b2de5e67d795..49adeef8090ca 100644 --- a/net/rds/connection.c +++ b/net/rds/connection.c @@ -190,6 +190,12 @@ new_conn: } } + if (trans == NULL) { + kmem_cache_free(rds_conn_slab, conn); + conn = ERR_PTR(-ENODEV); + goto out; + } + conn->c_trans = trans; ret = trans->conn_alloc(conn, gfp); -- GitLab From f4fff94e3e3a712ef062c44b64ecf8f552f48ea4 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Thu, 6 Aug 2015 18:17:05 +0800 Subject: [PATCH 6851/7006] Documentation: dt: binding: atmel-sama5d4-wdt: for SAMA5D4 watchdog driver The compatible "atmel,sama5d4-wdt" supports the SAMA5D4 watchdog driver and the watchdog's WDT_MR register can be written more than once. Signed-off-by: Wenyou Yang Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- .../bindings/watchdog/atmel-sama5d4-wdt.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt diff --git a/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt new file mode 100644 index 0000000000000..f7cc7c0609107 --- /dev/null +++ b/Documentation/devicetree/bindings/watchdog/atmel-sama5d4-wdt.txt @@ -0,0 +1,35 @@ +* Atmel SAMA5D4 Watchdog Timer (WDT) Controller + +Required properties: +- compatible: "atmel,sama5d4-wdt" +- reg: base physical address and length of memory mapped region. + +Optional properties: +- timeout-sec: watchdog timeout value (in seconds). +- interrupts: interrupt number to the CPU. +- atmel,watchdog-type: should be "hardware" or "software". + "hardware": enable watchdog fault reset. A watchdog fault triggers + watchdog reset. + "software": enable watchdog fault interrupt. A watchdog fault asserts + watchdog interrupt. +- atmel,idle-halt: present if you want to stop the watchdog when the CPU is + in idle state. + CAUTION: This property should be used with care, it actually makes the + watchdog not counting when the CPU is in idle state, therefore the + watchdog reset time depends on mean CPU usage and will not reset at all + if the CPU stop working while it is in idle state, which is probably + not what you want. +- atmel,dbg-halt: present if you want to stop the watchdog when the CPU is + in debug state. + +Example: + watchdog@fc068640 { + compatible = "atmel,sama5d4-wdt"; + reg = <0xfc068640 0x10>; + interrupts = <4 IRQ_TYPE_LEVEL_HIGH 5>; + timeout-sec = <10>; + atmel,watchdog-type = "hardware"; + atmel,dbg-halt; + atmel,idle-halt; + status = "okay"; + }; -- GitLab From a97a09bd119fbdf4ba8c634fed8f4148d1def1e0 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 16 Aug 2015 11:23:43 +0200 Subject: [PATCH 6852/7006] watchdog: at91sam9: get and use slow clock Commit dca1a4b5ff6e ("clk: at91: keep slow clk enabled to prevent system hang") added a workaround for the slow clock as it is not properly handled by its users. Get and use the slow clock as it is necessary for the at91sam9 watchdog. Signed-off-by: Alexandre Belloni Reviewed-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/at91sam9_wdt.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index e4698f7c5f930..7e6acaf3ece49 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c @@ -17,6 +17,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -90,6 +91,7 @@ struct at91wdt { unsigned long heartbeat; /* WDT heartbeat in jiffies */ bool nowayout; unsigned int irq; + struct clk *sclk; }; /* ......................................................................... */ @@ -352,15 +354,25 @@ static int __init at91wdt_probe(struct platform_device *pdev) if (IS_ERR(wdt->base)) return PTR_ERR(wdt->base); + wdt->sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(wdt->sclk)) + return PTR_ERR(wdt->sclk); + + err = clk_prepare_enable(wdt->sclk); + if (err) { + dev_err(&pdev->dev, "Could not enable slow clock\n"); + return err; + } + if (pdev->dev.of_node) { err = of_at91wdt_init(pdev->dev.of_node, wdt); if (err) - return err; + goto err_clk; } err = at91_wdt_init(pdev, wdt); if (err) - return err; + goto err_clk; platform_set_drvdata(pdev, wdt); @@ -368,6 +380,11 @@ static int __init at91wdt_probe(struct platform_device *pdev) wdt->wdd.timeout, wdt->nowayout); return 0; + +err_clk: + clk_disable_unprepare(wdt->sclk); + + return err; } static int __exit at91wdt_remove(struct platform_device *pdev) @@ -377,6 +394,7 @@ static int __exit at91wdt_remove(struct platform_device *pdev) pr_warn("I quit now, hardware will probably reboot!\n"); del_timer(&wdt->timer); + clk_disable_unprepare(wdt->sclk); return 0; } -- GitLab From bf5125d5e0759a0f513b1bcd33c15edc0cf4c17b Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 17 Aug 2015 09:19:03 -0700 Subject: [PATCH 6853/7006] watchdog: at91rm9200: Correct check for syscon_node_to_regmap() errors syscon_node_to_regmap() returns a regmap or an ERR_PTR(). Signed-off-by: Bjorn Andersson Acked-by: Guenter Roeck Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/at91rm9200_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 41cecb55766c0..464bf76842a49 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c @@ -244,7 +244,7 @@ static int at91wdt_probe(struct platform_device *pdev) } regmap_st = syscon_node_to_regmap(parent->of_node); - if (!regmap_st) + if (IS_ERR(regmap_st)) return -ENODEV; res = misc_register(&at91wdt_miscdev); -- GitLab From 6551881c86c791237a3bebf11eb3bd70b60ea782 Mon Sep 17 00:00:00 2001 From: Pratyush Anand Date: Thu, 20 Aug 2015 14:05:01 +0530 Subject: [PATCH 6854/7006] Watchdog: Fix parent of watchdog_devices /sys/class/watchdog/watchdogn/device/modalias can help to identify the driver/module for a given watchdog node. However, many wdt devices do not set their parent and so, we do not see an entry for device in sysfs for such devices. This patch fixes parent of watchdog_device so that /sys/class/watchdog/watchdogn/device is populated. Exceptions: booke, diag288, octeon, softdog and w83627hf -- They do not have any parent. Not sure, how we can identify driver for these devices. Signed-off-by: Pratyush Anand Reviewed-by: Johannes Thumshirn Acked-by: Guenter Roeck Acked-by: H Hartley Sweeten Acked-by: Lee Jones Acked-by: Lubomir Rintel Acked-by: Maxime Coquelin Acked-by: Thierry Reding Acked-by: Viresh Kumar Acked-by: Linus Walleij Signed-off-by: Wim Van Sebroeck --- drivers/misc/mei/wd.c | 1 + drivers/watchdog/bcm2835_wdt.c | 1 + drivers/watchdog/bcm47xx_wdt.c | 1 + drivers/watchdog/bcm_kona_wdt.c | 1 + drivers/watchdog/coh901327_wdt.c | 1 + drivers/watchdog/da9052_wdt.c | 1 + drivers/watchdog/da9055_wdt.c | 1 + drivers/watchdog/da9062_wdt.c | 1 + drivers/watchdog/da9063_wdt.c | 1 + drivers/watchdog/davinci_wdt.c | 1 + drivers/watchdog/digicolor_wdt.c | 1 + drivers/watchdog/ep93xx_wdt.c | 1 + drivers/watchdog/gpio_wdt.c | 1 + drivers/watchdog/ie6xx_wdt.c | 1 + drivers/watchdog/intel-mid_wdt.c | 1 + drivers/watchdog/jz4740_wdt.c | 1 + drivers/watchdog/mena21_wdt.c | 1 + drivers/watchdog/menf21bmc_wdt.c | 1 + drivers/watchdog/omap_wdt.c | 1 + drivers/watchdog/orion_wdt.c | 1 + drivers/watchdog/pnx4008_wdt.c | 1 + drivers/watchdog/qcom-wdt.c | 1 + drivers/watchdog/retu_wdt.c | 1 + drivers/watchdog/rt2880_wdt.c | 1 + drivers/watchdog/s3c2410_wdt.c | 1 + drivers/watchdog/shwdt.c | 1 + drivers/watchdog/sirfsoc_wdt.c | 1 + drivers/watchdog/sp805_wdt.c | 1 + drivers/watchdog/st_lpc_wdt.c | 1 + drivers/watchdog/stmp3xxx_rtc_wdt.c | 1 + drivers/watchdog/tegra_wdt.c | 1 + drivers/watchdog/twl4030_wdt.c | 1 + drivers/watchdog/txx9wdt.c | 1 + drivers/watchdog/ux500_wdt.c | 1 + drivers/watchdog/via_wdt.c | 1 + drivers/watchdog/wm831x_wdt.c | 1 + drivers/watchdog/wm8350_wdt.c | 1 + 37 files changed, 37 insertions(+) diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c index 2bc0f5089f829..b346638833b0c 100644 --- a/drivers/misc/mei/wd.c +++ b/drivers/misc/mei/wd.c @@ -364,6 +364,7 @@ int mei_watchdog_register(struct mei_device *dev) int ret; + amt_wd_dev.parent = dev->dev; /* unlock to perserve correct locking order */ mutex_unlock(&dev->device_lock); ret = watchdog_register_device(&amt_wd_dev); diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index 7116968dee129..66c3e656a6166 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -182,6 +182,7 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(&bcm2835_wdt_wdd, wdt); watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); + bcm2835_wdt_wdd.parent = &pdev->dev; err = watchdog_register_device(&bcm2835_wdt_wdd); if (err) { dev_err(dev, "Failed to register watchdog device"); diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index b28a072abf78f..4064a43f1360a 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c @@ -209,6 +209,7 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev) wdt->wdd.info = &bcm47xx_wdt_info; wdt->wdd.timeout = WDT_DEFAULT_TIME; + wdt->wdd.parent = &pdev->dev; ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); if (ret) goto err_timer; diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c index 22d8ae65772a5..e0c98423f2c9d 100644 --- a/drivers/watchdog/bcm_kona_wdt.c +++ b/drivers/watchdog/bcm_kona_wdt.c @@ -319,6 +319,7 @@ static int bcm_kona_wdt_probe(struct platform_device *pdev) spin_lock_init(&wdt->lock); platform_set_drvdata(pdev, wdt); watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt); + bcm_kona_wdt_wdd.parent = &pdev->dev; ret = bcm_kona_wdt_set_timeout_reg(&bcm_kona_wdt_wdd, 0); if (ret) { diff --git a/drivers/watchdog/coh901327_wdt.c b/drivers/watchdog/coh901327_wdt.c index ce12f437f1956..a099b77fc0b91 100644 --- a/drivers/watchdog/coh901327_wdt.c +++ b/drivers/watchdog/coh901327_wdt.c @@ -358,6 +358,7 @@ static int __init coh901327_probe(struct platform_device *pdev) if (ret < 0) coh901327_wdt.timeout = 60; + coh901327_wdt.parent = &pdev->dev; ret = watchdog_register_device(&coh901327_wdt); if (ret == 0) dev_info(&pdev->dev, diff --git a/drivers/watchdog/da9052_wdt.c b/drivers/watchdog/da9052_wdt.c index 2e9589652e1ee..67e67977bd29a 100644 --- a/drivers/watchdog/da9052_wdt.c +++ b/drivers/watchdog/da9052_wdt.c @@ -195,6 +195,7 @@ static int da9052_wdt_probe(struct platform_device *pdev) da9052_wdt->timeout = DA9052_DEF_TIMEOUT; da9052_wdt->info = &da9052_wdt_info; da9052_wdt->ops = &da9052_wdt_ops; + da9052_wdt->parent = &pdev->dev; watchdog_set_drvdata(da9052_wdt, driver_data); kref_init(&driver_data->kref); diff --git a/drivers/watchdog/da9055_wdt.c b/drivers/watchdog/da9055_wdt.c index 495089d8dbfeb..04d1430d93d20 100644 --- a/drivers/watchdog/da9055_wdt.c +++ b/drivers/watchdog/da9055_wdt.c @@ -161,6 +161,7 @@ static int da9055_wdt_probe(struct platform_device *pdev) da9055_wdt->timeout = DA9055_DEF_TIMEOUT; da9055_wdt->info = &da9055_wdt_info; da9055_wdt->ops = &da9055_wdt_ops; + da9055_wdt->parent = &pdev->dev; watchdog_set_nowayout(da9055_wdt, nowayout); watchdog_set_drvdata(da9055_wdt, driver_data); diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index b3a870ce85be7..7386111220d58 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -210,6 +210,7 @@ static int da9062_wdt_probe(struct platform_device *pdev) wdt->wdtdev.max_timeout = DA9062_WDT_MAX_TIMEOUT; wdt->wdtdev.timeout = DA9062_WDG_DEFAULT_TIMEOUT; wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; + wdt->wdtdev.parent = &pdev->dev; watchdog_set_drvdata(&wdt->wdtdev, wdt); dev_set_drvdata(&pdev->dev, wdt); diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c index e2fe2ebdebd4d..6bf130bd863d5 100644 --- a/drivers/watchdog/da9063_wdt.c +++ b/drivers/watchdog/da9063_wdt.c @@ -175,6 +175,7 @@ static int da9063_wdt_probe(struct platform_device *pdev) wdt->wdtdev.min_timeout = DA9063_WDT_MIN_TIMEOUT; wdt->wdtdev.max_timeout = DA9063_WDT_MAX_TIMEOUT; wdt->wdtdev.timeout = DA9063_WDG_TIMEOUT; + wdt->wdtdev.parent = &pdev->dev; wdt->wdtdev.status = WATCHDOG_NOWAYOUT_INIT_STATUS; diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index cfdf8a408aea0..17454ca653f42 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -179,6 +179,7 @@ static int davinci_wdt_probe(struct platform_device *pdev) wdd->min_timeout = 1; wdd->max_timeout = MAX_HEARTBEAT; wdd->timeout = DEFAULT_HEARTBEAT; + wdd->parent = &pdev->dev; watchdog_init_timeout(wdd, heartbeat, dev); diff --git a/drivers/watchdog/digicolor_wdt.c b/drivers/watchdog/digicolor_wdt.c index 31d8e4936611e..50abe1bf62a50 100644 --- a/drivers/watchdog/digicolor_wdt.c +++ b/drivers/watchdog/digicolor_wdt.c @@ -143,6 +143,7 @@ static int dc_wdt_probe(struct platform_device *pdev) } dc_wdt_wdd.max_timeout = U32_MAX / clk_get_rate(wdt->clk); dc_wdt_wdd.timeout = dc_wdt_wdd.max_timeout; + dc_wdt_wdd.parent = &pdev->dev; spin_lock_init(&wdt->lock); diff --git a/drivers/watchdog/ep93xx_wdt.c b/drivers/watchdog/ep93xx_wdt.c index 7a2cc7191c585..0a4d7cc05d543 100644 --- a/drivers/watchdog/ep93xx_wdt.c +++ b/drivers/watchdog/ep93xx_wdt.c @@ -132,6 +132,7 @@ static int ep93xx_wdt_probe(struct platform_device *pdev) val = readl(mmio_base + EP93XX_WATCHDOG); ep93xx_wdt_wdd.bootstatus = (val & 0x01) ? WDIOF_CARDRESET : 0; ep93xx_wdt_wdd.timeout = timeout; + ep93xx_wdt_wdd.parent = &pdev->dev; watchdog_set_nowayout(&ep93xx_wdt_wdd, nowayout); diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c index 5e16b0983e2ad..90d59d3f38a33 100644 --- a/drivers/watchdog/gpio_wdt.c +++ b/drivers/watchdog/gpio_wdt.c @@ -217,6 +217,7 @@ static int gpio_wdt_probe(struct platform_device *pdev) priv->wdd.ops = &gpio_wdt_ops; priv->wdd.min_timeout = SOFT_TIMEOUT_MIN; priv->wdd.max_timeout = SOFT_TIMEOUT_MAX; + priv->wdd.parent = &pdev->dev; if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0) priv->wdd.timeout = SOFT_TIMEOUT_DEF; diff --git a/drivers/watchdog/ie6xx_wdt.c b/drivers/watchdog/ie6xx_wdt.c index 9bc39ae51624c..78c2541f5d52d 100644 --- a/drivers/watchdog/ie6xx_wdt.c +++ b/drivers/watchdog/ie6xx_wdt.c @@ -267,6 +267,7 @@ static int ie6xx_wdt_probe(struct platform_device *pdev) ie6xx_wdt_dev.timeout = timeout; watchdog_set_nowayout(&ie6xx_wdt_dev, nowayout); + ie6xx_wdt_dev.parent = &pdev->dev; spin_lock_init(&ie6xx_wdt_data.unlock_sequence); diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index 84f6701c391fc..0a436b5d1e844 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -137,6 +137,7 @@ static int mid_wdt_probe(struct platform_device *pdev) wdt_dev->min_timeout = MID_WDT_TIMEOUT_MIN; wdt_dev->max_timeout = MID_WDT_TIMEOUT_MAX; wdt_dev->timeout = MID_WDT_DEFAULT_TIMEOUT; + wdt_dev->parent = &pdev->dev; watchdog_set_drvdata(wdt_dev, &pdev->dev); platform_set_drvdata(pdev, wdt_dev); diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index 4c2cc09c0c578..6a7d5c3654381 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c @@ -174,6 +174,7 @@ static int jz4740_wdt_probe(struct platform_device *pdev) jz4740_wdt->timeout = heartbeat; jz4740_wdt->min_timeout = 1; jz4740_wdt->max_timeout = MAX_HEARTBEAT; + jz4740_wdt->parent = &pdev->dev; watchdog_set_nowayout(jz4740_wdt, nowayout); watchdog_set_drvdata(jz4740_wdt, drvdata); diff --git a/drivers/watchdog/mena21_wdt.c b/drivers/watchdog/mena21_wdt.c index d193a5e79c381..69013007dc470 100644 --- a/drivers/watchdog/mena21_wdt.c +++ b/drivers/watchdog/mena21_wdt.c @@ -197,6 +197,7 @@ static int a21_wdt_probe(struct platform_device *pdev) watchdog_init_timeout(&a21_wdt, 30, &pdev->dev); watchdog_set_nowayout(&a21_wdt, nowayout); watchdog_set_drvdata(&a21_wdt, drv); + a21_wdt.parent = &pdev->dev; reset = a21_wdt_get_bootstatus(drv); if (reset == 2) diff --git a/drivers/watchdog/menf21bmc_wdt.c b/drivers/watchdog/menf21bmc_wdt.c index 59f0913c73412..3aefddebb3861 100644 --- a/drivers/watchdog/menf21bmc_wdt.c +++ b/drivers/watchdog/menf21bmc_wdt.c @@ -130,6 +130,7 @@ static int menf21bmc_wdt_probe(struct platform_device *pdev) drv_data->wdt.info = &menf21bmc_wdt_info; drv_data->wdt.min_timeout = BMC_WD_TIMEOUT_MIN; drv_data->wdt.max_timeout = BMC_WD_TIMEOUT_MAX; + drv_data->wdt.parent = &pdev->dev; drv_data->i2c_client = i2c_client; /* diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c index de911c7e477c2..d96bee017fd3c 100644 --- a/drivers/watchdog/omap_wdt.c +++ b/drivers/watchdog/omap_wdt.c @@ -253,6 +253,7 @@ static int omap_wdt_probe(struct platform_device *pdev) wdev->wdog.ops = &omap_wdt_ops; wdev->wdog.min_timeout = TIMER_MARGIN_MIN; wdev->wdog.max_timeout = TIMER_MARGIN_MAX; + wdev->wdog.parent = &pdev->dev; if (watchdog_init_timeout(&wdev->wdog, timer_margin, &pdev->dev) < 0) wdev->wdog.timeout = TIMER_MARGIN_DEFAULT; diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index ef0c628d50379..c6b8f4a43bdef 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -567,6 +567,7 @@ static int orion_wdt_probe(struct platform_device *pdev) dev->wdt.timeout = wdt_max_duration; dev->wdt.max_timeout = wdt_max_duration; + dev->wdt.parent = &pdev->dev; watchdog_init_timeout(&dev->wdt, heartbeat, &pdev->dev); platform_set_drvdata(pdev, &dev->wdt); diff --git a/drivers/watchdog/pnx4008_wdt.c b/drivers/watchdog/pnx4008_wdt.c index b9c6049c3e786..4224b3ec83a55 100644 --- a/drivers/watchdog/pnx4008_wdt.c +++ b/drivers/watchdog/pnx4008_wdt.c @@ -167,6 +167,7 @@ static int pnx4008_wdt_probe(struct platform_device *pdev) pnx4008_wdd.bootstatus = (readl(WDTIM_RES(wdt_base)) & WDOG_RESET) ? WDIOF_CARDRESET : 0; + pnx4008_wdd.parent = &pdev->dev; watchdog_set_nowayout(&pnx4008_wdd, nowayout); pnx4008_wdt_stop(&pnx4008_wdd); /* disable for now */ diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index aa03ca8f2d9b0..773dcfaee7b2f 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -171,6 +171,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) wdt->wdd.ops = &qcom_wdt_ops; wdt->wdd.min_timeout = 1; wdt->wdd.max_timeout = 0x10000000U / wdt->rate; + wdt->wdd.parent = &pdev->dev; /* * If 'timeout-sec' unspecified in devicetree, assume a 30 second diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c index b7c68e275aeb3..39cd51df2ffc7 100644 --- a/drivers/watchdog/retu_wdt.c +++ b/drivers/watchdog/retu_wdt.c @@ -127,6 +127,7 @@ static int retu_wdt_probe(struct platform_device *pdev) retu_wdt->timeout = RETU_WDT_MAX_TIMER; retu_wdt->min_timeout = 0; retu_wdt->max_timeout = RETU_WDT_MAX_TIMER; + retu_wdt->parent = &pdev->dev; watchdog_set_drvdata(retu_wdt, wdev); watchdog_set_nowayout(retu_wdt, nowayout); diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c index a6f7e2e29bebb..1967919ae7433 100644 --- a/drivers/watchdog/rt2880_wdt.c +++ b/drivers/watchdog/rt2880_wdt.c @@ -161,6 +161,7 @@ static int rt288x_wdt_probe(struct platform_device *pdev) rt288x_wdt_dev.dev = &pdev->dev; rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause(); rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq); + rt288x_wdt_dev.parent = &pdev->dev; watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout, &pdev->dev); diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c index e89ae027c91db..d781000c78250 100644 --- a/drivers/watchdog/s3c2410_wdt.c +++ b/drivers/watchdog/s3c2410_wdt.c @@ -607,6 +607,7 @@ static int s3c2410wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&wdt->wdt_device, nowayout); wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt); + wdt->wdt_device.parent = &pdev->dev; ret = watchdog_register_device(&wdt->wdt_device); if (ret) { diff --git a/drivers/watchdog/shwdt.c b/drivers/watchdog/shwdt.c index 567458b137a67..f908121706579 100644 --- a/drivers/watchdog/shwdt.c +++ b/drivers/watchdog/shwdt.c @@ -252,6 +252,7 @@ static int sh_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&sh_wdt_dev, nowayout); watchdog_set_drvdata(&sh_wdt_dev, wdt); + sh_wdt_dev.parent = &pdev->dev; spin_lock_init(&wdt->lock); diff --git a/drivers/watchdog/sirfsoc_wdt.c b/drivers/watchdog/sirfsoc_wdt.c index 42fa5c0c518ab..d0578ab2e636d 100644 --- a/drivers/watchdog/sirfsoc_wdt.c +++ b/drivers/watchdog/sirfsoc_wdt.c @@ -154,6 +154,7 @@ static int sirfsoc_wdt_probe(struct platform_device *pdev) watchdog_init_timeout(&sirfsoc_wdd, timeout, &pdev->dev); watchdog_set_nowayout(&sirfsoc_wdd, nowayout); + sirfsoc_wdd.parent = &pdev->dev; ret = watchdog_register_device(&sirfsoc_wdd); if (ret) diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c index 4e7fec36f5c36..01d816251302c 100644 --- a/drivers/watchdog/sp805_wdt.c +++ b/drivers/watchdog/sp805_wdt.c @@ -226,6 +226,7 @@ sp805_wdt_probe(struct amba_device *adev, const struct amba_id *id) wdt->adev = adev; wdt->wdd.info = &wdt_info; wdt->wdd.ops = &wdt_ops; + wdt->wdd.parent = &adev->dev; spin_lock_init(&wdt->lock); watchdog_set_nowayout(&wdt->wdd, nowayout); diff --git a/drivers/watchdog/st_lpc_wdt.c b/drivers/watchdog/st_lpc_wdt.c index 6785afdc0fcaa..14e9badf2bfa3 100644 --- a/drivers/watchdog/st_lpc_wdt.c +++ b/drivers/watchdog/st_lpc_wdt.c @@ -241,6 +241,7 @@ static int st_wdog_probe(struct platform_device *pdev) return -EINVAL; } st_wdog_dev.max_timeout = 0xFFFFFFFF / st_wdog->clkrate; + st_wdog_dev.parent = &pdev->dev; ret = clk_prepare_enable(clk); if (ret) { diff --git a/drivers/watchdog/stmp3xxx_rtc_wdt.c b/drivers/watchdog/stmp3xxx_rtc_wdt.c index e7f0d5b60d3d4..3ee6128a540e9 100644 --- a/drivers/watchdog/stmp3xxx_rtc_wdt.c +++ b/drivers/watchdog/stmp3xxx_rtc_wdt.c @@ -76,6 +76,7 @@ static int stmp3xxx_wdt_probe(struct platform_device *pdev) watchdog_set_drvdata(&stmp3xxx_wdd, &pdev->dev); stmp3xxx_wdd.timeout = clamp_t(unsigned, heartbeat, 1, STMP3XXX_MAX_TIMEOUT); + stmp3xxx_wdd.parent = &pdev->dev; ret = watchdog_register_device(&stmp3xxx_wdd); if (ret < 0) { diff --git a/drivers/watchdog/tegra_wdt.c b/drivers/watchdog/tegra_wdt.c index 30451ea469023..7f97cdd53f296 100644 --- a/drivers/watchdog/tegra_wdt.c +++ b/drivers/watchdog/tegra_wdt.c @@ -218,6 +218,7 @@ static int tegra_wdt_probe(struct platform_device *pdev) wdd->ops = &tegra_wdt_ops; wdd->min_timeout = MIN_WDT_TIMEOUT; wdd->max_timeout = MAX_WDT_TIMEOUT; + wdd->parent = &pdev->dev; watchdog_set_drvdata(wdd, wdt); diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c index 2c1db6fa9a272..9bf3cc0f39610 100644 --- a/drivers/watchdog/twl4030_wdt.c +++ b/drivers/watchdog/twl4030_wdt.c @@ -83,6 +83,7 @@ static int twl4030_wdt_probe(struct platform_device *pdev) wdt->timeout = 30; wdt->min_timeout = 1; wdt->max_timeout = 30; + wdt->parent = &pdev->dev; watchdog_set_nowayout(wdt, nowayout); platform_set_drvdata(pdev, wdt); diff --git a/drivers/watchdog/txx9wdt.c b/drivers/watchdog/txx9wdt.c index 7f615933d31a1..c2da880292bc2 100644 --- a/drivers/watchdog/txx9wdt.c +++ b/drivers/watchdog/txx9wdt.c @@ -131,6 +131,7 @@ static int __init txx9wdt_probe(struct platform_device *dev) txx9wdt.timeout = timeout; txx9wdt.min_timeout = 1; txx9wdt.max_timeout = WD_MAX_TIMEOUT; + txx9wdt.parent = &dev->dev; watchdog_set_nowayout(&txx9wdt, nowayout); ret = watchdog_register_device(&txx9wdt); diff --git a/drivers/watchdog/ux500_wdt.c b/drivers/watchdog/ux500_wdt.c index 9de09ab008380..37c084353cce2 100644 --- a/drivers/watchdog/ux500_wdt.c +++ b/drivers/watchdog/ux500_wdt.c @@ -96,6 +96,7 @@ static int ux500_wdt_probe(struct platform_device *pdev) ux500_wdt.max_timeout = WATCHDOG_MAX28; } + ux500_wdt.parent = &pdev->dev; watchdog_set_nowayout(&ux500_wdt, nowayout); /* disable auto off on sleep */ diff --git a/drivers/watchdog/via_wdt.c b/drivers/watchdog/via_wdt.c index 56369c4f1961d..5f9cbc37520d2 100644 --- a/drivers/watchdog/via_wdt.c +++ b/drivers/watchdog/via_wdt.c @@ -206,6 +206,7 @@ static int wdt_probe(struct pci_dev *pdev, timeout = WDT_TIMEOUT; wdt_dev.timeout = timeout; + wdt_dev.parent = &pdev->dev; watchdog_set_nowayout(&wdt_dev, nowayout); if (readl(wdt_mem) & VIA_WDT_FIRED) wdt_dev.bootstatus |= WDIOF_CARDRESET; diff --git a/drivers/watchdog/wm831x_wdt.c b/drivers/watchdog/wm831x_wdt.c index 2fa17e746ff6f..8d1184aee932e 100644 --- a/drivers/watchdog/wm831x_wdt.c +++ b/drivers/watchdog/wm831x_wdt.c @@ -215,6 +215,7 @@ static int wm831x_wdt_probe(struct platform_device *pdev) wm831x_wdt->info = &wm831x_wdt_info; wm831x_wdt->ops = &wm831x_wdt_ops; + wm831x_wdt->parent = &pdev->dev; watchdog_set_nowayout(wm831x_wdt, nowayout); watchdog_set_drvdata(wm831x_wdt, driver_data); diff --git a/drivers/watchdog/wm8350_wdt.c b/drivers/watchdog/wm8350_wdt.c index 34d272ada23d5..4ab4b8347d459 100644 --- a/drivers/watchdog/wm8350_wdt.c +++ b/drivers/watchdog/wm8350_wdt.c @@ -151,6 +151,7 @@ static int wm8350_wdt_probe(struct platform_device *pdev) watchdog_set_nowayout(&wm8350_wdt, nowayout); watchdog_set_drvdata(&wm8350_wdt, wm8350); + wm8350_wdt.parent = &pdev->dev; /* Default to 4s timeout */ wm8350_wdt_set_timeout(&wm8350_wdt, 4); -- GitLab From 592867bfabe2fcb449393ba7eb0de4f972a08c63 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Tue, 8 Sep 2015 18:00:09 +0200 Subject: [PATCH 6855/7006] ebpf: fix fd refcount leaks related to maps in bpf syscall We may already have gotten a proper fd struct through fdget(), so whenever we return at the end of an map operation, we need to call fdput(). However, each map operation from syscall side first probes CHECK_ATTR() to verify that unused fields in the bpf_attr union are zero. In case of malformed input, we return with error, but the lookup to the map_fd was already performed at that time, so that we return without an corresponding fdput(). Fix it by performing an fdget() only right before bpf_map_get(). The fdget() invocation on maps in the verifier is not affected. Fixes: db20fd2b0108 ("bpf: add lookup/update/delete/iterate methods to BPF maps") Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Signed-off-by: David S. Miller --- kernel/bpf/syscall.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index dc9b464fefa95..35bac8e8b071a 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -155,14 +155,15 @@ static int map_lookup_elem(union bpf_attr *attr) void __user *ukey = u64_to_ptr(attr->key); void __user *uvalue = u64_to_ptr(attr->value); int ufd = attr->map_fd; - struct fd f = fdget(ufd); struct bpf_map *map; void *key, *value, *ptr; + struct fd f; int err; if (CHECK_ATTR(BPF_MAP_LOOKUP_ELEM)) return -EINVAL; + f = fdget(ufd); map = bpf_map_get(f); if (IS_ERR(map)) return PTR_ERR(map); @@ -213,14 +214,15 @@ static int map_update_elem(union bpf_attr *attr) void __user *ukey = u64_to_ptr(attr->key); void __user *uvalue = u64_to_ptr(attr->value); int ufd = attr->map_fd; - struct fd f = fdget(ufd); struct bpf_map *map; void *key, *value; + struct fd f; int err; if (CHECK_ATTR(BPF_MAP_UPDATE_ELEM)) return -EINVAL; + f = fdget(ufd); map = bpf_map_get(f); if (IS_ERR(map)) return PTR_ERR(map); @@ -265,14 +267,15 @@ static int map_delete_elem(union bpf_attr *attr) { void __user *ukey = u64_to_ptr(attr->key); int ufd = attr->map_fd; - struct fd f = fdget(ufd); struct bpf_map *map; + struct fd f; void *key; int err; if (CHECK_ATTR(BPF_MAP_DELETE_ELEM)) return -EINVAL; + f = fdget(ufd); map = bpf_map_get(f); if (IS_ERR(map)) return PTR_ERR(map); @@ -305,14 +308,15 @@ static int map_get_next_key(union bpf_attr *attr) void __user *ukey = u64_to_ptr(attr->key); void __user *unext_key = u64_to_ptr(attr->next_key); int ufd = attr->map_fd; - struct fd f = fdget(ufd); struct bpf_map *map; void *key, *next_key; + struct fd f; int err; if (CHECK_ATTR(BPF_MAP_GET_NEXT_KEY)) return -EINVAL; + f = fdget(ufd); map = bpf_map_get(f); if (IS_ERR(map)) return PTR_ERR(map); -- GitLab From 10bfcfea9bbe91adf79cc4efc9c764edd0cbadda Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:44 -0700 Subject: [PATCH 6856/7006] ARM: dts: qcom: Label serial nodes for aliasing and stdout-path Add a label to the serial nodes that are being used for the console. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-apq8084.dtsi | 2 +- arch/arm/boot/dts/qcom-ipq8064.dtsi | 2 +- arch/arm/boot/dts/qcom-msm8660.dtsi | 2 +- arch/arm/boot/dts/qcom-msm8960.dtsi | 2 +- arch/arm/boot/dts/qcom-msm8974.dtsi | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/arch/arm/boot/dts/qcom-apq8084.dtsi b/arch/arm/boot/dts/qcom-apq8084.dtsi index 7084010ee61ba..0554fbd72c40b 100644 --- a/arch/arm/boot/dts/qcom-apq8084.dtsi +++ b/arch/arm/boot/dts/qcom-apq8084.dtsi @@ -234,7 +234,7 @@ interrupts = <0 208 0>; }; - serial@f995e000 { + blsp2_uart2: serial@f995e000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xf995e000 0x1000>; interrupts = <0 114 0x0>; diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi index 9f727d8eadf69..fa698635eea0d 100644 --- a/arch/arm/boot/dts/qcom-ipq8064.dtsi +++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi @@ -197,7 +197,7 @@ syscon-tcsr = <&tcsr>; - serial@16340000 { + gsbi4_serial: serial@16340000 { compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x16340000 0x1000>, <0x16300000 0x1000>; diff --git a/arch/arm/boot/dts/qcom-msm8660.dtsi b/arch/arm/boot/dts/qcom-msm8660.dtsi index ef2fe72b54c91..e5f7f33aa4677 100644 --- a/arch/arm/boot/dts/qcom-msm8660.dtsi +++ b/arch/arm/boot/dts/qcom-msm8660.dtsi @@ -98,7 +98,7 @@ syscon-tcsr = <&tcsr>; - serial@19c40000 { + gsbi12_serial: serial@19c40000 { compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x19c40000 0x1000>, <0x19c00000 0x1000>; diff --git a/arch/arm/boot/dts/qcom-msm8960.dtsi b/arch/arm/boot/dts/qcom-msm8960.dtsi index 2096a94c9b525..134cd91d68ece 100644 --- a/arch/arm/boot/dts/qcom-msm8960.dtsi +++ b/arch/arm/boot/dts/qcom-msm8960.dtsi @@ -157,7 +157,7 @@ syscon-tcsr = <&tcsr>; - serial@16440000 { + gsbi5_serial: serial@16440000 { compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm"; reg = <0x16440000 0x1000>, <0x16400000 0x1000>; diff --git a/arch/arm/boot/dts/qcom-msm8974.dtsi b/arch/arm/boot/dts/qcom-msm8974.dtsi index d7c99b894a491..ab8e572504680 100644 --- a/arch/arm/boot/dts/qcom-msm8974.dtsi +++ b/arch/arm/boot/dts/qcom-msm8974.dtsi @@ -259,7 +259,7 @@ hwlocks = <&tcsr_mutex 3>; }; - serial@f991e000 { + blsp1_uart2: serial@f991e000 { compatible = "qcom,msm-uartdm-v1.4", "qcom,msm-uartdm"; reg = <0xf991e000 0x1000>; interrupts = <0 108 0x0>; -- GitLab From 4e19db11e99b27bdd4817c3d58a7ead7af8d7d7c Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:45 -0700 Subject: [PATCH 6857/7006] ARM: dts: qcom: apq8064-cm-qs600: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Cc: Mike Rapoport Cc: Igor Grinberg Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts index 34ccb260f12a9..47c0282bdfca7 100644 --- a/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts +++ b/arch/arm/boot/dts/qcom-apq8064-cm-qs600.dts @@ -4,6 +4,14 @@ model = "CompuLab CM-QS600"; compatible = "qcom,apq8064-cm-qs600", "qcom,apq8064"; + aliases { + serial0 = &gsbi7_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { pinctrl@800000 { i2c1_pins: i2c1 { -- GitLab From 7f9e28b61057da3a4aa56a79436916a821e63a35 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:46 -0700 Subject: [PATCH 6858/7006] ARM: dts: qcom: apq8064-ifc6410: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-apq8064-ifc6410.dts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts index 88d6655ddaf6d..f3100da082b2a 100644 --- a/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts +++ b/arch/arm/boot/dts/qcom-apq8064-ifc6410.dts @@ -10,6 +10,10 @@ serial1 = &gsbi6_serial; }; + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { pinctrl@800000 { card_detect: card_detect { -- GitLab From 5f769789bdec38c1d5b19a8743924daf87f5d023 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:47 -0700 Subject: [PATCH 6859/7006] ARM: dts: qcom: apq8074-dragonboard: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-apq8074-dragonboard.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts b/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts index d484d08163e94..835bdc71c5ba4 100644 --- a/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts +++ b/arch/arm/boot/dts/qcom-apq8074-dragonboard.dts @@ -6,6 +6,14 @@ model = "Qualcomm APQ8074 Dragonboard"; compatible = "qcom,apq8074-dragonboard", "qcom,apq8074"; + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { serial@f991e000 { status = "ok"; -- GitLab From d92c945d854f9d973d3a0836548c93ed249b8f3a Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:48 -0700 Subject: [PATCH 6860/7006] ARM: dts: qcom: apq8084-ifc6540: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-apq8084-ifc6540.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts b/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts index f7725b96612c6..c9c2b769554f8 100644 --- a/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts +++ b/arch/arm/boot/dts/qcom-apq8084-ifc6540.dts @@ -5,6 +5,14 @@ model = "Qualcomm APQ8084/IFC6540"; compatible = "qcom,apq8084-ifc6540", "qcom,apq8084"; + aliases { + serial0 = &blsp2_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { serial@f995e000 { status = "okay"; -- GitLab From ccfdf7cd7dfaa4140702ff43d760d0eb1578d725 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:49 -0700 Subject: [PATCH 6861/7006] ARM: dts: qcom: apq8084-mtp: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-apq8084-mtp.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-apq8084-mtp.dts b/arch/arm/boot/dts/qcom-apq8084-mtp.dts index cb43acfc5d1d9..3016c7048d446 100644 --- a/arch/arm/boot/dts/qcom-apq8084-mtp.dts +++ b/arch/arm/boot/dts/qcom-apq8084-mtp.dts @@ -5,6 +5,14 @@ model = "Qualcomm APQ 8084-MTP"; compatible = "qcom,apq8084-mtp", "qcom,apq8084"; + aliases { + serial0 = &blsp2_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { serial@f995e000 { status = "okay"; -- GitLab From 9a61b3a39a88b955d89c5f19e01b0b19185ebce6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:50 -0700 Subject: [PATCH 6862/7006] ARM: dts: qcom: ipq8064-ap148: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Cc: Mathieu Olivari Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts index 55b2910efd872..d501382493e3d 100644 --- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts +++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts @@ -4,6 +4,14 @@ model = "Qualcomm IPQ8064/AP148"; compatible = "qcom,ipq8064-ap148", "qcom,ipq8064"; + aliases { + serial0 = &gsbi4_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + reserved-memory { #address-cells = <1>; #size-cells = <1>; -- GitLab From a96731089e8e0d550f017359dacaee19463517c7 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:51 -0700 Subject: [PATCH 6863/7006] ARM: dts: qcom: msm8660-surf: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-msm8660-surf.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8660-surf.dts b/arch/arm/boot/dts/qcom-msm8660-surf.dts index e0883c3762480..b17f379e8c2af 100644 --- a/arch/arm/boot/dts/qcom-msm8660-surf.dts +++ b/arch/arm/boot/dts/qcom-msm8660-surf.dts @@ -6,6 +6,14 @@ model = "Qualcomm MSM8660 SURF"; compatible = "qcom,msm8660-surf", "qcom,msm8660"; + aliases { + serial0 = &gsbi12_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { gsbi@19c00000 { status = "ok"; -- GitLab From c0ed595961c44beea0d0dc3b0e2b1ef354931bdf Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:52 -0700 Subject: [PATCH 6864/7006] ARM: dts: qcom: msm8960-cdp: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-msm8960-cdp.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8960-cdp.dts b/arch/arm/boot/dts/qcom-msm8960-cdp.dts index fad71d5527b0f..b72a55462caf1 100644 --- a/arch/arm/boot/dts/qcom-msm8960-cdp.dts +++ b/arch/arm/boot/dts/qcom-msm8960-cdp.dts @@ -6,6 +6,14 @@ model = "Qualcomm MSM8960 CDP"; compatible = "qcom,msm8960-cdp", "qcom,msm8960"; + aliases { + serial0 = &gsbi5_serial; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + soc { gsbi@16400000 { status = "ok"; -- GitLab From 8f1dc3cf8f1e617ec888bcdb69111aae9bf4a9e0 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Tue, 16 Jun 2015 14:31:53 -0700 Subject: [PATCH 6865/7006] ARM: dts: qcom: msm8974-sony-xperia-honami: Use stdout-path Use stdout-path so that we don't have to put the console on the kernel command line. Cc: Tim Bird Cc: Bjorn Andersson Signed-off-by: Stephen Boyd --- arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts index bd35b0674ff68..eb547f1f6a605 100644 --- a/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts +++ b/arch/arm/boot/dts/qcom-msm8974-sony-xperia-honami.dts @@ -6,6 +6,14 @@ model = "Sony Xperia Z1"; compatible = "sony,xperia-honami", "qcom,msm8974"; + aliases { + serial0 = &blsp1_uart2; + }; + + chosen { + stdout-path = "serial0:115200n8"; + }; + memory@0 { reg = <0 0x40000000>, <0x40000000 0x40000000>; device_type = "memory"; -- GitLab From 1b2b90cbea00670221f062814dc8bcecb3af7b90 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Wed, 9 Sep 2015 16:58:22 +0530 Subject: [PATCH 6866/7006] PM / OPP: Return suspend_opp only if it is enabled There is no point returning suspend_opp, if it is disabled by the core. As we can't use it at all. Fix it. Fixes: 4eafbd15b6c8 ("PM / OPP: add dev_pm_opp_get_suspend_opp() helper") Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki --- drivers/base/power/opp.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c index 3df62dbcec3ad..4eff4cd7eb546 100644 --- a/drivers/base/power/opp.c +++ b/drivers/base/power/opp.c @@ -345,7 +345,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); * @dev: device for which we do this operation * * Return: This function returns pointer to the suspend opp if it is - * defined, otherwise it returns NULL. + * defined and available, otherwise it returns NULL. * * Locking: This function must be called under rcu_read_lock(). opp is a rcu * protected pointer. The reason for the same is that the opp pointer which is @@ -356,17 +356,15 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_max_clock_latency); struct dev_pm_opp *dev_pm_opp_get_suspend_opp(struct device *dev) { struct device_opp *dev_opp; - struct dev_pm_opp *opp; opp_rcu_lockdep_assert(); dev_opp = _find_device_opp(dev); - if (IS_ERR(dev_opp)) - opp = NULL; - else - opp = dev_opp->suspend_opp; + if (IS_ERR(dev_opp) || !dev_opp->suspend_opp || + !dev_opp->suspend_opp->available) + return NULL; - return opp; + return dev_opp->suspend_opp; } EXPORT_SYMBOL_GPL(dev_pm_opp_get_suspend_opp); -- GitLab From 43717aadd2bc87fb10fbf1cd815c1cbae9bb95b3 Mon Sep 17 00:00:00 2001 From: Chen Yu Date: Wed, 9 Sep 2015 18:27:31 +0800 Subject: [PATCH 6867/7006] intel_pstate: Fix user input of min/max to legal policy region In current code, max_perf_pct might be smaller than min_perf_pct by improper user input: $ grep . /sys/devices/system/cpu/intel_pstate/m*_perf_pct /sys/devices/system/cpu/intel_pstate/max_perf_pct:100 /sys/devices/system/cpu/intel_pstate/min_perf_pct:100 $ echo 80 > /sys/devices/system/cpu/intel_pstate/max_perf_pct $ grep . /sys/devices/system/cpu/intel_pstate/m*_perf_pct /sys/devices/system/cpu/intel_pstate/max_perf_pct:80 /sys/devices/system/cpu/intel_pstate/min_perf_pct:100 Fix this problem by 2 steps: 1. Normalize the user input to [min_policy, max_policy]. 2. Make sure max_perf_pct>=min_perf_pct, suggested by Seiichi Ikarashi. Signed-off-by: Chen Yu Acked-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 31d0548638e89..63075cc4a4762 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -423,6 +423,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b, limits.max_sysfs_pct = clamp_t(int, input, 0 , 100); limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); + limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct); + limits.max_perf_pct = max(limits.min_perf_pct, limits.max_perf_pct); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); if (hwp_active) @@ -442,6 +444,8 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b, limits.min_sysfs_pct = clamp_t(int, input, 0 , 100); limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); + limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct); + limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct); limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); if (hwp_active) @@ -989,12 +993,19 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy) limits.min_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq; limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100); - limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); - limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); - limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq; limits.max_policy_pct = clamp_t(int, limits.max_policy_pct, 0 , 100); + + /* Normalize user input to [min_policy_pct, max_policy_pct] */ + limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct); + limits.min_perf_pct = min(limits.max_policy_pct, limits.min_perf_pct); limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct); + limits.max_perf_pct = max(limits.min_policy_pct, limits.max_perf_pct); + + /* Make sure min_perf_pct <= max_perf_pct */ + limits.min_perf_pct = min(limits.max_perf_pct, limits.min_perf_pct); + + limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100)); limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100)); if (hwp_active) -- GitLab From 74da56ce5c6715630aed3ccc0fcb86a9210c1a56 Mon Sep 17 00:00:00 2001 From: Kristen Carlson Accardi Date: Wed, 9 Sep 2015 11:41:22 -0700 Subject: [PATCH 6868/7006] intel_pstate: fix PCT_TO_HWP macro PCT_TO_HWP does not take the actual range of pstates exported by HWP_CAPABILITIES in account, and is broken on most platforms. Remove the macro and set the min and max pstate for hwp by determining the range and adjusting by the min and max percent limits values. Signed-off-by: Kristen Carlson Accardi Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/intel_pstate.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index 63075cc4a4762..27faee5f0e237 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c @@ -260,24 +260,31 @@ static inline void update_turbo_state(void) cpu->pstate.max_pstate == cpu->pstate.turbo_pstate); } -#define PCT_TO_HWP(x) (x * 255 / 100) static void intel_pstate_hwp_set(void) { - int min, max, cpu; - u64 value, freq; + int min, hw_min, max, hw_max, cpu, range, adj_range; + u64 value, cap; + + rdmsrl(MSR_HWP_CAPABILITIES, cap); + hw_min = HWP_LOWEST_PERF(cap); + hw_max = HWP_HIGHEST_PERF(cap); + range = hw_max - hw_min; get_online_cpus(); for_each_online_cpu(cpu) { rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value); - min = PCT_TO_HWP(limits.min_perf_pct); + adj_range = limits.min_perf_pct * range / 100; + min = hw_min + adj_range; value &= ~HWP_MIN_PERF(~0L); value |= HWP_MIN_PERF(min); - max = PCT_TO_HWP(limits.max_perf_pct); + adj_range = limits.max_perf_pct * range / 100; + max = hw_min + adj_range; if (limits.no_turbo) { - rdmsrl( MSR_HWP_CAPABILITIES, freq); - max = HWP_GUARANTEED_PERF(freq); + hw_max = HWP_GUARANTEED_PERF(cap); + if (hw_max < max) + max = hw_max; } value &= ~HWP_MAX_PERF(~0L); -- GitLab From 18912806bbf8bd6e2b5cb12317679790eb0e0ce4 Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Tue, 11 Aug 2015 23:48:15 -0500 Subject: [PATCH 6869/7006] soc: qcom: smem: Fix errant private access This patch corrects private partition item access. Instead of falling back to global for instances where we have an actual host and remote partition existing, return the results of the private lookup. Signed-off-by: Andy Gross --- drivers/soc/qcom/smem.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/soc/qcom/smem.c b/drivers/soc/qcom/smem.c index 7c2c324c4b10c..52365188a1c20 100644 --- a/drivers/soc/qcom/smem.c +++ b/drivers/soc/qcom/smem.c @@ -258,10 +258,6 @@ static int qcom_smem_alloc_private(struct qcom_smem *smem, size_t alloc_size; void *p; - /* We're not going to find it if there's no matching partition */ - if (host >= SMEM_HOST_COUNT || !smem->partitions[host]) - return -ENOENT; - phdr = smem->partitions[host]; p = (void *)phdr + sizeof(*phdr); @@ -371,8 +367,9 @@ int qcom_smem_alloc(unsigned host, unsigned item, size_t size) if (ret) return ret; - ret = qcom_smem_alloc_private(__smem, host, item, size); - if (ret == -ENOENT) + if (host < SMEM_HOST_COUNT && __smem->partitions[host]) + ret = qcom_smem_alloc_private(__smem, host, item, size); + else ret = qcom_smem_alloc_global(__smem, item, size); hwspin_unlock_irqrestore(__smem->hwlock, &flags); @@ -428,10 +425,6 @@ static int qcom_smem_get_private(struct qcom_smem *smem, struct smem_private_entry *hdr; void *p; - /* We're not going to find it if there's no matching partition */ - if (host >= SMEM_HOST_COUNT || !smem->partitions[host]) - return -ENOENT; - phdr = smem->partitions[host]; p = (void *)phdr + sizeof(*phdr); @@ -484,8 +477,9 @@ int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size) if (ret) return ret; - ret = qcom_smem_get_private(__smem, host, item, ptr, size); - if (ret == -ENOENT) + if (host < SMEM_HOST_COUNT && __smem->partitions[host]) + ret = qcom_smem_get_private(__smem, host, item, ptr, size); + else ret = qcom_smem_get_global(__smem, item, ptr, size); hwspin_unlock_irqrestore(__smem->hwlock, &flags); -- GitLab From 93dbed9121cc8e0fcc93edd9fca901322bdfbd1a Mon Sep 17 00:00:00 2001 From: Andy Gross Date: Wed, 26 Aug 2015 14:42:45 -0500 Subject: [PATCH 6870/7006] soc: qcom: smd: Use correct remote processor ID This patch fixes SMEM addressing issues when remote processors need to use secure SMEM partitions. Signed-off-by: Andy Gross Reviewed-by: Bjorn Andersson --- .../devicetree/bindings/soc/qcom/qcom,smd.txt | 6 ++++++ drivers/soc/qcom/smd.c | 16 ++++++++++++---- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt index f65c76db98599..97d9b3e1bf399 100644 --- a/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smd.txt @@ -37,6 +37,12 @@ The edge is described by the following properties: Definition: the identifier of the remote processor in the smd channel allocation table +- qcom,remote-pid: + Usage: optional + Value type: + Definition: the identifier for the remote processor as known by the rest + of the system. + = SMD DEVICES In turn, subnodes of the "edges" represent devices tied to SMD channels on that diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index 327adcf117c18..edd9d9a372385 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -96,6 +96,7 @@ static const struct { * @smd: handle to qcom_smd * @of_node: of_node handle for information related to this edge * @edge_id: identifier of this edge + * @remote_pid: identifier of remote processor * @irq: interrupt for signals on this edge * @ipc_regmap: regmap handle holding the outgoing ipc register * @ipc_offset: offset within @ipc_regmap of the register for ipc @@ -111,6 +112,7 @@ struct qcom_smd_edge { struct qcom_smd *smd; struct device_node *of_node; unsigned edge_id; + unsigned remote_pid; int irq; @@ -572,7 +574,7 @@ static irqreturn_t qcom_smd_edge_intr(int irq, void *data) * have to scan if the amount of available space in smem have changed * since last scan. */ - available = qcom_smem_get_free_space(edge->edge_id); + available = qcom_smem_get_free_space(edge->remote_pid); if (available != edge->smem_available) { edge->smem_available = available; edge->need_rescan = true; @@ -976,7 +978,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed spin_lock_init(&channel->recv_lock); init_waitqueue_head(&channel->fblockread_event); - ret = qcom_smem_get(edge->edge_id, smem_info_item, (void **)&info, &info_size); + ret = qcom_smem_get(edge->remote_pid, smem_info_item, (void **)&info, + &info_size); if (ret) goto free_name_and_channel; @@ -997,7 +1000,8 @@ static struct qcom_smd_channel *qcom_smd_create_channel(struct qcom_smd_edge *ed goto free_name_and_channel; } - ret = qcom_smem_get(edge->edge_id, smem_fifo_item, &fifo_base, &fifo_size); + ret = qcom_smem_get(edge->remote_pid, smem_fifo_item, &fifo_base, + &fifo_size); if (ret) goto free_name_and_channel; @@ -1041,7 +1045,7 @@ static void qcom_discover_channels(struct qcom_smd_edge *edge) int i; for (tbl = 0; tbl < SMD_ALLOC_TBL_COUNT; tbl++) { - ret = qcom_smem_get(edge->edge_id, + ret = qcom_smem_get(edge->remote_pid, smem_items[tbl].alloc_tbl_id, (void **)&alloc_tbl, NULL); @@ -1184,6 +1188,10 @@ static int qcom_smd_parse_edge(struct device *dev, return -EINVAL; } + edge->remote_pid = QCOM_SMEM_HOST_ANY; + key = "qcom,remote-pid"; + of_property_read_u32(node, key, &edge->remote_pid); + syscon_np = of_parse_phandle(node, "qcom,ipc", 0); if (!syscon_np) { dev_err(dev, "no qcom,ipc node\n"); -- GitLab From 208487a8f69084992f76ef87ddd3e00e5eaf6587 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Mon, 24 Aug 2015 13:38:46 -0700 Subject: [PATCH 6871/7006] soc: qcom: smd: Correct fBLOCKREADINTR handling fBLOCKREADINTR is masking the notification from the remote and should hence be cleared while we're waiting the tx fifo to drain. Also change the reset state to mask the notification, as send is the only use case where we're interested in it. Signed-off-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/soc/qcom/smd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/soc/qcom/smd.c b/drivers/soc/qcom/smd.c index edd9d9a372385..a6155c917d52d 100644 --- a/drivers/soc/qcom/smd.c +++ b/drivers/soc/qcom/smd.c @@ -312,7 +312,7 @@ static void qcom_smd_channel_reset(struct qcom_smd_channel *channel) SET_TX_CHANNEL_INFO(channel, fHEAD, 0); SET_TX_CHANNEL_INFO(channel, fTAIL, 0); SET_TX_CHANNEL_INFO(channel, fSTATE, 1); - SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0); + SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1); SET_TX_CHANNEL_INFO(channel, head, 0); SET_TX_CHANNEL_INFO(channel, tail, 0); @@ -683,7 +683,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len) goto out; } - SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1); + SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0); ret = wait_event_interruptible(channel->fblockread_event, qcom_smd_get_tx_avail(channel) >= tlen || @@ -691,7 +691,7 @@ int qcom_smd_send(struct qcom_smd_channel *channel, const void *data, int len) if (ret) goto out; - SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 0); + SET_TX_CHANNEL_INFO(channel, fBLOCKREADINTR, 1); } SET_TX_CHANNEL_INFO(channel, fTAIL, 0); -- GitLab From 6b9ea5a64ed5eeb3f68f2e6fcce0ed1179801d1e Mon Sep 17 00:00:00 2001 From: Roopa Prabhu Date: Tue, 8 Sep 2015 10:53:04 -0700 Subject: [PATCH 6872/7006] ipv6: fix multipath route replace error recovery Problem: The ecmp route replace support for ipv6 in the kernel, deletes the existing ecmp route too early, ie when it installs the first nexthop. If there is an error in installing the subsequent nexthops, its too late to recover the already deleted existing route leaving the fib in an inconsistent state. This patch reduces the possibility of this by doing the following: a) Changes the existing multipath route add code to a two stage process: build rt6_infos + insert them ip6_route_add rt6_info creation code is moved into ip6_route_info_create. b) This ensures that most errors are caught during building rt6_infos and we fail early c) Separates multipath add and del code. Because add needs the special two stage mode in a) and delete essentially does not care. d) In any event if the code fails during inserting a route again, a warning is printed (This should be unlikely) Before the patch: $ip -6 route show 3000:1000:1000:1000::2 via fe80::202:ff:fe00:b dev swp49s0 metric 1024 3000:1000:1000:1000::2 via fe80::202:ff:fe00:d dev swp49s1 metric 1024 3000:1000:1000:1000::2 via fe80::202:ff:fe00:f dev swp49s2 metric 1024 /* Try replacing the route with a duplicate nexthop */ $ip -6 route change 3000:1000:1000:1000::2/128 nexthop via fe80::202:ff:fe00:b dev swp49s0 nexthop via fe80::202:ff:fe00:d dev swp49s1 nexthop via fe80::202:ff:fe00:d dev swp49s1 RTNETLINK answers: File exists $ip -6 route show /* previously added ecmp route 3000:1000:1000:1000::2 dissappears from * kernel */ After the patch: $ip -6 route show 3000:1000:1000:1000::2 via fe80::202:ff:fe00:b dev swp49s0 metric 1024 3000:1000:1000:1000::2 via fe80::202:ff:fe00:d dev swp49s1 metric 1024 3000:1000:1000:1000::2 via fe80::202:ff:fe00:f dev swp49s2 metric 1024 /* Try replacing the route with a duplicate nexthop */ $ip -6 route change 3000:1000:1000:1000::2/128 nexthop via fe80::202:ff:fe00:b dev swp49s0 nexthop via fe80::202:ff:fe00:d dev swp49s1 nexthop via fe80::202:ff:fe00:d dev swp49s1 RTNETLINK answers: File exists $ip -6 route show 3000:1000:1000:1000::2 via fe80::202:ff:fe00:b dev swp49s0 metric 1024 3000:1000:1000:1000::2 via fe80::202:ff:fe00:d dev swp49s1 metric 1024 3000:1000:1000:1000::2 via fe80::202:ff:fe00:f dev swp49s2 metric 1024 Fixes: 27596472473a ("ipv6: fix ECMP route replacement") Signed-off-by: Roopa Prabhu Reviewed-by: Nikolay Aleksandrov Acked-by: Nicolas Dichtel Signed-off-by: David S. Miller --- net/ipv6/route.c | 201 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 175 insertions(+), 26 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index f45cac6f83563..34539d3b843fd 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -1748,7 +1748,7 @@ static int ip6_convert_metrics(struct mx6_config *mxc, return -EINVAL; } -int ip6_route_add(struct fib6_config *cfg) +int ip6_route_info_create(struct fib6_config *cfg, struct rt6_info **rt_ret) { int err; struct net *net = cfg->fc_nlinfo.nl_net; @@ -1756,7 +1756,6 @@ int ip6_route_add(struct fib6_config *cfg) struct net_device *dev = NULL; struct inet6_dev *idev = NULL; struct fib6_table *table; - struct mx6_config mxc = { .mx = NULL, }; int addr_type; if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) @@ -1981,6 +1980,32 @@ install_route: cfg->fc_nlinfo.nl_net = dev_net(dev); + *rt_ret = rt; + + return 0; +out: + if (dev) + dev_put(dev); + if (idev) + in6_dev_put(idev); + if (rt) + dst_free(&rt->dst); + + *rt_ret = NULL; + + return err; +} + +int ip6_route_add(struct fib6_config *cfg) +{ + struct mx6_config mxc = { .mx = NULL, }; + struct rt6_info *rt = NULL; + int err; + + err = ip6_route_info_create(cfg, &rt); + if (err) + goto out; + err = ip6_convert_metrics(&mxc, cfg); if (err) goto out; @@ -1988,14 +2013,12 @@ install_route: err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc); kfree(mxc.mx); + return err; out: - if (dev) - dev_put(dev); - if (idev) - in6_dev_put(idev); if (rt) dst_free(&rt->dst); + return err; } @@ -2776,19 +2799,78 @@ errout: return err; } -static int ip6_route_multipath(struct fib6_config *cfg, int add) +struct rt6_nh { + struct rt6_info *rt6_info; + struct fib6_config r_cfg; + struct mx6_config mxc; + struct list_head next; +}; + +static void ip6_print_replace_route_err(struct list_head *rt6_nh_list) +{ + struct rt6_nh *nh; + + list_for_each_entry(nh, rt6_nh_list, next) { + pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6 nexthop %pI6 ifi %d\n", + &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway, + nh->r_cfg.fc_ifindex); + } +} + +static int ip6_route_info_append(struct list_head *rt6_nh_list, + struct rt6_info *rt, struct fib6_config *r_cfg) +{ + struct rt6_nh *nh; + struct rt6_info *rtnh; + int err = -EEXIST; + + list_for_each_entry(nh, rt6_nh_list, next) { + /* check if rt6_info already exists */ + rtnh = nh->rt6_info; + + if (rtnh->dst.dev == rt->dst.dev && + rtnh->rt6i_idev == rt->rt6i_idev && + ipv6_addr_equal(&rtnh->rt6i_gateway, + &rt->rt6i_gateway)) + return err; + } + + nh = kzalloc(sizeof(*nh), GFP_KERNEL); + if (!nh) + return -ENOMEM; + nh->rt6_info = rt; + err = ip6_convert_metrics(&nh->mxc, r_cfg); + if (err) { + kfree(nh); + return err; + } + memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg)); + list_add_tail(&nh->next, rt6_nh_list); + + return 0; +} + +static int ip6_route_multipath_add(struct fib6_config *cfg) { struct fib6_config r_cfg; struct rtnexthop *rtnh; + struct rt6_info *rt; + struct rt6_nh *err_nh; + struct rt6_nh *nh, *nh_safe; int remaining; int attrlen; - int err = 0, last_err = 0; + int err = 1; + int nhn = 0; + int replace = (cfg->fc_nlinfo.nlh && + (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE)); + LIST_HEAD(rt6_nh_list); remaining = cfg->fc_mp_len; -beginning: rtnh = (struct rtnexthop *)cfg->fc_mp; - /* Parse a Multipath Entry */ + /* Parse a Multipath Entry and build a list (rt6_nh_list) of + * rt6_info structs per nexthop + */ while (rtnh_ok(rtnh, remaining)) { memcpy(&r_cfg, cfg, sizeof(*cfg)); if (rtnh->rtnh_ifindex) @@ -2808,22 +2890,32 @@ beginning: if (nla) r_cfg.fc_encap_type = nla_get_u16(nla); } - err = add ? ip6_route_add(&r_cfg) : ip6_route_del(&r_cfg); + + err = ip6_route_info_create(&r_cfg, &rt); + if (err) + goto cleanup; + + err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); if (err) { - last_err = err; - /* If we are trying to remove a route, do not stop the - * loop when ip6_route_del() fails (because next hop is - * already gone), we should try to remove all next hops. - */ - if (add) { - /* If add fails, we should try to delete all - * next hops that have been already added. - */ - add = 0; - remaining = cfg->fc_mp_len - remaining; - goto beginning; - } + dst_free(&rt->dst); + goto cleanup; + } + + rtnh = rtnh_next(rtnh, &remaining); + } + + err_nh = NULL; + list_for_each_entry(nh, &rt6_nh_list, next) { + err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc); + /* nh->rt6_info is used or freed at this point, reset to NULL*/ + nh->rt6_info = NULL; + if (err) { + if (replace && nhn) + ip6_print_replace_route_err(&rt6_nh_list); + err_nh = nh; + goto add_errout; } + /* Because each route is added like a single route we remove * these flags after the first nexthop: if there is a collision, * we have already failed to add the first nexthop: @@ -2833,6 +2925,63 @@ beginning: */ cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL | NLM_F_REPLACE); + nhn++; + } + + goto cleanup; + +add_errout: + /* Delete routes that were already added */ + list_for_each_entry(nh, &rt6_nh_list, next) { + if (err_nh == nh) + break; + ip6_route_del(&nh->r_cfg); + } + +cleanup: + list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) { + if (nh->rt6_info) + dst_free(&nh->rt6_info->dst); + if (nh->mxc.mx) + kfree(nh->mxc.mx); + list_del(&nh->next); + kfree(nh); + } + + return err; +} + +static int ip6_route_multipath_del(struct fib6_config *cfg) +{ + struct fib6_config r_cfg; + struct rtnexthop *rtnh; + int remaining; + int attrlen; + int err = 1, last_err = 0; + + remaining = cfg->fc_mp_len; + rtnh = (struct rtnexthop *)cfg->fc_mp; + + /* Parse a Multipath Entry */ + while (rtnh_ok(rtnh, remaining)) { + memcpy(&r_cfg, cfg, sizeof(*cfg)); + if (rtnh->rtnh_ifindex) + r_cfg.fc_ifindex = rtnh->rtnh_ifindex; + + attrlen = rtnh_attrlen(rtnh); + if (attrlen > 0) { + struct nlattr *nla, *attrs = rtnh_attrs(rtnh); + + nla = nla_find(attrs, attrlen, RTA_GATEWAY); + if (nla) { + nla_memcpy(&r_cfg.fc_gateway, nla, 16); + r_cfg.fc_flags |= RTF_GATEWAY; + } + } + err = ip6_route_del(&r_cfg); + if (err) + last_err = err; + rtnh = rtnh_next(rtnh, &remaining); } @@ -2849,7 +2998,7 @@ static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) return err; if (cfg.fc_mp) - return ip6_route_multipath(&cfg, 0); + return ip6_route_multipath_del(&cfg); else return ip6_route_del(&cfg); } @@ -2864,7 +3013,7 @@ static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) return err; if (cfg.fc_mp) - return ip6_route_multipath(&cfg, 1); + return ip6_route_multipath_add(&cfg); else return ip6_route_add(&cfg); } -- GitLab From 687f07156b0c99205c21aa4e2986564046d342fe Mon Sep 17 00:00:00 2001 From: Alexei Starovoitov Date: Tue, 8 Sep 2015 13:40:01 -0700 Subject: [PATCH 6873/7006] bpf: fix out of bounds access in verifier log when the verifier log is enabled the print_bpf_insn() is doing bpf_alu_string[BPF_OP(insn->code) >> 4] and bpf_jmp_string[BPF_OP(insn->code) >> 4] where BPF_OP is a 4-bit instruction opcode. Malformed insns can cause out of bounds access. Fix it by sizing arrays appropriately. The bug was found by clang address sanitizer with libfuzzer. Reported-by: Yonghong Song Signed-off-by: Alexei Starovoitov Acked-by: Daniel Borkmann Signed-off-by: David S. Miller --- kernel/bpf/verifier.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ed12e385fb759..b074b23000d6e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -283,7 +283,7 @@ static const char *const bpf_class_string[] = { [BPF_ALU64] = "alu64", }; -static const char *const bpf_alu_string[] = { +static const char *const bpf_alu_string[16] = { [BPF_ADD >> 4] = "+=", [BPF_SUB >> 4] = "-=", [BPF_MUL >> 4] = "*=", @@ -307,7 +307,7 @@ static const char *const bpf_ldst_string[] = { [BPF_DW >> 3] = "u64", }; -static const char *const bpf_jmp_string[] = { +static const char *const bpf_jmp_string[16] = { [BPF_JA >> 4] = "jmp", [BPF_JEQ >> 4] = "==", [BPF_JGT >> 4] = ">", -- GitLab From 03679a14739a0d4c14b52ba65a69ff553bfba73b Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 8 Sep 2015 20:06:41 -0700 Subject: [PATCH 6874/7006] net: dsa: bcm_sf2: Fix 64-bits register writes The macro to write 64-bits quantities to the 32-bits register swapped the value and offsets arguments, we want to preserve the ordering of the arguments with respect to how writel() is implemented for instance: value first, offset/base second. Fixes: 246d7f773c13 ("net: dsa: add Broadcom SF2 switch driver") Signed-off-by: Florian Fainelli Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.h b/drivers/net/dsa/bcm_sf2.h index 22e2ebf313332..789d7b7737da4 100644 --- a/drivers/net/dsa/bcm_sf2.h +++ b/drivers/net/dsa/bcm_sf2.h @@ -112,8 +112,8 @@ static inline u64 name##_readq(struct bcm_sf2_priv *priv, u32 off) \ spin_unlock(&priv->indir_lock); \ return (u64)indir << 32 | dir; \ } \ -static inline void name##_writeq(struct bcm_sf2_priv *priv, u32 off, \ - u64 val) \ +static inline void name##_writeq(struct bcm_sf2_priv *priv, u64 val, \ + u32 off) \ { \ spin_lock(&priv->indir_lock); \ reg_writel(priv, upper_32_bits(val), REG_DIR_DATA_WRITE); \ -- GitLab From 444c5f92ed152346aef0952316e0ea855129846c Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Wed, 9 Sep 2015 11:24:29 +0200 Subject: [PATCH 6875/7006] net: ethoc: Remove unnecessary #ifdef CONFIG_OF For !CONFIG_OF of_get_property() is defined to always return NULL. Thus there's no need to protect the call to of_get_property() with #ifdef CONFIG_OF. Signed-off-by: Tobias Klauser Signed-off-by: David S. Miller --- drivers/net/ethernet/ethoc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/net/ethernet/ethoc.c b/drivers/net/ethernet/ethoc.c index 442410cd2ca4b..a2c96fd883938 100644 --- a/drivers/net/ethernet/ethoc.c +++ b/drivers/net/ethernet/ethoc.c @@ -1132,10 +1132,6 @@ static int ethoc_probe(struct platform_device *pdev) memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN); priv->phy_id = pdata->phy_id; } else { - priv->phy_id = -1; - -#ifdef CONFIG_OF - { const uint8_t *mac; mac = of_get_property(pdev->dev.of_node, @@ -1143,8 +1139,7 @@ static int ethoc_probe(struct platform_device *pdev) NULL); if (mac) memcpy(netdev->dev_addr, mac, IFHWADDRLEN); - } -#endif + priv->phy_id = -1; } /* Check that the given MAC address is valid. If it isn't, read the -- GitLab From f53de1e9a4aaf8cbe08845da6f7ff26a078ac507 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Wed, 9 Sep 2015 14:20:56 +0200 Subject: [PATCH 6876/7006] net: ipv6: use common fib_default_rule_pref This switches IPv6 policy routing to use the shared fib_default_rule_pref() function of IPv4 and DECnet. It is also used in multicast routing for IPv4 as well as IPv6. The motivation for this patch is a complaint about iproute2 behaving inconsistent between IPv4 and IPv6 when adding policy rules: Formerly, IPv6 rules were assigned a fixed priority of 0x3FFF whereas for IPv4 the assigned priority value was decreased with each rule added. Since then all users of the default_pref field have been converted to assign the generic function fib_default_rule_pref(), fib_nl_newrule() may just use it directly instead. Therefore get rid of the function pointer altogether and make fib_default_rule_pref() static, as it's not used outside fib_rules.c anymore. Signed-off-by: Phil Sutter Signed-off-by: David S. Miller --- include/net/fib_rules.h | 2 -- net/core/fib_rules.c | 10 +++------- net/decnet/dn_rules.c | 1 - net/ipv4/fib_rules.c | 1 - net/ipv4/ipmr.c | 1 - net/ipv6/fib6_rules.c | 6 ------ net/ipv6/ip6mr.c | 1 - 7 files changed, 3 insertions(+), 19 deletions(-) diff --git a/include/net/fib_rules.h b/include/net/fib_rules.h index 4e8f804f45898..59160de702b68 100644 --- a/include/net/fib_rules.h +++ b/include/net/fib_rules.h @@ -66,7 +66,6 @@ struct fib_rules_ops { struct nlattr **); int (*fill)(struct fib_rule *, struct sk_buff *, struct fib_rule_hdr *); - u32 (*default_pref)(struct fib_rules_ops *ops); size_t (*nlmsg_payload)(struct fib_rule *); /* Called after modifications to the rules set, must flush @@ -118,5 +117,4 @@ int fib_rules_lookup(struct fib_rules_ops *, struct flowi *, int flags, struct fib_lookup_arg *); int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table, u32 flags); -u32 fib_default_rule_pref(struct fib_rules_ops *ops); #endif diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index ae8306e7c56f9..bf77e3639ce0f 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -44,7 +44,7 @@ int fib_default_rule_add(struct fib_rules_ops *ops, } EXPORT_SYMBOL(fib_default_rule_add); -u32 fib_default_rule_pref(struct fib_rules_ops *ops) +static u32 fib_default_rule_pref(struct fib_rules_ops *ops) { struct list_head *pos; struct fib_rule *rule; @@ -60,7 +60,6 @@ u32 fib_default_rule_pref(struct fib_rules_ops *ops) return 0; } -EXPORT_SYMBOL(fib_default_rule_pref); static void notify_rule_change(int event, struct fib_rule *rule, struct fib_rules_ops *ops, struct nlmsghdr *nlh, @@ -299,8 +298,8 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) } rule->fr_net = net; - if (tb[FRA_PRIORITY]) - rule->pref = nla_get_u32(tb[FRA_PRIORITY]); + rule->pref = tb[FRA_PRIORITY] ? nla_get_u32(tb[FRA_PRIORITY]) + : fib_default_rule_pref(ops); if (tb[FRA_IIFNAME]) { struct net_device *dev; @@ -350,9 +349,6 @@ static int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh) else rule->suppress_ifgroup = -1; - if (!tb[FRA_PRIORITY] && ops->default_pref) - rule->pref = ops->default_pref(ops); - err = -EINVAL; if (tb[FRA_GOTO]) { if (rule->action != FR_ACT_GOTO) diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c index 9d66a0f72f906..295bbd6a56f2e 100644 --- a/net/decnet/dn_rules.c +++ b/net/decnet/dn_rules.c @@ -229,7 +229,6 @@ static const struct fib_rules_ops __net_initconst dn_fib_rules_ops_template = { .configure = dn_fib_rule_configure, .compare = dn_fib_rule_compare, .fill = dn_fib_rule_fill, - .default_pref = fib_default_rule_pref, .flush_cache = dn_fib_rule_flush_cache, .nlgroup = RTNLGRP_DECnet_RULE, .policy = dn_fib_rule_policy, diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c index 18123d50f5761..f2bda9e89c61b 100644 --- a/net/ipv4/fib_rules.c +++ b/net/ipv4/fib_rules.c @@ -318,7 +318,6 @@ static const struct fib_rules_ops __net_initconst fib4_rules_ops_template = { .delete = fib4_rule_delete, .compare = fib4_rule_compare, .fill = fib4_rule_fill, - .default_pref = fib_default_rule_pref, .nlmsg_payload = fib4_rule_nlmsg_payload, .flush_cache = fib4_rule_flush_cache, .nlgroup = RTNLGRP_IPV4_RULE, diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 3a2c0162c3bad..866ee89f5254a 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -233,7 +233,6 @@ static const struct fib_rules_ops __net_initconst ipmr_rules_ops_template = { .match = ipmr_rule_match, .configure = ipmr_rule_configure, .compare = ipmr_rule_compare, - .default_pref = fib_default_rule_pref, .fill = ipmr_rule_fill, .nlgroup = RTNLGRP_IPV4_RULE, .policy = ipmr_rule_policy, diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c index 2367a16eae58a..9f777ec59a59d 100644 --- a/net/ipv6/fib6_rules.c +++ b/net/ipv6/fib6_rules.c @@ -258,11 +258,6 @@ nla_put_failure: return -ENOBUFS; } -static u32 fib6_rule_default_pref(struct fib_rules_ops *ops) -{ - return 0x3FFF; -} - static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) { return nla_total_size(16) /* dst */ @@ -279,7 +274,6 @@ static const struct fib_rules_ops __net_initconst fib6_rules_ops_template = { .configure = fib6_rule_configure, .compare = fib6_rule_compare, .fill = fib6_rule_fill, - .default_pref = fib6_rule_default_pref, .nlmsg_payload = fib6_rule_nlmsg_payload, .nlgroup = RTNLGRP_IPV6_RULE, .policy = fib6_rule_policy, diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 5f36266b1f5ef..0e004cc42a22b 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -217,7 +217,6 @@ static const struct fib_rules_ops __net_initconst ip6mr_rules_ops_template = { .match = ip6mr_rule_match, .configure = ip6mr_rule_configure, .compare = ip6mr_rule_compare, - .default_pref = fib_default_rule_pref, .fill = ip6mr_rule_fill, .nlgroup = RTNLGRP_IPV6_RULE, .policy = ip6mr_rule_policy, -- GitLab From ae1973a2df8ea48ab04cd406c569ce0b5721dd99 Mon Sep 17 00:00:00 2001 From: Kishon Vijay Abraham I Date: Fri, 4 Sep 2015 17:43:15 +0530 Subject: [PATCH 6877/7006] ARM: multi_v7_defconfig: Enable PBIAS regulator PBIAS regulator is required for MMC module in OMAP2, OMAP3, OMAP4, OMAP5 and DRA7 SoCs. Enable it here. Signed-off-by: Kishon Vijay Abraham I Signed-off-by: Kevin Hilman --- arch/arm/configs/multi_v7_defconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig index 824a0cff39987..52ebbc5570ff8 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -411,6 +411,7 @@ CONFIG_REGULATOR_MAX8973=y CONFIG_REGULATOR_MAX77686=y CONFIG_REGULATOR_MAX77693=m CONFIG_REGULATOR_PALMAS=y +CONFIG_REGULATOR_PBIAS=y CONFIG_REGULATOR_PWM=m CONFIG_REGULATOR_S2MPS11=y CONFIG_REGULATOR_S5M8767=y -- GitLab From ce8e5c7035098fa5b8fea910f14be59b8cace81f Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 9 Sep 2015 10:38:02 +0200 Subject: [PATCH 6878/7006] net: cavium: liquidio: use kzalloc in setup_glist() We save a little .text and get rid of the sizeof(...) style inconsistency. Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/liquidio/lio_main.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index 0660deecc2c9a..f683d97d7614e 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -818,10 +818,9 @@ static int setup_glist(struct lio *lio) INIT_LIST_HEAD(&lio->glist); for (i = 0; i < lio->tx_qsize; i++) { - g = kmalloc(sizeof(*g), GFP_KERNEL); + g = kzalloc(sizeof(*g), GFP_KERNEL); if (!g) break; - memset(g, 0, sizeof(struct octnic_gather)); g->sg_size = ((ROUNDUP4(OCTNIC_MAX_SG) >> 2) * OCT_SG_ENTRY_SIZE); -- GitLab From e9b5ac277e8f8dffa28f85a065e2fd890d9e48c7 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 9 Sep 2015 10:38:03 +0200 Subject: [PATCH 6879/7006] net: jme: use kzalloc() instead of kmalloc+memset Using kzalloc saves a tiny bit on .text. Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/net/ethernet/jme.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c index 6e9a792097d31..060dd39229747 100644 --- a/drivers/net/ethernet/jme.c +++ b/drivers/net/ethernet/jme.c @@ -583,7 +583,7 @@ jme_setup_tx_resources(struct jme_adapter *jme) atomic_set(&txring->next_to_clean, 0); atomic_set(&txring->nr_free, jme->tx_ring_size); - txring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + txring->bufinf = kzalloc(sizeof(struct jme_buffer_info) * jme->tx_ring_size, GFP_ATOMIC); if (unlikely(!(txring->bufinf))) goto err_free_txring; @@ -592,8 +592,6 @@ jme_setup_tx_resources(struct jme_adapter *jme) * Initialize Transmit Descriptors */ memset(txring->alloc, 0, TX_RING_ALLOC_SIZE(jme->tx_ring_size)); - memset(txring->bufinf, 0, - sizeof(struct jme_buffer_info) * jme->tx_ring_size); return 0; @@ -845,7 +843,7 @@ jme_setup_rx_resources(struct jme_adapter *jme) rxring->next_to_use = 0; atomic_set(&rxring->next_to_clean, 0); - rxring->bufinf = kmalloc(sizeof(struct jme_buffer_info) * + rxring->bufinf = kzalloc(sizeof(struct jme_buffer_info) * jme->rx_ring_size, GFP_ATOMIC); if (unlikely(!(rxring->bufinf))) goto err_free_rxring; @@ -853,8 +851,6 @@ jme_setup_rx_resources(struct jme_adapter *jme) /* * Initiallize Receive Descriptors */ - memset(rxring->bufinf, 0, - sizeof(struct jme_buffer_info) * jme->rx_ring_size); for (i = 0 ; i < jme->rx_ring_size ; ++i) { if (unlikely(jme_make_new_rx_buf(jme, i))) { jme_free_rx_resources(jme); -- GitLab From b66a60857ca4fae5900c5d81c2ba04e657509b99 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 9 Sep 2015 10:38:04 +0200 Subject: [PATCH 6880/7006] net: mv643xx_eth: use kzalloc The double memset is a little ugly; using kzalloc avoids it altogether. Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mv643xx_eth.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index d52639bc491f7..960169efe636a 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -1859,14 +1859,11 @@ oom: return; } - mc_spec = kmalloc(0x200, GFP_ATOMIC); + mc_spec = kzalloc(0x200, GFP_ATOMIC); if (mc_spec == NULL) goto oom; mc_other = mc_spec + (0x100 >> 2); - memset(mc_spec, 0, 0x100); - memset(mc_other, 0, 0x100); - netdev_for_each_mc_addr(ha, dev) { u8 *a = ha->addr; u32 *table; -- GitLab From 1f0ca208531a152e1da6aa43d095fe0b2039d9ca Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Wed, 9 Sep 2015 10:38:05 +0200 Subject: [PATCH 6881/7006] net: qlcnic: delete redundant memsets In all cases, mbx->req.arg and mbx->rsp.arg have just been allocated using kcalloc(), so these six memsets are redundant. Signed-off-by: Rasmus Villemoes Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c | 2 -- drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c | 2 -- drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c | 2 -- 3 files changed, 6 deletions(-) diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c index 5ab3adf88166c..9f0bdd993955c 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c @@ -918,8 +918,6 @@ int qlcnic_83xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, mbx->req.arg = NULL; return -ENOMEM; } - memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num); - memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); temp = adapter->ahw->fw_hal_version << 29; mbx->req.arg[0] = (type | (mbx->req.num << 16) | temp); mbx->cmd_op = type; diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c index 6e6f18fc5d769..a5f422f26cb43 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_ctx.c @@ -73,8 +73,6 @@ int qlcnic_82xx_alloc_mbx_args(struct qlcnic_cmd_args *mbx, mbx->req.arg = NULL; return -ENOMEM; } - memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num); - memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); mbx->req.arg[0] = type; break; } diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c index 546cd5f1c85ae..7327b729ba2ea 100644 --- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c +++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c @@ -729,8 +729,6 @@ static int qlcnic_sriov_alloc_bc_mbx_args(struct qlcnic_cmd_args *mbx, u32 type) mbx->req.arg = NULL; return -ENOMEM; } - memset(mbx->req.arg, 0, sizeof(u32) * mbx->req.num); - memset(mbx->rsp.arg, 0, sizeof(u32) * mbx->rsp.num); mbx->req.arg[0] = (type | (mbx->req.num << 16) | (3 << 29)); mbx->rsp.arg[0] = (type & 0xffff) | mbx->rsp.num << 16; -- GitLab From dfc50fcaad574e5c8c85cbc83eca1426b2413fa4 Mon Sep 17 00:00:00 2001 From: Alexey Brodkin Date: Wed, 9 Sep 2015 18:01:08 +0300 Subject: [PATCH 6882/7006] stmmac: fix check for phydev being open Current check of phydev with IS_ERR(phydev) may make not much sense because of_phy_connect() returns NULL on failure instead of error value. Still for checking result of phy_connect() IS_ERR() makes perfect sense. So let's use combined check IS_ERR_OR_NULL() that covers both cases. Cc: Sergei Shtylyov Cc: Giuseppe Cavallaro Cc: linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org Cc: David Miller Signed-off-by: Alexey Brodkin Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 864b476f7fd5a..925f2f8659b8f 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -837,8 +837,11 @@ static int stmmac_init_phy(struct net_device *dev) interface); } - if (IS_ERR(phydev)) { + if (IS_ERR_OR_NULL(phydev)) { pr_err("%s: Could not attach to PHY\n", dev->name); + if (!phydev) + return -ENODEV; + return PTR_ERR(phydev); } -- GitLab From 792aec47d59d951865cc617a97b6e6be53d4b977 Mon Sep 17 00:00:00 2001 From: "Woojung.Huh@microchip.com" Date: Wed, 9 Sep 2015 20:49:53 +0000 Subject: [PATCH 6883/7006] add microchip LAN88xx phy driver Add Microchip LAN88XX phy driver for phylib. Signed-off-by: Woojung Huh Signed-off-by: David S. Miller --- drivers/net/phy/Kconfig | 5 ++ drivers/net/phy/Makefile | 1 + drivers/net/phy/microchip.c | 148 +++++++++++++++++++++++++++++++++++ include/linux/microchipphy.h | 73 +++++++++++++++++ 4 files changed, 227 insertions(+) create mode 100644 drivers/net/phy/microchip.c create mode 100644 include/linux/microchipphy.h diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index c07030dbe7484..c5ad98ace5d0a 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -127,6 +127,11 @@ config DP83867_PHY ---help--- Currently supports the DP83867 PHY. +config MICROCHIP_PHY + tristate "Drivers for Microchip PHYs" + help + Supports the LAN88XX PHYs. + config FIXED_PHY tristate "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" depends on PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index 9bb103358c74d..87f079c4b2c7a 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -37,3 +37,4 @@ obj-$(CONFIG_MDIO_BUS_MUX_MMIOREG) += mdio-mux-mmioreg.o obj-$(CONFIG_MDIO_SUN4I) += mdio-sun4i.o obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o +obj-$(CONFIG_MICROCHIP_PHY) += microchip.o diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c new file mode 100644 index 0000000000000..c0a20ebd083b1 --- /dev/null +++ b/drivers/net/phy/microchip.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2015 Microchip Technology + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ +#include +#include +#include +#include +#include +#include + +#define DRIVER_AUTHOR "WOOJUNG HUH " +#define DRIVER_DESC "Microchip LAN88XX PHY driver" + +struct lan88xx_priv { + int chip_id; + int chip_rev; + __u32 wolopts; +}; + +static int lan88xx_phy_config_intr(struct phy_device *phydev) +{ + int rc; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* unmask all source and clear them before enable */ + rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF); + rc = phy_read(phydev, LAN88XX_INT_STS); + rc = phy_write(phydev, LAN88XX_INT_MASK, + LAN88XX_INT_MASK_MDINTPIN_EN_ | + LAN88XX_INT_MASK_LINK_CHANGE_); + } else { + rc = phy_write(phydev, LAN88XX_INT_MASK, 0); + } + + return rc < 0 ? rc : 0; +} + +static int lan88xx_phy_ack_interrupt(struct phy_device *phydev) +{ + int rc = phy_read(phydev, LAN88XX_INT_STS); + + return rc < 0 ? rc : 0; +} + +int lan88xx_suspend(struct phy_device *phydev) +{ + struct lan88xx_priv *priv = phydev->priv; + + /* do not power down PHY when WOL is enabled */ + if (!priv->wolopts) + genphy_suspend(phydev); + + return 0; +} + +static int lan88xx_probe(struct phy_device *phydev) +{ + struct device *dev = &phydev->dev; + struct lan88xx_priv *priv; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->wolopts = 0; + + /* these values can be used to identify internal PHY */ + priv->chip_id = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_ID, + 3, phydev->addr); + priv->chip_rev = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_REV, + 3, phydev->addr); + + phydev->priv = priv; + + return 0; +} + +static void lan88xx_remove(struct phy_device *phydev) +{ + struct device *dev = &phydev->dev; + struct lan88xx_priv *priv = phydev->priv; + + if (priv) + devm_kfree(dev, priv); +} + +static int lan88xx_set_wol(struct phy_device *phydev, + struct ethtool_wolinfo *wol) +{ + struct lan88xx_priv *priv = phydev->priv; + + priv->wolopts = wol->wolopts; + + return 0; +} + +static struct phy_driver microchip_phy_driver[] = { +{ + .phy_id = 0x0007c130, + .phy_id_mask = 0xfffffff0, + .name = "Microchip LAN88xx", + + .features = (PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + + .probe = lan88xx_probe, + .remove = lan88xx_remove, + + .config_init = genphy_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + + .ack_interrupt = lan88xx_phy_ack_interrupt, + .config_intr = lan88xx_phy_config_intr, + + .suspend = lan88xx_suspend, + .resume = genphy_resume, + .set_wol = lan88xx_set_wol, + + .driver = { .owner = THIS_MODULE, } +} }; + +module_phy_driver(microchip_phy_driver); + +static struct mdio_device_id __maybe_unused microchip_tbl[] = { + { 0x0007c130, 0xfffffff0 }, + { } +}; + +MODULE_DEVICE_TABLE(mdio, microchip_tbl); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h new file mode 100644 index 0000000000000..eb492d47f7171 --- /dev/null +++ b/include/linux/microchipphy.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015 Microchip Technology + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _MICROCHIPPHY_H +#define _MICROCHIPPHY_H + +#define LAN88XX_INT_MASK (0x19) +#define LAN88XX_INT_MASK_MDINTPIN_EN_ (0x8000) +#define LAN88XX_INT_MASK_SPEED_CHANGE_ (0x4000) +#define LAN88XX_INT_MASK_LINK_CHANGE_ (0x2000) +#define LAN88XX_INT_MASK_FDX_CHANGE_ (0x1000) +#define LAN88XX_INT_MASK_AUTONEG_ERR_ (0x0800) +#define LAN88XX_INT_MASK_AUTONEG_DONE_ (0x0400) +#define LAN88XX_INT_MASK_POE_DETECT_ (0x0200) +#define LAN88XX_INT_MASK_SYMBOL_ERR_ (0x0100) +#define LAN88XX_INT_MASK_FAST_LINK_FAIL_ (0x0080) +#define LAN88XX_INT_MASK_WOL_EVENT_ (0x0040) +#define LAN88XX_INT_MASK_EXTENDED_INT_ (0x0020) +#define LAN88XX_INT_MASK_RESERVED_ (0x0010) +#define LAN88XX_INT_MASK_FALSE_CARRIER_ (0x0008) +#define LAN88XX_INT_MASK_LINK_SPEED_DS_ (0x0004) +#define LAN88XX_INT_MASK_MASTER_SLAVE_DONE_ (0x0002) +#define LAN88XX_INT_MASK_RX__ER_ (0x0001) + +#define LAN88XX_INT_STS (0x1A) +#define LAN88XX_INT_STS_INT_ACTIVE_ (0x8000) +#define LAN88XX_INT_STS_SPEED_CHANGE_ (0x4000) +#define LAN88XX_INT_STS_LINK_CHANGE_ (0x2000) +#define LAN88XX_INT_STS_FDX_CHANGE_ (0x1000) +#define LAN88XX_INT_STS_AUTONEG_ERR_ (0x0800) +#define LAN88XX_INT_STS_AUTONEG_DONE_ (0x0400) +#define LAN88XX_INT_STS_POE_DETECT_ (0x0200) +#define LAN88XX_INT_STS_SYMBOL_ERR_ (0x0100) +#define LAN88XX_INT_STS_FAST_LINK_FAIL_ (0x0080) +#define LAN88XX_INT_STS_WOL_EVENT_ (0x0040) +#define LAN88XX_INT_STS_EXTENDED_INT_ (0x0020) +#define LAN88XX_INT_STS_RESERVED_ (0x0010) +#define LAN88XX_INT_STS_FALSE_CARRIER_ (0x0008) +#define LAN88XX_INT_STS_LINK_SPEED_DS_ (0x0004) +#define LAN88XX_INT_STS_MASTER_SLAVE_DONE_ (0x0002) +#define LAN88XX_INT_STS_RX_ER_ (0x0001) + +#define LAN88XX_EXT_PAGE_ACCESS (0x1F) +#define LAN88XX_EXT_PAGE_SPACE_0 (0x0000) +#define LAN88XX_EXT_PAGE_SPACE_1 (0x0001) +#define LAN88XX_EXT_PAGE_SPACE_2 (0x0002) + +/* Extended Register Page 1 space */ +#define LAN88XX_EXT_MODE_CTRL (0x13) +#define LAN88XX_EXT_MODE_CTRL_MDIX_MASK_ (0x000C) +#define LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_ (0x0000) +#define LAN88XX_EXT_MODE_CTRL_MDI_ (0x0008) +#define LAN88XX_EXT_MODE_CTRL_MDI_X_ (0x000C) + +/* MMD 3 Registers */ +#define LAN88XX_MMD3_CHIP_ID (32877) +#define LAN88XX_MMD3_CHIP_REV (32878) + +#endif /* _MICROCHIPPHY_H */ -- GitLab From 52fe51f8523751da0e79c85350c47eb3bb94da5b Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Thu, 10 Sep 2015 06:57:12 +0800 Subject: [PATCH 6884/7006] ipv6: fix ifnullfree.cocci warnings net/ipv6/route.c:2946:3-8: WARNING: NULL check before freeing functions like kfree, debugfs_remove, debugfs_remove_recursive or usb_free_urb is not needed. Maybe consider reorganizing relevant code to avoid passing NULL values. NULL check before some freeing functions is not needed. Based on checkpatch warning "kfree(NULL) is safe this check is probably not required" and kfreeaddr.cocci by Julia Lawall. Generated by: scripts/coccinelle/free/ifnullfree.cocci CC: Roopa Prabhu Signed-off-by: Fengguang Wu Signed-off-by: David S. Miller --- net/ipv6/route.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 34539d3b843fd..53617d7151885 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2942,8 +2942,7 @@ cleanup: list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) { if (nh->rt6_info) dst_free(&nh->rt6_info->dst); - if (nh->mxc.mx) - kfree(nh->mxc.mx); + kfree(nh->mxc.mx); list_del(&nh->next); kfree(nh); } -- GitLab From d0942473e3ca4629a40bbf0c9fd74fc0c7ff2a79 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Mon, 7 Sep 2015 11:57:43 +0800 Subject: [PATCH 6885/7006] r8152: split DRIVER_VERSION Split DRIVER_VERSION into NETNEXT_VERSION and NET_VERSION. Then, according to the value of DRIVER_VERSION, we could know which patches are used generally without comparing the source code. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index fe4ec324aebc0..6bb48bc514841 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -26,8 +26,13 @@ #include #include -/* Version Information */ -#define DRIVER_VERSION "v1.08.1 (2015/07/28)" +/* Information for net-next */ +#define NETNEXT_VERSION "08" + +/* Information for net */ +#define NET_VERSION "1" + +#define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION #define DRIVER_AUTHOR "Realtek linux nic maintainers " #define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" -- GitLab From 2dd49e0f16fb0e07c6fcc1322ebba310f5827072 Mon Sep 17 00:00:00 2001 From: hayeswang Date: Mon, 7 Sep 2015 11:57:44 +0800 Subject: [PATCH 6886/7006] r8152: fix the runtime suspend issues Fix the runtime suspend issues result from the linking change. Case 1: a) link down occurs. b) driver disable tx/rx. c) autosuspend occurs. d) hw linking up. e) device suspends without enabling tx/rx. f) couldn't wake up when receiving packets. Case 2: a) Nway results in linking down. b) autosuspend occurs. c) device suspends. d) device may not wake up when linking up. Signed-off-by: Hayes Wang Signed-off-by: David S. Miller --- drivers/net/usb/r8152.c | 59 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 6bb48bc514841..d9427ca3dba79 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -30,7 +30,7 @@ #define NETNEXT_VERSION "08" /* Information for net */ -#define NET_VERSION "1" +#define NET_VERSION "2" #define DRIVER_VERSION "v1." NETNEXT_VERSION "." NET_VERSION #define DRIVER_AUTHOR "Realtek linux nic maintainers " @@ -148,6 +148,7 @@ #define OCP_EEE_ABLE 0xa5c4 #define OCP_EEE_ADV 0xa5d0 #define OCP_EEE_LPABLE 0xa5d2 +#define OCP_PHY_STATE 0xa708 /* nway state for 8153 */ #define OCP_ADC_CFG 0xbc06 /* SRAM Register */ @@ -432,6 +433,10 @@ /* OCP_DOWN_SPEED */ #define EN_10M_BGOFF 0x0080 +/* OCP_PHY_STATE */ +#define TXDIS_STATE 0x01 +#define ABD_STATE 0x02 + /* OCP_ADC_CFG */ #define CKADSEL_L 0x0100 #define ADC_EN 0x0080 @@ -609,6 +614,7 @@ struct r8152 { void (*unload)(struct r8152 *); int (*eee_get)(struct r8152 *, struct ethtool_eee *); int (*eee_set)(struct r8152 *, struct ethtool_eee *); + bool (*in_nway)(struct r8152 *); } rtl_ops; int intr_interval; @@ -2946,6 +2952,32 @@ static void rtl8153_down(struct r8152 *tp) r8153_enable_aldps(tp); } +static bool rtl8152_in_nway(struct r8152 *tp) +{ + u16 nway_state; + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, 0x2000); + tp->ocp_base = 0x2000; + ocp_write_byte(tp, MCU_TYPE_PLA, 0xb014, 0x4c); /* phy state */ + nway_state = ocp_read_word(tp, MCU_TYPE_PLA, 0xb01a); + + /* bit 15: TXDIS_STATE, bit 14: ABD_STATE */ + if (nway_state & 0xc000) + return false; + else + return true; +} + +static bool rtl8153_in_nway(struct r8152 *tp) +{ + u16 phy_state = ocp_reg_read(tp, OCP_PHY_STATE) & 0xff; + + if (phy_state == TXDIS_STATE || phy_state == ABD_STATE) + return false; + else + return true; +} + static void set_carrier(struct r8152 *tp) { struct net_device *netdev = tp->netdev; @@ -3410,6 +3442,27 @@ static int rtl8152_post_reset(struct usb_interface *intf) return 0; } +static bool delay_autosuspend(struct r8152 *tp) +{ + bool sw_linking = !!netif_carrier_ok(tp->netdev); + bool hw_linking = !!(rtl8152_get_speed(tp) & LINK_STATUS); + + /* This means a linking change occurs and the driver doesn't detect it, + * yet. If the driver has disabled tx/rx and hw is linking on, the + * device wouldn't wake up by receiving any packet. + */ + if (work_busy(&tp->schedule.work) || sw_linking != hw_linking) + return true; + + /* If the linking down is occurred by nway, the device may miss the + * linking change event. And it wouldn't wake when linking on. + */ + if (!sw_linking && tp->rtl_ops.in_nway(tp)) + return true; + else + return false; +} + static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) { struct r8152 *tp = usb_get_intfdata(intf); @@ -3419,7 +3472,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) mutex_lock(&tp->control); if (PMSG_IS_AUTO(message)) { - if (netif_running(netdev) && work_busy(&tp->schedule.work)) { + if (netif_running(netdev) && delay_autosuspend(tp)) { ret = -EBUSY; goto out1; } @@ -4049,6 +4102,7 @@ static int rtl_ops_init(struct r8152 *tp) ops->unload = rtl8152_unload; ops->eee_get = r8152_get_eee; ops->eee_set = r8152_set_eee; + ops->in_nway = rtl8152_in_nway; break; case RTL_VER_03: @@ -4063,6 +4117,7 @@ static int rtl_ops_init(struct r8152 *tp) ops->unload = rtl8153_unload; ops->eee_get = r8153_get_eee; ops->eee_set = r8153_set_eee; + ops->in_nway = rtl8153_in_nway; break; default: -- GitLab From 9638d19e481605217f95d9ab3c8896e499b1407d Mon Sep 17 00:00:00 2001 From: Nimrod Andy Date: Thu, 10 Sep 2015 09:35:39 +0800 Subject: [PATCH 6887/7006] net: fec: add netif status check before set mac address There exist one issue by below case that case system hang: ifconfig eth0 down ifconfig eth0 hw ether 00:10:19:19:81:19 After eth0 down, all fec clocks are gated off. In the .fec_set_mac_address() function, it will set new MAC address to registers, which causes system hang. So it needs to add netif status check to avoid registers access when clocks are gated off. Until eth0 up the new MAC address are wrote into related registers. V2: As Lucas Stach's suggestion, add a comment in the code to explain why it needed. CC: Lucas Stach CC: Florian Fainelli Signed-off-by: Fugang Duan Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fec_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c index 6cc334035e073..dd4ca39d5d8f6 100644 --- a/drivers/net/ethernet/freescale/fec_main.c +++ b/drivers/net/ethernet/freescale/fec_main.c @@ -3031,6 +3031,14 @@ fec_set_mac_address(struct net_device *ndev, void *p) memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); } + /* Add netif status check here to avoid system hang in below case: + * ifconfig ethx down; ifconfig ethx hw ether xx:xx:xx:xx:xx:xx; + * After ethx down, fec all clocks are gated off and then register + * access causes system hang. + */ + if (!netif_running(ndev)) + return 0; + writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), fep->hwp + FEC_ADDR_LOW); -- GitLab From f2be053c83ee93888fc09d90df2bded0deb28947 Mon Sep 17 00:00:00 2001 From: Hariprasad Shenai Date: Thu, 10 Sep 2015 09:55:13 +0530 Subject: [PATCH 6888/7006] cxgb4: changes for new firmware 1.14.4.0 Incorporate fw_ldst_cmd structure change for new firmware and also update version string for the same Signed-off-by: Hariprasad Shenai Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h | 33 +++++++++++++++++-- .../net/ethernet/chelsio/cxgb4/t4fw_version.h | 12 +++---- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h index ab4674684acc2..a32de30ea663b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h @@ -762,8 +762,6 @@ enum fw_ldst_func_mod_index { struct fw_ldst_cmd { __be32 op_to_addrspace; -#define FW_LDST_CMD_ADDRSPACE_S 0 -#define FW_LDST_CMD_ADDRSPACE_V(x) ((x) << FW_LDST_CMD_ADDRSPACE_S) __be32 cycles_to_len16; union fw_ldst { struct fw_ldst_addrval { @@ -788,6 +786,13 @@ struct fw_ldst_cmd { __be16 vctl; __be16 rval; } mdio; + struct fw_ldst_cim_rq { + u8 req_first64[8]; + u8 req_second64[8]; + u8 resp_first64[8]; + u8 resp_second64[8]; + __be32 r3[2]; + } cim_rq; union fw_ldst_mps { struct fw_ldst_mps_rplc { __be16 fid_idx; @@ -828,9 +833,33 @@ struct fw_ldst_cmd { __be16 nset_pkd; __be32 data[12]; } pcie; + struct fw_ldst_i2c_deprecated { + u8 pid_pkd; + u8 base; + u8 boffset; + u8 data; + __be32 r9; + } i2c_deprecated; + struct fw_ldst_i2c { + u8 pid; + u8 did; + u8 boffset; + u8 blen; + __be32 r9; + __u8 data[48]; + } i2c; + struct fw_ldst_le { + __be32 index; + __be32 r9; + u8 val[33]; + u8 r11[7]; + } le; } u; }; +#define FW_LDST_CMD_ADDRSPACE_S 0 +#define FW_LDST_CMD_ADDRSPACE_V(x) ((x) << FW_LDST_CMD_ADDRSPACE_S) + #define FW_LDST_CMD_MSG_S 31 #define FW_LDST_CMD_MSG_V(x) ((x) << FW_LDST_CMD_MSG_S) diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h index 92bafa793de6c..c4b262ca7d436 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h @@ -36,8 +36,8 @@ #define __T4FW_VERSION_H__ #define T4FW_VERSION_MAJOR 0x01 -#define T4FW_VERSION_MINOR 0x0D -#define T4FW_VERSION_MICRO 0x20 +#define T4FW_VERSION_MINOR 0x0E +#define T4FW_VERSION_MICRO 0x04 #define T4FW_VERSION_BUILD 0x00 #define T4FW_MIN_VERSION_MAJOR 0x01 @@ -45,8 +45,8 @@ #define T4FW_MIN_VERSION_MICRO 0x00 #define T5FW_VERSION_MAJOR 0x01 -#define T5FW_VERSION_MINOR 0x0D -#define T5FW_VERSION_MICRO 0x20 +#define T5FW_VERSION_MINOR 0x0E +#define T5FW_VERSION_MICRO 0x04 #define T5FW_VERSION_BUILD 0x00 #define T5FW_MIN_VERSION_MAJOR 0x00 @@ -54,8 +54,8 @@ #define T5FW_MIN_VERSION_MICRO 0x00 #define T6FW_VERSION_MAJOR 0x01 -#define T6FW_VERSION_MINOR 0x0D -#define T6FW_VERSION_MICRO 0x2D +#define T6FW_VERSION_MINOR 0x0E +#define T6FW_VERSION_MICRO 0x04 #define T6FW_VERSION_BUILD 0x00 #define T6FW_MIN_VERSION_MAJOR 0x00 -- GitLab From a66e36568e30ed3714c0e3a12bd3b64696343ff5 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 10 Sep 2015 01:20:46 +0200 Subject: [PATCH 6889/7006] netlink, mmap: don't walk rx ring on poll if receive queue non-empty In case of netlink mmap, there can be situations where received frames have to be placed into the normal receive queue. The ring buffer indicates this through NL_MMAP_STATUS_COPY, so the user is asked to pick them up via recvmsg(2) syscall, and to put the slot back to NL_MMAP_STATUS_UNUSED. Commit 0ef707700f1c ("netlink: rx mmap: fix POLLIN condition") changed polling, so that we walk in the worst case the whole ring through the new netlink_has_valid_frame(), for example, when the ring would have no NL_MMAP_STATUS_VALID, but at least one NL_MMAP_STATUS_COPY frame. Since we do a datagram_poll() already earlier to pick up a mask that could possibly contain POLLIN | POLLRDNORM already (due to NL_MMAP_STATUS_COPY), we can skip checking the rx ring entirely. In case the kernel is compiled with !CONFIG_NETLINK_MMAP, then all this is irrelevant anyway as netlink_poll() is just defined as datagram_poll(). Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- net/netlink/af_netlink.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 50889be1517d0..173817a5dfad0 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -674,12 +674,19 @@ static unsigned int netlink_poll(struct file *file, struct socket *sock, mask = datagram_poll(file, sock, wait); - spin_lock_bh(&sk->sk_receive_queue.lock); - if (nlk->rx_ring.pg_vec) { - if (netlink_has_valid_frame(&nlk->rx_ring)) - mask |= POLLIN | POLLRDNORM; + /* We could already have received frames in the normal receive + * queue, that will show up as NL_MMAP_STATUS_COPY in the ring, + * so if mask contains pollin/etc already, there's no point + * walking the ring. + */ + if ((mask & (POLLIN | POLLRDNORM)) != (POLLIN | POLLRDNORM)) { + spin_lock_bh(&sk->sk_receive_queue.lock); + if (nlk->rx_ring.pg_vec) { + if (netlink_has_valid_frame(&nlk->rx_ring)) + mask |= POLLIN | POLLRDNORM; + } + spin_unlock_bh(&sk->sk_receive_queue.lock); } - spin_unlock_bh(&sk->sk_receive_queue.lock); spin_lock_bh(&sk->sk_write_queue.lock); if (nlk->tx_ring.pg_vec) { -- GitLab From 6bb0fef489f667cf701853054f44579754f00a06 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 10 Sep 2015 02:10:57 +0200 Subject: [PATCH 6890/7006] netlink, mmap: fix edge-case leakages in nf queue zero-copy When netlink mmap on receive side is the consumer of nf queue data, it can happen that in some edge cases, we write skb shared info into the user space mmap buffer: Assume a possible rx ring frame size of only 4096, and the network skb, which is being zero-copied into the netlink skb, contains page frags with an overall skb->len larger than the linear part of the netlink skb. skb_zerocopy(), which is generic and thus not aware of the fact that shared info cannot be accessed for such skbs then tries to write and fill frags, thus leaking kernel data/pointers and in some corner cases possibly writing out of bounds of the mmap area (when filling the last slot in the ring buffer this way). I.e. the ring buffer slot is then of status NL_MMAP_STATUS_VALID, has an advertised length larger than 4096, where the linear part is visible at the slot beginning, and the leaked sizeof(struct skb_shared_info) has been written to the beginning of the next slot (also corrupting the struct nl_mmap_hdr slot header incl. status etc), since skb->end points to skb->data + ring->frame_size - NL_MMAP_HDRLEN. The fix adds and lets __netlink_alloc_skb() take the actual needed linear room for the network skb + meta data into account. It's completely irrelevant for non-mmaped netlink sockets, but in case mmap sockets are used, it can be decided whether the available skb_tailroom() is really large enough for the buffer, or whether it needs to internally fallback to a normal alloc_skb(). >From nf queue side, the information whether the destination port is an mmap RX ring is not really available without extra port-to-socket lookup, thus it can only be determined in lower layers i.e. when __netlink_alloc_skb() is called that checks internally for this. I chose to add the extra ldiff parameter as mmap will then still work: We have data_len and hlen in nfqnl_build_packet_message(), data_len is the full length (capped at queue->copy_range) for skb_zerocopy() and hlen some possible part of data_len that needs to be copied; the rem_len variable indicates the needed remaining linear mmap space. The only other workaround in nf queue internally would be after allocation time by f.e. cap'ing the data_len to the skb_tailroom() iff we deal with an mmap skb, but that would 1) expose the fact that we use a mmap skb to upper layers, and 2) trim the skb where we otherwise could just have moved the full skb into the normal receive queue. After the patch, in my test case the ring slot doesn't fit and therefore shows NL_MMAP_STATUS_COPY, where a full skb carries all the data and thus needs to be picked up via recv(). Fixes: 3ab1f683bf8b ("nfnetlink: add support for memory mapped netlink") Signed-off-by: Daniel Borkmann Signed-off-by: David S. Miller --- include/linux/netlink.h | 13 +++++++++++-- net/netfilter/nfnetlink_queue_core.c | 5 +++-- net/netlink/af_netlink.c | 18 ++++++++++++------ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 9120edb650a06..639e9b8b0e4d9 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -68,8 +68,17 @@ extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); extern void __netlink_clear_multicast_users(struct sock *sk, unsigned int group); extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); extern int netlink_has_listeners(struct sock *sk, unsigned int group); -extern struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size, - u32 dst_portid, gfp_t gfp_mask); + +extern struct sk_buff *__netlink_alloc_skb(struct sock *ssk, unsigned int size, + unsigned int ldiff, u32 dst_portid, + gfp_t gfp_mask); +static inline struct sk_buff * +netlink_alloc_skb(struct sock *ssk, unsigned int size, u32 dst_portid, + gfp_t gfp_mask) +{ + return __netlink_alloc_skb(ssk, size, 0, dst_portid, gfp_mask); +} + extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock); extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid, __u32 group, gfp_t allocation); diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c index 685cc6a17163f..a5cd6d90b78b1 100644 --- a/net/netfilter/nfnetlink_queue_core.c +++ b/net/netfilter/nfnetlink_queue_core.c @@ -301,7 +301,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, __be32 **packet_id_ptr) { size_t size; - size_t data_len = 0, cap_len = 0; + size_t data_len = 0, cap_len = 0, rem_len = 0; unsigned int hlen = 0; struct sk_buff *skb; struct nlattr *nla; @@ -360,6 +360,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, hlen = min_t(unsigned int, hlen, data_len); size += sizeof(struct nlattr) + hlen; cap_len = entskb->len; + rem_len = data_len - hlen; break; } @@ -377,7 +378,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue, size += nla_total_size(seclen); } - skb = nfnetlink_alloc_skb(net, size, queue->peer_portid, + skb = __netlink_alloc_skb(net->nfnl, size, rem_len, queue->peer_portid, GFP_ATOMIC); if (!skb) { skb_tx_error(entskb); diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 173817a5dfad0..7f86d3b550601 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -1844,15 +1844,16 @@ retry: } EXPORT_SYMBOL(netlink_unicast); -struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size, - u32 dst_portid, gfp_t gfp_mask) +struct sk_buff *__netlink_alloc_skb(struct sock *ssk, unsigned int size, + unsigned int ldiff, u32 dst_portid, + gfp_t gfp_mask) { #ifdef CONFIG_NETLINK_MMAP + unsigned int maxlen, linear_size; struct sock *sk = NULL; struct sk_buff *skb; struct netlink_ring *ring; struct nl_mmap_hdr *hdr; - unsigned int maxlen; sk = netlink_getsockbyportid(ssk, dst_portid); if (IS_ERR(sk)) @@ -1863,7 +1864,11 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size, if (ring->pg_vec == NULL) goto out_put; - if (ring->frame_size - NL_MMAP_HDRLEN < size) + /* We need to account the full linear size needed as a ring + * slot cannot have non-linear parts. + */ + linear_size = size + ldiff; + if (ring->frame_size - NL_MMAP_HDRLEN < linear_size) goto out_put; skb = alloc_skb_head(gfp_mask); @@ -1877,13 +1882,14 @@ struct sk_buff *netlink_alloc_skb(struct sock *ssk, unsigned int size, /* check again under lock */ maxlen = ring->frame_size - NL_MMAP_HDRLEN; - if (maxlen < size) + if (maxlen < linear_size) goto out_free; netlink_forward_ring(ring); hdr = netlink_current_frame(ring, NL_MMAP_STATUS_UNUSED); if (hdr == NULL) goto err2; + netlink_ring_setup_skb(skb, sk, ring, hdr); netlink_set_status(hdr, NL_MMAP_STATUS_RESERVED); atomic_inc(&ring->pending); @@ -1909,7 +1915,7 @@ out: #endif return alloc_skb(size, gfp_mask); } -EXPORT_SYMBOL_GPL(netlink_alloc_skb); +EXPORT_SYMBOL_GPL(__netlink_alloc_skb); int netlink_has_listeners(struct sock *sk, unsigned int group) { -- GitLab From b14132797d8041a42e03f4ffa1e722da1425adfb Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Tue, 18 Aug 2015 03:28:01 -0400 Subject: [PATCH 6891/7006] elf-em.h: move EM_MICROBLAZE to the common header The linux/audit.h header uses EM_MICROBLAZE in order to define AUDIT_ARCH_MICROBLAZE, but it's only available in the microblaze asm headers. Move it to the common elf-em.h header so that the define can be used on non-microblaze systems. Otherwise we get build errors that EM_MICROBLAZE isn't defined when we try to use the AUDIT_ARCH_MICROBLAZE symbol. Signed-off-by: Mike Frysinger Signed-off-by: Michal Simek --- arch/microblaze/include/uapi/asm/elf.h | 3 ++- include/uapi/linux/elf-em.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/microblaze/include/uapi/asm/elf.h b/arch/microblaze/include/uapi/asm/elf.h index be1731d5e2fa2..e9bcdb6e0086b 100644 --- a/arch/microblaze/include/uapi/asm/elf.h +++ b/arch/microblaze/include/uapi/asm/elf.h @@ -11,12 +11,13 @@ #ifndef _UAPI_ASM_MICROBLAZE_ELF_H #define _UAPI_ASM_MICROBLAZE_ELF_H +#include + /* * Note there is no "official" ELF designation for Microblaze. * I've snaffled the value from the microblaze binutils source code * /binutils/microblaze/include/elf/microblaze.h */ -#define EM_MICROBLAZE 189 #define EM_MICROBLAZE_OLD 0xbaab #define ELF_ARCH EM_MICROBLAZE diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h index 3429a3ba382b6..b56dfcfe922ae 100644 --- a/include/uapi/linux/elf-em.h +++ b/include/uapi/linux/elf-em.h @@ -39,6 +39,7 @@ #define EM_TI_C6000 140 /* TI C6X DSPs */ #define EM_AARCH64 183 /* ARM 64 bit */ #define EM_TILEPRO 188 /* Tilera TILEPro */ +#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ #define EM_TILEGX 191 /* Tilera TILE-Gx */ #define EM_FRV 0x5441 /* Fujitsu FR-V */ #define EM_AVR32 0x18ad /* Atmel AVR32 */ -- GitLab From 1ab1e895492d8084dfc1c854efacde219e56b8c1 Mon Sep 17 00:00:00 2001 From: Henrik Austad Date: Wed, 9 Sep 2015 12:25:17 +0200 Subject: [PATCH 6892/7006] ether: add IEEE 1722 ethertype - TSN IEEE 1722 describes AVB (later renamed to TSN - Time Sensitive Networking), a protocol, encapsualtion and synchronization to utilize standard networks for audio/video (and later other time-sensitive) streams. This standard uses ethertype 0x22F0. http://standards.ieee.org/develop/regauth/ethertype/eth.txt This is a respin of a previous patch ("ether: add AVB frame type ETH_P_AVB") CC: "David S. Miller" CC: netdev@vger.kernel.org CC: linux-api@vger.kernel.org CC: linux-kernel@vger.kernel.org Signed-off-by: Henrik Austad Signed-off-by: David S. Miller --- include/uapi/linux/if_ether.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h index aa63ed023c2b9..ea9221b0331ad 100644 --- a/include/uapi/linux/if_ether.h +++ b/include/uapi/linux/if_ether.h @@ -42,6 +42,7 @@ #define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ #define ETH_P_PUP 0x0200 /* Xerox PUP packet */ #define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ +#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */ #define ETH_P_IP 0x0800 /* Internet Protocol packet */ #define ETH_P_X25 0x0805 /* CCITT X.25 */ #define ETH_P_ARP 0x0806 /* Address Resolution packet */ -- GitLab From 982b0b2dd590c00f089fc6fe915bd0cb302a7f5c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 9 Sep 2015 16:52:09 +0200 Subject: [PATCH 6893/7006] drm/i915: Fix CSR MMIO address check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix a wrong logical AND (&&) used for the range check of CSR MMIO. Spotted nicely by gcc -Wlogical-op flag: drivers/gpu/drm/i915/intel_csr.c: In function ‘finish_csr_load’: drivers/gpu/drm/i915/intel_csr.c:353:41: warning: logical ‘and’ of mutually exclusive tests is always false [-Wlogical-op] Fixes: eb805623d8b1 ('drm/i915/skl: Add support to load SKL CSR firmware.') Cc: # v4.2 Signed-off-by: Takashi Iwai Reviewed-by: Daniel Vetter Reviewed-by: Animesh Manna Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_csr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/i915/intel_csr.c b/drivers/gpu/drm/i915/intel_csr.c index ba1ae031e6fd4..d0f1b8d833cd2 100644 --- a/drivers/gpu/drm/i915/intel_csr.c +++ b/drivers/gpu/drm/i915/intel_csr.c @@ -350,7 +350,7 @@ static void finish_csr_load(const struct firmware *fw, void *context) } csr->mmio_count = dmc_header->mmio_count; for (i = 0; i < dmc_header->mmio_count; i++) { - if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE && + if (dmc_header->mmioaddr[i] < CSR_MMIO_START_RANGE || dmc_header->mmioaddr[i] > CSR_MMIO_END_RANGE) { DRM_ERROR(" Firmware has wrong mmio address 0x%x\n", dmc_header->mmioaddr[i]); -- GitLab From 58590c14d80defc94e900308a9d8fa55284de6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= Date: Tue, 8 Sep 2015 21:05:12 +0300 Subject: [PATCH 6894/7006] drm/i915: Don't try to use DDR DVFS on CHV when disabled in the BIOS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If one disables DDR DVFS in the BIOS, Punit will apparently ignores all DDR DVFS request. Currently we assume that DDR DVFS is always operational, which leads to errors in dmesg when the DDR DVFS requests time out. Fix the problem by gently prodding Punit during driver load to find out whether it will respond to DDR DVFS requests. If the request times out, we assume that DDR DVFS has been permanenly disabled in the BIOS and no longer perster the Punit about it. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=91629 Signed-off-by: Ville Syrjälä Reviewed-by: Clint Taylor Tested-by: Clint Taylor Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 2 ++ drivers/gpu/drm/i915/intel_pm.c | 42 +++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 522da7b12a882..b06e030807719 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -1928,6 +1928,8 @@ struct drm_i915_private { struct skl_wm_values skl_hw; struct vlv_wm_values vlv; }; + + uint8_t max_level; } wm; struct i915_runtime_pm pm; diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index fff0c22682ee3..ddbb7ed0a1932 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -955,8 +955,6 @@ enum vlv_wm_level { VLV_WM_LEVEL_PM2, VLV_WM_LEVEL_PM5, VLV_WM_LEVEL_DDR_DVFS, - CHV_WM_NUM_LEVELS, - VLV_WM_NUM_LEVELS = 1, }; /* latency must be in 0.1us units. */ @@ -982,9 +980,13 @@ static void vlv_setup_wm_latency(struct drm_device *dev) /* all latencies in usec */ dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM2] = 3; + dev_priv->wm.max_level = VLV_WM_LEVEL_PM2; + if (IS_CHERRYVIEW(dev_priv)) { dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM5] = 12; dev_priv->wm.pri_latency[VLV_WM_LEVEL_DDR_DVFS] = 33; + + dev_priv->wm.max_level = VLV_WM_LEVEL_DDR_DVFS; } } @@ -1137,10 +1139,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc) memset(wm_state, 0, sizeof(*wm_state)); wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed; - if (IS_CHERRYVIEW(dev)) - wm_state->num_levels = CHV_WM_NUM_LEVELS; - else - wm_state->num_levels = VLV_WM_NUM_LEVELS; + wm_state->num_levels = to_i915(dev)->wm.max_level + 1; wm_state->num_active_planes = 0; @@ -1220,7 +1219,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc) } /* clear any (partially) filled invalid levels */ - for (level = wm_state->num_levels; level < CHV_WM_NUM_LEVELS; level++) { + for (level = wm_state->num_levels; level < to_i915(dev)->wm.max_level + 1; level++) { memset(&wm_state->wm[level], 0, sizeof(wm_state->wm[level])); memset(&wm_state->sr[level], 0, sizeof(wm_state->sr[level])); } @@ -1324,10 +1323,7 @@ static void vlv_merge_wm(struct drm_device *dev, struct intel_crtc *crtc; int num_active_crtcs = 0; - if (IS_CHERRYVIEW(dev)) - wm->level = VLV_WM_LEVEL_DDR_DVFS; - else - wm->level = VLV_WM_LEVEL_PM2; + wm->level = to_i915(dev)->wm.max_level; wm->cxsr = true; for_each_intel_crtc(dev, crtc) { @@ -4083,9 +4079,29 @@ void vlv_wm_get_hw_state(struct drm_device *dev) if (val & DSP_MAXFIFO_PM5_ENABLE) wm->level = VLV_WM_LEVEL_PM5; + /* + * If DDR DVFS is disabled in the BIOS, Punit + * will never ack the request. So if that happens + * assume we don't have to enable/disable DDR DVFS + * dynamically. To test that just set the REQ_ACK + * bit to poke the Punit, but don't change the + * HIGH/LOW bits so that we don't actually change + * the current state. + */ val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2); - if ((val & FORCE_DDR_HIGH_FREQ) == 0) - wm->level = VLV_WM_LEVEL_DDR_DVFS; + val |= FORCE_DDR_FREQ_REQ_ACK; + vlv_punit_write(dev_priv, PUNIT_REG_DDR_SETUP2, val); + + if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2) & + FORCE_DDR_FREQ_REQ_ACK) == 0, 3)) { + DRM_DEBUG_KMS("Punit not acking DDR DVFS request, " + "assuming DDR DVFS is disabled\n"); + dev_priv->wm.max_level = VLV_WM_LEVEL_PM5; + } else { + val = vlv_punit_read(dev_priv, PUNIT_REG_DDR_SETUP2); + if ((val & FORCE_DDR_HIGH_FREQ) == 0) + wm->level = VLV_WM_LEVEL_DDR_DVFS; + } mutex_unlock(&dev_priv->rps.hw_lock); } -- GitLab From 824257857fd81f5e749831ff9cd63566b5a86abe Mon Sep 17 00:00:00 2001 From: Gaurav K Singh Date: Mon, 3 Aug 2015 15:45:32 +0530 Subject: [PATCH 6895/7006] drm/i915: Allow DSI dual link to be configured on any pipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just like single link MIPI panels, similarly for dual link panels, pipe to be configured is based on the DVO port from VBT Block 2. In hardware, Port A is mapped with Pipe A and Port C is mapped with Pipe B. This issue got introduced in - commit 7e9804fdcffc650515c60f524b8b2076ee59e710 Author: Jani Nikula Date: Fri Jan 16 14:27:23 2015 +0200 drm/i915/dsi: add drm mipi dsi host support Cc: stable@vger.kernel.org # v4.0 Signed-off-by: Gaurav K Singh Reviewed-by: Ville Syrjälä Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dsi.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c index 4a601cf90f16c..32a6c7184ca4f 100644 --- a/drivers/gpu/drm/i915/intel_dsi.c +++ b/drivers/gpu/drm/i915/intel_dsi.c @@ -1048,11 +1048,7 @@ void intel_dsi_init(struct drm_device *dev) intel_connector->unregister = intel_connector_unregister; /* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */ - if (dev_priv->vbt.dsi.config->dual_link) { - /* XXX: does dual link work on either pipe? */ - intel_encoder->crtc_mask = (1 << PIPE_A); - intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C)); - } else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) { + if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) { intel_encoder->crtc_mask = (1 << PIPE_A); intel_dsi->ports = (1 << PORT_A); } else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) { @@ -1060,6 +1056,9 @@ void intel_dsi_init(struct drm_device *dev) intel_dsi->ports = (1 << PORT_C); } + if (dev_priv->vbt.dsi.config->dual_link) + intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C)); + /* Create a DSI host (and a device) for each port. */ for_each_dsi_port(port, intel_dsi->ports) { struct intel_dsi_host *host; -- GitLab From 420203204eada39cfe0e8eb65e609da7b209cf33 Mon Sep 17 00:00:00 2001 From: Corinna Vinschen Date: Thu, 10 Sep 2015 10:47:35 +0200 Subject: [PATCH 6896/7006] r8169: Fix sleeping function called during get_stats64, v2 Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=104031 Fixes: 6e85d5ad36a26debc23a9a865c029cbe242b2dc8 Based on the discussion starting at http://www.spinics.net/lists/netdev/msg342193.html Tested locally on RTL8168evl/8111evl with various concurrent processes accessing /proc/net/dev while changing the link state as well as removing/reloading the r8169 module. Signed-off-by: Corinna Vinschen Tested-by: poma Signed-off-by: David S. Miller --- drivers/net/ethernet/realtek/r8169.c | 137 +++++++++++---------------- 1 file changed, 54 insertions(+), 83 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c index 24dcbe62412a1..2b32e0c5a0b46 100644 --- a/drivers/net/ethernet/realtek/r8169.c +++ b/drivers/net/ethernet/realtek/r8169.c @@ -833,7 +833,8 @@ struct rtl8169_private { unsigned features; struct mii_if_info mii; - struct rtl8169_counters counters; + dma_addr_t counters_phys_addr; + struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; u32 saved_wolopts; u32 opts1_mask; @@ -2190,53 +2191,37 @@ static int rtl8169_get_sset_count(struct net_device *dev, int sset) } } -static struct rtl8169_counters *rtl8169_map_counters(struct net_device *dev, - dma_addr_t *paddr, - u32 counter_cmd) +DECLARE_RTL_COND(rtl_counters_cond) { - struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - struct device *d = &tp->pci_dev->dev; - struct rtl8169_counters *counters; - u32 cmd; - counters = dma_alloc_coherent(d, sizeof(*counters), paddr, GFP_KERNEL); - if (counters) { - RTL_W32(CounterAddrHigh, (u64)*paddr >> 32); - cmd = (u64)*paddr & DMA_BIT_MASK(32); - RTL_W32(CounterAddrLow, cmd); - RTL_W32(CounterAddrLow, cmd | counter_cmd); - } - return counters; + return RTL_R32(CounterAddrLow) & (CounterReset | CounterDump); } -static void rtl8169_unmap_counters (struct net_device *dev, - dma_addr_t paddr, - struct rtl8169_counters *counters) +static bool rtl8169_do_counters(struct net_device *dev, u32 counter_cmd) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - struct device *d = &tp->pci_dev->dev; + dma_addr_t paddr = tp->counters_phys_addr; + u32 cmd; + bool ret; - RTL_W32(CounterAddrLow, 0); - RTL_W32(CounterAddrHigh, 0); + RTL_W32(CounterAddrHigh, (u64)paddr >> 32); + cmd = (u64)paddr & DMA_BIT_MASK(32); + RTL_W32(CounterAddrLow, cmd); + RTL_W32(CounterAddrLow, cmd | counter_cmd); - dma_free_coherent(d, sizeof(*counters), counters, paddr); -} + ret = rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000); -DECLARE_RTL_COND(rtl_reset_counters_cond) -{ - void __iomem *ioaddr = tp->mmio_addr; + RTL_W32(CounterAddrLow, 0); + RTL_W32(CounterAddrHigh, 0); - return RTL_R32(CounterAddrLow) & CounterReset; + return ret; } static bool rtl8169_reset_counters(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); - struct rtl8169_counters *counters; - dma_addr_t paddr; - bool ret = true; /* * Versions prior to RTL_GIGA_MAC_VER_19 don't support resetting the @@ -2245,32 +2230,13 @@ static bool rtl8169_reset_counters(struct net_device *dev) if (tp->mac_version < RTL_GIGA_MAC_VER_19) return true; - counters = rtl8169_map_counters(dev, &paddr, CounterReset); - if (!counters) - return false; - - if (!rtl_udelay_loop_wait_low(tp, &rtl_reset_counters_cond, 10, 1000)) - ret = false; - - rtl8169_unmap_counters(dev, paddr, counters); - - return ret; -} - -DECLARE_RTL_COND(rtl_counters_cond) -{ - void __iomem *ioaddr = tp->mmio_addr; - - return RTL_R32(CounterAddrLow) & CounterDump; + return rtl8169_do_counters(dev, CounterReset); } static bool rtl8169_update_counters(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; - struct rtl8169_counters *counters; - dma_addr_t paddr; - bool ret = true; /* * Some chips are unable to dump tally counters when the receiver @@ -2279,23 +2245,13 @@ static bool rtl8169_update_counters(struct net_device *dev) if ((RTL_R8(ChipCmd) & CmdRxEnb) == 0) return true; - counters = rtl8169_map_counters(dev, &paddr, CounterDump); - if (!counters) - return false; - - if (rtl_udelay_loop_wait_low(tp, &rtl_counters_cond, 10, 1000)) - memcpy(&tp->counters, counters, sizeof(*counters)); - else - ret = false; - - rtl8169_unmap_counters(dev, paddr, counters); - - return ret; + return rtl8169_do_counters(dev, CounterDump); } static bool rtl8169_init_counter_offsets(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_counters *counters = tp->counters; bool ret = false; /* @@ -2323,9 +2279,9 @@ static bool rtl8169_init_counter_offsets(struct net_device *dev) if (rtl8169_update_counters(dev)) ret = true; - tp->tc_offset.tx_errors = tp->counters.tx_errors; - tp->tc_offset.tx_multi_collision = tp->counters.tx_multi_collision; - tp->tc_offset.tx_aborted = tp->counters.tx_aborted; + tp->tc_offset.tx_errors = counters->tx_errors; + tp->tc_offset.tx_multi_collision = counters->tx_multi_collision; + tp->tc_offset.tx_aborted = counters->tx_aborted; tp->tc_offset.inited = true; return ret; @@ -2335,24 +2291,25 @@ static void rtl8169_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { struct rtl8169_private *tp = netdev_priv(dev); + struct rtl8169_counters *counters = tp->counters; ASSERT_RTNL(); rtl8169_update_counters(dev); - data[0] = le64_to_cpu(tp->counters.tx_packets); - data[1] = le64_to_cpu(tp->counters.rx_packets); - data[2] = le64_to_cpu(tp->counters.tx_errors); - data[3] = le32_to_cpu(tp->counters.rx_errors); - data[4] = le16_to_cpu(tp->counters.rx_missed); - data[5] = le16_to_cpu(tp->counters.align_errors); - data[6] = le32_to_cpu(tp->counters.tx_one_collision); - data[7] = le32_to_cpu(tp->counters.tx_multi_collision); - data[8] = le64_to_cpu(tp->counters.rx_unicast); - data[9] = le64_to_cpu(tp->counters.rx_broadcast); - data[10] = le32_to_cpu(tp->counters.rx_multicast); - data[11] = le16_to_cpu(tp->counters.tx_aborted); - data[12] = le16_to_cpu(tp->counters.tx_underun); + data[0] = le64_to_cpu(counters->tx_packets); + data[1] = le64_to_cpu(counters->rx_packets); + data[2] = le64_to_cpu(counters->tx_errors); + data[3] = le32_to_cpu(counters->rx_errors); + data[4] = le16_to_cpu(counters->rx_missed); + data[5] = le16_to_cpu(counters->align_errors); + data[6] = le32_to_cpu(counters->tx_one_collision); + data[7] = le32_to_cpu(counters->tx_multi_collision); + data[8] = le64_to_cpu(counters->rx_unicast); + data[9] = le64_to_cpu(counters->rx_broadcast); + data[10] = le32_to_cpu(counters->rx_multicast); + data[11] = le16_to_cpu(counters->tx_aborted); + data[12] = le16_to_cpu(counters->tx_underun); } static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -7780,6 +7737,7 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { struct rtl8169_private *tp = netdev_priv(dev); void __iomem *ioaddr = tp->mmio_addr; + struct rtl8169_counters *counters = tp->counters; unsigned int start; if (netif_running(dev)) @@ -7816,11 +7774,11 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) * Subtract values fetched during initalization. * See rtl8169_init_counter_offsets for a description why we do that. */ - stats->tx_errors = le64_to_cpu(tp->counters.tx_errors) - + stats->tx_errors = le64_to_cpu(counters->tx_errors) - le64_to_cpu(tp->tc_offset.tx_errors); - stats->collisions = le32_to_cpu(tp->counters.tx_multi_collision) - + stats->collisions = le32_to_cpu(counters->tx_multi_collision) - le32_to_cpu(tp->tc_offset.tx_multi_collision); - stats->tx_aborted_errors = le16_to_cpu(tp->counters.tx_aborted) - + stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted) - le16_to_cpu(tp->tc_offset.tx_aborted); return stats; @@ -8022,6 +7980,9 @@ static void rtl_remove_one(struct pci_dev *pdev) unregister_netdev(dev); + dma_free_coherent(&tp->pci_dev->dev, sizeof(*tp->counters), + tp->counters, tp->counters_phys_addr); + rtl_release_firmware(tp); if (pci_dev_run_wake(pdev)) @@ -8447,9 +8408,16 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->rtl_fw = RTL_FIRMWARE_UNKNOWN; + tp->counters = dma_alloc_coherent (&pdev->dev, sizeof(*tp->counters), + &tp->counters_phys_addr, GFP_KERNEL); + if (!tp->counters) { + rc = -ENOMEM; + goto err_out_msi_4; + } + rc = register_netdev(dev); if (rc < 0) - goto err_out_msi_4; + goto err_out_cnt_5; pci_set_drvdata(pdev, dev); @@ -8483,6 +8451,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) out: return rc; +err_out_cnt_5: + dma_free_coherent(&pdev->dev, sizeof(*tp->counters), tp->counters, + tp->counters_phys_addr); err_out_msi_4: netif_napi_del(&tp->napi); rtl_disable_msi(pdev, tp); -- GitLab From 4c82ac3c37363e8c4ded6a5fe1ec5fa756b34df3 Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 10 Sep 2015 11:18:57 +0100 Subject: [PATCH 6897/7006] xen-netback: respect user provided max_queues Originally that parameter was always reset to num_online_cpus during module initialisation, which renders it useless. The fix is to only set max_queues to num_online_cpus when user has not provided a value. Reported-by: Johnny Strom Signed-off-by: Wei Liu Reviewed-by: David Vrabel Acked-by: Ian Campbell Signed-off-by: David S. Miller --- drivers/net/xen-netback/netback.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c index b588b1a08cd4b..abc1381264fc2 100644 --- a/drivers/net/xen-netback/netback.c +++ b/drivers/net/xen-netback/netback.c @@ -2114,8 +2114,11 @@ static int __init netback_init(void) if (!xen_domain()) return -ENODEV; - /* Allow as many queues as there are CPUs, by default */ - xenvif_max_queues = num_online_cpus(); + /* Allow as many queues as there are CPUs if user has not + * specified a value. + */ + if (xenvif_max_queues == 0) + xenvif_max_queues = num_online_cpus(); if (fatal_skb_slots < XEN_NETBK_LEGACY_SLOTS_MAX) { pr_info("fatal_skb_slots too small (%d), bump it to XEN_NETBK_LEGACY_SLOTS_MAX (%d)\n", -- GitLab From 32a844056fd43dda647e1c3c6b9983bdfa04d17d Mon Sep 17 00:00:00 2001 From: Wei Liu Date: Thu, 10 Sep 2015 11:18:58 +0100 Subject: [PATCH 6898/7006] xen-netfront: respect user provided max_queues Originally that parameter was always reset to num_online_cpus during module initialisation, which renders it useless. The fix is to only set max_queues to num_online_cpus when user has not provided a value. Signed-off-by: Wei Liu Cc: David Vrabel Reviewed-by: David Vrabel Tested-by: David Vrabel Signed-off-by: David S. Miller --- drivers/net/xen-netfront.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index e27e6d2ea6d28..b9c637a0036b5 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -2132,8 +2132,11 @@ static int __init netif_init(void) pr_info("Initialising Xen virtual ethernet driver\n"); - /* Allow as many queues as there are CPUs, by default */ - xennet_max_queues = num_online_cpus(); + /* Allow as many queues as there are CPUs if user has not + * specified a value. + */ + if (xennet_max_queues == 0) + xennet_max_queues = num_online_cpus(); return xenbus_register_frontend(&netfront_driver); } -- GitLab From 05c5a46d71f621df620fbabbd7758ee1b44575ad Mon Sep 17 00:00:00 2001 From: Neal Cardwell Date: Wed, 9 Sep 2015 21:54:37 -0700 Subject: [PATCH 6899/7006] tcp: generate CA_EVENT_TX_START on data frames Issuing a CC TX_START event on control frames like pure ACK is a waste of time, as a CC should not care. Following patch needs this change, as we want CUBIC to properly track idle time at a low cost, with a single TX_START being generated. Yuchung might slightly refine the condition triggering TX_START on a followup patch. Signed-off-by: Neal Cardwell Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Cc: Jana Iyengar Cc: Stephen Hemminger Cc: Sangtae Ha Cc: Lawrence Brakmo Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 1188e4fcf23bf..f9a8a12b62ee6 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -164,6 +164,9 @@ static void tcp_event_data_sent(struct tcp_sock *tp, struct inet_connection_sock *icsk = inet_csk(sk); const u32 now = tcp_time_stamp; + if (tcp_packets_in_flight(tp) == 0) + tcp_ca_event(sk, CA_EVENT_TX_START); + tp->lsndtime = now; /* If it is a reply for ato after last received @@ -940,9 +943,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, &md5); tcp_header_size = tcp_options_size + sizeof(struct tcphdr); - if (tcp_packets_in_flight(tp) == 0) - tcp_ca_event(sk, CA_EVENT_TX_START); - /* if no packet is in qdisc/device queue, then allow XPS to select * another queue. We can be called from tcp_tsq_handler() * which holds one reference to sk_wmem_alloc. -- GitLab From 30927520dbae297182990bb21d08762bcc35ce1d Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 9 Sep 2015 21:55:07 -0700 Subject: [PATCH 6900/7006] tcp_cubic: better follow cubic curve after idle period Jana Iyengar found an interesting issue on CUBIC : The epoch is only updated/reset initially and when experiencing losses. The delta "t" of now - epoch_start can be arbitrary large after app idle as well as the bic_target. Consequentially the slope (inverse of ca->cnt) would be really large, and eventually ca->cnt would be lower-bounded in the end to 2 to have delayed-ACK slow-start behavior. This particularly shows up when slow_start_after_idle is disabled as a dangerous cwnd inflation (1.5 x RTT) after few seconds of idle time. Jana initial fix was to reset epoch_start if app limited, but Neal pointed out it would ask the CUBIC algorithm to recalculate the curve so that we again start growing steeply upward from where cwnd is now (as CUBIC does just after a loss). Ideally we'd want the cwnd growth curve to be the same shape, just shifted later in time by the amount of the idle period. Reported-by: Jana Iyengar Signed-off-by: Eric Dumazet Signed-off-by: Yuchung Cheng Signed-off-by: Neal Cardwell Cc: Stephen Hemminger Cc: Sangtae Ha Cc: Lawrence Brakmo Signed-off-by: David S. Miller --- net/ipv4/tcp_cubic.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 28011fb1f4a21..c6ded6b2a79fb 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -151,6 +151,21 @@ static void bictcp_init(struct sock *sk) tcp_sk(sk)->snd_ssthresh = initial_ssthresh; } +static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) +{ + if (event == CA_EVENT_TX_START) { + s32 delta = tcp_time_stamp - tcp_sk(sk)->lsndtime; + struct bictcp *ca = inet_csk_ca(sk); + + /* We were application limited (idle) for a while. + * Shift epoch_start to keep cwnd growth to cubic curve. + */ + if (ca->epoch_start && delta > 0) + ca->epoch_start += delta; + return; + } +} + /* calculate the cubic root of x using a table lookup followed by one * Newton-Raphson iteration. * Avg err ~= 0.195% @@ -450,6 +465,7 @@ static struct tcp_congestion_ops cubictcp __read_mostly = { .cong_avoid = bictcp_cong_avoid, .set_state = bictcp_state, .undo_cwnd = bictcp_undo_cwnd, + .cwnd_event = bictcp_cwnd_event, .pkts_acked = bictcp_acked, .owner = THIS_MODULE, .name = "cubic", -- GitLab From 3f0e131221eb951c45c93d1cce9db73889be2a5e Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 9 Sep 2015 15:35:16 -0700 Subject: [PATCH 6901/7006] zpool: add zpool_has_pool() This series makes creation of the zpool and compressor dynamic, so that they can be changed at runtime. This makes using/configuring zswap easier, as before this zswap had to be configured at boot time, using boot params. This uses a single list to track both the zpool and compressor together, although Seth had mentioned an alternative which is to track the zpools and compressors using separate lists. In the most common case, only a single zpool and single compressor, using one list is slightly simpler than using two lists, and for the uncommon case of multiple zpools and/or compressors, using one list is slightly less simple (and uses slightly more memory, probably) than using two lists. This patch (of 4): Add zpool_has_pool() function, indicating if the specified type of zpool is available (i.e. zsmalloc or zbud). This allows checking if a pool is available, without actually trying to allocate it, similar to crypto_has_alg(). This is used by a following patch to zswap that enables the dynamic runtime creation of zswap zpools. Signed-off-by: Dan Streetman Acked-by: Seth Jennings Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/zpool.h | 2 ++ mm/zpool.c | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/linux/zpool.h b/include/linux/zpool.h index c924a28d98050..42f8ec9924523 100644 --- a/include/linux/zpool.h +++ b/include/linux/zpool.h @@ -36,6 +36,8 @@ enum zpool_mapmode { ZPOOL_MM_DEFAULT = ZPOOL_MM_RW }; +bool zpool_has_pool(char *type); + struct zpool *zpool_create_pool(char *type, char *name, gfp_t gfp, const struct zpool_ops *ops); diff --git a/mm/zpool.c b/mm/zpool.c index 68d2dd8ed2d8c..8f670d3e87060 100644 --- a/mm/zpool.c +++ b/mm/zpool.c @@ -99,6 +99,39 @@ static void zpool_put_driver(struct zpool_driver *driver) module_put(driver->owner); } +/** + * zpool_has_pool() - Check if the pool driver is available + * @type The type of the zpool to check (e.g. zbud, zsmalloc) + * + * This checks if the @type pool driver is available. This will try to load + * the requested module, if needed, but there is no guarantee the module will + * still be loaded and available immediately after calling. If this returns + * true, the caller should assume the pool is available, but must be prepared + * to handle the @zpool_create_pool() returning failure. However if this + * returns false, the caller should assume the requested pool type is not + * available; either the requested pool type module does not exist, or could + * not be loaded, and calling @zpool_create_pool() with the pool type will + * fail. + * + * Returns: true if @type pool is available, false if not + */ +bool zpool_has_pool(char *type) +{ + struct zpool_driver *driver = zpool_get_driver(type); + + if (!driver) { + request_module("zpool-%s", type); + driver = zpool_get_driver(type); + } + + if (!driver) + return false; + + zpool_put_driver(driver); + return true; +} +EXPORT_SYMBOL(zpool_has_pool); + /** * zpool_create_pool() - Create a new zpool * @type The type of the zpool to create (e.g. zbud, zsmalloc) -- GitLab From f1c54846ee4504d89b59b04d870831db4046b478 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 9 Sep 2015 15:35:19 -0700 Subject: [PATCH 6902/7006] zswap: dynamic pool creation Add dynamic creation of pools. Move the static crypto compression per-cpu transforms into each pool. Add a pointer to zswap_entry to the pool it's in. This is required by the following patch which enables changing the zswap zpool and compressor params at runtime. [akpm@linux-foundation.org: fix merge snafus] Signed-off-by: Dan Streetman Acked-by: Seth Jennings Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zswap.c | 548 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 405 insertions(+), 143 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index 48a1d081e2a5f..f9ba9bb1c1b89 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -99,66 +99,19 @@ module_param_named(zpool, zswap_zpool_type, charp, 0444); static struct zpool *zswap_pool; /********************************* -* compression functions +* data structures **********************************/ -/* per-cpu compression transforms */ -static struct crypto_comp * __percpu *zswap_comp_pcpu_tfms; -enum comp_op { - ZSWAP_COMPOP_COMPRESS, - ZSWAP_COMPOP_DECOMPRESS +struct zswap_pool { + struct zpool *zpool; + struct crypto_comp * __percpu *tfm; + struct kref kref; + struct list_head list; + struct rcu_head rcu_head; + struct notifier_block notifier; + char tfm_name[CRYPTO_MAX_ALG_NAME]; }; -static int zswap_comp_op(enum comp_op op, const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - struct crypto_comp *tfm; - int ret; - - tfm = *per_cpu_ptr(zswap_comp_pcpu_tfms, get_cpu()); - switch (op) { - case ZSWAP_COMPOP_COMPRESS: - ret = crypto_comp_compress(tfm, src, slen, dst, dlen); - break; - case ZSWAP_COMPOP_DECOMPRESS: - ret = crypto_comp_decompress(tfm, src, slen, dst, dlen); - break; - default: - ret = -EINVAL; - } - - put_cpu(); - return ret; -} - -static int __init zswap_comp_init(void) -{ - if (!crypto_has_comp(zswap_compressor, 0, 0)) { - pr_info("%s compressor not available\n", zswap_compressor); - /* fall back to default compressor */ - zswap_compressor = ZSWAP_COMPRESSOR_DEFAULT; - if (!crypto_has_comp(zswap_compressor, 0, 0)) - /* can't even load the default compressor */ - return -ENODEV; - } - pr_info("using %s compressor\n", zswap_compressor); - - /* alloc percpu transforms */ - zswap_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *); - if (!zswap_comp_pcpu_tfms) - return -ENOMEM; - return 0; -} - -static void __init zswap_comp_exit(void) -{ - /* free percpu transforms */ - free_percpu(zswap_comp_pcpu_tfms); -} - -/********************************* -* data structures -**********************************/ /* * struct zswap_entry * @@ -166,22 +119,24 @@ static void __init zswap_comp_exit(void) * page within zswap. * * rbnode - links the entry into red-black tree for the appropriate swap type + * offset - the swap offset for the entry. Index into the red-black tree. * refcount - the number of outstanding reference to the entry. This is needed * to protect against premature freeing of the entry by code * concurrent calls to load, invalidate, and writeback. The lock * for the zswap_tree structure that contains the entry must * be held while changing the refcount. Since the lock must * be held, there is no reason to also make refcount atomic. - * offset - the swap offset for the entry. Index into the red-black tree. - * handle - zpool allocation handle that stores the compressed page data * length - the length in bytes of the compressed page data. Needed during * decompression + * pool - the zswap_pool the entry's data is in + * handle - zpool allocation handle that stores the compressed page data */ struct zswap_entry { struct rb_node rbnode; pgoff_t offset; int refcount; unsigned int length; + struct zswap_pool *pool; unsigned long handle; }; @@ -201,6 +156,48 @@ struct zswap_tree { static struct zswap_tree *zswap_trees[MAX_SWAPFILES]; +/* RCU-protected iteration */ +static LIST_HEAD(zswap_pools); +/* protects zswap_pools list modification */ +static DEFINE_SPINLOCK(zswap_pools_lock); + +/********************************* +* helpers and fwd declarations +**********************************/ + +#define zswap_pool_debug(msg, p) \ + pr_debug("%s pool %s/%s\n", msg, (p)->tfm_name, \ + zpool_get_type((p)->zpool)) + +static int zswap_writeback_entry(struct zpool *pool, unsigned long handle); +static int zswap_pool_get(struct zswap_pool *pool); +static void zswap_pool_put(struct zswap_pool *pool); + +static const struct zpool_ops zswap_zpool_ops = { + .evict = zswap_writeback_entry +}; + +static bool zswap_is_full(void) +{ + return totalram_pages * zswap_max_pool_percent / 100 < + DIV_ROUND_UP(zswap_pool_total_size, PAGE_SIZE); +} + +static void zswap_update_total_size(void) +{ + struct zswap_pool *pool; + u64 total = 0; + + rcu_read_lock(); + + list_for_each_entry_rcu(pool, &zswap_pools, list) + total += zpool_get_total_size(pool->zpool); + + rcu_read_unlock(); + + zswap_pool_total_size = total; +} + /********************************* * zswap entry functions **********************************/ @@ -294,10 +291,11 @@ static void zswap_rb_erase(struct rb_root *root, struct zswap_entry *entry) */ static void zswap_free_entry(struct zswap_entry *entry) { - zpool_free(zswap_pool, entry->handle); + zpool_free(entry->pool->zpool, entry->handle); + zswap_pool_put(entry->pool); zswap_entry_cache_free(entry); atomic_dec(&zswap_stored_pages); - zswap_pool_total_size = zpool_get_total_size(zswap_pool); + zswap_update_total_size(); } /* caller must hold the tree lock */ @@ -339,35 +337,21 @@ static struct zswap_entry *zswap_entry_find_get(struct rb_root *root, **********************************/ static DEFINE_PER_CPU(u8 *, zswap_dstmem); -static int __zswap_cpu_notifier(unsigned long action, unsigned long cpu) +static int __zswap_cpu_dstmem_notifier(unsigned long action, unsigned long cpu) { - struct crypto_comp *tfm; u8 *dst; switch (action) { case CPU_UP_PREPARE: - tfm = crypto_alloc_comp(zswap_compressor, 0, 0); - if (IS_ERR(tfm)) { - pr_err("can't allocate compressor transform\n"); - return NOTIFY_BAD; - } - *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu) = tfm; dst = kmalloc_node(PAGE_SIZE * 2, GFP_KERNEL, cpu_to_node(cpu)); if (!dst) { pr_err("can't allocate compressor buffer\n"); - crypto_free_comp(tfm); - *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu) = NULL; return NOTIFY_BAD; } per_cpu(zswap_dstmem, cpu) = dst; break; case CPU_DEAD: case CPU_UP_CANCELED: - tfm = *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu); - if (tfm) { - crypto_free_comp(tfm); - *per_cpu_ptr(zswap_comp_pcpu_tfms, cpu) = NULL; - } dst = per_cpu(zswap_dstmem, cpu); kfree(dst); per_cpu(zswap_dstmem, cpu) = NULL; @@ -378,43 +362,303 @@ static int __zswap_cpu_notifier(unsigned long action, unsigned long cpu) return NOTIFY_OK; } -static int zswap_cpu_notifier(struct notifier_block *nb, - unsigned long action, void *pcpu) +static int zswap_cpu_dstmem_notifier(struct notifier_block *nb, + unsigned long action, void *pcpu) { - unsigned long cpu = (unsigned long)pcpu; - return __zswap_cpu_notifier(action, cpu); + return __zswap_cpu_dstmem_notifier(action, (unsigned long)pcpu); } -static struct notifier_block zswap_cpu_notifier_block = { - .notifier_call = zswap_cpu_notifier +static struct notifier_block zswap_dstmem_notifier = { + .notifier_call = zswap_cpu_dstmem_notifier, }; -static int __init zswap_cpu_init(void) +static int __init zswap_cpu_dstmem_init(void) +{ + unsigned long cpu; + + cpu_notifier_register_begin(); + for_each_online_cpu(cpu) + if (__zswap_cpu_dstmem_notifier(CPU_UP_PREPARE, cpu) == + NOTIFY_BAD) + goto cleanup; + __register_cpu_notifier(&zswap_dstmem_notifier); + cpu_notifier_register_done(); + return 0; + +cleanup: + for_each_online_cpu(cpu) + __zswap_cpu_dstmem_notifier(CPU_UP_CANCELED, cpu); + cpu_notifier_register_done(); + return -ENOMEM; +} + +static void zswap_cpu_dstmem_destroy(void) +{ + unsigned long cpu; + + cpu_notifier_register_begin(); + for_each_online_cpu(cpu) + __zswap_cpu_dstmem_notifier(CPU_UP_CANCELED, cpu); + __unregister_cpu_notifier(&zswap_dstmem_notifier); + cpu_notifier_register_done(); +} + +static int __zswap_cpu_comp_notifier(struct zswap_pool *pool, + unsigned long action, unsigned long cpu) +{ + struct crypto_comp *tfm; + + switch (action) { + case CPU_UP_PREPARE: + if (WARN_ON(*per_cpu_ptr(pool->tfm, cpu))) + break; + tfm = crypto_alloc_comp(pool->tfm_name, 0, 0); + if (IS_ERR_OR_NULL(tfm)) { + pr_err("could not alloc crypto comp %s : %ld\n", + pool->tfm_name, PTR_ERR(tfm)); + return NOTIFY_BAD; + } + *per_cpu_ptr(pool->tfm, cpu) = tfm; + break; + case CPU_DEAD: + case CPU_UP_CANCELED: + tfm = *per_cpu_ptr(pool->tfm, cpu); + if (!IS_ERR_OR_NULL(tfm)) + crypto_free_comp(tfm); + *per_cpu_ptr(pool->tfm, cpu) = NULL; + break; + default: + break; + } + return NOTIFY_OK; +} + +static int zswap_cpu_comp_notifier(struct notifier_block *nb, + unsigned long action, void *pcpu) +{ + unsigned long cpu = (unsigned long)pcpu; + struct zswap_pool *pool = container_of(nb, typeof(*pool), notifier); + + return __zswap_cpu_comp_notifier(pool, action, cpu); +} + +static int zswap_cpu_comp_init(struct zswap_pool *pool) { unsigned long cpu; + memset(&pool->notifier, 0, sizeof(pool->notifier)); + pool->notifier.notifier_call = zswap_cpu_comp_notifier; + cpu_notifier_register_begin(); for_each_online_cpu(cpu) - if (__zswap_cpu_notifier(CPU_UP_PREPARE, cpu) != NOTIFY_OK) + if (__zswap_cpu_comp_notifier(pool, CPU_UP_PREPARE, cpu) == + NOTIFY_BAD) goto cleanup; - __register_cpu_notifier(&zswap_cpu_notifier_block); + __register_cpu_notifier(&pool->notifier); cpu_notifier_register_done(); return 0; cleanup: for_each_online_cpu(cpu) - __zswap_cpu_notifier(CPU_UP_CANCELED, cpu); + __zswap_cpu_comp_notifier(pool, CPU_UP_CANCELED, cpu); cpu_notifier_register_done(); return -ENOMEM; } +static void zswap_cpu_comp_destroy(struct zswap_pool *pool) +{ + unsigned long cpu; + + cpu_notifier_register_begin(); + for_each_online_cpu(cpu) + __zswap_cpu_comp_notifier(pool, CPU_UP_CANCELED, cpu); + __unregister_cpu_notifier(&pool->notifier); + cpu_notifier_register_done(); +} + /********************************* -* helpers +* pool functions **********************************/ -static bool zswap_is_full(void) + +static struct zswap_pool *__zswap_pool_current(void) { - return totalram_pages * zswap_max_pool_percent / 100 < - DIV_ROUND_UP(zswap_pool_total_size, PAGE_SIZE); + struct zswap_pool *pool; + + pool = list_first_or_null_rcu(&zswap_pools, typeof(*pool), list); + WARN_ON(!pool); + + return pool; +} + +static struct zswap_pool *zswap_pool_current(void) +{ + assert_spin_locked(&zswap_pools_lock); + + return __zswap_pool_current(); +} + +static struct zswap_pool *zswap_pool_current_get(void) +{ + struct zswap_pool *pool; + + rcu_read_lock(); + + pool = __zswap_pool_current(); + if (!pool || !zswap_pool_get(pool)) + pool = NULL; + + rcu_read_unlock(); + + return pool; +} + +static struct zswap_pool *zswap_pool_last_get(void) +{ + struct zswap_pool *pool, *last = NULL; + + rcu_read_lock(); + + list_for_each_entry_rcu(pool, &zswap_pools, list) + last = pool; + if (!WARN_ON(!last) && !zswap_pool_get(last)) + last = NULL; + + rcu_read_unlock(); + + return last; +} + +static struct zswap_pool *zswap_pool_find_get(char *type, char *compressor) +{ + struct zswap_pool *pool; + + assert_spin_locked(&zswap_pools_lock); + + list_for_each_entry_rcu(pool, &zswap_pools, list) { + if (strncmp(pool->tfm_name, compressor, sizeof(pool->tfm_name))) + continue; + if (strncmp(zpool_get_type(pool->zpool), type, + sizeof(zswap_zpool_type))) + continue; + /* if we can't get it, it's about to be destroyed */ + if (!zswap_pool_get(pool)) + continue; + return pool; + } + + return NULL; +} + +static struct zswap_pool *zswap_pool_create(char *type, char *compressor) +{ + struct zswap_pool *pool; + gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN; + + pool = kzalloc(sizeof(*pool), GFP_KERNEL); + if (!pool) { + pr_err("pool alloc failed\n"); + return NULL; + } + + pool->zpool = zpool_create_pool(type, "zswap", gfp, &zswap_zpool_ops); + if (!pool->zpool) { + pr_err("%s zpool not available\n", type); + goto error; + } + pr_debug("using %s zpool\n", zpool_get_type(pool->zpool)); + + strlcpy(pool->tfm_name, compressor, sizeof(pool->tfm_name)); + pool->tfm = alloc_percpu(struct crypto_comp *); + if (!pool->tfm) { + pr_err("percpu alloc failed\n"); + goto error; + } + + if (zswap_cpu_comp_init(pool)) + goto error; + pr_debug("using %s compressor\n", pool->tfm_name); + + /* being the current pool takes 1 ref; this func expects the + * caller to always add the new pool as the current pool + */ + kref_init(&pool->kref); + INIT_LIST_HEAD(&pool->list); + + zswap_pool_debug("created", pool); + + return pool; + +error: + free_percpu(pool->tfm); + if (pool->zpool) + zpool_destroy_pool(pool->zpool); + kfree(pool); + return NULL; +} + +static struct zswap_pool *__zswap_pool_create_fallback(void) +{ + if (!crypto_has_comp(zswap_compressor, 0, 0)) { + pr_err("compressor %s not available, using default %s\n", + zswap_compressor, ZSWAP_COMPRESSOR_DEFAULT); + strncpy(zswap_compressor, ZSWAP_COMPRESSOR_DEFAULT, + sizeof(zswap_compressor)); + } + if (!zpool_has_pool(zswap_zpool_type)) { + pr_err("zpool %s not available, using default %s\n", + zswap_zpool_type, ZSWAP_ZPOOL_DEFAULT); + strncpy(zswap_zpool_type, ZSWAP_ZPOOL_DEFAULT, + sizeof(zswap_zpool_type)); + } + + return zswap_pool_create(zswap_zpool_type, zswap_compressor); +} + +static void zswap_pool_destroy(struct zswap_pool *pool) +{ + zswap_pool_debug("destroying", pool); + + zswap_cpu_comp_destroy(pool); + free_percpu(pool->tfm); + zpool_destroy_pool(pool->zpool); + kfree(pool); +} + +static int __must_check zswap_pool_get(struct zswap_pool *pool) +{ + return kref_get_unless_zero(&pool->kref); +} + +static void __zswap_pool_release(struct rcu_head *head) +{ + struct zswap_pool *pool = container_of(head, typeof(*pool), rcu_head); + + /* nobody should have been able to get a kref... */ + WARN_ON(kref_get_unless_zero(&pool->kref)); + + /* pool is now off zswap_pools list and has no references. */ + zswap_pool_destroy(pool); +} + +static void __zswap_pool_empty(struct kref *kref) +{ + struct zswap_pool *pool; + + pool = container_of(kref, typeof(*pool), kref); + + spin_lock(&zswap_pools_lock); + + WARN_ON(pool == zswap_pool_current()); + + list_del_rcu(&pool->list); + call_rcu(&pool->rcu_head, __zswap_pool_release); + + spin_unlock(&zswap_pools_lock); +} + +static void zswap_pool_put(struct zswap_pool *pool) +{ + kref_put(&pool->kref, __zswap_pool_empty); } /********************************* @@ -477,6 +721,7 @@ static int zswap_writeback_entry(struct zpool *pool, unsigned long handle) pgoff_t offset; struct zswap_entry *entry; struct page *page; + struct crypto_comp *tfm; u8 *src, *dst; unsigned int dlen; int ret; @@ -517,13 +762,15 @@ static int zswap_writeback_entry(struct zpool *pool, unsigned long handle) case ZSWAP_SWAPCACHE_NEW: /* page is locked */ /* decompress */ dlen = PAGE_SIZE; - src = (u8 *)zpool_map_handle(zswap_pool, entry->handle, + src = (u8 *)zpool_map_handle(entry->pool->zpool, entry->handle, ZPOOL_MM_RO) + sizeof(struct zswap_header); dst = kmap_atomic(page); - ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src, - entry->length, dst, &dlen); + tfm = *get_cpu_ptr(entry->pool->tfm); + ret = crypto_comp_decompress(tfm, src, entry->length, + dst, &dlen); + put_cpu_ptr(entry->pool->tfm); kunmap_atomic(dst); - zpool_unmap_handle(zswap_pool, entry->handle); + zpool_unmap_handle(entry->pool->zpool, entry->handle); BUG_ON(ret); BUG_ON(dlen != PAGE_SIZE); @@ -572,6 +819,22 @@ end: return ret; } +static int zswap_shrink(void) +{ + struct zswap_pool *pool; + int ret; + + pool = zswap_pool_last_get(); + if (!pool) + return -ENOENT; + + ret = zpool_shrink(pool->zpool, 1, NULL); + + zswap_pool_put(pool); + + return ret; +} + /********************************* * frontswap hooks **********************************/ @@ -581,6 +844,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, { struct zswap_tree *tree = zswap_trees[type]; struct zswap_entry *entry, *dupentry; + struct crypto_comp *tfm; int ret; unsigned int dlen = PAGE_SIZE, len; unsigned long handle; @@ -596,7 +860,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, /* reclaim space if needed */ if (zswap_is_full()) { zswap_pool_limit_hit++; - if (zpool_shrink(zswap_pool, 1, NULL)) { + if (zswap_shrink()) { zswap_reject_reclaim_fail++; ret = -ENOMEM; goto reject; @@ -611,33 +875,42 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, goto reject; } + /* if entry is successfully added, it keeps the reference */ + entry->pool = zswap_pool_current_get(); + if (!entry->pool) { + ret = -EINVAL; + goto freepage; + } + /* compress */ dst = get_cpu_var(zswap_dstmem); + tfm = *get_cpu_ptr(entry->pool->tfm); src = kmap_atomic(page); - ret = zswap_comp_op(ZSWAP_COMPOP_COMPRESS, src, PAGE_SIZE, dst, &dlen); + ret = crypto_comp_compress(tfm, src, PAGE_SIZE, dst, &dlen); kunmap_atomic(src); + put_cpu_ptr(entry->pool->tfm); if (ret) { ret = -EINVAL; - goto freepage; + goto put_dstmem; } /* store */ len = dlen + sizeof(struct zswap_header); - ret = zpool_malloc(zswap_pool, len, __GFP_NORETRY | __GFP_NOWARN, - &handle); + ret = zpool_malloc(entry->pool->zpool, len, + __GFP_NORETRY | __GFP_NOWARN, &handle); if (ret == -ENOSPC) { zswap_reject_compress_poor++; - goto freepage; + goto put_dstmem; } if (ret) { zswap_reject_alloc_fail++; - goto freepage; + goto put_dstmem; } - zhdr = zpool_map_handle(zswap_pool, handle, ZPOOL_MM_RW); + zhdr = zpool_map_handle(entry->pool->zpool, handle, ZPOOL_MM_RW); zhdr->swpentry = swp_entry(type, offset); buf = (u8 *)(zhdr + 1); memcpy(buf, dst, dlen); - zpool_unmap_handle(zswap_pool, handle); + zpool_unmap_handle(entry->pool->zpool, handle); put_cpu_var(zswap_dstmem); /* populate entry */ @@ -660,12 +933,14 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset, /* update stats */ atomic_inc(&zswap_stored_pages); - zswap_pool_total_size = zpool_get_total_size(zswap_pool); + zswap_update_total_size(); return 0; -freepage: +put_dstmem: put_cpu_var(zswap_dstmem); + zswap_pool_put(entry->pool); +freepage: zswap_entry_cache_free(entry); reject: return ret; @@ -680,6 +955,7 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, { struct zswap_tree *tree = zswap_trees[type]; struct zswap_entry *entry; + struct crypto_comp *tfm; u8 *src, *dst; unsigned int dlen; int ret; @@ -696,13 +972,14 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset, /* decompress */ dlen = PAGE_SIZE; - src = (u8 *)zpool_map_handle(zswap_pool, entry->handle, + src = (u8 *)zpool_map_handle(entry->pool->zpool, entry->handle, ZPOOL_MM_RO) + sizeof(struct zswap_header); dst = kmap_atomic(page); - ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src, entry->length, - dst, &dlen); + tfm = *get_cpu_ptr(entry->pool->tfm); + ret = crypto_comp_decompress(tfm, src, entry->length, dst, &dlen); + put_cpu_ptr(entry->pool->tfm); kunmap_atomic(dst); - zpool_unmap_handle(zswap_pool, entry->handle); + zpool_unmap_handle(entry->pool->zpool, entry->handle); BUG_ON(ret); spin_lock(&tree->lock); @@ -755,10 +1032,6 @@ static void zswap_frontswap_invalidate_area(unsigned type) zswap_trees[type] = NULL; } -static const struct zpool_ops zswap_zpool_ops = { - .evict = zswap_writeback_entry -}; - static void zswap_frontswap_init(unsigned type) { struct zswap_tree *tree; @@ -839,49 +1112,38 @@ static void __exit zswap_debugfs_exit(void) { } **********************************/ static int __init init_zswap(void) { - gfp_t gfp = __GFP_NORETRY | __GFP_NOWARN; - - pr_info("loading zswap\n"); - - zswap_pool = zpool_create_pool(zswap_zpool_type, "zswap", gfp, - &zswap_zpool_ops); - if (!zswap_pool && strcmp(zswap_zpool_type, ZSWAP_ZPOOL_DEFAULT)) { - pr_info("%s zpool not available\n", zswap_zpool_type); - zswap_zpool_type = ZSWAP_ZPOOL_DEFAULT; - zswap_pool = zpool_create_pool(zswap_zpool_type, "zswap", gfp, - &zswap_zpool_ops); - } - if (!zswap_pool) { - pr_err("%s zpool not available\n", zswap_zpool_type); - pr_err("zpool creation failed\n"); - goto error; - } - pr_info("using %s pool\n", zswap_zpool_type); + struct zswap_pool *pool; if (zswap_entry_cache_create()) { pr_err("entry cache creation failed\n"); - goto cachefail; + goto cache_fail; } - if (zswap_comp_init()) { - pr_err("compressor initialization failed\n"); - goto compfail; + + if (zswap_cpu_dstmem_init()) { + pr_err("dstmem alloc failed\n"); + goto dstmem_fail; } - if (zswap_cpu_init()) { - pr_err("per-cpu initialization failed\n"); - goto pcpufail; + + pool = __zswap_pool_create_fallback(); + if (!pool) { + pr_err("pool creation failed\n"); + goto pool_fail; } + pr_info("loaded using pool %s/%s\n", pool->tfm_name, + zpool_get_type(pool->zpool)); + + list_add(&pool->list, &zswap_pools); frontswap_register_ops(&zswap_frontswap_ops); if (zswap_debugfs_init()) pr_warn("debugfs initialization failed\n"); return 0; -pcpufail: - zswap_comp_exit(); -compfail: + +pool_fail: + zswap_cpu_dstmem_destroy(); +dstmem_fail: zswap_entry_cache_destroy(); -cachefail: - zpool_destroy_pool(zswap_pool); -error: +cache_fail: return -ENOMEM; } /* must be late so crypto has time to come up */ -- GitLab From 90b0fc26d5dbe21c7a21668320b276af9b2281d7 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 9 Sep 2015 15:35:21 -0700 Subject: [PATCH 6903/7006] zswap: change zpool/compressor at runtime Update the zpool and compressor parameters to be changeable at runtime. When changed, a new pool is created with the requested zpool/compressor, and added as the current pool at the front of the pool list. Previous pools remain in the list only to remove existing compressed pages from. The old pool(s) are removed once they become empty. Signed-off-by: Dan Streetman Acked-by: Seth Jennings Cc: Sergey Senozhatsky Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/zswap.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 129 insertions(+), 13 deletions(-) diff --git a/mm/zswap.c b/mm/zswap.c index f9ba9bb1c1b89..4043df7c672fb 100644 --- a/mm/zswap.c +++ b/mm/zswap.c @@ -80,23 +80,39 @@ static u64 zswap_duplicate_entry; static bool zswap_enabled; module_param_named(enabled, zswap_enabled, bool, 0644); -/* Compressor to be used by zswap (fixed at boot for now) */ +/* Crypto compressor to use */ #define ZSWAP_COMPRESSOR_DEFAULT "lzo" -static char *zswap_compressor = ZSWAP_COMPRESSOR_DEFAULT; -module_param_named(compressor, zswap_compressor, charp, 0444); - -/* The maximum percentage of memory that the compressed pool can occupy */ -static unsigned int zswap_max_pool_percent = 20; -module_param_named(max_pool_percent, - zswap_max_pool_percent, uint, 0644); +static char zswap_compressor[CRYPTO_MAX_ALG_NAME] = ZSWAP_COMPRESSOR_DEFAULT; +static struct kparam_string zswap_compressor_kparam = { + .string = zswap_compressor, + .maxlen = sizeof(zswap_compressor), +}; +static int zswap_compressor_param_set(const char *, + const struct kernel_param *); +static struct kernel_param_ops zswap_compressor_param_ops = { + .set = zswap_compressor_param_set, + .get = param_get_string, +}; +module_param_cb(compressor, &zswap_compressor_param_ops, + &zswap_compressor_kparam, 0644); -/* Compressed storage to use */ +/* Compressed storage zpool to use */ #define ZSWAP_ZPOOL_DEFAULT "zbud" -static char *zswap_zpool_type = ZSWAP_ZPOOL_DEFAULT; -module_param_named(zpool, zswap_zpool_type, charp, 0444); +static char zswap_zpool_type[32 /* arbitrary */] = ZSWAP_ZPOOL_DEFAULT; +static struct kparam_string zswap_zpool_kparam = { + .string = zswap_zpool_type, + .maxlen = sizeof(zswap_zpool_type), +}; +static int zswap_zpool_param_set(const char *, const struct kernel_param *); +static struct kernel_param_ops zswap_zpool_param_ops = { + .set = zswap_zpool_param_set, + .get = param_get_string, +}; +module_param_cb(zpool, &zswap_zpool_param_ops, &zswap_zpool_kparam, 0644); -/* zpool is shared by all of zswap backend */ -static struct zpool *zswap_pool; +/* The maximum percentage of memory that the compressed pool can occupy */ +static unsigned int zswap_max_pool_percent = 20; +module_param_named(max_pool_percent, zswap_max_pool_percent, uint, 0644); /********************************* * data structures @@ -161,6 +177,9 @@ static LIST_HEAD(zswap_pools); /* protects zswap_pools list modification */ static DEFINE_SPINLOCK(zswap_pools_lock); +/* used by param callback function */ +static bool zswap_init_started; + /********************************* * helpers and fwd declarations **********************************/ @@ -661,6 +680,101 @@ static void zswap_pool_put(struct zswap_pool *pool) kref_put(&pool->kref, __zswap_pool_empty); } +/********************************* +* param callbacks +**********************************/ + +static int __zswap_param_set(const char *val, const struct kernel_param *kp, + char *type, char *compressor) +{ + struct zswap_pool *pool, *put_pool = NULL; + char str[kp->str->maxlen], *s; + int ret; + + /* + * kp is either zswap_zpool_kparam or zswap_compressor_kparam, defined + * at the top of this file, so maxlen is CRYPTO_MAX_ALG_NAME (64) or + * 32 (arbitrary). + */ + strlcpy(str, val, kp->str->maxlen); + s = strim(str); + + /* if this is load-time (pre-init) param setting, + * don't create a pool; that's done during init. + */ + if (!zswap_init_started) + return param_set_copystring(s, kp); + + /* no change required */ + if (!strncmp(kp->str->string, s, kp->str->maxlen)) + return 0; + + if (!type) { + type = s; + if (!zpool_has_pool(type)) { + pr_err("zpool %s not available\n", type); + return -ENOENT; + } + } else if (!compressor) { + compressor = s; + if (!crypto_has_comp(compressor, 0, 0)) { + pr_err("compressor %s not available\n", compressor); + return -ENOENT; + } + } + + spin_lock(&zswap_pools_lock); + + pool = zswap_pool_find_get(type, compressor); + if (pool) { + zswap_pool_debug("using existing", pool); + list_del_rcu(&pool->list); + } else { + spin_unlock(&zswap_pools_lock); + pool = zswap_pool_create(type, compressor); + spin_lock(&zswap_pools_lock); + } + + if (pool) + ret = param_set_copystring(s, kp); + else + ret = -EINVAL; + + if (!ret) { + put_pool = zswap_pool_current(); + list_add_rcu(&pool->list, &zswap_pools); + } else if (pool) { + /* add the possibly pre-existing pool to the end of the pools + * list; if it's new (and empty) then it'll be removed and + * destroyed by the put after we drop the lock + */ + list_add_tail_rcu(&pool->list, &zswap_pools); + put_pool = pool; + } + + spin_unlock(&zswap_pools_lock); + + /* drop the ref from either the old current pool, + * or the new pool we failed to add + */ + if (put_pool) + zswap_pool_put(put_pool); + + return ret; +} + +static int zswap_compressor_param_set(const char *val, + const struct kernel_param *kp) +{ + return __zswap_param_set(val, kp, zswap_zpool_type, NULL); +} + +static int zswap_zpool_param_set(const char *val, + const struct kernel_param *kp) +{ + return __zswap_param_set(val, kp, NULL, zswap_compressor); +} + /********************************* * writeback code **********************************/ @@ -1114,6 +1228,8 @@ static int __init init_zswap(void) { struct zswap_pool *pool; + zswap_init_started = true; + if (zswap_entry_cache_create()) { pr_err("entry cache creation failed\n"); goto cache_fail; -- GitLab From 9c4c5ef3760470cbf8bf408a173d1b2fdba065b1 Mon Sep 17 00:00:00 2001 From: Dan Streetman Date: Wed, 9 Sep 2015 15:35:25 -0700 Subject: [PATCH 6904/7006] zswap: update docs for runtime-changeable attributes Change the Documentation/vm/zswap.txt doc to indicate that the "zpool" and "compressor" params are now changeable at runtime. Signed-off-by: Dan Streetman Cc: Seth Jennings Cc: Sergey Senozhatsky Cc: Vlastimil Babka Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/zswap.txt | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/Documentation/vm/zswap.txt b/Documentation/vm/zswap.txt index 8458c0861e4e6..89fff7d611ccb 100644 --- a/Documentation/vm/zswap.txt +++ b/Documentation/vm/zswap.txt @@ -32,7 +32,7 @@ can also be enabled and disabled at runtime using the sysfs interface. An example command to enable zswap at runtime, assuming sysfs is mounted at /sys, is: -echo 1 > /sys/modules/zswap/parameters/enabled +echo 1 > /sys/module/zswap/parameters/enabled When zswap is disabled at runtime it will stop storing pages that are being swapped out. However, it will _not_ immediately write out or fault @@ -49,14 +49,26 @@ Zswap receives pages for compression through the Frontswap API and is able to evict pages from its own compressed pool on an LRU basis and write them back to the backing swap device in the case that the compressed pool is full. -Zswap makes use of zbud for the managing the compressed memory pool. Each -allocation in zbud is not directly accessible by address. Rather, a handle is +Zswap makes use of zpool for the managing the compressed memory pool. Each +allocation in zpool is not directly accessible by address. Rather, a handle is returned by the allocation routine and that handle must be mapped before being accessed. The compressed memory pool grows on demand and shrinks as compressed -pages are freed. The pool is not preallocated. +pages are freed. The pool is not preallocated. By default, a zpool of type +zbud is created, but it can be selected at boot time by setting the "zpool" +attribute, e.g. zswap.zpool=zbud. It can also be changed at runtime using the +sysfs "zpool" attribute, e.g. + +echo zbud > /sys/module/zswap/parameters/zpool + +The zbud type zpool allocates exactly 1 page to store 2 compressed pages, which +means the compression ratio will always be 2:1 or worse (because of half-full +zbud pages). The zsmalloc type zpool has a more complex compressed page +storage method, and it can achieve greater storage densities. However, +zsmalloc does not implement compressed page eviction, so once zswap fills it +cannot evict the oldest page, it can only reject new pages. When a swap page is passed from frontswap to zswap, zswap maintains a mapping -of the swap entry, a combination of the swap type and swap offset, to the zbud +of the swap entry, a combination of the swap type and swap offset, to the zpool handle that references that compressed swap page. This mapping is achieved with a red-black tree per swap type. The swap offset is the search key for the tree nodes. @@ -74,9 +86,17 @@ controlled policy: * max_pool_percent - The maximum percentage of memory that the compressed pool can occupy. -Zswap allows the compressor to be selected at kernel boot time by setting the -“compressor” attribute. The default compressor is lzo. e.g. -zswap.compressor=deflate +The default compressor is lzo, but it can be selected at boot time by setting +the “compressor” attribute, e.g. zswap.compressor=lzo. It can also be changed +at runtime using the sysfs "compressor" attribute, e.g. + +echo lzo > /sys/module/zswap/parameters/compressor + +When the zpool and/or compressor parameter is changed at runtime, any existing +compressed pages are not modified; they are left in their own zpool. When a +request is made for a page in an old zpool, it is uncompressed using its +original compressor. Once all pages are removed from an old zpool, the zpool +and its compressor are freed. A debugfs interface is provided for various statistic about pool size, number of pages stored, and various counters for the reasons pages are rejected. -- GitLab From 2fc045247089ad4ed611ec20cc3a736c0212bf1a Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:28 -0700 Subject: [PATCH 6905/7006] memcg: add page_cgroup_ino helper This patchset introduces a new user API for tracking user memory pages that have not been used for a given period of time. The purpose of this is to provide the userspace with the means of tracking a workload's working set, i.e. the set of pages that are actively used by the workload. Knowing the working set size can be useful for partitioning the system more efficiently, e.g. by tuning memory cgroup limits appropriately, or for job placement within a compute cluster. ==== USE CASES ==== The unified cgroup hierarchy has memory.low and memory.high knobs, which are defined as the low and high boundaries for the workload working set size. However, the working set size of a workload may be unknown or change in time. With this patch set, one can periodically estimate the amount of memory unused by each cgroup and tune their memory.low and memory.high parameters accordingly, therefore optimizing the overall memory utilization. Another use case is balancing workloads within a compute cluster. Knowing how much memory is not really used by a workload unit may help take a more optimal decision when considering migrating the unit to another node within the cluster. Also, as noted by Minchan, this would be useful for per-process reclaim (https://lwn.net/Articles/545668/). With idle tracking, we could reclaim idle pages only by smart user memory manager. ==== USER API ==== The user API consists of two new files: * /sys/kernel/mm/page_idle/bitmap. This file implements a bitmap where each bit corresponds to a page, indexed by PFN. When the bit is set, the corresponding page is idle. A page is considered idle if it has not been accessed since it was marked idle. To mark a page idle one should set the bit corresponding to the page by writing to the file. A value written to the file is OR-ed with the current bitmap value. Only user memory pages can be marked idle, for other page types input is silently ignored. Writing to this file beyond max PFN results in the ENXIO error. Only available when CONFIG_IDLE_PAGE_TRACKING is set. This file can be used to estimate the amount of pages that are not used by a particular workload as follows: 1. mark all pages of interest idle by setting corresponding bits in the /sys/kernel/mm/page_idle/bitmap 2. wait until the workload accesses its working set 3. read /sys/kernel/mm/page_idle/bitmap and count the number of bits set * /proc/kpagecgroup. This file contains a 64-bit inode number of the memory cgroup each page is charged to, indexed by PFN. Only available when CONFIG_MEMCG is set. This file can be used to find all pages (including unmapped file pages) accounted to a particular cgroup. Using /sys/kernel/mm/page_idle/bitmap, one can then estimate the cgroup working set size. For an example of using these files for estimating the amount of unused memory pages per each memory cgroup, please see the script attached below. ==== REASONING ==== The reason to introduce the new user API instead of using /proc/PID/{clear_refs,smaps} is that the latter has two serious drawbacks: - it does not count unmapped file pages - it affects the reclaimer logic The new API attempts to overcome them both. For more details on how it is achieved, please see the comment to patch 6. ==== PATCHSET STRUCTURE ==== The patch set is organized as follows: - patch 1 adds page_cgroup_ino() helper for the sake of /proc/kpagecgroup and patches 2-3 do related cleanup - patch 4 adds /proc/kpagecgroup, which reports cgroup ino each page is charged to - patch 5 introduces a new mmu notifier callback, clear_young, which is a lightweight version of clear_flush_young; it is used in patch 6 - patch 6 implements the idle page tracking feature, including the userspace API, /sys/kernel/mm/page_idle/bitmap - patch 7 exports idle flag via /proc/kpageflags ==== SIMILAR WORKS ==== Originally, the patch for tracking idle memory was proposed back in 2011 by Michel Lespinasse (see http://lwn.net/Articles/459269/). The main difference between Michel's patch and this one is that Michel implemented a kernel space daemon for estimating idle memory size per cgroup while this patch only provides the userspace with the minimal API for doing the job, leaving the rest up to the userspace. However, they both share the same idea of Idle/Young page flags to avoid affecting the reclaimer logic. ==== PERFORMANCE EVALUATION ==== SPECjvm2008 (https://www.spec.org/jvm2008/) was used to evaluate the performance impact introduced by this patch set. Three runs were carried out: - base: kernel without the patch - patched: patched kernel, the feature is not used - patched-active: patched kernel, 1 minute-period daemon is used for tracking idle memory For tracking idle memory, idlememstat utility was used: https://github.com/locker/idlememstat testcase base patched patched-active compiler 537.40 ( 0.00)% 532.26 (-0.96)% 538.31 ( 0.17)% compress 305.47 ( 0.00)% 301.08 (-1.44)% 300.71 (-1.56)% crypto 284.32 ( 0.00)% 282.21 (-0.74)% 284.87 ( 0.19)% derby 411.05 ( 0.00)% 413.44 ( 0.58)% 412.07 ( 0.25)% mpegaudio 189.96 ( 0.00)% 190.87 ( 0.48)% 189.42 (-0.28)% scimark.large 46.85 ( 0.00)% 46.41 (-0.94)% 47.83 ( 2.09)% scimark.small 412.91 ( 0.00)% 415.41 ( 0.61)% 421.17 ( 2.00)% serial 204.23 ( 0.00)% 213.46 ( 4.52)% 203.17 (-0.52)% startup 36.76 ( 0.00)% 35.49 (-3.45)% 35.64 (-3.05)% sunflow 115.34 ( 0.00)% 115.08 (-0.23)% 117.37 ( 1.76)% xml 620.55 ( 0.00)% 619.95 (-0.10)% 620.39 (-0.03)% composite 211.50 ( 0.00)% 211.15 (-0.17)% 211.67 ( 0.08)% time idlememstat: 17.20user 65.16system 2:15:23elapsed 1%CPU (0avgtext+0avgdata 8476maxresident)k 448inputs+40outputs (1major+36052minor)pagefaults 0swaps ==== SCRIPT FOR COUNTING IDLE PAGES PER CGROUP ==== #! /usr/bin/python # import os import stat import errno import struct CGROUP_MOUNT = "/sys/fs/cgroup/memory" BUFSIZE = 8 * 1024 # must be multiple of 8 def get_hugepage_size(): with open("/proc/meminfo", "r") as f: for s in f: k, v = s.split(":") if k == "Hugepagesize": return int(v.split()[0]) * 1024 PAGE_SIZE = os.sysconf("SC_PAGE_SIZE") HUGEPAGE_SIZE = get_hugepage_size() def set_idle(): f = open("/sys/kernel/mm/page_idle/bitmap", "wb", BUFSIZE) while True: try: f.write(struct.pack("Q", pow(2, 64) - 1)) except IOError as err: if err.errno == errno.ENXIO: break raise f.close() def count_idle(): f_flags = open("/proc/kpageflags", "rb", BUFSIZE) f_cgroup = open("/proc/kpagecgroup", "rb", BUFSIZE) with open("/sys/kernel/mm/page_idle/bitmap", "rb", BUFSIZE) as f: while f.read(BUFSIZE): pass # update idle flag idlememsz = {} while True: s1, s2 = f_flags.read(8), f_cgroup.read(8) if not s1 or not s2: break flags, = struct.unpack('Q', s1) cgino, = struct.unpack('Q', s2) unevictable = (flags >> 18) & 1 huge = (flags >> 22) & 1 idle = (flags >> 25) & 1 if idle and not unevictable: idlememsz[cgino] = idlememsz.get(cgino, 0) + \ (HUGEPAGE_SIZE if huge else PAGE_SIZE) f_flags.close() f_cgroup.close() return idlememsz if __name__ == "__main__": print "Setting the idle flag for each page..." set_idle() raw_input("Wait until the workload accesses its working set, " "then press Enter") print "Counting idle pages..." idlememsz = count_idle() for dir, subdirs, files in os.walk(CGROUP_MOUNT): ino = os.stat(dir)[stat.ST_INO] print dir + ": " + str(idlememsz.get(ino, 0) / 1024) + " kB" ==== END SCRIPT ==== This patch (of 8): Add page_cgroup_ino() helper to memcg. This function returns the inode number of the closest online ancestor of the memory cgroup a page is charged to. It is required for exporting information about which page is charged to which cgroup to userspace, which will be introduced by a following patch. Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memcontrol.h | 1 + mm/memcontrol.c | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index d92b80b63c5ca..f56c818e56bc3 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -345,6 +345,7 @@ static inline bool mm_match_cgroup(struct mm_struct *mm, } struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page); +ino_t page_cgroup_ino(struct page *page); static inline bool mem_cgroup_disabled(void) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 1742a2db89c7b..01009726d4120 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -441,6 +441,34 @@ struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page) return &memcg->css; } +/** + * page_cgroup_ino - return inode number of the memcg a page is charged to + * @page: the page + * + * Look up the closest online ancestor of the memory cgroup @page is charged to + * and return its inode number or 0 if @page is not charged to any cgroup. It + * is safe to call this function without holding a reference to @page. + * + * Note, this function is inherently racy, because there is nothing to prevent + * the cgroup inode from getting torn down and potentially reallocated a moment + * after page_cgroup_ino() returns, so it only should be used by callers that + * do not care (such as procfs interfaces). + */ +ino_t page_cgroup_ino(struct page *page) +{ + struct mem_cgroup *memcg; + unsigned long ino = 0; + + rcu_read_lock(); + memcg = READ_ONCE(page->mem_cgroup); + while (memcg && !(memcg->css.flags & CSS_ONLINE)) + memcg = parent_mem_cgroup(memcg); + if (memcg) + ino = cgroup_ino(memcg->css.cgroup); + rcu_read_unlock(); + return ino; +} + static struct mem_cgroup_per_zone * mem_cgroup_page_zoneinfo(struct mem_cgroup *memcg, struct page *page) { -- GitLab From 94a59fb36ee91b3f977a9b914ec701efe40041de Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:31 -0700 Subject: [PATCH 6906/7006] hwpoison: use page_cgroup_ino for filtering by memcg Hwpoison allows to filter pages by memory cgroup ino. Currently, it calls try_get_mem_cgroup_from_page to obtain the cgroup from a page and then its ino using cgroup_ino, but now we have a helper method for that, page_cgroup_ino, so use it instead. This patch also loosens the hwpoison memcg filter dependency rules - it makes it depend on CONFIG_MEMCG instead of CONFIG_MEMCG_SWAP, because hwpoison memcg filter does not require anything (nor it used to) from CONFIG_MEMCG_SWAP side. Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/hwpoison-inject.c | 5 +---- mm/memory-failure.c | 16 ++-------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/mm/hwpoison-inject.c b/mm/hwpoison-inject.c index aeba0edd6e447..9d26fd9fefe4a 100644 --- a/mm/hwpoison-inject.c +++ b/mm/hwpoison-inject.c @@ -45,12 +45,9 @@ static int hwpoison_inject(void *data, u64 val) /* * do a racy check with elevated page count, to make sure PG_hwpoison * will only be set for the targeted owner (or on a free page). - * We temporarily take page lock for try_get_mem_cgroup_from_page(). * memory_failure() will redo the check reliably inside page lock. */ - lock_page(hpage); err = hwpoison_filter(hpage); - unlock_page(hpage); if (err) goto put_out; @@ -126,7 +123,7 @@ static int pfn_inject_init(void) if (!dentry) goto fail; -#ifdef CONFIG_MEMCG_SWAP +#ifdef CONFIG_MEMCG dentry = debugfs_create_u64("corrupt-filter-memcg", 0600, hwpoison_dir, &hwpoison_filter_memcg); if (!dentry) diff --git a/mm/memory-failure.c b/mm/memory-failure.c index eeda6485e76c2..95882692e747c 100644 --- a/mm/memory-failure.c +++ b/mm/memory-failure.c @@ -130,27 +130,15 @@ static int hwpoison_filter_flags(struct page *p) * can only guarantee that the page either belongs to the memcg tasks, or is * a freed page. */ -#ifdef CONFIG_MEMCG_SWAP +#ifdef CONFIG_MEMCG u64 hwpoison_filter_memcg; EXPORT_SYMBOL_GPL(hwpoison_filter_memcg); static int hwpoison_filter_task(struct page *p) { - struct mem_cgroup *mem; - struct cgroup_subsys_state *css; - unsigned long ino; - if (!hwpoison_filter_memcg) return 0; - mem = try_get_mem_cgroup_from_page(p); - if (!mem) - return -EINVAL; - - css = &mem->css; - ino = cgroup_ino(css->cgroup); - css_put(css); - - if (ino != hwpoison_filter_memcg) + if (page_cgroup_ino(p) != hwpoison_filter_memcg) return -EINVAL; return 0; -- GitLab From e993d905c81e2c0f669f2f8e8327df86738baebe Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:35 -0700 Subject: [PATCH 6907/7006] memcg: zap try_get_mem_cgroup_from_page It is only used in mem_cgroup_try_charge, so fold it in and zap it. Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/memcontrol.h | 9 +------ mm/memcontrol.c | 48 ++++++++++---------------------------- 2 files changed, 13 insertions(+), 44 deletions(-) diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index f56c818e56bc3..ad800e62cb7a6 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -305,11 +305,9 @@ struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *); struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *); bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg); - -struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page); struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); - struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg); + static inline struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){ return css ? container_of(css, struct mem_cgroup, css) : NULL; @@ -556,11 +554,6 @@ static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, return &zone->lruvec; } -static inline struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page) -{ - return NULL; -} - static inline bool mm_match_cgroup(struct mm_struct *mm, struct mem_cgroup *memcg) { diff --git a/mm/memcontrol.c b/mm/memcontrol.c index 01009726d4120..6ddaeba34e097 100644 --- a/mm/memcontrol.c +++ b/mm/memcontrol.c @@ -2099,40 +2099,6 @@ static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages) css_put_many(&memcg->css, nr_pages); } -/* - * try_get_mem_cgroup_from_page - look up page's memcg association - * @page: the page - * - * Look up, get a css reference, and return the memcg that owns @page. - * - * The page must be locked to prevent racing with swap-in and page - * cache charges. If coming from an unlocked page table, the caller - * must ensure the page is on the LRU or this can race with charging. - */ -struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page) -{ - struct mem_cgroup *memcg; - unsigned short id; - swp_entry_t ent; - - VM_BUG_ON_PAGE(!PageLocked(page), page); - - memcg = page->mem_cgroup; - if (memcg) { - if (!css_tryget_online(&memcg->css)) - memcg = NULL; - } else if (PageSwapCache(page)) { - ent.val = page_private(page); - id = lookup_swap_cgroup_id(ent); - rcu_read_lock(); - memcg = mem_cgroup_from_id(id); - if (memcg && !css_tryget_online(&memcg->css)) - memcg = NULL; - rcu_read_unlock(); - } - return memcg; -} - static void lock_page_lru(struct page *page, int *isolated) { struct zone *zone = page_zone(page); @@ -5329,8 +5295,20 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, * the page lock, which serializes swap cache removal, which * in turn serializes uncharging. */ + VM_BUG_ON_PAGE(!PageLocked(page), page); if (page->mem_cgroup) goto out; + + if (do_swap_account) { + swp_entry_t ent = { .val = page_private(page), }; + unsigned short id = lookup_swap_cgroup_id(ent); + + rcu_read_lock(); + memcg = mem_cgroup_from_id(id); + if (memcg && !css_tryget_online(&memcg->css)) + memcg = NULL; + rcu_read_unlock(); + } } if (PageTransHuge(page)) { @@ -5338,8 +5316,6 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, VM_BUG_ON_PAGE(!PageTransHuge(page), page); } - if (do_swap_account && PageSwapCache(page)) - memcg = try_get_mem_cgroup_from_page(page); if (!memcg) memcg = get_mem_cgroup_from_mm(mm); -- GitLab From 80ae2fdceba8313b0433f899bdd9c6c463291a17 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:38 -0700 Subject: [PATCH 6908/7006] proc: add kpagecgroup file /proc/kpagecgroup contains a 64-bit inode number of the memory cgroup each page is charged to, indexed by PFN. Having this information is useful for estimating a cgroup working set size. The file is present if CONFIG_PROC_PAGE_MONITOR && CONFIG_MEMCG. Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/pagemap.txt | 6 +++- fs/proc/page.c | 53 ++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index 3cd38438242ae..ce294b0aace49 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -5,7 +5,7 @@ pagemap is a new (as of 2.6.25) set of interfaces in the kernel that allow userspace programs to examine the page tables and related information by reading files in /proc. -There are three components to pagemap: +There are four components to pagemap: * /proc/pid/pagemap. This file lets a userspace process find out which physical frame each virtual page is mapped to. It contains one 64-bit @@ -71,6 +71,10 @@ There are three components to pagemap: 23. BALLOON 24. ZERO_PAGE + * /proc/kpagecgroup. This file contains a 64-bit inode number of the + memory cgroup each page is charged to, indexed by PFN. Only available when + CONFIG_MEMCG is set. + Short descriptions to the page flags: 0. LOCKED diff --git a/fs/proc/page.c b/fs/proc/page.c index 7eee2d8b97d97..70d23245dd439 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "internal.h" @@ -225,10 +226,62 @@ static const struct file_operations proc_kpageflags_operations = { .read = kpageflags_read, }; +#ifdef CONFIG_MEMCG +static ssize_t kpagecgroup_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + u64 __user *out = (u64 __user *)buf; + struct page *ppage; + unsigned long src = *ppos; + unsigned long pfn; + ssize_t ret = 0; + u64 ino; + + pfn = src / KPMSIZE; + count = min_t(unsigned long, count, (max_pfn * KPMSIZE) - src); + if (src & KPMMASK || count & KPMMASK) + return -EINVAL; + + while (count > 0) { + if (pfn_valid(pfn)) + ppage = pfn_to_page(pfn); + else + ppage = NULL; + + if (ppage) + ino = page_cgroup_ino(ppage); + else + ino = 0; + + if (put_user(ino, out)) { + ret = -EFAULT; + break; + } + + pfn++; + out++; + count -= KPMSIZE; + } + + *ppos += (char __user *)out - buf; + if (!ret) + ret = (char __user *)out - buf; + return ret; +} + +static const struct file_operations proc_kpagecgroup_operations = { + .llseek = mem_lseek, + .read = kpagecgroup_read, +}; +#endif /* CONFIG_MEMCG */ + static int __init proc_page_init(void) { proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations); proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations); +#ifdef CONFIG_MEMCG + proc_create("kpagecgroup", S_IRUSR, NULL, &proc_kpagecgroup_operations); +#endif return 0; } fs_initcall(proc_page_init); -- GitLab From 1d7715c676a1566c2e4c3e77d16b1f9bb4909025 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:41 -0700 Subject: [PATCH 6909/7006] mmu-notifier: add clear_young callback In the scope of the idle memory tracking feature, which is introduced by the following patch, we need to clear the referenced/accessed bit not only in primary, but also in secondary ptes. The latter is required in order to estimate wss of KVM VMs. At the same time we want to avoid flushing tlb, because it is quite expensive and it won't really affect the final result. Currently, there is no function for clearing pte young bit that would meet our requirements, so this patch introduces one. To achieve that we have to add a new mmu-notifier callback, clear_young, since there is no method for testing-and-clearing a secondary pte w/o flushing tlb. The new method is not mandatory and currently only implemented by KVM. Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Acked-by: Paolo Bonzini Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/mmu_notifier.h | 44 ++++++++++++++++++++++++++++++++++++ mm/mmu_notifier.c | 17 ++++++++++++++ virt/kvm/kvm_main.c | 31 +++++++++++++++++++++++++ 3 files changed, 92 insertions(+) diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h index 61cd67f4d7881..a5b17137c683c 100644 --- a/include/linux/mmu_notifier.h +++ b/include/linux/mmu_notifier.h @@ -65,6 +65,16 @@ struct mmu_notifier_ops { unsigned long start, unsigned long end); + /* + * clear_young is a lightweight version of clear_flush_young. Like the + * latter, it is supposed to test-and-clear the young/accessed bitflag + * in the secondary pte, but it may omit flushing the secondary tlb. + */ + int (*clear_young)(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long start, + unsigned long end); + /* * test_young is called to check the young/accessed bitflag in * the secondary pte. This is used to know if the page is @@ -203,6 +213,9 @@ extern void __mmu_notifier_release(struct mm_struct *mm); extern int __mmu_notifier_clear_flush_young(struct mm_struct *mm, unsigned long start, unsigned long end); +extern int __mmu_notifier_clear_young(struct mm_struct *mm, + unsigned long start, + unsigned long end); extern int __mmu_notifier_test_young(struct mm_struct *mm, unsigned long address); extern void __mmu_notifier_change_pte(struct mm_struct *mm, @@ -231,6 +244,15 @@ static inline int mmu_notifier_clear_flush_young(struct mm_struct *mm, return 0; } +static inline int mmu_notifier_clear_young(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + if (mm_has_notifiers(mm)) + return __mmu_notifier_clear_young(mm, start, end); + return 0; +} + static inline int mmu_notifier_test_young(struct mm_struct *mm, unsigned long address) { @@ -311,6 +333,28 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm) __young; \ }) +#define ptep_clear_young_notify(__vma, __address, __ptep) \ +({ \ + int __young; \ + struct vm_area_struct *___vma = __vma; \ + unsigned long ___address = __address; \ + __young = ptep_test_and_clear_young(___vma, ___address, __ptep);\ + __young |= mmu_notifier_clear_young(___vma->vm_mm, ___address, \ + ___address + PAGE_SIZE); \ + __young; \ +}) + +#define pmdp_clear_young_notify(__vma, __address, __pmdp) \ +({ \ + int __young; \ + struct vm_area_struct *___vma = __vma; \ + unsigned long ___address = __address; \ + __young = pmdp_test_and_clear_young(___vma, ___address, __pmdp);\ + __young |= mmu_notifier_clear_young(___vma->vm_mm, ___address, \ + ___address + PMD_SIZE); \ + __young; \ +}) + #define ptep_clear_flush_notify(__vma, __address, __ptep) \ ({ \ unsigned long ___addr = __address & PAGE_MASK; \ diff --git a/mm/mmu_notifier.c b/mm/mmu_notifier.c index 3b9b3d0741b2a..5fbdd367bbed9 100644 --- a/mm/mmu_notifier.c +++ b/mm/mmu_notifier.c @@ -123,6 +123,23 @@ int __mmu_notifier_clear_flush_young(struct mm_struct *mm, return young; } +int __mmu_notifier_clear_young(struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct mmu_notifier *mn; + int young = 0, id; + + id = srcu_read_lock(&srcu); + hlist_for_each_entry_rcu(mn, &mm->mmu_notifier_mm->list, hlist) { + if (mn->ops->clear_young) + young |= mn->ops->clear_young(mn, mm, start, end); + } + srcu_read_unlock(&srcu, id); + + return young; +} + int __mmu_notifier_test_young(struct mm_struct *mm, unsigned long address) { diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index d8db2f8fce9c7..268fc0a5a9324 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -387,6 +387,36 @@ static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn, return young; } +static int kvm_mmu_notifier_clear_young(struct mmu_notifier *mn, + struct mm_struct *mm, + unsigned long start, + unsigned long end) +{ + struct kvm *kvm = mmu_notifier_to_kvm(mn); + int young, idx; + + idx = srcu_read_lock(&kvm->srcu); + spin_lock(&kvm->mmu_lock); + /* + * Even though we do not flush TLB, this will still adversely + * affect performance on pre-Haswell Intel EPT, where there is + * no EPT Access Bit to clear so that we have to tear down EPT + * tables instead. If we find this unacceptable, we can always + * add a parameter to kvm_age_hva so that it effectively doesn't + * do anything on clear_young. + * + * Also note that currently we never issue secondary TLB flushes + * from clear_young, leaving this job up to the regular system + * cadence. If we find this inaccurate, we might come up with a + * more sophisticated heuristic later. + */ + young = kvm_age_hva(kvm, start, end); + spin_unlock(&kvm->mmu_lock); + srcu_read_unlock(&kvm->srcu, idx); + + return young; +} + static int kvm_mmu_notifier_test_young(struct mmu_notifier *mn, struct mm_struct *mm, unsigned long address) @@ -419,6 +449,7 @@ static const struct mmu_notifier_ops kvm_mmu_notifier_ops = { .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start, .invalidate_range_end = kvm_mmu_notifier_invalidate_range_end, .clear_flush_young = kvm_mmu_notifier_clear_flush_young, + .clear_young = kvm_mmu_notifier_clear_young, .test_young = kvm_mmu_notifier_test_young, .change_pte = kvm_mmu_notifier_change_pte, .release = kvm_mmu_notifier_release, -- GitLab From 33c3fc71c8cfa3cc3a98beaa901c069c177dc295 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:45 -0700 Subject: [PATCH 6910/7006] mm: introduce idle page tracking Knowing the portion of memory that is not used by a certain application or memory cgroup (idle memory) can be useful for partitioning the system efficiently, e.g. by setting memory cgroup limits appropriately. Currently, the only means to estimate the amount of idle memory provided by the kernel is /proc/PID/{clear_refs,smaps}: the user can clear the access bit for all pages mapped to a particular process by writing 1 to clear_refs, wait for some time, and then count smaps:Referenced. However, this method has two serious shortcomings: - it does not count unmapped file pages - it affects the reclaimer logic To overcome these drawbacks, this patch introduces two new page flags, Idle and Young, and a new sysfs file, /sys/kernel/mm/page_idle/bitmap. A page's Idle flag can only be set from userspace by setting bit in /sys/kernel/mm/page_idle/bitmap at the offset corresponding to the page, and it is cleared whenever the page is accessed either through page tables (it is cleared in page_referenced() in this case) or using the read(2) system call (mark_page_accessed()). Thus by setting the Idle flag for pages of a particular workload, which can be found e.g. by reading /proc/PID/pagemap, waiting for some time to let the workload access its working set, and then reading the bitmap file, one can estimate the amount of pages that are not used by the workload. The Young page flag is used to avoid interference with the memory reclaimer. A page's Young flag is set whenever the Access bit of a page table entry pointing to the page is cleared by writing to the bitmap file. If page_referenced() is called on a Young page, it will add 1 to its return value, therefore concealing the fact that the Access bit was cleared. Note, since there is no room for extra page flags on 32 bit, this feature uses extended page flags when compiled on 32 bit. [akpm@linux-foundation.org: fix build] [akpm@linux-foundation.org: kpageidle requires an MMU] [akpm@linux-foundation.org: decouple from page-flags rework] Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/00-INDEX | 2 + Documentation/vm/idle_page_tracking.txt | 98 ++++++++++ fs/proc/page.c | 3 + fs/proc/task_mmu.c | 5 +- include/linux/mmu_notifier.h | 2 + include/linux/page-flags.h | 11 ++ include/linux/page_ext.h | 4 + include/linux/page_idle.h | 110 +++++++++++ mm/Kconfig | 12 ++ mm/Makefile | 1 + mm/debug.c | 4 + mm/huge_memory.c | 12 +- mm/migrate.c | 6 + mm/page_ext.c | 4 + mm/page_idle.c | 232 ++++++++++++++++++++++++ mm/rmap.c | 6 + mm/swap.c | 3 + 17 files changed, 512 insertions(+), 3 deletions(-) create mode 100644 Documentation/vm/idle_page_tracking.txt create mode 100644 include/linux/page_idle.h create mode 100644 mm/page_idle.c diff --git a/Documentation/vm/00-INDEX b/Documentation/vm/00-INDEX index 081c49777abb8..6a5e2a102a451 100644 --- a/Documentation/vm/00-INDEX +++ b/Documentation/vm/00-INDEX @@ -14,6 +14,8 @@ hugetlbpage.txt - a brief summary of hugetlbpage support in the Linux kernel. hwpoison.txt - explains what hwpoison is +idle_page_tracking.txt + - description of the idle page tracking feature. ksm.txt - how to use the Kernel Samepage Merging feature. numa diff --git a/Documentation/vm/idle_page_tracking.txt b/Documentation/vm/idle_page_tracking.txt new file mode 100644 index 0000000000000..85dcc3bb85dca --- /dev/null +++ b/Documentation/vm/idle_page_tracking.txt @@ -0,0 +1,98 @@ +MOTIVATION + +The idle page tracking feature allows to track which memory pages are being +accessed by a workload and which are idle. This information can be useful for +estimating the workload's working set size, which, in turn, can be taken into +account when configuring the workload parameters, setting memory cgroup limits, +or deciding where to place the workload within a compute cluster. + +It is enabled by CONFIG_IDLE_PAGE_TRACKING=y. + +USER API + +The idle page tracking API is located at /sys/kernel/mm/page_idle. Currently, +it consists of the only read-write file, /sys/kernel/mm/page_idle/bitmap. + +The file implements a bitmap where each bit corresponds to a memory page. The +bitmap is represented by an array of 8-byte integers, and the page at PFN #i is +mapped to bit #i%64 of array element #i/64, byte order is native. When a bit is +set, the corresponding page is idle. + +A page is considered idle if it has not been accessed since it was marked idle +(for more details on what "accessed" actually means see the IMPLEMENTATION +DETAILS section). To mark a page idle one has to set the bit corresponding to +the page by writing to the file. A value written to the file is OR-ed with the +current bitmap value. + +Only accesses to user memory pages are tracked. These are pages mapped to a +process address space, page cache and buffer pages, swap cache pages. For other +page types (e.g. SLAB pages) an attempt to mark a page idle is silently ignored, +and hence such pages are never reported idle. + +For huge pages the idle flag is set only on the head page, so one has to read +/proc/kpageflags in order to correctly count idle huge pages. + +Reading from or writing to /sys/kernel/mm/page_idle/bitmap will return +-EINVAL if you are not starting the read/write on an 8-byte boundary, or +if the size of the read/write is not a multiple of 8 bytes. Writing to +this file beyond max PFN will return -ENXIO. + +That said, in order to estimate the amount of pages that are not used by a +workload one should: + + 1. Mark all the workload's pages as idle by setting corresponding bits in + /sys/kernel/mm/page_idle/bitmap. The pages can be found by reading + /proc/pid/pagemap if the workload is represented by a process, or by + filtering out alien pages using /proc/kpagecgroup in case the workload is + placed in a memory cgroup. + + 2. Wait until the workload accesses its working set. + + 3. Read /sys/kernel/mm/page_idle/bitmap and count the number of bits set. If + one wants to ignore certain types of pages, e.g. mlocked pages since they + are not reclaimable, he or she can filter them out using /proc/kpageflags. + +See Documentation/vm/pagemap.txt for more information about /proc/pid/pagemap, +/proc/kpageflags, and /proc/kpagecgroup. + +IMPLEMENTATION DETAILS + +The kernel internally keeps track of accesses to user memory pages in order to +reclaim unreferenced pages first on memory shortage conditions. A page is +considered referenced if it has been recently accessed via a process address +space, in which case one or more PTEs it is mapped to will have the Accessed bit +set, or marked accessed explicitly by the kernel (see mark_page_accessed()). The +latter happens when: + + - a userspace process reads or writes a page using a system call (e.g. read(2) + or write(2)) + + - a page that is used for storing filesystem buffers is read or written, + because a process needs filesystem metadata stored in it (e.g. lists a + directory tree) + + - a page is accessed by a device driver using get_user_pages() + +When a dirty page is written to swap or disk as a result of memory reclaim or +exceeding the dirty memory limit, it is not marked referenced. + +The idle memory tracking feature adds a new page flag, the Idle flag. This flag +is set manually, by writing to /sys/kernel/mm/page_idle/bitmap (see the USER API +section), and cleared automatically whenever a page is referenced as defined +above. + +When a page is marked idle, the Accessed bit must be cleared in all PTEs it is +mapped to, otherwise we will not be able to detect accesses to the page coming +from a process address space. To avoid interference with the reclaimer, which, +as noted above, uses the Accessed bit to promote actively referenced pages, one +more page flag is introduced, the Young flag. When the PTE Accessed bit is +cleared as a result of setting or updating a page's Idle flag, the Young flag +is set on the page. The reclaimer treats the Young flag as an extra PTE +Accessed bit and therefore will consider such a page as referenced. + +Since the idle memory tracking feature is based on the memory reclaimer logic, +it only works with pages that are on an LRU list, other pages are silently +ignored. That means it will ignore a user memory page if it is isolated, but +since there are usually not many of them, it should not affect the overall +result noticeably. In order not to stall scanning of the idle page bitmap, +locked pages may be skipped too. diff --git a/fs/proc/page.c b/fs/proc/page.c index 70d23245dd439..c2d29edcaa6bd 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -10,12 +10,15 @@ #include #include #include +#include +#include #include #include #include "internal.h" #define KPMSIZE sizeof(u64) #define KPMMASK (KPMSIZE - 1) +#define KPMBITS (KPMSIZE * BITS_PER_BYTE) /* /proc/kpagecount - an array exposing page counts * diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 41f1a50c10c9e..e2d46adb54b42 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -459,7 +460,7 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page, mss->resident += size; /* Accumulate the size in pages that have been accessed. */ - if (young || PageReferenced(page)) + if (young || page_is_young(page) || PageReferenced(page)) mss->referenced += size; mapcount = page_mapcount(page); if (mapcount >= 2) { @@ -807,6 +808,7 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, /* Clear accessed and referenced bits. */ pmdp_test_and_clear_young(vma, addr, pmd); + test_and_clear_page_young(page); ClearPageReferenced(page); out: spin_unlock(ptl); @@ -834,6 +836,7 @@ out: /* Clear accessed and referenced bits. */ ptep_test_and_clear_young(vma, addr, pte); + test_and_clear_page_young(page); ClearPageReferenced(page); } pte_unmap_unlock(pte - 1, ptl); diff --git a/include/linux/mmu_notifier.h b/include/linux/mmu_notifier.h index a5b17137c683c..a1a210d59961a 100644 --- a/include/linux/mmu_notifier.h +++ b/include/linux/mmu_notifier.h @@ -471,6 +471,8 @@ static inline void mmu_notifier_mm_destroy(struct mm_struct *mm) #define ptep_clear_flush_young_notify ptep_clear_flush_young #define pmdp_clear_flush_young_notify pmdp_clear_flush_young +#define ptep_clear_young_notify ptep_test_and_clear_young +#define pmdp_clear_young_notify pmdp_test_and_clear_young #define ptep_clear_flush_notify ptep_clear_flush #define pmdp_huge_clear_flush_notify pmdp_huge_clear_flush #define pmdp_huge_get_and_clear_notify pmdp_huge_get_and_clear diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h index 41c93844fb1d1..416509e26d6d1 100644 --- a/include/linux/page-flags.h +++ b/include/linux/page-flags.h @@ -108,6 +108,10 @@ enum pageflags { #endif #ifdef CONFIG_TRANSPARENT_HUGEPAGE PG_compound_lock, +#endif +#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) + PG_young, + PG_idle, #endif __NR_PAGEFLAGS, @@ -289,6 +293,13 @@ PAGEFLAG_FALSE(HWPoison) #define __PG_HWPOISON 0 #endif +#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) +TESTPAGEFLAG(Young, young) +SETPAGEFLAG(Young, young) +TESTCLEARFLAG(Young, young) +PAGEFLAG(Idle, idle) +#endif + /* * On an anonymous page mapped into a user virtual memory area, * page->mapping points to its anon_vma, not to a struct address_space; diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h index c42981cd99aae..17f118a828549 100644 --- a/include/linux/page_ext.h +++ b/include/linux/page_ext.h @@ -26,6 +26,10 @@ enum page_ext_flags { PAGE_EXT_DEBUG_POISON, /* Page is poisoned */ PAGE_EXT_DEBUG_GUARD, PAGE_EXT_OWNER, +#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) + PAGE_EXT_YOUNG, + PAGE_EXT_IDLE, +#endif }; /* diff --git a/include/linux/page_idle.h b/include/linux/page_idle.h new file mode 100644 index 0000000000000..bf268fa92c5b3 --- /dev/null +++ b/include/linux/page_idle.h @@ -0,0 +1,110 @@ +#ifndef _LINUX_MM_PAGE_IDLE_H +#define _LINUX_MM_PAGE_IDLE_H + +#include +#include +#include + +#ifdef CONFIG_IDLE_PAGE_TRACKING + +#ifdef CONFIG_64BIT +static inline bool page_is_young(struct page *page) +{ + return PageYoung(page); +} + +static inline void set_page_young(struct page *page) +{ + SetPageYoung(page); +} + +static inline bool test_and_clear_page_young(struct page *page) +{ + return TestClearPageYoung(page); +} + +static inline bool page_is_idle(struct page *page) +{ + return PageIdle(page); +} + +static inline void set_page_idle(struct page *page) +{ + SetPageIdle(page); +} + +static inline void clear_page_idle(struct page *page) +{ + ClearPageIdle(page); +} +#else /* !CONFIG_64BIT */ +/* + * If there is not enough space to store Idle and Young bits in page flags, use + * page ext flags instead. + */ +extern struct page_ext_operations page_idle_ops; + +static inline bool page_is_young(struct page *page) +{ + return test_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags); +} + +static inline void set_page_young(struct page *page) +{ + set_bit(PAGE_EXT_YOUNG, &lookup_page_ext(page)->flags); +} + +static inline bool test_and_clear_page_young(struct page *page) +{ + return test_and_clear_bit(PAGE_EXT_YOUNG, + &lookup_page_ext(page)->flags); +} + +static inline bool page_is_idle(struct page *page) +{ + return test_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags); +} + +static inline void set_page_idle(struct page *page) +{ + set_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags); +} + +static inline void clear_page_idle(struct page *page) +{ + clear_bit(PAGE_EXT_IDLE, &lookup_page_ext(page)->flags); +} +#endif /* CONFIG_64BIT */ + +#else /* !CONFIG_IDLE_PAGE_TRACKING */ + +static inline bool page_is_young(struct page *page) +{ + return false; +} + +static inline void set_page_young(struct page *page) +{ +} + +static inline bool test_and_clear_page_young(struct page *page) +{ + return false; +} + +static inline bool page_is_idle(struct page *page) +{ + return false; +} + +static inline void set_page_idle(struct page *page) +{ +} + +static inline void clear_page_idle(struct page *page) +{ +} + +#endif /* CONFIG_IDLE_PAGE_TRACKING */ + +#endif /* _LINUX_MM_PAGE_IDLE_H */ diff --git a/mm/Kconfig b/mm/Kconfig index 3a4070f5ab794..6413d027c0b2e 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -649,6 +649,18 @@ config DEFERRED_STRUCT_PAGE_INIT processes running early in the lifetime of the systemm until kswapd finishes the initialisation. +config IDLE_PAGE_TRACKING + bool "Enable idle page tracking" + depends on SYSFS && MMU + select PAGE_EXTENSION if !64BIT + help + This feature allows to estimate the amount of user pages that have + not been touched during a given period of time. This information can + be useful to tune memory cgroup limits and/or for job placement + within a compute cluster. + + See Documentation/vm/idle_page_tracking.txt for more details. + config ZONE_DEVICE bool "Device memory (pmem, etc...) hotplug support" if EXPERT default !ZONE_DMA diff --git a/mm/Makefile b/mm/Makefile index b424d5e5b6ff5..56f8eed73f1a6 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -79,3 +79,4 @@ obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o obj-$(CONFIG_USERFAULTFD) += userfaultfd.o +obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o diff --git a/mm/debug.c b/mm/debug.c index 76089ddf99ea1..6c1b3ea61bfdd 100644 --- a/mm/debug.c +++ b/mm/debug.c @@ -48,6 +48,10 @@ static const struct trace_print_flags pageflag_names[] = { #ifdef CONFIG_TRANSPARENT_HUGEPAGE {1UL << PG_compound_lock, "compound_lock" }, #endif +#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) + {1UL << PG_young, "young" }, + {1UL << PG_idle, "idle" }, +#endif }; static void dump_flags(unsigned long flags, diff --git a/mm/huge_memory.c b/mm/huge_memory.c index b16279cbd91df..4b06b8db9df23 100644 --- a/mm/huge_memory.c +++ b/mm/huge_memory.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -1757,6 +1758,11 @@ static void __split_huge_page_refcount(struct page *page, /* clear PageTail before overwriting first_page */ smp_wmb(); + if (page_is_young(page)) + set_page_young(page_tail); + if (page_is_idle(page)) + set_page_idle(page_tail); + /* * __split_huge_page_splitting() already set the * splitting bit in all pmd that could map this @@ -2262,7 +2268,8 @@ static int __collapse_huge_page_isolate(struct vm_area_struct *vma, VM_BUG_ON_PAGE(PageLRU(page), page); /* If there is no mapped pte young don't collapse the page */ - if (pte_young(pteval) || PageReferenced(page) || + if (pte_young(pteval) || + page_is_young(page) || PageReferenced(page) || mmu_notifier_test_young(vma->vm_mm, address)) referenced = true; } @@ -2693,7 +2700,8 @@ static int khugepaged_scan_pmd(struct mm_struct *mm, */ if (page_count(page) != 1 + !!PageSwapCache(page)) goto out_unmap; - if (pte_young(pteval) || PageReferenced(page) || + if (pte_young(pteval) || + page_is_young(page) || PageReferenced(page) || mmu_notifier_test_young(vma->vm_mm, address)) referenced = true; } diff --git a/mm/migrate.c b/mm/migrate.c index 02ce25df16c26..c3cb566af3e27 100644 --- a/mm/migrate.c +++ b/mm/migrate.c @@ -37,6 +37,7 @@ #include #include #include +#include #include @@ -524,6 +525,11 @@ void migrate_page_copy(struct page *newpage, struct page *page) __set_page_dirty_nobuffers(newpage); } + if (page_is_young(page)) + set_page_young(newpage); + if (page_is_idle(page)) + set_page_idle(newpage); + /* * Copy NUMA information to the new page, to prevent over-eager * future migrations of this same page. diff --git a/mm/page_ext.c b/mm/page_ext.c index d86fd2f5353fc..292ca7b8debd2 100644 --- a/mm/page_ext.c +++ b/mm/page_ext.c @@ -6,6 +6,7 @@ #include #include #include +#include /* * struct page extension @@ -59,6 +60,9 @@ static struct page_ext_operations *page_ext_ops[] = { #ifdef CONFIG_PAGE_OWNER &page_owner_ops, #endif +#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) + &page_idle_ops, +#endif }; static unsigned long total_usage; diff --git a/mm/page_idle.c b/mm/page_idle.c new file mode 100644 index 0000000000000..d5dd790414845 --- /dev/null +++ b/mm/page_idle.c @@ -0,0 +1,232 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BITMAP_CHUNK_SIZE sizeof(u64) +#define BITMAP_CHUNK_BITS (BITMAP_CHUNK_SIZE * BITS_PER_BYTE) + +/* + * Idle page tracking only considers user memory pages, for other types of + * pages the idle flag is always unset and an attempt to set it is silently + * ignored. + * + * We treat a page as a user memory page if it is on an LRU list, because it is + * always safe to pass such a page to rmap_walk(), which is essential for idle + * page tracking. With such an indicator of user pages we can skip isolated + * pages, but since there are not usually many of them, it will hardly affect + * the overall result. + * + * This function tries to get a user memory page by pfn as described above. + */ +static struct page *page_idle_get_page(unsigned long pfn) +{ + struct page *page; + struct zone *zone; + + if (!pfn_valid(pfn)) + return NULL; + + page = pfn_to_page(pfn); + if (!page || !PageLRU(page) || + !get_page_unless_zero(page)) + return NULL; + + zone = page_zone(page); + spin_lock_irq(&zone->lru_lock); + if (unlikely(!PageLRU(page))) { + put_page(page); + page = NULL; + } + spin_unlock_irq(&zone->lru_lock); + return page; +} + +static int page_idle_clear_pte_refs_one(struct page *page, + struct vm_area_struct *vma, + unsigned long addr, void *arg) +{ + struct mm_struct *mm = vma->vm_mm; + spinlock_t *ptl; + pmd_t *pmd; + pte_t *pte; + bool referenced = false; + + if (unlikely(PageTransHuge(page))) { + pmd = page_check_address_pmd(page, mm, addr, + PAGE_CHECK_ADDRESS_PMD_FLAG, &ptl); + if (pmd) { + referenced = pmdp_clear_young_notify(vma, addr, pmd); + spin_unlock(ptl); + } + } else { + pte = page_check_address(page, mm, addr, &ptl, 0); + if (pte) { + referenced = ptep_clear_young_notify(vma, addr, pte); + pte_unmap_unlock(pte, ptl); + } + } + if (referenced) { + clear_page_idle(page); + /* + * We cleared the referenced bit in a mapping to this page. To + * avoid interference with page reclaim, mark it young so that + * page_referenced() will return > 0. + */ + set_page_young(page); + } + return SWAP_AGAIN; +} + +static void page_idle_clear_pte_refs(struct page *page) +{ + /* + * Since rwc.arg is unused, rwc is effectively immutable, so we + * can make it static const to save some cycles and stack. + */ + static const struct rmap_walk_control rwc = { + .rmap_one = page_idle_clear_pte_refs_one, + .anon_lock = page_lock_anon_vma_read, + }; + bool need_lock; + + if (!page_mapped(page) || + !page_rmapping(page)) + return; + + need_lock = !PageAnon(page) || PageKsm(page); + if (need_lock && !trylock_page(page)) + return; + + rmap_walk(page, (struct rmap_walk_control *)&rwc); + + if (need_lock) + unlock_page(page); +} + +static ssize_t page_idle_bitmap_read(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t pos, size_t count) +{ + u64 *out = (u64 *)buf; + struct page *page; + unsigned long pfn, end_pfn; + int bit; + + if (pos % BITMAP_CHUNK_SIZE || count % BITMAP_CHUNK_SIZE) + return -EINVAL; + + pfn = pos * BITS_PER_BYTE; + if (pfn >= max_pfn) + return 0; + + end_pfn = pfn + count * BITS_PER_BYTE; + if (end_pfn > max_pfn) + end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS); + + for (; pfn < end_pfn; pfn++) { + bit = pfn % BITMAP_CHUNK_BITS; + if (!bit) + *out = 0ULL; + page = page_idle_get_page(pfn); + if (page) { + if (page_is_idle(page)) { + /* + * The page might have been referenced via a + * pte, in which case it is not idle. Clear + * refs and recheck. + */ + page_idle_clear_pte_refs(page); + if (page_is_idle(page)) + *out |= 1ULL << bit; + } + put_page(page); + } + if (bit == BITMAP_CHUNK_BITS - 1) + out++; + cond_resched(); + } + return (char *)out - buf; +} + +static ssize_t page_idle_bitmap_write(struct file *file, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t pos, size_t count) +{ + const u64 *in = (u64 *)buf; + struct page *page; + unsigned long pfn, end_pfn; + int bit; + + if (pos % BITMAP_CHUNK_SIZE || count % BITMAP_CHUNK_SIZE) + return -EINVAL; + + pfn = pos * BITS_PER_BYTE; + if (pfn >= max_pfn) + return -ENXIO; + + end_pfn = pfn + count * BITS_PER_BYTE; + if (end_pfn > max_pfn) + end_pfn = ALIGN(max_pfn, BITMAP_CHUNK_BITS); + + for (; pfn < end_pfn; pfn++) { + bit = pfn % BITMAP_CHUNK_BITS; + if ((*in >> bit) & 1) { + page = page_idle_get_page(pfn); + if (page) { + page_idle_clear_pte_refs(page); + set_page_idle(page); + put_page(page); + } + } + if (bit == BITMAP_CHUNK_BITS - 1) + in++; + cond_resched(); + } + return (char *)in - buf; +} + +static struct bin_attribute page_idle_bitmap_attr = + __BIN_ATTR(bitmap, S_IRUSR | S_IWUSR, + page_idle_bitmap_read, page_idle_bitmap_write, 0); + +static struct bin_attribute *page_idle_bin_attrs[] = { + &page_idle_bitmap_attr, + NULL, +}; + +static struct attribute_group page_idle_attr_group = { + .bin_attrs = page_idle_bin_attrs, + .name = "page_idle", +}; + +#ifndef CONFIG_64BIT +static bool need_page_idle(void) +{ + return true; +} +struct page_ext_operations page_idle_ops = { + .need = need_page_idle, +}; +#endif + +static int __init page_idle_init(void) +{ + int err; + + err = sysfs_create_group(mm_kobj, &page_idle_attr_group); + if (err) { + pr_err("page_idle: register sysfs failed\n"); + return err; + } + return 0; +} +subsys_initcall(page_idle_init); diff --git a/mm/rmap.c b/mm/rmap.c index 0db38e7d0a72b..f5b5c1f3dcd75 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -59,6 +59,7 @@ #include #include #include +#include #include @@ -886,6 +887,11 @@ static int page_referenced_one(struct page *page, struct vm_area_struct *vma, pte_unmap_unlock(pte, ptl); } + if (referenced) + clear_page_idle(page); + if (test_and_clear_page_young(page)) + referenced++; + if (referenced) { pra->referenced++; pra->vm_flags |= vma->vm_flags; diff --git a/mm/swap.c b/mm/swap.c index a3a0a2f1f7c3d..983f692a47fdf 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" @@ -622,6 +623,8 @@ void mark_page_accessed(struct page *page) } else if (!PageReferenced(page)) { SetPageReferenced(page); } + if (page_is_idle(page)) + clear_page_idle(page); } EXPORT_SYMBOL(mark_page_accessed); -- GitLab From f074a8f49eb87cde95ac9d040ad5e7ea4f029738 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:48 -0700 Subject: [PATCH 6911/7006] proc: export idle flag via kpageflags As noted by Minchan, a benefit of reading idle flag from /proc/kpageflags is that one can easily filter dirty and/or unevictable pages while estimating the size of unused memory. Note that idle flag read from /proc/kpageflags may be stale in case the page was accessed via a PTE, because it would be too costly to iterate over all page mappings on each /proc/kpageflags read to provide an up-to-date value. To make sure the flag is up-to-date one has to read /sys/kernel/mm/page_idle/bitmap first. Signed-off-by: Vladimir Davydov Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- Documentation/vm/pagemap.txt | 7 +++++++ fs/proc/page.c | 3 +++ include/uapi/linux/kernel-page-flags.h | 1 + 3 files changed, 11 insertions(+) diff --git a/Documentation/vm/pagemap.txt b/Documentation/vm/pagemap.txt index ce294b0aace49..0e1e55588b598 100644 --- a/Documentation/vm/pagemap.txt +++ b/Documentation/vm/pagemap.txt @@ -70,6 +70,7 @@ There are four components to pagemap: 22. THP 23. BALLOON 24. ZERO_PAGE + 25. IDLE * /proc/kpagecgroup. This file contains a 64-bit inode number of the memory cgroup each page is charged to, indexed by PFN. Only available when @@ -120,6 +121,12 @@ Short descriptions to the page flags: 24. ZERO_PAGE zero page for pfn_zero or huge_zero page +25. IDLE + page has not been accessed since it was marked idle (see + Documentation/vm/idle_page_tracking.txt). Note that this flag may be + stale in case the page was accessed via a PTE. To make sure the flag + is up-to-date one has to read /sys/kernel/mm/page_idle/bitmap first. + [IO related page flags] 1. ERROR IO error occurred 3. UPTODATE page has up-to-date data diff --git a/fs/proc/page.c b/fs/proc/page.c index c2d29edcaa6bd..0b8286450a939 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -150,6 +150,9 @@ u64 stable_page_flags(struct page *page) if (PageBalloon(page)) u |= 1 << KPF_BALLOON; + if (page_is_idle(page)) + u |= 1 << KPF_IDLE; + u |= kpf_copy_bit(k, KPF_LOCKED, PG_locked); u |= kpf_copy_bit(k, KPF_SLAB, PG_slab); diff --git a/include/uapi/linux/kernel-page-flags.h b/include/uapi/linux/kernel-page-flags.h index a6c4962e5d462..5da5f8751ce7d 100644 --- a/include/uapi/linux/kernel-page-flags.h +++ b/include/uapi/linux/kernel-page-flags.h @@ -33,6 +33,7 @@ #define KPF_THP 22 #define KPF_BALLOON 23 #define KPF_ZERO_PAGE 24 +#define KPF_IDLE 25 #endif /* _UAPILINUX_KERNEL_PAGE_FLAGS_H */ -- GitLab From d3691d2c6d3e72624c987bbef6f322631bbb2d5d Mon Sep 17 00:00:00 2001 From: Vladimir Davydov Date: Wed, 9 Sep 2015 15:35:51 -0700 Subject: [PATCH 6912/7006] proc: add cond_resched to /proc/kpage* read/write loop Reading/writing a /proc/kpage* file may take long on machines with a lot of RAM installed. Signed-off-by: Vladimir Davydov Suggested-by: Andres Lagar-Cavilla Reviewed-by: Andres Lagar-Cavilla Cc: Minchan Kim Cc: Raghavendra K T Cc: Johannes Weiner Cc: Michal Hocko Cc: Greg Thelen Cc: Michel Lespinasse Cc: David Rientjes Cc: Pavel Emelyanov Cc: Cyrill Gorcunov Cc: Jonathan Corbet Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/page.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/proc/page.c b/fs/proc/page.c index 0b8286450a939..93484034a03d0 100644 --- a/fs/proc/page.c +++ b/fs/proc/page.c @@ -58,6 +58,8 @@ static ssize_t kpagecount_read(struct file *file, char __user *buf, pfn++; out++; count -= KPMSIZE; + + cond_resched(); } *ppos += (char __user *)out - buf; @@ -219,6 +221,8 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf, pfn++; out++; count -= KPMSIZE; + + cond_resched(); } *ppos += (char __user *)out - buf; @@ -267,6 +271,8 @@ static ssize_t kpagecgroup_read(struct file *file, char __user *buf, pfn++; out++; count -= KPMSIZE; + + cond_resched(); } *ppos += (char __user *)out - buf; -- GitLab From bdb4d100afe9818aebd1d98ced575c5ef143456c Mon Sep 17 00:00:00 2001 From: Calvin Owens Date: Wed, 9 Sep 2015 15:35:54 -0700 Subject: [PATCH 6913/7006] procfs: always expose /proc//map_files/ and make it readable Currently, /proc//map_files/ is restricted to CAP_SYS_ADMIN, and is only exposed if CONFIG_CHECKPOINT_RESTORE is set. Each mapped file region gets a symlink in /proc//map_files/ corresponding to the virtual address range at which it is mapped. The symlinks work like the symlinks in /proc//fd/, so you can follow them to the backing file even if that backing file has been unlinked. Currently, files which are mapped, unlinked, and closed are impossible to stat() from userspace. Exposing /proc//map_files/ closes this functionality "hole". Not being able to stat() such files makes noticing and explicitly accounting for the space they use on the filesystem impossible. You can work around this by summing up the space used by every file in the filesystem and subtracting that total from what statfs() tells you, but that obviously isn't great, and it becomes unworkable once your filesystem becomes large enough. This patch moves map_files/ out from behind CONFIG_CHECKPOINT_RESTORE, and adjusts the permissions enforced on it as follows: * proc_map_files_lookup() * proc_map_files_readdir() * map_files_d_revalidate() Remove the CAP_SYS_ADMIN restriction, leaving only the current restriction requiring PTRACE_MODE_READ. The information made available to userspace by these three functions is already available in /proc/PID/maps with MODE_READ, so I don't see any reason to limit them any further (see below for more detail). * proc_map_files_follow_link() This stub has been added, and requires that the user have CAP_SYS_ADMIN in order to follow the links in map_files/, since there was concern on LKML both about the potential for bypassing permissions on ancestor directories in the path to files pointed to, and about what happens with more exotic memory mappings created by some drivers (ie dma-buf). In older versions of this patch, I changed every permission check in the four functions above to enforce MODE_ATTACH instead of MODE_READ. This was an oversight on my part, and after revisiting the discussion it seems that nobody was concerned about anything outside of what is made possible by ->follow_link(). So in this version, I've left the checks for PTRACE_MODE_READ as-is. [akpm@linux-foundation.org: catch up with concurrent proc_pid_follow_link() changes] Signed-off-by: Calvin Owens Reviewed-by: Kees Cook Cc: Andy Lutomirski Cc: Cyrill Gorcunov Cc: Joe Perches Cc: Kirill A. Shutemov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index aa50d1ac28fc6..60c71b10eaee8 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1836,8 +1836,6 @@ end_instantiate: return dir_emit(ctx, name, len, 1, DT_UNKNOWN); } -#ifdef CONFIG_CHECKPOINT_RESTORE - /* * dname_to_vma_addr - maps a dentry name into two unsigned longs * which represent vma start and end addresses. @@ -1864,11 +1862,6 @@ static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) if (flags & LOOKUP_RCU) return -ECHILD; - if (!capable(CAP_SYS_ADMIN)) { - status = -EPERM; - goto out_notask; - } - inode = d_inode(dentry); task = get_proc_task(inode); if (!task) @@ -1957,6 +1950,29 @@ struct map_files_info { unsigned char name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */ }; +/* + * Only allow CAP_SYS_ADMIN to follow the links, due to concerns about how the + * symlinks may be used to bypass permissions on ancestor directories in the + * path to the file in question. + */ +static const char * +proc_map_files_follow_link(struct dentry *dentry, void **cookie) +{ + if (!capable(CAP_SYS_ADMIN)) + return ERR_PTR(-EPERM); + + return proc_pid_follow_link(dentry, NULL); +} + +/* + * Identical to proc_pid_link_inode_operations except for follow_link() + */ +static const struct inode_operations proc_map_files_link_inode_operations = { + .readlink = proc_pid_readlink, + .follow_link = proc_map_files_follow_link, + .setattr = proc_setattr, +}; + static int proc_map_files_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) @@ -1972,7 +1988,7 @@ proc_map_files_instantiate(struct inode *dir, struct dentry *dentry, ei = PROC_I(inode); ei->op.proc_get_link = proc_map_files_get_link; - inode->i_op = &proc_pid_link_inode_operations; + inode->i_op = &proc_map_files_link_inode_operations; inode->i_size = 64; inode->i_mode = S_IFLNK; @@ -1996,10 +2012,6 @@ static struct dentry *proc_map_files_lookup(struct inode *dir, int result; struct mm_struct *mm; - result = -EPERM; - if (!capable(CAP_SYS_ADMIN)) - goto out; - result = -ENOENT; task = get_proc_task(dir); if (!task) @@ -2053,10 +2065,6 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx) struct map_files_info *p; int ret; - ret = -EPERM; - if (!capable(CAP_SYS_ADMIN)) - goto out; - ret = -ENOENT; task = get_proc_task(file_inode(file)); if (!task) @@ -2245,7 +2253,6 @@ static const struct file_operations proc_timers_operations = { .llseek = seq_lseek, .release = seq_release_private, }; -#endif /* CONFIG_CHECKPOINT_RESTORE */ static int proc_pident_instantiate(struct inode *dir, struct dentry *dentry, struct task_struct *task, const void *ptr) @@ -2744,9 +2751,7 @@ static const struct inode_operations proc_task_inode_operations; static const struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), -#ifdef CONFIG_CHECKPOINT_RESTORE DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), -#endif DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), #ifdef CONFIG_NET -- GitLab From ecf1a3dfff22bd165532a3af64f32697ae97c1ef Mon Sep 17 00:00:00 2001 From: Waiman Long Date: Wed, 9 Sep 2015 15:35:57 -0700 Subject: [PATCH 6914/7006] proc: change proc_subdir_lock to a rwlock The proc_subdir_lock spinlock is used to allow only one task to make change to the proc directory structure as well as looking up information in it. However, the information lookup part can actually be entered by more than one task as the pde_get() and pde_put() reference count update calls in the critical sections are atomic increment and decrement respectively and so are safe with concurrent updates. The x86 architecture has already used qrwlock which is fair and other architectures like ARM are in the process of switching to qrwlock. So unfairness shouldn't be a concern in that conversion. This patch changed the proc_subdir_lock to a rwlock in order to enable concurrent lookup. The following functions were modified to take a write lock: - proc_register() - remove_proc_entry() - remove_proc_subtree() The following functions were modified to take a read lock: - xlate_proc_name() - proc_lookup_de() - proc_readdir_de() A parallel /proc filesystem search with the "find" command (1000 threads) was run on a 4-socket Haswell-EX box (144 threads). Before the patch, the parallel search took about 39s. After the patch, the parallel find took only 25s, a saving of about 14s. The micro-benchmark that I used was artificial, but it was used to reproduce an exit hanging problem that I saw in real application. In fact, only allow one task to do a lookup seems too limiting to me. Signed-off-by: Waiman Long Acked-by: "Eric W. Biederman" Cc: Alexey Dobriyan Cc: Nicolas Dichtel Cc: Al Viro Cc: Scott J Norton Cc: Douglas Hatch Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/generic.c | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/fs/proc/generic.c b/fs/proc/generic.c index e5dee5c3188eb..ff3ffc76a9379 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -26,7 +26,7 @@ #include "internal.h" -static DEFINE_SPINLOCK(proc_subdir_lock); +static DEFINE_RWLOCK(proc_subdir_lock); static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de) { @@ -172,9 +172,9 @@ static int xlate_proc_name(const char *name, struct proc_dir_entry **ret, { int rv; - spin_lock(&proc_subdir_lock); + read_lock(&proc_subdir_lock); rv = __xlate_proc_name(name, ret, residual); - spin_unlock(&proc_subdir_lock); + read_unlock(&proc_subdir_lock); return rv; } @@ -231,11 +231,11 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, { struct inode *inode; - spin_lock(&proc_subdir_lock); + read_lock(&proc_subdir_lock); de = pde_subdir_find(de, dentry->d_name.name, dentry->d_name.len); if (de) { pde_get(de); - spin_unlock(&proc_subdir_lock); + read_unlock(&proc_subdir_lock); inode = proc_get_inode(dir->i_sb, de); if (!inode) return ERR_PTR(-ENOMEM); @@ -243,7 +243,7 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, d_add(dentry, inode); return NULL; } - spin_unlock(&proc_subdir_lock); + read_unlock(&proc_subdir_lock); return ERR_PTR(-ENOENT); } @@ -270,12 +270,12 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file, if (!dir_emit_dots(file, ctx)) return 0; - spin_lock(&proc_subdir_lock); + read_lock(&proc_subdir_lock); de = pde_subdir_first(de); i = ctx->pos - 2; for (;;) { if (!de) { - spin_unlock(&proc_subdir_lock); + read_unlock(&proc_subdir_lock); return 0; } if (!i) @@ -287,19 +287,19 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file, do { struct proc_dir_entry *next; pde_get(de); - spin_unlock(&proc_subdir_lock); + read_unlock(&proc_subdir_lock); if (!dir_emit(ctx, de->name, de->namelen, de->low_ino, de->mode >> 12)) { pde_put(de); return 0; } - spin_lock(&proc_subdir_lock); + read_lock(&proc_subdir_lock); ctx->pos++; next = pde_subdir_next(de); pde_put(de); de = next; } while (de); - spin_unlock(&proc_subdir_lock); + read_unlock(&proc_subdir_lock); return 1; } @@ -338,16 +338,16 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp if (ret) return ret; - spin_lock(&proc_subdir_lock); + write_lock(&proc_subdir_lock); dp->parent = dir; if (pde_subdir_insert(dir, dp) == false) { WARN(1, "proc_dir_entry '%s/%s' already registered\n", dir->name, dp->name); - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); proc_free_inum(dp->low_ino); return -EEXIST; } - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); return 0; } @@ -549,9 +549,9 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) const char *fn = name; unsigned int len; - spin_lock(&proc_subdir_lock); + write_lock(&proc_subdir_lock); if (__xlate_proc_name(name, &parent, &fn) != 0) { - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); return; } len = strlen(fn); @@ -559,7 +559,7 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent) de = pde_subdir_find(parent, fn, len); if (de) rb_erase(&de->subdir_node, &parent->subdir); - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); if (!de) { WARN(1, "name '%s'\n", name); return; @@ -583,16 +583,16 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) const char *fn = name; unsigned int len; - spin_lock(&proc_subdir_lock); + write_lock(&proc_subdir_lock); if (__xlate_proc_name(name, &parent, &fn) != 0) { - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); return -ENOENT; } len = strlen(fn); root = pde_subdir_find(parent, fn, len); if (!root) { - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); return -ENOENT; } rb_erase(&root->subdir_node, &parent->subdir); @@ -605,7 +605,7 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) de = next; continue; } - spin_unlock(&proc_subdir_lock); + write_unlock(&proc_subdir_lock); proc_entry_rundown(de); next = de->parent; @@ -616,7 +616,7 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) break; pde_put(de); - spin_lock(&proc_subdir_lock); + write_lock(&proc_subdir_lock); de = next; } pde_put(root); -- GitLab From 8a5e5e02fc83aaf67053ab53b359af08c6c49aaf Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Wed, 9 Sep 2015 15:36:00 -0700 Subject: [PATCH 6915/7006] include/linux/poison.h: fix LIST_POISON{1,2} offset Poison pointer values should be small enough to find a room in non-mmap'able/hardly-mmap'able space. E.g. on x86 "poison pointer space" is located starting from 0x0. Given unprivileged users cannot mmap anything below mmap_min_addr, it should be safe to use poison pointers lower than mmap_min_addr. The current poison pointer values of LIST_POISON{1,2} might be too big for mmap_min_addr values equal or less than 1 MB (common case, e.g. Ubuntu uses only 0x10000). There is little point to use such a big value given the "poison pointer space" below 1 MB is not yet exhausted. Changing it to a smaller value solves the problem for small mmap_min_addr setups. The values are suggested by Solar Designer: http://www.openwall.com/lists/oss-security/2015/05/02/6 Signed-off-by: Vasily Kulikov Cc: Solar Designer Cc: Thomas Gleixner Cc: "Kirill A. Shutemov" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/poison.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/poison.h b/include/linux/poison.h index 2110a81c5e2af..253c9b4198eff 100644 --- a/include/linux/poison.h +++ b/include/linux/poison.h @@ -19,8 +19,8 @@ * under normal circumstances, used to verify that nobody uses * non-initialized list entries. */ -#define LIST_POISON1 ((void *) 0x00100100 + POISON_POINTER_DELTA) -#define LIST_POISON2 ((void *) 0x00200200 + POISON_POINTER_DELTA) +#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) +#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) /********** include/linux/timer.h **********/ /* -- GitLab From 8b839635e73575990e92cce1f19f5b1d7febd3fa Mon Sep 17 00:00:00 2001 From: Vasily Kulikov Date: Wed, 9 Sep 2015 15:36:03 -0700 Subject: [PATCH 6916/7006] include/linux/poison.h: remove not-used poison pointer macros Signed-off-by: Vasily Kulikov Cc: Solar Designer Cc: Thomas Gleixner Cc: "Kirill A. Shutemov" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/poison.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/include/linux/poison.h b/include/linux/poison.h index 253c9b4198eff..317e16de09e50 100644 --- a/include/linux/poison.h +++ b/include/linux/poison.h @@ -69,10 +69,6 @@ #define ATM_POISON_FREE 0x12 #define ATM_POISON 0xdeadbeef -/********** net/ **********/ -#define NEIGHBOR_DEAD 0xdeadbeef -#define NETFILTER_LINK_POISON 0xdead57ac - /********** kernel/mutexes **********/ #define MUTEX_DEBUG_INIT 0x11 #define MUTEX_DEBUG_FREE 0x22 @@ -83,7 +79,4 @@ /********** security/ **********/ #define KEY_DESTROY 0xbd -/********** sound/oss/ **********/ -#define OSS_POISON_FREE 0xAB - #endif -- GitLab From 2307e1a3c0780d7b908f6809f34034a04f954806 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 9 Sep 2015 15:36:06 -0700 Subject: [PATCH 6917/7006] kernel/extable.c: remove duplicated include Signed-off-by: Wei Yongjun Acked-by: Steven Rostedt Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/extable.c | 1 - 1 file changed, 1 deletion(-) diff --git a/kernel/extable.c b/kernel/extable.c index c98f926277a8d..e820ccee98467 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include -- GitLab From 52aa8536f8f41367d5f2938ad67aa87957e70010 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:36:09 -0700 Subject: [PATCH 6918/7006] kernel/cred.c: remove unnecessary kdebug atomic reads Commit e0e817392b9a ("CRED: Add some configurable debugging [try #6]") added the kdebug mechanism to this file back in 2009. The kdebug macro calls no_printk which always evaluates arguments. Most of the kdebug uses have an unnecessary call of atomic_read(&cred->usage) Make the kdebug macro do nothing by defining it with do { if (0) no_printk(...); } while (0) when not enabled. $ size kernel/cred.o* (defconfig x86-64) text data bss dec hex filename 2748 336 8 3092 c14 kernel/cred.o.new 2788 336 8 3132 c3c kernel/cred.o.old Miscellanea: o Neaten the #define kdebug macros while there Signed-off-by: Joe Perches Cc: David Howells Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/cred.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/kernel/cred.c b/kernel/cred.c index ec1c07667ec1d..71179a09c1d6a 100644 --- a/kernel/cred.c +++ b/kernel/cred.c @@ -20,11 +20,16 @@ #include #if 0 -#define kdebug(FMT, ...) \ - printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) +#define kdebug(FMT, ...) \ + printk("[%-5.5s%5u] " FMT "\n", \ + current->comm, current->pid, ##__VA_ARGS__) #else -#define kdebug(FMT, ...) \ - no_printk("[%-5.5s%5u] "FMT"\n", current->comm, current->pid ,##__VA_ARGS__) +#define kdebug(FMT, ...) \ +do { \ + if (0) \ + no_printk("[%-5.5s%5u] " FMT "\n", \ + current->comm, current->pid, ##__VA_ARGS__); \ +} while (0) #endif static struct kmem_cache *cred_jar; -- GitLab From 515a9adce0f0c3d2ef20f869c12902d03851a273 Mon Sep 17 00:00:00 2001 From: "Jason A. Donenfeld" Date: Wed, 9 Sep 2015 15:36:12 -0700 Subject: [PATCH 6919/7006] include/linux/printk.h: include pr_fmt in pr_debug_ratelimited The other two implementations of pr_debug_ratelimited include pr_fmt, along with every other pr_* function. But pr_debug_ratelimited forgot to add it with the CONFIG_DYNAMIC_DEBUG implementation. This patch unifies the behavior. Signed-off-by: Jason A. Donenfeld Cc: Steven Rostedt Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/printk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index a6298b27ac99d..6545d911054f3 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -404,10 +404,10 @@ do { \ static DEFINE_RATELIMIT_STATE(_rs, \ DEFAULT_RATELIMIT_INTERVAL, \ DEFAULT_RATELIMIT_BURST); \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ + DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, pr_fmt(fmt)); \ if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \ __ratelimit(&_rs)) \ - __dynamic_pr_debug(&descriptor, fmt, ##__VA_ARGS__); \ + __dynamic_pr_debug(&descriptor, pr_fmt(fmt), ##__VA_ARGS__); \ } while (0) #elif defined(DEBUG) #define pr_debug_ratelimited(fmt, ...) \ -- GitLab From 3cdea4d71439fb5676b7334a333dab0f7b1bd2e9 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:36:14 -0700 Subject: [PATCH 6920/7006] MAINTAINERS/CREDITS: mark MaxRAID as Orphan, move Anil Ravindranath to CREDITS Anil's email address bounces and he hasn't had a signoff in over 5 years. Signed-off-by: Joe Perches Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- CREDITS | 4 ++++ MAINTAINERS | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CREDITS b/CREDITS index bcb8efaa94590..8207cc62ee9d6 100644 --- a/CREDITS +++ b/CREDITS @@ -2992,6 +2992,10 @@ S: 2200 Mission College Blvd S: Santa Clara, CA 95052 S: USA +N: Anil Ravindranath +E: anil_ravindranath@pmc-sierra.com +D: PMC-Sierra MaxRAID driver + N: Eric S. Raymond E: esr@thyrsus.com W: http://www.tuxedo.org/~esr/ diff --git a/MAINTAINERS b/MAINTAINERS index 7635955f1c25e..59e2c0bc428ff 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8199,10 +8199,9 @@ F: drivers/hwmon/pmbus/ F: include/linux/i2c/pmbus.h PMC SIERRA MaxRAID DRIVER -M: Anil Ravindranath L: linux-scsi@vger.kernel.org W: http://www.pmc-sierra.com/ -S: Supported +S: Orphan F: drivers/scsi/pmcraid.* PMC SIERRA PM8001 DRIVER -- GitLab From 2d2e4715a65ca7e81b292d01ae009a03ccedb9b5 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 9 Sep 2015 15:36:17 -0700 Subject: [PATCH 6921/7006] kstrto*: accept "-0" for signed conversion strtol(3) et al accept "-0", so should we. Signed-off-by: Alexey Dobriyan Cc: David Howells Cc: Jan Kara Cc: Joel Becker Cc: Mark Fasheh Cc: Theodore Ts'o Cc: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/kstrtox.c | 2 +- lib/test-kstrtox.c | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/kstrtox.c b/lib/kstrtox.c index ec8da78df9be9..94be244e84410 100644 --- a/lib/kstrtox.c +++ b/lib/kstrtox.c @@ -152,7 +152,7 @@ int kstrtoll(const char *s, unsigned int base, long long *res) rv = _kstrtoull(s + 1, base, &tmp); if (rv < 0) return rv; - if ((long long)(-tmp) >= 0) + if ((long long)-tmp > 0) return -ERANGE; *res = -tmp; } else { diff --git a/lib/test-kstrtox.c b/lib/test-kstrtox.c index 4137bca5f8e8e..f355f67169b6a 100644 --- a/lib/test-kstrtox.c +++ b/lib/test-kstrtox.c @@ -260,6 +260,7 @@ static void __init test_kstrtoll_ok(void) {"4294967297", 10, 4294967297LL}, {"9223372036854775807", 10, 9223372036854775807LL}, + {"-0", 10, 0LL}, {"-1", 10, -1LL}, {"-2", 10, -2LL}, {"-9223372036854775808", 10, LLONG_MIN}, @@ -277,11 +278,6 @@ static void __init test_kstrtoll_fail(void) {"-9223372036854775809", 10}, {"-18446744073709551614", 10}, {"-18446744073709551615", 10}, - /* negative zero isn't an integer in Linux */ - {"-0", 0}, - {"-0", 8}, - {"-0", 10}, - {"-0", 16}, /* sign is first character if any */ {"-+1", 0}, {"-+1", 8}, -- GitLab From 774636e19ed514cdf560006813c0473409616de8 Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Wed, 9 Sep 2015 15:36:59 -0700 Subject: [PATCH 6922/7006] proc: convert to kstrto*()/kstrto*_from_user() Convert from manual allocation/copy_from_user/... to kstrto*() family which were designed for exactly that. One case can not be converted to kstrto*_from_user() to make code even more simpler because of whitespace stripping, oh well... Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/proc/base.c | 70 +++++++++++++++----------------------------------- 1 file changed, 21 insertions(+), 49 deletions(-) diff --git a/fs/proc/base.c b/fs/proc/base.c index 60c71b10eaee8..b25eee4cead53 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -1230,10 +1230,9 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { struct inode * inode = file_inode(file); - char *page, *tmp; - ssize_t length; uid_t loginuid; kuid_t kloginuid; + int rv; rcu_read_lock(); if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { @@ -1242,46 +1241,28 @@ static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, } rcu_read_unlock(); - if (count >= PAGE_SIZE) - count = PAGE_SIZE - 1; - if (*ppos != 0) { /* No partial writes. */ return -EINVAL; } - page = (char*)__get_free_page(GFP_TEMPORARY); - if (!page) - return -ENOMEM; - length = -EFAULT; - if (copy_from_user(page, buf, count)) - goto out_free_page; - page[count] = '\0'; - loginuid = simple_strtoul(page, &tmp, 10); - if (tmp == page) { - length = -EINVAL; - goto out_free_page; - - } + rv = kstrtou32_from_user(buf, count, 10, &loginuid); + if (rv < 0) + return rv; /* is userspace tring to explicitly UNSET the loginuid? */ if (loginuid == AUDIT_UID_UNSET) { kloginuid = INVALID_UID; } else { kloginuid = make_kuid(file->f_cred->user_ns, loginuid); - if (!uid_valid(kloginuid)) { - length = -EINVAL; - goto out_free_page; - } + if (!uid_valid(kloginuid)) + return -EINVAL; } - length = audit_set_loginuid(kloginuid); - if (likely(length == 0)) - length = count; - -out_free_page: - free_page((unsigned long) page); - return length; + rv = audit_set_loginuid(kloginuid); + if (rv < 0) + return rv; + return count; } static const struct file_operations proc_loginuid_operations = { @@ -1335,8 +1316,9 @@ static ssize_t proc_fault_inject_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos) { struct task_struct *task; - char buffer[PROC_NUMBUF], *end; + char buffer[PROC_NUMBUF]; int make_it_fail; + int rv; if (!capable(CAP_SYS_RESOURCE)) return -EPERM; @@ -1345,9 +1327,9 @@ static ssize_t proc_fault_inject_write(struct file * file, count = sizeof(buffer) - 1; if (copy_from_user(buffer, buf, count)) return -EFAULT; - make_it_fail = simple_strtol(strstrip(buffer), &end, 0); - if (*end) - return -EINVAL; + rv = kstrtoint(strstrip(buffer), 0, &make_it_fail); + if (rv < 0) + return rv; if (make_it_fail < 0 || make_it_fail > 1) return -EINVAL; @@ -2488,32 +2470,20 @@ static ssize_t proc_coredump_filter_write(struct file *file, { struct task_struct *task; struct mm_struct *mm; - char buffer[PROC_NUMBUF], *end; unsigned int val; int ret; int i; unsigned long mask; - ret = -EFAULT; - memset(buffer, 0, sizeof(buffer)); - if (count > sizeof(buffer) - 1) - count = sizeof(buffer) - 1; - if (copy_from_user(buffer, buf, count)) - goto out_no_task; - - ret = -EINVAL; - val = (unsigned int)simple_strtoul(buffer, &end, 0); - if (*end == '\n') - end++; - if (end - buffer == 0) - goto out_no_task; + ret = kstrtouint_from_user(buf, count, 0, &val); + if (ret < 0) + return ret; ret = -ESRCH; task = get_proc_task(file_inode(file)); if (!task) goto out_no_task; - ret = end - buffer; mm = get_task_mm(task); if (!mm) goto out_no_mm; @@ -2529,7 +2499,9 @@ static ssize_t proc_coredump_filter_write(struct file *file, out_no_mm: put_task_struct(task); out_no_task: - return ret; + if (ret < 0) + return ret; + return count; } static const struct file_operations proc_coredump_filter_operations = { -- GitLab From d21c3d4d1c6b2a0b85aeae5cc774b1bacc64e5b4 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Wed, 9 Sep 2015 15:37:02 -0700 Subject: [PATCH 6923/7006] lib/bitmap.c: correct a code style and do some, optimization We can avoid in-loop incrementation of ndigits. Save current totaldigits to ndigits before loop, and check ndigits against totaldigits after the loop. Signed-off-by: Pan Xinhui Cc: Yury Norov Cc: Chris Metcalf Cc: Rasmus Villemoes Cc: Sudeep Holla Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/bitmap.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/bitmap.c b/lib/bitmap.c index a578a01891997..eb21456be4b9e 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -367,7 +367,8 @@ int __bitmap_parse(const char *buf, unsigned int buflen, nchunks = nbits = totaldigits = c = 0; do { - chunk = ndigits = 0; + chunk = 0; + ndigits = totaldigits; /* Get the next chunk of the bitmap */ while (buflen) { @@ -406,9 +407,9 @@ int __bitmap_parse(const char *buf, unsigned int buflen, return -EOVERFLOW; chunk = (chunk << 4) | hex_to_bin(c); - ndigits++; totaldigits++; + totaldigits++; } - if (ndigits == 0) + if (ndigits == totaldigits) return -EINVAL; if (nchunks == 0 && chunk == 0) continue; -- GitLab From d9282cb66353be502aae09aae75d05a6863eb979 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Wed, 9 Sep 2015 15:37:05 -0700 Subject: [PATCH 6924/7006] lib/bitmap.c: fix a special string handling bug in __bitmap_parselist If string end with '-', for exapmle, bitmap_parselist("1,0-",&mask, nmaskbits), It is not in a valid pattern, so add a check after loop. Return -EINVAL on such condition. Signed-off-by: Pan Xinhui Cc: Yury Norov Cc: Chris Metcalf Cc: Rasmus Villemoes Cc: Sudeep Holla Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/bitmap.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/bitmap.c b/lib/bitmap.c index eb21456be4b9e..f549176e92502 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -546,6 +546,7 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, return -EINVAL; b = 0; in_range = 1; + at_start = 1; continue; } @@ -558,6 +559,9 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, at_start = 0; totaldigits++; } + /* if no digit is after '-', it's wrong*/ + if (at_start && in_range) + return -EINVAL; if (!(a <= b)) return -EINVAL; if (b >= nmaskbits) -- GitLab From 9bf98f168b7b004c94c766a6989071e0f858def3 Mon Sep 17 00:00:00 2001 From: Pan Xinhui Date: Wed, 9 Sep 2015 15:37:08 -0700 Subject: [PATCH 6925/7006] lib/bitmap.c: bitmap_parselist can accept string with whitespaces on head or tail In __bitmap_parselist we can accept whitespaces on head or tail during every parsing procedure. If input has valid ranges, there is no reason to reject the user. For example, bitmap_parselist(" 1-3, 5, ", &mask, nmaskbits). After separating the string, we get " 1-3", " 5", and " ". It's possible and reasonable to accept such string as long as the parsing result is correct. Signed-off-by: Pan Xinhui Cc: Yury Norov Cc: Chris Metcalf Cc: Rasmus Villemoes Cc: Sudeep Holla Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/bitmap.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/lib/bitmap.c b/lib/bitmap.c index f549176e92502..814814397cce3 100644 --- a/lib/bitmap.c +++ b/lib/bitmap.c @@ -506,7 +506,7 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, int nmaskbits) { unsigned a, b; - int c, old_c, totaldigits; + int c, old_c, totaldigits, ndigits; const char __user __force *ubuf = (const char __user __force *)buf; int at_start, in_range; @@ -516,6 +516,7 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, at_start = 1; in_range = 0; a = b = 0; + ndigits = totaldigits; /* Get the next cpu# or a range of cpu#'s */ while (buflen) { @@ -529,17 +530,20 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, if (isspace(c)) continue; - /* - * If the last character was a space and the current - * character isn't '\0', we've got embedded whitespace. - * This is a no-no, so throw an error. - */ - if (totaldigits && c && isspace(old_c)) - return -EINVAL; - /* A '\0' or a ',' signal the end of a cpu# or range */ if (c == '\0' || c == ',') break; + /* + * whitespaces between digits are not allowed, + * but it's ok if whitespaces are on head or tail. + * when old_c is whilespace, + * if totaldigits == ndigits, whitespace is on head. + * if whitespace is on tail, it should not run here. + * as c was ',' or '\0', + * the last code line has broken the current loop. + */ + if ((totaldigits != ndigits) && isspace(old_c)) + return -EINVAL; if (c == '-') { if (at_start || in_range) @@ -559,6 +563,8 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, at_start = 0; totaldigits++; } + if (ndigits == totaldigits) + continue; /* if no digit is after '-', it's wrong*/ if (at_start && in_range) return -EINVAL; @@ -566,11 +572,9 @@ static int __bitmap_parselist(const char *buf, unsigned int buflen, return -EINVAL; if (b >= nmaskbits) return -ERANGE; - if (!at_start) { - while (a <= b) { - set_bit(a, maskp); - a++; - } + while (a <= b) { + set_bit(a, maskp); + a++; } } while (buflen && c == ','); return 0; -- GitLab From cdf17449af1d9b596742c260134edd6c1fac2792 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 9 Sep 2015 15:37:11 -0700 Subject: [PATCH 6926/7006] hexdump: do not print debug dumps for !CONFIG_DEBUG print_hex_dump_debug() is likely supposed to be analogous to pr_debug() or dev_dbg() & friends. Currently it will adhere to dynamic debug, but will not stub out prints if CONFIG_DEBUG is not set. Let's make it do the right thing, because I am tired of having my dmesg buffer full of hex dumps on production systems. Signed-off-by: Linus Walleij Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/printk.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/include/linux/printk.h b/include/linux/printk.h index 6545d911054f3..9729565c25ff1 100644 --- a/include/linux/printk.h +++ b/include/linux/printk.h @@ -456,11 +456,17 @@ static inline void print_hex_dump_bytes(const char *prefix_str, int prefix_type, groupsize, buf, len, ascii) \ dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) -#else +#elif defined(DEBUG) #define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) \ print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ groupsize, buf, len, ascii) -#endif /* defined(CONFIG_DYNAMIC_DEBUG) */ +#else +static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, + int rowsize, int groupsize, + const void *buf, size_t len, bool ascii) +{ +} +#endif #endif -- GitLab From d89a3f7335bb5d9e572ecc287b300161200364eb Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 9 Sep 2015 15:37:14 -0700 Subject: [PATCH 6927/7006] lib/string_helpers: clarify esc arg in string_escape_mem The esc argument is used to reduce which characters will be escaped. For example, using " " with ESCAPE_SPACE will not produce any escaped spaces. Signed-off-by: Kees Cook Cc: Andy Shevchenko Cc: Rasmus Villemoes Cc: Mathias Krause Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/string_helpers.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/string_helpers.c b/lib/string_helpers.c index c98ae818eb4ee..0a307a97d489c 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -410,7 +410,7 @@ static bool escape_hex(unsigned char c, char **dst, char *end) * @dst: destination buffer (escaped) * @osz: destination buffer size * @flags: combination of the flags (bitwise OR): - * %ESCAPE_SPACE: + * %ESCAPE_SPACE: (special white space, not space itself) * '\f' - form feed * '\n' - new line * '\r' - carriage return @@ -432,8 +432,10 @@ static bool escape_hex(unsigned char c, char **dst, char *end) * all previous together * %ESCAPE_HEX: * '\xHH' - byte with hexadecimal value HH (2 digits) - * @esc: NULL-terminated string of characters any of which, if found in - * the source, has to be escaped + * @esc: NULL-terminated string containing characters used to limit + * the selected escape class. If characters are included in @esc + * that would not normally be escaped by the classes selected + * in @flags, they will be copied to @dst unescaped. * * Description: * The process of escaping byte buffer includes several parts. They are applied @@ -441,7 +443,7 @@ static bool escape_hex(unsigned char c, char **dst, char *end) * 1. The character is matched to the printable class, if asked, and in * case of match it passes through to the output. * 2. The character is not matched to the one from @esc string and thus - * must go as is to the output. + * must go as-is to the output. * 3. The character is checked if it falls into the class given by @flags. * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any * character. Note that they actually can't go together, otherwise -- GitLab From b40bdb7fb2b8359d5dfe19a91c147465c3d0359b Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 9 Sep 2015 15:37:16 -0700 Subject: [PATCH 6928/7006] lib/string_helpers: rename "esc" arg to "only" To further clarify the purpose of the "esc" argument, rename it to "only" to reflect that it is a limit, not a list of additional characters to escape. Signed-off-by: Kees Cook Suggested-by: Rasmus Villemoes Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/string_helpers.h | 14 +++++++------- lib/string_helpers.c | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/linux/string_helpers.h b/include/linux/string_helpers.h index 71f711db45006..dabe643eb5fad 100644 --- a/include/linux/string_helpers.h +++ b/include/linux/string_helpers.h @@ -48,24 +48,24 @@ static inline int string_unescape_any_inplace(char *buf) #define ESCAPE_HEX 0x20 int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, - unsigned int flags, const char *esc); + unsigned int flags, const char *only); static inline int string_escape_mem_any_np(const char *src, size_t isz, - char *dst, size_t osz, const char *esc) + char *dst, size_t osz, const char *only) { - return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, esc); + return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, only); } static inline int string_escape_str(const char *src, char *dst, size_t sz, - unsigned int flags, const char *esc) + unsigned int flags, const char *only) { - return string_escape_mem(src, strlen(src), dst, sz, flags, esc); + return string_escape_mem(src, strlen(src), dst, sz, flags, only); } static inline int string_escape_str_any_np(const char *src, char *dst, - size_t sz, const char *esc) + size_t sz, const char *only) { - return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, esc); + return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, only); } #endif diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 0a307a97d489c..54036ce2e2dd0 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c @@ -432,8 +432,8 @@ static bool escape_hex(unsigned char c, char **dst, char *end) * all previous together * %ESCAPE_HEX: * '\xHH' - byte with hexadecimal value HH (2 digits) - * @esc: NULL-terminated string containing characters used to limit - * the selected escape class. If characters are included in @esc + * @only: NULL-terminated string containing characters used to limit + * the selected escape class. If characters are included in @only * that would not normally be escaped by the classes selected * in @flags, they will be copied to @dst unescaped. * @@ -442,7 +442,7 @@ static bool escape_hex(unsigned char c, char **dst, char *end) * in the following sequence. * 1. The character is matched to the printable class, if asked, and in * case of match it passes through to the output. - * 2. The character is not matched to the one from @esc string and thus + * 2. The character is not matched to the one from @only string and thus * must go as-is to the output. * 3. The character is checked if it falls into the class given by @flags. * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any @@ -460,11 +460,11 @@ static bool escape_hex(unsigned char c, char **dst, char *end) * dst for a '\0' terminator if and only if ret < osz. */ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, - unsigned int flags, const char *esc) + unsigned int flags, const char *only) { char *p = dst; char *end = p + osz; - bool is_dict = esc && *esc; + bool is_dict = only && *only; while (isz--) { unsigned char c = *src++; @@ -473,7 +473,7 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, * Apply rules in the following sequence: * - the character is printable, when @flags has * %ESCAPE_NP bit set - * - the @esc string is supplied and does not contain a + * - the @only string is supplied and does not contain a * character under question * - the character doesn't fall into a class of symbols * defined by given @flags @@ -481,7 +481,7 @@ int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, * output buffer. */ if ((flags & ESCAPE_NP && isprint(c)) || - (is_dict && !strchr(esc, c))) { + (is_dict && !strchr(only, c))) { /* do nothing */ } else { if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) -- GitLab From 9789d8e0cfc6b5e265d9b0aa6e86b394a6d216a1 Mon Sep 17 00:00:00 2001 From: Wang Long Date: Wed, 9 Sep 2015 15:37:19 -0700 Subject: [PATCH 6929/7006] lib/test_kasan.c: fix a typo Signed-off-by: Wang Long Cc: Andrey Ryabinin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/test_kasan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 098c08eddfab7..044c54dd43fdb 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -65,7 +65,7 @@ static noinline void __init kmalloc_node_oob_right(void) kfree(ptr); } -static noinline void __init kmalloc_large_oob_rigth(void) +static noinline void __init kmalloc_large_oob_right(void) { char *ptr; size_t size = KMALLOC_MAX_CACHE_SIZE + 10; @@ -259,7 +259,7 @@ static int __init kmalloc_tests_init(void) kmalloc_oob_right(); kmalloc_oob_left(); kmalloc_node_oob_right(); - kmalloc_large_oob_rigth(); + kmalloc_large_oob_right(); kmalloc_oob_krealloc_more(); kmalloc_oob_krealloc_less(); kmalloc_oob_16(); -- GitLab From 6b4a35fc19a9229080dead8a9c316e8857b3e94d Mon Sep 17 00:00:00 2001 From: Wang Long Date: Wed, 9 Sep 2015 15:37:22 -0700 Subject: [PATCH 6930/7006] lib/test_kasan.c: make kmalloc_oob_krealloc_less more correctly In kmalloc_oob_krealloc_less, I think it is better to test the size2 boundary. If we do not call krealloc, the access of position size1 will still cause out-of-bounds and access of position size2 does not. After call krealloc, the access of position size2 cause out-of-bounds. So using size2 is more correct. Signed-off-by: Wang Long Cc: Andrey Ryabinin Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/test_kasan.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test_kasan.c b/lib/test_kasan.c index 044c54dd43fdb..c1efb1b610179 100644 --- a/lib/test_kasan.c +++ b/lib/test_kasan.c @@ -114,7 +114,7 @@ static noinline void __init kmalloc_oob_krealloc_less(void) kfree(ptr1); return; } - ptr2[size1] = 'x'; + ptr2[size2] = 'x'; kfree(ptr2); } -- GitLab From fe043ea1205695f2224b279ac9f5cc1742d18f0b Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:25 -0700 Subject: [PATCH 6931/7006] checkpatch: warn on bare SHA-1 commit IDs in commit logs Commit IDs should have commit descriptions too. Warn when a 12 to 40 byte SHA-1 is used in commit logs. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index a51ca0e5beef4..984a82e6b1885 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2317,9 +2317,11 @@ sub process { } # Check for git id commit length and improperly formed commit descriptions - if ($in_commit_log && $line =~ /\b(c)ommit\s+([0-9a-f]{5,})/i) { - my $init_char = $1; - my $orig_commit = lc($2); + if ($in_commit_log && + ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || + $line =~ /\b[0-9a-f]{12,40}\b/i)) { + my $init_char = "c"; + my $orig_commit = ""; my $short = 1; my $long = 0; my $case = 1; @@ -2330,6 +2332,13 @@ sub process { my $orig_desc = "commit description"; my $description = ""; + if ($line =~ /\b(c)ommit\s+([0-9a-f]{5,})\b/i) { + $init_char = $1; + $orig_commit = lc($2); + } elsif ($line =~ /\b([0-9a-f]{12,40})\b/i) { + $orig_commit = lc($1); + } + $short = 0 if ($line =~ /\bcommit\s+[0-9a-f]{12,40}/i); $long = 1 if ($line =~ /\bcommit\s+[0-9a-f]{41,}/i); $space = 0 if ($line =~ /\bcommit [0-9a-f]/i); -- GitLab From 9d3e3c705eb395528fd8f17208c87581b134da48 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:27 -0700 Subject: [PATCH 6932/7006] checkpatch: add warning on BUG/BUG_ON use Using BUG/BUG_ON crashes the kernel and is just unfriendly. Enable code that emits a warning on BUG/BUG_ON use. Make the code emit the message at WARNING level when scanning a patch and at CHECK level when scanning files so that script users don't feel an obligation to fix code that might be above their pay grade. Signed-off-by: Joe Perches Reported-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 984a82e6b1885..1629e3513f0d1 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3448,13 +3448,15 @@ sub process { } } -# # no BUG() or BUG_ON() -# if ($line =~ /\b(BUG|BUG_ON)\b/) { -# print "Try to use WARN_ON & Recovery code rather than BUG() or BUG_ON()\n"; -# print "$herecurr"; -# $clean = 0; -# } +# avoid BUG() or BUG_ON() + if ($line =~ /\b(?:BUG|BUG_ON)\b/) { + my $msg_type = \&WARN; + $msg_type = \&CHK if ($file); + &{$msg_type}("AVOID_BUG", + "Avoid crashing the kernel - try using WARN_ON & recovery code rather than BUG() or BUG_ON()\n" . $herecurr); + } +# avoid LINUX_VERSION_CODE if ($line =~ /\bLINUX_VERSION_CODE\b/) { WARN("LINUX_VERSION_CODE", "LINUX_VERSION_CODE should be avoided, code should be for the version to which it is merged\n" . $herecurr); -- GitLab From 9f5af480f4554aac12e002b6f5c2b04895857700 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:30 -0700 Subject: [PATCH 6933/7006] checkpatch: improve SUSPECT_CODE_INDENT test Many lines exist like if (foo) bar; where the tabbed indentation of the branch is not one more than the "if" line above it. checkpatch should emit a warning on those lines. Miscellenea: o Remove comments from branch blocks o Skip blank lines in block Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 1629e3513f0d1..ce305ff53aab4 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3076,15 +3076,22 @@ sub process { substr($s, 0, length($c), ''); - # Make sure we remove the line prefixes as we have - # none on the first line, and are going to readd them - # where necessary. - $s =~ s/\n./\n/gs; + # remove inline comments + $s =~ s/$;/ /g; + $c =~ s/$;/ /g; # Find out how long the conditional actually is. my @newlines = ($c =~ /\n/gs); my $cond_lines = 1 + $#newlines; + # Make sure we remove the line prefixes as we have + # none on the first line, and are going to readd them + # where necessary. + $s =~ s/\n./\n/gs; + while ($s =~ /\n\s+\\\n/) { + $cond_lines += $s =~ s/\n\s+\\\n/\n/g; + } + # We want to check the first line inside the block # starting at the end of the conditional, so remove: # 1) any blank line termination @@ -3150,8 +3157,10 @@ sub process { #print "line<$line> prevline<$prevline> indent<$indent> sindent<$sindent> check<$check> continuation<$continuation> s<$s> cond_lines<$cond_lines> stat_real<$stat_real> stat<$stat>\n"; - if ($check && (($sindent % 8) != 0 || - ($sindent <= $indent && $s ne ''))) { + if ($check && $s ne '' && + (($sindent % 8) != 0 || + ($sindent < $indent) || + ($sindent > $indent + 8))) { WARN("SUSPECT_CODE_INDENT", "suspect code indent for conditional statements ($indent, $sindent)\n" . $herecurr . "$stat_real\n"); } -- GitLab From 3e838b6c41e8ac86c992bdaaa78625faf528a578 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:33 -0700 Subject: [PATCH 6934/7006] checkpatch: Allow longer declaration macros Some really long declaration macros exist. For instance; DEFINE_DMA_BUF_EXPORT_INFO(exp_info); and DECLARE_DM_KCOPYD_THROTTLE_WITH_MODULE_PARM(name, description) Increase the limit from 2 words to 6 after DECLARE/DEFINE uses. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ce305ff53aab4..25314f37e79e8 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -584,7 +584,7 @@ our $LvalOrFunc = qr{((?:[\&\*]\s*)?$Lval)\s*($balanced_parens{0,1})\s*}; our $FuncArg = qr{$Typecast{0,1}($LvalOrFunc|$Constant|$String)}; our $declaration_macros = qr{(?x: - (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,2}\s*\(| + (?:$Storage\s+)?(?:[A-Z_][A-Z0-9]*_){0,2}(?:DEFINE|DECLARE)(?:_[A-Z0-9]+){1,6}\s*\(| (?:$Storage\s+)?LIST_HEAD\s*\(| (?:$Storage\s+)?${Type}\s+uninitialized_var\s*\( )}; -- GitLab From 100425deeb7586c9d401f787aeab3b43a4c6a0c6 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:36 -0700 Subject: [PATCH 6935/7006] checkpatch: add some _destroy functions to NEEDLESS_IF tests Sergey Senozhatsky has modified several destroy functions that can now be called with NULL values. - kmem_cache_destroy() - mempool_destroy() - dma_pool_destroy() Update checkpatch to warn when those functions are preceded by an if. Update checkpatch to --fix all the calls too only when the code style form is using leading tabs. from: if (foo) (foo); to: (foo); Signed-off-by: Joe Perches Tested-by: Sergey Senozhatsky Cc: David Rientjes Cc: Julia Lawall Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 25314f37e79e8..780c91d82aa9a 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -4836,10 +4836,34 @@ sub process { # check for needless "if () fn()" uses if ($prevline =~ /\bif\s*\(\s*($Lval)\s*\)/) { - my $expr = '\s*\(\s*' . quotemeta($1) . '\s*\)\s*;'; - if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/) { - WARN('NEEDLESS_IF', - "$1(NULL) is safe and this check is probably not required\n" . $hereprev); + my $tested = quotemeta($1); + my $expr = '\s*\(\s*' . $tested . '\s*\)\s*;'; + if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?|(?:kmem_cache|mempool|dma_pool)_destroy)$expr/) { + my $func = $1; + if (WARN('NEEDLESS_IF', + "$func(NULL) is safe and this check is probably not required\n" . $hereprev) && + $fix) { + my $do_fix = 1; + my $leading_tabs = ""; + my $new_leading_tabs = ""; + if ($lines[$linenr - 2] =~ /^\+(\t*)if\s*\(\s*$tested\s*\)\s*$/) { + $leading_tabs = $1; + } else { + $do_fix = 0; + } + if ($lines[$linenr - 1] =~ /^\+(\t+)$func\s*\(\s*$tested\s*\)\s*;\s*$/) { + $new_leading_tabs = $1; + if (length($leading_tabs) + 1 ne length($new_leading_tabs)) { + $do_fix = 0; + } + } else { + $do_fix = 0; + } + if ($do_fix) { + fix_delete_line($fixlinenr - 1, $prevrawline); + $fixed[$fixlinenr] =~ s/^\+$new_leading_tabs/\+$leading_tabs/; + } + } } } -- GitLab From 7d3a9f673e1bdb45f86d15a67e230e4a9b050850 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:39 -0700 Subject: [PATCH 6936/7006] checkpatch: report the right line # when using --emacs and --file commit 34d8815f9512 ("checkpatch: add --showfile to allow input via pipe to show filenames") broke the --emacs with --file option. Fix it. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 780c91d82aa9a..ea28336ea2a55 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2166,7 +2166,11 @@ sub process { if ($showfile) { $prefix = "$realfile:$realline: " } elsif ($emacs) { - $prefix = "$filename:$linenr: "; + if ($file) { + $prefix = "$filename:$realline: "; + } else { + $prefix = "$filename:$linenr: "; + } } if ($found_file) { -- GitLab From 86406b1cb7ac4fa5e7691eae5f2fb10c9af03dc3 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:41 -0700 Subject: [PATCH 6937/7006] checkpatch: always check block comment styles Some of the block comment tests that are used only for networking are appropriate for all patches. For example, these styles are not encouraged: /* block comment without introductory * */ and /* * block comment with line terminating */ Remove the networking specific test and add comments. There are some infrequent false positives where code is lazily commented out using /* and */ rather than using #if 0/#endif blocks like: /* case foo: case bar: */ case baz: Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ea28336ea2a55..7f309f0789a08 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2751,6 +2751,8 @@ sub process { } } +# Block comment styles +# Networking with an initial /* if ($realfile =~ m@^(drivers/net/|net/)@ && $prevrawline =~ /^\+[ \t]*\/\*[ \t]*$/ && $rawline =~ /^\+[ \t]*\*/ && @@ -2759,22 +2761,23 @@ sub process { "networking block comments don't use an empty /* line, use /* Comment...\n" . $hereprev); } - if ($realfile =~ m@^(drivers/net/|net/)@ && - $prevrawline =~ /^\+[ \t]*\/\*/ && #starting /* +# Block comments use * on subsequent lines + if ($prevline =~ /$;[ \t]*$/ && #ends in comment + $prevrawline =~ /^\+.*?\/\*/ && #starting /* $prevrawline !~ /\*\/[ \t]*$/ && #no trailing */ $rawline =~ /^\+/ && #line is new $rawline !~ /^\+[ \t]*\*/) { #no leading * - WARN("NETWORKING_BLOCK_COMMENT_STYLE", - "networking block comments start with * on subsequent lines\n" . $hereprev); + WARN("BLOCK_COMMENT_STYLE", + "Block comments use * on subsequent lines\n" . $hereprev); } - if ($realfile =~ m@^(drivers/net/|net/)@ && - $rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ +# Block comments use */ on trailing lines + if ($rawline !~ m@^\+[ \t]*\*/[ \t]*$@ && #trailing */ $rawline !~ m@^\+.*/\*.*\*/[ \t]*$@ && #inline /*...*/ $rawline !~ m@^\+.*\*{2,}/[ \t]*$@ && #trailing **/ $rawline =~ m@^\+[ \t]*.+\*\/[ \t]*$@) { #non blank */ - WARN("NETWORKING_BLOCK_COMMENT_STYLE", - "networking block comments put the trailing */ on a separate line\n" . $herecurr); + WARN("BLOCK_COMMENT_STYLE", + "Block comments use a trailing */ on a separate line\n" . $herecurr); } # check for missing blank lines after struct/union declarations -- GitLab From 7bd7e483c27d884c2f59e286e42623abba413f83 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:44 -0700 Subject: [PATCH 6938/7006] checkpatch: make --strict the default for drivers/staging files and patches Making --strict the default for staging may help some people submit patches without obvious defects. Signed-off-by: Joe Perches Cc: Dan Carpenter Cc: Greg Kroah-Hartman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 7f309f0789a08..41ecae81de998 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -2174,7 +2174,7 @@ sub process { } if ($found_file) { - if ($realfile =~ m@^(drivers/net/|net/)@) { + if ($realfile =~ m@^(?:drivers/net/|net/|drivers/staging/)@) { $check = 1; } else { $check = $check_orig; -- GitLab From 6e30075742316a1d72b7e8f794f6e0bd44d774e2 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:47 -0700 Subject: [PATCH 6939/7006] checkpatch: emit an error on formats with 0x% Using 0x%d is wrong. Emit a message when it happens. Miscellanea: Improve the %Lu warning to match formats like %16Lu. Signed-off-by: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 41ecae81de998..d98ffdd2180f1 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -4816,16 +4816,20 @@ sub process { "Consecutive strings are generally better as a single string\n" . $herecurr); } -# check for %L{u,d,i} in strings +# check for %L{u,d,i} and 0x%[udi] in strings my $string; while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) { $string = substr($rawline, $-[1], $+[1] - $-[1]); $string =~ s/%%/__/g; - if ($string =~ /(? Date: Wed, 9 Sep 2015 15:37:50 -0700 Subject: [PATCH 6940/7006] checkpatch: avoid some commit message long line warnings Fixes: and Link: lines may exceed 75 chars in the commit log. So too can stack dump and dmesg lines and lines that seem like filenames. And Fixes: lines don't need to have a "commit" prefix before the commit id. Add exceptions for these types of lines. Signed-off-by: Joe Perches Reported-by: Paul Bolle Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index d98ffdd2180f1..577241ed36968 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -1953,9 +1953,9 @@ sub process { our $clean = 1; my $signoff = 0; my $is_patch = 0; - my $in_header_lines = $file ? 0 : 1; my $in_commit_log = 0; #Scanning lines before patch + my $commit_log_possible_stack_dump = 0; my $commit_log_long_line = 0; my $commit_log_has_diff = 0; my $reported_maintainer_file = 0; @@ -2314,16 +2314,40 @@ sub process { # Check for line lengths > 75 in commit log, warn once if ($in_commit_log && !$commit_log_long_line && - length($line) > 75) { + length($line) > 75 && + !($line =~ /^\s*[a-zA-Z0-9_\/\.]+\s+\|\s+\d+/ || + # file delta changes + $line =~ /^\s*(?:[\w\.\-]+\/)++[\w\.\-]+:/ || + # filename then : + $line =~ /^\s*(?:Fixes:|Link:)/i || + # A Fixes: or Link: line + $commit_log_possible_stack_dump)) { WARN("COMMIT_LOG_LONG_LINE", "Possible unwrapped commit description (prefer a maximum 75 chars per line)\n" . $herecurr); $commit_log_long_line = 1; } +# Check if the commit log is in a possible stack dump + if ($in_commit_log && !$commit_log_possible_stack_dump && + ($line =~ /^\s*(?:WARNING:|BUG:)/ || + $line =~ /^\s*\[\s*\d+\.\d{6,6}\s*\]/ || + # timestamp + $line =~ /^\s*\[\<[0-9a-fA-F]{8,}\>\]/)) { + # stack dump address + $commit_log_possible_stack_dump = 1; + } + +# Reset possible stack dump if a blank line is found + if ($in_commit_log && $commit_log_possible_stack_dump && + $line =~ /^\s*$/) { + $commit_log_possible_stack_dump = 0; + } + # Check for git id commit length and improperly formed commit descriptions if ($in_commit_log && ($line =~ /\bcommit\s+[0-9a-f]{5,}\b/i || - $line =~ /\b[0-9a-f]{12,40}\b/i)) { + ($line =~ /\b[0-9a-f]{12,40}\b/i && + $line !~ /\bfixes:\s*[0-9a-f]{12,40}/i))) { my $init_char = "c"; my $orig_commit = ""; my $short = 1; -- GitLab From 4e5d56bdf892e18832a6540b63ebf709966bce2a Mon Sep 17 00:00:00 2001 From: Eddie Kovsky Date: Wed, 9 Sep 2015 15:37:52 -0700 Subject: [PATCH 6941/7006] checkpatch: fix left brace warning Using checkpatch.pl with Perl 5.22.0 generates the following warning: Unescaped left brace in regex is deprecated, passed through in regex; This patch fixes the warnings by escaping occurrences of the left brace inside the regular expression. Signed-off-by: Eddie Kovsky Cc: Joe Perches Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 577241ed36968..ba47dab3d0918 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -3571,7 +3571,7 @@ sub process { # function brace can't be on same line, except for #defines of do while, # or if closed on same line if (($line=~/$Type\s*$Ident\(.*\).*\s*{/) and - !($line=~/\#\s*define.*do\s{/) and !($line=~/}/)) { + !($line=~/\#\s*define.*do\s\{/) and !($line=~/}/)) { if (ERROR("OPEN_BRACE", "open brace '{' following function declarations go on the next line\n" . $herecurr) && $fix) { @@ -4083,8 +4083,8 @@ sub process { ## } #need space before brace following if, while, etc - if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) || - $line =~ /do{/) { + if (($line =~ /\(.*\)\{/ && $line !~ /\($Type\){/) || + $line =~ /do\{/) { if (ERROR("SPACING", "space required before the open brace '{'\n" . $herecurr) && $fix) { @@ -4531,7 +4531,7 @@ sub process { $dstat !~ /^for\s*$Constant$/ && # for (...) $dstat !~ /^for\s*$Constant\s+(?:$Ident|-?$Constant)$/ && # for (...) bar() $dstat !~ /^do\s*{/ && # do {... - $dstat !~ /^\({/ && # ({... + $dstat !~ /^\(\{/ && # ({... $ctx !~ /^.\s*#\s*define\s+TRACE_(?:SYSTEM|INCLUDE_FILE|INCLUDE_PATH)\b/) { $ctx =~ s/\n*$//; -- GitLab From 54507b5183cc4f8e4f1a58a312e1f30c130658b7 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:55 -0700 Subject: [PATCH 6942/7006] checkpatch: add __pmem to $Sparse annotations commit 61031952f4c8 ("arch, x86: pmem api for ensuring durability of persistent memory updates") added a new __pmem annotation for sparse verification. Add __pmem to the $Sparse variable so checkpatch can appropriately ignore uses of this attribute too. Signed-off-by: Joe Perches Reviewed-by: Ross Zwisler Acked-by: Andy Whitcroft Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index ba47dab3d0918..97ee377c4f517 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -264,6 +264,7 @@ our $Sparse = qr{ __kernel| __force| __iomem| + __pmem| __must_check| __init_refok| __kprobes| -- GitLab From c5595fa2f1ce3c1a74dbd2ddc949257e80d81dc0 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Wed, 9 Sep 2015 15:37:58 -0700 Subject: [PATCH 6943/7006] checkpatch: add constant comparison on left side test "CONST variable" checks like: if (NULL != foo) and while (0 < bar(...)) where a constant (or what appears to be a constant like an upper case identifier) is on the left of a comparison are generally preferred to be written using the constant on the right side like: if (foo != NULL) and while (bar(...) > 0) Add a test for this. Add a --fix option too, but only do it when the code is immediately surrounded by parentheses to avoid misfixing things like "(0 < bar() + constant)" Signed-off-by: Joe Perches Cc: Nicolas Morey Chaisemartin Cc: Viresh Kumar Cc: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/checkpatch.pl | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl index 97ee377c4f517..f2a1131b2f8ba 100755 --- a/scripts/checkpatch.pl +++ b/scripts/checkpatch.pl @@ -4231,6 +4231,35 @@ sub process { } } +# comparisons with a constant or upper case identifier on the left +# avoid cases like "foo + BAR < baz" +# only fix matches surrounded by parentheses to avoid incorrect +# conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5" + if ($^V && $^V ge 5.10.0 && + $line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) { + my $lead = $1; + my $const = $2; + my $comp = $3; + my $to = $4; + my $newcomp = $comp; + if ($lead !~ /$Operators\s*$/ && + $to !~ /^(?:Constant|[A-Z_][A-Z0-9_]*)$/ && + WARN("CONSTANT_COMPARISON", + "Comparisons should place the constant on the right side of the test\n" . $herecurr) && + $fix) { + if ($comp eq "<") { + $newcomp = ">"; + } elsif ($comp eq "<=") { + $newcomp = ">="; + } elsif ($comp eq ">") { + $newcomp = "<"; + } elsif ($comp eq ">=") { + $newcomp = "<="; + } + $fixed[$fixlinenr] =~ s/\(\s*\Q$const\E\s*$Compare\s*\Q$to\E\s*\)/($to $newcomp $const)/; + } + } + # Return of what appears to be an errno should normally be negative if ($sline =~ /\breturn(?:\s*\(+\s*|\s+)(E[A-Z]+)(?:\s*\)+\s*|\s*)[;:,]/) { my $name = $1; -- GitLab From 3725e9dd5bef376ab87d41e40c437a6b2a20eb59 Mon Sep 17 00:00:00 2001 From: Jan Harkes Date: Wed, 9 Sep 2015 15:38:01 -0700 Subject: [PATCH 6944/7006] fs/coda: fix readlink buffer overflow Dan Carpenter discovered a buffer overflow in the Coda file system readlink code. A userspace file system daemon can return a 4096 byte result which then triggers a one byte write past the allocated readlink result buffer. This does not trigger with an unmodified Coda implementation because Coda has a 1024 byte limit for symbolic links, however other userspace file systems using the Coda kernel module could be affected. Although this is an obvious overflow, I don't think this has to be handled as too sensitive from a security perspective because the overflow is on the Coda userspace daemon side which already needs root to open Coda's kernel device and to mount the file system before we get to the point that links can be read. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Jan Harkes Reported-by: Dan Carpenter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/coda/upcall.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index 9b1ffaa0572e5..f6c6c8adbc01e 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -353,7 +353,7 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid, char *result; insize = max_t(unsigned int, - INSIZE(readlink), OUTSIZE(readlink)+ *length + 1); + INSIZE(readlink), OUTSIZE(readlink)+ *length); UPARG(CODA_READLINK); inp->coda_readlink.VFid = *fid; @@ -361,8 +361,8 @@ int venus_readlink(struct super_block *sb, struct CodaFid *fid, error = coda_upcall(coda_vcp(sb), insize, &outsize, inp); if (!error) { retlen = outp->coda_readlink.count; - if ( retlen > *length ) - retlen = *length; + if (retlen >= *length) + retlen = *length - 1; *length = retlen; result = (char *)outp + (long)outp->coda_readlink.data; memcpy(buffer, result, retlen); -- GitLab From 7cb74be6fd827e314f81df3c5889b87e4c87c569 Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Wed, 9 Sep 2015 15:38:04 -0700 Subject: [PATCH 6945/7006] hfs,hfsplus: cache pages correctly between bnode_create and bnode_free Pages looked up by __hfs_bnode_create() (called by hfs_bnode_create() and hfs_bnode_find() for finding or creating pages corresponding to an inode) are immediately kmap()'ed and used (both read and write) and kunmap()'ed, and should not be page_cache_release()'ed until hfs_bnode_free(). This patch fixes a problem I first saw in July 2012: merely running "du" on a large hfsplus-mounted directory a few times on a reasonably loaded system would get the hfsplus driver all confused and complaining about B-tree inconsistencies, and generates a "BUG: Bad page state". Most recently, I can generate this problem on up-to-date Fedora 22 with shipped kernel 4.0.5, by running "du /" (="/" + "/home" + "/mnt" + other smaller mounts) and "du /mnt" simultaneously on two windows, where /mnt is a lightly-used QEMU VM image of the full Mac OS X 10.9: $ df -i / /home /mnt Filesystem Inodes IUsed IFree IUse% Mounted on /dev/mapper/fedora-root 3276800 551665 2725135 17% / /dev/mapper/fedora-home 52879360 716221 52163139 2% /home /dev/nbd0p2 4294967295 1387818 4293579477 1% /mnt After applying the patch, I was able to run "du /" (60+ times) and "du /mnt" (150+ times) continuously and simultaneously for 6+ hours. There are many reports of the hfsplus driver getting confused under load and generating "BUG: Bad page state" or other similar issues over the years. [1] The unpatched code [2] has always been wrong since it entered the kernel tree. The only reason why it gets away with it is that the kmap/memcpy/kunmap follow very quickly after the page_cache_release() so the kernel has not had a chance to reuse the memory for something else, most of the time. The current RW driver appears to have followed the design and development of the earlier read-only hfsplus driver [3], where-by version 0.1 (Dec 2001) had a B-tree node-centric approach to read_cache_page()/page_cache_release() per bnode_get()/bnode_put(), migrating towards version 0.2 (June 2002) of caching and releasing pages per inode extents. When the current RW code first entered the kernel [2] in 2005, there was an REF_PAGES conditional (and "//" commented out code) to switch between B-node centric paging to inode-centric paging. There was a mistake with the direction of one of the REF_PAGES conditionals in __hfs_bnode_create(). In a subsequent "remove debug code" commit [4], the read_cache_page()/page_cache_release() per bnode_get()/bnode_put() were removed, but a page_cache_release() was mistakenly left in (propagating the "REF_PAGES <-> !REF_PAGE" mistake), and the commented-out page_cache_release() in bnode_release() (which should be spanned by !REF_PAGES) was never enabled. References: [1]: Michael Fox, Apr 2013 http://www.spinics.net/lists/linux-fsdevel/msg63807.html ("hfsplus volume suddenly inaccessable after 'hfs: recoff %d too large'") Sasha Levin, Feb 2015 http://lkml.org/lkml/2015/2/20/85 ("use after free") https://bugs.launchpad.net/ubuntu/+source/linux/+bug/740814 https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1027887 https://bugzilla.kernel.org/show_bug.cgi?id=42342 https://bugzilla.kernel.org/show_bug.cgi?id=63841 https://bugzilla.kernel.org/show_bug.cgi?id=78761 [2]: http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/\ fs/hfs/bnode.c?id=d1081202f1d0ee35ab0beb490da4b65d4bc763db commit d1081202f1d0ee35ab0beb490da4b65d4bc763db Author: Andrew Morton Date: Wed Feb 25 16:17:36 2004 -0800 [PATCH] HFS rewrite http://git.kernel.org/cgit/linux/kernel/git/tglx/history.git/commit/\ fs/hfsplus/bnode.c?id=91556682e0bf004d98a529bf829d339abb98bbbd commit 91556682e0bf004d98a529bf829d339abb98bbbd Author: Andrew Morton Date: Wed Feb 25 16:17:48 2004 -0800 [PATCH] HFS+ support [3]: http://sourceforge.net/projects/linux-hfsplus/ http://sourceforge.net/projects/linux-hfsplus/files/Linux%202.4.x%20patch/hfsplus%200.1/ http://sourceforge.net/projects/linux-hfsplus/files/Linux%202.4.x%20patch/hfsplus%200.2/ http://linux-hfsplus.cvs.sourceforge.net/viewvc/linux-hfsplus/linux/\ fs/hfsplus/bnode.c?r1=1.4&r2=1.5 Date: Thu Jun 6 09:45:14 2002 +0000 Use buffer cache instead of page cache in bnode.c. Cache inode extents. [4]: http://git.kernel.org/cgit/linux/kernel/git/\ stable/linux-stable.git/commit/?id=a5e3985fa014029eb6795664c704953720cc7f7d commit a5e3985fa014029eb6795664c704953720cc7f7d Author: Roman Zippel Date: Tue Sep 6 15:18:47 2005 -0700 [PATCH] hfs: remove debug code Signed-off-by: Hin-Tak Leung Signed-off-by: Sergei Antonov Reviewed-by: Anton Altaparmakov Reported-by: Sasha Levin Cc: Al Viro Cc: Christoph Hellwig Cc: Vyacheslav Dubeyko Cc: Sougata Santra Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hfs/bnode.c | 9 ++++----- fs/hfsplus/bnode.c | 3 --- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/fs/hfs/bnode.c b/fs/hfs/bnode.c index d3fa6bd9503e7..221719eac5de6 100644 --- a/fs/hfs/bnode.c +++ b/fs/hfs/bnode.c @@ -288,7 +288,6 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) page_cache_release(page); goto fail; } - page_cache_release(page); node->page[i] = page; } @@ -398,11 +397,11 @@ node_error: void hfs_bnode_free(struct hfs_bnode *node) { - //int i; + int i; - //for (i = 0; i < node->tree->pages_per_bnode; i++) - // if (node->page[i]) - // page_cache_release(node->page[i]); + for (i = 0; i < node->tree->pages_per_bnode; i++) + if (node->page[i]) + page_cache_release(node->page[i]); kfree(node); } diff --git a/fs/hfsplus/bnode.c b/fs/hfsplus/bnode.c index 759708fd9331c..63924662aaf3e 100644 --- a/fs/hfsplus/bnode.c +++ b/fs/hfsplus/bnode.c @@ -454,7 +454,6 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid) page_cache_release(page); goto fail; } - page_cache_release(page); node->page[i] = page; } @@ -566,13 +565,11 @@ node_error: void hfs_bnode_free(struct hfs_bnode *node) { -#if 0 int i; for (i = 0; i < node->tree->pages_per_bnode; i++) if (node->page[i]) page_cache_release(node->page[i]); -#endif kfree(node); } -- GitLab From b4cc0efea4f0bfa2477c56af406cfcf3d3e58680 Mon Sep 17 00:00:00 2001 From: Hin-Tak Leung Date: Wed, 9 Sep 2015 15:38:07 -0700 Subject: [PATCH 6946/7006] hfs: fix B-tree corruption after insertion at position 0 Fix B-tree corruption when a new record is inserted at position 0 in the node in hfs_brec_insert(). This is an identical change to the corresponding hfs b-tree code to Sergei Antonov's "hfsplus: fix B-tree corruption after insertion at position 0", to keep similar code paths in the hfs and hfsplus drivers in sync, where appropriate. Signed-off-by: Hin-Tak Leung Cc: Sergei Antonov Cc: Joe Perches Reviewed-by: Vyacheslav Dubeyko Cc: Anton Altaparmakov Cc: Al Viro Cc: Christoph Hellwig Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/hfs/brec.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/fs/hfs/brec.c b/fs/hfs/brec.c index 9f4ee7f520261..6fc766df04617 100644 --- a/fs/hfs/brec.c +++ b/fs/hfs/brec.c @@ -131,13 +131,16 @@ skip: hfs_bnode_write(node, entry, data_off + key_len, entry_len); hfs_bnode_dump(node); - if (new_node) { - /* update parent key if we inserted a key - * at the start of the first node - */ - if (!rec && new_node != node) - hfs_brec_update_parent(fd); + /* + * update parent key if we inserted a key + * at the start of the node and it is not the new node + */ + if (!rec && new_node != node) { + hfs_bnode_read_key(node, fd->search_key, data_off + size); + hfs_brec_update_parent(fd); + } + if (new_node) { hfs_bnode_put(fd->bnode); if (!new_node->parent) { hfs_btree_inc_height(tree); @@ -166,9 +169,6 @@ skip: goto again; } - if (!rec) - hfs_brec_update_parent(fd); - return 0; } @@ -366,6 +366,8 @@ again: if (IS_ERR(parent)) return PTR_ERR(parent); __hfs_brec_find(parent, fd); + if (fd->record < 0) + return -ENOENT; hfs_bnode_dump(parent); rec = fd->record; -- GitLab From 60b61a6f42f36e4fbfbc0139b7e86ce1494d2d9b Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Wed, 9 Sep 2015 15:38:10 -0700 Subject: [PATCH 6947/7006] kmod: correct documentation of return status of request_module If request_module() successfully runs modprobe, but modprobe exits with a non-zero status, then the return value from request_module() will be that (positive) error status. So the return from request_module can be: negative errno zero for success positive exit code. Signed-off-by: NeilBrown Cc: Goldwyn Rodrigues Cc: Oleg Nesterov Cc: Tejun Heo Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kmod.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index 2777f40a9c7be..1734ba61ff239 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -114,10 +114,11 @@ out: * @...: arguments as specified in the format string * * Load a module using the user mode module loader. The function returns - * zero on success or a negative errno code on failure. Note that a - * successful module load does not mean the module did not then unload - * and exit on an error of its own. Callers must check that the service - * they requested is now available not blindly invoke it. + * zero on success or a negative errno code or positive exit code from + * "modprobe" on failure. Note that a successful module load does not mean + * the module did not then unload and exit on an error of its own. Callers + * must check that the service they requested is now available not blindly + * invoke it. * * If module auto-loading support is disabled then this function * becomes a no-operation. -- GitLab From b6b50a814d0ece9c1f98f2b3b5c2a251a5c9a211 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 9 Sep 2015 15:38:13 -0700 Subject: [PATCH 6948/7006] kmod: bunch of internal functions renames This patchset does a bunch of cleanups and converts khelper to use system unbound workqueues. The 3 first patches should be uncontroversial. The last 2 patches are debatable. Kmod creates kernel threads that perform userspace jobs and we want those to have a large affinity in order not to contend busy CPUs. This is (partly) why we use khelper which has a wide affinity that the kernel threads it create can inherit from. Now khelper is a dedicated workqueue that has singlethread properties which we aren't interested in. Hence those two debatable changes: _ We would like to use generic workqueues. System unbound workqueues are a very good candidate but they are not wide affine, only node affine. Now probably a node is enough to perform many parallel kmod jobs. _ We would like to remove the wait_for_helper kernel thread (UMH_WAIT_PROC handler) to use the workqueue. It means that if the workqueue blocks, and no other worker can take pending kmod request, we can be screwed. Now if we have 512 threads, this should be enough. This patch (of 5): Underscores on function names aren't much verbose to explain the purpose of a function. And kmod has interesting such flavours. Lets rename the following functions: * __call_usermodehelper -> call_usermodehelper_exec_work * ____call_usermodehelper -> call_usermodehelper_exec_async * wait_for_helper -> call_usermodehelper_exec_sync Signed-off-by: Frederic Weisbecker Cc: Rik van Riel Reviewed-by: Oleg Nesterov Cc: Christoph Lameter Cc: Tejun Heo Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kmod.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index 1734ba61ff239..2d83511e96108 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -214,7 +214,7 @@ static void umh_complete(struct subprocess_info *sub_info) /* * This is the task which runs the usermode application */ -static int ____call_usermodehelper(void *data) +static int call_usermodehelper_exec_async(void *data) { struct subprocess_info *sub_info = data; struct cred *new; @@ -259,7 +259,10 @@ static int ____call_usermodehelper(void *data) (const char __user *const __user *)sub_info->envp); out: sub_info->retval = retval; - /* wait_for_helper() will call umh_complete if UHM_WAIT_PROC. */ + /* + * call_usermodehelper_exec_sync() will call umh_complete + * if UHM_WAIT_PROC. + */ if (!(sub_info->wait & UMH_WAIT_PROC)) umh_complete(sub_info); if (!retval) @@ -268,14 +271,14 @@ out: } /* Keventd can't block, but this (a child) can. */ -static int wait_for_helper(void *data) +static int call_usermodehelper_exec_sync(void *data) { struct subprocess_info *sub_info = data; pid_t pid; /* If SIGCLD is ignored sys_wait4 won't populate the status. */ kernel_sigaction(SIGCHLD, SIG_DFL); - pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD); + pid = kernel_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD); if (pid < 0) { sub_info->retval = pid; } else { @@ -283,17 +286,18 @@ static int wait_for_helper(void *data) /* * Normally it is bogus to call wait4() from in-kernel because * wait4() wants to write the exit code to a userspace address. - * But wait_for_helper() always runs as keventd, and put_user() - * to a kernel address works OK for kernel threads, due to their - * having an mm_segment_t which spans the entire address space. + * But call_usermodehelper_exec_sync() always runs as keventd, + * and put_user() to a kernel address works OK for kernel + * threads, due to their having an mm_segment_t which spans the + * entire address space. * * Thus the __user pointer cast is valid here. */ sys_wait4(pid, (int __user *)&ret, 0, NULL); /* - * If ret is 0, either ____call_usermodehelper failed and the - * real error code is already in sub_info->retval or + * If ret is 0, either call_usermodehelper_exec_async failed and + * the real error code is already in sub_info->retval or * sub_info->retval is 0 anyway, so don't mess with it then. */ if (ret) @@ -305,17 +309,17 @@ static int wait_for_helper(void *data) } /* This is run by khelper thread */ -static void __call_usermodehelper(struct work_struct *work) +static void call_usermodehelper_exec_work(struct work_struct *work) { struct subprocess_info *sub_info = container_of(work, struct subprocess_info, work); pid_t pid; if (sub_info->wait & UMH_WAIT_PROC) - pid = kernel_thread(wait_for_helper, sub_info, + pid = kernel_thread(call_usermodehelper_exec_sync, sub_info, CLONE_FS | CLONE_FILES | SIGCHLD); else - pid = kernel_thread(____call_usermodehelper, sub_info, + pid = kernel_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD); if (pid < 0) { @@ -510,7 +514,7 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, if (!sub_info) goto out; - INIT_WORK(&sub_info->work, __call_usermodehelper); + INIT_WORK(&sub_info->work, call_usermodehelper_exec_work); sub_info->path = path; sub_info->argv = argv; sub_info->envp = envp; -- GitLab From d097c0240ae8085dd39aa6ca9bd9960969b2b38e Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 9 Sep 2015 15:38:16 -0700 Subject: [PATCH 6949/7006] kmod: remove unecessary explicit wide CPU affinity setting Khelper is affine to all CPUs. Now since it creates the call_usermodehelper_exec_[a]sync() kernel threads, those inherit the wide affinity. As such explicitly forcing a wide affinity from those kernel threads is like a no-op. Just remove it. It's needless and it breaks CPU isolation users who rely on workqueue affinity tuning. Signed-off-by: Frederic Weisbecker Cc: Rik van Riel Reviewed-by: Oleg Nesterov Cc: Christoph Lameter Cc: Tejun Heo Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kmod.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index 2d83511e96108..d910b6378fb6b 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -224,9 +224,6 @@ static int call_usermodehelper_exec_async(void *data) flush_signal_handlers(current, 1); spin_unlock_irq(¤t->sighand->siglock); - /* We can run anywhere, unlike our parent keventd(). */ - set_cpus_allowed_ptr(current, cpu_all_mask); - /* * Our parent is keventd, which runs with elevated scheduling priority. * Avoid propagating that into the userspace child. -- GitLab From b639e86bae431db3fbc9fae8d09a9bbf97b74711 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 9 Sep 2015 15:38:19 -0700 Subject: [PATCH 6950/7006] kmod: add up-to-date explanations on the purpose of each asynchronous levels There seem to be quite some confusions on the comments, likely due to changes that came after them. Now since it's very non obvious why we have 3 levels of asynchronous code to implement usermodehelpers, it's important to comment in detail the reason of this layout. Signed-off-by: Frederic Weisbecker Cc: Rik van Riel Reviewed-by: Oleg Nesterov Cc: Christoph Lameter Cc: Tejun Heo Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kmod.c | 32 ++++++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index d910b6378fb6b..81c67050c5aae 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -225,8 +225,8 @@ static int call_usermodehelper_exec_async(void *data) spin_unlock_irq(¤t->sighand->siglock); /* - * Our parent is keventd, which runs with elevated scheduling priority. - * Avoid propagating that into the userspace child. + * Our parent is khelper which runs with elevated scheduling + * priority. Avoid propagating that into the userspace child. */ set_user_nice(current, 0); @@ -267,7 +267,11 @@ out: do_exit(0); } -/* Keventd can't block, but this (a child) can. */ +/* + * Handles UMH_WAIT_PROC. Our parent khelper can't wait for usermodehelper + * completion without blocking every other pending requests. That's why + * we use a kernel thread dedicated for that purpose. + */ static int call_usermodehelper_exec_sync(void *data) { struct subprocess_info *sub_info = data; @@ -283,8 +287,8 @@ static int call_usermodehelper_exec_sync(void *data) /* * Normally it is bogus to call wait4() from in-kernel because * wait4() wants to write the exit code to a userspace address. - * But call_usermodehelper_exec_sync() always runs as keventd, - * and put_user() to a kernel address works OK for kernel + * But call_usermodehelper_exec_sync() always runs as kernel + * thread and put_user() to a kernel address works OK for kernel * threads, due to their having an mm_segment_t which spans the * entire address space. * @@ -305,7 +309,19 @@ static int call_usermodehelper_exec_sync(void *data) do_exit(0); } -/* This is run by khelper thread */ +/* + * This function doesn't strictly needs to be called asynchronously. But we + * need to create the usermodehelper kernel threads from a task that is affine + * to all CPUs (or nohz housekeeping ones) such that they inherit a widest + * affinity irrespective of call_usermodehelper() callers with possibly reduced + * affinity (eg: per-cpu workqueues). We don't want usermodehelper targets to + * contend any busy CPU. + * Khelper provides such wide affinity. + * + * Besides, khelper provides the privilege level that caller might not have to + * perform the usermodehelper request. + * + */ static void call_usermodehelper_exec_work(struct work_struct *work) { struct subprocess_info *sub_info = @@ -533,8 +549,8 @@ EXPORT_SYMBOL(call_usermodehelper_setup); * from interrupt context. * * Runs a user-space application. The application is started - * asynchronously if wait is not set, and runs as a child of keventd. - * (ie. it runs with full root capabilities). + * asynchronously if wait is not set, and runs as a child of khelper. + * (ie. it runs with full root capabilities and wide affinity). */ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) { -- GitLab From 90f023030e26ce8f981b3e688cb79329d8d07cc3 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 9 Sep 2015 15:38:22 -0700 Subject: [PATCH 6951/7006] kmod: use system_unbound_wq instead of khelper We need to launch the usermodehelper kernel threads with the widest affinity and this is partly why we use khelper. This workqueue has unbound properties and thus a wide affinity inherited by all its children. Now khelper also has special properties that we aren't much interested in: ordered and singlethread. There is really no need about ordering as all we do is creating kernel threads. This can be done concurrently. And singlethread is a useless limitation as well. The workqueue engine already proposes generic unbound workqueues that don't share these useless properties and handle well parallel jobs. The only worrysome specific is their affinity to the node of the current CPU. It's fine for creating the usermodehelper kernel threads but those inherit this affinity for longer jobs such as requesting modules. This patch proposes to use these node affine unbound workqueues assuming that a node is sufficient to handle several parallel usermodehelper requests. Signed-off-by: Frederic Weisbecker Cc: Rik van Riel Reviewed-by: Oleg Nesterov Cc: Christoph Lameter Cc: Tejun Heo Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kmod.h | 2 -- init/main.c | 1 - kernel/kmod.c | 40 +++++++++++++++++----------------------- 3 files changed, 17 insertions(+), 26 deletions(-) diff --git a/include/linux/kmod.h b/include/linux/kmod.h index 0555cc66a15b2..fcfd2bf14d3f0 100644 --- a/include/linux/kmod.h +++ b/include/linux/kmod.h @@ -85,8 +85,6 @@ enum umh_disable_depth { UMH_DISABLED, }; -extern void usermodehelper_init(void); - extern int __usermodehelper_disable(enum umh_disable_depth depth); extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth); diff --git a/init/main.c b/init/main.c index 56506553d4d80..9e64d7097f1ad 100644 --- a/init/main.c +++ b/init/main.c @@ -877,7 +877,6 @@ static void __init do_initcalls(void) static void __init do_basic_setup(void) { cpuset_init_smp(); - usermodehelper_init(); shmem_init(); driver_init(); init_irq_proc(); diff --git a/kernel/kmod.c b/kernel/kmod.c index 81c67050c5aae..d38b2dab99a7f 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -45,8 +45,6 @@ extern int max_threads; -static struct workqueue_struct *khelper_wq; - #define CAP_BSET (void *)1 #define CAP_PI (void *)2 @@ -225,7 +223,7 @@ static int call_usermodehelper_exec_async(void *data) spin_unlock_irq(¤t->sighand->siglock); /* - * Our parent is khelper which runs with elevated scheduling + * Our parent (unbound workqueue) runs with elevated scheduling * priority. Avoid propagating that into the userspace child. */ set_user_nice(current, 0); @@ -268,9 +266,10 @@ out: } /* - * Handles UMH_WAIT_PROC. Our parent khelper can't wait for usermodehelper - * completion without blocking every other pending requests. That's why - * we use a kernel thread dedicated for that purpose. + * Handles UMH_WAIT_PROC. Our parent (unbound workqueue) might not be able to + * run enough instances to handle usermodehelper completions without blocking + * some other pending requests. That's why we use a kernel thread dedicated for + * that purpose. */ static int call_usermodehelper_exec_sync(void *data) { @@ -312,14 +311,15 @@ static int call_usermodehelper_exec_sync(void *data) /* * This function doesn't strictly needs to be called asynchronously. But we * need to create the usermodehelper kernel threads from a task that is affine - * to all CPUs (or nohz housekeeping ones) such that they inherit a widest - * affinity irrespective of call_usermodehelper() callers with possibly reduced - * affinity (eg: per-cpu workqueues). We don't want usermodehelper targets to - * contend any busy CPU. - * Khelper provides such wide affinity. + * to an optimized set of CPUs (or nohz housekeeping ones) such that they + * inherit a widest affinity irrespective of call_usermodehelper() callers with + * possibly reduced affinity (eg: per-cpu workqueues). We don't want + * usermodehelper targets to contend a busy CPU. + * + * Unbound workqueues provide such wide affinity. * - * Besides, khelper provides the privilege level that caller might not have to - * perform the usermodehelper request. + * Besides, workqueues provide the privilege level that caller might not have + * to perform the usermodehelper request. * */ static void call_usermodehelper_exec_work(struct work_struct *work) @@ -549,8 +549,8 @@ EXPORT_SYMBOL(call_usermodehelper_setup); * from interrupt context. * * Runs a user-space application. The application is started - * asynchronously if wait is not set, and runs as a child of khelper. - * (ie. it runs with full root capabilities and wide affinity). + * asynchronously if wait is not set, and runs as a child of system workqueues. + * (ie. it runs with full root capabilities and optimized affinity). */ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) { @@ -562,7 +562,7 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) return -EINVAL; } helper_lock(); - if (!khelper_wq || usermodehelper_disabled) { + if (usermodehelper_disabled) { retval = -EBUSY; goto out; } @@ -574,7 +574,7 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done; sub_info->wait = wait; - queue_work(khelper_wq, &sub_info->work); + queue_work(system_unbound_wq, &sub_info->work); if (wait == UMH_NO_WAIT) /* task has freed sub_info */ goto unlock; @@ -704,9 +704,3 @@ struct ctl_table usermodehelper_table[] = { }, { } }; - -void __init usermodehelper_init(void) -{ - khelper_wq = create_singlethread_workqueue("khelper"); - BUG_ON(!khelper_wq); -} -- GitLab From bb304a5c6fc63d8506cd9741a3a5f35b73605625 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Wed, 9 Sep 2015 15:38:25 -0700 Subject: [PATCH 6952/7006] kmod: handle UMH_WAIT_PROC from system unbound workqueue The UMH_WAIT_PROC handler runs in its own thread in order to make sure that waiting for the exec kernel thread completion won't block other usermodehelper queued jobs. On older workqueue implementations, worklets couldn't sleep without blocking the rest of the queue. But now the workqueue subsystem handles that. Khelper still had the older limitation due to its singlethread properties but we replaced it to system unbound workqueues. Those are affine to the current node and can block up to some number of instances. They are a good candidate to handle UMH_WAIT_PROC assuming that we have enough system unbound workers to handle lots of parallel usermodehelper jobs. Signed-off-by: Frederic Weisbecker Cc: Rik van Riel Reviewed-by: Oleg Nesterov Cc: Christoph Lameter Cc: Tejun Heo Cc: Rusty Russell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kmod.c | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/kernel/kmod.c b/kernel/kmod.c index d38b2dab99a7f..da98d0593de24 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c @@ -265,15 +265,9 @@ out: do_exit(0); } -/* - * Handles UMH_WAIT_PROC. Our parent (unbound workqueue) might not be able to - * run enough instances to handle usermodehelper completions without blocking - * some other pending requests. That's why we use a kernel thread dedicated for - * that purpose. - */ -static int call_usermodehelper_exec_sync(void *data) +/* Handles UMH_WAIT_PROC. */ +static void call_usermodehelper_exec_sync(struct subprocess_info *sub_info) { - struct subprocess_info *sub_info = data; pid_t pid; /* If SIGCLD is ignored sys_wait4 won't populate the status. */ @@ -287,9 +281,9 @@ static int call_usermodehelper_exec_sync(void *data) * Normally it is bogus to call wait4() from in-kernel because * wait4() wants to write the exit code to a userspace address. * But call_usermodehelper_exec_sync() always runs as kernel - * thread and put_user() to a kernel address works OK for kernel - * threads, due to their having an mm_segment_t which spans the - * entire address space. + * thread (workqueue) and put_user() to a kernel address works + * OK for kernel threads, due to their having an mm_segment_t + * which spans the entire address space. * * Thus the __user pointer cast is valid here. */ @@ -304,19 +298,21 @@ static int call_usermodehelper_exec_sync(void *data) sub_info->retval = ret; } + /* Restore default kernel sig handler */ + kernel_sigaction(SIGCHLD, SIG_IGN); + umh_complete(sub_info); - do_exit(0); } /* - * This function doesn't strictly needs to be called asynchronously. But we - * need to create the usermodehelper kernel threads from a task that is affine + * We need to create the usermodehelper kernel thread from a task that is affine * to an optimized set of CPUs (or nohz housekeeping ones) such that they * inherit a widest affinity irrespective of call_usermodehelper() callers with * possibly reduced affinity (eg: per-cpu workqueues). We don't want * usermodehelper targets to contend a busy CPU. * - * Unbound workqueues provide such wide affinity. + * Unbound workqueues provide such wide affinity and allow to block on + * UMH_WAIT_PROC requests without blocking pending request (up to some limit). * * Besides, workqueues provide the privilege level that caller might not have * to perform the usermodehelper request. @@ -326,18 +322,18 @@ static void call_usermodehelper_exec_work(struct work_struct *work) { struct subprocess_info *sub_info = container_of(work, struct subprocess_info, work); - pid_t pid; - if (sub_info->wait & UMH_WAIT_PROC) - pid = kernel_thread(call_usermodehelper_exec_sync, sub_info, - CLONE_FS | CLONE_FILES | SIGCHLD); - else + if (sub_info->wait & UMH_WAIT_PROC) { + call_usermodehelper_exec_sync(sub_info); + } else { + pid_t pid; + pid = kernel_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD); - - if (pid < 0) { - sub_info->retval = pid; - umh_complete(sub_info); + if (pid < 0) { + sub_info->retval = pid; + umh_complete(sub_info); + } } } -- GitLab From fbb1816942c04429e85dbf4c1a080accc534299e Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Wed, 9 Sep 2015 15:38:28 -0700 Subject: [PATCH 6953/7006] fs: if a coredump already exists, unlink and recreate with O_EXCL It was possible for an attacking user to trick root (or another user) into writing his coredumps into an attacker-readable, pre-existing file using rename() or link(), causing the disclosure of secret data from the victim process' virtual memory. Depending on the configuration, it was also possible to trick root into overwriting system files with coredumps. Fix that issue by never writing coredumps into existing files. Requirements for the attack: - The attack only applies if the victim's process has a nonzero RLIMIT_CORE and is dumpable. - The attacker can trick the victim into coredumping into an attacker-writable directory D, either because the core_pattern is relative and the victim's cwd is attacker-writable or because an absolute core_pattern pointing to a world-writable directory is used. - The attacker has one of these: A: on a system with protected_hardlinks=0: execute access to a folder containing a victim-owned, attacker-readable file on the same partition as D, and the victim-owned file will be deleted before the main part of the attack takes place. (In practice, there are lots of files that fulfill this condition, e.g. entries in Debian's /var/lib/dpkg/info/.) This does not apply to most Linux systems because most distros set protected_hardlinks=1. B: on a system with protected_hardlinks=1: execute access to a folder containing a victim-owned, attacker-readable and attacker-writable file on the same partition as D, and the victim-owned file will be deleted before the main part of the attack takes place. (This seems to be uncommon.) C: on any system, independent of protected_hardlinks: write access to a non-sticky folder containing a victim-owned, attacker-readable file on the same partition as D (This seems to be uncommon.) The basic idea is that the attacker moves the victim-owned file to where he expects the victim process to dump its core. The victim process dumps its core into the existing file, and the attacker reads the coredump from it. If the attacker can't move the file because he does not have write access to the containing directory, he can instead link the file to a directory he controls, then wait for the original link to the file to be deleted (because the kernel checks that the link count of the corefile is 1). A less reliable variant that requires D to be non-sticky works with link() and does not require deletion of the original link: link() the file into D, but then unlink() it directly before the kernel performs the link count check. On systems with protected_hardlinks=0, this variant allows an attacker to not only gain information from coredumps, but also clobber existing, victim-writable files with coredumps. (This could theoretically lead to a privilege escalation.) Signed-off-by: Jann Horn Cc: Kees Cook Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/coredump.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index c5ecde6f3eed9..b696dc2c220d1 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -513,10 +513,10 @@ void do_coredump(const siginfo_t *siginfo) const struct cred *old_cred; struct cred *cred; int retval = 0; - int flag = 0; int ispipe; struct files_struct *displaced; - bool need_nonrelative = false; + /* require nonrelative corefile path and be extra careful */ + bool need_suid_safe = false; bool core_dumped = false; static atomic_t core_dump_count = ATOMIC_INIT(0); struct coredump_params cprm = { @@ -550,9 +550,8 @@ void do_coredump(const siginfo_t *siginfo) */ if (__get_dumpable(cprm.mm_flags) == SUID_DUMP_ROOT) { /* Setuid core dump mode */ - flag = O_EXCL; /* Stop rewrite attacks */ cred->fsuid = GLOBAL_ROOT_UID; /* Dump root private */ - need_nonrelative = true; + need_suid_safe = true; } retval = coredump_wait(siginfo->si_signo, &core_state); @@ -633,7 +632,7 @@ void do_coredump(const siginfo_t *siginfo) if (cprm.limit < binfmt->min_coredump) goto fail_unlock; - if (need_nonrelative && cn.corename[0] != '/') { + if (need_suid_safe && cn.corename[0] != '/') { printk(KERN_WARNING "Pid %d(%s) can only dump core "\ "to fully qualified path!\n", task_tgid_vnr(current), current->comm); @@ -641,8 +640,35 @@ void do_coredump(const siginfo_t *siginfo) goto fail_unlock; } + /* + * Unlink the file if it exists unless this is a SUID + * binary - in that case, we're running around with root + * privs and don't want to unlink another user's coredump. + */ + if (!need_suid_safe) { + mm_segment_t old_fs; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + /* + * If it doesn't exist, that's fine. If there's some + * other problem, we'll catch it at the filp_open(). + */ + (void) sys_unlink((const char __user *)cn.corename); + set_fs(old_fs); + } + + /* + * There is a race between unlinking and creating the + * file, but if that causes an EEXIST here, that's + * fine - another process raced with us while creating + * the corefile, and the other process won. To userspace, + * what matters is that at least one of the two processes + * writes its coredump successfully, not which one. + */ cprm.file = filp_open(cn.corename, - O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, + O_CREAT | 2 | O_NOFOLLOW | + O_LARGEFILE | O_EXCL, 0600); if (IS_ERR(cprm.file)) goto fail_unlock; -- GitLab From 40f705a736eac10e7dca7ab5dd5ed675a6df031d Mon Sep 17 00:00:00 2001 From: Jann Horn Date: Wed, 9 Sep 2015 15:38:30 -0700 Subject: [PATCH 6954/7006] fs: Don't dump core if the corefile would become world-readable. On a filesystem like vfat, all files are created with the same owner and mode independent of who created the file. When a vfat filesystem is mounted with root as owner of all files and read access for everyone, root's processes left world-readable coredumps on it (but other users' processes only left empty corefiles when given write access because of the uid mismatch). Given that the old behavior was inconsistent and insecure, I don't see a problem with changing it. Now, all processes refuse to dump core unless the resulting corefile will only be readable by their owner. Signed-off-by: Jann Horn Acked-by: Kees Cook Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/coredump.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index b696dc2c220d1..a8f75640ac86e 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -685,11 +685,15 @@ void do_coredump(const siginfo_t *siginfo) if (!S_ISREG(inode->i_mode)) goto close_fail; /* - * Dont allow local users get cute and trick others to coredump - * into their pre-created files. + * Don't dump core if the filesystem changed owner or mode + * of the file during file creation. This is an issue when + * a process dumps core while its cwd is e.g. on a vfat + * filesystem. */ if (!uid_eq(inode->i_uid, current_fsuid())) goto close_fail; + if ((inode->i_mode & 0677) != 0600) + goto close_fail; if (!(cprm.file->f_mode & FMODE_CAN_WRITE)) goto close_fail; if (do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file)) -- GitLab From 37607102c4426cf92aeb5da1b1d9a79ba6d95e3f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:33 -0700 Subject: [PATCH 6955/7006] seq_file: provide an analogue of print_hex_dump() This introduces a new helper and switches current users to use it. All patches are compiled tested. kmemleak is tested via its own test suite. This patch (of 6): The new seq_hex_dump() is a complete analogue of print_hex_dump(). We have few users of this functionality already. It allows to reduce their codebase. Signed-off-by: Andy Shevchenko Cc: Alexander Viro Cc: Joe Perches Cc: Tadeusz Struk Cc: Helge Deller Cc: Ingo Tuchscherer Cc: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/seq_file.c | 42 ++++++++++++++++++++++++++++++++++++++++ include/linux/seq_file.h | 4 ++++ 2 files changed, 46 insertions(+) diff --git a/fs/seq_file.c b/fs/seq_file.c index ce9e39fd5dafc..263b125dbcf4d 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -773,6 +774,47 @@ void seq_pad(struct seq_file *m, char c) } EXPORT_SYMBOL(seq_pad); +/* A complete analogue of print_hex_dump() */ +void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, + int rowsize, int groupsize, const void *buf, size_t len, + bool ascii) +{ + const u8 *ptr = buf; + int i, linelen, remaining = len; + int ret; + + if (rowsize != 16 && rowsize != 32) + rowsize = 16; + + for (i = 0; i < len && !seq_has_overflowed(m); i += rowsize) { + linelen = min(remaining, rowsize); + remaining -= rowsize; + + switch (prefix_type) { + case DUMP_PREFIX_ADDRESS: + seq_printf(m, "%s%p: ", prefix_str, ptr + i); + break; + case DUMP_PREFIX_OFFSET: + seq_printf(m, "%s%.8x: ", prefix_str, i); + break; + default: + seq_printf(m, "%s", prefix_str); + break; + } + + ret = hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, + m->buf + m->count, m->size - m->count, + ascii); + if (ret >= m->size - m->count) { + seq_set_overflow(m); + } else { + m->count += ret; + seq_putc(m, '\n'); + } + } +} +EXPORT_SYMBOL(seq_hex_dump); + struct list_head *seq_list_start(struct list_head *head, loff_t pos) { struct list_head *lh; diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index d4c7271382cb3..adeadbd6d7bfa 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -122,6 +122,10 @@ int seq_write(struct seq_file *seq, const void *data, size_t len); __printf(2, 3) int seq_printf(struct seq_file *, const char *, ...); __printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args); +void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, + int rowsize, int groupsize, const void *buf, size_t len, + bool ascii); + int seq_path(struct seq_file *, const struct path *, const char *); int seq_file_path(struct seq_file *, struct file *, const char *); int seq_dentry(struct seq_file *, struct dentry *, const char *); -- GitLab From d0cce062217fedb448cf7f36e0b82a80ac9e1243 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:36 -0700 Subject: [PATCH 6956/7006] drivers/crypto/qat: use seq_hex_dump() to dump buffers Instead of custom approach let's use recently introduced seq_hex_dump() helper. Signed-off-by: Andy Shevchenko Acked-by: Tadeusz Struk Cc: Alexander Viro Cc: Joe Perches Cc: Helge Deller Cc: Ingo Tuchscherer Cc: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../crypto/qat/qat_common/adf_transport_debug.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/drivers/crypto/qat/qat_common/adf_transport_debug.c b/drivers/crypto/qat/qat_common/adf_transport_debug.c index e419869672941..52340b9bb3873 100644 --- a/drivers/crypto/qat/qat_common/adf_transport_debug.c +++ b/drivers/crypto/qat/qat_common/adf_transport_debug.c @@ -86,9 +86,7 @@ static int adf_ring_show(struct seq_file *sfile, void *v) { struct adf_etr_ring_data *ring = sfile->private; struct adf_etr_bank_data *bank = ring->bank; - uint32_t *msg = v; void __iomem *csr = ring->bank->csr_addr; - int i, x; if (v == SEQ_START_TOKEN) { int head, tail, empty; @@ -113,18 +111,8 @@ static int adf_ring_show(struct seq_file *sfile, void *v) seq_puts(sfile, "----------- Ring data ------------\n"); return 0; } - seq_printf(sfile, "%p:", msg); - x = 0; - i = 0; - for (; i < (ADF_MSG_SIZE_TO_BYTES(ring->msg_size) >> 2); i++) { - seq_printf(sfile, " %08X", *(msg + i)); - if ((ADF_MSG_SIZE_TO_BYTES(ring->msg_size) >> 2) != i + 1 && - (++x == 8)) { - seq_printf(sfile, "\n%p:", msg + i + 1); - x = 0; - } - } - seq_puts(sfile, "\n"); + seq_hex_dump(sfile, "", DUMP_PREFIX_ADDRESS, 32, 4, + v, ADF_MSG_SIZE_TO_BYTES(ring->msg_size), false); return 0; } -- GitLab From b342a65dd71c02f606dfea51e99773c333a2439d Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:39 -0700 Subject: [PATCH 6957/7006] parisc: use seq_hex_dump() to dump buffers Instead of custom approach let's use recently introduced seq_hex_dump() helper. In one case it changes the output from 1111111122222222333333334444444455555555666666667777777788888888 to 11111111 22222222 33333333 44444444 55555555 66666666 77777777 88888888 though it seems it prints same data (by meaning) in both cases. I decide to choose to use the space divided one. Signed-off-by: Andy Shevchenko Acked-by: Helge Deller Cc: Alexander Viro Cc: Joe Perches Cc: Tadeusz Struk Cc: Ingo Tuchscherer Cc: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/parisc/ccio-dma.c | 13 +++---------- drivers/parisc/sba_iommu.c | 9 ++------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 02ff84fcfa612..957b42198328f 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -1103,16 +1103,9 @@ static int ccio_proc_bitmap_info(struct seq_file *m, void *p) struct ioc *ioc = ioc_list; while (ioc != NULL) { - u32 *res_ptr = (u32 *)ioc->res_map; - int j; - - for (j = 0; j < (ioc->res_size / sizeof(u32)); j++) { - if ((j & 7) == 0) - seq_puts(m, "\n "); - seq_printf(m, "%08x", *res_ptr); - res_ptr++; - } - seq_puts(m, "\n\n"); + seq_hex_dump(m, " ", DUMP_PREFIX_NONE, 32, 4, ioc->res_map, + ioc->res_size, false); + seq_putc(m, '\n'); ioc = ioc->next; break; /* XXX - remove me */ } diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c index f1441e466c06c..225049b492e53 100644 --- a/drivers/parisc/sba_iommu.c +++ b/drivers/parisc/sba_iommu.c @@ -1854,14 +1854,9 @@ sba_proc_bitmap_info(struct seq_file *m, void *p) { struct sba_device *sba_dev = sba_list; struct ioc *ioc = &sba_dev->ioc[0]; /* FIXME: Multi-IOC support! */ - unsigned int *res_ptr = (unsigned int *)ioc->res_map; - int i; - for (i = 0; i < (ioc->res_size/sizeof(unsigned int)); ++i, ++res_ptr) { - if ((i & 7) == 0) - seq_puts(m, "\n "); - seq_printf(m, " %08x", *res_ptr); - } + seq_hex_dump(m, " ", DUMP_PREFIX_NONE, 32, 4, ioc->res_map, + ioc->res_size, false); seq_putc(m, '\n'); return 0; -- GitLab From 5d2fe875c9e822aa55579ea2032153e2891db57a Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:42 -0700 Subject: [PATCH 6958/7006] drivers/s390/crypto/zcrypt_api.c: use seq_hex_dump() to dump buffers Instead of custom approach let's use recently introduced seq_hex_dump() helper. Signed-off-by: Andy Shevchenko Acked-by: Ingo Tuchscherer Cc: Alexander Viro Cc: Joe Perches Cc: Tadeusz Struk Cc: Helge Deller Cc: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/s390/crypto/zcrypt_api.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 01bf1f5cf2e95..4eb45546a3aaf 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -1206,16 +1206,8 @@ static void sprinthx(unsigned char *title, struct seq_file *m, static void sprinthx4(unsigned char *title, struct seq_file *m, unsigned int *array, unsigned int len) { - int r; - seq_printf(m, "\n%s\n", title); - for (r = 0; r < len; r++) { - if ((r % 8) == 0) - seq_printf(m, " "); - seq_printf(m, "%08X ", array[r]); - if ((r % 8) == 7) - seq_putc(m, '\n'); - } + seq_hex_dump(m, " ", DUMP_PREFIX_NONE, 32, 4, array, len, false); seq_putc(m, '\n'); } -- GitLab From 6fc37c4900765d579f25fbd293fcda7be5037896 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:45 -0700 Subject: [PATCH 6959/7006] kmemleak: use seq_hex_dump() to dump buffers Instead of custom approach let's use recently introduced seq_hex_dump() helper. Signed-off-by: Andy Shevchenko Cc: Alexander Viro Cc: Joe Perches Cc: Tadeusz Struk Cc: Helge Deller Cc: Ingo Tuchscherer Acked-by: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/kmemleak.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/mm/kmemleak.c b/mm/kmemleak.c index f532f6a37b553..77191eccdc6f6 100644 --- a/mm/kmemleak.c +++ b/mm/kmemleak.c @@ -302,23 +302,14 @@ static void hex_dump_object(struct seq_file *seq, struct kmemleak_object *object) { const u8 *ptr = (const u8 *)object->pointer; - int i, len, remaining; - unsigned char linebuf[HEX_ROW_SIZE * 5]; + size_t len; /* limit the number of lines to HEX_MAX_LINES */ - remaining = len = - min(object->size, (size_t)(HEX_MAX_LINES * HEX_ROW_SIZE)); - - seq_printf(seq, " hex dump (first %d bytes):\n", len); - for (i = 0; i < len; i += HEX_ROW_SIZE) { - int linelen = min(remaining, HEX_ROW_SIZE); - - remaining -= HEX_ROW_SIZE; - hex_dump_to_buffer(ptr + i, linelen, HEX_ROW_SIZE, - HEX_GROUP_SIZE, linebuf, sizeof(linebuf), - HEX_ASCII); - seq_printf(seq, " %s\n", linebuf); - } + len = min_t(size_t, object->size, HEX_MAX_LINES * HEX_ROW_SIZE); + + seq_printf(seq, " hex dump (first %zu bytes):\n", len); + seq_hex_dump(seq, " ", DUMP_PREFIX_NONE, HEX_ROW_SIZE, + HEX_GROUP_SIZE, ptr, len, HEX_ASCII); } /* -- GitLab From a202fbbf56e819de83876827c4bf5da2bfbac5ec Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 9 Sep 2015 15:38:48 -0700 Subject: [PATCH 6960/7006] drivers/net/wireless/ath/wil6210: use seq_hex_dump() to dump buffers Instead of custom approach let's use recently introduced seq_hex_dump() helper. Signed-off-by: Andy Shevchenko Cc: Alexander Viro Cc: Joe Perches Cc: Tadeusz Struk Cc: Helge Deller Cc: Ingo Tuchscherer Cc: Catalin Marinas Cc: Vladimir Kondratiev Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/wireless/ath/wil6210/debugfs.c | 35 +++++----------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 613ca2b2527be..d1a1e160ef311 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -156,6 +156,12 @@ static const struct file_operations fops_vring = { .llseek = seq_lseek, }; +static void wil_seq_hexdump(struct seq_file *s, void *p, int len, + const char *prefix) +{ + seq_hex_dump(s, prefix, DUMP_PREFIX_NONE, 16, 1, p, len, false); +} + static void wil_print_ring(struct seq_file *s, const char *prefix, void __iomem *off) { @@ -212,8 +218,6 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, le16_to_cpu(hdr.seq), len, le16_to_cpu(hdr.type), hdr.flags); if (len <= MAX_MBOXITEM_SIZE) { - int n = 0; - char printbuf[16 * 3 + 2]; unsigned char databuf[MAX_MBOXITEM_SIZE]; void __iomem *src = wmi_buffer(wil, d.addr) + sizeof(struct wil6210_mbox_hdr); @@ -223,16 +227,7 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, * reading header */ wil_memcpy_fromio_32(databuf, src, len); - while (n < len) { - int l = min(len - n, 16); - - hex_dump_to_buffer(databuf + n, l, - 16, 1, printbuf, - sizeof(printbuf), - false); - seq_printf(s, " : %s\n", printbuf); - n += l; - } + wil_seq_hexdump(s, databuf, len, " : "); } } else { seq_puts(s, "\n"); @@ -867,22 +862,6 @@ static const struct file_operations fops_wmi = { .open = simple_open, }; -static void wil_seq_hexdump(struct seq_file *s, void *p, int len, - const char *prefix) -{ - char printbuf[16 * 3 + 2]; - int i = 0; - - while (i < len) { - int l = min(len - i, 16); - - hex_dump_to_buffer(p + i, l, 16, 1, printbuf, - sizeof(printbuf), false); - seq_printf(s, "%s%s\n", prefix, printbuf); - i += l; - } -} - static void wil_seq_print_skb(struct seq_file *s, struct sk_buff *skb) { int i = 0; -- GitLab From a43cac0d9dc2073ff2245a171429ddbe1accece7 Mon Sep 17 00:00:00 2001 From: Dave Young Date: Wed, 9 Sep 2015 15:38:51 -0700 Subject: [PATCH 6961/7006] kexec: split kexec_file syscall code to kexec_file.c Split kexec_file syscall related code to another file kernel/kexec_file.c so that the #ifdef CONFIG_KEXEC_FILE in kexec.c can be dropped. Sharing variables and functions are moved to kernel/kexec_internal.h per suggestion from Vivek and Petr. [akpm@linux-foundation.org: fix bisectability] [akpm@linux-foundation.org: declare the various arch_kexec functions] [akpm@linux-foundation.org: fix build] Signed-off-by: Dave Young Cc: Eric W. Biederman Cc: Vivek Goyal Cc: Petr Tesarik Cc: Theodore Ts'o Cc: Josh Boyer Cc: David Howells Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kexec.h | 11 + kernel/Makefile | 1 + kernel/kexec.c | 1056 +-------------------------------------- kernel/kexec_file.c | 1045 ++++++++++++++++++++++++++++++++++++++ kernel/kexec_internal.h | 22 + 5 files changed, 1090 insertions(+), 1045 deletions(-) create mode 100644 kernel/kexec_file.c create mode 100644 kernel/kexec_internal.h diff --git a/include/linux/kexec.h b/include/linux/kexec.h index b63218f68c4b5..ab150ade0d187 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -318,6 +318,17 @@ int crash_shrink_memory(unsigned long new_size); size_t crash_get_memory_size(void); void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); +int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf, + unsigned long buf_len); +void * __weak arch_kexec_kernel_image_load(struct kimage *image); +int __weak arch_kimage_file_post_load_cleanup(struct kimage *image); +int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, + unsigned long buf_len); +int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, + Elf_Shdr *sechdrs, unsigned int relsec); +int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, + unsigned int relsec); + #else /* !CONFIG_KEXEC */ struct pt_regs; struct task_struct; diff --git a/kernel/Makefile b/kernel/Makefile index e0d7587e7684e..1b4890af5a659 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_MODULE_SIG) += module_signing.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o obj-$(CONFIG_KEXEC) += kexec.o +obj-$(CONFIG_KEXEC_FILE) += kexec_file.o obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_CGROUPS) += cgroup.o diff --git a/kernel/kexec.c b/kernel/kexec.c index a785c1015e25b..2d73ecfa55058 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -28,10 +28,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -44,6 +44,9 @@ #include #include +#include "kexec_internal.h" + +DEFINE_MUTEX(kexec_mutex); /* Per cpu memory for storing cpu states in case of system crash. */ note_buf_t __percpu *crash_notes; @@ -57,16 +60,6 @@ size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data); /* Flag to indicate we are going to kexec a new kernel */ bool kexec_in_progress = false; -/* - * Declare these symbols weak so that if architecture provides a purgatory, - * these will be overridden. - */ -char __weak kexec_purgatory[0]; -size_t __weak kexec_purgatory_size = 0; - -#ifdef CONFIG_KEXEC_FILE -static int kexec_calculate_store_digests(struct kimage *image); -#endif /* Location of the reserved area for the crash kernel */ struct resource crashk_res = { @@ -146,8 +139,6 @@ int kexec_should_crash(struct task_struct *p) */ #define KIMAGE_NO_DEST (-1UL) -static int kimage_is_destination_range(struct kimage *image, - unsigned long start, unsigned long end); static struct page *kimage_alloc_page(struct kimage *image, gfp_t gfp_mask, unsigned long dest); @@ -169,7 +160,7 @@ static int copy_user_segment_list(struct kimage *image, return ret; } -static int sanity_check_segment_list(struct kimage *image) +int sanity_check_segment_list(struct kimage *image) { int result, i; unsigned long nr_segments = image->nr_segments; @@ -259,7 +250,7 @@ static int sanity_check_segment_list(struct kimage *image) return 0; } -static struct kimage *do_kimage_alloc_init(void) +struct kimage *do_kimage_alloc_init(void) { struct kimage *image; @@ -286,8 +277,6 @@ static struct kimage *do_kimage_alloc_init(void) return image; } -static void kimage_free_page_list(struct list_head *list); - static int kimage_alloc_init(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, @@ -354,283 +343,7 @@ out_free_image: return ret; } -#ifdef CONFIG_KEXEC_FILE -static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len) -{ - struct fd f = fdget(fd); - int ret; - struct kstat stat; - loff_t pos; - ssize_t bytes = 0; - - if (!f.file) - return -EBADF; - - ret = vfs_getattr(&f.file->f_path, &stat); - if (ret) - goto out; - - if (stat.size > INT_MAX) { - ret = -EFBIG; - goto out; - } - - /* Don't hand 0 to vmalloc, it whines. */ - if (stat.size == 0) { - ret = -EINVAL; - goto out; - } - - *buf = vmalloc(stat.size); - if (!*buf) { - ret = -ENOMEM; - goto out; - } - - pos = 0; - while (pos < stat.size) { - bytes = kernel_read(f.file, pos, (char *)(*buf) + pos, - stat.size - pos); - if (bytes < 0) { - vfree(*buf); - ret = bytes; - goto out; - } - - if (bytes == 0) - break; - pos += bytes; - } - - if (pos != stat.size) { - ret = -EBADF; - vfree(*buf); - goto out; - } - - *buf_len = pos; -out: - fdput(f); - return ret; -} - -/* Architectures can provide this probe function */ -int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf, - unsigned long buf_len) -{ - return -ENOEXEC; -} - -void * __weak arch_kexec_kernel_image_load(struct kimage *image) -{ - return ERR_PTR(-ENOEXEC); -} - -void __weak arch_kimage_file_post_load_cleanup(struct kimage *image) -{ -} - -int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, - unsigned long buf_len) -{ - return -EKEYREJECTED; -} - -/* Apply relocations of type RELA */ -int __weak -arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, - unsigned int relsec) -{ - pr_err("RELA relocation unsupported.\n"); - return -ENOEXEC; -} - -/* Apply relocations of type REL */ -int __weak -arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, - unsigned int relsec) -{ - pr_err("REL relocation unsupported.\n"); - return -ENOEXEC; -} - -/* - * Free up memory used by kernel, initrd, and command line. This is temporary - * memory allocation which is not needed any more after these buffers have - * been loaded into separate segments and have been copied elsewhere. - */ -static void kimage_file_post_load_cleanup(struct kimage *image) -{ - struct purgatory_info *pi = &image->purgatory_info; - - vfree(image->kernel_buf); - image->kernel_buf = NULL; - - vfree(image->initrd_buf); - image->initrd_buf = NULL; - - kfree(image->cmdline_buf); - image->cmdline_buf = NULL; - - vfree(pi->purgatory_buf); - pi->purgatory_buf = NULL; - - vfree(pi->sechdrs); - pi->sechdrs = NULL; - - /* See if architecture has anything to cleanup post load */ - arch_kimage_file_post_load_cleanup(image); - - /* - * Above call should have called into bootloader to free up - * any data stored in kimage->image_loader_data. It should - * be ok now to free it up. - */ - kfree(image->image_loader_data); - image->image_loader_data = NULL; -} - -/* - * In file mode list of segments is prepared by kernel. Copy relevant - * data from user space, do error checking, prepare segment list - */ -static int -kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, - const char __user *cmdline_ptr, - unsigned long cmdline_len, unsigned flags) -{ - int ret = 0; - void *ldata; - - ret = copy_file_from_fd(kernel_fd, &image->kernel_buf, - &image->kernel_buf_len); - if (ret) - return ret; - - /* Call arch image probe handlers */ - ret = arch_kexec_kernel_image_probe(image, image->kernel_buf, - image->kernel_buf_len); - - if (ret) - goto out; - -#ifdef CONFIG_KEXEC_VERIFY_SIG - ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf, - image->kernel_buf_len); - if (ret) { - pr_debug("kernel signature verification failed.\n"); - goto out; - } - pr_debug("kernel signature verification successful.\n"); -#endif - /* It is possible that there no initramfs is being loaded */ - if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { - ret = copy_file_from_fd(initrd_fd, &image->initrd_buf, - &image->initrd_buf_len); - if (ret) - goto out; - } - - if (cmdline_len) { - image->cmdline_buf = kzalloc(cmdline_len, GFP_KERNEL); - if (!image->cmdline_buf) { - ret = -ENOMEM; - goto out; - } - - ret = copy_from_user(image->cmdline_buf, cmdline_ptr, - cmdline_len); - if (ret) { - ret = -EFAULT; - goto out; - } - - image->cmdline_buf_len = cmdline_len; - - /* command line should be a string with last byte null */ - if (image->cmdline_buf[cmdline_len - 1] != '\0') { - ret = -EINVAL; - goto out; - } - } - - /* Call arch image load handlers */ - ldata = arch_kexec_kernel_image_load(image); - - if (IS_ERR(ldata)) { - ret = PTR_ERR(ldata); - goto out; - } - - image->image_loader_data = ldata; -out: - /* In case of error, free up all allocated memory in this function */ - if (ret) - kimage_file_post_load_cleanup(image); - return ret; -} - -static int -kimage_file_alloc_init(struct kimage **rimage, int kernel_fd, - int initrd_fd, const char __user *cmdline_ptr, - unsigned long cmdline_len, unsigned long flags) -{ - int ret; - struct kimage *image; - bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH; - - image = do_kimage_alloc_init(); - if (!image) - return -ENOMEM; - - image->file_mode = 1; - - if (kexec_on_panic) { - /* Enable special crash kernel control page alloc policy. */ - image->control_page = crashk_res.start; - image->type = KEXEC_TYPE_CRASH; - } - - ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd, - cmdline_ptr, cmdline_len, flags); - if (ret) - goto out_free_image; - - ret = sanity_check_segment_list(image); - if (ret) - goto out_free_post_load_bufs; - - ret = -ENOMEM; - image->control_code_page = kimage_alloc_control_pages(image, - get_order(KEXEC_CONTROL_PAGE_SIZE)); - if (!image->control_code_page) { - pr_err("Could not allocate control_code_buffer\n"); - goto out_free_post_load_bufs; - } - - if (!kexec_on_panic) { - image->swap_page = kimage_alloc_control_pages(image, 0); - if (!image->swap_page) { - pr_err("Could not allocate swap buffer\n"); - goto out_free_control_pages; - } - } - - *rimage = image; - return 0; -out_free_control_pages: - kimage_free_page_list(&image->control_pages); -out_free_post_load_bufs: - kimage_file_post_load_cleanup(image); -out_free_image: - kfree(image); - return ret; -} -#else /* CONFIG_KEXEC_FILE */ -static inline void kimage_file_post_load_cleanup(struct kimage *image) { } -#endif /* CONFIG_KEXEC_FILE */ - -static int kimage_is_destination_range(struct kimage *image, +int kimage_is_destination_range(struct kimage *image, unsigned long start, unsigned long end) { @@ -676,7 +389,7 @@ static void kimage_free_pages(struct page *page) __free_pages(page, order); } -static void kimage_free_page_list(struct list_head *list) +void kimage_free_page_list(struct list_head *list) { struct list_head *pos, *next; @@ -892,7 +605,7 @@ static void kimage_free_extra_pages(struct kimage *image) kimage_free_page_list(&image->unusable_pages); } -static void kimage_terminate(struct kimage *image) +void kimage_terminate(struct kimage *image) { if (*image->entry != 0) image->entry++; @@ -913,7 +626,7 @@ static void kimage_free_entry(kimage_entry_t entry) kimage_free_pages(page); } -static void kimage_free(struct kimage *image) +void kimage_free(struct kimage *image) { kimage_entry_t *ptr, entry; kimage_entry_t ind = 0; @@ -1204,7 +917,7 @@ out: return result; } -static int kimage_load_segment(struct kimage *image, +int kimage_load_segment(struct kimage *image, struct kexec_segment *segment) { int result = -ENOMEM; @@ -1245,8 +958,6 @@ struct kimage *kexec_image; struct kimage *kexec_crash_image; int kexec_load_disabled; -static DEFINE_MUTEX(kexec_mutex); - SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, struct kexec_segment __user *, segments, unsigned long, flags) { @@ -1391,85 +1102,6 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry, } #endif -#ifdef CONFIG_KEXEC_FILE -SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, - unsigned long, cmdline_len, const char __user *, cmdline_ptr, - unsigned long, flags) -{ - int ret = 0, i; - struct kimage **dest_image, *image; - - /* We only trust the superuser with rebooting the system. */ - if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) - return -EPERM; - - /* Make sure we have a legal set of flags */ - if (flags != (flags & KEXEC_FILE_FLAGS)) - return -EINVAL; - - image = NULL; - - if (!mutex_trylock(&kexec_mutex)) - return -EBUSY; - - dest_image = &kexec_image; - if (flags & KEXEC_FILE_ON_CRASH) - dest_image = &kexec_crash_image; - - if (flags & KEXEC_FILE_UNLOAD) - goto exchange; - - /* - * In case of crash, new kernel gets loaded in reserved region. It is - * same memory where old crash kernel might be loaded. Free any - * current crash dump kernel before we corrupt it. - */ - if (flags & KEXEC_FILE_ON_CRASH) - kimage_free(xchg(&kexec_crash_image, NULL)); - - ret = kimage_file_alloc_init(&image, kernel_fd, initrd_fd, cmdline_ptr, - cmdline_len, flags); - if (ret) - goto out; - - ret = machine_kexec_prepare(image); - if (ret) - goto out; - - ret = kexec_calculate_store_digests(image); - if (ret) - goto out; - - for (i = 0; i < image->nr_segments; i++) { - struct kexec_segment *ksegment; - - ksegment = &image->segment[i]; - pr_debug("Loading segment %d: buf=0x%p bufsz=0x%zx mem=0x%lx memsz=0x%zx\n", - i, ksegment->buf, ksegment->bufsz, ksegment->mem, - ksegment->memsz); - - ret = kimage_load_segment(image, &image->segment[i]); - if (ret) - goto out; - } - - kimage_terminate(image); - - /* - * Free up any temporary buffers allocated which are not needed - * after image has been loaded - */ - kimage_file_post_load_cleanup(image); -exchange: - image = xchg(dest_image, image); -out: - mutex_unlock(&kexec_mutex); - kimage_free(image); - return ret; -} - -#endif /* CONFIG_KEXEC_FILE */ - void crash_kexec(struct pt_regs *regs) { /* Take the kexec_mutex here to prevent sys_kexec_load @@ -2024,672 +1656,6 @@ static int __init crash_save_vmcoreinfo_init(void) subsys_initcall(crash_save_vmcoreinfo_init); -#ifdef CONFIG_KEXEC_FILE -static int locate_mem_hole_top_down(unsigned long start, unsigned long end, - struct kexec_buf *kbuf) -{ - struct kimage *image = kbuf->image; - unsigned long temp_start, temp_end; - - temp_end = min(end, kbuf->buf_max); - temp_start = temp_end - kbuf->memsz; - - do { - /* align down start */ - temp_start = temp_start & (~(kbuf->buf_align - 1)); - - if (temp_start < start || temp_start < kbuf->buf_min) - return 0; - - temp_end = temp_start + kbuf->memsz - 1; - - /* - * Make sure this does not conflict with any of existing - * segments - */ - if (kimage_is_destination_range(image, temp_start, temp_end)) { - temp_start = temp_start - PAGE_SIZE; - continue; - } - - /* We found a suitable memory range */ - break; - } while (1); - - /* If we are here, we found a suitable memory range */ - kbuf->mem = temp_start; - - /* Success, stop navigating through remaining System RAM ranges */ - return 1; -} - -static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end, - struct kexec_buf *kbuf) -{ - struct kimage *image = kbuf->image; - unsigned long temp_start, temp_end; - - temp_start = max(start, kbuf->buf_min); - - do { - temp_start = ALIGN(temp_start, kbuf->buf_align); - temp_end = temp_start + kbuf->memsz - 1; - - if (temp_end > end || temp_end > kbuf->buf_max) - return 0; - /* - * Make sure this does not conflict with any of existing - * segments - */ - if (kimage_is_destination_range(image, temp_start, temp_end)) { - temp_start = temp_start + PAGE_SIZE; - continue; - } - - /* We found a suitable memory range */ - break; - } while (1); - - /* If we are here, we found a suitable memory range */ - kbuf->mem = temp_start; - - /* Success, stop navigating through remaining System RAM ranges */ - return 1; -} - -static int locate_mem_hole_callback(u64 start, u64 end, void *arg) -{ - struct kexec_buf *kbuf = (struct kexec_buf *)arg; - unsigned long sz = end - start + 1; - - /* Returning 0 will take to next memory range */ - if (sz < kbuf->memsz) - return 0; - - if (end < kbuf->buf_min || start > kbuf->buf_max) - return 0; - - /* - * Allocate memory top down with-in ram range. Otherwise bottom up - * allocation. - */ - if (kbuf->top_down) - return locate_mem_hole_top_down(start, end, kbuf); - return locate_mem_hole_bottom_up(start, end, kbuf); -} - -/* - * Helper function for placing a buffer in a kexec segment. This assumes - * that kexec_mutex is held. - */ -int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz, - unsigned long memsz, unsigned long buf_align, - unsigned long buf_min, unsigned long buf_max, - bool top_down, unsigned long *load_addr) -{ - - struct kexec_segment *ksegment; - struct kexec_buf buf, *kbuf; - int ret; - - /* Currently adding segment this way is allowed only in file mode */ - if (!image->file_mode) - return -EINVAL; - - if (image->nr_segments >= KEXEC_SEGMENT_MAX) - return -EINVAL; - - /* - * Make sure we are not trying to add buffer after allocating - * control pages. All segments need to be placed first before - * any control pages are allocated. As control page allocation - * logic goes through list of segments to make sure there are - * no destination overlaps. - */ - if (!list_empty(&image->control_pages)) { - WARN_ON(1); - return -EINVAL; - } - - memset(&buf, 0, sizeof(struct kexec_buf)); - kbuf = &buf; - kbuf->image = image; - kbuf->buffer = buffer; - kbuf->bufsz = bufsz; - - kbuf->memsz = ALIGN(memsz, PAGE_SIZE); - kbuf->buf_align = max(buf_align, PAGE_SIZE); - kbuf->buf_min = buf_min; - kbuf->buf_max = buf_max; - kbuf->top_down = top_down; - - /* Walk the RAM ranges and allocate a suitable range for the buffer */ - if (image->type == KEXEC_TYPE_CRASH) - ret = walk_iomem_res("Crash kernel", - IORESOURCE_MEM | IORESOURCE_BUSY, - crashk_res.start, crashk_res.end, kbuf, - locate_mem_hole_callback); - else - ret = walk_system_ram_res(0, -1, kbuf, - locate_mem_hole_callback); - if (ret != 1) { - /* A suitable memory range could not be found for buffer */ - return -EADDRNOTAVAIL; - } - - /* Found a suitable memory range */ - ksegment = &image->segment[image->nr_segments]; - ksegment->kbuf = kbuf->buffer; - ksegment->bufsz = kbuf->bufsz; - ksegment->mem = kbuf->mem; - ksegment->memsz = kbuf->memsz; - image->nr_segments++; - *load_addr = ksegment->mem; - return 0; -} - -/* Calculate and store the digest of segments */ -static int kexec_calculate_store_digests(struct kimage *image) -{ - struct crypto_shash *tfm; - struct shash_desc *desc; - int ret = 0, i, j, zero_buf_sz, sha_region_sz; - size_t desc_size, nullsz; - char *digest; - void *zero_buf; - struct kexec_sha_region *sha_regions; - struct purgatory_info *pi = &image->purgatory_info; - - zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT); - zero_buf_sz = PAGE_SIZE; - - tfm = crypto_alloc_shash("sha256", 0, 0); - if (IS_ERR(tfm)) { - ret = PTR_ERR(tfm); - goto out; - } - - desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); - desc = kzalloc(desc_size, GFP_KERNEL); - if (!desc) { - ret = -ENOMEM; - goto out_free_tfm; - } - - sha_region_sz = KEXEC_SEGMENT_MAX * sizeof(struct kexec_sha_region); - sha_regions = vzalloc(sha_region_sz); - if (!sha_regions) - goto out_free_desc; - - desc->tfm = tfm; - desc->flags = 0; - - ret = crypto_shash_init(desc); - if (ret < 0) - goto out_free_sha_regions; - - digest = kzalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); - if (!digest) { - ret = -ENOMEM; - goto out_free_sha_regions; - } - - for (j = i = 0; i < image->nr_segments; i++) { - struct kexec_segment *ksegment; - - ksegment = &image->segment[i]; - /* - * Skip purgatory as it will be modified once we put digest - * info in purgatory. - */ - if (ksegment->kbuf == pi->purgatory_buf) - continue; - - ret = crypto_shash_update(desc, ksegment->kbuf, - ksegment->bufsz); - if (ret) - break; - - /* - * Assume rest of the buffer is filled with zero and - * update digest accordingly. - */ - nullsz = ksegment->memsz - ksegment->bufsz; - while (nullsz) { - unsigned long bytes = nullsz; - - if (bytes > zero_buf_sz) - bytes = zero_buf_sz; - ret = crypto_shash_update(desc, zero_buf, bytes); - if (ret) - break; - nullsz -= bytes; - } - - if (ret) - break; - - sha_regions[j].start = ksegment->mem; - sha_regions[j].len = ksegment->memsz; - j++; - } - - if (!ret) { - ret = crypto_shash_final(desc, digest); - if (ret) - goto out_free_digest; - ret = kexec_purgatory_get_set_symbol(image, "sha_regions", - sha_regions, sha_region_sz, 0); - if (ret) - goto out_free_digest; - - ret = kexec_purgatory_get_set_symbol(image, "sha256_digest", - digest, SHA256_DIGEST_SIZE, 0); - if (ret) - goto out_free_digest; - } - -out_free_digest: - kfree(digest); -out_free_sha_regions: - vfree(sha_regions); -out_free_desc: - kfree(desc); -out_free_tfm: - kfree(tfm); -out: - return ret; -} - -/* Actually load purgatory. Lot of code taken from kexec-tools */ -static int __kexec_load_purgatory(struct kimage *image, unsigned long min, - unsigned long max, int top_down) -{ - struct purgatory_info *pi = &image->purgatory_info; - unsigned long align, buf_align, bss_align, buf_sz, bss_sz, bss_pad; - unsigned long memsz, entry, load_addr, curr_load_addr, bss_addr, offset; - unsigned char *buf_addr, *src; - int i, ret = 0, entry_sidx = -1; - const Elf_Shdr *sechdrs_c; - Elf_Shdr *sechdrs = NULL; - void *purgatory_buf = NULL; - - /* - * sechdrs_c points to section headers in purgatory and are read - * only. No modifications allowed. - */ - sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff; - - /* - * We can not modify sechdrs_c[] and its fields. It is read only. - * Copy it over to a local copy where one can store some temporary - * data and free it at the end. We need to modify ->sh_addr and - * ->sh_offset fields to keep track of permanent and temporary - * locations of sections. - */ - sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); - if (!sechdrs) - return -ENOMEM; - - memcpy(sechdrs, sechdrs_c, pi->ehdr->e_shnum * sizeof(Elf_Shdr)); - - /* - * We seem to have multiple copies of sections. First copy is which - * is embedded in kernel in read only section. Some of these sections - * will be copied to a temporary buffer and relocated. And these - * sections will finally be copied to their final destination at - * segment load time. - * - * Use ->sh_offset to reflect section address in memory. It will - * point to original read only copy if section is not allocatable. - * Otherwise it will point to temporary copy which will be relocated. - * - * Use ->sh_addr to contain final address of the section where it - * will go during execution time. - */ - for (i = 0; i < pi->ehdr->e_shnum; i++) { - if (sechdrs[i].sh_type == SHT_NOBITS) - continue; - - sechdrs[i].sh_offset = (unsigned long)pi->ehdr + - sechdrs[i].sh_offset; - } - - /* - * Identify entry point section and make entry relative to section - * start. - */ - entry = pi->ehdr->e_entry; - for (i = 0; i < pi->ehdr->e_shnum; i++) { - if (!(sechdrs[i].sh_flags & SHF_ALLOC)) - continue; - - if (!(sechdrs[i].sh_flags & SHF_EXECINSTR)) - continue; - - /* Make entry section relative */ - if (sechdrs[i].sh_addr <= pi->ehdr->e_entry && - ((sechdrs[i].sh_addr + sechdrs[i].sh_size) > - pi->ehdr->e_entry)) { - entry_sidx = i; - entry -= sechdrs[i].sh_addr; - break; - } - } - - /* Determine how much memory is needed to load relocatable object. */ - buf_align = 1; - bss_align = 1; - buf_sz = 0; - bss_sz = 0; - - for (i = 0; i < pi->ehdr->e_shnum; i++) { - if (!(sechdrs[i].sh_flags & SHF_ALLOC)) - continue; - - align = sechdrs[i].sh_addralign; - if (sechdrs[i].sh_type != SHT_NOBITS) { - if (buf_align < align) - buf_align = align; - buf_sz = ALIGN(buf_sz, align); - buf_sz += sechdrs[i].sh_size; - } else { - /* bss section */ - if (bss_align < align) - bss_align = align; - bss_sz = ALIGN(bss_sz, align); - bss_sz += sechdrs[i].sh_size; - } - } - - /* Determine the bss padding required to align bss properly */ - bss_pad = 0; - if (buf_sz & (bss_align - 1)) - bss_pad = bss_align - (buf_sz & (bss_align - 1)); - - memsz = buf_sz + bss_pad + bss_sz; - - /* Allocate buffer for purgatory */ - purgatory_buf = vzalloc(buf_sz); - if (!purgatory_buf) { - ret = -ENOMEM; - goto out; - } - - if (buf_align < bss_align) - buf_align = bss_align; - - /* Add buffer to segment list */ - ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz, - buf_align, min, max, top_down, - &pi->purgatory_load_addr); - if (ret) - goto out; - - /* Load SHF_ALLOC sections */ - buf_addr = purgatory_buf; - load_addr = curr_load_addr = pi->purgatory_load_addr; - bss_addr = load_addr + buf_sz + bss_pad; - - for (i = 0; i < pi->ehdr->e_shnum; i++) { - if (!(sechdrs[i].sh_flags & SHF_ALLOC)) - continue; - - align = sechdrs[i].sh_addralign; - if (sechdrs[i].sh_type != SHT_NOBITS) { - curr_load_addr = ALIGN(curr_load_addr, align); - offset = curr_load_addr - load_addr; - /* We already modifed ->sh_offset to keep src addr */ - src = (char *) sechdrs[i].sh_offset; - memcpy(buf_addr + offset, src, sechdrs[i].sh_size); - - /* Store load address and source address of section */ - sechdrs[i].sh_addr = curr_load_addr; - - /* - * This section got copied to temporary buffer. Update - * ->sh_offset accordingly. - */ - sechdrs[i].sh_offset = (unsigned long)(buf_addr + offset); - - /* Advance to the next address */ - curr_load_addr += sechdrs[i].sh_size; - } else { - bss_addr = ALIGN(bss_addr, align); - sechdrs[i].sh_addr = bss_addr; - bss_addr += sechdrs[i].sh_size; - } - } - - /* Update entry point based on load address of text section */ - if (entry_sidx >= 0) - entry += sechdrs[entry_sidx].sh_addr; - - /* Make kernel jump to purgatory after shutdown */ - image->start = entry; - - /* Used later to get/set symbol values */ - pi->sechdrs = sechdrs; - - /* - * Used later to identify which section is purgatory and skip it - * from checksumming. - */ - pi->purgatory_buf = purgatory_buf; - return ret; -out: - vfree(sechdrs); - vfree(purgatory_buf); - return ret; -} - -static int kexec_apply_relocations(struct kimage *image) -{ - int i, ret; - struct purgatory_info *pi = &image->purgatory_info; - Elf_Shdr *sechdrs = pi->sechdrs; - - /* Apply relocations */ - for (i = 0; i < pi->ehdr->e_shnum; i++) { - Elf_Shdr *section, *symtab; - - if (sechdrs[i].sh_type != SHT_RELA && - sechdrs[i].sh_type != SHT_REL) - continue; - - /* - * For section of type SHT_RELA/SHT_REL, - * ->sh_link contains section header index of associated - * symbol table. And ->sh_info contains section header - * index of section to which relocations apply. - */ - if (sechdrs[i].sh_info >= pi->ehdr->e_shnum || - sechdrs[i].sh_link >= pi->ehdr->e_shnum) - return -ENOEXEC; - - section = &sechdrs[sechdrs[i].sh_info]; - symtab = &sechdrs[sechdrs[i].sh_link]; - - if (!(section->sh_flags & SHF_ALLOC)) - continue; - - /* - * symtab->sh_link contain section header index of associated - * string table. - */ - if (symtab->sh_link >= pi->ehdr->e_shnum) - /* Invalid section number? */ - continue; - - /* - * Respective architecture needs to provide support for applying - * relocations of type SHT_RELA/SHT_REL. - */ - if (sechdrs[i].sh_type == SHT_RELA) - ret = arch_kexec_apply_relocations_add(pi->ehdr, - sechdrs, i); - else if (sechdrs[i].sh_type == SHT_REL) - ret = arch_kexec_apply_relocations(pi->ehdr, - sechdrs, i); - if (ret) - return ret; - } - - return 0; -} - -/* Load relocatable purgatory object and relocate it appropriately */ -int kexec_load_purgatory(struct kimage *image, unsigned long min, - unsigned long max, int top_down, - unsigned long *load_addr) -{ - struct purgatory_info *pi = &image->purgatory_info; - int ret; - - if (kexec_purgatory_size <= 0) - return -EINVAL; - - if (kexec_purgatory_size < sizeof(Elf_Ehdr)) - return -ENOEXEC; - - pi->ehdr = (Elf_Ehdr *)kexec_purgatory; - - if (memcmp(pi->ehdr->e_ident, ELFMAG, SELFMAG) != 0 - || pi->ehdr->e_type != ET_REL - || !elf_check_arch(pi->ehdr) - || pi->ehdr->e_shentsize != sizeof(Elf_Shdr)) - return -ENOEXEC; - - if (pi->ehdr->e_shoff >= kexec_purgatory_size - || (pi->ehdr->e_shnum * sizeof(Elf_Shdr) > - kexec_purgatory_size - pi->ehdr->e_shoff)) - return -ENOEXEC; - - ret = __kexec_load_purgatory(image, min, max, top_down); - if (ret) - return ret; - - ret = kexec_apply_relocations(image); - if (ret) - goto out; - - *load_addr = pi->purgatory_load_addr; - return 0; -out: - vfree(pi->sechdrs); - vfree(pi->purgatory_buf); - return ret; -} - -static Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, - const char *name) -{ - Elf_Sym *syms; - Elf_Shdr *sechdrs; - Elf_Ehdr *ehdr; - int i, k; - const char *strtab; - - if (!pi->sechdrs || !pi->ehdr) - return NULL; - - sechdrs = pi->sechdrs; - ehdr = pi->ehdr; - - for (i = 0; i < ehdr->e_shnum; i++) { - if (sechdrs[i].sh_type != SHT_SYMTAB) - continue; - - if (sechdrs[i].sh_link >= ehdr->e_shnum) - /* Invalid strtab section number */ - continue; - strtab = (char *)sechdrs[sechdrs[i].sh_link].sh_offset; - syms = (Elf_Sym *)sechdrs[i].sh_offset; - - /* Go through symbols for a match */ - for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) { - if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL) - continue; - - if (strcmp(strtab + syms[k].st_name, name) != 0) - continue; - - if (syms[k].st_shndx == SHN_UNDEF || - syms[k].st_shndx >= ehdr->e_shnum) { - pr_debug("Symbol: %s has bad section index %d.\n", - name, syms[k].st_shndx); - return NULL; - } - - /* Found the symbol we are looking for */ - return &syms[k]; - } - } - - return NULL; -} - -void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name) -{ - struct purgatory_info *pi = &image->purgatory_info; - Elf_Sym *sym; - Elf_Shdr *sechdr; - - sym = kexec_purgatory_find_symbol(pi, name); - if (!sym) - return ERR_PTR(-EINVAL); - - sechdr = &pi->sechdrs[sym->st_shndx]; - - /* - * Returns the address where symbol will finally be loaded after - * kexec_load_segment() - */ - return (void *)(sechdr->sh_addr + sym->st_value); -} - -/* - * Get or set value of a symbol. If "get_value" is true, symbol value is - * returned in buf otherwise symbol value is set based on value in buf. - */ -int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, - void *buf, unsigned int size, bool get_value) -{ - Elf_Sym *sym; - Elf_Shdr *sechdrs; - struct purgatory_info *pi = &image->purgatory_info; - char *sym_buf; - - sym = kexec_purgatory_find_symbol(pi, name); - if (!sym) - return -EINVAL; - - if (sym->st_size != size) { - pr_err("symbol %s size mismatch: expected %lu actual %u\n", - name, (unsigned long)sym->st_size, size); - return -EINVAL; - } - - sechdrs = pi->sechdrs; - - if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { - pr_err("symbol %s is in a bss section. Cannot %s\n", name, - get_value ? "get" : "set"); - return -EINVAL; - } - - sym_buf = (unsigned char *)sechdrs[sym->st_shndx].sh_offset + - sym->st_value; - - if (get_value) - memcpy((void *)buf, sym_buf, size); - else - memcpy((void *)sym_buf, buf, size); - - return 0; -} -#endif /* CONFIG_KEXEC_FILE */ - /* * Move into place and start executing a preloaded standalone * executable. If nothing was preloaded return an error. diff --git a/kernel/kexec_file.c b/kernel/kexec_file.c new file mode 100644 index 0000000000000..6a9a3f2a0e8e3 --- /dev/null +++ b/kernel/kexec_file.c @@ -0,0 +1,1045 @@ +/* + * kexec: kexec_file_load system call + * + * Copyright (C) 2014 Red Hat Inc. + * Authors: + * Vivek Goyal + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "kexec_internal.h" + +/* + * Declare these symbols weak so that if architecture provides a purgatory, + * these will be overridden. + */ +char __weak kexec_purgatory[0]; +size_t __weak kexec_purgatory_size = 0; + +static int kexec_calculate_store_digests(struct kimage *image); + +static int copy_file_from_fd(int fd, void **buf, unsigned long *buf_len) +{ + struct fd f = fdget(fd); + int ret; + struct kstat stat; + loff_t pos; + ssize_t bytes = 0; + + if (!f.file) + return -EBADF; + + ret = vfs_getattr(&f.file->f_path, &stat); + if (ret) + goto out; + + if (stat.size > INT_MAX) { + ret = -EFBIG; + goto out; + } + + /* Don't hand 0 to vmalloc, it whines. */ + if (stat.size == 0) { + ret = -EINVAL; + goto out; + } + + *buf = vmalloc(stat.size); + if (!*buf) { + ret = -ENOMEM; + goto out; + } + + pos = 0; + while (pos < stat.size) { + bytes = kernel_read(f.file, pos, (char *)(*buf) + pos, + stat.size - pos); + if (bytes < 0) { + vfree(*buf); + ret = bytes; + goto out; + } + + if (bytes == 0) + break; + pos += bytes; + } + + if (pos != stat.size) { + ret = -EBADF; + vfree(*buf); + goto out; + } + + *buf_len = pos; +out: + fdput(f); + return ret; +} + +/* Architectures can provide this probe function */ +int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf, + unsigned long buf_len) +{ + return -ENOEXEC; +} + +void * __weak arch_kexec_kernel_image_load(struct kimage *image) +{ + return ERR_PTR(-ENOEXEC); +} + +int __weak arch_kimage_file_post_load_cleanup(struct kimage *image) +{ + return -EINVAL; +} + +int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, + unsigned long buf_len) +{ + return -EKEYREJECTED; +} + +/* Apply relocations of type RELA */ +int __weak +arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, + unsigned int relsec) +{ + pr_err("RELA relocation unsupported.\n"); + return -ENOEXEC; +} + +/* Apply relocations of type REL */ +int __weak +arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, + unsigned int relsec) +{ + pr_err("REL relocation unsupported.\n"); + return -ENOEXEC; +} + +/* + * Free up memory used by kernel, initrd, and command line. This is temporary + * memory allocation which is not needed any more after these buffers have + * been loaded into separate segments and have been copied elsewhere. + */ +void kimage_file_post_load_cleanup(struct kimage *image) +{ + struct purgatory_info *pi = &image->purgatory_info; + + vfree(image->kernel_buf); + image->kernel_buf = NULL; + + vfree(image->initrd_buf); + image->initrd_buf = NULL; + + kfree(image->cmdline_buf); + image->cmdline_buf = NULL; + + vfree(pi->purgatory_buf); + pi->purgatory_buf = NULL; + + vfree(pi->sechdrs); + pi->sechdrs = NULL; + + /* See if architecture has anything to cleanup post load */ + arch_kimage_file_post_load_cleanup(image); + + /* + * Above call should have called into bootloader to free up + * any data stored in kimage->image_loader_data. It should + * be ok now to free it up. + */ + kfree(image->image_loader_data); + image->image_loader_data = NULL; +} + +/* + * In file mode list of segments is prepared by kernel. Copy relevant + * data from user space, do error checking, prepare segment list + */ +static int +kimage_file_prepare_segments(struct kimage *image, int kernel_fd, int initrd_fd, + const char __user *cmdline_ptr, + unsigned long cmdline_len, unsigned flags) +{ + int ret = 0; + void *ldata; + + ret = copy_file_from_fd(kernel_fd, &image->kernel_buf, + &image->kernel_buf_len); + if (ret) + return ret; + + /* Call arch image probe handlers */ + ret = arch_kexec_kernel_image_probe(image, image->kernel_buf, + image->kernel_buf_len); + + if (ret) + goto out; + +#ifdef CONFIG_KEXEC_VERIFY_SIG + ret = arch_kexec_kernel_verify_sig(image, image->kernel_buf, + image->kernel_buf_len); + if (ret) { + pr_debug("kernel signature verification failed.\n"); + goto out; + } + pr_debug("kernel signature verification successful.\n"); +#endif + /* It is possible that there no initramfs is being loaded */ + if (!(flags & KEXEC_FILE_NO_INITRAMFS)) { + ret = copy_file_from_fd(initrd_fd, &image->initrd_buf, + &image->initrd_buf_len); + if (ret) + goto out; + } + + if (cmdline_len) { + image->cmdline_buf = kzalloc(cmdline_len, GFP_KERNEL); + if (!image->cmdline_buf) { + ret = -ENOMEM; + goto out; + } + + ret = copy_from_user(image->cmdline_buf, cmdline_ptr, + cmdline_len); + if (ret) { + ret = -EFAULT; + goto out; + } + + image->cmdline_buf_len = cmdline_len; + + /* command line should be a string with last byte null */ + if (image->cmdline_buf[cmdline_len - 1] != '\0') { + ret = -EINVAL; + goto out; + } + } + + /* Call arch image load handlers */ + ldata = arch_kexec_kernel_image_load(image); + + if (IS_ERR(ldata)) { + ret = PTR_ERR(ldata); + goto out; + } + + image->image_loader_data = ldata; +out: + /* In case of error, free up all allocated memory in this function */ + if (ret) + kimage_file_post_load_cleanup(image); + return ret; +} + +static int +kimage_file_alloc_init(struct kimage **rimage, int kernel_fd, + int initrd_fd, const char __user *cmdline_ptr, + unsigned long cmdline_len, unsigned long flags) +{ + int ret; + struct kimage *image; + bool kexec_on_panic = flags & KEXEC_FILE_ON_CRASH; + + image = do_kimage_alloc_init(); + if (!image) + return -ENOMEM; + + image->file_mode = 1; + + if (kexec_on_panic) { + /* Enable special crash kernel control page alloc policy. */ + image->control_page = crashk_res.start; + image->type = KEXEC_TYPE_CRASH; + } + + ret = kimage_file_prepare_segments(image, kernel_fd, initrd_fd, + cmdline_ptr, cmdline_len, flags); + if (ret) + goto out_free_image; + + ret = sanity_check_segment_list(image); + if (ret) + goto out_free_post_load_bufs; + + ret = -ENOMEM; + image->control_code_page = kimage_alloc_control_pages(image, + get_order(KEXEC_CONTROL_PAGE_SIZE)); + if (!image->control_code_page) { + pr_err("Could not allocate control_code_buffer\n"); + goto out_free_post_load_bufs; + } + + if (!kexec_on_panic) { + image->swap_page = kimage_alloc_control_pages(image, 0); + if (!image->swap_page) { + pr_err("Could not allocate swap buffer\n"); + goto out_free_control_pages; + } + } + + *rimage = image; + return 0; +out_free_control_pages: + kimage_free_page_list(&image->control_pages); +out_free_post_load_bufs: + kimage_file_post_load_cleanup(image); +out_free_image: + kfree(image); + return ret; +} + +SYSCALL_DEFINE5(kexec_file_load, int, kernel_fd, int, initrd_fd, + unsigned long, cmdline_len, const char __user *, cmdline_ptr, + unsigned long, flags) +{ + int ret = 0, i; + struct kimage **dest_image, *image; + + /* We only trust the superuser with rebooting the system. */ + if (!capable(CAP_SYS_BOOT) || kexec_load_disabled) + return -EPERM; + + /* Make sure we have a legal set of flags */ + if (flags != (flags & KEXEC_FILE_FLAGS)) + return -EINVAL; + + image = NULL; + + if (!mutex_trylock(&kexec_mutex)) + return -EBUSY; + + dest_image = &kexec_image; + if (flags & KEXEC_FILE_ON_CRASH) + dest_image = &kexec_crash_image; + + if (flags & KEXEC_FILE_UNLOAD) + goto exchange; + + /* + * In case of crash, new kernel gets loaded in reserved region. It is + * same memory where old crash kernel might be loaded. Free any + * current crash dump kernel before we corrupt it. + */ + if (flags & KEXEC_FILE_ON_CRASH) + kimage_free(xchg(&kexec_crash_image, NULL)); + + ret = kimage_file_alloc_init(&image, kernel_fd, initrd_fd, cmdline_ptr, + cmdline_len, flags); + if (ret) + goto out; + + ret = machine_kexec_prepare(image); + if (ret) + goto out; + + ret = kexec_calculate_store_digests(image); + if (ret) + goto out; + + for (i = 0; i < image->nr_segments; i++) { + struct kexec_segment *ksegment; + + ksegment = &image->segment[i]; + pr_debug("Loading segment %d: buf=0x%p bufsz=0x%zx mem=0x%lx memsz=0x%zx\n", + i, ksegment->buf, ksegment->bufsz, ksegment->mem, + ksegment->memsz); + + ret = kimage_load_segment(image, &image->segment[i]); + if (ret) + goto out; + } + + kimage_terminate(image); + + /* + * Free up any temporary buffers allocated which are not needed + * after image has been loaded + */ + kimage_file_post_load_cleanup(image); +exchange: + image = xchg(dest_image, image); +out: + mutex_unlock(&kexec_mutex); + kimage_free(image); + return ret; +} + +static int locate_mem_hole_top_down(unsigned long start, unsigned long end, + struct kexec_buf *kbuf) +{ + struct kimage *image = kbuf->image; + unsigned long temp_start, temp_end; + + temp_end = min(end, kbuf->buf_max); + temp_start = temp_end - kbuf->memsz; + + do { + /* align down start */ + temp_start = temp_start & (~(kbuf->buf_align - 1)); + + if (temp_start < start || temp_start < kbuf->buf_min) + return 0; + + temp_end = temp_start + kbuf->memsz - 1; + + /* + * Make sure this does not conflict with any of existing + * segments + */ + if (kimage_is_destination_range(image, temp_start, temp_end)) { + temp_start = temp_start - PAGE_SIZE; + continue; + } + + /* We found a suitable memory range */ + break; + } while (1); + + /* If we are here, we found a suitable memory range */ + kbuf->mem = temp_start; + + /* Success, stop navigating through remaining System RAM ranges */ + return 1; +} + +static int locate_mem_hole_bottom_up(unsigned long start, unsigned long end, + struct kexec_buf *kbuf) +{ + struct kimage *image = kbuf->image; + unsigned long temp_start, temp_end; + + temp_start = max(start, kbuf->buf_min); + + do { + temp_start = ALIGN(temp_start, kbuf->buf_align); + temp_end = temp_start + kbuf->memsz - 1; + + if (temp_end > end || temp_end > kbuf->buf_max) + return 0; + /* + * Make sure this does not conflict with any of existing + * segments + */ + if (kimage_is_destination_range(image, temp_start, temp_end)) { + temp_start = temp_start + PAGE_SIZE; + continue; + } + + /* We found a suitable memory range */ + break; + } while (1); + + /* If we are here, we found a suitable memory range */ + kbuf->mem = temp_start; + + /* Success, stop navigating through remaining System RAM ranges */ + return 1; +} + +static int locate_mem_hole_callback(u64 start, u64 end, void *arg) +{ + struct kexec_buf *kbuf = (struct kexec_buf *)arg; + unsigned long sz = end - start + 1; + + /* Returning 0 will take to next memory range */ + if (sz < kbuf->memsz) + return 0; + + if (end < kbuf->buf_min || start > kbuf->buf_max) + return 0; + + /* + * Allocate memory top down with-in ram range. Otherwise bottom up + * allocation. + */ + if (kbuf->top_down) + return locate_mem_hole_top_down(start, end, kbuf); + return locate_mem_hole_bottom_up(start, end, kbuf); +} + +/* + * Helper function for placing a buffer in a kexec segment. This assumes + * that kexec_mutex is held. + */ +int kexec_add_buffer(struct kimage *image, char *buffer, unsigned long bufsz, + unsigned long memsz, unsigned long buf_align, + unsigned long buf_min, unsigned long buf_max, + bool top_down, unsigned long *load_addr) +{ + + struct kexec_segment *ksegment; + struct kexec_buf buf, *kbuf; + int ret; + + /* Currently adding segment this way is allowed only in file mode */ + if (!image->file_mode) + return -EINVAL; + + if (image->nr_segments >= KEXEC_SEGMENT_MAX) + return -EINVAL; + + /* + * Make sure we are not trying to add buffer after allocating + * control pages. All segments need to be placed first before + * any control pages are allocated. As control page allocation + * logic goes through list of segments to make sure there are + * no destination overlaps. + */ + if (!list_empty(&image->control_pages)) { + WARN_ON(1); + return -EINVAL; + } + + memset(&buf, 0, sizeof(struct kexec_buf)); + kbuf = &buf; + kbuf->image = image; + kbuf->buffer = buffer; + kbuf->bufsz = bufsz; + + kbuf->memsz = ALIGN(memsz, PAGE_SIZE); + kbuf->buf_align = max(buf_align, PAGE_SIZE); + kbuf->buf_min = buf_min; + kbuf->buf_max = buf_max; + kbuf->top_down = top_down; + + /* Walk the RAM ranges and allocate a suitable range for the buffer */ + if (image->type == KEXEC_TYPE_CRASH) + ret = walk_iomem_res("Crash kernel", + IORESOURCE_MEM | IORESOURCE_BUSY, + crashk_res.start, crashk_res.end, kbuf, + locate_mem_hole_callback); + else + ret = walk_system_ram_res(0, -1, kbuf, + locate_mem_hole_callback); + if (ret != 1) { + /* A suitable memory range could not be found for buffer */ + return -EADDRNOTAVAIL; + } + + /* Found a suitable memory range */ + ksegment = &image->segment[image->nr_segments]; + ksegment->kbuf = kbuf->buffer; + ksegment->bufsz = kbuf->bufsz; + ksegment->mem = kbuf->mem; + ksegment->memsz = kbuf->memsz; + image->nr_segments++; + *load_addr = ksegment->mem; + return 0; +} + +/* Calculate and store the digest of segments */ +static int kexec_calculate_store_digests(struct kimage *image) +{ + struct crypto_shash *tfm; + struct shash_desc *desc; + int ret = 0, i, j, zero_buf_sz, sha_region_sz; + size_t desc_size, nullsz; + char *digest; + void *zero_buf; + struct kexec_sha_region *sha_regions; + struct purgatory_info *pi = &image->purgatory_info; + + zero_buf = __va(page_to_pfn(ZERO_PAGE(0)) << PAGE_SHIFT); + zero_buf_sz = PAGE_SIZE; + + tfm = crypto_alloc_shash("sha256", 0, 0); + if (IS_ERR(tfm)) { + ret = PTR_ERR(tfm); + goto out; + } + + desc_size = crypto_shash_descsize(tfm) + sizeof(*desc); + desc = kzalloc(desc_size, GFP_KERNEL); + if (!desc) { + ret = -ENOMEM; + goto out_free_tfm; + } + + sha_region_sz = KEXEC_SEGMENT_MAX * sizeof(struct kexec_sha_region); + sha_regions = vzalloc(sha_region_sz); + if (!sha_regions) + goto out_free_desc; + + desc->tfm = tfm; + desc->flags = 0; + + ret = crypto_shash_init(desc); + if (ret < 0) + goto out_free_sha_regions; + + digest = kzalloc(SHA256_DIGEST_SIZE, GFP_KERNEL); + if (!digest) { + ret = -ENOMEM; + goto out_free_sha_regions; + } + + for (j = i = 0; i < image->nr_segments; i++) { + struct kexec_segment *ksegment; + + ksegment = &image->segment[i]; + /* + * Skip purgatory as it will be modified once we put digest + * info in purgatory. + */ + if (ksegment->kbuf == pi->purgatory_buf) + continue; + + ret = crypto_shash_update(desc, ksegment->kbuf, + ksegment->bufsz); + if (ret) + break; + + /* + * Assume rest of the buffer is filled with zero and + * update digest accordingly. + */ + nullsz = ksegment->memsz - ksegment->bufsz; + while (nullsz) { + unsigned long bytes = nullsz; + + if (bytes > zero_buf_sz) + bytes = zero_buf_sz; + ret = crypto_shash_update(desc, zero_buf, bytes); + if (ret) + break; + nullsz -= bytes; + } + + if (ret) + break; + + sha_regions[j].start = ksegment->mem; + sha_regions[j].len = ksegment->memsz; + j++; + } + + if (!ret) { + ret = crypto_shash_final(desc, digest); + if (ret) + goto out_free_digest; + ret = kexec_purgatory_get_set_symbol(image, "sha_regions", + sha_regions, sha_region_sz, 0); + if (ret) + goto out_free_digest; + + ret = kexec_purgatory_get_set_symbol(image, "sha256_digest", + digest, SHA256_DIGEST_SIZE, 0); + if (ret) + goto out_free_digest; + } + +out_free_digest: + kfree(digest); +out_free_sha_regions: + vfree(sha_regions); +out_free_desc: + kfree(desc); +out_free_tfm: + kfree(tfm); +out: + return ret; +} + +/* Actually load purgatory. Lot of code taken from kexec-tools */ +static int __kexec_load_purgatory(struct kimage *image, unsigned long min, + unsigned long max, int top_down) +{ + struct purgatory_info *pi = &image->purgatory_info; + unsigned long align, buf_align, bss_align, buf_sz, bss_sz, bss_pad; + unsigned long memsz, entry, load_addr, curr_load_addr, bss_addr, offset; + unsigned char *buf_addr, *src; + int i, ret = 0, entry_sidx = -1; + const Elf_Shdr *sechdrs_c; + Elf_Shdr *sechdrs = NULL; + void *purgatory_buf = NULL; + + /* + * sechdrs_c points to section headers in purgatory and are read + * only. No modifications allowed. + */ + sechdrs_c = (void *)pi->ehdr + pi->ehdr->e_shoff; + + /* + * We can not modify sechdrs_c[] and its fields. It is read only. + * Copy it over to a local copy where one can store some temporary + * data and free it at the end. We need to modify ->sh_addr and + * ->sh_offset fields to keep track of permanent and temporary + * locations of sections. + */ + sechdrs = vzalloc(pi->ehdr->e_shnum * sizeof(Elf_Shdr)); + if (!sechdrs) + return -ENOMEM; + + memcpy(sechdrs, sechdrs_c, pi->ehdr->e_shnum * sizeof(Elf_Shdr)); + + /* + * We seem to have multiple copies of sections. First copy is which + * is embedded in kernel in read only section. Some of these sections + * will be copied to a temporary buffer and relocated. And these + * sections will finally be copied to their final destination at + * segment load time. + * + * Use ->sh_offset to reflect section address in memory. It will + * point to original read only copy if section is not allocatable. + * Otherwise it will point to temporary copy which will be relocated. + * + * Use ->sh_addr to contain final address of the section where it + * will go during execution time. + */ + for (i = 0; i < pi->ehdr->e_shnum; i++) { + if (sechdrs[i].sh_type == SHT_NOBITS) + continue; + + sechdrs[i].sh_offset = (unsigned long)pi->ehdr + + sechdrs[i].sh_offset; + } + + /* + * Identify entry point section and make entry relative to section + * start. + */ + entry = pi->ehdr->e_entry; + for (i = 0; i < pi->ehdr->e_shnum; i++) { + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + + if (!(sechdrs[i].sh_flags & SHF_EXECINSTR)) + continue; + + /* Make entry section relative */ + if (sechdrs[i].sh_addr <= pi->ehdr->e_entry && + ((sechdrs[i].sh_addr + sechdrs[i].sh_size) > + pi->ehdr->e_entry)) { + entry_sidx = i; + entry -= sechdrs[i].sh_addr; + break; + } + } + + /* Determine how much memory is needed to load relocatable object. */ + buf_align = 1; + bss_align = 1; + buf_sz = 0; + bss_sz = 0; + + for (i = 0; i < pi->ehdr->e_shnum; i++) { + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + + align = sechdrs[i].sh_addralign; + if (sechdrs[i].sh_type != SHT_NOBITS) { + if (buf_align < align) + buf_align = align; + buf_sz = ALIGN(buf_sz, align); + buf_sz += sechdrs[i].sh_size; + } else { + /* bss section */ + if (bss_align < align) + bss_align = align; + bss_sz = ALIGN(bss_sz, align); + bss_sz += sechdrs[i].sh_size; + } + } + + /* Determine the bss padding required to align bss properly */ + bss_pad = 0; + if (buf_sz & (bss_align - 1)) + bss_pad = bss_align - (buf_sz & (bss_align - 1)); + + memsz = buf_sz + bss_pad + bss_sz; + + /* Allocate buffer for purgatory */ + purgatory_buf = vzalloc(buf_sz); + if (!purgatory_buf) { + ret = -ENOMEM; + goto out; + } + + if (buf_align < bss_align) + buf_align = bss_align; + + /* Add buffer to segment list */ + ret = kexec_add_buffer(image, purgatory_buf, buf_sz, memsz, + buf_align, min, max, top_down, + &pi->purgatory_load_addr); + if (ret) + goto out; + + /* Load SHF_ALLOC sections */ + buf_addr = purgatory_buf; + load_addr = curr_load_addr = pi->purgatory_load_addr; + bss_addr = load_addr + buf_sz + bss_pad; + + for (i = 0; i < pi->ehdr->e_shnum; i++) { + if (!(sechdrs[i].sh_flags & SHF_ALLOC)) + continue; + + align = sechdrs[i].sh_addralign; + if (sechdrs[i].sh_type != SHT_NOBITS) { + curr_load_addr = ALIGN(curr_load_addr, align); + offset = curr_load_addr - load_addr; + /* We already modifed ->sh_offset to keep src addr */ + src = (char *) sechdrs[i].sh_offset; + memcpy(buf_addr + offset, src, sechdrs[i].sh_size); + + /* Store load address and source address of section */ + sechdrs[i].sh_addr = curr_load_addr; + + /* + * This section got copied to temporary buffer. Update + * ->sh_offset accordingly. + */ + sechdrs[i].sh_offset = (unsigned long)(buf_addr + offset); + + /* Advance to the next address */ + curr_load_addr += sechdrs[i].sh_size; + } else { + bss_addr = ALIGN(bss_addr, align); + sechdrs[i].sh_addr = bss_addr; + bss_addr += sechdrs[i].sh_size; + } + } + + /* Update entry point based on load address of text section */ + if (entry_sidx >= 0) + entry += sechdrs[entry_sidx].sh_addr; + + /* Make kernel jump to purgatory after shutdown */ + image->start = entry; + + /* Used later to get/set symbol values */ + pi->sechdrs = sechdrs; + + /* + * Used later to identify which section is purgatory and skip it + * from checksumming. + */ + pi->purgatory_buf = purgatory_buf; + return ret; +out: + vfree(sechdrs); + vfree(purgatory_buf); + return ret; +} + +static int kexec_apply_relocations(struct kimage *image) +{ + int i, ret; + struct purgatory_info *pi = &image->purgatory_info; + Elf_Shdr *sechdrs = pi->sechdrs; + + /* Apply relocations */ + for (i = 0; i < pi->ehdr->e_shnum; i++) { + Elf_Shdr *section, *symtab; + + if (sechdrs[i].sh_type != SHT_RELA && + sechdrs[i].sh_type != SHT_REL) + continue; + + /* + * For section of type SHT_RELA/SHT_REL, + * ->sh_link contains section header index of associated + * symbol table. And ->sh_info contains section header + * index of section to which relocations apply. + */ + if (sechdrs[i].sh_info >= pi->ehdr->e_shnum || + sechdrs[i].sh_link >= pi->ehdr->e_shnum) + return -ENOEXEC; + + section = &sechdrs[sechdrs[i].sh_info]; + symtab = &sechdrs[sechdrs[i].sh_link]; + + if (!(section->sh_flags & SHF_ALLOC)) + continue; + + /* + * symtab->sh_link contain section header index of associated + * string table. + */ + if (symtab->sh_link >= pi->ehdr->e_shnum) + /* Invalid section number? */ + continue; + + /* + * Respective architecture needs to provide support for applying + * relocations of type SHT_RELA/SHT_REL. + */ + if (sechdrs[i].sh_type == SHT_RELA) + ret = arch_kexec_apply_relocations_add(pi->ehdr, + sechdrs, i); + else if (sechdrs[i].sh_type == SHT_REL) + ret = arch_kexec_apply_relocations(pi->ehdr, + sechdrs, i); + if (ret) + return ret; + } + + return 0; +} + +/* Load relocatable purgatory object and relocate it appropriately */ +int kexec_load_purgatory(struct kimage *image, unsigned long min, + unsigned long max, int top_down, + unsigned long *load_addr) +{ + struct purgatory_info *pi = &image->purgatory_info; + int ret; + + if (kexec_purgatory_size <= 0) + return -EINVAL; + + if (kexec_purgatory_size < sizeof(Elf_Ehdr)) + return -ENOEXEC; + + pi->ehdr = (Elf_Ehdr *)kexec_purgatory; + + if (memcmp(pi->ehdr->e_ident, ELFMAG, SELFMAG) != 0 + || pi->ehdr->e_type != ET_REL + || !elf_check_arch(pi->ehdr) + || pi->ehdr->e_shentsize != sizeof(Elf_Shdr)) + return -ENOEXEC; + + if (pi->ehdr->e_shoff >= kexec_purgatory_size + || (pi->ehdr->e_shnum * sizeof(Elf_Shdr) > + kexec_purgatory_size - pi->ehdr->e_shoff)) + return -ENOEXEC; + + ret = __kexec_load_purgatory(image, min, max, top_down); + if (ret) + return ret; + + ret = kexec_apply_relocations(image); + if (ret) + goto out; + + *load_addr = pi->purgatory_load_addr; + return 0; +out: + vfree(pi->sechdrs); + vfree(pi->purgatory_buf); + return ret; +} + +static Elf_Sym *kexec_purgatory_find_symbol(struct purgatory_info *pi, + const char *name) +{ + Elf_Sym *syms; + Elf_Shdr *sechdrs; + Elf_Ehdr *ehdr; + int i, k; + const char *strtab; + + if (!pi->sechdrs || !pi->ehdr) + return NULL; + + sechdrs = pi->sechdrs; + ehdr = pi->ehdr; + + for (i = 0; i < ehdr->e_shnum; i++) { + if (sechdrs[i].sh_type != SHT_SYMTAB) + continue; + + if (sechdrs[i].sh_link >= ehdr->e_shnum) + /* Invalid strtab section number */ + continue; + strtab = (char *)sechdrs[sechdrs[i].sh_link].sh_offset; + syms = (Elf_Sym *)sechdrs[i].sh_offset; + + /* Go through symbols for a match */ + for (k = 0; k < sechdrs[i].sh_size/sizeof(Elf_Sym); k++) { + if (ELF_ST_BIND(syms[k].st_info) != STB_GLOBAL) + continue; + + if (strcmp(strtab + syms[k].st_name, name) != 0) + continue; + + if (syms[k].st_shndx == SHN_UNDEF || + syms[k].st_shndx >= ehdr->e_shnum) { + pr_debug("Symbol: %s has bad section index %d.\n", + name, syms[k].st_shndx); + return NULL; + } + + /* Found the symbol we are looking for */ + return &syms[k]; + } + } + + return NULL; +} + +void *kexec_purgatory_get_symbol_addr(struct kimage *image, const char *name) +{ + struct purgatory_info *pi = &image->purgatory_info; + Elf_Sym *sym; + Elf_Shdr *sechdr; + + sym = kexec_purgatory_find_symbol(pi, name); + if (!sym) + return ERR_PTR(-EINVAL); + + sechdr = &pi->sechdrs[sym->st_shndx]; + + /* + * Returns the address where symbol will finally be loaded after + * kexec_load_segment() + */ + return (void *)(sechdr->sh_addr + sym->st_value); +} + +/* + * Get or set value of a symbol. If "get_value" is true, symbol value is + * returned in buf otherwise symbol value is set based on value in buf. + */ +int kexec_purgatory_get_set_symbol(struct kimage *image, const char *name, + void *buf, unsigned int size, bool get_value) +{ + Elf_Sym *sym; + Elf_Shdr *sechdrs; + struct purgatory_info *pi = &image->purgatory_info; + char *sym_buf; + + sym = kexec_purgatory_find_symbol(pi, name); + if (!sym) + return -EINVAL; + + if (sym->st_size != size) { + pr_err("symbol %s size mismatch: expected %lu actual %u\n", + name, (unsigned long)sym->st_size, size); + return -EINVAL; + } + + sechdrs = pi->sechdrs; + + if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { + pr_err("symbol %s is in a bss section. Cannot %s\n", name, + get_value ? "get" : "set"); + return -EINVAL; + } + + sym_buf = (unsigned char *)sechdrs[sym->st_shndx].sh_offset + + sym->st_value; + + if (get_value) + memcpy((void *)buf, sym_buf, size); + else + memcpy((void *)sym_buf, buf, size); + + return 0; +} diff --git a/kernel/kexec_internal.h b/kernel/kexec_internal.h new file mode 100644 index 0000000000000..e4392a698ad4a --- /dev/null +++ b/kernel/kexec_internal.h @@ -0,0 +1,22 @@ +#ifndef LINUX_KEXEC_INTERNAL_H +#define LINUX_KEXEC_INTERNAL_H + +#include + +struct kimage *do_kimage_alloc_init(void); +int sanity_check_segment_list(struct kimage *image); +void kimage_free_page_list(struct list_head *list); +void kimage_free(struct kimage *image); +int kimage_load_segment(struct kimage *image, struct kexec_segment *segment); +void kimage_terminate(struct kimage *image); +int kimage_is_destination_range(struct kimage *image, + unsigned long start, unsigned long end); + +extern struct mutex kexec_mutex; + +#ifdef CONFIG_KEXEC_FILE +void kimage_file_post_load_cleanup(struct kimage *image); +#else /* CONFIG_KEXEC_FILE */ +static inline void kimage_file_post_load_cleanup(struct kimage *image) { } +#endif /* CONFIG_KEXEC_FILE */ +#endif /* LINUX_KEXEC_INTERNAL_H */ -- GitLab From 2965faa5e03d1e71e9ff9aa143fff39e0a77543a Mon Sep 17 00:00:00 2001 From: Dave Young Date: Wed, 9 Sep 2015 15:38:55 -0700 Subject: [PATCH 6962/7006] kexec: split kexec_load syscall from kexec core code There are two kexec load syscalls, kexec_load another and kexec_file_load. kexec_file_load has been splited as kernel/kexec_file.c. In this patch I split kexec_load syscall code to kernel/kexec.c. And add a new kconfig option KEXEC_CORE, so we can disable kexec_load and use kexec_file_load only, or vice verse. The original requirement is from Ted Ts'o, he want kexec kernel signature being checked with CONFIG_KEXEC_VERIFY_SIG enabled. But kexec-tools use kexec_load syscall can bypass the checking. Vivek Goyal proposed to create a common kconfig option so user can compile in only one syscall for loading kexec kernel. KEXEC/KEXEC_FILE selects KEXEC_CORE so that old config files still work. Because there's general code need CONFIG_KEXEC_CORE, so I updated all the architecture Kconfig with a new option KEXEC_CORE, and let KEXEC selects KEXEC_CORE in arch Kconfig. Also updated general kernel code with to kexec_load syscall. [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Dave Young Cc: Eric W. Biederman Cc: Vivek Goyal Cc: Petr Tesarik Cc: Theodore Ts'o Cc: Josh Boyer Cc: David Howells Cc: Geert Uytterhoeven Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/Kconfig | 3 + arch/arm/Kconfig | 1 + arch/ia64/Kconfig | 1 + arch/m68k/Kconfig | 1 + arch/mips/Kconfig | 1 + arch/powerpc/Kconfig | 1 + arch/s390/Kconfig | 1 + arch/sh/Kconfig | 1 + arch/tile/Kconfig | 1 + arch/x86/Kconfig | 3 +- arch/x86/boot/header.S | 2 +- arch/x86/include/asm/kdebug.h | 2 +- arch/x86/kernel/Makefile | 4 +- arch/x86/kernel/kvmclock.c | 4 +- arch/x86/kernel/reboot.c | 4 +- arch/x86/kernel/setup.c | 2 +- arch/x86/kernel/vmlinux.lds.S | 2 +- arch/x86/kvm/vmx.c | 8 +- arch/x86/platform/efi/efi.c | 4 +- arch/x86/platform/uv/uv_nmi.c | 6 +- drivers/firmware/efi/Kconfig | 2 +- drivers/pci/pci-driver.c | 2 +- include/linux/kexec.h | 6 +- init/initramfs.c | 4 +- kernel/Makefile | 1 + kernel/events/core.c | 2 +- kernel/kexec.c | 1495 +------------------------------- kernel/kexec_core.c | 1511 +++++++++++++++++++++++++++++++++ kernel/ksysfs.c | 6 +- kernel/printk/printk.c | 2 +- kernel/reboot.c | 2 +- kernel/sysctl.c | 2 +- 32 files changed, 1560 insertions(+), 1527 deletions(-) create mode 100644 kernel/kexec_core.c diff --git a/arch/Kconfig b/arch/Kconfig index 8f35649305804..4e949e58b1928 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -2,6 +2,9 @@ # General architecture dependent options # +config KEXEC_CORE + bool + config OPROFILE tristate "OProfile system profiling" depends on PROFILING diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 0d1b717e1eca6..72ad724c67ae9 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig @@ -2020,6 +2020,7 @@ config KEXEC bool "Kexec system call (EXPERIMENTAL)" depends on (!SMP || PM_SLEEP_SMP) depends on !CPU_V7M + select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig index 42a91a7aa2b08..eb0249e379811 100644 --- a/arch/ia64/Kconfig +++ b/arch/ia64/Kconfig @@ -518,6 +518,7 @@ source "drivers/sn/Kconfig" config KEXEC bool "kexec system call" depends on !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) + select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig index 2dd8f63bfbbb7..498b567f007b0 100644 --- a/arch/m68k/Kconfig +++ b/arch/m68k/Kconfig @@ -95,6 +95,7 @@ config MMU_SUN3 config KEXEC bool "kexec system call" depends on M68KCLASSIC + select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index 752acca8de1fa..e3aa5b0b4ef17 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -2597,6 +2597,7 @@ source "kernel/Kconfig.preempt" config KEXEC bool "Kexec system call" + select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index b447918b9e2c8..9a7057ec21541 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -420,6 +420,7 @@ config PPC64_SUPPORTS_MEMORY_FAILURE config KEXEC bool "kexec system call" depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP)) + select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 4827870f7a6d8..1d57000b1b24a 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig @@ -48,6 +48,7 @@ config ARCH_SUPPORTS_DEBUG_PAGEALLOC config KEXEC def_bool y + select KEXEC_CORE config AUDIT_ARCH def_bool y diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig index 50057fed819dd..d514df7e04dd4 100644 --- a/arch/sh/Kconfig +++ b/arch/sh/Kconfig @@ -602,6 +602,7 @@ source kernel/Kconfig.hz config KEXEC bool "kexec system call (EXPERIMENTAL)" depends on SUPERH32 && MMU + select KEXEC_CORE help kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig index 2ba12d7617234..106c21bd7f449 100644 --- a/arch/tile/Kconfig +++ b/arch/tile/Kconfig @@ -205,6 +205,7 @@ source "kernel/Kconfig.hz" config KEXEC bool "kexec system call" + select KEXEC_CORE ---help--- kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index cc0d73eac0479..7aef2d52daa0d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1754,6 +1754,7 @@ source kernel/Kconfig.hz config KEXEC bool "kexec system call" + select KEXEC_CORE ---help--- kexec is a system call that implements the ability to shutdown your current kernel, and to start another kernel. It is like a reboot @@ -1770,8 +1771,8 @@ config KEXEC config KEXEC_FILE bool "kexec file based system call" + select KEXEC_CORE select BUILD_BIN2C - depends on KEXEC depends on X86_64 depends on CRYPTO=y depends on CRYPTO_SHA256=y diff --git a/arch/x86/boot/header.S b/arch/x86/boot/header.S index 16ef02596db2d..2d6b309c8e9a1 100644 --- a/arch/x86/boot/header.S +++ b/arch/x86/boot/header.S @@ -414,7 +414,7 @@ xloadflags: # define XLF23 0 #endif -#if defined(CONFIG_X86_64) && defined(CONFIG_EFI) && defined(CONFIG_KEXEC) +#if defined(CONFIG_X86_64) && defined(CONFIG_EFI) && defined(CONFIG_KEXEC_CORE) # define XLF4 XLF_EFI_KEXEC #else # define XLF4 0 diff --git a/arch/x86/include/asm/kdebug.h b/arch/x86/include/asm/kdebug.h index 32ce71375b212..b130d59406fb1 100644 --- a/arch/x86/include/asm/kdebug.h +++ b/arch/x86/include/asm/kdebug.h @@ -29,7 +29,7 @@ extern void show_trace(struct task_struct *t, struct pt_regs *regs, extern void __show_regs(struct pt_regs *regs, int all); extern unsigned long oops_begin(void); extern void oops_end(unsigned long, struct pt_regs *, int signr); -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE extern int in_crash_kexec; #else /* no crash dump is ever in progress if no crash kernel can be kexec'd */ diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile index 9ffdf25e5b868..b1b78ffe01d06 100644 --- a/arch/x86/kernel/Makefile +++ b/arch/x86/kernel/Makefile @@ -71,8 +71,8 @@ obj-$(CONFIG_LIVEPATCH) += livepatch.o obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o obj-$(CONFIG_FTRACE_SYSCALLS) += ftrace.o obj-$(CONFIG_X86_TSC) += trace_clock.o -obj-$(CONFIG_KEXEC) += machine_kexec_$(BITS).o -obj-$(CONFIG_KEXEC) += relocate_kernel_$(BITS).o crash.o +obj-$(CONFIG_KEXEC_CORE) += machine_kexec_$(BITS).o +obj-$(CONFIG_KEXEC_CORE) += relocate_kernel_$(BITS).o crash.o obj-$(CONFIG_KEXEC_FILE) += kexec-bzimage64.o obj-$(CONFIG_CRASH_DUMP) += crash_dump_$(BITS).o obj-y += kprobes/ diff --git a/arch/x86/kernel/kvmclock.c b/arch/x86/kernel/kvmclock.c index 49487b4880616..2c7aafa707027 100644 --- a/arch/x86/kernel/kvmclock.c +++ b/arch/x86/kernel/kvmclock.c @@ -200,7 +200,7 @@ static void kvm_setup_secondary_clock(void) * kind of shutdown from our side, we unregister the clock by writting anything * that does not have the 'enable' bit set in the msr */ -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE static void kvm_crash_shutdown(struct pt_regs *regs) { native_write_msr(msr_kvm_system_time, 0, 0); @@ -259,7 +259,7 @@ void __init kvmclock_init(void) x86_platform.save_sched_clock_state = kvm_save_sched_clock_state; x86_platform.restore_sched_clock_state = kvm_restore_sched_clock_state; machine_ops.shutdown = kvm_shutdown; -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE machine_ops.crash_shutdown = kvm_crash_shutdown; #endif kvm_get_preset_lpj(); diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 86db4bcd7ce52..02693dd9a0790 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -673,7 +673,7 @@ struct machine_ops machine_ops = { .emergency_restart = native_machine_emergency_restart, .restart = native_machine_restart, .halt = native_machine_halt, -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE .crash_shutdown = native_machine_crash_shutdown, #endif }; @@ -703,7 +703,7 @@ void machine_halt(void) machine_ops.halt(); } -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE void machine_crash_shutdown(struct pt_regs *regs) { machine_ops.crash_shutdown(regs); diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index baadbf90a7c59..fdb7f2a2d3286 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -478,7 +478,7 @@ static void __init memblock_x86_reserve_range_setup_data(void) * --------- Crashkernel reservation ------------------------------ */ -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * Keep the crash kernel below this limit. On 32 bits earlier kernels diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S index 00bf300fd8468..74e4bf11f562e 100644 --- a/arch/x86/kernel/vmlinux.lds.S +++ b/arch/x86/kernel/vmlinux.lds.S @@ -364,7 +364,7 @@ INIT_PER_CPU(irq_stack_union); #endif /* CONFIG_X86_32 */ -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE #include . = ASSERT(kexec_control_code_size <= KEXEC_CONTROL_CODE_MAX_SIZE, diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index 148ea20160222..d01986832afc2 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -1264,7 +1264,7 @@ static void vmcs_load(struct vmcs *vmcs) vmcs, phys_addr); } -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * This bitmap is used to indicate whether the vmclear * operation is enabled on all cpus. All disabled by @@ -1302,7 +1302,7 @@ static void crash_vmclear_local_loaded_vmcss(void) #else static inline void crash_enable_local_vmclear(int cpu) { } static inline void crash_disable_local_vmclear(int cpu) { } -#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_KEXEC_CORE */ static void __loaded_vmcs_clear(void *arg) { @@ -10411,7 +10411,7 @@ static int __init vmx_init(void) if (r) return r; -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE rcu_assign_pointer(crash_vmclear_loaded_vmcss, crash_vmclear_local_loaded_vmcss); #endif @@ -10421,7 +10421,7 @@ static int __init vmx_init(void) static void __exit vmx_exit(void) { -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE RCU_INIT_POINTER(crash_vmclear_loaded_vmcss, NULL); synchronize_rcu(); #endif diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index e4308fe6afe81..1db84c0758b73 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -650,7 +650,7 @@ static void __init get_systab_virt_addr(efi_memory_desc_t *md) static void __init save_runtime_map(void) { -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE efi_memory_desc_t *md; void *tmp, *p, *q = NULL; int count = 0; @@ -748,7 +748,7 @@ static void * __init efi_map_regions(int *count, int *pg_shift) static void __init kexec_enter_virtual_mode(void) { -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE efi_memory_desc_t *md; void *p; diff --git a/arch/x86/platform/uv/uv_nmi.c b/arch/x86/platform/uv/uv_nmi.c index 020c101c255fe..5c9f63fa6abf2 100644 --- a/arch/x86/platform/uv/uv_nmi.c +++ b/arch/x86/platform/uv/uv_nmi.c @@ -492,7 +492,7 @@ static void uv_nmi_touch_watchdogs(void) touch_nmi_watchdog(); } -#if defined(CONFIG_KEXEC) +#if defined(CONFIG_KEXEC_CORE) static atomic_t uv_nmi_kexec_failed; static void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) { @@ -519,13 +519,13 @@ static void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) uv_nmi_sync_exit(0); } -#else /* !CONFIG_KEXEC */ +#else /* !CONFIG_KEXEC_CORE */ static inline void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs) { if (master) pr_err("UV: NMI kdump: KEXEC not supported in this kernel\n"); } -#endif /* !CONFIG_KEXEC */ +#endif /* !CONFIG_KEXEC_CORE */ #ifdef CONFIG_KGDB #ifdef CONFIG_KGDB_KDB diff --git a/drivers/firmware/efi/Kconfig b/drivers/firmware/efi/Kconfig index 54071c1483400..84533e02fbf8b 100644 --- a/drivers/firmware/efi/Kconfig +++ b/drivers/firmware/efi/Kconfig @@ -43,7 +43,7 @@ config EFI_VARS_PSTORE_DEFAULT_DISABLE config EFI_RUNTIME_MAP bool "Export efi runtime maps to sysfs" - depends on X86 && EFI && KEXEC + depends on X86 && EFI && KEXEC_CORE default y help Export efi runtime memory maps to /sys/firmware/efi/runtime-map. diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 52a880ca17683..dd652f2ae03db 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -467,7 +467,7 @@ static void pci_device_shutdown(struct device *dev) pci_msi_shutdown(pci_dev); pci_msix_shutdown(pci_dev); -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * If this is a kexec reboot, turn off Bus Master bit on the * device to tell it to not continue to do DMA. Don't touch diff --git a/include/linux/kexec.h b/include/linux/kexec.h index ab150ade0d187..d140b1e9faa71 100644 --- a/include/linux/kexec.h +++ b/include/linux/kexec.h @@ -16,7 +16,7 @@ #include -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE #include #include #include @@ -329,13 +329,13 @@ int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, unsigned int relsec); -#else /* !CONFIG_KEXEC */ +#else /* !CONFIG_KEXEC_CORE */ struct pt_regs; struct task_struct; static inline void crash_kexec(struct pt_regs *regs) { } static inline int kexec_should_crash(struct task_struct *p) { return 0; } #define kexec_in_progress false -#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_KEXEC_CORE */ #endif /* !defined(__ASSEBMLY__) */ diff --git a/init/initramfs.c b/init/initramfs.c index ad1bd7787bbb0..b32ad7d97ac94 100644 --- a/init/initramfs.c +++ b/init/initramfs.c @@ -526,14 +526,14 @@ extern unsigned long __initramfs_size; static void __init free_initrd(void) { -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE unsigned long crashk_start = (unsigned long)__va(crashk_res.start); unsigned long crashk_end = (unsigned long)__va(crashk_res.end); #endif if (do_retain_initrd) goto skip; -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * If the initrd region is overlapped with crashkernel reserved region, * free only memory that is not part of crashkernel region. diff --git a/kernel/Makefile b/kernel/Makefile index 1b4890af5a659..d4988410b410a 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -49,6 +49,7 @@ obj-$(CONFIG_MODULES) += module.o obj-$(CONFIG_MODULE_SIG) += module_signing.o obj-$(CONFIG_KALLSYMS) += kallsyms.o obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o +obj-$(CONFIG_KEXEC_CORE) += kexec_core.o obj-$(CONFIG_KEXEC) += kexec.o obj-$(CONFIG_KEXEC_FILE) += kexec_file.o obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o diff --git a/kernel/events/core.c b/kernel/events/core.c index e8183895691c6..f548f69c4299d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -9094,7 +9094,7 @@ static void perf_event_init_cpu(int cpu) mutex_unlock(&swhash->hlist_mutex); } -#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC +#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE static void __perf_event_exit_context(void *__info) { struct remove_event re = { .detach_group = true }; diff --git a/kernel/kexec.c b/kernel/kexec.c index 2d73ecfa55058..4c5edc357923a 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c @@ -1,148 +1,23 @@ /* - * kexec.c - kexec system call + * kexec.c - kexec_load system call * Copyright (C) 2002-2004 Eric Biederman * * This source code is licensed under the GNU General Public License, * Version 2. See the file COPYING for more details. */ -#define pr_fmt(fmt) "kexec: " fmt - #include #include #include -#include -#include #include #include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include +#include -#include -#include #include "kexec_internal.h" -DEFINE_MUTEX(kexec_mutex); - -/* Per cpu memory for storing cpu states in case of system crash. */ -note_buf_t __percpu *crash_notes; - -/* vmcoreinfo stuff */ -static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES]; -u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; -size_t vmcoreinfo_size; -size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data); - -/* Flag to indicate we are going to kexec a new kernel */ -bool kexec_in_progress = false; - - -/* Location of the reserved area for the crash kernel */ -struct resource crashk_res = { - .name = "Crash kernel", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_MEM -}; -struct resource crashk_low_res = { - .name = "Crash kernel", - .start = 0, - .end = 0, - .flags = IORESOURCE_BUSY | IORESOURCE_MEM -}; - -int kexec_should_crash(struct task_struct *p) -{ - /* - * If crash_kexec_post_notifiers is enabled, don't run - * crash_kexec() here yet, which must be run after panic - * notifiers in panic(). - */ - if (crash_kexec_post_notifiers) - return 0; - /* - * There are 4 panic() calls in do_exit() path, each of which - * corresponds to each of these 4 conditions. - */ - if (in_interrupt() || !p->pid || is_global_init(p) || panic_on_oops) - return 1; - return 0; -} - -/* - * When kexec transitions to the new kernel there is a one-to-one - * mapping between physical and virtual addresses. On processors - * where you can disable the MMU this is trivial, and easy. For - * others it is still a simple predictable page table to setup. - * - * In that environment kexec copies the new kernel to its final - * resting place. This means I can only support memory whose - * physical address can fit in an unsigned long. In particular - * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled. - * If the assembly stub has more restrictive requirements - * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be - * defined more restrictively in . - * - * The code for the transition from the current kernel to the - * the new kernel is placed in the control_code_buffer, whose size - * is given by KEXEC_CONTROL_PAGE_SIZE. In the best case only a single - * page of memory is necessary, but some architectures require more. - * Because this memory must be identity mapped in the transition from - * virtual to physical addresses it must live in the range - * 0 - TASK_SIZE, as only the user space mappings are arbitrarily - * modifiable. - * - * The assembly stub in the control code buffer is passed a linked list - * of descriptor pages detailing the source pages of the new kernel, - * and the destination addresses of those source pages. As this data - * structure is not used in the context of the current OS, it must - * be self-contained. - * - * The code has been made to work with highmem pages and will use a - * destination page in its final resting place (if it happens - * to allocate it). The end product of this is that most of the - * physical address space, and most of RAM can be used. - * - * Future directions include: - * - allocating a page table with the control code buffer identity - * mapped, to simplify machine_kexec and make kexec_on_panic more - * reliable. - */ - -/* - * KIMAGE_NO_DEST is an impossible destination address..., for - * allocating pages whose destination address we do not care about. - */ -#define KIMAGE_NO_DEST (-1UL) - -static struct page *kimage_alloc_page(struct kimage *image, - gfp_t gfp_mask, - unsigned long dest); - static int copy_user_segment_list(struct kimage *image, unsigned long nr_segments, struct kexec_segment __user *segments) @@ -160,123 +35,6 @@ static int copy_user_segment_list(struct kimage *image, return ret; } -int sanity_check_segment_list(struct kimage *image) -{ - int result, i; - unsigned long nr_segments = image->nr_segments; - - /* - * Verify we have good destination addresses. The caller is - * responsible for making certain we don't attempt to load - * the new image into invalid or reserved areas of RAM. This - * just verifies it is an address we can use. - * - * Since the kernel does everything in page size chunks ensure - * the destination addresses are page aligned. Too many - * special cases crop of when we don't do this. The most - * insidious is getting overlapping destination addresses - * simply because addresses are changed to page size - * granularity. - */ - result = -EADDRNOTAVAIL; - for (i = 0; i < nr_segments; i++) { - unsigned long mstart, mend; - - mstart = image->segment[i].mem; - mend = mstart + image->segment[i].memsz; - if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK)) - return result; - if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT) - return result; - } - - /* Verify our destination addresses do not overlap. - * If we alloed overlapping destination addresses - * through very weird things can happen with no - * easy explanation as one segment stops on another. - */ - result = -EINVAL; - for (i = 0; i < nr_segments; i++) { - unsigned long mstart, mend; - unsigned long j; - - mstart = image->segment[i].mem; - mend = mstart + image->segment[i].memsz; - for (j = 0; j < i; j++) { - unsigned long pstart, pend; - pstart = image->segment[j].mem; - pend = pstart + image->segment[j].memsz; - /* Do the segments overlap ? */ - if ((mend > pstart) && (mstart < pend)) - return result; - } - } - - /* Ensure our buffer sizes are strictly less than - * our memory sizes. This should always be the case, - * and it is easier to check up front than to be surprised - * later on. - */ - result = -EINVAL; - for (i = 0; i < nr_segments; i++) { - if (image->segment[i].bufsz > image->segment[i].memsz) - return result; - } - - /* - * Verify we have good destination addresses. Normally - * the caller is responsible for making certain we don't - * attempt to load the new image into invalid or reserved - * areas of RAM. But crash kernels are preloaded into a - * reserved area of ram. We must ensure the addresses - * are in the reserved area otherwise preloading the - * kernel could corrupt things. - */ - - if (image->type == KEXEC_TYPE_CRASH) { - result = -EADDRNOTAVAIL; - for (i = 0; i < nr_segments; i++) { - unsigned long mstart, mend; - - mstart = image->segment[i].mem; - mend = mstart + image->segment[i].memsz - 1; - /* Ensure we are within the crash kernel limits */ - if ((mstart < crashk_res.start) || - (mend > crashk_res.end)) - return result; - } - } - - return 0; -} - -struct kimage *do_kimage_alloc_init(void) -{ - struct kimage *image; - - /* Allocate a controlling structure */ - image = kzalloc(sizeof(*image), GFP_KERNEL); - if (!image) - return NULL; - - image->head = 0; - image->entry = &image->head; - image->last_entry = &image->head; - image->control_page = ~0; /* By default this does not apply */ - image->type = KEXEC_TYPE_DEFAULT; - - /* Initialize the list of control pages */ - INIT_LIST_HEAD(&image->control_pages); - - /* Initialize the list of destination pages */ - INIT_LIST_HEAD(&image->dest_pages); - - /* Initialize the list of unusable pages */ - INIT_LIST_HEAD(&image->unusable_pages); - - return image; -} - static int kimage_alloc_init(struct kimage **rimage, unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, @@ -343,597 +101,6 @@ out_free_image: return ret; } -int kimage_is_destination_range(struct kimage *image, - unsigned long start, - unsigned long end) -{ - unsigned long i; - - for (i = 0; i < image->nr_segments; i++) { - unsigned long mstart, mend; - - mstart = image->segment[i].mem; - mend = mstart + image->segment[i].memsz; - if ((end > mstart) && (start < mend)) - return 1; - } - - return 0; -} - -static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order) -{ - struct page *pages; - - pages = alloc_pages(gfp_mask, order); - if (pages) { - unsigned int count, i; - pages->mapping = NULL; - set_page_private(pages, order); - count = 1 << order; - for (i = 0; i < count; i++) - SetPageReserved(pages + i); - } - - return pages; -} - -static void kimage_free_pages(struct page *page) -{ - unsigned int order, count, i; - - order = page_private(page); - count = 1 << order; - for (i = 0; i < count; i++) - ClearPageReserved(page + i); - __free_pages(page, order); -} - -void kimage_free_page_list(struct list_head *list) -{ - struct list_head *pos, *next; - - list_for_each_safe(pos, next, list) { - struct page *page; - - page = list_entry(pos, struct page, lru); - list_del(&page->lru); - kimage_free_pages(page); - } -} - -static struct page *kimage_alloc_normal_control_pages(struct kimage *image, - unsigned int order) -{ - /* Control pages are special, they are the intermediaries - * that are needed while we copy the rest of the pages - * to their final resting place. As such they must - * not conflict with either the destination addresses - * or memory the kernel is already using. - * - * The only case where we really need more than one of - * these are for architectures where we cannot disable - * the MMU and must instead generate an identity mapped - * page table for all of the memory. - * - * At worst this runs in O(N) of the image size. - */ - struct list_head extra_pages; - struct page *pages; - unsigned int count; - - count = 1 << order; - INIT_LIST_HEAD(&extra_pages); - - /* Loop while I can allocate a page and the page allocated - * is a destination page. - */ - do { - unsigned long pfn, epfn, addr, eaddr; - - pages = kimage_alloc_pages(KEXEC_CONTROL_MEMORY_GFP, order); - if (!pages) - break; - pfn = page_to_pfn(pages); - epfn = pfn + count; - addr = pfn << PAGE_SHIFT; - eaddr = epfn << PAGE_SHIFT; - if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) || - kimage_is_destination_range(image, addr, eaddr)) { - list_add(&pages->lru, &extra_pages); - pages = NULL; - } - } while (!pages); - - if (pages) { - /* Remember the allocated page... */ - list_add(&pages->lru, &image->control_pages); - - /* Because the page is already in it's destination - * location we will never allocate another page at - * that address. Therefore kimage_alloc_pages - * will not return it (again) and we don't need - * to give it an entry in image->segment[]. - */ - } - /* Deal with the destination pages I have inadvertently allocated. - * - * Ideally I would convert multi-page allocations into single - * page allocations, and add everything to image->dest_pages. - * - * For now it is simpler to just free the pages. - */ - kimage_free_page_list(&extra_pages); - - return pages; -} - -static struct page *kimage_alloc_crash_control_pages(struct kimage *image, - unsigned int order) -{ - /* Control pages are special, they are the intermediaries - * that are needed while we copy the rest of the pages - * to their final resting place. As such they must - * not conflict with either the destination addresses - * or memory the kernel is already using. - * - * Control pages are also the only pags we must allocate - * when loading a crash kernel. All of the other pages - * are specified by the segments and we just memcpy - * into them directly. - * - * The only case where we really need more than one of - * these are for architectures where we cannot disable - * the MMU and must instead generate an identity mapped - * page table for all of the memory. - * - * Given the low demand this implements a very simple - * allocator that finds the first hole of the appropriate - * size in the reserved memory region, and allocates all - * of the memory up to and including the hole. - */ - unsigned long hole_start, hole_end, size; - struct page *pages; - - pages = NULL; - size = (1 << order) << PAGE_SHIFT; - hole_start = (image->control_page + (size - 1)) & ~(size - 1); - hole_end = hole_start + size - 1; - while (hole_end <= crashk_res.end) { - unsigned long i; - - if (hole_end > KEXEC_CRASH_CONTROL_MEMORY_LIMIT) - break; - /* See if I overlap any of the segments */ - for (i = 0; i < image->nr_segments; i++) { - unsigned long mstart, mend; - - mstart = image->segment[i].mem; - mend = mstart + image->segment[i].memsz - 1; - if ((hole_end >= mstart) && (hole_start <= mend)) { - /* Advance the hole to the end of the segment */ - hole_start = (mend + (size - 1)) & ~(size - 1); - hole_end = hole_start + size - 1; - break; - } - } - /* If I don't overlap any segments I have found my hole! */ - if (i == image->nr_segments) { - pages = pfn_to_page(hole_start >> PAGE_SHIFT); - break; - } - } - if (pages) - image->control_page = hole_end; - - return pages; -} - - -struct page *kimage_alloc_control_pages(struct kimage *image, - unsigned int order) -{ - struct page *pages = NULL; - - switch (image->type) { - case KEXEC_TYPE_DEFAULT: - pages = kimage_alloc_normal_control_pages(image, order); - break; - case KEXEC_TYPE_CRASH: - pages = kimage_alloc_crash_control_pages(image, order); - break; - } - - return pages; -} - -static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) -{ - if (*image->entry != 0) - image->entry++; - - if (image->entry == image->last_entry) { - kimage_entry_t *ind_page; - struct page *page; - - page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST); - if (!page) - return -ENOMEM; - - ind_page = page_address(page); - *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; - image->entry = ind_page; - image->last_entry = ind_page + - ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); - } - *image->entry = entry; - image->entry++; - *image->entry = 0; - - return 0; -} - -static int kimage_set_destination(struct kimage *image, - unsigned long destination) -{ - int result; - - destination &= PAGE_MASK; - result = kimage_add_entry(image, destination | IND_DESTINATION); - - return result; -} - - -static int kimage_add_page(struct kimage *image, unsigned long page) -{ - int result; - - page &= PAGE_MASK; - result = kimage_add_entry(image, page | IND_SOURCE); - - return result; -} - - -static void kimage_free_extra_pages(struct kimage *image) -{ - /* Walk through and free any extra destination pages I may have */ - kimage_free_page_list(&image->dest_pages); - - /* Walk through and free any unusable pages I have cached */ - kimage_free_page_list(&image->unusable_pages); - -} -void kimage_terminate(struct kimage *image) -{ - if (*image->entry != 0) - image->entry++; - - *image->entry = IND_DONE; -} - -#define for_each_kimage_entry(image, ptr, entry) \ - for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ - ptr = (entry & IND_INDIRECTION) ? \ - phys_to_virt((entry & PAGE_MASK)) : ptr + 1) - -static void kimage_free_entry(kimage_entry_t entry) -{ - struct page *page; - - page = pfn_to_page(entry >> PAGE_SHIFT); - kimage_free_pages(page); -} - -void kimage_free(struct kimage *image) -{ - kimage_entry_t *ptr, entry; - kimage_entry_t ind = 0; - - if (!image) - return; - - kimage_free_extra_pages(image); - for_each_kimage_entry(image, ptr, entry) { - if (entry & IND_INDIRECTION) { - /* Free the previous indirection page */ - if (ind & IND_INDIRECTION) - kimage_free_entry(ind); - /* Save this indirection page until we are - * done with it. - */ - ind = entry; - } else if (entry & IND_SOURCE) - kimage_free_entry(entry); - } - /* Free the final indirection page */ - if (ind & IND_INDIRECTION) - kimage_free_entry(ind); - - /* Handle any machine specific cleanup */ - machine_kexec_cleanup(image); - - /* Free the kexec control pages... */ - kimage_free_page_list(&image->control_pages); - - /* - * Free up any temporary buffers allocated. This might hit if - * error occurred much later after buffer allocation. - */ - if (image->file_mode) - kimage_file_post_load_cleanup(image); - - kfree(image); -} - -static kimage_entry_t *kimage_dst_used(struct kimage *image, - unsigned long page) -{ - kimage_entry_t *ptr, entry; - unsigned long destination = 0; - - for_each_kimage_entry(image, ptr, entry) { - if (entry & IND_DESTINATION) - destination = entry & PAGE_MASK; - else if (entry & IND_SOURCE) { - if (page == destination) - return ptr; - destination += PAGE_SIZE; - } - } - - return NULL; -} - -static struct page *kimage_alloc_page(struct kimage *image, - gfp_t gfp_mask, - unsigned long destination) -{ - /* - * Here we implement safeguards to ensure that a source page - * is not copied to its destination page before the data on - * the destination page is no longer useful. - * - * To do this we maintain the invariant that a source page is - * either its own destination page, or it is not a - * destination page at all. - * - * That is slightly stronger than required, but the proof - * that no problems will not occur is trivial, and the - * implementation is simply to verify. - * - * When allocating all pages normally this algorithm will run - * in O(N) time, but in the worst case it will run in O(N^2) - * time. If the runtime is a problem the data structures can - * be fixed. - */ - struct page *page; - unsigned long addr; - - /* - * Walk through the list of destination pages, and see if I - * have a match. - */ - list_for_each_entry(page, &image->dest_pages, lru) { - addr = page_to_pfn(page) << PAGE_SHIFT; - if (addr == destination) { - list_del(&page->lru); - return page; - } - } - page = NULL; - while (1) { - kimage_entry_t *old; - - /* Allocate a page, if we run out of memory give up */ - page = kimage_alloc_pages(gfp_mask, 0); - if (!page) - return NULL; - /* If the page cannot be used file it away */ - if (page_to_pfn(page) > - (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { - list_add(&page->lru, &image->unusable_pages); - continue; - } - addr = page_to_pfn(page) << PAGE_SHIFT; - - /* If it is the destination page we want use it */ - if (addr == destination) - break; - - /* If the page is not a destination page use it */ - if (!kimage_is_destination_range(image, addr, - addr + PAGE_SIZE)) - break; - - /* - * I know that the page is someones destination page. - * See if there is already a source page for this - * destination page. And if so swap the source pages. - */ - old = kimage_dst_used(image, addr); - if (old) { - /* If so move it */ - unsigned long old_addr; - struct page *old_page; - - old_addr = *old & PAGE_MASK; - old_page = pfn_to_page(old_addr >> PAGE_SHIFT); - copy_highpage(page, old_page); - *old = addr | (*old & ~PAGE_MASK); - - /* The old page I have found cannot be a - * destination page, so return it if it's - * gfp_flags honor the ones passed in. - */ - if (!(gfp_mask & __GFP_HIGHMEM) && - PageHighMem(old_page)) { - kimage_free_pages(old_page); - continue; - } - addr = old_addr; - page = old_page; - break; - } else { - /* Place the page on the destination list I - * will use it later. - */ - list_add(&page->lru, &image->dest_pages); - } - } - - return page; -} - -static int kimage_load_normal_segment(struct kimage *image, - struct kexec_segment *segment) -{ - unsigned long maddr; - size_t ubytes, mbytes; - int result; - unsigned char __user *buf = NULL; - unsigned char *kbuf = NULL; - - result = 0; - if (image->file_mode) - kbuf = segment->kbuf; - else - buf = segment->buf; - ubytes = segment->bufsz; - mbytes = segment->memsz; - maddr = segment->mem; - - result = kimage_set_destination(image, maddr); - if (result < 0) - goto out; - - while (mbytes) { - struct page *page; - char *ptr; - size_t uchunk, mchunk; - - page = kimage_alloc_page(image, GFP_HIGHUSER, maddr); - if (!page) { - result = -ENOMEM; - goto out; - } - result = kimage_add_page(image, page_to_pfn(page) - << PAGE_SHIFT); - if (result < 0) - goto out; - - ptr = kmap(page); - /* Start with a clear page */ - clear_page(ptr); - ptr += maddr & ~PAGE_MASK; - mchunk = min_t(size_t, mbytes, - PAGE_SIZE - (maddr & ~PAGE_MASK)); - uchunk = min(ubytes, mchunk); - - /* For file based kexec, source pages are in kernel memory */ - if (image->file_mode) - memcpy(ptr, kbuf, uchunk); - else - result = copy_from_user(ptr, buf, uchunk); - kunmap(page); - if (result) { - result = -EFAULT; - goto out; - } - ubytes -= uchunk; - maddr += mchunk; - if (image->file_mode) - kbuf += mchunk; - else - buf += mchunk; - mbytes -= mchunk; - } -out: - return result; -} - -static int kimage_load_crash_segment(struct kimage *image, - struct kexec_segment *segment) -{ - /* For crash dumps kernels we simply copy the data from - * user space to it's destination. - * We do things a page at a time for the sake of kmap. - */ - unsigned long maddr; - size_t ubytes, mbytes; - int result; - unsigned char __user *buf = NULL; - unsigned char *kbuf = NULL; - - result = 0; - if (image->file_mode) - kbuf = segment->kbuf; - else - buf = segment->buf; - ubytes = segment->bufsz; - mbytes = segment->memsz; - maddr = segment->mem; - while (mbytes) { - struct page *page; - char *ptr; - size_t uchunk, mchunk; - - page = pfn_to_page(maddr >> PAGE_SHIFT); - if (!page) { - result = -ENOMEM; - goto out; - } - ptr = kmap(page); - ptr += maddr & ~PAGE_MASK; - mchunk = min_t(size_t, mbytes, - PAGE_SIZE - (maddr & ~PAGE_MASK)); - uchunk = min(ubytes, mchunk); - if (mchunk > uchunk) { - /* Zero the trailing part of the page */ - memset(ptr + uchunk, 0, mchunk - uchunk); - } - - /* For file based kexec, source pages are in kernel memory */ - if (image->file_mode) - memcpy(ptr, kbuf, uchunk); - else - result = copy_from_user(ptr, buf, uchunk); - kexec_flush_icache_page(page); - kunmap(page); - if (result) { - result = -EFAULT; - goto out; - } - ubytes -= uchunk; - maddr += mchunk; - if (image->file_mode) - kbuf += mchunk; - else - buf += mchunk; - mbytes -= mchunk; - } -out: - return result; -} - -int kimage_load_segment(struct kimage *image, - struct kexec_segment *segment) -{ - int result = -ENOMEM; - - switch (image->type) { - case KEXEC_TYPE_DEFAULT: - result = kimage_load_normal_segment(image, segment); - break; - case KEXEC_TYPE_CRASH: - result = kimage_load_crash_segment(image, segment); - break; - } - - return result; -} - /* * Exec Kernel system call: for obvious reasons only root may call it. * @@ -954,9 +121,6 @@ int kimage_load_segment(struct kimage *image, * kexec does not sync, or unmount filesystems so if you need * that to happen you need to do that yourself. */ -struct kimage *kexec_image; -struct kimage *kexec_crash_image; -int kexec_load_disabled; SYSCALL_DEFINE4(kexec_load, unsigned long, entry, unsigned long, nr_segments, struct kexec_segment __user *, segments, unsigned long, flags) @@ -1051,18 +215,6 @@ out: return result; } -/* - * Add and remove page tables for crashkernel memory - * - * Provide an empty default implementation here -- architecture - * code may override this - */ -void __weak crash_map_reserved_pages(void) -{} - -void __weak crash_unmap_reserved_pages(void) -{} - #ifdef CONFIG_COMPAT COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry, compat_ulong_t, nr_segments, @@ -1101,646 +253,3 @@ COMPAT_SYSCALL_DEFINE4(kexec_load, compat_ulong_t, entry, return sys_kexec_load(entry, nr_segments, ksegments, flags); } #endif - -void crash_kexec(struct pt_regs *regs) -{ - /* Take the kexec_mutex here to prevent sys_kexec_load - * running on one cpu from replacing the crash kernel - * we are using after a panic on a different cpu. - * - * If the crash kernel was not located in a fixed area - * of memory the xchg(&kexec_crash_image) would be - * sufficient. But since I reuse the memory... - */ - if (mutex_trylock(&kexec_mutex)) { - if (kexec_crash_image) { - struct pt_regs fixed_regs; - - crash_setup_regs(&fixed_regs, regs); - crash_save_vmcoreinfo(); - machine_crash_shutdown(&fixed_regs); - machine_kexec(kexec_crash_image); - } - mutex_unlock(&kexec_mutex); - } -} - -size_t crash_get_memory_size(void) -{ - size_t size = 0; - mutex_lock(&kexec_mutex); - if (crashk_res.end != crashk_res.start) - size = resource_size(&crashk_res); - mutex_unlock(&kexec_mutex); - return size; -} - -void __weak crash_free_reserved_phys_range(unsigned long begin, - unsigned long end) -{ - unsigned long addr; - - for (addr = begin; addr < end; addr += PAGE_SIZE) - free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT)); -} - -int crash_shrink_memory(unsigned long new_size) -{ - int ret = 0; - unsigned long start, end; - unsigned long old_size; - struct resource *ram_res; - - mutex_lock(&kexec_mutex); - - if (kexec_crash_image) { - ret = -ENOENT; - goto unlock; - } - start = crashk_res.start; - end = crashk_res.end; - old_size = (end == 0) ? 0 : end - start + 1; - if (new_size >= old_size) { - ret = (new_size == old_size) ? 0 : -EINVAL; - goto unlock; - } - - ram_res = kzalloc(sizeof(*ram_res), GFP_KERNEL); - if (!ram_res) { - ret = -ENOMEM; - goto unlock; - } - - start = roundup(start, KEXEC_CRASH_MEM_ALIGN); - end = roundup(start + new_size, KEXEC_CRASH_MEM_ALIGN); - - crash_map_reserved_pages(); - crash_free_reserved_phys_range(end, crashk_res.end); - - if ((start == end) && (crashk_res.parent != NULL)) - release_resource(&crashk_res); - - ram_res->start = end; - ram_res->end = crashk_res.end; - ram_res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; - ram_res->name = "System RAM"; - - crashk_res.end = end - 1; - - insert_resource(&iomem_resource, ram_res); - crash_unmap_reserved_pages(); - -unlock: - mutex_unlock(&kexec_mutex); - return ret; -} - -static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, - size_t data_len) -{ - struct elf_note note; - - note.n_namesz = strlen(name) + 1; - note.n_descsz = data_len; - note.n_type = type; - memcpy(buf, ¬e, sizeof(note)); - buf += (sizeof(note) + 3)/4; - memcpy(buf, name, note.n_namesz); - buf += (note.n_namesz + 3)/4; - memcpy(buf, data, note.n_descsz); - buf += (note.n_descsz + 3)/4; - - return buf; -} - -static void final_note(u32 *buf) -{ - struct elf_note note; - - note.n_namesz = 0; - note.n_descsz = 0; - note.n_type = 0; - memcpy(buf, ¬e, sizeof(note)); -} - -void crash_save_cpu(struct pt_regs *regs, int cpu) -{ - struct elf_prstatus prstatus; - u32 *buf; - - if ((cpu < 0) || (cpu >= nr_cpu_ids)) - return; - - /* Using ELF notes here is opportunistic. - * I need a well defined structure format - * for the data I pass, and I need tags - * on the data to indicate what information I have - * squirrelled away. ELF notes happen to provide - * all of that, so there is no need to invent something new. - */ - buf = (u32 *)per_cpu_ptr(crash_notes, cpu); - if (!buf) - return; - memset(&prstatus, 0, sizeof(prstatus)); - prstatus.pr_pid = current->pid; - elf_core_copy_kernel_regs(&prstatus.pr_reg, regs); - buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, - &prstatus, sizeof(prstatus)); - final_note(buf); -} - -static int __init crash_notes_memory_init(void) -{ - /* Allocate memory for saving cpu registers. */ - crash_notes = alloc_percpu(note_buf_t); - if (!crash_notes) { - pr_warn("Kexec: Memory allocation for saving cpu register states failed\n"); - return -ENOMEM; - } - return 0; -} -subsys_initcall(crash_notes_memory_init); - - -/* - * parsing the "crashkernel" commandline - * - * this code is intended to be called from architecture specific code - */ - - -/* - * This function parses command lines in the format - * - * crashkernel=ramsize-range:size[,...][@offset] - * - * The function returns 0 on success and -EINVAL on failure. - */ -static int __init parse_crashkernel_mem(char *cmdline, - unsigned long long system_ram, - unsigned long long *crash_size, - unsigned long long *crash_base) -{ - char *cur = cmdline, *tmp; - - /* for each entry of the comma-separated list */ - do { - unsigned long long start, end = ULLONG_MAX, size; - - /* get the start of the range */ - start = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("crashkernel: Memory value expected\n"); - return -EINVAL; - } - cur = tmp; - if (*cur != '-') { - pr_warn("crashkernel: '-' expected\n"); - return -EINVAL; - } - cur++; - - /* if no ':' is here, than we read the end */ - if (*cur != ':') { - end = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("crashkernel: Memory value expected\n"); - return -EINVAL; - } - cur = tmp; - if (end <= start) { - pr_warn("crashkernel: end <= start\n"); - return -EINVAL; - } - } - - if (*cur != ':') { - pr_warn("crashkernel: ':' expected\n"); - return -EINVAL; - } - cur++; - - size = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("Memory value expected\n"); - return -EINVAL; - } - cur = tmp; - if (size >= system_ram) { - pr_warn("crashkernel: invalid size\n"); - return -EINVAL; - } - - /* match ? */ - if (system_ram >= start && system_ram < end) { - *crash_size = size; - break; - } - } while (*cur++ == ','); - - if (*crash_size > 0) { - while (*cur && *cur != ' ' && *cur != '@') - cur++; - if (*cur == '@') { - cur++; - *crash_base = memparse(cur, &tmp); - if (cur == tmp) { - pr_warn("Memory value expected after '@'\n"); - return -EINVAL; - } - } - } - - return 0; -} - -/* - * That function parses "simple" (old) crashkernel command lines like - * - * crashkernel=size[@offset] - * - * It returns 0 on success and -EINVAL on failure. - */ -static int __init parse_crashkernel_simple(char *cmdline, - unsigned long long *crash_size, - unsigned long long *crash_base) -{ - char *cur = cmdline; - - *crash_size = memparse(cmdline, &cur); - if (cmdline == cur) { - pr_warn("crashkernel: memory value expected\n"); - return -EINVAL; - } - - if (*cur == '@') - *crash_base = memparse(cur+1, &cur); - else if (*cur != ' ' && *cur != '\0') { - pr_warn("crashkernel: unrecognized char\n"); - return -EINVAL; - } - - return 0; -} - -#define SUFFIX_HIGH 0 -#define SUFFIX_LOW 1 -#define SUFFIX_NULL 2 -static __initdata char *suffix_tbl[] = { - [SUFFIX_HIGH] = ",high", - [SUFFIX_LOW] = ",low", - [SUFFIX_NULL] = NULL, -}; - -/* - * That function parses "suffix" crashkernel command lines like - * - * crashkernel=size,[high|low] - * - * It returns 0 on success and -EINVAL on failure. - */ -static int __init parse_crashkernel_suffix(char *cmdline, - unsigned long long *crash_size, - const char *suffix) -{ - char *cur = cmdline; - - *crash_size = memparse(cmdline, &cur); - if (cmdline == cur) { - pr_warn("crashkernel: memory value expected\n"); - return -EINVAL; - } - - /* check with suffix */ - if (strncmp(cur, suffix, strlen(suffix))) { - pr_warn("crashkernel: unrecognized char\n"); - return -EINVAL; - } - cur += strlen(suffix); - if (*cur != ' ' && *cur != '\0') { - pr_warn("crashkernel: unrecognized char\n"); - return -EINVAL; - } - - return 0; -} - -static __init char *get_last_crashkernel(char *cmdline, - const char *name, - const char *suffix) -{ - char *p = cmdline, *ck_cmdline = NULL; - - /* find crashkernel and use the last one if there are more */ - p = strstr(p, name); - while (p) { - char *end_p = strchr(p, ' '); - char *q; - - if (!end_p) - end_p = p + strlen(p); - - if (!suffix) { - int i; - - /* skip the one with any known suffix */ - for (i = 0; suffix_tbl[i]; i++) { - q = end_p - strlen(suffix_tbl[i]); - if (!strncmp(q, suffix_tbl[i], - strlen(suffix_tbl[i]))) - goto next; - } - ck_cmdline = p; - } else { - q = end_p - strlen(suffix); - if (!strncmp(q, suffix, strlen(suffix))) - ck_cmdline = p; - } -next: - p = strstr(p+1, name); - } - - if (!ck_cmdline) - return NULL; - - return ck_cmdline; -} - -static int __init __parse_crashkernel(char *cmdline, - unsigned long long system_ram, - unsigned long long *crash_size, - unsigned long long *crash_base, - const char *name, - const char *suffix) -{ - char *first_colon, *first_space; - char *ck_cmdline; - - BUG_ON(!crash_size || !crash_base); - *crash_size = 0; - *crash_base = 0; - - ck_cmdline = get_last_crashkernel(cmdline, name, suffix); - - if (!ck_cmdline) - return -EINVAL; - - ck_cmdline += strlen(name); - - if (suffix) - return parse_crashkernel_suffix(ck_cmdline, crash_size, - suffix); - /* - * if the commandline contains a ':', then that's the extended - * syntax -- if not, it must be the classic syntax - */ - first_colon = strchr(ck_cmdline, ':'); - first_space = strchr(ck_cmdline, ' '); - if (first_colon && (!first_space || first_colon < first_space)) - return parse_crashkernel_mem(ck_cmdline, system_ram, - crash_size, crash_base); - - return parse_crashkernel_simple(ck_cmdline, crash_size, crash_base); -} - -/* - * That function is the entry point for command line parsing and should be - * called from the arch-specific code. - */ -int __init parse_crashkernel(char *cmdline, - unsigned long long system_ram, - unsigned long long *crash_size, - unsigned long long *crash_base) -{ - return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, - "crashkernel=", NULL); -} - -int __init parse_crashkernel_high(char *cmdline, - unsigned long long system_ram, - unsigned long long *crash_size, - unsigned long long *crash_base) -{ - return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, - "crashkernel=", suffix_tbl[SUFFIX_HIGH]); -} - -int __init parse_crashkernel_low(char *cmdline, - unsigned long long system_ram, - unsigned long long *crash_size, - unsigned long long *crash_base) -{ - return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, - "crashkernel=", suffix_tbl[SUFFIX_LOW]); -} - -static void update_vmcoreinfo_note(void) -{ - u32 *buf = vmcoreinfo_note; - - if (!vmcoreinfo_size) - return; - buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data, - vmcoreinfo_size); - final_note(buf); -} - -void crash_save_vmcoreinfo(void) -{ - vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds()); - update_vmcoreinfo_note(); -} - -void vmcoreinfo_append_str(const char *fmt, ...) -{ - va_list args; - char buf[0x50]; - size_t r; - - va_start(args, fmt); - r = vscnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - r = min(r, vmcoreinfo_max_size - vmcoreinfo_size); - - memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r); - - vmcoreinfo_size += r; -} - -/* - * provide an empty default implementation here -- architecture - * code may override this - */ -void __weak arch_crash_save_vmcoreinfo(void) -{} - -unsigned long __weak paddr_vmcoreinfo_note(void) -{ - return __pa((unsigned long)(char *)&vmcoreinfo_note); -} - -static int __init crash_save_vmcoreinfo_init(void) -{ - VMCOREINFO_OSRELEASE(init_uts_ns.name.release); - VMCOREINFO_PAGESIZE(PAGE_SIZE); - - VMCOREINFO_SYMBOL(init_uts_ns); - VMCOREINFO_SYMBOL(node_online_map); -#ifdef CONFIG_MMU - VMCOREINFO_SYMBOL(swapper_pg_dir); -#endif - VMCOREINFO_SYMBOL(_stext); - VMCOREINFO_SYMBOL(vmap_area_list); - -#ifndef CONFIG_NEED_MULTIPLE_NODES - VMCOREINFO_SYMBOL(mem_map); - VMCOREINFO_SYMBOL(contig_page_data); -#endif -#ifdef CONFIG_SPARSEMEM - VMCOREINFO_SYMBOL(mem_section); - VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS); - VMCOREINFO_STRUCT_SIZE(mem_section); - VMCOREINFO_OFFSET(mem_section, section_mem_map); -#endif - VMCOREINFO_STRUCT_SIZE(page); - VMCOREINFO_STRUCT_SIZE(pglist_data); - VMCOREINFO_STRUCT_SIZE(zone); - VMCOREINFO_STRUCT_SIZE(free_area); - VMCOREINFO_STRUCT_SIZE(list_head); - VMCOREINFO_SIZE(nodemask_t); - VMCOREINFO_OFFSET(page, flags); - VMCOREINFO_OFFSET(page, _count); - VMCOREINFO_OFFSET(page, mapping); - VMCOREINFO_OFFSET(page, lru); - VMCOREINFO_OFFSET(page, _mapcount); - VMCOREINFO_OFFSET(page, private); - VMCOREINFO_OFFSET(pglist_data, node_zones); - VMCOREINFO_OFFSET(pglist_data, nr_zones); -#ifdef CONFIG_FLAT_NODE_MEM_MAP - VMCOREINFO_OFFSET(pglist_data, node_mem_map); -#endif - VMCOREINFO_OFFSET(pglist_data, node_start_pfn); - VMCOREINFO_OFFSET(pglist_data, node_spanned_pages); - VMCOREINFO_OFFSET(pglist_data, node_id); - VMCOREINFO_OFFSET(zone, free_area); - VMCOREINFO_OFFSET(zone, vm_stat); - VMCOREINFO_OFFSET(zone, spanned_pages); - VMCOREINFO_OFFSET(free_area, free_list); - VMCOREINFO_OFFSET(list_head, next); - VMCOREINFO_OFFSET(list_head, prev); - VMCOREINFO_OFFSET(vmap_area, va_start); - VMCOREINFO_OFFSET(vmap_area, list); - VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER); - log_buf_kexec_setup(); - VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES); - VMCOREINFO_NUMBER(NR_FREE_PAGES); - VMCOREINFO_NUMBER(PG_lru); - VMCOREINFO_NUMBER(PG_private); - VMCOREINFO_NUMBER(PG_swapcache); - VMCOREINFO_NUMBER(PG_slab); -#ifdef CONFIG_MEMORY_FAILURE - VMCOREINFO_NUMBER(PG_hwpoison); -#endif - VMCOREINFO_NUMBER(PG_head_mask); - VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE); -#ifdef CONFIG_HUGETLBFS - VMCOREINFO_SYMBOL(free_huge_page); -#endif - - arch_crash_save_vmcoreinfo(); - update_vmcoreinfo_note(); - - return 0; -} - -subsys_initcall(crash_save_vmcoreinfo_init); - -/* - * Move into place and start executing a preloaded standalone - * executable. If nothing was preloaded return an error. - */ -int kernel_kexec(void) -{ - int error = 0; - - if (!mutex_trylock(&kexec_mutex)) - return -EBUSY; - if (!kexec_image) { - error = -EINVAL; - goto Unlock; - } - -#ifdef CONFIG_KEXEC_JUMP - if (kexec_image->preserve_context) { - lock_system_sleep(); - pm_prepare_console(); - error = freeze_processes(); - if (error) { - error = -EBUSY; - goto Restore_console; - } - suspend_console(); - error = dpm_suspend_start(PMSG_FREEZE); - if (error) - goto Resume_console; - /* At this point, dpm_suspend_start() has been called, - * but *not* dpm_suspend_end(). We *must* call - * dpm_suspend_end() now. Otherwise, drivers for - * some devices (e.g. interrupt controllers) become - * desynchronized with the actual state of the - * hardware at resume time, and evil weirdness ensues. - */ - error = dpm_suspend_end(PMSG_FREEZE); - if (error) - goto Resume_devices; - error = disable_nonboot_cpus(); - if (error) - goto Enable_cpus; - local_irq_disable(); - error = syscore_suspend(); - if (error) - goto Enable_irqs; - } else -#endif - { - kexec_in_progress = true; - kernel_restart_prepare(NULL); - migrate_to_reboot_cpu(); - - /* - * migrate_to_reboot_cpu() disables CPU hotplug assuming that - * no further code needs to use CPU hotplug (which is true in - * the reboot case). However, the kexec path depends on using - * CPU hotplug again; so re-enable it here. - */ - cpu_hotplug_enable(); - pr_emerg("Starting new kernel\n"); - machine_shutdown(); - } - - machine_kexec(kexec_image); - -#ifdef CONFIG_KEXEC_JUMP - if (kexec_image->preserve_context) { - syscore_resume(); - Enable_irqs: - local_irq_enable(); - Enable_cpus: - enable_nonboot_cpus(); - dpm_resume_start(PMSG_RESTORE); - Resume_devices: - dpm_resume_end(PMSG_RESTORE); - Resume_console: - resume_console(); - thaw_processes(); - Restore_console: - pm_restore_console(); - unlock_system_sleep(); - } -#endif - - Unlock: - mutex_unlock(&kexec_mutex); - return error; -} diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c new file mode 100644 index 0000000000000..9aa25c034b2ef --- /dev/null +++ b/kernel/kexec_core.c @@ -0,0 +1,1511 @@ +/* + * kexec.c - kexec system call core code. + * Copyright (C) 2002-2004 Eric Biederman + * + * This source code is licensed under the GNU General Public License, + * Version 2. See the file COPYING for more details. + */ + +#define pr_fmt(fmt) "kexec: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "kexec_internal.h" + +DEFINE_MUTEX(kexec_mutex); + +/* Per cpu memory for storing cpu states in case of system crash. */ +note_buf_t __percpu *crash_notes; + +/* vmcoreinfo stuff */ +static unsigned char vmcoreinfo_data[VMCOREINFO_BYTES]; +u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; +size_t vmcoreinfo_size; +size_t vmcoreinfo_max_size = sizeof(vmcoreinfo_data); + +/* Flag to indicate we are going to kexec a new kernel */ +bool kexec_in_progress = false; + + +/* Location of the reserved area for the crash kernel */ +struct resource crashk_res = { + .name = "Crash kernel", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; +struct resource crashk_low_res = { + .name = "Crash kernel", + .start = 0, + .end = 0, + .flags = IORESOURCE_BUSY | IORESOURCE_MEM +}; + +int kexec_should_crash(struct task_struct *p) +{ + /* + * If crash_kexec_post_notifiers is enabled, don't run + * crash_kexec() here yet, which must be run after panic + * notifiers in panic(). + */ + if (crash_kexec_post_notifiers) + return 0; + /* + * There are 4 panic() calls in do_exit() path, each of which + * corresponds to each of these 4 conditions. + */ + if (in_interrupt() || !p->pid || is_global_init(p) || panic_on_oops) + return 1; + return 0; +} + +/* + * When kexec transitions to the new kernel there is a one-to-one + * mapping between physical and virtual addresses. On processors + * where you can disable the MMU this is trivial, and easy. For + * others it is still a simple predictable page table to setup. + * + * In that environment kexec copies the new kernel to its final + * resting place. This means I can only support memory whose + * physical address can fit in an unsigned long. In particular + * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled. + * If the assembly stub has more restrictive requirements + * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be + * defined more restrictively in . + * + * The code for the transition from the current kernel to the + * the new kernel is placed in the control_code_buffer, whose size + * is given by KEXEC_CONTROL_PAGE_SIZE. In the best case only a single + * page of memory is necessary, but some architectures require more. + * Because this memory must be identity mapped in the transition from + * virtual to physical addresses it must live in the range + * 0 - TASK_SIZE, as only the user space mappings are arbitrarily + * modifiable. + * + * The assembly stub in the control code buffer is passed a linked list + * of descriptor pages detailing the source pages of the new kernel, + * and the destination addresses of those source pages. As this data + * structure is not used in the context of the current OS, it must + * be self-contained. + * + * The code has been made to work with highmem pages and will use a + * destination page in its final resting place (if it happens + * to allocate it). The end product of this is that most of the + * physical address space, and most of RAM can be used. + * + * Future directions include: + * - allocating a page table with the control code buffer identity + * mapped, to simplify machine_kexec and make kexec_on_panic more + * reliable. + */ + +/* + * KIMAGE_NO_DEST is an impossible destination address..., for + * allocating pages whose destination address we do not care about. + */ +#define KIMAGE_NO_DEST (-1UL) + +static struct page *kimage_alloc_page(struct kimage *image, + gfp_t gfp_mask, + unsigned long dest); + +int sanity_check_segment_list(struct kimage *image) +{ + int result, i; + unsigned long nr_segments = image->nr_segments; + + /* + * Verify we have good destination addresses. The caller is + * responsible for making certain we don't attempt to load + * the new image into invalid or reserved areas of RAM. This + * just verifies it is an address we can use. + * + * Since the kernel does everything in page size chunks ensure + * the destination addresses are page aligned. Too many + * special cases crop of when we don't do this. The most + * insidious is getting overlapping destination addresses + * simply because addresses are changed to page size + * granularity. + */ + result = -EADDRNOTAVAIL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK)) + return result; + if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT) + return result; + } + + /* Verify our destination addresses do not overlap. + * If we alloed overlapping destination addresses + * through very weird things can happen with no + * easy explanation as one segment stops on another. + */ + result = -EINVAL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + unsigned long j; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + for (j = 0; j < i; j++) { + unsigned long pstart, pend; + + pstart = image->segment[j].mem; + pend = pstart + image->segment[j].memsz; + /* Do the segments overlap ? */ + if ((mend > pstart) && (mstart < pend)) + return result; + } + } + + /* Ensure our buffer sizes are strictly less than + * our memory sizes. This should always be the case, + * and it is easier to check up front than to be surprised + * later on. + */ + result = -EINVAL; + for (i = 0; i < nr_segments; i++) { + if (image->segment[i].bufsz > image->segment[i].memsz) + return result; + } + + /* + * Verify we have good destination addresses. Normally + * the caller is responsible for making certain we don't + * attempt to load the new image into invalid or reserved + * areas of RAM. But crash kernels are preloaded into a + * reserved area of ram. We must ensure the addresses + * are in the reserved area otherwise preloading the + * kernel could corrupt things. + */ + + if (image->type == KEXEC_TYPE_CRASH) { + result = -EADDRNOTAVAIL; + for (i = 0; i < nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz - 1; + /* Ensure we are within the crash kernel limits */ + if ((mstart < crashk_res.start) || + (mend > crashk_res.end)) + return result; + } + } + + return 0; +} + +struct kimage *do_kimage_alloc_init(void) +{ + struct kimage *image; + + /* Allocate a controlling structure */ + image = kzalloc(sizeof(*image), GFP_KERNEL); + if (!image) + return NULL; + + image->head = 0; + image->entry = &image->head; + image->last_entry = &image->head; + image->control_page = ~0; /* By default this does not apply */ + image->type = KEXEC_TYPE_DEFAULT; + + /* Initialize the list of control pages */ + INIT_LIST_HEAD(&image->control_pages); + + /* Initialize the list of destination pages */ + INIT_LIST_HEAD(&image->dest_pages); + + /* Initialize the list of unusable pages */ + INIT_LIST_HEAD(&image->unusable_pages); + + return image; +} + +int kimage_is_destination_range(struct kimage *image, + unsigned long start, + unsigned long end) +{ + unsigned long i; + + for (i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz; + if ((end > mstart) && (start < mend)) + return 1; + } + + return 0; +} + +static struct page *kimage_alloc_pages(gfp_t gfp_mask, unsigned int order) +{ + struct page *pages; + + pages = alloc_pages(gfp_mask, order); + if (pages) { + unsigned int count, i; + + pages->mapping = NULL; + set_page_private(pages, order); + count = 1 << order; + for (i = 0; i < count; i++) + SetPageReserved(pages + i); + } + + return pages; +} + +static void kimage_free_pages(struct page *page) +{ + unsigned int order, count, i; + + order = page_private(page); + count = 1 << order; + for (i = 0; i < count; i++) + ClearPageReserved(page + i); + __free_pages(page, order); +} + +void kimage_free_page_list(struct list_head *list) +{ + struct list_head *pos, *next; + + list_for_each_safe(pos, next, list) { + struct page *page; + + page = list_entry(pos, struct page, lru); + list_del(&page->lru); + kimage_free_pages(page); + } +} + +static struct page *kimage_alloc_normal_control_pages(struct kimage *image, + unsigned int order) +{ + /* Control pages are special, they are the intermediaries + * that are needed while we copy the rest of the pages + * to their final resting place. As such they must + * not conflict with either the destination addresses + * or memory the kernel is already using. + * + * The only case where we really need more than one of + * these are for architectures where we cannot disable + * the MMU and must instead generate an identity mapped + * page table for all of the memory. + * + * At worst this runs in O(N) of the image size. + */ + struct list_head extra_pages; + struct page *pages; + unsigned int count; + + count = 1 << order; + INIT_LIST_HEAD(&extra_pages); + + /* Loop while I can allocate a page and the page allocated + * is a destination page. + */ + do { + unsigned long pfn, epfn, addr, eaddr; + + pages = kimage_alloc_pages(KEXEC_CONTROL_MEMORY_GFP, order); + if (!pages) + break; + pfn = page_to_pfn(pages); + epfn = pfn + count; + addr = pfn << PAGE_SHIFT; + eaddr = epfn << PAGE_SHIFT; + if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) || + kimage_is_destination_range(image, addr, eaddr)) { + list_add(&pages->lru, &extra_pages); + pages = NULL; + } + } while (!pages); + + if (pages) { + /* Remember the allocated page... */ + list_add(&pages->lru, &image->control_pages); + + /* Because the page is already in it's destination + * location we will never allocate another page at + * that address. Therefore kimage_alloc_pages + * will not return it (again) and we don't need + * to give it an entry in image->segment[]. + */ + } + /* Deal with the destination pages I have inadvertently allocated. + * + * Ideally I would convert multi-page allocations into single + * page allocations, and add everything to image->dest_pages. + * + * For now it is simpler to just free the pages. + */ + kimage_free_page_list(&extra_pages); + + return pages; +} + +static struct page *kimage_alloc_crash_control_pages(struct kimage *image, + unsigned int order) +{ + /* Control pages are special, they are the intermediaries + * that are needed while we copy the rest of the pages + * to their final resting place. As such they must + * not conflict with either the destination addresses + * or memory the kernel is already using. + * + * Control pages are also the only pags we must allocate + * when loading a crash kernel. All of the other pages + * are specified by the segments and we just memcpy + * into them directly. + * + * The only case where we really need more than one of + * these are for architectures where we cannot disable + * the MMU and must instead generate an identity mapped + * page table for all of the memory. + * + * Given the low demand this implements a very simple + * allocator that finds the first hole of the appropriate + * size in the reserved memory region, and allocates all + * of the memory up to and including the hole. + */ + unsigned long hole_start, hole_end, size; + struct page *pages; + + pages = NULL; + size = (1 << order) << PAGE_SHIFT; + hole_start = (image->control_page + (size - 1)) & ~(size - 1); + hole_end = hole_start + size - 1; + while (hole_end <= crashk_res.end) { + unsigned long i; + + if (hole_end > KEXEC_CRASH_CONTROL_MEMORY_LIMIT) + break; + /* See if I overlap any of the segments */ + for (i = 0; i < image->nr_segments; i++) { + unsigned long mstart, mend; + + mstart = image->segment[i].mem; + mend = mstart + image->segment[i].memsz - 1; + if ((hole_end >= mstart) && (hole_start <= mend)) { + /* Advance the hole to the end of the segment */ + hole_start = (mend + (size - 1)) & ~(size - 1); + hole_end = hole_start + size - 1; + break; + } + } + /* If I don't overlap any segments I have found my hole! */ + if (i == image->nr_segments) { + pages = pfn_to_page(hole_start >> PAGE_SHIFT); + break; + } + } + if (pages) + image->control_page = hole_end; + + return pages; +} + + +struct page *kimage_alloc_control_pages(struct kimage *image, + unsigned int order) +{ + struct page *pages = NULL; + + switch (image->type) { + case KEXEC_TYPE_DEFAULT: + pages = kimage_alloc_normal_control_pages(image, order); + break; + case KEXEC_TYPE_CRASH: + pages = kimage_alloc_crash_control_pages(image, order); + break; + } + + return pages; +} + +static int kimage_add_entry(struct kimage *image, kimage_entry_t entry) +{ + if (*image->entry != 0) + image->entry++; + + if (image->entry == image->last_entry) { + kimage_entry_t *ind_page; + struct page *page; + + page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST); + if (!page) + return -ENOMEM; + + ind_page = page_address(page); + *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION; + image->entry = ind_page; + image->last_entry = ind_page + + ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1); + } + *image->entry = entry; + image->entry++; + *image->entry = 0; + + return 0; +} + +static int kimage_set_destination(struct kimage *image, + unsigned long destination) +{ + int result; + + destination &= PAGE_MASK; + result = kimage_add_entry(image, destination | IND_DESTINATION); + + return result; +} + + +static int kimage_add_page(struct kimage *image, unsigned long page) +{ + int result; + + page &= PAGE_MASK; + result = kimage_add_entry(image, page | IND_SOURCE); + + return result; +} + + +static void kimage_free_extra_pages(struct kimage *image) +{ + /* Walk through and free any extra destination pages I may have */ + kimage_free_page_list(&image->dest_pages); + + /* Walk through and free any unusable pages I have cached */ + kimage_free_page_list(&image->unusable_pages); + +} +void kimage_terminate(struct kimage *image) +{ + if (*image->entry != 0) + image->entry++; + + *image->entry = IND_DONE; +} + +#define for_each_kimage_entry(image, ptr, entry) \ + for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \ + ptr = (entry & IND_INDIRECTION) ? \ + phys_to_virt((entry & PAGE_MASK)) : ptr + 1) + +static void kimage_free_entry(kimage_entry_t entry) +{ + struct page *page; + + page = pfn_to_page(entry >> PAGE_SHIFT); + kimage_free_pages(page); +} + +void kimage_free(struct kimage *image) +{ + kimage_entry_t *ptr, entry; + kimage_entry_t ind = 0; + + if (!image) + return; + + kimage_free_extra_pages(image); + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_INDIRECTION) { + /* Free the previous indirection page */ + if (ind & IND_INDIRECTION) + kimage_free_entry(ind); + /* Save this indirection page until we are + * done with it. + */ + ind = entry; + } else if (entry & IND_SOURCE) + kimage_free_entry(entry); + } + /* Free the final indirection page */ + if (ind & IND_INDIRECTION) + kimage_free_entry(ind); + + /* Handle any machine specific cleanup */ + machine_kexec_cleanup(image); + + /* Free the kexec control pages... */ + kimage_free_page_list(&image->control_pages); + + /* + * Free up any temporary buffers allocated. This might hit if + * error occurred much later after buffer allocation. + */ + if (image->file_mode) + kimage_file_post_load_cleanup(image); + + kfree(image); +} + +static kimage_entry_t *kimage_dst_used(struct kimage *image, + unsigned long page) +{ + kimage_entry_t *ptr, entry; + unsigned long destination = 0; + + for_each_kimage_entry(image, ptr, entry) { + if (entry & IND_DESTINATION) + destination = entry & PAGE_MASK; + else if (entry & IND_SOURCE) { + if (page == destination) + return ptr; + destination += PAGE_SIZE; + } + } + + return NULL; +} + +static struct page *kimage_alloc_page(struct kimage *image, + gfp_t gfp_mask, + unsigned long destination) +{ + /* + * Here we implement safeguards to ensure that a source page + * is not copied to its destination page before the data on + * the destination page is no longer useful. + * + * To do this we maintain the invariant that a source page is + * either its own destination page, or it is not a + * destination page at all. + * + * That is slightly stronger than required, but the proof + * that no problems will not occur is trivial, and the + * implementation is simply to verify. + * + * When allocating all pages normally this algorithm will run + * in O(N) time, but in the worst case it will run in O(N^2) + * time. If the runtime is a problem the data structures can + * be fixed. + */ + struct page *page; + unsigned long addr; + + /* + * Walk through the list of destination pages, and see if I + * have a match. + */ + list_for_each_entry(page, &image->dest_pages, lru) { + addr = page_to_pfn(page) << PAGE_SHIFT; + if (addr == destination) { + list_del(&page->lru); + return page; + } + } + page = NULL; + while (1) { + kimage_entry_t *old; + + /* Allocate a page, if we run out of memory give up */ + page = kimage_alloc_pages(gfp_mask, 0); + if (!page) + return NULL; + /* If the page cannot be used file it away */ + if (page_to_pfn(page) > + (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) { + list_add(&page->lru, &image->unusable_pages); + continue; + } + addr = page_to_pfn(page) << PAGE_SHIFT; + + /* If it is the destination page we want use it */ + if (addr == destination) + break; + + /* If the page is not a destination page use it */ + if (!kimage_is_destination_range(image, addr, + addr + PAGE_SIZE)) + break; + + /* + * I know that the page is someones destination page. + * See if there is already a source page for this + * destination page. And if so swap the source pages. + */ + old = kimage_dst_used(image, addr); + if (old) { + /* If so move it */ + unsigned long old_addr; + struct page *old_page; + + old_addr = *old & PAGE_MASK; + old_page = pfn_to_page(old_addr >> PAGE_SHIFT); + copy_highpage(page, old_page); + *old = addr | (*old & ~PAGE_MASK); + + /* The old page I have found cannot be a + * destination page, so return it if it's + * gfp_flags honor the ones passed in. + */ + if (!(gfp_mask & __GFP_HIGHMEM) && + PageHighMem(old_page)) { + kimage_free_pages(old_page); + continue; + } + addr = old_addr; + page = old_page; + break; + } + /* Place the page on the destination list, to be used later */ + list_add(&page->lru, &image->dest_pages); + } + + return page; +} + +static int kimage_load_normal_segment(struct kimage *image, + struct kexec_segment *segment) +{ + unsigned long maddr; + size_t ubytes, mbytes; + int result; + unsigned char __user *buf = NULL; + unsigned char *kbuf = NULL; + + result = 0; + if (image->file_mode) + kbuf = segment->kbuf; + else + buf = segment->buf; + ubytes = segment->bufsz; + mbytes = segment->memsz; + maddr = segment->mem; + + result = kimage_set_destination(image, maddr); + if (result < 0) + goto out; + + while (mbytes) { + struct page *page; + char *ptr; + size_t uchunk, mchunk; + + page = kimage_alloc_page(image, GFP_HIGHUSER, maddr); + if (!page) { + result = -ENOMEM; + goto out; + } + result = kimage_add_page(image, page_to_pfn(page) + << PAGE_SHIFT); + if (result < 0) + goto out; + + ptr = kmap(page); + /* Start with a clear page */ + clear_page(ptr); + ptr += maddr & ~PAGE_MASK; + mchunk = min_t(size_t, mbytes, + PAGE_SIZE - (maddr & ~PAGE_MASK)); + uchunk = min(ubytes, mchunk); + + /* For file based kexec, source pages are in kernel memory */ + if (image->file_mode) + memcpy(ptr, kbuf, uchunk); + else + result = copy_from_user(ptr, buf, uchunk); + kunmap(page); + if (result) { + result = -EFAULT; + goto out; + } + ubytes -= uchunk; + maddr += mchunk; + if (image->file_mode) + kbuf += mchunk; + else + buf += mchunk; + mbytes -= mchunk; + } +out: + return result; +} + +static int kimage_load_crash_segment(struct kimage *image, + struct kexec_segment *segment) +{ + /* For crash dumps kernels we simply copy the data from + * user space to it's destination. + * We do things a page at a time for the sake of kmap. + */ + unsigned long maddr; + size_t ubytes, mbytes; + int result; + unsigned char __user *buf = NULL; + unsigned char *kbuf = NULL; + + result = 0; + if (image->file_mode) + kbuf = segment->kbuf; + else + buf = segment->buf; + ubytes = segment->bufsz; + mbytes = segment->memsz; + maddr = segment->mem; + while (mbytes) { + struct page *page; + char *ptr; + size_t uchunk, mchunk; + + page = pfn_to_page(maddr >> PAGE_SHIFT); + if (!page) { + result = -ENOMEM; + goto out; + } + ptr = kmap(page); + ptr += maddr & ~PAGE_MASK; + mchunk = min_t(size_t, mbytes, + PAGE_SIZE - (maddr & ~PAGE_MASK)); + uchunk = min(ubytes, mchunk); + if (mchunk > uchunk) { + /* Zero the trailing part of the page */ + memset(ptr + uchunk, 0, mchunk - uchunk); + } + + /* For file based kexec, source pages are in kernel memory */ + if (image->file_mode) + memcpy(ptr, kbuf, uchunk); + else + result = copy_from_user(ptr, buf, uchunk); + kexec_flush_icache_page(page); + kunmap(page); + if (result) { + result = -EFAULT; + goto out; + } + ubytes -= uchunk; + maddr += mchunk; + if (image->file_mode) + kbuf += mchunk; + else + buf += mchunk; + mbytes -= mchunk; + } +out: + return result; +} + +int kimage_load_segment(struct kimage *image, + struct kexec_segment *segment) +{ + int result = -ENOMEM; + + switch (image->type) { + case KEXEC_TYPE_DEFAULT: + result = kimage_load_normal_segment(image, segment); + break; + case KEXEC_TYPE_CRASH: + result = kimage_load_crash_segment(image, segment); + break; + } + + return result; +} + +struct kimage *kexec_image; +struct kimage *kexec_crash_image; +int kexec_load_disabled; + +void crash_kexec(struct pt_regs *regs) +{ + /* Take the kexec_mutex here to prevent sys_kexec_load + * running on one cpu from replacing the crash kernel + * we are using after a panic on a different cpu. + * + * If the crash kernel was not located in a fixed area + * of memory the xchg(&kexec_crash_image) would be + * sufficient. But since I reuse the memory... + */ + if (mutex_trylock(&kexec_mutex)) { + if (kexec_crash_image) { + struct pt_regs fixed_regs; + + crash_setup_regs(&fixed_regs, regs); + crash_save_vmcoreinfo(); + machine_crash_shutdown(&fixed_regs); + machine_kexec(kexec_crash_image); + } + mutex_unlock(&kexec_mutex); + } +} + +size_t crash_get_memory_size(void) +{ + size_t size = 0; + + mutex_lock(&kexec_mutex); + if (crashk_res.end != crashk_res.start) + size = resource_size(&crashk_res); + mutex_unlock(&kexec_mutex); + return size; +} + +void __weak crash_free_reserved_phys_range(unsigned long begin, + unsigned long end) +{ + unsigned long addr; + + for (addr = begin; addr < end; addr += PAGE_SIZE) + free_reserved_page(pfn_to_page(addr >> PAGE_SHIFT)); +} + +int crash_shrink_memory(unsigned long new_size) +{ + int ret = 0; + unsigned long start, end; + unsigned long old_size; + struct resource *ram_res; + + mutex_lock(&kexec_mutex); + + if (kexec_crash_image) { + ret = -ENOENT; + goto unlock; + } + start = crashk_res.start; + end = crashk_res.end; + old_size = (end == 0) ? 0 : end - start + 1; + if (new_size >= old_size) { + ret = (new_size == old_size) ? 0 : -EINVAL; + goto unlock; + } + + ram_res = kzalloc(sizeof(*ram_res), GFP_KERNEL); + if (!ram_res) { + ret = -ENOMEM; + goto unlock; + } + + start = roundup(start, KEXEC_CRASH_MEM_ALIGN); + end = roundup(start + new_size, KEXEC_CRASH_MEM_ALIGN); + + crash_map_reserved_pages(); + crash_free_reserved_phys_range(end, crashk_res.end); + + if ((start == end) && (crashk_res.parent != NULL)) + release_resource(&crashk_res); + + ram_res->start = end; + ram_res->end = crashk_res.end; + ram_res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + ram_res->name = "System RAM"; + + crashk_res.end = end - 1; + + insert_resource(&iomem_resource, ram_res); + crash_unmap_reserved_pages(); + +unlock: + mutex_unlock(&kexec_mutex); + return ret; +} + +static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data, + size_t data_len) +{ + struct elf_note note; + + note.n_namesz = strlen(name) + 1; + note.n_descsz = data_len; + note.n_type = type; + memcpy(buf, ¬e, sizeof(note)); + buf += (sizeof(note) + 3)/4; + memcpy(buf, name, note.n_namesz); + buf += (note.n_namesz + 3)/4; + memcpy(buf, data, note.n_descsz); + buf += (note.n_descsz + 3)/4; + + return buf; +} + +static void final_note(u32 *buf) +{ + struct elf_note note; + + note.n_namesz = 0; + note.n_descsz = 0; + note.n_type = 0; + memcpy(buf, ¬e, sizeof(note)); +} + +void crash_save_cpu(struct pt_regs *regs, int cpu) +{ + struct elf_prstatus prstatus; + u32 *buf; + + if ((cpu < 0) || (cpu >= nr_cpu_ids)) + return; + + /* Using ELF notes here is opportunistic. + * I need a well defined structure format + * for the data I pass, and I need tags + * on the data to indicate what information I have + * squirrelled away. ELF notes happen to provide + * all of that, so there is no need to invent something new. + */ + buf = (u32 *)per_cpu_ptr(crash_notes, cpu); + if (!buf) + return; + memset(&prstatus, 0, sizeof(prstatus)); + prstatus.pr_pid = current->pid; + elf_core_copy_kernel_regs(&prstatus.pr_reg, regs); + buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS, + &prstatus, sizeof(prstatus)); + final_note(buf); +} + +static int __init crash_notes_memory_init(void) +{ + /* Allocate memory for saving cpu registers. */ + crash_notes = alloc_percpu(note_buf_t); + if (!crash_notes) { + pr_warn("Kexec: Memory allocation for saving cpu register states failed\n"); + return -ENOMEM; + } + return 0; +} +subsys_initcall(crash_notes_memory_init); + + +/* + * parsing the "crashkernel" commandline + * + * this code is intended to be called from architecture specific code + */ + + +/* + * This function parses command lines in the format + * + * crashkernel=ramsize-range:size[,...][@offset] + * + * The function returns 0 on success and -EINVAL on failure. + */ +static int __init parse_crashkernel_mem(char *cmdline, + unsigned long long system_ram, + unsigned long long *crash_size, + unsigned long long *crash_base) +{ + char *cur = cmdline, *tmp; + + /* for each entry of the comma-separated list */ + do { + unsigned long long start, end = ULLONG_MAX, size; + + /* get the start of the range */ + start = memparse(cur, &tmp); + if (cur == tmp) { + pr_warn("crashkernel: Memory value expected\n"); + return -EINVAL; + } + cur = tmp; + if (*cur != '-') { + pr_warn("crashkernel: '-' expected\n"); + return -EINVAL; + } + cur++; + + /* if no ':' is here, than we read the end */ + if (*cur != ':') { + end = memparse(cur, &tmp); + if (cur == tmp) { + pr_warn("crashkernel: Memory value expected\n"); + return -EINVAL; + } + cur = tmp; + if (end <= start) { + pr_warn("crashkernel: end <= start\n"); + return -EINVAL; + } + } + + if (*cur != ':') { + pr_warn("crashkernel: ':' expected\n"); + return -EINVAL; + } + cur++; + + size = memparse(cur, &tmp); + if (cur == tmp) { + pr_warn("Memory value expected\n"); + return -EINVAL; + } + cur = tmp; + if (size >= system_ram) { + pr_warn("crashkernel: invalid size\n"); + return -EINVAL; + } + + /* match ? */ + if (system_ram >= start && system_ram < end) { + *crash_size = size; + break; + } + } while (*cur++ == ','); + + if (*crash_size > 0) { + while (*cur && *cur != ' ' && *cur != '@') + cur++; + if (*cur == '@') { + cur++; + *crash_base = memparse(cur, &tmp); + if (cur == tmp) { + pr_warn("Memory value expected after '@'\n"); + return -EINVAL; + } + } + } + + return 0; +} + +/* + * That function parses "simple" (old) crashkernel command lines like + * + * crashkernel=size[@offset] + * + * It returns 0 on success and -EINVAL on failure. + */ +static int __init parse_crashkernel_simple(char *cmdline, + unsigned long long *crash_size, + unsigned long long *crash_base) +{ + char *cur = cmdline; + + *crash_size = memparse(cmdline, &cur); + if (cmdline == cur) { + pr_warn("crashkernel: memory value expected\n"); + return -EINVAL; + } + + if (*cur == '@') + *crash_base = memparse(cur+1, &cur); + else if (*cur != ' ' && *cur != '\0') { + pr_warn("crashkernel: unrecognized char\n"); + return -EINVAL; + } + + return 0; +} + +#define SUFFIX_HIGH 0 +#define SUFFIX_LOW 1 +#define SUFFIX_NULL 2 +static __initdata char *suffix_tbl[] = { + [SUFFIX_HIGH] = ",high", + [SUFFIX_LOW] = ",low", + [SUFFIX_NULL] = NULL, +}; + +/* + * That function parses "suffix" crashkernel command lines like + * + * crashkernel=size,[high|low] + * + * It returns 0 on success and -EINVAL on failure. + */ +static int __init parse_crashkernel_suffix(char *cmdline, + unsigned long long *crash_size, + const char *suffix) +{ + char *cur = cmdline; + + *crash_size = memparse(cmdline, &cur); + if (cmdline == cur) { + pr_warn("crashkernel: memory value expected\n"); + return -EINVAL; + } + + /* check with suffix */ + if (strncmp(cur, suffix, strlen(suffix))) { + pr_warn("crashkernel: unrecognized char\n"); + return -EINVAL; + } + cur += strlen(suffix); + if (*cur != ' ' && *cur != '\0') { + pr_warn("crashkernel: unrecognized char\n"); + return -EINVAL; + } + + return 0; +} + +static __init char *get_last_crashkernel(char *cmdline, + const char *name, + const char *suffix) +{ + char *p = cmdline, *ck_cmdline = NULL; + + /* find crashkernel and use the last one if there are more */ + p = strstr(p, name); + while (p) { + char *end_p = strchr(p, ' '); + char *q; + + if (!end_p) + end_p = p + strlen(p); + + if (!suffix) { + int i; + + /* skip the one with any known suffix */ + for (i = 0; suffix_tbl[i]; i++) { + q = end_p - strlen(suffix_tbl[i]); + if (!strncmp(q, suffix_tbl[i], + strlen(suffix_tbl[i]))) + goto next; + } + ck_cmdline = p; + } else { + q = end_p - strlen(suffix); + if (!strncmp(q, suffix, strlen(suffix))) + ck_cmdline = p; + } +next: + p = strstr(p+1, name); + } + + if (!ck_cmdline) + return NULL; + + return ck_cmdline; +} + +static int __init __parse_crashkernel(char *cmdline, + unsigned long long system_ram, + unsigned long long *crash_size, + unsigned long long *crash_base, + const char *name, + const char *suffix) +{ + char *first_colon, *first_space; + char *ck_cmdline; + + BUG_ON(!crash_size || !crash_base); + *crash_size = 0; + *crash_base = 0; + + ck_cmdline = get_last_crashkernel(cmdline, name, suffix); + + if (!ck_cmdline) + return -EINVAL; + + ck_cmdline += strlen(name); + + if (suffix) + return parse_crashkernel_suffix(ck_cmdline, crash_size, + suffix); + /* + * if the commandline contains a ':', then that's the extended + * syntax -- if not, it must be the classic syntax + */ + first_colon = strchr(ck_cmdline, ':'); + first_space = strchr(ck_cmdline, ' '); + if (first_colon && (!first_space || first_colon < first_space)) + return parse_crashkernel_mem(ck_cmdline, system_ram, + crash_size, crash_base); + + return parse_crashkernel_simple(ck_cmdline, crash_size, crash_base); +} + +/* + * That function is the entry point for command line parsing and should be + * called from the arch-specific code. + */ +int __init parse_crashkernel(char *cmdline, + unsigned long long system_ram, + unsigned long long *crash_size, + unsigned long long *crash_base) +{ + return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, + "crashkernel=", NULL); +} + +int __init parse_crashkernel_high(char *cmdline, + unsigned long long system_ram, + unsigned long long *crash_size, + unsigned long long *crash_base) +{ + return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, + "crashkernel=", suffix_tbl[SUFFIX_HIGH]); +} + +int __init parse_crashkernel_low(char *cmdline, + unsigned long long system_ram, + unsigned long long *crash_size, + unsigned long long *crash_base) +{ + return __parse_crashkernel(cmdline, system_ram, crash_size, crash_base, + "crashkernel=", suffix_tbl[SUFFIX_LOW]); +} + +static void update_vmcoreinfo_note(void) +{ + u32 *buf = vmcoreinfo_note; + + if (!vmcoreinfo_size) + return; + buf = append_elf_note(buf, VMCOREINFO_NOTE_NAME, 0, vmcoreinfo_data, + vmcoreinfo_size); + final_note(buf); +} + +void crash_save_vmcoreinfo(void) +{ + vmcoreinfo_append_str("CRASHTIME=%ld\n", get_seconds()); + update_vmcoreinfo_note(); +} + +void vmcoreinfo_append_str(const char *fmt, ...) +{ + va_list args; + char buf[0x50]; + size_t r; + + va_start(args, fmt); + r = vscnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + r = min(r, vmcoreinfo_max_size - vmcoreinfo_size); + + memcpy(&vmcoreinfo_data[vmcoreinfo_size], buf, r); + + vmcoreinfo_size += r; +} + +/* + * provide an empty default implementation here -- architecture + * code may override this + */ +void __weak arch_crash_save_vmcoreinfo(void) +{} + +unsigned long __weak paddr_vmcoreinfo_note(void) +{ + return __pa((unsigned long)(char *)&vmcoreinfo_note); +} + +static int __init crash_save_vmcoreinfo_init(void) +{ + VMCOREINFO_OSRELEASE(init_uts_ns.name.release); + VMCOREINFO_PAGESIZE(PAGE_SIZE); + + VMCOREINFO_SYMBOL(init_uts_ns); + VMCOREINFO_SYMBOL(node_online_map); +#ifdef CONFIG_MMU + VMCOREINFO_SYMBOL(swapper_pg_dir); +#endif + VMCOREINFO_SYMBOL(_stext); + VMCOREINFO_SYMBOL(vmap_area_list); + +#ifndef CONFIG_NEED_MULTIPLE_NODES + VMCOREINFO_SYMBOL(mem_map); + VMCOREINFO_SYMBOL(contig_page_data); +#endif +#ifdef CONFIG_SPARSEMEM + VMCOREINFO_SYMBOL(mem_section); + VMCOREINFO_LENGTH(mem_section, NR_SECTION_ROOTS); + VMCOREINFO_STRUCT_SIZE(mem_section); + VMCOREINFO_OFFSET(mem_section, section_mem_map); +#endif + VMCOREINFO_STRUCT_SIZE(page); + VMCOREINFO_STRUCT_SIZE(pglist_data); + VMCOREINFO_STRUCT_SIZE(zone); + VMCOREINFO_STRUCT_SIZE(free_area); + VMCOREINFO_STRUCT_SIZE(list_head); + VMCOREINFO_SIZE(nodemask_t); + VMCOREINFO_OFFSET(page, flags); + VMCOREINFO_OFFSET(page, _count); + VMCOREINFO_OFFSET(page, mapping); + VMCOREINFO_OFFSET(page, lru); + VMCOREINFO_OFFSET(page, _mapcount); + VMCOREINFO_OFFSET(page, private); + VMCOREINFO_OFFSET(pglist_data, node_zones); + VMCOREINFO_OFFSET(pglist_data, nr_zones); +#ifdef CONFIG_FLAT_NODE_MEM_MAP + VMCOREINFO_OFFSET(pglist_data, node_mem_map); +#endif + VMCOREINFO_OFFSET(pglist_data, node_start_pfn); + VMCOREINFO_OFFSET(pglist_data, node_spanned_pages); + VMCOREINFO_OFFSET(pglist_data, node_id); + VMCOREINFO_OFFSET(zone, free_area); + VMCOREINFO_OFFSET(zone, vm_stat); + VMCOREINFO_OFFSET(zone, spanned_pages); + VMCOREINFO_OFFSET(free_area, free_list); + VMCOREINFO_OFFSET(list_head, next); + VMCOREINFO_OFFSET(list_head, prev); + VMCOREINFO_OFFSET(vmap_area, va_start); + VMCOREINFO_OFFSET(vmap_area, list); + VMCOREINFO_LENGTH(zone.free_area, MAX_ORDER); + log_buf_kexec_setup(); + VMCOREINFO_LENGTH(free_area.free_list, MIGRATE_TYPES); + VMCOREINFO_NUMBER(NR_FREE_PAGES); + VMCOREINFO_NUMBER(PG_lru); + VMCOREINFO_NUMBER(PG_private); + VMCOREINFO_NUMBER(PG_swapcache); + VMCOREINFO_NUMBER(PG_slab); +#ifdef CONFIG_MEMORY_FAILURE + VMCOREINFO_NUMBER(PG_hwpoison); +#endif + VMCOREINFO_NUMBER(PG_head_mask); + VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE); +#ifdef CONFIG_HUGETLBFS + VMCOREINFO_SYMBOL(free_huge_page); +#endif + + arch_crash_save_vmcoreinfo(); + update_vmcoreinfo_note(); + + return 0; +} + +subsys_initcall(crash_save_vmcoreinfo_init); + +/* + * Move into place and start executing a preloaded standalone + * executable. If nothing was preloaded return an error. + */ +int kernel_kexec(void) +{ + int error = 0; + + if (!mutex_trylock(&kexec_mutex)) + return -EBUSY; + if (!kexec_image) { + error = -EINVAL; + goto Unlock; + } + +#ifdef CONFIG_KEXEC_JUMP + if (kexec_image->preserve_context) { + lock_system_sleep(); + pm_prepare_console(); + error = freeze_processes(); + if (error) { + error = -EBUSY; + goto Restore_console; + } + suspend_console(); + error = dpm_suspend_start(PMSG_FREEZE); + if (error) + goto Resume_console; + /* At this point, dpm_suspend_start() has been called, + * but *not* dpm_suspend_end(). We *must* call + * dpm_suspend_end() now. Otherwise, drivers for + * some devices (e.g. interrupt controllers) become + * desynchronized with the actual state of the + * hardware at resume time, and evil weirdness ensues. + */ + error = dpm_suspend_end(PMSG_FREEZE); + if (error) + goto Resume_devices; + error = disable_nonboot_cpus(); + if (error) + goto Enable_cpus; + local_irq_disable(); + error = syscore_suspend(); + if (error) + goto Enable_irqs; + } else +#endif + { + kexec_in_progress = true; + kernel_restart_prepare(NULL); + migrate_to_reboot_cpu(); + + /* + * migrate_to_reboot_cpu() disables CPU hotplug assuming that + * no further code needs to use CPU hotplug (which is true in + * the reboot case). However, the kexec path depends on using + * CPU hotplug again; so re-enable it here. + */ + cpu_hotplug_enable(); + pr_emerg("Starting new kernel\n"); + machine_shutdown(); + } + + machine_kexec(kexec_image); + +#ifdef CONFIG_KEXEC_JUMP + if (kexec_image->preserve_context) { + syscore_resume(); + Enable_irqs: + local_irq_enable(); + Enable_cpus: + enable_nonboot_cpus(); + dpm_resume_start(PMSG_RESTORE); + Resume_devices: + dpm_resume_end(PMSG_RESTORE); + Resume_console: + resume_console(); + thaw_processes(); + Restore_console: + pm_restore_console(); + unlock_system_sleep(); + } +#endif + + Unlock: + mutex_unlock(&kexec_mutex); + return error; +} + +/* + * Add and remove page tables for crashkernel memory + * + * Provide an empty default implementation here -- architecture + * code may override this + */ +void __weak crash_map_reserved_pages(void) +{} + +void __weak crash_unmap_reserved_pages(void) +{} diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 6683ccef9fffb..e83b264640615 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -90,7 +90,7 @@ static ssize_t profiling_store(struct kobject *kobj, KERNEL_ATTR_RW(profiling); #endif -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE static ssize_t kexec_loaded_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { @@ -134,7 +134,7 @@ static ssize_t vmcoreinfo_show(struct kobject *kobj, } KERNEL_ATTR_RO(vmcoreinfo); -#endif /* CONFIG_KEXEC */ +#endif /* CONFIG_KEXEC_CORE */ /* whether file capabilities are enabled */ static ssize_t fscaps_show(struct kobject *kobj, @@ -196,7 +196,7 @@ static struct attribute * kernel_attrs[] = { #ifdef CONFIG_PROFILING &profiling_attr.attr, #endif -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE &kexec_loaded_attr.attr, &kexec_crash_loaded_attr.attr, &kexec_crash_size_attr.attr, diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index cf8c242033686..8f0324ef72ab3 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -835,7 +835,7 @@ const struct file_operations kmsg_fops = { .release = devkmsg_release, }; -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE /* * This appends the listed symbols to /proc/vmcore * diff --git a/kernel/reboot.c b/kernel/reboot.c index d20c85d9f8c0d..bd30a973fe946 100644 --- a/kernel/reboot.c +++ b/kernel/reboot.c @@ -346,7 +346,7 @@ SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, kernel_restart(buffer); break; -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE case LINUX_REBOOT_CMD_KEXEC: ret = kernel_kexec(); break; diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 19b62b522158a..715cc57cc66ac 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -621,7 +621,7 @@ static struct ctl_table kern_table[] = { .proc_handler = proc_dointvec, }, #endif -#ifdef CONFIG_KEXEC +#ifdef CONFIG_KEXEC_CORE { .procname = "kexec_load_disabled", .data = &kexec_load_disabled, -- GitLab From 04e9949b2d26ae1f0acd1181876a2a8ece92112d Mon Sep 17 00:00:00 2001 From: Minfei Huang Date: Wed, 9 Sep 2015 15:38:58 -0700 Subject: [PATCH 6963/7006] kexec: remove unnecessary test in kimage_alloc_crash_control_pages() Transforming PFN(Page Frame Number) to struct page is never failure, so we can simplify the code logic to do the image->control_page assignment directly in the loop, and remove the unnecessary conditional judgement. Signed-off-by: Minfei Huang Acked-by: Dave Young Acked-by: Vivek Goyal Cc: Simon Horman Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kexec_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 9aa25c034b2ef..9ffc96b65d9a8 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -439,11 +439,10 @@ static struct page *kimage_alloc_crash_control_pages(struct kimage *image, /* If I don't overlap any segments I have found my hole! */ if (i == image->nr_segments) { pages = pfn_to_page(hole_start >> PAGE_SHIFT); + image->control_page = hole_end; break; } } - if (pages) - image->control_page = hole_end; return pages; } -- GitLab From bbb78b8f3f4ea8eca14937b693bfe244838e1d4d Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Wed, 9 Sep 2015 15:39:00 -0700 Subject: [PATCH 6964/7006] kexec: align crash_notes allocation to make it be inside one physical page People reported that crash_notes in /proc/vmcore were corrupted and this cause crash kdump failure. With code debugging and log we got the root cause. This is because percpu variable crash_notes are allocated in 2 vmalloc pages. Currently percpu is based on vmalloc by default. Vmalloc can't guarantee 2 continuous vmalloc pages are also on 2 continuous physical pages. So when 1st kernel exports the starting address and size of crash_notes through sysfs like below: /sys/devices/system/cpu/cpux/crash_notes /sys/devices/system/cpu/cpux/crash_notes_size kdump kernel use them to get the content of crash_notes. However the 2nd part may not be in the next neighbouring physical page as we expected if crash_notes are allocated accross 2 vmalloc pages. That's why nhdr_ptr->n_namesz or nhdr_ptr->n_descsz could be very huge in update_note_header_size_elf64() and cause note header merging failure or some warnings. In this patch change to call __alloc_percpu() to passed in the align value by rounding crash_notes_size up to the nearest power of two. This makes sure the crash_notes is allocated inside one physical page since sizeof(note_buf_t) in all ARCHS is smaller than PAGE_SIZE. Meanwhile add a BUILD_BUG_ON to break compile if size is bigger than PAGE_SIZE since crash_notes definitely will be in 2 pages. That need be avoided, and need be reported if it's unavoidable. [akpm@linux-foundation.org: use correct comment layout] Signed-off-by: Baoquan He Cc: Eric W. Biederman Cc: Vivek Goyal Cc: Dave Young Cc: Lisa Mitchell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kexec_core.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 9ffc96b65d9a8..322dd5579f594 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -1004,7 +1004,28 @@ void crash_save_cpu(struct pt_regs *regs, int cpu) static int __init crash_notes_memory_init(void) { /* Allocate memory for saving cpu registers. */ - crash_notes = alloc_percpu(note_buf_t); + size_t size, align; + + /* + * crash_notes could be allocated across 2 vmalloc pages when percpu + * is vmalloc based . vmalloc doesn't guarantee 2 continuous vmalloc + * pages are also on 2 continuous physical pages. In this case the + * 2nd part of crash_notes in 2nd page could be lost since only the + * starting address and size of crash_notes are exported through sysfs. + * Here round up the size of crash_notes to the nearest power of two + * and pass it to __alloc_percpu as align value. This can make sure + * crash_notes is allocated inside one physical page. + */ + size = sizeof(note_buf_t); + align = min(roundup_pow_of_two(sizeof(note_buf_t)), PAGE_SIZE); + + /* + * Break compile if size is bigger than PAGE_SIZE since crash_notes + * definitely will be in 2 pages with that. + */ + BUILD_BUG_ON(size > PAGE_SIZE); + + crash_notes = __alloc_percpu(size, align); if (!crash_notes) { pr_warn("Kexec: Memory allocation for saving cpu register states failed\n"); return -ENOMEM; -- GitLab From 1303a27c9c32020a3b6ac89be270d2ab1f28be24 Mon Sep 17 00:00:00 2001 From: Baoquan He Date: Wed, 9 Sep 2015 15:39:03 -0700 Subject: [PATCH 6965/7006] kexec: export KERNEL_IMAGE_SIZE to vmcoreinfo In x86_64, since v2.6.26 the KERNEL_IMAGE_SIZE is changed to 512M, and accordingly the MODULES_VADDR is changed to 0xffffffffa0000000. However, in v3.12 Kees Cook introduced kaslr to randomise the location of kernel. And the kernel text mapping addr space is enlarged from 512M to 1G. That means now KERNEL_IMAGE_SIZE is variable, its value is 512M when kaslr support is not compiled in and 1G when kaslr support is compiled in. Accordingly the MODULES_VADDR is changed too to be: #define MODULES_VADDR (__START_KERNEL_map + KERNEL_IMAGE_SIZE) So when kaslr is compiled in and enabled, the kernel text mapping addr space and modules vaddr space need be adjusted. Otherwise makedumpfile will collapse since the addr for some symbols is not correct. Hence KERNEL_IMAGE_SIZE need be exported to vmcoreinfo and got in makedumpfile to help calculate MODULES_VADDR. Signed-off-by: Baoquan He Acked-by: Kees Cook Acked-by: Vivek Goyal Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/kexec_core.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c index 322dd5579f594..201b45327804d 100644 --- a/kernel/kexec_core.c +++ b/kernel/kexec_core.c @@ -1417,6 +1417,9 @@ static int __init crash_save_vmcoreinfo_init(void) #endif VMCOREINFO_NUMBER(PG_head_mask); VMCOREINFO_NUMBER(PAGE_BUDDY_MAPCOUNT_VALUE); +#ifdef CONFIG_X86 + VMCOREINFO_NUMBER(KERNEL_IMAGE_SIZE); +#endif #ifdef CONFIG_HUGETLBFS VMCOREINFO_SYMBOL(free_huge_page); #endif -- GitLab From 9a5bc726d559221a3394bb8ef97d0abc1ee94d00 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Wed, 9 Sep 2015 15:39:06 -0700 Subject: [PATCH 6966/7006] sysctl: fix int -> unsigned long assignments in INT_MIN case The following if (val < 0) *lvalp = (unsigned long)-val; is incorrect because the compiler is free to assume -val to be positive and use a sign-extend instruction for extending the bit pattern. This is a problem if val == INT_MIN: # echo -2147483648 >/proc/sys/dev/scsi/logging_level # cat /proc/sys/dev/scsi/logging_level -18446744071562067968 Cast to unsigned long before negation - that way we first sign-extend and then negate an unsigned, which is well defined. With this: # cat /proc/sys/dev/scsi/logging_level -2147483648 Signed-off-by: Ilya Dryomov Cc: Mikulas Patocka Cc: Robert Xiao Cc: "Eric W. Biederman" Cc: Kees Cook Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/sysctl.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 715cc57cc66ac..e69201d8094eb 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -1995,7 +1995,7 @@ static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, int val = *valp; if (val < 0) { *negp = true; - *lvalp = (unsigned long)-val; + *lvalp = -(unsigned long)val; } else { *negp = false; *lvalp = (unsigned long)val; @@ -2201,7 +2201,7 @@ static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, int val = *valp; if (val < 0) { *negp = true; - *lvalp = (unsigned long)-val; + *lvalp = -(unsigned long)val; } else { *negp = false; *lvalp = (unsigned long)val; @@ -2436,7 +2436,7 @@ static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp, unsigned long lval; if (val < 0) { *negp = true; - lval = (unsigned long)-val; + lval = -(unsigned long)val; } else { *negp = false; lval = (unsigned long)val; @@ -2459,7 +2459,7 @@ static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp unsigned long lval; if (val < 0) { *negp = true; - lval = (unsigned long)-val; + lval = -(unsigned long)val; } else { *negp = false; lval = (unsigned long)val; @@ -2484,7 +2484,7 @@ static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, unsigned long lval; if (val < 0) { *negp = true; - lval = (unsigned long)-val; + lval = -(unsigned long)val; } else { *negp = false; lval = (unsigned long)val; -- GitLab From e852d82a5b55b44ce8be89078d0dfbddbeae3211 Mon Sep 17 00:00:00 2001 From: "Pranay Kr. Srivastava" Date: Wed, 9 Sep 2015 15:39:09 -0700 Subject: [PATCH 6967/7006] fs/affs: make root lookup from blkdev logical size This patch resolves https://bugzilla.kernel.org/show_bug.cgi?id=16531. When logical blkdev size > 512 then sector numbers become larger than the device can support. Make affs start lookup based on the device's logical sector size instead of 512. Reported-by: Mark Suggested-by: Mark Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/affs/super.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/affs/super.c b/fs/affs/super.c index 3f89c9e05b407..5b50c4ca43a7d 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -18,6 +18,7 @@ #include #include #include +#include #include "affs.h" static int affs_statfs(struct dentry *dentry, struct kstatfs *buf); @@ -352,18 +353,19 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) * blocks, we will have to change it. */ - size = sb->s_bdev->bd_inode->i_size >> 9; + size = i_size_read(sb->s_bdev->bd_inode) >> 9; pr_debug("initial blocksize=%d, #blocks=%d\n", 512, size); affs_set_blocksize(sb, PAGE_SIZE); /* Try to find root block. Its location depends on the block size. */ - i = 512; - j = 4096; + i = bdev_logical_block_size(sb->s_bdev); + j = PAGE_SIZE; if (blocksize > 0) { i = j = blocksize; size = size / (blocksize / 512); } + for (blocksize = i; blocksize <= j; blocksize <<= 1, size >>= 1) { sbi->s_root_block = root_block; if (root_block < 0) -- GitLab From 2d3862d26e67a59340ba1cf1748196c76c5787de Mon Sep 17 00:00:00 2001 From: Yinghai Lu Date: Wed, 9 Sep 2015 15:39:12 -0700 Subject: [PATCH 6968/7006] lib/decompressors: use real out buf size for gunzip with kernel When loading x86 64bit kernel above 4GiB with patched grub2, got kernel gunzip error. | early console in decompress_kernel | decompress_kernel: | input: [0x807f2143b4-0x807ff61aee] | output: [0x807cc00000-0x807f3ea29b] 0x027ea29c: output_len | boot via startup_64 | KASLR using RDTSC... | new output: [0x46fe000000-0x470138cfff] 0x0338d000: output_run_size | decompress: [0x46fe000000-0x47007ea29b] <=== [0x807f2143b4-0x807ff61aee] | | Decompressing Linux... gz... | | uncompression error | | -- System halted the new buffer is at 0x46fe000000ULL, decompressor_gzip is using 0xffffffb901ffffff as out_len. gunzip in lib/zlib_inflate/inflate.c cap that len to 0x01ffffff and decompress fails later. We could hit this problem with crashkernel booting that uses kexec loading kernel above 4GiB. We have decompress_* support: 1. inbuf[]/outbuf[] for kernel preboot. 2. inbuf[]/flush() for initramfs 3. fill()/flush() for initrd. This bug only affect kernel preboot path that use outbuf[]. Add __decompress and take real out_buf_len for gunzip instead of guessing wrong buf size. Fixes: 1431574a1c4 (lib/decompressors: fix "no limit" output buffer length) Signed-off-by: Yinghai Lu Cc: Alexandre Courbot Cc: Jon Medhurst Cc: Stephen Warren Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Ingo Molnar Cc: Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/arm/boot/compressed/decompress.c | 2 +- arch/h8300/boot/compressed/misc.c | 2 +- arch/m32r/boot/compressed/misc.c | 3 ++- arch/mips/boot/compressed/decompress.c | 4 ++-- arch/s390/boot/compressed/misc.c | 2 +- arch/sh/boot/compressed/misc.c | 2 +- arch/unicore32/boot/compressed/misc.c | 4 ++-- arch/x86/boot/compressed/misc.c | 3 ++- lib/decompress_bunzip2.c | 6 ++--- lib/decompress_inflate.c | 31 +++++++++++++++++++++----- lib/decompress_unlz4.c | 6 ++--- lib/decompress_unlzma.c | 7 +++--- lib/decompress_unlzo.c | 13 ++++++++++- lib/decompress_unxz.c | 12 +++++++++- 14 files changed, 70 insertions(+), 27 deletions(-) diff --git a/arch/arm/boot/compressed/decompress.c b/arch/arm/boot/compressed/decompress.c index bd245d34952d2..a0765e7ed6c7d 100644 --- a/arch/arm/boot/compressed/decompress.c +++ b/arch/arm/boot/compressed/decompress.c @@ -57,5 +57,5 @@ extern char * strstr(const char * s1, const char *s2); int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x)) { - return decompress(input, len, NULL, NULL, output, NULL, error); + return __decompress(input, len, NULL, NULL, output, 0, NULL, error); } diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c index 704274127c07e..c4f2cfcb117bd 100644 --- a/arch/h8300/boot/compressed/misc.c +++ b/arch/h8300/boot/compressed/misc.c @@ -70,5 +70,5 @@ void decompress_kernel(void) free_mem_ptr = (unsigned long)&_end; free_mem_end_ptr = free_mem_ptr + HEAP_SIZE; - decompress(input_data, input_len, NULL, NULL, output, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); } diff --git a/arch/m32r/boot/compressed/misc.c b/arch/m32r/boot/compressed/misc.c index 28a09529f2069..3a76927458681 100644 --- a/arch/m32r/boot/compressed/misc.c +++ b/arch/m32r/boot/compressed/misc.c @@ -86,6 +86,7 @@ decompress_kernel(int mmu_on, unsigned char *zimage_data, free_mem_end_ptr = free_mem_ptr + BOOT_HEAP_SIZE; puts("\nDecompressing Linux... "); - decompress(input_data, input_len, NULL, NULL, output_data, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output_data, 0, + NULL, error); puts("done.\nBooting the kernel.\n"); } diff --git a/arch/mips/boot/compressed/decompress.c b/arch/mips/boot/compressed/decompress.c index 54831069a2062..080cd53bac369 100644 --- a/arch/mips/boot/compressed/decompress.c +++ b/arch/mips/boot/compressed/decompress.c @@ -111,8 +111,8 @@ void decompress_kernel(unsigned long boot_heap_start) puts("\n"); /* Decompress the kernel with according algorithm */ - decompress((char *)zimage_start, zimage_size, 0, 0, - (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, error); + __decompress((char *)zimage_start, zimage_size, 0, 0, + (void *)VMLINUX_LOAD_ADDRESS_ULL, 0, 0, error); /* FIXME: should we flush cache here? */ puts("Now, booting the kernel...\n"); diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 42506b371b741..4da604ebf6fd8 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -167,7 +167,7 @@ unsigned long decompress_kernel(void) #endif puts("Uncompressing Linux... "); - decompress(input_data, input_len, NULL, NULL, output, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); puts("Ok, booting the kernel.\n"); return (unsigned long) output; } diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c index 95470a472d2cf..208a9753ab38c 100644 --- a/arch/sh/boot/compressed/misc.c +++ b/arch/sh/boot/compressed/misc.c @@ -132,7 +132,7 @@ void decompress_kernel(void) puts("Uncompressing Linux... "); cache_control(CACHE_ENABLE); - decompress(input_data, input_len, NULL, NULL, output, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output, 0, NULL, error); cache_control(CACHE_DISABLE); puts("Ok, booting the kernel.\n"); } diff --git a/arch/unicore32/boot/compressed/misc.c b/arch/unicore32/boot/compressed/misc.c index 176d5bda3559d..5c65dfee278c0 100644 --- a/arch/unicore32/boot/compressed/misc.c +++ b/arch/unicore32/boot/compressed/misc.c @@ -119,8 +119,8 @@ unsigned long decompress_kernel(unsigned long output_start, output_ptr = get_unaligned_le32(tmp); arch_decomp_puts("Uncompressing Linux..."); - decompress(input_data, input_data_end - input_data, NULL, NULL, - output_data, NULL, error); + __decompress(input_data, input_data_end - input_data, NULL, NULL, + output_data, 0, NULL, error); arch_decomp_puts(" done, booting the kernel.\n"); return output_ptr; } diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c index f63797942bb59..79dac1758e7c0 100644 --- a/arch/x86/boot/compressed/misc.c +++ b/arch/x86/boot/compressed/misc.c @@ -448,7 +448,8 @@ asmlinkage __visible void *decompress_kernel(void *rmode, memptr heap, #endif debug_putstr("\nDecompressing Linux... "); - decompress(input_data, input_len, NULL, NULL, output, NULL, error); + __decompress(input_data, input_len, NULL, NULL, output, output_len, + NULL, error); parse_elf(output); /* * 32-bit always performs relocations. 64-bit relocations are only diff --git a/lib/decompress_bunzip2.c b/lib/decompress_bunzip2.c index 6dd0335ea61b2..0234361b24b89 100644 --- a/lib/decompress_bunzip2.c +++ b/lib/decompress_bunzip2.c @@ -743,12 +743,12 @@ exit_0: } #ifdef PREBOOT -STATIC int INIT decompress(unsigned char *buf, long len, +STATIC int INIT __decompress(unsigned char *buf, long len, long (*fill)(void*, unsigned long), long (*flush)(void*, unsigned long), - unsigned char *outbuf, + unsigned char *outbuf, long olen, long *pos, - void(*error)(char *x)) + void (*error)(char *x)) { return bunzip2(buf, len - 4, fill, flush, outbuf, pos, error); } diff --git a/lib/decompress_inflate.c b/lib/decompress_inflate.c index d4c7891635ecc..555c06bf20daa 100644 --- a/lib/decompress_inflate.c +++ b/lib/decompress_inflate.c @@ -1,4 +1,5 @@ #ifdef STATIC +#define PREBOOT /* Pre-boot environment: included */ /* prevent inclusion of _LINUX_KERNEL_H in pre-boot environment: lots @@ -33,23 +34,23 @@ static long INIT nofill(void *buffer, unsigned long len) } /* Included from initramfs et al code */ -STATIC int INIT gunzip(unsigned char *buf, long len, +STATIC int INIT __gunzip(unsigned char *buf, long len, long (*fill)(void*, unsigned long), long (*flush)(void*, unsigned long), - unsigned char *out_buf, + unsigned char *out_buf, long out_len, long *pos, void(*error)(char *x)) { u8 *zbuf; struct z_stream_s *strm; int rc; - size_t out_len; rc = -1; if (flush) { out_len = 0x8000; /* 32 K */ out_buf = malloc(out_len); } else { - out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */ + if (!out_len) + out_len = ((size_t)~0) - (size_t)out_buf; /* no limit */ } if (!out_buf) { error("Out of memory while allocating output buffer"); @@ -181,4 +182,24 @@ gunzip_nomem1: return rc; /* returns Z_OK (0) if successful */ } -#define decompress gunzip +#ifndef PREBOOT +STATIC int INIT gunzip(unsigned char *buf, long len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *out_buf, + long *pos, + void (*error)(char *x)) +{ + return __gunzip(buf, len, fill, flush, out_buf, 0, pos, error); +} +#else +STATIC int INIT __decompress(unsigned char *buf, long len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *out_buf, long out_len, + long *pos, + void (*error)(char *x)) +{ + return __gunzip(buf, len, fill, flush, out_buf, out_len, pos, error); +} +#endif diff --git a/lib/decompress_unlz4.c b/lib/decompress_unlz4.c index 40f66ebe57b77..036fc882cd725 100644 --- a/lib/decompress_unlz4.c +++ b/lib/decompress_unlz4.c @@ -196,12 +196,12 @@ exit_0: } #ifdef PREBOOT -STATIC int INIT decompress(unsigned char *buf, long in_len, +STATIC int INIT __decompress(unsigned char *buf, long in_len, long (*fill)(void*, unsigned long), long (*flush)(void*, unsigned long), - unsigned char *output, + unsigned char *output, long out_len, long *posp, - void(*error)(char *x) + void (*error)(char *x) ) { return unlz4(buf, in_len - 4, fill, flush, output, posp, error); diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index 0be83af62b884..decb64629c146 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c @@ -667,13 +667,12 @@ exit_0: } #ifdef PREBOOT -STATIC int INIT decompress(unsigned char *buf, long in_len, +STATIC int INIT __decompress(unsigned char *buf, long in_len, long (*fill)(void*, unsigned long), long (*flush)(void*, unsigned long), - unsigned char *output, + unsigned char *output, long out_len, long *posp, - void(*error)(char *x) - ) + void (*error)(char *x)) { return unlzma(buf, in_len - 4, fill, flush, output, posp, error); } diff --git a/lib/decompress_unlzo.c b/lib/decompress_unlzo.c index b94a31bdd87d1..f4c158e3a022a 100644 --- a/lib/decompress_unlzo.c +++ b/lib/decompress_unlzo.c @@ -31,6 +31,7 @@ */ #ifdef STATIC +#define PREBOOT #include "lzo/lzo1x_decompress_safe.c" #else #include @@ -287,4 +288,14 @@ exit: return ret; } -#define decompress unlzo +#ifdef PREBOOT +STATIC int INIT __decompress(unsigned char *buf, long len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *out_buf, long olen, + long *pos, + void (*error)(char *x)) +{ + return unlzo(buf, len, fill, flush, out_buf, pos, error); +} +#endif diff --git a/lib/decompress_unxz.c b/lib/decompress_unxz.c index b07a78340e9d3..25d59a95bd668 100644 --- a/lib/decompress_unxz.c +++ b/lib/decompress_unxz.c @@ -394,4 +394,14 @@ error_alloc_state: * This macro is used by architecture-specific files to decompress * the kernel image. */ -#define decompress unxz +#ifdef XZ_PREBOOT +STATIC int INIT __decompress(unsigned char *buf, long len, + long (*fill)(void*, unsigned long), + long (*flush)(void*, unsigned long), + unsigned char *out_buf, long olen, + long *pos, + void (*error)(char *x)) +{ + return unxz(buf, len, fill, flush, out_buf, pos, error); +} +#endif -- GitLab From e4e29dc4841d21943bec1bc5378ab421d2320d83 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Wed, 9 Sep 2015 15:39:15 -0700 Subject: [PATCH 6969/7006] lib/decompress_unlzma: Do a NULL check for pointer Compare pointer-typed values to NULL rather than 0. The semantic patch that makes this change is available in scripts/coccinelle/null/badzero.cocci. Signed-off-by: Fabio Estevam Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/decompress_unlzma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/decompress_unlzma.c b/lib/decompress_unlzma.c index decb64629c146..ed7a1fd819f2f 100644 --- a/lib/decompress_unlzma.c +++ b/lib/decompress_unlzma.c @@ -620,7 +620,7 @@ STATIC inline int INIT unlzma(unsigned char *buf, long in_len, num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); p = (uint16_t *) large_malloc(num_probs * sizeof(*p)); - if (p == 0) + if (p == NULL) goto exit_2; num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp)); for (i = 0; i < num_probs; i++) -- GitLab From 8b235f2f16a472b8cfc10e8ef1286fcd3331e033 Mon Sep 17 00:00:00 2001 From: yalin wang Date: Wed, 9 Sep 2015 15:39:18 -0700 Subject: [PATCH 6970/7006] zlib_deflate/deftree: remove bi_reverse() Remove bi_reverse() and use generic bitrev32() instead - it should have better performance on some platforms. Signed-off-by: yalin wang Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- lib/zlib_deflate/deftree.c | 6 +++--- lib/zlib_deflate/defutil.h | 16 ---------------- 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/lib/zlib_deflate/deftree.c b/lib/zlib_deflate/deftree.c index ddf348299f244..9b1756b12743f 100644 --- a/lib/zlib_deflate/deftree.c +++ b/lib/zlib_deflate/deftree.c @@ -35,6 +35,7 @@ /* #include "deflate.h" */ #include +#include #include "defutil.h" #ifdef DEBUG_ZLIB @@ -146,7 +147,6 @@ static void send_all_trees (deflate_state *s, int lcodes, int dcodes, static void compress_block (deflate_state *s, ct_data *ltree, ct_data *dtree); static void set_data_type (deflate_state *s); -static unsigned bi_reverse (unsigned value, int length); static void bi_windup (deflate_state *s); static void bi_flush (deflate_state *s); static void copy_block (deflate_state *s, char *buf, unsigned len, @@ -284,7 +284,7 @@ static void tr_static_init(void) /* The static distance tree is trivial: */ for (n = 0; n < D_CODES; n++) { static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); + static_dtree[n].Code = bitrev32((u32)n) >> (32 - 5); } static_init_done = 1; } @@ -520,7 +520,7 @@ static void gen_codes( int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ - tree[n].Code = bi_reverse(next_code[len]++, len); + tree[n].Code = bitrev32((u32)(next_code[len]++)) >> (32 - len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); diff --git a/lib/zlib_deflate/defutil.h b/lib/zlib_deflate/defutil.h index b640b6402e99e..a8c370897c9f4 100644 --- a/lib/zlib_deflate/defutil.h +++ b/lib/zlib_deflate/defutil.h @@ -292,22 +292,6 @@ void zlib_tr_stored_type_only (deflate_state *); put_byte(s, (uch)((ush)(w) >> 8)); \ } -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -static inline unsigned bi_reverse(unsigned code, /* the value to invert */ - int len) /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - /* =========================================================================== * Flush the bit buffer, keeping at most 7 bits in it. */ -- GitLab From d0edd8528362c07216498340e928159510595e7b Mon Sep 17 00:00:00 2001 From: Davidlohr Bueso Date: Wed, 9 Sep 2015 15:39:20 -0700 Subject: [PATCH 6971/7006] ipc: convert invalid scenarios to use WARN_ON Considering Linus' past rants about the (ab)use of BUG in the kernel, I took a look at how we deal with such calls in ipc. Given that any errors or corruption in ipc code are most likely contained within the set of processes participating in the broken mechanisms, there aren't really many strong fatal system failure scenarios that would require a BUG call. Also, if something is seriously wrong, ipc might not be the place for such a BUG either. 1. For example, recently, a customer hit one of these BUG_ONs in shm after failing shm_lock(). A busted ID imho does not merit a BUG_ON, and WARN would have been better. 2. MSG_COPY functionality of posix msgrcv(2) for checkpoint/restore. I don't see how we can hit this anyway -- at least it should be IS_ERR. The 'copy' arg from do_msgrcv is always set by calling prepare_copy() first and foremost. We could also probably drop this check altogether. Either way, it does not merit a BUG_ON. 3. No ->fault() callback for the fs getting the corresponding page -- seems selfish to make the system unusable. Signed-off-by: Davidlohr Bueso Cc: Manfred Spraul Cc: Linus Torvalds Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- ipc/msgutil.c | 2 +- ipc/shm.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 2b491590ebab1..71f448e5e927a 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -123,7 +123,7 @@ struct msg_msg *copy_msg(struct msg_msg *src, struct msg_msg *dst) size_t len = src->m_ts; size_t alen; - BUG_ON(dst == NULL); + WARN_ON(dst == NULL); if (src->m_ts > dst->m_ts) return ERR_PTR(-EINVAL); diff --git a/ipc/shm.c b/ipc/shm.c index 4aef24d91b633..222131e8e38f3 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -159,7 +159,7 @@ static inline struct shmid_kernel *shm_lock(struct ipc_namespace *ns, int id) * We raced in the idr lookup or with shm_destroy(). Either way, the * ID is busted. */ - BUG_ON(IS_ERR(ipcp)); + WARN_ON(IS_ERR(ipcp)); return container_of(ipcp, struct shmid_kernel, shm_perm); } @@ -393,7 +393,7 @@ static int shm_mmap(struct file *file, struct vm_area_struct *vma) return ret; sfd->vm_ops = vma->vm_ops; #ifdef CONFIG_MMU - BUG_ON(!sfd->vm_ops->fault); + WARN_ON(!sfd->vm_ops->fault); #endif vma->vm_ops = &shm_vm_ops; shm_open(vma); -- GitLab From 2a78b857d3755a6f8d0c70d7e365e473925987c1 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Wed, 9 Sep 2015 15:39:23 -0700 Subject: [PATCH 6972/7006] namei: fix warning while make xmldocs caused by namei.c Fix the following warnings: Warning(.//fs/namei.c:2422): No description found for parameter 'nd' Warning(.//fs/namei.c:2422): Excess function parameter 'nameidata' description in 'path_mountpoint' Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/namei.c b/fs/namei.c index 29b927938b8ce..726d211db4842 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2438,7 +2438,7 @@ done: /** * path_mountpoint - look up a path to be umounted - * @nameidata: lookup context + * @nd: lookup context * @flags: lookup flags * @path: pointer to container for result * -- GitLab From 7cbea8dc0127a95226c7722a738ac6534950ef67 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Wed, 9 Sep 2015 15:39:26 -0700 Subject: [PATCH 6973/7006] mm: mark most vm_operations_struct const With two exceptions (drm/qxl and drm/radeon) all vm_operations_struct structs should be constant. Signed-off-by: Kirill A. Shutemov Reviewed-by: Oleg Nesterov Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Ingo Molnar Cc: Minchan Kim Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/entry/vsyscall/vsyscall_64.c | 2 +- drivers/android/binder.c | 2 +- drivers/gpu/drm/vgem/vgem_drv.c | 2 +- drivers/hsi/clients/cmt_speech.c | 2 +- drivers/infiniband/hw/qib/qib_file_ops.c | 2 +- drivers/infiniband/hw/qib/qib_mmap.c | 2 +- drivers/media/platform/omap/omap_vout.c | 2 +- drivers/misc/genwqe/card_dev.c | 2 +- drivers/staging/android/ion/ion.c | 2 +- drivers/staging/comedi/comedi_fops.c | 2 +- drivers/video/fbdev/omap2/omapfb/omapfb-main.c | 2 +- drivers/xen/gntalloc.c | 2 +- drivers/xen/gntdev.c | 2 +- drivers/xen/privcmd.c | 4 ++-- fs/ceph/addr.c | 2 +- fs/cifs/file.c | 2 +- security/selinux/selinuxfs.c | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 26a46f44e2981..b160c0c6baed5 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -277,7 +277,7 @@ static const char *gate_vma_name(struct vm_area_struct *vma) { return "[vsyscall]"; } -static struct vm_operations_struct gate_vma_ops = { +static const struct vm_operations_struct gate_vma_ops = { .name = gate_vma_name, }; static struct vm_area_struct gate_vma = { diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 6607f3c6ace10..a39e85f9efa98 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -2834,7 +2834,7 @@ static int binder_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -static struct vm_operations_struct binder_vm_ops = { +static const struct vm_operations_struct binder_vm_ops = { .open = binder_vma_open, .close = binder_vma_close, .fault = binder_vm_fault, diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index 6394547cf67a0..860062ef88144 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -125,7 +125,7 @@ static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } } -static struct vm_operations_struct vgem_gem_vm_ops = { +static const struct vm_operations_struct vgem_gem_vm_ops = { .fault = vgem_gem_fault, .open = drm_gem_vm_open, .close = drm_gem_vm_close, diff --git a/drivers/hsi/clients/cmt_speech.c b/drivers/hsi/clients/cmt_speech.c index d04643f9548bb..95638df73d1c3 100644 --- a/drivers/hsi/clients/cmt_speech.c +++ b/drivers/hsi/clients/cmt_speech.c @@ -1110,7 +1110,7 @@ static int cs_char_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return 0; } -static struct vm_operations_struct cs_char_vm_ops = { +static const struct vm_operations_struct cs_char_vm_ops = { .fault = cs_char_vma_fault, }; diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 725881890c4a2..e449e394963f0 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -908,7 +908,7 @@ static int qib_file_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return 0; } -static struct vm_operations_struct qib_file_vm_ops = { +static const struct vm_operations_struct qib_file_vm_ops = { .fault = qib_file_vma_fault, }; diff --git a/drivers/infiniband/hw/qib/qib_mmap.c b/drivers/infiniband/hw/qib/qib_mmap.c index 146cf29a2e1db..34927b700b0e6 100644 --- a/drivers/infiniband/hw/qib/qib_mmap.c +++ b/drivers/infiniband/hw/qib/qib_mmap.c @@ -75,7 +75,7 @@ static void qib_vma_close(struct vm_area_struct *vma) kref_put(&ip->ref, qib_release_mmap_info); } -static struct vm_operations_struct qib_vm_ops = { +static const struct vm_operations_struct qib_vm_ops = { .open = qib_vma_open, .close = qib_vma_close, }; diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index f09c5f17a42f3..de2474e1132de 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -872,7 +872,7 @@ static void omap_vout_vm_close(struct vm_area_struct *vma) vout->mmap_count--; } -static struct vm_operations_struct omap_vout_vm_ops = { +static const struct vm_operations_struct omap_vout_vm_ops = { .open = omap_vout_vm_open, .close = omap_vout_vm_close, }; diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c index c49d244265ecc..70e62d6a3231f 100644 --- a/drivers/misc/genwqe/card_dev.c +++ b/drivers/misc/genwqe/card_dev.c @@ -418,7 +418,7 @@ static void genwqe_vma_close(struct vm_area_struct *vma) kfree(dma_map); } -static struct vm_operations_struct genwqe_vma_ops = { +static const struct vm_operations_struct genwqe_vma_ops = { .open = genwqe_vma_open, .close = genwqe_vma_close, }; diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index eec878e183f5d..217aa537c4eb9 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -997,7 +997,7 @@ static void ion_vm_close(struct vm_area_struct *vma) mutex_unlock(&buffer->lock); } -static struct vm_operations_struct ion_vma_ops = { +static const struct vm_operations_struct ion_vma_ops = { .open = ion_vm_open, .close = ion_vm_close, .fault = ion_vm_fault, diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index fd54d098ab022..0e8a45102933e 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -2156,7 +2156,7 @@ static void comedi_vm_close(struct vm_area_struct *area) comedi_buf_map_put(bm); } -static struct vm_operations_struct comedi_vm_ops = { +static const struct vm_operations_struct comedi_vm_ops = { .open = comedi_vm_open, .close = comedi_vm_close, }; diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c index 4f0cbb54d4dbd..d3af01c94a58d 100644 --- a/drivers/video/fbdev/omap2/omapfb/omapfb-main.c +++ b/drivers/video/fbdev/omap2/omapfb/omapfb-main.c @@ -1091,7 +1091,7 @@ static void mmap_user_close(struct vm_area_struct *vma) omapfb_put_mem_region(rg); } -static struct vm_operations_struct mmap_user_ops = { +static const struct vm_operations_struct mmap_user_ops = { .open = mmap_user_open, .close = mmap_user_close, }; diff --git a/drivers/xen/gntalloc.c b/drivers/xen/gntalloc.c index e53fe191738cf..696301d9dc919 100644 --- a/drivers/xen/gntalloc.c +++ b/drivers/xen/gntalloc.c @@ -493,7 +493,7 @@ static void gntalloc_vma_close(struct vm_area_struct *vma) mutex_unlock(&gref_mutex); } -static struct vm_operations_struct gntalloc_vmops = { +static const struct vm_operations_struct gntalloc_vmops = { .open = gntalloc_vma_open, .close = gntalloc_vma_close, }; diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c index 0dbb222daaf1c..2ea0b3b2a91d2 100644 --- a/drivers/xen/gntdev.c +++ b/drivers/xen/gntdev.c @@ -433,7 +433,7 @@ static struct page *gntdev_vma_find_special_page(struct vm_area_struct *vma, return map->pages[(addr - map->pages_vm_start) >> PAGE_SHIFT]; } -static struct vm_operations_struct gntdev_vmops = { +static const struct vm_operations_struct gntdev_vmops = { .open = gntdev_vma_open, .close = gntdev_vma_close, .find_special_page = gntdev_vma_find_special_page, diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 5a296161d843b..56cb13fcbd0e8 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -414,7 +414,7 @@ static int alloc_empty_pages(struct vm_area_struct *vma, int numpgs) return 0; } -static struct vm_operations_struct privcmd_vm_ops; +static const struct vm_operations_struct privcmd_vm_ops; static long privcmd_ioctl_mmap_batch(void __user *udata, int version) { @@ -605,7 +605,7 @@ static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } -static struct vm_operations_struct privcmd_vm_ops = { +static const struct vm_operations_struct privcmd_vm_ops = { .close = privcmd_close, .fault = privcmd_fault }; diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 890c50971a690..a268abfe60acd 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c @@ -1593,7 +1593,7 @@ out: return err; } -static struct vm_operations_struct ceph_vmops = { +static const struct vm_operations_struct ceph_vmops = { .fault = ceph_filemap_fault, .page_mkwrite = ceph_page_mkwrite, }; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 3f50cee79df9d..e2a6af1508af2 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -3216,7 +3216,7 @@ cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_LOCKED; } -static struct vm_operations_struct cifs_file_vm_ops = { +static const struct vm_operations_struct cifs_file_vm_ops = { .fault = filemap_fault, .map_pages = filemap_map_pages, .page_mkwrite = cifs_page_mkwrite, diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c index 3d22014130289..5bed7716f8ab6 100644 --- a/security/selinux/selinuxfs.c +++ b/security/selinux/selinuxfs.c @@ -472,7 +472,7 @@ static int sel_mmap_policy_fault(struct vm_area_struct *vma, return 0; } -static struct vm_operations_struct sel_mmap_policy_ops = { +static const struct vm_operations_struct sel_mmap_policy_ops = { .fault = sel_mmap_policy_fault, .page_mkwrite = sel_mmap_policy_fault, }; -- GitLab From 1fcfd8db7f82fa1f533a6f0e4155614ff4144d56 Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 9 Sep 2015 15:39:29 -0700 Subject: [PATCH 6974/7006] mm, mpx: add "vm_flags_t vm_flags" arg to do_mmap_pgoff() Add the additional "vm_flags_t vm_flags" argument to do_mmap_pgoff(), rename it to do_mmap(), and re-introduce do_mmap_pgoff() as a simple wrapper on top of do_mmap(). Perhaps we should update the callers of do_mmap_pgoff() and kill it later. This way mpx_mmap() can simply call do_mmap(vm_flags => VM_MPX) and do not play with vm internals. After this change mmap_region() has a single user outside of mmap.c, arch/tile/mm/elf.c:arch_setup_additional_pages(). It would be nice to change arch/tile/ and unexport mmap_region(). [kirill@shutemov.name: fix build] [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Oleg Nesterov Acked-by: Dave Hansen Tested-by: Dave Hansen Signed-off-by: Kirill A. Shutemov Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Ingo Molnar Cc: Minchan Kim Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/x86/mm/mpx.c | 51 +++++++--------------------------------------- include/linux/mm.h | 12 +++++++++-- mm/mmap.c | 10 ++++----- mm/nommu.c | 19 +++++++++-------- 4 files changed, 31 insertions(+), 61 deletions(-) diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c index db1b0bc5017c9..134948b0926f5 100644 --- a/arch/x86/mm/mpx.c +++ b/arch/x86/mm/mpx.c @@ -42,58 +42,21 @@ static inline unsigned long mpx_bt_size_bytes(struct mm_struct *mm) */ static unsigned long mpx_mmap(unsigned long len) { - unsigned long ret; - unsigned long addr, pgoff; struct mm_struct *mm = current->mm; - vm_flags_t vm_flags; - struct vm_area_struct *vma; + unsigned long addr, populate; /* Only bounds table can be allocated here */ if (len != mpx_bt_size_bytes(mm)) return -EINVAL; down_write(&mm->mmap_sem); - - /* Too many mappings? */ - if (mm->map_count > sysctl_max_map_count) { - ret = -ENOMEM; - goto out; - } - - /* Obtain the address to map to. we verify (or select) it and ensure - * that it represents a valid section of the address space. - */ - addr = get_unmapped_area(NULL, 0, len, 0, MAP_ANONYMOUS | MAP_PRIVATE); - if (addr & ~PAGE_MASK) { - ret = addr; - goto out; - } - - vm_flags = VM_READ | VM_WRITE | VM_MPX | - mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; - - /* Set pgoff according to addr for anon_vma */ - pgoff = addr >> PAGE_SHIFT; - - ret = mmap_region(NULL, addr, len, vm_flags, pgoff); - if (IS_ERR_VALUE(ret)) - goto out; - - vma = find_vma(mm, ret); - if (!vma) { - ret = -ENOMEM; - goto out; - } - - if (vm_flags & VM_LOCKED) { - up_write(&mm->mmap_sem); - mm_populate(ret, len); - return ret; - } - -out: + addr = do_mmap(NULL, 0, len, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, VM_MPX, 0, &populate); up_write(&mm->mmap_sem); - return ret; + if (populate) + mm_populate(addr, populate); + + return addr; } enum reg_type { diff --git a/include/linux/mm.h b/include/linux/mm.h index f25a957bf0ab6..fda728e3c27d0 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1873,11 +1873,19 @@ extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned lo extern unsigned long mmap_region(struct file *file, unsigned long addr, unsigned long len, vm_flags_t vm_flags, unsigned long pgoff); -extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, +extern unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, - unsigned long pgoff, unsigned long *populate); + vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate); extern int do_munmap(struct mm_struct *, unsigned long, size_t); +static inline unsigned long +do_mmap_pgoff(struct file *file, unsigned long addr, + unsigned long len, unsigned long prot, unsigned long flags, + unsigned long pgoff, unsigned long *populate) +{ + return do_mmap(file, addr, len, prot, flags, 0, pgoff, populate); +} + #ifdef CONFIG_MMU extern int __mm_populate(unsigned long addr, unsigned long len, int ignore_errors); diff --git a/mm/mmap.c b/mm/mmap.c index b6be3249f0a92..c739d6db7193e 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1260,14 +1260,12 @@ static inline int mlock_future_check(struct mm_struct *mm, /* * The caller must hold down_write(¤t->mm->mmap_sem). */ - -unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, +unsigned long do_mmap(struct file *file, unsigned long addr, unsigned long len, unsigned long prot, - unsigned long flags, unsigned long pgoff, - unsigned long *populate) + unsigned long flags, vm_flags_t vm_flags, + unsigned long pgoff, unsigned long *populate) { struct mm_struct *mm = current->mm; - vm_flags_t vm_flags; *populate = 0; @@ -1311,7 +1309,7 @@ unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, * to. we assume access permissions have been handled by the open * of the memory object, so we don't do any here. */ - vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags) | + vm_flags |= calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; if (flags & MAP_LOCKED) diff --git a/mm/nommu.c b/mm/nommu.c index 1cc0709fcaa53..ab14a2014dea7 100644 --- a/mm/nommu.c +++ b/mm/nommu.c @@ -1233,18 +1233,19 @@ enomem: /* * handle mapping creation for uClinux */ -unsigned long do_mmap_pgoff(struct file *file, - unsigned long addr, - unsigned long len, - unsigned long prot, - unsigned long flags, - unsigned long pgoff, - unsigned long *populate) +unsigned long do_mmap(struct file *file, + unsigned long addr, + unsigned long len, + unsigned long prot, + unsigned long flags, + vm_flags_t vm_flags, + unsigned long pgoff, + unsigned long *populate) { struct vm_area_struct *vma; struct vm_region *region; struct rb_node *rb; - unsigned long capabilities, vm_flags, result; + unsigned long capabilities, result; int ret; *populate = 0; @@ -1262,7 +1263,7 @@ unsigned long do_mmap_pgoff(struct file *file, /* we've determined that we can make the mapping, now translate what we * now know into VMA flags */ - vm_flags = determine_vm_flags(file, prot, flags, capabilities); + vm_flags |= determine_vm_flags(file, prot, flags, capabilities); /* we're going to need to record the mapping */ region = kmem_cache_zalloc(vm_region_jar, GFP_KERNEL); -- GitLab From 6dc296e7df4c9a0857491cc3f55da16a9eeeeae7 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Wed, 9 Sep 2015 15:39:32 -0700 Subject: [PATCH 6975/7006] mm: make sure all file VMAs have ->vm_ops set We rely on vma->vm_ops == NULL to detect anonymous VMA: see vma_is_anonymous(), but some drivers doesn't set ->vm_ops. As a result we can end up with anonymous page in private file mapping. That should not lead to serious misbehaviour, but nevertheless is wrong. Let's fix by setting up dummy ->vm_ops for file mmapping if f_op->mmap() didn't set its own. The patch also adds sanity check into __vma_link_rb(). It will help catch broken VMAs which inserted directly into mm_struct via insert_vm_struct(). Signed-off-by: Kirill A. Shutemov Reviewed-by: Oleg Nesterov Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Ingo Molnar Cc: Minchan Kim Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/mmap.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/mm/mmap.c b/mm/mmap.c index c739d6db7193e..971dd2cb77d22 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -612,6 +612,8 @@ static unsigned long count_vma_pages_range(struct mm_struct *mm, void __vma_link_rb(struct mm_struct *mm, struct vm_area_struct *vma, struct rb_node **rb_link, struct rb_node *rb_parent) { + WARN_ONCE(vma->vm_file && !vma->vm_ops, "missing vma->vm_ops"); + /* Update tracking information for the gap following the new vma. */ if (vma->vm_next) vma_gap_update(vma->vm_next); @@ -1636,6 +1638,12 @@ unsigned long mmap_region(struct file *file, unsigned long addr, */ WARN_ON_ONCE(addr != vma->vm_start); + /* All file mapping must have ->vm_ops set */ + if (!vma->vm_ops) { + static const struct vm_operations_struct dummy_ops = {}; + vma->vm_ops = &dummy_ops; + } + addr = vma->vm_start; vm_flags = vma->vm_flags; } else if (vm_flags & VM_SHARED) { -- GitLab From fb6dd5fa4165c4b82f1a11416c2fc192ae3a84e2 Mon Sep 17 00:00:00 2001 From: "Kirill A. Shutemov" Date: Wed, 9 Sep 2015 15:39:35 -0700 Subject: [PATCH 6976/7006] mm: use vma_is_anonymous() in create_huge_pmd() and wp_huge_pmd() Let's use helper rather than direct check of vma->vm_ops to distinguish anonymous VMA. Signed-off-by: Kirill A. Shutemov Reviewed-by: Oleg Nesterov Cc: "H. Peter Anvin" Cc: Andy Lutomirski Cc: Dave Hansen Cc: Ingo Molnar Cc: Minchan Kim Cc: Thomas Gleixner Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/memory.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 6cd0b21604019..9cb27470fee99 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3233,7 +3233,7 @@ out: static int create_huge_pmd(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pmd_t *pmd, unsigned int flags) { - if (!vma->vm_ops) + if (vma_is_anonymous(vma)) return do_huge_pmd_anonymous_page(mm, vma, address, pmd, flags); if (vma->vm_ops->pmd_fault) return vma->vm_ops->pmd_fault(vma, address, pmd, flags); @@ -3244,7 +3244,7 @@ static int wp_huge_pmd(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pmd_t *pmd, pmd_t orig_pmd, unsigned int flags) { - if (!vma->vm_ops) + if (vma_is_anonymous(vma)) return do_huge_pmd_wp_page(mm, vma, address, pmd, orig_pmd); if (vma->vm_ops->pmd_fault) return vma->vm_ops->pmd_fault(vma, address, pmd, flags); -- GitLab From 6894258eda2f9badc28c878086c0e54bd5b7fb30 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 9 Sep 2015 15:39:39 -0700 Subject: [PATCH 6977/7006] dma-mapping: consolidate dma_{alloc,free}_{attrs,coherent} Since 2009 we have a nice asm-generic header implementing lots of DMA API functions for architectures using struct dma_map_ops, but unfortunately it's still missing a lot of APIs that all architectures still have to duplicate. This series consolidates the remaining functions, although we still need arch opt outs for two of them as a few architectures have very non-standard implementations. This patch (of 5): The coherent DMA allocator works the same over all architectures supporting dma_map operations. This patch consolidates them and converges the minor differences: - the debug_dma helpers are now called from all architectures, including those that were previously missing them - dma_alloc_from_coherent and dma_release_from_coherent are now always called from the generic alloc/free routines instead of the ops dma-mapping-common.h always includes dma-coherent.h to get the defintions for them, or the stubs if the architecture doesn't support this feature - checks for ->alloc / ->free presence are removed. There is only one magic instead of dma_map_ops without them (mic_dma_ops) and that one is x86 only anyway. Besides that only x86 needs special treatment to replace a default devices if none is passed and tweak the gfp_flags. An optional arch hook is provided for that. [linux@roeck-us.net: fix build] [jcmvbkbc@gmail.com: fix xtensa] Signed-off-by: Christoph Hellwig Cc: Arnd Bergmann Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Yoshinori Sato Cc: Michal Simek Cc: Jonas Bonn Cc: Chris Metcalf Cc: Guan Xuetao Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Andy Shevchenko Signed-off-by: Guenter Roeck Signed-off-by: Max Filippov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/dma-mapping.h | 18 ------- arch/arm/include/asm/dma-mapping.h | 29 ------------ arch/arm/mm/dma-mapping.c | 12 ----- arch/arm64/include/asm/dma-mapping.h | 33 ------------- arch/h8300/include/asm/dma-mapping.h | 26 ---------- arch/hexagon/include/asm/dma-mapping.h | 33 ------------- arch/ia64/include/asm/dma-mapping.h | 25 ---------- arch/microblaze/include/asm/dma-mapping.h | 31 ------------ arch/mips/cavium-octeon/dma-octeon.c | 8 ---- arch/mips/include/asm/dma-mapping.h | 31 ------------ arch/mips/loongson64/common/dma-swiotlb.c | 8 ---- arch/mips/mm/dma-default.c | 7 --- arch/mips/netlogic/common/nlm-dma.c | 10 ---- arch/openrisc/include/asm/dma-mapping.h | 30 ------------ arch/powerpc/include/asm/dma-mapping.h | 33 ------------- arch/s390/include/asm/dma-mapping.h | 31 ------------ arch/sh/include/asm/dma-mapping.h | 37 --------------- arch/sparc/include/asm/dma-mapping.h | 26 ---------- arch/tile/include/asm/dma-mapping.h | 27 ----------- arch/unicore32/include/asm/dma-mapping.h | 24 ---------- arch/x86/include/asm/dma-mapping.h | 16 ++----- arch/x86/kernel/pci-dma.c | 49 ++++--------------- arch/xtensa/include/asm/dma-mapping.h | 31 ------------ drivers/xen/swiotlb-xen.c | 6 --- include/asm-generic/dma-mapping-common.h | 58 +++++++++++++++++++++++ 25 files changed, 70 insertions(+), 569 deletions(-) diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index dfa32f0613201..9fef5bd59a826 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -12,24 +12,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - struct dma_attrs *attrs) -{ - return get_dma_ops(dev)->alloc(dev, size, dma_handle, gfp, attrs); -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - get_dma_ops(dev)->free(dev, size, vaddr, dma_handle, attrs); -} - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return get_dma_ops(dev)->mapping_error(dev, dma_addr); diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index a68b9d8a71fed..bc404473f1cac 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -8,7 +8,6 @@ #include #include -#include #include #include @@ -209,21 +208,6 @@ extern int arm_dma_set_mask(struct device *dev, u64 dma_mask); extern void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs); -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *cpu_addr; - BUG_ON(!ops); - - cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); - return cpu_addr; -} - /** * arm_dma_free - free memory allocated by arm_dma_alloc * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices @@ -241,19 +225,6 @@ static inline void *dma_alloc_attrs(struct device *dev, size_t size, extern void arm_dma_free(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle, struct dma_attrs *attrs); -#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - BUG_ON(!ops); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - /** * arm_dma_mmap - map a coherent DMA allocation into user space * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c index bf35abcc7d598..e62604384945e 100644 --- a/arch/arm/mm/dma-mapping.c +++ b/arch/arm/mm/dma-mapping.c @@ -676,10 +676,6 @@ void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) { pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL); - void *memory; - - if (dma_alloc_from_coherent(dev, size, handle, &memory)) - return memory; return __dma_alloc(dev, size, handle, gfp, prot, false, attrs, __builtin_return_address(0)); @@ -688,11 +684,6 @@ void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, static void *arm_coherent_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp, struct dma_attrs *attrs) { - void *memory; - - if (dma_alloc_from_coherent(dev, size, handle, &memory)) - return memory; - return __dma_alloc(dev, size, handle, gfp, PAGE_KERNEL, true, attrs, __builtin_return_address(0)); } @@ -752,9 +743,6 @@ static void __arm_dma_free(struct device *dev, size_t size, void *cpu_addr, struct page *page = pfn_to_page(dma_to_pfn(dev, handle)); bool want_vaddr = !dma_get_attr(DMA_ATTR_NO_KERNEL_MAPPING, attrs); - if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) - return; - size = PAGE_ALIGN(size); if (nommu()) { diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index f0d6d0bfe55ce..5e11b3f0fe3a4 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -22,8 +22,6 @@ #include #include -#include - #include #include @@ -120,37 +118,6 @@ static inline void dma_mark_clean(void *addr, size_t size) { } -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) -#define dma_free_coherent(d, s, h, f) dma_free_attrs(d, s, h, f, NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flags, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *vaddr; - - if (dma_alloc_from_coherent(dev, size, dma_handle, &vaddr)) - return vaddr; - - vaddr = ops->alloc(dev, size, dma_handle, flags, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, vaddr); - return vaddr; -} - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t dev_addr, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (dma_release_from_coherent(dev, get_order(size), vaddr)) - return; - - debug_dma_free_coherent(dev, size, vaddr, dev_addr); - ops->free(dev, size, vaddr, dev_addr, attrs); -} - /* * There is no dma_cache_sync() implementation, so just return NULL here. */ diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h index 6e67a90902f28..826aa9b519b78 100644 --- a/arch/h8300/include/asm/dma-mapping.h +++ b/arch/h8300/include/asm/dma-mapping.h @@ -1,8 +1,6 @@ #ifndef _H8300_DMA_MAPPING_H #define _H8300_DMA_MAPPING_H -#include - extern struct dma_map_ops h8300_dma_map_ops; static inline struct dma_map_ops *get_dma_ops(struct device *dev) @@ -25,30 +23,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *memory; - - memory = ops->alloc(dev, size, dma_handle, flag, attrs); - return memory; -} - -#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return 0; diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h index 16965427f6b48..c20d3caa7dada 100644 --- a/arch/hexagon/include/asm/dma-mapping.h +++ b/arch/hexagon/include/asm/dma-mapping.h @@ -70,37 +70,4 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return (dma_addr == bad_dma_address); } -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - void *ret; - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - - ret = ops->alloc(dev, size, dma_handle, flag, attrs); - - debug_dma_alloc_coherent(dev, size, *dma_handle, ret); - - return ret; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - - dma_ops->free(dev, size, cpu_addr, dma_handle, attrs); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); -} - #endif diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index cf3ab7e784b54..d36f83cc226ad 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -23,31 +23,6 @@ extern void machvec_dma_sync_single(struct device *, dma_addr_t, size_t, extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *daddr, gfp_t gfp, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = platform_dma_get_ops(dev); - void *caddr; - - caddr = ops->alloc(dev, size, daddr, gfp, attrs); - debug_dma_alloc_coherent(dev, size, *daddr, caddr); - return caddr; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *caddr, dma_addr_t daddr, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = platform_dma_get_ops(dev); - debug_dma_free_coherent(dev, size, caddr, daddr); - ops->free(dev, size, caddr, daddr, attrs); -} - #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index ab353723076a8..801dbe215a8cb 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -27,7 +27,6 @@ #include #include #include -#include #include #define DMA_ERROR_CODE (~(dma_addr_t)0x0) @@ -102,36 +101,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *memory; - - BUG_ON(!ops); - - memory = ops->alloc(dev, size, dma_handle, flag, attrs); - - debug_dma_alloc_coherent(dev, size, *dma_handle, memory); - return memory; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d, s, c, h, NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!ops); - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mips/cavium-octeon/dma-octeon.c b/arch/mips/cavium-octeon/dma-octeon.c index d8960d46417b0..2cd45f5f9481c 100644 --- a/arch/mips/cavium-octeon/dma-octeon.c +++ b/arch/mips/cavium-octeon/dma-octeon.c @@ -161,9 +161,6 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size, { void *ret; - if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) - return ret; - /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM); @@ -194,11 +191,6 @@ static void *octeon_dma_alloc_coherent(struct device *dev, size_t size, static void octeon_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) { - int order = get_order(size); - - if (dma_release_from_coherent(dev, order, vaddr)) - return; - swiotlb_free_coherent(dev, size, vaddr, dma_handle); } diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 360b3387182af..b197595134ba0 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -4,7 +4,6 @@ #include #include #include -#include #ifndef CONFIG_SGI_IP27 /* Kludge to fix 2.6.39 build for IP27 */ #include @@ -65,36 +64,6 @@ dma_set_mask(struct device *dev, u64 mask) extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - struct dma_attrs *attrs) -{ - void *ret; - struct dma_map_ops *ops = get_dma_ops(dev); - - ret = ops->alloc(dev, size, dma_handle, gfp, attrs); - - debug_dma_alloc_coherent(dev, size, *dma_handle, ret); - - return ret; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - ops->free(dev, size, vaddr, dma_handle, attrs); - - debug_dma_free_coherent(dev, size, vaddr, dma_handle); -} - - void *dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag); diff --git a/arch/mips/loongson64/common/dma-swiotlb.c b/arch/mips/loongson64/common/dma-swiotlb.c index 2c6b989c1bc40..ef9da3b5c543f 100644 --- a/arch/mips/loongson64/common/dma-swiotlb.c +++ b/arch/mips/loongson64/common/dma-swiotlb.c @@ -14,9 +14,6 @@ static void *loongson_dma_alloc_coherent(struct device *dev, size_t size, { void *ret; - if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) - return ret; - /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM); @@ -46,11 +43,6 @@ static void *loongson_dma_alloc_coherent(struct device *dev, size_t size, static void loongson_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) { - int order = get_order(size); - - if (dma_release_from_coherent(dev, order, vaddr)) - return; - swiotlb_free_coherent(dev, size, vaddr, dma_handle); } diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 8f23cf08f4baa..6c0fd13fa8e87 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -137,9 +137,6 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, struct page *page = NULL; unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; - if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) - return ret; - gfp = massage_gfp_flags(dev, gfp); if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC)) @@ -176,13 +173,9 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) { unsigned long addr = (unsigned long) vaddr; - int order = get_order(size); unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = NULL; - if (dma_release_from_coherent(dev, order, vaddr)) - return; - plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); if (!plat_device_is_coherent(dev) && !hw_coherentio) diff --git a/arch/mips/netlogic/common/nlm-dma.c b/arch/mips/netlogic/common/nlm-dma.c index f3d4ae87abc7f..3758715d4ab67 100644 --- a/arch/mips/netlogic/common/nlm-dma.c +++ b/arch/mips/netlogic/common/nlm-dma.c @@ -47,11 +47,6 @@ static char *nlm_swiotlb; static void *nlm_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp, struct dma_attrs *attrs) { - void *ret; - - if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) - return ret; - /* ignore region specifiers */ gfp &= ~(__GFP_DMA | __GFP_DMA32 | __GFP_HIGHMEM); @@ -69,11 +64,6 @@ static void *nlm_dma_alloc_coherent(struct device *dev, size_t size, static void nlm_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) { - int order = get_order(size); - - if (dma_release_from_coherent(dev, order, vaddr)) - return; - swiotlb_free_coherent(dev, size, vaddr, dma_handle); } diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index fab8628e1b6e7..a81d6f68e9c8f 100644 --- a/arch/openrisc/include/asm/dma-mapping.h +++ b/arch/openrisc/include/asm/dma-mapping.h @@ -23,7 +23,6 @@ */ #include -#include #include #include @@ -38,35 +37,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *memory; - - memory = ops->alloc(dev, size, dma_handle, gfp, attrs); - - debug_dma_alloc_coherent(dev, size, *dma_handle, memory); - - return memory; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp) { diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 710f60e380e07..e6ca63ac4c6c8 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -137,39 +137,6 @@ extern int dma_set_mask(struct device *dev, u64 dma_mask); extern int __dma_set_mask(struct device *dev, u64 dma_mask); extern u64 __dma_get_required_mask(struct device *dev); -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - void *cpu_addr; - - BUG_ON(!dma_ops); - - cpu_addr = dma_ops->alloc(dev, size, dma_handle, flag, attrs); - - debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); - - return cpu_addr; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - BUG_ON(!dma_ops); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - - dma_ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *dma_ops = get_dma_ops(dev); diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index 9d395961e7138..c29c9c7d81e83 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h @@ -56,35 +56,4 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return dma_addr == DMA_ERROR_CODE; } -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flags, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *cpu_addr; - - BUG_ON(!ops); - - cpu_addr = ops->alloc(dev, size, dma_handle, flags, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); - - return cpu_addr; -} - -#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!ops); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - #endif /* _ASM_S390_DMA_MAPPING_H */ diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index b437f2c780b83..3c78059e66ffb 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -9,7 +9,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return dma_ops; } -#include #include static inline int dma_supported(struct device *dev, u64 mask) @@ -53,42 +52,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return dma_addr == 0; } -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *memory; - - if (dma_alloc_from_coherent(dev, size, dma_handle, &memory)) - return memory; - if (!ops->alloc) - return NULL; - - memory = ops->alloc(dev, size, dma_handle, gfp, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, memory); - - return memory; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (dma_release_from_coherent(dev, get_order(size), vaddr)) - return; - - debug_dma_free_coherent(dev, size, vaddr, dma_handle); - if (ops->free) - ops->free(dev, size, vaddr, dma_handle, attrs); -} - /* arch/sh/mm/consistent.c */ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 7e064c68c5ec8..a8c678494ce7d 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -41,32 +41,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *cpu_addr; - - cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); - return cpu_addr; -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { debug_dma_mapping_error(dev, dma_addr); diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index 1eae359d83150..4aba10e49310b 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -116,34 +116,7 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - void *cpu_addr; - - cpu_addr = dma_ops->alloc(dev, size, dma_handle, flag, attrs); - - debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); - - return cpu_addr; -} - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - - dma_ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) -#define dma_free_coherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL) #define dma_free_noncoherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL) /* diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h index 366460a817965..5294d03e59de5 100644 --- a/arch/unicore32/include/asm/dma-mapping.h +++ b/arch/unicore32/include/asm/dma-mapping.h @@ -18,8 +18,6 @@ #include #include -#include - #include #include @@ -82,28 +80,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) return 0; } -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - return dma_ops->alloc(dev, size, dma_handle, flag, attrs); -} - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - dma_ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) #define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 1f5b7287d1ad8..f9b1b6cc48b6e 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #ifdef CONFIG_ISA @@ -41,6 +40,9 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #endif } +bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp); +#define arch_dma_alloc_attrs arch_dma_alloc_attrs + #include /* Make sure we keep the same behaviour */ @@ -125,16 +127,4 @@ static inline gfp_t dma_alloc_coherent_gfp_flags(struct device *dev, gfp_t gfp) return gfp; } -#define dma_alloc_coherent(d,s,h,f) dma_alloc_attrs(d,s,h,f,NULL) - -void * -dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t gfp, struct dma_attrs *attrs); - -#define dma_free_coherent(d,s,c,h) dma_free_attrs(d,s,c,h,NULL) - -void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t bus, - struct dma_attrs *attrs); - #endif diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index 353972c1946cd..bd23971e8f1df 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -140,50 +140,19 @@ void dma_generic_free_coherent(struct device *dev, size_t size, void *vaddr, free_pages((unsigned long)vaddr, get_order(size)); } -void *dma_alloc_attrs(struct device *dev, size_t size, dma_addr_t *dma_handle, - gfp_t gfp, struct dma_attrs *attrs) +bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp) { - struct dma_map_ops *ops = get_dma_ops(dev); - void *memory; - - gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); - - if (dma_alloc_from_coherent(dev, size, dma_handle, &memory)) - return memory; - - if (!dev) - dev = &x86_dma_fallback_dev; - - if (!is_device_dma_capable(dev)) - return NULL; - - if (!ops->alloc) - return NULL; - - memory = ops->alloc(dev, size, dma_handle, - dma_alloc_coherent_gfp_flags(dev, gfp), attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, memory); - - return memory; -} -EXPORT_SYMBOL(dma_alloc_attrs); - -void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t bus, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - WARN_ON(irqs_disabled()); /* for portability */ + *gfp = dma_alloc_coherent_gfp_flags(*dev, *gfp); + *gfp &= ~(__GFP_DMA | __GFP_HIGHMEM | __GFP_DMA32); - if (dma_release_from_coherent(dev, get_order(size), vaddr)) - return; + if (!*dev) + *dev = &x86_dma_fallback_dev; + if (!is_device_dma_capable(*dev)) + return false; + return true; - debug_dma_free_coherent(dev, size, vaddr, bus); - if (ops->free) - ops->free(dev, size, vaddr, bus, attrs); } -EXPORT_SYMBOL(dma_free_attrs); +EXPORT_SYMBOL(arch_dma_alloc_attrs); /* * See for the iommu kernel diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index f01cb3044e50d..bf24c908e5ff7 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -34,37 +34,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #define dma_alloc_noncoherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) #define dma_free_noncoherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL) -#define dma_alloc_coherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) -#define dma_free_coherent(d, s, c, h) dma_free_attrs(d, s, c, h, NULL) - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - struct dma_attrs *attrs) -{ - void *ret; - struct dma_map_ops *ops = get_dma_ops(dev); - - if (dma_alloc_from_coherent(dev, size, dma_handle, &ret)) - return ret; - - ret = ops->alloc(dev, size, dma_handle, gfp, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, ret); - - return ret; -} - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - struct dma_attrs *attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (dma_release_from_coherent(dev, get_order(size), vaddr)) - return; - - ops->free(dev, size, vaddr, dma_handle, attrs); - debug_dma_free_coherent(dev, size, vaddr, dma_handle); -} static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 4c549323c605d..da1029ef81592 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -311,9 +311,6 @@ xen_swiotlb_alloc_coherent(struct device *hwdev, size_t size, */ flags &= ~(__GFP_DMA | __GFP_HIGHMEM); - if (dma_alloc_from_coherent(hwdev, size, dma_handle, &ret)) - return ret; - /* On ARM this function returns an ioremap'ped virtual address for * which virt_to_phys doesn't return the corresponding physical * address. In fact on ARM virt_to_phys only works for kernel direct @@ -356,9 +353,6 @@ xen_swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr, phys_addr_t phys; u64 dma_mask = DMA_BIT_MASK(32); - if (dma_release_from_coherent(hwdev, order, vaddr)) - return; - if (hwdev && hwdev->coherent_dma_mask) dma_mask = hwdev->coherent_dma_mask; diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 940d5ec122c96..56dd9ea2bc8c8 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -6,6 +6,7 @@ #include #include #include +#include static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, size_t size, @@ -237,4 +238,61 @@ dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr, #define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, NULL) +#ifndef arch_dma_alloc_attrs +#define arch_dma_alloc_attrs(dev, flag) (true) +#endif + +static inline void *dma_alloc_attrs(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + void *cpu_addr; + + BUG_ON(!ops); + + if (dma_alloc_from_coherent(dev, size, dma_handle, &cpu_addr)) + return cpu_addr; + + if (!arch_dma_alloc_attrs(&dev, &flag)) + return NULL; + if (!ops->alloc) + return NULL; + + cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs); + debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); + return cpu_addr; +} + +static inline void dma_free_attrs(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle, + struct dma_attrs *attrs) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + BUG_ON(!ops); + WARN_ON(irqs_disabled()); + + if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) + return; + + if (!ops->free) + return; + + debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); + ops->free(dev, size, cpu_addr, dma_handle, attrs); +} + +static inline void *dma_alloc_coherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t flag) +{ + return dma_alloc_attrs(dev, size, dma_handle, flag, NULL); +} + +static inline void dma_free_coherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + return dma_free_attrs(dev, size, cpu_addr, dma_handle, NULL); +} + #endif -- GitLab From 1e8937526e2309d48fccd81bb30a590ac21a5516 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 9 Sep 2015 15:39:42 -0700 Subject: [PATCH 6978/7006] dma-mapping: consolidate dma_{alloc,free}_noncoherent Most architectures do not support non-coherent allocations and either define dma_{alloc,free}_noncoherent to their coherent versions or stub them out. Openrisc uses dma_{alloc,free}_attrs to implement them, and only Mips implements them directly. This patch moves the Openrisc version to common code, and handles the DMA_ATTR_NON_CONSISTENT case in the mips dma_map_ops instance. Note that actual non-coherent allocations require a dma_cache_sync implementation, so if non-coherent allocations didn't work on an architecture before this patch they still won't work after it. [jcmvbkbc@gmail.com: fix xtensa] Signed-off-by: Christoph Hellwig Cc: Arnd Bergmann Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Yoshinori Sato Cc: Michal Simek Cc: Jonas Bonn Cc: Chris Metcalf Cc: Guan Xuetao Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Andy Shevchenko Signed-off-by: Max Filippov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/dma-mapping.h | 3 --- arch/arm/include/asm/dma-mapping.h | 21 ++++++--------------- arch/arm64/include/asm/dma-mapping.h | 14 -------------- arch/h8300/include/asm/dma-mapping.h | 3 --- arch/hexagon/include/asm/dma-mapping.h | 3 --- arch/ia64/include/asm/dma-mapping.h | 3 --- arch/microblaze/include/asm/dma-mapping.h | 3 --- arch/mips/include/asm/dma-mapping.h | 6 ------ arch/mips/mm/dma-default.c | 20 +++++++++++++++----- arch/openrisc/include/asm/dma-mapping.h | 20 -------------------- arch/powerpc/include/asm/dma-mapping.h | 3 --- arch/s390/include/asm/dma-mapping.h | 3 --- arch/sh/include/asm/dma-mapping.h | 3 --- arch/sparc/include/asm/dma-mapping.h | 3 --- arch/tile/include/asm/dma-mapping.h | 3 --- arch/unicore32/include/asm/dma-mapping.h | 3 --- arch/x86/include/asm/dma-mapping.h | 3 --- arch/xtensa/include/asm/dma-mapping.h | 3 --- include/asm-generic/dma-mapping-common.h | 18 ++++++++++++++++++ 19 files changed, 39 insertions(+), 99 deletions(-) diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index 9fef5bd59a826..0552bf097245d 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -27,9 +27,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) return get_dma_ops(dev)->set_dma_mask(dev, mask); } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - #define dma_cache_sync(dev, va, size, dir) ((void)0) #endif /* _ALPHA_DMA_MAPPING_H */ diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index bc404473f1cac..0b7787167b640 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -38,6 +38,12 @@ static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) dev->archdata.dma_ops = ops; } +/* + * Note that while the generic code provides dummy dma_{alloc,free}_noncoherent + * implementations, we don't provide a dma_cache_sync function so drivers using + * this API are highlighted with build warnings. + */ + #include static inline int dma_set_mask(struct device *dev, u64 mask) @@ -175,21 +181,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return dma_addr == DMA_ERROR_CODE; } -/* - * Dummy noncoherent implementation. We don't provide a dma_cache_sync - * function so drivers using this API are highlighted with build warnings. - */ -static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *handle, gfp_t gfp) -{ - return NULL; -} - -static inline void dma_free_noncoherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t handle) -{ -} - extern int dma_supported(struct device *dev, u64 mask); extern int arm_dma_set_mask(struct device *dev, u64 dma_mask); diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index 5e11b3f0fe3a4..178e60b809224 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -118,19 +118,5 @@ static inline void dma_mark_clean(void *addr, size_t size) { } -/* - * There is no dma_cache_sync() implementation, so just return NULL here. - */ -static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *handle, gfp_t flags) -{ - return NULL; -} - -static inline void dma_free_noncoherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t handle) -{ -} - #endif /* __KERNEL__ */ #endif /* __ASM_DMA_MAPPING_H */ diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h index 826aa9b519b78..72465ce594539 100644 --- a/arch/h8300/include/asm/dma-mapping.h +++ b/arch/h8300/include/asm/dma-mapping.h @@ -20,9 +20,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { return 0; diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h index c20d3caa7dada..58d2d8f1544ac 100644 --- a/arch/hexagon/include/asm/dma-mapping.h +++ b/arch/hexagon/include/asm/dma-mapping.h @@ -34,9 +34,6 @@ extern int bad_dma_address; extern struct dma_map_ops *dma_ops; -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - static inline struct dma_map_ops *get_dma_ops(struct device *dev) { if (unlikely(dev == NULL)) diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index d36f83cc226ad..a925ff03c9640 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -23,9 +23,6 @@ extern void machvec_dma_sync_single(struct device *, dma_addr_t, size_t, extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int, enum dma_data_direction); -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - #define get_dma_ops(dev) platform_dma_get_ops(dev) #include diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index 801dbe215a8cb..bc81625d486fd 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -98,9 +98,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return (dma_addr == DMA_ERROR_CODE); } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index b197595134ba0..709b2ba79cc33 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -64,10 +64,4 @@ dma_set_mask(struct device *dev, u64 mask) extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); -void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag); - -void dma_free_noncoherent(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle); - #endif /* _ASM_DMA_MAPPING_H */ diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 6c0fd13fa8e87..a914dc1cb6d1b 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -112,7 +112,7 @@ static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp) return gfp | dma_flag; } -void *dma_alloc_noncoherent(struct device *dev, size_t size, +static void *mips_dma_alloc_noncoherent(struct device *dev, size_t size, dma_addr_t * dma_handle, gfp_t gfp) { void *ret; @@ -128,7 +128,6 @@ void *dma_alloc_noncoherent(struct device *dev, size_t size, return ret; } -EXPORT_SYMBOL(dma_alloc_noncoherent); static void *mips_dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t * dma_handle, gfp_t gfp, struct dma_attrs *attrs) @@ -137,6 +136,13 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, struct page *page = NULL; unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; + /* + * XXX: seems like the coherent and non-coherent implementations could + * be consolidated. + */ + if (dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) + return mips_dma_alloc_noncoherent(dev, size, dma_handle, gfp); + gfp = massage_gfp_flags(dev, gfp); if (IS_ENABLED(CONFIG_DMA_CMA) && !(gfp & GFP_ATOMIC)) @@ -161,13 +167,12 @@ static void *mips_dma_alloc_coherent(struct device *dev, size_t size, } -void dma_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) +static void mips_dma_free_noncoherent(struct device *dev, size_t size, + void *vaddr, dma_addr_t dma_handle) { plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); free_pages((unsigned long) vaddr, get_order(size)); } -EXPORT_SYMBOL(dma_free_noncoherent); static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, dma_addr_t dma_handle, struct dma_attrs *attrs) @@ -176,6 +181,11 @@ static void mips_dma_free_coherent(struct device *dev, size_t size, void *vaddr, unsigned int count = PAGE_ALIGN(size) >> PAGE_SHIFT; struct page *page = NULL; + if (dma_get_attr(DMA_ATTR_NON_CONSISTENT, attrs)) { + mips_dma_free_noncoherent(dev, size, vaddr, dma_handle); + return; + } + plat_unmap_dma_mem(dev, dma_handle, size, DMA_BIDIRECTIONAL); if (!plat_device_is_coherent(dev) && !hw_coherentio) diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index a81d6f68e9c8f..57722528ea4d4 100644 --- a/arch/openrisc/include/asm/dma-mapping.h +++ b/arch/openrisc/include/asm/dma-mapping.h @@ -37,26 +37,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) -{ - struct dma_attrs attrs; - - dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); - - return dma_alloc_attrs(dev, size, dma_handle, gfp, &attrs); -} - -static inline void dma_free_noncoherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - struct dma_attrs attrs; - - dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); - - dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); -} - static inline int dma_supported(struct device *dev, u64 dma_mask) { /* Support 32 bit DMA mask exclusively */ diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index e6ca63ac4c6c8..7971b421c6771 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -177,9 +177,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) return daddr - get_dma_offset(dev); } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - #define ARCH_HAS_DMA_MMAP_COHERENT static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index c29c9c7d81e83..b729efeb9ad8b 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h @@ -25,9 +25,6 @@ static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, { } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - #include static inline int dma_supported(struct device *dev, u64 mask) diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 3c78059e66ffb..2c3fa2ccbe9b4 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -38,9 +38,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir); -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { struct dma_map_ops *ops = get_dma_ops(dev); diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index a8c678494ce7d..2564edcb97280 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -9,9 +9,6 @@ int dma_supported(struct device *dev, u64 mask); -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir) { diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index 4aba10e49310b..e982dfa5d2f4b 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -116,9 +116,6 @@ dma_set_mask(struct device *dev, u64 mask) return 0; } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) -#define dma_free_noncoherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL) - /* * dma_alloc_noncoherent() is #defined to return coherent memory, * so there's no need to do any flushing here. diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h index 5294d03e59de5..636e942940a04 100644 --- a/arch/unicore32/include/asm/dma-mapping.h +++ b/arch/unicore32/include/asm/dma-mapping.h @@ -80,9 +80,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) return 0; } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index f9b1b6cc48b6e..7e47e4d6e69cd 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -56,9 +56,6 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) return (dma_addr == DMA_ERROR_CODE); } -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f) -#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h) - extern int dma_supported(struct device *hwdev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask); diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index bf24c908e5ff7..0a19581375dac 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -32,9 +32,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_attrs(d, s, h, f, NULL) -#define dma_free_noncoherent(d, s, v, h) dma_free_attrs(d, s, v, h, NULL) - static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) { diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 56dd9ea2bc8c8..ec321dd98f93b 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -295,4 +295,22 @@ static inline void dma_free_coherent(struct device *dev, size_t size, return dma_free_attrs(dev, size, cpu_addr, dma_handle, NULL); } +static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp) +{ + DEFINE_DMA_ATTRS(attrs); + + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); + return dma_alloc_attrs(dev, size, dma_handle, gfp, &attrs); +} + +static inline void dma_free_noncoherent(struct device *dev, size_t size, + void *cpu_addr, dma_addr_t dma_handle) +{ + DEFINE_DMA_ATTRS(attrs); + + dma_set_attr(DMA_ATTR_NON_CONSISTENT, &attrs); + dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); +} + #endif -- GitLab From efa21e432c7b3c8ae976039d614a017799b6e874 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 9 Sep 2015 15:39:46 -0700 Subject: [PATCH 6979/7006] dma-mapping: cosolidate dma_mapping_error Currently there are three valid implementations of dma_mapping_error: (1) call ->mapping_error (2) check for a hardcoded error code (3) always return 0 This patch provides a common implementation that calls ->mapping_error if present, then checks for DMA_ERROR_CODE if defined or otherwise returns 0. [jcmvbkbc@gmail.com: fix xtensa] Signed-off-by: Christoph Hellwig Cc: Arnd Bergmann Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Yoshinori Sato Cc: Michal Simek Cc: Jonas Bonn Cc: Chris Metcalf Cc: Guan Xuetao Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Andy Shevchenko Signed-off-by: Max Filippov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/dma-mapping.h | 5 ----- arch/arm/include/asm/dma-mapping.h | 9 --------- arch/arm64/include/asm/dma-mapping.h | 7 ------- arch/h8300/include/asm/dma-mapping.h | 5 ----- arch/hexagon/include/asm/dma-mapping.h | 11 +---------- arch/ia64/include/asm/dma-mapping.h | 7 ------- arch/microblaze/include/asm/dma-mapping.h | 11 ----------- arch/mips/include/asm/dma-mapping.h | 8 -------- arch/openrisc/include/asm/dma-mapping.h | 5 ----- arch/powerpc/include/asm/dma-mapping.h | 17 ++--------------- arch/s390/include/asm/dma-mapping.h | 10 ---------- arch/sh/include/asm/dma-mapping.h | 13 ++----------- arch/sparc/include/asm/dma-mapping.h | 6 ------ arch/tile/include/asm/dma-mapping.h | 7 ------- arch/unicore32/include/asm/dma-mapping.h | 10 ---------- arch/x86/include/asm/dma-mapping.h | 11 ----------- arch/xtensa/include/asm/dma-mapping.h | 9 --------- include/asm-generic/dma-mapping-common.h | 14 ++++++++++++++ 18 files changed, 19 insertions(+), 146 deletions(-) diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index 0552bf097245d..80ac3e835efeb 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -12,11 +12,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return get_dma_ops(dev)->mapping_error(dev, dma_addr); -} - static inline int dma_supported(struct device *dev, u64 mask) { return get_dma_ops(dev)->dma_supported(dev, mask); diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 0b7787167b640..9bef3c541c397 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -172,15 +172,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) static inline void dma_mark_clean(void *addr, size_t size) { } -/* - * DMA errors are defined by all-bits-set in the DMA address. - */ -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - debug_dma_mapping_error(dev, dma_addr); - return dma_addr == DMA_ERROR_CODE; -} - extern int dma_supported(struct device *dev, u64 mask); extern int arm_dma_set_mask(struct device *dev, u64 dma_mask); diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index 178e60b809224..f45f444b7a66a 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -84,13 +84,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) return (phys_addr_t)dev_addr; } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dev_addr) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - debug_dma_mapping_error(dev, dev_addr); - return ops->mapping_error(dev, dev_addr); -} - static inline int dma_supported(struct device *dev, u64 mask) { struct dma_map_ops *ops = get_dma_ops(dev); diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h index 72465ce594539..5eef05382fffb 100644 --- a/arch/h8300/include/asm/dma-mapping.h +++ b/arch/h8300/include/asm/dma-mapping.h @@ -20,9 +20,4 @@ static inline int dma_set_mask(struct device *dev, u64 mask) return 0; } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return 0; -} - #endif diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h index 58d2d8f1544ac..e66119290ecab 100644 --- a/arch/hexagon/include/asm/dma-mapping.h +++ b/arch/hexagon/include/asm/dma-mapping.h @@ -31,6 +31,7 @@ struct device; extern int bad_dma_address; +#define DMA_ERROR_CODE bad_dma_address extern struct dma_map_ops *dma_ops; @@ -57,14 +58,4 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops->mapping_error) - return dma_ops->mapping_error(dev, dma_addr); - - return (dma_addr == bad_dma_address); -} - #endif diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index a925ff03c9640..27b713d0edbc3 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -27,13 +27,6 @@ extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int, #include -static inline int dma_mapping_error(struct device *dev, dma_addr_t daddr) -{ - struct dma_map_ops *ops = platform_dma_get_ops(dev); - debug_dma_mapping_error(dev, daddr); - return ops->mapping_error(dev, daddr); -} - static inline int dma_supported(struct device *dev, u64 mask) { struct dma_map_ops *ops = platform_dma_get_ops(dev); diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index bc81625d486fd..e5b8438392630 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -87,17 +87,6 @@ static inline void __dma_sync(unsigned long paddr, } } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, dma_addr); - if (ops->mapping_error) - return ops->mapping_error(dev, dma_addr); - - return (dma_addr == DMA_ERROR_CODE); -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 709b2ba79cc33..158bb36bdcb4c 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -37,14 +37,6 @@ static inline int dma_supported(struct device *dev, u64 mask) return ops->dma_supported(dev, mask); } -static inline int dma_mapping_error(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, mask); - return ops->mapping_error(dev, mask); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index 57722528ea4d4..7dfe9d50856e7 100644 --- a/arch/openrisc/include/asm/dma-mapping.h +++ b/arch/openrisc/include/asm/dma-mapping.h @@ -43,11 +43,6 @@ static inline int dma_supported(struct device *dev, u64 dma_mask) return dma_mask == DMA_BIT_MASK(32); } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return 0; -} - static inline int dma_set_mask(struct device *dev, u64 dma_mask) { if (!dev->dma_mask || !dma_supported(dev, dma_mask)) diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 7971b421c6771..712d5afc055af 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -18,7 +18,9 @@ #include #include +#ifdef CONFIG_PPC64 #define DMA_ERROR_CODE (~(dma_addr_t)0x0) +#endif /* Some dma direct funcs must be visible for use in other dma_ops */ extern void *__dma_direct_alloc_coherent(struct device *dev, size_t size, @@ -137,21 +139,6 @@ extern int dma_set_mask(struct device *dev, u64 dma_mask); extern int __dma_set_mask(struct device *dev, u64 dma_mask); extern u64 __dma_get_required_mask(struct device *dev); -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, dma_addr); - if (dma_ops->mapping_error) - return dma_ops->mapping_error(dev, dma_addr); - -#ifdef CONFIG_PPC64 - return (dma_addr == DMA_ERROR_CODE); -#else - return 0; -#endif -} - static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) { #ifdef CONFIG_SWIOTLB diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index b729efeb9ad8b..3c293291319bc 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h @@ -43,14 +43,4 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, dma_addr); - if (dma_ops->mapping_error) - return dma_ops->mapping_error(dev, dma_addr); - return dma_addr == DMA_ERROR_CODE; -} - #endif /* _ASM_S390_DMA_MAPPING_H */ diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 2c3fa2ccbe9b4..98308c497162c 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -9,6 +9,8 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return dma_ops; } +#define DMA_ERROR_CODE 0 + #include static inline int dma_supported(struct device *dev, u64 mask) @@ -38,17 +40,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir); -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, dma_addr); - if (ops->mapping_error) - return ops->mapping_error(dev, dma_addr); - - return dma_addr == 0; -} - /* arch/sh/mm/consistent.c */ extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 2564edcb97280..5069d137453b4 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -38,12 +38,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - debug_dma_mapping_error(dev, dma_addr); - return (dma_addr == DMA_ERROR_CODE); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { #ifdef CONFIG_PCI diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index e982dfa5d2f4b..f8f7a05023bfc 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -74,13 +74,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } -static inline int -dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - debug_dma_mapping_error(dev, dma_addr); - return get_dma_ops(dev)->mapping_error(dev, dma_addr); -} - static inline int dma_supported(struct device *dev, u64 mask) { diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h index 636e942940a04..175d7e3f7b0ab 100644 --- a/arch/unicore32/include/asm/dma-mapping.h +++ b/arch/unicore32/include/asm/dma-mapping.h @@ -38,16 +38,6 @@ static inline int dma_supported(struct device *dev, u64 mask) return dma_ops->dma_supported(dev, mask); } -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops->mapping_error) - return dma_ops->mapping_error(dev, dma_addr); - - return 0; -} - #include static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index 7e47e4d6e69cd..bbca62e3e43f5 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -45,17 +45,6 @@ bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp); #include -/* Make sure we keep the same behaviour */ -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - debug_dma_mapping_error(dev, dma_addr); - if (ops->mapping_error) - return ops->mapping_error(dev, dma_addr); - - return (dma_addr == DMA_ERROR_CODE); -} - extern int dma_supported(struct device *hwdev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask); diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index 0a19581375dac..21925bfdaff70 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -32,15 +32,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int -dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - debug_dma_mapping_error(dev, dma_addr); - return ops->mapping_error(dev, dma_addr); -} - static inline int dma_supported(struct device *dev, u64 mask) { diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index ec321dd98f93b..cdaa24193d4cf 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -313,4 +313,18 @@ static inline void dma_free_noncoherent(struct device *dev, size_t size, dma_free_attrs(dev, size, cpu_addr, dma_handle, &attrs); } +static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) +{ + debug_dma_mapping_error(dev, dma_addr); + + if (get_dma_ops(dev)->mapping_error) + return get_dma_ops(dev)->mapping_error(dev, dma_addr); + +#ifdef DMA_ERROR_CODE + return dma_addr == DMA_ERROR_CODE; +#else + return 0; +#endif +} + #endif -- GitLab From ee196371d5cb1942ebdccc16bdce389812aa265e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 9 Sep 2015 15:39:49 -0700 Subject: [PATCH 6980/7006] dma-mapping: consolidate dma_supported Most architectures just call into ->dma_supported, but some also return 1 if the method is not present, or 0 if no dma ops are present (although that should never happeb). Consolidate this more broad version into common code. Also fix h8300 which inorrectly always returned 0, which would have been a problem if it's dma_set_mask implementation wasn't a similarly buggy noop. As a few architectures have much more elaborate implementations, we still allow for arch overrides. [jcmvbkbc@gmail.com: fix xtensa] Signed-off-by: Christoph Hellwig Cc: Arnd Bergmann Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Yoshinori Sato Cc: Michal Simek Cc: Jonas Bonn Cc: Chris Metcalf Cc: Guan Xuetao Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Andy Shevchenko Signed-off-by: Max Filippov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/dma-mapping.h | 5 ----- arch/arm/include/asm/dma-mapping.h | 6 +++--- arch/arm64/include/asm/dma-mapping.h | 6 ------ arch/h8300/include/asm/dma-mapping.h | 5 ----- arch/hexagon/include/asm/dma-mapping.h | 1 + arch/ia64/include/asm/dma-mapping.h | 6 ------ arch/microblaze/include/asm/dma-mapping.h | 13 +------------ arch/mips/include/asm/dma-mapping.h | 6 ------ arch/openrisc/include/asm/dma-mapping.h | 5 +++-- arch/powerpc/include/asm/dma-mapping.h | 11 ----------- arch/s390/include/asm/dma-mapping.h | 9 --------- arch/sh/include/asm/dma-mapping.h | 10 ---------- arch/sparc/include/asm/dma-mapping.h | 1 + arch/tile/include/asm/dma-mapping.h | 6 ------ arch/unicore32/include/asm/dma-mapping.h | 10 ---------- arch/x86/include/asm/dma-mapping.h | 4 +++- arch/xtensa/include/asm/dma-mapping.h | 6 ------ include/asm-generic/dma-mapping-common.h | 13 +++++++++++++ 18 files changed, 25 insertions(+), 98 deletions(-) diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index 80ac3e835efeb..9d763e535c5a2 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -12,11 +12,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - return get_dma_ops(dev)->dma_supported(dev, mask); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { return get_dma_ops(dev)->set_dma_mask(dev, mask); diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 9bef3c541c397..2f9c731691c0f 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -38,12 +38,14 @@ static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) dev->archdata.dma_ops = ops; } +#define HAVE_ARCH_DMA_SUPPORTED 1 +extern int dma_supported(struct device *dev, u64 mask); + /* * Note that while the generic code provides dummy dma_{alloc,free}_noncoherent * implementations, we don't provide a dma_cache_sync function so drivers using * this API are highlighted with build warnings. */ - #include static inline int dma_set_mask(struct device *dev, u64 mask) @@ -172,8 +174,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) static inline void dma_mark_clean(void *addr, size_t size) { } -extern int dma_supported(struct device *dev, u64 mask); - extern int arm_dma_set_mask(struct device *dev, u64 dma_mask); /** diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index f45f444b7a66a..f519a58c55ae0 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -84,12 +84,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) return (phys_addr_t)dev_addr; } -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - return ops->dma_supported(dev, mask); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { if (!dev->dma_mask || !dma_supported(dev, mask)) diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h index 5eef05382fffb..48d652eb1b5f5 100644 --- a/arch/h8300/include/asm/dma-mapping.h +++ b/arch/h8300/include/asm/dma-mapping.h @@ -10,11 +10,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - return 0; -} - static inline int dma_set_mask(struct device *dev, u64 mask) { return 0; diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h index e66119290ecab..36e8de710b325 100644 --- a/arch/hexagon/include/asm/dma-mapping.h +++ b/arch/hexagon/include/asm/dma-mapping.h @@ -43,6 +43,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return dma_ops; } +#define HAVE_ARCH_DMA_SUPPORTED 1 extern int dma_supported(struct device *dev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask); extern int dma_is_consistent(struct device *dev, dma_addr_t dma_handle); diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 27b713d0edbc3..7982caa7c5e76 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -27,12 +27,6 @@ extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int, #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = platform_dma_get_ops(dev); - return ops->dma_supported(dev, mask); -} - static inline int dma_set_mask (struct device *dev, u64 mask) { diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index e5b8438392630..3b453c503a43b 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -44,16 +44,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return &dma_direct_ops; } -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (unlikely(!ops)) - return 0; - if (!ops->dma_supported) - return 1; - return ops->dma_supported(dev, mask); -} +#include static inline int dma_set_mask(struct device *dev, u64 dma_mask) { @@ -69,8 +60,6 @@ static inline int dma_set_mask(struct device *dev, u64 dma_mask) return 0; } -#include - static inline void __dma_sync(unsigned long paddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 158bb36bdcb4c..8bf8ec30a4b2d 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -31,12 +31,6 @@ static inline void dma_mark_clean(void *addr, size_t size) {} #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - return ops->dma_supported(dev, mask); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index 7dfe9d50856e7..8fc08b883477a 100644 --- a/arch/openrisc/include/asm/dma-mapping.h +++ b/arch/openrisc/include/asm/dma-mapping.h @@ -35,14 +35,15 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return &or1k_dma_map_ops; } -#include - +#define HAVE_ARCH_DMA_SUPPORTED 1 static inline int dma_supported(struct device *dev, u64 dma_mask) { /* Support 32 bit DMA mask exclusively */ return dma_mask == DMA_BIT_MASK(32); } +#include + static inline int dma_set_mask(struct device *dev, u64 dma_mask) { if (!dev->dma_mask || !dma_supported(dev, dma_mask)) diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index 712d5afc055af..dd43e0c6f2190 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -124,17 +124,6 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off) #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - if (unlikely(dma_ops == NULL)) - return 0; - if (dma_ops->dma_supported == NULL) - return 1; - return dma_ops->dma_supported(dev, mask); -} - extern int dma_set_mask(struct device *dev, u64 dma_mask); extern int __dma_set_mask(struct device *dev, u64 dma_mask); extern u64 __dma_get_required_mask(struct device *dev); diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index 3c293291319bc..1f42489797da2 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h @@ -27,15 +27,6 @@ static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - if (dma_ops->dma_supported == NULL) - return 1; - return dma_ops->dma_supported(dev, mask); -} - static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) { if (!dev->dma_mask) diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 98308c497162c..088f6e5f1a927 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -13,16 +13,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (ops->dma_supported) - return ops->dma_supported(dev, mask); - - return 1; -} - static inline int dma_set_mask(struct device *dev, u64 mask) { struct dma_map_ops *ops = get_dma_ops(dev); diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 5069d137453b4..184651bb0b46a 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -7,6 +7,7 @@ #define DMA_ERROR_CODE (~(dma_addr_t)0x0) +#define HAVE_ARCH_DMA_SUPPORTED 1 int dma_supported(struct device *dev, u64 mask); static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index f8f7a05023bfc..559ed4a60077b 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -74,12 +74,6 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } -static inline int -dma_supported(struct device *dev, u64 mask) -{ - return get_dma_ops(dev)->dma_supported(dev, mask); -} - static inline int dma_set_mask(struct device *dev, u64 mask) { diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h index 175d7e3f7b0ab..21231c14182c6 100644 --- a/arch/unicore32/include/asm/dma-mapping.h +++ b/arch/unicore32/include/asm/dma-mapping.h @@ -28,16 +28,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return &swiotlb_dma_map_ops; } -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *dma_ops = get_dma_ops(dev); - - if (unlikely(dma_ops == NULL)) - return 0; - - return dma_ops->dma_supported(dev, mask); -} - #include static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index bbca62e3e43f5..b1fbf582048b4 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -43,9 +43,11 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) bool arch_dma_alloc_attrs(struct device **dev, gfp_t *gfp); #define arch_dma_alloc_attrs arch_dma_alloc_attrs +#define HAVE_ARCH_DMA_SUPPORTED 1 +extern int dma_supported(struct device *hwdev, u64 mask); + #include -extern int dma_supported(struct device *hwdev, u64 mask); extern int dma_set_mask(struct device *dev, u64 mask); extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index 21925bfdaff70..329abc7211e99 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -32,12 +32,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int -dma_supported(struct device *dev, u64 mask) -{ - return 1; -} - static inline int dma_set_mask(struct device *dev, u64 mask) { diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index cdaa24193d4cf..67fa6bcd644ce 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -327,4 +327,17 @@ static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) #endif } +#ifndef HAVE_ARCH_DMA_SUPPORTED +static inline int dma_supported(struct device *dev, u64 mask) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + if (!ops) + return 0; + if (!ops->dma_supported) + return 1; + return ops->dma_supported(dev, mask); +} +#endif + #endif -- GitLab From 452e06af1f0149b01201f94264d452cd7a95db7a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 9 Sep 2015 15:39:53 -0700 Subject: [PATCH 6981/7006] dma-mapping: consolidate dma_set_mask Almost everyone implements dma_set_mask the same way, although some time that's hidden in ->set_dma_mask methods. This patch consolidates those into a common implementation that either calls ->set_dma_mask if present or otherwise uses the default implementation. Some architectures used to only call ->set_dma_mask after the initial checks, and those instance have been fixed to do the full work. h8300 implemented dma_set_mask bogusly as a no-ops and has been fixed. Unfortunately some architectures overload unrelated semantics like changing the dma_ops into it so we still need to allow for an architecture override for now. [jcmvbkbc@gmail.com: fix xtensa] Signed-off-by: Christoph Hellwig Cc: Arnd Bergmann Cc: Russell King Cc: Catalin Marinas Cc: Will Deacon Cc: Yoshinori Sato Cc: Michal Simek Cc: Jonas Bonn Cc: Chris Metcalf Cc: Guan Xuetao Cc: Ralf Baechle Cc: Benjamin Herrenschmidt Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Andy Shevchenko Signed-off-by: Max Filippov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/alpha/include/asm/dma-mapping.h | 5 ----- arch/alpha/kernel/pci-noop.c | 10 ---------- arch/alpha/kernel/pci_iommu.c | 11 ----------- arch/arm/include/asm/dma-mapping.h | 5 ----- arch/arm64/include/asm/dma-mapping.h | 9 --------- arch/h8300/include/asm/dma-mapping.h | 5 ----- arch/hexagon/include/asm/dma-mapping.h | 1 - arch/hexagon/kernel/dma.c | 11 ----------- arch/ia64/include/asm/dma-mapping.h | 9 --------- arch/microblaze/include/asm/dma-mapping.h | 14 -------------- arch/mips/include/asm/dma-mapping.h | 16 ---------------- arch/mips/loongson64/common/dma-swiotlb.c | 3 +++ arch/openrisc/include/asm/dma-mapping.h | 9 --------- arch/powerpc/include/asm/dma-mapping.h | 4 +++- arch/s390/include/asm/dma-mapping.h | 2 -- arch/s390/pci/pci_dma.c | 10 ---------- arch/sh/include/asm/dma-mapping.h | 14 -------------- arch/sparc/include/asm/dma-mapping.h | 4 +++- arch/tile/include/asm/dma-mapping.h | 6 ++++-- arch/unicore32/include/asm/dma-mapping.h | 10 ---------- arch/x86/include/asm/dma-mapping.h | 2 -- arch/x86/kernel/pci-dma.c | 11 ----------- arch/xtensa/include/asm/dma-mapping.h | 11 ----------- include/asm-generic/dma-mapping-common.h | 15 +++++++++++++++ 24 files changed, 28 insertions(+), 169 deletions(-) diff --git a/arch/alpha/include/asm/dma-mapping.h b/arch/alpha/include/asm/dma-mapping.h index 9d763e535c5a2..72a8ca7796d91 100644 --- a/arch/alpha/include/asm/dma-mapping.h +++ b/arch/alpha/include/asm/dma-mapping.h @@ -12,11 +12,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_set_mask(struct device *dev, u64 mask) -{ - return get_dma_ops(dev)->set_dma_mask(dev, mask); -} - #define dma_cache_sync(dev, va, size, dir) ((void)0) #endif /* _ALPHA_DMA_MAPPING_H */ diff --git a/arch/alpha/kernel/pci-noop.c b/arch/alpha/kernel/pci-noop.c index df24b76f92461..2b1f4a1e92723 100644 --- a/arch/alpha/kernel/pci-noop.c +++ b/arch/alpha/kernel/pci-noop.c @@ -166,15 +166,6 @@ static int alpha_noop_supported(struct device *dev, u64 mask) return mask < 0x00ffffffUL ? 0 : 1; } -static int alpha_noop_set_mask(struct device *dev, u64 mask) -{ - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - *dev->dma_mask = mask; - return 0; -} - struct dma_map_ops alpha_noop_ops = { .alloc = alpha_noop_alloc_coherent, .free = alpha_noop_free_coherent, @@ -182,7 +173,6 @@ struct dma_map_ops alpha_noop_ops = { .map_sg = alpha_noop_map_sg, .mapping_error = alpha_noop_mapping_error, .dma_supported = alpha_noop_supported, - .set_dma_mask = alpha_noop_set_mask, }; struct dma_map_ops *dma_ops = &alpha_noop_ops; diff --git a/arch/alpha/kernel/pci_iommu.c b/arch/alpha/kernel/pci_iommu.c index eddee77203431..8969bf2dfe3a0 100644 --- a/arch/alpha/kernel/pci_iommu.c +++ b/arch/alpha/kernel/pci_iommu.c @@ -939,16 +939,6 @@ static int alpha_pci_mapping_error(struct device *dev, dma_addr_t dma_addr) return dma_addr == 0; } -static int alpha_pci_set_mask(struct device *dev, u64 mask) -{ - if (!dev->dma_mask || - !pci_dma_supported(alpha_gendev_to_pci(dev), mask)) - return -EIO; - - *dev->dma_mask = mask; - return 0; -} - struct dma_map_ops alpha_pci_ops = { .alloc = alpha_pci_alloc_coherent, .free = alpha_pci_free_coherent, @@ -958,7 +948,6 @@ struct dma_map_ops alpha_pci_ops = { .unmap_sg = alpha_pci_unmap_sg, .mapping_error = alpha_pci_mapping_error, .dma_supported = alpha_pci_supported, - .set_dma_mask = alpha_pci_set_mask, }; struct dma_map_ops *dma_ops = &alpha_pci_ops; diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h index 2f9c731691c0f..ccb3aa64640dc 100644 --- a/arch/arm/include/asm/dma-mapping.h +++ b/arch/arm/include/asm/dma-mapping.h @@ -48,11 +48,6 @@ extern int dma_supported(struct device *dev, u64 mask); */ #include -static inline int dma_set_mask(struct device *dev, u64 mask) -{ - return get_dma_ops(dev)->set_dma_mask(dev, mask); -} - #ifdef __arch_page_to_dma #error Please update to __arch_pfn_to_dma #endif diff --git a/arch/arm64/include/asm/dma-mapping.h b/arch/arm64/include/asm/dma-mapping.h index f519a58c55ae0..cfdb34bedbcd8 100644 --- a/arch/arm64/include/asm/dma-mapping.h +++ b/arch/arm64/include/asm/dma-mapping.h @@ -84,15 +84,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t dev_addr) return (phys_addr_t)dev_addr; } -static inline int dma_set_mask(struct device *dev, u64 mask) -{ - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - *dev->dma_mask = mask; - - return 0; -} - static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) { if (!dev->dma_mask) diff --git a/arch/h8300/include/asm/dma-mapping.h b/arch/h8300/include/asm/dma-mapping.h index 48d652eb1b5f5..d9b5b806afe6f 100644 --- a/arch/h8300/include/asm/dma-mapping.h +++ b/arch/h8300/include/asm/dma-mapping.h @@ -10,9 +10,4 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_set_mask(struct device *dev, u64 mask) -{ - return 0; -} - #endif diff --git a/arch/hexagon/include/asm/dma-mapping.h b/arch/hexagon/include/asm/dma-mapping.h index 36e8de710b325..268fde8a45756 100644 --- a/arch/hexagon/include/asm/dma-mapping.h +++ b/arch/hexagon/include/asm/dma-mapping.h @@ -45,7 +45,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #define HAVE_ARCH_DMA_SUPPORTED 1 extern int dma_supported(struct device *dev, u64 mask); -extern int dma_set_mask(struct device *dev, u64 mask); extern int dma_is_consistent(struct device *dev, dma_addr_t dma_handle); extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); diff --git a/arch/hexagon/kernel/dma.c b/arch/hexagon/kernel/dma.c index b74f9bae31a3b..9e3ddf792bd3e 100644 --- a/arch/hexagon/kernel/dma.c +++ b/arch/hexagon/kernel/dma.c @@ -44,17 +44,6 @@ int dma_supported(struct device *dev, u64 mask) } EXPORT_SYMBOL(dma_supported); -int dma_set_mask(struct device *dev, u64 mask) -{ - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - *dev->dma_mask = mask; - - return 0; -} -EXPORT_SYMBOL(dma_set_mask); - static struct gen_pool *coherent_pool; diff --git a/arch/ia64/include/asm/dma-mapping.h b/arch/ia64/include/asm/dma-mapping.h index 7982caa7c5e76..9beccf8010bd6 100644 --- a/arch/ia64/include/asm/dma-mapping.h +++ b/arch/ia64/include/asm/dma-mapping.h @@ -27,15 +27,6 @@ extern void machvec_dma_sync_sg(struct device *, struct scatterlist *, int, #include -static inline int -dma_set_mask (struct device *dev, u64 mask) -{ - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - *dev->dma_mask = mask; - return 0; -} - static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) { if (!dev->dma_mask) diff --git a/arch/microblaze/include/asm/dma-mapping.h b/arch/microblaze/include/asm/dma-mapping.h index 3b453c503a43b..24b12970c9cff 100644 --- a/arch/microblaze/include/asm/dma-mapping.h +++ b/arch/microblaze/include/asm/dma-mapping.h @@ -46,20 +46,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_set_mask(struct device *dev, u64 dma_mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (unlikely(ops == NULL)) - return -EIO; - if (ops->set_dma_mask) - return ops->set_dma_mask(dev, dma_mask); - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - *dev->dma_mask = dma_mask; - return 0; -} - static inline void __dma_sync(unsigned long paddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/mips/include/asm/dma-mapping.h b/arch/mips/include/asm/dma-mapping.h index 8bf8ec30a4b2d..e604f760c4a07 100644 --- a/arch/mips/include/asm/dma-mapping.h +++ b/arch/mips/include/asm/dma-mapping.h @@ -31,22 +31,6 @@ static inline void dma_mark_clean(void *addr, size_t size) {} #include -static inline int -dma_set_mask(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if(!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - if (ops->set_dma_mask) - return ops->set_dma_mask(dev, mask); - - *dev->dma_mask = mask; - - return 0; -} - extern void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); diff --git a/arch/mips/loongson64/common/dma-swiotlb.c b/arch/mips/loongson64/common/dma-swiotlb.c index ef9da3b5c543f..4ffa6fc81c8f7 100644 --- a/arch/mips/loongson64/common/dma-swiotlb.c +++ b/arch/mips/loongson64/common/dma-swiotlb.c @@ -85,6 +85,9 @@ static void loongson_dma_sync_sg_for_device(struct device *dev, static int loongson_dma_set_mask(struct device *dev, u64 mask) { + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + if (mask > DMA_BIT_MASK(loongson_sysconf.dma_mask_bits)) { *dev->dma_mask = DMA_BIT_MASK(loongson_sysconf.dma_mask_bits); return -EIO; diff --git a/arch/openrisc/include/asm/dma-mapping.h b/arch/openrisc/include/asm/dma-mapping.h index 8fc08b883477a..413bfcf863848 100644 --- a/arch/openrisc/include/asm/dma-mapping.h +++ b/arch/openrisc/include/asm/dma-mapping.h @@ -44,13 +44,4 @@ static inline int dma_supported(struct device *dev, u64 dma_mask) #include -static inline int dma_set_mask(struct device *dev, u64 dma_mask) -{ - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - - *dev->dma_mask = dma_mask; - - return 0; -} #endif /* __ASM_OPENRISC_DMA_MAPPING_H */ diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index dd43e0c6f2190..7f522c021dc30 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h @@ -122,9 +122,11 @@ static inline void set_dma_offset(struct device *dev, dma_addr_t off) /* this will be removed soon */ #define flush_write_buffers() +#define HAVE_ARCH_DMA_SET_MASK 1 +extern int dma_set_mask(struct device *dev, u64 dma_mask); + #include -extern int dma_set_mask(struct device *dev, u64 dma_mask); extern int __dma_set_mask(struct device *dev, u64 dma_mask); extern u64 __dma_get_required_mask(struct device *dev); diff --git a/arch/s390/include/asm/dma-mapping.h b/arch/s390/include/asm/dma-mapping.h index 1f42489797da2..b3fd54d93dd20 100644 --- a/arch/s390/include/asm/dma-mapping.h +++ b/arch/s390/include/asm/dma-mapping.h @@ -18,8 +18,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return &s390_dma_ops; } -extern int dma_set_mask(struct device *dev, u64 mask); - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/s390/pci/pci_dma.c b/arch/s390/pci/pci_dma.c index 42b76580c8b8a..37505b8b40937 100644 --- a/arch/s390/pci/pci_dma.c +++ b/arch/s390/pci/pci_dma.c @@ -262,16 +262,6 @@ out: spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, flags); } -int dma_set_mask(struct device *dev, u64 mask) -{ - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - *dev->dma_mask = mask; - return 0; -} -EXPORT_SYMBOL_GPL(dma_set_mask); - static dma_addr_t s390_dma_map_pages(struct device *dev, struct page *page, unsigned long offset, size_t size, enum dma_data_direction direction, diff --git a/arch/sh/include/asm/dma-mapping.h b/arch/sh/include/asm/dma-mapping.h index 088f6e5f1a927..a3745a3fe0290 100644 --- a/arch/sh/include/asm/dma-mapping.h +++ b/arch/sh/include/asm/dma-mapping.h @@ -13,20 +13,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int dma_set_mask(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - if (ops->set_dma_mask) - return ops->set_dma_mask(dev, mask); - - *dev->dma_mask = mask; - - return 0; -} - void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction dir); diff --git a/arch/sparc/include/asm/dma-mapping.h b/arch/sparc/include/asm/dma-mapping.h index 184651bb0b46a..a21da597b0b59 100644 --- a/arch/sparc/include/asm/dma-mapping.h +++ b/arch/sparc/include/asm/dma-mapping.h @@ -37,7 +37,7 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) return dma_ops; } -#include +#define HAVE_ARCH_DMA_SET_MASK 1 static inline int dma_set_mask(struct device *dev, u64 mask) { @@ -52,4 +52,6 @@ static inline int dma_set_mask(struct device *dev, u64 mask) return -EINVAL; } +#include + #endif diff --git a/arch/tile/include/asm/dma-mapping.h b/arch/tile/include/asm/dma-mapping.h index 559ed4a60077b..96ac6cce4a32c 100644 --- a/arch/tile/include/asm/dma-mapping.h +++ b/arch/tile/include/asm/dma-mapping.h @@ -59,8 +59,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) static inline void dma_mark_clean(void *addr, size_t size) {} -#include - static inline void set_dma_ops(struct device *dev, struct dma_map_ops *ops) { dev->archdata.dma_ops = ops; @@ -74,6 +72,10 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) return addr + size - 1 <= *dev->dma_mask; } +#define HAVE_ARCH_DMA_SET_MASK 1 + +#include + static inline int dma_set_mask(struct device *dev, u64 mask) { diff --git a/arch/unicore32/include/asm/dma-mapping.h b/arch/unicore32/include/asm/dma-mapping.h index 21231c14182c6..8140e053ccd35 100644 --- a/arch/unicore32/include/asm/dma-mapping.h +++ b/arch/unicore32/include/asm/dma-mapping.h @@ -50,16 +50,6 @@ static inline phys_addr_t dma_to_phys(struct device *dev, dma_addr_t daddr) static inline void dma_mark_clean(void *addr, size_t size) {} -static inline int dma_set_mask(struct device *dev, u64 dma_mask) -{ - if (!dev->dma_mask || !dma_supported(dev, dma_mask)) - return -EIO; - - *dev->dma_mask = dma_mask; - - return 0; -} - static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction) { diff --git a/arch/x86/include/asm/dma-mapping.h b/arch/x86/include/asm/dma-mapping.h index b1fbf582048b4..953b7263f8446 100644 --- a/arch/x86/include/asm/dma-mapping.h +++ b/arch/x86/include/asm/dma-mapping.h @@ -48,8 +48,6 @@ extern int dma_supported(struct device *hwdev, u64 mask); #include -extern int dma_set_mask(struct device *dev, u64 mask); - extern void *dma_generic_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_addr, gfp_t flag, struct dma_attrs *attrs); diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c index bd23971e8f1df..84b8ef82a159b 100644 --- a/arch/x86/kernel/pci-dma.c +++ b/arch/x86/kernel/pci-dma.c @@ -58,17 +58,6 @@ EXPORT_SYMBOL(x86_dma_fallback_dev); /* Number of entries preallocated for DMA-API debugging */ #define PREALLOC_DMA_DEBUG_ENTRIES 65536 -int dma_set_mask(struct device *dev, u64 mask) -{ - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - *dev->dma_mask = mask; - - return 0; -} -EXPORT_SYMBOL(dma_set_mask); - void __init pci_iommu_alloc(void) { struct iommu_table_entry *p; diff --git a/arch/xtensa/include/asm/dma-mapping.h b/arch/xtensa/include/asm/dma-mapping.h index 329abc7211e99..4427f38b634e6 100644 --- a/arch/xtensa/include/asm/dma-mapping.h +++ b/arch/xtensa/include/asm/dma-mapping.h @@ -32,17 +32,6 @@ static inline struct dma_map_ops *get_dma_ops(struct device *dev) #include -static inline int -dma_set_mask(struct device *dev, u64 mask) -{ - if(!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - - *dev->dma_mask = mask; - - return 0; -} - void dma_cache_sync(struct device *dev, void *vaddr, size_t size, enum dma_data_direction direction); diff --git a/include/asm-generic/dma-mapping-common.h b/include/asm-generic/dma-mapping-common.h index 67fa6bcd644ce..b1bc954eccf37 100644 --- a/include/asm-generic/dma-mapping-common.h +++ b/include/asm-generic/dma-mapping-common.h @@ -340,4 +340,19 @@ static inline int dma_supported(struct device *dev, u64 mask) } #endif +#ifndef HAVE_ARCH_DMA_SET_MASK +static inline int dma_set_mask(struct device *dev, u64 mask) +{ + struct dma_map_ops *ops = get_dma_ops(dev); + + if (ops->set_dma_mask) + return ops->set_dma_mask(dev, mask); + + if (!dev->dma_mask || !dma_supported(dev, mask)) + return -EIO; + *dev->dma_mask = mask; + return 0; +} +#endif + #endif -- GitLab From bd3e1c7c6de9f5f70d97cdb6c817151c0477c5e3 Mon Sep 17 00:00:00 2001 From: Jonathon Jongsma Date: Thu, 20 Aug 2015 14:04:32 -0500 Subject: [PATCH 6982/7006] drm/qxl: validate monitors config modes Due to some recent changes in drm_helper_probe_single_connector_modes_merge_bits(), old custom modes were not being pruned properly. In current kernels, drm_mode_validate_basic() is called to sanity-check each mode in the list. If the sanity-check passes, the mode's status gets set to to MODE_OK. In older kernels this check was not done, so old custom modes would still have a status of MODE_UNVERIFIED at this point, and would therefore be pruned later in the function. As a result of this new behavior, the list of modes for a device always includes every custom mode ever configured for the device, with the largest one listed first. Since desktop environments usually choose the first preferred mode when a hotplug event is emitted, this had the result of making it very difficult for the user to reduce the size of the display. The qxl driver did implement the mode_valid connector function, but it was empty. In order to restore the old behavior where old custom modes are pruned, we implement a proper mode_valid function for the qxl driver. This function now checks each mode against the last configured custom mode and the list of standard modes. If the mode doesn't match any of these, its status is set to MODE_BAD so that it will be pruned as expected. Signed-off-by: Jonathon Jongsma Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie --- drivers/gpu/drm/qxl/qxl_display.c | 66 +++++++++++++++++++------------ drivers/gpu/drm/qxl/qxl_drv.h | 2 + 2 files changed, 42 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/qxl/qxl_display.c b/drivers/gpu/drm/qxl/qxl_display.c index a8dbb3ef4e3c9..7c6225c84ba67 100644 --- a/drivers/gpu/drm/qxl/qxl_display.c +++ b/drivers/gpu/drm/qxl/qxl_display.c @@ -160,9 +160,35 @@ static int qxl_add_monitors_config_modes(struct drm_connector *connector, *pwidth = head->width; *pheight = head->height; drm_mode_probed_add(connector, mode); + /* remember the last custom size for mode validation */ + qdev->monitors_config_width = mode->hdisplay; + qdev->monitors_config_height = mode->vdisplay; return 1; } +static struct mode_size { + int w; + int h; +} common_modes[] = { + { 640, 480}, + { 720, 480}, + { 800, 600}, + { 848, 480}, + {1024, 768}, + {1152, 768}, + {1280, 720}, + {1280, 800}, + {1280, 854}, + {1280, 960}, + {1280, 1024}, + {1440, 900}, + {1400, 1050}, + {1680, 1050}, + {1600, 1200}, + {1920, 1080}, + {1920, 1200} +}; + static int qxl_add_common_modes(struct drm_connector *connector, unsigned pwidth, unsigned pheight) @@ -170,29 +196,6 @@ static int qxl_add_common_modes(struct drm_connector *connector, struct drm_device *dev = connector->dev; struct drm_display_mode *mode = NULL; int i; - struct mode_size { - int w; - int h; - } common_modes[] = { - { 640, 480}, - { 720, 480}, - { 800, 600}, - { 848, 480}, - {1024, 768}, - {1152, 768}, - {1280, 720}, - {1280, 800}, - {1280, 854}, - {1280, 960}, - {1280, 1024}, - {1440, 900}, - {1400, 1050}, - {1680, 1050}, - {1600, 1200}, - {1920, 1080}, - {1920, 1200} - }; - for (i = 0; i < ARRAY_SIZE(common_modes); i++) { mode = drm_cvt_mode(dev, common_modes[i].w, common_modes[i].h, 60, false, false, false); @@ -823,11 +826,22 @@ static int qxl_conn_get_modes(struct drm_connector *connector) static int qxl_conn_mode_valid(struct drm_connector *connector, struct drm_display_mode *mode) { + struct drm_device *ddev = connector->dev; + struct qxl_device *qdev = ddev->dev_private; + int i; + /* TODO: is this called for user defined modes? (xrandr --add-mode) * TODO: check that the mode fits in the framebuffer */ - DRM_DEBUG("%s: %dx%d status=%d\n", mode->name, mode->hdisplay, - mode->vdisplay, mode->status); - return MODE_OK; + + if(qdev->monitors_config_width == mode->hdisplay && + qdev->monitors_config_height == mode->vdisplay) + return MODE_OK; + + for (i = 0; i < ARRAY_SIZE(common_modes); i++) { + if (common_modes[i].w == mode->hdisplay && common_modes[i].h == mode->vdisplay) + return MODE_OK; + } + return MODE_BAD; } static struct drm_encoder *qxl_best_encoder(struct drm_connector *connector) diff --git a/drivers/gpu/drm/qxl/qxl_drv.h b/drivers/gpu/drm/qxl/qxl_drv.h index d8549690801d2..01a86948eb8cd 100644 --- a/drivers/gpu/drm/qxl/qxl_drv.h +++ b/drivers/gpu/drm/qxl/qxl_drv.h @@ -325,6 +325,8 @@ struct qxl_device { struct work_struct fb_work; struct drm_property *hotplug_mode_update_property; + int monitors_config_width; + int monitors_config_height; }; /* forward declaration for QXL_INFO_IO */ -- GitLab From 15ee005893c5ac8aabb66c2ad0033ef31dbdcfa3 Mon Sep 17 00:00:00 2001 From: Ilia Mirkin Date: Mon, 31 Aug 2015 22:50:28 -0400 Subject: [PATCH 6983/7006] drm/nouveau/gr/nv04: fix big endian setting on gr context Broken since "gr: convert user classes to new-style nvkm_object" Tested on a PPC64 G5 + NV34 Signed-off-by: Ilia Mirkin Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c index 426ba0025a8d0..85c5b7fea5f5e 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c @@ -1048,11 +1048,11 @@ nv04_gr_object_bind(struct nvkm_object *object, struct nvkm_gpuobj *parent, if (ret == 0) { nvkm_kmap(*pgpuobj); nvkm_wo32(*pgpuobj, 0x00, object->oclass); - nvkm_wo32(*pgpuobj, 0x04, 0x00000000); - nvkm_wo32(*pgpuobj, 0x08, 0x00000000); #ifdef __BIG_ENDIAN - nvkm_mo32(*pgpuobj, 0x08, 0x00080000, 0x00080000); + nvkm_mo32(*pgpuobj, 0x00, 0x00080000, 0x00080000); #endif + nvkm_wo32(*pgpuobj, 0x04, 0x00000000); + nvkm_wo32(*pgpuobj, 0x08, 0x00000000); nvkm_wo32(*pgpuobj, 0x0c, 0x00000000); nvkm_done(*pgpuobj); } -- GitLab From c5bf4609e03e296d74cbbfe124ba49e0f907feb3 Mon Sep 17 00:00:00 2001 From: Roy Spliet Date: Wed, 2 Sep 2015 23:21:02 +0100 Subject: [PATCH 6984/7006] drm/nouveau/clk/gt215: Unbreak engine pausing for GT21x/MCP7x Typo that snuck in with commit 6979c6303a4abf263753cd9d577d79f05c6e8c47 Signed-off-by: Roy Spliet Reported-by: Pierre Moreau Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c index 07feae620c8d9..c233e3f653ce2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c @@ -326,7 +326,7 @@ gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags) return -EIO; if (nvkm_msec(device, 2000, - u32 tmp = nvkm_rd32(device, 0x002504) & 0x0000003f; + u32 tmp = nvkm_rd32(device, 0x00251c) & 0x0000003f; if (tmp == 0x0000003f) break; ) < 0) -- GitLab From 778613e583994d947960a7f177226d0e7b5ef124 Mon Sep 17 00:00:00 2001 From: Ben Skeggs Date: Thu, 3 Sep 2015 12:39:45 +1000 Subject: [PATCH 6985/7006] drm/nouveau/device: enable c800 quirk for tecra w50 Signed-off-by: Ben Skeggs --- drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c index 9dd1cac81e808..e8eb14e438f4d 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/pci.c @@ -689,6 +689,7 @@ nvkm_device_pci_10de_11e3[] = { static const struct nvkm_device_pci_vendor nvkm_device_pci_10de_11fc[] = { + { 0x1179, 0x0001, NULL, { .War00C800_0 = true } }, /* Toshiba Tecra W50 */ { 0x17aa, 0x2211, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ { 0x17aa, 0x221e, NULL, { .War00C800_0 = true } }, /* Lenovo W541 */ {} -- GitLab From 8f9b565482c537821588444e09ff732c7d65ed6e Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 30 Jul 2015 18:28:13 -0700 Subject: [PATCH 6986/7006] target/qla2xxx: Honor max_data_sg_nents I/O transfer limit This patch adds an optional fabric driver provided SGL limit that target-core will honor as it's own internal I/O maximum transfer length limit, as exposed by EVPD=0xb0 block limits parameters. This is required for handling cases when host I/O transfer length exceeds the requested EVPD block limits maximum transfer length. The initial user of this logic is qla2xxx, so that we can avoid having to reject I/Os from some legacy FC hosts where EVPD=0xb0 parameters are not honored. When se_cmd payload length exceeds the provided limit in target_check_max_data_sg_nents() code, se_cmd->data_length + se_cmd->prot_length are reset with se_cmd->residual_count plus underflow bit for outgoing TFO response callbacks. It also checks for existing CDB level underflow + overflow and recalculates final residual_count as necessary. Note this patch currently assumes 1:1 mapping of PAGE_SIZE per struct scatterlist entry. Reported-by: Craig Watson Cc: Craig Watson Tested-by: Himanshu Madhani Cc: Roland Dreier Cc: Arun Easi Cc: Giridhar Malavali Cc: Andrew Vasquez Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Martin K. Petersen Signed-off-by: Nicholas Bellinger --- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 5 +++ drivers/target/target_core_spc.c | 13 +++++-- drivers/target/target_core_transport.c | 51 +++++++++++++++++++++++++- include/target/target_core_fabric.h | 13 +++++++ 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index c621623abeedf..edeb3aefa6fee 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1808,6 +1808,11 @@ static const struct target_core_fabric_ops tcm_qla2xxx_ops = { .module = THIS_MODULE, .name = "qla2xxx", .node_acl_size = sizeof(struct tcm_qla2xxx_nacl), + /* + * XXX: Limit assumes single page per scatter-gather-list entry. + * Current maximum is ~4.9 MB per se_cmd->t_data_sg with PAGE_SIZE=4096 + */ + .max_data_sg_nents = 1200, .get_fabric_name = tcm_qla2xxx_get_fabric_name, .tpg_get_wwn = tcm_qla2xxx_get_fabric_wwn, .tpg_get_tag = tcm_qla2xxx_get_tag, diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index a07d455e0dd56..0e0456f6a2829 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c @@ -477,8 +477,8 @@ static sense_reason_t spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) { struct se_device *dev = cmd->se_dev; - int have_tp = 0; - int opt, min; + u32 mtl = 0; + int have_tp = 0, opt, min; /* * Following spc3r22 section 6.5.3 Block Limits VPD page, when @@ -509,8 +509,15 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) /* * Set MAXIMUM TRANSFER LENGTH + * + * XXX: Currently assumes single PAGE_SIZE per scatterlist for fabrics + * enforcing maximum HW scatter-gather-list entry limit */ - put_unaligned_be32(dev->dev_attrib.hw_max_sectors, &buf[8]); + if (cmd->se_tfo->max_data_sg_nents) { + mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE) / + dev->dev_attrib.block_size; + } + put_unaligned_be32(min_not_zero(mtl, dev->dev_attrib.hw_max_sectors), &buf[8]); /* * Set OPTIMAL TRANSFER LENGTH diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 3f0b50082de4e..62bafaa670f46 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1075,6 +1075,55 @@ transport_set_vpd_ident(struct t10_vpd *vpd, unsigned char *page_83) } EXPORT_SYMBOL(transport_set_vpd_ident); +static sense_reason_t +target_check_max_data_sg_nents(struct se_cmd *cmd, struct se_device *dev, + unsigned int size) +{ + u32 mtl; + + if (!cmd->se_tfo->max_data_sg_nents) + return TCM_NO_SENSE; + /* + * Check if fabric enforced maximum SGL entries per I/O descriptor + * exceeds se_cmd->data_length. If true, set SCF_UNDERFLOW_BIT + + * residual_count and reduce original cmd->data_length to maximum + * length based on single PAGE_SIZE entry scatter-lists. + */ + mtl = (cmd->se_tfo->max_data_sg_nents * PAGE_SIZE); + if (cmd->data_length > mtl) { + /* + * If an existing CDB overflow is present, calculate new residual + * based on CDB size minus fabric maximum transfer length. + * + * If an existing CDB underflow is present, calculate new residual + * based on original cmd->data_length minus fabric maximum transfer + * length. + * + * Otherwise, set the underflow residual based on cmd->data_length + * minus fabric maximum transfer length. + */ + if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT) { + cmd->residual_count = (size - mtl); + } else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { + u32 orig_dl = size + cmd->residual_count; + cmd->residual_count = (orig_dl - mtl); + } else { + cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; + cmd->residual_count = (cmd->data_length - mtl); + } + cmd->data_length = mtl; + /* + * Reset sbc_check_prot() calculated protection payload + * length based upon the new smaller MTL. + */ + if (cmd->prot_length) { + u32 sectors = (mtl / dev->dev_attrib.block_size); + cmd->prot_length = dev->prot_length * sectors; + } + } + return TCM_NO_SENSE; +} + sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { @@ -1120,7 +1169,7 @@ target_cmd_size_check(struct se_cmd *cmd, unsigned int size) } } - return 0; + return target_check_max_data_sg_nents(cmd, dev, size); } diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 69355feabd1d5..7fb2557a760e4 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -5,6 +5,19 @@ struct target_core_fabric_ops { struct module *module; const char *name; size_t node_acl_size; + /* + * Limits number of scatterlist entries per SCF_SCSI_DATA_CDB payload. + * Setting this value tells target-core to enforce this limit, and + * report as INQUIRY EVPD=b0 MAXIMUM TRANSFER LENGTH. + * + * target-core will currently reset se_cmd->data_length to this + * maximum size, and set UNDERFLOW residual count if length exceeds + * this limit. + * + * XXX: Not all initiator hosts honor this block-limit EVPD + * XXX: Currently assumes single PAGE_SIZE per scatterlist entry + */ + u32 max_data_sg_nents; char *(*get_fabric_name)(void); char *(*tpg_get_wwn)(struct se_portal_group *); u16 (*tpg_get_tag)(struct se_portal_group *); -- GitLab From 4416f89b8cfcb794d040fc3b68e5fb159b7d8d02 Mon Sep 17 00:00:00 2001 From: Nicholas Bellinger Date: Thu, 3 Sep 2015 06:30:45 +0000 Subject: [PATCH 6987/7006] target: Attach EXTENDED_COPY local I/O descriptors to xcopy_pt_sess This patch is a >= v4.1 regression bug-fix where control CDB emulation logic in commit 38b57f82 now expects a se_cmd->se_sess pointer to exist when determining T10-PI support is to be exposed for initiator host ports. To address this bug, go ahead and add locally generated se_cmd descriptors for copy-offload block-copy to it's own stand-alone se_session nexus, while the parent EXTENDED_COPY se_cmd descriptor remains associated with it's originating se_cmd->se_sess nexus. Note a valid se_cmd->se_sess is also required for future support of WRITE_INSERT and READ_STRIP software emulation when submitting backend I/O to se_device that exposes T10-PI suport. Reported-by: Alex Gorbachev Tested-by: Alex Gorbachev Cc: "Martin K. Petersen" Cc: Hannes Reinecke Cc: Christoph Hellwig Cc: Doug Gilbert Cc: # v4.1+ Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_xcopy.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 4515f52546f83..47fe94ee10b82 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -450,6 +450,8 @@ int target_xcopy_setup_pt(void) memset(&xcopy_pt_sess, 0, sizeof(struct se_session)); INIT_LIST_HEAD(&xcopy_pt_sess.sess_list); INIT_LIST_HEAD(&xcopy_pt_sess.sess_acl_list); + INIT_LIST_HEAD(&xcopy_pt_sess.sess_cmd_list); + spin_lock_init(&xcopy_pt_sess.sess_cmd_lock); xcopy_pt_nacl.se_tpg = &xcopy_pt_tpg; xcopy_pt_nacl.nacl_sess = &xcopy_pt_sess; @@ -644,7 +646,7 @@ static int target_xcopy_read_source( pr_debug("XCOPY: Built READ_16: LBA: %llu Sectors: %u Length: %u\n", (unsigned long long)src_lba, src_sectors, length); - transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length, + transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length, DMA_FROM_DEVICE, 0, &xpt_cmd->sense_buffer[0]); xop->src_pt_cmd = xpt_cmd; @@ -704,7 +706,7 @@ static int target_xcopy_write_destination( pr_debug("XCOPY: Built WRITE_16: LBA: %llu Sectors: %u Length: %u\n", (unsigned long long)dst_lba, dst_sectors, length); - transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length, + transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, &xcopy_pt_sess, length, DMA_TO_DEVICE, 0, &xpt_cmd->sense_buffer[0]); xop->dst_pt_cmd = xpt_cmd; -- GitLab From 7dd03aca9d61a9b64cd2a8cf6f5ea6f1f5391e8d Mon Sep 17 00:00:00 2001 From: Roland Dreier Date: Tue, 8 Sep 2015 06:14:18 -0700 Subject: [PATCH 6988/7006] target: Fix max_cmd_sn increment w/o cmdsn mutex regressions Current for-next iscsi target is broken: commit 109e2381749c1cfd94a0d22b2b54142539024973 Author: Roland Dreier Date: Thu Jul 23 14:53:32 2015 -0700 target: Drop iSCSI use of mutex around max_cmd_sn increment This patch fixes incorrect pr_debug() + atomic_inc_return() usage within iscsit_increment_maxcmdsn() code. Also fix funny iscsit_determine_maxcmdsn() usage and update iscsi_target_do_tx_login_io() code. Reported-by: Sagi Grimberg Cc: Sagi Grimberg Signed-off-by: Roland Dreier Cc: Roland Dreier Signed-off-by: Nicholas Bellinger --- drivers/target/iscsi/iscsi_target_device.c | 7 +++++-- drivers/target/iscsi/iscsi_target_nego.c | 2 -- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c index 07d2ef67dba65..0382fa24b53ba 100644 --- a/drivers/target/iscsi/iscsi_target_device.c +++ b/drivers/target/iscsi/iscsi_target_device.c @@ -47,16 +47,19 @@ void iscsit_determine_maxcmdsn(struct iscsi_session *sess) * core_set_queue_depth_for_node(). */ sess->cmdsn_window = se_nacl->queue_depth; - atomic_set(&sess->max_cmd_sn, (u32) atomic_read(&sess->max_cmd_sn) + se_nacl->queue_depth - 1); + atomic_add(se_nacl->queue_depth - 1, &sess->max_cmd_sn); } void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess) { + u32 max_cmd_sn; + if (cmd->immediate_cmd || cmd->maxcmdsn_inc) return; cmd->maxcmdsn_inc = 1; - pr_debug("Updated MaxCmdSN to 0x%08x\n", atomic_inc_return(&sess->max_cmd_sn)); + max_cmd_sn = atomic_inc_return(&sess->max_cmd_sn); + pr_debug("Updated MaxCmdSN to 0x%08x\n", max_cmd_sn); } EXPORT_SYMBOL(iscsit_increment_maxcmdsn); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 74d041e815f4d..4d08afe71e67a 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -366,8 +366,6 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log return -1; login->rsp_length = 0; - login_rsp->exp_cmdsn = cpu_to_be32(login_rsp->exp_cmdsn); - login_rsp->max_cmdsn = cpu_to_be32(login_rsp->max_cmdsn); return 0; } -- GitLab From 4824640ec3fc84337cb2baa9fb780e95864feb88 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 3 Sep 2015 16:03:42 -0700 Subject: [PATCH 6989/7006] target/user: Remove unused variable We don't use it any more. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index c448ef421ce77..9fd50be4aab65 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -577,7 +577,6 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * static unsigned int tcmu_handle_completions(struct tcmu_dev *udev) { struct tcmu_mailbox *mb; - LIST_HEAD(cpl_cmds); unsigned long flags; int handled = 0; -- GitLab From 06b967e429cfb76494badb9ffdd69e934ba72c77 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 3 Sep 2015 16:03:43 -0700 Subject: [PATCH 6990/7006] target: Remove no-op conditional This does nothing, and there are many other places where transport_cmd_check_stop_to_fabric()'s retval is not checked>, If we wanted to check it here, we should probably do it those other places too. Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 62bafaa670f46..5bacc7b5ed6d8 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1741,8 +1741,7 @@ void transport_generic_request_failure(struct se_cmd *cmd, check_stop: transport_lun_remove_cmd(cmd); - if (!transport_cmd_check_stop_to_fabric(cmd)) - ; + transport_cmd_check_stop_to_fabric(cmd); return; queue_full: -- GitLab From ed97d0cd78a337450e17eb613bdeec15e729af46 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Thu, 3 Sep 2015 16:03:44 -0700 Subject: [PATCH 6991/7006] target/user: Fix UFLAG_UNKNOWN_OP handling Calling transport_generic_request_failure() from here causes list corruption. We should be using target_complete_cmd() instead. Which we do in all other cases, so the UNKNOWN_OP case can become just another member of the big else/if chain in tcmu_handle_completion(). Signed-off-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 9fd50be4aab65..d0bb652b65b50 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -538,14 +538,8 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * UPDATE_HEAD(udev->data_tail, cmd->data_length, udev->data_size); pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", cmd->se_cmd); - transport_generic_request_failure(cmd->se_cmd, - TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE); - cmd->se_cmd = NULL; - kmem_cache_free(tcmu_cmd_cache, cmd); - return; - } - - if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { + entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION; + } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, se_cmd->scsi_sense_length); -- GitLab From ac64a2ce509104a746321a4f9646b6750cf281eb Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Fri, 4 Sep 2015 01:39:56 +0200 Subject: [PATCH 6992/7006] target: use stringify.h instead of own definition Signed-off-by: David Disseldorp Acked-by: Andy Grover Signed-off-by: Nicholas Bellinger --- drivers/target/target_core_user.c | 3 ++- include/uapi/linux/target_core_user.h | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index d0bb652b65b50..937cebf766332 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -898,7 +899,7 @@ static int tcmu_configure_device(struct se_device *dev) WARN_ON(!PAGE_ALIGNED(udev->data_off)); WARN_ON(udev->data_size % PAGE_SIZE); - info->version = xstr(TCMU_MAILBOX_VERSION); + info->version = __stringify(TCMU_MAILBOX_VERSION); info->mem[0].name = "tcm-user command & data buffer"; info->mem[0].addr = (phys_addr_t) udev->mb_addr; diff --git a/include/uapi/linux/target_core_user.h b/include/uapi/linux/target_core_user.h index b67f99d3c520b..95c6521d8a95f 100644 --- a/include/uapi/linux/target_core_user.h +++ b/include/uapi/linux/target_core_user.h @@ -42,10 +42,6 @@ #define TCMU_MAILBOX_VERSION 2 #define ALIGN_SIZE 64 /* Should be enough for most CPUs */ -/* See https://gcc.gnu.org/onlinedocs/cpp/Stringification.html */ -#define xstr(s) str(s) -#define str(s) #s - struct tcmu_mailbox { __u16 version; __u16 flags; -- GitLab From 294ab783ad98066b87296db1311c7ba2a60206a5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 9 Sep 2015 18:04:18 +0200 Subject: [PATCH 6993/7006] scsi_dh: fix randconfig build error It looks like the Kconfig check that was meant to fix this (commit fe9233fb6914a0eb20166c967e3020f7f0fba2c9 [SCSI] scsi_dh: fix kconfig related build errors) was actually reversed, but no-one noticed until the new set of patches which separated DM and SCSI_DH). Fixes: fe9233fb6914a0eb20166c967e3020f7f0fba2c9 Signed-off-by: Christoph Hellwig Tested-by: Mike Snitzer Signed-off-by: James Bottomley --- drivers/md/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig index b597273090724..e9ea681129dfa 100644 --- a/drivers/md/Kconfig +++ b/drivers/md/Kconfig @@ -393,7 +393,7 @@ config DM_MULTIPATH # of SCSI_DH if the latter isn't defined but if # it is, DM_MULTIPATH must depend on it. We get a build # error if SCSI_DH=m and DM_MULTIPATH=y - depends on SCSI_DH || !SCSI_DH + depends on !SCSI_DH || SCSI ---help--- Allow volume managers to support multipath hardware. -- GitLab From 0ba13fd19d39b7cb672bcec052bc813389c079a4 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 11 Sep 2015 13:26:39 -0700 Subject: [PATCH 6994/7006] Revert "writeback: plug writeback at a high level" This reverts commit d353d7587d02116b9732d5c06615aed75a4d3a47. Doing the block layer plug/unplug inside writeback_sb_inodes() is broken, because that function is actually called with a spinlock held: wb->list_lock, as pointed out by Chris Mason. Chris suggested just dropping and re-taking the spinlock around the blk_finish_plug() call (the plgging itself can happen under the spinlock), and that would technically work, but is just disgusting. We do something fairly similar - but not quite as disgusting because we at least have a better reason for it - in writeback_single_inode(), so it's not like the caller can depend on the lock being held over the call, but in this case there just isn't any good reason for that "release and re-take the lock" pattern. [ In general, we should really strive to avoid the "release and retake" pattern for locks, because in the general case it can easily cause subtle bugs when the caller caches any state around the call that might be invalidated by dropping the lock even just temporarily. ] But in this case, the plugging should be easy to just move up to the callers before the spinlock is taken, which should even improve the effectiveness of the plug. So there is really no good reason to play games with locking here. I'll send off a test-patch so that Dave Chinner can verify that that plug movement works. In the meantime this just reverts the problematic commit and adds a comment to the function so that we hopefully don't make this mistake again. Reported-by: Chris Mason Cc: Josef Bacik Cc: Dave Chinner Cc: Neil Brown Cc: Jan Kara Cc: Christoph Hellwig Signed-off-by: Linus Torvalds --- fs/fs-writeback.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 24489126f8ca1..d8ea7ed411b22 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1380,6 +1380,10 @@ static long writeback_chunk_size(struct bdi_writeback *wb, * Write a portion of b_io inodes which belong to @sb. * * Return the number of pages and/or inodes written. + * + * NOTE! This is called with wb->list_lock held, and will + * unlock and relock that for each inode it ends up doing + * IO for. */ static long writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb, @@ -1398,9 +1402,7 @@ static long writeback_sb_inodes(struct super_block *sb, unsigned long start_time = jiffies; long write_chunk; long wrote = 0; /* count both pages and inodes */ - struct blk_plug plug; - blk_start_plug(&plug); while (!list_empty(&wb->b_io)) { struct inode *inode = wb_inode(wb->b_io.prev); @@ -1498,7 +1500,6 @@ static long writeback_sb_inodes(struct super_block *sb, break; } } - blk_finish_plug(&plug); return wrote; } -- GitLab From 7c0d35a339db612aae5496424030307128f088a9 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 11 Sep 2015 13:07:36 -0700 Subject: [PATCH 6995/7006] MODSIGN: fix a compilation warning in extract-cert Fix the following warning when compiling extract-cert: scripts/extract-cert.c: In function `write_cert': scripts/extract-cert.c:89:2: warning: format not a string literal and no format arguments [-Wformat-security] ERR(!i2d_X509_bio(wb, x509), cert_dst); ^ whereby the ERR() macro is taking cert_dst as the format string. "%s" should be used as the format string as the path could contain special characters. Signed-off-by: David Howells Reported-by: Jim Davis Acked-by : David Woodhouse Cc: James Morris Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- scripts/extract-cert.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/extract-cert.c b/scripts/extract-cert.c index fd0db015c65c2..10d23ca9f6176 100644 --- a/scripts/extract-cert.c +++ b/scripts/extract-cert.c @@ -86,7 +86,7 @@ static void write_cert(X509 *x509) ERR(!wb, "%s", cert_dst); } X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); - ERR(!i2d_X509_bio(wb, x509), cert_dst); + ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); if (kbuild_verbose) fprintf(stderr, "Extracted cert: %s\n", buf); } -- GitLab From 5b25b13ab08f616efd566347d809b4ece54570d1 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 11 Sep 2015 13:07:39 -0700 Subject: [PATCH 6996/7006] sys_membarrier(): system-wide memory barrier (generic, x86) Here is an implementation of a new system call, sys_membarrier(), which executes a memory barrier on all threads running on the system. It is implemented by calling synchronize_sched(). It can be used to distribute the cost of user-space memory barriers asymmetrically by transforming pairs of memory barriers into pairs consisting of sys_membarrier() and a compiler barrier. For synchronization primitives that distinguish between read-side and write-side (e.g. userspace RCU [1], rwlocks), the read-side can be accelerated significantly by moving the bulk of the memory barrier overhead to the write-side. The existing applications of which I am aware that would be improved by this system call are as follows: * Through Userspace RCU library (http://urcu.so) - DNS server (Knot DNS) https://www.knot-dns.cz/ - Network sniffer (http://netsniff-ng.org/) - Distributed object storage (https://sheepdog.github.io/sheepdog/) - User-space tracing (http://lttng.org) - Network storage system (https://www.gluster.org/) - Virtual routers (https://events.linuxfoundation.org/sites/events/files/slides/DPDK_RCU_0MQ.pdf) - Financial software (https://lkml.org/lkml/2015/3/23/189) Those projects use RCU in userspace to increase read-side speed and scalability compared to locking. Especially in the case of RCU used by libraries, sys_membarrier can speed up the read-side by moving the bulk of the memory barrier cost to synchronize_rcu(). * Direct users of sys_membarrier - core dotnet garbage collector (https://github.com/dotnet/coreclr/issues/198) Microsoft core dotnet GC developers are planning to use the mprotect() side-effect of issuing memory barriers through IPIs as a way to implement Windows FlushProcessWriteBuffers() on Linux. They are referring to sys_membarrier in their github thread, specifically stating that sys_membarrier() is what they are looking for. To explain the benefit of this scheme, let's introduce two example threads: Thread A (non-frequent, e.g. executing liburcu synchronize_rcu()) Thread B (frequent, e.g. executing liburcu rcu_read_lock()/rcu_read_unlock()) In a scheme where all smp_mb() in thread A are ordering memory accesses with respect to smp_mb() present in Thread B, we can change each smp_mb() within Thread A into calls to sys_membarrier() and each smp_mb() within Thread B into compiler barriers "barrier()". Before the change, we had, for each smp_mb() pairs: Thread A Thread B previous mem accesses previous mem accesses smp_mb() smp_mb() following mem accesses following mem accesses After the change, these pairs become: Thread A Thread B prev mem accesses prev mem accesses sys_membarrier() barrier() follow mem accesses follow mem accesses As we can see, there are two possible scenarios: either Thread B memory accesses do not happen concurrently with Thread A accesses (1), or they do (2). 1) Non-concurrent Thread A vs Thread B accesses: Thread A Thread B prev mem accesses sys_membarrier() follow mem accesses prev mem accesses barrier() follow mem accesses In this case, thread B accesses will be weakly ordered. This is OK, because at that point, thread A is not particularly interested in ordering them with respect to its own accesses. 2) Concurrent Thread A vs Thread B accesses Thread A Thread B prev mem accesses prev mem accesses sys_membarrier() barrier() follow mem accesses follow mem accesses In this case, thread B accesses, which are ensured to be in program order thanks to the compiler barrier, will be "upgraded" to full smp_mb() by synchronize_sched(). * Benchmarks On Intel Xeon E5405 (8 cores) (one thread is calling sys_membarrier, the other 7 threads are busy looping) 1000 non-expedited sys_membarrier calls in 33s =3D 33 milliseconds/call. * User-space user of this system call: Userspace RCU library Both the signal-based and the sys_membarrier userspace RCU schemes permit us to remove the memory barrier from the userspace RCU rcu_read_lock() and rcu_read_unlock() primitives, thus significantly accelerating them. These memory barriers are replaced by compiler barriers on the read-side, and all matching memory barriers on the write-side are turned into an invocation of a memory barrier on all active threads in the process. By letting the kernel perform this synchronization rather than dumbly sending a signal to every process threads (as we currently do), we diminish the number of unnecessary wake ups and only issue the memory barriers on active threads. Non-running threads do not need to execute such barrier anyway, because these are implied by the scheduler context switches. Results in liburcu: Operations in 10s, 6 readers, 2 writers: memory barriers in reader: 1701557485 reads, 2202847 writes signal-based scheme: 9830061167 reads, 6700 writes sys_membarrier: 9952759104 reads, 425 writes sys_membarrier (dyn. check): 7970328887 reads, 425 writes The dynamic sys_membarrier availability check adds some overhead to the read-side compared to the signal-based scheme, but besides that, sys_membarrier slightly outperforms the signal-based scheme. However, this non-expedited sys_membarrier implementation has a much slower grace period than signal and memory barrier schemes. Besides diminishing the number of wake-ups, one major advantage of the membarrier system call over the signal-based scheme is that it does not need to reserve a signal. This plays much more nicely with libraries, and with processes injected into for tracing purposes, for which we cannot expect that signals will be unused by the application. An expedited version of this system call can be added later on to speed up the grace period. Its implementation will likely depend on reading the cpu_curr()->mm without holding each CPU's rq lock. This patch adds the system call to x86 and to asm-generic. [1] http://urcu.so membarrier(2) man page: MEMBARRIER(2) Linux Programmer's Manual MEMBARRIER(2) NAME membarrier - issue memory barriers on a set of threads SYNOPSIS #include int membarrier(int cmd, int flags); DESCRIPTION The cmd argument is one of the following: MEMBARRIER_CMD_QUERY Query the set of supported commands. It returns a bitmask of supported commands. MEMBARRIER_CMD_SHARED Execute a memory barrier on all threads running on the system. Upon return from system call, the caller thread is ensured that all running threads have passed through a state where all memory accesses to user-space addresses match program order between entry to and return from the system call (non-running threads are de facto in such a state). This covers threads from all pro=E2=80=90 cesses running on the system. This command returns 0. The flags argument needs to be 0. For future extensions. All memory accesses performed in program order from each targeted thread is guaranteed to be ordered with respect to sys_membarrier(). If we use the semantic "barrier()" to represent a compiler barrier forcing memory accesses to be performed in program order across the barrier, and smp_mb() to represent explicit memory barriers forcing full memory ordering across the barrier, we have the following ordering table for each pair of barrier(), sys_membarrier() and smp_mb(): The pair ordering is detailed as (O: ordered, X: not ordered): barrier() smp_mb() sys_membarrier() barrier() X X O smp_mb() X O O sys_membarrier() O O O RETURN VALUE On success, these system calls return zero. On error, -1 is returned, and errno is set appropriately. For a given command, with flags argument set to 0, this system call is guaranteed to always return the same value until reboot. ERRORS ENOSYS System call is not implemented. EINVAL Invalid arguments. Linux 2015-04-15 MEMBARRIER(2) Signed-off-by: Mathieu Desnoyers Reviewed-by: Paul E. McKenney Reviewed-by: Josh Triplett Cc: KOSAKI Motohiro Cc: Steven Rostedt Cc: Nicholas Miell Cc: Ingo Molnar Cc: Alan Cox Cc: Lai Jiangshan Cc: Stephen Hemminger Cc: Thomas Gleixner Cc: Peter Zijlstra Cc: David Howells Cc: Pranith Kumar Cc: Michael Kerrisk Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- MAINTAINERS | 8 ++++ arch/x86/entry/syscalls/syscall_32.tbl | 1 + arch/x86/entry/syscalls/syscall_64.tbl | 1 + include/linux/syscalls.h | 2 + include/uapi/asm-generic/unistd.h | 4 +- include/uapi/linux/Kbuild | 1 + include/uapi/linux/membarrier.h | 53 +++++++++++++++++++++ init/Kconfig | 12 +++++ kernel/Makefile | 1 + kernel/membarrier.c | 66 ++++++++++++++++++++++++++ kernel/sys_ni.c | 3 ++ 11 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 include/uapi/linux/membarrier.h create mode 100644 kernel/membarrier.c diff --git a/MAINTAINERS b/MAINTAINERS index 310da4295c702..e77bc84dc580b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6789,6 +6789,14 @@ W: http://www.mellanox.com Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlxsw/ +MEMBARRIER SUPPORT +M: Mathieu Desnoyers +M: "Paul E. McKenney" +L: linux-kernel@vger.kernel.org +S: Supported +F: kernel/membarrier.c +F: include/uapi/linux/membarrier.h + MEMORY MANAGEMENT L: linux-mm@kvack.org W: http://www.linux-mm.org diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 477bfa6db3707..7663c455b9f65 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -381,3 +381,4 @@ 372 i386 recvmsg sys_recvmsg compat_sys_recvmsg 373 i386 shutdown sys_shutdown 374 i386 userfaultfd sys_userfaultfd +375 i386 membarrier sys_membarrier diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 81c490634db99..278842fdf1f63 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -330,6 +330,7 @@ 321 common bpf sys_bpf 322 64 execveat stub_execveat 323 common userfaultfd sys_userfaultfd +324 common membarrier sys_membarrier # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 08001317aee73..a460e2ef28437 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -885,4 +885,6 @@ asmlinkage long sys_execveat(int dfd, const char __user *filename, const char __user *const __user *argv, const char __user *const __user *envp, int flags); +asmlinkage long sys_membarrier(int cmd, int flags); + #endif diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index e016bd9b1a049..8da542a2874d6 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -709,9 +709,11 @@ __SYSCALL(__NR_memfd_create, sys_memfd_create) __SYSCALL(__NR_bpf, sys_bpf) #define __NR_execveat 281 __SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat) +#define __NR_membarrier 282 +__SYSCALL(__NR_membarrier, sys_membarrier) #undef __NR_syscalls -#define __NR_syscalls 282 +#define __NR_syscalls 283 /* * All syscalls below here should go away really, diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 70ff1d9abf0dd..f7b2db44eb4b0 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -252,6 +252,7 @@ header-y += mdio.h header-y += media.h header-y += media-bus-format.h header-y += mei.h +header-y += membarrier.h header-y += memfd.h header-y += mempolicy.h header-y += meye.h diff --git a/include/uapi/linux/membarrier.h b/include/uapi/linux/membarrier.h new file mode 100644 index 0000000000000..e0b108bd2624d --- /dev/null +++ b/include/uapi/linux/membarrier.h @@ -0,0 +1,53 @@ +#ifndef _UAPI_LINUX_MEMBARRIER_H +#define _UAPI_LINUX_MEMBARRIER_H + +/* + * linux/membarrier.h + * + * membarrier system call API + * + * Copyright (c) 2010, 2015 Mathieu Desnoyers + * + * 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 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. + */ + +/** + * enum membarrier_cmd - membarrier system call command + * @MEMBARRIER_CMD_QUERY: Query the set of supported commands. It returns + * a bitmask of valid commands. + * @MEMBARRIER_CMD_SHARED: Execute a memory barrier on all running threads. + * Upon return from system call, the caller thread + * is ensured that all running threads have passed + * through a state where all memory accesses to + * user-space addresses match program order between + * entry to and return from the system call + * (non-running threads are de facto in such a + * state). This covers threads from all processes + * running on the system. This command returns 0. + * + * Command to be passed to the membarrier system call. The commands need to + * be a single bit each, except for MEMBARRIER_CMD_QUERY which is assigned to + * the value 0. + */ +enum membarrier_cmd { + MEMBARRIER_CMD_QUERY = 0, + MEMBARRIER_CMD_SHARED = (1 << 0), +}; + +#endif /* _UAPI_LINUX_MEMBARRIER_H */ diff --git a/init/Kconfig b/init/Kconfig index 02da9f1fd9df1..c24b6f767bf0f 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -1602,6 +1602,18 @@ config PCI_QUIRKS bugs/quirks. Disable this only if your target machine is unaffected by PCI quirks. +config MEMBARRIER + bool "Enable membarrier() system call" if EXPERT + default y + help + Enable the membarrier() system call that allows issuing memory + barriers across all running threads, which can be used to distribute + the cost of user-space memory barriers asymmetrically by transforming + pairs of memory barriers into pairs consisting of membarrier() and a + compiler barrier. + + If unsure, say Y. + config EMBEDDED bool "Embedded system" option allnoconfig_y diff --git a/kernel/Makefile b/kernel/Makefile index d4988410b410a..53abf008ecb39 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -100,6 +100,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o obj-$(CONFIG_JUMP_LABEL) += jump_label.o obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o obj-$(CONFIG_TORTURE_TEST) += torture.o +obj-$(CONFIG_MEMBARRIER) += membarrier.o obj-$(CONFIG_HAS_IOMEM) += memremap.o diff --git a/kernel/membarrier.c b/kernel/membarrier.c new file mode 100644 index 0000000000000..536c727a56e97 --- /dev/null +++ b/kernel/membarrier.c @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2010, 2015 Mathieu Desnoyers + * + * membarrier system call + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +/* + * Bitmask made from a "or" of all commands within enum membarrier_cmd, + * except MEMBARRIER_CMD_QUERY. + */ +#define MEMBARRIER_CMD_BITMASK (MEMBARRIER_CMD_SHARED) + +/** + * sys_membarrier - issue memory barriers on a set of threads + * @cmd: Takes command values defined in enum membarrier_cmd. + * @flags: Currently needs to be 0. For future extensions. + * + * If this system call is not implemented, -ENOSYS is returned. If the + * command specified does not exist, or if the command argument is invalid, + * this system call returns -EINVAL. For a given command, with flags argument + * set to 0, this system call is guaranteed to always return the same value + * until reboot. + * + * All memory accesses performed in program order from each targeted thread + * is guaranteed to be ordered with respect to sys_membarrier(). If we use + * the semantic "barrier()" to represent a compiler barrier forcing memory + * accesses to be performed in program order across the barrier, and + * smp_mb() to represent explicit memory barriers forcing full memory + * ordering across the barrier, we have the following ordering table for + * each pair of barrier(), sys_membarrier() and smp_mb(): + * + * The pair ordering is detailed as (O: ordered, X: not ordered): + * + * barrier() smp_mb() sys_membarrier() + * barrier() X X O + * smp_mb() X O O + * sys_membarrier() O O O + */ +SYSCALL_DEFINE2(membarrier, int, cmd, int, flags) +{ + if (unlikely(flags)) + return -EINVAL; + switch (cmd) { + case MEMBARRIER_CMD_QUERY: + return MEMBARRIER_CMD_BITMASK; + case MEMBARRIER_CMD_SHARED: + if (num_online_cpus() > 1) + synchronize_sched(); + return 0; + default: + return -EINVAL; + } +} diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c index 03c3875d99589..a02decf155832 100644 --- a/kernel/sys_ni.c +++ b/kernel/sys_ni.c @@ -245,3 +245,6 @@ cond_syscall(sys_bpf); /* execveat */ cond_syscall(sys_execveat); + +/* membarrier */ +cond_syscall(sys_membarrier); -- GitLab From b6d973441675222a4e6c8cad8208c2fe098a0b25 Mon Sep 17 00:00:00 2001 From: Pranith Kumar Date: Fri, 11 Sep 2015 13:07:42 -0700 Subject: [PATCH 6997/7006] selftests: add membarrier syscall test Add a self test for the membarrier system call. Signed-off-by: Pranith Kumar Signed-off-by: Mathieu Desnoyers Cc: Michael Ellerman Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/membarrier/.gitignore | 1 + tools/testing/selftests/membarrier/Makefile | 11 +++ .../selftests/membarrier/membarrier_test.c | 71 +++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 tools/testing/selftests/membarrier/.gitignore create mode 100644 tools/testing/selftests/membarrier/Makefile create mode 100644 tools/testing/selftests/membarrier/membarrier_test.c diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 0501511445963..89b05e2222c91 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -6,6 +6,7 @@ TARGETS += firmware TARGETS += ftrace TARGETS += futex TARGETS += kcmp +TARGETS += membarrier TARGETS += memfd TARGETS += memory-hotplug TARGETS += mount diff --git a/tools/testing/selftests/membarrier/.gitignore b/tools/testing/selftests/membarrier/.gitignore new file mode 100644 index 0000000000000..020c44f49a9e6 --- /dev/null +++ b/tools/testing/selftests/membarrier/.gitignore @@ -0,0 +1 @@ +membarrier_test diff --git a/tools/testing/selftests/membarrier/Makefile b/tools/testing/selftests/membarrier/Makefile new file mode 100644 index 0000000000000..877a50355d7fd --- /dev/null +++ b/tools/testing/selftests/membarrier/Makefile @@ -0,0 +1,11 @@ +CFLAGS += -g -I../../../../usr/include/ + +all: + $(CC) $(CFLAGS) membarrier_test.c -o membarrier_test + +TEST_PROGS := membarrier_test + +include ../lib.mk + +clean: + $(RM) membarrier_test diff --git a/tools/testing/selftests/membarrier/membarrier_test.c b/tools/testing/selftests/membarrier/membarrier_test.c new file mode 100644 index 0000000000000..3c9f2179acd83 --- /dev/null +++ b/tools/testing/selftests/membarrier/membarrier_test.c @@ -0,0 +1,71 @@ +#define _GNU_SOURCE +#define __EXPORTED_HEADERS__ + +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" + +static int sys_membarrier(int cmd, int flags) +{ + return syscall(__NR_membarrier, cmd, flags); +} + +static void test_membarrier_fail(void) +{ + int cmd = -1, flags = 0; + + if (sys_membarrier(cmd, flags) != -1) { + printf("membarrier: Should fail but passed\n"); + ksft_exit_fail(); + } +} + +static void test_membarrier_success(void) +{ + int flags = 0; + + if (sys_membarrier(MEMBARRIER_CMD_SHARED, flags) != 0) { + printf("membarrier: Executing MEMBARRIER failed, %s\n", + strerror(errno)); + ksft_exit_fail(); + } + + printf("membarrier: MEMBARRIER_CMD_SHARED success\n"); +} + +static void test_membarrier(void) +{ + test_membarrier_fail(); + test_membarrier_success(); +} + +static int test_membarrier_exists(void) +{ + int flags = 0; + + if (sys_membarrier(MEMBARRIER_CMD_QUERY, flags)) + return 0; + + return 1; +} + +int main(int argc, char **argv) +{ + printf("membarrier: MEMBARRIER_CMD_QUERY "); + if (test_membarrier_exists()) { + printf("syscall implemented\n"); + test_membarrier(); + } else { + printf("syscall not implemented!\n"); + return ksft_exit_fail(); + } + + printf("membarrier: tests done!\n"); + + return ksft_exit_pass(); +} -- GitLab From c9946c4208a3725e116c05180d93154eb406d451 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Fri, 11 Sep 2015 13:07:45 -0700 Subject: [PATCH 6998/7006] selftests: enhance membarrier syscall test Update the membarrier syscall self-test to match the membarrier interface. Extend coverage of the interface. Consider ENOSYS as a "SKIP" test, since it is a valid configuration, but does not allow testing the system call. Signed-off-by: Mathieu Desnoyers Cc: Michael Ellerman Cc: Pranith Kumar Cc: Shuah Khan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- .../selftests/membarrier/membarrier_test.c | 100 +++++++++++++----- 1 file changed, 75 insertions(+), 25 deletions(-) diff --git a/tools/testing/selftests/membarrier/membarrier_test.c b/tools/testing/selftests/membarrier/membarrier_test.c index 3c9f2179acd83..dde3125080074 100644 --- a/tools/testing/selftests/membarrier/membarrier_test.c +++ b/tools/testing/selftests/membarrier/membarrier_test.c @@ -10,62 +10,112 @@ #include "../kselftest.h" +enum test_membarrier_status { + TEST_MEMBARRIER_PASS = 0, + TEST_MEMBARRIER_FAIL, + TEST_MEMBARRIER_SKIP, +}; + static int sys_membarrier(int cmd, int flags) { return syscall(__NR_membarrier, cmd, flags); } -static void test_membarrier_fail(void) +static enum test_membarrier_status test_membarrier_cmd_fail(void) { int cmd = -1, flags = 0; if (sys_membarrier(cmd, flags) != -1) { - printf("membarrier: Should fail but passed\n"); - ksft_exit_fail(); + printf("membarrier: Wrong command should fail but passed.\n"); + return TEST_MEMBARRIER_FAIL; + } + return TEST_MEMBARRIER_PASS; +} + +static enum test_membarrier_status test_membarrier_flags_fail(void) +{ + int cmd = MEMBARRIER_CMD_QUERY, flags = 1; + + if (sys_membarrier(cmd, flags) != -1) { + printf("membarrier: Wrong flags should fail but passed.\n"); + return TEST_MEMBARRIER_FAIL; } + return TEST_MEMBARRIER_PASS; } -static void test_membarrier_success(void) +static enum test_membarrier_status test_membarrier_success(void) { - int flags = 0; + int cmd = MEMBARRIER_CMD_SHARED, flags = 0; - if (sys_membarrier(MEMBARRIER_CMD_SHARED, flags) != 0) { - printf("membarrier: Executing MEMBARRIER failed, %s\n", + if (sys_membarrier(cmd, flags) != 0) { + printf("membarrier: Executing MEMBARRIER_CMD_SHARED failed. %s.\n", strerror(errno)); - ksft_exit_fail(); + return TEST_MEMBARRIER_FAIL; } - printf("membarrier: MEMBARRIER_CMD_SHARED success\n"); + printf("membarrier: MEMBARRIER_CMD_SHARED success.\n"); + return TEST_MEMBARRIER_PASS; } -static void test_membarrier(void) +static enum test_membarrier_status test_membarrier(void) { - test_membarrier_fail(); - test_membarrier_success(); + enum test_membarrier_status status; + + status = test_membarrier_cmd_fail(); + if (status) + return status; + status = test_membarrier_flags_fail(); + if (status) + return status; + status = test_membarrier_success(); + if (status) + return status; + return TEST_MEMBARRIER_PASS; } -static int test_membarrier_exists(void) +static enum test_membarrier_status test_membarrier_query(void) { - int flags = 0; - - if (sys_membarrier(MEMBARRIER_CMD_QUERY, flags)) - return 0; + int flags = 0, ret; - return 1; + printf("membarrier MEMBARRIER_CMD_QUERY "); + ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags); + if (ret < 0) { + printf("failed. %s.\n", strerror(errno)); + switch (errno) { + case ENOSYS: + /* + * It is valid to build a kernel with + * CONFIG_MEMBARRIER=n. However, this skips the tests. + */ + return TEST_MEMBARRIER_SKIP; + case EINVAL: + default: + return TEST_MEMBARRIER_FAIL; + } + } + if (!(ret & MEMBARRIER_CMD_SHARED)) { + printf("command MEMBARRIER_CMD_SHARED is not supported.\n"); + return TEST_MEMBARRIER_FAIL; + } + printf("syscall available.\n"); + return TEST_MEMBARRIER_PASS; } int main(int argc, char **argv) { - printf("membarrier: MEMBARRIER_CMD_QUERY "); - if (test_membarrier_exists()) { - printf("syscall implemented\n"); - test_membarrier(); - } else { - printf("syscall not implemented!\n"); + switch (test_membarrier_query()) { + case TEST_MEMBARRIER_FAIL: return ksft_exit_fail(); + case TEST_MEMBARRIER_SKIP: + return ksft_exit_skip(); + } + switch (test_membarrier()) { + case TEST_MEMBARRIER_FAIL: + return ksft_exit_fail(); + case TEST_MEMBARRIER_SKIP: + return ksft_exit_skip(); } printf("membarrier: tests done!\n"); - return ksft_exit_pass(); } -- GitLab From 6798a8caaf64fa68b9ab2044e070fe4545034e03 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Fri, 11 Sep 2015 13:07:48 -0700 Subject: [PATCH 6999/7006] fs/seq_file: convert int seq_vprint/seq_printf/etc... returns to void The seq_ function return values were frequently misused. See: commit 1f33c41c03da ("seq_file: Rename seq_overflow() to seq_has_overflowed() and make public") All uses of these return values have been removed, so convert the return types to void. Miscellanea: o Move seq_put_decimal_ and seq_escape prototypes closer the other seq_vprintf prototypes o Reorder seq_putc and seq_puts to return early on overflow o Add argument names to seq_vprintf and seq_printf o Update the seq_escape kernel-doc o Convert a couple of leading spaces to tabs in seq_escape Signed-off-by: Joe Perches Cc: Al Viro Cc: Steven Rostedt Cc: Mark Brown Cc: Stephen Rothwell Cc: Joerg Roedel Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/iommu/omap-iommu-debug.c | 3 +- fs/nsfs.c | 3 +- fs/seq_file.c | 70 ++++++++++++++------------------ include/linux/seq_file.h | 19 +++++---- 4 files changed, 45 insertions(+), 50 deletions(-) diff --git a/drivers/iommu/omap-iommu-debug.c b/drivers/iommu/omap-iommu-debug.c index 0717aa96ce39b..9bc20e2119a35 100644 --- a/drivers/iommu/omap-iommu-debug.c +++ b/drivers/iommu/omap-iommu-debug.c @@ -135,8 +135,9 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num) static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, struct seq_file *s) { - return seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram, + seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram, (cr->cam & MMU_CAM_P) ? 1 : 0); + return 0; } static size_t omap_dump_tlb_entries(struct omap_iommu *obj, struct seq_file *s) diff --git a/fs/nsfs.c b/fs/nsfs.c index e4905fbf33969..8f20d6016e205 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -142,7 +142,8 @@ static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry) struct inode *inode = d_inode(dentry); const struct proc_ns_operations *ns_ops = dentry->d_fsdata; - return seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); + seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); + return 0; } static const struct super_operations nsfs_ops = { diff --git a/fs/seq_file.c b/fs/seq_file.c index 263b125dbcf4d..225586e141cac 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -372,16 +372,16 @@ EXPORT_SYMBOL(seq_release); * @esc: set of characters that need escaping * * Puts string into buffer, replacing each occurrence of character from - * @esc with usual octal escape. Returns 0 in case of success, -1 - in - * case of overflow. + * @esc with usual octal escape. + * Use seq_has_overflowed() to check for errors. */ -int seq_escape(struct seq_file *m, const char *s, const char *esc) +void seq_escape(struct seq_file *m, const char *s, const char *esc) { char *end = m->buf + m->size; - char *p; + char *p; char c; - for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { + for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { if (!strchr(esc, c)) { *p++ = c; continue; @@ -394,14 +394,13 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc) continue; } seq_set_overflow(m); - return -1; - } + return; + } m->count = p - m->buf; - return 0; } EXPORT_SYMBOL(seq_escape); -int seq_vprintf(struct seq_file *m, const char *f, va_list args) +void seq_vprintf(struct seq_file *m, const char *f, va_list args) { int len; @@ -409,24 +408,20 @@ int seq_vprintf(struct seq_file *m, const char *f, va_list args) len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); if (m->count + len < m->size) { m->count += len; - return 0; + return; } } seq_set_overflow(m); - return -1; } EXPORT_SYMBOL(seq_vprintf); -int seq_printf(struct seq_file *m, const char *f, ...) +void seq_printf(struct seq_file *m, const char *f, ...) { - int ret; va_list args; va_start(args, f); - ret = seq_vprintf(m, f, args); + seq_vprintf(m, f, args); va_end(args); - - return ret; } EXPORT_SYMBOL(seq_printf); @@ -664,26 +659,25 @@ int seq_open_private(struct file *filp, const struct seq_operations *ops, } EXPORT_SYMBOL(seq_open_private); -int seq_putc(struct seq_file *m, char c) +void seq_putc(struct seq_file *m, char c) { - if (m->count < m->size) { - m->buf[m->count++] = c; - return 0; - } - return -1; + if (m->count >= m->size) + return; + + m->buf[m->count++] = c; } EXPORT_SYMBOL(seq_putc); -int seq_puts(struct seq_file *m, const char *s) +void seq_puts(struct seq_file *m, const char *s) { int len = strlen(s); - if (m->count + len < m->size) { - memcpy(m->buf + m->count, s, len); - m->count += len; - return 0; + + if (m->count + len >= m->size) { + seq_set_overflow(m); + return; } - seq_set_overflow(m); - return -1; + memcpy(m->buf + m->count, s, len); + m->count += len; } EXPORT_SYMBOL(seq_puts); @@ -694,8 +688,8 @@ EXPORT_SYMBOL(seq_puts); * This routine is very quick when you show lots of numbers. * In usual cases, it will be better to use seq_printf(). It's easier to read. */ -int seq_put_decimal_ull(struct seq_file *m, char delimiter, - unsigned long long num) +void seq_put_decimal_ull(struct seq_file *m, char delimiter, + unsigned long long num) { int len; @@ -707,35 +701,33 @@ int seq_put_decimal_ull(struct seq_file *m, char delimiter, if (num < 10) { m->buf[m->count++] = num + '0'; - return 0; + return; } len = num_to_str(m->buf + m->count, m->size - m->count, num); if (!len) goto overflow; m->count += len; - return 0; + return; + overflow: seq_set_overflow(m); - return -1; } EXPORT_SYMBOL(seq_put_decimal_ull); -int seq_put_decimal_ll(struct seq_file *m, char delimiter, - long long num) +void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num) { if (num < 0) { if (m->count + 3 >= m->size) { seq_set_overflow(m); - return -1; + return; } if (delimiter) m->buf[m->count++] = delimiter; num = -num; delimiter = '-'; } - return seq_put_decimal_ull(m, delimiter, num); - + seq_put_decimal_ull(m, delimiter, num); } EXPORT_SYMBOL(seq_put_decimal_ll); diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h index adeadbd6d7bfa..dde00defbaa52 100644 --- a/include/linux/seq_file.h +++ b/include/linux/seq_file.h @@ -114,13 +114,18 @@ int seq_open(struct file *, const struct seq_operations *); ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); loff_t seq_lseek(struct file *, loff_t, int); int seq_release(struct inode *, struct file *); -int seq_escape(struct seq_file *, const char *, const char *); -int seq_putc(struct seq_file *m, char c); -int seq_puts(struct seq_file *m, const char *s); int seq_write(struct seq_file *seq, const void *data, size_t len); -__printf(2, 3) int seq_printf(struct seq_file *, const char *, ...); -__printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args); +__printf(2, 0) +void seq_vprintf(struct seq_file *m, const char *fmt, va_list args); +__printf(2, 3) +void seq_printf(struct seq_file *m, const char *fmt, ...); +void seq_putc(struct seq_file *m, char c); +void seq_puts(struct seq_file *m, const char *s); +void seq_put_decimal_ull(struct seq_file *m, char delimiter, + unsigned long long num); +void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num); +void seq_escape(struct seq_file *m, const char *s, const char *esc); void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, int rowsize, int groupsize, const void *buf, size_t len, @@ -138,10 +143,6 @@ int single_release(struct inode *, struct file *); void *__seq_open_private(struct file *, const struct seq_operations *, int); int seq_open_private(struct file *, const struct seq_operations *, int); int seq_release_private(struct inode *, struct file *); -int seq_put_decimal_ull(struct seq_file *m, char delimiter, - unsigned long long num); -int seq_put_decimal_ll(struct seq_file *m, char delimiter, - long long num); static inline struct user_namespace *seq_user_ns(struct seq_file *seq) { -- GitLab From 4f1af60bcc2fc6caa7fa3036238b5994708e9a84 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 11 Sep 2015 13:07:50 -0700 Subject: [PATCH 7000/7006] mm/early_ioremap: add explicit #include of asm/early_ioremap.h Commit 6b0f68e32ea8 ("mm: add utility for early copy from unmapped ram") introduces a function copy_from_early_mem() into mm/early_ioremap.c which itself calls early_memremap()/early_memunmap(). However, since early_memunmap() has not been declared yet at this point in the .c file, nor by any explicitly included header files, we are depending on a transitive include of asm/early_ioremap.h to declare it, which is fragile. So instead, include this header explicitly. Signed-off-by: Ard Biesheuvel Acked-by: Mark Salter Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- mm/early_ioremap.c | 1 + 1 file changed, 1 insertion(+) diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c index 23f744d77ce00..17ae14b5aefa2 100644 --- a/mm/early_ioremap.c +++ b/mm/early_ioremap.c @@ -15,6 +15,7 @@ #include #include #include +#include #ifdef CONFIG_MMU static int early_ioremap_debug __initdata; -- GitLab From e527b22c3f63c02832ac4cb8ed0ec3a9b638bbdf Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Fri, 11 Sep 2015 13:07:53 -0700 Subject: [PATCH 7001/7006] revert "ocfs2/dlm: use list_for_each_entry instead of list_for_each" Revert commit f83c7b5e9fd6 ("ocfs2/dlm: use list_for_each_entry instead of list_for_each"). list_for_each_entry() will dereference its `pos' argument, which can be NULL in dlm_process_recovery_data(). Reported-by: Julia Lawall Reported-by: Fengguang Wu Cc: Joseph Qi Cc: Mark Fasheh Cc: Joel Becker Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/ocfs2/dlm/dlmrecovery.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index d0e436dc64371..ce12e0b1a31f1 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c @@ -1776,7 +1776,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, struct dlm_migratable_lockres *mres) { struct dlm_migratable_lock *ml; - struct list_head *queue; + struct list_head *queue, *iter; struct list_head *tmpq = NULL; struct dlm_lock *newlock = NULL; struct dlm_lockstatus *lksb = NULL; @@ -1821,7 +1821,9 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, spin_lock(&res->spinlock); for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) { tmpq = dlm_list_idx_to_ptr(res, j); - list_for_each_entry(lock, tmpq, list) { + list_for_each(iter, tmpq) { + lock = list_entry(iter, + struct dlm_lock, list); if (lock->ml.cookie == ml->cookie) break; lock = NULL; -- GitLab From 3ebb0540c20d6670396ccee9ff6794c095fa9311 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 11 Sep 2015 16:32:22 -0700 Subject: [PATCH 7002/7006] ARCv2: [axs103_smp] Reduce clk for SMP FPGA configs Newer bitfiles needs the reduced clk even for SMP builds Cc: #4.2 Signed-off-by: Vineet Gupta Signed-off-by: Linus Torvalds --- arch/arc/plat-axs10x/axs10x.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arc/plat-axs10x/axs10x.c b/arch/arc/plat-axs10x/axs10x.c index ad9825d4026ae..0a77b19e1df8d 100644 --- a/arch/arc/plat-axs10x/axs10x.c +++ b/arch/arc/plat-axs10x/axs10x.c @@ -402,6 +402,8 @@ static void __init axs103_early_init(void) unsigned int num_cores = (read_aux_reg(ARC_REG_MCIP_BCR) >> 16) & 0x3F; if (num_cores > 2) arc_set_core_freq(50 * 1000000); + else if (num_cores == 2) + arc_set_core_freq(75 * 1000000); #endif switch (arc_get_core_freq()/1000000) { -- GitLab From dfb22fc5c0eb7645f47a752ce537bfb2c8a6aea6 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 11 Sep 2015 20:06:59 -0700 Subject: [PATCH 7003/7006] thermal: fix intel PCH thermal driver mismerge MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I didn't notice this when merging the thermal code from Zhang, but his merge (commit 5a924a07f882: "Merge branches 'thermal-core' and 'thermal-intel' of .git into next") of the thermal-core and thermal-intel branches was wrong. In thermal-core, commit 17e8351a7739 ("thermal: consistently use int for temperatures") converted the thermal layer to use "int" for temperatures. But in parallel, in the thermal-intel branch commit d0a12625d2ff ("thermal: Add Intel PCH thermal driver") added support for the intel PCH thermal sensor using the old interfaces that used "unsigned long" pointers. This resulted in warnings like this: drivers/thermal/intel_pch_thermal.c:184:14: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] .get_temp = pch_thermal_get_temp, ^ drivers/thermal/intel_pch_thermal.c:184:14: note: (near initialization for ‘tzd_ops.get_temp’) drivers/thermal/intel_pch_thermal.c:186:19: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types] .get_trip_temp = pch_get_trip_temp, ^ drivers/thermal/intel_pch_thermal.c:186:19: note: (near initialization for ‘tzd_ops.get_trip_temp’) This fixes it. Signed-off-by: Linus Torvalds --- drivers/thermal/intel_pch_thermal.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/thermal/intel_pch_thermal.c b/drivers/thermal/intel_pch_thermal.c index 1650a62484bd7..50c7da79be830 100644 --- a/drivers/thermal/intel_pch_thermal.c +++ b/drivers/thermal/intel_pch_thermal.c @@ -117,8 +117,7 @@ read_trips: return 0; } -static int pch_wpt_get_temp(struct pch_thermal_device *ptd, - unsigned long *temp) +static int pch_wpt_get_temp(struct pch_thermal_device *ptd, int *temp) { u8 wpt_temp; @@ -132,7 +131,7 @@ static int pch_wpt_get_temp(struct pch_thermal_device *ptd, struct pch_dev_ops { int (*hw_init)(struct pch_thermal_device *ptd, int *nr_trips); - int (*get_temp)(struct pch_thermal_device *ptd, unsigned long *temp); + int (*get_temp)(struct pch_thermal_device *ptd, int *temp); }; @@ -142,8 +141,7 @@ static struct pch_dev_ops pch_dev_ops_wpt = { .get_temp = pch_wpt_get_temp, }; -static int pch_thermal_get_temp(struct thermal_zone_device *tzd, - unsigned long *temp) +static int pch_thermal_get_temp(struct thermal_zone_device *tzd, int *temp) { struct pch_thermal_device *ptd = tzd->devdata; @@ -165,8 +163,7 @@ static int pch_get_trip_type(struct thermal_zone_device *tzd, int trip, return 0; } -static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, - unsigned long *temp) +static int pch_get_trip_temp(struct thermal_zone_device *tzd, int trip, int *temp) { struct pch_thermal_device *ptd = tzd->devdata; -- GitLab From 505a666ee3fc611518e85df203eb8c707995ceaa Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 11 Sep 2015 13:37:19 -0700 Subject: [PATCH 7004/7006] writeback: plug writeback in wb_writeback() and writeback_inodes_wb() We had to revert the pluggin in writeback_sb_inodes() because the wb->list_lock is held, but we could easily plug at a higher level before taking that lock, and unplug after releasing it. This does that. Chris will run performance numbers, just to verify that this approach is comparable to the alternative (we could just drop and re-take the lock around the blk_finish_plug() rather than these two commits. I'd have preferred waiting for actual performance numbers before picking one approach over the other, but I don't want to release rc1 with the known "sleeping function called from invalid context" issue, so I'll pick this cleanup version for now. But if the numbers show that we really want to plug just at the writeback_sb_inodes() level, and we should just play ugly games with the spinlock, we'll switch to that. Cc: Chris Mason Cc: Josef Bacik Cc: Dave Chinner Cc: Neil Brown Cc: Jan Kara Cc: Christoph Hellwig Signed-off-by: Linus Torvalds --- fs/fs-writeback.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index d8ea7ed411b22..587ac08eabb62 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -1546,12 +1546,15 @@ static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, .range_cyclic = 1, .reason = reason, }; + struct blk_plug plug; + blk_start_plug(&plug); spin_lock(&wb->list_lock); if (list_empty(&wb->b_io)) queue_io(wb, &work); __writeback_inodes_wb(wb, &work); spin_unlock(&wb->list_lock); + blk_finish_plug(&plug); return nr_pages - work.nr_pages; } @@ -1579,10 +1582,12 @@ static long wb_writeback(struct bdi_writeback *wb, unsigned long oldest_jif; struct inode *inode; long progress; + struct blk_plug plug; oldest_jif = jiffies; work->older_than_this = &oldest_jif; + blk_start_plug(&plug); spin_lock(&wb->list_lock); for (;;) { /* @@ -1662,6 +1667,7 @@ static long wb_writeback(struct bdi_writeback *wb, } } spin_unlock(&wb->list_lock); + blk_finish_plug(&plug); return nr_pages - work->nr_pages; } -- GitLab From 10fbd36e362a0f367e34a7cd876a81295d8fc5ca Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 27 May 2015 15:32:15 -0700 Subject: [PATCH 7005/7006] blk: rq_data_dir() should not return a boolean MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rq_data_dir() returns either READ or WRITE (0 == READ, 1 == WRITE), not a boolean value. Now, admittedly the "!= 0" doesn't really change the value (0 stays as zero, 1 stays as one), but it's not only redundant, it confuses gcc, and causes gcc to warn about the construct switch (rq_data_dir(req)) { case READ: ... case WRITE: ... that we have in a few drivers. Now, the gcc warning is silly and stupid (it seems to warn not about the switch value having a different type from the case statements, but about _any_ boolean switch value), but in this case the code itself is silly and stupid too, so let's just change it, and get rid of warnings like this: drivers/block/hd.c: In function ‘hd_request’: drivers/block/hd.c:630:11: warning: switch condition has boolean value [-Wswitch-bool] switch (rq_data_dir(req)) { The odd '!= 0' came in when "cmd_flags" got turned into a "u64" in commit 5953316dbf90 ("block: make rq->cmd_flags be 64-bit") and is presumably because the old code (that just did a logical 'and' with 1) would then end up making the type of rq_data_dir() be u64 too. But if we want to retain the old regular integer type, let's just cast the result to 'int' rather than use that rather odd '!= 0'. Signed-off-by: Linus Torvalds --- include/linux/blkdev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 708923b9b623a..38a5ff772a37f 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -584,7 +584,7 @@ static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) #define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) -#define rq_data_dir(rq) (((rq)->cmd_flags & 1) != 0) +#define rq_data_dir(rq) ((int)((rq)->cmd_flags & 1)) /* * Driver can handle struct request, if it either has an old style -- GitLab From 6ff33f3902c3b1c5d0db6b1e2c70b6d76fba357f Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 12 Sep 2015 16:35:56 -0700 Subject: [PATCH 7006/7006] Linux 4.3-rc1 --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index f2d27061e5f79..1a132ea43ca52 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 4 -PATCHLEVEL = 2 +PATCHLEVEL = 3 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = -rc1 NAME = Hurr durr I'ma sheep # *DOCUMENTATION* -- GitLab